pax_global_header00006660000000000000000000000064150023651740014515gustar00rootroot0000000000000052 comment=ce3eb1d071b16f6f56727c3e21904a173a71e0cc elektroid-3.2.3/000077500000000000000000000000001500236517400135045ustar00rootroot00000000000000elektroid-3.2.3/.editorconfig000066400000000000000000000003041500236517400161560ustar00rootroot00000000000000root = true [*] charset = utf-8 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [*.{c,h}] tab_width = 8 [Makefile] [Makefile.am] indent_style = tab indent_size = 8 elektroid-3.2.3/.github/000077500000000000000000000000001500236517400150445ustar00rootroot00000000000000elektroid-3.2.3/.github/workflows/000077500000000000000000000000001500236517400171015ustar00rootroot00000000000000elektroid-3.2.3/.github/workflows/ubuntu.yml000066400000000000000000000014341500236517400211500ustar00rootroot00000000000000name: Ubuntu CI on: push: branches: [ "master" ] pull_request: branches: [ "master" ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: install dependencies run: | sudo apt-get update sudo apt-get -y --no-install-recommends install automake libtool build-essential libasound2-dev libgtk-3-dev libpulse-dev libsndfile1-dev libsamplerate0-dev autopoint gettext zlib1g-dev libjson-glib-dev libzip-dev sudo apt-get -y --no-install-recommends install libcunit1-dev - name: autoreconf run: autoreconf --install - name: configure run: ./configure - name: make run: make - name: make check run: make check - name: make distcheck run: make clean distcheck elektroid-3.2.3/.gitignore000066400000000000000000000023471500236517400155020ustar00rootroot00000000000000/autom4te.cache/ /config/ /Makefile /Makefile.in aclocal.m4 app.info compile config.h config.h.in config.log config.status configure configure.scan coverage_report depcomp install-sh libtool m4 missing stamp-h1 test-driver *~ *.log *.o *.la *.so* *.a .deps *.tar* *.zip *.lo *.gcno *.gcda .dirstamp man/Makefile man/Makefile.in res/Makefile res/Makefile.in src/Makefile src/Makefile.in src/elektroid src/elektroid-cli src/*.exe src/.libs src/*~ test/Makefile test/Makefile.in test/*.log test/*.trs test/*.exe test/.libs test/integration/*.trs test/tests_scala test/tests_common test/tests_microfreak test/tests_elektron test/tests_utils test/tests_sample test/tests_connector config.guess config.sub ltmain.sh ABOUT-NLS po/Makefile po/Makefile.in config.rpath po/Makefile.in.in po/Makevars.template po/POTFILES po/Rules-quot po/boldquot.sed po/en@boldquot.header po/en@quot.header po/*.gmo po/insert-header.sin po/quot.sed po/remove-potcdate.sin po/stamp-po po/remove-potcdate.sed debian/.debhelper/ debian/autoreconf.after debian/autoreconf.before debian/debhelper-build-stamp debian/elektroid.substvars debian/elektroid/ debian/files docs/_site/ docs/.sass-cache/ docs/.jekyll-cache/ docs/.jekyll-metadata docs/.bundle/ flatpak/build/ .flatpak-builder/ elektroid-3.2.3/AUTHORS000066400000000000000000000000501500236517400145470ustar00rootroot00000000000000David García Goñi elektroid-3.2.3/COPYING000066400000000000000000001045131500236517400145430ustar00rootroot00000000000000 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 . elektroid-3.2.3/ChangeLog000066400000000000000000000000001500236517400152440ustar00rootroot00000000000000elektroid-3.2.3/INSTALL000066400000000000000000000366141500236517400145470ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell command './configure && make && make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the 'README' file for instructions specific to this package. Some packages provide this 'INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The 'configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a 'Makefile' in each directory of the package. It may also create one or more '.h' files containing system-dependent definitions. Finally, it creates a shell script 'config.status' that you can run in the future to recreate the current configuration, and a file 'config.log' containing compiler output (useful mainly for debugging 'configure'). It can also use an optional file (typically called 'config.cache' and enabled with '--cache-file=config.cache' or simply '-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how 'configure' could check whether to do them, and mail diffs or instructions to the address given in the 'README' so they can be considered for the next release. If you are using the cache, and at some point 'config.cache' contains results you don't want to keep, you may remove or edit it. The file 'configure.ac' (or 'configure.in') is used to create 'configure' by a program called 'autoconf'. You need 'configure.ac' if you want to change it or regenerate 'configure' using a newer version of 'autoconf'. The simplest way to compile this package is: 1. 'cd' to the directory containing the package's source code and type './configure' to configure the package for your system. Running 'configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type 'make' to compile the package. 3. Optionally, type 'make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type 'make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the 'make install' phase executed with root privileges. 5. Optionally, type 'make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior 'make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing 'make clean'. To also remove the files that 'configure' created (so you can compile the package for a different kind of computer), type 'make distclean'. There is also a 'make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type 'make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide 'make distcheck', which can by used by developers to test that all other targets like 'make install' and 'make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the 'configure' script does not know about. Run './configure --help' for details on some of the pertinent environment variables. You can give 'configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU 'make'. 'cd' to the directory where you want the object files and executables to go and run the 'configure' script. 'configure' automatically checks for the source code in the directory that 'configure' is in and in '..'. This is known as a "VPATH" build. With a non-GNU 'make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use 'make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple '-arch' options to the compiler but only a single '-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the 'lipo' tool if you have problems. Installation Names ================== By default, 'make install' installs the package's commands under '/usr/local/bin', include files under '/usr/local/include', etc. You can specify an installation prefix other than '/usr/local' by giving 'configure' the option '--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option '--exec-prefix=PREFIX' to 'configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like '--bindir=DIR' to specify different values for particular kinds of files. Run 'configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of '${prefix}', so that specifying just '--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to 'configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the 'make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, 'make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of '${prefix}'. Any directories that were specified during 'configure', but not in terms of '${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the 'DESTDIR' variable. For example, 'make install DESTDIR=/alternate/directory' will prepend '/alternate/directory' before all installation names. The approach of 'DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of '${prefix}' at 'configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving 'configure' the option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'. Some packages pay attention to '--enable-FEATURE' options to 'configure', where FEATURE indicates an optional part of the package. They may also pay attention to '--with-PACKAGE' options, where PACKAGE is something like 'gnu-as' or 'x' (for the X Window System). The 'README' should mention any '--enable-' and '--with-' options that the package recognizes. For packages that use the X Window System, 'configure' can usually find the X include and library files automatically, but if it doesn't, you can use the 'configure' options '--x-includes=DIR' and '--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of 'make' will be. For these packages, running './configure --enable-silent-rules' sets the default to minimal output, which can be overridden with 'make V=1'; while running './configure --disable-silent-rules' sets the default to verbose, which can be overridden with 'make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX 'make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as 'configure' are involved. Use GNU 'make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its '' header file. The option '-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put '/usr/ucb' early in your 'PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in '/usr/bin'. So, if you need '/usr/ucb' in your 'PATH', put it _after_ '/usr/bin'. On Haiku, software installed for all users goes in '/boot/common', not '/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features 'configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, 'configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the '--build=TYPE' option. TYPE can either be a short name for the system type, such as 'sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file 'config.sub' for the possible values of each field. If 'config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option '--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with '--host=TYPE'. Sharing Defaults ================ If you want to set default values for 'configure' scripts to share, you can create a site shell script called 'config.site' that gives default values for variables like 'CC', 'cache_file', and 'prefix'. 'configure' looks for 'PREFIX/share/config.site' if it exists, then 'PREFIX/etc/config.site' if it exists. Or, you can set the 'CONFIG_SITE' environment variable to the location of the site script. A warning: not all 'configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to 'configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the 'configure' command line, using 'VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified 'gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash 'configure' Invocation ====================== 'configure' recognizes the following options to control how it operates. '--help' '-h' Print a summary of all of the options to 'configure', and exit. '--help=short' '--help=recursive' Print a summary of the options unique to this package's 'configure', and exit. The 'short' variant lists options used only in the top level, while the 'recursive' variant lists options also present in any nested packages. '--version' '-V' Print the version of Autoconf used to generate the 'configure' script, and exit. '--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally 'config.cache'. FILE defaults to '/dev/null' to disable caching. '--config-cache' '-C' Alias for '--cache-file=config.cache'. '--quiet' '--silent' '-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to '/dev/null' (any error messages will still be shown). '--srcdir=DIR' Look for the package's source code in directory DIR. Usually 'configure' can determine that directory automatically. '--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. '--no-create' '-n' Run the configure checks, but stop before creating any output files. 'configure' also accepts some other, not widely useful, options. Run 'configure --help' for more details. elektroid-3.2.3/Makefile.am000066400000000000000000000001551500236517400155410ustar00rootroot00000000000000ACLOCAL_AMFLAGS=-I m4 if ELEKTROID_CLI_ONLY SUBDIRS=src res test man else SUBDIRS=src res test po man endif elektroid-3.2.3/NEWS000066400000000000000000000000001500236517400141710ustar00rootroot00000000000000elektroid-3.2.3/README000066400000000000000000000000001500236517400143520ustar00rootroot00000000000000elektroid-3.2.3/README.md000066400000000000000000000337651500236517400150010ustar00rootroot00000000000000# Elektroid [//]: # (Do not modify this file manually.) [//]: # (This file is generated from the docs directory by executing `make`.) Elektroid is a sample and MIDI device manager. It includes the `elektroid` GUI application and the `elektroid-cli` CLI application. ![Elektroid GUI screenshot](docs/images/screenshot.png "Elektroid GUI") Elektroid started as a FLOSS Elektron Transfer alternative and it has ended up supporting other devices from different vendors in the same fashion. These are the supported devices: * Arturia MicroBrute * Arturia MicroFreak * Casio CZ-101 * Elektron Analog Four MKI, MKII and Keys * Elektron Analog Heat MKI, MKII and +FX * Elektron Analog Rytm MKI and MKII * Elektron Digitakt I and II * Elektron Digitone I and II and Digitone Keys * Elektron Model:Cycles * Elektron Model:Samples * Elektron Syntakt * Eventide ModFactor, PitchFactor, TimeFactor, Space and H9 * Moog Little Phatty and Slim Phatty * Novation Summit and Peak * Samplers implementing MIDI SDS While Elektroid is already available in some GNU/Linux distributions such as Debian or Ubuntu, it can also be easily installed on other distributions via Flatpak. ## Installation As with other autotools project, you need to run the following commands. If you just want to compile `elektroid-cli`, pass `CLI_ONLY=yes` to `./configure`. ``` autoreconf --install ./configure make sudo make install ``` The package dependencies for Debian-based distributions are: - automake - libtool - build-essential - libasound2-dev - libgtk-3-dev - libpulse-dev - libsndfile1-dev - libsamplerate0-dev - autopoint - gettext - zlib1g-dev - libjson-glib-dev - libzip-dev You can easily install them by running `sudo apt install automake libtool build-essential libasound2-dev libgtk-3-dev libpulse-dev libsndfile1-dev libsamplerate0-dev autopoint gettext zlib1g-dev libjson-glib-dev libzip-dev`. If you are only compiling the CLI, install the dependencies with `sudo apt install automake libtool build-essential libasound2-dev libglib2.0-dev libsndfile1-dev libsamplerate0-dev autopoint libtool zlib1g-dev libjson-glib-dev libzip-dev`. For Fedora, run `sudo dnf install autoconf libtool alsa-lib-devel zlib-devel libzip-devel gtk3-devel libsndfile-devel gettext-devel libsamplerate-devel pulseaudio-libs-devel json-glib-devel` to install the build dependencies. For Arch Linux, run `sudo pacman -S base-devel autoconf libtool alsa-lib zlib libzip gtk3 libsndfile gettext libsamplerate json-glib` to install the build dependencies. For OSX (Homebrew), run `homebrew install automake bltool pkg-config gtk+3 libsndfile libsamplerate gettext zlib json-glib libzip rtaudio rtmidi`. For MSYS2 (UCRT64), run `pacman -S mingw-w64-x86_64-toolchain gettext gettext-devel libtool pkg-config mingw-w64-x86_64-autotools mingw-w64-x86_64-gcc mingw-w64-ucrt-x86_64-zlib mingw-w64-ucrt-x86_64-libzip mingw-w64-ucrt-x86_64-gtk3 mingw-w64-x86_64-json-glib mingw-w64-ucrt-x86_64-libsndfile mingw-w64-ucrt-x86_64-rtmidi mingw-w64-ucrt-x86_64-rtaudio mingw-w64-ucrt-x86_64-libsamplerate` to install the build dependencies. #### Additional notes on MSYS2 (UCRT64) * Repository must be cloned with `-c core.symlinks=true` option for the included symbolic links to work. * `LANG` environmente variable must be set as in `LANG=es_ES.UTF-8` depending on your installed locales. * A shortcut could be manually created and use the `ico` file included in the installation for this purpose. It is recommended to set the `target` property to `C:\msys64\usr\bin\mintty.exe -w hide /bin/env MSYSTEM=UCRT64 LANG=es_ES.UTF-8 /bin/bash -l -i -c /ucrt64/bin/elektroid.exe` and the `start in` property to `C:\msys64\usr\bin` or the equivalent directories in your installation. ### MIDI backend By default, Elektroid uses ALSA as the MIDI backend on Linux and RtMidi on other OSs. To use RtMidi on Linux, pass `RTMIDI=yes` to `./configure`. In this case, the RtMidi development package will be needed (`librtmidi-dev` on Debian). ### Audio server By default, Elektroid uses PulseAudio as the audio server on Linux and RtAudio on other OSs. To use RtAudio on Linux, pass `RTAUDIO=yes` to `./configure`. In this case, the RtAudio development package will be needed (`librtaudio-dev` on Debian). ### Adding and reconfiguring Elektron devices Since version 2.1, it is possible to add and reconfigure devices without recompiling as the device definitions are stored in a JSON file. Hopefully, this approach will make it easier for users to modify and add devices and new releases will only be needed if new funcionalities are actually added. This is a device definition from `res/elektron/devices.json`. ``` }, { "id": 12, "name": "Digitakt", "alias": "dt", "filesystems": 57, "storage": 3 }, { ``` Properties `filesystems` and `storage` are based on the definitions found in `src/connectors/elektron.h` and are the bitwise OR result of all the supported filesystems and storage types. ``` enum connector_fs { FS_SAMPLES = 0x1, FS_RAW_ALL = 0x2, FS_RAW_PRESETS = 0x4, FS_DATA_ALL = 0x8, FS_DATA_PRJ = 0x10, FS_DATA_SND = 0x20, }; ``` ``` enum connector_storage { STORAGE_PLUS_DRIVE = 0x1, STORAGE_RAM = 0x2 }; ``` If the file `~/.config/elektroid/elektron/devices.json` is found, it will take precedence over the installed one. ## Packaging This is a quick glance at the instructions needed to build some distribution packages. ### Debian ``` $ dpkg-buildpackage -b -rfakeroot -us -uc ``` ### Fedora ``` $ rel=35 $ mock -r fedora-$rel-x86_64 --buildsrpm --spec rpm/elektroid.spec --sources . $ mock -r fedora-$rel-x86_64 --no-clean --rebuild /var/lib/mock/fedora-$rel-x86_64/result/elektroid-*.src.rpm ``` ### Flatpak There is an official Flathub repository in https://github.com/flathub/io.github.dagargo.Elektroid so installing the Flatpak is as easy as running `flatpak install flathub io.github.dagargo.Elektroid`. From that repository, building and installing the Flatpak can be done with `flatpak-builder --user --install --force-clean flatpak/build io.github.dagargo.Elektroid.yaml`. ## CLI `elektroid-cli` brings the same filesystem related functionality to the terminal. There are device commands and filesystem commands. The latter have the form `a-b-c` where `a` is a connector, `b` is a filesystem and `c` is the command, (e.g., `elektron-project-ls`, `cz-program-upload`, `sds-sample-download`). Notice that the filesystem is always in the singular form. As of version 2.2, **older command forms have been removed**. These are the available commands: * `ls` or `list` * `mkdir` (behave as `mkdir -p`) * `rmdir` or `rm` (both behave as `rm -rf`) * `mv` (in slot mode, the second path is just the name of the file) * `cp` * `cl`, clear item * `sw`, swap items * `ul` or `upload` * `dl` or `download` * `rdl` or `rdownload` or `backup` Keep in mind that not every filesystem implements all the commands. For instance, Elektron samples can not be swapped. Provided paths must always be prepended with the device id and a colon (e.g., `0:/incoming`). ### Device commands * `ld` or `ls-devices`, list all MIDI devices with input and output ``` $ elektroid-cli ld 0: id: SYSTEM_ID; name: computer 1: id: hw:2,0,0; name: hw:2,0,0: Elektron Digitakt, Elektron Digitakt MIDI 1 2: id: hw:1,0,0; name: hw:1,0,0: M-Audio MIDISPORT Uno, M-Audio MIDISPORT Uno MIDI 1 3: id: hw:3,0,0; name: hw:3,0,0: MicroBrute, MicroBrute MicroBrute 4: id: hw:3,0,1; name: hw:3,0,1: MicroBrute, MicroBrute MicroBrute MIDI Inte 5: id: hw:4,0,0; name: hw:4,0,0: Little Phatty SE II, Little Phatty SE II MIDI 1 6: id: hw:5,0,0; name: hw:5,0,0: Summit, Summit MIDI 1 7: id: hw:3,0,0; name: hw:3,0,0: Arturia MicroFreak, Arturia MicroFreak Arturia Micr ``` * `info` or `info-device`, show device info including the compatible filesystems (filesystems implemented in the connector but not compatible with the device are not shown). Notice that some filesystems are not meant to be used from the GUI so they are shown as `CLI only`. ``` $ elektroid-cli info 1 Type: MIDI Device name: Elektron Digitakt Device version: 1.51A Device description: Digitakt Connector name: elektron Filesystems: sample, data (CLI only), project, sound ``` * `df` or `info-storage`, show size and use of +Drive and RAM ``` $ elektroid-cli df 1:/ Storage Size Used Available Use% +Drive 959.5MiB 285.9MiB 673.6MiB 29.80% RAM 64MiB 0B 64MiB 0.00% ``` * `send` and `receive` work with a batch of SysEx messages. These are useful when working with generic devices, which have no filesystems implemented buf offer options to receive or send data. ``` $ elektroid-cli send file.syx 1 $ elektroid-cli receive 1 file.syx ``` * `upgrade`, upgrade firmware ``` $ elektroid-cli upgrade Digitakt_OS1.30.syx 1 ``` ### System connector The first connector is always a system (local computer) one used to convert sample formats. It can be used like any other connector. ``` $ elektroid-cli system-wav48k16b2c-ul square.wav 0:/home/user/samples ``` ### Elektron conector These are the available filesystems for the elektron connector: * `sample` * `raw` * `preset` * `data` * `project` * `sound` Raw and data are intended to interface directly with the filesystems provided by the devices so the downloaded or uploaded files are **not** compatible with Elektron Transfer formats. Preset is a particular instance of raw and so are project and sound but regarding data. Thus, raw and data filesystems should be used only for testing and are **not** available in the GUI. #### Sample, raw and preset commands * `elektron-sample-ls` It only works for directories. Notice that the first column is the file type, the second is the size, the third is an internal cksum and the last one is the sample name. ``` $ elektroid-cli elektron-sample-ls 0:/ D 0B 00000000 drum machines F 630.34KiB f8711cd9 saw F 1.29MiB 0bbc22bd square ``` * `elektron-sample-mkdir` ``` $ elektroid-cli elektron-sample-mkdir 0:/samples ``` * `elektron-sample-rmdir` ``` $ elektroid-cli elektron-sample-rmdir 0:/samples ``` * `elektron-sample-ul` ``` $ elektroid-cli elektron-sample-ul square.wav 0:/ ``` * `elektron-sample-dl` ``` $ elektroid-cli elektron-sample-dl 0:/square ``` * `elektron-sample-mv` ``` $ elektroid-cli elektron-sample-mv 0:/square 0:/sample ``` * `elektron-sample-rm` ``` $ elektroid-cli elektron-sample-rm 0:/sample ``` #### Data, sound and project commands There are a few things to clarify first. * All data commands are valid for both projects and sounds although the examples use just sounds. * All data commands that use paths to items and not directories use the item index instead the item name. Here are the commands. * `elektron-data-ls` It only works for directories. Notice that the first column is the file type, the second is the index, the third is the permissons in hexadecimal, the fourth indicates if the data in valid, the fifth indicates if it has metadatam, the sixth is the size and the last one is the item name. Permissions are 16 bits values but only 6 are used from bit 2 to bit 7 both included. From LSB to MSB, this permissions are read, write, clear, copy, swap, and move. ``` $ elektroid-cli elektron-data-ls 0:/ D -1 0000 0 0 0B projects D -1 0000 0 0 0B soundbanks ``` ``` $ elektroid-cli elektron-data-ls 0:/soundbanks/D F 1 0012 1 1 160B KICK F 2 0012 1 1 160B SNARE ``` * `elektron-data-cp` ``` $ elektroid-cli elektron-data-cp 0:/soundbanks/D/1 0:/soundbanks/D/3 $ elektroid-cli elektron-data-ls 0:/soundbanks/D F 1 0012 1 1 160B KICK F 2 0012 1 1 160B SNARE F 3 0012 1 1 160B KICK ``` * `elektron-data-sw` ``` $ elektroid-cli elektron-data-sw 0:/soundbanks/D/2 0:/soundbanks/D/3 $ elektroid-cli elektron-data-ls 0:/soundbanks/D F 1 0012 1 1 160B KICK F 2 0012 1 1 160B KICK F 3 0012 1 1 160B SNARE ``` * `elektron-data-mv` ``` $ elektroid-cli elektron-data-mv 0:/soundbanks/D/3 0:/soundbanks/D/1 $ elektroid-cli elektron-data-ls 0:/soundbanks/D F 1 0012 1 1 160B SNARE F 2 0012 1 1 160B KICK ``` * `elektron-data-cl` ``` $ elektroid-cli elektron-data-cl 0:/soundbanks/D/1 $ elektroid-cli elektron-data-ls 0:/soundbanks/D F 2 0012 1 1 160B KICK ``` * `elektron-data-dl` ``` $ elektroid-cli elektron-data-dl 0:/soundbanks/D/1 $ elektroid-cli elektron-data-dl 0:/soundbanks/D/1 dir ``` * `elektron-data-ul` ``` $ elektroid-cli elektron-data-ul sound 0:/soundbanks/D ``` ## API Elektroid, although statically compiled, is extensible through three extension points. * Connectors, which are a set of filesystems, each providing operations over MIDI and the computer native filesystem to implement uploading, downloading, renaming and the like. The API is defined in `src/connector.h`. Connectors are defined in the `src/connectors` directory and need to be configured in the connector registry in `src/regconn.c`. * Menu actions (GUI only), which are device related buttons in the application menu that provide the user with some configuration window or launch device configuration processes. The API is defined in `src/maction.h`. Menu actions are defined in the `src/mactions` directory and need to be configured in the menu action registry in `src/regma.c`. * Preferences, which are single configuration elements that are stored in the configuration JSON file and can be recalled from anywhere in the code. The API is defined in `src/preferences.h`. Preferences can be defined anywhere but need to be configured in the preferences registry in `src/regpref.c`. ## Tests Elektroid includes automated integration tests for the supported devices and filesystems. In order to run a test, proceed as follows. The variable `TEST_DEVICE` must contain the device id and variable `TEST_CONNECTOR_FILESYSTEM` must contain the connector name, an underscore char (`_`) and the filesystem name. ``` $ TEST_DEVICE=0 TEST_CONNECTOR_FILESYSTEM=efactor_preset make check ``` Running `make check` without setting any of these variables will run some system integration tests together with a few unit tests. elektroid-3.2.3/THANKS000066400000000000000000000001321500236517400144130ustar00rootroot00000000000000Dennis Braun Jonathan Wakely Szabolcs Szőke elektroid-3.2.3/configure.ac000066400000000000000000000051021500236517400157700ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.71]) AC_INIT([elektroid],[3.2.3],[dagargo@gmail.com]) AC_CONFIG_SRCDIR([src]) AC_CONFIG_HEADERS([config.h]) LT_INIT AC_SEARCH_LIBS([sqrt], [m]) AC_CONFIG_MACRO_DIRS([m4]) AM_INIT_AUTOMAKE([subdir-objects]) # Checks for programs. AC_PROG_CC # Define conditional prior to package checks AM_CONDITIONAL([ELEKTROID_CLI_ONLY], [test "${CLI_ONLY}" == yes]) # Needed to access the 'host_os' variable AC_CANONICAL_HOST case "${host_os}" in linux*) SYSTEM=opendesktop ;; *mingw*) SYSTEM=mingw RTMIDI=yes RTAUDIO=yes ;; darwin*) SYSTEM=darwin RTMIDI=yes RTAUDIO=yes ;; *) SYSTEM=opendesktop RTMIDI=yes RTAUDIO=yes ;; esac AM_CONDITIONAL([MINGW], [test "${SYSTEM}" == mingw]) AM_CONDITIONAL([DARWIN], [test "${SYSTEM}" == darwin]) AM_CONDITIONAL([OPENDESKTOP], [test "${SYSTEM}" == opendesktop]) AM_CONDITIONAL([ELEKTROID_RTMIDI], [test "${RTMIDI}" == yes]) AS_IF([test "${RTMIDI}" == yes], [AC_DEFINE([ELEKTROID_RTMIDI], [1], ["Use RtMidi"])]) AM_CONDITIONAL([ELEKTROID_RTAUDIO], [test "${RTAUDIO}" == yes]) AS_IF([test "${RTAUDIO}" == yes], [AC_DEFINE([ELEKTROID_RTAUDIO], [1], ["Use RtAudio"])]) # Checks for libraries. PKG_CHECK_MODULES(zlib, zlib >= 1.1.8) PKG_CHECK_MODULES(libzip, libzip >= 1.1.2) AM_COND_IF(ELEKTROID_CLI_ONLY, [], [PKG_CHECK_MODULES([GTK], [gtk+-3.0])]) PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0.2) PKG_CHECK_MODULES(SNDFILE_MP3, sndfile >= 1.1.0, ac_cv_sndfile_mp3=1, ac_cv_sndfile_mp3=0) AC_DEFINE_UNQUOTED([HAVE_SNDFILE_MP3],${ac_cv_sndfile_mp3}, [Set to 1 if you have libsndfile > 1.1.0.]) AC_SUBST(SNDFILE_CFLAGS) AC_SUBST(SNDFILE_LIBS) PKG_CHECK_MODULES(SAMPLERATE, samplerate >= 0.1.8) AC_SUBST(SAMPLERATE_CFLAGS) AC_SUBST(SAMPLERATE_LIBS) AM_COND_IF(ELEKTROID_RTMIDI, [PKG_CHECK_MODULES([RTMIDI], [rtmidi >= 5.0.0])], [PKG_CHECK_MODULES([ALSA], [alsa >= 1.1.3])]) AM_COND_IF(ELEKTROID_CLI_ONLY, [], [AM_COND_IF(ELEKTROID_RTAUDIO, [PKG_CHECK_MODULES([RTAUDIO], [rtaudio >= 5.2.0])], [PKG_CHECK_MODULES([ALSA], [alsa >= 1.1.3])])]) AC_SUBST(PULSEAUDIO_CFLAGS) AC_SUBST(PULSEAUDIO_LIBS) AM_COND_IF(ELEKTROID_CLI_ONLY, [], [ AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION([0.19]) ]) # Checks for header files. AC_CHECK_HEADERS([unistd.h limits.h]) # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_FUNC_MALLOC AC_CONFIG_FILES([Makefile src/Makefile res/Makefile test/Makefile po/Makefile.in po/Makefile man/Makefile]) AC_OUTPUT elektroid-3.2.3/debian/000077500000000000000000000000001500236517400147265ustar00rootroot00000000000000elektroid-3.2.3/debian/changelog000066400000000000000000000052571500236517400166110ustar00rootroot00000000000000elektroid (2.3-1) unstable; urgency=medium [ Johannes Schauer Marin Rodrigues ] * d/copyright: remove superfluous trailing newline [ Dennis Braun ] * New upstream version 2.3 * d/watch: Fix regex * Update my email address * Bump my d/copyright year * d/rules: Remove obsolete dh flag --with-autoreconf, it's default -- Dennis Braun Mon, 05 Dec 2022 15:49:42 +0100 elektroid (2.1-1) unstable; urgency=medium * New upstream version 2.1 * d/control: + Bump Standards Version to 4.6.1 + Update description from upstream and add Syntakt as supported * Update d/copyright years -- Dennis Braun Fri, 03 Jun 2022 17:45:00 +0200 elektroid (2.0-1) unstable; urgency=medium * New upstream version 2.0 * Drop patch, applied by upstream * Add libjson-glib-dev and libzip-dev to B-Ds -- Dennis Braun Sat, 15 Jan 2022 00:04:47 +0100 elektroid (1.4-2) unstable; urgency=medium * Change Architecture for the binary package to linux-any (Closes: #1001613) -- Dennis Braun Tue, 14 Dec 2021 17:30:00 +0100 elektroid (1.4-1) unstable; urgency=medium [ Jenkins ] * Remove constraints unnecessary since buster [ Dennis Braun ] * New upstream version 1.4 * Fix "format not a string literal and no format arguments" * d/control: + Bump Standards-Version to 4.6.0 + Mark ALSA dev library as linux-any * Add salsa-ci config -- Dennis Braun Mon, 29 Nov 2021 23:49:22 +0100 elektroid (1.3-2) unstable; urgency=medium * Remove the headers, we have no dev package atm (Closes: #982320) -- Dennis Braun Mon, 08 Feb 2021 21:12:46 +0100 elektroid (1.3-1) unstable; urgency=medium * New upstream version 1.3 * Drop GCC10 patch, applied by upstream * d/copyright: Add FSFAP license * d/copyright: Update year * d/control: Add zlib1g-dev to B-Ds * d/control: Bump S-V to 4.5.1, no changes needed -- Dennis Braun Sun, 07 Feb 2021 21:00:25 +0100 elektroid (1.2-2) unstable; urgency=medium * Fix GCC10 Build issue (Closes: #966880) -- Dennis Braun Sun, 30 Aug 2020 18:45:10 +0200 elektroid (1.2-1) unstable; urgency=medium * New upstream version 1.2 * Fix cross building * Bump dh-compat to 13 * Drop patches, applied by upstream * Drop obsolete --as-needed build-flag * d/upstream/metadata: Add archive and remove obsolete name field -- Dennis Braun Mon, 25 May 2020 17:09:24 +0200 elektroid (1.1-1) unstable; urgency=medium * Initial release (Closes: #953332) -- Dennis Braun Wed, 08 Apr 2020 21:46:46 +0200 elektroid-3.2.3/debian/control000066400000000000000000000022711500236517400163330ustar00rootroot00000000000000Source: elektroid Section: sound Priority: optional Maintainer: Debian Multimedia Maintainers Uploaders: Dennis Braun Build-Depends: debhelper-compat (= 13), libasound2-dev [linux-any], libjson-glib-dev, libgtk-3-dev, libpulse-dev, libsndfile1-dev, libsamplerate0-dev, libzip-dev, pkg-config, zlib1g-dev Homepage: https://github.com/dagargo/elektroid Vcs-Browser: https://salsa.debian.org/multimedia-team/elektroid Vcs-Git: https://salsa.debian.org/multimedia-team/elektroid.git Standards-Version: 4.6.2 Rules-Requires-Root: no Package: elektroid Architecture: linux-any Depends: ${misc:Depends}, ${shlibs:Depends} Description: Sample and MIDI device manager Elektroid is a sample and MIDI device manager. . With Elektroid you can easily upload and download audio files and manage different types of data on different MIDI devices, such as presets, projects or tunings. . It can also be used to send and receive SysEx MIDI files. . This package provides both the GUI and CLI application of Elektroid. elektroid-3.2.3/debian/copyright000066400000000000000000000431431500236517400166660ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: elektroid Upstream-Contact: https://github.com/dagargo/elektroid Source: https://github.com/dagargo/elektroid/releases Comment: This package was debianized by Dennis Braun on Sun, 08 Mar 2020 01:05:20 +0100. Files: * Copyright: 2019-2022 David García Goñi 2019 Olivier Humbert 2020-2022 Dennis Braun License: GPL-3+ Files: debian/* Copyright: 2020-2022 Dennis Braun License: GPL-3+ Files: res/elektroid.svg Copyright: 2020 David García Goñi License: CC-BY-SA-4.0 Files: res/elektroid.appdata.xml Copyright: 2020 Dennis Braun License: FSFAP Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty. License: GPL-3+ 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 package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Comment: On Debian systems, the complete text of the GNU General Public License version 3 can be found in `/usr/share/common-licenses/GPL-3'. . You should have received a copy of the GNU General Public License along with this program. If not, see . License: CC-BY-SA-4.0 Creative Commons Attribution-ShareAlike 4.0 International Public License . By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. . Section 1 -- Definitions. a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. c. BY-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. g. License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution and ShareAlike. h. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. i. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. j. Licensor means the individual(s) or entity(ies) granting rights under this Public License. k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. . Section 2 -- Scope. a. License grant. 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: a. reproduce and Share the Licensed Material, in whole or in part; and b. produce, reproduce, and Share Adapted Material. 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 3. Term. The term of this Public License is specified in Section 6(a). 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a) (4) never produces Adapted Material. 5. Downstream recipients. a. Offer from the Licensor -- Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. b. Additional offer from the Licensor -- Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter's License You apply. c. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). b. Other rights. 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 2. Patent and trademark rights are not licensed under this Public License. 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. . Section 3 -- License Conditions. Your exercise of the Licensed Rights is expressly made subject to the following conditions. a. Attribution. 1. If You Share the Licensed Material (including in modified form), You must: a. retain the following if it is supplied by the Licensor with the Licensed Material: i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); ii. a copyright notice; iii. a notice that refers to this Public License; iv. a notice that refers to the disclaimer of warranties; v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. b. ShareAlike. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. 1. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-SA Compatible License. 2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. 3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. . Section 4 -- Sui Generis Database Rights. Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. . Section 5 -- Disclaimer of Warranties and Limitation of Liability. a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. . Section 6 -- Term and Termination. a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 2. upon express reinstatement by the Licensor. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. . Section 7 -- Other Terms and Conditions. a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. . Section 8 -- Interpretation. a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. elektroid-3.2.3/debian/rules000077500000000000000000000007611500236517400160120ustar00rootroot00000000000000#!/usr/bin/make -f export DEB_BUILD_MAINT_OPTIONS = hardening=+all include /usr/share/dpkg/architecture.mk # Fix cross building ifneq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE)) export ac_cv_func_malloc_0_nonnull=yes endif %: dh $@ override_dh_auto_test: # Don't enable tests, if no elektron device is connected @echo "Tests disabled" override_dh_auto_install: dh_auto_install # We remove the headers, so far we have no -dev package rm -fr $(CURDIR)/debian/elektroid/usr/include elektroid-3.2.3/debian/salsa-ci.yml000066400000000000000000000002521500236517400171440ustar00rootroot00000000000000--- include: - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml elektroid-3.2.3/debian/source/000077500000000000000000000000001500236517400162265ustar00rootroot00000000000000elektroid-3.2.3/debian/source/format000066400000000000000000000000141500236517400174340ustar00rootroot000000000000003.0 (quilt) elektroid-3.2.3/debian/upstream/000077500000000000000000000000001500236517400165665ustar00rootroot00000000000000elektroid-3.2.3/debian/upstream/metadata000066400000000000000000000003631500236517400202730ustar00rootroot00000000000000Archive: github Bug-Database: https://github.com/dagargo/elektroid/issues Bug-Submit: https://github.com/dagargo/elektroid/issues/new Repository: https://github.com/dagargo/elektroid.git Repository-Browse: https://github.com/dagargo/elektroid elektroid-3.2.3/debian/watch000066400000000000000000000002221500236517400157530ustar00rootroot00000000000000version=4 opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/@PACKAGE@-$1\.tar\.gz/ \ https://github.com/dagargo/@PACKAGE@/tags .*/v?(\d\S+)\.tar\.gz elektroid-3.2.3/docs/000077500000000000000000000000001500236517400144345ustar00rootroot00000000000000elektroid-3.2.3/docs/404.html000066400000000000000000000006131500236517400156310ustar00rootroot00000000000000--- layout: base ---

404

Page not found :(

The requested page could not be found.

elektroid-3.2.3/docs/Gemfile000066400000000000000000000024751500236517400157370ustar00rootroot00000000000000source "https://rubygems.org" # Hello! This is where you manage which Jekyll version is used to run. # When you want to use a different version, change it below, save the # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: # # bundle exec jekyll serve # # This will help ensure the proper Jekyll version is running. # Happy Jekylling! #gem "jekyll", "~> 4.3.4" # This is the default theme for new Jekyll sites. You may change this to anything you like. gem "minima", "~> 2.5" # If you want to use GitHub Pages, remove the "gem "jekyll"" above and # uncomment the line below. To upgrade, run `bundle update github-pages`. gem "github-pages", "~> 231", group: :jekyll_plugins # If you have any plugins, put them here! group :jekyll_plugins do gem "jekyll-feed", "~> 0.12" end # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem # and associated library. platforms :mingw, :x64_mingw, :mswin, :jruby do gem "tzinfo", ">= 1", "< 3" gem "tzinfo-data" end # Performance-booster for watching directories on Windows gem "wdm", "~> 0.1", :platforms => [:mingw, :x64_mingw, :mswin] # Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem # do not have a Java counterpart. gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] gem "webrick", "~> 1.9" elektroid-3.2.3/docs/Gemfile.lock000066400000000000000000000171371500236517400166670ustar00rootroot00000000000000GEM remote: https://rubygems.org/ specs: activesupport (7.2.2.1) base64 benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) logger (>= 1.4.2) minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) base64 (0.2.0) benchmark (0.4.0) bigdecimal (3.1.8) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.12.2) colorator (1.1.0) commonmarker (0.23.11) concurrent-ruby (1.3.4) connection_pool (2.4.1) dnsruby (1.72.3) base64 (~> 0.2.0) simpleidn (~> 0.2.1) drb (2.2.1) em-websocket (0.5.3) eventmachine (>= 0.12.9) http_parser.rb (~> 0) ethon (0.16.0) ffi (>= 1.15.0) eventmachine (1.2.7) execjs (2.10.0) faraday (2.12.2) faraday-net_http (>= 2.0, < 3.5) json logger faraday-net_http (3.4.0) net-http (>= 0.5.0) ffi (1.17.0) forwardable-extended (2.6.0) gemoji (4.1.0) github-pages (231) github-pages-health-check (= 1.18.2) jekyll (= 3.9.5) jekyll-avatar (= 0.8.0) jekyll-coffeescript (= 1.2.2) jekyll-commonmark-ghpages (= 0.4.0) jekyll-default-layout (= 0.1.5) jekyll-feed (= 0.17.0) jekyll-gist (= 1.5.0) jekyll-github-metadata (= 2.16.1) jekyll-include-cache (= 0.2.1) jekyll-mentions (= 1.6.0) jekyll-optional-front-matter (= 0.3.2) jekyll-paginate (= 1.1.0) jekyll-readme-index (= 0.3.0) jekyll-redirect-from (= 0.16.0) jekyll-relative-links (= 0.6.1) jekyll-remote-theme (= 0.4.3) jekyll-sass-converter (= 1.5.2) jekyll-seo-tag (= 2.8.0) jekyll-sitemap (= 1.4.0) jekyll-swiss (= 1.0.0) jekyll-theme-architect (= 0.2.0) jekyll-theme-cayman (= 0.2.0) jekyll-theme-dinky (= 0.2.0) jekyll-theme-hacker (= 0.2.0) jekyll-theme-leap-day (= 0.2.0) jekyll-theme-merlot (= 0.2.0) jekyll-theme-midnight (= 0.2.0) jekyll-theme-minimal (= 0.2.0) jekyll-theme-modernist (= 0.2.0) jekyll-theme-primer (= 0.6.0) jekyll-theme-slate (= 0.2.0) jekyll-theme-tactile (= 0.2.0) jekyll-theme-time-machine (= 0.2.0) jekyll-titles-from-headings (= 0.5.3) jemoji (= 0.13.0) kramdown (= 2.4.0) kramdown-parser-gfm (= 1.1.0) liquid (= 4.0.4) mercenary (~> 0.3) minima (= 2.5.1) nokogiri (>= 1.13.6, < 2.0) rouge (= 3.30.0) terminal-table (~> 1.4) github-pages-health-check (1.18.2) addressable (~> 2.3) dnsruby (~> 1.60) octokit (>= 4, < 8) public_suffix (>= 3.0, < 6.0) typhoeus (~> 1.3) html-pipeline (2.14.3) activesupport (>= 2) nokogiri (>= 1.4) http_parser.rb (0.8.0) i18n (1.14.6) concurrent-ruby (~> 1.0) jekyll (3.9.5) addressable (~> 2.4) colorator (~> 1.0) em-websocket (~> 0.5) i18n (>= 0.7, < 2) jekyll-sass-converter (~> 1.0) jekyll-watch (~> 2.0) kramdown (>= 1.17, < 3) liquid (~> 4.0) mercenary (~> 0.3.3) pathutil (~> 0.9) rouge (>= 1.7, < 4) safe_yaml (~> 1.0) jekyll-avatar (0.8.0) jekyll (>= 3.0, < 5.0) jekyll-coffeescript (1.2.2) coffee-script (~> 2.2) coffee-script-source (~> 1.12) jekyll-commonmark (1.4.0) commonmarker (~> 0.22) jekyll-commonmark-ghpages (0.4.0) commonmarker (~> 0.23.7) jekyll (~> 3.9.0) jekyll-commonmark (~> 1.4.0) rouge (>= 2.0, < 5.0) jekyll-default-layout (0.1.5) jekyll (>= 3.0, < 5.0) jekyll-feed (0.17.0) jekyll (>= 3.7, < 5.0) jekyll-gist (1.5.0) octokit (~> 4.2) jekyll-github-metadata (2.16.1) jekyll (>= 3.4, < 5.0) octokit (>= 4, < 7, != 4.4.0) jekyll-include-cache (0.2.1) jekyll (>= 3.7, < 5.0) jekyll-mentions (1.6.0) html-pipeline (~> 2.3) jekyll (>= 3.7, < 5.0) jekyll-optional-front-matter (0.3.2) jekyll (>= 3.0, < 5.0) jekyll-paginate (1.1.0) jekyll-readme-index (0.3.0) jekyll (>= 3.0, < 5.0) jekyll-redirect-from (0.16.0) jekyll (>= 3.3, < 5.0) jekyll-relative-links (0.6.1) jekyll (>= 3.3, < 5.0) jekyll-remote-theme (0.4.3) addressable (~> 2.0) jekyll (>= 3.5, < 5.0) jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) rubyzip (>= 1.3.0, < 3.0) jekyll-sass-converter (1.5.2) sass (~> 3.4) jekyll-seo-tag (2.8.0) jekyll (>= 3.8, < 5.0) jekyll-sitemap (1.4.0) jekyll (>= 3.7, < 5.0) jekyll-swiss (1.0.0) jekyll-theme-architect (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-cayman (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-dinky (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-hacker (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-leap-day (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-merlot (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-midnight (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-minimal (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-modernist (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-primer (0.6.0) jekyll (> 3.5, < 5.0) jekyll-github-metadata (~> 2.9) jekyll-seo-tag (~> 2.0) jekyll-theme-slate (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-tactile (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-time-machine (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-titles-from-headings (0.5.3) jekyll (>= 3.3, < 5.0) jekyll-watch (2.2.1) listen (~> 3.0) jemoji (0.13.0) gemoji (>= 3, < 5) html-pipeline (~> 2.2) jekyll (>= 3.0, < 5.0) json (2.9.1) kramdown (2.4.0) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) liquid (4.0.4) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) logger (1.6.4) mercenary (0.3.6) mini_portile2 (2.8.8) minima (2.5.1) jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) minitest (5.25.4) net-http (0.6.0) uri nokogiri (1.18.8) mini_portile2 (~> 2.8.2) racc (~> 1.4) octokit (4.25.1) faraday (>= 1, < 3) sawyer (~> 0.9) pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (5.1.1) racc (1.8.1) rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) rexml (3.4.0) rouge (3.30.0) rubyzip (2.3.2) safe_yaml (1.0.5) sass (3.7.4) sass-listen (~> 4.0.0) sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) securerandom (0.4.1) simpleidn (0.2.3) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (1.8.0) uri (1.0.3) webrick (1.9.1) PLATFORMS ruby DEPENDENCIES github-pages (~> 231) http_parser.rb (~> 0.6.0) jekyll-feed (~> 0.12) minima (~> 2.5) tzinfo (>= 1, < 3) tzinfo-data wdm (~> 0.1) webrick (~> 1.9) BUNDLED WITH 2.3.7 elektroid-3.2.3/docs/Makefile000066400000000000000000000012551500236517400160770ustar00rootroot00000000000000# The project README.md is generated from the documentation pages by executing `make` on this directory. README=../README.md $(README): index.md installation.md packaging.md cli.md api.md tests.md echo '# Elektroid' > $(README) echo >> $(README) echo '[//]: # (Do not modify this file manually.)' >> $(README) echo '[//]: # (This file is generated from the docs directory by executing `make`.)' >> $(README) tail -n +4 index.md | sed "s^images/screenshot.png^docs/images/screenshot.png^" >> $(README) tail -n +6 installation.md >> $(README) tail -n +6 packaging.md >> $(README) tail -n +6 cli.md >> $(README) tail -n +6 api.md >> $(README) tail -n +6 tests.md >> $(README) elektroid-3.2.3/docs/_config.yml000066400000000000000000000007211500236517400165630ustar00rootroot00000000000000title: Elektroid author: name: David García Goñi email: "dagargo@gmail.com" description: Sample and MIDI device manager baseurl: "/elektroid/" url: "https://dagargo.github.io/elektroid/" # Build settings remote_theme: jekyll/minima plugins: - jekyll-remote-theme minima: skin: auto social_links: - { platform: github, user_url: "https://github.com/dagargo" } header_pages: - installation.md - packaging.md - cli.md - api.md - tests.md elektroid-3.2.3/docs/_includes/000077500000000000000000000000001500236517400164015ustar00rootroot00000000000000elektroid-3.2.3/docs/_includes/custom-head.html000066400000000000000000000001451500236517400215000ustar00rootroot00000000000000 elektroid-3.2.3/docs/_includes/footer.html000066400000000000000000000014331500236517400205660ustar00rootroot00000000000000
elektroid-3.2.3/docs/_includes/header.html000066400000000000000000000041441500236517400205220ustar00rootroot00000000000000 Fork me on GitHub elektroid-3.2.3/docs/api.md000066400000000000000000000021661500236517400155340ustar00rootroot00000000000000--- layout: base title: API permalink: /api/ --- ## API Elektroid, although statically compiled, is extensible through three extension points. * Connectors, which are a set of filesystems, each providing operations over MIDI and the computer native filesystem to implement uploading, downloading, renaming and the like. The API is defined in `src/connector.h`. Connectors are defined in the `src/connectors` directory and need to be configured in the connector registry in `src/regconn.c`. * Menu actions (GUI only), which are device related buttons in the application menu that provide the user with some configuration window or launch device configuration processes. The API is defined in `src/maction.h`. Menu actions are defined in the `src/mactions` directory and need to be configured in the menu action registry in `src/regma.c`. * Preferences, which are single configuration elements that are stored in the configuration JSON file and can be recalled from anywhere in the code. The API is defined in `src/preferences.h`. Preferences can be defined anywhere but need to be configured in the preferences registry in `src/regpref.c`. elektroid-3.2.3/docs/cli.md000066400000000000000000000147431500236517400155360ustar00rootroot00000000000000--- layout: base title: CLI permalink: /cli/ --- ## CLI `elektroid-cli` brings the same filesystem related functionality to the terminal. There are device commands and filesystem commands. The latter have the form `a-b-c` where `a` is a connector, `b` is a filesystem and `c` is the command, (e.g., `elektron-project-ls`, `cz-program-upload`, `sds-sample-download`). Notice that the filesystem is always in the singular form. As of version 2.2, **older command forms have been removed**. These are the available commands: * `ls` or `list` * `mkdir` (behave as `mkdir -p`) * `rmdir` or `rm` (both behave as `rm -rf`) * `mv` (in slot mode, the second path is just the name of the file) * `cp` * `cl`, clear item * `sw`, swap items * `ul` or `upload` * `dl` or `download` * `rdl` or `rdownload` or `backup` Keep in mind that not every filesystem implements all the commands. For instance, Elektron samples can not be swapped. Provided paths must always be prepended with the device id and a colon (e.g., `0:/incoming`). ### Device commands * `ld` or `ls-devices`, list all MIDI devices with input and output ``` $ elektroid-cli ld 0: id: SYSTEM_ID; name: computer 1: id: hw:2,0,0; name: hw:2,0,0: Elektron Digitakt, Elektron Digitakt MIDI 1 2: id: hw:1,0,0; name: hw:1,0,0: M-Audio MIDISPORT Uno, M-Audio MIDISPORT Uno MIDI 1 3: id: hw:3,0,0; name: hw:3,0,0: MicroBrute, MicroBrute MicroBrute 4: id: hw:3,0,1; name: hw:3,0,1: MicroBrute, MicroBrute MicroBrute MIDI Inte 5: id: hw:4,0,0; name: hw:4,0,0: Little Phatty SE II, Little Phatty SE II MIDI 1 6: id: hw:5,0,0; name: hw:5,0,0: Summit, Summit MIDI 1 7: id: hw:3,0,0; name: hw:3,0,0: Arturia MicroFreak, Arturia MicroFreak Arturia Micr ``` * `info` or `info-device`, show device info including the compatible filesystems (filesystems implemented in the connector but not compatible with the device are not shown). Notice that some filesystems are not meant to be used from the GUI so they are shown as `CLI only`. ``` $ elektroid-cli info 1 Type: MIDI Device name: Elektron Digitakt Device version: 1.51A Device description: Digitakt Connector name: elektron Filesystems: sample, data (CLI only), project, sound ``` * `df` or `info-storage`, show size and use of +Drive and RAM ``` $ elektroid-cli df 1:/ Storage Size Used Available Use% +Drive 959.5MiB 285.9MiB 673.6MiB 29.80% RAM 64MiB 0B 64MiB 0.00% ``` * `send` and `receive` work with a batch of SysEx messages. These are useful when working with generic devices, which have no filesystems implemented buf offer options to receive or send data. ``` $ elektroid-cli send file.syx 1 $ elektroid-cli receive 1 file.syx ``` * `upgrade`, upgrade firmware ``` $ elektroid-cli upgrade Digitakt_OS1.30.syx 1 ``` ### System connector The first connector is always a system (local computer) one used to convert sample formats. It can be used like any other connector. ``` $ elektroid-cli system-wav48k16b2c-ul square.wav 0:/home/user/samples ``` ### Elektron conector These are the available filesystems for the elektron connector: * `sample` * `raw` * `preset` * `data` * `project` * `sound` Raw and data are intended to interface directly with the filesystems provided by the devices so the downloaded or uploaded files are **not** compatible with Elektron Transfer formats. Preset is a particular instance of raw and so are project and sound but regarding data. Thus, raw and data filesystems should be used only for testing and are **not** available in the GUI. #### Sample, raw and preset commands * `elektron-sample-ls` It only works for directories. Notice that the first column is the file type, the second is the size, the third is an internal cksum and the last one is the sample name. ``` $ elektroid-cli elektron-sample-ls 0:/ D 0B 00000000 drum machines F 630.34KiB f8711cd9 saw F 1.29MiB 0bbc22bd square ``` * `elektron-sample-mkdir` ``` $ elektroid-cli elektron-sample-mkdir 0:/samples ``` * `elektron-sample-rmdir` ``` $ elektroid-cli elektron-sample-rmdir 0:/samples ``` * `elektron-sample-ul` ``` $ elektroid-cli elektron-sample-ul square.wav 0:/ ``` * `elektron-sample-dl` ``` $ elektroid-cli elektron-sample-dl 0:/square ``` * `elektron-sample-mv` ``` $ elektroid-cli elektron-sample-mv 0:/square 0:/sample ``` * `elektron-sample-rm` ``` $ elektroid-cli elektron-sample-rm 0:/sample ``` #### Data, sound and project commands There are a few things to clarify first. * All data commands are valid for both projects and sounds although the examples use just sounds. * All data commands that use paths to items and not directories use the item index instead the item name. Here are the commands. * `elektron-data-ls` It only works for directories. Notice that the first column is the file type, the second is the index, the third is the permissons in hexadecimal, the fourth indicates if the data in valid, the fifth indicates if it has metadatam, the sixth is the size and the last one is the item name. Permissions are 16 bits values but only 6 are used from bit 2 to bit 7 both included. From LSB to MSB, this permissions are read, write, clear, copy, swap, and move. ``` $ elektroid-cli elektron-data-ls 0:/ D -1 0000 0 0 0B projects D -1 0000 0 0 0B soundbanks ``` ``` $ elektroid-cli elektron-data-ls 0:/soundbanks/D F 1 0012 1 1 160B KICK F 2 0012 1 1 160B SNARE ``` * `elektron-data-cp` ``` $ elektroid-cli elektron-data-cp 0:/soundbanks/D/1 0:/soundbanks/D/3 $ elektroid-cli elektron-data-ls 0:/soundbanks/D F 1 0012 1 1 160B KICK F 2 0012 1 1 160B SNARE F 3 0012 1 1 160B KICK ``` * `elektron-data-sw` ``` $ elektroid-cli elektron-data-sw 0:/soundbanks/D/2 0:/soundbanks/D/3 $ elektroid-cli elektron-data-ls 0:/soundbanks/D F 1 0012 1 1 160B KICK F 2 0012 1 1 160B KICK F 3 0012 1 1 160B SNARE ``` * `elektron-data-mv` ``` $ elektroid-cli elektron-data-mv 0:/soundbanks/D/3 0:/soundbanks/D/1 $ elektroid-cli elektron-data-ls 0:/soundbanks/D F 1 0012 1 1 160B SNARE F 2 0012 1 1 160B KICK ``` * `elektron-data-cl` ``` $ elektroid-cli elektron-data-cl 0:/soundbanks/D/1 $ elektroid-cli elektron-data-ls 0:/soundbanks/D F 2 0012 1 1 160B KICK ``` * `elektron-data-dl` ``` $ elektroid-cli elektron-data-dl 0:/soundbanks/D/1 $ elektroid-cli elektron-data-dl 0:/soundbanks/D/1 dir ``` * `elektron-data-ul` ``` $ elektroid-cli elektron-data-ul sound 0:/soundbanks/D ``` elektroid-3.2.3/docs/images/000077500000000000000000000000001500236517400157015ustar00rootroot00000000000000elektroid-3.2.3/docs/images/logo.png000066400000000000000000000056541500236517400173610ustar00rootroot00000000000000PNG  IHDR@@iq cHRMz&u0`:pQ<bKGDC pHYsodtIME  2p q IDATxil\W8I%-iaQfE(b6+BT*B Bۄ 5P-BU)I؛ 5KJV;YNu8N$d'Et{|;9C6p ނxѐlkT\?}y@7Oa̓-^j=M",Y3'24wr@Djv` 뒖v:wO@M!Zw`"_ױ[7TB\xڎݚQmA/)S8 B,D lE*cC7ehT m܍&1!7R" ?[N0} Ǒx~ eʴb%U|~D>#}@c, ͺdO> #\zOG<ت;-7~w^#JEE$Gx-ׁ̓=:6dɞ/|،Yʎ xS t07 9QftP,FЃV6Ѝ_!!+H]sB1Vq짰+z8䩝tI1ej3.P>7VxQ' K@tl]7QZۆS0B1znqQwACn3m'I ORFx=OCP0CpQV(}! Iܦ/wLXqC8 ?!#"v>b[vg(_ x 0(NdqG]NƎ{qHJ_7 G;ֶ؞y?b-6kSTuY#}ă 6l< E~tŸlm`V>-|(| ი0(\eji³{l!+UDi34*|_7g7lZ0TvfɼXLsZ|%NjGQM*||oIx\><<`2YWs;3mE 4&ӜWI̩$$# '[7x7 = S}_K;NK]pG09{)V%$?'z\҈0[OJ_ӴLF:1#ؗ Zʝo$ȮfK!zRǶs2m߂E8D jm 1ԍVW7&R/ZU[ 1[4Y̭ x''}G-vx|˺U1#!6Z˦PXԙ6[m >tFbTuK f5\j&=}ΨZhja~U~Q Ib g2uu.%SW_=;<B.d|u.PT@nfH7$did;AT @Q1H8di }:%?K*mfGdHҥtT ? YP?;%5I2!p4$ cj%fg ԭ_ls$$¤d&l!|G1U -,<4C`<>$ȅ#I zhRW+#ļ̫Uĕ -f:3ΟxmɏMM1d24K Xj;PWќavt,]=<{~7| MM8"Z@7 1A ;vFv8 hSC3`->i5@}DA&LV`S;?Tum/8=GMQ bft6Wt3#'YsfJ[;a@ b/GNP 8_ P}鮲ɭbC C| |C!oa:&tEXtCreation Timesb 07 sep 2024 10:09:54w IDATxw|]AK " D \" *CA@Y"Sdm6~IzIi^I{{Oy͓""""""""""""""""""""""""""""""""""""""""""""%ǏODDDDDDDDDD):p LZO~Mf+̤5QRJ,^&$IROhf8ui-d6QҚx.NT٥ R2E$6Q(*iu%M7V^:""""""""""*;j g-|M.*]zx%JN+:ZS2[[˱;I.vۗd䵷d[oӒ\.j&J*{JX%+NZV:}QHqZמE=Vq&"""""""""*.XTnRDpQIdOhO}=JƗĵ]m_y[B_T J^/:}u?FKS[V)\vnt%!mZ}ZZLfilvmĵ{::r-.VK$;t[Ԩlc2qMDDDDDDDDDҢ}y9Z/y$6kDvQ lobjIiQ德dDvQEs휤.Hb n@DhlD3I4"ZmRT"q&eۂu">y[AXKrGO[V @hz&"""""""""*]Xd9\dhmo1hR+z휴POuw􉈌L 0MDDDDDDDDD E$Һk05.@}PT"Ga5ǵc#c5j|ӯ H1b6CPDDDDDDDDDDTANGhX#"ct󭝞믿u4t_v[!q^ϣ]}[ 6zJ\, 6lm ,ˡ(XDDF!4,ҦmG<@M`{Kdϫ [$h~BՒdMhh!! pE'VM`%=6HA;n'ek"""""""""+EQTT,'-^.:}t>{} WvTZ˅G]9sBR@*H$;':,B*Rjp4}* =Az xKrkIjuFDDDDDDDDDT#mV ,9~-zB#` qP hVL7V{?vQӈ%ciR$lV3׬Jvd^O@+-˲@(\"Sj|yִ^y1Ȓ]!>""""""""""M VvȰ,ODEGAf8|`/ !  T$$Ւb'&DtDEf򚈈ʐ(9jԁnEvAP5&NAk1xA a%g\vTUԱJ:n=qL_QYf#<"k' <"d(@ #y׀kº|BӉTgKAZO .֤ 2 = ֬vQe / 8 2+kR#=E^ʎ`D%d͍Q)D\1ou{~(h_V-[\UZ^ڼ]W/\2%b+TrsШA {A$'&*o1WϩS?)lc6oE_/]71tck$&Tƺ "9) oNYwi6\@JhբP<!K%c=FJ5IDDDT8/h? S:k/>A0i;IԪY9ݧvq9G_Q@}B)D^wY;3gc?Ѿt2fz9,_N]wMmZC{ԯ u2jj""""ܭZ6\%%$8S._كxf bB#I2 <,̧chLn"&cO+W31iTNK˛'SڄW)6PK.BDDDDT1J^RFJ5#G!&:իVu,Q^<>acǮ=mz`."@T ؙV w/EAרSj2`מ}k.)g(,Sg8׳OŬSQfMI;קXJKi΁=|#"8`0 ./½=Nᇟo7!=2L;rĿ;+@8<ܯ-Zy-BSZ%?3%͚bDԩY w`0^;+@kA;UԪy ؙZ??v \[5 5}*}~;϶);"Zv8b'Kh٬= *aÖG$ԫS@\];ߊ~ǁCpյ N:?R`[pSQfB/0ndrه]{p>V}Əy ?AQ$<,\!"""mڛS~Z~ei٬ȸt7]+CΞ>Q!znXB`tZDEoC;߶<(Y!2LY۠:Q!bUG vkϿo 9-Ӣ@}l7e1(ΖNj83}ڏo `z*BCy5N!b̺ZF+vb """"""""""R)DaAlql>;DDDDDDDDDTV[S[l!"""""""" Ag[0l""""""""""?H Q ]Y 0s]"~K`sp<iu:=&#"d(8u "DDDDDDDDDT ( Ȁ–e3ҡ3 @fXxG"""""""""!/I,"DJk N$I1+NRG:o&Hs`Q!($ 8v PO((N 8DDDDDDDDDT!\0`!4 zC(J??\G`3 &pNb QuZ%AS0y;&B)H (^Ob`$DDDDDDDDDD 8r%;'-&"""""""" /"DDDDDDDDDDDiס[M:UBDDDDDDDDDD&"""""""""6%&((QErp_*6^u(PL\Isn.dYsDDD/CXxA j@QJmy- DDDDD~P.9jJ-VN.9QE%ȼzgO9ׄP(!~8 9PP{-0MDDDDT9F#e]1*7jEaY9QYDEGAf8|`/")/) qz@CS).!1MDDDDJF:TEQ5E]CTMK!2Zb'h{T*@'yG""""2( dYٜ~#""Q ˲K_ ,j`9*ί@l""""2TNQȒ A? ))\($8f_*x-DDDDD~$@GDD_% &tBG`1+1yZ`'5}s9Ge'1MDDDDGAKL""" BP΁ DDDDDDDDD$Oұ!]Rt"Wwt ;ݎ t.#f,#"""СQP)ްa?^tG,(dYƊoźS'Q9>>ߑ#]}-7+} Lzc ~ec-[4w(~y+oZ( BC5UZSETZuA^ڎr<;t4^ޗ+I{Mzc 9qW 0x=c51)QOp<6۴7̙}zߋ޽|DD <a?xu ]uF4FԬZإvnJ2;u_~\SFF>^w•+WW ͛6#G &:1uedwO b~D(t7ݻbSO"%:moN8t}N9ώǣC&?'`ںuKmgGt2IKë/R|6'N?aO<. [𺆚ս/WE>~۶mMھtr1 EDQXK۸WБ=o>ΝE! !" NBփC!_}~QU`;vې<<>#fbw-1|Vu]uDƺV+"]; *UŋknDGF}uDDDDD~Eq?on vGklnf} n}] p,kL?q@/йYQ\ۤm䩼!Roo-.4 G&PjU̘ڴn( 6$A$M|o/drke˙4޻+}r dbʆX=!{#W7\yj,̛s;F ~EkU#G>,AQԮu ֭Utc|g׷Bkp_qIy?|g44oUUw:ތ~:ތdrmسgfϞVn@rr.|\tUp-b׮]ņwލ wgSbʯ[ O ۟_5DS#a4\e֭;`/I;Q>9]GG`WWޘ(gZѽw_̞l6;!Y f}02,\HEaP)691Mrۭy6w[(.qy(mfÜ лC޻/N\jYɄCŢ%/ĢOb xwl#vz<=yt ;vdrx(&.86b$,[u$jlxxp|%I¼w0uL4ig*v~6 ϝ~=Xnnw݉Sigwߟ.~}Аmm1΢,wİ#{Bz5[R&Xt)>#c;틄S7gᷭ[ㆍ`l?j׮:꫕زe ?^q9K`)ؽ;m܈n{ 33X3ύ̫xo cѣزy'/˾cǎC~h׶O숈SH;w/{Z͚ހjí7ߌ=ev[Xg~\S:R 9) +{<־}TY,Vdffjrժh4"''ק}`a5,]r){̙Xc|x]~\dkѠ~}<6d08y]tƎ-g%o| ?M ӥظi39/^p|fDAZYGi2`cg*ޛ6-^A3iiPy3 Y}-3 NéS}n/ }3yٳyƶTj^*۹p}>l( 6Ç)^EPO=N"+2 7~TQ"msv|ޖF ^:xrX,]/l'"Rw+W .cֻE8{/e׮#W˗E&={dgWѫGw[̘v[f\$v;N}Ϛ-[ZjDFFb`YxL4nkG  ++ QGЬY3$%%ѣ( =jµà¶~s9G۶mPZ5[HLL+|:l,Z^|^:&N|jr_~ &MDDDDR?٣;֮0=/4zd1d IDATeg㟓'@R1q@]{}ve ޚzMgΠGTg\DDdeg`Uҽ˲qf2mk1k~C#<<1QxaV`Ɯ^xVV7"dʆbvأ.z zX|+L?)ի">.rsseԮUsvGb\,tf|^z~~K*(r)#6m^@jUpm׬?9O8 ш믿жNfC˖-"##q7!]w o:M&@7(m۴c|:cGBe6 Y.|*.YS{$#<<aaahղ%v݇Z5k`: <|؅W]O,\3.c{c QfRl%,9gJq>)gb΅n/TtZdY GHr#>V~ x6^g]nGZ5!2@4iϜqKxSBϞ;IQf G 6_j~~e# YYȸrVͥLq]Xh(^|ŗx'uXxQ6DD%eOl+Hڬ(y$96k?N+d.N}[bɲ/01{WؔUFS6bb(@)$AοfCMS{9+RVMpԶ z}'Z9?kE;33o.3 I`4wZhhԓ ֹtwTtq:[MnDRR5_ Pd7 ;SSѾm(PP%9 ;ǚ~ނsϣik0Цuk٥cnHwሌ@ZYԮYӱwyK S a~r|^\@N~ZpN>ϖ}CXv^g 2lV+ AGhX*ϝjη,68 _NYy FٹYNӧE.Tǖ-[q)L& yf ^8 lIp(F""""oKH|7]EBѬiS|d)ڷm(ҫoyteo.\7&f3fcTgKnێϗ@zF[7mF޽e|9.56[bq,sCQA`Nj3u7dYKpQ:EA0|PLyg:Τ$%%"u>\pfg>s6>W!>.7L}EyL&?똆=w߅i3CqJ&>lc_BBeF|+\|?G]hWAC ļٳPJr1ZmCDTlV+?8B0(kŔCݳ?-f m[UY=wv!`vڍsLY|s<|oU/>SlݶW^Ţ%[:P>KVv6֬] /"+*mሉ-2`{͖TBcǎC.jyfhҤ "1};xѷ_l6t }JӴ t &6mӔL?>nhU`РA.S? 7noW+Wώ3gg<:7UP뾟EpsXh|]Q͊[;t[@VE,˸p"$'߶myK+|$rLHJLpvx4`>,[aHǥUժU.Z4oY 9m:>~'A!,$>.">.{][ϥnà}q_x0o ٥3~=:-7[9L)>EQ0fԓ`Lx5%;3ߝYrs< jը͚`3 'iQOa朹xWEq{y?Wv9F}ƫXgXh1Zmol pn/6 A!?,NzsoKR'C[ah`ziDΙ!:pUYY2Sahbdd=I1a,S۶[FQ\{NаAߘ;ݍ1wH@&`J,&l"hB50u4^~;/ӢsZ !o[昌3F7cذx #a((cI?QAb ߋEF 7@PHh F* ! ɘnb^o@]LPd=7&M8tzBue q]XxzCdGnNEuz=BC!̹y# !0 Df߆mASptzH@hhtMa;]sv ^3dbqI6S^ ש :?CHh`XvdY˼QѰ:୵mS fs}/Խ t:D1ob_ !.#C3 TCAwh19 o˂O _.) kB .kyQJu nli cU۵ECtz=Q$j8ރQѱ1e; GN\܏z^ $ K.,("$4,BxT.b]>KYDdhXn$EvZK܌&"""";)'XhOj-sf-Ic.LΟfCF\bKvs?8{\rsnh'm~ jA xHjy<ӓBu* \BJj0uPTcP [[ҺSq|ADl H3\~ 9ZЬ)քxGd CdH"H b̞Q?faw{d&}Y$YX1MDDDDOdp̜6:Q/Pɜ:}Τeȸr > '"*4-K2׬Cwaм 鎰;˧2{Юm[`6f]5"?R8UU` E\\\ť)'K}ޜCجV^k1MDDDDOI)"nw\8*O#' 1Ut :""" "}`'h-ρ?&""""Q'Be"ǑȲ,&X΁JGI^ l"""""? dDDTtC!"""?3L =X EMJSSDDDDDXOjA@l\<.gCGEDDD$2.g#&K &΁Jk!И&""""*c @EGF!":GGː$)СQ$ W._(Xh@M0Bq """""?(`W9!!_83'$QEuFJ:t?Akt l""""2VPb*#*E-USkQ\q.~8 TRco^ 68E,@A2 !i6~8`_"p-DDDDD~v&*"Qޒ'7N-uS>k41MDDDDG >"""*yd?þNlDDDT畾`*z*~BY4Y>0MDDDaJEQ4qzV$"""*-8=qC$sȸt9&dY t8DDDgCDd*'&!"*kYEQ( ٙ~ \DQ%$"*:NoƩDDD]2ΊE;\H5 :6:.!I̫H;bQ91Y\Ag.9jJ-VNnd#=}\(ܩc?N_;8[N`]p(Ni0߆wmc2T ǘgNaADDDnTTKQhDc$BU_ru߈3RjуRѰ%""2~oDdhXn$EvZלqUx"""zԬKϪRQ\HG`AE]CTMK!2:Fuqz{þ/`q8}&1GcBtl`KL8 W,lAxDD@ƭ( #"a5ABWa?N_KDDDe!@ Y8t$׋8_[dB_( @rt|2b)oq}_"""r~ob$6/d99@[qjW$"""*-8HqC!""""""""""RDDDTnEqzӖ$""" ~)/4Yq0MDDDRHt7g%g22sĆ hVMD!hRsQQ@qw/a۹ʕ`%e0MDDD`6I߭&׋4H{Q)BPtd q"C%(&pgCC `Ȓ dƷl.Ӎ ~9"#v̀'nb!g\Xtmƍ=&I凟`Y#cC>5Dht Ci`z?_ZpZ=? r]뮻0uT@֭8"uq2uQyR8n]Bk8|Q³j8 „)k~Ž d`q;^>O} ƼG&Y3xcV>M㒱bx0o0gڳt8A -v|qWʛf|p9 >kFxx8jժz/_!!!hܸ1fΜ I ե^r%u놔ĠUV?>6ioߎ׿3os鵮pעwطo_s歭AݟG_]9j /Zj!** ڵÆ  {n~툋C믿lZ@wK3k.-.5x䌌YH'O"0{ _@N;Hs`]#"#Ν sd8 Bx8b*ס'<3 Bx8̟-ieԞe\%%I֭[q뭷:%`L^Ο>T۞X֌LB=ɐpG&tet,}`6~|#W%)qzpW }"۞e&cP9JC$Df={_0kXhѺuk| ϣ/gҤIXz5,Y;w}ѣΞ=ȑ#ԩn޽ݺu]w݅={8hDO~2C:{{aߵoqwq$}`O {b"F C_jޢ)DEQ#,qKDDDeA)Aojgo-9ęnyؒ ,eCo 9Zdf\U<ŀwz"TCrcRP%B=Mu(,xuX(8ݟ7mCm#Q7ߑ"jP7^m"#oG7C/FUv܉cǎa>$''Cll,y\rSL eoٲeذaۇG͛̊oɁoz'&&CQF; `Vϣ{èQбcGi_cǎٳ'C=#_xbƌXxz(8%g\FO=oFNϡ%N%kW܏> |̓砩=c_| Bnl}),VŔ z2BFRnX7mwRJ@G!_w-6˿{ņ0dx/V"x|=u/6mڄ;::aiQQQhѢl&2|M4hqqq޽;N8޺ukhݺ5Ѷm[Cƍ^zҥK}V+ƍ5k")) =F8V;ڵ ?#ZnHԫW/nK,A.]uyqV+y\{@ dsZnYf}A6mcoQꭝ`ܷf(E c6#C =yPއ6zL‘2t;z Z,˰l0(f~Oos}~|YЩ~^WxocB[\Z233Ѹqck:u*&O˗`0'>,z{jwEU~ IDATv;f3N_}K;OgRg _ׯ R}O<3P}՞@;ӿ>縷O||<؞˗/aÆu+V@߾}]ׯ[c-Q&_OB:pҁpȗ(K)'j^ `{g]KJDjЩ{=*yZ5`o~~oHS[i*w l0?9sh۶-xXVyԕ+WbʕصkBCCѩS'vX~=,XcǎN:p)^;w_|Q~ԨQ8|0v؁T?~=KLjqzr{2dΜ9UV9:{Z7zh 8[lAUvԫW| O<#r,Z<~֧Z0L.nX$8ӧ7o'b0a ͆9s8ʪ=׮]s iM67ߌ~gΜVΝCժU~9998z(ڶm[d]>_}KWYW,;~~(Oaaahڴ)9XPQJVjM&c9ǽ}L> ǪUpcԩ_> 77[K=Gff&5CDAć>~كG@:r Mq= 9rʍX/^[D?8,:c7soz#'N%Sc*{=$&UyJP{Rn؊`ͅ:6C 7܀$<8<= łӧc޼yhڴ)ԩO?YYYo`hѢ1vX(cǢvڨ_>u `ҤIHJJBJJ ^uZ8=IKKjEnwQ_-ͦWBRDD΂(rNN=ˡX(**vDAj" -!!mvǒMlI6FOH{>g> 8#G=?O̝;=m;gt"m۶N yUc;Tq:_+~!gܽ`00zh8\wΫy-++ _On֭f͢,8ׯ&Mb̙3ޣnl8\Sqx@~~>/gfy};DT2vz=&W_ !ޔT9y \/̎Ơ20 FcNY:É4M\;9Q4C87Q}ȍD{\꺐X޺,!Z?Np%|M/^̇~N[úgsu F}Q;ω' 5b?s( 4 3g;w/o)))!; 7.`mi4f̘nϘ>}:zUN:Uk@5'<5u?>| {e߾}DGGӷo_p kW:BQTLż{gBݳ˖`c{wQ*n+diJQ@{o6۶]>X{o{hGogk#{]/TulES(\/a2FTj&+5mj^͋BnJnn.8q8̨T*֮]g}Veƌ\{~o) 𶝊 Fɓ'U|W^5ERyk_/<#o%&':x{Zipt8nnG)]l2a6,Nc뻾{M&*MmuC]u;?y}giE\w. %/F#/BӜz7;jf̘w}Gzz:|{wMII UUU`KORR_u+ָhJ FCߜ9s ثVrҒ맦bٳgn{Usi?ټ+,]޽{ӻwoVXqӟ@dd$FšJGB8 \usd#{MhW'izo-\oaul?j۠Pz?:TBƍv;;v`РA͊!==g}P}8q"K,aӦM|'W^~8k5cǩz5*i6Ƒl lw'11.Y1j}Qx ֮]nرkƍc=zcǎꫯorIL&=8הqxNJJ +lٲ& O?ͧ~J~~>O?4JS||<8N-~!FId5/̎B0yt:)xav}Մkڦ睿T垼k8iXJv*+ܷ.Ҷ_toorۻygj|8Ç祗^&++e˖5Hָ5ETUUQXXXo2 >OR1k,,XW\ᾱ'-륥l۶  /h"m"q:a 2^z1{lmƩSXl*7p{z?g}'Oh"V\jtJz@.Zm[t1AQ}֖J^螼kmګ8+W&oG5sp1jB0v ?Dįni6c~Uʦ]O]q=_iFw^tCQQQh5^xMu])..f-]Os}ĉٹs8}YRSS0`^z)ݺusWJJJ6lqqqk\)oӧ< ӧV Ze{ʔ)<ٓףѸ.~x-[~˶}OB!CN_K7F-Q0t8\pDҍQ~8*~>mom# ݠOr~ 0;xz%0hm8تoWoeJ*” *-;7ë[ӋM^H'|.3f`2[;v,t є`ջcccXp! bܸqlٲuѧOh*j5~-O=Ǐg̘1+ Tk\w4"X-ZD|||~M7͛ޜ'-뉉yv\s?"q:Sh4֬YCΝի< O=wq{CW_駟2`/_Κ5kׯ_@!BojZp-Vƕnz*5-㧐/zTu?β2yYZq;NX^( 6Zl~(.C͕RQJJD$|. _r9Bw(( z<ը ~;)L:S>Ss?*+ =k5//ޱ*qJ#G䮻b޼yB)cF hw:8v;9~G]w *=oq-{v LQ4Dk_8<~|߂'@au8w//Ar1NJd,F #Ttc${+* FRBPʑݎڂ+p^ ^_#W}g]wgx]K*ɿCVIq8_W [W=uӭaڲޫ/[ ݼ_6~ ʤD쇏`ۺkKpJL +`YWWSeyزQ=^ޫ7D,2j6^grԙ ZCqw>JBњB/oy(5``^3v|R(PQ4%xE7GO8g闢髌j8mg ݎ> /̎⑏H4*C\I]e$:[y'# nG`;랯T^ךOK)A??<{E=d WOGw-fvD[!NsbixY{!B!~,3zsXQܞ(p8M\MJ Éajl/tbjI!B#L]6+/X5uZljo!! Pgy+UjjN))~іWYVvCÔWTVa!tNMm\-_ClHW!3šN:aP4wVo E7l䍷ަնp8oXzN>CDD11QT\jvffzkiޝ=zSX;^6Xu.mP9PEn]##E_{8}Ryu;32h\2bw5>c;ظi3FTпo?F vʟùGp:חÇ7[oz9JFf&%%h5crz*3w"\l8ĄFźwߍKwV)f KyDj6?MkzcrK}|-^*W|W BAjN8yڢH{}Vfa爚Mk}/^l6s1ZC M+y~/5PS6޷6mnΨ#6 !B'u!Cx1zHt:;224pRqQ"#tɮ{^:Y?qhL&[o烏>nc)*.fͺoݽIY-?GRb"?qY)=`7mfSÀWԶ;P*uLAa!_g|V!22:7mLE_{ޕcСAχҲ2l6 t:Z,?Nll,UUfvddpqc`V6G'&&ΌL;:e[L&[n7^ӛSOƙftJKs).[[3 `_)-UTTnNIIn~wabBaaaqzáw?{/ S'***9zXQhx IDAT/8 Đؿ{~JrEB!D-VeX~ܲKmj54Ҳ2>ǎg^mZgDT}Nvfdҧwo.0>XIqI %%(Ppqһg8Kii)m碽5l$)}]Rd|q#?>!WM'11^:8{n=BQq1#..6PVVWVY3QTؙ N>Mz97BT.nΩӧIůu :~KKp80u2x0dgF&ӯFO0Փ;w6+MFFjpy;_ҊJehTcDz`V6cBT~6:{b٨wu oҢ"vCyK57<8;wsɡ"z=mwm(5fd:\PI_C sۿc5/œڽȅFh_RB!%u ~hXV~6 w/--/$2ċ."6&wR:f.i=zƈVNgmO5O,6|[tT BRQayǪɆzjf]?ǎqQrrsiu}_.2Yl4 jnvz'OPSҖ>g6>㫹y _ƎN3gΐ}(޽z6{?C0-3iiۧ7}%Ni~OjaM8WTV;xO߀dEP~.ڟ}B!:p1ˠ(..7虼v)NqkbQ(;N#:*=燘$Gsy Vß]sZw 8`N߭AODphc߆ċ/rZ-(* Z<ݺvt2?4u*-+c(JF ֬4:[=uI߱O(X_Ɏ ߯j_(+u'u_!BÆq( Q$8@~~A@czb0߯{O?wTTTR]]͔ɗ(mѱĐֹ3O`GO#TVy?;.68Ħk. 64'Q#s xoši)*,"--Mʾ?ǯNm;vڙ֑N`v6IiqcЧwzc!kM(J+8`Q-jt.l{*o}*x h' zN83`_m}^sj*IIe$Ļvt?f (6+F߁bU$%&r] ^^1tyTPXWW4TXXOv#nl=HW!;'ZcKNNfС(Jfea[/Z Ը1pHJ?ٳGmʱINJk&***|IYY>+nZu\ͅF@Ii ##INN ھw̅ٷĐˮ={ 蔒x" ~fCهr>.]kjD9hdԩ$&$=z#|itw}i?"a^:OB!8I8txQΤ3s?5~syOߝѾ{PӁ==ӄטI`$C?| Z-t:78b| e[6o!LB!AIy  L6i; יu&gFqB!B!B$ B!B!B!B4` !B!B!IaB!n;!B!I[!B!B!DHl!B!B!!Ic3LaO͹jxSwg7Dc_B!h q^IW!BtzCB  ~nu&G`QW&wB!B+i71!B!Zi !"B!B!"4IB!B!B$ B!B!B!B4` !B!B!I{ۓB!m"Dv{ B!D ؾHB!8_HB!8tnul{2mON'{/BRv޺=/}t|xwFZ9*9+!/b)5_Zl[~Jdx;mOb9jmF,MjqMGNWD]I|h'ޞ}t~TQ,ućqTDc=Lf}ɬĕ3>WyVühNyT3)O$xcnӵm~ W+h~L> 4}Fd*S5߁9w:^_[$yx}(nK`X+[VܱFޞG:}<>-*gs󪡿\˲&TOmO˫w$rXc4ګؔj_y9oF?v'RZ '&uzd&Ѝh=$-};IxѣNC9ˏ3+8;iۗO!usoim!VFF̟kd&U/1 1w*D睛ǟQN3ԓOHh/@u_uϝ>~"t9GQhw-՚;d*z2iY-EV00UJ蛢Kֱ<63b$J8' 'B`twTHײt5eUٚka\O06WBkx`J4j6qJ:/-hvcT%'-ӟSaq0(UCQcZ MΈZS%6Yw?\t-/oKQKVSnq69j*/S^:I%& 5q|%r{PJ1zU1|=^_SֺĆ,~QzǼ%dY[Zuj%1*_[ʱ"*cӢb9LT3͍kl4,3Tכ@p5h+itc._QP ,i(/D‡q1 b; {7H᣿pU$3@~*:$p!Z%ݙo&-QY''6JBR),pOtk\z],S/yva)DN8^dcXGб9Yfԡt-[묫+[[ԷB`a {׿'kC['N|4?{&EU|ү=qx(ŕv”wE^?=ʋ2j#J"xqʢ•Ꞷ5DꎯsWZǟ6_8k `uj'[W|D0.HmctR okXl/5HԃQ/kȭKVߑZC `zO/?KnR7}KQ\ooF#ʘ(9yӨz۫s§^P:ss ˏ0+WGځHC4C7Jɧ(?-!B1z*Yޢ:lG8MetAŊ(_ne~ p`?vCl%X )Q*qfه.=&~V>NTDžqguYRcXpjwrƣq㢳|!=qx>#<+o,oV̌zA j.nvrΑBؾ\::+`uC˦CfS+ɵ{m='k{N_6@,cszPafRұflFΌ]&| |Pw?]N .BEI᫅| .lC4-1KS+H 瓒?mWy|R /rq/-XQg+YqɃTOu1?v.ŕ[?q'SWݲ SWrAc"Zew&JlˢY~cak䕹mW{#bbjSPԜnEx8n]dd6jv(g%WPG{t@E◩X#&p1}eW_>K(˳Xz)t:1.# ~>5"fϤ/pjTwfb п)B)Q%$`/*&9s3?'}XBI}-Zܢ4Z-oKF־uN%)_"϶_dvK~' )Կ]}6qՉAڡ^XFqev4YIN%6l.TRˢ1h?cp]czxks*b]Fvs5ms0%dE螠C߸ґl9lfh- \ ;kٚkda3z҈Zv{Lcùǥ7X0hZ{cC(>jNhTR)LANgEBk҅#|̜5yq$mc%V'?nt?u Cc\?,PueG3y=7E2!"TS诘Q 瓶o'K~ v(MAhG MPo_䘺e=ʨH=Bz j8˷U5]F߭ n\c<%VR\_;f !:\IAAϱ闢ڗ= Ռ%ƘZjԱb[#jynmجv't} tl6cpFA5I*v_leQ~3|Eu8pAY+ gsk -9.cj&5z)Vv$~8dJxL鹸csY34\?xH0x|Z4^SB/ *\w c_Uh7|vt.K\ǺH>+{plG9SRDr;H=X.OO]iϬ.[oZr'OͷZ݆u}gM@ǯm,gD1gw%2<NWuYmcsu yO=05glYWS]Tq诙np1Qn[`޼N´v?fb4]9u42NC_a=pGk,ueL )#]=E~Ӝ}$2a\RZKlvm;0}͙fy|חP_PF0̞Iwín?#Alnevb[ gb]..zY<<(x o)F8b!=.# eoAߐmfx Yf ؓgr?c~^_͋\;£Mɮ !=.MjڦCf~?=(ӵU QJ 9=$wW܍q9Y-ucVodl CǧE3l'CR>cqĂQO~)[c??63,]K$u<.19}y#)rp5QdL- -SU$3݋sCV;7 IDATh.$+/Zy#*wd/Q Ѩ91ۜAͫW:lW%FDpZR_` eA}Pg؎o\;xʘhlLX[1-ӷ_JNrӲƆ;vp|V׎b*/WN ܐy4A !cZ=+/Ǽy{gwl~Y]4 I.#a r; z hV)hT)2\%}zahs8yrɨnZ R\v"Jn Fd=T@06詷!̬v"ໃU<>-5U0277Z&#;ϊᾹP׆l3NoVyt;*n?ƽ|;*& HQqcQx_0) VBXs]'y"~;}8R` t\zˮy KCWj{9ܳFF0'FpgȰ?-<띃v' pHQD6{Y( 4j=i$Ewr$^R{SѕExsWKs;x=)_3gePev*_Mr );)l3n*4Wif z`kiCrl_ߊ+~A;feS 9YZHcb޸^HW\N4F`%8-TIM.ț3$a+(#X^b w?-~A9;69V d_{ؿu^fi 3a)8+7.?Z5oq=o[pPSw sy̨h{IYgRՙs9TYo{ rۓm6磵GE!8!"oa q^ͼk'[ZOʗQr*ޡ!B]7  L6i; יu&gF]bitVS븼O!x-B!Dр-h=UNXQ(c !B!BӡB_Aq3 B!B!IB!B4+fwB!h2B!B!B$ B!B!B!BRH !A!Bel9!!Bq^B!B!B!B4` !B!B!IҀ-B!B!"$IB!B!B! E{ B!DH?!!B2:D/-B!-B!'̙B@Ph޽;=U 0rH/^us=ǨQ0Ջckꫯn4"99z󳳳QT]B7XoݩSrM7yٳyGZUݻ7/R%%%y׏ΪUJSz\+Ν;Yh5w<ʋJz~ *Xh+1זbALUZ,?5bQ1TPh4(aAz y^Rf<{avfx̙Hպ.\3VVVԩSǓ\ЦM J\9 {nݚEŨ@MWڼo[韨{Wj Apөs0SsvXqWpܲP3x+_/SJks=;l4CCE ]:?@ο!0JQzKm?}ԋ:O!q-1㩵7W~1}RY>vef=S/<&| ڇ`=a6oGSv4:#LzKexEUDBח4bccg͚5̝;OYl۶Cxb.\ә6m۶m쪉rpssѣ-&))QmyDDvvve[lՕ0=zZMXXj1ػw/Æ +sϜ9C#33Sm]||<_3g0i$u-zٌ=3f0|pѣG0a5jиMiǗ}1uTJ2Úc޼yaN>M.]߿?PKr.}%.1Ҙ3giiiץKui_֥pqqÃsѷo__,[+Ws |}}5  +q… -0`۷W[Vbc3>pRo$/>A`=^=x7:uo0ttP1jm|޽{ٿ?tС^v-C aرWmݲexF6o\زo˖-DDDpyT۶m[v_6Ş={8w\zYcL<7xKcN::FU5K߽%FZZvvvXXX<600N:;t իVVV߿(L"Θ1رcIKKS:u*M6ܜ͛aLV裏ե(rrrJoљӧOW-KOOؘ+WZÇ3f-Kc;n5jDӦMnkݝ6:h2:<<kkkڷo+AAAum;88X$Zxx8:t‚&M0{l8q"%nn:Ə[@}]Y`ZZ_6">> &Hj>sVi;;;.\999ZlYlQ΃cddzP(xNr.].1Ұިr*X~V[6|pvܩq 7nqȑ#ѣj/^ĉ1-2zFۊ^VJzd%r02vqG~b@2fE=;}:b3{N1nLR59T,K}T}PzG6jفrHj|O+R34m+r@~|yL`k7n 00cǪ-㭷⧟~K.Lq˖-9=<<صkڔ!ܹSuwB^^v)ȠA3f o&$$Dܻwի3rHjժEÆ Y(m_edd_goܸq+nMpY>gUشi>>>ʒ%Kh֬Y ўt&==i'O&''Grqqa88hJ1]]eiWI{}1133A7ND}yv<֥333yadtfHNNV{C^^III۷???M^L2Em;w̄ n, nF u299yAT_ƅX[ScWmuaI1@?YBF SS lȹgaB8Y>x{,&g5T6О.h-'Bʧ03ðF q|colhfnIY\1&&8JmM5:XLꦭzo[ Xb> 4 11؈Ə>QFѦMIIIa̛7FҺuk5jzcL<֮];w$**w}}!!!˗/#>C޽Ktt:T*_ZĉܻwK.MWGL;F޽155wބnz!\\\Tٽ{*NJJ T0`:u ("s[[[Zn5xӧ X|9sUmڵk:׵( 6J.m.笲]vel߾!C`ggǐ!CJ[y𫯾ҲK@Ο?ҥKuj.}U^_|'OΝ;]'O2`tjoYi;ҏZm[{{{ptc| '''^]~EM0Ǐoә=[[[ڧuE@:sM\"-w0nW8=aMGFFdæݽG֯Ӥ֞%?$VR=ȱΉX[]io.hllv ׯZThףGRSS|2o^5WT 숈wڅBٙtJ%Z777*;v(v۶&-[Gj ĸ&.9rHN4hƍ+t_vj ٻuf"00ѶsVt___vɥK|2666hBmJ;>}~~U0m4x[]]߽SN4m;;;\\\ ĉmExK?X#77k׮ѢE q:ˢEgL:U6rXe켿FW_rv(nj/p; W5?AC{9];+mg 0wI;=ONv(/=?1 "_>X) 0A8ei>}P|NZ::`#B~jrB!: Oҷ3D2$u,<9yQw:sPͩNc>4IS=`9F\s<-@n85SSnhGQsFLYP .uT*SNk,8xIbbb۪[`ر#waܹ`5J%ѣGxyyѫW/F]jӈܺu|7nٳg>$&&7xC:!!!2}3daaA׮]TMX߾}x"gnݪzшϟ'$$\UaÆ!!!:mhhȁؽ{7&&&xyy1pRԔ5k-oѢ޷볯̪W#X&++Kmn`###;k7owޥUV[j_|FFF|7e.2Ѭ\M6ѬY35k֭[ҥKZzftI/@c>gظqclllumևuѥP*޾ؗㆆ4j7n֭8eBCC2e ^^^Ԯ][z_~?~ݻwӳgOtc=HLLܹs9sFm$(`udNOQF$%%F#^~x9===aӦMЮ];ֽ{w9v;wΝ;`jˮ\uۧ黯Nʒ%K~zMLLQ/JvZ nܸqq~\}a}?gEHkAQm۶%KyPPꫯV۱Kvuw}6III4o^|iy[]l٢ \jlWC IDATw9880f6ǒ3Wmׁϒ&SVTW&m^ֆϖM~Z:p0{1waMRi: ՙ{'@8(]@T߮ݫD07y5Cj|OAFSBQudļoeFM[7JSMArnjSRU 3dU:ME$sss"++(*###fΜٳ9pyyyܺuӧO'''rJؼy[|ܘ?>F?P[oMLL 7n$77W}1x`,Yڦ~Ԯ]?SJtܙ АC2qD<<<011ѳwEiسgnZm'֭S}==zP+۰aC:t6Rݝ>ݺu+ [;wAdd$ۿ5:u*|ܽ{;vvZ&N,>$B|3pEؼy/ijW}m۶4mooo~bccټy3|;@J;j/~)ӻڎ]Yňcر9rX~g '-Zл 0m4BCCYd waժUl߾)SSfM>HnܸADD'N?`РAZ=w\:PYNf.R+<娷0j F 3W<@D9rvX +-UXc=pk33L;NAF&I˹;1R}kcpw?:ez= k:|k8}m qi3@^B":Η`f{bhoI(,,+rgտXJzN<4 07Can!B!X)߬rʷ}0t{o,!eFU}v|jNu0OaԠ>?S,ƌǨIc>*y1 cc l1pôsGJ`?՗_~)4k֌X3g~!'Oښݻs7oŋ7o͛7'$$D-YR_xyy͓{nnŋ]Cn޼I~~>111Fyzzr}:w~2Aq}ѫ#Fzݖ-tӶm[J!yzz6}֭`hX6oooW[Wb(11P80((cooիپ}9ڻtBPP4oޜE}v^}R{L۾.322̟?]ҩS'V\WVT_}~Ϊ2cccߏ iӦ,^k4MAm6nȭ[9s&fff޽%'vҥ]-FAA&&&3ƍ3rHuƦMt+]Cs?ˮ]hժ[lalY[.YYY?W^y7|{zӭ[7[RS< 7#IZE J]?9k1$~i~>#}\yt'VV{VN^<oN +u99E{X:?jX1/w0wI툽]]fIZGGa;g:??M rrʘ`1F͛t8Ϋ^m!B<_YD, XOGI\ZXjuW%7. cc}L툽Tr957xywSq<30 >m唣ߦKԻ~:Gq}IhE੗Sj_GFz%Ugi+PȨK!*=۶mgϞ]!pQZi_ϟ-u1Ʈ;“٩gʮB!3}k[s K? 7yOzy=~!F`KZCVV]@#!BTI^ !B BTKKKdNs!B!BQH[\54OB!B!ZeW@!B!^Tw=* B!k2[!B!B!D$ l!B!B!U$B!B!BTIB!B!BQ%I[!B!B!D$ l!B!B!U$B!B!BTI/D[PTvB!x.ߎ*!BQe lm$-B!^B!/*]щj  ccc5jĬYʪСk֬)LJJ .+++ԩINN3p@<==-6m5k$55Umytt4$$$8pBʺ1bĈۛ3f!!!4k֌III7-[bii3!!!:cŊ(J6m_|Q oN߾}qrr gggVZu;MǗQѾxT熢~M8W4i҄>@myvv6gϦAXZZҩS'"""4)8|?Qʯ7,6SaE0ܱX9֯e=u/fVL;^8EZ{v`34)JK'^3ǰ[1J3/!ByWݏr[j _1^yj k1t=zΟ̬gwE䟯P'SۦhߎޟSxX~ /THhFll,Ys>) _βe˸r ='N׷&͍G<88$~Gk٩mٲWWWxj7aaadggb޽ 6>s ݻwϏLu8;;~zΜ9äIptt)m8t/… L>iӦm۶2e0zhf̘ٿ?Ge„ ԨQC6_6ߟ$׊+h޼9m۶9ԩS+|޼yaN>M.]߿?PKhc..]%--9s搖z]tIחK.o>?ׯ_]┥].\ ,,u .,lo^mYU+"c3>pRo$/>A`=^=x7:uo0ttP1jm}JcՅ5ߩJxnkCƾ(EC^@_cj+)3uls^\3ʻ9q o!B{amZxy99ddRIR}y/ާ#ԩSGsذazʊI3fP~};vlNJӦM177ylذA{&''ӪU+>#Ƞq%{7ӧcll̕+WJ3fZE奵t5iӦj8 S]45۷Օ :[[[\]]Ms"8<<:`aaA&M={6L8n7Yn. )s̿`.J=lt3gp+֋">> &Hjſ… IHHe˖yi^( 6PPB{0i+~YcXa-i[ 5p:D'}߷2 lmUƍ2vX~~~[Otɓ'sUN:ٳg~:f G4i҄`.^ȨQ=z4W^- 6mj}5//$ۇӦM+ڼG%;;;w9rƍӢERChhZ"uΝ%sssSK`ݻ\\\_~ҥKdffұ㓹l٢CÃ]vMΝ;Uw'k.؉ 41cpmBBB~i{^:#GVZ4lؐˋcǎkYFFj8+W[[2(g7n+%gi&||| Օ%KЬY=17p/kL k&G[kSͩiVebԨQisssRRRXz5'''>cQnݚF8)XAA'O&%%kj'|-}Im}!!!˗/>C޽Ktt:T[ZĉܻwK.U؜/7779BAA;v޽{cjjJ޽U:jczz:wV%III >>SN_d<~6w!;;}bkkK֭&:}t<<æݽG֯K,'B36l~HHb{%qgL[j:5IW1y=;K~LIzc1"-{ʔ)PPP@JJ ͣG9rDU\QQQ3x`6lHÆ :t()))2qqqMϞ=>jq֭[ǚ5k *v͛Gnn.׮]E8;;sƍb嬭֭jvxx8Cݝ={ OVGcccصkP8g~077׹of=z 55˗/IUv0@Pz׮]( IOOGTꫯ%qssS}cuW˖-ѣZG-1K9ÇSzu ĸqXƏϊ+{AZDX}M6-h|[n1k,K21___vɥK|2666hBmJ;>}~~U0m4x>uvlҴ^ԩM68q ۷CV1b:t_WN{GY㔧]666h"Y~=SNչN\Uue;/1# 10+|qGOP^|iΪJ[`zNlwS#F- A/" SY>(Q~>YRQW'/7Ngr]9UikBQ\~RI`wHFn܂EҟO_֘~9MTXkR SSn85Vv$-5mU0 .uT*SNk,8xIbbbۤIKKcǎܹssR\\\P*k!5ߟƍukCO#r-iܸ1dϞ=<|x J`!ϐ]v%22R5}c}ŋ޺ua_G#?rssU J`JRO>M||</UV(nР6mbҥW#===UI}׏Ǐ{nz쉑Nuѣ;w3gΨxpմ.Pԩ| ?䓒gj_N||ڜڞİi&LLLh׮^u޽;;v;wjgÃ۷-rֹox\ [Nʒ%K~zMLLQ/tsn޼Ɉ#YL}?[Uڵk)((Pۗƍ999;Fնm[$e=>-440+ӵڎM/kܾ}$7/>͛>|XkgGv9880f6ǒ3]/m~EDuy)bXի[z6b`kCgKȉ&?-J~I?Žޘ°c4 s Oe?@=s}\}`ToUrt ;G:B!D<y>jˌ4"oyb IDATO)X @^B V*֦"ֹdeeEBBAAADDD0x`1sLfϞ֭́[>}(?99+W͛U45jںONdd$7n ""'0h ̒%KTԯ_ڵkӿpJΝ;`UT:2tP&N&&&z({!33֭[dݺujGje6lHԦQ*8"[n%>44!!uq222{ҿ:u*|ܽ{;vvZ&N,>$İqFrssUl{^w`h>qvv& /͛5~&rJz-EPثMY?[/mҴiS_e|7Z)̭[ ŅYfyqirQ8mܹs9t^_Bٮ*˳:/\VxQoaԼFb1?f.=xRr WZ7{p|ffvzLJ]swrc/0iCG,~2uʪ5ꁕ{tDp!@fDu*/[KG6^1j֔w}K=Y: 9}2wQccթE~jYro+/S!E֩3Ľ7i3k׈;+W Pܮ_kL-`xjBNPb9Q~(|HW{ǗKڧGlP_(2xeԫ`׿EIYw|J*2R doo϶mٳgeWE!x!=qmڗgK]g?dLߎxvjA-m"Bo_8d9E@S^E^%_)D$y-Dʼn!++]uB!*$B!xH` !*%aaa2B!B!r$-KFe3T!B!BB=Q!B!^]!B5-B!B!JB!B!B*IB!B!B!$I` !B!B!$-B!B!JB!B!B*IB!B!B!"P(* B!B<oGWvB!2^6B!/ Ip !B ~^۷ӷo_ٙUVU{fgg3{l4h%:u"""Xsꊭ-]v%22Lq*:t`͚5Ϧ% YfT{TeӳiӦQfMRSSՖGGGchhHBBjفP( >\#F(}1cFĸqhٲ%8;;Lb z~Bq$ECPߊmN&My{*{>*\㣱o 'O,{sJJ .+++ԩINN.1^igq|*X_R)i ҒGкuk-Z4jԈYfs;EЯ_?.\j~Z1XXXЯ_?&Mݻu{E;NM+|QauG~jjy+e+sWR|#+EaҮ |wz_~񫭰zo49*B!x1Xz!#,[q[uV!ojYε∟dt$̙WߘOV ߐh){ LZXق 22)$@)üNS^5Y`ZiL:MbnnNٰaZp:t者M4a:… IHHe'#L~oܹS8,}СCҥ VVVԩSb0qDܮo9++ OZ1W\)~Çg̘1j-Z֨Q#6m6MAxx8 80EX[[Ӿ}{\]] Ry\TU0=." `f.ObhnX/R+5HM!%W,5=IT0˝A}k^=9=ι皚ãqqqG_+o}~ p7SFl\Mqm/ʕ+x뭷XˋpBDFFBKKo!AU=5UVVGGG|j)44BPx(((ഽ&eӧki1=ű^^Qi^^^7o.\J2χ tJxb} 6 a濰8z}2`/kQCu6gNd Ni %e /ojڬ۲ePzdyQ+unX|_m`mc0߇=V +7} >&BH(p-*"mf?{*.r:O1FeOJ4%ZC QQQ D||<<<Y6h/7n܀+<<vx0MV0ߟB!OOKK/`{,l~9sUo,od#`#oժGV ۉ'd6++jkkq9vv&LQٞOOOdffaTWW̙3;v,tuu1vX$''N.VUU$Y 8q,I&H6 Ӳjq+VW\͛zjphڗ 㬺p#U݋|YSY Oؖ]Q#axbcݬo-^DFF/9׋k?Sbܸqk=}yQC^Qi8{Z?FoݺU ^zD;XwZ={[n>1rH(촴4L6 ^^^8|0iqReֆH;0a;VN777TTT!C`b"b6i$Y;==5ubb"x<PUUHAM#rСS$(jᒳfB@@,,,0ydEӾLظgյg۳F߽{+WDdd$|էbMb[ZvuG"""k.BR.] aZ)((@HHBCCYUk׬Y:ܾ}rss9͋rԤ<#F1c MrYnnn}gqU?-濎Fee%d/_x֛>},yke"fffE׮]YyZ.}Y" 8sL;rw}wyl͚5>e_C(bǎ5mK=5rwwH$Bhhhʸxbrv.nJ ӧ9͋rԤ"|1qD<˕H$’%Kꊸ8m/yP" %/|Q3Gפhu-P8\tz< x 烩0X WջDfѻ!Amv/E,[$-_E%* ݋U&PR$@:uvJH4?n &NE(乎½WNX:!B20  Qw.?uw3UymG XFnٝ*RY]?@rƪޠu/_M6!;;[n PTT7"H|ۣFBdd$Μ9)MS47Y_|||p{RXL28N#?CYpq &ٳHJJѣ! 9 %%%t.^ܑNKKMHOann;;;;-- ǎcFFQQkNm ** :::xW*}ZoooİݼySܷDsknZ 6K:Ϊ+33w3Xw aXGPP,YZskr>^z!** _~er|jmii(Hu~(ӦMc˕iiڃw;գtoj6V*9ۏEV?=@е4ZjiZ0eO 4:unK<>+&F SPY1ދB!_ Z&k:9PSy/+`=U/.SxV΢SUy#-['''899!,, W^ŭ[~$%%eeeGaa!ߏ?S}qq1"""X \iaooocHِ$''cӦMK|ԩ3 amhݺuHLLDaa!֭[ @SLMdݺuÖ-[0qDҩ1u\'0m4,Z\Çd ""5:66psscۻwo8;;D²eH9r$ai; IDAT,_p}:twƢE-GCgK_&:-Oʄc̙D*}hr>j鉵kbzߊ cѣ3/szz:VX "==-ɓ's~ɥ4;͛7xbA"@"HOOǪGbW@͕NhL9@hE"f̀ !|il{1 HӃk`h()UV{rEyeXw" g*wAo߆kf@8 QP_\UtzSaTaL]wt  f =OB!|nN@,5SQO0 ӏ>kвP}^=!N;9OEs@ط>ni' 6&P `!M B8qk׮ŏ?Ç(++C~qFYC||<+XZZX 2عs'bbb4M[[ǎ-&O {{{lܸk׮eF׿T$&&c0`"k>???m>_~N6ϡ999-FÇ:'OFnn.ƍRŵ|3fٳgպ <"5}H#444FGGG#00A_ֲBie XDFF_~ذabbb0h}ak+\2QMqVI:tAAA.}hr>j?Ŀo)}BsݻwCOOOJMRݻwD" K/7[[[|QNi5} Ķmm6BWW C\\w(:)gPLDf/vJ>%y<8g|##{uZ_=(D4٨aq-үBQ5W`<{FTNDA[͒>k>*vF;TA$郔R* GYv}=n\B(輬]BXQ"Ln`(EͿ+n '1ikl'薞 m!ă)3Pcd{jcQ7RRR`hhӧO 6iS[[vvvXr%$ h/?V{v~XC43@ ajlΝB[5'ui~"EC5il} =[!B|'vzܺ x󐦉 ahSxf>_$@̆uJ,z'l~>Ѽ7O_6gNt ױ"]o(u: v0y/ =e?7`s6}]r_xF’%KP]]J+**~ŋK.Λ(I_frmJQںu+g(,,lz%Ee|TY,#;;_}n޼ΝCppMk-Gݾ܅ ={`ĈI&aȐ!QYY|b׮]Xz5rwhoU )x}/*Vq+X1nxd{Br""w@JЮ7܋ꓧp'Nj.h;P+RgB!tճ;J>#Ǣ% >_'7?^抒_ 7ʿfWA&q._xd$^Gk*~qoP`bZ޴:x<0 f7w022-򅩵xbٗ/1i$֭[1qDHUVǖ-[?pΧ?e!##III >o<==˗/W^_¬Y)S?y$<==eСC8qqg=yd,XNرce;v pvvָܻwԩS1|?W_^cׯ3ɛȧi_frmJQAOOnTT,X"ÇҥK-x(+@Uv튝;w֭SY۴ٞX};`„ '[~jkk0a}]$%%q*{[y/ m~s;uJ75Γ+}w#rU{yB畗!>r lT;mA{#ޞGKOSYgB!|=. Z) dE"MQu[`SXW =1jNaheEaNhu6"l6ֆ퟿.Cn@Gwi;ni~tBO a+akl>@_q!. r.fw@CQzojkhJ0uޗob Q*"8M?Ѐ9WGy.تhʂ9󴵵ѷo_ի={6̙ PRRɓ'cܹweQeig!** 6myuu5=zKd$G:"""_ƍpuuJKKU}||Xs>}555Rff&+-g`` Yᄄ `׮]Cuu53;plmooo$&& GBBz$&&r `ox,,,0k,X[[wؼ~Ф/g5!88/;4mMU95UWWӧc)jjjPUUŋQ[[+{cΜ9R<&eGii)9%K $$sۼ(ԃ~(;M=~&M֪"22W{B7OO޽ uZywFCؼ>,Eet :s߁QiP+"l yKt$J>݄l&.f-f# RpG:?q`jj} >z5Ƕ믂-~믡;s ,P]b{r'!cp$h|Bi[<==,-Q_\m@FٺP3t+e?EŞ}7!с ֪hpTDEm{z!ؚ}6Q9spp0;;;كyyyajjʂ`Xnbbb0uTaԩY177 %MN4Zh l޼Vp-?>n8?ܿYY/n'N⬬^^^ŹsHڵk0aZmxzz"33 àgΜرcc"9Yzɓ'.VUU$Y 8q,I&H6 Ӳjq+VW\͛zjphڗ 㬺p#U݋|YSY Oؖ]Q#axbcݬo-^DFF/9׋k?Sbܸqk=}yQC^Qi8{Z?BoݺU ^zD;XwZ={|X 0`@VQY &$$ڵk~:LLLп٭̊(eee ]*MN1tPܺuK:X`n"x#GNKKôiÇ8qB6rjkkN0s˦***puddd`Ȑ!01~14i,Κ:11<NNNH$ AXcccxzzʦ9tP)QpYf! {N"l tm, >[}wB-(7H7}7IS>Ygw@(D͕e** 7(l=*9s >'3@@woχml~9߀9B!'3Tġ*! %Ež0hŲ g uG۰N]`c Of GѲrQoPq3,6)SH#wߠ}}I\[FE,,,ХK9rD:pqqA^^V^x?$*Ӳ(8886llO###D"HF999077>|ԭm@ P~10f̙3Gi>ӈܽ{ ӧ|}}qaC?W^?bhTVVL6ˈG]]lӧV*bff]]]tڕ%җ% kn`P3gδc);?.YM|wxwX֬YQyl߾_5B!vZ_V]Q#wwwD"/+n>} ::Sۼ(HM~/('NDɓ\D",YSkҚ5*P\G5\:<}tMV׮(ݲ AOWÀP0{>X piZ{A4kfQRH_ɲEUT ޽Xe %`9vutX˙0m'ӈhux|ށ8Gof /j(/<8y: ^;aBQ DGgoarzݹ>A]o<X~-> > Y%LEn?7!yo?7aUYvT̀ev UX*T5VS T6|rlڴ r/\"lܸDr5j"##q$$$ //Oibʔ)9u6hpttl^\{OjmGmc„ 8{,0zhBNtssCII .]/F6wydӠफ+>SNKKñcXQTTĚS999^yʦl111e7oT9-ќÚÆ kRv~ĝ;w0c ݻwa%KV\Ŷ욜W^—_~\%''#%%~ZiZf@ڿ9/1Rz+;|011iX?reiitZna|yy&(ljoe s_Ql%Cs ](M+MU;_nޞNSrNH_ʥtF}u=_&נ<_[Y*q[B!t?LurSSD-, #hYIE!HGE/{UF۫?*UQ]h(P@Kt]yꋋT)]u*z$e'''իuߏ$X[[ (,,ʶ/..FDD +M]aI\m3 FoK3aaGZ{&uF"A[w ik 1=;E6H3zm1uHSB'Nڵk?bpuuExx8Я_?lܸk֬A~ ("66C 9v܉*MƱc`kkɓ'7nڵkY!55pttāp1  "5u Hc6h}/SNA[[NRRqUt֍P;w999-FÇ:\'OFnn.ƍ:Ƶ3fٳgպͼ <"5}H#444FGGG#00A_&&Pn𨤤m}ZaÆ!66ׯ6l؀ 4HvDs\2QMqVqI:tAAA.}hr>j?Ŀo)}BsݻwCOOOJMRݻwD" K/7[[[|QNi5} Ķmm6BWW C\\w(:)gPLDf/vJ>%y 115I,!p鲴вAu:{.go-(v`Lpmǫ%tOZ_X 7!BچEӧ[1/ BwQ{SzGV]}atKOŶXYZOb-04~,zܺ,{it{&e/(D7'&zd_Ck9}3Q8/5n(ܦ %h |7_ʯ1eBxm&ώ3,XyutQG8x FE!B ;/vJ̧Uw{Ym&B! m @m@}WCՈ~.F`S𚐶D?ЈB!퇂ׄB!<\ !m)))>8!B!B!Qq9rdGB!B!:s.!B!B!@# !B!B!tJ&B!B!)"B!:B!pRttGF`B!B!B(M!B!B!S6!B!B!N؄B!B!B:":B! %B!" ]B!tK!Bcd{jcQ7RRR`hhӧO 6iS[[vvvXr%$ h/t1׾mAi:/B![nkH{{{|-֓wDm^k`yvsmqQ?g{cpi,\Zf w^\pÆ ĉ/[֭[pww7.] Zt:bdgg㫯͛7?ܹsnl<==qi444šGe-OOOǫ 333ٲ)))xl?RRRPSSC" 55ӧO׸/^ĨQdTWWҊpEҥK&iҗٸgR~(--en݊~a-Y|9 ۬^mIQ59u4UeVmZ{lOmy>.\@ٳ#FL4 C aJ#44vի9#ѵ} !wA#111a.^>bF(2Ga呔իUfF"0cƌam&K[j&y4=~Q[q96N9;;3[li<%%qvvfϟ,]uhgʮHٹ& @a`Ν;A[R mZ{lOmuWgWwodgg3]tQy?]qrrR sL׶׷t\gm \L!t3g2 |w uik`e׶?$Kvvvg///"%%5:ԩS;v,k]ccc 2ãqqqG_+o°h"hkk&"" ,r(˛ȧn_nDm8x"\z .Ddd$T]QSeeepttVBCC! e/@NkRfy-Umcd{jc:\qq10o<,\e>ntT{\:;;c޽3f pرV _!^y-ޛ˄BH[KP[[ @Z~wzѯz.تhr/hkko߾իW1{l̙3'Oܹsq=>CTTlڴ j 8qUS[[~~~HLL$%%a„ W-777TTT!C`bb@:~rr2魧䄪*D" 451<==eӈ:toi|Y L<AAAgKӾLظgյg۳Fݽ{+WDddӚӤ/eW|(""vBll,tuuYiK.0-^ $$ުµ̊[\E9FjRu{y}G#F`1ckOXf ܐiΆ}3k yzTVV, !B:N~~>,X[X|dk2E*ҥ 9pJ //WF||<,K8~8???LBxx8DGGcwaU\߀,{AQLU@DB((<E Z6jFR%"PMqK -EP0ƀYd;ށ\V<Μ9̙3{{fHaO[[[(JTTTGGGX[[K*G6m] pwwǾ}SO#r455SL#G?GTϨ(a[Ru!`ccQFɓ!j&LիWq֭V_۷pppBB˗R 1c0R$VVVӧ(S>>ؼy3^|ٳpqqAEEq}ٳ.]/++Q\\jL4 @faWJ=XRځAq`Ȑ!eaaaؾ}M#T*%Kh#q̘1;nYt)v؁-[ݻ8x >SJj &sfZK$&&b֬YP*mbW1zիWcΜ9qㆬ}!bbbvZl:KnIRCɘs * yyyӛEYY8,YY8Wc1ƞ.MMMxQTT_hhh"/hmlBDD7oޤ &3YYY0eDDnݢ^{K/RRRR8qFIvvv4f|rˑ͙*<VCu6tݒ6DGv&}EM[9ws 3GGG ,里#Ʊ]zmLB!j|]f1ƺJ[n^MrΎCMfꗙK=5\]U.a~-zR u ___̟?ofWWIcܸq]]c0wk8e1cO }qb\u[lx{FWƫ? DS1u"bԨQ]]cc_c14=،P(s3c1c1`33׫W/3c1c1X+=W_uuc1c1c1c1c1X،1c1c1ƺ%f1c1c1-6c1c1cnc1c1cuK<c1c1c[lc1c1cS1mbbU`1cSpc1O!3c }c1S5Yzrr2* IDAT&L_:=rJ j/77AAAǨQpIiI6b۶m)S ,,Uz||<郇 `ff2!011Add(opp0fΜ}#""|6_R7o#::BT*Ut3~P?M{뭷`bbuҥVWUUaXdIoOGUw#}ך(mcbb .2O?aݺu񁭭-y̟?Zӷ_ۣLkk玶c#== O 2hupssÊ+P[[+=: Ǿ]vtcc#6mڄ_WP*8p >c1Zr=7o^xU=>[ǿ W^^VZ4ڵ 9r$&M!O~~>\L0!!!+ͬYpp0N>&QCP^^ߢ, >B޽{t3?111Z6m#;SGGRvv6sN=0yd 6L/&&())ABBmۆw}WRǾ~~?q,[ ؿWW1ِr=;#Ju5ay{}4Y1x09K` >+A`⪫*I+)֟R˵gׯUTTcxyyQRR(ՕT* _yWiٲ$eN[n-L7oٙz-3g(DDO={RNNىuYYSffT߿C}lʕ!e3Ť䴟/}ח͛G/nt2}u{=w6FԾ5u&":s ڶJ6m#;SGr{](,,޽{ǴOW&[@sVr_w};xUZTT͚5#c1-\'MD2:eWĿb[q~G< xlXqcǒm-[>kxٴŘSyvG}rXf lmm.ҥK1p@X[[cРAصk(OFF|}}acc`ʕ988ʕ+(++?DJJrl6o!Zôiӄ/_~Ceez%][[ ggg,[LHT憁JL2颻O87vvv6lpa=Z}СCun޼h1|i vre5nk1)&헓+Ww( .Ď;УGe軆tCu{=TQQ///U /333~1u(P۴L9u;-!$$o&.\(Z&eSSS<6 pDgľصkƏ[[[;vm4nĈP(x饗p̙Vmj㙳3u֗1cK BgRY[z* 1&ȯFAAt汰p!\zsܹsqu0uTRR}+vލ(T*aÆ l!<Ɇʑr ** iiiהan游8\~_}kbŊZ+,,L4ӧQWW':O:wwwxzz^]-88X4}Q"00ոx"ڵk{ shâ)C""""<Ç% `:n'''̞=...puu7 d1\fIgۋң^xA8G1\h.z3f̀+muuujzsY6Iscc#ˑE!>>^r<+}d[Cq>w4=z'O֮]+{[n߾;v`޼y.8mwѢE5kΜ9#G- yf᭦yٳ51co6{93WO!"/_&TZZ*k=wwwڹs']rLMMۭ[@=z 333 եPIIhb@EEE$u }Q Y={޽KJLMM);;[X/}j-ڵkDDO֭#T 55IPЃhԩ;Q2e^ee%бcLjyLLLȑ#Br .QVVI㖈D_o)(( Kߧ %''Kle3Z~V]W^^Nt9QΝ;_zuN \,R.zD|?A , ???EFF/mSl߾eRzjὃki>3G_/uh$255Gj2v<өScRm:s }>қHz[<]zU{T*ra1Xv=/)??JKK/ ooo󣆆lI5/O!A<ڸn޼77Cuu5`_[4Ok׮oAϞ=)|%@n5UTTpwrf9m`aaiӦTL8GSSOWWW"<<?Ø1c3229r_ 44MC|78y$ ={h|?-- @WO>  JCM#bgg`a.[m={6"##䄩S"::@A=~V;wb;ܹ+V`ǎZ֒1bGZw9#۷c۶m8pD/^ "j~@||<D5DjWZܼy۷%ͳGr{m6Gڵk1sLKO?aժUS$ps=nmMaccs*=())i&3c1ڟ뱿?8<.]a-~S9mLnzLy*++bPTHMM%M)S\VPPD޽}0rHaO[[[(JTTTGGGX[[K*G6my@JP^pEEE(**w}iDܹ&cʔ)8r~GamWw`ccQFɓ!j&LիWq֭V_۷pppBB˗R 1c0R$VVVӧ(SIml^۹oPL4 <-J-?:$k±G[oGaڴi?~<Ν+1k;9cwwwwϖn=-7XokptRlذZgggׯJsررcΞ=]V^^EaXX+sL>$#g[xrss#1ܯ_?(JJz/yՃ'NL8_~%RSS1n8^݅z쌌 L0AHwrr?nnnwFF;&9PTTݻw/; Err(-//ܷxeKKK9rd'ײ3u)|9s(O?Gtt4-Zzs=;s=Hܽ{76nR!==3|~Y[[KޯJ)w;}n݊={"<<\O\zAѝHKKÆ P\\$$''c 9 4 |Jxx8bcc KKK9?`ʕ8~8qdgg N>6lׯ>&M<%ƯkYFmK`9r5552dhYXXo.pttD@@(+|}}Eӈ(J`ɒ%ZH3faij[}.];v`˖-{.5kJeeUc՘3gnܸ!}>|]/۽YYYXlN<۷o#++ qN*>Rv9_4sXYYAR!//qqqz644(++Áծ(:ǾjӖ : Ck;N|cfz|}̛7NBII Ν;W_}aaa-9Ŀt8i -6mDG&;;;rppQFѮ]hԫW/p>}:mٲn޼I&L ggg"oooaBu}ˈnݺEۗ_V;q9h̘1ƒ#g333Uxx6P;w QzSSmܸL666&H/2ʼnH %&&*..RŅ[JIIƏOK.ZƍO>CGҥK:6o*qY8z(1J%uo? a\6ۺ~VW?EԺݻG+}=NU]HA#MMM4i$:t(UUUQddζC?c@dee%4l:Pll,yzz5>M~m>3/jGιΦ{Nx8::R@@eee|?MG5}W̍m ]e*VUT:X{-caz|=%wwwz𡨜l+Gm倶eRp`w͟/WWU~_chmTĄ8`9::b7n\WW1{*|}48L]Z2}c1B_kmX @?QդjO5Q0TL!x(fff(++Ҏ?DFFc̙Z7""˗/osU*<<>>{ݻe3݌9Ť-:P^^.zmڴ  w.]wv]5zԕQXXyyypyߏ?X~=\e˖!>>~KڭgG0T'^mOvv6sN=0yd 6L/&&())ABBmۆw}W{u&}'J1chcd(^9:&&׮]Cff&222p-L8Qv})3=8`aF rΝ"]h)u\{~QEEE1%%%\]]IR /X^uQW_}fϞ-MÇ[m-;y&\!-//魷ޢ9sGDDП'Zٳ'䐝h_9effHMM111GQmm-? V\IR6sZLJ?ے1ǻ/}ח͛G/UfWW_#}ydd@ϟ79slmm(5k5k:vHaa!`Zz5HsιSZc[u|˱~]WҕmcΧJ]ZZJ&&&t]!'kkkp<-uv/xw!dž]y}i{+4ytyVc_mlC 򫫫QPP???y,,,0`:tW^Ŝ9s0w\\~L:o;T*aS2_ݻw#** * AAAذa<<<4χ?p၊ adCf9@ONNFrr2rrr`ii@!,,L4ӧQWW'`q) P\\> .]B޽1vXTWWpu|WQXX=M IDAT+V譟.rwFEE!--M4jic=P/^\v 555}w^aP>|X4eHDDRRR@Dq=|lCǭ6ٳg&A,Re~V1{bb""""`oo/JFLL ^x|Ƙ#둦̘1ޢաKS\\W`` Ν ggg؈rdffbѢEיٳv:i;)j=ɓ燵kPoƎ;0o|055EAA1cm'7m jQVVby9Ǿj~ ?|2RY빻Ν;ʕ+djjJonO2ѣQpp.JJJD***T&)#/ iH99]viݺudccCBZ||<Go߾c SSSԷo_o9Sȭ[KV=MٳgݻT*JgɑJDդP(DD4uTzwyN2EXlllرcBLLLȑ#vzEnnn%%"Wf {dccC[D{L;c~m-U{5;wNsN?ίK=/;J5?hG555²H+۷o'gggիrEK*lmm\ڭ NRNJ~9Q1CtQyZ ڎ+{{{:uJwl3ľD]qf{/**"tU&+++ꫯ555nܸ=5 c1NJ|stSSФIΝ;tuaÆɓ%ic_BtZrqqܼySo#!!7nݻ'=roZXX`ڴi8|0 55'NQuk) >7|'Obذaٳ'_BppÇabbTUUATbСiD,L#rV_qᒳgFdd$0uTDGG ;cKjj{ܹݵwX;v:MEKƜIj}\Զoߎm۶-[x1K~HHH=VUV7oބ'|||pmQ̟?6m[w?IJI/P=z4֮]3g'G駟j*ԩS߷;W^_#?Ѧ=bhmTVV/^߾a1Xɍo[211Arr2兙3g0u)+c1Nn|RqQTTT ;;o&nܸ!L+56jM5_t)6l -566";;Cx8q"`ĉ/q\X_s?.^///JZb uo"''Gt't{Pσ &NNN_8:: Xyy9222p1C(--ͩ"޽x饗dM1Mhh(Eiyyye3t.[ZZȑ#;ݟ~VSb̙O?D$7XhuI&l/Rkhvލ7zTiiiHOOl-YZZ Pmcc[Z_~ul;)䶕.[nEϞ=jP^zAP^=po{iZwwVkoc1~Ʒ|8qڔGi}؆(K,|||yf\zسgRSS₊ $&&سg.]$_VV۷8y$lllw7\x%%%سg>ѝHKKÆ P\\$$''c 9۬T*o`ꫯp=,^C߾}`ҤI5kֈc`ӦM?˗SN9?`ʕ8~8qdgg :99H->}:6l Z7Ch[xx8bcc KKK$8rjjj0dѲ0l߾]t舀Q^WWWQ* %Kޑ8f,];v-[p]暚^QTG!-11Pqq6|p={ ԫ555ƍidccCnnnBeff CͿ_8oߪ;wPFF65 EGGJ#"?.]7R>}_۷ХKZ:t(m޼UV.-ZpQ1b)JǏp=~йlu3}~~=\Iu:egV_#͇455ѤIhСTUUE:] YZZ|.KdmmM...4}tz*5?:v-Km7?ۓ:M{c$;;{9裏l) $IGc1ؗ1cx(fff(++Ҏ?DFFc̙Z7""˗/osurDGGcP(Jjnƞ@cc#6mڄ_WP*8p >C'[>>>?磢BgEUU %K^]Zfbb .-:ZK=^ ]3OG͘ׯ\\\0gTVV̯HOOBӧC {'Z&&&VXZImҙ8mWNѦ+N.7c5k W^^VZ4ڵ 9r$&M!O~~>\L0!!!+R`رXhjjj:"88OFSS(СC(//ǿoQzVV!m޽ Bzz:=z$GDD ==uuu2jkkqQ̘1z7DNN~ߣwm.f̹mׯǕ+Wl2cZWWW>g󈉉YtRܿU1ף\Е.xrn<vC9bbbp5dff"##nĉ%7;;QQQعs'F +xXec==y*S^k֬uuuXt)kkk 4vȀ/lll0`\R2\rEeeeHo"m.SEEE^|}9]viݺudccCBZ||8{,ݽ{J%UUU6IMM%GGGjjjjR("":u*;DԼoL"WYYI666t1&&&t!Oyy9YZZ _"777IrMAAw^>3#oood2$&&v7n?u"亭}~k:t(=jaɒ%t4kΝ;M&!&&ƍáCDU(}#RMMMhiiAKKij$F!G::ߡŽGbHHH@II,saÆ ܤ*6{lDEEz+:8r1j(^ZPPvɻ:55;l0xxxdʕ+Uޑ8i$tcccO?ׯ_#**JP]tV̟?f^Mq';;VBNN^lDEEҥK1cbJ\|}}~z,\.]Cdd$?#}bYlt uyJRRhp~KK {gXtt4o7xYZZfn۶mVVV& }4֟>۳텅 KKKM:ƪgcgعs=z4۲evmc۲pѣGٳ>d2`'NPЃ֗yZ.}ו+WƝb\\\)gfF--}RGףׅVFjkkYhhʇD2x]ۺu+ j`[!Ay2\o@>ϟ옹9{پ}4OUc@6ˋeggxž;:0>Zw,:: <ڲy۷ok̿m<\[[ـ=cXII cLX<˘~L!>bog{]8Oh+^m^ |~ωB"D8pLE!BzbScT5QKtq 4uuu&B'Mq4@FMm~f-m^m^ {"yJKKЀ &twQ!}jpttkB!gرC~---ؼy3@& q;#((Hi{\\{ܶ'N@" 44/Ν}CBBz_.[lmBDDF T wwwrMӵ/S]>hj민 $׹s:Dmm-+W򶋽i.) H~ BڅG_xxR6leULHRF{wFFFppp5k nž}Ō'ۍhs} ޟB!]Cwƍsss <K.Euuy_uzv{/ZWFhh(?\,_ {n:ddd`rn"x{{ʧ_M6Xjp."77BUUgggcر۷>>>!!!Dcc#/=zsѹ;PRR>/pDFFg{WIW0` 3, 0  zw@Bڻw/2dP>puueIIImÆ cryٲel}^z%`Q]$|6e۶fggu,Sզ֯_5VwTƶb_ͺ+xq7PD!oyvu)pهs {8W<ܱùds>{nNWށY_\~=6lsss鍍LMM1b޽OVV<<<`ffÇcڵҬpyjTVVbȑܶ/!!! EZZ|Ĝ3kݻwԩSannǏw.w?쳐Jx7(w>MMMM*:o$kjj J!̺E,Y˗҄,]֧O ݅bG:!t;MaBB_PB!u|lGGGաj122q!\p .ĢE/ܹ3f` ˹NMibϞ= \. ۷y Q]]ͭ-_~| ƏߡP())-[PRROOO̞=[i UN> iAAAusssEԩSptts CFFo8--Mii}M`=zF]]Ξ= x"yپ}5qa^= -- 1=| l!c{uuuqlll`cذaWEL_&hoti۶mCHH,--to)""x'-1ף1g؈ZW[hjj^Xhlmmsokkjjk_~:t("""?̚"` ӧիHNNFxxc{}ō5B!䣭_}U ASSc, B!|GKK p1 ..Cy>/ ?***DvcO>իJiJSHLLd}eחW)++cXii|zcǎe|}^<~U`.\r*UUUА]x1X\\۸q#333cEEEܶ8Xӌ1Ʈ_d2XF]3kkkT*ewa16c 3|q555̌?~+D"aGbg1KHeRS\\_|۷ݺu}Gܧ}ܡMYZZSǥu">ґؗ1q㉶ĎK m1ZBB5߱~z.Ntɳ_ZB0wicoo|nݺD`ʔ)߹9^^^puuEXX+8MipE߿?\\\DZ[[xO-U]-]맷PeС033CMM}˱tRl޼*I0{lȑ# Z3gÇ6mLMM5.p=1cп`___ÇC"d=z4o rˈbϹ3BM_>fΜSbѢEQ,#r58rn߾RL8Q9QL`NY>0apˇ(… rGMM J!JO?A.oΜ9\..LLL0p@vA円8}t:ވm~)-[6?][wXn_WWW-%%%?!>3#oood2$&&v7n? ]}:밣#k׮ub^{5#00wvbd2`ܸq8t萨cžt$BMB!000w(?r^w4EBBJJJT塢6m+d2Iɓ'#99OFZZ4UUU|?777^ ¾}xb֬Y 81笎>B(zfffؾ}iӦMo2e ܹ~7:YYY`ܸqxw`mm >שּׁ,?~wOII ***xkj{쁱1~iQe9#%%PڷDw1omদ&?KoSN_ܹs橏q3}`RDDbbbԄpGoٳg@ff&nݪhjs}/~7TUUaĈt+Tؾ};ٳg+Ԁ4>QoWZRJ!A_ɳǿB lm}7ʕ+wwwlٲ.\@QQ݋tۣ۶mí[w^;w;;wDYYꐓ333X[[kLsssBBBpYc޽xw!## (++CRRRRRb sV#u!Fkk+ϟRFss3?k,$$$p 2 G}@xanrX9:6{lDEEƢ//9z5;wNMM5x6 eDd2rJw$N44]?X$''O?qA|爊TD<]2yDFh[߶m^~ed2ﯯq'zc…t钨w"##?9vk>'m-ԩS(//w}^z AAApqq\}KH_Trָoss3ЀJ";;SQv޽{ܾo T<֯Z IDAT_?!bcmmͼXvv錇8*Pc_ c(4mf]]>}:JlڴijN!'v}l[\\̢ 355el֬Y… lߞGUKe楘 L]m* G*Q!$NY򀵵58)StwQ!^3iGiB!BSkj&P@S@KWkWVxpXBxB:Oii)0a„. !B@/!B!m lBHJ !B!BM`0`&M B!B!D M`B!B!BhB!B!BHD؄B!B!Bz$&B!B!#6!B!B!& !B!B!H4M!B!B!G lB!B!B!=RH$]B!BžB!<+& B!<.(%B!^5UzJJ ? pwwGRRRgcc#֮]CB*bܸqVگ>>>Ą S> aaaXr4DyԨQx4Gw]o qqq8p ݻ^\\ TVVrN8DP޾;w ի;\~\ggglٲ 9r$R)!7QO>Huqwbƍpww9KZ>|q~I;vP&ZQil;I۹`_L'''|Z!C .DMMTLHRPc H H`ddY 맳Qsc_}KG]]4]!B:NBW5դWM`AEzj1`W[֭CFFvލ<?(//)**7QPP|t5}t3Fmzw]o\:tUUU۞cʊ۶o> 33綇 33<pQ̙3GrcɈA}}=/_7u8o.}O8V]]JJJ_|Μ9H֭[m3PuN@^:CG4}!ہ_cӦM8/[`| e+VP9sFPz˗/3VXXlmm+.\?$$ ,??YXX>JfhhȎ;#== :C厌d| khh`SNe?kײNɛk2j70sss홙Ã;'_Ǝ˶o߮2M_*M=mOwh{n---Jaaa_V{~VQQ$ ~:~ fjjʾ{ym#%%%Nk_Rծ֯_5)"Ws\z7}]!B:3;S]Al]jmD?}\s|8wlp.ܲùw`w)ׯ_ 6\ezcc#bccSSS1w퓕aXv4+++?9r$/DHHBCC&*]izVlܸ#F%M+W߸q#}YHRy$^x޾3f |||ʥYZZGk'|veDEEH阝;wbҥWESD5!}Pk>!6uuupttmˑ}҄~!A9UWWo2%&&А{@"͛Z&>ݡJڢIYQQ1p@.?<2224~~~Xd /_K(ָOw /JV>F!@w]ƾ lmt P\\ OOOa8t.\ bѢE_w3xbo$4xwgA. pvv`-۷o+2jndm؈Z>xKRJJ RRRcccx{{8vmۆxzzb\kcǎC>}P\\ @g^PPo}\466~!:u1ﰰ0ddd&Ҕ֣ח7}Quuu8{,ŋ}5qa^ -- 1R<| lmV:ܸq666X`1l0|ᇂ냈#̈́ ǎCLL xēO>E1t鋝M9r=rΜ9pss}Mȵ*::MMM-)fLH;cskP&ؠTVVL޿ӧO'E!pU$''#<<\ݍb߮}䣭_}U ASS hcB<Ӻ8Ǿ =~ O?1Bql׮]1Ο?î^4Dַo_f``|}}ye)))aXyy92 ʧP@}[Hݿgrjjj5/U_ZZ .:fbb~.`.]Rm?!x"c8qFfffƊmqqqZV,qicׯ_g2֪ә5kmmeuuuL*;w01c{c>`fffƎ?νD"aGᝫ1l \B-cbl߾}֭[̌yt{Z8qLJGcl׮]lܸq.]k>}='1ףcDzlٲeӓsibU ;wd: ]Ǵ}ڒܜUUULZ[[; d׮]c `cƌaӧOWohh(swwg}aGUO8CUdNM%D(}'ľbi}i 1B!藾;Ӻձ/-!Iw._q[n!11!!!2e ~w#G\]];NS`!4\x?3+|-SKwiG+V1JHݕ[B :fffAII ZZZx зHgӞ&M݅ٳgG|WךfΜÇ1m4vp=1cпW|e:;;qD";jkk!0zh2"9xqnUQ<\r f̘zP':~̈́[͸|2\\\WڵkXf U~ \(]bgzN\v܉;v 55&&&41ת7o"..B̘֑vNuVyy9.]͛7Be>BD"AJJ ꊹs?Ư8N8;w.Wvu][^^^8uꔠ{ }6U!}B!#1xZ<طWN``jccc;;;;vL>555DYYz-rq8qall3g"88XkZqq1mۆ={ؿ?ƏϭinnL-PZZ kkk ʧ3ͼJm)&҂ilTQ,#r58rn߾RL8QPaaa\.|`2„ Q pߏXYYA*B*⧟~\.9s l\.xkMV+++.A8}t2jb``$&&Ǻupur?MY#oood2$&&v7n?i"vLӵSչ)ܿ3gԩSh"ygCѣGQ]]<,Y.]2kG`` ܹ#d2bbb0n8:tHԱbGzB+.1*B!B:OGcvUtGƾ lzGX$$$Dez^^***i&B&\spHNNӧ[QUZUUsss5 ۷Ojj*f͚ nH$嶵 //G֚m l &M6m[cʔ)044ܹJvVV6667nyX[[sWUU!++ ǏSRR ޚAAA(--Ş={`ll~ZT4iUVXXu[;m}ؘ6pSSƏťB9cz@LL D7&/v!hСسg} LlݺUUuLzة87Ѻfffؾ}cug+N<{:۷oG1{l? 1`HRž'Jhjz(>F!Σm<ݑ<{s+FFw\pwwǖ-[pa޽HOO=m6ܺu {Źs+++sN9990334777899!$$gϞEyy9݋>wl\\2222$%%!%%+Vtmu'ɰxb,[ ?~wX;Ցd_Kٳy&s>5k Aᣏ>B`` msDEE ">H6$;;VBNN^lDEEҥK1cʥk_.bXp!.]$}ݻHsGNGۘvNmڊ磴=N g۶mɓ'q5dddk֬Arָoss3ЀJ";;[ ž='JHOԩSzC 1B!t!1;{9զL "d#Ytt4 cIqq1b...Ԕ۳Yf ._8 E9@6zhV[[+ZuV3B5vꋶsjbw_M͟?1sssϳ}i,6>ƘX[[3///-n:! >Sc_1h#әT*eӦM奭B!s@ձoOx5$~B[2hRLp`m}c#xNT a@ܸq B]]uv8pLE!BzbScT5QK!Bz Mq4@FMm~f-m^m^H {"U HTZZL0B!PK!BH[}UXX_~'Oƍ7vZ^IRdffn7!B!B!W܁MI4hpBwwz`ҤI] B!B!BؤٳgB!B!.Bw`B!B!BhB!B!BHD؄B!B!Bz$&B!B!#6!B!B!& !B!B!H4M!B!B!G@!BHؗB!Gz6B!žB!qҫ&*X/'xRO>$bccq=AǏ5 QWWY%\pp0aJ䶝8q}}}}1w\իWwrزe o{UU"""0rHHRC. ʳ7o_d2899?pY)))'IIIZS9>ׅ.k׮СC!J1n8dggwE\mm-+W򶋭رCeZXXR 'ЎK[QW'BRoH$װapĶwbƍpww9KZJ9ᩧcLezAA$ rrrmc0}5k֠Av}uvt1>>>Ą x|Č'ۉRl_VCеBBcZ!zaȐ!… QSS#zT3J{]zv{c o 8<!`ff&(ӧc̘1Xd^J8|}}VC x۳1vXXYYqdffdffGCC=9s\|L<111UTT ;;;Ay8p_56mڄcժUÁt.`ѢEXz5BCCqqb0`c4}uuK{\n222{na DyyyWJŭ[:6v /D(jjj믣{]xQ/uО_WW|(,,_|3g 22RJ9?*6nܨ}Ayy9c[j߳;tƄ.}֋  ~~~+*]j'? UUUXn&L\UU''&t&B:V̵822/^ıcǐ+W`ڴi$//aaaصk&NƻbHڼ0!c0` @O`QxDu5L+SL*.֭[ȑ#Y}}}i7`z͓q\|`ܶBfkk^ypB!!!7~nhh`g‚r.cǎHOOgCP###'|ԩS?.mڵj---J/st{eC aբ9>nՅ.Օ%%% 6?233 g+VॉcDz۷L U_;sWm_4ՉQH>@)u>o+mTWb144 r IDATٱ{N)ٱ'Oj̣}֯_)" }֗-[ϟ祗^b ,O[O{=6ydQt] !6z-`]~v fjjʾ{6)))avvvZ]]M-s> pnxù-%=[6~8svs<:ヒ~&&&W_}~q?tBB_˗/Gcc#bccSSS1w潇vލSǏW*Ǽy[[[ZV[[ ###j|P,^{g3gj qprr}%6++ ~~~Fff&'O^kaa1c\%|||~!w_geefff>|8֮] زe `ddtΝ;tRaB>C-tnذaEs|ܨ ]ڣΟ?\]]J9RYOVQQ˗#99}UJ[mUWWo2%&&А{@"͛6vi/D(jjj J^c<#o{ ,@QQIM6!**J)ӴdB>}0x`eLjvY5_҄/!!! EZZ|t%ڊ7bĈĴip^<<< 7o+ t&B^ۘV赸8p ?<222Nee%d,_]mz6wo}W_^}U ASSl### >… pB,ZHio0~xxk梱ԟ:u pqqaaaM)L:/oѣ7pYŋQ__OOOn}qkhü%CBBBƭ ҂Ç sf̘ŋ~\.G:ܸq666X`1l0|+DӧOãCyQա.H}]ٳaaaABBեēO>ra1uVss3̙777Q[[j+::MMM-إN/jjjk_~:t("""O냐񸥥UUU8vbbbK~ĞVX[. R 慸z*.K+ڡ-f4~i۴zܾ}[ΨX#d<#%%)))χ1y1W_}t0vX@^^._^E!ŴؠǶeeeQ>}:<==/z_o}6l{ +ĨQ=xF1Ioc…xꩧ`jjNj/Jk(.. 0~~~hjj™3g7nŋECtSN1z>}/LLL /puݭV[[tnw}C`騨?:hҦ %FuBU?[oŻ;\4t:`uz!q„ ذaRRRK/ /}ugm(//8Ub@1hܽ{9/m֭JJ/u?{wU3 (bȃbQ3K Pʌ "(ZBat$K$ | ʇPA$!Gpx:?Y.3@ {=ù~p\p.slߥNϧ޶mۆoObhnnu?^n ^z C /Ƨs/ƙ3g?lقcm֭ʘ555:җwh5_6mm֭[ NyڟJP`˖-3`طo~7>|X^s=[[[X1Xpvv7tY!M1-D__~EEEXx1 4|w8sNxw96lU7|Se,s@ee%)Sۨi;-:4i)l̜98r؁ZiddPeP ݻ駟 XZZx0:~@ H$½{  3pC,,,ﯜFСC*vdȑ񁛛$ g`#_.9w\bX[[#$$z} cEE"""uV;;;#H###˗/㧟~%\]]9:IeeeXjN/J:hw^ٳ)))*S>DGG1s >>󅷚tS'|Soprr닔;wN9p]tcccԄk׮"ۏ>hiiHlܸUUUO|r׶oN<;Oޡ)~i۴խjkk@f>}.>yX^^^(,,TϨQEPF\.rB!D7Ŵ| $''nnn={6<==1qD|Ҩ3a_gFQQxO`we HOOW366,,,`lleeByy9֮] T wwwjF ---pttČ3p()) xS"(R)MbUNjԩt_2uRRr9|z… JhjjR5kr[*_}allP̘1C> g&puu#44/"ϟӾkkkѣQ( qGXʾo{r v܉HJJ¸qu֓bccqM)Ү]m6⣏>ҹZB(">>Se\d y\ŧNo9::eeeWW>|8舤$^usFFF!C|  tRx{{#55Uuʻ塪 6mBjpprгu 9s2e y555(((@~~>I_ZVNu'}_~L&sGW߿?j9`HLLʕ+*k[ zd_ u^=MW?/qE/ɓ'! ƍÞ={PZZ7ntP~'ODii)ݻ;;;bΝDbb"~_~el޼YaÆaȐ!x1m4;v,y@(c`̙B``S{ȑ#ѣ9ۂw^)))'<==9ӈB`ٲejH4iZUWWc޽(//G]]rssajj|#˗/GBB>Cܼy'|(^u҂9s栤9_O,[ "";vKPTTDΛ%Dw|c۾NNN QQQD|Gj~:tyqݻ?Arwl|ꭲ .ɓ'QQQgW^App0\]]msrrb 梴999իW똝=ǵk믿鏦zBBj ''G9Xt=P۽C[Ҵo l޼صk s}Mw X`-ZoFtt4lll8!BzĴv܉'N ŪU8o IHRbɒ%x#}jT-[ -- 'OGرo6oތz nnnxqwΜ9;v,F X lڴ pqqT*̶D婼`ܾ}cǎU Aii)^z%}ٳg̙3:vM;B!gVhii<DaaaHMMEKK g]eet555*lJII#99_[7)))HHH 6n܈dO#)) .]!C8_t ^y\xپ7`8::bܹ4i%elOOCP ""F«[n!77CuΞ&Mn߾&&&0113v؁TZJjwh5_#ydeepssÁp19@gEMM iZB!7m744ٳ=z4aݺux뭷IҐ۷w7ƻ|vf1h<On{m kB %! Ĕ)Sz(BHSmmB!BSl) lz&m6 k} l >%%%P(?~|OB!ؗB!6!!33<'B!B! `4h^sB!B!hB!B!BHD؄B!B!Bz%&B!B!+6!B!B!^ !B!B!J4M!B!B!WlB!B!B! `B!B!B@ "B!HPK!Blm('B! } !BO `ww.H  `dd777l۶ zP( p5ۥR)cA3f 88Xe}LL wr_rVꫯ  9i1{l ʕ+;]ڰL&Cxx8F 333D"HR^y677c֭x  m۶udL:C9D"vڥu?G]]444`հ1 *)CwwFe˖qZgسgmD%V~'c>P][nu߰aD"㩧BDDjkkNϷK>,cj@  77Wnظq#'ñj*( ^@ `ߧ.ҥ?i^Z999\mo5$B!{|GLL ;;;̛7r\4mg233affSN{q6}j-ZLׯcʕxɓ'cҥISN>552 8srr0f 8PCff&߿\L444pP(¬Y.6\UUHO_cӦMx"VXϟ+WB,رc8u/^AuE.bcc> yyy7nMXf rr|rw#|rTVVקz2IִGݮP\\-[_|Ν;HkC]/"33S 6>}:<<<8"##!QQQxٳk׮xܞ>Z***/QPPS" ?NK]{2 2 ?~2 NNN>&'B!K[LK˗/ѣsM Ho>L0@ߏ{Y0C` xx# ݓ3uKٓ#]WbEGGsֽ{Z<߿WrGFF>) /۷} ҷ]v`uƆl޼yaaaV_P0KKK,,,T*Unfѣ<ә}ʭ ^bnnnVY'HkwwlذaV/MuvIڛ6m۲eK7dl…*O]l̘1lj?Ν;GU)34@MmM[ oazV|%XlmmرcU1[[[fiiN8aԵ8&Wٓjc/ľ;kiѢElΜ94 ;wNƍɓuڧ(N"B1-x vM[now3Vg{,y8LJc ;<+pxñdӇcǚx8ܯݘ4G|Q7a믐hhh}'}SSVVV_6;v ** FFFꫯB"(P(`cc+V(ݻwFFF(,,X>X p߸q#BCCyzÇl`ƌ<} O⤵6`lxzz#Fիhn{EDD P_?ծz{wy:Ƿ/zhŋ֢#G0?\333^:ͪxb$$$'PٮOM:)>>w?2Iִ]Uwա.ܹsQTT|UզMzMSմׯz)~+vj4ms-} O,#--M|ŧt6l   \~u P///|غu+`nn3f}Å$B!kW`nn+bĉ#믿ŋsո#}r[ o޼ ;;;#F@jj*.]yayV^l!??:~pp0gSND `hZZʼ `gee!00/_F}}=i8C;00L48|0욚`_ Jn݂5Ν ;;;888_!j>}W\ ҵD"T*6o ggx7OjRzpDFFbԨQj ֧΀5k9544޽{*K[K,AccraccY[ v՚!pQ,]111z׷mcjjht!HMMU (--EBB.\=IؗϽC[쫩ַik_UXZwӞ'd$''#??hǏWb3f nܸ ڵk IDATx'B!]O=kkkrfTWWwu߿ӧ ׯnVBO]}}l_uttdc1V__LLLw}^__v 4n ɘ!|2cafjjʊbbbuӧO3y& ޽{<ʊ:fffjjjc5k0g3fP'˙);vcT #G(d2fll|$'' >W.^JKK5kۆ\^z8pUVVC1SSS̳FR)377g2L.\NO!ҖgO<300`Z̙3UUUǏ3wwwŚ8^gɾ}5Rgcƌa1[hbmbpQ޽{2kJkؾik7|UWSַ27=߶m 8VSS,,,?clٲeʸh)DOUm 03g" G@322Bhh(> HOOGPPߩ2ݻwO?!77`FrrrDwB!y4"WN#r!q;2rH Ǐ׺OKΝ;b Axx^_.TQQlݺ:8\vK4\|?,--ym=ooo899aEJJ Ν;N'aժUHHHP{+}l޽سgRRRT~cLeQΝ;A||< oSfmi:jk7|UWESS]WWWD"^%"##qFTUUO?y߶moN/{RSo4"R%LMM1~x*i5uT\t ׯ_W:)) rpHR455)͚5K9-Jym`` 066Fhh(f̘qĄ3_|ilj5lmmq( 8}#,euܹ3q4G#,--QVVYu֓bccqM)Ү]m6⣏>һ|}}! ߩ2.Y޼X=Iӕ} qỽ+`ሏ#tNUS{@tt4BCC1d Xt)wyZwľ|bKMm|ځ9B!\)SII пnkOu}477sb1066V\+uh{$B!goo,"//r0]Ҩo"00ӦMCMMNqoGzzWưʶ555(((@~~>i^ҳZԩS뭭uJفd2dggرcQUUřS;88%%%ؿ?sTɓ'#!!OFZZysq'''s4i<ؽ{N}-_7oFqqƜ1nܸG\ʾI&]S/@&Ev]'1iKXt)pBǻᆱ|edd 33uڏOWW􁭴mۻNop=,XXr4hP|Y棎};ĖK6 88III/ 箦3Ass33t1(N"B=]c`unܸ'N@"t*Mݻw3gT9=W`kӝObcggZܹHLL伲+ ?8<ܹ:_͛6l ӦM`ZcwQvj+/G3gDTTԓ#GGl ޽{9O_ >>>L#" e˖}"qҤI/KkU]]{uuuͅގ,_ qM:t| xEKK ̙|hjjR~ңe˖A$A$aǎt.^'''󨨨@bb"># mJ,\'ODEEΞ=W^ypuuu֛3uyի:ݻ?]UW+R ** W^EHHnז3mCk믿MMMP(P(FJJ rrrIW;Ŗ/Mddd`(//Ǯ]ޯ;SgB,X-w}۷o#::666XN_'B!݋O ܑcz;wĉ'PVV bժU7鈉 R) diR^6mBll,\\\ JU>>>> R΅=bhiiAIIʓw}6Ǝ\RKgƙ3gtzt?wwwB!yb>)) *κJjjjT^w<ٔXYY?Frrr7nRRRlܸɼ:JOOGRR.]!C(G133Í7x144/Ǐ7vܩ/ǎСC'''lڴ qqqolnw3`ll sŤI~z3>uɚ5k0qD*?GYY'T.YYY]RfoҮO? B5 *nݺ\ :TkKٶ&M~۷o LLL;v 55U緕CwǾbKMm|?,>|nnn8p;#G|_ӝ<쳨Avvv8BnbڎpYb=׿n:[}iiiHHH;Lכ^mEPvnkY9||𚠹A^{feebʔ)=]B!O)|C^^6} !BH_)oj@~6=w6KK[Zq>6t( ?B!PK!BH[}b}̐IB!B!^ y 4H9C !B!Bn4M!B!B!WlB!B!B! `B!B!BhB!B!BHD؄B!B!Bz%&B!B!+6!B!B!^ !B!B!J}b[ t!By$(%B!6B!žB!qҧ;XH$022mۆfT(vg}ss3n݊^xBNNNضm[gOA3f@pp <w嬿r P]]\W_A @,scj+WvRرcgL&Cxx8F 333D"HR^ydL:C9D"vڥu~uo( Qm Xz5affoooA"`߾}0am3^K!-|H\|GEvv6_ 3&|c!h` < 9 4.FG,'g'YGwb1{y޿`W^onnVI+HkHt5(2oyq҇~[B,--Y~~>`RTGrHOOg*wdd$B`/"۾}rիX,;o>tȆ jkkuOqK]xzznnnl׮]u 33yzz ?u1cưݻwݦ ;wWŧӦMc[l7|ͻļvX,flر*ۊ-d'NИGD"c=6moB」+-Z̙I+sO[mֶS>M}W+B!}{ vM[noV5}jK;^KXcNJ?;p,زñ'=k7&'~M0+r9|r899pqqg}IԄﰷ򗿨ͷ_?ժAcc*$ 666Xbrݽ{`ddBX`'7"44T{.7|p899q^9F@@f̘L'N'NZ xxx)))m Ά'LMM1b^cDEEHe{"""_A8;077i?M ߺŋ?4ŋEuu5F6}GYoVUUŋ#!!OK6>ۗ_~0b1tGj_ŋ9Ե[bԨQBPP_gG}k !Eӽ[[|RTTsss ~geիW#;;iiiχ)c>}js;u8ɓ'WWWH$ ̟LvVV닺:?peK9qaΔ!aaaHKKS܌ÇAHH,X_~RT:p-X[[cܹ{=qWWW+Wp>;wDXX a!H J͛7Y%>YoH5JúA[MMM5k9544޽{*K[K,AccraccY.7ēO> {{{ 777C&ѣXt)bbbl;wme֤}t=GSSSDGGs )//GjjJGii)pB)ľ|b_MMV___U%ΨU~G>}1}txyyaZjHHHg} .W_UbB!|kkkrfTWW\c>ckL^_{S766=Zkl߾}1뙉 N!ҞT*eL&.ɘ!|2cafjjʊbbbuʉӧO3y& ޽{HOzz:b---c!!!l͚51ٌ3rfjjʎ;{ȑ#42+_UaÇU/~RھRsK:td5¥x]p`UUUʇ^kB&gj#>>=w{&c""""ԾƷ{-ZļX}}rX,f:\M!w^fccugΜaEEE?~3///ԤL,>;h+sGAs,..0 ?0[l2&k_ `'Ov2hW{GۘRSŧot3Oyy9JJJxӞX,f"׏eeeMӶ4662 }M}:t%Bn>IKK Dlڴi,<>>pssD"ǵs΅X,5BBBח0>wvvvk׮pI~'''OGFF"-- /_O?KKKr^sou֓ʰj*$$$..uj޽سgRRRT}cLeQΝ;A||< oSfooo899aEJJ Ν;Q&66MMMv\]]!PZZ%;h+:AsDdd$6n܈*|X|9k۾~7'OGO'{Sj꿴mڮ7+++^moVL0ׯٳQTTKJJp]34.B!~O777̞=8qbSu՞.1M Pkh"d2ڵkR6\///cڵJpwwWP(܌fǻ>BCC/bӶN#RVV8::bƌ8r~W`„ Z C,ZHc+aW IDATW`Νؿ?쌤$7N\g=)667oބ-ڵ ۶m!>#렕/B!;U%Kۛoaii2z >pttDRRRnvLns{@tt4BCC1d'P(ҥKTjwh)5_! qNJJJ`ee}o@L6 555dz!һOYYYE^^^u\zÇW/XӨގl]aaacccmyyy¦MPyzĈ*_"ԑֹLMM{n郃AAA 9s2e xoMM yy1uTzkkkx{{cݺuRvx2 8vibTUUqFII cccWFF233[-/Lk|˩3;h*s{666X`rJ'ŠAf>W۽OL hm{4)))xݶڽ{7,--1sL>|8ZZZa>]wB!os 8qDv>4hqz6$:vvvΝ;QYYDBΝ;?6̙3%%%ԤBz嗱yf>Æ Ð!CcڴiL1vX;AOm<3sLDEE!00P=yqcќmػw/디XYYLJiDB!l2O$N4IUWWc޽(//G]]rssajj|m#˗/GBB>Cܼy'|(^u \˖-H$H$Ž;p%!11=]߅;w^P(TֶvwwpyTTT 11}ڷz3]-a޼yzNǽ{."##~z2WVVb…8y$***pY++rrrb 梴999իWڎ ms9]_N0 + ( TWW#%%999?􄮾jwh)5_#bbb͛7vBrrrz5`bbTB,YDm+++ ** ?3޽trN]B;'ώ'N@YY222UVql?|bV}%mO ` 6mڄX@*r>sa1B%t$%%ҥK2dr333ܸq---())Qy/88oرcBBBPZZ^zw9`8sNXPș>Upp0ZZZ8O'%%A"@%}XXRSS9R)?O6VVV㏑u~q!%% pqqƍgyF~]D!?8|?~r23`ll sŤI~O? B5 *nݺ\ :۵;h+Sv=G+++L4Iܾ};LLL`bbgggر:պ;vSj4mG<Çرc9r$5?Ґ۷Mg=&LO?-[} wB!444ٳ=z4aݺux뭷yt4|bƽڨAA]Y ,Oim>_wOM]{{xxM\H =1eʔ. !'|F>v/|qžB!75[ @v? @s-8pxxBOII  ƏE!B(%B!>1M>fff̤y !B!BHC؄< |B!B!t7&B!B!+6!B!B!^ !B!B!J4M!B!B!WlB!B!B! `B!B!BhB!B!BHD؄B!B!Bz>1-zB!<B!?}b[ !Bb_B!8S߼ypppO> {{{̙3՝Ğ={x/H  `ddÇcժUP(.Y3f@pp <w嬿r 8򫯾@ X,ٳ7,, +WtR)czLp9fffDJlnn֭[ /@( ۶mtYɘ:u* sssD"ڵK~GBЀիWfffFNNΣ(#w=1˖-׵4%J[O>}륣:?z[p2&h]U7lذ"xꩧZ;+]Q"gcL*׍=7nG5P」3À0~xQ|ZO233affSNPm)!B~mI}}=bbb0l0a޼y式D+}bѧʠ^PO 222pu:t"x;Gdd$r9***={`ڵ.Y8uZZZ8SSS!>''cƌ8???dffaaaDCC'B,̚5KrcXt)9۪ ~)׿>x klڴ /^Ċ+]rJb;v Nŋ1hР{|tTXddd>C^^ƍiӦQ#|rTVVu{tT'|F>&˱frr.tmuuu(..Ɩ-[PXX/ΝCddՕxEdffݶauӧOg]_c@[{GW֋@`ԩ?S>A"`߾}0a3(!BMq?$22/_ѣGׯ#((;5􅘗/AO0` I ` `08p0?`I=9S=:@Ou70بw[L,s֍3޽bEGGs1Hee$=ڵk +((P+,,d6667` co YZZ|faaRr[uu5344dG䑞;UH0B^|E}vիWw]477H$^;߻D6l0V[[~~BvY>233'[p=J:tOTwl;wNҫw^4 OM6mٲ)uZW| 377WYt9GX;lL8M4OE rȍ"%嵺?]WaW]X9dAN9UD@)P R6mQ6m6m<w4y33DGG+۷/܉'h%,,LٱcGm:e.cۂ񭷏}L_0a2rHy{1eԨQ.SX̙3Jttt>˸F!6/k|T*ҥKSRR,sݥ +Ϙƶ7rmn䂛 ׹+;K[5=ܒg`W'f<Ν;!C;zƌ<#@.mڴ!((-Z{nfΜ;W_}Vg}v8CVSF iӦQ~}hذ!K,ʹnݚ@իǟg+lĈ 6` **^xXNN;vԘʘ1c4hvPn]ׯow͛ݻ7<|;vࡇ744-[ңGV^m{.<<=z}͚5N}]Rߘ3g&M׷2 .dm⻦(L&Sۼݽ曼[\i㝦mQÇmgffr57np~g$--g}ESyWAa4i҄~ۥfϞVMJŕ+WZ}WY/emgllz9n^'!!qԨQ8qvd3f0i$wCqUV)>;*s|L_Ð!C7tP֭[R;\v޽{Oۍq׿wMdd$ٳ,i%!Rڸɉ' !&&|tt4;wfƍ1#i1oinvY3oӦ s;wfƌ\p7%ׯ_mw̝;3gжm[h䥗^^cȐ!L&9gΜaΜ9Ŗ)˹sXhcǎחzf9SO=ѣ9~8 81cp֮]kK\Q +?`4Hڵ5jTjLÆ +M׭[WgϞv M6ѧOu^租~'77m]|v>}X~]2d֭X,_ީ+}^'%%jժ1j(bccS|ā={кu qEQˊˢ&&&*rEQ+!Rt†vSxxkW/!!A/EQÇ+jZ9w\J{ E*(2}twU'N>}z1سg(r%%88X)3͆ Hj*z^ REQ*(2{lG-*[lQ%T*o͓t:ۥ*۷oW֭T\—Ԝ OJ,\Pr}W>R6q޽{'N(iii֭[͛+m۶UfS"oѣm(W^СC7|SIOOWBCCmcS#111v%D3Ϊ"1-g;Ǘ3g(rEe@ILLtjJQʦMSL&%44Ѽ%J"!Qxj*ZR$%%)ǏWƍlRyK\߱ :)X1H J8q‘`^z%Ο?ʕ+pmڴ~ߟa6nH=JvtѲ2e ( ׯ_7ޠk׮ڵ TfϞ͐!C޽;/_FиqcvJ&M6l[n[sEҥKY؛7ofݛo[ҧO2ceРA_ 6Я_?f]Ν;iٲ?2۷ӳgOrׯGRѪU+rrr{+#JϞ=meDbĕQ撣FbСTV2nܸrݬŋ?_ 66ӧO{8۟qĉ[?05jdw{yRRR/2-rxY|WA gzb% r ӧOgv7-ME]lgwfk׎AnXz5~s굖+7xӧiԨZܹsNư0&N{GZZ/fڴiNYެ}пK/##]Qd\#Bڜ@ 6m"33~SNQn]w Ώi1oi:`݃{lgRݛsk.R{qի?LZZ3f̠I&;L?,Z={n:;=W؀l~Я_?ˆ ޽;Z֩vJzz:+w:؛7oo߾ǫUFvFddm͛ٲeوgΜ!--ͮHLLdҥt:ZhRl}aժUv;vڷԒ d.{'6m3g̙3tvM&:t(o]ǂdGQ͛7/u@ߙ|(bחƍɓ1L;۠v,]n>묍77ly]lg/vp4lذXt:VE93f ˖-_,WJU}쨬}},_nիW裏)`trmAϞ=oͥiӦv 0 ڝ}zj"##ڵݼuԡuveDݻ7SNuxFb.]pQiӦh">.]_ΤIV#Gȗ_~lݰUM:VZѪU+̙Ñ#G8q˖->L,l޼9gȐ!O\xe˖駟:gmPXϞ=y7yꩧ8 IDATuKbĉ;u].]}WEwf2vXvŋٷo= QFn0Wyعs'ΝcL4SN1p@Y믳m6B,o>;*k|>blܸ3g̼yXjSL*ڵk9v?y"##8p &MdeeaÆb%JwɸF!}5>;w.;v ))7ҭ[7^~e*™1M[a-^Amɓ's=СC϶my,Rȑ#i߾=M6-w>???hРsa͚5hт 2c x 6lڵk풝^-[Yj~~~>gZILL,v&|2۷=6p@Ν;G^ʌٻwKzߎ7oNpp] jڝb F)6!CXfC !55bC4:t`,Z {j*R+aVX#GG Nqjlݺ7|;Ү];Νk%ʧXt?˖-[gԯ_3fo:w+}B!ĝqo@`dW4&Tn0|KMkҽ{wI^Fbb";z:!B]c_!B!Hhxգ=3;4nAD9h4"" gb q'[Q^D bk?PV+VC?eNUnťt.&%/7jQ@pAS}8B!BTԬ]W׷k%5$x|}=4bh21_XgWٺ%'TӰI3~~xfEQ<ۗSܚS!B[^Cphn3'<S<}+g ɓzf-01~AF^uF:Ūe__#BmUuJvzUbjl6yֳOVbS$ǁfT*HMD`p3=ڗSxu"B!Z,LkQ6Fc;xgٻo?ڷ+ˊ=֥c6hP)x3Ono/'x$y].JbqLQ1`ZQTvg`[VK%)g߉LġSWa4T޹bGZPff#j__"Cѹ&ږY!B!ߝ}2">>[?h1Y5Z։vw,$O`[-VT*O&KB~J,K>JjC/(|{l*3V"z>ABꇿ8B(IKϦ{[jAFp)- l?ƖNӥe]iB!B}z>ĆM9aZ4eyl#^nc'0 ۇc,?F^QO2n9§-仭[i߶&O;3ұ#H@m۷sjծ͋SqFN/@Nag S&ӼYS+mog [Ν9pW>9)epOMƘu@1DV??\r^,jd4P+VEdQ!ZZ $P y]]7V&'f O((Qc$=ٗ x:~;2 /W-8|xԘiwċ<7vF]qԍ sY9);B|Id !B!O1t,^ Uv˗K`lݶ0ǘs%-x|wWG\ys1M33o/Nlgæͼ8u21||Ⱥ rj/OBT|!&kW.GՖ#7g|~>+xf{Iln #Ow q< 0 "EQQS.%)ӯEHdޘb0)\L7q1szVѵq0ycs||!Di.eyCpp`C!L(jg 6h ڀM3U:e;*B!³>¡#G8y4˾ZI> *u9Vӧ`"Ϸm_(6hd՚iOH 6&=k{>GgoxQU:cݻ͚6zjL~v"lٺ{=ԃ Ɠ#vˌ$%g0ͳ38}:;t#6SQR_QO":FUaי,z>@fv^u'8[JeH,*\~q LVMH`|*r#jro2~x|2;Gf8؎ !B!;dPP=0_,] S&ͦXsmzt _}j"s%,V+ ׷=Vx OJjolF)qj{4 Z>6&2s;3\:{p5jZ\M⦅Sc0aBgbW\?MNawl5gb{E[JeH,r)_6?PJ$|=(V6Lp+^rkZB!B!}~GG.&KRFVMF#VՊZ]CP`01NWV+*T|g6՞(XVN<ϯr⽡uTkbfUphCy^[Q\ ,>ܞGFd+mvVW+|98>g1nE7x$d&~tq<qMq`jx"O\FZ:s| mKR"B!BQă`ユ>/<<~}߭[yb;{gٍq_~mn孿h$/;|[ioUK@v"bEy6'@cPهiV]#B!ĭnL} xl]{eب5crrsK]nؓcb7ҍ jeDGGuV󤥥3ШQ#hݺ5|[/COfS[VL>CqFbӷWOf=Jzz #eΧ _Z\rǏ۵`b~س ,Z>WO.^$egZ1d]V5Ƈgx7 _:IvyxE Wrs'?p3}R/QIՄR&xmuKj?霙\yΧ[s;hSfޔW"&x{SW$.Zx;%K\^Rg9 _MՔ6׊a0:_k$%_௯_%FXy~;Ē])<@~RJD!BܩE/oSN觨_?_ /oJ]K4lРJbݾ};SN%77ׯ;˴iӆ~dٻw/QQQU(|B͝W+s`^ßCv羖$O~}1^y zf>zt|8ߤ\I%"<ÆиaCXoժ FQf̘?ϓO>ILLf̘A׮]裏l5jԨJbιӿO:s"7kVӹ6Æ~f&W` xi=3oJ!3|%ҮM}-ϕ| .j{i׮|t\[\Q.^L]' բbh7*Z~>C^RB=&["H˕en#Yy Xl5m7[͇> Z‚FwDoeF- YsX`s*]oZLՔ ai݊;w=wcǎK^,YKm;ЭpxQH:}v8V!a@'/#r0Y˛eYm|1ϓmz"S9~مmVݺNЮm[vًܑÆ2z<l‹S'`l۱w~?W)KlwæL0_.&4E7njרe>o^Kʯ`׮޷Ϯ={ֵK!'Wr7.Qg%z Q:?լl}!Bq'Jj*wjf=dޜӼi|~X`~~ T׮]###0FALL vgc ϓ=]ù$>C:QYSYEOd-R2z%D1*|ۈkZˬH WUF 1`۾WZ,ڞ',XK\GyLPN(9W9c,Xy\4 I+eKnn.g;oо}?ڵiS6F#˾ZYPo <>-3x#41hDϖb>ö?9b8?V͚o{?yy8zM&=='Oѩ}5q淫,f#C]~&*ŅKB! ]IM f2q,X~}y3~z؞hd՚|,'$0gY~Ce_ŋQTL6zYfcFE:u۷oQ{oor (ˊ|%;+K_!z5=0W2*_|u:+3A~%_RU"]4>Ur9YN)X"b? 4Zu=P7hHnn.$ԭ?;|)lw4ϕZ&M9322233~ C^:۲{>6q} (u nd *nT߂ժrEQB!LXXcfͯӕtxo]숈Ega~MXJ+PCe'e]X"4e[P-0f^ȉ+xjN~A:u(vjZӸo;NtK(urc_ϸ[t=2hɶlۆ^G~g:^Sm\9a2ZX,G|ZteFOW<>'L[<(v<}z]н!@IoT>\S;&RڿGUGB!=I՝ި-.vQ&Պj^SUh4nذaCMReI]^%Rpue*'7Qc>ҾјKrΊԐe|+j`+.W z7g3 jl2Զ;ctf{w+PPH++m\ͱ2kG[ֺ}Op}'!mܙ6^Dt3 YKAvBl8Kl+y:~ ?Ν=_j[f 58x1ʱ'Wss~qԮ]lc'ɳRvmU߶M.xv!AX}[P*>~]Y%89 vv=Z.B!DY9Vq{͡eY94 ={dժUv;vv%'~Vz}\}.r<ڽ%:ԗ\/h lwiU˗ţ#sOc2=Rɟ DHvs9vEy;k!OŠfZ|c ҩL8J"#r4Z;.~ IDATcS$NK5X{~sʍu]p߽=KFؾs͚6e7ߒr˗YaQQä\&77@?c\KODxXa, -={`st P.]JAQ"##rittОg}Df ,cQ\ߒ>p%\i !Bqߧ׊N`媯9}&lݾF`7 ox8z ~e%F_ /'|g}ƥKXr%K.g8D&yV-i_Ӯp$9⿷vTMQ] AL áL\@\=Zm0V|WXuFO`\G?P2/ U@C?>NT%ȫC:ޣ^LXߎmX&Ydge2/[~P m'̜M]Nnr~vzGعk7VIQz5=5禽@\l >ڛY& =7MDmx1ig(h[y<: sg}:=}W jլɳE ~bv'Żw}~!#:Ĝ 7- TXe/ &3} *J !B;Zf;Iصg˜Yv-G ]johuL{5F=3qnu1իWyQT 66O׮]Y|9ͣaÆ|_^"}Rh$//*:kW/OYƤX\KW *@V*“Ф)4?}o{9ٳpt}0ZuС ͮӮ(6pR)bW ~cjT ?'-&MEb) dLN族rtuX,f<֒wG˞sj|Լ;vwY]zNFMh4$oA)6S~M2ebw%%*P8 褤mF3oy>ßwהy6@?o'7 ߰nEAQ(fIwc>r)=ǧZWB!BTвm'OQ. t{bqW q%>;r O?[HRkZ^^gNAL\<ѱn$ΜMP}nq_Gz4K' 0h2+`LE~o X MBRd*`P8rjf~=L@}L+[ȕXF2su Fvb)Y9zDVVf9ZX,&S$^3\Cz:?S9:,\y8髳.ߵU'/7kܽZt*y f!ѨUT*b1wzI{JdMpA+k!B!>)JoΝ&z4>>fsgX;JOЩyua1w+%&? =0L +z'LG2dŘT M(T9Z!zl22:nZDՂld\ƙRZ#B?b6ɾWmgGH׍Ʒ-;c*( .(>c+88X^wE#2B!B|=Y}XV,_76s-=f4){,c'@Nag S&ӼYbm;ķ㏣Gަ}0L|23I@Dlu؞v\9ԮKSoXa#W\Utʌ{,\__ێ]<ҿ/N\fcB94hҼ﫢(WZv@/j<#tD@.0咝uC^.Jj EA]0c$;+}N6FC׽wLT 9y4:tpiœ[SȽ|ܭ}FRhVW̼W,o*Ws,:6:h!B!JOV`ێ[, Z-Nt/O˗Ҥݼƛvӳ̛o7m?\Λ qE̛gϿ՗jRj\rgq!"̩GO`سm /NtEjt:Q538wbQQΞ:NF?/=z  FwFD:4s[ N<5I,F,t|~:׭kDZwDGͲ:E|.5T*Ծ!\Uqu\4eLd\:DW !B!HOV>ȲV$ԭC8xrrra>|A Hv ;f z^B]YyjaDUgFsnz=ԃΈ!CPC]5߻v)œQVF@X49oflؑ\MN`Q8ᦳtj^Kø w>> .\ JYwvH,^VS8-6̗Sh^" SPFLP H763ocvFSz$?W4 '.&;B!BT=>Y/`6iؠ149\&6&z%yu:_'%aZy7PHҚf]y:uj-w%㢹õ+y5Meߊ̅gKCVƍjyuFwhUk.*;voVUlzk;3hWCG㣃rܘCR}P{ VIb7Gyy]W-0R2rINfK8t  A{.B!^DOVрjbؒZ-:T*O> O>vnG[QU]8֯RjO )\HrY"Q ?< _K##-]i*jT*u l~Z5AB}SSvufex[QcZ:LUrT*S$YRR׭iʏ'$J"[`(`70PV3VS.mLe+(96ZE%,$j3u$t:j}B!BqW#>ӺeK ǎ``~nYGlL޳Mg6oQaŹ+8{ jlii E!hBTcƒvg闧Z3ԨG۩JO`M@Pg(H,?=ޗn(+NQqmЦ~[+\Sjb41  f3F:Nr[FB!BӿOf!okDGG%qܲF ʜO}Kի\KOqÆwTTu^˄_8 ߂NGHH_* R/_/ PZ%Z\KJbGEARyE_*-N W* ???t:mR|?4}B!;5, wtc꽼ӿON<9>^l1Ӧ}3F|?g+D3rؐr'C=ػGͽ-wqKwz)/ea]xR4&@{y>'{ WSSHLL\MBBtGtN.?CzY,gr))9 S6BФ mV֗/ri,VKX,VEEsUnl`k%84Ļ\F᩾lp(!"B!Q$?KPH>>O 0$?KLxO|< ΐ ($ft݊vvc)|iD q#B!LhxG V]B½(b!+3g $ гr|R2'U*ZjHVxEK:h_r&N!B!U/z4\ܙX-Uw巨8FC@@15o}"]p¯*.W%q ]ZRS}8B!BT`$)nmrUy< I ӪV [OX칲NO%IZ !B!B^^.I@O0bnŘB!B!7=B!B!B$B!B!Bx%I` !B!B!J}O B!B!ZztO`~&?Vt8 ɓ'iڤCdggs1%y:NڵkdegS<mRJ 11syt(NCPPCwׯӡv~9xV-Zx:ێm+m+m+m+m+m+mbMXz:)!4[t(B!B!Bq_X+.p>6b$ԭ鐄B!B!v>eϾ}J`_Xg鐄B!B!ⶒ͒eYUL&OהB!B!B! 3oՊ)Mn)!"B!B!!88D>g^yBJ`U3'С};O"B!B!wjΛop_ǜ>lc٢%y-B!B!pV,??Pl&=сx B!B!BqGa=$B!B!B$-B!B!9疩]` b%[$&>FML̓K3ƞذ`EAEQ"Hg-gǙ݅;3zvg9rJDDDDDDDDDDT&"""""""""6$&$1MDDDDDDDDD_D]ڍ1MDrbJ]""*57.Ƙ&*|*?\"Q :T~6F:'8"`R"ιE -p+&*楊]]bJF]"""K`m*_7(vv.kbh&dDDM%}/Q9R*/JDDDDÜn@TҘ&\&\\Eզ/zOxvGzG䱮-m]xH%!*%[+ 'QG/}ʕT~~3*?6r5UE|*&^kw &ZÊ^Ы+?ḌhgT/RiA>uAkyL ԫvh6o 4k/[(`cT|% """rIBDDDeꜻZ]L`, ;]]?/"W..;ƶT~}DԹ??ӓ`9ޫؗ=Nb\Ce-ODp\R(S1HI׿R[K͚݆;]χ_pqun?Lp8*6Q{d@DiBip€J5@D}ũ45bL`ufl1JctBDDDvܕAci#bD]t5;u":?ܲFybhMLY,n""2vk\MgU3WYmic 9k&wzSyCR 7\ܮ)ϸ-Wyn0m㥻\pE赚<gvgLo{]_x ^vZػ`0ZHo-qyt]ӓOt"ۊn>n}c+?ĉ`Iڮ#hsmC]q4/ 2V0cۥ"{ҧgsdž\zR"кN (;?GIa\sW+hx[ӻ*tOw #\UҌ.dema |9>M=]sëq|B+~N`=H1gV2꺩 3VLYĸ@xPWZ'ւ?H"ٺ=ߨk.y1BW=13߽m1=ceK+o}3ıgٰۙŚ+3ye~є8?Xaڒ;V{{â~pԅk??L5OFr}]w|_^2eQ&ʾuw+λ7MMiaUW2mT*\xqkym[_n[{U4)?N"xan*$tr,ֽ&q>M.ֵz:h[I5_ƨcwwo'1eaBs\;tpI8%͝E]9݂f,|_K|߸9eNuwLD퍎x{iW>ODq+q7#qB, L,׊՟ulLbje Ǯx,YֹagۋsS 'EВPVgLObu[ Z=C  PlCg))}MO2tݐ: `"`)L+"r\ IDATž&Cju *%LC _kJSvsF)}/(wo z15m uؐ_<%N_H7(W|㘿ӟG` mS (m0QLTB4p4=2 7Yo`&F< KfG p>]J<01@z~~ڰ4DHd")Pe/"G"*@C HJ.,POJ{3B~ּ5OFqaz#~|"JSf0j\hzOL!$*Q} DR # 5(TLsS_7~mm^M QZ+Q_)7Jn#m :)TPJ+ BWg X0F~~2X!Ws (yR []\bSx$kltO+ֵzZk`la``i?ƚ{Hl*L`ua}}uw9 ؆ 8h>O _)1A*UA)H)_'($2ֆ%{M~'pZxU քU0$2!|\O΁@uWhJ({6iTՅi\}By.[ " K4FKRခ&_ 꾣10v(g +R TR)ߑg | ![`DDe@>{ώggJT=3u-%`d똧Og^]FT~^M!LC}! 1.!&r̕٭ûTOg#.kiaUHR_CZ k ,Xl4tߒ-lrv xjJR]JC -R.SmHGg^#:(0 uu)u=BuF!:/߫ HfcI11{ZhI*+omi0$0~B~]_FSP%vu 7\pRB _I[c?72{O"leUr=S*LU~@M6 $lCAfc8K үlɡ;+IA.>I{Xۢ?t}~N Xumtq!$11i퓢iuӖ8-1Vwg_IsCȧ|Up\78 Zࡋ+b t[ d_D$ခT0h H~l9su̗Ӗ)y }ĬU.WI4THWHX'y#XVJ3| u./0V&(Q 3$:VЯhR Gm+r[msh X>,:>+C-ÀDڀ*=2 0 H>.ֵ*+ѯO8)d* ԅ%z 0$PH:zE܆ ۛxVå]wO+l6$1*wmuUm0@2waj.,QXq;J?MvV 'q+q5BmH)az 2hoaUPX٬/@'K*@kB.c-y%3 ~SV 8V(g_ 㥾zlfHݖJ:tF3P_!rTe>+rm̶R"\ ;K0k'H?&H!( ! ==oã׀*>YI9BMX'D_ T4w1Pz"*KD #MV m>n*ԉB >!e]Mqqit~a +8t۬zyl{-g@@^bZŹ)uA{63Z]9}d.&fwrGK4;7RVniƟoObz|ӗU xGUkz$kbLDȒ&M+(4ව}&=mU0nO"QhIzȸ@u@ 5#aUo1Oؽ,gb TNmE4'hb@nw!l%a]/Q7 ."I5"'ɣQ2BZVweNH ` \ i H)0-ܤ{df=06}ַXšC-Յ%K'2khAmUAߜcnnƴk;|ƒ^>q`l*T&r'Yg[&/H㘑su;[pya(~v\~2AMHOІf/L; l";>[>ĔzPvUdF#=o`7/&W uWJABK\oOsBO 3wє k7GpP%IGasÐCR&7hN(|Wo6*owm#L - O)mݾlzH<D~2@fP*"s}ܢuwb[N]= T>à &,LA.JF*۾]`@^edVvJ>Kv*?֋+<} ]'l}ūwk\B_uW椇1T&_uV{NZwۯOpPӓ9eaMko.3 ߚAdC Q>94''7=LXCmH"VT6im4'PLNeܤ,PB0?]H$*8^n#;ދ~~|7MM`5ո8NcczsZ܌Kp xS=fhMO'Rnm}f\gIR'}n@,ٖ7rsru,;1x:'}!-'7s+e qVu_"EueK7{0ig~,Oft]O/tMIhop<eSYݸF6cgl;!(\vd[rWP8d )n;/Wdp  ׻B'ʽwo۲ox~~|Ǽ5.}o?clmDO/2>iGmz 񔞨 غO e(d'k ֤Bgn7VlхR:!taF8@*X>t ],K{0 m:A[|x`8!E<13rALlzA>,i'zGV7{ZzB7^x49>{MƳ^U,rvvLV譝`k,kOީo= S9H8O 쪡>9E\\ul5Ġ>+ 'p z(Mh޸jX vM5~D7[ZڨWk70*gNe7mތXQ1p_wHR7BB#r[w=?'&ʒ .=[(Zyy{TX_nο"Hg{O:P HGq`!|۾fk$n;/v+$?Ї1.ώlz bɌBYt).}:XN?W_BtG$ ?aVRuQ=Bv޷W8c#Y ,ⅹ)\u\:__4yigss3*C"&DC@lDZ_ȯy'U&bi1!nɎb[A>; ,Sm|&:/O16 }ރ-cb?N n#;%gtRִ N_֎b5kZSب H?ZUel<;;bSª&CjN\>c’ Rq߮NX*@l'ikT"Ll ?:ʏ/6yAZ/qa~{b'qW4yʩm ѻ{oY{=oWGX@kJ'0s-``y6q$l+C-d\w=6gq{[ o.ؽz6UH @-a/\^ol'E\[.vQL:jQ]1w ;H?.8ğ?7Tt5m&~#;` }}8fCǯ]Q*o[h\qL??}7Cv&Jv~\rDΖׂL`aG듂 t8[ /ߒ!Tfa>L\xhKrI^}׃]|J^Ӯ!~Ž㇮P?ڱ3/&fк0-\·yEp  ;)ɯ=,d'}Bb#nJE.~鮾KD`v|{L~)kR[%kJY̿|# `گ ݿ!&faT>>.og#|k8Q3rn&}9;{Wa,{d&ͭy~y/R(e7ԥݶe| &[ qP i(o\;/5|Ǐbꭾ{=إ 5WeIwIeRù@C(1)/ZnV>C |lhPd][1y="-uq5. #ݘ\2f^a~r ' z;s_J-Iv!Y![J&;?0z/&=#vi 04JAw<vNO?փk8ǯPi:7ģE ;R4uO੻k\UED.: oswW~~ Dww8ulzbJv !{ru= n JK%->ۡ =1L`|UmMOcKsx󹜼JEW:@_X 9u`K=~z4cBsklCDDSEG.D}ِQי"""""6-.JPvůNK"""xrR_j_UgEQ|ޭ؏w=}@DDDTNa%Lͳ"h 6(63,vfDDDqXE "bz ?yPVr l*Sé ]~ YQP`b׋WD݊ ^np b""""qNE """&Qס<'x~3vD]#&" ۡFKBD{=pQe@D[|>\W .aDDDD}B> TNB"u^]͕dtҿ$EDkx%"100%"*g/5d0MGE*HD:u]"D-Q6Q\ȇ9f IDATDr HDDDDDT47gFL`GDDD[p@gFL`F..=rH6mp/DDDDDDDDDDT&"""""""""6$&$1MDDDDDDDDDD% l""""""""""*IL`QIbJDDDDDDDDDDT&"""""""""6$&$1MDDDDDDDDDD% l""""""""""*IL`QIbJDDDDDDDDDDT&"""""""""6$&$1MDDDDDDDDDD% l""""""""""*IL`QIbJDDDDDDDDDDT&"""""""""6$&$1MDDDDDDDDDD% l"""""""""ڦ&]ڍ1MDʸE ""1D "-]D78)pu9QH;͖'= gPkzE * %&"""ږeyT8(DDD }6(_'s7MMDDDDDedدrUc!\ '^h۞*vR&hu ϸ2|UO0-vGODA=j*% ^GQoYcdz{I,Syjw`P-Z$D塤Ӗd]^&E Iآ󃇸3szf3ݝ|1?Ň+#Y%1u)PR]*/x]O:'˜]tE *%YP!.Pa,WbR+-vUP)63ȧDQ{iT~3-߾P> "Y l&(f|^>p_EnR i-v\0rSH7gCNRi3LfpbhGJ: v<-Zhf,/4\N D_^+N`ey^;2xu!c[*|k6Q=I\B""""*oz1-0 &wwL]6% "nyb=Qw"L _ {_^昇&NXAGۮpÝX$c}ҜnY>lEni{ZxkIѴq`Ck%15}M=Vl0{Ug~HNkN,#G0V۞okUדmSRX2xfv G@+&x$߇>!pڳgpذK]g;ӜPo?Sz< {88z-4f`Ukih8},s:;r&/H7֤BncD"M4%W`ʂ|:# 4_vEx_/пRX..;h{Ňu^-tW -͍K1CXuF< ͢}Bo,฽N߻돳^_f'O]S V'1eQ'*,2~'69]qH7yZg \rDsV;8q7d$eؖP") h׮ K4F=X@o $ !)8. ]o 3LC@H9 !'@B""xcqB- XR6:-^+h R@ٹy 3M\Üպ{maǏ Nea ba`3q :R!K1 *FYo.,МPhl6Lh)8 Y@ u !5>hJauO`t? R I4'W_ڐXÍSj$BD/q!@2(Ԇ$<pUfd{Oi f~rtm` 6u9F78bq1Ml{DQYW!D4" !VƨR'N]ƆJRCj$|%ꠄ! >Kآ*`ǣX U5A QeoA[B B2~G?$[*oҍ[?Y2 t]l 7%Bw?#uzM4/TcbsL%v 5iWA ӓ IR&h h5AڐĀ* )9,}LRsI; B43ucm+DRڐD_Z9كmǡCMT$VTWJpHvrZA`Hoco [ N8Z{Jᖩ+! z:p=e=m5l/Bz>ٞx$&~DMPbS= dx3!HRִ_1·}$V5 HAc -7 0~\yM66E=<:&X-A-R*RBJpB8oX"Qf}hx\+K*Ttv$2.c }>SÄ/>S|D"O :1׃+&(|HfSu;K }ua@<`fqt0[d:ٶ2`!_OO[X?Gd_,3(O"h!@Pw:foYdn";rZ;c Zׯ zp3DMP`jWk}D6=j.Im h+M#1!TτuPۀM1! dQsCU@7# aKzܜP<`q?Nؽ,T$lK_!tٚ`cnó}` ; mɬp?M 3iA(n:'_h:>M:ϒhM(-] CUo@ǞB&/HC)/a }~}O,o&38>lk Vo߂FۨK}@֯A p\O"rq6}к6p7&Q_!ђPH;| ZUN~F _8oauftp( c k[=L_Fۨ oi᳍.k2..SYo@ _P"` hq|N>]6`O u*_Q6UƒRYouO M/1DBaiXxjʢ4a}4)~?L:(p*")aB~a}$sq [=N)tSpy?q\6l w{N@)85=%+$*}@ @OeWv}]կܿߗ1v|t_3ulvx#ϐ}\踡)cdm<3/~0eua*{37e=DSN??']|xqN_cI0 &WH|ESØ=60#^k 1/C==$\%i#Voo9[ 5't 1-aH}i[B*\F:k _ yۊm/f>YZ?y4WZU4/hMR Jlh8l\{Vny΁L\  *e~H΍n8鶾E\7`J;BsBJCj ,bEYes7oB-B7g|SgsH?ާ4jC~ZOEu^É8뫚7ʹ%W~\bDr):O%s>'7H[WD oZl a[Wto HY/d>A$-qq*} yxU7oU7N@ 1Ȏ"&0t (^wFQqa+zuttQDDQ}$l!d#{ztNwgy餻ԩSN)Cmа\'AnCm \> 5fR㔀$7Nf1(5KLfM((` a CwNZwCO(Pr`Z )Q 䗙Uh YM ur!@e "(,' :2$@lV'F[N.EV $LDQ@,L̒Y'Jv Ma}[ Y5ԬrL00$Zz$6 *̸PlFqd;(ߡ3WC3 P h Q.%&IABe7juW)ړ>QKuzq >k@`Fj IEa2GR9RZmFH\i$E* IrU V`tr]i$Lryr\d1'Yj('})hBmP ,$ˉ5_sN'ߞ#1J>MPbױPM%-_W]`L<#S 4P^$ &RgFJ>ٮ r zqzT K A%#HU*Kz$X~k-Jr{úˁ|,ʴ|PmgH0K+_ |BN!=Cl" f@% };1RDV:FЪWˍ{Qo4I4پ^^4()_05BY\X/,@* rDKgV:]lX~fe0YPm 4LGwMlT^nu H"@ol@K`;rUZγ|ԧs %om*\FZ 9/TZRJ@u |Vu۶/|] P+ć+P3(ʝrb3"E lr͊/ Zem\$AF"Z!Y'uF,wWI.w:qՌp\c,Zer[(R\fL&;%⢃5x cO5/7cDHqa"~>]Tg=+%$DșC:tQ L+Ř7KFg5gՓPohRؽTwoUo8KwOB3mcx8# us5c6^1/dAvڭaoAUƱ=j/jDJT^ŕfDVaem]EE&vbXV3_4"J̶ʂc[W $vDW(;^ F7X YtmI*\*1B qa"{q`xכἫW121Sw4`=Vw9KPBK&dt񆨺]ެN=7v=#[ro~A|dxjzW@ VpS55^yC9jDVDF>Iitܱ29Oڶ}8rń^qJ<1:ʜd.ohk[-۶u62/umyڶ^ <9& L  ,Mc;2PydlPN9f$EojӶ=5xub'm18}͈~UO @lMEI[핸+]S<l2 wFmG~]/l_Y\g $_*l%ש9EF7W╩Ax'yr!&'m[?MBvs46X]-9 ӈׯo.ͣxxxL;C$܌|wV᱑.8옾p]9?p(4 ^ λe{Iu^VW%(\7yfhuz<=>!Zz빵n&lk7M*Y+'aJlZik_*W ^7NJܕAV`?>eK\) jǯJo -yu~uZgL[[^ZpvRdC+0+MߍoT[v0x uc 47gc`.zkc6wg{wV㻝ο xhxg 5]tճ|sޚETN֓.EG';<_qjj|/5_ݼm!\DV= QAX-ow;oyൽ=q^~z(ڇ ^7n1 A0$k-!BjD϶5VԆ߆":Dė4@l<볂/׀LNVmGD?+Ck}vj<Sx3׌€$yZO[4^-!Pp"ou.gcO6g9i0K1-q"֐ʅntG/5hKUQryC\6BNf$ذB1FKgHY-`?v |0 rZ9%6< Vj7YZG%=nlON:Y74̚k/&FW0x Uú1sֹC4-xMpE7C_XuTݓ2m[J~8.j$6x[,Ͽ,X'u]~ǐ*| nEYl7f`GnVm]JRuCGG0ڇZƶmK!Rf]"{W{w4G˶5ۿsyg`7z~Vkj~ ^ↈ'Ӫ1x2 cAg9{OgۖZgƳ.hiu⦖, S9󻵞Xͭo=T#g=ڳmKD+F3uWp(&jAmYlY_oU*FS,zOh6Qk4ODf ?Q2\*^9+9C5+]o""""X1c6y¯- s 1MDDDD#ltyd8/ۻ!e\e[Wl׉mօ MLe=@D-12 `SzP+D|1QCDԲ8u `qC_'Ry'蝹NyDMć2 e""?LqJڮs(7""oؾ8 `3[~~{o $"""Gc,OagP18HD j^8z8I_{s["fDW@DԦm{5"/DDԲ`*""""j#Tހ-c,lV& `5`*"""""ꕩ|Q[6M콻0<""" ulP 9@D1MDtuwT: DDg2:@6LޝC6%/1MDDDDDDDDDD~l""""""""""K `_bDDDDDDDDDD&""""""""""6%/1MDDDDDDDDDD~l""""""""""K `_|&yv/K @eyW[_UY8|=oIku!"""""""""f*v@=Cwo#l꼬֦ N>$yMDDDDDDDDDD~l""""""""""K `_bDDDDDDDDDD䗔N|""""""""""r-i>]ؾ""""""""""OBDDDDDDDDDD&""""""""""6%/)}: DDDDDDDDDD^4W 0M^I(*ye< i: #Yѧ|G.DDDmDDD ls}~<CN BJL&*ːw"j.6+u/DDDDDDDDDD$.).BמTz7|P(9qڀ@DDDDDDDDDD~ :vzڞRD|B'\Y&"""""""""5U au2&"""""""""fkc^P(`2} ڊJTTz7EDDDD7/`GpyWT@R!22EB00PT6wź?Aⶌ /ܕi"""j6lEEݻKͶgmY}X0f3ћ""""ط9A@pp0:!#V8uD˯[$a| Z-ƢWo>~܍axލ]kر#jt:@Aa!V enZi"""j:@+t2ΝceڲJRn BreQ$vVPOk=c:Ԧu/_A\:ysэÆ޵{7N<[T4aİPmގ:}ݻuke Ӧȼ},"""#jqW~:rrs9%I#(((R@XXЯ__DGG8lF&ޢ;q97BEzwDd@VJ_FFxD8Ǝ Vi _nBaa!N?GǔIͷF=PSS hѷO6ш_CNu:oCBHHV˯+ӀK;!9{ǭiԱ#xTNC$'!88'OBHh(M$eDzZ:&t$""j!18`?yvw쭯?;m|BJ9$ z@Fz:4lY0GV[.ػ/%ׯ؀c`  zt#G޽qk7jT͛L&Ȃ$I#3u8DGCT|(.)}d WϞHT($%,I8tdt;w˱}TUUw^HNNVi;Qd˗m]xZ-}C|<***O?!'76ہǎ#6&xv+?cof&DQDDŽm"-8uQޗ YBRb' U*ܖDDD-))1p3W^WΆeO> ? 4o6Qfp؀cwSؘ (Sص{7:l A0m${?qaaak mܖDDD-KVAVAo0l6coyEeΆe5j55("!o!Sfk7WXa\N$SEaغO٥Ƚp1m*DQӞoXv/j㴵l;KP̝s Ä#>>}ނO?99ر{7G)n8`@=c.^g|v6Ξ;AFYȿv 555`{acAdD.]p돮]vVPހ /:'׎P(!rG}[!:%ù.aMUڥ $IBBB-߻tNݻmyJV PT\ I1![E-Zh^o@Xh(DQt{mv vEl6=7G .=DDD֭-"0guc m8]~7nPPPP*Nbbb0XjUǎ 1=wÖ}+yPZZ-!}pDF㟟xY R0{ ^\Ǝ;hбcBtNIAAA!Kj5s`0o5V Ht6$8S68+III2ۦ3|W)w׆a-Z+Wrfw^B"NIUSVv'mW!""INJZFXh(jO&Jnpzikqv!fܚhH> Νш?YA~/3Ƙ1} dBAag|,W~DQ¾k0LԱ#:As;JQKJlc7 G XX\89p%/II'zzpCzAp5-l6+&7 Z{Y9z6:$""j9ee_!"nMKvlc4\'m"""j~# Ñֿ51;?`?p67;rt>; 6ے޳( `61pۉvvg}mنjJٞ'm"""=OQQhMDNg\nJ-ZZYY]vΙ?׮]o3fL}ᷭ_-{Cբee刉ѣУ{7@^'OFh߾=(8u40og#F &:e0:x7$!""8tJ%08~k9%fE 4$99 c7>ΐAq[FDQ@CvT*WL=z`>6ӧNqU9ue1ѭtz=8jTnK""s99{UH 3M-}z;LY_[n˓6 'qc )1(((m6N[$AqLFF;:$?pV:ۿD-ۿxYN>Úc]n:'dGhp"-w늑#F>jq9M^4W2;x'"""o6'O{0|Pi=oIs݉'myy=b{IPTTx Cx,^W"::o.ȁ30(x ,z:FF&%yY9Dz9`{ ݼf3Ҳsae###|$r"%98v8!3gd6?G``7ǎ`&g6 B |""""""""򱓧NSAqI !CuN~}?deo[05#A~z;c`S˻p"tz=:tRDDDDDDDD7;V ɄOSS1~_'ꈎFZ0mnt&??~9F#nMOwxc&:ڮV5l̘(**BvN~!TDGꂂB;v Yh4"9) Fq IDATl"""""""""VHP`Μcefb_f Ӊ5j$ Rx `R ƍEpaFii) ,, )ׯo6Ğ_OuZ-{#n""y"""91fh_'EGNWejEn4`e_'|VGuaO &ɀdB}) """"""""""@6奾N*ˠ u2&I """"""""DF %Fh4"%D, V `7yKph#pQ{u8Ʉ8w8#e6lĉPc͚5>KOFF}AUUU Ν;̓  ]v̙3q&)o \-]wxWyꪯKdU^ _>z=-[$cРAعs رcCb׮]{:˷1nϗǦMЭ[7- >}˟Au9nt8ۏ_0_},IӌO ćEcq]QQ4jJ "qx7TTƇc1g@󭜏C\(Gp^NBa~>b;]l{_g?`/\K.ܹs}v޽<}4\חCz*֮]hddd`^OKkmɄ={o}fV[6ߔGNqAa֭ƍpt|ҥK?`kMԩSdx륺۱1UyguV[2d&O+W~si5 wy'0qDL0M|-ݾuu޿?nv,Y-,.g?tK:q5Xw  Fy e\,w,ǂ%_(M]SGiU3xB@$|mCЩsWtO퇞y=:u=N@}>ܹFhh}0UFAX\Т1tPt /w8Y IZlzg<I_۪-ٳgRrbccoZ!,, ,@II ^z%,_6Mkmʕ+}qW[s۱nlٲ/ưa6n܈}aԩիWcɶ˖-Á?x>Ζ}nuYfĉ[|y=>/tQ OU`*l{,t ś;Jl %H,ƥ`ˡ*5h5k2+D{_74o(EӢ6s=+V8Te6/{Ic>##/"222Xz5RSSiӦ7o& Pvmطo_iXt)xUVaʕOR# 3 )) QQQolt$᫯rw}7͛gNCLL |IgP8<222/nCpp0뇟~޴Z^{t޽;֭[#e1l0[ 1ܕ{HMM?_oyu0fb<ۿΖn_^vή[yZ4$WǠ84vWǺڇ-zY:[/򉈈,_qJ QJ8Y+`T w xF+tfa;B'S5͸O2]UU3g`.{alذFQmرΞ=z뭸pn݊L;w<|׮]?O8q cNӰxb:u Ápy੧1g ~=˶mۆ͛7c jT>֥jѧO>}mM2aݻwC; ~Gt)))oΟ?bžejt_~%= `…8uT'oMVף)ʏh]w݅}c,Y{? ˓m~mO>>|8^}U\tɣC\\柧?ovl7~iZ7on l~͘;w.ʠLz p=<Լr/VVV\ӧO}݇K.aӦMUy饗Ga޼yشiƎUV[njs֭JKKQ^^|-ߓ}]j凷unhX5 Am1%5YGaOW_nWteߓf>TUfT#q4VfDSک_f^ Cjcл;%~>w$Ir9NßgE>}(++{Cll,|IH'|֭.\xCG}Fv:FkYY{=<쳈ABB^xlڴtMMM z-۷/zfaQXX6%O?4pIGZZbbbOիiy~a)))rݻ+yR$Iݻo8a_`_|t9Ixb۴=X`nzy͵Z-ك%K`HJJ¼yp!i13cPKkZv{.qVMODDt3*^V@qi>Ϭĉ<>m > ௻0&CU VW<{a~v!66~m=jjj`2`4Ɛh49= |* _v>Fd2d2ABMM 9~ڣ#2eftӦM?}ζ=,˙ݲ+**0p@̚5 ѩS'L06]K;1enԨQ8u|M+ ^Nc/R0c L2mL{衇/CBۺI=tz~iDΖɾ^vή[5p Amu.jcMSXWpcry'""]+3!4@DX^J[Ʋd+I [KlO 3~=!!.c%\,1"$QEY) Q]] @Ddt C 6 ?kժU8tA{ng& ӧOmeo>0]bb"BBBe3 z5իW#%%cǎ(L]voI&M?-[`PT Negff*RSSp\y@uS o>$|Gxn8q/i J%N5 œ箞h^ 8q)Ooȑ())AVVߏ 6K*i ̜9Ai̾^v}uo:ixچ84u{.4-1$""ٜ7 ̄jZ<ѓiǾ_*1}D^u$Ia~._Dѧ ʫG~hyQlHOOoG㏱eC=}!??=bbb0nܸ&-{ŊꫯPPP+Vvܮ];dggC$T*rssq6oj9ܮBٳ裏;]X +Kx#~U\\k˨®]d n]vŜ9sw^\r1}]u]x lݺV˗flذ6Ԏi̾^vή7d]XjCPvKk[Gc] iU7wW݌xtTu"6T|ixK J؟dN.1* ꬅ$'U]{Fhx$ &W( @PR\R?ja~VTرc{9|:t( wyS7Ą 0}tr-())mۚ#cرxꩧХK??`l{Oc ߎ5| <{ܹs=aȑ4im\.]4h#E`2p6'7ecϦO\qnZvꫯgEݱiӦN#jCٳp:ޤ2go>|8f̘*>͵EFF,Y>}`Ȑ!_ߣ{ͣh_Z :t@jj*ƌz{7֚5kЮ];ŋ=Z7oU㍼j_ -- QQQxahZV}v$$$`ڵ+^}UѳgO}]j]}u˓þnCPs%5]ձaw˫tZ_c4W]>E/ψwyxvػ^ixR<22AXE `0I ƞB5jSdK0M%6\CNMJ%:`u,%ڽv/%]mUep eo>I!/ElT>zp[:!n^etK:Qk1`%jK.8nySG^yd©#Yydz%-^fTeDk~_N[k=\uzDmUkٷ%""""e6}DLfߏ%~D7iӦ: rUetK:u`l""""""""""K]Ǿ}|"""j؆ j]MDDDDDDDDDD~=|c+_zQ[̲fNIal""""""""""KMDDDDDDDD$P3j'uc6%&"""""""""j866A$INQԍ6 pqu BdÆ 8q"tYg555j2u:As<~޼y @Pk׮9s&>ܤt4ECGЌ)߄ j*5rH ;W7Gyl<,Z@RRϟbV7x&y矕z^Cז7o<<^[^]u+A믿_^Dzeː` 4;w7YYY;v,"""0tPڵ{OSwV8b0LXz5 toF/|~cP]ꀛ9#""LoCF4S}D|WCF´|dM;DՆ5"X|+ nK/;}&~^p!.]sbؽ{7yDGG:i[r%~/qU]뽞֪%& {n̺_[nme):ƍN֭[7"==K ^gךꉩS"-- WeKuccb֭Xn2331dL<W6FN>QF;DVV&N &i<ۗ|Ο}{8r|I<Zt[_/ ""IO`1?(A1qt| @gEC4 v L}+fnT QcYY)BO>Ν;qa>۷Szh4;rtt4N:aŸ;7 C##/T{ IDAT"22?{wdzP(PJ)B) ZpePA(W"2;(*U2 pz-N\V."[+KYЅMGML,oҦMǒy9{ΓoM@@رc$''I`` Ǐ͛FYn2`233-֡ ҹsgBBBx()) ))իW/h=jKJpp0>a4K/jٽ{=SF\WVV‚ ϕINNѼ 07|c.ʮ⥗^[nҽ{wnj~g2d~"""##Yj֭[yG d߾}䘫j***x]2dFm3<~O/_En߾=gggS2־)S0c |Me}Pi_7KGSʔq4Ktt4~~~d i|Zn͉'qmzO>aF2e v[~̕ok,)lnaO C= ZQ]2}9Ƒm+ZöʳR9J_SۊBqswbeX5kAU-TPmt|vђ|jϫR3 BJ\rs1p@ۭXRRRˋÇSUU&==͛7syxt{!++ .tRnٲzӧO3h FAaa:̝;3gΐɱc/ -bٲeL3g8=FJgu&[UUEiiCV[܇Vy'ӧO?7|Cll,l|)9 **z5kpEv۷l ֯_oߑb/ga} ٳvbʔ)>hcP27KKKin\0af̘+WHMMO_g۶m$$$ʈ#HJJ"""rڵ~"""(**Ν;c|%cV^f[h+m1бÇV\>kAi ǰ,uzX+Gk~%_!.Н²J+g/V5l_RCX?|FF 'ڱЫ[Z:[뮾Yi.\Veee%?",,x۷/ڵchZ,X@.]`u3g111tؑoml޼˗BNxWIMMXo[難gӦMӇP E:t ??fF۷+J/^̵k8wPKرc:u*#$$ŋsuٳgӫW/7h9VСCu~acΝfiZΝKqq1?mmժUL6޽{x|)9>|D %!!l]j5ǏgҥFWOIЙ9s&>z:~G򋽜Q3j= 9uqqqn./+sc(JQUUرciժz24rJRRR8q"[fĉׯ_Pg`nݺh?W:ekml=Ci tCڵkgϞmog)Y rg3r1\^7\d5y !`7J*k<_TVCmt>S#=|hHQp2& X)oƷy_%n߾vݜ .кukP]]M1p@~'ٳ'P{5s_گ]sYjjjx'WVWWS\\lqޓF1Z !z*qqq67qD?~zitg}Fbb";f ll7oc>L~~>7nܠL~gG>uuy7ok׮.cJܖ-["77:H~M_֎y@@-bvZ ~_o699dT*]ta̞=[)Jw$ثP2ٽ{7111/YYY6n./G8+KcңG Fdd$qqq<k'؛a%i=l {_c۪Bq/**mC*njoIV)]z/V>ۖ7?/$6ܛ;/Vr"GgON_nѱc߸c4mڴ]v|@YjℝI%fpo%77\\:9SYYFAX܇***8qzR?2"/_]2~x>3,KUvII $//W^yTj93F- >7|pXnC82x >>ӹsg>k/s̙cNi G٘:R)%KHH__>DI%["Vpww/$-- ///?~u;w 6m6"""࣏>"66UVH@@@o8+_XkvGXbj||<<ӧOW\ᚔ>].rgM}rkm ;r.lqd5y/B܋~)VgCu-k%Tkk ߛͩ];UUj- Ԅ,Ar73,[c34uKN`C퍽1zxx8*Ch4deeչ^t233]Ν  -- od=P cĈ7n88:2..#G?UvVVnb͚5DFF` GCމNl۳ޤ%J\hh(۶m߮5^%7 shѢ:t0ˋ ̾\l G9:~~~>} 6?Nvv6FA{a^bq5tPqavE^^P7>Zӧ7;vmsNx Xmkv{lJi CS[Qks5h%9Vz^Q:Bq9{FXn*ݛ޴Q6Ԯ}?6ԝ~T;a(,4h\v{ߟ~zN<ٳgپ};iii0c ^x233q#$$#G֫+W{nn޼ʕ+s6mڐVÃEdK4 /_&++KrEJKKm' gyYf/«jwt7#+**"##D֭[ƍQT׹sg:tڵkyǀ5HcbbXr׶V۷ 6pMon^rCȖ/jnWQ۝ss:FbŊL6u% 9=Jbb"#77sαj*4i<(gC|\xK.iӦ۷Nyy9n2zl;&MbΜ9[K4Fe: ٹs'#88͛7xzzo>:uĄ ֭k֬aŊsvMdd$;v`߾}C~K6[{1nJI0̿J>9NZZ}'OCFҥK;p9r5q$G[˱ư,1Wk(h~[qB!Foķ&cYG2ujCƲ6.xqX [g[oRڵ!w7w[j+⽄` P^--̝L~6|< -_φ]s81 rcf֬Y̜9"Jro|;w>sj9w+_!ʺOSs{Ws[ROWY!V˒Twe8v=z̩︿7:3'# |@Pm?5yMԹB4vpp0^J|ȱ qj.cU*B!pU>~ީ7Bb}XMA]G|ȱ qj.cU*B!pUۆp- h4ӷjkyWhסcoHB!B!BDPV;}h4F+[P\x g~$eklK lM]!B4Cr!D"cV!Mxr\CQuswۏv:5B!B!B ]c)B!B!.*cYӯA,DS5B!B!B$[!B!ByM]рzB!B!B(VۨTF-B!B!B6vDnZvlB!B!Bjj) &hl77w}|iզ-@ObTF*B!B!t\B j3Q)*,埩(/MH{B!B!p6Ņѳ/Zm UՕPU8P{doΜoo_[j-pkHIIaرtԉ@ƍ>|^eVVVRpႢPTT*֭O<?CQ^ȜkҘ1cHJJcذa퍝?:ڵkj4WΘh4>|C+Ǟ={lhXYYȑ#dϞ=|ߟ-[f…3k.~)O<ׯ(林L#4>˗/gϞ=lݺ,bccyǸz=gϞe<?~c2f;6Jc|hm7Tm.++#''wy~?G2{l+rEROWB!ӿ[g0u?~^PFa 6ô-7Tk?Be6Sߝ߿AQy mL/_*|u9m$Z**mZ->~T6Yt\v ;v~~ӧ k|xyyT;۶mܹs=zޥAb)Vk4exFYYY?ǏڵkWg"W MFAA:˖-oc'V^Uh4zsK qM㓖ܹs2do6~)<$''c_d ǎcڵ|ᇊcKvl~;6oެwX~=>e."WC!Sqf {~(cf9$uE>_]؎>}_x^|~;5x)+.k3nzyXݜVFSJEN`C\I.|+Xr/jjjx7޽;Z"..Yztt40p@;Frr22~xn޼iuK``  33bXp!;w&$${Xz516VYt):F#/ZݻwیSO=EBB`sxzzCtt4o ߟ}7Xx饗֭tޝ[Y1.%rA ucHVZe?FGGuVyٷol|)9j .^hW; B~~QL$O߿b=~GW۷oOzzԫ oʔ)̘1h7|x@YTMє2ex-{,Yj|Zn͉'qmzO>aF2e v[~̕ok,)lnaO =0TVVF׮]m+\g35h[9UnQ:VB/kX[: ߮h"|o/ŵKTS;h/%Zi5IMc.bQc62.++ܹs 8v+V %%bTUUIOOg͜?0|A.]Ğ={… ,]h[l᭷ 4#FPXXhs̙3dffr1rrr_EXl'O|^Yw^vEvv6~~~є7QQQ={fƍgvC2,8x ]v%,, / 64iѱ0dlOOOɓ'6mӧO̙3N>x`VUUQZZjPaj|I+b?$&&O7 (_J⡇b͚5\rEQ]F7?y ''[w$YeXk_BB{௬vbʔ)>hcP27KKUܸ*((`„ ̘1+W1믿ζmHHH 55#FDDDי;w(ڏ%[yZmţۮ@ǞsFCaa!_|ˊ#\g35 VRnXk(Myޯ$ !SXVCi$jƵmtKjk[6(课xݼdV;zutbDcs .jAYYY;? 7+r l IDAT~iKvX`Z ХK""">}zF̙CLL ;vom۶5Fkqq17of億ЩS'^}URSS-{***xٴi}!44d{ChQϷѣGsm~Gŋs5Ν;0vXNJ~ a\~]!%nՋ0M222%F΢j9tP_oعs}(sZsR\\?Ou[jӦMw*_J7&11dBCCIHH7[ZYtS'tfΜɃ>hߑb/ga}cƌGpuN:E\\>h[K:CX4RyyyTUU1vXZjE^ֿn.>fʕ0qDZnĉ_~rCܺuK~̕t,Yl+v{(=xhժGSN>µX}>Ymm +=/1Ma+W(MyoB!Ľ(ߍʺOxϔH32҇~*gl/e5̫ yB>=Vʛqsx*j=By0}p8PLl7w4d_deӳC [G-OJ fO&phFq.9ݦMڵk_|aq 4M,NؙT2n*@ Ǿ[rssʕ+3c=h44}8'NЫW/E-#rejjjڵ+Ǐ>#??\Ͳ̱[[e0p@xWHMM53c[ !ֿVN@@֭sGOdz~:w'|^r.\9sps-EOIp_콑#eRҾvjj~%}ОnliX9ݝ/4gMs96lmۈ "">XVZ@`` uᐛKpp0c|%cV^fk5vub`sXn]vxp}Js.9㳦>9R69Tk82VB!Ekq3Aݡe nmt5Z^SȵXmM~I T.Н*jBL %}h6|^n#9\rjo암DNNQT:tHF!++zK'33:uܙҬZ{̵$''ƈ#oܸq8p?88riii`SJI FAAǏ';;QF=}0/YTRܸ:t(׿8|0v"//KkӇǍǎ;ٹs'O<]qd,˶ln=m64J!kZwg9ZI57(r?G4y<(BkިF=6 vf7mT9k_k uNX`?7 .MҼ^_oP}v}h_ϟO߿?ׯɓ={۷F@@3f^ 337n0o3j(VXi8rss9wV"++I&)ޏrf~1|ŋt6mj}딗s-3i$̙ã>Â>h[K4Fe:n߾͖-[ˣ_ 4>}[nL< ^ٴiO>~_~={D^^7n$%%EԎ82lekmZcݞ6qk:g8p/~̙0až&\q4G[˱ư=%La uo+ !-|xs17Y4% |SmۗkEj/Vs%]ڴ <ăA]j*o[./-tF=F1F;|$Gf4kם ==+V3x` Ć WJ[1c0azMAA{#F`ѢEOusϟw_l/fܹ1tP:u*111K|[y6lqqqujfd!!!@իJT*.\P}BB* J;ݺu'~W=޸RZEC3f III2| 6L}CGG\v.]Chh(SNۀq<==wEٗat g={Ջ7|KHH`V)K}U!kRT|GGǕa|Xd 3h _=ǏgĈjՊsוǴ|mj.C4c˕p/W>~B!pS}b^{Cn3*җg%d0mCū[Ղ6mZ >ݎ{4\@cM57.==}t.\Ȕ)Sطo_m[ˋիW3sF/^ׯeڶmKtt4}QץrFh4>|C+Ǟ={lhXYYȑ#dϞ=|ߟ-[f…3k.~)O<ׯ(林L#4>˗/gϞ=lݺ,bccyǸz=gϞe<?~c2f;6Jc|hm7Ԝh̍-W*tz!1;{ufSe~edO b;LrJ-^-Tvm0uPmyAZW˝F-4CSͭ駏]v ;v~~ӧ k|xyyT;۶mܹs=zޥAb)Vk4exFYYY?ǏӢEmi׮]\]6m,[Li[XzuSW9/5q4OZZseȐ!|dffc=R|ɒ%;vk*ޏr,5vu[̓\R!BO<Ǚ%ڛn@֥q|wb;FF}mbzrT㥬 zM/׺Ѯۏ|x6i^b+W4TMM oݻwUV?_^#::ȱcHNN&22@Ə͛7޳n:bcc ddffZCUU .s΄sQRR@RRW?Ã_|{j5K.%44`}YGh䥗^Bղ{n{ꩧHHHп,XOOOrrr7`ӷo_uVvUU/ݺuחݻuV;+Fܯk>>*C)k2e 3f07$>>PuӼdx4eLGKj޽DGGGxx8K,֭[s EEEܾ}=zOYHca[Ya%9mI!h;n2j,sp jg*x(G6:A>nR\hIe A>ӚFRRlaGT*Z|jjj>555ܾO`&KN`q9hu+VBJJ xyy1|pۤyfΟ?OXX> .]bϞ=deeq.]j-[[oqi Ĉ#(,,4[sr2339v999/`ѢE,[ɓ'S]]mj,ۻw/v";;???hۛ(Ξ=k3~ƍ3Z;СCTUUM$}W^yo/%|DEECf\(V׮]}<-;_2/!!={}Pڵ)Sni^CX,--ZqUPP 1cW\!55U?c_m۶@jj*#F ))ϧk׮F;w(ڏ%[yZmţۮƠ!ƍh>kAi ǰ,uzX+Gɹ#;WB{),xm5~]Z6:%5wXnkW_oAQmsFCQm~ jVנwQQQb|O?4}]v,XV˂ ҥ L>Us!&&;mۚ]͛7|rBBBԩ*m=lڴ>}Jrr!Cیѣ}6?#P{EŋvΝjI;v~SN_~xb_֐c7{lzEXX\#gj:t/7zܹ>9Vܹs)..ͺZiӦѻwo|}}/%ۛÇHrr2$$$ߛZ,]):3gXOGH~3ʰվ1cP]]ѣG~:N"..NQ-%T}cen,E<;v,ZW^DGG_7rJRRR8q"[fĉׯ_PgڿߺuK~̕t,Yl+v{w܈RghkcXi6Ma+WXJm_!QRY ⢲|orCwFFO匍򥰬yU65o~^ȧJy35n~I6.~8G( :ܦmI\p֭[&''jϏO?}OϞ=ګ ^777bbb9{,555<r)..?[AؐKZ\z88q"ٿ?={4>#11ty儆g6J͛7ٱc&??7nPVV3cd`:u:<Λ7k*ڇ>e~ & /k< E1|Xv- oկ7Lrr2*.]0|fϞ߇i l;_Pe(޽҈ח,}R_DtL#ho~ѣÆ #228}Y~a3{lΞ=˩SxWIOO'**hVv E1Wұd-/[kx4fubYq#?%35JưsyݴrH̩y !ߖ0vF6:dҵ۞ !b%)amyBbýɿ!b%'xydKzvd\<ݽlٔDwssץ)5mڴ]v|@YjLk- IDATℝI%fpo%77\\:9SYYFqW***8qzR?2"/_]2~x>3,KUvII $//W^yTj93Fd_+sÇ' u9T# l'ٿ?;wO>ѿ /PXXHyy9.\`Μ9F3|]vԍVCAAƍcǎFܹ'x®82le[mZcݞ6R9Gskn קo[r G4y<(BkިF=6 vf7mT9k_k uNX`?7 ˚]m8̇a9nnnz45?>_'OrYoNZZ̘1^xLnܸy aȑ*{ʕ޽7orJܹ%M6j`ѢE,Y/F˗\xR ga֬Yddd/ꫯȊ 11uֱqFT*uܙ:vZ{1v ҘV\i-qUv)**bÆ ܼy۷P1Ķ􋚹UTv\{ΨQXbӦM@hICGȾ}ܹsZ,&Mx?g+O8ʙPll,|/^ҥKlڴS^^έ[~~~6ΤI3g> Jn)/Yr鸺}6[l!//28~) Ӈnݺ1yd222z*۷ogӦM<^~eCRRyyylܸ͛g~K6[{nO8ڊo܈ lg|8Xkc>}۴Q2PrBq/‡G0gxCy.НE[W?U(Ɯ}V&b%Y?WҥM C<N_k^ˇ26ٙse ==+V3x` Ć WJ[1c0azMAA{wpGE/_5w/?>۷oU|ٲe,^sСCkԩЫW/Wmcذa  ϣh8q}o$~ƍƍ蟛0a/^dъc7kewޝ5kְ|rwNjjj_"F)))1ޤǍ3F}вex衇lƗn}Dѣ|Wt]>,OIp򋡤$:vHdd$<]tx6nH6m/_VԾ?O9rɓ'ZT׭%K#V2Wܹ~͛IIIl|<==ٷo:ub„ t֍5kְb {9v<9w&22;vo>zx?%[yZ֘m7$_%Mظ͟g3>kr1l3;Ky"^֙!֛Tkvmc fox/!_W;wƤLn1W#φ7=k8FQnl̚53g6uUD#QTN_>`Ν|gN-n%k>XYi[5*tzyBeIIƲ;z'ǁ*_VGCk1s+h,Ξ˹[I9V5u||!VelJ=]B!y~t!D׏įce]Sǧn\ƖU!B![!B!B!K+Mdff6uB!N&B!̓\-B!B!%B!B!Be B4)[!B!B!K+B!B!pQXU H\-B!B!wXSWo@Q .:pޢ⨢֭WZ_WѪJqm{ * `bn y{ι{\"6%,1My$@DDDDDDDDD&҃n""""""""a]vu(VQzuY&׋^?)) 399<~PP$ $ ,--QlYt oʑ֛ #!nٲ%͛@X.5RohZ1"""0`xzzի޾} @%K@*fHKtY}sɶ0rlOs\%UJ"Q><^W &]62lse4m[.f 9*9mԶ:k˜P_.s>~DDDB# FpԷ~W QZI0+.#çgpA4.og#a`3ݺuÑ#Gp 2 颉6k,/4h޿Hlذ /oߞeɭ"-Jq)4lPX.0y@Μh֬q<~{AՑ7o^zzx1ƌɓ'g _nj'ڷojժt1s=KјJ~N`͸pжm[|RݻwVZhݺ5Zl+W(P@]KٽrSAеe̥R"""2N6j;F8Ҭ4wg$ɱ#1hU -~+$𭿋>HJحĬYQyrl۶ aaa|r9X..rPn](QÆ C-Ur<rr]p˗'OzS` \E=O>x~GL4Ifvb֬Y9]l\)f߿Æ Cz ,={pyom*GO0.]ŋi&埓RvBnk?(wj̑\ADDD]; 84z9cBD3o;쿚 zS'C ]vG_%Gc +=m4L>]SI&a򂫫+ڴiǏ+?___899VZtBBB gggto޼Qfҥ󃳳3j֬k-CJJ ƌ%KG\\`޼y5kv+++ 2D6'nnn믍F5F\.Ǿ}_=699=zxX[[ÇٳQfM8::J*8yֲ;%%FBٲeaoo///l޼Ym# k9~8ի C*&&ޘ1c7oF&M#Gw}9iiiHJJ“'O z!**Jm4OL;aaaZ˙7}Q)r…qQ/.Syku놾}?gtsP칮.i;9YWTСCʔ) &謟|ڵkcbb[/_^Ν;ѵkWtu놽{*IG(}גvY>z/]!3 *T34iw*5m'% ʊch}mkX_~urhGLF`ضh컚qV(Go*#Nꗳ^ǦO5,]zXUE{%qN ̉Yp=ԪUKzӦMî]k.\x666GJJrGbݺu>J*5jӧ8p.\`ĉjnذǭ[Pvm4m߿,ðap?.]Ç1n8رc1i$tXbme޽{qE888UlmmQbEeYWkNm'N %%E-Xpq.]J>|VÇQV- U򶶶F2eoӧqΝ,#12>~xɦ >>^mIKKӚG!-- ]tAʕ1e# >={ɓ'@%׬Y+VD1w\<\T]EDDpptt?<|+VZNcߘPY  ɔݻݺu :ׅhK#u%t-Szзo_<࿂fزe Mb޼y(W 11QQQ(]Z:ʕCLL >| *\Ke]>{3`/^`ǎz* , *O۶yjt}eg)h@5,&?mj9t#满1u{迦%'~6 ?q-f8JHwVx+U^ems`Al>Ep(e:LNN… zjTXJ/XH>ٳ'T bѐ=z4<==Q\9g5:tPԩSEŢEP@9Zcccn:L:(VfΜPַMRR/_kעr@HHUU"EZho͛G?wNB֭i ժU;ƏH庪JRޔܹsRGYE.ĉ:+Wڲ{n4ĞsrÆ Cll,~ge1cJ*^%ԩS>|8BBBၠ \zU,iii|2&N6QĴ C57}1TVoZlT={7nM6Am6vIAxٺU"֋/֭[>>>U/T?uӱk.tCΝGFF@Ѣ_쵤]ֵ#;]3߿?*VOOOϐH$عsQ'hk}egMVѺaPY}m6ȘR0~}'""/rs@\,1 2[^G;hR,n'uE{OsǞK1,2]p9<кÇի+_spp@Zpmm*T }4k~kaa:uꨍT{.d2:uOOOxzz"00ZӷÇ!J4/_Dr֟ 4h]v!e˖?w[j%V̱{ .]]qxrZVב>΃} $''gqĈjOĞs6l{n-τ/] cǎӧO믿YZ;$$ܹ3 #F(׬?1rbi_ e<ퟵ5:v ߿mڴsP۹]R<0EcˣQFFPPIƾ psD"0vQ`A>|X:IIIJZ r |ZZZ TpG#<\sf!INNT*T*՚p5?ϣ={LҥKC?G)o%D[;..j‹/0eT++0>@){ K.5*c/@dee;",, %KΝ; 4߿Gbb"z/]T329iccO)ڢLu g,|AB{uvEsYYG!U*lq&y /l'?QҿW]5 ,@͛2e@"ĉפR).\+f*oŨ.;z%K߯3T헩TRhڴk׮qAiЦM>}Gƍaeeep9}DGGcܹZTudh:mCF9-[`~ƫz>jɓEQ666՟vXY uK5j޽˗qE4osАs]]%J,aÆظq#N:{ŋ2֏V+Ww)k۶mS[gԩAs-k{ T8wEd ϊch1m5sW[} # 2jkJūX)Vk, ao(f!s_;c鿆$C!'dr' `9իWGձb \~w֭[~899o߾4hΟ?W^aĈpwwGf2ӱo>yӧOLJѣG尲رc1a_Jx.\Lx8~8}ڼ֛ .Z o޼֭[զ0Uc:jB7KJt\C9͛cڴiӧ߿ )gb8r=z{aƌpE#T ceeׯǓ'OS]di+$&&"::Zmqppл СCѪU+?Ĝum.QWҼ޾} 6ŋHHH@xx8SahOʕQlYtΝ˗/uV]]tQw7o^x5k`׮]ʩvĦc̵]ֵϺ}7ds2$$/^ׯ1fHRT? S345ƶѺX]װ!K4iCW>ڠ0~}m?Ll:C]P- :[blJcD#u%{DĤd̟eܭP-rVD)w1=iӦaǎ[.j׮UV)GJ,]-[D@@*UwСCѴiS;eʔ3g:}ޜ#Gb֭ʻO4 Ǐǰa₆ ŋʴz:uG|},[ 5B6m)SƠ}P܌ T*ŵkPJ:b]vxԩ|- OQbEٳ8vDĴʪEռyPhQx{{I&:Xk֬AՖgϞڿݻdu9uKdG]Kz=vލjժ ֭î]`kk+X?8r+-[sŴiпzUVo>x{{c۶m8rʗ//:c%}}^v&S}0sQF޽0m}mgsY>]Ƙ6ZW֗6BЕ2~}DDD91M*s"Vȏs⇀|uv_c16ATn:,-~XӰH ats|v,[uPY,U<>>Z[jB|>?dvѯ_. eD#7TT؋ =xt>W2rK9r/gqJɹIEΞ@J 07\ U1i*Lek, j:M]nnno</-''\k\i. """Am҉$xaz&MnPօ6)'$`Ӗ4nm:bňW[ϘX%+WC 茙fo'%%aYhܪ-)ߓJܽ'[k7lv ;3Sd2܍߲{Ď]{u LQoͬG:53HNI1i \9ױC;c?BwlC]dPX#x $')&62q6[Nȗ4=}G|ڵjb] #ǎǽ އ%+Vݻ ׺ pL8֮B%0 QQ~ۿ:j4<|g 'W\; ߏy"x 9s"55~݆3g rptp0*w"""""s>,ci̚7?KGL~?]ҟNLJ@p;rٶg;d2y=*BP%ǵ7qҥLc`@z 2; fM7nbޢ:btO-G`.BEDd$FO(u]bZ{ ׻o>7̜2n266f"߸p2-~F]dJ [c`zNfNMMEH.]8e]xǎ«\Yt  Oͣ!gE y.erb-M0!鄄$8;9NڊJǐs瑖&C~>zFص'4sd/&ժTFn\cFgv>~Ɣ Qʖ.Mwp֧_կGGGth\ _`H$kggTQÆKOHP#66f"l fUpBЮ-7ĉSS[v2sreQӷ::n߹M[(KR8C6㼅jkC&aӖ+4iODDd$@.OMaPrE(ΠBй{O "Yr5:t B1{ ?0S5fpv++ 8xiCt4,MԿ1O_Ll,/^)2..Nxw %~/?ʥN&_p8~LLmռ<{+Wy6t6F%rOQMTDDҹ雺މr+1Y~m۱aױ/7=|;r4h.\6mيQ\Ao'Ki&y={RNͩbɊ D_GGL})ҟNLL?%cHXX84j7PI8uZTӉSѧ@..}~L̚3O-_lŸ0ՔE*v>=} p˗OZ>WWTT '|-66>?G akkDaܤ)h۪%fDu/\O=dž5OkKXF- s?1-\`h]cێˬMrr2bbbPhK/x'&Jg΂%KB.p::&Ϙ'1t|;hJ/3]TSl+멩iHLL̰ҹ#N;\jT-[Uj`-vR⛨(}NeJyٳs={{W(ҥ<1ppu^yc&"""ϑPE*j]_LO zC:vcFWh24okV,Ce_s<ƍ=۶ۻ&NfPYWVYcqjH,$xBgeebEb3uzn3gœg2U_JHLŠ5k`AS ;=~z̍^paXZZ;ZK.C*/5mu!t=j'ΜUoSѬqzS5 ΝGe-b1jL&Cxoϟ =>^9~?OzJ{V]]*7Qo:k<=Q9Wpu `tCs?djԩU [7LjvF6ovҘ7AT[t _1a48;;a Xt0iXvE3,8t>CSS:qMpr?}.㝖czocm+kNرs7:t 3&"""ύPE([1Y:IB6-ZLRGmѬ)ʕk^opSmd6_MQ3}z" -i* /C6?^{vqcq-ZT}/^h"im.HPP!<tJELl,2<C.4Mk~4\>F۷xjhҺEye@b1 Ŋ^0k~O=ǼK !&6V^p4oDEEϿQpqqwL1 FB0qt7q*Ȑs;b&B<Ϟ}ؑc`zNy"Sg Qaogҥ<~kԛˈHe2x-|MP^DD"--MmB{;;;x{WOwNo FAtm;w!Xzʖ.MUDDDDD@[E,$F}c ď [ Wk{1\~111x-ԧs0 z_ժbܽ'rengH))) ߿WNcOnw8½2LҼm_X8;5iօ SQ'O_m֝;QU_鍾_BDd$ڍ>_ǖ?g:J"`i0A_xbؾlmiC5jT=0v:sZP.[]!C~;A!#kH,"Ch܅1bP8| X="3l[#ǎ!!! Mۨ߼¸F* LL3idd2HR`ccw{ C+++XkiW-^KW0~TVf̈́Cz+UpXNN[>=Jǝ;wE=sH$UFDGG#w5v ŘQjU ݇?Bw+S'cS~&8}`5UÓ=<qeFyƼY3P/SUԽ;,-aȟMF:$GGw{'O4_ w0lҙJNDDDD'GH 귤ԯ~¿A}|+,ceXTJ-GGGzZgېb>pB:ϭ k+x^p6ѳ6lkEؾs&Xd'N!][QM(Z-\?W݃2TP!̟w&zVVV4~,&}|psˇ5a(FE&*Z0/KKKelWnXf-v=hJNIS[:ڶt;0S՛ q`ڙBD_z c8~Lپ1t*O?Lh9{M}_L&;wQSx&JuWjU*cqXr<7QQ(\vv8)ps; ԮUW{g(Q4?S{-,85wIl1;kж >n[ti|~7B bI?'9:}ϞXsY[[cMDuu͋6ZϣGѳ[Lc.-R_֨nvbCXZZ"2~V;Qn?eOLGGWىW+w>&C t֗^y8(nhֈ|Zo#_2kTq{n߹5FuMz`43}"_+ѬqcR)6? @I%-\\Ӫy3{w0uDT*Ť3`gkcTĈu1&-6CQcU^pa \Z||? ^!tvvhݢ9.\nݻm[¼qm}-k޼E<~Tl޶]f@Hr~MTpʿ3ɃݻaڟpEd2z1{@~0~ۻ ;~^q\{@<}mǛ(ۏck`g:ڟ7.2Kx~ ܼu QQ8Q7Թm/}upo̘=Ϟ4(D[}B ]_D3Յ /{JM[Xl9v FzimSs)eυxg_`_p4nРUee$8&(WϪ'* U*b--'t޿{L}iRo/"**n)Pϯ~a",8VY(^gLUΩܫ'lmlx2D~|彼̲ĪTsfNú |(YgNS-8WlY,7Zl,[4%?}~|" .u1)GEMpothFz;?y2֯Z!:Çѽf-V39Rk+k̙uATggTSXCbw^XYYdIT荭+o*Iy }o:K,MlllP +/BűpRQL1k띈(')ϫV2V.Y @;:4I-5{p0Vs~`SQSlPW[ZZyeڿ!c톍XOFu||fKA%y0kJg:bfWRW_G}.~M8;M㠩v͚:ԅ.7ݿ_oc)u/[_|*`H?byRSSq qQl Oy5MR7o 㕯y(Ccwc`ggSj߶-6lv.^wPelDf}<}GZw T[7t6*TPT.REq , j΁I(cYTIDATqT^FD 5- }|r(YAԜz'"""""{-닭;v4ݜ t%G'Y6t Uچ X|L &DDDDDDDx)>}U [\zt2kÇ O2ջ ?s DHHj1S"f ţԧQF$ԧQNS2D8߸Kp/۷GN9](;8B"ӇA})DdPBDՂ݆5׺֜ZB|jODDDDDDDDDDq K8ﵾ5t[t!fhlب8P[l"q }FTkYmhYؚ h-&"""""""""σ൶A/-aK -596vicc@3hHM3 3%ۉ}^X,|||\ HDDDDDDDDDDuC@ eEAlCG_- ,[(| Dky d[i28rP5Hy rz5Gv wfG`K4vN5,UyԃΚbq=8DDDDDDDDDD/mhتj # `f*Alm(vDs 5DDDDDDDDDD'&-6[5o `+FZ>Z3xJO`Q!i0pMDDDDDDDDD9l8j [sP[3rV Zk{MslXת#}5ihP[hlCn(׌BD(lm4Bӆ GͿHZ5H5Q|.h(bBӪg6p`6ih]Co1l[l|][0ZWP[Ql~DDDDDDDDDDd .SH "AUTHOR" elektroid-cli was written by David García Goñi . .PP This manual page was written by Dennis Braun for the Debian project (but may be used by others). elektroid-3.2.3/man/elektroid.1000066400000000000000000000013651500236517400163300ustar00rootroot00000000000000.TH ELEKTROID "1" "Jan 2023" .SH NAME elektroid \- Sample and MIDI device manager (GUI) .SH SYNOPSIS .B elektroid .RI [ options ] .SH DESCRIPTION .B elektroid is part of Elektroid, a sample and MIDI device manager. See man elektroid-cli for the CLI application and the full list of features. .SH OPTIONS .TP \fB\-l\fR, \fB--local-directory\fR open the provided local directory .TP \fB\-v\fR, \fB--verbose\fR show verbose output. Use it more than once for more verbosity. .TP \fB\-h\fR, \fB--help\fR show a little help about the options .SH "AUTHOR" elektroid was written by David García Goñi . .PP This manual page was written by Dennis Braun for the Debian project (but may be used by others). elektroid-3.2.3/po/000077500000000000000000000000001500236517400141225ustar00rootroot00000000000000elektroid-3.2.3/po/LINGUAS000066400000000000000000000000251500236517400151440ustar00rootroot00000000000000ca de en es fr pt_BR elektroid-3.2.3/po/Makevars000066400000000000000000000065141500236517400156240ustar00rootroot00000000000000# Makefile variables for PO directory in any package using GNU gettext. # Usually the message domain is the same as the package name. DOMAIN = $(PACKAGE) # These two variables depend on the location of this directory. subdir = po top_builddir = .. # These options get passed to xgettext. XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --from-code=UTF-8 # This is the copyright holder that gets inserted into the header of the # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding # package. (Note that the msgstr strings, extracted from the package's # sources, belong to the copyright holder of the package.) Translators are # expected to transfer the copyright for their translations to this person # or entity, or to disclaim their copyright. The empty string stands for # the public domain; in this case the translators are expected to disclaim # their copyright. COPYRIGHT_HOLDER = David García Goñi # This tells whether or not to prepend "GNU " prefix to the package # name that gets inserted into the header of the $(DOMAIN).pot file. # Possible values are "yes", "no", or empty. If it is empty, try to # detect it automatically by scanning the files in $(top_srcdir) for # "GNU packagename" string. PACKAGE_GNU = # This is the email address or URL to which the translators shall report # bugs in the untranslated strings: # - Strings which are not entire sentences, see the maintainer guidelines # in the GNU gettext documentation, section 'Preparing Strings'. # - Strings which use unclear terms or require additional context to be # understood. # - Strings which make invalid assumptions about notation of date, time or # money. # - Pluralisation problems. # - Incorrect English spelling. # - Incorrect formatting. # It can be your email address, or a mailing list address where translators # can write to without being subscribed, or the URL of a web page through # which the translators can contact you. MSGID_BUGS_ADDRESS = $(PACKAGE_BUGREPORT) # This is the list of locale categories, beyond LC_MESSAGES, for which the # message catalogs shall be used. It is usually empty. EXTRA_LOCALE_CATEGORIES = # This tells whether the $(DOMAIN).pot file contains messages with an 'msgctxt' # context. Possible values are "yes" and "no". Set this to yes if the # package uses functions taking also a message context, like pgettext(), or # if in $(XGETTEXT_OPTIONS) you define keywords with a context argument. USE_MSGCTXT = no # These options get passed to msgmerge. # Useful options are in particular: # --previous to keep previous msgids of translated messages, # --quiet to reduce the verbosity. MSGMERGE_OPTIONS = # These options get passed to msginit. # If you want to disable line wrapping when writing PO files, add # --no-wrap to MSGMERGE_OPTIONS, XGETTEXT_OPTIONS, and # MSGINIT_OPTIONS. MSGINIT_OPTIONS = # This tells whether or not to regenerate a PO file when $(DOMAIN).pot # has changed. Possible values are "yes" and "no". Set this to no if # the POT file is checked in the repository and the version control # program ignores timestamps. PO_DEPENDS_ON_POT = yes # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained # externally. DIST_DEPENDS_ON_UPDATE_PO = yes elektroid-3.2.3/po/POTFILES.in000066400000000000000000000004721500236517400157020ustar00rootroot00000000000000src/elektroid.c src/editor.c src/tasks.c src/browser.c src/audio_pa.c src/mactions/autosampler.c src/mactions/backend.c src/mactions/microbrute.c src/mactions/microfreak.c src/progress.c src/guirecorder.c src/connectors/sds.c src/connectors/default.c src/connectors/system.c res/gui.glade res/microbrute/gui.glade elektroid-3.2.3/po/ca.po000066400000000000000000000377401500236517400150600ustar00rootroot00000000000000# Catalan translations for Elektroid package. # Copyright (C) 2019 David García Goñi # This file is distributed under the same license as the Elektroid package. # David García Goñi , 2020. # msgid "" msgstr "" "Project-Id-Version: elektroid 2.2\n" "Report-Msgid-Bugs-To: dagargo@gmail.com\n" "POT-Creation-Date: 2025-04-22 19:10+0200\n" "PO-Revision-Date: 2020-04-26 13:00+0100\n" "Last-Translator: David García Goñi \n" "Language-Team: Catalan\n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: src/elektroid.c:236 src/elektroid.c:242 src/editor.c:1309 msgid "Audio" msgstr "" #: src/elektroid.c:326 src/elektroid.c:3005 msgid "Not connected" msgstr "No connectat" #: src/elektroid.c:442 msgid "Receiving SysEx" msgstr "Rebent SysEx" #: src/elektroid.c:466 msgid "Save SysEx" msgstr "Alça SysEx" #: src/elektroid.c:467 src/elektroid.c:595 src/elektroid.c:854 #: src/elektroid.c:1418 src/editor.c:1203 src/mactions/microfreak.c:52 #: res/gui.glade:1003 res/gui.glade:3139 res/gui.glade:3245 res/gui.glade:3566 #: res/gui.glade:3652 msgid "_Cancel" msgstr "_Cancel·la" #: src/elektroid.c:468 res/gui.glade:3153 res/gui.glade:3259 msgid "_Save" msgstr "_Alça" #: src/elektroid.c:472 msgid "Received SysEx" msgstr "SysEx rebut" #: src/elektroid.c:477 src/elektroid.c:600 msgid "SysEx Files" msgstr "Fitxers SysEx" #: src/elektroid.c:514 #, c-format msgid "Error while saving “%s”: %s." msgstr "Error al guardar «%s»: %s." #: src/elektroid.c:539 #, c-format msgid "Error while loading “%s”: %s." msgstr "Error al carregar «%s»: %s." #: src/elektroid.c:593 msgid "Open SysEx" msgstr "Obri SysEx" #: src/elektroid.c:596 msgid "_Open" msgstr "_Obri" #: src/elektroid.c:612 msgid "Sending SysEx" msgstr "Enviant SysEx" #: src/elektroid.c:853 msgid "Are you sure you want to delete the selected items?" msgstr "Realmente desitja eliminar els elements seleccionats?" #: src/elektroid.c:855 msgid "_Delete" msgstr "_Elimina" #: src/elektroid.c:874 msgid "Deleting Files" msgstr "Eliminant fitxers" #: src/elektroid.c:874 msgid "Deleting..." msgstr "Eliminant..." #: src/elektroid.c:911 res/gui.glade:255 res/gui.glade:891 msgid "Rename" msgstr "Canvia el nom" #: src/elektroid.c:935 #, c-format msgid "Error while renaming to “%s”: %s." msgstr "Error al canviar el nom a «%s»: %s." #: src/elektroid.c:1289 res/gui.glade:1688 res/gui.glade:2132 msgid "Add Directory" msgstr "Afig directori" #: src/elektroid.c:1297 #, c-format msgid "Error while creating dir “%s”: %s." msgstr "Error al crear el directori «%s»: %s." #: src/elektroid.c:1416 src/editor.c:1200 #, c-format msgid "Replace file “%s”?" msgstr "Voleu reemplaçar el fitxer «%s»?" #: src/elektroid.c:1419 msgid "_Skip" msgstr "_Omet" #: src/elektroid.c:1420 src/editor.c:1204 msgid "_Replace" msgstr "_Reemplaça" #: src/elektroid.c:1425 msgid "Apply this action to all files" msgstr "Aplica aquesta acció a tots els fitxers" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2494 msgid "Preparing Tasks" msgstr "Preparant tasques..." #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2495 #: src/progress.c:107 msgid "Waiting..." msgstr "Esperant..." #: src/elektroid.c:2239 msgid "Connecting to Device" msgstr "Connectant amb el dispositiu" #: src/elektroid.c:2240 msgid "Connecting..." msgstr "Conectant..." #: src/elektroid.c:2247 #, c-format msgid "Device “%s” not recognized: %s" msgstr "Dispositiu «%s» no reconegut: %s" #: src/elektroid.c:2481 msgid "Moving Files" msgstr "Movent fitxers" #: src/elektroid.c:2482 msgid "Moving..." msgstr "Movent..." #: src/elektroid.c:2789 msgid "Acknowledgements" msgstr "" #: src/editor.c:1325 msgid "Save Sample" msgstr "Alça mostra" #: src/tasks.c:32 msgid "Queued" msgstr "A la cua" #: src/tasks.c:34 msgid "Running" msgstr "Executant" #: src/tasks.c:36 msgid "Completed" msgstr "Completada" #: src/tasks.c:38 msgid "Terminated with errors" msgstr "Terminada amb errors" #: src/tasks.c:40 msgid "Canceled" msgstr "Cancel·lada" #: src/tasks.c:42 src/tasks.c:56 msgid "Undefined" msgstr "Indefinit" #: src/tasks.c:52 msgid "Upload" msgstr "Càrrega" #: src/tasks.c:54 msgid "Download" msgstr "Descàrrega" #: src/browser.c:324 msgid "min." msgstr "min." #: src/audio_pa.c:337 msgid "Output" msgstr "Eixida" #: src/audio_pa.c:340 msgid "Input" msgstr "Entrada" #. This should only be translated if a non latin alphabet is used #: src/mactions/autosampler.c:205 res/gui.glade:982 msgid "Auto Sampler" msgstr "" #: src/mactions/autosampler.c:205 msgid "Recording..." msgstr "Gravant..." #: src/mactions/autosampler.c:282 msgid "_Auto Sampler" msgstr "" #: src/mactions/backend.c:60 msgid "OS _Upgrade" msgstr "_Actualitza el SO" #: src/mactions/backend.c:75 msgid "_Receive SysEx" msgstr "_Rep SysEx" #: src/mactions/backend.c:90 msgid "_Send SysEx" msgstr "_Envia SysEx" #: src/mactions/microbrute.c:394 msgid "_Configuration" msgstr "_Configuració" #: src/mactions/microbrute.c:422 msgid "_Calibration" msgstr "_Calibratge" #: src/mactions/microfreak.c:51 msgid "" "The defragmentation process could take several minutes and could not be " "canceled. Are you sure you want to defragment the sample memory?" msgstr "" "El procés de defragmentació podria llevar uns quants minuts i no es podria " "cancel·lar. Realment desitja defragmentar la memòria de mostres?" #: src/mactions/microfreak.c:53 src/mactions/microfreak.c:85 msgid "_Defragment" msgstr "_Defragmenta" #: src/mactions/microfreak.c:66 msgid "Defragmenting Sample Memory" msgstr "Defragmentando memòria de mostres" #: src/progress.c:52 msgid "Cancelling..." msgstr "Cancel·lant..." #: src/progress.c:110 msgid "Sending..." msgstr "Enviant..." #: src/progress.c:113 msgid "Receiving..." msgstr "Rebent..." #. TRANSLATORS: Stereo recording #: src/guirecorder.c:68 msgid "Stereo" msgstr "Estéreo" #. TRANSLATORS: Mono recording from left channel #: src/guirecorder.c:78 msgid "Left" msgstr "Esquerre" #. TRANSLATORS: Mono recording from right channel #: src/guirecorder.c:85 msgid "Right" msgstr "Dret" #: src/connectors/sds.c:1359 msgid "SDS sampler" msgstr "Mostrador SDS" #: src/connectors/default.c:84 msgid "MIDI device" msgstr "Dispositiu MIDI" #: src/connectors/system.c:670 msgid "System" msgstr "Sistema" #: res/gui.glade:104 res/gui.glade:218 res/gui.glade:854 msgid "Play" msgstr "Reproduïx" #: res/gui.glade:119 res/gui.glade:264 res/gui.glade:900 msgid "Delete" msgstr "Elimina" #: res/gui.glade:128 msgid "Undo" msgstr "Desfés" #: res/gui.glade:143 msgid "Save" msgstr "Alça" #: res/gui.glade:203 msgid "Upload Selection" msgstr "Carrega la selecció" #: res/gui.glade:233 res/gui.glade:869 msgid "Open With External Editor" msgstr "Obri amb l'editor extern" #: res/gui.glade:241 res/gui.glade:877 msgid "Show in File Manager" msgstr "Mostra al navegador de fitxers" #: res/gui.glade:839 msgid "Download Selection" msgstr "Descarrega la selecció" #: res/gui.glade:945 msgid "Sample and MIDI device manager" msgstr "Gestor de mostres i dispositius MIDI" #: res/gui.glade:948 msgid "translator-credits" msgstr "David García Goñi " #: res/gui.glade:1017 msgid "_Start" msgstr "_Inicia" #: res/gui.glade:1077 res/gui.glade:1819 res/gui.glade:2285 res/gui.glade:3184 msgid "Name" msgstr "Nom" #. Audio channels #: res/gui.glade:1103 res/gui.glade:1844 res/gui.glade:2312 res/gui.glade:3701 msgid "Channels" msgstr "Canals" #. Input audio monitor #: res/gui.glade:1134 res/gui.glade:3732 msgid "Monitor" msgstr "" #: res/gui.glade:1159 msgid "Global" msgstr "Global" #. Press key time #: res/gui.glade:1196 msgctxt "Auto Sampler" msgid "Press" msgstr "Pulsació" #. As the R in ADSR #: res/gui.glade:1209 msgctxt "Auto Sampler" msgid "Release" msgstr "Desvaniment" #: res/gui.glade:1252 res/gui.glade:1866 res/gui.glade:2336 msgid "Duration" msgstr "Duració" #. Start MIDI key (note) #: res/gui.glade:1301 msgctxt "Auto Sampler" msgid "Start" msgstr "Inici" #. End MIDI key (note) #: res/gui.glade:1333 msgctxt "Auto Sampler" msgid "End" msgstr "Fi" #. Distance between different samples #: res/gui.glade:1365 msgctxt "Auto Sampler" msgid "Distance" msgstr "Distància" #. As in MIDI velocity #: res/gui.glade:1378 msgctxt "Auto Sampler" msgid "Velocity" msgstr "Velocitat" #. MIDI channel #: res/gui.glade:1421 msgctxt "Auto Sampler" msgid "Channel" msgstr "Canal" #: res/gui.glade:1508 msgid "Show _Remote" msgstr "Mostrar remoto" #: res/gui.glade:1532 msgid "_Preferences " msgstr "_Preferències" #: res/gui.glade:1556 msgid "_About" msgstr "_Quant a" #: res/gui.glade:1667 res/gui.glade:2111 msgid "Go to Parent Directory" msgstr "Ves al directori pare" #: res/gui.glade:1709 res/gui.glade:2153 msgid "Refresh Directory" msgstr "Actualitza el directori" #: res/gui.glade:1730 res/gui.glade:2174 msgid "Search" msgstr "Buscar" #: res/gui.glade:1833 res/gui.glade:2300 msgid "Format" msgstr "Format" #: res/gui.glade:1855 res/gui.glade:2324 msgid "MIDI Note" msgstr "Nota MIDI" #: res/gui.glade:1877 res/gui.glade:2348 msgid "Rate" msgstr "Freqüència" #: res/gui.glade:1888 res/gui.glade:2360 msgid "Samples" msgstr "Mostres" #: res/gui.glade:1899 res/gui.glade:2372 msgid "Information" msgstr "Informació" #: res/gui.glade:1912 res/gui.glade:2387 msgid "Size" msgstr "Mida" #: res/gui.glade:2008 msgid "Refresh Devices" msgstr "Actualitza els dispositius" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2617 msgid "Auto play" msgstr "" "Reproduïx\n" "automàticament" #: res/gui.glade:2669 msgid "Grid" msgstr "Graella" #: res/gui.glade:2729 msgid "Playing mix depends on the remote channels" msgstr "La mescla per a reproducció depén dels canals del remot" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2731 msgid "" "Mix depending\n" "on remote" msgstr "" "Mescla segón\n" "el remot" #: res/gui.glade:2842 msgid "Status" msgstr "Estat" #: res/gui.glade:2853 msgid "Type" msgstr "Tipus" #: res/gui.glade:2874 msgid "Source" msgstr "Origen" #: res/gui.glade:2888 msgid "Destination" msgstr "Destinació" #: res/gui.glade:2903 msgid "Progress" msgstr "Progrés" #: res/gui.glade:2935 msgid "Cancel Tasks" msgstr "Cancel·la les tasques" #: res/gui.glade:2956 msgid "Remove Queued Tasks" msgstr "Elimina les tasques de la cua" #: res/gui.glade:2977 msgid "Clear Finished Tasks" msgstr "Neteja les tasques terminadas" #: res/gui.glade:3224 msgid "Preferences" msgstr "Preferencies" #: res/gui.glade:3314 msgid "Play sample while loading" msgstr "Reproduïx mostra al carregar" #: res/gui.glade:3342 msgid "Buffer length" msgstr "Llargària del buffer" #: res/gui.glade:3418 msgid "Stop device when connecting" msgstr "Para dispositiu al conectar" #. Sound is a type of data in Elektron devices so it is better not to translate these words or quote them. #: res/gui.glade:3488 msgid "Load sound and preset tags" msgstr "Carrega etiquetes de sounds i presets" #: res/gui.glade:3631 msgid "Record Channels" msgstr "Canals de gravació" #: res/gui.glade:3666 msgid "_Record" msgstr "_Gravar" #: res/microbrute/gui.glade:35 msgid "Calibration assistant" msgstr "Assistent de calibratge" #: res/microbrute/gui.glade:42 msgid "This procedure calibrates the pitch bend and modulation wheels." msgstr "Este procediment calibra les rodes d'inflexió y de modulació" #: res/microbrute/gui.glade:46 msgid "Start" msgstr "Inici" #: res/microbrute/gui.glade:54 msgid "" "Let the pitch bend wheel rest at the neutral position and click on the next " "button." msgstr "" "Deixa la roda d'inflexió a la posició neutral i fes clic al botó de següent." #: res/microbrute/gui.glade:59 msgid "Step 1" msgstr "Pas 1" #: res/microbrute/gui.glade:67 msgid "While setting both wheels at the bottom click on the next button." msgstr "Mentre mantens ambes rodes dalt, fes clic al botó de següent." #: res/microbrute/gui.glade:72 msgid "Step 2" msgstr "Pas 2" #: res/microbrute/gui.glade:80 msgid "While setting both wheels at the top click on the next button." msgstr "Mentre mantens ambes rodes baix, fes clic al botó de següent." #: res/microbrute/gui.glade:85 msgid "Step 3" msgstr "Pas 3" #: res/microbrute/gui.glade:93 msgid "Calibration completed" msgstr "Calibratge completat" #: res/microbrute/gui.glade:98 msgid "End" msgstr "Fi" #: res/microbrute/gui.glade:117 msgctxt "Gate Length" msgid "Short" msgstr "Curta" #: res/microbrute/gui.glade:121 msgctxt "Gate Length" msgid "Medium" msgstr "Mèdia" #: res/microbrute/gui.glade:125 msgctxt "Gate Length" msgid "Long" msgstr "Llarga" #: res/microbrute/gui.glade:139 msgctxt "Key Priority" msgid "Last" msgstr "Última" #: res/microbrute/gui.glade:143 msgctxt "Key Priority" msgid "Low" msgstr "Baixa" #: res/microbrute/gui.glade:147 msgctxt "Key Priority" msgid "High" msgstr "Alta" #: res/microbrute/gui.glade:161 msgctxt "Play Mode" msgid "Hold" msgstr "Contínua" #: res/microbrute/gui.glade:165 msgctxt "Play Mode" msgid "Note On" msgstr "Al polsar" #: res/microbrute/gui.glade:179 msgctxt "Receive Channel" msgid "Any" msgstr "Tots" #: res/microbrute/gui.glade:257 msgctxt "Sequence Change" msgid "At End" msgstr "A la fi" #: res/microbrute/gui.glade:261 msgctxt "Sequence Change" msgid "Instant Reset" msgstr "Reinici insttantani" #: res/microbrute/gui.glade:265 msgctxt "Sequence Change" msgid "Instant Continuation" msgstr "Continuació insttantània" #: res/microbrute/gui.glade:279 msgctxt "Sequence Retrigger" msgid "Reset" msgstr "Reinici" #: res/microbrute/gui.glade:283 msgctxt "Sequence Retrigger" msgid "Reset But Legato" msgstr "Reinici excepte en lligat" #: res/microbrute/gui.glade:287 msgctxt "Sequence Retrigger" msgid "None" msgstr "Retret de secuencia" #: res/microbrute/gui.glade:327 msgctxt "Step On" msgid "Clock" msgstr "Rellotge" #: res/microbrute/gui.glade:331 msgctxt "Step On" msgid "Gate" msgstr "Porta" #: res/microbrute/gui.glade:345 msgctxt "Synchronization" msgid "Auto" msgstr "Automàtica" #: res/microbrute/gui.glade:349 msgctxt "Synchronization" msgid "Internal" msgstr "Interna" #: res/microbrute/gui.glade:353 msgctxt "Synchronization" msgid "External" msgstr "Externa" #: res/microbrute/gui.glade:441 msgctxt "Velocity Response" msgid "Linear" msgstr "Lineal" #: res/microbrute/gui.glade:445 msgctxt "Velocity Response" msgid "Logarithmic" msgstr "Logarítmica" #: res/microbrute/gui.glade:449 msgctxt "Velocity Response" msgid "Exponential" msgstr "Exponencial" #: res/microbrute/gui.glade:456 msgid "MicroBrute Configuration" msgstr "Configuració de MicroBrute" #: res/microbrute/gui.glade:480 msgid "Persistent changes" msgstr "Canvis persistents" #: res/microbrute/gui.glade:547 msgid "Transmit Channel" msgstr "Canal de transmissió" #: res/microbrute/gui.glade:559 msgid "Receive Channel" msgstr "Canal de recepció" #: res/microbrute/gui.glade:650 msgid "Key Priority" msgstr "Prioritat de tecla" #: res/microbrute/gui.glade:662 msgid "Velocity Response" msgstr "Resposta de velocitat" #: res/microbrute/gui.glade:715 msgid "Keyboard Parameters" msgstr "Paràmetres del teclat" #: res/microbrute/gui.glade:753 msgid "Play Mode" msgstr "Modo de reproducció" #: res/microbrute/gui.glade:765 msgid "Sequence Retrigger" msgstr "Retret de seqüència" #: res/microbrute/gui.glade:777 msgid "Sequence Change" msgstr "Canvi de seqüència" #: res/microbrute/gui.glade:789 msgid "Next Step On" msgstr "Següent pas" #: res/microbrute/gui.glade:801 msgid "Step Length" msgstr "Llargària del pas" #: res/microbrute/gui.glade:914 msgid "Sequencer Control" msgstr "Control del seqüenciador" #: res/microbrute/gui.glade:952 msgid "LFO Key Retrigger" msgstr "Retret del LFO" #: res/microbrute/gui.glade:964 msgid "Envelope Legato" msgstr "Envoltant lligada" #: res/microbrute/gui.glade:976 msgid "Bend Range" msgstr "Inflexió de to" #: res/microbrute/gui.glade:988 msgid "Gate Length" msgstr "Llargària de la porta" #: res/microbrute/gui.glade:1000 msgid "Synchronization" msgstr "Sincronització" #: res/microbrute/gui.glade:1094 msgid "Module Parameters" msgstr "Paràmetres del mòdul" elektroid-3.2.3/po/de.po000066400000000000000000000377321500236517400150660ustar00rootroot00000000000000# German translations for Elektroid package. # Copyright (C) 2020-2024 Dennis Braun # This file is distributed under the same license as the Elektroid package. # Dennis Braun , 2024. # msgid "" msgstr "" "Project-Id-Version: elektroid 3.0\n" "Report-Msgid-Bugs-To: dagargo@gmail.com\n" "POT-Creation-Date: 2025-04-22 19:10+0200\n" "PO-Revision-Date: 2024-09-22 15:18+0200\n" "Last-Translator: Dennis Braun \n" "Language-Team: German\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: src/elektroid.c:236 src/elektroid.c:242 src/editor.c:1309 msgid "Audio" msgstr "" #: src/elektroid.c:326 src/elektroid.c:3005 msgid "Not connected" msgstr "Nicht verbunden" #: src/elektroid.c:442 #, fuzzy msgid "Receiving SysEx" msgstr "Empfange SysEx" #: src/elektroid.c:466 msgid "Save SysEx" msgstr "Speichere SysEx" #: src/elektroid.c:467 src/elektroid.c:595 src/elektroid.c:854 #: src/elektroid.c:1418 src/editor.c:1203 src/mactions/microfreak.c:52 #: res/gui.glade:1003 res/gui.glade:3139 res/gui.glade:3245 res/gui.glade:3566 #: res/gui.glade:3652 msgid "_Cancel" msgstr "_Abbrechen" #: src/elektroid.c:468 res/gui.glade:3153 res/gui.glade:3259 msgid "_Save" msgstr "_Speichern" #: src/elektroid.c:472 msgid "Received SysEx" msgstr "SysEx empfangen" #: src/elektroid.c:477 src/elektroid.c:600 msgid "SysEx Files" msgstr "SysEx Dateien" #: src/elektroid.c:514 #, c-format msgid "Error while saving “%s”: %s." msgstr "Fehler beim Speichern von »%s«: %s." #: src/elektroid.c:539 #, c-format msgid "Error while loading “%s”: %s." msgstr "Fehler beim Laden von »%s«: %s." #: src/elektroid.c:593 msgid "Open SysEx" msgstr "Öffne SysEx" #: src/elektroid.c:596 msgid "_Open" msgstr "_Öffnen" #: src/elektroid.c:612 msgid "Sending SysEx" msgstr "Sende SysEx" #: src/elektroid.c:853 msgid "Are you sure you want to delete the selected items?" msgstr "Bist du sicher das du die ausgewählten Dateien löschen möchtest?" #: src/elektroid.c:855 msgid "_Delete" msgstr "_Löschen" #: src/elektroid.c:874 msgid "Deleting Files" msgstr "Entferne Dateien" #: src/elektroid.c:874 msgid "Deleting..." msgstr "Lösche..." #: src/elektroid.c:911 res/gui.glade:255 res/gui.glade:891 msgid "Rename" msgstr "Umbenennen" #: src/elektroid.c:935 #, c-format msgid "Error while renaming to “%s”: %s." msgstr "Fehler beim Umbenennen von »%s«: %s." #: src/elektroid.c:1289 res/gui.glade:1688 res/gui.glade:2132 msgid "Add Directory" msgstr "Verzeichnis hinzufügen" #: src/elektroid.c:1297 #, c-format msgid "Error while creating dir “%s”: %s." msgstr "Fehler beim Erstellen des Verzeichnisses »%s«: %s." #: src/elektroid.c:1416 src/editor.c:1200 #, c-format msgid "Replace file “%s”?" msgstr "Ersetze Datei “%s”?" #: src/elektroid.c:1419 msgid "_Skip" msgstr "_Überspringe" #: src/elektroid.c:1420 src/editor.c:1204 msgid "_Replace" msgstr "_Ersetze" #: src/elektroid.c:1425 msgid "Apply this action to all files" msgstr "Diese Aktion auf alle Dateien anwenden" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2494 msgid "Preparing Tasks" msgstr "Aufgaben werden vorbereitet" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2495 #: src/progress.c:107 msgid "Waiting..." msgstr "Warte..." #: src/elektroid.c:2239 msgid "Connecting to Device" msgstr "Verbindung zum Gerät wird hergestellt" #: src/elektroid.c:2240 msgid "Connecting..." msgstr "Verbinde..." #: src/elektroid.c:2247 #, c-format msgid "Device “%s” not recognized: %s" msgstr "Gerät “%s” nicht erkannt: %s" #: src/elektroid.c:2481 msgid "Moving Files" msgstr "Verschiebe Dateien" #: src/elektroid.c:2482 msgid "Moving..." msgstr "Verschiebe..." #: src/elektroid.c:2789 msgid "Acknowledgements" msgstr "" #: src/editor.c:1325 msgid "Save Sample" msgstr "Speichere Sample" #: src/tasks.c:32 msgid "Queued" msgstr "In der Warteschlange" #: src/tasks.c:34 msgid "Running" msgstr "Wird ausgeführt" #: src/tasks.c:36 msgid "Completed" msgstr "Fertig" #: src/tasks.c:38 msgid "Terminated with errors" msgstr "Abgeschlossen mit Fehlern" #: src/tasks.c:40 msgid "Canceled" msgstr "Abgebrochen" #: src/tasks.c:42 src/tasks.c:56 msgid "Undefined" msgstr "Undefiniert" #: src/tasks.c:52 msgid "Upload" msgstr "Hochladen" #: src/tasks.c:54 msgid "Download" msgstr "Herunterladen" #: src/browser.c:324 msgid "min." msgstr "Min." #: src/audio_pa.c:337 msgid "Output" msgstr "Ausgabe" #: src/audio_pa.c:340 msgid "Input" msgstr "Eingabe" #. This should only be translated if a non latin alphabet is used #: src/mactions/autosampler.c:205 res/gui.glade:982 msgid "Auto Sampler" msgstr "" #: src/mactions/autosampler.c:205 msgid "Recording..." msgstr "Aufnahme..." #: src/mactions/autosampler.c:282 msgid "_Auto Sampler" msgstr "" #: src/mactions/backend.c:60 msgid "OS _Upgrade" msgstr "OS _Aktualisierung" #: src/mactions/backend.c:75 msgid "_Receive SysEx" msgstr "_Empfange SysEx" #: src/mactions/backend.c:90 msgid "_Send SysEx" msgstr "_Sende SysEx" #: src/mactions/microbrute.c:394 msgid "_Configuration" msgstr "_Konfiguration" #: src/mactions/microbrute.c:422 msgid "_Calibration" msgstr "_Kalibrierung" #: src/mactions/microfreak.c:51 msgid "" "The defragmentation process could take several minutes and could not be " "canceled. Are you sure you want to defragment the sample memory?" msgstr "" "Der Defragmentierungsprozess könnte mehrere Minuten dauern und kann nicht " "abgebrochen werden. Sind Sie sicher, dass Sie den Sample Speicher " "defragmentieren möchten?" #: src/mactions/microfreak.c:53 src/mactions/microfreak.c:85 msgid "_Defragment" msgstr "_Defragmentieren" #: src/mactions/microfreak.c:66 msgid "Defragmenting Sample Memory" msgstr "Defragmentiere Sample Speicher" #: src/progress.c:52 msgid "Cancelling..." msgstr "Abbrechen..." #: src/progress.c:110 msgid "Sending..." msgstr "Sende..." #: src/progress.c:113 msgid "Receiving..." msgstr "Empfange..." #. TRANSLATORS: Stereo recording #: src/guirecorder.c:68 msgid "Stereo" msgstr "" #. TRANSLATORS: Mono recording from left channel #: src/guirecorder.c:78 msgid "Left" msgstr "Links" #. TRANSLATORS: Mono recording from right channel #: src/guirecorder.c:85 msgid "Right" msgstr "Rechts" #: src/connectors/sds.c:1359 msgid "SDS sampler" msgstr "" #: src/connectors/default.c:84 msgid "MIDI device" msgstr "MIDI Gerät" #: src/connectors/system.c:670 msgid "System" msgstr "" #: res/gui.glade:104 res/gui.glade:218 res/gui.glade:854 msgid "Play" msgstr "Abspielen" #: res/gui.glade:119 res/gui.glade:264 res/gui.glade:900 msgid "Delete" msgstr "Löschen" #: res/gui.glade:128 msgid "Undo" msgstr "Rückgängig" #: res/gui.glade:143 msgid "Save" msgstr "Speichern" #: res/gui.glade:203 msgid "Upload Selection" msgstr "Upload Auswahl" #: res/gui.glade:233 res/gui.glade:869 msgid "Open With External Editor" msgstr "Öffnen mit externen Editor" #: res/gui.glade:241 res/gui.glade:877 msgid "Show in File Manager" msgstr "Im Dateimanager _Anzeigen" #: res/gui.glade:839 msgid "Download Selection" msgstr "Download Auswahl" #: res/gui.glade:945 msgid "Sample and MIDI device manager" msgstr "Sample und MIDI Gerätemanager" #: res/gui.glade:948 msgid "translator-credits" msgstr "Dennis Braun " #: res/gui.glade:1017 msgid "_Start" msgstr "" #: res/gui.glade:1077 res/gui.glade:1819 res/gui.glade:2285 res/gui.glade:3184 msgid "Name" msgstr "Name" #. Audio channels #: res/gui.glade:1103 res/gui.glade:1844 res/gui.glade:2312 res/gui.glade:3701 msgid "Channels" msgstr "Kanäle" #. Input audio monitor #: res/gui.glade:1134 res/gui.glade:3732 msgid "Monitor" msgstr "" #: res/gui.glade:1159 msgid "Global" msgstr "" #. Press key time #: res/gui.glade:1196 msgctxt "Auto Sampler" msgid "Press" msgstr "Drücke" #. As the R in ADSR #: res/gui.glade:1209 msgctxt "Auto Sampler" msgid "Release" msgstr "" #: res/gui.glade:1252 res/gui.glade:1866 res/gui.glade:2336 msgid "Duration" msgstr "Dauer" #. Start MIDI key (note) #: res/gui.glade:1301 msgctxt "Auto Sampler" msgid "Start" msgstr "" #. End MIDI key (note) #: res/gui.glade:1333 msgctxt "Auto Sampler" msgid "End" msgstr "Ende" #. Distance between different samples #: res/gui.glade:1365 msgctxt "Auto Sampler" msgid "Distance" msgstr "Distanz" #. As in MIDI velocity #: res/gui.glade:1378 msgctxt "Auto Sampler" msgid "Velocity" msgstr "Geschwindigkeit" #. MIDI channel #: res/gui.glade:1421 msgctxt "Auto Sampler" msgid "Channel" msgstr "Kanäle" #: res/gui.glade:1508 #, fuzzy msgid "Show _Remote" msgstr "Zeige Remote" #: res/gui.glade:1532 msgid "_Preferences " msgstr "_Einstellungen " #: res/gui.glade:1556 msgid "_About" msgstr "_Info" #: res/gui.glade:1667 res/gui.glade:2111 msgid "Go to Parent Directory" msgstr "Gehe zum übergeordneten Verzeichnis" #: res/gui.glade:1709 res/gui.glade:2153 msgid "Refresh Directory" msgstr "Aktualisiere Verzeichnis" #: res/gui.glade:1730 res/gui.glade:2174 msgid "Search" msgstr "Suche" #: res/gui.glade:1833 res/gui.glade:2300 msgid "Format" msgstr "" #: res/gui.glade:1855 res/gui.glade:2324 msgid "MIDI Note" msgstr "" #: res/gui.glade:1877 res/gui.glade:2348 msgid "Rate" msgstr "" #: res/gui.glade:1888 res/gui.glade:2360 msgid "Samples" msgstr "" #: res/gui.glade:1899 res/gui.glade:2372 msgid "Information" msgstr "Information" #: res/gui.glade:1912 res/gui.glade:2387 msgid "Size" msgstr "Größe" #: res/gui.glade:2008 msgid "Refresh Devices" msgstr "Aktualisiere Geräte" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2617 msgid "Auto play" msgstr "Auto Play" #: res/gui.glade:2669 msgid "Grid" msgstr "" #: res/gui.glade:2729 msgid "Playing mix depends on the remote channels" msgstr "Das Abspielen vom Mix hängt von den Remote-Kanälen ab" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2731 msgid "" "Mix depending\n" "on remote" msgstr "" "Mix hängt ab von\n" "den Remote-Kanälen" #: res/gui.glade:2842 msgid "Status" msgstr "Status" #: res/gui.glade:2853 msgid "Type" msgstr "Typ" #: res/gui.glade:2874 msgid "Source" msgstr "Quelle" #: res/gui.glade:2888 msgid "Destination" msgstr "Ziel" #: res/gui.glade:2903 msgid "Progress" msgstr "Fortschritt" #: res/gui.glade:2935 msgid "Cancel Tasks" msgstr "Aufgaben abbrechen" #: res/gui.glade:2956 msgid "Remove Queued Tasks" msgstr "Lösche Aufgaben in der Warteschlange" #: res/gui.glade:2977 msgid "Clear Finished Tasks" msgstr "Abgeschlossene Aufgaben aufräumen" #: res/gui.glade:3224 msgid "Preferences" msgstr "Einstellungen" #: res/gui.glade:3314 msgid "Play sample while loading" msgstr "Abspielen vom Sample während des Ladens" #: res/gui.glade:3342 msgid "Buffer length" msgstr "Pufferlänge" #: res/gui.glade:3418 msgid "Stop device when connecting" msgstr "Stoppe das Gerät beim Verbinden" #. Sound is a type of data in Elektron devices so it is better not to translate these words or quote them. #: res/gui.glade:3488 msgid "Load sound and preset tags" msgstr "Lade Sound und Preset Tags" #: res/gui.glade:3631 msgid "Record Channels" msgstr "Aufnahme Kanäle" #: res/gui.glade:3666 msgid "_Record" msgstr "_Aufnahme" #: res/microbrute/gui.glade:35 msgid "Calibration assistant" msgstr "Kalibrierungsassistent" #: res/microbrute/gui.glade:42 msgid "This procedure calibrates the pitch bend and modulation wheels." msgstr "Dieser Vorgang kalibriert das Pitchbend- und das Modulationsrad" #: res/microbrute/gui.glade:46 msgid "Start" msgstr "" #: res/microbrute/gui.glade:54 msgid "" "Let the pitch bend wheel rest at the neutral position and click on the next " "button." msgstr "" "Lassen Sie das Pitch-Bend-Rad in der neutralen Position stehen und klicken " "Sie auf die Schaltfläche „Weiter“." #: res/microbrute/gui.glade:59 msgid "Step 1" msgstr "Schritt 1" #: res/microbrute/gui.glade:67 msgid "While setting both wheels at the bottom click on the next button." msgstr "" "Während Sie beide Räder ganz unten einstellen, klicken Sie auf die " "Schaltfläche „Weiter“." #: res/microbrute/gui.glade:72 msgid "Step 2" msgstr "Schritt 2" #: res/microbrute/gui.glade:80 msgid "While setting both wheels at the top click on the next button." msgstr "" "Während Sie beide Räder ganz oben einstellen, klicken Sie auf die " "Schaltfläche „Weiter“." #: res/microbrute/gui.glade:85 msgid "Step 3" msgstr "Schritt 3" #: res/microbrute/gui.glade:93 msgid "Calibration completed" msgstr "Kalibrierung vollendet" #: res/microbrute/gui.glade:98 msgid "End" msgstr "Ende" #: res/microbrute/gui.glade:117 msgctxt "Gate Length" msgid "Short" msgstr "Kurz" #: res/microbrute/gui.glade:121 msgctxt "Gate Length" msgid "Medium" msgstr "" #: res/microbrute/gui.glade:125 msgctxt "Gate Length" msgid "Long" msgstr "Lang" #: res/microbrute/gui.glade:139 msgctxt "Key Priority" msgid "Last" msgstr "Letzte" #: res/microbrute/gui.glade:143 msgctxt "Key Priority" msgid "Low" msgstr "Niedrig" #: res/microbrute/gui.glade:147 msgctxt "Key Priority" msgid "High" msgstr "Hoch" #: res/microbrute/gui.glade:161 msgctxt "Play Mode" msgid "Hold" msgstr "Halten" #: res/microbrute/gui.glade:165 msgctxt "Play Mode" msgid "Note On" msgstr "Note an" #: res/microbrute/gui.glade:179 msgctxt "Receive Channel" msgid "Any" msgstr "Beliebig" #: res/microbrute/gui.glade:257 msgctxt "Sequence Change" msgid "At End" msgstr "Am Ende" #: res/microbrute/gui.glade:261 msgctxt "Sequence Change" msgid "Instant Reset" msgstr "Sofortiges Zurücksetzen" #: res/microbrute/gui.glade:265 msgctxt "Sequence Change" msgid "Instant Continuation" msgstr "Dauer" #: res/microbrute/gui.glade:279 msgctxt "Sequence Retrigger" msgid "Reset" msgstr "Zurücksetzen" #: res/microbrute/gui.glade:283 msgctxt "Sequence Retrigger" msgid "Reset But Legato" msgstr "Zurücksetzen, aber Legato" #: res/microbrute/gui.glade:287 msgctxt "Sequence Retrigger" msgid "None" msgstr "Keine" #: res/microbrute/gui.glade:327 msgctxt "Step On" msgid "Clock" msgstr "Uhr" #: res/microbrute/gui.glade:331 msgctxt "Step On" msgid "Gate" msgstr "" #: res/microbrute/gui.glade:345 msgctxt "Synchronization" msgid "Auto" msgstr "Auto Play" #: res/microbrute/gui.glade:349 msgctxt "Synchronization" msgid "Internal" msgstr "Intern" #: res/microbrute/gui.glade:353 msgctxt "Synchronization" msgid "External" msgstr "Extern" #: res/microbrute/gui.glade:441 msgctxt "Velocity Response" msgid "Linear" msgstr "" #: res/microbrute/gui.glade:445 msgctxt "Velocity Response" msgid "Logarithmic" msgstr "Logarithmisch" #: res/microbrute/gui.glade:449 msgctxt "Velocity Response" msgid "Exponential" msgstr "Exponentiell" #: res/microbrute/gui.glade:456 msgid "MicroBrute Configuration" msgstr "MicroBrute Konfiguration" #: res/microbrute/gui.glade:480 msgid "Persistent changes" msgstr "Beständige Veränderungen" #: res/microbrute/gui.glade:547 msgid "Transmit Channel" msgstr "Sendekanal" #: res/microbrute/gui.glade:559 msgid "Receive Channel" msgstr "Empfangskanal" #: res/microbrute/gui.glade:650 msgid "Key Priority" msgstr "Key Priorität" #: res/microbrute/gui.glade:662 msgid "Velocity Response" msgstr "Geschwindigkeitsreaktion" #: res/microbrute/gui.glade:715 msgid "Keyboard Parameters" msgstr "Keyboard Parameter" #: res/microbrute/gui.glade:753 msgid "Play Mode" msgstr "Abspielmodus" #: res/microbrute/gui.glade:765 msgid "Sequence Retrigger" msgstr "Sequenz Retrigger" #: res/microbrute/gui.glade:777 msgid "Sequence Change" msgstr "Sequenz Änderung" #: res/microbrute/gui.glade:789 msgid "Next Step On" msgstr "Nächster Schritt An" #: res/microbrute/gui.glade:801 msgid "Step Length" msgstr "Schrittlänge" #: res/microbrute/gui.glade:914 msgid "Sequencer Control" msgstr "Sequenzersteuerung" #: res/microbrute/gui.glade:952 msgid "LFO Key Retrigger" msgstr "" #: res/microbrute/gui.glade:964 msgid "Envelope Legato" msgstr "" #: res/microbrute/gui.glade:976 msgid "Bend Range" msgstr "Bend Bereich" #: res/microbrute/gui.glade:988 msgid "Gate Length" msgstr "Gate Länge" #: res/microbrute/gui.glade:1000 msgid "Synchronization" msgstr "Synchronisierung" #: res/microbrute/gui.glade:1094 msgid "Module Parameters" msgstr "Modul Parameter" elektroid-3.2.3/po/elektroid.pot000066400000000000000000000322401500236517400166310ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR David García Goñi # This file is distributed under the same license as the elektroid package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: elektroid 3.2.3\n" "Report-Msgid-Bugs-To: dagargo@gmail.com\n" "POT-Creation-Date: 2025-04-22 19:10+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/elektroid.c:236 src/elektroid.c:242 src/editor.c:1309 msgid "Audio" msgstr "" #: src/elektroid.c:326 src/elektroid.c:3005 msgid "Not connected" msgstr "" #: src/elektroid.c:442 msgid "Receiving SysEx" msgstr "" #: src/elektroid.c:466 msgid "Save SysEx" msgstr "" #: src/elektroid.c:467 src/elektroid.c:595 src/elektroid.c:854 #: src/elektroid.c:1418 src/editor.c:1203 src/mactions/microfreak.c:52 #: res/gui.glade:1003 res/gui.glade:3139 res/gui.glade:3245 res/gui.glade:3566 #: res/gui.glade:3652 msgid "_Cancel" msgstr "" #: src/elektroid.c:468 res/gui.glade:3153 res/gui.glade:3259 msgid "_Save" msgstr "" #: src/elektroid.c:472 msgid "Received SysEx" msgstr "" #: src/elektroid.c:477 src/elektroid.c:600 msgid "SysEx Files" msgstr "" #: src/elektroid.c:514 #, c-format msgid "Error while saving “%s”: %s." msgstr "" #: src/elektroid.c:539 #, c-format msgid "Error while loading “%s”: %s." msgstr "" #: src/elektroid.c:593 msgid "Open SysEx" msgstr "" #: src/elektroid.c:596 msgid "_Open" msgstr "" #: src/elektroid.c:612 msgid "Sending SysEx" msgstr "" #: src/elektroid.c:853 msgid "Are you sure you want to delete the selected items?" msgstr "" #: src/elektroid.c:855 msgid "_Delete" msgstr "" #: src/elektroid.c:874 msgid "Deleting Files" msgstr "" #: src/elektroid.c:874 msgid "Deleting..." msgstr "" #: src/elektroid.c:911 res/gui.glade:255 res/gui.glade:891 msgid "Rename" msgstr "" #: src/elektroid.c:935 #, c-format msgid "Error while renaming to “%s”: %s." msgstr "" #: src/elektroid.c:1289 res/gui.glade:1688 res/gui.glade:2132 msgid "Add Directory" msgstr "" #: src/elektroid.c:1297 #, c-format msgid "Error while creating dir “%s”: %s." msgstr "" #: src/elektroid.c:1416 src/editor.c:1200 #, c-format msgid "Replace file “%s”?" msgstr "" #: src/elektroid.c:1419 msgid "_Skip" msgstr "" #: src/elektroid.c:1420 src/editor.c:1204 msgid "_Replace" msgstr "" #: src/elektroid.c:1425 msgid "Apply this action to all files" msgstr "" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2494 msgid "Preparing Tasks" msgstr "" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2495 #: src/progress.c:107 msgid "Waiting..." msgstr "" #: src/elektroid.c:2239 msgid "Connecting to Device" msgstr "" #: src/elektroid.c:2240 msgid "Connecting..." msgstr "" #: src/elektroid.c:2247 #, c-format msgid "Device “%s” not recognized: %s" msgstr "" #: src/elektroid.c:2481 msgid "Moving Files" msgstr "" #: src/elektroid.c:2482 msgid "Moving..." msgstr "" #: src/elektroid.c:2789 msgid "Acknowledgements" msgstr "" #: src/editor.c:1325 msgid "Save Sample" msgstr "" #: src/tasks.c:32 msgid "Queued" msgstr "" #: src/tasks.c:34 msgid "Running" msgstr "" #: src/tasks.c:36 msgid "Completed" msgstr "" #: src/tasks.c:38 msgid "Terminated with errors" msgstr "" #: src/tasks.c:40 msgid "Canceled" msgstr "" #: src/tasks.c:42 src/tasks.c:56 msgid "Undefined" msgstr "" #: src/tasks.c:52 msgid "Upload" msgstr "" #: src/tasks.c:54 msgid "Download" msgstr "" #: src/browser.c:324 msgid "min." msgstr "" #: src/audio_pa.c:337 msgid "Output" msgstr "" #: src/audio_pa.c:340 msgid "Input" msgstr "" #. This should only be translated if a non latin alphabet is used #: src/mactions/autosampler.c:205 res/gui.glade:982 msgid "Auto Sampler" msgstr "" #: src/mactions/autosampler.c:205 msgid "Recording..." msgstr "" #: src/mactions/autosampler.c:282 msgid "_Auto Sampler" msgstr "" #: src/mactions/backend.c:60 msgid "OS _Upgrade" msgstr "" #: src/mactions/backend.c:75 msgid "_Receive SysEx" msgstr "" #: src/mactions/backend.c:90 msgid "_Send SysEx" msgstr "" #: src/mactions/microbrute.c:394 msgid "_Configuration" msgstr "" #: src/mactions/microbrute.c:422 msgid "_Calibration" msgstr "" #: src/mactions/microfreak.c:51 msgid "" "The defragmentation process could take several minutes and could not be " "canceled. Are you sure you want to defragment the sample memory?" msgstr "" #: src/mactions/microfreak.c:53 src/mactions/microfreak.c:85 msgid "_Defragment" msgstr "" #: src/mactions/microfreak.c:66 msgid "Defragmenting Sample Memory" msgstr "" #: src/progress.c:52 msgid "Cancelling..." msgstr "" #: src/progress.c:110 msgid "Sending..." msgstr "" #: src/progress.c:113 msgid "Receiving..." msgstr "" #. TRANSLATORS: Stereo recording #: src/guirecorder.c:68 msgid "Stereo" msgstr "" #. TRANSLATORS: Mono recording from left channel #: src/guirecorder.c:78 msgid "Left" msgstr "" #. TRANSLATORS: Mono recording from right channel #: src/guirecorder.c:85 msgid "Right" msgstr "" #: src/connectors/sds.c:1359 msgid "SDS sampler" msgstr "" #: src/connectors/default.c:84 msgid "MIDI device" msgstr "" #: src/connectors/system.c:670 msgid "System" msgstr "" #: res/gui.glade:104 res/gui.glade:218 res/gui.glade:854 msgid "Play" msgstr "" #: res/gui.glade:119 res/gui.glade:264 res/gui.glade:900 msgid "Delete" msgstr "" #: res/gui.glade:128 msgid "Undo" msgstr "" #: res/gui.glade:143 msgid "Save" msgstr "" #: res/gui.glade:203 msgid "Upload Selection" msgstr "" #: res/gui.glade:233 res/gui.glade:869 msgid "Open With External Editor" msgstr "" #: res/gui.glade:241 res/gui.glade:877 msgid "Show in File Manager" msgstr "" #: res/gui.glade:839 msgid "Download Selection" msgstr "" #: res/gui.glade:945 msgid "Sample and MIDI device manager" msgstr "" #: res/gui.glade:948 msgid "translator-credits" msgstr "" #: res/gui.glade:1017 msgid "_Start" msgstr "" #: res/gui.glade:1077 res/gui.glade:1819 res/gui.glade:2285 res/gui.glade:3184 msgid "Name" msgstr "" #. Audio channels #: res/gui.glade:1103 res/gui.glade:1844 res/gui.glade:2312 res/gui.glade:3701 msgid "Channels" msgstr "" #. Input audio monitor #: res/gui.glade:1134 res/gui.glade:3732 msgid "Monitor" msgstr "" #: res/gui.glade:1159 msgid "Global" msgstr "" #. Press key time #: res/gui.glade:1196 msgctxt "Auto Sampler" msgid "Press" msgstr "" #. As the R in ADSR #: res/gui.glade:1209 msgctxt "Auto Sampler" msgid "Release" msgstr "" #: res/gui.glade:1252 res/gui.glade:1866 res/gui.glade:2336 msgid "Duration" msgstr "" #. Start MIDI key (note) #: res/gui.glade:1301 msgctxt "Auto Sampler" msgid "Start" msgstr "" #. End MIDI key (note) #: res/gui.glade:1333 msgctxt "Auto Sampler" msgid "End" msgstr "" #. Distance between different samples #: res/gui.glade:1365 msgctxt "Auto Sampler" msgid "Distance" msgstr "" #. As in MIDI velocity #: res/gui.glade:1378 msgctxt "Auto Sampler" msgid "Velocity" msgstr "" #. MIDI channel #: res/gui.glade:1421 msgctxt "Auto Sampler" msgid "Channel" msgstr "" #: res/gui.glade:1508 msgid "Show _Remote" msgstr "" #: res/gui.glade:1532 msgid "_Preferences " msgstr "" #: res/gui.glade:1556 msgid "_About" msgstr "" #: res/gui.glade:1667 res/gui.glade:2111 msgid "Go to Parent Directory" msgstr "" #: res/gui.glade:1709 res/gui.glade:2153 msgid "Refresh Directory" msgstr "" #: res/gui.glade:1730 res/gui.glade:2174 msgid "Search" msgstr "" #: res/gui.glade:1833 res/gui.glade:2300 msgid "Format" msgstr "" #: res/gui.glade:1855 res/gui.glade:2324 msgid "MIDI Note" msgstr "" #: res/gui.glade:1877 res/gui.glade:2348 msgid "Rate" msgstr "" #: res/gui.glade:1888 res/gui.glade:2360 msgid "Samples" msgstr "" #: res/gui.glade:1899 res/gui.glade:2372 msgid "Information" msgstr "" #: res/gui.glade:1912 res/gui.glade:2387 msgid "Size" msgstr "" #: res/gui.glade:2008 msgid "Refresh Devices" msgstr "" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2617 msgid "Auto play" msgstr "" #: res/gui.glade:2669 msgid "Grid" msgstr "" #: res/gui.glade:2729 msgid "Playing mix depends on the remote channels" msgstr "" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2731 msgid "" "Mix depending\n" "on remote" msgstr "" #: res/gui.glade:2842 msgid "Status" msgstr "" #: res/gui.glade:2853 msgid "Type" msgstr "" #: res/gui.glade:2874 msgid "Source" msgstr "" #: res/gui.glade:2888 msgid "Destination" msgstr "" #: res/gui.glade:2903 msgid "Progress" msgstr "" #: res/gui.glade:2935 msgid "Cancel Tasks" msgstr "" #: res/gui.glade:2956 msgid "Remove Queued Tasks" msgstr "" #: res/gui.glade:2977 msgid "Clear Finished Tasks" msgstr "" #: res/gui.glade:3224 msgid "Preferences" msgstr "" #: res/gui.glade:3314 msgid "Play sample while loading" msgstr "" #: res/gui.glade:3342 msgid "Buffer length" msgstr "" #: res/gui.glade:3418 msgid "Stop device when connecting" msgstr "" #. Sound is a type of data in Elektron devices so it is better not to translate these words or quote them. #: res/gui.glade:3488 msgid "Load sound and preset tags" msgstr "" #: res/gui.glade:3631 msgid "Record Channels" msgstr "" #: res/gui.glade:3666 msgid "_Record" msgstr "" #: res/microbrute/gui.glade:35 msgid "Calibration assistant" msgstr "" #: res/microbrute/gui.glade:42 msgid "This procedure calibrates the pitch bend and modulation wheels." msgstr "" #: res/microbrute/gui.glade:46 msgid "Start" msgstr "" #: res/microbrute/gui.glade:54 msgid "" "Let the pitch bend wheel rest at the neutral position and click on the next " "button." msgstr "" #: res/microbrute/gui.glade:59 msgid "Step 1" msgstr "" #: res/microbrute/gui.glade:67 msgid "While setting both wheels at the bottom click on the next button." msgstr "" #: res/microbrute/gui.glade:72 msgid "Step 2" msgstr "" #: res/microbrute/gui.glade:80 msgid "While setting both wheels at the top click on the next button." msgstr "" #: res/microbrute/gui.glade:85 msgid "Step 3" msgstr "" #: res/microbrute/gui.glade:93 msgid "Calibration completed" msgstr "" #: res/microbrute/gui.glade:98 msgid "End" msgstr "" #: res/microbrute/gui.glade:117 msgctxt "Gate Length" msgid "Short" msgstr "" #: res/microbrute/gui.glade:121 msgctxt "Gate Length" msgid "Medium" msgstr "" #: res/microbrute/gui.glade:125 msgctxt "Gate Length" msgid "Long" msgstr "" #: res/microbrute/gui.glade:139 msgctxt "Key Priority" msgid "Last" msgstr "" #: res/microbrute/gui.glade:143 msgctxt "Key Priority" msgid "Low" msgstr "" #: res/microbrute/gui.glade:147 msgctxt "Key Priority" msgid "High" msgstr "" #: res/microbrute/gui.glade:161 msgctxt "Play Mode" msgid "Hold" msgstr "" #: res/microbrute/gui.glade:165 msgctxt "Play Mode" msgid "Note On" msgstr "" #: res/microbrute/gui.glade:179 msgctxt "Receive Channel" msgid "Any" msgstr "" #: res/microbrute/gui.glade:257 msgctxt "Sequence Change" msgid "At End" msgstr "" #: res/microbrute/gui.glade:261 msgctxt "Sequence Change" msgid "Instant Reset" msgstr "" #: res/microbrute/gui.glade:265 msgctxt "Sequence Change" msgid "Instant Continuation" msgstr "" #: res/microbrute/gui.glade:279 msgctxt "Sequence Retrigger" msgid "Reset" msgstr "" #: res/microbrute/gui.glade:283 msgctxt "Sequence Retrigger" msgid "Reset But Legato" msgstr "" #: res/microbrute/gui.glade:287 msgctxt "Sequence Retrigger" msgid "None" msgstr "" #: res/microbrute/gui.glade:327 msgctxt "Step On" msgid "Clock" msgstr "" #: res/microbrute/gui.glade:331 msgctxt "Step On" msgid "Gate" msgstr "" #: res/microbrute/gui.glade:345 msgctxt "Synchronization" msgid "Auto" msgstr "" #: res/microbrute/gui.glade:349 msgctxt "Synchronization" msgid "Internal" msgstr "" #: res/microbrute/gui.glade:353 msgctxt "Synchronization" msgid "External" msgstr "" #: res/microbrute/gui.glade:441 msgctxt "Velocity Response" msgid "Linear" msgstr "" #: res/microbrute/gui.glade:445 msgctxt "Velocity Response" msgid "Logarithmic" msgstr "" #: res/microbrute/gui.glade:449 msgctxt "Velocity Response" msgid "Exponential" msgstr "" #: res/microbrute/gui.glade:456 msgid "MicroBrute Configuration" msgstr "" #: res/microbrute/gui.glade:480 msgid "Persistent changes" msgstr "" #: res/microbrute/gui.glade:547 msgid "Transmit Channel" msgstr "" #: res/microbrute/gui.glade:559 msgid "Receive Channel" msgstr "" #: res/microbrute/gui.glade:650 msgid "Key Priority" msgstr "" #: res/microbrute/gui.glade:662 msgid "Velocity Response" msgstr "" #: res/microbrute/gui.glade:715 msgid "Keyboard Parameters" msgstr "" #: res/microbrute/gui.glade:753 msgid "Play Mode" msgstr "" #: res/microbrute/gui.glade:765 msgid "Sequence Retrigger" msgstr "" #: res/microbrute/gui.glade:777 msgid "Sequence Change" msgstr "" #: res/microbrute/gui.glade:789 msgid "Next Step On" msgstr "" #: res/microbrute/gui.glade:801 msgid "Step Length" msgstr "" #: res/microbrute/gui.glade:914 msgid "Sequencer Control" msgstr "" #: res/microbrute/gui.glade:952 msgid "LFO Key Retrigger" msgstr "" #: res/microbrute/gui.glade:964 msgid "Envelope Legato" msgstr "" #: res/microbrute/gui.glade:976 msgid "Bend Range" msgstr "" #: res/microbrute/gui.glade:988 msgid "Gate Length" msgstr "" #: res/microbrute/gui.glade:1000 msgid "Synchronization" msgstr "" #: res/microbrute/gui.glade:1094 msgid "Module Parameters" msgstr "" elektroid-3.2.3/po/en.po000066400000000000000000000324151500236517400150710ustar00rootroot00000000000000# English translations for Elektroid package. # Copyright (C) 2019 David García Goñi # This file is distributed under the same license as the Elektroid package. # David García Goñi , 2019. # msgid "" msgstr "" "Project-Id-Version: elektroid 2.2\n" "Report-Msgid-Bugs-To: dagargo@gmail.com\n" "POT-Creation-Date: 2025-04-22 19:10+0200\n" "PO-Revision-Date: 2020-04-26 13:00+0100\n" "Last-Translator: David García Goñi \n" "Language-Team: English\n" "Language: en\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: src/elektroid.c:236 src/elektroid.c:242 src/editor.c:1309 msgid "Audio" msgstr "" #: src/elektroid.c:326 src/elektroid.c:3005 msgid "Not connected" msgstr "" #: src/elektroid.c:442 msgid "Receiving SysEx" msgstr "" #: src/elektroid.c:466 msgid "Save SysEx" msgstr "" #: src/elektroid.c:467 src/elektroid.c:595 src/elektroid.c:854 #: src/elektroid.c:1418 src/editor.c:1203 src/mactions/microfreak.c:52 #: res/gui.glade:1003 res/gui.glade:3139 res/gui.glade:3245 res/gui.glade:3566 #: res/gui.glade:3652 msgid "_Cancel" msgstr "" #: src/elektroid.c:468 res/gui.glade:3153 res/gui.glade:3259 msgid "_Save" msgstr "" #: src/elektroid.c:472 msgid "Received SysEx" msgstr "" #: src/elektroid.c:477 src/elektroid.c:600 msgid "SysEx Files" msgstr "" #: src/elektroid.c:514 #, c-format msgid "Error while saving “%s”: %s." msgstr "" #: src/elektroid.c:539 #, c-format msgid "Error while loading “%s”: %s." msgstr "" #: src/elektroid.c:593 msgid "Open SysEx" msgstr "" #: src/elektroid.c:596 msgid "_Open" msgstr "" #: src/elektroid.c:612 msgid "Sending SysEx" msgstr "" #: src/elektroid.c:853 msgid "Are you sure you want to delete the selected items?" msgstr "" #: src/elektroid.c:855 msgid "_Delete" msgstr "" #: src/elektroid.c:874 msgid "Deleting Files" msgstr "" #: src/elektroid.c:874 msgid "Deleting..." msgstr "" #: src/elektroid.c:911 res/gui.glade:255 res/gui.glade:891 msgid "Rename" msgstr "" #: src/elektroid.c:935 #, c-format msgid "Error while renaming to “%s”: %s." msgstr "" #: src/elektroid.c:1289 res/gui.glade:1688 res/gui.glade:2132 msgid "Add Directory" msgstr "" #: src/elektroid.c:1297 #, c-format msgid "Error while creating dir “%s”: %s." msgstr "" #: src/elektroid.c:1416 src/editor.c:1200 #, c-format msgid "Replace file “%s”?" msgstr "" #: src/elektroid.c:1419 msgid "_Skip" msgstr "" #: src/elektroid.c:1420 src/editor.c:1204 msgid "_Replace" msgstr "" #: src/elektroid.c:1425 msgid "Apply this action to all files" msgstr "" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2494 msgid "Preparing Tasks" msgstr "" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2495 #: src/progress.c:107 msgid "Waiting..." msgstr "" #: src/elektroid.c:2239 msgid "Connecting to Device" msgstr "" #: src/elektroid.c:2240 msgid "Connecting..." msgstr "" #: src/elektroid.c:2247 #, c-format msgid "Device “%s” not recognized: %s" msgstr "" #: src/elektroid.c:2481 msgid "Moving Files" msgstr "" #: src/elektroid.c:2482 msgid "Moving..." msgstr "" #: src/elektroid.c:2789 msgid "Acknowledgements" msgstr "" #: src/editor.c:1325 msgid "Save Sample" msgstr "" #: src/tasks.c:32 msgid "Queued" msgstr "" #: src/tasks.c:34 msgid "Running" msgstr "" #: src/tasks.c:36 msgid "Completed" msgstr "" #: src/tasks.c:38 msgid "Terminated with errors" msgstr "" #: src/tasks.c:40 msgid "Canceled" msgstr "" #: src/tasks.c:42 src/tasks.c:56 msgid "Undefined" msgstr "" #: src/tasks.c:52 msgid "Upload" msgstr "" #: src/tasks.c:54 msgid "Download" msgstr "" #: src/browser.c:324 msgid "min." msgstr "" #: src/audio_pa.c:337 msgid "Output" msgstr "" #: src/audio_pa.c:340 msgid "Input" msgstr "" #. This should only be translated if a non latin alphabet is used #: src/mactions/autosampler.c:205 res/gui.glade:982 msgid "Auto Sampler" msgstr "" #: src/mactions/autosampler.c:205 msgid "Recording..." msgstr "" #: src/mactions/autosampler.c:282 msgid "_Auto Sampler" msgstr "" #: src/mactions/backend.c:60 msgid "OS _Upgrade" msgstr "" #: src/mactions/backend.c:75 msgid "_Receive SysEx" msgstr "" #: src/mactions/backend.c:90 msgid "_Send SysEx" msgstr "" #: src/mactions/microbrute.c:394 msgid "_Configuration" msgstr "" #: src/mactions/microbrute.c:422 msgid "_Calibration" msgstr "" #: src/mactions/microfreak.c:51 msgid "" "The defragmentation process could take several minutes and could not be " "canceled. Are you sure you want to defragment the sample memory?" msgstr "" #: src/mactions/microfreak.c:53 src/mactions/microfreak.c:85 msgid "_Defragment" msgstr "" #: src/mactions/microfreak.c:66 msgid "Defragmenting Sample Memory" msgstr "" #: src/progress.c:52 msgid "Cancelling..." msgstr "" #: src/progress.c:110 msgid "Sending..." msgstr "" #: src/progress.c:113 msgid "Receiving..." msgstr "" #. TRANSLATORS: Stereo recording #: src/guirecorder.c:68 msgid "Stereo" msgstr "" #. TRANSLATORS: Mono recording from left channel #: src/guirecorder.c:78 msgid "Left" msgstr "" #. TRANSLATORS: Mono recording from right channel #: src/guirecorder.c:85 msgid "Right" msgstr "" #: src/connectors/sds.c:1359 msgid "SDS sampler" msgstr "" #: src/connectors/default.c:84 msgid "MIDI device" msgstr "" #: src/connectors/system.c:670 msgid "System" msgstr "" #: res/gui.glade:104 res/gui.glade:218 res/gui.glade:854 msgid "Play" msgstr "" #: res/gui.glade:119 res/gui.glade:264 res/gui.glade:900 msgid "Delete" msgstr "" #: res/gui.glade:128 msgid "Undo" msgstr "" #: res/gui.glade:143 msgid "Save" msgstr "" #: res/gui.glade:203 msgid "Upload Selection" msgstr "" #: res/gui.glade:233 res/gui.glade:869 msgid "Open With External Editor" msgstr "" #: res/gui.glade:241 res/gui.glade:877 msgid "Show in File Manager" msgstr "" #: res/gui.glade:839 msgid "Download Selection" msgstr "" #: res/gui.glade:945 msgid "Sample and MIDI device manager" msgstr "" #: res/gui.glade:948 msgid "translator-credits" msgstr "David García Goñi " #: res/gui.glade:1017 msgid "_Start" msgstr "" #: res/gui.glade:1077 res/gui.glade:1819 res/gui.glade:2285 res/gui.glade:3184 msgid "Name" msgstr "" #. Audio channels #: res/gui.glade:1103 res/gui.glade:1844 res/gui.glade:2312 res/gui.glade:3701 msgid "Channels" msgstr "" #. Input audio monitor #: res/gui.glade:1134 res/gui.glade:3732 msgid "Monitor" msgstr "" #: res/gui.glade:1159 msgid "Global" msgstr "" #. Press key time #: res/gui.glade:1196 msgctxt "Auto Sampler" msgid "Press" msgstr "" #. As the R in ADSR #: res/gui.glade:1209 msgctxt "Auto Sampler" msgid "Release" msgstr "" #: res/gui.glade:1252 res/gui.glade:1866 res/gui.glade:2336 msgid "Duration" msgstr "" #. Start MIDI key (note) #: res/gui.glade:1301 msgctxt "Auto Sampler" msgid "Start" msgstr "" #. End MIDI key (note) #: res/gui.glade:1333 msgctxt "Auto Sampler" msgid "End" msgstr "" #. Distance between different samples #: res/gui.glade:1365 msgctxt "Auto Sampler" msgid "Distance" msgstr "" #. As in MIDI velocity #: res/gui.glade:1378 msgctxt "Auto Sampler" msgid "Velocity" msgstr "" #. MIDI channel #: res/gui.glade:1421 msgctxt "Auto Sampler" msgid "Channel" msgstr "" #: res/gui.glade:1508 msgid "Show _Remote" msgstr "" #: res/gui.glade:1532 msgid "_Preferences " msgstr "" #: res/gui.glade:1556 msgid "_About" msgstr "" #: res/gui.glade:1667 res/gui.glade:2111 msgid "Go to Parent Directory" msgstr "" #: res/gui.glade:1709 res/gui.glade:2153 msgid "Refresh Directory" msgstr "" #: res/gui.glade:1730 res/gui.glade:2174 msgid "Search" msgstr "" #: res/gui.glade:1833 res/gui.glade:2300 msgid "Format" msgstr "" #: res/gui.glade:1855 res/gui.glade:2324 msgid "MIDI Note" msgstr "" #: res/gui.glade:1877 res/gui.glade:2348 msgid "Rate" msgstr "" #: res/gui.glade:1888 res/gui.glade:2360 msgid "Samples" msgstr "" #: res/gui.glade:1899 res/gui.glade:2372 msgid "Information" msgstr "" #: res/gui.glade:1912 res/gui.glade:2387 msgid "Size" msgstr "" #: res/gui.glade:2008 msgid "Refresh Devices" msgstr "" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2617 msgid "Auto play" msgstr "" #: res/gui.glade:2669 msgid "Grid" msgstr "" #: res/gui.glade:2729 msgid "Playing mix depends on the remote channels" msgstr "" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2731 msgid "" "Mix depending\n" "on remote" msgstr "" #: res/gui.glade:2842 msgid "Status" msgstr "" #: res/gui.glade:2853 msgid "Type" msgstr "" #: res/gui.glade:2874 msgid "Source" msgstr "" #: res/gui.glade:2888 msgid "Destination" msgstr "" #: res/gui.glade:2903 msgid "Progress" msgstr "" #: res/gui.glade:2935 msgid "Cancel Tasks" msgstr "" #: res/gui.glade:2956 msgid "Remove Queued Tasks" msgstr "" #: res/gui.glade:2977 msgid "Clear Finished Tasks" msgstr "" #: res/gui.glade:3224 msgid "Preferences" msgstr "" #: res/gui.glade:3314 msgid "Play sample while loading" msgstr "" #: res/gui.glade:3342 msgid "Buffer length" msgstr "" #: res/gui.glade:3418 msgid "Stop device when connecting" msgstr "" #. Sound is a type of data in Elektron devices so it is better not to translate these words or quote them. #: res/gui.glade:3488 msgid "Load sound and preset tags" msgstr "" #: res/gui.glade:3631 msgid "Record Channels" msgstr "" #: res/gui.glade:3666 msgid "_Record" msgstr "" #: res/microbrute/gui.glade:35 msgid "Calibration assistant" msgstr "" #: res/microbrute/gui.glade:42 msgid "This procedure calibrates the pitch bend and modulation wheels." msgstr "" #: res/microbrute/gui.glade:46 msgid "Start" msgstr "" #: res/microbrute/gui.glade:54 msgid "" "Let the pitch bend wheel rest at the neutral position and click on the next " "button." msgstr "" #: res/microbrute/gui.glade:59 msgid "Step 1" msgstr "" #: res/microbrute/gui.glade:67 msgid "While setting both wheels at the bottom click on the next button." msgstr "" #: res/microbrute/gui.glade:72 msgid "Step 2" msgstr "" #: res/microbrute/gui.glade:80 msgid "While setting both wheels at the top click on the next button." msgstr "" #: res/microbrute/gui.glade:85 msgid "Step 3" msgstr "" #: res/microbrute/gui.glade:93 msgid "Calibration completed" msgstr "" #: res/microbrute/gui.glade:98 msgid "End" msgstr "" #: res/microbrute/gui.glade:117 msgctxt "Gate Length" msgid "Short" msgstr "" #: res/microbrute/gui.glade:121 msgctxt "Gate Length" msgid "Medium" msgstr "" #: res/microbrute/gui.glade:125 msgctxt "Gate Length" msgid "Long" msgstr "" #: res/microbrute/gui.glade:139 msgctxt "Key Priority" msgid "Last" msgstr "" #: res/microbrute/gui.glade:143 msgctxt "Key Priority" msgid "Low" msgstr "" #: res/microbrute/gui.glade:147 msgctxt "Key Priority" msgid "High" msgstr "" #: res/microbrute/gui.glade:161 msgctxt "Play Mode" msgid "Hold" msgstr "" #: res/microbrute/gui.glade:165 msgctxt "Play Mode" msgid "Note On" msgstr "" #: res/microbrute/gui.glade:179 msgctxt "Receive Channel" msgid "Any" msgstr "" #: res/microbrute/gui.glade:257 msgctxt "Sequence Change" msgid "At End" msgstr "" #: res/microbrute/gui.glade:261 msgctxt "Sequence Change" msgid "Instant Reset" msgstr "" #: res/microbrute/gui.glade:265 msgctxt "Sequence Change" msgid "Instant Continuation" msgstr "" #: res/microbrute/gui.glade:279 msgctxt "Sequence Retrigger" msgid "Reset" msgstr "" #: res/microbrute/gui.glade:283 msgctxt "Sequence Retrigger" msgid "Reset But Legato" msgstr "" #: res/microbrute/gui.glade:287 msgctxt "Sequence Retrigger" msgid "None" msgstr "" #: res/microbrute/gui.glade:327 msgctxt "Step On" msgid "Clock" msgstr "" #: res/microbrute/gui.glade:331 msgctxt "Step On" msgid "Gate" msgstr "" #: res/microbrute/gui.glade:345 msgctxt "Synchronization" msgid "Auto" msgstr "" #: res/microbrute/gui.glade:349 msgctxt "Synchronization" msgid "Internal" msgstr "" #: res/microbrute/gui.glade:353 msgctxt "Synchronization" msgid "External" msgstr "" #: res/microbrute/gui.glade:441 msgctxt "Velocity Response" msgid "Linear" msgstr "" #: res/microbrute/gui.glade:445 msgctxt "Velocity Response" msgid "Logarithmic" msgstr "" #: res/microbrute/gui.glade:449 msgctxt "Velocity Response" msgid "Exponential" msgstr "" #: res/microbrute/gui.glade:456 msgid "MicroBrute Configuration" msgstr "" #: res/microbrute/gui.glade:480 msgid "Persistent changes" msgstr "" #: res/microbrute/gui.glade:547 msgid "Transmit Channel" msgstr "" #: res/microbrute/gui.glade:559 msgid "Receive Channel" msgstr "" #: res/microbrute/gui.glade:650 msgid "Key Priority" msgstr "" #: res/microbrute/gui.glade:662 msgid "Velocity Response" msgstr "" #: res/microbrute/gui.glade:715 msgid "Keyboard Parameters" msgstr "" #: res/microbrute/gui.glade:753 msgid "Play Mode" msgstr "" #: res/microbrute/gui.glade:765 msgid "Sequence Retrigger" msgstr "" #: res/microbrute/gui.glade:777 msgid "Sequence Change" msgstr "" #: res/microbrute/gui.glade:789 msgid "Next Step On" msgstr "" #: res/microbrute/gui.glade:801 msgid "Step Length" msgstr "" #: res/microbrute/gui.glade:914 msgid "Sequencer Control" msgstr "" #: res/microbrute/gui.glade:952 msgid "LFO Key Retrigger" msgstr "" #: res/microbrute/gui.glade:964 msgid "Envelope Legato" msgstr "" #: res/microbrute/gui.glade:976 msgid "Bend Range" msgstr "" #: res/microbrute/gui.glade:988 msgid "Gate Length" msgstr "" #: res/microbrute/gui.glade:1000 msgid "Synchronization" msgstr "" #: res/microbrute/gui.glade:1094 msgid "Module Parameters" msgstr "" elektroid-3.2.3/po/es.po000066400000000000000000000401551500236517400150760ustar00rootroot00000000000000# Spanish translations for Elektroid package. # Copyright (C) 2019 David García Goñi # This file is distributed under the same license as the Elektroid package. # David García Goñi , 2019. # msgid "" msgstr "" "Project-Id-Version: elektroid 2.2\n" "Report-Msgid-Bugs-To: dagargo@gmail.com\n" "POT-Creation-Date: 2025-04-22 19:10+0200\n" "PO-Revision-Date: 2020-04-26 13:00+0100\n" "Last-Translator: David García Goñi \n" "Language-Team: Spanish\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: src/elektroid.c:236 src/elektroid.c:242 src/editor.c:1309 msgid "Audio" msgstr "" #: src/elektroid.c:326 src/elektroid.c:3005 msgid "Not connected" msgstr "No conectado" #: src/elektroid.c:442 msgid "Receiving SysEx" msgstr "Recibiendo SysEx" #: src/elektroid.c:466 msgid "Save SysEx" msgstr "Guardar SysEx" #: src/elektroid.c:467 src/elektroid.c:595 src/elektroid.c:854 #: src/elektroid.c:1418 src/editor.c:1203 src/mactions/microfreak.c:52 #: res/gui.glade:1003 res/gui.glade:3139 res/gui.glade:3245 res/gui.glade:3566 #: res/gui.glade:3652 msgid "_Cancel" msgstr "_Cancelar" #: src/elektroid.c:468 res/gui.glade:3153 res/gui.glade:3259 msgid "_Save" msgstr "_Guardar" #: src/elektroid.c:472 msgid "Received SysEx" msgstr "SysEx recibido" #: src/elektroid.c:477 src/elektroid.c:600 msgid "SysEx Files" msgstr "Archivos SysEx" #: src/elektroid.c:514 #, c-format msgid "Error while saving “%s”: %s." msgstr "Error al guardar «%s»: %s." #: src/elektroid.c:539 #, c-format msgid "Error while loading “%s”: %s." msgstr "Error al cargar «%s»: %s." #: src/elektroid.c:593 msgid "Open SysEx" msgstr "Abrir SysEx" #: src/elektroid.c:596 msgid "_Open" msgstr "_Abrir" #: src/elektroid.c:612 msgid "Sending SysEx" msgstr "Enviando SysEx" #: src/elektroid.c:853 msgid "Are you sure you want to delete the selected items?" msgstr "¿Realmente desea eliminar los elementos seleccionados?" #: src/elektroid.c:855 msgid "_Delete" msgstr "_Eliminar" #: src/elektroid.c:874 msgid "Deleting Files" msgstr "Eliminando archivos" #: src/elektroid.c:874 msgid "Deleting..." msgstr "Eliminando..." #: src/elektroid.c:911 res/gui.glade:255 res/gui.glade:891 msgid "Rename" msgstr "Renombrar" #: src/elektroid.c:935 #, c-format msgid "Error while renaming to “%s”: %s." msgstr "Error al renombrar a «%s»: %s." #: src/elektroid.c:1289 res/gui.glade:1688 res/gui.glade:2132 msgid "Add Directory" msgstr "Añadir directorio" #: src/elektroid.c:1297 #, c-format msgid "Error while creating dir “%s”: %s." msgstr "Error al crear el directorio «%s»: %s." #: src/elektroid.c:1416 src/editor.c:1200 #, c-format msgid "Replace file “%s”?" msgstr "¿Reemplazar el archivo «%s»?" #: src/elektroid.c:1419 msgid "_Skip" msgstr "_Omitir" #: src/elektroid.c:1420 src/editor.c:1204 msgid "_Replace" msgstr "_Reemplazar" #: src/elektroid.c:1425 msgid "Apply this action to all files" msgstr "Aplicar esta acción a todos los archivos" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2494 msgid "Preparing Tasks" msgstr "Preparando tareas" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2495 #: src/progress.c:107 msgid "Waiting..." msgstr "Esperando..." #: src/elektroid.c:2239 msgid "Connecting to Device" msgstr "Conectando con el dispositivo" #: src/elektroid.c:2240 msgid "Connecting..." msgstr "Conectando..." #: src/elektroid.c:2247 #, c-format msgid "Device “%s” not recognized: %s" msgstr "Dispositivo «%s» no reconocido: %s" #: src/elektroid.c:2481 msgid "Moving Files" msgstr "Moviendo archivos" #: src/elektroid.c:2482 msgid "Moving..." msgstr "Moviendo..." #: src/elektroid.c:2789 msgid "Acknowledgements" msgstr "" #: src/editor.c:1325 msgid "Save Sample" msgstr "Guardar muestra" #: src/tasks.c:32 msgid "Queued" msgstr "Encolada" #: src/tasks.c:34 msgid "Running" msgstr "Ejecutando" #: src/tasks.c:36 msgid "Completed" msgstr "Completada" #: src/tasks.c:38 msgid "Terminated with errors" msgstr "Terminada con errores" #: src/tasks.c:40 msgid "Canceled" msgstr "Cancelada" #: src/tasks.c:42 src/tasks.c:56 msgid "Undefined" msgstr "Indefinido" #: src/tasks.c:52 msgid "Upload" msgstr "Carga" #: src/tasks.c:54 msgid "Download" msgstr "Descarga" #: src/browser.c:324 msgid "min." msgstr "min." #: src/audio_pa.c:337 msgid "Output" msgstr "Salida" #: src/audio_pa.c:340 msgid "Input" msgstr "Entrada" #. This should only be translated if a non latin alphabet is used #: src/mactions/autosampler.c:205 res/gui.glade:982 msgid "Auto Sampler" msgstr "" #: src/mactions/autosampler.c:205 msgid "Recording..." msgstr "Grabando..." #: src/mactions/autosampler.c:282 msgid "_Auto Sampler" msgstr "" #: src/mactions/backend.c:60 msgid "OS _Upgrade" msgstr "Actualizar _SO" #: src/mactions/backend.c:75 msgid "_Receive SysEx" msgstr "_Recibir SysEx" #: src/mactions/backend.c:90 msgid "_Send SysEx" msgstr "_Enviar SysEx" #: src/mactions/microbrute.c:394 msgid "_Configuration" msgstr "_Configuración" #: src/mactions/microbrute.c:422 msgid "_Calibration" msgstr "_Calibración" #: src/mactions/microfreak.c:51 msgid "" "The defragmentation process could take several minutes and could not be " "canceled. Are you sure you want to defragment the sample memory?" msgstr "" "El proceso de defragmentación podría llevar varios minutos y no se podría " "cancelar. ¿Realmente desea defragmentar la memoria de muestras?" #: src/mactions/microfreak.c:53 src/mactions/microfreak.c:85 msgid "_Defragment" msgstr "_Defragmentar" #: src/mactions/microfreak.c:66 msgid "Defragmenting Sample Memory" msgstr "Defragmentando memoria de muestras" #: src/progress.c:52 msgid "Cancelling..." msgstr "Cancelando..." #: src/progress.c:110 msgid "Sending..." msgstr "Enviando..." #: src/progress.c:113 msgid "Receiving..." msgstr "Recibiendo..." #. TRANSLATORS: Stereo recording #: src/guirecorder.c:68 msgid "Stereo" msgstr "Estéreo" #. TRANSLATORS: Mono recording from left channel #: src/guirecorder.c:78 msgid "Left" msgstr "Izquierdo" #. TRANSLATORS: Mono recording from right channel #: src/guirecorder.c:85 msgid "Right" msgstr "Derecho" #: src/connectors/sds.c:1359 msgid "SDS sampler" msgstr "Sampler SDS" #: src/connectors/default.c:84 msgid "MIDI device" msgstr "Dispositivo MIDI" #: src/connectors/system.c:670 msgid "System" msgstr "Sistema" #: res/gui.glade:104 res/gui.glade:218 res/gui.glade:854 msgid "Play" msgstr "Reproducir" #: res/gui.glade:119 res/gui.glade:264 res/gui.glade:900 msgid "Delete" msgstr "Eliminar" #: res/gui.glade:128 msgid "Undo" msgstr "Deshacer" #: res/gui.glade:143 msgid "Save" msgstr "Guardar" #: res/gui.glade:203 msgid "Upload Selection" msgstr "Cargar selección" #: res/gui.glade:233 res/gui.glade:869 msgid "Open With External Editor" msgstr "Abrir con editor externo" #: res/gui.glade:241 res/gui.glade:877 msgid "Show in File Manager" msgstr "Mostrar en gestor de archivos" #: res/gui.glade:839 msgid "Download Selection" msgstr "Descargar selección" #: res/gui.glade:945 msgid "Sample and MIDI device manager" msgstr "Gestor de muestras y dispositivos MIDI" #: res/gui.glade:948 msgid "translator-credits" msgstr "David García Goñi " #: res/gui.glade:1017 msgid "_Start" msgstr "_Iniciar" #: res/gui.glade:1077 res/gui.glade:1819 res/gui.glade:2285 res/gui.glade:3184 msgid "Name" msgstr "Nombre" #. Audio channels #: res/gui.glade:1103 res/gui.glade:1844 res/gui.glade:2312 res/gui.glade:3701 msgid "Channels" msgstr "Canales" #. Input audio monitor #: res/gui.glade:1134 res/gui.glade:3732 msgid "Monitor" msgstr "" #: res/gui.glade:1159 msgid "Global" msgstr "Global" #. Press key time #: res/gui.glade:1196 msgctxt "Auto Sampler" msgid "Press" msgstr "Pulsación" #. As the R in ADSR #: res/gui.glade:1209 msgctxt "Auto Sampler" msgid "Release" msgstr "Desvanecimiento" #: res/gui.glade:1252 res/gui.glade:1866 res/gui.glade:2336 msgid "Duration" msgstr "Duración" #. Start MIDI key (note) #: res/gui.glade:1301 msgctxt "Auto Sampler" msgid "Start" msgstr "Inicio" #. End MIDI key (note) #: res/gui.glade:1333 msgctxt "Auto Sampler" msgid "End" msgstr "Fin" #. Distance between different samples #: res/gui.glade:1365 msgctxt "Auto Sampler" msgid "Distance" msgstr "Distancia" #. As in MIDI velocity #: res/gui.glade:1378 msgctxt "Auto Sampler" msgid "Velocity" msgstr "Velocidad" #. MIDI channel #: res/gui.glade:1421 msgctxt "Auto Sampler" msgid "Channel" msgstr "Canal" #: res/gui.glade:1508 msgid "Show _Remote" msgstr "Mostrar _remoto" #: res/gui.glade:1532 msgid "_Preferences " msgstr "_Preferencias" #: res/gui.glade:1556 msgid "_About" msgstr "_Acerca de" #: res/gui.glade:1667 res/gui.glade:2111 msgid "Go to Parent Directory" msgstr "Ir al directorio padre" #: res/gui.glade:1709 res/gui.glade:2153 msgid "Refresh Directory" msgstr "Actualizar directorio" #: res/gui.glade:1730 res/gui.glade:2174 msgid "Search" msgstr "Buscar" #: res/gui.glade:1833 res/gui.glade:2300 msgid "Format" msgstr "Formato" #: res/gui.glade:1855 res/gui.glade:2324 msgid "MIDI Note" msgstr "Nota MIDI" #: res/gui.glade:1877 res/gui.glade:2348 msgid "Rate" msgstr "Frecuencia" #: res/gui.glade:1888 res/gui.glade:2360 msgid "Samples" msgstr "Muestras" #: res/gui.glade:1899 res/gui.glade:2372 msgid "Information" msgstr "Información" #: res/gui.glade:1912 res/gui.glade:2387 msgid "Size" msgstr "Tamaño" #: res/gui.glade:2008 msgid "Refresh Devices" msgstr "Actualizar dispositivos" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2617 msgid "Auto play" msgstr "" "Reproducir\n" "automáticamente" #: res/gui.glade:2669 msgid "Grid" msgstr "Rejilla" #: res/gui.glade:2729 msgid "Playing mix depends on the remote channels" msgstr "La mezcla para reproducción depende de los canales del remoto" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2731 msgid "" "Mix depending\n" "on remote" msgstr "" "Mezclar según\n" "el remoto" #: res/gui.glade:2842 msgid "Status" msgstr "Estado" #: res/gui.glade:2853 msgid "Type" msgstr "Tipo" #: res/gui.glade:2874 msgid "Source" msgstr "Origen" #: res/gui.glade:2888 msgid "Destination" msgstr "Destino" #: res/gui.glade:2903 msgid "Progress" msgstr "Progreso" #: res/gui.glade:2935 msgid "Cancel Tasks" msgstr "Cancelar tareas" #: res/gui.glade:2956 msgid "Remove Queued Tasks" msgstr "Eliminar tareas encoladas" #: res/gui.glade:2977 msgid "Clear Finished Tasks" msgstr "Limpiar tareas terminadas" #: res/gui.glade:3224 msgid "Preferences" msgstr "Preferencias" #: res/gui.glade:3314 msgid "Play sample while loading" msgstr "Reproducir muestra durante la carga" #: res/gui.glade:3342 msgid "Buffer length" msgstr "Longitud del buffer" #: res/gui.glade:3418 msgid "Stop device when connecting" msgstr "Parar dispositivo al conectar" #. Sound is a type of data in Elektron devices so it is better not to translate these words or quote them. #: res/gui.glade:3488 msgid "Load sound and preset tags" msgstr "Cargar etiquetas de sonidos y presets" #: res/gui.glade:3631 msgid "Record Channels" msgstr "Canales de grabación" #: res/gui.glade:3666 msgid "_Record" msgstr "_Grabar" #: res/microbrute/gui.glade:35 msgid "Calibration assistant" msgstr "Asistente de calibración" #: res/microbrute/gui.glade:42 msgid "This procedure calibrates the pitch bend and modulation wheels." msgstr "" "Este procedimiento calibra la rueda de inflexión de tono y la rueda de " "modulación." #: res/microbrute/gui.glade:46 msgid "Start" msgstr "Inicio" #: res/microbrute/gui.glade:54 msgid "" "Let the pitch bend wheel rest at the neutral position and click on the next " "button." msgstr "" "Deja la rueda de inflexión de tono en la posición neutral y haz clic en el " "botón de siguiente." #: res/microbrute/gui.glade:59 msgid "Step 1" msgstr "Paso 1" #: res/microbrute/gui.glade:67 msgid "While setting both wheels at the bottom click on the next button." msgstr "" "Mientras mantienes ambas ruedas abajo, haz clic en el botón de siguiente." #: res/microbrute/gui.glade:72 msgid "Step 2" msgstr "Paso 2" #: res/microbrute/gui.glade:80 msgid "While setting both wheels at the top click on the next button." msgstr "" "Mientras mantienes ambas ruedas arriba, haz clic en el botón de siguiente." #: res/microbrute/gui.glade:85 msgid "Step 3" msgstr "Paso 3" #: res/microbrute/gui.glade:93 msgid "Calibration completed" msgstr "Calibración completada" #: res/microbrute/gui.glade:98 msgid "End" msgstr "Fin" #: res/microbrute/gui.glade:117 msgctxt "Gate Length" msgid "Short" msgstr "Corta" #: res/microbrute/gui.glade:121 msgctxt "Gate Length" msgid "Medium" msgstr "Media" #: res/microbrute/gui.glade:125 msgctxt "Gate Length" msgid "Long" msgstr "Larga" #: res/microbrute/gui.glade:139 msgctxt "Key Priority" msgid "Last" msgstr "Última" #: res/microbrute/gui.glade:143 msgctxt "Key Priority" msgid "Low" msgstr "Baja" #: res/microbrute/gui.glade:147 msgctxt "Key Priority" msgid "High" msgstr "Alta" #: res/microbrute/gui.glade:161 msgctxt "Play Mode" msgid "Hold" msgstr "Continua" #: res/microbrute/gui.glade:165 msgctxt "Play Mode" msgid "Note On" msgstr "Al pulsar" #: res/microbrute/gui.glade:179 msgctxt "Receive Channel" msgid "Any" msgstr "Todos" #: res/microbrute/gui.glade:257 msgctxt "Sequence Change" msgid "At End" msgstr "Al final" #: res/microbrute/gui.glade:261 msgctxt "Sequence Change" msgid "Instant Reset" msgstr "Reinicio instantáneo" #: res/microbrute/gui.glade:265 msgctxt "Sequence Change" msgid "Instant Continuation" msgstr "Continuación instantánea" #: res/microbrute/gui.glade:279 msgctxt "Sequence Retrigger" msgid "Reset" msgstr "Reinicio" #: res/microbrute/gui.glade:283 msgctxt "Sequence Retrigger" msgid "Reset But Legato" msgstr "Reinicio excepto en ligado" #: res/microbrute/gui.glade:287 msgctxt "Sequence Retrigger" msgid "None" msgstr "Redisparo de secuencia" #: res/microbrute/gui.glade:327 msgctxt "Step On" msgid "Clock" msgstr "Reloj" #: res/microbrute/gui.glade:331 msgctxt "Step On" msgid "Gate" msgstr "Puerta" #: res/microbrute/gui.glade:345 msgctxt "Synchronization" msgid "Auto" msgstr "Automática" #: res/microbrute/gui.glade:349 msgctxt "Synchronization" msgid "Internal" msgstr "Interna" #: res/microbrute/gui.glade:353 msgctxt "Synchronization" msgid "External" msgstr "Externa" #: res/microbrute/gui.glade:441 msgctxt "Velocity Response" msgid "Linear" msgstr "Lineal" #: res/microbrute/gui.glade:445 msgctxt "Velocity Response" msgid "Logarithmic" msgstr "Logarítmica" #: res/microbrute/gui.glade:449 msgctxt "Velocity Response" msgid "Exponential" msgstr "Exponencial" #: res/microbrute/gui.glade:456 msgid "MicroBrute Configuration" msgstr "Configuración de MicroBrute" #: res/microbrute/gui.glade:480 msgid "Persistent changes" msgstr "Cambios persistentes" #: res/microbrute/gui.glade:547 msgid "Transmit Channel" msgstr "Canal de transmisión" #: res/microbrute/gui.glade:559 msgid "Receive Channel" msgstr "Canal de recepción" #: res/microbrute/gui.glade:650 msgid "Key Priority" msgstr "Prioridad de tecla" #: res/microbrute/gui.glade:662 msgid "Velocity Response" msgstr "Respuesta de velocidad" #: res/microbrute/gui.glade:715 msgid "Keyboard Parameters" msgstr "Parámetros del teclado" #: res/microbrute/gui.glade:753 msgid "Play Mode" msgstr "Mode de reproducción" #: res/microbrute/gui.glade:765 msgid "Sequence Retrigger" msgstr "Redisparo de secuencia" #: res/microbrute/gui.glade:777 msgid "Sequence Change" msgstr "Cambio de secuencia" #: res/microbrute/gui.glade:789 msgid "Next Step On" msgstr "Siguiente paso" #: res/microbrute/gui.glade:801 msgid "Step Length" msgstr "Duración del paso" #: res/microbrute/gui.glade:914 msgid "Sequencer Control" msgstr "Control del secuenciador" #: res/microbrute/gui.glade:952 msgid "LFO Key Retrigger" msgstr "Redisparo del LFO" #: res/microbrute/gui.glade:964 msgid "Envelope Legato" msgstr "Envolvente ligada" #: res/microbrute/gui.glade:976 msgid "Bend Range" msgstr "Inflexión de tono" #: res/microbrute/gui.glade:988 msgid "Gate Length" msgstr "Longitud de la puerta" #: res/microbrute/gui.glade:1000 msgid "Synchronization" msgstr "Sincronización" #: res/microbrute/gui.glade:1094 msgid "Module Parameters" msgstr "Parámetros del módulo" elektroid-3.2.3/po/fr.po000066400000000000000000000407071500236517400151010ustar00rootroot00000000000000# French GUI translation for Elektroid. # Copyright (C) 2019-2024 Olivier Humbert # This file is distributed under the same license as the Elektroid package. # Olivier Humbert , 2019-2024. # msgid "" msgstr "" "Project-Id-Version: elektroid 3.0\n" "Report-Msgid-Bugs-To: dagargo@gmail.com\n" "POT-Creation-Date: 2025-04-22 19:10+0200\n" "PO-Revision-Date: 2024-09-21 11:57+0100\n" "Last-Translator: Olivier Humbert \n" "Language-Team: French\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: src/elektroid.c:236 src/elektroid.c:242 src/editor.c:1309 msgid "Audio" msgstr "" #: src/elektroid.c:326 src/elektroid.c:3005 msgid "Not connected" msgstr "Non connecté" #: src/elektroid.c:442 msgid "Receiving SysEx" msgstr "Réception de SysEx" #: src/elektroid.c:466 msgid "Save SysEx" msgstr "Sauvegarde de SysEx" #: src/elektroid.c:467 src/elektroid.c:595 src/elektroid.c:854 #: src/elektroid.c:1418 src/editor.c:1203 src/mactions/microfreak.c:52 #: res/gui.glade:1003 res/gui.glade:3139 res/gui.glade:3245 res/gui.glade:3566 #: res/gui.glade:3652 msgid "_Cancel" msgstr "_Annuler" #: src/elektroid.c:468 res/gui.glade:3153 res/gui.glade:3259 msgid "_Save" msgstr "_Sauvegarder" #: src/elektroid.c:472 msgid "Received SysEx" msgstr "SysEx reçu" #: src/elektroid.c:477 src/elektroid.c:600 msgid "SysEx Files" msgstr "Fichiers SysEx" #: src/elektroid.c:514 #, c-format msgid "Error while saving “%s”: %s." msgstr "Erreur lors de la sauvegarde de « %s » : %s." #: src/elektroid.c:539 #, c-format msgid "Error while loading “%s”: %s." msgstr "Erreur lors du chargement de « %s » : %s." #: src/elektroid.c:593 msgid "Open SysEx" msgstr "Ouvrir SysEx" #: src/elektroid.c:596 msgid "_Open" msgstr "_Ouvrir" #: src/elektroid.c:612 msgid "Sending SysEx" msgstr "Envoi SysEx" #: src/elektroid.c:853 msgid "Are you sure you want to delete the selected items?" msgstr "Souhaitez-vous vraiment supprimer les éléments sélectionnés ?" #: src/elektroid.c:855 msgid "_Delete" msgstr "_Supprimer" #: src/elektroid.c:874 msgid "Deleting Files" msgstr "Suppression des fichiers" #: src/elektroid.c:874 msgid "Deleting..." msgstr "Suppression..." #: src/elektroid.c:911 res/gui.glade:255 res/gui.glade:891 msgid "Rename" msgstr "Renommer" #: src/elektroid.c:935 #, c-format msgid "Error while renaming to “%s”: %s." msgstr "Erreur lors du renommage de « %s » : %s." #: src/elektroid.c:1289 res/gui.glade:1688 res/gui.glade:2132 msgid "Add Directory" msgstr "Ajout d'un répertoire" #: src/elektroid.c:1297 #, c-format msgid "Error while creating dir “%s”: %s." msgstr "Erreur lors de la création du répertoire « %s » : %s." #: src/elektroid.c:1416 src/editor.c:1200 #, c-format msgid "Replace file “%s”?" msgstr "Remplacer le fichier “%s”?" #: src/elektroid.c:1419 msgid "_Skip" msgstr "Pa_sser" #: src/elektroid.c:1420 src/editor.c:1204 msgid "_Replace" msgstr "_Remplacer" #: src/elektroid.c:1425 msgid "Apply this action to all files" msgstr "Appliquer cette action à tous les fichiers" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2494 msgid "Preparing Tasks" msgstr "Préparation des tâches" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2495 #: src/progress.c:107 msgid "Waiting..." msgstr "En attente..." #: src/elektroid.c:2239 msgid "Connecting to Device" msgstr "Connexion au périphérique" #: src/elektroid.c:2240 msgid "Connecting..." msgstr "Connexion..." #: src/elektroid.c:2247 #, c-format msgid "Device “%s” not recognized: %s" msgstr "Périphérique “%s” non reconnu : %s" #: src/elektroid.c:2481 msgid "Moving Files" msgstr "Déplacement des fichiers" #: src/elektroid.c:2482 msgid "Moving..." msgstr "Déplacement..." #: src/elektroid.c:2789 msgid "Acknowledgements" msgstr "" #: src/editor.c:1325 msgid "Save Sample" msgstr "Sauvegarde d'échantillon" #: src/tasks.c:32 msgid "Queued" msgstr "Mise en file d'attente" #: src/tasks.c:34 msgid "Running" msgstr "En cours" #: src/tasks.c:36 msgid "Completed" msgstr "Terminé" #: src/tasks.c:38 msgid "Terminated with errors" msgstr "Terminé avec des erreurs" #: src/tasks.c:40 msgid "Canceled" msgstr "Annulé" #: src/tasks.c:42 src/tasks.c:56 msgid "Undefined" msgstr "Indéfini" #: src/tasks.c:52 msgid "Upload" msgstr "Téléversement" #: src/tasks.c:54 msgid "Download" msgstr "Téléchargement" #: src/browser.c:324 msgid "min." msgstr "min." #: src/audio_pa.c:337 msgid "Output" msgstr "Sortie" #: src/audio_pa.c:340 msgid "Input" msgstr "Entrée" #. This should only be translated if a non latin alphabet is used #: src/mactions/autosampler.c:205 res/gui.glade:982 msgid "Auto Sampler" msgstr "" #: src/mactions/autosampler.c:205 msgid "Recording..." msgstr "Enregistre..." #: src/mactions/autosampler.c:282 msgid "_Auto Sampler" msgstr "Échantillonneur _automatique" #: src/mactions/backend.c:60 msgid "OS _Upgrade" msgstr "Mise à jo_ur SE" #: src/mactions/backend.c:75 msgid "_Receive SysEx" msgstr "_Réception de SysEx" #: src/mactions/backend.c:90 msgid "_Send SysEx" msgstr "Envoi de _Sysex" #: src/mactions/microbrute.c:394 msgid "_Configuration" msgstr "_Configuration" #: src/mactions/microbrute.c:422 msgid "_Calibration" msgstr "_Calibration" #: src/mactions/microfreak.c:51 msgid "" "The defragmentation process could take several minutes and could not be " "canceled. Are you sure you want to defragment the sample memory?" msgstr "" "Le processus de défragmentation peut prendre plusieurs minutes et ne peut " "pas être annulé. Êtes-vous sûr de vouloir défragmenter la mémoire de " "l'échantillon ?" #: src/mactions/microfreak.c:53 src/mactions/microfreak.c:85 msgid "_Defragment" msgstr "_Défragmentation" #: src/mactions/microfreak.c:66 msgid "Defragmenting Sample Memory" msgstr "Défragmentation de la mémoire des échantillons" #: src/progress.c:52 msgid "Cancelling..." msgstr "Annulation..." #: src/progress.c:110 msgid "Sending..." msgstr "Envoi en cours..." #: src/progress.c:113 msgid "Receiving..." msgstr "Réception en cours..." #. TRANSLATORS: Stereo recording #: src/guirecorder.c:68 msgid "Stereo" msgstr "Stéréo" #. TRANSLATORS: Mono recording from left channel #: src/guirecorder.c:78 msgid "Left" msgstr "Gauche" #. TRANSLATORS: Mono recording from right channel #: src/guirecorder.c:85 msgid "Right" msgstr "Droite" #: src/connectors/sds.c:1359 msgid "SDS sampler" msgstr "Échantillonneur SDS" #: src/connectors/default.c:84 msgid "MIDI device" msgstr "Périphérique MIDI" #: src/connectors/system.c:670 msgid "System" msgstr "Système" #: res/gui.glade:104 res/gui.glade:218 res/gui.glade:854 msgid "Play" msgstr "Lecture" #: res/gui.glade:119 res/gui.glade:264 res/gui.glade:900 msgid "Delete" msgstr "Supprimer" #: res/gui.glade:128 msgid "Undo" msgstr "Défaire" #: res/gui.glade:143 msgid "Save" msgstr "Sauvegarder" #: res/gui.glade:203 msgid "Upload Selection" msgstr "Téléversement de la sélection" #: res/gui.glade:233 res/gui.glade:869 msgid "Open With External Editor" msgstr "Ouvrir avec un éditeur externe" #: res/gui.glade:241 res/gui.glade:877 msgid "Show in File Manager" msgstr "Afficher dans un ge_stionnaire de fichier" #: res/gui.glade:839 msgid "Download Selection" msgstr "Téléchargement de la sélection" #: res/gui.glade:945 msgid "Sample and MIDI device manager" msgstr "Gestionnaire d'échantillons et de périphériques MIDI" #: res/gui.glade:948 msgid "translator-credits" msgstr "Olivier Humbert " #: res/gui.glade:1017 msgid "_Start" msgstr "_Démarrage" #: res/gui.glade:1077 res/gui.glade:1819 res/gui.glade:2285 res/gui.glade:3184 msgid "Name" msgstr "Nom" #. Audio channels #: res/gui.glade:1103 res/gui.glade:1844 res/gui.glade:2312 res/gui.glade:3701 msgid "Channels" msgstr "Canaux" #. Input audio monitor #: res/gui.glade:1134 res/gui.glade:3732 msgid "Monitor" msgstr "Moniteur" #: res/gui.glade:1159 msgid "Global" msgstr "" #. Press key time #: res/gui.glade:1196 msgctxt "Auto Sampler" msgid "Press" msgstr "Appui" #. As the R in ADSR #: res/gui.glade:1209 msgctxt "Auto Sampler" msgid "Release" msgstr "Relâche" #: res/gui.glade:1252 res/gui.glade:1866 res/gui.glade:2336 msgid "Duration" msgstr "Durée" #. Start MIDI key (note) #: res/gui.glade:1301 msgctxt "Auto Sampler" msgid "Start" msgstr "Démarrer" #. End MIDI key (note) #: res/gui.glade:1333 msgctxt "Auto Sampler" msgid "End" msgstr "Fin" #. Distance between different samples #: res/gui.glade:1365 msgctxt "Auto Sampler" msgid "Distance" msgstr "" #. As in MIDI velocity #: res/gui.glade:1378 msgctxt "Auto Sampler" msgid "Velocity" msgstr "Vélocité" #. MIDI channel #: res/gui.glade:1421 msgctxt "Auto Sampler" msgid "Channel" msgstr "Canal" #: res/gui.glade:1508 msgid "Show _Remote" msgstr "A_ffichage distant" #: res/gui.glade:1532 msgid "_Preferences " msgstr "_Préférences " #: res/gui.glade:1556 msgid "_About" msgstr "À _propos" #: res/gui.glade:1667 res/gui.glade:2111 msgid "Go to Parent Directory" msgstr "Aller au répertoire parent" #: res/gui.glade:1709 res/gui.glade:2153 msgid "Refresh Directory" msgstr "Rafraîchir le répertoire" #: res/gui.glade:1730 res/gui.glade:2174 msgid "Search" msgstr "Recherche" #: res/gui.glade:1833 res/gui.glade:2300 msgid "Format" msgstr "" #: res/gui.glade:1855 res/gui.glade:2324 msgid "MIDI Note" msgstr "Note MIDI" #: res/gui.glade:1877 res/gui.glade:2348 msgid "Rate" msgstr "Taux" #: res/gui.glade:1888 res/gui.glade:2360 msgid "Samples" msgstr "Échantillons" #: res/gui.glade:1899 res/gui.glade:2372 msgid "Information" msgstr "Informations" #: res/gui.glade:1912 res/gui.glade:2387 msgid "Size" msgstr "Taille" #: res/gui.glade:2008 msgid "Refresh Devices" msgstr "Rafraîchir les périphériques" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2617 msgid "Auto play" msgstr "" "Lecture\n" "automatique" #: res/gui.glade:2669 msgid "Grid" msgstr "Grille" #: res/gui.glade:2729 msgid "Playing mix depends on the remote channels" msgstr "Le mixage de lecture dépend des canaux de destination" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2731 msgid "" "Mix depending\n" "on remote" msgstr "" "Mélange selon\n" "la destination" #: res/gui.glade:2842 msgid "Status" msgstr "État" #: res/gui.glade:2853 msgid "Type" msgstr "Type" #: res/gui.glade:2874 msgid "Source" msgstr "Source" #: res/gui.glade:2888 msgid "Destination" msgstr "Destination" #: res/gui.glade:2903 msgid "Progress" msgstr "Progrès" #: res/gui.glade:2935 msgid "Cancel Tasks" msgstr "Annuler les tâches" #: res/gui.glade:2956 msgid "Remove Queued Tasks" msgstr "Supprimer les tâches dans la file d'attente" #: res/gui.glade:2977 msgid "Clear Finished Tasks" msgstr "Nettoyer les tâches terminées" #: res/gui.glade:3224 msgid "Preferences" msgstr "Préférences" #: res/gui.glade:3314 msgid "Play sample while loading" msgstr "Lecture de l'échantillon pendant le chargement" #: res/gui.glade:3342 msgid "Buffer length" msgstr "Taille du tampon" #: res/gui.glade:3418 msgid "Stop device when connecting" msgstr "Arrêter le périphérique lors de la connexion" #. Sound is a type of data in Elektron devices so it is better not to translate these words or quote them. #: res/gui.glade:3488 msgid "Load sound and preset tags" msgstr "Charger des tags de sons et de préréglages" #: res/gui.glade:3631 msgid "Record Channels" msgstr "Canaux enregistrés" #: res/gui.glade:3666 msgid "_Record" msgstr "E_nregistrement" #: res/microbrute/gui.glade:35 msgid "Calibration assistant" msgstr "Assistant de calibration" #: res/microbrute/gui.glade:42 msgid "This procedure calibrates the pitch bend and modulation wheels." msgstr "" "Cette procédure permet de calibrer les roues de pitch bend et de modulation." #: res/microbrute/gui.glade:46 msgid "Start" msgstr "Démarrer" #: res/microbrute/gui.glade:54 msgid "" "Let the pitch bend wheel rest at the neutral position and click on the next " "button." msgstr "" "Laisser la roulette de bend reposer en position neutre et cliquer sur le " "bouton suivant" #: res/microbrute/gui.glade:59 msgid "Step 1" msgstr "Étape 1" #: res/microbrute/gui.glade:67 msgid "While setting both wheels at the bottom click on the next button." msgstr "En réglant les deux roulettes en bas, cliquez sur le bouton suivant" #: res/microbrute/gui.glade:72 msgid "Step 2" msgstr "Étape 2" #: res/microbrute/gui.glade:80 msgid "While setting both wheels at the top click on the next button." msgstr "En réglant les deux roulettes en haut, cliquez sur le bouton suivant" #: res/microbrute/gui.glade:85 msgid "Step 3" msgstr "Étape 3" #: res/microbrute/gui.glade:93 msgid "Calibration completed" msgstr "Calibration complétée" #: res/microbrute/gui.glade:98 msgid "End" msgstr "Fin" #: res/microbrute/gui.glade:117 msgctxt "Gate Length" msgid "Short" msgstr "Court" #: res/microbrute/gui.glade:121 msgctxt "Gate Length" msgid "Medium" msgstr "Médium" #: res/microbrute/gui.glade:125 msgctxt "Gate Length" msgid "Long" msgstr "Long" #: res/microbrute/gui.glade:139 msgctxt "Key Priority" msgid "Last" msgstr "Dernier" #: res/microbrute/gui.glade:143 msgctxt "Key Priority" msgid "Low" msgstr "Bas" #: res/microbrute/gui.glade:147 msgctxt "Key Priority" msgid "High" msgstr "Haut" #: res/microbrute/gui.glade:161 msgctxt "Play Mode" msgid "Hold" msgstr "Maintien" #: res/microbrute/gui.glade:165 msgctxt "Play Mode" msgid "Note On" msgstr "Note on" #: res/microbrute/gui.glade:179 msgctxt "Receive Channel" msgid "Any" msgstr "Tous" #: res/microbrute/gui.glade:257 msgctxt "Sequence Change" msgid "At End" msgstr "À la fin" #: res/microbrute/gui.glade:261 msgctxt "Sequence Change" msgid "Instant Reset" msgstr "Réinitialisation instantanée" #: res/microbrute/gui.glade:265 msgctxt "Sequence Change" msgid "Instant Continuation" msgstr "Continuation instantanée" #: res/microbrute/gui.glade:279 msgctxt "Sequence Retrigger" msgid "Reset" msgstr "Réinitialisation" #: res/microbrute/gui.glade:283 msgctxt "Sequence Retrigger" msgid "Reset But Legato" msgstr "Réinitialisation sauf le légato" #: res/microbrute/gui.glade:287 msgctxt "Sequence Retrigger" msgid "None" msgstr "Aucun" #: res/microbrute/gui.glade:327 msgctxt "Step On" msgid "Clock" msgstr "Horloge" #: res/microbrute/gui.glade:331 msgctxt "Step On" msgid "Gate" msgstr "Gate" #: res/microbrute/gui.glade:345 msgctxt "Synchronization" msgid "Auto" msgstr "Auto" #: res/microbrute/gui.glade:349 msgctxt "Synchronization" msgid "Internal" msgstr "Interne" #: res/microbrute/gui.glade:353 msgctxt "Synchronization" msgid "External" msgstr "Externe" #: res/microbrute/gui.glade:441 msgctxt "Velocity Response" msgid "Linear" msgstr "Linéaire" #: res/microbrute/gui.glade:445 msgctxt "Velocity Response" msgid "Logarithmic" msgstr "Logarítmique" #: res/microbrute/gui.glade:449 msgctxt "Velocity Response" msgid "Exponential" msgstr "Exponentiel" #: res/microbrute/gui.glade:456 msgid "MicroBrute Configuration" msgstr "Contiguration du MicroBrute" #: res/microbrute/gui.glade:480 msgid "Persistent changes" msgstr "Changements persistants" #: res/microbrute/gui.glade:547 msgid "Transmit Channel" msgstr "Canal de transmission" #: res/microbrute/gui.glade:559 msgid "Receive Channel" msgstr "Canal de réception" #: res/microbrute/gui.glade:650 msgid "Key Priority" msgstr "Priorité de note" #: res/microbrute/gui.glade:662 msgid "Velocity Response" msgstr "Réponse de vélocité" #: res/microbrute/gui.glade:715 msgid "Keyboard Parameters" msgstr "Paramètres du clavier" #: res/microbrute/gui.glade:753 msgid "Play Mode" msgstr "Mode de lecture" #: res/microbrute/gui.glade:765 msgid "Sequence Retrigger" msgstr "Déclencheur de séquence" #: res/microbrute/gui.glade:777 msgid "Sequence Change" msgstr "Changement de séquence" #: res/microbrute/gui.glade:789 msgid "Next Step On" msgstr "Pas suivante on" #: res/microbrute/gui.glade:801 msgid "Step Length" msgstr "Durée du pas" #: res/microbrute/gui.glade:914 msgid "Sequencer Control" msgstr "Contrôle de séquence" #: res/microbrute/gui.glade:952 msgid "LFO Key Retrigger" msgstr "Déclencheur de clé LFO" #: res/microbrute/gui.glade:964 msgid "Envelope Legato" msgstr "Enveloppe Légato" #: res/microbrute/gui.glade:976 msgid "Bend Range" msgstr "Plage de courbure" #: res/microbrute/gui.glade:988 msgid "Gate Length" msgstr "Durée de gate" #: res/microbrute/gui.glade:1000 msgid "Synchronization" msgstr "Synchronisation" #: res/microbrute/gui.glade:1094 msgid "Module Parameters" msgstr "Paramètre du module" elektroid-3.2.3/po/pt_BR.po000066400000000000000000000371231500236517400154760ustar00rootroot00000000000000# elektroid Brazilian Portuguese translation # Copyright (C) 2021 David García Goñi # This file is distributed under the same license as the elektroid package. # Gustavo Costa , 2021. # msgid "" msgstr "" "Project-Id-Version: elektroid 2.2\n" "Report-Msgid-Bugs-To: dagargo@gmail.com\n" "POT-Creation-Date: 2025-04-22 19:10+0200\n" "PO-Revision-Date: 2023-03-26 11:30-0300\n" "Last-Translator: Gustavo Costa \n" "Language-Team: \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 3.2.2\n" #: src/elektroid.c:236 src/elektroid.c:242 src/editor.c:1309 msgid "Audio" msgstr "" #: src/elektroid.c:326 src/elektroid.c:3005 msgid "Not connected" msgstr "Não conectado" #: src/elektroid.c:442 #, fuzzy msgid "Receiving SysEx" msgstr "Receber SysEx" #: src/elektroid.c:466 msgid "Save SysEx" msgstr "Salvar SysEx" #: src/elektroid.c:467 src/elektroid.c:595 src/elektroid.c:854 #: src/elektroid.c:1418 src/editor.c:1203 src/mactions/microfreak.c:52 #: res/gui.glade:1003 res/gui.glade:3139 res/gui.glade:3245 res/gui.glade:3566 #: res/gui.glade:3652 msgid "_Cancel" msgstr "_Cancelar" #: src/elektroid.c:468 res/gui.glade:3153 res/gui.glade:3259 msgid "_Save" msgstr "_Salvar" #: src/elektroid.c:472 msgid "Received SysEx" msgstr "SysEx recebido" #: src/elektroid.c:477 src/elektroid.c:600 msgid "SysEx Files" msgstr "Arquivos SysEx" #: src/elektroid.c:514 #, c-format msgid "Error while saving “%s”: %s." msgstr "Erro ao salvar \"%s\": %s." #: src/elektroid.c:539 #, c-format msgid "Error while loading “%s”: %s." msgstr "Erro ao carregar \"%s\": %s." #: src/elektroid.c:593 msgid "Open SysEx" msgstr "Abrir SysEx" #: src/elektroid.c:596 msgid "_Open" msgstr "_Abrir" #: src/elektroid.c:612 msgid "Sending SysEx" msgstr "Enviando SysEx" #: src/elektroid.c:853 msgid "Are you sure you want to delete the selected items?" msgstr "Tem certeza de que deseja excluir os itens selecionados?" #: src/elektroid.c:855 msgid "_Delete" msgstr "_Excluir" #: src/elektroid.c:874 msgid "Deleting Files" msgstr "Excluindo arquivos" #: src/elektroid.c:874 msgid "Deleting..." msgstr "Excluindo..." #: src/elektroid.c:911 res/gui.glade:255 res/gui.glade:891 msgid "Rename" msgstr "Renomar" #: src/elektroid.c:935 #, c-format msgid "Error while renaming to “%s”: %s." msgstr "Erro ao renomear para \"%s\": %s." #: src/elektroid.c:1289 res/gui.glade:1688 res/gui.glade:2132 msgid "Add Directory" msgstr "Adicionar diretório" #: src/elektroid.c:1297 #, c-format msgid "Error while creating dir “%s”: %s." msgstr "Erro ao criar diretório \"%s\": %s." #: src/elektroid.c:1416 src/editor.c:1200 #, c-format msgid "Replace file “%s”?" msgstr "Substituir o arquivo \"%s\"?" #: src/elektroid.c:1419 msgid "_Skip" msgstr "_Pular" #: src/elektroid.c:1420 src/editor.c:1204 msgid "_Replace" msgstr "_Substituir" #: src/elektroid.c:1425 msgid "Apply this action to all files" msgstr "Aplicar esta ação a todos os arquivos" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2494 msgid "Preparing Tasks" msgstr "Preparando tarefas" #: src/elektroid.c:1686 src/elektroid.c:1868 src/elektroid.c:2495 #: src/progress.c:107 msgid "Waiting..." msgstr "Esperando..." #: src/elektroid.c:2239 msgid "Connecting to Device" msgstr "Conectando ao dispositivo" #: src/elektroid.c:2240 msgid "Connecting..." msgstr "Conectando..." #: src/elektroid.c:2247 #, c-format msgid "Device “%s” not recognized: %s" msgstr "Dispositivo \"%s\" não reconhecido: %s" #: src/elektroid.c:2481 msgid "Moving Files" msgstr "Movendo arquivos" #: src/elektroid.c:2482 msgid "Moving..." msgstr "Movendo..." #: src/elektroid.c:2789 msgid "Acknowledgements" msgstr "" #: src/editor.c:1325 msgid "Save Sample" msgstr "Salvar amostra" #: src/tasks.c:32 msgid "Queued" msgstr "Na fila" #: src/tasks.c:34 msgid "Running" msgstr "Executando" #: src/tasks.c:36 msgid "Completed" msgstr "Completado" #: src/tasks.c:38 msgid "Terminated with errors" msgstr "Encerrado com erros" #: src/tasks.c:40 msgid "Canceled" msgstr "Cancelado" #: src/tasks.c:42 src/tasks.c:56 msgid "Undefined" msgstr "Indefinido" #: src/tasks.c:52 msgid "Upload" msgstr "Upload" #: src/tasks.c:54 msgid "Download" msgstr "Download" #: src/browser.c:324 msgid "min." msgstr "min." #: src/audio_pa.c:337 msgid "Output" msgstr "" #: src/audio_pa.c:340 msgid "Input" msgstr "" #. This should only be translated if a non latin alphabet is used #: src/mactions/autosampler.c:205 res/gui.glade:982 msgid "Auto Sampler" msgstr "" #: src/mactions/autosampler.c:205 msgid "Recording..." msgstr "" #: src/mactions/autosampler.c:282 msgid "_Auto Sampler" msgstr "" #: src/mactions/backend.c:60 msgid "OS _Upgrade" msgstr "Atualizar _OS" #: src/mactions/backend.c:75 msgid "_Receive SysEx" msgstr "_Receber SysEx" #: src/mactions/backend.c:90 msgid "_Send SysEx" msgstr "_Enviar SysEx" #: src/mactions/microbrute.c:394 msgid "_Configuration" msgstr "_Configuração" #: src/mactions/microbrute.c:422 msgid "_Calibration" msgstr "_Calibração" #: src/mactions/microfreak.c:51 msgid "" "The defragmentation process could take several minutes and could not be " "canceled. Are you sure you want to defragment the sample memory?" msgstr "" #: src/mactions/microfreak.c:53 src/mactions/microfreak.c:85 msgid "_Defragment" msgstr "" #: src/mactions/microfreak.c:66 msgid "Defragmenting Sample Memory" msgstr "" #: src/progress.c:52 msgid "Cancelling..." msgstr "Cancelando..." #: src/progress.c:110 msgid "Sending..." msgstr "Enviando..." #: src/progress.c:113 msgid "Receiving..." msgstr "Recebendo..." #. TRANSLATORS: Stereo recording #: src/guirecorder.c:68 msgid "Stereo" msgstr "" #. TRANSLATORS: Mono recording from left channel #: src/guirecorder.c:78 msgid "Left" msgstr "" #. TRANSLATORS: Mono recording from right channel #: src/guirecorder.c:85 msgid "Right" msgstr "" #: src/connectors/sds.c:1359 msgid "SDS sampler" msgstr "Sampler SDS" #: src/connectors/default.c:84 msgid "MIDI device" msgstr "Dispositivo MIDI" #: src/connectors/system.c:670 msgid "System" msgstr "Sistema" #: res/gui.glade:104 res/gui.glade:218 res/gui.glade:854 msgid "Play" msgstr "Reproduzir" #: res/gui.glade:119 res/gui.glade:264 res/gui.glade:900 msgid "Delete" msgstr "Excluir" #: res/gui.glade:128 msgid "Undo" msgstr "Desfazer" #: res/gui.glade:143 msgid "Save" msgstr "Salvar" #: res/gui.glade:203 msgid "Upload Selection" msgstr "Seleção de upload" #: res/gui.glade:233 res/gui.glade:869 msgid "Open With External Editor" msgstr "Abrir com um editor externo" #: res/gui.glade:241 res/gui.glade:877 msgid "Show in File Manager" msgstr "Mostrar no gerenciador de arquivos" #: res/gui.glade:839 msgid "Download Selection" msgstr "Seleção de download" #: res/gui.glade:945 msgid "Sample and MIDI device manager" msgstr "Gerenciador de amostras e dispositivos MIDI" #: res/gui.glade:948 msgid "translator-credits" msgstr "Gustavo Costa " #: res/gui.glade:1017 msgid "_Start" msgstr "" #: res/gui.glade:1077 res/gui.glade:1819 res/gui.glade:2285 res/gui.glade:3184 msgid "Name" msgstr "Nome" #. Audio channels #: res/gui.glade:1103 res/gui.glade:1844 res/gui.glade:2312 res/gui.glade:3701 msgid "Channels" msgstr "Canais" #. Input audio monitor #: res/gui.glade:1134 res/gui.glade:3732 msgid "Monitor" msgstr "" #: res/gui.glade:1159 msgid "Global" msgstr "" #. Press key time #: res/gui.glade:1196 msgctxt "Auto Sampler" msgid "Press" msgstr "" #. As the R in ADSR #: res/gui.glade:1209 msgctxt "Auto Sampler" msgid "Release" msgstr "" #: res/gui.glade:1252 res/gui.glade:1866 res/gui.glade:2336 msgid "Duration" msgstr "Duração" #. Start MIDI key (note) #: res/gui.glade:1301 msgctxt "Auto Sampler" msgid "Start" msgstr "Começo" #. End MIDI key (note) #: res/gui.glade:1333 msgctxt "Auto Sampler" msgid "End" msgstr "Fim" #. Distance between different samples #: res/gui.glade:1365 msgctxt "Auto Sampler" msgid "Distance" msgstr "" #. As in MIDI velocity #: res/gui.glade:1378 msgctxt "Auto Sampler" msgid "Velocity" msgstr "Velocidade" #. MIDI channel #: res/gui.glade:1421 #, fuzzy msgctxt "Auto Sampler" msgid "Channel" msgstr "Canais" #: res/gui.glade:1508 msgid "Show _Remote" msgstr "" #: res/gui.glade:1532 msgid "_Preferences " msgstr "" #: res/gui.glade:1556 msgid "_About" msgstr "_Sobre" #: res/gui.glade:1667 res/gui.glade:2111 msgid "Go to Parent Directory" msgstr "Ir para o diretório pai" #: res/gui.glade:1709 res/gui.glade:2153 msgid "Refresh Directory" msgstr "Atualizar diretório" #: res/gui.glade:1730 res/gui.glade:2174 msgid "Search" msgstr "" #: res/gui.glade:1833 res/gui.glade:2300 msgid "Format" msgstr "" #: res/gui.glade:1855 res/gui.glade:2324 msgid "MIDI Note" msgstr "" #: res/gui.glade:1877 res/gui.glade:2348 msgid "Rate" msgstr "Taxa" #: res/gui.glade:1888 res/gui.glade:2360 msgid "Samples" msgstr "Amostras" #: res/gui.glade:1899 res/gui.glade:2372 msgid "Information" msgstr "" #: res/gui.glade:1912 res/gui.glade:2387 msgid "Size" msgstr "Tamanho" #: res/gui.glade:2008 msgid "Refresh Devices" msgstr "Atualizar dispositivos" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2617 msgid "Auto play" msgstr "" "Reprodução\n" "automática" #: res/gui.glade:2669 msgid "Grid" msgstr "" #: res/gui.glade:2729 msgid "Playing mix depends on the remote channels" msgstr "A reprodução da mixagem depende dos canais remotos" #. It is recommended to split the text in two lines if it is too long #: res/gui.glade:2731 msgid "" "Mix depending\n" "on remote" msgstr "" "Mixagem dependendo\n" "do destino" #: res/gui.glade:2842 msgid "Status" msgstr "Status" #: res/gui.glade:2853 msgid "Type" msgstr "Tipo" #: res/gui.glade:2874 msgid "Source" msgstr "Origem" #: res/gui.glade:2888 msgid "Destination" msgstr "Destino" #: res/gui.glade:2903 msgid "Progress" msgstr "Progresso" #: res/gui.glade:2935 msgid "Cancel Tasks" msgstr "Cancelar tarefas" #: res/gui.glade:2956 msgid "Remove Queued Tasks" msgstr "Remover tarefas em fila" #: res/gui.glade:2977 msgid "Clear Finished Tasks" msgstr "Limpar tarefas concluídas" #: res/gui.glade:3224 msgid "Preferences" msgstr "" #: res/gui.glade:3314 msgid "Play sample while loading" msgstr "" #: res/gui.glade:3342 msgid "Buffer length" msgstr "" #: res/gui.glade:3418 msgid "Stop device when connecting" msgstr "" #. Sound is a type of data in Elektron devices so it is better not to translate these words or quote them. #: res/gui.glade:3488 msgid "Load sound and preset tags" msgstr "" #: res/gui.glade:3631 msgid "Record Channels" msgstr "" #: res/gui.glade:3666 msgid "_Record" msgstr "" #: res/microbrute/gui.glade:35 msgid "Calibration assistant" msgstr "Assistente de calibração" #: res/microbrute/gui.glade:42 msgid "This procedure calibrates the pitch bend and modulation wheels." msgstr "Este procedimento calibra os controles de pitch bend e modulação." #: res/microbrute/gui.glade:46 msgid "Start" msgstr "Começo" #: res/microbrute/gui.glade:54 msgid "" "Let the pitch bend wheel rest at the neutral position and click on the next " "button." msgstr "" "Deixe o controle de pitch bend na posição neutra e clique no próximo botão." #: res/microbrute/gui.glade:59 msgid "Step 1" msgstr "Passo 1" #: res/microbrute/gui.glade:67 msgid "While setting both wheels at the bottom click on the next button." msgstr "" "Ao posicionar ambos os controles na posição mais baixa, clique no próximo " "botão." #: res/microbrute/gui.glade:72 msgid "Step 2" msgstr "Passo 2" #: res/microbrute/gui.glade:80 msgid "While setting both wheels at the top click on the next button." msgstr "" "Ao posicionar ambos os controles na posição mais alta, clique no próximo " "botão." #: res/microbrute/gui.glade:85 msgid "Step 3" msgstr "Passo 3" #: res/microbrute/gui.glade:93 msgid "Calibration completed" msgstr "Calibração completada" #: res/microbrute/gui.glade:98 msgid "End" msgstr "Fim" #: res/microbrute/gui.glade:117 msgctxt "Gate Length" msgid "Short" msgstr "Curta" #: res/microbrute/gui.glade:121 msgctxt "Gate Length" msgid "Medium" msgstr "Média" #: res/microbrute/gui.glade:125 msgctxt "Gate Length" msgid "Long" msgstr "Longa" #: res/microbrute/gui.glade:139 msgctxt "Key Priority" msgid "Last" msgstr "Última" #: res/microbrute/gui.glade:143 msgctxt "Key Priority" msgid "Low" msgstr "Baixa" #: res/microbrute/gui.glade:147 msgctxt "Key Priority" msgid "High" msgstr "Alta" #: res/microbrute/gui.glade:161 msgctxt "Play Mode" msgid "Hold" msgstr "Manter" #: res/microbrute/gui.glade:165 msgctxt "Play Mode" msgid "Note On" msgstr "Nota ativa" #: res/microbrute/gui.glade:179 msgctxt "Receive Channel" msgid "Any" msgstr "Qualquer um" #: res/microbrute/gui.glade:257 msgctxt "Sequence Change" msgid "At End" msgstr "No fim" #: res/microbrute/gui.glade:261 msgctxt "Sequence Change" msgid "Instant Reset" msgstr "Reinício instantâneo" #: res/microbrute/gui.glade:265 msgctxt "Sequence Change" msgid "Instant Continuation" msgstr "Continuação instantânea" #: res/microbrute/gui.glade:279 msgctxt "Sequence Retrigger" msgid "Reset" msgstr "Reiniciar" #: res/microbrute/gui.glade:283 msgctxt "Sequence Retrigger" msgid "Reset But Legato" msgstr "Reiniciar (com legato)" #: res/microbrute/gui.glade:287 msgctxt "Sequence Retrigger" msgid "None" msgstr "Nenhum" #: res/microbrute/gui.glade:327 msgctxt "Step On" msgid "Clock" msgstr "Clock" #: res/microbrute/gui.glade:331 msgctxt "Step On" msgid "Gate" msgstr "Gate" #: res/microbrute/gui.glade:345 msgctxt "Synchronization" msgid "Auto" msgstr "Automática" #: res/microbrute/gui.glade:349 msgctxt "Synchronization" msgid "Internal" msgstr "Interna" #: res/microbrute/gui.glade:353 msgctxt "Synchronization" msgid "External" msgstr "Externa" #: res/microbrute/gui.glade:441 msgctxt "Velocity Response" msgid "Linear" msgstr "Linear" #: res/microbrute/gui.glade:445 msgctxt "Velocity Response" msgid "Logarithmic" msgstr "Logarítmica" #: res/microbrute/gui.glade:449 msgctxt "Velocity Response" msgid "Exponential" msgstr "Exponencial" #: res/microbrute/gui.glade:456 msgid "MicroBrute Configuration" msgstr "Configuração do MicroBrute" #: res/microbrute/gui.glade:480 msgid "Persistent changes" msgstr "Alterações persistentes" #: res/microbrute/gui.glade:547 msgid "Transmit Channel" msgstr "Canal de transmissão" #: res/microbrute/gui.glade:559 msgid "Receive Channel" msgstr "Canal de recepção" #: res/microbrute/gui.glade:650 msgid "Key Priority" msgstr "Prioridade de tecla" #: res/microbrute/gui.glade:662 msgid "Velocity Response" msgstr "Velocidade de resposta" #: res/microbrute/gui.glade:715 msgid "Keyboard Parameters" msgstr "Parâmetros de teclado" #: res/microbrute/gui.glade:753 msgid "Play Mode" msgstr "Modo de reprodução" #: res/microbrute/gui.glade:765 msgid "Sequence Retrigger" msgstr "Acionamento de sequência" #: res/microbrute/gui.glade:777 msgid "Sequence Change" msgstr "Mudança de sequência" #: res/microbrute/gui.glade:789 msgid "Next Step On" msgstr "Próximo passo" #: res/microbrute/gui.glade:801 msgid "Step Length" msgstr "Comprimento de passo" #: res/microbrute/gui.glade:914 msgid "Sequencer Control" msgstr "Controle de sequenciador" #: res/microbrute/gui.glade:952 msgid "LFO Key Retrigger" msgstr "Acionamento de tecla de LFO" #: res/microbrute/gui.glade:964 msgid "Envelope Legato" msgstr "Envelope legato" #: res/microbrute/gui.glade:976 msgid "Bend Range" msgstr "Faixa de bend" #: res/microbrute/gui.glade:988 msgid "Gate Length" msgstr "Comprimento de gate" #: res/microbrute/gui.glade:1000 msgid "Synchronization" msgstr "Sincronização" #: res/microbrute/gui.glade:1094 msgid "Module Parameters" msgstr "Parâmetros de módulo" elektroid-3.2.3/res/000077500000000000000000000000001500236517400142755ustar00rootroot00000000000000elektroid-3.2.3/res/Makefile.am000066400000000000000000000036261500236517400163400ustar00rootroot00000000000000if ELEKTROID_CLI_ONLY res_DATA = THANKS desktop_DATA = metainfo_DATA = svgicon_DATA = microbrute_DATA = ico_DATA = else res_DATA = gui.glade gui.css THANKS svgicon_DATA = io.github.dagargo.Elektroid.svg \ io.github.dagargo.Elektroid-symbolic.svg \ elektroid-file-symbolic.svg \ elektroid-folder-symbolic.svg \ elektroid-keys-symbolic.svg \ elektroid-project-symbolic.svg \ elektroid-sequence-symbolic.svg \ elektroid-sound-symbolic.svg \ elektroid-wave-symbolic.svg \ elektroid-wavetable-symbolic.svg microbrute_DATA = microbrute/gui.glade # System dependent resources if MINGW ico_DATA = elektroid.ico else ico_DATA = endif if OPENDESKTOP desktop_DATA = io.github.dagargo.Elektroid.desktop metainfo_DATA = io.github.dagargo.Elektroid.appdata.xml else desktop_DATA = metainfo_DATA = endif endif elektron_DATA = elektron/devices.json # Elektroid data dirs resdir = $(datadir)/elektroid icodir = $(datadir)/elektroid desktopdir = $(datadir)/applications metainfodir= $(datadir)/metainfo svgicondir = $(datarootdir)/icons/hicolor/scalable/apps # Connectors data dirs elektrondir = $(resdir)/elektron microbrutedir = $(resdir)/microbrute gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datarootdir)/icons/hicolor install-data-hook: update-icon-cache uninstall-hook: update-icon-cache update-icon-cache: @-if test -z "$(DESTDIR)"; then \ echo "Updating Gtk icon cache."; \ $(gtk_update_icon_cache); \ else \ echo "*** Icon cache not updated. After (un)install, run this:"; \ echo "*** $(gtk_update_icon_cache)"; \ fi EXTRA_DIST = \ $(res_DATA) \ $(desktop_DATA) \ $(metainfo_DATA) \ $(svgicon_DATA) \ $(elektron_DATA) \ $(microbrute_DATA) \ $(ico_DATA) \ THANKS elektroid-3.2.3/res/THANKS000077700000000000000000000000001500236517400163312../THANKSustar00rootroot00000000000000elektroid-3.2.3/res/elektroid-file-symbolic.svg000066400000000000000000000130731500236517400215400ustar00rootroot00000000000000 elektroid file symbolic image/svg+xml elektroid wave symbolic David García Goñi elektroid-3.2.3/res/elektroid-folder-symbolic.svg000066400000000000000000000115451500236517400220760ustar00rootroot00000000000000 elektroid folder symbolic image/svg+xml elektroid wave symbolic David García Goñi elektroid-3.2.3/res/elektroid-keys-symbolic.svg000066400000000000000000000122321500236517400215700ustar00rootroot00000000000000 elektroid keys symbolic image/svg+xml elektroid wave symbolic David García Goñi elektroid-3.2.3/res/elektroid-project-symbolic.svg000066400000000000000000000300311500236517400222600ustar00rootroot00000000000000 elektroid project symbolic image/svg+xml elektroid project symbolic David García Goñi elektroid-3.2.3/res/elektroid-sequence-symbolic.svg000066400000000000000000000205071500236517400224310ustar00rootroot00000000000000 elektroid sequence symbolic image/svg+xml elektroid sequence symbolic David García Goñi elektroid-3.2.3/res/elektroid-sound-symbolic.svg000066400000000000000000000146131500236517400217520ustar00rootroot00000000000000 elektroid sound symbolic image/svg+xml elektroid sound symbolic David García Goñi elektroid-3.2.3/res/elektroid-wave-symbolic.svg000066400000000000000000000130171500236517400215610ustar00rootroot00000000000000 elektroid wave symbolic image/svg+xml elektroid wave symbolic David García Goñi elektroid-3.2.3/res/elektroid-wavetable-symbolic.svg000066400000000000000000000345401500236517400225750ustar00rootroot00000000000000 elektroid wavetable symbolic image/svg+xml elektroid wave symbolic David García Goñi elektroid-3.2.3/res/elektroid.ico000066400000000000000000000604061500236517400167610ustar00rootroot00000000000000 hF   6@@ (B(  6,  2 *!$$c:!v'!$$$$!$$$$$$$$$ߪ""$ݷ$$$$$$$$$$[%[%[%MY"`$$$$$$$$$q-r.1q.g)̢^#eb"d$$$$$J$$V#R!u/J5ހ4t/f)ɢ^#bc"g$$$0$g)h*o,455݀3t/f)Ǣ^"_b !$N$$44555555݀3s.g)_&a'5555555555݀3v0w055555555555(?95!5;5c555555+555515555,555555755?(0  P; HsF##ک D#$$$߫ A#$$$$!D>#$$$$$$#  wc#$$$$$$$$$$$$$w$ Ŋ#$$$$$$$$$$$$$$$w!$$E$$$$$$$$$$$$$$$$v\%Z$[$[%_P2$$m$$$$$$$$$$$$$$s[%9! _&^&؝[%w[$qnCo$$p$$$$$$$$$$$y$(o-Y${1y1j+_&՝[$t[$$$s$$$$$$$$43555z1j*_&ӝ[$q[$$$v$$$$$$Z$([$x[$[%|25555y1i*^&ѝ[$n[$`:r$$y$$$$e)sj+k+k+{2555555y1i*^&ϝ[$k[$qC_ $$$$߁4w555555555555x0h*^&͝[$D[%[%5w55555555555554x0k+y0_&5w5555555555555555d7m+5w555555555555555@555D5555555555555C5575555 55555555E55655555555H5 55555555J5 55555<5R5 55@( @ 5j6hIe"$$#I$b"$$$$$I$_"$$$$$$_bcK \!$$$$$$$$=Y!$$$$$$$$$$""""!H!$$$$$$$$$$$$$$$$$$H(!$$$$$$$$$$$$$$$$$$$$H""%$$$$$$$$$$$$$$$$$$$$$$G%%$k$$$$$$$$$$$$$$$$$$$$$G\%\%\%\%\%$$$$x$$$$$$$$$$$$$$$$$$$G[%[%![%[%\%(\%\%$$$ ${$$$$$$$$$$$$$$$$$)a'`'Gf)b'\%[%\%&\%\%$$$"$~$$$$$$$$$$]$$$ $$}2|2I43p-b'\%ޞ[%\%$\%\%$$$#$$$$$$$$$G$55I5553p-a'\%ܞ[%\%"\%\%$$$%$$$$$$$G$\%\%\%\%V#{1_55555~3o-a'\%ڞ[%|\% ]%\%$$$'$$$$$F$[%)[%Þ[%[%ߝ[$ߴh*5555555~3o-a'\%؞[%y\%]%\%$$$*$$$!$c(Gl+o-o-o,u/555555555~2n,`'\%֞[%u\%\%\%$$$$$݀3H5555555555555555}2n,`'[%՞[%i\%\%5H555555555555555555}2m,`'[%$\%5H55555555555555555555|2p-)q-5H555555555555555555555555H55555555555555555555\5555=555555555555555555_5555 5M5e5d5a555555555555b55555H555555555e55555H5555555h55555H55555k555556555m55555565650 0 ??(@ @-a8,?*{(&#$#"$#$$$$#ۀ&"~#$$$$$$$݀% {#$$$$$$$$$݀%x"$$$$$$$$$$$%u"$$$$$$$$$$$$#܂r"$$$$$$$$$$$$$$ko"$$$$$$$$$$$$$$$$Il"$$$$$$$$$$$$$$$$$$ii"$$$$$$$$$$$$$$$$$$$$"        if"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$# h"O"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$h$"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$h$2"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$g$4!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$g$  6#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$g$$$+$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$f$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$e$$$$;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$e$$$$=$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$e$Z$[&\'\'X%"$$$@$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$e$\%\% \%e\%\%\\%\%\%'$$$B$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$T$]"\%\%T\%\%\%\%\%Z\%\%\%#$$$E$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\#\%\%|\%\%[%\%\%\%\%W\%\%\&"$$ $H$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$#\#b'^&~k+s.i*^&[%\%\%\%\%T\% \%[&%$$ $J$$$$$$$$$$$$$$$$$$$z$^$5v/~455y1i*^&[%\%\%\%\%Q\% \%\$%$$ $M$$$$$$$$$$$$$$$$$z$o)6555555y1i*^&[%\%\%\%\%O\% \%[&%$$ $P$$$$$$$$$$$$$$$z$r*655555554x0h*]&[%\%\%\%\%L\% \%\%$$$ $S$$$$$$$$$$$$$z$r*65555555554x0h*]&[%\%\%\%\%I\% \%^%$$$$V$$$$$$$$$$$z$r*6555555555554w0g)]%[%\%\%\%\%F\%\%\&$$$$X$$$$$$$$${$]$\%\%\%\%\%\%\%\%\%V#35555555555554w0g)]%[%\%\%\%\%D\%\%]'#$$$[$$$$$$$y$\%\%\%\%ݟ\%ߟ\%ߟ\%ߟ\%ߟ\%ߟ\%ߞ[%q-555555555555554w0f)]%[%\%\%\%\%A\%\%Z!$$$$^$$$$$R$\%\%V\%\%\%\%\%\%\%\%[%p-55555555555555554v/f)]%[%\%\%\%\%>\%\%\$$$$`$$g$ $\%\%h]%_&`'`'`'`'`'`'_&r.5555555555555555554v/f)]%[%\%\%\%\%<\%\%##$$$f)c(fs.~3~3~3~3~3~3~3~3߁4555555555555555555554u/e)]%[%\%\%\%\%9\%\%߁4}2g55555555555555555555555555555555߁4u/e)\%\%\%\%\%\%7\%\%55h5555555555555555555555555555555555߁4t/d(\%\%\%\%\%{\%\%55h555555555555555555555555555555555555ށ4t/d(\%\%\%\%(\%55h55555555555555555555555555555555555555ށ4s.d(\%\%4\%55h5555555555555555555555555555555555555555ހ4o-_&6`'55h555555555555555555555555555555555555555554y06y155h5555555555555555555555555555555555555555555 555h555555555555555555555555555555555555555555T5555h5555555555555555555555555555555555555555k56555h55555555555555555555555555555555555555n55555g555555555555555555555555555555555555q5?555H5555555555555555555555555555555555u555555m5555555555555555555555555555555w5555555555555555555555555555555555{5 55255}555555555555555555~5!55255~55555555555555555#55255~555555555555555%55255~5555555555555'55255~55555555555)55255~555555555+55255y5555555.55`%55?55555055555:5e5155???????elektroid-3.2.3/res/elektron/000077500000000000000000000000001500236517400161205ustar00rootroot00000000000000elektroid-3.2.3/res/elektron/devices.json000066400000000000000000000071401500236517400204370ustar00rootroot00000000000000[ { "id": 4, "name": "Elektron Analog Four", "filesystems": { "data": null, "project": [ "afprj" ], "sound": [ "afsnd" ] }, "storage": [] }, { "id": 6, "name": "Elektron Analog Keys", "filesystems": { "data": null, "project": [ "akprj" ], "sound": [ "aksnd" ] }, "storage": [] }, { "id": 8, "name": "Elektron Analog Rytm", "filesystems": { "sample": null, "data": null, "project": [ "arprj" ], "sound": [ "arsnd" ] }, "storage": [ "+Drive", "RAM" ] }, { "id": 10, "name": "Elektron Analog Heat", "filesystems": { "data": null, "preset": [ "ahpst" ] }, "storage": [] }, { "id": 12, "name": "Elektron Digitakt", "filesystems": { "sample": null, "data": null, "project": [ "dtprj" ], "sound": [ "dtsnd" ] }, "storage": [ "+Drive", "RAM" ] }, { "id": 14, "name": "Elektron Analog Four MKII", "filesystems": { "data": null, "project": [ "afprj" ], "sound": [ "afsnd" ] }, "storage": [] }, { "id": 16, "name": "Elektron Analog Rytm MKII", "filesystems": { "sample": null, "data": null, "project": [ "arprj" ], "sound": [ "arsnd" ] }, "storage": [ "+Drive", "RAM" ] }, { "id": 20, "name": "Elektron Digitone", "filesystems": { "data": null, "project": [ "dnprj" ], "sound": [ "dnsnd" ] }, "storage": [] }, { "id": 22, "name": "Elektron Analog Heat MKII", "filesystems": { "data": null, "preset": [ "ahpst" ] }, "storage": [] }, { "id": 28, "name": "Elektron Digitone Keys", "filesystems": { "data": null, "project": [ "dnprj" ], "sound": [ "dnsnd" ] }, "storage": [] }, { "id": 25, "name": "Elektron Model:Samples", "filesystems": { "sample": null, "data": null, "project": [ "msprj" ], "sound": [ "mssnd" ] }, "storage": [ "+Drive", "RAM" ] }, { "id": 27, "name": "Elektron Model:Cycles", "filesystems": { "raw": null, "preset-raw": [ "mcpst" ], "data": null, "project": [ "mcprj" ] }, "storage": [ "+Drive" ] }, { "id": 30, "name": "Elektron Syntakt", "filesystems": { "data": null, "project": [ "stprj" ], "sound": [ "stsnd" ] }, "storage": [] }, { "id": 32, "name": "Elektron Analog Heat +FX", "filesystems": { "data": null, "preset": [ "ahfxpst", "ahpst" ] }, "storage": [] }, { "id": 42, "name": "Elektron Digitakt II", "filesystems": { "data": null, "project": [ "dt2prj", "dtprj" ], "sample-stereo": null, "preset-takt-ii": [ "dt2pst", "dtsnd" ] }, "storage": [ "+Drive", "RAM" ] }, { "id": 43, "name": "Elektron Digitone II", "filesystems": { "data": null, "project": [ "dn2prj", "dnprj" ], "preset-takt-ii": [ "dn2pst", "dnsnd" ] }, "storage": [] } ] elektroid-3.2.3/res/gui.css000066400000000000000000000022211500236517400155700ustar00rootroot00000000000000@define-color local_color #3584e4; @define-color local_color_dark #255c9f; @define-color remote_color #e01b24; @define-color remote_color_dark #9d1319; @define-color disabled_color #7f7f7f; .local { color: @local_color; } .remote { color: @remote_color; } .local_switch { background-color: @local_color_dark; } .local_switch:checked, .local_switch:checked slider { border-color: @local_color_dark; background-color: @local_color; } .remote_switch { background-color: @remote_color_dark; } .remote_switch:checked, .remote_switch:checked slider { border-color: @remote_color_dark; background-color: @remote_color; } #local_up_button, #local_add_dir_button, #local_refresh_button, #local_search_button, #upload_button { color: @local_color; } #remote_up_button, #remote_add_dir_button, #remote_refresh_button, #remote_search_button, #download_button, #refresh_devices_button { color: @remote_color } *:disabled { color: @disabled_color; } #local_tree_view:selected { background-color: @local_color; } #remote_tree_view:selected { background-color: @remote_color; } #local_name_entry { border-color: transparent; background-color: transparent; } elektroid-3.2.3/res/gui.glade000066400000000000000000005464631500236517400161010ustar00rootroot00000000000000 256 512 1024 2048 4096 0.01 30 0.01 10 15 1 1 30 0.01000000000000001 10 1 127 1 12 127 1 10 True False True False Play True True False True False Delete True True False Undo True True False True False Save True 2 64 16 1 16 True False True False Upload Selection True True False True False Play True True False True False Open With External Editor True True False Show in File Manager True True False True False Rename True True False Delete True C-1 0 C#-1 1 D-1 2 D#-1 3 E-1 4 F-1 5 F#-1 6 G-1 7 G#-1 8 A-1 9 A#-1 10 B-1 11 C0 12 C#0 13 D0 14 D#0 15 E0 16 F0 17 F#0 18 G0 19 G#0 20 A0 21 A#0 22 B0 23 C1 24 C#1 25 D1 26 D#1 27 E1 28 F1 29 F#1 30 G1 31 G#1 32 A1 33 A#1 34 B1 35 C2 36 C#2 37 D2 38 D#2 39 E2 40 F2 41 F#2 42 G2 43 G#2 44 A2 45 A#2 46 B2 47 C3 48 C#3 49 D3 50 D#3 51 E3 52 F3 53 F#3 54 G3 55 G#3 56 A3 57 A#3 58 B3 59 C4 60 C#4 61 D4 62 D#4 63 E4 64 F4 65 F#4 66 G4 67 G#4 68 A4 69 A#4 70 B4 71 C5 72 C#5 73 D5 74 D#5 75 E5 76 F5 77 F#5 78 G5 79 G#5 80 A5 81 A#5 82 B5 83 C6 84 C#6 85 D6 86 D#6 87 E6 88 F6 89 F#6 90 G6 91 G#6 92 A6 93 A#6 94 B6 95 C7 96 C#7 97 D7 98 D#7 99 E7 100 F7 101 F#7 102 G7 103 G#7 104 A7 105 A#7 106 B7 107 C8 108 C#8 109 D8 110 D#8 111 E8 112 F8 113 F#8 114 G8 115 G#8 116 A8 117 A#8 118 B8 119 C9 120 C#9 121 D9 122 D#9 123 E9 124 F9 125 F#9 126 G9 127 True False True False Download Selection True True False True False Play True True False True False Open With External Editor True True False Show in File Manager True True False True False Rename True True False Delete True 100 1 10 False False True dialog main_window Elektroid Copyright © 2019 David García Goñi Sample and MIDI device manager https://dagargo.github.io/elektroid/ David García Goñi<dagargo@gmail.com> translator-credits io.github.dagargo.Elektroid gpl-3-0 False vertical 2 False end False False 0 400 False Auto Sampler False True dialog False main_window False 6 6 6 6 vertical 6 False end _Cancel True True True True False True 0 _Start True True True True False True False True 1 False False 4 True False True 6 True True False True vertical 6 True False 0 in True False 6 6 6 6 6 6 6 6 True True False start Name 0 0 True True end True True alpha 1 0 True False start Channels 0 1 True False True autosampler_dialog_channels_list_store 0 0 1 1 True False start Monitor 0 2 True False center True 1 2 True False Global False True 0 True False 0 in True False 6 6 6 6 6 6 6 6 True False start Press True 0 0 True False start Release True 0 1 True True True autosampler_duration_adj 0.10 2 1 1 0 True True True autosampler_release_adj 0.10 2 1 1 True False Duration False True 1 False True 0 True False start True 0 in True False start 6 6 6 6 6 6 False 6 6 True True False start Start True 0 0 True False True notes_list_store 24 0 1 0 True False start End True 0 1 True False True notes_list_store 36 0 1 1 True False start Distance True 0 2 True False start Velocity True 0 4 True True end True autosampler_semitones_adj 1 1 1 2 True True end True autosampler_velocity_adj 1 100 1 4 True False start Channel True 0 3 True True end True autosampler_midi_channel_adj 1 1 3 True False MIDI False True 1 False True 0 autosampler_dialog_cancel_button autosampler_dialog_start_button False menu_button True False 9 9 9 9 vertical True False vertical False True 0 True True True Show _Remote False True 1 True False False True 2 True True True _Preferences False True 3 True False False True 4 True True True _About False True 5 main 1 800 600 False io.github.dagargo.Elektroid True False vertical True False 6 6 6 True True vertical True False True True vertical True True True False 6 6 vertical 6 local_name_entry True False True False False True 0 True False True True vertical 6 True False True 6 True True True False False True 0 True False False True False 6 local_up_button True True True Go to Parent Directory True False go-up-symbolic False True 0 local_up_button True True True Add Directory True False folder-new-symbolic False True 1 local_refresh_button True True True Refresh Directory True False view-refresh-symbolic False True 2 local_search_button True True True Search True False edit-find-symbolic False True 3 buttons True True edit-find-symbolic False False search 1 False True 1 False True 0 True False True True 100 True True True True in local_tree_view True True True True local_list_store 1 multiple 0 True 100 Name True middle 1 Format 10 Channels 11 MIDI Note 12 Duration 9 Rate 8 Samples 7 Information middle 6 Size 3 list True False 0 True False spinner 1 False True 1 False True 1 True False True False 6 6 vertical 6 True False 6 True False True devices_list_store end 2 False True 0 refresh_devices_button True True True Refresh Devices True False view-refresh-symbolic False True 1 True False False True 2 True False fs_list_store 1 3 1 2 False True 3 False True 0 True False True True vertical 6 True False True 6 True True True False False True 0 True False False True False 6 remote_up_button True True True Go to Parent Directory True False go-up-symbolic False True 0 remote_up_button True True True Add Directory True False folder-new-symbolic False True 1 remote_refresh_button True True True Refresh Directory True False view-refresh-symbolic False True 2 remote_search_button True True True Search True False edit-find-symbolic False True 3 buttons True True edit-find-symbolic False False search 1 False True 1 False True 0 True False True True 100 True True True True in remote_tree_view True True True True remote_list_store 1 multiple 0 False 5 False 13 True 100 Name True middle 1 False Format 10 False Channels 11 False MIDI Note 12 False Duration 9 False Rate 8 False Samples 7 False Information True middle 6 False Size 3 list True False 0 True False spinner 1 False True 1 False True 1 True False True False True False 6 6 vertical 6 True False 6 True False center 6 True False play_button True True True True False media-playback-start-symbolic 2 False True 0 stop_button True True True True False media-playback-stop-symbolic 2 False True 1 loop_button True True True True False media-playlist-repeat-symbolic 2 False True 2 play_button True True True True False media-record-symbolic 2 False True 3 True True 0 True True False True none audio-volume-muted-symbolic audio-volume-high-symbolic audio-volume-low-symbolic audio-volume-medium-symbolic False False False False False True 1 True False False True 2 True False 6 True False end Auto play right False True 0 autoplay_switch True True start center True False True 1 False True 3 False True 0 True False 6 True False 6 True False Grid False True 0 True True grid_lenght_adj 16 False True 1 True True center False True 2 False True 0 True False False True 1 True False 6 True False Playing mix depends on the remote channels end Mix depending on remote right False True 0 autoplay_switch True True start center True False True 1 False True 2 False True end 1 False True 0 100 True True True True waveform_adj never in True False False True 1 False False True False True False 6 6 True 6 True True True True in True True task_list_store False 0 none Status 5 Type 6 8 Source True middle 2 Destination True middle 3 120 Progress 4 False True 0 True False start vertical 6 True True False True True Cancel Tasks True False edit-delete-symbolic False True 0 True False True True Remove Queued Tasks True False list-remove-all-symbolic False True 1 True False True True Clear Finished Tasks True False edit-clear-all-symbolic False True 2 False True 1 False False False True 0 True False 6 6 6 True 6 True False 6 True False start False True 0 True False vertical False True 1 True False start False True 2 False True 0 True False end True False True 1 False True 1 True False Elektroid False True True True True none main_popover end 400 False False True dialog False main_window False 6 6 6 6 vertical 6 False end _Cancel True True True True False True 0 _Save True True True True False True False True 1 False False 0 True False 6 6 True False Name False True 0 True True True True True alpha False True 1 False True 1 name_dialog_cancel_button name_dialog_accept_button 300 False Preferences False True dialog False main_window False 6 6 6 6 vertical 2 False end _Cancel True True True True False True 0 _Save True True True True False True False True 1 False False 0 True False 6 vertical 6 True False start True 0 in True False 6 6 6 6 6 6 True 6 6 True False start Play sample while loading right True 0 0 True True end center True True 1 0 True False start Buffer length right True 0 1 True False end True True audio_buffer_length_list_store 0 1 1 True False Audio False True 0 True False start True 0 in True False 6 6 6 6 6 6 True 6 6 True True False start Stop device when connecting right True 0 0 True True end center True True 1 0 True False MIDI False True 1 True False start True 0 in True False 6 6 6 6 6 6 True 6 6 True True False start Load sound and preset tags True 0 0 True True end center True True 1 0 True False Elektron False True 2 False True 1 record_dialog_cancel_button1 settings_dialog_accept_button 400 False False True dialog False main_window False 6 6 6 6 vertical 6 False end _Cancel True True True True True True 1 False False 0 True False 6 vertical 6 True False start False True 0 True False False True 1 True True 1 progress_dialog_cancel_button 400 False Record Channels False True dialog False main_window False 6 6 6 6 vertical 6 False end _Cancel True True True True False True 0 _Record True True True True False True False True 1 False False 0 True False 6 6 6 True True False end Channels 0 0 True False True record_dialog_channels_list_store 0 0 1 0 True False end Monitor 0 1 True False center True 1 1 False True 0 record_dialog_cancel_button record_dialog_record_button elektroid-3.2.3/res/io.github.dagargo.Elektroid-symbolic.svg000066400000000000000000000101011500236517400240420ustar00rootroot00000000000000 elektroid symbolic image/svg+xml elektroid symbolic David García Goñi elektroid-3.2.3/res/io.github.dagargo.Elektroid.appdata.xml000066400000000000000000000060101500236517400236410ustar00rootroot00000000000000 io.github.dagargo.Elektroid FSFAP GPL-3.0+ Elektroid Sample and MIDI device manager

Elektroid is a sample and MIDI device manager. It includes the `elektroid` GUI application and the `elektroid-cli` CLI application.

Elektroid started as a FLOSS Elektron Transfer alternative and it has ended up supporting other devices from different vendors in the same fashion.

These are the supported devices:

  • Arturia MicroBrute
  • Arturia MicroFreak
  • Casio CZ-101
  • Elektron Analog Four MKI, MKII and Keys
  • Elektron Analog Heat MKI, MKII and +FX
  • Elektron Analog Rytm MKI and MKII
  • Elektron Digitakt I and II
  • Elektron Digitone I and II and Digitone Keys
  • Elektron Model:Cycles
  • Elektron Model:Samples
  • Elektron Syntakt
  • Eventide ModFactor, PitchFactor, TimeFactor, Space and H9
  • Moog Little Phatty and Slim Phatty
  • Novation Summit and Peak
  • Samplers implementing MIDI SDS
io.github.dagargo.Elektroid.desktop elektroid #c0bfbc #3d3846 https://dagargo.github.io/elektroid/images/screenshot.png The main window showing the application in action Sample MIDI https://dagargo.github.io/elektroid/ https://liberapay.com/dagargo David García Goñi dagargo@gmail.com
elektroid-3.2.3/res/io.github.dagargo.Elektroid.desktop000066400000000000000000000010251500236517400231020ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Elektroid Comment=Sample and MIDI device manager Comment[ca]=Gestor de mostres i dispositius MIDI Comment[de]=Sample und MIDI Gerätemanager Comment[es]=Gestor de muestras y dispositivos MIDI Comment[fr]=Gestionnaire d'échantillons et de périphériques MIDI Comment[pt_BR]=Gerenciador de amostras e dispositivos MIDI Categories=Music;AudioVideo;X-Sound;Audio;X-Alsa Keywords=music;alsa;realtime;standalone; Exec=elektroid Icon=io.github.dagargo.Elektroid Terminal=false SingleMainWindow=false elektroid-3.2.3/res/io.github.dagargo.Elektroid.svg000066400000000000000000000105541500236517400222370ustar00rootroot00000000000000 elektroid image/svg+xml elektroid David García Goñi elektroid-3.2.3/res/microbrute/000077500000000000000000000000001500236517400164505ustar00rootroot00000000000000elektroid-3.2.3/res/microbrute/gui.glade000066400000000000000000001330331500236517400202350ustar00rootroot00000000000000 1 12 2 1 False Calibration assistant False True True False This procedure calibrates the pitch bend and modulation wheels. True Start True True False Let the pitch bend wheel rest at the neutral position and click on the next button. True intro Step 1 True True False While setting both wheels at the bottom click on the next button. True intro Step 2 True True False While setting both wheels at the top click on the next button. True intro Step 3 True True False Calibration completed True summary End True False Short 1 Medium 2 Long 3 Last 0 Low 1 High 2 Hold 0 Note On 1 Any 16 1 0 2 1 3 2 4 3 5 4 6 5 7 6 8 7 9 8 10 9 11 10 12 11 13 12 14 13 15 14 16 15 At End 0 Instant Reset 1 Instant Continuation 2 Reset 0 Reset But Legato 1 None 2 1/4 4 1/8 8 1/16 16 1/32 32 Clock 0 Gate 1 Auto 0 Internal 1 External 2 1 0 2 1 3 2 4 3 5 4 6 5 7 6 8 7 9 8 10 9 11 10 12 11 13 12 14 13 15 14 16 15 Linear 0 Logarithmic 1 Exponential 2 False MicroBrute Configuration False True microdude True False True True vertical True False 6 6 6 6 True False end Persistent changes False True 0 True True start center True True False True 1 False True 0 True False 6 6 6 6 6 6 True False True True 0 in True False 6 6 6 6 True 6 6 True True False end Transmit Channel 0 0 True False end Receive Channel 0 1 True False center True transmit_channels 0 0 1 0 True False center True receive_channels 0 0 1 1 True False MIDI 1 0 True False True True 0 in True False 6 6 6 6 True 6 6 True True False end Key Priority 0 0 True False end Velocity Response 0 1 True False center True key_priorities 0 0 1 0 True False center True velocity_responses 0 0 1 1 True False Keyboard Parameters 0 0 True False True True 0 in True False 6 6 6 6 True 6 6 True True False end Play Mode 0 0 True False end Sequence Retrigger 0 1 True False end Sequence Change 0 2 True False end Next Step On 0 3 True False end Step Length 0 4 True False center True step_lenghts 0 0 1 4 True False center True play_modes 0 0 1 0 True False center True sequence_retrigger_modes 0 0 1 1 True False center True sequence_change_modes 0 0 1 2 True False center True step_on_modes 0 0 1 3 True False Sequencer Control 1 1 True False True True 0 in True False 6 6 6 6 True 6 6 True True False end LFO Key Retrigger 0 0 True False end Envelope Legato 0 1 True False end Bend Range 0 2 True False end Gate Length 0 3 True False end Synchronization 0 4 True False center True synchronization_modes 0 0 1 4 True False center True gate_lengths 0 0 1 3 True True start center True 1 0 True True start center True 1 1 True True center True number bend_ranges 2 1 2 True False Module Parameters 0 1 False True 1 elektroid-3.2.3/rpm/000077500000000000000000000000001500236517400143025ustar00rootroot00000000000000elektroid-3.2.3/rpm/elektroid.spec000066400000000000000000000047511500236517400171470ustar00rootroot00000000000000Name: elektroid Version: 2.5 Release: 1%{?dist} Summary: Transfer application for Elektron devices License: GPLv3+ URL: https://github.com/dagargo/elektroid Source0: https://github.com/dagargo/elektroid/releases/download/%{version}/%{name}-%{version}.tar.gz BuildRequires: autoconf BuildRequires: libtool BuildRequires: alsa-lib-devel BuildRequires: zlib-devel BuildRequires: libzip-devel BuildRequires: gtk3-devel BuildRequires: libsndfile-devel BuildRequires: libsamplerate-devel %if 0%{?suse_version} BuildRequires: libpulse-devel %else %if 0%{?mgaversion} BuildRequires: libpulseaudio-devel %else # RHEL, CentOS and Fedora use this name: BuildRequires: pulseaudio-libs-devel %endif %endif BuildRequires: gettext-devel BuildRequires: json-glib-devel %description Elektroid is a sample and MIDI device manager. With Elektroid you can easily upload and download audio files and manage different types of data on different MIDI devices, such as presets, projects or tunings. It can also be used to send and receive SysEx MIDI files. %package cli Summary: Sample and MIDI device manager %description cli This is the command-line client for Elektroid. %prep %autosetup -p1 %build %configure %make_build %install %make_install %files %{_bindir}/elektroid %{_datadir}/applications/%{name}.desktop %{_datadir}/%{name}/elektron/devices.json %{_datadir}/%{name}/microbrute/gui.glade %{_datadir}/%{name}/gui.css %{_datadir}/%{name}/gui.glade %{_datadir}/icons/hicolor/scalable/apps/%{name}.svg %{_datadir}/icons/hicolor/scalable/apps/%{name}-symbolic.svg %{_datadir}/icons/hicolor/scalable/apps/%{name}-sequence-symbolic.svg %{_datadir}/icons/hicolor/scalable/apps/%{name}-project-symbolic.svg %{_datadir}/icons/hicolor/scalable/apps/%{name}-sound-symbolic.svg %{_datadir}/icons/hicolor/scalable/apps/%{name}-wave-symbolic.svg %{_datadir}/locale/*/LC_MESSAGES/%{name}.mo %{_mandir}/man1/elektroid.1.gz %{_metainfodir}/%{name}.appdata.xml %license COPYING %files cli %{_bindir}/elektroid-cli %{_datadir}/%{name}/elektron/devices.json %{_datadir}/locale/*/LC_MESSAGES/%{name}.mo %{_mandir}/man1/elektroid-cli.1.gz %license COPYING %changelog * Sat Mar 11 2023 David García Goñi - 2.5-1 - Update to 2.5 release * Wed Jun 08 2022 Jonathan Wakely - 2.1-1 - Update to 2.1 release * Wed Jun 08 2022 Jonathan Wakely - 2.0-2 - Add subpackage for elektroid-cli * Mon Feb 07 2022 Jonathan Wakely - 2.0-1 - RPM package for Fedora elektroid-3.2.3/src/000077500000000000000000000000001500236517400142735ustar00rootroot00000000000000elektroid-3.2.3/src/Makefile.am000066400000000000000000000052431500236517400163330ustar00rootroot00000000000000PKG_CONFIG ?= pkg-config CLI_LIBS_BASE = glib-2.0 zlib json-glib-1.0 libzip if MINGW MSYS2_LIBS = -lws2_32 endif if ELEKTROID_RTMIDI CLI_LIBS = rtmidi $(CLI_LIBS_BASE) else CLI_LIBS = alsa $(CLI_LIBS_BASE) endif GUI_LIBS_BASE = $(CLI_LIBS) gtk+-3.0 if ELEKTROID_RTAUDIO GUI_LIBS = rtaudio $(GUI_LIBS_BASE) else GUI_LIBS = libpulse libpulse-mainloop-glib $(GUI_LIBS_BASE) endif elektroid_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(GUI_LIBS)` $(SNDFILE_CFLAGS) $(SAMPLERATE_CFLAGS) -D_GNU_SOURCE elektroid_LDFLAGS = `$(PKG_CONFIG) --libs $(GUI_LIBS)` $(SNDFILE_LIBS) $(SAMPLERATE_LIBS) $(MSYS2_LIBS) elektroid_cli_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(CLI_LIBS)` $(SNDFILE_CFLAGS) $(SAMPLERATE_CFLAGS) -D_GNU_SOURCE elektroid_cli_LDFLAGS = `$(PKG_CONFIG) --libs $(CLI_LIBS)` $(SNDFILE_LIBS) $(SAMPLERATE_LIBS) $(MSYS2_LIBS) if ELEKTROID_CLI_ONLY bin_PROGRAMS = elektroid-cli else bin_PROGRAMS = elektroid elektroid-cli endif if ELEKTROID_RTMIDI elektroid_backend_sources = backend_rtmidi.c else elektroid_backend_sources = backend_alsa.c endif if ELEKTROID_RTAUDIO elektroid_audio_sources = audio_rtaudio.c else elektroid_audio_sources = audio_pa.c endif elektroid_common_sources = local.c local.h \ connector.c connector.h \ preferences.c preferences.h \ regconn.c regconn.h\ regpref.c regpref.h\ sample.c sample.h \ utils.c utils.h \ backend.c backend.h $(elektroid_backend_sources) \ connectors/common.c connectors/common.h \ connectors/system.c connectors/system.h \ connectors/elektron.c connectors/elektron.h \ connectors/package.c connectors/package.h \ connectors/microbrute.c connectors/microbrute.h \ connectors/microfreak_sample.c connectors/microfreak_sample.h \ connectors/microfreak.c connectors/microfreak.h \ connectors/cz.c connectors/cz.h \ connectors/sds.c connectors/sds.h \ connectors/efactor.c connectors/efactor.h \ connectors/phatty.c connectors/phatty.h \ connectors/summit.c connectors/summit.h \ connectors/scala.c connectors/scala.h \ connectors/default.c connectors/default.h elektroid_cli_SOURCES = $(elektroid_common_sources) elektroid-cli.c elektroid_SOURCES = $(elektroid_common_sources) \ audio.h audio.c $(elektroid_audio_sources) \ browser.c browser.h notifier.c notifier.h \ regma.c regma.h \ maction.c maction.h \ mactions/autosampler.c \ mactions/backend.c \ mactions/microbrute.c \ mactions/microfreak.c \ editor.c editor.h \ tasks.c tasks.h \ guirecorder.c guirecorder.h \ progress.c progress.h \ elektroid.c SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ SAMPLERATE_CFLAGS = @SAMPLERATE_CFLAGS@ SAMPLERATE_LIBS = @SAMPLERATE_LIBS@ AM_CPPFLAGS = -Wall -O3 -DDATADIR='"$(datadir)/$(PACKAGE)"' -DLOCALEDIR='"$(localedir)"' elektroid-3.2.3/src/audio.c000066400000000000000000000270741500236517400155520ustar00rootroot00000000000000/* * audio.c * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "audio.h" #define FRAMES_TO_MONITOR 10000 void audio_init_int (struct audio *); void audio_destroy_int (struct audio *); const gchar *audio_name (); const gchar *audio_version (); static inline gint16 audio_mix_channels (gint16 **src, guint channels) { gdouble mix = 0; for (gint i = 0; i < channels; i++, (*src)++) { mix += **src; } return (gint16) (mix * MONO_MIX_GAIN (channels)); } static inline void audio_copy_sample (gint16 *dst, gint16 *src, struct audio *audio) { #if defined(ELEKTROID_RTAUDIO) *dst = (gint16) (*src * audio->volume); #else *dst = *src; #endif } void audio_write_to_output (struct audio *audio, void *buffer, gint frames) { guint32 start, end; size_t size; gint16 *dst, *src; guint bytes_per_frame; gboolean stopping = FALSE; struct sample_info *sample_info; guint8 *data; debug_print (2, "Writing %d frames...", frames); g_mutex_lock (&audio->control.mutex); sample_info = audio->sample.info; if (!sample_info) { goto end; } data = audio->sample.content->data; if (AUDIO_SEL_LEN (audio)) { start = audio->sel_start; end = audio->sel_end; } else { start = sample_info->loop_start; end = sample_info->loop_end; } bytes_per_frame = SAMPLE_INFO_FRAME_SIZE (sample_info); size = frames * FRAME_SIZE (AUDIO_CHANNELS, SF_FORMAT_PCM_16); memset (buffer, 0, size); if ((audio->pos == sample_info->frames && !audio->loop) || audio->status == AUDIO_STATUS_PREPARING_PLAYBACK || audio->status == AUDIO_STATUS_STOPPING_PLAYBACK) { if (audio->status == AUDIO_STATUS_PREPARING_PLAYBACK) { audio->status = AUDIO_STATUS_PLAYING; } else //Stopping... { stopping = TRUE; } goto end; } dst = buffer; src = (gint16 *) & data[audio->pos * bytes_per_frame]; for (gint i = 0; i < frames; i++) { //Using "audio->pos >" instead of "audio->pos ==" improves the playback //of the selection while changing it because it's possible that an audio //iteration might be in the middle of 2 selection changes and in this //case the equality might not have a change. if (audio->pos == sample_info->frames || audio->pos > end + 1) { if (!audio->loop) { break; } debug_print (2, "Sample reset"); audio->pos = start; src = (gint16 *) & data[audio->pos * bytes_per_frame]; } if (audio->mono_mix) { gint16 mix = audio_mix_channels (&src, sample_info->channels); audio_copy_sample (dst, &mix, audio); dst++; audio_copy_sample (dst, &mix, audio); dst++; } else { audio_copy_sample (dst, src, audio); src++; dst++; audio_copy_sample (dst, src, audio); src++; dst++; } audio->pos++; } end: if (!sample_info || stopping) { audio->release_frames += frames; } g_mutex_unlock (&audio->control.mutex); if (audio->release_frames > AUDIO_BUF_FRAMES) { audio_stop_playback (audio); } } void audio_read_from_input (struct audio *audio, void *buffer, gint frames) { static gint monitor_frames = 0; static gint16 level = 0; gint16 *data; guint recorded_frames, remaining_frames, recording_frames; guint channels = (audio->record_options & RECORD_STEREO) == RECORD_STEREO ? 2 : 1; guint bytes_per_frame = FRAME_SIZE (channels, SF_FORMAT_PCM_16); guint record = !(audio->record_options & RECORD_MONITOR_ONLY); struct sample_info *sample_info = audio->sample.info; debug_print (2, "Reading %d frames (recording = %d)...", frames, record); g_mutex_lock (&audio->control.mutex); recorded_frames = audio->sample.content->len / bytes_per_frame; remaining_frames = sample_info->frames - recorded_frames; recording_frames = remaining_frames > frames ? frames : remaining_frames; if (channels == 2) { if (record) { g_byte_array_append (audio->sample.content, buffer, recording_frames * bytes_per_frame); } data = buffer; for (gint i = 0; i < frames * 2; i++, data++) { if (*data > level) { level = *data; } } } else if (channels == 1) { data = buffer; if (audio->record_options & RECORD_RIGHT) { data++; } for (gint i = 0; i < recording_frames; i++, data += 2) { if (record) { g_byte_array_append (audio->sample.content, (guint8 *) data, sizeof (gint16)); } if (*data > level) { level = *data; } } } monitor_frames += frames; if (audio->monitor && monitor_frames >= FRAMES_TO_MONITOR) { audio->monitor (audio->monitor_data, level / (gdouble) SHRT_MAX); level = 0; monitor_frames -= FRAMES_TO_MONITOR; } g_mutex_unlock (&audio->control.mutex); if (recording_frames < frames) { audio_stop_recording (audio); } } void audio_reset_record_buffer (struct audio *audio, guint record_options, void (*monitor) (void *, gdouble), void *monitor_data) { guint size; GByteArray *content; struct sample_info *si = g_malloc (sizeof (struct sample_info)); debug_print (1, "Resetting record buffer..."); si->channels = (record_options & RECORD_STEREO) == 3 ? 2 : 1; si->frames = audio->rate * MAX_RECORDING_TIME_S; si->loop_start = si->frames - 1; si->loop_end = si->loop_start; si->format = SF_FORMAT_PCM_16; si->rate = audio->rate; si->midi_note = 0; si->loop_type = 0; size = si->frames * SAMPLE_INFO_FRAME_SIZE (si); content = g_byte_array_sized_new (size); g_mutex_lock (&audio->control.mutex); idata_free (&audio->sample); idata_init (&audio->sample, content, NULL, si); audio->pos = 0; audio->record_options = record_options; audio->monitor = monitor; audio->monitor_data = monitor_data; g_mutex_unlock (&audio->control.mutex); } void audio_init (struct audio *audio, void (*volume_change_callback) (gpointer, gdouble), void (*audio_ready_callback) (gpointer), gpointer data) { debug_print (1, "Initializing audio (%s %s)...", audio_name (), audio_version ()); idata_init (&audio->sample, NULL, NULL, NULL); audio->loop = FALSE; audio->path = NULL; audio->status = AUDIO_STATUS_STOPPED; audio->volume_change_callback = volume_change_callback; audio->ready_callback = audio_ready_callback; audio->callback_data = data; audio->control.callback = NULL; audio->sel_start = -1; audio->sel_end = -1; audio_init_int (audio); } void audio_destroy (struct audio *audio) { debug_print (1, "Destroying audio..."); audio_stop_playback (audio); audio_stop_recording (audio); audio_reset_sample (audio); g_mutex_lock (&audio->control.mutex); audio_destroy_int (audio); g_mutex_unlock (&audio->control.mutex); } void audio_reset_sample (struct audio *audio) { debug_print (1, "Resetting sample..."); g_mutex_lock (&audio->control.mutex); idata_free (&audio->sample); audio->pos = 0; g_free (audio->path); audio->path = NULL; audio->release_frames = 0; audio->status = AUDIO_STATUS_STOPPED; g_mutex_unlock (&audio->control.mutex); } void audio_prepare (struct audio *audio, enum audio_status status) { g_mutex_lock (&audio->control.mutex); audio->pos = audio->sel_end - audio->sel_start ? audio->sel_start : 0; audio->release_frames = 0; audio->status = status; g_mutex_unlock (&audio->control.mutex); } guint audio_detect_start (struct audio *audio) { guint start_frame = 0; struct sample_info *sample_info = audio->sample.info; gint16 *data = (gint16 *) audio->sample.content->data; //Searching for audio data... for (gint i = 0; i < sample_info->frames; i++) { for (gint j = 0; j < sample_info->channels; j++, data++) { if (!start_frame && abs (*data) >= SHRT_MAX * 0.01) { start_frame = i; data -= j + 1; goto search_last_zero; } } } search_last_zero: for (gint i = start_frame - 1; i >= 1; i--) { for (gint j = 0; j < sample_info->channels; j++, data--) { gint16 curr = *data; gint16 prev = *(data - sample_info->channels); if ((curr > 0 && prev < 0) || (curr < 0 && prev > 0)) { start_frame = i - 1; goto end; } } } end: data = (gint16 *) & audio->sample.content->data[start_frame]; for (gint j = 0; j < sample_info->channels; j++, data++) { *data = 0; } debug_print (1, "Detected start at frame %d", start_frame); return start_frame; } void audio_delete_range (struct audio *audio, guint32 start, guint32 length) { guint bytes_per_frame, index, len; struct sample_info *sample_info = audio->sample.info; g_mutex_lock (&audio->control.mutex); bytes_per_frame = SAMPLE_INFO_FRAME_SIZE (sample_info); index = start * bytes_per_frame; len = length * bytes_per_frame; debug_print (2, "Deleting range from %d with len %d...", index, len); g_byte_array_remove_range (audio->sample.content, index, len); sample_info->frames -= length; if (sample_info->loop_start >= audio->sel_end) { sample_info->loop_start -= length; } else if (sample_info->loop_start >= audio->sel_start && sample_info->loop_start < audio->sel_end) { sample_info->loop_start = sample_info->frames - 1; } if (sample_info->loop_end >= audio->sel_end) { sample_info->loop_end -= length; } else if (sample_info->loop_end >= audio->sel_start && sample_info->loop_end < audio->sel_end) { sample_info->loop_end = sample_info->frames - 1; } audio->sel_start = -1; audio->sel_end = -1; g_mutex_unlock (&audio->control.mutex); } static void audio_normalize (struct audio *audio) { gdouble ratio, ratiop, ration; gint16 *data, maxp = 1, minn = -1; guint samples = audio->sample.content->len / SAMPLE_SIZE (SF_FORMAT_PCM_16); data = (gint16 *) audio->sample.content->data; for (gint i = 0; i < samples; i++, data++) { gint16 v = *data; if (v >= 0) { if (v > maxp) { maxp = v; } } else { if (v < minn) { minn = v; } } } ratiop = SHRT_MAX / (gdouble) maxp; ration = SHRT_MIN / (gdouble) minn; ratio = ratiop < ration ? ratiop : ration; debug_print (1, "Normalizing to %f...", ratio); data = (gint16 *) audio->sample.content->data; for (gint i = 0; i < samples; i++, data++) { *data = (gint16) (*data * ratio); } } void audio_finish_recording (struct audio *audio) { struct sample_info *sample_info = audio->sample.info; guint record = !(audio->record_options & RECORD_MONITOR_ONLY); g_mutex_lock (&audio->control.mutex); audio->status = AUDIO_STATUS_STOPPED; sample_info->frames = audio->sample.content->len / SAMPLE_INFO_FRAME_SIZE (sample_info); sample_info->loop_start = sample_info->frames - 1; sample_info->loop_end = sample_info->loop_start; if (record) { audio_normalize (audio); } if (audio->monitor) { audio->monitor (audio->monitor_data, 0.0); } g_mutex_unlock (&audio->control.mutex); } elektroid-3.2.3/src/audio.h000066400000000000000000000072341500236517400155530ustar00rootroot00000000000000/* * audio.h * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef AUDIO_H #define AUDIO_H #include #include "sample.h" #include "utils.h" #include "preferences.h" #if defined(ELEKTROID_RTAUDIO) #include "rtaudio_c.h" #else #include #endif typedef void (*audio_monitor_notifier) (gpointer, gdouble); #define MAX_RECORDING_TIME_S 30 #define AUDIO_CHANNELS 2 // Audio system is always stereo #define AUDIO_BUF_FRAMES (preferences_get_int (PREF_KEY_AUDIO_BUFFER_LEN)) #define AUDIO_BUF_BYTES (AUDIO_BUF_FRAMES * FRAME_SIZE (AUDIO_CHANNELS,SF_FORMAT_PCM_16)) #define AUDIO_SEL_LEN(a) ((a)->sel_start == -1 && (a)->sel_end == -1 ? 0 : (a)->sel_end - (a)->sel_start + 1) #define RECORD_LEFT 0x1 #define RECORD_RIGHT 0x2 #define RECORD_STEREO (RECORD_LEFT | RECORD_RIGHT) #define RECORD_MONITOR_ONLY 0x4 enum audio_status { AUDIO_STATUS_PREPARING_PLAYBACK, AUDIO_STATUS_PLAYING, AUDIO_STATUS_STOPPING_PLAYBACK, AUDIO_STATUS_PREPARING_RECORD, AUDIO_STATUS_RECORDING, AUDIO_STATUS_STOPPING_RECORD, AUDIO_STATUS_STOPPED }; struct audio { // PulseAudio or RtAudio backend #if defined(ELEKTROID_RTAUDIO) rtaudio_t playback_rtaudio; rtaudio_t record_rtaudio; gdouble volume; #else pa_threaded_mainloop *mainloop; pa_context *context; pa_stream *playback_stream; pa_stream *record_stream; guint32 playback_index; guint32 record_index; pa_cvolume volume; pa_sample_spec sample_spec; #endif guint32 rate; struct idata sample; struct sample_info sample_info_src; gboolean loop; guint32 pos; void (*volume_change_callback) (gpointer, gdouble); void (*ready_callback) (gpointer); gpointer callback_data; guint32 release_frames; struct job_control control; //Used to synchronize access to sample, frames, loop and pos members. gchar *path; enum audio_status status; gint64 sel_start; //Space for guint32 and -1 gint64 sel_end; //Space for guint32 and -1 gboolean mono_mix; guint record_options; void (*monitor) (void *, gdouble); void *monitor_data; }; void audio_start_playback (struct audio *); void audio_stop_playback (struct audio *); void audio_start_recording (struct audio *, guint, audio_monitor_notifier, void *); void audio_stop_recording (struct audio *); gboolean audio_check (struct audio *); void audio_reset_record_buffer (struct audio *, guint, audio_monitor_notifier, void *); void audio_init (struct audio *, void (*)(gpointer, gdouble), void (*)(gpointer), gpointer); gint audio_run (struct audio *); void audio_destroy (struct audio *); void audio_reset_sample (struct audio *); void audio_set_volume (struct audio *, gdouble); void audio_write_to_output (struct audio *, void *, gint); void audio_read_from_input (struct audio *, void *, gint); void audio_prepare (struct audio *, enum audio_status); void audio_delete_range (struct audio *, guint32, guint32); guint audio_detect_start (struct audio *); const gchar *audio_name (); const gchar *audio_version (); #endif elektroid-3.2.3/src/audio_pa.c000066400000000000000000000307621500236517400162300ustar00rootroot00000000000000/* * audio_pa.c * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "audio.h" void audio_finish_recording (struct audio *); #define WAIT_TIME_TO_STOP_US 10000 static void audio_success_cb (pa_stream *stream, int success, void *data) { struct audio *audio = data; pa_threaded_mainloop_signal (audio->mainloop, 0); } static void audio_wait_success (struct audio *audio, pa_operation *operation) { if (!operation) { debug_print (2, "No operation. Skipping wait..."); return; } while (pa_operation_get_state (operation) != PA_OPERATION_DONE) { pa_threaded_mainloop_wait (audio->mainloop); } } static void audio_read_callback (pa_stream *stream, size_t size, void *data) { const void *buffer; size_t frame_size; struct audio *audio = data; struct sample_info *sample_info = audio->sample.info; if (!sample_info) { return; } if (pa_stream_peek (stream, &buffer, &size) < 0) { audio_stop_recording (audio); return; } frame_size = FRAME_SIZE (AUDIO_CHANNELS, SF_FORMAT_PCM_16); audio_read_from_input (audio, (void *) buffer, size / frame_size); pa_stream_drop (stream); } static void audio_write_callback (pa_stream *stream, size_t size, void *data) { void *buffer; size_t frame_size; struct audio *audio = data; struct sample_info *sample_info = audio->sample.info; if (!sample_info) { return; } frame_size = FRAME_SIZE (AUDIO_CHANNELS, SF_FORMAT_PCM_16); pa_stream_begin_write (stream, &buffer, &size); audio_write_to_output (audio, buffer, size / frame_size); pa_stream_write (stream, buffer, size, NULL, 0, PA_SEEK_RELATIVE); } void audio_stop_and_flush_stream (struct audio *audio, pa_stream *stream) { pa_operation *operation; if (pa_threaded_mainloop_in_thread (audio->mainloop)) { pa_stream_flush (stream, NULL, NULL); pa_stream_cork (stream, 1, NULL, NULL); } else { pa_threaded_mainloop_lock (audio->mainloop); operation = pa_stream_flush (stream, audio_success_cb, audio); audio_wait_success (audio, operation); operation = pa_stream_cork (stream, 1, audio_success_cb, audio); audio_wait_success (audio, operation); pa_threaded_mainloop_unlock (audio->mainloop); } } void audio_stop_playback (struct audio *audio) { g_mutex_lock (&audio->control.mutex); if (audio->status == AUDIO_STATUS_PREPARING_RECORD || audio->status == AUDIO_STATUS_RECORDING || audio->status == AUDIO_STATUS_STOPPING_RECORD) { g_mutex_unlock (&audio->control.mutex); } else if (audio->status == AUDIO_STATUS_PREPARING_PLAYBACK || audio->status == AUDIO_STATUS_PLAYING) { audio->status = AUDIO_STATUS_STOPPING_PLAYBACK; g_mutex_unlock (&audio->control.mutex); debug_print (1, "Stopping playback..."); audio_stop_and_flush_stream (audio, audio->playback_stream); g_mutex_lock (&audio->control.mutex); audio->status = AUDIO_STATUS_STOPPED; g_mutex_unlock (&audio->control.mutex); } else { while (audio->status != AUDIO_STATUS_STOPPED && !pa_threaded_mainloop_in_thread (audio->mainloop)) { g_mutex_unlock (&audio->control.mutex); usleep (WAIT_TIME_TO_STOP_US); g_mutex_lock (&audio->control.mutex); } g_mutex_unlock (&audio->control.mutex); } } void audio_start_playback (struct audio *audio) { pa_operation *operation; audio_stop_playback (audio); debug_print (1, "Starting playback..."); audio_prepare (audio, AUDIO_STATUS_PREPARING_PLAYBACK); pa_threaded_mainloop_lock (audio->mainloop); operation = pa_stream_cork (audio->playback_stream, 0, audio_success_cb, audio); audio_wait_success (audio, operation); pa_threaded_mainloop_unlock (audio->mainloop); } void audio_stop_recording (struct audio *audio) { struct sample_info *sample_info = audio->sample.info; if (!audio->record_stream) { return; } g_mutex_lock (&audio->control.mutex); if (audio->status == AUDIO_STATUS_PREPARING_PLAYBACK || audio->status == AUDIO_STATUS_PLAYING || audio->status == AUDIO_STATUS_STOPPING_PLAYBACK) { g_mutex_unlock (&audio->control.mutex); } else if (audio->status == AUDIO_STATUS_PREPARING_RECORD || audio->status == AUDIO_STATUS_RECORDING) { audio->status = AUDIO_STATUS_STOPPING_RECORD; g_mutex_unlock (&audio->control.mutex); audio_finish_recording (audio); debug_print (1, "Stopping recording (%d frames read)...", sample_info->frames); audio_stop_and_flush_stream (audio, audio->record_stream); } else { while (audio->status != AUDIO_STATUS_STOPPED && !pa_threaded_mainloop_in_thread (audio->mainloop)) { g_mutex_unlock (&audio->control.mutex); usleep (WAIT_TIME_TO_STOP_US); g_mutex_lock (&audio->control.mutex); } g_mutex_unlock (&audio->control.mutex); } } void audio_start_recording (struct audio *audio, guint options, audio_monitor_notifier monitor_notifier, void *monitor_data) { pa_operation *operation; struct sample_info *sample_info; if (!audio->record_stream) { return; } audio_stop_recording (audio); audio_reset_record_buffer (audio, options, monitor_notifier, monitor_data); audio_prepare (audio, AUDIO_STATUS_PREPARING_RECORD); sample_info = audio->sample.info; debug_print (1, "Starting recording (max %d frames)...", sample_info->frames); pa_threaded_mainloop_lock (audio->mainloop); operation = pa_stream_cork (audio->record_stream, 0, audio_success_cb, audio); audio_wait_success (audio, operation); pa_threaded_mainloop_unlock (audio->mainloop); } static void audio_set_sink_volume (pa_context *context, const pa_sink_input_info *info, int eol, void *data) { struct audio *audio = data; if (info && pa_cvolume_valid (&info->volume)) { gdouble v = pa_sw_volume_to_linear (pa_cvolume_avg (&info->volume)); debug_print (1, "Setting volume to %f...", v); audio->volume_change_callback (audio->callback_data, v); } } static void audio_notify (pa_context *context, pa_subscription_event_type_t type, uint32_t index, void *data) { struct audio *audio = data; if (audio->context != context) { return; } if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) { if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE) { pa_context_get_sink_input_info (audio->context, audio->playback_index, audio_set_sink_volume, audio); } } } static void audio_connect_playback_stream_callback (pa_stream *stream, void *data) { struct audio *audio = data; if (pa_stream_get_state (stream) == PA_STREAM_READY) { pa_stream_set_write_callback (stream, audio_write_callback, audio); audio->playback_index = pa_stream_get_index (audio->playback_stream); debug_print (2, "Sink index: %d", audio->playback_index); pa_context_get_sink_input_info (audio->context, audio->playback_index, audio_set_sink_volume, audio); } } static void audio_connect_record_stream_callback (pa_stream *stream, void *data) { struct audio *audio = data; if (pa_stream_get_state (stream) == PA_STREAM_READY) { pa_stream_set_read_callback (stream, audio_read_callback, audio); audio->record_index = pa_stream_get_index (audio->record_stream); debug_print (2, "Sink index: %d", audio->record_index); } } void audio_server_info_callback (pa_context *context, const pa_server_info *info, void *data) { struct audio *audio = data; pa_operation *operation; pa_stream_flags_t stream_flags = PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_NOT_MONOTONIC | PA_STREAM_AUTO_TIMING_UPDATE; pa_proplist *props = pa_proplist_new (); pa_buffer_attr buffer_attr = { .maxlength = AUDIO_BUF_BYTES, .tlength = -1, .prebuf = 0, .minreq = AUDIO_BUF_BYTES, .fragsize = AUDIO_BUF_BYTES }; audio->rate = info->sample_spec.rate; audio->sample_spec.format = PA_SAMPLE_S16LE; audio->sample_spec.channels = AUDIO_CHANNELS; audio->sample_spec.rate = audio->rate; debug_print (1, "Using %d Hz sample rate...", audio->rate); pa_proplist_set (props, PA_PROP_APPLICATION_ICON_NAME, PACKAGE, sizeof (PACKAGE)); audio->playback_stream = pa_stream_new_with_proplist (context, _("Output"), &audio->sample_spec, NULL, props); audio->record_stream = pa_stream_new_with_proplist (context, _("Input"), &audio->sample_spec, NULL, props); pa_proplist_free (props); pa_stream_set_state_callback (audio->playback_stream, audio_connect_playback_stream_callback, audio); pa_stream_connect_playback (audio->playback_stream, NULL, &buffer_attr, stream_flags, NULL, NULL); pa_stream_set_state_callback (audio->record_stream, audio_connect_record_stream_callback, audio); pa_stream_connect_record (audio->record_stream, NULL, &buffer_attr, stream_flags); pa_context_set_subscribe_callback (audio->context, audio_notify, audio); operation = pa_context_subscribe (audio->context, PA_SUBSCRIPTION_MASK_SINK_INPUT, NULL, NULL); if (operation != NULL) { pa_operation_unref (operation); } audio->ready_callback (audio); } static void audio_context_callback (pa_context *context, void *data) { struct audio *audio = data; if (pa_context_get_state (context) == PA_CONTEXT_READY) { pa_context_get_server_info (context, audio_server_info_callback, audio); } else { audio->ready_callback (audio); } } void audio_init_int (struct audio *audio) { pa_mainloop_api *api; audio->playback_stream = NULL; audio->playback_index = PA_INVALID_INDEX; audio->record_stream = NULL; audio->record_index = PA_INVALID_INDEX; audio->mainloop = pa_threaded_mainloop_new (); if (!audio->mainloop) { audio->ready_callback (audio->callback_data); return; } api = pa_threaded_mainloop_get_api (audio->mainloop); audio->context = pa_context_new (api, APP_NAME); if (pa_context_connect (audio->context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) { pa_context_unref (audio->context); pa_threaded_mainloop_free (audio->mainloop); audio->mainloop = NULL; audio->ready_callback (audio->callback_data); return; } else { pa_context_set_state_callback (audio->context, audio_context_callback, audio); pa_threaded_mainloop_start (audio->mainloop); pa_threaded_mainloop_wait (audio->mainloop); } } void audio_destroy_int (struct audio *audio) { if (audio->mainloop) { pa_threaded_mainloop_stop (audio->mainloop); pa_context_disconnect (audio->context); pa_context_unref (audio->context); if (audio->playback_stream) { pa_stream_unref (audio->playback_stream); audio->playback_stream = NULL; } if (audio->record_stream) { pa_stream_unref (audio->record_stream); audio->record_stream = NULL; } pa_threaded_mainloop_free (audio->mainloop); audio->mainloop = NULL; } } gboolean audio_check (struct audio *audio) { return audio->mainloop ? TRUE : FALSE; } void audio_set_volume (struct audio *audio, gdouble volume) { pa_operation *operation; pa_volume_t v; if (audio->playback_index != PA_INVALID_INDEX) { debug_print (1, "Setting volume to %f...", volume); v = pa_sw_volume_from_linear (volume); pa_cvolume_set (&audio->volume, AUDIO_CHANNELS, v); operation = pa_context_set_sink_input_volume (audio->context, audio->playback_index, &audio->volume, NULL, NULL); if (operation != NULL) { pa_operation_unref (operation); } } } const gchar * audio_name () { return "PulseAudio"; } const gchar * audio_version () { return pa_get_library_version (); } elektroid-3.2.3/src/audio_rtaudio.c000066400000000000000000000170021500236517400172670ustar00rootroot00000000000000/* * audio_rtaudio.c * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "audio.h" void audio_finish_recording (struct audio *); static struct rtaudio_stream_options STREAM_OPTIONS = { .flags = 0, .priority = 99, .name = APP_NAME }; void audio_stop_playback (struct audio *audio) { enum audio_status status; g_mutex_lock (&audio->control.mutex); status = audio->status; g_mutex_unlock (&audio->control.mutex); if (status != AUDIO_STATUS_PLAYING) { return; } g_mutex_lock (&audio->control.mutex); audio->status = AUDIO_STATUS_STOPPED; g_mutex_unlock (&audio->control.mutex); debug_print (1, "Stopping playback..."); rtaudio_abort_stream (audio->playback_rtaudio); //Stop and flush buffer } void audio_start_playback (struct audio *audio) { audio_stop_playback (audio); audio_prepare (audio, AUDIO_STATUS_PLAYING); debug_print (1, "Starting playback..."); rtaudio_start_stream (audio->playback_rtaudio); } void audio_stop_recording (struct audio *audio) { struct sample_info *sample_info = audio->sample.info; enum audio_status status; g_mutex_lock (&audio->control.mutex); status = audio->status; g_mutex_unlock (&audio->control.mutex); if (status != AUDIO_STATUS_RECORDING) { return; } g_mutex_lock (&audio->control.mutex); audio->status = AUDIO_STATUS_STOPPING_RECORD; g_mutex_unlock (&audio->control.mutex); audio_finish_recording (audio); debug_print (1, "Stopping recording (%d frames read)...", sample_info->frames); rtaudio_abort_stream (audio->record_rtaudio); //Stop and flush buffer } void audio_start_recording (struct audio *audio, guint options, audio_monitor_notifier monitor_notifier, void *monitor_data) { struct sample_info *sample_info; audio_stop_recording (audio); audio_reset_record_buffer (audio, options, monitor_notifier, monitor_data); audio_prepare (audio, AUDIO_STATUS_RECORDING); sample_info = audio->sample.info; debug_print (1, "Starting recording (max %d frames)...", sample_info->frames); rtaudio_start_stream (audio->record_rtaudio); } int audio_record_cb (void *out, void *in, unsigned int frames, double stream_time, rtaudio_stream_status_t rtaudio_status, void *audio) { audio_read_from_input (audio, in, frames); return 0; } int audio_playback_cb (void *out, void *in, unsigned int frames, double stream_time, rtaudio_stream_status_t rtaudio_status, void *audio) { audio_write_to_output (audio, out, frames); return 0; } void audio_error_cb (rtaudio_error_t err, const char *msg) { error_print ("Audio error: %s", msg); } void audio_init_int (struct audio *audio) { gint i, err, dev_id; guint buffer_frames; rtaudio_device_info_t dev_info; struct rtaudio_stream_parameters playback_stream_params, record_stream_params; const rtaudio_api_t *apis = rtaudio_compiled_api (); gint api_count = rtaudio_get_num_compiled_apis (); audio->playback_rtaudio = NULL; audio->record_rtaudio = NULL; for (i = 0; i < api_count; i++) { debug_print (2, "Testing %s API...", rtaudio_api_name (apis[i])); #if defined(__linux__) if (apis[i] == RTAUDIO_API_LINUX_PULSE) { break; } #elif defined(__APPLE__) if (apis[i] == RTAUDIO_API_MACOSX_CORE) { break; } #elif defined(_WIN32) if (apis[i] == RTAUDIO_API_WINDOWS_DS) { break; } #endif } if (i == api_count) { return; } audio->playback_rtaudio = rtaudio_create (apis[i]); if (rtaudio_error (audio->playback_rtaudio)) { error_print ("Error while initilizing playback RtAudio: %s", rtaudio_error (audio->playback_rtaudio)); return; } if (!rtaudio_device_count (audio->playback_rtaudio)) { error_print ("No devices found"); goto error_playback; } dev_id = rtaudio_get_default_output_device (audio->playback_rtaudio); playback_stream_params = (struct rtaudio_stream_parameters) { .device_id = dev_id, .num_channels = AUDIO_CHANNELS, .first_channel = 0 }; dev_info = rtaudio_get_device_info (audio->playback_rtaudio, dev_id); audio->rate = dev_info.preferred_sample_rate; buffer_frames = AUDIO_BUF_FRAMES; err = rtaudio_open_stream (audio->playback_rtaudio, &playback_stream_params, NULL, RTAUDIO_FORMAT_SINT16, audio->rate, &buffer_frames, audio_playback_cb, audio, &STREAM_OPTIONS, audio_error_cb); if (err || !rtaudio_is_stream_open (audio->playback_rtaudio)) { error_print ("Error occurred while opening the playback RtAudio stream: %s", rtaudio_error (audio->playback_rtaudio)); goto error_playback; } debug_print (1, "Using %s for playback with %d Hz sample rate and %d frames...", dev_info.name, audio->rate, buffer_frames); audio->volume = 1.0; audio->volume_change_callback (audio->callback_data, audio->volume); audio->record_rtaudio = rtaudio_create (apis[i]); if (rtaudio_error (audio->record_rtaudio)) { error_print ("Error while initilizing recording RtAudio: %s", rtaudio_error (audio->record_rtaudio)); goto error_playback; } if (!rtaudio_device_count (audio->record_rtaudio)) { error_print ("No devices found"); goto error_record; } dev_id = rtaudio_get_default_input_device (audio->record_rtaudio); record_stream_params = (struct rtaudio_stream_parameters) { .device_id = dev_id, .num_channels = AUDIO_CHANNELS, .first_channel = 0 }; dev_info = rtaudio_get_device_info (audio->record_rtaudio, dev_id); buffer_frames = AUDIO_BUF_FRAMES; err = rtaudio_open_stream (audio->record_rtaudio, NULL, &record_stream_params, RTAUDIO_FORMAT_SINT16, audio->rate, &buffer_frames, audio_record_cb, audio, &STREAM_OPTIONS, audio_error_cb); if (err || !rtaudio_is_stream_open (audio->record_rtaudio)) { error_print ("Error occurred while opening the recording RtAudio stream: %s", rtaudio_error (audio->record_rtaudio)); goto error_record; } debug_print (1, "Using %s for recording with %d Hz sample rate and %d frames...", dev_info.name, audio->rate, buffer_frames); goto end; error_record: rtaudio_destroy (audio->record_rtaudio); audio->record_rtaudio = NULL; error_playback: rtaudio_destroy (audio->playback_rtaudio); audio->playback_rtaudio = NULL; end: audio->ready_callback (audio->callback_data); } void audio_destroy_int (struct audio *audio) { if (audio_check (audio)) { rtaudio_destroy (audio->playback_rtaudio); rtaudio_destroy (audio->record_rtaudio); } } gboolean audio_check (struct audio *audio) { return audio->playback_rtaudio != NULL; } void audio_set_volume (struct audio *audio, gdouble volume) { audio->volume = volume; } const gchar * audio_name () { return "RtAudio"; } const gchar * audio_version () { return rtaudio_version (); } elektroid-3.2.3/src/backend.c000066400000000000000000000445371500236517400160430ustar00rootroot00000000000000/* * backend.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "backend.h" #include "local.h" #include "sample.h" #include "preferences.h" struct connector *system_connector = NULL; GSList *connectors = NULL; // When sending a batch of SysEx messages we want the trasfer status to be controlled outside this function. // This is what the update parameter is for. gint backend_tx_sysex_internal (struct backend *, struct sysex_transfer *, gboolean); void backend_rx_drain_int (struct backend *); void backend_destroy_int (struct backend *); gint backend_init_int (struct backend *, const gchar *); gboolean backend_check_int (struct backend *); const gchar *backend_name (); const gchar *backend_version (); void backend_fill_devices_array (GArray *); //Identity Request Universal Sysex message static const guint8 BE_MIDI_IDENTITY_REQUEST[] = { 0xf0, 0x7e, 0x7f, 6, 1, 0xf7 }; gdouble backend_get_storage_stats_percent (struct backend_storage_stats *statfs) { return (statfs->bsize - statfs->bfree) * 100.0 / statfs->bsize; } static gint backend_get_fs_operations_id_comparator (gconstpointer a, gconstpointer b) { const struct fs_operations *ops = a; return ops->id != *((guint32 *) b); } const struct fs_operations * backend_get_fs_operations_by_id (struct backend *backend, guint32 id) { GSList *e = g_slist_find_custom (backend->fs_ops, &id, backend_get_fs_operations_id_comparator); return e ? e->data : NULL; } static gint backend_get_fs_operations_name_comparator (gconstpointer a, gconstpointer b) { const struct fs_operations *ops = a; return strcmp (GET_CLI_NAME (ops), (gchar *) b); } const struct fs_operations * backend_get_fs_operations_by_name (struct backend *backend, const gchar *name) { GSList *e = g_slist_find_custom (backend->fs_ops, name, backend_get_fs_operations_name_comparator); return e ? e->data : NULL; } void backend_midi_handshake (struct backend *backend) { GByteArray *tx_msg; GByteArray *rx_msg; gint offset; backend->name[0] = 0; backend->version[0] = 0; backend->description[0] = 0; backend->fs_ops = NULL; backend->upgrade_os = NULL; backend->get_storage_stats = NULL; memset (&backend->midi_info, 0, sizeof (struct backend_midi_info)); tx_msg = g_byte_array_sized_new (sizeof (BE_MIDI_IDENTITY_REQUEST)); g_byte_array_append (tx_msg, (guchar *) BE_MIDI_IDENTITY_REQUEST, sizeof (BE_MIDI_IDENTITY_REQUEST)); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, BE_SYSEX_TIMEOUT_GUESS_MS); if (!rx_msg) { debug_print (1, "No MIDI identity reply"); return; } if (rx_msg->data[4] == 2) { if (rx_msg->len == 15 || rx_msg->len == 17) { offset = rx_msg->len - 15; memset (backend->midi_info.company, 0, BE_COMPANY_LEN); memcpy (backend->midi_info.company, &rx_msg->data[5], rx_msg->len == 15 ? 1 : BE_COMPANY_LEN); memcpy (backend->midi_info.family, &rx_msg->data[6 + offset], BE_FAMILY_LEN); memcpy (backend->midi_info.model, &rx_msg->data[8 + offset], BE_MODEL_LEN); memcpy (backend->midi_info.version, &rx_msg->data[10 + offset], BE_VERSION_LEN); snprintf (backend->name, LABEL_MAX, "%02x-%02x-%02x %02x-%02x %02x-%02x", backend->midi_info.company[0], backend->midi_info.company[1], backend->midi_info.company[2], backend->midi_info.family[0], backend->midi_info.family[1], backend->midi_info.model[0], backend->midi_info.model[1]); snprintf (backend->version, LABEL_MAX, "%d.%d.%d.%d", backend->midi_info.version[0], backend->midi_info.version[1], backend->midi_info.version[2], backend->midi_info.version[3]); debug_print (1, "Detected device: %s %s", backend->name, backend->version); } else { debug_print (1, "Illegal MIDI identity reply length"); } } else { debug_print (1, "Illegal SUB-ID2"); } free_msg (rx_msg); usleep (BE_REST_TIME_US); } gint backend_tx_sysex_no_status (struct backend *backend, struct sysex_transfer *transfer) { return backend_tx_sysex_internal (backend, transfer, FALSE); } gint backend_tx_sysex (struct backend *backend, struct sysex_transfer *transfer) { return backend_tx_sysex_internal (backend, transfer, TRUE); } //Synchronized gint backend_tx (struct backend *backend, GByteArray *tx_msg) { struct sysex_transfer transfer; transfer.raw = tx_msg; g_mutex_lock (&backend->mutex); backend_tx_sysex (backend, &transfer); g_mutex_unlock (&backend->mutex); free_msg (tx_msg); return transfer.err; } //Synchronized gint backend_tx_and_rx_sysex_transfer (struct backend *backend, struct sysex_transfer *transfer, gboolean free) { transfer->batch = FALSE; transfer->err = 0; g_mutex_lock (&backend->mutex); if (transfer->raw) { backend_tx_sysex (backend, transfer); if (free) { free_msg (transfer->raw); transfer->raw = NULL; } } if (!transfer->err) { backend_rx_sysex (backend, transfer); } g_mutex_unlock (&backend->mutex); return transfer->err; } //Synchronized //A timeout of 0 means infinity; a negative timeout means the default timeout. GByteArray * backend_tx_and_rx_sysex (struct backend *backend, GByteArray *tx_msg, gint timeout) { struct sysex_transfer transfer; transfer.raw = tx_msg; transfer.timeout = timeout < 0 ? BE_SYSEX_TIMEOUT_MS : timeout; backend_tx_and_rx_sysex_transfer (backend, &transfer, TRUE); return transfer.raw; } void backend_destroy_data (struct backend *backend) { debug_print (1, "Destroying backend data..."); g_free (backend->data); backend->data = NULL; } gint backend_program_change (struct backend *backend, guint8 channel, guint8 program) { ssize_t size; guint8 msg[2]; msg[0] = 0xc0 | (channel & 0xf); msg[1] = program & 0x7f; debug_print (1, "Sending MIDI program %d...", msg[1]); if ((size = backend_tx_raw (backend, msg, 2)) < 0) { return size; } return 0; } gint backend_send_3_byte_message (struct backend *backend, guint8 msg_type, guint8 channel, guint8 d1, guint8 d2) { ssize_t size; guint8 msg[3]; msg[0] = msg_type | (channel & 0xf); msg[1] = d1 & 0x7f; msg[2] = d2 & 0x7f; debug_print (1, "Sending MIDI message: status %08x; data %d, %d...", msg[0], msg[1], msg[2]); if ((size = backend_tx_raw (backend, msg, 3)) < 0) { return size; } return 0; } gint backend_send_controller (struct backend *backend, guint8 channel, guint8 controller, guint8 value) { return backend_send_3_byte_message (backend, 0xb0, channel, controller, value); } gint backend_send_note_on (struct backend *backend, guint8 channel, guint8 note, guint8 velocity) { return backend_send_3_byte_message (backend, 0x90, channel, note, velocity); } gint backend_send_note_off (struct backend *backend, guint8 channel, guint8 note, guint8 velocity) { return backend_send_3_byte_message (backend, 0x80, channel, note, velocity); } gint backend_send_rpn (struct backend *backend, guint8 channel, guint8 controller_msb, guint8 controller_lsb, guint8 value_msb, guint8 value_lsb) { gint err = backend_send_controller (backend, channel, 101, controller_msb); err |= backend_send_controller (backend, channel, 100, controller_lsb); err |= backend_send_controller (backend, channel, 6, value_msb); err |= backend_send_controller (backend, channel, 38, value_lsb); return err; } gint backend_init_midi (struct backend *backend, const gchar *id) { debug_print (1, "Initializing backend (%s) to '%s'...", backend_name (), id); backend->type = BE_TYPE_MIDI; gint err = backend_init_int (backend, id); if (!err) { g_mutex_lock (&backend->mutex); backend_rx_drain (backend); g_mutex_unlock (&backend->mutex); } if (preferences_get_boolean (PREF_KEY_STOP_DEVICE_WHEN_CONNECTING)) { debug_print (1, "Stopping device..."); if (backend_tx_raw (backend, (guint8 *) "\xfc", 1) < 0) { error_print ("Error while stopping device"); } usleep (BE_REST_TIME_US); } return err; } void backend_destroy (struct backend *backend) { debug_print (1, "Destroying backend..."); if (backend->destroy_data) { backend->destroy_data (backend); } if (backend->type == BE_TYPE_MIDI) { backend_destroy_int (backend); } backend->upgrade_os = NULL; backend->get_storage_stats = NULL; backend->destroy_data = NULL; backend->type = BE_TYPE_NONE; g_slist_free (backend->fs_ops); } gboolean backend_check (struct backend *backend) { switch (backend->type) { case BE_TYPE_MIDI: return backend_check_int (backend); case BE_TYPE_SYSTEM: return TRUE; default: return FALSE; } } static ssize_t backend_rx_raw_loop (struct backend *backend, struct sysex_transfer *transfer) { ssize_t rx_len, rx_len_msg; gchar *text; guint8 tmp[BE_TMP_BUFF_LEN]; guint8 *tmp_msg, *data = backend->buffer + backend->rx_len; if (!backend->inputp) { error_print ("Input port is NULL"); return -ENOTCONN; } debug_print (4, "Reading data..."); while (1) { if (!transfer->active) { return -ECANCELED; } debug_print (6, "Checking timeout (%d ms, %d ms, %s mode)...", transfer->time, transfer->timeout, transfer->batch ? "batch" : "single"); if (((transfer->batch && transfer->status == RECEIVING) || !transfer->batch) && transfer->timeout > -1 && transfer->time >= transfer->timeout) { debug_print (1, "Timeout (%d)", transfer->timeout); gchar *text = debug_get_hex_data (debug_level, backend->buffer, backend->rx_len); debug_print (4, "Internal buffer data (%zd): %s", backend->rx_len, text); g_free (text); return -ETIMEDOUT; } rx_len = backend_rx_raw (backend, tmp, BE_TMP_BUFF_LEN); if (rx_len < 0) { return rx_len; } if (rx_len == 0) { if ((transfer->batch && transfer->status == RECEIVING) || !transfer->batch) { transfer->time += BE_POLL_TIMEOUT_MS; } continue; } //Everything is skipped until a 0xf0 is found. This includes every RT MIDI message. tmp_msg = tmp; if (!backend->rx_len && *tmp_msg != 0xf0) { if (debug_level >= 4) { gchar *text = debug_get_hex_data (debug_level, tmp, rx_len); debug_print (4, "Skipping non SysEx data (%zd): %s", rx_len, text); g_free (text); } tmp_msg++; rx_len_msg = 1; for (gint i = 1; i < rx_len; i++, tmp_msg++, rx_len_msg++) { if (*tmp_msg == 0xf0) { break; } } rx_len -= rx_len_msg; } if (rx_len == 0) { transfer->time += BE_POLL_TIMEOUT_MS; continue; } if (rx_len > 0) { memcpy (backend->buffer + backend->rx_len, tmp_msg, rx_len); backend->rx_len += rx_len; break; } if (rx_len < 0) { break; } } if (debug_level >= 3) { text = debug_get_hex_data (debug_level, data, rx_len); debug_print (3, "Queued data (%zu): %s", rx_len, text); g_free (text); } return rx_len; } //Access to this function must be synchronized. gint backend_rx_sysex (struct backend *backend, struct sysex_transfer *transfer) { gint next_check, len, i; guint8 *b; ssize_t rx_len; transfer->err = 0; transfer->time = 0; transfer->active = TRUE; transfer->status = WAITING; transfer->raw = g_byte_array_sized_new (BE_INT_BUF_LEN); next_check = 0; while (1) { if (backend->rx_len == next_check) { debug_print (4, "Reading from MIDI device..."); if (transfer->batch) { transfer->time = 0; } rx_len = backend_rx_raw_loop (backend, transfer); if (rx_len == -ENODATA || rx_len == -ETIMEDOUT || rx_len == -ECANCELED) { if (transfer->batch) { break; } else { transfer->err = rx_len; goto end; } } else if (rx_len < 0) { transfer->err = -EIO; goto end; } } else { debug_print (4, "Reading from internal buffer..."); } transfer->status = RECEIVING; len = -1; b = backend->buffer + next_check; for (; next_check < backend->rx_len; next_check++, b++) { if (*b == 0xf7) { next_check++; len = next_check; break; } } //We filter out whatever SysEx message not suitable for Elektroid. if (len > 0) { //Filter out everything until an 0xf0 is found. b = backend->buffer; for (i = 0; i < len && *b != 0xf0; i++, b++); if (i > 0 && debug_level >= 4) { gchar *text = debug_get_hex_data (debug_level, backend->buffer, i); debug_print (4, "Skipping non SysEx data in buffer (%d): %s", i, text); g_free (text); } debug_print (3, "Copying %d bytes...", len - i); g_byte_array_append (transfer->raw, b, len - i); backend->rx_len -= len; memmove (backend->buffer, backend->buffer + next_check, backend->rx_len); transfer->err = 0; next_check = 0; //Filter empty message if (transfer->raw->len == 2 && !memcmp (transfer->raw->data, "\xf0\xf7", 2)) { debug_print (4, "Removing empty message..."); g_byte_array_remove_range (transfer->raw, 0, 2); continue; } if (debug_level >= 4) { gchar *text = debug_get_hex_data (debug_level, transfer->raw->data, transfer->raw->len); debug_print (4, "Queued data (%d): %s", transfer->raw->len, text); g_free (text); } } else { debug_print (4, "No message in the queue. Continuing..."); } if (transfer->raw->len && !transfer->batch) { break; } } end: if (!transfer->raw->len) { transfer->err = -ETIMEDOUT; } if (transfer->err) { free_msg (transfer->raw); transfer->raw = NULL; } else { if (debug_level >= 2) { gchar *text = debug_get_hex_data (debug_level, transfer->raw->data, transfer->raw->len); debug_print (2, "Raw message received (%d): %s", transfer->raw->len, text); g_free (text); } } transfer->active = FALSE; transfer->status = FINISHED; return transfer->err; } //Access to this function must be synchronized. void backend_rx_drain (struct backend *backend) { struct sysex_transfer transfer; transfer.timeout = 1000; transfer.batch = FALSE; debug_print (2, "Draining buffers..."); backend->rx_len = 0; backend_rx_drain_int (backend); while (!backend_rx_sysex (backend, &transfer)) { free_msg (transfer.raw); } } enum path_type backend_get_path_type (struct backend *backend) { return (!backend || backend->type == BE_TYPE_SYSTEM) ? PATH_SYSTEM : PATH_INTERNAL; } GArray * backend_get_devices () { struct backend_device *backend_device; GArray *devices = g_array_new (FALSE, FALSE, sizeof (struct backend_device)); backend_device = g_malloc (sizeof (struct backend_device)); backend_device->type = BE_TYPE_SYSTEM; snprintf (backend_device->id, LABEL_MAX, "%s", BE_SYSTEM_ID); snprintf (backend_device->name, LABEL_MAX, "%s", g_get_host_name ()); g_array_append_vals (devices, backend_device, 1); backend_fill_devices_array (devices); return devices; } // A handshake function might return these values: // 0, the device matches the connector. // -ENODEV, the device does not match the connector but we can continue with the next connector. // Other negative errors are allowed but we will not continue with the remaining connectors. gint backend_init_connector (struct backend *backend, struct backend_device *device, const gchar *conn_name, struct sysex_transfer *sysex_transfer) { gint err; GSList *list = NULL, *iterator; gboolean active = TRUE; GSList *c; if (device->type == BE_TYPE_SYSTEM) { backend->conn_name = system_connector->name; backend->type = BE_TYPE_SYSTEM; return system_connector->handshake (backend); } err = backend_init_midi (backend, device->id); if (err) { return err; } c = connectors; while (c) { struct connector *connector = c->data; if (connector->regex) { GRegex *regex = g_regex_new (connector->regex, G_REGEX_CASELESS, 0, NULL); if (g_regex_match (regex, device->name, 0, NULL)) { debug_print (1, "Connector %s matches the device", connector->name); list = g_slist_prepend (list, (void *) connector); } else { list = g_slist_append (list, (void *) connector); } g_regex_unref (regex); } else { list = g_slist_append (list, (void *) connector); } c = c->next; } if (!conn_name) { backend_midi_handshake (backend); } err = -ENODEV; for (iterator = list; iterator; iterator = iterator->next) { const struct connector *c = iterator->data; if (sysex_transfer) { g_mutex_lock (&sysex_transfer->mutex); active = sysex_transfer->active; g_mutex_unlock (&sysex_transfer->mutex); } if (!active) { err = -ECANCELED; goto end; } debug_print (1, "Testing %s connector (%sstandard handshake)...", c->name, c->standard ? "" : "non "); if (conn_name) { if (!strcmp (conn_name, c->name)) { if (c->standard) { backend_midi_handshake (backend); } err = c->handshake (backend); if (!err) { debug_print (1, "Using %s connector...", c->name); backend->conn_name = c->name; } goto end; } } else { err = c->handshake (backend); if (err && err != -ENODEV) { goto end; } if (!err) { debug_print (1, "Using %s connector...", c->name); backend->conn_name = c->name; goto end; } } } error_print ("No device recognized"); end: g_slist_free (list); if (err) { backend_destroy (backend); } return err; } elektroid-3.2.3/src/backend.h000066400000000000000000000136121500236517400160360ustar00rootroot00000000000000/* * backend.h * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "utils.h" #if defined(ELEKTROID_RTMIDI) #include #include #else #include #endif #ifndef BACKEND_H #define BACKEND_H #define BE_MAX_MIDI_PROGRAMS 128 #define BE_POLL_TIMEOUT_MS 20 #define BE_MAX_TX_LEN KI //With a higher value than 4 KB, functions behave erratically. #define BE_INT_BUF_LEN (32 * KI) //Max length of a SysEx message for Elektroid #define BE_DEV_RING_BUF_LEN (256 * KI) #define BE_TMP_BUFF_LEN (64 * KI) //This size is required by RtMidi as it needs enough space for the messages. #define BE_REST_TIME_US 50000 #define BE_SYSEX_TIMEOUT_MS 5000 #define BE_SYSEX_TIMEOUT_GUESS_MS 1000 //When the request is not implemented, 5 s is too much. #define BE_COMPANY_LEN 3 #define BE_FAMILY_LEN 2 #define BE_MODEL_LEN 2 #define BE_VERSION_LEN 4 #define BE_SYSTEM_ID "SYSTEM_ID" #define BE_SYSEX_EXT "syx" #define PREF_KEY_STOP_DEVICE_WHEN_CONNECTING "stopDeviceWhenConnecting" extern GSList *connectors; extern struct connector *system_connector; struct backend_storage_stats { gchar name[LABEL_MAX]; guint64 bsize; guint64 bfree; }; struct backend; typedef void (*t_destroy_data) (struct backend * backend); typedef gint (*t_get_storage_stats) (struct backend * backend, guint8 type, struct backend_storage_stats * stats, const gchar * path); struct backend_midi_info { gchar company[BE_COMPANY_LEN]; gchar family[BE_FAMILY_LEN]; gchar model[BE_MODEL_LEN]; gchar version[BE_VERSION_LEN]; }; enum backend_type { BE_TYPE_NONE, BE_TYPE_SYSTEM, BE_TYPE_MIDI }; enum sysex_transfer_status { WAITING, SENDING, RECEIVING, FINISHED }; struct sysex_transfer { gboolean active; GMutex mutex; enum sysex_transfer_status status; gint timeout; //Measured in ms. -1 is infinite. gint time; gboolean batch; GByteArray *raw; gint err; }; typedef gint (*t_sysex_transfer) (struct backend *, struct sysex_transfer *); struct backend { // ALSA or RtMidi backend #if defined(ELEKTROID_RTMIDI) struct RtMidiWrapper *inputp; struct RtMidiWrapper *outputp; #else snd_rawmidi_t *inputp; snd_rawmidi_t *outputp; gint npfds; struct pollfd *pfds; #endif guint8 *buffer; ssize_t rx_len; enum backend_type type; struct backend_midi_info midi_info; gchar name[LABEL_MAX]; gchar version[LABEL_MAX]; gchar description[LABEL_MAX]; GMutex mutex; //This must be filled by the concrete connector. const gchar *conn_name; GSList *fs_ops; void *data; t_destroy_data destroy_data; t_sysex_transfer upgrade_os; //This function is device function, not a filesystem function. t_get_storage_stats get_storage_stats; //This function is a device function, not a filesystem function. Several filesystems might share the same memory. }; struct backend_device { enum backend_type type; gchar name[LABEL_MAX]; gchar id[LABEL_MAX]; }; gint backend_init (struct backend *, struct backend_device *); void backend_destroy (struct backend *); ssize_t backend_rx_raw (struct backend *, guint8 *, guint); ssize_t backend_tx_raw (struct backend *, guint8 *, guint); gint backend_tx_sysex_no_status (struct backend *, struct sysex_transfer *); gint backend_tx_sysex (struct backend *, struct sysex_transfer *); gint backend_rx_sysex (struct backend *, struct sysex_transfer *); gint backend_tx (struct backend *, GByteArray *); gint backend_tx_and_rx_sysex_transfer (struct backend *, struct sysex_transfer *, gboolean); GByteArray *backend_tx_and_rx_sysex (struct backend *, GByteArray *, gint); void backend_rx_drain (struct backend *); gboolean backend_check (struct backend *); GArray *backend_get_devices (); const struct fs_operations *backend_get_fs_operations_by_id (struct backend *, guint32); const struct fs_operations *backend_get_fs_operations_by_name (struct backend *, const char *); const gchar *backend_get_fs_name (struct backend *, guint); gdouble backend_get_storage_stats_percent (struct backend_storage_stats *); void backend_destroy_data (struct backend *); void backend_midi_handshake (struct backend *backend); gint backend_program_change (struct backend *, guint8, guint8); gint backend_send_controller (struct backend *backend, guint8 channel, guint8 controller, guint8 value); gint backend_send_note_on (struct backend *backend, guint8 channel, guint8 note, guint8 velocity); gint backend_send_note_off (struct backend *backend, guint8 channel, guint8 note, guint8 velocity); gint backend_send_rpn (struct backend *backend, guint8 channel, guint8 controller_msb, guint8 controller_lsb, guint8 value_msb, guint8 value_lsb); /** * Returns a human readable message for the given error or for the last ocurred error if the underlying API only returs a boolean value. */ const gchar *backend_strerror (struct backend *backend, gint error); enum path_type backend_get_path_type (struct backend *); const gchar *backend_name (); void backend_fill_fs_ops (struct backend *backend, ...); gint backend_init_connector (struct backend *backend, struct backend_device *device, const gchar * name, struct sysex_transfer *sysex_transfer); #endif elektroid-3.2.3/src/backend_alsa.c000066400000000000000000000233421500236517400170320ustar00rootroot00000000000000/* * backend_alsa.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "backend.h" #define BE_DEVICE_NAME "hw:%d,%d" #define BE_DEVICE_NAME_SUB "hw:%d,%d,%d" void backend_destroy_int (struct backend *backend) { gint err; if (backend->inputp) { err = snd_rawmidi_close (backend->inputp); if (err) { error_print ("Error while closing MIDI port: %s", snd_strerror (err)); } backend->inputp = NULL; } if (backend->outputp) { err = snd_rawmidi_close (backend->outputp); if (err) { error_print ("Error while closing MIDI port: %s", snd_strerror (err)); } backend->outputp = NULL; } if (backend->buffer) { g_free (backend->buffer); backend->buffer = NULL; } if (backend->pfds) { g_free (backend->pfds); backend->pfds = NULL; } } gint backend_init_int (struct backend *backend, const gchar *id) { snd_rawmidi_params_t *params; gint err; backend->inputp = NULL; backend->outputp = NULL; backend->pfds = NULL; backend->rx_len = 0; backend->buffer = NULL; backend->buffer = g_malloc (sizeof (guint8) * BE_INT_BUF_LEN); if ((err = snd_rawmidi_open (&backend->inputp, &backend->outputp, id, SND_RAWMIDI_NONBLOCK | SND_RAWMIDI_SYNC)) < 0) { error_print ("Error while opening MIDI port: %s", g_strerror (-err)); goto cleanup; } debug_print (1, "Setting blocking mode..."); if ((err = snd_rawmidi_nonblock (backend->outputp, 0)) < 0) { error_print ("Error while setting blocking mode"); goto cleanup; } if ((err = snd_rawmidi_nonblock (backend->inputp, 1)) < 0) { error_print ("Error while setting blocking mode"); goto cleanup; } backend->npfds = snd_rawmidi_poll_descriptors_count (backend->inputp); backend->pfds = g_malloc (backend->npfds * sizeof (struct pollfd)); snd_rawmidi_poll_descriptors (backend->inputp, backend->pfds, backend->npfds); err = snd_rawmidi_params_malloc (¶ms); if (err) { goto cleanup; } err = snd_rawmidi_params_current (backend->inputp, params); if (err) { goto cleanup_params; } err = snd_rawmidi_params_set_buffer_size (backend->inputp, params, BE_DEV_RING_BUF_LEN); if (err) { goto cleanup_params; } err = snd_rawmidi_params (backend->inputp, params); if (err) { goto cleanup_params; } return 0; cleanup_params: snd_rawmidi_params_free (params); cleanup: backend_destroy (backend); g_free (backend->buffer); return err; } ssize_t backend_tx_raw (struct backend *backend, guint8 *data, guint len) { ssize_t tx_len; if (!backend->outputp) { error_print ("Output port is NULL"); return -ENOTCONN; } snd_rawmidi_read (backend->inputp, NULL, 0); // trigger reading tx_len = snd_rawmidi_write (backend->outputp, data, len); if (tx_len < 0) { error_print ("Error while writing to device: %s", snd_strerror (tx_len)); } return tx_len; } gint backend_tx_sysex_internal (struct backend *backend, struct sysex_transfer *transfer, gboolean update) { ssize_t tx_len; guint total; guint len; guchar *b; if (update) { transfer->err = 0; transfer->active = TRUE; transfer->status = SENDING; } b = transfer->raw->data; total = 0; while (total < transfer->raw->len && transfer->active) { len = transfer->raw->len - total; if (len > BE_MAX_TX_LEN) { len = BE_MAX_TX_LEN; } tx_len = backend_tx_raw (backend, b, len); if (tx_len < 0) { transfer->err = tx_len; break; } b += len; total += len; } if (!transfer->active) { transfer->err = -ECANCELED; } if (!transfer->err && debug_level >= 2) { gchar *text = debug_get_hex_data (debug_level, transfer->raw->data, transfer->raw->len); debug_print (2, "Raw message sent (%d): %s", transfer->raw->len, text); g_free (text); } if (update) { transfer->active = FALSE; transfer->status = FINISHED; } return transfer->err; } void backend_rx_drain_int (struct backend *backend) { snd_rawmidi_drain (backend->inputp); } ssize_t backend_rx_raw (struct backend *backend, guint8 *buffer, guint len) { gint err; ssize_t rx_len; unsigned short revents; debug_print (6, "Polling..."); err = poll (backend->pfds, backend->npfds, BE_POLL_TIMEOUT_MS); if (err == 0) { return 0; } if (err < 0) { error_print ("Error while polling. %s.", g_strerror (errno)); if (errno == EINTR) { return -ECANCELED; } return err; } if ((err = snd_rawmidi_poll_descriptors_revents (backend->inputp, backend->pfds, backend->npfds, &revents)) < 0) { error_print ("Error while getting poll events. %s.", snd_strerror (err)); return err; } if (revents & (POLLERR | POLLHUP)) { return -ENODATA; } if (!(revents & POLLIN)) { return 0; } rx_len = snd_rawmidi_read (backend->inputp, buffer, len); if (rx_len == -EAGAIN) { return 0; } if (rx_len < 0) { error_print ("Error while reading from device: %s", snd_strerror (rx_len)); } return rx_len; } gboolean backend_check_int (struct backend *backend) { return backend->inputp && backend->outputp; } static void backend_get_system_subdevices (snd_ctl_t *ctl, int card, int device, GArray *devices) { snd_rawmidi_info_t *info; const gchar *name; const gchar *sub_name; int subs, subs_in, subs_out; int sub; int err; struct backend_device *backend_device; snd_rawmidi_info_alloca (&info); snd_rawmidi_info_set_device (info, device); snd_rawmidi_info_set_stream (info, SND_RAWMIDI_STREAM_INPUT); err = snd_ctl_rawmidi_info (ctl, info); if (err) { subs_in = 0; } else { subs_in = snd_rawmidi_info_get_subdevices_count (info); } snd_rawmidi_info_set_stream (info, SND_RAWMIDI_STREAM_OUTPUT); err = snd_ctl_rawmidi_info (ctl, info); if (err) { subs_out = 0; } else { subs_out = snd_rawmidi_info_get_subdevices_count (info); } subs = subs_in > subs_out ? subs_in : subs_out; if (!subs) { return; } if (subs_in <= 0 || subs_out <= 0) { return; } for (sub = 0; sub < subs; sub++) { if (sub >= subs_in || sub >= subs_out) //The port needs to be and IO port. { break; } snd_rawmidi_info_set_subdevice (info, sub); snd_rawmidi_info_set_stream (info, SND_RAWMIDI_STREAM_INPUT); err = snd_ctl_rawmidi_info (ctl, info); if (err < 0) { debug_print (1, "Cannot get rawmidi input information %d:%d:%d: %s", card, device, sub, snd_strerror (err)); continue; } snd_rawmidi_info_set_stream (info, sub < subs_in ? SND_RAWMIDI_STREAM_INPUT : SND_RAWMIDI_STREAM_OUTPUT); err = snd_ctl_rawmidi_info (ctl, info); if (err < 0) { debug_print (1, "Cannot get rawmidi output information %d:%d:%d: %s", card, device, sub, snd_strerror (err)); continue; } name = snd_rawmidi_info_get_name (info); sub_name = snd_rawmidi_info_get_subdevice_name (info); debug_print (1, "Adding hw:%d (name '%s', subname '%s')...", card, name, sub_name); backend_device = g_malloc (sizeof (struct backend_device)); backend_device->type = BE_TYPE_MIDI; if (sub == 0 && !*sub_name) { snprintf (backend_device->id, LABEL_MAX, BE_DEVICE_NAME, card, device); snprintf (backend_device->name, LABEL_MAX, BE_DEVICE_NAME ": %s", card, device, name); } else { snprintf (backend_device->id, LABEL_MAX, BE_DEVICE_NAME_SUB, card, device, sub); snprintf (backend_device->name, LABEL_MAX, BE_DEVICE_NAME_SUB ": %s", card, device, sub, sub_name); } g_array_append_vals (devices, backend_device, 1); if (sub == 0 && !*sub_name) { break; } } } static void backend_fill_card_devices (gint card, GArray *devices) { snd_ctl_t *ctl; gchar name[32]; gint device; gint err; sprintf (name, "hw:%d", card); if ((err = snd_ctl_open (&ctl, name, 0)) < 0) { error_print ("Cannot open control for card %d: %s", card, snd_strerror (err)); return; } device = -1; while (!(err = snd_ctl_rawmidi_next_device (ctl, &device)) && device >= 0) { backend_get_system_subdevices (ctl, card, device, devices); } if (device >= 0 && err < 0) { error_print ("Cannot determine device number %d: %s", device, snd_strerror (err)); } snd_ctl_close (ctl); } void backend_fill_devices_array (GArray *devices) { gint card, err; card = -1; while (!(err = snd_card_next (&card)) && card >= 0) { backend_fill_card_devices (card, devices); } if (card >= 0 && err < 0) { error_print ("Cannot determine card number %d: %s", card, snd_strerror (err)); } } const gchar * backend_strerror (struct backend *backend, gint err) { return snd_strerror (err); } const gchar * backend_name () { return "ALSA"; } elektroid-3.2.3/src/backend_rtmidi.c000066400000000000000000000173111500236517400174010ustar00rootroot00000000000000/* * backend_rtmidi.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "backend.h" #include "rtmidi_c.h" #if defined(__linux__) #define ELEKTROID_RTMIDI_API RTMIDI_API_LINUX_ALSA #define FIRST_OUTPUT_PORT 1 //Skip Midi Through #elif defined(__APPLE__) && defined(__MACH__) #define ELEKTROID_RTMIDI_API RTMIDI_API_MACOSX_CORE #define FIRST_OUTPUT_PORT 0 #else #define ELEKTROID_RTMIDI_API RTMIDI_API_WINDOWS_MM #define FIRST_OUTPUT_PORT 1 //Skip Microsoft GS Wavetable Synth 0 #endif #define INPUT_OUTPUT_SEPARATOR " :: " void backend_destroy_int (struct backend *backend) { if (backend->inputp) { rtmidi_close_port (backend->inputp); rtmidi_in_free (backend->inputp); backend->inputp = NULL; } if (backend->outputp) { rtmidi_close_port (backend->outputp); rtmidi_in_free (backend->outputp); backend->outputp = NULL; } if (backend->buffer) { g_free (backend->buffer); backend->buffer = NULL; } } gint backend_init_int (struct backend *backend, const gchar *id) { struct RtMidiWrapper *inputp; struct RtMidiWrapper *outputp; guint iports, oports, err = 0; gchar iportname[LABEL_MAX]; gchar oportname[LABEL_MAX]; gint iportnamelen, oportnamelen; backend->inputp = NULL; backend->outputp = NULL; backend->buffer = NULL; if (!(inputp = rtmidi_in_create_default ())) { return -ENODEV; } if (!(outputp = rtmidi_out_create_default ())) { err = -ENODEV; goto cleanup_input; } iports = rtmidi_get_port_count (inputp); oports = rtmidi_get_port_count (outputp); for (guint i = 0; i < iports; i++) { if (rtmidi_get_port_name (inputp, i, NULL, &iportnamelen)) { goto cleanup_output; } if (rtmidi_get_port_name (inputp, i, iportname, &iportnamelen) < 0) { goto cleanup_output; } for (guint j = FIRST_OUTPUT_PORT; j < oports; j++) { if (rtmidi_get_port_name (outputp, j, NULL, &oportnamelen)) { goto cleanup_output; } if (rtmidi_get_port_name (outputp, j, oportname, &oportnamelen) < 0) { goto cleanup_output; } #if defined(__linux__) if (!strcmp (iportname, oportname) && !strcmp (iportname, id)) #else guint iportnamelen = strlen (iportname); if (!strncmp (id, iportname, iportnamelen) && !strcmp (id + iportnamelen + strlen (INPUT_OUTPUT_SEPARATOR), oportname)) #endif { backend->inputp = rtmidi_in_create (ELEKTROID_RTMIDI_API, PACKAGE_NAME, BE_INT_BUF_LEN); rtmidi_in_ignore_types (backend->inputp, false, true, true); rtmidi_open_port (backend->inputp, i, PACKAGE_NAME); backend->outputp = rtmidi_out_create (ELEKTROID_RTMIDI_API, PACKAGE_NAME); rtmidi_open_port (backend->outputp, j, PACKAGE_NAME); backend->rx_len = 0; backend->buffer = g_malloc (sizeof (guint8) * BE_INT_BUF_LEN); goto cleanup_output; } } } cleanup_output: rtmidi_close_port (inputp); rtmidi_in_free (inputp); cleanup_input: rtmidi_close_port (outputp); rtmidi_out_free (outputp); return err; } gint backend_tx_sysex_internal (struct backend *backend, struct sysex_transfer *transfer, gboolean update) { if (update) { transfer->err = 0; transfer->active = TRUE; transfer->status = SENDING; } rtmidi_out_send_message (backend->outputp, transfer->raw->data, transfer->raw->len); transfer->err = backend->outputp->ok ? 0 : -EIO; if (!transfer->err && debug_level >= 2) { gchar *text = debug_get_hex_data (debug_level, transfer->raw->data, transfer->raw->len); debug_print (2, "Raw message sent (%d): %s", transfer->raw->len, text); g_free (text); } if (update) { transfer->active = FALSE; transfer->status = FINISHED; } return transfer->err; } ssize_t backend_tx_raw (struct backend *backend, guint8 *data, guint len) { struct sysex_transfer transfer; transfer.raw = g_byte_array_sized_new (len); g_byte_array_append (transfer.raw, data, len); backend_tx_sysex_internal (backend, &transfer, TRUE); return transfer.err ? transfer.err : len; } void backend_rx_drain_int (struct backend *backend) { while (1) { size_t len = BE_INT_BUF_LEN; rtmidi_in_get_message (backend->inputp, backend->buffer, &len); if (len == 0) { break; } } } ssize_t backend_rx_raw (struct backend *backend, guint8 *buffer, guint len) { size_t size = len; rtmidi_in_get_message (backend->inputp, buffer, &size); if (!backend->inputp->ok) { return -EIO; } if (!size) { usleep (BE_POLL_TIMEOUT_MS * 1000); } return size; } gboolean backend_check_int (struct backend *backend) { return backend->inputp && backend->outputp; } void backend_fill_devices_array (GArray *devices) { struct RtMidiWrapper *inputp; struct RtMidiWrapper *outputp; guint iports, oports; gchar iportname[LABEL_MAX]; gchar oportname[LABEL_MAX]; gint iportnamelen, oportnamelen; struct backend_device *backend_device; if (!(inputp = rtmidi_in_create_default ())) { return; } if (!(outputp = rtmidi_out_create_default ())) { goto cleanup_input; } iports = rtmidi_get_port_count (inputp); oports = rtmidi_get_port_count (outputp); for (guint i = 0; i < iports; i++) { if (rtmidi_get_port_name (inputp, i, NULL, &iportnamelen)) { goto cleanup_output; } if (rtmidi_get_port_name (inputp, i, iportname, &iportnamelen) < 0) { goto cleanup_output; } for (guint j = FIRST_OUTPUT_PORT; j < oports; j++) { if (rtmidi_get_port_name (outputp, j, NULL, &oportnamelen)) { goto cleanup_output; } if (rtmidi_get_port_name (outputp, j, oportname, &oportnamelen) < 0) { goto cleanup_output; } debug_print (3, "Checking I/O availability (%s == %s)...", iportname, oportname); #if defined(__linux__) if (!strcmp (iportname, oportname)) { backend_device = g_malloc (sizeof (struct backend_device)); backend_device->type = BE_TYPE_MIDI; snprintf (backend_device->id, LABEL_MAX, "%s", iportname); snprintf (backend_device->name, LABEL_MAX, "%s", iportname); g_array_append_vals (devices, backend_device, 1); } #else //We consider the cartesian product of inputs and outputs as the available ports. backend_device = g_malloc (sizeof (struct backend_device)); backend_device->type = BE_TYPE_MIDI; snprintf (backend_device->id, LABEL_MAX, "%s%s%s", iportname, INPUT_OUTPUT_SEPARATOR, oportname); snprintf (backend_device->name, LABEL_MAX, "%s%s%s", iportname, INPUT_OUTPUT_SEPARATOR, oportname); g_array_append_vals (devices, backend_device, 1); #endif } } cleanup_output: rtmidi_close_port (inputp); rtmidi_in_free (inputp); cleanup_input: rtmidi_close_port (outputp); rtmidi_out_free (outputp); } const gchar * backend_strerror (struct backend *backend, gint err) { return backend->outputp->msg ? backend->outputp->msg : backend->inputp->msg; } const gchar * backend_name () { return "RtMidi"; } elektroid-3.2.3/src/browser.c000066400000000000000000001163241500236517400161310ustar00rootroot00000000000000/* * browser.c * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "browser.h" #include "editor.h" #include "local.h" #include "backend.h" #include "sample.h" #include "maction.h" #define OTHER_BROWSER(b) (b == &local_browser ? &remote_browser : &local_browser) #define BROWSER_HAS_EDITOR(b) ((b)->fs_ops && (b)->fs_ops->options & FS_OPTION_SAMPLE_EDITOR ? TRUE : FALSE) #define EDITOR_IS_AVAILABLE BROWSER_HAS_EDITOR(&local_browser) #define DND_TIMEOUT 800 #define DIR_ICON "elektroid-folder-symbolic" struct browser local_browser; struct browser remote_browser; extern struct editor editor; struct browser_add_dentry_item_data { struct browser *browser; struct item item; const gchar *icon; gchar *rel_path; }; gboolean elektroid_check_backend (gboolean); static gboolean browser_check_backend () { return elektroid_check_backend (FALSE); } static void browser_widget_set_sensitive (gpointer widget, gpointer data) { gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE); } static void browser_widget_set_insensitive (gpointer widget, gpointer data) { gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE); } gint browser_sort_by_name (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data) { struct item itema; struct item itemb; gint ret = 0; browser_set_item (model, a, &itema); browser_set_item (model, b, &itemb); if (itema.type == itemb.type) { #if defined(__MINGW32__) | defined(__MINGW64__) ret = strcmp (itema.name, itemb.name); #else ret = g_utf8_collate (itema.name, itemb.name); #endif } else { ret = itema.type > itemb.type; } return ret; } gint browser_sort_by_id (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data) { struct item itema; struct item itemb; gint ret = 0; browser_set_item (model, a, &itema); browser_set_item (model, b, &itemb); if (itema.type == itemb.type) { ret = itema.id > itemb.id; } else { ret = itema.type > itemb.type; } return ret; } void browser_set_item (GtkTreeModel *model, GtkTreeIter *iter, struct item *item) { gchar *name; gtk_tree_model_get (model, iter, BROWSER_LIST_STORE_TYPE_FIELD, &item->type, BROWSER_LIST_STORE_NAME_FIELD, &name, BROWSER_LIST_STORE_SIZE_FIELD, &item->size, BROWSER_LIST_STORE_ID_FIELD, &item->id, -1); snprintf (item->name, LABEL_MAX, "%s", name); g_free (name); } gint browser_set_selected_row_iter (struct browser *browser, GtkTreeIter *iter) { gint index, *indices; GtkTreeModel *model; GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view)); GList *paths = gtk_tree_selection_get_selected_rows (selection, &model); GtkTreePath *row = g_list_nth_data (paths, 0); indices = gtk_tree_path_get_indices (row); index = *indices; gtk_tree_model_get_iter (model, iter, row); g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free); return index; } static void browser_clear (struct browser *browser) { GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (browser->view)); GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view)); gtk_entry_set_text (browser->dir_entry, browser->dir ? browser->dir : ""); g_signal_handlers_block_by_func (selection, G_CALLBACK (browser_selection_changed), browser); gtk_list_store_clear (list_store); g_signal_handlers_unblock_by_func (selection, G_CALLBACK (browser_selection_changed), browser); } void browser_refresh (GtkWidget *object, gpointer data) { struct browser *browser = data; browser_load_dir (browser); } void browser_go_up (GtkWidget *object, gpointer data) { struct browser *browser = data; g_mutex_lock (&browser->mutex); if (!browser->loading) { if (strcmp (browser->dir, "/")) { gchar *new_path = g_path_get_dirname (browser->dir); strcpy (browser->dir, new_path); g_free (new_path); } } g_mutex_unlock (&browser->mutex); browser_load_dir (browser); } void browser_item_activated (GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) { GtkTreeIter iter; struct item item; struct browser *browser = data; GtkTreeModel *model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view)); gtk_tree_model_get_iter (model, &iter, path); browser_set_item (model, &iter, &item); if (item.type == ITEM_TYPE_DIR) { enum path_type type = backend_get_path_type (browser->backend); gchar *new_dir = path_chain (type, browser->dir, item.name); g_free (browser->dir); browser->dir = new_dir; browser_close_search (NULL, browser); //This triggers a refresh } } gint browser_get_selected_items_count (struct browser *browser) { GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view)); return gtk_tree_selection_count_selected_rows (selection); } void browser_clear_selection (struct browser *browser) { GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view)); g_signal_handlers_block_by_func (selection, G_CALLBACK (browser_selection_changed), browser); gtk_tree_selection_unselect_all (selection); g_signal_handlers_unblock_by_func (selection, G_CALLBACK (browser_selection_changed), browser); browser->last_selected_index = -1; } gchar * browser_get_item_path (struct browser *browser, struct item *item) { gchar *filename = item_get_filename (item, browser->fs_ops->options); enum path_type type = backend_get_path_type (browser->backend); gchar *path = path_chain (type, browser->dir, filename); debug_print (1, "Using %s path for item %s (id %d)...", path, item->name, item->id); g_free (filename); return path; } static gint browser_add_dentry_item (gpointer data) { gchar *hsize; gdouble time; gchar *name; gchar label[LABEL_MAX]; GtkTreeIter iter, note_iter; struct browser_add_dentry_item_data *add_data = data; struct browser *browser = add_data->browser; struct item *item = &add_data->item; GValue v = G_VALUE_INIT; GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (browser->view)); GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view)); hsize = get_human_size (item->size, TRUE); gtk_list_store_insert_with_values (list_store, &iter, -1, BROWSER_LIST_STORE_ICON_FIELD, item->type == ITEM_TYPE_DIR ? DIR_ICON : add_data->icon, BROWSER_LIST_STORE_NAME_FIELD, add_data->rel_path, BROWSER_LIST_STORE_SIZE_FIELD, item->size, BROWSER_LIST_STORE_SIZE_STR_FIELD, hsize, BROWSER_LIST_STORE_TYPE_FIELD, item->type, BROWSER_LIST_STORE_ID_FIELD, item->id, -1); g_free (hsize); if (browser->fs_ops->options & FS_OPTION_SLOT_STORAGE) { if (browser->fs_ops->get_slot) { gchar *s = browser->fs_ops->get_slot (item, browser->backend); g_value_init (&v, G_TYPE_STRING); g_value_set_string (&v, s); gtk_list_store_set_value (list_store, &iter, BROWSER_LIST_STORE_SLOT_FIELD, &v); g_free (s); g_value_unset (&v); } } if (item->type == ITEM_TYPE_FILE && browser->fs_ops->options & FS_OPTION_SHOW_SAMPLE_COLUMNS && item->sample_info.frames) { snprintf (label, LABEL_MAX, "%u", item->sample_info.frames); g_value_init (&v, G_TYPE_STRING); g_value_set_string (&v, label); gtk_list_store_set_value (list_store, &iter, BROWSER_LIST_STORE_SAMPLE_FRAMES_FIELD, &v); g_value_unset (&v); snprintf (label, LABEL_MAX, "%.5g kHz", item->sample_info.rate / 1000.0); g_value_init (&v, G_TYPE_STRING); g_value_set_string (&v, label); gtk_list_store_set_value (list_store, &iter, BROWSER_LIST_STORE_SAMPLE_RATE_FIELD, &v); g_value_unset (&v); time = item->sample_info.frames / (gdouble) item->sample_info.rate; if (time >= 60) { snprintf (label, LABEL_MAX, "%.4g %s", time / 60.0, _("min.")); } else { snprintf (label, LABEL_MAX, "%.3g s", time); } g_value_init (&v, G_TYPE_STRING); g_value_set_string (&v, label); gtk_list_store_set_value (list_store, &iter, BROWSER_LIST_STORE_SAMPLE_TIME_FIELD, &v); g_value_unset (&v); snprintf (label, LABEL_MAX, "%s, %s", sample_get_format (&item->sample_info), sample_get_subtype (&item->sample_info)); g_value_init (&v, G_TYPE_STRING); g_value_set_string (&v, label); gtk_list_store_set_value (list_store, &iter, BROWSER_LIST_STORE_SAMPLE_FORMAT_FIELD, &v); g_value_unset (&v); snprintf (label, LABEL_MAX, "%u", item->sample_info.channels); g_value_init (&v, G_TYPE_STRING); g_value_set_string (&v, label); gtk_list_store_set_value (list_store, &iter, BROWSER_LIST_STORE_SAMPLE_CHANNELS_FIELD, &v); g_value_unset (&v); gtk_tree_model_get_iter_first (GTK_TREE_MODEL (editor.notes_list_store), ¬e_iter); if (item->sample_info.midi_note <= 127) { for (gint i = 0; i < item->sample_info.midi_note; i++) { gtk_tree_model_iter_next (GTK_TREE_MODEL (editor.notes_list_store), ¬e_iter); } gtk_tree_model_get_value (GTK_TREE_MODEL (editor.notes_list_store), ¬e_iter, 0, &v); } else { g_value_init (&v, G_TYPE_STRING); g_value_set_string (&v, "-"); } gtk_list_store_set_value (list_store, &iter, BROWSER_LIST_STORE_SAMPLE_MIDI_NOTE_FIELD, &v); g_value_unset (&v); } if (item->type == ITEM_TYPE_FILE && browser->fs_ops->options & FS_OPTION_SHOW_INFO_COLUMN) { g_value_init (&v, G_TYPE_STRING); g_value_set_string (&v, item->object_info); gtk_list_store_set_value (list_store, &iter, BROWSER_LIST_STORE_INFO_FIELD, &v); g_value_unset (&v); } if (editor.audio.path && editor.browser == browser) { name = path_chain (PATH_SYSTEM, browser->dir, add_data->rel_path); if (!strcmp (editor.audio.path, name)) { g_signal_handlers_block_by_func (selection, G_CALLBACK (browser_selection_changed), browser); gtk_tree_selection_select_iter (selection, &iter); g_signal_handlers_unblock_by_func (selection, G_CALLBACK (browser_selection_changed), browser); } g_free (name); } g_free (add_data->rel_path); g_free (add_data); return G_SOURCE_REMOVE; } static gboolean browser_load_dir_runner_hide_spinner (gpointer data) { struct browser *browser = data; gtk_spinner_stop (GTK_SPINNER (browser->spinner)); gtk_stack_set_visible_child_name (GTK_STACK (browser->list_stack), "list"); return FALSE; } static gboolean browser_load_dir_runner_show_spinner_and_lock_browser (gpointer data) { struct browser *browser = data; g_slist_foreach (browser->sensitive_widgets, browser_widget_set_insensitive, NULL); gtk_stack_set_visible_child_name (GTK_STACK (browser->list_stack), "spinner"); gtk_spinner_start (GTK_SPINNER (browser->spinner)); return FALSE; } static void browser_wait (struct browser *browser) { if (browser->thread) { g_thread_join (browser->thread); browser->thread = NULL; //Wait for every pending call to browser_add_dentry_item scheduled from the thread while (gtk_events_pending ()) { gtk_main_iteration (); } } } static gboolean browser_load_dir_runner_update_ui (gpointer data) { struct browser *browser = data; GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view)); gboolean active = BROWSER_IS_SYSTEM (browser); browser_wait (browser); if (browser->check_callback) { browser->check_callback (); } gtk_tree_view_columns_autosize (browser->view); if (!browser->search_mode) { gtk_widget_grab_focus (GTK_WIDGET (browser->view)); notifier_update_dir (browser->notifier, active); } //Unlock browser g_slist_foreach (browser->sensitive_widgets, browser_widget_set_sensitive, NULL); if (browser_get_selected_items_count (browser)) { GList *list = gtk_tree_selection_get_selected_rows (selection, NULL); g_signal_handlers_block_by_func (selection, G_CALLBACK (browser_selection_changed), browser); gtk_tree_view_set_cursor (browser->view, list->data, NULL, FALSE); g_signal_handlers_unblock_by_func (selection, G_CALLBACK (browser_selection_changed), browser); g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free); } else { GtkTreeModel *model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view)); if (gtk_tree_model_iter_n_children (model, NULL)) { GtkTreePath *first = gtk_tree_path_new_first (); gtk_tree_view_scroll_to_cell (browser->view, first, NULL, FALSE, 0, 0); gtk_tree_path_free (first); gtk_widget_grab_focus (GTK_WIDGET (browser->view)); } //If editor.audio.path is empty is a recording buffer. if (editor.browser == browser && editor.audio.path) { editor_reset (&editor, NULL); } } g_mutex_lock (&browser->mutex); browser->loading = FALSE; g_mutex_unlock (&browser->mutex); return FALSE; } static void browser_iterate_dir_add (struct browser *browser, struct item_iterator *iter, const gchar *icon, struct item *item, gchar *rel_path) { if (browser->filter) { if (browser->fs_ops->options & FS_OPTION_SHOW_INFO_COLUMN) { if (!g_str_match_string (browser->filter, iter->item.name, TRUE) && !g_str_match_string (browser->filter, iter->item.object_info, TRUE)) { return; } } else { if (!g_str_match_string (browser->filter, iter->item.name, TRUE)) { return; } } } struct browser_add_dentry_item_data *data = g_malloc (sizeof (struct browser_add_dentry_item_data)); data->browser = browser; memcpy (&data->item, &iter->item, sizeof (struct item)); data->icon = icon; data->rel_path = rel_path; g_idle_add (browser_add_dentry_item, data); } static void browser_iterate_dir (struct browser *browser, struct item_iterator *iter, const gchar *icon) { gboolean loading = TRUE; while (loading && !item_iterator_next (iter)) { browser_iterate_dir_add (browser, iter, icon, &iter->item, strdup (iter->item.name)); g_mutex_lock (&browser->mutex); loading = browser->loading; g_mutex_unlock (&browser->mutex); } } static void browser_iterate_dir_recursive (struct browser *browser, const gchar *rel_dir, struct item_iterator *iter, const gchar *icon, const gchar **extensions) { gint err; gchar *child_dir, *child_rel_dir; struct item_iterator child_iter; gboolean loading = TRUE; enum path_type type = backend_get_path_type (browser->backend); while (loading && !item_iterator_next (iter)) { child_rel_dir = path_chain (type, rel_dir, iter->item.name); browser_iterate_dir_add (browser, iter, icon, &iter->item, strdup (child_rel_dir)); if (iter->item.type == ITEM_TYPE_DIR) { child_dir = path_chain (type, browser->dir, child_rel_dir); err = browser->fs_ops->readdir (browser->backend, &child_iter, child_dir, extensions); if (!err) { browser_iterate_dir_recursive (browser, child_rel_dir, &child_iter, icon, extensions); item_iterator_free (&child_iter); } g_free (child_dir); } g_free (child_rel_dir); g_mutex_lock (&browser->mutex); loading = browser->loading; g_mutex_unlock (&browser->mutex); } } static gpointer browser_load_dir_runner (gpointer data) { gint err; struct browser *browser = data; struct item_iterator iter; const gchar **exts; const gchar *icon; gboolean search_mode; if (browser == &remote_browser) { exts = remote_browser.fs_ops->get_exts (remote_browser.backend, remote_browser.fs_ops); icon = remote_browser.fs_ops->gui_icon; } else { if (remote_browser.fs_ops) { exts = remote_browser.fs_ops->get_exts (remote_browser.backend, remote_browser.fs_ops); if (remote_browser.fs_ops->upload) { icon = remote_browser.fs_ops->gui_icon; } else { icon = local_browser.fs_ops->gui_icon; } } else { //If !remote_browser.fs_ops, only FS_LOCAL_SAMPLE_OPERATIONS is used, which implements get_exts. exts = local_browser.fs_ops->get_exts (remote_browser.backend, remote_browser.fs_ops); icon = local_browser.fs_ops->gui_icon; } } g_idle_add (browser_load_dir_runner_show_spinner_and_lock_browser, browser); err = browser->fs_ops->readdir (browser->backend, &iter, browser->dir, exts); g_idle_add (browser_load_dir_runner_hide_spinner, browser); if (err) { error_print ("Error while opening '%s' dir", browser->dir); goto end; } g_mutex_lock (&browser->mutex); search_mode = browser->search_mode; g_mutex_unlock (&browser->mutex); if (search_mode) { browser_iterate_dir_recursive (browser, "", &iter, icon, exts); } else { browser_iterate_dir (browser, &iter, icon); } item_iterator_free (&iter); end: g_idle_add (browser_load_dir_runner_update_ui, browser); return NULL; } gboolean browser_load_dir (gpointer data) { struct browser *browser = data; g_mutex_lock (&browser->mutex); if (browser->loading) { g_mutex_unlock (&browser->mutex); debug_print (1, "Browser already loading. Skipping load..."); return FALSE; } else { browser->last_selected_index = -1; browser->loading = TRUE; } g_mutex_unlock (&browser->mutex); browser_clear (browser); if (!browser->fs_ops || !browser->fs_ops->readdir) { return FALSE; } browser->thread = g_thread_new ("browser_thread", browser_load_dir_runner, browser); return FALSE; } gboolean browser_load_dir_if_needed (gpointer data) { struct browser *browser = data; if ((browser->backend && browser->backend->type == BE_TYPE_MIDI) || !browser->notifier->monitor) { browser_load_dir (browser); } return FALSE; } static void browser_update_fs_sorting_options (struct browser *browser) { GtkTreeSortable *sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model (browser->view)); gboolean slot = browser->fs_ops && browser->fs_ops->options & FS_OPTION_SLOT_STORAGE; if (browser->search_mode || !slot) { gtk_tree_sortable_set_sort_func (sortable, BROWSER_LIST_STORE_NAME_FIELD, browser_sort_by_name, NULL, NULL); gtk_tree_sortable_set_sort_column_id (sortable, BROWSER_LIST_STORE_NAME_FIELD, GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID); } else { gtk_tree_sortable_set_sort_column_id (sortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID); } } void browser_update_fs_options (struct browser *browser) { gtk_widget_set_visible (browser->add_dir_button, !browser->fs_ops || browser->fs_ops->mkdir); gtk_widget_set_visible (browser->search_button, !browser->fs_ops || browser->fs_ops->options & FS_OPTION_ALLOW_SEARCH); gtk_widget_set_sensitive (browser->refresh_button, browser->fs_ops && browser->fs_ops->readdir); gtk_widget_set_sensitive (browser->up_button, browser->fs_ops && browser->fs_ops->readdir); browser_update_fs_sorting_options (browser); browser->set_columns_visibility (); browser->set_popup_menuitems_visibility (); } static void browser_init (struct browser *browser) { notifier_init (&browser->notifier, browser); } void browser_destroy (struct browser *browser) { if (browser->thread) { browser_reset (&remote_browser); // This waits too. } notifier_destroy (browser->notifier); g_slist_free (browser->sensitive_widgets); } static void browser_cancel_search (struct browser *browser) { gtk_stack_set_visible_child_name (GTK_STACK (browser->buttons_stack), "buttons"); g_mutex_lock (&browser->mutex); browser->loading = FALSE; browser->search_mode = FALSE; g_mutex_unlock (&browser->mutex); browser_wait (browser); gtk_entry_set_text (GTK_ENTRY (browser->search_entry), ""); browser->filter = NULL; } void browser_reset (struct browser *browser) { browser_cancel_search (browser); //This cancels load too. browser->fs_ops = NULL; g_free (browser->dir); browser->dir = NULL; browser_clear (browser); } void browser_clear_dnd_function (struct browser *browser) { if (browser->dnd_timeout_function_id) { g_source_remove (browser->dnd_timeout_function_id); browser->dnd_timeout_function_id = 0; } } void browser_set_dnd_function (struct browser *browser, GSourceFunc function) { browser_clear_dnd_function (browser); browser->dnd_timeout_function_id = g_timeout_add (DND_TIMEOUT, function, browser); } static void browser_set_columns_visibility (struct browser *browser) { gboolean sample_columns, info_column; if (browser->fs_ops) { sample_columns = (browser->fs_ops->options & FS_OPTION_SHOW_SAMPLE_COLUMNS) != 0; info_column = (browser->fs_ops->options & FS_OPTION_SHOW_INFO_COLUMN) != 0; } else { sample_columns = FALSE; info_column = FALSE; } gtk_tree_view_column_set_visible (browser->tree_view_sample_frames_column, sample_columns); gtk_tree_view_column_set_visible (browser->tree_view_sample_rate_column, sample_columns); gtk_tree_view_column_set_visible (browser->tree_view_sample_duration_column, sample_columns); gtk_tree_view_column_set_visible (browser->tree_view_sample_channels_column, sample_columns); gtk_tree_view_column_set_visible (browser->tree_view_sample_bits_column, sample_columns); gtk_tree_view_column_set_visible (browser->tree_view_sample_midi_note_column, sample_columns); gtk_tree_view_column_set_visible (browser->tree_view_info_column, info_column); } static inline void browser_local_set_columns_visibility () { browser_set_columns_visibility (&local_browser); } static void browser_remote_set_columns_visibility () { browser_set_columns_visibility (&remote_browser); if (remote_browser.fs_ops) { gtk_tree_view_column_set_visible (remote_browser.tree_view_id_column, remote_browser.fs_ops->options & FS_OPTION_SHOW_ID_COLUMN); gtk_tree_view_column_set_visible (remote_browser.tree_view_slot_column, remote_browser.fs_ops->options & FS_OPTION_SHOW_SLOT_COLUMN); gtk_tree_view_column_set_visible (remote_browser.tree_view_size_column, remote_browser.fs_ops->options & FS_OPTION_SHOW_SIZE_COLUMN); } else { gtk_tree_view_column_set_visible (remote_browser.tree_view_id_column, FALSE); gtk_tree_view_column_set_visible (remote_browser.tree_view_slot_column, FALSE); gtk_tree_view_column_set_visible (remote_browser.tree_view_size_column, FALSE); } } void browser_open_search (GtkWidget *widget, gpointer data) { struct browser *browser = data; gtk_stack_set_visible_child_name (GTK_STACK (browser->buttons_stack), "search"); g_mutex_lock (&browser->mutex); browser->loading = FALSE; browser->search_mode = TRUE; g_mutex_unlock (&browser->mutex); browser_wait (browser); browser_clear (browser); browser_update_fs_sorting_options (data); } void browser_close_search (GtkSearchEntry *entry, gpointer data) { struct browser *browser = data; browser_cancel_search (browser); browser_update_fs_sorting_options (browser); browser_refresh (NULL, browser); } void browser_search_changed (GtkSearchEntry *entry, gpointer data) { struct browser *browser = data; const gchar *filter = gtk_entry_get_text (GTK_ENTRY (entry)); g_mutex_lock (&browser->mutex); browser->loading = FALSE; g_mutex_unlock (&browser->mutex); browser_wait (browser); browser_clear (browser); usleep (250000); if (strlen (filter)) { browser->filter = filter; browser_refresh (NULL, browser); } } static void browser_clear_other_browser_selection_if_system (struct browser *browser) { struct browser *other = OTHER_BROWSER (browser); if (BROWSER_IS_SYSTEM (other)) { browser_clear_selection (other); } } static void browser_check_selection (gpointer data) { gint index; struct item item; GtkTreeIter iter; GtkTreeModel *model; struct browser *browser = data; gint count = browser_get_selected_items_count (browser); gboolean sel_impl = browser->fs_ops && browser->fs_ops->select_item ? TRUE : FALSE; if (count != 1) { if (EDITOR_IS_AVAILABLE && BROWSER_IS_SYSTEM (browser)) { browser_clear_other_browser_selection_if_system (browser); editor_reset (&editor, NULL); } browser->last_selected_index = -1; return; } index = browser_set_selected_row_iter (browser, &iter); model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view)); browser_set_item (model, &iter, &item); if (item.type == ITEM_TYPE_DIR) { return; } if (index == browser->last_selected_index) { return; } browser->last_selected_index = index; if (EDITOR_IS_AVAILABLE && BROWSER_IS_SYSTEM (browser)) { enum path_type type = backend_get_path_type (browser->backend); gchar *sample_path = path_chain (type, browser->dir, item.name); browser_clear_other_browser_selection_if_system (browser); editor_reset (&editor, browser); editor_start_load_thread (&editor, sample_path); } if (!sel_impl) { return; } remote_browser.fs_ops->select_item (browser->backend, browser->dir, &item); } void browser_local_set_popup_visibility () { gboolean ul_avail = remote_browser.fs_ops && !(remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE) && remote_browser.fs_ops->upload; gboolean edit_avail = local_browser.fs_ops->options & FS_OPTION_SAMPLE_EDITOR; gtk_widget_set_visible (local_browser.transfer_menuitem, ul_avail); gtk_widget_set_visible (local_browser.play_separator, ul_avail); gtk_widget_set_visible (local_browser.play_menuitem, edit_avail); gtk_widget_set_visible (local_browser.options_separator, edit_avail); } static void browser_local_set_popup_sensitivity (gint count, gboolean file) { gboolean ul_avail = remote_browser.fs_ops && !(remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE) && remote_browser.fs_ops->upload; gboolean editing = editor.browser == &local_browser; gtk_widget_set_sensitive (local_browser.transfer_menuitem, count > 0 && ul_avail); gtk_widget_set_sensitive (local_browser.play_menuitem, file && editing); gtk_widget_set_sensitive (local_browser.open_menuitem, file); gtk_widget_set_sensitive (local_browser.show_menuitem, count <= 1); gtk_widget_set_sensitive (local_browser.rename_menuitem, count == 1); gtk_widget_set_sensitive (local_browser.delete_menuitem, count > 0); } void browser_remote_set_popup_visibility () { gboolean dl_impl = remote_browser.fs_ops && remote_browser.fs_ops->download ? TRUE : FALSE; gboolean edit_avail = remote_browser.fs_ops && remote_browser.fs_ops->options & FS_OPTION_SAMPLE_EDITOR; gboolean system = remote_browser.fs_ops && remote_browser.backend->type == BE_TYPE_SYSTEM; gtk_widget_set_visible (remote_browser.transfer_menuitem, dl_impl); gtk_widget_set_visible (remote_browser.play_separator, dl_impl); gtk_widget_set_visible (remote_browser.play_menuitem, system && edit_avail); gtk_widget_set_visible (remote_browser.options_separator, system && edit_avail); gtk_widget_set_visible (remote_browser.open_menuitem, system); gtk_widget_set_visible (remote_browser.show_menuitem, system); gtk_widget_set_visible (remote_browser.actions_separator, system); } static void browser_remote_set_popup_sensitivity (gint count, gboolean file) { gboolean dl_impl = remote_browser.fs_ops && remote_browser.fs_ops->download ? TRUE : FALSE; gboolean ren_impl = remote_browser.fs_ops && remote_browser.fs_ops->rename ? TRUE : FALSE; gboolean del_impl = remote_browser.fs_ops && remote_browser.fs_ops->delete ? TRUE : FALSE; gboolean editing = editor.browser == &remote_browser; gboolean system = remote_browser.fs_ops && remote_browser.backend->type == BE_TYPE_SYSTEM; gtk_widget_set_sensitive (remote_browser.transfer_menuitem, count > 0 && dl_impl); gtk_widget_set_sensitive (remote_browser.play_menuitem, file && editing); gtk_widget_set_sensitive (remote_browser.open_menuitem, file); gtk_widget_set_sensitive (remote_browser.show_menuitem, count <= 1 && system); gtk_widget_set_sensitive (remote_browser.rename_menuitem, count == 1 && ren_impl); gtk_widget_set_sensitive (remote_browser.delete_menuitem, count > 0 && del_impl); } static void browser_setup_popup_sensitivity (struct browser *browser) { struct item item; GtkTreeIter iter; gboolean file = FALSE; gint count = browser_get_selected_items_count (browser); GtkTreeModel *model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view)); if (count == 1) { browser_set_selected_row_iter (browser, &iter); browser_set_item (model, &iter, &item); file = item.type == ITEM_TYPE_FILE; } if (browser == &local_browser) { browser_local_set_popup_sensitivity (count, file); } else { browser_remote_set_popup_sensitivity (count, file); } } void browser_selection_changed (GtkTreeSelection *selection, gpointer data) { struct browser *browser = data; browser_check_selection (browser); browser_setup_popup_sensitivity (browser); } void browser_local_init (struct browser *browser, GtkBuilder *builder, gchar *local_dir) { browser->name = "local"; browser->view = GTK_TREE_VIEW (gtk_builder_get_object (builder, "local_tree_view")); browser->buttons_stack = GTK_WIDGET (gtk_builder_get_object (builder, "local_buttons_stack")); browser->up_button = GTK_WIDGET (gtk_builder_get_object (builder, "local_up_button")); browser->add_dir_button = GTK_WIDGET (gtk_builder_get_object (builder, "local_add_dir_button")); browser->refresh_button = GTK_WIDGET (gtk_builder_get_object (builder, "local_refresh_button")); browser->search_button = GTK_WIDGET (gtk_builder_get_object (builder, "local_search_button")); browser->search_entry = GTK_WIDGET (gtk_builder_get_object (builder, "local_search_entry")); browser->dir_entry = GTK_ENTRY (gtk_builder_get_object (builder, "local_dir_entry")); browser->menu = GTK_MENU (gtk_builder_get_object (builder, "local_menu")); browser->dir = local_dir; browser->fs_ops = &FS_LOCAL_SAMPLE_OPERATIONS; browser->backend = NULL; browser->check_callback = NULL; browser->set_popup_menuitems_visibility = browser_local_set_popup_visibility; browser->set_columns_visibility = browser_local_set_columns_visibility; browser->sensitive_widgets = NULL; browser->list_stack = GTK_WIDGET (gtk_builder_get_object (builder, "local_list_stack")); browser->spinner = GTK_WIDGET (gtk_builder_get_object (builder, "local_spinner")); browser->transfer_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "upload_menuitem")); browser->play_separator = GTK_WIDGET (gtk_builder_get_object (builder, "local_play_separator")); browser->play_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "local_play_menuitem")); browser->options_separator = GTK_WIDGET (gtk_builder_get_object (builder, "local_options_separator")); browser->open_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "local_open_menuitem")); browser->show_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "local_show_menuitem")); browser->rename_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "local_rename_menuitem")); browser->delete_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "local_delete_menuitem")); browser->tree_view_name_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "local_tree_view_name_column")); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, browser->view); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, browser->up_button); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, browser->add_dir_button); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, browser->refresh_button); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, browser->search_button); browser->tree_view_sample_frames_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "local_tree_view_sample_frames_column")); browser->tree_view_sample_rate_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "local_tree_view_sample_rate_column")); browser->tree_view_sample_duration_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "local_tree_view_sample_duration_column")); browser->tree_view_sample_channels_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "local_tree_view_sample_channels_column")); browser->tree_view_sample_bits_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "local_tree_view_sample_bits_column")); browser->tree_view_sample_midi_note_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "local_tree_view_sample_midi_note_column")); browser->tree_view_info_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "local_tree_view_info_column")); browser->tree_view_id_column = NULL; browser->tree_view_slot_column = NULL; browser->tree_view_size_column = NULL; browser_init (browser); } void browser_remote_init (struct browser *browser, GtkBuilder *builder, struct backend *backend) { browser->name = "remote"; browser->view = GTK_TREE_VIEW (gtk_builder_get_object (builder, "remote_tree_view")); browser->buttons_stack = GTK_WIDGET (gtk_builder_get_object (builder, "remote_buttons_stack")); browser->up_button = GTK_WIDGET (gtk_builder_get_object (builder, "remote_up_button")); browser->add_dir_button = GTK_WIDGET (gtk_builder_get_object (builder, "remote_add_dir_button")); browser->refresh_button = GTK_WIDGET (gtk_builder_get_object (builder, "remote_refresh_button")); browser->search_button = GTK_WIDGET (gtk_builder_get_object (builder, "remote_search_button")); browser->search_entry = GTK_WIDGET (gtk_builder_get_object (builder, "remote_search_entry")); browser->dir_entry = GTK_ENTRY (gtk_builder_get_object (builder, "remote_dir_entry")); browser->menu = GTK_MENU (gtk_builder_get_object (builder, "remote_menu")); browser->dir = NULL; browser->fs_ops = NULL; browser->backend = backend; browser->check_callback = browser_check_backend; browser->set_popup_menuitems_visibility = browser_remote_set_popup_visibility; browser->set_columns_visibility = browser_remote_set_columns_visibility; browser->sensitive_widgets = NULL; browser->list_stack = GTK_WIDGET (gtk_builder_get_object (builder, "remote_list_stack")); browser->spinner = GTK_WIDGET (gtk_builder_get_object (builder, "remote_spinner")); browser->transfer_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "download_menuitem")); browser->play_separator = GTK_WIDGET (gtk_builder_get_object (builder, "remote_play_separator")); browser->play_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "remote_play_menuitem")); browser->options_separator = GTK_WIDGET (gtk_builder_get_object (builder, "remote_options_separator")); browser->open_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "remote_open_menuitem")); browser->show_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "remote_show_menuitem")); browser->actions_separator = GTK_WIDGET (gtk_builder_get_object (builder, "remote_actions_separator")); browser->rename_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "remote_rename_menuitem")); browser->delete_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "remote_delete_menuitem")); browser->tree_view_name_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "remote_tree_view_name_column")); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, GTK_WIDGET (gtk_builder_get_object (builder, "devices_combo"))); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, GTK_WIDGET (gtk_builder_get_object (builder, "refresh_devices_button"))); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, GTK_WIDGET (gtk_builder_get_object (builder, "fs_combo"))); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, browser->view); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, browser->up_button); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, browser->add_dir_button); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, browser->refresh_button); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, browser->search_button); browser->sensitive_widgets = g_slist_append (browser->sensitive_widgets, maction_context.box); browser->tree_view_id_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "remote_tree_view_id_column")); browser->tree_view_slot_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "remote_tree_view_slot_column")); browser->tree_view_size_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "remote_tree_view_size_column")); browser->tree_view_sample_frames_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "remote_tree_view_sample_frames_column")); browser->tree_view_sample_rate_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "remote_tree_view_sample_rate_column")); browser->tree_view_sample_duration_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "remote_tree_view_sample_duration_column")); browser->tree_view_sample_channels_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "remote_tree_view_sample_channels_column")); browser->tree_view_sample_bits_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "remote_tree_view_sample_bits_column")); browser->tree_view_sample_midi_note_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "remote_tree_view_sample_midi_note_column")); browser->tree_view_info_column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, "remote_tree_view_info_column")); browser_init (browser); } elektroid-3.2.3/src/browser.h000066400000000000000000000115051500236517400161310ustar00rootroot00000000000000/* * browser.h * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "utils.h" #include "notifier.h" #include "preferences.h" #include "connector.h" #ifndef BROWSER_H #define BROWSER_H #define SIZE_LABEL_LEN 16 //Common columns #define BROWSER_LIST_STORE_ICON_FIELD 0 #define BROWSER_LIST_STORE_NAME_FIELD 1 //This is the value returned by the funciton se in the get_item_key member in struct fs_operations. It's the filename. #define BROWSER_LIST_STORE_SIZE_FIELD 2 #define BROWSER_LIST_STORE_SIZE_STR_FIELD 3 #define BROWSER_LIST_STORE_TYPE_FIELD 4 #define BROWSER_LIST_STORE_ID_FIELD 5 #define BROWSER_LIST_STORE_INFO_FIELD 6 #define BROWSER_LIST_STORE_SAMPLE_FRAMES_FIELD 7 #define BROWSER_LIST_STORE_SAMPLE_RATE_FIELD 8 #define BROWSER_LIST_STORE_SAMPLE_TIME_FIELD 9 #define BROWSER_LIST_STORE_SAMPLE_FORMAT_FIELD 10 #define BROWSER_LIST_STORE_SAMPLE_CHANNELS_FIELD 11 #define BROWSER_LIST_STORE_SAMPLE_MIDI_NOTE_FIELD 12 //Remote columns #define BROWSER_LIST_STORE_SLOT_FIELD 13 //This is an optional map of the id (number) to some string like "A1", "001" or "[A:001]" to mimic the device way of numbering the items. #define BROWSER_IS_SYSTEM(b) (!(b)->backend || (b)->backend->type == BE_TYPE_SYSTEM) struct browser { const gchar *name; GtkTreeView *view; GtkWidget *buttons_stack; GtkWidget *up_button; GtkWidget *add_dir_button; GtkWidget *refresh_button; GtkWidget *search_button; GtkWidget *search_entry; GtkEntry *dir_entry; gchar *dir; GtkMenu *menu; gboolean dnd; GtkTreePath *dnd_motion_path; gint dnd_timeout_function_id; GString *dnd_data; const struct fs_operations *fs_ops; struct backend *backend; gboolean (*check_callback) (); void (*set_columns_visibility) (); void (*set_popup_menuitems_visibility) (); struct notifier *notifier; //Background loading members GSList *sensitive_widgets; GtkWidget *list_stack; GtkWidget *spinner; GThread *thread; GMutex mutex; gboolean loading; gboolean dirty; gboolean search_mode; const gchar *filter; gint64 last_selected_index; //This needs space for gint and -1 //Menu GtkWidget *transfer_menuitem; GtkWidget *play_separator; GtkWidget *play_menuitem; GtkWidget *options_separator; GtkWidget *open_menuitem; GtkWidget *show_menuitem; GtkWidget *actions_separator; GtkWidget *rename_menuitem; GtkWidget *delete_menuitem; GtkTreeViewColumn *tree_view_name_column; GtkTreeViewColumn *tree_view_info_column; GtkTreeViewColumn *tree_view_sample_frames_column; GtkTreeViewColumn *tree_view_sample_rate_column; GtkTreeViewColumn *tree_view_sample_duration_column; GtkTreeViewColumn *tree_view_sample_channels_column; GtkTreeViewColumn *tree_view_sample_bits_column; GtkTreeViewColumn *tree_view_sample_midi_note_column; //Only present in the remote browser GtkTreeViewColumn *tree_view_id_column; GtkTreeViewColumn *tree_view_slot_column; GtkTreeViewColumn *tree_view_size_column; }; void browser_set_item (GtkTreeModel *, GtkTreeIter *, struct item *); gint browser_get_selected_items_count (struct browser *); void browser_clear_selection (struct browser *); gint browser_set_selected_row_iter (struct browser *, GtkTreeIter *); void browser_selection_changed (GtkTreeSelection *, gpointer); void browser_refresh (GtkWidget *, gpointer); void browser_go_up (GtkWidget *, gpointer); void browser_item_activated (GtkTreeView *, GtkTreePath *, GtkTreeViewColumn *, gpointer); gchar *browser_get_item_path (struct browser *, struct item *); gboolean browser_load_dir (gpointer); gboolean browser_load_dir_if_needed (gpointer); void browser_update_fs_options (struct browser *); void browser_local_init (struct browser *, GtkBuilder *, gchar *); void browser_remote_init (struct browser *, GtkBuilder *, struct backend *); void browser_destroy (struct browser *); void browser_reset (struct browser *); void browser_clear_dnd_function (struct browser *); void browser_set_dnd_function (struct browser *, GSourceFunc); void browser_open_search (GtkWidget *, gpointer); void browser_close_search (GtkSearchEntry *, gpointer); void browser_search_changed (GtkSearchEntry *, gpointer); #endif elektroid-3.2.3/src/connector.c000066400000000000000000000034261500236517400164360ustar00rootroot00000000000000/* * connector.c * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "connector.h" void item_iterator_init (struct item_iterator *iter, const gchar *dir, void *data, iterator_next next, iterator_free free) { iter->dir = strdup (dir); iter->data = data; iter->next = next; iter->free = free; } gint item_iterator_next (struct item_iterator *iter) { return iter->next (iter); } void item_iterator_free (struct item_iterator *iter) { g_free (iter->dir); if (iter->free) { iter->free (iter->data); } } gboolean item_iterator_is_dir_or_matches_extensions (struct item_iterator *iter, const gchar **extensions) { if (iter->item.type == ITEM_TYPE_DIR) { return TRUE; } return file_matches_extensions (iter->item.name, extensions); } gchar * item_get_filename (struct item *item, guint32 fs_options) { if (fs_options & FS_OPTION_SLOT_STORAGE && item->type == ITEM_TYPE_FILE) { gchar *id = g_malloc (LABEL_MAX); snprintf (id, LABEL_MAX, "%d", item->id); return id; } return strdup (item->name); } elektroid-3.2.3/src/connector.h000066400000000000000000000214461500236517400164450ustar00rootroot00000000000000/* * connector.h * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "backend.h" #ifndef CONNECTOR_H #define CONNECTOR_H #define FS_ICON_WAVE "elektroid-wave-symbolic" #define FS_ICON_WAVETABLE "elektroid-wavetable-symbolic" #define FS_ICON_SEQ "elektroid-sequence-symbolic" #define FS_ICON_PRJ "elektroid-project-symbolic" #define FS_ICON_SND "elektroid-sound-symbolic" #define FS_ICON_GENERIC "elektroid-file-symbolic" #define FS_ICON_KEYS "elektroid-keys-symbolic" #define GET_SAVE_EXT(ops,backend) (ops->get_exts(backend, ops)[0]) #define GET_CLI_NAME(ops) (ops->cli_name ? ops->cli_name : ops->name) enum item_type { ITEM_TYPE_NONE = 0, ITEM_TYPE_FILE = 'F', ITEM_TYPE_DIR = 'D' }; //name must be filled up always. If no name is available, this can be a string representation of the id without padding. See set_item_name_from_id function. //In slot mode, id needs to be filled up and will typically be the MIDI preset number. //As the id is used to address items, it is recommended to follow the same user naming convention as the device regardless of its internal meaning or representation. //In default mode (not slot mode), id can be used for any or no purpose. It's still possible to use the id as the filename by using the FS_OPTION_ID_AS_FILENAME option. //A -1 size (unknown) will show no size in either the GUI or the CLI. //A 0 size item will be skipped by the `backup` command for efficiency purposes. It depends on the connector if this can be determined. //A download on an item of size 0 is still possible and the actual size might be different than 0 as an empty slot might contain an initialized item. //However, the GUI must list all the items always as the slot destination is always needed and the `ls` command will list them as well. //If the size column is not used at all, do not use FS_OPTION_SHOW_SIZE_COLUMN. struct item { enum item_type type; gchar name[LABEL_MAX]; gint32 id; // Used only by slot filesystems gint64 size; //Optionally filled up structs by filesystems. //Filesystem options must indicate if these are in use with FS_OPTION_SHOW_SAMPLE_COLUMNS and FS_OPTION_SHOW_INFO_COLUMN. struct sample_info sample_info; gchar object_info[LABEL_MAX]; }; struct item_iterator; typedef gint (*iterator_next) (struct item_iterator *); typedef void (*iterator_free) (void *); struct item_iterator { gchar *dir; iterator_next next; iterator_free free; void *data; struct item item; }; struct fs_operations; typedef void (*fs_print_item) (struct item_iterator *, struct backend *, const struct fs_operations *); typedef gint (*fs_init_iter_func) (struct backend * backend, struct item_iterator * iter, const gchar * dir, const gchar ** exts); typedef gint (*fs_path_func) (struct backend *, const gchar *); typedef gint (*fs_src_dst_func) (struct backend *, const gchar *, const gchar *); typedef gint (*fs_remote_file_op) (struct backend *, const gchar *, struct idata *, struct job_control *); typedef gchar *(*fs_get_item_slot) (struct item *, struct backend *); typedef gint (*fs_local_file_op) (const gchar *, struct idata *, struct job_control *); typedef const gchar **(*fs_get_exts) (struct backend *, const struct fs_operations *); typedef gchar *(*fs_get_path) (struct backend * backend, const struct fs_operations * ops, const gchar * dst_dir, const gchar * src_path, struct idata * idata); typedef void (*fs_select_item) (struct backend *, const gchar *, struct item *); typedef gboolean (*fs_file_exists) (struct backend *, const gchar *); // All the function members that return gint should return 0 if no error and a negative number in case of error. // errno values are recommended as will provide the user with a meaningful message. In particular, // ENOSYS could be used when a particular device does not support a feature that other devices implementing the same filesystem do. // rename and move are different operations. If move is implemented, rename must behave the same way. However, it's perfectly // possible to implement rename without implementing move. This is the case in slot mode filesystems. struct fs_operations { guint32 id; guint32 options; const gchar *name; // This needs to be unique among all the filesystems of a given connector. Used to address filesystems. Using spaces is not recommended and hyphen is the suggested replacement. const gchar *gui_name; const gchar *cli_name; //Optional. Used to determine the fs_operations name if set. If not, name is used. This can be duplicated among all the filesystems of a given connector but not for a connected device. const gchar *gui_icon; guint32 max_name_len; fs_init_iter_func readdir; //This function runs on its own thread so it can take as long as needed in order to make calls to item_iterator_next not to wait for IO. fs_file_exists file_exists; fs_print_item print_item; fs_path_func mkdir; fs_path_func delete; fs_src_dst_func rename; fs_src_dst_func move; fs_src_dst_func copy; fs_path_func clear; fs_src_dst_func swap; fs_remote_file_op download; //Donload a resource from the filesystem to memory. fs_remote_file_op upload; //Upload a resource from memory to the filesystem. fs_local_file_op save; //Write a file from memory to the OS storage. Typically used after download. fs_local_file_op load; //Load a file from the OS storage into memory. Typically used before upload. fs_get_item_slot get_slot; //Optionally used by slot filesystems to show a custom slot name column such `A01` or `[P-01]`. Needs FS_OPTION_SHOW_SLOT_COLUMN. fs_get_exts get_exts; //Length must be one at least. First element will be used as file extension and all will be used as loading extensions. fs_get_path get_upload_path; fs_get_path get_download_path; fs_select_item select_item; }; enum fs_options { //Show the audio player. FS_OPTION_SAMPLE_EDITOR = 0x1, //Allow mono samples. Only useful if used together with FS_OPTION_SAMPLE_EDITOR FS_OPTION_MONO = 0x2, //Allow stereo samples. Only useful if used together with FS_OPTION_SAMPLE_EDITOR FS_OPTION_STEREO = 0x4, //Every operation will block the remote browser. FS_OPTION_SINGLE_OP = 0x8, //In slot storage mode, the item name in dst_path passed to get_upload_path is the ID. //DND is only possible over a concrete slot. //A DND operation of several items over a slot will behave as dropping the first item over the destination slot and the rest over the following ones. FS_OPTION_SLOT_STORAGE = 0x10, //Show column options. Name column is always showed. FS_OPTION_SHOW_ID_COLUMN = 0x20, // Not 0 padded. For a 0 padded value use FS_OPTION_SHOW_SLOT_COLUMN and a custom get_slot function. FS_OPTION_SHOW_SIZE_COLUMN = 0x40, FS_OPTION_SHOW_SLOT_COLUMN = 0x80, FS_OPTION_SHOW_INFO_COLUMN = 0x100, FS_OPTION_SHOW_SAMPLE_COLUMNS = 0x200, //This requires the function readdir to be relatively fast because canceling the search will block the GUI. FS_OPTION_ALLOW_SEARCH = 0x400 }; struct connector { const gchar *name; gint (*handshake) (struct backend * backend); //Used to indicate if the handshake requires a MIDI identity request gboolean standard; //If the backend device name matches this regex, the handshake will be run before than the connectors that didn't match. const gchar *regex; }; void item_iterator_init (struct item_iterator *iter, const gchar * dir, void *data, iterator_next next, iterator_free free); gint item_iterator_next (struct item_iterator *iter); void item_iterator_free (struct item_iterator *iter); gboolean item_iterator_is_dir_or_matches_extensions (struct item_iterator *iter, const gchar ** extensions); /** * Returns the filename for an item, which is a string that uniquely idenfifies an item. * In a PC, filenames are typically strings but in embedded devices this could be just a number (in string format). * Typically, in these systems, several slots can have the same name but the id is an address to a memory slot. * @param options The options member in the fs_operations struct. * @param item */ gchar *item_get_filename (struct item *item, guint32 options); #endif elektroid-3.2.3/src/connectors/000077500000000000000000000000001500236517400164505ustar00rootroot00000000000000elektroid-3.2.3/src/connectors/common.c000066400000000000000000000222711500236517400201100ustar00rootroot00000000000000/* * common.h * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "common.h" #include "sample.h" static const gchar *SYSEX_EXTS[] = { "syx", NULL }; static void common_replace_chars (gchar *str, gchar x, gchar y) { gchar *c = str; while (*c) { if (*c == x) { *c = y; } c++; } } //These conversions depend on the OS but its safer and simpler to apply this restrictions to all of them. void common_to_os_sanitized_name (gchar *name) { common_replace_chars (name, '/', '?'); common_replace_chars (name, '\\', '?'); } const gchar ** common_sysex_get_extensions () { return SYSEX_EXTS; } const gchar ** common_get_all_extensions () { return NULL; } gchar * common_slot_get_upload_path (struct backend *backend, const struct fs_operations *ops, const gchar *dst_path, const gchar *src_path, struct idata *content) { //In SLOT mode, dst_path points to a slot not to a directory return strdup (dst_path); } gint common_slot_get_id_from_path (const char *path, guint *id) { gint err = 0; gchar *basename, *remainder; basename = g_path_get_basename (path); *id = (guint) g_ascii_strtoull (basename, &remainder, 10); if (remainder == basename) { err = -EINVAL; goto end; } if (!id && errno) { err = -errno; } end: g_free (basename); return err; } gchar * common_get_id_as_slot_padded (struct item *item, struct backend *backend, gint digits) { gchar *slot = g_malloc (LABEL_MAX); snprintf (slot, LABEL_MAX, "%.*d", digits, item->id); return slot; } gchar * common_get_id_as_slot (struct item *item, struct backend *backend) { gchar *slot = g_malloc (LABEL_MAX); snprintf (slot, LABEL_MAX, "%d", item->id); return slot; } void common_print_item (struct item_iterator *iter, struct backend *backend, const struct fs_operations *fs_ops) { gchar *slot = NULL; gchar *hsize = get_human_size (iter->item.size, FALSE); gint max_name_len = fs_ops->max_name_len ? fs_ops->max_name_len : DEFAULT_MAX_NAME_LEN; gboolean info = (fs_ops->options & FS_OPTION_SHOW_INFO_COLUMN) && *iter->item.object_info; if (fs_ops->options & FS_OPTION_SLOT_STORAGE) { if (fs_ops->get_slot) { slot = fs_ops->get_slot (&iter->item, backend); } else { slot = common_get_id_as_slot (&iter->item, backend); } } printf ("%c %10s %.*s%s%-*s%s%s%s\n", iter->item.type, hsize, slot ? 10 : 0, slot, slot ? " " : "", info ? max_name_len : (gint) strlen (iter->item.name), iter->item.name, info ? " [ " : "", info ? iter->item.object_info : "", info ? " ]" : ""); g_free (hsize); g_free (slot); } void common_midi_program_change_int (struct backend *backend, const gchar *dir, guint32 program) { backend_send_controller (backend, 0, 0, COMMON_GET_MIDI_BANK (program)); backend_program_change (backend, 0, COMMON_GET_MIDI_PRESET (program)); } void common_midi_program_change (struct backend *backend, const gchar *dir, struct item *item) { if (item->id > BE_MAX_MIDI_PROGRAMS) { return; } backend_program_change (backend, 0, item->id); } gint common_simple_next_dentry (struct item_iterator *iter) { struct common_simple_read_dir_data *data = iter->data; guint digits = ((guint) floor (log10 (data->last))) + 1; if (data->next > data->last) { return -ENOENT; } snprintf (iter->item.name, LABEL_MAX, "%.*d", digits, data->next); iter->item.id = data->next; iter->item.type = ITEM_TYPE_FILE; iter->item.size = -1; data->next++; return 0; } gint common_data_tx (struct backend *backend, GByteArray *msg, struct job_control *control) { gint err = 0; struct sysex_transfer transfer; g_mutex_lock (&backend->mutex); job_control_reset (control, 1); transfer.raw = msg; err = backend_tx_sysex (backend, &transfer); if (err < 0) { goto cleanup; } if (job_control_get_active_lock (control)) { job_control_set_progress (control, 1.0); } else { err = -ECANCELED; } cleanup: g_mutex_unlock (&backend->mutex); return err; } gint common_data_tx_and_rx_part (struct backend *backend, GByteArray *tx_msg, GByteArray **rx_msg, struct job_control *control) { gint err = 0; *rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!*rx_msg) { err = -EIO; goto cleanup; } job_control_set_progress (control, 1.0); if (!job_control_get_active_lock (control)) { free_msg (*rx_msg); *rx_msg = NULL; err = -ECANCELED; } control->part++; cleanup: return err; } gint common_data_tx_and_rx (struct backend *backend, GByteArray *tx_msg, GByteArray **rx_msg, struct job_control *control) { job_control_reset (control, 1); return common_data_tx_and_rx_part (backend, tx_msg, rx_msg, control); } static gchar * common_slot_get_download_path_id_name (struct backend *backend, const struct fs_operations *ops, const gchar *dst_dir, guint id, guint digits, const gchar *name) { gchar *path; const gchar *ext = GET_SAVE_EXT (ops, backend); GString *str = g_string_new (NULL); g_string_append_printf (str, "%s %s", backend->name, ops->name); if (digits) { g_string_append_printf (str, " %.*d", digits, id); } if (name) { gchar *sanitized_name = strdup (name); common_to_os_sanitized_name (sanitized_name); g_string_append (str, " - "); g_string_append (str, sanitized_name); g_free (sanitized_name); } g_string_append (str, "."); g_string_append (str, ext); path = path_chain (PATH_SYSTEM, dst_dir, str->str); g_string_free (str, TRUE); return path; } gchar * common_slot_get_download_path (struct backend *backend, const struct fs_operations *ops, const gchar *dst_dir, const gchar *src_path, struct idata *idata, guint digits) { guint id; if (common_slot_get_id_from_path (src_path, &id)) { return NULL; } return common_slot_get_download_path_id_name (backend, ops, dst_dir, id, digits, idata->name); } gchar * common_slot_get_download_path_n (struct backend *backend, const struct fs_operations *ops, const gchar *dst_dir, const gchar *src_path, struct idata *idata) { return common_slot_get_download_path (backend, ops, dst_dir, src_path, idata, 1); } gchar * common_slot_get_download_path_nn (struct backend *backend, const struct fs_operations *ops, const gchar *dst_dir, const gchar *src_path, struct idata *idata) { return common_slot_get_download_path (backend, ops, dst_dir, src_path, idata, 2); } gchar * common_slot_get_download_path_nnn (struct backend *backend, const struct fs_operations *ops, const gchar *dst_dir, const gchar *src_path, struct idata *idata) { return common_slot_get_download_path (backend, ops, dst_dir, src_path, idata, 3); } gchar * common_get_sanitized_name (const gchar *name, const gchar *alphabet, gchar defchar) { gchar *sanitized = g_str_to_ascii (name, NULL); gchar *t, *v; if (alphabet) { t = sanitized; while (*t) { gboolean valid = FALSE; v = (gchar *) alphabet; while (*v) { if (*t == *v) { valid = TRUE; break; } v++; } if (!valid) { *t = defchar; } t++; } } return sanitized; } gint common_sample_load (const gchar *path, struct idata *sample, struct job_control *control, guint32 rate, guint32 channels, guint32 format) { struct sample_info sample_info_req, sample_info_src; sample_info_req.rate = rate; sample_info_req.channels = channels; sample_info_req.format = format; return sample_load_from_file (path, sample, control, &sample_info_req, &sample_info_src); } gchar * common_system_get_download_path (struct backend *backend, const struct fs_operations *ops, const gchar *dst_dir, const gchar *src_path, struct idata *idata) { const gchar *ext = GET_SAVE_EXT (ops, backend); GString *name_with_ext = g_string_new (NULL); g_string_append_printf (name_with_ext, "%s.%s", idata->name, ext); gchar *path = path_chain (PATH_SYSTEM, dst_dir, name_with_ext->str); g_string_free (name_with_ext, TRUE); return path; } gchar * common_system_get_upload_path (struct backend *backend, const struct fs_operations *ops, const gchar *dst_dir, const gchar *src_path, struct idata *content) { return common_system_get_download_path (backend, ops, dst_dir, src_path, content); } elektroid-3.2.3/src/connectors/common.h000066400000000000000000000074021500236517400201140ustar00rootroot00000000000000/* * common.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "connector.h" #include "sample.h" #define DEFAULT_MAX_NAME_LEN 32 #define COMMON_GET_MIDI_BANK(p) ((p & 0x3f80) >> 7) #define COMMON_GET_MIDI_PRESET(p) (p & 0x7f) struct common_simple_read_dir_data { guint32 next; guint32 last; }; const gchar **common_sysex_get_extensions (); const gchar **common_get_all_extensions (); gchar *common_slot_get_upload_path (struct backend *backend, const struct fs_operations *ops, const gchar * dst_dir, const gchar * src_path, struct idata *idata); gint common_slot_get_id_from_path (const char *path, guint * id); gchar *common_get_id_as_slot (struct item *item, struct backend *backend); gchar *common_get_id_as_slot_padded (struct item *item, struct backend *backend, gint digits); void common_print_item (struct item_iterator *iter, struct backend *backend, const struct fs_operations *fs_ops); void common_midi_program_change (struct backend *backend, const gchar * dir, struct item *item); void common_midi_program_change_int (struct backend *backend, const gchar * dir, guint32 program); gint common_simple_next_dentry (struct item_iterator *iter); gint common_data_tx (struct backend *backend, GByteArray * msg, struct job_control *control); gint common_data_tx_and_rx (struct backend *backend, GByteArray * tx_msg, GByteArray ** rx_msg, struct job_control *control); gint common_data_tx_and_rx_part (struct backend *backend, GByteArray * tx_msg, GByteArray ** rx_msg, struct job_control *control); gchar *common_slot_get_download_path (struct backend *backend, const struct fs_operations *ops, const gchar * dst_dir, const gchar * src_path, struct idata *idata, guint digits); gchar *common_slot_get_download_path_n (struct backend *backend, const struct fs_operations *ops, const gchar * dst_dir, const gchar * src_path, struct idata *idata); gchar *common_slot_get_download_path_nn (struct backend *backend, const struct fs_operations *ops, const gchar * dst_dir, const gchar * src_path, struct idata *idata); gchar *common_slot_get_download_path_nnn (struct backend *backend, const struct fs_operations *ops, const gchar * dst_dir, const gchar * src_path, struct idata *idata); void common_to_os_sanitized_name (gchar * name); gchar *common_get_sanitized_name (const gchar * name, const gchar * alphabet, gchar defchar); gint common_sample_load (const gchar * path, struct idata *sample, struct job_control *control, guint32 rate, guint32 channels, guint32 format); gchar *common_system_get_download_path (struct backend *backend, const struct fs_operations *ops, const gchar * dst_dir, const gchar * src_path, struct idata *content); gchar *common_system_get_upload_path (struct backend *backend, const struct fs_operations *ops, const gchar * dst_dir, const gchar * src_path, struct idata *content); elektroid-3.2.3/src/connectors/cz.c000066400000000000000000000177431500236517400172440ustar00rootroot00000000000000/* * cz.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "cz.h" #include "common.h" #define CZ_PROGRAM_LEN 263 #define CZ_PROGRAM_LEN_FIXED 264 #define CZ_MAX_PROGRAMS 16 #define CZ_PRESET_PREFIX "CZ-101" #define CZ_PROGRAM_HEADER_ID 6 #define CZ_PROGRAM_HEADER_OFFSET 6 #define CZ_MEM_TYPE_OFFSET 0x20 #define CZ_PANEL_ID 0x60 #define CZ_FIRST_CARTRIDGE_ID 0x40 #define CZ_PANEL "panel" static const char *CZ_MEM_TYPES[] = { "preset", "internal", "cartridge", NULL }; static const guint8 CZ_PROGRAM_REQUEST[] = { 0xf0, 0x44, 0x00, 0x00, 0x70, 0x10, 0x00, 0x70, 0x31, 0xf7 }; static const guint8 CZ_PROGRAM_HEADER[] = { 0xf0, 0x44, 0x00, 0x00, 0x70, 0x20, 0x00 }; enum cz_fs { FS_PROGRAM_CZ }; struct cz_type_iterator_data { guint next; gint type; struct backend *backend; }; static gchar * cz_get_download_path (struct backend *backend, const struct fs_operations *ops, const gchar *dst_dir, const gchar *src_path, struct idata *preset) { guint digits = preset->name ? 0 : 2; return common_slot_get_download_path (backend, ops, dst_dir, src_path, preset, digits); } static GByteArray * cz_get_program_dump_msg (guint8 id) { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (CZ_PROGRAM_REQUEST)); g_byte_array_append (tx_msg, CZ_PROGRAM_REQUEST, sizeof (CZ_PROGRAM_REQUEST)); tx_msg->data[CZ_PROGRAM_HEADER_OFFSET] = id; return tx_msg; } static gint cz_next_dentry_root (struct item_iterator *iter) { GByteArray *tx_msg, *rx_msg; struct cz_type_iterator_data *data = iter->data; if (data->next < 3) { iter->item.id = 0x1000 + data->next; //Unique id snprintf (iter->item.name, LABEL_MAX, "%s", CZ_MEM_TYPES[data->next]); iter->item.type = ITEM_TYPE_DIR; iter->item.size = -1; if (data->next == 2) { tx_msg = cz_get_program_dump_msg (CZ_FIRST_CARTRIDGE_ID); rx_msg = backend_tx_and_rx_sysex (data->backend, tx_msg, BE_SYSEX_TIMEOUT_GUESS_MS); data->next++; if (rx_msg) { free_msg (rx_msg); return 0; } } else { data->next++; return 0; } } if (data->next == 3) { iter->item.id = CZ_PANEL_ID + 1; //1 based snprintf (iter->item.name, LABEL_MAX, CZ_PANEL); iter->item.type = ITEM_TYPE_FILE; iter->item.size = CZ_PROGRAM_LEN_FIXED; data->next++; return 0; } else { return -ENOENT; } } static gint cz_next_dentry (struct item_iterator *iter) { struct cz_type_iterator_data *data = iter->data; if (data->next >= CZ_MAX_PROGRAMS) { return -ENOENT; } iter->item.id = data->next + 1 + data->type * CZ_MEM_TYPE_OFFSET; snprintf (iter->item.name, LABEL_MAX, "%d", data->next + 1); iter->item.type = ITEM_TYPE_FILE; iter->item.size = CZ_PROGRAM_LEN_FIXED; data->next++; return 0; } static gint get_mem_type (const gchar *name) { const char **mem_type = CZ_MEM_TYPES; for (int i = 0; *mem_type; i++, mem_type++) { if (!strcmp (*mem_type, name)) { return i; } } return -1; } static gint cz_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { gint mem_type; if (!strcmp (dir, "/")) { struct cz_type_iterator_data *data = g_malloc (sizeof (struct cz_type_iterator_data)); data->next = 0; data->type = -1; data->backend = backend; item_iterator_init (iter, dir, data, cz_next_dentry_root, g_free); return 0; } else if ((mem_type = get_mem_type (&dir[1])) >= 0) { struct cz_type_iterator_data *data = g_malloc (sizeof (struct cz_type_iterator_data)); data->next = 0; data->type = mem_type; data->backend = backend; item_iterator_init (iter, dir, data, cz_next_dentry, g_free); return 0; } else { return -ENOTDIR; } } static gint cz_get_id_from_path (const gchar *path, guint8 *id) { guint idl; gchar *dir; gint err, type; err = common_slot_get_id_from_path (path, &idl); if (err) { return err; } *id = idl; (*id)--; if (*id != CZ_PANEL_ID) { dir = g_path_get_dirname (path); type = get_mem_type (&dir[1]); g_free (dir); if (type < 0) { return -EINVAL; } if (*id >= CZ_MAX_PROGRAMS) { return -EINVAL; } *id += type * CZ_MEM_TYPE_OFFSET; } return 0; } static gint cz_download (struct backend *backend, const gchar *path, struct idata *program, struct job_control *control) { guint8 id; gint len, err; GByteArray *tx_msg, *rx_msg; GByteArray *output; err = cz_get_id_from_path (path, &id); if (err) { return err; } tx_msg = cz_get_program_dump_msg (id); err = common_data_tx_and_rx (backend, tx_msg, &rx_msg, control); if (err) { return err; } len = rx_msg->len; if (len != CZ_PROGRAM_LEN) { err = -EINVAL; goto cleanup; } output = g_byte_array_sized_new (512); g_byte_array_append (output, CZ_PROGRAM_HEADER, sizeof (CZ_PROGRAM_HEADER)); g_byte_array_append (output, &rx_msg->data[CZ_PROGRAM_HEADER_OFFSET], CZ_PROGRAM_LEN - CZ_PROGRAM_HEADER_OFFSET); output->data[CZ_PROGRAM_HEADER_ID] = id; idata_init (program, output, id == CZ_PANEL_ID ? strdup (CZ_PANEL) : NULL, NULL); cleanup: free_msg (rx_msg); return err; } static gint cz_upload (struct backend *backend, const gchar *path, struct idata *program, struct job_control *control) { guint8 id; gint err; GByteArray *msg; GByteArray *input = program->content; err = cz_get_id_from_path (path, &id); if (err) { return err; } msg = g_byte_array_sized_new (input->len); g_byte_array_append (msg, input->data, input->len); msg->data[CZ_PROGRAM_HEADER_ID] = id; err = common_data_tx (backend, msg, control); free_msg (msg); return err; } static gchar * cz_get_id_as_slot (struct item *item, struct backend *backend) { gchar *slot = g_malloc (LABEL_MAX); snprintf (slot, LABEL_MAX, "%0*d", item->id == CZ_PANEL_ID + 1 ? 4 : 2, item->id); return slot; } static const struct fs_operations FS_PROGRAM_CZ_OPERATIONS = { .id = FS_PROGRAM_CZ, .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SIZE_COLUMN, .name = "program", .gui_name = "Programs", .gui_icon = FS_ICON_SND, .readdir = cz_read_dir, .print_item = common_print_item, .download = cz_download, .upload = cz_upload, .get_slot = cz_get_id_as_slot, .load = file_load, .save = file_save, .get_exts = common_sysex_get_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = cz_get_download_path, .select_item = common_midi_program_change }; static gint cz_handshake (struct backend *backend) { gint len, err = 0; GByteArray *tx_msg, *rx_msg; tx_msg = cz_get_program_dump_msg (CZ_PANEL_ID); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, BE_SYSEX_TIMEOUT_GUESS_MS); if (!rx_msg) { return -ENODEV; } len = rx_msg->len; if (len != CZ_PROGRAM_LEN) { err = -ENODEV; goto end; } gslist_fill (&backend->fs_ops, &FS_PROGRAM_CZ_OPERATIONS, NULL); snprintf (backend->name, LABEL_MAX, "Casio CZ-101"); end: free_msg (rx_msg); return err; } const struct connector CONNECTOR_CZ = { .name = "cz", .handshake = cz_handshake, .standard = FALSE, .regex = NULL }; elektroid-3.2.3/src/connectors/cz.h000066400000000000000000000015641500236517400172430ustar00rootroot00000000000000/* * cz.h * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef CZ_H #define CZ_H #include "connector.h" extern const struct connector CONNECTOR_CZ; #endif elektroid-3.2.3/src/connectors/default.c000066400000000000000000000044221500236517400202420ustar00rootroot00000000000000/* * default.c * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "default.h" #include "common.h" #define DEFAULT_MAX_PROGRAMS 128 enum default_fs { FS_PROGRAM_DEFAULT }; static gint default_next_dentry (struct item_iterator *iter) { guint *data = iter->data; if (*data >= DEFAULT_MAX_PROGRAMS) { return -ENOENT; } iter->item.id = *data; snprintf (iter->item.name, LABEL_MAX, "%d", *data); iter->item.type = ITEM_TYPE_FILE; iter->item.size = -1; (*data)++; return 0; } static gint default_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { if (strcmp (dir, "/")) { return -ENOTDIR; } guint *data = g_malloc (sizeof (guint)); *data = 0; item_iterator_init (iter, dir, data, default_next_dentry, g_free); return 0; } const struct fs_operations FS_PROGRAM_DEFAULT_OPERATIONS = { .id = FS_PROGRAM_DEFAULT, .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE, .name = "program", .gui_name = "Programs", .gui_icon = FS_ICON_SND, .readdir = default_read_dir, .print_item = common_print_item, .select_item = common_midi_program_change, .get_exts = common_get_all_extensions }; static gint default_handshake (struct backend *backend) { gslist_fill (&backend->fs_ops, &FS_PROGRAM_DEFAULT_OPERATIONS, NULL); snprintf (backend->name, LABEL_MAX, "%s", _("MIDI device")); return 0; } const struct connector CONNECTOR_DEFAULT = { .name = "default", .handshake = default_handshake, .standard = FALSE, .regex = NULL }; elektroid-3.2.3/src/connectors/default.h000066400000000000000000000017121500236517400202460ustar00rootroot00000000000000/* * default.h * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef DEFAULT_H #define DEFAULT_H #include "connector.h" extern const struct fs_operations FS_PROGRAM_DEFAULT_OPERATIONS; extern const struct connector CONNECTOR_DEFAULT; #endif elektroid-3.2.3/src/connectors/efactor.c000066400000000000000000000377141500236517400202530ustar00rootroot00000000000000/* * efactor.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "efactor.h" #include "common.h" #define EFACTOR_MAX_PRESETS 100 #define EFACTOR_MSG_TYPE_OBJECT 0x31 #define EFACTOR_MSG_TYPE_VALUE 0x3b #define EFACTOR_KEY_LEN 4 #define EFACTOR_FACTOR_SW_LEN 17 #define EFACTOR_H9_SW_LEN 18 #define EFACTOR_FACTOR_NAME_PREFIX "Eventide Factor" #define EFACTOR_H9_NAME_PREFIX "Eventide H9" #define EFACTOR_PRESET_LINE_SEPARATOR "\x0d\x0a" #define EFACTOR_OP_PRESETS_WANT 0x48 #define EFACTOR_OP_PROGRAM_WANT 0x4e #define EFACTOR_OP_PRESETS_DUMP 0x49 #define EFACTOR_PRESET_DUMP_OFFSET 5 #define EFACTOR_SINGLE_PRESET_MIN_LEN (sizeof(EFACTOR_REQUEST_HEADER) + 5) //The additional 5 bytes are the 2 square brackets and the preset number and the \0 and 0xf7 at the end. #define EFACTOR_SINGLE_PRESET_MAX_LEN 256 //This is an empirical value. The maximum found value is 233 but we just add a few bytes just in case. #define EFACTOR_MAX_ID_TAG_LEN 16 //The longest value is "[100]" plus the \0. #define EFACTOR_TIMEOUT_TOTAL_PRESETS 30000 //20 s is not enough with RtMidi. #define EFACTOR_PEDAL_NAME(data) (data->type == EFACTOR_FACTOR ? EFACTOR_FACTOR_NAME_PREFIX : EFACTOR_H9_NAME_PREFIX) #define EFACTOR_MAX_NAME_LEN 16 #define EFACTOR_ALPHABET " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*+-_|}" #define EFACTOR_DEFAULT_CHAR '_' static const guint8 EVENTIDE_ID[] = { 0x1c }; static const guint8 FAMILY_ID[] = { 0, 6 }; //This might not be the same value for all the Factor and H9 pedals. static const guint8 MODEL_ID[] = { 0x11, 0 }; //This might not be the same value for all the Factor and H9 pedals. //Identity Request Universal Sysex message. This is the same message used in the backend. //We replicate this here because the compiler can't know the size of an external const array. static const guint8 MIDI_IDENTITY_REQUEST[] = { 0xf0, 0x7e, 0x7f, 6, 1, 0xf7 }; static const guint8 EFACTOR_REQUEST_HEADER[] = { 0xf0, 0x1c, 0x70, 0 }; enum efactor_type { EFACTOR_FACTOR, EFACTOR_H9 }; struct efactor_data { guint id; guint presets; guint min; enum efactor_type type; //Readdir data is kept in memory so it can be used in other operations. //In the efactor case, the only way to get a single preset is by getting the panel, which needs a preset to be loaded // but won't work properly if there are preset mappings. So we read all the memory -we were reading it anyway- and // use it to get the download data from there. gchar **lines; }; struct efactor_iter_data { guint next; guint presets; struct efactor_data *backend_data; }; enum efactor_fs { FS_EFACTOR_PRESET }; static GByteArray * efactor_new_op_msg (guint8 op) { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (EFACTOR_REQUEST_HEADER)); g_byte_array_append (tx_msg, EFACTOR_REQUEST_HEADER, sizeof (EFACTOR_REQUEST_HEADER) + 2); tx_msg->data[4] = op; tx_msg->data[5] = 0xf7; return tx_msg; } static GByteArray * efactor_new_get_msg (guint8 type, const gchar *key) { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (EFACTOR_REQUEST_HEADER)); g_byte_array_append (tx_msg, EFACTOR_REQUEST_HEADER, sizeof (EFACTOR_REQUEST_HEADER) + 6); tx_msg->data[4] = type; memcpy (&tx_msg->data[5], key, EFACTOR_KEY_LEN); tx_msg->data[9] = 0xf7; return tx_msg; } static gint efactor_next_dentry (struct item_iterator *iter) { struct efactor_iter_data *data = iter->data; struct efactor_data *backend_data = data->backend_data; gchar *preset_name; if (data->next == data->presets) { return -ENOENT; } iter->item.id = data->next + backend_data->min; preset_name = data->backend_data->lines[data->next * 7 + 6]; snprintf (iter->item.name, LABEL_MAX, "%s", preset_name); iter->item.type = ITEM_TYPE_FILE; iter->item.size = -1; data->next++; return 0; } static gint efactor_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { GByteArray *tx_msg; GByteArray *rx_msg; struct efactor_iter_data *iter_data; struct efactor_data *data = backend->data; if (strcmp (dir, "/")) { return -ENOTDIR; } if (data->lines) { //Reading from the device switches off and on the internal relays. //In case we call this function again just after calling it, we give the device some time to do it. sleep (1); } tx_msg = efactor_new_op_msg (EFACTOR_OP_PRESETS_WANT); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, EFACTOR_TIMEOUT_TOTAL_PRESETS); if (!rx_msg) { return -ETIMEDOUT; } iter_data = g_malloc (sizeof (struct efactor_iter_data)); iter_data->next = 0; iter_data->presets = data->presets; iter_data->backend_data = backend->data; if (iter_data->backend_data->lines) { g_strfreev (iter_data->backend_data->lines); } data->lines = g_strsplit ((gchar *) & rx_msg->data[EFACTOR_PRESET_DUMP_OFFSET], EFACTOR_PRESET_LINE_SEPARATOR, -1); free_msg (rx_msg); item_iterator_init (iter, dir, iter_data, efactor_next_dentry, g_free); return 0; } static gint efactor_download (struct backend *backend, const gchar *path, struct idata *preset, struct job_control *control) { gint err = 0; guint id; gchar *name, **lines; struct item_iterator iter; struct efactor_data *data = backend->data; GByteArray *output; job_control_reset (control, 1); if (!data->lines) { err = efactor_read_dir (backend, &iter, "/", NULL); if (err) { return err; } item_iterator_free (&iter); } err = common_slot_get_id_from_path (path, &id); if (err) { return err; } if (id < data->min || id >= data->presets) { return -EINVAL; } output = g_byte_array_sized_new (1024); g_byte_array_append (output, EFACTOR_REQUEST_HEADER, sizeof (EFACTOR_REQUEST_HEADER)); g_byte_array_append (output, (guint8 *) "\x49", 1); // EFACTOR_OP_PRESETS_DUMP lines = &data->lines[(id - data->min) * 7]; name = lines[6]; for (gint i = 0; i < 7; i++, lines++) { g_byte_array_append (output, (guint8 *) * lines, strlen (*lines)); g_byte_array_append (output, (guint8 *) EFACTOR_PRESET_LINE_SEPARATOR, strlen (EFACTOR_PRESET_LINE_SEPARATOR)); } g_byte_array_append (output, (guint8 *) "\0\xf7", 2); job_control_set_progress (control, 1.0); idata_init (preset, output, strdup (name), NULL); sleep (1); return err; } static gint efactor_upload (struct backend *backend, const gchar *path, struct idata *preset, struct job_control *control) { gint err = 0, i, num; guint id; gchar *b; GByteArray *tx_msg; gchar id_tag[EFACTOR_MAX_ID_TAG_LEN]; struct efactor_data *data = backend->data; GByteArray *input = preset->content; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } if (id < data->min || id >= data->presets) { return -EINVAL; } //The fourth header byte is the device number ID so it might be different than 0. input->data[sizeof (EFACTOR_REQUEST_HEADER) - 1] = 0; if (input->len > EFACTOR_SINGLE_PRESET_MAX_LEN || input->len <= EFACTOR_SINGLE_PRESET_MIN_LEN || memcmp (input->data, EFACTOR_REQUEST_HEADER, sizeof (EFACTOR_REQUEST_HEADER)) || input->data[sizeof (EFACTOR_REQUEST_HEADER)] != EFACTOR_OP_PRESETS_DUMP) { error_print ("Bad preset"); err = -EBADMSG; goto end; } tx_msg = g_byte_array_sized_new (input->len + 2); // With this we ensure there is enough space for all the digits of the preset number. g_byte_array_append (tx_msg, input->data, sizeof (EFACTOR_REQUEST_HEADER) + 1); tx_msg->data[sizeof (EFACTOR_REQUEST_HEADER) - 1] = (guint8) data->id; num = (id % EFACTOR_MAX_PRESETS) + 1; snprintf (id_tag, EFACTOR_MAX_ID_TAG_LEN, "[%d]", num); //1 based g_byte_array_append (tx_msg, (guint8 *) id_tag, strlen (id_tag)); i = sizeof (EFACTOR_REQUEST_HEADER) + 1; for (b = (gchar *) & input->data[i]; i < input->len; i++, b++) { if (*b == ' ') { break; } } if (i == input->len) { free_msg (tx_msg); err = -EBADMSG; goto end; } g_byte_array_append (tx_msg, (guint8 *) b, input->len - i); err = common_data_tx (backend, tx_msg, control); free_msg (tx_msg); end: sleep (1); return err; } static gint efactor_rename (struct backend *backend, const gchar *src, const gchar *dst) { GByteArray *preset, *rx_msg; gint err, len; struct job_control control; gchar **lines, **line, *sanitized; struct idata idata; debug_print (1, "Renaming from %s to %s...", src, dst); //The control initialization is needed. control.active = TRUE; control.callback = NULL; g_mutex_init (&control.mutex); err = efactor_download (backend, src, &idata, &control); if (err) { return err; } preset = idata.content; lines = g_strsplit ((gchar *) & preset->data[EFACTOR_PRESET_DUMP_OFFSET], EFACTOR_PRESET_LINE_SEPARATOR, -1); g_free (lines[6]); lines[6] = NULL; line = lines; g_byte_array_set_size (preset, EFACTOR_PRESET_DUMP_OFFSET); while (*line) { g_byte_array_append (preset, (guint8 *) (*line), strlen (*line)); g_byte_array_append (preset, (guint8 *) EFACTOR_PRESET_LINE_SEPARATOR, strlen (EFACTOR_PRESET_LINE_SEPARATOR)); line++; } sanitized = common_get_sanitized_name (dst, EFACTOR_ALPHABET, EFACTOR_DEFAULT_CHAR); len = strlen (sanitized); len = len > EFACTOR_MAX_NAME_LEN ? EFACTOR_MAX_NAME_LEN : len; g_byte_array_append (preset, (guint8 *) sanitized, len); g_byte_array_append (preset, (guint8 *) EFACTOR_PRESET_LINE_SEPARATOR, strlen (EFACTOR_PRESET_LINE_SEPARATOR)); g_byte_array_append (preset, (guint8 *) "\0\xf7", 2); g_free (sanitized); g_strfreev (lines); rx_msg = backend_tx_and_rx_sysex (backend, preset, 100); //There must be no response. if (rx_msg) { err = -EIO; free_msg (rx_msg); } sleep (1); return err; } static gchar * efactor_get_slot (struct item *item, struct backend *backend) { gchar *slot = g_malloc (LABEL_MAX); struct efactor_data *data = backend->data; if (data->type == EFACTOR_FACTOR) { //This is a bit of a hack since not only are we showing the ID but also the bank-preset pair. snprintf (slot, LABEL_MAX, "%02d [%d:%d]", item->id, (item->id / 2) + 1, (item->id % 2) + 1); } else { snprintf (slot, LABEL_MAX, "%02d", item->id + 1); } return slot; } static const struct fs_operations FS_EFACTOR_OPERATIONS = { .id = FS_EFACTOR_PRESET, .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SLOT_COLUMN, .name = "preset", .gui_name = "Presets", .gui_icon = FS_ICON_SND, .max_name_len = EFACTOR_MAX_NAME_LEN, .readdir = efactor_read_dir, .print_item = common_print_item, .rename = efactor_rename, .download = efactor_download, .upload = efactor_upload, .get_slot = efactor_get_slot, .load = file_load, .save = file_save, .get_exts = common_sysex_get_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_slot_get_download_path_nn, .select_item = common_midi_program_change }; static void efactor_destroy_data (struct backend *backend) { struct efactor_data *data = backend->data; if (data->lines) { g_strfreev (data->lines); } backend_destroy_data (backend); } //The MIDI Identity Request follows the standard but the Identity Reply does not. static gint efactor_handshake (struct backend *backend) { gint swlen, max, min, presets, id; enum efactor_type type; struct efactor_data *data; GByteArray *tx_msg; GByteArray *rx_msg; tx_msg = g_byte_array_sized_new (sizeof (MIDI_IDENTITY_REQUEST)); g_byte_array_append (tx_msg, (guchar *) MIDI_IDENTITY_REQUEST, sizeof (MIDI_IDENTITY_REQUEST)); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -ENODEV; } if (rx_msg->data[4] == 2) { if (rx_msg->len > 17) { memset (backend->midi_info.company, 0, BE_COMPANY_LEN); memcpy (backend->midi_info.company, &rx_msg->data[5], 1); memcpy (backend->midi_info.family, &rx_msg->data[6], BE_FAMILY_LEN); memcpy (backend->midi_info.model, &rx_msg->data[8], BE_MODEL_LEN); memcpy (backend->midi_info.version, &rx_msg->data[10], BE_VERSION_LEN); snprintf (backend->name, LABEL_MAX, "%02x-%02x-%02x %02x-%02x %02x-%02x", backend->midi_info.company[0], backend->midi_info.company[1], backend->midi_info.company[2], backend->midi_info.family[0], backend->midi_info.family[1], backend->midi_info.model[0], backend->midi_info.model[1]); snprintf (backend->version, LABEL_MAX, "%d.%d.%d.%d", backend->midi_info.version[0], backend->midi_info.version[1], backend->midi_info.version[2], backend->midi_info.version[3]); debug_print (1, "XML version:\n%s", &rx_msg->data[14]); } else { debug_print (1, "Illegal MIDI identity reply length"); } } else { debug_print (1, "Illegal SUB-ID2"); } free_msg (rx_msg); if (memcmp (backend->midi_info.company, EVENTIDE_ID, sizeof (EVENTIDE_ID)) || memcmp (backend->midi_info.family, FAMILY_ID, sizeof (FAMILY_ID)) || memcmp (backend->midi_info.model, MODEL_ID, sizeof (MODEL_ID))) { return -ENODEV; } tx_msg = efactor_new_get_msg (EFACTOR_MSG_TYPE_OBJECT, "0000"); //tj_version_key rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); id = rx_msg->data[sizeof (EFACTOR_REQUEST_HEADER) - 1]; debug_print (1, "Version: %s", &rx_msg->data[7]); free_msg (rx_msg); tx_msg = efactor_new_get_msg (EFACTOR_MSG_TYPE_VALUE, "0001"); //tj_switch_key rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); debug_print (1, "Switches: %s", &rx_msg->data[7]); swlen = strlen ((gchar *) & rx_msg->data[7]) - 2; //Remove single quotes free_msg (rx_msg); tx_msg = efactor_new_get_msg (EFACTOR_MSG_TYPE_OBJECT, "0206"); //sp_num_banks_lo rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); debug_print (1, "Minimum value: %s", &rx_msg->data[7]); min = atoi ((gchar *) & rx_msg->data[9]); free_msg (rx_msg); tx_msg = efactor_new_get_msg (EFACTOR_MSG_TYPE_OBJECT, "020A"); //sp_num_banks rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); debug_print (1, "Maximum value: %s", &rx_msg->data[7]); max = atoi ((gchar *) & rx_msg->data[9]); free_msg (rx_msg); if (swlen == EFACTOR_FACTOR_SW_LEN) { debug_print (1, "Factor pedal detected"); min = 2 * min; max = 2 * (max + 1); type = EFACTOR_FACTOR; } else if (swlen == EFACTOR_H9_SW_LEN) { debug_print (1, "H9 pedal detected"); type = EFACTOR_H9; } else { error_print ("Illegal switches number %d", swlen); return -ENODEV; } presets = max - min; debug_print (1, "Total presets: %d [%d, %d]", presets, min, max - 1); data = g_malloc (sizeof (struct efactor_data)); data->id = id; data->presets = presets; data->min = min; data->type = type; data->lines = NULL; gslist_fill (&backend->fs_ops, &FS_EFACTOR_OPERATIONS, NULL); backend->destroy_data = efactor_destroy_data; backend->data = data; snprintf (backend->name, LABEL_MAX, "%s", EFACTOR_PEDAL_NAME (data)); return 0; } const struct connector CONNECTOR_EFACTOR = { .handshake = efactor_handshake, .name = "efactor", .standard = FALSE, .regex = ".*Factor Pedal.*" }; elektroid-3.2.3/src/connectors/efactor.h000066400000000000000000000016101500236517400202420ustar00rootroot00000000000000/* * efactor.h * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef EFACTOR_H #define EFACTOR_H #include "connector.h" extern const struct connector CONNECTOR_EFACTOR; #endif elektroid-3.2.3/src/connectors/elektron.c000066400000000000000000002714741500236517400204560ustar00rootroot00000000000000/* * elektron.c * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include #include "elektron.h" #include "package.h" #include "common.h" #include "../config.h" #define DEVICES_FILE "/elektron/devices.json" #define DEV_TAG_ID "id" #define DEV_TAG_NAME "name" #define DEV_TAG_FILESYSTEMS "filesystems" #define DEV_TAG_STORAGE "storage" static const gchar *FS_TYPE_NAMES[] = { "+Drive", "RAM", NULL }; static const gchar *FS_RAW_ANY_EXTS[] = { "raw", NULL }; static const gchar *FS_DATA_ANY_EXTS[] = { "data", NULL }; #define DATA_TRANSF_BLOCK_BYTES 0x2000 #define OS_TRANSF_BLOCK_BYTES 0x800 #define MAX_ZIP_SIZE (128 * 1024 * 1024) #define FS_DATA_PRJ_PREFIX "/projects" #define FS_DATA_SND_PREFIX "/soundbanks" #define FS_DATA_PST_PREFIX "/presets" #define FS_SAMPLES_START_POS 5 #define FS_DATA_START_POS 18 #define FS_SAMPLES_SIZE_POS_W 21 #define FS_SAMPLES_LAST_FRAME_POS_W 33 #define FS_SAMPLES_PAD_RES 22 #define ELEKTRON_NAME_MAX_LEN 32 #define ELEKTRON_SAMPLE_INFO_PAD_I32_LEN 10 #define ELEKTRON_LOOP_TYPE_FWD 0 #define ELEKTRON_LOOP_TYPE_NO 0x7f struct elektron_sample_header { guint8 type; guint8 stereo; //0: mono, 1: stereo interleaved guint8 rsvd0[2]; guint32 size; //Bytes guint32 rate; guint32 loop_start; guint32 loop_end; guint8 loop_type; // as in midi sds, 0x00 = forward loop, 0x7F = no loop guint8 rsvd1[3]; guint32 padding[ELEKTRON_SAMPLE_INFO_PAD_I32_LEN]; }; enum elektron_iterator_mode { ITER_MODE_SAMPLE, ITER_MODE_RAW, ITER_MODE_DATA, ITER_MODE_DATA_SND }; struct elektron_iterator_data { GByteArray *msg; guint32 pos; guint32 hash; guint16 operations; guint8 has_valid_data; guint8 has_metadata; enum elektron_iterator_mode mode; gint32 max_slots; struct backend *backend; gboolean load_metadata; }; typedef GByteArray *(*elektron_msg_id_func) (guint); typedef GByteArray *(*elektron_msg_id_len_func) (guint, guint); typedef GByteArray *(*elektron_msg_path_func) (const gchar *); typedef GByteArray *(*elektron_msg_path_len_func) (const gchar *, guint); typedef GByteArray *(*elektron_msg_read_blk_func) (guint, guint, guint); typedef GByteArray *(*elektron_msg_write_blk_func) (guint, GByteArray *, guint *, guint, void *); typedef void (*elektron_copy_array) (GByteArray *, GByteArray *); typedef gint (*elektron_path_func) (struct backend *, const gchar *); typedef gint (*elektron_src_dst_func) (struct backend *, const gchar *, const gchar *); static gint elektron_download_data_snd (struct backend *, const gchar *, struct idata *, struct job_control *); static gint elektron_download_data_snd_pkg (struct backend *, const gchar *, struct idata *, struct job_control *); static gint elektron_download_data_prj_pkg (struct backend *, const gchar *, struct idata *, struct job_control *); static gint elektron_download_data_pst_pkg (struct backend *, const gchar *, struct idata *, struct job_control *); static gint elektron_download_raw_pst_pkg (struct backend *, const gchar *, struct idata *, struct job_control *); static gint elektron_upload_data_prj_pkg (struct backend *, const gchar *, struct idata *, struct job_control *); static gint elektron_upload_data_snd_pkg (struct backend *, const gchar *, struct idata *, struct job_control *); static gint elektron_upload_data_pst_pkg (struct backend *, const gchar *, struct idata *, struct job_control *); static gint elektron_upload_raw_pst_pkg (struct backend *, const gchar *, struct idata *, struct job_control *); static gboolean elektron_sample_file_exists (struct backend *, const gchar *); static gboolean elektron_raw_file_exists (struct backend *, const gchar *); const gchar **elektron_get_dev_exts (struct backend *, const struct fs_operations *); static const guint8 MSG_HEADER[] = { 0xf0, 0, 0x20, 0x3c, 0x10, 0 }; static const guint8 PING_REQUEST[] = { 0x1 }; static const guint8 SOFTWARE_VERSION_REQUEST[] = { 0x2 }; static const guint8 DEVICEUID_REQUEST[] = { 0x3 }; static const guint8 STORAGEINFO_REQUEST[] = { 0x5 }; static const guint8 FS_SAMPLE_READ_DIR_REQUEST[] = { 0x10 }; static const guint8 FS_SAMPLE_CREATE_DIR_REQUEST[] = { 0x11 }; static const guint8 FS_SAMPLE_DELETE_DIR_REQUEST[] = { 0x12 }; static const guint8 FS_SAMPLE_DELETE_FILE_REQUEST[] = { 0x20 }; static const guint8 FS_SAMPLE_RENAME_FILE_REQUEST[] = { 0x21 }; static const guint8 FS_SAMPLE_GET_FILE_INFO_FROM_PATH_REQUEST[] = { 0x22 }; static const guint8 FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST[] = { 0x23, 0, 0, 0, 0, 0, 0, 0, 0 }; static const guint8 FS_SAMPLE_OPEN_FILE_READER_REQUEST[] = { 0x30 }; static const guint8 FS_SAMPLE_CLOSE_FILE_READER_REQUEST[] = { 0x31 }; static const guint8 FS_SAMPLE_READ_FILE_REQUEST[] = { 0x32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const guint8 FS_SAMPLE_OPEN_FILE_WRITER_REQUEST[] = { 0x40, 0, 0, 0, 0 }; static const guint8 FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST[] = { 0x41, 0, 0, 0, 0, 0, 0, 0, 0 }; static const guint8 FS_SAMPLE_WRITE_FILE_REQUEST[] = { 0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const guint8 FS_RAW_READ_DIR_REQUEST[] = { 0x14 }; static const guint8 FS_RAW_CREATE_DIR_REQUEST[] = { 0x15 }; static const guint8 FS_RAW_DELETE_DIR_REQUEST[] = { 0x16 }; static const guint8 FS_RAW_DELETE_FILE_REQUEST[] = { 0x24 }; static const guint8 FS_RAW_RENAME_FILE_REQUEST[] = { 0x25 }; static const guint8 FS_RAW_GET_FILE_INFO_FROM_PATH_REQUEST[] = { 0x26 }; static const guint8 FS_RAW_OPEN_FILE_READER_REQUEST[] = { 0x33 }; static const guint8 FS_RAW_CLOSE_FILE_READER_REQUEST[] = { 0x34 }; static const guint8 FS_RAW_READ_FILE_REQUEST[] = { 0x35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const guint8 FS_RAW_OPEN_FILE_WRITER_REQUEST[] = { 0x43, 0, 0, 0, 0 }; static const guint8 FS_RAW_CLOSE_FILE_WRITER_REQUEST[] = { 0x44, 0, 0, 0, 0, 0, 0, 0, 0 }; static const guint8 FS_RAW_WRITE_FILE_REQUEST[] = { 0x45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const guint8 DATA_LIST_REQUEST[] = { 0x53 }; static const guint8 DATA_READ_OPEN_REQUEST[] = { 0x54 }; static const guint8 DATA_READ_PARTIAL_REQUEST[] = { 0x55 }; static const guint8 DATA_READ_CLOSE_REQUEST[] = { 0x56 }; static const guint8 DATA_WRITE_OPEN_REQUEST[] = { 0x57 }; static const guint8 DATA_WRITE_PARTIAL_REQUEST[] = { 0x58 }; static const guint8 DATA_WRITE_CLOSE_REQUEST[] = { 0x59 }; static const guint8 DATA_MOVE_REQUEST[] = { 0x5a }; static const guint8 DATA_COPY_REQUEST[] = { 0x5b }; static const guint8 DATA_CLEAR_REQUEST[] = { 0x5c }; static const guint8 DATA_SWAP_REQUEST[] = { 0x5d }; static const guint8 OS_UPGRADE_START_REQUEST[] = { 0x50, 0, 0, 0, 0, 's', 'y', 's', 'e', 'x', '\0', 1 }; static const guint8 OS_UPGRADE_WRITE_RESPONSE[] = { 0x51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static gchar * elektron_get_id_as_slot (struct item *item, struct backend *backend) { gchar *slot = g_malloc (LABEL_MAX); if (item->id >= 0) { snprintf (slot, LABEL_MAX, "%03d", item->id); } else { slot[0] = 0; } return slot; } static void elektron_print_smplrw (struct item_iterator *iter, struct backend *backend, const struct fs_operations *fs_ops) { gchar *hsize = get_human_size (iter->item.size, FALSE); struct elektron_iterator_data *data = iter->data; printf ("%c %10s %08x %s\n", iter->item.type, hsize, data->hash, iter->item.name); g_free (hsize); } static void elektron_print_data (struct item_iterator *iter, struct backend *backend, const struct fs_operations *fs_ops) { struct elektron_iterator_data *data = iter->data; gchar *hsize = get_human_size (iter->item.size, FALSE); gchar *slot = iter->item.id > 0 ? elektron_get_id_as_slot (&iter->item, backend) : strdup (" -1"); gboolean info = (fs_ops->options & FS_OPTION_SHOW_INFO_COLUMN) && *iter->item.object_info; printf ("%c %04x %d %d %10s %s %-*s%s%s%s\n", iter->item.type, data->operations, data->has_valid_data, data->has_metadata, hsize, slot, DEFAULT_MAX_NAME_LEN, iter->item.name, info ? " [ " : "", iter->item.object_info, info ? " ]" : ""); g_free (hsize); g_free (slot); } static void elektron_free_iterator_data (void *iter_data) { struct elektron_iterator_data *data = iter_data; free_msg (data->msg); g_free (data); } static inline void elektron_get_utf8 (gchar *dst, const gchar *s) { gchar *aux = g_convert (s, -1, "UTF8", "CP1252", NULL, NULL, NULL); snprintf (dst, LABEL_MAX, "%s", aux); g_free (aux); } static inline gchar * elektron_get_cp1252 (const gchar *s) { return g_convert (s, -1, "CP1252", "UTF8", NULL, NULL, NULL); } static inline guint8 elektron_get_msg_status (const GByteArray *msg) { return msg->data[5]; } static inline gchar * elektron_get_msg_string (const GByteArray *msg) { return (gchar *) & msg->data[6]; } static gint elektron_next_smplrw_entry (struct item_iterator *iter) { guint32 *data32; gchar *name_cp1252; struct elektron_iterator_data *data = iter->data; if (data->pos == data->msg->len) { return -ENOENT; } else { data32 = (guint32 *) & data->msg->data[data->pos]; data->hash = g_ntohl (*data32); data->pos += sizeof (guint32); data32 = (guint32 *) & data->msg->data[data->pos]; iter->item.size = g_ntohl (*data32); data->pos += sizeof (guint32); data->pos++; //write_protected iter->item.type = data->msg->data[data->pos]; data->pos++; name_cp1252 = (gchar *) & data->msg->data[data->pos]; elektron_get_utf8 (iter->item.name, name_cp1252); if (data->mode == ITER_MODE_RAW && iter->item.type == ITEM_TYPE_FILE) { //This eliminates the extension ".mc-snd" that the device provides. iter->item.name[strlen (iter->item.name) - 7] = 0; } data->pos += strlen (name_cp1252) + 1; iter->item.id = -1; return 0; } } static gint elektron_init_iterator (struct backend *backend, struct item_iterator *iter, const gchar *dir, GByteArray *msg, iterator_next next, enum elektron_iterator_mode mode, gint32 max_slots) { struct elektron_iterator_data *data = g_malloc (sizeof (struct elektron_iterator_data)); data->msg = msg; data->pos = (mode == ITER_MODE_DATA || mode == ITER_MODE_DATA_SND) ? FS_DATA_START_POS : FS_SAMPLES_START_POS; data->mode = mode; data->max_slots = max_slots; data->backend = backend; data->load_metadata = TRUE; item_iterator_init (iter, dir, data, next, elektron_free_iterator_data); iter->item.id = 0; //This is needed to point to the next item id iter->item.type = ITEM_TYPE_NONE; //This is needed in case the response when reading a directory is empty return 0; } static GByteArray * elektron_decode_payload (const GByteArray *src) { GByteArray *dst; int i, j, k, dst_len; unsigned int shift; dst_len = src->len - ceill (src->len / 8.0); dst = g_byte_array_sized_new (dst_len); dst->len = dst_len; for (i = 0, j = 0; i < src->len; i += 8, j += 7) { shift = 0x40; for (k = 0; k < 7 && i + k + 1 < src->len; k++) { dst->data[j + k] = src->data[i + k + 1] | (src->data[i] & shift ? 0x80 : 0); shift = shift >> 1; } } return dst; } static GByteArray * elektron_encode_payload (const GByteArray *src) { GByteArray *dst; int i, j, k, dst_len; unsigned int accum; dst_len = src->len + ceill (src->len / 7.0); dst = g_byte_array_sized_new (dst_len); dst->len = dst_len; for (i = 0, j = 0; j < src->len; i += 8, j += 7) { accum = 0; for (k = 0; k < 7; k++) { accum = accum << 1; if (j + k < src->len) { if (src->data[j + k] & 0x80) { accum |= 1; } dst->data[i + k + 1] = src->data[j + k] & 0x7f; } } dst->data[i] = accum; } return dst; } static GByteArray * elektron_msg_to_raw (const GByteArray *msg) { GByteArray *encoded = elektron_encode_payload (msg); guint total = sizeof (MSG_HEADER) + encoded->len + 1; GByteArray *raw = g_byte_array_sized_new (total); g_byte_array_append (raw, MSG_HEADER, sizeof (MSG_HEADER)); g_byte_array_append (raw, encoded->data, encoded->len); g_byte_array_append (raw, (guint8 *) "\xf7", 1); free_msg (encoded); return raw; } static gint elektron_get_smplrw_info_from_msg (GByteArray *info_msg, guint32 *id, guint *size) { if (elektron_get_msg_status (info_msg)) { if (id) { *id = g_ntohl (*((guint32 *) & info_msg->data[6])); } if (size) { *size = g_ntohl (*((guint32 *) & info_msg->data[10])); } } else { if (id) { return -EIO; } } return 0; } static GByteArray * elektron_new_msg (const guint8 *data, guint len) { GByteArray *msg = g_byte_array_new (); g_byte_array_append (msg, (guchar *) "\0\0\0\0", 4); g_byte_array_append (msg, data, len); return msg; } static GByteArray * elektron_new_msg_uint8 (const guint8 *data, guint len, guint8 type) { GByteArray *msg = elektron_new_msg (data, len); g_byte_array_append (msg, &type, 1); return msg; } static GByteArray * elektron_new_msg_path (const guint8 *data, guint len, const gchar *path) { GByteArray *msg; gchar *path_cp1252 = elektron_get_cp1252 (path); if (!path_cp1252) { return NULL; } msg = elektron_new_msg (data, len); g_byte_array_append (msg, (guchar *) path_cp1252, strlen (path_cp1252) + 1); g_free (path_cp1252); return msg; } static GByteArray * elektron_new_msg_close_common_read (const guint8 *data, guint len, guint id) { guint32 aux32; GByteArray *msg = elektron_new_msg (data, len); aux32 = g_htonl (id); g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32)); return msg; } static GByteArray * elektron_new_msg_close_sample_read (guint id) { return elektron_new_msg_close_common_read (FS_SAMPLE_CLOSE_FILE_READER_REQUEST, sizeof (FS_SAMPLE_CLOSE_FILE_READER_REQUEST), id); } static GByteArray * elektron_new_msg_close_raw_read (guint id) { return elektron_new_msg_close_common_read (FS_RAW_CLOSE_FILE_READER_REQUEST, sizeof (FS_RAW_CLOSE_FILE_READER_REQUEST), id); } static GByteArray * elektron_new_msg_open_common_write (const guint8 *data, guint len, const gchar *path, guint bytes) { guint32 aux32; GByteArray *msg = elektron_new_msg_path (data, len, path); aux32 = g_htonl (bytes); memcpy (&msg->data[5], &aux32, sizeof (guint32)); return msg; } static GByteArray * elektron_new_msg_open_sample_write (const gchar *path, guint bytes) { return elektron_new_msg_open_common_write (FS_SAMPLE_OPEN_FILE_WRITER_REQUEST, sizeof (FS_SAMPLE_OPEN_FILE_WRITER_REQUEST), path, bytes + sizeof (struct elektron_sample_header)); } static GByteArray * elektron_new_msg_open_raw_write (const gchar *path, guint bytes) { return elektron_new_msg_open_common_write (FS_RAW_OPEN_FILE_WRITER_REQUEST, sizeof (FS_RAW_OPEN_FILE_WRITER_REQUEST), path, bytes); } static GByteArray * elektron_new_msg_list (const gchar *path, int32_t start_index, int32_t end_index, gboolean all) { guint32 aux32; guint8 aux8; GByteArray *msg = elektron_new_msg_path (DATA_LIST_REQUEST, sizeof (DATA_LIST_REQUEST), path); aux32 = g_htonl (start_index); g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32)); aux32 = g_htonl (end_index); g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32)); aux8 = all; g_byte_array_append (msg, (guchar *) & aux8, sizeof (guint8)); return msg; } static GByteArray * elektron_new_msg_write_sample_blk (guint id, GByteArray *sample, guint *total, guint seq, void *data) { guint32 aux32; guint16 aux16, *aux16p; int i, consumed, bytes_blk; struct sample_info *sample_info = data; struct elektron_sample_header elektron_sample_header; GByteArray *msg = elektron_new_msg (FS_SAMPLE_WRITE_FILE_REQUEST, sizeof (FS_SAMPLE_WRITE_FILE_REQUEST)); aux32 = g_htonl (id); memcpy (&msg->data[5], &aux32, sizeof (guint32)); aux32 = g_htonl (DATA_TRANSF_BLOCK_BYTES * seq); memcpy (&msg->data[13], &aux32, sizeof (guint32)); bytes_blk = DATA_TRANSF_BLOCK_BYTES; consumed = 0; if (seq == 0) { //See comment in elektron_sample_header struct. guint8 loop_type = sample_info->loop_type ? ELEKTRON_LOOP_TYPE_NO : ELEKTRON_LOOP_TYPE_FWD; elektron_sample_header.type = 0; elektron_sample_header.stereo = sample_info->channels - 1; memset (&elektron_sample_header.rsvd0, 0, 2); elektron_sample_header.size = g_htonl (sample->len); elektron_sample_header.rate = g_htonl (ELEKTRON_SAMPLE_RATE); elektron_sample_header.loop_start = g_htonl (sample_info->loop_start); elektron_sample_header.loop_end = g_htonl (sample_info->loop_end); elektron_sample_header.loop_type = loop_type; memset (&elektron_sample_header.rsvd1, 0, 3); memset (&elektron_sample_header.padding, 0, sizeof (guint32) * ELEKTRON_SAMPLE_INFO_PAD_I32_LEN); g_byte_array_append (msg, (guchar *) & elektron_sample_header, sizeof (struct elektron_sample_header)); consumed = sizeof (struct elektron_sample_header); bytes_blk -= consumed; } i = 0; aux16p = (guint16 *) & sample->data[*total]; while (i < bytes_blk && *total < sample->len) { aux16 = g_htons (*aux16p); g_byte_array_append (msg, (guint8 *) & aux16, sizeof (guint16)); aux16p++; (*total) += sizeof (guint16); consumed += sizeof (guint16); i += sizeof (guint16); } aux32 = g_htonl (consumed); memcpy (&msg->data[9], &aux32, sizeof (guint32)); return msg; } static GByteArray * elektron_new_msg_write_raw_blk (guint id, GByteArray *raw, guint *total, guint seq, void *data) { gint len; guint32 aux32; GByteArray *msg = elektron_new_msg (FS_RAW_WRITE_FILE_REQUEST, sizeof (FS_RAW_WRITE_FILE_REQUEST)); aux32 = g_htonl (id); memcpy (&msg->data[5], &aux32, sizeof (guint32)); aux32 = g_htonl (DATA_TRANSF_BLOCK_BYTES * seq); memcpy (&msg->data[13], &aux32, sizeof (guint32)); len = raw->len - *total; len = len > DATA_TRANSF_BLOCK_BYTES ? DATA_TRANSF_BLOCK_BYTES : len; g_byte_array_append (msg, &raw->data[*total], len); (*total) += len; aux32 = g_htonl (len); memcpy (&msg->data[9], &aux32, sizeof (guint32)); return msg; } static GByteArray * elektron_new_msg_close_common_write (const guint8 *data, guint len, guint id, guint bytes) { guint32 aux32; GByteArray *msg = elektron_new_msg (data, len); aux32 = g_htonl (id); memcpy (&msg->data[5], &aux32, sizeof (guint32)); aux32 = g_htonl (bytes); memcpy (&msg->data[9], &aux32, sizeof (guint32)); return msg; } static GByteArray * elektron_new_msg_close_sample_write (guint id, guint bytes) { return elektron_new_msg_close_common_write (FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST, sizeof (FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST), id, bytes + sizeof (struct elektron_sample_header)); } static GByteArray * elektron_new_msg_close_raw_write (guint id, guint bytes) { return elektron_new_msg_close_common_write (FS_RAW_CLOSE_FILE_WRITER_REQUEST, sizeof (FS_RAW_CLOSE_FILE_WRITER_REQUEST), id, bytes); } static GByteArray * elektron_new_msg_read_common_blk (const guint8 *data, guint len, guint id, guint start, guint size) { guint32 aux; GByteArray *msg = elektron_new_msg (data, len); aux = g_htonl (id); memcpy (&msg->data[5], &aux, sizeof (guint32)); aux = g_htonl (size); memcpy (&msg->data[9], &aux, sizeof (guint32)); aux = g_htonl (start); memcpy (&msg->data[13], &aux, sizeof (guint32)); return msg; } static GByteArray * elektron_new_msg_read_sample_blk (guint id, guint start, guint size) { return elektron_new_msg_read_common_blk (FS_SAMPLE_READ_FILE_REQUEST, sizeof (FS_SAMPLE_READ_FILE_REQUEST), id, start, size); } static GByteArray * elektron_new_msg_read_raw_blk (guint id, guint start, guint size) { return elektron_new_msg_read_common_blk (FS_RAW_READ_FILE_REQUEST, sizeof (FS_RAW_READ_FILE_REQUEST), id, start, size); } static GByteArray * elektron_raw_to_msg (GByteArray *sysex) { GByteArray *msg; GByteArray *payload; guint len = sysex->len - sizeof (MSG_HEADER) - 1; if (len > 0) { payload = g_byte_array_sized_new (len); g_byte_array_append (payload, &sysex->data[sizeof (MSG_HEADER)], len); msg = elektron_decode_payload (payload); free_msg (payload); } else { msg = NULL; } return msg; } static gint elektron_tx (struct backend *backend, const GByteArray *msg) { gint res; guint16 aux; gchar *text; struct sysex_transfer transfer; struct elektron_data *data = backend->data; aux = g_htons (data->seq); memcpy (msg->data, &aux, sizeof (guint16)); data->seq++; transfer.raw = elektron_msg_to_raw (msg); res = backend_tx_sysex (backend, &transfer); if (!res) { text = debug_get_hex_msg (msg); debug_print (1, "Message sent (%d): %s", msg->len, text); g_free (text); } free_msg (transfer.raw); return res; } static GByteArray * elektron_rx (struct backend *backend, gint timeout) { gchar *text; GByteArray *msg; struct sysex_transfer transfer; transfer.timeout = timeout; transfer.batch = FALSE; while (1) { if (backend_rx_sysex (backend, &transfer)) { return NULL; } if (transfer.raw->len >= 12 && !memcmp (transfer.raw->data, MSG_HEADER, 6)) { break; } if (debug_level > 1) { text = debug_get_hex_msg (transfer.raw); debug_print (2, "Message skipped (%d): %s", transfer.raw->len, text); g_free (text); } free_msg (transfer.raw); } msg = elektron_raw_to_msg (transfer.raw); if (msg) { text = debug_get_hex_msg (msg); debug_print (1, "Message received (%d): %s", msg->len, text); g_free (text); } free_msg (transfer.raw); return msg; } //Synchronized static GByteArray * elektron_tx_and_rx_timeout (struct backend *backend, GByteArray *tx_msg, gint timeout) { ssize_t len; guint16 seq; GByteArray *rx_msg; guint msg_type = tx_msg->data[4] | 0x80; struct elektron_data *data = backend->data; gint t = timeout < 0 ? BE_SYSEX_TIMEOUT_MS : timeout; g_mutex_lock (&backend->mutex); seq = data->seq; len = elektron_tx (backend, tx_msg); if (len < 0) { rx_msg = NULL; goto cleanup; } while (1) { rx_msg = elektron_rx (backend, t); if (!rx_msg) { break; } guint16 exp_seq = g_ntohs (*((guint16 *) & rx_msg->data[2])); if (seq != exp_seq) { error_print ("Unexpected sequence in response. Skipping..."); free_msg (rx_msg); continue; } if (rx_msg->data[4] != msg_type) { error_print ("Illegal message type in response. Skipping..."); free_msg (rx_msg); rx_msg = NULL; break; } break; } cleanup: g_mutex_unlock (&backend->mutex); free_msg (tx_msg); return rx_msg; } static GByteArray * elektron_tx_and_rx (struct backend *backend, GByteArray *tx_msg) { return elektron_tx_and_rx_timeout (backend, tx_msg, -1); } static enum item_type elektron_get_path_type (struct backend *backend, const gchar *path, fs_init_iter_func init_iter) { gchar *dir, *name; enum item_type res; struct item_iterator iter; if (strcmp (path, "/") == 0) { return ITEM_TYPE_DIR; } name = g_path_get_basename (path); dir = g_path_get_dirname (path); res = ITEM_TYPE_NONE; if (!init_iter (backend, &iter, dir, NULL)) { while (!item_iterator_next (&iter)) { if (strcmp (name, iter.item.name) == 0) { res = iter.item.type; break; } } item_iterator_free (&iter); } g_free (name); g_free (dir); return res; } static gint elektron_read_common_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const guint8 msg[], int size, fs_init_iter_func init_iter, enum elektron_iterator_mode mode, fs_file_exists file_exists) { GByteArray *tx_msg, *rx_msg = NULL; gboolean is_file = file_exists (backend, dir); usleep (BE_REST_TIME_US); if (is_file) { return -ENOTDIR; } tx_msg = elektron_new_msg_path (msg, size, dir); if (!tx_msg) { return -EINVAL; } rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { return -EIO; } if (rx_msg->len == 5 && elektron_get_path_type (backend, dir, init_iter) != ITEM_TYPE_DIR) { free_msg (rx_msg); return -ENOTDIR; } return elektron_init_iterator (backend, iter, dir, rx_msg, elektron_next_smplrw_entry, mode, -1); } static gint elektron_read_samples_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { return elektron_read_common_dir (backend, iter, dir, FS_SAMPLE_READ_DIR_REQUEST, sizeof (FS_SAMPLE_READ_DIR_REQUEST), elektron_read_samples_dir, ITER_MODE_SAMPLE, elektron_sample_file_exists); } static gint elektron_read_raw_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { return elektron_read_common_dir (backend, iter, dir, FS_RAW_READ_DIR_REQUEST, sizeof (FS_RAW_READ_DIR_REQUEST), elektron_read_raw_dir, ITER_MODE_RAW, elektron_raw_file_exists); } static gint elektron_src_dst_common (struct backend *backend, const gchar *src, const gchar *dst, const guint8 *data, guint len) { gint res; GByteArray *rx_msg; GByteArray *tx_msg = elektron_new_msg (data, len); gchar *dst_cp1252 = elektron_get_cp1252 (dst); if (!dst_cp1252) { return -EINVAL; } gchar *src_cp1252 = elektron_get_cp1252 (src); if (!src_cp1252) { g_free (dst_cp1252); return -EINVAL; } g_byte_array_append (tx_msg, (guchar *) src_cp1252, strlen (src_cp1252) + 1); g_byte_array_append (tx_msg, (guchar *) dst_cp1252, strlen (dst_cp1252) + 1); g_free (src_cp1252); g_free (dst_cp1252); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { return -EIO; } //Response: x, x, x, x, 0xa1, [0 (error), 1 (success)]... if (elektron_get_msg_status (rx_msg)) { res = 0; } else { res = -EPERM; error_print ("%s (%s)", backend_strerror (backend, res), elektron_get_msg_string (rx_msg)); } free_msg (rx_msg); return res; } static gint elektron_rename_sample_file (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_src_dst_common (backend, src, dst, FS_SAMPLE_RENAME_FILE_REQUEST, sizeof (FS_SAMPLE_RENAME_FILE_REQUEST)); } static gint elektron_rename_raw_file (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_src_dst_common (backend, src, dst, FS_RAW_RENAME_FILE_REQUEST, sizeof (FS_RAW_RENAME_FILE_REQUEST)); } static gint elektron_move_common_item (struct backend *backend, const gchar *src, const gchar *dst, fs_init_iter_func init_iter, elektron_src_dst_func mv, fs_path_func mkdir, elektron_path_func rmdir) { enum item_type type; gint res; gchar *src_plus; gchar *dst_plus; struct item_iterator iter; //Renaming is not implemented for directories so we need to implement it. debug_print (1, "Renaming remotely from %s to %s...", src, dst); type = elektron_get_path_type (backend, src, init_iter); if (type == ITEM_TYPE_FILE) { return mv (backend, src, dst); } else if (type == ITEM_TYPE_DIR) { res = mkdir (backend, dst); if (res) { return res; } if (!init_iter (backend, &iter, src, NULL)) { while (!item_iterator_next (&iter) && !res) { src_plus = path_chain (PATH_INTERNAL, src, iter.item.name); dst_plus = path_chain (PATH_INTERNAL, dst, iter.item.name); res = elektron_move_common_item (backend, src_plus, dst_plus, init_iter, mv, mkdir, rmdir); g_free (src_plus); g_free (dst_plus); } item_iterator_free (&iter); } if (!res) { res = rmdir (backend, src); } return res; } else { return -EBADF; } } static gint elektron_path_common (struct backend *backend, const gchar *path, const guint8 *template, gint size) { gint res; GByteArray *rx_msg; GByteArray *tx_msg; tx_msg = elektron_new_msg_path (template, size, path); if (!tx_msg) { return -EINVAL; } rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { return -EIO; } //Response: x, x, x, x, 0xX0, [0 (error), 1 (success)]... if (elektron_get_msg_status (rx_msg)) { res = 0; } else { res = -EPERM; debug_print (1, "Error: %s", elektron_get_msg_string (rx_msg)); } free_msg (rx_msg); return res; } static gint elektron_delete_sample (struct backend *backend, const gchar *path) { return elektron_path_common (backend, path, FS_SAMPLE_DELETE_FILE_REQUEST, sizeof (FS_SAMPLE_DELETE_FILE_REQUEST)); } static gint elektron_delete_samples_dir (struct backend *backend, const gchar *path) { return elektron_path_common (backend, path, FS_SAMPLE_DELETE_DIR_REQUEST, sizeof (FS_SAMPLE_DELETE_DIR_REQUEST)); } //This adds back the extension ".mc-snd" that the device provides. static gchar * elektron_add_ext_to_mc_snd (const gchar *path) { gchar *path_with_ext; GString *str = g_string_new (path); g_string_append (str, ".mc-snd"); path_with_ext = g_string_free (str, FALSE); return path_with_ext; } static gboolean elektron_sample_file_exists (struct backend *backend, const gchar *path) { gint res = elektron_path_common (backend, path, FS_SAMPLE_GET_FILE_INFO_FROM_PATH_REQUEST, sizeof (FS_SAMPLE_GET_FILE_INFO_FROM_PATH_REQUEST)); return res == 0; } static gboolean elektron_raw_file_exists (struct backend *backend, const gchar *path) { gchar *name_with_ext = elektron_add_ext_to_mc_snd (path); gint res = elektron_path_common (backend, path, FS_RAW_GET_FILE_INFO_FROM_PATH_REQUEST, sizeof (FS_RAW_GET_FILE_INFO_FROM_PATH_REQUEST)); g_free (name_with_ext); return res == 0; } static gint elektron_delete_raw (struct backend *backend, const gchar *path) { gint ret; gchar *path_with_ext = elektron_add_ext_to_mc_snd (path); ret = elektron_path_common (backend, path_with_ext, FS_RAW_DELETE_FILE_REQUEST, sizeof (FS_RAW_DELETE_FILE_REQUEST)); g_free (path_with_ext); return ret; } static gint elektron_delete_raw_dir (struct backend *backend, const gchar *path) { return elektron_path_common (backend, path, FS_RAW_DELETE_DIR_REQUEST, sizeof (FS_RAW_DELETE_DIR_REQUEST)); } static gint elektron_create_samples_dir (struct backend *backend, const gchar *path) { return elektron_path_common (backend, path, FS_SAMPLE_CREATE_DIR_REQUEST, sizeof (FS_SAMPLE_CREATE_DIR_REQUEST)); } static gint elektron_move_samples_item (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_move_common_item (backend, src, dst, elektron_read_samples_dir, elektron_rename_sample_file, elektron_create_samples_dir, elektron_delete_samples_dir); } static gint elektron_create_raw_dir (struct backend *backend, const gchar *path) { return elektron_path_common (backend, path, FS_RAW_CREATE_DIR_REQUEST, sizeof (FS_RAW_CREATE_DIR_REQUEST)); } static gint elektron_move_raw_item (struct backend *backend, const gchar *src, const gchar *dst) { gint ret; gchar *src_with_ext = elektron_add_ext_to_mc_snd (src); ret = elektron_move_common_item (backend, src_with_ext, dst, elektron_read_raw_dir, elektron_rename_raw_file, elektron_create_raw_dir, elektron_delete_raw_dir); g_free (src_with_ext); return ret; } static gint elektron_delete_common_item (struct backend *backend, const gchar *path, fs_init_iter_func init_iter, elektron_path_func rmdir, elektron_path_func rm) { enum item_type type; gchar *new_path; struct item_iterator iter; gint res; type = elektron_get_path_type (backend, path, init_iter); if (type == ITEM_TYPE_FILE) { return rm (backend, path); } else if (type == ITEM_TYPE_DIR) { debug_print (1, "Deleting %s samples dir...", path); if (init_iter (backend, &iter, path, NULL)) { error_print ("Error while opening samples dir %s dir", path); res = -EINVAL; } else { res = 0; while (!res && !item_iterator_next (&iter)) { new_path = path_chain (PATH_INTERNAL, path, iter.item.name); res = res || elektron_delete_common_item (backend, new_path, init_iter, rmdir, rm); g_free (new_path); } item_iterator_free (&iter); } return res || rmdir (backend, path); } else { return -EBADF; } } static gint elektron_delete_samples_item (struct backend *backend, const gchar *path) { return elektron_delete_common_item (backend, path, elektron_read_samples_dir, elektron_delete_samples_dir, elektron_delete_sample); } static gint elektron_delete_raw_item (struct backend *backend, const gchar *path) { return elektron_delete_common_item (backend, path, elektron_read_raw_dir, elektron_delete_raw_dir, elektron_delete_raw); } static gint elektron_upload_smplrw (struct backend *backend, const gchar *path, struct idata *smplrw, struct job_control *control, elektron_msg_path_len_func new_msg_open_write, elektron_msg_write_blk_func new_msg_write_blk, elektron_msg_id_len_func new_msg_close_write) { GByteArray *tx_msg; GByteArray *rx_msg; guint transferred; guint32 id; int i; gboolean active; gint res = 0; GByteArray *input = smplrw->content; //If the file already exists the device makes no difference between creating a new file and creating an already existent file. //Also, the new file would be discarded if an upload is not completed. tx_msg = new_msg_open_write (path, input->len); if (!tx_msg) { return -EINVAL; } rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { return -EIO; } //Response: x, x, x, x, 0xc0, [0 (error), 1 (success)], id, frames res = elektron_get_smplrw_info_from_msg (rx_msg, &id, NULL); if (res) { error_print ("%s (%s)", backend_strerror (backend, res), elektron_get_msg_string (rx_msg)); free_msg (rx_msg); return res; } free_msg (rx_msg); transferred = 0; i = 0; g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); while (transferred < input->len && active) { tx_msg = new_msg_write_blk (id, input, &transferred, i, smplrw->info); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { return -EIO; } //Response: x, x, x, x, 0xc2, [0 (error), 1 (success)]... if (!elektron_get_msg_status (rx_msg)) { error_print ("Unexpected status"); } free_msg (rx_msg); i++; job_control_set_progress (control, transferred / (double) input->len); g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); usleep (BE_REST_TIME_US); } debug_print (2, "%d bytes sent", transferred); if (active) { tx_msg = new_msg_close_write (id, transferred); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { return -EIO; } //Response: x, x, x, x, 0xc1, [0 (error), 1 (success)]... if (!elektron_get_msg_status (rx_msg)) { error_print ("Unexpected status"); } free_msg (rx_msg); } return res; } gint elektron_upload_sample_part (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { return elektron_upload_smplrw (backend, path, sample, control, elektron_new_msg_open_sample_write, elektron_new_msg_write_sample_blk, elektron_new_msg_close_sample_write); } static gint elektron_upload_sample (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { control->parts = 1; control->part = 0; return elektron_upload_sample_part (backend, path, sample, control); } static gint elektron_upload_raw (struct backend *backend, const gchar *path, struct idata *raw, struct job_control *control) { return elektron_upload_smplrw (backend, path, raw, control, elektron_new_msg_open_raw_write, elektron_new_msg_write_raw_blk, elektron_new_msg_close_raw_write); } static GByteArray * elektron_new_msg_open_sample_read (const gchar *path) { return elektron_new_msg_path (FS_SAMPLE_OPEN_FILE_READER_REQUEST, sizeof (FS_SAMPLE_OPEN_FILE_READER_REQUEST), path); } static GByteArray * elektron_new_msg_open_raw_read (const gchar *path) { return elektron_new_msg_path (FS_RAW_OPEN_FILE_READER_REQUEST, sizeof (FS_RAW_OPEN_FILE_READER_REQUEST), path); } static void elektron_copy_sample_data (GByteArray *input, GByteArray *output) { gint i; gint16 v; gint16 *frame = (gint16 *) input->data; for (i = 0; i < input->len; i += sizeof (gint16)) { v = g_ntohs (*frame); g_byte_array_append (output, (guint8 *) & v, sizeof (gint16)); frame++; } } static void elektron_copy_raw_data (GByteArray *input, GByteArray *output) { g_byte_array_append (output, input->data, input->len); } static gint elektron_download_smplrw (struct backend *backend, const gchar *path, struct idata *smplrw, struct job_control *control, elektron_msg_path_func new_msg_open_read, guint read_offset, elektron_msg_read_blk_func new_msg_read_blk, elektron_msg_id_func new_msg_close_read, elektron_copy_array copy_array) { struct sample_info *sample_info = NULL; struct elektron_sample_header *elektron_sample_header; GByteArray *tx_msg, *rx_msg; GByteArray *array, *output; guint32 id; guint frames; guint next_block_start; guint req_size; guint offset; gboolean active; gint res; tx_msg = new_msg_open_read (path); if (!tx_msg) { return -EINVAL; } rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { return -EIO; } res = elektron_get_smplrw_info_from_msg (rx_msg, &id, &frames); if (res) { error_print ("%s (%s)", backend_strerror (backend, res), elektron_get_msg_string (rx_msg)); free_msg (rx_msg); return res; } free_msg (rx_msg); debug_print (2, "%d frames to download", frames); g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); output = g_byte_array_new (); array = g_byte_array_new (); res = 0; next_block_start = 0; offset = read_offset; while (next_block_start < frames && active) { req_size = frames - next_block_start > DATA_TRANSF_BLOCK_BYTES ? DATA_TRANSF_BLOCK_BYTES : frames - next_block_start; tx_msg = new_msg_read_blk (id, next_block_start, req_size); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { res = -EIO; goto cleanup; } g_byte_array_append (array, &rx_msg->data[FS_SAMPLES_PAD_RES + offset], req_size - offset); next_block_start += req_size; //Only in the first iteration. It has no effect for the raw filesystem (M:C) as offset is 0. if (offset) { offset = 0; elektron_sample_header = (struct elektron_sample_header *) &rx_msg->data[FS_SAMPLES_PAD_RES]; sample_info = g_malloc (sizeof (struct sample_info)); sample_info->frames = frames; sample_info->loop_start = g_ntohl (elektron_sample_header->loop_start); sample_info->loop_end = g_ntohl (elektron_sample_header->loop_end); sample_info->loop_type = elektron_sample_header->loop_type; sample_info->rate = g_ntohl (elektron_sample_header->rate); //In the case of the RAW filesystem is not used and it is harmless. sample_info->midi_note = 0; sample_info->channels = elektron_sample_header->stereo + 1; sample_info->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; debug_print (2, "Loop start at %d, loop end at %d", sample_info->loop_start, sample_info->loop_end); } free_msg (rx_msg); job_control_set_progress (control, next_block_start / (double) frames); g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); usleep (BE_REST_TIME_US); } debug_print (2, "%d bytes received", next_block_start); if (active) { copy_array (array, output); } else { res = -1; } tx_msg = new_msg_close_read (id); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { res = -EIO; goto cleanup; } //Response: x, x, x, x, 0xb1, 00 00 00 0a 00 01 65 de (sample id and received bytes) free_msg (rx_msg); cleanup: free_msg (array); if (res) { g_byte_array_free (output, TRUE); g_free (sample_info); } else { idata_init (smplrw, output, g_path_get_basename (path), sample_info); } return res; } gint elektron_download_sample_part (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { return elektron_download_smplrw (backend, path, sample, control, elektron_new_msg_open_sample_read, sizeof (struct elektron_sample_header), elektron_new_msg_read_sample_blk, elektron_new_msg_close_sample_read, elektron_copy_sample_data); } static gint elektron_download_sample (struct backend *backend, const gchar *path, struct idata *file, struct job_control *control) { control->parts = 1; control->part = 0; return elektron_download_sample_part (backend, path, file, control); } static gint elektron_download_raw (struct backend *backend, const gchar *path, struct idata *file, struct job_control *control) { gint ret; gchar *path_with_ext = elektron_add_ext_to_mc_snd (path); ret = elektron_download_smplrw (backend, path_with_ext, file, control, elektron_new_msg_open_raw_read, 0, elektron_new_msg_read_raw_blk, elektron_new_msg_close_raw_read, elektron_copy_raw_data); g_free (path_with_ext); return ret; } static GByteArray * elektron_new_msg_upgrade_os_start (guint size) { GByteArray *msg = elektron_new_msg (OS_UPGRADE_START_REQUEST, sizeof (OS_UPGRADE_START_REQUEST)); memcpy (&msg->data[5], &size, sizeof (guint32)); return msg; } static GByteArray * elektron_new_msg_upgrade_os_write (GByteArray *os_data, gint *offset) { GByteArray *msg = elektron_new_msg (OS_UPGRADE_WRITE_RESPONSE, sizeof (OS_UPGRADE_WRITE_RESPONSE)); guint len; guint32 crc; guint32 aux32; if (*offset + OS_TRANSF_BLOCK_BYTES < os_data->len) { len = OS_TRANSF_BLOCK_BYTES; } else { len = os_data->len - *offset; } crc = crc32 (0xffffffff, &os_data->data[*offset], len); debug_print (2, "CRC: %0x", crc); aux32 = g_htonl (crc); memcpy (&msg->data[5], &aux32, sizeof (guint32)); aux32 = g_htonl (len); memcpy (&msg->data[9], &aux32, sizeof (guint32)); aux32 = g_htonl (*offset); memcpy (&msg->data[13], &aux32, sizeof (guint32)); g_byte_array_append (msg, &os_data->data[*offset], len); *offset = *offset + len; return msg; } static gint elektron_upgrade_os (struct backend *backend, struct sysex_transfer *transfer) { GByteArray *tx_msg; GByteArray *rx_msg; gint8 op; gint offset; gint res = 0; gboolean active; tx_msg = elektron_new_msg_upgrade_os_start (transfer->raw->len); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { res = -EIO; goto end; } //Response: x, x, x, x, 0xd0, [0 (ok), 1 (error)]... op = elektron_get_msg_status (rx_msg); if (op) { res = -EIO; error_print ("%s (%s)", backend_strerror (backend, res), elektron_get_msg_string (rx_msg)); free_msg (rx_msg); goto end; } free_msg (rx_msg); offset = 0; while (offset < transfer->raw->len) { tx_msg = elektron_new_msg_upgrade_os_write (transfer->raw, &offset); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { res = -EIO; break; } //Response: x, x, x, x, 0xd1, int32, [0..3]... op = rx_msg->data[9]; if (op == 1) { break; } else if (op > 1) { res = -EIO; error_print ("%s (%s)", backend_strerror (backend, res), elektron_get_msg_string (rx_msg)); free_msg (rx_msg); break; } free_msg (rx_msg); usleep (BE_REST_TIME_US); g_mutex_lock (&transfer->mutex); active = transfer->active; g_mutex_unlock (&transfer->mutex); if (!active) { res = -ECANCELED; goto end; } } end: return res; } static gint elektron_get_storage_stats (struct backend *backend, guint8 type, struct backend_storage_stats *statfs, const gchar *path) { GByteArray *tx_msg, *rx_msg; gint8 op; guint64 *v; gint res = 0; guint8 fsid; struct elektron_data *data = backend->data; if (!(type & data->device_desc.storage)) { return -EINVAL; } fsid = log2l (type); tx_msg = elektron_new_msg_uint8 (STORAGEINFO_REQUEST, sizeof (STORAGEINFO_REQUEST), fsid + 1); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { return -EIO; } op = elektron_get_msg_status (rx_msg); if (!op) { error_print ("%s (%s)", backend_strerror (backend, -EIO), elektron_get_msg_string (rx_msg)); free_msg (rx_msg); return -EIO; } snprintf (statfs->name, LABEL_MAX, "%s", FS_TYPE_NAMES[fsid]); v = (guint64 *) & rx_msg->data[6]; statfs->bfree = GUINT64_FROM_BE (*v); v = (guint64 *) & rx_msg->data[14]; statfs->bsize = GUINT64_FROM_BE (*v); free_msg (rx_msg); return res ? res : type << 1 < data->device_desc.storage; } static gint elektron_next_data_entry (struct item_iterator *iter) { gchar *name_cp1252; guint32 *data32; guint16 *data16; guint8 type; guint8 has_children; guint32 id; struct elektron_iterator_data *data = iter->data; if (data->pos == data->msg->len) { //A data directory only contains either files or directories. //If the last visited item was a directory, there are no more slots to visit. if (iter->item.type == ITEM_TYPE_DIR || iter->item.id >= data->max_slots) { return -ENOENT; } goto not_found; } name_cp1252 = (gchar *) & data->msg->data[data->pos]; if (data->max_slots != -1 && iter->item.type != ITEM_TYPE_DIR) { guint32 pos = data->pos + strlen (name_cp1252) + 3; data32 = (guint32 *) & data->msg->data[pos]; id = g_ntohl (*data32); if (id > iter->item.id + 1) { goto not_found; } } elektron_get_utf8 (iter->item.name, name_cp1252); data->pos += strlen (name_cp1252) + 1; has_children = data->msg->data[data->pos]; data->pos++; type = data->msg->data[data->pos]; data->pos++; switch (type) { case 1: iter->item.type = ITEM_TYPE_DIR; data->pos += sizeof (guint32); // child entries iter->item.size = 0; iter->item.id = -1; data->operations = 0; data->has_valid_data = 0; data->has_metadata = 0; iter->item.object_info[0] = 0; break; case 2: iter->item.type = has_children ? ITEM_TYPE_DIR : ITEM_TYPE_FILE; data32 = (guint32 *) & data->msg->data[data->pos]; iter->item.id = has_children ? -1 : g_ntohl (*data32); data->pos += sizeof (gint32); data32 = (guint32 *) & data->msg->data[data->pos]; iter->item.size = g_ntohl (*data32); data->pos += sizeof (guint32); data16 = (guint16 *) & data->msg->data[data->pos]; data->operations = g_ntohs (*data16); data->pos += sizeof (guint16); data->has_valid_data = data->msg->data[data->pos]; data->pos++; data->has_metadata = data->msg->data[data->pos]; data->pos++; iter->item.object_info[0] = 0; if (data->load_metadata && data->has_metadata && data->mode == ITER_MODE_DATA_SND && preferences_get_boolean (PREF_KEY_ELEKTRON_LOAD_SOUND_TAGS)) { gchar metadata_path[PATH_MAX]; struct idata output; struct job_control control; control.active = TRUE; control.callback = NULL; g_mutex_init (&control.mutex); snprintf (metadata_path, PATH_MAX, "%s/%d/%s", iter->dir, iter->item.id, FS_DATA_METADATA_FILE); debug_print (2, "Reading metadata from %s...", metadata_path); if (!elektron_download_data_snd (data->backend, metadata_path, &output, &control)) { gchar *s; gboolean first = TRUE; GString *info = g_string_new (NULL); GSList *tags = package_get_tags_from_snd_metadata (output.content); GSList *e = tags; while (e) { gchar *tag = (gchar *) e->data; const gchar *separator = first ? "" : ", "; g_string_append_printf (info, "%s%s", separator, tag); first = FALSE; e = e->next; } s = g_string_free (info, FALSE); snprintf (iter->item.object_info, LABEL_MAX, "%s", s); g_free (s); g_slist_free_full (tags, g_free); idata_free (&output); } } break; default: error_print ("Unrecognized data entry: %d", iter->item.type); break; } return 0; not_found: iter->item.type = ITEM_TYPE_FILE; iter->item.name[0] = 0; iter->item.size = 0; iter->item.id++; data->operations = 0; data->has_valid_data = 0; data->has_metadata = 0; iter->item.object_info[0] = 0; return 0; } static gchar * elektron_add_prefix_to_path (const gchar *dir, const gchar *prefix) { gchar *full; if (prefix) { GString *str = g_string_new (NULL); g_string_append_printf (str, "%s%s", prefix, dir); full = g_string_free (str, FALSE); } else { full = strdup (dir); } return full; } static gint elektron_read_data_dir_prefix (struct backend *backend, struct item_iterator *iter, const gchar *dir, const char *prefix, enum elektron_iterator_mode mode, gint32 max_slots) { int res; GByteArray *tx_msg; GByteArray *rx_msg; gchar *dir_w_prefix = elektron_add_prefix_to_path (dir, prefix); tx_msg = elektron_new_msg_list (dir_w_prefix, 0, 0, 1); g_free (dir_w_prefix); if (!tx_msg) { return -EINVAL; } rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { return -EIO; } res = elektron_get_msg_status (rx_msg); if (!res) { free_msg (rx_msg); return -ENOTDIR; } return elektron_init_iterator (backend, iter, dir, rx_msg, elektron_next_data_entry, mode, max_slots); } static gint elektron_read_data_dir_any (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { return elektron_read_data_dir_prefix (backend, iter, dir, NULL, ITER_MODE_DATA, -1); } static gint elektron_read_data_dir_prj (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { return elektron_read_data_dir_prefix (backend, iter, dir, FS_DATA_PRJ_PREFIX, ITER_MODE_DATA, 128); } static gint elektron_read_data_dir_snd (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { return elektron_read_data_dir_prefix (backend, iter, dir, FS_DATA_SND_PREFIX, ITER_MODE_DATA_SND, 256); } static gint elektron_read_data_dir_pst (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { struct elektron_data *data = backend->data; gint32 slots = data->device_desc.id == ELEKTRON_AH_FX_ID ? 512 : 128; //Analog Heat +FX has 512 presets return elektron_read_data_dir_prefix (backend, iter, dir, FS_DATA_PST_PREFIX, ITER_MODE_DATA, slots); } static gint elektron_dst_src_data_prefix_common (struct backend *backend, const gchar *src, const gchar *dst, const char *prefix, const guint8 *op_data, guint len) { gint res; char *src_w_prefix = elektron_add_prefix_to_path (src, prefix); char *dst_w_prefix = elektron_add_prefix_to_path (dst, prefix); res = elektron_src_dst_common (backend, src_w_prefix, dst_w_prefix, op_data, len); g_free (src_w_prefix); g_free (dst_w_prefix); return res; } static gint elektron_move_data_item_prefix (struct backend *backend, const gchar *src, const gchar *dst, const char *prefix) { return elektron_dst_src_data_prefix_common (backend, src, dst, prefix, DATA_MOVE_REQUEST, sizeof (DATA_MOVE_REQUEST)); } static gint elektron_move_data_item_any (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_move_data_item_prefix (backend, src, dst, NULL); } static gint elektron_move_data_item_prj (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_move_data_item_prefix (backend, src, dst, FS_DATA_PRJ_PREFIX); } static gint elektron_move_data_item_snd (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_move_data_item_prefix (backend, src, dst, FS_DATA_SND_PREFIX); } static gint elektron_move_data_item_pst (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_move_data_item_prefix (backend, src, dst, FS_DATA_PST_PREFIX); } static gint elektron_copy_data_item_prefix (struct backend *backend, const gchar *src, const gchar *dst, const gchar *prefix) { return elektron_dst_src_data_prefix_common (backend, src, dst, prefix, DATA_COPY_REQUEST, sizeof (DATA_COPY_REQUEST)); } static gint elektron_copy_data_item_any (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_copy_data_item_prefix (backend, src, dst, NULL); } static gint elektron_copy_data_item_prj (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_copy_data_item_prefix (backend, src, dst, FS_DATA_PRJ_PREFIX); } static gint elektron_copy_data_item_snd (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_copy_data_item_prefix (backend, src, dst, FS_DATA_SND_PREFIX); } static gint elektron_copy_data_item_pst (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_copy_data_item_prefix (backend, src, dst, FS_DATA_PST_PREFIX); } static gint elektron_path_data_prefix_common (struct backend *backend, const gchar *path, const char *prefix, const guint8 *op_data, guint len) { gint res; char *path_w_prefix = elektron_add_prefix_to_path (path, prefix); res = elektron_path_common (backend, path_w_prefix, op_data, len); g_free (path_w_prefix); return res; } static gint elektron_clear_data_item_prefix (struct backend *backend, const gchar *path, const gchar *prefix) { return elektron_path_data_prefix_common (backend, path, prefix, DATA_CLEAR_REQUEST, sizeof (DATA_CLEAR_REQUEST)); } static gint elektron_clear_data_item_any (struct backend *backend, const gchar *path) { return elektron_clear_data_item_prefix (backend, path, NULL); } static gint elektron_clear_data_item_prj (struct backend *backend, const gchar *path) { return elektron_clear_data_item_prefix (backend, path, FS_DATA_PRJ_PREFIX); } static gint elektron_clear_data_item_snd (struct backend *backend, const gchar *path) { return elektron_clear_data_item_prefix (backend, path, FS_DATA_SND_PREFIX); } static gint elektron_clear_data_item_pst (struct backend *backend, const gchar *path) { return elektron_clear_data_item_prefix (backend, path, FS_DATA_PST_PREFIX); } static gint elektron_swap_data_item_prefix (struct backend *backend, const gchar *src, const gchar *dst, const gchar *prefix) { return elektron_dst_src_data_prefix_common (backend, src, dst, prefix, DATA_SWAP_REQUEST, sizeof (DATA_SWAP_REQUEST)); } static gint elektron_swap_data_item_any (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_swap_data_item_prefix (backend, src, dst, NULL); } static gint elektron_swap_data_item_prj (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_swap_data_item_prefix (backend, src, dst, FS_DATA_PRJ_PREFIX); } static gint elektron_swap_data_item_snd (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_swap_data_item_prefix (backend, src, dst, FS_DATA_SND_PREFIX); } static gint elektron_swap_data_item_pst (struct backend *backend, const gchar *src, const gchar *dst) { return elektron_swap_data_item_prefix (backend, src, dst, FS_DATA_PST_PREFIX); } static gint elektron_open_datum (struct backend *backend, const gchar *path, guint32 *jid, gint mode, guint32 size) { guint32 *data32; guint32 sizebe; guint32 chunk_size; guint8 compression; GByteArray *rx_msg; GByteArray *tx_msg; const guint8 *data; guint len; gchar *path_cp1252; gint res = 0; if (mode == O_RDONLY) { data = DATA_READ_OPEN_REQUEST; len = sizeof (DATA_READ_OPEN_REQUEST); } else if (mode == O_WRONLY) { data = DATA_WRITE_OPEN_REQUEST; len = sizeof (DATA_WRITE_OPEN_REQUEST); } else { return -EINVAL; } tx_msg = elektron_new_msg (data, len); path_cp1252 = elektron_get_cp1252 (path); if (mode == O_RDONLY) { g_byte_array_append (tx_msg, (guint8 *) path_cp1252, strlen (path_cp1252) + 1); chunk_size = g_htonl (DATA_TRANSF_BLOCK_BYTES); g_byte_array_append (tx_msg, (guint8 *) & chunk_size, sizeof (guint32)); compression = 1; g_byte_array_append (tx_msg, &compression, sizeof (guint8)); } if (mode == O_WRONLY) { sizebe = g_htonl (size); g_byte_array_append (tx_msg, (guint8 *) & sizebe, sizeof (guint32)); g_byte_array_append (tx_msg, (guint8 *) path_cp1252, strlen (path_cp1252) + 1); } rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { res = -EIO; goto cleanup; } if (!elektron_get_msg_status (rx_msg)) { res = -EPERM; error_print ("%s (%s)", backend_strerror (backend, res), elektron_get_msg_string (rx_msg)); free_msg (rx_msg); goto cleanup; } data32 = (guint32 *) & rx_msg->data[6]; *jid = g_ntohl (*data32); if (mode == O_RDONLY) { data32 = (guint32 *) & rx_msg->data[10]; chunk_size = g_ntohl (*data32); compression = rx_msg->data[14]; debug_print (1, "Open datum info: job id: %d; chunk size: %d; compression: %d", *jid, chunk_size, compression); } if (mode == O_WRONLY) { debug_print (1, "Open datum info: job id: %d", *jid); } free_msg (rx_msg); cleanup: g_free (path_cp1252); return res; } static gint elektron_close_datum (struct backend *backend, guint32 jid, gint mode, guint32 wsize) { guint32 jidbe; guint32 wsizebe; guint32 r_jid; guint32 asize; guint32 *data32; GByteArray *rx_msg; GByteArray *tx_msg; const guint8 *data; guint len; if (mode == O_RDONLY) { data = DATA_READ_CLOSE_REQUEST; len = sizeof (DATA_READ_CLOSE_REQUEST); } else if (mode == O_WRONLY) { data = DATA_WRITE_CLOSE_REQUEST; len = sizeof (DATA_WRITE_CLOSE_REQUEST); } else { return -EINVAL; } tx_msg = elektron_new_msg (data, len); jidbe = g_htonl (jid); g_byte_array_append (tx_msg, (guchar *) & jidbe, sizeof (guint32)); if (mode == O_WRONLY) { wsizebe = g_htonl (wsize); g_byte_array_append (tx_msg, (guchar *) & wsizebe, sizeof (guint32)); } rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { return -EIO; } if (!elektron_get_msg_status (rx_msg)) { error_print ("%s (%s)", backend_strerror (backend, -EPERM), elektron_get_msg_string (rx_msg)); free_msg (rx_msg); return -EPERM; } data32 = (guint32 *) & rx_msg->data[6]; r_jid = g_ntohl (*data32); data32 = (guint32 *) & rx_msg->data[10]; asize = g_ntohl (*data32); debug_print (1, "Close datum info: job id: %d; size: %d", r_jid, asize); free_msg (rx_msg); if (mode == O_WRONLY && asize != wsize) { error_print ("Actual download bytes (%d) differs from expected ones (%d)", asize, wsize); return -EINVAL; } return 0; } static gint elektron_download_data_prefix (struct backend *backend, const gchar *path, struct idata *data, struct job_control *control, const gchar *prefix) { gint err; guint32 seq; guint32 seqbe; guint32 jid; guint32 r_jid; guint32 r_seq; guint32 status; guint8 last; guint32 hash; guint32 *data32; guint32 jidbe; guint32 data_size; gboolean active; GByteArray *rx_msg, *tx_msg, *content; gchar *path_w_prefix, *basename; basename = g_path_get_basename (path); err = strcmp (basename, FS_DATA_METADATA_FILE); g_free (basename); if (err) { guint id; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } } path_w_prefix = elektron_add_prefix_to_path (path, prefix); err = elektron_open_datum (backend, path_w_prefix, &jid, O_RDONLY, 0); g_free (path_w_prefix); if (err) { return -EIO; } usleep (BE_REST_TIME_US); content = g_byte_array_sized_new (4 * MI); g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); jidbe = g_htonl (jid); err = 0; seq = 0; last = 0; while (!last && active) { tx_msg = elektron_new_msg (DATA_READ_PARTIAL_REQUEST, sizeof (DATA_READ_PARTIAL_REQUEST)); g_byte_array_append (tx_msg, (guint8 *) & jidbe, sizeof (guint32)); seqbe = g_htonl (seq); g_byte_array_append (tx_msg, (guint8 *) & seqbe, sizeof (guint32)); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { err = -EIO; break; } if (!elektron_get_msg_status (rx_msg)) { err = -EPERM; error_print ("%s (%s)", backend_strerror (backend, err), elektron_get_msg_string (rx_msg)); free_msg (rx_msg); break; } data32 = (guint32 *) & rx_msg->data[6]; r_jid = g_ntohl (*data32); data32 = (guint32 *) & rx_msg->data[10]; r_seq = g_ntohl (*data32); data32 = (guint32 *) & rx_msg->data[14]; status = g_ntohl (*data32); last = rx_msg->data[18]; data32 = (guint32 *) & rx_msg->data[19]; hash = g_ntohl (*data32); data32 = (guint32 *) & rx_msg->data[23]; data_size = g_ntohl (*data32); if (data_size) { debug_print (1, "Read datum info: job id: %d; last: %d; seq: %d; status: %d; hash: 0x%08x", r_jid, last, r_seq, status, hash); g_byte_array_append (content, (guint8 *) & rx_msg->data[27], data_size); } else { // Sometimes, the first message returns 0 data size and the rest of the parameters are not initialized. debug_print (1, "Read datum info: job id: %d; last: %d, hash: 0x%08x", r_jid, last, hash); status = 0; } free_msg (rx_msg); seq++; job_control_set_progress (control, status / 1000.0); g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); usleep (BE_REST_TIME_US); } if (active) { job_control_set_progress (control, 1.0); idata_init (data, content, NULL, NULL); } else { g_byte_array_free (content, TRUE); } return elektron_close_datum (backend, jid, O_RDONLY, 0); } static gint elektron_download_data_any (struct backend *backend, const gchar *path, struct idata *any, struct job_control *control) { control->parts = 1; control->part = 0; return elektron_download_data_prefix (backend, path, any, control, NULL); } static gint elektron_download_data_prj (struct backend *backend, const gchar *path, struct idata *prj, struct job_control *control) { return elektron_download_data_prefix (backend, path, prj, control, FS_DATA_PRJ_PREFIX); } static gint elektron_download_data_snd (struct backend *backend, const gchar *path, struct idata *snd, struct job_control *control) { return elektron_download_data_prefix (backend, path, snd, control, FS_DATA_SND_PREFIX); } static gint elektron_download_data_pst (struct backend *backend, const gchar *path, struct idata *pst, struct job_control *control) { return elektron_download_data_prefix (backend, path, pst, control, FS_DATA_PST_PREFIX); } static gchar * elektron_get_download_name (struct backend *backend, const struct fs_operations *ops, const gchar *src_path) { gint32 id; gint ret; gchar *dir, *name; struct item_iterator iter; struct elektron_iterator_data *data; if (ops->id == FS_RAW_ALL || ops->id == FS_RAW_PRESETS) { return g_path_get_basename (src_path); } dir = g_path_get_dirname (src_path); ret = ops->readdir (backend, &iter, dir, NULL); g_free (dir); if (ret) { return NULL; } name = g_path_get_basename (src_path); id = atoi (name); g_free (name); name = NULL; data = iter.data; data->load_metadata = FALSE; while (!item_iterator_next (&iter)) { if (iter.item.id == id) { name = g_strdup (iter.item.name); break; } } item_iterator_free (&iter); return name; } static gint elektron_download_pkg (struct backend *backend, const gchar *path, struct idata *output, struct job_control *control, enum package_type type, const struct fs_operations *ops, fs_remote_file_op download) { gint ret; gchar *pkg_name; struct package pkg; struct elektron_data *data = backend->data; pkg_name = elektron_get_download_name (backend, ops, path); if (!pkg_name) { return -1; } if (package_begin (&pkg, pkg_name, backend->version, &data->device_desc, type)) { g_free (pkg_name); return -1; } ret = package_receive_pkg_resources (&pkg, path, control, backend, download, type); ret = ret || package_end (&pkg, output); package_destroy (&pkg); return ret; } static gchar * elektron_get_upload_path_smplrw (struct backend *backend, const struct fs_operations *ops, const gchar *dst_dir, const gchar *src_path, struct idata *smplrw) { gchar *path, *name, *aux; name = g_path_get_basename (src_path); filename_remove_ext (name); aux = path_chain (PATH_INTERNAL, dst_dir, name); g_free (name); if (ops->id == FS_RAW_ALL || ops->id == FS_RAW_PRESETS) { path = elektron_add_ext_to_mc_snd (aux); g_free (aux); } else { path = aux; } return path; } // As Elektron devices provide their own file extension and the file content is // not just SysEx, it is not needed to indicate in the filename the type of // device, filesystem or id. static gchar * elektron_get_download_path (struct backend *backend, const struct fs_operations *ops, const gchar *dst_dir, const gchar *src_path, struct idata *any) { gchar *path, *name, *src_fpath; const gchar *md_ext, *ext = filename_get_ext (src_path); // Examples: // 0:/project0 // 0:/soundbanks/A/1 // 0:/soundbanks/A/1/.metadata if (strcmp (ext, FS_DATA_METADATA_EXT)) { src_fpath = strdup (src_path); md_ext = ""; } else { src_fpath = g_path_get_dirname (src_path); md_ext = FS_DATA_METADATA_FILE; } name = elektron_get_download_name (backend, ops, src_fpath); g_free (src_fpath); if (name) { GString *filename = g_string_new (NULL); const gchar *dl_ext = ops->get_exts (backend, ops)[0]; g_string_append_printf (filename, "%s.%s%s", name, dl_ext, md_ext); path = path_chain (PATH_SYSTEM, dst_dir, filename->str); g_free (name); g_string_free (filename, TRUE); } else { path = NULL; } return path; } static gint elektron_upload_data_prefix (struct backend *backend, const gchar *path, struct idata *data, struct job_control *control, const gchar *prefix) { gint err; guint id; guint32 seq; guint32 jid; guint32 crc; guint32 len; guint32 r_jid; guint32 r_seq; guint32 offset; guint32 *data32; guint32 jidbe; guint32 aux32; gboolean active; guint32 total; GByteArray *rx_msg; GByteArray *tx_msg; gchar *path_w_prefix; GByteArray *array = data->content; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } path_w_prefix = elektron_add_prefix_to_path (path, prefix); err = elektron_open_datum (backend, path_w_prefix, &jid, O_WRONLY, array->len); g_free (path_w_prefix); if (err) { goto end; } usleep (BE_REST_TIME_US); jidbe = g_htonl (jid); seq = 0; offset = 0; g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); while (offset < array->len && active) { tx_msg = elektron_new_msg (DATA_WRITE_PARTIAL_REQUEST, sizeof (DATA_WRITE_PARTIAL_REQUEST)); g_byte_array_append (tx_msg, (guint8 *) & jidbe, sizeof (guint32)); aux32 = g_htonl (seq); g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32)); if (offset + DATA_TRANSF_BLOCK_BYTES < array->len) { len = DATA_TRANSF_BLOCK_BYTES; } else { len = array->len - offset; } crc = crc32 (0xffffffff, &array->data[offset], len); aux32 = g_htonl (crc); g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32)); aux32 = g_htonl (len); g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32)); g_byte_array_append (tx_msg, &array->data[offset], len); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { err = -EIO; goto end; } usleep (BE_REST_TIME_US); if (!elektron_get_msg_status (rx_msg)) { err = -EPERM; error_print ("%s (%s)", backend_strerror (backend, err), elektron_get_msg_string (rx_msg)); free_msg (rx_msg); break; } data32 = (guint32 *) & rx_msg->data[6]; r_jid = g_ntohl (*data32); data32 = (guint32 *) & rx_msg->data[10]; r_seq = g_ntohl (*data32); data32 = (guint32 *) & rx_msg->data[14]; total = g_ntohl (*data32); free_msg (rx_msg); debug_print (1, "Write datum info: job id: %d; seq: %d; total: %d", r_jid, r_seq, total); seq++; offset += len; if (total != offset) { error_print ("Actual upload bytes (%d) differs from expected ones (%d)", total, offset); } job_control_set_progress (control, offset / (gdouble) array->len); g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); } debug_print (2, "%d bytes sent", offset); err = elektron_close_datum (backend, jid, O_WRONLY, array->len); end: return err; } static gint elektron_upload_data_any (struct backend *backend, const gchar *path, struct idata *any, struct job_control *control) { control->parts = 1; control->part = 0; return elektron_upload_data_prefix (backend, path, any, control, NULL); } static gint elektron_upload_data_prj (struct backend *backend, const gchar *path, struct idata *prj, struct job_control *control) { return elektron_upload_data_prefix (backend, path, prj, control, FS_DATA_PRJ_PREFIX); } static gint elektron_upload_data_snd (struct backend *backend, const gchar *path, struct idata *snd, struct job_control *control) { return elektron_upload_data_prefix (backend, path, snd, control, FS_DATA_SND_PREFIX); } static gint elektron_upload_data_pst (struct backend *backend, const gchar *path, struct idata *pst, struct job_control *control) { return elektron_upload_data_prefix (backend, path, pst, control, FS_DATA_PST_PREFIX); } static gint elektron_upload_pkg (struct backend *backend, const gchar *path, struct idata *input, struct job_control *control, guint8 type, const struct fs_operations *ops, fs_remote_file_op upload) { gint ret; struct package pkg; struct elektron_data *data = backend->data; ret = package_open (&pkg, input, &data->device_desc); if (!ret) { ret = package_send_pkg_resources (&pkg, path, control, backend, upload); package_close (&pkg); } return ret; } const gchar ** elektron_get_dev_exts (struct backend *backend, const struct fs_operations *ops) { struct elektron_data *data = backend->data; struct fs_desc *fs_desc = data->device_desc.fs_descs; for (guint i = 0; i < data->device_desc.fs_descs_len; i++) { if (!strcmp (fs_desc->name, ops->name)) { return (const gchar **) fs_desc->extensions; } fs_desc++; } return NULL; } const gchar ** elektron_get_data_any_exts (struct backend *backend, const struct fs_operations *ops) { return FS_DATA_ANY_EXTS; } const gchar ** elektron_get_raw_any_exts (struct backend *backend, const struct fs_operations *ops) { return FS_RAW_ANY_EXTS; } gint elektron_sample_load (const gchar *path, struct idata *sample, struct job_control *control) { return common_sample_load (path, sample, control, ELEKTRON_SAMPLE_RATE, 1, SF_FORMAT_PCM_16); } gint elektron_sample_stereo_load (const gchar *path, struct idata *sample, struct job_control *control) { struct sample_info *sample_info; gint err = common_sample_load (path, sample, control, ELEKTRON_SAMPLE_RATE, 0, SF_FORMAT_PCM_16); if (err) { return err; } sample_info = sample->info; if (sample_info->channels > 2) { idata_free (sample); err = -EINVAL; } return err; } gchar * elektron_get_sample_path_from_hash_size (struct backend *backend, guint32 hash, guint32 size) { guint32 aux32; gchar *path; GByteArray *rx_msg, *tx_msg = elektron_new_msg (FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST, sizeof (FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST)); aux32 = g_htonl (hash); memcpy (&tx_msg->data[5], &aux32, sizeof (guint32)); aux32 = g_htonl (size); memcpy (&tx_msg->data[9], &aux32, sizeof (guint32)); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { return NULL; } if (elektron_get_msg_status (rx_msg)) { path = strdup ((gchar *) & rx_msg->data[14]); } else { path = NULL; } g_byte_array_free (rx_msg, TRUE); return path; } static gint elektron_sample_save (const gchar *path, struct idata *sample, struct job_control *control) { return sample_save_to_file (path, sample, control, SF_FORMAT_WAV | SF_FORMAT_PCM_16); } static const struct fs_operations FS_SAMPLES_OPERATIONS = { .id = FS_SAMPLES, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "sample", .gui_name = "Samples", .gui_icon = FS_ICON_WAVE, .max_name_len = ELEKTRON_NAME_MAX_LEN, .readdir = elektron_read_samples_dir, .file_exists = elektron_sample_file_exists, .print_item = elektron_print_smplrw, .mkdir = elektron_create_samples_dir, .delete = elektron_delete_samples_item, .rename = elektron_move_samples_item, .move = elektron_move_samples_item, .download = elektron_download_sample, .upload = elektron_upload_sample, .load = elektron_sample_load, .save = elektron_sample_save, .get_exts = sample_get_sample_extensions, .get_upload_path = elektron_get_upload_path_smplrw, .get_download_path = common_system_get_download_path }; static const struct fs_operations FS_RAW_ANY_OPERATIONS = { .id = FS_RAW_ALL, .options = 0, .name = "raw", .max_name_len = ELEKTRON_NAME_MAX_LEN, .readdir = elektron_read_raw_dir, .file_exists = elektron_raw_file_exists, .print_item = elektron_print_smplrw, .mkdir = elektron_create_raw_dir, .delete = elektron_delete_raw_item, .rename = elektron_move_raw_item, .move = elektron_move_raw_item, .download = elektron_download_raw, .upload = elektron_upload_raw, .load = file_load, .save = file_save, .get_exts = elektron_get_raw_any_exts, .get_upload_path = elektron_get_upload_path_smplrw, .get_download_path = elektron_get_download_path }; static const struct fs_operations FS_RAW_PRESETS_OPERATIONS = { .id = FS_RAW_PRESETS, .options = FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "preset-raw", .cli_name = "preset", .gui_name = "Presets", .gui_icon = FS_ICON_SND, .max_name_len = ELEKTRON_NAME_MAX_LEN, .readdir = elektron_read_raw_dir, .file_exists = elektron_raw_file_exists, .print_item = elektron_print_smplrw, .mkdir = elektron_create_raw_dir, .delete = elektron_delete_raw_item, .rename = elektron_move_raw_item, .move = elektron_move_raw_item, .download = elektron_download_raw_pst_pkg, .upload = elektron_upload_raw_pst_pkg, .load = file_load, .save = file_save, .get_exts = elektron_get_dev_exts, .get_upload_path = elektron_get_upload_path_smplrw, .get_download_path = elektron_get_download_path }; static const struct fs_operations FS_DATA_ANY_OPERATIONS = { .id = FS_DATA_ANY, .options = FS_OPTION_SLOT_STORAGE, .name = "data", .readdir = elektron_read_data_dir_any, .print_item = elektron_print_data, .delete = elektron_clear_data_item_any, .move = elektron_move_data_item_any, .copy = elektron_copy_data_item_any, .clear = elektron_clear_data_item_any, .swap = elektron_swap_data_item_any, .download = elektron_download_data_any, .upload = elektron_upload_data_any, .get_slot = elektron_get_id_as_slot, .load = file_load, .save = file_save, .get_exts = elektron_get_data_any_exts, .get_upload_path = common_slot_get_upload_path, .get_download_path = elektron_get_download_path }; static const struct fs_operations FS_DATA_PRJ_OPERATIONS = { .id = FS_DATA_PRJ, .options = FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SLOT_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "project", .gui_name = "Projects", .gui_icon = FS_ICON_PRJ, .readdir = elektron_read_data_dir_prj, .print_item = elektron_print_data, .delete = elektron_clear_data_item_prj, .move = elektron_move_data_item_prj, .copy = elektron_copy_data_item_prj, .clear = elektron_clear_data_item_prj, .swap = elektron_swap_data_item_prj, .download = elektron_download_data_prj_pkg, .upload = elektron_upload_data_prj_pkg, .get_slot = elektron_get_id_as_slot, .load = file_load, .save = file_save, .get_exts = elektron_get_dev_exts, .get_upload_path = common_slot_get_upload_path, .get_download_path = elektron_get_download_path }; static const struct fs_operations FS_DATA_SND_OPERATIONS = { .id = FS_DATA_SND, .options = FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SLOT_COLUMN | FS_OPTION_SHOW_INFO_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "sound", .gui_name = "Sounds", .gui_icon = FS_ICON_SND, .readdir = elektron_read_data_dir_snd, .print_item = elektron_print_data, .delete = elektron_clear_data_item_snd, .move = elektron_move_data_item_snd, .copy = elektron_copy_data_item_snd, .clear = elektron_clear_data_item_snd, .swap = elektron_swap_data_item_snd, .download = elektron_download_data_snd_pkg, .upload = elektron_upload_data_snd_pkg, .get_slot = elektron_get_id_as_slot, .load = file_load, .save = file_save, .get_exts = elektron_get_dev_exts, .get_upload_path = common_slot_get_upload_path, .get_download_path = elektron_get_download_path }; static const struct fs_operations FS_DATA_PST_OPERATIONS = { .id = FS_DATA_PST, .options = FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SLOT_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "preset", .gui_name = "Presets", .gui_icon = FS_ICON_SND, .readdir = elektron_read_data_dir_pst, .print_item = elektron_print_data, .delete = elektron_clear_data_item_pst, .move = elektron_move_data_item_pst, .copy = elektron_copy_data_item_pst, .clear = elektron_clear_data_item_pst, .swap = elektron_swap_data_item_pst, .download = elektron_download_data_pst_pkg, .upload = elektron_upload_data_pst_pkg, .get_slot = elektron_get_id_as_slot, .load = file_load, .save = file_save, .get_exts = elektron_get_dev_exts, .get_upload_path = common_slot_get_upload_path, .get_download_path = elektron_get_download_path }; static const struct fs_operations FS_SAMPLES_STEREO_OPERATIONS = { .id = FS_SAMPLES_STEREO, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "sample-stereo", .cli_name = "sample", .gui_name = "Samples", .gui_icon = FS_ICON_WAVE, .max_name_len = ELEKTRON_NAME_MAX_LEN, .readdir = elektron_read_samples_dir, .file_exists = elektron_sample_file_exists, .print_item = elektron_print_smplrw, .mkdir = elektron_create_samples_dir, .delete = elektron_delete_samples_item, .rename = elektron_move_samples_item, .move = elektron_move_samples_item, .download = elektron_download_sample, .upload = elektron_upload_sample, .load = elektron_sample_stereo_load, .save = elektron_sample_save, .get_exts = sample_get_sample_extensions, .get_upload_path = elektron_get_upload_path_smplrw, .get_download_path = common_system_get_download_path }; static const struct fs_operations FS_DATA_TAKT_II_PST_OPERATIONS = { .id = FS_DATA_TAKT_II_PST, .options = FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SLOT_COLUMN | FS_OPTION_SHOW_INFO_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "preset-takt-ii", .cli_name = "preset", .gui_name = "Presets", .gui_icon = FS_ICON_SND, .readdir = elektron_read_data_dir_snd, .print_item = elektron_print_data, .delete = elektron_clear_data_item_snd, .move = elektron_move_data_item_snd, .copy = elektron_copy_data_item_snd, .clear = elektron_clear_data_item_snd, .swap = elektron_swap_data_item_snd, .download = elektron_download_data_snd_pkg, .upload = elektron_upload_data_snd_pkg, .get_slot = elektron_get_id_as_slot, .load = file_load, .save = file_save, .get_exts = elektron_get_dev_exts, .get_upload_path = common_slot_get_upload_path, .get_download_path = elektron_get_download_path }; static const struct fs_operations *FS_OPERATIONS[] = { &FS_SAMPLES_OPERATIONS, &FS_RAW_ANY_OPERATIONS, &FS_RAW_PRESETS_OPERATIONS, &FS_DATA_ANY_OPERATIONS, &FS_DATA_PRJ_OPERATIONS, &FS_DATA_SND_OPERATIONS, &FS_DATA_PST_OPERATIONS, &FS_SAMPLES_STEREO_OPERATIONS, &FS_DATA_TAKT_II_PST_OPERATIONS, NULL }; gint elektron_configure_device_from_file (struct backend *backend, guint8 id, const gchar *filename) { gint err, devices, storage; JsonParser *parser; JsonReader *reader; gchar **members; gchar **name; GError *error = NULL; struct elektron_data *data = backend->data; parser = json_parser_new (); if (!json_parser_load_from_file (parser, filename, &error)) { debug_print (1, "%s", error->message); g_clear_error (&error); err = -ENODEV; goto cleanup_parser; } debug_print (1, "Parsing %s...", filename); reader = json_reader_new (json_parser_get_root (parser)); if (!reader) { error_print ("Unable to read from parser"); err = -ENODEV; goto cleanup_parser; } if (!json_reader_is_array (reader)) { error_print ("Not an array"); err = -ENODEV; goto cleanup_reader; } devices = json_reader_count_elements (reader); if (!devices) { debug_print (1, "No devices found"); err = -ENODEV; goto cleanup_reader; } err = -ENODEV; for (guint i = 0; i < devices; i++) { if (!json_reader_read_element (reader, i)) { error_print ("Cannot read element %d. Continuing...", i); continue; } if (!json_reader_read_member (reader, DEV_TAG_ID)) { error_print ("Cannot read member '%s'. Continuing...", DEV_TAG_ID); continue; } data->device_desc.id = json_reader_get_int_value (reader); json_reader_end_member (reader); if (data->device_desc.id != id) { json_reader_end_element (reader); continue; } err = 0; debug_print (1, "Device %d found", id); if (!json_reader_read_member (reader, DEV_TAG_NAME)) { error_print ("Cannot read member '%s'. Stopping...", DEV_TAG_NAME); json_reader_end_element (reader); err = -ENODEV; break; } snprintf (backend->name, LABEL_MAX, "%s", json_reader_get_string_value (reader)); json_reader_end_member (reader); if (!json_reader_read_member (reader, DEV_TAG_FILESYSTEMS)) { error_print ("Cannot read member '%s'. Stopping...", DEV_TAG_FILESYSTEMS); json_reader_end_element (reader); err = -ENODEV; break; } members = json_reader_list_members (reader); name = members; data->device_desc.fs_descs_len = 0; backend->fs_ops = NULL; while (*name) { const struct fs_operations **fs_ops = FS_OPERATIONS; while (*fs_ops) { const gchar *fs_name = (*fs_ops)->name; if (!strcmp (fs_name, *name)) { debug_print (2, "Reading '%s' filesystem...", fs_name); backend->fs_ops = g_slist_append (backend->fs_ops, (gpointer) * fs_ops); break; } fs_ops++; } if (*fs_ops) { if (data->device_desc.fs_descs_len == ELEKTRON_MAX_FS) { error_print ("Too many filesystems"); break; } struct fs_desc *fs_desc = &data->device_desc.fs_descs[data->device_desc.fs_descs_len]; snprintf (fs_desc->name, LABEL_MAX, "%s", *name); data->device_desc.fs_descs_len++; json_reader_read_member (reader, *name); gint j = 0; if (!json_reader_get_null_value (reader)) { gint extensions = json_reader_count_elements (reader); for (; j < extensions && j < ELEKTRON_MAX_EXTENSIONS - 1; j++) { json_reader_read_element (reader, j); const gchar *ext_name = json_reader_get_string_value (reader); debug_print (2, "Adding '%s' extension...", ext_name); fs_desc->extensions[j] = strdup (ext_name); json_reader_end_element (reader); } } fs_desc->extensions[j] = NULL; json_reader_end_member (reader); } else { error_print ("Filesystem '%s' not found", *name); } name++; } g_strfreev (members); json_reader_end_member (reader); if (!json_reader_read_member (reader, DEV_TAG_STORAGE)) { error_print ("Cannot read member '%s'. Stopping...", DEV_TAG_STORAGE); json_reader_end_element (reader); err = -ENODEV; break; } data->device_desc.storage = 0; storage = json_reader_count_elements (reader); if (storage > ELEKTRON_MAX_STORAGE) { error_print ("Too many storage (%d)", storage); storage = ELEKTRON_MAX_STORAGE; } for (guint j = 0; j < storage; j++) { json_reader_read_element (reader, j); const gchar *storage_name = json_reader_get_string_value (reader); const gchar **stname = FS_TYPE_NAMES; guint id = 1; while (*stname) { if (strcmp (*stname, storage_name) == 0) { data->device_desc.storage |= id; break; } stname++; id <<= 1; } json_reader_end_element (reader); } json_reader_end_element (reader); break; } cleanup_reader: g_object_unref (reader); cleanup_parser: g_object_unref (parser); if (err) { data->device_desc.id = -1; } return err; } static gint elektron_configure_device (struct backend *backend, guint8 id) { gchar *filename = get_user_dir (CONF_DIR DEVICES_FILE); gint err = elektron_configure_device_from_file (backend, id, filename); g_free (filename); if (err) { filename = strdup (DATADIR DEVICES_FILE); err = elektron_configure_device_from_file (backend, id, filename); g_free (filename); } return err; } GByteArray * elektron_ping (struct backend *backend) { GByteArray *tx_msg, *rx_msg; struct elektron_data *data = g_malloc (sizeof (struct elektron_data)); data->seq = 0; backend->data = data; tx_msg = elektron_new_msg (PING_REQUEST, sizeof (PING_REQUEST)); rx_msg = elektron_tx_and_rx_timeout (backend, tx_msg, BE_SYSEX_TIMEOUT_GUESS_MS); if (!rx_msg) { backend->data = NULL; g_free (data); } return rx_msg; } void elektron_destroy_data (struct backend *backend) { struct elektron_data *data = backend->data; struct device_desc *device_desc = &data->device_desc; struct fs_desc *fs_desc = device_desc->fs_descs; debug_print (1, "Destroying backend elektron data..."); for (guint i = 0; i < device_desc->fs_descs_len; i++) { gchar **ext = fs_desc->extensions; for (guint j = 0; j < ELEKTRON_MAX_EXTENSIONS; j++) { if (!*ext) { break; } g_free (*ext); ext++; } fs_desc++; } g_free (backend->data); backend->data = NULL; } static gint elektron_handshake (struct backend *backend) { guint8 id; gchar *overbridge_name; GByteArray *tx_msg, *rx_msg; struct elektron_data *data; rx_msg = elektron_ping (backend); if (!rx_msg) { return -ENODEV; } data = backend->data; overbridge_name = strdup ((gchar *) & rx_msg->data[7 + rx_msg->data[6]]); id = rx_msg->data[5]; free_msg (rx_msg); if (elektron_configure_device (backend, id)) { backend->data = NULL; g_free (overbridge_name); g_free (data); return -ENODEV; } usleep (BE_REST_TIME_US); tx_msg = elektron_new_msg (SOFTWARE_VERSION_REQUEST, sizeof (SOFTWARE_VERSION_REQUEST)); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (!rx_msg) { backend->data = NULL; g_free (overbridge_name); g_free (data); return -ENODEV; } snprintf (backend->version, LABEL_MAX, "%s", (gchar *) & rx_msg->data[10]); free_msg (rx_msg); usleep (BE_REST_TIME_US); if (debug_level > 1) { tx_msg = elektron_new_msg (DEVICEUID_REQUEST, sizeof (DEVICEUID_REQUEST)); rx_msg = elektron_tx_and_rx (backend, tx_msg); if (rx_msg) { debug_print (1, "UID: %x", *((guint32 *) & rx_msg->data[5])); free_msg (rx_msg); } usleep (BE_REST_TIME_US); } snprintf (backend->description, LABEL_MAX, "%s", overbridge_name); g_free (overbridge_name); backend->destroy_data = elektron_destroy_data; backend->upgrade_os = elektron_upgrade_os; backend->get_storage_stats = data->device_desc.storage ? elektron_get_storage_stats : NULL; return 0; } static gint elektron_download_data_snd_pkg (struct backend *backend, const gchar *path, struct idata *pkg, struct job_control *control) { return elektron_download_pkg (backend, path, pkg, control, PKG_FILE_TYPE_DATA_SOUND, &FS_DATA_SND_OPERATIONS, elektron_download_data_snd); } static gint elektron_download_data_prj_pkg (struct backend *backend, const gchar *path, struct idata *pkg, struct job_control *control) { return elektron_download_pkg (backend, path, pkg, control, PKG_FILE_TYPE_DATA_PROJECT, &FS_DATA_PRJ_OPERATIONS, elektron_download_data_prj); } static gint elektron_download_data_pst_pkg (struct backend *backend, const gchar *path, struct idata *pkg, struct job_control *control) { return elektron_download_pkg (backend, path, pkg, control, PKG_FILE_TYPE_DATA_PRESET, &FS_DATA_PST_OPERATIONS, elektron_download_data_pst); } static gint elektron_download_raw_pst_pkg (struct backend *backend, const gchar *path, struct idata *pkg, struct job_control *control) { return elektron_download_pkg (backend, path, pkg, control, PKG_FILE_TYPE_RAW_PRESET, &FS_RAW_ANY_OPERATIONS, elektron_download_raw); } static gint elektron_upload_data_snd_pkg (struct backend *backend, const gchar *path, struct idata *pkg, struct job_control *control) { return elektron_upload_pkg (backend, path, pkg, control, PKG_FILE_TYPE_DATA_SOUND, &FS_DATA_SND_OPERATIONS, elektron_upload_data_snd); } static gint elektron_upload_data_prj_pkg (struct backend *backend, const gchar *path, struct idata *pkg, struct job_control *control) { return elektron_upload_pkg (backend, path, pkg, control, PKG_FILE_TYPE_DATA_PROJECT, &FS_DATA_PRJ_OPERATIONS, elektron_upload_data_prj); } static gint elektron_upload_data_pst_pkg (struct backend *backend, const gchar *path, struct idata *pkg, struct job_control *control) { return elektron_upload_pkg (backend, path, pkg, control, PKG_FILE_TYPE_DATA_PRESET, &FS_DATA_PST_OPERATIONS, elektron_upload_data_pst); } static gint elektron_upload_raw_pst_pkg (struct backend *backend, const gchar *path, struct idata *pkg, struct job_control *control) { return elektron_upload_pkg (backend, path, pkg, control, PKG_FILE_TYPE_RAW_PRESET, &FS_RAW_ANY_OPERATIONS, elektron_upload_raw); } const struct connector CONNECTOR_ELEKTRON = { .handshake = elektron_handshake, .name = "elektron", .standard = FALSE, .regex = ".*Elektron.*" }; elektroid-3.2.3/src/connectors/elektron.h000066400000000000000000000035511500236517400204500ustar00rootroot00000000000000/* * elektron.h * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef ELEKTRON_H #define ELEKTRON_H #include "connector.h" #include "preferences.h" #define ELEKTRON_ANALOG_RYTM_ID 8 #define ELEKTRON_DIGITAKT_ID 12 #define ELEKTRON_ANALOG_RYTM_MKII_ID 16 #define ELEKTRON_MODEL_SAMPLES_ID 25 #define ELEKTRON_DIGITAKT_II_ID 42 #define ELEKTRON_AH_FX_ID 32 #define PREF_KEY_ELEKTRON_LOAD_SOUND_TAGS "elektronLoadSoundTags" enum elektron_fs { FS_SAMPLES = 0x1, FS_RAW_ALL = 0x2, FS_RAW_PRESETS = 0x4, FS_DATA_ANY = 0x8, FS_DATA_PRJ = 0x10, FS_DATA_SND = 0x20, FS_DATA_PST = 0x40, FS_SAMPLES_STEREO = 0x80, FS_DATA_TAKT_II_PST = 0x100 }; extern const struct connector CONNECTOR_ELEKTRON; gchar *elektron_get_sample_path_from_hash_size (struct backend *backend, guint32 hash, guint32 size); gint elektron_upload_sample_part (struct backend *backend, const gchar * path, struct idata *sample, struct job_control *control); gint elektron_download_sample_part (struct backend *backend, const gchar * path, struct idata *sample, struct job_control *control); GByteArray *elektron_ping (struct backend *backend); #endif elektroid-3.2.3/src/connectors/microbrute.c000066400000000000000000000366151500236517400210020ustar00rootroot00000000000000/* * microbrute.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "microbrute.h" #include "common.h" #define MICROBRUTE_MAX_SEQ_STR_LEN 256 #define MICROBRUTE_MAX_SEQS 8 #define MICROBRUTE_SEQ_REQ_COUNTER_POS 6 #define MICROBRUTE_SEQ_REQ_ID_POS 9 #define MICROBRUTE_SEQ_REQ_OFFSET_POS 10 #define MICROBRUTE_SEQ_RPLY_LEN_POS 11 #define MICROBRUTE_SEQ_RPLY_DATA_POS 12 #define MICROBRUTE_SEQ_TXT_POS 2 #define MICROBRUTE_SYSEX_RX_CHANNEL 0x5 #define MICROBRUTE_SYSEX_TX_CHANNEL 0x7 #define MICROBRUTE_SYSEX_NOTE_PRIORITY 0xB #define MICROBRUTE_SYSEX_ENVELOPE_LEGATO 0xD #define MICROBRUTE_SYSEX_LFO_KEY_RETRIGGER 0xF #define MICROBRUTE_SYSEX_VEL_RESPONSE 0x11 #define MICROBRUTE_SYSEX_STEP_ON 0x2A #define MICROBRUTE_SYSEX_BEND_RANGE 0x2C #define MICROBRUTE_SYSEX_PLAY_ON 0x2E #define MICROBRUTE_SYSEX_NEXT_SEQUENCE 0x32 #define MICROBRUTE_SYSEX_RETRIGGERING 0x34 #define MICROBRUTE_SYSEX_GATE_LENGTH 0x36 #define MICROBRUTE_SYSEX_STEP_LENGTH 0x38 #define MICROBRUTE_SYSEX_SYNC 0x3C #define MICROBRUTE_SYSEX_CALIB_PB_CENTER 0x21 #define MICROBRUTE_SYSEX_CALIB_BOTH_BOTTOM 0x22 #define MICROBRUTE_SYSEX_CALIB_BOTH_TOP 0x23 #define MICROBRUTE_SYSEX_CALIB_END 0x24 #define MICROBRUTE_CTL_RX_CHANNEL 102 #define MICROBRUTE_CTL_TX_CHANNEL 103 #define MICROBRUTE_CTL_NOTE_PRIORITY 111 #define MICROBRUTE_CTL_ENVELOPE_LEGATO 109 #define MICROBRUTE_CTL_LFO_KEY_RETRIGGER 110 #define MICROBRUTE_CTL_VEL_RESPONSE 112 #define MICROBRUTE_CTL_STEP_ON 114 //Setting the bend range is performed with a RPN #define MICROBRUTE_CTL_PLAY_ON 105 #define MICROBRUTE_CTL_NEXT_SEQUENCE 106 #define MICROBRUTE_CTL_RETRIGGERING 104 #define MICROBRUTE_CTL_GATE_LENGTH 113 #define MICROBRUTE_CTL_STEP_LENGTH 107 #define MICROBRUTE_CTL_SYNC 108 #define MICROBRUTE_NOP 0xff static const gchar *MICROBRUTE_EXTS[] = { "mbseq", NULL }; static const guint8 ARTURIA_ID[] = { 0x0, 0x20, 0x6b }; static const guint8 FAMILY_ID[] = { 0x4, 0x0 }; static const guint8 MODEL_ID[] = { 0x2, 0x1 }; static const guint8 MICROBRUTE_SEQ_REQ[] = { 0xf0, 0x0, 0x20, 0x6b, 0x5, 0x1, 0x0, 0x03, 0x3B, 0x0, 0x0, 0x20, 0xf7 }; static const guint8 MICROBRUTE_SEQ_MSG[] = { 0xf0, 0x0, 0x20, 0x6b, 0x05, 0x01, 0x0, 0x23, 0x3a, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf7 }; static const guint8 MICROBRUTE_GET_PARAM_MSG[] = { 0xf0, 0x0, 0x20, 0x6b, 0x5, 0x1, 0, 0, 0, 0xf7 }; static const guint8 MICROBRUTE_SET_PARAM_MSG[] = { 0xf0, 0x0, 0x20, 0x6b, 0x5, 0x1, 0, 0, 0, 0, 0xf7 }; enum microbrute_fs { FS_MICROBRUTE_SEQUENCE }; struct microbrute_int_param { guint8 sysex; guint8 ctl; guint8 (*value_map) (guint8); }; static guint8 microbrute_map_plus_one (guint8 value) { return value + 1; } static guint8 microbrute_map_proportional_3 (guint8 value) { return value * 42; } static guint8 microbrute_map_proportional_2 (guint8 value) { return value * 64; } static guint8 microbrute_map_step_length (guint8 value) { switch (value) { case 4: return 0; case 8: return 30; case 16: return 60; case 32: return 90; default: return 0; } } static guint8 microbrute_map_special (guint8 value) { switch (value) { case 0: return 0; case 1: return 43; case 2: return 87; default: return 0; } } static const struct microbrute_int_param MICROBRUTE_PARAMS[] = { {MICROBRUTE_SYSEX_NOTE_PRIORITY, MICROBRUTE_CTL_NOTE_PRIORITY, microbrute_map_special}, {MICROBRUTE_SYSEX_VEL_RESPONSE, MICROBRUTE_CTL_VEL_RESPONSE, microbrute_map_special}, {MICROBRUTE_SYSEX_LFO_KEY_RETRIGGER, MICROBRUTE_CTL_LFO_KEY_RETRIGGER, microbrute_map_proportional_2}, {MICROBRUTE_SYSEX_ENVELOPE_LEGATO, MICROBRUTE_CTL_ENVELOPE_LEGATO, microbrute_map_proportional_2}, {MICROBRUTE_SYSEX_BEND_RANGE, MICROBRUTE_NOP, NULL}, //This uses a NRPN instead of a controller {MICROBRUTE_SYSEX_GATE_LENGTH, MICROBRUTE_CTL_GATE_LENGTH, microbrute_map_proportional_3}, {MICROBRUTE_SYSEX_SYNC, MICROBRUTE_CTL_SYNC, microbrute_map_special}, {MICROBRUTE_SYSEX_TX_CHANNEL, MICROBRUTE_CTL_TX_CHANNEL, microbrute_map_plus_one}, {MICROBRUTE_SYSEX_RX_CHANNEL, MICROBRUTE_CTL_RX_CHANNEL, microbrute_map_plus_one}, {MICROBRUTE_SYSEX_RETRIGGERING, MICROBRUTE_CTL_RETRIGGERING, microbrute_map_special}, {MICROBRUTE_SYSEX_PLAY_ON, MICROBRUTE_CTL_PLAY_ON, microbrute_map_proportional_2}, {MICROBRUTE_SYSEX_NEXT_SEQUENCE, MICROBRUTE_CTL_NEXT_SEQUENCE, microbrute_map_special}, {MICROBRUTE_SYSEX_STEP_ON, MICROBRUTE_CTL_STEP_ON, microbrute_map_proportional_2}, {MICROBRUTE_SYSEX_STEP_LENGTH, MICROBRUTE_CTL_STEP_LENGTH, microbrute_map_step_length}, {MICROBRUTE_SYSEX_CALIB_PB_CENTER, MICROBRUTE_NOP, NULL}, {MICROBRUTE_SYSEX_CALIB_BOTH_BOTTOM, MICROBRUTE_NOP, NULL}, {MICROBRUTE_SYSEX_CALIB_BOTH_TOP, MICROBRUTE_NOP, NULL}, {MICROBRUTE_SYSEX_CALIB_END, MICROBRUTE_NOP, NULL} }; static guint8 microbrute_get_counter (struct backend *backend) { guint8 *seq = backend->data; guint8 value = *seq; (*seq)++; if (*seq == 0x80) { *seq = 0; } return value; } static gint microbrute_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { struct common_simple_read_dir_data *data; if (strcmp (dir, "/")) { return -ENOTDIR; } data = g_malloc (sizeof (struct common_simple_read_dir_data)); data->next = 1; data->last = MICROBRUTE_MAX_SEQS; item_iterator_init (iter, dir, data, common_simple_next_dentry, g_free); return 0; } static GByteArray * microbrute_get_sequence_request_msg (struct backend *backend, guint8 id, guint8 offset) { guint8 counter = microbrute_get_counter (backend); GByteArray *tx_msg = g_byte_array_sized_new (sizeof (MICROBRUTE_SEQ_REQ)); g_byte_array_append (tx_msg, MICROBRUTE_SEQ_REQ, sizeof (MICROBRUTE_SEQ_REQ)); tx_msg->data[MICROBRUTE_SEQ_REQ_COUNTER_POS] = counter; tx_msg->data[MICROBRUTE_SEQ_REQ_ID_POS] = id; tx_msg->data[MICROBRUTE_SEQ_REQ_OFFSET_POS] = offset; return tx_msg; } static gint microbrute_download_seq_data (struct backend *backend, guint seqnum, guint offset, GByteArray *sequence) { GByteArray *tx_msg, *rx_msg; gchar aux[LABEL_MAX]; guint8 *step; if (!offset) { snprintf (aux, LABEL_MAX, "%1d:", seqnum + 1); g_byte_array_append (sequence, (guint8 *) aux, strlen (aux)); } tx_msg = microbrute_get_sequence_request_msg (backend, seqnum, offset); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } step = &rx_msg->data[MICROBRUTE_SEQ_RPLY_DATA_POS]; while (*step && *step != 0xf7) { if (*step == 0x7f) { g_byte_array_append (sequence, (guint8 *) " x", 2); } else { snprintf (aux, LABEL_MAX, " %02d", *step); g_byte_array_append (sequence, (guint8 *) aux, strlen (aux)); } step++; } free_msg (rx_msg); return 0; } static gint microbrute_download (struct backend *backend, const gchar *src_path, struct idata *sequence, struct job_control *control) { gint err; guint seqnum; GByteArray *data; err = common_slot_get_id_from_path (src_path, &seqnum); if (err) { return err; } seqnum--; if (seqnum >= MICROBRUTE_MAX_SEQS) { return -EINVAL; } job_control_reset (control, 1); data = g_byte_array_new (); err = microbrute_download_seq_data (backend, seqnum, 0, data); if (err) { goto err; } job_control_set_progress (control, 0.5); err = microbrute_download_seq_data (backend, seqnum, 0x20, data); if (err) { goto err; } job_control_set_progress (control, 1.0); idata_init (sequence, data, NULL, NULL); return 0; err: g_byte_array_free (data, TRUE); return err; } static GByteArray * microbrute_set_sequence_request_msg (struct backend *backend, guint8 id, guint8 offset) { guint8 counter = microbrute_get_counter (backend); GByteArray *tx_msg = g_byte_array_sized_new (sizeof (MICROBRUTE_SEQ_MSG)); g_byte_array_append (tx_msg, MICROBRUTE_SEQ_MSG, sizeof (MICROBRUTE_SEQ_MSG)); tx_msg->data[MICROBRUTE_SEQ_REQ_COUNTER_POS] = counter; tx_msg->data[MICROBRUTE_SEQ_REQ_ID_POS] = id; tx_msg->data[MICROBRUTE_SEQ_REQ_OFFSET_POS] = offset; return tx_msg; } static gint microbrute_send_seq_msg (struct backend *backend, guint8 seqnum, guint8 offset, gchar **tokens, gint *pos, gint total) { struct sysex_transfer transfer; guint8 steps = 0; gchar *token = *tokens; gint err; guint8 *step; transfer.raw = microbrute_set_sequence_request_msg (backend, seqnum, offset); step = &transfer.raw->data[MICROBRUTE_SEQ_RPLY_DATA_POS]; while (steps < 32 && *pos < total) { if (*token < 0x20) { error_print ("Invalid character"); token++; (*pos)++; continue; } else if (*token == ' ') { token++; (*pos)++; continue; } else if (token[0] == '0' && token[1] != ' ') { token++; (*pos)++; continue; } else if (*token == 'x' || *token == 'X') { *step = 0x7f; token++; (*pos)++; debug_print (2, "Note: -"); } else { gchar *rem; glong note = strtol (token, &rem, 10); *step = note >= 0x7f ? 0x7f : note; *step = *step < 12 ? 0x7f : *step; if (*step == 0 && token == rem) { error_print ("Error while reading note"); token++; (*pos)++; continue; } token = rem; *pos += (*step >= 100) ? 3 : (*step >= 10) ? 2 : 1; debug_print (2, "Note: 0x%02x (%d)", *step, *step); } steps++; step++; } transfer.raw->data[MICROBRUTE_SEQ_RPLY_LEN_POS] = steps; //This doesn't need synchronized access as the caller provices this already. err = backend_tx_sysex (backend, &transfer); free_msg (transfer.raw); *tokens = token; return err < 0 ? err : steps; } static gint microbrute_upload (struct backend *backend, const gchar *path, struct idata *sequence, struct job_control *control) { GByteArray *input = sequence->content; gchar *token = (gchar *) & input->data[MICROBRUTE_SEQ_TXT_POS]; gint pos = MICROBRUTE_SEQ_TXT_POS; guint seqnum; gint steps, err; err = common_slot_get_id_from_path (path, &seqnum); if (err) { return err; } seqnum--; if (seqnum >= MICROBRUTE_MAX_SEQS) { return -EINVAL; } g_mutex_lock (&backend->mutex); job_control_reset (control, 1); steps = microbrute_send_seq_msg (backend, seqnum, 0, &token, &pos, input->len); if (steps < 0) { goto end; } else if (pos < input->len) { job_control_set_progress (control, 0.5); steps = microbrute_send_seq_msg (backend, seqnum, 0x20, &token, &pos, input->len); if (steps < 0) { goto end; } } job_control_set_progress (control, 1.0); end: g_mutex_unlock (&backend->mutex); return steps < 0 ? steps : 0; } static const gchar ** microbrute_get_extensions () { return MICROBRUTE_EXTS; } static const struct fs_operations FS_MICROBRUTE_OPERATIONS = { .id = FS_MICROBRUTE_SEQUENCE, .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE, .name = "sequence", .gui_name = "Sequences", .gui_icon = FS_ICON_SEQ, .readdir = microbrute_read_dir, .print_item = common_print_item, .download = microbrute_download, .upload = microbrute_upload, .load = file_load, .save = file_save, .get_exts = microbrute_get_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_slot_get_download_path_n }; gint microbrute_handshake (struct backend *backend) { guint8 *seq; if (memcmp (backend->midi_info.company, ARTURIA_ID, sizeof (ARTURIA_ID)) || memcmp (backend->midi_info.family, FAMILY_ID, sizeof (FAMILY_ID)) || memcmp (backend->midi_info.model, MODEL_ID, sizeof (MODEL_ID))) { return -ENODEV; } seq = g_malloc (sizeof (guint8)); *seq = 0; gslist_fill (&backend->fs_ops, &FS_MICROBRUTE_OPERATIONS, NULL); backend->destroy_data = backend_destroy_data; backend->data = seq; snprintf (backend->name, LABEL_MAX, "Arturia MicroBrute"); return 0; } static GByteArray * microbrute_get_parameter_msg (struct backend *backend, guint8 param) { GByteArray *tx_msg; guint8 counter = microbrute_get_counter (backend); tx_msg = g_byte_array_sized_new (sizeof (MICROBRUTE_GET_PARAM_MSG)); g_byte_array_append (tx_msg, MICROBRUTE_GET_PARAM_MSG, sizeof (MICROBRUTE_GET_PARAM_MSG)); tx_msg->data[6] = counter; tx_msg->data[8] = param; return tx_msg; } gint microbrute_get_parameter (struct backend *backend, enum microbrute_param param, guint8 *value) { GByteArray *tx_msg, *rx_msg; guint8 *seq = backend->data; guint8 counter = *seq; guint8 op = MICROBRUTE_PARAMS[param].sysex; tx_msg = microbrute_get_parameter_msg (backend, op + 1); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } if (rx_msg->data[6] != counter) { error_print ("Bad sequence number byte"); return -EIO; } if (rx_msg->data[7] != 1) { error_print ("Bad client byte"); return -EIO; } if (rx_msg->data[8] != op) { error_print ("Bad parameter byte"); return -EIO; } *value = rx_msg->data[9]; free_msg (rx_msg); return 0; } static GByteArray * microbrute_set_parameter_msg (struct backend *backend, guint8 param, guint8 value) { guint8 counter = microbrute_get_counter (backend); GByteArray *tx_msg = g_byte_array_sized_new (sizeof (MICROBRUTE_SET_PARAM_MSG)); g_byte_array_append (tx_msg, MICROBRUTE_SET_PARAM_MSG, sizeof (MICROBRUTE_SET_PARAM_MSG)); tx_msg->data[6] = counter; tx_msg->data[7] = 1; tx_msg->data[8] = MICROBRUTE_PARAMS[param].sysex; tx_msg->data[9] = value; return tx_msg; } gint microbrute_set_parameter (struct backend *backend, enum microbrute_param param, guint8 value, guint8 channel, gboolean sysex) { gint err; if (sysex) { struct sysex_transfer transfer; transfer.raw = microbrute_set_parameter_msg (backend, param, value); err = backend_tx_sysex (backend, &transfer); free_msg (transfer.raw); } else { if (MICROBRUTE_PARAMS[param].ctl == MICROBRUTE_NOP || !MICROBRUTE_PARAMS[param].value_map) { error_print ("Bad parameter"); return -EINVAL; } if (param == MICROBRUTE_BEND_RANGE) { err = backend_send_rpn (backend, channel, 0, 0, value, 0); } else { guint8 v = MICROBRUTE_PARAMS[param].value_map (value); err = backend_send_controller (backend, channel, MICROBRUTE_PARAMS[param].ctl, v); } } return err; } const struct connector CONNECTOR_MICROBRUTE = { .name = MICROBRUTE_NAME, .handshake = microbrute_handshake, .standard = TRUE, .regex = ".*MicroBrute.*" }; elektroid-3.2.3/src/connectors/microbrute.h000066400000000000000000000032451500236517400210000ustar00rootroot00000000000000/* * cz.h * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef MICROBRUTE_H #define MICROBRUTE_H #include "connector.h" #define MICROBRUTE_NAME "microbrute" enum microbrute_param { MICROBRUTE_NOTE_PRIORITY, MICROBRUTE_VEL_RESPONSE, MICROBRUTE_LFO_KEY_RETRIGGER, MICROBRUTE_ENVELOPE_LEGATO, MICROBRUTE_BEND_RANGE, MICROBRUTE_GATE_LENGTH, MICROBRUTE_SYNC, MICROBRUTE_TX_CHANNEL, MICROBRUTE_RX_CHANNEL, MICROBRUTE_RETRIGGERING, MICROBRUTE_PLAY_ON, MICROBRUTE_NEXT_SEQUENCE, MICROBRUTE_STEP_ON, MICROBRUTE_STEP_LENGTH, MICROBRUTE_CALIB_PB_CENTER, MICROBRUTE_CALIB_BOTH_BOTTOM, MICROBRUTE_CALIB_BOTH_TOP, MICROBRUTE_CALIB_END }; gint microbrute_handshake (struct backend *); gint microbrute_get_parameter (struct backend *, enum microbrute_param, guint8 *); gint microbrute_set_parameter (struct backend *, enum microbrute_param, guint8, guint8, gboolean); extern const struct connector CONNECTOR_MICROBRUTE; #endif elektroid-3.2.3/src/connectors/microfreak.c000066400000000000000000001470231500236517400207450ustar00rootroot00000000000000/* * microfreak.c * Copyright (C) 2024 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "microfreak.h" #include "common.h" #define MICROFREAK_PRESET_NAME_LEN 14 #define MICROFREAK_MAX_PRESETS 512 #define MICROFREAK_MAX_SAMPLES 128 #define MICROFREAK_REST_TIME_US 5000 #define MICROFREAK_REST_TIME_LONG_US 30000 #define MICROFREAK_SAMPLE_BATCH_SIZE MICROFREAK_SAMPLE_BLOCK_SIZE // 147 packets (146 * 28 + 8) #define MICROFREAK_SAMPLE_BATCH_LEN (MICROFREAK_SAMPLE_BATCH_SIZE / MICROFREAK_SAMPLE_SIZE) #define MICROFREAK_SAMPLE_BATCH_PACKETS 147 #define MICROFREAK_MAX_WAVETABLES 16 #define MICROFREAK_WAVETABLE_PARTS 4 #define MICROFREAK_WAVETABLE_FRAMES_PER_BATCH (MICROFREAK_SAMPLE_BATCH_SIZE / (MICROFREAK_WAVETABLE_CYCLES * MICROFREAK_SAMPLE_SIZE)) #define MICROFREAK_SAMPLE_ITEM_MAX_LEN (MICROFREAK_SAMPLERATE * MICROFREAK_SAMPLE_ITEM_MAX_TIME_S) #define MICROFREAK_SAMPLE_ITEM_MAX_SIZE (MICROFREAK_SAMPLE_ITEM_MAX_LEN * MICROFREAK_SAMPLE_SIZE) #define MICROFREAK_SAMPLE_MAX_BATCHES (MICROFREAK_SAMPLE_ITEM_MAX_SIZE / MICROFREAK_SAMPLE_BATCH_SIZE) #define MICROFREAK_PRESET_HEADER "174" #define MICROFREAK_GET_MSG_PAYLOAD_LEN(msg) ((msg)->data[7]) #define MICROFREAK_GET_MSG_OP(msg) ((msg)->data[8]) #define MICROFREAK_GET_MSG_PAYLOAD(msg) (&(msg)->data[9]) #define MICROFREAK_GET_ID_FROM_HEADER(header) ((header[0] << 7) | header[1]) #define MICROFREAK_GET_ID_IN_BANK_FROM_HEADER(header) (&header[8]) // Equals to header[1] #define MICROFREAK_GET_INIT_FROM_HEADER(header) (&header[3]) #define MICROFREAK_GET_CATEGORY_FROM_HEADER(header) (&header[10]) #define MICROFREAK_GET_P1_FROM_HEADER(header) (&header[11]) #define MICROFREAK_GET_NAME_FROM_HEADER(header) ((gchar*)&header[12]) #define MICROFREAK_CHECK_OP_LEN(msg,op,len) (MICROFREAK_GET_MSG_OP(msg) == op && MICROFREAK_GET_MSG_PAYLOAD_LEN(msg) == len ? 0 : -EIO) #define MICROFREAK_ALPHABET " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-" #define MICROFREAK_DEFAULT_CHAR '.' #define MICROFREAK_PPRESET_EXT "mfp" #define MICROFREAK_PPRESET_EXT_2 "mbp" //This extension is used in the files inside the mfprojz files (zip files). #define MICROFREAK_ZPRESET_EXT "mfpz" #define MICROFREAK_WAVETABLE_EMPTY 0x08 static const gchar *MICROFREAK_PRESET_EXTS[] = { MICROFREAK_ZPRESET_EXT, MICROFREAK_PPRESET_EXT, MICROFREAK_PPRESET_EXT_2 }; static const gchar *MICROFREAK_PPRESET_EXTS[] = { MICROFREAK_PPRESET_EXT, NULL }; static const gchar *MICROFREAK_ZPRESET_EXTS[] = { MICROFREAK_ZPRESET_EXT, NULL }; static const gchar *MICROFREAK_PWAVETABLE_EXTS[] = { MICROFREAK_PWAVETABLE_EXT, NULL }; static const gchar *MICROFREAK_ZWAVETABLE_EXTS[] = { MICROFREAK_ZWAVETABLE_EXT, NULL }; static const guint8 MICROFREAK_REQUEST_HEADER[] = { 0xf0, 0, 0x20, 0x6b, 7, 1 }; static const guint8 ARTURIA_ID[] = { 0x0, 0x20, 0x6b }; static const guint8 FAMILY_ID[] = { 0x6, 0x0 }; static const guint8 MODEL_ID[] = { 0x6, 0x1 }; enum microfreak_fs { FS_MICROFREAK_PPRESET, //Plain presets FS_MICROFREAK_ZPRESET, //Zipped presets FS_MICROFREAK_PRESET, //Loads ppreset and zpreset and stores zpreset FS_MICROFREAK_SAMPLE, FS_MICROFREAK_PWAVETABLE, //Plain wavetables FS_MICROFREAK_ZWAVETABLE, //Zipped wavetables FS_MICROFREAK_WAVETABLE //Loads pwavetable, zwavetable and audio files and stores wav files }; struct microfreak_iter_data { guint next; struct backend *backend; }; void microfreak_midi_msg_to_8bit_msg (guint8 *msg_midi, guint8 *msg_8bit) { guint8 *dst = msg_8bit; guint8 *src = msg_midi; for (gint i = 0; i < 4; i++) { guint8 bits = *src; src++; for (gint j = 0; j < 7; j++, src++, dst++) { *dst = *src | (bits & 0x1 ? 0x80 : 0); bits >>= 1; } } } void microfreak_8bit_msg_to_midi_msg (guint8 *msg_8bit, guint8 *msg_midi) { guint8 *dst = msg_midi; guint8 *src = msg_8bit; for (gint i = 0; i < 4; i++) { guint8 *bits = dst; *bits = 0; dst++; for (gint j = 0; j < 7; j++, src++, dst++) { *dst = *src & 0x7f; *bits |= *src & 0x80; *bits >>= 1; } } } static void microfreak_preset_get_name (gchar *preset_name, GByteArray *preset_rx) { guint8 *payload = MICROFREAK_GET_MSG_PAYLOAD (preset_rx); gchar *name = MICROFREAK_GET_NAME_FROM_HEADER (payload); memcpy (preset_name, name, MICROFREAK_PRESET_NAME_LEN); preset_name[MICROFREAK_PRESET_NAME_LEN] = 0; } static GByteArray * microfreak_get_msg (struct backend *backend, guint8 op, void *data, guint8 len) { guint8 *seq = backend->data; GByteArray *tx_msg = g_byte_array_sized_new (256); g_byte_array_append (tx_msg, MICROFREAK_REQUEST_HEADER, sizeof (MICROFREAK_REQUEST_HEADER)); g_byte_array_append (tx_msg, seq, 1); if (!data) { len = 0; } g_byte_array_append (tx_msg, (guint8 *) & len, 1); g_byte_array_append (tx_msg, &op, 1); if (data) { g_byte_array_append (tx_msg, (guint8 *) data, len); } g_byte_array_append (tx_msg, (guint8 *) "\xf7", 1); (*seq)++; if (*seq == 0x80) { *seq = 0; } return tx_msg; } static GByteArray * microfreak_get_msg_from_8bit_msg (struct backend *backend, guint8 op, guint8 *msg_8bit) { guint8 midi_msg[MICROFREAK_WAVE_MSG_SIZE]; microfreak_8bit_msg_to_midi_msg (msg_8bit, midi_msg); GByteArray *msg = microfreak_get_msg (backend, op, midi_msg, MICROFREAK_WAVE_MSG_SIZE); return msg; } static GByteArray * microfreak_get_preset_op_msg (struct backend *backend, guint8 op, guint id, guint8 data) { guint8 payload[3]; payload[0] = COMMON_GET_MIDI_BANK (id); payload[1] = COMMON_GET_MIDI_PRESET (id); payload[2] = data; return microfreak_get_msg (backend, op, payload, 3); } static const gchar * microfreak_get_category_name (GByteArray *rx_msg) { gint8 category_id = *MICROFREAK_GET_CATEGORY_FROM_HEADER (MICROFREAK_GET_MSG_PAYLOAD (rx_msg)); switch (category_id) { case 0: return "Bass"; case 1: return "Brass"; case 2: return "Keys"; case 3: return "Lead"; case 4: return "Organ"; case 5: return "Pad"; case 6: return "Percussion"; case 7: return "Sequence"; case 8: return "SFX"; case 9: return "Strings"; case 10: return "Template"; case 11: return "Vocoder"; default: return ""; } } static gint microfreak_common_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, iterator_next next) { struct microfreak_iter_data *data; if (strcmp (dir, "/")) { return -ENOTDIR; } data = g_malloc (sizeof (struct microfreak_iter_data)); data->next = 1; data->backend = backend; item_iterator_init (iter, dir, data, next, g_free); return 0; } static gint microfreak_next_preset_dentry (struct item_iterator *iter) { gint err; const gchar *category; gchar preset_name[MICROFREAK_PRESET_NAME_LEN + 1]; GByteArray *tx_msg, *rx_msg; struct microfreak_iter_data *data = iter->data; guint id = data->next - 1; if (data->next > MICROFREAK_MAX_PRESETS) { return -ENOENT; } tx_msg = microfreak_get_preset_op_msg (data->backend, 0x19, id, 0); rx_msg = backend_tx_and_rx_sysex (data->backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x52, MICROFREAK_PRESET_HEADER_MSG_LEN); if (err) { goto end; } microfreak_preset_get_name (preset_name, rx_msg); snprintf (iter->item.name, LABEL_MAX, "%s", preset_name); iter->item.id = data->next; iter->item.type = ITEM_TYPE_FILE; iter->item.size = -1; category = microfreak_get_category_name (rx_msg); snprintf (iter->item.object_info, LABEL_MAX, "%s", category); (data->next)++; end: free_msg (rx_msg); usleep (MICROFREAK_REST_TIME_LONG_US); return 0; } static gint microfreak_preset_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *path, const gchar **extensions) { return microfreak_common_read_dir (backend, iter, path, microfreak_next_preset_dentry); } gint microfreak_deserialize_preset (struct microfreak_preset *mfp, GByteArray *input) { gchar *name = MICROFREAK_GET_NAME_FROM_HEADER (mfp->header); guint8 *category = MICROFREAK_GET_CATEGORY_FROM_HEADER (mfp->header); guint8 *init = MICROFREAK_GET_INIT_FROM_HEADER (mfp->header); guint8 *p1 = MICROFREAK_GET_P1_FROM_HEADER (mfp->header); gint64 datalen = 0; gint err; memset (mfp, 0, sizeof (struct microfreak_preset)); err = microfreak_deserialize_object (input, MICROFREAK_PRESET_HEADER, name, category, init, p1, mfp->data, &datalen); *init = *init ? 0x08 : 0; mfp->parts = datalen / MICROFREAK_PRESET_PART_LEN; return err; } gint microfreak_serialize_preset (GByteArray *output, struct microfreak_preset *mfp) { guint8 category = *MICROFREAK_GET_CATEGORY_FROM_HEADER (mfp->header); const gchar *name = MICROFREAK_GET_NAME_FROM_HEADER (mfp->header); guint8 init = *MICROFREAK_GET_INIT_FROM_HEADER (mfp->header); guint8 p1 = *MICROFREAK_GET_P1_FROM_HEADER (mfp->header); init = init & 0x08 ? 1 : 0; return microfreak_serialize_object (output, MICROFREAK_PRESET_HEADER, name, category, init, p1, mfp->data, mfp->parts * MICROFREAK_PRESET_PART_LEN); } static gint microfreak_preset_download (struct backend *backend, const gchar *path, struct idata *preset, struct job_control *control) { guint id; gint err; guint8 init, *payload; GByteArray *tx_msg, *rx_msg, *output; struct microfreak_preset mfp; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } id--; if (id >= MICROFREAK_MAX_PRESETS) { return -EINVAL; } output = g_byte_array_new (); job_control_reset (control, 2 + MICROFREAK_PRESET_PARTS); //Worst case tx_msg = microfreak_get_preset_op_msg (backend, 0x19, id, 0); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { goto end; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x52, MICROFREAK_PRESET_HEADER_MSG_LEN); if (err) { err = -EINVAL; free_msg (rx_msg); goto end; } payload = MICROFREAK_GET_MSG_PAYLOAD (rx_msg); init = (*MICROFREAK_GET_INIT_FROM_HEADER (payload)) & 0x08; memcpy (mfp.header, payload, MICROFREAK_PRESET_HEADER_MSG_LEN); free_msg (rx_msg); mfp.parts = init ? 0 : MICROFREAK_PRESET_PARTS; usleep (MICROFREAK_REST_TIME_US); if (init) { control->parts = 1; control->part = 0; job_control_set_progress (control, 1.0); goto end; } tx_msg = microfreak_get_preset_op_msg (backend, 0x19, id, 1); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { goto end; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x15, 0); free_msg (rx_msg); if (err) { err = -EINVAL; goto end; } usleep (MICROFREAK_REST_TIME_US); for (gint i = 0; i < mfp.parts; i++) { guint8 op = i == mfp.parts - 1 ? 0x17 : 0x16; if (!job_control_get_active_lock (control)) { err = -ECANCELED; goto end; } tx_msg = microfreak_get_msg (backend, 0x18, "\x00", 1); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { goto end; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, op, MICROFREAK_PRESET_PART_LEN); if (err) { err = -EINVAL; free_msg (rx_msg); goto end; } memcpy (&mfp.data[i * MICROFREAK_PRESET_PART_LEN], MICROFREAK_GET_MSG_PAYLOAD (rx_msg), MICROFREAK_PRESET_PART_LEN); free_msg (rx_msg); usleep (MICROFREAK_REST_TIME_US); } end: if (err) { g_byte_array_free (output, TRUE); } else { gint64 len; gchar *next; gchar name[MICROFREAK_PRESET_NAME_LEN + 1]; microfreak_serialize_preset (output, &mfp); len = g_ascii_strtoll ((gchar *) & output->data[38], &next, 10); next++; memcpy (name, next, len); name[len] = 0; idata_init (preset, output, strdup (name), NULL); } usleep (MICROFREAK_REST_TIME_LONG_US); //Additional rest return err; } static gint microfreak_preset_upload (struct backend *backend, const gchar *path, struct idata *preset, struct job_control *control) { struct microfreak_preset mfp; GByteArray *tx_msg, *rx_msg; guint id; gint err; GByteArray *input = preset->content; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } id--; if (id >= MICROFREAK_MAX_PRESETS) { return -EINVAL; } err = microfreak_deserialize_preset (&mfp, input); if (err) { return err; } job_control_reset (control, 3 + mfp.parts); mfp.header[0] = COMMON_GET_MIDI_BANK (id); mfp.header[1] = COMMON_GET_MIDI_PRESET (id); *MICROFREAK_GET_ID_IN_BANK_FROM_HEADER (mfp.header) = mfp.header[1]; tx_msg = microfreak_get_msg (backend, 0x52, mfp.header, MICROFREAK_PRESET_HEADER_MSG_LEN); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { return err; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); tx_msg = microfreak_get_preset_op_msg (backend, 0x52, id, 1); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { return err; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); tx_msg = microfreak_get_msg (backend, 0x15, NULL, 0); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { return err; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); for (gint i = 0; i < mfp.parts; i++) { if (!job_control_get_active_lock (control)) { err = -ECANCELED; break; } guint8 op = (i < mfp.parts - 1) ? 0x16 : 0x17; tx_msg = microfreak_get_msg (backend, op, &mfp.data[i * MICROFREAK_PRESET_PART_LEN], MICROFREAK_PRESET_PART_LEN); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); } usleep (MICROFREAK_REST_TIME_LONG_US); //Additional rest return 0; } static gchar * microfreak_get_object_id_as_slot (struct item *item, struct backend *backend) { return common_get_id_as_slot_padded (item, backend, 3); } void microfreak_midi_program_change (struct backend *backend, const gchar *dir, struct item *item) { common_midi_program_change_int (backend, dir, item->id - 1); } static gint microfreak_preset_rename (struct backend *backend, const gchar *src, const gchar *dst) { guint id; gint err; gchar *name, *sanitized; guint8 *header_payload, len; GByteArray *tx_msg, *rx_msg; debug_print (1, "Renaming preset..."); err = common_slot_get_id_from_path (src, &id); if (err) { return err; } id--; if (id >= MICROFREAK_MAX_PRESETS) { return -EINVAL; } tx_msg = microfreak_get_preset_op_msg (backend, 0x19, id, 0); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x52, MICROFREAK_PRESET_HEADER_MSG_LEN); if (err) { free_msg (rx_msg); return -EIO; } usleep (MICROFREAK_REST_TIME_US); header_payload = MICROFREAK_GET_MSG_PAYLOAD (rx_msg); name = MICROFREAK_GET_NAME_FROM_HEADER (header_payload); sanitized = common_get_sanitized_name (dst, MICROFREAK_ALPHABET, MICROFREAK_DEFAULT_CHAR); len = strlen (sanitized); len = len > MICROFREAK_PRESET_NAME_LEN ? MICROFREAK_PRESET_NAME_LEN : len; memcpy (name, sanitized, len); g_free (sanitized); memset (name + len, 0, MICROFREAK_PRESET_NAME_LEN - len); tx_msg = microfreak_get_msg (backend, 0x52, header_payload, MICROFREAK_PRESET_HEADER_MSG_LEN); free_msg (rx_msg); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } free_msg (rx_msg); usleep (MICROFREAK_REST_TIME_US); tx_msg = microfreak_get_preset_op_msg (backend, 0x52, id, 1); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } free_msg (rx_msg); usleep (MICROFREAK_REST_TIME_US); common_midi_program_change_int (backend, NULL, id); return 0; } static const gchar ** microfreak_ppreset_get_extensions () { return MICROFREAK_PPRESET_EXTS; } static const struct fs_operations FS_MICROFREAK_PPRESET_OPERATIONS = { .id = FS_MICROFREAK_PPRESET, .options = FS_OPTION_SLOT_STORAGE, .name = "ppreset", .max_name_len = MICROFREAK_PRESET_NAME_LEN, .readdir = microfreak_preset_read_dir, .print_item = common_print_item, .get_slot = microfreak_get_object_id_as_slot, .rename = microfreak_preset_rename, .download = microfreak_preset_download, .upload = microfreak_preset_upload, .load = file_load, .save = file_save, .get_exts = microfreak_ppreset_get_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_slot_get_download_path_nnn }; static gint microfreak_zpreset_save (const gchar *path, struct idata *zpreset, struct job_control *control) { return microfreak_zobject_save (path, zpreset, control, "0_preset"); } static const gchar ** microfreak_zpreset_get_extensions () { return MICROFREAK_ZPRESET_EXTS; } static const struct fs_operations FS_MICROFREAK_ZPRESET_OPERATIONS = { .id = FS_MICROFREAK_ZPRESET, .options = FS_OPTION_SLOT_STORAGE, .name = "zpreset", .max_name_len = MICROFREAK_PRESET_NAME_LEN, .readdir = microfreak_preset_read_dir, .print_item = common_print_item, .get_slot = microfreak_get_object_id_as_slot, .rename = microfreak_preset_rename, .download = microfreak_preset_download, .upload = microfreak_preset_upload, .load = microfreak_zobject_load, .save = microfreak_zpreset_save, .get_exts = microfreak_zpreset_get_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_slot_get_download_path_nnn }; static gint microfreak_preset_load (const char *path, struct idata *preset, struct job_control *control) { const gchar *ext = filename_get_ext (path); if (strcmp (ext, MICROFREAK_ZPRESET_EXT)) { return file_load (path, preset, control); } else { return microfreak_zobject_load (path, preset, control); } } static const gchar ** microfreak_preset_get_exts (struct backend *backend, const struct fs_operations *ops) { return MICROFREAK_PRESET_EXTS; } static const struct fs_operations FS_MICROFREAK_PRESET_OPERATIONS = { .id = FS_MICROFREAK_PRESET, .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SLOT_COLUMN | FS_OPTION_SHOW_INFO_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "preset", .gui_name = "Presets", .gui_icon = FS_ICON_SND, .max_name_len = MICROFREAK_PRESET_NAME_LEN, .readdir = microfreak_preset_read_dir, .print_item = common_print_item, .get_slot = microfreak_get_object_id_as_slot, .rename = microfreak_preset_rename, .download = microfreak_preset_download, .upload = microfreak_preset_upload, .load = microfreak_preset_load, .save = microfreak_zpreset_save, .get_exts = microfreak_preset_get_exts, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_slot_get_download_path_nnn, .select_item = microfreak_midi_program_change }; static GByteArray * microfreak_get_wave_op_msg (struct backend *backend, guint8 op, guint8 id, guint8 part, guint8 data) { guint8 payload[3]; payload[0] = COMMON_GET_MIDI_PRESET (id); payload[1] = part; payload[2] = data; return microfreak_get_msg (backend, op, payload, 3); } static gint microfreak_next_sample_dentry (struct item_iterator *iter) { gint err; GByteArray *tx_msg, *rx_msg; struct microfreak_sample_header header; struct microfreak_iter_data *data = iter->data; if (data->next > MICROFREAK_MAX_SAMPLES) { return -ENOENT; } tx_msg = microfreak_get_wave_op_msg (data->backend, 0x5b, data->next - 1, 0, 0); rx_msg = backend_tx_and_rx_sysex (data->backend, tx_msg, -1); if (!rx_msg) { err = -EIO; goto end; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x15, 0); free_msg (rx_msg); if (err) { goto end; } tx_msg = microfreak_get_msg (data->backend, 0x18, "\x00", 1); rx_msg = backend_tx_and_rx_sysex (data->backend, tx_msg, -1); if (!rx_msg) { err = -EIO; goto end; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x16, MICROFREAK_WAVE_MSG_SIZE); if (err) { free_msg (rx_msg); goto end; } microfreak_midi_msg_to_8bit_msg (MICROFREAK_GET_MSG_PAYLOAD (rx_msg), (guint8 *) & header); snprintf (iter->item.name, LABEL_MAX, "%s", header.name); iter->item.id = data->next; iter->item.type = ITEM_TYPE_FILE; iter->item.size = GINT32_FROM_LE (header.size); (data->next)++; free_msg (rx_msg); end: usleep (MICROFREAK_REST_TIME_US); return err; } static gint microfreak_sample_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *path, const gchar **extensions) { return microfreak_common_read_dir (backend, iter, path, microfreak_next_sample_dentry); } static gint microfreak_sample_reset (struct backend *backend, guint id, struct microfreak_sample_header *header) { gint err; GByteArray *tx_msg, *rx_msg; tx_msg = microfreak_get_wave_op_msg (backend, 0x5a, id, 0, 0); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); tx_msg = microfreak_get_msg (backend, 0x15, NULL, 0); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); tx_msg = microfreak_get_msg_from_8bit_msg (backend, 0x17, (guint8 *) header); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); usleep (MICROFREAK_REST_TIME_US); return err; } static gint microfreak_sample_clear (struct backend *backend, const gchar *path) { gint err; guint id; struct microfreak_sample_header header; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } id--; if (id >= MICROFREAK_MAX_SAMPLES) { return -EINVAL; } memset (&header, 0, sizeof (header)); header.id = id; return microfreak_sample_reset (backend, id, &header); } //This function provides the same value as Arturia MIDI Control Center most of the time. //Perhaps, the differences appear due to sample transformations like normalization or the like. static guint16 microfreak_sample_get_cksum (GByteArray *input) { guint16 cksum = 0, *v; v = (guint16 *) input->data; for (gint i = 0; i < input->len; i += 2, v++) { cksum += *v; } debug_print (2, "sum: %0x", cksum); return cksum; } static guint64 microfreak_get_bfree_from_msg (GByteArray *rx_msg) { guint8 *payload, lsb, msb; gfloat tused_ms, tfree_ms, used_ms; payload = MICROFREAK_GET_MSG_PAYLOAD (rx_msg); lsb = payload[6] | (payload[2] & 0x08 ? 0x80 : 0); msb = payload[7] | (payload[2] & 0x04 ? 0x80 : 0); tused_ms = (((msb << 8) | lsb) << 2); tfree_ms = MICROFREAK_SAMPLE_TOTAL_MAX_TIME_MS - tused_ms; used_ms = tfree_ms / MICROFREAK_SAMPLE_TOTAL_MAX_TIME_MS; return MICROFREAK_SAMPLE_MEM_SIZE * used_ms; } static gint microfreak_get_storage_stats (struct backend *backend, guint8 type, struct backend_storage_stats *statfs, const gchar *path) { gint err = 0; GByteArray *tx_msg, *rx_msg; tx_msg = microfreak_get_msg (backend, 0x47, "\x0a", 1); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } if (MICROFREAK_CHECK_OP_LEN (rx_msg, 0x48, 9)) { err = -EIO; goto err; } snprintf (statfs->name, LABEL_MAX, "%s", "sample"); statfs->bfree = microfreak_get_bfree_from_msg (rx_msg); statfs->bsize = MICROFREAK_SAMPLE_MEM_SIZE; err: free_msg (rx_msg); usleep (MICROFREAK_REST_TIME_US); return err; } //This function handles out of order packages. static gint microfreak_sample_upload_tx_and_rx (struct backend *backend, GByteArray *tx_msg, GByteArray **rx_msg, struct job_control *control) { guint8 seq = tx_msg->data[sizeof (MICROFREAK_REQUEST_HEADER)]; gint err = common_data_tx_and_rx_part (backend, tx_msg, rx_msg, control); if (err) { if (err == -EIO) { control->part++; } err = 0; //The response will be out of order. } else { //Note that there are some packets are just not sent sometimes. while (seq != (*rx_msg)->data[sizeof (MICROFREAK_REQUEST_HEADER)]) { free_msg (*rx_msg); *rx_msg = backend_tx_and_rx_sysex (backend, NULL, -1); if (!*rx_msg) { err = -EIO; break; } } } return err; } static gint microfreak_sample_upload (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { gint err; guint id, batches; gchar *sanitized; struct backend_storage_stats statfs; struct microfreak_sample_header header; GByteArray *tx_msg, *rx_msg; GByteArray *input = sample->content; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } sanitized = common_get_sanitized_name (sample->name, MICROFREAK_ALPHABET, MICROFREAK_DEFAULT_CHAR); id--; if (id >= MICROFREAK_MAX_SAMPLES) { err = -EINVAL; goto end; } batches = input->len / MICROFREAK_SAMPLE_BATCH_SIZE; batches += (input->len % MICROFREAK_SAMPLE_BATCH_SIZE) ? 1 : 0; if (batches > MICROFREAK_SAMPLE_MAX_BATCHES) { batches = MICROFREAK_SAMPLE_MAX_BATCHES; } job_control_reset (control, 6 + batches * (2 + MICROFREAK_SAMPLE_BATCH_PACKETS) + 1 + MICROFREAK_SAMPLE_BATCH_PACKETS); //This is called by Arturia MIDI Control Center before uploading a sample. //Perhaps this does more than just retrieving the statistics. microfreak_get_storage_stats (backend, 0, &statfs, NULL); job_control_set_progress (control, 1.0); control->part++; tx_msg = microfreak_get_wave_op_msg (backend, 0x5d, id, 0, 0); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { goto end; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { goto end; } usleep (MICROFREAK_REST_TIME_US); tx_msg = microfreak_get_msg (backend, 0x15, NULL, 0); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { goto end; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { goto end; } usleep (MICROFREAK_REST_TIME_US); memset (&header, 0, sizeof (header)); header.size = GINT32_TO_LE (input->len); header.cksum = microfreak_sample_get_cksum (input); snprintf (header.name, MICROFREAK_SAMPLE_NAME_LEN, "%s", sanitized); header.id = id; tx_msg = microfreak_get_msg_from_8bit_msg (backend, 0x17, (guint8 *) & header); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { goto end; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x16, 1); if (!err) { err = *MICROFREAK_GET_MSG_PAYLOAD (rx_msg) == 1 ? 0 : -ENOMEM; // No space on the device for more samples } free_msg (rx_msg); if (err) { common_data_tx_and_rx_part (backend, NULL, &rx_msg, control); free_msg (rx_msg); goto end; } usleep (MICROFREAK_REST_TIME_US); err = common_data_tx_and_rx_part (backend, NULL, &rx_msg, control); if (err) { goto end; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { goto end; } usleep (MICROFREAK_REST_TIME_US); err = microfreak_sample_reset (backend, id, &header); if (err) { goto end; } job_control_set_progress (control, 1.0); control->part++; usleep (MICROFREAK_REST_TIME_US); guint32 total = 0; gint16 *src = (gint16 *) input->data; for (gint b = 0; b < batches; b++) { //Starting packets tx_msg = microfreak_get_wave_op_msg (backend, 0x58, id, 0, 1); err = microfreak_sample_upload_tx_and_rx (backend, tx_msg, &rx_msg, control); if (err) { goto end; } if (rx_msg) { err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { goto end; } } usleep (MICROFREAK_REST_TIME_US); tx_msg = microfreak_get_msg (backend, 0x15, NULL, 0); err = microfreak_sample_upload_tx_and_rx (backend, tx_msg, &rx_msg, control); if (err) { goto end; } if (rx_msg) { err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { goto end; } } //Data packets for (gint p = 1; p <= MICROFREAK_SAMPLE_BATCH_PACKETS; p++) { guint8 op, midi_msg[MICROFREAK_WAVE_MSG_SIZE]; guint len; gint16 blk[MICROFREAK_WAVE_BLK_SHRT]; gint16 *dst = blk; if (!job_control_get_active_lock (control)) { err = -ECANCELED; goto end; } if (p < MICROFREAK_SAMPLE_BATCH_PACKETS) { op = 0x16; len = MICROFREAK_WAVE_BLK_SHRT; } else { op = 0x17; len = MICROFREAK_WAVE_BLK_LAST_SHRT; } gint i; for (i = 0; i < len && total < input->len; i++) { *dst = GINT16_TO_LE (*src); dst++; src++; total += sizeof (gint16); } for (; i < len; i++) { *dst = 0; dst++; } usleep (MICROFREAK_REST_TIME_US); microfreak_8bit_msg_to_midi_msg ((guint8 *) blk, midi_msg); tx_msg = microfreak_get_msg (backend, op, midi_msg, MICROFREAK_WAVE_MSG_SIZE); err = microfreak_sample_upload_tx_and_rx (backend, tx_msg, &rx_msg, control); if (err) { goto end; } if (rx_msg) { err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { goto end; } } } usleep (MICROFREAK_REST_TIME_US); } //This phase happens after the upload. It is unknown that the purpose is. tx_msg = microfreak_get_wave_op_msg (backend, 0x5b, id, 0, 1); err = microfreak_sample_upload_tx_and_rx (backend, tx_msg, &rx_msg, control); if (err) { goto end; } if (rx_msg) { err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x15, 0); free_msg (rx_msg); if (err) { goto end; } } usleep (MICROFREAK_REST_TIME_US); for (gint p = 1; p <= MICROFREAK_SAMPLE_BATCH_PACKETS; p++) { guint8 op = p < MICROFREAK_SAMPLE_BATCH_PACKETS ? 0x16 : 0x17; tx_msg = microfreak_get_msg (backend, 0x18, "\x00", 1); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { goto end; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, op, 0x20); free_msg (rx_msg); if (err) { goto end; } usleep (MICROFREAK_REST_TIME_US); } //Arturia MIDI Control Center sends an additional 0x18 message as the latest above //but looks like it is not actualy needed. end: g_free (sanitized); usleep (MICROFREAK_REST_TIME_US); return err; } static gint microfreak_next_wavetable_dentry (struct item_iterator *iter) { gint err; GByteArray *tx_msg, *rx_msg; struct microfreak_wavetable_header header; struct microfreak_iter_data *data = iter->data; guint8 id = data->next - 1; if (data->next > MICROFREAK_MAX_WAVETABLES) { return -ENOENT; } tx_msg = microfreak_get_wave_op_msg (data->backend, 0x57, id, 0, 0); //Last byte is 1 in MIDI Control Center rx_msg = backend_tx_and_rx_sysex (data->backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x15, 0); free_msg (rx_msg); if (err) { goto end; } tx_msg = microfreak_get_msg (data->backend, 0x18, "\x01", 1); rx_msg = backend_tx_and_rx_sysex (data->backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x16, MICROFREAK_WAVE_MSG_SIZE); if (err) { goto end; } microfreak_midi_msg_to_8bit_msg (MICROFREAK_GET_MSG_PAYLOAD (rx_msg), (guint8 *) & header); snprintf (iter->item.name, LABEL_MAX, "%s", header.name); iter->item.id = data->next; iter->item.type = ITEM_TYPE_FILE; iter->item.size = header.status0 == MICROFREAK_WAVETABLE_EMPTY ? 0 : MICROFREAK_WAVETABLE_SIZE; (data->next)++; end: free_msg (rx_msg); usleep (MICROFREAK_REST_TIME_LONG_US); return err; } static gint microfreak_wavetable_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *path, const gchar **extensions) { return microfreak_common_read_dir (backend, iter, path, microfreak_next_wavetable_dentry); } static gint microfreak_wavetable_load (const gchar *path, struct idata *wavetable, struct job_control *control) { struct idata aux; gint err = common_sample_load (path, &aux, control, 0, 1, SF_FORMAT_PCM_16); if (err) { return -EINVAL; } if (aux.content->len == MICROFREAK_WAVETABLE_SIZE) { struct sample_info *sample_info = microfreak_new_sample_info (MICROFREAK_WAVETABLE_LEN); gchar *name = strdup (aux.name); idata_init (wavetable, idata_steal (&aux), name, sample_info); return 0; } else { debug_print (1, "Resampling to get a valid wavetable..."); struct sample_info *si = aux.info; struct sample_info si_req; GByteArray *a; microfreak_init_sample_info (&si_req, MICROFREAK_WAVETABLE_LEN); si_req.rate = si->rate * MICROFREAK_WAVETABLE_LEN / si->frames; err = sample_reload (&aux, wavetable, NULL, &si_req, job_control_set_sample_progress_no_sync, NULL); idata_free (&aux); a = wavetable->content; debug_print (2, "Resulting size: %d", a->len); if (a->len < MICROFREAK_WAVETABLE_SIZE) { for (gint i = a->len; i < MICROFREAK_WAVETABLE_SIZE; i += 2) { g_byte_array_append (a, (guint8 *) "\x00\x00", 2); } debug_print (2, "Resulting fixed size: %d", a->len); } return err; } } static gint microfreak_wavetable_download_part (struct backend *backend, GByteArray *output, struct job_control *control, guint8 id, guint8 part) { gint err; gint16 *src, *dst; guint8 msg_8bit[MICROFREAK_WAVE_BLK_SIZE]; GByteArray *tx_msg, *rx_msg; tx_msg = microfreak_get_wave_op_msg (backend, 0x55, id, part, 0); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { return -err; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x15, 0); free_msg (rx_msg); if (err) { goto end; } usleep (MICROFREAK_REST_TIME_US); dst = (gint16 *) (output->data + part * MICROFREAK_SAMPLE_BATCH_SIZE); for (gint p = 1; p <= MICROFREAK_SAMPLE_BATCH_PACKETS; p++) { guint8 op; guint len; if (!job_control_get_active_lock (control)) { return -ECANCELED; } if (p < MICROFREAK_SAMPLE_BATCH_PACKETS) { op = 0x16; len = MICROFREAK_WAVE_BLK_SHRT; } else { op = 0x17; len = MICROFREAK_WAVE_BLK_LAST_SHRT; } tx_msg = microfreak_get_msg (backend, 0x18, "0x00", 1); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { return err; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, op, 0x20); if (!err) { microfreak_midi_msg_to_8bit_msg (MICROFREAK_GET_MSG_PAYLOAD (rx_msg), msg_8bit); src = (gint16 *) msg_8bit; for (gint i = 0; i < len; i++) { gint16 v = GINT16_FROM_LE (*src); memcpy ((guint8 *) dst, (guint8 *) & v, MICROFREAK_SAMPLE_SIZE); dst++; src++; } } free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); } end: return err; } static gint microfreak_wavetable_download (struct backend *backend, const gchar *path, struct idata *wavetable, struct job_control *control) { guint id; guint err = 0; struct sample_info *sample_info; struct item_iterator iter; gboolean found; gchar name[MICROFREAK_WAVETABLE_NAME_LEN]; GByteArray *content; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } id--; if (id >= MICROFREAK_MAX_WAVETABLES) { return -EINVAL; } err = microfreak_wavetable_read_dir (backend, &iter, "/", NULL); if (err) { return err; } name[0] = 0; found = FALSE; while (!item_iterator_next (&iter)) { if (iter.item.id - 1 == id) { err = snprintf (name, MICROFREAK_WAVETABLE_NAME_LEN, "%s", iter.item.name); //If truncation happen, it is not marked as found and it will eventually lead to an error. if (err < MICROFREAK_WAVETABLE_NAME_LEN) { found = TRUE; } } } item_iterator_free (&iter); if (!found) { return -EINVAL; } sample_info = microfreak_new_sample_info (MICROFREAK_WAVETABLE_LEN); content = g_byte_array_sized_new (MICROFREAK_WAVETABLE_SIZE); content->len = MICROFREAK_WAVETABLE_SIZE; job_control_reset (control, (MICROFREAK_SAMPLE_BATCH_PACKETS + 1) * MICROFREAK_WAVETABLE_PARTS); err = 0; for (guint8 part = 0; part < MICROFREAK_WAVETABLE_PARTS && !err; part++) { err = microfreak_wavetable_download_part (backend, content, control, id, part); } if (err) { g_free (content); g_free (sample_info); } else { idata_init (wavetable, content, strdup (name), sample_info); } return err; } //This function is used to upload but also to clear up wavetables so it is not possible to have a control struct here. static gint microfreak_wavetable_upload_part (struct backend *backend, GByteArray *input, guint8 id, guint8 part) { gint err; gint16 *src, *dst; GByteArray *tx_msg, *rx_msg; guint8 msg_8bit[MICROFREAK_WAVE_BLK_SIZE]; tx_msg = microfreak_get_wave_op_msg (backend, 0x54, id, part, 1); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); tx_msg = microfreak_get_msg (backend, 0x15, NULL, 0); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); src = (gint16 *) (input->data + part * MICROFREAK_SAMPLE_BATCH_SIZE); for (gint p = 1; p <= MICROFREAK_SAMPLE_BATCH_PACKETS; p++) { guint8 op; guint len; if (p < MICROFREAK_SAMPLE_BATCH_PACKETS) { op = 0x16; len = MICROFREAK_WAVE_BLK_SHRT; } else { op = 0x17; len = MICROFREAK_WAVE_BLK_LAST_SHRT; } dst = (gint16 *) msg_8bit; for (gint i = 0; i < len; i++) { gint16 v = GINT16_TO_LE (*src); memcpy ((guint8 *) dst, (guint8 *) & v, MICROFREAK_SAMPLE_SIZE); dst++; src++; } tx_msg = microfreak_get_msg_from_8bit_msg (backend, op, (guint8 *) & msg_8bit); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); } return 0; } static gint microfreak_wavetable_reset (struct backend *backend, guint id, struct microfreak_wavetable_header *header) { gint err; GByteArray *tx_msg, *rx_msg; tx_msg = microfreak_get_wave_op_msg (backend, 0x56, id, 0, 0); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); tx_msg = microfreak_get_msg (backend, 0x15, NULL, 0); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); tx_msg = microfreak_get_msg_from_8bit_msg (backend, 0x16, (guint8 *) header); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); tx_msg = microfreak_get_msg (backend, 0x17, "\x00\x00\x00\x00\x00\x00\x00\x00", 8); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { return -EIO; } err = MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0); free_msg (rx_msg); if (err) { return err; } usleep (MICROFREAK_REST_TIME_US); return err; } static gint microfreak_wavetable_set_entry (struct backend *backend, guint id, const gchar *name, guint8 status) { gchar *sanitized; struct microfreak_wavetable_header header; memset (&header, 0, sizeof (header)); header.id0 = id; header.id1 = id; header.status0 = status; header.status1 = 1; header.status2 = 1; sanitized = common_get_sanitized_name (name, MICROFREAK_ALPHABET, MICROFREAK_DEFAULT_CHAR); snprintf (header.name, MICROFREAK_WAVETABLE_NAME_LEN, "%s", sanitized); g_free (sanitized); return microfreak_wavetable_reset (backend, id, &header); } static gint microfreak_wavetable_rename (struct backend *backend, const gchar *src, const gchar *dst) { guint id; if (common_slot_get_id_from_path (src, &id)) { return -EINVAL; } id--; if (id >= MICROFREAK_MAX_WAVETABLES) { return -EINVAL; } return microfreak_wavetable_set_entry (backend, id, dst, 0); } static gint microfreak_wavetable_upload_id_name (struct backend *backend, const gchar *path, GByteArray *wavetable, struct job_control *control, guint id, const gchar *name) { gint err; id--; if (id >= MICROFREAK_MAX_WAVETABLES) { return -EINVAL; } job_control_reset (control, 1 + MICROFREAK_WAVETABLE_PARTS); err = microfreak_wavetable_set_entry (backend, id, name, 0); if (err) { return err; } job_control_set_progress (control, 1.0); control->part++; for (guint8 part = 0; part < MICROFREAK_WAVETABLE_PARTS && !err; part++) { if (!job_control_get_active_lock (control)) { return -ECANCELED; } err = microfreak_wavetable_upload_part (backend, wavetable, id, part); job_control_set_progress (control, 1.0); control->part++; } return err; } static gint microfreak_xwavetable_upload (struct backend *backend, const gchar *path, struct idata *idata, struct job_control *control) { gint err; guint id; GByteArray *wavetable = idata->content; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } return microfreak_wavetable_upload_id_name (backend, path, wavetable, control, id, idata->name); } static gint microfreak_wavetable_upload (struct backend *backend, const gchar *path, struct idata *idata, struct job_control *control) { gint err; guint id; GByteArray *wavetable = idata->content; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } err = microfreak_wavetable_upload_id_name (backend, path, wavetable, control, id, idata->name); return err; } static gint microfreak_wavetable_clear (struct backend *backend, const gchar *path) { gint err; guint id; GByteArray *data; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } id--; if (id >= MICROFREAK_MAX_WAVETABLES) { return -EINVAL; } err = microfreak_wavetable_set_entry (backend, id, "", MICROFREAK_WAVETABLE_EMPTY); if (err) { return err; } data = g_byte_array_sized_new (MICROFREAK_SAMPLE_BATCH_SIZE); memset (data->data, 0, MICROFREAK_SAMPLE_BATCH_SIZE); for (guint8 part = 0; part < MICROFREAK_WAVETABLE_PARTS && !err; part++) { err = microfreak_wavetable_upload_part (backend, data, id, part); } g_byte_array_free (data, TRUE); return err; } static gint microfreak_sample_load (const gchar *path, struct idata *sample, struct job_control *control) { return common_sample_load (path, sample, control, MICROFREAK_SAMPLERATE, 1, SF_FORMAT_PCM_16); } static const struct fs_operations FS_MICROFREAK_SAMPLE_OPERATIONS = { .id = FS_MICROFREAK_SAMPLE, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SLOT_COLUMN | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "sample", .gui_name = "Samples", .gui_icon = FS_ICON_WAVE, .max_name_len = MICROFREAK_SAMPLE_NAME_LEN - 1, .readdir = microfreak_sample_read_dir, .print_item = common_print_item, .get_slot = microfreak_get_object_id_as_slot, .delete = microfreak_sample_clear, .clear = microfreak_sample_clear, .upload = microfreak_sample_upload, .load = microfreak_sample_load, .get_exts = sample_get_sample_extensions, .get_upload_path = common_slot_get_upload_path }; static gchar * microfreak_get_wavetable_id_as_slot (struct item *item, struct backend *backend) { return common_get_id_as_slot_padded (item, backend, 2); } static const gchar ** microfreak_pwavetable_get_extensions () { return MICROFREAK_PWAVETABLE_EXTS; } static const struct fs_operations FS_MICROFREAK_PWAVETABLE_OPERATIONS = { .id = FS_MICROFREAK_PWAVETABLE, .options = FS_OPTION_SLOT_STORAGE, .name = "pwavetable", .max_name_len = MICROFREAK_WAVETABLE_NAME_LEN - 1, .readdir = microfreak_wavetable_read_dir, .print_item = common_print_item, .get_slot = microfreak_get_wavetable_id_as_slot, .clear = microfreak_wavetable_clear, .rename = microfreak_wavetable_rename, .download = microfreak_wavetable_download, .upload = microfreak_xwavetable_upload, .load = microfreak_pwavetable_load, .save = microfreak_pwavetable_save, .get_exts = microfreak_pwavetable_get_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_slot_get_download_path_nn }; static const gchar ** microfreak_zwavetable_get_extensions () { return MICROFREAK_ZWAVETABLE_EXTS; } static const struct fs_operations FS_MICROFREAK_ZWAVETABLE_OPERATIONS = { .id = FS_MICROFREAK_ZWAVETABLE, .options = FS_OPTION_SLOT_STORAGE, .name = "zwavetable", .max_name_len = MICROFREAK_WAVETABLE_NAME_LEN - 1, .readdir = microfreak_wavetable_read_dir, .print_item = common_print_item, .get_slot = microfreak_get_wavetable_id_as_slot, .clear = microfreak_wavetable_clear, .rename = microfreak_wavetable_rename, .download = microfreak_wavetable_download, .upload = microfreak_xwavetable_upload, .load = microfreak_zwavetable_load, .save = microfreak_zwavetable_save, .get_exts = microfreak_zwavetable_get_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_slot_get_download_path_nn }; static gint microfreak_wavetable_save (const gchar *path, struct idata *wavetable, struct job_control *control) { return sample_save_to_file (path, wavetable, control, SF_FORMAT_WAV | SF_FORMAT_PCM_16); } static const struct fs_operations FS_MICROFREAK_WAVETABLE_OPERATIONS = { .id = FS_MICROFREAK_WAVETABLE, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SLOT_COLUMN | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "wavetable", .gui_name = "Wavetables", .gui_icon = FS_ICON_WAVETABLE, .max_name_len = MICROFREAK_WAVETABLE_NAME_LEN - 1, .readdir = microfreak_wavetable_read_dir, .print_item = common_print_item, .get_slot = microfreak_get_wavetable_id_as_slot, .delete = microfreak_wavetable_clear, .clear = microfreak_wavetable_clear, .rename = microfreak_wavetable_rename, .download = microfreak_wavetable_download, .upload = microfreak_wavetable_upload, .load = microfreak_wavetable_load, .save = microfreak_wavetable_save, .get_exts = sample_get_sample_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_slot_get_download_path_nn }; static gint microfreak_handshake_int (struct backend *backend) { if (memcmp (backend->midi_info.company, ARTURIA_ID, sizeof (ARTURIA_ID)) || memcmp (backend->midi_info.family, FAMILY_ID, sizeof (FAMILY_ID)) || memcmp (backend->midi_info.model, MODEL_ID, sizeof (MODEL_ID))) { return -ENODEV; } if (backend->midi_info.version[0] != 5) { error_print ("MicroFreak firmware version 5 required"); return -ENODEV; } return 0; } gint microfreak_sample_defragment (struct backend *backend) { gint err = 0; GByteArray *tx_msg, *rx_msg; tx_msg = microfreak_get_msg (backend, 0x49, "\x09\x7f\x00", 3); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, 3600000); // 1 hour if (!rx_msg) { return -EIO; } if (MICROFREAK_CHECK_OP_LEN (rx_msg, 0x18, 0)) { err = -EIO; } free_msg (rx_msg); usleep (MICROFREAK_REST_TIME_LONG_US); return err; } static gint microfreak_handshake (struct backend *backend) { gint err; guint8 *seq; GByteArray *tx_msg, *rx_msg; seq = g_malloc (sizeof (guint8)); *seq = 0; backend->data = seq; err = microfreak_handshake_int (backend); if (err) { //After booting, the MicroFreak needs this message to start responding. tx_msg = microfreak_get_preset_op_msg (backend, 0x19, 0, 0); rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1); if (!rx_msg) { g_free (backend->data); backend->data = NULL; return -ENODEV; } free_msg (rx_msg); usleep (MICROFREAK_REST_TIME_LONG_US); backend_midi_handshake (backend); err = microfreak_handshake_int (backend); if (err) { g_free (backend->data); backend->data = NULL; return err; } } gslist_fill (&backend->fs_ops, &FS_MICROFREAK_PPRESET_OPERATIONS, &FS_MICROFREAK_ZPRESET_OPERATIONS, &FS_MICROFREAK_PRESET_OPERATIONS, &FS_MICROFREAK_SAMPLE_OPERATIONS, &FS_MICROFREAK_PWAVETABLE_OPERATIONS, &FS_MICROFREAK_ZWAVETABLE_OPERATIONS, &FS_MICROFREAK_WAVETABLE_OPERATIONS, NULL); backend->destroy_data = backend_destroy_data; backend->get_storage_stats = microfreak_get_storage_stats; snprintf (backend->name, LABEL_MAX, "Arturia MicroFreak"); return 0; } const struct connector CONNECTOR_MICROFREAK = { .name = MICROFREAK_NAME, .handshake = microfreak_handshake, .standard = TRUE, .regex = ".*MicroFreak.*" }; elektroid-3.2.3/src/connectors/microfreak.h000066400000000000000000000074701500236517400207530ustar00rootroot00000000000000/* * microfreak.h * Copyright (C) 2024 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef MICROFREAK_H #define MICROFREAK_H #include "connector.h" #include "microfreak_sample.h" #define MICROFREAK_NAME "microfreak" #define MICROFREAK_PRESET_HEADER_MSG_LEN 0x23 #define MICROFREAK_PRESET_PARTS 146 #define MICROFREAK_PRESET_PART_LEN 0x20 #define MICROFREAK_SAMPLE_NAME_LEN 13 //Includes a NUL at the end #define MICROFREAK_SAMPLE_BLOCK_SIZE 4096 #define MICROFREAK_SAMPLE_ITEM_MAX_TIME_S 24 // 375 blocks #define MICROFREAK_SAMPLE_TOTAL_MAX_TIME_MS 209920 // Closest value to 210 s being multiple of MICROFREAK_SAMPLE_BLOCK_SIZE (3280 blocks) #define MICROFREAK_SAMPLE_SIZE_PER_S (MICROFREAK_SAMPLERATE * MICROFREAK_SAMPLE_SIZE) // at 32 kHz 16 bits #define MICROFREAK_SAMPLE_MEM_SIZE ((uint32_t)(MICROFREAK_SAMPLE_TOTAL_MAX_TIME_MS * MICROFREAK_SAMPLE_SIZE_PER_S / 1000)) #define MICROFREAK_WAVE_BLK_SHRT 14 #define MICROFREAK_WAVE_BLK_LAST_SHRT 4 #define MICROFREAK_WAVE_BLK_SIZE (MICROFREAK_WAVE_BLK_SHRT * MICROFREAK_SAMPLE_SIZE) #define MICROFREAK_WAVE_MSG_SIZE (MICROFREAK_WAVE_BLK_SIZE * 8 / 7) //32 #define MICROFREAK_PRESET_DATALEN (MICROFREAK_PRESET_PARTS * MICROFREAK_PRESET_PART_LEN) struct microfreak_preset { guint8 header[MICROFREAK_PRESET_HEADER_MSG_LEN]; guint8 data[MICROFREAK_PRESET_DATALEN]; guint parts; }; //Sample memory seems to start at 0x00281000. Addressing block size is MICROFREAK_SAMPLE_BLOCK_SIZE. //When an upload is performed, the MicroFreak tries to find a gap in the address space. //* If there is a big enough gap, it will be used; otherwise, the new sample is appended after the last used block. //* If there is no space for a sample, no error is thrown and the process runs. Sometimes, an error is thrown and -ENOMEM is returned. //This scheme may lead to fragmentation (the sum of the space in the gaps is enough for a sample but it does not fit at the end). //This is totally independent of the slot used. //Samples larger than MICROFREAK_SAMPLE_ITEM_MAX_TIME_S are handled by this connector by truncating the size when loading the sample. See microfreak_sample_load. //If a sample does not fit, the MicroFreak returns an error which is handled by this connector with a -ENOMEM. See microfreak_sample_upload. //Theoretical sample limit space is MICROFREAK_SAMPLE_MEM_SIZE (0x00cd0000) or 3280 blocks of MICROFREAK_SAMPLE_BLOCK_SIZE or roughly 210 s. // The size of this structure is 28 bytes and matches MICROFREAK_WAVE_BLK_SIZE. struct microfreak_sample_header { guint32 address; //Only used when reading the samples directory. Set to 0 when uploading. guint32 size; guint16 cksum; //Values stored here do not seem to be important. gchar name[MICROFREAK_SAMPLE_NAME_LEN]; guint8 id; guint8 end[4]; }; // The size of this structure is 28 bytes and matches MICROFREAK_WAVE_BLK_SIZE. struct microfreak_wavetable_header { guint8 id0; guint8 pad0[2]; guint8 status0; guint8 data[4]; guint8 id1; guint8 pad1; guint8 status1; guint8 status2; gchar name[MICROFREAK_WAVETABLE_NAME_LEN]; }; extern const struct connector CONNECTOR_MICROFREAK; gint microfreak_sample_defragment (struct backend *backend); #endif elektroid-3.2.3/src/connectors/microfreak_sample.c000066400000000000000000000331701500236517400223030ustar00rootroot00000000000000/* * microfreak_sample.c * Copyright (C) 2024 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "utils.h" #include "microfreak_sample.h" #define MICROFREAK_SERIALIZATION_TAG "serialization::archive" #define MICROFREAK_ZEROS "000000000000000000" #define MICROFREAK_WAVETABLE_HEADER "DEVBUILD" #define MICROFREAK_SAMPLE_HEADER "94" gint microfreak_serialize_object (GByteArray *output, const gchar *version, const gchar *name, guint8 p0, guint8 p3, guint8 p5, guint8 *data, guint datalen) { gchar aux[LABEL_MAX]; guint namelen = strlen (name); gint8 *v; guint len; debug_print (2, "Serializing object '%s'...", name); len = strlen (MICROFREAK_SERIALIZATION_TAG); snprintf (aux, LABEL_MAX, "%d ", len); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); g_byte_array_append (output, (guint8 *) MICROFREAK_SERIALIZATION_TAG, len); snprintf (aux, LABEL_MAX, " %d", 10); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); snprintf (aux, LABEL_MAX, " %d", 0); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); snprintf (aux, LABEL_MAX, " %d", 4); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); len = strlen (version); snprintf (aux, LABEL_MAX, " %d ", len); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); g_byte_array_append (output, (guint8 *) version, len); snprintf (aux, LABEL_MAX, " %d ", namelen); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); g_byte_array_append (output, (guint8 *) name, namelen); snprintf (aux, LABEL_MAX, " %d", p0); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); snprintf (aux, LABEL_MAX, " %d", 0); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); snprintf (aux, LABEL_MAX, " %d", 0); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); len = strlen (MICROFREAK_ZEROS); snprintf (aux, LABEL_MAX, " %d ", len); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); g_byte_array_append (output, (guint8 *) MICROFREAK_ZEROS, len); snprintf (aux, LABEL_MAX, " %d", p3); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); snprintf (aux, LABEL_MAX, " %d", 0); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); snprintf (aux, LABEL_MAX, " %d", p5); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); snprintf (aux, LABEL_MAX, " %d", datalen); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); v = (gint8 *) data; for (guint i = 0; i < datalen; i++, v++) { snprintf (aux, LABEL_MAX, " %d", *v); g_byte_array_append (output, (guint8 *) aux, strlen (aux)); } g_byte_array_append (output, (guint8 *) "\x0a", 1); return 0; } static gint microfreak_deserialize_read_value (guint8 **position, gint64 *value) { gchar *p = (gchar *) * position; gchar *endp; *value = g_ascii_strtoll (p, &endp, 10); if (p == endp) { return -EINVAL; } *position = (guint8 *) endp; return 0; } static gint microfreak_deserialize_check_value (guint8 **position, gint64 test) { gint64 value; gint err = microfreak_deserialize_read_value (position, &value); if (err || value != test) { return -EINVAL; } return 0; } gint microfreak_deserialize_object (GByteArray *input, const gchar *header, gchar *name, guint8 *p0, guint8 *p3, guint8 *p5, guint8 *data, gint64 *datalen) { gint64 v; gint err; guint len; guint8 *p; GByteArray *safe; //As this relies on string readings, the input data needs to be NULL //terminated to handle errors properly. len = input->len + 1; safe = g_byte_array_sized_new (len); g_byte_array_append (safe, input->data, input->len); g_byte_array_append (safe, (guint8 *) "\x00", 1); p = safe->data; len = strlen (MICROFREAK_SERIALIZATION_TAG); err = microfreak_deserialize_check_value (&p, len); if (err) { goto end; } p++; err = memcmp (p, (guint8 *) MICROFREAK_SERIALIZATION_TAG, len); if (err) { err = -EINVAL; goto end; } p += len; err = microfreak_deserialize_check_value (&p, 10); if (err) { goto end; } err = microfreak_deserialize_check_value (&p, 0); if (err) { goto end; } err = microfreak_deserialize_check_value (&p, 4); if (err) { goto end; } err = microfreak_deserialize_read_value (&p, &v); if (err) { goto end; } p += v + 1; err = microfreak_deserialize_read_value (&p, &v); if (err) { goto end; } p++; memcpy (name, p, v); name[v] = 0; debug_print (2, "Deserializing object '%s'...", name); p += v; err = microfreak_deserialize_read_value (&p, &v); if (err) { goto end; } *p0 = v; err = microfreak_deserialize_check_value (&p, 0); if (err) { goto end; } err = microfreak_deserialize_check_value (&p, 0); if (err) { goto end; } err = microfreak_deserialize_check_value (&p, 18); if (err) { goto end; } p++; len = strlen (MICROFREAK_ZEROS); if (memcmp (p, (guint8 *) MICROFREAK_ZEROS, len)) { err = -EINVAL; goto end; } p += len + 1; err = microfreak_deserialize_read_value (&p, &v); if (err) { goto end; } *p3 = v; err = microfreak_deserialize_check_value (&p, 0); if (err) { goto end; } err = microfreak_deserialize_read_value (&p, &v); if (err) { goto end; } *p5 = v; err = microfreak_deserialize_read_value (&p, &v); if (err) { goto end; } *datalen = v; for (guint i = 0; i < *datalen; i++, data++) { err = microfreak_deserialize_read_value (&p, &v); if (err) { goto end; } *data = v; } //A byte 0x0d appears in wavetables and samples when exported from Arturia //MIDI Control Center but not when downloading wavetables. if (*p == 0x0d) { p++; } //A byte 0x0a is always present at the end. if (*p != 0x0a) { err = -EINVAL; } end: g_byte_array_free (safe, TRUE); return err; } void microfreak_init_sample_info (struct sample_info *sample_info, guint32 frames) { sample_info->midi_note = 0; sample_info->loop_type = 0; sample_info->channels = 1; sample_info->rate = MICROFREAK_SAMPLERATE; sample_info->format = SF_FORMAT_PCM_16; sample_info->frames = frames; sample_info->loop_start = 0; sample_info->loop_end = sample_info->frames - 1; } struct sample_info * microfreak_new_sample_info (guint32 frames) { struct sample_info *sample_info = g_malloc (sizeof (struct sample_info)); microfreak_init_sample_info (sample_info, frames); return sample_info; } gint microfreak_deserialize_sample (struct idata *sample, struct idata *serialized, const gchar *header) { gchar name[MICROFREAK_WAVETABLE_NAME_LEN]; guint8 p0, p3, p5; gint64 datalen; gint err; struct sample_info *sample_info; GByteArray *data = g_byte_array_sized_new (2 * MI); //Enough for 24 s samples or wavetables err = microfreak_deserialize_object (serialized->content, header, name, &p0, &p3, &p5, data->data, &datalen); if (err) { g_byte_array_free (data, TRUE); return err; } data->len = datalen; sample_info = microfreak_new_sample_info (datalen / 2); idata_init (sample, data, strdup (name), sample_info); return 0; } gint microfreak_zobject_save (const gchar *path, struct idata *zobject, struct job_control *control, const gchar *name) { gint err = 0, index; zip_t *archive; zip_error_t zerror; zip_source_t *source; GByteArray *array = zobject->content; zip_error_init (&zerror); archive = zip_open (path, ZIP_CREATE, &err); if (!archive) { zip_error_init_with_code (&zerror, err); error_print ("Error while saving zip file: %s", zip_error_strerror (&zerror)); zip_error_fini (&zerror); return -EIO; } source = zip_source_buffer (archive, array->data, array->len, 0); if (!source) { error_print ("Error while creating source buffer: %s", zip_strerror (archive)); err = -EIO; goto end; } //Any name works as long as its a number, an underscore and additional characters without spaces. index = zip_file_add (archive, name, source, ZIP_FL_OVERWRITE); if (index < 0) { error_print ("Error while adding to file: %s", zip_strerror (archive)); err = -EIO; goto end; } if (zip_close (archive)) { error_print ("Error while saving zip file: %s", zip_error_strerror (&zerror)); zip_error_fini (&zerror); err = -EIO; } end: if (err) { zip_discard (archive); } return err; } gint microfreak_zobject_load (const char *path, struct idata *zobject, struct job_control *control) { gint err = 0; zip_t *archive; zip_stat_t zstat; zip_error_t zerror; zip_file_t *zip_file = NULL; GByteArray *array; archive = zip_open (path, ZIP_RDONLY, &err); if (!archive) { zip_error_init_with_code (&zerror, err); error_print ("Error while opening zip file: %s", zip_error_strerror (&zerror)); zip_error_fini (&zerror); return -EIO; } array = g_byte_array_new (); if (zip_get_num_entries (archive, 0) != 1) { err = -EIO; goto end; } zip_file = zip_fopen_index (archive, 0, 0); if (!zip_file) { err = -EIO; goto end; } if (zip_stat_index (archive, 0, ZIP_FL_ENC_STRICT, &zstat)) { err = -EIO; goto end; } g_byte_array_set_size (array, zstat.size); zip_fread (zip_file, array->data, zstat.size); end: if (zip_file) { zip_fclose (zip_file); } err = zip_close (archive) ? -EIO : 0; if (err) { g_byte_array_free (array, TRUE); } else { idata_init (zobject, array, NULL, NULL); } return err; } gint microfreak_zsample_load (const gchar *path, struct idata *sample, struct job_control *control) { gint err; struct idata aux; err = microfreak_zobject_load (path, &aux, control); if (err) { return err; } err = microfreak_deserialize_sample (sample, &aux, MICROFREAK_SAMPLE_HEADER); idata_free (&aux); return err; } gint microfreak_psample_load (const gchar *path, struct idata *sample, struct job_control *control) { gint err; struct idata aux; err = file_load (path, &aux, control); if (err) { return err; } err = microfreak_deserialize_sample (sample, &aux, MICROFREAK_SAMPLE_HEADER); idata_free (&aux); return err; } gint microfreak_serialize_sample (struct idata *serialized, struct idata *wavetable, const gchar *header) { gint err; GByteArray *data = g_byte_array_sized_new (MICROFREAK_WAVETABLE_SIZE * 8); err = microfreak_serialize_object (data, header, wavetable->name, 1, 0, 1, wavetable->content->data, wavetable->content->len); if (err) { g_byte_array_free (data, TRUE); } else { idata_init (serialized, data, NULL, NULL); } return err; } gint microfreak_serialize_wavetable (struct idata *serialized, struct idata *wavetable) { return microfreak_serialize_sample (serialized, wavetable, MICROFREAK_WAVETABLE_HEADER); } gint microfreak_deserialize_wavetable (struct idata *wavetable, struct idata *serialized) { struct sample_info *sample_info; gint err; err = microfreak_deserialize_sample (wavetable, serialized, MICROFREAK_WAVETABLE_HEADER); if (err) { return err; } sample_info = wavetable->info; if (sample_info->frames != MICROFREAK_WAVETABLE_LEN) { idata_free (wavetable); return -EINVAL; } return 0; } gint microfreak_pwavetable_load (const gchar *path, struct idata *wavetable, struct job_control *control) { gint err; struct idata aux; err = file_load (path, &aux, control); if (err) { return err; } err = microfreak_deserialize_wavetable (wavetable, &aux); idata_free (&aux); return err; } gint microfreak_zwavetable_load (const gchar *path, struct idata *wavetable, struct job_control *control) { gint err; struct idata aux; err = microfreak_zobject_load (path, &aux, control); if (err) { return err; } err = microfreak_deserialize_wavetable (wavetable, &aux); idata_free (&aux); return err; } gint microfreak_pwavetable_save (const gchar *path, struct idata *wavetable, struct job_control *control) { gint err; struct idata aux; err = microfreak_serialize_wavetable (&aux, wavetable); if (err) { goto cleanup; } err = file_save (path, &aux, control); cleanup: idata_free (&aux); return err; } gint microfreak_zwavetable_save (const gchar *path, struct idata *wavetable, struct job_control *control) { gint err; struct idata aux; err = microfreak_serialize_sample (&aux, wavetable, MICROFREAK_WAVETABLE_HEADER); if (err) { goto cleanup; } err = microfreak_zobject_save (path, &aux, control, "0_wavetable"); cleanup: idata_free (&aux); return err; } elektroid-3.2.3/src/connectors/microfreak_sample.h000066400000000000000000000055041500236517400223100ustar00rootroot00000000000000/* * microfreak_sample.h * Copyright (C) 2024 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "sample.h" #ifndef MICROFREAK_UTILS_H #define MICROFREAK_UTILS_H #define MICROFREAK_SAMPLERATE 32000 #define MICROFREAK_SAMPLE_SIZE (sizeof(gint16)) #define MICROFREAK_WAVETABLE_SAMPLE_LEN 256 #define MICROFREAK_WAVETABLE_CYCLES 32 #define MICROFREAK_WAVETABLE_LEN (MICROFREAK_WAVETABLE_SAMPLE_LEN * MICROFREAK_WAVETABLE_CYCLES) #define MICROFREAK_WAVETABLE_SIZE (MICROFREAK_WAVETABLE_LEN * MICROFREAK_SAMPLE_SIZE) #define MICROFREAK_WAVETABLE_NAME_LEN 16 #define MICROFREAK_PWAVETABLE_EXT "mfw" #define MICROFREAK_ZWAVETABLE_EXT "mfwz" #define MICROFREAK_PSAMPLE_EXT "mfs" #define MICROFREAK_ZSAMPLE_EXT "mfsz" gint microfreak_serialize_object (GByteArray * output, const gchar * header, const gchar * name, guint8 p0, guint8 p3, guint8 p5, guint8 * data, guint datalen); gint microfreak_deserialize_object (GByteArray * input, const gchar * header, gchar * name, guint8 * p0, guint8 * p3, guint8 * p5, guint8 * data, gint64 * datalen); void microfreak_init_sample_info (struct sample_info *sample_info, guint32 frames); struct sample_info *microfreak_new_sample_info (guint32 frames); gint microfreak_zobject_save (const gchar * path, struct idata *zobject, struct job_control *control, const gchar * name); gint microfreak_zobject_load (const char *path, struct idata *zobject, struct job_control *control); gint microfreak_zsample_load (const gchar * path, struct idata *sample, struct job_control *control); gint microfreak_psample_load (const gchar * path, struct idata *sample, struct job_control *control); gint microfreak_pwavetable_load (const gchar * path, struct idata *wavetable, struct job_control *control); gint microfreak_zwavetable_load (const gchar * path, struct idata *wavetable, struct job_control *control); gint microfreak_pwavetable_save (const gchar * path, struct idata *wavetable, struct job_control *control); gint microfreak_zwavetable_save (const gchar * path, struct idata *wavetable, struct job_control *control); #endif elektroid-3.2.3/src/connectors/package.c000066400000000000000000000634501500236517400202170ustar00rootroot00000000000000/* * package.c * Copyright (C) 2021 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include #include "package.h" #include "utils.h" #include "sample.h" #include "elektron.h" #define PKG_TAG_FORMAT_VERSION "FormatVersion" #define PKG_TAG_PRODUCT_TYPE "ProductType" #define PKG_TAG_PAYLOAD "Payload" #define PKG_TAG_FILE_TYPE "FileType" #define PKG_TAG_FIRMWARE_VERSION "FirmwareVersion" #define PKG_TAG_METAINFO "MetaInfo" #define PKG_TAG_TAGS "Tags" #define PKG_TAG_SAMPLES "Samples" #define PKG_TAG_FILE_NAME "FileName" #define PKG_TAG_FILE_SIZE "FileSize" #define PKG_TAG_HASH "Hash" #define PKG_VAL_FILE_TYPE_PRJ "Project" #define PKG_VAL_FILE_TYPE_SND "Sound" #define PKG_VAL_FILE_TYPE_PST "Preset" #define PKG_VAL_FILE_TYPE_UNK "Unknown" #define MAN_TAG_SAMPLE_REFS "sample_references" #define MAN_TAG_HASH "hash" #define MAN_TAG_SIZE "size" #define METADATA_TAG_SAMPLE_REFS "sound_tags" #define MAX_PACKAGE_LEN (512 * 1024 * 1024) #define MAX_MANIFEST_LEN (128 * 1024) #define MANIFEST_FILENAME "manifest.json" static GSList * package_get_tags_from_snd_metadata_int (JsonReader *reader) { gint elements; GSList *tags = NULL; if (!json_reader_read_member (reader, METADATA_TAG_SAMPLE_REFS)) { debug_print (1, "Member '%s' not found", METADATA_TAG_SAMPLE_REFS); return NULL; } if (!json_reader_is_array (reader)) { error_print ("Member '%s' is not an array. Continuing...", METADATA_TAG_SAMPLE_REFS); goto end; } elements = json_reader_count_elements (reader); if (!elements) { debug_print (1, "No tags found"); return NULL; } for (gint i = 0; i < elements; i++) { const gchar *tag; if (!json_reader_read_element (reader, i)) { error_print ("Cannot read element %d. Continuing...", i); continue; } tag = json_reader_get_string_value (reader); tags = g_slist_append (tags, strdup (tag)); json_reader_end_element (reader); } end: json_reader_end_element (reader); return tags; } GSList * package_get_tags_from_snd_metadata (GByteArray *metadata) { JsonParser *parser; JsonReader *reader; GError *error = NULL; GSList *tags = NULL; parser = json_parser_new (); if (!json_parser_load_from_data (parser, (gchar *) metadata->data, metadata->len, &error)) { error_print ("Unable to parse stream: %s. Continuing...", error->message); g_clear_error (&error); goto cleanup_parser; } reader = json_reader_new (json_parser_get_root (parser)); if (!reader) { error_print ("Unable to read from parser. Continuing..."); goto cleanup_parser; } tags = package_get_tags_from_snd_metadata_int (reader); g_object_unref (reader); cleanup_parser: g_object_unref (parser); return tags; } static gint package_add_resource (struct package *pkg, struct package_resource *pkg_resource, gboolean new) { zip_source_t *sample_source; zip_int64_t index; zip_error_t zerror; debug_print (1, "Adding file %s to zip (%d B)...", pkg_resource->path, pkg_resource->data->len); sample_source = zip_source_buffer_create (pkg_resource->data->data, pkg_resource->data->len, 0, &zerror); if (!sample_source) { error_print ("Error while creating file source: %s", zip_error_strerror (&zerror)); zip_error_fini (&zerror); return -1; } index = zip_file_add (pkg->zip, pkg_resource->path, sample_source, ZIP_FL_OVERWRITE | ZIP_FL_ENC_UTF_8); if (index < 0) { error_print ("Error while adding file: %s", zip_error_strerror (zip_get_error (pkg->zip))); zip_source_free (sample_source); return -1; } if (new) { pkg->resources = g_list_append (pkg->resources, pkg_resource); } return 0; } gint package_begin (struct package *pkg, gchar *name, const gchar *fw_version, const struct device_desc *device_desc, enum package_type type) { zip_error_t zerror; pkg->resources = NULL; pkg->buff = g_malloc (MAX_PACKAGE_LEN); pkg->name = name; pkg->fw_version = strdup (fw_version); pkg->device_desc = device_desc; pkg->type = type; debug_print (1, "Creating zip buffer..."); zip_error_init (&zerror); pkg->zip_source = zip_source_buffer_create (pkg->buff, MAX_PACKAGE_LEN, 0, &zerror); if (!pkg->zip_source) { error_print ("Error while creating zip source: %s", zip_error_strerror (&zerror)); zip_error_fini (&zerror); g_free (pkg->buff); return -1; } pkg->zip = zip_open_from_source (pkg->zip_source, ZIP_TRUNCATE, &zerror); if (!pkg->zip) { error_print ("Error while creating in memory zip: %s", zip_error_strerror (&zerror)); zip_error_fini (&zerror); zip_source_free (pkg->zip_source); g_free (pkg->buff); return -1; } zip_source_keep (pkg->zip_source); pkg->manifest = g_malloc (sizeof (struct package_resource)); pkg->manifest->type = PKG_RES_TYPE_MANIFEST; pkg->manifest->data = g_byte_array_sized_new (MAX_MANIFEST_LEN); //We need this because we can not resize later. pkg->manifest->path = strdup (MANIFEST_FILENAME); package_add_resource (pkg, pkg->manifest, TRUE); return 0; } static const gchar * package_get_file_type (enum package_type type) { if (type & PKG_FILE_TYPE_DATA_PROJECT) { return PKG_VAL_FILE_TYPE_PRJ; } else if (type & PKG_FILE_TYPE_DATA_SOUND) { return PKG_VAL_FILE_TYPE_SND; } else if (type & PKG_FILE_TYPE_DATA_PRESET) { return PKG_VAL_FILE_TYPE_PST; } else { return PKG_VAL_FILE_TYPE_UNK; } } static gint package_add_manifest (struct package *pkg) { JsonBuilder *builder; JsonGenerator *gen; JsonNode *root; gchar *json; gint len; gchar *val = g_malloc (LABEL_MAX); GList *resource; gboolean samples_found = FALSE; struct package_resource *pkg_resource; builder = json_builder_new (); json_builder_begin_object (builder); json_builder_set_member_name (builder, PKG_TAG_FORMAT_VERSION); json_builder_add_string_value (builder, "1.0"); json_builder_set_member_name (builder, PKG_TAG_PRODUCT_TYPE); json_builder_begin_array (builder); snprintf (val, LABEL_MAX, "%d", pkg->device_desc->id); json_builder_add_string_value (builder, val); json_builder_end_array (builder); json_builder_set_member_name (builder, PKG_TAG_PAYLOAD); json_builder_add_string_value (builder, pkg->name); json_builder_set_member_name (builder, PKG_TAG_FILE_TYPE); json_builder_add_string_value (builder, package_get_file_type (pkg->type)); if (pkg->type != PKG_FILE_TYPE_RAW_PRESET) { json_builder_set_member_name (builder, PKG_TAG_FIRMWARE_VERSION); json_builder_add_string_value (builder, pkg->fw_version); } for (resource = pkg->resources; resource; resource = resource->next) { pkg_resource = resource->data; if (pkg_resource->type == PKG_RES_TYPE_SAMPLE) { samples_found = TRUE; break; } } if (pkg->manifest->tags) // PKG_FILE_TYPE_DATA_SOUND { json_builder_set_member_name (builder, PKG_TAG_METAINFO); json_builder_begin_object (builder); json_builder_set_member_name (builder, PKG_TAG_TAGS); json_builder_begin_array (builder); GSList *e = pkg->manifest->tags; while (e) { gchar *tag = (gchar *) e->data; json_builder_add_string_value (builder, tag); e = e->next; } json_builder_end_array (builder); json_builder_end_object (builder); } if (samples_found) { json_builder_set_member_name (builder, PKG_TAG_SAMPLES); json_builder_begin_array (builder); for (resource = pkg->resources; resource; resource = resource->next) { pkg_resource = resource->data; if (pkg_resource->type == PKG_RES_TYPE_SAMPLE) { json_builder_begin_object (builder); json_builder_set_member_name (builder, PKG_TAG_FILE_NAME); json_builder_add_string_value (builder, pkg_resource->path); json_builder_set_member_name (builder, PKG_TAG_FILE_SIZE); json_builder_add_int_value (builder, pkg_resource->size); json_builder_set_member_name (builder, PKG_TAG_HASH); snprintf (val, LABEL_MAX, "%u", pkg_resource->hash); json_builder_add_string_value (builder, val); json_builder_end_object (builder); } } json_builder_end_array (builder); } json_builder_end_object (builder); gen = json_generator_new (); g_object_set (gen, "pretty", TRUE, NULL); root = json_builder_get_root (builder); json_generator_set_root (gen, root); json = json_generator_to_data (gen, NULL); len = strlen (json); memcpy (pkg->manifest->data->data, json, len); pkg->manifest->data->len = len; package_add_resource (pkg, pkg->manifest, FALSE); g_free (json); json_node_free (root); g_object_unref (gen); g_object_unref (builder); g_free (val); return 0; } gint package_end (struct package *pkg, struct idata *out) { int ret = 0; zip_stat_t zstat; GByteArray *content; ret = package_add_manifest (pkg); if (ret) { error_print ("Error while formatting %s", MANIFEST_FILENAME); return ret; } debug_print (1, "Writing zip to buffer..."); if (zip_close (pkg->zip)) { error_print ("Error while creating in memory zip: %s", zip_error_strerror (zip_get_error (pkg->zip))); return -1; } zip_source_stat (pkg->zip_source, &zstat); debug_print (1, "%" PRIu64 " B written to package", zstat.comp_size); zip_source_open (pkg->zip_source); content = g_byte_array_sized_new (zstat.comp_size); content->len = zstat.comp_size; zip_source_read (pkg->zip_source, content->data, zstat.comp_size); zip_source_close (pkg->zip_source); idata_init (out, content, NULL, NULL); return 0; } void package_free_package_resource (gpointer data) { struct package_resource *pkg_resource = data; g_byte_array_free (pkg_resource->data, TRUE); g_free (pkg_resource); } void package_destroy (struct package *pkg) { zip_source_free (pkg->zip_source); g_free (pkg->buff); g_free (pkg->name); g_free (pkg->fw_version); g_list_free_full (pkg->resources, package_free_package_resource); } gint package_open (struct package *pkg, struct idata *idata, const struct device_desc *device_desc) { gint err; zip_error_t zerror; zip_file_t *manifest_file; zip_stat_t zstat; GByteArray *data = idata->content; debug_print (1, "Opening zip stream..."); zip_error_init (&zerror); pkg->zip_source = zip_source_buffer_create (data->data, data->len, 0, &zerror); if (!pkg->zip_source) { error_print ("Error while creating zip source: %s", zip_error_strerror (&zerror)); zip_error_fini (&zerror); return -1; } pkg->zip = zip_open_from_source (pkg->zip_source, ZIP_RDONLY, &zerror); if (!pkg->zip) { error_print ("Error while creating in memory zip: %s", zip_error_strerror (&zerror)); zip_error_fini (&zerror); zip_source_free (pkg->zip_source); return -1; } err = zip_stat (pkg->zip, MANIFEST_FILENAME, ZIP_FL_ENC_STRICT, &zstat); if (err) { error_print ("Error while loading '%s': %s", MANIFEST_FILENAME, zip_error_strerror (&zerror)); zip_error_fini (&zerror); zip_source_free (pkg->zip_source); zip_close (pkg->zip); return -1; } pkg->manifest = g_malloc (sizeof (struct package_resource)); pkg->manifest->type = PKG_RES_TYPE_MANIFEST; pkg->manifest->data = g_byte_array_sized_new (zstat.size); pkg->manifest->path = strdup (MANIFEST_FILENAME); manifest_file = zip_fopen (pkg->zip, MANIFEST_FILENAME, 0); zip_fread (manifest_file, pkg->manifest->data->data, zstat.size); pkg->manifest->data->len = zstat.size; zip_fclose (manifest_file); pkg->resources = NULL; pkg->resources = g_list_append (pkg->resources, pkg->manifest); pkg->buff = NULL; pkg->name = NULL; pkg->fw_version = NULL; pkg->device_desc = device_desc; return 0; } void package_close (struct package *pkg) { zip_source_close (pkg->zip_source); package_destroy (pkg); } //This function is just used as the upper bound estimation. static gint package_get_max_sample_slots (struct backend *backend) { struct elektron_data *data = backend->data; // Slot 0 is never used. // Digitakt and similar devices have 128 slots. // Digitakt II has 8 banks (1024). return data->device_desc.id == ELEKTRON_DIGITAKT_II_ID ? 1023 : 127; } gint package_receive_pkg_resources (struct package *pkg, const gchar *payload_path, struct job_control *control, struct backend *backend, fs_remote_file_op download_data, enum package_type type) { gint ret, i, elements; JsonParser *parser; JsonReader *reader; gint64 hash, size; GError *error = NULL; gchar *sample_path, *metadata_path; struct package_resource *pkg_resource; GString *package_resource_path; struct idata metadata_file, payload_file, sample_file, file; struct elektron_data *data = backend->data; pkg->manifest->tags = NULL; job_control_reset (control, 1); //payload if ((type == PKG_FILE_TYPE_DATA_PROJECT && data->device_desc.id != ELEKTRON_ANALOG_RYTM_ID && data->device_desc.id != ELEKTRON_DIGITAKT_ID && data->device_desc.id != ELEKTRON_ANALOG_RYTM_MKII_ID && data->device_desc.id != ELEKTRON_MODEL_SAMPLES_ID && data->device_desc.id != ELEKTRON_DIGITAKT_II_ID) || type == PKG_FILE_TYPE_DATA_PRESET) { goto get_payload; } control->parts += 1 + package_get_max_sample_slots (backend); // ... plus metadata and sample slots. metadata_path = path_chain (PATH_INTERNAL, payload_path, FS_DATA_METADATA_FILE); debug_print (1, "Getting metadata from %s...", metadata_path); ret = download_data (backend, metadata_path, &metadata_file, control); if (ret) { debug_print (1, "Metadata file not available"); control->parts = 1; goto get_payload; } control->part++; parser = json_parser_new (); if (!json_parser_load_from_data (parser, (gchar *) metadata_file.content->data, metadata_file.content->len, &error)) { error_print ("Unable to parse stream: %s. Continuing...", error->message); g_clear_error (&error); control->parts = 2; goto cleanup_parser; } reader = json_reader_new (json_parser_get_root (parser)); if (!reader) { error_print ("Unable to read from parser. Continuing..."); control->parts = 2; goto cleanup_parser; } if (type == PKG_FILE_TYPE_DATA_SOUND) { pkg->manifest->tags = package_get_tags_from_snd_metadata_int (reader); } else { pkg->manifest->tags = NULL; } if (!json_reader_read_member (reader, MAN_TAG_SAMPLE_REFS)) { debug_print (1, "Member '%s' not found", MAN_TAG_SAMPLE_REFS); control->parts = 2; goto cleanup_reader; } if (!json_reader_is_array (reader)) { error_print ("Member '%s' is not an array. Continuing...", MAN_TAG_SAMPLE_REFS); control->parts = 2; goto cleanup_reader; } elements = json_reader_count_elements (reader); if (!elements) { debug_print (1, "No samples found"); control->parts = 2; goto cleanup_reader; } control->parts = 2 + elements; job_control_set_progress (control, 0.0); for (i = 0; i < elements; i++, control->part++) { if (!json_reader_read_element (reader, i)) { error_print ("Cannot read element %d. Continuing...", i); continue; } if (!json_reader_read_member (reader, MAN_TAG_HASH)) { error_print ("Cannot read member '%s'. Continuing...", MAN_TAG_HASH); continue; } hash = json_reader_get_int_value (reader); json_reader_end_element (reader); if (!json_reader_read_member (reader, MAN_TAG_SIZE)) { error_print ("Cannot read member '%s'. Continuing...", MAN_TAG_SIZE); continue; } size = json_reader_get_int_value (reader); json_reader_end_element (reader); json_reader_end_element (reader); sample_path = elektron_get_sample_path_from_hash_size (backend, hash, size); if (!sample_path) { debug_print (1, "Sample not found. Skipping..."); continue; } debug_print (1, "Hash: %" PRIu64 "; size: %" PRIu64 "; path: %s", hash, size, sample_path); debug_print (1, "Getting sample %s...", sample_path); if (elektron_download_sample_part (backend, sample_path, &sample_file, control)) { g_free (sample_path); error_print ("Error while downloading sample. Continuing..."); continue; } ret = sample_get_memfile_from_sample (&sample_file, &file, control, SF_FORMAT_WAV | SF_FORMAT_PCM_16); if (ret) { error_print ("Error while converting sample to wave file. Continuing..."); g_free (sample_path); continue; } pkg_resource = g_malloc (sizeof (struct package_resource)); pkg_resource->type = PKG_RES_TYPE_SAMPLE; pkg_resource->data = idata_steal (&file); pkg_resource->hash = hash; pkg_resource->size = size; package_resource_path = g_string_new (NULL); g_string_append_printf (package_resource_path, "%s%s.wav", PKG_TAG_SAMPLES, sample_path); pkg_resource->path = g_string_free (package_resource_path, FALSE); if (package_add_resource (pkg, pkg_resource, TRUE)) { package_free_package_resource (pkg_resource); error_print ("Error while packaging sample"); continue; } idata_free (&sample_file); } cleanup_reader: g_object_unref (reader); cleanup_parser: g_object_unref (parser); idata_free (&metadata_file); get_payload: debug_print (1, "Getting payload from %s...", payload_path); ret = download_data (backend, payload_path, &payload_file, control); if (ret) { error_print ("Error while downloading payload"); } else { pkg_resource = g_malloc (sizeof (struct package_resource)); pkg_resource->type = PKG_RES_TYPE_PAYLOAD; pkg_resource->data = idata_steal (&payload_file); pkg_resource->path = strdup (pkg->name); if (package_add_resource (pkg, pkg_resource, TRUE)) { package_free_package_resource (pkg_resource); ret = -1; } } return ret; } gint package_send_pkg_resources (struct package *pkg, const gchar *payload_path, struct job_control *control, struct backend *backend, fs_remote_file_op upload_data) { gint elements, i, ret = 0; const gchar *file_type, *sample_path; gchar *dev_sample_path; gint64 product_type; JsonParser *parser; JsonReader *reader; GError *error = NULL; zip_stat_t zstat; zip_error_t zerror; zip_file_t *zip_file; struct package_resource *pkg_resource; struct idata file, sample, sample_file; zip_error_init (&zerror); parser = json_parser_new (); if (!json_parser_load_from_data (parser, (gchar *) pkg->manifest->data->data, pkg->manifest->data->len, &error)) { error_print ("Unable to parse stream: %s", error->message); g_clear_error (&error); ret = -1; goto cleanup_parser; } reader = json_reader_new (json_parser_get_root (parser)); if (!reader) { ret = -1; goto cleanup_parser; } if (!json_reader_read_member (reader, PKG_TAG_PAYLOAD)) { error_print ("No '%s' found", PKG_TAG_PAYLOAD); ret = -1; goto cleanup_reader; } pkg->name = strdup (json_reader_get_string_value (reader)); json_reader_end_element (reader); if (zip_stat (pkg->zip, pkg->name, ZIP_FL_ENC_STRICT, &zstat)) { error_print ("Error while loading '%s': %s", MANIFEST_FILENAME, zip_error_strerror (&zerror)); zip_error_fini (&zerror); ret = -1; goto cleanup_reader; } pkg_resource = g_malloc (sizeof (struct package_resource)); pkg_resource->type = PKG_RES_TYPE_PAYLOAD; pkg_resource->data = g_byte_array_sized_new (zstat.size); pkg_resource->path = strdup (pkg->name); zip_file = zip_fopen (pkg->zip, pkg->name, 0); zip_fread (zip_file, pkg_resource->data->data, zstat.size); pkg_resource->data->len = zstat.size; zip_fclose (zip_file); pkg->resources = g_list_append (pkg->resources, pkg_resource); control->parts = 1 + package_get_max_sample_slots (backend); // main and sample slots control->part = 0; idata_init (&file, pkg_resource->data, NULL, NULL); ret = upload_data (backend, payload_path, &file, control); if (ret) { error_print ("Error while uploading payload to '%s'", payload_path); goto cleanup_reader; } control->part++; if (!json_reader_read_member (reader, PKG_TAG_FIRMWARE_VERSION)) { error_print ("No '%s' found", PKG_TAG_FIRMWARE_VERSION); ret = -1; goto cleanup_reader; } pkg->fw_version = strdup (json_reader_get_string_value (reader)); json_reader_end_element (reader); if (!json_reader_read_member (reader, PKG_TAG_FILE_TYPE)) { error_print ("No '%s' found", PKG_TAG_FILE_TYPE); ret = -1; goto cleanup_reader; } file_type = json_reader_get_string_value (reader); json_reader_end_element (reader); if (strcmp (file_type, PKG_VAL_FILE_TYPE_SND) == 0) { pkg->type = PKG_FILE_TYPE_DATA_SOUND; } else if (strcmp (file_type, PKG_VAL_FILE_TYPE_PRJ) == 0) { pkg->type = PKG_FILE_TYPE_DATA_PROJECT; } else if (strcmp (file_type, PKG_VAL_FILE_TYPE_PST) == 0) { pkg->type = PKG_FILE_TYPE_DATA_PRESET; } else { pkg->type = PKG_FILE_TYPE_NONE; debug_print (1, "Invalid '%s': %s", PKG_TAG_FILE_TYPE, file_type); } if (!json_reader_read_member (reader, PKG_TAG_PRODUCT_TYPE)) { error_print ("No '%s' found", PKG_TAG_PRODUCT_TYPE); ret = 0; goto cleanup_reader; } if (!json_reader_is_array (reader)) { error_print ("Member '%s' is not an array", PKG_TAG_PRODUCT_TYPE); ret = -1; goto cleanup_reader; } if (!json_reader_count_elements (reader)) { error_print ("No product types found"); ret = 0; goto cleanup_reader; } if (!json_reader_read_element (reader, 0)) { ret = -1; goto cleanup_reader; } product_type = atoi (json_reader_get_string_value (reader)); debug_print (1, "ProductType: %" PRId64 "", product_type); if (pkg->device_desc->id != product_type) { debug_print (1, "Incompatible product type. Continuing..."); } json_reader_end_element (reader); json_reader_end_element (reader); if (!json_reader_read_member (reader, PKG_TAG_SAMPLES)) { control->parts = 1; // Only payload and it's done. control->part = 0; job_control_set_progress (control, 1.0); goto cleanup_reader; } if (!json_reader_is_array (reader)) { error_print ("Member '%s' is not an array. Skipping samples...", PKG_TAG_SAMPLES); ret = -1; goto cleanup_reader; } //We are reusing the same sample_file. Let's be careful. idata_init (&sample_file, g_byte_array_sized_new (zstat.size), NULL, NULL); elements = json_reader_count_elements (reader); control->parts = elements + 1; control->part = 1; for (i = 0; i < elements; i++, control->part++) { struct sample_info sample_info_req, sample_info_src; sample_info_req.rate = ELEKTRON_SAMPLE_RATE; sample_info_req.channels = 0; //Automatic sample_info_req.format = SF_FORMAT_PCM_16; json_reader_read_element (reader, i); json_reader_read_member (reader, PKG_TAG_FILE_NAME); sample_path = json_reader_get_string_value (reader); json_reader_end_element (reader); json_reader_end_element (reader); debug_print (2, "Uploading %s...", sample_path); if (zip_stat (pkg->zip, sample_path, ZIP_FL_ENC_STRICT, &zstat)) { error_print ("Error while loading '%s': %s", MANIFEST_FILENAME, zip_error_strerror (&zerror)); zip_error_fini (&zerror); ret = -1; continue; } //We remove the "Samples" at the beggining of the full zip path... dev_sample_path = strdup (&sample_path[7]); //... And the extension. filename_remove_ext (dev_sample_path); sample_file.name = g_path_get_basename (dev_sample_path); g_byte_array_set_size (sample_file.content, zstat.size); zip_file = zip_fopen (pkg->zip, sample_path, 0); zip_fread (zip_file, sample_file.content->data, zstat.size); sample_file.content->len = zstat.size; zip_fclose (zip_file); if (sample_load_from_memfile (&sample_file, &sample, control, &sample_info_req, &sample_info_src)) { error_print ("Error while loading '%s': %s", sample_path, zip_error_strerror (&zerror)); } else { ret = elektron_upload_sample_part (backend, dev_sample_path, &sample, control); if (ret) { error_print ("Error while uploading sample to '%s'", &sample_path[7]); } pkg_resource = g_malloc (sizeof (struct package_resource)); pkg_resource->type = PKG_RES_TYPE_SAMPLE; pkg_resource->data = idata_steal (&sample); pkg_resource->path = strdup (sample_path); pkg->resources = g_list_append (pkg->resources, pkg_resource); } g_free (dev_sample_path); g_free (sample_file.name); sample_file.name = NULL; } idata_free (&sample_file); cleanup_reader: g_object_unref (reader); cleanup_parser: g_object_unref (parser); return ret; } elektroid-3.2.3/src/connectors/package.h000066400000000000000000000061661500236517400202250ustar00rootroot00000000000000/* * package.h * Copyright (C) 2021 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include "connector.h" #ifndef PACKAGE_H #define PACKAGE_H #define ELEKTRON_SAMPLE_RATE 48000 #define ELEKTRON_MAX_STORAGE 8 //Limited to 8 by guint8 type in t_get_storage_stats #define ELEKTRON_MAX_FS 32 //Limiter to 32 by guint32 id in fs_operations #define ELEKTRON_MAX_EXTENSIONS 32 #define FS_DATA_METADATA_EXT "metadata" #define FS_DATA_METADATA_FILE "." FS_DATA_METADATA_EXT enum package_resource_type { PKG_RES_TYPE_NONE, PKG_RES_TYPE_PAYLOAD, PKG_RES_TYPE_MANIFEST, PKG_RES_TYPE_SAMPLE }; struct package_resource { enum package_resource_type type; guint32 hash; guint32 size; gchar *path; GByteArray *data; GSList *tags; //Used for PKG_RES_TYPE_MANIFEST only }; enum package_type { PKG_FILE_TYPE_NONE, PKG_FILE_TYPE_DATA_SOUND, PKG_FILE_TYPE_DATA_PROJECT, PKG_FILE_TYPE_DATA_PRESET, //Analog Heat family (no tags) PKG_FILE_TYPE_RAW_PRESET }; struct fs_desc { gchar name[LABEL_MAX]; gchar *extensions[ELEKTRON_MAX_EXTENSIONS]; }; struct device_desc { guint32 id; gchar name[LABEL_MAX]; guint8 storage; guint fs_descs_len; struct fs_desc fs_descs[ELEKTRON_MAX_FS]; }; struct elektron_data { guint16 seq; struct device_desc device_desc; }; struct package { gchar *name; enum package_type type; gchar *fw_version; const struct device_desc *device_desc; gchar *buff; zip_source_t *zip_source; zip_t *zip; GList *resources; struct package_resource *manifest; }; GSList *package_get_tags_from_snd_metadata (GByteArray * metadata); gint package_begin (struct package *pkg, gchar * name, const gchar * fw_version, const struct device_desc *device_desc, enum package_type type); gint package_receive_pkg_resources (struct package *pkg, const gchar * payload_path, struct job_control *control, struct backend *backend, fs_remote_file_op download_data, enum package_type type); gint package_end (struct package *pkg, struct idata *idata); void package_destroy (struct package *pkg); gint package_open (struct package *pkg, struct idata *idata, const struct device_desc *device_desc); gint package_send_pkg_resources (struct package *pkg, const gchar * payload_path, struct job_control *control, struct backend *backend, fs_remote_file_op upload_data); void package_close (struct package *pkg); #endif elektroid-3.2.3/src/connectors/phatty.c000066400000000000000000000274211500236517400201330ustar00rootroot00000000000000/* * phatty.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "phatty.h" #include "common.h" #include "scala.h" #define PHATTY_ALPHABET " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz!#$%&()*?@" #define PHATTY_MAX_PRESETS 100 #define PHATTY_PROGRAM_SIZE 193 #define PHATTY_PRESET_TYPE_OFFSET 3 // 0x04 is panel; 0x05 is preset #define PHATTY_PRESET_ID_OFFSET 5 #define MOOG_NAME_LEN 13 #define PHATTY_PRESETS_DIR "/presets" #define PHATTY_PANEL "panel" #define PHATTY_PANEL_ID 0x100 #define PHATTY_MAX_SCALES 32 static const gchar *PHATTY_SCALE_EXTS[] = { "scl", NULL }; static const guint8 MOOG_ID[] = { 0x04 }; static const guint8 FAMILY_ID[] = { 0x0, 0x5 }; static const guint8 MODEL_ID[] = { 0x0, 0x1 }; static const guint8 PHATTY_REQUEST_PANEL[] = { 0xf0, 4, 5, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xf7 }; static const guint8 PHATTY_REQUEST_PRESET[] = { 0xf0, 4, 5, 6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xf7 }; struct phatty_iter_data { guint next; struct backend *backend; }; enum phatty_fs { FS_PHATTY_PRESET, FS_PHATTY_SCALE }; static gchar phatty_decode_char (guint8 *data, gint position) { gint index; gint k = (3 * (position / 2)) + 23; if (position % 2 == 0) { index = ((data[k] & 0x1) << 6) | (data[k + 1] & 0x3f); } else { index = ((data[k + 2] & 0x3) << 4) | ((data[k + 3] & 0x3c) >> 2); } if (index >= strlen (PHATTY_ALPHABET)) { return '?'; } else { return PHATTY_ALPHABET[index]; } } static void phatty_encode_char (guint8 *data, gchar c, gint position) { gchar *s = PHATTY_ALPHABET; gint k, index = 0; while (*s != 0 && *s != c) { s++; index++; } if (!*s) { index = 0; } // Code adapted from https://gitlab.com/jp-ma/phatty-editor/blob/master/libphatty/phatty-fmt.x k = (3 * (position / 2)) + 23; if (position % 2 == 0) { data[k] &= ~0x1; data[k] |= (index >> 6) & 0x01; data[k + 1] &= ~0x3f; data[k + 1] |= index & 0x3f; } else { data[k + 2] &= ~0x3; data[k + 2] |= (index >> 4) & 0x7; data[k + 3] &= ~0x3c; data[k + 3] |= (index & 0xf) << 2; } } void phatty_set_preset_name (guint8 *preset, const gchar *preset_name) { gint i; const gchar *c = preset_name; for (i = 0; i < strlen (preset_name); i++, c++) { phatty_encode_char (preset, *c, i); } for (; i < MOOG_NAME_LEN; i++, c++) { phatty_encode_char (preset, ' ', i); } } void phatty_get_preset_name (guint8 *preset, gchar *preset_name) { gchar *c = preset_name; for (gint i = 0; i < MOOG_NAME_LEN; i++, c++) { *c = phatty_decode_char (preset, i); } *c = 0; c--; for (gint i = MOOG_NAME_LEN; i > 0; i--, c--) { if (*c == ' ') { *c = 0; } else { break; } } } static gchar * phatty_get_download_path (struct backend *backend, const struct fs_operations *ops, const gchar *dst_dir, const gchar *src_path, struct idata *preset) { guint id = 0; if (common_slot_get_id_from_path (src_path, &id)) { return NULL; } guint digits = id == PHATTY_PANEL_ID ? 0 : 2; return common_slot_get_download_path (backend, ops, dst_dir, src_path, preset, digits); } static GByteArray * phatty_get_panel_dump_msg () { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (PHATTY_REQUEST_PANEL)); g_byte_array_append (tx_msg, PHATTY_REQUEST_PANEL, sizeof (PHATTY_REQUEST_PANEL)); return tx_msg; } static GByteArray * phatty_get_preset_dump_msg (guint8 id) { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (PHATTY_REQUEST_PRESET)); g_byte_array_append (tx_msg, PHATTY_REQUEST_PRESET, sizeof (PHATTY_REQUEST_PRESET)); tx_msg->data[PHATTY_PRESET_ID_OFFSET] = id; return tx_msg; } static gint phatty_next_root_dentry (struct item_iterator *iter) { guint *next = iter->data; if (*next == 0) { snprintf (iter->item.name, LABEL_MAX, "%s", "presets"); iter->item.id = 0x1000; iter->item.type = ITEM_TYPE_DIR; iter->item.size = -1; } else if (*next == 1) { snprintf (iter->item.name, LABEL_MAX, "%s", PHATTY_PANEL); iter->item.id = PHATTY_PANEL_ID; iter->item.type = ITEM_TYPE_FILE; iter->item.size = -1; } else { return -ENOENT; } (*next)++; return 0; } static gint phatty_next_preset_dentry (struct item_iterator *iter) { gchar preset_name[MOOG_NAME_LEN + 1]; GByteArray *tx_msg, *rx_msg; struct phatty_iter_data *data = iter->data; if (data->next >= PHATTY_MAX_PRESETS) { return -ENOENT; } tx_msg = phatty_get_preset_dump_msg (data->next); rx_msg = backend_tx_and_rx_sysex (data->backend, tx_msg, -1); if (!rx_msg) { return -EIO; } phatty_get_preset_name (rx_msg->data, preset_name); snprintf (iter->item.name, LABEL_MAX, "%s", preset_name); iter->item.id = data->next; iter->item.type = ITEM_TYPE_FILE; iter->item.size = PHATTY_PROGRAM_SIZE; (data->next)++; free_msg (rx_msg); return 0; } static gint phatty_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { gint err = 0; if (!strcmp (dir, "/")) { guint *id = g_malloc (sizeof (guint)); *id = 0; item_iterator_init (iter, dir, id, phatty_next_root_dentry, g_free); } else if (!strcmp (dir, PHATTY_PRESETS_DIR)) { struct phatty_iter_data *data = g_malloc (sizeof (struct phatty_iter_data)); data->next = 0; data->backend = backend; item_iterator_init (iter, dir, data, phatty_next_preset_dentry, g_free); } else { err = -ENOTDIR; } return err; } static gchar * phatty_get_id_as_slot (struct item *item, struct backend *backend) { gchar *slot = g_malloc (LABEL_MAX); snprintf (slot, LABEL_MAX, "%0*d", item->id == PHATTY_PANEL_ID ? 4 : 2, item->id); return slot; } static gint phatty_download (struct backend *backend, const gchar *path, struct idata *preset, struct job_control *control) { guint id; gint err = 0; gboolean panel; GByteArray *tx_msg, *rx_msg; gchar name[MOOG_NAME_LEN + 1]; err = common_slot_get_id_from_path (path, &id); if (err) { return err; } if (id == PHATTY_PANEL_ID) { tx_msg = phatty_get_panel_dump_msg (); panel = TRUE; } else { if (id >= PHATTY_MAX_PRESETS) { return -EINVAL; } tx_msg = phatty_get_preset_dump_msg (id); panel = FALSE; } err = common_data_tx_and_rx (backend, tx_msg, &rx_msg, control); if (err) { return err; } if (rx_msg->len != PHATTY_PROGRAM_SIZE) { err = -EINVAL; goto cleanup; } if (!panel) { phatty_get_preset_name (rx_msg->data, name); } idata_init (preset, rx_msg, strdup (panel ? PHATTY_PANEL : name), NULL); return 0; cleanup: free_msg (rx_msg); return err; } static gint phatty_upload (struct backend *backend, const gchar *path, struct idata *preset, struct job_control *control) { gint err; guint id; if (preset->content->len != PHATTY_PROGRAM_SIZE) { return -EINVAL; } err = common_slot_get_id_from_path (path, &id); if (err) { return err; } if (id == PHATTY_PANEL_ID) { preset->content->data[PHATTY_PRESET_TYPE_OFFSET] = 0x04; preset->content->data[PHATTY_PRESET_ID_OFFSET] = 0x01; } else { if (id >= PHATTY_MAX_PRESETS) { return -EINVAL; } preset->content->data[PHATTY_PRESET_TYPE_OFFSET] = 0x05; preset->content->data[PHATTY_PRESET_ID_OFFSET] = id; } return common_data_tx (backend, preset->content, control); } static gint phatty_rename (struct backend *backend, const gchar *src, const gchar *dst) { guint id; gint err; struct job_control control; struct sysex_transfer transfer; struct idata preset; debug_print (1, "Renaming preset..."); err = common_slot_get_id_from_path (src, &id); if (err) { return err; } //The control initialization is needed. control.active = TRUE; control.callback = NULL; g_mutex_init (&control.mutex); err = phatty_download (backend, src, &preset, &control); if (err) { goto end; } phatty_set_preset_name (preset.content->data, dst); transfer.raw = preset.content; err = backend_tx_sysex (backend, &transfer); idata_free (&preset); end: return err; } static const struct fs_operations FS_PHATTY_PRESET_OPERATIONS = { .id = FS_PHATTY_PRESET, .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SLOT_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "preset", .gui_name = "Presets", .gui_icon = FS_ICON_SND, .max_name_len = MOOG_NAME_LEN, .readdir = phatty_read_dir, .print_item = common_print_item, .rename = phatty_rename, .download = phatty_download, .upload = phatty_upload, .get_slot = phatty_get_id_as_slot, .load = file_load, .save = file_save, .get_exts = common_sysex_get_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = phatty_get_download_path, .select_item = common_midi_program_change }; static gint phatty_scale_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { struct common_simple_read_dir_data *data; if (strcmp (dir, "/")) { return -ENOTDIR; } data = g_malloc (sizeof (struct common_simple_read_dir_data)); data->next = 0; data->last = PHATTY_MAX_SCALES - 1; item_iterator_init (iter, dir, data, common_simple_next_dentry, g_free); return 0; } static gint phatty_scale_upload (struct backend *backend, const gchar *path, struct idata *scale, struct job_control *control) { guint id; GByteArray *input = scale->content; if (common_slot_get_id_from_path (path, &id)) { return -EINVAL; } input->data[5] = 0; //bank input->data[6] = id; //scale return common_data_tx (backend, input, control); } static const gchar ** phatty_scale_get_extensions () { return PHATTY_SCALE_EXTS; } static const struct fs_operations FS_PHATTY_SCALE_OPERATIONS = { .id = FS_PHATTY_SCALE, .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE, .name = "scale", .gui_name = "Scales", .gui_icon = FS_ICON_KEYS, .readdir = phatty_scale_read_dir, .print_item = common_print_item, .upload = phatty_scale_upload, .load = scl_load_2_byte_octave_tuning_msg_from_scala_file, .get_exts = phatty_scale_get_extensions, .get_upload_path = common_slot_get_upload_path }; static gint phatty_handshake (struct backend *backend) { if (memcmp (backend->midi_info.company, MOOG_ID, sizeof (MOOG_ID)) || memcmp (backend->midi_info.family, FAMILY_ID, sizeof (FAMILY_ID)) || memcmp (backend->midi_info.model, MODEL_ID, sizeof (MODEL_ID))) { return -ENODEV; } gslist_fill (&backend->fs_ops, &FS_PHATTY_PRESET_OPERATIONS, &FS_PHATTY_SCALE_OPERATIONS, NULL); snprintf (backend->name, LABEL_MAX, "Moog Little Phatty"); return 0; } const struct connector CONNECTOR_PHATTY = { .name = "phatty", .handshake = phatty_handshake, .standard = TRUE, .regex = ".*Phatty.*" }; elektroid-3.2.3/src/connectors/phatty.h000066400000000000000000000016041500236517400201330ustar00rootroot00000000000000/* * phatty.h * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef PHATTY_H #define PHATTY_H #include "connector.h" extern const struct connector CONNECTOR_PHATTY; #endif elektroid-3.2.3/src/connectors/scala.c000066400000000000000000000201661500236517400177040ustar00rootroot00000000000000/* * scala.h * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include "scala.h" #define SCALA_FILE_LINE_SEPARATOR "\x0d\x0a" #define SCALA_FILE_COMMENT_CHAR '!' #define SCALA_OCTAVE_NOTES 12 #define SCALA_MIDI_TUNING_NAME_LEN 16 #define SCALA_OCTAVE_STEP_SIZE .012207 #define SCALA_C0_FREQ 8.1758 #define SCALA_BULK_STEP_SIZE .0061 static const guint8 SCALA_MIDI_OCTAVE_TUNING_HEADER[] = { 0xf0, 0x7e, 0x7f, 8, 6, 0, 0 }; static const guint8 SCALA_MIDI_BULK_TUNING_HEADER[] = { 0xf0, 0x7e, 0x7f, 8, 1, 0 }; static gint scl_parser_get_pitch (gchar *line, gdouble *val) { gint err = 0; gdouble num, den; gboolean dot; gchar *c, *rem, *denrem; c = line; dot = FALSE; while (*c) { if (*c == '.') { dot = TRUE; break; } c++; } if (dot) { double cents = g_ascii_strtod (line, NULL); *val = exp (log (2) * cents / 1200); } else { num = g_ascii_strtoull (line, &rem, 10); if (num == 0 && !strcmp (line, rem)) { return -EINVAL; } if (*rem != '/') { return -EINVAL; } rem++; den = g_ascii_strtoull (rem, &denrem, 10); if (num == 0 && !strcmp (rem, denrem)) { return -EINVAL; } *val = num / (gdouble) den; } return err; } static gchar ** scl_parser_get_next_line (gchar **lines) { while (*lines && (*lines)[0] == SCALA_FILE_COMMENT_CHAR) { lines++; } return lines; } gint scl_init_scala_from_bytes (struct scala *scala, GByteArray *input) { gint err = 0; gchar **line, **lines, *rem; guint64 notes; if (!input->len) { return -EINVAL; } lines = g_strsplit ((gchar *) input->data, SCALA_FILE_LINE_SEPARATOR, -1); line = scl_parser_get_next_line (lines); if (!*line) { err = -EINVAL; goto end; } snprintf (scala->desc, SCALA_DESC_MAX_LEN, "%s", *line); debug_print (2, "Scala description: %s", scala->desc); line++; line = scl_parser_get_next_line (line); if (!*line) { err = -EINVAL; goto end; } scala->notes = g_ascii_strtoull (*line, &rem, 10); if (scala->notes < 0 || (!scala->notes && !strcmp (*line, rem)) || scala->notes > SCALA_NOTES_MAX) { err = -ERANGE; goto end; } debug_print (2, "Scala notes: %" G_GUINT64_FORMAT, scala->notes); notes = 0; for (gint i = 0; i < scala->notes; i++) { line++; line = scl_parser_get_next_line (line); if (!*line) { err = -EINVAL; goto end; } err = scl_parser_get_pitch (*line, &scala->pitches[i]); if (err) { goto end; } debug_print (2, "Scala pitch %d: %f", i, scala->pitches[i]); notes++; } if (scala->notes != notes) { err = -EINVAL; } end: g_strfreev (lines); return err; } static gdouble scala_get_cents_from_ratio (gdouble ratio) { return 1200.0 * log (ratio) / log (2); } static guint8 scl_get_nearest_note_below (gdouble f, gdouble *note_f) { gdouble next; guint8 n; *note_f = SCALA_C0_FREQ; for (n = 0; n < SCALA_MIDI_NOTES - 1; n++) { next = exp (log (2.0) * ((n + 1) / 12.0)) * SCALA_C0_FREQ; if (next - f > 0.00001) { return n; } *note_f = next; } return n; } static void scl_append_name_to_msg (struct scala *scala, GByteArray *msg) { guint len = strlen (scala->desc); if (len > SCALA_MIDI_TUNING_NAME_LEN) { len = SCALA_MIDI_TUNING_NAME_LEN; } g_byte_array_append (msg, (guint8 *) scala->desc, len); while (len < SCALA_MIDI_TUNING_NAME_LEN) { g_byte_array_append (msg, (guint8 *) " ", 1); len++; } } static guint8 scl_get_cksum (guint8 *b, gint len) { guint8 cksum = 0; for (gint i = 0; i < len; i++, b++) { cksum ^= *b; } cksum &= 0x7f; return cksum; } gint scl_load_2_byte_octave_tuning_msg_from_scala_file (const char *path, struct idata *idata, struct job_control *control) { gint err = 0; struct idata input; guint8 cksum, msb, lsb; struct scala scala; GByteArray *msg; err = file_load (path, &input, control); if (err) { return err; } err = scl_init_scala_from_bytes (&scala, input.content); if (err) { goto end; } if (scala.notes != SCALA_OCTAVE_NOTES) { err = -EINVAL; goto end; } msg = g_byte_array_new (); g_byte_array_append (msg, SCALA_MIDI_OCTAVE_TUNING_HEADER, sizeof (SCALA_MIDI_OCTAVE_TUNING_HEADER)); scl_append_name_to_msg (&scala, msg); for (guint8 i = 0; i < SCALA_OCTAVE_NOTES; i++) { double pitch, cents, diff; guint value; if (i == 0) { pitch = scala.pitches[SCALA_OCTAVE_NOTES - 1] / 2.0; } else { pitch = scala.pitches[i - 1]; } cents = scala_get_cents_from_ratio (pitch); diff = cents - i * 100.0; value = (diff + 100.0) / SCALA_OCTAVE_STEP_SIZE; msb = (value >> 7) & 0x7f; lsb = value & 0x7f; debug_print (2, "Note %d (pitch %.6f, cents %.2f, diff %.2f, value %d, MSB %02x, LSB %02x)...", i, pitch, cents, diff, value, msb, lsb); g_byte_array_append (msg, (guint8 *) & msb, 1); g_byte_array_append (msg, (guint8 *) & lsb, 1); } cksum = scl_get_cksum (&msg->data[1], 46); g_byte_array_append (msg, &cksum, 1); g_byte_array_append (msg, (guint8 *) "\xf7", 1); idata_init (idata, msg, NULL, NULL); end: idata_free (&input); return err; } gint scl_load_key_based_tuning_msg_from_scala_file (const char *path, struct idata *scale, struct job_control *control) { gint err = 0; guint8 cksum; struct idata input; GByteArray *msg; struct scala scala; guint8 note[SCALA_OCTAVE_NOTES]; guint8 msb[SCALA_OCTAVE_NOTES]; guint8 lsb[SCALA_OCTAVE_NOTES]; err = file_load (path, &input, control); if (err) { return err; } err = scl_init_scala_from_bytes (&scala, input.content); if (err) { goto end; } if (scala.notes != SCALA_OCTAVE_NOTES) { err = -EINVAL; goto end; } msg = g_byte_array_new (); g_byte_array_append (msg, SCALA_MIDI_BULK_TUNING_HEADER, sizeof (SCALA_MIDI_BULK_TUNING_HEADER)); scl_append_name_to_msg (&scala, msg); //Calculate pitches only for the first octave. for (guint8 i = 0; i < SCALA_OCTAVE_NOTES; i++) { double pitch, f, note_f, cents; guint value; if (i == 0) { pitch = scala.pitches[SCALA_OCTAVE_NOTES - 1] / 2.0; } else { pitch = scala.pitches[i - 1]; } f = pitch * SCALA_C0_FREQ; note[i] = scl_get_nearest_note_below (f, ¬e_f); cents = scala_get_cents_from_ratio (f / note_f); value = cents / SCALA_BULK_STEP_SIZE; msb[i] = (value >> 7) & 0x7f; lsb[i] = value & 0x7f; debug_print (2, "Note %d (pitch %.6f, note %d, cents %.2f, value %d, MSB %02x, LSB %02x)...", i, pitch, note[i], cents, value, msb[i], lsb[i]); } //Replicate pitches for all the notes. for (guint8 i = 0; i < 128; i++) { gint pos = i % SCALA_OCTAVE_NOTES; gint octave = i / SCALA_OCTAVE_NOTES; guint8 n = note[pos] + octave * SCALA_OCTAVE_NOTES; g_byte_array_append (msg, (guint8 *) & n, 1); g_byte_array_append (msg, (guint8 *) & msb[pos], 1); g_byte_array_append (msg, (guint8 *) & lsb[pos], 1); } cksum = scl_get_cksum (&msg->data[1], 405); g_byte_array_append (msg, &cksum, 1); g_byte_array_append (msg, (guint8 *) "\xf7", 1); idata_init (scale, msg, NULL, NULL); end: idata_free (&input); return err; } elektroid-3.2.3/src/connectors/scala.h000066400000000000000000000025411500236517400177060ustar00rootroot00000000000000/* * scala.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "utils.h" #define SCALA_DESC_MAX_LEN 1024 #define SCALA_NOTES_MAX 1024 #define SCALA_MIDI_NOTES 128 #define SCALA_TUNING_BANK_SIZE 408 #define SCALA_EXT "scl" struct scala { gchar desc[SCALA_DESC_MAX_LEN]; guint64 notes; gdouble pitches[SCALA_NOTES_MAX]; }; gint scl_load_2_byte_octave_tuning_msg_from_scala_file (const char *path, struct idata *idata, struct job_control *control); gint scl_load_key_based_tuning_msg_from_scala_file (const char *path, struct idata *idata, struct job_control *control); elektroid-3.2.3/src/connectors/sds.c000066400000000000000000001074171500236517400174170ustar00rootroot00000000000000/* * sds.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include #include "elektron.h" #include "sds.h" #include "default.h" #include "common.h" #define SDS_SAMPLE_LIMIT 1000 #define SDS_DATA_PACKET_LEN 127 #define SDS_DATA_PACKET_PAYLOAD_LEN 120 #define SDS_DATA_PACKET_CKSUM_POS 125 #define SDS_DATA_PACKET_CKSUM_START 1 #define SDS_BYTES_PER_WORD 3 #define SDS_MAX_RETRIES 5 #define SDS_SPEC_TIMEOUT 20 //Timeout in the specs to consider no response when transmission is going on. #define SDS_SPEC_TIMEOUT_HANDSHAKE 2000 //Timeout in the specs to consider no response during the handshake. #define SDS_NO_SPEC_TIMEOUT 5000 //Timeout used when the specs indicate to wait indefinitely. #define SDS_NO_SPEC_TIMEOUT_TRY 1500 //Timeout for SDS extensions that might not be implemented. #define SDS_REST_TIME_DEFAULT 50000 //Rest time to not overwhelm the devices when sending consecutive packets. Lower values cause an an E-Mu ESI-2000 to send corrupted packets.s #define SDS_INCOMPLETE_PACKET_TIMEOUT 2000 #define SDS_NO_SPEC_OPEN_LOOP_REST_TIME 200000 #define SDS_SAMPLE_CHANNELS 1 #define SDS_SAMPLE_NAME_MAX_LEN 127 struct sds_data { gint rest_time; gboolean name_extension; }; struct sds_iterator_data { guint32 next; struct backend *backend; }; static const guint8 SDS_SAMPLE_REQUEST[] = { 0xf0, 0x7e, 0, 0x3, 0, 0, 0xf7 }; static const guint8 SDS_ACK[] = { 0xf0, 0x7e, 0, 0x7f, 0, 0xf7 }; static const guint8 SDS_NAK[] = { 0xf0, 0x7e, 0, 0x7e, 0, 0xf7 }; static const guint8 SDS_CANCEL[] = { 0xf0, 0x7e, 0, 0x7d, 0, 0xf7 }; static const guint8 SDS_WAIT[] = { 0xf0, 0x7e, 0, 0x7c, 0, 0xf7 }; static const guint8 SDS_SAMPLE_NAME_REQUEST[] = { 0xf0, 0x7e, 0, 0x5, 0x4, 0, 0, 0xf7 }; static const guint8 SDS_DATA_PACKET_HEADER[] = { 0xf0, 0x7e, 0, 0x2, 0 }; static const guint8 SDS_SAMPLE_NAME_HEADER[] = { 0xf0, 0x7e, 0, 0x5, 0x3, 0, 0, 0 }; static const guint8 SDS_DUMP_HEADER[] = { 0xf0, 0x7e, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xf7 }; static const guint8 SDS_LOOP_POINT_REQUEST[] = { 0xf0, 0x7e, 0, 5, 2, 0, 0, 0, 0, 0xf7 }; static gchar * sds_get_sample_name (struct backend *backend, gint index) { GByteArray *tx_msg, *rx_msg; gchar *name = NULL; tx_msg = g_byte_array_sized_new (sizeof (SDS_SAMPLE_NAME_REQUEST)); g_byte_array_append (tx_msg, SDS_SAMPLE_NAME_REQUEST, sizeof (SDS_SAMPLE_NAME_REQUEST)); tx_msg->data[5] = index % 0x80; tx_msg->data[6] = index / 0x80; rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, SDS_NO_SPEC_TIMEOUT); if (rx_msg) { size_t n = rx_msg->data[9]; name = g_malloc (sizeof (gchar) * (SDS_SAMPLE_NAME_MAX_LEN + 1)); memcpy (name, (gchar *) & rx_msg->data[10], n); memset (name + n, 0, SDS_SAMPLE_NAME_MAX_LEN + 1 - n); free_msg (rx_msg); } return name; } static guint sds_get_bytes_value_right_just (guint8 *data, gint length) { gint value = 0; for (gint i = 0, shift = 0; i < length; i++, shift += 7) { value |= data[i] << shift; } return value; } static void sds_set_bytes_value_right_just (guint8 *data, gint length, guint value) { for (gint i = 0, shift = 0; i < length; i++, shift += 7) { *data = 0x7f & (value >> shift); data++; } } static gint16 sds_get_gint16_value_left_just (guint8 *data, gint length, guint bits) { guint value = 0; gint16 svalue; for (gint i = length - 1, shift = 0; i >= 0; i--, shift += 7) { value |= (((guint) data[i]) << shift); } value >>= length * 7 - bits; svalue = (gint16) (value - 0x8000); return svalue; } static void sds_set_gint16_value_left_just (guint8 *data, gint length, guint bits, gint16 svalue) { gint value = svalue; value += (guint) 0x8000; value <<= length * 7 - bits; for (gint i = length - 1, shift = 0; i >= 0; i--, shift += 7) { data[i] = (guint8) (0x7f & (value >> shift)); } } static guint8 sds_checksum (guint8 *data) { guint8 checksum = 0; for (int i = SDS_DATA_PACKET_CKSUM_START; i < SDS_DATA_PACKET_CKSUM_POS; i++) { checksum ^= data[i]; } checksum &= 0x7F; return checksum; } static gint sds_get_bytes_per_word (gint32 bits, guint *word_size, guint *bytes_per_word) { *word_size = (guint) ceil (bits / 8.0); if (*word_size != 2) { error_print ("%d bits resolution not supported", bits); return -1; } if (bits < 15) { *bytes_per_word = 2; } else { *bytes_per_word = 3; } return 0; } static gint sds_tx_handshake (struct backend *backend, const guint8 *msg, guint8 packet) { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (SDS_ACK)); g_byte_array_append (tx_msg, msg, sizeof (SDS_ACK)); tx_msg->data[4] = packet; return backend_tx (backend, tx_msg); } static guint sds_get_download_info (GByteArray *header, struct sample_info *sample_info, guint *bits, guint *words, guint *word_size, guint *bytes_per_word) { *bits = header->data[6]; if (*bits == 8) { sample_info->format = SF_FORMAT_WAV | SF_FORMAT_PCM_U8; } else { sample_info->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; } if (sds_get_bytes_per_word (*bits, word_size, bytes_per_word)) { return -1; } sample_info->rate = 1.0e9 / sds_get_bytes_value_right_just (&header->data[7], SDS_BYTES_PER_WORD); *words = sds_get_bytes_value_right_just (&header->data[10], SDS_BYTES_PER_WORD); sample_info->loop_start = sds_get_bytes_value_right_just (&header->data[13], SDS_BYTES_PER_WORD); sample_info->loop_end = sds_get_bytes_value_right_just (&header->data[16], SDS_BYTES_PER_WORD); sample_info->loop_type = header->data[19]; sample_info->midi_note = 0; sample_info->channels = 1; return 0; } static inline gboolean sds_check_message_id (GByteArray *msg, guint id) { return (msg->data[4] == id % 0x80 && msg->data[5] == id / 0x80); } static inline void sds_set_message_id (GByteArray *tx_msg, guint id) { tx_msg->data[4] = id % 0x80; tx_msg->data[5] = id / 0x80; } static GByteArray * sds_get_request_msg (guint id) { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (SDS_SAMPLE_REQUEST)); g_byte_array_append (tx_msg, SDS_SAMPLE_REQUEST, sizeof (SDS_SAMPLE_REQUEST)); sds_set_message_id (tx_msg, id); return tx_msg; } static GByteArray * sds_get_dump_msg (guint id, guint frames, struct sample_info *sample_info, guint bits) { guint period; GByteArray *tx_msg = g_byte_array_sized_new (sizeof (SDS_DUMP_HEADER)); g_byte_array_append (tx_msg, SDS_DUMP_HEADER, sizeof (SDS_DUMP_HEADER)); sds_set_message_id (tx_msg, id); if (sample_info) { tx_msg->data[6] = (guint8) bits; period = 1.0e9 / sample_info->rate; sds_set_bytes_value_right_just (&tx_msg->data[7], SDS_BYTES_PER_WORD, period); sds_set_bytes_value_right_just (&tx_msg->data[10], SDS_BYTES_PER_WORD, frames); sds_set_bytes_value_right_just (&tx_msg->data[13], SDS_BYTES_PER_WORD, sample_info->loop_start); sds_set_bytes_value_right_just (&tx_msg->data[16], SDS_BYTES_PER_WORD, sample_info->loop_end); tx_msg->data[19] = (sample_info->loop_start == sample_info->loop_end && sample_info->loop_start == frames - 1) ? 0x7f : sample_info->loop_type; } return tx_msg; } static GByteArray * sds_rx (struct backend *backend, gint timeout) { struct sysex_transfer transfer; transfer.timeout = timeout; transfer.batch = FALSE; g_mutex_lock (&backend->mutex); backend_rx_sysex (backend, &transfer); g_mutex_unlock (&backend->mutex); return transfer.raw; } static void sds_download_inc_packet (gboolean *first, guint *packet) { if (*first) { *first = FALSE; } else { (*packet)++; } } static void sds_debug_print_sample_data (guint bits, guint bytes_per_word, guint word_size, guint sample_rate, guint words, guint packets) { debug_print (1, "Resolution: %d bits; %d bytes per word; word size %d bytes.", bits, bytes_per_word, word_size); debug_print (1, "Sample rate: %d Hz", sample_rate); debug_print (1, "Words: %d", words); debug_print (1, "Packets: %d", packets); } static GByteArray * sds_download_get_header (struct backend *backend, guint id) { GByteArray *tx_msg, *rx_msg; tx_msg = sds_get_request_msg (id); g_byte_array_append (tx_msg, SDS_WAIT, sizeof (SDS_WAIT)); //We add a WAIT packet. tx_msg->data[11] = 0; rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, SDS_NO_SPEC_TIMEOUT); if (rx_msg && rx_msg->len == sizeof (SDS_DUMP_HEADER) && !memcmp (rx_msg->data, SDS_DUMP_HEADER, 4) && sds_check_message_id (rx_msg, id)) { return rx_msg; } debug_print (1, "Bad dump header"); return NULL; } static gint sds_download_try (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { guint id, words, word_size, read_bytes, bytes_per_word, total_words, err, retries, packets, packet, exp_packet, rx_packets, bits; gint16 s; GByteArray *tx_msg, *rx_msg; gchar *name, *basename; guint8 *dataptr; gboolean active, first; gboolean last_packet_ack; struct sample_info *sample_info; struct sysex_transfer transfer; struct sds_data *sds_data = backend->data; GByteArray *output = g_byte_array_new (); basename = g_path_get_basename (path); id = atoi (basename); g_free (basename); debug_print (1, "Sending dump request..."); packet = 0; retries = 0; while (1) { g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); if (!active) { err = -ECANCELED; goto end; } g_mutex_lock (&backend->mutex); backend_rx_drain (backend); g_mutex_unlock (&backend->mutex); rx_msg = sds_download_get_header (backend, id); if (rx_msg) { break; } retries++; if (retries == SDS_MAX_RETRIES) { err = -EIO; goto end; } } sample_info = g_malloc (sizeof (struct sample_info)); if (sds_get_download_info (rx_msg, sample_info, &bits, &words, &word_size, &bytes_per_word)) { free_msg (rx_msg); g_free (sample_info); err = -EINVAL; goto end; } packets = ceil (words / (double) (SDS_DATA_PACKET_PAYLOAD_LEN / bytes_per_word)); sds_debug_print_sample_data (bits, bytes_per_word, word_size, sample_info->rate, words, packets); g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); job_control_reset (control, 1); debug_print (1, "Receiving dump data..."); tx_msg = g_byte_array_new (); total_words = 0; retries = 0; last_packet_ack = TRUE; err = 0; exp_packet = 0; first = TRUE; rx_packets = 0; while (active && rx_packets <= packets) { if (retries == SDS_MAX_RETRIES) { debug_print (1, "Too many retries"); err = -EIO; break; } g_byte_array_set_size (tx_msg, 0); if (last_packet_ack) { g_byte_array_append (tx_msg, SDS_ACK, sizeof (SDS_ACK)); } else { g_byte_array_append (tx_msg, SDS_NAK, sizeof (SDS_NAK)); } tx_msg->data[4] = packet % 0x80; if (rx_packets == packets) { err = backend_tx (backend, tx_msg); goto end; } if (last_packet_ack) { sds_download_inc_packet (&first, &packet); } g_byte_array_append (tx_msg, SDS_WAIT, sizeof (SDS_WAIT)); tx_msg->data[10] = (packet) % 0x80; transfer.raw = tx_msg; transfer.timeout = SDS_INCOMPLETE_PACKET_TIMEOUT; //This is enough to detect incomplete packets. err = backend_tx_and_rx_sysex_transfer (backend, &transfer, FALSE); if (err == -ECANCELED) { break; } else if (err == -ETIMEDOUT) { debug_print (2, "Packet not received. Remaining packets: %d; remaining samples: %d", packets - rx_packets, words - total_words); //This is a hack to fix a downloading error with an E-Mu ESI-2000 as it never sends the last packet when there is only 1 sample. if ((rx_packets == packets - 1) && (total_words == words - 1)) { debug_print (2, "Skipping last packet as it has only one sample..."); rx_packets++; //We cancel the upload. usleep (sds_data->rest_time); sds_tx_handshake (backend, SDS_CANCEL, packet % 0x80); usleep (sds_data->rest_time); err = 0; goto end; } rx_msg = NULL; goto retry; } else { rx_msg = transfer.raw; } if (rx_msg->len != SDS_DATA_PACKET_LEN) { debug_print (2, "Invalid length"); goto retry; } guint exp_packet_id = exp_packet % 0x80; if (rx_msg->data[4] != exp_packet_id) { debug_print (2, "Invalid packet number (%d != %d)", rx_msg->data[4], exp_packet_id); goto retry; } if (sds_checksum (rx_msg->data) != rx_msg->data[SDS_DATA_PACKET_CKSUM_POS]) { debug_print (2, "Invalid cksum"); goto retry; } exp_packet++; rx_packets++; last_packet_ack = TRUE; retries = 0; read_bytes = 0; dataptr = &rx_msg->data[5]; while (read_bytes < SDS_DATA_PACKET_PAYLOAD_LEN && total_words < words) { s = sds_get_gint16_value_left_just (dataptr, bytes_per_word, bits); g_byte_array_append (output, (guint8 *) & s, sizeof (gint16)); dataptr += bytes_per_word; read_bytes += bytes_per_word; total_words++; } job_control_set_progress (control, rx_packets / (double) packets); g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); free_msg (rx_msg); continue; retry: debug_print (2, "Retrying packet..."); if (rx_msg) { free_msg (rx_msg); } last_packet_ack = FALSE; usleep (sds_data->rest_time); retries++; continue; } free_msg (tx_msg); end: if (active && !err && rx_packets == packets) { debug_print (1, "%d frames received", total_words); job_control_set_progress (control, 1.0); if (sds_data->name_extension) { name = sds_get_sample_name (backend, id); } else { name = g_malloc (LABEL_MAX); snprintf (name, LABEL_MAX, "%03d", id); } idata_init (sample, output, name, sample_info); } else { debug_print (1, "Cancelling SDS download..."); sds_tx_handshake (backend, SDS_CANCEL, packet % 0x80); g_byte_array_free (output, TRUE); } usleep (sds_data->rest_time); return err; } static gint sds_download (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { gint err; for (gint i = 0; i < SDS_MAX_RETRIES; i++) { err = sds_download_try (backend, path, sample, control); if (err == -EBADMSG) { //We retry the whole download to fix a downloading error with an E-Mu ESI-2000 as it occasionally doesn't send the last packet. debug_print (2, "Bug detected. Retrying download..."); } else { break; } } return err; } static gint sds_tx_and_wait_ack (struct backend *backend, GByteArray *tx_msg, guint packet, gint timeout, gint timeout2) { gint err; gint t; guint rx_packet; GByteArray *rx_msg; gboolean waiting = FALSE; rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, timeout); if (!rx_msg) { return -ETIMEDOUT; //Nothing was received } t = timeout2; while (1) { rx_packet = rx_msg->data[4]; rx_msg->data[4] = 0; if (!memcmp (rx_msg->data, SDS_WAIT, sizeof (SDS_WAIT)) && !waiting) { debug_print (2, "WAIT received. Waiting for an ACK..."); t = SDS_NO_SPEC_TIMEOUT; waiting = TRUE; } else if (!memcmp (rx_msg->data, SDS_ACK, sizeof (SDS_ACK))) { err = 0; break; } else if (!memcmp (rx_msg->data, SDS_NAK, sizeof (SDS_NAK))) { err = -EBADMSG; break; } else if (!memcmp (rx_msg->data, SDS_CANCEL, sizeof (SDS_CANCEL))) { err = -ECANCELED; break; } else if (rx_packet != packet) { err = -EINVAL; //Unexpected package number break; } else { err = -EIO; //Message received but unrecognized break; } free_msg (rx_msg); rx_msg = sds_rx (backend, t); if (!rx_msg) { return -ENOMSG; } } free_msg (rx_msg); return err; } static inline GByteArray * sds_get_data_packet_msg (gint packet, guint words, guint *word, gint16 **frame, guint bits, guint bytes_per_word) { guint8 *data; GByteArray *tx_msg = g_byte_array_sized_new (SDS_DATA_PACKET_LEN); g_byte_array_append (tx_msg, SDS_DATA_PACKET_HEADER, sizeof (SDS_DATA_PACKET_HEADER)); g_byte_array_set_size (tx_msg, SDS_DATA_PACKET_LEN); tx_msg->data[4] = packet; memset (&tx_msg->data[sizeof (SDS_DATA_PACKET_HEADER)], 0, SDS_DATA_PACKET_PAYLOAD_LEN); tx_msg->data[SDS_DATA_PACKET_LEN - 1] = 0xf7; data = &tx_msg->data[sizeof (SDS_DATA_PACKET_HEADER)]; for (guint i = 0; i < SDS_DATA_PACKET_PAYLOAD_LEN; i += bytes_per_word) { if (*word < words) { sds_set_gint16_value_left_just (data, bytes_per_word, bits, **frame); data += bytes_per_word; (*frame)++; (*word)++; } } tx_msg->data[SDS_DATA_PACKET_CKSUM_POS] = sds_checksum (tx_msg->data); return tx_msg; } static inline GByteArray * sds_get_rename_sample_msg (guint id, const gchar *name) { GByteArray *tx_msg; gchar *sanitized = common_get_sanitized_name (name, NULL, 0); size_t len = strlen (sanitized); guint8 total; len = len > SDS_SAMPLE_NAME_MAX_LEN ? SDS_SAMPLE_NAME_MAX_LEN : len; total = sizeof (SDS_SAMPLE_NAME_HEADER) + 2 + len; tx_msg = g_byte_array_sized_new (total); g_byte_array_append (tx_msg, SDS_SAMPLE_NAME_HEADER, sizeof (SDS_SAMPLE_NAME_HEADER)); tx_msg->data[5] = id % 0x80; tx_msg->data[6] = id / 0x80; g_byte_array_append (tx_msg, (guint8 *) & len, 1); g_byte_array_append (tx_msg, (guint8 *) sanitized, len); g_byte_array_append (tx_msg, (guint8 *) "\xf7", 1); g_free (sanitized); return tx_msg; } static gint sds_rename (struct backend *backend, const gchar *src, const gchar *dst) { GByteArray *tx_msg, *rx_msg; guint id; gint err; debug_print (1, "Sending rename request..."); err = common_slot_get_id_from_path (src, &id); if (err) { return err; } g_mutex_lock (&backend->mutex); backend_rx_drain (backend); g_mutex_unlock (&backend->mutex); tx_msg = sds_get_rename_sample_msg (id, dst); err = -ENOSYS; rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, SDS_NO_SPEC_TIMEOUT); if (rx_msg) { err = 0; free_msg (rx_msg); } return err; } static gint sds_upload (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control, guint bits) { GByteArray *tx_msg; gint16 *frame, *f; gboolean active, open_loop = FALSE; guint word, words, words_per_packet, id, packet = 0, packets, retries = 0, w, bytes_per_word; gint err = 0, word_size; struct sds_data *sds_data = backend->data; struct sample_info *sample_info = sample->info; GByteArray *input = sample->content; job_control_reset (control, 1); if (common_slot_get_id_from_path (path, &id)) { return -EINVAL; } g_mutex_lock (&backend->mutex); backend_rx_drain (backend); g_mutex_unlock (&backend->mutex); g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); debug_print (1, "Sending dump header..."); words = input->len >> 1; //bytes to words (frames) word_size = (gint) ceil (bits / 8.0); bytes_per_word = (gint) ceil (bits / 7.0); words_per_packet = SDS_DATA_PACKET_PAYLOAD_LEN / bytes_per_word; packets = ceil (words / (double) words_per_packet); tx_msg = sds_get_dump_msg (id, words, sample_info, bits); //The first timeout should be SDS_SPEC_TIMEOUT_HANDSHAKE (2 s) but it is not enough sometimes. err = sds_tx_and_wait_ack (backend, tx_msg, 0, SDS_NO_SPEC_TIMEOUT, SDS_NO_SPEC_TIMEOUT); if (err == -ENOMSG) { debug_print (2, "No packet received after a WAIT. Continuing..."); } else if (err == -ETIMEDOUT) { //In case of no response, we can assume an open loop. debug_print (1, "Assuming open loop..."); open_loop = TRUE; } else if (err) { return err; } debug_print (1, "Sending dump data..."); word = 0; sds_debug_print_sample_data (bits, bytes_per_word, word_size, sample_info->rate, words, packets); frame = (gint16 *) input->data; while (packet < packets && active) { if (retries) { usleep (sds_data->rest_time); } if (retries == SDS_MAX_RETRIES) { debug_print (1, "Too many retries"); break; } f = frame; w = word; tx_msg = sds_get_data_packet_msg (packet % 0x80, words, &w, &f, bits, bytes_per_word); if (open_loop) { err = backend_tx (backend, tx_msg); usleep (SDS_NO_SPEC_OPEN_LOOP_REST_TIME); } else { //SDS_SPEC_TIMEOUT is too low to be used here. err = sds_tx_and_wait_ack (backend, tx_msg, packet % 0x80, SDS_NO_SPEC_TIMEOUT, SDS_NO_SPEC_TIMEOUT); } if (err == -EBADMSG) { debug_print (2, "NAK received. Retrying..."); retries++; continue; } else if (err == -ENOMSG) { debug_print (2, "No packet received after a WAIT. Continuing..."); g_mutex_lock (&backend->mutex); backend_rx_drain (backend); g_mutex_unlock (&backend->mutex); } else if (err == -EINVAL) { debug_print (2, "Unexpected packet number. Retrying..."); retries++; continue; } else if (err == -ETIMEDOUT) { debug_print (2, "No response. Retrying..."); retries++; continue; } else if (err == -ECANCELED) { debug_print (2, "Cancelled by device. Stopping..."); goto end; } else if (err) { error_print ("Unhandled error"); goto end; } job_control_set_progress (control, packet / (gdouble) packets); g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); word = w; frame = f; packet++; retries = 0; err = 0; usleep (sds_data->rest_time); } if (active && sds_data->name_extension) { sds_rename (backend, path, sample->name); } end: if (active && packet == packets) { job_control_set_progress (control, 1.0); } else { debug_print (2, "Cancelling SDS upload..."); sds_tx_handshake (backend, SDS_CANCEL, packet % 0x80); err = -ECANCELED; } return err; } static gint sds_upload_8b (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { return sds_upload (backend, path, sample, control, 8); } static gint sds_upload_12b (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { return sds_upload (backend, path, sample, control, 12); } static gint sds_upload_14b (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { return sds_upload (backend, path, sample, control, 14); } static gint sds_upload_16b (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { return sds_upload (backend, path, sample, control, 16); } static gint sds_next_sample_dentry (struct item_iterator *iter) { struct sds_iterator_data *iterator_data = iter->data; struct sds_data *data = iterator_data->backend->data; if (iterator_data->next >= SDS_SAMPLE_LIMIT) { return -ENOENT; } iter->item.id = iterator_data->next; iter->item.type = ITEM_TYPE_FILE; iter->item.size = -1; (iterator_data->next)++; if (data->name_extension) { gchar *name = sds_get_sample_name (iterator_data->backend, iterator_data->next); snprintf (iter->item.name, LABEL_MAX, "%s", name ? name : ""); g_free (name); } else { iter->item.name[0] = 0; } return 0; } static gint sds_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { struct sds_iterator_data *data; if (strcmp (dir, "/")) { return -ENOTDIR; } data = g_malloc (sizeof (struct sds_iterator_data)); data->next = 0; data->backend = backend; item_iterator_init (iter, dir, data, sds_next_sample_dentry, g_free); return 0; } static gint sds_sample_load_common (const gchar *path, struct idata *sample, struct job_control *control, gint32 rate) { return common_sample_load (path, sample, control, rate, SDS_SAMPLE_CHANNELS, SF_FORMAT_PCM_16); } static gint sds_sample_load (const gchar *path, struct idata *sample, struct job_control *control) { return sds_sample_load_common (path, sample, control, 0); // Any sample rate is valid. } static gint sds_sample_load_441 (const gchar *path, struct idata *sample, struct job_control *control) { return sds_sample_load_common (path, sample, control, 44100); } static gint sds_sample_load_32 (const gchar *path, struct idata *sample, struct job_control *control) { return sds_sample_load_common (path, sample, control, 32000); } static gint sds_sample_load_16 (const gchar *path, struct idata *sample, struct job_control *control) { return sds_sample_load_common (path, sample, control, 16000); } static gint sds_sample_load_8 (const gchar *path, struct idata *sample, struct job_control *control) { return sds_sample_load_common (path, sample, control, 8000); } static gint sds_sample_save (const gchar *path, struct idata *sample, struct job_control *control) { return sample_save_to_file (path, sample, control, SF_FORMAT_WAV | SF_FORMAT_PCM_16); } enum sds_fs { FS_SAMPLES_SDS_16_B = 1, //SDS devices also include FS_PROGRAM_DEFAULT_OPERATIONS as the first filesystem. FS_SAMPLES_SDS_14_B, FS_SAMPLES_SDS_12_B, FS_SAMPLES_SDS_8_B, FS_SAMPLES_SDS_16_B_441, FS_SAMPLES_SDS_16_B_32, FS_SAMPLES_SDS_16_B_16, FS_SAMPLES_SDS_16_B_8 }; static const struct fs_operations FS_SAMPLES_SDS_8B_OPERATIONS = { .id = FS_SAMPLES_SDS_8_B, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_ID_COLUMN, .name = "8b1c", .gui_name = "8 bits mono", .gui_icon = FS_ICON_WAVE, .max_name_len = SDS_SAMPLE_NAME_MAX_LEN, .readdir = sds_read_dir, .print_item = common_print_item, .rename = sds_rename, .download = sds_download, .upload = sds_upload_8b, .load = sds_sample_load, .save = sds_sample_save, .get_exts = sample_get_sample_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_system_get_download_path }; static const struct fs_operations FS_SAMPLES_SDS_12B_OPERATIONS = { .id = FS_SAMPLES_SDS_12_B, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_ID_COLUMN, .name = "12b1c", .gui_name = "12 bits mono", .gui_icon = FS_ICON_WAVE, .max_name_len = SDS_SAMPLE_NAME_MAX_LEN, .readdir = sds_read_dir, .print_item = common_print_item, .rename = sds_rename, .download = sds_download, .upload = sds_upload_12b, .load = sds_sample_load, .save = sds_sample_save, .get_exts = sample_get_sample_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_system_get_download_path }; static const struct fs_operations FS_SAMPLES_SDS_14B_OPERATIONS = { .id = FS_SAMPLES_SDS_14_B, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_ID_COLUMN, .name = "14b1c", .gui_name = "14 bits mono", .gui_icon = FS_ICON_WAVE, .max_name_len = SDS_SAMPLE_NAME_MAX_LEN, .readdir = sds_read_dir, .print_item = common_print_item, .rename = sds_rename, .download = sds_download, .upload = sds_upload_14b, .load = sds_sample_load, .save = sds_sample_save, .get_exts = sample_get_sample_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_system_get_download_path }; static const struct fs_operations FS_SAMPLES_SDS_16B_OPERATIONS = { .id = FS_SAMPLES_SDS_16_B, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_ID_COLUMN, .name = "16b1c", .gui_name = "16 bits mono", .gui_icon = FS_ICON_WAVE, .max_name_len = SDS_SAMPLE_NAME_MAX_LEN, .readdir = sds_read_dir, .print_item = common_print_item, .rename = sds_rename, .download = sds_download, .upload = sds_upload_16b, .load = sds_sample_load, .save = sds_sample_save, .get_exts = sample_get_sample_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_system_get_download_path }; static const struct fs_operations FS_SAMPLES_SDS_16B_441_OPERATIONS = { .id = FS_SAMPLES_SDS_16_B_441, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_ID_COLUMN, .name = "44.1k16b1c", .gui_name = "44.1 KHz 16 bits mono", .gui_icon = FS_ICON_WAVE, .max_name_len = SDS_SAMPLE_NAME_MAX_LEN, .readdir = sds_read_dir, .print_item = common_print_item, .rename = sds_rename, .download = sds_download, .upload = sds_upload_16b, .load = sds_sample_load_441, .save = sds_sample_save, .get_exts = sample_get_sample_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_system_get_download_path }; static const struct fs_operations FS_SAMPLES_SDS_16B_32_OPERATIONS = { .id = FS_SAMPLES_SDS_16_B_32, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_ID_COLUMN, .name = "32k16b1c", .gui_name = "32 KHz 16 bits mono", .gui_icon = FS_ICON_WAVE, .max_name_len = SDS_SAMPLE_NAME_MAX_LEN, .readdir = sds_read_dir, .print_item = common_print_item, .rename = sds_rename, .download = sds_download, .upload = sds_upload_16b, .load = sds_sample_load_32, .save = sds_sample_save, .get_exts = sample_get_sample_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_system_get_download_path }; static const struct fs_operations FS_SAMPLES_SDS_16B_16_OPERATIONS = { .id = FS_SAMPLES_SDS_16_B_16, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_ID_COLUMN, .name = "16k16b1c", .gui_name = "16 KHz 16 bits mono", .gui_icon = FS_ICON_WAVE, .max_name_len = SDS_SAMPLE_NAME_MAX_LEN, .readdir = sds_read_dir, .print_item = common_print_item, .rename = sds_rename, .download = sds_download, .upload = sds_upload_16b, .load = sds_sample_load_16, .save = sds_sample_save, .get_exts = sample_get_sample_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_system_get_download_path }; static const struct fs_operations FS_SAMPLES_SDS_16B_8_OPERATIONS = { .id = FS_SAMPLES_SDS_16_B_8, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_ID_COLUMN, .name = "8k16b1c", .gui_name = "8 KHz 16 bits mono", .gui_icon = FS_ICON_WAVE, .max_name_len = SDS_SAMPLE_NAME_MAX_LEN, .readdir = sds_read_dir, .print_item = common_print_item, .rename = sds_rename, .download = sds_download, .upload = sds_upload_16b, .load = sds_sample_load_8, .save = sds_sample_save, .get_exts = sample_get_sample_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_system_get_download_path }; static gint sds_handshake_elektron (struct backend *backend) { //Elektron devices support SDS so we need to be sure it is not. GByteArray *rx_msg = elektron_ping (backend); if (rx_msg) { free_msg (rx_msg); //This is filled up by elektron_ping. g_free (backend->data); return -ENODEV; } g_mutex_lock (&backend->mutex); backend_rx_drain (backend); g_mutex_unlock (&backend->mutex); return 0; } gint sds_handshake_name (struct backend *backend) { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (SDS_SAMPLE_NAME_REQUEST)); g_byte_array_append (tx_msg, SDS_SAMPLE_NAME_REQUEST, sizeof (SDS_SAMPLE_NAME_REQUEST)); tx_msg->data[5] = 1; tx_msg->data[6] = 0; GByteArray *rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, SDS_NO_SPEC_TIMEOUT_TRY); if (rx_msg) { free_msg (rx_msg); return 0; } return -ENODEV; } gint sds_handshake_loop_point (struct backend *backend) { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (SDS_LOOP_POINT_REQUEST)); g_byte_array_append (tx_msg, SDS_LOOP_POINT_REQUEST, sizeof (SDS_LOOP_POINT_REQUEST)); tx_msg->data[5] = 1; tx_msg->data[6] = 0; tx_msg->data[7] = 1; tx_msg->data[8] = 0; GByteArray *rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, SDS_NO_SPEC_TIMEOUT_TRY); if (rx_msg) { free_msg (rx_msg); return 0; } return -ENODEV; } gint sds_handshake_esi_2000 (struct backend *backend) { //An upload to a real sample will erase the sample even if cancelled, so a sample id of a non existing slot is need. //We send a dump header for a number higher than every device might allow. Hopefully, this will fail on every device. //Numbers higher than 1500 make an E-Mu ESI-2000 crash when entering into the 'MIDI SAMPLE DUMP' menu but the actual limit is unknown. GByteArray *tx_msg = sds_get_dump_msg (1000, 0, NULL, 16); //In case we receive an ACK, NAK or CANCEL, there is a MIDI SDS device listening. gint err = sds_tx_and_wait_ack (backend, tx_msg, 0, SDS_SPEC_TIMEOUT_HANDSHAKE, SDS_NO_SPEC_TIMEOUT_TRY); if (err && err != -EBADMSG && err != -ECANCELED) { return -ENODEV; } //We cancel the upload. usleep (SDS_REST_TIME_DEFAULT); sds_tx_handshake (backend, SDS_CANCEL, 0); usleep (SDS_REST_TIME_DEFAULT); return 0; } gint sds_handshake (struct backend *backend) { gint err; gboolean name_extension; struct sds_data *sds_data; //We cancel anything that might be running. usleep (SDS_REST_TIME_DEFAULT); sds_tx_handshake (backend, SDS_CANCEL, 0); usleep (SDS_REST_TIME_DEFAULT); err = sds_handshake_elektron (backend); if (err) { return err; } err = sds_handshake_name (backend); if (err) { name_extension = FALSE; } else { name_extension = TRUE; goto end; } err = sds_handshake_loop_point (backend); if (!err) { goto end; } err = sds_handshake_esi_2000 (backend); if (err) { return err; } end: debug_print (1, "Name extension: %s", name_extension ? "yes" : "no"); //The remaining code is meant to set up different devices. These are the default values. sds_data = g_malloc (sizeof (struct sds_data)); sds_data->rest_time = SDS_REST_TIME_DEFAULT; sds_data->name_extension = name_extension; gslist_fill (&backend->fs_ops, &FS_PROGRAM_DEFAULT_OPERATIONS, &FS_SAMPLES_SDS_8B_OPERATIONS, &FS_SAMPLES_SDS_12B_OPERATIONS, &FS_SAMPLES_SDS_14B_OPERATIONS, &FS_SAMPLES_SDS_16B_OPERATIONS, &FS_SAMPLES_SDS_16B_441_OPERATIONS, &FS_SAMPLES_SDS_16B_32_OPERATIONS, &FS_SAMPLES_SDS_16B_16_OPERATIONS, &FS_SAMPLES_SDS_16B_8_OPERATIONS, NULL); backend->destroy_data = backend_destroy_data; backend->data = sds_data; if (!strlen (backend->name)) { snprintf (backend->name, LABEL_MAX, "%s", _("SDS sampler")); } return 0; } const struct connector CONNECTOR_SDS = { .name = "sds", .handshake = sds_handshake, .standard = FALSE, .regex = NULL }; elektroid-3.2.3/src/connectors/sds.h000066400000000000000000000015701500236517400174150ustar00rootroot00000000000000/* * sds.h * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef SDS_H #define SDS_H #include "connector.h" extern const struct connector CONNECTOR_SDS; #endif elektroid-3.2.3/src/connectors/summit.c000066400000000000000000000577271500236517400201540ustar00rootroot00000000000000/* * summit.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "summit.h" #include "common.h" #include "scala.h" #define SUMMIT_PATCHES_PER_BANK 128 #define SUMMIT_PATCH_NAME_LEN 16 #define SUMMIT_SINGLE_LEN 527 #define SUMMIT_MULTI_LEN 1039 #define SUMMIT_REST_TIME_US 10000 #define SUMMIT_MSG_BANK_POS 12 #define SUMMIT_MSG_PATCH_POS 13 #define SUMMIT_MAX_TUNINGS 17 // Tuning 0 is stored but can't be changed from the UI. #define SUMMIT_MAX_WAVETABLES 10 #define SUMMIT_WAVETABLE_NAME_LEN 7 //In the device there are 8 available characters in the wavetable names but the wavetable messages only contain the first 7 characters. #define SUMMIT_WAVETABLE_HEADER_LEN 23 #define SUMMIT_WAVETABLE_WAVE_LEN 531 #define SUMMIT_WAVETABLE_WAVES 5 #define SUMMIT_WAVETABLE_LEN (SUMMIT_WAVETABLE_HEADER_LEN + SUMMIT_WAVETABLE_WAVES * SUMMIT_WAVETABLE_WAVE_LEN) #define SUMMIT_WAVETABLE_ID_POS 14 #define SUMMIT_REQ_OP_POS 8 #define SUMMIT_GET_NAME_FROM_MSG(msg, type) (&msg->data[type == FS_SUMMIT_SINGLE_PATCH ? 0x10 : 0x19b]) #define SUMMIT_GET_BANK_ID_FROM_DIR(dir) ((guint8) dir[1] - 0x40) // Bank A is the bank 1. #define SUMMIT_ALPHABET " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}" #define SUMMIT_DEFAULT_CHAR '?' static const gchar *SUMMIT_TUNING_EXTS[] = { BE_SYSEX_EXT, SCALA_EXT, NULL }; static const guint8 NOVATION_ID[] = { 0x0, 0x20, 0x29 }; static const guint8 SUMMIT_ID[] = { 0x33, 1, 0, 0 }; static const guint8 SUMMIT_GENERIC_REQ[] = { 0xf0, 0, 0x20, 0x29, 0x01, 0x11, 0x01, 0x33, 0, 0, 0, 0, 0, 0, 0xf7 }; static const guint8 SUMMIT_BULK_TUNING_REQ[] = { 0xf0, 0x7e, 0x00, 0x08, 0x00, 0x00, 0xf7 }; enum summit_fs { FS_SUMMIT_SINGLE_PATCH, FS_SUMMIT_MULTI_PATCH, FS_SUMMIT_WAVETABLE, FS_SUMMIT_BULK_TUNING }; struct summit_bank_iterator_data { guint8 next; guint8 bank; enum summit_fs fs; struct backend *backend; }; struct summit_wavetable_iterator_data { guint next; struct backend *backend; }; static gint summit_set_patch_bank_and_id (GByteArray *msg, guint8 bank, guint8 id) { if (msg->len <= SUMMIT_MSG_PATCH_POS) { return -EINVAL; } msg->data[SUMMIT_MSG_BANK_POS] = bank; msg->data[SUMMIT_MSG_PATCH_POS] = id; return 0; } static GByteArray * summit_get_patch_dump_msg (gint bank, gint id, enum summit_fs fs) { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (SUMMIT_GENERIC_REQ)); g_byte_array_append (tx_msg, SUMMIT_GENERIC_REQ, sizeof (SUMMIT_GENERIC_REQ)); tx_msg->data[SUMMIT_REQ_OP_POS] = fs == FS_SUMMIT_SINGLE_PATCH ? 0x41 : 0x43; summit_set_patch_bank_and_id (tx_msg, bank, id); return tx_msg; } //This function truncates the name to the last useful char ignoring the trailing spaces. static void summit_truncate_name (gchar *c) { for (int i = SUMMIT_PATCH_NAME_LEN - 1; i >= 0; i--, c--) { if (*c == ' ') { *c = 0; } else { break; } } } static const gchar * summit_get_category_name (GByteArray *rx_msg) { switch (rx_msg->data[32]) { case 0: return "None"; case 1: return "Arp"; case 2: return "Bass"; case 3: return "Bell"; case 4: return "Classic"; case 5: return "DrumPerc"; case 6: return "Keyboard"; case 7: return "Lead"; case 8: return "Motion"; case 9: return "Pad"; case 10: return "Poly"; case 11: return "SFX"; case 12: return "String"; case 13: return "User 1"; case 14: return "User 2"; default: return ""; } } static gint summit_patch_next_dentry (struct item_iterator *iter) { GByteArray *tx_msg, *rx_msg; struct summit_bank_iterator_data *data = iter->data; if (data->next >= SUMMIT_PATCHES_PER_BANK) { return -ENOENT; } tx_msg = summit_get_patch_dump_msg (data->bank, data->next, data->fs); rx_msg = backend_tx_and_rx_sysex (data->backend, tx_msg, -1); if (!rx_msg) { return -EIO; } memcpy (iter->item.name, SUMMIT_GET_NAME_FROM_MSG (rx_msg, data->fs), SUMMIT_PATCH_NAME_LEN); iter->item.name[SUMMIT_PATCH_NAME_LEN] = 0; gchar *c = &iter->item.name[SUMMIT_PATCH_NAME_LEN - 1]; summit_truncate_name (c); if (data->fs == FS_SUMMIT_SINGLE_PATCH) { const gchar *category = summit_get_category_name (rx_msg); snprintf (iter->item.object_info, LABEL_MAX, "%s", category); } free_msg (rx_msg); iter->item.id = data->next; iter->item.type = ITEM_TYPE_FILE; iter->item.size = data->fs == FS_SUMMIT_SINGLE_PATCH ? SUMMIT_SINGLE_LEN : SUMMIT_MULTI_LEN; data->next++; usleep (SUMMIT_REST_TIME_US); return 0; } static gint summit_patch_next_dentry_root (struct item_iterator *iter) { guint *next = iter->data; if (*next < 4) { iter->item.id = 0x10000 + *next; //Unique id snprintf (iter->item.name, LABEL_MAX, "%c", 0x41 + iter->item.id); iter->item.type = ITEM_TYPE_DIR; iter->item.size = -1; iter->item.object_info[0] = 0; (*next)++; return 0; } return -ENOENT; } static gint summit_patch_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, enum summit_fs fs) { guint bank; if (!strcmp (dir, "/")) { guint *next = g_malloc (sizeof (guint)); *next = 0; item_iterator_init (iter, dir, next, summit_patch_next_dentry_root, g_free); return 0; } bank = SUMMIT_GET_BANK_ID_FROM_DIR (dir); if (strlen (dir) == 2 && bank >= 1 && bank <= 4) { struct summit_bank_iterator_data *data = g_malloc (sizeof (struct summit_bank_iterator_data)); data->next = 0; data->fs = fs; data->bank = bank; data->backend = backend; item_iterator_init (iter, dir, data, summit_patch_next_dentry, g_free); return 0; } return -ENOTDIR; } static gint summit_single_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { return summit_patch_read_dir (backend, iter, dir, FS_SUMMIT_SINGLE_PATCH); } static gint summit_multi_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *path, const gchar **extensions) { return summit_patch_read_dir (backend, iter, path, FS_SUMMIT_MULTI_PATCH); } static guint summit_get_bank_and_id_from_path (const gchar *path, guint8 *bank, guint8 *id) { if (strlen (path) < 4) { return -EINVAL; } *bank = SUMMIT_GET_BANK_ID_FROM_DIR (path); *id = (guint8) atoi (&path[3]); if (*bank < 1 || *bank > 4 || *id >= SUMMIT_PATCHES_PER_BANK) { return -EINVAL; } return 0; } static gint summit_patch_download (struct backend *backend, const gchar *path, struct idata *patch, struct job_control *control, enum summit_fs fs) { guint8 id, bank; gint len, err; GByteArray *tx_msg, *rx_msg; gchar name[SUMMIT_PATCH_NAME_LEN + 1]; err = summit_get_bank_and_id_from_path (path, &bank, &id); if (err) { goto end; } tx_msg = summit_get_patch_dump_msg (bank, id, fs); err = common_data_tx_and_rx (backend, tx_msg, &rx_msg, control); if (err) { goto end; } len = (fs == FS_SUMMIT_SINGLE_PATCH ? SUMMIT_SINGLE_LEN : SUMMIT_MULTI_LEN); if (rx_msg->len != len) { err = -EINVAL; goto cleanup; } memcpy (name, SUMMIT_GET_NAME_FROM_MSG (rx_msg, fs), SUMMIT_PATCH_NAME_LEN); name[SUMMIT_PATCH_NAME_LEN] = 0; summit_truncate_name (&name[SUMMIT_PATCH_NAME_LEN - 1]); idata_init (patch, rx_msg, strdup (name), NULL); goto end; cleanup: free_msg (rx_msg); end: usleep (SUMMIT_REST_TIME_US); return err; } static gint summit_single_download (struct backend *backend, const gchar *path, struct idata *patch, struct job_control *control) { return summit_patch_download (backend, path, patch, control, FS_SUMMIT_SINGLE_PATCH); } static gint summit_multi_download (struct backend *backend, const gchar *path, struct idata *patch, struct job_control *control) { return summit_patch_download (backend, path, patch, control, FS_SUMMIT_MULTI_PATCH); } static gint summit_patch_upload (struct backend *backend, const gchar *path, GByteArray *input, struct job_control *control) { guint8 id, bank; gint err; GByteArray *msg; err = summit_get_bank_and_id_from_path (path, &bank, &id); if (err) { goto end; } msg = g_byte_array_sized_new (input->len); g_byte_array_append (msg, input->data, input->len); err = summit_set_patch_bank_and_id (msg, bank, id); if (err) { goto cleanup; } err = common_data_tx (backend, msg, control); cleanup: free_msg (msg); end: usleep (SUMMIT_REST_TIME_US); return err; } static gint summit_single_upload (struct backend *backend, const gchar *path, struct idata *patch, struct job_control *control) { if (patch->content->len != SUMMIT_SINGLE_LEN) { return -EINVAL; } return summit_patch_upload (backend, path, patch->content, control); } static gint summit_multi_upload (struct backend *backend, const gchar *path, struct idata *patch, struct job_control *control) { if (patch->content->len != SUMMIT_MULTI_LEN) { return -EINVAL; } return summit_patch_upload (backend, path, patch->content, control); } static gint summit_patch_rename (struct backend *backend, const gchar *src, const gchar *dst, enum summit_fs fs) { struct idata preset; GByteArray *rx_msg; gint err, len; guint8 *name; gchar *sanitized; struct job_control control; debug_print (1, "Renaming from %s to %s...", src, dst); //The control initialization is needed. control.active = TRUE; control.callback = NULL; g_mutex_init (&control.mutex); err = summit_patch_download (backend, src, &preset, &control, fs); if (err) { return err; } usleep (SUMMIT_REST_TIME_US); name = SUMMIT_GET_NAME_FROM_MSG (preset.content, fs); sanitized = common_get_sanitized_name (dst, SUMMIT_ALPHABET, SUMMIT_DEFAULT_CHAR); len = strlen (sanitized); len = len > SUMMIT_PATCH_NAME_LEN ? SUMMIT_PATCH_NAME_LEN : len; memcpy (name, sanitized, len); g_free (sanitized); memset (name + len, ' ', SUMMIT_PATCH_NAME_LEN - len); rx_msg = backend_tx_and_rx_sysex (backend, preset.content, 100); //There must be no response. if (rx_msg) { err = -EIO; free_msg (rx_msg); } usleep (SUMMIT_REST_TIME_US); return err; } static gint summit_single_rename (struct backend *backend, const gchar *src, const gchar *dst) { return summit_patch_rename (backend, src, dst, FS_SUMMIT_SINGLE_PATCH); } static gint summit_multi_rename (struct backend *backend, const gchar *src, const gchar *dst) { return summit_patch_rename (backend, src, dst, FS_SUMMIT_MULTI_PATCH); } static gchar * summit_get_id_as_slot (struct item *item, struct backend *backend, gint digits) { gchar *slot = g_malloc (LABEL_MAX); if (item->id < BE_MAX_MIDI_PROGRAMS) { snprintf (slot, LABEL_MAX, "%.*d", digits, item->id); } else { slot[0] = 0; } return slot; } static gchar * summit_get_patch_id_as_slot (struct item *item, struct backend *backend) { return summit_get_id_as_slot (item, backend, 3); } static void summit_common_patch_change (struct backend *backend, guint8 type, const gchar *dir, struct item *item) { guint8 msg[3]; if (!strcmp (dir, "/")) { return; } //This seems to be broken on firmware 2.1 as documented in https://forum.electra.one/t/preset-novation-summit-peak/1424/24 //Single o multi backend_tx_raw (backend, (guint8 *) "\xb0\x63\x3e", 3); backend_tx_raw (backend, (guint8 *) "\xb0\x62\x00", 3); memcpy (msg, "\xb0\x06", 2); msg[2] = type; backend_tx_raw (backend, msg, 3); //Bank memcpy (msg, "\xb0\x20", 2); msg[2] = SUMMIT_GET_BANK_ID_FROM_DIR (dir); backend_tx_raw (backend, msg, 3); //Patch common_midi_program_change (backend, dir, item); } static void summit_single_patch_change (struct backend *backend, const gchar *dir, struct item *item) { summit_common_patch_change (backend, 0, dir, item); } static void summit_multi_patch_change (struct backend *backend, const gchar *dir, struct item *item) { summit_common_patch_change (backend, 1, dir, item); } static const struct fs_operations FS_SUMMIT_SINGLE_OPERATIONS = { .id = FS_SUMMIT_SINGLE_PATCH, .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SLOT_COLUMN | FS_OPTION_SHOW_INFO_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "single", .gui_name = "Single", .gui_icon = FS_ICON_SND, .max_name_len = SUMMIT_PATCH_NAME_LEN, .readdir = summit_single_read_dir, .print_item = common_print_item, .rename = summit_single_rename, .download = summit_single_download, .upload = summit_single_upload, .get_slot = summit_get_patch_id_as_slot, .load = file_load, .save = file_save, .get_exts = common_sysex_get_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_slot_get_download_path_nnn, .select_item = summit_single_patch_change }; static const struct fs_operations FS_SUMMIT_MULTI_OPERATIONS = { .id = FS_SUMMIT_MULTI_PATCH, .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SLOT_COLUMN | FS_OPTION_ALLOW_SEARCH, .name = "multi", .gui_name = "Multi", .gui_icon = FS_ICON_SND, .max_name_len = SUMMIT_PATCH_NAME_LEN, .readdir = summit_multi_read_dir, .print_item = common_print_item, .rename = summit_multi_rename, .download = summit_multi_download, .upload = summit_multi_upload, .get_slot = summit_get_patch_id_as_slot, .load = file_load, .save = file_save, .get_exts = common_sysex_get_extensions, .get_upload_path = common_slot_get_upload_path, .get_download_path = common_slot_get_download_path_nnn, .select_item = summit_multi_patch_change }; static gint summit_tuning_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { struct common_simple_read_dir_data *data; if (strcmp (dir, "/")) { return -ENOTDIR; } data = g_malloc (sizeof (struct common_simple_read_dir_data)); data->next = 0; data->last = SUMMIT_MAX_TUNINGS - 1; item_iterator_init (iter, dir, data, common_simple_next_dentry, g_free); return 0; } static gint summit_tuning_upload (struct backend *backend, const gchar *path, struct idata *tuning, struct job_control *control) { guint id; GByteArray *input = tuning->content; if (common_slot_get_id_from_path (path, &id)) { return -EINVAL; } if (id >= SUMMIT_MAX_TUNINGS) { return -EINVAL; } if (input->len != SCALA_TUNING_BANK_SIZE) { return -EINVAL; } input->data[2] = 0; //0x7f does not work with the Summit. input->data[5] = id; //tuning return common_data_tx (backend, input, control); } static gint summit_tuning_download (struct backend *backend, const gchar *path, struct idata *tuning, struct job_control *control) { guint32 id; gint err = 0; GByteArray *tx_msg, *rx_msg; if (common_slot_get_id_from_path (path, &id)) { return -EINVAL; } if (id >= SUMMIT_MAX_TUNINGS) { return -EINVAL; } tx_msg = g_byte_array_sized_new (16); g_byte_array_append (tx_msg, SUMMIT_BULK_TUNING_REQ, sizeof (SUMMIT_BULK_TUNING_REQ)); tx_msg->data[5] = id; err = common_data_tx_and_rx (backend, tx_msg, &rx_msg, control); if (err) { goto end; } if (rx_msg->len != SCALA_TUNING_BANK_SIZE) { err = -EINVAL; goto cleanup; } idata_init (tuning, rx_msg, NULL, NULL); goto end; cleanup: free_msg (rx_msg); end: usleep (SUMMIT_REST_TIME_US); return err; } static gint summit_tuning_load (const gchar *path, struct idata *tuning, struct job_control *control) { gint err; gchar *filename = g_path_get_basename (path); if (strcmp (filename_get_ext (filename), SCALA_EXT)) { err = file_load (path, tuning, control); } else { err = scl_load_key_based_tuning_msg_from_scala_file (path, tuning, control); } g_free (filename); return err; } static const gchar ** summit_tuning_get_extensions () { return SUMMIT_TUNING_EXTS; } static const struct fs_operations FS_SUMMIT_BULK_TUNING_OPERATIONS = { .id = FS_SUMMIT_BULK_TUNING, .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE, .name = "tuning", .gui_name = "Tuning Tables", .gui_icon = FS_ICON_KEYS, .readdir = summit_tuning_read_dir, .print_item = common_print_item, .download = summit_tuning_download, .upload = summit_tuning_upload, .load = summit_tuning_load, .save = file_save, .get_exts = summit_tuning_get_extensions, .get_download_path = common_slot_get_download_path_nn, .get_upload_path = common_slot_get_upload_path }; static GByteArray * summit_get_wavetable_header_dump_msg (guint8 id) { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (SUMMIT_GENERIC_REQ)); g_byte_array_append (tx_msg, SUMMIT_GENERIC_REQ, sizeof (SUMMIT_GENERIC_REQ)); tx_msg->data[SUMMIT_REQ_OP_POS] = 0x47; tx_msg->data[11] = id; return tx_msg; } static GByteArray * summit_get_wavetable_wave_dump_msg (guint id, guint8 wave) { GByteArray *tx_msg = g_byte_array_sized_new (sizeof (SUMMIT_GENERIC_REQ)); g_byte_array_append (tx_msg, SUMMIT_GENERIC_REQ, sizeof (SUMMIT_GENERIC_REQ)); tx_msg->data[SUMMIT_REQ_OP_POS] = 0x46; tx_msg->data[11] = id; tx_msg->data[12] = wave; return tx_msg; } static gint summit_wavetable_next_dentry (struct item_iterator *iter) { GByteArray *tx_msg, *rx_msg; struct summit_bank_iterator_data *data = iter->data; if (data->next >= SUMMIT_MAX_WAVETABLES) { return -ENOENT; } tx_msg = summit_get_wavetable_header_dump_msg (data->next + 64); rx_msg = backend_tx_and_rx_sysex (data->backend, tx_msg, -1); if (!rx_msg) { return -EIO; } memcpy (iter->item.name, &rx_msg->data[15], SUMMIT_WAVETABLE_NAME_LEN); iter->item.name[SUMMIT_WAVETABLE_NAME_LEN] = 0; gchar *c = &iter->item.name[SUMMIT_WAVETABLE_NAME_LEN - 1]; summit_truncate_name (c); free_msg (rx_msg); iter->item.id = data->next; iter->item.type = ITEM_TYPE_FILE; iter->item.size = 2678; data->next++; usleep (SUMMIT_REST_TIME_US * 10); return 0; } static gint summit_wavetable_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { if (!strcmp (dir, "/")) { struct summit_wavetable_iterator_data *data = g_malloc (sizeof (struct summit_wavetable_iterator_data)); data->next = 0; data->backend = backend; item_iterator_init (iter, dir, data, summit_wavetable_next_dentry, g_free); return 0; } return -ENOTDIR; } static gint summit_wavetable_download (struct backend *backend, const gchar *path, struct idata *wavetable, struct job_control *control) { guint32 id; gint err = 0; gchar name[SUMMIT_PATCH_NAME_LEN + 1]; GByteArray *tx_msg, *rx_msg, *output; if (common_slot_get_id_from_path (path, &id)) { return -EINVAL; } if (id >= SUMMIT_MAX_WAVETABLES) { return -EINVAL; } job_control_reset (control, 6); output = g_byte_array_new (); //Header tx_msg = summit_get_wavetable_header_dump_msg (id + 64); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { return err; } if (rx_msg->len != SUMMIT_WAVETABLE_HEADER_LEN) { err = -EINVAL; goto err; } rx_msg->data[SUMMIT_WAVETABLE_ID_POS] = id; g_byte_array_append (output, rx_msg->data, rx_msg->len); free_msg (rx_msg); usleep (SUMMIT_REST_TIME_US); //Waves for (gint8 i = 0; i < SUMMIT_WAVETABLE_WAVES; i++) { tx_msg = summit_get_wavetable_wave_dump_msg (id, i); err = common_data_tx_and_rx_part (backend, tx_msg, &rx_msg, control); if (err) { goto err; } if (rx_msg->len != SUMMIT_WAVETABLE_WAVE_LEN) { err = -EINVAL; goto err; } g_byte_array_append (output, rx_msg->data, rx_msg->len); free_msg (rx_msg); usleep (SUMMIT_REST_TIME_US); } memcpy (name, &output->data[15], SUMMIT_WAVETABLE_NAME_LEN); name[SUMMIT_WAVETABLE_NAME_LEN] = 0; summit_truncate_name (&name[SUMMIT_WAVETABLE_NAME_LEN - 1]); idata_init (wavetable, output, strdup (name), NULL); goto end; err: g_byte_array_free (output, TRUE); free_msg (rx_msg); end: usleep (SUMMIT_REST_TIME_US); return err; } static gint summit_wavetable_upload (struct backend *backend, const gchar *path, struct idata *wavetable, struct job_control *control) { guint id; GByteArray *input = wavetable->content; if (common_slot_get_id_from_path (path, &id)) { return -EINVAL; } if (id >= SUMMIT_MAX_WAVETABLES) { return -EINVAL; } if (input->len != SUMMIT_WAVETABLE_LEN) { return -EINVAL; } //Header input->data[SUMMIT_WAVETABLE_ID_POS] = id; //Waves for (gint8 i = 0; i < SUMMIT_WAVETABLE_WAVES; i++) { input->data[SUMMIT_WAVETABLE_HEADER_LEN + i * SUMMIT_WAVETABLE_WAVE_LEN + SUMMIT_WAVETABLE_ID_POS] = id; } return common_data_tx (backend, input, control); } static gint summit_wavetable_rename (struct backend *backend, const gchar *src, const gchar *dst) { GByteArray *tx_msg; guint id, len; gchar *sanitized; if (common_slot_get_id_from_path (src, &id)) { return -EINVAL; } if (id >= SUMMIT_MAX_WAVETABLES) { return -EINVAL; } debug_print (1, "Renaming from %s to %s...", src, dst); tx_msg = g_byte_array_sized_new (23); g_byte_array_append (tx_msg, SUMMIT_GENERIC_REQ, sizeof (SUMMIT_GENERIC_REQ)); tx_msg->data[SUMMIT_REQ_OP_POS] = 0x7; tx_msg->data[14] = id; g_byte_array_append (tx_msg, (guint8 *) " \xf7", 8); sanitized = common_get_sanitized_name (dst, SUMMIT_ALPHABET, SUMMIT_DEFAULT_CHAR); len = strlen (sanitized); len = len > SUMMIT_WAVETABLE_NAME_LEN ? SUMMIT_WAVETABLE_NAME_LEN : len; memcpy (&tx_msg->data[15], sanitized, len); g_free (sanitized); return backend_tx (backend, tx_msg); } static const struct fs_operations FS_SUMMIT_WAVETABLE_OPERATIONS = { .id = FS_SUMMIT_WAVETABLE, .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE | FS_OPTION_SHOW_ID_COLUMN | FS_OPTION_SHOW_SIZE_COLUMN, .name = "wavetable", .gui_name = "Wavetables", .gui_icon = FS_ICON_WAVETABLE, .max_name_len = SUMMIT_WAVETABLE_NAME_LEN, .readdir = summit_wavetable_read_dir, .print_item = common_print_item, .rename = summit_wavetable_rename, .download = summit_wavetable_download, .upload = summit_wavetable_upload, .load = file_load, .save = file_save, .get_exts = common_sysex_get_extensions, .get_download_path = common_slot_get_download_path_n, .get_upload_path = common_slot_get_upload_path }; static gint summit_handshake (struct backend *backend) { if (memcmp (backend->midi_info.company, NOVATION_ID, sizeof (NOVATION_ID)) || memcmp (backend->midi_info.family, SUMMIT_ID, sizeof (SUMMIT_ID))) { return -ENODEV; } gslist_fill (&backend->fs_ops, &FS_SUMMIT_SINGLE_OPERATIONS, &FS_SUMMIT_MULTI_OPERATIONS, &FS_SUMMIT_WAVETABLE_OPERATIONS, &FS_SUMMIT_BULK_TUNING_OPERATIONS, NULL); snprintf (backend->name, LABEL_MAX, "Novation Summit"); return 0; } const struct connector CONNECTOR_SUMMIT = { .handshake = summit_handshake, .name = "summit", .standard = TRUE, .regex = ".*(Peak|Summit).*" }; elektroid-3.2.3/src/connectors/summit.h000066400000000000000000000016001500236517400201340ustar00rootroot00000000000000/* * summit.h * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef PEAK_H #define PEAK_H #include "connector.h" extern const struct connector CONNECTOR_SUMMIT; #endif elektroid-3.2.3/src/connectors/system.c000066400000000000000000000453701500236517400201510ustar00rootroot00000000000000/* * system.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include #if defined(__linux__) #include #include #endif #include "local.h" #include "sample.h" #include "connectors/common.h" struct system_iterator_data { GDir *dir; const gchar **extensions; }; static gint system_download (struct backend *backend, const gchar *path, struct idata *idata, struct job_control *control) { gint err; job_control_reset (control, 1); err = file_load (path, idata, control); if (!err) { job_control_set_progress (control, 1.0); } return err; } gint system_mkdir (struct backend *backend, const gchar *name) { gint res = g_mkdir_with_parents (name, 0755); if (res == 0 || errno == EEXIST) { res = 0; } else { error_print ("Error while creating dir %s", name); res = -errno; } return res; } gint system_delete (struct backend *backend, const gchar *path) { GDir *dir; gchar *new_path; if ((dir = g_dir_open (path, 0, NULL))) { debug_print (1, "Deleting local %s dir...", path); const gchar *name; while ((name = g_dir_read_name (dir)) != NULL) { new_path = path_chain (PATH_SYSTEM, path, name); system_delete (backend, new_path); g_free (new_path); } g_dir_close (dir); return rmdir (path); } else { debug_print (1, "Deleting local %s file...", path); return g_unlink (path); } } gint system_rename (struct backend *backend, const gchar *old, const gchar *new) { debug_print (1, "Renaming locally from %s to %s...", old, new); return rename (old, new); } static void system_free_iterator_data (void *iter_data) { struct system_iterator_data *data = iter_data; g_dir_close (data->dir); g_free (data); } static gint system_next_dentry (struct item_iterator *iter, gboolean sample_info) { gchar *full_path; const gchar *name; struct stat st; struct system_iterator_data *data = iter->data; while ((name = g_dir_read_name (data->dir)) != NULL) { if (name[0] == '.') { continue; } full_path = path_chain (PATH_SYSTEM, iter->dir, name); enum item_type type; if (g_file_test (full_path, G_FILE_TEST_IS_DIR)) { type = ITEM_TYPE_DIR; } else if (g_file_test (full_path, G_FILE_TEST_IS_REGULAR)) { type = ITEM_TYPE_FILE; } else { error_print ("'%s' is neither file nor directory", full_path); continue; } if (!stat (full_path, &st)) { snprintf (iter->item.name, LABEL_MAX, "%s", name); iter->item.type = type; iter->item.size = st.st_size; iter->item.id = -1; if (item_iterator_is_dir_or_matches_extensions (iter, data->extensions)) { if (iter->item.type == ITEM_TYPE_FILE && sample_info) { sample_load_sample_info (full_path, &iter->item.sample_info); } g_free (full_path); return 0; } } g_free (full_path); } return -ENOENT; } static gint system_next_dentry_without_sample_info (struct item_iterator *iter) { return system_next_dentry (iter, FALSE); } static gint system_next_dentry_with_sample_info (struct item_iterator *iter) { return system_next_dentry (iter, TRUE); } static gint system_read_dir_opts (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions, iterator_next next) { GDir *gdir; struct system_iterator_data *data; if (!(gdir = g_dir_open (dir, 0, NULL))) { return -errno; } data = g_malloc (sizeof (struct system_iterator_data)); data->dir = gdir; data->extensions = extensions; item_iterator_init (iter, dir, data, next, system_free_iterator_data); return 0; } gint system_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { return system_read_dir_opts (backend, iter, dir, extensions, system_next_dentry_without_sample_info); } gint system_samples_read_dir (struct backend *backend, struct item_iterator *iter, const gchar *dir, const gchar **extensions) { return system_read_dir_opts (backend, iter, dir, extensions, system_next_dentry_with_sample_info); } static gint system_load_custom (const gchar *path, struct idata *sample, struct job_control *control, const struct sample_info *sample_info_req) { struct sample_info sample_info_src; //Typically, control parts are set not here but in this case makes more sense. control->parts = 1; control->part = 0; return sample_load_from_file (path, sample, control, sample_info_req, &sample_info_src); } static gint system_load_48_16_stereo (const gchar *path, struct idata *sample, struct job_control *control) { struct sample_info sample_info_dst; sample_info_dst.rate = 48000; sample_info_dst.channels = 2; sample_info_dst.format = SF_FORMAT_PCM_16; return system_load_custom (path, sample, control, &sample_info_dst); } gint system_upload (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { //Typically, control parts are set here but in this case makes more sense do it in the load functions. return sample_save_to_file (path, sample, control, SF_FORMAT_WAV | SF_FORMAT_PCM_16); } static gint system_load_48_16_mono (const gchar *path, struct idata *sample, struct job_control *control) { struct sample_info sample_info_dst; sample_info_dst.rate = 48000; sample_info_dst.channels = 1; sample_info_dst.format = SF_FORMAT_PCM_16; return system_load_custom (path, sample, control, &sample_info_dst); } static gint system_load_441_16_stereo (const gchar *path, struct idata *sample, struct job_control *control) { struct sample_info sample_info_dst; sample_info_dst.rate = 44100; sample_info_dst.channels = 2; sample_info_dst.format = SF_FORMAT_PCM_16; return system_load_custom (path, sample, control, &sample_info_dst); } static gint system_load_441_16_mono (const gchar *path, struct idata *sample, struct job_control *control) { struct sample_info sample_info_dst; sample_info_dst.rate = 44100; sample_info_dst.channels = 1; sample_info_dst.format = SF_FORMAT_PCM_16; return system_load_custom (path, sample, control, &sample_info_dst); } static gint system_load_441_24_stereo (const gchar *path, struct idata *sample, struct job_control *control) { struct sample_info sample_info_dst; sample_info_dst.rate = 44100; sample_info_dst.channels = 2; sample_info_dst.format = SF_FORMAT_PCM_32; return system_load_custom (path, sample, control, &sample_info_dst); } static gint system_upload_24_bits (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { return sample_save_to_file (path, sample, control, SF_FORMAT_WAV | SF_FORMAT_PCM_24); } static gint system_load_441_24_mono (const gchar *path, struct idata *sample, struct job_control *control) { struct sample_info sample_info_dst; sample_info_dst.rate = 44100; sample_info_dst.channels = 1; sample_info_dst.format = SF_FORMAT_PCM_32; return system_load_custom (path, sample, control, &sample_info_dst); } static gint system_load_441_8_stereo (const gchar *path, struct idata *sample, struct job_control *control) { struct sample_info sample_info_dst; sample_info_dst.rate = 44100; sample_info_dst.channels = 2; sample_info_dst.format = SF_FORMAT_PCM_16; return system_load_custom (path, sample, control, &sample_info_dst); } static gint system_upload_8_bits (struct backend *backend, const gchar *path, struct idata *sample, struct job_control *control) { return sample_save_to_file (path, sample, control, SF_FORMAT_WAV | SF_FORMAT_PCM_U8); } static gint system_load_441_8_mono (const gchar *path, struct idata *sample, struct job_control *control) { struct sample_info sample_info_dst; sample_info_dst.rate = 44100; sample_info_dst.channels = 1; sample_info_dst.format = SF_FORMAT_PCM_16; return system_load_custom (path, sample, control, &sample_info_dst); } static gint system_load_32_16_mono (const gchar *path, struct idata *sample, struct job_control *control) { struct sample_info sample_info_dst; sample_info_dst.rate = 32000; sample_info_dst.channels = 1; sample_info_dst.format = SF_FORMAT_PCM_16; return system_load_custom (path, sample, control, &sample_info_dst); } gboolean system_file_exists (struct backend *backend, const gchar *path) { return access (path, F_OK) == 0; } enum system_fs { FS_SAMPLES_LOCAL_48_16_STEREO, FS_SAMPLES_LOCAL_48_16_MONO, FS_SAMPLES_LOCAL_441_16_STEREO, FS_SAMPLES_LOCAL_441_16_MONO, FS_SAMPLES_LOCAL_441_24_STEREO, FS_SAMPLES_LOCAL_441_24_MONO, FS_SAMPLES_LOCAL_441_8_STEREO, FS_SAMPLES_LOCAL_441_8_MONO, FS_SAMPLES_LOCAL_32_16_MONO }; const struct fs_operations FS_SYSTEM_SAMPLES_48_16_STEREO_OPERATIONS = { .id = FS_SAMPLES_LOCAL_48_16_STEREO, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_STEREO | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SAMPLE_COLUMNS | FS_OPTION_ALLOW_SEARCH, .name = "wav48k16b2c", .gui_name = "WAV 48 KHz 16 bits stereo", .gui_icon = FS_ICON_WAVE, .readdir = system_samples_read_dir, .print_item = common_print_item, .file_exists = system_file_exists, .mkdir = system_mkdir, .delete = system_delete, .rename = system_rename, .move = system_rename, .download = system_download, .upload = system_upload, .load = system_load_48_16_stereo, .save = file_save, .get_upload_path = common_system_get_upload_path, .get_download_path = common_system_get_download_path, .get_exts = sample_get_sample_extensions, .max_name_len = 255 }; const struct fs_operations FS_SYSTEM_SAMPLES_48_16_MONO_OPERATIONS = { .id = FS_SAMPLES_LOCAL_48_16_MONO, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SAMPLE_COLUMNS | FS_OPTION_ALLOW_SEARCH, .name = "wav48k16b1c", .gui_name = "WAV 48 KHz 16 bits mono", .gui_icon = FS_ICON_WAVE, .readdir = system_samples_read_dir, .print_item = common_print_item, .file_exists = system_file_exists, .mkdir = system_mkdir, .delete = system_delete, .rename = system_rename, .move = system_rename, .download = system_download, .upload = system_upload, .load = system_load_48_16_mono, .save = file_save, .get_upload_path = common_system_get_upload_path, .get_download_path = common_system_get_download_path, .get_exts = sample_get_sample_extensions, .max_name_len = 255 }; const struct fs_operations FS_SYSTEM_SAMPLES_441_16_STEREO_OPERATIONS = { .id = FS_SAMPLES_LOCAL_441_16_STEREO, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_STEREO | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SAMPLE_COLUMNS | FS_OPTION_ALLOW_SEARCH, .name = "wav44.1k16b2c", .gui_name = "WAV 44.1 KHz 16 bits stereo", .gui_icon = FS_ICON_WAVE, .readdir = system_samples_read_dir, .print_item = common_print_item, .file_exists = system_file_exists, .mkdir = system_mkdir, .delete = system_delete, .rename = system_rename, .move = system_rename, .download = system_download, .upload = system_upload, .load = system_load_441_16_stereo, .save = file_save, .get_upload_path = common_system_get_upload_path, .get_download_path = common_system_get_download_path, .get_exts = sample_get_sample_extensions, .max_name_len = 255 }; const struct fs_operations FS_SYSTEM_SAMPLES_441_16_MONO_OPERATIONS = { .id = FS_SAMPLES_LOCAL_441_16_MONO, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SAMPLE_COLUMNS | FS_OPTION_ALLOW_SEARCH, .name = "wav44.1k16b1c", .gui_name = "WAV 44.1 KHz 16 bits mono", .gui_icon = FS_ICON_WAVE, .readdir = system_samples_read_dir, .print_item = common_print_item, .file_exists = system_file_exists, .mkdir = system_mkdir, .delete = system_delete, .rename = system_rename, .move = system_rename, .copy = NULL, .clear = NULL, .swap = NULL, .download = system_download, .upload = system_upload, .load = system_load_441_16_mono, .save = file_save, .get_upload_path = common_system_get_upload_path, .get_download_path = common_system_get_download_path, .get_exts = sample_get_sample_extensions, .max_name_len = 255 }; const struct fs_operations FS_SYSTEM_SAMPLES_441_24_STEREO_OPERATIONS = { .id = FS_SAMPLES_LOCAL_441_24_STEREO, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_STEREO | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SAMPLE_COLUMNS | FS_OPTION_ALLOW_SEARCH, .name = "wav44.1k24b2c", .gui_name = "WAV 44.1 KHz 24 bits stereo", .gui_icon = FS_ICON_WAVE, .readdir = system_samples_read_dir, .file_exists = system_file_exists, .mkdir = system_mkdir, .delete = system_delete, .rename = system_rename, .move = system_rename, .download = system_download, .upload = system_upload_24_bits, .load = system_load_441_24_stereo, .save = file_save, .get_upload_path = common_system_get_upload_path, .get_download_path = common_system_get_download_path, .get_exts = sample_get_sample_extensions, .max_name_len = 255 }; const struct fs_operations FS_SYSTEM_SAMPLES_441_24_MONO_OPERATIONS = { .id = FS_SAMPLES_LOCAL_441_24_MONO, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SAMPLE_COLUMNS | FS_OPTION_ALLOW_SEARCH, .name = "wav44.1k24b1c", .gui_name = "WAV 44.1 KHz 24 bits mono", .gui_icon = FS_ICON_WAVE, .readdir = system_samples_read_dir, .file_exists = system_file_exists, .mkdir = system_mkdir, .delete = system_delete, .rename = system_rename, .move = system_rename, .copy = NULL, .clear = NULL, .swap = NULL, .download = system_download, .upload = system_upload_24_bits, .load = system_load_441_24_mono, .save = file_save, .get_upload_path = common_system_get_upload_path, .get_download_path = common_system_get_download_path, .get_exts = sample_get_sample_extensions, .max_name_len = 255 }; const struct fs_operations FS_SYSTEM_SAMPLES_441_8_STEREO_OPERATIONS = { .id = FS_SAMPLES_LOCAL_441_8_STEREO, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_STEREO | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SAMPLE_COLUMNS | FS_OPTION_ALLOW_SEARCH, .name = "wav44.1k8b2c", .gui_name = "WAV 44.1 KHz 8 bits stereo", .gui_icon = FS_ICON_WAVE, .readdir = system_samples_read_dir, .file_exists = system_file_exists, .mkdir = system_mkdir, .delete = system_delete, .rename = system_rename, .move = system_rename, .download = system_download, .upload = system_upload_8_bits, .load = system_load_441_8_stereo, .save = file_save, .get_upload_path = common_system_get_upload_path, .get_download_path = common_system_get_download_path, .get_exts = sample_get_sample_extensions, .max_name_len = 255 }; const struct fs_operations FS_SYSTEM_SAMPLES_441_8_MONO_OPERATIONS = { .id = FS_SAMPLES_LOCAL_441_8_MONO, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SAMPLE_COLUMNS | FS_OPTION_ALLOW_SEARCH, .name = "wav44.1k8b1c", .gui_name = "WAV 44.1 KHz 8 bits mono", .gui_icon = FS_ICON_WAVE, .readdir = system_samples_read_dir, .file_exists = system_file_exists, .mkdir = system_mkdir, .delete = system_delete, .rename = system_rename, .move = system_rename, .copy = NULL, .clear = NULL, .swap = NULL, .download = system_download, .upload = system_upload_8_bits, .load = system_load_441_8_mono, .save = file_save, .get_upload_path = common_system_get_upload_path, .get_download_path = common_system_get_download_path, .get_exts = sample_get_sample_extensions, .max_name_len = 255 }; const struct fs_operations FS_SYSTEM_SAMPLES_32_16_MONO_OPERATIONS = { .id = FS_SAMPLES_LOCAL_32_16_MONO, .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_SHOW_SIZE_COLUMN | FS_OPTION_SHOW_SAMPLE_COLUMNS | FS_OPTION_ALLOW_SEARCH, .name = "wav32k8b1c", .gui_name = "WAV 32 KHz 16 bits mono", .gui_icon = FS_ICON_WAVE, .readdir = system_samples_read_dir, .file_exists = system_file_exists, .mkdir = system_mkdir, .delete = system_delete, .rename = system_rename, .move = system_rename, .copy = NULL, .clear = NULL, .swap = NULL, .download = system_download, .upload = system_upload, .load = system_load_32_16_mono, .save = file_save, .get_upload_path = common_system_get_upload_path, .get_download_path = common_system_get_download_path, .get_exts = sample_get_sample_extensions, .max_name_len = 255 }; #if defined (__linux__) static gint system_get_storage_stats (struct backend *backend, guint8 type, struct backend_storage_stats *statfs, const gchar *path) { gint err; FILE *f; struct statvfs svfs; struct stat s1, s2; struct mntent *me; if ((err = stat (path, &s1)) < 0) { return err; } f = setmntent ("/proc/mounts", "r"); if (f == NULL) { return -ENODEV; } while ((me = getmntent (f))) { if (!stat (me->mnt_dir, &s2)) { if (s1.st_dev == s2.st_dev) { break; } } } endmntent (f); err = statvfs (path, &svfs); if (!err) { snprintf (statfs->name, LABEL_MAX, "%s", me->mnt_fsname); statfs->bfree = svfs.f_bavail * svfs.f_frsize; statfs->bsize = svfs.f_blocks * svfs.f_frsize; } return err; } #endif static gint system_handshake (struct backend *backend) { gslist_fill (&backend->fs_ops, &FS_SYSTEM_SAMPLES_48_16_STEREO_OPERATIONS, &FS_SYSTEM_SAMPLES_48_16_MONO_OPERATIONS, &FS_SYSTEM_SAMPLES_441_16_STEREO_OPERATIONS, &FS_SYSTEM_SAMPLES_441_16_MONO_OPERATIONS, &FS_SYSTEM_SAMPLES_441_24_STEREO_OPERATIONS, &FS_SYSTEM_SAMPLES_441_24_MONO_OPERATIONS, &FS_SYSTEM_SAMPLES_441_8_STEREO_OPERATIONS, &FS_SYSTEM_SAMPLES_441_8_MONO_OPERATIONS, &FS_SYSTEM_SAMPLES_32_16_MONO_OPERATIONS, NULL); snprintf (backend->name, LABEL_MAX, "%s", _("System")); backend->get_storage_stats = #if defined (__linux__) system_get_storage_stats; #else NULL; #endif return 0; } const struct connector CONNECTOR_SYSTEM = { .handshake = system_handshake, .name = "system", .standard = FALSE, .regex = NULL }; elektroid-3.2.3/src/connectors/system.h000066400000000000000000000027231500236517400201510ustar00rootroot00000000000000/* * system.h * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "connector.h" #include "sample.h" extern struct connector CONNECTOR_SYSTEM; gint system_read_dir (struct backend *backend, struct item_iterator *iter, const gchar * dir, const gchar ** extensions); gint system_samples_read_dir (struct backend *backend, struct item_iterator *iter, const gchar * dir, const gchar ** extensions); gboolean system_file_exists (struct backend *, const gchar *); gint system_mkdir (struct backend *, const gchar *); gint system_delete (struct backend *, const gchar *); gint system_rename (struct backend *, const gchar *, const gchar *); gint system_upload (struct backend *, const gchar *, GByteArray *, struct job_control *); elektroid-3.2.3/src/editor.c000066400000000000000000001262211500236517400157310ustar00rootroot00000000000000/* * editor.c * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include #include #include "editor.h" #include "sample.h" #include "connectors/system.h" #define EDITOR_LOOP_MARKER_WIDTH 7 #define EDITOR_LOOP_MARKER_HALF_HEIGHT 4 #define EDITOR_LOOP_MARKER_FULL_HEIGHT (EDITOR_LOOP_MARKER_HALF_HEIGHT * 2) #if defined(__linux__) #define FRAMES_TO_PLAY (16 * 1024) #else #define FRAMES_TO_PLAY (64 * 1024) #endif //Some OSs do not allow ':' in the name. Same format used by the GNOME screenshot tool. #define DATE_TIME_FILENAME_FORMAT "%Y-%m-%d %H-%M-%S" #define MAX_FRAMES_PER_PIXEL 300 extern struct browser local_browser; extern struct browser remote_browser; static double press_event_x; void elektroid_update_audio_status (gboolean); gint elektroid_run_dialog_and_destroy (GtkWidget *); struct editor_y_frame_state { gdouble *wp; gdouble *wn; guint *wpc; guint *wnc; }; struct editor_set_volume_data { struct editor *editor; gdouble volume; }; gchar *elektroid_ask_name_get_path (const gchar * title, const gchar * value, struct browser *browser, gint start_pos, gint end_pos); static void editor_set_layout_width_to_val (struct editor *editor, guint w) { guint h; gtk_layout_get_size (GTK_LAYOUT (editor->waveform), NULL, &h); gtk_layout_set_size (GTK_LAYOUT (editor->waveform), w, h); } static void editor_set_layout_width (struct editor *editor) { guint w = gtk_widget_get_allocated_width (editor->waveform_scrolled_window); w = w * editor->zoom - 2; //2 border pixels editor_set_layout_width_to_val (editor, w); } static void editor_set_widget_source (struct editor *editor, GtkWidget *widget) { const char *class; GtkStyleContext *context = gtk_widget_get_style_context (widget); GList *classes, *list = gtk_style_context_list_classes (context); for (classes = list; classes != NULL; classes = g_list_next (classes)) { gtk_style_context_remove_class (context, classes->data); } g_list_free (list); if (editor->browser == NULL) { return; } if (GTK_IS_SWITCH (widget)) { class = editor->browser == &local_browser ? "local_switch" : "remote_switch"; } else { class = editor->browser == &local_browser ? "local" : "remote"; } gtk_style_context_add_class (context, class); } static void editor_reset_browser (struct editor *editor, struct browser *browser) { editor->browser = browser; editor_set_layout_width_to_val (editor, 1); gtk_widget_queue_draw (editor->waveform); editor_set_widget_source (editor, editor->autoplay_switch); editor_set_widget_source (editor, editor->mix_switch); editor_set_widget_source (editor, editor->play_button); editor_set_widget_source (editor, editor->stop_button); editor_set_widget_source (editor, editor->loop_button); editor_set_widget_source (editor, editor->record_button); editor_set_widget_source (editor, editor->volume_button); editor_set_widget_source (editor, editor->show_grid_switch); editor_set_widget_source (editor, editor->waveform); gtk_widget_set_sensitive (editor->play_button, FALSE); gtk_widget_set_sensitive (editor->stop_button, FALSE); gtk_widget_set_sensitive (editor->loop_button, FALSE); } void editor_reset (struct editor *editor, struct browser *browser) { editor_stop_load_thread (editor); audio_stop_playback (&editor->audio); audio_stop_recording (&editor->audio); audio_reset_sample (&editor->audio); editor_reset_browser (editor, browser); } static void editor_set_start_frame (struct editor *editor, gint start) { struct sample_info *sample_info = editor->audio.sample.info; gint max = sample_info->frames - 1; start = start < 0 ? 0 : start; start = start > max ? max : start; gdouble widget_w = gtk_widget_get_allocated_width (editor->waveform_scrolled_window); GtkAdjustment *adj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (editor->waveform_scrolled_window)); gdouble upper = widget_w * editor->zoom - 3; //Base 0 and 2 border pixels gdouble lower = 0; gdouble value = upper * start / (double) sample_info->frames; debug_print (1, "Setting waveform scrollbar to %f [%f, %f]...", value, lower, upper); gtk_adjustment_set_lower (adj, 0); gtk_adjustment_set_upper (adj, upper); gtk_adjustment_set_value (adj, value); } static guint editor_get_start_frame (struct editor *editor) { struct sample_info *sample_info = editor->audio.sample.info; GtkAdjustment *adj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (editor->waveform_scrolled_window)); return sample_info->frames * gtk_adjustment_get_value (adj) / (gdouble) gtk_adjustment_get_upper (adj); } void editor_set_audio_mono_mix (struct editor *editor) { struct sample_info *sample_info = editor->audio.sample.info; if (sample_info && sample_info->frames > 0) { gboolean remote_mono = remote_browser.fs_ops && !(remote_browser.fs_ops->options & FS_OPTION_STEREO); gboolean mono_mix = (preferences_get_boolean (PREF_KEY_MIX) && remote_mono) || sample_info->channels != 2; g_mutex_lock (&editor->audio.control.mutex); editor->audio.mono_mix = mono_mix; g_mutex_unlock (&editor->audio.control.mutex); } } static gboolean editor_loading_completed_no_lock (struct editor *editor, guint32 *actual_frames) { gboolean completed; guint32 actual; gint bytes_per_frame; struct sample_info *sample_info = editor->audio.sample.info; if (!sample_info) { if (actual_frames) { *actual_frames = 0; } return FALSE; } bytes_per_frame = SAMPLE_INFO_FRAME_SIZE (sample_info); actual = editor->audio.sample.content->len / bytes_per_frame; completed = actual == sample_info->frames && actual; if (actual_frames) { *actual_frames = actual; } return completed; } static gboolean editor_update_ui_on_load (gpointer data) { struct editor *editor = data; editor_set_audio_mono_mix (editor); editor_set_layout_width (editor); if (audio_check (&editor->audio)) { gtk_widget_set_sensitive (editor->play_button, TRUE); gtk_widget_set_sensitive (editor->stop_button, TRUE); gtk_widget_set_sensitive (editor->loop_button, TRUE); if (preferences_get_boolean (PREF_KEY_AUTOPLAY)) { audio_start_playback (&editor->audio); } } return FALSE; } static void editor_init_y_frame_state (struct editor_y_frame_state *state, guint channels) { state->wp = g_malloc (sizeof (gdouble) * channels); state->wn = g_malloc (sizeof (gdouble) * channels); state->wpc = g_malloc (sizeof (guint) * channels); state->wnc = g_malloc (sizeof (guint) * channels); } static void editor_destroy_y_frame_state (struct editor_y_frame_state *state) { g_free (state->wp); g_free (state->wn); g_free (state->wpc); g_free (state->wnc); } static gboolean editor_get_y_frame (GByteArray *sample, guint channels, guint frame, guint len, struct editor_y_frame_state *state) { guint loaded_frames = sample->len / FRAME_SIZE (channels, SF_FORMAT_PCM_16); gshort *data = (gshort *) sample->data; gshort *s = &data[frame * channels]; len = len < MAX_FRAMES_PER_PIXEL ? len : MAX_FRAMES_PER_PIXEL; for (guint i = 0; i < channels; i++) { state->wp[i] = 0.0; state->wn[i] = 0.0; state->wpc[i] = 0; state->wnc[i] = 0; } for (guint i = 0, f = frame; i < len; i++, f++) { if (f >= loaded_frames) { return FALSE; } for (guint j = 0; j < channels; j++, s++) { if (*s > 0) { state->wp[j] += *s; state->wpc[j]++; } else { state->wn[j] += *s; state->wnc[j]++; } } } for (guint i = 0; i < channels; i++) { state->wp[i] = state->wpc[i] == 0 ? 0.0 : state->wp[i] / state->wpc[i]; state->wn[i] = state->wnc[i] == 0 ? 0.0 : state->wn[i] / state->wnc[i]; } return TRUE; } static gdouble editor_get_x_ratio (struct editor *editor) { guint layout_width; struct sample_info *sample_info = editor->audio.sample.info; gtk_layout_get_size (GTK_LAYOUT (editor->waveform), &layout_width, NULL); return sample_info->frames / (gdouble) layout_width; } gboolean editor_draw_waveform (GtkWidget *widget, cairo_t *cr, gpointer data) { GdkRGBA color, bgcolor; guint width, height, x_count, c_height, c_height_half, start; guint32 loop_start, loop_end; GtkStyleContext *context; gdouble x_ratio, x_frame, x_frame_next, y_scale, value; struct editor_y_frame_state y_frame_state; struct editor *editor = data; struct sample_info *sample_info; struct audio *audio = &editor->audio; width = gtk_widget_get_allocated_width (widget); height = gtk_widget_get_allocated_height (widget); context = gtk_widget_get_style_context (widget); gtk_render_background (context, cr, 0, 0, width, height); g_mutex_lock (&audio->control.mutex); sample_info = editor->audio.sample.info; if (!sample_info) { goto end; } start = editor_get_start_frame (editor); debug_print (3, "Drawing waveform from %d with %f.2x zoom...", start, editor->zoom); loop_start = sample_info->loop_start; loop_end = sample_info->loop_end; x_ratio = editor_get_x_ratio (editor); y_scale = height / (double) SHRT_MIN; y_scale /= (gdouble) sample_info->channels * 2; c_height = height / (gdouble) sample_info->channels; c_height_half = c_height / 2; editor_init_y_frame_state (&y_frame_state, sample_info->channels); cairo_set_line_width (cr, x_ratio < 1.0 ? 1.0 / x_ratio : 1); if (sample_info->frames) { GtkStateFlags state = gtk_style_context_get_state (context); gtk_style_context_get_color (context, state, &color); gtk_style_context_get_color (context, state, &bgcolor); bgcolor.alpha = 0.25; guint32 sel_len = AUDIO_SEL_LEN (&editor->audio); if (sel_len) { gdouble x_len = sel_len / x_ratio; x_len = x_len < 1 ? 1 : x_len; gdouble x_start = (editor->audio.sel_start - (gdouble) start) / x_ratio; gdk_cairo_set_source_rgba (cr, &bgcolor); cairo_rectangle (cr, x_start, 0, x_len, height); cairo_fill (cr); } gdk_cairo_set_source_rgba (cr, &color); for (gint i = 0; i < width; i++) { x_frame = start + i * x_ratio; x_frame_next = x_frame + x_ratio; x_count = x_frame_next - (guint) x_frame; if (!x_count) { continue; } if (!editor_get_y_frame (audio->sample.content, sample_info->channels, x_frame, x_count, &y_frame_state)) { debug_print (3, "Last available frame before the sample end. Stopping..."); break; } gdouble mid_c = c_height_half; for (gint j = 0; j < sample_info->channels; j++) { value = mid_c + y_frame_state.wp[j] * y_scale; cairo_move_to (cr, i + 0.5, value); value = mid_c + y_frame_state.wn[j] * y_scale; cairo_line_to (cr, i + 0.5, value); cairo_stroke (cr); mid_c += c_height; } } } cairo_set_line_width (cr, 1); if (sample_info->frames) { context = gtk_widget_get_style_context (editor->play_menuitem); //Any text widget is valid gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color); gdk_cairo_set_source_rgba (cr, &color); value = ((gint) ((loop_start - start) / x_ratio)) + .5; cairo_move_to (cr, value, 0); cairo_line_to (cr, value, height - 1); cairo_stroke (cr); cairo_move_to (cr, value, 0); cairo_line_to (cr, value + EDITOR_LOOP_MARKER_WIDTH, EDITOR_LOOP_MARKER_HALF_HEIGHT); cairo_line_to (cr, value, EDITOR_LOOP_MARKER_FULL_HEIGHT); cairo_fill (cr); value = ((gint) ((loop_end - start) / x_ratio)) + .5; cairo_move_to (cr, value, 0); cairo_line_to (cr, value, height - 1); cairo_stroke (cr); cairo_move_to (cr, value, 0); cairo_line_to (cr, value - EDITOR_LOOP_MARKER_WIDTH, EDITOR_LOOP_MARKER_HALF_HEIGHT); cairo_line_to (cr, value, EDITOR_LOOP_MARKER_FULL_HEIGHT); cairo_fill (cr); if (preferences_get_boolean (PREF_KEY_SHOW_GRID)) { gint grid_length = preferences_get_int (PREF_KEY_GRID_LENGTH); color.alpha = 0.25; gdk_cairo_set_source_rgba (cr, &color); gdouble grid_inc = sample_info->frames / (gdouble) grid_length; for (gint i = 1; i < grid_length; i++) { value = ((gint) ((i * grid_inc) - start) / x_ratio) + .5; cairo_move_to (cr, value, 0); cairo_line_to (cr, value, height - 1); cairo_stroke (cr); } } } editor_destroy_y_frame_state (&y_frame_state); end: g_mutex_unlock (&audio->control.mutex); return FALSE; } static gboolean editor_queue_draw (gpointer data) { struct editor *editor = data; gtk_widget_queue_draw (editor->waveform); return FALSE; } static gboolean editor_join_load_thread (gpointer data) { struct editor *editor = data; if (editor->thread) { g_thread_join (editor->thread); editor->thread = NULL; } return FALSE; } static void editor_load_sample_cb (struct job_control *control, gdouble p, gpointer data) { guint32 actual_frames; gboolean completed, ready_to_play; struct editor *editor = data; job_control_set_sample_progress_no_sync (control, p, NULL); g_idle_add (editor_queue_draw, data); completed = editor_loading_completed_no_lock (editor, &actual_frames); if (!editor->ready) { ready_to_play = (preferences_get_boolean (PREF_KEY_PLAY_WHILE_LOADING) && actual_frames >= FRAMES_TO_PLAY) || completed; if (ready_to_play) { g_idle_add (editor_update_ui_on_load, data); editor->ready = TRUE; } } //If the call to sample_load_from_file_full fails, we reset the browser. if (!completed && !actual_frames) { editor_reset_browser (editor, NULL); } } static gpointer editor_load_sample_runner (gpointer data) { struct editor *editor = data; struct audio *audio = &editor->audio; struct sample_info sample_info_req; editor->dirty = FALSE; editor->ready = FALSE; editor->zoom = 1; editor->audio.sel_start = -1; editor->audio.sel_end = -1; sample_info_req.channels = 0; //Automatic sample_info_req.format = SF_FORMAT_PCM_16; sample_info_req.rate = audio->rate; audio->control.active = TRUE; sample_load_from_file_full (audio->path, &audio->sample, &audio->control, &sample_info_req, &audio->sample_info_src, editor_load_sample_cb, editor); return NULL; } void editor_play_clicked (GtkWidget *object, gpointer data) { struct editor *editor = data; if (audio_check (&editor->audio)) { audio_stop_recording (&editor->audio); audio_start_playback (&editor->audio); } } static void editor_update_ui_on_record (gpointer data, gdouble value) { struct editor *editor = data; g_idle_add (editor_queue_draw, data); if (!editor->ready && editor_loading_completed_no_lock (data, NULL)) { g_idle_add (editor_update_ui_on_load, data); editor->ready = TRUE; } } static void editor_stop_clicked (GtkWidget *object, gpointer data) { struct editor *editor = data; audio_stop_playback (&editor->audio); audio_stop_recording (&editor->audio); } static void editor_reset_for_recording (struct editor *editor) { guint options; editor_reset (editor, &local_browser); guirecorder_set_channels_masks (&editor->guirecorder, editor->browser->fs_ops->options); editor->ready = FALSE; editor->dirty = TRUE; editor->zoom = 1; editor->audio.sel_start = -1; editor->audio.sel_end = -1; options = guirecorder_get_channel_mask (&editor->guirecorder); audio_start_recording (&editor->audio, options | RECORD_MONITOR_ONLY, guirecorder_monitor_notifier, &editor->guirecorder); } static void editor_record_clicked (GtkWidget *object, gpointer data) { gint res; guint options; struct editor *editor = data; browser_clear_selection (&local_browser); browser_clear_selection (&remote_browser); editor_reset_for_recording (editor); res = gtk_dialog_run (editor->record_dialog); gtk_widget_hide (GTK_WIDGET (editor->record_dialog)); if (res != GTK_RESPONSE_ACCEPT) { audio_stop_recording (&editor->audio); editor_reset (editor, NULL); return; } gtk_widget_set_sensitive (editor->stop_button, TRUE); options = guirecorder_get_channel_mask (&editor->guirecorder); audio_start_recording (&editor->audio, options, editor_update_ui_on_record, data); } static void editor_loop_clicked (GtkWidget *object, gpointer data) { struct editor *editor = data; editor->audio.loop = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (object)); } static gboolean editor_autoplay_clicked (GtkWidget *object, gboolean state, gpointer data) { preferences_set_boolean (PREF_KEY_AUTOPLAY, state); return FALSE; } void editor_start_load_thread (struct editor *editor, gchar *sample_path) { debug_print (1, "Creating load thread..."); editor->audio.path = sample_path; editor->thread = g_thread_new ("load_sample", editor_load_sample_runner, editor); } void editor_stop_load_thread (struct editor *editor) { struct audio *audio = &editor->audio; debug_print (1, "Stopping load thread..."); g_mutex_lock (&audio->control.mutex); audio->control.active = FALSE; g_mutex_unlock (&audio->control.mutex); editor_join_load_thread (editor); } static gboolean editor_mix_clicked (GtkWidget *object, gboolean state, gpointer data) { struct editor *editor = data; preferences_set_boolean (PREF_KEY_MIX, state); editor_set_audio_mono_mix (editor); return FALSE; } static void editor_set_volume (GtkScaleButton *button, gdouble value, gpointer data) { struct editor *editor = data; audio_set_volume (&editor->audio, value); } static gboolean editor_set_volume_callback_bg (gpointer user_data) { struct editor_set_volume_data *data = user_data; struct editor *editor = data->editor; gdouble volume = data->volume; g_free (data); debug_print (1, "Setting volume to %f...", volume); g_signal_handler_block (editor->volume_button, editor->volume_changed_handler); gtk_scale_button_set_value (GTK_SCALE_BUTTON (editor->volume_button), volume); g_signal_handler_unblock (editor->volume_button, editor->volume_changed_handler); return FALSE; } static void editor_set_volume_callback (gpointer editor, gdouble volume) { struct editor_set_volume_data *data = g_malloc (sizeof (struct editor_set_volume_data)); data->editor = editor; data->volume = volume; g_idle_add (editor_set_volume_callback_bg, data); } static gboolean editor_show_grid_clicked (GtkWidget *object, gboolean state, gpointer data) { struct editor *editor = data; preferences_set_boolean (PREF_KEY_SHOW_GRID, state); g_idle_add (editor_queue_draw, editor); return FALSE; } static void editor_grid_length_changed (GtkSpinButton *object, gpointer data) { struct editor *editor = data; preferences_set_boolean (PREF_KEY_GRID_LENGTH, gtk_spin_button_get_value (object)); g_idle_add (editor_queue_draw, editor); } static void editor_get_frame_at_position (struct editor *editor, gdouble x, guint *cursor_frame, gdouble *rel_pos) { guint lw; guint start = editor_get_start_frame (editor); struct sample_info *sample_info = editor->audio.sample.info; gtk_layout_get_size (GTK_LAYOUT (editor->waveform), &lw, NULL); x = x > lw ? lw : x < 0.0 ? 0.0 : x; *cursor_frame = (sample_info->frames - 1) * (x / (gdouble) lw); if (rel_pos) { *rel_pos = (*cursor_frame - start) / (sample_info->frames / (double) editor->zoom); } } static gdouble editor_get_max_zoom (struct editor *editor) { struct sample_info *sample_info = editor->audio.sample.info; guint w = gtk_widget_get_allocated_width (editor->waveform_scrolled_window); gdouble max_zoom = sample_info->frames / (double) w; return max_zoom < 1 ? 1 : max_zoom; } static gboolean editor_zoom (struct editor *editor, GdkEventScroll *event, gdouble dy) { gdouble rel_pos; gboolean err = TRUE; guint start, cursor_frame; struct sample_info *sample_info; gboolean ctrl = ((event->state) & GDK_CONTROL_MASK) != 0; if (!ctrl) { return FALSE; } if (dy == 0.0) { return FALSE; } g_mutex_lock (&editor->audio.control.mutex); sample_info = editor->audio.sample.info; if (!sample_info) { err = FALSE; goto end; } editor_get_frame_at_position (editor, event->x, &cursor_frame, &rel_pos); debug_print (1, "Zooming at frame %d...", cursor_frame); if (dy == -1.0) { gdouble max_zoom = editor_get_max_zoom (editor); if (editor->zoom == max_zoom) { goto end; } editor->zoom = editor->zoom * 2.0; if (editor->zoom > max_zoom) { editor->zoom = max_zoom; } } else { if (editor->zoom == 1) { goto end; } editor->zoom = editor->zoom / 2.0; if (editor->zoom < 1.0) { editor->zoom = 1.0; } } debug_print (1, "Setting zoom to %f.2x...", editor->zoom); start = cursor_frame - rel_pos * sample_info->frames / (gdouble) editor->zoom; editor_set_start_frame (editor, start); editor_set_layout_width (editor); end: g_mutex_unlock (&editor->audio.control.mutex); return err; } gboolean editor_waveform_scroll (GtkWidget *widget, GdkEventScroll *event, gpointer data) { if (event->direction == GDK_SCROLL_SMOOTH) { gdouble dx, dy; gdk_event_get_scroll_deltas ((GdkEvent *) event, &dx, &dy); if (editor_zoom (data, event, dy)) { g_idle_add (editor_queue_draw, data); } } return FALSE; } static void editor_on_size_allocate (GtkWidget *self, GtkAllocation *allocation, struct editor *editor) { struct sample_info *sample_info; guint start; g_mutex_lock (&editor->audio.control.mutex); sample_info = editor->audio.sample.info; if (!sample_info) { goto end; } start = editor_get_start_frame (editor); editor_set_start_frame (editor, start); editor_set_layout_width (editor); end: g_mutex_unlock (&editor->audio.control.mutex); } static gboolean editor_loading_completed (struct editor *editor) { gboolean res; g_mutex_lock (&editor->audio.control.mutex); res = editor_loading_completed_no_lock (editor, NULL); g_mutex_unlock (&editor->audio.control.mutex); return res; } static gboolean editor_cursor_frame_over_frame (struct editor *editor, guint cursor_frame, guint frame) { gdouble x_ratio = editor_get_x_ratio (editor); gdouble shift = x_ratio < 2 ? 2 : x_ratio * 2; return cursor_frame >= frame - shift && cursor_frame <= frame + shift; } static void editor_set_cursor (struct editor *editor, const gchar *cursor_name) { GdkDisplay *display = gdk_display_get_default (); GdkCursor *cursor = gdk_cursor_new_from_name (display, cursor_name); gdk_window_set_cursor (gtk_widget_get_window (editor->waveform), cursor); g_object_unref (cursor); } static gboolean editor_button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) { guint cursor_frame; guint32 sel_len; struct editor *editor = data; struct sample_info *sample_info; g_mutex_lock (&editor->audio.control.mutex); if (!editor_loading_completed_no_lock (editor, NULL)) { goto end; } sample_info = editor->audio.sample.info; if (!sample_info) { goto end; } sel_len = AUDIO_SEL_LEN (&editor->audio); press_event_x = event->x; editor_get_frame_at_position (editor, event->x, &cursor_frame, NULL); if (event->button == GDK_BUTTON_PRIMARY) { debug_print (2, "Pressing at frame %d...", cursor_frame); if (editor_cursor_frame_over_frame (editor, cursor_frame, sample_info->loop_start)) { debug_print (2, "Clicking on loop start..."); editor->operation = EDITOR_OP_MOVE_LOOP_START; editor_set_cursor (editor, "col-resize"); } else if (editor_cursor_frame_over_frame (editor, cursor_frame, sample_info->loop_end)) { debug_print (2, "Clicking on loop end..."); editor->operation = EDITOR_OP_MOVE_LOOP_END; editor_set_cursor (editor, "col-resize"); } else if (editor_cursor_frame_over_frame (editor, cursor_frame, editor->audio.sel_start) && sel_len) { debug_print (2, "Clicking on selection start..."); editor->operation = EDITOR_OP_MOVE_SEL_START; editor_set_cursor (editor, "col-resize"); } else if (editor_cursor_frame_over_frame (editor, cursor_frame, editor->audio.sel_end) && sel_len) { debug_print (2, "Clicking on selection end..."); editor->operation = EDITOR_OP_MOVE_SEL_END; editor_set_cursor (editor, "col-resize"); } else { g_mutex_unlock (&editor->audio.control.mutex); audio_stop_playback (&editor->audio); g_mutex_lock (&editor->audio.control.mutex); editor->operation = EDITOR_OP_MOVE_SEL_END; editor->audio.sel_start = cursor_frame; editor->audio.sel_end = cursor_frame; gtk_widget_grab_focus (editor->waveform_scrolled_window); g_idle_add (editor_queue_draw, editor); } } else if (event->button == GDK_BUTTON_SECONDARY) { gboolean cursor_on_sel = sel_len > 0 && cursor_frame >= editor->audio.sel_start && cursor_frame < editor->audio.sel_end; if (!cursor_on_sel) { editor->audio.sel_start = -1; editor->audio.sel_end = -1; } gtk_widget_set_sensitive (editor->delete_menuitem, sel_len > 0); gtk_widget_set_sensitive (editor->undo_menuitem, editor->dirty); gtk_widget_set_sensitive (editor->save_menuitem, editor->dirty || cursor_on_sel); gtk_menu_popup_at_pointer (editor->menu, (GdkEvent *) event); } end: g_mutex_unlock (&editor->audio.control.mutex); return FALSE; } static gboolean editor_button_release (GtkWidget *widget, GdkEventButton *event, gpointer data) { struct editor *editor = data; if (!editor->operation) { return FALSE; } if (editor->operation == EDITOR_OP_MOVE_SEL_START || editor->operation == EDITOR_OP_MOVE_SEL_END) { gtk_widget_grab_focus (editor->waveform_scrolled_window); if (press_event_x == event->x) { debug_print (2, "Cleaning selection..."); editor->audio.sel_start = -1; editor->audio.sel_end = -1; g_idle_add (editor_queue_draw, editor); } else { debug_print (2, "Selected range: [%" PRId64 " to %" PRId64 "]...", editor->audio.sel_start, editor->audio.sel_end); if (AUDIO_SEL_LEN (&editor->audio)) { gtk_widget_set_sensitive (editor->delete_menuitem, TRUE); if (preferences_get_boolean (PREF_KEY_AUTOPLAY)) { audio_start_playback (&editor->audio); } } } } editor->operation = EDITOR_OP_NONE; return FALSE; } static gboolean editor_motion_notify (GtkWidget *widget, GdkEventMotion *event, gpointer data) { guint cursor_frame; guint32 sel_len; struct editor *editor = data; struct audio *audio = &editor->audio; struct sample_info *sample_info; g_mutex_lock (&editor->audio.control.mutex); sample_info = audio->sample.info; if (!sample_info) { goto end; } sel_len = AUDIO_SEL_LEN (&editor->audio); editor_get_frame_at_position (editor, event->x, &cursor_frame, NULL); if (editor->operation == EDITOR_OP_MOVE_SEL_END) { if (cursor_frame > editor->audio.sel_start) { editor->audio.sel_end = cursor_frame; } else { editor->operation = EDITOR_OP_MOVE_SEL_START; editor->audio.sel_end = editor->audio.sel_start; editor->audio.sel_start = cursor_frame; } debug_print (2, "Setting selection to [%" PRId64 ", %" PRId64 "]...", editor->audio.sel_start, editor->audio.sel_end); } else if (editor->operation == EDITOR_OP_MOVE_SEL_START) { if (cursor_frame < editor->audio.sel_end) { editor->audio.sel_start = cursor_frame; } else { editor->operation = EDITOR_OP_MOVE_SEL_END; editor->audio.sel_start = editor->audio.sel_end; editor->audio.sel_end = cursor_frame; } debug_print (2, "Setting selection to [%" PRId64 ", %" PRId64 "]...", editor->audio.sel_start, editor->audio.sel_end); } else if (editor->operation == EDITOR_OP_MOVE_LOOP_START) { sample_info->loop_start = cursor_frame; debug_print (2, "Setting loop to [%d, %d]...", sample_info->loop_start, sample_info->loop_end); editor->dirty = TRUE; } else if (editor->operation == EDITOR_OP_MOVE_LOOP_END) { sample_info->loop_end = cursor_frame; debug_print (2, "Setting loop to [%d, %d]...", sample_info->loop_start, sample_info->loop_end); editor->dirty = TRUE; } else { if (editor_cursor_frame_over_frame (editor, cursor_frame, sample_info->loop_start)) { editor_set_cursor (editor, "col-resize"); } else if (editor_cursor_frame_over_frame (editor, cursor_frame, sample_info->loop_end)) { editor_set_cursor (editor, "col-resize"); } else if (editor_cursor_frame_over_frame (editor, cursor_frame, editor->audio.sel_start) && sel_len) { editor_set_cursor (editor, "col-resize"); } else if (editor_cursor_frame_over_frame (editor, cursor_frame, editor->audio.sel_end) && sel_len) { editor_set_cursor (editor, "col-resize"); } else { editor_set_cursor (editor, "default"); } } g_idle_add (editor_queue_draw, data); end: g_mutex_unlock (&editor->audio.control.mutex); return FALSE; } static void editor_delete_clicked (GtkWidget *object, gpointer data) { enum audio_status status; guint32 sel_len; struct editor *editor = data; if (!editor_loading_completed (editor)) { return; } sel_len = AUDIO_SEL_LEN (&editor->audio); if (!sel_len) { return; } //As the playback pointer could be in the selected range, it's safer to stop. //Later, playback will be restarted. g_mutex_lock (&editor->audio.control.mutex); status = editor->audio.status; g_mutex_unlock (&editor->audio.control.mutex); if (status == AUDIO_STATUS_PLAYING) { audio_stop_playback (&editor->audio); } audio_delete_range (&editor->audio, editor->audio.sel_start, sel_len); editor->dirty = TRUE; g_idle_add (editor_queue_draw, data); if (status == AUDIO_STATUS_PLAYING) { audio_start_playback (&editor->audio); } } static void editor_undo_clicked (GtkWidget *object, gpointer data) { struct editor *editor = data; if (editor->audio.path) { //As there is only one undo level, it's enough to reload the sample. editor_start_load_thread (editor, editor->audio.path); } else { //This is a recording editor_reset (editor, NULL); } } static gboolean editor_file_exists_no_overwrite (const gchar *filename) { gint res = GTK_RESPONSE_ACCEPT; GtkWidget *dialog; if (g_file_test (filename, G_FILE_TEST_EXISTS)) { dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_USE_HEADER_BAR, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, _("Replace file “%s”?"), (gchar *) filename); gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Replace"), GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); res = elektroid_run_dialog_and_destroy (dialog); } return res != GTK_RESPONSE_ACCEPT; } //This function does not need synchronized access as it is only called from //editor_save_clicked which already provides this. static gint editor_save_with_format (struct editor *editor, const gchar *dst_path, struct idata *sample) { gint err; struct sample_info *sample_info_src = &editor->audio.sample_info_src; struct sample_info *sample_info = sample->info; if (sample_info->rate == sample_info_src->rate) { err = sample_save_to_file (dst_path, sample, NULL, sample_info_src->format); } else { struct idata resampled; err = sample_reload (sample, &resampled, NULL, sample_info_src, job_control_set_sample_progress_no_sync, NULL); if (err) { return err; } err = sample_save_to_file (dst_path, &resampled, NULL, sample_info_src->format); idata_free (&resampled); } browser_load_dir_if_needed (editor->browser); return err; } static void editor_save_clicked (GtkWidget *object, gpointer data) { gchar *path; const gchar *ext; guint32 sel_len, sugg_sel_len, ext_len; struct idata aux; GByteArray *selection = NULL; struct sample_info *aux_si; gchar suggestion[PATH_MAX]; struct editor *editor = data; struct sample_info *sample_info; g_mutex_lock (&editor->audio.control.mutex); if (!editor_loading_completed_no_lock (editor, NULL)) { goto end; } sample_info = editor->audio.sample.info; if (!sample_info) { goto end; } sel_len = AUDIO_SEL_LEN (&editor->audio); if (sel_len) { guint fsize = SAMPLE_INFO_FRAME_SIZE (sample_info); guint start = editor->audio.sel_start * fsize; guint len = sel_len * fsize; selection = g_byte_array_sized_new (len); g_byte_array_append (selection, &editor->audio.sample.content->data[start], len); aux_si = g_malloc (sizeof (struct sample_info)); memcpy (aux_si, editor->audio.sample.info, sizeof (struct sample_info)); aux_si->frames = sel_len; aux_si->loop_start = sel_len - 1; aux_si->loop_end = aux_si->loop_start; idata_init (&aux, selection, NULL, aux_si); snprintf (suggestion, PATH_MAX, "%s", "Sample.wav"); } else { if (editor->audio.path) { gchar *basename = g_path_get_basename (editor->audio.path); snprintf (suggestion, PATH_MAX, "%s", basename); g_free (basename); } else { GDateTime *dt = g_date_time_new_now_local (); gchar *s = g_date_time_format (dt, DATE_TIME_FILENAME_FORMAT); snprintf (suggestion, PATH_MAX, "%s %s.wav", _("Audio"), s); g_free (s); g_date_time_unref (dt); } } g_mutex_unlock (&editor->audio.control.mutex); sugg_sel_len = strlen (suggestion); ext = filename_get_ext (suggestion); ext_len = strlen (ext); if (ext_len) { sugg_sel_len -= ext_len + 1; } path = elektroid_ask_name_get_path (_("Save Sample"), suggestion, editor->browser, 0, sugg_sel_len); if (path == NULL || editor_file_exists_no_overwrite (path)) { goto cleanup; } g_mutex_lock (&editor->audio.control.mutex); if (editor->audio.path) { if (sel_len) { debug_print (2, "Saving selection to %s...", path); aux.name = g_path_get_basename (path); editor_save_with_format (editor, path, &aux); } else { debug_print (2, "Saving changes to %s...", path); g_free (editor->audio.path); g_free (editor->audio.sample.name); editor->audio.path = path; editor->audio.sample.name = g_path_get_basename (path); editor_save_with_format (editor, editor->audio.path, &editor->audio.sample); } } else { memcpy (&editor->audio.sample_info_src, editor->audio.sample.info, sizeof (struct sample_info)); editor->audio.sample_info_src.format |= SF_FORMAT_WAV; if (sel_len) { //This does not set anything and leaves everything as if no sample would have been loaded. debug_print (2, "Saving recorded selection to %s...", path); aux.name = g_path_get_basename (path); editor_save_with_format (editor, path, &aux); } else { //This sets everything as if a sample would have been loaded. debug_print (2, "Saving recording to %s...", path); editor->audio.path = path; editor->audio.sample.name = g_path_get_basename (path); editor_save_with_format (editor, editor->audio.path, &editor->audio.sample); } } end: g_mutex_unlock (&editor->audio.control.mutex); cleanup: if (selection) { idata_free (&aux); } } static gboolean editor_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data) { struct editor *editor = data; if (event->type != GDK_KEY_PRESS) { return FALSE; } if (event->keyval == GDK_KEY_space) { editor_play_clicked (NULL, editor); } else if (event->keyval == GDK_KEY_Delete) { editor_delete_clicked (NULL, editor); } else if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_z && editor->dirty) { editor_undo_clicked (NULL, editor); } else if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_s && editor->dirty) { editor_save_clicked (NULL, editor); } return TRUE; } static void editor_update_audio_status (gpointer data) { struct editor *editor = data; gboolean status = audio_check (&editor->audio); gtk_widget_set_sensitive (editor->record_button, status); gtk_widget_set_sensitive (editor->volume_button, status); elektroid_update_audio_status (status); } void editor_init (struct editor *editor, GtkBuilder *builder) { editor->box = GTK_WIDGET (gtk_builder_get_object (builder, "editor_box")); editor->waveform_scrolled_window = GTK_WIDGET (gtk_builder_get_object (builder, "waveform_scrolled_window")); editor->waveform = GTK_WIDGET (gtk_builder_get_object (builder, "waveform")); editor->play_button = GTK_WIDGET (gtk_builder_get_object (builder, "play_button")); editor->stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop_button")); editor->loop_button = GTK_WIDGET (gtk_builder_get_object (builder, "loop_button")); editor->record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record_button")); editor->autoplay_switch = GTK_WIDGET (gtk_builder_get_object (builder, "autoplay_switch")); editor->mix_switch = GTK_WIDGET (gtk_builder_get_object (builder, "mix_switch")); editor->volume_button = GTK_WIDGET (gtk_builder_get_object (builder, "volume_button")); editor->mix_switch_box = GTK_WIDGET (gtk_builder_get_object (builder, "mix_switch_box")); editor->grid_length_spin = GTK_WIDGET (gtk_builder_get_object (builder, "grid_length_spin")); editor->show_grid_switch = GTK_WIDGET (gtk_builder_get_object (builder, "show_grid_switch")); editor->notes_list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "notes_list_store")); editor->menu = GTK_MENU (gtk_builder_get_object (builder, "editor_menu")); editor->play_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "editor_play_menuitem")); editor->delete_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "editor_delete_menuitem")); editor->undo_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "editor_undo_menuitem")); editor->save_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "editor_save_menuitem")); editor->record_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "record_dialog")); editor->guirecorder.channels_combo = GTK_WIDGET (gtk_builder_get_object (builder, "record_dialog_channels_combo")); editor->guirecorder.channels_list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "record_dialog_channels_list_store")); editor->guirecorder.monitor_levelbar = GTK_LEVEL_BAR (gtk_builder_get_object (builder, "record_dialog_monitor_levelbar")); editor->guirecorder.audio = &editor->audio; g_signal_connect (editor->waveform, "draw", G_CALLBACK (editor_draw_waveform), editor); gtk_widget_add_events (editor->waveform, GDK_SCROLL_MASK); g_signal_connect (editor->waveform, "scroll-event", G_CALLBACK (editor_waveform_scroll), editor); g_signal_connect (editor->play_button, "clicked", G_CALLBACK (editor_play_clicked), editor); g_signal_connect (editor->stop_button, "clicked", G_CALLBACK (editor_stop_clicked), editor); g_signal_connect (editor->loop_button, "clicked", G_CALLBACK (editor_loop_clicked), editor); g_signal_connect (editor->record_button, "clicked", G_CALLBACK (editor_record_clicked), editor); g_signal_connect (editor->autoplay_switch, "state-set", G_CALLBACK (editor_autoplay_clicked), NULL); g_signal_connect (editor->mix_switch, "state-set", G_CALLBACK (editor_mix_clicked), editor); g_signal_connect (editor->grid_length_spin, "value-changed", G_CALLBACK (editor_grid_length_changed), editor); g_signal_connect (editor->show_grid_switch, "state-set", G_CALLBACK (editor_show_grid_clicked), editor); editor->volume_changed_handler = g_signal_connect (editor->volume_button, "value_changed", G_CALLBACK (editor_set_volume), editor); g_signal_connect (editor->waveform_scrolled_window, "size-allocate", G_CALLBACK (editor_on_size_allocate), editor); gtk_widget_add_events (editor->waveform, GDK_BUTTON_PRESS_MASK); g_signal_connect (editor->waveform, "button-press-event", G_CALLBACK (editor_button_press), editor); gtk_widget_add_events (editor->waveform, GDK_BUTTON_RELEASE_MASK); g_signal_connect (editor->waveform, "button-release-event", G_CALLBACK (editor_button_release), editor); gtk_widget_add_events (editor->waveform, GDK_POINTER_MOTION_MASK); g_signal_connect (editor->waveform, "motion-notify-event", G_CALLBACK (editor_motion_notify), editor); g_signal_connect (editor->waveform_scrolled_window, "key-press-event", G_CALLBACK (editor_key_press), editor); g_signal_connect (editor->play_menuitem, "activate", G_CALLBACK (editor_play_clicked), editor); g_signal_connect (editor->delete_menuitem, "activate", G_CALLBACK (editor_delete_clicked), editor); g_signal_connect (editor->undo_menuitem, "activate", G_CALLBACK (editor_undo_clicked), editor); g_signal_connect (editor->save_menuitem, "activate", G_CALLBACK (editor_save_clicked), editor); editor_loop_clicked (editor->loop_button, editor); gtk_switch_set_active (GTK_SWITCH (editor->autoplay_switch), preferences_get_boolean (PREF_KEY_AUTOPLAY)); gtk_switch_set_active (GTK_SWITCH (editor->mix_switch), preferences_get_boolean (PREF_KEY_MIX)); gtk_switch_set_active (GTK_SWITCH (editor->show_grid_switch), preferences_get_boolean (PREF_KEY_SHOW_GRID)); gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->grid_length_spin), preferences_get_int (PREF_KEY_GRID_LENGTH)); g_signal_connect (editor->guirecorder.channels_combo, "changed", G_CALLBACK (guirecorder_channels_changed), &editor->guirecorder); audio_init (&editor->audio, editor_set_volume_callback, editor_update_audio_status, editor); editor_reset (editor, NULL); } void editor_destroy (struct editor *editor) { audio_destroy (&editor->audio); } void editor_reset_audio (struct editor *editor) { audio_destroy (&editor->audio); audio_init (&editor->audio, editor_set_volume_callback, editor_update_audio_status, editor); editor_reset (editor, NULL); //Resetting the audio causes the edited sample to be cleared so that these are //needed to keep the selection consistent with the editor. browser_clear_selection (&local_browser); browser_clear_selection (&remote_browser); } elektroid-3.2.3/src/editor.h000066400000000000000000000044501500236517400157350ustar00rootroot00000000000000/* * editor.h * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef EDITOR_H #define EDITOR_H #include "audio.h" #include "browser.h" #include "guirecorder.h" #include "preferences.h" enum editor_operation { EDITOR_OP_NONE, EDITOR_OP_MOVE_LOOP_START, EDITOR_OP_MOVE_LOOP_END, EDITOR_OP_MOVE_SEL_START, EDITOR_OP_MOVE_SEL_END }; struct editor { struct audio audio; GThread *thread; GtkWidget *box; GtkWidget *waveform_scrolled_window; GtkWidget *waveform; GtkWidget *play_button; GtkWidget *stop_button; GtkWidget *loop_button; GtkWidget *record_button; GtkWidget *autoplay_switch; GtkWidget *mix_switch; GtkWidget *volume_button; GtkWidget *mix_switch_box; GtkWidget *grid_length_spin; GtkWidget *show_grid_switch; gulong volume_changed_handler; GtkListStore *notes_list_store; GtkMenu *menu; GtkWidget *play_menuitem; GtkWidget *delete_menuitem; GtkWidget *undo_menuitem; GtkWidget *save_menuitem; GtkDialog *record_dialog; struct guirecorder guirecorder; gdouble zoom; enum editor_operation operation; gboolean dirty; gboolean ready; struct browser *browser; }; void editor_reset (struct editor *editor, struct browser *browser); void editor_play_clicked (GtkWidget * object, gpointer data); void editor_start_load_thread (struct editor *editor, gchar * sample_path); void editor_stop_load_thread (struct editor *editor); void editor_init (struct editor *editor, GtkBuilder * builder); void editor_destroy (struct editor *); void editor_set_audio_mono_mix (struct editor *editor); void editor_reset_audio (struct editor *editor); #endif elektroid-3.2.3/src/elektroid-cli.c000066400000000000000000000540461500236517400171770ustar00rootroot00000000000000/* * elektroid-cli.c * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include #if defined(__linux__) #include #endif #include #include #include #include #include #include "backend.h" #include "regconn.h" #include "regpref.h" #include "utils.h" #define COMMAND_NOT_IN_SYSTEM_FS "Command not available in system backend" #define GET_FS_OPS_OFFSET(member) offsetof(struct fs_operations, member) #define GET_FS_OPS_FUNC(type,fs,offset) (*(((type *) (((gchar *) fs) + offset)))) #define RETURN_IF_NULL(f) if (!(f)) {return -ENOSYS;} static struct backend backend; static struct job_control control; static struct sysex_transfer sysex_transfer; static gchar *connector, *fs, *op; const struct fs_operations *fs_ops; const gchar *current_path_progress; gboolean same_line_progress; static void complete_progress () { if (same_line_progress) { fprintf (stderr, "\n"); } } static void print_progress (struct job_control *control) { gint progress = control->progress * 100; const gchar *end = same_line_progress ? "\r" : "\n"; fprintf (stderr, "%s: %3d %%%s", current_path_progress, progress, end); if (same_line_progress) { fflush (stderr); } } static void set_progress_type () { same_line_progress = !debug_level && isatty (fileno (stderr)); } static const gchar * cli_get_path (const gchar *device_path) { gint len = strlen (device_path); const gchar *path = device_path; gint i = 0; while (*path != G_SEARCHPATH_SEPARATOR && i < len) { path++; i++; } path++; return path; } static gint cli_ld () { struct backend_device device; GArray *devices = backend_get_devices (); for (gint i = 0; i < devices->len; i++) { device = g_array_index (devices, struct backend_device, i); printf ("%d: id: %s; name: %s\n", i, device.id, device.name); } g_array_free (devices, TRUE); return EXIT_SUCCESS; } static gint cli_connect (const gchar *device_path) { struct backend_device device; GArray *devices = backend_get_devices (); gint err, id; gchar *rem; if (!devices->len) { error_print ("No devices found"); err = -ENODEV; goto end; } errno = 0; id = (gint) g_ascii_strtoll (device_path, &rem, 10); if (errno || device_path == rem) { error_print ("Device not provided properly in '%s'", device_path); err = -ENODEV; goto end; } if (id >= devices->len) { error_print ("Invalid device '%d'", id); err = -ENODEV; goto end; } device = g_array_index (devices, struct backend_device, id); err = backend_init_connector (&backend, &device, connector, NULL); if (!err && fs) { fs_ops = backend_get_fs_operations_by_name (&backend, fs); if (!fs_ops) { error_print ("Invalid filesystem '%s'", fs); err = -EINVAL; } } end: g_array_free (devices, TRUE); return err; } static gint cli_list (int argc, gchar *argv[], int *optind) { gint err; const gchar *path; struct item_iterator iter; const gchar *device_path; gboolean active; if (*optind == argc) { error_print ("Remote path missing"); return -EINVAL; } else { device_path = argv[*optind]; (*optind)++; } err = cli_connect (device_path); if (err) { return err; } RETURN_IF_NULL (fs_ops->readdir); RETURN_IF_NULL (fs_ops->print_item); active = TRUE; sysex_transfer.active = TRUE; path = cli_get_path (device_path); err = fs_ops->readdir (&backend, &iter, path, NULL); if (err) { return err; } while (!item_iterator_next (&iter) && active) { fs_ops->print_item (&iter, &backend, fs_ops); g_mutex_lock (&sysex_transfer.mutex); active = sysex_transfer.active; g_mutex_unlock (&sysex_transfer.mutex); } item_iterator_free (&iter); return EXIT_SUCCESS; } static gint cli_command_path (int argc, gchar *argv[], int *optind, ssize_t member_offset) { const gchar *path; const gchar *device_path; gint err; fs_path_func f; if (*optind == argc) { error_print ("Remote path missing"); return -EINVAL; } else { device_path = argv[*optind]; (*optind)++; } err = cli_connect (device_path); if (err) { return err; } f = GET_FS_OPS_FUNC (fs_path_func, fs_ops, member_offset); RETURN_IF_NULL (f); path = cli_get_path (device_path); return f (&backend, path); } static gint cli_command_src_dst (int argc, gchar *argv[], int *optind, ssize_t member_offset) { const gchar *src_path, *dst_path; gchar *device_src_path, *device_dst_path; gint src_card, dst_card, err; fs_src_dst_func f; if (*optind == argc) { error_print ("Remote path source missing"); return -EINVAL; } else { device_src_path = argv[*optind]; (*optind)++; } if (*optind == argc) { error_print ("Remote path destination missing"); return -EINVAL; } else { device_dst_path = argv[*optind]; (*optind)++; } src_card = atoi (device_src_path); dst_card = atoi (device_dst_path); if (src_card != dst_card) { error_print ("Source and destination device must be the same"); return -EINVAL; } err = cli_connect (device_src_path); if (err) { return err; } f = GET_FS_OPS_FUNC (fs_src_dst_func, fs_ops, member_offset); RETURN_IF_NULL (f); src_path = cli_get_path (device_src_path); dst_path = cli_get_path (device_dst_path); return f (&backend, src_path, dst_path); } static gint cli_command_mv_rename (int argc, gchar *argv[], int *optind) { const gchar *src_path, *dst_path; gchar *device_src_path, *device_dst_path; gint src_card, dst_card, err; fs_src_dst_func f; if (*optind == argc) { error_print ("Remote path source missing"); return -EINVAL; } else { device_src_path = argv[*optind]; (*optind)++; } if (*optind == argc) { error_print ("Remote path destination missing"); return -EINVAL; } else { device_dst_path = argv[*optind]; (*optind)++; } err = cli_connect (device_src_path); if (err) { return err; } src_card = atoi (device_src_path); src_path = cli_get_path (device_src_path); f = fs_ops->move; // If move is implemented, rename must behave the same way. if (f) { dst_card = atoi (device_dst_path); if (src_card != dst_card) { error_print ("Source and destination device must be the same"); return -EINVAL; } dst_path = cli_get_path (device_dst_path); } else { f = fs_ops->rename; RETURN_IF_NULL (f); dst_path = device_dst_path; } return f (&backend, src_path, dst_path); } static gint cli_info (int argc, gchar *argv[], int *optind) { const gchar *device_path; gint err; gboolean first; GSList *e; if (*optind == argc) { error_print ("Device missing"); return -EINVAL; } else { device_path = argv[*optind]; (*optind)++; } err = cli_connect (device_path); if (err) { return err; } printf ("Type: %s\n", backend.type == BE_TYPE_SYSTEM ? "SYSTEM" : "MIDI"); printf ("Device name: %s\n", backend.name); printf ("Device version: %s\n", backend.version); printf ("Device description: %s\n", backend.description); printf ("Connector name: %s\n", backend.conn_name); printf ("Filesystems: "); e = backend.fs_ops; first = TRUE; while (e) { const struct fs_operations *fs_ops = e->data; const gchar *name = GET_CLI_NAME (fs_ops); gboolean cli_only = fs_ops->gui_name == NULL; printf ("%s%s%s", first ? "" : ", ", name, cli_only ? " (CLI only)" : ""); first = FALSE; e = e->next; } printf ("\n"); return EXIT_SUCCESS; } static gint cli_df (int argc, gchar *argv[], int *optind) { const gchar *device_path; const gchar *path; gchar *size; gchar *diff; gchar *free; gint err; struct backend_storage_stats statfs; if (*optind == argc) { error_print ("Device missing"); return -EINVAL; } else { device_path = argv[*optind]; (*optind)++; } err = cli_connect (device_path); if (err) { return err; } if (!backend.get_storage_stats) { return -ENOSYS; } path = cli_get_path (device_path); if (!strlen (path)) { return -EINVAL; } printf ("%-20.20s%16.16s%16.16s%16.16s%11.10s\n", "Storage", "Size", "Used", "Available", "Use%"); err = 0; for (guint i = 1; i < G_MAXUINT8; i <<= 1) { gint v = backend.get_storage_stats (&backend, i, &statfs, path); if (v >= 0) { size = get_human_size (statfs.bsize, FALSE); diff = get_human_size (statfs.bsize - statfs.bfree, FALSE); free = get_human_size (statfs.bfree, FALSE); printf ("%-20.20s%16s%16s%16s%10.2f%%\n", statfs.name, size, diff, free, backend_get_storage_stats_percent (&statfs)); g_free (size); g_free (diff); g_free (free); } if (!v) { break; } } return err; } static gint cli_upgrade_os (int argc, gchar *argv[], int *optind) { gint err; const gchar *src_path; const gchar *device_path; struct idata idata; if (*optind == argc) { error_print ("Local path missing"); return EXIT_FAILURE; } else { src_path = argv[*optind]; (*optind)++; } if (*optind == argc) { error_print ("Remote path missing"); return EXIT_FAILURE; } else { device_path = argv[*optind]; (*optind)++; } err = cli_connect (device_path); if (err) { return err; } if (backend.type == BE_TYPE_SYSTEM) { error_print (COMMAND_NOT_IN_SYSTEM_FS); return EXIT_FAILURE; } RETURN_IF_NULL (backend.upgrade_os); err = file_load (src_path, &idata, NULL); if (err) { error_print ("Error while loading '%s'.", src_path); } else { sysex_transfer.raw = idata.content; sysex_transfer.active = TRUE; sysex_transfer.timeout = BE_SYSEX_TIMEOUT_MS; err = backend.upgrade_os (&backend, &sysex_transfer); idata_free (&idata); } return err; } static gint cli_download_item (const gchar *src_path, const gchar *dst_path) { gint err; gchar *download_path; struct idata idata; RETURN_IF_NULL (fs_ops->download); RETURN_IF_NULL (fs_ops->get_download_path); RETURN_IF_NULL (fs_ops->save); control.active = TRUE; control.callback = print_progress; current_path_progress = src_path; err = fs_ops->download (&backend, src_path, &idata, &control); if (err) { return err; } download_path = fs_ops->get_download_path (&backend, fs_ops, dst_path, src_path, &idata); if (!download_path) { err = -EINVAL; goto cleanup; } err = fs_ops->save (download_path, &idata, &control); g_free (download_path); cleanup: idata_free (&idata); complete_progress (); return err; } static gint cli_download_dir (const gchar *src_path, const gchar *dst_path) { gint err; gboolean active; struct item_iterator iter; RETURN_IF_NULL (fs_ops->readdir); active = TRUE; sysex_transfer.active = TRUE; err = fs_ops->readdir (&backend, &iter, src_path, NULL); if (err) { return err; } while (!item_iterator_next (&iter) && active && !err) { gchar *rsrc_path; gchar *filename = item_get_filename (&iter.item, fs_ops->options); rsrc_path = path_chain (PATH_INTERNAL, src_path, filename); g_free (filename); if (iter.item.type == ITEM_TYPE_FILE && iter.item.size != 0) //File and non empty slot { err = cli_download_item (rsrc_path, dst_path); } else if (iter.item.type == ITEM_TYPE_DIR) { gchar *rdst_path = path_chain (PATH_SYSTEM, dst_path, iter.item.name); err = g_mkdir (rdst_path, 0755); if (err) { error_print ("Error while creating directory '%s'. Continuing...", rdst_path); } else { err = cli_download_dir (rsrc_path, rdst_path); } g_free (rdst_path); } g_free (rsrc_path); g_mutex_lock (&sysex_transfer.mutex); active = sysex_transfer.active; g_mutex_unlock (&sysex_transfer.mutex); } item_iterator_free (&iter); return active ? err : -ECANCELED; } static gint cli_download (int argc, gchar *argv[], int *optind, gint recursive) { const gchar *src_path; const gchar *dst_path; gchar *device_src_path; gint err; if (*optind == argc) { error_print ("Remote path missing"); return EXIT_FAILURE; } else { device_src_path = argv[*optind]; (*optind)++; } err = cli_connect (device_src_path); if (err) { return err; } src_path = cli_get_path (device_src_path); if (*optind == argc) { dst_path = "."; } else { dst_path = argv[*optind]; debug_print (1, "Creating directory '%s'...", dst_path); err = g_mkdir_with_parents (dst_path, 0755); if (err) { error_print ("Error while creating directory '%s'", dst_path); return err; } } if (recursive) { if (strcmp (src_path, "/")) { gchar *new_dir = g_path_get_basename (src_path); gchar *full_dst_path = path_chain (PATH_SYSTEM, dst_path, new_dir); debug_print (1, "Creating directory '%s'...", full_dst_path); err = g_mkdir (full_dst_path, 0755); if (err) { error_print ("Error while creating directory '%s'", full_dst_path); } else { err = cli_download_dir (src_path, full_dst_path); } g_free (full_dst_path); g_free (new_dir); return err; } else { return cli_download_dir (src_path, dst_path); } } else { return cli_download_item (src_path, dst_path); } } static gint cli_upload_item (const gchar *src_path, const gchar *dst_path) { gint err; gchar *upload_path; struct idata idata; RETURN_IF_NULL (fs_ops->load); RETURN_IF_NULL (fs_ops->get_upload_path); RETURN_IF_NULL (fs_ops->upload); control.active = TRUE; control.callback = print_progress; current_path_progress = src_path; err = fs_ops->load (src_path, &idata, &control); if (err) { return err; } upload_path = fs_ops->get_upload_path (&backend, fs_ops, dst_path, src_path, &idata); err = fs_ops->upload (&backend, upload_path, &idata, &control); idata_free (&idata); g_free (upload_path); complete_progress (); return err; } static gint cli_upload (int argc, gchar *argv[], int *optind) { gint err; const gchar *dst_path; gchar *src_path, *device_dst_path; if (*optind == argc) { error_print ("Local path missing"); return EXIT_FAILURE; } else { src_path = argv[*optind]; (*optind)++; } if (*optind == argc) { error_print ("Remote path missing"); return EXIT_FAILURE; } else { device_dst_path = argv[*optind]; (*optind)++; } err = cli_connect (device_dst_path); if (err) { return err; } dst_path = cli_get_path (device_dst_path); return cli_upload_item (src_path, dst_path); } static gint cli_send (int argc, gchar *argv[], int *optind) { gint err; const gchar *device_dst_path, *src_file; struct idata idata; if (*optind == argc) { error_print ("Source file missing"); return -EINVAL; } else { src_file = argv[*optind]; (*optind)++; } if (*optind == argc) { error_print ("Remote device missing"); return -EINVAL; } else { device_dst_path = argv[*optind]; (*optind)++; } connector = "default"; err = cli_connect (device_dst_path); if (err) { return err; } if (backend.type == BE_TYPE_SYSTEM) { error_print (COMMAND_NOT_IN_SYSTEM_FS); return EXIT_FAILURE; } err = file_load (src_file, &idata, NULL); if (!err) { sysex_transfer.active = TRUE; sysex_transfer.timeout = BE_SYSEX_TIMEOUT_MS; sysex_transfer.raw = idata.content; err = backend_tx_sysex (&backend, &sysex_transfer); idata_free (&idata); } return err; } static gint cli_receive (int argc, gchar *argv[], int *optind) { gint err; const gchar *device_src_path, *dst_file; if (*optind == argc) { error_print ("Remote device missing"); return -EINVAL; } else { device_src_path = argv[*optind]; (*optind)++; } if (*optind == argc) { error_print ("Destination file missing"); return -EINVAL; } else { dst_file = argv[*optind]; (*optind)++; } connector = "default"; err = cli_connect (device_src_path); if (err) { return err; } if (backend.type == BE_TYPE_SYSTEM) { error_print (COMMAND_NOT_IN_SYSTEM_FS); return EXIT_FAILURE; } sysex_transfer.timeout = BE_SYSEX_TIMEOUT_MS; sysex_transfer.batch = TRUE; backend_rx_drain (&backend); //This doesn't need to be synchronized because the CLI is not multithreaded. err = backend_rx_sysex (&backend, &sysex_transfer); if (!err) { struct idata idata; idata.content = sysex_transfer.raw; err = file_save (dst_file, &idata, NULL); } free_msg (sysex_transfer.raw); return err; } static gint set_conn_fs_op_from_command (const gchar *cmd) { gchar *aux; connector = strdup (cmd); aux = strchr (connector, '-'); if (!aux) { g_free (connector); return -EINVAL; } *aux = 0; aux++; fs = strdup (aux); aux = strchr (fs, '-'); if (!aux) { g_free (connector); g_free (fs); return -EINVAL; } *aux = 0; aux++; op = strdup (aux); return 0; } #if defined(__linux__) static void cli_end (int sig) { job_control_set_active_lock (&control, FALSE); g_mutex_lock (&sysex_transfer.mutex); sysex_transfer.active = FALSE; g_mutex_unlock (&sysex_transfer.mutex); } #endif int main (int argc, gchar *argv[]) { gint c; gint err; gchar *command; gint vflg = 0, errflg = 0; #if defined(__linux__) struct sigaction action; action.sa_handler = cli_end; sigemptyset (&action.sa_mask); action.sa_flags = 0; sigaction (SIGTERM, &action, NULL); sigaction (SIGQUIT, &action, NULL); sigaction (SIGINT, &action, NULL); sigaction (SIGHUP, &action, NULL); #endif while ((c = getopt (argc, argv, "v")) != -1) { switch (c) { case 'v': vflg++; break; case '?': errflg++; } } if (optind == argc) { errflg = 1; } else { command = argv[optind]; optind++; } if (vflg) { debug_level = vflg; } if (errflg > 0) { fprintf (stderr, "%s\n", PACKAGE_STRING); gchar *exec_name = g_path_get_basename (argv[0]); fprintf (stderr, "Usage: %s [options] command\n", exec_name); exit (EXIT_FAILURE); } set_progress_type (); regconn_register (); regpref_register (); preferences_load (); if (!strcmp (command, "ld") || !strcmp (command, "list-devices")) { err = cli_ld (); } else if (!strcmp (command, "info") || !strcmp (command, "info-device")) { err = cli_info (argc, argv, &optind); } else if (!strcmp (command, "df") || !strcmp (command, "info-storage")) { err = cli_df (argc, argv, &optind); } else if (!strcmp (command, "send")) { err = cli_send (argc, argv, &optind); } else if (!strcmp (command, "receive")) { err = cli_receive (argc, argv, &optind); } else if (!strcmp (command, "upgrade")) { err = cli_upgrade_os (argc, argv, &optind); } else { err = set_conn_fs_op_from_command (command); if (err) { goto end; } debug_print (1, "Connector: \"%s\"; filesystem: \"%s\"; operation: \"%s\"", connector, fs, op); if (!strcmp (op, "ls") || !strcmp (op, "list")) { err = cli_list (argc, argv, &optind); } else if (!strcmp (op, "mkdir")) { err = cli_command_path (argc, argv, &optind, GET_FS_OPS_OFFSET (mkdir)); } else if (!strcmp (op, "rm") || !strcmp (op, "rmdir")) { err = cli_command_path (argc, argv, &optind, GET_FS_OPS_OFFSET (delete)); } else if (!strcmp (op, "download") || !strcmp (op, "dl")) { err = cli_download (argc, argv, &optind, 0); } else if (!strcmp (op, "rdownload") || !strcmp (op, "rdl") || !strcmp (op, "backup")) { err = cli_download (argc, argv, &optind, 1); } else if (!strcmp (op, "upload") || !strcmp (op, "ul")) { err = cli_upload (argc, argv, &optind); } else if (!strcmp (op, "cl")) { err = cli_command_path (argc, argv, &optind, GET_FS_OPS_OFFSET (clear)); } else if (!strcmp (op, "cp")) { err = cli_command_src_dst (argc, argv, &optind, GET_FS_OPS_OFFSET (copy)); } else if (!strcmp (op, "sw")) { err = cli_command_src_dst (argc, argv, &optind, GET_FS_OPS_OFFSET (swap)); } else if (!strcmp (op, "mv")) { err = cli_command_mv_rename (argc, argv, &optind); } else { error_print ("Command '%s' not recognized", command); err = EXIT_FAILURE; } if (backend_check (&backend)) { backend_destroy (&backend); } g_free (connector); g_free (fs); g_free (op); } end: if (err && err != EXIT_FAILURE) { error_print ("Error: %s", g_strerror (-err)); } regconn_unregister (); regpref_unregister (); usleep (BE_REST_TIME_US * 2); return err ? EXIT_FAILURE : EXIT_SUCCESS; } elektroid-3.2.3/src/elektroid.c000066400000000000000000002542151500236517400164320ustar00rootroot00000000000000/* * elektroid.c * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include #if defined(__linux__) #include #endif #include #include #include #include "regconn.h" #include "regma.h" #include "regpref.h" #include "browser.h" #include "editor.h" #include "tasks.h" #include "sample.h" #include "local.h" #include "preferences.h" #include "progress.h" #define PATH_TYPE_FROM_DND_TYPE(dnd) (strcmp (dnd, TEXT_URI_LIST_ELEKTROID) ? PATH_SYSTEM : backend_get_path_type (&backend)) #define TEXT_URI_LIST_STD "text/uri-list" #define TEXT_URI_LIST_ELEKTROID "text/uri-list-elektroid" #define MSG_WARN_SAME_SRC_DST "Same source and destination path. Skipping..." #define TREEVIEW_SCROLL_LINES 2 #define TREEVIEW_EDGE_SIZE 20 #define PROGRESS_DELETE_THRESHOLD 25 #define BACKEND_PLAYING "\u23f5" #define BACKEND_STOPPED "\u23f9" #define SYSEX_FILTER "*." BE_SYSEX_EXT enum device_list_store_columns { DEVICES_LIST_STORE_TYPE_FIELD, DEVICES_LIST_STORE_ID_FIELD, DEVICES_LIST_STORE_NAME_FIELD }; enum fs_list_store_columns { FS_LIST_STORE_ID_FIELD, FS_LIST_STORE_ICON_FIELD, FS_LIST_STORE_NAME_FIELD }; enum { TARGET_STRING, }; struct elektroid_dnd_data { GtkWidget *widget; gchar **uris; gchar *type_name; }; static gpointer elektroid_upload_task_runner (gpointer); static gpointer elektroid_download_task_runner (gpointer); static void elektroid_update_progress (struct job_control *); static const GtkTargetEntry TARGET_ENTRIES_LOCAL_DST[] = { {TEXT_URI_LIST_STD, 0, TARGET_STRING}, {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP | GTK_TARGET_OTHER_WIDGET, TARGET_STRING} }; static const GtkTargetEntry TARGET_ENTRIES_LOCAL_SRC[] = { {TEXT_URI_LIST_STD, 0, TARGET_STRING} }; static const GtkTargetEntry TARGET_ENTRIES_REMOTE_SYSTEM_DST[] = { {TEXT_URI_LIST_STD, 0, TARGET_STRING}, {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP, TARGET_STRING} }; static const GtkTargetEntry TARGET_ENTRIES_REMOTE_SYSTEM_SRC[] = { {TEXT_URI_LIST_ELEKTROID, 0, TARGET_STRING} }; static const GtkTargetEntry TARGET_ENTRIES_REMOTE_MIDI_DST[] = { {TEXT_URI_LIST_STD, 0, TARGET_STRING}, {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP, TARGET_STRING} }; static const GtkTargetEntry TARGET_ENTRIES_REMOTE_MIDI_DST_SLOT[] = { {TEXT_URI_LIST_STD, 0, TARGET_STRING} }; static const GtkTargetEntry TARGET_ENTRIES_REMOTE_MIDI_SRC[] = { {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP, TARGET_STRING} }; static const GtkTargetEntry TARGET_ENTRIES_UP_BUTTON_DST[] = { {TEXT_URI_LIST_STD, 0, TARGET_STRING}, {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP, TARGET_STRING} }; static const gchar *hostname; static gchar *local_dir; struct editor editor; struct tasks tasks; extern struct browser local_browser; extern struct browser remote_browser; extern struct maction_context maction_context; static struct backend backend; static guint batch_id; GtkWidget *dialog; static GtkWindow *main_window; static GtkBuilder *builder; static GtkAboutDialog *about_dialog; static GtkDialog *name_dialog; static GtkEntry *name_dialog_entry; static GtkWidget *name_dialog_accept_button; static GtkDialog *preferences_dialog; static GtkWidget *play_sample_while_loading_switch; static GtkWidget *audio_buffer_length_combo; static GtkWidget *stop_device_when_connecting_switch; static GtkWidget *elektron_load_sound_tags_switch; static GtkPopover *main_popover; static GtkWidget *show_remote_button; static GtkWidget *preferences_button; static GtkWidget *about_button; static GtkWidget *local_name_entry; static GtkWidget *local_box; static GtkWidget *remote_devices_box; static GtkWidget *remote_box; static GtkWidget *local_side; static GtkWidget *remote_side; static GtkWidget *tasks_box; static GtkLabel *backend_status_label; static GtkLabel *host_audio_status_label; static GtkLabel *host_midi_status_label; static GtkListStore *devices_list_store; static GtkWidget *devices_combo; static GtkListStore *fs_list_store; static GtkWidget *fs_combo; static void show_error_msg (const char *format, ...) { gchar *msg; va_list args; va_start (args, format); g_vasprintf (&msg, format, args); dialog = gtk_message_dialog_new (main_window, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", msg); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); dialog = NULL; g_free (msg); va_end (args); } static void elektroid_load_devices (gboolean auto_select) { gint i; gint device_index; GArray *devices = backend_get_devices (); struct backend_device device; debug_print (1, "Loading devices..."); if (editor.browser == &remote_browser) { editor_reset (&editor, NULL); } gtk_list_store_clear (fs_list_store); gtk_list_store_clear (devices_list_store); for (i = 0; i < devices->len; i++) { device = g_array_index (devices, struct backend_device, i); gtk_list_store_insert_with_values (devices_list_store, NULL, -1, DEVICES_LIST_STORE_TYPE_FIELD, device.type, DEVICES_LIST_STORE_ID_FIELD, device.id, DEVICES_LIST_STORE_NAME_FIELD, device.name, -1); } g_array_free (devices, TRUE); device_index = auto_select && i == 1 ? 0 : -1; debug_print (1, "Selecting device %d...", device_index); gtk_combo_box_set_active (GTK_COMBO_BOX (devices_combo), device_index); if (device_index == -1) { browser_update_fs_options (&local_browser); browser_load_dir (&local_browser); } } void elektroid_update_audio_status (gboolean status) { gchar msg[LABEL_MAX]; if (status) { snprintf (msg, LABEL_MAX, "%s: %s %s, %.5g kHz %s", _("Audio"), audio_name (), audio_version (), editor.audio.rate / 1000.f, BACKEND_PLAYING); } else { snprintf (msg, LABEL_MAX, "%s: %s %s %s", _("Audio"), audio_name (), audio_version (), BACKEND_STOPPED); } gtk_label_set_text (host_audio_status_label, msg); } static void elektroid_update_midi_status () { gchar msg[LABEL_MAX]; const gchar *v = backend.type == BE_TYPE_MIDI ? BACKEND_PLAYING : BACKEND_STOPPED; snprintf (msg, LABEL_MAX, "MIDI: %s %s", backend_name (), v); gtk_label_set_text (host_midi_status_label, msg); } static void elektroid_update_backend_status () { gchar *status; gchar *statfss_str; struct backend_storage_stats statfs; GString *statfss; if (backend_check (&backend)) { statfss = g_string_new (NULL); if (backend.get_storage_stats) { for (guint i = 1; i < G_MAXUINT8; i <<= 1) { gint v = backend.get_storage_stats (&backend, i, &statfs, remote_browser.dir); if (v >= 0) { g_string_append_printf (statfss, " %s %.2f%%", statfs.name, backend_get_storage_stats_percent (&statfs)); } if (!v) { break; } } } statfss_str = g_string_free (statfss, FALSE); status = g_malloc (LABEL_MAX); if (strlen (backend.name)) { snprintf (status, LABEL_MAX, "%s", backend.name); if (*backend.version) { strncat (status, " ", LABEL_MAX - sizeof (status) - 2); strncat (status, backend.version, LABEL_MAX - sizeof (status) - strlen (backend.version) - 1); } if (*backend.description) { strncat (status, " (", LABEL_MAX - sizeof (status) - 3); strncat (status, backend.description, LABEL_MAX - sizeof (status) - strlen (backend.description) - 1); strncat (status, ")", LABEL_MAX - sizeof (status) - 2); } if (statfss_str) { strncat (status, statfss_str, sizeof (status) - strlen (statfss_str) - 1); } } else { status[0] = 0; } gtk_label_set_text (backend_status_label, status); g_free (status); g_free (statfss_str); } else { gtk_label_set_text (backend_status_label, _("Not connected")); } } gboolean elektroid_check_backend (gboolean startup) { gboolean connected = backend_check (&backend); gtk_widget_set_sensitive (remote_box, connected); if (!connected) { browser_reset (&remote_browser); elektroid_load_devices (startup); } elektroid_update_backend_status (); return connected; } static void elektroid_cancel_all_tasks_and_wait () { tasks_cancel_all (NULL, &tasks); //In this case, the active waiting can not be avoided as the user has canceled the operation. while (tasks.transfer.status == TASK_STATUS_RUNNING) { usleep (50000); } } static void elektroid_set_preferences_remote_dir () { if (backend.type == BE_TYPE_SYSTEM) { if (remote_browser.dir) { preferences_set_string (PREF_KEY_REMOTE_DIR, strdup (remote_browser.dir)); } } } void elektroid_refresh_devices (gboolean startup) { elektroid_set_preferences_remote_dir (); if (backend_check (&backend)) { elektroid_cancel_all_tasks_and_wait (); backend_destroy (&backend); maction_menu_clear (&maction_context); browser_reset (&remote_browser); } elektroid_check_backend (startup); //This triggers the actual devices refresh if there is no backend } static void elektroid_refresh_devices_int (GtkWidget *widget, gpointer data) { elektroid_refresh_devices (FALSE); } static gpointer elektroid_rx_sysex_runner (gpointer data) { gint *res = g_malloc (sizeof (gint)); gchar *text; progress.sysex_transfer.status = WAITING; progress.sysex_transfer.active = TRUE; progress.sysex_transfer.timeout = BE_SYSEX_TIMEOUT_MS; progress.sysex_transfer.batch = TRUE; //This doesn't need to be synchronized because the GUI doesn't allow concurrent access when receiving SysEx in batch mode. backend_rx_drain (&backend); if (progress.sysex_transfer.active) { *res = backend_rx_sysex (&backend, &progress.sysex_transfer); if (!*res) { text = debug_get_hex_msg (progress.sysex_transfer.raw); debug_print (1, "SysEx message received (%d): %s", progress.sysex_transfer.raw->len, text); g_free (text); } } else { *res = -ECANCELED; } progress_response (GTK_RESPONSE_ACCEPT); return res; } void elektroid_rx_sysex () { GtkFileChooser *chooser; GtkFileFilter *filter; gint dres; gchar *filename; gchar *filename_w_ext; const gchar *ext; gint *res; GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE; res = progress_run (elektroid_rx_sysex_runner, PROGRESS_TYPE_SYSEX_TRANSFER, NULL, _("Receiving SysEx"), "", TRUE, &dres); if (!res) //Signal captured while running the dialog. { g_byte_array_free (progress.sysex_transfer.raw, TRUE); return; } if (dres != GTK_RESPONSE_ACCEPT) { if (!*res) { g_byte_array_free (progress.sysex_transfer.raw, TRUE); } g_free (res); return; } if (*res) { elektroid_check_backend (FALSE); g_free (res); return; } dialog = gtk_file_chooser_dialog_new (_("Save SysEx"), main_window, action, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Save"), GTK_RESPONSE_ACCEPT, NULL); chooser = GTK_FILE_CHOOSER (dialog); gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE); gtk_file_chooser_set_current_name (chooser, _("Received SysEx")); gtk_file_chooser_set_create_folders (chooser, TRUE); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("SysEx Files")); gtk_file_filter_add_pattern (filter, SYSEX_FILTER); gtk_file_chooser_add_filter (chooser, filter); gtk_file_chooser_set_current_folder (chooser, g_get_home_dir ()); gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter); while (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename (chooser); ext = filename_get_ext (filename); if (strcmp (ext, BE_SYSEX_EXT) != 0) { filename_w_ext = g_strconcat (filename, SYSEX_FILTER, NULL); g_free (filename); filename = filename_w_ext; if (g_file_test (filename, G_FILE_TEST_EXISTS)) { gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), filename); g_free (filename); filename = NULL; continue; } } break; } if (filename != NULL) { struct idata idata; idata.content = progress.sysex_transfer.raw; *res = file_save (filename, &idata, NULL); if (*res) { show_error_msg (_("Error while saving “%s”: %s."), filename, g_strerror (-*res)); } g_byte_array_free (progress.sysex_transfer.raw, TRUE); g_free (res); g_free (filename); } gtk_widget_destroy (dialog); dialog = NULL; } static gint elektroid_send_sysex_file (const gchar *filename, t_sysex_transfer f) { struct idata idata; gint err = file_load (filename, &idata, NULL); if (!err) { progress.sysex_transfer.raw = idata.content; err = f (&backend, &progress.sysex_transfer); idata_free (&idata); } if (err && err != -ECANCELED) { show_error_msg (_("Error while loading “%s”: %s."), filename, g_strerror (-err)); } return err; } gpointer elektroid_tx_sysex_files_runner (gpointer data) { GSList *filenames = data; gint *err = g_malloc (sizeof (gint)); progress.sysex_transfer.active = TRUE; progress.sysex_transfer.status = SENDING; *err = 0; while (*err != -ECANCELED && filenames) { *err = elektroid_send_sysex_file (filenames->data, backend_tx_sysex_no_status); filenames = filenames->next; //The device may have sent some messages in response so we skip all these. backend_rx_drain (&backend); usleep (BE_REST_TIME_US); } progress_response (GTK_RESPONSE_CANCEL); //Any response is OK. return err; } gpointer elektroid_tx_upgrade_os_runner (gpointer data) { GSList *filenames = data; gint *err = g_malloc (sizeof (gint)); progress.sysex_transfer.active = TRUE; progress.sysex_transfer.status = SENDING; progress.sysex_transfer.timeout = BE_SYSEX_TIMEOUT_MS; *err = elektroid_send_sysex_file (filenames->data, backend.upgrade_os); progress_response (GTK_RESPONSE_CANCEL); //Any response is OK. return err; } void elektroid_tx_sysex_common (GThreadFunc func, gboolean multiple) { GtkFileChooser *chooser; GtkFileFilter *filter; gint res, *err; GSList *filenames; dialog = gtk_file_chooser_dialog_new (_("Open SysEx"), main_window, GTK_FILE_CHOOSER_ACTION_OPEN, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Open"), GTK_RESPONSE_ACCEPT, NULL); chooser = GTK_FILE_CHOOSER (dialog); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("SysEx Files")); gtk_file_filter_add_pattern (filter, SYSEX_FILTER); gtk_file_chooser_add_filter (chooser, filter); gtk_file_chooser_set_current_folder (chooser, g_get_home_dir ()); gtk_file_chooser_set_select_multiple (chooser, multiple); res = gtk_dialog_run (GTK_DIALOG (dialog)); if (res == GTK_RESPONSE_ACCEPT) { gtk_widget_hide (GTK_WIDGET (dialog)); filenames = gtk_file_chooser_get_filenames (chooser); err = progress_run (func, PROGRESS_TYPE_SYSEX_TRANSFER, filenames, _("Sending SysEx"), "", TRUE, NULL); g_slist_free_full (g_steal_pointer (&filenames), g_free); if (!err) //Signal captured while running the dialog. { goto cleanup; } if (*err < 0) { elektroid_check_backend (FALSE); } g_free (err); } cleanup: gtk_widget_destroy (dialog); dialog = NULL; } static void elektroid_show_remote (gboolean active) { elektroid_refresh_devices (TRUE); gtk_widget_set_visible (local_name_entry, active); gtk_widget_set_visible (remote_side, active); gtk_widget_set_margin_end (local_side, active ? 6 : 0); gtk_widget_set_visible (tasks_box, active); gtk_widget_set_visible (editor.mix_switch_box, active); } static void elektroid_show_remote_clicked (GtkWidget *object, gpointer data) { gboolean active; g_object_get (G_OBJECT (show_remote_button), "active", &active, NULL); active = !active; preferences_set_boolean (PREF_KEY_SHOW_REMOTE, active); g_object_set (G_OBJECT (show_remote_button), "active", active, NULL); gtk_widget_hide (GTK_WIDGET (main_popover)); elektroid_show_remote (active); } static void elektroid_show_preferences (GtkWidget *object, gpointer data) { gint res, i, prev, post; gboolean v; GtkTreeIter iter; GValue x = G_VALUE_INIT; GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX (audio_buffer_length_combo)); v = preferences_get_boolean (PREF_KEY_PLAY_WHILE_LOADING); gtk_switch_set_active (GTK_SWITCH (play_sample_while_loading_switch), v); v = preferences_get_boolean (PREF_KEY_STOP_DEVICE_WHEN_CONNECTING); gtk_switch_set_active (GTK_SWITCH (stop_device_when_connecting_switch), v); v = preferences_get_boolean (PREF_KEY_ELEKTRON_LOAD_SOUND_TAGS); gtk_switch_set_active (GTK_SWITCH (elektron_load_sound_tags_switch), v); prev = preferences_get_int (PREF_KEY_AUDIO_BUFFER_LEN); gtk_tree_model_get_iter_first (model, &iter); i = 0; do { gtk_tree_model_get_value (model, &iter, 0, &x); if (g_value_get_int (&x) == prev) { gtk_combo_box_set_active (GTK_COMBO_BOX (audio_buffer_length_combo), i); } i++; g_value_unset (&x); } while (gtk_tree_model_iter_next (model, &iter)); res = gtk_dialog_run (GTK_DIALOG (preferences_dialog)); gtk_widget_hide (GTK_WIDGET (preferences_dialog)); if (res != GTK_RESPONSE_ACCEPT) { return; } v = gtk_switch_get_active (GTK_SWITCH (play_sample_while_loading_switch)); preferences_set_boolean (PREF_KEY_PLAY_WHILE_LOADING, v); v = gtk_switch_get_active (GTK_SWITCH (stop_device_when_connecting_switch)); preferences_set_boolean (PREF_KEY_STOP_DEVICE_WHEN_CONNECTING, v); v = gtk_switch_get_active (GTK_SWITCH (elektron_load_sound_tags_switch)); preferences_set_boolean (PREF_KEY_ELEKTRON_LOAD_SOUND_TAGS, v); i = gtk_combo_box_get_active (GTK_COMBO_BOX (audio_buffer_length_combo)); gtk_tree_model_get_iter_first (model, &iter); for (gint j = 0; j < i; j++) { gtk_tree_model_iter_next (model, &iter); } gtk_tree_model_get_value (model, &iter, 0, &x); post = g_value_get_int (&x); preferences_set_int (PREF_KEY_AUDIO_BUFFER_LEN, post); g_value_unset (&x); if (prev != post) { editor_reset_audio (&editor); } } static void elektroid_show_about (GtkWidget *object, gpointer data) { gtk_dialog_run (GTK_DIALOG (about_dialog)); gtk_widget_hide (GTK_WIDGET (about_dialog)); } static gint elektroid_delete_file (struct browser *browser, gchar *dir, struct item *item) { gint err = 0; gchar *path; enum path_type type = backend_get_path_type (browser->backend); path = path_chain (type, dir, item->name); debug_print (1, "Deleting %s...", path); if (item->type == ITEM_TYPE_FILE) { gchar *filename = item_get_filename (item, browser->fs_ops->options); gchar *id_path = path_chain (type, dir, filename); g_free (filename); err = browser->fs_ops->delete (browser->backend, id_path); if (err) { error_print ("Error while deleting “%s”: %s.", path, g_strerror (-err)); } g_free (id_path); } else if (item->type == ITEM_TYPE_DIR) { struct item_iterator iter; if (browser->fs_ops->readdir (browser->backend, &iter, path, NULL)) { err = -ENOTDIR; goto end; } while (!item_iterator_next (&iter)) { elektroid_delete_file (browser, path, &iter.item); if (!progress_is_active ()) { item_iterator_free (&iter); err = -ECANCELED; goto end; } } browser->fs_ops->delete (browser->backend, path); item_iterator_free (&iter); } end: g_free (path); return err; } static gpointer elektroid_delete_files_runner (gpointer data) { GList *list, *tree_path_list, *ref_list; GtkTreeSelection *selection; GtkTreeModel *model; struct browser *browser = data; progress.sysex_transfer.active = TRUE; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view)); model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view)); tree_path_list = gtk_tree_selection_get_selected_rows (selection, &model); ref_list = NULL; //A GtkTreeModel object can NOT be modified while iterating over the selection. list = tree_path_list; while (list) { GtkTreeRowReference *ref = gtk_tree_row_reference_new (model, list->data); ref_list = g_list_append (ref_list, ref); list = g_list_next (list); } g_list_free_full (tree_path_list, (GDestroyNotify) gtk_tree_path_free); g_mutex_lock (&browser->mutex); list = ref_list; while (list) { GtkTreeIter iter; struct item item; GtkTreePath *tree_path = gtk_tree_row_reference_get_path (list->data); gtk_tree_model_get_iter (model, &iter, tree_path); browser_set_item (model, &iter, &item); if (elektroid_delete_file (browser, browser->dir, &item)) { error_print ("Error while deleting file"); } if (!progress_is_active ()) { break; } list = g_list_next (list); } g_list_free_full (ref_list, (GDestroyNotify) gtk_tree_row_reference_free); g_mutex_unlock (&browser->mutex); progress_response (GTK_RESPONSE_ACCEPT); return NULL; } static void elektroid_delete_files (GtkWidget *object, gpointer data) { gint res; struct browser *browser = data; dialog = gtk_message_dialog_new (main_window, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE, _ ("Are you sure you want to delete the selected items?")); gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Delete"), GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); res = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); dialog = NULL; if (res != GTK_RESPONSE_ACCEPT) { return; } if (BROWSER_IS_SYSTEM (browser) && browser_get_selected_items_count (browser) <= PROGRESS_DELETE_THRESHOLD) { elektroid_delete_files_runner (browser); } else { progress_run (elektroid_delete_files_runner, PROGRESS_TYPE_PULSE, browser, _("Deleting Files"), _("Deleting..."), TRUE, NULL); } browser_load_dir_if_needed (data); } static void elektroid_rename_item (GtkWidget *object, gpointer data) { gchar *old_path, *new_path; const gchar *ext; gint result, err, sel_len, ext_len; GtkTreeIter iter; struct item item; struct browser *browser = data; GtkTreeModel *model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view)); browser_set_selected_row_iter (browser, &iter); browser_set_item (model, &iter, &item); old_path = browser_get_item_path (browser, &item); sel_len = strlen (item.name); ext = filename_get_ext (item.name); ext_len = strlen (ext); if (ext_len) { sel_len -= ext_len + 1; } gtk_entry_set_max_length (name_dialog_entry, browser->fs_ops->max_name_len); gtk_entry_set_text (name_dialog_entry, item.name); gtk_widget_grab_focus (GTK_WIDGET (name_dialog_entry)); gtk_editable_select_region (GTK_EDITABLE (name_dialog_entry), 0, sel_len); gtk_widget_set_sensitive (name_dialog_accept_button, FALSE); gtk_window_set_title (GTK_WINDOW (name_dialog), _("Rename")); result = GTK_RESPONSE_ACCEPT; err = -1; while (err < 0 && result == GTK_RESPONSE_ACCEPT) { result = gtk_dialog_run (GTK_DIALOG (name_dialog)); if (result == GTK_RESPONSE_ACCEPT) { if (browser->fs_ops->options & FS_OPTION_SLOT_STORAGE) { new_path = strdup (gtk_entry_get_text (name_dialog_entry)); } else { enum path_type type = backend_get_path_type (browser->backend); new_path = path_chain (type, browser->dir, gtk_entry_get_text (name_dialog_entry)); } err = browser->fs_ops->rename (&backend, old_path, new_path); if (err) { show_error_msg (_("Error while renaming to “%s”: %s."), new_path, g_strerror (-err)); } else { browser_load_dir_if_needed (browser); } g_free (new_path); } } g_free (old_path); gtk_widget_hide (GTK_WIDGET (name_dialog)); } static gboolean elektroid_drag_begin (GtkWidget *widget, GdkDragContext *context, gpointer data) { GtkTreeIter iter; GList *tree_path_list; GList *list; gchar *uri, *path; struct item item; struct browser *browser = data; enum path_type type = backend_get_path_type (browser->backend); GtkTreeView *view = GTK_TREE_VIEW (widget); GtkTreeModel *model = gtk_tree_view_get_model (view); GtkTreeSelection *selection = gtk_tree_view_get_selection (view); tree_path_list = gtk_tree_selection_get_selected_rows (selection, &model); browser->dnd_data = g_string_new (""); for (list = tree_path_list; list != NULL; list = g_list_next (list)) { gtk_tree_model_get_iter (model, &iter, list->data); browser_set_item (model, &iter, &item); path = browser_get_item_path (browser, &item); uri = path_filename_to_uri (type, path); g_free (path); g_string_append (browser->dnd_data, uri); g_free (uri); g_string_append (browser->dnd_data, "\n"); } g_list_free_full (tree_path_list, (GDestroyNotify) gtk_tree_path_free); browser->dnd = TRUE; debug_print (1, "Drag begin data:\n%s", browser->dnd_data->str); return FALSE; } static gboolean elektroid_selection_function_true (GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer data) { return TRUE; } static gboolean elektroid_selection_function_false (GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer data) { return FALSE; } static gboolean elektroid_drag_end (GtkWidget *widget, GdkDragContext *context, gpointer data) { GtkTreeSelection *selection; struct browser *browser = data; debug_print (1, "Drag end"); g_string_free (browser->dnd_data, TRUE); browser->dnd = FALSE; //Performing a DND that was ending in the same browser and directory has no //effect. But the selection function was disabled on the button press and //never enabled again as there is no button release signal. selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view)); gtk_tree_selection_set_select_function (selection, elektroid_selection_function_true, NULL, NULL); return FALSE; } static gboolean elektroid_button_press (GtkWidget *treeview, GdkEventButton *event, gpointer data) { GtkTreePath *path; GtkTreeSelection *selection; struct browser *browser = data; gboolean val = FALSE; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view)); gtk_tree_selection_set_select_function (selection, elektroid_selection_function_true, NULL, NULL); if (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) { return FALSE; } if (event->button == GDK_BUTTON_PRIMARY || event->button == GDK_BUTTON_SECONDARY) { gtk_tree_view_get_path_at_pos (browser->view, event->x, event->y, &path, NULL, NULL, NULL); if (path) { if (gtk_tree_selection_path_is_selected (selection, path)) { if (event->button == GDK_BUTTON_PRIMARY) { gtk_tree_selection_set_select_function (selection, elektroid_selection_function_false, NULL, NULL); } else if (event->button == GDK_BUTTON_SECONDARY) { val = TRUE; } } else { gtk_tree_selection_unselect_all (selection); gtk_tree_selection_select_path (selection, path); } gtk_tree_path_free (path); } else { gtk_tree_selection_unselect_all (selection); } if (event->button == GDK_BUTTON_SECONDARY) { gtk_menu_popup_at_pointer (browser->menu, (GdkEvent *) event); } } return val; } static gboolean elektroid_button_release (GtkWidget *treeview, GdkEventButton *event, gpointer data) { GtkTreePath *path; GtkTreeSelection *selection; struct browser *browser = data; if (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) { return FALSE; } if (event->button == GDK_BUTTON_PRIMARY) { gtk_tree_view_get_path_at_pos (browser->view, event->x, event->y, &path, NULL, NULL, NULL); if (path) { selection = gtk_tree_view_get_selection (browser->view); if (gtk_tree_selection_path_is_selected (selection, path)) { gtk_tree_selection_set_select_function (selection, elektroid_selection_function_true, NULL, NULL); if (browser_get_selected_items_count (browser) != 1) { gtk_tree_selection_unselect_all (selection); gtk_tree_selection_select_path (selection, path); } } gtk_tree_path_free (path); } } return FALSE; } static void elektroid_show_clicked (GtkWidget *object, gpointer data) { GtkTreeIter iter; GtkTreeModel *model; gchar *uri; GVariant *params, *result; GVariantBuilder builder; GFile *file; GDBusProxy *proxy; struct item item; gchar *path = NULL; gboolean done = FALSE; struct browser *browser = data; gint count = browser_get_selected_items_count (browser); enum path_type type = backend_get_path_type (browser->backend); if (count == 0) { path = path_chain (type, browser->dir, NULL); } else if (count == 1) { browser_set_selected_row_iter (browser, &iter); model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view)); browser_set_item (model, &iter, &item); path = path_chain (type, browser->dir, item.name); } else { return; } file = g_file_new_for_path (path); g_free (path); uri = g_file_get_uri (file); g_object_unref (file); proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, "org.freedesktop.FileManager1", "/org/freedesktop/FileManager1", "org.freedesktop.FileManager1", NULL, NULL); if (proxy) { g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); g_variant_builder_add (&builder, "s", uri); params = g_variant_new ("(ass)", &builder, ""); result = g_dbus_proxy_call_sync (proxy, "ShowItems", params, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); if (result != NULL) { done = TRUE; g_variant_unref (result); } g_object_unref (proxy); } if (!done) { g_app_info_launch_default_for_uri (uri, NULL, NULL); } g_free (uri); } static void elektroid_open_clicked (GtkWidget *object, gpointer data) { GtkTreeIter iter; GtkTreeModel *model; gchar *path; gchar *uri; GFile *file; struct item item; struct browser *browser = data; enum path_type type = backend_get_path_type (browser->backend); browser_set_selected_row_iter (browser, &iter); model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view)); browser_set_item (model, &iter, &item); path = path_chain (type, browser->dir, item.name); file = g_file_new_for_path (path); g_free (path); uri = g_file_get_uri (file); g_object_unref (file); g_app_info_launch_default_for_uri_async (uri, NULL, NULL, NULL, NULL); g_free (uri); } gint elektroid_run_dialog_and_destroy (GtkWidget *custom_dialog) { dialog = custom_dialog; gtk_window_set_transient_for (GTK_WINDOW (dialog), main_window); gint result = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); dialog = NULL; return result; } gchar * elektroid_ask_name_get_path (const gchar *title, const gchar *value, struct browser *browser, gint start_pos, gint end_pos) { char *pathname = NULL; int result; gint err; enum path_type type = backend_get_path_type (browser->backend); gtk_entry_set_text (name_dialog_entry, value); gtk_entry_set_max_length (name_dialog_entry, browser->fs_ops->max_name_len); gtk_widget_grab_focus (GTK_WIDGET (name_dialog_entry)); gtk_editable_select_region (GTK_EDITABLE (name_dialog_entry), start_pos, end_pos); gtk_widget_set_sensitive (name_dialog_accept_button, strlen (value) > 0); gtk_window_set_title (GTK_WINDOW (name_dialog), title); result = GTK_RESPONSE_ACCEPT; err = -1; while (err < 0 && result == GTK_RESPONSE_ACCEPT) { result = gtk_dialog_run (GTK_DIALOG (name_dialog)); if (result == GTK_RESPONSE_ACCEPT) { pathname = path_chain (type, browser->dir, gtk_entry_get_text (name_dialog_entry)); break; } } gtk_widget_hide (GTK_WIDGET (name_dialog)); return pathname; } static void elektroid_add_dir (GtkWidget *object, gpointer data) { char *pathname; struct browser *browser = data; pathname = elektroid_ask_name_get_path (_("Add Directory"), "", browser, 0, 0); if (pathname) { gint err = browser->fs_ops->mkdir (&backend, pathname); if (err) { show_error_msg (_("Error while creating dir “%s”: %s."), pathname, g_strerror (-err)); } else { browser_load_dir_if_needed (browser); } g_free (pathname); } } static void elektroid_name_dialog_entry_changed (GtkWidget *object, gpointer data) { size_t len = strlen (gtk_entry_get_text (name_dialog_entry)); gtk_widget_set_sensitive (name_dialog_accept_button, len > 0); } static gboolean elektroid_run_next (gpointer data) { GtkTreeIter iter; enum task_type type; gchar *src; gchar *dst; gint fs; guint batch_id, mode; GtkTreePath *path; gboolean transfer_active; gboolean found = tasks_get_next_queued (&tasks, &iter, &type, &src, &dst, &fs, &batch_id, &mode); const gchar *status_human = tasks_get_human_status (TASK_STATUS_RUNNING); transfer_active = job_control_get_active_lock (&tasks.transfer.control); if (!transfer_active && found) { const struct fs_operations *ops = backend_get_fs_operations_by_id (&backend, fs); if (ops->options & FS_OPTION_SINGLE_OP) { gtk_widget_set_sensitive (remote_box, FALSE); gtk_widget_set_sensitive (fs_combo, FALSE); } gtk_widget_set_sensitive (maction_context.box, FALSE); gtk_list_store_set (tasks.list_store, &iter, TASK_LIST_STORE_STATUS_FIELD, TASK_STATUS_RUNNING, TASK_LIST_STORE_STATUS_HUMAN_FIELD, status_human, -1); path = gtk_tree_model_get_path (GTK_TREE_MODEL (tasks.list_store), &iter); gtk_tree_view_set_cursor (GTK_TREE_VIEW (tasks.tree_view), path, NULL, FALSE); gtk_tree_path_free (path); tasks.transfer.status = TASK_STATUS_RUNNING; tasks.transfer.control.active = TRUE; tasks.transfer.control.callback = elektroid_update_progress; tasks.transfer.control.parts = 0; tasks.transfer.control.part = 0; tasks.transfer.control.progress = 0.0; tasks.transfer.src = src; tasks.transfer.dst = dst; tasks.transfer.fs_ops = ops; tasks.transfer.batch_id = batch_id; tasks.transfer.mode = mode; debug_print (1, "Running task type %d from %s to %s (filesystem %s)...", type, tasks.transfer.src, tasks.transfer.dst, tasks.transfer.fs_ops->name); tasks_update_current_progress (&tasks); if (type == TASK_TYPE_UPLOAD) { tasks.thread = g_thread_new ("upload_task", elektroid_upload_task_runner, NULL); remote_browser.dirty = TRUE; } else if (type == TASK_TYPE_DOWNLOAD) { tasks.thread = g_thread_new ("download_task", elektroid_download_task_runner, NULL); } gtk_widget_set_sensitive (tasks.cancel_task_button, TRUE); } else { if (remote_browser.fs_ops && remote_browser.fs_ops->options & FS_OPTION_SINGLE_OP) { gtk_widget_set_sensitive (remote_box, TRUE); gtk_widget_set_sensitive (fs_combo, TRUE); if (remote_browser.dirty) { remote_browser.dirty = FALSE; g_idle_add (browser_load_dir_if_needed, &remote_browser); } } gtk_widget_set_sensitive (maction_context.box, TRUE); } tasks_check_buttons (&tasks); return FALSE; } static gboolean elektroid_show_task_overwrite_dialog (gpointer data) { gint res; gboolean apply_to_all; GtkWidget *container, *checkbutton; dialog = gtk_message_dialog_new (main_window, GTK_DIALOG_MODAL | GTK_DIALOG_USE_HEADER_BAR, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, _("Replace file “%s”?"), (gchar *) data); gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Skip"), GTK_RESPONSE_REJECT, _("_Replace"), GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); container = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); checkbutton = gtk_check_button_new_with_label (_("Apply this action to all files")); gtk_widget_set_hexpand (checkbutton, TRUE); gtk_widget_set_halign (checkbutton, GTK_ALIGN_CENTER); gtk_widget_show (checkbutton); gtk_container_add (GTK_CONTAINER (container), checkbutton); res = gtk_dialog_run (GTK_DIALOG (dialog)); apply_to_all = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton)); switch (res) { case GTK_RESPONSE_CANCEL: //Cancel current task. tasks.transfer.status = TASK_STATUS_CANCELED; //Cancel all tasks belonging to the same batch. tasks_visit_pending (&tasks, tasks_visitor_set_batch_canceled); break; case GTK_RESPONSE_REJECT: //Cancel current task. tasks.transfer.status = TASK_STATUS_CANCELED; if (apply_to_all) { //Mark pending tasks as SKIP. tasks_visit_pending (&tasks, tasks_batch_visitor_set_skip); } break; case GTK_RESPONSE_ACCEPT: //Mark pending tasks as REPLACE. if (apply_to_all) { tasks_visit_pending (&tasks, tasks_batch_visitor_set_replace); } break; } gtk_widget_destroy (dialog); dialog = NULL; g_mutex_lock (&tasks.transfer.control.mutex); g_cond_signal (&tasks.transfer.control.cond); g_mutex_unlock (&tasks.transfer.control.mutex); return FALSE; } //Close the preparing tasks progress dialog if it is open. static gboolean elektroid_close_progress_dialog (gpointer data) { progress_response (GTK_RESPONSE_CANCEL); return FALSE; } static void elektroid_check_file_and_wait (gchar *path, struct browser *browser) { struct backend *backend = browser->backend; const struct fs_operations *fs_ops = browser->fs_ops; if (fs_ops->file_exists && fs_ops->file_exists (backend, path)) { switch (tasks.transfer.mode) { case TASK_MODE_ASK: g_idle_add (elektroid_close_progress_dialog, NULL); g_idle_add (elektroid_show_task_overwrite_dialog, path); g_cond_wait (&tasks.transfer.control.cond, &tasks.transfer.control.mutex); break; case TASK_MODE_SKIP: tasks.transfer.status = TASK_STATUS_CANCELED; break; } } } static gpointer elektroid_upload_task_runner (gpointer data) { gint res; struct idata idata; gchar *dst_dir, *upload_path; debug_print (1, "Local path: %s", tasks.transfer.src); debug_print (1, "Remote path: %s", tasks.transfer.dst); if (remote_browser.fs_ops->mkdir && remote_browser.fs_ops->mkdir (remote_browser.backend, tasks.transfer.dst)) { error_print ("Error while creating remote %s dir", tasks.transfer.dst); tasks.transfer.status = TASK_STATUS_COMPLETED_ERROR; return NULL; } res = tasks.transfer.fs_ops->load (tasks.transfer.src, &idata, &tasks.transfer.control); if (res) { error_print ("Error while loading file"); tasks.transfer.status = TASK_STATUS_COMPLETED_ERROR; goto end; } debug_print (1, "Writing from file %s (filesystem %s)...", tasks.transfer.src, tasks.transfer.fs_ops->name); upload_path = remote_browser.fs_ops->get_upload_path (&backend, remote_browser.fs_ops, tasks.transfer.dst, tasks.transfer.src, &idata); g_mutex_lock (&tasks.transfer.control.mutex); elektroid_check_file_and_wait (upload_path, &remote_browser); g_mutex_unlock (&tasks.transfer.control.mutex); if (tasks.transfer.status == TASK_STATUS_CANCELED) { goto cleanup; } res = tasks.transfer.fs_ops->upload (remote_browser.backend, upload_path, &idata, &tasks.transfer.control); if (res && tasks.transfer.control.active) { error_print ("Error while uploading"); tasks.transfer.status = TASK_STATUS_COMPLETED_ERROR; } else { tasks.transfer.status = job_control_get_active_lock (&tasks.transfer.control) ? TASK_STATUS_COMPLETED_OK : TASK_STATUS_CANCELED; } dst_dir = g_path_get_dirname (upload_path); if (!res && tasks.transfer.fs_ops == remote_browser.fs_ops && !strncmp (dst_dir, remote_browser.dir, strlen (remote_browser.dir)) && !(tasks.transfer.fs_ops->options & FS_OPTION_SINGLE_OP)) { g_idle_add (browser_load_dir_if_needed, &remote_browser); } g_free (upload_path); g_free (dst_dir); cleanup: idata_free (&idata); end: g_idle_add (tasks_complete_current, &tasks); g_idle_add (elektroid_run_next, NULL); return NULL; } static void elektroid_add_upload_task_path (const gchar *rel_path, const gchar *src_dir, const gchar *dst_dir) { struct item_iterator iter; gchar *path, *src_abs_path, *rel_path_trans; enum path_type type = backend_get_path_type (&backend); if (!progress_is_active ()) { return; } rel_path_trans = path_translate (PATH_SYSTEM, rel_path); src_abs_path = path_chain (PATH_SYSTEM, src_dir, rel_path_trans); g_free (rel_path_trans); //Check if the item is a dir. If error, it's not. if (local_browser.fs_ops->readdir (NULL, &iter, src_abs_path, NULL)) { rel_path_trans = path_translate (type, rel_path); gchar *dst_abs_path = path_chain (type, dst_dir, rel_path_trans); g_free (rel_path_trans); gchar *dst_abs_dir = g_path_get_dirname (dst_abs_path); tasks_add (&tasks, TASK_TYPE_UPLOAD, src_abs_path, dst_abs_dir, remote_browser.fs_ops->id, &backend); g_free (dst_abs_path); goto cleanup; } if (!remote_browser.fs_ops->mkdir) { //No recursive case. goto cleanup_iter; } while (!item_iterator_next (&iter)) { path = path_chain (PATH_INTERNAL, rel_path, iter.item.name); elektroid_add_upload_task_path (path, src_dir, dst_dir); g_free (path); } cleanup_iter: item_iterator_free (&iter); cleanup: g_free (src_abs_path); } static gpointer elektroid_add_upload_tasks_runner (gpointer userdata) { GtkTreeIter iter; GList *selected_rows; gboolean queued_before, queued_after; GtkTreeModel *model = gtk_tree_view_get_model (local_browser.view); GtkTreeSelection *sel = gtk_tree_view_get_selection (local_browser.view); progress.sysex_transfer.active = TRUE; queued_before = tasks_get_next_queued (&tasks, &iter, NULL, NULL, NULL, NULL, NULL, NULL); selected_rows = gtk_tree_selection_get_selected_rows (sel, NULL); while (selected_rows) { struct item item; GtkTreeIter path_iter; GtkTreePath *path = selected_rows->data; gtk_tree_model_get_iter (model, &path_iter, path); browser_set_item (model, &path_iter, &item); elektroid_add_upload_task_path (item.name, local_browser.dir, remote_browser.dir); if (!progress_is_active ()) { break; } selected_rows = g_list_next (selected_rows); } g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free); queued_after = tasks_get_next_queued (&tasks, &iter, NULL, NULL, NULL, NULL, NULL, NULL); if (!queued_before && queued_after) { g_idle_add (elektroid_run_next, NULL); } progress_response (GTK_RESPONSE_ACCEPT); return NULL; } static void elektroid_add_upload_tasks (GtkWidget *object, gpointer data) { GtkTreeSelection *sel = gtk_tree_view_get_selection (local_browser.view); if (!gtk_tree_selection_count_selected_rows (sel)) { return; } progress_run (elektroid_add_upload_tasks_runner, PROGRESS_TYPE_PULSE, NULL, _("Preparing Tasks"), _("Waiting..."), TRUE, NULL); } static gpointer elektroid_download_task_runner (gpointer userdata) { gint res; struct idata idata; gchar *dst_path; debug_print (1, "Remote path: %s", tasks.transfer.src); debug_print (1, "Local dir: %s", tasks.transfer.dst); if (local_browser.fs_ops->mkdir (local_browser.backend, tasks.transfer.dst)) { error_print ("Error while creating local %s dir", tasks.transfer.dst); tasks.transfer.status = TASK_STATUS_COMPLETED_ERROR; goto end_no_dir; } res = tasks.transfer.fs_ops->download (remote_browser.backend, tasks.transfer.src, &idata, &tasks.transfer.control); g_mutex_lock (&tasks.transfer.control.mutex); if (res) { if (tasks.transfer.control.active) { error_print ("Error while downloading"); tasks.transfer.status = TASK_STATUS_COMPLETED_ERROR; } else { tasks.transfer.status = TASK_STATUS_CANCELED; } goto end_with_download_error; } dst_path = remote_browser.fs_ops->get_download_path (&backend, remote_browser.fs_ops, tasks.transfer.dst, tasks.transfer.src, &idata); elektroid_check_file_and_wait (dst_path, &local_browser); if (tasks.transfer.status != TASK_STATUS_CANCELED) { debug_print (1, "Writing %d bytes to file %s (filesystem %s)...", idata.content->len, dst_path, tasks.transfer.fs_ops->name); res = tasks.transfer.fs_ops->save (dst_path, &idata, &tasks.transfer.control); if (!res) { tasks.transfer.status = TASK_STATUS_COMPLETED_OK; g_idle_add (browser_load_dir_if_needed, &local_browser); } } g_free (dst_path); idata_free (&idata); end_with_download_error: g_mutex_unlock (&tasks.transfer.control.mutex); g_idle_add (tasks_complete_current, &tasks); g_idle_add (elektroid_run_next, NULL); end_no_dir: return NULL; } static void elektroid_add_download_task_path (const gchar *rel_path, const gchar *src_dir, const gchar *dst_dir) { struct item_iterator iter; gchar *path, *filename, *src_abs_path, *rel_path_trans; enum path_type type = backend_get_path_type (&backend); if (!progress_is_active ()) { return; } rel_path_trans = path_translate (type, rel_path); src_abs_path = path_chain (type, src_dir, rel_path_trans); g_free (rel_path_trans); //Check if the item is a dir. If error, it's not. if (remote_browser. fs_ops->readdir (remote_browser.backend, &iter, src_abs_path, NULL)) { rel_path_trans = path_translate (PATH_SYSTEM, rel_path); gchar *dst_abs_path = path_chain (PATH_SYSTEM, dst_dir, rel_path_trans); g_free (rel_path_trans); gchar *dst_abs_dir = g_path_get_dirname (dst_abs_path); tasks_add (&tasks, TASK_TYPE_DOWNLOAD, src_abs_path, dst_abs_dir, remote_browser.fs_ops->id, &backend); g_free (dst_abs_dir); g_free (dst_abs_path); goto cleanup; } while (!item_iterator_next (&iter)) { filename = item_get_filename (&iter.item, remote_browser.fs_ops->options); path = path_chain (PATH_INTERNAL, rel_path, filename); elektroid_add_download_task_path (path, src_dir, dst_dir); debug_print (1, "name: %s", filename); g_free (path); g_free (filename); debug_print (1, "next"); } item_iterator_free (&iter); cleanup: g_free (src_abs_path); } static gpointer elektroid_add_download_tasks_runner (gpointer data) { GtkTreeIter iter; GList *selected_rows; gboolean queued_before, queued_after; GtkTreeModel *model = gtk_tree_view_get_model (remote_browser.view); GtkTreeSelection *sel = gtk_tree_view_get_selection (remote_browser.view); progress.sysex_transfer.active = TRUE; queued_before = tasks_get_next_queued (&tasks, &iter, NULL, NULL, NULL, NULL, NULL, NULL); selected_rows = gtk_tree_selection_get_selected_rows (sel, NULL); while (selected_rows) { gchar *filename; struct item item; GtkTreeIter path_iter; GtkTreePath *path = selected_rows->data; gtk_tree_model_get_iter (model, &path_iter, path); browser_set_item (model, &path_iter, &item); filename = item_get_filename (&item, remote_browser.fs_ops->options); elektroid_add_download_task_path (filename, remote_browser.dir, local_browser.dir); g_free (filename); if (!progress_is_active ()) { break; } selected_rows = g_list_next (selected_rows); } g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free); queued_after = tasks_get_next_queued (&tasks, &iter, NULL, NULL, NULL, NULL, NULL, NULL); if (!queued_before && queued_after) { g_idle_add (elektroid_run_next, NULL); } progress_response (GTK_RESPONSE_ACCEPT); return NULL; } static void elektroid_add_download_tasks (GtkWidget *object, gpointer data) { GtkTreeSelection *sel = gtk_tree_view_get_selection (remote_browser.view); if (!gtk_tree_selection_count_selected_rows (sel)) { return; } progress_run (elektroid_add_download_tasks_runner, PROGRESS_TYPE_PULSE, NULL, _("Preparing Tasks"), _("Waiting..."), TRUE, NULL); } static void elektroid_update_progress (struct job_control *control) { g_idle_add (tasks_update_current_progress, &tasks); } static gboolean elektroid_common_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data) { gint count; GtkAllocation allocation; GdkWindow *gdk_window; struct browser *browser = data; struct sample_info *sample_info = editor.audio.sample.info; if (event->keyval == GDK_KEY_Menu) { count = browser_get_selected_items_count (browser); gtk_widget_get_allocation (GTK_WIDGET (browser->view), &allocation); gdk_window = gtk_widget_get_window (GTK_WIDGET (browser->view)); gtk_menu_popup_at_rect (browser->menu, gdk_window, &allocation, GDK_GRAVITY_CENTER, GDK_GRAVITY_NORTH_WEST, NULL); return TRUE; } else if (event->keyval == GDK_KEY_space && sample_info->frames) { editor_play_clicked (NULL, &editor); return TRUE; } else if (event->keyval == GDK_KEY_F2) { count = browser_get_selected_items_count (browser); if (count == 1 && browser->fs_ops->rename) { elektroid_rename_item (NULL, browser); } return TRUE; } else if (event->keyval == GDK_KEY_Delete) { if (browser_get_selected_items_count (browser) > 0 && browser->fs_ops->delete) { elektroid_delete_files (NULL, browser); } return TRUE; } else if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_r) { browser_load_dir (browser); return TRUE; } else if (event->state & GDK_CONTROL_MASK && (event->keyval == GDK_KEY_U || event->keyval == GDK_KEY_u)) { browser_go_up (NULL, browser); return TRUE; } else if (event->state & GDK_CONTROL_MASK && event->state & GDK_SHIFT_MASK && (event->keyval == GDK_KEY_N || event->keyval == GDK_KEY_n)) { elektroid_add_dir (NULL, browser); return TRUE; } else { return FALSE; } } static gboolean elektroid_remote_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data) { if (event->type != GDK_KEY_PRESS) { return FALSE; } if (!(event->state & GDK_CONTROL_MASK) || event->keyval != GDK_KEY_Left) { return elektroid_common_key_press (widget, event, data); } if (!remote_browser.fs_ops->download) { return FALSE; } elektroid_add_download_tasks (NULL, NULL); return TRUE; } static gboolean elektroid_local_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data) { if (event->type != GDK_KEY_PRESS) { return FALSE; } if (!(event->state & GDK_CONTROL_MASK) || event->keyval != GDK_KEY_Right) { return elektroid_common_key_press (widget, event, data); } if (remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE) { //Slot mode needs a slot destination. return FALSE; } if (!remote_browser.fs_ops->upload) { return FALSE; } elektroid_add_upload_tasks (NULL, NULL); return TRUE; } static void elektroid_set_fs (GtkWidget *object, gpointer data) { GtkTreeIter iter; GValue fsv = G_VALUE_INIT; gint fs; gboolean editor_visible; if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (fs_combo), &iter)) { local_browser.fs_ops = &FS_LOCAL_SAMPLE_OPERATIONS; browser_update_fs_options (&local_browser); browser_load_dir (&local_browser); browser_reset (&remote_browser); browser_update_fs_options (&remote_browser); gtk_widget_set_visible (editor.box, TRUE); editor_set_audio_mono_mix (&editor); return; } gtk_tree_model_get_value (GTK_TREE_MODEL (fs_list_store), &iter, FS_LIST_STORE_ID_FIELD, &fsv); fs = g_value_get_uint (&fsv); g_value_unset (&fsv); remote_browser.fs_ops = backend_get_fs_operations_by_id (&backend, fs); editor_visible = remote_browser.fs_ops->options & FS_OPTION_SAMPLE_EDITOR ? TRUE : FALSE; if (editor_visible) { local_browser.fs_ops = &FS_LOCAL_SAMPLE_OPERATIONS; } else { local_browser.fs_ops = &FS_LOCAL_GENERIC_OPERATIONS; editor_reset (&editor, NULL); } editor_set_audio_mono_mix (&editor); if (backend.type == BE_TYPE_SYSTEM) { if (!remote_browser.dir) { gchar *dir = strdup (preferences_get_string (PREF_KEY_REMOTE_DIR)); remote_browser.dir = dir; } } else { if (remote_browser.dir) { g_free (remote_browser.dir); } remote_browser.dir = strdup ("/"); } gtk_widget_set_visible (editor.box, editor_visible); gtk_drag_source_unset ((GtkWidget *) remote_browser.view); gtk_drag_dest_unset ((GtkWidget *) remote_browser.view); if (remote_browser.fs_ops->upload) { if (backend.type == BE_TYPE_SYSTEM) { gtk_drag_dest_set ((GtkWidget *) remote_browser.view, GTK_DEST_DEFAULT_ALL, TARGET_ENTRIES_REMOTE_SYSTEM_DST, G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_SYSTEM_DST), GDK_ACTION_COPY | GDK_ACTION_MOVE); } else { if (remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE) { gtk_drag_dest_set ((GtkWidget *) remote_browser.view, GTK_DEST_DEFAULT_ALL, TARGET_ENTRIES_REMOTE_MIDI_DST_SLOT, G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_MIDI_DST_SLOT), GDK_ACTION_COPY); } else { gtk_drag_dest_set ((GtkWidget *) remote_browser.view, GTK_DEST_DEFAULT_ALL, TARGET_ENTRIES_REMOTE_MIDI_DST, G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_MIDI_DST), GDK_ACTION_COPY); } } } if (remote_browser.fs_ops->download) { if (backend.type == BE_TYPE_SYSTEM) { gtk_drag_source_set ((GtkWidget *) remote_browser.view, GDK_BUTTON1_MASK, TARGET_ENTRIES_REMOTE_SYSTEM_SRC, G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_SYSTEM_SRC), GDK_ACTION_COPY | GDK_ACTION_MOVE); } else { if (remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE) { gtk_drag_source_set ((GtkWidget *) remote_browser.view, GDK_BUTTON1_MASK, TARGET_ENTRIES_REMOTE_MIDI_SRC, G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_MIDI_SRC), GDK_ACTION_COPY); } else { gtk_drag_source_set ((GtkWidget *) remote_browser.view, GDK_BUTTON1_MASK, TARGET_ENTRIES_REMOTE_MIDI_SRC, G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_MIDI_SRC), GDK_ACTION_COPY); } } } browser_close_search (NULL, &local_browser); //This triggers a refresh browser_update_fs_options (&local_browser); browser_close_search (NULL, &remote_browser); //This triggers a refresh browser_update_fs_options (&remote_browser); } static gboolean elektroid_fill_fs_combo_bg (gpointer data) { const struct fs_operations *fs_ops; GSList *e; gboolean any = FALSE; g_signal_handlers_block_by_func (fs_combo, G_CALLBACK (elektroid_set_fs), NULL); gtk_list_store_clear (fs_list_store); e = backend.fs_ops; while (e) { fs_ops = e->data; if (fs_ops->gui_name) { any = TRUE; gtk_list_store_insert_with_values (fs_list_store, NULL, -1, FS_LIST_STORE_ID_FIELD, fs_ops->id, FS_LIST_STORE_ICON_FIELD, fs_ops->gui_icon, FS_LIST_STORE_NAME_FIELD, fs_ops->gui_name, -1); } e = e->next; } g_signal_handlers_unblock_by_func (fs_combo, G_CALLBACK (elektroid_set_fs), NULL); if (any) { debug_print (1, "Selecting first filesystem..."); gtk_combo_box_set_active (GTK_COMBO_BOX (fs_combo), 0); } return FALSE; } static gpointer elektroid_set_device_runner (gpointer data) { struct backend_device *be_sys_device = data; progress.sysex_transfer.active = TRUE; progress.sysex_transfer.err = backend_init_connector (&backend, be_sys_device, NULL, &progress.sysex_transfer); elektroid_update_midi_status (); progress_response (backend_check (&backend) ? GTK_RESPONSE_ACCEPT : GTK_RESPONSE_CANCEL); return NULL; } static void elektroid_set_device (GtkWidget *object, gpointer data) { GtkTreeIter iter; gchar *id, *name; gint dres, err; struct backend_device be_sys_device; elektroid_cancel_all_tasks_and_wait (); if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (devices_combo), &iter)) { return; } elektroid_set_preferences_remote_dir (); if (backend_check (&backend)) { backend_destroy (&backend); } gtk_tree_model_get (GTK_TREE_MODEL (devices_list_store), &iter, DEVICES_LIST_STORE_TYPE_FIELD, &be_sys_device.type, DEVICES_LIST_STORE_ID_FIELD, &id, DEVICES_LIST_STORE_NAME_FIELD, &name, -1); strcpy (be_sys_device.id, id); strcpy (be_sys_device.name, name); g_free (id); g_free (name); maction_menu_clear (&maction_context); if (be_sys_device.type == BE_TYPE_SYSTEM) { backend_init_connector (&backend, &be_sys_device, NULL, NULL); elektroid_update_midi_status (); err = 0; } else { progress_run (elektroid_set_device_runner, PROGRESS_TYPE_PULSE, &be_sys_device, _("Connecting to Device"), _("Connecting..."), TRUE, &dres); if (progress.sysex_transfer.err && progress.sysex_transfer.err != -ECANCELED) { error_print ("Error while connecting: %s", g_strerror (-progress.sysex_transfer.err)); show_error_msg (_("Device “%s” not recognized: %s"), be_sys_device.name, g_strerror (-progress.sysex_transfer.err)); } elektroid_check_backend (FALSE); err = dres == GTK_RESPONSE_ACCEPT ? 0 : 1; } if (err) { gtk_combo_box_set_active (GTK_COMBO_BOX (devices_combo), -1); } else { elektroid_fill_fs_combo_bg (NULL); maction_menu_setup (&maction_context); } } static void elektroid_dnd_received_browser (const gchar *dir, const gchar *name, const gchar *filename, struct browser *browser) { gchar *dst_path; gint res; enum path_type type = backend_get_path_type (browser->backend); if (strcmp (dir, browser->dir)) { dst_path = path_chain (type, browser->dir, name); res = browser->fs_ops->move (browser->backend, filename, dst_path); if (res) { error_print ("Error while moving from “%s” to “%s”: %s.", filename, dst_path, g_strerror (-res)); } g_free (dst_path); g_idle_add (browser_load_dir_if_needed, browser); } else { debug_print (1, MSG_WARN_SAME_SRC_DST); } } static void elektroid_add_upload_task_slot (const gchar *name, const gchar *src_file_path, gint slot) { GtkTreeIter iter; struct item item; gchar *dst_file_path, *filename; GString *str; GtkTreeModel *model = gtk_tree_view_get_model (remote_browser.view); if (gtk_tree_model_get_iter (model, &iter, remote_browser.dnd_motion_path)) { for (gint i = 0; i < slot; i++) { if (!gtk_tree_model_iter_next (model, &iter)) { return; } } browser_set_item (model, &iter, &item); filename = item_get_filename (&item, remote_browser.fs_ops->options); str = g_string_new (NULL); g_string_append_printf (str, "%s%s%s", remote_browser.dir, strcmp (remote_browser.dir, "/") ? "/" : "", filename); g_free (filename); dst_file_path = g_string_free (str, FALSE); tasks_add (&tasks, TASK_TYPE_UPLOAD, src_file_path, dst_file_path, remote_browser.fs_ops->id, &backend); } } static gpointer elektroid_dnd_received_runner_dialog (gpointer data) { GtkTreeIter iter; gboolean queued_before, queued_after; struct elektroid_dnd_data *dnd_data = data; GtkWidget *widget = dnd_data->widget; progress.sysex_transfer.active = TRUE; queued_before = tasks_get_next_queued (&tasks, &iter, NULL, NULL, NULL, NULL, NULL, NULL); for (gint i = 0; dnd_data->uris[i] != NULL; i++) { if (!progress_is_active ()) { goto end; } enum path_type type = PATH_TYPE_FROM_DND_TYPE (dnd_data->type_name); gchar *src_path = path_filename_from_uri (type, dnd_data->uris[i]); gchar *name = g_path_get_basename (src_path); gchar *dir = g_path_get_dirname (src_path); if (widget == GTK_WIDGET (local_browser.view)) { if (!strcmp (dnd_data->type_name, TEXT_URI_LIST_STD)) { elektroid_dnd_received_browser (dir, name, src_path, &local_browser); } else if (!strcmp (dnd_data->type_name, TEXT_URI_LIST_ELEKTROID)) { elektroid_add_download_task_path (name, dir, local_browser.dir); } } else if (widget == GTK_WIDGET (remote_browser.view)) { if (!strcmp (dnd_data->type_name, TEXT_URI_LIST_ELEKTROID)) { elektroid_dnd_received_browser (dir, name, src_path, &remote_browser); } else if (!strcmp (dnd_data->type_name, TEXT_URI_LIST_STD)) { if (remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE) { elektroid_add_upload_task_slot (name, src_path, i); } else { elektroid_add_upload_task_path (name, dir, remote_browser.dir); } } } g_free (name); g_free (dir); g_free (src_path); } end: queued_after = tasks_get_next_queued (&tasks, &iter, NULL, NULL, NULL, NULL, NULL, NULL); if (!queued_before && queued_after) { g_idle_add (elektroid_run_next, NULL); } progress_response (GTK_RESPONSE_ACCEPT); g_free (dnd_data->type_name); g_strfreev (dnd_data->uris); g_free (dnd_data); return NULL; } static void elektroid_dnd_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, gpointer userdata) { gchar *data; GdkAtom type; const gchar *title, *text; gboolean blocking = TRUE; gchar *filename, *src_dir, *dst_dir = NULL; struct elektroid_dnd_data *dnd_data; if (!gtk_selection_data_get_length (selection_data)) { gtk_drag_finish (context, TRUE, TRUE, time); error_print ("DND invalid data"); return; } if (widget == GTK_WIDGET (remote_browser.view) && (remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE) && remote_browser.dnd_motion_path == NULL) { gtk_drag_finish (context, TRUE, TRUE, time); error_print ("DND destination needs a slot"); return; } dnd_data = g_malloc (sizeof (struct elektroid_dnd_data)); dnd_data->widget = widget; type = gtk_selection_data_get_data_type (selection_data); dnd_data->type_name = gdk_atom_name (type); data = (gchar *) gtk_selection_data_get_data (selection_data); debug_print (1, "DND received batch %d data (%s):\n%s", batch_id, dnd_data->type_name, data); dnd_data->uris = g_uri_list_extract_uris (data); gtk_drag_finish (context, TRUE, TRUE, time); enum path_type path_type = PATH_TYPE_FROM_DND_TYPE (dnd_data->type_name); filename = path_filename_from_uri (path_type, dnd_data->uris[0]); src_dir = g_path_get_dirname (filename); //Checking if it's a local move. if (widget == GTK_WIDGET (local_browser.view) && !strcmp (dnd_data->type_name, TEXT_URI_LIST_STD)) { dst_dir = local_browser.dir; //Move } //Checking if it's a remote move. if (widget == GTK_WIDGET (remote_browser.view) && !strcmp (dnd_data->type_name, TEXT_URI_LIST_ELEKTROID)) { dst_dir = remote_browser.dir; //Move } if (dst_dir) { // If we are moving a file (source and destination is the same browser) and the // basedir of the first URI (every URI will share the same basename), equals // the browser directory, there's nothing to do. if (!strcmp (src_dir, dst_dir)) { debug_print (1, MSG_WARN_SAME_SRC_DST); goto end; } title = _("Moving Files"); text = _("Moving..."); if (!strcmp (dnd_data->type_name, TEXT_URI_LIST_STD) || (!strcmp (dnd_data->type_name, TEXT_URI_LIST_ELEKTROID) && backend.type == BE_TYPE_SYSTEM)) { //Moving inside the local browser takes no time. blocking = FALSE; } } else { title = _("Preparing Tasks"); text = _("Waiting..."); } if (blocking) { progress_run (elektroid_dnd_received_runner_dialog, PROGRESS_TYPE_PULSE, dnd_data, title, text, TRUE, NULL); batch_id++; } else { elektroid_dnd_received_runner_dialog (dnd_data); } end: g_free (filename); g_free (src_dir); } static void elektroid_dnd_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data) { struct browser *browser = user_data; debug_print (1, "Creating DND data..."); gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (guchar *) browser->dnd_data->str, browser->dnd_data->len); } static gboolean elektroid_drag_list_timeout (gpointer user_data) { struct browser *browser = user_data; gchar *spath; spath = gtk_tree_path_to_string (browser->dnd_motion_path); debug_print (2, "Getting into path: %s...", spath); g_free (spath); browser_item_activated (browser->view, browser->dnd_motion_path, NULL, browser); gtk_tree_path_free (browser->dnd_motion_path); browser_clear_dnd_function (browser); browser->dnd_motion_path = NULL; return FALSE; } static gboolean elektroid_drag_scroll_up_timeout (gpointer user_data) { GtkTreePath *start; struct browser *browser = user_data; debug_print (2, "Scrolling up..."); gtk_tree_view_get_visible_range (browser->view, &start, NULL); for (guint i = 0; i < TREEVIEW_SCROLL_LINES; i++) { gtk_tree_path_prev (start); } gtk_tree_view_scroll_to_cell (browser->view, start, NULL, FALSE, .0, .0); gtk_tree_path_free (start); browser_set_dnd_function (browser, elektroid_drag_scroll_up_timeout); return TRUE; } static gboolean elektroid_drag_scroll_down_timeout (gpointer user_data) { GtkTreePath *end; struct browser *browser = user_data; debug_print (2, "Scrolling down..."); gtk_tree_view_get_visible_range (browser->view, NULL, &end); for (guint i = 0; i < TREEVIEW_SCROLL_LINES; i++) { gtk_tree_path_next (end); } gtk_tree_view_scroll_to_cell (browser->view, end, NULL, FALSE, .0, .0); gtk_tree_path_free (end); browser_set_dnd_function (browser, elektroid_drag_scroll_down_timeout); return TRUE; } static gboolean elektroid_drag_motion_list (GtkWidget *widget, GdkDragContext *context, gint wx, gint wy, guint time, gpointer user_data) { GtkTreePath *path; GtkTreeModel *model; GtkTreeIter iter; gchar *spath; gint tx, ty; gboolean slot; GtkTreeSelection *selection; struct item item; struct browser *browser = user_data; slot = GTK_TREE_VIEW (widget) == remote_browser.view && remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE; gtk_tree_view_convert_widget_to_bin_window_coords (browser->view, wx, wy, &tx, &ty); if (gtk_tree_view_get_path_at_pos (browser->view, tx, ty, &path, NULL, NULL, NULL)) { GtkAllocation allocation; gtk_widget_get_allocation (widget, &allocation); spath = gtk_tree_path_to_string (path); debug_print (2, "Drag motion path: %s", spath); g_free (spath); if (slot) { gtk_tree_view_set_drag_dest_row (browser->view, path, GTK_TREE_VIEW_DROP_INTO_OR_BEFORE); } else { selection = gtk_tree_view_get_selection (browser->view); if (gtk_tree_selection_path_is_selected (selection, path)) { browser_clear_dnd_function (browser); return TRUE; } } model = gtk_tree_view_get_model (browser->view); gtk_tree_model_get_iter (model, &iter, path); browser_set_item (model, &iter, &item); if (item.type == ITEM_TYPE_DIR && (!browser->dnd_motion_path || (browser->dnd_motion_path && gtk_tree_path_compare (browser->dnd_motion_path, path)))) { browser_set_dnd_function (browser, elektroid_drag_list_timeout); } if (ty < TREEVIEW_EDGE_SIZE) { browser_set_dnd_function (browser, elektroid_drag_scroll_up_timeout); } else if (wy > allocation.height - TREEVIEW_EDGE_SIZE) { browser_set_dnd_function (browser, elektroid_drag_scroll_down_timeout); } } else { browser_clear_dnd_function (browser); if (slot) { gtk_tree_view_set_drag_dest_row (browser->view, NULL, GTK_TREE_VIEW_DROP_INTO_OR_BEFORE); } } if (browser->dnd_motion_path) { gtk_tree_path_free (browser->dnd_motion_path); browser->dnd_motion_path = NULL; } browser->dnd_motion_path = path; return TRUE; } static void elektroid_drag_leave_list (GtkWidget *widget, GdkDragContext *context, guint time, gpointer user_data) { browser_clear_dnd_function (user_data); } static gboolean elektroid_drag_up_timeout (gpointer user_data) { struct browser *browser = user_data; browser_go_up (NULL, browser); return TRUE; } static gboolean elektroid_drag_motion_up (GtkWidget *widget, GdkDragContext *context, gint wx, gint wy, guint time, gpointer user_data) { struct browser *browser = user_data; browser_set_dnd_function (browser, elektroid_drag_up_timeout); return TRUE; } static void elektroid_drag_leave_up (GtkWidget *widget, GdkDragContext *context, guint time, gpointer user_data) { browser_clear_dnd_function (user_data); } static void elektroid_set_window_size () { GdkRectangle geometry; GdkDisplay *display = gdk_display_get_default (); GdkMonitor *monitor = gdk_display_get_monitor (display, 0); gdk_monitor_get_geometry (monitor, &geometry); if (geometry.height >= 800) { gtk_window_resize (main_window, 1024, 768); } else { gtk_window_maximize (main_window); } } static void elektroid_exit () { gtk_dialog_response (GTK_DIALOG (about_dialog), GTK_RESPONSE_CANCEL); progress_response (GTK_RESPONSE_CANCEL); if (dialog) { gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); } progress_stop_thread (); tasks_stop_thread (&tasks); editor_stop_load_thread (&editor); browser_destroy (&local_browser); browser_destroy (&remote_browser); editor_destroy (&editor); if (backend_check (&backend)) { backend_destroy (&backend); } gtk_widget_destroy (GTK_WIDGET (main_window)); g_object_unref (builder); } static gboolean elektroid_delete_window (GtkWidget *widget, GdkEvent *event, gpointer data) { elektroid_exit (); return FALSE; } static void build_ui () { GtkCssProvider *css_provider; GtkWidget *refresh_devices_button; gchar *thanks; builder = gtk_builder_new (); gtk_builder_add_from_file (builder, DATADIR "/gui.glade", NULL); css_provider = gtk_css_provider_new (); gtk_css_provider_load_from_path (css_provider, DATADIR "/gui.css", NULL); gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider), GTK_STYLE_PROVIDER_PRIORITY_USER); main_window = GTK_WINDOW (gtk_builder_get_object (builder, "main_window")); about_dialog = GTK_ABOUT_DIALOG (gtk_builder_get_object (builder, "about_dialog")); gtk_about_dialog_set_version (about_dialog, PACKAGE_VERSION); if (g_file_get_contents (DATADIR "/THANKS", &thanks, NULL, NULL)) { gchar *last_new_line = strrchr (thanks, '\n'); if (last_new_line != NULL) { *last_new_line = 0; } gchar **lines = g_strsplit (thanks, "\n", 0); gtk_about_dialog_add_credit_section (about_dialog, _("Acknowledgements"), (const gchar **) lines); g_free (thanks); g_strfreev (lines); } name_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "name_dialog")); name_dialog_accept_button = GTK_WIDGET (gtk_builder_get_object (builder, "name_dialog_accept_button")); name_dialog_entry = GTK_ENTRY (gtk_builder_get_object (builder, "name_dialog_entry")); preferences_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "preferences_dialog")); play_sample_while_loading_switch = GTK_WIDGET (gtk_builder_get_object (builder, "play_sample_while_loading_switch")); audio_buffer_length_combo = GTK_WIDGET (gtk_builder_get_object (builder, "audio_buffer_length_combo")); stop_device_when_connecting_switch = GTK_WIDGET (gtk_builder_get_object (builder, "stop_device_when_connecting_switch")); elektron_load_sound_tags_switch = GTK_WIDGET (gtk_builder_get_object (builder, "elektron_load_sound_tags_switch")); maction_context.box = GTK_WIDGET (gtk_builder_get_object (builder, "menu_actions_box")); main_popover = GTK_POPOVER (gtk_builder_get_object (builder, "main_popover")); gtk_popover_set_constrain_to (main_popover, GTK_POPOVER_CONSTRAINT_NONE); show_remote_button = GTK_WIDGET (gtk_builder_get_object (builder, "show_remote_button")); g_object_set (G_OBJECT (show_remote_button), "role", GTK_BUTTON_ROLE_CHECK, NULL); preferences_button = GTK_WIDGET (gtk_builder_get_object (builder, "preferences_button")); about_button = GTK_WIDGET (gtk_builder_get_object (builder, "about_button")); local_name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "local_name_entry")); remote_devices_box = GTK_WIDGET (gtk_builder_get_object (builder, "remote_devices_box")); local_box = GTK_WIDGET (gtk_builder_get_object (builder, "local_box")); remote_box = GTK_WIDGET (gtk_builder_get_object (builder, "remote_box")); local_side = GTK_WIDGET (gtk_builder_get_object (builder, "local_side")); remote_side = GTK_WIDGET (gtk_builder_get_object (builder, "remote_side")); tasks_box = GTK_WIDGET (gtk_builder_get_object (builder, "tasks_box")); backend_status_label = GTK_LABEL (gtk_builder_get_object (builder, "backend_status_label")); host_audio_status_label = GTK_LABEL (gtk_builder_get_object (builder, "host_audio_status_label")); host_midi_status_label = GTK_LABEL (gtk_builder_get_object (builder, "host_midi_status_label")); g_signal_connect (GTK_WIDGET (main_window), "delete-event", G_CALLBACK (elektroid_delete_window), NULL); g_signal_connect (show_remote_button, "clicked", G_CALLBACK (elektroid_show_remote_clicked), NULL); g_signal_connect (preferences_button, "clicked", G_CALLBACK (elektroid_show_preferences), NULL); g_signal_connect (about_button, "clicked", G_CALLBACK (elektroid_show_about), NULL); g_signal_connect (name_dialog_entry, "changed", G_CALLBACK (elektroid_name_dialog_entry_changed), NULL); browser_remote_init (&remote_browser, builder, &backend); g_signal_connect (remote_browser.transfer_menuitem, "activate", G_CALLBACK (elektroid_add_download_tasks), NULL); g_signal_connect (remote_browser.play_menuitem, "activate", G_CALLBACK (editor_play_clicked), &editor); g_signal_connect (remote_browser.open_menuitem, "activate", G_CALLBACK (elektroid_open_clicked), &remote_browser); g_signal_connect (remote_browser.show_menuitem, "activate", G_CALLBACK (elektroid_show_clicked), &remote_browser); g_signal_connect (remote_browser.rename_menuitem, "activate", G_CALLBACK (elektroid_rename_item), &remote_browser); g_signal_connect (remote_browser.delete_menuitem, "activate", G_CALLBACK (elektroid_delete_files), &remote_browser); browser_local_init (&local_browser, builder, strdup (preferences_get_string (PREF_KEY_LOCAL_DIR))); g_signal_connect (local_browser.transfer_menuitem, "activate", G_CALLBACK (elektroid_add_upload_tasks), NULL); g_signal_connect (local_browser.play_menuitem, "activate", G_CALLBACK (editor_play_clicked), &editor); g_signal_connect (local_browser.open_menuitem, "activate", G_CALLBACK (elektroid_open_clicked), &local_browser); g_signal_connect (local_browser.show_menuitem, "activate", G_CALLBACK (elektroid_show_clicked), &local_browser); g_signal_connect (local_browser.rename_menuitem, "activate", G_CALLBACK (elektroid_rename_item), &local_browser); g_signal_connect (local_browser.delete_menuitem, "activate", G_CALLBACK (elektroid_delete_files), &local_browser); g_signal_connect (gtk_tree_view_get_selection (remote_browser.view), "changed", G_CALLBACK (browser_selection_changed), &remote_browser); g_signal_connect (remote_browser.view, "row-activated", G_CALLBACK (browser_item_activated), &remote_browser); g_signal_connect (remote_browser.up_button, "clicked", G_CALLBACK (browser_go_up), &remote_browser); g_signal_connect (remote_browser.add_dir_button, "clicked", G_CALLBACK (elektroid_add_dir), &remote_browser); g_signal_connect (remote_browser.refresh_button, "clicked", G_CALLBACK (browser_refresh), &remote_browser); g_signal_connect (remote_browser.search_button, "clicked", G_CALLBACK (browser_open_search), &remote_browser); g_signal_connect (remote_browser.search_entry, "stop-search", G_CALLBACK (browser_close_search), &remote_browser); g_signal_connect (remote_browser.search_entry, "search-changed", G_CALLBACK (browser_search_changed), &remote_browser); g_signal_connect (remote_browser.view, "button-press-event", G_CALLBACK (elektroid_button_press), &remote_browser); g_signal_connect (remote_browser.view, "button-release-event", G_CALLBACK (elektroid_button_release), &remote_browser); g_signal_connect (remote_browser.view, "key-press-event", G_CALLBACK (elektroid_remote_key_press), &remote_browser); g_signal_connect (remote_browser.view, "drag-begin", G_CALLBACK (elektroid_drag_begin), &remote_browser); g_signal_connect (remote_browser.view, "drag-end", G_CALLBACK (elektroid_drag_end), &remote_browser); g_signal_connect (remote_browser.view, "drag-data-get", G_CALLBACK (elektroid_dnd_get), &remote_browser); g_signal_connect (remote_browser.view, "drag-data-received", G_CALLBACK (elektroid_dnd_received), NULL); g_signal_connect (remote_browser.view, "drag-motion", G_CALLBACK (elektroid_drag_motion_list), &remote_browser); g_signal_connect (remote_browser.view, "drag-leave", G_CALLBACK (elektroid_drag_leave_list), &remote_browser); g_signal_connect (remote_browser.up_button, "drag-motion", G_CALLBACK (elektroid_drag_motion_up), &remote_browser); g_signal_connect (remote_browser.up_button, "drag-leave", G_CALLBACK (elektroid_drag_leave_up), &remote_browser); gtk_drag_dest_set ((GtkWidget *) remote_browser.up_button, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT, TARGET_ENTRIES_UP_BUTTON_DST, G_N_ELEMENTS (TARGET_ENTRIES_UP_BUTTON_DST), GDK_ACTION_COPY | GDK_ACTION_MOVE); g_signal_connect (gtk_tree_view_get_selection (local_browser.view), "changed", G_CALLBACK (browser_selection_changed), &local_browser); g_signal_connect (local_browser.view, "row-activated", G_CALLBACK (browser_item_activated), &local_browser); g_signal_connect (local_browser.up_button, "clicked", G_CALLBACK (browser_go_up), &local_browser); g_signal_connect (local_browser.add_dir_button, "clicked", G_CALLBACK (elektroid_add_dir), &local_browser); g_signal_connect (local_browser.refresh_button, "clicked", G_CALLBACK (browser_refresh), &local_browser); g_signal_connect (local_browser.search_button, "clicked", G_CALLBACK (browser_open_search), &local_browser); g_signal_connect (local_browser.search_entry, "stop-search", G_CALLBACK (browser_close_search), &local_browser); g_signal_connect (local_browser.search_entry, "search-changed", G_CALLBACK (browser_search_changed), &local_browser); g_signal_connect (local_browser.view, "button-press-event", G_CALLBACK (elektroid_button_press), &local_browser); g_signal_connect (local_browser.view, "button-release-event", G_CALLBACK (elektroid_button_release), &local_browser); g_signal_connect (local_browser.view, "key-press-event", G_CALLBACK (elektroid_local_key_press), &local_browser); g_signal_connect (local_browser.view, "drag-begin", G_CALLBACK (elektroid_drag_begin), &local_browser); g_signal_connect (local_browser.view, "drag-end", G_CALLBACK (elektroid_drag_end), &local_browser); g_signal_connect (local_browser.view, "drag-data-get", G_CALLBACK (elektroid_dnd_get), &local_browser); g_signal_connect (local_browser.view, "drag-data-received", G_CALLBACK (elektroid_dnd_received), NULL); g_signal_connect (local_browser.view, "drag-motion", G_CALLBACK (elektroid_drag_motion_list), &local_browser); g_signal_connect (local_browser.view, "drag-leave", G_CALLBACK (elektroid_drag_leave_list), &local_browser); g_signal_connect (local_browser.up_button, "drag-motion", G_CALLBACK (elektroid_drag_motion_up), &local_browser); g_signal_connect (local_browser.up_button, "drag-leave", G_CALLBACK (elektroid_drag_leave_up), &local_browser); gtk_drag_source_set ((GtkWidget *) local_browser.view, GDK_BUTTON1_MASK, TARGET_ENTRIES_LOCAL_SRC, G_N_ELEMENTS (TARGET_ENTRIES_LOCAL_SRC), GDK_ACTION_COPY | GDK_ACTION_MOVE); gtk_drag_dest_set ((GtkWidget *) local_browser.view, GTK_DEST_DEFAULT_ALL, TARGET_ENTRIES_LOCAL_DST, G_N_ELEMENTS (TARGET_ENTRIES_LOCAL_DST), GDK_ACTION_COPY | GDK_ACTION_MOVE); gtk_drag_dest_set ((GtkWidget *) local_browser.up_button, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT, TARGET_ENTRIES_UP_BUTTON_DST, G_N_ELEMENTS (TARGET_ENTRIES_UP_BUTTON_DST), GDK_ACTION_COPY | GDK_ACTION_MOVE); devices_list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "devices_list_store")); devices_combo = GTK_WIDGET (gtk_builder_get_object (builder, "devices_combo")); refresh_devices_button = GTK_WIDGET (gtk_builder_get_object (builder, "refresh_devices_button")); g_signal_connect (devices_combo, "changed", G_CALLBACK (elektroid_set_device), NULL); g_signal_connect (refresh_devices_button, "clicked", G_CALLBACK (elektroid_refresh_devices_int), NULL); gtk_label_set_text (backend_status_label, _("Not connected")); fs_list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "fs_list_store")); fs_combo = GTK_WIDGET (gtk_builder_get_object (builder, "fs_combo")); g_signal_connect (fs_combo, "changed", G_CALLBACK (elektroid_set_fs), NULL); editor_init (&editor, builder); elektroid_update_midi_status (); tasks_init (&tasks, builder); progress_init (builder); g_object_set (G_OBJECT (show_remote_button), "active", preferences_get_boolean (PREF_KEY_SHOW_REMOTE), NULL); gtk_widget_set_sensitive (remote_box, FALSE); maction_context.backend = &backend; maction_context.audio = &editor.audio; maction_context.builder = builder; maction_context.parent = main_window; elektroid_show_remote (preferences_get_boolean (PREF_KEY_SHOW_REMOTE)); //This triggers both browsers initializations. gtk_entry_set_text (GTK_ENTRY (local_name_entry), hostname); elektroid_set_window_size (); } #if defined(__linux__) static gboolean elektroid_signal_handler (gpointer data) { elektroid_exit (); return FALSE; } #endif static void elektroid_startup (GApplication *gapp, gpointer *user_data) { if (local_dir) { preferences_set_string (PREF_KEY_LOCAL_DIR, get_system_startup_path (local_dir)); g_free (local_dir); } build_ui (); gtk_application_add_window (GTK_APPLICATION (gapp), GTK_WINDOW (main_window)); } static void elektroid_activate (GApplication *gapp, gpointer *user_data) { gtk_window_present (GTK_WINDOW (main_window)); } static gboolean elektroid_increment_debug_level (const gchar *option_name, const gchar *value, gpointer data, GError **error) { debug_level++; return TRUE; } const GOptionEntry CMD_PARAMS[] = { { .long_name = "verbosity", .short_name = 'v', .flags = G_OPTION_FLAG_NO_ARG, .arg = G_OPTION_ARG_CALLBACK, .arg_data = elektroid_increment_debug_level, .description = "Increase verbosity. For more verbosity use it more than once.", .arg_description = NULL, }, { .long_name = "local-directory", .short_name = 'l', .flags = G_OPTION_FLAG_NONE, .arg = G_OPTION_ARG_FILENAME, .arg_data = &local_dir, .description = "Local directory at startup", .arg_description = "DIRECTORY", }, {NULL} }; int main (int argc, char *argv[]) { gint err; GtkApplication *app; #if defined(__linux__) g_unix_signal_add (SIGHUP, elektroid_signal_handler, NULL); g_unix_signal_add (SIGINT, elektroid_signal_handler, NULL); g_unix_signal_add (SIGTERM, elektroid_signal_handler, NULL); #endif setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); hostname = g_get_host_name (); regconn_register (); regma_register (); regpref_register (); preferences_load (); app = gtk_application_new ("io.github.dagargo.Elektroid", G_APPLICATION_NON_UNIQUE); g_signal_connect (app, "startup", G_CALLBACK (elektroid_startup), NULL); g_signal_connect (app, "activate", G_CALLBACK (elektroid_activate), NULL); g_application_add_main_option_entries (G_APPLICATION (app), CMD_PARAMS); err = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); preferences_set_string (PREF_KEY_LOCAL_DIR, strdup (local_browser.dir)); elektroid_set_preferences_remote_dir (); preferences_save (); preferences_free (); regconn_unregister (); regma_unregister (); regpref_unregister (); return err; } elektroid-3.2.3/src/guirecorder.c000066400000000000000000000062321500236517400167540ustar00rootroot00000000000000/* * guirecorder.c * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "guirecorder.h" #include "audio.h" static gboolean guirecorder_set_monitor_level (gpointer data) { struct guirecorder *guirecorder = data; gtk_level_bar_set_value (guirecorder->monitor_levelbar, guirecorder->level); return FALSE; } void guirecorder_monitor_notifier (gpointer recorder, gdouble value) { struct guirecorder *guirecorder = recorder; guirecorder->level = value; g_idle_add (guirecorder_set_monitor_level, guirecorder); } guint guirecorder_get_channel_mask (struct guirecorder *guirecorder) { guint channel_mask = 0; GtkTreeIter iter; GtkComboBox *combo = GTK_COMBO_BOX (guirecorder->channels_combo); GtkTreeModel *model = gtk_combo_box_get_model (combo); if (gtk_combo_box_get_active_iter (combo, &iter)) { gtk_tree_model_get (model, &iter, CHANNELS_LIST_STORE_ID_FIELD, &channel_mask, -1); } return channel_mask; } void guirecorder_set_channels_masks (struct guirecorder *guirecorder, guint32 opts) { gtk_list_store_clear (guirecorder->channels_list_store); gtk_combo_box_set_active (GTK_COMBO_BOX (guirecorder->channels_combo), -1); if (opts & FS_OPTION_STEREO) { gtk_list_store_insert_with_values (guirecorder->channels_list_store, NULL, -1, CHANNELS_LIST_STORE_CAPTION_FIELD, /* TRANSLATORS: Stereo recording */ _("Stereo"), CHANNELS_LIST_STORE_ID_FIELD, RECORD_STEREO, -1); } if (opts & FS_OPTION_MONO) { gtk_list_store_insert_with_values (guirecorder->channels_list_store, NULL, -1, CHANNELS_LIST_STORE_CAPTION_FIELD, /* TRANSLATORS: Mono recording from left channel */ _("Left"), CHANNELS_LIST_STORE_ID_FIELD, RECORD_LEFT, -1); gtk_list_store_insert_with_values (guirecorder->channels_list_store, NULL, -1, CHANNELS_LIST_STORE_CAPTION_FIELD, /* TRANSLATORS: Mono recording from right channel */ _("Right"), CHANNELS_LIST_STORE_ID_FIELD, RECORD_RIGHT, -1); } gtk_combo_box_set_active (GTK_COMBO_BOX (guirecorder->channels_combo), 0); } void guirecorder_channels_changed (GtkWidget *object, gpointer data) { struct guirecorder *guirecorder = data; struct audio *audio = guirecorder->audio; guint options = guirecorder_get_channel_mask (guirecorder) | RECORD_MONITOR_ONLY; g_mutex_lock (&audio->control.mutex); audio->record_options = options; g_mutex_unlock (&audio->control.mutex); } elektroid-3.2.3/src/guirecorder.h000066400000000000000000000026541500236517400167650ustar00rootroot00000000000000/* * guirecorder.h * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef GUIRECORDER_H #define GUIRECORDER_H #include #include "connector.h" #include "audio.h" enum channels_list_store_columns { CHANNELS_LIST_STORE_CAPTION_FIELD, CHANNELS_LIST_STORE_ID_FIELD }; struct guirecorder { GtkWidget *channels_combo; GtkListStore *channels_list_store; GtkLevelBar *monitor_levelbar; struct audio *audio; gdouble level; }; void guirecorder_monitor_notifier (void *, gdouble); guint guirecorder_get_channel_mask (struct guirecorder *guirecorder); void guirecorder_set_channels_masks (struct guirecorder *guirecorder, guint32); void guirecorder_channels_changed (GtkWidget *, gpointer); #endif elektroid-3.2.3/src/local.c000066400000000000000000000032701500236517400155330ustar00rootroot00000000000000/* * local.c * Copyright (C) 2021 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "local.h" #include "connectors/system.h" const struct fs_operations FS_LOCAL_GENERIC_OPERATIONS = { .options = FS_OPTION_ALLOW_SEARCH, .name = "local", .gui_name = "localhost", .gui_icon = FS_ICON_GENERIC, .readdir = system_read_dir, .file_exists = system_file_exists, .mkdir = system_mkdir, .delete = system_delete, .rename = system_rename, .move = system_rename, .max_name_len = 255 }; const struct fs_operations FS_LOCAL_SAMPLE_OPERATIONS = { .options = FS_OPTION_SAMPLE_EDITOR | FS_OPTION_MONO | FS_OPTION_STEREO | FS_OPTION_SHOW_SAMPLE_COLUMNS | FS_OPTION_ALLOW_SEARCH, .name = "local", .gui_name = "localhost", .gui_icon = FS_ICON_WAVE, .readdir = system_samples_read_dir, .file_exists = system_file_exists, .mkdir = system_mkdir, .delete = system_delete, .rename = system_rename, .move = system_rename, .get_exts = sample_get_sample_extensions, .max_name_len = 255 }; elektroid-3.2.3/src/local.h000066400000000000000000000017421500236517400155420ustar00rootroot00000000000000/* * local.h * Copyright (C) 2021 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef LOCAL_H #define LOCAL_H #include "connector.h" #include "sample.h" extern const struct fs_operations FS_LOCAL_GENERIC_OPERATIONS; extern const struct fs_operations FS_LOCAL_SAMPLE_OPERATIONS; #endif elektroid-3.2.3/src/maction.c000066400000000000000000000054631500236517400161010ustar00rootroot00000000000000/* * maction.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "maction.h" GSList *mactions = NULL; struct maction_context maction_context; struct maction * maction_separator_builder (struct maction_context *context) { struct maction *ma = g_malloc (sizeof (struct maction)); ma->type = MACTION_SEPARATOR; return ma; } static GSList * maction_context_build_all (struct maction_context *context) { GSList *actions = NULL; GSList *i = mactions; struct maction *ma; while (i) { t_maction_builder builder = i->data; ma = builder (context); if (ma) { actions = g_slist_append (actions, ma); } i = i->next; } ma = maction_separator_builder (context); actions = g_slist_append (actions, ma); return actions; } static void maction_remove_widget (GtkWidget *widget, gpointer data) { struct maction_context *context = data; gtk_container_remove (GTK_CONTAINER (context->box), widget); } void maction_menu_clear (struct maction_context *context) { gtk_container_foreach (GTK_CONTAINER (context->box), maction_remove_widget, context); } static void maction_add (gpointer data, gpointer user_data) { struct maction *ma = data; struct maction_context *context = user_data; if (ma->type == MACTION_BUTTON) { context->separator = TRUE; GtkWidget *button = gtk_model_button_new (); g_object_set (button, "text", ma->name, NULL); gtk_widget_set_sensitive (button, ma->sensitive); gtk_widget_show (button); gtk_container_add (GTK_CONTAINER (context->box), button); g_signal_connect (button, "clicked", ma->callback, context); } else { if (context->separator) { GtkWidget *separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); gtk_container_add (GTK_CONTAINER (context->box), separator); gtk_widget_show (separator); } context->separator = FALSE; } } void maction_menu_setup (struct maction_context *context) { GSList *src = maction_context_build_all (context); context->separator = FALSE; g_slist_foreach (src, maction_add, context); g_slist_free_full (src, g_free); } elektroid-3.2.3/src/maction.h000066400000000000000000000031731500236517400161020ustar00rootroot00000000000000/* * maction.h * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef MACTION_H #define MACTION_H #include #include "backend.h" #include "audio.h" enum maction_type { MACTION_BUTTON, MACTION_SEPARATOR }; struct maction { enum maction_type type; const gchar *name; gboolean sensitive; GCallback callback; }; struct maction_context { GtkWidget *box; struct backend *backend; struct audio *audio; GtkBuilder *builder; GtkWindow *parent; gboolean separator; //This does not need to be initialized as it's used internally. }; extern GSList *mactions; extern struct maction_context maction_context; typedef struct maction *(*t_maction_builder) (struct maction_context * context); void maction_menu_clear (struct maction_context *context); void maction_menu_setup (struct maction_context *context); struct maction *maction_separator_builder (struct maction_context *context); #endif elektroid-3.2.3/src/mactions/000077500000000000000000000000001500236517400161105ustar00rootroot00000000000000elektroid-3.2.3/src/mactions/autosampler.c000066400000000000000000000223661500236517400206210ustar00rootroot00000000000000/* * autosampler.c * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include "maction.h" #include "editor.h" #include "audio.h" #include "sample.h" #include "progress.h" #include "connectors/system.h" #include "guirecorder.h" extern struct editor editor; extern struct browser local_browser; static GtkDialog *autosampler_dialog; static GtkEntry *autosampler_dialog_name_entry; static struct guirecorder autosampler_guirecorder; static GtkWidget *autosampler_dialog_channel_spin; static GtkWidget *autosampler_dialog_start_combo; static GtkWidget *autosampler_dialog_end_combo; static GtkWidget *autosampler_dialog_distance_spin; static GtkWidget *autosampler_dialog_velocity_spin; static GtkWidget *autosampler_dialog_press_spin; static GtkWidget *autosampler_dialog_release_spin; static GtkWidget *autosampler_dialog_start_button; static GtkListStore *notes_list_store; struct autosampler_data { const gchar *name; guint channel_mask; gint channel; gint first; gint last; gint semitones; gint velocity; gdouble press; gdouble release; struct backend *backend; GtkTreeIter iter; }; static gpointer autosampler_runner (gpointer user_data) { struct autosampler_data *data = user_data; const gchar *note; gint s, total, i; GValue value = G_VALUE_INIT; gdouble fract; gchar filename[LABEL_MAX]; struct sample_info *sample_info; progress.sysex_transfer.active = TRUE; progress_set_fraction (0.0); total = ((data->last - data->first) / data->semitones) + 1; s = 0; i = data->first; while (1) { gtk_tree_model_get_value (GTK_TREE_MODEL (notes_list_store), &data->iter, 0, &value); note = g_value_get_string (&value); debug_print (1, "Recording note %s (%d)...", note, i); audio_start_recording (&editor.audio, data->channel_mask, NULL, NULL); backend_send_note_on (data->backend, data->channel, i, data->velocity); //Add some extra time to deal with runtime delays. usleep ((data->press + 0.25) * 1000000); backend_send_note_off (data->backend, data->channel, i, data->velocity); usleep (data->release * 1000000); audio_stop_recording (&editor.audio); sample_info = editor.audio.sample.info; sample_info->midi_note = i; //Remove the heading silent frames. guint start = audio_detect_start (&editor.audio); audio_delete_range (&editor.audio, 0, start); //Cut off the frames after the requested time. start = (data->press + data->release) * editor.audio.rate; guint len = sample_info->frames - start; audio_delete_range (&editor.audio, start, len); gchar *dir = path_chain (PATH_SYSTEM, local_browser.dir, data->name); system_mkdir (NULL, dir); //We add the note number to ensure lexicographical order. snprintf (filename, LABEL_MAX, "%03d %s %s.wav", s, data->name, note); gchar *path = path_chain (PATH_SYSTEM, dir, filename); debug_print (1, "Saving sample to %s...", path); sample_save_to_file (path, &editor.audio.sample, &editor.audio.control, SF_FORMAT_WAV | SF_FORMAT_PCM_16); g_free (dir); g_free (path); g_value_unset (&value); for (gint j = 0; j < data->semitones; j++, i++) { gtk_tree_model_iter_next (GTK_TREE_MODEL (notes_list_store), &data->iter); } s++; fract = s / (gdouble) total; progress_set_fraction (fract); if (i > data->last) { break; } if (!progress_is_active ()) { break; } sleep (1); } g_free (data); progress_response (GTK_RESPONSE_ACCEPT); return NULL; } static void autosampler_callback (GtkWidget *object, gpointer user_data) { gint res; guint options; struct maction_context *context = user_data; struct autosampler_data *data = g_malloc (sizeof (struct autosampler_data)); data->backend = context->backend; guirecorder_set_channels_masks (&autosampler_guirecorder, FS_OPTION_STEREO | FS_OPTION_MONO); options = guirecorder_get_channel_mask (&autosampler_guirecorder) | RECORD_MONITOR_ONLY; audio_stop_playback (&editor.audio); audio_stop_recording (&editor.audio); audio_start_recording (&editor.audio, options, guirecorder_monitor_notifier, &autosampler_guirecorder); gtk_entry_set_text (autosampler_dialog_name_entry, ""); gtk_widget_grab_focus (GTK_WIDGET (autosampler_dialog_name_entry)); gtk_widget_set_sensitive (autosampler_dialog_start_button, FALSE); res = gtk_dialog_run (GTK_DIALOG (autosampler_dialog)); gtk_widget_hide (GTK_WIDGET (autosampler_dialog)); audio_stop_recording (&editor.audio); if (res != GTK_RESPONSE_ACCEPT) { return; } data->channel_mask = guirecorder_get_channel_mask (&autosampler_guirecorder); data->name = gtk_entry_get_text (autosampler_dialog_name_entry); data->channel = gtk_spin_button_get_value (GTK_SPIN_BUTTON (autosampler_dialog_channel_spin)); data->velocity = gtk_spin_button_get_value (GTK_SPIN_BUTTON (autosampler_dialog_velocity_spin)); data->first = gtk_combo_box_get_active (GTK_COMBO_BOX (autosampler_dialog_start_combo)); data->last = gtk_combo_box_get_active (GTK_COMBO_BOX (autosampler_dialog_end_combo)); data->semitones = gtk_spin_button_get_value (GTK_SPIN_BUTTON (autosampler_dialog_distance_spin)); data->press = gtk_spin_button_get_value (GTK_SPIN_BUTTON (autosampler_dialog_press_spin)); data->release = gtk_spin_button_get_value (GTK_SPIN_BUTTON (autosampler_dialog_release_spin)); gtk_combo_box_get_active_iter (GTK_COMBO_BOX (autosampler_dialog_start_combo), &data->iter); progress_run (autosampler_runner, PROGRESS_TYPE_NO_AUTO, data, _("Auto Sampler"), _("Recording..."), TRUE, NULL); } static void autosampler_dialog_name_changed (GtkWidget *object, gpointer data) { size_t len = strlen (gtk_entry_get_text (autosampler_dialog_name_entry)); gtk_widget_set_sensitive (autosampler_dialog_start_button, len > 0); } static void autosampler_configure_gui (struct backend *backend, GtkBuilder *builder) { if (autosampler_dialog) { return; } autosampler_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "autosampler_dialog")); autosampler_dialog_name_entry = GTK_ENTRY (gtk_builder_get_object (builder, "autosampler_dialog_name_entry")); autosampler_guirecorder.channels_combo = GTK_WIDGET (gtk_builder_get_object (builder, "autosampler_dialog_channels_combo")); autosampler_guirecorder.channels_list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "autosampler_dialog_channels_list_store")); autosampler_guirecorder.monitor_levelbar = GTK_LEVEL_BAR (gtk_builder_get_object (builder, "autosampler_dialog_monitor_levelbar")); autosampler_guirecorder.audio = &editor.audio; autosampler_dialog_channel_spin = GTK_WIDGET (gtk_builder_get_object (builder, "autosampler_dialog_channel_spin")); autosampler_dialog_start_combo = GTK_WIDGET (gtk_builder_get_object (builder, "autosampler_dialog_start_combo")); autosampler_dialog_end_combo = GTK_WIDGET (gtk_builder_get_object (builder, "autosampler_dialog_end_combo")); autosampler_dialog_distance_spin = GTK_WIDGET (gtk_builder_get_object (builder, "autosampler_dialog_distance_spin")); autosampler_dialog_velocity_spin = GTK_WIDGET (gtk_builder_get_object (builder, "autosampler_dialog_velocity_spin")); autosampler_dialog_press_spin = GTK_WIDGET (gtk_builder_get_object (builder, "autosampler_dialog_press_spin")); autosampler_dialog_release_spin = GTK_WIDGET (gtk_builder_get_object (builder, "autosampler_dialog_release_spin")); autosampler_dialog_start_button = GTK_WIDGET (gtk_builder_get_object (builder, "autosampler_dialog_start_button")); notes_list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "notes_list_store")); g_signal_connect (autosampler_dialog_name_entry, "changed", G_CALLBACK (autosampler_dialog_name_changed), NULL); g_signal_connect (autosampler_guirecorder.channels_combo, "changed", G_CALLBACK (guirecorder_channels_changed), &autosampler_guirecorder); } struct maction * autosampler_maction_builder (struct maction_context *context) { struct maction *ma = NULL; if (context->backend->type == BE_TYPE_MIDI) { ma = g_malloc (sizeof (struct maction)); ma->type = MACTION_BUTTON; ma->name = _("_Auto Sampler"); ma->sensitive = audio_check (context->audio); ma->callback = G_CALLBACK (autosampler_callback); } autosampler_configure_gui (context->backend, context->builder); return ma; } elektroid-3.2.3/src/mactions/backend.c000066400000000000000000000055221500236517400176470ustar00rootroot00000000000000/* * backend.c * Copyright (C) 2022 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "maction.h" //This is a bit of a hack as the backend function are implemented inside //elektroid.c. However, as these actions depend on the backend initialization, //it's convenient to implement the menus this way. extern gpointer elektroid_tx_upgrade_os_runner (gpointer data); extern gpointer elektroid_tx_sysex_files_runner (gpointer data); extern void elektroid_tx_sysex_common (GThreadFunc func, gboolean multiple); extern void elektroid_rx_sysex (); extern void elektroid_refresh_devices (gboolean startup); static void os_upgrade_callback (GtkWidget *object, gpointer data) { elektroid_tx_sysex_common (elektroid_tx_upgrade_os_runner, FALSE); elektroid_refresh_devices (FALSE); } static void tx_sysex_callback (GtkWidget *object, gpointer data) { elektroid_tx_sysex_common (elektroid_tx_sysex_files_runner, TRUE); } static void rx_sysex_callback (GtkWidget *object, gpointer data) { elektroid_rx_sysex (); } struct maction * backend_maction_os_upgrade_builder (struct maction_context *context) { struct maction *ma = NULL; if (context->backend->upgrade_os) { ma = g_malloc (sizeof (struct maction)); ma->type = MACTION_BUTTON; ma->name = _("OS _Upgrade"); ma->sensitive = TRUE; ma->callback = G_CALLBACK (os_upgrade_callback); } return ma; } struct maction * backend_maction_rx_sysex_builder (struct maction_context *context) { struct maction *ma = NULL; if (context->backend->type == BE_TYPE_MIDI) { ma = g_malloc (sizeof (struct maction)); ma->type = MACTION_BUTTON; ma->name = _("_Receive SysEx"); ma->sensitive = TRUE; ma->callback = G_CALLBACK (rx_sysex_callback); } return ma; } struct maction * backend_maction_tx_sysex_builder (struct maction_context *context) { struct maction *ma = NULL; if (context->backend->type == BE_TYPE_MIDI) { ma = g_malloc (sizeof (struct maction)); ma->type = MACTION_BUTTON; ma->name = _("_Send SysEx"); ma->sensitive = TRUE; ma->callback = G_CALLBACK (tx_sysex_callback); } return ma; } elektroid-3.2.3/src/mactions/microbrute.c000066400000000000000000000320521500236517400204310ustar00rootroot00000000000000/* * microbrute.c * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "maction.h" #include "connectors/microbrute.h" #include "utils.h" static guint8 channel; static GtkWidget *config_window = NULL; static GtkWidget *calibration_assistant; static GtkWidget *note_priority; static GtkWidget *vel_response; static GtkWidget *lfo_key_retrigger; static GtkWidget *envelope_legato; static GtkWidget *bend_range; static GtkWidget *gate_length; static GtkWidget *synchronization; static GtkWidget *tx_channel; static GtkWidget *rx_channel; static GtkWidget *retriggering; static GtkWidget *play; static GtkWidget *next_sequence; static GtkWidget *step_on; static GtkWidget *step_length; static GtkWidget *persistent_changes; static gboolean loading; static void microbrute_set_combo_value (GtkWidget *combo, guint8 value) { guint v; gint index = 0; GtkTreeIter iter; gboolean found = FALSE; GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); gboolean valid = gtk_tree_model_get_iter_first (model, &iter); while (valid) { gtk_tree_model_get (model, &iter, 1, &v, -1); if (v == value) { found = TRUE; break; } valid = gtk_tree_model_iter_next (model, &iter); index += 1; } if (found) { gtk_combo_box_set_active (GTK_COMBO_BOX (combo), index); } } static void microbrute_configure_callback (GtkWidget *object, gpointer data) { guint8 v; struct maction_context *context = data; struct backend *backend = context->backend; debug_print (2, "Configuring %s...", backend->name); loading = TRUE; microbrute_get_parameter (backend, MICROBRUTE_NOTE_PRIORITY, &v); microbrute_set_combo_value (note_priority, v); microbrute_get_parameter (backend, MICROBRUTE_VEL_RESPONSE, &v); microbrute_set_combo_value (vel_response, v); microbrute_get_parameter (backend, MICROBRUTE_LFO_KEY_RETRIGGER, &v); gtk_switch_set_state (GTK_SWITCH (lfo_key_retrigger), v); gtk_switch_set_active (GTK_SWITCH (lfo_key_retrigger), v); microbrute_get_parameter (backend, MICROBRUTE_ENVELOPE_LEGATO, &v); gtk_switch_set_state (GTK_SWITCH (envelope_legato), v); gtk_switch_set_active (GTK_SWITCH (envelope_legato), v); microbrute_get_parameter (backend, MICROBRUTE_BEND_RANGE, &v); gtk_spin_button_set_value (GTK_SPIN_BUTTON (bend_range), v); microbrute_get_parameter (backend, MICROBRUTE_STEP_LENGTH, &v); microbrute_set_combo_value (step_length, v); microbrute_get_parameter (backend, MICROBRUTE_GATE_LENGTH, &v); microbrute_set_combo_value (gate_length, v); microbrute_get_parameter (backend, MICROBRUTE_TX_CHANNEL, &v); microbrute_set_combo_value (tx_channel, v); microbrute_get_parameter (backend, MICROBRUTE_RX_CHANNEL, &channel); microbrute_set_combo_value (rx_channel, channel); microbrute_get_parameter (backend, MICROBRUTE_PLAY_ON, &v); microbrute_set_combo_value (play, v); microbrute_get_parameter (backend, MICROBRUTE_RETRIGGERING, &v); microbrute_set_combo_value (retriggering, v); microbrute_get_parameter (backend, MICROBRUTE_NEXT_SEQUENCE, &v); microbrute_set_combo_value (next_sequence, v); microbrute_get_parameter (backend, MICROBRUTE_STEP_ON, &v); microbrute_set_combo_value (step_on, v); microbrute_get_parameter (backend, MICROBRUTE_SYNC, &v); microbrute_set_combo_value (synchronization, v); loading = FALSE; gtk_widget_show (config_window); } static void microbrute_combo_changed (GtkComboBox *combo, struct backend *backend, guint8 param) { guint value; GtkTreeIter iter; gboolean sysex; GtkTreeModel *model; if (!loading) { model = gtk_combo_box_get_model (combo); sysex = gtk_switch_get_active (GTK_SWITCH (persistent_changes)); gtk_combo_box_get_active_iter (combo, &iter); gtk_tree_model_get (model, &iter, 1, &value, -1); microbrute_set_parameter (backend, param, value, channel, sysex); } } static gboolean microbrute_switch_state_set (struct backend *backend, guint8 param, guint8 state) { gboolean sysex; if (!loading) { sysex = gtk_switch_get_active (GTK_SWITCH (persistent_changes)); microbrute_set_parameter (backend, param, state, channel, sysex); } return FALSE; } static void microbrute_note_priority_changed (GtkComboBox *combo, gpointer data) { microbrute_combo_changed (combo, data, MICROBRUTE_NOTE_PRIORITY); } static void microbrute_vel_response_changed (GtkComboBox *combo, gpointer data) { microbrute_combo_changed (combo, data, MICROBRUTE_VEL_RESPONSE); } static gboolean microbrute_lfo_key_retrigger_state_set (GtkSwitch *s, gboolean state, gpointer data) { return microbrute_switch_state_set (data, MICROBRUTE_LFO_KEY_RETRIGGER, state); } static gboolean microbrute_envelope_legato_state_set (GtkSwitch *s, gboolean state, gpointer data) { return microbrute_switch_state_set (data, MICROBRUTE_ENVELOPE_LEGATO, state); } static void microbrute_bend_range_value_changed (GtkSpinButton *spin, gpointer data) { gboolean sysex; guint8 value; if (!loading) { sysex = gtk_switch_get_active (GTK_SWITCH (persistent_changes)); value = gtk_spin_button_get_value (spin); microbrute_set_parameter (data, MICROBRUTE_BEND_RANGE, value, channel, sysex); } } static void microbrute_gate_length_changed (GtkComboBox *combo, gpointer data) { microbrute_combo_changed (combo, data, MICROBRUTE_GATE_LENGTH); } static void microbrute_synchronization_changed (GtkComboBox *combo, gpointer data) { microbrute_combo_changed (combo, data, MICROBRUTE_SYNC); } static void microbrute_tx_channel_changed (GtkComboBox *combo, gpointer data) { microbrute_combo_changed (combo, data, MICROBRUTE_TX_CHANNEL); } static void microbrute_rx_channel_changed (GtkComboBox *combo, gpointer data) { microbrute_combo_changed (combo, data, MICROBRUTE_RX_CHANNEL); } static void microbrute_play_changed (GtkComboBox *combo, gpointer data) { microbrute_combo_changed (combo, data, MICROBRUTE_PLAY_ON); } static void microbrute_retriggering_changed (GtkComboBox *combo, gpointer data) { microbrute_combo_changed (combo, data, MICROBRUTE_RETRIGGERING); } static void microbrute_next_sequence_changed (GtkComboBox *combo, gpointer data) { microbrute_combo_changed (combo, data, MICROBRUTE_NEXT_SEQUENCE); } static void microbrute_step_on_changed (GtkComboBox *combo, gpointer data) { microbrute_combo_changed (combo, data, MICROBRUTE_STEP_ON); } static void microbrute_step_length_changed (GtkComboBox *combo, gpointer data) { microbrute_combo_changed (combo, data, MICROBRUTE_STEP_LENGTH); } static void microbrute_assistant_close (GtkWidget *assistant, gpointer data) { gtk_widget_hide (assistant); } static void microbrute_assistant_prepare (GtkAssistant *assistant, GtkWidget *page, gpointer data) { struct backend *backend = data; gint npage = gtk_assistant_get_current_page (assistant); switch (npage) { case 2: microbrute_set_parameter (backend, MICROBRUTE_CALIB_PB_CENTER, 0, channel, TRUE); break; case 3: microbrute_set_parameter (backend, MICROBRUTE_CALIB_BOTH_BOTTOM, 0, channel, TRUE); break; case 4: microbrute_set_parameter (backend, MICROBRUTE_CALIB_BOTH_TOP, 0, channel, TRUE); sleep (1); microbrute_set_parameter (backend, MICROBRUTE_CALIB_END, 0, channel, TRUE); break; } } static void microbrute_configure_gui (struct backend *backend, GtkWindow *parent) { if (config_window) { return; } GtkBuilder *builder = gtk_builder_new (); gtk_builder_add_from_file (builder, DATADIR "/microbrute/gui.glade", NULL); config_window = GTK_WIDGET (gtk_builder_get_object (builder, "config_window")); gtk_window_resize (GTK_WINDOW (config_window), 1, 1); gtk_window_set_transient_for (GTK_WINDOW (config_window), parent); note_priority = GTK_WIDGET (gtk_builder_get_object (builder, "note_priority")); vel_response = GTK_WIDGET (gtk_builder_get_object (builder, "vel_response")); lfo_key_retrigger = GTK_WIDGET (gtk_builder_get_object (builder, "lfo_key_retrigger")); envelope_legato = GTK_WIDGET (gtk_builder_get_object (builder, "envelope_legato")); bend_range = GTK_WIDGET (gtk_builder_get_object (builder, "bend_range")); gate_length = GTK_WIDGET (gtk_builder_get_object (builder, "gate_length")); synchronization = GTK_WIDGET (gtk_builder_get_object (builder, "synchronization")); tx_channel = GTK_WIDGET (gtk_builder_get_object (builder, "tx_channel")); rx_channel = GTK_WIDGET (gtk_builder_get_object (builder, "rx_channel")); play = GTK_WIDGET (gtk_builder_get_object (builder, "play")); retriggering = GTK_WIDGET (gtk_builder_get_object (builder, "retriggering")); next_sequence = GTK_WIDGET (gtk_builder_get_object (builder, "next_sequence")); step_on = GTK_WIDGET (gtk_builder_get_object (builder, "step_on")); step_length = GTK_WIDGET (gtk_builder_get_object (builder, "step_length")); persistent_changes = GTK_WIDGET (gtk_builder_get_object (builder, "persistent_changes")); g_signal_connect (note_priority, "changed", G_CALLBACK (microbrute_note_priority_changed), backend); g_signal_connect (note_priority, "changed", G_CALLBACK (microbrute_vel_response_changed), backend); g_signal_connect (lfo_key_retrigger, "state-set", G_CALLBACK (microbrute_lfo_key_retrigger_state_set), backend); g_signal_connect (envelope_legato, "state-set", G_CALLBACK (microbrute_envelope_legato_state_set), backend); g_signal_connect (bend_range, "value-changed", G_CALLBACK (microbrute_bend_range_value_changed), backend); g_signal_connect (gate_length, "changed", G_CALLBACK (microbrute_gate_length_changed), backend); g_signal_connect (synchronization, "changed", G_CALLBACK (microbrute_synchronization_changed), backend); g_signal_connect (tx_channel, "changed", G_CALLBACK (microbrute_tx_channel_changed), backend); g_signal_connect (rx_channel, "changed", G_CALLBACK (microbrute_rx_channel_changed), backend); g_signal_connect (play, "changed", G_CALLBACK (microbrute_play_changed), backend); g_signal_connect (retriggering, "changed", G_CALLBACK (microbrute_retriggering_changed), backend); g_signal_connect (next_sequence, "changed", G_CALLBACK (microbrute_next_sequence_changed), backend); g_signal_connect (step_on, "changed", G_CALLBACK (microbrute_step_on_changed), backend); g_signal_connect (step_length, "changed", G_CALLBACK (microbrute_step_length_changed), backend); g_signal_connect (config_window, "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), NULL); //Assistant calibration_assistant = GTK_WIDGET (gtk_builder_get_object (builder, "calibration_assistant")); gtk_window_set_transient_for (GTK_WINDOW (calibration_assistant), parent); g_signal_connect (calibration_assistant, "close", G_CALLBACK (microbrute_assistant_close), backend); g_signal_connect (calibration_assistant, "cancel", G_CALLBACK (microbrute_assistant_close), backend); g_signal_connect (calibration_assistant, "escape", G_CALLBACK (microbrute_assistant_close), backend); g_signal_connect (calibration_assistant, "prepare", G_CALLBACK (microbrute_assistant_prepare), backend); g_object_unref (G_OBJECT (builder)); } struct maction * microbrute_maction_conf_builder (struct maction_context *context) { struct maction *ma; if (!context->backend->conn_name || strcmp (context->backend->conn_name, MICROBRUTE_NAME)) { return NULL; } microbrute_configure_gui (context->backend, context->parent); ma = g_malloc (sizeof (struct maction)); ma->type = MACTION_BUTTON; ma->name = _("_Configuration"); ma->sensitive = TRUE; ma->callback = G_CALLBACK (microbrute_configure_callback); return ma; } static void microbrute_calibration_callback (GtkWidget *object, gpointer data) { gtk_widget_show (calibration_assistant); } struct maction * microbrute_maction_cal_builder (struct maction_context *context) { struct maction *ma; if (!context->backend->conn_name || strcmp (context->backend->conn_name, MICROBRUTE_NAME)) { return NULL; } microbrute_configure_gui (context->backend, context->parent); ma = g_malloc (sizeof (struct maction)); ma->type = MACTION_BUTTON; ma->name = _("_Calibration"); ma->sensitive = TRUE; ma->callback = G_CALLBACK (microbrute_calibration_callback); return ma; } elektroid-3.2.3/src/mactions/microfreak.c000066400000000000000000000052101500236517400203740ustar00rootroot00000000000000/* * microfreak.c * Copyright (C) 2024 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "maction.h" #include "../progress.h" #include "../browser.h" #include "connectors/microfreak.h" extern GtkWidget *dialog; extern struct browser remote_browser; static gpointer microfreak_defragment_runner (gpointer data) { struct backend *backend = data; progress.sysex_transfer.active = TRUE; microfreak_sample_defragment (backend); progress_response (GTK_RESPONSE_ACCEPT); return NULL; } static void microfreak_defragment_callback (GtkWidget *object, gpointer data) { gint res; struct maction_context *context = data; dialog = gtk_message_dialog_new (GTK_WINDOW (context->parent), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE, _ ("The defragmentation process could take several minutes and could not be canceled. Are you sure you want to defragment the sample memory?")); gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Defragment"), GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); res = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); dialog = NULL; if (res != GTK_RESPONSE_ACCEPT) { return; } progress_run (microfreak_defragment_runner, PROGRESS_TYPE_PULSE, context->backend, _("Defragmenting Sample Memory"), NULL, FALSE, NULL); browser_refresh (NULL, &remote_browser); } struct maction * microfreak_maction_defrag_builder (struct maction_context *context) { struct maction *ma; if (!context->backend->conn_name || strcmp (context->backend->conn_name, MICROFREAK_NAME)) { return NULL; } ma = g_malloc (sizeof (struct maction)); ma->type = MACTION_BUTTON; ma->name = _("_Defragment"); ma->sensitive = TRUE; ma->callback = G_CALLBACK (microfreak_defragment_callback); return ma; } elektroid-3.2.3/src/notifier.c000066400000000000000000000077311500236517400162660ustar00rootroot00000000000000/* * notifier.c * Copyright (C) 2021 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "notifier.h" #define NOTIFIER_RATE_LIMIT 1000 static gboolean notifier_go_up (gpointer data) { struct browser *browser = data; browser_go_up (NULL, browser); return FALSE; } static void notifier_parent_changed (GFileMonitor *self, GFile *file, GFile *other_file, GFileMonitorEvent event_type, gpointer user_data) { struct notifier *notifier = user_data; gchar *p1 = g_file_get_path (notifier->dir); gchar *p2 = g_file_get_path (file); gboolean itself = strcmp (p1, p2) == 0; g_free (p1); g_free (p2); debug_print (2, "Processing notifier parent change..."); if (event_type == G_FILE_MONITOR_EVENT_DELETED && itself) { debug_print (1, "Processing notifier dir deletion..."); g_idle_add (notifier_go_up, notifier->browser); } } static void notifier_changed (GFileMonitor *self, GFile *file, GFile *other_file, GFileMonitorEvent event_type, gpointer user_data) { struct notifier *notifier = user_data; gchar *p1 = g_file_get_path (notifier->dir); gchar *p2 = g_file_get_path (file); gboolean itself = strcmp (p1, p2) == 0; g_free (p1); g_free (p2); debug_print (2, "Processing notifier change..."); if (event_type != G_FILE_MONITOR_EVENT_DELETED || !itself) { debug_print (1, "Processing notifier reload..."); g_idle_add (browser_load_dir, notifier->browser); } } void notifier_init (struct notifier **notifier, struct browser *browser) { struct notifier *n = g_malloc (sizeof (struct notifier)); n->monitor = NULL; n->parent_monitor = NULL; n->browser = browser; *notifier = n; } void notifier_update_dir (struct notifier *notifier, gboolean active) { GFile *parent; debug_print (1, "Changing %s browser path to '%s'...", notifier->browser->name, notifier->browser->dir); if (notifier->monitor) { g_object_unref (notifier->monitor); g_object_unref (notifier->dir); } if (notifier->parent_monitor) { g_object_unref (notifier->parent_monitor); } if (active) { notifier->dir = g_file_new_for_path (notifier->browser->dir); notifier->monitor = g_file_monitor_directory (notifier->dir, G_FILE_MONITOR_NONE, NULL, NULL); g_file_monitor_set_rate_limit (notifier->monitor, NOTIFIER_RATE_LIMIT); g_signal_connect (notifier->monitor, "changed", G_CALLBACK (notifier_changed), notifier); parent = g_file_get_parent (notifier->dir); if (parent) { notifier->parent_monitor = g_file_monitor_directory (parent, G_FILE_MONITOR_NONE, NULL, NULL); g_file_monitor_set_rate_limit (notifier->parent_monitor, NOTIFIER_RATE_LIMIT); g_signal_connect (notifier->parent_monitor, "changed", G_CALLBACK (notifier_parent_changed), notifier); g_object_unref (parent); } else { notifier->parent_monitor = NULL; } } else { notifier->monitor = NULL; notifier->parent_monitor = NULL; } } void notifier_destroy (struct notifier *notifier) { if (notifier->monitor) { g_object_unref (notifier->monitor); g_object_unref (notifier->dir); } if (notifier->parent_monitor) { g_object_unref (notifier->parent_monitor); } g_free (notifier); } elektroid-3.2.3/src/notifier.h000066400000000000000000000022401500236517400162610ustar00rootroot00000000000000/* * notifier.h * Copyright (C) 2021 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef NOTIFIER_H #define NOTIFIER_H #include #include "browser.h" struct notifier { GFile *dir; GFileMonitor *monitor; GFileMonitor *parent_monitor; struct browser *browser; }; void notifier_init (struct notifier **notifier, struct browser *browser); void notifier_update_dir (struct notifier *, gboolean active); void notifier_destroy (struct notifier *notifier); #endif elektroid-3.2.3/src/preferences.c000066400000000000000000000155041500236517400167450ustar00rootroot00000000000000/* * preferences.c * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include #include "preferences.h" #include "utils.h" #define PREFERENCES_FILE "/preferences.json" GSList *preferences; static GHashTable *preferences_hashtable; static gpointer preferences_get_boolean_value (const gpointer in, gboolean def_value) { gboolean *out = g_malloc (sizeof (gboolean)); if (in) { *out = *(gboolean *) in; } else { *out = def_value; } return out; } gpointer preferences_get_boolean_value_true (const gpointer b) { return preferences_get_boolean_value (b, TRUE); } gpointer preferences_get_boolean_value_false (const gpointer b) { return preferences_get_boolean_value (b, FALSE); } gpointer preferences_get_int_value (const gpointer in, gint max, gint min, gint def) { gint *out = g_malloc (sizeof (gint)); if (in) { *out = *(gint *) in; if (*out > max || *out < min) { *out = def; } } else { *out = def; } return out; } static void preferences_set_value (const struct preference *p, JsonBuilder *builder) { gpointer v = g_hash_table_lookup (preferences_hashtable, p->key); json_builder_set_member_name (builder, p->key); if (p->type == PREFERENCE_TYPE_BOOLEAN) { json_builder_add_boolean_value (builder, *(gboolean *) v); } else if (p->type == PREFERENCE_TYPE_INT) { json_builder_add_int_value (builder, *(gint *) v); } else if (p->type == PREFERENCE_TYPE_STRING) { json_builder_add_string_value (builder, (gchar *) v); } else { error_print ("Illegal type"); //This should never happen as the application exists when loading the values for the same reason. } } gint preferences_save () { gchar *preferences_path; JsonBuilder *builder; JsonGenerator *gen; JsonNode *root; gchar *json; GSList *l; preferences_path = get_user_dir (CONF_DIR); if (g_mkdir_with_parents (preferences_path, S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { error_print ("Error wile creating directory `%s'", preferences_path); return 1; } g_free (preferences_path); preferences_path = get_user_dir (CONF_DIR PREFERENCES_FILE); debug_print (1, "Saving preferences to '%s'...", preferences_path); builder = json_builder_new (); json_builder_begin_object (builder); l = preferences; while (l) { const struct preference *p = l->data; debug_print (1, "Saving preference '%s'...", p->key); preferences_set_value (p, builder); l = l->next; } json_builder_end_object (builder); gen = json_generator_new (); root = json_builder_get_root (builder); json_generator_set_root (gen, root); json_generator_set_pretty (gen, TRUE); json = json_generator_to_data (gen, NULL); file_save_data (preferences_path, (guint8 *) json, strlen (json)); g_free (json); json_node_free (root); g_object_unref (gen); g_object_unref (builder); g_free (preferences_path); return 0; } static gpointer preferences_get_value (const struct preference *p, JsonReader *reader) { gpointer v; if (json_reader_read_member (reader, p->key)) { if (p->type == PREFERENCE_TYPE_BOOLEAN) { gboolean b = json_reader_get_boolean_value (reader); v = p->get_value (&b); } else if (p->type == PREFERENCE_TYPE_INT) { gint i = json_reader_get_int_value (reader); v = p->get_value (&i); } else if (p->type == PREFERENCE_TYPE_STRING) { gchar *s = (gchar *) json_reader_get_string_value (reader); v = p->get_value (s); } else { error_print ("Illegal type"); exit (EXIT_FAILURE); } } else { v = p->get_value (NULL); } json_reader_end_member (reader); return v; } gint preferences_load () { GError *error; JsonReader *reader; GSList *l; JsonParser *parser = json_parser_new (); gchar *preferences_file = get_user_dir (CONF_DIR PREFERENCES_FILE); //Keys need to be static constants defined only in one place preferences_hashtable = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); error = NULL; json_parser_load_from_file (parser, preferences_file, &error); if (error) { debug_print (1, "Error wile loading preferences from `%s': %s", preferences_file, error->message); g_error_free (error); g_object_unref (parser); g_free (preferences_file); l = preferences; while (l) { gpointer v; const struct preference *p = l->data; debug_print (1, "Initializing preference '%s'...", p->key); v = p->get_value (NULL); g_hash_table_insert (preferences_hashtable, p->key, v); l = l->next; } return 0; } debug_print (1, "Loading preferences from '%s'...", preferences_file); reader = json_reader_new (json_parser_get_root (parser)); l = preferences; while (l) { gpointer v; const struct preference *p = l->data; debug_print (1, "Loading preference '%s'...", p->key); v = preferences_get_value (p, reader); g_hash_table_insert (preferences_hashtable, p->key, v); l = l->next; } g_object_unref (reader); g_object_unref (parser); g_free (preferences_file); return 0; } void preferences_free () { g_hash_table_unref (preferences_hashtable); } gboolean preferences_get_boolean (const gchar *key) { gboolean *v = g_hash_table_lookup (preferences_hashtable, key); return *v; } gint preferences_get_int (const gchar *key) { gint *v = g_hash_table_lookup (preferences_hashtable, key); return *v; } const gchar * preferences_get_string (const gchar *key) { return (gchar *) g_hash_table_lookup (preferences_hashtable, key); } void preferences_set_boolean (const gchar *key, gboolean v) { gboolean *p = g_malloc (sizeof (gint)); *p = v; g_hash_table_insert (preferences_hashtable, (gpointer) key, p); } void preferences_set_int (const gchar *key, gint v) { gint *p = g_malloc (sizeof (gint)); *p = v; g_hash_table_insert (preferences_hashtable, (gpointer) key, p); } void preferences_set_string (const char *key, gchar *v) { g_hash_table_insert (preferences_hashtable, (gpointer) key, v); } elektroid-3.2.3/src/preferences.h000066400000000000000000000044371500236517400167550ustar00rootroot00000000000000/* * preferences.h * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef PREFERENCES_H #define PREFERENCES_H #include //Preferences need to be here as need to be available from the CLI even though some are not accessible from the CLI. #define PREF_KEY_LOCAL_DIR "localDir" #define PREF_KEY_REMOTE_DIR "remoteDir" //Only used in system filesystems. #define PREF_KEY_SHOW_REMOTE "showRemote" #define PREF_KEY_AUTOPLAY "autoplay" #define PREF_KEY_MIX "mix" #define PREF_KEY_SHOW_GRID "showGrid" #define PREF_KEY_GRID_LENGTH "gridLength" #define PREF_KEY_PLAY_WHILE_LOADING "playSampleWhileLoading" #define PREF_KEY_AUDIO_BUFFER_LEN "audioBufferLength" enum preference_type { PREFERENCE_TYPE_BOOLEAN, PREFERENCE_TYPE_INT, PREFERENCE_TYPE_STRING }; typedef gpointer (*preference_get_value_f) (const gpointer); struct preference { gchar *key; enum preference_type type; preference_get_value_f get_value; }; extern GSList *preferences; gpointer preferences_get_boolean_value_true (const gpointer b); gpointer preferences_get_boolean_value_false (const gpointer b); gpointer preferences_get_int_value (const gpointer in, gint max, gint min, gint def); gint preferences_save (); gint preferences_load (); void preferences_free (); gboolean preferences_get_boolean (const gchar * key); gint preferences_get_int (const gchar * key); const gchar *preferences_get_string (const gchar * key); void preferences_set_boolean (const gchar * key, gboolean v); void preferences_set_int (const gchar * key, gint v); void preferences_set_string (const gchar * key, gchar * s); #endif elektroid-3.2.3/src/progress.c000066400000000000000000000127621500236517400163130ustar00rootroot00000000000000/* * progress.c * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "progress.h" #define MIN_TIME_UNTIL_DIALOG_RESPONSE 1e6 #define PROGRESS_BAR_UPDATE_TIME 100 struct progress progress; static gpointer progress_join_thread () { gpointer output = NULL; debug_print (1, "Stopping SysEx thread..."); if (progress.thread) { output = g_thread_join (progress.thread); } progress.thread = NULL; return output; } //This function is called from gtk_dialog_response in progress_response. See the "response" signal handler. static void progress_stop_running_sysex (GtkDialog *dialog, gint response_id, gpointer data) { if (response_id == GTK_RESPONSE_CANCEL) { gtk_label_set_text (GTK_LABEL (progress.label), _("Cancelling...")); } debug_print (1, "Stopping SysEx transfer..."); g_mutex_lock (&progress.sysex_transfer.mutex); progress.sysex_transfer.active = FALSE; g_mutex_unlock (&progress.sysex_transfer.mutex); } void progress_stop_thread () { progress_stop_running_sysex (NULL, 0, NULL); progress_join_thread (); } void progress_set_fraction (gdouble fraction) { gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress.bar), fraction); } gboolean progress_is_active () { gboolean active; g_mutex_lock (&progress.sysex_transfer.mutex); active = progress.sysex_transfer.active; g_mutex_unlock (&progress.sysex_transfer.mutex); return active; } static gboolean progress_pulse (gpointer data) { gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progress.bar)); return progress_is_active (); } static gboolean progress_sysex_transfer (gpointer data) { gchar *text; enum sysex_transfer_status status; g_mutex_lock (&progress.sysex_transfer.mutex); status = progress.sysex_transfer.status; g_mutex_unlock (&progress.sysex_transfer.mutex); switch (status) { case WAITING: text = _("Waiting..."); break; case SENDING: text = _("Sending..."); break; case RECEIVING: text = _("Receiving..."); break; default: text = ""; } gtk_label_set_text (GTK_LABEL (progress.label), text); return progress_pulse (NULL); } void progress_init (GtkBuilder *builder) { progress.dialog = GTK_DIALOG (gtk_builder_get_object (builder, "progress_dialog")); progress.bar = GTK_WIDGET (gtk_builder_get_object (builder, "progress_dialog_bar")); progress.label = GTK_WIDGET (gtk_builder_get_object (builder, "progress_dialog_label")); progress.cancel_button = GTK_WIDGET (gtk_builder_get_object (builder, "progress_dialog_cancel_button")); g_signal_connect (progress.dialog, "response", G_CALLBACK (progress_stop_running_sysex), NULL); } static void progress_start_thread_gsourcefunc () { if (progress.type == PROGRESS_TYPE_PULSE) { g_timeout_add (PROGRESS_BAR_UPDATE_TIME, progress_pulse, NULL); } else if (progress.type == PROGRESS_TYPE_SYSEX_TRANSFER) { g_timeout_add (PROGRESS_BAR_UPDATE_TIME, progress_sysex_transfer, NULL); } } //Using this before a call to gtk_dialog_run ensures that the threads starts after the dialog is being run. gpointer progress_run (GThreadFunc f, enum progress_type type, gpointer user_data, const gchar *name, const gchar *text, gboolean cancellable, gint *res) { gpointer v; gint dres; gtk_widget_set_visible (progress.cancel_button, cancellable); debug_print (1, "Creating progress thread..."); progress.thread = g_thread_new ("progress thread", f, user_data); progress.type = type; progress_start_thread_gsourcefunc (); progress.start = g_get_monotonic_time (); gtk_window_set_title (GTK_WINDOW (progress.dialog), name); gtk_label_set_text (GTK_LABEL (progress.label), text); dres = gtk_dialog_run (progress.dialog); if (res) { *res = dres; } //Without these lines below, the progress.label is not updated. //This happens because when the dialog is closed the gtk main thread is blocked //when joining the thread which ultimately causes pending widget updates to //not be performed. usleep (100000); while (gtk_events_pending ()) { gtk_main_iteration (); } v = progress_join_thread (); gtk_widget_hide (GTK_WIDGET (progress.dialog)); return v; } /** * This function guarantees that the time since start is at least the timeout. * This is needed when controlling a dialog from a thread because the dialog needs to be showed before the response is sent from the thread. */ static void progress_usleep_since (gint64 timeout, gint64 start) { gint64 diff = g_get_monotonic_time () - start; if (diff < timeout) { usleep (timeout - diff); } } void progress_response (gint response) { progress_usleep_since (MIN_TIME_UNTIL_DIALOG_RESPONSE, progress.start); gtk_dialog_response (GTK_DIALOG (progress.dialog), response); } elektroid-3.2.3/src/progress.h000066400000000000000000000033751500236517400163200ustar00rootroot00000000000000/* * progress.h * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "connector.h" #ifndef PROGRESS_H #define PROGRESS_H enum progress_type { PROGRESS_TYPE_NO_AUTO, //Progress must be set by calling progress_set_fraction. PROGRESS_TYPE_PULSE, //Progress pulses. PROGRESS_TYPE_SYSEX_TRANSFER //Progress pulses and the label tracks the sysex transfer status. }; struct progress { struct sysex_transfer sysex_transfer; GtkDialog *dialog; GtkWidget *bar; GtkWidget *label; GtkWidget *cancel_button; GThread *thread; gint64 start; enum progress_type type; }; extern struct progress progress; void progress_stop_thread (); void progress_dialog_close (gpointer data); void progress_set_fraction (gdouble fraction); gboolean progress_is_active (); gpointer progress_run (GThreadFunc f, enum progress_type type, gpointer user_data, const gchar * name, const gchar * text, gboolean cancellable, gint * res); void progress_init (GtkBuilder * builder); void progress_response (gint response); #endif elektroid-3.2.3/src/regconn.c000066400000000000000000000027441500236517400161010ustar00rootroot00000000000000/* * regconn.c * Copyright (C) 2024 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "regconn.h" #include "connectors/system.h" #include "connectors/elektron.h" #include "connectors/microbrute.h" #include "connectors/microfreak.h" #include "connectors/cz.h" #include "connectors/sds.h" #include "connectors/efactor.h" #include "connectors/phatty.h" #include "connectors/summit.h" #include "connectors/default.h" void regconn_register () { system_connector = &CONNECTOR_SYSTEM; gslist_fill (&connectors, &CONNECTOR_ELEKTRON, &CONNECTOR_MICROBRUTE, &CONNECTOR_MICROFREAK, &CONNECTOR_PHATTY, &CONNECTOR_SUMMIT, &CONNECTOR_CZ, &CONNECTOR_SDS, &CONNECTOR_EFACTOR, &CONNECTOR_DEFAULT, NULL); } void regconn_unregister () { g_slist_free (g_steal_pointer (&connectors)); } elektroid-3.2.3/src/regconn.h000066400000000000000000000015411500236517400161000ustar00rootroot00000000000000/* * regconn.h * Copyright (C) 2024 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "connector.h" void regconn_register (); void regconn_unregister (); elektroid-3.2.3/src/regma.c000066400000000000000000000034751500236517400155430ustar00rootroot00000000000000/* * regma.c * Copyright (C) 2024 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "regma.h" struct maction *autosampler_maction_builder (struct maction_context *); struct maction *backend_maction_os_upgrade_builder (struct maction_context *); struct maction *backend_maction_rx_sysex_builder (struct maction_context *); struct maction *backend_maction_tx_sysex_builder (struct maction_context *); struct maction *microbrute_maction_conf_builder (struct maction_context *); struct maction *microbrute_maction_cal_builder (struct maction_context *); struct maction *microfreak_maction_defrag_builder (struct maction_context *); void regma_register () { gslist_fill (&mactions, microbrute_maction_conf_builder, microbrute_maction_cal_builder, microfreak_maction_defrag_builder, maction_separator_builder, backend_maction_rx_sysex_builder, backend_maction_tx_sysex_builder, maction_separator_builder, backend_maction_os_upgrade_builder, maction_separator_builder, autosampler_maction_builder, NULL); } void regma_unregister () { g_slist_free (g_steal_pointer (&mactions)); } elektroid-3.2.3/src/regma.h000066400000000000000000000015311500236517400155370ustar00rootroot00000000000000/* * regma.h * Copyright (C) 2024 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "maction.h" void regma_register (); void regma_unregister (); elektroid-3.2.3/src/regpref.c000066400000000000000000000100201500236517400160620ustar00rootroot00000000000000/* * regpref.c * Copyright (C) 2024 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "regpref.h" #define PREF_DEFAULT_GRID_LENGTH 16 #define PREF_MAX_GRID_LENGTH 64 #define PREF_MIN_GRID_LENGTH 2 #define PREF_DEFAULT_AUDIO_BUF_LENGTH 256 #define PREF_MAX_AUDIO_BUF_LENGTH 4096 #define PREF_MIN_AUDIO_BUF_LENGTH 256 static gpointer regpref_get_grid (const gpointer grid) { return preferences_get_int_value (grid, PREF_MAX_GRID_LENGTH, PREF_MIN_GRID_LENGTH, PREF_DEFAULT_GRID_LENGTH); } static gpointer regpref_get_audio_buffer_length (const gpointer len) { gpointer p = preferences_get_int_value (len, PREF_MAX_AUDIO_BUF_LENGTH, PREF_MIN_AUDIO_BUF_LENGTH, PREF_DEFAULT_AUDIO_BUF_LENGTH); gint v = *(gint *) p; if (v > 256 && v < 512) { v = 256; } else if (v > 512 && v < 1024) { v = 512; } else if (v > 1024 && v < 2048) { v = 1024; } else if (v > 2048 && v < 4096) { v = 2048; } *(gint *) p = v; return p; } static gpointer regpref_get_home (const gpointer home) { return home ? g_strdup (home) : get_user_dir (NULL); } static const struct preference PREF_LOCAL_DIR = { .key = PREF_KEY_LOCAL_DIR, .type = PREFERENCE_TYPE_STRING, .get_value = regpref_get_home }; static const struct preference PREF_REMOTE_DIR = { .key = PREF_KEY_REMOTE_DIR, .type = PREFERENCE_TYPE_STRING, .get_value = regpref_get_home }; const struct preference PREF_SHOW_REMOTE = { .key = PREF_KEY_SHOW_REMOTE, .type = PREFERENCE_TYPE_BOOLEAN, .get_value = preferences_get_boolean_value_true }; static const struct preference PREF_AUTOPLAY = { .key = PREF_KEY_AUTOPLAY, .type = PREFERENCE_TYPE_BOOLEAN, .get_value = preferences_get_boolean_value_true }; static const struct preference PREF_MIX = { .key = PREF_KEY_MIX, .type = PREFERENCE_TYPE_BOOLEAN, .get_value = preferences_get_boolean_value_false }; static const struct preference PREF_SHOW_GRID = { .key = PREF_KEY_SHOW_GRID, .type = PREFERENCE_TYPE_BOOLEAN, .get_value = preferences_get_boolean_value_false }; static const struct preference PREF_GRID_LENGTH = { .key = PREF_KEY_GRID_LENGTH, .type = PREFERENCE_TYPE_INT, .get_value = regpref_get_grid }; static const struct preference PREF_PLAY_WHILE_LOADING = { .key = PREF_KEY_PLAY_WHILE_LOADING, .type = PREFERENCE_TYPE_BOOLEAN, .get_value = preferences_get_boolean_value_true }; static const struct preference PREF_AUDIO_BUFFER_LEN = { .key = PREF_KEY_AUDIO_BUFFER_LEN, .type = PREFERENCE_TYPE_INT, .get_value = regpref_get_audio_buffer_length }; const struct preference PREF_STOP_DEVICE_WHEN_CONNECTING = { .key = PREF_KEY_STOP_DEVICE_WHEN_CONNECTING, .type = PREFERENCE_TYPE_BOOLEAN, .get_value = preferences_get_boolean_value_true }; const struct preference PREF_ELEKTRON_LOAD_SOUND_TAGS = { .key = PREF_KEY_ELEKTRON_LOAD_SOUND_TAGS, .type = PREFERENCE_TYPE_BOOLEAN, .get_value = preferences_get_boolean_value_true }; void regpref_register () { gslist_fill (&preferences, &PREF_LOCAL_DIR, &PREF_REMOTE_DIR, &PREF_SHOW_REMOTE, &PREF_AUTOPLAY, &PREF_MIX, &PREF_SHOW_GRID, &PREF_GRID_LENGTH, &PREF_PLAY_WHILE_LOADING, &PREF_AUDIO_BUFFER_LEN, &PREF_STOP_DEVICE_WHEN_CONNECTING, &PREF_ELEKTRON_LOAD_SOUND_TAGS, NULL); } void regpref_unregister () { g_slist_free (g_steal_pointer (&preferences)); } elektroid-3.2.3/src/regpref.h000066400000000000000000000016311500236517400160770ustar00rootroot00000000000000/* * regpref.h * Copyright (C) 2024 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include "preferences.h" #include "backend.h" #include "connectors/elektron.h" void regpref_register (); void regpref_unregister (); elektroid-3.2.3/src/sample.c000066400000000000000000000677551500236517400157440ustar00rootroot00000000000000/* * sample.c * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include #include "sample.h" #include "connectors/microfreak_sample.h" #define LOAD_BUFFER_LEN (32 * KI) #define JUNK_CHUNK_ID "JUNK" #define SMPL_CHUNK_ID "smpl" #define HEADERS_SPACE 4096 //Gross estimation for the sample (WAV) headers static const gchar *ELEKTROID_AUDIO_LOCAL_EXTS[] = { "wav", "ogg", "aiff", "flac", MICROFREAK_PWAVETABLE_EXT, MICROFREAK_ZWAVETABLE_EXT, MICROFREAK_PSAMPLE_EXT, MICROFREAK_ZSAMPLE_EXT, #if !defined(__linux__) || HAVE_SNDFILE_MP3 "mp3", #endif NULL }; struct smpl_chunk_data { guint32 manufacturer; guint32 product; guint32 sample_period; guint32 midi_unity_note; guint32 midi_pitch_fraction; guint32 smpte_format; guint32 smpte_offset; guint32 num_sampler_loops; guint32 sampler_data; struct sample_loop { guint32 cue_point_id; guint32 type; guint32 start; guint32 end; guint32 fraction; guint32 play_count; } sample_loop; }; struct g_byte_array_io_data { GByteArray *array; guint pos; }; static const guint8 JUNK_CHUNK_DATA[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static sf_count_t get_filelen_byte_array_io (void *user_data) { struct g_byte_array_io_data *data = user_data; return data->array->len; } static sf_count_t seek_byte_array_io (sf_count_t offset, int whence, void *user_data) { struct g_byte_array_io_data *data = user_data; switch (whence) { case SEEK_SET: data->pos = offset; break; case SEEK_CUR: data->pos = data->pos + offset; break; case SEEK_END: data->pos = data->array->len + offset; break; default: break; }; if (data->pos > data->array->len) { g_byte_array_set_size (data->array, data->pos); } return data->pos; } static sf_count_t read_byte_array_io (void *ptr, sf_count_t count, void *user_data) { struct g_byte_array_io_data *data = user_data; if (data->pos + count > data->array->len) { count = data->array->len - data->pos; } memcpy (ptr, data->array->data + data->pos, count); data->pos += count; return count; } static sf_count_t write_byte_array_io (const void *ptr, sf_count_t count, void *user_data) { struct g_byte_array_io_data *data = user_data; if (data->pos >= data->array->len) { g_byte_array_set_size (data->array, data->pos); } if (data->pos + count > data->array->len) { g_byte_array_set_size (data->array, data->pos + count); } memcpy (data->array->data + data->pos, (guint8 *) ptr, count); data->pos += count; return count; } static sf_count_t tell_byte_array_io (void *user_data) { struct g_byte_array_io_data *data = user_data; return data->pos; } static SF_VIRTUAL_IO G_BYTE_ARRAY_IO = { .get_filelen = get_filelen_byte_array_io, .seek = seek_byte_array_io, .read = read_byte_array_io, .write = write_byte_array_io, .tell = tell_byte_array_io }; static sf_count_t get_filelen_file_io (void *user_data) { long fileSize, position; FILE *file = user_data; position = ftell (file); fseek (file, 0, SEEK_END); fileSize = ftell (file); fseek (file, position, SEEK_SET); return fileSize; } static sf_count_t seek_file_io (sf_count_t offset, int whence, void *user_data) { FILE *file = user_data; fseek (file, offset, whence); return ftell (file); } static sf_count_t read_file_io (void *ptr, sf_count_t count, void *user_data) { FILE *file = user_data; return fread (ptr, 1, count, file); } static sf_count_t write_file_io (const void *ptr, sf_count_t count, void *user_data) { FILE *file = user_data; return fwrite (ptr, 1, count, file); } static sf_count_t tell_file_io (void *user_data) { FILE *file = user_data; return ftell (file); } static SF_VIRTUAL_IO FILE_IO = { .get_filelen = get_filelen_file_io, .seek = seek_file_io, .read = read_file_io, .write = write_file_io, .tell = tell_file_io }; static gint sample_write_audio_file_data (struct idata *idata, struct g_byte_array_io_data *wave, struct job_control *control, guint32 format) { SF_INFO sf_info; SNDFILE *sndfile; sf_count_t frames, total; struct SF_CHUNK_INFO junk_chunk_info; struct SF_CHUNK_INFO smpl_chunk_info; struct smpl_chunk_data smpl_chunk_data; GByteArray *sample = idata->content; struct sample_info *sample_info = idata->info; frames = sample->len / SAMPLE_INFO_FRAME_SIZE (sample_info); debug_print (1, "Frames: %" PRIu64 "; sample rate: %d; channels: %d", frames, sample_info->rate, sample_info->channels); debug_print (1, "Loop start at %d; loop end at %d", sample_info->loop_start, sample_info->loop_end); memset (&sf_info, 0, sizeof (sf_info)); sf_info.samplerate = sample_info->rate; sf_info.channels = sample_info->channels; sf_info.format = format; sndfile = sf_open_virtual (&G_BYTE_ARRAY_IO, SFM_WRITE, &sf_info, wave); if (!sndfile) { error_print ("%s", sf_strerror (sndfile)); return -1; } strcpy (junk_chunk_info.id, JUNK_CHUNK_ID); junk_chunk_info.id_size = strlen (JUNK_CHUNK_ID); junk_chunk_info.datalen = sizeof (JUNK_CHUNK_DATA); junk_chunk_info.data = (void *) JUNK_CHUNK_DATA; if (sf_set_chunk (sndfile, &junk_chunk_info) != SF_ERR_NO_ERROR) { error_print ("%s", sf_strerror (sndfile)); } smpl_chunk_data.manufacturer = 0; smpl_chunk_data.product = 0; smpl_chunk_data.sample_period = 1e9 / sample_info->rate; smpl_chunk_data.midi_unity_note = GUINT32_TO_LE (sample_info->midi_note); smpl_chunk_data.midi_pitch_fraction = 0; smpl_chunk_data.smpte_format = 0; smpl_chunk_data.smpte_offset = 0; smpl_chunk_data.num_sampler_loops = 1; smpl_chunk_data.sampler_data = 0; smpl_chunk_data.sample_loop.cue_point_id = 0; smpl_chunk_data.sample_loop.type = GUINT32_TO_LE (sample_info->loop_type); smpl_chunk_data.sample_loop.start = GUINT32_TO_LE (sample_info->loop_start); smpl_chunk_data.sample_loop.end = GUINT32_TO_LE (sample_info->loop_end); smpl_chunk_data.sample_loop.fraction = 0; smpl_chunk_data.sample_loop.play_count = 0; strcpy (smpl_chunk_info.id, SMPL_CHUNK_ID); smpl_chunk_info.id_size = strlen (SMPL_CHUNK_ID); smpl_chunk_info.datalen = sizeof (struct smpl_chunk_data); smpl_chunk_info.data = &smpl_chunk_data; if (sf_set_chunk (sndfile, &smpl_chunk_info) != SF_ERR_NO_ERROR) { error_print ("%s", sf_strerror (sndfile)); } if ((sample_info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_16) { total = sf_writef_short (sndfile, (gint16 *) sample->data, frames); } else if ((sample_info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT) { total = sf_writef_float (sndfile, (gfloat *) sample->data, frames); } else if ((sample_info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_32) { total = sf_writef_int (sndfile, (gint32 *) sample->data, frames); } else { error_print ("Invalid sample format. Using short..."); total = sf_writef_short (sndfile, (gint16 *) sample->data, frames); } sf_close (sndfile); if (total != frames) { error_print ("Unexpected frames while writing to file (%" PRIu64 " != %" PRIu64 ")", total, frames); return -1; } return 0; } gint sample_get_memfile_from_sample (struct idata *sample, struct idata *memfile, struct job_control *control, guint32 format) { gint err; GByteArray *content; struct g_byte_array_io_data data; struct sample_info *sample_info = sample->info; guint frame_size = FRAME_SIZE (sample_info->channels, format & SF_FORMAT_SUBMASK); content = g_byte_array_sized_new (sample->content->len * frame_size + HEADERS_SPACE); idata_init (memfile, content, sample->name ? strdup (sample->name) : NULL, NULL); data.pos = 0; data.array = content; err = sample_write_audio_file_data (sample, &data, control, format); if (err) { idata_free (memfile); } return err; } gint sample_save_to_file (const gchar *path, struct idata *sample, struct job_control *control, guint32 format) { gint err; struct idata file; err = sample_get_memfile_from_sample (sample, &file, control, format); if (err) { return err; } err = file_save (path, &file, control); idata_free (&file); return err; } static void audio_multichannel_to_mono_short (gshort *input, gshort *output, gint size, gint channels) { gint32 i, j, v; debug_print (2, "Converting short values to mono..."); for (i = 0; i < size; i++) { v = 0; for (j = 0; j < channels; j++) { v += input[i * channels + j]; } v *= MONO_MIX_GAIN (channels); output[i] = v; } } static void audio_multichannel_to_mono_float (gfloat *input, gfloat *output, gint size, gint channels) { gfloat v; gint i, j; debug_print (2, "Converting float values to mono..."); for (i = 0; i < size; i++) { v = 0; for (j = 0; j < channels; j++) { v += input[i * channels + j]; } v *= MONO_MIX_GAIN (channels); output[i] = v; } } static void audio_multichannel_to_mono_int (gint32 *input, gint32 *output, gint size, gint channels) { gint32 v; gint i, j; debug_print (2, "Converting int values to mono..."); for (i = 0; i < size; i++) { v = 0; for (j = 0; j < channels; j++) { v += input[i * channels + j]; } v *= MONO_MIX_GAIN (channels); output[i] = v; } } static void audio_mono_to_stereo_short (gshort *input, gshort *output, gint size) { debug_print (2, "Converting short values to stereo..."); for (gint i = 0; i < size; i++, input++) { *output = *input; output++; *output = *input; output++; } } static void audio_mono_to_stereo_float (gfloat *input, gfloat *output, gint size) { debug_print (2, "Converting float values to stereo..."); for (gint i = 0; i < size; i++, input++) { *output = *input; output++; *output = *input; output++; } } static void audio_mono_to_stereo_int (gint32 *input, gint32 *output, gint size) { debug_print (2, "Converting int values to stereo..."); for (gint i = 0; i < size; i++, input++) { *output = *input; output++; *output = *input; output++; } } static void sample_set_sample_info (struct sample_info *sample_info, SNDFILE *sndfile, SF_INFO *sf_info) { struct SF_CHUNK_INFO chunk_info; SF_CHUNK_ITERATOR *chunk_iter; struct smpl_chunk_data smpl_chunk_data; gboolean disable_loop = FALSE; sample_info->channels = sf_info->channels; sample_info->rate = sf_info->samplerate; sample_info->frames = sf_info->frames; sample_info->format = sf_info->format; strcpy (chunk_info.id, SMPL_CHUNK_ID); chunk_info.id_size = strlen (SMPL_CHUNK_ID); chunk_iter = sf_get_chunk_iterator (sndfile, &chunk_info); if (chunk_iter) { chunk_info.datalen = sizeof (struct smpl_chunk_data); memset (&smpl_chunk_data, 0, chunk_info.datalen); debug_print (2, "%s chunk found (%d B)", SMPL_CHUNK_ID, chunk_info.datalen); chunk_info.data = &smpl_chunk_data; sf_get_chunk_data (chunk_iter, &chunk_info); sample_info->loop_start = GUINT32_FROM_LE (smpl_chunk_data.sample_loop.start); sample_info->loop_end = GUINT32_FROM_LE (smpl_chunk_data.sample_loop.end); sample_info->loop_type = GUINT32_FROM_LE (smpl_chunk_data.sample_loop.type); sample_info->midi_note = GUINT32_FROM_LE (smpl_chunk_data.midi_unity_note); if (sample_info->loop_start >= sample_info->frames) { debug_print (2, "Bad loop start"); disable_loop = TRUE; } if (sample_info->loop_end >= sample_info->frames) { debug_print (2, "Bad loop end"); disable_loop = TRUE; } while (chunk_iter) { chunk_iter = sf_next_chunk_iterator (chunk_iter); } } else { disable_loop = TRUE; sample_info->midi_note = 0; } if (disable_loop) { sample_info->loop_start = sample_info->frames - 1; sample_info->loop_end = sample_info->loop_start; sample_info->loop_type = 0; } debug_print (2, "Loop start at %d, loop end at %d", sample_info->loop_start, sample_info->loop_end); } static gint sample_load_sample_info_libsndfile (const gchar *path, struct sample_info *sample_info) { SF_INFO sf_info; SNDFILE *sndfile; FILE *file; gint err = 0; file = fopen (path, "rb"); if (!file) { return -errno; } sndfile = sf_open_virtual (&FILE_IO, SFM_READ, &sf_info, file); if (!sndfile) { error_print ("Error while reading %s: %s", path, sf_strerror (sndfile)); err = -1; goto end; } sample_set_sample_info (sample_info, sndfile, &sf_info); end: fclose (file); return err; } static gint sample_load_microfreak_sample (const gchar *path, struct idata *sample, struct job_control *control) { gint err; const gchar *ext = filename_get_ext (path); if (!strcmp (MICROFREAK_PWAVETABLE_EXT, ext)) { err = microfreak_pwavetable_load (path, sample, control); } else if (!strcmp (MICROFREAK_ZWAVETABLE_EXT, ext)) { err = microfreak_zwavetable_load (path, sample, control); } else if (!strcmp (MICROFREAK_PSAMPLE_EXT, ext)) { err = microfreak_psample_load (path, sample, control); } else if (!strcmp (MICROFREAK_ZSAMPLE_EXT, ext)) { err = microfreak_zsample_load (path, sample, control); } else { err = -1; } return err; } static gboolean sample_microfreak_filename (const gchar *path) { const gchar *ext = filename_get_ext (path); return !strcmp (MICROFREAK_PWAVETABLE_EXT, ext) || !strcmp (MICROFREAK_ZWAVETABLE_EXT, ext) || !strcmp (MICROFREAK_PSAMPLE_EXT, ext) || !strcmp (MICROFREAK_ZSAMPLE_EXT, ext); } gint sample_load_sample_info (const gchar *path, struct sample_info *sample_info) { gint err; memset (sample_info, 0, sizeof (struct sample_info)); if (sample_microfreak_filename (path)) { struct idata aux; struct job_control control; control.active = TRUE; g_mutex_init (&control.mutex); err = sample_load_microfreak_sample (path, &aux, &control); if (err) { return err; } memcpy (sample_info, aux.info, sizeof (struct sample_info)); idata_free (&aux); } else { err = sample_load_sample_info_libsndfile (path, sample_info); } return err; } static void sample_info_fix_frame_values (struct sample_info *sample_info) { if (sample_info->loop_start >= sample_info->frames) { sample_info->loop_start = sample_info->frames - 1; } if (sample_info->loop_end >= sample_info->frames) { sample_info->loop_end = sample_info->frames - 1; } } static gint sample_load_libsndfile (void *data, SF_VIRTUAL_IO *sf_virtual_io, struct job_control *control, struct idata *idata, const struct sample_info *sample_info_req, struct sample_info *sample_info_src, sample_load_cb cb, gpointer cb_data, const gchar *name) { SF_INFO sf_info; SNDFILE *sndfile; SRC_DATA src_data; SRC_STATE *src_state; void *buffer_input; void *buffer_input_multi; void *buffer_input_mono; void *buffer_input_stereo; void *buffer_i; //For gint16 or gint32 gfloat *buffer_f; void *buffer_output; gint err = 0, resampled_buffer_len, frames; gboolean active, rounding_fix; gdouble ratio; guint bytes_per_sample, bytes_per_frame; guint32 read_frames, actual_frames = 0; GByteArray *sample = NULL; struct sample_info *sample_info; sf_info.format = 0; sndfile = sf_open_virtual (sf_virtual_io, SFM_READ, &sf_info, data); if (!sndfile) { error_print ("%s", sf_strerror (sndfile)); return -1; } sample_set_sample_info (sample_info_src, sndfile, &sf_info); sample_info = g_malloc (sizeof (struct sample_info)); sample_info->midi_note = sample_info_src->midi_note; sample_info->loop_type = sample_info_src->loop_type; sample_info->channels = sample_info_req->channels ? sample_info_req->channels : sample_info_src->channels; sample_info->rate = sample_info_req->rate ? sample_info_req->rate : sample_info_src->rate; sample_info->format = sample_info_req->format ? sample_info_req->format : SF_FORMAT_PCM_16; if (sample_info->format != SF_FORMAT_PCM_16 && sample_info->format != SF_FORMAT_PCM_32 && sample_info->format != SF_FORMAT_FLOAT) { error_print ("Invalid sample format. Using short..."); sample_info->format = SF_FORMAT_PCM_16; } bytes_per_frame = SAMPLE_INFO_FRAME_SIZE (sample_info); bytes_per_sample = SAMPLE_SIZE (sample_info->format); //Set scale factor. See http://www.mega-nerd.com/libsndfile/api.html#note2 if ((sample_info_src->format & SF_FORMAT_FLOAT) == SF_FORMAT_FLOAT || (sample_info_src->format & SF_FORMAT_DOUBLE) == SF_FORMAT_DOUBLE) { debug_print (2, "Setting scale factor to ensure correct integer readings..."); sf_command (sndfile, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE); } buffer_input_multi = g_malloc (LOAD_BUFFER_LEN * FRAME_SIZE (sample_info_src->channels, sample_info->format)); buffer_input_mono = g_malloc (LOAD_BUFFER_LEN * bytes_per_sample); buffer_input_stereo = g_malloc (LOAD_BUFFER_LEN * 2 * bytes_per_sample); ratio = sample_info->rate / (double) sample_info_src->rate; src_data.src_ratio = ratio; src_data.output_frames = ceil (LOAD_BUFFER_LEN * src_data.src_ratio); resampled_buffer_len = src_data.output_frames * sample_info->channels; buffer_i = g_malloc (resampled_buffer_len * bytes_per_sample); src_data.data_out = g_malloc (resampled_buffer_len * sizeof (gfloat)); if (sample_info->format == SF_FORMAT_PCM_16 || sample_info->format == SF_FORMAT_PCM_32) { buffer_f = g_malloc (LOAD_BUFFER_LEN * sample_info->channels * sizeof (gfloat)); src_data.data_in = buffer_f; buffer_output = buffer_i; } else { buffer_f = NULL; buffer_output = src_data.data_out; } src_state = src_new (SRC_SINC_BEST_QUALITY, sample_info->channels, &err); if (err) { error_print ("Error while creating the resampler: %s", src_strerror (err)); goto cleanup; } active = TRUE; if (control) { g_mutex_lock (&control->mutex); active = control->active; } sample_info->frames = ceil (sample_info_src->frames * ratio); //Upper bound estimation. The actual amount is updated later. sample_info->loop_start = round (sample_info_src->loop_start * ratio); sample_info->loop_end = round (sample_info_src->loop_end * ratio); sample_info_fix_frame_values (sample_info); sample = g_byte_array_sized_new (sample_info->frames * bytes_per_frame); idata_init (idata, sample, strdup (name), sample_info); if (control) { g_mutex_unlock (&control->mutex); } debug_print (2, "Loading sample (%d frames)...", sample_info_src->frames); read_frames = 0; while (read_frames < sample_info_src->frames && active) { debug_print (2, "Loading %d channels buffer...", sample_info->channels); if (sample_info->format == SF_FORMAT_FLOAT) { frames = sf_readf_float (sndfile, (gfloat *) buffer_input_multi, LOAD_BUFFER_LEN); } else if (sample_info->format == SF_FORMAT_PCM_32) { frames = sf_readf_int (sndfile, (gint32 *) buffer_input_multi, LOAD_BUFFER_LEN); } else { frames = sf_readf_short (sndfile, (gint16 *) buffer_input_multi, LOAD_BUFFER_LEN); } read_frames += frames; if (sample_info->channels == sample_info_src->channels) { buffer_input = buffer_input_multi; } else { if (sample_info->format == SF_FORMAT_FLOAT) { audio_multichannel_to_mono_float (buffer_input_multi, buffer_input_mono, frames, sample_info_src->channels); } else if (sample_info->format == SF_FORMAT_PCM_32) { audio_multichannel_to_mono_int (buffer_input_multi, buffer_input_mono, frames, sample_info_src->channels); } else { audio_multichannel_to_mono_short (buffer_input_multi, buffer_input_mono, frames, sample_info_src->channels); } if (sample_info->channels == 1) { buffer_input = buffer_input_mono; } else { if (sample_info->format == SF_FORMAT_FLOAT) { audio_mono_to_stereo_float (buffer_input_mono, buffer_input_stereo, frames); } else if (sample_info->format == SF_FORMAT_PCM_32) { audio_mono_to_stereo_int (buffer_input_mono, buffer_input_stereo, frames); } else { audio_mono_to_stereo_short (buffer_input_mono, buffer_input_stereo, frames); } buffer_input = buffer_input_stereo; } } if (sample_info->rate == sample_info_src->rate) { if (control) { g_mutex_lock (&control->mutex); } g_byte_array_append (sample, (guint8 *) buffer_input, frames * bytes_per_frame); actual_frames += frames; if (control) { g_mutex_unlock (&control->mutex); } } else { debug_print (2, "Resampling %d channels with ratio %f...", sample_info->channels, src_data.src_ratio); src_data.end_of_input = frames < LOAD_BUFFER_LEN ? SF_TRUE : 0; src_data.input_frames = frames; if (sample_info->format == SF_FORMAT_FLOAT) { src_data.data_in = buffer_input; } else if (sample_info->format == SF_FORMAT_PCM_32) { src_int_to_float_array (buffer_input, buffer_f, frames * sample_info->channels); } else { src_short_to_float_array (buffer_input, buffer_f, frames * sample_info->channels); } err = src_process (src_state, &src_data); if (err) { error_print ("Error while resampling: %s", src_strerror (err)); break; } if (control) { g_mutex_lock (&control->mutex); } if (sample_info->format == SF_FORMAT_PCM_32) { src_float_to_int_array (src_data.data_out, buffer_i, src_data.output_frames_gen * sample_info->channels); } if (sample_info->format == SF_FORMAT_PCM_16) { src_float_to_short_array (src_data.data_out, buffer_i, src_data.output_frames_gen * sample_info->channels); } g_byte_array_append (sample, (guint8 *) buffer_output, src_data.output_frames_gen * bytes_per_frame); actual_frames += src_data.output_frames_gen; if (control) { g_mutex_unlock (&control->mutex); } } if (control) { cb (control, read_frames * 1.0 / sample_info_src->frames, cb_data); active = job_control_get_active_lock (control); } } src_delete (src_state); cleanup: g_free (buffer_input_multi); g_free (buffer_input_mono); g_free (buffer_input_stereo); g_free (buffer_i); if (sample_info->format == SF_FORMAT_PCM_16 || sample_info->format == SF_FORMAT_PCM_32) { g_free (buffer_f); } g_free (src_data.data_out); sf_close (sndfile); if (!sample) { g_free (sample_info); return err; } if (control) { g_mutex_lock (&control->mutex); } if (!active || !sample_info->frames || err) { idata_free (idata); cb (control, 0, cb_data); g_mutex_unlock (&control->mutex); return -1; } // This removes the additional samples added by the estimation above. if (sample_info->frames > actual_frames) { rounding_fix = TRUE; sample_info->frames = actual_frames; sample_info_fix_frame_values (sample_info); sample->len = sample_info->frames * bytes_per_frame; } if (control) { //It there was a rounding fix in the previous lines, the call is needed to detect the end of the loading process. if (rounding_fix) { cb (control, 1.0, cb_data); } g_mutex_unlock (&control->mutex); } return 0; } gint sample_load_from_memfile (struct idata *memfile, struct idata *sample, struct job_control *control, const struct sample_info *sample_info_req, struct sample_info *sample_info_src) { struct g_byte_array_io_data data; data.pos = 0; data.array = memfile->content; return sample_load_libsndfile (&data, &G_BYTE_ARRAY_IO, control, sample, sample_info_req, sample_info_src, job_control_set_sample_progress_no_sync, NULL, memfile->name); } // Reloads the input into the output following all the requirements. gint sample_reload (struct idata *input, struct idata *output, struct job_control *control, const struct sample_info *sample_info_req, sample_load_cb cb, gpointer cb_data) { gint err; struct idata aux; struct sample_info sample_info_src; struct g_byte_array_io_data data; err = sample_get_memfile_from_sample (input, &aux, NULL, SF_FORMAT_WAV | SF_FORMAT_PCM_16); if (err) { return err; } data.pos = 0; data.array = aux.content; err = sample_load_libsndfile (&data, &G_BYTE_ARRAY_IO, control, output, sample_info_req, &sample_info_src, cb, cb_data, input->name); idata_free (&aux); return err; } gint sample_load_from_file_full (const gchar *path, struct idata *sample, struct job_control *control, const struct sample_info *sample_info_req, struct sample_info *sample_info_src, sample_load_cb cb, gpointer cb_data) { gint err; if (sample_microfreak_filename (path)) { struct idata aux; err = sample_load_microfreak_sample (path, &aux, control); if (err) { return err; } memcpy (sample_info_src, aux.info, sizeof (struct sample_info)); err = sample_reload (&aux, sample, control, sample_info_req, cb, cb_data); idata_free (&aux); } else { gchar *name; FILE *file = fopen (path, "rb"); if (!file) { return -errno; } name = g_path_get_basename (path); filename_remove_ext (name); err = sample_load_libsndfile (file, &FILE_IO, control, sample, sample_info_req, sample_info_src, cb, cb_data, name); g_free (name); fclose (file); } return err; } gint sample_load_from_file (const gchar *path, struct idata *sample, struct job_control *control, const struct sample_info *sample_info_req, struct sample_info *sample_info_src) { return sample_load_from_file_full (path, sample, control, sample_info_req, sample_info_src, job_control_set_sample_progress_no_sync, NULL); } const gchar ** sample_get_sample_extensions () { return ELEKTROID_AUDIO_LOCAL_EXTS; } const gchar * sample_get_format (struct sample_info *sample_info) { switch (sample_info->format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_WAV: return "WAV"; case SF_FORMAT_AIFF: return "AIFF"; case SF_FORMAT_AU: return "Au"; case SF_FORMAT_FLAC: return "FLAC"; case SF_FORMAT_OGG: return "Ogg"; #if !defined(__linux__) || HAVE_SNDFILE_MP3 case SF_FORMAT_MPEG: return "MPEG"; #endif default: return "?"; } } const gchar * sample_get_subtype (struct sample_info *sample_info) { switch (sample_info->format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8: return "s8"; case SF_FORMAT_PCM_16: return "s16"; case SF_FORMAT_PCM_24: return "s24"; case SF_FORMAT_PCM_32: return "s32"; case SF_FORMAT_PCM_U8: return "u8"; case SF_FORMAT_FLOAT: return "f32"; case SF_FORMAT_DOUBLE: return "f64"; default: return "?"; } } elektroid-3.2.3/src/sample.h000066400000000000000000000060221500236517400157250ustar00rootroot00000000000000/* * sample.h * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include #include #include #include "utils.h" #ifndef SAMPLE_H #define SAMPLE_H #define SAMPLE_SIZE(format) ((format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_16 ? 2 : 4) #define FRAME_SIZE(channels,format) ((channels) * SAMPLE_SIZE(format)) #define SAMPLE_INFO_FRAME_SIZE(sample_info) FRAME_SIZE((sample_info)->channels, (sample_info)->format) #define MONO_MIX_GAIN(channels) (channels == 2 ? 0.5 : 1.0 / sqrt (channels)) #define SAMPLE_GET_FILE_FORMAT(sample_info, sample_format) (((sample_info)->format & SF_FORMAT_TYPEMASK) | sample_format) typedef void (*sample_load_cb) (struct job_control * control, gdouble progress, gpointer data); void job_control_set_sample_progress_no_sync (struct job_control *control, gdouble p, gpointer data); gint sample_save_to_file (const gchar * path, struct idata *sample, struct job_control *control, guint32 format); gint sample_load_from_memfile (struct idata *memfile, struct idata *sample, struct job_control *control, const struct sample_info *sample_info_req, struct sample_info *sample_info_src); gint sample_load_from_file (const gchar * path, struct idata *sample, struct job_control *control, const struct sample_info *sample_info_req, struct sample_info *sample_info_src); gint sample_get_memfile_from_sample (struct idata *sample, struct idata *file, struct job_control *control, guint32 format); gint sample_load_from_file_full (const gchar * path, struct idata *sample, struct job_control *control, const struct sample_info *sample_info_req, struct sample_info *sample_info_src, sample_load_cb callback, gpointer data); gint sample_load_sample_info (const gchar * path, struct sample_info *sample_info); const gchar **sample_get_sample_extensions (); void sample_check_and_fix_loop_points (struct sample_info *sample_info); const gchar *sample_get_format (struct sample_info *sample_info); const gchar *sample_get_subtype (struct sample_info *sample_info); gint sample_reload (struct idata *input, struct idata *output, struct job_control *control, const struct sample_info *sample_info_req, sample_load_cb cb, gpointer cb_data); #endif elektroid-3.2.3/src/tasks.c000066400000000000000000000260411500236517400155670ustar00rootroot00000000000000/* * tasks.c * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #include "tasks.h" #include "backend.h" #include "browser.h" const gchar * tasks_get_human_status (enum task_status status) { switch (status) { case TASK_STATUS_QUEUED: return _("Queued"); case TASK_STATUS_RUNNING: return _("Running"); case TASK_STATUS_COMPLETED_OK: return _("Completed"); case TASK_STATUS_COMPLETED_ERROR: return _("Terminated with errors"); case TASK_STATUS_CANCELED: return _("Canceled"); default: return _("Undefined"); } } static const gchar * tasks_get_human_type (enum task_type type) { switch (type) { case TASK_TYPE_UPLOAD: return _("Upload"); case TASK_TYPE_DOWNLOAD: return _("Download"); default: return _("Undefined"); } } static void tasks_stop_current (GtkWidget *object, gpointer data) { struct tasks *tasks = data; job_control_set_active_lock (&tasks->transfer.control, FALSE); } void tasks_visit_pending (struct tasks *tasks, void (*visitor) (struct tasks *tasks, GtkTreeIter *iter)) { enum task_status status; GtkTreeIter iter; gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tasks->list_store), &iter); while (valid) { gtk_tree_model_get (GTK_TREE_MODEL (tasks->list_store), &iter, TASK_LIST_STORE_STATUS_FIELD, &status, -1); if (status == TASK_STATUS_QUEUED) { visitor (tasks, &iter); } valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (tasks->list_store), &iter); } } static gboolean tasks_get_current (struct tasks *tasks, GtkTreeIter *iter) { enum task_status status; gboolean found = FALSE; gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tasks->list_store), iter); while (valid) { gtk_tree_model_get (GTK_TREE_MODEL (tasks->list_store), iter, TASK_LIST_STORE_STATUS_FIELD, &status, -1); if (status == TASK_STATUS_RUNNING) { found = TRUE; break; } valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (tasks->list_store), iter); } return found; } gboolean tasks_complete_current (gpointer data) { struct tasks *tasks = data; GtkTreeIter iter; const gchar *status = tasks_get_human_status (tasks->transfer.status); if (tasks_get_current (tasks, &iter)) { gtk_list_store_set (tasks->list_store, &iter, TASK_LIST_STORE_STATUS_FIELD, tasks->transfer.status, TASK_LIST_STORE_STATUS_HUMAN_FIELD, status, -1); tasks_stop_current (NULL, tasks); g_free (tasks->transfer.src); g_free (tasks->transfer.dst); gtk_widget_set_sensitive (tasks->cancel_task_button, FALSE); } else { debug_print (1, "No task running. Skipping..."); } return FALSE; } gboolean tasks_get_next_queued (struct tasks *tasks, GtkTreeIter *iter, enum task_type *type, gchar **src, gchar **dst, gint *fs, guint *batch_id, guint *mode) { enum task_status status; gboolean found = FALSE; gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tasks->list_store), iter); while (valid) { if (type) { gtk_tree_model_get (GTK_TREE_MODEL (tasks->list_store), iter, TASK_LIST_STORE_STATUS_FIELD, &status, TASK_LIST_STORE_TYPE_FIELD, type, TASK_LIST_STORE_SRC_FIELD, src, TASK_LIST_STORE_DST_FIELD, dst, TASK_LIST_STORE_REMOTE_FS_ID_FIELD, fs, TASK_LIST_STORE_BATCH_ID_FIELD, batch_id, TASK_LIST_STORE_MODE_FIELD, mode, -1); } else { gtk_tree_model_get (GTK_TREE_MODEL (tasks->list_store), iter, TASK_LIST_STORE_STATUS_FIELD, &status, -1); } if (status == TASK_STATUS_QUEUED) { found = TRUE; break; } valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (tasks->list_store), iter); } return found; } static gboolean tasks_is_queued (enum task_status status) { return (status == TASK_STATUS_QUEUED); } static gboolean tasks_is_finished (enum task_status status) { return (status == TASK_STATUS_COMPLETED_OK || status == TASK_STATUS_COMPLETED_ERROR || status == TASK_STATUS_CANCELED); } gboolean tasks_check_buttons (gpointer data) { struct tasks *tasks = data; enum task_status status; gboolean queued = FALSE; gboolean finished = FALSE; GtkTreeIter iter; gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tasks->list_store), &iter); while (valid) { gtk_tree_model_get (GTK_TREE_MODEL (tasks->list_store), &iter, TASK_LIST_STORE_STATUS_FIELD, &status, -1); if (tasks_is_queued (status)) { queued = TRUE; } if (tasks_is_finished (status)) { finished = TRUE; } valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (tasks->list_store), &iter); } gtk_widget_set_sensitive (tasks->remove_tasks_button, queued); gtk_widget_set_sensitive (tasks->clear_tasks_button, finished); return FALSE; } static void tasks_remove_on_cond (struct tasks *tasks, gboolean (*selector) (enum task_status)) { enum task_status status; GtkTreeIter iter; gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tasks->list_store), &iter); while (valid) { gtk_tree_model_get (GTK_TREE_MODEL (tasks->list_store), &iter, TASK_LIST_STORE_STATUS_FIELD, &status, -1); if (selector (status)) { gtk_list_store_remove (tasks->list_store, &iter); valid = gtk_list_store_iter_is_valid (tasks->list_store, &iter); } else { valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (tasks->list_store), &iter); } } tasks_check_buttons (tasks); } static void tasks_remove_queued (GtkWidget *object, gpointer data) { tasks_remove_on_cond (data, tasks_is_queued); } static void tasks_clear_finished (GtkWidget *object, gpointer data) { tasks_remove_on_cond (data, tasks_is_finished); } static void tasks_visitor_set_canceled (struct tasks *tasks, GtkTreeIter *iter) { const gchar *canceled = tasks_get_human_status (TASK_STATUS_CANCELED); gtk_list_store_set (tasks->list_store, iter, TASK_LIST_STORE_STATUS_FIELD, TASK_STATUS_CANCELED, TASK_LIST_STORE_STATUS_HUMAN_FIELD, canceled, -1); } void tasks_cancel_all (GtkWidget *object, gpointer data) { tasks_visit_pending (data, tasks_visitor_set_canceled); tasks_stop_current (NULL, data); tasks_check_buttons (data); } void tasks_visitor_set_batch_status (struct tasks *tasks, GtkTreeIter *iter, enum task_mode mode) { gint batch_id; gtk_tree_model_get (GTK_TREE_MODEL (tasks->list_store), iter, TASK_LIST_STORE_BATCH_ID_FIELD, &batch_id, -1); if (batch_id == tasks->transfer.batch_id) { gtk_list_store_set (tasks->list_store, iter, TASK_LIST_STORE_MODE_FIELD, mode, -1); } } void tasks_visitor_set_batch_canceled (struct tasks *tasks, GtkTreeIter *iter) { gint batch_id; gtk_tree_model_get (GTK_TREE_MODEL (tasks->list_store), iter, TASK_LIST_STORE_BATCH_ID_FIELD, &batch_id, -1); if (batch_id == tasks->transfer.batch_id) { tasks_visitor_set_canceled (tasks, iter); } } void tasks_batch_visitor_set_skip (struct tasks *tasks, GtkTreeIter *iter) { tasks_visitor_set_batch_status (tasks, iter, TASK_MODE_SKIP); } void tasks_batch_visitor_set_replace (struct tasks *tasks, GtkTreeIter *iter) { tasks_visitor_set_batch_status (tasks, iter, TASK_MODE_REPLACE); } void tasks_add (struct tasks *tasks, enum task_type type, const char *src, const char *dst, gint remote_fs_id, struct backend *backend) { const gchar *status_human = tasks_get_human_status (TASK_STATUS_QUEUED); const gchar *type_human = tasks_get_human_type (type); const struct fs_operations *ops = backend_get_fs_operations_by_id (backend, remote_fs_id); gtk_list_store_insert_with_values (tasks->list_store, NULL, -1, TASK_LIST_STORE_STATUS_FIELD, TASK_STATUS_QUEUED, TASK_LIST_STORE_TYPE_FIELD, type, TASK_LIST_STORE_SRC_FIELD, src, TASK_LIST_STORE_DST_FIELD, dst, TASK_LIST_STORE_PROGRESS_FIELD, 0, TASK_LIST_STORE_STATUS_HUMAN_FIELD, status_human, TASK_LIST_STORE_TYPE_HUMAN_FIELD, type_human, TASK_LIST_STORE_REMOTE_FS_ID_FIELD, remote_fs_id, TASK_LIST_STORE_REMOTE_FS_ICON_FIELD, ops->gui_icon, TASK_LIST_STORE_BATCH_ID_FIELD, tasks->batch_id, TASK_LIST_STORE_MODE_FIELD, TASK_MODE_ASK, -1); gtk_widget_set_sensitive (tasks->remove_tasks_button, TRUE); } static void tasks_join_thread (struct tasks *tasks) { debug_print (2, "Joining task thread..."); g_mutex_lock (&tasks->transfer.control.mutex); g_cond_signal (&tasks->transfer.control.cond); g_mutex_unlock (&tasks->transfer.control.mutex); if (tasks->thread) { g_thread_join (tasks->thread); tasks->thread = NULL; } } void tasks_stop_thread (struct tasks *tasks) { debug_print (1, "Stopping task thread..."); job_control_set_active_lock (&tasks->transfer.control, FALSE); tasks_join_thread (tasks); } gboolean tasks_update_current_progress (gpointer data) { struct tasks *tasks = data; GtkTreeIter iter; gdouble progress; gint percent; if (tasks_get_current (tasks, &iter)) { g_mutex_lock (&tasks->transfer.control.mutex); progress = tasks->transfer.control.progress; g_mutex_unlock (&tasks->transfer.control.mutex); percent = (gint) (100.0 * progress); gtk_list_store_set (tasks->list_store, &iter, TASK_LIST_STORE_PROGRESS_FIELD, percent, -1); } return FALSE; } void tasks_init (struct tasks *tasks, GtkBuilder *builder) { tasks->list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "task_list_store")); tasks->tree_view = GTK_WIDGET (gtk_builder_get_object (builder, "task_tree_view")); tasks->cancel_task_button = GTK_WIDGET (gtk_builder_get_object (builder, "cancel_task_button")); tasks->remove_tasks_button = GTK_WIDGET (gtk_builder_get_object (builder, "remove_tasks_button")); tasks->clear_tasks_button = GTK_WIDGET (gtk_builder_get_object (builder, "clear_tasks_button")); g_signal_connect (tasks->cancel_task_button, "clicked", G_CALLBACK (tasks_cancel_all), tasks); g_signal_connect (tasks->remove_tasks_button, "clicked", G_CALLBACK (tasks_remove_queued), tasks); g_signal_connect (tasks->clear_tasks_button, "clicked", G_CALLBACK (tasks_clear_finished), tasks); } elektroid-3.2.3/src/tasks.h000066400000000000000000000062211500236517400155720ustar00rootroot00000000000000/* * tasks.h * Copyright (C) 2023 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef TASKS_H #define TASKS_H #include #include "connector.h" enum task_list_store_columns { TASK_LIST_STORE_STATUS_FIELD, TASK_LIST_STORE_TYPE_FIELD, TASK_LIST_STORE_SRC_FIELD, TASK_LIST_STORE_DST_FIELD, TASK_LIST_STORE_PROGRESS_FIELD, TASK_LIST_STORE_STATUS_HUMAN_FIELD, TASK_LIST_STORE_TYPE_HUMAN_FIELD, TASK_LIST_STORE_REMOTE_FS_ID_FIELD, TASK_LIST_STORE_REMOTE_FS_ICON_FIELD, TASK_LIST_STORE_BATCH_ID_FIELD, TASK_LIST_STORE_MODE_FIELD }; enum task_status { TASK_STATUS_QUEUED, TASK_STATUS_RUNNING, TASK_STATUS_COMPLETED_OK, TASK_STATUS_COMPLETED_ERROR, TASK_STATUS_CANCELED }; enum task_mode { TASK_MODE_ASK, TASK_MODE_REPLACE, TASK_MODE_SKIP }; enum task_type { TASK_TYPE_UPLOAD, TASK_TYPE_DOWNLOAD }; struct task_transfer { struct job_control control; gchar *src; //Contains a path to a file gchar *dst; //Contains a path to a file enum task_status status; //Contains the final status const struct fs_operations *fs_ops; //Contains the fs_operations to use in this transfer guint mode; guint batch_id; }; struct tasks { struct task_transfer transfer; GThread *thread; gint batch_id; GtkListStore *list_store; GtkWidget *tree_view; GtkWidget *cancel_task_button; GtkWidget *remove_tasks_button; GtkWidget *clear_tasks_button; }; void tasks_init (struct tasks *tasks, GtkBuilder * builder); gboolean tasks_get_next_queued (struct tasks *tasks, GtkTreeIter * iter, enum task_type *type, gchar ** src, gchar ** dst, gint * fs, guint * batch_id, guint * mode); gboolean tasks_complete_current (gpointer data); void tasks_cancel_all (GtkWidget * object, gpointer data); void tasks_visitor_set_batch_canceled (struct tasks *tasks, GtkTreeIter * iter); void tasks_batch_visitor_set_skip (struct tasks *tasks, GtkTreeIter * iter); void tasks_batch_visitor_set_replace (struct tasks *tasks, GtkTreeIter * iter); void tasks_stop_thread (struct tasks *tasks); const gchar *tasks_get_human_status (enum task_status status); gboolean tasks_check_buttons (gpointer data); void tasks_visit_pending (struct tasks *tasks, void (*visitor) (struct tasks * tasks, GtkTreeIter * iter)); void tasks_add (struct tasks *tasks, enum task_type type, const char *src, const char *dst, gint remote_fs_id, struct backend *backend); gboolean tasks_update_current_progress (gpointer data); #endif elektroid-3.2.3/src/utils.c000066400000000000000000000241171500236517400156040ustar00rootroot00000000000000/* * utils.c * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #include #if !defined(__linux__) #include #endif #include #include "utils.h" #define DEBUG_SHORT_HEX_LEN 64 #define DEBUG_FULL_HEX_THRES 5 gint debug_level; static guint get_max_message_length (guint msg_len) { guint len; if (debug_level >= DEBUG_FULL_HEX_THRES) { len = msg_len; } else { len = msg_len > DEBUG_SHORT_HEX_LEN ? DEBUG_SHORT_HEX_LEN : msg_len; } return len; } gchar * debug_get_hex_data (gint level, guint8 *data, guint len) { gint i; guint8 *b; guint size; guint bytes_shown; guint extra; gchar *str; gchar *next; if (level >= DEBUG_FULL_HEX_THRES) { bytes_shown = len; extra = 0; } else { if (len > DEBUG_SHORT_HEX_LEN) { bytes_shown = DEBUG_SHORT_HEX_LEN; extra = 3; } else { bytes_shown = len; extra = 0; } } size = bytes_shown * 3 + extra; if (!size) { return NULL; } str = g_malloc (sizeof (char) * size); b = data; next = str; sprintf (next, "%02x", *b); next += 2; b++; i = 1; while (i < get_max_message_length (len)) { sprintf (next, " %02x", *b); next += 3; b++; i++; } if (level < DEBUG_FULL_HEX_THRES && len > DEBUG_SHORT_HEX_LEN) { sprintf (next, "..."); next += 3; } return str; } gchar * debug_get_hex_msg (const GByteArray *msg) { return debug_get_hex_data (debug_level, msg->data, msg->len); } void filename_remove_ext (char *name) { gint namelen = strlen (name); gchar *dot = &name[namelen - 1]; gint i = namelen - 1; while (i > 0) { if (*dot == '.') { *dot = 0; break; } dot--; i--; } } const gchar * filename_get_ext (const gchar *name) { int namelen = strlen (name); const gchar *ext = &name[namelen], *p = name; for (guint i = 0; i < namelen; i++, p++) { if (*p == '.') { i++; p++; ext = p; } } return ext; } //The returned value is owned by the caller. //As this is used from the code, rel_dir uses '/' always and needs to be converted. gchar * get_user_dir (const char *rel_dir) { const gchar *home = g_get_home_dir (); if (rel_dir) { gchar *rel_dir_conv = path_translate (PATH_SYSTEM, rel_dir); gchar *dir = path_chain (PATH_SYSTEM, home, rel_dir_conv); g_free (rel_dir_conv); return dir; } else { return strdup (home); } } char * get_system_startup_path (const gchar *local_dir) { DIR *dir; gchar *startup_path = NULL; if (local_dir) { dir = opendir (local_dir); if (dir) { startup_path = strdup (local_dir); } else { error_print ("Unable to open dir '%s'", local_dir); } closedir (dir); } if (!startup_path) { startup_path = get_user_dir (NULL); } debug_print (1, "Using '%s' as local dir...", startup_path); return startup_path; } void free_msg (gpointer msg) { g_byte_array_free ((GByteArray *) msg, TRUE); } gint file_load (const char *path, struct idata *idata, struct job_control *control) { FILE *f; size_t size; gint res; GByteArray *array; f = fopen (path, "rb"); if (!f) { return -errno; } res = 0; if (fseek (f, 0, SEEK_END)) { error_print ("Unexpected value"); res = -errno; goto end; } size = ftell (f); rewind (f); array = g_byte_array_sized_new (size); array->len = size; if (fread (array->data, 1, size, f) == size) { gchar *name = g_path_get_basename (path); filename_remove_ext (name); idata_init (idata, array, strdup (name), NULL); g_free (name); debug_print (1, "%zu B read", size); } else { error_print ("Error while reading from file %s", path); g_byte_array_free (array, TRUE); res = -errno; } end: fclose (f); return res; } gint file_save_data (const gchar *path, const guint8 *data, ssize_t len) { gint res; size_t bytes; FILE *file; file = fopen (path, "wb"); if (!file) { return -errno; } debug_print (1, "Saving file %s...", path); res = 0; bytes = fwrite (data, 1, len, file); if (bytes == len) { debug_print (1, "%zu B written", bytes); } else { error_print ("Error while writing to file %s", path); res = -EIO; } fclose (file); return res; } gint file_save (const gchar *path, struct idata *idata, struct job_control *control) { return file_save_data (path, idata->content->data, idata->content->len); } gchar * get_human_size (gint64 size, gboolean with_space) { gchar *label = g_malloc (LABEL_MAX); gchar *space = with_space ? " " : ""; if (size < 0) { *label = 0; } else if (size < KI) { snprintf (label, LABEL_MAX, "%" PRId64 "%sB", size, space); } else if (size < MI) { snprintf (label, LABEL_MAX, "%.4g%sKiB", size / (double) KI, space); } else if (size < GI) { snprintf (label, LABEL_MAX, "%.4g%sMiB", size / (double) MI, space); } else { snprintf (label, LABEL_MAX, "%.4g%sGiB", size / (double) GI, space); } return label; } static inline void job_control_set_progress_value (struct job_control *control, gdouble p) { if (control->parts) { if (control->part == control->parts) { control->progress = 1.0; } else { control->progress = (control->part / (double) control->parts) + (p / (double) control->parts); } } else { control->progress = 0.0; } } void job_control_set_sample_progress_no_sync (struct job_control *control, gdouble p, gpointer data) { job_control_set_progress_value (control, p); if (control->callback) { control->callback (control); } } void job_control_set_progress (struct job_control *control, gdouble p) { g_mutex_lock (&control->mutex); job_control_set_progress_value (control, p); g_mutex_unlock (&control->mutex); if (control->callback) { control->callback (control); } } gboolean file_matches_extensions (const gchar *name, const gchar **extensions) { const gchar *extension; const gchar **e = extensions; if (!e) { return TRUE; } extension = filename_get_ext (name); if (!*extension) { return FALSE; } while (*e) { if (!strcasecmp (extension, *e)) { return TRUE; } e++; } return FALSE; } static inline const gchar * path_get_separator (enum path_type type) { const gchar *sep; if (type == PATH_SYSTEM) { #if defined(__MINGW32__) | defined(__MINGW64__) sep = "\\"; #else sep = "/"; #endif } else { sep = "/"; } return sep; } gchar * path_chain (enum path_type type, const gchar *parent, const gchar *child) { const gchar *sep = path_get_separator (type); return g_build_path (sep, parent, child, NULL); } //Translate from internal path to system path. gchar * path_translate (enum path_type type, const gchar *input) { gchar *output, *o; const gchar *i; const gchar *sep = path_get_separator (type); if (!strcmp (sep, "/")) { return strdup (input); } output = g_malloc (strlen (input) * 2 + 1); //Worst case scenario i = input; o = output; while (*i) { if (*i == '/') { *o = 0; strcat (o, sep); o += strlen (sep); } else { *o = *i; o++; } i++; } *o = 0; return output; } //These two functions are needed as g_filename_to_uri and g_uri_to_filename //depend on the local system and therefore can not be used for BE_TYPE_MIDI //under MSYS2. gchar * path_filename_from_uri (enum path_type type, gchar *uri) { if (type == PATH_SYSTEM) { return g_filename_from_uri (uri, NULL, NULL); } const gchar *filename = &uri[7]; //Skip "file://". return g_uri_unescape_string (filename, ":/"); } gchar * path_filename_to_uri (enum path_type type, gchar *filename) { if (type == PATH_SYSTEM) { return g_filename_to_uri (filename, NULL, NULL); } gchar *uri = g_strconcat ("file://", filename, NULL); gchar *escaped_uri = g_uri_escape_string (uri, ":/", FALSE); g_free (uri); return escaped_uri; } void gslist_fill (GSList **list, ...) { gpointer v; va_list argptr; *list = NULL; va_start (argptr, list); while ((v = va_arg (argptr, gpointer))) { *list = g_slist_append (*list, v); } va_end (argptr); } void idata_init (struct idata *idata, GByteArray *content, gchar *name, void *info) { idata->content = content; idata->name = name; idata->info = info; } void idata_free (struct idata *idata) { if (idata->content) { g_byte_array_free (idata->content, TRUE); idata->content = NULL; } g_free (idata->name); idata->name = NULL; g_free (idata->info); idata->info = NULL; } GByteArray * idata_steal (struct idata *idata) { g_free (idata->name); g_free (idata->info); return idata->content; } gboolean job_control_get_active_lock (struct job_control *control) { gboolean active; g_mutex_lock (&control->mutex); active = control->active; g_mutex_unlock (&control->mutex); return active; } void job_control_set_active_lock (struct job_control *control, gboolean active) { g_mutex_lock (&control->mutex); control->active = active; g_mutex_unlock (&control->mutex); } void job_control_reset (struct job_control *control, gint parts) { control->parts = parts; control->part = 0; job_control_set_progress (control, 0.0); } elektroid-3.2.3/src/utils.h000066400000000000000000000075731500236517400156200ustar00rootroot00000000000000/* * utils.h * Copyright (C) 2019 David García Goñi * * This file is part of Elektroid. * * Elektroid 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. * * Elektroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Elektroid. If not, see . */ #ifndef UTILS_H #define UTILS_H #include #include #include #include #include #include "../config.h" #define CONF_DIR "/.config/" PACKAGE #define APP_NAME "Elektroid" #define LABEL_MAX 256 #define KI 1024 #define MI (KI * KI) #define GI (KI * MI) #define debug_print(level, format, ...) {\ if (level <= debug_level) \ { \ fprintf(stderr, "DEBUG:" __FILE__ ":%d:%s: " format "\n", __LINE__, __FUNCTION__, ## __VA_ARGS__); \ } \ } #define error_print(format, ...) { \ gboolean tty = isatty(fileno(stderr)); \ fprintf(stderr, "%sERROR:" __FILE__ ":%d:%s: " format "%s\n", tty ? "\x1b[31m" : "", __LINE__, __FUNCTION__, ## __VA_ARGS__, tty ? "\x1b[m" : ""); \ } struct sample_info { guint32 frames; guint32 loop_start; guint32 loop_end; guint32 loop_type; // 0 = forward loop guint32 rate; guint32 format; // Used as in libsndfile. guint32 channels; guint32 midi_note; }; struct job_control; typedef void (*job_control_callback) (struct job_control *); struct job_control { gboolean active; GMutex mutex; GCond cond; //This can be used by the calling threads. It requires to call g_cond_init and g_cond_clear. job_control_callback callback; gint parts; gint part; gdouble progress; }; enum path_type { PATH_INTERNAL, // Slash separated paths PATH_SYSTEM // Slash or backslash depending on the system }; struct idata { GByteArray *content; gchar *name; //Optional field to store a name void *info; //Optional field to store information about the content }; extern int debug_level; gchar *debug_get_hex_data (gint, guint8 *, guint); gchar *debug_get_hex_msg (const GByteArray *); void filename_remove_ext (gchar *); const gchar *filename_get_ext (const gchar *); gchar *get_user_dir (const gchar *); gchar *get_system_startup_path (const gchar *); void free_msg (gpointer); gint file_load (const char *path, struct idata *idata, struct job_control *control); gint file_save (const char *path, struct idata *idata, struct job_control *control); gint file_save_data (const gchar * path, const guint8 * data, ssize_t len); gchar *get_human_size (gint64, gboolean); void job_control_set_progress_no_sync (struct job_control *control, gdouble progress); void job_control_set_progress (struct job_control *control, gdouble progress); gboolean file_matches_extensions (const gchar * name, const gchar ** extensions); gchar *path_chain (enum path_type, const gchar *, const gchar *); gchar *path_translate (enum path_type, const gchar *); gchar *path_filename_from_uri (enum path_type, gchar *); gchar *path_filename_to_uri (enum path_type, gchar *); void gslist_fill (GSList ** list, ...); void idata_init (struct idata *idata, GByteArray * content, gchar * name, void *info); void idata_free (struct idata *idata); GByteArray *idata_steal (struct idata *idata); gboolean job_control_get_active_lock (struct job_control *control); void job_control_set_active_lock (struct job_control *control, gboolean active); void job_control_reset (struct job_control *control, gint parts); #endif elektroid-3.2.3/test/000077500000000000000000000000001500236517400144635ustar00rootroot00000000000000elektroid-3.2.3/test/Makefile.am000066400000000000000000000104761500236517400165270ustar00rootroot00000000000000PKG_CONFIG ?= pkg-config if MINGW MSYS2_LIBS = -lws2_32 endif if ELEKTROID_RTMIDI BE_LIBS = rtmidi BE_SOURCES = ../src/backend_rtmidi.c else BE_LIBS = alsa BE_SOURCES = ../src/backend_alsa.c endif AM_CPPFLAGS = -Wall -DTEST_DATA_DIR='"$(srcdir)/res"' -DDATADIR='"../res"' check_PROGRAMS = tests_scala tests_common tests_microfreak tests_elektron tests_utils tests_sample tests_connector tests_LIBS = glib-2.0 json-glib-1.0 cunit libzip zlib $(BE_LIBS) tests_scala_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(tests_LIBS)` -pthread tests_scala_LDFLAGS = `$(PKG_CONFIG) --libs $(tests_LIBS)` $(MSYS2_LIBS) tests_scala_SOURCES = \ tests_scala.c \ ../src/utils.c \ ../src/utils.h \ ../src/connectors/scala.c \ ../src/connectors/scala.h tests_common_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(tests_LIBS)` $(SNDFILE_CFLAGS) $(SAMPLERATE_CFLAGS) -pthread tests_common_LDFLAGS = `$(PKG_CONFIG) --libs $(tests_LIBS)` $(SNDFILE_LIBS) $(SAMPLERATE_LIBS) $(MSYS2_LIBS) tests_common_SOURCES = \ tests_common.c \ ../src/utils.c \ ../src/utils.h \ ../src/preferences.c \ ../src/preferences.h \ ../src/backend.c \ ../src/backend.h \ ../src/connector.c \ ../src/connector.h \ $(BE_SOURCES) \ ../src/connectors/common.c \ ../src/connectors/common.h \ ../src/sample.c \ ../src/sample.h \ ../src/connectors/microfreak_sample.c \ ../src/connectors/microfreak_sample.h tests_microfreak_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(tests_LIBS)` $(SNDFILE_CFLAGS) $(SAMPLERATE_CFLAGS) -pthread tests_microfreak_LDFLAGS = `$(PKG_CONFIG) --libs $(tests_LIBS)` $(SNDFILE_LIBS) $(SAMPLERATE_LIBS) $(MSYS2_LIBS) tests_microfreak_SOURCES = \ tests_microfreak.c \ ../src/utils.c \ ../src/utils.h \ ../src/preferences.c \ ../src/preferences.h \ ../src/backend.c \ ../src/backend.h \ ../src/connector.c \ ../src/connector.h \ $(BE_SOURCES) \ ../src/connectors/common.c \ ../src/connectors/common.h \ ../src/connectors/microfreak_sample.c \ ../src/connectors/microfreak_sample.h \ ../src/sample.c \ ../src/sample.h \ ../src/connectors/microfreak.c \ ../src/connectors/microfreak.h tests_elektron_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(tests_LIBS)` $(SNDFILE_CFLAGS) $(SAMPLERATE_CFLAGS) -pthread tests_elektron_LDFLAGS = `$(PKG_CONFIG) --libs $(tests_LIBS)` $(SNDFILE_LIBS) $(SAMPLERATE_LIBS) $(MSYS2_LIBS) tests_elektron_SOURCES = \ tests_elektron.c \ ../src/utils.c \ ../src/utils.h \ ../src/preferences.c \ ../src/preferences.h \ ../src/backend.c \ ../src/backend.h \ ../src/connector.c \ ../src/connector.h \ $(BE_SOURCES) \ ../src/connectors/common.c \ ../src/connectors/common.h \ ../src/connectors/microfreak_sample.c \ ../src/connectors/microfreak_sample.h \ ../src/sample.c \ ../src/sample.h \ ../src/connectors/package.c \ ../src/connectors/package.h \ ../src/connectors/elektron.c \ ../src/connectors/elektron.h tests_utils_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(tests_LIBS)` -pthread tests_utils_LDFLAGS = `$(PKG_CONFIG) --libs $(tests_LIBS)` $(MSYS2_LIBS) tests_utils_SOURCES = \ tests_utils.c \ ../src/utils.c \ ../src/utils.h tests_sample_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(tests_LIBS)` $(SNDFILE_CFLAGS) $(SAMPLERATE_CFLAGS) -pthread tests_sample_LDFLAGS = `$(PKG_CONFIG) --libs $(tests_LIBS)` $(SNDFILE_LIBS) $(SAMPLERATE_LIBS) $(MSYS2_LIBS) tests_sample_SOURCES = \ tests_sample.c \ ../src/utils.c \ ../src/utils.h \ ../src/connectors/microfreak_sample.c \ ../src/connectors/microfreak_sample.h \ ../src/sample.c \ ../src/sample.h tests_connector_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(tests_LIBS)` -pthread tests_connector_LDFLAGS = `$(PKG_CONFIG) --libs $(tests_LIBS)` $(MSYS2_LIBS) tests_connector_SOURCES = \ tests_connector.c \ ../src/utils.c \ ../src/utils.h \ ../src/preferences.c \ ../src/preferences.h \ ../src/backend.c \ ../src/backend.h \ ../src/connector.c \ ../src/connector.h \ $(BE_SOURCES) TESTS = integration/test.sh integration/system_all_fs_tests.sh $(check_PROGRAMS) EXTRA_DIST = integration res AM_TESTS_ENVIRONMENT = \ ecli='$(abs_top_builddir)/src/elektroid-cli -vv'; \ export ecli; elektroid-3.2.3/test/integration/000077500000000000000000000000001500236517400170065ustar00rootroot00000000000000elektroid-3.2.3/test/integration/cz_program_fs_tests.sh000077500000000000000000000004701500236517400234230ustar00rootroot00000000000000#!/usr/bin/env bash #ls / [ $($ecli cz-program-ls $TEST_DEVICE:/ | wc -l) -ne 3 ] && exit 1 #panel id (1 based) $ecli cz-program-dl $TEST_DEVICE:/97 err=$? rm *.syx [ $err -ne 0 ] && exit $err $srcdir/integration/generic_fs_tests.sh cz program /internal 16 "/internal/0 /internal/17" /internal/16 "" exit $? elektroid-3.2.3/test/integration/efactor_preset_fs_tests.sh000077500000000000000000000001571500236517400242670ustar00rootroot00000000000000#!/usr/bin/env bash $srcdir/integration/generic_fs_tests.sh efactor preset / 100 /100 /99 "New Name" exit $? elektroid-3.2.3/test/integration/elektron_data_fs_tests.sh000077500000000000000000000062061500236517400240770ustar00rootroot00000000000000#!/usr/bin/env bash function cleanupAndExit () { for s in 1 62 63 64 256; do if [ -f $s.dtdata.bak ]; then $ecli elektron-data-ul $s.dtdata.bak $TEST_DEVICE:/soundbanks/H/$s rm -f $s.dtdata.bak fi done exit $1 } function get_sound_n_with_id () { s="sound$1" echo "${!s}" | sed "s/^F $1 0012/F $2 007e/" } echo "Using device $TEST_DEVICE..." echo "Preparing tests..." for s in 1 62 63 64 256; do $ecli elektron-data-dl $TEST_DEVICE:/soundbanks/H/$s mv *.dtdata $s.dtdata.bak > /dev/null 2>&1 done $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/1 sound1=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/A | grep "^F 1") nsound1=$(get_sound_n_with_id 1 64) sound2=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/A | grep "^F 2") echo "Testing data copy..." $ecli elektron-data-cp $TEST_DEVICE:/soundbanks/A/1 $TEST_DEVICE:/soundbanks/H/64 [ $? -ne 0 ] && cleanupAndExit 1 $ecli elektron-data-cp $TEST_DEVICE:/soundbanks/A/2 $TEST_DEVICE:/soundbanks/H/63 [ $? -ne 0 ] && cleanupAndExit 1 output=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/H) actual=$(echo "$output" | grep "^F 64") expected=$(get_sound_n_with_id 1 64) [ "$actual" != "$expected" ] && cleanupAndExit 1 actual=$(echo "$output" | grep "^F 63") expected=$(get_sound_n_with_id 2 63) [ "$actual" != "$expected" ] && cleanupAndExit 1 echo "Testing data move..." $ecli elektron-data-mv $TEST_DEVICE:/soundbanks/H/64 $TEST_DEVICE:/soundbanks/H/62 [ $? -ne 0 ] && cleanupAndExit 1 output=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/H) actual=$(echo "$output" | grep "^F 62") expected=$(get_sound_n_with_id 1 62) [ "$actual" != "$expected" ] && cleanupAndExit 1 actual=$(echo "$output" | grep "^F 64") [ -n "$actual" ] && cleanupAndExit 1 echo "Testing data swap..." $ecli elektron-data-sw $TEST_DEVICE:/soundbanks/H/62 $TEST_DEVICE:/soundbanks/H/63 [ $? -ne 0 ] && cleanupAndExit 1 output=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/H) actual=$(echo "$output" | grep "^F 62") expected=$(get_sound_n_with_id 2 62) [ "$actual" != "$expected" ] && cleanupAndExit 1 actual=$(echo "$output" | grep "^F 63") expected=$(get_sound_n_with_id 1 63) [ "$actual" != "$expected" ] && cleanupAndExit 1 echo "Testing data clear..." $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/63 [ $? -ne 0 ] && cleanupAndExit 1 $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/62 [ $? -ne 0 ] && cleanupAndExit 1 output=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/H) [ $(echo "$output" | grep "^F 62" | wc -l) -ne 0 ] && cleanupAndExit 1 [ $(echo "$output" | grep "^F 63" | wc -l) -ne 0 ] && cleanupAndExit 1 echo "Testing upload without slot..." $ecli elektron-data-ul $srcdir/res/connectors/SOUND.dtdata $TEST_DEVICE:/soundbanks/H [ $? -eq 0 ] && cleanupAndExit 1 echo "Testing upload..." $ecli elektron-data-ul $srcdir/res/connectors/SOUND.dtdata $TEST_DEVICE:/soundbanks/H/256 [ $? -ne 0 ] && cleanupAndExit 1 id=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/H | tail -n 1 | grep SOUND | awk '{print $6}') [ "$id" != 256 ] && cleanupAndExit 1 echo "Testing data clear..." $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/256 [ $? -ne 0 ] && cleanupAndExit 1 cleanupAndExit 0 elektroid-3.2.3/test/integration/elektron_project_fs_tests.sh000077500000000000000000000023611500236517400246320ustar00rootroot00000000000000#!/usr/bin/env bash err=0 echo "Cleaning up sample..." $ecli elektron-sample-rm $TEST_DEVICE:/auto-test/square $ecli elektron-sample-rmdir $TEST_DEVICE:/auto-test echo "Preparing tests..." $ecli elektron-project-ul $srcdir/res/connectors/elektron_project.data $TEST_DEVICE:/128 $ecli elektron-project-dl $TEST_DEVICE:/128 src_content=$(unzip -l $srcdir/res/connectors/elektron_project.data | tail -n +4 | head -n -2 | awk '{print $1" "$4}') dst_content=$(unzip -l $srcdir/PROJECT.dtprj | tail -n +4 | head -n -2 | awk '{print $1" "$4}') echo "Comparing zip files..." echo "$src_content" echo "---" echo "$dst_content" cksum1=$(echo "$src_content" | cksum) cksum2=$(echo "$dst_content" | cksum) [ "$cksum1" != "$cksum2" ] && err=1 if [ $err -eq 0 ]; then echo "Looking for sample..." $ecli elektron-sample-dl $TEST_DEVICE:/auto-test/square [ $? -ne 0 ] && err=1 fi if [ $err -eq 0 ]; then $srcdir/integration/generic_fs_tests.sh --no-download elektron project / 128 "/0 /129" /128 "" [ $? -ne 0 ] && err=1 fi echo "Cleaning up..." rm -f $srcdir/PROJECT.dtprj rm -f $srcdir/square.wav $ecli elektron-project-rm $TEST_DEVICE:/H/256 $ecli elektron-sample-rm $TEST_DEVICE:/auto-test/square $ecli elektron-sample-rmdir $TEST_DEVICE:/auto-test exit $err elektroid-3.2.3/test/integration/elektron_sample_fs_tests.sh000077500000000000000000000053151500236517400244470ustar00rootroot00000000000000#!/usr/bin/env bash TEST_NAME=auto-test echo "Using device $TEST_DEVICE..." echo "Testing info..." $ecli info $TEST_DEVICE:/ [ $? -ne 0 ] && exit 1 echo "Testing df..." $ecli df $TEST_DEVICE:/ [ $? -ne 0 ] && exit 1 echo "Testing ls..." $ecli elektron-sample-ls $TEST_DEVICE:/ [ $? -ne 0 ] && exit 1 echo "Testing mkdir..." $ecli elektron-sample-mkdir $TEST_DEVICE:/$TEST_NAME [ $? -ne 0 ] && exit 1 $ecli elektron-sample-ls $TEST_DEVICE:/$TEST_NAME [ $? -ne 0 ] && exit 1 echo "Testing upload..." $ecli elektron-sample-ul $srcdir/res/connectors/square.wav $TEST_DEVICE:/$TEST_NAME [ $? -ne 0 ] && exit 1 output=$($ecli elektron-sample-ls $TEST_DEVICE:/$TEST_NAME) type=$(echo "$output" | head -n 1 | awk '{print $1}') size=$(echo "$output" | head -n 1 | awk '{print $2}') name=$(echo "$output" | head -n 1 | awk '{print $4}') [ "$type" != "F" ] || [ "$size" != "93.81KiB" ] || [ "$name" != "square" ] && exit 1 echo "Testing upload (nonexistent source)..." $ecli elektron-sample-upload $srcdir/res/connectors/foo $TEST_DEVICE:/$TEST_NAME [ $? -eq 0 ] && exit 1 echo "Testing download..." $ecli elektron-sample-download $TEST_DEVICE:/$TEST_NAME/square [ $? -ne 0 ] && exit 1 actual_cksum="$(cksum square.wav | awk '{print $1}')" rm square.wav [ "$actual_cksum" != "$(cksum $srcdir/res/connectors/square.wav | awk '{print $1}')" ] && exit 1 echo "Testing download (nonexistent source)..." $ecli elektron-sample-dl $TEST_DEVICE:/$TEST_NAME/foo [ $? -eq 0 ] && exit 1 echo "Testing mv..." $ecli elektron-sample-mv $TEST_DEVICE:/$TEST_NAME/square $TEST_DEVICE:/$TEST_NAME/sample [ $? -ne 0 ] && exit 1 echo "Testing mv (nonexistent file)..." $ecli elektron-sample-mv $TEST_DEVICE:/$TEST_NAME/foo $TEST_DEVICE:/$TEST_NAME/sample [ $? -eq 0 ] && exit 1 echo "Testing rm..." $ecli elektron-sample-rm $TEST_DEVICE:/$TEST_NAME/sample [ $? -ne 0 ] && exit 1 echo "Testing rm (nonexistent file)..." $ecli elektron-sample-rm $TEST_DEVICE:/$TEST_NAME/sample [ $? -eq 0 ] && exit 1 echo "Testing rmdir..." $ecli elektron-sample-rmdir $TEST_DEVICE:/$TEST_NAME [ $? -ne 0 ] && exit 1 echo "Testing rmdir (nonexistent dir)..." $ecli elektron-sample-rmdir $TEST_DEVICE:/$TEST_NAME [ $? -eq 0 ] && exit 1 echo "Testing recursive mkdir..." $ecli elektron-sample-mkdir $TEST_DEVICE:/$TEST_NAME/foo [ $? -ne 0 ] && exit 1 echo "Testing recursive rmdir..." $ecli elektron-sample-rmdir $TEST_DEVICE:/$TEST_NAME [ $? -ne 0 ] && exit 1 echo "Testing ls (nonexistent dir) [fails on versions newer than 1.40B]..." $ecli elektron-sample-ls $TEST_DEVICE:/$TEST_NAME [ $? -eq 0 ] && exit 1 echo "Testing ls (nonexistent dir inside nonexistent dir) [fails on versions newer than 1.40B]..." $ecli elektron-sample-ls $TEST_DEVICE:/$TEST_NAME/foo [ $? -eq 0 ] && exit 1 exit 0 elektroid-3.2.3/test/integration/elektron_sound_fs_tests.sh000077500000000000000000000030621500236517400243130ustar00rootroot00000000000000#!/usr/bin/env bash err=0 echo "Cleaning up sample..." $ecli elektron-sample-rm $TEST_DEVICE:/auto-test/square $ecli elektron-sample-rmdir $TEST_DEVICE:/auto-test echo "Preparing tests..." $ecli elektron-sound-ul $srcdir/res/connectors/elektron_sound.data $TEST_DEVICE:/H/256 $ecli elektron-sound-dl $TEST_DEVICE:/H/256 src_content=$(unzip -l $srcdir/res/connectors/elektron_sound.data | tail -n +4 | head -n -2 | awk '{print $1" "$4}') dst_content=$(unzip -l $srcdir/SOUND.dtsnd | tail -n +4 | head -n -2 | awk '{print $1" "$4}') echo "Comparing zip files..." echo "$src_content" echo "---" echo "$dst_content" cksum1=$(echo "$src_content" | cksum) cksum2=$(echo "$dst_content" | cksum) [ "$cksum1" != "$cksum2" ] && err=1 src_manifest_content=$(unzip -p $srcdir/res/connectors/elektron_sound.data manifest.json) dst_manifest_content=$(unzip -p $srcdir/SOUND.dtsnd manifest.json) echo "Checking manifest.json..." echo "$src_manifest_content" echo "---" echo "$dst_manifest_content" [ "$src_manifest_content" != "$dst_manifest_content" ] && err=1 if [ $err -eq 0 ]; then echo "Looking for sample..." $ecli elektron-sample-dl $TEST_DEVICE:/auto-test/square [ $? -ne 0 ] && err=1 fi if [ $err -eq 0 ]; then $srcdir/integration/generic_fs_tests.sh --no-download elektron sound /H 256 "/H/0 /H/257" /H/256 "" [ $? -ne 0 ] && err=1 fi echo "Cleaning up..." rm -f $srcdir/SOUND.dtsnd rm -f $srcdir/square.wav $ecli elektron-sound-rm $TEST_DEVICE:/H/256 $ecli elektron-sample-rm $TEST_DEVICE:/auto-test/square $ecli elektron-sample-rmdir $TEST_DEVICE:/auto-test exit $err elektroid-3.2.3/test/integration/generic_fs_tests.sh000077500000000000000000000051071500236517400226760ustar00rootroot00000000000000#!/usr/bin/env bash download=true [ "$1" == "--no-download" ] && shift && download=false CONN=$1 FS=$2 DIR_PATH=$3 LS_ROWS=$4 BAD_FILE_PATHS=$5 FILE_PATH=$6 FILE_NEW_NAME=$7 FILE_TO_UPLOAD=$srcdir/res/connectors/${CONN}_${FS}.data FILE_UPLOADED_BACK="$FILE_TO_UPLOAD.back" if [ ! -f "$FILE_UPLOADED_BACK" ]; then FILE_UPLOADED_BACK="$FILE_TO_UPLOAD" fi BACKUP_PREFIX="Backup - " function exitWithError() { if [ -n "$FILE_BACKUP" ]; then echo "Restoring..." $ecli ${CONN}-${FS}-ul "$FILE_BACKUP" $TEST_DEVICE:$FILE_PATH fi rm -f "$FILE" rm -f "$FILE_BACKUP" exit $1 } echo "Using device $TEST_DEVICE..." DEVICE_NAME=$(elektroid-cli info $TEST_DEVICE | grep "Device name:" | awk -F': ' '{print $2}') echo "Device name: $DEVICE_NAME" echo "Cleaning up previous executions..." rm -f "$srcdir/$DEVICE_NAME $FS"* rm -f "$srcdir/$BACKUP_PREFIX$DEVICE_NAME $FS"* echo "Testing ls..." files=$($ecli ${CONN}-${FS}-ls $TEST_DEVICE:$DIR_PATH) [ $? -ne 0 ] && exit 1 echo "$files" | head [ $(echo "$files" | wc -l) -ne $LS_ROWS ] && exit 1 if $download; then for p in $BAD_FILE_PATHS; do echo "Testing download with bad path $p..." $ecli ${CONN}-${FS}-dl $TEST_DEVICE:$p [ $? -eq 0 ] && exit 1 done echo "Testing download with path $FILE_PATH..." $ecli ${CONN}-${FS}-dl $TEST_DEVICE:$FILE_PATH [ $? -ne 0 ] && exit 1 FILE=$(echo "$srcdir/$DEVICE_NAME $FS"*) [ ! -f "$FILE" ] && exit 1 FILE_BACKUP=$srcdir/$BACKUP_PREFIX$(basename "$FILE") mv "$FILE" "$FILE_BACKUP" fi for p in $BAD_FILE_PATHS; do echo "Testing upload with bad path $p..." $ecli ${CONN}-${FS}-ul $FILE_TO_UPLOAD $TEST_DEVICE:$p [ $? -eq 0 ] && exitWithError 1 done echo "Testing upload with non existing file to $FILE_PATH..." $ecli ${CONN}-${FS}-ul foo $TEST_DEVICE:$FILE_PATH [ $? -eq 0 ] && exitWithError 1 echo "Testing upload with path $FILE_PATH..." $ecli ${CONN}-${FS}-ul $FILE_TO_UPLOAD $TEST_DEVICE:$FILE_PATH [ $? -ne 0 ] && exitWithError 1 if [ -n "$FILE_NEW_NAME" ]; then echo "Testing mv of $FILE_PATH to $FILE_NEW_NAME..." $ecli ${CONN}-${FS}-mv $TEST_DEVICE:$FILE_PATH "$FILE_NEW_NAME" [ $? -ne 0 ] && exitWithError 1 fi if $download; then echo "Testing data changes..." $ecli ${CONN}-${FS}-dl $TEST_DEVICE:$FILE_PATH [ $? -ne 0 ] && exitWithError 1 FILE=$(echo "$srcdir/$DEVICE_NAME $FS"*) [ ! -f "$FILE" ] && exitWithError 1 cksum_act=$(cksum "$FILE" | awk '{print $1}') cksum_exp=$(cksum "$FILE_UPLOADED_BACK" | awk '{print $1}') echo "Actual cksum: $cksum_act" echo "Expected cksum: $cksum_exp" [ $cksum_act != $cksum_exp ] && exitWithError 1 fi exitWithError 0 elektroid-3.2.3/test/integration/microbrute_sequence_fs_tests.sh000077500000000000000000000001541500236517400253220ustar00rootroot00000000000000#!/usr/bin/env bash $srcdir/integration/generic_fs_tests.sh microbrute sequence / 8 "/0 /9" /1 "" exit $? elektroid-3.2.3/test/integration/microfreak_ppreset_fs_tests.sh000077500000000000000000000001711500236517400251420ustar00rootroot00000000000000#!/usr/bin/env bash $srcdir/integration/generic_fs_tests.sh microfreak ppreset / 512 "/0 /513" /512 "New Name" exit $? elektroid-3.2.3/test/integration/microfreak_pwavetable_fs_tests.sh000077500000000000000000000001711500236517400256120ustar00rootroot00000000000000#!/usr/bin/env bash $srcdir/integration/generic_fs_tests.sh microfreak pwavetable / 16 "/0 /17" /16 "New Name" exit $? elektroid-3.2.3/test/integration/microfreak_wavetable_fs_tests.sh000077500000000000000000000001701500236517400254310ustar00rootroot00000000000000#!/usr/bin/env bash $srcdir/integration/generic_fs_tests.sh microfreak wavetable / 16 "/0 /17" /16 "New Name" exit $? elektroid-3.2.3/test/integration/microfreak_zpreset_fs_tests.sh000077500000000000000000000016101500236517400251530ustar00rootroot00000000000000#!/usr/bin/env bash #Zip files include date information, hence generic testing is not possible. echo "Backing up preset..." $ecli microfreak-ppreset-dl $TEST_DEVICE:/512 [ $? -ne 0 ] && exit 1 FILE=$(echo "$srcdir/Arturia MicroFreak ppreset 512"*.mfp) BACKUP=$srcdir/backup.mfp mv "$FILE" $srcdir/backup.mfp $srcdir/integration/generic_fs_tests.sh --no-download microfreak zpreset / 512 "/0 /513" /512 "" [ $? -ne 0 ] && exit 1 echo "Testing download..." $ecli microfreak-zpreset-dl $TEST_DEVICE:/512 [ $? -ne 0 ] && exit 1 FILE=$(echo "$srcdir/Arturia MicroFreak zpreset 512"*.mfpz) [ ! -f "$FILE" ] && exit 1 exp=$(cksum "$srcdir/res/connectors/microfreak_ppreset.data" | awk '{print $1}') act=$(unzip -p "$FILE" "0_preset" | cksum | awk '{print $1}') [ "$exp" != "$act" ] && exit 1 rm "$FILE" echo "Restoring preset..." $ecli microfreak-ppreset-ul $BACKUP $TEST_DEVICE:/512 rm "$BACKUP" exit $? elektroid-3.2.3/test/integration/microfreak_zwavetable_fs_tests.sh000077500000000000000000000016361500236517400256330ustar00rootroot00000000000000#!/usr/bin/env bash #Zip files include date information, hence generic testing is not possible. echo "Backing up wavetable..." $ecli microfreak-pwavetable-dl $TEST_DEVICE:/16 [ $? -ne 0 ] && exit 1 FILE=$(echo "$srcdir/Arturia MicroFreak pwavetable 16"*.mfw) BACKUP=$srcdir/backup.mfw mv "$FILE" $srcdir/backup.mfw $srcdir/integration/generic_fs_tests.sh --no-download microfreak zwavetable / 16 "/0 /17" /16 "" [ $? -ne 0 ] && exit 1 echo "Testing download..." $ecli microfreak-zwavetable-dl $TEST_DEVICE:/16 [ $? -ne 0 ] && exit 1 FILE=$(echo "$srcdir/Arturia MicroFreak zwavetable 16"*.mfwz) [ ! -f "$FILE" ] && exit 1 exp=$(cksum "$srcdir/res/connectors/microfreak_pwavetable.data" | awk '{print $1}') act=$(unzip -p "$FILE" "0_wavetable" | cksum | awk '{print $1}') [ "$exp" != "$act" ] && exit 1 rm "$FILE" echo "Restoring wavetable..." $ecli microfreak-pwavetable-ul $BACKUP $TEST_DEVICE:/16 rm "$BACKUP" exit $? elektroid-3.2.3/test/integration/phatty_preset_fs_tests.sh000077500000000000000000000004731500236517400241560ustar00rootroot00000000000000#!/usr/bin/env bash #ls / [ $($ecli phatty-preset-ls $TEST_DEVICE:/ | wc -l) -ne 2 ] && exit 1 #panel id $ecli phatty-preset-dl $TEST_DEVICE:/256 && exit 1 err=$? rm *.syx [ $err -ne 0 ] && exit $err $srcdir/integration/generic_fs_tests.sh phatty preset /presets 100 /presets/127 /presets/99 "New Name" exit $? elektroid-3.2.3/test/integration/sds_16b1c_fs_tests.sh000077500000000000000000000013461500236517400227500ustar00rootroot00000000000000#!/usr/bin/env bash echo "Using device $TEST_DEVICE..." echo "Testing ls..." files=$($ecli sds-16b1c-ls $TEST_DEVICE:/) [ $? -ne 0 ] && exit 1 echo "$files" | head echo '[...]' [ $(echo "$files" | wc -l) -ne 1000 ] && exit 1 echo "Testing upload..." $ecli sds-16b1c-ul $srcdir/res/connectors/silence.wav $TEST_DEVICE:/1 [ $? -ne 0 ] && exit 1 # If renaming is not implemented, this will fail. echo "Testing mv..." $ecli sds-16b1c-mv $TEST_DEVICE:/1 "Foo" [ $? -ne 1 ] && exit 1 echo "Testing download..." $ecli sds-16b1c-download $TEST_DEVICE:/1 [ $? -ne 0 ] && exit 1 actual_cksum="$(cksum 001.wav | awk '{print $1}')" rm 001.wav [ "$actual_cksum" != "$(cksum $srcdir/res/connectors/silence.wav | awk '{print $1}')" ] && exit 1 exit 0 elektroid-3.2.3/test/integration/summit_multi_fs_tests.sh000077500000000000000000000001631500236517400240070ustar00rootroot00000000000000#!/usr/bin/env bash $srcdir/integration/generic_fs_tests.sh summit multi /D 128 /D/128 /D/127 "New Name" exit $? elektroid-3.2.3/test/integration/summit_single_fs_tests.sh000077500000000000000000000001641500236517400241370ustar00rootroot00000000000000#!/usr/bin/env bash $srcdir/integration/generic_fs_tests.sh summit single /D 128 /D/128 /D/127 "New Name" exit $? elektroid-3.2.3/test/integration/summit_tuning_fs_tests.sh000077500000000000000000000020361500236517400241620ustar00rootroot00000000000000#!/usr/bin/env bash FILE="$srcdir/Novation Summit tuning 16.syx" BACKUP="$FILE.bak" function exitWithError () { echo "Restoring..." $ecli summit-tuning-ul "$BACKUP" $TEST_DEVICE:/16 rm -f "$FILE" "$BACKUP" exit $1 } $srcdir/integration/generic_fs_tests.sh summit tuning / 17 /17 /16 "" err=$? [ $err -ne 0 ] && exit $err echo "Creating backup..." $ecli summit-tuning-dl $TEST_DEVICE:/16 err=$? [ $err -ne 0 ] && exit $err [ ! -f "$FILE" ] && exitWithError 1 mv "$FILE" "$BACKUP" echo "Uploading scala file..." $ecli summit-tuning-ul $srcdir/res/scala/TET.scl $TEST_DEVICE:/16 err=$? [ $err -ne 0 ] && exitWithError $err echo "Testing download scala as tuning..." $ecli summit-tuning-dl $TEST_DEVICE:/16 [ $? -ne 0 ] && exitWithError 1 [ ! -f "$FILE" ] && exitWithError 1 cksum_act=$(cksum "$FILE" | awk '{print $1}') cksum_exp=$(cksum $srcdir/res/connectors/summit_tunning_scale.data.back | awk '{print $1}') echo "Actual cksum: $cksum_act" echo "Expected cksum: $cksum_exp" [ $cksum_act != $cksum_exp ] && exitWithError 1 exitWithError 0 elektroid-3.2.3/test/integration/summit_wavetable_fs_tests.sh000077500000000000000000000001551500236517400246300ustar00rootroot00000000000000#!/usr/bin/env bash $srcdir/integration/generic_fs_tests.sh summit wavetable / 10 /10 /9 "NewName" exit $? elektroid-3.2.3/test/integration/system_all_fs_tests.sh000077500000000000000000000030241500236517400234320ustar00rootroot00000000000000#!/usr/bin/env bash err=0 tmpdir=$(mktemp -d) echo "Runnning tests on $tmpdir..." actf=$tmpdir/square.wav for f in $($ecli info 0 | grep Filesystems | awk '{print $2}' | sed 's/,/ /g'); do expf=$srcdir/res/connectors/square-$f.wav [ ! -f $expf ] && echo "$expf test file not found" && err=1 && continue $ecli system-$f-ul $srcdir/res/connectors/square.wav 0:$tmpdir [ $? -ne 0 ] && err=1 && continue cksum $actf cksum $expf ls -l $tmpdir act=$(cksum $actf | awk '{print $1 " " $2}') exp=$(cksum $expf | awk '{print $1 " " $2}') [ "$act" != "$exp" ] && echo "Unexpected cksum for $f" && err=1 done echo "Runnning test from 1 to 2 channels on $tmpdir..." actf=$tmpdir/square-wav48k16b1c.wav expf=$srcdir/res/connectors/square-wav48k16b2c.wav $ecli system-wav48k16b2c-ul $srcdir/res/connectors/square-wav48k16b1c.wav 0:$tmpdir if [ $? -eq 0 ]; then cksum $actf cksum $expf act=$(cksum $actf | awk '{print $1 " " $2}') exp=$(cksum $expf | awk '{print $1 " " $2}') [ "$act" != "$exp" ] && echo "Unexpected cksum for $f" && err=1 else err=1 fi echo "Runnning test from 2 to 1 channels on $tmpdir..." act=$tmpdir/square-wav48k16b2c.wav exp=$srcdir/res/connectors/square-wav48k16b1c.wav $ecli system-wav48k16b1c-ul $srcdir/res/connectors/square-wav48k16b2c.wav 0:$tmpdir if [ $? -eq 0 ]; then cksum $actf cksum $expf act=$(cksum $actf | awk '{print $1 " " $2}') exp=$(cksum $expf | awk '{print $1 " " $2}') [ "$act" != "$exp" ] && echo "Unexpected cksum for $f" && err=1 else err=1 fi rm -rf $tmpdir exit $err elektroid-3.2.3/test/integration/test.sh000077500000000000000000000004721500236517400203270ustar00rootroot00000000000000#!/usr/bin/env bash [ -z "$TEST_DEVICE" ] && echo "Environment variable TEST_DEVICE not set. Nothing to run." && exit 0 [ -z "$TEST_CONNECTOR_FILESYSTEM" ] && echo "Environment variable TEST_CONNECTOR_FILESYSTEM not set. Nothing to run." && exit 0 ./integration/${TEST_CONNECTOR_FILESYSTEM}_fs_tests.sh exit $? elektroid-3.2.3/test/res/000077500000000000000000000000001500236517400152545ustar00rootroot00000000000000elektroid-3.2.3/test/res/connectors/000077500000000000000000000000001500236517400174315ustar00rootroot00000000000000elektroid-3.2.3/test/res/connectors/PROJECT.dtdata000066400000000000000000000610351500236517400217270ustar00rootroot000000000000000073 7*  PROJECTXi$--., ,m>?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>2/>"=#>?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>!/>"=#>?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>/>"=#>?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>d/>"=#-pG-C2PB  O--)8>~<B b Pg ebP\bP{>?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>/>"=#8@pO_i-., ,-X4i|  -7,.7, -8<5PMY-Zi)-m*-*NbSPT-VWn^i|j y -r^Ni-m  -bqP |o/-8~<i|-m--i-m3-PbhP!., ,, >?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>d/>"=#-pG-C2PB  O--)8A~<B bP^c$bPUbPy-., ,->?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>/>"=#>?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>/>"=#>?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>2/>"=#>?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>/>"=#>?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>d/>"=#-pG-C2PB  O--)8>~<B b Pf ebP]bP|>?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>/>"=#8@pO_i-., ,-X4i|  -7,.7, -8<5PLY-Zi)-m*-*NbSP T-VWn^i|j y -r^Ni-m  -bqP|o/-8~<i|-m--i-m3-PbhP ., ,, >?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>d/>"=#-pG-C2PB  O--)8A~<B bP_c$bPTbPy-., ,->?o@AAt@@N??(C:@'@A'@=<=;@BDDaAAAx<>/>"=#P} d10 ~Z2Z3ZPPKL M~ s@@0 FGHIJKLlqO 21F0@nCQ Y2 ~ ROH8@]Q S Q9S2,1QC=2 *]*+A0kTA VRF T  8d0vBVߠ~PwxyHj:@8f B P>P8AP aڪelektroid-3.2.3/test/res/connectors/SOUND.dtdata000066400000000000000000000003001500236517400214750ustar00rootroot000000000000000073 @SOUNDXI@@) @D(?]dKH!L@/0@n@a@$S,;. :ݓڪelektroid-3.2.3/test/res/connectors/cz_program.data000066400000000000000000000004101500236517400224220ustar00rootroot00000000000000Dp `                  elektroid-3.2.3/test/res/connectors/cz_program.data.back000066400000000000000000000004101500236517400233210ustar00rootroot00000000000000Dp /                  elektroid-3.2.3/test/res/connectors/efactor_preset.data000066400000000000000000000002471500236517400232740ustar00rootroot00000000000000pI[100] 0 3 2 0 0 0 0 0 0 0 0 0 0 0 3ff0 0 0 0 0 0 0 0 0 0 3f20 0 20 0 0 0 0 0 0 0 0 0 2c2a 0 0 0 0 0.125 0 0 0 0.0998 0 0 0 65000 65000 C_a72a Preset elektroid-3.2.3/test/res/connectors/efactor_preset.data.back000066400000000000000000000002511500236517400241660ustar00rootroot00000000000000pI[100] 0 3 2 0 0 0 0 0 0 0 0 0 0 0 3ff0 0 0 0 0 0 0 0 0 0 3f20 0 20 0 0 0 0 0 0 0 0 0 2c2a 0 0 0 0 0.125 0 0 0 0.0998 0 0 0 65000 65000 C_a72a New Name elektroid-3.2.3/test/res/connectors/elektron_project.data000066400000000000000000000767001500236517400236470ustar00rootroot00000000000000PKhY0Ȱ manifest.jsonUA 0sv$:t:pͶM.c|/_c ) "cO6ۦg= 9KDuAzpfvp sZ ^  p߸r49FCNPJ6Dȅx]Y[MJ}{Nd⮛Z[ eFPKhYiJ\pwSamples/auto-test/square.wav UW/{k5HB1$MTPVLPՒBJUa*;;{5P@N*TҦ[+ rh+m8D $[םg=^/s7% m/~v|͕ӦM{S'>iKzقiook J\eϼMyw45[=+sfh @-(R(\R(GefJ7[CCzSp qG ɏeHs{<3,wyZ"^yҮ5h95<|yF~$'}Ri]Ÿ%Z+ͣV-oވ+==:x!87|qϊZ)Wo$ӾNn{p=)n _sUI4֣",qsWB?kä3t=gךWȮl3څhlavKCOwۆw gweK;_v5?%W+x7^'ׂCc _%_ *'܋4\)%%c<珢-ΛUo~.ni=g*(xUw%I~LJځ3w2܊GNOVV&rȷRÕA{VQV\ ]5m=#N_KFɻ2 [e*cٵ6R=0~|`܂wޮw#M;p=odo C~#uCl&ӽbڴ7ȕObY E* ;<4_:Դ/|Ʋ2bF< N• {vܙ\yͣUo'TYy>||b>mY}Qi&oV:tx۴fΓ+ H߸aSWbwϟ;Wr U5p~xw_ˊz Ws 7 ǽJ^I' 'wVw(J$2g|n3ޝ ѓkԘ9ϑ#2_u=^EEQFϟ}}BهZ2VJ+ZCjq/3ILqJ}RuF7{|ŒQH4`>ʽ/U@zݹ2f^5~, o1|||;ߣ4?&%r6"hW=YVy'ΑozΎ)Z9au26/; wMqSACUDד*ǞO[KstfgCROmH:S"iYK_;-y60L#w,B4Jn+M~FZ@G&j 5݋y7uh;YD!wߡm|!J}>>׫૽QУ>-IӍџ,2 0 3Qf[8#D22VO5=^.O@Qgwf,m|l\7$f=I'}o4 &)iΑ~tVEwyxhIRǓ&zOaF#u*7=/PsV$) JV>-h!)鍣&06xY#cVKcW;P/ܷv˫t4QFsp|xW{;Q1.״\Gpmb~UMw*]eRbVHJtbm ox#js+NL1 >4wMyVkmg]J:Ѳpe ޾t*͙STفqz|Ne@ KMϬ3tQkmVufhWW{I߻/}xs whw:>]Y;yMoUm- +aTr:3sžp~c~Pghtmy>cO`^q2_!nlerDYɨLg'_zk dq)no а{W5:Fh=1! tޙXܒD܇ߣ Str<=mufYyemz0)uhvދUS|Մv;nwrg(lh[m St9B%e/sU7$)ml9=Ӛ$W׀~=? bVT܇l)1h9om_W{3z3y.sm}F ΩyM) ߘU>{q=>9rigQrCokwʹHxEySKvo WQ*X:4}3j૆aZJO=JkHKOfr+/L~q蟂p'l#ܰg^$zs|9^%T8R,:'IE̊.z &@68ʽX?::rvɠPz7SvQ[s!Wsȷ QRIe)cvcvT`6q|EW`֩tjm[}-3μ@)t N3acwBwyB: wc_Mzx%AwԩG^뵋A u"4ic.$#YMR%iգlxyiF=~9f_V٘u&-AxD%;yÚ7yr66HTY8/uG:̸b'^ͧ&.+)nvDB!qǹ 7d GGlr!mshZ oywjsUÇp\Q@}~`" bosg t;B G2 }gۊj= x \NAFS_(欵"ۯ/읿yJ6RƷ] Cf5H/pH4=弸.2MBJ:<+WXdZs9nYvIOjs+"Ǐ^g&?c;TD ҕض!Ud4߉>hܯxƹtQf ]\GW,NVM^盵Wϯ.1mxG𮱜󫔱”;)jVοWb6.( kN&srV/GO\9\Gl8ںb~U<5(ov.nj;_oX Wb5YB?.]1w5I*&} OFRKTGJJ<5@fx⪢V^F>}rtf\5E&*GZ>zQ}RȢ_X0T)ObJv|~Tϯ\'sM%j6 ;ZHw A@t3K~WfdLT˂EUt۴ _5g5ƀ0O»C=T6'3+$#Wـy]nl.Ku2z˼B|ޗZ'z\++iBg5qa~SYuݭgC'cJڎF=dۄ f:2W4n `%yT\]Dē}uhtEkx̌GjzO:kawصLvn)Wp/΢iW|d0V{w'al&s _؍EGPJ9{5U:kt_Mޕ{7cE+Sh= YfWv7~/Z~ҙIPvȮUmNjȬ6ds!dž3|'OMg +S+L%_Sǰo`K;Nn;KIl+/&ImGVf#/T~_uK|LE7s>%.^|g0q\ƴkJOogzMo [N>-i<=cRYԞL9&frS~䉅%<#t Ս0+h2s곸)?=7QJ`?/s =ms,fM!wz]RqVo1~v`8q3|TFpWQ|^N^_JSF:=_m=xqs_Wɿɨ>{zՒffb:2ˮCG +Mo]L^RۤLE_̖?;q󼻀TƜ~;1uwI෿slgc_%̗jR{}->s߮s+@4i(/UKnk#/'6 nF:'jˀT~:{^OLB(ZU~;r3k?R9j(QD_] Y.%MEnwwq .RldF}ZO.5v=/Ѫ]'迟|"|n=: *c Lɏ]_CqVr^opg9%ܯ4hWv*F_ Ǹ2 Y0yWsau*2rD+{9_:4y*\xE}}\>\;jiIeR0wu7/[W/j-hMVdɻ]Y7iw jšgL%WP6"z2]N{ 6|^D_ Ŗ-ԙ81hg&|T 4Z"=PRꩺ(*V\#tL#Q`߆܋N5Sʛ58n Egia? u1qJ GV-:5e/g+]R*FvbgxH "T?xOגuƶ>ha@2}Z?o|U^Ch0BnȬ.lu2TsF5Uf\ݣyxHaNO6%+:t3W1 lN_Dl9M%MMV+Wg1iC9G0qdȕpr+{2JG4Io,c _ KN8L$+C1[N0z_ty˙hpYjgꡑrtb1ʻXO~Q؛Z4y2'/34QZGwVb8I+<:_2o!`MLTVW'̿7~oZgo*cGț*~14#j%\N~Ԓ1a @&&̿DHYTv*[OE2n@\|sAX 3{KJ…=%w; LpoI|Rpnη_T_c|̔qI~_`~JH|.4_ ϴ$YV\2jj@MMy\~BE`^EޅFg*= l;}n-ʡb-ApO|#Lyy5Sz#ZSd8kFҶ>KE _6OHچ[$܇Ft?Y+g%us0%򯶉ʕ$y.?58 YV4δ8=qhaW̟]bõݒʴP1 cEW!zph.J,_/WC:s'`U/VmnҮ1j,w%nle~ˆ{ʒGO]x-s9O$*&ifB|v̿_Q݊sj`Gբ )6 SZZJON 4m33,yYٮQaΚZ+qFRl%-K\+|PZ;!ESbnK2= uܫ*wkV5IWj %7m>5جxOi2|Io VϊȕWYKZv5IZ9C:~T.-ɨdd*X`UH+~W4I~YF:bs :[/fbl'\Brl?hKkL50)ku>N%3Pv?M߮{b1gK[]  WMΥ5qAiD3_I{ͼ(;z)848*wN6MM*xCaQvkȥ#Kx'{5C hxvM4(ؔgziӚFJ[< ջ4z29Mg-zW4;o]FmVjYMogܟLL'T.&GL[iۘp?HEqhUx^UbL:Ij;Qd`JSl vsR1Ys|oƯI %a?j2ub`_ r^HNd\nje;SW!g9Z#ބ|.ߺ-O0'>i]:ʣ·^()[NYn.uJ%d)ư}%>|/oxeELi87'o%_=^~cɗ㩯:dgM#uϲxqPA&V3V5:Q?qo?S' =uVM1Xeawܥn|NSN;yeIk~3^{Pz+:zmzW O_/I(HYr<ⲟß':E?X@ 72kYQwDF/bj@\?8aI99 j"JRtoHH[}SYra{o3$ /䶣;V9isѻqo/u7UOJ s:條;wf'uQR,n 7,5}/{A/zt%7{d\:k\ VpfY)ckZ\ٓVޜVH+N~ Jo *{BC";-s9!򯨿 hIM*Fz T.{D<%d81%dc^yR𯘿(c޽Y#V3N=]_QoF4^`IK3}{zf;||ccdIO7̉)j_}th]K 0bbܿ9_xzXiJ]}z[VBճ¿.OٲC<<V|qjmznkY4i豇lpdpY0Nd3%c2#8S zT3S:2WTh>֟pDljudm|g/~X|yRqpD;yɊָL*Ϋl\ {ve7.xRSb vݡVW-N -ēzyWp̯ʚ];g m$oUx W߬׹ =̫w9K]U ]hύ>xmb |}|4UP=%g`__ߌgr'ÕK*Off%0|5!Kw)ZN*STB]%DE>Eu$iqeK[7WhulYuYyI+ctW1|W*m)z2ʝjx#?hIn^y-Y8e!Kn%l5 ^T|5bHZZ|2?w~ί ~{Iq}| EM"=~T|5Uڪ+O[e:ً7хLic[0?CXAzIGq &UiK~5T?| <_IE^RgDqJIs}!ӊOJ ڊ\~wE̟A>KKYL~58I*kNT]+MCo_(#qn>bj<v|9-H%5,&T_K9}?xR]!_Q*TīBzWm& bqJ\f;KaެIw*`:5َZ= =E^,ŕ^6je'QW_Me6 }䰇3A wY[lrQBIOβ|lLճ#Ջx 3UrSJof̪.C]s ;(巟7mAqbO~N=W_?UmuCUYvT~t`XDEFҫQnrU )_+ϨA5q9!!Ry  %'}o:2.(X_|?{WBT#KK <+`]5*gPyz<.3WwÌf\,P<#Aʨin$~zS l$s9mY8̼![VvÕt?x@B`s=ؙ Awh9L)vf&'$Vu9JrV2mE)'NE+%gڵ7ϫ"M !J M P+c>9C5Wu?9-izx@gL&8W*l? O쩔1x6WS _݂|%WzsSfs {ίĮ=E_ v6wU'3.(zx*?z?wvBj4#{ԔŜ]3a.]]u '%ek3)2-AE巯n!Io^~TmmbMgU䅻KӭJMZƖ!$n@נ? "wEMư'S1I~zVKEh&Ȝ\Z44zIo&pa&I'k~Z_RWL[)o?l=i+N("}fru2.&3GG|V3G!FvZ?vx)X|_`ȓ_u@⽭[N1|QDkn:VF(CE/_WʜE ;48 ۆ O>u,xy"Qx^!<A;3n,G+)ai io|0hu^ڧN Jptj%ފ3/b]Fwj;糂DE?ldjV߂89;_}?1Tvk_7+Gr&kaIhvͤplwÊom?W+p28kթARqy7 8+Cɦ~+NzvxMW;Nx&Gq²'E`K@0c;<9+jݷk)u{Fi?x7W9iIil\K9?-Ԏ>iS]>uEͿ g="'U$* u'0+ݟeS1m&U]w˼/IYvUU4&%I!QnZ'2l [Ufik3U"t)&̟|A~k;3 ވ &zreҥѐ8ɟBoT1u~ rm2s\c.+u~3N\ceKSlt;n@! _vDpV{F"I\@w;q: *N[% .Q`g! ҵ\~12{v_;(pVKNMa8\MK,Կ}-xjduSa\i|g߾"u9a;Uv͖ȟa_4̙J5u,j4Y9qU*n̴c-'ue/SF[S|bajrЁ$Luf L{̫ςNP .WŤ?l43ʍe$emkGԿ=s_+HZ;WO'Ao+ADE4ĩ*\]|hrWrVS/|?(6C}wi40y| DjIl7Li-Dg8?A:=DS}tWt=+ϻe>6u]ZK 9Akoij%h( d&G|%4]gꬤC O*)tv \t<_1 XǑI㌓]F[$*,E=A>6kpN,J-iE#ǔoN>ooVN+Ǵ\Mꗊ]Ks\PytE>NEW\Y]TU%y+(U=Wia.Qo~R_mYYEiE)@/U~aN>)[;ŘNLҹBFP?yXފɃH+eI͛\D' 'oyn?ui؉wI C@CP1SԤ1ۗtӰ^lx>k}-U`qD4o? ~˕W&Z᪖NՌMMr ZM^>ёաYPW|T%2e:HT`soAɪ2P]=VXeD 6+KݖOJQm7%DMB"bSiwN,a9m8detF=u:ʛ7B?Sf%Kb|QvZ8!K8-KgcYtIߪUeeC4i뒤آC?ۃwegGDnG.1n\;3qջp] WNH"S s'm K*xQut +tBSeibtfDW?@l吕3PO4_NH7g7U8}SkWrI%' !RF/X޳п};OJ*,X!Y9CWO>W9=oV oʂF rf_(ұl=")% ) _>x ^K,k21E>ѿJ6P˞Pn ]gz"i,eNHΩ3|g{<7a~pɫ=)j[uR$:?l>zi"BBR{SfyT%K_O%IgHYˤ]1 p8l?WdRL=ߏϟ ]):NZrҚ:Y3rrD+jJ36}M7U5=VT7S*ϵw!uHpַx\:C}jTL BR46ܳRp?_[=\ǷՔҢ\| Фh`\Y$a~udp28pJ{&k?Ooǐsެ-緷*~-){nѕè:@ ۅu.ndq>2tOUv_m2 \8;ȕQ~fE)O'wBTH'_K*s'hHIqלyۙKGn&*w gkkU??6 OxgI})i gig_Էqo.&\\UICK5p;+)W7,p"i~eE75jbƪ g=_u(mQRqw?&Bey3Q} L>;Мނ\?8#v28rl8\tc}>7 {ŸqOve9e\LIc__ }VMm,>EP ~B^#u6ۧ_}mtwU+tpp,^b^[φ]LȚV %,tk(˦KUk+e%Z#E*k)2 8}SN(CVꮺ:Kβ^ :kNS8>Wpyg/Rd$J Wԟ!?yeSZe (ǨCsl=8mW-kyOT˴oH;4۷;,*Gw;$4 䘎?i[itn[z#9~[o 9=sw`YRvؿΧNmkON̴h?H}o?03pk 4Ө_ڮ٫q9xpې;y|czBi}2%['V{ښ1-~0s_m,i.Emf26eؒvAr5eݾHef|9UѯfR掲j2eq`'e!|#xJ1>SQOE6>_'][ENW+|~5 vμTs%MoE+ FO+%"w&6cӭΩ h\7RK%uLxabI NqvUGv%Ӣ5A1Uob+W񿲻_.Y޲E5lPɟSf-D9ƿ-|>LSzJK}F y(jG & jGخ/ܼȷ&9՞l8,YQbbEqWt>HϜ;hk=9<9Z#¿#o7 `#'FnZS}©@OsCgrxY/gS0ٷvSc5:Ԡ/u&HY9lSF- _=W%!ԳPwᜥAϰ=);ڔu'Fi)IEm)6O!@8RWvfuJ0:8qzrmr,?qHiAS aׄӖ&;$uJiECG'A?6'OkIt-SӴEKi)qutAjWo w2rKGI\4ь^43u_4zr1c_jxϨ啋.\))ʒOAuuJ2W3 7_3Q)w*f'6cΖG!~L޳="m<>sj*Ws/4y 9bѡթ{T3M?!87{W,!WzLT={NMWD.OzXۙno?K5exN&bnԿw],J^ۡ"RZ[ru`˹[kMj#0~wCQ}re"oM5cſ|EQH:fsFV<i'X͆ĂS ̃|N-hphK"|k=IEg~F 4ڗE!Y_zA_fu VI{"~&muTq,K.Mh7B Lu|Sf6gT;;x gHO_* M5k [a4tTS~4muT 뾌سj \=_"i?HN<Ֆ 'ҵ萳zW/rNMefwWC,XEԬ4 t?K˹<k9ݷV>{W0t?|$TEz|6 +PW{fOuu~ Tis?C,\ 9 @NݠRM˂5UȝPvsrߪǹ=̻ϜRM(~Md>_ j 9ǞbiPՏ@mk3SCu~݉>Eլ |,[Qo_>2kJN[BUm_wI6f^L8[ܯ!fWIeQX/2s=oII[8ZCnS#!YYǗ7}`Շk9hۆМ</'j3VhoJ?U5Ob7%8x_}JzٶYmҶBx)STޥB?XBQ_c&yo{fUQSί~p9A٬2mW>QaSEЍm!*)߹CJtS9 &|}6V},mt-uSO5"s>v#w"sTm:sNE &IԿGIKJ*Nۓ6ly5W3sΎV?edehnnv8F8ICW:U#9|E^ĵVVҢFPMH>kV2S1m9G4Uy'"ϲ5mz>hj% ?Cˮ$c y%lDϡ8&j3) 98hX,hj@JwT)mʙgSg/,e܉sRSڳD4Hs|E?1g)09]~{W"굦U2(kN62co[y7}k&$GN;e~s&r2D M[HF_-|]_9 4KXuV1 d'xvi=snlD I_O>AԼQ9vM7AyqU̟540;šߞTłQ+[M@(rw`?xb&}_qsc0uag!,=Ӡ̃~g6yf%#)[jק!y>L$Wsaʷi1\[dnuƥ9ܿ=,=[֜ƮRSx_ 4J-9a@ʂ'J>B^(#א{57/{E3th~&K%Ĕ x (Կ*_mnDZBʒ~3IU/GZ  K>yF+]GU=<}PBw vW{rN0?nE+_ڟ$Du+_kq?;cM3 n*3uu h?EeT+7Mu"#} A]_\Y:%$Hθnlo)tZTSgwrF}v+ZъZ.@l69o:8 XR3Gj&t [jCn:9vJCuܣ*!esEGF/~3y%&*,tO-pN.(݋}Z ʌl _.q JwRq>IIn/JJ;q&g(Ywy`xvȑ;S䑅y䌞,+59COC0Jh=jt.U.>0ckE8.|.82*gAgɚT8Zrv;fw _Q%E eg`o_G֜-xa9%DW٤j$B@އ~Hմi|#䘳d[\r'y׮/3_`d`/5[7exdž[8s6:\1VS8)YT.>WtDɓcc) mFW_3z/Q,ʦ+[ ubS8|pf͞&kq2g[,aE7I[RLN20ߪ£WF) ~Z _ki%(b:+\]w˼k&ΐ_gwRI?ú/s|(LZ%.K]#=sqIwQ.< yp |-*.U\V JuǙ2ZiJ)]={ܿ=w*p.D#YP2rb .6<&UJv.Ԧð{F1OT vpS0 .Q泠KڜQ"W|w_wLŽ/VNeuV Q?HKsڮSEN&͚ L?E~f^VAV& w{qgj1)X\\tU{sNb:~6^8Q[N13\*=ϰh4_v}aOﳫwܙ W̿}=L rO7ͤ´!9 #ʳ9^w-̕U6L{rL\_E' @?%]6RT` 4'ރ_|ۙ{'o!duDx=k1)]_RmΏ܀/d\ՃΞ>xRx+!R-(!ō}2tw۟9=:l)*jBvU3a>N̯$3м"ht@ɑ3i ?Gz05PWwLgПR;2|EW_ o\p'Ǭyj1_][C>69Y^D*)|^ȇޏ5~;3T&#E˖Mu@ dܫ~;)66y?))dQ Ư" 0/[J~ Weα< TN%C|Ylӷ)z *,j&]*̯X8=,e0ƲZn1s"j@ϣ]ϰ9ÙK{WR"xQ`eEeiӶSJAUSZg4Ii^-2&ŴFzYIۅb<”E21.v7ICov#3dt&AQOGzRO6)d%c4jR>α/ =<+uto~<^O-|$'uU6S.qy3${CJj}ԎahzٞU|EJFͯvUrUec)o~r _oԔ2rѫѿ;sZ̯蕥8 Q{碱kJew>>D 31{ZעL[PdFyۢF6+ቴc371(z9v;yՔN>.MWꎾiE%~;F̕)[n_PdJMȕ%D>Y6})d_S%`:̯zL&oHHe&2`7gc4q'5gEu_u.qog+_J}U]Wy6Ww!V& I?i,8unɩ %m~E9ͤ2/s+W^5} +b=I0Wsq3{S5mL䲧ȅu#_3++iDoρP]#ѯ&&Ц,{(=aV@a8Tvݧm.ͮ,= 8#j*kYq˥i^,r'O,ZNf-^RքVS1a_/TvQ9f_ε6wN_IWJ"eaN޷(0=jbg`)%{!x.E΂)ÝL;ׁUf `!yIG663]P8 T$̯Z~&xԯ}1֋YY&ҙ!eS Aʿ#I s*֓SeH$`0ϲИĥ$eO;9Yu #M~j[q53}*CSԠ5d#>!߹YvYif*>\-]ߴAWߪqF.,Џ0y"W3f;7/$X8bUZ-ԇ@W|uZr,?+fW+M۫[LPmu+B4{y9 {_tv-]Re.WFCb?#ͯ]eZ6cխ9$y$j'ÏB&Z@쥘٪_T| KG3^Y+ ľz 9}]~p'Z)dWXV>x|禠+ٟU8,sNNvQ >)f8\KctevaZ=-4\I<WK{3څϜٜZL=οڇ>SZŞk75xLWGq^1+7[]YaSч+U_s|޵2tN(M:.NA<૵_0D5SFJB˜~S|g\-T_XfWV{u%kj bM}~UwWq6Vn@ymfm*5*op$ӝ;qvL 89/FR>I_]1-9wc+h R>I5a?㫥ي~ેIݗSd$t-i&8)1߈V9jKAZƖyjA> s`f W k=?4WbPKhY;X UUPROJECT p߷0X*(6`prlqP\ ! m24ip0LGN=%Іe:Ѓ LH&S I4C&D}ll?O]w{'^%P2t#CŇFRXnxv%ƏEcqGǂ6YK0-VV~c|1>o 9߆L[X|!.[b<, 2 %jy-b嗫58CQ3kd߻|4ڇ5nuZj+G:̭;X2׵^HvfCQ,"|fC«(`@=+{e/x?t6S-Lۛ*/Prƫ]ˋ\8!MmАJ^MkLre}7CZn!z$`|X`#|9u|56Bj`CV)jkڡ8~yGO/jMET5rLfLc&fg6Bκrdn"u;-nL.N,2:3&10U&4# ZݶHX51Yv" LPSݶNP]=5%_@^jB_5QirF:Ԟ__cm>jƟzqIڕmE>[}:P#=ɧū@f:(i^EZ]%x{_VjɄ !_xTm3/sSf'sHk) bu//~dIk3cZLrc6PyۮTŎX~D\Z$ܹ1%!FA5:,1&|P[oW8b%5~Z+j/?tŝ wYX.7ꗼk-E]Iqz[v2DFT_s3pD d׶O Q5 2/"#H&?];ZAXf|Ey whazL1qrw9y獄ݩMhLB;wg;yMޡв1whNknt||;Cwfzd B;׿ޯ <'Q5^w:Ot%44xĿ eDoљ#YOyp3x{Q# b9BЕs׶C?qGa%4MKMWGg ϿI39%>#meWOUfd3r)_QRG9~Ra$xz)ig,c#,1XKt N1Iz#gJOp{6$HfHI0ATLK89蔜b舓95a^`cTPel8BZɅP Ϻtk[In"bIܼ#54埸OIoy(&+RHNcnYjEL$SR325@/Sp֍X+ՀFJEa-Q š 59Fυ(BiE" woH$!Mǝ8lHxm53){;4DDbN"R!a[梬$"rD%41 =RjЧ{H(z%d McfToepQonrn_\`sYtt3N-buSk-:e18:<[oNLeRJkgn?3i0DȦJʻ 5i;f+{[ci|90x:NjGb[{)F^}fT6h{PK?hY0Ȱ manifest.jsonPK?hYiJ\pwSamples/auto-test/square.wavPK?hY;X UUsqPROJECTPK|elektroid-3.2.3/test/res/connectors/elektron_sound.data000066400000000000000000000714501500236517400233260ustar00rootroot00000000000000PKVhY+#M manifest.jsonU[ 0jV]`Q fDJPWLJV7c{+-F3R{xL3dmvR֖(?y#8HMhL(D7u`8!u agQFqWD";S%f+ NKa9H?tCzKOӊc ĺ .SC4te4p~́_ 7r H~êPKVhYiJ\pwSamples/auto-test/square.wav UW/{k5HB1$MTPVLPՒBJUa*;;{5P@N*TҦ[+ rh+m8D $[םg=^/s7% m/~v|͕ӦM{S'>iKzقiook J\eϼMyw45[=+sfh @-(R(\R(GefJ7[CCzSp qG ɏeHs{<3,wyZ"^yҮ5h95<|yF~$'}Ri]Ÿ%Z+ͣV-oވ+==:x!87|qϊZ)Wo$ӾNn{p=)n _sUI4֣",qsWB?kä3t=gךWȮl3څhlavKCOwۆw gweK;_v5?%W+x7^'ׂCc _%_ *'܋4\)%%c<珢-ΛUo~.ni=g*(xUw%I~LJځ3w2܊GNOVV&rȷRÕA{VQV\ ]5m=#N_KFɻ2 [e*cٵ6R=0~|`܂wޮw#M;p=odo C~#uCl&ӽbڴ7ȕObY E* ;<4_:Դ/|Ʋ2bF< N• {vܙ\yͣUo'TYy>||b>mY}Qi&oV:tx۴fΓ+ H߸aSWbwϟ;Wr U5p~xw_ˊz Ws 7 ǽJ^I' 'wVw(J$2g|n3ޝ ѓkԘ9ϑ#2_u=^EEQFϟ}}BهZ2VJ+ZCjq/3ILqJ}RuF7{|ŒQH4`>ʽ/U@zݹ2f^5~, o1|||;ߣ4?&%r6"hW=YVy'ΑozΎ)Z9au26/; wMqSACUDד*ǞO[KstfgCROmH:S"iYK_;-y60L#w,B4Jn+M~FZ@G&j 5݋y7uh;YD!wߡm|!J}>>׫૽QУ>-IӍџ,2 0 3Qf[8#D22VO5=^.O@Qgwf,m|l\7$f=I'}o4 &)iΑ~tVEwyxhIRǓ&zOaF#u*7=/PsV$) JV>-h!)鍣&06xY#cVKcW;P/ܷv˫t4QFsp|xW{;Q1.״\Gpmb~UMw*]eRbVHJtbm ox#js+NL1 >4wMyVkmg]J:Ѳpe ޾t*͙STفqz|Ne@ KMϬ3tQkmVufhWW{I߻/}xs whw:>]Y;yMoUm- +aTr:3sžp~c~Pghtmy>cO`^q2_!nlerDYɨLg'_zk dq)no а{W5:Fh=1! tޙXܒD܇ߣ Str<=mufYyemz0)uhvދUS|Մv;nwrg(lh[m St9B%e/sU7$)ml9=Ӛ$W׀~=? bVT܇l)1h9om_W{3z3y.sm}F ΩyM) ߘU>{q=>9rigQrCokwʹHxEySKvo WQ*X:4}3j૆aZJO=JkHKOfr+/L~q蟂p'l#ܰg^$zs|9^%T8R,:'IE̊.z &@68ʽX?::rvɠPz7SvQ[s!Wsȷ QRIe)cvcvT`6q|EW`֩tjm[}-3μ@)t N3acwBwyB: wc_Mzx%AwԩG^뵋A u"4ic.$#YMR%iգlxyiF=~9f_V٘u&-AxD%;yÚ7yr66HTY8/uG:̸b'^ͧ&.+)nvDB!qǹ 7d GGlr!mshZ oywjsUÇp\Q@}~`" bosg t;B G2 }gۊj= x \NAFS_(欵"ۯ/읿yJ6RƷ] Cf5H/pH4=弸.2MBJ:<+WXdZs9nYvIOjs+"Ǐ^g&?c;TD ҕض!Ud4߉>hܯxƹtQf ]\GW,NVM^盵Wϯ.1mxG𮱜󫔱”;)jVοWb6.( kN&srV/GO\9\Gl8ںb~U<5(ov.nj;_oX Wb5YB?.]1w5I*&} OFRKTGJJ<5@fx⪢V^F>}rtf\5E&*GZ>zQ}RȢ_X0T)ObJv|~Tϯ\'sM%j6 ;ZHw A@t3K~WfdLT˂EUt۴ _5g5ƀ0O»C=T6'3+$#Wـy]nl.Ku2z˼B|ޗZ'z\++iBg5qa~SYuݭgC'cJڎF=dۄ f:2W4n `%yT\]Dē}uhtEkx̌GjzO:kawصLvn)Wp/΢iW|d0V{w'al&s _؍EGPJ9{5U:kt_Mޕ{7cE+Sh= YfWv7~/Z~ҙIPvȮUmNjȬ6ds!dž3|'OMg +S+L%_Sǰo`K;Nn;KIl+/&ImGVf#/T~_uK|LE7s>%.^|g0q\ƴkJOogzMo [N>-i<=cRYԞL9&frS~䉅%<#t Ս0+h2s곸)?=7QJ`?/s =ms,fM!wz]RqVo1~v`8q3|TFpWQ|^N^_JSF:=_m=xqs_Wɿɨ>{zՒffb:2ˮCG +Mo]L^RۤLE_̖?;q󼻀TƜ~;1uwI෿slgc_%̗jR{}->s߮s+@4i(/UKnk#/'6 nF:'jˀT~:{^OLB(ZU~;r3k?R9j(QD_] Y.%MEnwwq .RldF}ZO.5v=/Ѫ]'迟|"|n=: *c Lɏ]_CqVr^opg9%ܯ4hWv*F_ Ǹ2 Y0yWsau*2rD+{9_:4y*\xE}}\>\;jiIeR0wu7/[W/j-hMVdɻ]Y7iw jšgL%WP6"z2]N{ 6|^D_ Ŗ-ԙ81hg&|T 4Z"=PRꩺ(*V\#tL#Q`߆܋N5Sʛ58n Egia? u1qJ GV-:5e/g+]R*FvbgxH "T?xOגuƶ>ha@2}Z?o|U^Ch0BnȬ.lu2TsF5Uf\ݣyxHaNO6%+:t3W1 lN_Dl9M%MMV+Wg1iC9G0qdȕpr+{2JG4Io,c _ KN8L$+C1[N0z_ty˙hpYjgꡑrtb1ʻXO~Q؛Z4y2'/34QZGwVb8I+<:_2o!`MLTVW'̿7~oZgo*cGț*~14#j%\N~Ԓ1a @&&̿DHYTv*[OE2n@\|sAX 3{KJ…=%w; LpoI|Rpnη_T_c|̔qI~_`~JH|.4_ ϴ$YV\2jj@MMy\~BE`^EޅFg*= l;}n-ʡb-ApO|#Lyy5Sz#ZSd8kFҶ>KE _6OHچ[$܇Ft?Y+g%us0%򯶉ʕ$y.?58 YV4δ8=qhaW̟]bõݒʴP1 cEW!zph.J,_/WC:s'`U/VmnҮ1j,w%nle~ˆ{ʒGO]x-s9O$*&ifB|v̿_Q݊sj`Gբ )6 SZZJON 4m33,yYٮQaΚZ+qFRl%-K\+|PZ;!ESbnK2= uܫ*wkV5IWj %7m>5جxOi2|Io VϊȕWYKZv5IZ9C:~T.-ɨdd*X`UH+~W4I~YF:bs :[/fbl'\Brl?hKkL50)ku>N%3Pv?M߮{b1gK[]  WMΥ5qAiD3_I{ͼ(;z)848*wN6MM*xCaQvkȥ#Kx'{5C hxvM4(ؔgziӚFJ[< ջ4z29Mg-zW4;o]FmVjYMogܟLL'T.&GL[iۘp?HEqhUx^UbL:Ij;Qd`JSl vsR1Ys|oƯI %a?j2ub`_ r^HNd\nje;SW!g9Z#ބ|.ߺ-O0'>i]:ʣ·^()[NYn.uJ%d)ư}%>|/oxeELi87'o%_=^~cɗ㩯:dgM#uϲxqPA&V3V5:Q?qo?S' =uVM1Xeawܥn|NSN;yeIk~3^{Pz+:zmzW O_/I(HYr<ⲟß':E?X@ 72kYQwDF/bj@\?8aI99 j"JRtoHH[}SYra{o3$ /䶣;V9isѻqo/u7UOJ s:條;wf'uQR,n 7,5}/{A/zt%7{d\:k\ VpfY)ckZ\ٓVޜVH+N~ Jo *{BC";-s9!򯨿 hIM*Fz T.{D<%d81%dc^yR𯘿(c޽Y#V3N=]_QoF4^`IK3}{zf;||ccdIO7̉)j_}th]K 0bbܿ9_xzXiJ]}z[VBճ¿.OٲC<<V|qjmznkY4i豇lpdpY0Nd3%c2#8S zT3S:2WTh>֟pDljudm|g/~X|yRqpD;yɊָL*Ϋl\ {ve7.xRSb vݡVW-N -ēzyWp̯ʚ];g m$oUx W߬׹ =̫w9K]U ]hύ>xmb |}|4UP=%g`__ߌgr'ÕK*Off%0|5!Kw)ZN*STB]%DE>Eu$iqeK[7WhulYuYyI+ctW1|W*m)z2ʝjx#?hIn^y-Y8e!Kn%l5 ^T|5bHZZ|2?w~ί ~{Iq}| EM"=~T|5Uڪ+O[e:ً7хLic[0?CXAzIGq &UiK~5T?| <_IE^RgDqJIs}!ӊOJ ڊ\~wE̟A>KKYL~58I*kNT]+MCo_(#qn>bj<v|9-H%5,&T_K9}?xR]!_Q*TīBzWm& bqJ\f;KaެIw*`:5َZ= =E^,ŕ^6je'QW_Me6 }䰇3A wY[lrQBIOβ|lLճ#Ջx 3UrSJof̪.C]s ;(巟7mAqbO~N=W_?UmuCUYvT~t`XDEFҫQnrU )_+ϨA5q9!!Ry  %'}o:2.(X_|?{WBT#KK <+`]5*gPyz<.3WwÌf\,P<#Aʨin$~zS l$s9mY8̼![VvÕt?x@B`s=ؙ Awh9L)vf&'$Vu9JrV2mE)'NE+%gڵ7ϫ"M !J M P+c>9C5Wu?9-izx@gL&8W*l? O쩔1x6WS _݂|%WzsSfs {ίĮ=E_ v6wU'3.(zx*?z?wvBj4#{ԔŜ]3a.]]u '%ek3)2-AE巯n!Io^~TmmbMgU䅻KӭJMZƖ!$n@נ? "wEMư'S1I~zVKEh&Ȝ\Z44zIo&pa&I'k~Z_RWL[)o?l=i+N("}fru2.&3GG|V3G!FvZ?vx)X|_`ȓ_u@⽭[N1|QDkn:VF(CE/_WʜE ;48 ۆ O>u,xy"Qx^!<A;3n,G+)ai io|0hu^ڧN Jptj%ފ3/b]Fwj;糂DE?ldjV߂89;_}?1Tvk_7+Gr&kaIhvͤplwÊom?W+p28kթARqy7 8+Cɦ~+NzvxMW;Nx&Gq²'E`K@0c;<9+jݷk)u{Fi?x7W9iIil\K9?-Ԏ>iS]>uEͿ g="'U$* u'0+ݟeS1m&U]w˼/IYvUU4&%I!QnZ'2l [Ufik3U"t)&̟|A~k;3 ވ &zreҥѐ8ɟBoT1u~ rm2s\c.+u~3N\ceKSlt;n@! _vDpV{F"I\@w;q: *N[% .Q`g! ҵ\~12{v_;(pVKNMa8\MK,Կ}-xjduSa\i|g߾"u9a;Uv͖ȟa_4̙J5u,j4Y9qU*n̴c-'ue/SF[S|bajrЁ$Luf L{̫ςNP .WŤ?l43ʍe$emkGԿ=s_+HZ;WO'Ao+ADE4ĩ*\]|hrWrVS/|?(6C}wi40y| DjIl7Li-Dg8?A:=DS}tWt=+ϻe>6u]ZK 9Akoij%h( d&G|%4]gꬤC O*)tv \t<_1 XǑI㌓]F[$*,E=A>6kpN,J-iE#ǔoN>ooVN+Ǵ\Mꗊ]Ks\PytE>NEW\Y]TU%y+(U=Wia.Qo~R_mYYEiE)@/U~aN>)[;ŘNLҹBFP?yXފɃH+eI͛\D' 'oyn?ui؉wI C@CP1SԤ1ۗtӰ^lx>k}-U`qD4o? ~˕W&Z᪖NՌMMr ZM^>ёաYPW|T%2e:HT`soAɪ2P]=VXeD 6+KݖOJQm7%DMB"bSiwN,a9m8detF=u:ʛ7B?Sf%Kb|QvZ8!K8-KgcYtIߪUeeC4i뒤آC?ۃwegGDnG.1n\;3qջp] WNH"S s'm K*xQut +tBSeibtfDW?@l吕3PO4_NH7g7U8}SkWrI%' !RF/X޳п};OJ*,X!Y9CWO>W9=oV oʂF rf_(ұl=")% ) _>x ^K,k21E>ѿJ6P˞Pn ]gz"i,eNHΩ3|g{<7a~pɫ=)j[uR$:?l>zi"BBR{SfyT%K_O%IgHYˤ]1 p8l?WdRL=ߏϟ ]):NZrҚ:Y3rrD+jJ36}M7U5=VT7S*ϵw!uHpַx\:C}jTL BR46ܳRp?_[=\ǷՔҢ\| Фh`\Y$a~udp28pJ{&k?Ooǐsެ-緷*~-){nѕè:@ ۅu.ndq>2tOUv_m2 \8;ȕQ~fE)O'wBTH'_K*s'hHIqלyۙKGn&*w gkkU??6 OxgI})i gig_Էqo.&\\UICK5p;+)W7,p"i~eE75jbƪ g=_u(mQRqw?&Bey3Q} L>;Мނ\?8#v28rl8\tc}>7 {ŸqOve9e\LIc__ }VMm,>EP ~B^#u6ۧ_}mtwU+tpp,^b^[φ]LȚV %,tk(˦KUk+e%Z#E*k)2 8}SN(CVꮺ:Kβ^ :kNS8>Wpyg/Rd$J Wԟ!?yeSZe (ǨCsl=8mW-kyOT˴oH;4۷;,*Gw;$4 䘎?i[itn[z#9~[o 9=sw`YRvؿΧNmkON̴h?H}o?03pk 4Ө_ڮ٫q9xpې;y|czBi}2%['V{ښ1-~0s_m,i.Emf26eؒvAr5eݾHef|9UѯfR掲j2eq`'e!|#xJ1>SQOE6>_'][ENW+|~5 vμTs%MoE+ FO+%"w&6cӭΩ h\7RK%uLxabI NqvUGv%Ӣ5A1Uob+W񿲻_.Y޲E5lPɟSf-D9ƿ-|>LSzJK}F y(jG & jGخ/ܼȷ&9՞l8,YQbbEqWt>HϜ;hk=9<9Z#¿#o7 `#'FnZS}©@OsCgrxY/gS0ٷvSc5:Ԡ/u&HY9lSF- _=W%!ԳPwᜥAϰ=);ڔu'Fi)IEm)6O!@8RWvfuJ0:8qzrmr,?qHiAS aׄӖ&;$uJiECG'A?6'OkIt-SӴEKi)qutAjWo w2rKGI\4ь^43u_4zr1c_jxϨ啋.\))ʒOAuuJ2W3 7_3Q)w*f'6cΖG!~L޳="m<>sj*Ws/4y 9bѡթ{T3M?!87{W,!WzLT={NMWD.OzXۙno?K5exN&bnԿw],J^ۡ"RZ[ru`˹[kMj#0~wCQ}re"oM5cſ|EQH:fsFV<i'X͆ĂS ̃|N-hphK"|k=IEg~F 4ڗE!Y_zA_fu VI{"~&muTq,K.Mh7B Lu|Sf6gT;;x gHO_* M5k [a4tTS~4muT 뾌سj \=_"i?HN<Ֆ 'ҵ萳zW/rNMefwWC,XEԬ4 t?K˹<k9ݷV>{W0t?|$TEz|6 +PW{fOuu~ Tis?C,\ 9 @NݠRM˂5UȝPvsrߪǹ=̻ϜRM(~Md>_ j 9ǞbiPՏ@mk3SCu~݉>Eլ |,[Qo_>2kJN[BUm_wI6f^L8[ܯ!fWIeQX/2s=oII[8ZCnS#!YYǗ7}`Շk9hۆМ</'j3VhoJ?U5Ob7%8x_}JzٶYmҶBx)STޥB?XBQ_c&yo{fUQSί~p9A٬2mW>QaSEЍm!*)߹CJtS9 &|}6V},mt-uSO5"s>v#w"sTm:sNE &IԿGIKJ*Nۓ6ly5W3sΎV?edehnnv8F8ICW:U#9|E^ĵVVҢFPMH>kV2S1m9G4Uy'"ϲ5mz>hj% ?Cˮ$c y%lDϡ8&j3) 98hX,hj@JwT)mʙgSg/,e܉sRSڳD4Hs|E?1g)09]~{W"굦U2(kN62co[y7}k&$GN;e~s&r2D M[HF_-|]_9 4KXuV1 d'xvi=snlD I_O>AԼQ9vM7AyqU̟540;šߞTłQ+[M@(rw`?xb&}_qsc0uag!,=Ӡ̃~g6yf%#)[jק!y>L$Wsaʷi1\[dnuƥ9ܿ=,=[֜ƮRSx_ 4J-9a@ʂ'J>B^(#א{57/{E3th~&K%Ĕ x (Կ*_mnDZBʒ~3IU/GZ  K>yF+]GU=<}PBw vW{rN0?nE+_ڟ$Du+_kq?;cM3 n*3uu h?EeT+7Mu"#} A]_\Y:%$Hθnlo)tZTSgwrF}v+ZъZ.@l69o:8 XR3Gj&t [jCn:9vJCuܣ*!esEGF/~3y%&*,tO-pN.(݋}Z ʌl _.q JwRq>IIn/JJ;q&g(Ywy`xvȑ;S䑅y䌞,+59COC0Jh=jt.U.>0ckE8.|.82*gAgɚT8Zrv;fw _Q%E eg`o_G֜-xa9%DW٤j$B@އ~Hմi|#䘳d[\r'y׮/3_`d`/5[7exdž[8s6:\1VS8)YT.>WtDɓcc) mFW_3z/Q,ʦ+[ ubS8|pf͞&kq2g[,aE7I[RLN20ߪ£WF) ~Z _ki%(b:+\]w˼k&ΐ_gwRI?ú/s|(LZ%.K]#=sqIwQ.< yp |-*.U\V JuǙ2ZiJ)]={ܿ=w*p.D#YP2rb .6<&UJv.Ԧð{F1OT vpS0 .Q泠KڜQ"W|w_wLŽ/VNeuV Q?HKsڮSEN&͚ L?E~f^VAV& w{qgj1)X\\tU{sNb:~6^8Q[N13\*=ϰh4_v}aOﳫwܙ W̿}=L rO7ͤ´!9 #ʳ9^w-̕U6L{rL\_E' @?%]6RT` 4'ރ_|ۙ{'o!duDx=k1)]_RmΏ܀/d\ՃΞ>xRx+!R-(!ō}2tw۟9=:l)*jBvU3a>N̯$3м"ht@ɑ3i ?Gz05PWwLgПR;2|EW_ o\p'Ǭyj1_][C>69Y^D*)|^ȇޏ5~;3T&#E˖Mu@ dܫ~;)66y?))dQ Ư" 0/[J~ Weα< TN%C|Ylӷ)z *,j&]*̯X8=,e0ƲZn1s"j@ϣ]ϰ9ÙK{WR"xQ`eEeiӶSJAUSZg4Ii^-2&ŴFzYIۅb<”E21.v7ICov#3dt&AQOGzRO6)d%c4jR>α/ =<+uto~<^O-|$'uU6S.qy3${CJj}ԎahzٞU|EJFͯvUrUec)o~r _oԔ2rѫѿ;sZ̯蕥8 Q{碱kJew>>D 31{ZעL[PdFyۢF6+ቴc371(z9v;yՔN>.MWꎾiE%~;F̕)[n_PdJMȕ%D>Y6})d_S%`:̯zL&oHHe&2`7gc4q'5gEu_u.qog+_J}U]Wy6Ww!V& I?i,8unɩ %m~E9ͤ2/s+W^5} +b=I0Wsq3{S5mL䲧ȅu#_3++iDoρP]#ѯ&&Ц,{(=aV@a8Tvݧm.ͮ,= 8#j*kYq˥i^,r'O,ZNf-^RքVS1a_/TvQ9f_ε6wN_IWJ"eaN޷(0=jbg`)%{!x.E΂)ÝL;ׁUf `!yIG663]P8 T$̯Z~&xԯ}1֋YY&ҙ!eS Aʿ#I s*֓SeH$`0ϲИĥ$eO;9Yu #M~j[q53}*CSԠ5d#>!߹YvYif*>\-]ߴAWߪqF.,Џ0y"W3f;7/$X8bUZ-ԇ@W|uZr,?+fW+M۫[LPmu+B4{y9 {_tv-]Re.WFCb?#ͯ]eZ6cխ9$y$j'ÏB&Z@쥘٪_T| KG3^Y+ ľz 9}]~p'Z)dWXV>x|禠+ٟU8,sNNvQ >)f8\KctevaZ=-4\I<WK{3څϜٜZL=οڇ>SZŞk75xLWGq^1+7[]YaSч+U_s|޵2tN(M:.NA<૵_0D5SFJB˜~S|g\-T_XfWV{u%kj bM}~UwWq6Vn@ymfm*5*op$ӝ;qvL 89/FR>I_]1-9wc+h R>I5a?㫥ي~ેIݗSd$t-i&8)1߈V9jKAZƖyjA> s`f W k=?4WbPKVhY2MSOUND[#xҔ<@3ӾA9C\60u0808000020Ո0;000|djJa`dT;``P 2وA7E  v@R }9f:Z*PK?VhY+#M manifest.jsonPK?VhYiJ\pwSamples/auto-test/square.wavPK?VhY2MqSOUNDPKZrelektroid-3.2.3/test/res/connectors/microbrute_sequence.data000066400000000000000000000001571500236517400243320ustar00rootroot000000000000001: 60 00 0 01 2xx 6200 000120 x12 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 elektroid-3.2.3/test/res/connectors/microbrute_sequence.data.back000066400000000000000000000001411500236517400252220ustar00rootroot000000000000001: 60 x x x x x x x 120 x 12 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60elektroid-3.2.3/test/res/connectors/microfreak.mfs000066400000000000000000000130751500236517400222700ustar00rootroot0000000000000022 serialization::archive 10 0 4 2 94 12 square32k16b 1 0 0 18 000000000000000000 0 0 1 1600 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 32 78 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 -32 -79 elektroid-3.2.3/test/res/connectors/microfreak.mfsz000066400000000000000000000003611500236517400224540ustar00rootroot00000000000000PKsoX2;s=0_square32k16b;@ EўU D;Q~H@2| VD]XuK%k~{^yt$ :Y/eڏ6*|"ںRJ)M&DDDDD{xPKsoX2;s=0_square32k16bPK<elektroid-3.2.3/test/res/connectors/microfreak.mfw000066400000000000000000001563401500236517400222770ustar00rootroot0000000000000022 serialization::archive 10 0 4 8 DEVBUILD 9 wavetable 1 0 0 18 000000000000000000 0 0 1 16384 -95 -37 103 -37 34 -37 -45 -38 122 -38 6 -38 119 -39 -50 -40 11 -40 37 -41 29 -42 -14 -44 -91 -45 54 -46 -92 -48 -13 -50 51 -51 111 -53 -86 -55 -26 -57 37 -58 118 -60 -38 -62 81 -63 -36 -65 -126 -66 68 -67 32 -68 23 -69 41 -70 86 -71 -98 -72 1 -72 127 -73 24 -73 -52 -74 -101 -74 -124 -74 -119 -74 -87 -74 -29 -74 57 -73 -87 -73 53 -72 -37 -72 -99 -71 121 -70 112 -69 -126 -68 -80 -67 -8 -66 91 -64 -39 -63 114 -61 38 -59 -11 -58 -33 -56 -29 -54 -16 -52 -3 -50 9 -47 22 -45 35 -43 47 -41 60 -39 73 -37 85 -35 98 -33 110 -31 123 -29 122 -27 92 -25 32 -23 -57 -22 81 -20 -67 -19 16 -17 75 -16 110 -15 119 -14 98 -13 45 -12 -33 -12 126 -11 19 -10 -100 -10 10 -9 89 -9 -119 -9 -102 -9 -116 -9 92 -9 36 -9 -17 -10 -61 -10 -92 -10 -108 -10 -109 -10 -98 -10 -81 -10 -61 -10 -48 -10 -49 -10 -67 -10 -109 -10 82 -10 -2 -11 -95 -11 65 -11 -18 -12 -76 -12 -93 -12 -56 -12 45 -11 -31 -11 -23 -10 73 -8 0 -6 -19 -5 -23 -3 -12 -1 1 2 14 4 26 6 39 8 52 10 64 12 77 14 90 16 102 18 115 20 -128 22 -116 24 -103 26 -91 28 -78 30 -65 32 -53 34 -40 36 -27 38 -15 40 -2 42 11 45 23 47 36 49 49 51 61 53 74 55 87 57 99 59 112 61 124 63 -119 65 -106 67 -94 69 -81 71 -68 73 -56 75 -43 77 -30 79 -18 81 -5 83 8 86 20 88 33 90 45 92 58 94 18 96 -91 97 -14 98 -5 99 -58 100 84 101 -85 101 -54 101 -78 101 98 101 -40 100 16 100 2 99 -82 97 11 96 27 94 -36 91 113 89 6 87 -101 84 48 82 -59 79 90 77 -17 74 -124 72 25 70 -82 67 67 65 -40 62 109 60 2 58 -105 55 44 53 -63 50 86 48 -21 45 -128 43 21 41 -86 38 63 36 -44 33 105 31 -2 28 -109 26 40 24 -67 21 82 19 -25 16 124 14 17 12 -90 9 59 7 -48 4 101 2 -6 -1 -113 -3 36 -5 -71 -8 78 -10 -29 -13 120 -15 13 -17 -94 -20 55 -22 -52 -25 97 -27 -10 -30 -117 -32 32 -34 -54 -37 -112 -39 123 -41 -107 -43 -29 -45 110 -46 57 -47 71 -48 -100 -49 56 -49 35 -49 97 -49 -7 -49 -20 -48 55 -46 -42 -45 -81 -43 -74 -41 -61 -39 -48 -37 -49 -41 34 -40 108 -40 -82 -40 -24 -40 13 -39 29 -39 25 -39 -1 -40 -53 -40 124 -40 18 -40 -115 -41 -20 -42 49 -42 94 -43 126 -44 -100 -45 -71 -46 -42 -47 -9 -48 37 -48 97 -49 -83 -50 9 -50 122 -51 0 -51 -101 -52 75 -52 17 -52 -21 -53 -37 -53 -32 -53 -6 -53 41 -52 109 -52 -57 -52 53 -51 -71 -51 82 -50 0 -49 -61 -49 -103 -48 -128 -47 120 -46 -126 -45 -97 -44 -50 -43 16 -41 106 -40 -39 -39 96 -37 -5 -36 -92 -34 86 -32 13 -30 -57 -29 -122 -27 55 -25 -38 -24 111 -22 -9 -21 111 -19 -44 -18 37 -16 98 -15 -118 -14 -91 -13 -69 -12 -48 -11 -36 -10 -40 -9 -60 -8 -101 -7 90 -6 -3 -6 -126 -5 -12 -5 82 -4 -100 -4 -49 -4 -23 -4 -17 -4 -26 -4 -43 -4 -69 -4 -116 -4 68 -4 -28 -5 108 -5 -37 -6 49 -6 127 -7 -48 -8 40 -8 -118 -9 -8 -10 113 -10 -12 -11 124 -11 21 -11 -99 -12 23 -12 -125 -13 -36 -14 35 -14 92 -15 -114 -16 -67 -17 -10 -18 67 -18 -80 -19 103 -19 -84 -19 119 -18 -97 -17 7 -15 -82 -14 105 -12 -18 -11 52 -9 74 -8 95 -7 117 -6 -117 -5 -95 -4 -73 -3 -51 -2 51 0 -1 1 -17 3 -28 5 -38 7 -48 9 -57 11 -59 13 -105 15 30 17 109 18 -88 19 -17 20 75 22 -63 23 123 25 -123 27 -95 29 -68 31 -40 33 -13 35 15 38 42 40 70 42 97 44 124 46 -104 48 -117 50 96 52 51 54 36 56 63 58 90 60 118 62 -111 64 -83 66 -56 68 -28 70 -1 72 -15 74 -83 76 50 78 -126 79 -95 80 120 81 20 82 -128 82 -56 82 -9 82 12 83 -19 82 -108 82 3 82 46 81 19 80 -83 78 14 77 74 75 93 73 90 71 79 69 68 67 63 65 77 63 110 61 -100 59 -46 57 6 56 54 54 90 52 111 50 118 48 105 46 85 44 63 42 40 40 25 38 29 36 49 34 85 32 -122 30 -71 28 -30 26 -13 24 -37 22 -96 20 95 18 15 16 -63 13 115 11 27 9 -61 6 113 4 61 2 22 0 -7 -3 -44 -5 -100 -7 71 -9 -36 -12 113 -14 15 -16 -66 -19 116 -21 43 -23 -29 -26 -100 -28 78 -30 18 -32 -11 -35 -10 -37 16 -38 73 -40 -97 -42 39 -43 -28 -45 -40 -46 4 -46 110 -47 25 -47 10 -47 68 -47 -62 -47 -126 -46 122 -45 -78 -44 7 -42 116 -41 -28 -45 -57 -44 -93 -43 122 -42 75 -41 14 -40 -63 -40 101 -39 -6 -39 125 -38 -21 -38 70 -37 -114 -37 -61 -37 -28 -37 -12 -37 -5 -37 0 -36 5 -36 10 -36 17 -36 34 -36 61 -36 99 -36 -107 -36 -43 -36 37 -35 -123 -35 -13 -35 113 -34 -3 -34 -103 -33 68 -32 -2 -32 -56 -31 -96 -30 -120 -29 127 -28 -123 -27 -102 -26 -66 -25 -14 -24 49 -22 117 -21 -63 -20 22 -18 116 -17 -36 -16 81 -14 -41 -13 110 -11 27 -9 -44 -8 -115 -6 61 -4 -37 -3 100 -1 -37 0 47 2 102 3 127 4 -128 5 94 6 23 7 -87 7 16 8 77 8 112 8 -120 8 -95 8 -78 8 -62 8 -47 8 -47 8 -63 8 -107 8 72 8 -21 7 -128 7 6 7 124 6 -32 5 53 5 -128 4 -59 3 4 3 51 2 80 1 93 0 88 -1 65 -2 24 -3 -23 -5 -67 -6 -106 -7 118 -8 94 -9 79 -10 70 -11 65 -12 92 -13 91 -14 76 -15 51 -16 13 -17 -39 -19 -100 -20 89 -21 20 -22 -41 -24 -88 -25 -113 -26 -42 -27 -7 -27 -38 -26 36 -24 -107 -23 44 -21 -78 -20 -65 -19 56 -18 81 -18 105 -18 -126 -18 -101 -18 -77 -18 -52 -18 -27 -18 -96 -17 43 -15 -4 -14 -40 -12 -73 -10 -106 -8 118 -6 101 -4 -4 -3 -6 -2 -122 -1 -22 -1 103 0 14 1 -23 1 77 3 86 5 -128 7 -85 9 -42 11 0 14 43 16 85 18 -128 20 -85 22 -43 24 0 27 -39 28 117 30 12 32 -32 33 11 36 54 38 96 40 -117 42 -74 44 -32 46 11 49 54 51 67 53 40 55 -25 56 -128 58 -11 59 23 61 -6 61 -75 62 95 63 17 64 -57 64 87 65 -72 65 -16 65 -19 65 -84 65 38 65 88 64 63 63 -45 61 59 60 -109 58 -21 56 77 55 -40 53 -119 52 84 51 47 50 7 49 -43 47 -116 46 37 45 -96 43 -11 41 58 40 122 38 -70 36 8 35 127 33 22 32 -52 30 -98 29 115 28 51 27 -61 25 1 24 -10 21 -31 19 -83 17 124 15 75 13 8 11 -61 8 -118 6 -113 4 -81 2 -31 0 3 -1 1 -3 -63 -6 86 -8 -21 -11 -109 -13 93 -15 53 -17 14 -19 -22 -22 -56 -24 -104 -26 119 -28 120 -30 -112 -32 -86 -34 -52 -36 -20 -38 47 -39 -103 -41 42 -42 -29 -44 -56 -45 -35 -46 35 -46 -98 -47 73 -47 36 -47 55 -47 -103 -47 49 -46 -5 -46 -34 -49 85 -47 -56 -46 56 -44 -92 -43 7 -41 98 -40 -77 -39 -4 -38 57 -36 107 -35 -111 -34 -85 -33 -70 -32 -66 -31 -73 -30 -85 -29 -98 -28 -112 -27 -126 -26 118 -25 112 -24 112 -23 118 -22 -124 -21 -102 -20 -71 -19 -30 -18 19 -16 77 -15 -111 -14 -35 -13 51 -11 -110 -10 -7 -9 106 -7 -28 -6 103 -4 -13 -3 -121 -1 37 1 -52 2 118 4 27 6 -67 7 94 9 0 11 -94 12 74 14 -1 15 -64 17 -109 19 106 21 52 23 -31 24 102 26 -67 27 -22 28 -34 29 -91 30 64 31 -74 31 -9 31 0 32 -52 31 88 31 -92 30 -56 29 -35 28 -15 27 2 27 32 26 76 25 112 24 -118 23 -118 22 101 21 51 20 -7 18 -73 17 106 16 19 15 -77 13 77 12 -28 10 119 9 0 8 127 6 -12 4 94 3 -66 1 19 0 101 -2 -72 -4 13 -5 104 -7 -57 -9 43 -10 -109 -12 -2 -14 -104 -15 10 -16 110 -18 -51 -20 35 -21 114 -23 -69 -25 0 -26 69 -28 -115 -30 -33 -32 61 -33 16 -34 17 -34 11 -33 117 -32 -16 -31 119 -29 -58 -28 87 -27 0 -27 20 -28 41 -29 61 -30 82 -31 103 -32 123 -33 -112 -34 -100 -34 -29 -33 -107 -31 89 -29 32 -27 -24 -26 -80 -24 -112 -22 -22 -21 90 -20 31 -20 -90 -21 82 -21 64 -21 125 -21 -119 -20 -113 -18 -55 -16 3 -13 62 -11 120 -9 -78 -7 -20 -5 39 -2 97 0 -101 2 -43 4 -109 6 -12 7 79 9 6 11 64 13 122 15 -76 17 -17 19 41 22 99 24 -99 26 -40 28 0 31 18 33 12 35 -17 36 -67 38 43 40 87 41 99 42 114 43 -85 44 7 46 74 47 106 48 111 49 68 50 -28 50 66 51 76 51 -30 50 -5 49 -48 48 -114 47 76 46 24 45 35 44 103 43 -44 42 88 42 -40 41 73 41 -106 40 -73 39 -87 38 97 37 2 36 -101 34 52 33 -29 31 -50 30 -20 29 57 29 -81 28 43 28 -122 27 -103 26 46 25 86 23 109 21 86 19 67 17 49 15 2 13 -47 10 -78 8 -15 6 89 5 -35 3 73 2 124 0 83 -2 -24 -5 125 -7 47 -9 20 -11 16 -13 12 -15 12 -17 16 -19 -1 -22 -6 -24 26 -25 74 -27 100 -29 109 -31 86 -33 83 -35 103 -37 -110 -39 -43 -41 51 -42 -84 -44 68 -45 -6 -47 -50 -48 -67 -49 -28 -50 107 -50 65 -50 99 -50 -68 -53 -53 -51 -39 -49 -26 -47 -15 -45 -6 -43 0 -40 4 -38 5 -36 2 -34 -4 -33 -14 -31 -27 -29 -44 -27 -64 -25 -87 -23 -112 -21 118 -19 93 -17 68 -15 43 -13 19 -11 -2 -10 -21 -8 -39 -6 -53 -4 -65 -2 -74 0 -80 2 -84 4 -84 6 -82 8 -78 10 -70 12 -60 14 -47 16 -31 18 -13 20 9 23 33 25 59 27 89 29 113 31 120 33 115 35 99 37 74 39 41 41 5 43 -23 44 -44 46 -49 48 -58 50 -96 52 76 54 -74 55 -38 56 -69 57 77 58 -95 58 -70 58 -95 58 65 58 -108 57 -106 56 64 55 -107 53 -76 51 -66 49 -57 47 -49 45 -11 43 56 42 122 40 -71 38 -33 36 -36 34 -48 32 -62 30 -79 28 -99 26 -122 24 108 22 81 20 52 18 22 16 -11 13 -47 11 -85 9 -128 7 83 5 34 3 -15 0 -64 -2 -113 -4 96 -6 51 -8 7 -10 -36 -13 -78 -15 -57 -17 -87 -19 125 -21 79 -23 31 -25 -20 -28 -72 -30 -125 -32 77 -34 25 -36 -25 -39 -71 -41 21 -42 -14 -43 5 -41 -110 -40 22 -38 -116 -37 -92 -36 -75 -36 -121 -37 -111 -39 -101 -41 -92 -43 -82 -45 -72 -47 -63 -49 -53 -51 35 -51 36 -50 -73 -49 97 -47 16 -45 -65 -44 112 -42 63 -40 90 -39 58 -39 50 -40 -41 -42 -84 -43 -37 -44 117 -44 39 -43 43 -41 117 -39 -65 -37 10 -34 84 -32 -98 -30 -23 -28 51 -25 125 -23 -57 -21 18 -18 -77 -17 -39 -16 -12 -15 -115 -13 -40 -11 34 -8 108 -6 -74 -4 1 -1 75 1 -107 3 -32 5 36 8 98 10 -103 12 -55 14 -14 16 -82 18 37 20 -123 21 -4 22 -66 24 -59 26 -64 28 -92 30 125 32 48 34 -75 35 -1 36 -26 37 48 38 -47 37 23 37 60 36 99 35 -99 34 43 34 6 34 25 34 75 34 119 34 -112 34 119 34 35 34 -112 33 -81 32 -82 31 -94 30 -105 29 -88 28 12 28 -77 27 -102 27 -70 27 -31 27 -37 27 116 27 99 26 -65 24 4 23 10 21 23 19 35 17 9 15 -18 12 -24 10 100 9 21 8 -18 6 -92 5 16 4 -3 1 -110 -1 40 -3 -29 -6 -27 -8 5 -9 38 -11 75 -13 118 -15 -123 -17 -99 -19 -36 -21 36 -22 61 -24 47 -26 -33 -29 -108 -31 79 -33 18 -35 -36 -38 -82 -40 -120 -42 108 -44 89 -46 79 -48 77 -50 -127 -52 39 -53 54 -54 -84 -55 -120 -50 -127 -48 124 -46 120 -44 113 -42 103 -40 89 -38 76 -36 59 -34 41 -32 25 -30 13 -28 10 -26 16 -24 23 -22 35 -20 42 -18 46 -16 42 -14 31 -12 15 -10 -12 -9 -44 -7 -76 -5 -111 -3 114 -1 93 1 81 3 76 5 84 7 110 9 -107 11 -62 13 -13 15 37 18 92 20 -114 22 -62 24 -8 26 48 29 107 31 -96 33 -53 35 -29 37 -12 39 1 42 5 44 2 46 -4 47 -5 49 -2 51 14 54 23 56 2 58 -67 59 54 61 105 62 88 63 -6 63 96 64 -115 64 -119 64 65 64 -81 63 -50 62 -103 61 16 60 81 58 120 56 -101 54 -62 52 8 51 107 49 -57 47 22 46 65 44 55 42 26 40 -9 37 -50 35 -89 33 -122 31 115 29 101 27 102 25 103 23 99 21 86 19 63 17 27 15 -23 12 -79 10 113 8 39 6 -42 3 -127 1 37 -1 -59 -4 95 -6 -12 -9 -56 -11 112 -13 22 -15 -60 -18 119 -20 43 -22 -36 -25 -120 -27 43 -29 -54 -32 105 -34 9 -36 43 -38 -67 -39 119 -38 -94 -37 -69 -36 -58 -35 112 -34 29 -34 -104 -36 80 -38 3 -40 -76 -43 102 -45 27 -47 -45 -50 -115 -52 -119 -53 32 -52 67 -51 123 -50 -76 -49 -17 -48 46 -46 -117 -45 60 -44 -69 -45 95 -46 -75 -48 62 -49 31 -50 105 -51 -63 -51 95 -49 65 -47 34 -45 0 -43 -36 -42 -70 -40 -101 -38 126 -36 103 -34 84 -32 66 -30 -113 -29 100 -28 50 -27 125 -26 124 -24 -125 -22 -107 -20 -76 -18 -33 -16 23 -13 92 -11 -88 -9 -13 -7 63 -4 -117 -2 -41 0 35 3 11 5 -75 6 78 8 -7 9 -28 11 11 14 32 16 30 18 16 20 -31 21 -115 23 5 25 36 26 -84 26 -110 26 32 26 -113 25 -3 24 -118 24 115 24 -73 24 61 25 -16 25 -96 26 61 27 -85 27 -32 27 -41 27 -125 27 16 27 -119 26 -6 25 119 25 59 25 57 25 110 25 -43 25 64 26 127 26 98 26 -93 25 84 24 -16 22 82 21 -69 19 34 18 96 16 -98 14 -17 12 -66 11 -68 10 -35 9 -39 8 -120 7 -68 5 -103 3 113 1 105 -1 -94 -3 -11 -5 72 -6 -100 -8 -14 -10 40 -11 97 -13 -65 -15 34 -16 87 -18 98 -20 37 -22 -30 -25 -97 -27 89 -29 12 -31 -69 -34 97 -36 -2 -39 -99 -41 60 -43 -38 -46 -88 -48 -40 -50 -120 -51 -106 -52 -123 -42 -26 -41 74 -39 -77 -38 19 -36 104 -35 -73 -34 6 -32 73 -31 -118 -30 -46 -29 38 -27 -113 -26 17 -24 -102 -23 45 -21 -78 -20 47 -18 -103 -17 -20 -16 51 -14 94 -13 121 -12 -110 -11 -90 -10 -60 -9 -1 -8 80 -6 -76 -5 63 -3 -8 -2 -42 0 -61 2 -68 4 -71 6 -62 8 -66 10 -66 12 -58 14 -46 16 -26 18 -21 20 -30 22 -51 24 -62 26 -59 28 -57 30 -54 32 -49 34 -39 36 -26 38 -4 40 13 43 8 45 -32 46 -121 48 -6 49 59 51 68 52 32 53 -46 53 97 54 -67 54 -30 54 -51 54 122 54 -22 53 45 53 80 52 106 51 -115 50 -54 49 21 49 73 48 91 47 51 46 -58 44 50 43 -118 41 -44 39 35 38 -124 36 10 35 -99 33 88 32 20 31 -60 29 91 28 -42 26 44 25 93 23 127 21 -120 19 121 17 83 15 37 13 -28 10 -107 8 57 6 -50 3 -108 1 69 -1 10 -3 -30 -6 -54 -8 -75 -10 -106 -12 106 -14 38 -16 -43 -19 -123 -21 57 -23 82 -25 123 -26 -120 -26 -16 -26 71 -25 -91 -25 -72 -25 26 -25 -96 -27 -106 -29 125 -31 93 -33 66 -35 46 -37 37 -39 29 -41 3 -42 23 -42 -112 -42 19 -41 -109 -41 24 -40 -93 -40 69 -39 108 -39 -78 -40 94 -41 -38 -43 127 -44 106 -45 -92 -46 -91 -46 -107 -45 -74 -44 -46 -43 -25 -42 -6 -41 13 -39 45 -38 81 -37 -125 -36 -61 -35 5 -33 -45 -33 75 -32 -63 -32 -99 -31 13 -29 -110 -28 54 -26 -3 -25 -25 -23 -13 -21 33 -18 100 -16 -90 -14 -24 -12 43 -9 109 -7 -81 -5 -88 -3 116 -1 50 1 -26 2 -81 4 -114 6 69 8 -37 9 88 11 -75 12 -11 13 11 15 -28 15 79 16 68 16 -5 15 -101 15 55 15 -1 14 35 15 -87 15 123 16 -119 17 -100 18 -95 19 -125 20 58 21 -59 21 24 22 84 22 111 22 114 22 96 22 111 22 -100 22 -30 22 69 23 -93 23 -30 23 -32 23 105 23 -120 22 -104 21 -123 20 118 19 98 18 40 17 -14 15 -57 14 -7 13 67 13 -93 12 -34 11 -40 10 116 9 -49 7 27 6 115 4 -7 2 -120 1 22 0 -97 -2 34 -3 -124 -5 -31 -7 92 -8 -36 -10 64 -11 -119 -13 -104 -15 -101 -17 -97 -19 -103 -21 -127 -23 90 -25 30 -27 -54 -30 123 -32 44 -34 -39 -37 -81 -39 -69 -41 94 -42 56 -43 110 -34 56 -33 7 -32 -34 -32 -90 -31 93 -30 10 -29 -74 -29 80 -28 -27 -28 -121 -27 59 -26 18 -25 19 -24 29 -23 57 -22 61 -21 53 -20 14 -19 -62 -19 98 -18 -45 -18 44 -17 -128 -17 -51 -17 41 -16 -74 -16 102 -15 52 -14 66 -13 -100 -12 50 -10 -32 -9 -94 -7 105 -5 68 -3 11 -1 -39 0 -78 2 -109 4 -127 6 85 8 25 10 -40 11 -79 13 -86 15 -87 17 -76 19 -60 21 -40 23 -18 25 11 28 36 30 47 32 35 34 -9 35 -86 37 61 39 -85 40 -4 41 50 43 81 44 80 45 43 46 -32 46 109 47 -45 47 21 48 50 48 66 48 95 48 -114 48 -64 48 -54 48 -100 48 33 48 79 47 66 46 21 45 -47 43 -108 42 117 41 -110 40 -59 39 57 39 -81 38 17 38 74 37 85 36 35 35 -73 33 49 32 -125 30 -82 28 -76 26 -84 24 -122 22 73 20 -11 17 -118 15 67 13 -2 10 -32 8 -29 6 -1 4 31 3 48 1 44 -1 1 -3 -65 -6 -127 -8 71 -10 88 -12 26 -13 124 -14 33 -14 -72 -15 108 -15 -22 -16 0 -16 -110 -18 -60 -20 -33 -22 -17 -24 5 -25 40 -27 92 -29 -109 -31 99 -32 -12 -33 -59 -33 -106 -33 95 -33 47 -33 8 -33 -15 -34 -113 -34 -100 -35 82 -36 -14 -38 -78 -39 -89 -40 -46 -41 125 -41 -65 -41 33 -40 123 -40 -54 -40 20 -39 96 -39 -64 -39 39 -38 -92 -38 56 -37 -48 -37 32 -36 60 -36 92 -36 -56 -36 -85 -35 -81 -34 -26 -33 87 -31 -1 -30 -32 -28 -7 -26 50 -23 107 -21 -92 -19 -35 -17 22 -14 79 -12 88 -10 68 -8 40 -6 -27 -5 -116 -3 36 -1 126 0 -83 1 -74 2 -95 3 117 4 42 5 -67 5 12 6 16 6 -17 5 -64 5 -119 5 -116 5 -22 5 -78 6 -50 7 54 9 -85 10 23 12 108 13 -90 14 -62 15 -69 16 -91 17 95 18 -12 18 80 19 -86 19 5 20 92 20 -69 20 13 21 76 21 101 21 53 21 -63 20 68 20 -71 19 50 19 -95 18 -17 17 67 17 -102 16 46 16 -61 15 98 15 -37 14 32 14 34 13 -5 11 -70 10 112 9 66 8 13 7 -42 5 -109 4 66 3 -48 1 81 0 -23 -2 -123 -3 24 -4 -97 -6 -6 -8 64 -9 -117 -11 -59 -13 -32 -15 -27 -17 -58 -19 -127 -21 66 -23 5 -25 -62 -28 -98 -30 -121 -32 29 -33 -60 -35 67 -26 120 -26 -76 -26 -7 -26 44 -25 70 -25 82 -25 93 -25 79 -25 59 -25 56 -25 78 -25 -108 -25 21 -24 -94 -24 72 -23 -51 -23 65 -22 -119 -22 -97 -22 -103 -22 83 -22 -21 -23 125 -23 4 -23 -95 -24 -127 -24 -111 -24 -52 -24 95 -23 90 -22 -87 -21 24 -19 -93 -18 54 -16 -28 -15 118 -13 17 -11 -68 -10 114 -8 58 -6 -34 -5 112 -3 3 -1 -64 0 -81 2 -84 4 -66 6 -39 8 -8 10 23 13 58 15 91 17 117 19 -123 21 -121 23 121 25 92 27 47 29 -12 30 -83 32 91 34 -6 35 -119 37 7 39 114 40 -53 41 10 43 31 44 33 45 53 46 86 47 107 48 73 49 -37 49 10 50 -47 49 74 49 -106 48 -61 47 -6 46 90 46 12 46 -34 45 9 46 55 46 72 46 34 46 -68 45 2 45 -8 43 -55 42 99 41 -57 39 -8 37 22 36 11 34 -33 31 -108 29 41 27 -44 24 -103 22 -103 20 -58 18 21 17 107 15 -85 13 -50 11 -69 9 -118 7 92 5 54 3 61 1 -102 -1 82 -2 54 -3 15 -4 26 -5 5 -6 -48 -8 110 -9 -36 -11 42 -12 104 -14 -80 -16 9 -17 122 -19 -17 -21 -87 -22 -71 -23 -28 -24 4 -24 23 -25 52 -26 93 -27 -113 -28 -90 -29 123 -30 57 -31 -3 -33 -39 -34 -40 -35 -13 -36 73 -36 -32 -37 -123 -37 30 -37 -88 -38 44 -38 -78 -39 84 -39 0 -39 -54 -40 -77 -40 -93 -40 119 -40 55 -40 1 -40 -1 -41 86 -40 -37 -40 -90 -39 -63 -38 41 -36 -33 -35 -30 -33 18 -30 66 -28 113 -26 -95 -24 -47 -22 0 -19 26 -17 39 -15 47 -13 -11 -12 123 -10 -52 -9 -54 -8 -109 -7 41 -6 -94 -6 13 -5 98 -5 -80 -5 -30 -5 -11 -5 -3 -5 -3 -5 -12 -5 49 -4 -56 -4 -47 -3 55 -1 -7 0 -50 2 -96 4 103 6 33 8 -50 9 107 11 1 13 90 14 126 15 72 16 -20 16 116 17 -36 17 55 18 126 18 -68 18 -17 18 7 19 -2 18 -13 18 -17 18 -18 18 -33 18 -76 18 -111 18 105 18 94 18 62 18 26 18 -47 17 95 17 -56 16 28 16 77 15 97 14 125 13 -124 12 -121 11 120 10 83 9 12 8 -79 6 101 5 30 4 -33 2 -93 1 72 0 -45 -2 100 -3 -36 -5 42 -6 90 -8 88 -10 33 -12 -12 -15 -56 -17 -108 -19 120 -21 62 -23 -57 -25 60 -26 -103 -19 68 -19 -7 -20 -69 -20 103 -20 -8 -21 123 -21 -3 -22 100 -22 -63 -23 47 -23 -72 -24 119 -24 123 -24 -115 -24 -68 -24 -63 -24 -79 -24 109 -24 -20 -25 73 -25 88 -26 63 -27 31 -28 -14 -30 -34 -31 28 -31 -108 -32 69 -32 99 -32 4 -31 16 -30 69 -29 -96 -28 8 -26 -109 -25 0 -23 122 -22 8 -20 -93 -19 83 -17 -45 -16 63 -14 -79 -13 87 -11 61 -9 55 -7 73 -5 104 -3 -118 -1 -87 1 -58 3 -30 5 -6 7 20 10 47 12 74 14 104 16 -123 18 -92 20 -61 22 -29 24 4 27 40 29 75 31 111 33 -104 35 -77 37 -103 39 109 41 90 43 77 45 44 47 -57 48 6 50 -43 50 47 51 45 51 -11 50 -104 50 70 50 38 50 105 50 -45 50 -88 51 125 52 46 53 -102 53 -74 53 104 53 -74 52 -45 51 -83 50 67 49 -103 47 -39 45 -28 43 -59 41 -128 39 21 37 -73 34 -120 32 -92 30 -6 28 120 27 -1 25 112 24 -64 22 -43 20 -56 18 -61 16 -54 14 -23 12 12 11 81 9 -82 7 -2 5 -114 4 12 3 -93 1 83 0 -2 -2 127 -3 -18 -5 100 -6 -22 -8 -119 -9 42 -10 -55 -12 97 -13 -8 -15 121 -16 -22 -18 100 -19 -16 -21 -127 -22 26 -23 -77 -25 109 -26 71 -27 45 -28 41 -29 41 -30 43 -31 34 -32 25 -33 1 -34 -37 -36 -81 -37 -122 -38 123 -39 122 -40 -98 -41 -26 -42 55 -42 -109 -43 -3 -44 109 -44 -3 -45 -53 -45 -48 -45 49 -44 -17 -44 11 -42 -123 -41 95 -39 113 -37 -116 -35 -77 -33 -43 -31 -1 -29 41 -26 81 -24 124 -22 -86 -20 -128 -18 -13 -17 20 -15 -46 -15 85 -14 -105 -14 -65 -14 -33 -14 -15 -14 16 -13 56 -13 96 -13 -109 -13 -55 -13 -14 -13 112 -12 60 -11 113 -10 7 -8 5 -6 31 -4 63 -2 96 0 117 2 -117 4 -97 6 -78 8 -119 10 29 12 58 13 23 14 -61 14 64 15 -111 15 -49 15 17 16 94 16 -78 16 -3 16 84 17 -55 17 61 18 -98 18 -34 18 43 19 112 19 -60 19 -12 19 23 20 21 20 -25 19 -84 19 114 19 19 19 -120 18 -10 17 63 17 -128 16 -88 15 -73 14 -92 13 116 12 69 11 16 10 -14 8 -27 7 -62 6 -124 5 78 4 -9 2 105 1 -68 -1 -48 -3 -84 -5 -103 -7 -114 -9 121 -11 118 -13 54 -15 -60 -17 38 -18 -64 -14 19 -14 124 -15 -1 -16 119 -16 -20 -17 102 -17 -14 -18 108 -18 -42 -19 50 -19 -127 -20 -33 -21 107 -21 5 -21 -90 -22 24 -22 115 -23 -92 -24 -92 -25 -121 -26 43 -27 -82 -29 43 -30 -99 -32 36 -33 -18 -35 -25 -36 57 -36 1 -36 88 -36 48 -35 65 -34 -110 -33 12 -31 -79 -30 84 -28 25 -26 -17 -25 -48 -23 -68 -21 101 -19 -13 -18 -124 -16 53 -14 20 -12 0 -10 -17 -9 -26 -7 -38 -5 -74 -3 -124 -1 70 1 -21 2 -103 4 85 6 19 8 -30 9 -78 11 -112 13 108 15 77 17 59 19 65 21 64 23 76 25 -127 27 -65 29 -98 31 -108 33 -83 35 -52 37 -30 39 -63 41 88 43 -109 44 111 45 0 46 100 46 -86 46 -7 46 113 47 59 48 35 49 99 50 -105 51 -115 52 62 53 -100 53 -127 53 -5 52 35 52 10 51 -85 49 11 48 84 46 98 44 51 42 -36 39 113 37 37 35 26 33 79 31 -53 29 94 28 3 27 -73 25 99 24 1 23 -95 21 97 20 68 19 77 18 79 17 108 16 -100 15 -95 14 -54 13 -60 12 -75 11 -93 10 -106 9 84 8 6 7 -99 5 22 4 -116 2 -20 0 75 -1 -107 -3 -1 -5 63 -6 119 -8 -95 -10 -8 -12 89 -13 -99 -15 -31 -17 62 -18 -42 -20 88 -21 -1 -23 -106 -24 63 -25 -48 -27 95 -28 -23 -30 122 -31 23 -32 -76 -34 86 -35 -19 -37 -95 -38 116 -39 77 -40 62 -41 99 -42 87 -43 100 -44 -81 -45 28 -45 13 -45 54 -45 -80 -45 122 -44 -83 -43 27 -41 -43 -40 -12 -38 -23 -36 40 -33 99 -31 -120 -29 -48 -27 42 -24 60 -22 -2 -21 124 -19 -93 -18 -96 -17 74 -16 -34 -16 113 -15 -8 -15 110 -14 -5 -14 96 -13 -35 -13 111 -12 -13 -12 -26 -11 -45 -10 -74 -9 -36 -8 100 -6 19 -4 -11 -3 -28 -1 108 1 -1 2 -128 4 -9 5 -119 7 -46 8 -96 9 76 10 -25 10 -107 11 -81 11 -1 11 94 12 -55 12 19 13 44 13 -118 13 40 14 -76 14 32 15 49 15 88 15 -95 15 76 16 -3 16 -83 17 48 18 41 18 31 18 36 18 64 18 49 18 40 18 -23 17 -125 17 0 17 121 16 -30 15 13 15 -2 13 -89 12 94 11 41 10 -57 8 116 7 54 6 -71 4 -16 2 63 1 58 -1 69 -3 -111 -5 7 -6 124 -8 8 -9 119 -11 -128 -12 -105 -13 2 -7 -3 -9 28 -9 97 -10 -88 -11 6 -11 125 -12 25 -12 -81 -13 46 -13 126 -14 -104 -15 -106 -16 -89 -17 -60 -18 -49 -19 -87 -20 108 -21 17 -22 -109 -24 1 -25 66 -27 108 -29 -111 -31 -81 -33 -36 -35 56 -36 -74 -38 -86 -39 22 -39 26 -39 -82 -39 -118 -38 -65 -37 57 -35 -26 -34 -83 -32 -84 -30 -72 -28 -50 -26 -30 -24 -96 -22 62 -20 -34 -19 -125 -17 67 -15 8 -13 -74 -12 105 -10 17 -8 -114 -7 -18 -6 57 -4 74 -3 110 -2 -84 -1 -17 0 81 2 -75 3 54 5 -80 6 52 8 -46 9 -98 11 92 13 50 15 87 17 -97 19 93 21 94 23 -116 25 -66 27 -11 29 6 32 -24 33 -120 35 -27 36 13 38 22 39 9 40 2 41 25 42 105 43 -50 44 114 46 -3 47 50 49 38 50 -60 50 -29 50 -110 50 -46 49 -43 48 -108 47 19 46 125 44 -88 42 -124 40 56 38 -19 35 -46 33 9 32 111 30 41 29 -27 27 -68 26 -55 25 -21 24 47 24 -100 23 66 23 33 23 52 23 52 23 72 23 104 23 61 23 22 23 -91 22 4 22 68 21 -109 20 -92 19 -83 18 124 17 -7 15 86 14 -121 12 -75 10 -62 8 16 7 31 5 49 3 28 1 80 -1 -110 -3 -111 -5 -114 -7 -99 -9 -1 -11 41 -12 -123 -14 -67 -16 24 -17 76 -19 126 -21 -77 -23 10 -24 124 -26 -20 -28 71 -29 127 -31 -52 -33 46 -34 -107 -36 32 -37 5 -38 -127 -40 12 -41 -46 -43 -94 -44 26 -44 -96 -45 101 -45 102 -45 -44 -45 126 -44 -71 -43 -76 -41 95 -39 -106 -37 -58 -35 -50 -33 23 -30 -126 -28 -70 -26 -71 -24 -119 -22 19 -20 -120 -19 -104 -18 -101 -17 -94 -16 -95 -15 112 -14 99 -13 4 -12 -54 -12 -70 -11 -103 -10 -1 -9 3 -7 -127 -7 32 -6 20 -5 57 -4 -64 -3 96 -1 59 0 42 1 -6 1 -77 2 -25 3 -49 4 61 5 -86 5 43 6 5 7 -29 6 66 7 -68 7 65 8 125 8 94 8 -64 8 -126 9 33 10 -109 10 112 10 107 10 -75 10 -74 11 -22 12 40 14 54 15 89 15 -123 15 -50 15 110 16 -27 16 113 17 -72 17 -73 17 -105 17 -119 17 -128 17 25 17 59 16 -49 14 104 13 24 12 -124 10 45 9 -10 7 99 6 113 4 -47 2 -52 0 36 -1 -20 -3 3 -3 33 -4 92 -5 -100 -6 55 -6 29 -6 122 -1 38 -2 1 -3 13 -4 39 -5 115 -6 -21 -7 -102 -7 78 -7 -25 -8 47 -8 27 -9 -64 -11 91 -12 1 -13 124 -15 -57 -17 -7 -19 27 -20 42 -22 45 -24 24 -26 -11 -29 -47 -31 -88 -33 -121 -35 -128 -37 -115 -39 41 -40 63 -41 -19 -42 59 -41 -37 -41 -20 -40 91 -38 3 -36 -30 -35 13 -32 64 -30 124 -28 -86 -26 113 -24 20 -22 -74 -21 69 -19 -39 -18 105 -16 -53 -15 46 -13 126 -12 -112 -11 120 -10 65 -9 -73 -9 72 -8 -1 -8 -67 -7 -87 -6 -106 -5 -83 -4 -68 -3 -39 -2 27 0 -97 1 16 3 -94 4 -89 6 -24 8 122 10 120 12 -85 14 -30 16 41 19 94 21 124 23 119 25 76 27 3 29 -87 30 67 32 -31 33 -113 35 92 37 54 39 51 41 9 43 117 44 -92 45 -128 46 -41 46 -65 46 27 46 66 45 40 44 -46 42 103 41 -68 39 -78 37 -125 35 103 33 -116 31 18 30 -74 28 -74 27 -91 26 -74 25 36 25 -63 24 -78 24 -15 24 -128 25 93 26 123 27 122 28 -124 29 -109 30 59 31 -58 31 -19 31 -65 31 87 31 8 31 113 30 -38 29 -23 28 118 27 -58 25 -45 23 -35 21 -68 19 -7 17 -27 15 -34 13 -103 11 -74 9 -26 7 -83 5 114 3 65 1 121 -1 86 -3 115 -5 89 -7 113 -9 84 -11 54 -13 35 -15 74 -17 -98 -19 -20 -21 11 -22 -16 -25 -31 -27 -34 -29 -34 -31 12 -32 -71 -34 -57 -36 -37 -38 37 -39 94 -41 98 -42 71 -43 88 -44 -113 -45 53 -45 20 -45 -56 -45 -112 -43 -27 -42 5 -39 26 -37 -11 -36 47 -33 -102 -31 -23 -29 24 -26 45 -24 15 -22 -15 -21 97 -19 -53 -18 63 -16 -80 -15 -45 -14 37 -12 -1 -12 8 -10 80 -9 -124 -8 84 -6 104 -5 125 -5 -113 -5 -25 -5 122 -4 -101 -3 -32 -2 7 -1 76 -1 98 -1 89 -1 38 0 -91 0 -80 0 -36 0 62 1 62 2 -30 1 76 2 -34 2 122 3 -89 3 80 3 -77 3 -108 4 65 5 -73 5 97 5 47 5 121 5 -55 6 120 8 59 10 -52 11 25 12 122 12 5 13 37 14 33 15 60 16 8 17 109 17 -78 17 30 18 -93 18 -83 18 7 18 -112 16 21 15 -77 13 -8 11 -90 10 126 9 -31 7 -43 5 80 4 90 2 11 1 88 0 24 0 -27 -1 -43 -1 -20 -1 29 0 -45 0 -75 5 25 4 -72 2 -112 1 -124 0 -65 -1 59 -1 -3 -2 -48 -2 -125 -2 -57 -3 -118 -4 -34 -6 14 -7 70 -9 62 -11 4 -13 -77 -16 95 -18 6 -20 -85 -23 74 -25 -25 -28 -125 -30 30 -32 -69 -35 93 -37 4 -39 83 -41 24 -42 118 -43 126 -43 -30 -43 -52 -42 44 -40 -56 -39 -72 -37 4 -34 85 -32 -83 -30 -22 -28 -77 -26 85 -24 -13 -23 101 -21 -55 -20 33 -18 53 -17 68 -16 59 -15 -31 -15 83 -14 -100 -14 124 -14 125 -14 -80 -14 -21 -14 97 -13 -39 -13 -121 -12 41 -11 -34 -11 -61 -10 -4 -9 29 -7 105 -6 72 -4 122 -2 -38 -1 -50 1 -3 3 47 6 126 8 -52 10 29 13 102 15 -89 17 -30 19 25 22 78 24 -125 26 -69 28 -5 30 61 33 -121 35 -96 37 58 39 -98 40 -79 41 61 42 91 42 -42 41 34 41 50 40 10 39 -49 37 82 36 106 34 94 32 120 30 -29 28 -70 27 -98 26 -26 25 9 25 86 24 36 24 57 24 -49 24 -40 25 69 27 19 29 44 31 29 33 16 35 1 37 113 38 -91 39 94 40 -97 40 -115 40 -100 40 94 40 37 40 117 39 22 38 97 36 83 34 66 32 -4 29 48 28 2 26 -20 23 -127 21 -113 19 -74 17 79 15 -25 12 -128 10 -105 8 51 6 26 4 -71 1 -104 -1 54 -3 -44 -6 -124 -8 -124 -10 -64 -12 -12 -14 -31 -16 127 -18 32 -20 -61 -23 103 -25 68 -27 -64 -29 108 -31 20 -33 -19 -36 -99 -38 53 -39 -124 -41 -21 -43 99 -44 73 -45 104 -46 -106 -46 38 -44 35 -43 36 -41 24 -39 -63 -38 -29 -36 69 -33 -96 -31 -11 -29 68 -26 115 -24 -73 -22 126 -20 70 -18 30 -16 -9 -15 101 -13 14 -11 26 -10 97 -9 -9 -8 121 -6 -89 -4 -58 -3 118 -3 1 -3 -61 -4 -58 -4 -127 -3 105 -2 -29 -3 -126 -3 -25 -4 35 -4 -118 -4 -94 -4 77 -4 58 -4 125 -4 -98 -3 10 -3 126 -3 37 -2 -43 -2 -14 -2 103 -2 -54 -2 -60 -1 125 0 -12 0 110 0 19 0 91 0 -14 1 16 4 77 6 87 8 -53 8 92 9 37 10 -69 11 50 13 -43 14 29 16 -30 16 -122 17 102 18 115 19 -23 19 122 19 -1 17 119 16 8 15 48 13 -25 11 -45 10 50 9 20 7 -80 5 -49 3 -37 2 -85 2 13 3 -124 3 35 4 8 5 -56 5 67 7 -32 10 -85 9 -115 8 -124 7 119 6 -73 5 83 5 40 5 12 5 -78 4 -36 3 107 2 -64 0 -18 -2 43 -3 65 -5 15 -7 -64 -10 120 -12 81 -14 3 -16 -75 -19 74 -21 -3 -24 -52 -26 97 -28 -5 -31 -71 -33 7 -34 -113 -36 -68 -37 -126 -37 -78 -37 107 -36 98 -35 88 -34 -105 -33 37 -31 -73 -30 -115 -28 52 -26 -119 -25 -92 -24 -51 -23 -85 -22 -98 -21 121 -20 50 -19 -42 -19 64 -18 -77 -18 -2 -18 86 -17 120 -17 -75 -17 31 -16 -122 -16 40 -15 -58 -15 -93 -14 91 -13 10 -12 12 -11 37 -10 15 -9 81 -8 -37 -7 -91 -5 -57 -4 106 -2 45 0 23 2 47 4 68 6 -123 8 -104 10 -106 12 -86 14 -95 16 -92 18 -66 20 -24 22 -6 24 37 27 47 29 -34 30 76 32 115 33 111 34 10 35 60 35 27 35 -44 34 26 34 81 33 125 32 120 31 6 30 119 28 6 27 -40 25 -20 24 -9 23 -123 23 -48 22 112 22 -81 22 57 23 64 24 -85 25 75 27 51 29 111 31 119 33 -118 35 -112 37 0 39 87 40 92 41 -64 41 -43 41 10 42 -48 41 -110 41 -35 40 109 39 -94 37 -109 35 125 33 57 31 97 29 61 27 60 25 24 23 87 21 -110 19 -123 17 -117 15 -120 13 -30 11 -25 9 11 8 2 6 68 4 59 2 13 0 -32 -3 5 -4 95 -6 -39 -8 -14 -10 -91 -12 95 -14 12 -16 -71 -19 -53 -21 114 -22 79 -24 27 -26 17 -28 -35 -31 72 -32 96 -34 -48 -36 23 -37 -95 -39 88 -40 -1 -41 -34 -40 117 -39 -41 -38 54 -36 111 -35 3 -33 -68 -32 106 -30 20 -28 -85 -27 43 -25 -52 -24 38 -22 -97 -21 -6 -20 72 -18 42 -17 71 -16 14 -15 -13 -15 28 -13 96 -12 41 -10 -4 -10 -70 -10 117 -10 70 -10 -115 -10 117 -9 124 -8 71 -8 53 -8 -16 -9 -121 -9 41 -8 90 -8 19 -8 27 -8 69 -8 72 -7 -30 -8 74 -7 -61 -7 101 -6 -111 -6 -14 -7 87 -6 118 -5 97 -4 -50 -4 87 -4 -4 -5 78 -4 11 -2 75 0 -109 2 121 4 15 5 -100 5 113 6 46 8 -86 9 92 11 -20 12 10 14 -70 14 -53 15 17 17 -34 17 -48 17 -70 16 -125 15 109 14 29 13 97 12 -99 11 67 10 -110 8 -82 7 118 6 37 6 -128 6 24 7 -59 7 -112 8 -104 9 -124 10 5 12 -14 15 98 15 -78 14 -32 13 -35 12 35 12 -24 11 -48 11 -67 11 71 11 74 10 -105 8 4 7 76 5 -81 3 22 2 22 0 -19 -3 -42 -5 16 -6 -21 -9 -57 -11 92 -13 57 -15 90 -17 -17 -20 -110 -22 -120 -24 -21 -26 50 -27 52 -28 -70 -29 -72 -29 64 -28 -78 -28 -54 -28 18 -27 -108 -27 25 -26 59 -25 19 -24 -51 -24 52 -23 -63 -23 -31 -23 78 -22 -107 -22 -13 -22 38 -21 -17 -22 70 -21 -117 -21 42 -20 -27 -20 -83 -19 -103 -18 114 -17 -124 -16 -121 -15 -45 -14 -41 -13 -86 -12 0 -10 15 -9 -48 -9 40 -7 82 -6 -101 -5 -127 -4 -63 -3 -6 -2 -117 0 97 2 40 4 77 6 2 8 -122 9 62 11 -82 12 61 14 2 16 -16 17 -93 19 -110 21 49 23 63 24 100 25 40 26 -12 26 -108 27 -49 27 46 28 110 28 -22 27 -112 27 53 27 -65 26 -35 25 -26 24 -8 23 58 23 125 22 -96 21 114 21 -37 20 -41 20 -111 21 -110 22 -3 23 -82 25 73 27 3 29 27 31 -12 32 -27 34 -66 36 -22 37 58 39 119 40 -30 40 13 41 83 41 -3 40 -111 40 -72 39 31 38 45 36 27 34 -5 31 -67 29 -53 27 -77 25 -57 23 9 22 -120 20 -39 18 77 17 -12 15 -124 14 63 13 -29 11 102 10 -24 8 -65 7 66 6 106 4 119 2 -45 0 88 -1 50 -2 -111 -4 111 -6 95 -8 45 -10 -3 -13 109 -14 89 -15 -108 -17 -81 -19 -18 -21 6 -22 85 -24 77 -26 1 -27 68 -29 -115 -31 -8 -33 19 -33 21 -33 69 -33 -36 -33 -127 -32 55 -31 24 -30 -14 -30 -77 -29 107 -28 -13 -28 108 -27 12 -26 -75 -26 -91 -25 50 -24 -97 -24 -89 -24 -29 -24 59 -23 -124 -23 -1 -23 -41 -22 -6 -21 99 -20 89 -20 -117 -20 -85 -20 -121 -19 -37 -18 57 -16 -75 -16 80 -15 -58 -15 33 -14 66 -13 -66 -13 -83 -13 -11 -13 7 -12 -39 -12 -58 -12 30 -11 81 -11 -37 -11 37 -10 121 -11 -29 -11 51 -9 101 -8 -58 -8 115 -8 37 -8 -119 -8 106 -6 -69 -4 -15 -2 -124 0 61 1 -76 1 -120 2 87 4 -77 5 80 7 32 9 -100 10 58 11 108 12 -44 13 -11 14 89 15 -53 14 4 14 104 13 -38 12 -37 12 123 12 123 11 96 10 29 10 -63 9 46 10 26 11 -62 11 126 12 73 13 56 14 48 15 119 16 24 21 47 21 -15 20 87 20 93 19 -86 18 -104 18 -109 18 -117 18 -8 17 -46 16 -36 14 97 13 -60 11 78 10 8 9 57 7 56 5 84 3 -17 1 -11 -1 -5 -3 -112 -5 -105 -7 12 -8 -95 -11 76 -13 124 -15 -13 -17 -6 -19 -48 -20 19 -20 -33 -21 53 -20 31 -20 86 -21 -93 -22 21 -22 -119 -23 -12 -23 -7 -23 22 -22 -57 -23 -75 -23 19 -23 -8 -24 -86 -24 -86 -24 107 -24 -111 -25 -54 -25 9 -24 -14 -24 70 -22 -100 -21 13 -19 89 -18 -35 -17 72 -15 4 -13 86 -12 76 -11 -9 -10 -4 -9 -108 -8 2 -6 -54 -6 -111 -5 57 -4 22 -3 -63 -3 -6 -2 -117 0 3 2 12 4 98 5 104 6 -61 7 -85 8 -60 9 51 11 -28 12 53 14 -23 15 27 17 -124 17 96 18 -64 18 90 19 0 20 67 20 36 21 -19 21 -95 21 -73 21 -41 21 -14 21 -94 21 70 21 -34 20 -112 20 5 20 64 19 87 19 -33 18 56 19 111 20 -23 21 -71 23 -80 25 72 27 -46 28 -57 30 111 32 62 34 -24 35 -49 36 23 38 -114 39 0 40 65 40 -102 40 38 40 -116 39 -114 38 -52 36 -78 34 -99 32 116 30 58 28 47 26 35 24 77 22 -10 20 -75 19 29 18 20 17 95 16 -124 15 -94 14 -24 13 -54 12 -38 11 72 11 90 10 -40 8 34 7 -74 5 101 4 -95 3 72 2 82 0 119 -2 104 -4 90 -6 42 -7 93 -8 -8 -10 98 -11 -21 -13 81 -14 -126 -16 91 -18 84 -19 -109 -21 -101 -23 -72 -25 69 -26 101 -27 44 -27 -10 -28 -34 -28 15 -27 57 -27 50 -27 2 -27 -61 -28 57 -28 -91 -29 65 -29 54 -29 -102 -29 86 -29 -33 -30 9 -30 98 -31 72 -31 -13 -32 -68 -32 38 -31 -95 -31 -99 -31 -50 -31 120 -30 -25 -30 92 -28 30 -26 -45 -25 3 -23 79 -22 -125 -21 -90 -20 71 -18 15 -17 54 -17 -67 -17 -72 -17 89 -16 -102 -16 -32 -16 -51 -16 62 -15 -90 -15 -19 -16 93 -15 -34 -14 88 -12 -82 -12 127 -12 62 -12 -75 -12 -69 -10 29 -7 64 -5 127 -4 92 -3 -67 -3 -113 -2 113 0 -84 1 52 3 69 5 31 7 -84 7 -2 8 -118 10 0 12 -40 12 -45 12 127 12 94 12 -106 12 87 13 92 13 -72 12 54 12 -106 12 25 13 71 14 -58 15 -128 16 74 17 21 18 -20 18 -17 19 -6 20 -15 25 -81 26 -30 26 -124 26 -106 25 -19 24 5 25 19 25 21 25 103 24 29 23 -21 20 -114 19 18 18 -55 16 -38 15 68 14 113 12 -57 10 -54 9 1 8 57 6 -41 3 16 2 -33 0 125 -2 57 -4 -86 -6 59 -7 8 -9 -73 -11 -69 -12 85 -12 119 -12 -38 -13 51 -14 -121 -16 -22 -18 79 -19 0 -19 51 -20 -78 -21 -83 -22 -3 -23 -100 -24 -7 -25 22 -25 -71 -26 7 -26 -115 -28 -87 -28 -32 -28 15 -26 -7 -25 -41 -23 -56 -21 -125 -19 114 -17 63 -15 102 -13 1 -11 23 -10 17 -8 8 -7 117 -7 -13 -6 87 -5 -104 -5 0 -4 117 -4 -112 -4 107 -3 -77 -2 -42 -1 -69 1 -84 2 50 3 42 4 -123 4 36 5 56 6 -91 7 -111 8 1 10 -62 10 -123 10 20 11 15 11 117 11 29 12 104 12 -56 13 24 15 4 15 -117 15 37 16 -47 16 21 17 84 17 116 17 -103 17 64 17 -105 16 -14 16 -101 16 79 17 -1 18 -19 20 28 23 82 25 -33 26 52 28 -2 29 111 31 21 33 -117 34 42 35 101 36 15 38 -120 38 -35 38 72 39 -72 38 -15 37 -46 36 -19 34 -76 32 -92 30 120 28 76 26 48 24 55 22 127 20 -109 19 -104 18 28 17 -101 16 -116 16 74 16 -50 15 -71 15 -1 14 -96 14 -89 14 75 14 39 13 -77 11 -124 10 99 9 5 9 -8 7 53 6 -105 4 -78 2 -49 0 2 0 127 -1 127 -2 64 -3 24 -4 -45 -6 -19 -8 -82 -10 -16 -11 49 -12 -1 -15 -43 -17 -38 -19 28 -20 123 -21 119 -22 -94 -23 78 -23 -64 -24 -41 -25 -73 -26 -126 -27 -25 -29 72 -30 -31 -32 34 -32 -7 -33 -27 -34 -117 -35 -39 -37 81 -38 -58 -39 -43 -40 -20 -41 -26 -41 -73 -41 71 -41 -79 -41 -47 -40 -114 -39 -106 -37 -65 -35 -59 -33 -91 -31 -99 -29 -117 -27 114 -25 -116 -23 -98 -22 -4 -22 -63 -21 -91 -21 18 -20 -90 -20 -39 -20 -128 -20 -40 -20 92 -19 -104 -20 13 -19 -71 -18 117 -16 -66 -16 -76 -16 -126 -16 10 -15 45 -13 -104 -11 -96 -9 -123 -8 -125 -7 -52 -7 -103 -6 -120 -4 -99 -3 11 -1 84 1 -121 3 -1 3 109 5 23 7 -35 8 38 10 -85 10 -54 10 38 11 34 12 -95 13 11 14 -59 13 -34 13 -32 14 65 16 45 18 58 20 2 21 -41 21 -97 22 90 23 100 24 48 25 53 28 111 29 -3 29 -45 29 1 29 111 28 -112 28 -104 28 -99 28 -40 27 105 26 23 24 -63 22 82 21 26 20 98 19 2 18 97 16 -18 14 55 14 -89 12 22 11 -12 8 122 7 -85 6 -119 4 115 2 47 1 -27 -1 -104 -3 41 -4 14 -5 -117 -6 121 -6 -121 -7 84 -9 -1 -12 -78 -14 107 -16 -96 -17 75 -18 95 -19 -28 -21 -57 -22 -5 -24 -10 -25 -94 -26 -22 -27 -32 -28 -13 -30 -43 -30 -33 -30 1 -28 35 -26 34 -24 53 -22 20 -20 29 -18 4 -16 49 -14 -53 -13 -61 -12 -85 -10 122 -9 -59 -9 36 -7 36 -7 -28 -8 -7 -8 18 -7 -45 -8 78 -7 66 -6 10 -5 -102 -4 40 -3 81 -3 12 -2 36 -2 -111 -2 127 -1 -50 0 -117 1 -39 2 105 3 -19 2 103 3 73 3 -109 3 46 4 124 4 25 6 -80 7 -67 7 -105 8 -125 9 -120 10 43 11 -41 11 109 12 -9 12 -30 12 117 12 12 13 -29 12 -44 13 -47 15 0 18 107 20 -52 22 72 24 -127 25 25 27 80 28 -55 29 26 31 -88 31 -17 32 -57 34 91 35 -59 35 62 36 -69 35 -9 34 -15 33 66 32 53 30 91 28 102 26 111 24 122 22 -44 20 121 19 15 19 125 18 63 17 43 17 -86 17 -19 17 -45 17 72 18 -1 17 34 18 -94 18 -87 18 -56 17 -114 16 -93 15 -49 14 -56 14 -12 13 78 12 -47 10 5 9 69 7 -70 6 106 6 -70 5 -65 4 -44 3 -71 2 -62 0 -98 -2 66 -2 -62 -4 -90 -6 110 -8 48 -10 -20 -13 8 -13 -118 -15 72 -16 -85 -17 -87 -18 53 -19 122 -21 -106 -23 70 -25 5 -27 29 -29 -4 -31 113 -31 -40 -33 -24 -35 -87 -37 -114 -39 -90 -40 73 -41 -4 -43 -103 -43 -39 -44 5 -44 104 -44 -100 -43 121 -42 -51 -40 28 -37 38 -35 59 -33 91 -31 122 -29 -96 -27 -54 -25 -31 -24 96 -23 64 -22 -7 -23 24 -22 -77 -22 -63 -22 81 -22 -90 -22 49 -21 99 -22 -80 -22 66 -20 0 -18 74 -18 123 -18 127 -18 51 -17 108 -15 -55 -13 -93 -11 69 -10 112 -9 -49 -9 -76 -8 -104 -6 112 -5 -92 -4 -31 -2 38 1 -122 1 -4 2 -76 4 -95 6 14 8 -54 8 42 9 -29 9 108 11 103 13 35 14 28 14 126 14 -49 15 -78 17 11 20 113 22 75 23 54 24 -7 24 -117 25 113 26 7 27 -30 24 53 26 -22 26 -27 26 84 26 -16 25 -49 25 -108 25 -121 25 -79 24 18 23 -44 20 72 19 -87 17 56 16 101 15 45 14 -72 12 113 11 -86 10 94 9 6 8 -96 6 -79 5 81 5 -21 3 64 2 88 1 72 0 33 -2 -97 -4 -80 -5 61 -5 -13 -6 32 -6 28 -8 -49 -11 -90 -13 -104 -15 -34 -16 -83 -17 -56 -18 107 -19 78 -20 -35 -22 -57 -23 82 -24 62 -25 18 -26 21 -28 117 -29 -12 -30 71 -29 -58 -28 -7 -27 86 -25 -82 -24 21 -22 110 -21 -66 -20 -85 -19 -17 -19 -29 -18 81 -17 -108 -17 102 -16 0 -16 71 -17 -39 -18 -76 -18 -104 -18 -81 -18 60 -17 -99 -17 102 -16 -106 -16 -69 -16 -104 -15 29 -14 13 -13 95 -12 -15 -11 11 -9 -117 -8 -117 -7 -54 -7 -67 -6 62 -5 -89 -5 20 -4 86 -4 -96 -3 -20 -2 -28 -2 -50 -1 -84 0 -117 1 19 2 -69 2 -91 3 122 4 -43 4 -18 4 -77 5 -40 5 -64 6 -82 8 -80 10 20 13 127 15 -28 16 64 18 -93 19 -99 20 -29 21 67 23 76 24 -32 25 -29 27 -49 28 73 29 -47 29 -67 29 102 29 5 29 89 28 40 27 -14 25 -78 24 71 23 -7 21 61 21 -45 20 32 21 79 21 -102 20 -77 20 -119 21 38 22 99 22 38 23 109 23 -14 23 -95 24 -103 24 -72 23 -102 22 1 22 -66 21 -20 21 28 21 84 19 -86 17 -59 15 12 14 106 13 21 13 127 12 -104 11 -70 10 91 9 86 7 -70 5 -5 5 71 5 -3 3 46 2 77 0 72 -2 120 -3 66 -4 75 -5 -14 -6 27 -6 -27 -8 84 -9 92 -11 40 -13 51 -15 -6 -17 58 -17 -76 -18 63 -19 106 -21 73 -23 77 -25 52 -26 -42 -28 -44 -29 63 -29 37 -30 -5 -32 -67 -32 30 -31 -79 -31 -83 -29 -106 -27 -14 -26 27 -24 47 -23 66 -22 112 -21 -82 -20 44 -19 -106 -19 68 -18 -94 -19 48 -19 29 -19 -42 -20 -63 -20 76 -19 -82 -19 -50 -20 -117 -20 98 -19 -117 -18 -3 -18 -97 -17 64 -16 101 -15 -79 -13 -40 -11 98 -9 -8 -9 119 -7 92 -6 -89 -5 82 -3 -71 -3 109 -2 2 0 -67 1 -5 1 83 3 -5 4 -71 6 -104 7 -59 7 -18 7 -65 8 86 10 62 12 34 13 11 13 -16 12 -48 13 100 15 118 17 -59 19 -64 20 -34 21 -99 22 -21 22 70 23 -67 23 61 21 -92 22 125 23 -98 23 78 23 26 23 -73 22 60 22 29 22 58 21 114 19 80 17 -107 15 -51 13 42 12 63 11 52 10 -16 8 -39 7 5 7 0 6 -27 4 61 4 -39 3 -23 3 65 3 5 2 123 1 -89 0 -83 -2 33 -3 95 -4 -2 -5 126 -5 -52 -6 -2 -8 -62 -10 -58 -12 -9 -14 80 -14 71 -15 109 -16 50 -17 26 -18 8 -19 -27 -21 86 -22 -21 -24 -94 -25 -100 -27 -128 -28 119 -29 -2 -30 -40 -29 61 -28 -29 -28 -80 -27 115 -26 60 -25 -83 -25 -20 -25 127 -25 127 -25 -116 -25 -59 -25 11 -24 67 -25 21 -26 40 -27 -58 -28 -51 -28 -126 -28 -90 -28 -95 -28 -91 -28 119 -28 -104 -28 -109 -27 -127 -26 -18 -25 -100 -23 107 -21 -36 -20 -120 -18 -14 -17 -24 -16 77 -14 105 -13 -17 -13 45 -12 100 -12 85 -11 83 -10 54 -10 45 -9 -6 -9 -80 -8 29 -7 -65 -7 -10 -6 18 -4 -38 -4 119 -3 102 -2 -42 -2 -77 -1 -117 1 87 3 -83 5 24 8 97 9 -38 10 4 12 -66 12 -50 13 54 15 -77 16 -114 18 -77 20 -15 21 123 22 15 23 105 23 125 23 -64 23 22 24 -64 23 49 23 -89 22 -53 21 39 21 83 21 -40 21 -41 22 -61 23 -106 23 -36 23 3 25 -9 25 -119 26 -106 27 104 28 76 29 38 30 16 30 51 29 53 28 -18 27 59 28 -100 28 -44 27 -16 25 33 24 43 22 127 20 -54 19 111 19 -9 18 38 18 89 17 -68 15 -81 13 -96 12 123 13 -111 13 26 13 -69 11 59 10 125 8 -62 7 -41 6 46 6 26 6 111 5 124 4 26 3 23 1 6 -1 100 -3 -38 -4 125 -4 -3 -5 -79 -6 -3 -8 3 -9 44 -11 -25 -13 -114 -14 -38 -15 22 -15 -89 -17 46 -18 83 -19 -29 -20 43 -19 -56 -18 70 -16 -14 -16 47 -15 55 -15 62 -15 116 -15 -58 -15 -85 -15 -1 -15 122 -14 -128 -15 -126 -16 -60 -17 43 -17 112 -17 45 -16 101 -16 120 -17 -88 -18 -60 -18 87 -17 -19 -17 -3 -16 52 -14 -59 -13 27 -10 4 -8 57 -7 -62 -7 -115 -5 -13 -4 -99 -2 10 0 0 0 52 0 31 1 75 2 102 2 -100 3 47 5 -73 6 7 7 -89 6 -102 6 126 7 29 9 -21 10 -14 11 -50 11 57 11 -90 11 -27 12 -85 14 -38 16 -15 17 61 19 -12 19 -1 19 -48 19 39 20 -73 17 50 19 45 20 114 20 97 20 91 20 -71 19 0 19 -48 18 -33 17 -16 15 -24 13 0 12 17 10 62 8 59 7 90 6 70 5 94 4 126 3 -67 2 -33 1 -19 1 17 2 -115 2 -100 2 -52 1 -99 1 4 1 54 -1 -98 -3 8 -3 -72 -4 5 -4 114 -5 -39 -7 -83 -9 -36 -11 74 -12 -73 -13 -44 -14 5 -14 -21 -16 -40 -17 32 -17 -15 -19 72 -20 -118 -22 37 -23 23 -25 -126 -27 -9 -29 -73 -30 -14 -30 -112 -30 -125 -30 -53 -30 -17 -30 44 -29 -59 -30 92 -30 68 -31 88 -32 6 -32 55 -32 -11 -33 -51 -34 47 -35 -58 -37 41 -37 83 -37 -87 -38 104 -38 0 -38 68 -39 -68 -40 -40 -40 -15 -39 69 -37 42 -35 50 -33 59 -31 1 -29 -40 -28 -89 -26 79 -24 35 -22 -43 -21 119 -20 -121 -20 -77 -20 79 -19 1 -18 -49 -19 -45 -18 -113 -17 30 -16 112 -16 11 -15 -113 -14 -18 -13 32 -11 61 -10 85 -9 14 -8 -32 -8 -94 -6 59 -4 -125 -2 -18 0 27 2 -79 3 -93 4 31 5 -5 5 106 7 89 9 120 11 -66 13 75 15 -27 15 -124 16 72 17 -59 17 -90 18 -11 19 117 20 -121 20 -83 20 91 20 92 20 105 21 -44 22 -127 24 34 26 122 26 -21 26 98 28 -88 29 -116 30 -30 31 59 33 122 34 125 35 91 35 -128 34 -95 33 -85 33 -125 34 21 35 84 34 86 32 99 30 91 28 -67 26 -12 25 -106 25 57 25 126 24 -63 23 -24 21 -43 19 77 19 -67 20 -105 21 -20 21 -7 20 -41 19 94 18 -72 17 21 17 -72 16 -26 16 103 16 -76 15 127 14 113 12 -126 10 48 9 81 9 82 9 -39 8 -75 7 34 6 76 4 -102 2 42 1 -43 -1 109 -1 123 -2 -70 -4 -11 -6 -126 -7 71 -8 71 -8 -119 -7 -98 -6 -97 -6 -7 -7 -3 -8 1 -8 70 -9 -75 -10 6 -10 69 -10 -115 -10 62 -11 -71 -13 85 -14 109 -15 8 -14 -9 -14 5 -13 12 -14 -76 -16 27 -16 29 -16 -42 -16 80 -14 25 -12 18 -10 114 -8 31 -6 2 -5 125 -5 -109 -3 117 -1 122 1 -84 2 53 2 -19 1 50 2 -43 2 -50 2 -30 3 96 5 -75 6 123 6 -110 5 80 5 72 6 -18 7 -93 9 -52 10 -102 10 -113 9 -114 9 123 10 -10 11 7 14 57 15 -78 16 98 17 43 17 119 16 -81 16 77 14 -37 15 -9 16 96 17 -117 17 -78 17 -45 16 -35 15 -99 15 -97 14 -118 12 -100 10 -120 8 114 6 113 4 88 3 -96 2 -70 1 -1 0 19 0 -107 -1 -16 -2 -80 -1 87 0 60 1 -4 1 -108 1 -66 1 94 1 -70 -1 24 -2 -84 -3 109 -3 -121 -4 19 -4 -82 -6 -111 -8 -23 -10 -109 -11 18 -11 84 -12 -112 -13 -106 -14 -121 -15 40 -15 -19 -17 43 -18 28 -20 -100 -22 -122 -24 123 -26 114 -28 114 -30 19 -30 -16 -32 55 -32 -3 -33 -121 -33 61 -33 5 -34 -7 -36 59 -37 107 -39 -67 -40 -26 -40 31 -40 -101 -42 -112 -44 -79 -46 -38 -47 37 -46 31 -47 124 -48 -76 -49 62 -50 95 -51 119 -51 -83 -50 99 -48 -67 -46 28 -43 94 -41 118 -39 117 -37 -88 -35 -5 -33 59 -30 126 -28 59 -27 30 -27 63 -27 -118 -27 -15 -27 -84 -27 -68 -26 105 -25 -48 -25 8 -24 -98 -24 107 -22 13 -20 -91 -19 61 -17 124 -16 124 -15 67 -14 -16 -13 89 -11 -110 -9 -3 -7 16 -5 -63 -4 125 -3 -66 -3 103 -2 -34 -1 57 2 -101 4 2 7 -36 8 -125 9 46 10 88 11 59 12 -75 13 -10 15 68 17 -15 17 -61 18 -9 18 -105 19 125 21 -55 23 28 26 111 28 71 29 -31 29 -91 31 60 33 112 34 11 36 -25 37 126 39 -86 40 122 40 -93 39 -30 38 58 39 -104 40 90 41 -96 40 -119 38 115 36 90 34 -55 32 -18 31 -117 31 72 31 -93 30 -11 29 -29 27 -55 25 -59 25 -59 27 93 29 120 30 -19 29 38 29 -16 27 93 27 1 27 -19 26 92 27 6 27 -111 26 -119 25 111 23 -94 21 -98 20 99 21 -63 21 78 21 80 20 -36 18 41 17 -100 15 2 14 -79 12 -110 12 116 11 101 9 84 7 78 5 79 3 9 3 -14 3 -93 4 -1 3 124 2 -124 0 -115 -2 -22 -4 124 -5 62 -6 104 -6 -128 -6 -33 -8 -42 -10 -46 -12 -99 -13 -116 -12 -86 -11 -111 -11 -117 -12 -81 -14 103 -15 -36 -16 -72 -15 -105 -13 -17 -11 76 -8 -75 -6 41 -4 -68 -4 42 -3 -120 -1 -29 1 65 4 57 5 88 4 -104 3 60 3 90 3 51 3 38 4 -112 5 -77 6 -13 5 -122 4 17 4 27 5 -55 6 101 8 -81 9 112 9 -13 7 -122 7 36 8 87 9 75 11 -105 12 59 14 -28 14 110 14 56 13 82 13 23 9 1 11 -121 12 100 13 -20 13 68 14 -106 13 -57 12 -55 12 94 12 -16 10 -91 9 30 8 70 6 113 4 -73 3 -110 3 68 3 29 3 119 2 -24 1 -118 1 -93 2 -127 3 -65 4 -6 5 39 6 -54 6 -112 6 -51 4 7 3 -111 2 -105 2 -7 1 -107 1 -20 -1 -127 -3 -123 -5 -24 -7 33 -7 88 -8 -118 -9 -81 -10 -76 -11 -4 -12 92 -13 104 -15 -9 -17 19 -17 -90 -19 -25 -21 11 -22 32 -24 111 -25 15 -26 68 -27 30 -27 -28 -28 -73 -28 119 -29 52 -30 20 -32 -3 -35 99 -35 -64 -35 -19 -36 74 -37 31 -39 38 -41 20 -42 -18 -43 -84 -44 -1 -45 87 -45 -79 -47 91 -48 -15 -49 -97 -48 29 -46 95 -44 -84 -42 -102 -40 65 -38 -91 -37 52 -35 3 -33 -60 -32 103 -30 -25 -30 -72 -30 87 -30 17 -30 -26 -31 37 -31 58 -30 21 -29 70 -29 67 -29 117 -29 -75 -28 -21 -27 40 -25 -60 -24 42 -22 -102 -21 -52 -20 -106 -18 -28 -17 -55 -15 41 -12 -98 -11 -85 -9 -114 -8 123 -8 -63 -8 -53 -7 -33 -5 -36 -3 -7 -1 -31 1 -74 2 5 3 -80 3 93 4 -46 5 35 8 -128 9 69 10 17 11 17 11 -113 11 -111 13 -42 15 61 18 -97 20 -88 21 -103 22 73 24 -113 25 -76 26 -101 28 -36 30 -39 32 79 34 125 34 32 34 -43 33 -100 34 21 36 58 37 14 37 -102 35 28 34 -128 32 39 31 127 30 -93 30 -25 30 -47 30 -98 30 -90 28 -58 26 52 27 80 29 17 31 -128 32 -115 32 97 32 -118 31 -11 30 120 30 96 30 0 31 -17 30 -105 30 100 29 9 27 22 25 8 24 -105 24 -44 24 92 24 -114 23 112 22 -9 20 104 19 -90 17 -114 16 -7 16 103 16 -47 14 50 13 -109 11 -85 9 81 9 44 10 -18 10 -126 10 61 9 125 7 -97 5 -27 3 61 2 -11 0 74 1 69 1 -102 -1 -118 -3 -92 -5 114 -6 1 -5 -66 -5 121 -5 103 -6 83 -8 -110 -10 -126 -11 -49 -11 105 -9 -124 -7 -88 -5 -84 -3 -88 -2 -63 -2 -92 -2 87 0 16 2 -59 3 52 4 53 3 8 2 41 1 -77 0 12 0 -116 0 -75 1 -112 2 -104 1 21 0 82 -1 18 0 79 1 -82 2 -13 3 -52 3 -64 2 -110 2 56 3 45 4 -20 5 117 7 62 9 -9 9 119 9 -13 7 -74 7 109 1 123 3 65 5 -119 6 104 7 -24 7 -93 7 52 7 -114 7 -10 7 -90 7 96 7 -38 6 -89 5 99 4 71 4 -32 4 91 5 -14 5 -60 5 44 5 48 5 109 6 84 7 -67 8 67 10 21 11 43 12 33 12 121 10 -43 8 92 8 -73 8 -101 8 86 8 -107 6 42 4 13 2 79 0 77 -1 -114 -2 -43 -3 66 -3 -119 -4 109 -5 -111 -7 -75 -9 94 -9 112 -9 29 -9 32 -10 -26 -12 -118 -13 -86 -14 89 -15 -72 -16 -54 -16 3 -15 28 -15 45 -16 -8 -18 -46 -20 -29 -22 -116 -22 30 -21 119 -22 2 -23 31 -25 112 -27 75 -28 -109 -29 73 -30 -67 -31 108 -31 -14 -33 75 -34 74 -35 38 -35 10 -34 -76 -33 121 -31 -98 -30 93 -29 -76 -29 24 -28 -47 -28 -115 -27 0 -26 23 -26 -32 -27 -23 -28 2 -28 46 -29 -16 -31 -38 -30 -47 -29 -70 -29 112 -29 24 -29 94 -29 -55 -29 72 -28 -114 -27 -30 -26 -103 -24 36 -22 -54 -21 -57 -20 -16 -19 -35 -17 -105 -15 -67 -13 -73 -12 70 -12 7 -12 87 -12 -95 -11 -70 -10 23 -8 -79 -7 -101 -6 99 -6 57 -6 113 -6 -124 -5 91 -3 108 -2 18 -1 -107 -1 58 -1 89 -1 3 1 -76 2 -82 4 -98 6 -94 7 -44 8 19 10 -85 10 126 11 104 13 -77 15 -51 17 95 19 0 20 82 20 -90 20 -49 21 18 23 124 24 16 25 -78 24 64 24 -116 23 -76 22 111 22 59 23 30 24 -63 24 52 25 -67 23 121 22 82 23 29 25 -92 26 32 28 -36 28 111 29 44 29 -88 28 8 28 -29 27 -101 28 -34 28 -79 28 114 27 40 25 85 23 89 22 106 22 98 22 -10 21 -126 21 -2 20 8 20 -76 18 16 17 113 16 111 17 -76 17 13 17 84 16 -100 15 71 14 -17 13 -92 14 109 15 122 15 -28 14 -28 13 -90 12 67 11 -65 9 -69 8 61 9 29 9 -68 7 19 6 -63 4 -42 3 -64 3 -41 3 108 3 122 2 -111 0 -99 -2 40 -3 -87 -4 -111 -3 -21 -2 85 0 126 1 -65 1 68 1 123 0 -7 0 -126 1 1 2 -74 1 -49 0 92 -1 22 -2 13 -3 -30 -5 -67 -5 99 -4 -58 -4 -57 -5 -126 -6 -125 -7 -65 -7 52 -6 11 -5 13 -4 16 -4 -40 -5 22 -4 -71 -4 67 -3 119 -2 8 0 -83 1 92 2 -16 1 97 0 -63 -1 9 -6 56 -4 61 -2 -19 -1 31 1 -58 1 -27 1 -45 1 -125 2 -75 3 121 4 46 5 -95 5 13 5 86 4 -47 4 33 6 95 7 -82 8 -12 8 83 8 -75 8 20 10 4 11 -105 12 100 14 -42 15 90 17 -128 17 -13 15 109 14 -12 13 -96 14 1 15 -38 14 2 13 -105 10 91 8 125 6 65 5 -115 4 -24 3 -102 3 33 3 -92 1 -113 -1 -55 -3 -125 -2 -127 -1 62 0 -3 -1 95 -1 -115 -2 127 -3 62 -4 -59 -5 13 -4 -75 -4 17 -3 113 -4 73 -5 29 -7 85 -9 62 -9 3 -8 -121 -9 63 -10 -94 -12 58 -13 1 -14 -67 -16 108 -17 -1 -18 2 -17 -78 -19 -67 -21 43 -22 61 -23 -117 -23 -92 -22 -28 -21 71 -20 38 -20 121 -21 -66 -22 105 -22 43 -22 121 -23 43 -23 -21 -24 99 -25 -31 -27 107 -28 -75 -30 117 -29 -122 -28 41 -28 -101 -29 -66 -30 20 -30 -70 -31 -125 -31 116 -30 -72 -29 -77 -27 -108 -25 24 -23 -58 -23 58 -22 -73 -21 -75 -19 -13 -17 2 -15 54 -16 120 -17 20 -17 -101 -17 -40 -17 124 -16 -54 -15 -56 -14 14 -14 23 -15 -34 -16 -108 -15 -11 -14 -67 -13 67 -12 -127 -12 -51 -13 -111 -13 -27 -12 9 -10 -102 -9 27 -7 27 -6 -117 -5 93 -4 78 -4 -47 -4 -65 -2 19 1 74 3 -10 4 6 6 0 7 -19 7 116 9 -123 10 49 12 126 13 45 14 -67 14 -22 14 -114 14 -88 14 22 16 -110 17 -24 18 -5 19 0 19 83 18 -109 19 15 21 96 22 -25 23 76 25 -104 26 -28 26 112 26 -81 25 124 25 77 26 -32 26 -36 26 -111 25 88 23 -93 21 -72 20 81 20 5 20 -89 19 -120 19 -102 19 33 19 7 18 -128 16 84 16 -31 17 -12 18 53 19 90 19 -127 19 -71 18 100 18 -13 18 -60 19 69 20 88 20 18 20 109 19 94 18 -2 16 59 16 -23 16 -83 16 -108 15 78 14 -116 13 -26 12 49 12 -90 11 24 11 68 10 -124 8 97 6 -119 4 69 3 -127 3 33 4 -39 4 45 5 -71 4 -79 3 65 2 -107 1 -8 0 77 0 79 -1 127 -2 -55 -4 31 -5 -119 -7 -35 -9 25 -9 65 -9 48 -9 42 -10 33 -11 -24 -13 -92 -13 89 -13 -82 -13 111 -12 -102 -12 47 -11 -43 -11 117 -10 -105 -10 69 -9 -34 -8 97 -6 5 -5 -84 -6 18 -7 20 -8 -26 -14 54 -11 119 -9 -117 -7 14 -5 -37 -5 90 -4 -95 -4 -92 -3 -102 -1 104 1 17 3 115 4 121 4 73 4 88 5 88 7 81 9 81 11 8 12 94 11 26 12 -101 13 -108 14 78 16 97 18 110 20 92 22 -81 22 60 21 -43 19 89 19 84 20 46 21 36 21 53 19 -54 16 112 14 115 12 0 11 87 10 -59 9 -71 9 126 9 -92 7 88 5 -89 3 104 5 75 7 14 9 -125 9 123 9 47 9 -11 7 -62 6 112 6 -20 6 0 8 -100 8 72 8 44 7 -6 4 88 3 -128 3 118 4 35 4 7 3 -84 1 -119 0 62 -1 114 -3 26 -4 -53 -5 32 -4 -8 -6 -73 -8 -102 -10 -24 -12 -90 -12 51 -11 -14 -11 -101 -11 -94 -12 -6 -14 42 -15 -48 -17 -96 -18 -45 -20 35 -20 -37 -21 -56 -23 -80 -25 -100 -27 114 -29 11 -28 53 -27 -108 -28 -59 -29 103 -30 -43 -32 -66 -33 -42 -34 118 -33 -86 -32 -25 -30 27 -27 126 -26 -32 -26 -92 -26 -74 -25 -12 -23 74 -20 110 -19 74 -20 18 -21 0 -22 -54 -23 51 -23 36 -23 42 -22 59 -21 3 -22 70 -24 -95 -25 -5 -25 -21 -24 108 -23 -43 -23 -50 -23 -58 -24 50 -24 51 -23 -50 -23 -6 -22 16 -20 12 -19 -72 -18 33 -17 112 -18 -89 -18 -105 -16 -12 -14 71 -11 12 -9 -120 -8 37 -6 -90 -5 -120 -3 102 -2 84 0 83 2 5 4 -114 5 -109 6 -80 6 37 7 48 9 64 11 67 13 -16 14 109 14 82 14 -12 15 38 17 65 18 -44 19 -37 21 -38 23 -80 24 76 24 106 23 43 23 18 24 -12 24 23 25 -63 23 -104 21 0 20 38 19 75 18 -66 17 107 17 -96 17 65 18 67 18 95 17 -11 15 57 16 79 18 42 20 74 21 70 22 67 23 4 23 -78 22 28 23 -12 23 -26 24 -100 25 9 26 -8 25 58 25 -4 23 120 23 80 24 -5 23 39 23 64 22 10 22 -91 21 87 20 49 19 -128 18 -54 17 48 16 -33 13 -88 11 -89 9 61 9 40 9 52 9 -68 8 -102 7 8 6 -9 3 44 2 115 0 -87 -2 -3 -4 68 -4 77 -6 66 -8 35 -10 -3 -13 -98 -14 76 -14 -52 -15 -65 -16 -16 -17 126 -18 -64 -19 -69 -20 -110 -20 21 -19 101 -19 -63 -18 -52 -17 105 -16 38 -16 83 -16 -12 -15 85 -13 -16 -13 -86 -13 5 -14 -85 -16 35 -16 60 -14 83 -12 91 -10 -50 -9 118 -8 -24 -8 52 -7 64 -6 85 -4 103 -2 73 0 -19 1 9 2 -18 1 18 3 50 5 76 7 121 9 71 10 -117 9 102 10 -90 11 117 12 25 14 63 16 -117 18 -119 20 -1 20 -82 19 -121 18 55 18 87 19 111 20 -102 20 -28 18 -36 16 -61 14 0 13 -87 11 55 11 -13 10 53 11 80 11 -110 9 104 7 15 6 91 8 -77 10 -1 12 2 14 -127 14 -79 14 -105 13 -108 12 -112 12 63 13 -98 14 92 15 50 15 42 14 20 12 -67 10 27 11 21 12 -35 11 -3 10 -4 9 73 9 19 8 48 6 -19 4 -19 4 -96 5 -64 4 -73 2 -93 0 -27 -2 97 -2 -52 -2 95 -1 -32 -2 -92 -3 -87 -5 115 -7 -94 -9 39 -10 -28 -13 65 -13 47 -13 21 -15 -42 -18 120 -20 98 -22 -73 -22 -30 -21 34 -21 45 -22 -112 -24 -111 -26 11 -27 -77 -29 -16 -29 -24 -28 -12 -26 33 -23 56 -22 102 -22 -73 -23 83 -22 85 -20 74 -18 35 -17 -60 -19 37 -20 -106 -22 -59 -23 -118 -24 -32 -25 127 -24 92 -23 -67 -25 -109 -27 -93 -28 -99 -28 35 -27 80 -27 108 -27 25 -27 -19 -29 39 -29 -30 -29 -18 -29 -81 -28 102 -27 77 -26 -4 -25 -4 -25 -49 -26 -92 -26 75 -24 83 -22 72 -20 -71 -19 50 -17 -46 -16 79 -14 8 -12 -100 -12 98 -10 94 -8 70 -6 -13 -5 26 -3 75 -3 -54 -3 -35 -1 23 2 53 4 3 6 -83 5 -27 5 -100 7 123 8 101 9 -39 10 29 13 101 15 127 16 62 16 120 15 98 15 122 16 -106 17 -3 17 -15 16 51 15 -2 13 91 13 -120 12 23 12 9 12 -98 12 -107 13 12 14 123 13 112 12 35 13 -114 15 -46 17 -124 19 19 21 -91 22 -33 22 -51 22 60 23 55 24 -123 25 -107 26 95 27 -87 27 50 27 56 26 10 26 -6 26 -86 26 54 26 -83 25 -31 25 -77 25 56 24 -20 22 101 22 2 22 -47 20 -54 18 -58 16 -63 14 47 14 -60 13 -106 13 -52 12 123 11 -44 9 -79 7 -107 5 66 3 34 1 49 -1 -83 -2 -86 -4 -86 -6 110 -8 55 -10 -84 -12 13 -12 70 -13 51 -14 103 -15 -42 -17 -74 -18 67 -19 -92 -20 -67 -20 -19 -20 118 -18 -108 -17 11 -16 -122 -17 81 -17 -97 -16 -94 -15 -19 -15 117 -15 -85 -17 1 -18 -85 -13 -2 -12 72 -10 -105 -9 102 -8 124 -8 67 -8 30 -8 -61 -8 9 -6 65 -5 81 -4 64 -3 -64 -4 28 -4 -91 -4 12 -2 98 -1 -6 0 94 1 -118 0 43 1 -107 1 -24 1 15 3 -16 4 -14 6 113 8 -3 8 -24 7 63 7 98 7 101 8 103 9 -20 9 -15 8 -18 7 -79 6 -71 5 1 5 10 5 111 5 19 6 -84 6 -60 5 76 4 -68 3 -30 5 10 8 43 10 -116 11 -120 12 48 13 -86 12 18 12 -102 12 120 13 -16 14 -92 15 120 15 -100 14 -27 12 33 12 -86 12 96 13 55 13 -72 12 66 12 74 12 109 11 28 10 33 9 -69 9 -34 10 -126 10 124 9 81 8 -110 7 52 7 11 8 -38 8 -3 8 81 8 -14 6 83 5 -50 3 -14 2 39 1 47 1 -83 1 84 0 -105 -2 110 -4 61 -5 31 -5 31 -4 115 -5 -123 -6 11 -7 81 -9 -54 -11 93 -12 17 -12 -125 -12 -87 -11 62 -9 -63 -9 -46 -9 -2 -10 5 -9 8 -8 -32 -8 -37 -8 109 -9 -119 -11 -65 -13 121 -14 -38 -16 -85 -17 -84 -17 -29 -17 3 -18 -17 -21 -26 -22 109 -22 -120 -22 68 -22 -54 -23 25 -23 20 -24 84 -25 -52 -25 51 -25 113 -25 -58 -25 123 -24 -52 -23 89 -23 -26 -25 52 -25 17 -24 41 -23 1 -22 114 -22 67 -21 -3 -21 -105 -20 95 -19 123 -19 120 -18 101 -17 93 -16 -1 -16 68 -15 2 -15 22 -15 81 -14 21 -12 120 -11 -76 -10 43 -10 100 -10 -74 -9 42 -8 -37 -8 -23 -7 -52 -5 -62 -3 -68 -2 -68 -2 112 -2 -45 -2 55 0 108 1 68 2 9 2 73 1 -20 0 -62 0 -88 0 -40 0 100 1 112 2 110 3 91 4 78 4 17 4 52 5 -97 7 -63 9 -102 11 96 13 43 15 -47 15 91 16 6 17 70 18 -46 19 -43 20 -119 21 -29 21 -79 21 56 21 -117 21 114 22 83 22 116 22 81 22 -51 22 -51 22 -60 21 -4 20 16 21 82 21 -5 20 -3 19 8 19 18 18 5 18 -63 17 -12 17 125 17 -76 16 -93 15 69 14 -2 12 -57 10 115 9 -43 7 -69 7 6 6 -75 4 1 3 96 1 71 0 -104 -1 -62 -2 -79 -3 -91 -4 36 -5 -60 -7 78 -8 64 -9 -89 -10 82 -10 44 -9 -27 -9 -2 -9 101 -9 -14 -10 92 -9 -98 -9 44 -9 36 -10 30 -12 60 -14 106 -9 -22 -9 91 -8 -27 -8 7 -7 -127 -8 -108 -9 -10 -10 47 -9 -104 -9 -23 -9 28 -8 74 -8 36 -9 -16 -11 -44 -11 119 -10 -3 -10 -11 -9 -23 -9 -3 -10 96 -9 -25 -10 -74 -10 89 -9 -15 -8 -91 -6 -99 -5 63 -4 106 -5 72 -5 -29 -5 -57 -4 -76 -3 -104 -2 98 -2 116 -2 33 -2 0 -2 -15 -3 126 -2 -107 -1 -95 0 -64 1 -70 1 0 1 69 1 66 3 56 5 43 7 -16 8 111 10 -105 11 -82 11 -120 11 -92 12 -74 13 72 15 -15 15 -61 15 20 15 -62 13 -101 13 82 14 -64 14 -89 14 -114 14 -86 14 122 15 -5 14 69 14 -105 13 -45 14 109 16 -99 16 -86 16 118 16 -58 16 -112 16 -39 17 -24 18 -73 19 -92 19 -21 18 -21 17 -73 16 -124 16 57 15 -9 15 14 17 -126 16 78 15 94 13 31 13 -122 12 89 13 -62 12 -36 11 -122 10 22 9 -114 7 11 6 45 5 17 5 68 5 55 6 28 6 17 6 21 5 125 4 114 4 26 4 43 3 -84 1 127 -1 118 -3 -75 -5 -84 -7 -16 -9 72 -9 -49 -10 -86 -12 -81 -14 -118 -15 -104 -16 64 -16 -122 -17 107 -18 87 -19 124 -20 -63 -21 -14 -21 -84 -22 94 -22 76 -22 -53 -22 -72 -21 -53 -22 13 -23 -51 -25 -43 -25 -18 -25 -106 -25 -8 -26 23 -25 -34 -26 -122 -26 78 -26 -21 -27 18 -26 -32 -27 -38 -27 96 -27 -75 -28 -7 -29 -100 -29 -15 -29 56 -27 -43 -27 117 -26 -72 -27 -14 -27 -39 -26 -37 -26 81 -25 -15 -25 109 -23 11 -21 -28 -21 41 -20 94 -20 65 -19 -9 -18 71 -16 -107 -15 55 -14 -122 -14 15 -13 100 -13 15 -12 -22 -12 24 -10 -93 -9 -88 -8 18 -6 -110 -6 47 -5 -55 -4 52 -1 49 1 52 3 53 5 61 7 86 8 -123 9 111 10 -9 11 -58 13 -68 14 88 15 -60 15 -39 15 -22 15 -59 16 -93 17 -71 17 119 18 -63 18 -119 19 -70 19 42 19 -19 18 -90 19 -105 20 39 21 67 21 109 21 -106 21 23 22 -4 21 -107 22 119 22 62 22 -52 21 63 21 -37 20 -63 18 70 18 1 17 86 17 -12 15 94 15 58 14 56 13 -105 12 -41 11 -15 10 -30 9 -110 8 35 7 126 5 5 4 -127 2 44 1 73 0 107 0 -73 0 110 0 -65 -1 9 -1 -125 -2 -9 -3 -67 -4 27 -5 -42 -8 -71 -10 -100 -5 65 -5 -48 -6 -115 -6 -3 -7 -32 -8 70 -9 54 -10 -2 -11 -126 -11 -25 -12 53 -12 -97 -13 -34 -15 38 -16 100 -17 57 -17 -26 -18 49 -17 -76 -18 -70 -19 -38 -19 -128 -20 -53 -21 -31 -21 27 -19 108 -18 -48 -18 -126 -17 -8 -18 95 -17 109 -16 40 -15 -13 -15 46 -13 -62 -13 -20 -12 -118 -11 68 -10 -31 -10 -20 -9 -84 -7 21 -5 -82 -4 -114 -3 -100 -3 -74 -2 114 0 30 2 -53 3 -32 5 -44 7 111 9 36 10 115 10 25 12 82 13 -20 14 -127 15 84 15 -36 14 0 14 121 14 85 15 118 15 109 15 -67 15 109 16 -3 17 -29 17 -44 17 123 17 77 19 77 21 8 22 43 23 -11 23 83 25 73 25 -10 26 56 28 -83 29 53 30 45 30 -37 29 7 29 -127 29 -57 28 52 30 -39 31 36 32 -119 31 -23 29 -93 30 -106 29 49 30 -74 29 -29 28 -62 27 -83 26 54 25 -81 23 71 22 -99 21 -42 20 26 21 96 20 56 20 31 19 -18 17 -46 16 74 15 121 13 -5 11 -99 9 110 7 68 5 -24 2 -79 0 102 -1 65 -2 -17 -5 36 -6 -15 -8 -113 -9 -57 -10 -99 -11 -19 -13 -127 -14 -38 -15 46 -15 21 -15 45 -17 86 -18 -36 -19 31 -18 -100 -18 63 -19 73 -21 -121 -23 -74 -24 -52 -25 68 -26 -101 -28 3 -28 -42 -30 -114 -31 86 -32 119 -33 -61 -34 112 -35 105 -36 -44 -38 63 -39 15 -40 68 -41 -83 -42 102 -41 51 -41 46 -41 67 -42 124 -42 -20 -42 122 -42 -82 -42 -40 -42 -37 -41 12 -39 -71 -39 65 -38 -10 -38 81 -36 69 -34 -95 -33 87 -31 -45 -30 48 -28 -100 -27 109 -26 -40 -25 87 -23 28 -21 20 -19 19 -18 -21 -17 -12 -16 103 -14 104 -12 -74 -10 118 -8 -117 -6 -80 -4 -35 -2 93 0 38 2 69 3 4 5 1 7 -34 7 90 8 -45 8 50 9 -52 9 40 11 -14 11 60 12 -111 13 70 14 81 15 -77 15 -93 15 -10 15 78 17 -26 18 88 20 -111 21 -36 22 39 24 48 25 65 25 58 26 120 26 -44 26 8 27 86 27 -37 27 -7 25 95 26 -126 25 69 26 71 25 117 25 -15 24 -101 24 125 24 -77 23 -55 22 -55 21 67 20 -10 18 32 17 -75 15 -53 13 -57 11 95 10 -60 9 -96 9 -11 8 56 8 72 7 -44 5 127 4 -120 2 95 0 -12 -3 -76 -5 -77 -1 -95 -2 119 -3 -122 -4 105 -5 -29 -7 -39 -9 127 -10 -22 -11 -77 -12 86 -13 -17 -15 -70 -16 -98 -18 -99 -20 92 -21 -127 -22 121 -23 37 -23 81 -24 99 -25 69 -25 72 -27 50 -28 -54 -29 -108 -28 109 -27 70 -27 -11 -27 -71 -27 -113 -26 -24 -25 108 -24 6 -23 110 -22 -91 -21 -88 -19 9 -17 112 -16 -107 -15 -11 -14 29 -11 -76 -10 -111 -8 36 -6 -32 -6 -102 -4 -14 -3 52 -1 122 0 -93 2 -53 4 -93 6 -47 7 127 8 117 10 -79 11 43 13 -95 13 121 13 60 13 -36 12 -42 13 -66 14 -105 14 -98 14 66 15 98 16 116 18 -75 18 56 19 51 19 91 21 -125 23 -90 24 -96 26 52 28 92 30 122 30 85 32 -90 33 -121 35 -119 36 29 37 106 37 0 37 6 38 -36 37 -65 39 -73 41 -73 42 -79 42 -128 41 1 43 -89 41 3 42 -83 41 -1 40 39 40 125 39 57 38 -44 36 22 35 0 34 114 32 23 32 -28 30 -89 30 -112 29 -10 27 5 26 -102 23 47 21 -41 19 -119 17 110 15 30 13 -77 10 72 8 -114 6 -17 4 -82 2 58 1 24 0 118 -2 96 -3 -15 -5 -24 -7 82 -8 -23 -9 90 -9 3 -9 -67 -12 -126 -13 -71 -14 -64 -14 -48 -14 50 -15 60 -17 52 -19 -71 -21 3 -22 -104 -25 45 -27 5 -28 32 -30 37 -32 43 -34 -12 -36 -110 -37 100 -39 -107 -41 48 -43 -11 -46 125 -47 101 -48 15 -49 57 -49 85 -50 -63 -51 -60 -52 -9 -52 -12 -52 39 -52 28 -52 -36 -53 91 -52 16 -51 -122 -51 59 -50 79 -49 -15 -48 -21 -46 48 -44 23 -42 44 -40 84 -38 99 -36 -115 -35 126 -33 102 -31 -125 -29 -85 -27 -115 -26 -104 -24 -2 -23 9 -20 49 -18 45 -16 -115 -15 126 -13 -113 -11 -90 -9 92 -7 127 -5 -79 -4 117 -2 105 0 27 1 112 1 -24 1 125 2 -126 3 44 5 -47 5 66 6 -6 7 -5 8 40 10 -87 10 12 11 -43 11 -106 13 -103 15 -82 17 -63 19 -23 21 17 24 121 25 -82 25 -28 26 108 27 65 28 1 29 7 30 76 31 -56 29 -22 30 125 30 -115 31 -1 30 -44 31 -23 31 50 32 -120 32 -53 31 -14 30 24 30 -119 28 121 27 -90 25 106 24 87 22 -20 19 50 18 1 17 125 16 -114 15 -41 14 -54 13 -85 11 -58 9 91 7 -16 4 -97 2 120 0 elektroid-3.2.3/test/res/connectors/microfreak.mfwz000066400000000000000000000513461500236517400224710ustar00rootroot00000000000000PKX1t@R0_sampleUT ffux mͮL5*|ߙ=D)_Б8R V#q8ok?9߻\v:3>ZY_?ӿ??os=W?^OW\W2}uغw?Ԫrxw'): }{yOEr_sO}xq#|~=Jw%>5Sw;ksřgի_Ux?z%7؋c sVexT.k]u1X3 Y*ťN!L.1xd︷wxz:GcxStu8c)b\kә'V5^GL\O]o=&.\m ޑ1^;8.D߻7??}3';fgךG d5W|FϾrCߵӼާ|'X&gR㏱-NKW{p♾36V{,=Q+wkw^1gL~zx>z%̋^:xN{}mKzo# |*\8v4t1S/KqSɿFDcXyez__L۩\>W5BUXnt $M#,ɮrGɦ>Ϋ|$ZGObD3):=I\\I7`~x۱w1ly, , ˶j~X[6Cs™&s6_^}kipD, q<QFpUT$[ߋ(^r^Ѹ0gۺ.oobw%ȓo(+Z,ϰUзF@AZ0/P׀fv#)ZJB# '3+kQ,whם$Jr AX嚈Ԩ_h{,r>䎽z5('!EI6V ?mk(;ZDzJ#޵BVE'^:ۮFhذH}lmΈHOM4aȧ%;miwxgRJӑAh˹@Wg(X+4 U_k*TNV-*tE㯡oB`b)RI*?TFƏy}ǘ Z R4<2جU{k8lg18MSASwXv=?K8sdњPft=Y̕TĽ?QfF.Nq~V]iHZ1_QSA?ZFw}%f6f21Xbԑfx!xolofV 4^~\߃?XtO| TT! hZS6*2n SSk!.uф&{>ǾIVxȶpo;xHᝏYOj:N"I0;{cޤ}lb.&!HABj<BO7aMY\ܔ|sDu™(í򛏲d o*ǢuXyfq +9(E6"M6K&Y R|ýh$;#$ D0@)!NW% wi\${}g4Rlέ~(OSօPB#V`|A/Ď|M [.0W_2z;Dn6ܑֆXM*I2 'V6'/#:Ib8L]#kdʉ3r[v˨V^Qe0L*YZ>x90->&dzM =MU¤nqEhkxfa[POT"u0i ]IN#Ɣz$k[+ZJEjTMQ4%_ə)].`yLw+'NI^i,.ƀTY-yL*OzNFp/A0 |炒IINL:fU\!cn8uL,^W؁»P.-(w5)1eA":UunoaǷ ;A|ӥe $@-7,U退6@&c_)|%Q: RpXEy em; 3/( !V h#Fhk卋VXqxzb:*;x^ jBH~l;*6swI+u2='4 VcþDtrw}x}a5 F (ǪFna?覇!xPL< Hk.{QH qߌFb2n͌)@\tғ,Btz 69Gxl麔ŽWU dh2z.cu JC5mQt%AIxc7lBYCDyU|apܪBsTUv E ]\);A8J= L`X]+3o: |XYm2$nQF]ఆv%6ry|\ߠܜ:6I!y2 "/qK͠ @ǰbȚi Iim+Rf nqOK,*ߙf>=Q0swB5N[wfZYx8 4{zT3B7y$&;!o'fn;L񔼪7FTS.4T0DD9~Bx*_+Ҙ 7^"'V7Jc+2R_V6U'@ /\WjYlVd="Y3R|h O}zm[I#GvYxQRa+wQoo)_֖%+^}ݶ!zٮy`uiTwDUl4(6#́J0e’fL:UAh@#w,n@rQ$s樒Z;Fqx折a3Rv6Е% ]dC^d4-|T^)B lA1QJq3bkǨwA}CebܺMWd Rw%~2$֒GlrK' H%φl; _a@UDW;o9V11_H0myXH4/?ͭ((HAQ5g)G%95utHŇgd.3/{P6@9]0yjW.dADijΕaTbFW]I$|R.q}-H)XKoK\aqJtx4德GJ-lF~3e:Hؼ3s;-W2e2 GkC[ULJ0m#>md @ :i@R3tV#؍mQ-Rsdh%CsduH_TP>Z$u\EVLOV4gxRX O* (/w,}rt8OBo#_.NQ `Kܷ%s _"VbI3D d+7KoPS).t"oCqg veAцzyPK ){`r U[BN}!7OF< r4Y4$E +<x{vr%&x@_d[H&,h~Z 639 V=v>(,O%kMfW~%K>4d _TPJi6?,O{3xD0#CprxNzw2Dz Ҵ%Pϗ3ly5OJ}\ۣ4jpqv S`$*ᆲA/O^$[, b*p a-A.Yz9!yC_|n00TeKK,؅,W@*_'[IBdJT{TY[%Ut4%=8<)nMDV_̙:Sf} o|8RZUcXR2=nN"{ ^v{ |.#@EZ'7-h|35#;`z_/5ʟ@΃uI(HJFw)% F2_㰡`!RWo`;纲yEVbpQ-QԬ͊)1޻Z*K+YM!42}1E$̲_r؝WTק U/63iWD<`9$Zjf&1Y,K. M%_t~̕K6|&[mB~ ` 3Emg_-)I\TieB6̸4ioR#TĊf>;gD7uL">fN_*|8ӏḢE"\|RI$&-N(U¤#*B-{R`y-Yұ?R "h@6,z­Ը&+\,Т@# JM|(WdnmZuUe/͝P_Hs!gnVٞH~h=(L9-Eq&E D q!\F2A;oD@$dE.L= ='"mK%KuxLH}e"݈/컄uVA9̠"B14J(E?vDIk'ťoqXU*ѽ;eEtiGVw/但Mx>i65s.]JQ6*3(*ŹL8͢6p6|b9 S1EtU`床AxQ9BpYsZCRmOŐy,A%__B BׄBQ1"Ex  I\FXqeP`G '2vQx28ML-(s$7m[ie]MP 쏡724D7]+Q[m&$|eUVd?՜Ķ !vnKRʯ.ܱT; M5WpɢG5Q&n {mu[lhLԛ2f15#$D=u{8ęKlXf)8NeTYT4Ma$ԗ,Q`̷1 & o\qkjnCBo*r5lVpQѣG6z\Xu-\tPW7}Jك@#-fWbW)+*d@\X9Vrhb2 <%39(rn#aGhU81@/?4kKYa}ޚA3jMOz:N#fdOFx4"D܅lD0ZbqX^nk$ٌǡ[3d\Mi0PR]QSXƙPAZ./CJx>ITq+^x 9_5pє|b{MH[MYPUa)y+XWBlu8ǠS_)4s;h.RydlPAM`%t2xW{t}ϛW# ;%0qWC Wbv@;e3Q PXyFBV`zfpD=xC1t_4s-twRB4_(#WRz 6Jj3J7ph ]BlHԿޅ.{02wXFzab]iXe:Sȼ #1!wK]MVa$:R5L$jp|cTM/* V*&ZiMVyÂU0 pBTͺ *7V59&|g<7̆dc2 TgI ZSzH?$,+8iibMPx oGa96SՃYjI")H'uTOd4 ;=n ݆2Qw 0ej?Zy!@G}t16`*5 I -WEOƖׁ,O B"nL=mZ.33XQ Bu`~E b*aQE=6¦\1-3xc[ٵ16PgfO Z9(Y (|tgrXgMX,|D\׻9T=n Ū:\/ ^PEp?)vT+~ҀsC 7i *cׯ? K%H^:]B*4 PbۄWAn ,ǟŐYI [ :uAeN*d.|U\&U9)T;QՀ\s䤶?`TEC%ݬrlUMpd%0RŦ MeȮcof2,}йZ3Uk -%\%_\.=j R]/ױBF >8P#EiϺX/W9]h%5>6!qƼT/!]_j$}rhMdg]`FtaYs:U‰IOYJ 9gCzGFAm#tnϧYlF^etE J9x1Yŏ5+o)g841̟jˢJW<s ېR4pqO q{#.䓝Xn,0>_֒eؑ,{$QU*™qe-_xORAeh~.TvYΕmf$U#3ZW Yu4PSH?( Z3keS*k"AJtM_0 >O@y]w|1yƄ~=BD6 ~AZu D,ɕ!bE[R0Q͔S*r &1Y:6_-yqTlNoMܪadZeyMC*l؎`Q?q1U0$%dP˘]vj>_-#7=܍otO7GH6Vh#Hxfv*,.lp?5VY S~ȹ) vjƻc2=]t1XWz"3I! 4{ܨ5%2\@XŅvsb]ef7ZtO)af/ 'iÓ}$1v G%6 Pꀟa&ot1 qR>2e[9tgg*%(6dVJIs;W4@F+#C(fBe8dd#"2JyקsϑgjwZXz,ɏ/ۋrj|LFDC ȟ\ 9=d)n;wrfiow~u2 J"%F vfg^B-H($涻7fM@h~w&f 䋕3|KL'Bc׆c`k6OgV.:VN&RfH GR2dCY"ۖ 5}>MmNO{+os\:|:2&8MXw}EHmDL.ns m5/K&{i2qi o=GqhMFf \+;ӟ8HIWE)4-78ckA-7(BStJW͢BZ.[wgFiA'͹H@?*"bF$"m7r[wщXtjԔ-;0ZZT& k\].Uxbw//*7dˡECl*q J-DlA^,ࣸAbb0\fgxXO'GICZR\Hvct?+nBnJfKټJYlxxje !rHx?X:9rGa)B V 4qx<-vU=c] 28˚tXXip>qqfov z(%9? 2|y+rO[>=^oToUO][0YXQdꞈ=]N}&瑻!!3~R$TM[Yso = 1\+W\Բ.KZAHbDX VQ/lxo #qwvIE F$E[rG+2[R"CSGFkX\oܣ:`CU(ie/Bw7tGs$jL[JI~E4[VmLu"QL?! l!9;ݩ;qdjiURm0Cl'LJVPzҶW៸\BRm+_DeFws@e'0F[R.8om#0䒘#a}Waн0gm`a$].e>;[WeuhWw{RA*:w*6VT BP27sAZ T(k&b"IQ=X{qឥZY?hയx"b~01Sz}N{uE%IVPSs&fٻ1yҲj&/'*vKT* Je;&Rj/IhN,7&}TNNu#>b*+ wrڣځ16(D> ZA8\u=X{ ȭ6vY~H&_O#xjOIbER[& QrfXhz=ִk+C xEE.X 8Ge'YZ!8tł.{ϒ*S|.f RdjO HG lm@RCnH%͠_//:pt9FD&zhv'jymfcc!Mvb\~ۯ s4apLX?q%.0*QrlXmۯ([n.GnAfle0L{QP.r6HJaI5{3=, t'WfP.RƟ/SŚe:12iЯll=[`"r~º ,6qEf o)%wH?6g pQت3?28s+oRkd:nk}ȓ^UIխb蓫13n9 ܓ_\YaS(IOmB:. SF%ҺQ'eppll*KI8:? +Z?!DYEfCr9rm$dS6ɂ8pE/%#p b"A!&f,)Z?7>+u&:vY_ Tq<6$W*e&hvMAI4ȆۚA׍C`Qw̳ HLflNތ}gWyЯ?{zDG荆l-ҺE70G\B><̍G?ه WXHBN,En֐gzR,6/{>~ll6U4Q>ve8(3$2-жj7D5qN%%DMm7c!ħpTaF0C^ e5[Zt"+,J0Q$Rr-#3I*de{@wiI@/X-f,B@ Me?9'G?+(T ,~fcTBơ访]VC | L m "˶KjjYм>>AN7?@y}_UK!Z{8,W4s"qS5K{9zLp?*^]H5. q`,탸R`};տ5]Ej)T#5?HNV(͉ȯ?Ii1;1:l4zT,YI>u տ_nlaA4]t}&\ GWJm;x޹'OP'IWOal?wVqJoE9躾kۀ&@_52:R8ܿ=%xd>(b+ 5}u*/B;Xlt ԍ@B:ǬUE*/s*b M Sg;)kH f&-$>,,ƮeX<*DeoA*Yٍ|;$i:Jp!GPc-/8+5έD>?}rhM}* KX/L-'Aюvs-KKe%NCTZ$45㾧ln.{U\pukKRmU8Ϛ3o}ݱ- qצ5ri N:QRد^ޔ]N[q&\-1ݠ8+N@szY]B07PAr9{ɕʹ{ :K+$[ʏ\FN+Dwr'czYfך16aDp%Wm?P$l]<:f@Zܺẓh6B;kNRe=:_7 @z o*CXFҮDmʹci1MXjylUH8;HtRd^A#L}id8Ӿѫd[YuJ0<L.p+[uK`X ҥ#y¨٭@]Mq {Y7nkO#\gB&^)X"q֑nw'?|Y]+WClM)w#>20n6;)x*dtUb 5\Jls Rn28$$$?La و,ovŘ8#]ۛUg7xy{26ߺ!V: b<.Id˕ھFɘM͏~_rApb@M&T?^~3Ҧ.C$>#MQ;!Q"-)DDo!}T xBj,/wqM${|T9mm̙YY)=ȣn+.g5^j"޲QLW:ݤ=.UV.*>{BwKP68cIa;X> iRΪ8@(xYdUkiqyJcXQj:piW>zx_G "-T UieESLK+[ݹ<@<`Ǘ)Nq;^,gGJ!u$X8V ܙ.Ib?Li-sJvˁ S5h$ kdIi%F]CDҀBZiyf*;vi3/Qdž|]lgT3[\e)qH҄BMD&uzt"3z.sfjA L )k u<[u.cSOoN0#Ѱ4Q`SpTʆ~g[qy~jOXI_^=VXqc^v?,ph+tkKq ‰/15}9wجjiVKo٪);[6.\U4ɕI\)e}7|y)?Oȩ\x@(;iw%&t}r!_`e8Nnކ+KUTع9MuRFE.kPPxN%-Nvkx^3tnAs3# z'H)ujSy "UhIkYjuzudmqѩcfļ#B%rMt RTgdkoJs =YaO fTmDyJtx Gۤ٫rb]'~J.%K(~ڔ' ֑mk -`ueh4K!VB?L *s% @6'L!`rɮ59`%_sx/uP)ŀƒ+DNs s\= cUmdvODy§W|OfV'%oF跑I͔f>=]-5vL414m !>-LP=& NYQ;mٹ\Rm"JR%}3jA 7l/' o})uaW @1ZR)L} kY7uE)X`:RS @~}j\7S5}\y ú2! U(=Ǝ,$6yΖVHqڬ,012ѓb%V3E׼1:ʔJQfEy d_ƊVFI)wղ+.zUnBDz3t :b=WnTpMtK2W\LJ&챮}]|l+<ʓ{I8DzUɌgټ:83T`'i,얔JOf,yMK_upK4R>8peMӤ+z4r0!/ hg縃AK\CeL,w߶_*MYda[jϱ,842X*H|l(oISlUsہƳpҲL!8=(4PY˂E?az569KR26]( ]\#8HSqPt:!Qsݹ5!,ey@t<oI2<4z`*0kRuKRmfETgnUrzhzy45W!ML!AxI;'{leMxuӶpئ"+cIZh-#5P X9:QHf6V"$=ѫCS :@v.J8Z[d$RhvuF =hM14-ڊX̎yl.ꤾZ7Sϛ:IV"@gO/Nlz~c߮f!u{1dgb!,RJRRIÜn~4a$t8ӍfƗ>wAnﲶzQuG"_:V.C l((qMwʵu]Fdj8$k~ _ԝ[@pߴ(A '˯Cwn0gOK SmM5|^\ dR*j_wHp2=]wf6xfQfܶYi`EQ&MBֻ&OYSй A$:cu绲pwIt6r7cSZ-:7TI`2fJ\yGe~TU*r"=k(h,) 6uh}4-,lr&GpO _׏tS}KdZ + *PKX1t@R0_sampleUTfux PKNRelektroid-3.2.3/test/res/connectors/microfreak_ppreset.data000066400000000000000000000341331500236517400241540ustar00rootroot0000000000000022 serialization::archive 10 0 4 3 174 4 Chip 7 0 0 18 000000000000000000 0 0 16 4672 0 35 86 67 79 68 84 121 16 112 101 99 12 43 10 70 0 80 97 114 97 109 49 99 3 110 63 78 70 80 97 114 16 97 109 50 99 110 0 0 0 70 80 97 114 97 109 51 2 99 110 0 0 71 66 101 0 110 100 82 110 103 99 24 0 0 64 64 35 86 67 70 0 68 84 121 112 101 99 2 0 0 0 70 67 117 116 111 16 102 102 99 0 44 25 68 0 82 101 115 111 99 0 0 0 0 64 35 69 71 49 68 0 77 111 100 101 99 2 0 0 0 71 82 105 115 101 76 0 118 108 99 0 0 0 71 0 82 105 115 101 83 108 112 4 99 0 127 63 71 70 97 0 108 108 76 118 108 99 0 0 117 24 68 72 111 108 100 0 99 0 0 0 71 70 97 0 108 108 83 108 112 99 0 0 0 0 70 65 109 111 117 16 110 116 99 0 127 127 64 0 35 75 98 100 69 71 108 0 105 100 101 99 0 0 0 0 70 79 99 116 97 118 101 0 99 6 0 64 69 86 101 0 108 111 99 99 1 0 0 0 68 72 111 108 100 99 1 0 0 0 70 71 108 77 111 0 100 101 99 2 0 0 71 0 80 114 101 115 65 109 112 0 99 10 0 0 64 35 65 0 114 112 70 69 110 97 98 0 108 101 99 1 0 0 69 0 82 97 110 103 101 99 3 0 0 0 67 68 105 118 99 2 10 25 89 68 82 97 116 8 101 99 0 96 46 69 83 0 119 105 110 103 99 25 0 0 0 68 83 121 110 99 99 0 1 0 0 69 83 112 105 8 99 101 99 110 0 0 68 32 68 105 99 101 99 110 0 0 0 67 68 105 114 99 3 0 85 85 69 83 101 113 79 8 110 99 1 127 127 64 35 0 76 70 79 69 83 104 97 16 112 101 99 5 76 76 67 32 68 105 118 99 12 42 106 0 68 82 97 116 101 99 0 0 86 80 68 83 121 110 99 0 99 1 0 0 70 82 101 0 116 114 105 103 99 2 0 0 64 64 35 69 71 50 68 64 77 111 100 101 99 1 127 0 127 70 65 116 116 97 99 0 107 99 0 0 0 70 68 0 101 99 82 101 108 99 0 1 39 62 71 83 117 115 116 0 97 105 110 99 0 71 87 0 70 76 101 103 97 116 111 0 99 1 0 0 64 35 71 0 101 110 71 80 97 114 97 0 102 111 110 99 1 0 0 0 71 80 111 108 121 67 110 8 116 99 1 125 127 71 80 0 114 115 116 86 111 108 99 0 24 0 64 70 86 111 108 48 117 109 101 99 102 126 127 0 64 35 83 121 115 71 80 0 114 115 101 116 73 68 99 0 0 0 0 71 80 114 115 0 101 116 66 116 99 0 0 0 0 68 83 97 118 101 99 0 0 0 0 71 85 116 105 0 108 105 116 121 99 0 0 0 0 64 35 77 97 116 70 0 77 97 116 69 110 99 99 0 0 0 0 70 77 97 116 0 66 116 110 99 0 0 0 0 71 65 115 115 105 103 110 0 49 99 0 2 5 71 65 0 115 115 105 103 110 50 99 0 0 3 9 71 65 115 115 0 105 103 110 51 99 0 4 0 9 64 35 67 111 49 67 96 69 71 49 99 0 97 122 0 67 69 71 50 99 0 0 0 0 67 76 70 79 99 0 0 1 32 67 88 112 114 99 0 0 0 0 67 75 101 121 0 99 0 0 0 64 35 67 0 111 50 67 69 71 49 99 0 0 0 0 67 69 71 50 0 99 0 0 0 67 76 70 0 79 99 0 0 0 67 88 0 112 114 99 0 0 0 67 0 75 101 121 99 0 0 0 0 64 35 67 111 51 67 69 0 71 49 99 0 0 0 67 0 69 71 50 99 0 0 0 0 67 76 70 79 99 0 0 0 0 67 88 112 114 99 0 0 0 0 67 75 101 121 99 0 0 0 0 64 35 67 111 0 52 67 69 71 49 99 0 0 0 0 67 69 71 50 99 2 0 90 78 67 76 70 79 0 99 0 0 0 67 88 112 0 114 99 0 0 0 67 75 0 101 121 99 0 0 0 64 0 35 67 111 53 67 69 71 0 49 99 0 0 0 67 69 0 71 50 99 0 0 0 67 0 76 70 79 99 0 0 0 0 67 88 112 114 99 0 0 0 0 67 75 101 121 99 0 1 95 93 64 35 67 111 54 0 67 69 71 49 99 0 0 0 0 67 69 71 50 99 0 0 0 0 67 76 70 79 99 0 0 0 0 67 88 112 114 0 99 0 0 0 67 75 101 0 121 99 0 0 0 64 35 0 67 111 55 67 69 71 49 0 99 0 0 0 67 69 71 0 50 99 0 0 0 67 76 0 70 79 99 0 0 0 67 0 88 112 114 99 0 0 0 0 67 75 101 121 99 0 0 0 0 64 35 83 121 65 64 0 35 83 101 113 70 76 101 64 110 103 116 104 99 60 59 0 59 71 88 105 99 101 82 0 115 116 99 1 0 0 71 0 71 97 116 101 76 101 110 0 99 80 0 64 71 83 109 0 111 111 116 104 49 99 1 1 127 127 71 83 109 111 111 0 116 104 50 99 1 0 0 0 71 83 109 111 111 116 104 0 51 99 1 0 0 71 83 0 109 111 111 116 104 52 99 0 1 0 0 64 32 111 116 0 104 52 99 1 0 0 64 126 32 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 63 127 127 127 127 127 127 24 7 127 127 127 61 0 0 0 0 0 0 0 0 1 0 0 28 0 24 127 127 127 70 0 0 0 0 0 0 0 0 1 112 0 0 0 36 127 127 127 0 77 0 0 0 0 0 0 64 0 1 0 0 0 24 127 3 127 127 79 0 0 0 0 0 0 0 0 1 0 0 0 14 24 127 127 127 76 0 0 0 0 0 0 0 0 1 0 56 0 0 24 127 127 127 73 0 0 0 0 0 0 0 0 96 1 0 0 0 36 127 127 1 127 53 0 0 0 0 0 0 0 0 1 0 0 0 24 7 127 127 127 73 0 0 0 0 0 0 0 0 1 0 0 28 0 24 127 127 127 76 0 0 0 0 0 0 0 0 1 112 0 0 0 24 127 127 127 0 79 0 0 0 0 0 0 64 0 1 0 0 0 36 127 3 127 127 75 0 0 0 0 0 0 0 0 1 0 0 0 14 24 127 127 127 84 0 0 0 0 0 0 0 0 1 0 56 0 0 24 127 127 127 69 0 0 0 0 0 0 0 0 96 1 0 0 0 24 127 127 1 127 84 0 0 0 0 0 0 0 0 1 0 0 0 36 7 127 127 127 76 0 0 0 0 0 0 0 0 1 0 0 28 0 24 127 127 127 75 0 0 0 0 0 0 0 0 1 112 0 0 0 26 127 127 127 0 76 0 0 0 0 0 0 64 0 1 0 0 0 26 127 3 127 127 84 0 0 0 0 0 0 0 0 1 0 0 0 14 38 127 127 127 68 0 0 0 0 0 0 0 0 1 0 56 0 0 26 127 127 127 71 0 0 0 0 0 0 0 0 96 1 0 0 0 26 127 127 1 127 76 0 0 0 0 0 0 0 0 1 0 0 0 26 7 127 127 127 69 0 0 0 0 0 0 0 0 1 0 0 28 0 38 127 127 127 76 0 0 0 0 0 0 0 0 1 112 0 0 0 26 127 127 127 0 64 0 0 0 0 0 0 64 0 1 0 0 0 33 127 3 127 127 79 0 0 0 0 0 0 0 0 1 0 0 0 14 33 127 127 127 61 0 0 0 0 0 0 0 0 1 0 56 0 0 48 127 127 127 61 0 0 0 0 0 0 0 0 96 1 0 0 0 33 127 127 1 127 73 0 0 0 0 0 0 0 0 1 0 0 0 33 7 127 127 127 78 0 0 0 0 0 0 0 0 1 0 0 28 0 33 127 127 127 82 0 0 0 0 0 0 0 0 1 112 0 0 0 48 127 127 127 0 71 0 0 0 0 0 0 64 0 1 0 0 0 33 127 3 127 127 85 0 0 0 0 0 0 0 0 1 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 126 0 127 127 127 127 127 127 3 127 127 50 32 0 1 0 72 0 0 0 37 0 24 127 3 127 127 82 0 0 0 0 0 0 0 0 1 0 0 0 14 36 127 127 127 38 0 0 0 0 0 0 0 0 1 0 56 0 0 24 127 127 127 88 0 0 0 0 0 0 0 0 96 1 0 0 0 36 127 127 1 127 50 0 0 0 0 0 0 0 0 1 0 0 0 24 7 127 127 127 86 0 0 0 0 0 0 0 0 1 0 0 28 0 36 127 127 127 56 0 0 0 0 0 0 0 0 1 112 0 0 0 24 127 127 127 0 73 0 0 0 0 0 0 64 0 1 0 0 0 36 127 3 127 127 47 0 0 0 0 0 0 0 0 1 0 0 0 14 24 127 127 127 73 0 0 0 0 0 0 0 0 1 0 56 0 0 36 127 127 127 53 0 0 0 0 0 0 0 0 96 1 0 0 0 24 127 127 1 127 83 0 0 0 0 0 0 0 0 1 0 0 0 36 7 127 127 127 46 0 0 0 0 0 0 0 0 1 0 0 28 0 24 127 127 127 76 0 0 0 0 0 0 0 0 1 112 0 0 0 36 127 127 127 0 55 0 0 0 0 0 0 64 0 1 0 0 0 24 127 3 127 127 58 0 0 0 0 0 0 0 0 1 0 0 0 14 36 127 127 127 55 0 0 0 0 0 0 0 0 1 0 56 0 0 26 127 127 127 76 0 0 0 0 0 0 0 0 96 1 0 0 0 38 127 127 1 127 49 0 0 0 0 0 0 0 0 1 0 0 0 26 7 127 127 127 70 0 0 0 0 0 0 0 0 1 0 0 28 0 38 127 127 127 52 0 0 0 0 0 0 0 0 1 112 0 0 0 26 127 127 127 0 76 0 0 0 0 0 0 64 0 1 0 0 0 38 127 3 127 127 65 0 0 0 0 0 0 0 0 1 0 0 0 14 26 127 127 127 69 0 0 0 0 0 0 0 0 1 0 56 0 0 38 127 127 127 60 0 0 0 0 0 0 0 0 96 1 0 0 0 33 127 127 1 127 76 0 0 0 0 0 0 0 0 1 0 0 0 48 7 127 127 127 60 0 0 0 0 0 0 0 0 1 0 0 28 0 33 127 127 127 62 0 0 0 0 0 0 0 0 1 112 0 0 0 48 127 127 127 0 61 0 0 0 0 0 0 64 0 1 0 0 0 33 127 3 127 127 76 0 0 0 0 0 0 0 0 1 0 0 0 14 48 127 127 127 76 0 0 0 0 0 0 0 0 1 0 56 0 0 33 127 127 127 57 0 0 0 0 0 0 0 0 96 1 0 0 0 48 127 127 1 127 73 0 0 0 0 0 64 0 0 1 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 127 1 127 50 32 1 0 0 0 4 0 0 37 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 elektroid-3.2.3/test/res/connectors/microfreak_ppreset.data.back000066400000000000000000000341371500236517400250570ustar00rootroot0000000000000022 serialization::archive 10 0 4 3 174 8 New Name 7 0 0 18 000000000000000000 0 0 16 4672 0 35 86 67 79 68 84 121 16 112 101 99 12 43 10 70 0 80 97 114 97 109 49 99 3 110 63 78 70 80 97 114 16 97 109 50 99 110 0 0 0 70 80 97 114 97 109 51 2 99 110 0 0 71 66 101 0 110 100 82 110 103 99 24 0 0 64 64 35 86 67 70 0 68 84 121 112 101 99 2 0 0 0 70 67 117 116 111 16 102 102 99 0 44 25 68 0 82 101 115 111 99 0 0 0 0 64 35 69 71 49 68 0 77 111 100 101 99 2 0 0 0 71 82 105 115 101 76 0 118 108 99 0 0 0 71 0 82 105 115 101 83 108 112 4 99 0 127 63 71 70 97 0 108 108 76 118 108 99 0 0 117 24 68 72 111 108 100 0 99 0 0 0 71 70 97 0 108 108 83 108 112 99 0 0 0 0 70 65 109 111 117 16 110 116 99 0 127 127 64 0 35 75 98 100 69 71 108 0 105 100 101 99 0 0 0 0 70 79 99 116 97 118 101 0 99 6 0 64 69 86 101 0 108 111 99 99 1 0 0 0 68 72 111 108 100 99 1 0 0 0 70 71 108 77 111 0 100 101 99 2 0 0 71 0 80 114 101 115 65 109 112 0 99 10 0 0 64 35 65 0 114 112 70 69 110 97 98 0 108 101 99 1 0 0 69 0 82 97 110 103 101 99 3 0 0 0 67 68 105 118 99 2 10 25 89 68 82 97 116 8 101 99 0 96 46 69 83 0 119 105 110 103 99 25 0 0 0 68 83 121 110 99 99 0 1 0 0 69 83 112 105 8 99 101 99 110 0 0 68 32 68 105 99 101 99 110 0 0 0 67 68 105 114 99 3 0 85 85 69 83 101 113 79 8 110 99 1 127 127 64 35 0 76 70 79 69 83 104 97 16 112 101 99 5 76 76 67 32 68 105 118 99 12 42 106 0 68 82 97 116 101 99 0 0 86 80 68 83 121 110 99 0 99 1 0 0 70 82 101 0 116 114 105 103 99 2 0 0 64 64 35 69 71 50 68 64 77 111 100 101 99 1 127 0 127 70 65 116 116 97 99 0 107 99 0 0 0 70 68 0 101 99 82 101 108 99 0 1 39 62 71 83 117 115 116 0 97 105 110 99 0 71 87 0 70 76 101 103 97 116 111 0 99 1 0 0 64 35 71 0 101 110 71 80 97 114 97 0 102 111 110 99 1 0 0 0 71 80 111 108 121 67 110 8 116 99 1 125 127 71 80 0 114 115 116 86 111 108 99 0 24 0 64 70 86 111 108 48 117 109 101 99 102 126 127 0 64 35 83 121 115 71 80 0 114 115 101 116 73 68 99 0 0 0 0 71 80 114 115 0 101 116 66 116 99 0 0 0 0 68 83 97 118 101 99 0 0 0 0 71 85 116 105 0 108 105 116 121 99 0 0 0 0 64 35 77 97 116 70 0 77 97 116 69 110 99 99 0 0 0 0 70 77 97 116 0 66 116 110 99 0 0 0 0 71 65 115 115 105 103 110 0 49 99 0 2 5 71 65 0 115 115 105 103 110 50 99 0 0 3 9 71 65 115 115 0 105 103 110 51 99 0 4 0 9 64 35 67 111 49 67 96 69 71 49 99 0 97 122 0 67 69 71 50 99 0 0 0 0 67 76 70 79 99 0 0 1 32 67 88 112 114 99 0 0 0 0 67 75 101 121 0 99 0 0 0 64 35 67 0 111 50 67 69 71 49 99 0 0 0 0 67 69 71 50 0 99 0 0 0 67 76 70 0 79 99 0 0 0 67 88 0 112 114 99 0 0 0 67 0 75 101 121 99 0 0 0 0 64 35 67 111 51 67 69 0 71 49 99 0 0 0 67 0 69 71 50 99 0 0 0 0 67 76 70 79 99 0 0 0 0 67 88 112 114 99 0 0 0 0 67 75 101 121 99 0 0 0 0 64 35 67 111 0 52 67 69 71 49 99 0 0 0 0 67 69 71 50 99 2 0 90 78 67 76 70 79 0 99 0 0 0 67 88 112 0 114 99 0 0 0 67 75 0 101 121 99 0 0 0 64 0 35 67 111 53 67 69 71 0 49 99 0 0 0 67 69 0 71 50 99 0 0 0 67 0 76 70 79 99 0 0 0 0 67 88 112 114 99 0 0 0 0 67 75 101 121 99 0 1 95 93 64 35 67 111 54 0 67 69 71 49 99 0 0 0 0 67 69 71 50 99 0 0 0 0 67 76 70 79 99 0 0 0 0 67 88 112 114 0 99 0 0 0 67 75 101 0 121 99 0 0 0 64 35 0 67 111 55 67 69 71 49 0 99 0 0 0 67 69 71 0 50 99 0 0 0 67 76 0 70 79 99 0 0 0 67 0 88 112 114 99 0 0 0 0 67 75 101 121 99 0 0 0 0 64 35 83 121 65 64 0 35 83 101 113 70 76 101 64 110 103 116 104 99 60 59 0 59 71 88 105 99 101 82 0 115 116 99 1 0 0 71 0 71 97 116 101 76 101 110 0 99 80 0 64 71 83 109 0 111 111 116 104 49 99 1 1 127 127 71 83 109 111 111 0 116 104 50 99 1 0 0 0 71 83 109 111 111 116 104 0 51 99 1 0 0 71 83 0 109 111 111 116 104 52 99 0 1 0 0 64 32 111 116 0 104 52 99 1 0 0 64 126 32 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 63 127 127 127 127 127 127 24 7 127 127 127 61 0 0 0 0 0 0 0 0 1 0 0 28 0 24 127 127 127 70 0 0 0 0 0 0 0 0 1 112 0 0 0 36 127 127 127 0 77 0 0 0 0 0 0 64 0 1 0 0 0 24 127 3 127 127 79 0 0 0 0 0 0 0 0 1 0 0 0 14 24 127 127 127 76 0 0 0 0 0 0 0 0 1 0 56 0 0 24 127 127 127 73 0 0 0 0 0 0 0 0 96 1 0 0 0 36 127 127 1 127 53 0 0 0 0 0 0 0 0 1 0 0 0 24 7 127 127 127 73 0 0 0 0 0 0 0 0 1 0 0 28 0 24 127 127 127 76 0 0 0 0 0 0 0 0 1 112 0 0 0 24 127 127 127 0 79 0 0 0 0 0 0 64 0 1 0 0 0 36 127 3 127 127 75 0 0 0 0 0 0 0 0 1 0 0 0 14 24 127 127 127 84 0 0 0 0 0 0 0 0 1 0 56 0 0 24 127 127 127 69 0 0 0 0 0 0 0 0 96 1 0 0 0 24 127 127 1 127 84 0 0 0 0 0 0 0 0 1 0 0 0 36 7 127 127 127 76 0 0 0 0 0 0 0 0 1 0 0 28 0 24 127 127 127 75 0 0 0 0 0 0 0 0 1 112 0 0 0 26 127 127 127 0 76 0 0 0 0 0 0 64 0 1 0 0 0 26 127 3 127 127 84 0 0 0 0 0 0 0 0 1 0 0 0 14 38 127 127 127 68 0 0 0 0 0 0 0 0 1 0 56 0 0 26 127 127 127 71 0 0 0 0 0 0 0 0 96 1 0 0 0 26 127 127 1 127 76 0 0 0 0 0 0 0 0 1 0 0 0 26 7 127 127 127 69 0 0 0 0 0 0 0 0 1 0 0 28 0 38 127 127 127 76 0 0 0 0 0 0 0 0 1 112 0 0 0 26 127 127 127 0 64 0 0 0 0 0 0 64 0 1 0 0 0 33 127 3 127 127 79 0 0 0 0 0 0 0 0 1 0 0 0 14 33 127 127 127 61 0 0 0 0 0 0 0 0 1 0 56 0 0 48 127 127 127 61 0 0 0 0 0 0 0 0 96 1 0 0 0 33 127 127 1 127 73 0 0 0 0 0 0 0 0 1 0 0 0 33 7 127 127 127 78 0 0 0 0 0 0 0 0 1 0 0 28 0 33 127 127 127 82 0 0 0 0 0 0 0 0 1 112 0 0 0 48 127 127 127 0 71 0 0 0 0 0 0 64 0 1 0 0 0 33 127 3 127 127 85 0 0 0 0 0 0 0 0 1 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 126 0 127 127 127 127 127 127 3 127 127 50 32 0 1 0 72 0 0 0 37 0 24 127 3 127 127 82 0 0 0 0 0 0 0 0 1 0 0 0 14 36 127 127 127 38 0 0 0 0 0 0 0 0 1 0 56 0 0 24 127 127 127 88 0 0 0 0 0 0 0 0 96 1 0 0 0 36 127 127 1 127 50 0 0 0 0 0 0 0 0 1 0 0 0 24 7 127 127 127 86 0 0 0 0 0 0 0 0 1 0 0 28 0 36 127 127 127 56 0 0 0 0 0 0 0 0 1 112 0 0 0 24 127 127 127 0 73 0 0 0 0 0 0 64 0 1 0 0 0 36 127 3 127 127 47 0 0 0 0 0 0 0 0 1 0 0 0 14 24 127 127 127 73 0 0 0 0 0 0 0 0 1 0 56 0 0 36 127 127 127 53 0 0 0 0 0 0 0 0 96 1 0 0 0 24 127 127 1 127 83 0 0 0 0 0 0 0 0 1 0 0 0 36 7 127 127 127 46 0 0 0 0 0 0 0 0 1 0 0 28 0 24 127 127 127 76 0 0 0 0 0 0 0 0 1 112 0 0 0 36 127 127 127 0 55 0 0 0 0 0 0 64 0 1 0 0 0 24 127 3 127 127 58 0 0 0 0 0 0 0 0 1 0 0 0 14 36 127 127 127 55 0 0 0 0 0 0 0 0 1 0 56 0 0 26 127 127 127 76 0 0 0 0 0 0 0 0 96 1 0 0 0 38 127 127 1 127 49 0 0 0 0 0 0 0 0 1 0 0 0 26 7 127 127 127 70 0 0 0 0 0 0 0 0 1 0 0 28 0 38 127 127 127 52 0 0 0 0 0 0 0 0 1 112 0 0 0 26 127 127 127 0 76 0 0 0 0 0 0 64 0 1 0 0 0 38 127 3 127 127 65 0 0 0 0 0 0 0 0 1 0 0 0 14 26 127 127 127 69 0 0 0 0 0 0 0 0 1 0 56 0 0 38 127 127 127 60 0 0 0 0 0 0 0 0 96 1 0 0 0 33 127 127 1 127 76 0 0 0 0 0 0 0 0 1 0 0 0 48 7 127 127 127 60 0 0 0 0 0 0 0 0 1 0 0 28 0 33 127 127 127 62 0 0 0 0 0 0 0 0 1 112 0 0 0 48 127 127 127 0 61 0 0 0 0 0 0 64 0 1 0 0 0 33 127 3 127 127 76 0 0 0 0 0 0 0 0 1 0 0 0 14 48 127 127 127 76 0 0 0 0 0 0 0 0 1 0 56 0 0 33 127 127 127 57 0 0 0 0 0 0 0 0 96 1 0 0 0 48 127 127 1 127 73 0 0 0 0 0 64 0 0 1 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 15 127 127 127 127 100 100 100 0 100 0 0 0 0 0 0 60 0 0 127 127 127 127 100 0 100 100 100 0 0 0 0 112 0 0 0 0 127 127 127 1 127 100 100 100 100 0 0 64 0 0 0 0 0 0 127 7 127 127 127 100 100 100 100 0 0 0 0 0 0 0 0 30 0 127 127 127 127 100 100 0 100 100 0 0 0 0 0 120 0 0 0 127 127 127 127 0 100 100 100 100 0 0 0 96 0 0 0 0 0 127 127 3 127 127 100 100 100 100 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 127 1 127 50 32 1 0 0 0 4 0 0 37 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 elektroid-3.2.3/test/res/connectors/microfreak_pwavetable.data000066400000000000000000001613141500236517400246260ustar00rootroot0000000000000022 serialization::archive 10 0 4 8 DEVBUILD 14 Pluck Additive 1 0 0 18 000000000000000000 0 0 1 16384 6 52 122 53 -29 54 70 56 -101 57 -28 58 39 60 96 61 -103 62 -36 63 49 65 -102 66 34 68 -57 69 -128 71 80 73 42 75 9 77 -27 78 -70 80 115 82 11 84 121 85 -66 86 -47 87 -84 88 69 89 -103 89 -86 89 123 89 4 89 65 88 63 87 -6 85 126 84 -44 82 1 81 22 79 21 77 4 75 -18 72 -41 70 -74 68 -107 66 116 64 83 62 50 60 11 58 -27 55 -66 53 -104 51 119 49 85 47 62 45 56 43 66 41 97 39 -107 37 -22 35 91 34 -21 32 -112 31 70 30 -5 28 -80 27 96 26 0 25 -109 23 24 22 -115 20 -3 18 109 17 -36 15 76 14 -63 12 54 11 -84 9 27 8 126 6 -48 4 15 3 62 1 93 -1 119 -3 -111 -5 -84 -7 -42 -9 21 -10 117 -12 -9 -14 -110 -15 71 -16 12 -17 -35 -19 -94 -20 88 -21 -3 -23 -120 -24 0 -25 112 -27 -32 -29 96 -30 -3 -32 -50 -33 -32 -34 53 -34 -40 -35 -48 -35 7 -34 -121 -34 67 -33 45 -32 58 -31 97 -30 -108 -29 -52 -28 5 -26 62 -25 113 -24 -107 -23 -94 -22 -102 -21 125 -20 63 -19 -30 -19 96 -18 -79 -18 -39 -18 -45 -18 -112 -18 20 -18 93 -19 111 -20 79 -21 3 -22 -107 -24 21 -25 -119 -27 -7 -29 110 -30 -18 -32 126 -33 35 -34 -29 -36 -72 -37 -97 -38 -102 -39 -97 -40 -81 -41 -59 -42 -37 -43 -21 -44 -4 -45 2 -45 2 -46 -8 -48 -19 -49 -29 -50 -39 -51 -50 -52 -60 -53 -70 -54 -80 -55 -91 -56 -91 -57 -90 -58 -90 -59 -84 -60 -76 -61 -59 -62 -38 -63 0 -63 55 -64 -127 -65 -25 -66 116 -66 45 -66 31 -66 75 -66 -80 -66 73 -65 27 -64 19 -63 39 -62 74 -61 109 -60 -123 -59 -115 -58 -125 -57 97 -56 30 -55 -65 -55 62 -54 -95 -54 -30 -54 15 -53 43 -53 61 -53 79 -53 110 -53 -87 -53 12 -52 -95 -52 120 -51 -114 -50 -14 -49 -104 -47 117 -45 -125 -43 -66 -41 10 -38 100 -36 -66 -34 14 -31 88 -29 -109 -27 -62 -25 -20 -23 12 -20 43 -18 74 -16 99 -14 125 -12 -105 -10 -79 -8 -51 -6 -20 -4 22 -1 69 1 -128 3 -65 5 10 8 100 10 -60 12 46 15 -103 17 2 20 109 22 -56 24 7 27 45 29 47 31 9 33 -69 34 65 36 -90 37 -18 38 33 40 74 41 114 42 -90 43 -30 44 49 46 -108 47 9 49 -116 50 106 51 -34 52 72 54 -81 55 6 57 79 58 -115 59 -62 60 -8 61 53 63 -125 64 -25 65 104 67 5 69 -69 70 -119 72 103 74 76 76 47 78 6 80 -60 81 102 83 -32 84 45 86 71 87 41 88 -48 88 54 89 87 89 48 89 -64 88 9 88 14 87 -47 85 89 84 -81 82 -36 80 -19 78 -24 76 -37 74 -59 72 -85 70 -112 68 117 66 91 64 54 62 18 60 -18 57 -54 55 -90 53 -126 51 94 49 68 47 45 45 33 43 40 41 68 39 121 37 -52 35 64 34 -46 32 123 31 55 30 -6 28 -69 27 112 26 26 25 -81 23 53 22 -84 20 29 19 -115 17 -2 15 112 14 -25 12 93 11 -44 9 69 8 -83 6 6 5 78 3 -125 1 -88 -1 -65 -3 -47 -5 -25 -7 12 -8 73 -10 -96 -12 29 -13 -68 -15 119 -16 65 -17 19 -18 -30 -20 -93 -21 77 -22 -35 -24 84 -25 -70 -27 31 -28 -112 -30 35 -31 -27 -33 -23 -34 49 -34 -55 -35 -74 -35 -16 -35 111 -34 43 -33 20 -32 37 -31 80 -30 -117 -29 -53 -28 11 -26 75 -25 -127 -24 -84 -23 -64 -22 -61 -21 -85 -20 117 -19 34 -18 -86 -18 7 -17 56 -17 54 -17 -1 -18 -116 -18 -36 -19 -10 -20 -43 -21 -116 -22 28 -23 -104 -25 5 -26 113 -28 -30 -30 93 -31 -21 -33 -114 -34 75 -35 31 -36 6 -37 3 -38 15 -39 36 -40 63 -41 88 -42 110 -43 122 -44 -126 -45 -126 -46 125 -47 119 -48 107 -49 95 -50 83 -51 72 -52 62 -53 58 -54 53 -55 49 -56 44 -57 47 -58 49 -59 59 -60 74 -61 98 -62 -127 -63 -81 -64 -14 -65 78 -65 -48 -66 -127 -66 100 -66 -127 -66 -39 -66 116 -65 66 -64 56 -63 78 -62 118 -61 -93 -60 -58 -59 -38 -58 -44 -57 -75 -56 118 -55 25 -54 -101 -54 -3 -54 66 -53 107 -53 -123 -53 -113 -53 -108 -53 -91 -53 -47 -53 37 -52 -86 -52 111 -51 122 -50 -50 -49 104 -47 66 -45 81 -43 -117 -41 -36 -39 57 -36 -107 -34 -20 -32 53 -29 113 -27 -96 -25 -55 -23 -22 -21 7 -18 35 -16 59 -14 78 -12 97 -10 116 -8 -116 -6 -88 -4 -54 -2 -11 0 36 3 97 5 -88 7 -5 9 86 12 -67 14 40 17 -109 19 -6 21 82 24 -101 26 -58 28 -53 30 -90 32 89 34 -31 35 72 37 -116 38 -69 39 -35 40 -2 41 38 43 92 44 -92 45 0 47 116 48 -10 49 -121 50 -11 51 100 53 -58 54 27 56 100 57 -100 58 -52 59 -6 60 45 62 110 63 -53 64 64 66 -41 67 -117 69 89 71 61 73 39 75 17 77 -17 78 -74 80 97 82 -27 83 62 85 100 86 83 87 6 88 120 88 -89 88 -112 88 46 88 126 87 -122 86 76 85 -41 83 50 82 94 80 112 78 108 76 91 74 70 72 47 70 18 68 -12 65 -41 63 -71 61 -101 59 126 57 92 55 59 53 25 51 -9 48 -38 46 -59 44 -68 42 -65 40 -41 38 12 37 95 35 -43 33 105 32 21 31 -44 29 -98 28 106 27 41 26 -39 24 122 23 8 22 -119 20 -3 18 114 17 -25 15 97 14 -36 12 93 11 -33 9 90 8 -52 6 46 5 126 3 -71 1 -29 -1 -1 -3 19 -4 39 -6 72 -8 -128 -10 -37 -12 88 -13 -11 -15 -79 -16 -125 -17 98 -18 58 -19 5 -20 -75 -22 74 -23 -58 -25 46 -26 -115 -28 -10 -30 121 -31 39 -32 24 -33 83 -34 -32 -35 -65 -35 -14 -35 108 -34 40 -33 19 -32 37 -31 85 -30 -105 -29 -32 -28 42 -26 109 -25 -86 -24 -37 -23 -5 -22 6 -20 -8 -20 -52 -19 -128 -18 15 -17 119 -17 -77 -17 -64 -17 -107 -17 44 -17 -120 -18 -89 -19 -117 -20 66 -21 -41 -23 81 -24 -68 -26 36 -27 -113 -29 8 -30 -110 -32 51 -33 -19 -35 -66 -36 -86 -37 -86 -38 -70 -39 -41 -40 -10 -41 21 -41 44 -42 63 -43 72 -44 76 -45 73 -46 65 -47 56 -48 48 -49 40 -50 32 -51 23 -52 18 -53 13 -54 10 -55 7 -56 10 -57 14 -58 21 -59 34 -60 53 -61 82 -62 124 -63 -70 -64 16 -64 -119 -65 44 -65 4 -65 23 -65 108 -65 -3 -65 -56 -64 -60 -63 -32 -62 16 -60 70 -59 111 -58 -118 -57 -119 -56 110 -55 48 -54 -44 -54 86 -53 -71 -53 -1 -53 38 -52 53 -52 52 -52 48 -52 51 -52 75 -52 -119 -52 -3 -52 -80 -51 -87 -50 -15 -49 -127 -47 84 -45 97 -43 -105 -41 -25 -39 66 -36 -98 -34 -16 -32 54 -29 108 -27 -107 -25 -72 -23 -46 -21 -23 -19 -1 -17 20 -14 34 -12 49 -10 63 -8 77 -6 97 -4 123 -2 -100 0 -61 2 -10 4 54 7 -125 9 -40 11 55 14 -98 16 9 19 112 21 -52 23 19 26 62 28 69 30 35 32 -43 33 93 35 -65 36 -2 37 35 39 60 40 81 41 107 42 -109 43 -47 44 38 46 -109 47 17 49 -64 49 48 51 -102 52 -4 53 80 55 -106 56 -53 57 -11 58 26 60 71 61 -128 62 -50 63 61 65 -49 66 125 68 75 70 43 72 25 74 6 76 -21 77 -68 79 111 81 -3 82 94 84 -114 85 -119 86 72 87 -58 87 1 88 -11 87 -100 87 -5 86 16 86 -34 84 112 83 -54 81 -6 79 12 78 7 76 -11 73 -32 71 -53 69 -75 67 -97 65 -119 63 115 61 87 59 59 57 30 55 1 53 -30 50 -59 48 -87 46 -108 44 -119 42 -115 40 -91 38 -42 36 41 35 -97 33 54 32 -24 30 -79 29 -124 28 87 27 35 26 -33 24 -123 23 26 22 -98 20 23 19 -118 17 -3 15 119 14 -10 12 122 11 2 10 -122 8 -1 6 105 5 -62 3 5 2 49 0 76 -2 91 -4 107 -6 -120 -8 -70 -10 14 -11 -119 -13 43 -14 -20 -16 -61 -17 -85 -18 -113 -19 98 -20 30 -21 -70 -23 53 -24 -102 -26 -12 -28 80 -29 -56 -31 110 -32 80 -33 125 -34 -3 -35 -47 -35 -8 -35 110 -34 39 -33 24 -32 48 -31 100 -30 -86 -29 -13 -28 67 -26 -116 -25 -54 -24 1 -22 38 -21 54 -20 48 -19 13 -18 -55 -18 100 -17 -40 -17 33 -16 57 -16 28 -16 -64 -17 34 -17 70 -18 47 -19 -24 -21 121 -22 -19 -24 85 -25 -70 -27 34 -28 -107 -30 30 -31 -71 -33 113 -34 68 -35 45 -36 45 -37 65 -38 95 -39 -127 -40 -93 -41 -63 -42 -39 -43 -27 -44 -22 -45 -23 -46 -26 -47 -35 -48 -43 -49 -52 -50 -61 -51 -70 -52 -72 -53 -74 -54 -76 -55 -77 -56 -76 -57 -74 -58 -65 -59 -54 -60 -35 -61 -12 -62 23 -62 75 -63 -104 -64 6 -64 -100 -65 104 -65 110 -65 -71 -65 71 -64 15 -63 10 -62 44 -61 99 -60 -98 -59 -44 -58 -11 -57 -3 -56 -30 -55 -83 -54 86 -53 -33 -53 71 -52 -115 -52 -79 -52 -66 -52 -73 -52 -87 -52 -93 -52 -82 -52 -38 -52 60 -51 -37 -51 -58 -50 0 -48 -125 -47 81 -45 91 -43 -111 -41 -30 -39 66 -36 -94 -34 -9 -32 58 -29 113 -27 -107 -25 -82 -23 -61 -21 -46 -19 -32 -17 -21 -15 -11 -13 0 -10 11 -8 21 -6 31 -4 46 -2 71 0 104 2 -109 4 -55 6 13 9 91 11 -76 13 24 16 -125 18 -18 20 78 23 -100 25 -49 27 -38 29 -70 31 110 33 -14 34 78 36 -119 37 -87 38 -72 39 -60 40 -43 41 -14 42 39 44 113 45 -41 46 78 48 76 49 -66 50 45 52 -108 53 -21 54 47 56 96 57 -125 58 -96 59 -63 60 -15 61 57 63 -98 64 39 66 -44 67 -94 69 -121 71 122 73 113 75 97 77 61 79 -6 80 -107 82 5 84 68 85 75 86 22 87 -94 87 -20 87 -22 87 -98 87 5 87 33 86 -12 84 -120 83 -28 81 19 80 33 78 26 76 8 74 -16 71 -44 69 -72 67 -95 65 -117 63 116 61 90 59 62 57 34 55 5 53 -27 50 -59 48 -87 46 -110 44 -124 42 -127 40 -109 38 -63 36 13 35 125 33 17 32 -59 30 -110 29 110 28 75 27 31 26 -29 24 -111 23 41 22 -82 20 39 19 -102 17 13 16 -121 14 11 13 -111 11 30 10 -88 8 39 7 -104 5 -10 3 62 2 109 0 -119 -2 -103 -4 -93 -6 -70 -8 -25 -10 54 -11 -85 -13 73 -14 11 -15 -21 -17 -40 -18 -60 -19 -93 -20 103 -21 6 -22 -125 -24 -30 -26 49 -27 -128 -29 -23 -31 123 -32 74 -33 100 -34 -43 -35 -97 -35 -64 -35 53 -34 -17 -34 -29 -33 -1 -32 59 -30 -121 -29 -38 -28 48 -26 -128 -25 -55 -24 5 -22 50 -21 74 -20 77 -19 50 -18 -9 -18 -102 -17 26 -16 111 -16 -108 -16 -127 -16 47 -16 -98 -17 -53 -18 -71 -19 115 -20 2 -21 117 -23 -41 -25 53 -26 -105 -28 5 -29 -122 -31 30 -32 -49 -34 -97 -35 -119 -36 -120 -37 -100 -38 -67 -39 -29 -40 8 -40 41 -41 68 -42 84 -43 92 -44 93 -45 88 -46 79 -47 71 -48 63 -49 54 -50 46 -51 43 -52 41 -53 39 -54 37 -55 37 -56 38 -57 43 -58 51 -59 65 -60 85 -61 114 -62 -97 -63 -32 -64 66 -64 -51 -65 -116 -65 -120 -65 -54 -65 80 -64 22 -63 17 -62 54 -61 113 -60 -74 -59 -14 -58 26 -56 41 -55 26 -54 -21 -54 -104 -53 33 -52 -116 -52 -47 -52 -9 -52 0 -51 -10 -52 -34 -52 -55 -52 -59 -52 -32 -52 46 -51 -70 -51 -110 -50 -68 -49 55 -47 -1 -46 8 -43 65 -41 -103 -39 -2 -37 98 -34 -68 -32 4 -29 58 -27 98 -25 123 -23 -113 -21 -100 -19 -89 -17 -78 -15 -68 -13 -62 -11 -58 -9 -55 -7 -45 -5 -32 -3 -12 -1 18 2 57 4 108 6 -84 8 -7 10 80 13 -78 15 29 18 -120 20 -20 22 61 25 116 27 -120 29 114 31 46 33 -73 34 18 36 73 37 96 38 104 39 107 40 115 41 -119 42 -74 43 -3 44 95 46 -41 47 94 48 -49 49 64 51 -89 52 -2 53 65 55 109 56 -117 57 -97 58 -73 59 -37 60 22 62 115 63 -12 64 -101 66 101 68 74 70 63 72 58 74 47 76 18 78 -38 79 124 81 -13 82 59 84 77 85 38 86 -67 86 17 87 29 87 -35 86 80 86 117 85 82 84 -21 82 75 81 123 79 -120 77 127 75 110 73 83 71 58 69 37 67 17 65 -3 62 -23 60 -43 58 -64 56 -89 54 -115 52 115 50 89 48 63 46 42 44 30 42 27 40 44 38 87 36 -94 34 20 33 -85 31 102 30 60 29 35 28 13 27 -17 25 -65 24 117 23 21 22 -97 20 28 19 -111 17 9 16 -120 14 15 13 -100 11 46 10 -63 8 75 7 -57 5 45 4 123 2 -80 0 -51 -2 -35 -4 -27 -6 -10 -8 29 -9 104 -11 -39 -13 120 -14 62 -15 36 -16 30 -17 26 -18 5 -19 -43 -21 126 -22 2 -23 97 -25 -84 -27 -16 -29 73 -30 -56 -32 -123 -33 -114 -34 -16 -35 -81 -35 -54 -35 56 -34 -14 -34 -24 -33 8 -31 70 -30 -107 -29 -19 -28 71 -26 -98 -25 -18 -24 50 -22 103 -21 -118 -20 -110 -19 127 -18 78 -17 -4 -17 -123 -16 -27 -16 21 -15 17 -15 -49 -16 75 -16 127 -17 114 -18 46 -19 -67 -21 45 -22 -116 -24 -25 -26 70 -27 -79 -29 47 -30 -61 -32 115 -33 63 -34 41 -35 44 -36 66 -37 105 -38 -106 -39 -61 -40 -21 -41 9 -41 29 -42 40 -43 43 -44 42 -45 36 -46 30 -47 24 -48 18 -49 18 -50 17 -51 16 -52 15 -53 15 -54 17 -55 19 -56 24 -57 29 -58 42 -59 61 -60 88 -61 125 -62 -72 -63 14 -63 -117 -64 61 -64 44 -64 96 -64 -36 -64 -99 -63 -104 -62 -65 -61 1 -59 78 -58 -110 -57 -60 -56 -38 -55 -48 -54 -93 -53 82 -52 -33 -52 74 -51 -110 -51 -74 -51 -68 -51 -88 -51 -121 -51 99 -51 77 -51 83 -51 -116 -51 6 -50 -54 -50 -29 -49 79 -47 14 -45 16 -43 71 -41 -96 -39 10 -36 114 -34 -52 -32 20 -29 69 -27 100 -25 119 -23 -127 -21 -122 -19 -117 -17 -113 -15 -110 -13 -109 -11 -112 -9 -116 -7 -116 -5 -111 -3 -100 -1 -80 1 -51 3 -7 5 49 8 118 10 -53 12 42 15 -109 17 -2 19 101 22 -68 24 -8 26 15 29 -6 30 -75 32 61 34 -106 35 -57 36 -41 37 -45 38 -56 39 -63 40 -55 41 -21 42 39 44 126 45 -17 46 -117 47 -3 48 110 50 -43 51 45 53 111 54 -101 55 -78 56 -66 57 -54 58 -31 59 17 61 96 62 -42 63 118 65 57 67 26 69 17 71 18 73 13 75 -6 76 -54 78 116 80 -9 81 74 83 103 84 74 85 -17 85 79 86 104 86 55 86 -75 85 -28 84 -55 83 104 82 -54 80 -3 78 12 77 4 75 -15 72 -37 70 -58 68 -77 66 -94 64 -110 62 -127 60 113 58 96 56 76 54 57 52 35 50 13 48 -8 45 -28 43 -44 41 -47 39 -32 37 8 36 83 34 -63 32 90 31 24 30 -10 28 -27 27 -38 26 -56 25 -93 24 100 23 10 22 -103 20 23 19 -113 17 8 16 -119 14 19 13 -88 11 67 10 -35 8 114 7 -8 5 105 4 -67 2 -6 0 28 -1 46 -3 51 -5 63 -7 96 -9 -92 -11 17 -12 -81 -14 120 -15 100 -16 103 -17 112 -18 106 -19 70 -20 -6 -22 -125 -23 -27 -25 43 -26 104 -28 -77 -30 33 -31 -52 -33 -58 -34 24 -34 -55 -35 -37 -35 68 -34 -4 -34 -14 -33 23 -31 91 -30 -79 -29 14 -27 107 -26 -58 -25 26 -23 98 -22 -101 -21 -61 -20 -45 -19 -59 -18 -102 -17 79 -16 -30 -16 75 -15 -119 -15 -113 -15 90 -15 -32 -16 31 -16 25 -17 -40 -19 105 -20 -42 -22 50 -23 -121 -25 -31 -27 70 -28 -65 -30 81 -31 -4 -33 -58 -34 -82 -35 -76 -36 -48 -37 -6 -38 44 -38 93 -39 -117 -40 -80 -41 -56 -42 -40 -43 -35 -44 -34 -45 -36 -46 -41 -47 -46 -48 -49 -49 -51 -50 -50 -51 -48 -52 -47 -53 -45 -54 -43 -55 -40 -56 -36 -57 -27 -58 -15 -59 2 -59 25 -60 58 -61 108 -62 -74 -63 39 -63 -54 -64 -85 -64 -45 -64 70 -63 3 -62 -1 -62 42 -60 115 -59 -57 -58 19 -56 76 -55 105 -54 100 -53 60 -52 -14 -52 -126 -51 -17 -51 57 -50 93 -50 95 -50 71 -50 29 -50 -18 -51 -56 -51 -66 -51 -28 -51 71 -50 -7 -50 0 -48 96 -47 19 -45 16 -43 69 -41 -95 -39 12 -36 118 -34 -45 -32 25 -29 74 -27 101 -25 114 -23 118 -21 118 -19 117 -17 115 -15 111 -13 107 -11 98 -9 87 -7 79 -5 75 -3 79 -1 91 1 113 3 -108 5 -62 7 -1 9 75 12 -90 14 9 17 115 19 -41 21 49 24 112 26 -115 28 124 30 59 32 -59 33 28 35 70 36 79 37 66 38 45 39 27 40 26 41 46 42 96 43 -79 44 30 46 72 46 -75 47 35 49 -119 50 -34 51 29 53 65 54 82 55 83 56 84 57 93 58 124 59 -66 60 38 62 -69 63 120 65 86 67 75 69 75 71 73 73 55 75 12 77 -66 78 70 80 -97 81 -60 82 -79 83 97 84 -51 84 -14 84 -50 84 91 84 -103 83 -118 82 50 81 -99 79 -44 77 -27 75 -32 73 -48 71 -66 69 -84 67 -98 65 -106 63 -112 61 -118 59 -125 57 124 55 114 53 101 51 87 49 74 47 60 45 47 43 39 41 40 39 57 37 97 35 -85 33 30 32 -71 30 125 29 100 28 94 27 97 26 93 25 69 24 19 23 -60 21 90 20 -33 18 92 17 -40 15 94 14 -17 12 -116 11 48 10 -43 8 119 7 10 6 -118 4 -18 2 54 1 96 -1 117 -3 -128 -5 -116 -7 -86 -9 -20 -11 89 -12 -10 -14 -59 -15 -70 -16 -54 -17 -31 -18 -18 -19 -37 -20 -98 -21 50 -22 -103 -24 -34 -26 20 -27 84 -29 -75 -31 80 -32 57 -33 124 -34 34 -34 42 -34 -116 -34 64 -33 53 -32 91 -31 -95 -30 -6 -29 89 -27 -70 -26 21 -24 106 -23 -75 -22 -14 -21 30 -19 51 -18 44 -17 6 -16 -64 -16 90 -15 -50 -15 24 -14 46 -14 6 -14 -102 -15 -27 -16 -24 -17 -83 -18 63 -19 -81 -21 11 -22 96 -24 -71 -26 32 -27 -103 -29 40 -30 -44 -32 -96 -33 -118 -34 -110 -35 -77 -36 -25 -37 36 -37 96 -38 -105 -39 -61 -40 -30 -41 -10 -42 1 -42 7 -43 7 -44 6 -45 5 -46 6 -47 8 -48 13 -49 19 -50 24 -51 29 -52 34 -53 41 -54 48 -55 59 -56 72 -57 90 -58 113 -59 -113 -60 -69 -61 -3 -62 98 -62 -8 -63 -51 -63 -22 -63 82 -62 6 -61 -2 -61 42 -59 119 -58 -47 -57 36 -55 99 -54 -124 -53 -126 -52 92 -51 17 -50 -93 -50 17 -49 92 -49 -127 -49 -127 -49 100 -49 48 -49 -13 -50 -67 -50 -95 -50 -79 -50 -1 -50 -104 -49 -119 -48 -41 -47 124 -45 110 -43 -99 -41 -10 -39 97 -36 -53 -34 37 -31 103 -29 -113 -27 -94 -25 -91 -23 -99 -21 -108 -19 -121 -17 121 -15 108 -13 92 -11 72 -9 51 -7 30 -5 12 -3 1 -1 -1 0 8 3 30 5 62 7 110 9 -82 11 -3 13 88 16 -68 18 29 21 115 23 -78 25 -49 27 -65 29 124 31 2 33 85 34 121 35 120 36 95 37 60 38 26 39 7 40 14 41 52 42 121 43 -34 44 -1 44 104 46 -41 47 60 49 -111 50 -50 51 -17 52 -9 53 -19 54 -35 55 -42 56 -28 57 20 59 111 60 -11 61 -89 63 127 65 112 67 112 69 110 71 96 73 58 75 -15 76 127 78 -32 79 14 81 4 82 -65 82 56 83 109 83 86 83 -15 82 61 82 56 81 -23 79 89 78 -105 76 -83 74 -84 72 -97 70 -112 68 -123 66 -127 64 127 62 -126 60 -122 58 -118 56 -117 54 -118 52 -121 50 -125 48 127 46 120 44 116 42 114 40 118 38 -119 36 -77 34 -2 32 112 31 14 30 -41 28 -58 27 -50 26 -32 25 -20 24 -27 23 -63 22 124 21 28 20 -89 18 39 17 -89 15 48 14 -57 12 107 11 27 10 -51 8 124 7 31 6 -84 4 31 3 115 1 -90 -1 -64 -3 -51 -5 -39 -7 -10 -9 50 -10 -100 -12 59 -13 14 -14 13 -15 42 -16 82 -17 111 -18 112 -19 69 -20 -28 -22 83 -23 -104 -25 -53 -27 0 -28 84 -30 -33 -32 -73 -33 -22 -34 -125 -34 -128 -34 -37 -34 -117 -33 -127 -32 -86 -31 -13 -30 78 -28 -81 -27 15 -25 107 -24 -63 -23 14 -21 80 -20 -126 -19 -103 -18 -105 -17 119 -16 57 -15 -40 -15 86 -14 -85 -14 -48 -14 -71 -14 93 -14 -75 -15 -61 -16 -114 -17 34 -18 -109 -20 -18 -22 67 -23 -100 -25 2 -26 122 -28 10 -29 -76 -31 125 -32 104 -33 115 -34 -103 -35 -46 -36 23 -36 91 -37 -102 -38 -50 -39 -12 -40 14 -40 32 -41 41 -42 46 -43 50 -44 54 -45 59 -46 67 -47 76 -48 87 -49 98 -50 108 -51 117 -52 126 -53 -119 -54 -106 -55 -90 -56 -72 -57 -50 -58 -21 -59 18 -59 75 -60 -91 -61 44 -61 -16 -62 -5 -62 87 -61 3 -60 -9 -60 36 -58 117 -57 -43 -56 46 -54 115 -53 -103 -52 -101 -51 121 -50 49 -49 -58 -49 57 -48 -123 -48 -83 -48 -82 -48 -115 -48 82 -48 10 -48 -60 -49 -109 -49 -116 -49 -62 -49 70 -48 34 -47 90 -46 -16 -45 -43 -43 -1 -41 83 -38 -66 -36 39 -33 -127 -31 -65 -29 -29 -27 -21 -25 -30 -23 -50 -21 -72 -19 -96 -17 -117 -15 114 -13 87 -11 55 -9 21 -7 -14 -6 -44 -4 -69 -2 -83 0 -88 2 -80 4 -61 6 -27 8 24 11 89 13 -86 15 4 18 97 20 -74 22 -12 24 16 27 2 29 -65 30 69 32 -109 33 -81 34 -93 35 125 36 74 37 26 38 -8 38 -17 39 7 41 66 42 -99 43 -38 43 64 45 -83 46 20 48 104 49 -92 50 -62 51 -60 52 -77 53 -103 54 -124 55 -124 56 -91 57 -16 58 107 60 20 62 -27 63 -44 65 -45 67 -44 69 -55 71 -89 73 99 75 -9 76 94 78 -111 79 -113 80 82 81 -42 81 23 82 14 82 -74 81 13 81 21 80 -47 78 73 77 -117 75 -91 73 -91 71 -102 69 -113 67 -121 65 -119 63 -113 61 -103 59 -90 57 -78 55 -68 53 -60 51 -55 49 -52 47 -49 45 -47 43 -46 41 -42 39 -34 37 -12 35 30 34 104 32 -38 30 123 29 72 28 62 27 82 26 114 25 -115 24 -107 23 127 22 70 21 -19 19 125 18 1 17 -123 15 18 14 -83 12 89 11 15 10 -51 8 -120 7 54 6 -46 4 81 3 -79 1 -17 -1 15 -2 29 -4 38 -6 63 -8 120 -10 -34 -12 124 -13 80 -14 86 -15 126 -16 -75 -17 -28 -18 -10 -19 -38 -20 -122 -21 -5 -23 67 -24 112 -26 -100 -28 -30 -30 93 -31 37 -32 73 -33 -44 -34 -58 -34 27 -33 -58 -33 -69 -32 -27 -31 50 -29 -113 -28 -13 -27 85 -25 -76 -24 10 -22 90 -21 -98 -20 -46 -19 -17 -18 -14 -17 -42 -16 -100 -15 65 -14 -56 -14 41 -13 91 -13 82 -13 4 -13 106 -14 -126 -15 84 -16 -19 -18 94 -19 -70 -21 13 -22 101 -24 -53 -26 65 -27 -49 -29 121 -30 66 -31 47 -32 60 -33 103 -34 -89 -35 -13 -36 65 -36 -120 -37 -62 -38 -16 -39 16 -39 36 -40 49 -41 56 -42 63 -43 69 -44 77 -45 88 -46 100 -47 115 -48 -127 -49 -114 -50 -102 -51 -89 -52 -77 -53 -61 -54 -44 -55 -23 -56 -1 -57 26 -57 61 -58 111 -59 -66 -60 56 -60 -20 -61 -22 -61 58 -60 -34 -60 -51 -59 -7 -58 77 -56 -77 -55 21 -53 97 -52 -115 -51 -109 -50 114 -49 44 -48 -62 -48 54 -47 -123 -47 -82 -47 -81 -47 -115 -47 76 -47 -5 -48 -88 -48 102 -48 75 -48 107 -48 -41 -48 -99 -47 -62 -46 72 -44 36 -42 71 -40 -101 -38 6 -35 112 -33 -56 -31 4 -28 33 -26 33 -24 14 -22 -16 -21 -51 -19 -83 -17 -114 -15 109 -13 73 -11 32 -9 -12 -8 -58 -6 -100 -4 120 -2 92 0 76 2 72 4 80 6 102 8 -116 10 -61 12 11 15 94 17 -74 19 9 22 72 24 102 26 89 28 23 30 -100 31 -25 32 -2 33 -21 34 -71 35 121 36 58 37 8 38 -15 38 -5 39 42 41 125 42 -125 42 -27 43 79 45 -76 46 8 48 67 49 93 50 90 51 63 52 23 53 -14 53 -31 54 -16 55 43 57 -105 58 53 60 -1 61 -23 63 -25 65 -23 67 -31 69 -62 71 -127 73 27 75 -122 76 -63 77 -58 78 -108 79 36 80 114 80 118 80 47 80 -107 79 -86 78 113 77 -13 75 59 74 88 72 92 70 85 68 78 66 76 64 85 62 100 60 121 58 -112 56 -90 54 -70 52 -54 50 -39 48 -25 46 -11 44 0 43 10 41 20 39 35 37 59 35 103 33 -80 31 33 30 -61 28 -107 27 -107 26 -75 25 -27 24 18 24 43 23 37 22 -6 20 -84 19 67 18 -53 16 83 15 -28 13 -123 12 56 11 -6 9 -61 8 -116 7 74 6 -11 4 -122 3 -13 1 61 0 102 -2 119 -4 -125 -6 -105 -8 -53 -10 45 -11 -55 -13 -96 -14 -83 -15 -30 -16 41 -16 109 -17 -107 -18 -114 -19 74 -20 -54 -22 21 -23 62 -25 97 -27 -103 -29 4 -30 -70 -32 -52 -33 72 -33 46 -33 122 -33 33 -32 20 -31 62 -30 -115 -29 -19 -28 83 -26 -75 -25 19 -23 105 -22 -70 -21 0 -19 55 -18 89 -17 95 -16 72 -15 17 -14 -68 -14 73 -13 -77 -13 -13 -13 -6 -13 -67 -13 50 -13 85 -14 47 -15 -53 -17 61 -18 -105 -20 -22 -22 67 -23 -87 -25 33 -26 -82 -28 87 -29 33 -30 14 -31 30 -32 78 -33 -107 -34 -22 -35 66 -35 -110 -36 -43 -37 9 -37 48 -38 74 -39 92 -40 105 -41 115 -42 126 -43 -117 -44 -101 -45 -82 -46 -61 -47 -41 -48 -23 -49 -6 -50 10 -50 26 -51 44 -52 64 -53 87 -54 111 -55 -118 -56 -86 -57 -42 -58 26 -58 -123 -59 42 -59 24 -59 89 -59 -17 -59 -40 -58 2 -56 89 -55 -58 -54 47 -52 -126 -51 -76 -50 -66 -49 -97 -48 89 -47 -15 -47 104 -46 -70 -46 -25 -46 -22 -46 -59 -46 127 -46 35 -46 -62 -47 110 -47 61 -47 68 -47 -105 -47 68 -46 84 -45 -57 -44 -105 -42 -78 -40 1 -37 107 -35 -42 -33 47 -30 103 -28 125 -26 114 -24 81 -22 37 -20 -10 -19 -54 -17 -96 -15 118 -13 72 -11 20 -9 -37 -8 -96 -6 103 -4 52 -2 10 0 -20 1 -40 3 -47 5 -41 7 -18 9 23 12 82 14 -101 16 -19 18 59 21 121 23 -104 25 -115 27 77 29 -46 30 26 32 43 33 16 34 -45 34 -123 35 54 36 -13 36 -53 37 -58 38 -25 39 45 41 21 41 113 42 -39 43 62 45 -109 46 -51 47 -27 48 -36 49 -74 50 -128 51 74 52 37 53 34 54 74 55 -89 56 55 58 -10 59 -39 61 -45 63 -45 65 -51 67 -80 69 115 71 15 73 127 74 -65 75 -52 76 -95 77 60 78 -106 78 -87 78 113 78 -24 77 13 77 -31 75 109 74 -68 72 -34 70 -26 68 -31 66 -33 64 -27 62 -10 60 17 59 49 57 83 55 118 53 -107 51 -77 49 -49 47 -23 45 2 44 25 42 46 40 66 38 87 36 116 34 -94 32 -20 30 94 29 0 28 -42 26 -35 25 8 25 72 24 -120 23 -75 22 -65 21 -94 20 95 19 -4 17 -119 16 20 15 -87 13 82 12 12 11 -40 9 -82 8 -124 7 82 6 15 5 -80 3 46 2 -122 0 -69 -2 -44 -4 -32 -6 -13 -8 35 -9 -126 -11 28 -12 -12 -14 8 -14 73 -15 -95 -16 -7 -17 56 -17 69 -18 20 -19 -96 -21 -14 -23 26 -24 52 -26 97 -28 -69 -30 96 -31 97 -32 -51 -33 -91 -33 -25 -33 -119 -32 121 -31 -91 -30 -10 -29 90 -27 -63 -26 36 -24 -128 -23 -42 -22 37 -20 108 -19 -89 -18 -53 -17 -43 -16 -65 -15 -117 -14 57 -13 -52 -13 64 -12 -115 -12 -91 -12 122 -12 -1 -13 48 -13 18 -14 -76 -16 39 -17 -125 -19 -42 -21 48 -22 -105 -24 16 -25 -97 -27 72 -28 16 -29 -3 -31 15 -31 69 -32 -107 -33 -11 -34 87 -34 -78 -35 -1 -36 59 -36 103 -37 -120 -38 -96 -39 -78 -40 -63 -41 -47 -42 -28 -43 -7 -44 17 -44 43 -45 69 -46 92 -47 115 -48 -121 -49 -101 -50 -80 -51 -56 -52 -29 -53 -2 -54 27 -54 57 -55 97 -56 -101 -57 -8 -58 -116 -58 103 -58 -105 -58 34 -57 2 -56 42 -55 -124 -54 -11 -53 101 -51 -65 -50 -11 -49 1 -47 -28 -47 -96 -46 57 -45 -79 -45 7 -44 54 -44 59 -44 23 -44 -50 -45 104 -45 -7 -46 -110 -46 75 -46 59 -46 117 -46 9 -45 1 -44 96 -43 32 -41 49 -39 124 -37 -26 -35 81 -32 -87 -30 -35 -28 -21 -26 -43 -24 -90 -22 107 -20 45 -18 -13 -17 -67 -15 -121 -13 78 -11 15 -9 -55 -8 -128 -6 56 -4 -10 -3 -67 -1 -112 1 110 3 88 5 78 7 84 9 108 11 -103 13 -42 15 30 18 103 20 -94 22 -63 24 -74 26 118 28 -6 29 63 31 75 32 37 33 -35 33 127 34 31 35 -52 35 -110 36 124 37 -114 38 -56 39 -77 39 10 41 109 42 -47 43 38 45 95 46 117 47 102 48 56 49 -11 49 -81 50 121 51 99 52 122 53 -58 54 72 56 -3 57 -40 59 -50 61 -51 63 -58 65 -86 67 109 69 11 71 126 72 -63 73 -45 74 -79 75 84 76 -71 76 -39 76 -81 76 52 76 103 75 71 74 -34 72 53 71 93 69 105 67 106 65 108 63 121 61 -109 59 -72 57 -29 55 17 54 64 52 107 50 -109 48 -71 46 -34 44 3 43 38 41 71 39 101 37 -124 35 -89 33 -40 31 35 30 -107 28 57 27 19 26 33 25 89 24 -88 23 -7 22 56 22 85 21 70 20 13 19 -78 17 67 16 -46 14 106 13 23 12 -38 10 -81 9 -112 8 117 7 82 6 31 5 -46 3 97 2 -55 0 8 -1 39 -3 54 -5 73 -7 117 -9 -48 -11 104 -12 66 -13 90 -14 -90 -15 14 -15 123 -16 -50 -17 -15 -18 -44 -19 111 -20 -55 -22 -14 -24 8 -25 42 -27 119 -29 12 -30 -1 -32 92 -32 41 -32 98 -32 -2 -32 -21 -31 22 -29 105 -28 -51 -27 52 -25 -107 -24 -20 -23 63 -21 -117 -20 -46 -19 13 -17 53 -16 67 -15 48 -14 -2 -14 -82 -13 69 -12 -64 -12 25 -11 65 -11 39 -11 -67 -12 -3 -13 -22 -14 -112 -15 6 -16 98 -18 -74 -20 17 -21 124 -23 -9 -25 -121 -26 49 -27 -6 -29 -25 -30 -4 -31 54 -31 -114 -32 -9 -33 100 -33 -55 -34 31 -34 100 -35 -105 -36 -67 -37 -38 -38 -15 -39 6 -39 27 -40 49 -41 75 -42 104 -43 -119 -44 -87 -45 -56 -46 -29 -47 -3 -48 20 -48 45 -49 73 -50 105 -51 -119 -52 -88 -53 -57 -54 -22 -55 28 -55 109 -56 -15 -57 -68 -57 -36 -57 90 -56 50 -55 87 -54 -78 -53 41 -51 -97 -50 -2 -49 57 -47 71 -46 41 -45 -26 -45 -128 -44 -6 -44 82 -43 -123 -43 -114 -43 107 -43 30 -43 -77 -44 56 -44 -62 -45 105 -45 66 -45 99 -45 -34 -45 -66 -44 8 -42 -73 -41 -66 -39 3 -36 104 -34 -45 -32 41 -29 90 -27 95 -25 63 -23 2 -21 -72 -20 107 -18 36 -16 -30 -15 -94 -13 95 -11 20 -9 -63 -8 106 -6 18 -4 -63 -3 122 -1 62 1 14 3 -24 4 -50 6 -61 8 -53 10 -24 12 26 15 88 17 -101 19 -46 21 -17 23 -28 25 -93 27 38 29 106 30 111 31 66 32 -18 32 -124 33 20 34 -80 34 101 35 62 36 65 37 111 38 51 38 -126 39 -30 40 67 42 -104 43 -46 44 -25 45 -45 46 -100 47 76 48 -10 48 -85 49 -127 50 -125 51 -67 52 48 54 -40 55 -85 57 -101 59 -105 61 -114 63 114 65 55 67 -43 68 73 70 -112 71 -89 72 -117 73 55 74 -88 74 -42 74 -69 74 81 74 -108 73 -123 72 38 71 -121 69 -75 67 -58 65 -52 63 -43 61 -22 59 13 58 61 56 118 54 -78 52 -18 50 39 49 92 47 -113 45 -63 43 -14 41 34 40 80 38 122 36 -94 34 -51 32 1 31 78 29 -65 27 98 26 62 25 82 24 -107 23 -10 22 92 22 -80 21 -31 20 -29 19 -74 18 98 17 -7 15 -117 14 40 13 -39 11 -93 10 -125 9 112 8 98 7 80 6 48 5 -10 3 -104 2 17 1 94 -1 -122 -3 -104 -5 -87 -7 -47 -9 39 -10 -69 -12 -106 -13 -76 -14 11 -14 -124 -15 6 -15 114 -16 -81 -17 -87 -18 85 -19 -71 -21 -28 -23 -12 -25 10 -26 72 -28 -51 -30 -82 -31 -5 -32 -71 -32 -26 -32 122 -31 100 -30 -113 -29 -29 -28 73 -26 -78 -25 18 -23 102 -22 -76 -21 -3 -20 67 -18 -128 -17 -85 -16 -69 -15 -86 -14 120 -13 42 -12 -60 -12 71 -11 -83 -11 -27 -11 -32 -11 -118 -11 -38 -12 -46 -13 127 -14 -9 -16 83 -17 -88 -19 6 -20 115 -22 -14 -24 -124 -25 46 -26 -9 -28 -28 -29 -6 -30 57 -30 -103 -31 12 -31 -124 -32 -11 -33 86 -33 -93 -34 -34 -35 10 -35 45 -36 73 -37 99 -38 125 -39 -103 -40 -71 -41 -35 -42 3 -42 42 -43 80 -44 114 -45 -112 -46 -84 -47 -55 -48 -22 -49 13 -49 50 -50 86 -51 118 -52 -105 -53 -63 -54 5 -54 120 -55 48 -55 62 -55 -84 -55 121 -54 -102 -53 -10 -52 114 -50 -16 -49 87 -47 -106 -46 -89 -45 -118 -44 69 -43 -33 -43 90 -42 -74 -42 -19 -42 -5 -42 -38 -42 -116 -42 27 -42 -106 -43 16 -43 -93 -44 100 -44 107 -44 -54 -44 -113 -43 -62 -42 95 -40 90 -38 -105 -36 -4 -34 103 -31 -69 -29 -24 -27 -26 -25 -71 -23 108 -21 17 -19 -77 -18 92 -16 13 -14 -62 -13 116 -11 29 -9 -67 -8 85 -6 -19 -5 -117 -3 51 -1 -25 0 -90 2 113 4 69 6 41 8 31 10 44 12 78 14 -126 16 -68 18 -16 20 11 23 0 25 -64 26 67 28 -125 29 -123 30 78 31 -18 31 116 32 -12 32 125 33 32 34 -25 34 -38 35 -7 36 -79 36 -8 37 83 39 -76 40 9 42 68 43 88 44 64 45 1 46 -93 46 60 47 -35 47 -99 48 -117 49 -78 50 20 52 -82 53 120 55 97 57 91 59 82 61 54 63 -4 64 -101 66 16 68 89 69 117 70 95 71 20 72 -113 72 -54 72 -66 72 101 72 -71 71 -71 70 104 69 -46 67 7 66 28 64 38 62 52 60 80 58 125 56 -71 54 -1 52 73 51 -109 49 -38 47 28 46 91 44 -103 42 -41 40 21 39 81 37 -119 35 -68 33 -18 31 39 30 117 28 -27 26 -121 25 100 24 126 23 -51 22 61 22 -73 21 33 21 103 20 122 19 91 18 17 17 -84 15 64 14 -33 12 -106 11 103 10 81 9 75 8 76 7 74 6 58 5 20 4 -54 2 85 1 -79 -1 -28 -3 -5 -5 11 -6 47 -8 -128 -10 16 -11 -22 -13 12 -13 108 -14 -11 -15 -116 -15 18 -15 105 -16 122 -17 58 -18 -86 -20 -38 -22 -26 -24 -14 -26 33 -27 -109 -29 99 -30 -97 -31 78 -31 112 -31 -5 -31 -32 -30 10 -28 97 -27 -53 -26 52 -24 -109 -23 -28 -22 43 -20 111 -19 -78 -18 -16 -17 30 -15 50 -14 35 -13 -14 -13 -93 -12 63 -11 -57 -11 56 -10 -126 -10 -112 -10 79 -10 -79 -11 -74 -12 105 -13 -28 -15 64 -16 -106 -18 -10 -20 103 -21 -21 -23 -126 -24 45 -25 -11 -27 -30 -28 -7 -29 60 -29 -94 -30 32 -30 -91 -31 35 -31 -114 -32 -27 -33 39 -33 90 -34 -126 -35 -91 -36 -59 -37 -27 -38 5 -38 42 -39 83 -40 -127 -41 -81 -42 -36 -43 5 -43 42 -44 74 -45 107 -46 -113 -47 -72 -48 -29 -49 12 -49 47 -50 78 -51 113 -52 -86 -53 12 -53 -80 -54 -86 -54 6 -53 -56 -53 -29 -52 65 -50 -62 -49 71 -47 -75 -46 -7 -45 12 -43 -17 -43 -87 -42 65 -41 -67 -41 28 -40 88 -40 107 -40 77 -40 0 -40 -119 -41 -7 -42 101 -42 -28 -43 -113 -43 124 -43 -64 -43 106 -42 -124 -41 13 -39 -8 -38 47 -35 -110 -33 -3 -31 82 -28 125 -26 116 -24 58 -22 -34 -21 112 -19 1 -17 -102 -16 62 -14 -25 -13 -114 -11 45 -9 -65 -8 72 -6 -49 -5 91 -3 -14 -2 -105 0 70 2 0 4 -59 5 -107 7 119 9 113 11 -124 13 -85 15 -35 17 11 20 37 22 25 24 -38 25 93 27 -100 28 -104 29 89 30 -18 30 102 31 -44 31 76 32 -36 32 -111 33 115 34 -125 35 60 35 122 36 -48 37 46 39 -125 40 -66 41 -47 42 -73 43 112 44 8 45 -112 45 31 46 -54 46 -92 47 -73 48 8 50 -108 51 82 53 52 55 41 57 29 59 0 61 -60 62 98 64 -42 65 31 67 60 68 42 69 -27 69 105 70 -81 70 -79 70 104 70 -51 69 -35 68 -103 67 14 66 74 64 100 62 115 60 -121 58 -85 56 -31 54 41 53 125 51 -43 49 45 48 -127 46 -47 44 29 43 104 41 -77 39 -1 37 72 36 -114 34 -50 32 9 31 72 29 -104 27 8 26 -87 24 -121 23 -90 22 -3 21 124 21 9 21 -120 20 -30 19 8 19 -10 17 -75 16 85 15 -20 13 -114 12 73 11 34 10 22 9 28 8 42 7 55 6 57 5 37 4 -16 2 -114 1 -5 -1 58 -2 87 -4 104 -6 -119 -8 -42 -10 98 -11 59 -12 97 -13 -54 -14 97 -14 12 -14 -86 -15 28 -15 70 -16 26 -17 -104 -19 -49 -21 -39 -23 -36 -25 -1 -27 99 -28 35 -29 80 -30 -14 -31 8 -30 -118 -30 106 -29 -109 -28 -21 -27 87 -25 -62 -24 30 -22 104 -21 -88 -20 -27 -19 37 -17 99 -16 -109 -15 -86 -14 -99 -13 106 -12 26 -11 -76 -11 63 -10 -72 -10 17 -9 51 -9 6 -9 123 -10 -116 -11 72 -12 -59 -14 35 -15 122 -17 -36 -19 83 -20 -36 -22 120 -23 38 -24 -18 -26 -39 -27 -16 -28 54 -28 -92 -29 45 -29 -66 -30 71 -30 -66 -31 29 -31 102 -32 -97 -33 -50 -34 -10 -35 27 -35 65 -36 103 -37 -110 -38 -63 -39 -11 -40 43 -40 96 -41 -112 -42 -70 -43 -32 -44 5 -44 46 -45 92 -46 -115 -47 -68 -48 -28 -49 4 -49 36 -50 82 -51 -91 -52 55 -52 29 -52 105 -52 29 -51 49 -50 -115 -49 19 -47 -97 -46 19 -44 93 -43 113 -42 83 -41 10 -40 -97 -40 27 -39 124 -39 -66 -39 -41 -39 -66 -39 115 -39 -6 -40 99 -40 -62 -41 49 -41 -57 -42 -99 -42 -58 -42 86 -41 87 -40 -53 -39 -89 -37 -43 -35 52 -32 -97 -30 -11 -28 29 -25 12 -23 -57 -22 90 -20 -38 -19 89 -17 -31 -16 119 -14 22 -12 -77 -11 71 -9 -52 -8 70 -6 -68 -5 55 -3 -66 -2 84 0 -11 1 -96 3 83 5 16 7 -33 8 -59 10 -57 12 -31 14 9 17 49 19 71 21 58 23 -6 24 125 26 -70 27 -78 28 108 29 -10 29 97 30 -64 30 38 31 -92 31 72 32 24 33 26 34 -94 33 -41 34 38 36 -127 37 -43 38 17 40 37 41 8 42 -68 42 72 43 -65 43 57 44 -50 44 -111 45 -114 46 -52 47 72 49 -7 50 -46 52 -63 54 -77 56 -108 58 87 60 -13 61 100 63 -83 64 -53 65 -68 66 125 67 10 68 91 68 108 68 52 68 -83 67 -49 66 -100 65 28 64 97 62 -126 60 -107 58 -82 56 -38 54 28 53 114 51 -44 49 61 48 -92 46 8 45 102 43 -64 41 25 40 114 38 -51 36 38 35 123 33 -55 31 16 30 86 28 -88 26 24 25 -72 23 -106 22 -72 21 24 21 -89 20 72 20 -33 19 81 19 -116 18 -117 17 84 16 -7 14 -109 13 55 12 -10 10 -42 9 -44 8 -25 7 5 7 33 6 53 5 54 4 23 3 -52 1 77 0 -102 -2 -65 -4 -46 -6 -16 -8 55 -9 -65 -11 -107 -12 -67 -13 45 -13 -45 -14 -110 -14 75 -14 -38 -15 33 -15 14 -16 -99 -18 -37 -20 -27 -22 -31 -24 -9 -26 75 -27 -5 -29 23 -29 -86 -30 -78 -30 41 -29 2 -28 40 -27 -126 -26 -15 -25 94 -23 -72 -22 -3 -21 51 -19 103 -18 -96 -17 -35 -16 16 -14 42 -13 31 -12 -20 -12 -105 -11 46 -10 -70 -10 60 -9 -92 -9 -37 -9 -57 -9 81 -9 114 -10 55 -11 -72 -13 21 -14 108 -16 -45 -18 79 -19 -32 -21 -126 -22 52 -23 -3 -25 -25 -26 -2 -27 71 -27 -67 -28 81 -28 -16 -29 -121 -29 10 -29 115 -30 -59 -31 5 -31 57 -32 104 -33 -108 -34 -65 -35 -20 -36 28 -36 81 -37 -116 -38 -53 -39 8 -39 64 -40 113 -41 -100 -42 -59 -43 -13 -44 39 -44 96 -45 -105 -46 -58 -47 -23 -48 5 -48 42 -49 110 -50 -22 -51 -69 -51 -14 -51 -105 -50 -95 -49 -4 -48 -123 -46 24 -44 -107 -43 -29 -42 -6 -41 -38 -40 -115 -39 31 -38 -103 -38 -4 -38 67 -37 99 -37 82 -37 10 -37 -112 -38 -15 -39 68 -39 -94 -40 35 -40 -33 -41 -19 -41 96 -40 69 -39 -96 -38 106 -36 -115 -34 -24 -32 83 -29 -87 -27 -49 -25 -72 -23 102 -21 -25 -20 81 -18 -70 -17 48 -15 -73 -14 74 -12 -34 -11 102 -9 -33 -8 72 -6 -85 -5 18 -3 -121 -2 12 0 -98 1 56 3 -40 4 -127 6 58 8 11 10 -7 11 3 14 31 16 63 18 81 20 66 22 2 24 -124 25 -64 26 -76 27 103 28 -26 28 67 29 -111 29 -27 29 80 30 -32 30 -99 31 -115 32 14 32 56 33 -128 34 -41 35 43 37 104 38 124 39 95 40 12 41 -114 41 -11 41 91 42 -40 42 -124 43 107 44 -108 45 -2 46 -95 48 112 50 89 52 71 54 38 56 -27 57 126 59 -19 60 51 62 82 63 70 64 12 65 -96 65 -4 65 26 66 -13 65 126 65 -76 64 -110 63 31 62 109 60 -108 58 -84 56 -53 54 -1 52 76 51 -81 49 33 48 -102 46 18 45 -123 43 -14 41 90 40 -64 38 40 37 -110 35 -4 33 98 32 -64 30 20 29 99 27 -71 25 41 24 -57 22 -93 21 -57 20 48 20 -52 19 -127 19 48 19 -69 18 12 18 28 17 -16 15 -101 14 55 13 -36 11 -97 10 -122 9 -113 8 -81 7 -38 6 6 6 43 5 63 4 54 3 2 2 -104 0 -10 -2 37 -3 58 -5 85 -7 -105 -9 25 -10 -19 -12 22 -12 -115 -13 64 -13 19 -13 -27 -14 -111 -14 -10 -15 -2 -16 -96 -17 -23 -19 -12 -21 -22 -23 -12 -25 58 -26 -39 -28 -26 -29 105 -29 100 -29 -48 -29 -95 -28 -60 -27 30 -25 -111 -24 0 -22 88 -21 -106 -20 -63 -19 -23 -18 27 -16 85 -15 -117 -14 -87 -13 -95 -12 108 -11 19 -10 -91 -10 47 -9 -74 -9 44 -8 121 -8 125 -8 30 -8 81 -9 32 -10 -92 -12 0 -13 88 -15 -63 -17 68 -18 -34 -20 -119 -21 64 -22 9 -23 -15 -25 7 -25 82 -26 -50 -27 110 -27 27 -27 -63 -28 80 -28 -61 -29 28 -29 99 -30 -98 -31 -45 -32 6 -32 56 -33 107 -34 -95 -35 -35 -36 31 -36 103 -37 -83 -38 -17 -39 39 -39 88 -40 -123 -41 -73 -42 -15 -43 49 -43 114 -44 -87 -45 -47 -46 -19 -47 11 -47 64 -48 -87 -49 99 -49 -124 -49 24 -48 24 -47 111 -46 -4 -45 -106 -43 26 -41 110 -40 -122 -39 100 -38 18 -37 -96 -37 23 -36 125 -36 -54 -36 -14 -36 -24 -36 -90 -36 43 -36 -121 -37 -49 -38 29 -38 -117 -39 49 -39 36 -39 121 -39 65 -38 -126 -37 56 -35 79 -33 -91 -31 16 -28 103 -26 -116 -24 110 -22 15 -20 126 -19 -46 -18 37 -16 -121 -15 -1 -14 -122 -12 15 -10 -114 -9 -7 -8 82 -6 -94 -5 -11 -4 87 -2 -52 -1 79 1 -38 2 105 4 -3 5 -98 7 88 9 49 11 42 13 58 15 81 17 93 19 75 21 10 23 -116 24 -56 25 -71 26 101 27 -38 27 41 28 104 28 -86 28 2 29 126 29 41 30 8 31 -114 30 -83 31 -19 32 64 34 -109 35 -47 36 -24 37 -53 38 116 39 -20 39 69 40 -105 40 -1 40 -108 41 102 42 124 43 -43 44 106 46 45 48 15 50 -7 51 -43 53 -109 55 40 57 -109 58 -42 59 -13 60 -23 61 -76 62 77 63 -78 63 -36 63 -60 63 98 63 -85 62 -101 61 54 60 -115 58 -72 56 -43 54 -7 52 53 51 -116 49 -4 47 126 46 6 45 -113 43 17 42 -116 40 2 39 118 37 -21 35 99 34 -36 32 83 31 -63 29 35 28 124 26 -41 24 71 23 -30 21 -68 20 -32 19 78 19 -9 18 -65 18 -123 18 40 18 -113 17 -80 16 -112 15 64 14 -35 12 -125 11 72 10 53 9 72 8 116 7 -83 6 -25 5 26 5 64 4 77 3 49 2 -34 0 77 -1 -122 -3 -97 -5 -72 -7 -12 -9 112 -10 64 -11 105 -12 -28 -13 -94 -13 -121 -13 113 -13 58 -13 -67 -14 -32 -15 -105 -16 -20 -18 -6 -20 -21 -22 -21 -24 34 -25 -77 -27 -79 -28 38 -28 19 -28 116 -28 60 -27 90 -26 -76 -25 43 -23 -97 -22 -9 -21 46 -19 77 -18 105 -17 -111 -16 -57 -15 0 -13 35 -12 30 -11 -24 -11 -119 -10 20 -9 -102 -9 35 -8 -90 -8 7 -7 36 -7 -34 -8 36 -8 -3 -10 -124 -11 -32 -13 55 -14 -94 -16 45 -17 -47 -19 -124 -20 65 -21 11 -22 -15 -24 4 -24 79 -25 -47 -26 124 -26 55 -26 -21 -27 -121 -27 4 -27 100 -28 -79 -29 -15 -30 45 -30 102 -31 -98 -32 -41 -33 19 -33 84 -34 -100 -35 -21 -36 59 -36 -122 -37 -58 -38 -3 -39 46 -39 100 -40 -94 -41 -21 -42 54 -42 118 -43 -91 -44 -61 -45 -38 -46 2 -46 88 -47 -4 -48 8 -47 -120 -47 125 -46 -48 -45 95 -43 1 -41 -114 -40 -24 -39 2 -37 -34 -37 -121 -36 15 -35 -125 -35 -24 -35 58 -34 107 -34 107 -34 47 -34 -74 -35 13 -35 76 -36 -115 -37 -23 -38 122 -38 84 -38 -115 -38 56 -37 95 -36 0 -34 10 -32 90 -30 -59 -28 30 -25 68 -23 33 -21 -74 -20 20 -18 83 -17 -113 -16 -35 -15 69 -13 -63 -12 66 -10 -71 -9 25 -7 99 -6 -96 -5 -33 -4 46 -2 -110 -1 7 1 -123 2 3 4 -124 5 15 7 -79 8 118 10 93 12 96 14 110 16 116 18 95 20 29 22 -97 23 -38 24 -55 25 112 26 -36 26 31 27 78 27 -128 27 -58 27 48 28 -56 28 -107 29 -8 28 11 30 66 31 -112 32 -31 33 33 35 59 36 30 37 -59 37 53 38 127 38 -67 38 13 39 -118 39 68 40 69 41 -117 42 14 44 -58 45 -97 47 -123 49 95 51 26 53 -86 54 16 56 78 57 105 58 96 59 46 60 -50 60 58 61 111 61 104 61 26 61 120 60 124 59 38 58 -121 56 -71 54 -38 52 3 51 70 49 -87 47 39 46 -71 44 83 43 -19 41 -128 40 11 39 -112 37 17 36 -108 34 27 33 -90 31 47 30 -81 28 33 27 -123 25 -26 23 86 22 -18 20 -61 19 -25 18 90 18 15 18 -22 17 -55 17 -122 17 7 17 60 16 41 15 -33 13 125 12 34 11 -23 9 -37 8 -7 7 51 7 121 6 -63 5 4 5 61 4 97 3 95 2 37 1 -86 -1 -16 -3 14 -4 36 -6 90 -8 -49 -10 -102 -11 -62 -12 66 -12 9 -12 0 -12 2 -12 -22 -13 -113 -13 -48 -14 -96 -15 4 -16 23 -18 3 -20 -9 -23 32 -24 -95 -26 -113 -27 -10 -28 -43 -28 39 -27 -28 -27 -4 -26 86 -24 -47 -23 74 -21 -93 -20 -45 -19 -27 -18 -15 -17 12 -15 61 -14 120 -13 -94 -12 -95 -11 106 -10 5 -9 -122 -9 5 -8 -113 -8 29 -7 -109 -7 -52 -7 -94 -7 -2 -8 -28 -9 111 -10 -56 -12 29 -13 -118 -15 29 -16 -51 -18 -115 -19 82 -20 30 -21 1 -22 15 -23 89 -24 -32 -25 -105 -25 97 -25 38 -25 -49 -26 87 -26 -65 -27 18 -27 88 -28 -102 -29 -37 -30 27 -30 90 -31 -101 -32 -30 -33 49 -33 -120 -34 -30 -35 56 -35 -126 -36 -64 -37 -11 -38 44 -38 112 -39 -64 -40 21 -40 99 -41 -101 -42 -69 -43 -51 -44 -23 -45 44 -45 -72 -46 -86 -46 21 -45 -6 -45 72 -43 -38 -42 -124 -40 26 -38 124 -37 -104 -36 114 -35 21 -34 -107 -34 3 -33 104 -33 -64 -33 -5 -33 6 -32 -45 -33 93 -33 -79 -34 -25 -35 26 -35 102 -36 -30 -37 -94 -37 -66 -37 72 -36 81 -35 -38 -34 -44 -32 29 -29 -120 -27 -27 -25 12 -22 -26 -21 112 -19 -69 -18 -30 -17 5 -15 60 -14 -110 -13 2 -11 123 -10 -22 -9 64 -7 122 -6 -94 -5 -53 -4 5 -2 87 -1 -66 0 46 2 -99 3 9 5 124 6 4 8 -79 9 -123 11 121 13 125 15 124 17 99 19 32 21 -94 22 -34 23 -53 24 110 25 -48 25 7 26 39 26 71 26 122 26 -48 26 85 27 16 28 117 27 123 28 -88 29 -17 30 63 32 -128 33 -99 34 -125 35 41 36 -110 36 -50 36 -8 36 50 37 -105 37 59 38 39 39 89 40 -52 41 117 43 69 45 37 47 -3 48 -74 50 65 52 -96 53 -40 54 -17 55 -25 56 -72 57 92 58 -49 58 13 59 20 59 -39 58 78 58 103 57 34 56 -115 54 -59 52 -22 50 24 49 98 47 -49 45 92 44 -3 42 -87 41 84 40 -8 38 -109 37 37 36 -76 34 68 33 -38 31 117 30 16 29 -93 27 38 26 -105 24 -1 22 112 21 4 20 -43 18 -10 17 107 17 43 17 24 17 14 17 -26 16 -128 16 -54 15 -59 14 -126 13 33 12 -60 10 -118 9 -126 8 -86 7 -15 6 70 6 -101 5 -21 4 51 4 108 3 -123 2 102 1 0 0 86 -2 121 -4 -114 -6 -67 -8 43 -9 -15 -11 23 -11 -103 -12 104 -12 109 -12 -122 -12 -117 -12 81 -12 -77 -13 -99 -14 17 -15 42 -17 20 -19 -1 -22 27 -23 -115 -25 109 -26 -58 -27 -105 -27 -35 -27 -114 -26 -99 -25 -10 -24 117 -22 -11 -21 81 -19 124 -18 127 -17 120 -16 -124 -15 -82 -14 -21 -13 28 -11 34 -10 -21 -10 126 -9 -12 -9 105 -8 -16 -8 -122 -7 16 -6 101 -6 88 -6 -52 -7 -64 -8 78 -9 -91 -11 -10 -13 100 -14 -2 -16 -69 -17 -119 -18 88 -19 40 -20 7 -21 15 -22 86 -23 -31 -24 -93 -24 125 -24 82 -24 10 -24 -100 -25 12 -25 100 -26 -80 -27 -8 -28 64 -28 -121 -29 -51 -30 20 -30 96 -31 -76 -32 19 -32 120 -33 -40 -34 45 -34 113 -35 -86 -36 -28 -37 42 -37 -126 -38 -29 -39 61 -39 -127 -40 -90 -41 -74 -42 -57 -43 -7 -44 110 -44 71 -44 -101 -44 112 -43 -74 -42 74 -40 -4 -39 -100 -37 5 -35 36 -34 -5 -34 -105 -33 15 -32 118 -32 -39 -32 52 -31 122 -31 -110 -31 104 -31 -8 -32 74 -32 120 -33 -97 -34 -36 -35 69 -35 -16 -36 -17 -36 90 -35 68 -34 -77 -33 -100 -31 -35 -29 72 -26 -87 -24 -46 -22 -87 -20 41 -18 98 -17 114 -16 123 -15 -101 -14 -34 -13 66 -11 -76 -10 29 -8 106 -7 -106 -6 -85 -5 -67 -4 -31 -3 34 -1 124 0 -31 1 66 3 -101 4 -10 5 100 7 -8 8 -72 10 -99 12 -107 14 -115 16 111 18 42 20 -83 21 -23 22 -41 23 117 24 -48 24 -5 24 13 25 29 25 62 25 -126 25 -12 25 -99 26 -9 25 -17 26 17 28 82 29 -97 30 -30 31 2 33 -20 33 -109 34 -9 34 38 35 62 35 96 35 -83 35 58 36 17 37 48 38 -111 39 42 41 -16 42 -53 44 -94 46 89 48 -32 49 54 51 102 52 120 53 111 54 68 55 -19 55 100 56 -86 56 -67 56 -107 56 33 56 81 55 30 54 -107 52 -46 50 -7 48 43 47 124 45 -13 43 -114 42 64 41 -3 39 -70 38 111 37 25 36 -70 34 86 33 -13 31 -106 30 65 29 -18 27 -107 26 43 25 -85 23 28 22 -113 20 31 19 -23 17 5 17 123 16 67 16 66 16 80 16 67 16 -8 15 88 15 98 14 39 13 -58 11 102 10 42 9 37 8 87 7 -82 6 17 6 114 5 -51 4 36 4 113 3 -92 2 -94 1 86 0 -68 -2 -25 -4 -6 -6 35 -7 -119 -9 73 -10 108 -11 -17 -12 -59 -12 -42 -12 4 -11 38 -11 14 -11 -109 -12 -103 -13 32 -14 65 -16 41 -18 11 -20 26 -22 126 -24 80 -25 -101 -26 96 -26 -104 -26 59 -25 65 -24 -107 -23 25 -21 -95 -20 3 -18 42 -17 30 -16 1 -15 -6 -15 27 -13 90 -12 -108 -11 -94 -10 109 -9 -7 -9 97 -8 -55 -8 73 -7 -27 -7 -126 -6 -12 -6 7 -5 -106 -6 -102 -7 44 -8 127 -10 -54 -12 55 -13 -40 -15 -92 -16 -125 -17 94 -18 50 -19 13 -20 13 -21 79 -22 -36 -23 -88 -23 -108 -23 122 -23 65 -23 -34 -24 85 -24 -78 -25 2 -25 81 -26 -96 -27 -17 -28 61 -28 -119 -29 -40 -30 50 -30 -104 -31 6 -31 115 -32 -45 -33 32 -33 92 -34 -105 -35 -33 -36 61 -36 -86 -37 19 -37 100 -38 -111 -39 -96 -40 -88 -41 -55 -42 39 -42 -26 -43 32 -42 -30 -42 31 -40 -76 -39 110 -37 24 -35 -118 -34 -83 -33 -126 -32 23 -31 -123 -31 -29 -31 66 -30 -95 -30 -16 -30 22 -29 -6 -30 -112 -30 -30 -31 8 -31 36 -32 84 -33 -83 -34 66 -34 39 -34 114 -34 58 -33 -115 -32 99 -30 -101 -28 6 -25 108 -23 -103 -21 112 -19 -24 -18 15 -16 7 -15 -11 -15 -4 -14 43 -12 -125 -11 -18 -10 83 -8 -103 -7 -72 -6 -71 -5 -77 -4 -64 -3 -18 -2 59 0 -105 1 -19 2 52 4 118 5 -55 6 66 8 -20 9 -62 11 -80 13 -97 15 123 17 52 19 -73 20 -10 21 -28 22 -128 23 -45 23 -13 23 -9 23 -9 23 8 24 57 24 -104 24 46 25 116 24 92 25 115 26 -85 27 -11 28 57 30 95 31 77 32 -9 32 87 33 124 33 -128 33 -119 33 -68 33 50 34 -12 34 -1 35 76 37 -44 38 -116 40 98 42 56 44 -18 45 112 47 -67 48 -30 49 -19 50 -28 51 -68 52 105 53 -28 53 47 54 78 54 57 54 -33 53 40 53 9 52 -115 50 -49 48 -7 46 46 45 -124 43 6 42 -81 40 114 39 65 38 17 37 -39 35 -109 34 67 33 -20 31 -106 30 70 29 1 28 -63 26 125 25 40 24 -70 22 52 21 -87 19 53 18 -8 16 13 16 -126 15 80 15 95 15 -122 15 -106 15 103 15 -32 14 -4 13 -54 12 106 11 5 10 -61 8 -64 7 -3 6 100 6 -40 5 69 5 -86 4 13 4 110 3 -67 2 -37 1 -84 0 38 -1 88 -3 106 -5 -117 -7 -23 -9 -95 -10 -64 -11 68 -11 30 -11 58 -11 123 -11 -70 -11 -57 -11 114 -11 -103 -12 54 -13 97 -15 71 -17 32 -19 34 -21 119 -23 59 -24 122 -25 49 -25 91 -25 -17 -25 -24 -24 54 -22 -66 -21 80 -19 -68 -18 -30 -17 -58 -16 -112 -15 112 -14 -124 -13 -59 -12 11 -10 37 -9 -13 -9 119 -8 -48 -8 38 -7 -99 -7 59 -6 -21 -6 123 -5 -78 -5 96 -5 120 -6 15 -7 92 -9 -98 -11 8 -12 -80 -14 -116 -15 126 -16 106 -17 68 -18 27 -19 17 -20 74 -21 -40 -22 -81 -22 -84 -22 -90 -22 125 -22 38 -22 -92 -23 5 -23 91 -24 -81 -25 6 -25 94 -26 -77 -27 5 -27 89 -28 -74 -29 35 -29 -100 -30 22 -30 -125 -31 -39 -32 26 -32 84 -33 -100 -34 -1 -35 121 -35 -12 -36 85 -36 -116 -37 -100 -38 -100 -39 -83 -40 -13 -41 -106 -41 -75 -41 96 -40 -111 -39 38 -37 -23 -36 -96 -34 28 -32 68 -31 23 -30 -92 -30 7 -29 90 -29 -78 -29 19 -28 110 -28 -92 -28 -104 -28 56 -28 -118 -29 -87 -30 -70 -31 -35 -32 40 -32 -86 -33 115 -33 -100 -33 65 -32 116 -31 51 -29 97 -27 -52 -25 55 -22 107 -20 67 -18 -77 -17 -54 -16 -88 -15 121 -14 99 -13 125 -12 -57 -11 44 -9 -114 -8 -49 -7 -29 -6 -48 -5 -79 -4 -93 -3 -67 -2 -3 -1 81 1 -98 2 -44 3 -3 4 49 6 -116 7 32 9 -27 10 -56 12 -82 14 -125 16 55 18 -69 19 -3 20 -19 21 -121 22 -44 22 -24 22 -34 22 -49 22 -49 22 -18 22 58 23 -68 23 -39 22 -79 23 -71 24 -27 25 40 27 105 28 -112 29 -126 30 45 31 -116 31 -88 31 -101 31 -115 31 -89 31 6 32 -77 32 -86 33 -31 34 82 36 -7 37 -60 39 -107 41 72 43 -62 44 2 46 24 47 24 48 11 49 -28 49 -108 50 16 51 93 51 -125 51 127 51 62 51 -94 50 -100 49 48 48 124 46 -84 44 -25 42 71 41 -42 39 -113 38 101 37 73 36 45 35 8 34 -42 32 -105 31 80 30 7 29 -57 27 -110 26 103 25 59 24 -2 22 -91 21 46 20 -86 18 54 17 -12 15 3 15 118 14 73 14 100 14 -95 14 -51 14 -70 14 76 14 124 13 86 12 -6 10 -109 9 78 8 77 7 -107 6 14 6 -108 5 15 5 124 4 -24 3 91 3 -59 2 5 2 -10 0 -119 -1 -55 -3 -33 -5 -2 -7 87 -8 11 -9 41 -10 -83 -11 -117 -11 -83 -11 -3 -11 84 -10 -124 -10 85 -10 -97 -11 86 -12 -112 -14 123 -16 83 -18 78 -20 -103 -22 83 -23 -119 -24 55 -24 84 -24 -40 -24 -65 -23 1 -21 -120 -20 34 -18 -105 -17 -68 -16 -113 -15 60 -14 -1 -14 1 -12 64 -11 -113 -10 -76 -9 -122 -8 2 -7 74 -7 -116 -7 -12 -7 -113 -6 76 -5 -9 -5 81 -4 33 -4 80 -5 -16 -7 59 -8 119 -10 -32 -12 -112 -13 126 -14 -120 -15 -119 -16 110 -17 69 -18 49 -19 97 -20 -19 -21 -50 -21 -35 -21 -21 -21 -45 -21 -121 -21 13 -21 115 -22 -51 -23 39 -23 -120 -24 -22 -25 73 -25 -94 -26 -5 -27 93 -27 -48 -28 83 -28 -37 -29 87 -29 -70 -30 1 -30 60 -31 -125 -32 -22 -33 113 -33 -1 -34 115 -34 -72 -35 -51 -36 -54 -37 -49 -38 4 -38 -115 -39 -113 -39 33 -38 65 -37 -47 -36 -103 -34 88 -32 -37 -31 5 -29 -44 -29 89 -28 -80 -28 -10 -28 69 -27 -91 -27 8 -26 79 -26 85 -26 1 -26 86 -27 113 -28 121 -29 -108 -30 -43 -31 74 -31 -3 -32 7 -31 -121 -31 -105 -30 59 -28 88 -26 -68 -24 39 -21 93 -19 52 -17 -101 -16 -96 -15 101 -14 23 -13 -29 -13 -28 -12 29 -10 122 -9 -40 -8 20 -6 28 -5 -10 -5 -69 -4 -111 -3 -109 -2 -60 -1 15 1 84 2 123 3 -119 4 -100 5 -41 6 80 8 2 10 -43 11 -82 13 118 15 34 17 -95 18 -29 19 -43 20 109 21 -77 21 -67 21 -89 21 -117 21 124 21 -117 21 -60 21 51 22 47 21 -11 21 -20 22 10 24 68 25 -126 26 -85 27 -95 28 80 29 -82 29 -61 29 -90 29 -128 29 125 29 -61 29 92 30 63 31 95 32 -73 33 70 35 4 37 -47 38 -126 40 -10 41 39 43 41 44 27 45 8 46 -27 46 -104 47 21 48 96 48 -118 48 -106 48 112 48 -11 47 10 47 -80 45 7 44 60 42 125 40 -25 38 -125 37 78 36 56 35 50 34 43 33 28 32 -2 30 -47 29 -101 28 98 27 48 26 12 25 -10 23 -30 22 -64 21 -128 20 28 19 -95 17 45 16 -27 14 -18 13 91 13 48 13 88 13 -86 13 -13 13 -1 13 -83 13 -13 12 -36 11 -121 10 29 9 -47 7 -50 6 33 6 -81 5 77 5 -42 4 73 4 -69 3 60 3 -61 2 41 2 64 1 -16 -1 65 -2 92 -4 120 -6 -53 -8 123 -9 -105 -10 28 -10 -4 -11 35 -10 125 -10 -20 -10 63 -9 59 -9 -83 -10 -126 -11 -51 -13 -64 -15 -104 -17 -115 -19 -49 -21 127 -22 -84 -23 82 -23 100 -23 -42 -23 -89 -22 -40 -21 90 -19 -2 -18 -127 -16 -86 -15 109 -14 -8 -14 -107 -13 127 -12 -70 -11 21 -9 73 -8 34 -7 -105 -7 -53 -7 -11 -7 73 -6 -35 -6 -93 -5 107 -4 -21 -4 -29 -4 45 -4 -38 -6 34 -7 85 -9 -71 -11 113 -12 115 -13 -103 -14 -76 -15 -87 -16 -128 -17 97 -18 -125 -19 11 -19 -11 -20 25 -19 61 -19 55 -19 -9 -20 -123 -20 -15 -21 79 -21 -81 -22 24 -22 -121 -23 -14 -24 83 -24 -80 -25 22 -25 -113 -26 28 -26 -78 -27 63 -27 -78 -28 3 -28 61 -29 -128 -30 -24 -31 125 -31 33 -31 -84 -32 1 -32 30 -33 25 -34 22 -35 57 -36 -88 -37 -118 -37 -3 -37 9 -35 -110 -34 94 -32 39 -30 -78 -29 -34 -28 -86 -27 39 -26 112 -26 -89 -26 -23 -26 69 -25 -79 -25 10 -24 37 -24 -31 -25 60 -25 83 -26 82 -27 100 -28 -97 -29 10 -29 -86 -30 -109 -30 -21 -30 -45 -29 86 -27 95 -25 -69 -23 38 -20 95 -18 54 -16 -106 -15 -118 -14 52 -13 -58 -13 112 -12 84 -11 122 -10 -50 -9 41 -7 98 -6 97 -5 38 -4 -49 -4 -123 -3 106 -2 -118 -1 -49 0 14 2 39 3 26 4 8 5 30 6 120 7 21 9 -38 10 -92 12 94 14 -4 15 119 17 -71 18 -82 19 70 20 -122 20 -123 20 99 20 58 20 29 20 27 20 65 20 -100 20 -109 19 73 20 46 21 61 22 107 23 -90 24 -48 25 -54 26 126 27 -33 27 -16 27 -59 27 -122 27 102 27 -111 27 23 28 -22 28 -12 29 48 31 -91 32 82 34 28 36 -49 37 63 39 97 40 76 41 42 42 16 43 -14 43 -83 44 41 45 111 45 -104 45 -79 45 -89 45 79 45 -126 44 61 43 -99 41 -41 39 29 38 -113 36 57 35 20 34 19 33 34 32 49 31 54 30 45 29 19 28 -19 26 -61 25 -97 24 -118 23 -121 22 -116 21 -122 20 97 19 18 18 -95 16 46 15 -32 13 -32 12 71 12 27 12 76 12 -77 12 24 13 68 13 14 13 107 12 102 11 26 10 -83 8 87 7 77 6 -88 5 79 5 7 5 -96 4 23 4 -119 3 21 3 -73 2 68 2 -123 1 84 0 -72 -2 -40 -4 -14 -6 63 -7 -23 -9 3 -9 -119 -10 107 -10 -108 -10 -12 -10 118 -9 -21 -9 21 -8 -78 -9 -89 -10 5 -11 0 -13 -39 -16 -55 -18 3 -19 -88 -21 -52 -22 108 -22 117 -22 -41 -22 -111 -21 -85 -20 35 -18 -47 -17 104 -15 -100 -14 82 -13 -71 -13 41 -12 -12 -12 41 -10 -109 -9 -37 -8 -67 -7 44 -6 76 -6 92 -6 -104 -6 31 -5 -20 -5 -50 -4 119 -3 -103 -3 5 -3 -65 -5 4 -6 43 -8 -121 -10 68 -11 90 -12 -98 -13 -41 -14 -32 -15 -70 -16 -115 -17 -99 -18 27 -18 14 -18 72 -18 -124 -18 -111 -18 94 -18 -13 -19 100 -19 -59 -20 41 -20 -101 -21 23 -21 -112 -22 -6 -23 90 -23 -62 -24 64 -24 -42 -25 122 -25 25 -25 -98 -26 -5 -27 53 -27 112 -28 -43 -29 117 -29 50 -29 -40 -30 64 -30 101 -31 96 -32 85 -33 106 -34 -63 -35 -126 -35 -45 -35 -59 -34 70 -32 24 -30 -20 -29 127 -27 -82 -26 119 -25 -20 -25 41 -24 79 -24 -127 -24 -43 -24 72 -23 -75 -23 -23 -23 -72 -23 27 -23 45 -24 34 -25 43 -26 99 -27 -55 -28 89 -28 36 -28 81 -28 14 -27 111 -26 98 -24 -76 -22 31 -19 93 -17 54 -15 -111 -14 117 -13 6 -12 120 -12 -2 -12 -62 -11 -45 -10 31 -8 122 -7 -78 -6 -86 -5 94 -4 -21 -4 125 -3 67 -2 80 -1 -112 0 -49 1 -33 2 -71 3 -128 4 109 5 -89 6 49 8 -24 9 -92 11 77 13 -35 14 80 16 -108 17 -114 18 40 19 98 19 87 19 39 19 -13 18 -54 18 -71 18 -52 18 18 19 44 18 -45 18 -87 19 -88 20 -54 21 1 23 46 24 45 25 -28 25 73 26 91 26 39 26 -47 25 -109 25 -91 25 28 26 -29 26 -36 27 -3 28 85 30 -15 31 -72 33 113 35 -30 36 -9 37 -54 38 -111 39 110 40 86 41 27 42 -102 42 -41 42 -7 42 26 43 42 43 -11 42 71 42 21 41 125 39 -70 37 3 36 124 34 49 33 28 32 44 31 78 30 113 29 -119 28 -110 27 -118 26 115 25 85 24 60 23 51 22 64 21 90 20 111 19 100 18 42 17 -59 15 82 14 -2 12 -10 11 85 11 37 11 91 11 -46 11 83 12 -99 12 -126 12 -14 11 -2 10 -67 9 81 8 -18 6 -42 5 53 5 -12 4 -53 4 118 4 -19 3 89 3 -22 2 -94 2 85 2 -65 1 -81 0 36 -1 73 -3 96 -5 -89 -7 74 -8 97 -9 -22 -10 -50 -10 -8 -10 88 -9 -27 -9 121 -8 -50 -8 -106 -8 -85 -9 26 -10 29 -12 -9 -15 -27 -17 23 -18 -78 -20 -51 -21 105 -21 110 -21 -60 -21 101 -20 101 -19 -49 -18 -124 -16 51 -14 122 -13 42 -12 108 -12 -83 -12 83 -11 -128 -10 -5 -9 91 -7 75 -6 -75 -6 -62 -6 -72 -6 -38 -6 81 -5 30 -4 22 -3 -25 -3 53 -2 -62 -3 -116 -4 -51 -6 -27 -8 53 -9 -12 -11 28 -11 124 -12 -44 -13 -11 -14 -44 -15 -102 -16 -110 -17 3 -17 -4 -18 76 -17 -94 -17 -63 -17 -105 -17 51 -17 -87 -18 13 -18 114 -19 -22 -20 115 -20 -5 -21 110 -21 -49 -22 55 -22 -71 -23 87 -23 5 -23 -76 -24 77 -24 -71 -25 -12 -26 34 -26 127 -27 39 -27 -2 -28 -64 -28 59 -28 104 -29 99 -30 84 -31 94 -32 -94 -33 69 -33 115 -33 74 -32 -64 -31 -104 -29 121 -27 22 -25 72 -24 14 -23 124 -23 -81 -23 -58 -23 -26 -23 47 -22 -91 -22 37 -21 115 -21 88 -21 -60 -22 -47 -23 -69 -24 -69 -25 -15 -26 88 -26 -32 -27 -112 -27 -107 -27 40 -26 103 -25 69 -23 -115 -21 -8 -19 60 -16 26 -14 115 -13 75 -12 -58 -12 26 -11 127 -11 35 -10 31 -9 99 -8 -64 -7 -5 -6 -17 -5 -105 -4 12 -3 124 -3 32 -2 25 -1 87 0 -100 1 -86 2 111 3 16 4 -44 4 -18 5 102 7 21 9 -58 10 95 12 -35 13 71 15 -114 16 -112 17 46 18 100 18 78 18 19 18 -43 17 -92 17 -121 17 -120 17 -69 17 -68 16 85 17 27 18 7 19 25 20 75 21 124 22 -126 23 63 24 -88 24 -65 24 -122 24 25 24 -74 23 -89 23 15 24 -47 24 -68 25 -67 26 -15 27 118 29 58 31 -1 32 120 34 -127 35 54 36 -35 36 -83 37 -97 38 119 39 -6 39 42 40 60 40 96 40 -114 40 -125 40 -4 39 -34 38 77 37 -117 35 -42 33 84 32 20 31 15 30 51 29 106 28 -96 27 -53 26 -25 25 -14 24 -20 23 -37 22 -51 21 -49 20 -22 19 26 19 75 18 95 17 63 16 -25 14 117 13 25 12 5 11 91 10 36 10 90 10 -32 10 -128 11 -17 11 -15 11 117 11 -111 10 97 9 -6 7 -122 6 84 5 -81 4 -116 4 -114 4 82 4 -59 3 35 3 -79 2 127 2 93 2 -7 1 16 1 -103 -1 -63 -3 -44 -5 20 -6 -81 -8 -64 -9 74 -9 53 -9 94 -9 -71 -9 74 -8 -4 -8 -123 -7 -125 -7 -70 -8 59 -9 69 -11 34 -13 14 -15 56 -17 -58 -19 -42 -20 109 -20 114 -20 -64 -20 71 -19 35 -18 117 -17 49 -15 2 -13 105 -12 26 -11 52 -11 54 -11 -85 -11 -53 -10 92 -8 -33 -7 -28 -6 74 -5 64 -5 24 -5 29 -5 124 -5 68 -4 81 -3 79 -2 -47 -2 -119 -2 103 -3 -92 -5 -88 -7 -28 -9 -97 -10 -37 -11 92 -11 -40 -12 23 -12 3 -13 -71 -15 -112 -16 -24 -17 -26 -17 83 -16 -54 -16 -4 -16 -37 -16 124 -16 -8 -17 96 -17 -60 -18 61 -18 -44 -19 113 -19 -14 -20 82 -20 -76 -21 58 -21 -30 -22 -101 -22 86 -22 6 -22 -118 -23 -53 -24 -26 -25 45 -25 -37 -26 -46 -26 -70 -26 76 -26 -128 -27 123 -28 104 -29 106 -30 -100 -31 32 -31 35 -31 -43 -31 61 -29 30 -27 17 -25 -68 -24 -16 -23 -77 -22 27 -21 69 -21 77 -21 86 -21 -116 -21 3 -20 -103 -20 7 -19 8 -19 -127 -20 -117 -21 100 -22 86 -23 -117 -24 -6 -25 -128 -25 22 -25 -19 -26 77 -25 101 -24 44 -22 106 -20 -43 -18 33 -15 9 -13 99 -12 47 -11 -109 -11 -54 -11 11 -10 -120 -10 104 -9 -91 -8 9 -6 74 -5 61 -4 -38 -4 56 -3 -126 -3 -5 -3 -39 -2 22 0 106 1 125 2 47 3 -89 3 57 4 44 5 -110 6 61 8 -24 9 109 11 -44 12 50 14 125 15 -117 16 49 17 100 17 65 17 -8 16 -81 16 120 16 82 16 65 16 92 16 110 15 -2 15 -71 16 -112 17 -112 18 -69 19 -11 20 5 22 -59 22 49 23 80 23 28 23 -100 22 14 22 -41 21 49 22 -8 22 -35 23 -65 24 -56 25 48 27 -12 28 -53 30 84 32 88 33 -18 33 107 34 38 35 38 36 27 37 -86 37 -55 37 -64 37 -32 37 43 38 81 38 -13 37 -21 36 94 35 -104 33 -31 31 100 30 44 29 52 28 106 27 -75 26 -2 25 58 25 104 24 -123 23 -113 22 -119 21 -125 20 -114 19 -76 18 -11 17 65 17 118 16 113 15 40 14 -75 12 78 11 45 10 120 9 58 9 108 9 -5 9 -71 10 82 11 117 11 7 11 45 10 18 9 -69 7 54 6 -39 4 33 4 33 4 92 4 62 4 -87 3 -16 2 116 2 83 2 92 2 45 2 113 1 12 0 53 -2 65 -4 122 -6 10 -7 16 -8 -101 -9 -111 -9 -66 -9 12 -8 -108 -8 96 -7 35 -6 93 -6 -71 -7 71 -8 84 -10 52 -12 32 -14 64 -16 -65 -18 -64 -19 83 -19 93 -19 -86 -19 27 -18 -53 -18 -6 -17 -71 -15 -77 -13 75 -11 9 -10 -6 -11 -77 -11 -22 -11 -7 -10 -90 -8 86 -6 120 -5 -37 -5 -72 -5 114 -5 89 -5 -100 -5 86 -4 116 -3 -95 -2 93 -1 68 -1 57 -2 115 -4 93 -6 122 -8 45 -9 124 -10 31 -10 -66 -11 31 -11 32 -12 -53 -14 117 -15 -90 -16 -90 -16 55 -15 -44 -15 27 -14 -2 -15 -95 -15 38 -15 -108 -16 -12 -17 103 -17 9 -17 -62 -18 86 -18 -79 -19 6 -19 -115 -20 68 -20 6 -20 -58 -21 -117 -21 51 -21 -126 -22 -126 -23 -92 -24 80 -24 112 -24 -124 -24 45 -24 102 -25 96 -26 73 -27 68 -28 107 -29 -46 -30 -89 -30 44 -29 -126 -28 113 -26 125 -24 56 -22 113 -21 46 -20 -111 -20 -74 -20 -78 -20 -94 -20 -66 -20 47 -19 -34 -19 114 -18 -111 -18 26 -18 34 -19 -25 -21 -61 -22 -11 -23 115 -23 2 -23 -125 -24 39 -24 81 -24 66 -23 -13 -22 39 -19 -110 -17 -23 -15 -30 -13 67 -11 4 -10 81 -10 111 -10 -113 -10 -30 -10 -97 -9 -42 -8 72 -6 -107 -5 -123 -4 29 -3 108 -3 -110 -3 -41 -3 -110 -2 -46 -1 62 1 97 2 5 3 84 3 -82 3 117 4 -54 5 122 7 38 9 -104 10 -29 11 48 13 -126 14 -93 15 85 16 -122 16 86 16 -4 15 -89 15 110 15 68 15 33 15 33 15 88 14 -26 14 -99 15 97 16 71 17 107 18 -77 19 -44 20 -105 21 -1 21 39 22 5 22 124 21 -68 20 79 20 -100 20 119 21 101 22 40 23 -1 23 71 25 13 27 -4 28 -98 30 -88 31 33 32 106 32 5 33 22 34 54 35 -37 35 -26 35 -74 35 -59 35 46 36 -118 36 89 36 101 35 -41 33 7 32 75 30 -47 28 -98 27 -83 26 -12 25 84 25 -84 24 -13 23 48 23 95 22 118 21 121 20 121 19 -120 18 -75 17 3 17 101 16 -71 15 -46 14 -105 13 34 12 -83 10 124 9 -67 8 120 8 -94 8 50 9 9 10 -46 10 29 11 -72 10 -39 9 -48 8 -100 7 15 6 114 4 -116 3 -79 3 59 4 68 4 -98 3 -61 2 54 2 30 2 78 2 90 2 -50 1 123 0 -101 -2 -100 -4 -47 -6 88 -7 75 -8 -50 -9 -41 -9 21 -8 80 -8 -68 -8 -105 -7 -101 -6 26 -5 -103 -6 44 -7 56 -9 26 -11 5 -13 29 -15 -117 -17 120 -18 2 -18 21 -18 110 -18 -48 -18 81 -17 80 -16 9 -14 49 -12 13 -10 -22 -10 -73 -10 28 -10 9 -10 1 -9 -50 -8 -74 -6 0 -4 97 -4 31 -4 -67 -5 -116 -5 -79 -5 81 -4 121 -3 -39 -2 -45 -1 -24 -1 -9 -2 48 -3 -2 -6 -16 -8 -114 -9 -13 -10 -68 -10 118 -10 -12 -11 25 -11 -61 -13 53 -14 42 -15 39 -15 -26 -15 -79 -14 12 -13 -18 -14 -115 -14 26 -14 -105 -15 -14 -16 80 -16 -11 -17 -45 -17 -122 -17 -41 -18 16 -18 -107 -19 101 -19 51 -19 -24 -20 -75 -20 -113 -20 2 -20 -30 -22 -62 -23 97 -23 -74 -23 3 -22 -67 -23 -11 -24 -17 -25 -44 -26 -58 -27 -24 -28 63 -28 -28 -29 47 -28 111 -27 116 -25 -94 -23 112 -21 -83 -20 103 -19 -62 -19 -28 -19 -34 -19 -72 -19 -84 -19 15 -18 -37 -18 -102 -17 -41 -17 114 -17 125 -18 45 -19 -25 -21 14 -21 -93 -22 75 -22 -67 -23 43 -23 26 -23 -25 -23 -120 -21 -74 -19 33 -16 -126 -14 -109 -12 7 -10 -66 -10 -17 -10 -7 -10 7 -9 47 -9 -69 -9 -22 -8 123 -6 -38 -5 -61 -4 84 -3 -91 -3 -79 -3 -71 -3 66 -2 -121 -1 28 1 88 2 -12 2 30 3 65 3 -47 3 21 5 -40 6 -110 8 -13 9 28 11 84 12 -83 13 -22 14 -82 15 -35 15 -96 15 52 15 -49 14 -108 14 114 14 68 14 32 14 37 13 -72 13 121 14 37 15 -32 15 -11 16 82 18 -112 19 88 20 -82 20 -42 20 -36 20 101 20 100 19 -100 18 -43 18 -35 19 -25 20 -120 21 22 22 43 23 -11 24 6 27 -59 28 -31 29 71 30 69 30 -97 30 -58 31 44 33 -10 33 -19 33 127 33 101 33 -16 33 -102 34 -98 34 -65 33 52 32 84 30 -116 28 28 27 -13 25 -1 24 85 24 -40 23 65 23 -118 22 -38 21 33 21 70 20 83 19 89 18 107 17 -97 16 -8 15 108 15 -26 14 40 14 0 13 -120 11 6 10 -66 8 -15 7 -81 7 -52 7 74 8 58 9 64 10 -61 10 111 10 116 9 105 8 -127 7 24 6 16 4 -70 2 18 3 37 4 102 4 -106 3 -116 2 -18 1 -43 1 40 2 -127 2 56 2 -6 0 11 -1 -8 -4 46 -5 -69 -7 -112 -8 -14 -9 24 -8 -118 -8 -81 -8 -45 -8 -81 -7 16 -5 -22 -5 -110 -5 35 -6 38 -8 16 -10 3 -12 18 -14 111 -16 69 -17 -70 -18 -41 -18 80 -17 -80 -17 -13 -17 -89 -16 73 -14 -92 -12 -34 -10 -5 -9 -93 -9 -102 -10 33 -10 -12 -10 -27 -8 24 -5 -96 -4 4 -3 -115 -4 4 -4 -49 -5 -45 -5 60 -4 99 -3 2 -1 75 0 -104 0 -65 -1 2 -2 -68 -5 111 -7 -38 -9 96 -9 111 -9 60 -9 -64 -10 38 -10 -6 -12 24 -13 -100 -15 -105 -15 -94 -14 -93 -13 20 -12 -10 -13 -125 -13 18 -13 -77 -14 23 -14 68 -15 -44 -16 -15 -16 -27 -16 37 -16 35 -17 -102 -18 -99 -18 -112 -18 31 -18 -47 -19 -9 -19 -58 -19 -124 -20 -25 -22 87 -22 11 -21 -70 -21 112 -21 -107 -22 -89 -23 -118 -24 96 -25 -123 -26 -28 -27 86 -27 68 -27 89 -26 -122 -24 -24 -22 -62 -20 2 -18 -65 -18 8 -17 33 -17 41 -17 -6 -18 -83 -18 -32 -18 -34 -17 -28 -16 49 -15 -37 -16 3 -16 -99 -18 28 -19 44 -20 -28 -21 -65 -21 49 -21 84 -22 -15 -23 -100 -22 48 -20 81 -18 -68 -16 34 -13 71 -11 -26 -10 -100 -9 -108 -9 -123 -9 -94 -9 -101 -9 -55 -9 -27 -8 -73 -6 59 -4 4 -3 -128 -3 -17 -3 -9 -3 -93 -3 -42 -3 32 -1 -4 0 95 2 -23 2 -12 2 -31 2 29 3 58 4 42 6 8 8 74 9 73 10 94 11 -79 12 34 14 7 15 32 15 -35 14 103 14 -33 13 -97 13 -104 13 110 13 19 13 -75 10 69 11 11 12 -123 12 -21 12 -66 13 6 15 48 16 -23 16 29 17 25 17 79 17 52 17 18 16 -31 14 -3 14 35 16 49 17 -97 17 -58 17 112 18 -4 19 -17 21 126 23 119 24 -22 24 -98 24 104 24 -118 25 34 27 -35 27 -43 27 65 27 -52 26 101 27 99 28 -121 28 -49 27 -110 26 -27 24 60 23 21 22 57 21 73 20 -77 19 -118 19 20 19 90 18 -33 17 100 17 -95 16 -34 15 26 15 59 14 -102 13 27 13 -103 12 76 12 -31 11 -19 10 -97 9 92 8 42 7 79 6 60 6 83 6 125 6 99 7 -120 8 34 9 -2 8 14 8 -38 6 107 6 -39 5 -120 3 -121 1 32 2 -57 3 61 4 61 3 27 2 -86 1 123 1 -68 1 111 2 116 2 107 1 -62 -1 -43 -3 72 -4 50 -5 29 -6 71 -7 115 -7 70 -6 101 -6 -15 -7 -106 -6 70 -4 79 -3 37 -3 -19 -5 23 -6 100 -8 -69 -10 -11 -12 -115 -13 -126 -14 -33 -15 -3 -15 -113 -14 -1 -14 -9 -14 41 -13 122 -12 -100 -10 -41 -8 56 -6 -49 -7 108 -8 -89 -9 32 -8 -15 -7 28 -4 -99 -3 37 -2 104 -3 -90 -4 -71 -4 -90 -4 -112 -4 -114 -3 53 -1 -118 0 18 1 89 0 -28 -2 9 -3 -53 -6 21 -7 -64 -8 74 -7 46 -7 116 -8 67 -8 -56 -9 -51 -11 -63 -13 -56 -13 43 -11 24 -10 -124 -10 -123 -10 1 -10 125 -11 105 -11 22 -11 18 -12 103 -13 -48 -13 65 -12 108 -13 73 -14 -76 -15 -36 -15 68 -14 -97 -15 -18 -16 110 -15 -31 -15 -67 -16 -80 -18 -52 -19 -42 -18 43 -16 -92 -17 -108 -18 57 -18 63 -19 -16 -21 74 -21 -18 -22 78 -22 -48 -23 109 -22 127 -20 -22 -18 86 -16 95 -15 56 -14 59 -14 61 -14 105 -14 69 -14 -33 -15 125 -15 -111 -14 27 -12 6 -12 -55 -13 101 -13 22 -14 124 -16 -113 -17 118 -17 -113 -17 65 -17 49 -18 95 -19 -6 -19 85 -17 -22 -16 34 -13 37 -11 -24 -10 -116 -8 92 -7 -24 -8 -109 -8 25 -7 -7 -8 123 -8 76 -7 69 -5 -53 -4 70 -3 93 -3 5 -2 80 -2 113 -3 71 -3 73 -2 63 0 -48 1 -48 1 1 2 -59 1 -101 1 61 2 16 4 64 6 -65 6 -118 7 -98 8 38 9 -25 10 13 12 -112 11 -112 11 104 11 -39 10 -51 10 -42 10 -51 10 -57 10 elektroid-3.2.3/test/res/connectors/microfreak_pwavetable.data.back000066400000000000000000001613051500236517400255250ustar00rootroot0000000000000022 serialization::archive 10 0 4 8 DEVBUILD 8 New Name 1 0 0 18 000000000000000000 0 0 1 16384 6 52 122 53 -29 54 70 56 -101 57 -28 58 39 60 96 61 -103 62 -36 63 49 65 -102 66 34 68 -57 69 -128 71 80 73 42 75 9 77 -27 78 -70 80 115 82 11 84 121 85 -66 86 -47 87 -84 88 69 89 -103 89 -86 89 123 89 4 89 65 88 63 87 -6 85 126 84 -44 82 1 81 22 79 21 77 4 75 -18 72 -41 70 -74 68 -107 66 116 64 83 62 50 60 11 58 -27 55 -66 53 -104 51 119 49 85 47 62 45 56 43 66 41 97 39 -107 37 -22 35 91 34 -21 32 -112 31 70 30 -5 28 -80 27 96 26 0 25 -109 23 24 22 -115 20 -3 18 109 17 -36 15 76 14 -63 12 54 11 -84 9 27 8 126 6 -48 4 15 3 62 1 93 -1 119 -3 -111 -5 -84 -7 -42 -9 21 -10 117 -12 -9 -14 -110 -15 71 -16 12 -17 -35 -19 -94 -20 88 -21 -3 -23 -120 -24 0 -25 112 -27 -32 -29 96 -30 -3 -32 -50 -33 -32 -34 53 -34 -40 -35 -48 -35 7 -34 -121 -34 67 -33 45 -32 58 -31 97 -30 -108 -29 -52 -28 5 -26 62 -25 113 -24 -107 -23 -94 -22 -102 -21 125 -20 63 -19 -30 -19 96 -18 -79 -18 -39 -18 -45 -18 -112 -18 20 -18 93 -19 111 -20 79 -21 3 -22 -107 -24 21 -25 -119 -27 -7 -29 110 -30 -18 -32 126 -33 35 -34 -29 -36 -72 -37 -97 -38 -102 -39 -97 -40 -81 -41 -59 -42 -37 -43 -21 -44 -4 -45 2 -45 2 -46 -8 -48 -19 -49 -29 -50 -39 -51 -50 -52 -60 -53 -70 -54 -80 -55 -91 -56 -91 -57 -90 -58 -90 -59 -84 -60 -76 -61 -59 -62 -38 -63 0 -63 55 -64 -127 -65 -25 -66 116 -66 45 -66 31 -66 75 -66 -80 -66 73 -65 27 -64 19 -63 39 -62 74 -61 109 -60 -123 -59 -115 -58 -125 -57 97 -56 30 -55 -65 -55 62 -54 -95 -54 -30 -54 15 -53 43 -53 61 -53 79 -53 110 -53 -87 -53 12 -52 -95 -52 120 -51 -114 -50 -14 -49 -104 -47 117 -45 -125 -43 -66 -41 10 -38 100 -36 -66 -34 14 -31 88 -29 -109 -27 -62 -25 -20 -23 12 -20 43 -18 74 -16 99 -14 125 -12 -105 -10 -79 -8 -51 -6 -20 -4 22 -1 69 1 -128 3 -65 5 10 8 100 10 -60 12 46 15 -103 17 2 20 109 22 -56 24 7 27 45 29 47 31 9 33 -69 34 65 36 -90 37 -18 38 33 40 74 41 114 42 -90 43 -30 44 49 46 -108 47 9 49 -116 50 106 51 -34 52 72 54 -81 55 6 57 79 58 -115 59 -62 60 -8 61 53 63 -125 64 -25 65 104 67 5 69 -69 70 -119 72 103 74 76 76 47 78 6 80 -60 81 102 83 -32 84 45 86 71 87 41 88 -48 88 54 89 87 89 48 89 -64 88 9 88 14 87 -47 85 89 84 -81 82 -36 80 -19 78 -24 76 -37 74 -59 72 -85 70 -112 68 117 66 91 64 54 62 18 60 -18 57 -54 55 -90 53 -126 51 94 49 68 47 45 45 33 43 40 41 68 39 121 37 -52 35 64 34 -46 32 123 31 55 30 -6 28 -69 27 112 26 26 25 -81 23 53 22 -84 20 29 19 -115 17 -2 15 112 14 -25 12 93 11 -44 9 69 8 -83 6 6 5 78 3 -125 1 -88 -1 -65 -3 -47 -5 -25 -7 12 -8 73 -10 -96 -12 29 -13 -68 -15 119 -16 65 -17 19 -18 -30 -20 -93 -21 77 -22 -35 -24 84 -25 -70 -27 31 -28 -112 -30 35 -31 -27 -33 -23 -34 49 -34 -55 -35 -74 -35 -16 -35 111 -34 43 -33 20 -32 37 -31 80 -30 -117 -29 -53 -28 11 -26 75 -25 -127 -24 -84 -23 -64 -22 -61 -21 -85 -20 117 -19 34 -18 -86 -18 7 -17 56 -17 54 -17 -1 -18 -116 -18 -36 -19 -10 -20 -43 -21 -116 -22 28 -23 -104 -25 5 -26 113 -28 -30 -30 93 -31 -21 -33 -114 -34 75 -35 31 -36 6 -37 3 -38 15 -39 36 -40 63 -41 88 -42 110 -43 122 -44 -126 -45 -126 -46 125 -47 119 -48 107 -49 95 -50 83 -51 72 -52 62 -53 58 -54 53 -55 49 -56 44 -57 47 -58 49 -59 59 -60 74 -61 98 -62 -127 -63 -81 -64 -14 -65 78 -65 -48 -66 -127 -66 100 -66 -127 -66 -39 -66 116 -65 66 -64 56 -63 78 -62 118 -61 -93 -60 -58 -59 -38 -58 -44 -57 -75 -56 118 -55 25 -54 -101 -54 -3 -54 66 -53 107 -53 -123 -53 -113 -53 -108 -53 -91 -53 -47 -53 37 -52 -86 -52 111 -51 122 -50 -50 -49 104 -47 66 -45 81 -43 -117 -41 -36 -39 57 -36 -107 -34 -20 -32 53 -29 113 -27 -96 -25 -55 -23 -22 -21 7 -18 35 -16 59 -14 78 -12 97 -10 116 -8 -116 -6 -88 -4 -54 -2 -11 0 36 3 97 5 -88 7 -5 9 86 12 -67 14 40 17 -109 19 -6 21 82 24 -101 26 -58 28 -53 30 -90 32 89 34 -31 35 72 37 -116 38 -69 39 -35 40 -2 41 38 43 92 44 -92 45 0 47 116 48 -10 49 -121 50 -11 51 100 53 -58 54 27 56 100 57 -100 58 -52 59 -6 60 45 62 110 63 -53 64 64 66 -41 67 -117 69 89 71 61 73 39 75 17 77 -17 78 -74 80 97 82 -27 83 62 85 100 86 83 87 6 88 120 88 -89 88 -112 88 46 88 126 87 -122 86 76 85 -41 83 50 82 94 80 112 78 108 76 91 74 70 72 47 70 18 68 -12 65 -41 63 -71 61 -101 59 126 57 92 55 59 53 25 51 -9 48 -38 46 -59 44 -68 42 -65 40 -41 38 12 37 95 35 -43 33 105 32 21 31 -44 29 -98 28 106 27 41 26 -39 24 122 23 8 22 -119 20 -3 18 114 17 -25 15 97 14 -36 12 93 11 -33 9 90 8 -52 6 46 5 126 3 -71 1 -29 -1 -1 -3 19 -4 39 -6 72 -8 -128 -10 -37 -12 88 -13 -11 -15 -79 -16 -125 -17 98 -18 58 -19 5 -20 -75 -22 74 -23 -58 -25 46 -26 -115 -28 -10 -30 121 -31 39 -32 24 -33 83 -34 -32 -35 -65 -35 -14 -35 108 -34 40 -33 19 -32 37 -31 85 -30 -105 -29 -32 -28 42 -26 109 -25 -86 -24 -37 -23 -5 -22 6 -20 -8 -20 -52 -19 -128 -18 15 -17 119 -17 -77 -17 -64 -17 -107 -17 44 -17 -120 -18 -89 -19 -117 -20 66 -21 -41 -23 81 -24 -68 -26 36 -27 -113 -29 8 -30 -110 -32 51 -33 -19 -35 -66 -36 -86 -37 -86 -38 -70 -39 -41 -40 -10 -41 21 -41 44 -42 63 -43 72 -44 76 -45 73 -46 65 -47 56 -48 48 -49 40 -50 32 -51 23 -52 18 -53 13 -54 10 -55 7 -56 10 -57 14 -58 21 -59 34 -60 53 -61 82 -62 124 -63 -70 -64 16 -64 -119 -65 44 -65 4 -65 23 -65 108 -65 -3 -65 -56 -64 -60 -63 -32 -62 16 -60 70 -59 111 -58 -118 -57 -119 -56 110 -55 48 -54 -44 -54 86 -53 -71 -53 -1 -53 38 -52 53 -52 52 -52 48 -52 51 -52 75 -52 -119 -52 -3 -52 -80 -51 -87 -50 -15 -49 -127 -47 84 -45 97 -43 -105 -41 -25 -39 66 -36 -98 -34 -16 -32 54 -29 108 -27 -107 -25 -72 -23 -46 -21 -23 -19 -1 -17 20 -14 34 -12 49 -10 63 -8 77 -6 97 -4 123 -2 -100 0 -61 2 -10 4 54 7 -125 9 -40 11 55 14 -98 16 9 19 112 21 -52 23 19 26 62 28 69 30 35 32 -43 33 93 35 -65 36 -2 37 35 39 60 40 81 41 107 42 -109 43 -47 44 38 46 -109 47 17 49 -64 49 48 51 -102 52 -4 53 80 55 -106 56 -53 57 -11 58 26 60 71 61 -128 62 -50 63 61 65 -49 66 125 68 75 70 43 72 25 74 6 76 -21 77 -68 79 111 81 -3 82 94 84 -114 85 -119 86 72 87 -58 87 1 88 -11 87 -100 87 -5 86 16 86 -34 84 112 83 -54 81 -6 79 12 78 7 76 -11 73 -32 71 -53 69 -75 67 -97 65 -119 63 115 61 87 59 59 57 30 55 1 53 -30 50 -59 48 -87 46 -108 44 -119 42 -115 40 -91 38 -42 36 41 35 -97 33 54 32 -24 30 -79 29 -124 28 87 27 35 26 -33 24 -123 23 26 22 -98 20 23 19 -118 17 -3 15 119 14 -10 12 122 11 2 10 -122 8 -1 6 105 5 -62 3 5 2 49 0 76 -2 91 -4 107 -6 -120 -8 -70 -10 14 -11 -119 -13 43 -14 -20 -16 -61 -17 -85 -18 -113 -19 98 -20 30 -21 -70 -23 53 -24 -102 -26 -12 -28 80 -29 -56 -31 110 -32 80 -33 125 -34 -3 -35 -47 -35 -8 -35 110 -34 39 -33 24 -32 48 -31 100 -30 -86 -29 -13 -28 67 -26 -116 -25 -54 -24 1 -22 38 -21 54 -20 48 -19 13 -18 -55 -18 100 -17 -40 -17 33 -16 57 -16 28 -16 -64 -17 34 -17 70 -18 47 -19 -24 -21 121 -22 -19 -24 85 -25 -70 -27 34 -28 -107 -30 30 -31 -71 -33 113 -34 68 -35 45 -36 45 -37 65 -38 95 -39 -127 -40 -93 -41 -63 -42 -39 -43 -27 -44 -22 -45 -23 -46 -26 -47 -35 -48 -43 -49 -52 -50 -61 -51 -70 -52 -72 -53 -74 -54 -76 -55 -77 -56 -76 -57 -74 -58 -65 -59 -54 -60 -35 -61 -12 -62 23 -62 75 -63 -104 -64 6 -64 -100 -65 104 -65 110 -65 -71 -65 71 -64 15 -63 10 -62 44 -61 99 -60 -98 -59 -44 -58 -11 -57 -3 -56 -30 -55 -83 -54 86 -53 -33 -53 71 -52 -115 -52 -79 -52 -66 -52 -73 -52 -87 -52 -93 -52 -82 -52 -38 -52 60 -51 -37 -51 -58 -50 0 -48 -125 -47 81 -45 91 -43 -111 -41 -30 -39 66 -36 -94 -34 -9 -32 58 -29 113 -27 -107 -25 -82 -23 -61 -21 -46 -19 -32 -17 -21 -15 -11 -13 0 -10 11 -8 21 -6 31 -4 46 -2 71 0 104 2 -109 4 -55 6 13 9 91 11 -76 13 24 16 -125 18 -18 20 78 23 -100 25 -49 27 -38 29 -70 31 110 33 -14 34 78 36 -119 37 -87 38 -72 39 -60 40 -43 41 -14 42 39 44 113 45 -41 46 78 48 76 49 -66 50 45 52 -108 53 -21 54 47 56 96 57 -125 58 -96 59 -63 60 -15 61 57 63 -98 64 39 66 -44 67 -94 69 -121 71 122 73 113 75 97 77 61 79 -6 80 -107 82 5 84 68 85 75 86 22 87 -94 87 -20 87 -22 87 -98 87 5 87 33 86 -12 84 -120 83 -28 81 19 80 33 78 26 76 8 74 -16 71 -44 69 -72 67 -95 65 -117 63 116 61 90 59 62 57 34 55 5 53 -27 50 -59 48 -87 46 -110 44 -124 42 -127 40 -109 38 -63 36 13 35 125 33 17 32 -59 30 -110 29 110 28 75 27 31 26 -29 24 -111 23 41 22 -82 20 39 19 -102 17 13 16 -121 14 11 13 -111 11 30 10 -88 8 39 7 -104 5 -10 3 62 2 109 0 -119 -2 -103 -4 -93 -6 -70 -8 -25 -10 54 -11 -85 -13 73 -14 11 -15 -21 -17 -40 -18 -60 -19 -93 -20 103 -21 6 -22 -125 -24 -30 -26 49 -27 -128 -29 -23 -31 123 -32 74 -33 100 -34 -43 -35 -97 -35 -64 -35 53 -34 -17 -34 -29 -33 -1 -32 59 -30 -121 -29 -38 -28 48 -26 -128 -25 -55 -24 5 -22 50 -21 74 -20 77 -19 50 -18 -9 -18 -102 -17 26 -16 111 -16 -108 -16 -127 -16 47 -16 -98 -17 -53 -18 -71 -19 115 -20 2 -21 117 -23 -41 -25 53 -26 -105 -28 5 -29 -122 -31 30 -32 -49 -34 -97 -35 -119 -36 -120 -37 -100 -38 -67 -39 -29 -40 8 -40 41 -41 68 -42 84 -43 92 -44 93 -45 88 -46 79 -47 71 -48 63 -49 54 -50 46 -51 43 -52 41 -53 39 -54 37 -55 37 -56 38 -57 43 -58 51 -59 65 -60 85 -61 114 -62 -97 -63 -32 -64 66 -64 -51 -65 -116 -65 -120 -65 -54 -65 80 -64 22 -63 17 -62 54 -61 113 -60 -74 -59 -14 -58 26 -56 41 -55 26 -54 -21 -54 -104 -53 33 -52 -116 -52 -47 -52 -9 -52 0 -51 -10 -52 -34 -52 -55 -52 -59 -52 -32 -52 46 -51 -70 -51 -110 -50 -68 -49 55 -47 -1 -46 8 -43 65 -41 -103 -39 -2 -37 98 -34 -68 -32 4 -29 58 -27 98 -25 123 -23 -113 -21 -100 -19 -89 -17 -78 -15 -68 -13 -62 -11 -58 -9 -55 -7 -45 -5 -32 -3 -12 -1 18 2 57 4 108 6 -84 8 -7 10 80 13 -78 15 29 18 -120 20 -20 22 61 25 116 27 -120 29 114 31 46 33 -73 34 18 36 73 37 96 38 104 39 107 40 115 41 -119 42 -74 43 -3 44 95 46 -41 47 94 48 -49 49 64 51 -89 52 -2 53 65 55 109 56 -117 57 -97 58 -73 59 -37 60 22 62 115 63 -12 64 -101 66 101 68 74 70 63 72 58 74 47 76 18 78 -38 79 124 81 -13 82 59 84 77 85 38 86 -67 86 17 87 29 87 -35 86 80 86 117 85 82 84 -21 82 75 81 123 79 -120 77 127 75 110 73 83 71 58 69 37 67 17 65 -3 62 -23 60 -43 58 -64 56 -89 54 -115 52 115 50 89 48 63 46 42 44 30 42 27 40 44 38 87 36 -94 34 20 33 -85 31 102 30 60 29 35 28 13 27 -17 25 -65 24 117 23 21 22 -97 20 28 19 -111 17 9 16 -120 14 15 13 -100 11 46 10 -63 8 75 7 -57 5 45 4 123 2 -80 0 -51 -2 -35 -4 -27 -6 -10 -8 29 -9 104 -11 -39 -13 120 -14 62 -15 36 -16 30 -17 26 -18 5 -19 -43 -21 126 -22 2 -23 97 -25 -84 -27 -16 -29 73 -30 -56 -32 -123 -33 -114 -34 -16 -35 -81 -35 -54 -35 56 -34 -14 -34 -24 -33 8 -31 70 -30 -107 -29 -19 -28 71 -26 -98 -25 -18 -24 50 -22 103 -21 -118 -20 -110 -19 127 -18 78 -17 -4 -17 -123 -16 -27 -16 21 -15 17 -15 -49 -16 75 -16 127 -17 114 -18 46 -19 -67 -21 45 -22 -116 -24 -25 -26 70 -27 -79 -29 47 -30 -61 -32 115 -33 63 -34 41 -35 44 -36 66 -37 105 -38 -106 -39 -61 -40 -21 -41 9 -41 29 -42 40 -43 43 -44 42 -45 36 -46 30 -47 24 -48 18 -49 18 -50 17 -51 16 -52 15 -53 15 -54 17 -55 19 -56 24 -57 29 -58 42 -59 61 -60 88 -61 125 -62 -72 -63 14 -63 -117 -64 61 -64 44 -64 96 -64 -36 -64 -99 -63 -104 -62 -65 -61 1 -59 78 -58 -110 -57 -60 -56 -38 -55 -48 -54 -93 -53 82 -52 -33 -52 74 -51 -110 -51 -74 -51 -68 -51 -88 -51 -121 -51 99 -51 77 -51 83 -51 -116 -51 6 -50 -54 -50 -29 -49 79 -47 14 -45 16 -43 71 -41 -96 -39 10 -36 114 -34 -52 -32 20 -29 69 -27 100 -25 119 -23 -127 -21 -122 -19 -117 -17 -113 -15 -110 -13 -109 -11 -112 -9 -116 -7 -116 -5 -111 -3 -100 -1 -80 1 -51 3 -7 5 49 8 118 10 -53 12 42 15 -109 17 -2 19 101 22 -68 24 -8 26 15 29 -6 30 -75 32 61 34 -106 35 -57 36 -41 37 -45 38 -56 39 -63 40 -55 41 -21 42 39 44 126 45 -17 46 -117 47 -3 48 110 50 -43 51 45 53 111 54 -101 55 -78 56 -66 57 -54 58 -31 59 17 61 96 62 -42 63 118 65 57 67 26 69 17 71 18 73 13 75 -6 76 -54 78 116 80 -9 81 74 83 103 84 74 85 -17 85 79 86 104 86 55 86 -75 85 -28 84 -55 83 104 82 -54 80 -3 78 12 77 4 75 -15 72 -37 70 -58 68 -77 66 -94 64 -110 62 -127 60 113 58 96 56 76 54 57 52 35 50 13 48 -8 45 -28 43 -44 41 -47 39 -32 37 8 36 83 34 -63 32 90 31 24 30 -10 28 -27 27 -38 26 -56 25 -93 24 100 23 10 22 -103 20 23 19 -113 17 8 16 -119 14 19 13 -88 11 67 10 -35 8 114 7 -8 5 105 4 -67 2 -6 0 28 -1 46 -3 51 -5 63 -7 96 -9 -92 -11 17 -12 -81 -14 120 -15 100 -16 103 -17 112 -18 106 -19 70 -20 -6 -22 -125 -23 -27 -25 43 -26 104 -28 -77 -30 33 -31 -52 -33 -58 -34 24 -34 -55 -35 -37 -35 68 -34 -4 -34 -14 -33 23 -31 91 -30 -79 -29 14 -27 107 -26 -58 -25 26 -23 98 -22 -101 -21 -61 -20 -45 -19 -59 -18 -102 -17 79 -16 -30 -16 75 -15 -119 -15 -113 -15 90 -15 -32 -16 31 -16 25 -17 -40 -19 105 -20 -42 -22 50 -23 -121 -25 -31 -27 70 -28 -65 -30 81 -31 -4 -33 -58 -34 -82 -35 -76 -36 -48 -37 -6 -38 44 -38 93 -39 -117 -40 -80 -41 -56 -42 -40 -43 -35 -44 -34 -45 -36 -46 -41 -47 -46 -48 -49 -49 -51 -50 -50 -51 -48 -52 -47 -53 -45 -54 -43 -55 -40 -56 -36 -57 -27 -58 -15 -59 2 -59 25 -60 58 -61 108 -62 -74 -63 39 -63 -54 -64 -85 -64 -45 -64 70 -63 3 -62 -1 -62 42 -60 115 -59 -57 -58 19 -56 76 -55 105 -54 100 -53 60 -52 -14 -52 -126 -51 -17 -51 57 -50 93 -50 95 -50 71 -50 29 -50 -18 -51 -56 -51 -66 -51 -28 -51 71 -50 -7 -50 0 -48 96 -47 19 -45 16 -43 69 -41 -95 -39 12 -36 118 -34 -45 -32 25 -29 74 -27 101 -25 114 -23 118 -21 118 -19 117 -17 115 -15 111 -13 107 -11 98 -9 87 -7 79 -5 75 -3 79 -1 91 1 113 3 -108 5 -62 7 -1 9 75 12 -90 14 9 17 115 19 -41 21 49 24 112 26 -115 28 124 30 59 32 -59 33 28 35 70 36 79 37 66 38 45 39 27 40 26 41 46 42 96 43 -79 44 30 46 72 46 -75 47 35 49 -119 50 -34 51 29 53 65 54 82 55 83 56 84 57 93 58 124 59 -66 60 38 62 -69 63 120 65 86 67 75 69 75 71 73 73 55 75 12 77 -66 78 70 80 -97 81 -60 82 -79 83 97 84 -51 84 -14 84 -50 84 91 84 -103 83 -118 82 50 81 -99 79 -44 77 -27 75 -32 73 -48 71 -66 69 -84 67 -98 65 -106 63 -112 61 -118 59 -125 57 124 55 114 53 101 51 87 49 74 47 60 45 47 43 39 41 40 39 57 37 97 35 -85 33 30 32 -71 30 125 29 100 28 94 27 97 26 93 25 69 24 19 23 -60 21 90 20 -33 18 92 17 -40 15 94 14 -17 12 -116 11 48 10 -43 8 119 7 10 6 -118 4 -18 2 54 1 96 -1 117 -3 -128 -5 -116 -7 -86 -9 -20 -11 89 -12 -10 -14 -59 -15 -70 -16 -54 -17 -31 -18 -18 -19 -37 -20 -98 -21 50 -22 -103 -24 -34 -26 20 -27 84 -29 -75 -31 80 -32 57 -33 124 -34 34 -34 42 -34 -116 -34 64 -33 53 -32 91 -31 -95 -30 -6 -29 89 -27 -70 -26 21 -24 106 -23 -75 -22 -14 -21 30 -19 51 -18 44 -17 6 -16 -64 -16 90 -15 -50 -15 24 -14 46 -14 6 -14 -102 -15 -27 -16 -24 -17 -83 -18 63 -19 -81 -21 11 -22 96 -24 -71 -26 32 -27 -103 -29 40 -30 -44 -32 -96 -33 -118 -34 -110 -35 -77 -36 -25 -37 36 -37 96 -38 -105 -39 -61 -40 -30 -41 -10 -42 1 -42 7 -43 7 -44 6 -45 5 -46 6 -47 8 -48 13 -49 19 -50 24 -51 29 -52 34 -53 41 -54 48 -55 59 -56 72 -57 90 -58 113 -59 -113 -60 -69 -61 -3 -62 98 -62 -8 -63 -51 -63 -22 -63 82 -62 6 -61 -2 -61 42 -59 119 -58 -47 -57 36 -55 99 -54 -124 -53 -126 -52 92 -51 17 -50 -93 -50 17 -49 92 -49 -127 -49 -127 -49 100 -49 48 -49 -13 -50 -67 -50 -95 -50 -79 -50 -1 -50 -104 -49 -119 -48 -41 -47 124 -45 110 -43 -99 -41 -10 -39 97 -36 -53 -34 37 -31 103 -29 -113 -27 -94 -25 -91 -23 -99 -21 -108 -19 -121 -17 121 -15 108 -13 92 -11 72 -9 51 -7 30 -5 12 -3 1 -1 -1 0 8 3 30 5 62 7 110 9 -82 11 -3 13 88 16 -68 18 29 21 115 23 -78 25 -49 27 -65 29 124 31 2 33 85 34 121 35 120 36 95 37 60 38 26 39 7 40 14 41 52 42 121 43 -34 44 -1 44 104 46 -41 47 60 49 -111 50 -50 51 -17 52 -9 53 -19 54 -35 55 -42 56 -28 57 20 59 111 60 -11 61 -89 63 127 65 112 67 112 69 110 71 96 73 58 75 -15 76 127 78 -32 79 14 81 4 82 -65 82 56 83 109 83 86 83 -15 82 61 82 56 81 -23 79 89 78 -105 76 -83 74 -84 72 -97 70 -112 68 -123 66 -127 64 127 62 -126 60 -122 58 -118 56 -117 54 -118 52 -121 50 -125 48 127 46 120 44 116 42 114 40 118 38 -119 36 -77 34 -2 32 112 31 14 30 -41 28 -58 27 -50 26 -32 25 -20 24 -27 23 -63 22 124 21 28 20 -89 18 39 17 -89 15 48 14 -57 12 107 11 27 10 -51 8 124 7 31 6 -84 4 31 3 115 1 -90 -1 -64 -3 -51 -5 -39 -7 -10 -9 50 -10 -100 -12 59 -13 14 -14 13 -15 42 -16 82 -17 111 -18 112 -19 69 -20 -28 -22 83 -23 -104 -25 -53 -27 0 -28 84 -30 -33 -32 -73 -33 -22 -34 -125 -34 -128 -34 -37 -34 -117 -33 -127 -32 -86 -31 -13 -30 78 -28 -81 -27 15 -25 107 -24 -63 -23 14 -21 80 -20 -126 -19 -103 -18 -105 -17 119 -16 57 -15 -40 -15 86 -14 -85 -14 -48 -14 -71 -14 93 -14 -75 -15 -61 -16 -114 -17 34 -18 -109 -20 -18 -22 67 -23 -100 -25 2 -26 122 -28 10 -29 -76 -31 125 -32 104 -33 115 -34 -103 -35 -46 -36 23 -36 91 -37 -102 -38 -50 -39 -12 -40 14 -40 32 -41 41 -42 46 -43 50 -44 54 -45 59 -46 67 -47 76 -48 87 -49 98 -50 108 -51 117 -52 126 -53 -119 -54 -106 -55 -90 -56 -72 -57 -50 -58 -21 -59 18 -59 75 -60 -91 -61 44 -61 -16 -62 -5 -62 87 -61 3 -60 -9 -60 36 -58 117 -57 -43 -56 46 -54 115 -53 -103 -52 -101 -51 121 -50 49 -49 -58 -49 57 -48 -123 -48 -83 -48 -82 -48 -115 -48 82 -48 10 -48 -60 -49 -109 -49 -116 -49 -62 -49 70 -48 34 -47 90 -46 -16 -45 -43 -43 -1 -41 83 -38 -66 -36 39 -33 -127 -31 -65 -29 -29 -27 -21 -25 -30 -23 -50 -21 -72 -19 -96 -17 -117 -15 114 -13 87 -11 55 -9 21 -7 -14 -6 -44 -4 -69 -2 -83 0 -88 2 -80 4 -61 6 -27 8 24 11 89 13 -86 15 4 18 97 20 -74 22 -12 24 16 27 2 29 -65 30 69 32 -109 33 -81 34 -93 35 125 36 74 37 26 38 -8 38 -17 39 7 41 66 42 -99 43 -38 43 64 45 -83 46 20 48 104 49 -92 50 -62 51 -60 52 -77 53 -103 54 -124 55 -124 56 -91 57 -16 58 107 60 20 62 -27 63 -44 65 -45 67 -44 69 -55 71 -89 73 99 75 -9 76 94 78 -111 79 -113 80 82 81 -42 81 23 82 14 82 -74 81 13 81 21 80 -47 78 73 77 -117 75 -91 73 -91 71 -102 69 -113 67 -121 65 -119 63 -113 61 -103 59 -90 57 -78 55 -68 53 -60 51 -55 49 -52 47 -49 45 -47 43 -46 41 -42 39 -34 37 -12 35 30 34 104 32 -38 30 123 29 72 28 62 27 82 26 114 25 -115 24 -107 23 127 22 70 21 -19 19 125 18 1 17 -123 15 18 14 -83 12 89 11 15 10 -51 8 -120 7 54 6 -46 4 81 3 -79 1 -17 -1 15 -2 29 -4 38 -6 63 -8 120 -10 -34 -12 124 -13 80 -14 86 -15 126 -16 -75 -17 -28 -18 -10 -19 -38 -20 -122 -21 -5 -23 67 -24 112 -26 -100 -28 -30 -30 93 -31 37 -32 73 -33 -44 -34 -58 -34 27 -33 -58 -33 -69 -32 -27 -31 50 -29 -113 -28 -13 -27 85 -25 -76 -24 10 -22 90 -21 -98 -20 -46 -19 -17 -18 -14 -17 -42 -16 -100 -15 65 -14 -56 -14 41 -13 91 -13 82 -13 4 -13 106 -14 -126 -15 84 -16 -19 -18 94 -19 -70 -21 13 -22 101 -24 -53 -26 65 -27 -49 -29 121 -30 66 -31 47 -32 60 -33 103 -34 -89 -35 -13 -36 65 -36 -120 -37 -62 -38 -16 -39 16 -39 36 -40 49 -41 56 -42 63 -43 69 -44 77 -45 88 -46 100 -47 115 -48 -127 -49 -114 -50 -102 -51 -89 -52 -77 -53 -61 -54 -44 -55 -23 -56 -1 -57 26 -57 61 -58 111 -59 -66 -60 56 -60 -20 -61 -22 -61 58 -60 -34 -60 -51 -59 -7 -58 77 -56 -77 -55 21 -53 97 -52 -115 -51 -109 -50 114 -49 44 -48 -62 -48 54 -47 -123 -47 -82 -47 -81 -47 -115 -47 76 -47 -5 -48 -88 -48 102 -48 75 -48 107 -48 -41 -48 -99 -47 -62 -46 72 -44 36 -42 71 -40 -101 -38 6 -35 112 -33 -56 -31 4 -28 33 -26 33 -24 14 -22 -16 -21 -51 -19 -83 -17 -114 -15 109 -13 73 -11 32 -9 -12 -8 -58 -6 -100 -4 120 -2 92 0 76 2 72 4 80 6 102 8 -116 10 -61 12 11 15 94 17 -74 19 9 22 72 24 102 26 89 28 23 30 -100 31 -25 32 -2 33 -21 34 -71 35 121 36 58 37 8 38 -15 38 -5 39 42 41 125 42 -125 42 -27 43 79 45 -76 46 8 48 67 49 93 50 90 51 63 52 23 53 -14 53 -31 54 -16 55 43 57 -105 58 53 60 -1 61 -23 63 -25 65 -23 67 -31 69 -62 71 -127 73 27 75 -122 76 -63 77 -58 78 -108 79 36 80 114 80 118 80 47 80 -107 79 -86 78 113 77 -13 75 59 74 88 72 92 70 85 68 78 66 76 64 85 62 100 60 121 58 -112 56 -90 54 -70 52 -54 50 -39 48 -25 46 -11 44 0 43 10 41 20 39 35 37 59 35 103 33 -80 31 33 30 -61 28 -107 27 -107 26 -75 25 -27 24 18 24 43 23 37 22 -6 20 -84 19 67 18 -53 16 83 15 -28 13 -123 12 56 11 -6 9 -61 8 -116 7 74 6 -11 4 -122 3 -13 1 61 0 102 -2 119 -4 -125 -6 -105 -8 -53 -10 45 -11 -55 -13 -96 -14 -83 -15 -30 -16 41 -16 109 -17 -107 -18 -114 -19 74 -20 -54 -22 21 -23 62 -25 97 -27 -103 -29 4 -30 -70 -32 -52 -33 72 -33 46 -33 122 -33 33 -32 20 -31 62 -30 -115 -29 -19 -28 83 -26 -75 -25 19 -23 105 -22 -70 -21 0 -19 55 -18 89 -17 95 -16 72 -15 17 -14 -68 -14 73 -13 -77 -13 -13 -13 -6 -13 -67 -13 50 -13 85 -14 47 -15 -53 -17 61 -18 -105 -20 -22 -22 67 -23 -87 -25 33 -26 -82 -28 87 -29 33 -30 14 -31 30 -32 78 -33 -107 -34 -22 -35 66 -35 -110 -36 -43 -37 9 -37 48 -38 74 -39 92 -40 105 -41 115 -42 126 -43 -117 -44 -101 -45 -82 -46 -61 -47 -41 -48 -23 -49 -6 -50 10 -50 26 -51 44 -52 64 -53 87 -54 111 -55 -118 -56 -86 -57 -42 -58 26 -58 -123 -59 42 -59 24 -59 89 -59 -17 -59 -40 -58 2 -56 89 -55 -58 -54 47 -52 -126 -51 -76 -50 -66 -49 -97 -48 89 -47 -15 -47 104 -46 -70 -46 -25 -46 -22 -46 -59 -46 127 -46 35 -46 -62 -47 110 -47 61 -47 68 -47 -105 -47 68 -46 84 -45 -57 -44 -105 -42 -78 -40 1 -37 107 -35 -42 -33 47 -30 103 -28 125 -26 114 -24 81 -22 37 -20 -10 -19 -54 -17 -96 -15 118 -13 72 -11 20 -9 -37 -8 -96 -6 103 -4 52 -2 10 0 -20 1 -40 3 -47 5 -41 7 -18 9 23 12 82 14 -101 16 -19 18 59 21 121 23 -104 25 -115 27 77 29 -46 30 26 32 43 33 16 34 -45 34 -123 35 54 36 -13 36 -53 37 -58 38 -25 39 45 41 21 41 113 42 -39 43 62 45 -109 46 -51 47 -27 48 -36 49 -74 50 -128 51 74 52 37 53 34 54 74 55 -89 56 55 58 -10 59 -39 61 -45 63 -45 65 -51 67 -80 69 115 71 15 73 127 74 -65 75 -52 76 -95 77 60 78 -106 78 -87 78 113 78 -24 77 13 77 -31 75 109 74 -68 72 -34 70 -26 68 -31 66 -33 64 -27 62 -10 60 17 59 49 57 83 55 118 53 -107 51 -77 49 -49 47 -23 45 2 44 25 42 46 40 66 38 87 36 116 34 -94 32 -20 30 94 29 0 28 -42 26 -35 25 8 25 72 24 -120 23 -75 22 -65 21 -94 20 95 19 -4 17 -119 16 20 15 -87 13 82 12 12 11 -40 9 -82 8 -124 7 82 6 15 5 -80 3 46 2 -122 0 -69 -2 -44 -4 -32 -6 -13 -8 35 -9 -126 -11 28 -12 -12 -14 8 -14 73 -15 -95 -16 -7 -17 56 -17 69 -18 20 -19 -96 -21 -14 -23 26 -24 52 -26 97 -28 -69 -30 96 -31 97 -32 -51 -33 -91 -33 -25 -33 -119 -32 121 -31 -91 -30 -10 -29 90 -27 -63 -26 36 -24 -128 -23 -42 -22 37 -20 108 -19 -89 -18 -53 -17 -43 -16 -65 -15 -117 -14 57 -13 -52 -13 64 -12 -115 -12 -91 -12 122 -12 -1 -13 48 -13 18 -14 -76 -16 39 -17 -125 -19 -42 -21 48 -22 -105 -24 16 -25 -97 -27 72 -28 16 -29 -3 -31 15 -31 69 -32 -107 -33 -11 -34 87 -34 -78 -35 -1 -36 59 -36 103 -37 -120 -38 -96 -39 -78 -40 -63 -41 -47 -42 -28 -43 -7 -44 17 -44 43 -45 69 -46 92 -47 115 -48 -121 -49 -101 -50 -80 -51 -56 -52 -29 -53 -2 -54 27 -54 57 -55 97 -56 -101 -57 -8 -58 -116 -58 103 -58 -105 -58 34 -57 2 -56 42 -55 -124 -54 -11 -53 101 -51 -65 -50 -11 -49 1 -47 -28 -47 -96 -46 57 -45 -79 -45 7 -44 54 -44 59 -44 23 -44 -50 -45 104 -45 -7 -46 -110 -46 75 -46 59 -46 117 -46 9 -45 1 -44 96 -43 32 -41 49 -39 124 -37 -26 -35 81 -32 -87 -30 -35 -28 -21 -26 -43 -24 -90 -22 107 -20 45 -18 -13 -17 -67 -15 -121 -13 78 -11 15 -9 -55 -8 -128 -6 56 -4 -10 -3 -67 -1 -112 1 110 3 88 5 78 7 84 9 108 11 -103 13 -42 15 30 18 103 20 -94 22 -63 24 -74 26 118 28 -6 29 63 31 75 32 37 33 -35 33 127 34 31 35 -52 35 -110 36 124 37 -114 38 -56 39 -77 39 10 41 109 42 -47 43 38 45 95 46 117 47 102 48 56 49 -11 49 -81 50 121 51 99 52 122 53 -58 54 72 56 -3 57 -40 59 -50 61 -51 63 -58 65 -86 67 109 69 11 71 126 72 -63 73 -45 74 -79 75 84 76 -71 76 -39 76 -81 76 52 76 103 75 71 74 -34 72 53 71 93 69 105 67 106 65 108 63 121 61 -109 59 -72 57 -29 55 17 54 64 52 107 50 -109 48 -71 46 -34 44 3 43 38 41 71 39 101 37 -124 35 -89 33 -40 31 35 30 -107 28 57 27 19 26 33 25 89 24 -88 23 -7 22 56 22 85 21 70 20 13 19 -78 17 67 16 -46 14 106 13 23 12 -38 10 -81 9 -112 8 117 7 82 6 31 5 -46 3 97 2 -55 0 8 -1 39 -3 54 -5 73 -7 117 -9 -48 -11 104 -12 66 -13 90 -14 -90 -15 14 -15 123 -16 -50 -17 -15 -18 -44 -19 111 -20 -55 -22 -14 -24 8 -25 42 -27 119 -29 12 -30 -1 -32 92 -32 41 -32 98 -32 -2 -32 -21 -31 22 -29 105 -28 -51 -27 52 -25 -107 -24 -20 -23 63 -21 -117 -20 -46 -19 13 -17 53 -16 67 -15 48 -14 -2 -14 -82 -13 69 -12 -64 -12 25 -11 65 -11 39 -11 -67 -12 -3 -13 -22 -14 -112 -15 6 -16 98 -18 -74 -20 17 -21 124 -23 -9 -25 -121 -26 49 -27 -6 -29 -25 -30 -4 -31 54 -31 -114 -32 -9 -33 100 -33 -55 -34 31 -34 100 -35 -105 -36 -67 -37 -38 -38 -15 -39 6 -39 27 -40 49 -41 75 -42 104 -43 -119 -44 -87 -45 -56 -46 -29 -47 -3 -48 20 -48 45 -49 73 -50 105 -51 -119 -52 -88 -53 -57 -54 -22 -55 28 -55 109 -56 -15 -57 -68 -57 -36 -57 90 -56 50 -55 87 -54 -78 -53 41 -51 -97 -50 -2 -49 57 -47 71 -46 41 -45 -26 -45 -128 -44 -6 -44 82 -43 -123 -43 -114 -43 107 -43 30 -43 -77 -44 56 -44 -62 -45 105 -45 66 -45 99 -45 -34 -45 -66 -44 8 -42 -73 -41 -66 -39 3 -36 104 -34 -45 -32 41 -29 90 -27 95 -25 63 -23 2 -21 -72 -20 107 -18 36 -16 -30 -15 -94 -13 95 -11 20 -9 -63 -8 106 -6 18 -4 -63 -3 122 -1 62 1 14 3 -24 4 -50 6 -61 8 -53 10 -24 12 26 15 88 17 -101 19 -46 21 -17 23 -28 25 -93 27 38 29 106 30 111 31 66 32 -18 32 -124 33 20 34 -80 34 101 35 62 36 65 37 111 38 51 38 -126 39 -30 40 67 42 -104 43 -46 44 -25 45 -45 46 -100 47 76 48 -10 48 -85 49 -127 50 -125 51 -67 52 48 54 -40 55 -85 57 -101 59 -105 61 -114 63 114 65 55 67 -43 68 73 70 -112 71 -89 72 -117 73 55 74 -88 74 -42 74 -69 74 81 74 -108 73 -123 72 38 71 -121 69 -75 67 -58 65 -52 63 -43 61 -22 59 13 58 61 56 118 54 -78 52 -18 50 39 49 92 47 -113 45 -63 43 -14 41 34 40 80 38 122 36 -94 34 -51 32 1 31 78 29 -65 27 98 26 62 25 82 24 -107 23 -10 22 92 22 -80 21 -31 20 -29 19 -74 18 98 17 -7 15 -117 14 40 13 -39 11 -93 10 -125 9 112 8 98 7 80 6 48 5 -10 3 -104 2 17 1 94 -1 -122 -3 -104 -5 -87 -7 -47 -9 39 -10 -69 -12 -106 -13 -76 -14 11 -14 -124 -15 6 -15 114 -16 -81 -17 -87 -18 85 -19 -71 -21 -28 -23 -12 -25 10 -26 72 -28 -51 -30 -82 -31 -5 -32 -71 -32 -26 -32 122 -31 100 -30 -113 -29 -29 -28 73 -26 -78 -25 18 -23 102 -22 -76 -21 -3 -20 67 -18 -128 -17 -85 -16 -69 -15 -86 -14 120 -13 42 -12 -60 -12 71 -11 -83 -11 -27 -11 -32 -11 -118 -11 -38 -12 -46 -13 127 -14 -9 -16 83 -17 -88 -19 6 -20 115 -22 -14 -24 -124 -25 46 -26 -9 -28 -28 -29 -6 -30 57 -30 -103 -31 12 -31 -124 -32 -11 -33 86 -33 -93 -34 -34 -35 10 -35 45 -36 73 -37 99 -38 125 -39 -103 -40 -71 -41 -35 -42 3 -42 42 -43 80 -44 114 -45 -112 -46 -84 -47 -55 -48 -22 -49 13 -49 50 -50 86 -51 118 -52 -105 -53 -63 -54 5 -54 120 -55 48 -55 62 -55 -84 -55 121 -54 -102 -53 -10 -52 114 -50 -16 -49 87 -47 -106 -46 -89 -45 -118 -44 69 -43 -33 -43 90 -42 -74 -42 -19 -42 -5 -42 -38 -42 -116 -42 27 -42 -106 -43 16 -43 -93 -44 100 -44 107 -44 -54 -44 -113 -43 -62 -42 95 -40 90 -38 -105 -36 -4 -34 103 -31 -69 -29 -24 -27 -26 -25 -71 -23 108 -21 17 -19 -77 -18 92 -16 13 -14 -62 -13 116 -11 29 -9 -67 -8 85 -6 -19 -5 -117 -3 51 -1 -25 0 -90 2 113 4 69 6 41 8 31 10 44 12 78 14 -126 16 -68 18 -16 20 11 23 0 25 -64 26 67 28 -125 29 -123 30 78 31 -18 31 116 32 -12 32 125 33 32 34 -25 34 -38 35 -7 36 -79 36 -8 37 83 39 -76 40 9 42 68 43 88 44 64 45 1 46 -93 46 60 47 -35 47 -99 48 -117 49 -78 50 20 52 -82 53 120 55 97 57 91 59 82 61 54 63 -4 64 -101 66 16 68 89 69 117 70 95 71 20 72 -113 72 -54 72 -66 72 101 72 -71 71 -71 70 104 69 -46 67 7 66 28 64 38 62 52 60 80 58 125 56 -71 54 -1 52 73 51 -109 49 -38 47 28 46 91 44 -103 42 -41 40 21 39 81 37 -119 35 -68 33 -18 31 39 30 117 28 -27 26 -121 25 100 24 126 23 -51 22 61 22 -73 21 33 21 103 20 122 19 91 18 17 17 -84 15 64 14 -33 12 -106 11 103 10 81 9 75 8 76 7 74 6 58 5 20 4 -54 2 85 1 -79 -1 -28 -3 -5 -5 11 -6 47 -8 -128 -10 16 -11 -22 -13 12 -13 108 -14 -11 -15 -116 -15 18 -15 105 -16 122 -17 58 -18 -86 -20 -38 -22 -26 -24 -14 -26 33 -27 -109 -29 99 -30 -97 -31 78 -31 112 -31 -5 -31 -32 -30 10 -28 97 -27 -53 -26 52 -24 -109 -23 -28 -22 43 -20 111 -19 -78 -18 -16 -17 30 -15 50 -14 35 -13 -14 -13 -93 -12 63 -11 -57 -11 56 -10 -126 -10 -112 -10 79 -10 -79 -11 -74 -12 105 -13 -28 -15 64 -16 -106 -18 -10 -20 103 -21 -21 -23 -126 -24 45 -25 -11 -27 -30 -28 -7 -29 60 -29 -94 -30 32 -30 -91 -31 35 -31 -114 -32 -27 -33 39 -33 90 -34 -126 -35 -91 -36 -59 -37 -27 -38 5 -38 42 -39 83 -40 -127 -41 -81 -42 -36 -43 5 -43 42 -44 74 -45 107 -46 -113 -47 -72 -48 -29 -49 12 -49 47 -50 78 -51 113 -52 -86 -53 12 -53 -80 -54 -86 -54 6 -53 -56 -53 -29 -52 65 -50 -62 -49 71 -47 -75 -46 -7 -45 12 -43 -17 -43 -87 -42 65 -41 -67 -41 28 -40 88 -40 107 -40 77 -40 0 -40 -119 -41 -7 -42 101 -42 -28 -43 -113 -43 124 -43 -64 -43 106 -42 -124 -41 13 -39 -8 -38 47 -35 -110 -33 -3 -31 82 -28 125 -26 116 -24 58 -22 -34 -21 112 -19 1 -17 -102 -16 62 -14 -25 -13 -114 -11 45 -9 -65 -8 72 -6 -49 -5 91 -3 -14 -2 -105 0 70 2 0 4 -59 5 -107 7 119 9 113 11 -124 13 -85 15 -35 17 11 20 37 22 25 24 -38 25 93 27 -100 28 -104 29 89 30 -18 30 102 31 -44 31 76 32 -36 32 -111 33 115 34 -125 35 60 35 122 36 -48 37 46 39 -125 40 -66 41 -47 42 -73 43 112 44 8 45 -112 45 31 46 -54 46 -92 47 -73 48 8 50 -108 51 82 53 52 55 41 57 29 59 0 61 -60 62 98 64 -42 65 31 67 60 68 42 69 -27 69 105 70 -81 70 -79 70 104 70 -51 69 -35 68 -103 67 14 66 74 64 100 62 115 60 -121 58 -85 56 -31 54 41 53 125 51 -43 49 45 48 -127 46 -47 44 29 43 104 41 -77 39 -1 37 72 36 -114 34 -50 32 9 31 72 29 -104 27 8 26 -87 24 -121 23 -90 22 -3 21 124 21 9 21 -120 20 -30 19 8 19 -10 17 -75 16 85 15 -20 13 -114 12 73 11 34 10 22 9 28 8 42 7 55 6 57 5 37 4 -16 2 -114 1 -5 -1 58 -2 87 -4 104 -6 -119 -8 -42 -10 98 -11 59 -12 97 -13 -54 -14 97 -14 12 -14 -86 -15 28 -15 70 -16 26 -17 -104 -19 -49 -21 -39 -23 -36 -25 -1 -27 99 -28 35 -29 80 -30 -14 -31 8 -30 -118 -30 106 -29 -109 -28 -21 -27 87 -25 -62 -24 30 -22 104 -21 -88 -20 -27 -19 37 -17 99 -16 -109 -15 -86 -14 -99 -13 106 -12 26 -11 -76 -11 63 -10 -72 -10 17 -9 51 -9 6 -9 123 -10 -116 -11 72 -12 -59 -14 35 -15 122 -17 -36 -19 83 -20 -36 -22 120 -23 38 -24 -18 -26 -39 -27 -16 -28 54 -28 -92 -29 45 -29 -66 -30 71 -30 -66 -31 29 -31 102 -32 -97 -33 -50 -34 -10 -35 27 -35 65 -36 103 -37 -110 -38 -63 -39 -11 -40 43 -40 96 -41 -112 -42 -70 -43 -32 -44 5 -44 46 -45 92 -46 -115 -47 -68 -48 -28 -49 4 -49 36 -50 82 -51 -91 -52 55 -52 29 -52 105 -52 29 -51 49 -50 -115 -49 19 -47 -97 -46 19 -44 93 -43 113 -42 83 -41 10 -40 -97 -40 27 -39 124 -39 -66 -39 -41 -39 -66 -39 115 -39 -6 -40 99 -40 -62 -41 49 -41 -57 -42 -99 -42 -58 -42 86 -41 87 -40 -53 -39 -89 -37 -43 -35 52 -32 -97 -30 -11 -28 29 -25 12 -23 -57 -22 90 -20 -38 -19 89 -17 -31 -16 119 -14 22 -12 -77 -11 71 -9 -52 -8 70 -6 -68 -5 55 -3 -66 -2 84 0 -11 1 -96 3 83 5 16 7 -33 8 -59 10 -57 12 -31 14 9 17 49 19 71 21 58 23 -6 24 125 26 -70 27 -78 28 108 29 -10 29 97 30 -64 30 38 31 -92 31 72 32 24 33 26 34 -94 33 -41 34 38 36 -127 37 -43 38 17 40 37 41 8 42 -68 42 72 43 -65 43 57 44 -50 44 -111 45 -114 46 -52 47 72 49 -7 50 -46 52 -63 54 -77 56 -108 58 87 60 -13 61 100 63 -83 64 -53 65 -68 66 125 67 10 68 91 68 108 68 52 68 -83 67 -49 66 -100 65 28 64 97 62 -126 60 -107 58 -82 56 -38 54 28 53 114 51 -44 49 61 48 -92 46 8 45 102 43 -64 41 25 40 114 38 -51 36 38 35 123 33 -55 31 16 30 86 28 -88 26 24 25 -72 23 -106 22 -72 21 24 21 -89 20 72 20 -33 19 81 19 -116 18 -117 17 84 16 -7 14 -109 13 55 12 -10 10 -42 9 -44 8 -25 7 5 7 33 6 53 5 54 4 23 3 -52 1 77 0 -102 -2 -65 -4 -46 -6 -16 -8 55 -9 -65 -11 -107 -12 -67 -13 45 -13 -45 -14 -110 -14 75 -14 -38 -15 33 -15 14 -16 -99 -18 -37 -20 -27 -22 -31 -24 -9 -26 75 -27 -5 -29 23 -29 -86 -30 -78 -30 41 -29 2 -28 40 -27 -126 -26 -15 -25 94 -23 -72 -22 -3 -21 51 -19 103 -18 -96 -17 -35 -16 16 -14 42 -13 31 -12 -20 -12 -105 -11 46 -10 -70 -10 60 -9 -92 -9 -37 -9 -57 -9 81 -9 114 -10 55 -11 -72 -13 21 -14 108 -16 -45 -18 79 -19 -32 -21 -126 -22 52 -23 -3 -25 -25 -26 -2 -27 71 -27 -67 -28 81 -28 -16 -29 -121 -29 10 -29 115 -30 -59 -31 5 -31 57 -32 104 -33 -108 -34 -65 -35 -20 -36 28 -36 81 -37 -116 -38 -53 -39 8 -39 64 -40 113 -41 -100 -42 -59 -43 -13 -44 39 -44 96 -45 -105 -46 -58 -47 -23 -48 5 -48 42 -49 110 -50 -22 -51 -69 -51 -14 -51 -105 -50 -95 -49 -4 -48 -123 -46 24 -44 -107 -43 -29 -42 -6 -41 -38 -40 -115 -39 31 -38 -103 -38 -4 -38 67 -37 99 -37 82 -37 10 -37 -112 -38 -15 -39 68 -39 -94 -40 35 -40 -33 -41 -19 -41 96 -40 69 -39 -96 -38 106 -36 -115 -34 -24 -32 83 -29 -87 -27 -49 -25 -72 -23 102 -21 -25 -20 81 -18 -70 -17 48 -15 -73 -14 74 -12 -34 -11 102 -9 -33 -8 72 -6 -85 -5 18 -3 -121 -2 12 0 -98 1 56 3 -40 4 -127 6 58 8 11 10 -7 11 3 14 31 16 63 18 81 20 66 22 2 24 -124 25 -64 26 -76 27 103 28 -26 28 67 29 -111 29 -27 29 80 30 -32 30 -99 31 -115 32 14 32 56 33 -128 34 -41 35 43 37 104 38 124 39 95 40 12 41 -114 41 -11 41 91 42 -40 42 -124 43 107 44 -108 45 -2 46 -95 48 112 50 89 52 71 54 38 56 -27 57 126 59 -19 60 51 62 82 63 70 64 12 65 -96 65 -4 65 26 66 -13 65 126 65 -76 64 -110 63 31 62 109 60 -108 58 -84 56 -53 54 -1 52 76 51 -81 49 33 48 -102 46 18 45 -123 43 -14 41 90 40 -64 38 40 37 -110 35 -4 33 98 32 -64 30 20 29 99 27 -71 25 41 24 -57 22 -93 21 -57 20 48 20 -52 19 -127 19 48 19 -69 18 12 18 28 17 -16 15 -101 14 55 13 -36 11 -97 10 -122 9 -113 8 -81 7 -38 6 6 6 43 5 63 4 54 3 2 2 -104 0 -10 -2 37 -3 58 -5 85 -7 -105 -9 25 -10 -19 -12 22 -12 -115 -13 64 -13 19 -13 -27 -14 -111 -14 -10 -15 -2 -16 -96 -17 -23 -19 -12 -21 -22 -23 -12 -25 58 -26 -39 -28 -26 -29 105 -29 100 -29 -48 -29 -95 -28 -60 -27 30 -25 -111 -24 0 -22 88 -21 -106 -20 -63 -19 -23 -18 27 -16 85 -15 -117 -14 -87 -13 -95 -12 108 -11 19 -10 -91 -10 47 -9 -74 -9 44 -8 121 -8 125 -8 30 -8 81 -9 32 -10 -92 -12 0 -13 88 -15 -63 -17 68 -18 -34 -20 -119 -21 64 -22 9 -23 -15 -25 7 -25 82 -26 -50 -27 110 -27 27 -27 -63 -28 80 -28 -61 -29 28 -29 99 -30 -98 -31 -45 -32 6 -32 56 -33 107 -34 -95 -35 -35 -36 31 -36 103 -37 -83 -38 -17 -39 39 -39 88 -40 -123 -41 -73 -42 -15 -43 49 -43 114 -44 -87 -45 -47 -46 -19 -47 11 -47 64 -48 -87 -49 99 -49 -124 -49 24 -48 24 -47 111 -46 -4 -45 -106 -43 26 -41 110 -40 -122 -39 100 -38 18 -37 -96 -37 23 -36 125 -36 -54 -36 -14 -36 -24 -36 -90 -36 43 -36 -121 -37 -49 -38 29 -38 -117 -39 49 -39 36 -39 121 -39 65 -38 -126 -37 56 -35 79 -33 -91 -31 16 -28 103 -26 -116 -24 110 -22 15 -20 126 -19 -46 -18 37 -16 -121 -15 -1 -14 -122 -12 15 -10 -114 -9 -7 -8 82 -6 -94 -5 -11 -4 87 -2 -52 -1 79 1 -38 2 105 4 -3 5 -98 7 88 9 49 11 42 13 58 15 81 17 93 19 75 21 10 23 -116 24 -56 25 -71 26 101 27 -38 27 41 28 104 28 -86 28 2 29 126 29 41 30 8 31 -114 30 -83 31 -19 32 64 34 -109 35 -47 36 -24 37 -53 38 116 39 -20 39 69 40 -105 40 -1 40 -108 41 102 42 124 43 -43 44 106 46 45 48 15 50 -7 51 -43 53 -109 55 40 57 -109 58 -42 59 -13 60 -23 61 -76 62 77 63 -78 63 -36 63 -60 63 98 63 -85 62 -101 61 54 60 -115 58 -72 56 -43 54 -7 52 53 51 -116 49 -4 47 126 46 6 45 -113 43 17 42 -116 40 2 39 118 37 -21 35 99 34 -36 32 83 31 -63 29 35 28 124 26 -41 24 71 23 -30 21 -68 20 -32 19 78 19 -9 18 -65 18 -123 18 40 18 -113 17 -80 16 -112 15 64 14 -35 12 -125 11 72 10 53 9 72 8 116 7 -83 6 -25 5 26 5 64 4 77 3 49 2 -34 0 77 -1 -122 -3 -97 -5 -72 -7 -12 -9 112 -10 64 -11 105 -12 -28 -13 -94 -13 -121 -13 113 -13 58 -13 -67 -14 -32 -15 -105 -16 -20 -18 -6 -20 -21 -22 -21 -24 34 -25 -77 -27 -79 -28 38 -28 19 -28 116 -28 60 -27 90 -26 -76 -25 43 -23 -97 -22 -9 -21 46 -19 77 -18 105 -17 -111 -16 -57 -15 0 -13 35 -12 30 -11 -24 -11 -119 -10 20 -9 -102 -9 35 -8 -90 -8 7 -7 36 -7 -34 -8 36 -8 -3 -10 -124 -11 -32 -13 55 -14 -94 -16 45 -17 -47 -19 -124 -20 65 -21 11 -22 -15 -24 4 -24 79 -25 -47 -26 124 -26 55 -26 -21 -27 -121 -27 4 -27 100 -28 -79 -29 -15 -30 45 -30 102 -31 -98 -32 -41 -33 19 -33 84 -34 -100 -35 -21 -36 59 -36 -122 -37 -58 -38 -3 -39 46 -39 100 -40 -94 -41 -21 -42 54 -42 118 -43 -91 -44 -61 -45 -38 -46 2 -46 88 -47 -4 -48 8 -47 -120 -47 125 -46 -48 -45 95 -43 1 -41 -114 -40 -24 -39 2 -37 -34 -37 -121 -36 15 -35 -125 -35 -24 -35 58 -34 107 -34 107 -34 47 -34 -74 -35 13 -35 76 -36 -115 -37 -23 -38 122 -38 84 -38 -115 -38 56 -37 95 -36 0 -34 10 -32 90 -30 -59 -28 30 -25 68 -23 33 -21 -74 -20 20 -18 83 -17 -113 -16 -35 -15 69 -13 -63 -12 66 -10 -71 -9 25 -7 99 -6 -96 -5 -33 -4 46 -2 -110 -1 7 1 -123 2 3 4 -124 5 15 7 -79 8 118 10 93 12 96 14 110 16 116 18 95 20 29 22 -97 23 -38 24 -55 25 112 26 -36 26 31 27 78 27 -128 27 -58 27 48 28 -56 28 -107 29 -8 28 11 30 66 31 -112 32 -31 33 33 35 59 36 30 37 -59 37 53 38 127 38 -67 38 13 39 -118 39 68 40 69 41 -117 42 14 44 -58 45 -97 47 -123 49 95 51 26 53 -86 54 16 56 78 57 105 58 96 59 46 60 -50 60 58 61 111 61 104 61 26 61 120 60 124 59 38 58 -121 56 -71 54 -38 52 3 51 70 49 -87 47 39 46 -71 44 83 43 -19 41 -128 40 11 39 -112 37 17 36 -108 34 27 33 -90 31 47 30 -81 28 33 27 -123 25 -26 23 86 22 -18 20 -61 19 -25 18 90 18 15 18 -22 17 -55 17 -122 17 7 17 60 16 41 15 -33 13 125 12 34 11 -23 9 -37 8 -7 7 51 7 121 6 -63 5 4 5 61 4 97 3 95 2 37 1 -86 -1 -16 -3 14 -4 36 -6 90 -8 -49 -10 -102 -11 -62 -12 66 -12 9 -12 0 -12 2 -12 -22 -13 -113 -13 -48 -14 -96 -15 4 -16 23 -18 3 -20 -9 -23 32 -24 -95 -26 -113 -27 -10 -28 -43 -28 39 -27 -28 -27 -4 -26 86 -24 -47 -23 74 -21 -93 -20 -45 -19 -27 -18 -15 -17 12 -15 61 -14 120 -13 -94 -12 -95 -11 106 -10 5 -9 -122 -9 5 -8 -113 -8 29 -7 -109 -7 -52 -7 -94 -7 -2 -8 -28 -9 111 -10 -56 -12 29 -13 -118 -15 29 -16 -51 -18 -115 -19 82 -20 30 -21 1 -22 15 -23 89 -24 -32 -25 -105 -25 97 -25 38 -25 -49 -26 87 -26 -65 -27 18 -27 88 -28 -102 -29 -37 -30 27 -30 90 -31 -101 -32 -30 -33 49 -33 -120 -34 -30 -35 56 -35 -126 -36 -64 -37 -11 -38 44 -38 112 -39 -64 -40 21 -40 99 -41 -101 -42 -69 -43 -51 -44 -23 -45 44 -45 -72 -46 -86 -46 21 -45 -6 -45 72 -43 -38 -42 -124 -40 26 -38 124 -37 -104 -36 114 -35 21 -34 -107 -34 3 -33 104 -33 -64 -33 -5 -33 6 -32 -45 -33 93 -33 -79 -34 -25 -35 26 -35 102 -36 -30 -37 -94 -37 -66 -37 72 -36 81 -35 -38 -34 -44 -32 29 -29 -120 -27 -27 -25 12 -22 -26 -21 112 -19 -69 -18 -30 -17 5 -15 60 -14 -110 -13 2 -11 123 -10 -22 -9 64 -7 122 -6 -94 -5 -53 -4 5 -2 87 -1 -66 0 46 2 -99 3 9 5 124 6 4 8 -79 9 -123 11 121 13 125 15 124 17 99 19 32 21 -94 22 -34 23 -53 24 110 25 -48 25 7 26 39 26 71 26 122 26 -48 26 85 27 16 28 117 27 123 28 -88 29 -17 30 63 32 -128 33 -99 34 -125 35 41 36 -110 36 -50 36 -8 36 50 37 -105 37 59 38 39 39 89 40 -52 41 117 43 69 45 37 47 -3 48 -74 50 65 52 -96 53 -40 54 -17 55 -25 56 -72 57 92 58 -49 58 13 59 20 59 -39 58 78 58 103 57 34 56 -115 54 -59 52 -22 50 24 49 98 47 -49 45 92 44 -3 42 -87 41 84 40 -8 38 -109 37 37 36 -76 34 68 33 -38 31 117 30 16 29 -93 27 38 26 -105 24 -1 22 112 21 4 20 -43 18 -10 17 107 17 43 17 24 17 14 17 -26 16 -128 16 -54 15 -59 14 -126 13 33 12 -60 10 -118 9 -126 8 -86 7 -15 6 70 6 -101 5 -21 4 51 4 108 3 -123 2 102 1 0 0 86 -2 121 -4 -114 -6 -67 -8 43 -9 -15 -11 23 -11 -103 -12 104 -12 109 -12 -122 -12 -117 -12 81 -12 -77 -13 -99 -14 17 -15 42 -17 20 -19 -1 -22 27 -23 -115 -25 109 -26 -58 -27 -105 -27 -35 -27 -114 -26 -99 -25 -10 -24 117 -22 -11 -21 81 -19 124 -18 127 -17 120 -16 -124 -15 -82 -14 -21 -13 28 -11 34 -10 -21 -10 126 -9 -12 -9 105 -8 -16 -8 -122 -7 16 -6 101 -6 88 -6 -52 -7 -64 -8 78 -9 -91 -11 -10 -13 100 -14 -2 -16 -69 -17 -119 -18 88 -19 40 -20 7 -21 15 -22 86 -23 -31 -24 -93 -24 125 -24 82 -24 10 -24 -100 -25 12 -25 100 -26 -80 -27 -8 -28 64 -28 -121 -29 -51 -30 20 -30 96 -31 -76 -32 19 -32 120 -33 -40 -34 45 -34 113 -35 -86 -36 -28 -37 42 -37 -126 -38 -29 -39 61 -39 -127 -40 -90 -41 -74 -42 -57 -43 -7 -44 110 -44 71 -44 -101 -44 112 -43 -74 -42 74 -40 -4 -39 -100 -37 5 -35 36 -34 -5 -34 -105 -33 15 -32 118 -32 -39 -32 52 -31 122 -31 -110 -31 104 -31 -8 -32 74 -32 120 -33 -97 -34 -36 -35 69 -35 -16 -36 -17 -36 90 -35 68 -34 -77 -33 -100 -31 -35 -29 72 -26 -87 -24 -46 -22 -87 -20 41 -18 98 -17 114 -16 123 -15 -101 -14 -34 -13 66 -11 -76 -10 29 -8 106 -7 -106 -6 -85 -5 -67 -4 -31 -3 34 -1 124 0 -31 1 66 3 -101 4 -10 5 100 7 -8 8 -72 10 -99 12 -107 14 -115 16 111 18 42 20 -83 21 -23 22 -41 23 117 24 -48 24 -5 24 13 25 29 25 62 25 -126 25 -12 25 -99 26 -9 25 -17 26 17 28 82 29 -97 30 -30 31 2 33 -20 33 -109 34 -9 34 38 35 62 35 96 35 -83 35 58 36 17 37 48 38 -111 39 42 41 -16 42 -53 44 -94 46 89 48 -32 49 54 51 102 52 120 53 111 54 68 55 -19 55 100 56 -86 56 -67 56 -107 56 33 56 81 55 30 54 -107 52 -46 50 -7 48 43 47 124 45 -13 43 -114 42 64 41 -3 39 -70 38 111 37 25 36 -70 34 86 33 -13 31 -106 30 65 29 -18 27 -107 26 43 25 -85 23 28 22 -113 20 31 19 -23 17 5 17 123 16 67 16 66 16 80 16 67 16 -8 15 88 15 98 14 39 13 -58 11 102 10 42 9 37 8 87 7 -82 6 17 6 114 5 -51 4 36 4 113 3 -92 2 -94 1 86 0 -68 -2 -25 -4 -6 -6 35 -7 -119 -9 73 -10 108 -11 -17 -12 -59 -12 -42 -12 4 -11 38 -11 14 -11 -109 -12 -103 -13 32 -14 65 -16 41 -18 11 -20 26 -22 126 -24 80 -25 -101 -26 96 -26 -104 -26 59 -25 65 -24 -107 -23 25 -21 -95 -20 3 -18 42 -17 30 -16 1 -15 -6 -15 27 -13 90 -12 -108 -11 -94 -10 109 -9 -7 -9 97 -8 -55 -8 73 -7 -27 -7 -126 -6 -12 -6 7 -5 -106 -6 -102 -7 44 -8 127 -10 -54 -12 55 -13 -40 -15 -92 -16 -125 -17 94 -18 50 -19 13 -20 13 -21 79 -22 -36 -23 -88 -23 -108 -23 122 -23 65 -23 -34 -24 85 -24 -78 -25 2 -25 81 -26 -96 -27 -17 -28 61 -28 -119 -29 -40 -30 50 -30 -104 -31 6 -31 115 -32 -45 -33 32 -33 92 -34 -105 -35 -33 -36 61 -36 -86 -37 19 -37 100 -38 -111 -39 -96 -40 -88 -41 -55 -42 39 -42 -26 -43 32 -42 -30 -42 31 -40 -76 -39 110 -37 24 -35 -118 -34 -83 -33 -126 -32 23 -31 -123 -31 -29 -31 66 -30 -95 -30 -16 -30 22 -29 -6 -30 -112 -30 -30 -31 8 -31 36 -32 84 -33 -83 -34 66 -34 39 -34 114 -34 58 -33 -115 -32 99 -30 -101 -28 6 -25 108 -23 -103 -21 112 -19 -24 -18 15 -16 7 -15 -11 -15 -4 -14 43 -12 -125 -11 -18 -10 83 -8 -103 -7 -72 -6 -71 -5 -77 -4 -64 -3 -18 -2 59 0 -105 1 -19 2 52 4 118 5 -55 6 66 8 -20 9 -62 11 -80 13 -97 15 123 17 52 19 -73 20 -10 21 -28 22 -128 23 -45 23 -13 23 -9 23 -9 23 8 24 57 24 -104 24 46 25 116 24 92 25 115 26 -85 27 -11 28 57 30 95 31 77 32 -9 32 87 33 124 33 -128 33 -119 33 -68 33 50 34 -12 34 -1 35 76 37 -44 38 -116 40 98 42 56 44 -18 45 112 47 -67 48 -30 49 -19 50 -28 51 -68 52 105 53 -28 53 47 54 78 54 57 54 -33 53 40 53 9 52 -115 50 -49 48 -7 46 46 45 -124 43 6 42 -81 40 114 39 65 38 17 37 -39 35 -109 34 67 33 -20 31 -106 30 70 29 1 28 -63 26 125 25 40 24 -70 22 52 21 -87 19 53 18 -8 16 13 16 -126 15 80 15 95 15 -122 15 -106 15 103 15 -32 14 -4 13 -54 12 106 11 5 10 -61 8 -64 7 -3 6 100 6 -40 5 69 5 -86 4 13 4 110 3 -67 2 -37 1 -84 0 38 -1 88 -3 106 -5 -117 -7 -23 -9 -95 -10 -64 -11 68 -11 30 -11 58 -11 123 -11 -70 -11 -57 -11 114 -11 -103 -12 54 -13 97 -15 71 -17 32 -19 34 -21 119 -23 59 -24 122 -25 49 -25 91 -25 -17 -25 -24 -24 54 -22 -66 -21 80 -19 -68 -18 -30 -17 -58 -16 -112 -15 112 -14 -124 -13 -59 -12 11 -10 37 -9 -13 -9 119 -8 -48 -8 38 -7 -99 -7 59 -6 -21 -6 123 -5 -78 -5 96 -5 120 -6 15 -7 92 -9 -98 -11 8 -12 -80 -14 -116 -15 126 -16 106 -17 68 -18 27 -19 17 -20 74 -21 -40 -22 -81 -22 -84 -22 -90 -22 125 -22 38 -22 -92 -23 5 -23 91 -24 -81 -25 6 -25 94 -26 -77 -27 5 -27 89 -28 -74 -29 35 -29 -100 -30 22 -30 -125 -31 -39 -32 26 -32 84 -33 -100 -34 -1 -35 121 -35 -12 -36 85 -36 -116 -37 -100 -38 -100 -39 -83 -40 -13 -41 -106 -41 -75 -41 96 -40 -111 -39 38 -37 -23 -36 -96 -34 28 -32 68 -31 23 -30 -92 -30 7 -29 90 -29 -78 -29 19 -28 110 -28 -92 -28 -104 -28 56 -28 -118 -29 -87 -30 -70 -31 -35 -32 40 -32 -86 -33 115 -33 -100 -33 65 -32 116 -31 51 -29 97 -27 -52 -25 55 -22 107 -20 67 -18 -77 -17 -54 -16 -88 -15 121 -14 99 -13 125 -12 -57 -11 44 -9 -114 -8 -49 -7 -29 -6 -48 -5 -79 -4 -93 -3 -67 -2 -3 -1 81 1 -98 2 -44 3 -3 4 49 6 -116 7 32 9 -27 10 -56 12 -82 14 -125 16 55 18 -69 19 -3 20 -19 21 -121 22 -44 22 -24 22 -34 22 -49 22 -49 22 -18 22 58 23 -68 23 -39 22 -79 23 -71 24 -27 25 40 27 105 28 -112 29 -126 30 45 31 -116 31 -88 31 -101 31 -115 31 -89 31 6 32 -77 32 -86 33 -31 34 82 36 -7 37 -60 39 -107 41 72 43 -62 44 2 46 24 47 24 48 11 49 -28 49 -108 50 16 51 93 51 -125 51 127 51 62 51 -94 50 -100 49 48 48 124 46 -84 44 -25 42 71 41 -42 39 -113 38 101 37 73 36 45 35 8 34 -42 32 -105 31 80 30 7 29 -57 27 -110 26 103 25 59 24 -2 22 -91 21 46 20 -86 18 54 17 -12 15 3 15 118 14 73 14 100 14 -95 14 -51 14 -70 14 76 14 124 13 86 12 -6 10 -109 9 78 8 77 7 -107 6 14 6 -108 5 15 5 124 4 -24 3 91 3 -59 2 5 2 -10 0 -119 -1 -55 -3 -33 -5 -2 -7 87 -8 11 -9 41 -10 -83 -11 -117 -11 -83 -11 -3 -11 84 -10 -124 -10 85 -10 -97 -11 86 -12 -112 -14 123 -16 83 -18 78 -20 -103 -22 83 -23 -119 -24 55 -24 84 -24 -40 -24 -65 -23 1 -21 -120 -20 34 -18 -105 -17 -68 -16 -113 -15 60 -14 -1 -14 1 -12 64 -11 -113 -10 -76 -9 -122 -8 2 -7 74 -7 -116 -7 -12 -7 -113 -6 76 -5 -9 -5 81 -4 33 -4 80 -5 -16 -7 59 -8 119 -10 -32 -12 -112 -13 126 -14 -120 -15 -119 -16 110 -17 69 -18 49 -19 97 -20 -19 -21 -50 -21 -35 -21 -21 -21 -45 -21 -121 -21 13 -21 115 -22 -51 -23 39 -23 -120 -24 -22 -25 73 -25 -94 -26 -5 -27 93 -27 -48 -28 83 -28 -37 -29 87 -29 -70 -30 1 -30 60 -31 -125 -32 -22 -33 113 -33 -1 -34 115 -34 -72 -35 -51 -36 -54 -37 -49 -38 4 -38 -115 -39 -113 -39 33 -38 65 -37 -47 -36 -103 -34 88 -32 -37 -31 5 -29 -44 -29 89 -28 -80 -28 -10 -28 69 -27 -91 -27 8 -26 79 -26 85 -26 1 -26 86 -27 113 -28 121 -29 -108 -30 -43 -31 74 -31 -3 -32 7 -31 -121 -31 -105 -30 59 -28 88 -26 -68 -24 39 -21 93 -19 52 -17 -101 -16 -96 -15 101 -14 23 -13 -29 -13 -28 -12 29 -10 122 -9 -40 -8 20 -6 28 -5 -10 -5 -69 -4 -111 -3 -109 -2 -60 -1 15 1 84 2 123 3 -119 4 -100 5 -41 6 80 8 2 10 -43 11 -82 13 118 15 34 17 -95 18 -29 19 -43 20 109 21 -77 21 -67 21 -89 21 -117 21 124 21 -117 21 -60 21 51 22 47 21 -11 21 -20 22 10 24 68 25 -126 26 -85 27 -95 28 80 29 -82 29 -61 29 -90 29 -128 29 125 29 -61 29 92 30 63 31 95 32 -73 33 70 35 4 37 -47 38 -126 40 -10 41 39 43 41 44 27 45 8 46 -27 46 -104 47 21 48 96 48 -118 48 -106 48 112 48 -11 47 10 47 -80 45 7 44 60 42 125 40 -25 38 -125 37 78 36 56 35 50 34 43 33 28 32 -2 30 -47 29 -101 28 98 27 48 26 12 25 -10 23 -30 22 -64 21 -128 20 28 19 -95 17 45 16 -27 14 -18 13 91 13 48 13 88 13 -86 13 -13 13 -1 13 -83 13 -13 12 -36 11 -121 10 29 9 -47 7 -50 6 33 6 -81 5 77 5 -42 4 73 4 -69 3 60 3 -61 2 41 2 64 1 -16 -1 65 -2 92 -4 120 -6 -53 -8 123 -9 -105 -10 28 -10 -4 -11 35 -10 125 -10 -20 -10 63 -9 59 -9 -83 -10 -126 -11 -51 -13 -64 -15 -104 -17 -115 -19 -49 -21 127 -22 -84 -23 82 -23 100 -23 -42 -23 -89 -22 -40 -21 90 -19 -2 -18 -127 -16 -86 -15 109 -14 -8 -14 -107 -13 127 -12 -70 -11 21 -9 73 -8 34 -7 -105 -7 -53 -7 -11 -7 73 -6 -35 -6 -93 -5 107 -4 -21 -4 -29 -4 45 -4 -38 -6 34 -7 85 -9 -71 -11 113 -12 115 -13 -103 -14 -76 -15 -87 -16 -128 -17 97 -18 -125 -19 11 -19 -11 -20 25 -19 61 -19 55 -19 -9 -20 -123 -20 -15 -21 79 -21 -81 -22 24 -22 -121 -23 -14 -24 83 -24 -80 -25 22 -25 -113 -26 28 -26 -78 -27 63 -27 -78 -28 3 -28 61 -29 -128 -30 -24 -31 125 -31 33 -31 -84 -32 1 -32 30 -33 25 -34 22 -35 57 -36 -88 -37 -118 -37 -3 -37 9 -35 -110 -34 94 -32 39 -30 -78 -29 -34 -28 -86 -27 39 -26 112 -26 -89 -26 -23 -26 69 -25 -79 -25 10 -24 37 -24 -31 -25 60 -25 83 -26 82 -27 100 -28 -97 -29 10 -29 -86 -30 -109 -30 -21 -30 -45 -29 86 -27 95 -25 -69 -23 38 -20 95 -18 54 -16 -106 -15 -118 -14 52 -13 -58 -13 112 -12 84 -11 122 -10 -50 -9 41 -7 98 -6 97 -5 38 -4 -49 -4 -123 -3 106 -2 -118 -1 -49 0 14 2 39 3 26 4 8 5 30 6 120 7 21 9 -38 10 -92 12 94 14 -4 15 119 17 -71 18 -82 19 70 20 -122 20 -123 20 99 20 58 20 29 20 27 20 65 20 -100 20 -109 19 73 20 46 21 61 22 107 23 -90 24 -48 25 -54 26 126 27 -33 27 -16 27 -59 27 -122 27 102 27 -111 27 23 28 -22 28 -12 29 48 31 -91 32 82 34 28 36 -49 37 63 39 97 40 76 41 42 42 16 43 -14 43 -83 44 41 45 111 45 -104 45 -79 45 -89 45 79 45 -126 44 61 43 -99 41 -41 39 29 38 -113 36 57 35 20 34 19 33 34 32 49 31 54 30 45 29 19 28 -19 26 -61 25 -97 24 -118 23 -121 22 -116 21 -122 20 97 19 18 18 -95 16 46 15 -32 13 -32 12 71 12 27 12 76 12 -77 12 24 13 68 13 14 13 107 12 102 11 26 10 -83 8 87 7 77 6 -88 5 79 5 7 5 -96 4 23 4 -119 3 21 3 -73 2 68 2 -123 1 84 0 -72 -2 -40 -4 -14 -6 63 -7 -23 -9 3 -9 -119 -10 107 -10 -108 -10 -12 -10 118 -9 -21 -9 21 -8 -78 -9 -89 -10 5 -11 0 -13 -39 -16 -55 -18 3 -19 -88 -21 -52 -22 108 -22 117 -22 -41 -22 -111 -21 -85 -20 35 -18 -47 -17 104 -15 -100 -14 82 -13 -71 -13 41 -12 -12 -12 41 -10 -109 -9 -37 -8 -67 -7 44 -6 76 -6 92 -6 -104 -6 31 -5 -20 -5 -50 -4 119 -3 -103 -3 5 -3 -65 -5 4 -6 43 -8 -121 -10 68 -11 90 -12 -98 -13 -41 -14 -32 -15 -70 -16 -115 -17 -99 -18 27 -18 14 -18 72 -18 -124 -18 -111 -18 94 -18 -13 -19 100 -19 -59 -20 41 -20 -101 -21 23 -21 -112 -22 -6 -23 90 -23 -62 -24 64 -24 -42 -25 122 -25 25 -25 -98 -26 -5 -27 53 -27 112 -28 -43 -29 117 -29 50 -29 -40 -30 64 -30 101 -31 96 -32 85 -33 106 -34 -63 -35 -126 -35 -45 -35 -59 -34 70 -32 24 -30 -20 -29 127 -27 -82 -26 119 -25 -20 -25 41 -24 79 -24 -127 -24 -43 -24 72 -23 -75 -23 -23 -23 -72 -23 27 -23 45 -24 34 -25 43 -26 99 -27 -55 -28 89 -28 36 -28 81 -28 14 -27 111 -26 98 -24 -76 -22 31 -19 93 -17 54 -15 -111 -14 117 -13 6 -12 120 -12 -2 -12 -62 -11 -45 -10 31 -8 122 -7 -78 -6 -86 -5 94 -4 -21 -4 125 -3 67 -2 80 -1 -112 0 -49 1 -33 2 -71 3 -128 4 109 5 -89 6 49 8 -24 9 -92 11 77 13 -35 14 80 16 -108 17 -114 18 40 19 98 19 87 19 39 19 -13 18 -54 18 -71 18 -52 18 18 19 44 18 -45 18 -87 19 -88 20 -54 21 1 23 46 24 45 25 -28 25 73 26 91 26 39 26 -47 25 -109 25 -91 25 28 26 -29 26 -36 27 -3 28 85 30 -15 31 -72 33 113 35 -30 36 -9 37 -54 38 -111 39 110 40 86 41 27 42 -102 42 -41 42 -7 42 26 43 42 43 -11 42 71 42 21 41 125 39 -70 37 3 36 124 34 49 33 28 32 44 31 78 30 113 29 -119 28 -110 27 -118 26 115 25 85 24 60 23 51 22 64 21 90 20 111 19 100 18 42 17 -59 15 82 14 -2 12 -10 11 85 11 37 11 91 11 -46 11 83 12 -99 12 -126 12 -14 11 -2 10 -67 9 81 8 -18 6 -42 5 53 5 -12 4 -53 4 118 4 -19 3 89 3 -22 2 -94 2 85 2 -65 1 -81 0 36 -1 73 -3 96 -5 -89 -7 74 -8 97 -9 -22 -10 -50 -10 -8 -10 88 -9 -27 -9 121 -8 -50 -8 -106 -8 -85 -9 26 -10 29 -12 -9 -15 -27 -17 23 -18 -78 -20 -51 -21 105 -21 110 -21 -60 -21 101 -20 101 -19 -49 -18 -124 -16 51 -14 122 -13 42 -12 108 -12 -83 -12 83 -11 -128 -10 -5 -9 91 -7 75 -6 -75 -6 -62 -6 -72 -6 -38 -6 81 -5 30 -4 22 -3 -25 -3 53 -2 -62 -3 -116 -4 -51 -6 -27 -8 53 -9 -12 -11 28 -11 124 -12 -44 -13 -11 -14 -44 -15 -102 -16 -110 -17 3 -17 -4 -18 76 -17 -94 -17 -63 -17 -105 -17 51 -17 -87 -18 13 -18 114 -19 -22 -20 115 -20 -5 -21 110 -21 -49 -22 55 -22 -71 -23 87 -23 5 -23 -76 -24 77 -24 -71 -25 -12 -26 34 -26 127 -27 39 -27 -2 -28 -64 -28 59 -28 104 -29 99 -30 84 -31 94 -32 -94 -33 69 -33 115 -33 74 -32 -64 -31 -104 -29 121 -27 22 -25 72 -24 14 -23 124 -23 -81 -23 -58 -23 -26 -23 47 -22 -91 -22 37 -21 115 -21 88 -21 -60 -22 -47 -23 -69 -24 -69 -25 -15 -26 88 -26 -32 -27 -112 -27 -107 -27 40 -26 103 -25 69 -23 -115 -21 -8 -19 60 -16 26 -14 115 -13 75 -12 -58 -12 26 -11 127 -11 35 -10 31 -9 99 -8 -64 -7 -5 -6 -17 -5 -105 -4 12 -3 124 -3 32 -2 25 -1 87 0 -100 1 -86 2 111 3 16 4 -44 4 -18 5 102 7 21 9 -58 10 95 12 -35 13 71 15 -114 16 -112 17 46 18 100 18 78 18 19 18 -43 17 -92 17 -121 17 -120 17 -69 17 -68 16 85 17 27 18 7 19 25 20 75 21 124 22 -126 23 63 24 -88 24 -65 24 -122 24 25 24 -74 23 -89 23 15 24 -47 24 -68 25 -67 26 -15 27 118 29 58 31 -1 32 120 34 -127 35 54 36 -35 36 -83 37 -97 38 119 39 -6 39 42 40 60 40 96 40 -114 40 -125 40 -4 39 -34 38 77 37 -117 35 -42 33 84 32 20 31 15 30 51 29 106 28 -96 27 -53 26 -25 25 -14 24 -20 23 -37 22 -51 21 -49 20 -22 19 26 19 75 18 95 17 63 16 -25 14 117 13 25 12 5 11 91 10 36 10 90 10 -32 10 -128 11 -17 11 -15 11 117 11 -111 10 97 9 -6 7 -122 6 84 5 -81 4 -116 4 -114 4 82 4 -59 3 35 3 -79 2 127 2 93 2 -7 1 16 1 -103 -1 -63 -3 -44 -5 20 -6 -81 -8 -64 -9 74 -9 53 -9 94 -9 -71 -9 74 -8 -4 -8 -123 -7 -125 -7 -70 -8 59 -9 69 -11 34 -13 14 -15 56 -17 -58 -19 -42 -20 109 -20 114 -20 -64 -20 71 -19 35 -18 117 -17 49 -15 2 -13 105 -12 26 -11 52 -11 54 -11 -85 -11 -53 -10 92 -8 -33 -7 -28 -6 74 -5 64 -5 24 -5 29 -5 124 -5 68 -4 81 -3 79 -2 -47 -2 -119 -2 103 -3 -92 -5 -88 -7 -28 -9 -97 -10 -37 -11 92 -11 -40 -12 23 -12 3 -13 -71 -15 -112 -16 -24 -17 -26 -17 83 -16 -54 -16 -4 -16 -37 -16 124 -16 -8 -17 96 -17 -60 -18 61 -18 -44 -19 113 -19 -14 -20 82 -20 -76 -21 58 -21 -30 -22 -101 -22 86 -22 6 -22 -118 -23 -53 -24 -26 -25 45 -25 -37 -26 -46 -26 -70 -26 76 -26 -128 -27 123 -28 104 -29 106 -30 -100 -31 32 -31 35 -31 -43 -31 61 -29 30 -27 17 -25 -68 -24 -16 -23 -77 -22 27 -21 69 -21 77 -21 86 -21 -116 -21 3 -20 -103 -20 7 -19 8 -19 -127 -20 -117 -21 100 -22 86 -23 -117 -24 -6 -25 -128 -25 22 -25 -19 -26 77 -25 101 -24 44 -22 106 -20 -43 -18 33 -15 9 -13 99 -12 47 -11 -109 -11 -54 -11 11 -10 -120 -10 104 -9 -91 -8 9 -6 74 -5 61 -4 -38 -4 56 -3 -126 -3 -5 -3 -39 -2 22 0 106 1 125 2 47 3 -89 3 57 4 44 5 -110 6 61 8 -24 9 109 11 -44 12 50 14 125 15 -117 16 49 17 100 17 65 17 -8 16 -81 16 120 16 82 16 65 16 92 16 110 15 -2 15 -71 16 -112 17 -112 18 -69 19 -11 20 5 22 -59 22 49 23 80 23 28 23 -100 22 14 22 -41 21 49 22 -8 22 -35 23 -65 24 -56 25 48 27 -12 28 -53 30 84 32 88 33 -18 33 107 34 38 35 38 36 27 37 -86 37 -55 37 -64 37 -32 37 43 38 81 38 -13 37 -21 36 94 35 -104 33 -31 31 100 30 44 29 52 28 106 27 -75 26 -2 25 58 25 104 24 -123 23 -113 22 -119 21 -125 20 -114 19 -76 18 -11 17 65 17 118 16 113 15 40 14 -75 12 78 11 45 10 120 9 58 9 108 9 -5 9 -71 10 82 11 117 11 7 11 45 10 18 9 -69 7 54 6 -39 4 33 4 33 4 92 4 62 4 -87 3 -16 2 116 2 83 2 92 2 45 2 113 1 12 0 53 -2 65 -4 122 -6 10 -7 16 -8 -101 -9 -111 -9 -66 -9 12 -8 -108 -8 96 -7 35 -6 93 -6 -71 -7 71 -8 84 -10 52 -12 32 -14 64 -16 -65 -18 -64 -19 83 -19 93 -19 -86 -19 27 -18 -53 -18 -6 -17 -71 -15 -77 -13 75 -11 9 -10 -6 -11 -77 -11 -22 -11 -7 -10 -90 -8 86 -6 120 -5 -37 -5 -72 -5 114 -5 89 -5 -100 -5 86 -4 116 -3 -95 -2 93 -1 68 -1 57 -2 115 -4 93 -6 122 -8 45 -9 124 -10 31 -10 -66 -11 31 -11 32 -12 -53 -14 117 -15 -90 -16 -90 -16 55 -15 -44 -15 27 -14 -2 -15 -95 -15 38 -15 -108 -16 -12 -17 103 -17 9 -17 -62 -18 86 -18 -79 -19 6 -19 -115 -20 68 -20 6 -20 -58 -21 -117 -21 51 -21 -126 -22 -126 -23 -92 -24 80 -24 112 -24 -124 -24 45 -24 102 -25 96 -26 73 -27 68 -28 107 -29 -46 -30 -89 -30 44 -29 -126 -28 113 -26 125 -24 56 -22 113 -21 46 -20 -111 -20 -74 -20 -78 -20 -94 -20 -66 -20 47 -19 -34 -19 114 -18 -111 -18 26 -18 34 -19 -25 -21 -61 -22 -11 -23 115 -23 2 -23 -125 -24 39 -24 81 -24 66 -23 -13 -22 39 -19 -110 -17 -23 -15 -30 -13 67 -11 4 -10 81 -10 111 -10 -113 -10 -30 -10 -97 -9 -42 -8 72 -6 -107 -5 -123 -4 29 -3 108 -3 -110 -3 -41 -3 -110 -2 -46 -1 62 1 97 2 5 3 84 3 -82 3 117 4 -54 5 122 7 38 9 -104 10 -29 11 48 13 -126 14 -93 15 85 16 -122 16 86 16 -4 15 -89 15 110 15 68 15 33 15 33 15 88 14 -26 14 -99 15 97 16 71 17 107 18 -77 19 -44 20 -105 21 -1 21 39 22 5 22 124 21 -68 20 79 20 -100 20 119 21 101 22 40 23 -1 23 71 25 13 27 -4 28 -98 30 -88 31 33 32 106 32 5 33 22 34 54 35 -37 35 -26 35 -74 35 -59 35 46 36 -118 36 89 36 101 35 -41 33 7 32 75 30 -47 28 -98 27 -83 26 -12 25 84 25 -84 24 -13 23 48 23 95 22 118 21 121 20 121 19 -120 18 -75 17 3 17 101 16 -71 15 -46 14 -105 13 34 12 -83 10 124 9 -67 8 120 8 -94 8 50 9 9 10 -46 10 29 11 -72 10 -39 9 -48 8 -100 7 15 6 114 4 -116 3 -79 3 59 4 68 4 -98 3 -61 2 54 2 30 2 78 2 90 2 -50 1 123 0 -101 -2 -100 -4 -47 -6 88 -7 75 -8 -50 -9 -41 -9 21 -8 80 -8 -68 -8 -105 -7 -101 -6 26 -5 -103 -6 44 -7 56 -9 26 -11 5 -13 29 -15 -117 -17 120 -18 2 -18 21 -18 110 -18 -48 -18 81 -17 80 -16 9 -14 49 -12 13 -10 -22 -10 -73 -10 28 -10 9 -10 1 -9 -50 -8 -74 -6 0 -4 97 -4 31 -4 -67 -5 -116 -5 -79 -5 81 -4 121 -3 -39 -2 -45 -1 -24 -1 -9 -2 48 -3 -2 -6 -16 -8 -114 -9 -13 -10 -68 -10 118 -10 -12 -11 25 -11 -61 -13 53 -14 42 -15 39 -15 -26 -15 -79 -14 12 -13 -18 -14 -115 -14 26 -14 -105 -15 -14 -16 80 -16 -11 -17 -45 -17 -122 -17 -41 -18 16 -18 -107 -19 101 -19 51 -19 -24 -20 -75 -20 -113 -20 2 -20 -30 -22 -62 -23 97 -23 -74 -23 3 -22 -67 -23 -11 -24 -17 -25 -44 -26 -58 -27 -24 -28 63 -28 -28 -29 47 -28 111 -27 116 -25 -94 -23 112 -21 -83 -20 103 -19 -62 -19 -28 -19 -34 -19 -72 -19 -84 -19 15 -18 -37 -18 -102 -17 -41 -17 114 -17 125 -18 45 -19 -25 -21 14 -21 -93 -22 75 -22 -67 -23 43 -23 26 -23 -25 -23 -120 -21 -74 -19 33 -16 -126 -14 -109 -12 7 -10 -66 -10 -17 -10 -7 -10 7 -9 47 -9 -69 -9 -22 -8 123 -6 -38 -5 -61 -4 84 -3 -91 -3 -79 -3 -71 -3 66 -2 -121 -1 28 1 88 2 -12 2 30 3 65 3 -47 3 21 5 -40 6 -110 8 -13 9 28 11 84 12 -83 13 -22 14 -82 15 -35 15 -96 15 52 15 -49 14 -108 14 114 14 68 14 32 14 37 13 -72 13 121 14 37 15 -32 15 -11 16 82 18 -112 19 88 20 -82 20 -42 20 -36 20 101 20 100 19 -100 18 -43 18 -35 19 -25 20 -120 21 22 22 43 23 -11 24 6 27 -59 28 -31 29 71 30 69 30 -97 30 -58 31 44 33 -10 33 -19 33 127 33 101 33 -16 33 -102 34 -98 34 -65 33 52 32 84 30 -116 28 28 27 -13 25 -1 24 85 24 -40 23 65 23 -118 22 -38 21 33 21 70 20 83 19 89 18 107 17 -97 16 -8 15 108 15 -26 14 40 14 0 13 -120 11 6 10 -66 8 -15 7 -81 7 -52 7 74 8 58 9 64 10 -61 10 111 10 116 9 105 8 -127 7 24 6 16 4 -70 2 18 3 37 4 102 4 -106 3 -116 2 -18 1 -43 1 40 2 -127 2 56 2 -6 0 11 -1 -8 -4 46 -5 -69 -7 -112 -8 -14 -9 24 -8 -118 -8 -81 -8 -45 -8 -81 -7 16 -5 -22 -5 -110 -5 35 -6 38 -8 16 -10 3 -12 18 -14 111 -16 69 -17 -70 -18 -41 -18 80 -17 -80 -17 -13 -17 -89 -16 73 -14 -92 -12 -34 -10 -5 -9 -93 -9 -102 -10 33 -10 -12 -10 -27 -8 24 -5 -96 -4 4 -3 -115 -4 4 -4 -49 -5 -45 -5 60 -4 99 -3 2 -1 75 0 -104 0 -65 -1 2 -2 -68 -5 111 -7 -38 -9 96 -9 111 -9 60 -9 -64 -10 38 -10 -6 -12 24 -13 -100 -15 -105 -15 -94 -14 -93 -13 20 -12 -10 -13 -125 -13 18 -13 -77 -14 23 -14 68 -15 -44 -16 -15 -16 -27 -16 37 -16 35 -17 -102 -18 -99 -18 -112 -18 31 -18 -47 -19 -9 -19 -58 -19 -124 -20 -25 -22 87 -22 11 -21 -70 -21 112 -21 -107 -22 -89 -23 -118 -24 96 -25 -123 -26 -28 -27 86 -27 68 -27 89 -26 -122 -24 -24 -22 -62 -20 2 -18 -65 -18 8 -17 33 -17 41 -17 -6 -18 -83 -18 -32 -18 -34 -17 -28 -16 49 -15 -37 -16 3 -16 -99 -18 28 -19 44 -20 -28 -21 -65 -21 49 -21 84 -22 -15 -23 -100 -22 48 -20 81 -18 -68 -16 34 -13 71 -11 -26 -10 -100 -9 -108 -9 -123 -9 -94 -9 -101 -9 -55 -9 -27 -8 -73 -6 59 -4 4 -3 -128 -3 -17 -3 -9 -3 -93 -3 -42 -3 32 -1 -4 0 95 2 -23 2 -12 2 -31 2 29 3 58 4 42 6 8 8 74 9 73 10 94 11 -79 12 34 14 7 15 32 15 -35 14 103 14 -33 13 -97 13 -104 13 110 13 19 13 -75 10 69 11 11 12 -123 12 -21 12 -66 13 6 15 48 16 -23 16 29 17 25 17 79 17 52 17 18 16 -31 14 -3 14 35 16 49 17 -97 17 -58 17 112 18 -4 19 -17 21 126 23 119 24 -22 24 -98 24 104 24 -118 25 34 27 -35 27 -43 27 65 27 -52 26 101 27 99 28 -121 28 -49 27 -110 26 -27 24 60 23 21 22 57 21 73 20 -77 19 -118 19 20 19 90 18 -33 17 100 17 -95 16 -34 15 26 15 59 14 -102 13 27 13 -103 12 76 12 -31 11 -19 10 -97 9 92 8 42 7 79 6 60 6 83 6 125 6 99 7 -120 8 34 9 -2 8 14 8 -38 6 107 6 -39 5 -120 3 -121 1 32 2 -57 3 61 4 61 3 27 2 -86 1 123 1 -68 1 111 2 116 2 107 1 -62 -1 -43 -3 72 -4 50 -5 29 -6 71 -7 115 -7 70 -6 101 -6 -15 -7 -106 -6 70 -4 79 -3 37 -3 -19 -5 23 -6 100 -8 -69 -10 -11 -12 -115 -13 -126 -14 -33 -15 -3 -15 -113 -14 -1 -14 -9 -14 41 -13 122 -12 -100 -10 -41 -8 56 -6 -49 -7 108 -8 -89 -9 32 -8 -15 -7 28 -4 -99 -3 37 -2 104 -3 -90 -4 -71 -4 -90 -4 -112 -4 -114 -3 53 -1 -118 0 18 1 89 0 -28 -2 9 -3 -53 -6 21 -7 -64 -8 74 -7 46 -7 116 -8 67 -8 -56 -9 -51 -11 -63 -13 -56 -13 43 -11 24 -10 -124 -10 -123 -10 1 -10 125 -11 105 -11 22 -11 18 -12 103 -13 -48 -13 65 -12 108 -13 73 -14 -76 -15 -36 -15 68 -14 -97 -15 -18 -16 110 -15 -31 -15 -67 -16 -80 -18 -52 -19 -42 -18 43 -16 -92 -17 -108 -18 57 -18 63 -19 -16 -21 74 -21 -18 -22 78 -22 -48 -23 109 -22 127 -20 -22 -18 86 -16 95 -15 56 -14 59 -14 61 -14 105 -14 69 -14 -33 -15 125 -15 -111 -14 27 -12 6 -12 -55 -13 101 -13 22 -14 124 -16 -113 -17 118 -17 -113 -17 65 -17 49 -18 95 -19 -6 -19 85 -17 -22 -16 34 -13 37 -11 -24 -10 -116 -8 92 -7 -24 -8 -109 -8 25 -7 -7 -8 123 -8 76 -7 69 -5 -53 -4 70 -3 93 -3 5 -2 80 -2 113 -3 71 -3 73 -2 63 0 -48 1 -48 1 1 2 -59 1 -101 1 61 2 16 4 64 6 -65 6 -118 7 -98 8 38 9 -25 10 13 12 -112 11 -112 11 104 11 -39 10 -51 10 -42 10 -51 10 -57 10 elektroid-3.2.3/test/res/connectors/microfreak_wavetable.data000066400000000000000000000402541500236517400244450ustar00rootroot00000000000000RIFF@WAVEfmt }JUNK4smpl<zdata@'+Z  '8 3 r{x1uԝY >s**$2C6A6F;8F88X%6+! dw !#\8ɴüNto^χğxQ+<7J)]XN OnU>5=/'4J(^$Rʹs)jENԊa5;Wh!Y\bLyO.ZoC:b?)w&J  ל,^-W(M1d W'FPJ];fZecgVNFG/-u:'! iOʫT5SG;uv^&,0:{BgqPiuqZ\;\GUGqJ1&' iḴҳpϒ'K!0mU^[lj^9n+kAUVN14_23 x% ^0̼8ޞ12EiȦDziGfko:I@eq~̜s7 {y!;U=Yj{ng[leYOYH7;n*GZig"c3 ΨE*IӠ(BF8\jf`gpb`wfQR@n@- )f h߀R"R5+PVI":rI H]Nj\a`^aJDG6\0X6#Q8bbщ+ɬۭޠE7&ިxZv{&{4;WbV^aOUYDC?=%\/: ߌݮש"&X+j_)}CkHI\Y`XdbK)GQCH-,0dRnFKNqПA՝"*0 ;X]Ye_ O\SN=?L<$qk=ɟntrߵw٫ھkU|6-PJ/M(N ^VY#Tqb[JL@)($O<?&QK-"[nþ1m2V4?TT%Yg+^{PR Eq5=4#GiD˜qNu׮qW4ɢEFF2KIS6a VQZAOE Ld>)' k/ m!ҔXOs<n‹öÚ۾G"6p6LC=QKU1bVMQS@<3q6)S7"JJ;EDN Gb`L'`4YDEUaTR/VEoA~Gx6+W, 6 iaḢJ[Ҳu6n4}[32R OmN?>=3׸I˥Q;4$4(H<^CCW\ RWT^A>=f-),>j \ CIߔ`~t.lٶzSlSZ/-6=RVOUSaGMKt961T~*NI\Ożnp\+ c=B '2EEF^UTOaXR@>77B%'(&PV Wv ^ݵ2:h^\s 3"5@zTRPYP$EH2A(46R0PjU };u\ ѹ̠ׄ6i~ !S(8KxI@KTMgKZUIKf?.A3"#< &Y%͜ ۽Ǻo G.+:`8zCPMPzZ8OD%F8w.3q)!M  iֽE`WFlc~տgb%<)f=KHPUJIMA"KTBR ".;9CN/HH*MoAZ9=c4*.$y77HG"l2å?n ;!/2@K(DjDJ@@CG5<45'>\5F ʐ|H\1מٶ7?#'%85?;C8HB9GKB?89o,&*tv߯nӛH9&NǜN޺l(~02BHAHH==1?424&bXM I/ݐYU¥ܺX*#+=B=DC=DEi::8($#mI +S< ŀ<кhK u1L35AB>|H:G;F@&:=5Z06.0}%'%u Lej~6콱ؿ˷n>+8v7>B9:?8U7<3 ** @# U@'ҠǡMv/*`>9 !u-5-6<77G=C;:< 2.0(h"#[P. qϖϜ˨~gb41FY X.L66=@B9:;1)486.**}'[!6לԫͺòȌB!^ʾӟ',=E'.1<<5J;Y5F;{74:55-/M+"&L#@/1p<̡ť{M]bTО`JM p,,48>8:7 ;l2U-1-G)-)X58ێ1 ̌Ap u``!%1:/6 681"16/,/( e"6f_;|ӵ`Z:ñV԰L-",@):0.J5.93d6D90:,.r'%*:#:# >J/+ځ͆˙-#!_TDB߁ #&=494 87.V./)*o.;& ?H@ђxǹ]Xeɗ:ޑ~ x.3.1~6B5 /)4T4+, -##/% C ͸@%Įǥ\ҚՑ\}.; X#'C*U4>5E27A6,,*#'9*" I0V,+~Ч#گ O#12'3B83w- 0, 'V+*"" 7zR rZ̟D9ɮϠԢގO? m)G+?.)561s/50t*,'7!y$#Mp|g e n<Ӌz@x&Т] =' 10>371,>-&"(% 6#}c ̦ˢn˫ɴ!he K G ,,2?6/F.01*'*\%"z{ 7^ԋ>ʖʣҞѷӦ]YJ!#,C1&.14-,+"@ |#~t![ y2;=)X΢k6ܘ $+-L45-.-,$ $& 6" "WΥґleD ~$ (?12z-/F/C))) KKZ K/ЙP6.Df!%-.Z,.,#[!/o13 I ;:L^Nwմ6@s*,-A1+%&"p\LQc qFXJ3f( 8` '#%)1/y,),' 9 0:OL ntc-a޺֑^ն҈1-vI F"e++A.0B*$#RS1Lv F *xdk-" =[oַ+cN& (\-0*+(( "Q  pj כ՚|ܬVn S ',*--&$!bw[  ([}1<;ٗ u;K!'l)/1)]'%%qn   ^rcֲ}eژ}%"G F $,-*+<)#!2y  . ] z]٤ҫf؀[f}r %()!0N.'n'". hANog$/݊Gڭ֍ZِNJm #.(//*U*`%9]CN!$]tcL8.ؾ_>H"**K+J.)g%%n d Rd]IkTݵ؞րbT?X; )"$*0i-*)X"|x) ]bijv0tk֊ڨڞ'Kj:'r.,,},%"! t[LbٱC*s t@/!T'',/*()Z(k ! ? r/{wU@/LݢJ|KF <I"N+`/--*D#]YU VT=>V+ -ߍyqt lQJ N/*'`+'+.Q-'2'$RJ5  (f|_sߤ> ܘ+ݔJfW} y\#&Q-g.,-;)v!P* e~^K{$/ݡgB! j!9+,-~0+(%W$pT<M# Eu;9ܖ3nn.q4k%<(*W/E-**%d @ ; $ E;0ߟ۽Y;AAY4&-d-.0)$!b `h7 5=|-2ݔEfzI )'+.U1,3)b'!`| d=2Jr$3$=߸ܜky5 !/%~+/\-/F.&#/ gaLu' 7Lo#"Ug n%+O-p1,2+'$1X: nTHFyE~ߴ9~IF%,*l00.-2*# 5 paRQ߻h݅43"9+ ..2{0)k'!L!G߷VOqB#m) .32.,& F3a  %@_~]hޑNTM% !k)U00014-'%l MjpF@kYߚTb2y) d)},1<51.+*$  &eE -3P ` &.(4"3120) %w"h%uI߾8߷/Fu c0'. 034`0-)!' LT@N2Uކݕ86Frb+ %C+26743/*'"5 '%,Wc4+1o;B/q}#v.W335&4-*&]o ۨtlecs!u$U+ 05g6\4<3-Q%&  EIU"]{ٽ;Ldv r)`356 8d3+G(#"|xMxhڡz`B + 14H8R63b1B*"#! =ޣ2qG۵ڬ߻ 7t IR&N/X6Z7:8824*%t& c}׳LrbE v&048:62-p&= e܀G>ׯژpo*]&,4,9]88p7/(#\]Z A#F7^#Rjب5qx/S8]!,47; <6;1'+j"Z p]agٔ~J7AMgm~B "+2:;9884+&X IO&-9<5*M#TOsM. ~( (28F:=l;5 0(v<vAۅՃѮк~׷ߛOc (07=>:+80(# ^Ax;uwvSҲg,ESJ71NsA7&/8^;<=k92#.% 4g}T/A,Ҩ@O U@3 *$.4K;`@>S;7A.%lj &o;fۉiԪ|I Rہl4ZjQZ#+5B=>>=6%0V+!M<@ܓװѰΌ5ЗwPPmT|mt ,5n9>A=c:5+#|_ Zaz^&W̙-=K1=T)^1:$@@@6=14-'^Yi Hٮ!7̵˵ ԭ#:c ^ #'2:=AcA<^82(I Y Td\@9̻ͭadd)  T'/!7>AA/A;2+"V u|_NَS `>Хh&9# QJ#t-87>,A;DAF;5,.$0 R۰Τ̢ ȕxg׍-da i#.6x<BBA(@n8/B) T)Ԍ̆ȳəυ;-N ?lI"6*3<@CEA9931*' LS]ݐpŃƽтٟ4"lM)4:TA)ECAl=4-%>| &:c Fޡթ̺UƔmV18 8N) 1#:@B\E`E>7 1\&T Pxݦب4&Fæɛp(uXaQA1 C&%_0[9 ?DNGDA:Z1)!"/ wvi]ٞD͟ÆŬj˕ ֧'o% |p%b/c7@ZD'EFC<5%."aIY'ӒU$\}P #_,6=qBGGCD?,8P.%{w +w%ܾkĘ <Ǝ*Ӷ$m(D 9!,4 =DTGGUFA82)pk %y#x bk&/K4]X*m!)3\=%BEH GB=5+! R1JypaM ƺӈ$8{7(2:AGH)HF>6b7#szϢ3)[QS m'03:BEHIE@';2'o aمҧʿbu}?ԐG %/9{?EIfI:HmD:<4P+/KBӁuJdNڑZL U3$- 6?wFHJID>7~-#+ 4?Ծ@ îȘHݷO;Tb;_"+69?oD3IJWI&GAq9X1}' 5EC ΢Ě꽰j}܄`@j[ +.4H$6-#6( ڈrŘ!нM¬դބ_6 };'2:FBH&KK9L2G?9H0$J)k[hZHu^*~ &.8JBGKnNLHB;92)  y*͓ƅ&fOÿȞ׬_".8@GL!MLJDp=7R,  {fROȊ"qr:OI 5@X3",5? GJNOKF@7X. %43&I]ȉU#,~?эK& )4~>EKbONLH@:2'G( .EwڮѸNq?n_ϝq-8) ,(43t4* yH l% Eh2 ַOcƚݴP,M&-0;CI,OPO{L_Fq>878.#2#eB,JA_ٺ3qyV#/59B.KNPPbM GA:a0%'n< 5"זLjcwԸj_Z*E ",v7YBIMVQ1QNJD;3)^ S69ڒEɻÉ̶bʿ6Ŀ~܅ D*5$?QHOHQQ)QKD>6$,O#) EoWTbs3(n+څ(2Z>HMQ SP>MMHA80h%9fVşSõ;C΃ߺ]za%1H@s9/l%GqTQܖѺc3VwYң_cY*'8BLSVsWgV QJD;1( /A@fIkZ(Dxx '4@GKQWhYAWPSlME^=5*!py\24񶊳ܰF/16@̘ա"<1g>HQwWXhXQU@NG0A]7- %1f}nϷ߸eݼVe F +.;GPvUlYYfVXQKB90s& [{OȓaԲ}Xcپ^')u8DKNUY2ZX~SK0E<2)n! EY˶›׵+ŰAM;(w`/ &4AMTXF[YTN&H>:6,"i2*טęͶ/Ҹ~-":1?JSYb[ZW-QqIA}8z.&r5 )ppsaݾZ1ʵb%s]Z-L;IHS7Xn[{\XhR1LlD:Z2)} ,܊9Cpٳ'hٰSiżͩ) %)8zFoPAW[\AZUINF}>U4*5"{9è'X?ᶩ+uޮ*%4BANVZ#]\DWPIM@6H.$vMZ O6U}үw,2Ĺ!Ȝй !0?uLTZ]\ YRPKZC:R0&~ n_ZVƸͰƮCڳ*H+ `-\W-PGn?N6,#8 PD;pFz,eȅѢJF#W4BNX\&^]PYRnKBI8. &0 _FLVbԮcxk۸D}/t>>LU[o_^ZTMNDN;1([^u?(񱢯8nq< ˉ;&M * ;HS[_^\VIOH^>44M+Y"qq0e3Y`ɷsa&w6sEQFYA^ `]XRkJ@P7d-$5 ]9\]ulQAq6ٽ 2ANWi^` _%[SnLC90'u bڳYl9"BP̮63 X-G=K^V\ ``[3VOF<{3)r pDL݂4!+a"c$ $"߸ïF|$]x Q%e6@E&Q~Z_`^YRJAf7v.z%2 t׬v۴٭Q|س(z 31$ANW]`_ZuUMD:&1P' MŎ1~rv7T ;v,< JTc\__\WbOGA=`3*!%QJޞӑɍL.`ֵ6Ӭs'7rF_R+Z^D`\?XQ>I?6f-# h$rͮ&9¸P_"z3BnNW]R_]s**$2C6A6F;8F88X%6+! dw !#\8ɴüNto^χğxQ+<7J)]XN OnU>5=/'4J(^$Rʹs)jENԊa5;Wh!Y\bLyO.ZoC:b?)w&J  ל,^-W(M1d W'FPJ];fZecgVNFG/-u:'! iOʫT5SG;uv^&,0:{BgqPiuqZ\;\GUGqJ1&' iḴҳpϒ'K!0mU^[lj^9n+kAUVN14_23 x% ^0̼8ޞ12EiȦDziGfko:I@eq~̜s7 {y!;U=Yj{ng[leYOYH7;n*GZig"c3 ΨE*IӠ(BF8\jf`gpb`wfQR@n@- )f h߀R"R5+PVI":rI H]Nj\a`^aJDG6\0X6#Q8bbщ+ɬۭޠE7&ިxZv{&{4;WbV^aOUYDC?=%\/: ߌݮש"&X+j_)}CkHI\Y`XdbK)GQCH-,0dRnFKNqПA՝"*0 ;X]Ye_ O\SN=?L<$qk=ɟntrߵw٫ھkU|6-PJ/M(N ^VY#Tqb[JL@)($O<?&QK-"[nþ1m2V4?TT%Yg+^{PR Eq5=4#GiD˜qNu׮qW4ɢEFF2KIS6a VQZAOE Ld>)' k/ m!ҔXOs<n‹öÚ۾G"6p6LC=QKU1bVMQS@<3q6)S7"JJ;EDN Gb`L'`4YDEUaTR/VEoA~Gx6+W, 6 iaḢJ[Ҳu6n4}[32R OmN?>=3׸I˥Q;4$4(H<^CCW\ RWT^A>=f-),>j \ CIߔ`~t.lٶzSlSZ/-6=RVOUSaGMKt961T~*NI\Ożnp\+ c=B '2EEF^UTOaXR@>77B%'(&PV Wv ^ݵ2:h^\s 3"5@zTRPYP$EH2A(46R0PjU };u\ ѹ̠ׄ6i~ !S(8KxI@KTMgKZUIKf?.A3"#< &Y%͜ ۽Ǻo G.+:`8zCPMPzZ8OD%F8w.3q)!M  iֽE`WFlc~տgb%<)f=KHPUJIMA"KTBR ".;9CN/HH*MoAZ9=c4*.$y77HG"l2å?n ;!/2@K(DjDJ@@CG5<45'>\5F ʐ|H\1מٶ7?#'%85?;C8HB9GKB?89o,&*tv߯nӛH9&NǜN޺l(~02BHAHH==1?424&bXM I/ݐYU¥ܺX*#+=B=DC=DEi::8($#mI +S< ŀ<кhK u1L35AB>|H:G;F@&:=5Z06.0}%'%u Lej~6콱ؿ˷n>+8v7>B9:?8U7<3 ** @# U@'ҠǡMv/*`>9 !u-5-6<77G=C;:< 2.0(h"#[P. qϖϜ˨~gb41FY X.L66=@B9:;1)486.**}'[!6לԫͺòȌB!^ʾӟ',=E'.1<<5J;Y5F;{74:55-/M+"&L#@/1p<̡ť{M]bTО`JM p,,48>8:7 ;l2U-1-G)-)X58ێ1 ̌Ap u``!%1:/6 681"16/,/( e"6f_;|ӵ`Z:ñV԰L-",@):0.J5.93d6D90:,.r'%*:#:# >J/+ځ͆˙-#!_TDB߁ #&=494 87.V./)*o.;& ?H@ђxǹ]Xeɗ:ޑ~ x.3.1~6B5 /)4T4+, -##/% C ͸@%Įǥ\ҚՑ\}.; X#'C*U4>5E27A6,,*#'9*" I0V,+~Ч#گ O#12'3B83w- 0, 'V+*"" 7zR rZ̟D9ɮϠԢގO? m)G+?.)561s/50t*,'7!y$#Mp|g e n<Ӌz@x&Т] =' 10>371,>-&"(% 6#}c ̦ˢn˫ɴ!he K G ,,2?6/F.01*'*\%"z{ 7^ԋ>ʖʣҞѷӦ]YJ!#,C1&.14-,+"@ |#~t![ y2;=)X΢k6ܘ $+-L45-.-,$ $& 6" "WΥґleD ~$ (?12z-/F/C))) KKZ K/ЙP6.Df!%-.Z,.,#[!/o13 I ;:L^Nwմ6@s*,-A1+%&"p\LQc qFXJ3f( 8` '#%)1/y,),' 9 0:OL ntc-a޺֑^ն҈1-vI F"e++A.0B*$#RS1Lv F *xdk-" =[oַ+cN& (\-0*+(( "Q  pj כ՚|ܬVn S ',*--&$!bw[  ([}1<;ٗ u;K!'l)/1)]'%%qn   ^rcֲ}eژ}%"G F $,-*+<)#!2y  . ] z]٤ҫf؀[f}r %()!0N.'n'". hANog$/݊Gڭ֍ZِNJm #.(//*U*`%9]CN!$]tcL8.ؾ_>H"**K+J.)g%%n d Rd]IkTݵ؞րbT?X; )"$*0i-*)X"|x) ]bijv0tk֊ڨڞ'Kj:'r.,,},%"! t[LbٱC*s t@/!T'',/*()Z(k ! ? r/{wU@/LݢJ|KF <I"N+`/--*D#]YU VT=>V+ -ߍyqt lQJ N/*'`+'+.Q-'2'$RJ5  (f|_sߤ> ܘ+ݔJfW} y\#&Q-g.,-;)v!P* e~^K{$/ݡgB! j!9+,-~0+(%W$pT<M# Eu;9ܖ3nn.q4k%<(*W/E-**%d @ ; $ E;0ߟ۽Y;AAY4&-d-.0)$!b `h7 5=|-2ݔEfzI )'+.U1,3)b'!`| d=2Jr$3$=߸ܜky5 !/%~+/\-/F.&#/ gaLu' 7Lo#"Ug n%+O-p1,2+'$1X: nTHFyE~ߴ9~IF%,*l00.-2*# 5 paRQ߻h݅43"9+ ..2{0)k'!L!G߷VOqB#m) .32.,& F3a  %@_~]hޑNTM% !k)U00014-'%l MjpF@kYߚTb2y) d)},1<51.+*$  &eE -3P ` &.(4"3120) %w"h%uI߾8߷/Fu c0'. 034`0-)!' LT@N2Uކݕ86Frb+ %C+26743/*'"5 '%,Wc4+1o;B/q}#v.W335&4-*&]o ۨtlecs!u$U+ 05g6\4<3-Q%&  EIU"]{ٽ;Ldv r)`356 8d3+G(#"|xMxhڡz`B + 14H8R63b1B*"#! =ޣ2qG۵ڬ߻ 7t IR&N/X6Z7:8824*%t& c}׳LrbE v&048:62-p&= e܀G>ׯژpo*]&,4,9]88p7/(#\]Z A#F7^#Rjب5qx/S8]!,47; <6;1'+j"Z p]agٔ~J7AMgm~B "+2:;9884+&X IO&-9<5*M#TOsM. ~( (28F:=l;5 0(v<vAۅՃѮк~׷ߛOc (07=>:+80(# ^Ax;uwvSҲg,ESJ71NsA7&/8^;<=k92#.% 4g}T/A,Ҩ@O U@3 *$.4K;`@>S;7A.%lj &o;fۉiԪ|I Rہl4ZjQZ#+5B=>>=6%0V+!M<@ܓװѰΌ5ЗwPPmT|mt ,5n9>A=c:5+#|_ Zaz^&W̙-=K1=T)^1:$@@@6=14-'^Yi Hٮ!7̵˵ ԭ#:c ^ #'2:=AcA<^82(I Y Td\@9̻ͭadd)  T'/!7>AA/A;2+"V u|_NَS `>Хh&9# QJ#t-87>,A;DAF;5,.$0 R۰Τ̢ ȕxg׍-da i#.6x<BBA(@n8/B) T)Ԍ̆ȳəυ;-N ?lI"6*3<@CEA9931*' LS]ݐpŃƽтٟ4"lM)4:TA)ECAl=4-%>| &:c Fޡթ̺UƔmV18 8N) 1#:@B\E`E>7 1\&T Pxݦب4&Fæɛp(uXaQA1 C&%_0[9 ?DNGDA:Z1)!"/ wvi]ٞD͟ÆŬj˕ ֧'o% |p%b/c7@ZD'EFC<5%."aIY'ӒU$\}P #_,6=qBGGCD?,8P.%{w +w%ܾkĘ <Ǝ*Ӷ$m(D 9!,4 =DTGGUFA82)pk %y#x bk&/K4]X*m!)3\=%BEH GB=5+! R1JypaM ƺӈ$8{7(2:AGH)HF>6b7#szϢ3)[QS m'03:BEHIE@';2'o aمҧʿbu}?ԐG %/9{?EIfI:HmD:<4P+/KBӁuJdNڑZL U3$- 6?wFHJID>7~-#+ 4?Ծ@ îȘHݷO;Tb;_"+69?oD3IJWI&GAq9X1}' 5EC ΢Ě꽰j}܄`@j[ +.4H$6-#6( ڈrŘ!нM¬դބ_6 };'2:FBH&KK9L2G?9H0$J)k[hZHu^*~ &.8JBGKnNLHB;92)  y*͓ƅ&fOÿȞ׬_".8@GL!MLJDp=7R,  {fROȊ"qr:OI 5@X3",5? GJNOKF@7X. %43&I]ȉU#,~?эK& )4~>EKbONLH@:2'G( .EwڮѸNq?n_ϝq-8) ,(43t4* yH l% Eh2 ַOcƚݴP,M&-0;CI,OPO{L_Fq>878.#2#eB,JA_ٺ3qyV#/59B.KNPPbM GA:a0%'n< 5"זLjcwԸj_Z*E ",v7YBIMVQ1QNJD;3)^ S69ڒEɻÉ̶bʿ6Ŀ~܅ D*5$?QHOHQQ)QKD>6$,O#) EoWTbs3(n+څ(2Z>HMQ SP>MMHA80h%9fVşSõ;C΃ߺ]za%1H@s9/l%GqTQܖѺc3VwYң_cY*'8BLSVsWgV QJD;1( /A@fIkZ(Dxx '4@GKQWhYAWPSlME^=5*!py\24񶊳ܰF/16@̘ա"<1g>HQwWXhXQU@NG0A]7- %1f}nϷ߸eݼVe F +.;GPvUlYYfVXQKB90s& [{OȓaԲ}Xcپ^')u8DKNUY2ZX~SK0E<2)n! EY˶›׵+ŰAM;(w`/ &4AMTXF[YTN&H>:6,"i2*טęͶ/Ҹ~-":1?JSYb[ZW-QqIA}8z.&r5 )ppsaݾZ1ʵb%s]Z-L;IHS7Xn[{\XhR1LlD:Z2)} ,܊9Cpٳ'hٰSiżͩ) %)8zFoPAW[\AZUINF}>U4*5"{9è'X?ᶩ+uޮ*%4BANVZ#]\DWPIM@6H.$vMZ O6U}үw,2Ĺ!Ȝй !0?uLTZ]\ YRPKZC:R0&~ n_ZVƸͰƮCڳ*H+ `-\W-PGn?N6,#8 PD;pFz,eȅѢJF#W4BNX\&^]PYRnKBI8. &0 _FLVbԮcxk۸D}/t>>LU[o_^ZTMNDN;1([^u?(񱢯8nq< ˉ;&M * ;HS[_^\VIOH^>44M+Y"qq0e3Y`ɷsa&w6sEQFYA^ `]XRkJ@P7d-$5 ]9\]ulQAq6ٽ 2ANWi^` _%[SnLC90'u bڳYl9"BP̮63 X-G=K^V\ ``[3VOF<{3)r pDL݂4!+a"c$ $"߸ïF|$]x Q%e6@E&Q~Z_`^YRJAf7v.z%2 t׬v۴٭Q|س(z 31$ANW]`_ZuUMD:&1P' MŎ1~rv7T ;v,< JTc\__\WbOGA=`3*!%QJޞӑɍL.`ֵ6Ӭs'7rF_R+Z^D`\?XQ>I?6f-# h$rͮ&9¸P_"z3BnNW]R_]) SV럟N v_< єW)U*$F֦*D9D\@X@V.P(PK]"聴i[*V!gXiQ8 9ԭ1}[@sj04\!)Q o Ɠ$MCݷl2"ucd}M5L@OzvdIMq,M$5$PF N4PUE#!ͮahΓHr' 9U*T l^giP3Gjgg!$zfg0g](7 ћ(Jt$SbANSa^&9eV"QY,Q8]emPs1Kp;C_c91V=fYmMނwժG*=E%9 ".I2c0_P0ō!J(> 'k{Ĵ"AIey/l&d)xg7@2Zjzke =ʋIed@5Qh4:pXk݁AOBj0OJ  ٚ;n}n_q }]@]iHo $K;d3 MEL_pgo%ϥgcڙ-SKoB ۯK{I,iHnfnj ጏ8CE9nq??, gE"~^CT8tz?ǿM_*s|lgO3[gϺ>c~*o؟v>%~>~}߬9?~9W_5>]gݿvRgߗqb/~~}_F_}-RBךf:]#>|]s}!=.{Ӻ輪ʵJcb $apxq/k9"'W~E[V,޻2OIJ}+jUrSW{ "ݟv/}7?-Oq;XzvG?*K={?c5O*{%_MW[ƿO{ZY;r?_]J\+'ngwo^;O,UmM}Z,},^NuݢO#.^ӳk냾Nmp]Mӵju wQqw0Klkkg1?_ko_~ȏZ=X ע˟SPvc=67x:u7b;9~7UE{n<./Ż¿cYg6 cC׸a޻;}e2=[[u G7^;_ޏ<^_˦џg>5"L.!ΛSX>o+.~+=[xm5=E2V*,С-^,l`ZDjťg -[.vC|lݫ::އSOvd T_`G\W6\8#wU|+6 3g6~8B﫽: q_s?{oK'~Go=òp% y߬}ޞWvI:>vGm 1$D :ݍ\ZKKn~4K~IpVDu}{e6_Tk6(^QSDt/@^yϳV1ֽ)NmWysKZa]4Ads?x|Avm7J7u6V7p]5t4g#~C#NxOMH(C~\{ދ]ٺ)¤8IP#"}ݽ%%{{6[Fp:r2kϦc-?+|tr.V=y𓿏ȭ>*b,svIYuxmL^4Qď> T ^I$N#O/XW$O-Yo^q$iqDkڨȚH0PEaPI;M+h| W]\r,\ܥ"caasb",Jc]92NH#aR@=O8\Kرrrap>#;V}Jɯ`qq%vh ,U|PJN+yGPJeS#.j:s]2SGVZ\a1;VW~Ob(-|^tq0S(M.b;[@9s`m`NԻ#mYM\yD`N ~6|&Oa>JqtlHv Oӟ>^5*{KT7tn3đW 33 ȵŖ] w) p)HXljOMKSAS2 |/UD/m| Mie3,:J!?Q:Y06b؞%yix0{-V㥟ʟt Ԋ˾pl9++ Ã4XoXŰeVĽ"97xYN|[ =&=bS&!9oHn;Μ]u9ņp&j{8p|sLJ,aa{̊õL#B*{kkФ0<_zոq{I.yOUM{cVIg߷4sNO~mhnuE*<=pGQ+|SpM?''9&Ձlneqb|XK!]te% qn L]Z,NܨFaZKx6) \:VX;HkS" /^s'1T2v齥I*@CW/E>R `Kww@>+V(6U}3zHb7] vzߑr<M>a Ѱc<^lf1z ߙv u8od#JhT EEdrViXoM*CXxa,rp/ZC9 8YH-lFy)@9~ž*%N@_ zc6\,Z]f; t@UiRKGi!% "T2Q Tk.1G1V`}8Rĩ6qi#"vBJy 3I( _>; +Xpjq2\hW";!;͋:BBS> ZgGɿŢ`OMLb塔V‚ik2aV̥򙡑[*PtKTBKq Y+p3 *9c}ٕERY`Q9TS\/?'xH *MyB13 ǃ A 㴈1Py*ʾf&$QKc{z\' .ӌJ&ã5nU¤6[k"D2WA"⊯ZmPL(K\TñT@Heo,.s\zK>V %dyJnml%> 1jۧVܲ*UKRؿzzqoNсj"*e'7|A?J8N -U͌'{#Jeh I `4^OpW9WxQb\ O!0u Xf'$;c;R,T05{3[ jONy3_@]a'L)JNC!KC-Ȋ}l W t@qZ+vNʽC hkj'|x~sNt+2 ?yp2]L,b{d+I\ԽWﴶmÛ}Tު蚭0n5g$ȇ( T_6;?6nЩή'ieܥdCev:"Z17`r'2.80lZ &K ʱ۝pkKRX#Ť{ J8zo;;#U^w6^OlPV9#\X3)ĠǐFť=ANt5 @Z/JW*$8JW[8?C3p q(+ (8LQOVyn _)Ў%1?(M6 -.#<6F44o)ZVR-fvuTnbW2*3l?Ym3y؛:?PUA?ö|_F4Kok%pBbU%-EPR)k+ 4, p/Š#Fd*1Wl9WU48H7Xsd-еihn#8 drrO-\]i(;nq>eN.*֡^F-O6qd`wZټh#qat4\tck ح.&+O?&x񋍶X@1SoOpŶ@kuYE3zfBd:fvR"&]T{q-5ju*rJq?hjI&įQ8IH4L#ewEfK 8Y듛$C-1*US7虚w&zT9F 3VǏ3܅SD inN%[teo#Ks]Ne۫q_+w;+&g ׃6v;@[va^x [`CJɝ\uQL U,!Q-?vcwӅRUW( QOބ D$AZYļ<4Se na^,?.fzI5hE]?#Ț'6'^:g~ 9=t¼'U6geKn=lpT9u =)[i-) @Y~m$7f<2_tgãd&_յ,4\U_QfEދ_ ;?Y~j'ܔvmUvҊɯqhNrZEAvn ؘn=s÷=о^S_R2l> 5p)nvQ_cBκr9*/|M !$M9.kvWyw5yU#@)7YFNxab_{BGb4Wޛ?i[AʔS)+?ISU.JN ~nfdDp3B@A3Y*Q'sPD=$2fqI8z.aǛkU$՛ho*u$Bb;nRo7'IBXA:r C/[E=r׀&[EK27oщ:X8EY  ibP'P6U~bI 6ưeqYtԻ T\JZ؎{&v$sSnr'qT+au. J8+::J` (g1pDɼ~"zb ( ۩ge)ҜSf !%#NMclo~=Mܱ%dHt6&Z+P粑Wb~2=]&ghQ4L+bu[jTkht_)ϔDhWeZ7kfv?g%AHW~LfY3F(s,; ttXEeHڏ@ឈf4>0ܪ)[Ncw!*I<]\0YM8If?qfO;EʏІ 7/I:(I5:%+"䉟;p<3 锆Frc4z,E􊱾IkFFY(b=bFl$];lVJDlEgbve&7Q9,i$0]JP0Ax3*VX:!fr\rd̄¢3[e`kXLa%c jE]hhLh*}_ʙt-AJ0h?[x?NGܼ>$*[r,2V:D$:9O(0E^=e (Nڪ6 SZ%͇{~n2B틞ZӗKJOL/⛴Ū:eqx|YSg3ڠϨ"4IZ1uXsN>AXU̬%!Iѡ$WYR$vt_*j!/=@ÒYM.nG3{ŤXQs1U ] U{튬@TS4es jA셕#@cڞАeJ5),A=v'+SGXt#4_ԏ+eߞALS^m46d&D;y#;<0pgiR+ԧ o[:mDLu}OcPVyT=fd +6DSCF@-3S2m4qq3j#tkNdJ^wi ~7;yR}؍;mO%[t}clZz2.|X,xw@Q6 \ `oǀxzZA] _&gT8MyKŬmq3XWM&e\#L6}$R.G]Ι 'C>bDj}!6l_RDrg(`WϢ&3yRKe0h^^B91I̢m @tyP!}+aAKμ$/k ڞ RJRk0.]j68k ,4$@d"jةsH%OevB!"<Φٔt9gDE,=Zs(^L7B34OZˤKC"; js6ɾROaV,:=jˆ9*jHV LA(Ǵ 'Ts~Y·òmM F&VT!vW=^c0_sz>Ζ3YZ֋*bsFd #@Q+XL!܆mo/\JfT-9iգZ{+Ӿe5Gk< zyhreS>ҽ8BNu\[T-d솚>1 *3Ŏ7,BY\x4ݙwA гdZB+AMc6w-9=-'s75yelMg*II8F2ɱt_~s3^}YR #Ψ=eoa,RS6 Dpn6NOI kP^ϑݛ;+2әCw'`Me3SկVzqS[o[x/OS ,Rt)y@O[;#'m5}ug6d}OθI$PDzPX\"v:|Ԫٜ"mS62IYS Lk1[Q5-禜Q&,Hɛ^ܬpIFXxa+ޥrbQHKP5fͤ «Ga]^z Sq. ,؃Ux= }p#wt=CXui(4U0@л W XeY:5g7Q-rMi5 5 8.z„W-n.9Ԭx"HC?e{g*=O\Y67s@`fB$,ip*ʀzF0R';,jY"v%Gyݺo 7|F9sڮ+2vxG1c9g ڼIFr/ud A}b OZhOoQ'oVoʔ']]UX vpJK[|QS:IcP*?̜^m&ڄa4K 5Ul#au( L=rp)ÃZjWYVtuAOT?zpA06U[~R8`B͔`e^ (ؗ*; ]Cҩy(R'Į<_';ᗍ#+qOGAH:;|l[XBC9w}U+48޶8ə#sj fTyAUD%8QF<͇iYní.wճQ"UBPh|PX{TKrJسׄj: mq>,C?rcp+s,'SP1mn7jvb+O&Ϊ2g1]NfCSYk|y .k*rţ=i\ 6i#BɦK941WD}YFQkQYOTT@`üӷ&lb)-$5py(Gv["4l•;rlB50hJ>\'MR'aV/cXbh3/],n2;dfIܛJye׳!쥯Z`q4G](ƍy> {F`i.SPD[B缼9^93*|ZYeY['.f*Υa{Gs'읋)&ͮWؠ洃=2Ja\r 6Ĥte)7:F}={SlM+Gm&UQTyLݓsdf$#I)e5M>71L^Μfpm5:а;e Ҝ!в3 n]7[|)_Ѯ9Mјfۚ?ЭhsxL\,r!dYn)BY~7m͂pr V=VbON8q-I`ik v6T34_9ay}>cDpn:F_lFS6yBC:B 帜d:2 ojm?E#4Ģ>r,gG TX*@ِ3c|1>g)RȲB{)*, ϢԬlOT \3RɗJn($&_w8yӈД &c9N\INxOC_y"'pXxS𮍃tV7Lsmj1bS5eg _2^Jai'kt}U ]٘R-tBSE$SǛWY^4dצ.9=Ms6[>%ښ=Wm<)5[{|!)Ux~t$:98OeN%ȳ~ ے֢+6Az!`R1+2f{`RM.ZfCv}pJ_·Lff}# {U.MT,ObeQ҉ @SoE*?ޅI)b'nT{`Lvwխ9zJe9vS kLUPESjapڋ{9Zqo* WI&#SPHt͐kBeڃB=1d J~>Ōe ).TIN]={$l[?G B !n%5&|6Y;MJPH{ƟbޫG\=ܞw3ߝ+r12^sFyZM{Wkլ7DZw#р‰e>̀X0V\OzbzrvUI1/paY@ή|wtg$CE c "§`BGӑ?+hÄb2, `lh\0\VЬABn[Rr@ L Ţql5 vsd`FK 69BQb)i [#sm5d"nRez3:[$޳p0i< OBݙ+~| &0 Iҋ lݠM}*WY<iWYI2M6̞uikCLSpC&/S;)AcaZ#43C79N1 =ݺz\3]Atr2/uh9,C&8$Imo~>X BlJO9]>~ۇ:8:4 05s-J;=.`ELdYNf6/iùbb39d()6Zz#1Iw/5o"T<ҴL wGdqwIJ^4(,T1 Pt]QAa>װb5@HǮrmg n dT-a4nۣ26#Iaۣփ{[0fÌԉnW/׌d&9ɐrzS=}L*Nѵ(m3T8My`22[?6=:!9-hY[0lD&M1Yׇ ytlQf%ENdShe$Ōg $π^SKT'RH9'p‰*L]jlٴW\CmcZ& Kdgz%̜a*@҂۵ 21ၔy]H(:iGrEhXufѐoK ?_TÞ>] ?fN]&t;w=+Vs1%mLf:-@ ')~1E}ZWkeLlԃ *U%;F\G02Km>-Y[9O(M?Zґ"xHZD_:C5e5-gT J[<5 riV,CTD"b+M&$w闏*O6,YKWshzBQϠo__z&_T6 64cEf)OVWMijKCq|n_܇E@]aa:ir#ٺc;#wP\,٠œWk'ᄓtF! lUcM2Hs}R"VSuēeRwrĢMPX*t~j8)5ҊYFn wGV:9ϓgW3֩7n]*꓄t,_[_.0z TaB-r;eHeC6"6'saT،g5V@hɩ²:/_ K$[JTB \Ng.[F:炙M^@<et>W xgϮ*FS^/acn&;C)[ʮskPʯ|QEWek=K^Ui)+87T$RKt[Ԋ7'ҳ bQQRE1+Ek"!YZ%:EOZ;a'A6VƧVFSS ^.k_Fnu ApRI2/ 7wzv7ЁH#U+)97f4Vw68BIz`jU{$̂t뉌 1H<'JtuH}kp1)`M/%T01?4eI5Ow'\J$sa 38w*%:6Lx+$I ]9a؛R3%PV7iגSo!X)?A$O{u=sO|&Ԭ?$6S#`3Tر(0&?$l0|NN L?^bts;%w 71N>aI!@G5Nn2YMvkלf"{ =_Ԭ6=)Q@Mdgw{CKSTիg}g;@J w3a1ԟӢ Wnׁݕ@GX8?[cJ˹O QErJUvWI壩bOF| `uq ѫnqNeG-oi-kfUebE)XK UD ɓPK0AVu5TW +mz)&25'yT lP\HSI'a^:K8->+$ vk?`jYԠW ͟zl2ڒIF+iȹݩ V&:]ʗ'?_IPK?~X\FuS 0_wavetablePK9Selektroid-3.2.3/test/res/connectors/phatty_preset.data000066400000000000000000000003011500236517400231510ustar00rootroot00000000000000c3)) (,8 ?7?????76(??( ??5?>   &"<? elektroid-3.2.3/test/res/connectors/phatty_preset.data.back000066400000000000000000000003011500236517400240500ustar00rootroot00000000000000c3$;1$ (,8 ?7?????76(??( ??5?>   &"<? elektroid-3.2.3/test/res/connectors/silence.wav000066400000000000000000000050141500236517400215720ustar00rootroot00000000000000RIFF WAVEfmt wJUNK4smpl<aQdata` elektroid-3.2.3/test/res/connectors/square-wav44.1k16b1c.wav000066400000000000000000002544641500236517400235010ustar00rootroot00000000000000RIFF,YWAVEfmt DXJUNK4smpl<XqdataX~Vh egle|geegeOge7ge gegefff,ffAffUffffftf}ffsffiffcff^ff[ffZff]ffifof,g\ d)Uszz|~~}|}~}zvs__Jg ffZffhffoffpffnffnffoffpffrffrfftffwff{f}f|f|f}fzffvffqffnffiffcff[fffc$Fhorsvwz{}}{yuohbQoc8f$ffQffaffgffjfflffoffsffwffyffyff|f{ffwffvffufftffpffnffkffgff`ffRffff_:$ƚSbkrvy}{vutsrndFqK"cffaffffflffoffrffuffyf~f|f|f}fzffwfftfftffsffrffoffpffpffoffnffgffYff fgKx qrx}}{{{ywvwyz{zybݙ= [PgSfffwffyf~f|f|f~fxffxffwffufftfftffufftffsffsffsfftffuffvffxff{f}fxffAfgX[]ϙi~|yyz{z{|}}~|z֘cKPgffaffnffrffqffpffoffpffrffsfftffuffwffyffxff{f|f}fzffwffqfflffhffifffJaa<;Llrtuwwwxy|{yurngb@XgffSffcffhffkffpffqffpffrfftffvffwffyff{f|f~fyfftffofflffjfffff_ffRff>fe/2ɓՙI_iruvz~|{ywuqmcHé+d`ffWffcffiffmffoffqfftffwff{f|f}fzffyffwffvffrffofflffjffiffgffcffVff fgoE߃Sslqvy}~|{zzxwyzyvmP*3_gnfsffoffrffuffxffzf}f|f{ffwfftffrffrffrffqffqffqffqffsfftffvfftffjff$fg?Tkx}|{{{|||||}~tvUg(ffmffvffwffvfftffrffsffqffqffrfftfftffufftffvffxf~f|fyffuffqffnffwfgfgl^ (Sryzyxwyzyxy~|xvtpwC7 Gg ffUffdffjffnffpffpffpffqffrffrffsffvffzf}f~fyffwfftffoffjffeff^ffVffnfqdl)ΘIenrtuwxy{~}{zwsnjcNʙיK4(f6ffSff_ffefflffoffrffsffuffvffzf~f|f{ffxffuffsffqffoffkffhfffffaffQfff5g<>֐]enuxy|~|{yvwvuneFHaffeffgffmfftffxff{f}f|f{ffyffuffvffvffvfftffrffqffpffqffqffqffmff`fffgNj蘙yw{~||{yxxyz{}}gՙP YugCffxf|f}f{f|f}f{f~fyffvfftffsffsffsffrffsfftffuffvffvffwffzf|ffxffxf}ffJfegZGٙbz||||zxvxzzz}~{wwˠlMgff]ffkffpffqffpffoffpffqffqffsffuffvffxffyf}f|fzffvffrffpfflfffffbfff|b) XFgpstvyzy|}}}{xtofZ&WT< gffOff`ffhfflffmfflffoffqffsffwff{f{f~fyffxffuffrffnfflffhfffff_ffRff.fjf\6™Nblrvwy|~}{yvrnjcF񙦘$'d}ff]ffeffiffkffoffuffyf~f{f|f}fzffxffuffsffqffpffqffqffnffkffkffiff[ff fgH䶞1~ptx}~}|{yxxxy{yrV-])gcfyffsfftffwff|fzffxffvffuffufftfftffsffqffpffpffrffuffwffxffyffrff1fgVx${™r~{xwxz|~}}~'Rgffjffuffvfftffqffoffpffqffsffrffsffsffuffxf~f{f|f~fyffwffuffrffmffpftff_,Nlsvwwxzxxz|ytohld|ݳCg ffTffcffkfflffnffnffpffsffuffvffuffyf}f~fxffwffxfftffoffjffgffaffVffTf9e-$Hdmoqvwz{~|xurnjaGܙY0eKffTff_ffhfflffoffqfftffxffyf}f}fzffwffwffuffuffrffnffmfflffiffcffSff fwgA(vvfiptwz~~zxxwutrqkM2`fzfnffmffpffsffxf~f{f}f|f|f}fyffvffrffrffqffpffqfftffufftfftffsffqffefffgQf@Ø|{~~{z{|zz{{{}mʙk:Wg6fftff|f}fzffuffsfftffrffoffpffrffsfftfftffvffxf~f|f|f~fzffyffwffvfffWf@g\ V4Ztxy{{yxxy{|}}zvr^ ^Jg ffZffhffkfflffmffoffqffqffrffsfftffxff{f{f~fyffwffvfftffoffjffdff_fffc$Ccnqsvy||~~|zwvrmdRpc8f$ffQff^ffffflffmffmffpffsffxffzf}f|f|ffwffuffsffsffpffoffkfffff^ffPffff_:#ƚWekqwzz}~|{zyxvsncEmM"cffafffffjffnffqffuffxf~f{f|f}fzffvfftffrffsffrffqffpffmfflfflffjff]ff fgK~ tuz|zy{zzzz{|||y_; [OgTfffvffxff{f|f}fzffwffuffuffuffsffrffrffqffrffsffuffvffxff|f|f~f{fzff?fgXZ_͙l~}{{yzyz{z}|z՘cJPgffbffpffsffrffpffqffrffqffqffrfftffuffvffzf}f|f|f}fzffvffpffnffjffjfffKaa=;Kltusuwxyz{|}xvrnfa@YgffRffbffiffmffnffoffqffrfftffvffzf}f|f|f}fzffwffsffpffmffkffgffaffSff?fe/2ɔՙJ`ksvwxy}}zzxtrqlbGê+daffVffaffiffmffpffrffvffxff{f}f~fyffyffwffsffpffnffnffmffmffjffcffTff fgoE߃Trnrvy|~|{zzvvvwtnR-2_gofrfflffpffuffzf|f}fzffxffvffufftffqffrffrffpffqffsffvffuffuffufflff'fg@Tl{|}{zzzyz{}uxUg*ffmffvffvffufftfftffsffqffqffrfftffuffuffvffwffzf~f|fzffvffsffqffwfhfgo^ (Sryyyyyzz{{{}~~yvrnwC9GgffXffhfflfflfflffnffpffpffqffuffyffyf~f|f|f}fyffvffsffqffnffjffdffZffofqdk)˘Fckqsssw{}zurpmcL̙יL4'f6ffRff^ffdffjffnffqffsffwffzf}f|f}f|f|f}fyffvffqffoffoffofflffgff`ffNfff5g<>֐^fmrvy}{z{|zvtpnhJGaffgffhffkffpffuffyf~f{f|f~fxffvffuffsffsffrffrffqffqffqffoffofflffafffgNj昙{z}~{yxz{{||}~|fՙP YrgGff}fxffzf|f~fyffxffwffsffqffqffrfftffsffrffsfftffuffyf~f|f{f~fyffyf|ffLfbgZëCܙ`z~}zyz{{|||{||yx͠mMg ff]ffkffnffnfflffmffrffsfftfftfftffuffwffyf}f}fzffuffsffnfflfffffafff}b+ \Khpsuvwwxy{~}{yupkd[(VT< gffQffbffgffjffmffpffrffqffsffxffzf}f}f|f}fyffvffrffnffkffhffeff_ffPff,fkf]6!Ockotx|~~{yxvuqmdF󙥘"'d|ff\ffcffiffpffsfftffvffxf~f{f{ffwffufftffsffqffoffnfflffkffjfffffYff fgH䷞0qtx|~|{yxwwxxsW.],gafzffpfftffxff|f|f}f{f~fyffvffrffqffqffrffqffrffsfftffuffvffyffyffpff0fgVw%zÙq~}}|yxxxz|~})Rg!ffiffqfftfftfftffrffqffqffrffqffqffsffuffxffyf~f{f{f~fxffuffpffjfflfxff_,Omsvwxxyz|~~zvqjlf|ݴCg ffSffdffiffkffmffnffnffqfftffwffxff{f}f|f|f}fzffvffrffoffkffgff`ffTffSf9e-%Gakqtvwz}}{zxtoi`GݙW 0eIffUffbffjffmffqffsfftffwffzf}f{f|ffxffvffvfftffqffpffoffmffhffaffPff fxgA(vufgpwzz}~~|yyywvvriK1`ffiffkffsffxffyf~fzf~f|fzffxffvffuffufftffrffqffqffpffqffqffqffqffgfffgQeA|~|ywyyyz|~}}pƙn9Wg7ffsffzf~fyffxffwfftffrffpffpffpffrfftffuffwffxffzf}f|f{f}f|f~fxffuff{f]f֎^dmtwz|~}zz{xvvspiJIaffdffgffmffqffsffxff{f{f}f{ffxffuffqffpffpffpffoffoffrffsffrffoffbfffgNj蘗xx||zyz{z{{{||zeՙPYwgBffxf}f}f{f~f{f}f|fzffwfftffrffpffpffqffsffsffsfftffuffyf~f|fzffxffwfffNfbgZEܙaz}|{{yy{z|}~~{wwʠiMg ff_ffmffoffnffnffoffqffrffrffsffvffxff{f}f|f|f}f{f~fzffwffuffoffgff`fffb' XGhpsuuuvz}}{xsmcV%YS< gffSffbfffffhffjffoffrffuffwffwffzf|ffxffvffuffsffrffofflffeff_ffQff+fmfZ6Pckptwz}~|{zxusqogG񙦘#'d{ff[ffbffjffoffqffsffxff|fzffzffyffwffuffsffrffpffoffnffmfflfffffWfffgH䴞3}puy~{yzxxwwx{{vY-]+gaf{ffrffuffxffzf|f}fyffxffvffsffsffsffsffqffpffpffqfftffxf~f{f~fzffrff2fgV{#{Ùp~}|zxxy|~~~~'Rg!ffiffsfftffrffrffqffqffrffrffpffpffqffuffyf~f|f|f~fxffwfftffpfflffpftff_,Nkswxxzyyz|~}xupike{ݳCg ffTffeffjfflffmffmffoffrffvffuffuffwff|fzffvffsffqffpffnffjffaffTffSf:e-"Falpsvxz~|{ywtplcIܙX 0eHffTffaffgffmffrfftffuffvffyf}f}fzffyffwffvfftffqffoffnffkffiffcffSff fygA(vvdfntz}}|}{xvuuvrkM5`f|fkffjffoffsffwffyf~f|f{f~fyffwffwffsffpffoffpffqffqffrffrffrffpffffffgQf@Ø}}~|{yxz|}||~kʙj;Wg9ffuffzf~fzffxffuffrffrffsffrffqffrffsfftfftffwffyf}f}fzffyffwfftff|f[f>g\ V5\w{zyxxxyz{|}|~{wtr^ ]JgffYffhfflffmffoffoffqffrfftffuffvffxff{f|f}f{f~fyffuffrffofflfffff^fffc$Gelruuvyz|~}|wtplcSpc8f&ffQff`fffffkffmffoffrffuffxf~fzf}f|f{f~fyffwffuffrffpffnffkffgff`ffRff ffa:"ƚSbkquwz~zyywtsspiIoN" cff^ffcffjffpfftffwffzf|f}f{f~fzffyffwfftffqffpffoffnffnffnffmffhff]fffgK| tw{}{zwwyzy{{|y`ߙ< [PgTfffxffxffyf}f}fzffvffvffuffsffsffrffpffrfftffvffvffwffxff{f|f}f|fwff=fgXY]Йh}~~}|zyy{{{z}|{y՘cMPgffeffoffqffqffqffrffqffqffqffrffuffwffxffwffxff{fzffuffqffoffjffifffLa`=9Jjruwwwyyy|~zvsohc@[g ffPffbffhfflffnffqffrffsffvffwffxffzf}f}fzffwffsffqffmffjffgffbffVffAfe02ɔԙIailqvy||wtttokaEê+dbffWffaffhffoffsffuffuffvffwff{fzffvffrffrffqffqffpffnffkffhffdffUff fgpE߃Upipw|}{zzyyyyxxwqS+4_gpfqffnffrffuffxff{f}f|f|ffwfftffsffrffpffpffrffrfftfftffuffvffufflff&fg?Tm}~|zyzzxxz}~wxUg,ffnffvffvffuffuffsffsffrffqffqffqffsffvffwffxf~f|f|f}f{ffwffrffoffvfhfgm^+Tquwyzzzzzy{|}zxsmvD7!Gg ffVffdffifflffoffpffpffqffsfftffxf~f{f|f}f{f|f|f~fxffuffofflffhffbffYffofodm)͘Hdknqtwz{~}ywuplbKΙәI4*f5ffRff^ffdfflffqffsffrffuffyf|f~fzf~fyffxfftffsffrffqffoffmffhffaffPfff7g:>֍^fnsvy}|yyxxtsogHHaffefffffjffqffvffxf~f|f{f~fzffyfftffrffqffqffqffsfftfftffqffoffkff_fffgNj昙xy}|zxwwx{||}~|gԙQYvgDffzfzffyf~f{f|f~fxffufftffsffrffqffpffqffsffvffxffxffzffzf}f|f{f}f{f{ffLfagZëCܙ`w|}~{zyzzzz{}~zuu̠nMgff]fflffpffpffoffoffpffpffqffrffuffxffyffzf}f|f{ffxffuffpffkffeffbfff}b* YHhquuvwxyz}~{yvsmeW%YR< gffPffaffjffmffnffoffpffsffwffyffzf~f|fzffxffvfftffrffoffjffdff_ffSff-fkf\6ęMakqtvy}~|zyyxvrlbE񙨘&'d}ff\ffdffjffnffrffsffwffxf~f|f{ffyffwffvffsffpffnffmfflffkffjffgffYff fgH䶞1pv{}}{{zxwwwwvtZ/]-g_f{ffqffsffwf~f{f|f~fyffwffufftffsffsffrffrffpffsffuffvffvffvffxffsff2fgVz#{Ùq~{zyzz{{|~~|)Rgffhfftffufftffrffpffoffoffqffsfftfftffvffwffyf~f{fzffxffuffpffkffnfvff_-Olswwxzzzy{~|zvpikf}ݳCg ffTffcffhffmffoffqffqffrffsffvffyffyf~fzf}f}fyffwffsffoffkffeff^ffTffUf8e-%F`joruz|~}zwtpkbHܙY 0eIffSffaffgffkffnffrffuffxffzf}f}f{ffxffvfftffsffrffpffmffkffhffdffTff fxgA)wtfhnrvz~~|ywvwxwuqkM2`f|flffkffpffsffvffzf|f~fzf~fxffvffsfftffufftffsffoffnffpffqffsffqffffffgQfA˜}|~~}|yxxxz{|}~mǙn7Wg8fftffxffwffxffwffuffsffsffsffsffsffrffrfftffvffxff{f{ffwffufftfffYf?g\ X3\vzz{{yxyyyz{|xts^ ^Jg ff[ffiffmffnffnfflffkffmffrffuffwffxff{f|f}f{f}fzffwffpffjfffffbff]fffc$Femqsvy{|~~~zwtpleUqc8f&ffQff_ffeffiffkffofftffwffyff{f|f|f|f~f{f~fxfftffrffqffmffifffffaffRff ffb:!ǚTclqsw|~|zwvutqneDnM"cff_ffffflffnffqfftffyf}f~fxffuffuffufftffrffqffpffqffqffnffmffjff]ff fgKz svz}~{yzzz{zz{{v]; [PgUfffuffxff{f{ffwffuffuffvffuffrffqffrfftfftffrffsffwffyf~f|f|f~f{fyff>fgXY_Ιi}}{|||zz{|||~z{՘cJPgffdffqffsffrffpffpffpffpffpffrfftfftffwffwff{f|f~fyffuffqffmffhffhfffKaa=:Klruvvvxy}}~~{yuqmhe@XgffPffaffgffkffmffoffoffrffuffyf~fzf~f{f{f}fzffuffsffqffnffjffgffaffTff@fe22ɗҙK_hotvxz|zywsojcGè+d`ffUff`ffhffnffrffuffvffyf~f|fzffyffvffvfftffrffpffqffofflffjfffffUfffglE߂Uqlqw{}|zz{|ywvvunP(7_gqfqffpffuffyf~f|f{f~fyffyffyffyffxffuffqffoffoffoffqfftffuffvffwffnff%fg>Tnz}{yxxz|}|~uyUg+fflfftffvffuffuffsffrffrffrffsffrfftffuffwffzf~f{f}f|fzffvffrffqff{fdfgj^,Touwtuwxwy|~}zwtnwC7!Gg ffWfffffiffjffnffpffqffoffqfftffxffzf}f|f|f}fzffvffrffoffmffiffcff[ffpfqdj)ɘEdmrtxyyz{~zxutoiaL̙֙I4*f5ffTffcffifflfflffoffsffwffyf~f{f|f~fzffyffyffuffrffnfflffjfffff`ffQfff5g<>֎^gnrux|}{yxvttsqjJJ߸affeffgffmffpfftffwff{f}f}fyffwfftfftffsffsffrffqffpffoffoffpfflff`fffgNh昚yz}~{zzxxxyz}}gԙQ YtgEff{fyffxff|fzffwffuffufftffrffqffqffsffrfftffwffyffzf~f{f|f~fzff{f{ffKfcgZHؙdy{|||{yvuy|||~{wtʠkMgff_ffnffqffqffqffrffpffoffrfftfftffuffvffxff{f{ffxfftffqffmffgffafffb& TEhsuuuy{|{{~{vsqmeY(UU< gffQff`fffffjfflffpffsffuffwffvffyffzf}f~fxffuffsffoffkffjffgffaffSff-fkfZ6ęLakquxz}~~}{yuqmmeF񙧘&'d~ff\ffcffjffmffnffqffvff|f{f~fyffwffsffrfftfftffrffoffmfflffkffiff[ff fgH䴞4|nsy}~~{ywwyyzzyuX-])gdfwffpffuffzf}f}f{f~fxffvfftfftffrffsffqffrffsfftfftffuffvffxffwffqff0fgVx${™r~}{yxyyz|}~~|*Rg!ffjfftffuffrffqffqffqffqffrffsffrffrfftffxff{f|f~fzffwfftffpfflffofuff_.Qotuutvwy|~|wphke}ݲCg ffTffcffhffkffmffmffpfftffvffvffwffxff{f{ffxfftffqffnfflffhff`ffTffTf:e-#Ickouy|}}}~~zxvsojdJۙY 0eGffTffbffhffjffmffrffvffxf~f|f|f}fzf~fzffwfftffqffpffnffnfflffjffdffSff fwgA'xtfgnsw{}~}|{yvvuvrjL1`f}fkffkffpffuffxffzf~f|f{f~fyffwfftfftffrffrffrffqffpffpffqffrffqffgfffgQeB~|}|{xxz|{z|məjTlz~~|{||{wxz~txUg+ffnffvffvffvffuffufftffsffrffrffqffpffsffvffwffzf|f~fzffwfftffpffvfhfgm^+Souwwwxzzz|}~|wplwC8GgffVffgfflffnffnffnffqffsffsffqfftffxf~f}fzffwffwfftffqffmffiffbffXffmfrdk)͘Hfkpswwy{}~{zxtpkbK̙יK4(f6ffRffaffgfflffmffoffpfftffvffzf|ffxffwfftffqffqffoffnffjfffffaffQfff6g:>֎]emtx{~}}{xutstrjJIaffgffhffkffpffvffxffyf~f|fzffxffuffsffqffoffpffpffqffqffqffpffmffafffgNk瘙zz~}|}|{zyz{|{}|f֙PYtgFff{fzf~f{f|f}fzffyffwffuffsffrffrffqffqffpffqffuffxff{f|f~fzffwffxf}ffLfbgZEڙd{~}}{zxwvxy{}}xuu̠mMgff]ffmffrffrffpffoffpffrffrffsffuffxffxffyf~f|f{ffxffvffqfflffgffbfff}b) ZHhprtuuux|zwvtmeY'WT< gffPffaffgffifflffpffqffrfftffxf~f|f{ffyffxffvffsffoffnffkffeff_ffQff,flf\6!Obkpuyz}zxwwvtmaC󙦘%'d|ff[ffbffhffnffsffvffxffyf}f}fzffxffwfftffqffqffqffqffnfflffjfffffXff fgH䴞3|ovy{~~|}|zzyxwxxxsW-],gaf{ffuffwffyff{f}f}fzffwffvffufftfftffsffqffqffrfftfftffvffwffxffrff2fgVz"}™r|{{zxxz{}}'Rg ffjffuffvffufftffsffsffqffqffqffrfftffuffwffyf}f}fzf~fxffuffrffpffqftff_*Mmstuwxyzz{}~}zsmile|ݳCg ffTfffffkffkffmffoffqffrffuffwffxffyff|f{f~fxffwffsffqffnffiff`ffSffPffgX\]Йh~~|zwvyz{|~~z{ӘeJPgffcffoffrffrffpffoffpffsffsffrffqffrffwff|f{f~fzf~fyffuffsffoffhffgfffIad9=Jhpswxxy{}}~~{wupib@YgffSffaffgffifflffnffoffrffvffxffzf}f}fzffxffwfftffqffoffkffhff`ffTff=fe-2ɒՙJcnqsvz}~}zxwsnibGé+dcffZffcffgffkffnffqfftffwffzf}f}fzffwffuffrffpffoffnffmfflffjffdffRfffgpE߅Sskqv|~~{wvxy{xtmP(7_grfrffpffsffvffyf}f|f{ffxffuffuffsffsffqffsffsffsffrffqffpffsffuffmff'fgATjx}|{{||{{{}}~wyUg-ffnfftfftffufftfftffsfftffrffrffqffrfftffwffzf}f}f{f~fyffyffuffrffvfhfgl^*Spwzyxwxwz|}~~~zwpkvD7 Gg ffVffffflffnffoffpffrffsffsffsfftffwf~f{f|ffxffyffvffrfflffhffaffVfflfsdi)˘Gemquwwy{}~{yxsqlbK͙֙J4*f5ffQffaffgffkfflffpffuffxffzf~f{f}f|f{f~fyffuffqffpffpffoffmffiffaffQfff7g9>֍]gnruwz~}yyxwvvvsqhJJ޸affgffhffmffsffvffwffyf~f|f|f}fyffwffsffsffqffqffpffpffpffoffnffmffafffgNh昙zy|}{yxyz{z{|}e֙P YrgGff|fzff{f{f~fyffwfftffsffsfftfftffrffrffrffsfftffwffzf}f{f}f|f|f}f{f{ffMfagZëCܙ`x|~}zyxz|||}}~~{xxΠmMgff]ffjffmffnffnffoffoffpffqfftffvffvffxff{f|f~fxffuffsffpfflffgffcfff{b+ ZHfosuvvvyz|~{xtqkcZ)VT< gffOffbffiffmffpffpffqffsfftffuffxf~f|f{ffwffuffrffpffofflfffff_ffOff+fmfZ6™Oclosx}|zxyyvsoeG𙧘$'d{ff[ffcffhfflffoffrffwff{f}f|fzffxffufftffqffoffnffmffmffnffmffiffYff fgH䷞0~orw|}}}|zxuwyywqV/].g_f{ffsfftffxffyf~f|fzffufftffuffufftffrffrffqffqffrfftffwffyf~fzffqff2fgVw%zÙp}}|{yxyyz|~~~(Rg!ffiffsfftffrffpffrffrffqffrffrfftfftffvffyf~f{f}f|f{ffxfftffqffnffofvff_.Pnuxyxuuvx{}~}zxuqkmd|ݲCg ffSffcffhffkfflffpffsfftffuffwffxffyf~f{f{ffwffuffrffpfflffhffbffVffUf8e-#Gclpsvxz|~{xusplbIۙY 0eGffQff^ffgfflffoffrffuffyff{f}f{f|f}fyffvffsffrffqffnffnfflffiffaffSff fwgA'wufgouy{~{zz{zxvwwtlK1`f}flfflffqffuffvffxf~f|fzffufftfftffufftffsffqffqffrffsffsffrffqffffffgQfA˜}}|yzyyyzz{}oǙm9Wg8ffuff{f}fzffyffwfftffrffrfftffrffsffsfftffsffuffwffzf|f~fxffuffvfffXf@g\ X3Zuzyzyxyxxy|}}zwuq!\ ^Jg ff[ffhfflffoffqffpffpffoffrfftffuffvffxff{f{ffwfftffqffnffjffbff[fffc$Igptuttvz~}yvuqldRoc8f$ffQffaffgffkfflffpffrfftffwffyf}f|f|f}fzffvfftffqffpffmffkfffffaffQffff`:#ǚTemsvz{|}}{zzxwtpleFoK"cffafffffjffnffrffvffyffzf|f~fyffvffufftffqffqffpffpffpffnfflffhffZff fgKy uvy~~}}zyxy{{{{y`ޙ< [OgUfffvffxffzf~f{f|f|f{ffvffrffpffoffoffqffuffufftfftffwffyf~f{f}f|f}fxff@fgXZ^ϙi}~~|zxwxz~~|}ԘdJPgffdffoffpffrffqffpffnffoffqffsfftffvffzf}f|f|f}fzffxffwffuffpffiffifffJab;fe02ɕԙKcknrv{}}}zxwvtrmdFé+daffVff`fffffkffoffsffvffyf}f}fzffxffwffvffsffqffpffnffmfflffjffeffUff fgpE߄Tqkqvy}}|{xwxwwwvoR,3_gofsfflffrffyf}f{f}f{f~fzf}f~fxffuffsfftffsffpffoffqffrffsfftffuffvffnff(fg>Tn{||zyy{{z{~xwUg,ffoffuffvffwffvffuffrffpffrffrffsffuffwffwffxffyf}f}f{ffxffvffsffxfhfgo^*Vsxvtuvxz{||~{vqnxB7 Gg ffYffgffmffoffnffnffoffnffoffrffuffwff{f{ffwffvfftffqffmffiffbffVffjfudi)̘Fbltvwx{||~~zywuqlcOəؙK4+f2ffNff]fffffkffnffqfftffuffxffzf}f|f{ffwffsffrffoffmfflffkffhffaffRfff3g=>֐^flrv{~}yvututpgGGaffeffhffoffrfftffxf~f}fyffxffxffxffvffsffpffpffpffpffqffpffpffmffafffgNj蘗xx|}{{ywxyz}fՙP YsgGff|fyffyf}f~fxffvffufftffsffsfftffsffsffrffrffrffuffxf}f}fyffwffxf}ffKfcgZ«Cݙ`z}{z{zxwxz}|zvvˠlMgff_ffnffqffpffnffoffoffpffqffrfftffuffwff{f{f~fxfftffrffpffnffiffefff}b( XEeosuuwy|{yvqlg\(WR< gffPff`ffeffiffmffpffrfftffuffxffzf}f}fzffwfftffrffofflffjffhffcffTff-flf\6 ™O`inty|}|yxxwuqjbF񙨘&'d}ffYffbffjffoffrfftffvffxf~f{f{ffxfftffqffpffrffqffpffoffnffkffgffYff fgH䶞1}nsx}~}zyyyxxxwtW.]+gcfxffqffuffyf}f~fyffyffyffwfftffsffrffrffrffqffrfftffvffvffwffxffqff1fgVx$zęo}{zz{zz{}{}|~)Rgffiffsfftfftffqffpffqffrffrffqffrffsffvffyf~f|f|f}f{ffyfftffqfflffnfwff_-Mnuvtuxxy|}zwrjnczݴCgffPff`ffhffmffpffqffqffpffqffuffxf~f|f}f|f{f~fyffuffrffoffkfffff`ffVffUf8e-%Gbkoqux{|~~|yxusqmbHܙY 0eJffUffaffgffjffnffqffuffvffyf~f|f{ffxffufftfftffqffmffjffkffiffdffSff fxgA)wtggmtz~|zxwwutttmN3`f}fmffnffqffrffuffzf}f|f{ffyffvffufftffsffsffqffpffqffrffrffrffpffffffgQf@Ø|}~}{z{zxwy}mʙk9Wg7ffuffzffwffvffvffvffuffsffrffsfftffsfftffsffvffwff|fzffxffwffwfffXf@g\ W3\uyzzyxvwwz}~}ytq^ _Jg ff\ffjfflffnffnffnffoffpffrffuffxffzf~fzf~fzf~f{f|f~fxffuffqffjffaffZfffc$Eepssuwxz~~|zupjbRod8f%ffOff\ffdffiffmffqfftffwffxffzf~f{f|f}fzffvffsffqffnfflfflffhffbffTffff`:#ƚS`iptx|}{xwutrneGqK"cff`ffgffkffnffrffvffyf~f|f}f}fzffxfftffrffpffoffnffoffoffoffpfflff^ff fgK| tvz~~|yvvxyz|~x]8 [QgRfffwffzf~fzf}f{f|ffwfftffsffrffrffrfftffuffuffvffvffwffxff{f|f|f~fvff֎^flsx{{}~{{zywwvtogHHafffffhfflffqffsffvff{fzffxffwffuffsffsffqffqffrffrffpffoffpffnffafffgNi昚zy|~~||{yyxyxz}}fՙPYugDffzfzffzf}f~fxffuffuffuffufftfftffsffqffqffrffuffwffzf}f}fzf~fyffzf|ffKfbgZëCܙ`x|}~~|{zzyxz}}zxw̠mMgff^ffkffoffpffoffnffoffoffrffsffvffxffyf~f{f}f|f|f~fyffuffqfflffeffbfff~b' WEgqtuvxxy|~}{vole\'YQ<gffRffaffhffkffoffrffsfftffuffxffzf}f|f|f~fyffyffvffqfflfffffdff`ffRff-flf[6ÙNcmqtw{~}|{{xvuqkcF񙨘''d}ff[ffdffjffmffoffrffuffzf~f|f{ffxffuffrffpffqffqffoffmffnfflffhffXff fgH䶞1}nsx{}{{|zxwwxwwpV-]-g_f}ffvffyf~f{f}f{f}f|f{f~fxffxffvfftffqffpffrfftfftfftfftfftffvffyffrff2fgVx%{™q~}|{zyy{|~{*Rgffifftffufftffsffsffqffoffoffpffrffsffuffvff{f|f~fyffwffsffqffmffpfuff_,Nmtwxwwwy{}}|zvrkld}ݲCg ffUffeffgffiffkffnffpffsfftffwffxffyff|f{ffxffuffqffnffjffiffbffXffVf7e-!D`mruuy{||~{yxuqpmeJۙZ 0eHffRff_ffhffnffrffsffsffvff{f|f}fzffzf~fxffuffrffpffoffnfflffiffcffSff fxgA(wufgnrw{~~{yxuvuuslM3`f}fkffjffoffrffuffzf|f~fyffwffuffrffqffrffsffsffrffrffqffqffqffsffifffgQfA~|~~{yyy{{{y}nșl9Wg9ffvf~f{f~fzffxffuffrffqffsffsffqffoffqfftffvffwff{f|f~fyffxffufftfffXfAg\ U5\uyyxxwwxzz{ztn ^`Jg ffYffgffkffmffrffsffrffpffqffsfftffwff{f|f}fzffyffxffuffoffjffcff]fffc$Ffpqqqtx|~~}yxvsmdSpc8f$ffRff`ffgffjffmffoffrffuffyffyffyf~f}fzffvfftffrffpffmffjfffff`ffOffff^:#ȚVfnrvy|}|{yvusrogIpM" cff_ffgfflffoffrffwffyf~f{f{f~fyffyffwffsffqffoffoffnffnffoffoffjff[ff fgK{ uy{~|{|{zxz{{zz{v\: [SgOfffvffwffzf}f|f|f}fyffwffuffsffrffqffsffrffrffsfftffuffwffzf}f}f|fwff?fgX[^Ιj}~~{{|{yxy|}~|z|ҘeLPgffeffoffqffpffoffpffqffrffqffsffsfftffuffyf~f{f{f~fyffuffqffmffhffhfffJac:;Jisttvxyy{}~~~~{unfa@ZgffRffcffhffkffnffqffsfftfftffuffwff{f{ffyffxffuffsffpfflfffff_ffRff>fe.2ɒ֙Iblqtvy{~~{zyxuqmcFé+daffWffaffeffkffnffqfftffxf}f}fzffxffwffsffpffqffrffpffmfflffjffeffWff fgoE߃Trmqtw}|zxxyyxvuoR*5_gnfsffnffqffwffxffzf~f|f{ffvfftffsfftffsffsffpffpffqffrfftffuffuffjff$fg?Tkx~{ywxy{|~~wxUg*ffoffxffxffvfftffsffrffpffqffrfftffuffvffwffwffxf~f|fyffufftffrffvfhfgl^,Tqwwvvxxyz|}~{vrnwD:Gg ffXffeffiffkffnffoffpffpffrfftffwff|f|f}f{f~fyffvffrffpffmffjffdffYffnfrdj)̘Gemqsuxzz||ywuqlbJ͙ՙJ4*f4ffQff^fffffjffnffqffuffwffzf~f{f|f~fzffwfftffsffsffqffmffkffhffcffRfff5g:>֌[dmsx{~~|ywwvusphHHafffffhfflffrffuffyf~f|f{ffxffxffxffvffuffsffqffnffoffpffqffpfflff_fffgNh昚z{~|}|{xxxz{}|e֙O YrgGffzf}f{f}f{f~fzffwfftffsffufftffqffpffrffrfftfftffwffzf|f}f{f~fyffxf~ffMfbgZEٙd{|{|||zxyz|}|}|xuʠkMgff^fflffpffoffoffoffpffrfftffvffufftffvffyf}f}fzffwffuffpffkffdffbfffzb, ZGhpqqsuxz}}yvrncX'VV< gffRff_ffeffiffmffnffpfftffwffzf}f|f{f~fzffwffvfftffrffoffkfffff`ffRff,flfZ6ęMblqvy{}~~}|zyvrpleH$'dzffYffaffgffnffsffvffwffzf}f}fzffwffufftffrffoffpffpffpffnfflffhff[ff fgH䵞2}nqv{}yyyyxxyxwqV-]-g^f~ffvffwffwffzf}f~fxffvffuffuffvffuffsffrffrffsffrfftffxffzf~fzffpff1fgVx%{™q{xxzzxyz}}~)Rg#ffjffrffrffqffpffqffsffrffrffsffsfftfftffwffzf}f|f|f~fxfftffpfflffofvff_-Onuvuwwxyy{}{wtpkld{ݴCg ffSffcffiffnffoffoffoffqffrfftffxff|f{ffxffxffwffsffnffkffgff`ffWffVf7e-#Gblqtuxz|~zwuspkbKڙZ 0eHffSff_fffffiffoffrfftffwff|f{f~fyffyffvfftffrffqffoffnffkffhffbffTfffvgA)uvehptwz|}||xwwvtsqkL4`fzfmffkffoffsffvffzf}f}fzffxffuffrffrffsfftffsffqffqffqffsffsffqffffffgQf@˜}}~|||{z{{zy{~~lʙk:Wg8fftffzffxffvffvffuffsffrffrffsffrffsffsffvffwff{f}f|f{f~fzffxffwfffXf?g\ Y1Zuzyxxxxzz{|}~|xtp!] ^Jg ff[ffiffmffoffoffoffpffsffsffsfftffuffwff{f|f~fwffvffrffnffjffbff\fffc$Cdostuwy}}~}yvutpfSoa8f#ffPff_ffdffjffmffpffqfftffvffzf|f}fzf~fyffxffrffnffkfflffiffeffaffTff!ffa:!ȚVenqtx{~|yxwvrneEoL"cff^ffcffhffmffrffvff{fzffxffwffxffvffsffsffrffpffoffoffoffnffkff[ff fgK{ tvz~~|zxyzyy{|}|x_ߙ< [PgRff~fwffuffwf~f|f{ffxffufftffsffsffqffrffsffsfftffuffvffyf~fzf~fzffuff=fgX\[әe|}zzyzzzyz}}{՘dJPgffaffmffqffrffqffqffrffqffqffrfftffvffwffxff{f|f~fyffsffqffoffjffifffJad:=Mjqsstvx{}~}ysoid@ZgffRffaffgffiffjffmffqfftffwffxffyffzf|f}f{ffwfftffoffkffjffhffbffTff>fe/2ɔԙJakptwy{~|xvstqldGè+dcffYffcffgfflffpffsffuffxff{f|f}f{ffxffvffsffrffoffmffnffnffjffbffSfffgoE߃Sskqty~~}{zxywvvvuoS+2_gmfuffoffpfftffyf~f{f|f}fzffxffvfftfftffrffpffpffrffsffsfftffufftffkff$fg?Tkz~}}{ywxy{|}uxUg*ffmffufftffsfftffufftffrffqffrffvffufftffuffxffzf|f~fyffwfftffqffwfgfgk^-Tpwyxuvxy{{|~~{wrmvD8Gg ffWffgfflffmfflffmffpffrffsfftffvffxffzf}f}fyffuffrffnfflffjffcffYffnfqdl)˘Ednpsty{}~|vtrojaK̙יL4'f7ffUffbffiffiffkffnffqfftffxf~f|f{f}fzffwffsffpffpffpffnffkffgffaffSfff4g<>֎]ekqwz}~|zzyxussqiII߸affeffffflffqffuffxff{f}f}fzffvffsffqffqffrffsffrffrffsffrffoffkff]fffgNi嘚zz{~|yxz}}}}~~zdؙN YtgDffyf{f}f|f}f|f|f}fzffvffrffqffrffsffqffqffqfftffuffwff{f}f}f{f}f{f~f{f{ffLfagZ«Eڙc{||{{{yxxz|{|~{usˠmMgff`ffnffpffoffpffoffoffoffpffrfftffwff{f|f~fyffyffzf~fyffrffkffeffbfff}b) YGfmquuvxz~~{wsndW%YS< gffRff`ffhffkffmffnffoffsffxf~fzffzf~fzf}f~fzffwffuffpffjfffffeff`ffRff,flf[6ÙNalqtvy~~|yxvurmcG𙨘&'d}ff\ffbffgffkffoffsffxff{f{ffxffvffvffuffsffpffpffpffqffoffkfffffVfffgH䶞1}ptw{~||{{{zxvwy{xtY/]-g`f{ffqffsffwffzf}f|f{ffxffvffuffsffrffsffrffrffqffqffqfftffxffxffqff2fgVw&yřn}}|{zzz{}~}(Rg!ffhffqffrffsffpffqffrffrffqffrffuffwffwffvffwff{fzffuffrffpffnffqfuff_/Rouvssvyxx{}}zwtnjoaxݶCg ffSffbffeffifflffnffrfftffuffvffyff{f|f}fzffwffvfftffqfflffhffaffWffUf8e-$G`iouvxz|~{yxupi^FݙX 0eJffUff`fffffkffpfftffvffxffwffzf}f}fxfftffrffpffoffoffofflffkffdffRff fxgA'wthiquwz|~{yxwwvwwukL1`f}flffkffoffrffwffzf}f|f{ffwffuffsffrffrffsffrffrffrffrfftffsffqffefffgQg@Ø|z~~|zz{z{{zz|məm8Wg9ffwf|f}f|f{ffwffuffsffrffpffpffpffrffsffuffxffwffwffzf|ffwffufftfffXf@g\ W4Ztwyyyyzzz{|~{vr^ ^Jg ffZffiffnffmffkffmffnffpffsffuffvffxffzf~f|f{f~fyfftffqffnffjffbff\fffc$Fdnrtvx{|~~~{ytpkdTqc8f$ffPff_ffgffkffkffoffqfftffwffzf|f}f{f~fzffwffuffrffoffnffifffff`ffQffff^:%ŚTenswy{}~}zxvusqmfGoK"cffcfffffifflffqfftffxf~f}fyffvffuffufftffqffqffqffoffoffqffpffkff\ff fgK}tv{}{z{{{zyy{~|u]; [PgTfffuffwffzf|f~fyffwfftffrffrfftfftffsffqffqffsffuffxffyf~f{f}f{f}fwff>fgXZ]ϙi{}}}}}||{z{{{|}|xx՘eLPgfffffpffqffqffqffqffpffpffpffqffsfftffwffzf}f}fyffvffufftffpffiffhfffJac;=Kjpruuwwz||yvupib@YgffPffaffhffkffnffoffrffsffsfftffxf~f{f{ffxffvfftffqffofflffgff_ffSff>fe/2ɔԙJ`iotxz{~~{{ywrpneGæ+d]ffSff_ffhffnffrfftffxf~f|f|f}fzffzffwffuffufftffqffnffmfflffjffeffVff fgpE߃Trkqt{~~~{xwvwxxvnP*4_gofsffoffsffvffyffzf}f{f}f~fxffuffsffqffpffnffnffpfftffwffwffvffvffnff'fg?Tl|}}|{||{zyxy{}~yvUg*ffnffwffxffwffvfftffrffqffrffrffqffrffuffvffvff{f|f~fyffwfftffqffwfifgq^!*Wsyyywuwxz|~~{vplwC7Gg ffWffgfflffnffnffoffpffqffsffuffvffxff{f{ffxffwffuffsffoffgffaffXffmfsdi)˘Gfnqsvxz|~|zxuqlcM˙ՙH4,f2ffPff^ffdffiffmffqfftffvffyf~f{f{ffwffsffqffqffqffrffrffoffkffbffQfff6g:>֍\forvz}}||zvtssqiJIaffdffgffmffqffsffxf~f|f{ffwffuffufftfftffrffrffpffoffoffqffqffnffbfffgNi瘘yz~~~{zxywvy{}~}hәQYugBffvf~f|f|f|f~fzffyffxffwfftffrffrffrffrffrffsffvffwffxffzf|f~fyffxf~ffMfagZFٙcy{|}{{yyxzz|}{wu̠nMgff`ffnffqffqffoffqffoffnffoffqfftffvffxffzf|f~fyffuffsffpfflffeffafffb' YIiqrtvxyz}|ywtneX'XS< gffPff_ffeffifflffnffqfftffvffyf~f{f|f~fyffuffrffpffpffnffmffiffaffQff+flf\6!Pdlquxy{~|zwtsrmcD󙥘$'d}ff[ffbffiffnffqffuffxff{f{f~fyffyffvffsffqffqffqffpffpffoffkfffffXff fgH䴞2}nsw|||{zyzzxwwxvZ/]*gbfyffrffuffxff{f|f~fyffwffufftffrffrffqffqffrffsfftffuffwffyffyffpff1fgV{!~r|zzzyyz{{}{}*Rg!ffhffsffufftffsffrffqffqffrffrffsffvffvffwffwffzf|f~fxfftffrffoffqfuff_*Mltuxyzyzyz|}{vnhjf~ݱCg ffTffdffiffkfflffoffsffuffvffuffvffyf~f|f{ffyffvffrffmffifffffaffWffUf8e-#Hdloruy|}~}zxvqj_FޙW 0eGffRff`ffiffnffqffsffuffwffxff{f{ffwffsffrffsffsffrffofflffiffcffQff fygA'ysgfmsy}}|{{zxwwwsiJ0`f|flffkffoffrffvffyf~f|fzffxffvfftffqffpffqffqffpffqffrffsffqffpffefffgQbD}|}|}{yy{z||~oǙn8Wg8fftffzf}f{ffxffvfftffsffrffqffqffpffrfftffvffxffzf}f|f|f}fyffxfftfffZf>g\ Z2\x{|yxxyywz{}~|ytr] \Jg ffZffiffmffnffnffnffoffrffrffrfftffwffyf~f|fzffwffvffsffmfffffbff^fffc$Eenruwyy{~zwtqmeTob8f$ffPff`ffgffkfflffmffqffuffxffzf~f{f}f}fzffuffrffqffofflffjffgff`ffPffff_:#ǚVemrux{~}z{yxuurogGoN" cff_fffffkffpffsffwffzf~f|f{f~fzffyffuffrffrffrffrffoffnffmffmffhff[ff fgKy tvz}~}|{zxyzzz{{v]9 [PgTfffwffyf|f~fyffxffwffwffuffsffrfftffuffuffrffqffrffwffyf}f{f}f|f|fyff@fgXX`͙i|~{z{||zz|~}}{|ԘeLPgffdffpffpffnfflffnffnffoffrffuffwffxffxffzf~fzf}f}fzfftffqffnffkffifffKab<Tmy~}|{zyx{|wzUg.ffpffwffvfftffrffrffsffrffrffpffrffsffuffvffyff{f|f}f{ffwfftffqffwfhfgo^+Tnuwxxxxzz{}~zuqmxB6!Gg ffXffgffkffmfflffmffmffpffrffuffwff{f}f}fzffyffwffsffoffkffiffeff\ffpfqdj)ʘFbkpsuwy{~}|zwupkbM˙יJ4)f5ffSff`fffffkffoffqffrfftffyf}f}fzffyffxffuffsffqffoffnfflffhffbffRfff6g:>֍\enqvz~zvvvuturjKJ߸affeffhfflffqffuffwffzf}f}fzffxffwfftffqffnffoffpffqffpffpffpffnffcfffgNiꘕwz}||{zyyxz{{|~|gәSYtgFff|fyf~f{f{ffxffwffwffwfftffrffqffrffsffrffsffuffxffxffyf~f}fzffxf}ffLfbgZëCݙa{~~}zzyyyzz{xvˠkMgff]ffjffnffpffpffqffoffpffqffrffsffuffyf~f|fzffxffuffrffnffkffeffcfff{b* ZHiquvvvxz{|}}{yuqle\*TW< gffOff^ffeffjffnffoffqfftffwffvffxff{f{ffwffsffqffoffmffjffeff`ffSff.fjf^6!Oakpsvy|~}||zwtqomeG('cffZffaffhfflffpffuffyf~fzf~f|f{f~fwffuffsffrffqffqffoffnffmffjfffffWff fgH䷞1|msy|~~{zzzzyyxz||tW+]+gafzffrfftffyf}f|f|f~fzf~fyffvffufftffrffpffoffpffrfftffvffxffxffxffrff3fgVy$|™q}|zzxz{||~z+Rg!ffhffpffsffqffrffsffsffrffrffqffqffrfftffyf~f|f|f}fzffyffuffpffkffnfuff_,Nntxxyyyxxz|}}{xtmhld|ݲCg ffTffffflfflfflffnffpffrfftffuffwffzf}f|f{f~fyffuffqffpffnffgff_ffTffSf:e-$Iclprsx}~{yxwsokbHܙZ 0eIffTff`fffffkfflffnffsffyf}f|f|f~fzffwffvfftffqffpffoffnffjffgffaffSff fwgA(wtghmu{~{yyywvurjK1`f|flffkffpfftffuffxff{fzffvfftffufftffsffqffqffpffqffqffqffqffqffifffgQdAØ|{}zyzz{zyz|}oǙm8Wg7ffsffxffxffxffvffsffrffrffrffsffuffvffvffuffuffwff{f{ffxffwffvfffYf?g\ W4Zuxyyzxxxyz|~}{vr \ ]Jg ff[ffjffnffoffnffnffoffoffqfftffuffxff{f|f~fzf~fxffuffsffpffjffcff\fffc$Efortxyyx{}}zxwqkbRpc8f%ffRff`ffgffjffmffoffqfftffvffyf~f|f{ffxffvfftffsffpffkffhfffff`ffPffff`:"ȚWemrwy{}}zxwwwtpfGmO" cff_ffefflffofftffuffwffyf|ffxffvffsffpffoffqffqffpffqffpffpffmff]ff fgK|svz}~{zy{zyxz|||y`ߙ; [NgUffftffwff{f|f~fyffxffvfftffpffpffqffqfftfftffuffuffvffzf}f|f|f|f~fuff=fgXZ]ϙi~}zxxyzyz|~}{|ӘeLPgffdffoffpffoffmffoffrffsffrffrfftffvffxffzf~f|f{f~fxffuffqffoffkffjfffHad:Tmz~{{z{z|zyz}~vvUg*ffnffwffuffuffuffuffsffrffpffqffrffsfftffvffwffyf~f|fzffuffrffoffvfhfgo^ )Trxxxwxz||{{}~zwtoyB7!Gg ffVffeffjffkffkffmffoffqffsffvffyffyffzf}f|f{ffxfftffpfflffgff_ffUffmfsdj)͘Ielquwxz}||~~{yupj`MʙיI4+f3ffQff_fffffkffnffoffsffxff{f|f}fzffyffzffxffsffqffofflffjffiffcffSfff5g;>֎[bjqw{}|{xwttttmLJaffbffeffkffpffuffyf~f|f{ffxffvfftffsfftffrffqffoffqffqffoffmffmffcfffgNg昙ww|}||{|yyxy{}|eՙQ YsgFffzf|f}f}fzf~fzffyffxffvffuffsffpffnffpffrfftfftffuffxff{f{f~fzffyf~ffPf^gZëEڙcz}|{{{zyz{|||{uu̠lMgff]ffkffoffqffqffpffoffqffsfftfftffvffwffyf~f{f|ffwffsffoffiffdffcfffzb- [Hfqttsuwz}~{xuqle[(VT< gffNff]ffefflffoffpffqffsffvff{f|f|f|f}f{f~fyfftffqffoffmffkffhffbffSff-flfZ6ęMblqw||{}}}}zwspkcF&'dzffWff`ffhffnffrffvffxf~f|f|f~fyffwffvfftffrffqffoffnffmffoffoffhffYff fgH䶞2|mrvz}zyxvvx{}{yrX.]+gaf{ffsffvffyffzf~f}f{ffxffxffufftffrffqffqffrffsfftfftfftffuffvffpff2fgVw%zÙp~||{{{zzz|~{(Rgffiffqffrffqffrffsffrffrffpffpffrffvffxffyffxff{f{ffwffsffoffkffofvff_/Qpvuuvwwxz{}}zuofif{ݵCg ffUffdffjffnffpffpffoffpffrffvffxffyff{f|f~fxffuffrffpfflffhffaffUffRf;e-"Genqsvxz{~{xuvtpkcHܙY 0eLffUffaffgffjfflffpfftffxff{f}f|f|f}fyffwffuffsffoffnfflffkffiffcffSff fxgA*uvfhouy{~}zxwvvwwslN6`f}fkffjffoffqffvffyf}f|f{f~fzffxfftffqffpffqffrffrffrffqffqffrffqffefffgQfA˜~|~{zz{z}}}}}~məm9Wg:fftffyffxffwffufftffsffsfftfftffrffrffsffvffxffyffyf~f}fzffuffufffYf?g\ X3\vzy{yxxxzz{|~}{uq] ]Jg ffZffkffoffoffoffnffmffnffpffrffuffwff{f|f~fzffwffuffqffnffhffbff]fffc$Edmptxyzz}~{wsokdTpb8f#ffPff^ffdffiffmffpffrffwffzf|f}f{f}f{f~fzffwffuffsffpffmffkffgff_ffPffffa:!ǚUcmqv{}}{xxwvsmcEnN"cff`ffeffkffpfftffwffyf~f{f|f~fyffxffvffsffqffpffoffoffoffnffkffjff]fffgKy tuz|~~}|yxwxy{{||x_ߙ< [PgRff~fwffuffwff|fzffvffuffuffvfftffsffpffpffpffrffuffwffzf~f|f|f|f}fxff?fgX[]љg}~{|{zzxx{~~{|ӘdKPgffaffmffqffqffrffrfftffrffpffqffsffvffwffxf~f|f{ffwffvffrffnffiffifffJac:=Lipuvvwxzzz|}yvrlfa@[gffRffdffkffnffoffoffqffsffuffuffvffzf|f~fyffwffuffrffnfflffgff_ffQff=fe.2ɓՙJcknrv{~~}|ywsojbFë+ddffXff`fffffkffoffrffvffzf}f|f|f}fzffvffuffufftffqffofflffkffjffdffTfffgoE߃Tqkou{}|ywvvvxxvoS,5_gnfrffoffsffwffyff{f}f|f{f~fzffwffsffrffoffpffrffsffsffsfftfftffuffmff&fg>Tn{~zxxxyxz{}wxUg+ffoffwffxffufftffsffrffpffqffrffrffsffuffvffwffzf|ffxfftffsffqffxfgfgm^*Urvwxyxyzzz}{wrluE7 Gg ffWffgffkffnffnffoffpffrffrffsffuffyf~f{f}f|fzffvffqffoffkffgffbffYffqfndn)ΘGcknqtvy}}z{yxsl`J͙֙K4)f6ffSff`ffeffhffmffrffvffxf~f{f}f|f}f{f|f~fyffvfftffqffpffmffjfffff`ffRfff5g<>֏]forvy|~~|zzywuttphHHafffffgffmffqffvffzf}f|f|f~fyffvffvffvfftfftffrffpffoffoffpffofflff`fffgNj瘙z{|zyyy{{z{|}{fԙSYugDffzfzffzf}f|f{ffxffuffsfftffsffsffqffqffqfftffwffxffzf}f|fyffwffxf|ffKfcgZHؙdz|||{{yxxzy{~{wvˠkMgff_ffkffoffqffqffpffnffoffoffpffuffzf}f|f|f|f{f~fyffwffuffofflffhffcfff}b* [Gemswxww|~~~ztrne[*UT< gffNff_ffeffiffnffpffqfftffvffwffwffyf}ffwffrffqffoffmffjfffff^ffPff+flf[6"Qemqsx|}}{zyxvrkaC󙥘$'d|ffZffbffhffnffsffwffzf~f{f}f|f|f~fxffvfftffrffpffqffqffoffnffjffdffWff fgH䷞0nquz}zwvvxzzyxtY.]+gafzffrffvffyf~f{f}f}fzffxffvfftffrffrffsffsfftffrffrffsffvffxffxffpff0fgVx%zÙq~~{yyz{{z|}'Rg"ffhffpfftfftffsffqffoffpffqffrffsfftffwffzf}f}fzffyffxffvffqffmffqftff_-Qovvstuwxz|~}}zxvpijf{ݴCg ffUffeffjffkfflffmffnffqffsffwffyf~f{f|f}fzffwfftffqffoffmffiffcffUffSf:e-#Fbmptw{{}~|yvspj`GݙY 0eJffUffcffifflffnffqffuffxffyf~f{f}f}f{ffwffuffsffqffpffmffkffgffbffTff fwgA)vvdemsx||yxwwvvtslL1`fzfofflffoffrffwffzf{ffyffxffxffuffsfftffsffsffrffqffqffsffrffoffefffgQg@˜~~~~{yyzzz||~mʙj:Wg7ffsffyffxffwffuffufftfftfftffsffrffqffqfftffwffwff{f{ffwffvffvfffYf>g\ Y2Ztz{{zywyyzz|~}xsq ] \JgffXffgffmffoffqffrffuffufftfftffuffvffwffyf}f}fzffwffrffmffhffbff]fffc$Ddnrtuvyz|}zvtqlbPnc8f$ffQff`ffgffkffnffpffrffuffxf~fzf~f{f|f}f{ffwffuffrffnffkffhffeff`ffQffffb:!ȚVekou{~}{yvvvsmcFoL"cff^ffcffjffpfftffwffyf~f|fzffxffwffvfftffrffpffoffnffpffnffmffiff]fffgKz twy|~|{|{yvvwy{|zaݙ> [RgRfffvffvffxff{f|f~fxfftfftffufftffqffpffqffqffsffuffwffxf~f|f{f~f{fxff?fgX[^Ιk~~|||zxwxy|~~yzӘfLPgffcffoffrffqffpffoffpffpffqffqffrffuffxf~f|f|f}fzffxffvffsffpffmffkfffJab<;Ihoqtvxyzyz~|xsrogb@VgffRffbffhffkfflffmffoffrffsffvffxffzf}f~fxffuffrffofflffifffff`ffTff>fe.2ɕҙMelrtwxz|~{xwtsnibHé+dbffWffbffiffmffpfftffvffwff{f|f}fzffxffuffsffqffoffoffnffmffjffcffTfffgoE߄Sslsw{}}{ywwxwxxxqQ)4_gnftffpfftffuffuffxf~f|f{ffxffuffsffqffqffsffsffqffqffqffsffuffvffkff$fg>Tlz~~}|{{zy{|}~uxUg+ffmffufftfftffsffrffqffpffrffrffqfftffwffyffyf~f{f|f~fxffvffsffqffxfffgm^+Vswxxzxxxzyz}~{wrlwD9GgffVffeffiffmffqffrffqffqffrffsffvffyf~f|f|f~fyffwffuffpfflffiffcffZffofpdl)ʘDakquuwz|~|zwurmbL͙ԙH4+f4ffQff_ffhffmffpffqffuffwffyffyf~f|f{f}fzffxfftffqffnffmffifffff_ffOfff7g;>֐`gmswz|~}zyzyxwtofEEaffgffiffnffsffwffyf~f|f|f}fzffxffvfftffsffrffpffnffpffqffrffpffmffcfffgNi昘xw{}zzywvxz}|fԙQYsgFffzf|f}f{f}f|f|f~fyffwfftffrffpffqffrffsfftffvffvffuffwff{f{ffzffzfzffKfcgZ«Dۙbx{{|{{yyz{{z}{yx͠lMgff_ffkffmffnffpffqffrffqffqffrffuffxffzffzf~f{f}f~fxfftffnffjfffffcfffb' WGhqtxzyyz{{~|zvrkbW%YS< gffPffaffjfflffnffpffqffsffvffwffyf~f|fzffwffuffrffoffmffkfffffaffPff+flf\6!™Nclrvxz{~~{zzywtqmdF񙧘%'d|ffZffcffjffoffqffsffuffzf}f~fxffwffuffuffrffqffsffqffnffmffkffgffVfffgH䶞1ptx|}|zyzzxwwyyvZ/]-gafzffpffsffvff{f|f~fxffwffvffuffsffrffrffsffrffrffsffuffvffwffwffpff1fgVy#|r~|zzzyyz{}~~(Rg!ffhffqffsfftffsffpffqffsfftffrffrffsffuffvffxff{fzffwfftffpffkffnfvff_+Pnswxwx{|yy{|yvrklf}ݱCgffSffdffiffmffpffpffpffpffqffuffxffzf~f|fzffvffsffqffofflffiffaffUffTf:e-#Fcnqtwyz|}yvspjaHݙX 0eKffTff_fffffkffoffpfftffvffyf~f{f{ffyffuffrffqffpffnffmffkffgffaffQff fvgA%zshhotw{}{zzzyyxvtqkL1`f{fmffjffoffsffvffxf~f}fxffsffrffrfftffsffsffqffrffqffsffsffsffrffgfffgQg@~}~}zyyyxyz}pƙo7Wg8fftffzf~fyffwffvffufftffsffrffpffoffpffsffvffyffzf}f}f{ffwffvffufffZf>g\ W4[uyz|zxwy{{z{}~ywus_`Jg ffZffhfflffmffnffnffoffqfftffsfftffvffyf~f|fzffwffuffrffoffjffdff\fffc$Ffpstvwy{|}xtnjbQnb8f%ffSffbffhffkffmffpffrfftffvffyf~f{f{f~fzffvffuffrffqffmffjfffff`ffQffff_:#ǚVbkswy|~}{{|zvsqldFoL"cffaffhffmffpffqffrffvffzf|ffwffvfftffsffrffrffpffpffpffqffnffhffXff fgK{ uw|~~{zzyz{{{{||w]: [RgRfffvffwff{f|f}fzffyffwfftffrffrffsffsffsffrfftfftffvffyf~f{f|f|ffuff֏^fosvy||z{ztqqphIIaffeffhffnffqffuffxff{f}f|f{ffxfftffrffrffrffrffpffpffpffpffoffnffcfffgNj蘘xy|}|{yzzz{z{~~fՙP YqgGffzf{f}f}f{ffxffvfftffuffufftffsffqffqfftfftffuffwffyf~f|f{f~fyffyf|ffKfcgZFڙby}}{zzyz{|{y{~|wt̠nMgff_fflffoffoffoffoffqffqffpffpffsffwffyffzf}f}fzffuffrffoffkffeffbfff{b+ ZGepuxwvyyy{|ywtmdZ'XR<gffOff^ffdffkffnffqffsffuffwffxf~f{f|f}fzffwfftffrffoffnffjffgffaffRff.fjf^6"Qckorux|~|{ywutqlbE𙨘&'d|ffZffbffiffnffrfftffwffzf|f~fyffwffuffuffsffpffoffoffoffnffnffjffYfffgH䴞2|nrw{~{z{zzyxxy{{uY-]*gbfyffqfftffwffzf|f~fxffvfftffufftffsffqffsfftfftfftfftfftffuffvffpff3fgVw%{™q}{zzz{z{z|~|(Rg"ffjffsffrffsfftffsffrffqffpffpffpffsfftffwff{f|f~fyffwfftffpfflffpfuff_+Mmvwxwxxz{||~|wspkob{ݴCg ffRffaffhffkfflffoffsffsffrfftffxf~f{f}f}fzffxfftffrffqffnffgff`ffUffUf8e-$Eakqtxz|{yusqjaIڙZ 0eHffSff_ffeffjffnffrffwffzffzf}f|f{ffyffxffuffsffpffmfflffifffffbffUfffugA'xufgosw{~}||{xvvutslK2`fzfmffkffofftffxffzffzf~f|f{ffwffuffsffqffqffpffoffpffpffsfftffsffefffgQeB}{}|||{yy{}|~~mək:Wg9fftffyf~fzf~fyffvffrffpffpffoffpffqffsffvffxffxffyf~f|f{ffxffuffsff~fZf?g\ V4Ztz{zz{zzyz{{}|xtr_aJgffZffhfflffmfflfflffmffoffpffsffvffzf}f|f|f}fzffyffuffqfflffiffdff^fffc$Gelqtuwx{|~|yxvqkbRpc8f$ffPff_ffeffhffjffoffsffxff{f|f}f{f~fzffyffwffuffrffpffmffkffgff`ffQffffb: ɚVckpuy|~~|zxuqomdFoL"cff`ffdffkffoffrfftffxff|fyffwffuffufftffrffoffoffnffnffoffpffmff^fffgK{tuy}~|}{yxyxz{}|y^: [PgTfffvffxffzf|f~fyffvffufftffsfftfftffsffrfftffvffuffvffwffxffzffvff>fgX[]ϙj~|}~|{{zxy{{~|xzӘeLPgffeffqffrffqffrffqffoffoffqffqffuffwffzffzf~f{f|f}fzffxfftffqfflffifffMa_?8Ikrttvxyz{|}~zvrnfb@WgffRffbffhffkfflffmffrfftfftffsffvff|f{ffwffvfftffqffnffkffgff_ffRff=fe.2ɔՙJ`kptwx{~}{zywspldIè+daffWffaffhfflffpffrffvffxf~f{f|f}fzffxfftffrffqffoffnfflfflffjffeffVff fgpE߃Uqkrwz}~~|zyyzyvurmQ,3_gofsffpffsffuffxf~fzf}f}fzffwffuffuffrffqffqffpffqffsfftffuffvfftffjff#fg=Tmx|{{z|{zzz|twUg+ffoffwffwffuffrffrffrffrffqffrffrfftffuffvffyffzf|f~fzffvffrffqffxfefgl^*Tpvxxxxxxxz|~|xtplvD7 Gg ffYffhfflffmffoffoffmffnffrffvffyf}f{f~f{f~f{f|ffwffsffpfflffhffcffXffnfqdk)͘Fdlpsuxy|~{xtpk`JΙԙI4*f5ffTffbffifflffoffqffrffuffxffzf|f}fzffxffwffuffrffpffnffkfffff_ffOfff6g;>֎\dmsxz}|zxxyyvtqfEFaffgffgffkffqffuffyf~f{f{f~fzffxffuffrffrffrffsffsffqffqffqffpffmff`fffgNk蘗wy~}}||{yxwz~ze֙PYugDffxf|f}f|f|f}fzf~fzffxffvfftffqffqffrffsffsffuffwffxffxffzf}f|f{ffzf{ffKfcgZEۙax|{|zzyyxyz}~|xw̠kMgff^ffmffpffqffpffpffpffqffqffrfftffvffxffzf~f}fzffwffrffoffmffgffcfff{b+ ZGeotuvvwwy|}|xuqldY&XR< gffTffdffgffhfflffpffsffuffwffyf~f{f|f}f{f}f{ffxfftffpfflffiffdff_ffRff-fjf]6 Nbkptx|~~|xvuurmcE򙦘&'d~ff[ff`ffffflffrffvffyf~f{f}f}f{ffxffvffvffsffqffoffmfflffkffkffgffYff fgH䷞1~nrvz~}~|zzyxvvwyzvX,].g]fffufftffwff{f|f}f{ffxffufftffsfftfftffsffpffpffrffwffzf~fzffwffoff/fgV{"|Ùq~||{yyy{{~&Rg!ffiffrfftfftffsffrffsfftffsffpffoffqffuffvffzf~f}fyffwffuffrfflffnfvff_+Nmtwxwxyyyz}}zxungld{ݴCg ffTffdffhffkffmffoffqffrffuffwffxffxff|f{ffwfftffrffpfflffgff_ffUffUf8e-$Hbjnsw{|}{zwtojbJٙ\ 0eIffTff`ffdffhffmffrffvffyffzf~f|f{ffwffuffufftffqffnfflffjffhffdffSff fxgA&yrhioru{}}|wuvwvusmN3`f~fiffiffoffuffxf~f{f~f|f{f~fyffufftfftffqffpffqffpffqffrffsffsffrffhfffgQf@˜~}~~|{ywxxxzj̙i;Wg7ffrffyffyffxffwfftffrffqfftffuffuffrffrffsfftffwff}fzffyffwffuff}fZf?g\ W3Ysy{}zxxvvy{~}zwut_ _Jg ffZffhfflffmffpffrffqffpffpffsffwffxffwffyf}f}fxffuffqffnffkffeff\fffc$Ddnuxvuwz~}yvuskaQpd8f&ffTffbffgffiffjffnffrffuffwffzf~f|f|f~fyffwffuffrffnfflffkffiffaffQffff_:$ĚScmquy}~~{zywuutoeFoL" cff_fffffjffmffqffwffzf}f|f|f~fyffxffuffrffoffpffoffnffmffnffmfflff^fffgKy svy}~}|yyz|zyy{||w_; [NgVfffuffxf}f}fzffwffwffufftffsffrffqffsffsffuffuffuffwffyf~f{f|f|f}fvff=fgX[\љg}~~}}{{|zyz|~~{~ӘdJPgffcffmffoffpffqffrffrffsffsffsffsffsfftffvff{f{ffwfftffpfflffiffjfffHac;:Iirstvxxyz|}{xumfc@YgffTffcffgffkffmffoffrffuffvffvffxffyf~f|fzffwfftffsffpfflfffff^ffNff9fe,2ɔәKdmqtxyz}{wtrpldHê+daffTffaffhffkffnffsffuffxff{f|f~fxffvffuffqffoffnffoffnfflffjffeffUff fgpE߄Sslpuz~}zzzyyxwuuoQ)5_gnftffpffsffvffyf~f{f{ffyffxffvffuffsffrffsffsffqffqffrfftfftfftffkff&fg?Tly~|zzzzyy{uwUg*ffoffxffyffvffvfftffsffrffpffpffrfftfftffuffwffyf~f|fzffuffrffqffxfhfgn^!)Tqxyyyyyyyz{{|}ytokvD6"Gg ffXffgffkfflfflffmffoffsffuffvffvffyf~f{f|f}f{ffxffsffoffkffiffcffXffmfrdk)˘Ecnqruwz{}~xttrlcMʙיK4)f5ffSffafffffjffmffpffrffsffvffzf}f}fyffwffsffqffoffmfflffkffiffbffQfff5g;>֎]eotvz}~}}|zxvtsphHHaffgfffffkffqffwffyf~f{f|f~fyffwffuffsffsffrffrffqffoffqffpffoffmffbfffgNj蘙xx|}|||yxy{}}}}}zeԙRYtgFff}fxffyf}f}fzffwfftffrffqffrffrffsfftffsffrfftffxff{f|f|f|f}fzffyf}ffLfbgZDۙbz}}}{zyyyxy|{xvΠoMgff^fflffoffmffnffnffoffoffqffrfftffvffyf}f}fzffwfftffrffoffkffgffefffzb+ ZHgorsuwy{}~|xspmfZ)VT< gffPff`ffeffjffnffpffpffrffvffxffzf}f}fzffwffvfftffqfflffhffdff_ffQff,flf[6 Qdlqsvz}|wuuurmdF񙧘%'d}ff[ffcffjffnffrffuffwffyf~f{f|f}fyffuffrffqffpffpffoffpffoffmffgffYff fgH䳞2~prw}~{xwwxyyzzzuZ.])gdfyffqffuffyf~f{f}f}fzffwfftffsffrffsffrffrffsffuffuffvffxffxffwffnff/fgVy$|r~}~ywy{{{|}}~'Rgffhfftffuffuffuffsffrffpffqffsfftffvffwffvffuffyf}f~fwfftffoffmffpfuff_,Nmtvuuuwy{}|yvrmne~ݰCgffSffdffkffkffmffnffqfftfftffuffxff{f|f~fyffxffvfftffpffmffgff`ffVffWf7e-"D`kruxz{}~zurnh`IۙZ 0eHffTffbffgffkffnffsffvffwffxffzf|f~fyffvfftffqffnffnffmffkffiffcffRff fxgA(wufhouy}}{zxxxxwvtmN5`f~fiffiffnffsffvffwffzf}f}fzffuffsffqffpffpffoffoffoffpffrffsffrffhfffgQeA˜~~}|}}|yyxz|məl9Wg8ffsffxffyffyffvffsffqffrffrffsffrffqfftffwffyffzf~f|f|f~fzffyffxfff[f=g\ X5\tuwwzz{zyz}~~|yvu`^Jg ffXfffffkffmffpffpffpffqfftffuffvffwffzf~f{f|f}f{ffvffrffoffjffdff\fffc$Eenpswz{|~~{ytqkbPla8f$ffRffaffgfflffoffoffoffrffvffyf~f~fyffvffuffsffpffpffoffkffeff_ffPffffa:!ɚWcksvxz~}zwvtrqofGpK"cffaffffflffpfftffwffyffzf}f|f|f}fzffvffsffrffpffoffoffnffmffmffjff\ff fgK{ ux}}|zyyxzz{{|z_9  [NgUfffuffyf}f~fyffzf~fzffxfftffrffqffqffqffqffrffsffuffxffzf~f|f|f{ffuff>fgX[_͙k~~|{xz{{yz|~}{|ӘeKPgffbffnffpffrffqffrfftffsfftffsffsfftffvffxffzf|f~fzffuffqffnfflffjfffKab<:Hfpuwwxyyz~~zunea@Zg ffNff`ffhfflffnffpffpffqffuffwff{f}f}f{f}fzffwfftffrffnffhffdff_ffSff@fe02ɔԙJblrtwy||~~|{xuqplbFè+dbffWffbffgffmffrffuffvffwffyf}f~fxffuffufftffrffpffpffmffkffiffeffVff fgpE߄Trkqtx}}|zyxyxvwvpR(5_gpfrffoffuffvffwffxff}fyffuffsffrffqffqffrffrffsffrffsffuffvfftffjff%fg>Tly~|zwxxz|}vyUg,ffnffwffxffvfftfftfftffsffpffqffrffsfftffuffvffzf}f|f{f~fxfftffqffxfgfgp^"'Rpvwwyz{{zz{}~zvroyB8GgffVffeffjfflffmffoffrfftffsffsffuffyf}f}f{ffzffxfftffpffmffhffcffZffqfpdk)˘Dbjprux{}~}zxwtpleOəؙI4*f5ffSff`fffffhfflffoffrffwffyf~f{f}f}fzffyffvffsffpffmffkffkffgff`ffOfff6g;>֐_gouwy|}zyvvuuvqhHI߸affhffjffmffpffsffwffzf~f|f{ffxffwfftffqffpffpffpffoffpffqffqffnffdfffgNkꘕvy|~|y{zzxzz{}zeՙQYvgCffyfzffyffzf|f~fyffvfftffqffqffpffrfftffvffvffvffvffyf~f{f{f~f{f}f{f|ffKfcgZGٙdz}||zyxwwy||}~~|yʠjMgff^ffkffnffmffoffpffqffqffsffsfftffvffyf~f{f|f|f{f}fzffvffpffjffeff`fff~b) ZFepuuuux{|}~{xurng[(VT< gffRffbfffffhffkffoffrffsffuffxff|f{f}fzffxffuffrffpffoffjfffff_ffQff-fkf]6!Oajouwz|~}{yxtromeI홫('d~ffZffaffffflffpffuffxffzf~f|f{f~fyffufftffrffpffoffnffnffnfflfffffWff fgH䵞1}pux{}}{yyxyyyzxxsX/]-gaf{ffsffuffvffyf~f|f{f~fyffvfftffsffrffrffrffrffsfftffsfftffvffxffpff0fgVz"|™p~}}}|{|}{{{{~|*Rgffhffrffsffrffpffpffrffsffqffqfftffvffwffwffzf}f|fzffxffuffqfflffofuff_,Ljswvx{{{|}|}zxvpinbzݳCgffRffbffiffkffkffnffpffsfftffwff{f}f{f~f{f|f~fwfftffpffnffkffiffcffWffWf7e-#Fclnqty|~}}{xurndHݙW 0eHffQff]ffdffkffpffsfftffuffyff|fzffvffsffqffqffqffqffofflffiffdffSff fygA)wthjpsuz}~|{{{yvuutrlM3`f{fmffjffnffsffvffzf|f~fyffxffwffwffwffwffvffvffvffuffuffufftffpffbfffgQr2Ԙeaabgmt}veQ=ՙ'3ʘI_vUelektroid-3.2.3/test/res/connectors/square-wav44.1k16b2c.wav000066400000000000000000005306741500236517400235020ustar00rootroot00000000000000RIFFWAVEfmt DJUNK4smpl<Xqdata~~VVhh e egglele|g|geeegegeeOgOgee7g7gee g geeggeeffffff,f,fffAfAfffUfUffffffffftftf}f}fffsfsfffififffcfcfff^f^fff[f[fffZfZfff]f]fffififofof,g,g\\ dd))UUsszzzz||~~~~}}||}}~~}}zzvvss___J_Jgg f fffZfZfffhfhfffofofffpfpfffnfnfffnfnfffofofffpfpfffrfrfffrfrffftftfffwfwfff{f{f}f}f|f|f|f|f}f}fzfzfffvfvfffqfqfffnfnfffififffcfcfff[f[fffffcc$$FFhhoorrssvvwwzz{{}}}}{{yyuuoohhbbQQooc8c8ff$f$fffQfQfffafafffgfgfffjfjffflflfffofofffsfsfffwfwfffyfyfffyfyfff|f|f{f{fffwfwfffvfvfffufuffftftfffpfpfffnfnfffkfkfffgfgfff`f`fffRfRfffffff_:_:$$ƚƚSSbbkkrrvvyy}}{{vvuuttssrrnnddFFqqKK""ccffffafaffffffffflflfffofofffrfrfffufufffyfyf~f~f|f|f|f|f}f}fzfzfffwfwffftftffftftfffsfsfffrfrfffofofffpfpfffpfpfffofofffnfnfffgfgfffYfYfff f fggKKxx qqrrxx}}}}{{{{{{yywwvvwwyyzz{{zzyybbݙݙ==  [[PgPgSfSfffffwfwfffyfyf~f~f|f|f|f|f~f~fxfxfffxfxfffwfwfffufuffftftffftftfffufuffftftfffsfsfffsfsfffsfsffftftfffufufffvfvfffxfxfff{f{f}f}fxfxfffAfAfggXX[[]]ϙϙii~~||yyyyzz{{zz{{||}}}}~~||zz֘֘ccKPKPggffffafafffnfnfffrfrfffqfqfffpfpfffofofffpfpfffrfrfffsfsffftftfffufufffwfwfffyfyfffxfxfff{f{f|f|f}f}fzfzfffwfwfffqfqffflflfffhfhfffififffffJaJaaa<<;;LLllrrttuuwwwwwwxxyy||{{yyuurrnnggbb@@XgXgffffSfSfffcfcfffhfhfffkfkfffpfpfffqfqfffpfpfffrfrffftftfffvfvfffwfwfffyfyfff{f{f|f|f~f~fyfyffftftfffofoffflflfffjfjfffffffff_f_fffRfRfff>f>fee/2/2ɦɓՙՙII__iirruuvvzz~~||{{yywwuuqqmmccHHìé++dd`f`fffWfWfffcfcfffififffmfmfffofofffqfqffftftfffwfwfff{f{f|f|f}f}fzfzfffyfyfffwfwfffvfvfffrfrfffofoffflflfffjfjfffififffgfgfffcfcfffVfVfff f fggoEoE߃SSssllqqvvyy}}~~||{{zzzzxxwwyyzzyyvvmmPP**3_3_ggnfnfsfsfffofofffrfrfffufufffxfxfffzfzf}f}f|f|f{f{fffwfwffftftfffrfrfffrfrfffrfrfffqfqfffqfqfffqfqfffqfqfffsfsffftftfffvfvffftftfffjfjfff$f$fgg?T?Tkkxx}}||{{{{{{||||||||||}}~~ttvUvUgg(f(fffmfmfffvfvfffwfwfffvfvffftftfffrfrfffsfsfffqfqfffqfqfffrfrffftftffftftfffufuffftftfffvfvfffxfxf~f~f|f|fyfyfffufufffqfqfffnfnfffwfwfgfgfggl^l^ ((SSrryyzzyyxxwwyyzzyyxxyy~~||xxvvttppwwCC77 G Ggg f fffUfUfffdfdfffjfjfffnfnfffpfpfffpfpfffpfpfffqfqfffrfrfffrfrfffsfsfffvfvfffzfzf}f}f~f~fyfyfffwfwffftftfffofofffjfjfffefefff^f^fffVfVfffnfnfqdqdl)l)ΘΘIIeennrrttuuwwxxyy{{~~}}{{zzwwssnnjjccNNʙʙיי˶K4K4(f(f6f6fffSfSfff_f_fffefeffflflfffofofffrfrfffsfsfffufufffvfvfffzfzf~f~f|f|f{f{fffxfxfffufufffsfsfffqfqfffofofffkfkfffhfhfffffffffafafffQfQfffff5g5g<><>֔֐]]eennuuxxyy||~~||{{yyvvwwvvuunneeFFHHaaffffefefffgfgfffmfmffftftfffxfxfff{f{f}f}f|f|f{f{fffyfyfffufufffvfvfffvfvfffvfvffftftfffrfrfffqfqfffpfpfffqfqfffqfqfffqfqfffmfmfff`f`fffffggNNjj蘙yyww{{~~||||{{yyxxxxyyzz{{}}}}ggՙՙPP  YYugugCfCfffxfxf|f|f}f}f{f{f|f|f}f}f{f{f~f~fyfyfffvfvffftftfffsfsfffsfsfffsfsfffrfrfffsfsffftftfffufufffvfvfffvfvfffwfwfffzfzf|f|fffxfxfffxfxf}f}fffJfJfegegZZGGٙٙbbzz||||||||zzxxvvxxzzzzzz}}~~{{wwwwˠˠlMlMggffff]f]fffkfkfffpfpfffqfqfffpfpfffofofffpfpfffqfqfffqfqfffsfsfffufufffvfvfffxfxfffyfyf}f}f|f|fzfzfffvfvfffrfrfffpfpffflflfffffffffbfbfffff|b|b) ) XXFFggppssttvvyyzzyy||}}}}}}{{xxttooffZZ&&WWT<>֔֐^^ffmmrrvvyy}}{{zz{{||zzvvttppnnhhJJGGaaffffgfgfffhfhfffkfkfffpfpfffufufffyfyf~f~f{f{f|f|f~f~fxfxfffvfvfffufufffsfsfffsfsfffrfrfffrfrfffqfqfffqfqfffqfqfffofofffofoffflflfffafafffffggNNjj昙{{zz}}~~{{yyxxzz{{{{||||}}~~||ffՙՙPP  YYrgrgGfGfff}f}fxfxfffzfzf|f|f~f~fyfyfffxfxfffwfwfffsfsfffqfqfffqfqfffrfrffftftfffsfsfffrfrfffsfsffftftfffufufffyfyf~f~f|f|f{f{f~f~fyfyfffyfyf|f|fffLfLfbgbgZZëëCCܙܙ``zz~~}}zzyyzz{{{{||||||{{||||yyxx͠͠mMmMgg f fff]f]fffkfkfffnfnfffnfnffflflfffmfmfffrfrfffsfsffftftffftftffftftfffufufffwfwfffyfyf}f}f}f}fzfzfffufufffsfsfffnfnffflflfffffffffafafffff}b}b+ + \\KKhhppssuuvvwwwwxxyy{{~~}}{{yyuuppkkdd[[((VVT:>֖֎^^ddmmttwwzz||~~}}zzzz{{xxvvvvssppiiJJIIaaffffdfdfffgfgfffmfmfffqfqfffsfsfffxfxfff{f{f{f{f}f}f{f{fffxfxfffufufffqfqfffpfpfffpfpfffpfpfffofofffofofffrfrfffsfsfffrfrfffofofffbfbfffffggNNjj蘗xxxx||||zzyyzz{{zz{{{{{{||||zzeeՙՙPPYYwgwgBfBfffxfxf}f}f}f}f{f{f~f~f{f{f}f}f|f|fzfzfffwfwffftftfffrfrfffpfpfffpfpfffqfqfffsfsfffsfsfffsfsffftftfffufufffyfyf~f~f|f|fzfzfffxfxfffwfwfffffNfNfbgbgZZEEܙܙaazz}}||{{{{yyyy{{zz||}}~~~~{{wwwwʠʠiMiMgg f fff_f_fffmfmfffofofffnfnfffnfnfffofofffqfqfffrfrfffrfrfffsfsfffvfvfffxfxfff{f{f}f}f|f|f|f|f}f}f{f{f~f~fzfzfffwfwfffufufffofofffgfgfff`f`fffffbb' ' XXGGhhppssuuuuuuvvzz}}}}{{xxssmmccVV%%YYSg>g\\ VV55\\ww{{zzyyxxxxxxyyzz{{||}}||~~{{wwttrr^^ ]J]JggffffYfYfffhfhffflflfffmfmfffofofffofofffqfqfffrfrffftftfffufufffvfvfffxfxfff{f{f|f|f}f}f{f{f~f~fyfyfffufufffrfrfffofoffflflfffffffff^f^fffffcc$$GGeellrruuuuvvyyzz||~~}}||wwttppllccSSppc8c8ff&f&fffQfQfff`f`fffffffffkfkfffmfmfffofofffrfrfffufufffxfxf~f~fzfzf}f}f|f|f{f{f~f~fyfyfffwfwfffufufffrfrfffpfpfffnfnfffkfkfffgfgfff`f`fffRfRfff f fffa:a:""ƚƚSSbbkkqquuwwzz~~zzyyyywwttssssppiiIIooNN"" c cffff^f^fffcfcfffjfjfffpfpffftftfffwfwfffzfzf|f|f}f}f{f{f~f~fzfzfffyfyfffwfwffftftfffqfqfffpfpfffofofffnfnfffnfnfffnfnfffmfmfffhfhfff]f]fffffggKK|| ttww{{}}{{zzwwwwyyzzyy{{{{||yy``ߙߙ<<  [[PgPgTfTfffffxfxfffxfxfffyfyf}f}f}f}fzfzfffvfvfffvfvfffufufffsfsfffsfsfffrfrfffpfpfffrfrffftftfffvfvfffvfvfffwfwfffxfxfff{f{f|f|f}f}f|f|fwfwfff=f=fggXXYY]]ЙЙhh}}~~~~}}||zzyyyy{{{{{{zz}}||{{yy՘՘ccMPMPggffffefefffofofffqfqfffqfqfffqfqfffrfrfffqfqfffqfqfffqfqfffrfrfffufufffwfwfffxfxfffwfwfffxfxfff{f{fzfzfffufufffqfqfffofofffjfjfffififffffLaLa``==99JJjjrruuwwwwwwyyyyyy||~~zzvvssoohhcc@@[g[g f fffPfPfffbfbfffhfhffflflfffnfnfffqfqfffrfrfffsfsfffvfvfffwfwfffxfxfffzfzf}f}f}f}fzfzfffwfwfffsfsfffqfqfffmfmfffjfjfffgfgfffbfbfffVfVfffAfAfee0202ɥɔԙԙIIaaiillqqvvyy||||wwttttttookkaaEEëê++ddbfbfffWfWfffafafffhfhfffofofffsfsfffufufffufufffvfvfffwfwfff{f{fzfzfffvfvfffrfrfffrfrfffqfqfffqfqfffpfpfffnfnfffkfkfffhfhfffdfdfffUfUfff f fggpEpE߃UUppiippww||}}{{zzzzyyyyyyyyxxxxwwqqSS++4_4_ggpfpfqfqfffnfnfffrfrfffufufffxfxfff{f{f}f}f|f|f|f|fffwfwffftftfffsfsfffrfrfffpfpfffpfpfffrfrfffrfrffftftffftftfffufufffvfvfffufuffflflfff&f&fgg?T?Tmm}}~~||zzyyzzzzxxxxzz}}~~wwxUxUgg,f,fffnfnfffvfvfffvfvfffufufffufufffsfsfffsfsfffrfrfffqfqfffqfqfffqfqfffsfsfffvfvfffwfwfffxfxf~f~f|f|f|f|f}f}f{f{fffwfwfffrfrfffofofffvfvfhfhfggm^m^++TTqquuwwyyzzzzzzzzzzyy{{||}}zzxxssmmvvDD77!G!Ggg f fffVfVfffdfdfffififfflflfffofofffpfpfffpfpfffqfqfffsfsffftftfffxfxf~f~f{f{f|f|f}f}f{f{f|f|f|f|f~f~fxfxfffufufffofoffflflfffhfhfffbfbfffYfYfffofofododm)m)͘͘HHddkknnqqttwwzz{{~~}}yywwuuppllbbKKΙΙәә˸I4I4*f*f5f5fffRfRfff^f^fffdfdffflflfffqfqfffsfsfffrfrfffufufffyfyf|f|f~f~fzfzf~f~fyfyfffxfxffftftfffsfsfffrfrfffqfqfffofofffmfmfffhfhfffafafffPfPfffff7g7g:>:>֖֍^^ffnnssvvyy}}||yyyyxxxxttssooggHHHHaaffffefefffffffffjfjfffqfqfffvfvfffxfxf~f~f|f|f{f{f~f~fzfzfffyfyffftftfffrfrfffqfqfffqfqfffqfqfffsfsffftftffftftfffqfqfffofofffkfkfff_f_fffffggNNjj昙xxyy}}||zzxxwwwwxx{{||||}}~~||ggԙԙQQYYvgvgDfDfffzfzfzfzfffyfyf~f~f{f{f|f|f~f~fxfxfffufuffftftfffsfsfffrfrfffqfqfffpfpfffqfqfffsfsfffvfvfffxfxfffxfxfffzfzfffzfzf}f}f|f|f{f{f}f}f{f{f{f{fffLfLfagagZZëëCCܙܙ``ww||}}~~{{zzyyzzzzzzzz{{}}~~zzuuuu̠̠nMnMggffff]f]ffflflfffpfpfffpfpfffofofffofofffpfpfffpfpfffqfqfffrfrfffufufffxfxfffyfyfffzfzf}f}f|f|f{f{fffxfxfffufufffpfpfffkfkfffefefffbfbfffff}b}b* * YYHHhhqquuuuvvwwxxyyzz}}~~{{yyvvssmmeeWW%%YYRf>fggXXYY__ΙΙii}}}}{{||||||zzzz{{||||||~~zz{{՘՘ccJPJPggffffdfdfffqfqfffsfsfffrfrfffpfpfffpfpfffpfpfffpfpfffpfpfffrfrffftftffftftfffwfwfffwfwfff{f{f|f|f~f~fyfyfffufufffqfqfffmfmfffhfhfffhfhfffffKaKaaa==::KKllrruuvvvvvvxxyy}}}}~~~~{{yyuuqqmmhhee@@XgXgffffPfPfffafafffgfgfffkfkfffmfmfffofofffofofffrfrfffufufffyfyf~f~fzfzf~f~f{f{f{f{f}f}fzfzfffufufffsfsfffqfqfffnfnfffjfjfffgfgfffafafffTfTfff@f@fee2222ɢɗҙҙKK__hhoottvvxxzz||zzyywwssoojjccGGíè++dd`f`fffUfUfff`f`fffhfhfffnfnfffrfrfffufufffvfvfffyfyf~f~f|f|fzfzfffyfyfffvfvfffvfvffftftfffrfrfffpfpfffqfqfffofoffflflfffjfjfffffffffUfUfffffgglElE߂UUqqllqqww{{}}||zzzz{{||yywwvvvvuunnPP((7_7_ggqfqfqfqfffpfpfffufufffyfyf~f~f|f|f{f{f~f~fyfyfffyfyfffyfyfffyfyfffxfxfffufufffqfqfffofofffofofffofofffqfqffftftfffufufffvfvfffwfwfffnfnfff%f%fgg>T>Tnnzz}}{{yyxxxxzz||}}||~~uuyUyUgg+f+ffflflffftftfffvfvfffufufffufufffsfsfffrfrfffrfrfffrfrfffsfsfffrfrffftftfffufufffwfwfffzfzf~f~f{f{f}f}f|f|fzfzfffvfvfffrfrfffqfqfff{f{fdfdfggj^j^,,TToouuwwttuuwwxxwwyy||~~}}zzwwttnnwwCC77!G!Ggg f fffWfWfffffffffififffjfjfffnfnfffpfpfffqfqfffofofffqfqffftftfffxfxfffzfzf}f}f|f|f|f|f}f}fzfzfffvfvfffrfrfffofofffmfmfffififffcfcfff[f[fffpfpfqdqdj)j)ɘɘEEddmmrrttxxyyyyzz{{~~zzxxuuttooiiaaLL̙̙֙֙˷I4I4*f*f5f5fffTfTfffcfcfffififfflflffflflfffofofffsfsfffwfwfffyfyf~f~f{f{f|f|f~f~fzfzfffyfyfffyfyfffufufffrfrfffnfnffflflfffjfjfffffffff`f`fffQfQfffff5g5g<><>֖֎^^ggnnrruuxx||}}{{yyxxvvttttssqqjjJJJJ߸߸aaffffefefffgfgfffmfmfffpfpffftftfffwfwfff{f{f}f}f}f}fyfyfffwfwffftftffftftfffsfsfffsfsfffrfrfffqfqfffpfpfffofofffofofffpfpffflflfff`f`fffffggNNhh昚yyzz}}~~{{zzzzxxxxxxyyzz}}}}ggԙԙQQ  YYtgtgEfEfff{f{fyfyfffxfxfff|f|fzfzfffwfwfffufufffufuffftftfffrfrfffqfqfffqfqfffsfsfffrfrffftftfffwfwfffyfyfffzfzf~f~f{f{f|f|f~f~fzfzfff{f{f{f{fffKfKfcgcgZZHHؙؙddyy{{||||||{{yyvvuuyy||||||~~{{wwttʠʠkMkMggffff_f_fffnfnfffqfqfffqfqfffqfqfffrfrfffpfpfffofofffrfrffftftffftftfffufufffvfvfffxfxfff{f{f{f{fffxfxffftftfffqfqfffmfmfffgfgfffafafffffbb& & TTEEhhssuuuuuuyy{{||{{{{~~{{vvssqqmmeeYY((UUUT>Tllzz~~~~||{{||||{{wwxxzz~~ttxUxUgg+f+fffnfnfffvfvfffvfvfffvfvfffufufffufuffftftfffsfsfffrfrfffrfrfffqfqfffpfpfffsfsfffvfvfffwfwfffzfzf|f|f~f~fzfzfffwfwffftftfffpfpfffvfvfhfhfggm^m^++SSoouuwwwwwwxxzzzzzz||}}~~||wwppllwwCC88GGggffffVfVfffgfgffflflfffnfnfffnfnfffnfnfffqfqfffsfsfffsfsfffqfqffftftfffxfxf~f~f}f}fzfzfffwfwfffwfwffftftfffqfqfffmfmfffififffbfbfffXfXfffmfmfrdrdk)k)͘͘HHffkkppsswwwwyy{{}}~~{{zzxxttppkkbbKK̙̙יי˵K4K4(f(f6f6fffRfRfffafafffgfgffflflfffmfmfffofofffpfpffftftfffvfvfffzfzf|f|fffxfxfffwfwffftftfffqfqfffqfqfffofofffnfnfffjfjfffffffffafafffQfQfffff6g6g:>:>֖֎]]eemmttxx{{~~}}}}{{xxuuttssttrrjjJJIIaaffffgfgfffhfhfffkfkfffpfpfffvfvfffxfxfffyfyf~f~f|f|fzfzfffxfxfffufufffsfsfffqfqfffofofffpfpfffpfpfffqfqfffqfqfffqfqfffpfpfffmfmfffafafffffggNNkk瘙zzzz~~}}||}}||{{zzyyzz{{||{{}}||ff֙֙PPYYtgtgFfFfff{f{fzfzf~f~f{f{f|f|f}f}fzfzfffyfyfffwfwfffufufffsfsfffrfrfffrfrfffqfqfffqfqfffpfpfffqfqfffufufffxfxfff{f{f|f|f~f~fzfzfffwfwfffxfxf}f}fffLfLfbgbgZZEEڙڙdd{{~~}}}}{{zzxxwwvvxxyy{{}}}}xxuuuu̠̠mMmMggffff]f]fffmfmfffrfrfffrfrfffpfpfffofofffpfpfffrfrfffrfrfffsfsfffufufffxfxfffxfxfffyfyf~f~f|f|f{f{fffxfxfffvfvfffqfqffflflfffgfgfffbfbfffff}b}b) ) ZZHHhhpprrttuuuuuuxx||zzwwvvttmmeeYY''WWTf>fggXX\\]]ЙЙhh~~~~||zzwwvvyyzz{{||~~~~zz{{ӘӘeeJPJPggffffcfcfffofofffrfrfffrfrfffpfpfffofofffpfpfffsfsfffsfsfffrfrfffqfqfffrfrfffwfwfff|f|f{f{f~f~fzfzf~f~fyfyfffufufffsfsfffofofffhfhfffgfgfffffIaIadd99==JJhhppsswwxxxxyy{{}}}}~~~~{{wwuuppiibb@@YgYgffffSfSfffafafffgfgfffififfflflfffnfnfffofofffrfrfffvfvfffxfxfffzfzf}f}f}f}fzfzfffxfxfffwfwffftftfffqfqfffofofffkfkfffhfhfff`f`fffTfTfff=f=fee-2-2ɧɒՙՙJJccnnqqssvvzz}}~~}}zzxxwwssnniibbGGìé++ddcfcfffZfZfffcfcfffgfgfffkfkfffnfnfffqfqffftftfffwfwfffzfzf}f}f}f}fzfzfffwfwfffufufffrfrfffpfpfffofofffnfnfffmfmffflflfffjfjfffdfdfffRfRfffffggpEpE߅SSsskkqqvv||~~~~{{wwvvxxyy{{xxttmmPP((7_7_ggrfrfrfrfffpfpfffsfsfffvfvfffyfyf}f}f|f|f{f{fffxfxfffufufffufufffsfsfffsfsfffqfqfffsfsfffsfsfffsfsfffrfrfffqfqfffpfpfffsfsfffufufffmfmfff'f'fggATATjjxx}}||{{{{||||{{{{{{}}}}~~wwyUyUgg-f-fffnfnffftftffftftfffufuffftftffftftfffsfsffftftfffrfrfffrfrfffqfqfffrfrffftftfffwfwfffzfzf}f}f}f}f{f{f~f~fyfyfffyfyfffufufffrfrfffvfvfhfhfggl^l^**SSppwwzzyyxxwwxxwwzz||}}~~~~~~zzwwppkkvvDD77 G Ggg f fffVfVffffffffflflfffnfnfffofofffpfpfffrfrfffsfsfffsfsfffsfsffftftfffwfwf~f~f{f{f|f|fffxfxfffyfyfffvfvfffrfrffflflfffhfhfffafafffVfVffflflfsdsdi)i)˘˘GGeemmqquuwwwwyy{{}}~~{{yyxxssqqllbbKK͙͙֙֙˵J4J4*f*f5f5fffQfQfffafafffgfgfffkfkffflflfffpfpfffufufffxfxfffzfzf~f~f{f{f}f}f|f|f{f{f~f~fyfyfffufufffqfqfffpfpfffpfpfffofofffmfmfffififffafafffQfQfffff7g7g9>9>֗֍]]ggnnrruuwwzz~~}}yyyyxxwwvvvvvvssqqhhJJJJ޸޸aaffffgfgfffhfhfffmfmfffsfsfffvfvfffwfwfffyfyf~f~f|f|f|f|f}f}fyfyfffwfwfffsfsfffsfsfffqfqfffqfqfffpfpfffpfpfffpfpfffofofffnfnfffmfmfffafafffffggNNhh昙zzyy||}}{{yyxxyyzz{{zz{{||}}ee֙֙PP  YYrgrgGfGfff|f|fzfzfff{f{f{f{f~f~fyfyfffwfwffftftfffsfsfffsfsffftftffftftfffrfrfffrfrfffrfrfffsfsffftftfffwfwfffzfzf}f}f{f{f}f}f|f|f|f|f}f}f{f{f{f{fffMfMfagagZZëëCCܙܙ``xx||~~}}zzyyxxzz||||||}}}}~~~~{{xxxxΠΠmMmMggffff]f]fffjfjfffmfmfffnfnfffnfnfffofofffofofffpfpfffqfqffftftfffvfvfffvfvfffxfxfff{f{f|f|f~f~fxfxfffufufffsfsfffpfpffflflfffgfgfffcfcfffff{b{b+ + ZZHHffoossuuvvvvvvyyzz||~~{{xxttqqkkccZZ))VVTf>fee0202ɤɕԙԙKKcckknnrrvv{{}}}}}}zzxxwwvvttrrmmddFFíé++ddafafffVfVfff`f`fffffffffkfkfffofofffsfsfffvfvfffyfyf}f}f}f}fzfzfffxfxfffwfwfffvfvfffsfsfffqfqfffpfpfffnfnfffmfmffflflfffjfjfffefefffUfUfff f fggpEpE߄TTqqkkqqvvyy}}}}||{{xxwwxxwwwwwwvvooRR,,3_3_ggofofsfsffflflfffrfrfffyfyf}f}f{f{f}f}f{f{f~f~fzfzf}f}f~f~fxfxfffufufffsfsffftftfffsfsfffpfpfffofofffqfqfffrfrfffsfsffftftfffufufffvfvfffnfnfff(f(fgg>T>Tnn{{||||zzyyyy{{{{zz{{~~xxwUwUgg,f,fffofofffufufffvfvfffwfwfffvfvfffufufffrfrfffpfpfffrfrfffrfrfffsfsfffufufffwfwfffwfwfffxfxfffyfyf}f}f}f}f{f{fffxfxfffvfvfffsfsfffxfxfhfhfggo^o^**VVssxxvvttuuvvxxzz{{||||~~{{vvqqnnxxBB77 G Ggg f fffYfYfffgfgfffmfmfffofofffnfnfffnfnfffofofffnfnfffofofffrfrfffufufffwfwfff{f{f{f{fffwfwfffvfvffftftfffqfqfffmfmfffififffbfbfffVfVfffjfjfududi)i)̘̘FFbbllttvvwwxx{{||||~~~~zzyywwuuqqllccOOəəؙؙ˴K4K4+f+f2f2fffNfNfff]f]fffffffffkfkfffnfnfffqfqffftftfffufufffxfxfffzfzf}f}f|f|f{f{fffwfwfffsfsfffrfrfffofofffmfmffflflfffkfkfffhfhfffafafffRfRfffff3g3g=>=>֔֐^^ffllrrvv{{~~}}yyvvuuttuuttppggGGGGaaffffefefffhfhfffofofffrfrffftftfffxfxf~f~f}f}fyfyfffxfxfffxfxfffxfxfffvfvfffsfsfffpfpfffpfpfffpfpfffpfpfffqfqfffpfpfffpfpfffmfmfffafafffffggNNjj蘗xxxx||}}{{{{yywwxxyyzz}}ffՙՙPP  YYsgsgGfGfff|f|fyfyfffyfyf}f}f~f~fxfxfffvfvfffufuffftftfffsfsfffsfsffftftfffsfsfffsfsfffrfrfffrfrfffrfrfffufufffxfxf}f}f}f}fyfyfffwfwfffxfxf}f}fffKfKfcgcgZZ««CCݙݙ``zz}}{{zz{{zzxxwwxxzz}}||zzvvvvˠˠlMlMggffff_f_fffnfnfffqfqfffpfpfffnfnfffofofffofofffpfpfffqfqfffrfrffftftfffufufffwfwfff{f{f{f{f~f~fxfxffftftfffrfrfffpfpfffnfnfffififffefefffff}b}b( ( XXEEeeoossuuuuwwyy||{{yyvvqqllgg\\((WWR:>֗֎^^ffllssxx{{{{}}~~{{{{zzyywwwwvvttooggHHHHaaffffffffffhfhffflflfffqfqfffsfsfffvfvfff{f{fzfzfffxfxfffwfwfffufufffsfsfffsfsfffqfqfffqfqfffrfrfffrfrfffpfpfffofofffpfpfffnfnfffafafffffggNNii昚zzyy||~~~~||||{{yyyyxxyyxxzz}}}}ffՙՙPPYYugugDfDfffzfzfzfzfffzfzf}f}f~f~fxfxfffufufffufufffufufffufuffftftffftftfffsfsfffqfqfffqfqfffrfrfffufufffwfwfffzfzf}f}f}f}fzfzf~f~fyfyfffzfzf|f|fffKfKfbgbgZZëëCCܙܙ``xx||}}~~~~||{{zzzzyyxxzz}}}}zzxxww̠̠mMmMggffff^f^fffkfkfffofofffpfpfffofofffnfnfffofofffofofffrfrfffsfsfffvfvfffxfxfffyfyf~f~f{f{f}f}f|f|f|f|f~f~fyfyfffufufffqfqffflflfffefefffbfbfffff~b~b' ' WWEEggqqttuuvvxxxxyy||~~}}{{vvoollee\\''YYQf>fee.2.2ɧɒ֙֙IIbbllqqttvvyy{{~~~~{{zzyyxxuuqqmmccFFìé++ddafafffWfWfffafafffefefffkfkfffnfnfffqfqffftftfffxfxf}f}f}f}fzfzfffxfxfffwfwfffsfsfffpfpfffqfqfffrfrfffpfpfffmfmffflflfffjfjfffefefffWfWfff f fggoEoE߃TTrrmmqqttww}}||zzxxxxyyyyxxvvuuooRR**5_5_ggnfnfsfsfffnfnfffqfqfffwfwfffxfxfffzfzf~f~f|f|f{f{fffvfvffftftfffsfsffftftfffsfsfffsfsfffpfpfffpfpfffqfqfffrfrffftftfffufufffufufffjfjfff$f$fgg?T?Tkkxx~~{{yywwxxyy{{||~~~~wwxUxUgg*f*fffofofffxfxfffxfxfffvfvffftftfffsfsfffrfrfffpfpfffqfqfffrfrffftftfffufufffvfvfffwfwfffwfwfffxfxf~f~f|f|fyfyfffufuffftftfffrfrfffvfvfhfhfggl^l^,,TTqqwwwwvvvvxxxxyyzz||}}~~{{vvrrnnwwDD::GGgg f fffXfXfffefefffififffkfkfffnfnfffofofffpfpfffpfpfffrfrffftftfffwfwfff|f|f|f|f}f}f{f{f~f~fyfyfffvfvfffrfrfffpfpfffmfmfffjfjfffdfdfffYfYfffnfnfrdrdj)j)̘̘GGeemmqqssuuxxzzzz||||yywwuuqqllbbJJ͙͙ՙՙ˷J4J4*f*f4f4fffQfQfff^f^fffffffffjfjfffnfnfffqfqfffufufffwfwfffzfzf~f~f{f{f|f|f~f~fzfzfffwfwffftftfffsfsfffsfsfffqfqfffmfmfffkfkfffhfhfffcfcfffRfRfffff5g5g:>:>֘֌[[ddmmssxx{{~~~~||yywwwwvvuusspphhHHHHaaffffffffffhfhffflflfffrfrfffufufffyfyf~f~f|f|f{f{fffxfxfffxfxfffxfxfffvfvfffufufffsfsfffqfqfffnfnfffofofffpfpfffqfqfffpfpffflflfff_f_fffffggNNhh昚zz{{~~||}}||{{xxxxxxzz{{}}||ee֙֙OO  YYrgrgGfGfffzfzf}f}f{f{f}f}f{f{f~f~fzfzfffwfwffftftfffsfsfffufuffftftfffqfqfffpfpfffrfrfffrfrffftftffftftfffwfwfffzfzf|f|f}f}f{f{f~f~fyfyfffxfxf~f~fffMfMfbgbgZZEEٙٙdd{{||{{||||||zzxxyyzz||}}||}}||xxuuʠʠkMkMggffff^f^ffflflfffpfpfffofofffofofffofofffpfpfffrfrffftftfffvfvfffufuffftftfffvfvfffyfyf}f}f}f}fzfzfffwfwfffufufffpfpfffkfkfffdfdfffbfbfffffzbzb, , ZZGGhhppqqqqssuuxxzz}}}}yyvvrrnnccXX''VVVf>fee/2/2ɥɔԙԙJJaakkppttwwyy{{~~||xxvvssttqqllddGGîè++ddcfcfffYfYfffcfcfffgfgffflflfffpfpfffsfsfffufufffxfxfff{f{f|f|f}f}f{f{fffxfxfffvfvfffsfsfffrfrfffofofffmfmfffnfnfffnfnfffjfjfffbfbfffSfSfffffggoEoE߃SSsskkqqttyy~~~~}}{{zzxxyywwvvvvvvuuooSS++2_2_ggmfmfufufffofofffpfpffftftfffyfyf~f~f{f{f|f|f}f}fzfzfffxfxfffvfvffftftffftftfffrfrfffpfpfffpfpfffrfrfffsfsfffsfsffftftfffufuffftftfffkfkfff$f$fgg?T?Tkkzz~~}}}}{{yywwxxyy{{||}}uuxUxUgg*f*fffmfmfffufuffftftfffsfsffftftfffufuffftftfffrfrfffqfqfffrfrfffvfvfffufuffftftfffufufffxfxfffzfzf|f|f~f~fyfyfffwfwffftftfffqfqfffwfwfgfgfggk^k^--TTppwwyyxxuuvvxxyy{{{{||~~~~{{wwrrmmvvDD88GGgg f fffWfWfffgfgffflflfffmfmffflflfffmfmfffpfpfffrfrfffsfsffftftfffvfvfffxfxfffzfzf}f}f}f}fyfyfffufufffrfrfffnfnffflflfffjfjfffcfcfffYfYfffnfnfqdqdl)l)˘˘EEddnnppssttyy{{}}~~||vvttrroojjaaKK̙̙יי˵L4L4'f'f7f7fffUfUfffbfbfffififffififffkfkfffnfnfffqfqffftftfffxfxf~f~f|f|f{f{f}f}fzfzfffwfwfffsfsfffpfpfffpfpfffpfpfffnfnfffkfkfffgfgfffafafffSfSfffff4g4g<><>֕֎]]eekkqqwwzz}}~~||zzzzyyxxuussssqqiiIIII߸߸aaffffefeffffffffflflfffqfqfffufufffxfxfff{f{f}f}f}f}fzfzfffvfvfffsfsfffqfqfffqfqfffrfrfffsfsfffrfrfffrfrfffsfsfffrfrfffofofffkfkfff]f]fffffggNNii嘚zzzz{{~~||yyxxzz}}}}}}}}~~~~zzddؙؙNN  YYtgtgDfDfffyfyf{f{f}f}f|f|f}f}f|f|f|f|f}f}fzfzfffvfvfffrfrfffqfqfffrfrfffsfsfffqfqfffqfqfffqfqffftftfffufufffwfwfff{f{f}f}f}f}f{f{f}f}f{f{f~f~f{f{f{f{fffLfLfagagZZ««EEڙڙcc{{||||{{{{{{yyxxxxzz||{{||~~{{uussˠˠmMmMggffff`f`fffnfnfffpfpfffofofffpfpfffofofffofofffofofffpfpfffrfrffftftfffwfwfff{f{f|f|f~f~fyfyfffyfyfffzfzf~f~fyfyfffrfrfffkfkfffefefffbfbfffff}b}b) ) YYGGffmmqquuuuvvxxzz~~~~{{wwssnnddWW%%YYSf>fggXXZZ]]ϙϙii{{}}}}}}}}}}||||{{zz{{{{{{||}}||xxxx՘՘eeLPLPggffffffffffpfpfffqfqfffqfqfffqfqfffqfqfffpfpfffpfpfffpfpfffqfqfffsfsffftftfffwfwfffzfzf}f}f}f}fyfyfffvfvfffufuffftftfffpfpfffififffhfhfffffJaJacc;;==KKjjpprruuuuwwwwzz||||yyvvuuppiibb@@YgYgffffPfPfffafafffhfhfffkfkfffnfnfffofofffrfrfffsfsfffsfsffftftfffxfxf~f~f{f{f{f{fffxfxfffvfvffftftfffqfqfffofoffflflfffgfgfff_f_fffSfSfff>f>fee/2/2ɥɔԙԙJJ``iioottxxzz{{~~~~{{{{yywwrrppnneeGGïæ++dd]f]fffSfSfff_f_fffhfhfffnfnfffrfrffftftfffxfxf~f~f|f|f|f|f}f}fzfzfffzfzfffwfwfffufufffufuffftftfffqfqfffnfnfffmfmffflflfffjfjfffefefffVfVfff f fggpEpE߃TTrrkkqqtt{{~~~~~~{{xxwwvvwwxxxxvvnnPP**4_4_ggofofsfsfffofofffsfsfffvfvfffyfyfffzfzf}f}f{f{f}f}f~f~fxfxfffufufffsfsfffqfqfffpfpfffnfnfffnfnfffpfpffftftfffwfwfffwfwfffvfvfffvfvfffnfnfff'f'fgg?T?Tll||}}}}||{{||||{{zzyyxxyy{{}}~~yyvUvUgg*f*fffnfnfffwfwfffxfxfffwfwfffvfvffftftfffrfrfffqfqfffrfrfffrfrfffqfqfffrfrfffufufffvfvfffvfvfff{f{f|f|f~f~fyfyfffwfwffftftfffqfqfffwfwfififggq^q^!!**WWssyyyyyywwuuwwxxzz||~~~~{{vvppllwwCC77GGgg f fffWfWfffgfgffflflfffnfnfffnfnfffofofffpfpfffqfqfffsfsfffufufffvfvfffxfxfff{f{f{f{fffxfxfffwfwfffufufffsfsfffofofffgfgfffafafffXfXfffmfmfsdsdi)i)˘˘GGffnnqqssvvxxzz||~~||zzxxuuqqllccMM˙˙ՙՙ˸H4H4,f,f2f2fffPfPfff^f^fffdfdfffififffmfmfffqfqffftftfffvfvfffyfyf~f~f{f{f{f{fffwfwfffsfsfffqfqfffqfqfffqfqfffrfrfffrfrfffofofffkfkfffbfbfffQfQfffff6g6g:>:>֗֍\\ffoorrvvzz}}}}||||zzvvttssssqqiiJJIIaaffffdfdfffgfgfffmfmfffqfqfffsfsfffxfxf~f~f|f|f{f{fffwfwfffufufffufuffftftffftftfffrfrfffrfrfffpfpfffofofffofofffqfqfffqfqfffnfnfffbfbfffffggNNii瘘yyzz~~~~~~{{zzxxyywwvvyy{{}}~~}}hhәәQQYYugugBfBfffvfvf~f~f|f|f|f|f|f|f~f~fzfzfffyfyfffxfxfffwfwffftftfffrfrfffrfrfffrfrfffrfrfffrfrfffsfsfffvfvfffwfwfffxfxfffzfzf|f|f~f~fyfyfffxfxf~f~fffMfMfagagZZFFٙٙccyy{{||}}{{{{yyyyxxzzzz||}}{{wwuu̠̠nMnMggffff`f`fffnfnfffqfqfffqfqfffofofffqfqfffofofffnfnfffofofffqfqffftftfffvfvfffxfxfffzfzf|f|f~f~fyfyfffufufffsfsfffpfpffflflfffefefffafafffffbb' ' YYIIiiqqrrttvvxxyyzz}}||yywwttnneeXX''XXSg>g\\ ZZ22\\xx{{||yyxxxxyyyywwzz{{}}~~||yyttrr]] \J\Jgg f fffZfZfffififffmfmfffnfnfffnfnfffnfnfffofofffrfrfffrfrfffrfrffftftfffwfwfffyfyf~f~f|f|fzfzfffwfwfffvfvfffsfsfffmfmfffffffffbfbfff^f^fffffcc$$EEeennrruuwwyyyy{{~~zzwwttqqmmeeTToob8b8ff$f$fffPfPfff`f`fffgfgfffkfkffflflfffmfmfffqfqfffufufffxfxfffzfzf~f~f{f{f}f}f}f}fzfzfffufufffrfrfffqfqfffofoffflflfffjfjfffgfgfff`f`fffPfPfffffff_:_:##ǚǚVVeemmrruuxx{{~~}}zz{{yyxxuuuurrooggGGooNN"" c cffff_f_fffffffffkfkfffpfpfffsfsfffwfwfffzfzf~f~f|f|f{f{f~f~fzfzfffyfyfffufufffrfrfffrfrfffrfrfffrfrfffofofffnfnfffmfmfffmfmfffhfhfff[f[fff f fggKKyy ttvvzz}}~~}}||{{zzxxyyzzzzzz{{{{vv]]99  [[PgPgTfTfffffwfwfffyfyf|f|f~f~fyfyfffxfxfffwfwfffwfwfffufufffsfsfffrfrffftftfffufufffufufffrfrfffqfqfffrfrfffwfwfffyfyf}f}f{f{f}f}f|f|f|f|fyfyfff@f@fggXXXX``͙͙ii||~~{{zz{{||||zzzz||~~}}}}{{||ԘԘeeLPLPggffffdfdfffpfpfffpfpfffnfnffflflfffnfnfffnfnfffofofffrfrfffufufffwfwfffxfxfffxfxfffzfzf~f~fzfzf}f}f}f}fzfzffftftfffqfqfffnfnfffkfkfffififffffKaKabb<<<T>Tmmyy~~}}||{{zzyyxx{{||wwzUzUgg.f.fffpfpfffwfwfffvfvffftftfffrfrfffrfrfffsfsfffrfrfffrfrfffpfpfffrfrfffsfsfffufufffvfvfffyfyfff{f{f|f|f}f}f{f{fffwfwffftftfffqfqfffwfwfhfhfggo^o^++TTnnuuwwxxxxxxxxzzzz{{}}~~zzuuqqmmxxBB66!G!Ggg f fffXfXfffgfgfffkfkfffmfmffflflfffmfmfffmfmfffpfpfffrfrfffufufffwfwfff{f{f}f}f}f}fzfzfffyfyfffwfwfffsfsfffofofffkfkfffififffefefff\f\fffpfpfqdqdj)j)ʘʘFFbbkkppssuuwwyy{{~~}}||zzwwuuppkkbbMM˙˙יי˵J4J4)f)f5f5fffSfSfff`f`fffffffffkfkfffofofffqfqfffrfrffftftfffyfyf}f}f}f}fzfzfffyfyfffxfxfffufufffsfsfffqfqfffofofffnfnffflflfffhfhfffbfbfffRfRfffff6g6g:>:>֗֍\\eennqqvvzz~~zzvvvvvvuuttuurrjjKKJJ߸߸aaffffefefffhfhffflflfffqfqfffufufffwfwfffzfzf}f}f}f}fzfzfffxfxfffwfwffftftfffqfqfffnfnfffofofffpfpfffqfqfffpfpfffpfpfffpfpfffnfnfffcfcfffffggNNiiꘕwwzz}}||||{{zzyyyyxxzz{{{{||~~||ggәәSSYYtgtgFfFfff|f|fyfyf~f~f{f{f{f{fffxfxfffwfwfffwfwfffwfwffftftfffrfrfffqfqfffrfrfffsfsfffrfrfffsfsfffufufffxfxfffxfxfffyfyf~f~f}f}fzfzfffxfxf}f}fffLfLfbgbgZZëëCCݙݙaa{{~~~~}}zzzzyyyyyyzzzz{{xxvvˠˠkMkMggffff]f]fffjfjfffnfnfffpfpfffpfpfffqfqfffofofffpfpfffqfqfffrfrfffsfsfffufufffyfyf~f~f|f|fzfzfffxfxfffufufffrfrfffnfnfffkfkfffefefffcfcfffff{b{b* * ZZHHiiqquuvvvvvvxxzz{{||}}}}{{yyuuqqllee\\**TTWT>Tmmzz~~{{{{zz{{zz||zzyyzz}}~~vvvUvUgg*f*fffnfnfffwfwfffufufffufufffufufffufufffsfsfffrfrfffpfpfffqfqfffrfrfffsfsffftftfffvfvfffwfwfffyfyf~f~f|f|fzfzfffufufffrfrfffofofffvfvfhfhfggo^o^ ))TTrrxxxxxxwwxxzz||||{{{{}}~~zzwwttooyyBB77!G!Ggg f fffVfVfffefefffjfjfffkfkfffkfkfffmfmfffofofffqfqfffsfsfffvfvfffyfyfffyfyfffzfzf}f}f|f|f{f{fffxfxffftftfffpfpffflflfffgfgfff_f_fffUfUfffmfmfsdsdj)j)͘͘IIeellqquuwwxxzz}}||||~~~~{{yyuuppjj``MMʙʙיי˶I4I4+f+f3f3fffQfQfff_f_fffffffffkfkfffnfnfffofofffsfsfffxfxfff{f{f|f|f}f}fzfzfffyfyfffzfzfffxfxfffsfsfffqfqfffofoffflflfffjfjfffififffcfcfffSfSfffff5g5g;>;>֖֎[[bbjjqqww{{}}||{{xxwwttttttttmmLLJJaaffffbfbfffefefffkfkfffpfpfffufufffyfyf~f~f|f|f{f{fffxfxfffvfvffftftfffsfsffftftfffrfrfffqfqfffofofffqfqfffqfqfffofofffmfmfffmfmfffcfcfffffggNNgg昙wwww||}}||||{{||yyyyxxyy{{}}||eeՙՙQQ  YYsgsgFfFfffzfzf|f|f}f}f}f}fzfzf~f~fzfzfffyfyfffxfxfffvfvfffufufffsfsfffpfpfffnfnfffpfpfffrfrffftftffftftfffufufffxfxfff{f{f{f{f~f~fzfzfffyfyf~f~fffPfPf^g^gZZëëEEڙڙcczz}}||{{{{{{zzyyzz{{||||||{{uuuu̠̠lMlMggffff]f]fffkfkfffofofffqfqfffqfqfffpfpfffofofffqfqfffsfsffftftffftftfffvfvfffwfwfffyfyf~f~f{f{f|f|fffwfwfffsfsfffofofffififffdfdfffcfcfffffzbzb- - [[HHffqqttttssuuwwzz}}~~{{xxuuqqllee[[((VVTT>Tnn{{~~zzxxxxxxyyxxzz{{}}wwxUxUgg+f+fffofofffwfwfffxfxfffufuffftftfffsfsfffrfrfffpfpfffqfqfffrfrfffrfrfffsfsfffufufffvfvfffwfwfffzfzf|f|fffxfxffftftfffsfsfffqfqfffxfxfgfgfggm^m^**UUrrvvwwxxyyxxyyzzzzzz}}{{wwrrlluuEE77 G Ggg f fffWfWfffgfgfffkfkfffnfnfffnfnfffofofffpfpfffrfrfffrfrfffsfsfffufufffyfyf~f~f{f{f}f}f|f|fzfzfffvfvfffqfqfffofofffkfkfffgfgfffbfbfffYfYfffqfqfndndn)n)ΘΘGGcckknnqqttvvyy}}}}zz{{yyxxssll``JJ͙͙֙֙˵K4K4)f)f6f6fffSfSfff`f`fffefefffhfhfffmfmfffrfrfffvfvfffxfxf~f~f{f{f}f}f|f|f}f}f{f{f|f|f~f~fyfyfffvfvffftftfffqfqfffpfpfffmfmfffjfjfffffffff`f`fffRfRfffff5g5g<><>֕֏]]ffoorrvvyy||~~~~||zzzzyywwuuttttpphhHHHHaaffffffffffgfgfffmfmfffqfqfffvfvfffzfzf}f}f|f|f|f|f~f~fyfyfffvfvfffvfvfffvfvffftftffftftfffrfrfffpfpfffofofffofofffpfpfffofoffflflfff`f`fffffggNNjj瘙zz{{||zzyyyyyy{{{{zz{{||}}{{ffԙԙSSYYugugDfDfffzfzfzfzfffzfzf}f}f|f|f{f{fffxfxfffufufffsfsffftftfffsfsfffsfsfffqfqfffqfqfffqfqffftftfffwfwfffxfxfffzfzf}f}f|f|fyfyfffwfwfffxfxf|f|fffKfKfcgcgZZHHؙؙddzz||||||{{{{yyxxxxzzyy{{~~{{wwvvˠˠkMkMggffff_f_fffkfkfffofofffqfqfffqfqfffpfpfffnfnfffofofffofofffpfpfffufufffzfzf}f}f|f|f|f|f|f|f{f{f~f~fyfyfffwfwfffufufffofoffflflfffhfhfffcfcfffff}b}b* * [[GGeemmsswwxxwwww||~~~~~~zzttrrnnee[[**UUTg>g\\ YY22ZZttzz{{{{zzyywwyyyyzzzz||~~}}xxssqq ]] \J\JggffffXfXfffgfgfffmfmfffofofffqfqfffrfrfffufufffufuffftftffftftfffufufffvfvfffwfwfffyfyf}f}f}f}fzfzfffwfwfffrfrfffmfmfffhfhfffbfbfff]f]fffffcc$$DDddnnrrttuuvvyyzz||}}zzvvttqqllbbPPnnc8c8ff$f$fffQfQfff`f`fffgfgfffkfkfffnfnfffpfpfffrfrfffufufffxfxf~f~fzfzf~f~f{f{f|f|f}f}f{f{fffwfwfffufufffrfrfffnfnfffkfkfffhfhfffefefff`f`fffQfQfffffffb:b:!!ȚȚVVeekkoouu{{~~}}{{yyvvvvvvssmmccFFooLL""ccffff^f^fffcfcfffjfjfffpfpffftftfffwfwfffyfyf~f~f|f|fzfzfffxfxfffwfwfffvfvffftftfffrfrfffpfpfffofofffnfnfffpfpfffnfnfffmfmfffififff]f]fffffggKKzz ttwwyy||~~||{{||{{yyvvvvwwyy{{||zzaaݙݙ>>  [[RgRgRfRfffffvfvfffvfvfffxfxfff{f{f|f|f~f~fxfxffftftffftftfffufuffftftfffqfqfffpfpfffqfqfffqfqfffsfsfffufufffwfwfffxfxf~f~f|f|f{f{f~f~f{f{fxfxfff?f?fggXX[[^^ΙΙkk~~~~||||||zzxxwwxxyy||~~~~yyzzӘӘffLPLPggffffcfcfffofofffrfrfffqfqfffpfpfffofofffpfpfffpfpfffqfqfffqfqfffrfrfffufufffxfxf~f~f|f|f|f|f}f}fzfzfffxfxfffvfvfffsfsfffpfpfffmfmfffkfkfffffJaJabb<<;;IIhhooqqttvvxxyyzzyyzz~~||xxssrrooggbb@@VgVgffffRfRfffbfbfffhfhfffkfkffflflfffmfmfffofofffrfrfffsfsfffvfvfffxfxfffzfzf}f}f~f~fxfxfffufufffrfrfffofoffflflfffififffffffff`f`fffTfTfff>f>fee.2.2ɥɕҙҙMMeellrrttwwxxzz||~~{{xxwwttssnniibbHHíé++ddbfbfffWfWfffbfbfffififffmfmfffpfpffftftfffvfvfffwfwfff{f{f|f|f}f}fzfzfffxfxfffufufffsfsfffqfqfffofofffofofffnfnfffmfmfffjfjfffcfcfffTfTfffffggoEoE߄SSssllssww{{}}}}{{yywwwwxxwwxxxxxxqqQQ))4_4_ggnfnftftfffpfpffftftfffufufffufufffxfxf~f~f|f|f{f{fffxfxfffufufffsfsfffqfqfffqfqfffsfsfffsfsfffqfqfffqfqfffqfqfffsfsfffufufffvfvfffkfkfff$f$fgg>T>Tllzz~~~~}}||{{{{zzyy{{||}}~~uuxUxUgg+f+fffmfmfffufuffftftffftftfffsfsfffrfrfffqfqfffpfpfffrfrfffrfrfffqfqffftftfffwfwfffyfyfffyfyf~f~f{f{f|f|f~f~fxfxfffvfvfffsfsfffqfqfffxfxfffffggm^m^++VVsswwxxxxzzxxxxxxzzyyzz}}~~{{wwrrllwwDD99GGggffffVfVfffefefffififffmfmfffqfqfffrfrfffqfqfffqfqfffrfrfffsfsfffvfvfffyfyf~f~f|f|f|f|f~f~fyfyfffwfwfffufufffpfpffflflfffififffcfcfffZfZfffofofpdpdl)l)ʘʘDDaakkqquuuuwwzz||~~||zzwwuurrmmbbLL͙͙ԙԙ˸H4H4+f+f4f4fffQfQfff_f_fffhfhfffmfmfffpfpfffqfqfffufufffwfwfffyfyfffyfyf~f~f|f|f{f{f}f}fzfzfffxfxffftftfffqfqfffnfnfffmfmfffififffffffff_f_fffOfOfffff7g7g;>;>֕֐``ggmmsswwzz||~~}}zzyyzzyyxxwwttooffEEEEaaffffgfgfffififffnfnfffsfsfffwfwfffyfyf~f~f|f|f|f|f}f}fzfzfffxfxfffvfvffftftfffsfsfffrfrfffpfpfffnfnfffpfpfffqfqfffrfrfffpfpfffmfmfffcfcfffffggNNii昘xxww{{}}zzzzyywwvvxxzz}}||ffԙԙQQYYsgsgFfFfffzfzf|f|f}f}f{f{f}f}f|f|f|f|f~f~fyfyfffwfwffftftfffrfrfffpfpfffqfqfffrfrfffsfsffftftfffvfvfffvfvfffufufffwfwfff{f{f{f{fffzfzfffzfzfzfzfffKfKfcgcgZZ««DDۙۙbbxx{{{{||{{{{yyyyzz{{{{zz}}{{yyxx͠͠lMlMggffff_f_fffkfkfffmfmfffnfnfffpfpfffqfqfffrfrfffqfqfffqfqfffrfrfffufufffxfxfffzfzfffzfzf~f~f{f{f}f}f~f~fxfxffftftfffnfnfffjfjfffffffffcfcfffffbb' ' WWGGhhqqttxxzzyyyyzz{{{{~~||zzvvrrkkbbWW%%YYSg>g\\ WW44[[uuyyzz||zzxxwwyy{{{{zz{{}}~~yywwuuss__`J`Jgg f fffZfZfffhfhffflflfffmfmfffnfnfffnfnfffofofffqfqffftftfffsfsffftftfffvfvfffyfyf~f~f|f|fzfzfffwfwfffufufffrfrfffofofffjfjfffdfdfff\f\fffffcc$$FFffppssttvvwwyy{{||}}xxttnnjjbbQQnnb8b8ff%f%fffSfSfffbfbfffhfhfffkfkfffmfmfffpfpfffrfrffftftfffvfvfffyfyf~f~f{f{f{f{f~f~fzfzfffvfvfffufufffrfrfffqfqfffmfmfffjfjfffffffff`f`fffQfQfffffff_:_:##ǚǚVVbbkksswwyy||~~}}{{{{||zzvvssqqllddFFooLL""ccffffafafffhfhfffmfmfffpfpfffqfqfffrfrfffvfvfffzfzf|f|fffwfwfffvfvffftftfffsfsfffrfrfffrfrfffpfpfffpfpfffpfpfffqfqfffnfnfffhfhfffXfXfff f fggKK{{ uuww||~~~~{{zzzzyyzz{{{{{{{{||||ww]]::  [[RgRgRfRfffffvfvfffwfwfff{f{f|f|f}f}fzfzfffyfyfffwfwffftftfffrfrfffrfrfffsfsfffsfsfffsfsfffrfrffftftffftftfffvfvfffyfyf~f~f{f{f|f|f|f|fffufufff<>֔֏^^ffoossvvyy||||zz{{zzttqqqqpphhIIIIaaffffefefffhfhfffnfnfffqfqfffufufffxfxfff{f{f}f}f|f|f{f{fffxfxffftftfffrfrfffrfrfffrfrfffrfrfffpfpfffpfpfffpfpfffpfpfffofofffnfnfffcfcfffffggNNjj蘘xxyy||}}||{{yyzzzzzz{{zz{{~~~~ffՙՙPP  YYqgqgGfGfffzfzf{f{f}f}f}f}f{f{fffxfxfffvfvffftftfffufufffufuffftftfffsfsfffqfqfffqfqffftftffftftfffufufffwfwfffyfyf~f~f|f|f{f{f~f~fyfyfffyfyf|f|fffKfKfcgcgZZFFڙڙbbyy}}}}{{zzzzyyzz{{||{{yy{{~~||wwtt̠̠nMnMggffff_f_ffflflfffofofffofofffofofffofofffqfqfffqfqfffpfpfffpfpfffsfsfffwfwfffyfyfffzfzf}f}f}f}fzfzfffufufffrfrfffofofffkfkfffefefffbfbfffff{b{b+ + ZZGGeeppuuxxwwvvyyyyyy{{||yywwttmmddZZ''XXRf>fggXX[[]]ϙϙjj~~||}}~~||{{{{zzxxyy{{{{~~||xxzzӘӘeeLPLPggffffefefffqfqfffrfrfffqfqfffrfrfffqfqfffofofffofofffqfqfffqfqfffufufffwfwfffzfzfffzfzf~f~f{f{f|f|f}f}fzfzfffxfxffftftfffqfqffflflfffififffffMaMa__??88IIkkrrttttvvxxyyzz{{||}}~~zzvvrrnnffbb@@WgWgffffRfRfffbfbfffhfhfffkfkffflflfffmfmfffrfrffftftffftftfffsfsfffvfvfff|f|f{f{fffwfwfffvfvffftftfffqfqfffnfnfffkfkfffgfgfff_f_fffRfRfff=f=fee.2.2ɥɔՙՙJJ``kkppttwwxx{{~~}}{{zzyywwssppllddIIìè++ddafafffWfWfffafafffhfhffflflfffpfpfffrfrfffvfvfffxfxf~f~f{f{f|f|f}f}fzfzfffxfxffftftfffrfrfffqfqfffofofffnfnffflflffflflfffjfjfffefefffVfVfff f fggpEpE߃UUqqkkrrwwzz}}~~~~||zzyyyyzzyyvvuurrmmQQ,,3_3_ggofofsfsfffpfpfffsfsfffufufffxfxf~f~fzfzf}f}f}f}fzfzfffwfwfffufufffufufffrfrfffqfqfffqfqfffpfpfffqfqfffsfsffftftfffufufffvfvffftftfffjfjfff#f#fgg=T=Tmmxx||{{{{zz||{{zzzzzz||ttwUwUgg+f+fffofofffwfwfffwfwfffufufffrfrfffrfrfffrfrfffrfrfffqfqfffrfrfffrfrffftftfffufufffvfvfffyfyfffzfzf|f|f~f~fzfzfffvfvfffrfrfffqfqfffxfxfefefggl^l^**TTppvvxxxxxxxxxxxxxxzz||~~||xxttppllvvDD77 G Ggg f fffYfYfffhfhffflflfffmfmfffofofffofofffmfmfffnfnfffrfrfffvfvfffyfyf}f}f{f{f~f~f{f{f~f~f{f{f|f|fffwfwfffsfsfffpfpffflflfffhfhfffcfcfffXfXfffnfnfqdqdk)k)͘͘FFddllppssuuxxyy||~~{{xxttppkk``JJΙΙԙԙ˸I4I4*f*f5f5fffTfTfffbfbfffififfflflfffofofffqfqfffrfrfffufufffxfxfffzfzf|f|f}f}fzfzfffxfxfffwfwfffufufffrfrfffpfpfffnfnfffkfkfffffffff_f_fffOfOfffff6g6g;>;>֖֎\\ddmmssxxzz}}||zzxxxxyyyyvvttqqffEEFFaaffffgfgfffgfgfffkfkfffqfqfffufufffyfyf~f~f{f{f{f{f~f~fzfzfffxfxfffufufffrfrfffrfrfffrfrfffsfsfffsfsfffqfqfffqfqfffqfqfffpfpfffmfmfff`f`fffffggNNkk蘗wwyy~~}}}}||||{{yyxxwwzz~~zzee֙֙PPYYugugDfDfffxfxf|f|f}f}f|f|f|f|f}f}fzfzf~f~fzfzfffxfxfffvfvffftftfffqfqfffqfqfffrfrfffsfsfffsfsfffufufffwfwfffxfxfffxfxfffzfzf}f}f|f|f{f{fffzfzf{f{fffKfKfcgcgZZEEۙۙaaxx||{{||zzzzyyyyxxyyzz}}~~||xxww̠̠kMkMggffff^f^fffmfmfffpfpfffqfqfffpfpfffpfpfffpfpfffqfqfffqfqfffrfrffftftfffvfvfffxfxfffzfzf~f~f}f}fzfzfffwfwfffrfrfffofofffmfmfffgfgfffcfcfffff{b{b+ + ZZGGeeoottuuvvvvwwwwyy||}}||xxuuqqllddYY&&XXR;>֕֎]]eeoottvvzz}}~~}}}}||zzxxvvttsspphhHHHHaaffffgfgfffffffffkfkfffqfqfffwfwfffyfyf~f~f{f{f|f|f~f~fyfyfffwfwfffufufffsfsfffsfsfffrfrfffrfrfffqfqfffofofffqfqfffpfpfffofofffmfmfffbfbfffffggNNjj蘙xxxx||}}||||||yyxxyy{{}}}}}}}}}}zzeeԙԙRRYYtgtgFfFfff}f}fxfxfffyfyf}f}f}f}fzfzfffwfwffftftfffrfrfffqfqfffrfrfffrfrfffsfsffftftfffsfsfffrfrffftftfffxfxfff{f{f|f|f|f|f|f|f}f}fzfzfffyfyf}f}fffLfLfbgbgZZDDۙۙbbzz}}}}}}{{zzyyyyyyxxyy||{{xxvvΠΠoMoMggffff^f^ffflflfffofofffmfmfffnfnfffnfnfffofofffofofffqfqfffrfrffftftfffvfvfffyfyf}f}f}f}fzfzfffwfwffftftfffrfrfffofofffkfkfffgfgfffefefffffzbzb+ + ZZHHggoorrssuuwwyy{{}}~~||xxssppmmffZZ))VVTf>fggXX[[__͙͙kk~~~~||{{xxzz{{{{yyzz||~~}}{{||ӘӘeeKPKPggffffbfbfffnfnfffpfpfffrfrfffqfqfffrfrffftftfffsfsffftftfffsfsfffsfsffftftfffvfvfffxfxfffzfzf|f|f~f~fzfzfffufufffqfqfffnfnffflflfffjfjfffffKaKabb<<::HHffppuuwwwwxxyyyyzz~~~~zzuunneeaa@@ZgZg f fffNfNfff`f`fffhfhffflflfffnfnfffpfpfffpfpfffqfqfffufufffwfwfff{f{f}f}f}f}f{f{f}f}fzfzfffwfwffftftfffrfrfffnfnfffhfhfffdfdfff_f_fffSfSfff@f@fee0202ɤɔԙԙJJbbllrrttwwyy||||~~~~||{{xxuuqqppllbbFFíè++ddbfbfffWfWfffbfbfffgfgfffmfmfffrfrfffufufffvfvfffwfwfffyfyf}f}f~f~fxfxfffufufffufuffftftfffrfrfffpfpfffpfpfffmfmfffkfkfffififffefefffVfVfff f fggpEpE߄TTrrkkqqttxx}}}}||zzyyxxyyxxvvwwvvppRR((5_5_ggpfpfrfrfffofofffufufffvfvfffwfwfffxfxfff}f}fyfyfffufufffsfsfffrfrfffqfqfffqfqfffrfrfffrfrfffsfsfffrfrfffsfsfffufufffvfvffftftfffjfjfff%f%fgg>T>Tllyy~~||zzwwxxxxzz||}}vvyUyUgg,f,fffnfnfffwfwfffxfxfffvfvffftftffftftffftftfffsfsfffpfpfffqfqfffrfrfffsfsffftftfffufufffvfvfffzfzf}f}f|f|f{f{f~f~fxfxffftftfffqfqfffxfxfgfgfggp^p^""''RRppvvwwwwyyzz{{{{zzzz{{}}~~zzvvrrooyyBB88GGggffffVfVfffefefffjfjffflflfffmfmfffofofffrfrffftftfffsfsfffsfsfffufufffyfyf}f}f}f}f{f{fffzfzfffxfxffftftfffpfpfffmfmfffhfhfffcfcfffZfZfffqfqfpdpdk)k)˘˘DDbbjjpprruuxx{{}}~~}}zzxxwwttpplleeOOəəؙؙ˵I4I4*f*f5f5fffSfSfff`f`fffffffffhfhffflflfffofofffrfrfffwfwfffyfyf~f~f{f{f}f}f}f}fzfzfffyfyfffvfvfffsfsfffpfpfffmfmfffkfkfffkfkfffgfgfff`f`fffOfOfffff6g6g;>;>֔֐__ggoouuwwyy||}}zzyyvvvvuuuuvvqqhhHHII߸߸aaffffhfhfffjfjfffmfmfffpfpfffsfsfffwfwfffzfzf~f~f|f|f{f{fffxfxfffwfwffftftfffqfqfffpfpfffpfpfffpfpfffofofffpfpfffqfqfffqfqfffnfnfffdfdfffffggNNkkꘕvvyy||~~||yy{{zzzzxxzzzz{{}}zzeeՙՙQQYYvgvgCfCfffyfyfzfzfffyfyfffzfzf|f|f~f~fyfyfffvfvffftftfffqfqfffqfqfffpfpfffrfrffftftfffvfvfffvfvfffvfvfffvfvfffyfyf~f~f{f{f{f{f~f~f{f{f}f}f{f{f|f|fffKfKfcgcgZZGGٙٙddzz}}||||zzyyxxwwwwyy||||}}~~~~||yyʠʠjMjMggffff^f^fffkfkfffnfnfffmfmfffofofffpfpfffqfqfffqfqfffsfsfffsfsffftftfffvfvfffyfyf~f~f{f{f|f|f|f|f{f{f}f}fzfzfffvfvfffpfpfffjfjfffefefff`f`fffff~b~b) ) ZZFFeeppuuuuuuuuxx{{||}}~~{{xxuurrnngg[[((VVTڀ|q4|͋zIxɏtogháatQ.n2b8ff#ffPffrafԒfQgffiffkff4offrffgwffxf~fxff{f%{f~fvfqfufςftfXfsffof‰fmf,fkffgffo`ffQffff_:#ŚjSQb4PkQr2bv"yÌ|숙Csބ9Ɓl$~u3{_ v)[uDs3srmcLF#pJ"KcĜfWfaff#fff9lfZfYoffqfftffxf}f{f{f:}f8zfefpwfBfytffsffKsffqf3fLoffof\f|pffqoffmffgffSYfسfX fgKIx$ 劙p֖brԒFxQ}~-ӄ~剙5}ϋzČZ{L_{}y㏙vrv3vxÍyW{{)zyfbܙ:= [PgRfff&wffxf~f{f{fI~fzxffwfMfvflftf(f(tff}tfnf?uff3tfUfrfIfrffrfof)tf΃ftfʂfcvffwf+fzf\}fwff@fq7l՞PcGñ+d_ffVffcfefkif7flffnfcfpffsffvf)fzf8|f }fyflfxf%fvffuff4rf߇f9ofĊfkff\jffhffigff|cffuVff fgnEuߨ}Sr8kpRu%x0@}8́Eބ\~{Ìzwbzyw\w[y덙zy.u~m.P)A3_jg"nfGsfgf3off^rf̈́ftffwffWzf|f{f0{f7flwfVfftfxfrf΅fqffGrffTqff;qf`fqfefpf fsfT^kOe&xz~dā΃Q~Ɖ|WM|狙{z/z֋{狙{{x|]}|}c}py3zׂԇMt4ъaVvUg6(f flff%vffOwfƁfvf5fsfNfgrffrfUfpf@fXqf fqffAtfftfftfbfwtffufCfwff~f$|f\yfftffqffjnfRfvf:gfgql^Ė) 7(/Rr㐙xۍ-zJy,xzwُxy`x@wx_}:⅙*u5{4xONvsoJwB_7Gg fIfTf{fdff!jf΋fnnff%pffPpfCfpfɇfdqf$f'rffTrffSsfyfuf8fyf|fu~fxf-fvfFfsfɆfnf‹fjff*efNf^ffVffmfpdel)=ΘHͫyeٜm̗1rsْyuYwҏdxx/{3~b%hd~}ыz(z^&w*r嗙mi,bM ʙ֙صJ4F(f:6ff Sf'f _ffQffffV5g;> ~]cdnᕙtw y&f|uz 9mȁ$?҇>~ي@|zyϏvav*vtQn2eFGaffdf3f}gԙO] YugCffwfv|f>}fS{f|f }fzfI~fyffBvffdtff@sffrff1sffgrfffxsfftf=fsufnfvffuff^wfhfyzf|f~fwf؀fwfK}fHfIfdgZ2Gٙcb]yA{ʋ |Q|{|y玙xTzvZwyˍyhyR|R@r{N}ӊ{ggwCvd9AˠLkMgFfʯf]fDf kffpf|fpffof}fnffofՈfpf}fpfvfosfhftfbf]vf؀fwffzyfs}f`|fyffvf/fqfwfoff)lf)fJfffybfff{b7) ˑWyWF;g[prtbuxƎ1zwmy){|5ǃSa|Ċ}'k{wtyo雙 fAYu&,WSӃއ?}J|d{=y Ov풙rniGc.Fh \$'Kd|ff\ffdfCfhff}kff5ofLftf^fxf)~fzfO|fm}fyf,fwf4ftffsf\fpffLpf fpff qffmf&fjffkffPiffZfBf fgH\䮵0~xepMtxG|/߃څ12~|^@|{Sydww_x:y͍zsx7rZMVN- M9])gbfkyfYfrffsff2wf~f|fTzf\fwfvfSvfԂf-ufBftfdfXtf{fsfDf sfqՔu *wy|{ ~݇[Ԅr҈'~n{ xatqؗnHUja CGTܙY͛Dž 0veJfbfuTffQ_ffUhf,fSlfىfnf fpqffgtf@fwff yf|fm}fyffwf́fvfzfwufftfBfqffmfˊfmffkfčfhffbfmfRffZ f;wgAA(.vueh/o̕s[vP1zʋ}߇Mmꂙ7l}*yIw,w'wkauђs?qꕙaqR1ksL2ߡ`fyfmfflffofwfrfpfwf?~fzf|fD|f|f+}ffpfefQpffqqfvf tfftf(fsfuf\tffgsff#qffVefffgWQf?ZØѤւ |f{w~χ+vF%}܊u{ݍyVzU{挙zэmzz7z/>{7}K~腙' lə k9WՔgV6ffytf~f{f|ftzf9fLufĄf^sff tfȄfqfOfcoffofֆfhrffrfPfsfwf}tfkfuf f3xfO~f{f{f}fyf~fsyf$ffsff5offif fcf)f^fJffPct$/B/cQmq5Qs?v x{X/|#}}F݅FG8= |/ywupSrZm&cͫ_RvoGgc8fv$ffPf9f,^ffef fkfflff mffofGf{sf9faxfPfyf}f|f{f~fwfftfHfrfofrfنfoffnffjffpfff&^ffOffff^:#rƚ`W)d\;kmTq [Ng|Tfffufҁfwf~f{f*|f}fHzfxf wfftf‚fufftf'frffqfRfqffYqfXfqffasfftff\vffjxf~f{f{f}fzfyf.fk?fLg}XiY^V͙kΌ+Jo~|${zՍYy΍yFy荙 z̍z錙Wz񌙎|щ~RH]<Յ뉙b|1z5՘ c!IPrgf?faffof؅fgsf=fqfŇfof"fqffqff~qf?fpffErff?tffufԂfovfifyf|fe|f{fZ}fyf|fufŅf6pfKfmf}fRjff]jf܁ffJa&a<:JKlQ,tnt|sxt瑙)wStx{yzr{2{e~^u}Y%x𐙡u9rmecalؤ@XgfSftRffbffhff mfjf nffnf؈f7qf*fqffsffuffyfo}f{f{f0}ftzf~f8wf\frffoffnmffkf9fngff}affSf2f!?fe+/2kɒԙIg`Ikk瘙rÒuvːwHBy|~Vl܄>(u|܌AzuzwytxRrpkJb讙FP+d'afOfIVffEaf̒fhfÌfmffof"fprffufρfwf~fzf|f}fyfSfxffCwffusfDfof͉f[nf‰f9nfŠfXmf!flffif fbff-Tff f gwoET7TqymGrux쌙9|,/j~y~ |g&{yyȏu1uǒuܐvgsmâQ,𐲰x2_MgfofqfЋf4lf!f)pffNuffyfE|f-}fEzfMf%xf]f8vfftf&fsf…f\qffqffqff]pffNqffsffufWftfSftfpftf…fkff&flg:@Tk>y{Άgm؂L^*=Mp|B|Q{y zs z^y{zʌ{.|ԉ~{ƃ̂tNߋJ$+xUgt*fflf5fuf4fufЂftffttf~fsffrfPf"qffpfFfqffsfftf^f{uffuffhwf}fyf(~f{fKzffOvfzfrffqffvfHhfggo^ n '[7SPqڐ/yOyxx⎙x|z@zSzJz6{|~D~7;L~TyPu|trm}w5CM9GUgffcXf fehffrlfflf=fylf!fmf1fofhf(pffIqfftffxf~f[yfi~f{f{f%}fxffufkf?sf1f#qffmffiffdffYff,of qdj)˘E®bȟ-kprsFesˑvV\{؉' 1}׆UAވ0}yBtVr_Ap՘lÞbˮK˙֙i|L4-'fo6ffRfڞf{^fJfedffif@fnfTfqfKf;sf|fvffyf}f{f|f |f{f}f}yfLfcvffpfƈfofff'^eŝvmPrLv$yt|5cyIl{\zz${0z׎svsӕ2pLsngIGy<a׼f[fffOfGhffskffkpffrufgfxf^~fzf{fL~fsxff&vffufBf|sffrf&fqfPfqffUqffpf&fIqffof fofflfBf`fffTgNi^xqz5z"}h2 ꁙOˈ}`{y{xyB{@{Ӌ{u{-|J.~r{Ǒe.ՙO2 YqgFff|f-xffyf{fC~fxf ffxfefvffHsflfpffpfɆfrf|fsffrffqf+frffsfۃfauf@fxf}f|f{f}fKyffyf9|fʆfLfagZ'\ëcCܙ_+y}Lz}7zUxty_z⌙z{C|I{zk|~PeGH{y܏Nxk̠lMg ff\fqfjf fmffmf4fkffymffqffrffxtff)tffxtfftfYf@wf-fjyf;}f|fyffCuf~fsf4fHnf6fkffefJf{afsffH}b* [J"h1p9rtPcvv\dw!w[xōz$0~zdQ}zxfquobjBc!Zҝ'*VԕStfEfnfˋfiffdff]fffc$3EnemYp!JsGv=y{닙||P K'Èb~#|狙z̍Sx[sl%cxQmV_8ffofaOff_fvfhf[fif-fnlfgfpof܇fqffsffwf~f{f|f{fV{fj}f)zff(vffvqf݇ftofXfpmfffqkf(fhf feff_fܜf\Rfbfffb:\ȚʫU~dm1q+ux`E}[~>V0V|{'yvMu,rbo7lOe`E7mM"cfzfzafXf.effjffof*fuffwff>yffzfR}f{f{f~fxfftfgf&tffsffrffofˈfnfEfclf8fZjf fkfCfjfdf]fڮfmfEgKyqbcux쌙(}凙dკ8ff|z4iygxty z~zFI|v}Ҋ{g{OzuZ [-7 m[?Rg PfDf{}fdwfȀfExfPfyf6}f|fyff$wf߂ftfftf'fKtffVrfΆfpfˇfpfqf8rffsffvffwffxf1fexfFfyf~fyfftfܐff2rffAofŠfkfUfhffafMfnWffmfsdh)ɘoEzc,kHqtvwz/|}&$$r􅙻}Avx8t2rBrkaˮKA˙֙:J4+(f6f۱fSfKf`ffef fvjfYz]짙+dl4s8wjy ~|06~6i+9} nzɍymzލLx+yvuYsؕp;hJHahff,dfNfVgfՍf mffpffJsffwf,fzfz{fX}fzf~fwfftffWqffUpf*fpf fofpfnff+ofUfqffrffrffnfrfvbfffgpNiϑBxЏx {y~ކ;s4Q׈~7{`y'yzOzSy䍙z zE{{KD|%zUeԙ'Pއ6YvgAffwf|f|fzf}fzf$}fT|f5zffwf-f6tf7fqf{fpfÈf+pf{fZqfJfrffrfȅfrfftffxuf?fxf}f|fYzffwf fvf}ffNfag}ZVsEۙ`$y~|9|{zez1'yQTy䍙z׌z{|5~z~z{KzTvvLΑfɠ'hMgf ff^fnflffNoffwnffmf[fnf$fpf9fqffyrf:frffufNfLxf~f%{f|f|f{f}fzf}f$zfZfwfaftfJfnfɌfffcf_f֑f0fb<' hFXAGh֚o2rtkuS+u|^vy(}?8ME~*~ȉ%}z7w|s6lmbx|V$XRef*fifHf%lfflfHf mff"off!rffuff1ufjfufӂfwf#f{fyffuffrffiqffoff#nfPfiffhaff}TffSfH:e-àŴ!䙡Ea0l\oE!sےvw&z싙~ꇙÃLf~뉙t|(zxvsyHpk=cQHۙWǵ0ȑeGfͮfSff`ffwgfflfψfqfqfsffEuffuffyfj}f|fyf]fxffwffufkfsff{qffoffnffjffhffcfXfhSff fxgQA0(۹uyvce坙m;sr{jLK5韵%`{fe|fWkffdjff\of%frfqfvffxfO~f{fzf`~f(yfFf`wffvfFfrffupfֈfofefofχfpffHqffqfІfqf…f@rff4pfBfffǤf7fXgQJf?˜t}v}A[z]v~Jr|~{Vfy9exzl||銙{{Ɗ}؀%Ac(덙8kədj>;-WБg9fftffJzf}fBzf@f(xfbfuffzrff[rfԅfrf fqf@fpf&fqffKsfބfsffsfufvff^yf }f+}fTzf~fg<\ Ue5 }f{/whtPpkbRʶoϒb8f%f|fEQff_ffeffkfsfOmffnf}fqff[uff4xfX~fgzf#}f~|fzf~flyff[wfyftffqffoffmfgfnkffff'fa`ffQf2ff{fa:{"ƚR¬Xbjqqa#uSwJy~/ ~#}&zAyoxwsPFsr*oۙ i娙HnN!"b cf{f^fїfocffiffoffsf f wfbf&zf|f1}fzf/~fyfBfxf f^wffsff qffofÈfnfofmffmfĉf;nffnmfvfOhff\ff fgK{a 됙%tvt{8{a\Uބ|!=Y}7?{xyGwwʏxߎyMy3z݌z|x_ޙE<Q r[OgSff!fwffxffxff}f:}fyf%f\vfOfuflftff[sf f sffqf^fpfɇfqf&f.tff,vffqvffvf)fwf~fX{f{fU}f6|fvff 6 }y珙#v璙Cseog6bJR@.[g ffPfޜfbffhffkf0fnnffpffqf…fsffvffwff,xfVfyf }f|fyfwfnwfrfzsfsfpfif@mf$fifXfgff(bffUf:fAfje/2k\ԙGI`h~l(p u]yy*|s怙UၙڄI怙B|6wܒsts͕To~jA`_E~å+YdafLfWffrfftfyfdxf~fzf|f{f{f~f!wffsffrff rf+fgpf9fdpfCfLrff'rffsffsffVuf?fufxf=uf`f6lffw&fag)?TmyqO}ƀꈙS /~z8|܌ygypy֍yLwwy|I$~1샙@Eav+@@xUg+ffmffufKfufʂfufjftffisffrfȆfqff>qfsfpffpffrffuf#f,wfvfpxft~f{f"|f|f{ffvf fqf߈fofRfufgf'gl^d6+%_T9=qR0uvސxtyzҍy7/z$zx\zz|:G텙%.|}xlzwבAsymǛ vC17E!G)g ff0VfXfcfxfhfڍfKlffnffofˈfoffjqf9f9sffjtffixf}f3{f2|f|f|{fr|f,|f}fWxf2fYufOfnoff4lffgffHbffXffvof]odGm).l͘}꙾Gcݞ]kߚ>no q딙s֒vyI{?~ z̅1~|x=wtU5p-l蟙a<K Ιeә^˗H4B*f5ff]Rff8^ffYdffkfwfpffrff2rfGftfځfxfU|f}fozfo~f?yfkfwfTfutffrffqfvfpfefwofflffgff`ffOfVff7g9> j.1^e:nŖ%s蒙v5y팙|܈%~փxXچ3S~>|xoxMwwMs.rsoTgYHtGHJYa\ff"ef=feff`jffpffuf:f"xf}f[|f\{f~fyf~fxfʁfdtf/fqfpfqffpfYfqqffrfVfsf„fsffpffnff~kff^f4f$fgFNjf]w_x|uM|)?|JRzPxُv,va1x+z挙{j{|}.~{Yfuԙ2QֆhYugCffyfyffZyf}f>{f{f|~fwffbuffsffQsfbf!rfofpffoffpff-sffuffwfRgOffYhffsffguffsff2rffGpff^offHoff#qf:frfdf@tfsfCtffuffvfȀfxfq~fo{f`zfffgxffuffoffjffMnfvfmf_V<4-:OࣙLl/Eshvِxw8IxPy>yyD"yҍzJ}~y%]󆙜ꉙ[| yPu|o ioje }݄Cg[ fIfSff+cffZhfflffnf)fpffpffrfYfrffvff yffxf_~fhzf|fJ}f\yff$wffesfنfGofKfkff,eff]ffSffTf7e:-ŀ$iFH_,jnbr~uz{ džeG؄$뀙sQ~K|ry;wrs}'pjܟaGۙYt 03eHfffWSf f`ff*gffkfafmf fBrffyufufwffyf|f|fzf~fwfWf'vf]f+tfafJsffqffVpfdflffkfTf2hff&dfəfTf=f fwgA(۳vqtkf:gm:eruŏyr~3Sq̃^%ʉ}Š{܌lyw䐙Gv␙,w3#xpAw.upjM^2/`f0|fkff@kffrpffsf"ftvffjzf|f}fzzf'~fvxf_fuffnsffwtfftfWfsfՄfrfnfXofUfcnflf?pffiqfhfsfbfpffefåffgoQe@n}H|~d#$~ӉH}{xxw菙wxZzj{*|劙}}]m@Ǚ n\7g\G 1Xq3k䙁[!*vsyQ9zz͌#{xwxxӎyyN{4<a#=ۉ{!w:t&sޑȅS^`^Jg ffu[fWfhfcflffmffmfԋfkffjffmf8fqfJf^uffvffwffzfC|fP}fzf$}fezffvff6pf fbjf%f5ff!fabffP]ffJfc $x‰rF̬dٝ+mZq3r *v-yэzG"|3}g~:т*};ziwkntpkVd#TpTb8lf%ff Qfaf,_ffdfvfhfPfykffof̆fsfтfvffQyf~f{f |fx|f{f}fzfO~fwf(fOtffVrftfpf fpmfKf\if~fafff`fRfRffff b: }ǚ8Slb򟙀kGpYs!BwT{A~G%p 큙o~Y|dfiff\ff f\gKy0 esuAze}Q|!Z~zCyC=z΍y㍙yQz{zUyv{zn{fv\uᙄ:[ [OgTfffEuf&fwf~fE{f {ffvfftff~uffufofuffqffpf$fGrffsfwfsffrffjsffvffyf}f{f{f}fzfxfrf=fg*XQY^/Ιȉ|bN~ʼn|z9{ {ŋ{Ay荙y퍙zN |{&{~Nρo}`yM{ԞԘkcDJPgsffddffpf$f\sf)frff pf'f?pfbfpf҇fVpff=pffKrf fsffsffvfyf[wffzf_|f}fxfdftffJqfnflf͍fGhf?fkhf"ffJa`=9TJk Qrtǒu~avÑuYwoy~| }}2S~ֈw~Ċl{͍x upl9h:e8}]@!Xg ffOff`ffnffnfrfqf߄fjuffxfk~f#zf~fu{fo{f}fzffufJf2sfjfpflfmfތfiffffГf`ffSfTfj@f]eP22ɗMҙJJ^Σg3o$sݒuwD|ӌDz 0yv[rmnEjWbLEGkBʧ+zd<`ffUff-`ffhf4fmffqf ftfIfvffxf[~fB|fGzf~fxfyfQvfZfufftffqffoffdqf‡foffrlf'f&jffeffTfffg\lE Tqݝkqlv׎z=|bԃ偙~@|Jz) zz2{PYyg~wRvv̑t=nO(Q Y7_EgpfXqffofyf~fryffzuffqffmfȋfkfDfiffeff_f)fHQf:ff4g;>֯)]f*mjqU[ufwff>tfEfsfjfIsffrffqffeqf foffnf܉f)ofqfofىfklfɏf_fDffgNxhʓ9yʎLz鋙V}#%e}T{^yyюw>w6woy)Dz*}~)?Ј }OzgәPi YsgDff_{flyff,xf~fk|f zffvff1uffftf?fsff@rffsqffpffrf&fqf)fwtffvff|yf~fyf}f8{f{f}fyf~fzfzffKfncgZWؾG1ؙdayp+{;{{{15{ތ5yʐug7uGx㌙H|*|O|~چڄdT~ˊN{VNws ]*ɠ#ekM-gff_fwfmffpfSfpff;qffqffof3fXofQfqfфf9tfftf+fvuffjvffRxf~f^{fzfYfwffsff[qfЈfMmff$gffjaff$fb% pTDgr1t uEuTx]{{ތ {y{‹}'Vwdzcv)rdp;mZe~|ߋz#y WxnyC7y6z猙{?|t}~x„c~w/~Aj|eҭ3**SRg ffjf9fsfXftf&frffpffpf f?qf_fqf%fwrffrffqff rfSftfӂfwf~fzf{f}fyfQfvf܂fsfֆfof)f&lfhfnftff_)g._%Q롙n甙t䒙Zuʒt@0tuڑvx0{ÊQ~퇙ֆꁙJ 4섙I ~N{fpfÇfoffapfȆfrf.f(tfÂfwf fyf|f}fyfRfxf\f!ufftfӂf}f8Yf.@gt\- 3U+5_ZTft)yz {>Eyx-w&vw؎zY|*0LJPQIۄЀoI}䌙y:KurGn[ [J g ffYffgf:fkfflfffmff~nf5fpfӆf?rf3fAsffrfftf2fwffpwf(fyfD|ffufUfqffof݉fkffhffdf#f _fffc$PGcWd ko–UrȒBvאxBz|m~‡끙?aYfI~z3u|o,Uk%!dR9n2a8Ψf "f#fMffF^fPf!fffkffcnf׆fsfTftfRf]uf`fjvfTfVwff yf}f{fyffyuffqfjfOqf"fpffmf6fififff%f8bfΛfQffff ]:%ĚᮙRobl{qu,xލ{VIӅmЈP~|{^#{Pxyxvw`tʓqslpҙh쩙FwmM"wcDff]]f@fddffjffJoffqfftffyf|f}f.zf~fxffwfʁfufńf`rffqf.f qfBfpffToffmf:flfflff-kff\fAf fgK{q aMv~Hyb|≙) R႙gĆ+#Zs|Bs{zylz z{x+ xyy鎙wv-\)♶9 H[`Rg.Qfɂffvffxf+~f{f{f'}fOzfEfwfLftfރfXtffsf'frff qfNfrfՅfrfՄfBtfftff\vf foxffxf~fAzf}fl{f}fuff;fgwXɈZu\lЙg@| ~~{`O{㋙||Nj|yUdyCyxz?|}Ԉ~tc~~{{qԘcdKPcgf{fNafʎfmfLfqffrf{f-rffqffoffpfNfqff{sf ftfBftffuffwffzf}f|fyffuffqfKfmffhffrhf΂fef'Jab<9p[I˧jtffDrffNsffsffrff,ofrf.lffjf|fDhfcf9dffUff fgoE0Tpi:spGuގ}z⋙}򈙣ᆙ8Zb}뉙~~}늙|xKw3vÐvɐdwbv5:t$Nm6P)O5_gCnfsfPfrofKfqffmufofzf:{f~fyf>fwfUfwffxwffGtf.fVrfpfpff+rf0fnrffrfȅfWsfQfQtff2tff-tfbfrfPfjff%fg{>T{l8ųFz႙4Lsӆ{}މ}}v|L{y{mc|zcwk6xyz {~ۂ/)`*tƼ $wU|gH+f>fnffufsfuf4fufftff|ufUfStffrf6f7rf;fqffqffQpffrfofuff`wf`fyfE|f}fyffvff+tfdfoftfufgf[gl^Qg9+ύܑ%]me3mHJt5rx{H}~o>~w`}C}{썙wÑtsDas8t퓙q9i姙IKEIuhaüf~ffffgffjffoff!vf{fwffxfF~f{fMzfzfwfftf frfNfpfۇfqoffhpfifoffpffpf f qfʇf2pfPf mff afNffUgN k푡$%zyߋ#~8Ii3ډ|R=|}-|1zHyuy2?zw{{d{򋙦|É͈|eՙqPiY.tgEff${f&zfz~fzf_|f"}fzf~fxff wffuff"sffqfifqf$fpffpfڇfpff{qfpftff_xf~fzf1|f}fzff$wff{xfW}ffKfbgZAEٙc{{扙c~rz}|${댙9znwwff4xf>fqfpf1fgVy!|q<3†È+_~JK|w{zny؎bx x뎙yčz },nڄ32~)s}'zR=gfFfifftffufftf[fsffrffrf|fGqf݆fpffpffqffsfCftffvffOyf2}fm}fzf]~fwfftfބfqf fofʉfqfsff_**OL$lr#!tYcuTvcx'byy"zČA{|}䀙QĀ~VD}yr`\miݟ\ld{ݔCgfXfSffefhfjfTfjfflffoof0f8qfGflrf؄fEuffvffwffxf~f{fzfW~fNxf@fvfPf@sff"qffmffiffu`fxfSf7fxPfjrӖp0nfxf~fzf|f{f|fs~f)wf fsfRf{f[f{Jw{ی zǎjwtsWplm͝dXHF'fnL"1cfuf;bffdffFjfRfmfjfrffvffvzf|f}fyfNfwffwffvffDuftfrf`fqfCfoffmfΊf?mf(fmf\fnff|kff^ff f gKdyS7 鉙rsj1yV'}f~j D~I|}9w{Ǎzxcfx?xjxx;y썙z⌙{r}݉E{˓Ja+ޙ:c [MgUfnfہf7uffwf$~f{f{f}fyf~fxffgGpEߜSr k$qu{"}y>~F~ʊ{ĎwuMwxy,S{w_x`tFlhO|( 6_gqfqffofKfZsfCfwvfTfxf}f|f{fHf/xffkufBftffrffrff3qffrfޅfrfnfrfffrfwf`qffpf!frfftfflf,f&fg@Tj&C}xԃRPx⃙W~̉K}犙{X{{_{틙|Z6|#{1z^{z|| ~R؀]Rv_.xUg-f;fnff_tf?fatfftffEtffsf҄frf fsffPrfυfIrffqffqff!tfكfvf^fyFxv)xwy}{|}剙~툙*eˈ}i[zvojbuC6GgffUf`fefflffmfZfnftfoffqfЅfsffssffWsf˄fDtffxwf<~fw{f{f~faxfTfxfyf=vfƒfqffYlffgff`ffVffJlfIsdh)˘N왧Fnel\q-TuvÐvmyz }J備t}4z{ jy w瑙rpqޘlٞbJ̙!֙lI4*f4f8fPf^faffffݎfjfuf5lfΉf^pfftfفf?xffyf4~fzf}f{fb{f&~fxffbufnfpf^fofֈf|pffaof-flfȍfhffvaffNQff-f6g8>^’\Bf}m=rIt7wsza}Ɂ"\ }yxnxHwߏ,w@vumuJrѕpg䨙JIs޸daMffffÑf*hffImfKfrffuff{wffxf}f{fS|f?}fbyffvf{fxsfMfrf@fqffpfIfofZfoffof׈fnffLnfŊflff%afff5gcNThy昉وyOxf|dF[ꃙ4nf}g{QBy"QxRwyyÍz܍y${3|~݀N}( eՙO Y[rgmGf\f|fyf~f {f/{f]~fxffvffsffrffgsf؃fUtff{tfτfrffqffrfrfsflfsffvff:zfN}fzf6}f{f{f}fzf6{fWfLf`agsZEëCtܙ `"Lxr}|?}ъ|ƋAzx4x0AzЌ{{|5}x}䉙W~و,4lG~E${x~x;攙p͠lMcgPfįf]fMfXjfߋfomf fmffnffnfffof fof fpf2fsffufKf6vffwf:fzf|fX~f xf5ftffsf؆f pf?fkf ffffrcfkffzb:+ s5Z]G$eFnޖr֓uuDuKVvwx獙jzj|-yqԅ퀙{}4zrx-.tҔplkpcJZ*T)UԂS< gfftOffaffIifftmffoffoffpffmsf܄fsff"ufCfwf_~f{fzf-fpwfjftffqf"foffnfflff.ff2f^ff#Of[f*fImfY6 D{™N'ck]orx|~E2UE!{Ìyvdx󎙚xߎx&urn_d\FhĦ$'dm{f?fh[f:fbffhf6fVlfYfnffirfdfvfdfzf|fp|fWzffwff&uffsffpf$fnfPfCnffhmffimfʊf_nfflffhf{fWYfDfp fgHĜ/;~RoRqDw|{d,}rc1}ˊ| |O|ywᑙ}uvyaxp.w7qV'ꙟ.$]-gS_fzffrf_f,tffxff@yf}fw|fyfĀfAufxfsfxftfςfJuffsf}fqf݆fqffqfˆf^qffqffsfGfvff\yf~fyffpff1fߡg:Vaw;%y,ÙrpA d6gфr]}W||ыz>xWGxxC!yԍ0zƌ|}.…=^n }ى~4'&RgS!f/fhf1fsfTfsf3fqffoffqfɆfqf8f&qḟfqffIrf1ftfKfsff vffxfx~fzf8}f{fzf fwffsfօfpffmffnfUvffB_ńA.OP9n-t x%xԎwxNuuxv\vxzϋ }r~Ї__|7Cz_=x퐙t۔q˙jpmc=|ݶCܒgf,fRf4fcffhfώfjffkffoffsffHtfRfTufׁfZwffwffxfV~fO{fL{ffowfbftffqffoffWlf֍fhfʒfaff!VfBfTf7e-P#Giclps3Fv2Sx5zz{~~Q+^~zwt֓r+pkҟ}b<IۙAY(ǂ 0eFffPfٟfL^ffZgf@f>lf*f=ofևfrfftf݀fyf~fzf|f{{fd|fz}f"yffuff/sfƅf/rffpf҈f?nffmffkf]fhffBafqfRfPf fvgAr'vte䣙/g\o\t͐xoz6}'q~&0{>zXzŒR{ЌyՎw7vِwvskfej02 әJc柙jmqNuz|"}҉~f'SW} /zw-)wov7;tT.r_jmKc|EQÓ+d2af6fRVfHf1`ffef̏fkf]fnff5sfsfuf܀fIyf}f|fzzffwffwffufЃfsffpffpf̈fYnff:mf׋flffajffef{fTfff٦goE`S(qEj(p uCyW}0灙? ZĉG}{ZztxMv\4x⏙bwH w\wuSnQV+i2_gnfrffkfSfqf{fxf}f[{fu}fzfh~fT.n>Pp{ >3T*~=1|{~z֍xx썙zz.GzA{j}+&vɂwɍ=zwUg+ffnfftfKfuffwfcflvfHftflfkrfĆf[pffqffqf>frfʄftffvfˁfYwfxfwftfuyf|f|fzf~fmxf$fvf>frffwfhfgo^#-*홇UrwS=v+#t t uAwݎ+z+{ꋙE|{o~ℙJ9nF4~D{qu>q͘mSKx]B6R GKg fLfXff`gfflf#fnff nfXfcnfډfnffnfRfnfNfqfftf}f0wfgf{f4{f\fWwfՁfuffsffpfflf#fwifБfaf#fUf˦f jftd;i)˘왑E,*bpwlnsu@vQ6xzA{v6|zi~n}܋]zx6vPu~q~kVbkffdhfՒfvafmfQfbff2gU=>3ֹ]eHz0z:ywv xʎz3|^Ç.lAR|yޏu%ulʠ!lMFgmf٭f0_ffmffeqfUfoffcnfӉf off|of߈foffqfRf>rfftfRfuf؁f9wff{f|{f=~fwf(fktfӅfqff0pfDfmffifۑfdf֌ff|b3( -WnDϬ8e ngs󓙆t tw xQp|~+Ӈ!Uׂ݆~7{эxvQqqlf[֜,(5WpR< gff#Pff_f4fdfrfEiffSmfyfpfqf6rffLtffpuf[fwff=zf|f|f~zffvffsfNf'rfmfnffkffTjffhf͑fcfMfSfuf,fkf[6Ͱ™N@G`h]nusّxn{Q}4톙 ~W=|* yrfۄftfDfuf=f!xft~f}{f{f~fwfׂfsf_fpffofڇfqffpfufoffnffnf؋fIkffbgf&fXfڴf fgH0l17}A.nps\x||b~ynX燙LD~|Ōy]xOx᎙x|xwCw#gwsJW陭-]*gbfxxfpfqf܅ftf4fdyf|f ~f0yfOfxf fxffUwff tfńfrfdžfqfԅfqffXrftfqff:rff tffufHf{vfXfvffwffpfAf0fVgVwI$|zÙjoƊf+y’nWU}䊙U{y6y錙zS&zz-{|];{|aH~4|dp~୙(&IRgg.f}fhf7f.sffztf߃fsffqf߇fof|fpffqflfrff]qffqffIsffcvffUyf&~f{f{f|fzf~fxfftf0fpfWfHlffpnfvff_m-iMmMKuutt)Qu㐙w|ixsy]{ ~(؀݆\ t7|ÌczACwqgjJmbXlzݽCcgffOff,`ffgflfmfӉfof}fBqfYfpffHpffpffQuf4f)xf}f{f2}f{f {f<~fxfrfuff@rffnoffjfefeffP`f˜fUffQUf7ey-ŗ$F쯙b蟙jn×Gqz(uRXx{_|,F~ÒcNс0O~{oYyxAu哙rѕpiliaG#ܙ]Y 0*e!JffCUffZaffff:fRjfČf+nf6f>qfZftfWfuffxf}f|f4{f~f xfʁftfJf tff?tffAqfBfomff>jffjfof)ifyfcfofRf}f f9xg|A(twsfעMgls{#zЊr~ ]O1,ՉN|y,xEiwSvt tssle N3`{f|flffrnfWfpf}fxrff7uf€fyf|fq|fzf~fxfɀfuf9ftfHfXtf+fTsffrf fpffWpf݇f qffrfOfqfچfqfÆf5pf8fOffffgQe?[Ø! ||މ*肙.}؊|{z{ߌzxvtxmr}͇0Ă愙鋙lə;k9WXgE7fՑftf~f5zfifiwff`vf1f#vf.fEvfftffRsffqfftsffsffrffsfʄfysf[fufWfwwf~f{fJzffwffvffvfdf7fvXf?gH\Q Wv3䙕[txR ze|zS#yw֐Zvܐv^`wSyc|+*~;gꆙ䁙 ?ᇙ|ӌx?t╙p7]3_JOgw ffp\f̒fKjfkfzlf[f/nffmf@fmf+fofۈfofSf2rffTuffwffyfY~f5zf?~fyf~f:{f{f~~fwffouffpffif^f`fDfYfkffϊcE$Dome$pJXsK>stvNwA7z~<2˄)G~y{ꌙyruQpjbQ o.ud8fi%ffNff=\ffcfEfhflfomfLfpf&f`tffDwffxxf~fzfx~f{f{f|fyff~vfTfZsfofpff>nfftlfvfkfԍf1hf̒faff4TffCff_:b#ҀŚQmSN`̢hposˑw{  Z邙Ac8Ɉ~;}zj\x󏙣vt4-tq;md㫙'Gtp*KI"cfēfD`fffffkffnf܈fqf.f?vfxfxf}f{f|f|fzffwfftf˅fqf߆fdpffpoff nf}foffnf fnfBfoffkff]ff fJggK{; &䐙s̒Mv3z}ׇȄ؄ƀ 臙7s~B|⌙xSwv8uw.;y_y{5}Ӌfx\r8 [Pg/Rff[fxwffyfS~fzf"}fT{f{ffvfɂfsffrffqfKfrffqffsffuf*fLoYap|z|јe%KPgf#fbfόfpffrf˅fYrff^pffoff;ofYf0of_fof!fpfQfEsf~fvffryf}f{fe|fo|fzf~fxffMwf?fsffnffUjffiff5fIac?;:\I!iups}ssuv.wzpy|$~ ˀ.j\؈}5|sw?7uX(o|f(_Qr@uWgxfWfSRfYf affcgffajfȌflffnfΈfofGfqqfftf6fxfW}f{f3|f"}f#{f|fzf~fxf؁ftfyfTrff(qfflff$hf“f_ff@Qfqf:fe,2>)ՙJ*+a|j2oeRs wlzR}p]=n|z{ G't6+dQ`ffUf͜f_ffWgffUmffmqfWf!rf:fsfifHvflf%zf{f}fRyfftvfftfRfqfƆfVqfffoffmffkkffjfZfiffdfSfUff fgOpE߭PRryj›mst͏{G fꂙĂq|q|c{l{9sz̍zwyŽtxvTSwT/uǔnYQ+3_gpf~qf+flffpf_fttffwff zf|f}fxffufnf uffrffoffnfوfofˇfqf_fvsfHftffsffsf\ftfǃfsfGfVlff%fݺg>Tlxy/"{āL 瀙 8|ayz$|$|kw{ጙ.zɎx{ҊV~Ѕ胙ނ҂҈s܌ZvUGg *fMflfnfeuffwffvfwftff%uffsff4qffof fpnfˆf|pf{frf f]tff7vffyf$|f}fzffhxffvffWtffOsf9fyfdfgl^(Rߠn:uv:wƏMxxkyfxyɍzz}uځcBF>{Zy~vTCsbnwC6!Gg fpfnYf.fgfSfjfffjfflf%fof?fgqfӇfnpffDpfxfrffufZfyf3~fzf|f|f{f}fwfgfsf͇fnfʊflf4fSifqfaffWfʣf^mfrdj)P"ɘ_D;%a{Rkwps@wƏXy1{ʌ}||~WրՅ~ۊ{4y׎rw&vkqYk>`GuKU̙UՙfˡH4*f4f0fYSffw`ffgf4f!lfMfnf fofLfpfftff+yf}fZ{f|f|fyffwfpf4ufƂfsfff.offlf.fmfKflfufifՑf0bffQf֍ᑙ]fݝ lrwOzzm}Շ{⃙ᄙш}zތS{Uz\yBkwܐv!uNCtmo gGIH߸/afffffgfՎfkffpffrf\f:vf+fs{fyffwffvfftffMsfOf{sff|qf(fSqfΆfqffqfЇfofvfFof*fofȈfmff`ffBf.gNhI嘠zx팙Y|P$z~A}@-|{={`x)x+_xxbXxuJzF?}yM2|Ґe|ՙzPYY ug Dffyfrzf~fzf|f}f2xffcufftf8fufftff_tffjtfτfrfhfpfJfpffqf!f*uffvffyf|fT}fkzfm~fxffyf{ffHKfwbgZ«6C&ܙs`w܌l||W}቙}=x|yzBy#yx鏙NxpzO}Ո~HDž؃ځOT}`y掙w(w䋙-M'̠lMRgfcfK^f(ftkffnffof؈fgoffmffnffFofqf_rffwsffvffwf fxf1~fzfZ}f{f{f}fxfgftffqffkffdffaf̎ffH~bf' }Vk`E?g皙p: tYCu~vawxZy[{}q )Àj^}zuzoekd.[<&YԎP<gffQfUfafifgff.kffnffqffrf2fsffnufLfwffyf<}f{f{f~fzyf~fxfifvff6qf3fkffeffcff_ffQfϴf,fkf[6s0ÙM|bl qqsVvc{}~m܃H}'{ߋ^{T{ixmvtŔqUhk\cE𙅧忭&'kdn}ff [ffdff)jf$flffnf]fqffuffyf}f{fzf}fwfftffrf3fEpffpf8fpfQfofaflf_fmfjfkfJfhf:fcXff fgmH^õE1|SnrowN{h!;\mns}zN {~{q$zӎ/xwxww쏙fwvo`UꙠ,oKI],g&_f3}ffvffxfO~fzf|f?{f|fI|fzfn~f]xfـfwf?fuftfsfyfpf)f~pffrffsfofsffsfɄfsffztffIvffxff^rf{f"2fgJVw$ {-™Tqˁn&#WF~f}<{:{" zxRx_zD{}G쁙>ׇyɆ{zH^*TR9gWfTfhffsfftf5fsf`fXsfЄf9sff=qfDfnftfSofΈf5pff@rfff=sfftf0f[vffzf{fD~fxffvffasf}f&qfIf5mf2fppftfef_/+Ml͕\tJ$wwvGw}iwPyd{P|- }~샙܅L`|yz1nvGrjן0l9d|CggI fvfUffdffngfNf]if!fRkffmfFfbpffrffRtffvffwffxf~f{fzf1fwffuffpffmfafKjffhf'fbfzfXffUf}7e;-Ġd!DO `柙lԗ{rtuudxuj{{{R~t;x~z{捙x!wܑtDvqnpVmdIۙYHǷ 03eGfǯfQf˞f{_fdfgfrfmfȇfqffrffsf4fvfhf+{f{f}fyf~fHzfl~f xfɁftf*fqf]f~pf^fnffmfXfkfjfPiffbfҚfRSfǹf1 fxg A'vt@fhngHn)|za{ {ًzynxyʍzSz&pzj>z"z[vy\ 9 $[7SgqOff~fAvf\fvffTNkw0K`c>Y}Pzύhyu,wWwqyjzg|~Z;g&~j@҅ℙw'Z]wUg'*fgfnf=fwffwfrfŗ֌ZdZmsՑx֍}{󊙍}WfYmɆֈ`~̉{y>uwݐv"fpff\ofLfunffkfBfhff bffSff f'vgfA(iuu3e>h4o$ytXw:zv|*dڃ*~z}l{c{~xfw 3w=gv˒srHGqjzL3t]`fmzfmffjffoffrffufSfyf|fQ}fyf fwfԁfquf_fbrfXfrfօfbsfɃf|tffsffpff`qf$fpfYfrf#frf|fpf@fefץffgקQeO@I˜taX}y|`\~*솙n|R||{lUza{틙e{ό zx.Y{[~ƀHنi~3kəAk :Wݓg7ffsffyffwffYvffuf"ftf̄frffUrfbfrffrffrff sffwsffufkfrwf~fzfE}f{f[{f}fuzf~fPxffdwffff4XfS?g1\ Xd1Yt4yOy~xgw3w֏x y[z͌{鋙%|`A}}l{ĂRL{U~xs7yph !\ i^Jg f fQ[fof'iff\mffnffnffnf f;pf~frffsffrf"fsf}ftffEwfJf:{f{f?~f>wfVfuffqffnffifbf+bfaf[fffc$N]bCOdnrRsɒRuvx&}v}fZ~P ؆|]yu֒t,soejSn~1a8f#ffwPfOf^f,fXdffiff mf$foffpff\tffYvfIfyf|fH}fszf~fuyffwff4rffmf5f=kfflfOfif f5eff/af֛f TfMf fLfEa:>!ǚ{Uc=eɝm5qbtiwΎzz} ~^~|:xJwvMuqk ndeEnL؄"cf۔fV^fߗfbfŒf]hffmfʈfqfLf,vff7{fqzffwffvffwfhfufwfysffrffqfMf"pfTfy*z֍xy̍z匙{&|銙}|w<'_yߙ; [YPgQfԃf&~fYwffluffwfu~f{f:{f~fwfftffsff2sffrfԆfKqff rffsfvf=sfftf ftfǂfuffxf~fJzf~fyffuffF=fgXl[Zҙe{ۈ߀1s}\zfUzUyAzyyȎxDvz|cU{~)|!zZԘcIPgf~f`f{}}Ӆ:~%|_1x/v'^s t┙qi~lcFo>kî+dbffYffbffxgf}y|Uz yRw' x&Qy~zg| [}hmbtwwUEg*f\9\d͟4kYCqՓv>y拙q}Yiӆ聙aԁ7}~{_dzwzM%yxtrrphCII޸!manffdffcfff4lffqff?uffrxf~fzf|f|fzffxvfUfysff{qfOfpfNf-rfTfrffUrfxfqffrffErfGfXoffjff"]fffgYNh铡\癙yyFN{ω_eS~~9}{`x2wڏy닙}'K}I|w}.~}azcיMm YtgHDf@fCyf>{f}f{f|f^|f{f|f8zfVfuffqffVqf8f0rffksf,fyqf?fpffHqfAfsfσf~uf,f wf&fzf|f|fzf9}fzf}fzf,{fqfkLfPag}Z39«Dٙ^cwz芙L|Kd|{{Kz،z:yxwŎ#zKW|{ًu|~恙фʂuO{_}u~r'2[ˠmMgfԬf`f%fmffoff7of foff"offMof͉fnf]fMpf1f0rf~fsffvffzf|f}fvyfNfZyf~fyfp~fxffqffjff efݔf_bffef}b( aY[G3Yf= mPbq6cuڑvuڑuwz$~(o9v[P燙Z~Njzhv6sqnZd.Wѡ$X^SfFhf4faffVfCfTf7e -#♺FM_h盙nt26vlwy6|e%1!ꁙ}zx2wTuQoN5i&s^wF]ݙWX 0 eMJffTfffM`fUfef~fjffKpfxfsffBvf&fwffvwf#fyf%}fJ}f=xfftf_fqfXfpffqoffnffnffkf~fjffcf[fQfZf fwg]A&&wsgܡPiqtvy{~ʆӂGu߀^}z̍~yBw-ww吙vҐuڑaw鏙v`tjK18գ`f|fkfafkffDofŇf\rffvff@zf }f|fzf/fUwfftf)frffqfvfqf f.sffqf+fqf'fqf.fqfׅf]tf4frffpfKfYefaffgQf?2Ø58{_z}aM~}{yyAzፙyŌz V{ yez~>|b~W텙BCl%əl7Wg8f+fvfy|f}f|fzf|fMwf:ftfefrffqf ffpf f~zՎv&rA:]C !^Jg fUfYffhf@fmfyflfftkf=flf#f>nffZpfІfrfYftffkvffwff1zf}f{fM{f}fxfԁfntffpffmffifff:bf2f9\ff-fc$Ecmq&sג1vԐ1xzY{ ~fr~ {ÃЄ؁!}zgxs,oj dS#pJc8f[$fdfPffZ_fffffjfgf kfۋfnfzf>qfftffvff7zf/|f^}fzfQ~fyf\fmwfāftfXfqffwoffmfÌf7iff=fff`ffPfOfff]:$Ě묙hTઙden|rnuwyȍzg5}牙Ac~|szw*u Ju+s68qWle&G4sooK"Kc^ffbffeffhf9fkffpfDžfFtff6xf}f|fuyffufaftfffufSfGtfąfqfHfpfsfpf@f@of"fCoffpffofafjfƒf\ff f*gxK} M6sv?vm:{~I ɂ녙O|싙zaz5]{׋Q{zy)HyDxȍ{ }{Y5u\/.; [cPgSfff.uf fvffizf |f}fxffvfւfztfhftrffrfRfsfXf-tff@sfSfRqfAfpfֆfsfftffwffxfN~f!{f}fs{f|fvff>fgXoZ~]ϙhY~{劙_}(-}`m}劙||@z|;|3{0zz}-{N{L{bR}\u:%{x퐙Kx^לN՘dM LPTgSf&f%fffNpffXqf+fpfAfpfifqf!f pffoffof"fpffrf,f&tf҂fvff*zf|f?}fxffhvffVuffRtfflpf"fHifRfhf!ffIab:fe.2RՓԙ/Jί_inݕtKx捙Vz)){}LJbC3~4zVzxv[brx"pm윙enG癿󘀮^+d\ffRfRf^ffgf{fnffQrff^tf fxfL~f{f{fQ}f,zf~fyffvfftfftf%fsff[qf1fmffmffkffiffdffJVffe fg pE ߣiTaruk(p>Utz2~瀙=.~}}t{덙xnwΑuLw=xwmu┙On󢙿OlR*3_tgnfrff?ofzfrf6fuffGyf~fMzfW}f{f|f}fwfftfofisffiqfLJfof3f~nf6f;nffof]ftffwfrfvffuffuffmff&fgA?T{l\벙|ed|Չ}f}V{TS{{{4{Kz~x3xxzF}뉙}ڄxȎ%vU߱g)ffmffSwffwffwffvffPtfͅfqffqffqffqfCfqfنf%rff\{b;vo{k1AwB[7<GgffVf fffXfkf^fmffNnf7f`ofψfpffpf`frfqf!uffuffwf~fp{fzffwffvfftf؃frfKfBof%fUgfܓf`f9fWf_fGmfAsdi)`ʘ2\GRem#nq@ruwyЌ{-} ~^W]퇙~|_z?xxRuz q9kbL|˙=ՙEˑG4+fd2ffOffg^fqfMdfBf[ifŒf~mfψffqffsffrvfWfxf}f{fzffvffrff;qfrfpfcf]qfmfqffqfsfof׊fjffaffPfmff6g:> 1 \e|n@Lr=v؏z|މm6|l{{Yz}v)tƔrwrDpZh"JIaEff5dfQfYgffUmff"qff sf4fwf<~f{fzfTf/wfftfŃfsuffsff;vfqfvffwffyfK|f}f%yf,fwf}ffLf`gZt>Frٙbx{ɋ||lz?{{yQx>OxXyez7U|~؅?4}zvQuÍᐙˠmM'gSff_fdfnffpffpf4fkof*fpfYfnffmftfnf{fpfمfsfуfuffwfjfyf;|f}fxffuffsfhfqpffkffseff`fff~bj' XH=iGqݕzrUs]vw x_zr=}|ɀ瀙򅙏Ɓ냙XC{p*yvQtm eE?X&WԑR< gf0fuPfZfw_ff ef1fhf܍flf:f(nfvf@qffsf f vffxf=~fzf6|f}fKyfހftf_f0rffpfnfofZf'nfflfWfhfQf6af,fPf̶f*fkf[6 c"P䫙.dBlnq.uǐwc!y z }0]Ё:Ӈy舙R|~yJws错rqWem螙b3Cr I $'d*}ffZfљf]bff^iffnfvfqfsftffwf@fe{f#{f ~fOyffyfHfuf frffqffsqffpff-pf؈f?pffnfofJkf\f7fffkXfQf5 fgYHAq2}H4nms;w|2Džpl̆>{{z?wz+eyyʍy dxv"{wɏ!x동uZN癪.f])gBbfxf8fqfftffwffzfN|f}fxffvf fufAfsffqrfӅfqf3fpfևfpffqffsffsf˃f}ufCfvff=yf~fxf#fTpffe1fgEVz!~hq{d1r8.|Ɍy/ zvyxy%y7zz `{Z|0ᇙB!~ i{}Q}~*VRg ff,hf݈frff;uffsffrf"fqff qffqffSrffqf fsffuffuffwfQf#wffGzf2|f}fDxfIf%tfWfqffoffxqftff>_)>LƤ[l㖙sEu[wuxgy[yyڍyӎy{I%C^m↙~"}Jz%uNnnfUh⡙bje}pCՒgf0fTfvf\df~faif,fjfzfGlffAofRfrfƃffuffufGftffdvffxf~f|fzf~fxffnvfȃfRrfψflffhifefXfff`ffVffZUf8e4-Ŭ"A♀Hclљ6oCryu@:y||<~K耙P,}ꉙ|izwuipgjo_QgFݙcWP 0ΑeFfflRff_f9fhfŌfnffpffrffDuff9wffvxffzf_{f~fQwfsfksfDfbrfcfrf#fsffqffnfފfkffhfafcf؛f`Qf@f fxgA&xrOg裙/f؝>mrۑxT|CC}w|{C0{fsf,fqf foffpfԇfpffOpf܇fqffCrffrffSqff>pf]fdfff3gQ}bDDè~F|6|쀙# ~ }|=}K{jgyQyzCy{׋6|}n?tBxnƙm7W g7ffsffzfK}fzf~fwf8fuffHtfWfysfg\ Y2[|#xt{⋙{aykx UxxxSwyxP{"x}{~v<[W{`uyit-:rْR] i\Jg ffZf7fEiff#mffJnfPfmfFf(nf̉fnf%fqffsrffrfif9tfYf4wfPfxf}f|fozffSwffufyfrffamfHfyffMfbff]fffc$kDﭙdmqwtpw!xx鍙^{%}~4%4?~΋zd5w2tUqleSoRb8 f#f fePfpf_ff0gffjffkf flffpfftffwfgfyf ~fzf}f|fyfЀftffqf?fpfgf&ofXf+lffmjf8ffff_ffOfĹfff0_:"ƚVze8mmrUuwf{}ᇙK]Èb}OzziyWNxUrutXrhyof窙FnM/"cff^fVf,ff܎fQkffoffKsf͂fvf'fyf}f)|fV{f}fyf~fxf`fXuf|fqffrf'frffqff/offmffqmff mfNf1hfafc[ffu f0g>Kx 4t:uZy}ĀMU~4G}{_{8ydwgyf6zҌZzyz zՍu\Kw9 [OgSfffvffvyf{fj~f#yffwfʀf&wf)fvf)fvuffrsf;fqffsfftfQftff|rffpffqffvff^yf>}f"{fC}f|f|fxff?fۃg:X-3X1`U͙{iT{m~C}Jz4yzn|狙{p"zD zl|ʉC~쉙*}ߊ0}M(ETU{w{Ԙ eULPGg fЧfcf^foffof0fmffqlfifmffsnfyfWoffqf9ftff|wffwfl(m儙9 w꺙0zUkg-fZfof3fvffuffsfŅf-rfVfqfЅf!sfAfUrfvfqfofpfnfqff>sfftffuf,fxf~f,{f{f|fzff)wf fsffsqffvf\hfgn^E+>TOen Muvw[xFxwy+zmv{݋ }WJqcɆ8~Nj:z珙#u$nqel홙Ux_B{%6M!Gg ffXffffhfjfaflf4fLlfflfffmfΉf pfdfyrffufAfvfQfzf|f|f^zf~fxf]fvf,fsffnfڋfkff4iff}ef;f[ffFpfCqdyj)sYʘ1EaKmk or!ucw_"y鍙.{&~!2sS}/{SywtApijab CMʙ֙zqJ4(f]5fԲfRff`fԔf=fffjf|fnffpffqffsf^fxf}f|fYzf~f}yffkxfρfuf$frffpqffnfUfnfflf]f6hffaf1fQfff5g9>e\{Ge(n(pהuuz扙ڇjƃbK}(z5sv6OvuŒts2tǓTri{J J޸.Ya4ffdfFfgffVlffpfsftf2f+wffyf|f|fzfUfaxfzfwffLtf!fqffjnffoffpffpffofRfEpfVfoffnnfߌfacfbffgNi13vfyA}n~Yƒ~y|ȋ{ :{E]zɍxywy2{A{1{芙}{א:gҙR^YmtgEffy|fFyf}~f1{fA{ffwfwfvff#wflfkwfނfsfIfqffqffrffsfЅfrffsfGf{ufbfixff\xff*yf}f|fyffNxfY}f fLfagVZcëBܙ` ){e~Έ~|#qz퍙yюx⎙yꎙ4yyAySd{~ʇ݅SU=7†~Nxmv팙ʠ-kMyg ff\ffjfnfCnf fpfχf6pf‡fpfʈfoffoff9qffBrf̅frfftfށfxf}fl|fNzfXfwffLuffPrffnffjfҐf2efif:cffxfS{b) MZ?Ghۙ|qݓ u^uu쑙vv>x{3z* {1|3|4*}-zxJuypkT_eħ[!) TԏV< goffOf@fa^f˕f~efAfiffmff)of]fpfхf&tfRf wffjvffwffzfB{ffvffrff4qfVfnffmfBfqjfGfeef f_ffRff:.f9jf]6U TOʭca렙joslvݏy5H|M~1 0耙|]|2m|xyw tpn{l4dFF-?('c~ffYfcf`ffgfIfRlffpflftfрf[yf]~fyf}f|f?{ff~fywf{fCuf)f1sfdfhrfˆfqf^fpff'off~nf{femff@jfӏfeffVfյfE fgzH;W1Z|{ltrߑx{O~Ձ˄O~z[yBzYyyKyxlDxŎmz>{̋{=vtFV}*ZMP].+g`f-zfdfqf6f2tfɁfxfg}fH|f{f}fyfE~fkyfzfxvfiftf^fsffqfćfoffoffof{fqf_f4tf(fufρfwf8fUxffwffqf=f3fgVx#{@q_SeAW~}{یyEylcx+y(z錙{ŋ|%ᆙ.ԁˇ~aY~y6߬+Rg6!ffgffppfUfrffpfΆfqfdfsff)sffqffqf†f9qfGfpf:fqf fsf(fxf}f{f{fn}fzf~fxf)f%ufIfvpffjffnnf$uff_,-ONmsqw xxx#x+IxՏxiy {򊙻|Uj(o}*{^ws>bm5hBld!{(C=gT f3fSff5fff)lf֋flf)fAlffnfɈf0pff7rffsfftffvff^zfr}f{fzfj~fxfftf*fuqf=f[PNg'Uff&fBtffvfsfzf{f}fkyf{fWxfŀf{vfftfTf}pffoffpffqfOf=tff6tfftfrftff-vf&fyf|f?|f{f{f}fGuffdffnffoffnffqmf^foffqfʅfsf}fCrffrrfՄfrtfzf|f|fzff*xf2fxfmfluffHqf?fkffEifgfPfff^fОfwRff>fe02әJy-a&j֙pÔuÏ x\Ty zj }Jv҃L舙7|Py܎x$y͎xt@nqmߝdE_+{d`ff VfCfafffffkff^off4pffsfsfxf`}f|fUzffdxf,fQvffsffpqf9foff>ofwfnffnfVf`lfmf~jffffMf Vf}fc fQgnE`TqlqvVEz[{j~㇙?u}zsUy玙xw|vݐzvۑu)ovu qR)5_xgof rfkfRnf~fqfÄfuff'zfu|fB}f{f|fzf~fxf6f]tffHrf6frffsffsfXf sfefpf~fpffqftfUsfbftf_fNtfflf.f(%f_g>TQm̞\y8U`ȃ~GzHz ywzU&z{یyasyWz}~j99-uٻ݊#vUg=*f%fnf/fvffNufftfpftff[uff`sfڅfqfdfCpffpffrffrfPfsfރfuff[wfafxf}f{fHzf΀ftufgfqf݈f%off$vf$hfEgqo^_ (!T`qӑx ixGxvixrSz{g{{q{݋}c3W8Z;}`wzĎvYs?ioTyAq6 Gg4 f&fIVfzfdffif[fRkfόfVkfflffnf1fpffrffuffxf~fxf+fuzf}f{fzfEfwf]fsffof=fkff|gfffx_fIfAUfflfrdSj)Y͘H]e)^lpAt6sw9xz|[|㋙I|DD~}Ŋ@{xŐtꔙoiޡ{` L`ʙ1יʵLI4x+f3ffPf=f^ffFfflfkf`fmf+f$offsf+fwf~fzf|f}fvzff yf~fyffwfffRsfdžfhqf}fnffblf]fiffhff=cfƚfSfӹffy5g:>_퍛^[>b硙jhqӓvz0BI:ڃ`O~1}-|7{@xvUPtasI(tsmK>I@u#afpfaffdffjfgfofftffxf}f(|fzf~fxfofuffsf fjsffsf;f3rffqffoffpfՇfpffUofWfWmf=flfݍfMcfHfJfgNYg퓡ىSwOv{؅ꂙTZ;~$}{{I{g{)xdy)x-yGzi}~A|"d|ՙPae YCsgEfƉfyf{f|f|fwzf@~fyfGf,yffwff5vfftf_frf݆foff}nf.f_pffSrffWtfDftfŃfuf>fxf~fZ{fA{f}f zffxf}f̃fOff^gZ«D>ڙEc.~z݊o}o\|xzzՌzhyty򍙷yx"{({w}|y|s~tE+EQz]tett̠ lMgf]ff]ffPkffnffpfHfpf·foffaofbfBqffDsfqf*tf#fVtftfuffvf^f'yfu~fzf{f~f+wf fsfTfnffnifّfdffbffmfyb, ZG«rfpts2rtv7zX|}Ub~ꊙ {w#t,q٘k dZM!(.VԍSg\ X3䙴[7vƎy%yz*x_jxawZxy_z;zx=|C-~မ[ꁙ~ꉙ|lz\u|pS8] \JgfbfYfZfkffoff$offnff&nfԊfumffmffXpffRrfftffvffzf{f:~fyfwf5wfVftfLfCqfUf%nfьfgffbff\fffنc$0IfLnffkf̎fffCf^ffQffrؗk%_I,͙ՙiJ4(f5fOfRff_ffdfdfgfflffrfJfuffwfc~ft{f|f{f|fO{f|f}fnyffQvffsffpffofʉfmfڌf+jfffffr`f0fQfXff4g<>I\enLr듙u)x |Š}㈙f#u~ c|{f}f|f%zf~fQxfNf,vfPfsffwrfȆfqfŅfrf*fTsffsff[rf3fqfQf)sfԃfvf fwf;fwffoff'0fgVw$qz™p򉙃8'}~7|}Hz2xxG%zz挙z/z쌙k|SFc@~4|W b'SpRx~5xjwuJwuّ^vsJrkEzL@@1Z`fyfnf7flf fnfӇfJrffvffLzfd{f8fxfDfwff$xf2ftffrfEfsff^sfUf[sfcfzrfKfpffpfbfrfjfqffbofQfdfffgqQfb@˜'C~}ˆˆքn6~ԉ}}Ί&{Xxx=yOy y{拙 |}ڈ5煙ₙbltʙj5:d%Wg6fٓfrffxffOxfqfZwffrufftfDŽfsffsf8fsf5fsf4fqffpff-qfhf?tf{fvff wffzfzffvff)vf/f vfff6Yf>g\ XM2Y?DtyތB{rzzSxCwx17yy܍y${؊}ψ候ӄ]Zd'}wSnsqo\ [JgffWf@fQgfٍflfRfnf%fpf8f(rfftfftfftffsffcuffvffvffEyf4}f|fzffvf fSrff mfffgffaflf\fQf4fNc$fCiMdnɖorHstDu vxunz*|~5 mH"}Œzsvs?:qzkKbO_tn3τb8f+$fzflQffW`ffJgfGfjf{fmfjf2pf9f3rfSf}uff2xfj~f E[QgQf~ff vfgfvf_fwfBfzf{f}fwf$fsffsf fxuffdtfUfbqfۇf/pffpfhfqffrffZuf?fvfPfwfv~f{fzf}fr{f7xff>fgXZ])Ιj=o~Ku‡g㈙}ފd|Hp|b8|Gz-xvҏ#x@y{{Պq~熙8*H}2xBy%Әe !LPgfvf cff~of܆frf)f?qf'fpffnf+fpffpf߇f#qffzqff&rfTfQuff6xf}f{f{fy}fyf=f?xffufiffޤa@Vgff}Rftf>bfffhffNkff!lffmffxofFfqffQ( x4_g=nftf`frpf̅fsftfHuf.f_ufցfxf~~f{fzffVxfҁftf)frffpf0fpf6frfȅfrffpffpffpfɆfrfʄftf fvffkf$f#fg=Tel3)yƒ2XELHɇ~}}G}{9{{Ōzty{]|1}~凙/>⃙ttxUKg-+fflf#ftff-tf΃f4tffisfVfqff5qffHpffqfÆfqfcf|qfхfsfނfBwfhf7yf;fgyf}fx{f|f`~fwfOfufMf:sfÅfhqfffxfgffgl^8*pVBrvOw2x@SzdVxBTx[xyrxdyy|yƂŀi~)<{֍FwrԘ@lv)D8G=gffUff,ef|f ifflf=fpf^f(rff7qf%f:qf†fqffrfAf'vffxf ~f{f{f2~fxffrwffEuffofˊfkfӍfhffxcffDZfơf9of&pdk)-ʘJC䰙aj:pהt璙ue7wz֌{6~]ςc,u|匙yv#tMql"aJK̙)ԙH4)+f3f"fSQff-_fcfgfflffof:f7qfftf:f?wf fxffIyf}f |fS{fd}fzf(f;xf݁fsffpf'f.nff7mffbiffNfff^f-fNfjfkf6g:>͔_ɤIg^l̗rLaw鎙y{ӊ/~:XAƅ ~}[zxmybxdwwv_tneE$BEtAaKffgfffiffmffrffvffyfB~f{f{f;}fzffxf~f3vffUtf#f_sfflrffoffZnfKfpftfqffqffofljflffecffsfgNhOzމwp?w6N{ي~Tu脙Հ}HyۍyPxvܑsv!wQz6|SvhcY~%|eәQȇ:YrgEffyf{fG}fzf|f{f0|f}fyffvff^tf3fqffofafpffqfمfsff!tff]vfʁf}vfIftff;wfJfzf {f~fyf~fYzfzfSfJfbgDZ?«:Dۙaw퍙zƌ{{8zzݍIyixҎ(zz팙zIvz!~}}<*<톙 zxTwJ̠%ilM]gfaf^fyf\kfflfufmffoffpffqf]fpfNfpffqf#ftf1fxf~f(zf~fyf}fzf}f}f=xfEfsff8nffrjfHf;fffbf&ff~b& |WaG}gpX1twԎyKxxyz댙K{}a삙pC{y'vq}ck۟DbjV$XԞR< gfAfOfȝfJaffif2fwf=fxf]~f$|fyfpfvfmftffqfۇfkofcflf fjfftffГf`fDf*Pff{+fkf\6V͖ KNtbȟol뗙 ruÐx5yu@{R}Nxc9~ˋ{ʌ'zCzv(y@?w|sEprl՞cWEY2濫$'d{ffYffbf>f`jffnffVqf/frfftff zf|f-~fwffvffufyftftfLrf[f!qffrffpfffcnf7flfUfjfffffOVff6fgH䚵0~YZptHx2g|ҀjJ9/-x}v{;zq yyˍ zwvfvx莙xu-ZF/Ueњ],g`fyf%fpffrff]vffzf+|f}f xfVfBwffufftf_frfVfqffrf˅frfffnrff)rfRf>sffoufւfuffvfހfYwffIpff0fסgVxA#{jr鈙فꄙ΂Džမ}{Uzzi#zJ yxH>zb{]}^~ψqH~F%~Kί (Rzg ffLhffqfۆfrf f\tffrf5f;pffqfDf sffsf'f5rfRflrffAsfكf.uffvfOfcxf~f*{f~zf-fvf_fHtffpffjff nfgvff=_4|+-OmI=sӒv+xhwӐx,{{hry%y@{Qن偙WulɆ~~{Cx`uP,rjke|;C˓g7fCfRf7fcff+ifflfufoffofEfpftfof.fqfхftfЁfxfOfyf}f"|fyff}vfYfosf…fwqfrfnf؊fkf7f ifDfZafFf-UfAfSf9e-š"䙻Eb@n6patvMyy1|䉙<႙ƃńƂ[ӈ|6yurgp[j!aGܙWԜǔ 0eJffETfНf_ffHffߎfkf~fi{fzffxfŀf?uffqffOqfćf-pffynfيflfӋf8kfgfff~f&afԜf{Qff f]vgFA$ۨyrg墙$hgzo0t㑙@w {W8}U:쁙J~={Az֍ zyy1y؎xx͏3v;spfk4,L31 `fz{flffijffnfjfrffufJfqxf}fn}fwffIsf*fErff^rfʄfrtffrff~sfхfxqf:f@rffNqffrfUfXsffrfŅfqff$gfffg Qf@fBv~\}6 م$k8ÅzވP~ |ߌyOxyxȎ.xxԎy|s5i넙恙o7ƙn 74GWg)8fۑf tfkfwzf~fOyffiwff2vffuffhtffksfufrffofCfnffof܆f8sff vffyf~fzf|f|fzf.fcwffvfffuff~fYf=g\ $W3=o[{quȏ\yaz{8y_wِwU|y*{z܌7z.G{f}Èɂ}Dywtr4^4_J g ffZf5fgffkf‹fKmfflnffmnffnoffmqffsftf;sffYtfȃfufifxf]~f6|f zffvfyftff8rfӇfbofMf/jf+fcfrf[ffflc$UFffoUsftOutv$yzv|T~DcZUၙ!+|]xs閙mTja1QDmCb8f$f۵f`Sffaffgf fkf"flfFfipf܇fqf;fsfRfsvfʀfxfW~fR{f9{f6~fyff@vfނftf$fHrffpfflfČfiff~fff `fJfPfffsf^:"ҁƚU1CbRkSrגvy{v}Јyzo:}狙"{q[{{yϏuSspk{cEn&LU"cuffnaf[fgfҍfsmfшfpfŇfJqfFf_rfnfuf=fszf{fJfvf[fufwf+tfqfrfޅfmrffrf fppffoff pf+fpfЈfmffgffiXfsf fgKz*D TtڑJw?{򊙽}聙QE…T~|{yy]y%zތN{،zzz鋙#|{ w7\ᙜ9?| [QgQfjffuffvffzf[|f|fyffxffvf fttffqfYfrffrfքfrfօfrff^rffsfhf:tffcvfQfxf}f{fr|f{f~fufftfOfqffof f-nffUmfflff-kffYfff~Ufffg|oE<`|Sqʝ#kho;sOxX}~󇙜N*~}f|y;vavHwWyNw wgaul⣙P{*L3_^gRmfctffmffof3frffxf\~f8|fyffwfفfuffctffrffhrffqffsffqf@fMpff&qfɅfsfڃfuf5f\tfDfsff|fdzffvffsfHfqffpffGmffYkf|f2iffOgf%f}af,fPffcfv4gd<>GT]ߦtfnLruxՌ4| ~G(*oY{y!zyߏ`tq8qŖIprhɩHHUafsfueffgffmffKqfńfxuf{fwfJfzf|f$|fN{f~f xffsffqf߆fqfBfqfWfrf4fepffofˈfEpffoff]ofBf)nffwcfAf<fgNjӑMxƏx7{}4Kډ|{zxyz0{zeznjyލzӋ}R}mfgՙOP ^Ypg4Gffzzf{f|f|f9{f~fwfrfNvffatfftfÃftffsfބfrfAfpff6qfNfsfyfsfftfLfvf;f yf}fc|fzf^~fxfzfxf{ffKfbcgRZi(FٙaY{y|}z썙Gzy8yˎy}{{z xz{@2~<_&tMu0|Wvsg̠_mM g1ff^fsfKlfÉfoffuofʈfnff)offpffqf;fofafofcfjsffwffxfZfyf=}f|fyfĀftffqf؇fof7fjfCfUeffAbf܌fdfzb(+ ZqFeiotUwאv<7vvxxxi_{ʅx#ˆ~{~'yqwrt$sm c 5ZƝ&XQ<gffNfhf]fIfBdfI3ڙY) 0eGffRff^ffefyfiffmf2ffwf6fyfEfyf}f{f {f+f4wfEfeuffMsffvqfކfpf"fpfƈfPofψfpf/fMpffrffsffrff:ef.f*f+gzQdSBf?}z|eƃR!Y{{| zx xz|抙@|Ȋ}&}XN'u~1mșWkI:g#W}g>9f‘fsfafzyf}fYzf=~fyfbf_vffqffpffofhfJof(fpffg\f WV3YUt3zz-zyƌV{쌙zyt\yJz5z.{틙|*eˆ6{|8xt0q퓙^4.aJyg f]f~ZfɔfihffkfcflfыfGlff6lf,f+mf f"offmpffrffevffyfe}f |f{fo}f zf~fxffWufMfpfNfkfڍfhffdfSfN^fcffCcm$d $Gdf,gff_ffofuf)nf6fnffXofUfpf׈f0mf%f3^fff7gNK{ }s@uqxC|\քI}{o|ዙzx䎙YxNx3xَMzHzu|ዙ{狙xq^96; [OgTfρffvff1xffyf{fO~fxffvfftfftf"frf|fsfcfsffrffBrffsffuff=ufڂfuffQwfˀfSxf~f~zf~fvfTfe>f$gX~[S]Nϙi}~jI||t}䊙{9z㌙{yrx@x獙zʌd{9};UGz{ xjyYQӘdQLPgffdff qfڅfqf8fpqffqfOfgqf f(ofefnf/fpffqfͅftfqfP8wHjerꓙ8tsԒuxxzxz4|s}mdσj}RyeNv,r:m`fPf3vfYf{fzffBwf}f:vf;f@tf#fTqffmff^kffffefh_ffQf+f0O؆!}䉙}p}|G6zMyypy+yxv!t1oreCm,Q`,2__gnfrffoffrfftffwf|~fgzfI}f|fyffwfpfGufftff%rfʆfqffgqfԇfoffpfņfrff!tfftfтfuffsfIfifJf"f g$=TmQxV̆A6~Š|]zzZz{zv}zgyȍKzό=|%Rꃙς5I9?tDLy wU'gR+ffoffxwffvfftffqffqffqf fHrf]f|qff8rffqffsf,ftff1vfɀfxf&f;zf{f}fyffuf frffpf@f_xf\ef g"l^*T&f~Offf5g:>ƕf\بclZswynz}7ˆ2ć~V#|az뎙y}sGل4׆R|B}芙K|({{ ^yw wzB~>w2HszܒdJ֙O͇GYPugCflfhxfq|f|f{f{f|}ffzfE~fyffxfrfuffsff[qf܇fpffqf…f#sffYsff{uffvffwffwffyf4}f{fzf~f4zfzffKfbgxZGDڙyayxa|ϋQ{{Yz'zǍQyώy wx\gz|$~ł N0r{|?uxǐv댙ˠGDkMg ffF^fflf8fof~fqfWfHpfefof8foffpfчfpffrf|ftffuffwf!fzf}f|fzf/fvffӄ-[쀙~Z%jvRg!ffhffrfӄftff:tffrfTfqfVfrffsffrffppffVofӇfhqf̅ftfof'vf_fyf}f|fxfۀfvfftffqffwlfcfnfufhf"_.,+{N]msvÐw8v=xxgxFxt z|O(Ň'}y xt@7nigo^lczsCg ffHTff4dfkf_hf1fOkfVfmf fpoffpfRfqfftfYfwffBxffwff{f{fffvffUtfׄfkrf݆fRpff{lfCfff)f_fhfUffWUf7e2-#Gyab}imr^\w {&|<~~臙uZ|W{y2Gws1ao̚jOa Jؙ \z 0ɏeHff|Tff_f3fdfxf?hfIfcmffqfofuffxf~fyf}fP|fzfMfAwff}uffufftff qf{SVwVu葙vv\utR*slNB3A `f_~fhfˍftlfDfmffoffqf{fsqffrpflftpfʆfrff`wffwf~f wff~yf|fv}fwfftffqfbfpnfzfjfLfdff/\ff3fc $Z5CDpMdnΕtJwZvuvXhz}ሙ&^惙F爙|̌#y^uj,u+r>RkM`P޶,pDd8Kf &ffSffaffgfʏfyifffjffmffqf΄fufDfvffyf}f{f{f}fyffwfftffqff6nf0flffjf܍fhfjfdaff{Qfϸfff_:C$4ĚNRhbl,qVtxG/}#a~M$т {~ʊ~{(z΍SyLw.uΒtC t5oFReEmn}L`"cff^ffcff>fif;f~mf`fbqf fvffyf}f|f|f}fyyf[fexffAuffqff>offofyz!m3$|#zDv!tԔqp(l/d۬G Ú+d`fflTf[f`fQfhfrfkffFnf)frffGuffwf1fzf{fS~fWxfEfufftff)qffoffnf7fxofSfmfYftlffif>fRefwfTff f+gQpE=:Srkp&ptz}|G8’;~|AzyzyxӎxOwďvC)u2unQw(r4_SgmfsfΈfoffDsff)vffxfJ~fS{f {f~fxf fwfˁfufpfYufjfrffqffrfPfrfʅf\qffpf=fqfvfsfUfsfkfsffKkff&fg>Tl9xRFą灙P˄1W$MR~{IzcDzyy`xĎey3{~?w^tu#vUgk*fɚfnffwf-fxfRfPvffuffsfτf1sfЅfqff pfĈfbpffqfdfsf fsff@ufifwf{fyf}f0|fzffIufVfyrf.fpffwfgfgGn^ ()@SПpwbyxΎxx`yXVyByPzR{nj${ËW|艙4܄NU|x tەo욙jvCG5!Ggy ffXf!fAgffkf[fkffkf@f mfFfoffrfftf=fvff;vffxfw~fzfQ|f|fzfHfwf4fLsffnffhkffhffcffjXf[f{mfSrdj)J˘ E֮Zcn$wq'rSuCgwt zÍz|kwWV$cو}w/ptӓs0srkb#dM}ʙ9יJ4)f4fpfRfIf`f flffŐfiffWmf(f(pf\frff9sfKf vffyf|f|fzyf߀fvff&sf6f=qfÈfnffmffElff]kflfhfqfbffQf#f f)5gb;>`85\`eqo㕙 t呙|v,y1| ~2W~}C|劙|{5zю_xA.v#trOo⚙hʩbHG\a@fffff$ff fkffpf܃fvffxf*~f{fy|f}fyf#fvf>f"uffrffrffHrfffUrfƆf qf\fuofsfpfefypffnfflf}f7bflffgBNi瘁alxyx`|>x}ዙ{?|ȋ{xwɏEy-{ʊ<}׊|E||Њ|ydiԙQ*FYtg!Ff3f|fwfjfkyf-}f|fyffvff$tftfrffqffqfafqfӅfvsfЄfsfdfsffrfLfsf'fwf~fN{f|f*|f{fb}fyf~f|yf|f,fKf&bgZٓy苙M}D||ً{)z͎xXyʎxwᏙxΌw|t恙=ƒׇ~ʊzw0u.Lc͠@oMIgff]f fkf\f/off"mf͊fmf~fmffnffoffpffXrfօfsffOvf1fyfY}f|fyffvf#ftffqff1of'fbkfZfmgffeffAfrzbV+ xZr_Hggko疙qUsXtꑙwꏙ4y\z{S|}dهȀtЃ≙{@wpsoɘ#metuZ/)BVԔS<> gffOfPf=`fkfdf-fiff]nf fofNfapf·fqfdfufofmxf~fMzf|f|f_zfvf>wffuffsffpffkf=fhf7fPdff_f؞fQf5fY,fkf[6! P c]7lp3 suy2|ˆӀE<9\Z~c{iwau6ttErltm}cME;񙤦^%'8d|ffE[ffEcff/jffmffqff ufفfwf€fxfZ~fzf<|fg}flyf,fnuff/rfefBqf.fSpff*pffnffof5fofKflfٍfJgffXfffgH&1~ߖo閙Nrv|avwk݀J}zw͏Lw]vFxxŎx,FzZHz%)z"u~Y7.](gcfxf9fzqfffufIfxf~fzfG}f|f-zffvff1tffrfofHrffrffFrffqfڅf4sf'fufbfuffuffwfnfwfwfvf2f+nfjf.fgiV y# |\q+;qs}?2}-u})y5wjEyKzz,zV|M}݀N쀙K}Ŋ}&RgfƢf$hfLJfsffQufftf}fuuffsffqffoffdqf fsffsfƃfuffvffufZf}uf݁fxf}f~fwfނfsffofLflf΋fof%uf:f_+vN>lstّIv{utWu.vxӍj{'|_~ꀙJ;{͍xu{r\@mlnd\~ݩCgff0SfUfcf[fkfYf~kf\flf fKnfKfqfhfsffsff,uffKxf~f!{f{f}fryffwff噓C'`jqhtbw8y{|e~U3cŁ䀙7~䋙y⏙ouqf1n=h_rHڙY 0ŐeGf/fuTfEfaf1fqgfގfjffmffrfnfuffvffwfEfLzf|f}fxf fPvffytf@fqff_nffmfflf̌fjf}fhf3fNcffQfһf f xgcA_(ۻvte!gϛnG8uUy_|~ 瀙6Ev|䋙-{ь]zutxx'x4w>wmEw됙usl7N4 `2f}f9if0fhf>f^nff2sfZfHvfMf9wffyf }f|fzf|f[uffjsffpffofwfoffof fnff3ofdf pfgfBrf fsfʅfqfPfgfffBgRQd@0˜!O~~Ո~L%̈́1*.K~||y{[}|{gyJy؎ex(y~|凙 /߀h~llșpl87Wkg`8fcfJsff$xffxffxff}vfуf:sffAqf1fqfUfIrfVf.sf fqfsfqf8fsf)f+wff|yf~fyf}f{f{f}fyf~f yffxfPf_fZfK=g\ W4♨[csbPuv䐙qwyzҌz2Gz8x yp|2<~Շ,I}Ê{xovt~s_tV^JRg2 f4fWff:fffjf^flffofÈfoffofsfpf+ftffuf]f,vfIfvffyf}f{{f|f|fzf,fUvf,frf fnfZfJjffcfژf[ffffDc$,DŬeYnNp^s̒v/ytz7{ъ} _-fLgX[^̙zkՍ}~};G|nz5xzEzczvyly,{8}~H႙L5}ڋ^{ߌ{&fҘdJPgfYfafmfmfFfoffqfdf"qf?fqf҅fsf߄f"sfNftfyfrffrf4ftf΂fTvfGf:xf<f.zfN|f}fzf.f=uffVqfDfnf:f'lf7fIjfƀfwfJaa;r:`2H8fomutvv[rxD5yx捙fz,}e,݀S鈙}3zȏtmN@e`jZ`@Ygo f!f Nff@`f#f.hffkff.nf|fofEfoffpf܅ftffwf~fzf|f|fx{f@}fyffvf]fNtffqfmfLnffWhf7fcff^fޝf]Sfѯf?f~eA02mәJtbb lUqєt$WwTq$kpftVx=|怙LfɆx~}t|䋙@zdyywxmw&vEvjupSQ(y(j5_8gofqfPfMofftf.fOvf fvffaxf~f|fxfWftffsfXfrffkqffqf8fLrf;fKrffrffprff|sflftffuffxtf#,叙%_ϥfnt葙v;~y{뉙~C[QE|׋yx|v*ut&?uߑvqޙ%h6THbH]߸$affgffjff)mf߉foff_sfvfvffyf}f{f{f~fxf̀fvfӂf!tfkf|qf@foffpf3foffgof fofnf qfwfpfmfDnffcffffagNjn픙%vǐx||WdރƆDꈙ@~{wy&zQzwywyzzt}dD>sz䒙Ue ՙP녪#YugBf5f/yfDzfafxffyf0|f}fxffbvffsffBqffpff6pf_fqff7tffxvff8vfNfivfفfUvffVyf}fT{fp{f}f{f@}fzf{ff Kfbg"ZAGؙc dz|Fp|h{yˎx xJv[v_y%L|Ћ|]|1W~}b|xVfyf}f{fzfe~fxfOfyvffsfQfrfffqf}jr֑vDWvcwzJ{zi{y|m|_}]܄S3vz7jxuoUvinanzSC glfQfQffbfefhffjffjf^fmffpfOfrfftf8fvfKfzfu}fzf}fL{f3|f}fowffpffrfEf9tf@fouf5fxf~f |fyfefvfwf2sf؅fpffpffpf1fpffoffClf~fhfzfcf2f}Sff fygTA(vs hi{oɕr:u?y }#^]~qs|3{֌3{>{yV vAut_ctPqk6LE3i`fzflfififfnffrfqfVvffJzf|f]~fxfcfwffvwfMfwff2wffvf̂fvf5fuffDvfJftfLftffuffjtfPfspffDbfffgCQq1Әb]e>ma`$bglsʏ|}ubdmP>ڀڀ||qq44||͋͋zzIIxxɏɏttooghghááaatQtQ..nn22b8b8ffff#f#fffPfPfffrafrafԒfԒfQgfQgfffififffkfkfff4of4offfrfrfffgwfgwfffxfxf~f~fxfxfff{f{f%{f%{f~f~fvfvfqfqfufufςfςftftfXfXfsfsfffofof‰f‰fmfmf,f,fkfkfffgfgfffo`fo`fffQfQfffffff_:_:#ҫ#ŚŚjSjSQQbb44PkPkQrQr22bvbv""yyÌÌ||숙숙CCssބބ99ƁƁll$$~~uu3{3{__ v v))[u[uDDss3s3srrmmccLLFF##ppJJ""KcKcĜfĜfWfWfafafff#ff#ffff9lf9lfZfZfYofYofffqfqffftftfffxfxf}f}f{f{f{f{f:}f:}f8zf8zfefefpwfpwfBfBfytfytfffsfsfffKsfKsfffqfqf3f3fLofLofffofof\f\f|pf|pfffqofqofffmfmfffgfgfffSYfSYfسfسfX fX fggKKIxIx$ $ 劙劙pp֖֖brbrԒԒFxFxQQ}}~~--ӄӄ~~剙剙5}5}ϋϋzzČČZ{Z{LL_{_{}y}y㏙㏙vvrrvv33vvxxÍÍyyWW{{{{)z)zyyffbbܙܙ:=:=  [[PgPgRfRfffff&wf&wfffxfxf~f~f{f{f{f{fI~fI~fzxfzxfffwfwfMfMfvfvflflftftf(f(f(tf(tfff}tf}tfnfnf?uf?ufff3tf3tfUfUfrfrfIfIfrfrfffrfrfofof)tf)tf΃f΃ftftfʂfʂfcvfcvfffwfwf+f+fzfzf\}f\}fwfwfff@f@fq>q77ll՞՞PcPcGG晿ñ++dd_f_fffVfVfffcfcfefefkifkif7f7flflfffnfnfcfcfpfpfffsfsfffvfvf)f)fzfzf8|f8|f }f }fyfyflflfxfxf%f%fvfvfffufufff4rf4rf߇f߇f9of9ofĊfĊfkfkfff\jf\jfffhfhfffigfigfff|cf|cfffuVfuVfff f fggnEnEuuߨ}S}Srr88kkppRRuu%%xx00@}@}88́́EEބބ\~\~{{ÌÌzzwwbzbzyyww\w\w[[yy덙덙zzyy..uu~m~m..PP))AA3_3_jgjg"nf"nfGsfGsfgfgf3of3offf^rf^rf̈́f̈́ftftfffwfwfffWzfWzf|f|f{f{f0{f0{f7f7flwflwfVfVfftfftfxfxfrfrf΅f΅fqfqfffGrfGrfffTqfTqfff;qf;qf`f`fqfqfefefpfpf f fsfsfT>T^k^kOOee&x&xzz~~ddāā΃΃QQ~~ƉƉ||WWM|M|狙狙{{zz//zz֋֋{{狙狙{{{{x|x|]]}|}|}}cc}}ppyy33zzׂׂԇԇMtMt44ъъaaVvUVvUgg6(f6(f f flflfff%vf%vfffOwfOwfƁfƁfvfvf5f5fsfsfNfNfgrfgrfffrfrfUfUfpfpf@f@fXqfXqf f fqfqfffAtfAtffftftffftftfbfbfwtfwtfffufufCfCfwfwff~ff~f$|f$|f\yf\yffftftfffqfqfffjnfjnfRfRfvfvf:gf:gfggql^ql^ĖĖ) ) 7(7(//RRrr㐙㐙xxۍۍ-z-zJyJy,x,xzwzwُُxxyy``xx@@wwxx__}}::⅙⅙**uu55{{4x4xOONvNvssooJwJwBB_7_7GGgg f fIfIfTfTf{f{fdfdfff!jf!jf΋f΋fnnfnnfff%pf%pfffPpfPpfCfCfpfpfɇfɇfdqfdqf$f$f'rf'rfffTrfTrfffSsfSsfyfyfufuf8f8fyfyf|f|fu~fu~fxfxf-f-fvfvfFfFfsfsfɆfɆfnfnf‹f‹fjfjfff*ef*efNfNf^f^fffVfVfffmfmfpdpdel)el)=Θ=ΘHHͫͫyeyeٜٜmm̗̗1r1rssْْyuyuYwYwҏҏdxdxxx//{{33~~bb%%hhdd~}~}ыыzz((zz^^&w&w**rr嗙嗙mmii,,bbMM ʙ ʙ֙֙صصJ4J4F(fF(f:6f:6fff Sf Sf'f'f _f _fffQf>QfffffffV5gV5g;>;>փ ~]~]ccddnnᕙᕙttww y y&&f|f|uuzz 99mmȁȁ$$??҇҇>~>~يي@|@|zzyyϏϏvvaavv*v*vttQnQn2e2eFFGGaaffffdfdf3f3f}>}ggԙԙOO]]  YYugugCfCfffwfwfv|fv|f>}f>}fS{fS{f|f|f }f }fzfzfI~fI~fyfyfffBvfBvfffdtfdtfff@sf@sfffrfrfff1sf1sfffgrfgrfffffxsfxsffftftf=f=fsufsufnfnfvfvfffufufff^wf^wfhfhfyzfyzf|f|f~f~fwfwf؀f؀fwfwfK}fK}fHfHfIfIfdgdgZZ2G2Gٙٙcbcb]]yyAA{{ʋʋ | |Q|Q|{{||yy玙玙xxTTzvzvZZwwyyˍˍyyhhyyRR||RR@@rr{{NN}}ӊӊ{{gggwgwCCvvdd99AˠAˠLLkMkMggFfFfʯfʯf]f]fDfDf kf kfffpfpf|f|fpfpfffofof}f}fnfnfffofofՈfՈfpfpf}f}fpfpfvfvfosfosfhfhftftfbfbf]vf]vf؀f؀fwfwfffzyfzyfs}fs}f`|f`|fyfyfffvfvf/f/fqfqfwfwfofofff)lf)lf)f)fJffJffffybfybfffff{b{b7) 7) ˑˑWWyyWFWF;;gg[p[prrttbbuuxxƎƎ1z1zwwmymy)){{||55ǃǃSSaa||ĊĊ}}''k{k{wwttyoyo雙雙 f fAAYYu&u&,W,WS>ӃӃއއ??}}JJ||d{d{==yy OvOv풙풙rrnniiGcGc.F.Fhh \$'\$'KdKd|f|fff\f\fffdfdfCfCfhfhfff}kf}kfff5of5ofLfLftftf^f^fxfxf)~f)~fzfzfO|fO|fm}fm}fyfyf,f,fwfwf4f4ftftfffsfsf\f\fpfpfffLpfLpf f fpfpfff qf qfffmfmf&f&fjfjfffkfkfffPifPifffZfZfBfBf f fggHH\\䮵00~~xxepepMtMtxxGG||//߃߃څڅ112~2~||^^@|@|{{SySyddwwww_x_x:y:y͍͍zzssxx77rrZZMVMVNN-- MM9]9])g)gbfbfkyfkyfYfYfrfrfffsfsfff2wf2wf~f~f|f|fTzfTzf\f\fwfwfvfvfSvfSvfԂfԂf-uf-ufBfBftftfdfdfXtfXtf{f{fsfsfDfDf sf sfq>qՔՔuu *w*wyy|{|{ ~~݇݇[[ԄԄrr҈҈'~'~nn{{ x xaattqqؗؗnnHHUjUjaa CGCGTܙTܙYY͛͛Dž 0 0veveJfJfbfbfuTfuTfffQ_fQ_fffUhfUhf,f,fSlfSlfىfىfnfnf f fpqfpqfffgtfgtf@f@fwfwfff yf yf|f|fm}fm}fyfyfffwfwf́f́fvfvfzfzfwufwuffftftfBfBfqfqfffmfmfˊfˊfmfmfffkfkfčfčfhfhfffbfbfmfmfRfRfffZ fZ f;wg;wgAAA(A(.v.vuueehh//oo̕̕ss[[vvPP1z1zʋʋ}}߇߇MMmmꂙꂙ77ll}}**yyIIww,,ww''wwkkauauђђss??qqꕙꕙaqaqRR1k1kssLL22ߡߡ``ffyfyfmfmffflflfffofofwfwfrfrfpfpfwfwf?~f?~fzfzf|f|fD|fD|f|f|f+}f+}ff>fpfpfefefQpfQpfffqqfqqfvfvf tf tffftftf(f(fsfsfufuf\tf\tfffgsfgsfff#qf#qfffVefVefffffggWQWQff??ZØZØѤѤււ | |f{f{w~w~χχ++vvFF%%}}܊܊u{u{ݍݍyyVVzzUU{{挙挙zzээmzmzzz77zz//>{>{7}7}KK~~腙腙'' lləə k k99WWՔgՔgV6fV6fffytfytf~f~f{f{f|f|ftzftzf9f9fLufLufĄfĄf^sf^sfff tf tfȄfȄfqfqfOfOfcofcofffofofֆfֆfhrfhrfffrfrfPfPfsfsfwfwf}tf}tfkfkfufuf f f3xf3xfO~fO~f{f{f{f{f}f}fyfyf~f~fsyfsyf$f$ff>fsfsfff5of5offfifif f fcfcf)f)f^f^fJfJfffPcPct$t$//BB/c/cQQmmqq55QsQs?v?v xx{{XX/|/|##}}}}FF݅݅FFGG88== | |//yywwuuppSrSrZmZm&&ccͫͫ_R_RvvooGGgc8gc8ffv$fv$fffPfPf9f9f,^f,^fffefef f fkfkffflflfff mf mfffofofGfGf{sf{sf9f9faxfaxfPfPfyfyf}f}f|f|f{f{f~f~fwfwffftftfHfHfrfrfofofrfrfنfنfofofffnfnfffjfjfffpffpffff&^f&^fffOfOfffffff^:^:##rƚrƚ`W`W))dd\\;k;kmmTqTq< > [[NgNg|Tf|Tfffffufufҁfҁfwfwf~f~f{f{f*|f*|f}f}fHzfHzfxfxf wf wffftftf‚f‚fufuffftftf'f'frfrfffqfqfRfRfqfqfffYqfYqfXfXfqfqfffasfasffftftfff\vf\vfffjxfjxf~f~f{f{f{f{f}f}fzfzfyfyf.f.fk?fk?fLgLg}X}XiiYY^^V͙V͙kkΌΌ++JJoo~~||${${zzՍՍYyYy΍΍yyFyFy荙荙 z z̍̍zz錙錙WzWz񌙎||щщ~~RRHH]]<<ՅՅ뉙뉙b|b|1z1z5՘5՘ c c!!IPIPrgrgff?f?fafafffofof؅f؅fgsfgsf=f=fqfqfŇfŇfofof"f"fqfqfffqfqfff~qf~qf?f?fpfpfffErfErfff?tf?tfffufufԂfԂfovfovfififyfyf|f|fe|fe|f{f{fZ}fZ}fyfyf|f|fufufŅfŅf6pf6pfKfKfmfmf}f}fRjfRjfff]jf]jf܁f܁fffJaJa&a&a<<::JJKlKlQQ,t,tnntt|s|sxxtt瑙瑙)w)wSStxtx{y{yzzr{r{22{{ee~~^^uu}}YY%x%x𐙡uu9r9rmmeecacallؤ@@XgXgffSfSftRftRfffbfbfffhfhfff mf mfjfjf nf nfffnfnf؈f؈f7qf7qf*f*fqfqfffsfsfffufufffyfyfo}fo}f{f{f{f{f0}f0}ftzftzf~f~f8wf8wf\f\frfrfffofofffnmfnmfffkfkf9f9fngfngfff}af}afffSfSf2f2f!?f!?fee+/2+/2kkɒԙԙIIg`g`IIkkkk瘙瘙rrÒÒuuvvːːwwHHByBy||~~VVll܄܄>>((uu||܌܌AzAzuzuzwwytytxxRrRrppkkJbJb讙讙FF癄PPé++dd'af'afOfOfIVfIVfffEafEaf̒f̒fhfhfÌfÌfmfmfffofof"f"fprfprfffufufρfρfwfwf~f~fzfzf|f|f}f}fyfyfSfSfxfxfffCwfCwfffusfusfDfDfofof͉f͉f[nf[nf‰f‰f9nf9nfŠfŠfXmfXmf!f!flflfffifif f fbfbfff-Tf-Tfff f f g gwoEwoEߗTT7T7TqqyymmGrGruuxx쌙쌙9|9|,,//jj~~y~y~ ||gg&{&{yyyyȏȏuu11uuǒǒuuܐܐvvggssmmââQQ,,𐲰x2_x2_MgMgfoffofqfqfЋfЋf4lf4lf!f!f)pf)pfffNufNufffyfyfE|fE|f-}f-}fEzfEzfMfMf%xf%xf]f]f8vf8vffftftf&f&fsfsf…f…f\qf\qfffqfqfffqfqfff]pf]pfffNqfNqfffsfsfffufufWfWftftfSfSftftfpfpftftf…f…fkfkfff&f&flglg:@T:@Tkk>>y{y{ΆΆggmm؂؂LL^^**==MMp|p|BB||QQ{{yy z zss z z^y^y{z{zʌʌ{{..||ԉԉ~~{{ƃƃ̂̂ttNNߋߋJJ$$+xU+xUggt*ft*ffflflf5f5fufuf4f4fufufЂfЂftftfffttfttf~f~fsfsfffrfrfPfPf"qf"qfffpfpfFfFfqfqfffsfsffftftf^f^f{uf{ufffufufffhwfhwf}f}fyfyf(~f(~f{f{fKzfKzfffOvfOvfzfzfrfrfffqfqfffvfvfHhfHhfggggo^o^  n n ''[[7S7SPPqqڐڐ/y/yOOyyxxxx⎙⎙xx||zz@@zzSSzzJJzz6{6{||~~D~D~77;;L~L~TyTyPPuu||trtrmm}}ww5C5CM9M9GGUgUgffffcXfcXf f fehfehfffrlfrlffflflf=f=fylfylf!f!fmfmf1f1fofofhfhf(pf(pfffIqfIqffftftfffxfxf~f~f[yf[yfi~fi~f{f{f{f{f%}f%}fxfxfffufufkfkf?sf?sf1f1f#qf#qfffmfmfffififffdfdfffYfYfff,of,of qd qdj)j)˘˘왊EE®®bbȟȟ-k-kpprrssFFesesˑˑvvVV\{\{؉؉'' 11}}׆׆UUAAވވ0}0}yyBBttVrVr__ApAp՘՘llÞÞbbˮˮKK˙˙֙֙ii|L4|L4-'f-'fo6fo6fffRfRfڞfڞf{^f{^fJfJfedfedfffifif@f@fnfnfTfTfqfqfKfKf;sf;sf|f|fvfvfffyfyf}f}f{f{f|f|f |f |f{f{f}f}f}yf}yfLfLfcvfcvfffpfpfƈfƈfofofffff:<>֪''^^eeŝŝvmvmPrPrLvLv$y$ytt||55ccyyIIl{l{\\zzzz$${{0z0z׎׎svsvssӕӕ2p2pLLsnsnggIIGGyy<<aa׼f׼f[f[fffffOfOfGhfGhfffskfskfffkpfkpfffrufrufgfgfxfxf^~f^~fzfzf{f{fL~fL~fsxfsxfff&vf&vfffufufBfBf|sf|sfffrfrf&f&fqfqfPfPfqfqfffUqfUqfffpfpf&f&fIqfIqfffofof f fofoffflflfBfBf`f`fffffTgTgNNii^^嘱xxqqzz5z5z""}}hh22 ꁙꁙOOˈˈ}}``{{yy{x{xyyB{B{@{@{ӋӋ{{uu{{--||JJ.~.~rr{{ǑǑee.ՙ.ՙOO2 2 YYqgqgFfFfff|f|f-xf-xfffyfyf{f{fC~fC~fxfxf f ffxffxfefefvfvfffHsfHsflflfpfpfffpfpfɆfɆfrfrf|f|fsfsfffrfrfffqfqf+f+frfrfffsfsfۃfۃfaufauf@f@fxfxf}f}f|f|f{f{f}f}fKyfKyfffyfyf9|f9|fʆfʆfLfLfagagZZ''\ë\ëcCcCܙܙ__++yy}}LLz}z}7z7zUUxxttyy__zz⌙⌙zz{{C|C|II{{zzkk||~~PPeeGGHH{{yy܏܏NxNxkk̠̠lMlMgg f fff\f\fqfqfjfjf f fmfmfffmfmf4f4fkfkfffymfymfffqfqfffrfrfffxtfxtfff)tf)tfffxtfxtffftftfYfYf@wf@wf-f-fjyfjyf;}f;}f|f|fyfyfffCufCuf~f~fsfsf4f4fHnfHnf6f6fkfkfffefefJfJf{af{afsfsfffH}bH}b* * [[JJ"h"h1p1p99rrttPPcvcvvv\\dwdw!!ww[[xxōōzz$$0~0~zzddQQ}}zzxxffququoobbjjBBcc!!ZZҝҝ''*V*VԕStf>tfEfEfnfnfˋfˋfififffdfdfff]f]fffffcc$$33EEnenemmYpYp!!JsJsGvGv=y=y{{닙닙||||PP KK''ÈÈb~b~##||狙狙zz̍̍SxSx[s[sll%%ccxQxQmmσV_8V_8ffffofofaOfaOfff_f_fvfvfhfhf[f[fifif-f-fnlfnlfgfgfpofpof܇f܇fqfqfffsfsfffwfwf~f~f{f{f|f|f{f{fV{fV{fj}fj}f)zf)zfff(vf(vfffvqfvqf݇f݇ftoftofXfXfpmfpmfffffqkfqkf(f(fhfhf f fefefff_f_fܜfܜf\Rf\Rfbfbfffffb:b:\Ț\ȚʫʫUU~~ddmm11qq++uuxx``E}E}[[~~>>VV00VV||{{'y'yvvMuMu,,rrbboo77llOOee``EE77mmMM""ccffzfzfzafzafXfXf.ef.efffjfjfffofof*f*fufufffwfwfff>yf>yfffzfzfR}fR}f{f{f{f{f~f~fxfxffftftfgfgf&tf&tfffsfsfffrfrfffofofˈfˈfnfnfEfEfclfclf8f8fZjfZjf f fkfkfCfCfjfjfdfdf]f]fڮfڮfmfmfEgEgKKyyqqbbcucuxx쌙쌙(}(}凙凙ddკკ88ffff||zz44iyiygxgxtyty z z~z~zFFI|I|vv}}ҊҊ{{g{g{OzOzuuZZ [ [--77  m[m[?Rg?Rg Pf PfDfDf{}f{}fdwfdwfȀfȀfExfExfPfPfyfyf6}f6}f|f|fyfyfff$wf$wf߂f߂ftftffftftf'f'fKtfKtfffVrfVrfΆfΆfpfpfˇfˇfpfpfqfqf8rf8rfffsfsfffvfvfffwfwfffxfxf1f1fexfexfFfFfyfyf~f~fyfyffftftfܐfܐff>f2rf2rfffAofAofŠfŠfkfkfUfUfhfhfffafafMfMfnWfnWfffmfmfsdsdh)h)ɘɘoEoEzzcc,,kkHqHqttvvwwzz/|/|}}&&$$$$rr􅙻}}AAvxvx8t8t22rrBrBrkkaaˮˮKKA˙A˙֙֙:J4:J4+(f+(f6f6f۱f۱fSfSfKfKf`f`fffefef f fvjfvjf:>ֈYYzz]]짙짙+d+dll44ss8w8wjjyy ~|~|006~6~66ii++99}} nznzɍɍyymmzzލލLxLx++yvyvuuYsYsؕؕpp;;hhJJHHḒaahfhfff,df,dfNfNfVgfVgfՍfՍf mf mfffpfpfffJsfJsfffwfwf,f,fzfzfz{fz{fX}fX}fzfzf~f~fwfwffftftfffWqfWqfffUpfUpf*f*fpfpf f fofofpfpfnfnfff+of+ofUfUfqfqfffrfrfffrfrfffnfnfrfrfvbfvbfffffggpNpNiiϑϑBxBxЏЏxx {{yy~~ކކ;;ss44QQ׈׈~~77{{``yy'y'yzzOOzzSSyy䍙䍙zz zzE{E{{{KKD|D|%%zzUeUeԙԙ'P'Pއއ6Y6YvgvgAfAfffwfwf|f|f|f|fzfzf}f}fzfzf$}f$}fT|fT|f5zf5zfffwfwf-f-f6tf6tf7f7fqfqf{f{fpfpfÈfÈf+pf+pf{f{fZqfZqfJfJfrfrfffrfrfȅfȅfrfrffftftfffxufxuf?f?fxfxf}f}f|f|fYzfYzfffwfwf f fvfvf}f}fffNfNfagag}Z}ZVVssEEۙۙ``$$yy~~||99||{{zzeezz11'y'yQQTyTy䍙䍙zz׌׌zz{{||5~5~z~z~zz{{KKzzTTvvvvLLΑΑffɠɠ''hMhMggf ff fff^f^fnfnflflfffNofNofffwnfwnfffmfmf[f[fnfnf$f$fpfpf9f9fqfqfffyrfyrf:f:frfrfffufufNfNfLxfLxf~f~f%{f%{f|f|f|f|f{f{f}f}fzfzf}f}f$zf$zfZfZfwfwfafaftftfJfJfnfnfɌfɌfffffcfcf_f_f֑f֑f0f0fbb<' <' hhFXFXAGAGhh֚֚oo22rrttkukuSS+u+u||^v^vyy(}(}??88MMEE~~**~~ȉȉ%}%}zz77ww|s|s66llmmbbxx|V|V$$XXRef>ef*f*fififHfHf%lf%lffflflfHfHf mf mfff"of"offf!rf!rfffufufff1uf1ufjfjfufufӂfӂfwfwf#f#f{f{fyfyfffufufffrfrfffiqfiqfffofofff#nf#nfPfPfififffhafhafff}Tf}TfffSfSfH:eH:e--ààŴ!!䙡EEaa0l0l\\ooEE!s!sےےvvww&z&z싙싙~~ꇙꇙAÃ̃LLff~~뉙뉙t|t|((zzxxvvssyyHpHpkk==ccQQHHۙۙWWǠǵ00ȑeȑeGfGfͮfͮfSfSfff`f`fffwgfwgffflflfψfψfqfqfqfqfsfsfffEufEufffufufffyfyfj}fj}f|f|fyfyf]f]fxfxfffwfwfffufufkfkfsfsfff{qf{qfffofofffnfnfffjfjfffhfhfffcfcfXfXfhSfhSfff f fxgxgQAQA0(0(۹uuyvyvccee坙坙mm;;ss<r>r{{jjLLK5K5韵韵%`%`{f{fe|fe|fWkfWkfffdjfdjfff\of\of%f%frfrfqfqfvfvfffxfxfO~fO~f{f{fzfzf`~f`~f(yf(yfFfFf`wf`wfffvfvfFfFfrfrfffupfupfֈfֈfofofefefofofχfχfpfpfffHqfHqfffqfqfІfІfqfqf…f…f@rf@rfff4pf4pfBfBfffffǤfǤf7f7fXgXgQQJfJf??˜˜t}t}v}v}AA[[zz]]vv~~JJr|r|~{~{VVfyfy99exexzzll||||銙銙{{{{ƊƊ}}؀؀%%AAcc((덙덙8k8kəədjdj>;>;--WWБgБg9f9ffftftfffJzfJzf}f}fBzfBzf@f@f(xf(xfbfbfufufffzrfzrfff[rf[rfԅfԅfrfrf f fqfqf@f@fpfpf&f&fqfqfffKsfKsfބfބfsfsfffsfsfufufvfvfff^yf^yf }f }f+}f+}fTzfTzf~f~fge>g<\<\  UUe5e5<> } }ff{{/w/whthtPPppkkbbRRʶʶooϒb8b8ff%f%f|f|fEQfEQfff_f_fffefefffkfkfsfsfOmfOmfffnfnf}f}fqfqfff[uf[ufff4xf4xfX~fX~fgzfgzf#}f#}f~|f~|fzfzf~f~flyflyfff[wf[wfyfyftftfffqfqfffofofffmfmfgfgfnkfnkfffffff'f'fa`fa`fffQfQf2f2fff{f{fa:a:{"{"ƚƚRR¬¬XbXbjjqqqqaa#u#uSwSwJJyy~~// ~~##}}&z&zAyAyooxxwwssPPFsFsrr**ooۙۙ i i娙娙HHnnNN!"!"b cb cff{f{f^f^fїfїfocfocfffififffofofffsfsf f f wf wfbfbf&zf&zf|f|f1}f1}fzfzf/~f/~fyfyfBfBfxfxf f f^wf^wfffsfsfff qf qfffofofÈfÈfnfnfofofmfmfffmfmfĉfĉf;nf;nfffnmfnmfvfvfOhfOhfff\f\fff f fggKK{{a a 됙됙%t%tvvt{t{88{{aa\\UUބބ||!!==Y}Y}77?{?{xxyyGwGwwwʏʏxxߎߎyyMyMy33zz݌݌zz||xx__ޙޙE> 66 }}yy珙珙#v#v璙璙CsCseeoogg66bbJJؼR@R@.[g.[g f fffPfPfޜfޜfbfbfffhfhfffkfkf0f0fnnfnnfffpfpfffqfqf…f…fsfsfffvfvfffwfwfff,xf,xfVfVfyfyf }f }f|f|fyfyfwfwfnwfnwfrfrfzsfzsfsfsfpfpfifif@mf@mf$f$fififXfXfgfgfff(bf(bfffUfUf:f:fAfAfjeje/2/2Ʌkk\ԙ\ԙGIGI``hh~l~l((pp uu]]yyyy*|*|ss怙怙UUၙၙڄڄII怙怙B|B|6w6wܒܒssttss͕͕ToTo~~jjAA``_E_E~~å++YdYdafafLfLfWfWff>frfrffftftfyfyfdxfdxf~f~fzfzf|f|f{f{f{f{f~f~f!wf!wfffsfsfffrfrfff rf rf+f+fgpfgpf9f9fdpfdpfCfCfLrfLrfff'rf'rfffsfsfffsfsfffVufVuf?f?fufufxfxf=uf=uf`f`f6lf6lfffw&fw&fagag)?T)?TmmyyqqO}O}ƀƀꈙꈙSS //~~zz8|8|܌܌yyggyyppyy֍֍yyLLwwwwyy||II$~$~11샙샙@@EEaavv++@@@xU@xUgg+f+fffmfmfffufufKfKfufufʂfʂfufufjfjftftfffisfisfffrfrfȆfȆfqfqfff>qf>qfsfsfpfpfffpfpfffrfrfffufuf#f#f,wf,wfvfvfpxfpxft~ft~f{f{f"|f"|f|f|f{f{fffvfvf f fqfqf߈f߈fofofRfRfufufgfgf'g'gl^l^dd6+6+%%_T_T99=q=qRR0u0uvvސސxxttyyzzҍҍyy77/z/z$z$zxx\\zzz|z|::GG텙텙%%..|}|}xxlzlzwwבבAsAsyymmǛǛ v vCC1717E!GE!G)g)g f fff0Vf0VfXfXfcfcfxfxfhfhfڍfڍfKlfKlfffnfnfffofofˈfˈfofofffjqfjqf9f9f9sf9sfffjtfjtfffixfixf}f}f3{f3{f2|f2|f|f|f|{f|{fr|fr|f,|f,|f}f}fWxfWxf2f2fYufYufOfOfnofnofff4lf4lfffgfgfffHbfHbfffXfXfffvofvof]od]odGm)Gm)..l͘l͘}}꙾GGccݞݞ]k]kߚߚ>n>noo q q딙딙ss֒֒vvyyII{{?~?~ zz̅̅11~~||xx=w=wttUU5p5p-l-l蟙蟙aa<<KK Ι Ιeәeә^^˗H4H4B*fB*f5f5fff]Rf]Rfff8^f8^fffYdfYdfffkfkfwfwfpfpfffrfrfff2rf2rfGfGftftfځfځfxfxfU|fU|f}f}fozfozfo~fo~f?yf?yfkfkfwfwfTfTfutfutfffrfrfffqfqfvfvfpfpfefefwofwoffflflfffgfgfff`f`fffOfOfVfVfff7g7g9>9> jj..1^1^ee:n:nŖŖ%s%s蒙蒙vv55yy팙팙||܈܈%%~~փփxxXXچچ33SS~~>|>|xxooxxMMwwwwMMss..rrsosoTgTgYHYHttGHGHJJYaYa\f\fff"ef"ef=f=fefefff`jf`jfffpfpfffufuf:f:f"xf"xf}f}f[|f[|f\{f\{f~f~fyfyf~f~fxfxfʁfʁfdtfdtf/f/fqfqfpfpfqfqfffpfpfYfYfqqfqqfffrfrfVfVfsfsf„f„fsfsfffpfpfffnfnfff~kf~kfff^f^f4f4f$f$fggFNFNjjff]]ww__xx||uuMM||))?|?|JJRzRzPxPxُُvv,,vvaa1x1x++zz挙挙{{jj{{||}}..~~{{YYffuԙuԙ2Q2QֆֆhhYYugugCfCfffyfyfyfyfffZyfZyf}f}f>{f>{f{f{f|~f|~fwfwfffbufbufffsfsfffQsfQsfbfbf!rf!rfofofpfpfffofofffpfpfff-sf-sfffufufffwfwf>RRggOfOfffYhfYhfffsfsfffgufgufffsfsfff2rf2rfffGpfGpfff^of^offfHofHofff#qf#qf:f:frfrfdfdf@tf@tfsfsfCtfCtfffufufffvfvfȀfȀfxfxfq~fq~fo{fo{f`zf`zfffffgxfgxfffufufffofofffjfjfffMnfMnfvfvfmfmf__VV<<4-4-:O:OࣙࣙLlLl//EsEshhvvِِxwxw88IxIxPPyy>>yyyyDD"y"yҍҍzzJJ}}~~yy%%]]󆙜ꉙꉙ[|[| yyPPuu||oo i ioojjee } }݄CCgg[ f[ fIfIfSfSfff+cf+cfffZhfZhffflflfffnfnf)f)fpfpfffpfpfffrfrfYfYfrfrfffvfvfff yf yfffxfxf_~f_~fhzfhzf|f|fJ}fJ}f\yf\yfff$wf$wfffesfesfنfنfGofGofKfKfkfkfff,ef,efff]f]fffSfSfffTfTf7e7e:-:-ŀ$$iiFFHH__,j,jnnbbrr~u~uzz{{  dždžeeGG؄؄$$뀙뀙ssQ~Q~KK||rryy;w;wrrss}}'p'pjjܟܟaaGGۙۙYYtt 0 03e3eHfHfffffWSfWSf f f`f`fff*gf*gfffkfkfafafmfmf f fBrfBrfffyufyufufufwfwfffyfyf|f|f|f|fzfzf~f~fwfwfWfWf'vf'vf]f]f+tf+tfafafJsfJsfffqfqfffVpfVpfdfdflflfffkfkfTfTf2hf2hfff&df&dfəfəfTfTf=f=f f fwgwgAA(۴(۳vvqtqtkfkf::ggmm::ereruuŏŏyyr~r~33SSqq̃̃^^%%ʉʉ}}ŠŠ{{܌܌lylyww䐙䐙GvGv␙␙,w,w33#x#xppAwAw.u.uppjjMM^2^2//``ff0|f0|fkfkfff@kf@kfffrpfrpfffsfsf"f"ftvftvfffjzfjzf|f|f}f}fzzfzzf'~f'~fvxfvxf_f_fufufffnsfnsfffwtfwtffftftfWfWfsfsfՄfՄfrfrfnfnfXofXofUfUfcnfcnflflf?pf?pfffiqfiqfhfhfsfsfbfbfpfpfffefefåfåfffggoQoQee@@n}n}H|H|~~dd##$~$~ӉӉH}H}{{xxxxww菙菙wwxxZZzzj{j{*|*|劙劙}}}}]m]m@Ǚ@Ǚ n n\7\7g>g\\G G 1X1Xq3q3kk䙁[[!!*v*vssyyQQ9z9zzz͌͌#{#{xxwwxxxxӎӎyyyyN{N{44<<aa##==ۉۉ{{!!ww:t:t&s&sޑޑȅȅS^S^`^J`^Jgg f fffu[fu[fWfWfhfhfcfcflflfffmfmfffmfmfԋfԋfkfkfffjfjfffmfmf8f8fqfqfJfJf^uf^ufffvfvfffwfwfffzfzfC|fC|fP}fP}fzfzf$}f$}fezfezfffvfvfff6pf6pf f fbjfbjf%f%f5ff5ff!f!fabfabfffP]fP]fffJfJfcc $ $xx‰‰rFrF̬̬ddٝٝ+m+mZqZq33rr *v*v--yyээzzGG"|"|33}}g~g~::тт**}};z;ziiwwkkntntppkkVVdd##TTppTTb8b8lflf%f%fff Qf Qfafaf,_f,_fffdfdfvfvfhfhfPfPfykfykfffofof̆f̆fsfsfтfтfvfvfffQyfQyf~f~f{f{f |f |fx|fx|f{f{f}f}fzfzfO~fO~fwfwf(f(fOtfOtfffVrfVrftftfpfpf f fpmfpmfKfKf\if\if~f~faffaffff`f`fRfRfRfRfffffff b: b: }ǚ}ǚ88SSllbb򟙀kkGGppYsYs!!BwBwTT{{A~A~GG%%pp 큙큙oo~~YY||ddf>fififff\f\fff f f\g\gKKyy0 0 esesuuAzAze}e}QQ||!!Z~Z~zzCyCyCC=z=z΍΍yy㍙㍙yyQQzz{{zzUUyyv{v{zzn{n{ffvv\\uuᙄ::[ [ [[OgOgTfTfffffEufEuf&f&fwfwf~f~fE{fE{f {f {fffvfvffftftfff~uf~ufffufufofofufufffqfqfffpfpf$f$fGrfGrfffsfsfwfwfsfsfffrfrfffjsfjsfffvfvfffyfyf}f}f{f{f{f{f}f}fzfzfxfxfrfrf=f=fgg*X*XQYQY^^/Ι/Ιiȉ̏||bbNN~~ʼnʼn||zz99{{ {{ŋŋ{{AAyy荙荙yy퍙퍙zzNN | |{{&&{{~~NNρρoo}}``yyM{M{ԞԞԘԘkckcDDJPJPggsfsfffddfddfffpfpf$f$f\sf\sf)f)frfrfff pf pf'f'f?pf?pfbfbfpfpf҇f҇fVpfVpfff=pf=pfffKrfKrf f fsfsfffsfsfffvfvfyfyf[wf[wfffzfzf_|f_|f}f}fxfxfdfdftftfffJqfJqfnfnflflf͍f͍fGhfGhf?f?fkhfkhf"f"fffJaJa``==99TTJJkk QrQrttǒǒuu~~avavÑÑuuYYwwoyoy~~|| } }}}22S~S~ֈֈww~~ĊĊl{l{͍͍xx u uppll9h9h:e:e88}}]@]@!Xg!Xg f fffOfOfff`f`ff>fnfnfffnfnfrfrfqfqf߄f߄fjufjufffxfxfk~fk~f#zf#zf~f~fu{fu{fo{fo{f}f}fzfzfffufufJfJf2sf2sfjfjfpfpflflfmfmfތfތfififffffffГfГf`f`fffSfSfTfTfj@fj@f]e]eP22P22ɄɗMҙMҙJJJJ^^ΣΣgg3o3o$$ssݒݒuuwwDD|>|ӌӌDzDz 0y0yvv[[rrmmnnEjEjWWbbLLEGEGkkBBʧ+ʧ+zdzd<`f<`fffUfUfff-`f-`fffhfhf4f4fmfmfffqfqf f ftftfIfIfvfvfffxfxf[~f[~fB|fB|fGzfGzf~f~fxfxfyfyfQvfQvfZfZfufuffftftfffqfqfffofofffdqfdqf‡f‡fofofffrlfrlf'f'f&jf&jfffefefffTfTfffffgg\lE\lE TTqqݝݝkkqqllvv׎׎zz==||bbԃԃ偙偙~~@|@|JzJz)) z zzz22{{PPYyYygg~w~wRvRvvv̑̑tt=n=nOO((QQ  Y7_Y7_EgEgpfpfXqfXqfffofofyf>yf~f~fryfryfffzufzufffqfqfffmfmfȋfȋfkfkfDfDfififffefefff_f_f)f)fHQfHQf:f:fff4g4g;>;>֐֯))]]ff**mmjjqqUU[u[u<f>fwfwfff>tf>tfEfEfsfsfjfjfIsfIsfffrfrfffqfqfffeqfeqf f fofofffnfnf܉f܉f)of)ofqfqfofofىfىfklfklfɏfɏf_f_fDfDfffggNNxhxhʓʓ99yyʎʎLzLz鋙鋙V}V}##%%ee}}TT{{^^yyyyююww>>ww66wwoyoy))DzDz*}*}~~))??ЈЈ } }OOzgzgәәPPi i YYsgsgDfDfff_{f_{flyflyfff,xf,xf~f~fk|fk|f zf zfffvfvfff1uf1uffffftftf?f?fsfsfff@rf@rfffsqfsqfffpfpfffrfrf&f&fqfqf)f)fwtfwtfffvfvfff|yf|yf~f~fyfyf}f}f8{f8{f{f{f}f}fyfyf~f~fzfzfzfzfffKfKfncgncgZZWWؾؾGG1ؙ1ؙddaayypp+{+{;;{{{{{{115{5{ތތ5y5yʐʐuugg7u7uGGxx㌙㌙H|H|*|*|O|O|~~چچڄڄddT~T~ˊˊN{N{VVNwNwss ]]**ɠɠ##ekMekM-g-gffff_f_fwfwfmfmfffpfpfSfSfpfpfff;qf;qfffqfqfffofof3f3fXofXofQfQfqfqfфfфf9tf9tffftftf+f+fvufvufffjvfjvfffRxfRxf~f~f^{f^{fzfzfYfYfwfwfffsfsfff[qf[qfЈfЈfMmfMmfff$gf$gfffjafjafff$f$fbb% % pTpTDDggrr11tt u uEEuuTTxx]{]{{{ތތ { {yy{{‹‹}}''VVwwddzzcvcv))rrddpp;m;mZZee~>~||ߋߋzz#y#y WxWxnynyCC7y7y6z6z猙猙{{??||tt}}~~xx„„cc~~ww/~/~AAj|j|eeҭҭ3*3***SRSRgg f fffjfjf9f9fsfsfXfXftftf&f&frfrfffpfpfffpfpf f f?qf?qf_f_fqfqf%f%fwrfwrfffrfrfffqfqfff rf rfSfSftftfӂfӂfwfwf~f~fzfzf{f{f}f}fyfyfQfQfvfvf܂f܂fsfsfֆfֆfofof)f)f&lf&lfhfhfnfnftftfff__))g.g.__%Q%Q롙롙nn甙甙tt䒙䒙ZuZuʒʒtt@@0t0tuuڑڑvvxx00{{ÊÊQ~Q~퇙퇙ֆֆꁙꁙJJ 44섙섙II ~~NN{{f>fpfpfÇfÇfofofffapfapfȆfȆfrfrf.f.f(tf(tfÂfÂfwfwf f fyfyf|f|f}f}fyfyfRfRfxfxf\f\f!uf!uffftftfӂfӂf}f}f8Yf8Yf.@g.@gt\t\- - 3U3U+5+5__ZZTTftft))yyzz { {>>EyEyxx-w-w&v&vww؎؎zzYY||**00LJLJPPQQIIۄۄЀЀooI}I}䌙䌙yy::KuKurrGGnn[[ [J[J g g f fffYfYfffgfgf:f:fkfkffflflffffmffmfff~nf~nf5f5fpfpfӆfӆf?rf?rf3f3fAsfAsfffrfrffftftf2f2fwfwfffpwfpwf(f(fyfyfD|fD|fffufufUfUfqfqfffofof݉f݉fkfkfffhfhfffdfdf#f#f _f _fffffcc$$PPGGccWdWd kkoo––UrUrȒȒBvBvאאxxBzBz||m~m~‡‡끙끙??aaYYffII~~zz3u3u||oo,,UkUk%%!d!dRR9n9n22a8a8ΨfΨf "f "f#f#fMfMfffF^fF^fPfPf!ff!ffffkfkfffcnfcnf׆f׆fsfsfTfTftftfRfRf]uf]uf`f`fjvfjvfTfTfVwfVwfff yf yf}f}f{f{fyfyfffyufyufffqfqfjfjfOqfOqf"f"fpfpfffmfmf6f6fififififffff%f%f8bf8bfΛfΛfQfQfffffff ]: ]:%%ĚĚᮙᮙRRoobbll{q{quu,,xxލލ{{VVIIӅӅmmЈЈP~P~||{{^^#{#{PPxyxyxxvvww``ttʓʓqsqslplpҙҙhh쩙쩙FFwwmmMM""wcwcDfDfff]]f]]f@f@fddfddfffjfjfffJofJofffqfqffftftfffyfyf|f|f}f}f.zf.zf~f~fxfxfffwfwfʁfʁfufufńfńf`rf`rfffqfqf.f.f qf qfBfBfpfpfffTofTofffmfmf:f:flflffflflfff-kf-kfff\f\fAfAf f fggKK{{qq aaMvMv~~HyHyb|b|≙≙)) RR႙႙ggĆĆ++##ZZs|s|BBs{s{zzyylzlz z z{{xx++ x xyyyy鎙鎙wvwv--\\))♶99  H[H[`Rg`Rg.Qf.Qfɂfɂfffvfvfffxfxf+~f+~f{f{f{f{f'}f'}fOzfOzfEfEfwfwfLfLftftfރfރfXtfXtfffsfsf'f'frfrfff qf qfNfNfrfrfՅfՅfrfrfՄfՄfBtfBtffftftfff\vf\vf f foxfoxfffxfxf~f~fAzfAzf}f}fl{fl{f}f}fufufff;f;fggwXwXɈɈZZu\u\lЙlЙgg@|@| ~~~~{{``O{O{㋙㋙||||NjNj||yyUUdydyCyCyxxzz??||}}ԈԈ~~ttcc~~~~{{{{qqԘԘcdcdKPKPcgcgff{f{fNafNafʎfʎfmfmfLfLfqfqfffrfrf{f{f-rf-rfffqfqfffofofffpfpfNfNfqfqfff{sf{sf f ftftfBfBftftfffufufffwfwfffzfzf}f}f|f|fyfyfffufufffqfqfKfKfmfmfffhfhfffrhfrhf΂f΂fefef'Ja'Jabb<<99pp[I[I˧˧jj<tf>tfffDrfDrfffNsfNsfffsfsfffrfrfff,of,ofrfrf.lf.lfffjfjf|f|fDhfDhfcfcf9df9dfffUfUfff f fggoEoE00TTppii::spspGuGuގގ}z}z⋙⋙}}򈙣ᆙᆙ88ZZb}b}뉙뉙~~~~}}늙늙||xxKKww33vvÐÐvvɐɐdwdwbvbv55:t:t$$NmNm66PP))OO5_5_ggCnfCnfsfsfPfPfrofrofKfKfqfqfffmufmufofofzfzf:{f:{f~f~fyfyf>f>fwfwfUfUfwfwfffxwfxwfffGtfGtf.f.fVrfVrfpfpfpfpfff+rf+rf0f0fnrfnrfffrfrfȅfȅfWsfWsfQfQfQtfQtfff2tf2tfff-tf-tfbfbfrfrfPfPfjfjfff%f%fgg{>T{>T{l{l88ųųFzFz႙႙44LLssӆӆ{{}}މމ}}}}v|v|LL{{yy{{mmc|c|zzcwcwkk6x6xyzyz {~{~ۂۂ//))``*t*tƼƼ  $$wUwU|g|gH+fH+f>f>fnfnfffufufsfsfufuf4f4fufuffftftfff|uf|ufUfUfStfStfffrfrf6f6f7rf7rf;f;fqfqfffqfqfffQpfQpfffrfrfofofufufff`wf`wf`f`fyfyfE|fE|f}f}fyfyfffvfvfff+tf+tfdfdfofoftftfufufgfgf[g[gl^l^QQgg9+9+4:>րύύܑܑ%]%]meme3m3mHHJtJt55rxrx{{HH}}~~oo>>~~ww`}`}C}C}{{썙썙wwÑÑttssDDasas8t8t퓙퓙qq99ii姙姙IIKKEIEIuuhhaaüfüf~f~fffffffgfgfffjfjfffofofff!vf!vf{f{fwfwfffxfxfF~fF~f{f{fMzfMzfzfzfwfwffftftf f frfrfNfNfpfpfۇfۇfqofqofffhpfhpfififofofffpfpfffpfpf f f qf qfʇfʇf2pf2pfPfPf mf mfff af afNfNfffUgUgNN k k푡푡昖$$%z%zyyߋߋ#~#~88IIii33ډډ||RR=|=|}}-|-|11zzHHyyuuyy22?z?zw{w{{{dd{{򋙦||ÉÉ͈͈||eeՙՙqPqPiiYY.tg.tgEfEfff${f${f&zf&zfz~fz~fzfzf_|f_|f"}f"}fzfzf~f~fxfxfff wf wfffufufff"sf"sfffqfqfififqfqf$f$fpfpfffpfpfڇfڇfpfpfff{qf{qfpfpftftfff_xf_xf~f~fzfzf1|f1|f}f}fzfzfff$wf$wfff{xf{xfW}fW}fffKfKfbgbgZZAEAEٙٙcc{{{{扙扙c~c~rrz}z}||${${댙댙9z9znnww<wf>wfff4xf4xf>f>fqfqfpfpf1f1fggVVyy!!||qq<<33††ÈÈ++__~~JJK|K|ww{{zznnyy؎؎bxbx x x뎙뎙yyččzz } },,nnڄڄ3322~~))s}s}''zRzR=g=gffFfFfififfftftfffufuffftftf[f[fsfsfffrfrfffrfrf|f|fGqfGqf݆f݆fpfpfffpfpfffqfqfffsfsfCfCftftfffvfvfffOyfOyf2}f2}fm}fm}fzfzf]~f]~fwfwffftftfބfބfqfqf f fofofʉfʉfqfqfsfsfff__****OOLL$$llrr##!t!tYYcucuTTvvcxcx''bybyyy"z"zČČA{A{||}}䀙䀙QQĀĀ~~VVD}D}yyrr``\m\miiݟݟ\l\ldd{{ݔCCggffXfXfSfSfffefefhfhfjfjfTfTfjfjffflflfffoofoof0f0f8qf8qfGfGflrflrf؄f؄fEufEufffvfvfffwfwfffxfxf~f~f{f{fzfzfW~fW~fNxfNxf@f@fvfvfPfPf@sf@sfff"qf"qfffmfmfffififffu`fu`fxfxfSfSf7f7fxPfxPfjr>rӖӖpp00nnf>fxfxf~f~fzfzf|f|f{f{f|f|fs~fs~f)wf)wf f fsfsfRfRf{f{f[f[f{>{JJw{w{یی z zǎǎjwjwttssWWpplmlm͝͝ddXXHFHF''fnfnLL""1c1cffufuf;bf;bfffdfdfffFjfFjfRfRfmfmfjfjfrfrfffvfvfffvzfvzf|f|f}f}fyfyfNfNfwfwfffwfwfffvfvfffDufDuftftfrfrf`f`fqfqfCfCfofofffmfmfΊfΊf?mf?mf(f(fmfmf\f\fnfnfff|kf|kfff^f^fff f f g gKKdydySS7 7 鉙鉙rrssjj1y1yVV'}'}ff~~jj  D~D~II|}|}99w{w{ǍǍzxzxccfxfx??xxjjxxxx;;yy썙썙zz⌙⌙{{r}r}݉݉E{E{˓˓JaJa+ޙ+ޙ::cc  [[MgMgUfUfnfnfہfہf7uf7ufffwfwf$~f$~f{f{f{f{f}f}fyfyf~f~fxfxff>fggGpEGpEߜSSrr k k$q$quu{{""}}yy>>~~F~F~ʊʊ{{ĎĎwwuuMMwwxxyy,,S{S{ww_x_x`t`tFFllhhOO|(|(  6_6_ggqfqfqfqfffofofKfKfZsfZsfCfCfwvfwvfTfTfxfxf}f}f|f|f{f{fHfHf/xf/xfffkufkufBfBftftfffrfrfffrfrfff3qf3qfffrfrfޅfޅfrfrfnfnfrfrffffrffrfwfwf`qf`qfffpfpf!f!frfrffftftffflflf,f,f&f&fgg@T@Tjj&&CC}x}xԃԃRRPPxx⃙⃙WW~~̉̉K}K}犙犙{{XX{{{{__{{틙틙||ZZ6|6|#{#{11zz^{^{zz|||| ~ ~RR؀؀]]RRvv__..xUxUgg-f-f;f;fnfnfff_tf_tf?f?fatfatffftftfffEtfEtfffsfsf҄f҄frfrf f fsfsfffPrfPrfυfυfIrfIrfffqfqfffqfqfff!tf!tfكfكfvfvf^f^fy>yFxFxvv)x)xwwyy}}{{||}}剙剙~~툙툙**eeˈˈ}}ii[z[zvvoojjbbuuCC66GGggffffUfUf`f`fefeffflflfffmfmfZfZfnfnftftfofofffqfqfЅfЅfsfsfffssfssfffWsfWsf˄f˄fDtfDtfffxwfxwf<~f<~fw{fw{f{f{f~f~faxfaxfTfTfxfxfyfyf=vf=vfƒfƒfqfqfffYlfYlfffgfgfff`f`fffVfVfffJlfJlfIsdIsdh)h)˘˘NN왧FFnenell\q\q--TuTuvvÐÐvvmymyzz } }JJ備備tt}}44z{z{ jyjy ww瑙瑙rrpqpqޘޘllٞٞbbJJ̙̙!֙!֙llI4I4*f*f4f4f8f8fPfPf^f^fafafffffffݎfݎfjfjfufuf5lf5lfΉfΉf^pf^pffftftfفfفf?xf?xfffyfyf4~f4~fzfzf}f}f{f{fb{fb{f&~f&~fxfxfffbufbufnfnfpfpf^f^fofofֈfֈf|pf|pfffaofaof-f-flflfȍfȍfhfhfffvafvafffNQfNQfff-f-f6g6g8>8>^^’’\\BBff}}mm=r=rIItt77wwszszaa}}ɁɁ""\\ } }yyxxnnxxHHwwߏߏ,w,w@v@vuummuuJJrrѕѕppgg䨙䨙JJIIs޸s޸dadaMfMfffffffÑfÑf*hf*hfffImfImfKfKfrfrfffufufff{wf{wfffxfxf}f}f{f{fS|fS|f?}f?}fbyfbyfffvfvf{f{fxsfxsfMfMfrfrf@f@fqfqfffpfpfIfIfofofZfZfofofffofof׈f׈fnfnfffLnfLnfŊfŊflflfff%af%afffff5g5gcNcNThThyy昉ووyyOOxxf|f|ddFF[[ꃙꃙ44nnf}f}g{g{QQByBy""QxQxRRwywyyyÍÍzz܍܍yy$${{3|3|~~݀݀N}N}(( e eՙՙOO  YY[rg[rgmGfmGf\f\f|f|fyfyf~f~f {f {f/{f/{f]~f]~fxfxfffvfvfffsfsfffrfrfffgsfgsf؃f؃fUtfUtfff{tf{tfτfτfrfrfffqfqfffrfrfrfrfsfsflflfsfsfffvfvfff:zf:zfN}fN}fzfzf6}f6}f{f{f{f{f}f}fzfzf6{f6{fWfWfLfLf`ag`agsZsZEëEëCCtܙtܙ ` `""LxLxrr}|}|??}}ъъ||ƋƋAzAzxx4x4x00AzAzЌЌ{{{{||5}5}x}x}䉙䉙W~W~وو,,44llG~G~EE${${xx~x~x;;攙攙pp͠͠lMlMcgcgPfPfįfįf]f]fMfMfXjfXjfߋfߋfomfomf f fmfmfffnfnfffnfnffffoffof f fofof f fpfpf2f2fsfsfffufufKfKf6vf6vfffwfwf:f:fzfzf|f|fX~fX~f xf xf5f5ftftfffsfsf؆f؆f pf pf?f?fkfkf f fffffffrcfrcfkfkfffzbzb:+ :+ ss5Z5Z]]GG$$eeFFnnޖޖrr֓֓uuuuDDuuKKVvVvwwxx獙獙jzjzj|j|--yyqqԅԅ퀙퀙{{}}44zzrxrx--.t.tҔҔpplklkpcpcJJZZ**T)T)UUԂS>xxWWGxGxxxCC!y!yԍԍ0z0zƌƌ||}}..……==^^nn }}ىى~~44''&&RRggS!fS!f/f/fhfhf1f1fsfsfTfTfsfsf3f3fqfqfffofofffqfqfɆfɆfqfqf8f8f&qf&qḟḟfqfqfffIrfIrf1f1ftftfKfKfsfsfff vf vfffxfxfx~fx~fzfzf8}f8}f{f{fzfzf f fwfwfffsfsfօfօfpfpfffmfmfffnfnfUvfUvfffB_B_ńńA.A.OPOP9n9n--tt x x%%xxԎԎwwxxNuNuuuxvxv\\vxvxzzϋϋ } }r~r~ЇЇ____||77CzCz__=x=x퐙퐙tt۔۔qq˙˙jjpmpmcc=|=|ݶCCܒgܒgff,f,fRfRf4f4fcfcfffhfhfώfώfjfjfffkfkfffofofffsfsfffHtfHtfRfRfTufTufׁfׁfZwfZwfffwfwfffxfxfV~fV~fO{fO{fL{fL{fffowfowfbfbftftfffqfqfffofofffWlfWlf֍f֍fhfhfʒfʒfafafff!Vf!VfBfBfTfTf7e7e--źP#P#♍GGicicllppss33FvFv22SxSx55zzzz{{~~~~QQ++^^~~zzwwtt֓֓rr+p+pkkҟҟ}b}b<<IIۙۙAYAY((ǂ 0 0eeFfFfffPfPfٟfٟfL^fL^fffZgfZgf@f@f>lf>lf*f*f=of=ofևfևfrfrffftftf݀f݀fyfyf~f~fzfzf|f|f{{f{{fd|fd|fz}fz}f"yf"yfffufufff/sf/sfƅfƅf/rf/rfffpfpf҈f҈f?nf?nfffmfmfffkfkf]f]fhfhfffBafBafqfqfRfRfPfPf f fvgvgAAr'r'vvttee䣙䣙/g/g\o\o\\tt͐͐xxoozz66}}''qq~~&&0{0{>z>zXzXzŒŒR{R{ЌЌyyՎՎww7v7vِِwwvvsskkfk>feej02j02Ɉ әәJJcc柙柙jjmmqqNNuuzz||"}"}҉҉~~ff''SSW}W} /z/zww--)w)wovov77;t;tTT.r.r__jmjmKKcc||EEQQÓ++dd2af2af6f6fRVfRVfHfHf1`f1`fffefef̏f̏fkfkf]f]fnfnfff5sf5sfsfsfufuf܀f܀fIyfIyf}f}f|f|fzzfzzfffwfwfffwfwfffufufЃfЃfsfsfffpfpfffpfpf̈f̈fYnfYnfff:mf:mf׋f׋flflfffajfajfffefef{f{fTfTfffff٦g٦goEoE߮``SS(q(qEEjj((pp uuCCyyW}W}00灙灙?? ZZĉĉG}G}{{ZZzztxtxMMvv\\4x4x⏙⏙bwbwHH w w\w\wuuSSnnQQVV++ii2_2_ggnfnfrfrfffkfkfSfSfqfqf{f{fxfxf}f}f[{f[{fu}fu}fzfzfh~fh~fT]>T.n.n>>PPp{p{ >>33TT**~~==1|1|{{~z~z֍֍xxxx썙썙zzzz..GzGzAA{{jj}}++&&vvɂɂwwɍɍ==zwUzwUgg+f+fffnfnffftftfKfKfufufffwfwfcfcflvflvfHfHftftflflfkrfkrfĆfĆf[pf[pfffqfqfffqfqf>f>frfrfʄfʄftftfffvfvfˁfˁfYwfYwfxfxfwfwftftfuyfuyf|f|f|f|fzfzf~f~fmxfmxf$f$fvfvf>f>frfrfffwfwfhfhfggo^o^##--**홇UUrrwwSS=v=v++#t#t tt uuAAwwݎݎ+z+z+{+{ꋙꋙE|E|{{oo~~ℙℙJJ99nnFF4~4~D{D{qquu>>qq͘͘mmSSKxKx]B]B66R GR GKgKg f fLfLfXfXfff`gf`gffflflf#f#fnfnfff nf nfXfXfcnfcnfډfډfnfnfffnfnfRfRfnfnfNfNfqfqffftftf}f}f0wf0wfgfgf{f{f4{f4{f\f\fWwfWwfՁfՁfufufffsfsfffpfpffflflf#f#fwifwifБfБfafaf#f#fUfUf˦f˦f jf jftdtd;i);i)˘˘왑EE,,*b*bppwlwlnnssuu@@vvQQ6x6xzzAA{{vv6|6|zzi~i~nn}}܋܋]z]zxx66vvPuPu~q~q~~kkVVbb<kf>kfffdhfdhfՒfՒfvafvafmfmfQfQfbfbfff2g2gU=>U=>33ֹ]]ee<>HzHz00zz::yywwvv x xʎʎzz33||^^ÇÇ..llAAR|R|yyޏޏuu%%uullʠʠ!lM!lMFgFgmfmf٭f٭f0_f0_fffmfmfffeqfeqfUfUfofofffcnfcnfӉfӉf of offf|of|of߈f߈fofofffqfqfRfRf>rf>rffftftfRfRfufuf؁f؁f9wf9wfff{f{f|{f|{f=~f=~fwfwf(f(fktfktfӅfӅfqfqfff0pf0pfDfDfmfmfffififۑfۑfdfdf֌f֌fff|b|b3( 3( --WWnnDDϬϬ8e8e nngsgs󓙆tt ttww xxQQp|p|~~++ӇӇ!!UUׂׂ݆݆~~7{7{ээxxvvQqQqqlqlff[[֜֜,(,(5W5WpRrf>rfۄfۄftftfDfDfufuf=f=f!xf!xft~ft~f}{f}{f{f{f~f~fwfwfׂfׂfsfsf_f_fpfpfffofofڇfڇfqfqfffpfpfufufofofffnfnfffnfnf؋f؋fIkfIkfffbgfbgf&f&fXfXfڴfڴf f fggHH乜00l1l17}7}AA.n.nppss\x\x||||bb~~yynnXX燙燙LLD~D~||ŌŌyy]]xxOOxx᎙᎙xx|x|xwwCCww##gwgwssJWJW陂陭--]]*g*gbfbfxxfxxfpfpfqfqf܅f܅ftftf4f4fdyfdyf|f|f ~f ~f0yf0yfOfOfxfxf f fxfxfffUwfUwfff tf tfńfńfrfrfdžfdžfqfqfԅfԅfqfqfffXrfXrftftfqfqfff:rf:rfff tf tfffufufHfHf{vf{vfXfXfvfvfffwfwfffpfpfAfAf0f0fVgVgVVwwI$I$|z|zÙÙjojoƊƊff++yy’’nnWWU}U}䊙䊙U{U{yy66yy錙錙zzSS&z&zzz-{-{||]];{;{||aaHH~~4|4|ddp~p~୙୙((&&IRIRgggg.f.f}f}fhfhf7f7f.sf.sfffztfztf߃f߃fsfsfffqfqf߇f߇fofof|f|fpfpfffqfqflflfrfrfff]qf]qfffqfqfffIsfIsfffcvfcvfffUyfUyf&~f&~f{f{f{f{f|f|fzfzf~f~fxfxffftftf0f0fpfpfWfWfHlfHlfffpnfpnfvfvfff__m-m-iMiMmmMMKuKuuutttt))QuQu㐙㐙ww||ixixsysy]]{{ ~~((؀؀݆݆\\ tt77||ÌÌczczAACwCwqqgjgjJJmmbbXXlzlzݽCCcgcgffffOfOfff,`f,`fffgfgflflfmfmfӉfӉfofof}f}fBqfBqfYfYfpfpfffHpfHpfffpfpfffQufQuf4f4f)xf)xf}f}f{f{f2}f2}f{f{f {f {f<~f<~fxfxfrfrfufufff@rf@rfffnofnofffjfjfefefefefffP`fP`f˜f˜fUfUfffQUfQUf7e7ey-y-Œŗ$$FF쯙쯙bb蟙蟙jjnn××GqGqzz(u(uRRXxXx{{_|_|,,F~F~OÒ̀ccNNсс00O~O~{{ooYyYyxxAAuu哙哙rrѕѕppiilliiaaGG#ܙ#ܙ]Y]YǍ 0 0*e*e!Jf!JfffCUfCUfffZafZafffffff:f:fRjfRjfČfČf+nf+nf6f6f>qf>qfZfZftftfWfWfufufffxfxf}f}f|f|f4{f4{f~f~f xf xfʁfʁftftfJfJf tf tfff?tf?tfffAqfAqfBfBfomfomfff>jf>jfffjfjfofof)if)ifyfyfcfcfofofRfRf}f}f f f9xg9xg|A|A(۸(twtwssffעעMgMgllss{{#z#zЊЊr~r~ ]]OO11,,ՉՉN|N|yy,x,xEEiwiwSSvvtt t tssssllee N N33``{f{f|f|flflfffrnfrnfWfWfpfpf}f}fxrfxrfff7uf7uf€f€fyfyf|f|fq|fq|fzfzf~f~fxfxfɀfɀfufuf9f9ftftfHfHfXtfXtf+f+fTsfTsfffrfrf f fpfpfffWpfWpf݇f݇f qf qfffrfrfOfOfqfqfچfچfqfqfÆfÆf5pf5pf8f8fOffOffffffggQQee??[Ø[Ø!! ||||މމ**肙肙..}}؊؊||{{zz{{ߌߌzzxxvvttxxmmr}r}͇͇00ĂĂ愙愙鋙鋙lləə;k;k99WWXgXgE7fE7fՑfՑftftf~f~f5zf5zfififiwfiwfff`vf`vf1f1f#vf#vf.f.fEvfEvffftftfffRsfRsfffqfqffftsftsfffsfsfffrfrfffsfsfʄfʄfysfysf[f[fufufWfWfwwfwwf~f~f{f{fJzfJzfffwfwfffvfvfffvfvfdfdf7f7fvXfvXf?g?gH\H\Q Q WWv3v3䙼䙕[[ttxxRR z zee|z|zSS#y#yww֐֐ZvZvܐܐvv^^`w`wSSyycc||++*~*~;;ggꆙꆙ䁙䁙 ??ᇙᇙ||ӌӌxx??tt╙╙pp77]]3_J3_JOgOgw fw fffp\fp\f̒f̒fKjfKjfkfkfzlfzlf[f[f/nf/nfffmfmf@f@fmfmf+f+fofofۈfۈfofofSfSf2rf2rfffTufTufffwfwfffyfyfY~fY~f5zf5zf?~f?~fyfyf~f~f:{f:{f{f{f~~f~~fwfwfffoufoufffpfpfffifif^f^f`f`fDfDfYfYfkfkfffϊcϊcE$E$DDoomeme$p$pJJXsXsKK>s>sttvvNNwwAA7z7z~~<<22˄˄))G~G~yy{{ꌙꌙyyruruQpQpjjbbQQ o o..ud8ud8ffi%fi%fffNfNfff=\f=\fffcfcfEfEfhfhflflfomfomfLfLfpfpf&f&f`tf`tfffDwfDwfffxxfxxf~f~fzfzfx~fx~f{f{f{f{f|f|fyfyfff~vf~vfTfTfZsfZsfofofpfpfff>nf>nffftlftlfvfvfkfkfԍfԍf1hf1hf̒f̒fafafff4Tf4TfffCfCfff_:_:b#b#ҀŚŚQQmSmSN`N`̢̢hhppoossˑˑww{{   ZZ邙邙AAcc88ɈɈ~~;};}zzjj\x\x󏙣vvtt44-t-tqq;;mmdd㫙㫙'G'Gttpp*K*KI"I"ccffēfēfD`fD`fffffffffkfkfffnfnf܈f܈fqfqf.f.f?vf?vfxfxfxfxf}f}f{f{f|f|f|f|fzfzfffwfwffftftf˅f˅fqfqf߆f߆fdpfdpfffpofpofff nf nf}f}fofofffnfnf f fnfnfBfBfofofffkfkfff]f]fff f fJgJggKgK{{; ; &&䐙䐙ss̒̒MvMv3z3z}}ׇׇȄȄ؄؄ƀƀ 臙臙77s~s~B|B|⌙⌙xxSSwvwv88uuww..;y;y__yy{{55}}ӋӋfxfx\\r8r8  [[PgPg/Rf/Rfff[f[fxwfxwfffyfyfS~fS~fzfzf"}f"}fT{fT{f{f{fffvfvfɂfɂfsfsfffrfrfffqfqfKfKfrfrfffqfqfffsfsfffufuf*f*f>LLooYYaap|p|zz||јјee%KP%KPggff#f#fbfbfόfόfpfpfffrfrf˅f˅fYrfYrfff^pf^pfffofofff;of;ofYfYf0of0of_f_fofof!f!fpfpfQfQfEsfEsf~f~fvfvfffryfryf}f}f{f{fe|fe|fo|fo|fzfzf~f~fxfxfffMwfMwf?f?fsfsfffnfnfffUjfUjfffififff5f5fIaIacc?;?;::\\II!i!iuuppss}}ssssuuvv.w.wzzpypy||$$~~ ˀˀ..jj\\؈؈}}5|5|ssww??7u7uXX(o(o|f|f((__QQr@r@uWguWgxfxfWfWfSRfSRfYfYf af afffcgfcgfffajfajfȌfȌflflfffnfnfΈfΈfofofGfGfqqfqqffftftf6f6fxfxfW}fW}f{f{f3|f3|f"}f"}f#{f#{f|f|fzfzf~f~fxfxf؁f؁ftftfyfyfTrfTrfff(qf(qffflflfff$hf$hf“f“f_f_fff@Qf@Qfqfqf:f:fee,2,2ɉ>>)ՙ)ՙJJ**+a+a|j|j2o2oeeRsRs w wlzlzRR}}pp]]==nn||zz{{> G G''tt6+6+ddQ`fQ`fffUfUf͜f͜f_f_fffWgfWgfffUmfUmfffmqfmqfWfWf!rf!rf:f:fsfsfififHvfHvflflf%zf%zf{f{f}f}fRyfRyffftvftvffftftfRfRfqfqfƆfƆfVqfVqfffffofofffmfmfffkkfkkfffjfjfZfZfififffdfdfSfSfUfUfff f fggOpEOpE߭PRPRrryyjj››mmstst͏͏{{GG  ffꂙꂙĂĂqq||qq||cc{{ll{{99szsz̍̍zzwwyyŽŽtxtxvvTTSwSwTT/u/uǔǔnnYYQQ++3_3_ggpfpf~qf~qf+f+flflfffpfpf_f_fttfttfffwfwfff zf zf|f|f}f}fxfxfffufufnfnf uf ufffrfrfffofofffnfnfوfوfofofˇfˇfqfqf_f_fvsfvsfHfHftftfffsfsfffsfsf\f\ftftfǃfǃfsfsfGfGfVlfVlfff%f%fݺgݺg>T>Tllxyxy//""{{āāLL 瀙瀙 8|8|aayyzz$|$|$$||kkw{w{ጙጙ.z.zɎɎxx{{ҊҊV~V~ЅЅ胙胙ނނ҂҂҈҈ss܌܌ZvUZvUGgGg *f *fMfMflflfnfnfeufeufffwfwfffvfvfwfwftftfff%uf%ufffsfsfff4qf4qfffofof f fpnfpnfˆfˆf|pf|pf{f{frfrf f f]tf]tfff7vf7vfffyfyf$|f$|f}f}fzfzfffhxfhxfffvfvfffWtfWtfffOsfOsf9f9fyfyfdfdfggl^l^((RRߠߠnn:u:uvv::wwƏƏMxMxxxkykyffxxyyɍɍzzzz}}uuځځccBBFF>>{{ZZyy~v~vTTCsCsbnbnwwCC66!G!Ggg f fpfpfnYfnYf.f.fgfgfSfSfjfjffffjffjffflflf%f%fofof?f?fgqfgqfӇfӇfnpfnpfffDpfDpfxfxfrfrfffufufZfZfyfyf3~f3~fzfzf|f|f|f|f{f{f}f}fwfwfgfgfsfsf͇f͇fnfnfʊfʊflflf4f4fSifSifqfqfafafffWfWfʣfʣf^mf^mfrdrdj)j)PP"ɘ"ɘ_D_D;;%a%a{{RkRkwwppss@w@wƏƏXyXy1{1{ʌʌ}|}||~|~WWրրՅՅ~~ۊۊ{{44yy׎׎rwrw&&vvkqkqYYkk>`>`GGuKuKU̙U̙UՙUՙffˡH4H4*f*f4f4f0f0fYSfYSfffw`fw`fffgfgf4f4f!lf!lfMfMfnfnf f fofofLfLfpfpffftftfff+yf+yf}f}fZ{fZ{f|f|f|f|fyfyfffwfwfpfpf4uf4ufƂfƂfsfsfffff.of.offflflf.f.fmfmfKfKflflfufufififՑfՑf0bf0bfffQfQf9>֍ᑙᑙ]]ffݝݝ l lrrwwOOzzzzm}m}ՇՇ{{⃙⃙ᄙᄙшш}}zzތތS{S{UzUz\y\yBBkwkwܐܐvv!!uuNNCtCtmomo g gGGIHIH߸߸//aaffffffffffgfgfՎfՎfkfkfffpfpfffrfrf\f\f:vf:vf+f+fs{fs{fyfyfffwfwfffvfvffftftfffMsfMsfOfOf{sf{sfff|qf|qf(f(fSqfSqfΆfΆfqfqfffqfqfЇfЇfofofvfvfFofFof*f*fofofȈfȈfmfmfff`f`fffBfBf.g.gNNhhII嘯嘠zzxx팙팙Y|Y|PP$$z~z~AA}}@@-|-|{{=={{``xx))xx++_x_xxxbbXxXxuuJzJzFF?}?}yyMM22||ҐҐee|ՙ|ՙzPzPYYYY ug ug Df Dfffyfyfrzfrzf~f~fzfzf|f|f}f}f2xf2xfffcufcuffftftf8f8fufuffftftfff_tf_tfffjtfjtfτfτfrfrfhfhfpfpfJfJfpfpfffqfqf!f!f*uf*ufffvfvfffyfyf|f|fT}fT}fkzfkzfm~fm~fxfxfffyfyf{f{fffHKfHKfwbgwbgZZ««6C6C&ܙ&ܙs`s`ww܌܌l|l|||WW}}቙቙}}==x|x|yyzzBByy##yyxx鏙鏙NxNxpzpzOO}}ՈՈ~~HHDžDž؃؃ځځOOT}T}``yy掙掙ww(w(w䋙䋙--MM'̠'̠lMlMRgRgffcfcfK^fK^f(f(ftkftkfffnfnfffofof؈f؈fgofgofffmfmfffnfnfffFofFofqfqf_rf_rfffwsfwsfffvfvfffwfwf f fxfxf1~f1~fzfzfZ}fZ}f{f{f{f{f}f}fxfxfgfgftftfffqfqfffkfkfffdfdfffafaf̎f̎fffH~bH~bf' f' }}VVkk`E`E?g?g皙皙pp:: t tYYCuCu~v~vaawwxxZZyy[[{{}}qq ))ÀÀjj^}^}zzuuzozoeekkdd..[[<<&&YYԎP>ׇׇyyɆɆ{{zzHH^*^*TRTR9g9gWfWfTfTfhfhfffsfsffftftf5f5fsfsf`f`fXsfXsfЄfЄf9sf9sfff=qf=qfDfDfnfnftftfSofSofΈfΈf5pf5pfff@rf@rfffff=sf=sffftftf0f0f[vf[vfffzfzf{f{fD~fD~fxfxfffvfvfffasfasf}f}f&qf&qfIfIf5mf5mf2f2fppfppftftfefef__//++MMll͕͕\t\tJJ$w$wwwvvGwGw}}iwiwPyPydd{{PP||-- } }~~샙샙܅܅LL`|`|yyzz11nvnvGrGrjjןן0l0l9d9d||CCggggI fI fvfvfUfUfffdfdfffngfngfNfNf]if]if!f!fRkfRkfffmfmfFfFfbpfbpfffrfrfffRtfRtfffvfvfffwfwfffxfxf~f~f{f{fzfzf1f1fwfwfffufufffpfpfffmfmfafafKjfKjfffhfhf'f'fbfbfzfzfXfXfffUfUf}7e}7e;-;-ĠĠd!d!器DDOO ` `柙柙llԗԗ{r{rttuuuuddxxuuj{j{{{{{RR~~tt;;xx~~z{z{捙捙xx!!wwܑܑttDDvqvqnnppVVmmddIIۙۙYYHHǷ 0 03e3eGfGfǯfǯfQfQf˞f˞f{_f{_fdfdfgfgfrfrfmfmfȇfȇfqfqfffrfrfffsfsf4f4fvfvfhfhf+{f+{f{f{f}f}fyfyf~f~fHzfHzfl~fl~f xf xfɁfɁftftf*f*fqfqf]f]f~pf~pf^f^fnfnfffmfmfXfXfkfkfjfjfPifPifffbfbfҚfҚfRSfRSfǹfǹf1 f1 fxgxg A A''vvtt@f@fhhngngHnHn<>))||zza{a{ {{ًًzzyynxnxyyʍʍzzSSzz&&pzpzjj>z>z""zz[v[vy\y\ 99  $[$[7Sg7SgqOfqOfff~f~fAvfAvf\f\fvfvfffT>TNkNkww00KK``cc>>YY}}PPzzύύhyhyuu,w,wWWwwqyqyjjzzg|g|~~ZZ;;gg&~&~jj@@҅҅ℙℙww''ZZ]]wUwUgg'*f'*fgfgfnfnf=f=fwfwfffwfwfrfrf9>ŗŗ֌ZZddZmZmssՑՑxx֍֍}{}{󊙍}}WWffYYmmɆɆֈֈ`~`~̉̉{{yy>>uwuwݐݐvv""f>fpfpfff\of\ofLfLfunfunfffkfkfBfBfhfhfff bf bfffSfSfff f f'vg'vgfAfA((iuiuuu3e3e>h>h44oo$$ytytXwXw:z:zv|v|**ddڃڃ**~~z}z}ll{{cc{{~~xxfwfw 3w3w==gvgv˒˒ssrrHHGqGqjjzLzL33tt]`]`ffmzfmzfmfmfffjfjfffofofffrfrfffufufSfSfyfyf|f|fQ}fQ}fyfyf f fwfwfԁfԁfqufquf_f_fbrfbrfXfXfrfrfօfօfbsfbsfɃfɃf|tf|tfffsfsfffpfpfff`qf`qf$f$fpfpfYfYfrfrf#f#frfrf|f|fpfpf@f@fefefץfץfffggקQקQeeO@O@I˜I˜ttaaX}X}yy||``\~\~**솙솙n|n|R|R|||{{llUzUza{a{틙틙e{e{όό z zxx..Y{Y{[~[~ƀƀHHننi~i~33kkəəAkAk : :WWݓgݓg7f7fffsfsfffyfyfffwfwfffYvfYvfffufuf"f"ftftf̄f̄frfrfffUrfUrfbfbfrfrfffrfrfffrfrfff sf sfffwsfwsfffufufkfkfrwfrwf~f~fzfzfE}fE}f{f{f[{f[{f}f}fuzfuzf~f~fPxfPxfffdwfdwfffffff4Xf4XfS?gS?g1\1\  XXd1d1YYtt44yyOOyy~x~xggww33ww֏֏xx yy[z[z͌͌{{鋙鋙%|%|``A}A}}}ll{{ĂĂRRLL{{UU~x~xss77ypyphh !!\\  i^Ji^Jgg f f f fQ[fQ[fofof'if'ifff\mf\mfffnfnfffnfnfffnfnf f f;pf;pf~f~frfrfffsfsfffrfrf"f"fsfsf}f}ftftfffEwfEwfJfJf:{f:{f{f{f?~f?~f>wf>wfVfVfufufffqfqfffnfnfffififbfbf+bf+bfafaf[f[fffffcc$$NN]]bCbCOdOdnnrrRRssɒɒRuRuvvxx&}&}v}v}ffZ~Z~PP ؆؆||]y]yuu֒֒tt,,ssooeejSjSnn~~1a81a8ff#f#fffwPfwPfOfOf^f^f,f,fXdfXdfffififff mf mf$f$fofofffpfpfff\tf\tfffYvfYvfIfIfyfyf|f|fH}fH}fszfszf~f~fuyfuyfffwfwfff4rf4rfffmfmf5f5f=kf=kffflflfOfOfifif f f5ef5efff/af/af֛f֛f Tf TfMfMf f fLfLfEa:Ea:>!>!ǚǚ{{UUcc=e=eɝɝmm5q5qbtbtiiwwΎΎzzzz}} ~~^^~~||::xxJJwwvvMMuuqqkk n nddeEeEnnLL؄"؄"ccff۔f۔fV^fV^fߗfߗfbfbfŒfŒf]hf]hfffmfmfʈfʈfqfqfLfLf,vf,vfff7{f7{fqzfqzfffwfwfffvfvfffwfwfhfhfufufwfwfysfysfffrfrfffqfqfMfMf"pf"pfTfTfy>y**zz֍֍xxyy̍̍zz匙匙{{&&||銙銙}|}|ww<<'_'_yߙyߙ;;  [[YPgYPgQfQfԃfԃf&~f&~fYwfYwfffluflufffwfwfu~fu~f{f{f:{f:{f~f~fwfwffftftfffsfsfff2sf2sfffrfrfԆfԆfKqfKqfff rf rfffsfsfvfvf=sf=sffftftf f ftftfǂfǂfufufffxfxf~f~fJzfJzf~f~fyfyfffufufffF=fF=fggXXll[[ZZҙҙee{{ۈۈ߀߀11ss}}\z\zffUzUzUyUyAzAzyyyyȎȎxxDDvzvz||ccUU{{~~))||!!zzZZԘԘccIPIPggff~f~f`f`f{>{}}}}ӅӅ::~~%|%|__1x1x/v/v''^s^s t t┙┙qqii~l~lccFFoo>>kkî++ddbfbfffYfYfffbfbfffxgfxgf>}}yy||UUzz y yRwRw'' x x&&QyQy~~zzg|g| [}[}hhmmbbttwwwUwUEgEg*f*f<>\\99\\dd͟͟4k4kYYCqCqՓՓvv>>yy拙拙q}q}YYiiӆӆ聙聙aaԁԁ77}}~~{{__dzdzwzwzMM%y%yxxttrrrrpphhCICIII޸޸!!mamanfnfffdfdfffcffcffff4lf4lfffqfqfff?uf?ufffrxfrxf~f~fzfzf|f|f|f|fzfzfffxvfxvfUfUfysfysfff{qf{qfOfOfpfpfNfNf-rf-rfTfTfrfrfffUrfUrfxfxfqfqfffrfrfffErfErfGfGfXofXofffjfjfff"]f"]fffffggYNYNhh铡铡\\癙癙yyyyFFN{N{ωω__eeSS~~~~99}}{{``xx22wwڏڏyy닙닙}}''K}K}II||w}w}.~.~}}aazzccייMMmm  YYtgtgHDfHDf@f@fCyfCyf>{f>{f}f}f{f{f|f|f^|f^|f{f{f|f|f8zf8zfVfVfufufffqfqfffVqfVqf8f8f0rf0rfffksfksf,f,fyqfyqf?f?fpfpfffHqfHqfAfAfsfsfσfσf~uf~uf,f,f wf wf&f&fzfzf|f|f|f|fzfzf9}f9}fzfzf}f}fzfzf,{f,{fqfqfkLfkLfPagPag}Z}Z339«9«DDٙٙ^c^cwwzz芙芙L|L|KKd|d|{{{{KKzz،،zz:y:yxxwwŎŎ#z#zKKW|W|{{ًًu|u|~~恙恙ффʂʂuuO{O{__}u}u~~rr''22[ˠ[ˠmMmMggffԬfԬf`f`f%f%fmfmfffofofff7of7of f fofofff"of"offfMofMof͉f͉fnfnf]f]fMpfMpf1f1f0rf0rf~f~fsfsfffvfvfffzfzf|f|f}f}fvyfvyfNfNfZyfZyf~f~fyfyfp~fp~fxfxfffqfqfffjfjfff ef efݔfݔf_bf_bfffefef}b}b( ( aYaY[G[G33YfYf== m mPPbqbq66cucuڑڑvuvuڑڑuuwwzz$~$~((oo99vv[[PP燙燙Z~Z~NjNjzzhhvv6s6sqqnnZdZd..WWѡѡ$$XԀX^S<^Sf>fFhfFhf4f4fafafffVfVfCfCfTfTf7e7e - -##♺FFMM__hh盙盙nntt226v6vllwwyy6|6|ee%%11!!ꁙꁙ}}zzxx22wwTuTuQQooNN5i5i&&s^s^wFwF]ݙ]ݙWWǻX 0X 0 e eMJfMJfffTfTfffffM`fM`fUfUfefef~f~fjfjfffKpfKpfxfxfsfsfffBvfBvf&f&fwfwfffvwfvwf#f#fyfyf%}f%}fJ}fJ}f=xf=xffftftf_f_fqfqfXfXfpfpfffqofqofffnfnfffnfnfffkfkf~f~fjfjfffcfcf[f[fQfQfZfZf f fwgwg]A]A&&&w&wssggܡܡPiPiqqttvvyy{{~~ʆʆӂӂGGuu߀߀^^}}zz̍̍~y~yBBww--wwww吙吙vvҐҐuuڑڑawaw鏙鏙vv``ttjjKK1188գ`գ`ff|f|fkfkfafafkfkfffDofDofŇfŇf\rf\rfffvfvfff@zf@zf }f }f|f|fzfzf/f/fUwfUwffftftf)f)frfrfffqfqfvfvfqfqf f f.sf.sfffqfqf+f+fqfqf'f'fqfqf.f.fqfqfׅfׅf]tf]tf4f4frfrfffpfpfKfKfYefYefafafffggQQff??2Ø2Ø5588{{_z_z}}aaMM~~}}{{yyyyAAzzፙፙyyŌŌzz V{V{ yyezez~~>|>|bb~~WW텙텙BBCCll%ə%əll77WWgg8f8f+f+fvfvfy|fy|f}f}f|f|fzfzf|f|fMwfMwf:f:ftftfefefrfrfffqfqf f ffpffpf f f>~~zzՎՎvv&r&rAA::]]C C !^J!^Jgg f fUfUfYfYfffhfhf@f@fmfmfyfyflflffftkftkf=f=flflf#f#f>nf>nfffZpfZpfІfІfrfrfYfYftftfffkvfkvfffwfwfff1zf1zf}f}f{f{fM{fM{f}f}fxfxfԁfԁfntfntfffpfpfffmfmfffififffff:bf:bf2f2f9\f9\fff-f-fcc$$EEccmmqq&&ssגג1v1vԐԐ1x1xzzYY{{ ~ ~ffr~r~ {{ÃÃЄЄ؁؁!!}}zzggxxss,,oojj ddSS##ppψJc8Jc8ff[$f[$fdfdfPfPfffZ_fZ_fffffffffjfjfgfgf kf kfۋfۋfnfnfzfzf>qf>qffftftfffvfvfff7zf7zf/|f/|f^}f^}fzfzfQ~fQ~fyfyf\f\fmwfmwfāfāftftfXfXfqfqfffwofwofffmfmfÌfÌf7if7ifff=ff=ffff`f`fffPfPfOfOfffff]:]:$ұ$ĚĚ묙묙hThTઙઙddenen||rrnnuwuwyyȍȍzzgg5}5}牙牙AAc~c~||szszww**uu JuJu+s+s668q8qWWllee&G&G44sosooKoK""KcKc^f^fffbfbfffefefffhfhf9f9fkfkfffpfpfDžfDžfFtfFtfff6xf6xf}f}f|f|fuyfuyfffufufafaftftffffuffufSfSfGtfGtfąfąfqfqfHfHfpfpfsfsfpfpf@f@f@of@of"f"fCofCofffpfpfffofofafafjfjfƒfƒf\f\fff f f*g*gxKxK}}  MM66ssvv?v?vmm:{:{~~II ɂɂ녙녙OO||싙싙zzaazz55]{]{׋׋Q{Q{zzyy))HyHyDDxxȍȍ{{ }}{{YY5u5u\\//.;.;  [[cPgcPgSfSfffff.uf.uf f fvfvfffizfizf |f |f}f}fxfxfffvfvfւfւfztfztfhfhftrftrfffrfrfRfRfsfsfXfXf-tf-tfff@sf@sfSfSfRqfRqfAfAfpfpfֆfֆfsfsffftftfffwfwfffxfxfN~fN~f!{f!{f}f}fs{fs{f|f|fvfvfff>f>fggXXoZoZ~]~]ϙϙhhYY~{~{劙劙_}_}((-}-}``m}m}劙劙||||@@z|z|;;||3{3{0z0zzz}}-{-{N{N{LL{{bbR}R}\\uu::%%{{xx퐙퐙KxKx^^ללN՘N՘ddMM LP LPTgTgSfSf&f&f%ff%ffffNpfNpfffXqfXqf+f+fpfpfAfAfpfpfififqfqf!f!f pf pfffofofffofof"f"fpfpfffrfrf,f,f&tf&tf҂f҂fvfvfff*zf*zf|f|f?}f?}fxfxfffhvfhvfffVufVufffRtfRtffflpflpf"f"fHifHifRfRfhfhf!f!fffIaIabb::<f>fee.2.2RRՓՓԙԙ/J/Jίί__iinnݕݕttKxKx捙捙VzVz))){){}}LJLJbbCC3~3~44zzVVzzxxvv[[brbrxx"p"pmm윙윙eenGnG癿󘀮À^+^+dd\f\fffRfRfRfRf^f^fffgfgf{f{fnfnfffQrfQrfff^tf^tf f fxfxfL~fL~f{f{f{f{fQ}fQ}f,zf,zf~f~fyfyfffvfvffftftffftftf%f%fsfsfff[qf[qf1f1fmfmfffmfmfffkfkfffififffdfdfffJVfJVfffe fe fgg pE pE ߣiTiTararukuk((pp>>UtUtzz2~2~瀙瀙==..~~}}}}tt{{덙덙xxnnwwΑΑuuLwLw=x=xwwmmuu┙┙OnOn󢙿OOllR*R*3_3_tgtgnfnfrfrfff?of?ofzfzfrfrf6f6fufufffGyfGyf~f~fMzfMzfW}fW}f{f{f|f|f}f}fwfwffftftfofofisfisfffiqfiqfLJfLJfofof3f3f~nf~nf6f6f;nf;nfffofof]f]ftftfffwfwfrfrfvfvfffufufffufufffmfmfff&f&fggA?TA?T{l{l\\벙벙||eedd||ՉՉ}}f}f}VV{{TTS{S{{{{{4{4{KzKz~~xx3x3xxxzzF}F}뉙뉙}}ڄڄxxȎȎ%%vUvU߱g߱g)f)fffmfmfffSwfSwfffwfwfffwfwfffvfvfffPtfPtfͅfͅfqfqfffqfqfffqfqfffqfqfCfCfqfqfنfنf%rf%rfff>\{\{bb;v;voo{{kk11AwAwBB[7[7<G<GggffffVfVf f fffffXfXfkfkf^f^fmfmfffNnfNnf7f7f`of`ofψfψfpfpfffpfpf`f`frfrfqfqf!uf!ufffufufffwfwf~f~fp{fp{fzfzfffwfwfffvfvffftftf؃f؃frfrfKfKfBofBof%f%fUgfUgfܓfܓf`f`f9f9fWfWf_f_fGmfGmfAsdAsdi)i)``ʘʘ22\G\GRReemm##nqnq@@rruuwwyyЌЌ{{--}} ~~^^WW]]퇙퇙~~||_z_z??xxxxRuRuzz q q99kkbbLL|˙|˙=ՙ=ՙEEˑG4G4+f+fd2fd2fffOfOfffg^fg^fqfqfMdfMdfBfBf[if[ifŒfŒf~mf~mfψfψffqffqfffsfsfffrvfrvfWfWfxfxf}f}f{f{fzfzfffvfvfffrfrfff;qf;qfrfrfpfpfcfcf]qf]qfmfmfqfqfffqfqfsfsfofof׊f׊fjfjfffafafffPfPfmfmfff6g6g:>:> 11 \ \ee||nn@@LrLr==vv؏؏zz||މމmm66||ll{{{{YYzz}}vv)t)tƔƔrrwwrrDDppZZhh"J"JIIจaaEfEfff5df5dfQfQfYgfYgfffUmfUmfff"qf"qfff sf sf4f4fwfwf<~f<~f{f{fzfzfTfTf/wf/wffftftfŃfŃfsufsufffsf>sfff;vf;vfqfqfvfvfffwfwfffyfyfK|fK|f}f}f%yf%yf,f,fwfwf}f}fffLfLf`g`gZZtt>F>Frٙrٙbbxx{{ɋɋ||||llzz?{?{{y{yQQxx>>OxOxXXyyezez77U|U|~~؅؅??4}4}zzvvQQuuÍÍᐙᐙˠˠmMmM'g'gSfSfff_f_fdfdfnfnfffpfpfffpfpf4f4fkofkof*f*fpfpfYfYfnfnfffmfmftftfnfnf{f{fpfpfمfمfsfsfуfуfufufffwfwfjfjfyfyf;|f;|f}f}fxfxfffufufffsfsfhfhfqpfqpfffkfkfffsefsefff`f`fffff~b~bj' j' XXHH=i=iGGqqݕݕzrzrUUss]v]vww xx_z_zrr=}=}||ɀɀ瀙瀙򅙏ƁƁ냙냙XXCC{{pp*y*yvvQQttmm e eEE?X?X&&WԲWԑR>{{{{zz??wzwz++eyeyyyʍʍyy dxdxvv""{w{wɏɏ!x!x동동uuZZNN癪..f]f])g)gBbfBbfxfxf8f8fqfqffftftfffwfwfffzfzfN|fN|f}f}fxfxfffvfvf f fufufAfAfsfsfffqrfqrfӅfӅfqfqf3f3fpfpfևfևfpfpfffqfqfffsfsfffsfsf˃f˃f}uf}ufCfCfvfvfff=yf=yf~f~fxfxf#f#fTpfTpfffe1fe1fggEVEVzz!!~~hhqq{{dd11rr88.|.|ɌɌyy// z zvvyyxxyy%y%y7z7zzz `{`{ZZ||00ᇙᇙBB!!~~ i{i{}}Q}Q}~*~*VVRRgg f fff,hf,hf݈f݈frfrfff;uf;ufffsfsfffrfrf"f"fqfqfff qf qfffqfqfffSrfSrfffqfqf f fsfsfffufufffufufffwfwfQfQf#wf#wfffGzfGzf2|f2|f}f}fDxfDxfIfIf%tf%tfWfWfqfqfffofofffxqfxqftftfff>_>_))>>LLƤƤ[l[l㖙㖙ssEuEu[[wwuuxxggyy[y[yyyڍڍyyӎӎyy{{II%%CC^^mm↙↙~~""}}JJzz%%uuNNnnnnffUhUh⡙⡙bjbjee}}pCpCՒgՒgff0f0fTfTfvfvf\df\df~f~faifaif,f,fjfjfzfzfGlfGlfffAofAofRfRfrfrfƃfƃffuffufffufufGfGftftfffdvfdvfffxfxf~f~f|f|fzfzf~f~fxfxfffnvfnvfȃfȃfRrfRrfψfψflflfffhifhifefefXffXffff`f`fffVfVfffZUfZUf8e8e4-4-ŅŬ""AA♀HHccllљљ6o6oCrCryuyu@@:y:y||||<<~~KK耙耙PP,,}}ꉙꉙ||izizwwuuiippgjgjo_o_QQgFgFݙݙcWcWP 0P 0ΑeΑeFfFffflRflRfff_f_f9f9fhfhfŌfŌfnfnfffpfpfffrfrfffDufDufff9wf9wfffvxfvxfffzfzf_{f_{f~f~fQwfQwfsfsfksfksfDfDfbrfbrfcfcfrfrf#f#fsfsfffqfqfffnfnfފfފfkfkfffhfhfafafcfcf؛f؛f`Qf`Qf@f@f f fxgxgAA&ۤ&xxrrOgOg裙裙/f/f؝؝>m>mrrۑۑxxTT||CCCC}}ww||{{CC0{0{<f>fsfsf,f,fqfqf f fofofffpfpfԇfԇfpfpfffOpfOpf܇f܇fqfqfffCrfCrfffrfrfffSqfSqfff>pf>pf]f]fdfdfffff3g3gQQ}b}bDDDDèè~~FF||6|6|쀙쀙## ~~ } }||=}=}K{K{jjgygyQyQyzzCCyy{{׋׋6|6|}}nn??ttBBxxnnƙƙmm77WW g g7f7fffsfsfffzfzfK}fK}fzfzf~f~fwfwf8f8fufufffHtfHtfWfWfysfysfg>g\\ YY22[[||#x#xt{t{⋙⋙{{ayaykxkx UxUxxxxxSwSwyyxxP{P{""x}x}{~{~vv<<[[WW{{``uyuyitit--:r:rْْRR]] i\Ji\Jgg f fffZfZf7f7fEifEifff#mf#mfffJnfJnfPfPfmfmfFfFf(nf(nf̉f̉fnfnf%f%fqfqfffsrfsrfffrfrfifif9tf9tfYfYf4wf4wfPfPfxfxf}f}f|f|fozfozfffSwfSwfffufufyfyfrfrfffamfamfHfHfyffyffMfMfbfbfff]f]fffffcc$$kkDDﭙﭙddmmqqwwttpwpw!!xxxx鍙鍙^{^{%%}}~~44%%44??~~΋΋zzdd5w5w2t2tUqUqlleeSSooRRb8b8 f f#f#f f fePfePfpfpf_f_fff0gf0gfffjfjfffkfkf f flflfffpfpffftftfffwfwfgfgfyfyf ~f ~fzfzf}f}f|f|fyfyfЀfЀftftfffqfqf?f?fpfpfgfgf&of&ofXfXf+lf+lfffmjfmjf8f8fffffff_f_fffOfOfĹfĹfffff0_:0_:""ƚƚVVzzee8m8mmmrrUUuuwwf{f{}}ᇙᇙKK]]ÈÈb}b}OzOzzziyiyWWNxNxUUruruttXrXrhhyoyoff窙窙FFnnMM/"/"ccffff^f^fVfVf,ff,ff܎f܎fQkfQkfffofofffKsfKsf͂f͂fvfvf'f'fyfyf}f}f)|f)|fV{fV{f}f}fyfyf~f~fxfxf`f`fXufXuf|f|fqfqfffrfrf'f'frfrfffqfqfff/of/offfmfmfffqmfqmfff mf mfNfNf1hf1hfafafc[fc[fffu fu f0g0g>K>Kxx 44tt::uuZZyy}}ĀĀMMU~U~44G}G}{{_{_{88yyddwwggyyff6z6zҌҌZzZzyyzz zzՍՍuu\\KKw9w9  [[OgOgSfSfffffvfvfffvyfvyf{f{fj~fj~f#yf#yfffwfwfʀfʀf&wf&wf)f)fvfvf)f)fvufvufffrsfrsf;f;fqfqfffsfsffftftfQfQftftfff|rf|rfffpfpfffqfqfffvfvfff^yf^yf>}f>}f"{f"{fC}fC}f|f|f|f|fxfxfff?f?fۃgۃg:X:X--3X3X1`1`U͙U͙{i{iTT{{mm~~CC}}JJzz44yyzzn|n|狙狙{{pp"z"zDD z zl|l|ʉʉC~C~쉙쉙*}*}ߊߊ0}0}MM((EETTU{U{ww{{ԘԘ e eULPULPGgGg f fЧfЧfcfcf^f^fofofffofof0f0fmfmfffqlfqlfififmfmfffsnfsnfyfyfWofWofffqfqf9f9ftftfff|wf|wfffwfwf>ll((mm儙儙99 w w꺙꺙00zUzUkgkg-f-fZfZfofof3f3fvfvfffufufffsfsfŅfŅf-rf-rfVfVfqfqfЅfЅf!sf!sfAfAfUrfUrfvfvfqfqfofofpfpfnfnfqfqfff>sf>sffftftfffufuf,f,fxfxf~f~f,{f,{f{f{f|f|fzfzfff)wf)wf f fsfsfffsqfsqfffvfvf\hf\hfggn^n^E+E+>T>TOOenen MuMuvvww[x[xFxFxwwyy++zzmmv{v{݋݋ } }WWJJqqccɆɆ8~8~NjNj:z:z珙珙#u#u$$nqnqeell홙홙UxUx_B_B{{%6%6M!GM!Ggg f fffXfXfffffffhfhfjfjfafaflflf4f4fLlfLlffflflffffmffmfΉfΉf pf pfdfdfyrfyrfffufufAfAfvfvfQfQfzfzf|f|f|f|f^zf^zf~f~fxfxf]f]fvfvf,f,fsfsfffnfnfڋfڋfkfkfff4if4ifff}ef}ef;f;f[f[fffFpfFpfCqdCqdyj)yj)ssYʘYʘ11EEaaKKmkmk oorr!!uuccww__"y"y鍙鍙.{.{&~&~!!22ssS}S}//{{SSyywwttApApiijjabab CMCMʙʙ֙֙zzqJ4qJ4(f(f]5f]5fԲfԲfRfRfff`f`fԔfԔf=ff=ffffjfjf|f|fnfnfffpfpfffqfqfffsfsf^f^fxfxf}f}f|f|fYzfYzf~f~f}yf}yfffkxfkxfρfρfufuf$f$frfrfffpqfpqfffnfnfUfUfnfnffflflf]f]f6hf6hfffafaf1f1fQfQfffff5g5g9>9>֡e\e\{{GeGe(n(n((ppההuuuzuz扙扙ڇڇjjƃƃbbKK}}(z(z55svsv66OvOvuuŒŒttss22ttǓǓTrTrii{{JJ J J޸޸..YaYa4f4fffdfdfFfFfgfgfffVlfVlfffpfpfsfsftftf2f2f+wf+wfffyfyf|f|f|f|fzfzfUfUfaxfaxfzfzfwfwfffLtfLtf!f!fqfqfffjnfjnfffofofffpfpfffpfpfffofofRfRfEpfEpfVfVfofofffnnfnnfߌfߌfacfacfbfbfffggNNii11阗33vvffyyAA}}nn~~YYƒƒ~~y|y|ȋȋ{{ :{:{EE]z]zɍɍxxyywwyy22{{A{A{11{{芙芙}}{{אא:g:gҙҙRR^Y^YmtgmtgEfEfffy|fy|fFyfFyf}~f}~f1{f1{fA{fA{fffwfwfwfwfvfvfff#wf#wflflfkwfkwfނfނfsfsfIfIfqfqfffqfqfffrfrfffsfsfЅfЅfrfrfffsfsfGfGf{uf{ufbfbfixfixfff\xf\xfff*yf*yf}f}f|f|fyfyfffNxfNxfY}fY}f f fLfLfagagVZVZcëcëBBܙܙ`` ){){e~e~ΈΈ~~||##qzqz퍙퍙yyююxx⎙⎙yyꎙꎙ4y4yyyAAyySSd{d{~~ʇʇ݅݅SSUU==77††~~NxNxmvmv팙팙ʠʠ-kM-kMygyg f fff\f\fffjfjfnfnfCnfCnf f fpfpfχfχf6pf6pf‡f‡fpfpfʈfʈfofofffofofff9qf9qfffBrfBrf̅f̅frfrffftftfށfށfxfxf}f}fl|fl|fNzfNzfXfXfwfwfffLufLufffPrfPrfffnfnfffjfjfҐfҐf2ef2efifif:cf:cfffxfxfS{bS{b) ) MMZZ??GGhhۙۙ|q|qݓݓ u u^^uuuu쑙쑙vvvv>>xx{{3z3z** { {11||33||44*}*}--zzxxJuJuyyppkkTT_e_eħħ[[!!)) T TԏV>{{̋̋{{==vtvtFFVV}}**ZZMMP]P].+g.+g`f`f-zf-zfdfdfqfqf6f6f2tf2tfɁfɁfxfxfg}fg}fH|fH|f{f{f}f}fyfyfE~fE~fkyfkyfzfzfxvfxvfififtftf^f^fsfsfffqfqfćfćfofofffofofffofof{f{fqfqf_f_f4tf4tf(f(fufufρfρfwfwf8f8fUxfUxfffwfwfffqfqf=f=f3f3fggVVxx##{{@q@q__SSeeAAWW~~}}{{ییyyEEyyllcxcx++yy((zz錙錙{{ŋŋ||%%ᆙᆙ..ԁԁˇˇ~~aaY~Y~yy66߬߬++RRgg6!f6!fffgfgfffppfppfUfUfrfrfffpfpfΆfΆfqfqfdfdfsfsfff)sf)sfffqfqfffqfqf†f†f9qf9qfGfGfpfpf:f:fqfqf f fsfsf(f(fxfxf}f}f{f{f{f{fn}fn}fzfzf~f~fxfxf)f)f%uf%ufIfIfvpfvpfffjfjfffnnfnnf$uf$ufff__,,--ONONmmssqqww xxxxxx##xx++IxIxՏՏxxiiyy {{򊙻||UUjj((o}o}*{*{^^wwss>>bmbm5h5hBlBldd!!{{(C(C=g=gT fT f3f3fSfSfff5ff5ffff)lf)lf֋f֋flflf)f)fAlfAlfffnfnfɈfɈf0pf0pfff7rf7rfffsfsffftftfffvfvfff^zf^zfr}fr}f{f{fzfzfj~fj~fxfxffftftf*f*fuqfuqf=f=f[>[PNgPNg'Uf'Ufff&f&fBtfBtfffvfvfsfsfzfzf{f{f}f}fkyfkyf{f{fWxfWxfŀfŀf{vf{vffftftfTfTf}pf}pfffofofffpfpfffqfqfOfOf=tf=tfff6tf6tffftftfrfrftftfff-vf-vf&f&fyfyf|f|f?|f?|f{f{f{f{f}f}fGufGufffdf>dfffnfnfffofofffnfnfffqmfqmf^f^fofofffqfqfʅfʅfsfsf}f}fCrfCrfffrrfrrfՄfՄfrtfrtfzf>zf|f|f|f|fzfzfff*xf*xf2f2fxfxfmfmfluflufffHqfHqf?f?fkfkfffEifEifgfgfPffPffff^f^fОfОfwRfwRfff>f>fee0202ɏәәJJyy-a-a&j&j֙֙ppÔÔuuÏÏ x x\\TyTy z zjj } }JJvv҃҃LL舙舙7|7|PPyy܎܎xx$$yy͎͎xxtt@@nqnqmmߝߝddEE_+_+{d{d`f`fff Vf VfCfCfafafffffffffkfkfff^of^offf4pf4pfffsfsfsfsfxfxf`}f`}f|f|fUzfUzfffdxfdxf,f,fQvfQvfffsfsfffpqfpqf9f9fofofff>of>ofwfwfnfnfffnfnfVfVf`lf`lfmfmf~jf~jfffffffMfMf Vf Vf}f}fc fc fQgQgnEnE`T`TqqllqqvvVVEzEz[[{{j~j~㇙㇙??uu}}zzssUyUy玙玙xxww||vvݐݐzvzvۑۑuu))ovovuu q qRR))5_5_xgxgofof rf rfkfkfRnfRnf~f~fqfqfÄfÄfufufff'zf'zfu|fu|fB}fB}f{f{f|f|fzfzf~f~fxfxf6f6f]tf]tfffHrfHrf6f6frfrfffsfsfffsfsfXfXf sf sfefefpfpf~f~fpfpfffqfqftftfUsfUsfbfbftftf_f_fNtfNtffflflf.f.f(%f(%f_g_g>T>TQmQm̞̞\\yy88UU``ȃȃ~~GGzzHHzz yywwzzUU&z&z{{ییyyaasysyWzWz}}~~jj9999--uuٻٻ݊݊##vUvUgg=*f=*f%f%fnfnf/f/fvfvfffNufNuffftftfpfpftftfff[uf[ufff`sf`sfڅfڅfqfqfdfdfCpfCpfffpfpfffrfrfffrfrfPfPfsfsfރfރfufufff[wf[wfafafxfxf}f}f{f{fHzfHzf΀f΀ftuftufgfgfqfqf݈f݈f%of%offf$vf$vf$hf$hfEgEgqo^qo^_ _ ((!T!T``qqӑӑxx ixixGxGxvvixixrrSzSz{{gg{{{{q{q{݋݋}}cc33WW88ZZ;;}}``wzwzĎĎvvYYss??ioioTTyyAAqq66 G Ggg4 f4 f&f&fIVfIVfzfzfdfdfffifif[f[fRkfRkfόfόfVkfVkffflflfffnfnf1f1fpfpfffrfrfffufufffxfxf~f~fxfxf+f+fuzfuzf}f}f{f{fzfzfEfEfwfwf]f]fsfsfffofof=f=fkfkfff|gf|gfffffx_fx_fIfIfAUfAUffflflfrdrdSj)Sj)Y͘Y͘ꙿHH]]ee))^l^lppAAtt66swsw9x9xzz||[[||㋙㋙I|I|DDD~D~}}ŊŊ@{@{xxŐŐttꔙꔙooiiޡޡ{`{` LL`ʙ`ʙ1י1יʵʵLI4LI4x+fx+f3f3fffPfPf=f=f^f^fffFffFfflflfkfkf`f`fmfmf+f+f$of$offfsfsf+f+fwfwf~f~fzfzf|f|f}f}fvzfvzfff yf yf~f~fyfyfffwfwfffffRsfRsfdžfdžfhqfhqf}f}fnfnfffblfblf]f]fififffhfhfff=cf=cfƚfƚfSfSfӹfӹfffy5gy5g:>:>__퍛퍛^[^[>b>b硙硙jjhhqqӓӓvvzz00BBII::ڃڃ``OO~~1}1}-|-|7{7{@x@xvvUUPtPtaassII(t(tssmmKK>>II@@uu#a#affpfpfafafffdfdfffjfjfgfgfofoffftftfffxfxf}f}f(|f(|fzfzf~f~fxfxfofofufufffsfsf f fjsfjsfffsfsf;f;f3rf3rfffqfqfffofofffpfpfՇfՇfpfpfffUofUofWfWfWmfWmf=f=flflfݍfݍfMcfMcfHfHfJfJfggNNYgYg퓡퓡嘭ىىSwSwOOvv{{؅؅ꂙꂙTTZZ;;~~$$}}{{{{I{I{gg{{))xxdydy)x)x-y-yGGzzi}i}~~A|A|""dd|ՙ|ՙPPaae e YYCsgCsgEfEfƉfƉfyfyf{f{f|f|f|f|fwzfwzf@~f@~fyfyfGfGf,yf,yfffwfwfff5vf5vffftftf_f_frfrf݆f݆fofofff}nf}nf.f.f_pf_pfffSrfSrfffWtfWtfDfDftftfŃfŃfufuf>f>fxfxf~f~fZ{fZ{fA{fA{f}f}f zf zfffxfxf}f}f̃f̃fOfOff^gf^gZZ««DD>ڙ>ڙEcEc..~z~z݊݊o}o}oo\|\|xxzzzzՌՌzzhhyytyty򍙷yyxx"{"{(({{ww}|}|yy||ss~~ttEE++EEQQzz]]tteetttt̠̠ lM lMggff]f]ff]ff]fffPkfPkfffnfnfffpfpfHfHfpfpf·f·fofofffaofaofbfbfBqfBqfffDsfDsfqfqf*tf*tf#f#fVtfVtftftfufufffvfvf^f^f'yf'yfu~fu~fzfzf{f{f~f~f+wf+wf f fsfsfTfTfnfnfffnifnifّfّfdfdfffbfbfffmfmfybyb, , ZZGG««rfrfppttss22rrttvv77zzXX||}}UUbb~~ꊙꊙ { {ww##tt,q,q٘٘kk ddZZMM!(!(.V.VԍSg>g\\  XX33䙴[[7v7vƎƎyy%y%yzz**xx__jxjxaawwZxZxyy_z_z;;zzxx=|=|CC-~-~မမ[[ꁙꁙ~~ꉙꉙ||llzz\u\u||ppSS8]8] \J\JggffbfbfYfYfZfZfkfkfffofofff$of$offfnfnfff&nf&nfԊfԊfumfumfffmfmfffXpfXpfffRrfRrffftftfffvfvfffzfzf{f{f:~f:~fyfyfwfwf5wf5wfVfVftftfLfLfCqfCqfUfUf%nf%nfьfьfgfgfffbfbfff\f\fffffنcنc$$00IIf>fLnfLnfffkfkf̎f̎fffffCfCf^f^fffQfQfff>rrؗؗkk%%__II,͙,͙ՙՙiiJ4J4(f(f5f5fOfOfRfRfff_f_fffdfdfdfdfgfgffflflfffrfrfJfJfufufffwfwfc~fc~ft{ft{f|f|f{f{f|f|fO{fO{f|f|f}f}fnyfnyfffQvfQvfffsfsfffpfpfffofofʉfʉfmfmfڌfڌf+jf+jfffffffffr`fr`f0f0fQfQfXfXfff4g4g<><>֠II\\eennLrLr듙듙uu))xx | |ŠŠ}}㈙㈙ff##u~u~ c|c|{f>{f}f}f|f|f%zf%zf~f~fQxfQxfNfNf,vf,vfPfPfsfsfffwrfwrfȆfȆfqfqfŅfŅfrfrf*f*fTsfTsfffsfsfff[rf[rf3f3fqfqfQfQf)sf)sfԃfԃfvfvf f fwfwf;f;fwfwfffofofff'0f'0fggVVww$$qzqz™™pp򉙃88''}~}~77||}}HHzz22xxxxGG%z%zzz挙挙zz/z/z쌙쌙k|k|SSFFcc@@~~44||WW b'b'SSpRpR>xx~~5x5xjwjwuuJwJwuuّّ^v^vssJJrrkkEEzLzL@@@1@1ZZ``ffyfyfnfnf7f7flflf f fnfnfӇfӇfJrfJrfffvfvfffLzfLzfd{fd{f8f8fxfxfDfDfwfwfff$xf$xf2f2ftftfffrfrfEfEfsfsfff^sf^sfUfUf[sf[sfcfcfzrfzrfKfKfpfpfffpfpfbfbfrfrfjfjfqfqfffbofbofQfQfdfdfffffggqQqQffb@b@˜˜''C~C~}}ˆˆˆˆքքnn66~~ԉԉ}}}}ΊΊ&{&{XXxxxx==yyOOyy yy{{拙拙 | |}}ڈڈ55煙煙ₙₙbblltʙtʙjj5:5:dd%W%Wgg6f6fٓfٓfrfrfffxfxfffOxfOxfqfqfZwfZwfffrufruffftftfDŽfDŽfsfsfffsfsf8f8fsfsf5f5fsfsf4f4fqfqfffpfpfff-qf-qfhfhf?tf?tf{f{fvfvfff wf wfffzfzfzfzfffvfvfff)vf)vf/f/f vf vfffff6Yf6Yf>g>g\\ XXM2M2YY??DtDtyyތތB{B{rrzzzzSSxxCwCwxx117y7yyy܍܍yy$${{؊؊}}ψψ候候ӄӄ]]ZZdd'}'}wwSSnsnsqqoo\\ [J[JggffffWfWf@f@fQgfQgfٍfٍflflfRfRfnfnf%f%fpfpf8f8f(rf(rffftftffftftffftftfffsfsfffcufcufffvfvfffvfvfffEyfEyf4}f4}f|f|fzfzfffvfvf f fSrfSrfff mf mfffffgfgfffafaflflf\f\fQfQf4f4fNcNc$$ffCCiiMdMdnnɖɖororHHssttDuDu vvxxuunznz*|*|~~55 mmHH"}"}ŒŒzzsvsvss??:q:qzzkkKbKbOO__tntn33τb8b8ff+$f+$fzfzflQflQfffW`fW`fffJgfJgfGfGfjfjf{f{fmfmfjfjf2pf2pf9f9f3rf3rfSfSf}uf}ufff2xf2xfj~fj~fh>  E[E[QgQgQfQf~f~fff vf vfgfgfvfvf_f_fwfwfBfBfzfzf{f{f}f}fwfwf$f$fsfsfffsfsf f fxufxufffdtfdtfUfUfbqfbqfۇfۇf/pf/pfffpfpfhfhfqfqfffrfrfffZufZuf?f?fvfvfPfPfwfwfv~fv~f{f{fzfzf}f}fr{fr{f7xf7xfff>f>fggXXZZ]])Ι)Ιjj==o~o~KKuu‡‡gg㈙㈙}}ފފd|d|HHp|p|bb8|8|GGzz-x-xvvҏҏ#x#x@@yy{{{{ՊՊq~q~熙熙88**HH}}22xxBByy%Ә%Әee !LP!LPggffvfvf cf cfff~of~of܆f܆frfrf)f)f?qf?qf'f'fpfpfffnfnf+f+fpfpfffpfpf߇f߇f#qf#qfffzqfzqfff&rf&rfTfTfQufQufff6xf6xf}f}f{f{f{f{fy}fy}fyfyf=f=f?xf?xfffufufifif>ffޤޤaa@@VgVgffff}Rf}Rftftf>bf>bffffhffhfffNkfNkfff!lf!lfffmfmfffxofxofFfFfqfqfffQ>Q(( x4_x4_gg=nf=nftftf`f`frpfrpf̅f̅fsfsftftfHufHuf.f.f_uf_ufցfցfxfxf~~f~~f{f{fzfzfffVxfVxfҁfҁftftf)f)frfrfffpfpf0f0fpfpf6f6frfrfȅfȅfrfrfffpfpfffpfpfffpfpfɆfɆfrfrfʄfʄftftf f fvfvfffkfkf$f$f#f#fgg=T=Telel33))yyƒƒ22XXEELLHHɇɇ~~}}}}G}G}{{99{{{{ŌŌzzttyy{{]|]|1}1}~~凙凙//>>⃙⃙tttxUtxUKgKg-+f-+ffflflf#f#ftftfff-tf-tf΃f΃f4tf4tfffisfisfVfVfqfqfff5qf5qfffHpfHpfffqfqfÆfÆfqfqfcfcf|qf|qfхfхfsfsfނfނfBwfBwfhfhf7yf7yf;f;fgyfgyf}f}fx{fx{f|f|f`~f`~fwfwfOfOfufufMfMf:sf:sfÅfÅfhqfhqffffxffxfgffgffggl^l^88**ppVVBBrrvvOOww2x2x@@SzSzddVxVxBBTxTx[x[xyyrrxxddyyyy||yyƂƂŀŀi~i~))<{<{֍֍FwFwrrԘԘ@l@lvv)D)D88GG=g=gffffUfUfff,ef,ef|f|f if iffflflf=f=fpfpf^f^f(rf(rfff7qf7qf%f%f:qf:qf†f†fqfqfffrfrfAfAf'vf'vfffxfxf ~f ~f{f{f{f{f2~f2~fxfxfffrwfrwfffEufEufffofofˊfˊfkfkfӍfӍfhfhfffxcfxcfffDZfDZfơfơf9of9of&pd&pdk)k)-ʘ-ʘJJCC䰙䰙aajj::ppההtt璙璙uuee7w7wzz֌֌{{6~6~]]ςςcc,,u|u|匙匙yyvv##ttMMqqll""aaJJKK̙̙)ԙ)ԙH4H4)+f)+f3f3f"f"fSQfSQfff-_f-_fcfcfgfgffflflfffofof:f:f7qf7qffftftf:f:f?wf?wf f fxfxfffIyfIyf}f}f |f |fS{fS{fd}fd}fzfzf(f(f;xf;xf݁f݁fsfsfffpfpf'f'f.nf.nfff7mf7mfffbifbifffNffNffff^f^f-f-fNfNfjfjfkfkf6g6g:>:>͔͔__ɤɤIgIg^^ll̗̗rrLLawaw鎙鎙yy{{ӊӊ/~/~::XXAAƅƅ ~~}}[z[zxxmmyybbxxddwwwwvv_t_tnneeEE$$BEBEttAaAaKfKfffgfgffffiffifffmfmfffrfrfffvfvfffyfyfB~fB~f{f{f{f{f;}f;}fzfzfffxfxf~f~f3vf3vfffUtfUtf#f#f_sf_sffflrflrfffofofffZnfZnfKfKfpfpftftfqfqfffqfqfffofofljfljflflfffecfecfffsfsfggNNhhOOzzމމwwpp?w?w66N{N{يي~~TTuu脙脙ՀՀ}}HHyyۍۍyyPPxxvvܑܑsvsv!!wwQQzz66||SSvvhhccYY~~%|%|eeәәQQȇȇ::YYrgrgEfEfffyfyf{f{fG}fG}fzfzf|f|f{f{f0|f0|f}f}fyfyfffvfvfff^tf^tf3f3fqfqfffofofafafpfpfffqfqfمfمfsfsfff!tf!tfff]vf]vfʁfʁf}vf}vfIfIftftfff;wf;wfJfJfzfzf {f {f~f~fyfyf~f~fYzfYzfzfzfSfSfJfJfbgbgDZDZ?«?«:D:Dۙۙaaww퍙퍙zzƌƌ{{{{88zzzzݍݍIyIyiixxҎҎ(z(zzz팙팙zzIIvzvz!!~}~}}}<<**<<톙톙  zzxxTTwwJJ̠̠%%ilMilM]g]gffafaf^f^fyfyf\kf\kffflflfufufmfmfffofofffpfpfffqfqf]f]fpfpfNfNfpfpfffqfqf#f#ftftf1f1fxfxf~f~f(zf(zf~f~fyfyf}f}fzfzf}f}f}f}f=xf=xfEfEfsfsfff8nf8nfffrjfrjfHfHf;ff;ffffbfbf&f&fff~b~b& & |W|WaGaG}}ggppXX1t1twwԎԎyyKKxxxxyyzz댙댙K{K{}}aa삙삙ppCC{{yy'v'vqq}}ckck۟۟DbDbjjVV$$XԐXԞRwf>wf=f=fxfxf]~f]~f$|f$|fyfyfpfpfvfvfmfmftftfffqfqfۇfۇfkofkofcfcflflf f fjfjffftfftffГfГf`f`fDfDf*Pf*Pfff{+f{+fkfkf\6\6VV͖ KNKNttbbȟȟolol뗙뗙 r ruuÐÐxx55yyuu@{@{RR}}NNxxcc9~9~ˋˋ{{ʌʌ'z'zCzCzvv(y(y@@?w?w||ssEEpprrll՞՞ccWWEEYY22濷濫$'$'dd{f{fffYfYfffbfbf>f>f`jf`jfffnfnfffVqfVqf/f/frfrffftftfff zf zf|f|f-~f-~fwfwfffvfvfffufufyfyftftftftfLrfLrf[f[f!qf!qfffrfrfffpfpfffffcnfcnf7f7flflfUfUfjfjfffffffffOVfOVfff6f6fggHH䔞䚵00~~YYZpZpttHxHx22g|g|ҀҀjjJJ99//--x}x}vv{{;z;zqq y yyyˍˍ z zwwvvffvvxx莙莙xxuu-Z-ZF/F/UUeeњ]њ],g,g`f`fyfyf%f%fpfpfffrfrfff]vf]vfffzfzf+|f+|f}f}f xf xfVfVfBwfBwfffufuffftftf_f_frfrfVfVfqfqfffrfrf˅f˅frfrfffffnrfnrfff)rf)rfRfRf>sf>sfffoufoufւfւfufufffvfvfހfހfYwfYwfffIpfIpfff0f0fסgסgVVxxA#A#{{jjrr鈙鈙ففꄙꄙ΂΂DžDžမမ}}{{UzUzzzii#z#zJJ y yxxHH>z>zb{b{]}]}^~^~ψψqqH~H~FF%%~~KKίί ( (RRzgzg f fffLhfLhfffqfqfۆfۆfrfrf f f\tf\tfffrfrf5f5f;pf;pfffqfqfDfDf sf sfffsfsf'f'f5rf5rfRfRflrflrfffAsfAsfكfكf.uf.ufffvfvfOfOfcxfcxf~f~f*{f*{f~zf~zf-f-fvfvf_f_fHtfHtfffpfpfffjfjfff nf nfgvfgvfff=_=_44|+|+--OOmmII=s=sӒӒvv+x+xhwhwӐӐxx,{,{{{hhryry%y%y@{@{QQنن偙偙WWuullɆɆ~~~~{{CCxx``uuPP,r,rjjkkee||;C;C˓g˓g7f7fCfCfRfRf7f7fcfcfff+if+iffflflfufufofofffofofEfEfpfpftftfofof.f.fqfqfхfхftftfЁfЁfxfxfOfOfyfyf}f}f"|f"|fyfyfff}vf}vfYfYfosfosf…f…fwqfwqfrfrfnfnf؊f؊fkfkf7f7f if ifDfDfZafZafFfFf-Uf-UfAfAfSfSf9e9e--š""䙽䙻EEbb@n@n66ppatatvvMyMyyy1|1|䉙䉙<<႙႙ƃƃńńƂƂ[[ӈӈ||6y6yuurrggpp[j[j!a!aGGܙܙWWԜԜǔ 0 0eeJfJfffETfETfНfНf_f_fffHffHffߎfߎfkfkf~f>~fi{fi{fzfzfffxfxfŀfŀf?uf?ufffqfqfffOqfOqfćfćf-pf-pfffynfynfيfيflflfӋfӋf8kf8kfgfgfffff~f~f&af&afԜfԜf{Qf{Qfff f f]vg]vgFAFA$$ۨyyrrgg墙墙$h$hggzozo0t0t㑙㑙@w@w { {WW8}8}UU::쁙쁙JJ~~={={AzAz֍֍ z zyyyy1y1y؎؎xxxx͏͏3v3v;;ssppffkk44,L,L3131 ` `ffz{fz{flflfffijfijfffnfnfjfjfrfrfffufufJfJfqxfqxf}f}fn}fn}fwfwfffIsfIsf*f*fErfErfff^rf^rfʄfʄfrtfrtfffrfrfff~sf~sfхfхfxqfxqf:f:f@rf@rfffNqfNqfffrfrfUfUfXsfXsfffrfrfŅfŅfqfqfff$gf$gfffffgg Q Qff@@ffBBvv~~\}\}66 مم$$kk88ÅÅzzވވP~P~ ||ߌߌyyOOxxyyxxȎȎ.x.xxxԎԎyy||ss55ii넙넙恙恙oo7ƙ7ƙnn 7 744GWGWgg)8f)8fۑfۑf tf tfkfkfwzfwzf~f~fOyfOyfffiwfiwfff2vf2vfffufufffhtfhtfffksfksfufufrfrfffofofCfCfnfnfffofof܆f܆f8sf8sfff vf vfffyfyf~f~fzfzf|f|f|f|fzfzf.f.fcwfcwfffvfvffffuffufff~f~fYfYf=g=g\\ $W$W33==o[o[{{ququȏȏ\y\yazaz{{88yy__wwِِwwUU|y|y*{*{zz܌܌7z7z..G{G{f}f}ÈÈɂɂ}}DyDywwttrr44^^44_J_J g g f fffZfZf5f5fgfgfffkfkf‹f‹fKmfKmffflnflnfffmnfmnfffnofnofffmqfmqfffsfsftftf;sf;sfffYtfYtfȃfȃfufufififxfxf]~f]~f6|f6|f zf zfffvfvfyfyftftfff8rf8rfӇfӇfbofbofMfMf/jf/jf+f+fcfcfrfrf[f[ffffflclc$$UUFFffffooUsUsftftOOuuttvv$y$yzzv|v|TT~~DDccZZUUၙၙ!!++||]]xxss閙閙mmTjTjaa1Q1QDDmmϑCb8Cb8ff$f$f۵f۵f`Sf`Sfffafafffgfgf f fkfkf"f"flflfFfFfipfipf܇f܇fqfqf;f;fsfsfRfRfsvfsvfʀfʀfxfxfW~fW~fR{fR{f9{f9{f6~f6~fyfyfff@vf@vfނfނftftf$f$fHrfHrfffpfpffflflfČfČfififff~ff~ffff `f `fJfJfPfPfffffsfsf^:^:"Ҧ"ҁƚƚUU11CbCbRkRkSSrrגגvvyy{{vv}}ЈЈyyzzoo:}:}狙狙"{"{qq[{[{{{yyϏϏuuSSssppkk{{ccEEnn&L&LU"U"ccufufffnafnaf[f[fgfgfҍfҍfsmfsmfшfшfpfpfŇfŇfJqfJqfFfFf_rf_rfnfnfufuf=f=fszfszf{f{fJfJfvfvf[f[fufufwfwf+tf+tfqfqfrfrfޅfޅfmrfmrfffrfrf f fppfppfffofofff pf pf+f+fpfpfЈfЈfmfmfffgfgfffiXfiXfsfsf f fggKKzz**D D TTttڑڑJwJw??{{򊙽}}聙聙QQEE……TT~~||{{yyyy]y]y%%zzތތN{N{،،zzzzzz鋙鋙#|#|{{ w w77\\ᙥᙜ99??| | [[QgQgQfQfjfjfffufufffvfvfffzfzf[|f[|f|f|fyfyfffxfxfffvfvf f fttfttfffqfqfYfYfrfrfffrfrfքfքfrfrfօfօfrfrfff^rf^rfffsfsfhfhf:tf:tfffcvfcvfQfQfxfxf}f}f{f{fr|fr|f{f{f~f~fuf>uffftftfOfOfqfqfffofof f f-nf-nfffUmfUmffflflfff-kf-kfffYffYffff~Uf~Ufffffgg|oE|oE<<``|S|Sqqʝʝ#k#khoho;;ssOOxxX}X}~~󇙜NN*~*~}}ff||yy;;vvaavvHwHwWWyyNNww w wggauaull⣙⣙PP{{**LL3_3_^g^gRmfRmfctfctfffmfmfffofof3f3frfrfffxfxf\~f\~f8|f8|fyfyfffwfwfفfفfufufffctfctfffrfrfffhrfhrfffqfqfffsfsfffqfqf@f@fMpfMpfff&qf&qfɅfɅfsfsfڃfڃfufuf5f5f\tf\tfDfDfsfsfff|f>|fdzfdzfffvfvfffsfsfHfHfqfqfffpfpfffGmfGmfffYkfYkf|f|f2if2ifffOgfOgf%f%f}af}af,f,fPfPfffcfcfv4gv4gd<>d<>GGTT]]ߦߦtftfnnLLrruuxxՌՌ4|4| ~~GG((**ooYY{{yy!!zzyyߏߏ`t`tqq8q8qŖŖIpIprhrhɩɩHHHHUUaaffsfsfuefuefffgfgfffmfmfffKqfKqfńfńfxufxuf{f{fwfwfJfJfzfzf|f|f$|f$|fN{fN{f~f~f xf xfffsfsfffqfqf߆f߆fqfqfBfBfqfqfWfWfrfrf4f4fepfepfffofofˈfˈfEpfEpfffofofff]of]ofBfBf)nf)nfffwcfwcfAfAf<f<fggNNjjӑӑ瘔MxMxƏƏxx77{{}}44KKډډ||{{zzxxyyzz00{z{zeezznjnjyyލލzzӋӋ}}RR}}mmffgՙgՙOOP P ^Y^Ypgpg4Gf4Gfffzzfzzf{f{f|f|f|f|f9{f9{f~f~fwfwfrfrfNvfNvfffatfatffftftfÃfÃftftfffsfsfބfބfrfrfAfAfpfpfff6qf6qfNfNfsfsfyfyfsfsffftftfLfLfvfvf;f;f yf yf}f}fc|fc|fzfzf^~f^~fxfxfzfzfxfxf{f{fffKfKfbcgbcgRZRZii(F(FٙٙaaYY{y{y||}}zz썙썙GzGzyy88yyˎˎyy}}{{{{zz xxz{z{@@2~2~<<__&&ttMMuu0|0|WWvvssg̠g̠__mMmM g g1f1fff^f^fsfsfKlfKlfÉfÉfofofffuofuofʈfʈfnfnfff)of)offfpfpfffqfqf;f;fofofafafofofcfcfjsfjsfffwfwfffxfxfZfZfyfyf=}f=}f|f|fyfyfĀfĀftftfffqfqf؇f؇fofof7f7fjfjfCfCfUefUefffAbfAbf܌f܌fdfdfzbzb(+ (+ ZZqqFFeeiioottUUwwאאvv<<7v7vvvxxxxxxii_{_{ʅʅxx##ˆˆ~~{{~~'y'yqwqwrrtt$$smsm cc 5Z5ZƝƝ&&XXQI>I3ڙ3ڙYYDŽ) 0) 0eeGfGfffRfRfff^f^fffefefyfyfififffmfmf2f2ff>fwfwf6f6fyfyfEfEfyfyf}f}f{f{f {f {f+f+f4wf4wfEfEfeufeufffMsfMsfffvqfvqfކfކfpfpf"f"fpfpfƈfƈfPofPofψfψfpfpf/f/fMpfMpfffrfrfffsfsfffrfrfff:ef:ef.f.f*f*f+g+gzQzQddSBSBff?}?}zz||eeƃƃRR!!YY{{{{|| zzxx xxzz||抙抙@|@|ȊȊ}}&&}}XXNN''uu~~11mmșșWkWkI:I:gg#W#W}g}g>9f>9f‘f‘fsfsfafafzyfzyf}f}fYzfYzf=~f=~fyfyfbfbf_vf_vfffqfqfffpfpfffofofhfhfJofJof(f(fpfpfffg>g\\f f WVWV33YYUtUt33zzzz-z-zyyƌƌV{V{쌙쌙zzyytt\y\yJzJz55zz.{.{틙틙||**eeˆˆ66{|{|88xxtt00qq퓙퓙^^44.aJ.aJygyg f f]f]f~Zf~ZfɔfɔfihfihfffkfkfcfcflflfыfыfGlfGlfff6lf6lf,f,f+mf+mf f f"of"offfmpfmpfffrfrfffevfevfffyfyfe}fe}f |f |f{f{fo}fo}f zf zf~f~fxfxfffWufWufMfMfpfpfNfNfkfkfڍfڍfhfhfffdfdfSfSfN^fN^fcfcfffCcCcm$m$dd $G$Gdd<f>f,gf,gfff_f_fffof>ofufuf)nf)nf6f6fnfnfffXofXofUfUfpfpf׈f׈f0mf0mf%f%f3^f3^fffff7g7gNKNK{{ }}ss@u@uqqxxCC||\\քքII}}{{oo||ዙዙzzxx䎙䎙YxYxNNxx3x3xََMzMzHHzzuu||ዙዙ{{狙狙xxq^q^9966; ; [[OgOgTfTfρfρfffvfvfff1xf1xfffyfyf{f{fO~fO~fxfxfffvfvffftftffftftf"f"frfrf|f|fsfsfcfcfsfsfffrfrfffBrfBrfffsfsfffufufff=uf=ufڂfڂfufufffQwfQwfˀfˀfSxfSxf~f~f~zf~zf~f~fvfvfTfTfe>fe>f$g$gXX~[~[S]S]NϙNϙii}}~~jjI|I|||tt}}䊙䊙{{99zz㌙㌙{{yyrxrx@@xx獙獙zzʌʌd{d{99}};;UUGGzz{{ x xjjyyYYQӘQӘddQQLPLPggffffdfdfff qf qfڅfڅfqfqf8f8fpqfpqfffqfqfOfOfgqfgqf f f(of(ofefefnfnf/f/fpfpfffqfqfͅfͅftftfqfqf>P8P8wwHHjjererꓙꓙ8t8tssԒԒuuxxxxzzxxzz44||s}s}mmddσσjj}}RRyyeeNvNv,,rr::mm`f`fPPf>f3vf3vfYfYf{f{fzfzfffBwfBwf}f}f:vf:vf;f;f@tf@tf#f#fTqfTqfffmfmfff^kf^kfffffffefefh_fh_fffQfQf+f+f>00OO؆؆!!}}䉙䉙}}pp}|}|GG6z6zMMyyyypypy++yyxxvv!!tt11ororeeCmCm,Q,Q`,`,2_2__g_gnfnfrfrfffofofffrfrffftftfffwfwf|~f|~fgzfgzfI}fI}f|f|fyfyfffwfwfpfpfGufGuffftftfff%rf%rfʆfʆfqfqfffgqfgqfԇfԇfofofffpfpfņfņfrfrfff!tf!tffftftfтfтfufufffsfsfIfIfififJfJf"f"f g g$=T$=TmmQxQxVV̆̆AA66~~ŠŠ||]]zzzzZzZz{{zzvv}z}zggyyȍȍKzKzόό=|=|%%RRꃙꃙςς55II99?t?tDDLLyy wUwU'g'gR+fR+fffofofffxwfxwfffvfvffftftfffqfqfffqfqfffqfqf f fHrfHrf]f]f|qf|qfff8rf8rfffqfqfffsfsf,f,ftftfff1vf1vfɀfɀfxfxf&f&f;zf;zf{f{f}f}fyfyfffufuf f frfrfffpfpf@f@f_xf_xf\ef\ef g g"l^"l^**홏TT&&f>f~Of~Offfff5g5g:>:>ƕƕf\f\ببccllZsZswwyynznz}}77ˆˆ22ćć~~VV#|#|aazz뎙뎙y>y}}ssGGلل44׆׆RR||B}B}芙芙K|K|(({{{{ ^y^yww w wzzB~B~>>ww22HHszszܒܒddJ֙J֙OO͇͇GGYYPugPugCfCflflfhxfhxfq|fq|f|f|f{f{f{f{f|}f|}ffzffzfE~fE~fyfyfffxfxfrfrfufufffsfsfff[qf[qf܇f܇fpfpfffqfqf…f…f#sf#sfffYsfYsfff{uf{ufffvfvfffwfwfffwfwfffyfyf4}f4}f{f{fzfzf~f~f4zf4zfzfzfffKfKfbgbgxZxZGGDDڙڙyayayyxxa|a|ϋϋQ{Q{{{YzYz'z'zǍǍQyQyώώyy wwxx\\gzgz||$~$~łł NN00rr{|{|??uxuxǐǐvv댙댙ˠˠGGDkMDkMgg f fffF^fF^ffflflf8f8fofof~f~fqfqfWfWfHpfHpfefefofof8f8fofofffpfpfчfчfpfpfffrfrf|f|ftftfffufufffwfwf!f!fzfzf}f}f|f|fzfzf/f/fvfvfff>ӄӄ--[[쀙쀙~~ZZ%%jjvRvRgg!f!fffhfhfffrfrfӄfӄftftfff:tf:tfffrfrfTfTfqfqfVfVfrfrfffsfsfffrfrfffppfppfffVofVofӇfӇfhqfhqf̅f̅ftftfofof'vf'vf_f_fyfyf}f}f|f|fxfxfۀfۀfvfvffftftfffqfqfffwlfwlfcfcfnfnfufufhfhf"_"_..,,++{N{N]m]mssvvÐÐww88vv==xxxxggxxFFxxtt z z||OO((ŇŇ'}'}yy x xtt@@7n7nigigoo^l^lcczzsCsCgg f fffHTfHTfff4df4dfkfkf_hf_hf1f1fOkfOkfVfVfmfmf f fpofpofffpfpfRfRfqfqffftftfYfYfwfwfffBxfBxfffwfwfff{f{f{f{fffffvfvfffUtfUtfׄfׄfkrfkrf݆f݆fRpfRpfff{lf{lfCfCfffff)f)f_f_fhfhfUfUfffWUfWUf7e7e2-2-##GGyyabab}}iimmrr^^\w\w { {&|&|<<~~~~臙臙uuZZ||WW{{yy22GwGwss11aoao̚̚jjOOaa J Jؙؙ \ \z 0z 0ɏeɏeHfHfff|Tf|Tfff_f_f3f3fdfdfxfxf?hf?hfIfIfcmfcmfffqfqfofofufufffxfxf~f~fyfyf}f}fP|fP|fzfzfMfMfAwfAwfff}uf}ufffufuffftftfff qf qf>{{SSVwVwVuVu葙葙vvvv\\uuttRR*s*sllNNBB33AA ` `ff_~f_~fhf>hfˍfˍftlftlfDfDfmfmfffofofffqfqf{f{fsqfsqfffrpfrpflflftpftpfʆfʆfrfrfff`wf`wfffwfwf~f~f wf wfff~yf~yf|f|fv}fv}fwfwffftftfffqfqfbfbfpnfpnfzfzfjfjfLfLfdfdfff/\f/\fff3f3fcc $ $ZZ55CCDDppMdMdnnΕΕttJJwwZZvvuuvvXXhzhz}}ሙሙ&&^^惙惙FF爙爙||̌̌#y#y^^uujj,u,u++rr>>RkRkMM``PP޶޶,p,pDDd8d8KfKf &f &fffSfSfffafafffgfgfʏfʏfyifyiffffjffjfffmfmfffqfqf΄f΄fufufDfDfvfvfffyfyf}f}f{f{f{f{f}f}fyfyfffwfwffftftfffqfqfff6nf6nf0f0flflfffjfjf܍f܍fhfhfjfjfdafdafff{Qf{Qfϸfϸfffff_:_:C$C$4Ě4ĚNNRRhhbbll,q,qVVttxxGG/}/}##a~a~MM$$тт {~{~ʊʊ~{~{(z(z΍΍SySyLLww.u.uΒΒttCC t t5o5oFFReReEEmmnn}L}L`"`"ccffff^f^fffcffcff>f>fifif;f;f~mf~mf`f`fbqfbqf f fvfvfffyfyf}f}f|f|f|f|f}f}fyyfyyf[f[fexfexfffAufAufffqfqfff>of>offfofof>yzyz!!mm33$$||##zzDDvv!t!tԔԔqqpp((ll/d/d۬۬GG Ú++dd`f`ffflTflTf[f[f`f`fQfQfhfhfrfrfkfkfffFnfFnf)f)frfrfffGufGufffwfwf1f1fzfzf{f{fS~fS~fWxfWxfEfEfufuffftftfff)qf)qfffofofffnfnf7f7fxofxofSfSfmfmfYfYftlftlfffifif>f>fRefRefwfwfTfTfff f f+g+gQpEQpEߺ==:S:Srrkkpp&p&pttzz}}||GG88’’;;~~||AAzzyyzzyyxxӎӎxxOOwwďďvvCC)u)u2u2unnQQww((rr4_4_SgSgmfmfsfsfΈfΈfofofffDsfDsfff)vf)vfffxfxfJ~fJ~fS{fS{f {f {f~f~fxfxf f fwfwfˁfˁfufufpfpfYufYufjfjfrfrfffqfqfffrfrfPfPfrfrfʅfʅf\qf\qfffpfpf=f=fqfqfvfvfsfsfUfUfsfsfkfkfsfsfffKkfKkfff&f&fgg>T>Tll99xxRRFFąą灙灙PP˄˄11WW$$MMR~R~{{IzIzccDzDzyyyy``xxĎĎeyey3{3{~~??ww^^tutu##vUvUggk*fk*fɚfɚfnfnfffwfwf-f-fxfxfRfRfPvfPvfffufufffsfsfτfτf1sf1sfЅfЅfqfqfff pf pfĈfĈfbpfbpfffqfqfdfdfsfsf f fsfsfff@uf@ufififwfwf{f{fyfyf}f}f0|f0|fzfzfffIufIufVfVfyrfyrf.f.fpfpfffwfwfgfgfggGn^Gn^ ()()@@SSППppwwbbyyxxΎΎxxxx`y`yXXVyVyByByPzPzR{R{njnj${${ËËW|W|艙艙44܄܄NNUU||xx t tەەoo욙욙jjvvCCGG55!G!Gggy fy fffXfXf!f!fAgfAgfffkfkf[f[fkfkfffkfkf@f@f mf mfFfFfofofffrfrffftftf=f=fvfvfff;vf;vfffxfxfw~fw~fzfzfQ|fQ|f|f|fzfzfHfHfwfwf4f4fLsfLsfffnfnfffhkfhkfffhfhfffcfcfffjXfjXf[f[f{mf{mfSrdSrdj)j)J˘J˘홧 E E֮֮ZcZcnn$$wqwq'r'rSSuuCCgwgwtt z zÍÍzz||kkwwWWVV$$ccوو}}ww//ptptӓӓss00srsrkkbb##dMdM}ʙ}ʙ9י9יJ4J4)f)f4f4fpfpfRfRfIfIf`f`f f flfflffŐfŐfififffWmfWmf(f(f(pf(pf\f\frfrfff9sf9sfKfKf vf vfffyfyf|f|f|f|fzyfzyf߀f߀fvfvfff&sf&sf6f6f=qf=qfÈfÈfnfnfffmfmfffElfElfff]kf]kflflfhfhfqfqfbfbfffQfQf#f#f f f)5g)5gb;>b;>``8855\\`e`eqoqo㕙㕙 t t呙呙|v|v,,yy11|| ~~22WW~~}}CC||劙劙||{{5z5zюю_x_xAA.v.v#t#trrOOoo⚙⚙hhʩʩbHbHGG\\aa@f@fffffffff$ff$ff f fkfkfffpfpf܃f܃fvfvfffxfxf*~f*~f{f{fy|fy|f}f}fyfyf#f#fvfvf>f>f"uf"ufffrfrfffrfrfffHrfHrfffffUrfUrfƆfƆf qf qf\f\fuofuofsfsfpfpfefefypfypfffnfnffflflf}f}f7bf7bflflfffggBNBNii瘦瘁aalxlxyxyx`|`|>>xx}}ዙዙ{{?|?|ȋȋ{{xxwwɏɏEyEy-{-{ʊʊ<}<}׊׊||EE||||ЊЊ||yyddiԙiԙQQ**FFYYtgtg!Ff!Ff3f3f|f|fwfwfjfjfkyfkyf-}f-}f|f|fyfyfffvfvfff$tf$tftftfrfrfffqfqfffqfqfafafqfqfӅfӅfvsfvsfЄfЄfsfsfdfdfsfsfffrfrfLfLfsfsf'f'fwfwf~f~fN{fN{f|f|f*|f*|f{f{fb}fb}fyfyf~f~f|yf|yf|f|f,f,fKfKf&bg&bgZZٓٓ<>yy苙苙M}M}DD||||ًً{{)z)z͎͎xxXyXyʎʎxxwwᏙᏙxxΌΌw|w|tt恙恙==ƒƒׇׇ~~ʊʊzzww00uu..LLcc͠͠@oM@oMIgIgffff]f]f f fkfkf\f\f/of/offf"mf"mf͊f͊fmfmf~f~fmfmfffnfnfffofofffpfpfffXrfXrfօfօfsfsfffOvfOvf1f1fyfyfY}fY}f|f|fyfyfffvfvf#f#ftftfffqfqfff1of1of'f'fbkfbkfZfZfmgfmgfffefefffAfAfrzbrzbV+ V+ xxZZrr_H_Hggggkkoo疙疙qqUsUsXXttꑙꑙwwꏙꏙ4y4y\\z{z{SS||}}ddههȀȀttЃЃ≙≙{{@@wwpspsooɘɘ#m#meettuZuZ//))BVBVԔS g> gffffOfOfPfPf=`f=`fkfkfdfdf-f-fififff]nf]nf f fofofNfNfapfapf·f·fqfqfdfdfufufofofmxfmxf~f~fMzfMzf|f|f|f|f_zf_zfvfvf>wf>wfffufufffsfsfffpfpfffkfkf=f=fhfhf7f7fPdfPdfff_f_f؞f؞fQfQf5f5fY,fY,fkfkf[6[6͹! ! PP cc]]7l7lpp33 s suuyy22||ˆˆӀӀEE<<99\\ZZ~~cc{{iwiwauau66ttttErErlltmtm}}ccMMEE;;񙤦^%'^%'8d8d|f|fffE[fE[fffEcfEcfff/jf/jfffmfmfffqfqfff uf ufفfفfwfwf€f€fxfxfZ~fZ~fzfzf<|f<|fg}fg}flyflyf,f,fnufnufff/rf/rfefefBqfBqf.f.fSpfSpfff*pf*pfffnfnfffofof5f5fofofKfKflflfٍfٍfJgfJgfffXfXfffffggHH&&11~~ߖߖoo閙閙NrNrvv||aavvwwkk݀݀JJ}}zzww͏͏LwLw]]vvFxFxxxŎŎxx,,FzFzZZHzHz%%)z)z"u"u~~YY77..]](g(gcfcfxfxf9f9fzqfzqffffuffufIfIfxfxf~f~fzfzfG}fG}f|f|f-zf-zfffvfvfff1tf1tfffrfrfofofHrfHrfffrfrfffFrfFrfffqfqfڅfڅf4sf4sf'f'fufufbfbfufufffufufffwfwfnfnfwfwfwfwfvfvf2f2f+nf+nfjfjf.f.fggiViV y y## | |\\qq++;;qqss}}??2}2}--uu}})y)y5w5wjjEyEyKKzzzz,,zzV|V|M}M}݀݀NN쀙쀙K}K}ŊŊ}}&&RRggffƢfƢf$hf$hfLJfLJfsfsfffQufQuffftftf}f}fuufuufffsfsfffqfqfffofofffdqfdqf f fsfsfffsfsfƃfƃfufufffvfvfffufufZfZf}uf}uf݁f݁fxfxf}f}f~f~fwfwfނfނfsfsfffofofLfLflflf΋f΋fofof%uf%uf:f:f__++vNvN>>llststّّIvIv{u{uttWuWu..vvxxӍӍj{j{''||__~~ꀙꀙJJ;;{{͍͍xxuu{r{r\\@m@mlnlndd\~\~ݩCCggffff0Sf0SfUfUfcfcf[f[fkfkfYfYf~kf~kf\f\flflf f fKnfKnfKfKfqfqfhfhfsfsfffsfsfff,uf,ufffKxfKxf~f~f!{f!{f{f{f}f}fryfryfffwfwfff>噓CC'`'`jjqqhhttbbww88yy{{||ee~~UU33ccŁŁ䀙䀙77~~䋙䋙yy⏙⏙ououqqff1n1n=h=h__rrHHڙڙYY 0 0ŐeŐeGfGf/f/fuTfuTfEfEfafaf1f1fqgfqgfގfގfjfjfffmfmfffrfrfnfnfufufffvfvfffwfwfEfEfLzfLzf|f|f}f}fxfxf f fPvfPvfffytfytf@f@fqfqfff_nf_nfffmfmffflflf̌f̌fjfjf}f}fhfhf3f3fNcfNcfffQfQfһfһf f f xg xgcAcA_(_(ۻvvttee!!ggϛϛnnGG8u8uUyUy__||~~ 瀙瀙66EEvv||䋙䋙-{-{ьь]z]zuutxtxxx'x'x44ww>>wwmmEwEw됙됙uussll7N7N44 ` `2f2f}f}f9if9if0f0fhfhf>f>f^nf^nfff2sf2sfZfZfHvfHvfMfMf9wf9wfffyfyf }f }f|f|fzfzf|f|f[uf[ufffjsfjsfffpfpfffofofwfwfofofffofof f fnfnfff3of3ofdfdf pf pfgfgfBrfBrf f fsfsfʅfʅfqfqfPfPfgfgfffffBgBgRQRQdd@@0˜0˜!!OO~~~~ՈՈ~~LL%%̈́̈́11**..K~K~||||yy{{[[}}||{{gygyJyJy؎؎exex((yy~|~|凙凙 //߀߀hh~~llllșșplpl887W7Wkgkg`8f`8fcfcfJsfJsfff$xf$xfffxfxfffxfxfff}vf}vfуfуf:sf:sfffAqfAqf1f1fqfqfUfUfIrfIrfVfVf.sf.sf f fqfqfsfsfqfqf8f8fsfsf)f)f+wf+wfff|yf|yf~f~fyfyf}f}f{f{f{f{f}f}fyfyf~f~f yf yfffxfxfPfPf_f_fZfZfK=gK=g\\ WW44♨[[ccssbbPuPuvv䐙䐙qwqwyyzzҌҌzz22GzGz88xx yypp||22<~<~ՇՇ,,II}}ÊÊ{{xxovovtt~~ss__ttV^JV^JRgRg2 f2 f4f4fWfWfff:ff:ffffjfjf^f^flflfffofofÈfÈfofofffofofsfsfpfpf+f+ftftfffufuf]f]f,vf,vfIfIfvfvfffyfyf}f}f{{f{{f|f|f|f|fzfzf,f,fUvfUvf,f,frfrf f fnfnfZfZfJjfJjfffcfcfژfژf[f[fffffffDcDc$$,,DDŬŬeeYYnnNpNp^s^s̒̒vv//yyttzz77{{ъъ}} __--<f?>fLgLgXX[[^^̙̙zkzkՍՍ}}~~}};;G|G|nnzz5x5xzzEEzzcczzvyvyllyy,,{{88}}~~HH႙႙LL5}5}ڋڋ^{^{ߌߌ{{&&ffҘҘddJPJPggffYfYfafafmfmfmfmfFfFfofofffqfqfdfdf"qf"qf?f?fqfqf҅f҅fsfsf߄f߄f"sf"sfNfNftftfyfyfrfrfffrfrf4f4ftftf΂f΂fTvfTvfGfGf:xf:xf<f<f.zf.zfN|fN|f}f}fzfzf.f.f=uf=ufffVqfVqfDfDfnfnf:f:f'lf'lf7f7fIjfIjfƀfƀfwfwfJaJaaa;;r:r:``2H2H8f8foommuuttvvvv[[rxrxDD5y5yxx捙捙fzfz,,}}ee,,݀݀SS鈙鈙}}3z3zȏȏttmmNN@e@e``jjZZ`@`@YgYgo fo f!f!f Nf Nfff@`f@`f#f#f.hf.hfffkfkfff.nf.nf|f|fofofEfEfofofffpfpf܅f܅ftftfffwfwf~f~fzfzf|f|f|f|fx{fx{f@}f@}fyfyfffvfvf]f]fNtfNtfffqfqfmfmfLnfLnfffWhfWhf7f7fcfcfff^f^fޝfޝf]Sf]Sfѯfѯf?f?f~e~eA02A02mmәәJJtbtbbb l lUUqqєєtt$$WwWw<>TTqq$k$kppftftVxVx==||怙怙LLffɆɆxx~~}}t|t|䋙䋙@z@zddyyyywwxxmmww&v&vEEvvjjuuppSSQQ((y(y(jj5_5_8g8gofofqfqfPfPfMofMoffftftf.f.fOvfOvf f fvfvfffaxfaxf~f~f|f|fxfxfWfWftftfffsfsfXfXfrfrfffkqfkqfffqfqf8f8fLrfLrf;f;fKrfKrfffrfrfffprfprfff|sf|sflflftftfffufufffxtfxtf(;>##,,叙叙%_%_ϥϥffnntt葙葙vv;;~y~y{{뉙뉙~~CC[[QQEE||׋׋yyxx|v|v**uutt&&?u?uߑߑvvqqޙޙ%h%h66THTHbbHH]߸]߸$a$affffgfgfffjfjfff)mf)mf߉f߉fofofff_sf_sfvfvfvfvfffyfyf}f}f{f{f{f{f~f~fxfxf̀f̀fvfvfӂfӂf!tf!tfkfkf|qf|qf@f@fofofffpfpf3f3fofofffgofgof f fofofnfnf qf qfwfwfpfpfmfmfDnfDnfffcfcfffffffagagNNjjnn픙픙%v%vǐǐxx||||WWddރރƆƆDDꈙꈙ@~@~{{wywy&&zzQzQzwwyywwyyzzzztt}}ddDD>>szsz䒙䒙UeUe ՙ ՙPP녪녪#Y#YugugBfBf5f5f/yf/yfDzfDzfafafxfxfffyfyf0|f0|f}f}fxfxfffbvfbvfffsfsfffBqfBqfffpfpfff6pf6pf_f_fqfqfff7tf7tfffxvfxvfff8vf8vfNfNfivfivfفfفfUvfUvfffVyfVyf}f}fT{fT{fp{fp{f}f}f{f{f@}f@}fzfzf{f{fff Kf Kfbgbg"Z"ZAGAGؙؙcc dzdz||FFp|p|hh{{yyˎˎxx x xJJvv[[vv_y_y%%L|L|ЋЋ||]]||11WW~~}}bb||xxVV<f>fyfyf}f}f{f{fzfzfe~fe~fxfxfOfOfyvfyvfffsfsfQfQfrfrfffffqfqf>}j}jrr֑֑vvDDWvWvccwwzzJ{J{zzii{{yy||mm||_}_}]]܄܄SS33vzvz77jxjxuuooUUvivinnaanznzSCSC g glflfQfQfQfQfffbfbfefefhfhfffjfjfffjfjf^f^fmfmfffpfpfOfOfrfrffftftf8f8fvfvfKfKfzfzfu}fu}fzfzf}f}fL{fL{f3|f3|f}f}fowfowff>fpfpfffrfrfEfEf9tf9tf@f@foufouf5f5fxfxf~f~f |f |fyfyfefefvfvfwfwf2sf2sf؅f؅fpfpfffpfpfffpfpf1f1fpfpfffofofffClfClf~f~fhfhfzfzfcfcf2f2f}Sf}Sfff f fygygTATA(۹(vvss h hii{{ooɕɕrr::uu??yy }}##^^]~]~qqs|s|3{3{֌֌3{3{>{>{yyVV v vAAuutt__ctctPPqqkk66LLE3E3ii``ffzfzflflfififififffnfnfffrfrfqfqfVvfVvfffJzfJzf|f|f]~f]~fxfxfcfcfwfwfffvwfvwfMfMfwfwfff2wf2wfffvfvf̂f̂fvfvf5f5fufufffDvfDvfJfJftftfLfLftftfffufufffjtfjtfPfPfspfspfffDbfDbfffffggCQCQqq11ӘӘbb]e]e>>mama``$b$bggllssʏʏ|}|}uubbddmmPP<OROROROROROROROROROROROROROROROROROROROR>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<>OO溺RR<fUg^Hq{bҙ}[g0ffoffvffwffyff{f|f}fzffzf~f{f|f}f{f~fzf~f{f}f{f}f|f{ffxffzf}f|f|f|f}f|f{f~fzffyfftffMfgKa>$晎|y^ޙNkP Wgffeffpffuffxff{f}f{f}f{f~f{f}f{f}f|f|f|f}f{f~fyffyf~f|fzffxffyf}f}f{f~fzf~fyffvffrff^ffYc,]}uX5vSgffifftffuffwffxffxffzf}f|f|f|f}f|f{f~fzf~f|fzffxff{f|f|f}f|f{f~fzf}f}f{f}f}fzf}f~fxffpffd}4jӦ$zy^FNgffffftffyffzf~fzf}f|f}f{f~fyffzffxffwffyf}f}fzffyffyffyf~f{f|f}f}fzffyffzf~fzffxffrff;۱蘰s{t]ٙmeHrg.fflffwffxffwffyf}f}fzffzf~f{f|f}f{f}f}fzffyffzf~fzffyffyffzf}f|f|f|f}fzffxffuffnffMffB{DǙg}|fșCBfLfftffyffzf~f{f|f}f|f{ffxffyffzf}f{f~f{f|f}f{f}f|f{ffyffzf}f}fzffzf}f|f{ffyf~f}fvffeff)ftgHdoי`y}~|q꘮;fsffxffzf~f{f|f~fyffyf}f}f{f}f|f{f~fzffzf}f{ffxffxff{f|f}f|f|f}fzffzf~f{f|f}f|fzffuffiff!fgN D\yv!l{4dfuff{f}f{f}f|f{f~f{f}f|f{f}f}f{f}f|fzffyf~f{f|f|f}f|f|f|f|f|f}f|f|f|f|f}f|f|f|f|f}f{ffvffhfffgSv4Wv~_ˑ,_cfcffxf~f{f}f|f{f~f{f}f{f}f{f}f|f|f|f}f{f|f}f|f|f}f{f|f~fzffyffzf}f}f{f|f~fxffuffvfftffifffgWP mK^{x<$MagMffrffxffyffzf}f|f|f}f{f}f|f{f~fzf~f{f}fzffwffwff|fzffxffyffzf}f|f}f{f}f|f{ffwfflff*fg[ ҙbz}mF^[g7ffjffuffwffxffyf~f|fzffxffyf~fzffwffyf}f~fyff{f{ffyffzf}f|f|f|f}fzffzf}f~fvffkff8fZg^Gm~{cљ [g(ffiffvff{f|f~fyff{f|f}f{f}f}fzf~f{f}f|f|f{f~f{f}f|f{f~fzf~f{f}f|f|f|f|f}f|f{f~fzffxffpffJfgMa<$㙒w~~v[MmM Wg"ffjffvffzf~fzf~fzffyffzf~fzf~f{f}f|f{f}f}fzf~f{f|f~fyffyf~f{f}f|f|f|f|f}f{f}f{f~fzffxffdff\c, b~}zZ5wSgffhffuffxffyffzf}f|f}fzffyffzf~fzffyffzf~fzffyffzf}f|f}f{f}f{f}f}fzffzf}f|f|f|f}f}ftffd4iӦ%z~~x\ENgffhffvffzf}f|f|f|f}f|f|f|f|f}f{f~fyffxffyffyffzf~f{f|f}f|f{f~fzffyffxffwffyf~f{f~fxffpff;۳昱s{b֙oe~Hng2fflffuffxffyffyffzf}f|f}f{f}f|f|f}fzf~f{f}f|f{f~fzf~f{f}f|f|f|f|f}f{f~fzf~f{f}f{f~fyffrffNffB~Břgz~}fʙIyBfJffpffxf~f|f{f~f{f}f|f{f}f|f}f{f|f~fyffxffyf~f{f~fyffxffzf}f|f{ffxffxffzf}f|f|ffuffkff1fmgH~fmٙ]v~s蘱;fpffvff|f|f|f}f{f|f}f|f|f}fzf~f{f}f|f|f|f|f|f}f{f}f|f{f}f}fzffyf~f|f{f~fzf~f{f}fzffwfftffifffgNF[xz$i4dfuf}f~fzf~fzf~f{f~fzf~fzf~f|f|f|f|f|f}f|f|f|f|f}f|f{f~fzf~f|fzffzf}f}fyffzf}f|f{f~fzffuffefffgSu5Zx]˓,]cfbffvff|f{f~fzffyffzf}f}f{f~fzf~fzffzf}f|f|f|f}fzffyffyff{f}f{f|f}f}f{f}fzffzf~fyfflff fgWO mL\w|~x<$MagLffqffvffyf}f~fyf~f|f{ffxffyf~f|f{f}f}fyffvffxf~f|f|f|f}fzffyffxffzffyffwffvffmff/fg[}ԙ_w~oE^Xg=ffpffxf~f|f}f{f}f{f~fzffyf~f}fzf~f{f|f}f|f|f|f}f{f}f|f|f|f~fyffyffyffyf~f{f~fzffxffoff;fYg^Ckz~xaҙ~[g-fflffwff{f|f}f{f}f|f|f|f|f|f}f|f|f|f|f}f{f~fzf~f|f{f}f|f|f}f{f}f{f~f{f|f}f|f{f~fzf~f{ffuffOfgNa;$㙑yw[KmN Wg ffgffsffyf}f}f{f}f|f|f|f}f{f}f|f|f}f{f}fzff{f|f|f}fzffwffzf|f}fzff{f|f|f|f}f|f|f{ffwffaffYc,_wX4uSgffgffrffwf~f}f{f|f~fyff{f{f~f{f|f~fyf~f|f|f|f}fzffzf~fzffyffzf~f|fzffyff{f|f}fzffyfftffd{4lӤ%xy^ߙINgffhffsffxf}f~fyffyffyf~f|f|f}f{f}fzffvffwffzf~fzf~fzffyffyf}f}fzffyf}f}fzffzf}f}fxffnf f;ۯ蘱s|fљu^Htg-ffkffuffxffzf}f}fzf~f{f}f|f|f|f}f{f}f|f}f{f~fyffxffzf|f~fyff{f}f{f|f}f|f|f|f|f|f}fyffoffGffB}Eədx~}{hƙE|BfIffpffyffyffxff{f}f{f~fzf~f{f}f{f}f{f}f}fzffyffzf}f|f}f{f}f{f}f|f|f}fzffyff{f|f~fwffmff0fngH~enי`yp阯;foffwf~f}f{f|f~fyffyf~f{f}f|f}fzffyff{f|f|f}f{f}f|f{f}f|f|f|f}f{f}f{f}f|f|f}f{f|ffvffqffffffgNJ\w}x$j~4dfuf~f|f{f~fzffyf~f{f}f}fzf~fzffzf}f|f|f|f|f}f{f~fzf}f}f{f~fzf}f|f|f}f{f}f{f}f|f{ffxfftffhfffgSs8]{^˖,Ycf^ffwffzf}f{f~f{f|f}f{f~fzf~f{f}f|f|f}f{f}f{f}f|f|f|f|f|f}f|f{f~f{f|f~fyffzf~fzffwffrffiff"fgWK qGZw}9$PagNffsff{f}f|f}fzf~f{f}f|f{f~fzf~f{f|f~fzf~f{f|f}f|f|f|f|f}f{f}f|f|f}f{f|f}f|f|f{ffwfftffkff+fg[ љby{iK^Vg$㙑xx\LlP Wgffeffrffvff{f{f~f{f|f}f{f|f~fzf}f}fzffyf~f|f|f|f|f|f}f{f}f|f|f|f}fzffzf}f|f|f|f}fzffuff]ffYc,^~{v[9rSgfffffvffxffwffwff{f|f}f|f{f}f|f|f}f{f}f{f~f{f|f~fxffyf}f}fzffzf}f|f|f}f|f|f|f|f}f{f~f|fuffd}4kӥ$vy]HNgffgfftffyffzf}f|f|f}f{f}f|f|f}fzffyffyf~f{f}f{f}f|f|f}fzffxffvffwffzf~fzf~f{f}f{f~fxffqff;۶☷m|zb֙ng|Hmg2ffnffvffwff{f|f}f{f}f|f|f|f}f{f~fzf}f|f}f{f}fzffzffxffyffzf~fyffwffxffzf~f{f}f{ffrffKffB@l{~yhřB~BfKffpffwffxffyf~f{f}f|f{ffyf~f|f{f~f{f|f|f~fzf~fzf~f|f{f~fyffyf~f{f}f|f|f|f|f}f{f}f}fxffiff*fugHcnؙ`}~q蘱;foffsffwffzf}f|f|f}f{f}f|f|f|f}fzffyff{f{f~fzffzf|f~fzf~fzf~f{f}f|f{f~f{f|f~fzf~fzffxfflff"fgNFYv~y%l}4dfsff|f{f}f{f~fzf~f|fzffzf}f~fxffzf}f|f|f|f|f~fyff{f{ffzf|f~fyffyf~f{f}f{f~fyffvfftffjfffgSs7Xs|[˔,]cffff{f}fzffxff{f|f}f|f|f|f|f|f}f}fzf~f{f}f{f}f|f}f{f|f|f}f|f}fzffyffzf~f{f}f{f}f{ffwffkff!fgWJ qI]y|;$NagNfftffzf}f{f~f{f|f}fzffzf}f|f|f}fzf~f{f}f|f|f{ffyffzf}f}f{f}f|f{f~fzffyffyffxffuffkff*fg[Ιez~~ziK^Wg;ffoffwffzf|f}f{f~fzffxffyf~f|f|f|f}fzffzf~f{f|f}f|f{f~fzffzf}f|f{ffyffyffyffuffmff;fWg^Jn}|eЙ}[g*ffkffxf~fzffxffyf~f{f~fzffyffyff{f|f}fzf~f|f{f~fzf~f{f}f{f~fzffxffyffzf}f{ffxffpffLfgMa<$晏zx\JmN Wgffdffqffwff{f}f{f~fzf~f{f}f|f|f|f}f{f~fzf~fzffzf~fzf~f{f}f|f{ffyffzf}f}f{f}f{f~fzffwffaffZc,]{]6wSgfffffuffwffyffzf~f{f|f}f{f~f{f|f|f|f~fyffwffyf~f{f}f|f|f|f}f{f~fzf~f{f|f}f|f|f|f|f}f{ffrffd~4kӣ({~x[HNgffgffuff{f|f}fzffzf}f|f{ffyffzf}f|f}f{f}f|f{f~f{f}fzffwffzf{ffxffzf}f|fzffwffwffvffoff;۵䘴o|}~y^ڙlf~Hpg.ffiffxf}f}fzf~f{f~f{f{f~f{f|f~fyffxffyf~f|f|f|f}fyffwffyf}f|f|f}f|f|f{f~f{f|f}fzffyffqffIffBAșdw}fəGzBfLffpffyf~f{f}fzffzf~f{f}fzffyff{f|f}f{f}f|f|f|f}f{f}f|f{f~fzf~f{f}f{f~fyffzf|f~fxffuffjff.frgHbpי_yq蘯;fqffwffzf}f|f|f|f}f{f}f|f|f|f}f{f}f|f|f|f}f{f~fzf}f|f}f{f}f{f}f}f{f}f{f~fzffzf}f|f|f|f~fxfflff fgNF\y~w#j}4dfvf~f{f}f|f{ffyffzf}f|f|f}f|f{f}f{f~f|f{f|f}f|f}f{f|f~fzffyffzf~f|f{f~fzf~f{f}f|f{ffvffhfffgSt6[{`˕,Zcf`ffwff{f|f}f{f}f|f}fzf~f{f}f}fzf~f{f}f{f~fzf~f{f}f|f|f|f|f}f|f{ffxffwffwffvfftffpffefffgWI sG[x}y<$MagLffqffyf~f|f|f{f~fzffyffzf~f{f|f~fyff{f{ffyf~f}fyffyf~f|f{f}f}fzffyf~f|f{ffwffsffhff(fg[Йcx}kI^Xg:ffmffxffzf~f{f|f~fyff{f|f~fyffzf}f}f{f|f}f{f~f{f{f~f{f}f|f|f|f|f}f{f}f|f|f|f}fzffvffnff$噏|}w^ߙLmO Wgfffffvffzf}f{f~f{f|f}f{f}f}f{f|f~fyffzf|f}f{f}f}fyffxff{f{f~f{f}f{f}f{f~f{f}f{f~fyffwffcff\c,\}wY7tSgffhffuffxffxffwffzf}f}fzf~f{f}f|f{f~fzf~f|f{f}f{f~f{f}f{f|f~fzf~fzf~f{f~fzf~fzf~f|f|f|f}fvffdy4oӢ'z|`ޙINgffjffwffyf~f}fyff{f}f{f~fyffyf~f{f}f|f|f|f|f|f~fzf~fzf}f}f{f~fyffzf~f{f|f}f{f~fzffxffvffpff;۴☸jy}{b֙pcHog1ffkffuffyf~f{f}f{f}f|f|f}fzf~f{f}f|f|f|f|f}f{f}f|f|f}fzffzf}f}fzffzf}f|f{ffyffwffwffpffKffB{Eƙi}~~~jęD|BfKffrff{f~fxffvffyf~f{f~fzf~fzf~f|f|f|f|f|f}f|f|f{ffxffzf}f|f|f|f|f}f{f}f|f|f|f}fzffvffjff.fqgHdp֙az~~q昲;foffvffzf~f{f}f|f{f~f{f|f|f}f|f|f|f{ffyffzf}f|f|f|f~fyffzf}f|f|f|f}f{f|f}f{f~fzffwffsffffffgNG[u{}~y'm{4dfuff{f}f{f~fyffyf~f|f{f}f|f|f|f}fzffzf~fzf~fzf~f|f{f~fzf}f|f}f{f~fyff{f|f}f{f}f}fyfftffffffgSr8Yv` ˒,^cfcffvffyf~f|fzffzf~f{f}fzffzf~fzf~fzf~f{f}f{f}f|f{ffxffxffzf~f{f}f|f{f~f{f}f{f|ffwffkff"fgWM nJ[v~{=$LagMfftff|f|f|f}fzffyffxffxffzf}f|f{f~f{f}f{f}f|f}f{f|f}f|f|f|f|f|f~fzf}f{f~f{f}f{f~fwffiff)fg[~ؙ]w}}oE^\g6ffkffxf~f{f~fzf}f}f{f}f|f|f}f{f}f{f~f{f|f}f{f}f|f{f~f{f}f{f}f{f~f{f}f{f}f|f|f|f}fzfftffjff:fVg^~Ll|~~}dҙ[g*ffjffsffwffzf}f|f{ffxffzf|f~fyffyffzf}f|f|f}f|f|f{f~fzf~f{f}f{f}f{f~f{f|f}fzffwffrffOfgOa;$噏z{^HsI Wgffiffuffvffwffyf}f|f|f|f}f{f}f{f~fzf~f{f}f{f~fzf~f{f}f{f~fyffyf~f|f{f}f|f|f}fzffyffuffaff\c, avY6tSgffeffrffvffzf}f}f{f}f{f~fzf~f{f}f|f|f|f|f~fyffxffzf}f{f}f|f|f}fzffyffxff|f{f}f|f{ffzfxffd{4mӣ'|wZDNg!ffiffuffyf}f}f{f}f{f}f|f{ffyffzf|f~fzf~f{f|f~fyffyffzffzf}f{f}f|f}f{f}f{f}f}fyfftfftffpff;۰昵m|zbԙraHqg0ffnffyf}f}fzf~f{f}f|f|f|f|f}f{f~fzf~f{f|f}f|f|f|f|f|f~fzf}f|f|f}f|f{f~fzf~f{f~fyffxffxffpffJffB~BǙgz}l=BfHffpffuffxffyf}f|f}f{f~fyffzf~f{f|f}fzffyf}f|f|f}f|f|f|f{f~f{f}f|f{f~fzf~f|f{ffxffvfflff0fogHcrҙe}s䘵;fnffrffwff{f|f|f}f{f~fzf}f|f}f{f~fyffzf~f{f}f{f}f|f|f|f|f|f}f|f{f~fyffyffyffzffxffsffgfffgNDZxx#l{4dfuff{f|f}f{f}f|f|f}f{f}f|f{f~f{f|f~fzf}f}fzffzf}f}fzf~f|fzffxff{f|f|f}f|f|f{f}f|f|ffuffhfffgSq:[v~_ ˓,]cfdff|fzf~f{f}f|f|f|f|f}f{f}f|f{f~f{f|f}f{f}f|f|f|f|f}f{f}f|f{ffyffyffxffyffyffyffuffhfffgWM pI\z{=$KagKffsff|f|f|f|f|f}f|f|f|f{ffyffyffzf~f{f|f}f{f~fzf~f{f|f~fzf~fzf~f{f}f|f{f~fzffxffsffeff(fg[ ҙbx~}kK^UgfUg^Ip|xcϙ[g+ffifftff{f{f~fzf~f{f}f|f|f|f|f|f~fyffyff{f|f}f{f}f{f~f{f~fxffuffuffxf~f{f~fzffwffsffOfgNa;$♑zzt\ߙMlO Wgffdffsffxffxffyffzf~fzf~f{f|f~fyffxff{f|f}f|f{f}f|f|f~fxffzf}f|f|f{ffyffyffyffxffeff_c,^y[9rSgffgffxf~f{f|f|f}f}fzf~f{f|f~fyffyf~f{f}f{f~fyffxffyf~f|f|f{ffxffyf}f|f|f|f}f{f~fzf~fzffuffdw4qӠ)z}v]HNgffiffuffyf~f{f~fyffxffzf}f{f}f|f}fzffxffxffzf~f{f|f}f{f~fzf~fzf~f{f}f|f{f~fzf~f|f{f~fxffsff;۵䘴o~{`ؙmg|Hmg2ffjfftffyf}f|f|f|f}f{f~fyffxffzf|f}f{f}f}fzf~f{f}f|f|f|f|f}f|f{f~fzf~f|f{f}f|f|f|f~fwffkffEffBCǙfz}gșDBfEfflffvffzf}f}f{f}f{f}f}f{f}f{f~fzf~f{f|f~fyffzf~fzffyffzf}f}fzffzf}f|f|f}f{f~fyffuffjff-frgH`sәcys昴;fpffxf|f}f|f|f~fxffwffyf~f{f}f{f}f|f}fzffyff{f{ffxffwffxffyf~f{f~fzf~f{f|f~fzf}f}fxffiff!fgNDZw}}x"j}4dftff|f{f~fzf~f{f}f|f{f~f{f|f}f{f}f|f|f|f|f}f{f~fzf~fzffyff{f|f|f|f}f|f{f~fyffwffxffuffhfffgSu7\x}b ˕,Zcf`ffwff{f}f{f}f|f}fzffzf}f}fzf~f|f{f~f{f{ffyffzf}f|f|f}f{f}f{f}f}f{f}f|f{ffxffwffuffhfffgWL oKߙ_|~}w:$OagPffsffyffyffxffzf}fzffxffwffyffyf~f{f|f~fzf~fzffyffzf}f}f{f}f{f~fzffyffyffvffjff,fg[~ љby|lK^Wg;ffnffxf~f{f}f|f|f}fzf~f|fzffxffyf~f{f|f~fzf~f{f|f}f{f}f|f|f|f}f{f}f{f}f|f|f}f{f}f|fzffpff;fXg^Hnzbҙ}[g,ffhffrffxffzf~fzf~f{f}f|f|f{f~f{f}f|f{f}f}fzffyffzf~fzffyffzf~fzffzf}f{f~fzffvffqffLfgLa>$晎{z]KnN Wgffefftff{f|f}f|f{f~f{f|f}f{f}f}fyffyf~f|f{f~f{f|f}f{f~fzf}f|f}f{f}f{f}f|f|f|f}fzffyfftff^ffXc,]~w\8tSgffhffuffxffzffzf}f|f{f~f|f{f~fzf}f}f|f{f~fzffyffyffzf|f}f{f~fzf~f{f}f|f|f{ffyf~f|f{fftffd{4mӣ&x~~w]ߙJNg!ffiffuff{f|f|f}fzffzf}f|f|f}f|f{f}f|f|f}f{f}f|f|f|f}f{f~fzf}f}fzffyffzf}f|f|f}f{f~fxffsffnff;۶㘴p~y_ؙmf~Hng0ffkffvffwffwffyf~fzf~f{f}f|f|f|f|f}f{f}f{f}f|f|f|f}fzf~f{f~fzf~fzffyffyffyffxffwffoffIffBAęh}{hřC}BfKffqffwffwffxff{f}f{f}f|f|f}f{f|f}f{f}f|f|f|f|f|f|f~fzf~fzffyffyffxffyf~f{f}f{ffwffkff-fqgH|hlؙa|~~s瘳;fofftffyf~f{f}f{f}f|f{ffwffvffzf}f|f}fzffxffvffxf}f~fzf}f}f{f}f|f{f~f{f}f|f{f~fyffsfffff fgNI]zw$l|4dfuf}f}f{f}f|f|f|f}f|f{f~fzf~f|f{f}f|f{ffxffyffyffzf}f}fzf~f|f{f~fyffxffzf|f}f{f|ffuffhfffgSt8[x`˖,[cfbffvffwffzf}f|f}fzffyffyf~fzf~f{f}f|f|f|f|f}f{f~f{f|f}f{f~fzf~fzf~f{f}f{f}f{ffwffpffefffgWO lMߙ^y}}<$MagNffsffyffyffzf~f{f|f|f}f|f|f|f}fzffyffyf~f{f}f{f~fzf~f{f}f{f~fzf~fzffyffxffxffuffiff)fg[ ϙd{{kF^Zg:ffoffuffwff}fyf~f}fyffxf~f}fzf~f{f|f~f{f|f|f}fzffxff{f|f|f}f{f~fzf~fzffyffwffvffpffffpffwffxffxffwffxff{f|f}f|f|f{f~f{f}f|f{f}f}fzffyff{f{ffxffxffzf~fzffyffwffqff>fUg^Ji{z_ՙ [g*ffjffwf~f{f~f{f}f{f}f{f~f{f|f~fyffzf}f~fyffzf}f|f|f}f{f}f{f}f}fyffxffzf}f|f{f}f|f{ffrffMfgQa7$#ޙxy\KnM Wg!ffjfftfftffvffzf~fzffyf~f}fzffyf~f|f|f|f}fzffzf}f{f}f|f~fyffzf}f~fyffzf~fzffwffuffaff[c,_vZ6uSgffjffwff{f}f{f~fyffyf~f|f{f}f}fzf~f{f|f}f|f|f{f}f|f}f|f{f|f~f{f|f~fyff{f{f~f{f}f|f{f~fyffsffd{4mӤ%yw[FNg"ffkffvffxffzffzf}f|f{f~f|fzffzf}f|f|f}f{f}f{f}f}f{f}f{f~fzf~f{f|f~fzf~fzf~fzffwffvffsffmf f;۱昳p~~y`ؙne~Hog1ffmffvffxff{f|f|f}fzffxff{f|f~fyffxffzf}f|f|f{ffyffyf~f|f|f|f|f|f}fzffxffxffxffpffJffB}Eșf{}gǙE|BfKffpffxffzf~fzf~f{f}f|f|f{ffyffxff{f}f|f{f}f|f|f}f{f}f{f}f}fzffyffzf~fzf~fzffxffrffhff,fsgHemٙ^zo☵;frff{f|f|f|f|f}f{f~fyffxffzf}f|f|f|f}f{f}f{f~fzf~fzf~f{f}f|fzffxffxf}f~fyffzf{ffwffuffiff fgNI]z{&k~4dfsffyffzf~f{f}fzffwffwffzf|f~fzffxffyffzf}f|f|f|f}fzffzf}f|f|f|f}f{f|f~fzffxffuffffffgSs8[v}b ˑ,^cfbffuffyf}f~fxffvffyf~f{f}f{f}f|f}fzffyff{f|f}f|f{f~fzf~f|f{f~fzf~f{f}f|f}fzffvffrffhff fgWK pJ\w9$OagNffuf}f}f{f}f|f|f}fzffxffxff{f|f|f}f{f~fzf~f{f}f{f}f{f~f{f|f|f}fzffwffwffwffxfftffhff'fg[ Йd}mI^Zg8ffmffvffuffwffzf}f|f|f|f}f{f~fzf~fzf~f{f}f{f~fyffyf~f{f}f|f|f}f{f|f~fzffyf~f{ffxffmff7f\g^Gj}}~|eϙ [g'ffeffqffwff{f}fzffwffyf}f}f{f|f}f|f{f~fyffzf|f}f{f}f|f|f|f}f{f}f{f~f{f}f{f}f{ffxffrffMfgOa9$ ᙓw}~x]KnM Wg ffhfftffxffyf~f{f|f~fzf~f{f|f}f{f~fzffxffzf}f|f|f{ffyffzf}f|f|f~fyffzf}f}f{f|f}f|fyff_ffYc,]~wZ6uSgffhffsffwffyffzf|f~f{f|f~fyff{f|f}f|f{f~fzf}f}fzf~f{f|f}f{f~fyffxffzf|f}f{f~fzf~f{f|ffrffd~4kӤ&z}v_ݙJNgffgffuff{f|f}f{f|ffxff|fzffxff{f}f{f}f|f|f|f}f{f}f|f{f~fzf~f|fzffyff{f|f|f|f|f~fyffvffpff;۲嘴o~}cՙoe~Hng1ffmffvffxffxffyffzf}f|f}f{f}f|f{ffyf~f|fzffzf~f{f|f|f}f{f~f{f|f}f{f}f|f}f{f~fyffwffmffFffB~DǙf|~~~|iƙF{BfIffqff|f{f}f|f|f|f}f{f|f}f{f}f|f|f|f|f}f{f}f}fzf~f|f{f~fzf~f{f|f}f{f~fzf~f{f|f~fyffxffuffhff,frgHcpי_w}yk䘲;fqffyffyffzf}f|f|f|f|f~fyffzf~f{f}f|f{f~f{f}f|f|f{f~f|f|f|f{f~f{f}f{f}f|f{f~f{f|f~fxffsffgff fgNG\w~~{$k~4dfsff|f|f|f|f|f}f{f}f|f{f~f{f|f}fzffzf~fzf~f{f}f{f~fzffyf~f|f|f|f|f|f|f}f{f}f|f{f~fzffvffjfffgSs7[y^˕,Zcf`ffvf~f}f{f~fzf~fzffzf}f}fyffwffxf~f|f|f|f}fzffzf}f|f|f|f~fzf~fzf}f}f{f~fzf~f{f{ffvffiff fgWL pI\z|<$NagNfftffzf~fyffyffyffzf}f}fzffyf~f|f|f|f}f{f}f|f|f|f~fyff{f{ffyffzf~fzffyffxffvffmff+fg[ әaz~~oG^Xg;ffpffxffzf}f}f{f|f}f{f}f}fyffwffzf~fzf~fzffzf}f|f{ffyf~f|f{f~f{f}f{f}f|f|f}f{f~fyffnff;fWg^Kk|~~~~xcЙ [g(ffjffuffvffwffxffzf~f{f|f}f{f}f|f|f|f}f{f~fzf}f}fzffwffvffzf}f{f~fyffzf|f}f|fzfftffPfgNa<$♒xz\JnO Wg ffifftffxff{f|f|f}f{f~fzf}f|f|f|f|f|f}f|f{f~fyffxff{f|f}f{f~fzffxffzf}f}fzf~f{f|ffwffbff]c,^vW5uSgffeffrffwffzf}f|f|f|f|f|f}f{f}f{f}f|f|f|f}f{f~fzf~f{f~fyffxffzf|f}f{f}f|f}f{f}f{f}f}fzffsffd}4lӤ%v{~x\HNgffhffuffxff{f}f{f}f{f~fzffyffzf}f}fzffzf}f|f|f}f{f|f~fyffwff{f}f|f|f|f|f}f{f~fzf~f|fyffqff;۴䘵n|za֙odHpg.ffiffxf|f~fzf~f{f}f{f}f}fyffwffzf~fzffxff{f{f~fzffyffyffyf~f{f}f|f}fzffyffyffuffnffJffB}Dřj|~zgƙB~BfJffrffzf}f{f}f}fzffyffzf}f|f|f}f|f{f~fzf~f|fzffxff{f|f}f|f{f~fzffyffyffxff{f|ffuffkff0fogHarԙb{t꘯;fqfftffwff{f|f}f{f}f{f~fzf~f{f|f}f|f|f}fzffzf~f{f|f}f{f~fzf~f{f}f|f|f|f}f{f~fzf~f{f|f~fxffjff fgNG[xx!i}4dfwf|f}f|f|f}fzffzf}f|f|f|f~fyffzf~f{f}f{f~fzf~f{f|f}f|f|f|f}fzff{f|f}fzffzf~fzffxfftffifffgSs7Zuy|b ˑ,^cfaffvff|fzffxff{f|f}f|f{f}f}fzffwffxff|fzffyffzffyffyffzffyffzf|ffxffwffuffffffgWM oK]y}~}y:$PagQffsffvffwffzf}f}fzf~f{f|f~f{f|f|f|f}f|f}fzf~f{f}f}f{f|f}f{f~f{f|f|f}f|f{f~fyffwfftffiff*fg[ Йd{}mF^Yg:ffmffvffzf|f}f}fzffxffzf~fzf~f{f}f{f~fzf~f{f|f~fyffxff|f{f}f|f|f|f~fyffxffwffuffnff8f[g^Gk{zfΙ [g+ffjffuffyffzf|f~fzf~f{f}f{f}f|f{ffyf~f{f|f}f|f|f|f|f|f}f{f}f|f|f|f|f|f}f|f{f~fyffvffqffKfgJa?$䙐z~v[LlP Wgffgffsffwffyffzf}f|f|f|f}f{f}f{f~fzffyf~f|f{f~f{f{ffyffzf|f}f|f}f{f|f|f}f|f}f{f|f~fxffbff]c,_xY5vSgfffffrffwffyffyffxffyffyffzf~f{f|f}f|f|f|f|f}f|f|f{f~f{f~fyff{f|f}fzffzf}f|f{f~fzffuffdz4nӣ%x}w\INg"ffiffuffyffyffzf~f{f}f{f~fzf}f}f{f~fzf}f|f|f}f|f{f~fyffyffzf|f}f|f}f{f}f{f}f|f|f~fxfftffpff;۱嘶ky{_ٙmeHsg,ffhffrffvffzf~fzf~f{f}f|f{f}f|f}f{f}f{f~fyffyf~f{f}f{ffxff|fzffxf~f}fzffxfftffrffoffLffB}DǙf|~xdəFzBfMffpffvffyf~f|f{f~fzf~f{f|f~fyff{f{ffxffzf}f|f|f|f|f}f{f}f|f|f|f|f|f}f|f{f~fzffxffvffiff+ftgHbqԙc{~o㘶;fsffzf}f{ffwffxf~f{f}f|f|f|f}f{f}f|f|f}f{f|f}f|f|f|f}fzf~f{f}f|f|f}f{f}f{f}f|f~fyffyfftffefffgNDYz~y'ox4dfwf}f{f~fzf~f{f}f{f~fzf~fzffyffxffzf~f{f}f{f}f|f{f~fzf~f{f}f{f}f{f}f|f|f~fwffuffvffrffefffgSs8]x~]˒,^cfcffyf}f|f|f|f}f{f}f|f{ffyffzf}f}fzffxffzf~f{f~fyffyffyf~f{f|f~fzf}f}fyffwffxffvffhfffgWM oJ\wz!9$NagLffsff{f}f{f}f{f}f|f|f|f}f{f|f}f{f~f{f|f|f}f|f|f}fzffzf~fzf~f|f{f~fzf}f}f{f|f~fzf}f~fvffkff-fg[|ՙ`x|mE^\g7fflffvffvffuffxffxffyf~f|f{f~fzffyffyff{f|f}f{f}f|f|f|f}f{f}f|f|f|f|f|f}f{f~fxffnff:fXg^Imz}}dЙ [g(ffhffsffxf~f|f{f}f}fzffyf~f|f{f~f{f|f|f}fzffyf}f}fzffzf}f|f}f{f}f{f~f{f|f}f{f}f}fzfftffOfgNa;$ᙔu~x[IqJ Wg#ffmffzf}f|f}fzf~f{f|f~f{f{f~fzf~f{f}f{f~fzf~fzffyffyf~f{f}f|f}fzffyffxff{f|f}f|fzffvffaffZc,`~x[:qSgffkffxf~fzffxff{f{ffyffyff{f{ffxffyffyffxff{f|f}f|f{f~fzf~f|f{f~fyffzffyffyff|fuffd}4kӥ%x~}x]HNg!ffiffuffzf}f|f|f|f}f{f~fzf~f{f}f{f~fzf~f{f|f~fyffxff|fzffyffzf~f{f|f~fyffyf~f{f}f{fftfflf f;۴㘶m}y`ؙndHug*ffgffrffwffxffyf}f~fyff{f{ffzf}f|f{f}f}f{f}f|f{ffyf~f{f}f|f|f}fzf~f{f}f|f|f{f~f{f{ffoffHffB}Dři{}}ziřE{BfLffpffvffwffzf}f|f|f}f{f}f{f}f}fzf~fzf~f{f}f|f{f~fzf~f|f{f~fzf}f~fxffvff|fzf~f|fzffuffkff.fqgHcqԙc{}p꘮;fqffwffzf|f}f{f~fzffxffwffyf}f}f{f}f}fzf}f~fyffxff{f}f|f{f~fzf~f|fzffxff|fyffuffsffgfffgNH[v~}&l}4dfqffyffyffwffvffvffyf|f~fzffyf~f{f|f~fzf}f|f|f|f}f{f~fzf}f|f}f{f~fyffyf~f|f|f{ffvffgfffgSx4Xw^˖,Zcfaffyf|f}f{f}f|f|f|f|f}f{f}f|f|f}f{f}f{f~f{f}f{f}f{f~f{f|f}f{f~fzf}f}fzffxff{f{ffxfftffhff fgWJ rGZx}}z:$PagQfftffxff{f|f|f}f|f{f~f{f|f}f{f}f|f|f|f}f{f|f~fyffyf}f~fxffzf|f~fzf}f}fzffzf}f|f}fyfflff+fg[ ϙcx||ymI^Ug$LagLffofftffxf~fzffyff{f|f|f}fzffzf}f}fzf~f{f}f|f|f|f|f}f{f}f|f|f}f{f|f~fzf~fzffxfftffkff+fg[ Ιf|~kJ^Yg9fflffwffzf}f|f|f{ffyffzf}f}fzffzf}f}f{f}f|f|f|f}f|f{f~fzf~f{f|f}f{f~fzf~fzf~f{ffvfflff9fYg^Hk}{cљ [g-ffnffwffzf}f{f}f{f~f{f|f|f|f}f{f}f|f|f}fzf~f{f~fzf}f}fzf~f{f}f|f|f|f|f}f{f}f{ffxffvffqffOfgPa;$晎{}w\JoM Wgffhffuffyf~f{f}f{f}f|f{f~f{f{ffvffwff|fyffxffxff{f}f{f|f}f|f}fzf~f{f}f|f|f|f|f}f|fzffcff]c, a~{u[9rSgffiffwff{f|f}f{f}f|f|f}f{f}f|f|f}f{f}f|f{f~f{f|f~fxffxff{f{ffyffyffzf~f{f|f}f|f{f~fzffsffd4hӨ"w~z]FNg!ffgfftffxffzf~fzf~f{f}f{f}f{f}f|f{ffyf~f{f}f|f}fzf~fzffzf}f|f{f~f|f{f}f{f~f{f}f{f~fyfftffmff;۲昳p}}x`יocHpg0ffnffwffxffyffzf}f{f}f}f{f}f{f}f|f|f}f{f~fzf~fzffzf~fzf~f{f}f|f{f~f{f}f{f}f{ffyffxffqffJffB|Eșgz{ięB~BfMfftff|f|f|f~fxffxff{f{f~f{f|f~fyffyf}f}f{f~fzf~fzf~f{f}f{f~fzf~f{f}f|f}fzf~f|f{f~f{fzffiff-frgHbrԙb{o嘳;fqffxffyffzf}f|f}f{f}f{f}f|f|f|f}f{f~fzf}f|f|f}f|f{f}f|f|f}f{f}f|f|f}fzffyffyf~f{f|f~fxffhfffgNLݙ_x~}}|%i4dfvfzffuffwffzffzf}f|f{f~f|f{f}f|f{f~f{f}f|f{f}f{f~fzffyf~f{f}f|f|f|f|f~fyffxffyffvffffffgSu8]x]˖,Zcfafftffvffyf}f|f}fzffyffyffyf~f|f{f}f}fyffwffzf}f|f}fzf~f{f}f|f}fzf~f{f}f|f}fyffsffffffgWL pJ^z~}x 8$QagPffsffyff{f|f|f}fzffzf~fzffxffzf}f}fzf~f{f}f|f|f|f|f}f{f}f|f|f|f|f|f}f{f~fzf~fzffwffiff'fg[ љbwz|lG^Zg9ffnffxffxffwffzf}f}fzf~f{f}f|f|f|f|f}f{f}f|f|f|f|f|f~fyffzf}f|f}fzffyffzf~fyffvffnff=fVg^Fn|zbҙ [g)ffjffwf~f|f|f}fzffyff{f|f|f|f}f{f~fyffyf~f|fzffxff{f}f{f}f{f}f}fzffyffzf~f{f}fzffpffIfgMa:$㙐{~|w[GsI Wgfffffuff|f|f{f~fzf~f{f|f}f|f{f}f|f|f}f|f{f~fzf~f{f}f{f~fzf~f{f|f}f|f|f}f{f}f{f~f{f|f|f~fwff]ffWc, azZ6uSgffdffsffvffwffwffzf|f~fzf~fzf~f{f}f|f{f~fzf~f{f|f~fzf~fzf~f{f~fzf}f|f|f}f|f{f~fzf~f{f}f|fxffd{4lӤ&y~x\FNg!ffiffvffzf~fzf~fzffyffzf~f{f|f}f|f|f}f{f|f~fyffyf~f{f|f}f|f|f|f|f|f}f|f|f|f|f}fzffwffvffsff;۴䘵n|~}y`ؙmg|Hpg-ffgffsffzf}f}fzf~f{f}f|f{f}f|f|f}f{f|f}fzffyf~f{f|f}f|f}fzffxffxffxffxffwffwffvffoffIffBAęh{}yiřE{BfJffoffwffyf~f|f|f}fzf~f{f}f|f}fzf~f|f{f~fzf}f~fyffzf}f|f}f{f}f|f{ffxffzf}f|f|f}fzffvfflff1fpgHarՙaw}}p䘳;fmffvff{f{f~fyff|f{f~fyffzf~f{f|f}f{f}f|f|f|f|f}f{f~fzf~fzffyffzf~fzf}f}f{f~fyffyffvffjff$fgNF]x}~{'m{4dfyfzffzf~f{f}f{f~fzf~f{f}f{f}f{f~fzf~f{f|f}f{f~f{f|f|f}f{f~fzf}f|f|f|f}fzffyffwffxffvffhfffgSt6Yu|~[˗,Ycfaffwffzf~f{f}f{f~fzf~f{f}f{f~fzffxffzf}f|f{f~f{f}fzffzf}f}fzffyffzf~f{f|f|f~fxffrffefffgWL nLߙ^y~z<$MagNffrffwffxf~f|f|f}f|f{f}f|f|f}f{f~fzf}f}fzffwffxffyf~f|f{f~f{f}f|f|f|f}f{f}f|f|f}fyffnff,fg[ ҙc}}{lL~^Ug=ffnffuffyf~f{f}f|f{f~f{f|f~fzf}f}fzf~f|f{f~fzf}f|f}f{f}f{f}f|f}fzffyff{f|f}f|fzffwffoff$晏z}xZJmP Wgffiffvffyf~f{f}f{f~fyffzf|f~fyffyf~f{f}f|f{f~f{f}f{f}f|f|f}f{f}f|f|f}fzffzf~f{f|f{fftff^ff[c,\z]8tSgffgffvffzf~fzf~f{f|f~fyf~f|f{ffyffyff{f|f~fyffxffzf|f~fzf~f{f}f{f~fzf~f{f}f{f}f|f|f{ffrffd4jӥ%y~~~y^GNg"fffffsffwffyf~f|f{f~fzf~f|f{f~fzffyffzf}f}fzf~f{f|f~fyffxffyffyffxffzf|f~fyffxffvffqff;۲瘱r}xa֙pcHqg.ffifftffxff{f{ffxffzf}f|f{f}f}fzffvffvffyf}f}fzffyffzf~fzf~f{f}f|f{f~fzffyffvffoffJffB|Dęj}~}ziÙ@BfIffnffvff{f|f|f|f}f{f~fyff{f|f~fxff{f|f}fzffzf~fzffyffxff{f}f|f{f~fzf~f|f{f~fzf~fzffpff3fmgHbsҙd}o㘵;fpffuffxffzffzf}f{f~fzffyffzf}f|f|f}fzffzf}f|f|f|f}f{f}f|f|f{ffyffzf}f|f|f}f|fzfftffefffgNIߙ_yz"hӀ4dfrff{f|f~fzf}f|f}f{f}f|f{f~f{f|f}f{f}f}f{f}fzff{f|f~fxffxffzf~f{f}f{f}f{f~f{f}f{f|ffuffbfffgSv4Yx}~a˕,\cfeffzf|f}f{f~fzf~f{f}f{f~fyffzf|f}f|f{ffxff|fzffzf}f}fzf~f{f}f|f|f|f|f}fzffyffwffrffefffgWL oJ]x{8$QagOfftffzf}f|f|f}f{f}f|f|f|f|f}f|f|f{f~f{f}f{f}f{f~fzf}f}fzffyffyffzf~f|fzffyffwffsffhff(fg[ЙczyhF^Yg:fflffuffzf~fzffzf}f{f}f}fzffyffzf~fzf~f|f{f~fzf~fzffzf}f|f|f|f}f{f}f|f|f|f|f|f~fxffmff8fZg^Ioyaә [g)ffiffsffuffxff{f{f~f{f}f|f|f|f}f{f}f|f}f{f|f|f}f|f|f|f|f|f|f}f|f|f{f}f|f}f{f}f{f}f{ffsffLfgNa:$ ᙒxz_ݙOjQ Wgffjffvffwffxffxffyf~f}fyffyf~f|f|f{ffxffuffyf}f}f{f|f~fzf}f|f|f}f{f}f{f}f|f|f{ffuffaffZc,^z\9qSgffhffvffyffxffxffzf~f{f{f~fzffyffzf~fzf~f{f}f|f{f~f{f}f|f{f~fzffyffzf}f}fzffyffzfftffd}4kӥ%zxZGNg ffkffvffyf}f}f{f}f{f~f{f}f{f}f{ffyf~f{f}f|f}fzf~f{f}f}fyffzf~f|fzffyffxffwffxffxfftffpff;۰蘱rz`ؙne~Hog1ffmffxffzf~fzffyff{f{ffxffwffxffzffyffzf}f}f{f~fyffyffzf|f~fzf~f{f}f{f}fzffwffnffGffBAřhz|hƙD}BfKffrffzf~fzf~fzf~f{f|f}f{f}f{f}f{f}f|f|f|f|f|f}f{f}f{f~fzf~fzffzf~fzf}f|f~fyffwffxffuffjff/fpgHdoؙ^t}s阯;fqffzf}fzffzf}f~fxffzf}f|f|f|f}f{f~fzf~fzf~f{f}f|f{f~fzf}f~fyffxff{f}f|f{f}f|f|f~fxfftffiff!fgNIߙ]w|}~w#j4dfrff{f|f{ffwffvffyf~f{f}f{f~fyffzf~f{f}f{f}f|f|f}f|f{f~fzf~f{f}f{f}f{f~fyffuffrffnffcfffgSs8\x~^ˑ,]cf^ffsff|f{f}f|f|f|f}f{f|f}f{f}f|f|f{f~fzffyffzf~fzffxffvffyf}f}f{f|f~fyff{f{ffzf{ffkff fgWM oI[xx<$NagPfftffyf~f{f}f{f~fzf~f{f}f{f~fzf~f|fzffxff|fzffyff{f}f{f|f}f|f}f|fzffzf~f{f}fzfftffjff+fg[ ҙc{{oD^[g8fflffvffxffzf~f{f}f{f~fzf~f{f}f{f}f|f{ffxffxf~f{f~fzffyf~f|f{f~fzf~f{f}f{f~fyffvffoff;fYg^Fpzf̙[g*ffkffuffuffwff{f|f}f{f}f|f|f|f}fzffzf~f{f}f{f~f{f|f~fyffyf~f{f|f}f|f|f|f|f|f}f{f}f~fuffPfgQa9$噎||v\JpK Wg!ffgffrffyf|f~fzffyf~f{f~fzf~fzf~f|f{f}f|f|f}f|f|f{ffxffxffxffyf~f{f}f|f|f|f|f}f{f~fxffbffYc,`~zY3vSgffeffuff{f|f}f{f}f{f~fzf~f{f|f~fyff{f|f}f|fzffvffxffzf}f}f{f}f|fzffyf~f{f}fzffzf~f{f~ftffd|4mӢ(y~{\ENg ffhffsffwffxffyffxffzf|f~fyff{f|f}f{f|f}f}fyffvffzf}f|f|f{f~f{f}f|f{f~fzf~f{f}f{ffvffpff;۱瘲pxbԙqcHog0fflffsffsfftffxf~f{f}f{f~fzf~f{f}f{f}f{f~fzffyffyffzf~f{f|f|f}f{f}f|f{ffxffyffxffpffHffB?řgz|ięABfGffnffyffzf}f|f{ffyf~f|f{f~fzf~f{f~fzf~fzffzf}f}fyffwffyffzf~f{f|f}f{f}f}fzffwfftffkff0fogH}fn֙bzs昳;fofftffxf~f}fzf~f{f|f~fyffzf~f{f|f}f{f~fzffyffxff{f}f|f{f~f{f|f}f{f}f|f|f|f|f|f}f{f~fxfflff"fgNDZxx%n{4dfuf~f{f~fyffyf~f|f{f~fzf~f{f}f|f{f~fzf~f{f}f|f|f|f}fzffxffyf}f~fyffzf}f}fzffxffvfftffifffgSv3Vu}` ˓,\cf`ffxf~f{f~fyffzf~fzf~f{f}f{f~fyffyf~f|f{f~fzf~f{f|f~fzf~fzf~f{f~fyffzf~f{f}f{ffwffpff`fffgWJ qI]z}>$LagMffoffuffyffyffzf}f}f{f}f{f~fzf~f{f|f~fyffxffxffxffzf}f|f}fzffzf}f|f|f}f{f}f|f{ffoff0fg[~ љd||lI^Yg9ffmffwff{f|f|f}f{f~fzf~fzffyffzf~f{f|f}f|f|f|f|f|f}f|f{f~fzf}f}f{f}f|f{f~fzffxffuffmff;fXg^Hl}x_ԙ [g*ffkffuffwffvffxffzf}f|f{ffxffwffzf~fzf~fzf~f|f|f|f|f|f}f{f~fzf~f{f|f~fzf~fzffxffpffKfgMa;$噎|{xt]ޙOjP Wgffhffvffzf}f|f{ffxffxff{f{ffyffzf~f{f}fzffzf~fzf~fzf~f{f}f|f|f{ffyffzf}f}f{f|f~fxffdff^c,_}}w[7tSgffhffvffyff{f|f}f{f}f{f~fzffyf~f{f|f~fzf~fzf}f}f{f~fyffzf~f|f{f~fyffyff{f|f|f}f{f~fzffuffd{4mӣ'z~x]HNgffgffrffwff|fzf~f|f|f|f|f|f}f|f|f|f|f|f~fzf~fyffyffzf}f{f~fzffzf}f|f}f{f}f|f|f|f~fxffuffpff;۱瘳o~xaԙs`Hpg0ffjffrffwff{f|f}f{f}f|f{ffxffwffyf~f{f|f}f|f|f}f{f|f~fyffzf|f}f{f}f}fzf~f{f}f{f~fxffoffIffB~CǙgz|iƙFzBfIffoffxffzf~f|fzf~f{f}f|f{f~fzffyffzf}f|f|f~fyffyffyf~f|f{f~fzf~f|f{f~fyffxffwffvffmff/fqgHarԙcz~p嘴;fofftffyff{f{f~f{f|f}f|f{f~fzf~f|f{f}f|f|f}f{f}f{f~fzffyffyffxffwffzf~fzffxffuffsffhff!fgNE]z{'nz4dfwf|f~fzf~fyffyffyffzf~f{f|f}f|f|f}fzffyff{f|f}fzf~f|f|f|f|f|f}f{f}f{ffyf~f{f}f{ffvffhfffgSq8]{\˖,\cfeffyf~fzf~f{f}f|f|f{ffyffzf}f|f}f{f}f{f~f{f|f}f{f}f|f|f|f|f}fzffxffyf~f{f}f}fzf~f{f{ffkff fgWK pJ\w~~y<$KagKffqffzf}f}f{f}f{f}f}f{f|f}fzffxffzf~fzffyffyffyf~f|fzff{f{ffwffyf}f}fzffwfftffgff&fg[ ЙcznK^Zg9ffnffyf|f~f|f|f|f{f}f}f|f{f~fyff{f|f}f{f}f{f~fzffyffzf}f}fzffyffzf~fzf~fzffwffuffoff:fZg^Ify}wcϙ [g(ffiffvffyffyff{f|f|f}f{f~fzf}f}f{f}f|f{f~fzf~f{f}f{f}f|f{f~f{f|f~fyffyffxffyffxffqffOfgQa8$!ᙒx{aܙPjO Wg ffgffrffwffzf~fzffyf~f|f{f~fzf~f|fzffyffyf~f{f|f}f{f~fzf~fzf~f|f{f~fyffyf~f{f}f|f|f{fffff]c,a}tW5uSgffgffvf~f}f{f}f|f|f|f}f|f{ffwffuffvffxffwffyf}f}f{f}f}fzffzf}f|f|f}f{f~fzf}f}fzffzf}fxffdz4mӤ'|~xYB"Ngffeffsffyf~f{f}fzffzf~f{f|f|f}f{f}f}fzf~f{f|f~fzf~fzffyffzf}f}f{f|f}f{f}f|f|f|f|f}fzfftffnff;ۯ阱q}v]ٙncHrg.fflffwffzf}f|f}fzf~f|f{f~fzf}f~fxffvffvffzf|f}f{f}f|f|f|f|f}f{f}f}fyffyf~f{f~fyffuffnffIffB{FǙh{~kÙB}BfMfftff|f{f}f|f|f}fzffyffzf}f}fzffyff{f{f~f{f}f|f{f}f|f}f{f|f}f{f~fzf~fzffzf}f|f{ffxfflff/fpgHenי`x~~~n;fqffuffxf~f}fzf~f|fzff{f{ffxffzf}f|f|f|f}f{f}f|f|f}f{f}f{f~fzffyf~f{f}f}fyffxffwfftffffffgNG]v~x"j~4dfsffyffzf~f{f{f~f{f~fzf}f|f{ffxffxff|f{f~fzf~f{f}f{f}f|f|f}f{f}f{f~f{f}fzffxffxffwffgfffgSu5Wt^˕,\cfaffqfftffxffzf~f{f}fzff{f|f}fzf~f|f|f}fzf~f{f}f|f}fzffyffzffyf~f{f}f|f}fyffvffuffkff"fgWL oJ\yy;$MagLffpffwffxffzf}f}f|f{f~fyff{f|f}fzf~f|f{f}f|f{f~f{f|f}f{f~fzffxffzf~fzf~fzffyffxffmff-fg[ ϙe}~nI^Xg;ffmffvff}fyff{f|f}f{f|ffxffyf}f~fzf~fzf~f{f}f}fzf~f{f}f|f|f}f{f}f{f~fzffyffyffwffmff;fXg^Jm}{dϙ [g,fflffxf~f{f~fzf~f{f}f{f~fzf~f{f|f~fzf}f|f|f|f}f{f~fzf}f|f}f{f~fyff{f|f|f|f}fzffwffuffpffLfgQa7$"ᙐ|z^KnN Wgffdffqffvffyffzf~fzffxffxff{f{f~f{f|f}f{f}f}fzf~f{f|f~fzf}f|f|f|f}f{f}f|f|f|f|f}f}fxffaffZc,`}|x[5wSgffhfftffvffxf~f{f|f~fzf~fzf}f}f|f{f}f{f~f{f}f{f|f}f|f|f}fzffyffzf~f{f}fzffxffyffyffzfzffdz4kӧ"v~z^ߙINgffkffyf~fzffyffzf~f{f}f{f}f|f|f|f}f{f}f{f~fzf~f{f|f~fzf~f{f}f{f}f|f|f}f{f|f}f{f~fzffxffwfftff;۲瘲pz}{bՙqaHpg0ffnffvffvffvffzf}f|f|f}f{f}f|f{f~f{f}f|f{f~fzf~f|fzffxff{f|f~fyffzffyffyff{f}fyffpffJffB~Aęiz}wb˙E}BfJffpffvffxff{f}fzffyffzf~f{f|f|f|f}f|f{f~fzf~f{f}f{f~fzf~f{f|f~fyffzf}f}f{f|f~fxffuffjff1fmgH{gnי_x~~r蘰;foffuffxffyf~f|fzffyf~f{f}f{f~fzf~f{f}f{f}f{f~f{f|f}f{f}f|f|f|f}f|f|f}fzffzf~fzffxfftffiff"fgNH]x~~~{$i~4dfwfzffxffzf|f}f{f~f{f|f}f{f}f|f|f|f}f{f}f{f}f}fzf~fzffyffyffzf~fzf~fzffyffxffxffsffdfffgSt7Zx^˕,[cfdffzf{ffxffxffzf}f|f|f|f|f|f}fzffyffzf~f{f}f{f}f|f|f}f{f}f{f~fzf~f{f|f}f|f{ffwffsffffffgWN oHXt}~{9$PagMffrffyf~f{f|f}f{ffxffyf~f}fyffzffyffwffyf~f{f}f{f~fzf~f{f}f{f}f{f~f{f|f|f}f{ffwffnff.fg[֙]y|nJ^Vg;ffkfftffxffyffzf|f~fzffzf}f{f~f{f}f|f|f{ffyf~f|f{f~f{f{f~f{f}f|f{f~fzffzf}f|f}fyffmff7f]g^Em}cҙ~[g-ffkfftffwff|f{f}f|f{f~f{f}f|f{f}f|f|f~fyffzf}f~fyffwffyf~f|f{f}f|f{f~f{f}f|f{f~fyffqffKfgNa:$㙏|~x\LlP Wgffhffsffvffyf~f{f|f}f{f}f}fzf~fzf~f{f}f|f|f|f}fzffzffyffyff{f}f{f}f{f~f{f|f}f{f}f}fyffdffZc,[|]8telektroid-3.2.3/test/res/connectors/square-wav48k16b2c.wav000066400000000000000000005672541500236517400233530ustar00rootroot00000000000000RIFFWAVEfmt JUNK4smpl<aQ0dataSSggffffhfhfffufufff{f{f|f|f}f}f{f{f|f|f}f}f|f|f|f|f|f|f{f{fffyfyfffzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~f{f{f|f|f}f}fzfzfffxfxfffxfxfffyfyfffzfzf~f~f{f{f|f|f}f}f{f{fffyfyfffufufffdd|4|4llӤ&&{{{{^^GGNNgg f fffgfgffftftfffxfxfffwfwfffyfyf}f}f}f}fzfzfffzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f|f|fzfzfffxfxfffyfyfffyfyfffxfxfffxfxfffvfvfffrfrfffnfnfff;;۱昴oo}}zzccԙԙqqbbHHqgqg.f.fffkfkfffxfxfffyfyfffzfzf}f}f}f}f{f{f}f}f|f|f{f{f~f~fyfyfffzfzf}f}f|f|f|f|fzfzfffyfyfffzfzf}f}fzfzfffxfxfffyfyf}f}f}f}f{f{f}f}f{f{f~f~fzfzfffyfyfffyfyfffvfvfffpfpfffJfJfffBBCCǙǙeeww{{}}xxhhęęBB~~BBffJfJfffpfpfffwfwfffyfyfffxfxfffyfyf~f~f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~f{f{f}f}f{f{f~f~fyfyfffyfyf~f~f{f{f}f}f{f{f~f~fzfzf}f}f|f|f|f|f}f}f}f}fwfwfffhfhfff+f+frgrgHH~~eeppԙԙddzz||}}}}~~~~ss昳;;ffqfqfffwfwfff{f{f|f|f}f}f{f{f}f}f|f|f|f|f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{fffyfyfffzfzf|f|f~f~fzfzfffyfyfffyfyfffzfzf}f}f|f|f|f|f|f|f}f}fyfyfffqfqfffdfdfffffggNNHH^^zz{{%%iiӀ44ddffrfrfffwfwfffyfyf}f}f}f}f{f{f}f}f{f{f}f}f{f{fffyfyf~f~f{f{f|f|f~f~fyfyfffxfxfffzfzf~f~f|f|fzfzfffxfxfffyfyf~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f~f~fxfxfffufufffrfrfffgfgfffffggSSuu77^^{{__˂˖,,ZcZcffafafffwfwf~f~f|f|f|f|f}f}f{f{f~f~fyfyfff{f{f|f|f~f~fyfyf~f~f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fyfyfffxfxfffzfzf|f|f~f~fzfzf}f}f}f}fzfzfffyfyfffxfxfffsfsfffgfgfffffggWWL L ppHHZZtt}}=$=$NaNaggNfNfffrfrfff{f{f{f{f~f~f{f{f|f|f~f~fyfyfffxfxfffzfzf}f}f|f|f{f{f~f~f{f{f}f}f{f{f}f}f{f{f~f~f{f{f|f|f}f}fzfzfffxfxfff{f{f|f|f~f~fyfyfff{f{f|f|f~f~fxfxfffufufffrfrfffjfjfff)f)fgg[[ ҙҙcczz~~llHH^^ZgZg:f:fffnfnfffxfxf~f~f|f|f|f|f|f|f|f|f|f|f}f}f|f|f|f|f|f|f{f{fffyfyfffzfzf}f}f}f}f{f{f}f}f{f{f}f}f|f|f}f}f{f{f}f}f{f{f}f}f|f|f|f|f}f}f{f{f|f|f}f}f{f{fffxfxfffxfxffftftfffififff5f5f\g\g^^HHnn||}}yy``ԙԙ[[gg'f'fffififffufufffxfxfffyfyfffzfzf}f}f|f|f|f|f|f|f}f}f|f|f|f|f{f{f~f~fzfzfffyfyf~f~f{f{f~f~fyfyfffxfxfffwfwfffzfzf}f}f}f}f{f{f|f|f~f~fxfxfffvfvfffwfwfffwfwfffrfrfffLfLfggMaMa:$:$!!ᙑzz~~~~yy[[KKnnN N WWggffffefeffftftfff|f|fzfzfffzfzf}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f~f~fyfyfffwfwfffxfxf~f~f|f|fzfzfffyfyfffyfyfffzfzf~f~f|f|fzfzfffwfwfffwfwfffxfxfffxfxfffdfdfffZcZc,,ˀ\\}}{{xx\\77ttSSggffffififfftftfffxfxf~f~f|f|f}f}fzfzfffyfyfffyfyf~f~f{f{f}f}f|f|f}f}fzfzfffyfyfffxfxfffxfxfffyfyf~f~f{f{f}f}f|f|f{f{f~f~fzfzfffzfzf}f}f|f|f|f|f|f|f~f~fyfyfffzfzf}f}f}f}fvfvfffdd|4|4jjӦ%%zzuuYYFFNNgg!f!fffjfjfffxfxf}f}f~f~fxfxfffxfxfff{f{f{f{fffyfyfffyfyfffzfzfffzfzf|f|f~f~fzfzf~f~f|f|fzfzfffxfxfffyfyf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fxfxfffrfrfff;;۳嘵nn~~{{ddԙԙppddHHrgrg.f.fffmfmfffyfyf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{f~f~f{f{f|f|f|f|f|f|f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fzfzf~f~f{f{f|f|f}f}f{f{f}f}f}f}fzfzfffxfxfffsfsfffLfLfffBB??™™jj||||hhƙƙBBBBffHfHfffofofffyfyf~f~fzfzfffyfyfffzfzf}f}f|f|f}f}fzfzf~f~fzfzfffzfzf~f~fzfzf}f}f}f}f{f{f~f~fzfzf~f~fzfzf~f~fzfzfffyfyfffzfzf}f}f|f|f{f{f~f~f|f|f{f{f~f~fzfzf~f~fzfzfffvfvfffkfkfff/f/fqgqgHHccooיי``zz{{ll㘴;;ffofoffftftfffzfzf}f}f|f|f}f}fzfzf~f~f|f|f{f{fffxfxfff{f{f|f|f~f~fyfyfffwfwfffyfyf~f~f|f|f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{fffxfxfffyfyfff{f{f{f{f~f~fyfyffftftfffhfhfff f fggNNHH[[vv}}zz$$ll|4|4ddffrfrfffzfzf}f}f}f}fyfyfff{f{f|f|f}f}f{f{f|f|f~f~fzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~fzfzfffyfyfffzfzf~f~f{f{f|f|f}f}f{f{f}f}f}f}fyfyfffyfyf~f~f{f{f~f~fxfxffftftfffsfsfffhfhfffffggSStt77[[yy]]ˁ˗,,[c[cffbfbfffvfvfffyfyf~f~fzfzfffyfyfff{f{f|f|f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~fzfzfffyfyf~f~f|f|f{f{f~f~fzfzf}f}f}f}fzfzfffyfyf~f~f|f|f{f{f~f~fzfzfffxfxffftftfffhfhfffffggWWM M nnLLߙߙ^^yyzz=$=$JaJaggJfJfffrfrfffzfzf~f~fzfzfffyfyfffzfzf}f}f}f}fzfzf~f~f|f|f{f{f~f~fyfyfff{f{f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f|f|f|f|f{f{f~f~fzfzfffwfwfffwfwfffyfyfffxfxffftftfffjfjfff)f)fgg[[ әәaazzzzkkII^^WgWg;f;fffofofffxfxf}f}f}f}f|f|f|f|f|f|f{f{f~f~f{f{f}f}f{f{f}f}f{f{fffyfyf~f~f{f{f|f|f~f~f{f{f{f{f~f~f{f{f|f|f~f~fyfyf~f~f}f}fyfyfffzfzf|f|f}f}f|f|f{f{fffxfxfffyfyfffwfwfffmfmfff9f9fYgYg^^IImm||~~~~zztt]]ՙՙ [[gg+f+fffjfjfffsfsfffyfyfffzfzf~f~fyfyfff{f{f}f}f{f{f}f}f{f{f~f~f{f{f}f}fzfzfffzfzf~f~f{f{f|f|f}f}f|f|f|f|f}f}fzfzf~f~f|f|f{f{fffyfyf~f~f{f{f}f}f|f|f|f|f}f}fzfzfffvfvfffofofffJfJfggKaKa=$=$㙒xx}}ww]]LLllP P WWggffffgfgfffvfvfffzfzf~f~f{f{f|f|f~f~fzfzf}f}f|f|f|f|f|f|f~f~fyfyfffzfzf}f}f}f}f{f{f|f|f}f}f{f{f~f~fzfzf~f~fzfzf~f~f|f|fzfzfffxfxfff{f{f|f|f}f}f{f{f~f~fzfzf}f}f}f}fzfzffftftfff^f^fffXcXc,,ˁ__xx[[66ttSSggffffffffffrfrffftftfffxfxf}f}f}f}f|f|f{f{f~f~f{f{f|f|f|f|f~f~fyfyfffyfyf}f}f}f}f{f{f~f~fzfzf}f}f|f|f|f|f}f}f{f{f~f~fyfyfffwfwfffwfwfffzfzf|f|f}f}f|f|f|f|f}f}fzfzfffyfyfffrfrfffdd|4|4mmӢ(({{}}uuZZEENNggffffefefffrfrfffvfvfffzfzf|f|f~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzf}f}f}f}f{f{f}f}f{f{f|f|f~f~fzfzf~f~fzfzf~f~f|f|f|f|f|f|f}f}fzfzfffzfzf~f~f{f{f|f|f}f}fzfzfffsfsfff;;ۯ蘳nn||{{bbՙՙppccHHpgpg.f.fffififffsfsfffyfyf~f~fzfzfffzfzf}f}f}f}fyfyfffzfzf}f}f|f|f{f{f}f}f}f}f{f{f}f}f{f{f}f}f|f|f}f}fzfzf~f~f|f|f{f{f~f~fyfyfff{f{f}f}f{f{f|f|f}f}f|f|f|f|f|f|f|f|f|f|fffvfvfffmfmfffGfGfffBBBBǙǙhh~~yyggǙǙCC}}BBffMfMfffsfsfffyfyfffyfyfffzfzf~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf}f}f}f}f{f{f~f~fzfzf}f}f|f|f}f}f{f{f~f~fyfyfffzfzf~f~f|f|fzfzfffzfzf}f}f}f}fyfyffftftfffififff-f-ftgtgHH``rrՙՙ``xx||pp䘵;;ffqfqfffufufffxfxfffzfzf~f~fzfzfffyfyfffzfzf~f~fzfzfffzfzf|f|f}f}f{f{f~f~f{f{f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzf~f~fzfzf~f~f{f{f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f~f~fyfyfffufuffflflfff%f%fggNNGG^^xx}}zz%%kk}4}4ddffqfqfffwfwfff{f{f{f{f~f~f{f{f|f|f}f}f|f|f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f{f{fffyfyfffzfzf~f~fzfzfffwfwfffxfxfffvfvfffhfhfffffggSSuu77]]}}^^ˁ˗,,YcYcff_f_fffvfvfffzfzf}f}f}f}fzfzfffzfzf}f}f|f|f|f|f|f|f}f}f|f|f|f|f{f{f~f~fzfzfffzfzf}f}f|f|f}f}f{f{f}f}f|f|f{f{fffxfxfffyfyfffyfyfffwfwfffvfvfffvfvfffwfwfffufufffgfgfffffggWWN N mmKK\\vv~~~~~~}}@$@$JaJaggLfLfffqfqfffxfxf~f~f|f|f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~f{f{f}f}f{f{f}f}f|f|f}f}f{f{f|f|f}f}f|f|f{f{fffxfxfffzfzf}f}f|f|f}f}fzfzfffyfyfffxfxfffyfyfffyfyffftftfffjfjfff,f,fgg[[ әәaa||{{jjDD^^ZgZg:f:fffnfnfffufufffwfwfffzfzf}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f}f}f|f|f}f}f{f{f|f|f}f}f{f{f~f~f{f{f}f}fzfzfffzfzf~f~f|f|fzfzf~f~f|f|f|f|f|f|f}f}fzfzfffwfwfffnfnfff;f;fXgXg^^DDmm||zzbbљљ [[gg(f(fffhfhfffufufffyfyf~f~f{f{f}f}f{f{f~f~fzfzfffyfyfffzfzf~f~fzfzfffyfyfffzfzf}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f{f{f~f~f{f{f|f|f}f}fzfzfffzfzfffwfwfffpfpfffLfLfggNaNa;$;$䙎}}yy\\JJooN N WWggffffififffvfvfffwfwfffwfwfffzfzf}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~f{f{f|f|f~f~fzfzf}f}f|f|f}f}f|f|f|f|f{f{f}f}f}f}f{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fxfxfffsfsfff]f]fffXcXc,,˂]]~~xxZZ88rrSSggffffefefffpfpffftftfffyfyf~f~f{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~f{f{f|f|f~f~fyfyfffzfzf}f}f~f~fyfyf~f~f|f|f{f{f~f~f{f{f|f|f}f}f{f{f}f}f}f}fzfzfffxfxfffyfyf~f~fvfvfffdd|4|4kkӥ&&{{~~xx^^FFNNggffffjfjfffwfwfffyfyf~f~f|f|f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzfffyfyfffyfyfffzfzfffxfxfffyfyfff{f{f{f{fffwfwfffofofff;;۲嘴nn}}||bb֙֙nnff}}HHmgmg1f1fffkfkfffsfsfffxfxf}f}f}f}f{f{f}f}f|f|f}f}fzfzfffzfzf}f}f}f}fzfzfffzfzf}f}f|f|f|f|f|f|f~f~fyfyfff{f{f|f|f}f}f{f{f~f~fzfzf~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}fzfzfffrfrfffKfKfffBB{{GGəədd{{}}ggǙǙDD~~BBffGfGfffofofffyfyf~f~f{f{f|f|f}f}fzfzfffyfyf}f}f~f~fxfxfffyfyf~f~f{f{f|f|f}f}f|f|f{f{f~f~fyfyfffyfyf~f~f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf}f}f}f}f{f{f~f~fxfxfffwfwfffsfsfffhfhfff-f-fpgpgHH~~ddppԙԙddzz~~~~rr瘱;;ffnfnffftftfffxfxfffzfzf}f}f|f|f{f{f~f~f{f{f}f}f{f{f~f~fyfyfffzfzf|f|f~f~fyfyfff{f{f}f}f{f{f}f}f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f{f{fffxfxfffyfyf~f~f|f|fzfzfffwfwfffrfrfffefefffffggNNIIߙߙ^^yy~~{{((rru4u4ddffvfvf}f}f}f}f{f{f}f}f|f|f|f|f{f{fffxfxfffzfzf}f}f|f|f{f{f~f~f|f|f{f{f}f}f{f{f}f}f}f}fzfzfffyfyfffzfzf~f~fzfzfffyfyfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f|f|f{f{fffxfxffftftfffififff f fggSSww44[[zz^^˃˖,,YcYcffbfbfffzfzf|f|f|f|f}f}f{f{f}f}f{f{f}f}f|f|f}f}fzfzfffyfyf~f~f|f|f{f{fffyfyf~f~f{f{f}f}f|f|f}f}fzfzfffzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzfffyfyfffwfwfffvfvffftftfffgfgfffffggWWJ J qqII^^yy{{<$<$NaNaggNfNfffqfqfffvfvfffzfzf~f~fzfzf~f~fzfzfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f}f}f{f{f~f~fxfxfffsfsfffjfjfff,f,fgg[[ ϙϙee{{mmGG^^XgXg;f;fffmfmfffwfwfffyfyfffyfyfffzfzf~f~fzfzf~f~f|f|f{f{f}f}f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f|f|f|f|f}f}fxfxfffofoffff>fUgUg^^HHqq{{bbҙҙ}}[[gg0f0fffofofffvfvfffwfwfffyfyfff{f{f|f|f}f}fzfzfffzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f|f|f{f{fffxfxfffzfzf}f}f|f|f|f|f|f|f}f}f|f|f{f{f~f~fzfzfffyfyffftftfffMfMfggKaKa>$>$晎||yy^^ޙޙNNkkP P WWggffffefefffpfpfffufufffxfxfff{f{f}f}f{f{f}f}f{f{f~f~f{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fyfyfffyfyf~f~f|f|fzfzfffxfxfffyfyf}f}f}f}f{f{f~f~fzfzf~f~fyfyfffvfvfffrfrfff^f^fffYcYc,,˂]]}}uuXX55vvSSggffffififfftftfffufufffwfwfffxfxfffxfxfffzfzf}f}f|f|f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f|f|fzfzfffxfxfff{f{f|f|f|f|f}f}f|f|f{f{f~f~fzfzf}f}f}f}f{f{f}f}f}f}fzfzf}f}f~f~fxfxfffpfpfffdd}4}4jjӦ$$zzyy^^FFNNggfffffffffftftfffyfyfffzfzf~f~fzfzf}f}f|f|f}f}f{f{f~f~fyfyfffzfzfffxfxfffwfwfffyfyf}f}f}f}fzfzfffyfyfffyfyfffyfyf~f~f{f{f|f|f}f}f}f}fzfzfffyfyfffzfzf~f~fzfzfffxfxfffrfrfff;;۱蘰ss{{tt]]ٙٙmmeeHHrgrg.f.ffflflfffwfwfffxfxfffwfwfffyfyf}f}f}f}fzfzfffzfzf~f~f{f{f|f|f}f}f{f{f}f}f}f}fzfzfffyfyfffzfzf~f~fzfzfffyfyfffyfyfffzfzf}f}f|f|f|f|f|f|f}f}fzfzfffxfxfffufufffnfnfffMfMfffBB{{DDǙǙgg}}||ffșșCCBBffLfLffftftfffyfyfffzfzf~f~f{f{f|f|f}f}f|f|f{f{fffxfxfffyfyfffzfzf}f}f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f{f{fffyfyfffzfzf}f}f}f}fzfzfffzfzf}f}f|f|f{f{fffyfyf~f~f}f}fvfvfffefefff)f)ftgtgHHddooיי``yy}}~~||qq꘮;;ffsfsfffxfxfffzfzf~f~f{f{f|f|f~f~fyfyfffyfyf}f}f}f}f{f{f}f}f|f|f{f{f~f~fzfzfffzfzf}f}f{f{fffxfxfffxfxfff{f{f|f|f}f}f|f|f|f|f}f}fzfzfffzfzf~f~f{f{f|f|f}f}f|f|fzfzfffufufffififff!f!fggNN DD\\yyvv!!ll{4{4ddffufufff{f{f}f}f{f{f}f}f|f|f{f{f~f~f{f{f}f}f|f|f{f{f}f}f}f}f{f{f}f}f|f|fzfzfffyfyf~f~f{f{f|f|f|f|f}f}f|f|f|f|f|f|f|f|f|f|f}f}f|f|f|f|f|f|f|f|f}f}f|f|f|f|f|f|f|f|f}f}f{f{fffvfvfffhfhfffffggSSvv44WWvv~~__ˆˑ,,_c_cffcfcfffxfxf~f~f{f{f}f}f|f|f{f{f~f~f{f{f}f}f{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f|f|f}f}f|f|f|f|f}f}f{f{f|f|f~f~fzfzfffyfyfffzfzf}f}f}f}f{f{f|f|f~f~fxfxfffufufffvfvffftftfffififffffggWWP P mmKK^^{{xx<$<$MaMaggMfMfffrfrfffxfxfffyfyfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}fzfzfffwfwfffwfwfff|f|fzfzfffxfxfffyfyfffzfzf}f}f|f|f}f}f{f{f}f}f|f|f{f{fffwfwffflflfff*f*fgg[[ ҙҙbbzz}}mmFF^^[g[g7f7fffjfjfffufufffwfwfffxfxfffyfyf~f~f|f|fzfzfffxfxfffyfyf~f~fzfzfffwfwfffyfyf}f}f~f~fyfyfff{f{f{f{fffyfyfffzfzf}f}f|f|f|f|f|f|f}f}fzfzfffzfzf}f}f~f~fvfvfffkfkfff8f8fZgZg^^GGmm~~{{ccљљ [[gg(f(fffififffvfvfff{f{f|f|f~f~fyfyfff{f{f|f|f}f}f{f{f}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f{f{f~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f|f|f{f{f~f~fzfzfffxfxfffpfpfffJfJfggMaMa<$<$㙒ww~~~~vv[[MMmmM M WWgg"f"fffjfjfffvfvfffzfzf~f~fzfzf~f~fzfzfffyfyfffzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f}f}f}f}fzfzf~f~f{f{f|f|f~f~fyfyfffyfyf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzfffxfxfffdfdfff\c\c,,˅ bb~~}}zzZZ55wwSSggffffhfhfffufufffxfxfffyfyfffzfzf}f}f|f|f}f}fzfzfffyfyfffzfzf~f~fzfzfffyfyfffzfzf~f~fzfzfffyfyfffzfzf}f}f|f|f}f}f{f{f}f}f{f{f}f}f}f}fzfzfffzfzf}f}f|f|f|f|f|f|f}f}f}f}ftftfffdd44iiӦ%%zz~~~~xx\\EENNggffffhfhfffvfvfffzfzf}f}f|f|f|f|f|f|f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fyfyfffxfxfffyfyfffyfyfffzfzf~f~f{f{f|f|f}f}f|f|f{f{f~f~fzfzfffyfyfffxfxfffwfwfffyfyf~f~f{f{f~f~fxfxfffpfpfff;;۳昱ss{{bb֙֙ooee~~HHngng2f2ffflflfffufufffxfxfffyfyfffyfyfffzfzf}f}f|f|f}f}f{f{f}f}f|f|f|f|f}f}fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fyfyfffrfrfffNfNfffBB~~BBřřggzz~~}}ffʙʙIIyyBBffJfJfffpfpfffxfxf~f~f|f|f{f{f~f~f{f{f}f}f|f|f{f{f}f}f|f|f}f}f{f{f|f|f~f~fyfyfffxfxfffyfyf~f~f{f{f~f~fyfyfffxfxfffzfzf}f}f|f|f{f{fffxfxfffxfxfffzfzf}f}f|f|f|f|fffufufffkfkfff1f1fmgmgHH~~ffmmٙٙ]]vv~~ss蘱;;ffpfpfffvfvfff|f|f|f|f|f|f}f}f{f{f|f|f}f}f|f|f|f|f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{f}f}f}f}fzfzfffyfyf~f~f|f|f{f{f~f~fzfzf~f~f{f{f}f}fzfzfffwfwffftftfffififffffggNNFF[[xxzz$$ii44ddffufuf}f}f~f~fzfzf~f~fzfzf~f~f{f{f~f~fzfzf~f~fzfzf~f~f|f|f|f|f|f|f|f|f|f|f}f}f|f|f|f|f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f|f|fzfzfffzfzf}f}f}f}fyfyfffzfzf}f}f|f|f{f{f~f~fzfzfffufufffefefffffggSSuu55ZZxx]]˄˓,,]c]cffbfbfffvfvfff|f|f{f{f~f~fzfzfffyfyfffzfzf}f}f}f}f{f{f~f~fzfzf~f~fzfzfffzfzf}f}f|f|f|f|f|f|f}f}fzfzfffyfyfffyfyfff{f{f}f}f{f{f|f|f}f}f}f}f{f{f}f}fzfzfffzfzf~f~fyfyffflflfff f fggWWO O mmLL\\ww||~~xx<$<$MaMaggLfLfffqfqfffvfvfffyfyf}f}f~f~fyfyf~f~f|f|f{f{fffxfxfffyfyf~f~f|f|f{f{f}f}f}f}fyfyfffvfvfffxfxf~f~f|f|f|f|f|f|f}f}fzfzfffyfyfffxfxfffzfzfffyfyfffwfwfffvfvfffmfmfff/f/fgg[[}}ԙԙ__ww~~ooEE^^XgXg=f=fffpfpfffxfxf~f~f|f|f}f}f{f{f}f}f{f{f~f~fzfzfffyfyf~f~f}f}fzfzf~f~f{f{f|f|f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f~f~fyfyfffyfyfffyfyfffyfyf~f~f{f{f~f~fzfzfffxfxfffofofff;f;fYgYg^^CCkkzz~~xxaaҙҙ~~[[gg-f-ffflflfffwfwfff{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~f|f|f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~f{f{f|f|f}f}f|f|f{f{f~f~fzfzf~f~f{f{fffufufffOfOfggNaNa;$;$㙑yyww[[KKmmN N WWgg f fffgfgfffsfsfffyfyf}f}f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}fzfzfff{f{f|f|f|f|f}f}fzfzfffwfwfffzfzf|f|f}f}fzfzfff{f{f|f|f|f|f|f|f}f}f|f|f|f|f{f{fffwfwfffafafffYcYc,,˂__wwXX44uuSSggffffgfgfffrfrfffwfwf~f~f}f}f{f{f|f|f~f~fyfyfff{f{f{f{f~f~f{f{f|f|f~f~fyfyf~f~f|f|f|f|f|f|f}f}fzfzfffzfzf~f~fzfzfffyfyfffzfzf~f~f|f|fzfzfffyfyfff{f{f|f|f}f}fzfzfffyfyffftftfffdd{4{4llӤ%%xxyy^^ߙߙIINNggffffhfhfffsfsfffxfxf}f}f~f~fyfyfffyfyfffyfyf~f~f|f|f|f|f}f}f{f{f}f}fzfzfffvfvfffwfwfffzfzf~f~fzfzf~f~fzfzfffyfyfffyfyf}f}f}f}fzfzfffyfyf}f}f}f}fzfzfffzfzf}f}f}f}fxfxfffnfnf f f;;ۯ蘱ss||ffљљuu^^HHtgtg-f-fffkfkfffufufffxfxfffzfzf}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f}f}f{f{f~f~fyfyfffxfxfffzfzf|f|f~f~fyfyfff{f{f}f}f{f{f|f|f}f}f|f|f|f|f|f|f|f|f|f|f}f}fyfyfffofofffGfGfffBB}}EEəəddxx~~}}{{hhƙƙEE||BBffIfIfffpfpfffyfyfffyfyfffxfxfff{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{f}f}f}f}fzfzfffyfyfffzfzf}f}f|f|f}f}f{f{f}f}f{f{f}f}f|f|f|f|f}f}fzfzfffyfyfff{f{f|f|f~f~fwfwfffmfmfff0f0fngngHH~~eennיי``yypp阯;;ffofofffwfwf~f~f}f}f{f{f|f|f~f~fyfyfffyfyf~f~f{f{f}f}f|f|f}f}fzfzfffyfyfff{f{f|f|f|f|f}f}f{f{f}f}f|f|f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f{f{f}f}f|f|f|f|f}f}f{f{f|f|fffvfvfffqfqfffffffffffggNNJJ\\ww}}xx$$jj~4~4ddffufuf~f~f|f|f{f{f~f~fzfzfffyfyf~f~f{f{f}f}f}f}fzfzf~f~fzfzfffzfzf}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf}f}f}f}f{f{f~f~fzfzf}f}f|f|f|f|f}f}f{f{f}f}f{f{f}f}f|f|f{f{fffxfxffftftfffhfhfffffggSSss88]]{{^^˂˖,,YcYcff^f^fffwfwfffzfzf}f}f{f{f~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f}f}f|f|f{f{f~f~f{f{f|f|f~f~fyfyfffzfzf~f~fzfzfffwfwfffrfrfffififff"f"fggWWK K qqGGZZww}}9$9$PaPaggNfNfffsfsfff{f{f}f}f|f|f}f}fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f{f{f|f|f~f~fzfzf~f~f{f{f|f|f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}f{f{f|f|f}f}f|f|f|f|f{f{fffwfwffftftfffkfkfff+f+fgg[[ љљbbyy{{iiKK^^VgVg$>$㙑xxxx\\LLllP P WWggffffefefffrfrfffvfvfff{f{f{f{f~f~f{f{f|f|f}f}f{f{f|f|f~f~fzfzf}f}f}f}fzfzfffyfyf~f~f|f|f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}fzfzfffzfzf}f}f|f|f|f|f|f|f}f}fzfzfffufufff]f]fffYcYc,,˄^^~~{{vv[[99rrSSggffffffffffvfvfffxfxfffwfwfffwfwfff{f{f|f|f}f}f|f|f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~f{f{f|f|f~f~fxfxfffyfyf}f}f}f}fzfzfffzfzf}f}f|f|f|f|f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~f|f|fufufffdd}4}4kkӥ$$vvyy]]HHNNggffffgfgffftftfffyfyfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}fzfzfffyfyfffyfyf~f~f{f{f}f}f{f{f}f}f|f|f|f|f}f}fzfzfffxfxfffvfvfffwfwfffzfzf~f~fzfzf~f~f{f{f}f}f{f{f~f~fxfxfffqfqfff;;۶☷mm||zzbb֙֙nngg||HHmgmg2f2fffnfnfffvfvfffwfwfff{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf}f}f|f|f}f}f{f{f}f}fzfzfffzfzfffxfxfffyfyfffzfzf~f~fyfyfffwfwfffxfxfffzfzf~f~f{f{f}f}f{f{fffrfrfffKfKfffBB@@ll{{~~yyhhřřBB~~BBffKfKfffpfpfffwfwfffxfxfffyfyf~f~f{f{f}f}f|f|f{f{fffyfyf~f~f|f|f{f{f~f~f{f{f|f|f|f|f~f~fzfzf~f~fzfzf~f~f|f|f{f{f~f~fyfyfffyfyf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f}f}fxfxfffififff*f*fugugHHccnnؙؙ``}}~~qq蘱;;ffofofffsfsfffwfwfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}fzfzfffyfyfff{f{f{f{f~f~fzfzfffzfzf|f|f~f~fzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~f{f{f|f|f~f~fzfzf~f~fzfzfffxfxffflflfff"f"fggNNFFYYvv~~yy%%ll}4}4ddffsfsfff|f|f{f{f}f}f{f{f~f~fzfzf~f~f|f|fzfzfffzfzf}f}f~f~fxfxfffzfzf}f}f|f|f|f|f|f|f|f|f~f~fyfyfff{f{f{f{fffzfzf|f|f~f~fyfyfffyfyf~f~f{f{f}f}f{f{f~f~fyfyfffvfvffftftfffjfjfffffggSSss77XXss||[[˂˔,,]c]cffffffff{f{f}f}fzfzfffxfxfff{f{f|f|f}f}f|f|f|f|f|f|f|f|f|f|f}f}f}f}fzfzf~f~f{f{f}f}f{f{f}f}f|f|f}f}f{f{f|f|f|f|f}f}f|f|f}f}fzfzfffyfyfffzfzf~f~f{f{f}f}f{f{f}f}f{f{fffwfwfffkfkfff!f!fggWWJ J qqII]]yy||;$;$NaNaggNfNffftftfffzfzf}f}f{f{f~f~f{f{f|f|f}f}fzfzfffzfzf}f}f|f|f|f|f}f}fzfzf~f~f{f{f}f}f|f|f|f|f{f{fffyfyfffzfzf}f}f}f}f{f{f}f}f|f|f{f{f~f~fzfzfffyfyfffyfyfffxfxfffufufffkfkfff*f*fgg[[ΙΙeezz~~~~zziiKK^^WgWg;f;fffofofffwfwfffzfzf|f|f}f}f{f{f~f~fzfzfffxfxfffyfyf~f~f|f|f|f|f|f|f}f}fzfzfffzfzf~f~f{f{f|f|f}f}f|f|f{f{f~f~fzfzfffzfzf}f}f|f|f{f{fffyfyfffyfyfffyfyfffufufffmfmfff;f;fWgWg^^JJnn}}||eeЙЙ}}[[gg*f*fffkfkfffxfxf~f~fzfzfffxfxfffyfyf~f~f{f{f~f~fzfzfffyfyfffyfyfff{f{f|f|f}f}fzfzf~f~f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzfffxfxfffyfyfffzfzf}f}f{f{fffxfxfffpfpfffLfLfggMaMa<$<$晏zzxx\\JJmmN N WWggffffdfdfffqfqfffwfwfff{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~fzfzfffzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{fffyfyfffzfzf}f}f}f}f{f{f}f}f{f{f~f~fzfzfffwfwfffafafffZcZc,,˂]]{{]]66wwSSggffffffffffufufffwfwfffyfyfffzfzf~f~f{f{f|f|f}f}f{f{f~f~f{f{f|f|f|f|f|f|f~f~fyfyfffwfwfffyfyf~f~f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~f{f{f|f|f}f}f|f|f|f|f|f|f|f|f}f}f{f{fffrfrfffdd~4~4kkӣ(({{~~xx[[HHNNggffffgfgfffufufff{f{f|f|f}f}fzfzfffzfzf}f}f|f|f{f{fffyfyfffzfzf}f}f|f|f}f}f{f{f}f}f|f|f{f{f~f~f{f{f}f}fzfzfffwfwfffzfzf{f{fffxfxfffzfzf}f}f|f|fzfzfffwfwfffwfwfffvfvfffofofff;;۵䘴oo||}}~~yy^^ڙڙllff~~HHpgpg.f.fffififffxfxf}f}f}f}fzfzf~f~f{f{f~f~f{f{f{f{f~f~f{f{f|f|f~f~fyfyfffxfxfffyfyf~f~f|f|f|f|f|f|f}f}fyfyfffwfwfffyfyf}f}f|f|f|f|f}f}f|f|f|f|f{f{f~f~f{f{f|f|f}f}fzfzfffyfyfffqfqfffIfIfffBBAAșșddww}}ffəəGGzzBBffLfLfffpfpfffyfyf~f~f{f{f}f}fzfzfffzfzf~f~f{f{f}f}fzfzfffyfyfff{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fyfyfffzfzf|f|f~f~fxfxfffufufffjfjfff.f.frgrgHHbbppיי__yyqq蘯;;ffqfqfffwfwfffzfzf}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf}f}f|f|f}f}f{f{f}f}f{f{f}f}f}f}f{f{f}f}f{f{f~f~fzfzfffzfzf}f}f|f|f|f|f|f|f~f~fxfxffflflfff f fggNNFF\\yy~~ww##jj}4}4ddffvfvf~f~f{f{f}f}f|f|f{f{fffyfyfffzfzf}f}f|f|f|f|f}f}f|f|f{f{f}f}f{f{f~f~f|f|f{f{f|f|f}f}f|f|f}f}f{f{f|f|f~f~fzfzfffyfyfffzfzf~f~f|f|f{f{f~f~fzfzf~f~f{f{f}f}f|f|f{f{fffvfvfffhfhfffffggSStt66[[{{``˄˕,,ZcZcff`f`fffwfwfff{f{f|f|f}f}f{f{f}f}f|f|f}f}fzfzf~f~f{f{f}f}f}f}fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f|f|f{f{fffxfxfffwfwfffwfwfffvfvffftftfffpfpfffefefffffggWWI I ssGG[[xx}}yy<$<$MaMaggLfLfffqfqfffyfyf~f~f|f|f|f|f{f{f~f~fzfzfffyfyfffzfzf~f~f{f{f|f|f~f~fyfyfff{f{f{f{fffyfyf~f~f}f}fyfyfffyfyf~f~f|f|f{f{f}f}f}f}fzfzfffyfyf~f~f|f|f{f{fffwfwfffsfsfffhfhfff(f(fgg[[ЙЙccxx}}kkII^^XgXg:f:fffmfmfffxfxfffzfzf~f~f{f{f|f|f~f~fyfyfff{f{f|f|f~f~fyfyfffzfzf}f}f}f}f{f{f|f|f}f}f{f{f~f~f{f{f{f{f~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}fzfzfffvfvfffnfnfff$>$噏||}}ww^^ߙߙLLmmO O WWggffffffffffvfvfffzfzf}f}f{f{f~f~f{f{f|f|f}f}f{f{f}f}f}f}f{f{f|f|f~f~fyfyfffzfzf|f|f}f}f{f{f}f}f}f}fyfyfffxfxfff{f{f{f{f~f~f{f{f}f}f{f{f}f}f{f{f~f~f{f{f}f}f{f{f~f~fyfyfffwfwfffcfcfff\c\c,,˂\\}}wwYY77ttSSggffffhfhfffufufffxfxfffxfxfffwfwfffzfzf}f}f}f}fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f|f|f{f{f}f}f{f{f~f~f{f{f}f}f{f{f|f|f~f~fzfzf~f~fzfzf~f~f{f{f~f~fzfzf~f~fzfzf~f~f|f|f|f|f|f|f}f}fvfvfffddy4y4ooӢ''zz||``ޙޙIINNggffffjfjfffwfwfffyfyf~f~f}f}fyfyfff{f{f}f}f{f{f~f~fyfyfffyfyf~f~f{f{f}f}f|f|f|f|f|f|f|f|f|f|f~f~fzfzf~f~fzfzf}f}f}f}f{f{f~f~fyfyfffzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzfffxfxfffvfvfffpfpfff;;۴☸jjyy}}{{bb֙֙ppccHHogog1f1fffkfkfffufufffyfyf~f~f{f{f}f}f{f{f}f}f|f|f|f|f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}fzfzfffzfzf}f}f}f}fzfzfffzfzf}f}f|f|f{f{fffyfyfffwfwfffwfwfffpfpfffKfKfffBB{{EEƙƙii}}~~~~~~jjęęDD||BBffKfKfffrfrfff{f{f~f~fxfxfffvfvfffyfyf~f~f{f{f~f~fzfzf~f~fzfzf~f~f|f|f|f|f|f|f|f|f|f|f}f}f|f|f|f|f{f{fffxfxfffzfzf}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}fzfzfffvfvfffjfjfff.f.fqgqgHHddpp֙֙aazz~~~~qq昲;;ffofofffvfvfffzfzf~f~f{f{f}f}f|f|f{f{f~f~f{f{f|f|f|f|f}f}f|f|f|f|f|f|f{f{fffyfyfffzfzf}f}f|f|f|f|f|f|f~f~fyfyfffzfzf}f}f|f|f|f|f|f|f}f}f{f{f|f|f}f}f{f{f~f~fzfzfffwfwfffsfsfffffffffffggNNGG[[uu{{}}~~yy''mm{4{4ddffufufff{f{f}f}f{f{f~f~fyfyfffyfyf~f~f|f|f{f{f}f}f|f|f|f|f|f|f}f}fzfzfffzfzf~f~fzfzf~f~fzfzf~f~f|f|f{f{f~f~fzfzf}f}f|f|f}f}f{f{f~f~fyfyfff{f{f|f|f}f}f{f{f}f}f}f}fyfyffftftfffffffffffggSSrr88YYvv`` ˆ˒,,^c^cffcfcfffvfvfffyfyf~f~f|f|fzfzfffzfzf~f~f{f{f}f}fzfzfffzfzf~f~fzfzf~f~fzfzf~f~f{f{f}f}f{f{f}f}f|f|f{f{fffxfxfffxfxfffzfzf~f~f{f{f}f}f|f|f{f{f~f~f{f{f}f}f{f{f|f|fffwfwfffkfkfff"f"fggWWM M nnJJ[[vv~~{{=$=$LaLaggMfMffftftfff|f|f|f|f|f|f}f}fzfzfffyfyfffxfxfffxfxfffzfzf}f}f|f|f{f{f~f~f{f{f}f}f{f{f}f}f|f|f}f}f{f{f|f|f}f}f|f|f|f|f|f|f|f|f|f|f~f~fzfzf}f}f{f{f~f~f{f{f}f}f{f{f~f~fwfwfffififff)f)fgg[[~~ؙؙ]]ww}}}}ooEE^^\g\g6f6fffkfkfffxfxf~f~f{f{f~f~fzfzf}f}f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f{f{f~f~f{f{f}f}f{f{f}f}f{f{f~f~f{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}fzfzffftftfffjfjfff:f:fVgVg^^~~LLll||~~~~}}ddҙҙ[[gg*f*fffjfjfffsfsfffwfwfffzfzf}f}f|f|f{f{fffxfxfffzfzf|f|f~f~fyfyfffyfyfffzfzf}f}f|f|f|f|f}f}f|f|f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{f~f~f{f{f|f|f}f}fzfzfffwfwfffrfrfffOfOfggOaOa;$;$噏zz{{^^HHssI I WWggffffififffufufffvfvfffwfwfffyfyf}f}f|f|f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fyfyfffyfyf~f~f|f|f{f{f}f}f|f|f|f|f}f}fzfzfffyfyfffufufffafafff\c\c,,ˆ aavvYY66ttSSggffffefefffrfrfffvfvfffzfzf}f}f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f~f~fyfyfffxfxfffzfzf}f}f{f{f}f}f|f|f|f|f}f}fzfzfffyfyfffxfxfff|f|f{f{f}f}f|f|f{f{fffzfzfxfxfffdd{4{4mmӣ''||wwZZDDNNgg!f!fffififffufufffyfyf}f}f}f}f{f{f}f}f{f{f}f}f|f|f{f{fffyfyfffzfzf|f|f~f~fzfzf~f~f{f{f|f|f~f~fyfyfffyfyfffzfzfffzfzf}f}f{f{f}f}f|f|f}f}f{f{f}f}f{f{f}f}f}f}fyfyffftftffftftfffpfpfff;;۰昵mm||zzbbԙԙrraaHHqgqg0f0fffnfnfffyfyf}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~f{f{f|f|f}f}f|f|f|f|f|f|f|f|f|f|f~f~fzfzf}f}f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f{f{f~f~fyfyfffxfxfffxfxfffpfpfffJfJfffBB~~BBǙǙggzz}}ll==BBffHfHfffpfpfffufufffxfxfffyfyf}f}f|f|f}f}f{f{f~f~fyfyfffzfzf~f~f{f{f|f|f}f}fzfzfffyfyf}f}f|f|f|f|f}f}f|f|f|f|f|f|f{f{f~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f|f|f{f{fffxfxfffvfvffflflfff0f0fogogHHccrrҙҙee}}ss䘵;;ffnfnfffrfrfffwfwfff{f{f|f|f|f|f}f}f{f{f~f~fzfzf}f}f|f|f}f}f{f{f~f~fyfyfffzfzf~f~f{f{f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f}f}f|f|f{f{f~f~fyfyfffyfyfffyfyfffzfzfffxfxfffsfsfffgfgfffffggNNDDZZxxxx##ll{4{4ddffufufff{f{f|f|f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~f{f{f|f|f~f~fzfzf}f}f}f}fzfzfffzfzf}f}f}f}fzfzf~f~f|f|fzfzfffxfxfff{f{f|f|f|f|f}f}f|f|f|f|f{f{f}f}f|f|f|f|fffufufffhfhfffffggSSqq::[[vv~~__ ˆ˓,,]c]cffdfdfff|f|fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{fffyfyfffyfyfffxfxfffyfyfffyfyfffyfyfffufufffhfhfffffggWWM M ppII\\zz{{=$=$KaKaggKfKfffsfsfff|f|f|f|f|f|f|f|f|f|f}f}f|f|f|f|f|f|f{f{fffyfyfffyfyfffzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzfffxfxfffsfsfffefefff(f(fgg[[ ҙҙbbxx~~}}kkKK^^UgUgf>fUgUg^^IIpp||xxccϙϙ[[gg+f+fffififfftftfff{f{f{f{f~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f|f|f~f~fyfyfffyfyfff{f{f|f|f}f}f{f{f}f}f{f{f~f~f{f{f~f~fxfxfffufufffufufffxfxf~f~f{f{f~f~fzfzfffwfwfffsfsfffOfOfggNaNa;$;$♑zzzztt\\ߙߙMMllO O WWggffffdfdfffsfsfffxfxfffxfxfffyfyfffzfzf~f~fzfzf~f~f{f{f|f|f~f~fyfyfffxfxfff{f{f|f|f}f}f|f|f{f{f}f}f|f|f|f|f~f~fxfxfffzfzf}f}f|f|f|f|f{f{fffyfyfffyfyfffyfyfffxfxfffefefff_c_c,,ˆ^^yy[[99rrSSggffffgfgfffxfxf~f~f{f{f|f|f|f|f}f}f}f}fzfzf~f~f{f{f|f|f~f~fyfyfffyfyf~f~f{f{f}f}f{f{f~f~fyfyfffxfxfffyfyf~f~f|f|f|f|f{f{fffxfxfffyfyf}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~fzfzfffufufffddw4w4qqӠ))zz}}vv]]HHNNggffffififffufufffyfyf~f~f{f{f~f~fyfyfffxfxfffzfzf}f}f{f{f}f}f|f|f}f}fzfzfffxfxfffxfxfffzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f|f|f{f{f~f~fxfxfffsfsfff;;۵䘴oo~~{{``ؙؙmmgg||HHmgmg2f2fffjfjffftftfffyfyf}f}f|f|f|f|f|f|f}f}f{f{f~f~fyfyfffxfxfffzfzf|f|f}f}f{f{f}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f|f|f{f{f}f}f|f|f|f|f|f|f~f~fwfwfffkfkfffEfEfffBBCCǙǙffzz}}ggșșDDBBffEfEffflflfffvfvfffzfzf}f}f}f}f{f{f}f}f{f{f}f}f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fyfyfffzfzf~f~fzfzfffyfyfffzfzf}f}f}f}fzfzfffzfzf}f}f|f|f|f|f}f}f{f{f~f~fyfyfffufufffjfjfff-f-frgrgHH``ssәәccyyss昴;;ffpfpfffxfxf|f|f}f}f|f|f|f|f~f~fxfxfffwfwfffyfyf~f~f{f{f}f}f{f{f}f}f|f|f}f}fzfzfffyfyfff{f{f{f{fffxfxfffwfwfffxfxfffyfyf~f~f{f{f~f~fzfzf~f~f{f{f|f|f~f~fzfzf}f}f}f}fxfxfffififff!f!fggNNDDZZww}}}}xx""jj}4}4ddfftftfff|f|f{f{f~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~fzfzfffyfyfff{f{f|f|f|f|f|f|f}f}f|f|f{f{f~f~fyfyfffwfwfffxfxfffufufffhfhfffffggSSuu77\\xx}}bb ˄˕,,ZcZcff`f`fffwfwfff{f{f}f}f{f{f}f}f|f|f}f}fzfzfffzfzf}f}f}f}fzfzf~f~f|f|f{f{f~f~f{f{f{f{fffyfyfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f{f{f}f}f}f}f{f{f}f}f|f|f{f{fffxfxfffwfwfffufufffhfhfffffggWWL L ooKKߙߙ__||~~}}ww:$:$OaOaggPfPfffsfsfffyfyfffyfyfffxfxfffzfzf}f}fzfzfffxfxfffwfwfffyfyfffyfyf~f~f{f{f|f|f~f~fzfzf~f~fzfzfffyfyfffzfzf}f}f}f}f{f{f}f}f{f{f~f~fzfzfffyfyfffyfyfffvfvfffjfjfff,f,fgg[[~~ љљbbyy||llKK^^WgWg;f;fffnfnfffxfxf~f~f{f{f}f}f|f|f|f|f}f}fzfzf~f~f|f|fzfzfffxfxfffyfyf~f~f{f{f|f|f~f~fzfzf~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}f|f|fzfzfffpfpfff;f;fXgXg^^HHnnzzbbҙҙ}}[[gg,f,fffhfhfffrfrfffxfxfffzfzf~f~fzfzf~f~f{f{f}f}f|f|f|f|f{f{f~f~f{f{f}f}f|f|f{f{f}f}f}f}fzfzfffyfyfffzfzf~f~fzfzfffyfyfffzfzf~f~fzfzfffzfzf}f}f{f{f~f~fzfzfffvfvfffqfqfffLfLfggLaLa>$>$晎{{zz]]KKnnN N WWggffffefeffftftfff{f{f|f|f}f}f|f|f{f{f~f~f{f{f|f|f}f}f{f{f}f}f}f}fyfyfffyfyf~f~f|f|f{f{f~f~f{f{f|f|f}f}f{f{f~f~fzfzf}f}f|f|f}f}f{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}fzfzfffyfyffftftfff^f^fffXcXc,,ˁ]]~~ww\\88ttSSggffffhfhfffufufffxfxfffzfzfffzfzf}f}f|f|f{f{f~f~f|f|f{f{f~f~fzfzf}f}f}f}f|f|f{f{f~f~fzfzfffyfyfffyfyfffzfzf|f|f}f}f{f{f~f~fzfzf~f~f{f{f}f}f|f|f|f|f{f{fffyfyf~f~f|f|f{f{ffftftfffdd{4{4mmӣ&&xx~~~~ww]]ߙߙJJNNgg!f!fffififffufufff{f{f|f|f|f|f}f}fzfzfffzfzf}f}f|f|f|f|f}f}f|f|f{f{f}f}f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf}f}f}f}fzfzfffyfyfffzfzf}f}f|f|f|f|f}f}f{f{f~f~fxfxfffsfsfffnfnfff;;۶㘴pp~~yy__ؙؙmmff~~HHngng0f0fffkfkfffvfvfffwfwfffwfwfffyfyf~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}fzfzf~f~f{f{f~f~fzfzf~f~fzfzfffyfyfffyfyfffyfyfffxfxfffwfwfffofofffIfIfffBBAAęęhh}}{{hhřřCC}}BBffKfKfffqfqfffwfwfffwfwfffxfxfff{f{f}f}f{f{f}f}f|f|f|f|f}f}f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f|f|f~f~fzfzf~f~fzfzfffyfyfffyfyfffxfxfffyfyf~f~f{f{f}f}f{f{fffwfwfffkfkfff-f-fqgqgHH||hhllؙؙaa||~~~~ss瘳;;ffofoffftftfffyfyf~f~f{f{f}f}f{f{f}f}f|f|f{f{fffwfwfffvfvfffzfzf}f}f|f|f}f}fzfzfffxfxfffvfvfffxfxf}f}f~f~fzfzf}f}f}f}f{f{f}f}f|f|f{f{f~f~f{f{f}f}f|f|f{f{f~f~fyfyfffsfsfffffffff f fggNNII]]zzww$$ll|4|4ddffufuf}f}f}f}f{f{f}f}f|f|f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f|f|f{f{f}f}f|f|f{f{fffxfxfffyfyfffyfyfffzfzf}f}f}f}fzfzf~f~f|f|f{f{f~f~fyfyfffxfxfffzfzf|f|f}f}f{f{f|f|fffufufffhfhfffffggSStt88[[xx``˂˖,,[c[cffbfbfffvfvfffwfwfffzfzf}f}f|f|f}f}fzfzfffyfyfffyfyf~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{fffwfwfffpfpfffefefffffggWWO O llMMߙߙ^^yy}}}}<$<$MaMaggNfNfffsfsfffyfyfffyfyfffzfzf~f~f{f{f|f|f|f|f}f}f|f|f|f|f|f|f}f}fzfzfffyfyfffyfyf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~fzfzfffyfyfffxfxfffxfxfffufufffififff)f)fgg[[ ϙϙdd{{{{kkFF^^ZgZg:f:fffofofffufufffwfwfff}f}fyfyf~f~f}f}fyfyfffxfxf~f~f}f}fzfzf~f~f{f{f|f|f~f~f{f{f|f|f|f|f}f}fzfzfffxfxfff{f{f|f|f|f|f}f}f{f{f~f~fzfzf~f~fzfzfffyfyfffwfwfffvfvfffpfpffff>fffpfpfffwfwfffxfxfffxfxfffwfwfffxfxfff{f{f|f|f}f}f|f|f|f|f{f{f~f~f{f{f}f}f|f|f{f{f}f}f}f}fzfzfffyfyfff{f{f{f{fffxfxfffxfxfffzfzf~f~fzfzfffyfyfffwfwfffqfqfff>f>fUgUg^^JJii{{zz__ՙՙ [[gg*f*fffjfjfffwfwf~f~f{f{f~f~f{f{f}f}f{f{f}f}f{f{f~f~f{f{f|f|f~f~fyfyfffzfzf}f}f~f~fyfyfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f{f{f}f}f}f}fyfyfffxfxfffzfzf}f}f|f|f{f{f}f}f|f|f{f{fffrfrfffMfMfggQaQa7$7$##ޙޙxxyy\\KKnnM M WWgg!f!fffjfjffftftffftftfffvfvfffzfzf~f~fzfzfffyfyf~f~f}f}fzfzfffyfyf~f~f|f|f|f|f|f|f}f}fzfzfffzfzf}f}f{f{f}f}f|f|f~f~fyfyfffzfzf}f}f~f~fyfyfffzfzf~f~fzfzfffwfwfffufufffafafff[c[c,,˄__vvZZ66uuSSggffffjfjfffwfwfff{f{f}f}f{f{f~f~fyfyfffyfyf~f~f|f|f{f{f}f}f}f}fzfzf~f~f{f{f|f|f}f}f|f|f|f|f{f{f}f}f|f|f}f}f|f|f{f{f|f|f~f~f{f{f|f|f~f~fyfyfff{f{f{f{f~f~f{f{f}f}f|f|f{f{f~f~fyfyfffsfsfffdd{4{4mmӤ%%yyww[[FFNNgg"f"fffkfkfffvfvfffxfxfffzfzfffzfzf}f}f|f|f{f{f~f~f|f|fzfzfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f{f{f}f}f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fzfzf~f~fzfzf~f~fzfzfffwfwfffvfvfffsfsfffmfmf f f;;۱昳pp~~~~yy``ؙؙnnee~~HHogog1f1fffmfmfffvfvfffxfxfff{f{f|f|f|f|f}f}fzfzfffxfxfff{f{f|f|f~f~fyfyfffxfxfffzfzf}f}f|f|f|f|f{f{fffyfyfffyfyf~f~f|f|f|f|f|f|f|f|f|f|f}f}fzfzfffxfxfffxfxfffxfxfffpfpfffJfJfffBB}}EEșșff{{}}ggǙǙEE||BBffKfKfffpfpfffxfxfffzfzf~f~fzfzf~f~f{f{f}f}f|f|f|f|f{f{fffyfyfffxfxfff{f{f}f}f|f|f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f}f}f}f}fzfzfffyfyfffzfzf~f~fzfzf~f~fzfzfffxfxfffrfrfffhfhfff,f,fsgsgHHeemmٙٙ^^zzoo☵;;ffrfrfff{f{f|f|f|f|f|f|f|f|f}f}f{f{f~f~fyfyfffxfxfffzfzf}f}f|f|f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzf~f~fzfzf~f~f{f{f}f}f|f|fzfzfffxfxfffxfxf}f}f~f~fyfyfffzfzf{f{fffwfwfffufufffififff f fggNNII]]zz{{&&kk~4~4ddffsfsfffyfyfffzfzf~f~f{f{f}f}fzfzfffwfwfffwfwfffzfzf|f|f~f~fzfzfffxfxfffyfyfffzfzf}f}f|f|f|f|f|f|f}f}fzfzfffzfzf}f}f|f|f|f|f|f|f}f}f{f{f|f|f~f~fzfzfffxfxfffufufffffffffffggSSss88[[vv}}bb ˈˑ,,^c^cffbfbfffufufffyfyf}f}f~f~fxfxfffvfvfffyfyf~f~f{f{f}f}f{f{f}f}f|f|f}f}fzfzfffyfyfff{f{f|f|f}f}f|f|f{f{f~f~fzfzf~f~f|f|f{f{f~f~fzfzf~f~f{f{f}f}f|f|f}f}fzfzfffvfvfffrfrfffhfhfff f fggWWK K ppJJ\\ww9$9$OaOaggNfNfffufuf}f}f}f}f{f{f}f}f|f|f|f|f}f}fzfzfffxfxfffxfxfff{f{f|f|f|f|f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{f~f~f{f{f|f|f|f|f}f}fzfzfffwfwfffwfwfffwfwfffxfxffftftfffhfhfff'f'fgg[[ ЙЙdd}}mmII^^ZgZg8f8fffmfmfffvfvfffufufffwfwfffzfzf}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~fzfzf~f~f{f{f}f}f{f{f~f~fyfyfffyfyf~f~f{f{f}f}f|f|f|f|f}f}f{f{f|f|f~f~fzfzfffyfyf~f~f{f{fffxfxfffmfmfff7f7f\g\g^^GGjj}}}}~~||eeϙϙ [[gg'f'fffefefffqfqfffwfwfff{f{f}f}fzfzfffwfwfffyfyf}f}f}f}f{f{f|f|f}f}f|f|f{f{f~f~fyfyfffzfzf|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f{f{f~f~f{f{f}f}f{f{f}f}f{f{fffxfxfffrfrfffMfMfggOaOa9$9$ ᙓww}}~~xx]]KKnnM M WWgg f fffhfhffftftfffxfxfffyfyf~f~f{f{f|f|f~f~fzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzfffxfxfffzfzf}f}f|f|f|f|f{f{fffyfyfffzfzf}f}f|f|f|f|f~f~fyfyfffzfzf}f}f}f}f{f{f|f|f}f}f|f|fyfyfff_f_fffYcYc,,˂]]~~wwZZ66uuSSggffffhfhfffsfsfffwfwfffyfyfffzfzf|f|f~f~f{f{f|f|f~f~fyfyfff{f{f|f|f}f}f|f|f{f{f~f~fzfzf}f}f}f}fzfzf~f~f{f{f|f|f}f}f{f{f~f~fyfyfffxfxfffzfzf|f|f}f}f{f{f~f~fzfzf~f~f{f{f|f|fffrfrfffdd~4~4kkӤ&&zz}}vv__ݙݙJJNNggffffgfgfffufufff{f{f|f|f}f}f{f{f|f|fffxfxfff|f|fzfzfffxfxfff{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~fzfzf~f~f|f|fzfzfffyfyfff{f{f|f|f|f|f|f|f|f|f~f~fyfyfffvfvfffpfpfff;;۲嘴oo~~}}ccՙՙooee~~HHngng1f1fffmfmfffvfvfffxfxfffxfxfffyfyfffzfzf}f}f|f|f}f}f{f{f}f}f|f|f{f{fffyfyf~f~f|f|fzfzfffzfzf~f~f{f{f|f|f|f|f}f}f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f}f}f{f{f~f~fyfyfffwfwfffmfmfffFfFfffBB~~DDǙǙff||~~~~~~||iiƙƙFF{{BBffIfIfffqfqfff|f|f{f{f}f}f|f|f|f|f|f|f}f}f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f}f}fzfzf~f~f|f|f{f{f~f~fzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fyfyfffxfxfffufufffhfhfff,f,frgrgHHccppיי__ww}}yykk䘲;;ffqfqfffyfyfffyfyfffzfzf}f}f|f|f|f|f|f|f|f|f~f~fyfyfffzfzf~f~f{f{f}f}f|f|f{f{f~f~f{f{f}f}f|f|f|f|f{f{f~f~f|f|f|f|f|f|f{f{f~f~f{f{f}f}f{f{f}f}f|f|f{f{f~f~f{f{f|f|f~f~fxfxfffsfsfffgfgfff f fggNNGG\\ww~~~~{{$$kk~4~4ddffsfsfff|f|f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~f{f{f|f|f}f}fzfzfffzfzf~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzfffyfyf~f~f|f|f|f|f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~fzfzfffvfvfffjfjfffffggSSss77[[yy^^˃˕,,ZcZcff`f`fffvfvf~f~f}f}f{f{f~f~fzfzf~f~fzfzfffzfzf}f}f}f}fyfyfffwfwfffxfxf~f~f|f|f|f|f|f|f}f}fzfzfffzfzf}f}f|f|f|f|f|f|f~f~fzfzf~f~fzfzf}f}f}f}f{f{f~f~fzfzf~f~f{f{f{f{fffvfvfffififff f fggWWL L ppII\\zz||<$<$NaNaggNfNffftftfffzfzf~f~fyfyfffyfyfffyfyfffzfzf}f}f}f}fzfzfffyfyf~f~f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f~f~fyfyfff{f{f{f{fffyfyfffzfzf~f~fzfzfffyfyfffxfxfffvfvfffmfmfff+f+fgg[[ әәaazz~~~~ooGG^^XgXg;f;fffpfpfffxfxfffzfzf}f}f}f}f{f{f|f|f}f}f{f{f}f}f}f}fyfyfffwfwfffzfzf~f~fzfzf~f~fzfzfffzfzf}f}f|f|f{f{fffyfyf~f~f|f|f{f{f~f~f{f{f}f}f{f{f}f}f|f|f|f|f}f}f{f{f~f~fyfyfffnfnfff;f;fWgWg^^KKkk||~~~~~~~~xxccЙЙ [[gg(f(fffjfjfffufufffvfvfffwfwfffxfxfffzfzf~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf}f}f}f}fzfzfffwfwfffvfvfffzfzf}f}f{f{f~f~fyfyfffzfzf|f|f}f}f|f|fzfzffftftfffPfPfggNaNa<$<$♒xxzz\\JJnnO O WWgg f fffififfftftfffxfxfff{f{f|f|f|f|f}f}f{f{f~f~fzfzf}f}f|f|f|f|f|f|f|f|f|f|f}f}f|f|f{f{f~f~fyfyfffxfxfff{f{f|f|f}f}f{f{f~f~fzfzfffxfxfffzfzf}f}f}f}fzfzf~f~f{f{f|f|fffwfwfffbfbfff]c]c,,˄^^vvWW55uuSSggffffefefffrfrfffwfwfffzfzf}f}f|f|f|f|f|f|f|f|f|f|f}f}f{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~f{f{f~f~fyfyfffxfxfffzfzf|f|f}f}f{f{f}f}f|f|f}f}f{f{f}f}f{f{f}f}f}f}fzfzfffsfsfffdd}4}4llӤ%%vv{{~~xx\\HHNNggffffhfhfffufufffxfxfff{f{f}f}f{f{f}f}f{f{f~f~fzfzfffyfyfffzfzf}f}f}f}fzfzfffzfzf}f}f|f|f|f|f}f}f{f{f|f|f~f~fyfyfffwfwfff{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~f|f|fyfyfffqfqfff;;۴䘵nn||zzaa֙֙ooddHHpgpg.f.fffififffxfxf|f|f~f~fzfzf~f~f{f{f}f}f{f{f}f}f}f}fyfyfffwfwfffzfzf~f~fzfzfffxfxfff{f{f{f{f~f~fzfzfffyfyfffyfyfffyfyf~f~f{f{f}f}f|f|f}f}fzfzfffyfyfffyfyfffufufffnfnfffJfJfffBB}}DDřřjj||~~zzggƙƙBB~~BBffJfJfffrfrfffzfzf}f}f{f{f}f}f}f}fzfzfffyfyfffzfzf}f}f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f|f|fzfzfffxfxfff{f{f|f|f}f}f|f|f{f{f~f~fzfzfffyfyfffyfyfffxfxfff{f{f|f|fffufufffkfkfff0f0fogogHHaarrԙԙbb{{tt꘯;;ffqfqffftftfffwfwfff{f{f|f|f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f}f}f|f|f|f|f}f}fzfzfffzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fxfxfffjfjfff f fggNNGG[[xxxx!!ii}4}4ddffwfwf|f|f}f}f|f|f|f|f}f}fzfzfffzfzf}f}f|f|f|f|f|f|f~f~fyfyfffzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f}f}f|f|f|f|f|f|f}f}fzfzfff{f{f|f|f}f}fzfzfffzfzf~f~fzfzfffxfxffftftfffififffffggSSss77ZZuuyy||bb ˇˑ,,^c^cffafafffvfvfff|f|fzfzfffxfxfff{f{f|f|f}f}f|f|f{f{f}f}f}f}fzfzfffwfwfffxfxfff|f|fzfzfffyfyfffzfzfffyfyfffyfyfffzfzfffyfyfffzfzf|f|fffxfxfffwfwfffufufffffffffffggWWM M ooKK]]yy}}~~}}yy:$:$PaPaggQfQfffsfsfffvfvfffwfwfffzfzf}f}f}f}fzfzf~f~f{f{f|f|f~f~f{f{f|f|f|f|f|f|f}f}f|f|f}f}fzfzf~f~f{f{f}f}f}f}f{f{f|f|f}f}f{f{f~f~f{f{f|f|f|f|f}f}f|f|f{f{f~f~fyfyfffwfwffftftfffififff*f*fgg[[ ЙЙdd{{}}mmFF^^YgYg:f:fffmfmfffvfvfffzfzf|f|f}f}f}f}fzfzfffxfxfffzfzf~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fyfyfffxfxfff|f|f{f{f}f}f|f|f|f|f|f|f~f~fyfyfffxfxfffwfwfffufufffnfnfff8f8f[g[g^^GGkk{{zzffΙΙ [[gg+f+fffjfjfffufufffyfyfffzfzf|f|f~f~fzfzf~f~f{f{f}f}f{f{f}f}f|f|f{f{fffyfyf~f~f{f{f|f|f}f}f|f|f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f}f}f|f|f{f{f~f~fyfyfffvfvfffqfqfffKfKfggJaJa?$?$䙐zz~~vv[[LLllP P WWggffffgfgfffsfsfffwfwfffyfyfffzfzf}f}f|f|f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzfffyfyf~f~f|f|f{f{f~f~f{f{f{f{fffyfyfffzfzf|f|f}f}f|f|f}f}f{f{f|f|f|f|f}f}f|f|f}f}f{f{f|f|f~f~fxfxfffbfbfff]c]c,,˄__xxYY55vvSSggffffffffffrfrfffwfwfffyfyfffyfyfffxfxfffyfyfffyfyfffzfzf~f~f{f{f|f|f}f}f|f|f|f|f|f|f|f|f}f}f|f|f|f|f{f{f~f~f{f{f~f~fyfyfff{f{f|f|f}f}fzfzfffzfzf}f}f|f|f{f{f~f~fzfzfffufufffddz4z4nnӣ%%xx}}ww\\IINNgg"f"fffififffufufffyfyfffyfyfffzfzf~f~f{f{f}f}f{f{f~f~fzfzf}f}f}f}f{f{f~f~fzfzf}f}f|f|f|f|f}f}f|f|f{f{f~f~fyfyfffyfyfffzfzf|f|f}f}f|f|f}f}f{f{f}f}f{f{f}f}f|f|f|f|f~f~fxfxffftftfffpfpfff;;۱嘶kkyy{{__ٙٙmmeeHHsgsg,f,fffhfhfffrfrfffvfvfffzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f}f}f|f|f}f}f{f{f}f}f{f{f~f~fyfyfffyfyf~f~f{f{f}f}f{f{fffxfxfff|f|fzfzfffxfxf~f~f}f}fzfzfffxfxffftftfffrfrfffofofffLfLfffBB}}DDǙǙff||~~xxddəəFFzzBBffMfMfffpfpfffvfvfffyfyf~f~f|f|f{f{f~f~fzfzf~f~f{f{f|f|f~f~fyfyfff{f{f{f{fffxfxfffzfzf}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f}f}f|f|f{f{f~f~fzfzfffxfxfffvfvfffififff+f+ftgtgHHbbqqԙԙcc{{~~oo㘶;;ffsfsfffzfzf}f}f{f{fffwfwfffxfxf~f~f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}f{f{f|f|f}f}f|f|f|f|f|f|f}f}fzfzf~f~f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f}f}f|f|f~f~fyfyfffyfyffftftfffefefffffggNNDDYYzz~~yy''oox4x4ddffwfwf}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~fzfzfffyfyfffxfxfffzfzf~f~f{f{f}f}f{f{f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{f}f}f|f|f|f|f~f~fwfwfffufufffvfvfffrfrfffefefffffggSSss88]]xx~~]]˅˒,,^c^cffcfcfffyfyf}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f{f{fffyfyfffzfzf}f}f}f}fzfzfffxfxfffzfzf~f~f{f{f~f~fyfyfffyfyfffyfyf~f~f{f{f|f|f~f~fzfzf}f}f}f}fyfyfffwfwfffxfxfffvfvfffhfhfffffggWWM M ooJJ\\wwzz!!9$9$NaNaggLfLfffsfsfff{f{f}f}f{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f|f|f}f}f{f{f~f~f{f{f|f|f|f|f}f}f|f|f|f|f}f}fzfzfffzfzf~f~fzfzf~f~f|f|f{f{f~f~fzfzf}f}f}f}f{f{f|f|f~f~fzfzf}f}f~f~fvfvfffkfkfff-f-fgg[[||ՙՙ``xx||mmEE^^\g\g7f7ffflflfffvfvfffvfvfffufufffxfxfffxfxfffyfyf~f~f|f|f{f{f~f~fzfzfffyfyfffyfyfff{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f}f}f{f{f~f~fxfxfffnfnfff:f:fXgXg^^IImmzz}}}}ddЙЙ [[gg(f(fffhfhfffsfsfffxfxf~f~f|f|f{f{f}f}f}f}fzfzfffyfyf~f~f|f|f{f{f~f~f{f{f|f|f|f|f}f}fzfzfffyfyf}f}f}f}fzfzfffzfzf}f}f|f|f}f}f{f{f}f}f{f{f~f~f{f{f|f|f}f}f{f{f}f}f}f}fzfzffftftfffOfOfggNaNa;$;$ᙔuu~~xx[[IIqqJ J WWgg#f#fffmfmfffzfzf}f}f|f|f}f}fzfzf~f~f{f{f|f|f~f~f{f{f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~fzfzfffyfyfffyfyf~f~f{f{f}f}f|f|f}f}fzfzfffyfyfffxfxfff{f{f|f|f}f}f|f|fzfzfffvfvfffafafffZcZc,,˃``~~xx[[::qqSSggffffkfkfffxfxf~f~fzfzfffxfxfff{f{f{f{fffyfyfffyfyfff{f{f{f{fffxfxfffyfyfffyfyfffxfxfff{f{f|f|f}f}f|f|f{f{f~f~fzfzf~f~f|f|f{f{f~f~fyfyfffzfzfffyfyfffyfyfff|f|fufufffdd}4}4kkӥ%%xx~~}}xx]]HHNNgg!f!fffififffufufffzfzf}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fyfyfffxfxfff|f|fzfzfffyfyfffzfzf~f~f{f{f|f|f~f~fyfyfffyfyf~f~f{f{f}f}f{f{ffftftffflflf f f;;۴㘶mm}}yy``ؙؙnnddHHugug*f*fffgfgfffrfrfffwfwfffxfxfffyfyf}f}f~f~fyfyfff{f{f{f{fffzfzf}f}f|f|f{f{f}f}f}f}f{f{f}f}f|f|f{f{fffyfyf~f~f{f{f}f}f|f|f|f|f}f}fzfzf~f~f{f{f}f}f|f|f|f|f{f{f~f~f{f{f{f{fffofofffHfHfffBB}}DDřřii{{}}}}zziiřřEE{{BBffLfLfffpfpfffvfvfffwfwfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f{f{f}f}f}f}fzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f|f|f{f{f~f~fzfzf}f}f~f~fxfxfffvfvfff|f|fzfzf~f~f|f|fzfzfffufufffkfkfff.f.fqgqgHHccqqԙԙcc{{}}pp꘮;;ffqfqfffwfwfffzfzf|f|f}f}f{f{f~f~fzfzfffxfxfffwfwfffyfyf}f}f}f}f{f{f}f}f}f}fzfzf}f}f~f~fyfyfffxfxfff{f{f}f}f|f|f{f{f~f~fzfzf~f~f|f|fzfzfffxfxfff|f|fyfyfffufufffsfsfffgfgfffffggNNHH[[vv~~}}&&ll}4}4ddffqfqfffyfyfffyfyfffwfwfffvfvfffvfvfffyfyf|f|f~f~fzfzfffyfyf~f~f{f{f|f|f~f~fzfzf}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf}f}f|f|f}f}f{f{f~f~fyfyfffyfyf~f~f|f|f|f|f{f{fffvfvfffgfgfffffggSSxx44XXww^^˂˖,,ZcZcffafafffyfyf|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~f{f{f}f}f{f{f}f}f{f{f~f~f{f{f|f|f}f}f{f{f~f~fzfzf}f}f}f}fzfzfffxfxfff{f{f{f{fffxfxffftftfffhfhfff f fggWWJ J rrGGZZxx}}}}zz:$:$PaPaggQfQffftftfffxfxfff{f{f|f|f|f|f}f}f|f|f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f|f|f~f~fyfyfffyfyf}f}f~f~fxfxfffzfzf|f|f~f~fzfzf}f}f}f}fzfzfffzfzf}f}f|f|f}f}fyfyffflflfff+f+fgg[[ ϙϙccxx||||yymmII^^UgUg$>$LaLaggLfLfffofoffftftfffxfxf~f~fzfzfffyfyfff{f{f|f|f|f|f}f}fzfzfffzfzf}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}f{f{f|f|f~f~fzfzf~f~fzfzfffxfxffftftfffkfkfff+f+fgg[[ ΙΙff||~~kkJJ^^YgYg9f9ffflflfffwfwfffzfzf}f}f|f|f|f|f{f{fffyfyfffzfzf}f}f}f}fzfzfffzfzf}f}f}f}f{f{f}f}f|f|f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~fzfzf~f~f{f{fffvfvffflflfff9f9fYgYg^^HHkk}}{{ccљљ [[gg-f-fffnfnfffwfwfffzfzf}f}f{f{f}f}f{f{f~f~f{f{f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}fzfzf~f~f{f{f~f~fzfzf}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f{f{fffxfxfffvfvfffqfqfffOfOfggPaPa;$;$晎{{}}ww\\JJooM M WWggffffhfhfffufufffyfyf~f~f{f{f}f}f{f{f}f}f|f|f{f{f~f~f{f{f{f{fffvfvfffwfwfff|f|fyfyfffxfxfffxfxfff{f{f}f}f{f{f|f|f}f}f|f|f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f|f|fzfzfffcfcfff]c]c,,ˇ aa~~{{uu[[99rrSSggffffififffwfwfff{f{f|f|f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~f{f{f|f|f~f~fxfxfffxfxfff{f{f{f{fffyfyfffyfyfffzfzf~f~f{f{f|f|f}f}f|f|f{f{f~f~fzfzfffsfsfffdd44hhӨ""ww~~zz]]FFNNgg!f!fffgfgffftftfffxfxfffzfzf~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{f}f}f|f|f{f{fffyfyf~f~f{f{f}f}f|f|f}f}fzfzf~f~fzfzfffzfzf}f}f|f|f{f{f~f~f|f|f{f{f}f}f{f{f~f~f{f{f}f}f{f{f~f~fyfyffftftfffmfmfff;;۲昳pp}}}}xx``ייooccHHpgpg0f0fffnfnfffwfwfffxfxfffyfyfffzfzf}f}f{f{f}f}f}f}f{f{f}f}f{f{f}f}f|f|f|f|f}f}f{f{f~f~fzfzf~f~fzfzfffzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~f{f{f}f}f{f{f}f}f{f{fffyfyfffxfxfffqfqfffJfJfffBB||EEșșggzz{{iięęBB~~BBffMfMffftftfff|f|f|f|f|f|f~f~fxfxfffxfxfff{f{f{f{f~f~f{f{f|f|f~f~fyfyfffyfyf}f}f}f}f{f{f~f~fzfzf~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f|f|f}f}fzfzf~f~f|f|f{f{f~f~f{f{fzfzfffififff-f-frgrgHHbbrrԙԙbb{{oo嘳;;ffqfqfffxfxfffyfyfffzfzf}f}f|f|f}f}f{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf}f}f|f|f|f|f}f}f|f|f{f{f}f}f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}fzfzfffyfyfffyfyf~f~f{f{f|f|f~f~fxfxfffhfhfffffggNNLLݙݙ__xx~~}}}}||%%ii44ddffvfvfzfzfffufufffwfwfffzfzfffzfzf}f}f|f|f{f{f~f~f|f|f{f{f}f}f|f|f{f{f~f~f{f{f}f}f|f|f{f{f}f}f{f{f~f~fzfzfffyfyf~f~f{f{f}f}f|f|f|f|f|f|f|f|f~f~fyfyfffxfxfffyfyfffvfvfffffffffffggSSuu88]]xx]]˂˖,,ZcZcffafaffftftfffvfvfffyfyf}f}f|f|f}f}fzfzfffyfyfffyfyfffyfyf~f~f|f|f{f{f}f}f}f}fyfyfffwfwfffzfzf}f}f|f|f}f}fzfzf~f~f{f{f}f}f|f|f}f}fzfzf~f~f{f{f}f}f|f|f}f}fyfyfffsfsfffffffffffggWWL L ppJJ^^zz~~}}xx 8$8$QaQaggPfPfffsfsfffyfyfff{f{f|f|f|f|f}f}fzfzfffzfzf~f~fzfzfffxfxfffzfzf}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~fzfzfffwfwfffififff'f'fgg[[ љљbbwwzz||llGG^^ZgZg9f9fffnfnfffxfxfffxfxfffwfwfffzfzf}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f~f~fyfyfffzfzf}f}f|f|f}f}fzfzfffyfyfffzfzf~f~fyfyfffvfvfffnfnfff=f=fVgVg^^FFnn||zzbbҙҙ [[gg)f)fffjfjfffwfwf~f~f|f|f|f|f}f}fzfzfffyfyfff{f{f|f|f|f|f|f|f}f}f{f{f~f~fyfyfffyfyf~f~f|f|fzfzfffxfxfff{f{f}f}f{f{f}f}f{f{f}f}f}f}fzfzfffyfyfffzfzf~f~f{f{f}f}fzfzfffpfpfffIfIfggMaMa:$:$㙐{{~~||ww[[GGssI I WWggffffffffffufufff|f|f|f|f{f{f~f~fzfzf~f~f{f{f|f|f}f}f|f|f{f{f}f}f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~f{f{f|f|f|f|f~f~fwfwfff]f]fffWcWc,,˄ aazzZZ66uuSSggffffdfdfffsfsfffvfvfffwfwfffwfwfffzfzf|f|f~f~fzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f{f{f|f|f~f~fzfzf~f~fzfzf~f~f{f{f~f~fzfzf}f}f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f|f|fxfxfffdd{4{4llӤ&&yy~~xx\\FFNNgg!f!fffififffvfvfffzfzf~f~fzfzf~f~fzfzfffyfyfffzfzf~f~f{f{f|f|f}f}f|f|f|f|f}f}f{f{f|f|f~f~fyfyfffyfyf~f~f{f{f|f|f}f}f|f|f|f|f|f|f|f|f|f|f}f}f|f|f|f|f|f|f|f|f}f}fzfzfffwfwfffvfvfffsfsfff;;۴䘵nn||~~}}yy``ؙؙmmgg||HHpgpg-f-fffgfgfffsfsfffzfzf}f}f}f}fzfzf~f~f{f{f}f}f|f|f{f{f}f}f|f|f|f|f}f}f{f{f|f|f}f}fzfzfffyfyf~f~f{f{f|f|f}f}f|f|f}f}fzfzfffxfxfffxfxfffxfxfffxfxfffwfwfffwfwfffvfvfffofofffIfIfffBBAAęęhh{{}}yyiiřřEE{{BBffJfJfffofofffwfwfffyfyf~f~f|f|f|f|f}f}fzfzf~f~f{f{f}f}f|f|f}f}fzfzf~f~f|f|f{f{f~f~fzfzf}f}f~f~fyfyfffzfzf}f}f|f|f}f}f{f{f}f}f|f|f{f{fffxfxfffzfzf}f}f|f|f|f|f}f}fzfzfffvfvffflflfff1f1fpgpgHHaarrՙՙaaww}}}}pp䘳;;ffmfmfffvfvfff{f{f{f{f~f~fyfyfff|f|f{f{f~f~fyfyfffzfzf~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~fzfzfffyfyfffzfzf~f~fzfzf}f}f}f}f{f{f~f~fyfyfffyfyfffvfvfffjfjfff$f$fggNNFF]]xx}}~~{{''mm{4{4ddffyfyfzfzfffzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f}f}f{f{f~f~f{f{f|f|f|f|f}f}f{f{f~f~fzfzf}f}f|f|f|f|f|f|f}f}fzfzfffyfyfffwfwfffxfxfffvfvfffhfhfffffggSStt66YYuu||~~[[ˁ˗,,YcYcffafafffwfwfffzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzfffxfxfffzfzf}f}f|f|f{f{f~f~f{f{f}f}fzfzfffzfzf}f}f}f}fzfzfffyfyfffzfzf~f~f{f{f|f|f|f|f~f~fxfxfffrfrfffefefffffggWWL L nnLLߙߙ^^yy~~zz<$<$MaMaggNfNfffrfrfffwfwfffxfxf~f~f|f|f|f|f}f}f|f|f{f{f}f}f|f|f|f|f}f}f{f{f~f~fzfzf}f}f}f}fzfzfffwfwfffxfxfffyfyf~f~f|f|f{f{f~f~f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}fyfyfffnfnfff,f,fgg[[ ҙҙcc}}}}{{llLL~~^^UgUg=f=fffnfnfffufufffyfyf~f~f{f{f}f}f|f|f{f{f~f~f{f{f|f|f~f~fzfzf}f}f}f}fzfzf~f~f|f|f{f{f~f~fzfzf}f}f|f|f}f}f{f{f}f}f{f{f}f}f|f|f}f}fzfzfffyfyfff{f{f|f|f}f}f|f|fzfzfffwfwfffofofff$>$晏zz}}xxZZJJmmP P WWggffffififffvfvfffyfyf~f~f{f{f}f}f{f{f~f~fyfyfffzfzf|f|f~f~fyfyfffyfyf~f~f{f{f}f}f|f|f{f{f~f~f{f{f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}fzfzfffzfzf~f~f{f{f|f|f{f{ffftftfff^f^fff[c[c,,˂\\zz]]88ttSSggffffgfgfffvfvfffzfzf~f~fzfzf~f~f{f{f|f|f~f~fyfyf~f~f|f|f{f{fffyfyfffyfyfff{f{f|f|f~f~fyfyfffxfxfffzfzf|f|f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f|f|f|f|f{f{fffrfrfffdd44jjӥ%%yy~~~~~~yy^^GGNNgg"f"fffffffffsfsfffwfwfffyfyf~f~f|f|f{f{f~f~fzfzf~f~f|f|f{f{f~f~fzfzfffyfyfffzfzf}f}f}f}fzfzf~f~f{f{f|f|f~f~fyfyfffxfxfffyfyfffyfyfffxfxfffzfzf|f|f~f~fyfyfffxfxfffvfvfffqfqfff;;۲瘱rr}}xxaa֙֙ppccHHqgqg.f.fffififfftftfffxfxfff{f{f{f{fffxfxfffzfzf}f}f|f|f{f{f}f}f}f}fzfzfffvfvfffvfvfffyfyf}f}f}f}fzfzfffyfyfffzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzfffyfyfffvfvfffofofffJfJfffBB||DDęęjj}}~~}}zziiÙÙ@@BBffIfIfffnfnfffvfvfff{f{f|f|f|f|f|f|f}f}f{f{f~f~fyfyfff{f{f|f|f~f~fxfxfff{f{f|f|f}f}fzfzfffzfzf~f~fzfzfffyfyfffxfxfff{f{f}f}f|f|f{f{f~f~fzfzf~f~f|f|f{f{f~f~fzfzf~f~fzfzfffpfpfff3f3fmgmgHHbbssҙҙdd}}oo㘵;;ffpfpfffufufffxfxfffzfzfffzfzf}f}f{f{f~f~fzfzfffyfyfffzfzf}f}f|f|f|f|f}f}fzfzfffzfzf}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f{f{fffyfyfffzfzf}f}f|f|f|f|f}f}f|f|fzfzffftftfffefefffffggNNIIߙߙ__yyzz""hhӀ44ddffrfrfff{f{f|f|f~f~fzfzf}f}f|f|f}f}f{f{f}f}f|f|f{f{f~f~f{f{f|f|f}f}f{f{f}f}f}f}f{f{f}f}fzfzfff{f{f|f|f~f~fxfxfffxfxfffzfzf~f~f{f{f}f}f{f{f}f}f{f{f~f~f{f{f}f}f{f{f|f|fffufufffbfbfffffggSSvv44YYxx}}~~aa˃˕,,\c\cffefefffzfzf|f|f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fyfyfffzfzf|f|f}f}f|f|f{f{fffxfxfff|f|fzfzfffzfzf}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}fzfzfffyfyfffwfwfffrfrfffefefffffggWWL L ooJJ]]xx{{8$8$QaQaggOfOffftftfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}f|f|f|f|f{f{f~f~f{f{f}f}f{f{f}f}f{f{f~f~fzfzf}f}f}f}fzfzfffyfyfffyfyfffzfzf~f~f|f|fzfzfffyfyfffwfwfffsfsfffhfhfff(f(fgg[[ЙЙcczzyyhhFF^^YgYg:f:ffflflfffufufffzfzf~f~fzfzfffzfzf}f}f{f{f}f}f}f}fzfzfffyfyfffzfzf~f~fzfzf~f~f|f|f{f{f~f~fzfzf~f~fzfzfffzfzf}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f~f~fxfxfffmfmfff8f8fZgZg^^IIooyyaaәә [[gg)f)fffififffsfsfffufufffxfxfff{f{f{f{f~f~f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f}f}f{f{f|f|f|f|f}f}f|f|f|f|f|f|f|f|f|f|f|f|f}f}f|f|f|f|f{f{f}f}f|f|f}f}f{f{f}f}f{f{f}f}f{f{fffsfsfffLfLfggNaNa:$:$ ᙒxxzz__ݙݙOOjjQ Q WWggffffjfjfffvfvfffwfwfffxfxfffxfxfffyfyf~f~f}f}fyfyfffyfyf~f~f|f|f|f|f{f{fffxfxfffufufffyfyf}f}f}f}f{f{f|f|f~f~fzfzf}f}f|f|f|f|f}f}f{f{f}f}f{f{f}f}f|f|f|f|f{f{fffufufffafafffZcZc,,ˁ^^zz\\99qqSSggffffhfhfffvfvfffyfyfffxfxfffxfxfffzfzf~f~f{f{f{f{f~f~fzfzfffyfyfffzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~f{f{f}f}f|f|f{f{f~f~fzfzfffyfyfffzfzf}f}f}f}fzfzfffyfyfffzfzffftftfffdd}4}4kkӥ%%zzxxZZGGNNgg f fffkfkfffvfvfffyfyf}f}f}f}f{f{f}f}f{f{f~f~f{f{f}f}f{f{f}f}f{f{fffyfyf~f~f{f{f}f}f|f|f}f}fzfzf~f~f{f{f}f}f}f}fyfyfffzfzf~f~f|f|fzfzfffyfyfffxfxfffwfwfffxfxfffxfxffftftfffpfpfff;;۰蘱rrzz``ؙؙnnee~~HHogog1f1fffmfmfffxfxfffzfzf~f~fzfzfffyfyfff{f{f{f{fffxfxfffwfwfffxfxfffzfzfffyfyfffzfzf}f}f}f}f{f{f~f~fyfyfffyfyfffzfzf|f|f~f~fzfzf~f~f{f{f}f}f{f{f}f}fzfzfffwfwfffnfnfffGfGfffBBAAřřhhzz||hhƙƙDD}}BBffKfKfffrfrfffzfzf~f~fzfzf~f~fzfzf~f~f{f{f|f|f}f}f{f{f}f}f{f{f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzf~f~fzfzfffzfzf~f~fzfzf}f}f|f|f~f~fyfyfffwfwfffxfxfffufufffjfjfff/f/fpgpgHHddooؙؙ^^tt}}ss阯;;ffqfqfffzfzf}f}fzfzfffzfzf}f}f~f~fxfxfffzfzf}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzf}f}f~f~fyfyfffxfxfff{f{f}f}f|f|f{f{f}f}f|f|f|f|f~f~fxfxffftftfffififff!f!fggNNIIߙߙ]]ww||}}~~ww##jj44ddffrfrfff{f{f|f|f{f{fffwfwfffvfvfffyfyf~f~f{f{f}f}f{f{f~f~fyfyfffzfzf~f~f{f{f}f}f{f{f}f}f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{f~f~fyfyfffufufffrfrfffnfnfffcfcfffffggSSss88\\xx~~^^ˇˑ,,]c]cff^f^fffsfsfff|f|f{f{f}f}f|f|f|f|f|f|f}f}f{f{f|f|f}f}f{f{f}f}f|f|f|f|f{f{f~f~fzfzfffyfyfffzfzf~f~fzfzfffxfxfffvfvfffyfyf}f}f}f}f{f{f|f|f~f~fyfyfff{f{f{f{fffzfzf{f{fffkfkfff f fggWWM M ooII[[xxxx<$<$NaNaggPfPffftftfffyfyf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f|f|fzfzfffxfxfff|f|fzfzfffyfyfff{f{f}f}f{f{f|f|f}f}f|f|f}f}f|f|fzfzfffzfzf~f~f{f{f}f}fzfzffftftfffjfjfff+f+fgg[[ ҙҙcc{{{{ooDD^^[g[g8f8ffflflfffvfvfffxfxfffzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f|f|f{f{fffxfxfffxfxf~f~f{f{f~f~fzfzfffyfyf~f~f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fyfyfffvfvfffofofff;f;fYgYg^^FFppzzff̙̙[[gg*f*fffkfkfffufufffufufffwfwfff{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}fzfzfffzfzf~f~f{f{f}f}f{f{f~f~f{f{f|f|f~f~fyfyfffyfyf~f~f{f{f|f|f}f}f|f|f|f|f|f|f|f|f|f|f}f}f{f{f}f}f~f~fufufffPfPfggQaQa9$9$噎||||vv\\JJppK K WWgg!f!fffgfgfffrfrfffyfyf|f|f~f~fzfzfffyfyf~f~f{f{f~f~fzfzf~f~fzfzf~f~f|f|f{f{f}f}f|f|f|f|f}f}f|f|f|f|f{f{fffxfxfffxfxfffxfxfffyfyf~f~f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f~f~fxfxfffbfbfffYcYc,,˃``~~zzYY33vvSSggffffefefffufufff{f{f|f|f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fyfyfff{f{f|f|f}f}f|f|fzfzfffvfvfffxfxfffzfzf}f}f}f}f{f{f}f}f|f|fzfzfffyfyf~f~f{f{f}f}fzfzfffzfzf~f~f{f{f~f~ftftfffdd|4|4mmӢ((yy~~{{\\EENNgg f fffhfhfffsfsfffwfwfffxfxfffyfyfffxfxfffzfzf|f|f~f~fyfyfff{f{f|f|f}f}f{f{f|f|f}f}f}f}fyfyfffvfvfffzfzf}f}f|f|f|f|f{f{f~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{fffvfvfffpfpfff;;۱瘲ppxxbbԙԙqqccHHogog0f0ffflflfffsfsfffsfsffftftfffxfxf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{f~f~fzfzfffyfyfffyfyfffzfzf~f~f{f{f|f|f|f|f}f}f{f{f}f}f|f|f{f{fffxfxfffyfyfffxfxfffpfpfffHfHfffBB??řřggzz||iięęAABBffGfGfffnfnfffyfyfffzfzf}f}f|f|f{f{fffyfyf~f~f|f|f{f{f~f~fzfzf~f~f{f{f~f~fzfzf~f~fzfzfffzfzf}f}f}f}fyfyfffwfwfffyfyfffzfzf~f~f{f{f|f|f}f}f{f{f}f}f}f}fzfzfffwfwffftftfffkfkfff0f0fogogHH}}ffnn֙֙bbzzss昳;;ffofoffftftfffxfxf~f~f}f}fzfzf~f~f{f{f|f|f~f~fyfyfffzfzf~f~f{f{f|f|f}f}f{f{f~f~fzfzfffyfyfffxfxfff{f{f}f}f|f|f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f|f|f}f}f{f{f~f~fxfxffflflfff"f"fggNNDDZZxxxx%%nn{4{4ddffufuf~f~f{f{f~f~fyfyfffyfyf~f~f|f|f{f{f~f~fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f}f}fzfzfffxfxfffyfyf}f}f~f~fyfyfffzfzf}f}f}f}fzfzfffxfxfffvfvffftftfffififffffggSSvv33VVuu}}`` ˆ˓,,\c\cff`f`fffxfxf~f~f{f{f~f~fyfyfffzfzf~f~fzfzf~f~f{f{f}f}f{f{f~f~fyfyfffyfyf~f~f|f|f{f{f~f~fzfzf~f~f{f{f|f|f~f~fzfzf~f~fzfzf~f~f{f{f~f~fyfyfffzfzf~f~f{f{f}f}f{f{fffwfwfffpfpfff`f`fffffggWWJ J qqII]]zz}}>$>$LaLaggMfMfffofofffufufffyfyfffyfyfffzfzf}f}f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fyfyfffxfxfffxfxfffxfxfffzfzf}f}f|f|f}f}fzfzfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f|f|f{f{fffofofff0f0fgg[[~~ љљdd||||llII^^YgYg9f9fffmfmfffwfwfff{f{f|f|f|f|f}f}f{f{f~f~fzfzf~f~fzfzfffyfyfffzfzf~f~f{f{f|f|f}f}f|f|f|f|f|f|f|f|f|f|f}f}f|f|f{f{f~f~fzfzf}f}f}f}f{f{f}f}f|f|f{f{f~f~fzfzfffxfxfffufufffmfmfff;f;fXgXg^^HHll}}xx__ԙԙ [[gg*f*fffkfkfffufufffwfwfffvfvfffxfxfffzfzf}f}f|f|f{f{fffxfxfffwfwfffzfzf~f~fzfzf~f~fzfzf~f~f|f|f|f|f|f|f|f|f|f|f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fzfzf~f~fzfzfffxfxfffpfpfffKfKfggMaMa;$;$噎||{{xxtt]]ޙޙOOjjP P WWggffffhfhfffvfvfffzfzf}f}f|f|f{f{fffxfxfffxfxfff{f{f{f{fffyfyfffzfzf~f~f{f{f}f}fzfzfffzfzf~f~fzfzf~f~fzfzf~f~f{f{f}f}f|f|f|f|f{f{fffyfyfffzfzf}f}f}f}f{f{f|f|f~f~fxfxfffdfdfff^c^c,,˄__}}}}ww[[77ttSSggffffhfhfffvfvfffyfyfff{f{f|f|f}f}f{f{f}f}f{f{f~f~fzfzfffyfyf~f~f{f{f|f|f~f~fzfzf~f~fzfzf}f}f}f}f{f{f~f~fyfyfffzfzf~f~f|f|f{f{f~f~fyfyfffyfyfff{f{f|f|f|f|f}f}f{f{f~f~fzfzfffufufffdd{4{4mmӣ''zz~~xx]]HHNNggffffgfgfffrfrfffwfwfff|f|fzfzf~f~f|f|f|f|f|f|f|f|f|f|f}f}f|f|f|f|f|f|f|f|f|f|f~f~fzfzf~f~fyfyfffyfyfffzfzf}f}f{f{f~f~fzfzfffzfzf}f}f|f|f}f}f{f{f}f}f|f|f|f|f|f|f~f~fxfxfffufufffpfpfff;;۱瘳oo~~xxaaԙԙss``HHpgpg0f0fffjfjfffrfrfffwfwfff{f{f|f|f}f}f{f{f}f}f|f|f{f{fffxfxfffwfwfffyfyf~f~f{f{f|f|f}f}f|f|f|f|f}f}f{f{f|f|f~f~fyfyfffzfzf|f|f}f}f{f{f}f}f}f}fzfzf~f~f{f{f}f}f{f{f~f~fxfxfffofofffIfIfffBB~~CCǙǙggzz||iiƙƙFFzzBBffIfIfffofofffxfxfffzfzf~f~f|f|fzfzf~f~f{f{f}f}f|f|f{f{f~f~fzfzfffyfyfffzfzf}f}f|f|f|f|f~f~fyfyfffyfyfffyfyf~f~f|f|f{f{f~f~fzfzf~f~f|f|f{f{f~f~fyfyfffxfxfffwfwfffvfvfffmfmfff/f/fqgqgHHaarrԙԙcczz~~pp嘴;;ffofoffftftfffyfyfff{f{f{f{f~f~f{f{f|f|f}f}f|f|f{f{f~f~fzfzf~f~f|f|f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzfffyfyfffyfyfffxfxfffwfwfffzfzf~f~fzfzfffxfxfffufufffsfsfffhfhfff!f!fggNNEE]]zz{{''nnz4z4ddffwfwf|f|f~f~fzfzf~f~fyfyfffyfyfffyfyfffzfzf~f~f{f{f|f|f}f}f|f|f|f|f}f}fzfzfffyfyfff{f{f|f|f}f}fzfzf~f~f|f|f|f|f|f|f|f|f|f|f}f}f{f{f}f}f{f{fffyfyf~f~f{f{f}f}f{f{fffvfvfffhfhfffffggSSqq88]]{{\\ˁ˖,,\c\cffefefffyfyf~f~fzfzf~f~f{f{f}f}f|f|f|f|f{f{fffyfyfffzfzf}f}f|f|f}f}f{f{f}f}f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}fzfzfffxfxfffyfyf~f~f{f{f}f}f}f}fzfzf~f~f{f{f{f{fffkfkfff f fggWWK K ppJJ\\ww~~~~yy<$<$KaKaggKfKfffqfqfffzfzf}f}f}f}f{f{f}f}f{f{f}f}f}f}f{f{f|f|f}f}fzfzfffxfxfffzfzf~f~fzfzfffyfyfffyfyfffyfyf~f~f|f|fzfzfff{f{f{f{fffwfwfffyfyf}f}f}f}fzfzfffwfwffftftfffgfgfff&f&fgg[[ ЙЙcczznnKK^^ZgZg9f9fffnfnfffyfyf|f|f~f~f|f|f|f|f|f|f{f{f}f}f}f}f|f|f{f{f~f~fyfyfff{f{f|f|f}f}f{f{f}f}f{f{f~f~fzfzfffyfyfffzfzf}f}f}f}fzfzfffyfyfffzfzf~f~fzfzf~f~fzfzfffwfwfffufufffofofff:f:fZgZg^^IIffyy}}wwccϙϙ [[gg(f(fffififffvfvfffyfyfffyfyfff{f{f|f|f|f|f}f}f{f{f~f~fzfzf}f}f}f}f{f{f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f|f|f{f{f~f~f{f{f|f|f~f~fyfyfffyfyfffxfxfffyfyfffxfxfffqfqfffOfOfggQaQa8$8$!!ᙒxx{{aaܙܙPPjjO O WWgg f fffgfgfffrfrfffwfwfffzfzf~f~fzfzfffyfyf~f~f|f|f{f{f~f~fzfzf~f~f|f|fzfzfffyfyfffyfyf~f~f{f{f|f|f}f}f{f{f~f~fzfzf~f~fzfzf~f~f|f|f{f{f~f~fyfyfffyfyf~f~f{f{f}f}f|f|f|f|f{f{fffffffff]c]c,,˄aa}}ttWW55uuSSggffffgfgfffvfvf~f~f}f}f{f{f}f}f|f|f|f|f|f|f}f}f|f|f{f{fffwfwfffufufffvfvfffxfxfffwfwfffyfyf}f}f}f}f{f{f}f}f}f}fzfzfffzfzf}f}f|f|f|f|f}f}f{f{f~f~fzfzf}f}f}f}fzfzfffzfzf}f}fxfxfffddz4z4mmӤ''||~~xxYYBB""NNggffffefefffsfsfffyfyf~f~f{f{f}f}fzfzfffzfzf~f~f{f{f|f|f|f|f}f}f{f{f}f}f}f}fzfzf~f~f{f{f|f|f~f~fzfzf~f~fzfzfffyfyfffzfzf}f}f}f}f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}fzfzffftftfffnfnfff;;ۯ阱qq}}vv]]ٙٙnnccHHrgrg.f.ffflflfffwfwfffzfzf}f}f|f|f}f}fzfzf~f~f|f|f{f{f~f~fzfzf}f}f~f~fxfxfffvfvfffvfvfffzfzf|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}f{f{f}f}f}f}fyfyfffyfyf~f~f{f{f~f~fyfyfffufufffnfnfffIfIfffBB{{FFǙǙhh{{~~kkÙÙBB}}BBffMfMffftftfff|f|f{f{f}f}f|f|f|f|f}f}fzfzfffyfyfffzfzf}f}f}f}fzfzfffyfyfff{f{f{f{f~f~f{f{f}f}f|f|f{f{f}f}f|f|f}f}f{f{f|f|f}f}f{f{f~f~fzfzf~f~fzfzfffzfzf}f}f|f|f{f{fffxfxffflflfff/f/fpgpgHHeennיי``xx~~~~~~nn;;ffqfqfffufufffxfxf~f~f}f}fzfzf~f~f|f|fzfzfff{f{f{f{fffxfxfffzfzf}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzfffyfyf~f~f{f{f}f}f}f}fyfyfffxfxfffwfwffftftfffffffffffggNNGG]]vv~~xx""jj~4~4ddffsfsfffyfyfffzfzf~f~f{f{f{f{f~f~f{f{f~f~fzfzf}f}f|f|f{f{fffxfxfffxfxfff|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~f{f{f}f}fzfzfffxfxfffxfxfffwfwfffgfgfffffggSSuu55WWtt^^˂˕,,\c\cffafafffqfqffftftfffxfxfffzfzf~f~f{f{f}f}fzfzfff{f{f|f|f}f}fzfzf~f~f|f|f|f|f}f}fzfzf~f~f{f{f}f}f|f|f}f}fzfzfffyfyfffzfzfffyfyf~f~f{f{f}f}f|f|f}f}fyfyfffvfvfffufufffkfkfff"f"fggWWL L ooJJ\\yyyy;$;$MaMaggLfLfffpfpfffwfwfffxfxfffzfzf}f}f}f}f|f|f{f{f~f~fyfyfff{f{f|f|f}f}fzfzf~f~f|f|f{f{f}f}f|f|f{f{f~f~f{f{f|f|f}f}f{f{f~f~fzfzfffxfxfffzfzf~f~fzfzf~f~fzfzfffyfyfffxfxfffmfmfff-f-fgg[[ ϙϙee}}~~nnII^^XgXg;f;fffmfmfffvfvfff}f}fyfyfff{f{f|f|f}f}f{f{f|f|fffxfxfffyfyf}f}f~f~fzfzf~f~fzfzf~f~f{f{f}f}f}f}fzfzf~f~f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzfffyfyfffyfyfffwfwfffmfmfff;f;fXgXg^^JJmm}}{{ddϙϙ [[gg,f,ffflflfffxfxf~f~f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fzfzf}f}f|f|f|f|f|f|f}f}f{f{f~f~fzfzf}f}f|f|f}f}f{f{f~f~fyfyfff{f{f|f|f|f|f|f|f}f}fzfzfffwfwfffufufffpfpfffLfLfggQaQa7$7$""ᙐ||zz^^KKnnN N WWggffffdfdfffqfqfffvfvfffyfyfffzfzf~f~fzfzfffxfxfffxfxfff{f{f{f{f~f~f{f{f|f|f}f}f{f{f}f}f}f}fzfzf~f~f{f{f|f|f~f~fzfzf}f}f|f|f|f|f|f|f}f}f{f{f}f}f|f|f|f|f|f|f|f|f}f}f}f}fxfxfffafafffZcZc,,˄``}}||xx[[55wwSSggffffhfhffftftfffvfvfffxfxf~f~f{f{f|f|f~f~fzfzf~f~fzfzf}f}f}f}f|f|f{f{f}f}f{f{f~f~f{f{f}f}f{f{f|f|f}f}f|f|f|f|f}f}fzfzfffyfyfffzfzf~f~f{f{f}f}fzfzfffxfxfffyfyfffyfyfffzfzfzfzfffddz4z4kkӧ""vv~~zz^^ߙߙIINNggffffkfkfffyfyf~f~fzfzfffyfyfffzfzf~f~f{f{f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fzfzf~f~f{f{f}f}f{f{f}f}f|f|f|f|f}f}f{f{f|f|f}f}f{f{f~f~fzfzfffxfxfffwfwffftftfff;;۲瘲ppzz}}{{bbՙՙqqaaHHpgpg0f0fffnfnfffvfvfffvfvfffvfvfffzfzf}f}f|f|f|f|f}f}f{f{f}f}f|f|f{f{f~f~f{f{f}f}f|f|f{f{f~f~fzfzf~f~f|f|fzfzfffxfxfff{f{f|f|f~f~fyfyfffzfzfffyfyfffyfyfff{f{f}f}fyfyfffpfpfffJfJfffBB~~AAęęiizz}}wwbb˙˙EE}}BBffJfJfffpfpfffvfvfffxfxfff{f{f}f}fzfzfffyfyfffzfzf~f~f{f{f|f|f|f|f|f|f}f}f|f|f{f{f~f~fzfzf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f~f~fyfyfffzfzf}f}f}f}f{f{f|f|f~f~fxfxfffufufffjfjfff1f1fmgmgHH{{ggnnיי__xx~~~~rr蘰;;ffofofffufufffxfxfffyfyf~f~f|f|fzfzfffyfyf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f|f|f|f|f}f}fzfzfffzfzf~f~fzfzfffxfxffftftfffififff"f"fggNNHH]]xx~~~~~~{{$$ii~4~4ddffwfwfzfzfffxfxfffzfzf|f|f}f}f{f{f~f~f{f{f|f|f}f}f{f{f}f}f|f|f|f|f|f|f}f}f{f{f}f}f{f{f}f}f}f}fzfzf~f~fzfzfffyfyfffyfyfffzfzf~f~fzfzf~f~fzfzfffyfyfffxfxfffxfxfffsfsfffdfdfffffggSStt77ZZxx^^˃˕,,[c[cffdfdfffzfzf{f{fffxfxfffxfxfffzfzf}f}f|f|f|f|f|f|f|f|f|f|f}f}fzfzfffyfyfffzfzf~f~f{f{f}f}f{f{f}f}f|f|f|f|f}f}f{f{f}f}f{f{f~f~fzfzf~f~f{f{f|f|f}f}f|f|f{f{fffwfwfffsfsfffffffffffggWWN N ooHHXXtt}}~~{{9$9$PaPaggMfMfffrfrfffyfyf~f~f{f{f|f|f}f}f{f{fffxfxfffyfyf~f~f}f}fyfyfffzfzfffyfyfffwfwfffyfyf~f~f{f{f}f}f{f{f~f~fzfzf~f~f{f{f}f}f{f{f}f}f{f{f~f~f{f{f|f|f|f|f}f}f{f{fffwfwfffnfnfff.f.fgg[[֙֙]]yy||nnJJ^^VgVg;f;fffkfkffftftfffxfxfffyfyfffzfzf|f|f~f~fzfzfffzfzf}f}f{f{f~f~f{f{f}f}f|f|f|f|f{f{fffyfyf~f~f|f|f{f{f~f~f{f{f{f{f~f~f{f{f}f}f|f|f{f{f~f~fzfzfffzfzf}f}f|f|f}f}fyfyfffmfmfff7f7f]g]g^^EEmm}}ccҙҙ~~[[gg-f-fffkfkffftftfffwfwfff|f|f{f{f}f}f|f|f{f{f~f~f{f{f}f}f|f|f{f{f}f}f|f|f|f|f~f~fyfyfffzfzf}f}f~f~fyfyfffwfwfffyfyf~f~f|f|f{f{f}f}f|f|f{f{f~f~f{f{f}f}f|f|f{f{f~f~fyfyfffqfqfffKfKfggNaNa:$:$㙏||~~xx\\LLllP P WWggffffhfhfffsfsfffvfvfffyfyf~f~f{f{f|f|f}f}f{f{f}f}f}f}fzfzf~f~fzfzf~f~f{f{f}f}f|f|f|f|f|f|f}f}fzfzfffzfzfffyfyfffyfyfff{f{f}f}f{f{f}f}f{f{f~f~f{f{f|f|f}f}f{f{f}f}f}f}fyfyfffdfdfffZcZc,,[[||]]88ttelektroid-3.2.3/test/res/connectors/square.wav000066400000000000000000002736541500236517400214710ustar00rootroot00000000000000RIFFwWAVEfmt wJUNK4smpl<aQ0datawSgffhffuff{f|f}f{f|f}f|f|f|f{ffyffzf~f{f|f}f{f~fzf~f{f|f}fzffxffxffyffzf~f{f|f}f{ffyffuffd|4lӤ&{{^GNg ffgfftffxffwffyf}f}fzffzf~fzf~f{f}f|f{f~fzf~f{f}f{f~fzf~f|fzffxffyffyffxffxffvffrffnff;۱昴o}zcԙqbHqg.ffkffxffyffzf}f}f{f}f|f{f~fyffzf}f|f|fzffyffzf}fzffxffyf}f}f{f}f{f~fzffyffyffvffpffJffBCǙew{}xhęB~BfJffpffwffyffxffyf~f|f|f|f}f{f}f|f|f|f}f{f}f|f{f~f{f}f{f~fyffyf~f{f}f{f~fzf}f|f|f}f}fwffhff+frgH~epԙdz|}}~~s昳;fqffwff{f|f}f{f}f|f|f}fzf~f{f}f|f|f|f|f}f{f}f|f{ffyffzf|f~fzffyffyffzf}f|f|f|f}fyffqffdfffgNH^z{%iӀ4dfrffwffyf}f}f{f}f{f}f{ffyf~f{f|f~fyffxffzf~f|fzffxffyf~fzf~f{f}f|f|f|f|f~fxffuffrffgfffgSu7^{_˖,Zcfaffwf~f|f|f}f{f~fyff{f|f~fyf~f|f|f}f{f}f{f~fzf~f{f|f~fyffxffzf|f~fzf}f}fzffyffxffsffgfffgWL pHZt}=$NagNffrff{f{f~f{f|f~fyffxffzf}f|f{f~f{f}f{f}f{f~f{f|f}fzffxff{f|f~fyff{f|f~fxffuffrffjff)fg[ ҙcz~lH^Zg:ffnffxf~f|f|f|f|f|f}f|f|f|f{ffyffzf}f}f{f}f{f}f|f}f{f}f{f}f|f|f}f{f|f}f{ffxffxfftffiff5f\g^Hn|}y`ԙ[g'ffiffuffxffyffzf}f|f|f|f}f|f|f{f~fzffyf~f{f~fyffxffwffzf}f}f{f|f~fxffvffwffwffrffLfgMa:$!ᙑz~~y[KnN Wgffefftff|fzffzf}f|f|f|f}f{f}f|f|f|f|f~fyffwffxf~f|fzffyffyffzf~f|fzffwffwffxffxffdffZc,\}{x\7tSgffifftffxf~f|f}fzffyffyf~f{f}f|f}fzffyffxffxffyf~f{f}f|f{f~fzffzf}f|f|f|f~fyffzf}f}fvffd|4jӦ%zuYFNg!ffjffxf}f~fxffxff{f{ffyffyffzffzf|f~fzf~f|fzffxffyf~f{f}f|f|f|f|f}f{f~fzf~f{f}f{f~fxffrff;۳嘵n~{dԙpdHrg.ffmffyf~f{f}f{f~fzf~f{f}f{f}f{f~f{f|f|f|f}f|f|f|f|f}f{f~fzf~f{f|f~fzf~f{f|f}f{f}f}fzffxffsffLffB?™j||hƙBBfHffoffyf~fzffyffzf}f|f}fzf~fzffzf~fzf}f}f{f~fzf~fzf~fzffyffzf}f|f{f~f|f{f~fzf~fzffvffkff/fqgHcoי`z{l㘴;fofftffzf}f|f}fzf~f|f{ffxff{f|f~fyffwffyf~f|f{f}f|f|f|f}f{f}f|f{ffxffyff{f{f~fyfftffhff fgNH[v}z$l|4dfrffzf}f}fyff{f|f}f{f|f~fzf~f{f|f}f{f~fzf~fzffyffzf~f{f|f}f{f}f}fyffyf~f{f~fxfftffsffhfffgSt7[y]˗,[cfbffvffyf~fzffyff{f|f}f{f}f|f|f}f{f}f|f{f~fzffyf~f|f{f~fzf}f}fzffyf~f|f{f~fzffxfftffhfffgWM nLߙ^yz=$JagJffrffzf~fzffyffzf}f}fzf~f|f{f~fyff{f}f{f}f{f~fzf~f{f}f|f|f{f~fzffwffwffyffxfftffjff)fg[ әazzkI^Wg;ffoffxf}f}f|f|f|f{f~f{f}f{f}f{ffyf~f{f|f~f{f{f~f{f|f~fyf~f}fyffzf|f}f|f{ffxffyffwffmff9fYg^Im|~~zt]ՙ [g+ffjffsffyffzf~fyff{f}f{f}f{f~f{f}fzffzf~f{f|f}f|f|f}fzf~f|f{ffyf~f{f}f|f|f}fzffvffoffJfgKa=$㙒x}w]LlP Wgffgffvffzf~f{f|f~fzf}f|f|f|f~fyffzf}f}f{f|f}f{f~fzf~fzf~f|fzffxff{f|f}f{f~fzf}f}fzfftff^ffXc,_x[6tSgfffffrfftffxf}f}f|f{f~f{f|f|f~fyffyf}f}f{f~fzf}f|f|f}f{f~fyffwffwffzf|f}f|f|f}fzffyffrffd|4mӢ({}uZENgffeffrffvffzf|f~f{f|f}f{f}f|f|f|f}f{f}f{f~fzf}f}f{f}f{f|f~fzf~fzf~f|f|f|f}fzffzf~f{f|f}fzffsff;ۯ蘳n|{bՙpcHpg.ffiffsffyf~fzffzf}f}fyffzf}f|f{f}f}f{f}f{f}f|f}fzf~f|f{f~fyff{f}f{f|f}f|f|f|f|f|ffvffmffGffBBǙh~ygǙC}BfMffsffyffyffzf~f{f|f}f{f}f|f|f|f|f}f{f~fzf}f}f{f~fzf}f|f}f{f~fyffzf~f|fzffzf}f}fyfftffiff-ftgH`rՙ`x|p䘵;fqffuffxffzf~fzffyffzf~fzffzf|f}f{f~f{f|f|f}f{f}f{f~fzf~fzf~f{f}f{f}f|f|f|f|f|f~fyffufflff%fgNG^x}z%k}4dfqffwff{f{f~f{f|f}f|f{f~f{f|f}f{f}f|f|f|f}f{f}f|f|f|f}f{f}f|f|f{ffyffzf~fzffwffxffvffhfffgSu7]}^˗,Ycf_ffvffzf}f}fzffzf}f|f|f|f}f|f|f{f~fzffzf}f|f}f{f}f|f{ffxffyffyffwffvffvffwffuffgfffgWN mK\v~~~}@$JagLffqffxf~f|f{f}f|f|f}f{f}f{f~f{f}f{f}f|f}f{f|f}f|f{ffxffzf}f|f}fzffyffxffyffyfftffjff,fg[ әa|{jD^Zg:ffnffuffwffzf}f}fzf~f{f}f|f|f}f{f}f{f}f|f}f{f|f}f{f~f{f}fzffzf~f|fzf~f|f|f|f}fzffwffnff;fXg^Dm|zbљ [g(ffhffuffyf~f{f}f{f~fzffyffzf~fzffyffzf}f}fzf~f{f}f|f|f|f}f{f}f{f~f{f|f}fzffzffwffpffLfgNa;$䙎}y\JoN Wgffiffvffwffwffzf}f|f|f|f|f}f{f}f|f{f~f{f|f~fzf}f|f}f|f|f{f}f}f{f}f{f}f|f|f|f}f{f~fxffsff]ffXc,]~xZ8rSgffeffpfftffyf~f{f}f{f}f|f|f|f}f{f}f|f{f~f{f|f~fyffzf}f~fyf~f|f{f~f{f|f}f{f}f}fzffxffyf~fvffd|4kӥ&{~x^FNgffjffwffyf~f|f{f}f|f|f}f{f}f{f~fzf~f{f|f}f{f~fzf~f{f}f|f{f~fzffyffyffzffxffyff{f{ffwffoff;۲嘴n}|b֙nf}Hmg1ffkffsffxf}f}f{f}f|f}fzffzf}f}fzffzf}f|f|f|f~fyff{f|f}f{f~fzf~f{f|f}f{f}f|f|f|f|f}fzffrffKffB{Gəd{}gǙD~BfGffoffyf~f{f|f}fzffyf}f~fxffyf~f{f|f}f|f{f~fyffyf~f{f}f|f|f|f}f{f~fzf}f}f{f~fxffwffsffhff-fpgH~dpԙdz~~r瘱;fnfftffxffzf}f|f{f~f{f}f{f~fyffzf|f~fyff{f}f{f}f{f~f{f|f}f{f}f|f{ffxffyf~f|fzffwffrffefffgNIߙ^y~{(ru4dfvf}f}f{f}f|f|f{ffxffzf}f|f{f~f|f{f}f{f}f}fzffyffzf~fzffyffzf}f|f|f}f{f}f|f{ffxfftffiff fgSw4[z^˖,Ycfbffzf|f|f}f{f}f{f}f|f}fzffyf~f|f{ffyf~f{f}f|f}fzffzf~fzf~f{f}f|f{f~fzffyffwffvfftffgfffgWJ qI^y{<$NagNffqffvffzf~fzf~fzffzf}f|f|f}f{f}f{f~fzf~f{f|f}f{f}f|f|f|f}f{f}f|f|f|f|f|f}f{f~fxffsffjff,fg[ ϙe{mG^Xg;ffmffwffyffyffzf~fzf~f|f{f}f|f|f}f{f}f|f|f|f|f}f|f{f~fzf~f|f{f~fzf~f{f}f{f}f|f|f}fxffofffUg^Hq{bҙ}[g0ffoffvffwffyff{f|f}fzffzf~f{f|f}f{f~fzf~f{f}f{f}f|f{ffxffzf}f|f|f|f}f|f{f~fzffyfftffMfgKa>$晎|y^ޙNkP Wgffeffpffuffxff{f}f{f}f{f~f{f}f{f}f|f|f|f}f{f~fyffyf~f|fzffxffyf}f}f{f~fzf~fyffvffrff^ffYc,]}uX5vSgffifftffuffwffxffxffzf}f|f|f|f}f|f{f~fzf~f|fzffxff{f|f|f}f|f{f~fzf}f}f{f}f}fzf}f~fxffpffd}4jӦ$zy^FNgffffftffyffzf~fzf}f|f}f{f~fyffzffxffwffyf}f}fzffyffyffyf~f{f|f}f}fzffyffzf~fzffxffrff;۱蘰s{t]ٙmeHrg.fflffwffxffwffyf}f}fzffzf~f{f|f}f{f}f}fzffyffzf~fzffyffyffzf}f|f|f|f}fzffxffuffnffMffB{DǙg}|fșCBfLfftffyffzf~f{f|f}f|f{ffxffyffzf}f{f~f{f|f}f{f}f|f{ffyffzf}f}fzffzf}f|f{ffyf~f}fvffeff)ftgHdoי`y}~|q꘮;fsffxffzf~f{f|f~fyffyf}f}f{f}f|f{f~fzffzf}f{ffxffxff{f|f}f|f|f}fzffzf~f{f|f}f|fzffuffiff!fgN D\yv!l{4dfuff{f}f{f}f|f{f~f{f}f|f{f}f}f{f}f|fzffyf~f{f|f|f}f|f|f|f|f|f}f|f|f|f|f}f|f|f|f|f}f{ffvffhfffgSv4Wv~_ˑ,_cfcffxf~f{f}f|f{f~f{f}f{f}f{f}f|f|f|f}f{f|f}f|f|f}f{f|f~fzffyffzf}f}f{f|f~fxffuffvfftffifffgWP mK^{x<$MagMffrffxffyffzf}f|f|f}f{f}f|f{f~fzf~f{f}fzffwffwff|fzffxffyffzf}f|f}f{f}f|f{ffwfflff*fg[ ҙbz}mF^[g7ffjffuffwffxffyf~f|fzffxffyf~fzffwffyf}f~fyff{f{ffyffzf}f|f|f|f}fzffzf}f~fvffkff8fZg^Gm~{cљ [g(ffiffvff{f|f~fyff{f|f}f{f}f}fzf~f{f}f|f|f{f~f{f}f|f{f~fzf~f{f}f|f|f|f|f}f|f{f~fzffxffpffJfgMa<$㙒w~~v[MmM Wg"ffjffvffzf~fzf~fzffyffzf~fzf~f{f}f|f{f}f}fzf~f{f|f~fyffyf~f{f}f|f|f|f|f}f{f}f{f~fzffxffdff\c, b~}zZ5wSgffhffuffxffyffzf}f|f}fzffyffzf~fzffyffzf~fzffyffzf}f|f}f{f}f{f}f}fzffzf}f|f|f|f}f}ftffd4iӦ%z~~x\ENgffhffvffzf}f|f|f|f}f|f|f|f|f}f{f~fyffxffyffyffzf~f{f|f}f|f{f~fzffyffxffwffyf~f{f~fxffpff;۳昱s{b֙oe~Hng2fflffuffxffyffyffzf}f|f}f{f}f|f|f}fzf~f{f}f|f{f~fzf~f{f}f|f|f|f|f}f{f~fzf~f{f}f{f~fyffrffNffB~Břgz~}fʙIyBfJffpffxf~f|f{f~f{f}f|f{f}f|f}f{f|f~fyffxffyf~f{f~fyffxffzf}f|f{ffxffxffzf}f|f|ffuffkff1fmgH~fmٙ]v~s蘱;fpffvff|f|f|f}f{f|f}f|f|f}fzf~f{f}f|f|f|f|f|f}f{f}f|f{f}f}fzffyf~f|f{f~fzf~f{f}fzffwfftffifffgNF[xz$i4dfuf}f~fzf~fzf~f{f~fzf~fzf~f|f|f|f|f|f}f|f|f|f|f}f|f{f~fzf~f|fzffzf}f}fyffzf}f|f{f~fzffuffefffgSu5Zx]˓,]cfbffvff|f{f~fzffyffzf}f}f{f~fzf~fzffzf}f|f|f|f}fzffyffyff{f}f{f|f}f}f{f}fzffzf~fyfflff fgWO mL\w|~x<$MagLffqffvffyf}f~fyf~f|f{ffxffyf~f|f{f}f}fyffvffxf~f|f|f|f}fzffyffxffzffyffwffvffmff/fg[}ԙ_w~oE^Xg=ffpffxf~f|f}f{f}f{f~fzffyf~f}fzf~f{f|f}f|f|f|f}f{f}f|f|f|f~fyffyffyffyf~f{f~fzffxffoff;fYg^Ckz~xaҙ~[g-fflffwff{f|f}f{f}f|f|f|f|f|f}f|f|f|f|f}f{f~fzf~f|f{f}f|f|f}f{f}f{f~f{f|f}f|f{f~fzf~f{ffuffOfgNa;$㙑yw[KmN Wg ffgffsffyf}f}f{f}f|f|f|f}f{f}f|f|f}f{f}fzff{f|f|f}fzffwffzf|f}fzff{f|f|f|f}f|f|f{ffwffaffYc,_wX4uSgffgffrffwf~f}f{f|f~fyff{f{f~f{f|f~fyf~f|f|f|f}fzffzf~fzffyffzf~f|fzffyff{f|f}fzffyfftffd{4lӤ%xy^ߙINgffhffsffxf}f~fyffyffyf~f|f|f}f{f}fzffvffwffzf~fzf~fzffyffyf}f}fzffyf}f}fzffzf}f}fxffnf f;ۯ蘱s|fљu^Htg-ffkffuffxffzf}f}fzf~f{f}f|f|f|f}f{f}f|f}f{f~fyffxffzf|f~fyff{f}f{f|f}f|f|f|f|f|f}fyffoffGffB}Eədx~}{hƙE|BfIffpffyffyffxff{f}f{f~fzf~f{f}f{f}f{f}f}fzffyffzf}f|f}f{f}f{f}f|f|f}fzffyff{f|f~fwffmff0fngH~enי`yp阯;foffwf~f}f{f|f~fyffyf~f{f}f|f}fzffyff{f|f|f}f{f}f|f{f}f|f|f|f}f{f}f{f}f|f|f}f{f|ffvffqffffffgNJ\w}x$j~4dfuf~f|f{f~fzffyf~f{f}f}fzf~fzffzf}f|f|f|f|f}f{f~fzf}f}f{f~fzf}f|f|f}f{f}f{f}f|f{ffxfftffhfffgSs8]{^˖,Ycf^ffwffzf}f{f~f{f|f}f{f~fzf~f{f}f|f|f}f{f}f{f}f|f|f|f|f|f}f|f{f~f{f|f~fyffzf~fzffwffrffiff"fgWK qGZw}9$PagNffsff{f}f|f}fzf~f{f}f|f{f~fzf~f{f|f~fzf~f{f|f}f|f|f|f|f}f{f}f|f|f}f{f|f}f|f|f{ffwfftffkff+fg[ љby{iK^Vg$㙑xx\LlP Wgffeffrffvff{f{f~f{f|f}f{f|f~fzf}f}fzffyf~f|f|f|f|f|f}f{f}f|f|f|f}fzffzf}f|f|f|f}fzffuff]ffYc,^~{v[9rSgfffffvffxffwffwff{f|f}f|f{f}f|f|f}f{f}f{f~f{f|f~fxffyf}f}fzffzf}f|f|f}f|f|f|f|f}f{f~f|fuffd}4kӥ$vy]HNgffgfftffyffzf}f|f|f}f{f}f|f|f}fzffyffyf~f{f}f{f}f|f|f}fzffxffvffwffzf~fzf~f{f}f{f~fxffqff;۶☷m|zb֙ng|Hmg2ffnffvffwff{f|f}f{f}f|f|f|f}f{f~fzf}f|f}f{f}fzffzffxffyffzf~fyffwffxffzf~f{f}f{ffrffKffB@l{~yhřB~BfKffpffwffxffyf~f{f}f|f{ffyf~f|f{f~f{f|f|f~fzf~fzf~f|f{f~fyffyf~f{f}f|f|f|f|f}f{f}f}fxffiff*fugHcnؙ`}~q蘱;foffsffwffzf}f|f|f}f{f}f|f|f|f}fzffyff{f{f~fzffzf|f~fzf~fzf~f{f}f|f{f~f{f|f~fzf~fzffxfflff"fgNFYv~y%l}4dfsff|f{f}f{f~fzf~f|fzffzf}f~fxffzf}f|f|f|f|f~fyff{f{ffzf|f~fyffyf~f{f}f{f~fyffvfftffjfffgSs7Xs|[˔,]cffff{f}fzffxff{f|f}f|f|f|f|f|f}f}fzf~f{f}f{f}f|f}f{f|f|f}f|f}fzffyffzf~f{f}f{f}f{ffwffkff!fgWJ qI]y|;$NagNfftffzf}f{f~f{f|f}fzffzf}f|f|f}fzf~f{f}f|f|f{ffyffzf}f}f{f}f|f{f~fzffyffyffxffuffkff*fg[Ιez~~ziK^Wg;ffoffwffzf|f}f{f~fzffxffyf~f|f|f|f}fzffzf~f{f|f}f|f{f~fzffzf}f|f{ffyffyffyffuffmff;fWg^Jn}|eЙ}[g*ffkffxf~fzffxffyf~f{f~fzffyffyff{f|f}fzf~f|f{f~fzf~f{f}f{f~fzffxffyffzf}f{ffxffpffLfgMa<$晏zx\JmN Wgffdffqffwff{f}f{f~fzf~f{f}f|f|f|f}f{f~fzf~fzffzf~fzf~f{f}f|f{ffyffzf}f}f{f}f{f~fzffwffaffZc,]{]6wSgfffffuffwffyffzf~f{f|f}f{f~f{f|f|f|f~fyffwffyf~f{f}f|f|f|f}f{f~fzf~f{f|f}f|f|f|f|f}f{ffrffd~4kӣ({~x[HNgffgffuff{f|f}fzffzf}f|f{ffyffzf}f|f}f{f}f|f{f~f{f}fzffwffzf{ffxffzf}f|fzffwffwffvffoff;۵䘴o|}~y^ڙlf~Hpg.ffiffxf}f}fzf~f{f~f{f{f~f{f|f~fyffxffyf~f|f|f|f}fyffwffyf}f|f|f}f|f|f{f~f{f|f}fzffyffqffIffBAșdw}fəGzBfLffpffyf~f{f}fzffzf~f{f}fzffyff{f|f}f{f}f|f|f|f}f{f}f|f{f~fzf~f{f}f{f~fyffzf|f~fxffuffjff.frgHbpי_yq蘯;fqffwffzf}f|f|f|f}f{f}f|f|f|f}f{f}f|f|f|f}f{f~fzf}f|f}f{f}f{f}f}f{f}f{f~fzffzf}f|f|f|f~fxfflff fgNF\y~w#j}4dfvf~f{f}f|f{ffyffzf}f|f|f}f|f{f}f{f~f|f{f|f}f|f}f{f|f~fzffyffzf~f|f{f~fzf~f{f}f|f{ffvffhfffgSt6[{`˕,Zcf`ffwff{f|f}f{f}f|f}fzf~f{f}f}fzf~f{f}f{f~fzf~f{f}f|f|f|f|f}f|f{ffxffwffwffvfftffpffefffgWI sG[x}y<$MagLffqffyf~f|f|f{f~fzffyffzf~f{f|f~fyff{f{ffyf~f}fyffyf~f|f{f}f}fzffyf~f|f{ffwffsffhff(fg[Йcx}kI^Xg:ffmffxffzf~f{f|f~fyff{f|f~fyffzf}f}f{f|f}f{f~f{f{f~f{f}f|f|f|f|f}f{f}f|f|f|f}fzffvffnff$噏|}w^ߙLmO Wgfffffvffzf}f{f~f{f|f}f{f}f}f{f|f~fyffzf|f}f{f}f}fyffxff{f{f~f{f}f{f}f{f~f{f}f{f~fyffwffcff\c,\}wY7tSgffhffuffxffxffwffzf}f}fzf~f{f}f|f{f~fzf~f|f{f}f{f~f{f}f{f|f~fzf~fzf~f{f~fzf~fzf~f|f|f|f}fvffdy4oӢ'z|`ޙINgffjffwffyf~f}fyff{f}f{f~fyffyf~f{f}f|f|f|f|f|f~fzf~fzf}f}f{f~fyffzf~f{f|f}f{f~fzffxffvffpff;۴☸jy}{b֙pcHog1ffkffuffyf~f{f}f{f}f|f|f}fzf~f{f}f|f|f|f|f}f{f}f|f|f}fzffzf}f}fzffzf}f|f{ffyffwffwffpffKffB{Eƙi}~~~jęD|BfKffrff{f~fxffvffyf~f{f~fzf~fzf~f|f|f|f|f|f}f|f|f{ffxffzf}f|f|f|f|f}f{f}f|f|f|f}fzffvffjff.fqgHdp֙az~~q昲;foffvffzf~f{f}f|f{f~f{f|f|f}f|f|f|f{ffyffzf}f|f|f|f~fyffzf}f|f|f|f}f{f|f}f{f~fzffwffsffffffgNG[u{}~y'm{4dfuff{f}f{f~fyffyf~f|f{f}f|f|f|f}fzffzf~fzf~fzf~f|f{f~fzf}f|f}f{f~fyff{f|f}f{f}f}fyfftffffffgSr8Yv` ˒,^cfcffvffyf~f|fzffzf~f{f}fzffzf~fzf~fzf~f{f}f{f}f|f{ffxffxffzf~f{f}f|f{f~f{f}f{f|ffwffkff"fgWM nJ[v~{=$LagMfftff|f|f|f}fzffyffxffxffzf}f|f{f~f{f}f{f}f|f}f{f|f}f|f|f|f|f|f~fzf}f{f~f{f}f{f~fwffiff)fg[~ؙ]w}}oE^\g6ffkffxf~f{f~fzf}f}f{f}f|f|f}f{f}f{f~f{f|f}f{f}f|f{f~f{f}f{f}f{f~f{f}f{f}f|f|f|f}fzfftffjff:fVg^~Ll|~~}dҙ[g*ffjffsffwffzf}f|f{ffxffzf|f~fyffyffzf}f|f|f}f|f|f{f~fzf~f{f}f{f}f{f~f{f|f}fzffwffrffOfgOa;$噏z{^HsI Wgffiffuffvffwffyf}f|f|f|f}f{f}f{f~fzf~f{f}f{f~fzf~f{f}f{f~fyffyf~f|f{f}f|f|f}fzffyffuffaff\c, avY6tSgffeffrffvffzf}f}f{f}f{f~fzf~f{f}f|f|f|f|f~fyffxffzf}f{f}f|f|f}fzffyffxff|f{f}f|f{ffzfxffd{4mӣ'|wZDNg!ffiffuffyf}f}f{f}f{f}f|f{ffyffzf|f~fzf~f{f|f~fyffyffzffzf}f{f}f|f}f{f}f{f}f}fyfftfftffpff;۰昵m|zbԙraHqg0ffnffyf}f}fzf~f{f}f|f|f|f|f}f{f~fzf~f{f|f}f|f|f|f|f|f~fzf}f|f|f}f|f{f~fzf~f{f~fyffxffxffpffJffB~BǙgz}l=BfHffpffuffxffyf}f|f}f{f~fyffzf~f{f|f}fzffyf}f|f|f}f|f|f|f{f~f{f}f|f{f~fzf~f|f{ffxffvfflff0fogHcrҙe}s䘵;fnffrffwff{f|f|f}f{f~fzf}f|f}f{f~fyffzf~f{f}f{f}f|f|f|f|f|f}f|f{f~fyffyffyffzffxffsffgfffgNDZxx#l{4dfuff{f|f}f{f}f|f|f}f{f}f|f{f~f{f|f~fzf}f}fzffzf}f}fzf~f|fzffxff{f|f|f}f|f|f{f}f|f|ffuffhfffgSq:[v~_ ˓,]cfdff|fzf~f{f}f|f|f|f|f}f{f}f|f{f~f{f|f}f{f}f|f|f|f|f}f{f}f|f{ffyffyffxffyffyffyffuffhfffgWM pI\z{=$KagKffsff|f|f|f|f|f}f|f|f|f{ffyffyffzf~f{f|f}f{f~fzf~f{f|f~fzf~fzf~f{f}f|f{f~fzffxffsffeff(fg[ ҙbx~}kK^UgfUg^Ip|xcϙ[g+ffifftff{f{f~fzf~f{f}f|f|f|f|f|f~fyffyff{f|f}f{f}f{f~f{f~fxffuffuffxf~f{f~fzffwffsffOfgNa;$♑zzt\ߙMlO Wgffdffsffxffxffyffzf~fzf~f{f|f~fyffxff{f|f}f|f{f}f|f|f~fxffzf}f|f|f{ffyffyffyffxffeff_c,^y[9rSgffgffxf~f{f|f|f}f}fzf~f{f|f~fyffyf~f{f}f{f~fyffxffyf~f|f|f{ffxffyf}f|f|f|f}f{f~fzf~fzffuffdw4qӠ)z}v]HNgffiffuffyf~f{f~fyffxffzf}f{f}f|f}fzffxffxffzf~f{f|f}f{f~fzf~fzf~f{f}f|f{f~fzf~f|f{f~fxffsff;۵䘴o~{`ؙmg|Hmg2ffjfftffyf}f|f|f|f}f{f~fyffxffzf|f}f{f}f}fzf~f{f}f|f|f|f|f}f|f{f~fzf~f|f{f}f|f|f|f~fwffkffEffBCǙfz}gșDBfEfflffvffzf}f}f{f}f{f}f}f{f}f{f~fzf~f{f|f~fyffzf~fzffyffzf}f}fzffzf}f|f|f}f{f~fyffuffjff-frgH`sәcys昴;fpffxf|f}f|f|f~fxffwffyf~f{f}f{f}f|f}fzffyff{f{ffxffwffxffyf~f{f~fzf~f{f|f~fzf}f}fxffiff!fgNDZw}}x"j}4dftff|f{f~fzf~f{f}f|f{f~f{f|f}f{f}f|f|f|f|f}f{f~fzf~fzffyff{f|f|f|f}f|f{f~fyffwffxffuffhfffgSu7\x}b ˕,Zcf`ffwff{f}f{f}f|f}fzffzf}f}fzf~f|f{f~f{f{ffyffzf}f|f|f}f{f}f{f}f}f{f}f|f{ffxffwffuffhfffgWL oKߙ_|~}w:$OagPffsffyffyffxffzf}fzffxffwffyffyf~f{f|f~fzf~fzffyffzf}f}f{f}f{f~fzffyffyffvffjff,fg[~ љby|lK^Wg;ffnffxf~f{f}f|f|f}fzf~f|fzffxffyf~f{f|f~fzf~f{f|f}f{f}f|f|f|f}f{f}f{f}f|f|f}f{f}f|fzffpff;fXg^Hnzbҙ}[g,ffhffrffxffzf~fzf~f{f}f|f|f{f~f{f}f|f{f}f}fzffyffzf~fzffyffzf~fzffzf}f{f~fzffvffqffLfgLa>$晎{z]KnN Wgffefftff{f|f}f|f{f~f{f|f}f{f}f}fyffyf~f|f{f~f{f|f}f{f~fzf}f|f}f{f}f{f}f|f|f|f}fzffyfftff^ffXc,]~w\8tSgffhffuffxffzffzf}f|f{f~f|f{f~fzf}f}f|f{f~fzffyffyffzf|f}f{f~fzf~f{f}f|f|f{ffyf~f|f{fftffd{4mӣ&x~~w]ߙJNg!ffiffuff{f|f|f}fzffzf}f|f|f}f|f{f}f|f|f}f{f}f|f|f|f}f{f~fzf}f}fzffyffzf}f|f|f}f{f~fxffsffnff;۶㘴p~y_ؙmf~Hng0ffkffvffwffwffyf~fzf~f{f}f|f|f|f|f}f{f}f{f}f|f|f|f}fzf~f{f~fzf~fzffyffyffyffxffwffoffIffBAęh}{hřC}BfKffqffwffwffxff{f}f{f}f|f|f}f{f|f}f{f}f|f|f|f|f|f|f~fzf~fzffyffyffxffyf~f{f}f{ffwffkff-fqgH|hlؙa|~~s瘳;fofftffyf~f{f}f{f}f|f{ffwffvffzf}f|f}fzffxffvffxf}f~fzf}f}f{f}f|f{f~f{f}f|f{f~fyffsfffff fgNI]zw$l|4dfuf}f}f{f}f|f|f|f}f|f{f~fzf~f|f{f}f|f{ffxffyffyffzf}f}fzf~f|f{f~fyffxffzf|f}f{f|ffuffhfffgSt8[x`˖,[cfbffvffwffzf}f|f}fzffyffyf~fzf~f{f}f|f|f|f|f}f{f~f{f|f}f{f~fzf~fzf~f{f}f{f}f{ffwffpffefffgWO lMߙ^y}}<$MagNffsffyffyffzf~f{f|f|f}f|f|f|f}fzffyffyf~f{f}f{f~fzf~f{f}f{f~fzf~fzffyffxffxffuffiff)fg[ ϙd{{kF^Zg:ffoffuffwff}fyf~f}fyffxf~f}fzf~f{f|f~f{f|f|f}fzffxff{f|f|f}f{f~fzf~fzffyffwffvffpffffpffwffxffxffwffxff{f|f}f|f|f{f~f{f}f|f{f}f}fzffyff{f{ffxffxffzf~fzffyffwffqff>fUg^Ji{z_ՙ [g*ffjffwf~f{f~f{f}f{f}f{f~f{f|f~fyffzf}f~fyffzf}f|f|f}f{f}f{f}f}fyffxffzf}f|f{f}f|f{ffrffMfgQa7$#ޙxy\KnM Wg!ffjfftfftffvffzf~fzffyf~f}fzffyf~f|f|f|f}fzffzf}f{f}f|f~fyffzf}f~fyffzf~fzffwffuffaff[c,_vZ6uSgffjffwff{f}f{f~fyffyf~f|f{f}f}fzf~f{f|f}f|f|f{f}f|f}f|f{f|f~f{f|f~fyff{f{f~f{f}f|f{f~fyffsffd{4mӤ%yw[FNg"ffkffvffxffzffzf}f|f{f~f|fzffzf}f|f|f}f{f}f{f}f}f{f}f{f~fzf~f{f|f~fzf~fzf~fzffwffvffsffmf f;۱昳p~~y`ؙne~Hog1ffmffvffxff{f|f|f}fzffxff{f|f~fyffxffzf}f|f|f{ffyffyf~f|f|f|f|f|f}fzffxffxffxffpffJffB}Eșf{}gǙE|BfKffpffxffzf~fzf~f{f}f|f|f{ffyffxff{f}f|f{f}f|f|f}f{f}f{f}f}fzffyffzf~fzf~fzffxffrffhff,fsgHemٙ^zo☵;frff{f|f|f|f|f}f{f~fyffxffzf}f|f|f|f}f{f}f{f~fzf~fzf~f{f}f|fzffxffxf}f~fyffzf{ffwffuffiff fgNI]z{&k~4dfsffyffzf~f{f}fzffwffwffzf|f~fzffxffyffzf}f|f|f|f}fzffzf}f|f|f|f}f{f|f~fzffxffuffffffgSs8[v}b ˑ,^cfbffuffyf}f~fxffvffyf~f{f}f{f}f|f}fzffyff{f|f}f|f{f~fzf~f|f{f~fzf~f{f}f|f}fzffvffrffhff fgWK pJ\w9$OagNffuf}f}f{f}f|f|f}fzffxffxff{f|f|f}f{f~fzf~f{f}f{f}f{f~f{f|f|f}fzffwffwffwffxfftffhff'fg[ Йd}mI^Zg8ffmffvffuffwffzf}f|f|f|f}f{f~fzf~fzf~f{f}f{f~fyffyf~f{f}f|f|f}f{f|f~fzffyf~f{ffxffmff7f\g^Gj}}~|eϙ [g'ffeffqffwff{f}fzffwffyf}f}f{f|f}f|f{f~fyffzf|f}f{f}f|f|f|f}f{f}f{f~f{f}f{f}f{ffxffrffMfgOa9$ ᙓw}~x]KnM Wg ffhfftffxffyf~f{f|f~fzf~f{f|f}f{f~fzffxffzf}f|f|f{ffyffzf}f|f|f~fyffzf}f}f{f|f}f|fyff_ffYc,]~wZ6uSgffhffsffwffyffzf|f~f{f|f~fyff{f|f}f|f{f~fzf}f}fzf~f{f|f}f{f~fyffxffzf|f}f{f~fzf~f{f|ffrffd~4kӤ&z}v_ݙJNgffgffuff{f|f}f{f|ffxff|fzffxff{f}f{f}f|f|f|f}f{f}f|f{f~fzf~f|fzffyff{f|f|f|f|f~fyffvffpff;۲嘴o~}cՙoe~Hng1ffmffvffxffxffyffzf}f|f}f{f}f|f{ffyf~f|fzffzf~f{f|f|f}f{f~f{f|f}f{f}f|f}f{f~fyffwffmffFffB~DǙf|~~~|iƙF{BfIffqff|f{f}f|f|f|f}f{f|f}f{f}f|f|f|f|f}f{f}f}fzf~f|f{f~fzf~f{f|f}f{f~fzf~f{f|f~fyffxffuffhff,frgHcpי_w}yk䘲;fqffyffyffzf}f|f|f|f|f~fyffzf~f{f}f|f{f~f{f}f|f|f{f~f|f|f|f{f~f{f}f{f}f|f{f~f{f|f~fxffsffgff fgNG\w~~{$k~4dfsff|f|f|f|f|f}f{f}f|f{f~f{f|f}fzffzf~fzf~f{f}f{f~fzffyf~f|f|f|f|f|f|f}f{f}f|f{f~fzffvffjfffgSs7[y^˕,Zcf`ffvf~f}f{f~fzf~fzffzf}f}fyffwffxf~f|f|f|f}fzffzf}f|f|f|f~fzf~fzf}f}f{f~fzf~f{f{ffvffiff fgWL pI\z|<$NagNfftffzf~fyffyffyffzf}f}fzffyf~f|f|f|f}f{f}f|f|f|f~fyff{f{ffyffzf~fzffyffxffvffmff+fg[ әaz~~oG^Xg;ffpffxffzf}f}f{f|f}f{f}f}fyffwffzf~fzf~fzffzf}f|f{ffyf~f|f{f~f{f}f{f}f|f|f}f{f~fyffnff;fWg^Kk|~~~~xcЙ [g(ffjffuffvffwffxffzf~f{f|f}f{f}f|f|f|f}f{f~fzf}f}fzffwffvffzf}f{f~fyffzf|f}f|fzfftffPfgNa<$♒xz\JnO Wg ffifftffxff{f|f|f}f{f~fzf}f|f|f|f|f|f}f|f{f~fyffxff{f|f}f{f~fzffxffzf}f}fzf~f{f|ffwffbff]c,^vW5uSgffeffrffwffzf}f|f|f|f|f|f}f{f}f{f}f|f|f|f}f{f~fzf~f{f~fyffxffzf|f}f{f}f|f}f{f}f{f}f}fzffsffd}4lӤ%v{~x\HNgffhffuffxff{f}f{f}f{f~fzffyffzf}f}fzffzf}f|f|f}f{f|f~fyffwff{f}f|f|f|f|f}f{f~fzf~f|fyffqff;۴䘵n|za֙odHpg.ffiffxf|f~fzf~f{f}f{f}f}fyffwffzf~fzffxff{f{f~fzffyffyffyf~f{f}f|f}fzffyffyffuffnffJffB}Dřj|~zgƙB~BfJffrffzf}f{f}f}fzffyffzf}f|f|f}f|f{f~fzf~f|fzffxff{f|f}f|f{f~fzffyffyffxff{f|ffuffkff0fogHarԙb{t꘯;fqfftffwff{f|f}f{f}f{f~fzf~f{f|f}f|f|f}fzffzf~f{f|f}f{f~fzf~f{f}f|f|f|f}f{f~fzf~f{f|f~fxffjff fgNG[xx!i}4dfwf|f}f|f|f}fzffzf}f|f|f|f~fyffzf~f{f}f{f~fzf~f{f|f}f|f|f|f}fzff{f|f}fzffzf~fzffxfftffifffgSs7Zuy|b ˑ,^cfaffvff|fzffxff{f|f}f|f{f}f}fzffwffxff|fzffyffzffyffyffzffyffzf|ffxffwffuffffffgWM oK]y}~}y:$PagQffsffvffwffzf}f}fzf~f{f|f~f{f|f|f|f}f|f}fzf~f{f}f}f{f|f}f{f~f{f|f|f}f|f{f~fyffwfftffiff*fg[ Йd{}mF^Yg:ffmffvffzf|f}f}fzffxffzf~fzf~f{f}f{f~fzf~f{f|f~fyffxff|f{f}f|f|f|f~fyffxffwffuffnff8f[g^Gk{zfΙ [g+ffjffuffyffzf|f~fzf~f{f}f{f}f|f{ffyf~f{f|f}f|f|f|f|f|f}f{f}f|f|f|f|f|f}f|f{f~fyffvffqffKfgJa?$䙐z~v[LlP Wgffgffsffwffyffzf}f|f|f|f}f{f}f{f~fzffyf~f|f{f~f{f{ffyffzf|f}f|f}f{f|f|f}f|f}f{f|f~fxffbff]c,_xY5vSgfffffrffwffyffyffxffyffyffzf~f{f|f}f|f|f|f|f}f|f|f{f~f{f~fyff{f|f}fzffzf}f|f{f~fzffuffdz4nӣ%x}w\INg"ffiffuffyffyffzf~f{f}f{f~fzf}f}f{f~fzf}f|f|f}f|f{f~fyffyffzf|f}f|f}f{f}f{f}f|f|f~fxfftffpff;۱嘶ky{_ٙmeHsg,ffhffrffvffzf~fzf~f{f}f|f{f}f|f}f{f}f{f~fyffyf~f{f}f{ffxff|fzffxf~f}fzffxfftffrffoffLffB}DǙf|~xdəFzBfMffpffvffyf~f|f{f~fzf~f{f|f~fyff{f{ffxffzf}f|f|f|f|f}f{f}f|f|f|f|f|f}f|f{f~fzffxffvffiff+ftgHbqԙc{~o㘶;fsffzf}f{ffwffxf~f{f}f|f|f|f}f{f}f|f|f}f{f|f}f|f|f|f}fzf~f{f}f|f|f}f{f}f{f}f|f~fyffyfftffefffgNDYz~y'ox4dfwf}f{f~fzf~f{f}f{f~fzf~fzffyffxffzf~f{f}f{f}f|f{f~fzf~f{f}f{f}f{f}f|f|f~fwffuffvffrffefffgSs8]x~]˒,^cfcffyf}f|f|f|f}f{f}f|f{ffyffzf}f}fzffxffzf~f{f~fyffyffyf~f{f|f~fzf}f}fyffwffxffvffhfffgWM oJ\wz!9$NagLffsff{f}f{f}f{f}f|f|f|f}f{f|f}f{f~f{f|f|f}f|f|f}fzffzf~fzf~f|f{f~fzf}f}f{f|f~fzf}f~fvffkff-fg[|ՙ`x|mE^\g7fflffvffvffuffxffxffyf~f|f{f~fzffyffyff{f|f}f{f}f|f|f|f}f{f}f|f|f|f|f|f}f{f~fxffnff:fXg^Imz}}dЙ [g(ffhffsffxf~f|f{f}f}fzffyf~f|f{f~f{f|f|f}fzffyf}f}fzffzf}f|f}f{f}f{f~f{f|f}f{f}f}fzfftffOfgNa;$ᙔu~x[IqJ Wg#ffmffzf}f|f}fzf~f{f|f~f{f{f~fzf~f{f}f{f~fzf~fzffyffyf~f{f}f|f}fzffyffxff{f|f}f|fzffvffaffZc,`~x[:qSgffkffxf~fzffxff{f{ffyffyff{f{ffxffyffyffxff{f|f}f|f{f~fzf~f|f{f~fyffzffyffyff|fuffd}4kӥ%x~}x]HNg!ffiffuffzf}f|f|f|f}f{f~fzf~f{f}f{f~fzf~f{f|f~fyffxff|fzffyffzf~f{f|f~fyffyf~f{f}f{fftfflf f;۴㘶m}y`ؙndHug*ffgffrffwffxffyf}f~fyff{f{ffzf}f|f{f}f}f{f}f|f{ffyf~f{f}f|f|f}fzf~f{f}f|f|f{f~f{f{ffoffHffB}Dři{}}ziřE{BfLffpffvffwffzf}f|f|f}f{f}f{f}f}fzf~fzf~f{f}f|f{f~fzf~f|f{f~fzf}f~fxffvff|fzf~f|fzffuffkff.fqgHcqԙc{}p꘮;fqffwffzf|f}f{f~fzffxffwffyf}f}f{f}f}fzf}f~fyffxff{f}f|f{f~fzf~f|fzffxff|fyffuffsffgfffgNH[v~}&l}4dfqffyffyffwffvffvffyf|f~fzffyf~f{f|f~fzf}f|f|f|f}f{f~fzf}f|f}f{f~fyffyf~f|f|f{ffvffgfffgSx4Xw^˖,Zcfaffyf|f}f{f}f|f|f|f|f}f{f}f|f|f}f{f}f{f~f{f}f{f}f{f~f{f|f}f{f~fzf}f}fzffxff{f{ffxfftffhff fgWJ rGZx}}z:$PagQfftffxff{f|f|f}f|f{f~f{f|f}f{f}f|f|f|f}f{f|f~fyffyf}f~fxffzf|f~fzf}f}fzffzf}f|f}fyfflff+fg[ ϙcx||ymI^Ug$LagLffofftffxf~fzffyff{f|f|f}fzffzf}f}fzf~f{f}f|f|f|f|f}f{f}f|f|f}f{f|f~fzf~fzffxfftffkff+fg[ Ιf|~kJ^Yg9fflffwffzf}f|f|f{ffyffzf}f}fzffzf}f}f{f}f|f|f|f}f|f{f~fzf~f{f|f}f{f~fzf~fzf~f{ffvfflff9fYg^Hk}{cљ [g-ffnffwffzf}f{f}f{f~f{f|f|f|f}f{f}f|f|f}fzf~f{f~fzf}f}fzf~f{f}f|f|f|f|f}f{f}f{ffxffvffqffOfgPa;$晎{}w\JoM Wgffhffuffyf~f{f}f{f}f|f{f~f{f{ffvffwff|fyffxffxff{f}f{f|f}f|f}fzf~f{f}f|f|f|f|f}f|fzffcff]c, a~{u[9rSgffiffwff{f|f}f{f}f|f|f}f{f}f|f|f}f{f}f|f{f~f{f|f~fxffxff{f{ffyffyffzf~f{f|f}f|f{f~fzffsffd4hӨ"w~z]FNg!ffgfftffxffzf~fzf~f{f}f{f}f{f}f|f{ffyf~f{f}f|f}fzf~fzffzf}f|f{f~f|f{f}f{f~f{f}f{f~fyfftffmff;۲昳p}}x`יocHpg0ffnffwffxffyffzf}f{f}f}f{f}f{f}f|f|f}f{f~fzf~fzffzf~fzf~f{f}f|f{f~f{f}f{f}f{ffyffxffqffJffB|Eșgz{ięB~BfMfftff|f|f|f~fxffxff{f{f~f{f|f~fyffyf}f}f{f~fzf~fzf~f{f}f{f~fzf~f{f}f|f}fzf~f|f{f~f{fzffiff-frgHbrԙb{o嘳;fqffxffyffzf}f|f}f{f}f{f}f|f|f|f}f{f~fzf}f|f|f}f|f{f}f|f|f}f{f}f|f|f}fzffyffyf~f{f|f~fxffhfffgNLݙ_x~}}|%i4dfvfzffuffwffzffzf}f|f{f~f|f{f}f|f{f~f{f}f|f{f}f{f~fzffyf~f{f}f|f|f|f|f~fyffxffyffvffffffgSu8]x]˖,Zcfafftffvffyf}f|f}fzffyffyffyf~f|f{f}f}fyffwffzf}f|f}fzf~f{f}f|f}fzf~f{f}f|f}fyffsffffffgWL pJ^z~}x 8$QagPffsffyff{f|f|f}fzffzf~fzffxffzf}f}fzf~f{f}f|f|f|f|f}f{f}f|f|f|f|f|f}f{f~fzf~fzffwffiff'fg[ љbwz|lG^Zg9ffnffxffxffwffzf}f}fzf~f{f}f|f|f|f|f}f{f}f|f|f|f|f|f~fyffzf}f|f}fzffyffzf~fyffvffnff=fVg^Fn|zbҙ [g)ffjffwf~f|f|f}fzffyff{f|f|f|f}f{f~fyffyf~f|fzffxff{f}f{f}f{f}f}fzffyffzf~f{f}fzffpffIfgMa:$㙐{~|w[GsI Wgfffffuff|f|f{f~fzf~f{f|f}f|f{f}f|f|f}f|f{f~fzf~f{f}f{f~fzf~f{f|f}f|f|f}f{f}f{f~f{f|f|f~fwff]ffWc, azZ6uSgffdffsffvffwffwffzf|f~fzf~fzf~f{f}f|f{f~fzf~f{f|f~fzf~fzf~f{f~fzf}f|f|f}f|f{f~fzf~f{f}f|fxffd{4lӤ&y~x\FNg!ffiffvffzf~fzf~fzffyffzf~f{f|f}f|f|f}f{f|f~fyffyf~f{f|f}f|f|f|f|f|f}f|f|f|f|f}fzffwffvffsff;۴䘵n|~}y`ؙmg|Hpg-ffgffsffzf}f}fzf~f{f}f|f{f}f|f|f}f{f|f}fzffyf~f{f|f}f|f}fzffxffxffxffxffwffwffvffoffIffBAęh{}yiřE{BfJffoffwffyf~f|f|f}fzf~f{f}f|f}fzf~f|f{f~fzf}f~fyffzf}f|f}f{f}f|f{ffxffzf}f|f|f}fzffvfflff1fpgHarՙaw}}p䘳;fmffvff{f{f~fyff|f{f~fyffzf~f{f|f}f{f}f|f|f|f|f}f{f~fzf~fzffyffzf~fzf}f}f{f~fyffyffvffjff$fgNF]x}~{'m{4dfyfzffzf~f{f}f{f~fzf~f{f}f{f}f{f~fzf~f{f|f}f{f~f{f|f|f}f{f~fzf}f|f|f|f}fzffyffwffxffvffhfffgSt6Yu|~[˗,Ycfaffwffzf~f{f}f{f~fzf~f{f}f{f~fzffxffzf}f|f{f~f{f}fzffzf}f}fzffyffzf~f{f|f|f~fxffrffefffgWL nLߙ^y~z<$MagNffrffwffxf~f|f|f}f|f{f}f|f|f}f{f~fzf}f}fzffwffxffyf~f|f{f~f{f}f|f|f|f}f{f}f|f|f}fyffnff,fg[ ҙc}}{lL~^Ug=ffnffuffyf~f{f}f|f{f~f{f|f~fzf}f}fzf~f|f{f~fzf}f|f}f{f}f{f}f|f}fzffyff{f|f}f|fzffwffoff$晏z}xZJmP Wgffiffvffyf~f{f}f{f~fyffzf|f~fyffyf~f{f}f|f{f~f{f}f{f}f|f|f}f{f}f|f|f}fzffzf~f{f|f{fftff^ff[c,\z]8tSgffgffvffzf~fzf~f{f|f~fyf~f|f{ffyffyff{f|f~fyffxffzf|f~fzf~f{f}f{f~fzf~f{f}f{f}f|f|f{ffrffd4jӥ%y~~~y^GNg"fffffsffwffyf~f|f{f~fzf~f|f{f~fzffyffzf}f}fzf~f{f|f~fyffxffyffyffxffzf|f~fyffxffvffqff;۲瘱r}xa֙pcHqg.ffifftffxff{f{ffxffzf}f|f{f}f}fzffvffvffyf}f}fzffyffzf~fzf~f{f}f|f{f~fzffyffvffoffJffB|Dęj}~}ziÙ@BfIffnffvff{f|f|f|f}f{f~fyff{f|f~fxff{f|f}fzffzf~fzffyffxff{f}f|f{f~fzf~f|f{f~fzf~fzffpff3fmgHbsҙd}o㘵;fpffuffxffzffzf}f{f~fzffyffzf}f|f|f}fzffzf}f|f|f|f}f{f}f|f|f{ffyffzf}f|f|f}f|fzfftffefffgNIߙ_yz"hӀ4dfrff{f|f~fzf}f|f}f{f}f|f{f~f{f|f}f{f}f}f{f}fzff{f|f~fxffxffzf~f{f}f{f}f{f~f{f}f{f|ffuffbfffgSv4Yx}~a˕,\cfeffzf|f}f{f~fzf~f{f}f{f~fyffzf|f}f|f{ffxff|fzffzf}f}fzf~f{f}f|f|f|f|f}fzffyffwffrffefffgWL oJ]x{8$QagOfftffzf}f|f|f}f{f}f|f|f|f|f}f|f|f{f~f{f}f{f}f{f~fzf}f}fzffyffyffzf~f|fzffyffwffsffhff(fg[ЙczyhF^Yg:fflffuffzf~fzffzf}f{f}f}fzffyffzf~fzf~f|f{f~fzf~fzffzf}f|f|f|f}f{f}f|f|f|f|f|f~fxffmff8fZg^Ioyaә [g)ffiffsffuffxff{f{f~f{f}f|f|f|f}f{f}f|f}f{f|f|f}f|f|f|f|f|f|f}f|f|f{f}f|f}f{f}f{f}f{ffsffLfgNa:$ ᙒxz_ݙOjQ Wgffjffvffwffxffxffyf~f}fyffyf~f|f|f{ffxffuffyf}f}f{f|f~fzf}f|f|f}f{f}f{f}f|f|f{ffuffaffZc,^z\9qSgffhffvffyffxffxffzf~f{f{f~fzffyffzf~fzf~f{f}f|f{f~f{f}f|f{f~fzffyffzf}f}fzffyffzfftffd}4kӥ%zxZGNg ffkffvffyf}f}f{f}f{f~f{f}f{f}f{ffyf~f{f}f|f}fzf~f{f}f}fyffzf~f|fzffyffxffwffxffxfftffpff;۰蘱rz`ؙne~Hog1ffmffxffzf~fzffyff{f{ffxffwffxffzffyffzf}f}f{f~fyffyffzf|f~fzf~f{f}f{f}fzffwffnffGffBAřhz|hƙD}BfKffrffzf~fzf~fzf~f{f|f}f{f}f{f}f{f}f|f|f|f|f|f}f{f}f{f~fzf~fzffzf~fzf}f|f~fyffwffxffuffjff/fpgHdoؙ^t}s阯;fqffzf}fzffzf}f~fxffzf}f|f|f|f}f{f~fzf~fzf~f{f}f|f{f~fzf}f~fyffxff{f}f|f{f}f|f|f~fxfftffiff!fgNIߙ]w|}~w#j4dfrff{f|f{ffwffvffyf~f{f}f{f~fyffzf~f{f}f{f}f|f|f}f|f{f~fzf~f{f}f{f}f{f~fyffuffrffnffcfffgSs8\x~^ˑ,]cf^ffsff|f{f}f|f|f|f}f{f|f}f{f}f|f|f{f~fzffyffzf~fzffxffvffyf}f}f{f|f~fyff{f{ffzf{ffkff fgWM oI[xx<$NagPfftffyf~f{f}f{f~fzf~f{f}f{f~fzf~f|fzffxff|fzffyff{f}f{f|f}f|f}f|fzffzf~f{f}fzfftffjff+fg[ ҙc{{oD^[g8fflffvffxffzf~f{f}f{f~fzf~f{f}f{f}f|f{ffxffxf~f{f~fzffyf~f|f{f~fzf~f{f}f{f~fyffvffoff;fYg^Fpzf̙[g*ffkffuffuffwff{f|f}f{f}f|f|f|f}fzffzf~f{f}f{f~f{f|f~fyffyf~f{f|f}f|f|f|f|f|f}f{f}f~fuffPfgQa9$噎||v\JpK Wg!ffgffrffyf|f~fzffyf~f{f~fzf~fzf~f|f{f}f|f|f}f|f|f{ffxffxffxffyf~f{f}f|f|f|f|f}f{f~fxffbffYc,`~zY3vSgffeffuff{f|f}f{f}f{f~fzf~f{f|f~fyff{f|f}f|fzffvffxffzf}f}f{f}f|fzffyf~f{f}fzffzf~f{f~ftffd|4mӢ(y~{\ENg ffhffsffwffxffyffxffzf|f~fyff{f|f}f{f|f}f}fyffvffzf}f|f|f{f~f{f}f|f{f~fzf~f{f}f{ffvffpff;۱瘲pxbԙqcHog0fflffsffsfftffxf~f{f}f{f~fzf~f{f}f{f}f{f~fzffyffyffzf~f{f|f|f}f{f}f|f{ffxffyffxffpffHffB?řgz|ięABfGffnffyffzf}f|f{ffyf~f|f{f~fzf~f{f~fzf~fzffzf}f}fyffwffyffzf~f{f|f}f{f}f}fzffwfftffkff0fogH}fn֙bzs昳;fofftffxf~f}fzf~f{f|f~fyffzf~f{f|f}f{f~fzffyffxff{f}f|f{f~f{f|f}f{f}f|f|f|f|f|f}f{f~fxfflff"fgNDZxx%n{4dfuf~f{f~fyffyf~f|f{f~fzf~f{f}f|f{f~fzf~f{f}f|f|f|f}fzffxffyf}f~fyffzf}f}fzffxffvfftffifffgSv3Vu}` ˓,\cf`ffxf~f{f~fyffzf~fzf~f{f}f{f~fyffyf~f|f{f~fzf~f{f|f~fzf~fzf~f{f~fyffzf~f{f}f{ffwffpff`fffgWJ qI]z}>$LagMffoffuffyffyffzf}f}f{f}f{f~fzf~f{f|f~fyffxffxffxffzf}f|f}fzffzf}f|f|f}f{f}f|f{ffoff0fg[~ љd||lI^Yg9ffmffwff{f|f|f}f{f~fzf~fzffyffzf~f{f|f}f|f|f|f|f|f}f|f{f~fzf}f}f{f}f|f{f~fzffxffuffmff;fXg^Hl}x_ԙ [g*ffkffuffwffvffxffzf}f|f{ffxffwffzf~fzf~fzf~f|f|f|f|f|f}f{f~fzf~f{f|f~fzf~fzffxffpffKfgMa;$噎|{xt]ޙOjP Wgffhffvffzf}f|f{ffxffxff{f{ffyffzf~f{f}fzffzf~fzf~fzf~f{f}f|f|f{ffyffzf}f}f{f|f~fxffdff^c,_}}w[7tSgffhffvffyff{f|f}f{f}f{f~fzffyf~f{f|f~fzf~fzf}f}f{f~fyffzf~f|f{f~fyffyff{f|f|f}f{f~fzffuffd{4mӣ'z~x]HNgffgffrffwff|fzf~f|f|f|f|f|f}f|f|f|f|f|f~fzf~fyffyffzf}f{f~fzffzf}f|f}f{f}f|f|f|f~fxffuffpff;۱瘳o~xaԙs`Hpg0ffjffrffwff{f|f}f{f}f|f{ffxffwffyf~f{f|f}f|f|f}f{f|f~fyffzf|f}f{f}f}fzf~f{f}f{f~fxffoffIffB~CǙgz|iƙFzBfIffoffxffzf~f|fzf~f{f}f|f{f~fzffyffzf}f|f|f~fyffyffyf~f|f{f~fzf~f|f{f~fyffxffwffvffmff/fqgHarԙcz~p嘴;fofftffyff{f{f~f{f|f}f|f{f~fzf~f|f{f}f|f|f}f{f}f{f~fzffyffyffxffwffzf~fzffxffuffsffhff!fgNE]z{'nz4dfwf|f~fzf~fyffyffyffzf~f{f|f}f|f|f}fzffyff{f|f}fzf~f|f|f|f|f|f}f{f}f{ffyf~f{f}f{ffvffhfffgSq8]{\˖,\cfeffyf~fzf~f{f}f|f|f{ffyffzf}f|f}f{f}f{f~f{f|f}f{f}f|f|f|f|f}fzffxffyf~f{f}f}fzf~f{f{ffkff fgWK pJ\w~~y<$KagKffqffzf}f}f{f}f{f}f}f{f|f}fzffxffzf~fzffyffyffyf~f|fzff{f{ffwffyf}f}fzffwfftffgff&fg[ ЙcznK^Zg9ffnffyf|f~f|f|f|f{f}f}f|f{f~fyff{f|f}f{f}f{f~fzffyffzf}f}fzffyffzf~fzf~fzffwffuffoff:fZg^Ify}wcϙ [g(ffiffvffyffyff{f|f|f}f{f~fzf}f}f{f}f|f{f~fzf~f{f}f{f}f|f{f~f{f|f~fyffyffxffyffxffqffOfgQa8$!ᙒx{aܙPjO Wg ffgffrffwffzf~fzffyf~f|f{f~fzf~f|fzffyffyf~f{f|f}f{f~fzf~fzf~f|f{f~fyffyf~f{f}f|f|f{fffff]c,a}tW5uSgffgffvf~f}f{f}f|f|f|f}f|f{ffwffuffvffxffwffyf}f}f{f}f}fzffzf}f|f|f}f{f~fzf}f}fzffzf}fxffdz4mӤ'|~xYB"Ngffeffsffyf~f{f}fzffzf~f{f|f|f}f{f}f}fzf~f{f|f~fzf~fzffyffzf}f}f{f|f}f{f}f|f|f|f|f}fzfftffnff;ۯ阱q}v]ٙncHrg.fflffwffzf}f|f}fzf~f|f{f~fzf}f~fxffvffvffzf|f}f{f}f|f|f|f|f}f{f}f}fyffyf~f{f~fyffuffnffIffB{FǙh{~kÙB}BfMfftff|f{f}f|f|f}fzffyffzf}f}fzffyff{f{f~f{f}f|f{f}f|f}f{f|f}f{f~fzf~fzffzf}f|f{ffxfflff/fpgHenי`x~~~n;fqffuffxf~f}fzf~f|fzff{f{ffxffzf}f|f|f|f}f{f}f|f|f}f{f}f{f~fzffyf~f{f}f}fyffxffwfftffffffgNG]v~x"j~4dfsffyffzf~f{f{f~f{f~fzf}f|f{ffxffxff|f{f~fzf~f{f}f{f}f|f|f}f{f}f{f~f{f}fzffxffxffwffgfffgSu5Wt^˕,\cfaffqfftffxffzf~f{f}fzff{f|f}fzf~f|f|f}fzf~f{f}f|f}fzffyffzffyf~f{f}f|f}fyffvffuffkff"fgWL oJ\yy;$MagLffpffwffxffzf}f}f|f{f~fyff{f|f}fzf~f|f{f}f|f{f~f{f|f}f{f~fzffxffzf~fzf~fzffyffxffmff-fg[ ϙe}~nI^Xg;ffmffvff}fyff{f|f}f{f|ffxffyf}f~fzf~fzf~f{f}f}fzf~f{f}f|f|f}f{f}f{f~fzffyffyffwffmff;fXg^Jm}{dϙ [g,fflffxf~f{f~fzf~f{f}f{f~fzf~f{f|f~fzf}f|f|f|f}f{f~fzf}f|f}f{f~fyff{f|f|f|f}fzffwffuffpffLfgQa7$"ᙐ|z^KnN Wgffdffqffvffyffzf~fzffxffxff{f{f~f{f|f}f{f}f}fzf~f{f|f~fzf}f|f|f|f}f{f}f|f|f|f|f}f}fxffaffZc,`}|x[5wSgffhfftffvffxf~f{f|f~fzf~fzf}f}f|f{f}f{f~f{f}f{f|f}f|f|f}fzffyffzf~f{f}fzffxffyffyffzfzffdz4kӧ"v~z^ߙINgffkffyf~fzffyffzf~f{f}f{f}f|f|f|f}f{f}f{f~fzf~f{f|f~fzf~f{f}f{f}f|f|f}f{f|f}f{f~fzffxffwfftff;۲瘲pz}{bՙqaHpg0ffnffvffvffvffzf}f|f|f}f{f}f|f{f~f{f}f|f{f~fzf~f|fzffxff{f|f~fyffzffyffyff{f}fyffpffJffB~Aęiz}wb˙E}BfJffpffvffxff{f}fzffyffzf~f{f|f|f|f}f|f{f~fzf~f{f}f{f~fzf~f{f|f~fyffzf}f}f{f|f~fxffuffjff1fmgH{gnי_x~~r蘰;foffuffxffyf~f|fzffyf~f{f}f{f~fzf~f{f}f{f}f{f~f{f|f}f{f}f|f|f|f}f|f|f}fzffzf~fzffxfftffiff"fgNH]x~~~{$i~4dfwfzffxffzf|f}f{f~f{f|f}f{f}f|f|f|f}f{f}f{f}f}fzf~fzffyffyffzf~fzf~fzffyffxffxffsffdfffgSt7Zx^˕,[cfdffzf{ffxffxffzf}f|f|f|f|f|f}fzffyffzf~f{f}f{f}f|f|f}f{f}f{f~fzf~f{f|f}f|f{ffwffsffffffgWN oHXt}~{9$PagMffrffyf~f{f|f}f{ffxffyf~f}fyffzffyffwffyf~f{f}f{f~fzf~f{f}f{f}f{f~f{f|f|f}f{ffwffnff.fg[֙]y|nJ^Vg;ffkfftffxffyffzf|f~fzffzf}f{f~f{f}f|f|f{ffyf~f|f{f~f{f{f~f{f}f|f{f~fzffzf}f|f}fyffmff7f]g^Em}cҙ~[g-ffkfftffwff|f{f}f|f{f~f{f}f|f{f}f|f|f~fyffzf}f~fyffwffyf~f|f{f}f|f{f~f{f}f|f{f~fyffqffKfgNa:$㙏|~x\LlP Wgffhffsffvffyf~f{f|f}f{f}f}fzf~fzf~f{f}f|f|f|f}fzffzffyffyff{f}f{f}f{f~f{f|f}f{f}f}fyffdffZc,[|]8telektroid-3.2.3/test/res/connectors/summit_multi.data000066400000000000000000000020171500236517400230140ustar00rootroot00000000000000 )3PartA-Init Patch@<@@@@@@@@@@L@@@@@@@@@L@@@@@@@@@L@@@@@@@Z(@K#-@K#-@@@@@U Z2@@J(@@Z<@2@@@@@@@@@@@@@@@@@@@@@@@@@@@Init Multi @<PartB-Init Patch@<@@@@@@@@@@L@@@@@@@@@L@@@@@@@@@L@@@@@@@Z(@K#-@K#-@@@@@U Z2@@J(@@Z<@2@@@@@@@@@@@@@@@@@@@@@@@@@@@Init Patch @<elektroid-3.2.3/test/res/connectors/summit_multi.data.back000066400000000000000000000020171500236517400237130ustar00rootroot00000000000000 )3PartA-Init Patch@<@@@@@@@@@@L@@@@@@@@@L@@@@@@@@@L@@@@@@@Z(@K#-@K#-@@@@@U Z2@@J(@@Z<@2@@@@@@@@@@@@@@@@@@@@@@@@@@@New Name @<PartB-Init Patch@<@@@@@@@@@@L@@@@@@@@@L@@@@@@@@@L@@@@@@@Z(@K#-@K#-@@@@@U Z2@@J(@@Z<@2@@@@@@@@@@@@@@@@@@@@@@@@@@@Init Patch @<elektroid-3.2.3/test/res/connectors/summit_single.data000066400000000000000000000010171500236517400231420ustar00rootroot00000000000000 )3Init Patch @<@@@@@@@@@@L@@@@@@@@@L@@@@@@@@@L@@@@@@@Z(@K#-@K#-@@@@@U Z2Z@J(@@Z<@2@@@@@@@@@@@@@@@@@@@@@Init Patch @<elektroid-3.2.3/test/res/connectors/summit_single.data.back000066400000000000000000000010171500236517400240410ustar00rootroot00000000000000 )3New Name @<@@@@@@@@@@L@@@@@@@@@L@@@@@@@@@L@@@@@@@Z(@K#-@K#-@@@@@U Z2Z@J(@@Z<@2@@@@@@@@@@@@@@@@@@@@@Init Patch @<elektroid-3.2.3/test/res/connectors/summit_tuning.data000066400000000000000000000006301500236517400231650ustar00rootroot00000000000000~Peak Table 01 n@}@s@@@l { q n@}@s@@@l{qn@}@s@@ @ l!{"q$%&''n@(}@)s@+@,@,l-{.q01233n@4}@5s@7@8@8l9{:q<=>??n@@}@As@C@D@DlE{FqHIJKKn@L}@Ms@O@P@PlQ{RqTUVWWn@X}@Ys@[@\@\l]{^q`abccn@d}@es@g@h@hli{jqlmnoon@p}@qs@s@t@tlu{vqxyz{{n@|}@}s@@elektroid-3.2.3/test/res/connectors/summit_tuning.data.back000066400000000000000000000006301500236517400240640ustar00rootroot00000000000000~Peak Table 16 n@}@s@@@l { q n@}@s@@@l{qn@}@s@@ @ l!{"q$%&''n@(}@)s@+@,@,l-{.q01233n@4}@5s@7@8@8l9{:q<=>??n@@}@As@C@D@DlE{FqHIJKKn@L}@Ms@O@P@PlQ{RqTUVWWn@X}@Ys@[@\@\l]{^q`abccn@d}@es@g@h@hli{jqlmnoon@p}@qs@s@t@tlu{vqxyz{{n@|}@}s@@elektroid-3.2.3/test/res/connectors/summit_tunning_scale.data.back000066400000000000000000000006301500236517400254110ustar00rootroot00000000000000~Peak Table 16   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~elektroid-3.2.3/test/res/connectors/summit_wavetable.data000066400000000000000000000051661500236517400236440ustar00rootroot00000000000000 )3User WT )3@ )3KL<]}x/6Yiq v xz{|}}~~~ )3+?WEA?rCA ?wvA]?zA?{CA?|,A,?|uAn?}+A??}TA?}uA}?~Ae?~%AQ?~8A@?~HA1?~UA$?~bA?~lA?~vA?~~A~?Av? Ap?Aj?Ad?A_?$AZ?)AU?-AQ?1AM?5AI?9AF?<AB??A??BA<?EA9?HA6?KA4?NA1?PA/?SA,?UA*?WA(?YA&?[A$?^A!?`A?aA?cA?eA?gA?iA?kA?lA?nA?pA?qA?sA ?uA ?vA ?xA?yA?{A?}A?~A?A )3@djWdsdvqdxvdzd{d{ed|&d|Yd}d}&d}Cd}\d}rd~d~d~%d~3d~?d~Jd~Td~]d~fd~nd~ud~|dd ddddd#d(d,d0d4d8d<d?dCdFdIdLdOdRdUdXd[d^dadcdfdidkdndpdsdudxdzd}dd )3`%({WWEssJw6rEz^z^|{wz|l|lJ|6z$}k}kk}{J~4~40}P|5~e~e}x}j~}7!!S~-}b55A~?~FF3~M~ SS&~Z~8^^~d~Lhh~m~^qq ~u~mxx~|~{}w  rm'h0d8` A \$H$$X(O''U+V++R.]..N2d22K5j55H8q88E;w;;A?}>>elektroid-3.2.3/test/res/connectors/summit_wavetable.data.back000066400000000000000000000051661500236517400245430ustar00rootroot00000000000000 )3 NewName )3 @ )3 KL<]}x/6Yiq v xz{|}}~~~ )3 +?WEA?rCA ?wvA]?zA?{CA?|,A,?|uAn?}+A??}TA?}uA}?~Ae?~%AQ?~8A@?~HA1?~UA$?~bA?~lA?~vA?~~A~?Av? Ap?Aj?Ad?A_?$AZ?)AU?-AQ?1AM?5AI?9AF?<AB??A??BA<?EA9?HA6?KA4?NA1?PA/?SA,?UA*?WA(?YA&?[A$?^A!?`A?aA?cA?eA?gA?iA?kA?lA?nA?pA?qA?sA ?uA ?vA ?xA?yA?{A?}A?~A?A )3 @djWdsdvqdxvdzd{d{ed|&d|Yd}d}&d}Cd}\d}rd~d~d~%d~3d~?d~Jd~Td~]d~fd~nd~ud~|dd ddddd#d(d,d0d4d8d<d?dCdFdIdLdOdRdUdXd[d^dadcdfdidkdndpdsdudxdzd}dd )3 `%({WWEssJw6rEz^z^|{wz|l|lJ|6z$}k}kk}{J~4~40}P|5~e~e}x}j~}7!!S~-}b55A~?~FF3~M~ SS&~Z~8^^~d~Lhh~m~^qq ~u~mxx~|~{}w  rm'h0d8` A \$H$$X(O''U+V++R.]..N2d22K5j55H8q88E;w;;A?}>>elektroid-3.2.3/test/res/scala/000077500000000000000000000000001500236517400163375ustar00rootroot00000000000000elektroid-3.2.3/test/res/scala/TET.scl000066400000000000000000000001351500236517400174750ustar00rootroot00000000000000TET 12 100.0 200.0 300.0 400.0 500.0 600.0 700.0 800.0 900.0 1000.0 1100.0 2/1 elektroid-3.2.3/test/res/scala/no_notes.scl000066400000000000000000000000331500236517400206620ustar00rootroot00000000000000! scale !scala0 ! ! 2 elektroid-3.2.3/test/res/scala/perfect_5th.scl000066400000000000000000000001171500236517400212510ustar00rootroot00000000000000! Only 1 note Perfect 5th ! With double values 1 !Another comment 3/2 ! elektroid-3.2.3/test/res/scala/success.scl000066400000000000000000000001601500236517400205070ustar00rootroot00000000000000! Success ! 5-limit just intonation 12 ! 16/15 9/8 6/5 5/4 4/3 45/32 3/2 8/5 5/3 16/9 15/8 2/1 elektroid-3.2.3/test/res/scala/too_many_notes.scl000066400000000000000000000000761500236517400221020ustar00rootroot00000000000000Too many notes 1025 !The parser should not reach this line elektroid-3.2.3/test/res/scala/unmatching_notes.scl000066400000000000000000000000251500236517400224040ustar00rootroot00000000000000Unmatching notes 1 elektroid-3.2.3/test/tests_common.c000066400000000000000000000074451500236517400173530ustar00rootroot00000000000000#include #include #include #include #include "../src/utils.h" #include "../src/connectors/common.h" void test_common_slot_get_id_from_path () { guint id; gint err; printf ("\n"); err = common_slot_get_id_from_path ("", &id); CU_ASSERT_TRUE (err == -EINVAL); err = common_slot_get_id_from_path ("/", &id); CU_ASSERT_TRUE (err == -EINVAL); err = common_slot_get_id_from_path ("/1", &id); CU_ASSERT_TRUE (err == 0); CU_ASSERT_TRUE (id == 1); err = common_slot_get_id_from_path ("/p/1", &id); CU_ASSERT_TRUE (err == 0); CU_ASSERT_TRUE (id == 1); } void test_common_get_sanitized_name () { gchar *str; printf ("\n"); str = common_get_sanitized_name ("asdf", NULL, '?'); CU_ASSERT_STRING_EQUAL (str, "asdf"); g_free (str); str = common_get_sanitized_name ("ásdf", NULL, '?'); CU_ASSERT_STRING_EQUAL (str, "asdf"); g_free (str); str = common_get_sanitized_name ("asdf", "asd", '?'); CU_ASSERT_STRING_EQUAL (str, "asd?"); g_free (str); str = common_get_sanitized_name ("ásdf", "asd", '?'); CU_ASSERT_STRING_EQUAL (str, "asd?"); g_free (str); str = common_get_sanitized_name ("ásdf", "asd", 0); CU_ASSERT_STRING_EQUAL (str, "asd"); g_free (str); } void test_common_to_os_sanitized_name () { gchar *str = strdup ("\\^/"); printf ("\n"); common_to_os_sanitized_name (str); CU_ASSERT_STRING_EQUAL (str, "?^?"); g_free (str); } static const gchar *EXTS[] = { "ext", NULL }; static const gchar ** get_exts () { return EXTS; } void test_common_slot_get_download_path () { struct backend backend; struct fs_operations ops; gchar *path; struct idata idata; snprintf (backend.name, LABEL_MAX, "Dev Name"); ops.name = "fsname"; ops.get_exts = get_exts; idata_init (&idata, NULL, strdup ("name"), NULL); path = common_slot_get_download_path_n (&backend, &ops, "/dst_dir", "/1", &idata); CU_ASSERT_STRING_EQUAL ("/dst_dir/Dev Name fsname 1 - name.ext", path); g_free (path); path = common_slot_get_download_path_nn (&backend, &ops, "/dst_dir", "/1", &idata); CU_ASSERT_STRING_EQUAL ("/dst_dir/Dev Name fsname 01 - name.ext", path); g_free (path); path = common_slot_get_download_path_nnn (&backend, &ops, "/dst_dir", "/1", &idata); CU_ASSERT_STRING_EQUAL ("/dst_dir/Dev Name fsname 001 - name.ext", path); g_free (path); path = common_slot_get_download_path (&backend, &ops, "/dst_dir", "/1", &idata, 0); printf ("%s\n", path); CU_ASSERT_STRING_EQUAL ("/dst_dir/Dev Name fsname - name.ext", path); g_free (path); idata_free (&idata); idata_init (&idata, NULL, NULL, NULL); path = common_slot_get_download_path_n (&backend, &ops, "/dst_dir", "/1", &idata); CU_ASSERT_STRING_EQUAL ("/dst_dir/Dev Name fsname 1.ext", path); g_free (path); idata_free (&idata); } gint main (gint argc, gchar *argv[]) { gint err = 0; debug_level = 5; if (CU_initialize_registry () != CUE_SUCCESS) { goto cleanup; } CU_pSuite suite = CU_add_suite ("Elektroid common connector tests", 0, 0); if (!suite) { goto cleanup; } if (!CU_add_test (suite, "common_slot_get_id_from_path", test_common_slot_get_id_from_path)) { goto cleanup; } if (!CU_add_test (suite, "common_get_sanitized_name", test_common_get_sanitized_name)) { goto cleanup; } if (!CU_add_test (suite, "test_common_to_os_sanitized_name", test_common_to_os_sanitized_name)) { goto cleanup; } if (!CU_add_test (suite, "common_slot_get_download_path", test_common_slot_get_download_path)) { goto cleanup; } CU_basic_set_mode (CU_BRM_VERBOSE); CU_basic_run_tests (); err = CU_get_number_of_tests_failed (); cleanup: CU_cleanup_registry (); return err || CU_get_error (); } elektroid-3.2.3/test/tests_connector.c000066400000000000000000000026061500236517400200470ustar00rootroot00000000000000#include #include #include "../src/connector.h" void test_item_iterator_is_dir_or_matches_extensions () { const gchar *exts0[] = { NULL }; const gchar *exts1[] = { "ext1", NULL }; const gchar *exts2[] = { "ext2", NULL }; struct item_iterator iter; printf ("\n"); iter.item.type = ITEM_TYPE_DIR; CU_ASSERT_EQUAL (item_iterator_is_dir_or_matches_extensions (&iter, NULL), TRUE); CU_ASSERT_EQUAL (item_iterator_is_dir_or_matches_extensions (&iter, exts0), TRUE); iter.item.type = ITEM_TYPE_FILE; snprintf (iter.item.name, LABEL_MAX, "%s", "file.ext1"); CU_ASSERT_EQUAL (item_iterator_is_dir_or_matches_extensions (&iter, exts1), TRUE); CU_ASSERT_EQUAL (item_iterator_is_dir_or_matches_extensions (&iter, exts2), FALSE); } gint main (gint argc, gchar *argv[]) { gint err = 0; debug_level = 5; if (CU_initialize_registry () != CUE_SUCCESS) { goto cleanup; } CU_pSuite suite = CU_add_suite ("Elektroid connector tests", 0, 0); if (!suite) { goto cleanup; } if (!CU_add_test (suite, "item_iterator_is_dir_or_matches_extensions", test_item_iterator_is_dir_or_matches_extensions)) { goto cleanup; } CU_basic_set_mode (CU_BRM_VERBOSE); CU_basic_run_tests (); err = CU_get_number_of_tests_failed (); cleanup: CU_cleanup_registry (); return err || CU_get_error (); } elektroid-3.2.3/test/tests_elektron.c000066400000000000000000000130701500236517400176750ustar00rootroot00000000000000#include #include #include #include #include "../config.h" #include "../src/utils.h" #include "../src/connectors/package.h" #include "../src/connectors/elektron.h" gchar *elektron_get_dev_ext (struct backend *backend, const struct fs_operations *ops); const gchar **elektron_get_dev_exts (struct backend *backend, const struct fs_operations *ops); gint elektron_configure_device_from_file (struct backend *backend, guint8 id, const gchar * filename); void elektron_destroy_data (struct backend *backend); void test_elektron_get_dev_exts () { const gchar **exts; struct backend backend; struct elektron_data elektron_data; struct fs_operations ops = { .name = "fs0" }; backend.data = &elektron_data; elektron_data.device_desc.fs_descs_len = 1; snprintf (elektron_data.device_desc.fs_descs[0].name, LABEL_MAX, "%s", "fs0"); elektron_data.device_desc.fs_descs[0].extensions[0] = "ext0"; elektron_data.device_desc.fs_descs[0].extensions[1] = NULL; printf ("\n"); exts = elektron_get_dev_exts (&backend, &ops); CU_ASSERT_EQUAL (exts, elektron_data.device_desc.fs_descs[0].extensions); CU_ASSERT_EQUAL (strcmp (exts[0], "ext0"), 0); CU_ASSERT_EQUAL (exts[1], NULL); } static gint compare_exts (const gchar **a, const gchar **b) { const gchar **x = a; const gchar **y = b; while (*x) { if (strcmp (*x, *y)) { return 1; } x++; y++; } return *y != NULL; } void test_elektron_configure_device_from_file () { const gchar **exts; const struct fs_operations *ops; struct backend backend; struct elektron_data *elektron_data; static const gchar *DATA[] = { "data", NULL }; static const gchar *PRJ[] = { "dtprj", NULL }; static const gchar *SND[] = { "dtsnd", NULL }; printf ("\n"); elektron_data = g_malloc (sizeof (struct elektron_data)); backend.data = elektron_data; elektron_configure_device_from_file (&backend, 12, TEST_DATA_DIR "/../../res/elektron/devices.json"); CU_ASSERT_EQUAL (elektron_data->device_desc.fs_descs_len, 4); ops = backend_get_fs_operations_by_name (&backend, "sample"); exts = ops->get_exts (&backend, ops); CU_ASSERT_NOT_EQUAL (exts, NULL); //Several sample extensions ops = backend_get_fs_operations_by_name (&backend, "data"); exts = ops->get_exts (&backend, ops); CU_ASSERT_EQUAL (compare_exts (exts, DATA), 0); ops = backend_get_fs_operations_by_name (&backend, "project"); exts = ops->get_exts (&backend, ops); CU_ASSERT_EQUAL (compare_exts (exts, PRJ), 0); ops = backend_get_fs_operations_by_name (&backend, "sound"); exts = ops->get_exts (&backend, ops); CU_ASSERT_EQUAL (compare_exts (exts, SND), 0); CU_ASSERT_EQUAL (elektron_data->device_desc.storage, 3); elektron_destroy_data (&backend); CU_ASSERT_EQUAL (backend.data, NULL); } void test_elektron_special_exts () { const gchar **exts; const struct fs_operations *ops; struct backend backend; static const gchar *AHFX_PST[] = { "ahfxpst", "ahpst", NULL }; static const gchar *DTII_PRJ[] = { "dt2prj", "dtprj", NULL }; static const gchar *DTII_PST[] = { "dt2pst", "dtsnd", NULL }; static const gchar *DNII_PRJ[] = { "dn2prj", "dnprj", NULL }; static const gchar *DNII_PST[] = { "dn2pst", "dnsnd", NULL }; printf ("\n"); //Analog Heat +FX backend.data = g_malloc (sizeof (struct elektron_data)); elektron_configure_device_from_file (&backend, 32, TEST_DATA_DIR "/../../res/elektron/devices.json"); ops = backend_get_fs_operations_by_name (&backend, "preset"); exts = ops->get_exts (&backend, ops); CU_ASSERT_EQUAL (compare_exts (exts, AHFX_PST), 0); elektron_destroy_data (&backend); CU_ASSERT_EQUAL (backend.data, NULL); //Digitakt II backend.data = g_malloc (sizeof (struct elektron_data)); elektron_configure_device_from_file (&backend, 42, TEST_DATA_DIR "/../../res/elektron/devices.json"); ops = backend_get_fs_operations_by_name (&backend, "project"); exts = ops->get_exts (&backend, ops); CU_ASSERT_EQUAL (compare_exts (exts, DTII_PRJ), 0); ops = backend_get_fs_operations_by_name (&backend, "preset"); exts = ops->get_exts (&backend, ops); CU_ASSERT_EQUAL (compare_exts (exts, DTII_PST), 0); elektron_destroy_data (&backend); CU_ASSERT_EQUAL (backend.data, NULL); //Digitone II backend.data = g_malloc (sizeof (struct elektron_data)); elektron_configure_device_from_file (&backend, 43, TEST_DATA_DIR "/../../res/elektron/devices.json"); ops = backend_get_fs_operations_by_name (&backend, "project"); exts = ops->get_exts (&backend, ops); CU_ASSERT_EQUAL (compare_exts (exts, DNII_PRJ), 0); ops = backend_get_fs_operations_by_name (&backend, "preset"); exts = ops->get_exts (&backend, ops); CU_ASSERT_EQUAL (compare_exts (exts, DNII_PST), 0); elektron_destroy_data (&backend); CU_ASSERT_EQUAL (backend.data, NULL); } gint main (gint argc, gchar *argv[]) { gint err = 0; debug_level = 5; if (CU_initialize_registry () != CUE_SUCCESS) { goto cleanup; } CU_pSuite suite = CU_add_suite ("Elektroid elektron tests", 0, 0); if (!suite) { goto cleanup; } if (!CU_add_test (suite, "elektron_configure_device_from_file", test_elektron_configure_device_from_file)) { goto cleanup; } if (!CU_add_test (suite, "elektron_special_exts", test_elektron_special_exts)) { goto cleanup; } CU_basic_set_mode (CU_BRM_VERBOSE); CU_basic_run_tests (); err = CU_get_number_of_tests_failed (); cleanup: CU_cleanup_registry (); return err || CU_get_error (); } elektroid-3.2.3/test/tests_microfreak.c000066400000000000000000000143241500236517400201770ustar00rootroot00000000000000#include #include #include #include #include "../src/utils.h" #include "../src/connectors/microfreak.h" #define HEADER_PAYLOAD "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x10\x4e\x65\x72\x76\x6f\x75\x73\x4b\x65\x79\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" gint microfreak_serialize_preset (GByteArray * output, struct microfreak_preset *mfp); gint microfreak_deserialize_preset (struct microfreak_preset *mfp, GByteArray * input); gint microfreak_serialize_wavetable (struct idata *serialized, struct idata *wavetable); gint microfreak_deserialize_wavetable (struct idata *wavetable, struct idata *serialized); void microfreak_midi_msg_to_8bit_msg (guint8 *, guint8 *); void microfreak_8bit_msg_to_midi_msg (guint8 *, guint8 *); void test_serialization_deserialization_preset () { struct microfreak_preset mfp_src; struct microfreak_preset mfp_dst; gint err; GByteArray *serialized = g_byte_array_sized_new (64 * 1024); printf ("\n"); memcpy (mfp_src.header, HEADER_PAYLOAD, MICROFREAK_PRESET_HEADER_MSG_LEN); mfp_src.parts = MICROFREAK_PRESET_PARTS; for (guint i = 0; i < MICROFREAK_PRESET_DATALEN; i++) { mfp_src.data[i] = g_random_int () & 0x7f; } err = microfreak_serialize_preset (serialized, &mfp_src); CU_ASSERT_EQUAL (err, 0); err = microfreak_deserialize_preset (&mfp_dst, serialized); CU_ASSERT_EQUAL (err, 0); err = memcmp (mfp_src.header, mfp_dst.header, MICROFREAK_PRESET_HEADER_MSG_LEN); CU_ASSERT_EQUAL (err, 0); CU_ASSERT_EQUAL (mfp_dst.parts, mfp_src.parts); err = memcmp (mfp_src.data, mfp_dst.data, MICROFREAK_PRESET_DATALEN); CU_ASSERT_EQUAL (err, 0); } void test_serialization_deserialization_preset_init () { struct microfreak_preset mfp_src; struct microfreak_preset mfp_dst; gint err; GByteArray *serialized = g_byte_array_sized_new (64 * 1024); printf ("\n"); memcpy (mfp_src.header, HEADER_PAYLOAD, MICROFREAK_PRESET_HEADER_MSG_LEN); mfp_src.header[3] = 0x08; //Init mfp_src.parts = 0; err = microfreak_serialize_preset (serialized, &mfp_src); CU_ASSERT_EQUAL (err, 0); err = microfreak_deserialize_preset (&mfp_dst, serialized); CU_ASSERT_EQUAL (err, 0); err = memcmp (mfp_src.header, mfp_dst.header, MICROFREAK_PRESET_HEADER_MSG_LEN); CU_ASSERT_EQUAL (err, 0); CU_ASSERT_EQUAL (mfp_dst.parts, mfp_src.parts); } void test_serialization_deserialization_wavetable () { gint err; gint8 *v; struct idata src, dst, serialized; gchar *text; GByteArray *src_content; printf ("\n"); src_content = g_byte_array_sized_new (MICROFREAK_WAVETABLE_SIZE); src_content->len = MICROFREAK_WAVETABLE_SIZE; idata_init (&src, src_content, strdup ("0123456789abcde"), NULL); v = (gint8 *) src.content->data; for (guint i = 0; i < MICROFREAK_WAVETABLE_SIZE; i++, v++) { *v = (g_random_int () & 0xff) - 128; } text = debug_get_hex_data (debug_level, src.content->data, src.content->len); debug_print (0, "src (%d): %s\n", src.content->len, text); g_free (text); err = microfreak_serialize_wavetable (&serialized, &src); CU_ASSERT_EQUAL (err, 0); debug_print (0, "src (%d): %.*s\n", serialized.content->len, serialized.content->len, serialized.content->data); err = microfreak_deserialize_wavetable (&dst, &serialized); CU_ASSERT_EQUAL (err, 0); CU_ASSERT_EQUAL (dst.content->len, MICROFREAK_WAVETABLE_SIZE); CU_ASSERT_EQUAL (strcmp (dst.name, "0123456789abcde"), 0); text = debug_get_hex_data (debug_level, dst.content->data, dst.content->len); debug_print (0, "dst (%d): %s\n", dst.content->len, text); g_free (text); err = memcmp (src.content->data, dst.content->data, MICROFREAK_WAVETABLE_SIZE); CU_ASSERT_EQUAL (err, 0); idata_free (&src); idata_free (&dst); idata_free (&serialized); } void test_bad_deserialization_wavetable () { gint err; struct idata dst, serialized; GByteArray *serialized_content; printf ("\n"); serialized_content = g_byte_array_new (); idata_init (&serialized, serialized_content, NULL, NULL); err = microfreak_deserialize_wavetable (&dst, &serialized); CU_ASSERT_NOT_EQUAL (err, 0); idata_free (&serialized); } void test_8bit_header_conversions () { struct microfreak_sample_header src, dst; guint8 msg_midi[MICROFREAK_WAVE_MSG_SIZE]; gchar *text; guint8 *v = (guint8 *) & src; printf ("\n"); for (gint i = 0; i < sizeof (src); i++, v++) { *v = g_random_int () & 0xff; } snprintf (src.name, MICROFREAK_SAMPLE_NAME_LEN, "%s", "foo"); text = debug_get_hex_data (debug_level, (guint8 *) & src, sizeof (src)); debug_print (0, "src (%zd): %s\n", sizeof (src), text); g_free (text); microfreak_8bit_msg_to_midi_msg ((guint8 *) & src, msg_midi); text = debug_get_hex_data (debug_level, msg_midi, MICROFREAK_WAVE_MSG_SIZE); debug_print (0, "msg (%zd): %s\n", MICROFREAK_WAVE_MSG_SIZE, text); g_free (text); microfreak_midi_msg_to_8bit_msg (msg_midi, (guint8 *) & dst); text = debug_get_hex_data (debug_level, (guint8 *) & dst, sizeof (dst)); debug_print (0, "dst (%zd): %s\n", sizeof (dst), text); g_free (text); CU_ASSERT_EQUAL (memcmp (&src, &dst, sizeof (src)), 0); } gint main (gint argc, gchar *argv[]) { gint err = 0; debug_level = 5; if (CU_initialize_registry () != CUE_SUCCESS) { goto cleanup; } CU_pSuite suite = CU_add_suite ("Elektroid microfreak tests", 0, 0); if (!suite) { goto cleanup; } if (!CU_add_test (suite, "test_serialization_deserialization_preset", test_serialization_deserialization_preset)) { goto cleanup; } if (!CU_add_test (suite, "test_serialization_deserialization_preset_init", test_serialization_deserialization_preset_init)) { goto cleanup; } if (!CU_add_test (suite, "test_serialization_deserialization_wavetable", test_serialization_deserialization_wavetable)) { goto cleanup; } if (!CU_add_test (suite, "test_sample_header_conversions", test_8bit_header_conversions)) { goto cleanup; } CU_basic_set_mode (CU_BRM_VERBOSE); CU_basic_run_tests (); err = CU_get_number_of_tests_failed (); cleanup: CU_cleanup_registry (); return err || CU_get_error (); } elektroid-3.2.3/test/tests_sample.c000066400000000000000000000214741500236517400173420ustar00rootroot00000000000000#include #include #include "../src/sample.h" static void test_load_sample_resampling (struct job_control *control) { gint err; struct idata sample; struct sample_info sample_info_req; struct sample_info sample_info_src; struct sample_info *sample_info; printf ("\n"); sample_info_req.channels = 1; sample_info_req.rate = 48000; sample_info_req.format = SF_FORMAT_PCM_16; err = sample_load_from_file (TEST_DATA_DIR "/connectors/square-wav44.1k8b2c.wav", &sample, control, &sample_info_req, &sample_info_src); CU_ASSERT_EQUAL (err, 0); if (err) { return; } CU_ASSERT_EQUAL (sample_info_src.frames, 44100); CU_ASSERT_EQUAL (sample_info_src.loop_start, 5817); CU_ASSERT_EQUAL (sample_info_src.loop_end, 39793); CU_ASSERT_EQUAL (sample_info_src.loop_type, 0x7f); CU_ASSERT_EQUAL (sample_info_src.rate, 44100); CU_ASSERT_EQUAL (sample_info_src.format, SF_FORMAT_WAV | SF_FORMAT_PCM_U8); CU_ASSERT_EQUAL (sample_info_src.channels, 2); CU_ASSERT_EQUAL (sample_info_src.midi_note, 0); sample_info = sample.info; CU_ASSERT_EQUAL (sample_info->frames, 48000); CU_ASSERT_EQUAL (sample_info->loop_start, 6331); CU_ASSERT_EQUAL (sample_info->loop_end, 43312); CU_ASSERT_EQUAL (sample_info->loop_type, 0x7f); CU_ASSERT_EQUAL (sample_info->rate, 48000); CU_ASSERT_EQUAL (sample_info->format, SF_FORMAT_PCM_16); CU_ASSERT_EQUAL (sample_info->channels, 1); CU_ASSERT_EQUAL (sample_info->midi_note, 0); CU_ASSERT_EQUAL (sample.content->len, sample_info->frames * 2); CU_ASSERT_EQUAL (0, memcmp (sample.content->data, "\xa3\x03\x49\x4f\xeb\x6a\x51\x62", 8)); idata_free (&sample); } static void test_load_sample_control_resampling () { struct job_control control; control.active = TRUE; control.callback = NULL; g_mutex_init (&control.mutex); test_load_sample_resampling (&control); } static void test_load_sample_no_control_resampling () { test_load_sample_resampling (NULL); } static void test_load_sample_no_resampling (struct job_control *control) { gint err; struct idata sample; struct sample_info sample_info_req; struct sample_info sample_info_src; struct sample_info *sample_info; printf ("\n"); sample_info_req.channels = 1; sample_info_req.rate = 48000; sample_info_req.format = SF_FORMAT_PCM_16; err = sample_load_from_file (TEST_DATA_DIR "/connectors/square-wav48k16b1c.wav", &sample, control, &sample_info_req, &sample_info_src); CU_ASSERT_EQUAL (err, 0); if (err) { return; } CU_ASSERT_EQUAL (sample_info_src.frames, 48000); CU_ASSERT_EQUAL (sample_info_src.loop_start, 6331); CU_ASSERT_EQUAL (sample_info_src.loop_end, 43312); CU_ASSERT_EQUAL (sample_info_src.loop_type, 0x7f); CU_ASSERT_EQUAL (sample_info_src.rate, 48000); CU_ASSERT_EQUAL (sample_info_src.format, SF_FORMAT_WAV | SF_FORMAT_PCM_16); CU_ASSERT_EQUAL (sample_info_src.channels, 1); CU_ASSERT_EQUAL (sample_info_src.midi_note, 0); sample_info = sample.info; CU_ASSERT_EQUAL (sample_info->frames, 48000); CU_ASSERT_EQUAL (sample_info->loop_start, 6331); CU_ASSERT_EQUAL (sample_info->loop_end, 43312); CU_ASSERT_EQUAL (sample_info->loop_type, 0x7f); CU_ASSERT_EQUAL (sample_info->rate, 48000); CU_ASSERT_EQUAL (sample_info->format, SF_FORMAT_PCM_16); CU_ASSERT_EQUAL (sample_info->channels, 1); CU_ASSERT_EQUAL (sample_info->midi_note, 0); CU_ASSERT_EQUAL (sample.content->len, sample_info->frames * 2); CU_ASSERT_EQUAL (0, memcmp (sample.content->data, "\xff\xff\x8d\x53\xc8\x67\x1d\x66", 8)); idata_free (&sample); } static void test_load_sample_control_no_resampling () { struct job_control control; control.active = TRUE; control.callback = NULL; g_mutex_init (&control.mutex); test_load_sample_no_resampling (&control); } static void test_load_sample_no_control_no_resampling () { test_load_sample_no_resampling (NULL); } static void test_load_microfreak_wavetable (const gchar *path) { gint err; struct idata sample; struct sample_info sample_info_req; struct sample_info sample_info_src; struct sample_info *sample_info; printf ("\n"); sample_info_req.channels = 1; sample_info_req.rate = 48000; sample_info_req.format = SF_FORMAT_PCM_16; err = sample_load_from_file (path, &sample, NULL, &sample_info_req, &sample_info_src); CU_ASSERT_EQUAL (err, 0); if (err) { return; } CU_ASSERT_EQUAL (sample_info_src.frames, 8 * KI); CU_ASSERT_EQUAL (sample_info_src.loop_start, 0); CU_ASSERT_EQUAL (sample_info_src.loop_end, 8191); CU_ASSERT_EQUAL (sample_info_src.loop_type, 0); CU_ASSERT_EQUAL (sample_info_src.rate, 32000); CU_ASSERT_EQUAL (sample_info_src.format, SF_FORMAT_PCM_16); CU_ASSERT_EQUAL (sample_info_src.channels, 1); CU_ASSERT_EQUAL (sample_info_src.midi_note, 0); sample_info = sample.info; CU_ASSERT_EQUAL (sample_info->frames, 12288); CU_ASSERT_EQUAL (sample_info->loop_start, 0); CU_ASSERT_EQUAL (sample_info->loop_end, 12287); CU_ASSERT_EQUAL (sample_info->loop_type, 0); CU_ASSERT_EQUAL (sample_info->rate, 48000); CU_ASSERT_EQUAL (sample_info->format, SF_FORMAT_PCM_16); CU_ASSERT_EQUAL (sample_info->channels, 1); CU_ASSERT_EQUAL (sample_info->midi_note, 0); CU_ASSERT_EQUAL (sample.content->len, sample_info->frames * 2); CU_ASSERT_EQUAL (0, memcmp (sample.content->data, "\x40\xdc\x6b\xd7\x85\xdd\xbf\xdb", 8)); idata_free (&sample); } static void test_load_microfreak_mfw () { test_load_microfreak_wavetable (TEST_DATA_DIR "/connectors/microfreak.mfw"); } static void test_load_microfreak_mfwz () { test_load_microfreak_wavetable (TEST_DATA_DIR "/connectors/microfreak.mfwz"); } static void test_load_microfreak_sample (const gchar *path) { gint err; struct idata sample; struct sample_info sample_info_req; struct sample_info sample_info_src; struct sample_info *sample_info; printf ("\n"); sample_info_req.channels = 1; sample_info_req.rate = 48000; sample_info_req.format = SF_FORMAT_PCM_16; err = sample_load_from_file (path, &sample, NULL, &sample_info_req, &sample_info_src); CU_ASSERT_EQUAL (err, 0); if (err) { return; } CU_ASSERT_EQUAL (sample_info_src.frames, 800); CU_ASSERT_EQUAL (sample_info_src.loop_start, 0); CU_ASSERT_EQUAL (sample_info_src.loop_end, 799); CU_ASSERT_EQUAL (sample_info_src.loop_type, 0); CU_ASSERT_EQUAL (sample_info_src.rate, 32000); CU_ASSERT_EQUAL (sample_info_src.format, SF_FORMAT_PCM_16); CU_ASSERT_EQUAL (sample_info_src.channels, 1); CU_ASSERT_EQUAL (sample_info_src.midi_note, 0); sample_info = sample.info; CU_ASSERT_EQUAL (sample_info->frames, 1200); CU_ASSERT_EQUAL (sample_info->loop_start, 0); CU_ASSERT_EQUAL (sample_info->loop_end, 1199); CU_ASSERT_EQUAL (sample_info->loop_type, 0); CU_ASSERT_EQUAL (sample_info->rate, 48000); CU_ASSERT_EQUAL (sample_info->format, SF_FORMAT_PCM_16); CU_ASSERT_EQUAL (sample_info->channels, 1); CU_ASSERT_EQUAL (sample_info->midi_note, 0); CU_ASSERT_EQUAL (sample.content->len, sample_info->frames * 2); CU_ASSERT_EQUAL (0, memcmp (sample.content->data, "\xc9\x4c\xe3\x56\x61\x49\xce\x4c", 8)); idata_free (&sample); } static void test_load_microfreak_mfs () { test_load_microfreak_sample (TEST_DATA_DIR "/connectors/microfreak.mfs"); } static void test_load_microfreak_mfsz () { test_load_microfreak_sample (TEST_DATA_DIR "/connectors/microfreak.mfsz"); } gint main (gint argc, gchar *argv[]) { gint err = 0; debug_level = 5; if (CU_initialize_registry () != CUE_SUCCESS) { goto cleanup; } CU_pSuite suite = CU_add_suite ("Elektroid sample tests", 0, 0); if (!suite) { goto cleanup; } if (!CU_add_test (suite, "load_sample_control_resampling", test_load_sample_control_resampling)) { goto cleanup; } if (!CU_add_test (suite, "load_sample_no_control_resampling", test_load_sample_no_control_resampling)) { goto cleanup; } if (!CU_add_test (suite, "load_sample_control_no_resampling", test_load_sample_control_no_resampling)) { goto cleanup; } if (!CU_add_test (suite, "load_sample_no_control_no_resampling", test_load_sample_no_control_no_resampling)) { goto cleanup; } if (!CU_add_test (suite, "load_microfreak_mfw", test_load_microfreak_mfw)) { goto cleanup; } if (!CU_add_test (suite, "load_microfreak_mfwz", test_load_microfreak_mfwz)) { goto cleanup; } if (!CU_add_test (suite, "load_microfreak_mfs", test_load_microfreak_mfs)) { goto cleanup; } if (!CU_add_test (suite, "load_microfreak_mfsz", test_load_microfreak_mfsz)) { goto cleanup; } CU_basic_set_mode (CU_BRM_VERBOSE); CU_basic_run_tests (); err = CU_get_number_of_tests_failed (); cleanup: CU_cleanup_registry (); return err || CU_get_error (); } elektroid-3.2.3/test/tests_scala.c000066400000000000000000000217021500236517400171360ustar00rootroot00000000000000#include #include #include #include #include "../src/utils.h" #include "../src/connectors/scala.h" #define TEST_MAX_FILE_LEN 1024 gint scl_init_scala_from_bytes (struct scala *scala, GByteArray * input); static const guint8 SUCCESS_OCTAVE_MIDI_MSG[] = { 0xf0, 0x7e, 0x7f, 8, 6, 0, //bank 0, //tuning 0x35, 0x2d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x20, 0x6a, 0x75, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, //name 0x40, 0x00, //pitches 0x47, 0x41, 0x42, 0x40, 0x4a, 0x01, 0x37, 0x1e, 0x3e, 0x5f, 0x39, 0x5f, 0x41, 0x20, 0x48, 0x61, 0x35, 0x7e, 0x3d, 0x3f, 0x38, 0x3e, 0x2f, //cksum 0xf7 }; static const guint8 SUCCESS_BULK_MIDI_MSG_HEADER[] = { 0xf0, 0x7e, 0x7f, 8, 1, 0, //tuning 0x35, 0x2d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x20, 0x6a, 0x75, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74 //name }; static const guint8 SUCCESS_BULK_MIDI_MSG_OCTAVE_DATA[] = { 0x00, 0x00, 0x00, 0x01, 0x0f, 0x03, 0x02, 0x05, 0x00, 0x03, 0x14, 0x04, 0x03, 0x6e, 0x45, 0x04, 0x7d, 0x48, 0x05, 0x73, 0x46, 0x07, 0x02, 0x40, 0x08, 0x11, 0x43, 0x08, 0x6c, 0x05, 0x09, 0x7b, 0x08, 0x0a, 0x71, 0x06 }; static const guint8 SUCCESS_OCTAVE_MIDI_MSG_TET[] = { 0xf0, 0x7e, 0x7f, 8, 6, 0, //bank 0, //tuning 0x54, 0x45, 0x54, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, //name 0x40, 0x00, //pitches 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x6a, //cksum 0xf7 }; static const guint8 SUCCESS_BULK_MIDI_MSG_HEADER_TET[] = { 0xf0, 0x7e, 0x7f, 8, 1, 0, //tuning 0x54, 0x45, 0x54, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 //name }; void test_success () { struct scala scala; struct idata idata; gint err; printf ("\n"); file_load (TEST_DATA_DIR "/scala/success.scl", &idata, NULL); err = scl_init_scala_from_bytes (&scala, idata.content); idata_free (&idata); CU_ASSERT_EQUAL (err, 0); CU_ASSERT_STRING_EQUAL (scala.desc, "5-limit just intonation"); CU_ASSERT_EQUAL (scala.notes, 12); CU_ASSERT_EQUAL (scala.pitches[0], 16 / (double) 15); CU_ASSERT_EQUAL (scala.pitches[1], 9 / (double) 8); CU_ASSERT_EQUAL (scala.pitches[2], 6 / (double) 5); CU_ASSERT_EQUAL (scala.pitches[3], 5 / (double) 4); CU_ASSERT_EQUAL (scala.pitches[4], 4 / (double) 3); CU_ASSERT_EQUAL (scala.pitches[5], 45 / (double) 32); CU_ASSERT_EQUAL (scala.pitches[6], 3 / (double) 2); CU_ASSERT_EQUAL (scala.pitches[7], 8 / (double) 5); CU_ASSERT_EQUAL (scala.pitches[8], 5 / (double) 3); CU_ASSERT_EQUAL (scala.pitches[9], 16 / (double) 9); CU_ASSERT_EQUAL (scala.pitches[10], 15 / (double) 8); CU_ASSERT_EQUAL (scala.pitches[11], 2 / (double) 1); } void test_success_perfect_5th () { struct scala scala; struct idata idata; gint err; printf ("\n"); file_load (TEST_DATA_DIR "/scala/perfect_5th.scl", &idata, NULL); err = scl_init_scala_from_bytes (&scala, idata.content); idata_free (&idata); CU_ASSERT_EQUAL (err, 0); CU_ASSERT_STRING_EQUAL (scala.desc, "Perfect 5th"); CU_ASSERT_EQUAL (scala.notes, 1); CU_ASSERT_EQUAL (scala.pitches[0], 1.5); } void test_empty_file () { struct scala scala; GByteArray *data; gint err; printf ("\n"); data = g_byte_array_sized_new (0); err = scl_init_scala_from_bytes (&scala, data); CU_ASSERT_EQUAL (err, -EINVAL); g_byte_array_free (data, TRUE); } void test_too_many_notes () { struct scala scala; struct idata idata; gint err; printf ("\n"); file_load (TEST_DATA_DIR "/scala/too_many_notes.scl", &idata, NULL); err = scl_init_scala_from_bytes (&scala, idata.content); CU_ASSERT_EQUAL (err, -ERANGE); idata_free (&idata); } void test_no_notes () { struct scala scala; struct idata idata; gint err; printf ("\n"); file_load (TEST_DATA_DIR "/scala/no_notes.scl", &idata, NULL); err = scl_init_scala_from_bytes (&scala, idata.content); CU_ASSERT_EQUAL (err, -ERANGE); idata_free (&idata); } void test_unmatching_notes () { struct scala scala; struct idata idata; gint err; printf ("\n"); file_load (TEST_DATA_DIR "/scala/unmatching_notes.scl", &idata, NULL); err = scl_init_scala_from_bytes (&scala, idata.content); CU_ASSERT_EQUAL (err, -EINVAL); idata_free (&idata); } void test_get_2_byte_octave_midi_message () { struct idata idata; gint err; printf ("\n"); err = scl_load_2_byte_octave_tuning_msg_from_scala_file (TEST_DATA_DIR "/scala/success.scl", &idata, NULL); CU_ASSERT_EQUAL (err, 0); CU_ASSERT_EQUAL (idata.content->len, sizeof (SUCCESS_OCTAVE_MIDI_MSG)); CU_ASSERT_EQUAL (memcmp (idata.content->data, SUCCESS_OCTAVE_MIDI_MSG, sizeof (SUCCESS_OCTAVE_MIDI_MSG)), 0); idata_free (&idata); } void test_get_bulk_tuning_midi_message () { gint err; struct idata idata; guint8 *b, *f_data; printf ("\n"); err = scl_load_key_based_tuning_msg_from_scala_file (TEST_DATA_DIR "/scala/success.scl", &idata, NULL); CU_ASSERT_EQUAL (err, 0); CU_ASSERT_EQUAL (idata.content->len, SCALA_TUNING_BANK_SIZE); CU_ASSERT_EQUAL (memcmp (idata.content->data, SUCCESS_BULK_MIDI_MSG_HEADER, sizeof (SUCCESS_BULK_MIDI_MSG_HEADER)), 0); //Test the first octave. f_data = idata.content->data + sizeof (SUCCESS_BULK_MIDI_MSG_HEADER); CU_ASSERT_EQUAL (memcmp (f_data, SUCCESS_BULK_MIDI_MSG_OCTAVE_DATA, sizeof (SUCCESS_BULK_MIDI_MSG_OCTAVE_DATA)), 0); //Test the nots above the first octave by comparing them to the notes in the first one. b = f_data + 12 * 3; for (guint8 i = 12; i < SCALA_MIDI_NOTES; i++, b += 3) { gint offset = (i % 12) * 3; gint octave = (i / 12) * 12; CU_ASSERT_EQUAL (*b, *(f_data + offset) + octave); CU_ASSERT_EQUAL (*(b + 1), *(f_data + offset + 1)); CU_ASSERT_EQUAL (*(b + 2), *(f_data + offset + 2)); } CU_ASSERT_EQUAL (idata.content->data[406], 0x03); CU_ASSERT_EQUAL (idata.content->data[407], 0xf7); idata_free (&idata); } void test_get_2_byte_octave_midi_message_test () { struct idata idata; gint err; printf ("\n"); err = scl_load_2_byte_octave_tuning_msg_from_scala_file (TEST_DATA_DIR "/scala/TET.scl", &idata, NULL); CU_ASSERT_EQUAL (err, 0); CU_ASSERT_EQUAL (idata.content->len, sizeof (SUCCESS_OCTAVE_MIDI_MSG_TET)); CU_ASSERT_EQUAL (memcmp (idata.content->data, SUCCESS_OCTAVE_MIDI_MSG_TET, sizeof (SUCCESS_OCTAVE_MIDI_MSG_TET)), 0); idata_free (&idata); } void test_get_bulk_tuning_midi_message_tet () { gint err; guint8 *b; struct idata idata; printf ("\n"); err = scl_load_key_based_tuning_msg_from_scala_file (TEST_DATA_DIR "/scala/TET.scl", &idata, NULL); CU_ASSERT_EQUAL (err, 0); CU_ASSERT_EQUAL (idata.content->len, SCALA_TUNING_BANK_SIZE); CU_ASSERT_EQUAL (memcmp (idata.content->data, SUCCESS_BULK_MIDI_MSG_HEADER_TET, sizeof (SUCCESS_BULK_MIDI_MSG_HEADER_TET)), 0); b = idata.content->data + sizeof (SUCCESS_BULK_MIDI_MSG_HEADER_TET); for (guint8 i = 0; i < SCALA_MIDI_NOTES; i++, b += 3) { CU_ASSERT_EQUAL (*b, i); CU_ASSERT_EQUAL (*(b + 1), 0); CU_ASSERT_EQUAL (*(b + 2), 0); } CU_ASSERT_EQUAL (idata.content->data[406], 0x6d); CU_ASSERT_EQUAL (idata.content->data[407], 0xf7); idata_free (&idata); } gint main (gint argc, gchar *argv[]) { gint err = 0; debug_level = 5; if (CU_initialize_registry () != CUE_SUCCESS) { goto cleanup; } CU_pSuite suite = CU_add_suite ("Elektroid scala tests", 0, 0); if (!suite) { goto cleanup; } if (!CU_add_test (suite, "test_success", test_success)) { goto cleanup; } if (!CU_add_test (suite, "success_perfect_5th", test_success_perfect_5th)) { goto cleanup; } if (!CU_add_test (suite, "test_empty_file", test_empty_file)) { goto cleanup; } if (!CU_add_test (suite, "test_too_many_notes", test_too_many_notes)) { goto cleanup; } if (!CU_add_test (suite, "no_notes", test_no_notes)) { goto cleanup; } if (!CU_add_test (suite, "unmatching_notes", test_unmatching_notes)) { goto cleanup; } if (!CU_add_test (suite, "test_get_2_byte_octave_midi_message", test_get_2_byte_octave_midi_message)) { goto cleanup; } if (!CU_add_test (suite, "test_get_bulk_tuning_midi_message", test_get_bulk_tuning_midi_message)) { goto cleanup; } if (!CU_add_test (suite, "test_get_2_byte_octave_midi_message_test", test_get_2_byte_octave_midi_message_test)) { goto cleanup; } if (!CU_add_test (suite, "test_get_bulk_tuning_midi_message_tet", test_get_bulk_tuning_midi_message_tet)) { goto cleanup; } CU_basic_set_mode (CU_BRM_VERBOSE); CU_basic_run_tests (); err = CU_get_number_of_tests_failed (); cleanup: CU_cleanup_registry (); return err || CU_get_error (); } elektroid-3.2.3/test/tests_utils.c000066400000000000000000000031161500236517400172120ustar00rootroot00000000000000#include #include #include "../src/utils.h" void test_file_matches_extensions () { const gchar *exts0[] = { NULL }; const gchar *exts1[] = { "ext1", NULL }; const gchar *exts2[] = { "ext1", "ext2", NULL }; printf ("\n"); CU_ASSERT_EQUAL (file_matches_extensions ("file.ext1", NULL), TRUE); CU_ASSERT_EQUAL (file_matches_extensions ("file.ext1", exts0), FALSE); CU_ASSERT_EQUAL (file_matches_extensions ("file", exts1), FALSE); CU_ASSERT_EQUAL (file_matches_extensions ("file.ext1", exts1), TRUE); CU_ASSERT_EQUAL (file_matches_extensions ("file.ext2", exts2), TRUE); CU_ASSERT_EQUAL (file_matches_extensions ("file.eXt2", exts2), TRUE); } void test_filename_get_ext () { printf ("\n"); CU_ASSERT_STRING_EQUAL ("", filename_get_ext ("file")); CU_ASSERT_STRING_EQUAL ("", filename_get_ext ("file.")); CU_ASSERT_STRING_EQUAL ("ext1", filename_get_ext ("file.ext2.ext1")); } gint main (gint argc, gchar *argv[]) { gint err = 0; debug_level = 5; if (CU_initialize_registry () != CUE_SUCCESS) { goto cleanup; } CU_pSuite suite = CU_add_suite ("Elektroid utils tests", 0, 0); if (!suite) { goto cleanup; } if (!CU_add_test (suite, "file_matches_extensions", test_file_matches_extensions)) { goto cleanup; } if (!CU_add_test (suite, "filename_get_ext", test_filename_get_ext)) { goto cleanup; } CU_basic_set_mode (CU_BRM_VERBOSE); CU_basic_run_tests (); err = CU_get_number_of_tests_failed (); cleanup: CU_cleanup_registry (); return err || CU_get_error (); }