pax_global_header00006660000000000000000000000064147551353310014521gustar00rootroot0000000000000052 comment=7c11a0ecbc99f57ba883d415eae9ed19c725d672 ibus-table-1.17.11/000077500000000000000000000000001475513533100137205ustar00rootroot00000000000000ibus-table-1.17.11/.github/000077500000000000000000000000001475513533100152605ustar00rootroot00000000000000ibus-table-1.17.11/.github/ISSUE_TEMPLATE/000077500000000000000000000000001475513533100174435ustar00rootroot00000000000000ibus-table-1.17.11/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000021651475513533100221410ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: "[BUG]" labels: bug assignees: mike-fabian --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots or videos** If applicable, add screenshots or videos to help explain your problem. **ibus-table version?** Open the ibus-table setup tool and click on the `About` button (Or check the version of the installed package, for example using `rpm -q ibus-table` on rpm based distribtions). **ibus version?** Run `ibus version` (Or check the version of the installed package, for example using `rpm -q ibus` on rpm based distribtions). **Distribution and version?** For example Fedora 35, Ubuntu 20.04, FreeBSD 11.1, … **Desktop and version?** For example Gnome 3, KDE, XFCE, i3, ... **Xorg or Wayland?** You can check this with `echo $XDG_SESSION_TYPE` **Additional context** Add any other context about the problem here. ibus-table-1.17.11/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000011741475513533100231730ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: "[ENHANCEMENT]" labels: enhancement assignees: mike-fabian --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots or videos about the feature request here. ibus-table-1.17.11/.gitignore000066400000000000000000000004151475513533100157100ustar00rootroot00000000000000/INSTALL /ABOUT-NLS compile Makefile Makefile.in /aclocal.m4 /config.guess /config.log /config.rpath /config.status /config.sub /configure /install-sh /autom4te.cache/ ibus-table.pc ibus-table.spec /missing /py-compile ibus-table-*.tar.gz *.metainfo.xml test-driver *~ ibus-table-1.17.11/AUTHORS000066400000000000000000000002741475513533100147730ustar00rootroot00000000000000Original Author(s) YU Yuwei (acevery) Developer(s) Caius "kaio" CHANCE MA Xiaojun Mike FABIAN ibus-table-1.17.11/COPYING000066400000000000000000000635041475513533100147630ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ibus-table-1.17.11/ChangeLog000066400000000000000000014475401475513533100155110ustar00rootroot00000000000000commit 521770ec32e5d0eb0449c27230dbca5d1e894c00 Author: Mike FABIAN Date: Tue Feb 18 17:35:29 2025 +0100 Release 1.17.11 commit 7b336c5a9d8a77f13ada1e53a6698358bae15486 Author: Mike FABIAN Date: Tue Feb 18 17:26:20 2025 +0100 Calling static methods as `self._my_method()` works, but is not recommended, use `self.__class__._my_method()` commit 9e35493874cf1e6cb651f419928df2c09fe1e3e5 Author: Mike FABIAN Date: Tue Feb 18 16:19:27 2025 +0100 Fix to load EN compose file Now EN compose file is loaded in the class init of IBus.EngineSimple and IBus.init() needs to be called before the init. This fix is needed for ibus >= 1.5.32~beta2. See also: https://github.com/ibus/ibus-anthy/commit/14b2759772fb1adc67453108e958bf0bf181ce1d commit 40764b0a634375f53bd637ff22066d0354770226 Author: Sergey A Date: Sat Feb 15 16:51:20 2025 +0100 Translated using Weblate (Russian) Currently translated at 98.6% (150 of 152 strings) Co-authored-by: Sergey A Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ru/ Translation: ibus-table/app commit 878f802810b9689318d988810ac754e817833a23 Author: N M Date: Tue Feb 4 18:38:36 2025 +0100 Translated using Weblate (Spanish) Currently translated at 96.7% (147 of 152 strings) Co-authored-by: N M Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translation: ibus-table/app commit 3a16e44367d39279e6fb98d7c31c5bc43567f9c7 Author: Weblate Date: Tue Jan 21 10:15:42 2025 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 8b0f3567dae83e2e876a6dc0ffbfa5f1faa10fdf Author: Mike FABIAN Date: Tue Jan 21 10:15:42 2025 +0100 Translated using Weblate (French) Currently translated at 100.0% (152 of 152 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ Translation: ibus-table/app commit 287dd34734018daa89de456d25d62d6b59a9e12c Author: Mike FABIAN Date: Tue Jan 21 01:18:54 2025 +0100 Release 1.17.10 commit 61ffe389fb396d98540a3f15f1b4500db3d4fed1 Author: Mike FABIAN Date: Tue Jan 21 01:39:32 2025 +0100 Update ibus-table.pot (Only line number changes) commit 1ad83aea17469cea8042fb0913fcdb7986b27c11 Author: Mike FABIAN Date: Tue Jan 21 01:59:02 2025 +0100 Add the generated .desktop files to the tarball (Avoids gettext dependency when building from the tarball) commit a3265a7bfe64839ae223f18fe2493ffa46bbf918 Author: Mike FABIAN Date: Tue Jan 21 00:47:38 2025 +0100 Generate translations into metainfo.xml files with autotools Resolves: https://github.com/mike-fabian/ibus-table/issues/171 commit 42bd3b4770d5fd38bf69b12635bd598158ff082a Author: Yuri Chornoivan Date: Tue Jan 21 00:19:30 2025 +0100 Translated using Weblate (Ukrainian) Currently translated at 100.0% (152 of 152 strings) Co-authored-by: Yuri Chornoivan Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ Translation: ibus-table/app commit 0846d2521b69cc164ced0326a7de67f4f1c1f954 Author: Oğuz Ersen Date: Sun Jan 19 20:57:51 2025 +0100 Translated using Weblate (Turkish) Currently translated at 100.0% (152 of 152 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translation: ibus-table/app commit 5448e7047a99fbf89aebf9cd994914bdabcae208 Author: Weblate Date: Sun Jan 19 02:57:54 2025 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 76b94b085df2a10161c261cf0eee4173fd8845cf Author: Mike FABIAN Date: Sun Jan 19 03:01:35 2025 +0100 Update ibus-table.pot (Only line number changes) commit 21781e4589b465f5275b14561a738b75ff208238 Author: Mike FABIAN Date: Sun Jan 19 02:59:07 2025 +0100 Rename ibus-table.appdata.xml, see also: https://github.com/mike-fabian/ibus-typing-booster/issues/598 commit 33cdd35fe1fdb17011a43162621f0dc343e38d36 Author: Mike FABIAN Date: Sun Jan 19 02:44:08 2025 +0100 Translated using Weblate (Japanese) Currently translated at 48.0% (73 of 152 strings) Translated using Weblate (German) Currently translated at 100.0% (152 of 152 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ja/ Translation: ibus-table/app commit c80bf4d817a2c9fa081e259a2c16c08a54234fe9 Author: Weblate Date: Sun Jan 19 02:39:08 2025 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 3de89b2d682be2529de621ff177e028e198c36fd Author: Mike FABIAN Date: Sun Jan 19 02:42:11 2025 +0100 Update ibus-table.pot (2 new messages for translation of “Name” and “Comment” in ibus-setup-table.desktop) commit c2a0defb843509a6f078b69508169decfb430726 Author: Mike FABIAN Date: Sun Jan 19 02:25:02 2025 +0100 Make desktop file translatable and generate translations into desktop file commit 841c70b85bb2869403acffbeab1f4e9e6b07bb4a Author: Mike FABIAN Date: Sun Jan 19 02:27:53 2025 +0100 Fix mypy warnings commit bdda5ca03e20933bf066a4e0256d94f9cfb53fd0 Author: Sergey A Date: Tue Jan 7 13:38:47 2025 +0100 Translated using Weblate (Russian) Currently translated at 98.6% (148 of 150 strings) Co-authored-by: Sergey A Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ru/ Translation: ibus-table/app commit a7c852b22ec7b0c83e94815591e13ec76d69bbb7 Author: Sergey A Date: Sat Jan 4 22:20:35 2025 +0100 Translated using Weblate (Russian) Currently translated at 98.0% (147 of 150 strings) Co-authored-by: Sergey A Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ru/ Translation: ibus-table/app commit 65de56eac725ba4aa91147ca2477a119263a72a2 Author: Weblate Date: Wed Dec 11 15:10:16 2024 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 825ddfba9dad832b18471c7bfb95a7243c6d3f77 Author: Mike FABIAN Date: Wed Dec 11 14:30:45 2024 +0100 Release 1.17.9 commit 0a1e272f577640740b4d1842a2cbc6267cf28cce Author: Mike FABIAN Date: Wed Dec 11 14:32:40 2024 +0100 Update ibus-table.pot (Only line number changes) commit b805f48d8563975cb4313c714cb94ce009b23c7e Author: Mike FABIAN Date: Wed Dec 11 14:22:02 2024 +0100 Make the setup tool use the wrapper itb_sound.py instead of using simpleaudio unconditionally Resolves: https://github.com/mike-fabian/ibus-table/issues/162 commit fa864522898b4dc3b3fdcead91175ac05c6cad13 Author: Mike FABIAN Date: Wed Dec 11 14:20:51 2024 +0100 Add more debug output commit 0b752dfdf49d8cda859a8cdfc82ff7825dce75f6 Author: Mike FABIAN Date: Wed Dec 11 14:17:40 2024 +0100 Fix some mypy warnings which appeared after the upgrade to Fedora 41 (python3-mypy-1.13.0-1.fc41.noarch) commit 01e2632164c98b610bc157faa68f2d761c4e416a Author: Mike FABIAN Date: Wed Dec 11 14:14:18 2024 +0100 Improve it_util.variant_to_value() commit 8c6896387959f9cd855434d96aef710abcf6915a Author: ButterflyOfFire Date: Thu Nov 21 17:38:41 2024 +0100 Translated using Weblate (Kabyle) Currently translated at 29.3% (44 of 150 strings) Co-authored-by: ButterflyOfFire Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/kab/ Translation: ibus-table/app commit 16176b40840ff0a381ed035235581f6a2a19dc40 Author: Weblate Translation Memory Date: Thu Oct 24 11:38:33 2024 +0200 Translated using Weblate (Kabyle) Currently translated at 29.3% (44 of 150 strings) Co-authored-by: Weblate Translation Memory Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/kab/ Translation: ibus-table/app commit 67d1e8e63a7e7b420dafe805522c118404a5ef10 Author: ButterflyOfFire Date: Thu Oct 24 11:38:33 2024 +0200 Translated using Weblate (Kabyle) Currently translated at 29.3% (44 of 150 strings) Added translation using Weblate (Kabyle) Co-authored-by: ButterflyOfFire Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/kab/ Translation: ibus-table/app commit 31707f63f73edd08ea0107fb581934207e5aea0c Author: Mike FABIAN Date: Wed Sep 11 16:43:28 2024 +0200 Release 1.17.8 commit 36054877febf633daa90dd0faa22e5cf54b87084 Author: Mike FABIAN Date: Wed Sep 11 17:00:22 2024 +0200 Update Unihan_Variants.txt and regenerate engine/chinese_variants.py for Unicode 16.0.0 release - Update Unihan_Variants.txt from “2023-07-15 Unicode 15.1.0” to “2024-07-31 Unicode version: 16.0.0” - Regenerate engine/chinese_variants.py for Unihan_Variants.txt commit cd6a4ed0d09f3f3e5d9b291ea5ae9b273a8f98c8 Author: Weblate Translation Memory Date: Sun Sep 8 12:38:29 2024 +0200 Translated using Weblate (Greek) Currently translated at 17.3% (26 of 150 strings) Co-authored-by: Weblate Translation Memory Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/el/ Translation: ibus-table/app commit 36db5ffa3ea2da492e801f0a383116f417f250fb Author: Giannis Antypas Date: Sun Sep 8 12:38:29 2024 +0200 Translated using Weblate (Greek) Currently translated at 17.3% (26 of 150 strings) Added translation using Weblate (Greek) Co-authored-by: Giannis Antypas Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/el/ Translation: ibus-table/app commit ddd30b8c6b2485b866a077d1bb1d6ac9ddd08727 Author: Mike FABIAN Date: Sun Aug 25 19:52:28 2024 +0200 Release 1.17.7 commit 19d632adad8326510296e39c776f7074688f1684 Author: Mike FABIAN Date: Sun Aug 25 18:48:08 2024 +0200 Translated using Weblate (French) Currently translated at 100.0% (150 of 150 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ Translation: ibus-table/app commit c5050577926ca625ecc57441f295f8a47ab851cc Author: Léane GRASSER Date: Fri Aug 23 15:36:06 2024 +0200 Translated using Weblate (French) Currently translated at 100.0% (150 of 150 strings) Co-authored-by: Léane GRASSER Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ Translation: ibus-table/app commit bcaa9d820fb0be3281063ca181f8c72f47605687 Author: Sergey A Date: Fri Aug 23 15:36:06 2024 +0200 Translated using Weblate (Russian) Currently translated at 93.3% (140 of 150 strings) Co-authored-by: Sergey A Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ru/ Translation: ibus-table/app commit 374b32d49126feaa1b3d5c36d2927f4cab08d5f2 Author: Sergey A Date: Tue Jul 30 09:02:36 2024 +0200 Translated using Weblate (Russian) Currently translated at 92.6% (139 of 150 strings) Co-authored-by: Sergey A Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ru/ Translation: ibus-table/app commit 8386ac2ce1ab543515605d4e7f96b69fc995d589 Author: Sergey A Date: Sun Jul 28 12:38:40 2024 +0200 Translated using Weblate (Russian) Currently translated at 87.3% (131 of 150 strings) Co-authored-by: Sergey A Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ru/ Translation: ibus-table/app commit f1aaf7998d72d127bd91ebbe1a8d656f8cb36460 Author: Weblate Date: Thu Jun 27 14:38:22 2024 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit f4a9e2746ba420fc798e2d9258075d8a309964fe Author: Mike FABIAN Date: Thu Jun 27 14:40:56 2024 +0200 Fix typo in comment commit 46ccd315f4f0cfaa3c6cc675f228c2df247a0a06 Author: Mike FABIAN Date: Thu Jun 27 09:47:45 2024 +0200 Release 1.17.6 commit b2cbc7af2adf8820fac36c7630211cd86ae0a1ab Author: Mike FABIAN Date: Thu Jun 27 09:49:36 2024 +0200 Update ibus-table.pot (Only line number changes) commit 72e6d9d64905c58337bd9d60a62f9174e610cfd7 Author: Mike FABIAN Date: Thu Jun 27 09:41:40 2024 +0200 Yet another fix to make it possible again to use keys with Unicode keysyms in keybindings and make it work with all known versions of ibus Resolves: https://github.com/kaio/ibus-table/issues/85 See also: https://github.com/mike-fabian/ibus-typing-booster/issues/497 This makes the code work both with older ibus (<= 1.5.29) which does >>> IBus.keyval_name(0x0100263a) 'U+263A' >>> and newer ibus (>= 1.5.31 or 1.5.30 with some patches) which does: >>> IBus.keyval_name(0x0100263a) '0x100263a' >>> So this should work with all currently known versions of ibus. commit ebc56a23362f953a21804245a1ea2382341efa8e Author: Weblate Translation Memory Date: Wed Jun 26 17:36:08 2024 +0200 Translated using Weblate (Czech) Currently translated at 40.0% (60 of 150 strings) Co-authored-by: Weblate Translation Memory Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/cs/ Translation: ibus-table/app commit 0d64bd3149ae95e673ba1f46774571129c699302 Author: Weblate Date: Tue Jun 25 17:30:32 2024 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit a18bca96e4f04db6e96a670bc8b021d41c38aeab Author: Mike FABIAN Date: Wed Jun 19 12:03:50 2024 +0200 Release 1.17.5 commit 3eba07a6622c475f3828af92ebed2b2c4da158c8 Author: Mike FABIAN Date: Wed Jun 19 10:24:52 2024 +0200 Update ibus-table.pot (Only line number changes) commit 14b06afa2b7fbe2af30b1d0b0f426647a3ffd861 Author: Mike FABIAN Date: Wed Jun 19 11:53:31 2024 +0200 Fix for ibus-1.5.30: Make it possible again to use keys with Unicode keysyms in keybindings See: https://github.com/mike-fabian/ibus-typing-booster/issues/497 Behaviour change between ibus-1.5.29 and 1.5.30. commit 3dfd67d7275b71a62f44678ab78e32a824235dc2 Author: Mike FABIAN Date: Wed Jun 19 10:29:41 2024 +0200 Fix DeprecationWarning engine/main.py:232: DeprecationWarning: Testing an element's truth value will raise an exception in future versions. Use specific 'len(elem)' or 'elem is not None' test instead. commit cc53fde689092d4083dda158c75eb31044c112ce Author: Mike FABIAN Date: Wed May 29 17:30:49 2024 +0200 Remove unused import commit fa2f0864d94f00fa2684f5edc221f9c9fd47dc30 Author: Mike FABIAN Date: Wed May 29 16:37:14 2024 +0200 Drop Python2 support (using pyupgrade --py3-plus *.py) commit 2e477732c307501fa8f1d1263f69672d9591d99e Author: Mike FABIAN Date: Wed May 29 16:45:04 2024 +0200 Consistently use `if a not in b:` instead of `if not a in b:` commit 2e5a1f46a18a42495683fab1b47a13c8ccd65804 Author: Mike FABIAN Date: Wed May 29 12:26:58 2024 +0200 Consistently use `if a not in b:` instead of `if not a in b:` commit 7433010763e83df4f580e9e4ce828018c10d801b Author: Mike FABIAN Date: Mon Apr 15 15:15:04 2024 +0200 Fix appstreamcli validate warnings mfabian@fedora:~$ cat /etc/fedora-release Fedora release 40 (Forty) mfabian@fedora:~$ appstreamcli validate --pedantic --no-net /usr/share/metainfo/ibus-table.appdata.xml W: org.freedesktop.ibus.engine.table:33: developer-id-missing ✘ Validation failed: 警告: 1 commit 7296d33b523a1426c28908bc0b8a049fcbead185 Author: Mike FABIAN Date: Wed Feb 14 10:51:36 2024 +0100 Display key values in hexadecimal when printing debug messages commit 7cd57e8ce9819ec1f1b47d52ed2f55384bbc1721 Author: Mike FABIAN Date: Wed Feb 14 10:25:51 2024 +0100 Make it possible to use keys with Unicode keysyms in keybindings See: https://github.com/mike-fabian/ibus-typing-booster/issues/497 commit ad3cd2d8a4845f1ccc2d9591d7903ca6a38a6141 Author: Mike FABIAN Date: Thu Dec 14 13:29:13 2023 +0100 Use `frames_per_buffer=chunk_size` option in `self._paudio.open()` See: https://bugzilla.redhat.com/show_bug.cgi?id=2238746#c3 commit a9691e8ec5a10e077e73e890aaa7ad23c7ef05b0 Author: Weblate Translation Memory Date: Fri Mar 1 07:36:00 2024 +0100 Translated using Weblate (Japanese) Currently translated at 47.3% (71 of 150 strings) Co-authored-by: Weblate Translation Memory Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ja/ Translation: ibus-table/app commit 5fb65b72e2cb48fbda276eb9b6f7d9fde6b770d3 Author: Weblate Translation Memory Date: Mon Jan 15 03:37:09 2024 +0100 Translated using Weblate (Czech) Currently translated at 36.6% (55 of 150 strings) Co-authored-by: Weblate Translation Memory Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/cs/ Translation: ibus-table/app commit f53190350b35b4fa0157967436aad65aa416bbca Author: Liu Tao Date: Tue Dec 26 15:36:50 2023 +0100 Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 92.0% (138 of 150 strings) Co-authored-by: Liu Tao Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_CN/ Translation: ibus-table/app commit 97f8f76b69aec37c6181b62962e60b9f05ce5425 Author: Mike FABIAN Date: Tue Dec 26 15:36:50 2023 +0100 Translated using Weblate (Japanese) Currently translated at 45.3% (68 of 150 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ja/ Translation: ibus-table/app commit 2cebe7236085409b093835dc62ad2459f2266de9 Author: Weblate Date: Fri Nov 10 17:42:45 2023 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit d016b6fa8e357c7ae531aa99afa25f617f1e0d89 Author: Mike FABIAN Date: Thu Nov 9 16:58:10 2023 +0100 Release 1.17.4 commit 081ee0b91988c4b85d6f5269eab0dfe4ec56e42c Author: Mike FABIAN Date: Fri Nov 10 16:04:17 2023 +0100 Update ibus-table.pot (Only line number changes) commit 400047662e624c00d2e89ebf30f9f5078f05999e Author: Mike FABIAN Date: Fri Nov 10 17:01:56 2023 +0100 Use “” in ibus-table.appdata.xml instead of “” Because is deprecated and it makes the build fail on Fedora rawhide: + appstreamcli validate --pedantic --explain --no-net /builddir/build/BUILDROOT/ibus-table-1.17.4-1.fc40.x86_64//usr/share/metainfo/ibus-table.appdata.xml W: org.freedesktop.ibus.engine.table:33: developer-name-tag-deprecated The toplevel `developer_name` element is deprecated. Please use the `name` element in a `developer` block instead. ✘ Validation failed: warnings: 1 commit ecb280a942298c1a2e4e244f3db740a4cf07805e Author: Mike FABIAN Date: Thu Nov 9 15:52:50 2023 +0100 Fix compose support for ibus >= 1.5.28 Resolves: https://github.com/mike-fabian/ibus-table/issues/145 - IBus.init() has been required to load the compose resource since 1.5.28 after the EN compose table was moved to GResource. Thanks to Takao Fujiwara for the hint! - Load $HOME/.XCompose file by calling self.add_table_by_locale(None) - Add add_table_by_locale() to mock_engine.py to fix the unit tests commit cc295b0dd05c36694409e440b7e755bfa3c1e04d Author: Sergey A Date: Sat Oct 14 16:35:55 2023 +0200 Translated using Weblate (Russian) Currently translated at 80.0% (120 of 150 strings) Co-authored-by: Sergey A Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ru/ Translation: ibus-table/app commit 4ef37f63e8b362b2c336cbf14368c0070df8fbc7 Author: Sergey A Date: Tue Sep 19 14:19:38 2023 +0000 Translated using Weblate (Russian) Currently translated at 66.6% (100 of 150 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ru/ commit c3512f028ba1de18da6f23901550d89409f6cec9 Author: Anonymous Date: Tue Sep 19 15:59:06 2023 +0200 Translated using Weblate (Russian) Currently translated at 48.0% (72 of 150 strings) Translated using Weblate (Russian) Currently translated at 18.0% (27 of 150 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ru/ Translation: ibus-table/app commit 1ba3fb818f1528b899af36932c9e89782efe772b Author: Sergey A Date: Tue Sep 19 15:59:05 2023 +0200 Translated using Weblate (Russian) Currently translated at 48.0% (72 of 150 strings) Translated using Weblate (Russian) Currently translated at 18.0% (27 of 150 strings) Added translation using Weblate (Russian) Co-authored-by: Sergey A Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ru/ Translation: ibus-table/app commit ea685aa695a27968a35c4cb83d36dd9bd42d70fb Author: Weblate Date: Thu Sep 14 12:08:36 2023 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit d1149261616a2590185c2aae19437dd50162ce05 Author: Mike FABIAN Date: Wed Sep 13 15:42:41 2023 +0200 Release 1.17.3 commit 4cfd348e8ff18c467a5c1a994af0275cc53b3890 Author: Mike FABIAN Date: Wed Sep 13 16:34:07 2023 +0200 Update ibus-table.pot (Only line number changes) commit 88072e7efee35675eae4a5e547a7ca86c8650dff Author: Mike FABIAN Date: Wed Sep 13 18:25:22 2023 +0200 remove /ibus-typing-booster.pc from .gitignore commit 8c1cb448f98393a884e9b7513b7df22dcd2b87ed Author: Mike FABIAN Date: Wed Sep 13 18:19:52 2023 +0200 Fix some comments which mentioned ibus-typing-booster and not ibus-table commit a008897a9b58893975e21f842360a435014df98d Author: Mike FABIAN Date: Wed Sep 13 15:35:31 2023 +0200 Support several backends for playing sounds Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2237674 The available backends are: • automatic - choose one of the available backends automatically, depending on what is installed and what should work depending on the version of Python and other stuff • pygame - Seems best, can also play mp3. But requires the SDL libs • pyaudio - Broken for Python >= 3.10 if not updated to pyaudio >= 0.2.12 See: https://stackoverflow.com/questions/70344884) - Sometimes it seems to hang. Not often, but when this happens this is really bad • simpleaudio Broken in Fedora 39, see: https://bugzilla.redhat.com/show_bug.cgi?id=2237680 • aplay - Use the “aplay” binary. Quite reliable, apparently commit ba730cccad81f265bae441f4279bf09ec367b5e3 Author: Mike FABIAN Date: Tue Sep 12 22:28:40 2023 +0200 Update Unihan_Variants.txt and regenerate engine/chinese_variants.py - Update Unihan_Variants.txt from “2022-04-26 Unicode 15.0.0 draft” to “2023-07-15 Unicode version: 15.1.0” - Regenerate engine/chinese_variants.py for Unihan_Variants.txt commit 3aea49962801ee30d70cc9e005daeee51b15dfd7 Author: Mike FABIAN Date: Mon Aug 21 12:10:45 2023 +0200 Release 1.17.2 commit 39619ba99d9978a4e311250d52e156e5687dc3e9 Author: Oğuz Ersen Date: Fri Aug 4 19:21:05 2023 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (150 of 150 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translation: ibus-table/app commit a8e2f3d87879cc2dc84417d85f2de1230dcfc65e Author: Mike FABIAN Date: Fri Jul 28 18:20:59 2023 +0200 Translated using Weblate (German) Currently translated at 100.0% (150 of 150 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translation: ibus-table/app commit 70f734278acf890aab53c61a9ffed6a77e0227b8 Author: Mike FABIAN Date: Mon Jul 10 11:07:21 2023 +0200 Release 1.17.1 commit 0802887fb746ef49bcdabac9776bded06a8fd9fb Author: Mike FABIAN Date: Mon Jul 10 11:28:14 2023 +0200 Fix mypy warnings commit 9188fa74a5445e0a3763ee5273193dc7147a4a4a Author: Mike FABIAN Date: Mon Jul 10 11:00:28 2023 +0200 Return empty program_name and window_title in get_active_window_xprop() when xprop results are unexpected Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2215466 See also this ibus-typing-booster bug: https://bugzilla.redhat.com/show_bug.cgi?id=2175009 commit a39794d39f45e0c4faecef68e757175b0e473d07 Author: Anonymous Date: Tue May 30 08:20:43 2023 +0200 Translated using Weblate (Sinhala) Currently translated at 10.0% (15 of 150 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/si/ Translation: ibus-table/app commit 9c48742c0bf0f443f97d4e46a8447ddf0bfdb1dc Author: Mike FABIAN Date: Wed Apr 5 11:15:27 2023 +0200 Release 1.17.0 commit e758bc45b99dda5e1faaf13160da0d2cf0830dbf Author: Mike FABIAN Date: Wed Apr 5 10:33:57 2023 +0200 New option commit_invalid_mode: Choose what happens when a character not in valid input characters is typed Resolves: https://github.com/mike-fabian/ibus-table/issues/133 See also: https://github.com/moebiuscurve/ibus-table-others/issues/26 commit ed1fd30fba4e6c392d29433ef03260659d8b5c76 Author: Mike FABIAN Date: Tue Feb 21 17:52:35 2023 +0100 Ignore some mypy warnings commit 64d3aec6f2184b7bdbb423086189c088a4a68789 Author: Mike FABIAN Date: Tue Feb 21 17:42:22 2023 +0100 Stop calling self.set_wmclass('ibus-setup-table', 'IBus Table Preferences') https://tronche.com/gui/x/icccm/sec-4.html#WM_CLASS gnome-shell seemed to use the first argument of set_wmclass() to find the .desktop file. If the .desktop file is found, the name shown by gnome-shell in the top bar comes from that .desktop file and the icon to show is also read from that .desktop file. If the .desktop file cannot be found, the second argument of set_wmclass() is shown by gnome-shell in the top bar. It only works like this when gnome-shell runs under Xorg though, under Wayland things are different. But https://docs.gtk.org/gtk3/method.Window.set_wmclass.html says: Don’t use this function. It sets the X Window System “class” and “name” hints for a window. According to the ICCCM, you should always set these to the same value for all windows in an application, and GTK+ sets them to that value by default, so calling this function is sort of pointless. Deprecated since: 3.22 Please do not use it in newly written code. Nevertheless calling set_wmclass() still used to be necessary so I kept calling it inspite of the deprecation warning on stdout. But apparently this is not needed anymore since at least Fedora 34/RHEL9, now the icon and the correct text appear in the Gnome panel without calling set_wmclass(). commit 732f6225055e07ff27d6712061c6354798f9f739 Author: Yuri Chornoivan Date: Wed Apr 5 15:50:33 2023 +0200 Translated using Weblate (Ukrainian) Currently translated at 100.0% (150 of 150 strings) Co-authored-by: Yuri Chornoivan Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ Translation: ibus-table/app commit a1cb01fc6f174a1a7ad4aa72bbcc09edc7d783bb Author: Mike FABIAN Date: Wed Apr 5 13:48:01 2023 +0200 Translated using Weblate (German) Currently translated at 100.0% (150 of 150 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translation: ibus-table/app commit f05e2c1279101074d0a27ab5f936ab61c7c7960d Author: Weblate Date: Wed Apr 5 13:40:51 2023 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 52f1d4874d80e0e43c1608af6386e97447b35fa6 Author: Mike FABIAN Date: Wed Apr 5 11:09:45 2023 +0200 Update ibus-table.pot (4 new messages) commit e262fade03160085a95a33245552e11361033f3b Author: Temuri Doghonadze Date: Sun Feb 5 19:20:26 2023 +0100 Translated using Weblate (Georgian) Currently translated at 44.5% (65 of 146 strings) Co-authored-by: Temuri Doghonadze Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ka/ Translation: ibus-table/app commit ee8bb2317b9f52ecf7f24c1437b060040070b74c Author: Weblate Date: Sat Feb 4 03:20:37 2023 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translated using Weblate (Georgian) Currently translated at 44.5% (65 of 146 strings) Co-authored-by: Anonymous Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ka/ Translation: ibus-table/app commit aa9e2ad29b6bd313baec86783029b323059b346b Author: Mike FABIAN Date: Thu Nov 10 14:52:05 2022 +0100 Release 1.16.14 commit 873c133c25990c7fba8fcdc14029534fe337ee2a Author: Mike FABIAN Date: Thu Nov 10 14:53:21 2022 +0100 Update ibus-table.pot (Only line number changes) commit cf2c5020146ed03369649b8c0ca104a78baae207 Author: Mike FABIAN Date: Thu Nov 10 14:40:38 2022 +0100 Add “class Capabilite(Flag)” for compatibilty To be able to write if self.client_capabilities & it_util.Capabilite.OSK: instead of always checking whether a capability is already available in the current version of ibus: if (hasattr(IBus.Capabilite, 'OSK') and self.client_capabilities & IBus.Capabilite.OSK): commit ca296cba952e56a9171b4daed471203c365b4464 Author: Mike FABIAN Date: Thu Nov 10 09:08:18 2022 +0100 Use lower() on LC_MESSAGES only if it is a string and not None Resolves: https://github.com/mike-fabian/ibus-table/issues/130 Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2131410 commit 38d844bc77b0a0c4b75bddb756fcfbc3d927049e Author: Mike FABIAN Date: Thu Nov 3 17:15:57 2022 +0100 Improve string representation of class KeyEvent for better debugging output commit 8861905c8a64191faeee7189820d82eaa2c29f17 Author: Mike FABIAN Date: Thu Nov 3 16:28:04 2022 +0100 Use InputPurpose and and InputHints compatibility classes This code is synced from ibus-typing-booster. commit 399751b84b078b79afcfbf64b2ce374018400e21 Author: Mike FABIAN Date: Tue Nov 1 08:31:56 2022 +0100 Release 1.16.13 commit 11ccc00849f4793b9608931ca9760085d01509ab Author: Mike FABIAN Date: Tue Nov 1 08:34:28 2022 +0100 Update ibus-table.pot (Only line number changes) commit 2d86913f189853ae7765933d9beafbc5a71e64e7 Author: Mike FABIAN Date: Tue Nov 1 21:21:04 2022 +0100 Remove self._on, seems useless and change do_enable() and do_disable() to do the same as in ibus-typing-booster. commit fbd93c21df7b99939fd9f498940e6ec82e8c87ed Author: Mike FABIAN Date: Tue Nov 1 21:13:13 2022 +0100 Get program name of focused window also when ibus cannot get it - On Wayland desktops: Tries AT-SPI first and falls back to xprop - On X11 desktops: Uses only xprop commit bb82fddb6410e43bf40ea239b50355640696a74a Author: Mike FABIAN Date: Tue Nov 1 16:37:21 2022 +0100 Use focus id if available (it is available for ibus >= 1.5.27) commit 54efc800bde13f01638d855e135f64767093c853 Author: Mike FABIAN Date: Tue Nov 1 15:58:52 2022 +0100 Use IBus.PreeditFocusMode.COMMIT and make sure the input is cleared and the UI updated when the focus changes Resolves: https://github.com/mike-fabian/ibus-table/issues/129 commit 628f5510f09afdfd2951d78060a0bfb7bae68b53 Author: Mike FABIAN Date: Tue Nov 1 15:41:12 2022 +0100 Do not reset input purpose on focus out See: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5966#note_1576732 commit e33b2d23b3620a7987007f8eaf072f686b27c5ea Author: Mike FABIAN Date: Tue Nov 1 08:24:44 2022 +0100 Do not commit by index when OSK is visible Resolves: https://github.com/mike-fabian/ibus-table/issues/128 Currently works only on Gnome Wayland. On Gnome Xorg it works only in gnome-shell entry widgets like “Run a Command” (Alt+F2) but not in other programs like gnome-terminal and gedit. commit 9f047c950d54dbee5c5fd7f0013b32e5f52a260f Author: Mike FABIAN Date: Fri Sep 9 21:40:54 2022 +0200 Use Gtk.Box instead of Gtk.ButtonBox Helps with porting to Gtk4 because Gtk.ButtonBox is not available in Gtk4 anymore. commit 150a15f5d15b803c6715e2f5549618551abcc676 Author: Mike FABIAN Date: Fri Sep 9 21:31:33 2022 +0200 Use Gtk.Box instead of Gtk.VBox and Gtk.HBox In Gtk4 there no Gtk.VBox and no Gtk.HBox, only Gtk.Box. Replacing the uses of Gtk.VBox and Gtk.HBox with Gtk4 compatible code will make porting to Gtk4 a bit easier. commit 2b2cd118a03b761f5d76a5c344e3fbedaf07ba93 Author: Temuri Doghonadze Date: Tue Oct 25 07:28:26 2022 +0200 Translated using Weblate (Georgian) Currently translated at 43.8% (64 of 146 strings) Co-authored-by: Temuri Doghonadze Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ka/ Translation: ibus-table/app commit 2ee27a58ddb94c3eee34d285982a76c47d5c9093 Author: Anonymous Date: Sat Oct 1 01:20:54 2022 +0200 Translated using Weblate (Georgian) Currently translated at 43.8% (64 of 146 strings) Translated using Weblate (Chinese (Traditional) (zh_TW)) Currently translated at 62.3% (91 of 146 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ka/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_TW/ Translation: ibus-table/app commit 705ccaa8d81769ba1a5bd5c60ce78d3fc6cd421f Author: Oğuz Ersen Date: Sat Sep 24 17:19:36 2022 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (146 of 146 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translation: ibus-table/app commit c1f2009655af4dfc1aaf3bfd9d0d5fc42402c5ae Author: Weblate Date: Fri Sep 9 18:58:34 2022 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 7ffccf83283f5366fa3b81abede735eec7a8ae6a Author: Temuri Doghonadze Date: Fri Sep 9 18:58:33 2022 +0200 Translated using Weblate (Georgian) Currently translated at 41.0% (60 of 146 strings) Added translation using Weblate (Georgian) Co-authored-by: Temuri Doghonadze Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ka/ Translation: ibus-table/app commit 88ac6d921e6252e2d1450f017a519fc12e591138 Author: Mike FABIAN Date: Mon Sep 5 19:51:48 2022 +0200 Release 1.16.12 commit 930bfd8ddfe35948aa5e6164f244a79c29cba787 Author: Mike FABIAN Date: Mon Sep 5 19:53:06 2022 +0200 Update ibus-table.pot (Only line number changes) commit 1779f8f9f2cf709092db613c0ad0bc1067ba16ce Author: Mike FABIAN Date: Mon Sep 5 14:57:20 2022 +0200 Add 128x128, 256x256, and svg (remote) icons to ibus-table.appdata.xml commit bbcfba9d5882735b81276ce80c115b6ac5e5502c Author: Mike FABIAN Date: Mon Sep 5 14:52:16 2022 +0200 Use setlocale() and getlocale() instead of getdefaultlocale() Resolves: https://github.com/mike-fabian/ibus-table/issues/120 commit 1616f65f4a05c6de634b6aa6580b8ebfad9318e6 Author: Mike FABIAN Date: Wed Aug 10 09:19:10 2022 +0200 Translated using Weblate (Portuguese (Portugal)) Currently translated at 78.0% (114 of 146 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ Translation: ibus-table/app commit f5583ba6dbe3aaca551effa00b8873f9fd5c26ec Author: Mike FABIAN Date: Sat Aug 6 13:58:57 2022 +0200 Release 1.16.11 commit 2372bc731171863e29e43cc2c47888e789aa0469 Author: Mike FABIAN Date: Sat Aug 6 13:54:08 2022 +0200 Remove hashbang from chinese_variants.py and tabcreatedb.py - chinese_variants.py is only imported an never executed - tabcreatedb.py is usually executed via a the wrapper script “ibus-table-createdb” Resolves: https://github.com/mike-fabian/ibus-table/issues/118 commit dd232594b475ce6b97a81be21fe906c8231d00eb Author: Mike FABIAN Date: Wed Aug 3 09:34:46 2022 +0200 Add “translate” URL and keywords to ibus-table.appdata.xml commit 013e682491bf35cc84e9b9f37dfdf238fd130212 Author: Mike FABIAN Date: Tue Aug 2 10:57:43 2022 +0200 Release 1.16.10 commit ec4f225599fef4fc45878f84dc2be9a4a28d54b6 Author: Mike FABIAN Date: Tue Aug 2 11:02:59 2022 +0200 Do not make the caption of the screenshot in the appdata.xml file translatable I think gnome-sofware would not display the translation anyway. commit b72de3f8a760ec6bd0f248053ee9081c1348856e Author: Mike FABIAN Date: Thu Jul 28 09:53:32 2022 +0200 Add (remote) icon and screenshot to ibus-table.appdata.xml commit e3ca6b174c95c2fad3ffdb230f1baaa65fb803f8 Author: Mike FABIAN Date: Tue Aug 2 08:20:45 2022 +0200 Generate png versions of the ibus-table icon from the svg master To be able to display an icon in gnome-software, svg does not work there. I tried to use “convert” from ImageMagick to do the conversion like this: for i in 16 22 32 48 64 128 256 do mkdir ${i}x${i} convert -background none -density 1024 -resize ${i}x${i} ibus-table.svg ${i}x${i}/ibus-table.png mogrify -density 96 ${i}x${i}/ibus-table.png done But that just produces completely empty png files. Adding the -verbose option shows that inkscape is used for the conversion. But opening the ibus-table.svg in inkscape just shows a white box. So I used gimp to do the conversion. commit 040ae4fa1216b099aa774d41c0b44d6d654f6dc7 Author: Mike FABIAN Date: Sat Jul 30 09:48:59 2022 +0200 Add to appdata.xml files See: https://github.com/hughsie/oars/blob/master/specification/oars-1.1.md commit 3b6afbfced8a56f026bfb2449f15066b4fc4280f Author: Mike FABIAN Date: Mon Jun 13 18:30:57 2022 +0200 Release 1.16.9 commit 026eeca3c8600f90f732764e7c48ee171763a5c1 Author: Mike FABIAN Date: Mon Jun 13 18:27:44 2022 +0200 Require Python >= 3.6 to build commit 7c3573745407414ba7d6cb8c9a9b0b42bceaf2bd Author: Mike FABIAN Date: Mon Jun 13 18:20:24 2022 +0200 Use a less exact type hint to make building tables from sources work with Python 3.6 as well Resolves: https://github.com/kaio/ibus-table/issues/79 Resolves: https://github.com/mike-fabian/ibus-table-chinese/issues/5 commit c4903d86910417ae40c1089fdb885bb89081d8eb Author: Mike FABIAN Date: Mon Jun 13 18:16:24 2022 +0200 Update ibus-table.pot (Only line number changes) commit e6fd5a336e0618e40b0b69e42c2251262a83acf2 Author: Mike FABIAN Date: Mon Jun 13 18:04:17 2022 +0200 Update configure.ac for latest autoconf 2.71 Resolves: https://github.com/mike-fabian/ibus-table/issues/112 - Use “autoupdate” to modernize configure.ac - Use “autoreconf -fiv” in “./autogen.sh” commit 0c621fd918c27ddd69ef04e15047995e9b260d57 Author: Mike FABIAN Date: Mon Jun 13 18:02:07 2022 +0200 Update home page URLs (code.google.com is not used anymore) commit 3b9e25d1728fd154cf66c122c28cbe79c80fff15 Author: Mike FABIAN Date: Thu Apr 28 10:28:32 2022 +0200 Release 1.16.8 commit 44e99f2a7482ad75554fae9e54913207dd8cc656 Author: Mike FABIAN Date: Thu Apr 28 10:17:15 2022 +0200 Regenerate engine/chinese_variants.py for Unihan_Variants.txt from “2022-04-26 Unicode 15.0.0 draft” - Because of the new Unihan_Variants.txt, the following 4 characters are added to the VARIANTS_TABLE in chinese_variants.py: u'囃': 2, u'戠': 3, u'臤': 3, u'鰛': 2, - And because of the new Unihan_Variants.txt, the following character is removed from VARIANTS_TABLE in chinese_variants.py: u'𫝜': 2, 1 = simplified Chinese 2 = traditional Chinese 3 = used both in simplified *and* traditional Chinese commit b20b84e87ae7e3f79b7e70433913aecdc683c5f7 Author: Mike FABIAN Date: Thu Apr 28 10:02:26 2022 +0200 Update Unihan_Variants.txt from “2021-12-01 Unicode 15.0.0 draft” to “2022-04-26 Unicode 15.0.0 draft” All our fixes are included upstream. commit 391432f8a34a3e35615d1e2b70f7a2578fa96f4c Author: Mike FABIAN Date: Mon Apr 4 08:05:29 2022 +0200 Fix some pylint warnings commit 27ae3129b11efa47095f143ee726a17f1ebd8264 Author: Mike FABIAN Date: Mon Jan 31 09:03:42 2022 +0100 Add type hints also for the test cases commit e181dd2e584a77975d0f366fb2003a4b3d774f92 Author: Mike FABIAN Date: Mon Jan 31 09:02:50 2022 +0100 Remove duplicate function in mock_engine.py commit 7d94f39009b3c5cd4940a3c83165684ab2b4eacc Author: Mike FABIAN Date: Sun Jan 30 11:19:53 2022 +0100 Use mypy --strict commit 93aeed71aaf4404418f3df84265f53fdbaec8e8a Author: Mike FABIAN Date: Sun Jan 30 11:19:32 2022 +0100 Add some more type hints commit 79847e3581c965a3e0ee0adfe50d27185fd46f43 Author: Anonymous Date: Wed Mar 30 09:56:14 2022 +0200 Translated using Weblate (Persian) Currently translated at 11.6% (17 of 146 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fa/ Translation: ibus-table/app commit 3433649b1a923257b59aaf6401e99a11cd2f233f Author: Mike FABIAN Date: Thu Feb 17 13:59:05 2022 +0100 Add "Bug report" and "Feature request" issue templates commit 31465f33ed95a84fc74b5ff30e0f1c8268177307 Author: Anonymous Date: Fri Feb 4 19:16:38 2022 +0100 Translated using Weblate (French) Currently translated at 97.2% (142 of 146 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ Translation: ibus-table/app commit 6ffd9b36aaa2410aad8ae6df8430c62a9f923caf Author: Weblate Date: Sat Jan 29 11:38:46 2022 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 8fe3e3c9a18dfc45bfdf7b13970a44796181e7bb Author: Mike FABIAN Date: Tue Jan 25 16:55:21 2022 +0100 Release 1.16.7 commit de758ee10970d84c3e5b902efd1e83f3f7364bfe Author: Mike FABIAN Date: Fri Jan 28 12:58:33 2022 +0100 Update ibus-table.pot (Only line number changes) commit 9150ab7996e75389fe4ce3706d4904820db9e581 Author: Mike FABIAN Date: Fri Jan 28 08:30:11 2022 +0100 Update copyright years commit e72481fd0652cefb71c791eed9803c084d7ab779 Author: Mike FABIAN Date: Fri Jan 28 10:29:04 2022 +0100 Add default value for auto_wildcard in self._default_ime_attributes commit 0078dc05caf62da118d13617b597af783999eb5f Author: Mike FABIAN Date: Thu Jan 27 12:59:16 2022 +0100 Ignore MOD3_MASK (“Usually” Scroll Lock) when matching key bindings Resolves: https://github.com/mike-fabian/ibus-table/issues/102 commit cd8746e1eba0d427c7440b93602d7adc333755a2 Author: Mike FABIAN Date: Wed Jan 26 11:09:02 2022 +0100 Add some more type hints commit 05cc750a0c84d1cc48d9c54855391d558d17efdb Author: Mike FABIAN Date: Tue Jan 25 16:51:04 2022 +0100 When a Modifier key release matches a hotkey command, return False not True. Resolves: https://github.com/mike-fabian/ibus-table/issues/98 Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2038973 commit 082680dd44b89e9dbbd81e5b93e2f385414bd712 Author: Mike FABIAN Date: Tue Jan 25 12:55:14 2022 +0100 Add some more type hints commit c71482e3cdd4ed824278cb0cd8c58d2d9f6c89f2 Author: Weblate Date: Fri Jan 28 08:39:46 2022 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 9d9bbbd11d728bf0c4031785c2cf0e2f8d6b05dc Author: Mike FABIAN Date: Tue Jan 25 17:00:29 2022 +0100 Update ibus-table.pot (Only line number changes) commit 8d0ce1e3d5b8d2cbd5483c7912bcbdaa363c9327 Author: Mike FABIAN Date: Mon Jan 24 18:14:57 2022 +0100 Release 1.16.4 commit b25a994cf34120f00f82a106c06e3d8d1124b716 Author: Mike FABIAN Date: Mon Jan 24 21:08:32 2022 +0100 Adapt test case for “Fix more errors in Unihan_Variants.txt by checking against a Traditional Chinese dictionary” See: https://github.com/mike-fabian/ibus-table/issues/100 commit a0bef3f19dfb034f360533f6d932b329f1a72aec Author: Mike FABIAN Date: Mon Jan 24 20:04:13 2022 +0100 Fix more errors in Unihan_Variants.txt by checking against a Traditional Chinese dictionary Resolves: https://github.com/mike-fabian/ibus-table/issues/100 commit c01cd0a3e53db5ad52495416797431c7be9c65fa Author: Mike FABIAN Date: Sat Jan 22 16:30:17 2022 +0100 Fix some errors in Unihan_Variants.txt Resolves: https://github.com/mike-fabian/ibus-table/issues/97 commit 89415b0c6704f7f61607a85095531eb8b5858857 Author: Emilio Herrera Date: Sun Jan 23 17:16:37 2022 +0100 Translated using Weblate (Spanish) Currently translated at 100.0% (146 of 146 strings) Co-authored-by: Emilio Herrera Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translation: ibus-table/app commit 72fa3d30831c03f551c94b04c81fc1b4a8cbbcb0 Author: Mike FABIAN Date: Thu Jan 20 12:47:10 2022 +0100 Release 1.16.3 commit 9ee6edbe23ed1ad39199d916ec740775d69b58f0 Author: Mike FABIAN Date: Fri Jan 21 11:26:12 2022 +0100 Fix a few errors in Unihan_Variants.txt Resolves: https://github.com/mike-fabian/ibus-table/issues/96 commit c80597d1d35bb7bf3302ed0c7ffa3fea37a3c67d Author: Mike FABIAN Date: Thu Jan 20 12:34:45 2022 +0100 栗 U+6817 is used in Traditional Chinese as well. Resolves: https://github.com/mike-fabian/ibus-table/issues/95 commit c1c39a3dd8aca8c334c00118ba54dd74995fbd47 Author: Mike FABIAN Date: Thu Jan 20 11:22:12 2022 +0100 Regenerate engine/chinese_variants.py for Unihan_Variants.txt from “2021-12-01 Unicode 15.0.0 draft” - Because of the new Unihan_Variants.txt, the following 37 characters are added to the VARIANTS_TABLE in chinese_variants.py: u'䓨': 1, u'沄': 1, u'潕': 2, u'澐': 2, u'罃': 2, u'鮗': 2, u'龻': 2, u'鿟': 1, u'鿠': 2, u'鿰': 1, u'鿲': 1, u'鿳': 2, u'鿴': 1, u'鿵': 1, u'鿶': 1, u'鿷': 1, u'鿸': 1, u'鿹': 1, u'鿺': 1, u'𣲘': 1, u'𤇾': 2, u'𤪤': 2, u'𦥯': 2, u'𧰎': 2, u'𩷓': 2, u'𩷕': 2, u'𩹎': 2, u'𪄳': 2, u'𪛞': 1, u'𫇦': 1, u'𬉧': 2, u'𬵨': 2, u'𰀡': 1, u'𰀢': 1, u'𰁜': 1, u'𰃮': 1, u'𰯲': 2, 1 = simplified Chinese 2 = traditional Chinese 3 = used both in simplified *and* traditional Chinese commit df46474f7e8bc57e66910529c319c1512c0f3366 Author: Mike FABIAN Date: Thu Jan 20 11:12:52 2022 +0100 Update Unihan_Variants.txt from “2021-08-06 Unicode 14.0.0 final” to “2021-12-01 Unicode 15.0.0 draft” commit f52c1071d6157619a57e3b14f898a4660b2b7d0e Author: Mike FABIAN Date: Wed Jan 12 11:56:58 2022 +0100 Release 1.16.0 commit 8ce8323f955fb249c11bfdff337461c6abce12b4 Author: Mike FABIAN Date: Tue Jan 18 14:42:02 2022 +0100 Make true the default for “rememberinputmode” When the input mode is remembered, it works much better when using “[x] Switch input sources individually for each window”. See: https://github.com/mike-fabian/ibus-table/issues/85#issuecomment-1015417630 Overall remembering the input mode is the nicer default. commit 41b35381cdd44a28d19cbfd39029f22442862945 Author: Mike FABIAN Date: Mon Jan 10 15:37:15 2022 +0100 Save “inputmode” to gsettings and add a “rememberinputmode” gsettings Resolves: https://github.com/mike-fabian/ibus-table/issues/85 This makes it possible to change the current input mode from the command line. And with “rememberinputmode” one can choose whether the last used input mode should be remembered and be used again when a new session starts or whether a new session should always start in table mode. commit 22d0772d132fea008195e90b1ccdb654ab490bc6 Author: Mike FABIAN Date: Wed Jan 12 10:58:16 2022 +0100 Remove useless + when concatenating strings commit 6e421a2ec808e05f11dfb5b66d8a45569c755a57 Author: Mike FABIAN Date: Wed Jan 12 10:58:45 2022 +0100 Rename a local variable commit cf4f52943bb9fbd3ccee898dca03ca61b0adea1b Author: Mike FABIAN Date: Tue Jan 11 19:18:30 2022 +0100 Skip cangjie5 and erbi-qs test cases if the tables are too old commit 4350424214eb9b47cf232fd2c030134bd521f383 Author: Mike FABIAN Date: Tue Jan 11 16:48:01 2022 +0100 Replace deprecated module “optparse” with “argparse” commit 0476c2de7a6a8f160f90f6df34748fd4ab8ee17d Author: Oğuz Ersen Date: Thu Jan 13 08:03:15 2022 +0100 Translated using Weblate (Turkish) Currently translated at 100.0% (146 of 146 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translation: ibus-table/app commit 407430eb28fa1d2371bb32eeb0e3e4adc08287f2 Author: Yuri Chornoivan Date: Thu Jan 13 08:03:14 2022 +0100 Translated using Weblate (Ukrainian) Currently translated at 100.0% (146 of 146 strings) Co-authored-by: Yuri Chornoivan Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ Translation: ibus-table/app commit b5a4722493daa6b7725ee0462cd3af00f675c873 Author: Anonymous Date: Wed Jan 12 18:33:19 2022 +0100 Translated using Weblate (Ukrainian) Currently translated at 99.3% (145 of 146 strings) Translated using Weblate (Spanish) Currently translated at 96.5% (141 of 146 strings) Translated using Weblate (Czech) Currently translated at 36.9% (54 of 146 strings) Translated using Weblate (Catalan) Currently translated at 86.9% (127 of 146 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ca/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/cs/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ Translation: ibus-table/app commit a205ea795a8cc24f81329f1f80a523cb8652c923 Author: Anonymous Date: Wed Jan 12 18:30:46 2022 +0100 Translated using Weblate (Turkish) Currently translated at 99.3% (145 of 146 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translation: ibus-table/app commit 9297231c96090dbcad73c05799aefc345f96d7d8 Author: Mike FABIAN Date: Wed Jan 12 18:23:21 2022 +0100 Translated using Weblate (German) Currently translated at 100.0% (146 of 146 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translation: ibus-table/app commit 5c59c66820443c0c5a210274f98cd69edbfb2b67 Author: Weblate Date: Wed Jan 12 18:23:21 2022 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 59b26f4766db3c5c09baeada3ad2dfc9cabf9fd5 Author: Mike FABIAN Date: Wed Jan 12 18:17:06 2022 +0100 Update ibus-table.po (Fix mistakes in one English message I commit 925f9d76aaed26a354ba85d41f687d91040ec4d7 Author: Mike FABIAN Date: Wed Jan 12 18:11:02 2022 +0100 Update ibus-table.po (Fix mistakes in one English message ID) commit 25eb384914ea633a7cf3f4ef570be845b811abba Author: Anonymous Date: Wed Jan 12 18:01:18 2022 +0100 Translated using Weblate (German) Currently translated at 99.3% (145 of 146 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translation: ibus-table/app commit 2c97d9ddf32b0f341c6c7061744eb04cf0c1bed1 Author: Weblate Date: Wed Jan 12 17:54:59 2022 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit ae297221f26c80a399dbca4921625b038b084bf7 Author: Mike FABIAN Date: Wed Jan 12 12:02:51 2022 +0100 Update ibus-table.po (Two new messages because of rememberinputmode) commit c90a0e3349d6fe681f79aaf19519a3f528c7d058 Author: Weblate Date: Tue Jan 11 12:15:15 2022 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 84ad6bbc3b754de1c3e0566b138e1ff62d8711fe Author: Mike FABIAN Date: Tue Sep 28 13:02:33 2021 +0200 Release 1.15.0 commit 0fbc83d5af306a512b177defa0c1e0a73fdff53a Author: Mike FABIAN Date: Tue Jan 11 09:56:28 2022 +0100 Update ibus-table.pot (Only line number changes) commit 4aaca9f9bc6bba15ad0d9a8d32155be59d42b734 Author: Mike FABIAN Date: Tue Jan 11 09:17:09 2022 +0100 Fix type hint warning commit d1ebf137b7076d00953b05ae9a60fd6cf73ffc77 Author: Mike FABIAN Date: Tue Jan 11 08:29:58 2022 +0100 Fix some pylint warnings commit 3a3ce9076667cf61ba3fb5c93d8d883b5a7d9e9e Author: Mike FABIAN Date: Mon Jan 10 15:35:31 2022 +0100 Improve comment explaining goucima commit 4399053de16462574785108909bd53e61a9a7153 Author: Mike FABIAN Date: Mon Jan 10 15:34:28 2022 +0100 Add test cases for goucima for the wubi-jidian86 and erbi-qs tables commit 8b819bf378615c37e9d649c1a8870983ee2d7526 Author: lidan Date: Thu Dec 23 15:56:51 2021 +0800 skip i/u/v started code for pinyin mode of erbi-qs commit ee338f3642f7c020021c671de43047c88ed0a70f Author: lidan Date: Wed Dec 22 20:02:05 2021 +0800 use max same-prefix count code as pinyin candidate for example select "sxr." in ["sx", "sxr.", "isong"] for 松 in erbi-qs commit 54391f45645f042ccca4120068761e3cc8671320 Author: lidan Date: Wed Dec 22 16:24:27 2021 +0800 add code to table by section in case unmarked auxiliary code in erbi-qs selected as goucima. commit 00871d6d5cd4b24232aefc00bc8a64c893bb5fef Author: Mike FABIAN Date: Tue Jan 11 07:40:34 2022 +0100 Adapt test cases for cangjie5 for the improvements in the cangjie5 table The cangjie5 table has been improved according to: https://github.com/mike-fabian/ibus-table/issues/76 https://github.com/mike-fabian/ibus-table/issues/87 Therefore, the test cases need to be changed as well. commit 4debaa58c3fda80880a33f87f54568a11649f03c Author: Mike FABIAN Date: Tue Oct 5 11:30:31 2021 +0200 Regenerate engine/chinese_variants.py for Unihan_Variants.txt from “2021-08-06 Unicode 14.0.0 final” - *All* our fixes which are now included upstream. - Because of the new Unihan_Variants.txt, the following 48 characters are added to the VARIANTS_TABLE in chinese_variants.py: u'䓖': 1, u'了': 1, u'伙': 1, u'借': 1, u'傢': 2, u'冬': 1, u'千': 1, u'卜': 1, u'卷': 1, u'吁': 1, u'合': 1, u'回': 1, u'夥': 2, u'姜': 1, u'家': 1, u'峃': 1, u'嶨': 2, u'庼': 1, u'廎': 2, u'懞': 2, u'才': 1, u'折': 1, u'捲': 2, u'摺': 2, u'旋': 1, u'朱': 1, u'濛': 2, u'灶': 1, u'瞭': 3, u'矇': 2, u'硃': 2, u'秋': 1, u'竈': 2, u'籲': 2, u'纔': 2, u'蒙': 1, u'蔑': 1, u'蔔': 2, u'薑': 2, u'藉': 3, u'藭': 2, u'衊': 2, u'迴': 2, u'霉': 1, u'鞦': 2, u'黴': 2, u'鼕': 2, 1 = simplified Chinese 2 = traditional Chinese 3 = used both in simplified *and* traditional Chinese commit 6ade76f6212fc21fb842bf59fbc6d83dde266f90 Author: Mike FABIAN Date: Tue Oct 5 11:19:27 2021 +0200 Update Unihan_Variants.txt from “2021-05-18 Unicode 14.0.0 draft” to “2021-08-06 Unicode 14.0.0 final” commit a816c14bcea6642368656b9bb9e9b9f5e58d2c8b Author: Anonymous Date: Tue Sep 28 14:00:34 2021 +0200 Translated using Weblate (Ukrainian) Currently translated at 100.0% (145 of 145 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ Translation: ibus-table/app commit 63c5839731ce32e1392fc31ca93af9d5c6604a31 Author: Mike FABIAN Date: Tue Sep 28 14:00:34 2021 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (145 of 145 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (145 of 145 strings) Translated using Weblate (German) Currently translated at 100.0% (145 of 145 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translation: ibus-table/app commit cf894c6bbdd971a7cce2d64b2ca9061c58f88ac4 Author: Weblate Date: Tue Sep 28 13:08:15 2021 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 3af201336edd646b07da063100e76c668dd1de41 Author: Mike FABIAN Date: Tue Sep 28 13:04:44 2021 +0200 Update ibus-table.pot, Rafael Fontenelle fixed a typo commit 3cf8a94f05d6ae7651dc407a8a2a2d2c417bd65f Author: Rafael Fontenelle Date: Sat Sep 4 21:23:21 2021 -0300 Fix typo in main file commit 55a61b94d0330305592176d58a894b15057204f5 Author: Rafael Fontenelle Date: Mon Sep 6 03:05:05 2021 +0200 Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (145 of 145 strings) Co-authored-by: Rafael Fontenelle Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translation: ibus-table/app commit e83aa51cc0b580829b7f9751c10f5a753138bafe Author: Anonymous Date: Mon Sep 6 03:05:05 2021 +0200 Translated using Weblate (Spanish) Currently translated at 97.2% (141 of 145 strings) Translated using Weblate (Catalan) Currently translated at 87.5% (127 of 145 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ca/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translation: ibus-table/app commit 96286e3458150aad08bf00c23bb5b0b204b334bd Author: Anonymous Date: Thu Aug 26 14:04:54 2021 +0200 Translated using Weblate (Sinhala) Currently translated at 6.8% (10 of 145 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/si/ Translation: ibus-table/app commit 32307584f7b9329c706adcf61fd4d786a0a5f677 Author: Weblate Date: Wed Aug 25 13:18:50 2021 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit cc121ef1bfa5ba97b679b9496a608357cd1f1940 Author: Mike FABIAN Date: Thu Jul 22 16:44:27 2021 +0200 Release 1.14.1 commit 523c63097fedd5a79de886e58395d0c11b6bfd29 Author: Mike FABIAN Date: Wed Aug 25 12:38:05 2021 +0200 Update ibus-table.pot (Only line number changes) commit c43c22e8088f0da92ee8a187f3bfe0438addef34 Author: Mike FABIAN Date: Wed Aug 25 12:31:40 2021 +0200 If an exception happens when trying to play a sound, catch it. This bug has been reported: https://bugzilla.redhat.com/show_bug.cgi?id=1995955 Bug 1995955 - [abrt] ibus-table: play_buffer(): shiny.py:60:play_buffer:_simpleaudio.SimpleaudioError: Error opening PCM device. -- CODE: -24 -- MSG: 開啟太多檔案 (開啟太多檔案 = Too many files open) I have no idea how to reproduce that but catching the exception should fix it, it should make ibus-table continue working normally if any such serious problem with playing sounds occurs. Without sound of course but it should not stop working. commit 0dc03fd2cb97013f2e208b42b62237d4b2e07f79 Author: Mike FABIAN Date: Wed Aug 25 12:24:01 2021 +0200 When changing the error sound file with the setup tool, play it To make the user hear immediately what kind of sound was selected. commit 56d2ef760ce37565b8ae4589004ae5208443a17c Author: Mike FABIAN Date: Sun Aug 22 20:21:56 2021 +0200 Translated using Weblate (Spanish) Currently translated at 95.8% (139 of 145 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translation: ibus-table/app commit eab7d13075e25b0a05d1251fdb93f1eb8ba3df43 Author: Mike FABIAN Date: Mon Jul 26 11:56:57 2021 +0200 Fix typo when attaching to the options grid Luckily that typo had no effect. commit 22df558c379edaf9a273c1c6cdb26d1f296f6130 Author: Yuri Chornoivan Date: Thu Jul 22 17:04:01 2021 +0200 Translated using Weblate (Ukrainian) Currently translated at 100.0% (145 of 145 strings) Co-authored-by: Yuri Chornoivan Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ Translation: ibus-table/app commit d65bfda0905e95aeaf87c8404f0860c8bae16881 Author: Mike FABIAN Date: Thu Jul 22 17:04:01 2021 +0200 Translated using Weblate (Portuguese (Portugal)) Currently translated at 78.6% (114 of 145 strings) Translated using Weblate (Turkish) Currently translated at 100.0% (145 of 145 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.8% (139 of 145 strings) Translated using Weblate (French) Currently translated at 95.8% (139 of 145 strings) Translated using Weblate (Spanish) Currently translated at 95.8% (139 of 145 strings) Translated using Weblate (German) Currently translated at 100.0% (145 of 145 strings) Translated using Weblate (Catalan) Currently translated at 86.8% (126 of 145 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ca/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translation: ibus-table/app commit aaa6dc1deb10eb91e4c50e71eefab0df16d86a9c Author: Anonymous Date: Thu Jul 22 17:04:00 2021 +0200 Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 95.1% (138 of 145 strings) Translated using Weblate (Turkish) Currently translated at 99.3% (144 of 145 strings) Translated using Weblate (Portuguese (Portugal)) Currently translated at 78.6% (114 of 145 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.1% (138 of 145 strings) Translated using Weblate (Catalan) Currently translated at 86.8% (126 of 145 strings) Translated using Weblate (Spanish) Currently translated at 95.1% (138 of 145 strings) Translated using Weblate (German) Currently translated at 100.0% (145 of 145 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ca/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_CN/ Translation: ibus-table/app commit 8319049d7e8a3422a1bf297a806e23e6079c0217 Author: Mike FABIAN Date: Thu Jul 22 17:04:00 2021 +0200 Translated using Weblate (German) Currently translated at 100.0% (145 of 145 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translation: ibus-table/app commit cebefbe4500a49c9c422e9df3ebc6302625f14a6 Author: Anonymous Date: Thu Jul 22 17:03:59 2021 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Anonymous Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit beb9eb87fcf30924a1dc866667845b3c2344827f Author: Mike FABIAN Date: Thu Jul 22 16:51:38 2021 +0200 Update ibus-table.pot (Remove some :s at the end of messages which are not checkboxes) commit dc0c4603ef7ce6e07e97701e3e700e55ee5cf436 Author: Mike FABIAN Date: Thu Jul 22 16:42:01 2021 +0200 Remove colons after “Auto select:”, “Auto wildcard:”, and “Use dark theme:” Resolves: https://github.com/mike-fabian/ibus-table/issues/70#issuecomment-884664898 commit cb98270d665c92bf8210f3d177656ac728193d76 Author: Mike FABIAN Date: Wed Jul 14 11:16:22 2021 +0200 Release 1.14.0 commit 62843052ed1c1d427a7b384fbf25c22c39575278 Author: Mike FABIAN Date: Mon Jul 19 19:28:19 2021 +0200 Fix some pylint warnings commit eb06116266fb8066ac25b751b4f83cb184ca9016 Author: Mike FABIAN Date: Mon Jul 19 19:27:54 2021 +0200 Update copyright years commit 5d6ff33455a697ff554b57ff16fe5546be2a48d6 Author: Mike FABIAN Date: Mon Jul 19 13:27:09 2021 +0200 Hide options which make no sense for certain tables instead of just graying them out commit a132945ad87bccfb5321480be5b1bb348d105cce Author: Mike FABIAN Date: Mon Jul 19 11:41:08 2021 +0200 Save some now unused translatable strings for possible use later To avoid losing translations which are already done. commit b799cb9acf68855d0edfceaba518eaade5e85080 Author: Mike FABIAN Date: Mon Jul 19 11:34:46 2021 +0200 Use a checkbutton instead of a combobox for the always show lookup option commit 9775c29d20bd1981506943071787ac7457bf5af2 Author: Mike FABIAN Date: Mon Jul 19 11:23:01 2021 +0200 Use a checkbutton instead of a combobox for the dark theme option commit f312eaeee81c32c42a4ace9600f353b71068aba9 Author: Mike FABIAN Date: Mon Jul 19 11:03:56 2021 +0200 Use a checkbutton instead of a combobox for the autowildcard option commit 65011db885e8e3a6fe52bd14c4fbe6fba503eb94 Author: Mike FABIAN Date: Mon Jul 19 10:46:13 2021 +0200 Use a checkbutton instead of a combobox for the autoselect option commit fe2aef8c393c4f6eb3b9bd7950cfa5df5d276431 Author: Mike FABIAN Date: Mon Jul 19 08:38:43 2021 +0200 Test case for new dynamic adjust option commit f0ba8ffd23416189916d5b6778cd41348214dbbe Author: Mike FABIAN Date: Wed Jul 14 18:45:32 2021 +0200 Add option to set dynamic adjust at runtime Resolves: https://github.com/mike-fabian/ibus-table/issues/70 Also add a button to forget all the data learned by typing and selecting candidates. commit 5bb3c11fe41f818e958fb5fe103efbb599d90b6b Author: Mike FABIAN Date: Sat Jul 17 21:43:17 2021 +0200 Use variables to count rows in options tabs in setup tools commit 5e6d7c87f0673e84e5519db5fb03ce356fe9edca Author: Mike FABIAN Date: Fri Jul 16 13:45:38 2021 +0200 Add more type hints to setup/main.py commit c18050e47f2a8f5f58cd30212690996bb0fd5350 Author: Mike FABIAN Date: Wed Jul 14 18:29:09 2021 +0200 Remove self.suggestion_mode from class TabSqliteDb, it was unused there commit 20d665f768c38904cb88cc37b33a0cb107526b40 Author: Mike FABIAN Date: Wed Jul 14 18:03:18 2021 +0200 Move self._dynamic_adjust variable from tabsqlitedb.py to table.py Preparation to make dynamic adjustment changeable at runtime. commit 3a75033754490eccea6fe580cbe625a3bdbb6a64 Author: Mike FABIAN Date: Mon Jul 12 10:35:46 2021 +0200 Add options to play sound file on error Resolves: https://github.com/kaio/ibus-table/issues/75 commit 55e6bc4ec120c31ed6dc63306914f319bb972a21 Author: Mike FABIAN Date: Thu Jul 8 15:47:47 2021 +0200 Add sound file coin9.wav To be used as an error sound. Downloaded from: https://freesound.org/people/The-Sacha-Rush/sounds/336936/download/336936__the-sacha-rush__coin9.wav License: This work is licensed under the Creative Commons 0 License. https://creativecommons.org/publicdomain/zero/1.0/ CC0 1.0 Universal (CC0 1.0) Public Domain Dedication No Copyright The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. https://creativecommons.org/publicdomain/zero/1.0/legalcode commit 6848ee810a6ea790d6b764c6196fa5bc65ceac4a Author: Mike FABIAN Date: Tue Jul 20 10:59:38 2021 +0200 Translated using Weblate (German) Currently translated at 100.0% (145 of 145 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translation: ibus-table/app commit 05a6686d49e140469a88e773c5e1906dc48ac823 Author: Yuri Chornoivan Date: Tue Jul 20 10:59:38 2021 +0200 Translated using Weblate (Ukrainian) Currently translated at 100.0% (145 of 145 strings) Co-authored-by: Yuri Chornoivan Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ Translation: ibus-table/app commit eb3bbaf9afb964f40c1f4d57285e0d9bc1f8b9e0 Author: Anonymous Date: Tue Jul 20 10:59:37 2021 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (145 of 145 strings) Translated using Weblate (German) Currently translated at 100.0% (145 of 145 strings) Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Anonymous Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translation: ibus-table/app commit bbf9f1ae72575833dc239a8c0bf6d9b1020c8239 Author: Mike FABIAN Date: Mon Jul 19 20:49:57 2021 +0200 Update ibus-table.pot (Added a missing space after a period in a tooltip) commit 219063b075736cb4288e7914d15ae96fc2ebd318 Author: Oğuz Ersen Date: Mon Jul 19 20:18:08 2021 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (145 of 145 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translation: ibus-table/app commit 6c3cbd00e4782db05890d28c4218ac88a4e02bfa Author: Yuri Chornoivan Date: Mon Jul 19 16:10:59 2021 +0200 Translated using Weblate (Ukrainian) Currently translated at 100.0% (145 of 145 strings) Translated using Weblate (Ukrainian) Currently translated at 98.6% (143 of 145 strings) Co-authored-by: Yuri Chornoivan Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ Translation: ibus-table/app commit 24652bf9b52e992947f024e96db8d04b72c4ec51 Author: Anonymous Date: Mon Jul 19 16:10:59 2021 +0200 Translated using Weblate (Turkish) Currently translated at 95.8% (139 of 145 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 95.8% (139 of 145 strings) Translated using Weblate (Ukrainian) Currently translated at 97.9% (142 of 145 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_CN/ Translation: ibus-table/app commit f9d410fc52d4351adc08c6d7e12a6534172e86e4 Author: Yuri Chornoivan Date: Mon Jul 19 16:10:59 2021 +0200 Translated using Weblate (Ukrainian) Currently translated at 97.9% (142 of 145 strings) Co-authored-by: Yuri Chornoivan Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ Translation: ibus-table/app commit 95c9360c2ae3b77b270ce53b8d20a1e0a66a2621 Author: Anonymous Date: Mon Jul 19 16:10:59 2021 +0200 Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.8% (139 of 145 strings) Translated using Weblate (French) Currently translated at 95.8% (139 of 145 strings) Translated using Weblate (Spanish) Currently translated at 95.8% (139 of 145 strings) Translated using Weblate (German) Currently translated at 100.0% (145 of 145 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translation: ibus-table/app commit 454e15dfc4cb533397566c35bb3cb0f7df15a655 Author: Mike FABIAN Date: Mon Jul 19 16:10:58 2021 +0200 Translated using Weblate (German) Currently translated at 100.0% (145 of 145 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translation: ibus-table/app commit adb2d99d8e18e239444e2d264cfd56a69077db57 Author: Anonymous Date: Mon Jul 19 16:10:58 2021 +0200 Translated using Weblate (Czech) Currently translated at 36.5% (53 of 145 strings) Translated using Weblate (Catalan) Currently translated at 86.8% (126 of 145 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ca/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/cs/ Translation: ibus-table/app commit 0e1e69d34ba3d3e6f9ca996988760d6dc77eb968 Author: Weblate Date: Mon Jul 19 15:56:59 2021 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit a509825412bceaa10a7d1fbb14cec9ebef42a7fa Author: Mike FABIAN Date: Wed Jul 14 11:21:08 2021 +0200 Update ibus-table.pot (some new messages because of the new options) commit b8ad155d77a033b5d5cde0ebf6d9f3fd6a6e007e Author: Mike FABIAN Date: Wed Jul 14 18:21:21 2021 +0200 Small adjustment to one of the latex test cases To make it work with both with ibus-table-others-1.3.12 *and* ibus-table-others-1.3.11. The latex.txt table in ibus-table-others-1.3.12 has SELECT_KEYS = F1,F2,F3,F4,F5,F6,F7,F8,F9,F10 the older version in ibus-table-others-1.3.11 has SELECT_KEYS = F1,F2,F3,F4,F5,F6,F7,F8,F9 The default page size is calculated from the number of select keys, to make this test work for both versions, set the page size to 9 in the test. commit 08db3d41dd63bb5efd602595d80c722d57f160d3 Author: Mike FABIAN Date: Tue Jul 13 14:52:01 2021 +0200 Fix a pylint warning commit 2f4b8556a28a7e342d200bed8b81d5fe6efb1ce3 Author: Mike FABIAN Date: Wed Jun 9 17:47:30 2021 +0200 Release 1.13.3 commit 5ed1cc16b398e0161e63ef35421d94166caf56c0 Author: Mike FABIAN Date: Wed Jun 9 17:29:46 2021 +0200 Fix some more bugs in Unihan_Variants.txt Resolves: https://github.com/ibus/ibus/issues/2323 commit 521054fc811a72161673aea07b55062a34df8d52 Author: Mike FABIAN Date: Wed Jun 9 15:46:17 2021 +0200 Move test characters which are already fixed in Unicode up in generate-chinese-variants.py commit d14b2d8d5a573ecd8eb3996187002a429aec9254 Author: Mike FABIAN Date: Tue Jun 8 14:29:49 2021 +0200 Release 1.13.2 commit 6384e217f7283d12b1bdabbc10da4d2cf2e4f94a Author: Mike FABIAN Date: Tue Jun 8 13:59:59 2021 +0200 Fix bug in Unihan_Variants.txt, 只 U+53EA is both simplified *and* traditional Chinese Resolves: https://github.com/kaio/ibus-table/issues/74 commit 5406e5badb03d2719b47f9878f64969afc304bce Author: Mike FABIAN Date: Tue Jun 8 14:17:02 2021 +0200 Small improvements to the test function in generate-chinese-variants.py (Don’t exit after the first fail, do all tests and print a summary) commit 7152e2eaa01a9cb234e7e4a6f02174684f4ac42c Author: Mike FABIAN Date: Tue Jun 8 14:40:50 2021 +0200 Adapt test case to update of Unihan_Variants.txt commit 7a8a23dbe988dcdba100cb32caca228fdb2c7c93 Author: Mike FABIAN Date: Tue Jun 8 14:13:41 2021 +0200 Regenerate engine/chinese_variants.py for Unihan_Variants.txt from “2021-05-18 Unicode 14.0.0” (Including our fixes which are not yet included upstream) commit c37452a7bf49ccfd0f2062a3e90085022cb3735b Author: Mike FABIAN Date: Tue Jun 8 13:58:22 2021 +0200 Keep our fixes to Unihan_Variants which are not yet included upstream commit 68bffbdde2f98399abd430d749bcbfcfc361aaa6 Author: Mike FABIAN Date: Tue Jun 8 13:40:25 2021 +0200 Update Unihan_Variants.txt from “2017-05-14 Unicode 10.0.0” to “2021-05-18 Unicode 14.0.0” (From the current draft version of Unicode 14.0.0) commit bd85760453498920be33aaf5eab9313115ff8945 Author: Mike FABIAN Date: Sat May 22 07:59:09 2021 +0200 Remove redundant line commit b59e0bc0b8aa6a6d25fe337c013be714fd4d3721 Author: Emilio Herrera Date: Sat Jun 5 18:03:19 2021 +0200 Translated using Weblate (Spanish) Currently translated at 100.0% (138 of 138 strings) Co-authored-by: Emilio Herrera Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translation: ibus-table/app commit 93d39887ef87e83525f395d5ccdc74ef6ec8fc62 Author: Rafael Fontenelle Date: Tue May 25 00:03:31 2021 +0200 Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (138 of 138 strings) Co-authored-by: Rafael Fontenelle Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translation: ibus-table/app commit 34218eb71047896e6256e7666c779abae55f0754 Author: Mike FABIAN Date: Sun May 16 21:40:59 2021 +0200 Release 1.13.1 commit 4acb1f35b898f6f0d0c6c30237a7705cd993ffd6 Author: Mike FABIAN Date: Sun May 16 21:34:59 2021 +0200 Fix reading the source file for the suggestions phrase.txt.bz2 Problem was introduced by removing the Python2 compatibility stuff in: commit 221acc4a876d4590cef677571f328bca819ced51 Author: Mike FABIAN Date: Thu May 6 09:36:42 2021 +0200 Add more type hints and remove some Python2 compatibility stuff commit 9efec48c10ae6720490f30407a5e0d4ede5f5953 Author: Julien Humbert Date: Sun May 16 21:28:38 2021 +0200 Translated using Weblate (French) Currently translated at 100.0% (138 of 138 strings) Co-authored-by: Julien Humbert Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ Translation: ibus-table/app commit 407cb1520e65123361b69cc0f7297a643d0649f1 Author: Anonymous Date: Sun May 9 10:02:14 2021 +0200 Translated using Weblate (Catalan) Currently translated at 90.5% (125 of 138 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ca/ Translation: ibus-table/app commit 9807b49739c03fa308227500bfb6ff3f3935a14f Author: Weblate Date: Sat May 8 09:44:22 2021 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 5515afbef8d3a7360700a04ebaf35a18d6caff76 Author: Mike FABIAN Date: Tue May 4 19:50:34 2021 +0200 Release 1.13.0 commit a4f666a1615d74ff483e72dbe3dae3d1d10b0d5a Author: Mike FABIAN Date: Thu May 6 12:07:21 2021 +0200 Update ibus-table.pot (Only line numbers changed) commit a602611304f381228a9ae18236670f30cf4c7743 Author: Mike FABIAN Date: Thu May 6 12:03:47 2021 +0200 Add test case for the immediate switch between table and pinyin mode commit bc5bfdb63253389ac298c7bf49df9625725fca26 Author: Mike FABIAN Date: Thu May 6 11:35:59 2021 +0200 Make switch to pinyin mode also happen immediately even when the preedit is not empty That is better for consistency. commit b89d1fd6a72a90b2b6575a59afa1d48ab8e10480 Author: Mike FABIAN Date: Thu May 6 11:04:35 2021 +0200 Add test case for “Commit English input and then switch into direct mode” When toggle to direct mode from table mode, if the preedit is not empty, commit the English input first. Then switch to direct input mode. Related: https://github.com/kaio/ibus-table/issues/68 commit 221acc4a876d4590cef677571f328bca819ced51 Author: Mike FABIAN Date: Thu May 6 09:36:42 2021 +0200 Add more type hints and remove some Python2 compatibility stuff commit 9f7742183b3630f23c49baf9bcfc54a966532203 Author: Mike FABIAN Date: Wed May 5 23:43:58 2021 +0200 Make rolling the mouse wheel in the candidate area of the lookup table work commit 0744db76aab12ca5fe400326a5e8a0326b4d86f6 Author: Mike FABIAN Date: Wed May 5 14:34:00 2021 +0200 Add more type hints commit 4ad5e60336662439c5b4285d525589e2108a5d2d Author: Mike FABIAN Date: Wed May 5 13:56:23 2021 +0200 Use the same color_string_to_argb() function as in ibus-typing-booster commit e1cf7331fbafe1b378b78d6f92ec4cf9b0c5493c Author: Mike FABIAN Date: Mon Apr 19 08:50:29 2021 +0200 Add some type hints commit 15ed3ecb80200c2404075a67c47f86e9e377391c Author: Mike FABIAN Date: Mon Apr 19 08:37:56 2021 +0200 Add wrapper script for mypy to check type hints commit b0392d0540dcc0465778513337f4744b39d9fcd9 Author: Mike FABIAN Date: Wed May 5 13:15:29 2021 +0200 Move the writing of the XML into a function in main.py commit 9a662d751ec4c7c7996db9b4f4a72c508cde4586 Author: Mike FABIAN Date: Mon Apr 19 08:58:34 2021 +0200 Remove Python2 compatibility stuff ibus-table doesn’t work with Python2 for a long time already commit 27030927c388210e464d4f4dbfecd5343bfaf498 Author: Mike FABIAN Date: Tue May 4 19:06:06 2021 +0200 Improve readability by spelling out keyword option commit 0546f70e026f49dd0bef3a6ee5e96947c399cf5e Author: Mike FABIAN Date: Tue May 4 19:05:36 2021 +0200 Improve function documentation commit 084488197e4b36db6da28f46c802041c21a2eae1 Author: Mike FABIAN Date: Tue May 4 18:11:37 2021 +0200 Fix a typo in a comment commit 56636c1f1421bbf2673f46d17ad414fb873c9514 Author: Mike FABIAN Date: Tue May 4 10:10:48 2021 +0200 Fix typo in comment commit a0aa3646d82f96be1a0b8750d4e5713456dc78c2 Author: Mike FABIAN Date: Tue May 4 20:53:46 2021 +0200 Adapt the test case to the new default keybinding for commit_to_preedit Adapting this test case is also necessary because Shift_L now commits English input and then switches to direct mode. Related: https://github.com/kaio/ibus-table/issues/68 commit 0574308f10e6c7b9a3e9e0a79ed69e24bfe3b127 Author: Mike FABIAN Date: Tue May 4 20:01:07 2021 +0200 Change the default keybinding for commit_to_preedit to ['Control+Shift_L', 'Control+Shift_R'] Related: https://github.com/kaio/ibus-table/issues/68 The previous default had a conflict with toggle_input_mode_on_off and toggle_pinyin_mode: commit_to_preedit ['Shift_R', 'Shift_L'] toogle_input_mode_on_off ['Shift_L'] toggle_pinyin_mode ['Shift_R'] This conflict didn’t matter as the toggling of the modes was only done when the preedit was empty and commit_to_preedit can only be done when the preedit is not empty. So there was no real conflict in practice. But now when toggle_input_mode_on_off is also done when the preedit is not empty to fix https://github.com/kaio/ibus-table/issues/68, then it is not possible to use the same keybindings for these commands. commit_to_preedit is probably used much more rarely than toggling the input or the pinyin modes. So it is probably better to leave the default keybindinds for toggling the input and pinyin modes as they always were and change the default keybinding of commit_to_preedit. commit c17fecf3ee072bdb42a07867a7ad5fbe59bb64cc Author: Mike FABIAN Date: Tue May 4 19:04:13 2021 +0200 Add “darktheme” option to org.freedesktop.ibus.engine.table.gschema.xml Resolves: https://github.com/kaio/ibus-table/issues/67 commit 23a6fd60be7374ad94728ca875902bc209e284c0 Author: mozbugbox Date: Sat Mar 27 14:50:16 2021 +0800 Show all the tabkeys when using wildcards When wildcards were used, most likely the user would like to learn the exact tabkeys. commit 89eff501a06df712ae0166fc973752277ce6bd8a Author: mozbugbox Date: Sat Mar 27 10:40:51 2021 +0800 Add use dark theme option to the setup applet Related: https://github.com/kaio/ibus-table/issues/67 commit 915429f1be890ce166267c95086ff3c621e3bb3a Author: mozbugbox Date: Sat Mar 27 09:33:11 2021 +0800 Group color scheme into theme and dark theme The foreground colors should be different between normal light theme and dark theme. Related: https://github.com/kaio/ibus-table/issues/67 commit 36e83774df11c8b995b4500df15c60e6ffd922e7 Author: mozbugbox Date: Fri Mar 26 22:57:07 2021 +0800 Apply a couple modes immediately when changed When change mode for Chinese_mode or onechar_mode, if the input is not empty, update the candidates with the new mode setting. commit 3cd370115104e627123e642aa4d43a0a850e5e11 Author: mozbugbox Date: Fri Mar 26 22:53:09 2021 +0800 Commit English input and then switch into direct mode When toggle to direct mode from table mode, if the preedit is not empty, commit the English input first. Then switch to direct input mode Resolves: https://github.com/kaio/ibus-table/issues/68 commit 6e9d0ee4359c682b0b6f2a7f868745af520a456e Author: Mike FABIAN Date: Tue May 4 09:54:56 2021 +0200 Clarify comment about the order of handling the hotkeys The keybindings treeview is sortable now, but the default is alphabetic order of the commands. The order of handling the shortcuts is also in alphabetic order of the commands. commit 9e91318040a50c2a9709d88b4678962191c4d22f Author: Mike FABIAN Date: Thu May 6 16:16:45 2021 +0200 Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (138 of 138 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_CN/ Translation: ibus-table/app commit 666fb9800db5de57396d4978b29399a4feebe69a Author: Oğuz Ersen Date: Wed May 5 11:12:45 2021 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (138 of 138 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translation: ibus-table/app commit dc48c3b5fc8d81fa8f46240554abf33cab4a791e Author: Mike FABIAN Date: Tue May 4 20:33:30 2021 +0200 Translated using Weblate (Japanese) Currently translated at 33.3% (46 of 138 strings) Translated using Weblate (German) Currently translated at 100.0% (138 of 138 strings) Co-authored-by: Mike FABIAN Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ja/ Translation: ibus-table/app commit afad554f9a6e85b79ba1adc37a26aa414d13e437 Author: Yuri Chornoivan Date: Tue May 4 20:20:13 2021 +0200 Translated using Weblate (Ukrainian) Currently translated at 100.0% (138 of 138 strings) Co-authored-by: Yuri Chornoivan Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ Translation: ibus-table/app commit 19f342ef329b7967d0a31fc18a9aa90c030a6865 Author: Weblate Date: Tue May 4 20:20:12 2021 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translation: ibus-table/app commit 1278ce6bd18e395349448dc7c14fce79bf094096 Author: Mike FABIAN Date: Tue May 4 20:10:59 2021 +0200 Update ibus-table.pot, two new messages The two new messages are for the dark theme mode which will become available in the next release. commit f4a027ebc4f094ba8912b003cec053d7996bbe57 Author: Mike FABIAN Date: Mon Apr 19 08:33:21 2021 +0200 Release 1.12.6 commit c09f1fd4caf202e5250538ff830633ed321415d7 Author: Mike FABIAN Date: Mon May 3 09:17:57 2021 +0200 Update ibus-table.pot (Only line numbers changed) commit 7a090b62d8661c9b7debd0385a54c59ccf598a3d Author: Mike FABIAN Date: Mon May 3 08:52:13 2021 +0200 In main.py “import factory” only when the --xml option is not used “import factory” is only needed in IMApp and not when using “python3 main.py --xml”. And importing factory imports other stuff which imports Gtk and that needs a display. By moving to import of factory to where it is really needed it becomes possible to use the --xml option in an environment where there is no display without getting an error message like this: $ env -u DISPLAY python3 main.py --xml Unable to init server: Could not connect: Connection refused The --xml option is used by “ibus write-cache” which is used during rpm updates and then there is often no display and the above error message appears. Resolves: rhbz#1955283 See: https://bugzilla.redhat.com/show_bug.cgi?id=1955283 commit da2548663d77fce75c22ffea8fc24d22e52e4cf9 Author: Mike FABIAN Date: Mon Apr 19 08:26:57 2021 +0200 Make the keybindings treeview sortable by clicking the column headers commit 3d9a20562d0c5ad9efeefb90b14e578e5e3ac478 Author: Mike FABIAN Date: Wed Mar 10 17:27:02 2021 +0100 Remove deprecated bind_textdomain_codeset(DOMAINNAME, "UTF-8") https://docs.python.org/3.8/library/gettext.html says: “Deprecated since version 3.8, will be removed in version 3.10.” commit 60430f9d7177444dd2a646a602f628e0d8184ad8 Author: Rafael Fontenelle Date: Mon Mar 8 03:01:47 2021 +0100 Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (136 of 136 strings) Co-authored-by: Rafael Fontenelle Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translation: ibus-table/app commit f54dde19af97817780c478907eee502c3476c593 Author: Mike FABIAN Date: Thu Mar 4 21:19:01 2021 +0100 Release 1.12.5 commit 3a7248b1b59903e68b10cc3a457c58e8e0ba9cd1 Author: Mike FABIAN Date: Thu Mar 4 21:07:18 2021 +0100 Return False in _execute_command_commit_candidate_number(self, number) if number out of range Was reported as an issue in ibus-table-others with the ipa-x-sampa table. But it is actually and ibus-table bug. When using a keybinding to commit a candidate with a certain number, ibus-table crashed when the number was out of range of the currently displayed lookup table. Resolves: https://github.com/moebiuscurve/ibus-table-others/issues/21 commit b633b8c3eb9c3462bfd662677d52e6352c03be9a Author: Anonymous Date: Fri Mar 5 17:50:43 2021 +0100 Translated using Weblate (Sinhala) Currently translated at 4.4% (6 of 136 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/si/ Translation: ibus-table/app commit 6954a3290176461094a805a31cb707248bdfcbcd Author: Hela Basa Date: Wed Mar 3 22:12:19 2021 +0100 Added translation using Weblate (Sinhala) Co-authored-by: Hela Basa commit f41791d752a7a398b57f88e07bb2871ae533ca1c Author: Mike FABIAN Date: Tue Feb 2 11:42:49 2021 +0100 Use “from unittest import mock” instead of just “import mock”. Since Python 3.3, mock is part of unittest in the standard library. The third-party `mock` library is a backport for older Python versions. This makes it possible to remove the “BuildRequires: python3-mock” from the ibus-table.spec file. commit 0d542da882839de677a892530b19f459be1c1176 Author: Anonymous Date: Wed Jan 27 14:40:04 2021 +0100 Translated using Weblate (Chinese (Traditional) (zh_TW)) Currently translated at 66.9% (91 of 136 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_TW/ Translation: ibus-table/app commit 54a0f6fc8f05f322892cd78e219f6f0ae1eca618 Author: Mike FABIAN Date: Sun Jan 24 19:09:29 2021 +0100 Release 1.12.4 commit 84e30e1f3af4e1b86ebee652e440c53b53a222cc Author: Dingzhong Chen Date: Fri Jan 22 09:36:59 2021 +0100 Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (136 of 136 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (136 of 136 strings) Co-authored-by: Dingzhong Chen Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_CN/ Translation: ibus-table/app commit 23965bb4e0acbb1b2b18c154a6561070670266c3 Author: Anonymous Date: Fri Jan 22 09:36:59 2021 +0100 Translated using Weblate (Persian) Currently translated at 11.7% (16 of 136 strings) Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 70.5% (96 of 136 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 92.6% (126 of 136 strings) Translated using Weblate (Spanish) Currently translated at 96.3% (131 of 136 strings) Translated using Weblate (Czech) Currently translated at 38.2% (52 of 136 strings) Co-authored-by: Anonymous Co-authored-by: Weblate Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/cs/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fa/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_CN/ Translation: ibus-table/app commit f7aa4f992fd1bc26a98bdc312fc05be62d3db673 Author: Mike FABIAN Date: Wed Jan 6 13:36:43 2021 +0100 Release 1.12.3 commit 06d69f910604b3a593874dc8d046732e269295dd Author: Mike FABIAN Date: Mon Jan 4 16:02:21 2021 +0100 Pass the key for the command 'cancel' (default Esc) through if the preedit is empty Resolves: https://github.com/kaio/ibus-table/issues/64 commit 96a56b913a3b7f6a42d3cdc30522fc83c8407c4b Author: Mike FABIAN Date: Mon Jan 4 08:36:22 2021 +0100 Release 1.12.2 commit 637a7ee7d2f590013d9a2006ea479c2eb7a90a83 Author: Anonymous Date: Wed Dec 30 14:36:02 2020 +0100 Translated using Weblate (Persian) Currently translated at 11.0% (15 of 136 strings) Translated using Weblate (Portuguese (Portugal)) Currently translated at 83.8% (114 of 136 strings) Translated using Weblate (Chinese (Traditional) (zh_TW)) Currently translated at 66.1% (90 of 136 strings) Translated using Weblate (Chinese (Hong Kong) (zh_HK)) Currently translated at 14.7% (20 of 136 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 69.8% (95 of 136 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 91.9% (125 of 136 strings) Translated using Weblate (Japanese) Currently translated at 33.8% (46 of 136 strings) Translated using Weblate (Spanish) Currently translated at 94.8% (129 of 136 strings) Translated using Weblate (Czech) Currently translated at 36.0% (49 of 136 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/cs/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fa/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ja/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_CN/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_HK/ Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_TW/ Translation: ibus-table/app commit b6ddf758988d0c65567efa93582569a3b9608e29 Author: Anonymous Date: Tue Oct 13 12:28:10 2020 +0200 Translated using Weblate (Catalan) Currently translated at 91.1% (124 of 136 strings) Co-authored-by: Anonymous Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ca/ Translation: ibus-table/app commit 7b5a0c9f1e49740bf6c0b9227aa5ba9c4342a33d Author: Oğuz Ersen Date: Fri Sep 18 19:29:22 2020 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (136 of 136 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translation: ibus-table/app commit 3b199801e8051034c1d1a0f5ffc317793f40478f Author: Mike FABIAN Date: Thu Aug 27 09:49:46 2020 +0200 Release 1.12.1 commit 2ba14131533a902b306730c56ada717fe3d8e992 Author: Mike FABIAN Date: Thu Sep 3 11:57:00 2020 +0200 Code cleanup in the handling of hotkeys commit 73e11e01028e51899d4b556e47c6f9f38c9ee093 Author: Mike FABIAN Date: Thu Sep 3 13:45:46 2020 +0200 Work around timing problem updating gsettings in test_it.py commit 3721b7d0847c676373a621999682233e284266f4 Author: Mike FABIAN Date: Wed Sep 2 11:05:47 2020 +0200 Enable compose support commit 3f72398c89f4b501cd13abe65b08a3f5a95039d4 Author: Mike FABIAN Date: Mon Aug 31 16:15:11 2020 +0200 Move key event debug log entry commit c3b4e6cb0ad37564147dcbd40feb34644248cb2c Author: Mike FABIAN Date: Sun Aug 30 15:04:12 2020 +0200 Add some more comments for translators commit 4da208705f77e8843210485c9a40bf4bdb10a3dd Author: Mike FABIAN Date: Sun Aug 30 14:35:48 2020 +0200 Add buttons to move key bindings for a command up or down The order of key bindings for a certain command may matter a bit in some cases. For example, currently the first key binding for the command “commit_candidate_” is used to label the candidate with that number in the lookup table. commit 82d373647197e2ba551a9426970e73e61c1fc63a Author: Mike FABIAN Date: Sun Aug 30 12:53:53 2020 +0200 Fix the code which resolves conflicts between SELECT_KEYS and VALID_INPUT_CHARS commit 58b6a224274bb6bf310c841d7df997c85d8fd5d3 Author: Mike FABIAN Date: Sun Aug 30 12:43:19 2020 +0200 Remove obsolete comment This comment is obsolete because the configurable key bindings. A similar comment is now in it_util.py above the code which replaces SELECT_KEYS = 1,2,3,4,5,6,7,8,9,0 found in a table where the digits are also valid input with SELECT_KEYS = F1,F2,F3,F4,F5,F6,F7,F8,F9,F10. commit ee82ecd6692df27457e39d1afdaef767fb780a08 Author: Mike FABIAN Date: Thu Aug 27 17:58:54 2020 +0200 Improve a Translators: comment commit de5e3096e527cd060406166fee7589ec21299fd2 Author: Mike FABIAN Date: Thu Aug 27 12:33:24 2020 +0200 Make translations of 'Edit key bindings for command “%s”' work commit 0a99e79c991b6dc719545da85fb2fdb26d8bd225 Author: Mike FABIAN Date: Wed Aug 26 18:09:56 2020 +0200 Rewrite on_gsettings_value_changed() in table.py commit 51fcd35f3d96f4bf7bd76052232dfd902674bda4 Author: Mike FABIAN Date: Wed Aug 26 23:34:15 2020 +0200 Fix some pylint warnings commit 6e1ebe86a4a9d991b55686c11c2eca8c64594f7f Author: Jean-Baptiste Holcroft Date: Thu Sep 3 07:07:12 2020 +0200 Translated using Weblate (French) Currently translated at 100.0% (136 of 136 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ commit 2fa11bbc93c050ee7e7468b3b15d057d023fb7a9 Author: Oğuz Ersen Date: Wed Sep 2 12:12:53 2020 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (136 of 136 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ commit 5dda845db4c2fef30ef1e5f8bd61f6130e1ae026 Author: Yuri Chornoivan Date: Wed Sep 2 11:34:16 2020 +0200 Translated using Weblate (Ukrainian) Currently translated at 100.0% (136 of 136 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ commit e48f132af2496ac74beea41a4b83890ad38e016b Author: Mike FABIAN Date: Wed Sep 2 11:22:03 2020 +0200 Translated using Weblate (German) Currently translated at 100.0% (136 of 136 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ commit 22f93c217715a546c92ccb3e0cfc0c2a70c204bf Author: Weblate Date: Wed Sep 2 11:22:03 2020 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ commit fd1fc0ddeade9c4b3723b1c93cfd29fd28762d21 Author: Mike FABIAN Date: Wed Sep 2 11:13:23 2020 +0200 Update ibus-table.pot commit 1b91dc6e406c046c69ec55137bae8ecf8383e06c Author: Anonymous Date: Tue Sep 1 12:28:11 2020 +0200 Translated using Weblate (Catalan) Currently translated at 91.7% (123 of 134 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ca/ commit 27501441c8c61c01c3ef8d562634db97144507fb Author: Oğuz Ersen Date: Thu Aug 27 17:53:20 2020 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (134 of 134 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ commit c0e8466b8c90edbc250189c1e9b0ac602cdbfbf5 Author: Yuri Chornoivan Date: Thu Aug 27 09:43:15 2020 +0200 Translated using Weblate (Ukrainian) Currently translated at 100.0% (134 of 134 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ commit 64803a30a127a5dfcf911d44c69304c88c7b3f15 Author: Julien Humbert Date: Thu Aug 27 09:43:15 2020 +0200 Translated using Weblate (French) Currently translated at 100.0% (134 of 134 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ commit 2b5485a590d4236fbcca9ddfb34c52c8b6b859b8 Author: Mike FABIAN Date: Thu Aug 27 09:43:14 2020 +0200 Translated using Weblate (German) Currently translated at 100.0% (134 of 134 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ commit 1b7abb048d7a1521f5af680b577a480ba761ed86 Author: Weblate Date: Thu Aug 27 09:43:14 2020 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ commit 5413469f9f06a55ef06bb1f3c9da4cd5f64b7ac3 Author: Mike FABIAN Date: Thu Aug 27 00:15:33 2020 +0200 Update ibus-table.pot (New translatable strings from it_util.py) commit c65614a875bcc968386807c9b9a7bfa3efae447d Author: Mike FABIAN Date: Thu Aug 27 00:12:38 2020 +0200 Add engine/it_util to POTFILES (The about and the key input dialogs are there) commit 4b395bb645961220aabacbb70a31be04fe15482e Author: Oğuz Ersen Date: Wed Aug 26 23:07:48 2020 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (127 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ commit f7f4089d22cc5c6ede22124a7d5dbf1e711e5963 Author: Mike FABIAN Date: Wed Aug 26 00:31:39 2020 +0200 Release 1.12.0 commit 9239878729427a7e6672ba471123235f8601b6a5 Author: Mike FABIAN Date: Wed Aug 26 12:29:50 2020 +0200 Put exact (except tone) pinyin matches next after exact matches in the candidate list Resolves: https://github.com/kaio/ibus-table/issues/63 commit cfc1ca83aa64e3e995709e18d304295da64dd7f3 Author: Yuri Chornoivan Date: Wed Aug 26 10:24:44 2020 +0200 Translated using Weblate (Ukrainian) Currently translated at 100.0% (127 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ commit 53e4382017d8626c7676968d43ffcf8ccb59f5c6 Author: Mike FABIAN Date: Wed Aug 26 10:24:43 2020 +0200 Translated using Weblate (Japanese) Currently translated at 31.4% (40 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ja/ Translated using Weblate (French) Currently translated at 97.6% (124 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ commit bd532cb1b36b52047b50bfaf847052ea3892d929 Author: Anonymous Date: Wed Aug 26 10:24:43 2020 +0200 Translated using Weblate (Persian) Currently translated at 10.2% (13 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fa/ Translated using Weblate (Portuguese (Portugal)) Currently translated at 86.6% (110 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ Translated using Weblate (Turkish) Currently translated at 97.6% (124 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ Translated using Weblate (Chinese (Traditional)) Currently translated at 67.7% (86 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_TW/ Translated using Weblate (Chinese (Hong Kong)) Currently translated at 11.0% (14 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_HK/ Translated using Weblate (Chinese (Simplified)) Currently translated at 65.3% (83 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_CN/ Translated using Weblate (Portuguese (Brazil)) Currently translated at 93.7% (119 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translated using Weblate (Spanish) Currently translated at 97.6% (124 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translated using Weblate (Czech) Currently translated at 36.2% (46 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/cs/ Translated using Weblate (Catalan) Currently translated at 92.1% (117 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ca/ Translated using Weblate (French) Currently translated at 97.6% (124 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ Translated using Weblate (Japanese) Currently translated at 31.4% (40 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ja/ commit 0b4272cec4744c6879be81ad2990e4e2368e78ea Author: Mike FABIAN Date: Wed Aug 26 02:10:18 2020 +0200 Translated using Weblate (Japanese) Currently translated at 29.1% (37 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ja/ Translated using Weblate (German) Currently translated at 100.0% (127 of 127 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ commit ed42e3d209e80b837b2882de4c32cd4c81c4a1d3 Author: Weblate Date: Wed Aug 26 02:10:17 2020 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ commit 500b8cfdaf8ce5c1e637c72811808a635d3a7c58 Author: Mike FABIAN Date: Wed Aug 26 00:19:51 2020 +0200 Update ibus-table.pot commit 7c94515e64421c139901aa22887399587bcec31e Author: Mike FABIAN Date: Tue Aug 25 22:47:01 2020 +0200 Use new 'debuglevel' option commit 29bfe8a88d2ef56bc99f51d2bbae813cb470a5e1 Author: Mike FABIAN Date: Tue Aug 25 18:41:09 2020 +0200 Sync new default keybinding handling from the setup tool to table.py commit f4c57c2c1bc46dd4d5d25a5d60c59f3df304c791 Author: Mike FABIAN Date: Tue Aug 25 19:01:21 2020 +0200 Remove unused function select_key(self, keycode) commit 85a8e5f72b7c3dffe77f4dd76dbec64ebe70d13c Author: Mike FABIAN Date: Tue Aug 25 16:25:42 2020 +0200 Remove “spacekeybehavior” option Now all keybindings are configurable. Therefore, the option to choose the behaviour of the space key makes no sense anymore. In the setup tool, there is now a new tab to configure all the keybindings, one can configure the behaviour of the space key there as well. commit 23db98cec23069d3ebd2f3b217dd51e6bbaa4722 Author: Mike FABIAN Date: Wed Aug 19 15:12:19 2020 +0200 New setup tool, now keybindings can be configured with a GUI Resolves: https://github.com/kaio/ibus-table/issues/57 Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1133127 commit 1b7f00a39802fe2c4a87b337f8913b7f8162ecb8 Author: Mike FABIAN Date: Mon Aug 24 09:40:17 2020 +0200 Use deep copy in set_keybindings() commit 4e48dfb25e06d70b2c0cbd8d7777a943e386f637 Author: Mike FABIAN Date: Sat Aug 22 02:50:26 2020 +0200 Fix typo in old setup tool which mistakenly disabled the autocommit combobox for wubi-jidian86 commit b08006c8495f2d2c4849a385231d9e3ca88b45bc Author: Mike FABIAN Date: Thu Aug 20 15:20:26 2020 +0200 Allow lookup table orientation “System Default” in old setup tool commit a3ffdbf1cfad29cd3b3c807ff1968add9e9f3ec8 Author: Mike FABIAN Date: Tue Aug 25 16:05:15 2020 +0200 Use unit_test=True when instantiating Tabsqlitedb in test_0_gtk.py To avoid failing tests because of the cache. commit d5b6fd7dd5bce1f28354b0b707b43b9591031b93 Author: Mike FABIAN Date: Thu Aug 20 11:58:21 2020 +0200 Remove redundant line commit 06edda1ed8becf7e9215b1219830265b53835ba9 Author: Mike FABIAN Date: Tue Aug 18 19:22:38 2020 +0200 Fix some pylint warnings commit 8120e5fa3597a021d6a3b50f132dcbcae4501829 Author: Mike FABIAN Date: Sun Aug 16 02:27:58 2020 +0200 Release 1.11.0 commit 1c4966d076c8ed63a3f9754ab8a805ed2443a746 Author: Mike FABIAN Date: Sun Aug 16 02:31:58 2020 +0200 Update ibus-table.pot (only line numbers changed) commit 2c97c38301b762830cecf3996ad4c5b230b41164 Author: Mike FABIAN Date: Wed Aug 12 11:09:57 2020 +0200 Make key bindings configurable Only via the command line for the moment, not yet easy to do for normal users. I have to rewrite the setup tool eventually to make that possible. Resolves: https://github.com/ibus/ibus/issues/2241 This rewrite of the handling of the key bindings also fixes the problem reported in https://github.com/ibus/ibus/issues/2241 that the Shift_L key cannot switch between Chinese and English mode when using google-chrome. commit 7e02ee75852218afa27dc0d6e6430a33b34f8e64 Author: Mike FABIAN Date: Wed Aug 12 10:17:02 2020 +0200 Move KeyEvent class to it_util.py to make it usable from the setup tool commit 9309c393173289819330c79810d608cabd9b31a5 Author: Mike FABIAN Date: Thu Aug 6 16:00:03 2020 +0200 Merge Editor class into TabEngine class It makes no sense to have an extra class “Editor” when TabEngine needs to access most internals of the Editor class all the time. commit a30872906dd4a6661e2793d8288ee44b2e360aae Author: Mike FABIAN Date: Wed Jul 15 13:59:15 2020 +0200 Release 1.10.1 commit 422fbed8f48d051f0bf82387f6100c6d1b1b3aa8 Author: Mike FABIAN Date: Fri Jul 17 11:37:12 2020 +0200 Skip GUI test if wubi-jidian86 table is not installed commit 23c55adc85cb2b445eeb6e92310301874d31774e Author: Mike FABIAN Date: Thu Jul 16 09:03:27 2020 +0200 Add *.log and *.trs to tests/.gitignore commit b0a49bee0e50edaa5d1b80e5a9c72301671d219d Author: Mike FABIAN Date: Wed Jul 15 13:56:25 2020 +0200 Fix warnings and errors in ibus-table.appdata.xml commit 07ee590b63392b96498901e40c04521ac3fb491c Author: Mike FABIAN Date: Wed Jul 15 18:17:19 2020 +0200 Before set_up() returns False it needs to call tear_down() This is necessary to call the stop() functions of the patchers. Because if setUp() of a test case decides to skip, tearDown() is apparently not called. commit 88d29d203c310928719c66a52262a2fb98c5b2dd Author: Mike FABIAN Date: Mon Jul 13 20:41:35 2020 +0200 Better way to patch the IBus stuff with the mock classes in the unit tests commit d4d0fba272581686139438cbe7d08c7df0b19ca9 Author: Mike FABIAN Date: Tue Jul 7 20:11:24 2020 +0200 Add a GTK test for CI commit 767809be71b3bc58e068b98ed7f4d77ffaf79f3c Author: Weblate Date: Sat Jul 11 17:27:42 2020 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ commit 91b7c8621da06e9327d2f330d53e0b81b208c8d2 Author: Boyuan Yang <073plan@gmail.com> Date: Sat Jul 11 17:27:42 2020 +0200 Translated using Weblate (Chinese (Simplified)) Currently translated at 76.7% (89 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_CN/ commit 4b50f8fc926c335d66693abaffd9045471965f5f Author: Boyuan Yang Date: Mon Feb 17 16:23:14 2020 -0500 Make output of ibus-table-createdb deterministic With this patch, the output of ibus-table-createdb would be of determined order as proposed by the Reproducible Builds project (https://reproducible-builds.org/). Downstream Debian bug report can be found at https://bugs.debian.org/797521 . Even though python's dict has become ordered since Python 3.6+, a `sorted()` function would be harmless and benefit users of Python 3.5, like users of Debian 9. commit dad98d15fab198f621ceb247eb885a893c1c4940 Author: Côme Borsoi Date: Fri Jul 10 04:27:40 2020 +0200 Translated using Weblate (French) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ commit 853ac39817e49a661fc8d4a6e2b726cfa1bfedbf Author: Weblate Date: Fri Jul 10 04:27:39 2020 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ Translated using Weblate (Persian) Currently translated at 6.8% (8 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fa/ Translated using Weblate (Chinese (Traditional)) Currently translated at 75.8% (88 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_TW/ Translated using Weblate (Chinese (Simplified)) Currently translated at 62.0% (72 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/zh_CN/ Translated using Weblate (Japanese) Currently translated at 21.5% (25 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ja/ Translated using Weblate (Czech) Currently translated at 19.8% (23 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/cs/ Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ commit efbe7099e192411f5b5c61572a33d17d7747a9c6 Author: Weblate Date: Tue Jul 7 23:27:42 2020 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ commit 7ae75294368fd2c037e62dc8d12271b48b0f5c41 Author: Côme Borsoi Date: Tue Jul 7 23:27:39 2020 +0200 Translated using Weblate (French) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ commit 82c22dafbd2dd113d229eeb3e8fa5706b735d59b Author: Weblate Date: Mon Jul 6 08:56:21 2020 +0200 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ commit a402ab611153a43a1053acd2eb6beb286b720581 Author: Oğuz Ersen Date: Mon Jul 6 08:56:21 2020 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ commit 5d3179a2100d6a2b2bb0838cb0b841eb18a916e1 Author: Mike FABIAN Date: Mon Feb 17 16:25:03 2020 +0100 Release 1.10.0 commit 4e01c63cf3cadc8d3098cbf2f827975606b67973 Author: Mike FABIAN Date: Wed Jul 1 17:55:52 2020 +0200 Update ibus-table.pot (only line numbers changed) commit 6bc4cf33f6e6f5461217a3a211b2ec26d163a6e1 Author: Mike FABIAN Date: Thu Jul 2 13:23:51 2020 +0200 Fix a few pylint warnings commit e354bcdfb5fd7339cd9bb252169aa4ee9cb681d9 Author: Mike FABIAN Date: Mon Feb 24 07:38:30 2020 +0100 Restructure input mode, pinyin mode, suggestion mode commit e35a4fe5f64da55300c4966f2994f4d95d0f4e1a Author: Mike FABIAN Date: Wed Jul 1 17:01:39 2020 +0200 Fix problems with property menus Property menus were behaving strangely sometimes. For example, when choosing pinyin mode in the property menu, then moving the focus to a client window and typing in pinyin, then opening the pinyin property menu again, it showed table mode, not pinyin mode. Although the real mode was pinyin mode. Fix the property menu handling by making the code as similar as possible with the property menu handling in ibus-typing-booster. The property menu handling code in ibus-typing-booster code has several bugs fixed, and it is easier to maintain. commit a913869f02c7fd0b26ad2ea2e86e33bc4f74da83 Author: Mike FABIAN Date: Tue Jun 30 18:12:43 2020 +0200 Skip test cases for engines when the database for that engine is not installed commit 0a2d3122f4c1b6f99d3b1b23f490c28215c1c2f8 Author: Manuela Silva Date: Fri May 22 12:40:27 2020 +0200 Translated using Weblate (Portuguese (Portugal)) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ commit a2dfc6dc6d58156fab521f0e6823ff53ff8c7530 Author: Manuela Silva Date: Wed May 13 15:40:24 2020 +0200 Translated using Weblate (Portuguese (Portugal)) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ commit c7e0443ef01da13751d964906ca5b5c9b4d09526 Author: Manuela Silva Date: Wed May 6 12:40:21 2020 +0200 Translated using Weblate (Portuguese (Portugal)) Currently translated at 97.4% (113 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ commit 3d11c5417722aab89d89fd605c5b2aee173eda5a Author: Adolfo Jayme Barrientos Date: Sun Apr 26 05:40:18 2020 +0200 Translated using Weblate (Spanish) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/es/ Translated using Weblate (Catalan) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ca/ commit da68840058cf742a4e5059a9bcc06edeec3994f7 Author: Adolfo Ketzer Date: Sun Apr 26 05:40:18 2020 +0200 Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.6% (111 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_BR/ commit 35f6fae24286a644fdd1b7ac65edc56e0aa0256f Author: Oğuz Ersen Date: Thu Apr 16 20:40:17 2020 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ commit 001c42254e3df3b05790d0b8ac447b0a9a45b6a3 Author: Oğuz Ersen Date: Mon Apr 13 08:29:51 2020 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ commit e1a899e866940cdb088ed895de1c0509bbb4fd33 Author: Manuela Silva Date: Wed Apr 8 09:54:08 2020 +0200 Translated using Weblate (Portuguese (Portugal)) Currently translated at 94.8% (110 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ commit bb59a830bc923dd898c6c55146b0161f45cad3f7 Author: Oğuz Ersen Date: Wed Apr 8 09:54:07 2020 +0200 Translated using Weblate (Turkish) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ commit fb5b66fc2ceb1e738a761d5af836b1ab5b82e577 Author: Manuela Silva Date: Sun Mar 1 16:38:21 2020 +0100 Translated using Weblate (Portuguese (Portugal)) Currently translated at 93.9% (109 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ Translated using Weblate (Portuguese (Portugal)) Currently translated at 91.3% (106 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ commit eeafea1f484720135bf817df7b74caeaf7ad971e Author: Oğuz Ersen Date: Sun Feb 23 18:38:19 2020 +0100 Translated using Weblate (Turkish) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ commit 30160d08b801ee3d702db3105dbb316aee638728 Author: Yuri Chornoivan Date: Sun Feb 23 18:38:19 2020 +0100 Translated using Weblate (Ukrainian) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/uk/ commit fccb68f8b31ba9eb154096f89f7da6f4fb305ea8 Author: Julien Humbert Date: Sun Feb 23 18:38:19 2020 +0100 Translated using Weblate (French) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/fr/ commit e4a572b0b404c6735259a28a9c10d0cf5da2f546 Author: Mike FABIAN Date: Thu Feb 20 12:34:30 2020 +0100 Translated using Weblate (German) Currently translated at 100.0% (116 of 116 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/de/ commit bdafd4190826460fed4f5c9e3f53e65ed2af6315 Author: Weblate Date: Thu Feb 20 12:34:30 2020 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/ commit fc70d558e0526a28aa464c2c164c8f84ee88fc60 Author: Mike FABIAN Date: Mon Feb 17 16:52:55 2020 +0100 Update ibus-table.pot, new translatable strings for new “Suggestion mode” commit 270939a8b989e9d84570adbcc9f295c9c9ba9c88 Author: Mike FABIAN Date: Wed Feb 19 14:39:27 2020 +0100 Fix typo in comment commit b42ddd39c4e82164fad9f75e9df382811e728d68 Author: Mike FABIAN Date: Tue Feb 18 15:38:46 2020 +0100 Fix some pylint warnings commit 8786c6f98457bc1496bce1170c011d9d116f3d92 Author: Mike FABIAN Date: Tue Feb 18 14:15:39 2020 +0100 Use “Suggestion mode” instead of “Legend mode” in translatable strings commit 0df767cb026dc25d6e8823815500fb505fde2d06 Author: Mike FABIAN Date: Tue Feb 18 15:07:16 2020 +0100 Use LOGGER.exeption() in exception handlers commit 47e8f3e5e4b8e6d7ecdcbc25b46e893ea527eb0c Author: Mike FABIAN Date: Tue Feb 18 10:07:45 2020 +0100 Use python logging module with log file rotation instead of writing to stdout/stderr commit 607f6e626178993659b31263cfabdd6769b10dc4 Author: Mike FABIAN Date: Mon Feb 17 18:25:07 2020 +0100 Add test cases for suggestion mode commit f66bfe4fda7dddffd3ca1bbfbf9af552a78533f6 Author: Peng Wu Date: Wed Jan 22 13:42:23 2020 +0800 fixes pinyin mode commit 60d2f37337a415374ef841a273c22abfa17c1585 Author: Peng Wu Date: Mon Oct 21 14:08:45 2019 +0800 fixes suggestion mode menu item commit 1472c26c150aa7614dd8e6da8f9e93d524ff9b85 Author: Peng Wu Date: Tue Sep 17 11:19:57 2019 +0800 fixes tabcreatedb.py commit f5be00f407a62aa46069f6e99d9930c21c8462e2 Author: Peng Wu Date: Mon Sep 9 14:24:57 2019 +0800 fixes python compile commit 800d5c684526273b174b119bc7587d06bd312772 Author: Peng Wu Date: Fri Sep 6 15:37:59 2019 +0800 re-factor class TabEngine in progress commit 45dd34eaf2ecd3d21bde377c592e7d5a59d62afe Author: Peng Wu Date: Fri Sep 6 13:23:46 2019 +0800 start to re-factor class TabEngine commit e9dafcead4c692863ab48fd7551cb2bc6e6e56d9 Author: Peng Wu Date: Tue Sep 3 14:32:58 2019 +0800 re-factor candidate methods commit 6bad3d71d67a01f613fef16ce495788329068f48 Author: Peng Wu Date: Fri Aug 30 14:53:11 2019 +0800 re-factor append_candidate_to_lookup_table method commit c50c37461fe90d63f80f45728796c038e543aeba Author: Peng Wu Date: Wed Jul 24 15:23:28 2019 +0800 update tabcreatedb.py for suggestion candidates commit d3f4a35b34f8110da067376863f83ecdc23cacf7 Author: Peng Wu Date: Tue Jul 23 16:14:23 2019 +0800 update tabsqlitedb.py for suggestion candidates commit 0883006072a9fe340c9325a7975e7596d3d308af Author: Peng Wu Date: Mon Jul 22 17:18:06 2019 +0800 update Makefile.am commit 6df76a02d147b21c7bd1ce817253ec7d017779bc Author: Peng Wu Date: Mon Jul 15 14:58:43 2019 +0800 import phrase.txt.bz2 commit 6eeaa8cf35b452a5e8b43af84cb6a464f6e1e8eb Author: Mike FABIAN Date: Wed Feb 12 17:58:19 2020 +0100 Release 1.9.25 commit a0f8dcce840b5abebb930312abd7a7ab012ce023 Author: Mike FABIAN Date: Fri Feb 14 11:59:12 2020 +0100 Fix crash when changing some options using the menu or the floating panel Resolves: https://github.com/mike-fabian/ibus-table/issues/26 Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1803028 commit 8a8decee675a7ef1f7679081537b2fffeb82fc08 Author: Anonymous Date: Thu Jan 23 10:10:39 2020 +0100 Translated using Weblate (Portuguese (Portugal)) Currently translated at 81.1% (90 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ commit 02afce2a1542a27388db02f1dd8a4dc1362ad0eb Author: Manuela Silva Date: Thu Jan 23 10:10:39 2020 +0100 Translated using Weblate (Portuguese (Portugal)) Currently translated at 81.1% (90 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/pt_PT/ commit c0deea6da57110c69fe5537b79a0ac500bf60918 Author: Mike FABIAN Date: Wed Jan 22 16:13:57 2020 +0100 Release 1.9.24 commit 7c65cf1f090374518d1a475a163fb9871d460caa Author: Mike FABIAN Date: Tue Jan 7 17:37:39 2020 +0100 Add new test cases for ibus-table-others-1.3.11 New in ibus-table-others-1.3.11: - Extend russian translit for latin slavic layouts. - Add Vietnamese input methods Telex and VNI commit 07efc1eb30ccb2e89f0532c99a4cc784a28d1d7e Author: Mike FABIAN Date: Tue Jan 7 12:02:00 2020 +0100 Add new test case for ibus-table-others-1.3.10 Most of Unicode 9.0 block Mathematical Alphanumeric Symbols are added in the “latex” table of ibus-table-others-1.3.10. commit 26d2b558fd23359539b7ed4a91e2e32bd765a1a1 Author: Oğuz Ersen Date: Wed Jan 22 09:07:20 2020 +0100 Translated using Weblate (Turkish) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.fedoraproject.org/projects/ibus-table/app/tr/ commit 3dbdf93ef5c2ce54f028ded2c77e032eb6d00238 Author: Julien Humbert Date: Sun Jan 19 02:47:54 2020 +0100 Translated using Weblate (French) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/fr/ commit fcc269353eff5ceb29b1a254b67b22dfab67985c Author: Anonymous Date: Sun Jan 19 02:47:54 2020 +0100 Translated using Weblate (Persian) Currently translated at 2.7% (3 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/fa/ Translated using Weblate (Portuguese (Portugal)) Currently translated at 75.7% (84 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/pt_PT/ commit accfc505af85967e2956f7d85f0c1e050486afd3 Author: Manuela Silva Date: Tue Jan 14 15:01:11 2020 +0100 Translated using Weblate (Portuguese (Portugal)) Currently translated at 74.8% (83 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/pt_PT/ commit 6edd412964de7acecb0caa02fa6bff605b0cbee0 Author: Ahmad Haghighi Date: Tue Jan 14 15:01:11 2020 +0100 Added translation using Weblate (Persian) commit dd596ebe51823b6e7804e739192ea08ec73e2821 Author: Mike FABIAN Date: Tue Jan 7 13:47:56 2020 +0100 Translated using Weblate (Ukrainian) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/uk/ Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translated using Weblate (Spanish) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/es/ Translated using Weblate (German) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/de/ Translated using Weblate (Catalan) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/ca/ commit 32c6515bbc6896736edec312e04136071090c4aa Author: Anonymous Date: Tue Jan 7 13:47:56 2020 +0100 Translated using Weblate (Turkish) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/tr/ Translated using Weblate (French) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/fr/ Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/ commit cb1bd986d01bfd9f65445b473013d1ed8ea3b18f Author: Mike FABIAN Date: Tue Jan 7 13:39:16 2020 +0100 Update ibus-table.pot for Rafael Fontenelle’s fixes commit 038606649a82d3bdea57bd6ed1463be882dd566b Author: Rafael Fontenelle Date: Fri Jan 3 14:44:35 2020 -0300 preferences: minor word changes commit 75b68ee00fd83f88d38a262de92cb2d947eb2982 Author: Mike FABIAN Date: Tue Jan 7 12:47:23 2020 +0100 Release 1.9.23 commit 42134fe0ffc6d7c170c11d183d9294113af5f70c Author: Mike FABIAN Date: Mon Jan 6 19:39:04 2020 +0100 Move MockEngine classes into a separate file and make test_itb.py runnable standalone Now one can directly run ./test_it.py Use TAPTestRunner() instead of TextTestRunner(), but only when tap.py is installed. commit 7034f592314a79903c8ce5958de4deba2c13ae22 Author: Mike FABIAN Date: Mon Jan 6 19:09:56 2020 +0100 Add exist_ok=True in os.makedirs(path, exist_ok=True) to avoid failure due to race condition Resolves: rhbz#1786652 (https://bugzilla.redhat.com/show_bug.cgi?id=1786652) [abrt] ibus-table: makedirs(): os.py:221:makedirs:FileExistsError: [Errno 17] File exists: '/home/username/.local/share/ibus-table' commit 73de2f7068382a49f0d20d97cbeb53008db32024 Author: Anonymous Date: Tue Jan 7 11:01:34 2020 +0100 Translated using Weblate (Portuguese (Portugal)) Currently translated at 31.5% (35 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/pt_PT/ commit b226cbf15bb0e3d700cf00d2230e784072472d6a Author: Manuela Silva Date: Tue Jan 7 11:01:34 2020 +0100 Translated using Weblate (Portuguese (Portugal)) Currently translated at 31.5% (35 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/pt_PT/ commit c1ceacbc756cf0303162748ebfdcdeb7292d471e Author: Manuela Silva Date: Mon Jan 6 10:46:03 2020 +0100 Added translation using Weblate (Portuguese (Portugal)) commit d108f8e905cfff946c23ea1dc4b9f7591aac8aca Author: Rafael Fontenelle Date: Mon Jan 6 10:46:02 2020 +0100 Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translated using Weblate (Portuguese (Brazil)) Currently translated at 20.7% (23 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/pt_BR/ commit f6ba75fdf8136008059f23e37b6f071970aaecff Author: Anonymous Date: Sun Dec 29 19:49:34 2019 +0100 Translated using Weblate (Chinese (Traditional)) Currently translated at 75.7% (84 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/zh_TW/ Translated using Weblate (Chinese (Hong Kong)) Currently translated at 2.7% (3 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/zh_HK/ Translated using Weblate (Portuguese (Brazil)) Currently translated at 17.1% (19 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translated using Weblate (Japanese) Currently translated at 14.4% (16 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/ja/ commit 01ddabf7934f9cb5b2fe51120c2240dbadee2270 Author: Jean-Baptiste Holcroft Date: Sun Dec 29 19:49:34 2019 +0100 Translated using Weblate (French) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/fr/ commit 592b6f0570bc7d10aa7e0f640d3f25c316fce312 Author: Mike FABIAN Date: Fri Dec 20 01:12:23 2019 +0100 Translated using Weblate (Portuguese (Brazil)) Currently translated at 16.2% (18 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translated using Weblate (Japanese) Currently translated at 13.5% (15 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/ja/ Translated using Weblate (Czech) Currently translated at 17.1% (19 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/cs/ commit a6c0cab280166ed04a8ff6a3b2340a3dc38573d8 Author: Julien Humbert Date: Fri Dec 20 01:12:23 2019 +0100 Translated using Weblate (French) Currently translated at 44.1% (49 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/fr/ commit f55d99e9468f7a3d6921b7d2b6a6954ab285102a Author: Anonymous Date: Fri Dec 20 01:12:22 2019 +0100 Translated using Weblate (Chinese (Simplified)) Currently translated at 62.2% (69 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/zh_CN/ Translated using Weblate (Portuguese (Brazil)) Currently translated at 16.2% (18 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/pt_BR/ Translated using Weblate (Japanese) Currently translated at 13.5% (15 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/ja/ Translated using Weblate (Czech) Currently translated at 17.1% (19 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/cs/ commit ee5568c05046d503706c99d468dfe8a842795e1c Author: Mike FABIAN Date: Tue Dec 17 15:14:34 2019 +0000 Translated using Weblate (Turkish) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/tr/ commit 736eed327df3685c0c9d46b54403e1a40e53ece0 Author: Mike FABIAN Date: Tue Dec 17 15:11:13 2019 +0000 Translated using Weblate (Chinese (Traditional)) Currently translated at 74.8% (83 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/zh_TW/ commit e6b85022d4ccf05ffb213bed412b4c336aabcb15 Author: Mike FABIAN Date: Tue Dec 17 15:14:50 2019 +0000 Translated using Weblate (Ukrainian) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/uk/ commit 2aaf51cc2fd057859709e1d9a8bdfb27df90204b Author: Mike FABIAN Date: Tue Dec 17 15:14:15 2019 +0000 Translated using Weblate (Spanish) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/es/ commit 480f71eaf896172bb473b9722e20f48515bd583b Author: Mike FABIAN Date: Tue Dec 17 15:13:56 2019 +0000 Translated using Weblate (German) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/de/ commit d7cd71bee06b2eebbce6d2a3db2bbe0828eca0e9 Author: Mike FABIAN Date: Tue Dec 17 15:09:58 2019 +0000 Translated using Weblate (Catalan) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/ca/ commit 984c90ebe5f8ed6e9665c1ba5534702f04b5f2aa Author: Weblate Date: Tue Dec 17 16:08:08 2019 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/ commit 190187fd5d92683609167844b234bcbc629ab302 Author: Mike FABIAN Date: Tue Dec 17 16:06:17 2019 +0100 Update ibus-table.pot for the spelling fix. commit d0aa98c579d0f294a0a4535f6823c1d66e3e7060 Author: Mike FABIAN Date: Tue Dec 17 15:29:58 2019 +0100 Fix misspelled word "wildchard" in the UI Resolves: https://github.com/kaio/ibus-table/issues/56 commit e8c92afb81f28fb5f9557e71361c92e444cf7bba Author: Mike FABIAN Date: Tue Dec 17 14:21:16 2019 +0100 Release 1.9.22 commit daac707c786cacf581409b76cdae6ee7e878b306 Author: Mike FABIAN Date: Tue Dec 17 13:05:04 2019 +0000 Translated using Weblate (Ukrainian) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/uk/ commit 047d43a34c865ba1e42a8a8b38f7d5af5ce6392e Author: Mike FABIAN Date: Tue Dec 17 13:06:08 2019 +0000 Translated using Weblate (Portuguese (Brazil)) Currently translated at 10.8% (12 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/pt_BR/ commit fd4d2a22e36d97c0b573c4a2fec835f0ae137821 Author: Mike FABIAN Date: Tue Dec 17 13:06:41 2019 +0000 Translated using Weblate (French) Currently translated at 43.2% (48 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/fr/ commit 9f841218bfd311a198820d9a506a4fe97566db6f Author: Mike FABIAN Date: Tue Dec 17 13:03:27 2019 +0000 Translated using Weblate (Catalan) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/ca/ commit 03bf3d08fd6125d71229574256970cb8b4ecbdf0 Author: Weblate Date: Tue Dec 17 13:59:44 2019 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/ commit bdb0f5c40ae96e1860515bd338b3bcb96714faa8 Author: Weblate Date: Tue Dec 17 13:15:23 2019 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/ commit 5de30646940d8d44f6c41cc618864d4e034246c9 Author: Oğuz Ersen Date: Mon Dec 16 19:19:29 2019 +0000 Translated using Weblate (Turkish) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/tr/ commit cf277929579b32508bf6ed3022364bd4cf38adcf Author: Mike FABIAN Date: Tue Dec 17 13:55:11 2019 +0100 Update ibus-table.pot commit 4ff87711a36cba0a0334e8924ea8300fa2a6f999 Author: Mike FABIAN Date: Tue Dec 17 13:54:38 2019 +0100 Add -c option for xgettext to enable comments for translators commit 6e3461ecee809a38a691bfa072f223927d1f7066 Author: Mike FABIAN Date: Tue Dec 17 13:42:14 2019 +0100 Add some comments for translators commit 5a451b4c2fdc7dbaad8ac2abc370deb9ed2e9214 Author: Mike FABIAN Date: Mon Dec 16 18:13:43 2019 +0000 Translated using Weblate (German) Currently translated at 80.6% (112 of 139 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/de/ commit 761bcc7e7012a0fd816b11f486e2000c97c96c44 Author: Oğuz Ersen Date: Mon Dec 16 16:08:48 2019 +0000 Translated using Weblate (Turkish) Currently translated at 100.0% (111 of 111 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/tr/ commit 39cef443ccc631ad74089bf09d7e225d9ec1b284 Author: Oğuz Ersen Date: Mon Dec 16 16:08:24 2019 +0000 Added translation using Weblate (Turkish) commit 39a60c8e57d7a7ff66d316bad0f2de4026fded12 Merge: 944a82d ae5aed3 Author: Mike FABIAN Date: Mon Dec 16 07:58:34 2019 +0100 Merge pull request #11 from weblate/weblate-ibus-table-app Update from Weblate commit 944a82d6db05272db55cf44395501f6a0ac1eb11 Author: Mike FABIAN Date: Mon Dec 16 07:21:03 2019 +0100 Add ibus-table.its and ibus-table.loc to avoid making the release descriptions and developer name in ibus-table.appdata.xml translatable Translating all the release notes would be too much for the translators, I think. So I added ibus-table.its and ibus-table.loc to ibus-table. Ibus-table’s ibus-table.its differs from the upstream /usr/share/gettext/its/metainfo.its like this: $ diff -u /usr/share/gettext/its/metainfo.its its/ibus-table.its --- /usr/share/gettext/its/metainfo.its 2019-06-16 22:33:05.000000000 +0200 +++ its/ibus-table.its 2019-12-16 07:41:40.993341715 +0100 @@ -5,9 +5,7 @@ @@ -15,4 +13,6 @@ translate="no"/> + commit ae5aed38706d69c0c74e3ede9d646d6472d312b0 Author: Jean-Baptiste Holcroft Date: Sun Dec 15 15:14:17 2019 +0000 Translated using Weblate (French) Currently translated at 42.9% (48 of 112 strings) Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/fr/ commit 46e4c89667425d379b49413e8bdd1f4cab7ede25 Author: Weblate Date: Sun Dec 15 16:13:30 2019 +0100 Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: ibus-table/app Translate-URL: https://translate.stg.fedoraproject.org/projects/ibus-table/app/ commit 3cd5c2beef555ec676933a96916feaefc546cb43 Author: Mike FABIAN Date: Sun Dec 15 15:59:51 2019 +0100 Add ibus-table.pot file to repo. commit 7bf7a90d189364678a53aad1149246b5bff3a2e8 Author: Mike FABIAN Date: Tue Jul 31 18:16:58 2018 +0200 Release 1.9.21 commit 255ba22360de30477b5e0a173dc4b2a9c65f9b1c Author: Mike FABIAN Date: Tue Aug 28 23:37:36 2018 +0200 Add missing tags to ibus-table-createdb.sgml Resolves: https://github.com/mike-fabian/ibus-table/issues/3 commit 13ccd7c78be2b572a222ca8e43cb277ed5e769de Author: Mike FABIAN Date: Fri Aug 10 16:24:32 2018 +0200 Fix some pylint warnings commit 0cb39acf1deefc6a4f0af2ff95faeee7934f5ca8 Author: Mike FABIAN Date: Tue Aug 7 00:29:18 2018 +0200 Add a test case for chinese mode using the 'wubi-jidian86' table commit 6c55a4670da78440db3fee92f875712d9219dade Author: Mike FABIAN Date: Tue Aug 7 00:28:54 2018 +0200 Make some lines shorter commit 43e900117801e7e6b52016dea0a6c54cf89874b6 Author: Mike FABIAN Date: Tue Aug 7 00:28:20 2018 +0200 Some more debug messages and comments commit 7caa4913f52edea16cac7226447dcd24a93dfc74 Author: Mike FABIAN Date: Fri Aug 3 16:40:22 2018 +0200 Add test cases for latex commit 40913515c6f6be8751c58a4b46cadfdcfc13c73b Author: Mike FABIAN Date: Fri Aug 3 12:11:16 2018 +0200 Add test cases for ipa-x-sampa commit 50fb9b9122eda743333e4b960137e0663a2d54a8 Author: Mike FABIAN Date: Fri Aug 3 10:29:13 2018 +0200 Add test cases for cangjie5 commit f9195f877c5212fef0dfa446acb328c45ba5852b Author: Mike FABIAN Date: Thu Aug 2 10:40:04 2018 +0200 Migrate IBusConfig to GSettings IBus plans to deprecate IBusConfig and suggests to migrate to GSettings. https://groups.google.com/forum/#!topic/ibus-devel/Mu1IoFX-bKE The old settings are unfortunately lost, so one has to open the setup tool and recreate ones favourite settings. Fix some minor bugs while doing the migration: - Use 4 as the default Chinese mode, not -1. 4 means no special filtering and sorting at all, which is appropriate for non-Chinese tables as well. commit d9cf5f14934ccc65255d04876bc3decac001f87a Author: Mike FABIAN Date: Thu Apr 26 10:23:10 2018 +0200 Add a test suite commit 672455cbc5cb54356b8b3924eeef9114471f4319 Author: Mike FABIAN Date: Tue Jul 31 15:57:30 2018 +0200 Do not read the dconf key lookuptableselectkeys There is no such option in the setup tool anyway, it makes no sense to read this from a dconf key if the setup tool doesn’t support it. The select keys come only from the table headers. commit 75d89b595a85abf4dea3647cca0c3190ef6a00c8 Author: Mike FABIAN Date: Tue Jul 31 15:22:15 2018 +0200 Add IBus.KEY_KP_Prior and IBus.KEY_KP_Next to the default page-up and page-down keys These have the same numerical value, so it is not really necessary to add them to self._page_up_keys and self._page_down_keys: src/ibuskeysyms.h:#define IBUS_KEY_KP_Prior 0xff9a src/ibuskeysyms.h:#define IBUS_KEY_KP_Page_Up 0xff9a src/ibuskeysyms.h:#define IBUS_KEY_KP_Next 0xff9b src/ibuskeysyms.h:#define IBUS_KEY_KP_Page_Down 0xff9b it is for clarity only. commit 433923158c24bc6626399f3e5d02d3b8ebe27baa Author: Mike FABIAN Date: Tue Jul 31 15:12:33 2018 +0200 More debug messages in _match_hotkey() commit 675a537004926d74f53f9727de3c31ec9e1ccfc2 Author: Mike FABIAN Date: Tue Jul 31 08:19:22 2018 +0200 Improve KeyEvent class to make debugging easier commit 23d8cc8b742fbcdf6428a104e3d75c2ddffdcba2 Author: Mike FABIAN Date: Mon Jul 30 17:59:05 2018 +0200 Add a debug message in select_words() commit ffbefa829d697f2e7f96af8fc9be9ae258e7972c Author: Mike FABIAN Date: Mon Jul 30 16:52:51 2018 +0200 Fix wrong syntax in debug message commit 396437c768d349e6c16678c5853fedaf47547bc3 Author: Mike FABIAN Date: Thu May 3 09:58:56 2018 +0200 Release 1.9.20 commit 593f3cd7491d9dbd131f62b1b3d861940c299114 Author: Takao Fujiwara Date: Thu May 3 09:54:19 2018 +0200 Draw InputMode text instead of icon into panel on non-Gnome desktops Resolves: https://github.com/mike-fabian/ibus-table/issues/6 commit e9a8ebaf2cca88bf7c2d9aa1ffb1c1ec847432c3 Author: Mike FABIAN Date: Thu May 3 09:46:21 2018 +0200 Make it work with Python2 again commit 1188651f58c5d0531ff85290584b45813250b24d Author: Mike FABIAN Date: Wed Sep 13 08:51:57 2017 +0200 Release 1.9.19 commit 8fc59050efc554d5e0cf1218a6be08eda539040f Author: Mike FABIAN Date: Mon Apr 30 11:38:40 2018 +0200 Add some debug code to see whether _phrases_cache is handled correctly It needs to be reset when changing the Chinese mode. And stuff committed to the user database needs to be removed. Can be tested using the SmartCangJie6 table (scj6.txt) because this table uses both USER_CAN_DEFINE_PHRASE = FALSE and DYNAMIC_ADJUST = FALSE so no tabkeys are ever removed individually from _phrases_cache but _phrases_cache is reset to empty when the Chinese mode is changed (or when other settings influencing the caching like onechar mode or wildcard characters are changed). commit 8c791d35feeca7083babf23e4a0b5c4f10a1c205 Author: Heiher Date: Fri Aug 4 11:18:05 2017 +0800 Sync phrases cache from/to external storage. commit a7c845185d561055f756971686c01c90ab0bc337 Author: Mike FABIAN Date: Wed Sep 13 08:40:28 2017 +0200 Update translations from zanata (cs new) commit 13753d1f23159e521ff8f61ed47c36211d2f0060 Author: Mike FABIAN Date: Wed Aug 2 09:23:32 2017 +0200 Release 1.9.18 commit 0cf87b9170a2d3018ddd162e553cc503f9500187 Author: Mike FABIAN Date: Wed Aug 2 09:30:48 2017 +0200 Update translations from zanata (pt_BR updated, es new) commit ccb0effe6dc15c81e4782588f709fd6dca4cb41d Author: Heiher Date: Sun Jul 23 10:37:04 2017 +0800 Don't query user database if user define phrase and dynamic adjust are disabled commit b10c2ddfa9f003a529efc7bb4f2309e899f64444 Author: Heiher Date: Wed Aug 2 15:10:03 2017 +0800 Enable hash map based cache for user database enabled. commit d68a20c1aece6092ee58b57927a554d16a425dfa Author: Heiher Date: Sun Jul 23 12:03:29 2017 +0800 Import hash map based cache for table database. commit b426d421908846973c506a666b5ac36701087c31 Author: Mike FABIAN Date: Wed Aug 2 09:17:48 2017 +0200 Fix another appdata warning commit bb7d86abea69543e435e77e67a03992cae9e8b3d Author: Jeremy Bicha Date: Mon Jul 3 00:48:05 2017 -0400 build: Install appstream metadata to /usr/share/metainfo/ commit 8d9d143769571a60d452067f5645278f2c4cd38b Author: Jeremy Bicha Date: Mon Jul 3 00:47:10 2017 -0400 appdata: Fix some validation issues commit 96e10b288da4d4c60e2201ef048d29a8fbcace6d Author: Mike FABIAN Date: Tue Aug 1 07:48:55 2017 +0200 Add 著 U+8457 to the test cases in generate-chinese-variants.py commit 3128edf8519671500b01747cf0f024fb0711c965 Author: Heiher Date: Mon Jul 24 18:48:29 2017 +0800 Fix bug in Unihan_Variants.txt, 著 U+8457 is both simplified *and* traditional Chinese commit 97619240b43968ed6296eead80139986ad2857cb Author: Mike FABIAN Date: Mon Jul 31 17:29:23 2017 +0200 Keep our fixes to Unihan_Variants which are not yet included upstream commit 7a320806d3a546eba57dddf4de7e0b644aae1bb8 Author: Mike FABIAN Date: Mon Jul 31 17:10:18 2017 +0200 Update Unihan_Variants.txt from “2016-06-01 Unicode 9.0.0” to “2017-05-14 Unicode 10.0.0” There are no new lines in Unihan_Variants.txt which are relevant for simplified and traditional detection. Unfortunately none of our fixes for simplified and traditional detection seems to be included upstream yet. commit 360933c93068ce50d3dd807bf6d22b3c1cafafc6 Author: Mike FABIAN Date: Thu Jun 1 13:11:04 2017 +0200 Release 1.9.17 commit f2ad418163efbe78d8e1ef98d8b2389499e32f3e Author: Mike FABIAN Date: Thu Jun 1 13:17:13 2017 +0200 Update translations from zanata commit 2d26e15cb828a94e4e26512626c4b783cdc9680a Author: Mike FABIAN Date: Thu Jun 1 13:08:29 2017 +0200 Load .desktop file for ibus-setup-table correctly under Gnome Wayland commit 4cf3f6d8490392de28c7fdc311d8e4e782dcd0b7 Author: Mike FABIAN Date: Thu Feb 23 05:11:25 2017 +0100 Set WM_CLASS of ibus-setup-table correctly This is needed to get the application name and icon shown correctly by gnome-shell in the top bar. gnome-shell seems to use the first argument of set_wmclass() to find the .desktop file. If the .desktop file can be found, the name shown by gnome-shell in the top bar comes from that .desktop file and the icon to show is also read from that .desktop file. If the .desktop file cannot be found, the second argument of set_wmclass() is shown by gnome-shell in the top bar. Therefore, for ibus-setup-typing-table we need: set_wmclass('ibus-setup-table', 'IBus Table Setup') commit 02f1b980582e784c22cf41915e28b706d09000e9 Author: Mike FABIAN Date: Mon Jan 16 14:46:57 2017 +0100 Release 1.9.16 commit faa9d95c9cdef4a5516f6185fa3d06f8bbf4409e Author: Mike FABIAN Date: Mon Jan 16 14:24:02 2017 +0100 Unbreak sqlite on Python 3.6 Resolves: rhbz#1413580 - [abrt] ibus-table: __init__(): factory.py:96:do_create_engine:Exception: Cannot create engine wubi-jidian86 See: https://bugzilla.redhat.com/show_bug.cgi?id=1413580 Py3.6 changed the transaction behavior; DDL commands like PRAGMA do not commit open transactions anymore, and since the default for execute() is to auto-open a transaction, setting the journal_mode fails. Changing the isolation_level to None so that transactions aren't opened anymore is a possible workaround. However, using executescript() seems like a better idea; it always commits any open transaction first. Jan Alexander Steffens (heftig) submitted this patch for ibus-typing-booster, ibus-table needs this as well to run with Python >= 3.6. commit 8291d20227e013a4ebb396a92b3dfc3de54b300a Author: Mike FABIAN Date: Mon Jan 16 13:08:39 2017 +0100 Add comment commit a4c12a577adcbf2814718167fd3362b4b2889ad9 Author: Osamu Aoki Date: Sat Jan 14 23:44:00 2017 +0900 Avoid running initialization code of ibus_table_location.py The code refactoring which placed "import ibus_table_location" at the start of this script caused regression for distribution use of this ibus-table-createdb script where there is no gurantee that the HOME directory is writable etc. This bug is reported as release critical bug as: https://bugs.debian.org/848756 https://bugs.debian.org/848765 commit 4683791c3137c4a351ffc56fa8e87f06d480f062 Author: Mike FABIAN Date: Mon Jan 16 08:25:16 2017 +0100 Release 1.9.15 commit 58272136c275eb925b0aa536c9836f6631b17368 Author: Mike FABIAN Date: Mon Jan 16 08:22:14 2017 +0100 Update translations from zanata (ca, de, fr, uk updated) commit 9f19f4689d94f37c6435cdb93ed23df050ba4996 Author: Mike FABIAN Date: Thu Sep 8 10:14:06 2016 +0200 Point to new home-page in the “About” tab. commit 0f1bb5121a470156530ed3253f40e2e28488667e Author: Mike FABIAN Date: Mon Aug 29 14:12:30 2016 +0200 Improve README commit 057c5e12575d309188830d12e1e77b1c1980bdbe Author: Mike FABIAN Date: Mon Aug 29 13:41:26 2016 +0200 Fix a typo in a comment commit 6c0677c4e54b203cf5f7dec4762112d332060f7c Author: Mike FABIAN Date: Wed Aug 24 13:45:51 2016 +0200 Release 1.9.14 commit ac1229bbc73e2ac67daf6dea98a31d9673afe38d Author: Mike FABIAN Date: Wed Aug 24 13:39:43 2016 +0200 Add test case for 乾 to make sure it is detected as both traditional and simplified Chinese commit d38e16f8a4f7fd52faf58eb1da7859ce2089c2cc Author: Mike FABIAN Date: Wed Aug 24 12:22:26 2016 +0200 Regenerate engine/chinese_variants.py commit d7f92a6f3c76daa02f271ee5a1989e748e6be7d9 Author: Mike FABIAN Date: Wed Aug 24 11:37:21 2016 +0200 Update Unihan_Variants.txt from “2015-04-30 Unicode 8.0.0” to “2016-06-01 Unicode 9.0.0” But keep our fixes which are not yet included upstream. New lines in Unihan_Variants.txt which are relevant for simplified and traditional detection: > U+27835 kSimplifiedVariant U+2C88D U+27835 = 𧠵 U+2C88D = 𬢍 > U+2C88D kTraditionalVariant U+27835 U+2C88D = 𬢍 U+27835 = 𧠵 commit 63169be512839583c4d0743f1bebc5a6a8c07a6a Merge: ac11e4e 0dde127 Author: Mike FABIAN Date: Wed Aug 24 13:18:01 2016 +0200 Merge pull request #47 from heiher/master Fix bug in Unihan_Variants.txt, 乾 U+4E7E is both simplified and traditional Chinese commit ac11e4e94a22a1064139361d657ca444125c4318 Author: Mike FABIAN Date: Tue Aug 23 18:22:04 2016 +0200 Release 1.9.13 commit bd2b87bd0bc99df3e842e6c4c8f0c82df53d54b9 Author: Mike FABIAN Date: Wed Aug 24 08:56:06 2016 +0200 Add ibus-table.appdata.xml to POTFILES.in to make it translatable Update po files. Translate the new stuff in de.po. commit 5e7f9758dec21a1499d4d7071514ac316ff0f1da Author: Mike FABIAN Date: Tue Aug 23 18:19:49 2016 +0200 When ignoring key release events, “False” should be returned, not “True” Resolves: rhbz#1369514 - When ibus-table is active the “enter command” dialog of Gnome cannot be closed with ESC See: https://bugzilla.redhat.com/show_bug.cgi?id=1369514 commit ffcca5ed7b4172da8c21a17e11f7f08a392f45c8 Author: Mike FABIAN Date: Wed Aug 24 08:06:49 2016 +0200 Specify IBus and Gtk versions before importing in setup/main.py commit b8913c5f4dfaf2529c85f70fde7cd5a7cdcc17a7 Author: Mike FABIAN Date: Wed Aug 24 08:01:16 2016 +0200 Specify IBus version before importing in engine/{factory,table}.py commit 4d59c40eb3a0b66b88d8fba006ebab0883edb70b Author: McSinyx Date: Wed Jun 22 10:47:37 2016 +0700 Specify IBus version before importing in engine/main.py commit 80639b148326ba3ab391c0bb7fb71484976a7ce2 Author: Mike FABIAN Date: Wed Aug 24 07:45:19 2016 +0200 Add ibus-table.appdata.xml and install it commit 55fa0b3cd97dae4d8941cd56abefa24508273d9c Author: Mike FABIAN Date: Wed Aug 24 08:40:54 2016 +0200 Add ca.po, fr.po, pt_BR.po, and uk.po from zanata commit d54c4612e7e80f549a1a01127b39713c187d104a Author: Mike FABIAN Date: Wed Aug 24 08:37:49 2016 +0200 pull ja.po, zh_CN.po, and zh_TW.po from zanata commit d38217aceb217fe5af9b8122aeb3c5066067334c Author: Mike FABIAN Date: Wed Aug 24 08:34:11 2016 +0200 Add .zanata-cache/ to .gitignore commit f1c4bfb7c42f71e8248acf6bc41c484bc00d9fe4 Author: Mike FABIAN Date: Wed Aug 24 07:13:32 2016 +0200 Add zanata.xml commit 0dde127843b2bf12921460fa3ab3f7e568f11d18 Author: Heiher Date: Wed Aug 24 13:43:55 2016 +0800 Fix bug in Unihan_Variants.txt, 乾 U+4E7E is both simplified *and* traditional Chinese commit edd0fea561f0f5953d291456ec851c17518e1cd1 Author: Mike FABIAN Date: Wed Mar 16 07:34:54 2016 +0100 Release 1.9.12 commit 1bf38d6cc74e9de6482b2d28f6065ef283391361 Author: Mike FABIAN Date: Wed Mar 16 07:29:50 2016 +0100 Show the table code in the candidate list when pinyin mode is used Resolves: rhbz#1318109 - [RFE] Please show Wubi table code when in pinyin mode See: https://bugzilla.redhat.com/show_bug.cgi?id=1318109, https://github.com/ibus/ibus/issues/1846 When using pinyin mode for a table like Wubi or Cangjie, the reason is probably because one does not know the Wubi or Cangjie code. So get that code from the table and display it as well to help the user learn that code. commit f02b1b2efc074e6095aa0286b2fac9f335e7a4c6 Author: Mike FABIAN Date: Fri Nov 27 09:55:37 2015 +0100 Release 1.9.11 commit 734274cc52c23acae12b075887838c3f28e58cb9 Author: Mike FABIAN Date: Fri Nov 27 09:44:52 2015 +0100 Add a few more IBus.Text.new_from_string() conversions surprisingly it works without this change on all my machines. But for 楊文齊 who uses an older system than me (Ubuntu 14.04.2 LTS, Unity desktop, IBUS 1.5.5), this change was necessary to make it work. The change looks correct anyway and works fine for me as well,so I’ll add it. commit be8eb2994a2385544ebaec12284653b3cade2c4e Author: Mike FABIAN Date: Wed Nov 25 11:06:31 2015 +0100 Fix bug in Unihan_Variants.txt, 面 U+9762 and 系 U+7CFB are both simplified *and* traditional Chinese Resolves: rhbz#1285379 See: https://bugzilla.redhat.com/show_bug.cgi?id=1285379 commit fd1523aa6f16072b9e2ff0601c3ad5353b738633 Author: Mike FABIAN Date: Tue Nov 24 07:34:34 2015 +0100 Release 1.9.10 commit b6113d6d8a601cefb3dfee2ca41267979f3cd7a8 Author: Mike FABIAN Date: Tue Nov 24 06:56:20 2015 +0100 Fix bug in Unihan_Variants.txt, 表 and 杰 are both simplified *and* traditional Chinese Resolves: rhbz#1284749 See: https://bugzilla.redhat.com/show_bug.cgi?id=1284749 commit 0f6d2a2852953f6bf34807aaaa5ad5b66a39189b Author: Mike FABIAN Date: Tue Nov 17 09:12:42 2015 +0100 Release 1.9.9 commit 72577d80a097bcc0ed675dde4222a1b1d3101250 Author: Mike FABIAN Date: Tue Nov 17 09:04:03 2015 +0100 Update copyright years commit 1affea5b31537ae1fc1e480dbad30c6112088551 Author: Mike FABIAN Date: Wed May 14 19:30:46 2014 +0200 Add optional debug code commit 35403961397f2d7dfc34d001be9ad3da4724c61f Author: Mike FABIAN Date: Tue Nov 17 07:04:59 2015 +0100 Fix hotkey matching Resolves: Bug 1282683 - Some keyboard shortcuts in ibus-table do not work See: https://bugzilla.redhat.com/show_bug.cgi?id=1282683 Some hotkeys did not work because the matching on the key release event was done inconsistently. Bug was reported by river tree . commit 6e8335efc7b8c5e11327eded8b1b0eef6567897c Author: Mike FABIAN Date: Wed Oct 21 08:55:04 2015 +0200 Release 1.9.8 commit a52e9dc7c68426d8c6ddf24bf658ce8714b75e74 Author: Mike FABIAN Date: Wed Oct 21 08:52:45 2015 +0200 Fix a few pylint warnings commit 8515046c0d0b23823cf800ae13511ce907fd5324 Author: Mike FABIAN Date: Wed Oct 21 08:40:04 2015 +0200 Document “orientation” and “select_keys” options in template.txt commit de9ff578577672f1314b247a5c0812d82477dadf Author: Heiher Date: Wed Oct 21 13:17:33 2015 +0800 Get option 'lookuptableorientation' default value from database. commit 9193fce1921db961198a562be179354f932c2082 Author: Mike FABIAN Date: Wed Oct 14 16:43:02 2015 +0200 Release v1.9.7 commit 39ac7575759f2bfe5ff8d2f1a67750eb0518e822 Author: Mike FABIAN Date: Wed Oct 14 08:43:20 2015 +0200 Fix some pylint warnings commit 372dbc04791770f1ca7b0e5504b03ee4423b23d2 Author: Mike FABIAN Date: Wed Oct 14 08:31:44 2015 +0200 When matching hotkeys, ignore all modifiers not requested in the match Hotkeys didn’t work when capslock was on. Now we ignore not only NumLock/MOD2 but all modifiers which are not requested to match in _match_hotkey(). commit 22bbda0584bca5049657e5b66e0423f016ea22d1 Author: Mike FABIAN Date: Wed Oct 14 08:26:39 2015 +0200 Fix 覆 U+8986 in Unihan_variants.txt, it is both simplified *and* traditional Chinese Resolves: rhbz#1271036 See: https://bugzilla.redhat.com/show_bug.cgi?id=1271036#c3 commit 0d5cdac37d244a879c090e3586ff264ddd714f23 Author: Mike FABIAN Date: Wed Oct 14 07:58:18 2015 +0200 Update Unihan_Variants.txt from “2014-05-09 Unicode 7.0.0” to “2015-04-30 Unicode 8.0.0” And regenerate engine/chinese_variants.py. New lines in Unihan_Variants.txt which are relevant for simplified and traditional detection: > U+4CA4 kTraditionalVariant U+9FD0 U+4CA4 = 䲤 U+9FD0 = 鿐 > U+540C kSimplifiedVariant U+540C U+540C = 同 > U+93B6 kSimplifiedVariant U+9FD4 U+93B6 = 鎶 U+9FD4 = 鿔 > U+9FCF kTraditionalVariant U+4951 U+9FCF = 鿏 U+4951 = 䥑 > U+9FD0 kSimplifiedVariant U+4CA4 U+9FD0 = 鿐 U+4CA4 = 䲤 > U+9FD2 kSimplifiedVariant U+9FD3 > U+9FD3 kTraditionalVariant U+9FD2 U+9FD2 = 鿒 U+9FD3 鿓 > U+9FD4 kTraditionalVariant U+93B6 U+9FD4 = 鿔 U+93B6 = 鎶 commit bd8e1206afb60f74a7df4bcaf02dd2738cc2d20c Author: Mike FABIAN Date: Wed May 6 08:38:41 2015 +0200 Release v1.9.6 commit 877e6059ceeb667d0a754c7acbcf630c49bbe2e3 Author: Mike FABIAN Date: Wed May 6 08:26:20 2015 +0200 Use os.path.expanduser('~') instead of os.getenv('HOME') Resolves: rhbz#1218023 - [abrt] ibus-table: posixpath.py:83:join:TypeError: unsupported operand type(s) for +=: 'NoneType' and 'str' See: https://bugzilla.redhat.com/show_bug.cgi?id=1218023 The Python documentation says: os.path.expanduser(path) On Unix and Windows, return the argument with an initial component of ~ or ~user replaced by that user‘s home directory. On Unix, an initial ~ is replaced by the environment variable HOME if it is set; otherwise the current user’s home directory is looked up in the password directory through the built-in module pwd. An initial ~user is looked up directly in the password directory. This helps if HOME is not set. commit 90a2a74c4a61ba9f3a9e43c69c1c0b593a2f1b63 Author: Mike FABIAN Date: Mon Apr 13 12:34:19 2015 +0200 Release v1.9.5 commit 822ec75b57abd20cd7a004a10035e292882b36db Author: Mike FABIAN Date: Mon Apr 13 11:22:37 2015 +0200 Don’t strip space when parsing phrases from a source table In some cases, one might want to start a key with a space. As the columns in the table are separated by tab, there is no reason to strip a leading space from the first column. Suggestion by James Wood, needed for a table to write the Shwa script (http://shwa.org/). Resolves: rhbz#1211208 - ibus-table-createdb should allow table keys to start with spaces See: https://bugzilla.redhat.com/show_bug.cgi?id=1211208 commit 6f11a71399dc5ff227c8ff35091c10095a72519c Author: Mike FABIAN Date: Mon Apr 13 11:18:56 2015 +0200 Fix typo in regexp parsing table entries There was ([^t]) instead of ([^\t]) in the part of the regexp getting the frequency. As the frequency is an integer and should contain only digits, this did not cause problems. But it still is a typo. commit 64c831a643dc68ef1f523ae12deb9d7398b50773 Author: Mike FABIAN Date: Sat Mar 7 19:15:51 2015 +0100 Release 1.9.4 commit 65aff02f6c099b07931e83da7701fbcac9e8dabf Author: Mike FABIAN Date: Sat Mar 7 19:13:19 2015 +0100 Check existence of old log files before trying to delete them Resolves: rhbz#1199673 - [abrt] ibus-table: factory.py:89:do_create_engine:Exception: Cannot create engine wubi-jidian86 See: https://bugzilla.redhat.com/show_bug.cgi?id=1199673 commit d858a60a7651505f2d4443cdce1b352a2a209cd5 Author: Mike FABIAN Date: Mon Mar 2 06:46:52 2015 +0100 Release v1.9.3 commit 4793b610944261c3484d624564cfd3790b3440e0 Author: Mike FABIAN Date: Fri Feb 27 22:17:58 2015 +0100 Try to get the English name of the table if run in locale C/POSIX Resolves: rhbz#1197001 - [abrt] ibus-table: main.py:222:main:AttributeError: 'NoneType' object has no attribute 'lower' See: https://bugzilla.redhat.com/show_bug.cgi?id=1197001 commit cfd698f14c2cfccc88dd34abb303bdf2c1a9eb22 Author: Mike FABIAN Date: Fri Jan 9 11:23:50 2015 +0100 Release v1.9.2 commit 0370cb105b79adfab6e6f295c9a824ffc6f71055 Author: Mike FABIAN Date: Fri Jan 9 12:05:55 2015 +0100 add “compile” to .gitignore commit a69f91fefe5de2959b14aa597b432e916d6eebd2 Author: Mike FABIAN Date: Fri Jan 9 08:17:00 2015 +0100 Use directories according to theXDG Base Directory Specification See: http://standards.freedesktop.org/basedir-spec/latest/index.html Resolves: rhbz#1172524 - ibus-table log could use xdg See: https://bugzilla.redhat.com/show_bug.cgi?id=1172524 commit 75b956b3e060e03b93f270898a6e596a2c1bdfe6 Author: Mike FABIAN Date: Wed Oct 1 10:16:00 2014 +0200 When a leading invalid character is passed through, it needs to be remembered in self._prev_char When a string is committed using commit_string(), commit_string() remembers its last characters in self._prev_char. But when a invalid leading character is passed through directly to the application by returning False in the key event processing, that character needs to be remembered as well in self._prev_char. For example, when halfwidth letter mode but fullwidth punctuation mode is used, _convert_to_full_width() does not convert a “.” to “。” if the previous character was a halfwidth digit. Probably the purpose of this hack is to make it easier to enter floating point number like “3.141”. A digit like “3” is an invalid input character for most Chinese tables and thus committed or passed through to the application immediately. If the next character typed is “.”, _convert_to_full_width() checks whether the previous character was a halfwidth digit and if yet prevents conversion of “.” to ”。” to avoid getting “3。141”. Therefore, no matter whether a character is committed or passed through, the last character inserted into the application needs to be remembered. commit 930b539bbfdac14dbc715e7898063ec940e9e41a Author: Mike FABIAN Date: Wed Oct 1 09:44:20 2014 +0200 Change class “KeyEvent” to store the keycode as well - add the keycode to the class “KeyEvent”: I may need to access the keycode in tabengine._process_key_event() to forward a key event to the application: void ibus_engine_forward_key_event (IBusEngine *engine, guint keyval, guint keycode, guint state); if the object of the class “KeyEvent” passed to tabengine._process_key_event(self, key) does not contain the keycode anymore, I cannot properly forward a key event. - Fix the confusing naming of the member variables in the class “KeyEvent”: it is easier to give the member variables names like the parameters of the IBus API (Why self.code = keval?) commit aa1f1ee6d5cb76d660f9074e2c623be44956f062 Author: Mike FABIAN Date: Tue Sep 30 17:32:28 2014 +0200 Remove useless “is_press” parameter in constructor of class KeyEvent Checking whether the IBus.ModifierType.RELEASE_MASK bit is set in “state” and if yes, set it again is completely redundant. commit 71cd8d3ae7d417ff5077205183c976763b69c2cc Author: Mike FABIAN Date: Tue Sep 30 14:15:10 2014 +0200 Release v1.9.1 commit 616c93016c916d05555ad029768addfc12dbf548 Author: Mike FABIAN Date: Tue Sep 30 12:38:18 2014 +0200 Use proper fallback when reading the localized table name Try language and region (“xx_YY”) first, then only language (“xx”). Without this patch, NAME.ru = устаревшая would be ignored, only NAME.ru_RU = устаревшая would be used. commit 79bccdc39c6e233ea5081d011ef102bf2d7ef9ce Author: Mike FABIAN Date: Wed Sep 17 10:21:39 2014 +0200 Show pinyin mode as well in the input mode indicator commit 16e700192695fd75b392939abb34faccf1322639 Author: Mike FABIAN Date: Tue Sep 16 09:57:26 2014 +0200 Release v1.9.0 commit cf541b98b8a2fdb829efcbcd99701fa2e3130c16 Author: Mike FABIAN Date: Tue Sep 9 09:24:31 2014 +0200 Add a Japanese translation file I did not translate many messages, I mostly want that file because I run my desktop in Japanese and want to see whether the translation system is working correctly or not. commit 406685f717f76683dac68c54d7277a5dadd5558c Author: Mike FABIAN Date: Tue Sep 16 08:26:18 2014 +0200 Update Chinese .po files commit 741ab21b5a677604d4e47b3d03cd6345a2f78795 Author: Mike FABIAN Date: Tue Sep 16 08:23:51 2014 +0200 Update German translations commit 461ed20a4fec27b3603cc29323c2be36ce7fdf7d Author: Mike FABIAN Date: Mon Sep 8 14:14:58 2014 +0200 Redesign the property menus, use sub-menus instead of toggles The toogles are very confusing, one cannot easily see to which mode one will switch when a toggle is clicked. When the floating panel is shown, tooltips explain to which mode will switch. But the floating panel is never shown in Gnome3, so this does not help for Gnome3. User feedback also shows that many users are confused whether the currently visible menu entry in case of a toggles shows the state which is currently used or the state one will switch to when that toggle is clicked. For toggles which have more than 2 values, for example the Chinese mode: 0 means to show simplified Chinese only 1 means to show traditional Chinese only 2 means to show all characters but show simplified Chinese first 3 means to show all characters but show traditional Chinese first 4 means to show all characters it is tedious to change from mode 0 to mode 4 for example: Open the menu, click on the toggle, menu closes and one has changed to mode 1. Repeat 3 more times to get to mode 4. The new system to use sub-menus instead of toogles also agrees better with: https://wiki.gnome.org/AllanDay/IMEGuidelines > Avoid mutable menu items (menu items whose label changes after it has > been selected). Instead, consider providing two adjacent menu items > for the commands. Then make the items sensitive or insensitive as the > situation demands. > > Do not use mutable menu items to toggle a two-state setting (for > example, Show and Hide). Use a check box or radio buttons instead. Also included in this commit: - reset() not needed when switching Chinese mode commit 55b7b3b0c490397cd74610052345963f4f9ae982 Author: Mike FABIAN Date: Sun Sep 14 13:32:16 2014 +0200 Release v1.8.11 commit 6bfad0054a7d8fea292557984a985d57f68bc74f Author: Mike FABIAN Date: Tue Sep 9 20:34:21 2014 +0200 Fix typo in variable name self_onechar -> self._onechar This typo caused a Python backtrace when the dconf key /desktop/ibus/engine/table/wubi-jidian86/onechar was not set. commit 5bc44b0b45dfdfa5b0653625f37cd75e2533d927 Author: Mike FABIAN Date: Tue Sep 9 08:47:06 2014 +0200 Fix typo in e-mail address commit 2a0b323d0c052794964f8473c23a399a6743bfc4 Author: Mike FABIAN Date: Thu Sep 4 16:07:38 2014 +0200 Release v1.8.10 commit 2e30813032fe46c6df690a2ba68b38bf1dd3e68c Author: Mike FABIAN Date: Tue Sep 2 10:38:07 2014 +0200 Disable “onechar” (Phrase mode/Single char mode) option for non-CJK databases This option is only useful for Chinese. Some Chinese tables, for example wubi-jidian86 contain not only single Chinese characters but also longer phrases. When one wants to input a certain single character, longer phrases showing up as matches as well may make it more difficult to find the desired single character in the candidate list. I.e. to input single characters it may be sometimes useful to switch to single character mode. For non-Chinese tables, such a single character mode is useless. commit d489802af96db1d5c46cb2295728d475b4a3797f Author: Mike FABIAN Date: Mon Sep 1 16:50:28 2014 +0200 Disable hotkey to switch Chinese mode if database is not Chinese commit bbf7d0f3fcb73cb5ec777cb9fee30991fe3fcd53 Author: Mike FABIAN Date: Mon Sep 1 16:29:41 2014 +0200 Disable auto_commit option for tables which do not have RULES Resolves: rhbz#1135759 - The rusle is broken with "Normal commit mode" See: https://bugzilla.redhat.com/show_bug.cgi?id=1135759 If a table does not have USER_CAN_DEFINE_PHRASE=TRUE and a non-empty RULES, it makes no sense to use “commit to preedit” for that table. Therefore, for such tables, auto_commit should always be True (= “Direct commit mode”) and never False (= “Normal commit mode”). These tables have AUTO_COMMIT = TRUE in their source and this should never be changed by the user. “Normal commit mode”, i.e. committing to preedit makes sense only for tables like wubi-jidian86, wubi-haifeng86, and erbi-qs because only these 3 tables currently have RULES and USER_CAN_DEFINE_PHRASE=TRUE. For such tables, committing to preedit is used to define new user shortcuts semi-automatically. commit 3663711986a93b112a2f537b0c485620fc756106 Author: Mike FABIAN Date: Tue Aug 26 13:39:23 2014 +0200 Release v1.8.9 commit e43591313e619990c87dbfed91de25f1d34ab659 Author: Mike FABIAN Date: Sat Aug 23 14:18:43 2014 +0200 Pass IBus.KEY_KP_Enter to the application if the preedit is empty Resolves: rhbz#1133424 - With the new "rusle" table in ibus-table-cyrillic, Keypad Enter problem See: https://bugzilla.redhat.com/show_bug.cgi?id=1133424 If IBus.KEY_KP_Enter is typed: • if the preëdit is empty, we should always pass the key to the application. *Not* commit an empty string plus os.linesep because that behaves differently in some cases. For example when typing a message in Pidgin it would insert a linefeed into the message instead of sending the message. • if the preëdit is not empty: - when auto_select is true (typical for Russian input methods like “rusle” or “translit”), the pending preëdit should be committed and the IBus.KEY_KP_Enter key passed to the application. For example, when typing “C” with translit, the preëdit contains Ц because it is still possible that a “h” is typed next: C Ц 1000 Ch Ч 1000 CH Ч 1000 When IBus.KEY_KP_Enter is typed in this state, the Ц should be committed and the IBus.KEY_KP_Enter should be passed to the application. With the old code, typing “C” followed by IBus.KEY_KP_Enter inserted a Ц and a linefeed in Pidgin instead of sending the message ending with Ц. - when auto_select is false (typical for Chinese input methods), the typed tabkeys should be committed (not the Chinese characters in the preëdit) and IBus.KEY_KP_Enter should not be passed to the application. commit 48c2b7e9ac1a109b7b1cb77bc665f2a19b6fcbd4 Author: Mike FABIAN Date: Fri Aug 22 21:12:04 2014 +0200 Ignore Shift+Space hotkey to switch fullwidth/halfwidth if the database is not for CJK Resolves: rhbz#1133422 - With the new "rusle" table in ibus-table-cyrillic, Shift-Space does not work See: https://bugzilla.redhat.com/show_bug.cgi?id=1133422 commit 354acbd306780015d4e64219ca5fb6989f991016 Author: Mike FABIAN Date: Tue Aug 26 13:53:35 2014 +0200 Update Chinese .po files commit eb64958cbd55f6ce8288987900ccfd9dfd8c3bea Author: Mike FABIAN Date: Tue Aug 26 13:53:11 2014 +0200 Update German translations commit b9824969683c77278edbc45c9472092b96bf4b58 Author: Mike FABIAN Date: Sat Aug 9 17:47:36 2014 +0200 Move some options into a new tab “Details” commit c4842088ddf21aee02cef5808f3086a854c3ac39 Author: Mike FABIAN Date: Thu Aug 14 15:25:23 2014 +0200 Release v1.8.8 commit 72b75c5d32a9491b06f68d21ed08468d27416717 Author: Mike FABIAN Date: Thu Aug 14 14:37:59 2014 +0200 Disable properties related to fullwidth/halfwidth for non-CJK tables Resolves: rhbz#1128912 - With the new "rusle" table in ibus-table-cyrillic, typing space works strangely See: https://bugzilla.redhat.com/show_bug.cgi?id=1128912 commit 1fb4bffb7cb02962cc2453337a50445e06a236a5 Author: Mike FABIAN Date: Wed Aug 13 20:51:09 2014 +0200 If the database is not CJK, set sensitivity to comboboxes useful only for CJK to OFF commit 074a43e79475135e10ef0096498e48af512b339e Author: Mike FABIAN Date: Wed Aug 13 15:07:23 2014 +0200 Remove “Hide Candidates/Display Candidates” from the properties menu This is almost never changed while using ibus-table, either one keeps it always on or always off. It is changeable in the setup tool, that should be enough. Stuff which is used so rarely unnecessarily clutters the properties menu. commit c9895416e0ecef53c42f4af30c3b2a38eaa1b889 Author: Mike FABIAN Date: Tue Aug 12 19:55:24 2014 +0200 Show keyboard shortcuts also in the property menu entries To make them easier to discover. They are shown in the tooltips of the floating panel already, but Gnome3 does not have the floating panel. Therefore the keyboard shortcuts are not easy to discover when using Gnome3. See also https://bugzilla.redhat.com/show_bug.cgi?id=1128912 commit b8b0d2bcb9b21fc2a92a97758054aca7da16313c Author: Mike FABIAN Date: Mon Aug 11 19:00:23 2014 +0200 Release v1.8.7 commit 67faf246f7137cd901a042cf47f7a016ebf63f98 Author: Mike FABIAN Date: Mon Aug 11 18:40:33 2014 +0200 Use the “notify::text” signal instead of “activate” on GtkEntry widget To make it possible that any change of text in the GtkEntry widgets is applied immediately. The “activate” signal is only emitted when Enter/Return is typed, the “notify::text” signal is emitted on any sort of change in the text. commit e7a014318ba45239dc8f4b9409594d6e39c0c0bd Author: Mike FABIAN Date: Mon Aug 4 10:06:04 2014 +0200 Update Chinese .po files commit 7ded13e317f22cf0c97a2ee48819769c0d9024e9 Author: Mike FABIAN Date: Mon Aug 4 10:04:50 2014 +0200 Update German translation commit 64984f048d2dd578318769ee543265ee74b82947 Author: Mike FABIAN Date: Fri Aug 1 09:41:24 2014 +0200 Move the “Restore all defaults” button into the GtkButtonBox at bottom - Makes the dialog a little bit less tall (helps for small screens) - I want to add another tab for detailed settings, the “Restore all defaults” button restores the defaults for all options in all tabs, therefore it should not be part of a tab. commit 7a2d96a990f812cd62df2cd80abc29a1d78d9cf1 Author: Mike FABIAN Date: Fri Aug 1 09:11:40 2014 +0200 Fix typo in comment commit 85c59eb98465295dba2323aaec131bc5db3f9220 Author: Mike FABIAN Date: Wed Jul 30 09:44:01 2014 +0200 Apply fix for 同 again to Unihan_Variants.txt, it is both simplified *and* traditional Chinese This fix is not yet included in Unicode 7.0.0. It will be included in a future version though. commit edfa725889c6d68dce4eb41408976b83eed21430 Author: Mike FABIAN Date: Wed Jul 30 09:39:55 2014 +0200 Update Unihan_Variants.txt from “2013-02-25 Unicode 6.3.0” to “2014-05-09 Unicode 7.0.0” And regenerate engine/chinese_variants.py. New lines in Unihan_Variants.txt which are relevant for simplified and traditional detection: > U+9FC1 kSimplifiedVariant U+4724 > U+4724 kTraditionalVariant U+9FC1 U+4724 = 䜤 U+9FC1 = 鿁 commit 558aa047be78df18e85e2b58409a9a8f97d46d4f Author: Mike FABIAN Date: Mon Jul 28 21:08:40 2014 +0200 Release v1.8.6 commit 275d514e388afedce1a6c74525f671e6f287b3aa Author: Mike FABIAN Date: Mon Jul 28 21:04:21 2014 +0200 Escape % and _ if they are not intended as wildcards Resolves: rhbz#1123981 - With the new "rusle" table in ibus-table-cyrillic, typing '%' shows ':' in preëdit instead of committing it directly See: https://bugzilla.redhat.com/show_bug.cgi?id=1123981 commit fb4969c2f4ec9e5413322415ebe4b8c109dfe9c4 Author: Mike FABIAN Date: Tue Jul 22 16:41:16 2014 +0200 Require Python >= 3.3 When porting to Python3, I originally kept it working with Python2 as well. But I didn’t test with Python2 for a while and the current code would not work anymore with Python2. It doesn’t seem to make sense to invest effort to keep Python2 compatibility. Better require Python >= 3.3. commit fe79787880f451815efc86b7b9f7c35d6da27782 Author: Mike FABIAN Date: Mon Jul 21 15:38:17 2014 +0200 Release v1.8.5 commit 5a50f3e0e34ae61108cbf886bea2b7bbadc593fb Author: Mike FABIAN Date: Mon Jul 21 15:23:44 2014 +0200 Always write xml output in UTF-8 encoding, not in the encoding of the current locale Resolves: rhbz#1120919 - abrt] ibus-table: main.py:268:main:UnicodeEncodeError: 'ascii' codec can't encode characters in position 1150-1152: ordinal not in range(128) See: https://bugzilla.redhat.com/show_bug.cgi?id=1120919 commit 076063a362953a9fa75d72c97191c6651c0afabd Author: Caius "kaio" Chance Date: Mon Jul 7 16:37:19 2014 +1000 - Release v1.8.4 commit a87efc9f072114c47d9260cd779f923e5fca3c38 Merge: cd83314 e21444f Author: Caius 'kaio' Chance Date: Mon Jul 7 16:36:07 2014 +1000 Merge pull request #43 from mike-fabian/tweak-defaults-for-chinese-mode-taken-from-locale Tweak defaults for Chinese mode taken from the locale commit e21444f8ea90661f387ce2e9fb15d1d799162b06 Author: Mike FABIAN Date: Sun Jul 6 07:32:52 2014 +0200 For cangjie* and quick* tables: Use big5 order if the freq from the table is the same In the cangjie5.txt table, all the frequency weights are 1000, for example: su 己 1000 su 已 1000 su  1000 su 㔾 1000 Currently, the Unicode code point is used as a last ditch fallback if all the other sort keys are the same (sort keys are: exact match, user frequency, Chinese variant, system frequency, length of input sequence, input sequence alphabetical, Unicode code point). In case of the above characters matching “su”, the Unicode code points and Big5 code points: 㔾 U+353E Big5 - Big5HKSCS 8BC8 己 U+5DF1 Big5 A476 Big5HKSCS A476 已 U+5DF2 Big5 A477 Big5HKSCS A477  U+E81D Big5 - Big5HKSCS - Sorting via the Unicode code points gives: 尸山 (1/9) 1. 㔾 2. 己 3. 已 4.  ... And sorting first via the Big5 code points and then via the Unicode code points for characters which do not have a Big5 code point gives: 尸山 (1/9) 1. 己 2. 已 3. 㔾 4.  ... This order seems to make more sense for Cangjie because: • https://en.wikipedia.org/wiki/Big5: “The original Big5 character set is sorted first by usage frequency, second by stroke count, lastly by Kangxi radical.” • some other popular operating system also uses Big5 order for Cangjie Therefore, for the cangjie* and quick* tables, this commit introduces another sort key sorting according to the Big5 code point just before sorting the final sort key using the Unicode code point. As the frequency data in the tables (which is currently always 1000 for cangjie5.txt, cangjie3.txt, and cangjie-big.txt) has higher priority, one could still tweak the frequency data in the table if the order is still not perfect for some characters. But it looks like Big5 order is quite reasonable. commit db062f794099e2c57d977c212418ef5506f78e24 Author: Mike FABIAN Date: Fri Jul 4 15:15:26 2014 +0200 Make it possible to use select keys like F1, F2, F3 ... Select keys like F1, F2, F3, ... are necessary for the ipa-x-sampa table which has: VALID_INPUT_CHARS == +!\%&'-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~" Therefore, using 1, 2, 3, ... as the select keys for ipa-x-sampa is bad because it makes it impossible to input the following entries of the ipa-x-sampa table: 1 ɨ 0 ### U+0268 LATIN SMALL LETTER I WITH STROKE 2 ø 0 ### U+00F8 LATIN SMALL LETTER O WITH STROKE 3 ɜ 0 ### U+025C LATIN SMALL LETTER REVERSED OPEN E 3\ ɞ 0 ### U+025E LATIN SMALL LETTER CLOSED REVERSED OPEN E 4 ɾ 0 ### U+027E LATIN SMALL LETTER R WITH FISHHOOK 5 ɫ 0 ### U+026B LATIN SMALL LETTER L WITH MIDDLE TILDE 6 ɐ 0 ### U+0250 LATIN SMALL LETTER TURNED A 7 ɤ 0 ### U+0264 LATIN SMALL LETTER RAMS HORN 8 ɵ 0 ### U+0275 LATIN SMALL LETTER BARRED O 9 œ 0 ### U+0153 LATIN SMALL LIGATURE OE _0 ̥ 0 ### U+0325 COMBINING RING BELOW _1 ₁ 0 ### U+2081 SUBSCRIPT ONE _2 ₂ 0 ### U+2082 SUBSCRIPT TWO _3 ₃ 0 ### U+2083 SUBSCRIPT THREE _4 ₄ 0 ### U+2084 SUBSCRIPT FOUR _5 ₅ 0 ### U+2085 SUBSCRIPT FIVE _6 ₆ 0 ### U+2086 SUBSCRIPT SIX Also, use the key codes of the select keys instead of the names of the select keys in the key even processing. One could of course keep using the names and still make using select keys like F1, F2, F3, ... possible. But other similar key lists like self._commit_keys, self._page_up_keys, and self._page_down_keys use key codes, it seems nicer make all these similar key lists use the same data types. commit 04accb2a5f7cf688d8455cadc18f28a8c4d0a2e6 Author: Mike FABIAN Date: Thu Jul 3 11:57:08 2014 +0200 Update NEWS file for ibus-table 1.8.x commit adb107ef2273acc2257226ac0c87ba8d915de421 Author: Mike FABIAN Date: Wed Jul 2 17:26:52 2014 +0200 Fix prompts for array30 table and don’t use prompts in pinyin mode The array 30 table has prompts which are longer than one character. Like this: BEGIN_CHAR_PROMPTS_DEFINITION q 1^ w 2^ e 3^ ... m 7v , 8v . 9v / 0v END_CHAR_PROMPTS_DEFINITION This did not work with my old code. Also, do not use the prompts in pinyin mode. This commit commit c9f6a2bfe833da6f6a3d67546a89e0cefd886d83 Author: Mike FABIAN Date: Wed Jun 4 12:45:19 2014 +0200 Don’t show the prompt characters defined in the table in pinyin mode in the auxiliary text already avoided using the prompts in pinyin mode in the auxiliary text. But prompt characters may also appear in the candidate list to show which characters are needed to complete a candidate (“remaining_tabkeys”) and also in the preëdit when no candidate can be found for the typed characters. Fix this for pinyin mode for these cases as well. commit 4adcd6fe8be21892b856f20948314e9c5ea08cb5 Author: Mike FABIAN Date: Tue Jul 1 18:28:44 2014 +0200 Tweak defaults for Chinese mode taken from the locale - detect also the locale zh_SG as simplified Chinese - if the Chinese variant is detected from the locale, set the Chinese mode to a mode which prefers a variant instead of showing that variant only. I.e., if zh_CN or zh_SG is in the locale, set the Chinese mode to 2 (“Show simplified Chinese first”) instead of 0 (“Show *only* simplified Chinese”). If one wants to show only one variant, one can easily change that later, but as a default it is better not to hide one variant, this seems to confuse some users who have not yet discovered that these options exist (see for example: https://code.google.com/p/ibus/issues/detail?id=1492 and https://code.google.com/p/ibus/issues/detail?id=1670 ) - if no Chinese locale is set (and the Chinese mode is neither set in the table nor in the user settings either), use mode 4 (“Show all Chinese characters”) by default. In this case we don’t really know whether the table is intended for simplified or for traditional Chinese, it makes no sense to just guess simplified Chinese then. commit cd83314cecc5d78fa5545611a8f5a313dc8d044f Merge: b570739 cb4233c Author: Caius 'kaio' Chance Date: Fri Jun 27 14:46:43 2014 +1000 Merge pull request #42 from mike-fabian/do-not-add-wildcards-to-string-of-valid-input-chars Don’t add self._single_wildcard_char and self._multi_wildcard_char to se... commit cb4233ca63b4838580ce744cbe4048c9b095cf62 Author: Mike FABIAN Date: Thu Jun 26 15:37:22 2014 +0200 Don’t add self._single_wildcard_char and self._multi_wildcard_char to self._valid_input_chars and self._pinyin_valid_input_chars This is because the wildcard characters can be changed with the setup tool at runtime. If they are added to the string of valid input characters, the old wildcards would need to be removed from that string if the wildcards are changed. But the wildcard character may have been in that list already before it was added as a wildcard character. In that case, only one instance of the old wildcard character should be removed from the string of valid input characters if the wildcard character is changed. Replacing the wildcard characters in the string of valid input characters when they change seems more confusing that not adding them to that string in the first place. Therefore, I do not add the wildcard characters to the string of valid input characters anymore, but that means that when checking whether a character is a valid input character if c in self._valid_input_chars: is not enough anymore, now one needs if c in self._valid_input_chars + self._single_wildcard_char + self._multi_wildcard_char: That seems less confusing than adding the wildcard characters to self._valid_input_chars and replacing them there when they change. commit b570739aec426bebd166fb494d41d5f04cccb1aa Author: Caius "kaio" Chance Date: Wed Jun 25 22:46:53 2014 +1000 Release v1.8.3. commit 9dd5bd9c2f08c39143e3eea0ded8d34ce979bbcb Merge: 7cb2765 80c97fa Author: Caius 'kaio' Chance Date: Wed Jun 25 22:23:22 2014 +1000 Merge pull request #41 from mike-fabian/improve-wildcard-support Improve wildcard support commit 80c97fad74ae8be835576be15c5913efed081190 Author: Mike FABIAN Date: Wed Jun 25 11:03:15 2014 +0200 Update Chinese .po files (Only to get the changed strings from the source synced with the .po files, I did neither change nor add any translations). commit 1816bb90295ff0bb44f11f3b85deb3ca5d4484a7 Author: Mike FABIAN Date: Wed Jun 25 11:02:25 2014 +0200 Update German translations commit 95851e5dc6e3491813ac6ea8e3927d608d375a04 Author: Mike FABIAN Date: Mon Jun 23 18:26:32 2014 +0200 Make wildchard characters configurable The options AUTO_WILDCARD, SINGLE_WILDCARD_CHAR, and MULTI_WILDCARD_CHAR are now not only configurable in the table sources but also in the setup tool and via dconf. The default for AUTO_WILDCARD if neither specified in the table source nor in the setup tool nor in dconf is TRUE, this is best for most tables. The defaults for SINGLE_WILDCARD_CHAR and MULTI_WILDCARD_CHAR are the empty strings, this means no wildcards are used. In some table sources default values for SINGLE_WILDCARD_CHAR and MULTI_WILDCARD_CHAR are defined, in most cases these are SINGLE_WILDCARD_CHAR = ? MULTI_WILDCARD_CHAR = * commit 77a1a5a7a683e463538387684dcc37268aab37e5 Author: Mike FABIAN Date: Mon Jun 23 15:24:47 2014 +0200 Insert a special candidate for the wildcard character itself if only a wildcard character has been typed Resolves: rhbz#1110325 - Unable to input question marks in Wubi-jidian See: https://bugzilla.redhat.com/show_bug.cgi?id=1110325 The same problem has been also reported here: https://code.google.com/p/ibus/issues/detail?id=1720 If only a wildcard character has been typed, insert a special candidate at the first position for the wildcard character itself. For example, if “?” is used as a wildcard character and this is the only character typed, add a candidate ('?', '?', 0, 1000000000) in halfwidth mode or a candidate ('?', '?', 0, 1000000000) in fullwidth mode. This is needed to make it possible to input the wildcard characters themselves, if “?” acted only as a wildcard it would be impossible to input a fullwidth question mark. commit 7cb27653cbabc05d393903c6721e0b1fecd7f19c Author: Caius "kaio" Chance Date: Mon Jun 9 13:12:00 2014 +1000 Release v1.8.2. commit a6f9c22dead6992d15b15cd356d86fbfd14ac629 Merge: b07c6ea e18f708 Author: Caius 'kaio' Chance Date: Sat Jun 7 23:41:12 2014 +1000 Merge pull request #40 from mike-fabian/better-sorting-in-the-mixed-chinese-modes Better sorting in the mixed chinese modes commit e18f708fd9439e51ee115b578931f624852b53af Author: Mike FABIAN Date: Fri Jun 6 20:43:22 2014 +0200 Better sorting of the lookup table in the mixed Chinese modes In the mixed Chinese modes 2 and 3 (simplified Chinese first and traditional Chinese first), the filtering for simplified and traditional was done as a last step filtering the candidate list already sorted using the sort keys: - exact match? - user frequency - system frequency - length of input sequence - alphabetical order of input sequence - Unicode code point of first character of matched phrase But this simplified and traditional filtering is basically just another sort key. Doing this after the main sorting of the candidate list is inefficient and does not give nice results either. It is better to do all of the sorting in one place. The sort key for the desired Chinese variant (traditional or simplified) should have higher priority than the system frequency but lower priority than the user frequency. If the user selects a certain variant often, it should be preferred in future. An example for the behaviour after this commit is applied: wubi-jidian86.txt contains the following matches for 語 (as a single character): ygkg 語 204000000 It contains the following matches for 语 (as a single character): ygk 语 234000000 ygkg 语 234000000 And the following matches for the input sequence “ygkg”: ygkg 語 204000000 ygkg 语 234000000 ygkg 𢌐 0 ygkg 𣄟 0 ygkg 𩐕 0 After this commit, typing “ygkg” gives the following results in the lookup table (when all user frequencies are 0. For testing this can be achieved by removing the user database): Chinese mode 0, “simplified Chinese only”: ========================================== ygkg (1/4) 1. 语 234000000 0 2. 𢌐 0 0 3. 𣄟 0 0 4. 𩐕 0 0 Chinese mode 1, “traditional Chinese only”: =========================================== ygkg (1/4) 1. 語 204000000 0 2. 𢌐 0 0 3. 𣄟 0 0 4. 𩐕 0 0 Chinese mode 2, “simplified Chinese before traditional”: ======================================================== ygkg (1/5) 1. 语 234000000 0 2. 𢌐 0 0 3. 𣄟 0 0 4. 𩐕 0 0 5. 語 204000000 0 Chinese mode 3, “traditional Chinese before simplified”: ======================================================== ygkg (1/5) 1. 語 204000000 0 2. 𢌐 0 0 3. 𣄟 0 0 4. 𩐕 0 0 5. 语 234000000 0 Chinese mode 4, “All Chinese characters”: ========================================= ygkg (1/5) 1. 语 234000000 0 2. 語 204000000 0 3. 𢌐 0 0 4. 𣄟 0 0 5. 𩐕 0 0 commit b07c6ea38c6e60d82ffb96c0fd9c52103ab5b51b Merge: 9d94221 9c6840b Author: Caius 'kaio' Chance Date: Sat Jun 7 01:48:08 2014 +1000 Merge pull request #39 from mike-fabian/do-not-create-useless-indexes Do not create useless indexes commit 9c6840ba52cd2320f4ceb03f7be99b9ae705b9fe Author: Mike FABIAN Date: Fri Jun 6 10:44:30 2014 +0200 Do not create useless indexes Resolves: rhbz#1105465 - Please avoid to create sqlite table index in ibus-table See: https://bugzilla.redhat.com/show_bug.cgi?id=1105465 Most of indexes which were created were not helpful at all because most queries are done using the SQL “LIKE” operator which does not benefit from indexes. And the SELECT statements which do not use “LIKE” are not doing anything where speed is critical. So we could not find a benefit in any of the existing indexes. Benchmarking showed no significant difference between having the indexes or not having them. I changed the functions create_indexes() and drop_indexes() to do nothing, if we ever find that some index is really useful, we can easily add it again. Not creating the indexes saves a lot of space: Sizes with indexes: $ du -h -c /usr/share/ibus-table/tables/*.db 8.6M /usr/share/ibus-table/tables/array30-big.db 3.7M /usr/share/ibus-table/tables/array30.db 3.7M /usr/share/ibus-table/tables/cangjie-big.db 2.1M /usr/share/ibus-table/tables/cangjie3.db 4.7M /usr/share/ibus-table/tables/cangjie5.db 572K /usr/share/ibus-table/tables/cantonese.db 700K /usr/share/ibus-table/tables/cantonhk.db 5.0M /usr/share/ibus-table/tables/cns11643.db 64K /usr/share/ibus-table/tables/compose.db 7.7M /usr/share/ibus-table/tables/easy-big.db 96K /usr/share/ibus-table/tables/emoji-table.db 6.6M /usr/share/ibus-table/tables/erbi-qs.db 3.0M /usr/share/ibus-table/tables/erbi.db 40K /usr/share/ibus-table/tables/ipa-x-sampa.db 640K /usr/share/ibus-table/tables/jyutping.db 60K /usr/share/ibus-table/tables/latex.db 312K /usr/share/ibus-table/tables/mathwriter-ibus.db 812K /usr/share/ibus-table/tables/quick-classic.db 2.0M /usr/share/ibus-table/tables/quick3.db 4.4M /usr/share/ibus-table/tables/quick5.db 40K /usr/share/ibus-table/tables/rustrad.db 5.0M /usr/share/ibus-table/tables/scj6.db 364K /usr/share/ibus-table/tables/stroke5.db 40K /usr/share/ibus-table/tables/thai.db 40K /usr/share/ibus-table/tables/translit-ua.db 40K /usr/share/ibus-table/tables/translit.db 40K /usr/share/ibus-table/tables/viqr.db 1000K /usr/share/ibus-table/tables/wu.db 11M /usr/share/ibus-table/tables/wubi-haifeng86.db 12M /usr/share/ibus-table/tables/wubi-jidian86.db 40K /usr/share/ibus-table/tables/yawerty.db 4.2M /usr/share/ibus-table/tables/yong.db 87M 合計 Sizes without indexes: $ du -h -c /usr/share/ibus-table/tables/*.db 4.6M /usr/share/ibus-table/tables/array30-big.db 2.0M /usr/share/ibus-table/tables/array30.db 1.5M /usr/share/ibus-table/tables/cangjie-big.db 1020K /usr/share/ibus-table/tables/cangjie3.db 2.1M /usr/share/ibus-table/tables/cangjie5.db 236K /usr/share/ibus-table/tables/cantonese.db 292K /usr/share/ibus-table/tables/cantonhk.db 2.1M /usr/share/ibus-table/tables/cns11643.db 32K /usr/share/ibus-table/tables/compose.db 3.2M /usr/share/ibus-table/tables/easy-big.db 48K /usr/share/ibus-table/tables/emoji-table.db 3.2M /usr/share/ibus-table/tables/erbi-qs.db 1.3M /usr/share/ibus-table/tables/erbi.db 24K /usr/share/ibus-table/tables/ipa-x-sampa.db 268K /usr/share/ibus-table/tables/jyutping.db 36K /usr/share/ibus-table/tables/latex.db 152K /usr/share/ibus-table/tables/mathwriter-ibus.db 332K /usr/share/ibus-table/tables/quick-classic.db 980K /usr/share/ibus-table/tables/quick3.db 2.0M /usr/share/ibus-table/tables/quick5.db 24K /usr/share/ibus-table/tables/rustrad.db 2.2M /usr/share/ibus-table/tables/scj6.db 156K /usr/share/ibus-table/tables/stroke5.db 24K /usr/share/ibus-table/tables/thai.db 24K /usr/share/ibus-table/tables/translit-ua.db 24K /usr/share/ibus-table/tables/translit.db 24K /usr/share/ibus-table/tables/viqr.db 424K /usr/share/ibus-table/tables/wu.db 4.8M /usr/share/ibus-table/tables/wubi-haifeng86.db 5.7M /usr/share/ibus-table/tables/wubi-jidian86.db 24K /usr/share/ibus-table/tables/yawerty.db 1.8M /usr/share/ibus-table/tables/yong.db 40M 合計 commit 9d942218061379a17972eaf18987e886ba23291b Author: Caius "kaio" Chance Date: Wed Jun 4 22:28:24 2014 +1000 Release 1.8.1 commit 21448804bd27a77e9385406b2064d762311624a1 Merge: 8ded23b c9f6a2b Author: Caius 'kaio' Chance Date: Wed Jun 4 22:19:34 2014 +1000 Merge pull request #38 from mike-fabian/add-support-for-wildcards Add support for wildcards commit c9f6a2bfe833da6f6a3d67546a89e0cefd886d83 Author: Mike FABIAN Date: Wed Jun 4 12:45:19 2014 +0200 Don’t show the prompt characters defined in the table in pinyin mode in the auxiliary text commit 407d96f5e776f3543590fb2b459410892d64611b Author: Mike FABIAN Date: Wed Jun 4 12:29:55 2014 +0200 Add wildcard support also to pinyin mode The wildcards used are the same as for table mode. I.e. if the table defines: MULTI_WILDCARD_CHAR = * SINGLE_WILDCARD_CHAR = ? the same wildcards are used for pinyin as well. The AUTO_WILDCARD in the table is ignored for pinyin mode though, it is always treated as AUTO_WILDCARD = TRUE for pinyin mode, FALSE does not make any sense for pinyin mode. commit 42b68588fbf8a94892f4767f5a0180d987243d31 Author: Mike FABIAN Date: Tue Jun 3 16:43:04 2014 +0200 Add support for wildcards The options AUTO_WILDCARD, MULTI_WILDCARD_CHAR, and SINGLE_WILDCARD_CHAR are now read from the table and used. The defaults are: AUTO_WILDCARD = TRUE MULTI_WILDCARD_CHAR = * SINGLE_WILDCARD_CHAR = ? Now one can use wildcards as in the following example for cangjie5: “cangjie5.txt” contains: sqsf 馬 1000 Now typing something like “s*f” or “s?sf” will match 馬. If AUTO_WILDCARD = TRUE, a multi wildcard character will always be appended to the user input, for example typing “s” will match like “s*”. Until now, ibus-table was always working like that. Now it is possible to set AUTO_WILDCARD = FALSE to avoid that automatic final wildcard and get only exact matches. This is very rarely useful though, take care with that option, in most cases this should be TRUE! commit 8ded23bf3744468f6bf2867912c350e042a2e6dc Merge: 834b1db 58ab974 Author: Caius 'kaio' Chance Date: Tue Jun 3 16:57:15 2014 +1000 Merge pull request #37 from mike-fabian/adapt-ibus-table-query-to-the-new-database-format Adapt ibus table query to the new database format commit 58ab974582df90cee45579cf3419034be07ccdb1 Author: Mike FABIAN Date: Mon Jun 2 22:29:02 2014 +0200 Adapt tools/ibus-table-query to work with the new database format commit 834b1db8b481cd82d647f00758c45f7bf95940fd Author: Caius "kaio" Chance Date: Mon Jun 2 22:34:24 2014 +1000 Update version number and authors contacts. commit 78564ac272fa3aca313d383a39073fcfa78375c7 Author: Caius "kaio" Chance Date: Mon Jun 2 22:19:05 2014 +1000 Revert "Merge branch 'master' into 1.7" This reverts commit 109872fdb45dc625906e0039efc0897dd9c64ca5, reversing changes made to 3d8ec4f62c77fd67882ea32075777b9d01c55864. commit 109872fdb45dc625906e0039efc0897dd9c64ca5 Merge: 3d8ec4f a414433 Author: Caius "kaio" Chance Date: Sun Jun 1 22:49:58 2014 +1000 Merge branch 'master' into 1.7 Conflicts: engine/main.py engine/tabsqlitedb.py commit 3d8ec4f62c77fd67882ea32075777b9d01c55864 Merge: 7600acb 063a61a Author: Caius 'kaio' Chance Date: Fri May 30 08:46:49 2014 +1000 Merge pull request #36 from mike-fabian/use-unicode-code-point-as-a-last-sort-key Use Unicode code point as a last sort key commit 7600acb8dd81dfe703f3637646e9ed2518dd33b2 Merge: 217b8c5 39e44a2 Author: Caius 'kaio' Chance Date: Fri May 30 08:46:09 2014 +1000 Merge pull request #35 from mike-fabian/exact-matches-at-the-top-and-support-prompts-for-cangjie Exact matches at the top and support prompts for cangjie commit 063a61ae9923de14ce880a1a444af81cff22e00e Author: Mike FABIAN Date: Wed May 28 18:38:31 2014 +0200 Add the Unicode code point of the first character of the phrase as a last ditch sort key for the candidates In some cases, where there are several matches for *exactly* the same input sequences *and* the system frequencies are also the same for example bmr 同 1000 bmr 𦚈 1000 in cangjie5.txt, instead of getting the order randomly, use the Unicode code point as a last ditch sort key. Some defined order is better than random. On top of that, this puts characters with code points above the BMP *after* characters with code points in the BMP. Usually this is the right thing to do because the characters from the BMP are usually more common. Should this not be the case and the character above the BMP really is the more common one, the system frequency should be added to reflect this. This does not always help: In cangjie5.txt there are also cases where *exactly* the same input sequences matches different characters which are all in the BMP, for example: bmso 豚 1000 bmso 冢 1000 bmso 䐁 1000 dhe 皮 1000 dhe 板 1000 But sorting the characters in the BMP to the top if all other sort keys are the same is better than nothing. commit 9598e12ef26407edad1241921eb7750b561d9d2e Author: Mike FABIAN Date: Wed May 28 18:18:58 2014 +0200 Fix bug in Unihan_Variants.txt, 同 is both simplified *and* traditional Chinese commit 0d929b3aaaa486383857fd3a1fb085c1b4bd6d67 Author: Mike FABIAN Date: Wed May 28 18:16:28 2014 +0200 Add a test case to make sure 同 is detected as both simplified *and* traditional Chinese commit 93e4781d91e94be3327bf2dae4be4b8859e41bff Author: Mike FABIAN Date: Wed May 28 18:01:29 2014 +0200 Update Unihan_Variants.txt from “2011-08-08 Unicode 6.1.0” to “2013-02-25 Unicode 6.3.0” And regenerate engine/chinese_variants.py. commit cce4212c91a69d76d4dc2af7f4b54e1134fe94c0 Author: Mike FABIAN Date: Wed May 28 17:52:55 2014 +0200 Add __pycache__/ to tools/.gitignore commit 39e44a2e2a98de1546f6ad30453f11ae6d7bcd63 Author: Mike FABIAN Date: Thu May 22 17:50:42 2014 +0200 Support prompt characters Some tables, e.g. cangjie5.txt contain prompt character definitions: BEGIN_CHAR_PROMPTS_DEFINITION a 日 b 月 c 金 ... Read these when creating a database and save it to the database. When typing, show these prompts instead of showing the typed Latin characters in the auxiliary text, the preëdit, or in the candidate list for the remaining keys to type to complete a match. commit 0351a5bb44ba9ab19425fdd783fda67c7d2bbc4e Author: Mike FABIAN Date: Fri May 23 17:13:46 2014 +0200 Don’t create an “ikeys” table The “ikeys” table created in tabsqlitedb.py is apparently never used anywhere. commit f795793bdaa28d06787c334b2acf7e9ad6223501 Author: Mike FABIAN Date: Fri May 23 00:35:28 2014 +0200 Put exact matches always at the top of the candidate list Change the filtering in Chinese mode 2 (All characters with simplified Chinese first) and Chinese mode 3 (All characters with traditional Chinese first) to keep that property of the candidate list. I.e. keep the exact matches on top and the completion matches below and do the Chinese filtering for mode 2 and 3 separately for the exact matches and the completion matches. Sees also https://bugzilla.redhat.com/show_bug.cgi?id=1050753#c2 Bo-Yin Yang> 1. Any character which has that precise key sequence as Bo-Yin Yang> the encoding must be listed ahead of any other Bo-Yin Yang> character. That is, if 同 and U+26688 are the two (and Bo-Yin Yang> the only two) Chinese characters whose encodings are Bo-Yin Yang> "bmr", then input of bmr must list 同 and U+26688 as the Bo-Yin Yang> first two characters in the preedit window for choice of Bo-Yin Yang> characters, no matter how unlikely to appear 同 and might Bo-Yin Yang> be deemed by the data table. That the encoding matches Bo-Yin Yang> the input sequence must outweigh any other factor in the Bo-Yin Yang> AI. commit 409a8d96c2d0a7ec0f902ae25e8c55d829387af8 Author: Mike FABIAN Date: Fri May 23 00:04:10 2014 +0200 Don’t try to call filter_candidates() if it is not necessary commit 60bc283ee7065542f0ac865dc9604d6bf1c4369e Author: Mike FABIAN Date: Fri May 23 00:02:17 2014 +0200 Fix typo in the filtering for chinese mode 3 (All characters with traditional Chinese first) commit 217b8c5055cd51deb4fb139d2e39239ae9be852f Merge: 081f61e 2392853 Author: Caius 'kaio' Chance Date: Thu May 22 17:50:24 2014 +1000 Merge pull request #34 from mike-fabian/remove-tabdict-and-other-improvements-and-bugfixes Remove tabdict and other improvements and bugfixes commit 23928535f74e5a5f22ec5d97cf887ff89ac6e53b Author: Mike FABIAN Date: Tue May 13 10:20:40 2014 +0200 Update Chinese .po files (Only to get the changed strings from the source synced with the .po files, I did neither change nor add any translations). commit 7d8c023d2ce029c381259b4ccff88dfdaf027161 Author: Mike FABIAN Date: Tue May 13 08:55:43 2014 +0200 Update German translation commit e55172224a6e44211c32db25e883f23ef9f067a5 Author: Mike FABIAN Date: Tue May 20 20:34:15 2014 +0200 Add a “setup” property Apparently that was planned already, there was a comment which said “Need implementation”. I also think it is a good idea, especially under Gnome3 the setup for the input methods is quite difficult to reach, one has to start the “gnome-control-centre” first, then go to the “region” part, then to the input method, then click on the cogwheel icon. That is quite inconvenient if the setup is used regularly. If one wanted to reduce the number of entries in the properties, I think it would be better to remove other properties which are probably not used all the time and are available in the setup anyway. I guess the properties “Phrase mode/Single character mode”, “Direct commit mode/Normal commit mode” and “Display candidates/Hide candidates” are probably very rarely used and it might be good enough if they are accessible only in the setup tool. commit cec4f3f5f75b1846349eb5a81b81560911a1a177 Author: Mike FABIAN Date: Tue May 20 10:33:17 2014 +0200 Do not check whether the name in “NAME = ...” is a valid gconf key It is not used as a gconf key anyway. We use the basename of the table file as the gconf key, i.e. for /usr/share/ibus-table/tables/wubi-jidian86.db the gconf key is “wubi-jidian86”. The gconf key should be more or less constant, it should not change often. If it changes during an update, the old user settings may be lost. NAME = in the table source is more suitable for display to the user, here one can write a nice, user readable string. In the lastest master of ibus-table-chinese, wubi-jidian86.txt contains: NAME = WuBi-Jidian (JiShuag) 86 NAME.zh_CN = 极点五笔(极爽字库)86 NAME.zh_TW = 極點五筆(極爽字庫)86 NAME.zh_HK = 極點五筆(極爽字庫)86 which made tabcreatedb.py fail because it checked whether NAME is a valid gconf key. But we do not need that check. commit c5ec35f96c176f99a3d54d1acaf72534993ce968 Author: Mike FABIAN Date: Tue May 20 06:35:22 2014 +0200 Remove unused variable commit 55ccd674daaffb2e394748fdea0aa6daad29f0b7 Author: Mike FABIAN Date: Mon May 19 20:59:59 2014 +0200 Add option to the setup tool to show or hide the candidate list Already exists as a property and as a setting in the databases, should be in the setup tool as well. commit 91b22f1238b91df253d48c99131726feaf9c6aa3 Author: Mike FABIAN Date: Mon May 19 17:38:52 2014 +0200 Add tooltips to the widgets in the setup tool commit 196bbba3777475a096e913552be87cd313aab6ca Author: Mike FABIAN Date: Mon May 19 16:42:01 2014 +0200 Don’t try to write attributes into the system database unless the system database is created If the system database already exists, the user usually does not have write permissions there, so do not try to write into the system database in that case. commit 354becc353c42a28612df03a520af4432eef65a2 Author: Mike FABIAN Date: Mon May 19 12:29:33 2014 +0200 If the dconf key “lookuptablepagesize” changes to an invalid value, reset it to a valid value If the user sets the dconf key “lookuptablepagesize” to a value < 1 or > len(self._editor._select_keys), set it to a valid value again in the callback handler for dconf key changes. After this change, if the user tries to move the slider for the lookup table page size in the setup tool to 10 for a table like “stroke5” which has only 9 select keys (SELECT_KEYS = 1,2,3,4,5,6,7,8,9), the dconf key is set to 9 again and the slider moves back to 9. commit 0e97323ea267e81b8139db4074db63f9373acbee Author: Mike FABIAN Date: Sun May 18 22:24:24 2014 +0200 Add an option to the setup tool to restore the defaults from the database Useful if one messes up the input method by choosing weird options and wants to return to sane defaults. commit d7308655d5d293f7bd760a1675ef430d3c1e2ac1 Author: Mike FABIAN Date: Mon May 19 08:26:22 2014 +0200 Add *~ to .gitignore commit e0860a2d8ae1134cfef9227a6ca3fa4ca64a8268 Author: Mike FABIAN Date: Sun May 18 20:15:12 2014 +0200 Make the option in the setup tool to use “space” as a commit or page down key work And some more improvements in the handling of commit and page up/down keys. In future we might want to introduce separate options for commit keys and page up/down keys in the setup tool instead of the option for the space key behaviour. But this commit makes the existing option work which is enough for the moment. commit 57c98a3349282189e8bb23330610e752cc854488 Author: Mike FABIAN Date: Sun May 18 20:13:08 2014 +0200 Remove useless comment commit cce4419f154e3117958da7f1e471c2a9d2314575 Author: Mike FABIAN Date: Sun May 18 07:15:03 2014 +0200 Make the ids of the labels and the comboboxes more consistent in the setup ui If a combobox has id="comboboxfoo", give the label for that combobox id="labelfoo" to make it easier to find which label is used for which combobox when editing the English texts of the labels. commit 3cf6393af76d4d634fc5a5ae4281a21d1123bcc1 Author: Mike FABIAN Date: Sun May 18 06:39:20 2014 +0200 Add “auto_select” option to setup tool This option has a very misleading name. It does not really automatically select anything. When set to “True” does the following things: 1) commit the matched phrase and a line feed instead of the tabkeys and no line feed when Return is typed (apparently Chinese input methods like Wubi want to insert the tabkeys instead of the phrase on Return, this is used as a quick way to insert one Latin word without having to switch to direct input mode or another input method. But for non-Chinese input methods like the Russian “translit”, this makes of course no sense). 2) commit the matched phrase when Tab is typed 3) When committing by typing Space, commit the phrase followed by a “ ” instead of only the phrase. 4) if typing a valid input character has the result that there are no candidates anymore, but there were candidates before typing that character, pop that character from the input again, commit the first of the previous candidates and then reprocess the input character. This is also mainly needed for non-Chinese input methods like the Russian “translit”. The “translit” table contains: sh ш shh щ so typing “sh” matches “ш” and “щ”. The candidate with the shortest key sequence comes first in the lookup table, therefore “sh ш” is shown in the preëdit (The other candidate, “shh щ” comes second in the lookup table and could be selected using arrow-down. But “translit” hides the lookup table by default). Now, when after typing “sh” one types “s”, the key “shs” has no match, so add_input('s') returns “False” and we end up here. We pop the last character “s” which caused the match to fail, commit first of the previous candidates, i.e. “sh ш” and feed the “s” into the key event handler again. Maybe this option should be renamed because the name is really misleading? Maybe even split it in several options, maybe even a separate option for each of 1), 2), 3), and 4)? commit 727736b4a2821ed30d15a091652694e49e7918c2 Author: Mike FABIAN Date: Sat May 17 19:54:59 2014 +0200 Make the setup tool get the default from the database for settings which are not yet set in dconf The setup tool gets the the values for the options to show when it starts up from the following 3 places now: 1) dconf setting for this table 2) database of this table 3) Python dictionary OPTION_DEFAULTS in main.py of setup. So it prefers dconf settings, then the database, and finally the hardcoded values in the setup tool itself. Before this change it did fall back immediately to the hardcoded values OPTION_DEFAULTS if a setting was not yet set in dconf. I.e. it showed exactly the same defaults for all tables. But the defaults in the databases of the tables are usually there for a reason and they should of course be presented to the user before he first changes something in the setup tool. commit f461e78fabc1e58d728bd2d7d5a5cb1d64424463 Author: Mike FABIAN Date: Sat May 17 06:26:45 2014 +0200 Rename self._phrase_table_column_names to phrase_table_column_names It is only used locally when trying to open the user database to check whether the existing user database is incompatible. commit 9878c8da66a0132174bbc2e9c83aec51e012c4a4 Author: Mike FABIAN Date: Fri May 16 22:59:48 2014 +0200 Add a class to cache the ime properties It isn’t really necessary for speed, I removed the original property cache because it barely matters and the original code for the property cache was a bit ugly. But this new code taken from ibus-typing-booster looks quite nice. commit 34a9cd9a5893c4aea08625feed52230f0bce49a7 Author: Mike FABIAN Date: Fri May 16 22:09:32 2014 +0200 Fix typos in a docstring and in an error message commit d7111e64ada3224df4a9315e05f1975777bbacd8 Author: Mike FABIAN Date: Fri May 16 13:53:22 2014 +0200 Fix changing the number of candidates using the setup tool commit cdaa74331fa4ad96ba6b9becdd2db90138840cce Author: Mike FABIAN Date: Fri May 16 11:22:47 2014 +0200 Remove unused code to handle config changes config changes are handled in config_value_changed_cb(), this stuff is not used. commit 236a9349167c095f06c9162f445670da12270461 Author: Mike FABIAN Date: Fri May 16 11:20:07 2014 +0200 Improve coding style in key event handler commit 9527b265b7f4a46c220a9f223108fce93560ec86 Author: Mike FABIAN Date: Fri May 16 11:15:41 2014 +0200 Fix arrow-up and arrow-down keys in Table mode when preëdit is empty In that case, the arrow up and down keys should be passed to the application, for example arrow-up is useful to get the last command in bash. commit 83c1b00deea7e8aa120cea194af0773a5a2f7a13 Author: Mike FABIAN Date: Fri May 16 09:19:54 2014 +0200 Remove commented out line resetting self._editor_onechar in reset() The “onechar” option is even remembered in the config, it makes no sense to reset it in reset(). It was commented out of course already, but better remove it completely there to avoid confusion. commit 64c653cf37cb625764ad3d7b6e32e07aa0b0a707 Author: Mike FABIAN Date: Fri May 16 09:16:36 2014 +0200 Clean up code in do_property_activate commit 8551d2b393aac81a90e3f5078393d24d9bdc651c Author: Mike FABIAN Date: Fri May 16 07:29:30 2014 +0200 Add options to setup for fullwidth and halfwidth mode for direct input mode There are such options for “Table input” already but not for “Direct input”. But even for “Direct input”, when the fullwidth or halfwidth mode is changed using the property menu, the change is saved to the config and remembered, just as for “Table input”. There seems to be no reason for this is kind of “asymmetric” behaviour. So I added these options for “Direct mode” to the setup as well. commit d78936826897f17367d9581f62f90f126af44108 Author: Mike FABIAN Date: Thu May 15 16:52:39 2014 +0200 Improve texts in properties and setup - show “Table mode” ↔ “Pinyin mode” property only when the table really has a pinyin mode. - fix wrong key bindings mentioned in tooltip texts of properties. - improve texts of properties and in the setup tool. commit ed07db95f301c30440974b062624862cca310922 Author: Mike FABIAN Date: Thu May 15 14:25:00 2014 +0200 Fix the combobox in the setup tool to switch between direct input and table input The combobox in the setup tool which was labelled “Language:” and had the values “Chinese” and “English” did not do anything at all. Fix this and improve the names of the label, the options, and the variables to reflect better what it does. commit 7ec547dade8d5cd60ec149b93057a78c0accab3b Author: Mike FABIAN Date: Thu May 15 10:48:51 2014 +0200 Remove unused variable self._pt and unused function tabsqlitedb.get_phrase_table_index() Not needed anymore. After the database redesign, the number of columns does not depend on the table anymore, it is the same for all tables. commit f3c77c8978e2c88dce4b4c162809d8defb62dcfc Author: Mike FABIAN Date: Thu May 15 09:03:43 2014 +0200 Improve the code to recover user data from old, incompatible user databases Recover not only the frequency of phrases which are in the system database but also the frequency of user defined phrases. Code for upgrading from very old databases tested by upgrading from a user database from ibus-table-1.5.0.20140416-1.fc20. commit 39e4f964a427015704a24ae609e39bda39e9d331 Author: Mike FABIAN Date: Wed May 14 22:13:45 2014 +0200 When auto_commit is used and there is only one candidate, commit only when the typed characters match the tabkeys of the candidate completely Much better for non-Chinese tables like “latex”, “ipa-x-sampa”, ... For example, consider that “latex” table contains the following lines matching “\al”: \alpha α \aleph ℵ And the default for the “latex” table is to use auto_commit. That means that with the old code, after typing “\alp”, only the single candidate \alpha α matched and was committed immediately. That is annoying because this makes it necessary to look at the screen. It is easy to remember that “\alpha” means α in LaTeX and if these are commited only when typed completely, one does not have to look at the screen to type α. It is much harder to remember how many characters of \alpha one has to type to get a unique match. Of course committing at “\alp” already saves two key strokes. But even with the new code one can save a few keystrokes if one looks at the screen: Just type “\al”, notice that α is the first candidate, then commit it with space. The new code also avoids the distinction between Chinese/non-Chinese here: In a Chinese table, when len(self._editor._chars_valid) == self._max_key_length *and* there is only one candidate, it follows that the tabkeys for this candidate have been typed completely. That means one can just as well do the same check as for non-Chinese tables, i.e. self._editor._chars_valid == self._editor._candidates[0][0] instead of checking whether the maximum key length is reached. commit 6af47dc416842e3ecabc170c23006ddb215c106e Author: Mike FABIAN Date: Thu Apr 24 18:31:25 2014 +0200 Rewrite update_candidates() - simplify code in update_candidates() - remember both the valid and invalid characters when update_candidates() was last called and return immediately only when *both* are unchanged (Fixes a problem when removing invalid characters with backspace). - simplify add_input() - simplify section to handle valid input characters in key event handler - remove self._tabkeys, it is *always* identical to self._chars_valid commit 33aa9594a8da5022aee256528fcd40ec4e4e0199 Author: Mike FABIAN Date: Wed May 14 09:56:55 2014 +0200 auto_commit_to_preedit() is not needed There is no significant difference between auto_commit_to_preedit() and commit_to_preedit(). The only difference seems to be that auto_commit_to_preedit() tries to commit even when self._chars_valid is empty and even when self._candidates is empty. But in that case it will just fail with an “index out of range” error. To catch this, auto_commit_to_preedit() uses a “try: ... except: ...” instead of checking whether self._candidates is empty like commit_to_preedit() does, that seems to be the only real difference. commit c8eb0e31a375b81f083ae750cbcaf152235299ea Author: Mike FABIAN Date: Tue May 13 19:32:01 2014 +0200 Print some debug output in _table_mode_process_key_event() commit c60350c184622e283d6bfe296eb2db39f09d3a65 Author: Mike FABIAN Date: Tue May 13 19:11:02 2014 +0200 Remove redundant code when processing leading invalid input commit be3be5d02ddd491f16be93e94753064d9321d1c9 Author: Mike FABIAN Date: Tue May 13 17:09:47 2014 +0200 Fix handling of invalid trailing input - Improve documentation of _table_mode_process_key_event() - If invalid input characters came after some valid input characters, the old code committed the valid input and then the invalid character only if the key code of the invalid input was <= 127. Consider for example, for the cns11643 table, the valid input is “0123456789abcdef”. The Chinese character “一” has the table key “14421” in cns11643, it is the first character in that table with a key starting with “1442”. Both “A” and “☺” are invalid input for the cns11643 table. But as “A” has a key code <= 127, it would be committed after committing pending input whereas “☺” which has a key code > 127 would be passed through to the application. Therefore, typing “1442A” would commit “一A” but typing “1442☺” would pass “☹” to the application and keep “1442” in preedit, so the user sees “☺1442”. This makes no sense at all, instead of checking for <= 127, *all* typed keys where “IBus.keyval_to_unicode(key.code)” returns a result should be treated the same way here. Then typing “1442☺” commits “一☺”. - The added lines: if type(keychar) != type(u''): keychar = keychar.decode('UTF-8') are only for Python2 compatibility, they do nothing for Python3. (Maybe I should give up trying to keep Python2 compatibility?) commit 97b51bb779c55026b317ebdd52d4d0f0c24918f5 Author: Mike FABIAN Date: Tue May 13 10:00:50 2014 +0200 Improve wording of the label for the behaviour of the space key And use more consistent upper-case/lower-case spelling commit 614f7b03ea0df3df2781746557c7254441dad59a Author: Mike FABIAN Date: Tue May 13 09:28:32 2014 +0200 Mark 4 strings in the setup UI which should not be translated as untranslatable commit e40c0c9800be7f964bed5c4c72cb82db196a9ce8 Author: Mike FABIAN Date: Tue May 13 08:51:39 2014 +0200 Mark one string translatable and mark two others as untranslatable in main.py It does not make sense to translate "IBus Table %s" and "%s" but "IBus %s Preferences" can be translated. commit 83218dd2d4d07bf3f657ba969e627f233abd1b4a Author: Mike FABIAN Date: Tue May 13 08:47:52 2014 +0200 Improve three labels in the setup tool: “Half/full width:” → “Letter width:” (The combobox already says “Half/Full”, no need to repeat that in the label, better indicate that this is for letters, not for punctuation). “Punctuations:” → “Punctuation width” (“punctuation” is uncountable). “Number:” → “Number of candidates:” commit 075602335e0a1f0216588842a2ef886246e0afbf Author: Mike FABIAN Date: Tue May 13 08:23:58 2014 +0200 Add setup/main.py and setup/ibus-table-preferences.ui to POTFILES.in commit c267d7321b5f77dbaeb6e76e5c82911a498fbb92 Author: Mike FABIAN Date: Tue May 13 07:45:07 2014 +0200 Add names to “Contributors:” section in “About” commit f67e2dbacd77a1a840098ef887414c57401449c8 Author: Mike FABIAN Date: Mon May 12 17:52:48 2014 +0200 Colour invalid characters in preëdit magenta commit 7b16cc73ab02beebb5882058c06cd14ec38940b0 Author: Mike FABIAN Date: Mon May 12 17:35:08 2014 +0200 Improve readability _convert_to_full_width() Use the Unicode characters directly. For example, use u"¥" instead of u"\uffe5" commit d8e9543bac0427c6c079ebda186c28a48d1b7479 Author: Mike FABIAN Date: Mon May 12 16:38:47 2014 +0200 Improve readability in _table_mode_process_key_event() - Try not to use extremely long lines so much - more consistent use of parentheses - No need to check for “and(not self._editor._py_mode)” in “if key.code <32 ...”, pinyin mode does surely not use key codes < 32 either. - document why the Tab key is passed through to the application when auto select is used. Don’t use a very long chain of if ...: ... return True ... return False elif ...: ... <- jumps to the final “return False” here elif ...: ... return True elif ...: ... return True return False rather use if ...: ... return True ... return False if ...: ... return False if ...: ... return True if ...: ... return True return False That makes it easier to see immediately what is returned without always having to remember that there is a final “return False” at the end. commit 47d8ef00794c4bb4c0f2cb7fddcff530c35d8da9 Author: Mike FABIAN Date: Mon May 12 10:43:39 2014 +0200 Simplify code to commit everything in the key event handler There was a function space() which was not only used when committing by typing space but also in other cases. This function was hard too read, had a weird return value and the documentation was wrong. I think the new code is better readable. commit 4e0e598fce01909bf0531ddfb596049d90937c04 Author: Mike FABIAN Date: Mon May 12 05:23:18 2014 +0200 _check_phrase() can be called in commit_string() Makes the code a bit shorter and more readable. commit b9cc9547bed5831c92827c11127cc584675d18a0 Author: Mike FABIAN Date: Mon May 12 05:06:20 2014 +0200 _editor.clear_all_input_and_preedit() not needed here It is called by commit_string() already. commit 32fb67b28cba59a22bbebe550a36b95567a7a0dd Author: Mike FABIAN Date: Sun May 11 20:42:31 2014 +0200 Rename tabengine._ml and editor._max_key_len to tabengine._max_key_length and editor._max_key_length self._ml is not so readable. commit b64be0e575bb1d280c95c420d58166e338169f18 Author: Mike FABIAN Date: Sun May 11 17:39:13 2014 +0200 Remove function documentation which only repeats the function name commit de4d6b60ad1f49521b6aafe5e5d7b4fbc82547a0 Author: Mike FABIAN Date: Sun May 11 17:23:00 2014 +0200 Remove unreachable code in _english_mode_process_key_event() commit a9924b24e713aa4a1193ffb5f04b91c6c803ce9f Author: Mike FABIAN Date: Sun May 11 17:10:37 2014 +0200 Don’t repeat the definitions of cond_letter_translate() and cond_punct_translate() The same functions cond_letter_translate() and cond_punct_translate() are defined both in _english_mode_process_key_event() and _table_mode_process_key_event(). As they are exactly the same, it makes more sense to define these function in one place. commit 44f12df6375df59f6916fa02fec691b6d206fb1e Author: Mike FABIAN Date: Sun May 11 16:43:59 2014 +0200 Rename editor.clear() to editor.clear_all_input_and_preedit() and editor.clear_input() to editor.clear_input_not_committed_to_preedit() Make it more obvious what the different clear...() functions do. Also fix a typo: self._candidate_previous -> self._candidates_previous commit 559a4b399565f847351ef992e0a556a98c4bfefa Author: Mike FABIAN Date: Fri May 9 19:17:03 2014 +0200 rename tabsqlitedb.select_zi() to tabsqlitedb.select_chinese_characters_by_pinyin() commit d9c868670912cefdeffae5af9266d4eb986d3f2e Author: Mike FABIAN Date: Fri May 9 18:49:15 2014 +0200 Rename get_all_input_strings() to get_preedit_tabkeys_complete() To get the strings (= phrases) in the preëdit as parts are complete there are: get_preedit_string_parts() get_preedit_string_complete() For the functions to get the typed key sequences belonging to phrases in the preëdit, there were: get_preedit_tabkeys_parts() get_all_input_strings() which is a bit inconsistent. Better make it get_preedit_tabkeys_parts() get_preedit_tabkeys_complete() then the naming is more symmetric and it also describes better what it actually does (Because if strings in the preëdit have been split, get_preedit_tabkeys_complete() does not necessarily return the exact key sequence the user typed as the key sequences for the split phrases will have been recalculated) commit 889dc948c6211f2ed694e2500703ca926d81dcf6 Author: Mike FABIAN Date: Fri May 9 18:28:12 2014 +0200 Committing with the mouse or by typing Control+Number should not define new abbreviations I avoided defining new abbreviations when committing by typing “space” already, see: commit 56796c39c92697d4fcd233e42ebe8f208f0e1324 Author: Mike FABIAN Date: Wed May 7 14:07:56 2014 +0200 Don’t define new abbreviations automatically For example, the latex table system database contains: \alpha|α|0|0 If one types “\alp” and then selects the candidate “α” from the lookup table, do *not* automatically create (or update) an abbreviated entry \alp|α|0|1 in the user database, instead create (or update) an entry using the full length of the tabkeys: \alpha|α|0|1 Creating shortcuts automatically like this is useful in ibus-typing-booster but it seems useless and confusing in ibus-table. but it didn’t work when committing using Control+Number because the code for Control+Number got the input key sequence *before* committing to preedit and at this point it may not yet be the complete input key sequence of a candidate. During commit to preëdit, the really typed input key sequence is replaced by the input key sequence of the selected candidate, which may be longer. Committing with the mouse inherited this error from the code copied from committing with Control+Number. commit 694aa04ed256fafd13e66accd3a0526e5ed19fc5 Author: Mike FABIAN Date: Fri May 9 17:56:18 2014 +0200 Commit candidate clicked on with the mouse commit d19a2768ec09e5c038db512846678518c98f8daa Author: Mike FABIAN Date: Thu May 8 18:08:07 2014 +0200 Move toggle_tab_py_mode() method from class editor to class tabengine It seems to me it fits better there, because it is nice if it also calls the _refresh_properties() and _update_ui() methods of the class tabengine. commit d977c064a5e21bfc06c4f813d4cfe8a7e103f40f Author: Mike FABIAN Date: Thu May 8 17:46:14 2014 +0200 There is no need to check for differences in pinyin mode before and after commit_string() or editor.clear() commit_string() calls editor.clear() and clear() used to switch off pinyin mode. But we stopped doing that, see: commit 059061e3e76761dca6853610580c9c2549918fbb Author: Mike FABIAN Date: Tue Apr 8 16:34:58 2014 +0200 Don’t switch off pinyin mode in clear() clear() is called in do_focus_out(). And do_focus_out() is called after clicking into the gnome menu to switch to pinyin mode. This makes it almost impossible to enable pinyin mode and keep it when pinyin mode is switched off in clear(). Therefore, there is no need to check whether the pinyin mode has changed after commit_string() or editor.clear() anymore. commit 636aa6604003264cb0e26b77da9c8abb0f67e88b Author: Mike FABIAN Date: Thu May 8 16:43:28 2014 +0200 Show number of candidates and number of current candidate in the auxiliary text commit 64a1fcc13018d19079060dcc04646a08070744d6 Author: Mike FABIAN Date: Thu May 8 16:34:10 2014 +0200 Better variable name _ic -> aux_string in _update_aux() commit 2abd1c56ac3dddb6ff0a2e05595a601f9dba438a Author: Mike FABIAN Date: Thu May 8 16:29:37 2014 +0200 Remove meaningless comment commit 5c14c84d665fa9cd6a0b93ec516f0a18eb47194e Author: Mike FABIAN Date: Thu May 8 16:09:57 2014 +0200 Show the list of possible input key sequences for characters in the preëdit not only for pinyin If there are no input strings at the moment but there are strings committed to preëdit, some information about these may be shown in the auxiliary text. If the last character committed to preëdit was typed by using pinyin mode, a list of possible input sequences how this character could be typed using the current table (e.g. wubi-jidian86) was shown. This way, one can type a character using pinyin, commit it to preëdit and then see which table input key sequences could have been used to type the same character. It doesn’t really make sense to limit this to the last typed character and only if it has been typed using pinyin. Showing these table codes always is better. commit 75483fd33d139a8ccabfbe42b286a09b4e8e2f78 Author: Mike FABIAN Date: Thu May 8 15:01:31 2014 +0200 Do not hide the auxiliary text when there are no candidates, it might contain useful information The auxiliary text may contain useful information even when there are no candidates. For example, when committing a few characters to preëdit to define a user defined phrase, the auxiliary text shows what key sequence will be defined for that phrase. For example, when wubi-jidian86 is used and the phrase “王不各” is commited to preëdit and no further input is currently there, the auxiliary text shows “#: ggtk” Here “ggtk” is the key sequence which will be defined for that phrase, i.e. in future one can type “ggtk” to input “王不各”. The auxiliary text also shows the table keys if the last character committed to preëdit has been typed using pinyin. For example, if one uses wubi-jidian86 and has forgotten the table codes for 你 one can type it using pinyin by switching to pinyin mode (with the menu or the right shift key), type “ni + Shift + 3” to get 你, commit it to preëdit by selecting it with Control+Number in the lookup table, then the wubi-jidian86 table codes for 你 are displayed in the auxiliary text: wq wqi wqiy commit f7430ef738e3a236019a2a8f3a8bea98cb6ebee1 Author: Mike FABIAN Date: Wed May 7 22:44:06 2014 +0200 Use an integer self._cursor_precommit instead of an array self._cursor[] self._cursor[1] is never used anymore after my rewrite of the cursor movement code because I split the strings committed to preëdit already when the cursor is moved and not in add_input() anymore, so there is no need to keep track of a second cursor position. commit 7c6eb47bb0e9db76d1c21433e812f1cc7b0bd5b7 Author: Mike FABIAN Date: Wed May 7 14:07:56 2014 +0200 Don’t define new abbreviations automatically For example, the latex table system database contains: \alpha|α|0|0 If one types “\alp” and then selects the candidate “α” from the lookup table, do *not* automatically create (or update) an abbreviated entry \alp|α|0|1 in the user database, instead create (or update) an entry using the full length of the tabkeys: \alpha|α|0|1 Creating shortcuts automatically like this is useful in ibus-typing-booster but it seems useless and confusing in ibus-table. commit fe807080c31ca0b09ff46aaee6c9575c2e9bb1c9 Author: Mike FABIAN Date: Wed Apr 23 16:03:25 2014 +0200 Fix cursor movements in the strings committed to preëdit Rewrite most of the code for cursor movements in the preëdit because it did not work at all. The old non-working code tried to use wrap around when the cursor reached the ends of the preëdit. I think that is confusing and implemented it without wrap around. When there are strings committed to preëdit and a space is typed while the current input is empty, the preëdit should be committed (this was broken). commit 940e629c2fae386ea0f1532325c6a971b703cdf0 Author: Mike FABIAN Date: Wed May 7 09:29:41 2014 +0200 Remove useless “else:” when committing using space editor.space never returns (False, u' ', ...) so this “else:” part can never be reached. commit 193d2bbd20492e05f29290995aac0fe4ea73ad09 Author: Mike FABIAN Date: Wed May 7 09:26:15 2014 +0200 Remove comments mentioning self.add_string_len() because there is no such function anymore commit b7946d48de07ae6b6cca0d80519130d94b245337 Author: Mike FABIAN Date: Mon May 5 21:27:38 2014 +0200 Fix find_zi_code, it should return a list of possible tabkeys for a phrase The documentation “Check word freq and user_freq” was very misleading. Actually it should return a list of possible tabkeys for a phrase. For example, if “phrase” is “你” and the table is wubi-jidian.86.txt, the result will be ['wq', 'wqi', 'wqiy'] because that table contains the following 3 lines matching that phrase exactly: wq 你 597727619 wqi 你 1490000000 wqiy 你 1490000000 commit b55980f79ab6eb36ece9560b4c04b9bee5a21bce Author: Mike FABIAN Date: Mon May 5 16:30:25 2014 +0200 Add one space between the phrase and the remaining tabkeys in the lookup table Easier to read. commit 49be55f44ceb1d12c9e8d45d17163b0998234eeb Author: Mike FABIAN Date: Mon May 5 16:06:04 2014 +0200 Merge matches from the system database and the user database To avoid duplicates in the candidate list. For example, if we have the result ('aaaa', '工', 551000000, 0) from the system database and ('aaaa', '工', 0, 5) from the user database, these should be merged into one match ('aaaa', '工', 551000000, 5). commit bfe7932dc50f413ae7804e4f923acd08247264ac Author: Mike FABIAN Date: Sun May 4 19:17:36 2014 +0200 Improve documentation of select_key() commit e831737780d3284cfcea41ec5183ffdd38f03746 Author: Mike FABIAN Date: Sun May 4 18:45:17 2014 +0200 Handle start characters correctly Some tables (currently the “latex” table is the only one I know of) have special “start characters”. For example, in the latex table, the start character is “\”, i.e. every key in that table starts with a “\”, if the first character typed is anything else but “\”, no match is possible and therefore the typed character should be directly committed or directly passed to the application without attempting a match in the table. commit 77aee36498f6f17a28193de60b87fc28c33d0dba Author: Mike FABIAN Date: Fri May 2 11:38:39 2014 +0200 Remove self._t_chars self._t_chars seems to be just self._chars_valid + self._chars_invalid (possibly + u''.join(self._u_chars)?? Anyway, there is no need to have yet another variable for the same stuff. It is error prone to correctly keep it in sync with the other variables containing the same information. commit 754175b068c111211d6dad76e990f8e88ad173ec Author: Mike FABIAN Date: Thu May 1 18:59:03 2014 +0200 Rewrite _update_preedit() and get_preedit_strings() Instead of returning a complicated string in get_preedit_strings() and parse it again into parts using regular expressions in _update_preedit(), rather return a tuple of the parts _update_preedit() needs. Rename the function returning these parts from get_preedit_strings() to get_preedit_string_parts() and add a function get_preedit_string_complete() which joins these parts and is used where the distinction of the parts is not necessary. commit ab4bb95fb873febc52aa69cf2ad0f1cbc3c91fc0 Author: Mike FABIAN Date: Wed Apr 30 16:33:02 2014 +0200 over_input() should not clear self._u_chars[] It does this only to cause a weird side effect in get_preedit_strings(). But that is quite nonsensical, get_predit_strings() and _update_preedit() should be rewritten not to depend on this. Clearing only self._u_chars[] but not self._strings[] makes these two arrays have different lengths, but they should always have the same length. if clearing self._u_chars[] is removed from over_input(), over_input() becomes useless as it only calls clear_input() now and it can be removed. commit 2c10c727e2ee3ecfa92afe372f9f3ea424eee740 Author: Mike FABIAN Date: Wed Apr 30 09:26:06 2014 +0200 self._strings and self._u_chars should always have the same length As self._strings and self._u_chars *always* should have the same length, there is no need to check “if self._strings” before self._strings.pop() if self._u_chars is already known to be not empty. Of course the extra check doesn’t hurt, but if self._strings and self._u_chars ever happen to have a different length, I want it to fail and then figure out how this could happen. commit 73b836dd0212aac3dbe1be3d4d6f877e6382acd6 Author: Mike FABIAN Date: Wed Apr 30 09:46:22 2014 +0200 self._caret is never used outside of get_caret(), it should not be a member variable A local variable in get_caret() is enough and makes the code better readable. commit 4ced4cde39213d265b20e45a743069d1f697d55b Author: Mike FABIAN Date: Wed Apr 30 09:21:06 2014 +0200 Remove useless function add_caret() Only used once and it only adds the length of a string to self._caret, I think it is more readable to do that directly. commit d1b2489bbf72092c258ad76d74d23c9d8ba527f5 Author: Mike FABIAN Date: Wed Apr 30 08:43:31 2014 +0200 Remove useless line in pop_input() self._chars_invalid = self._chars_invalid[:-1] does nothing there because it is in the “else:” part of “if self._chars_invalid:”. commit af666b23c45e453bef07b2a2076e8849f0935d85 Author: Mike FABIAN Date: Wed Apr 30 07:46:37 2014 +0200 Improve readability of _update_preedit() and enable colours commit 2d1292994f5a133b5ad4a9a0cad7fb7f27315339 Author: Mike FABIAN Date: Wed Apr 30 07:49:27 2014 +0200 Remove unused function get_input_chars_string() commit 947f550135ab924e7fe722f6d4b68bb1cce523fd Author: Mike FABIAN Date: Tue Apr 29 17:26:34 2014 +0200 Remove arbitrary limit max_length = 64 in editor class commit b8a78e00cb18eb2d948c4865a068537dec18445b Author: Mike FABIAN Date: Tue Apr 29 17:24:47 2014 +0200 Remove useless uses of try: ... except: commit d1b76b3d388a879c543dc875cd4de43719fb27b5 Author: Mike FABIAN Date: Tue Apr 29 16:57:58 2014 +0200 Remove useless “pass” commit 021ed36dccf2c936cef580d376bd303e599237f9 Author: Mike FABIAN Date: Tue Apr 29 15:09:01 2014 +0200 self._u_chars needs to be an array of strings self._u_chars needs to be an array of strings, not a simple string because it needs to hold the key sequences which were used when the phrases in self._strings were automatically committed. commit 6d072baab9f33d2daa4adc8b7437c73cb5d558d2 Author: Mike FABIAN Date: Tue Apr 29 14:53:09 2014 +0200 Add debug information about self._u_chars into the aux strings commit a2f716ca1f238f4f78e90bf5c199e81c48b7a9fb Author: Mike FABIAN Date: Tue Apr 29 14:08:56 2014 +0200 Don’t use “pass” so much after “except:” Better print a backtrack to the debug log. It is better to at least see in the debug log what went wrong. commit 72cbde05efbc3b8c2e5fd847c00a2739fc7970d6 Author: Mike FABIAN Date: Mon Apr 28 15:35:59 2014 +0200 Split _candidates[[],[]] into two arrays _candidates[] and _candidates_previous[] Makes the code more readable. commit 45eb8d275d9dae573cd632e2efdc8e065c9f3fb1 Author: Mike FABIAN Date: Mon Apr 28 13:59:28 2014 +0200 Add comments about the meaning of “auto select” in the source code commit 288a1ccdf2a6b033e4977e1a526f7dfc08c43422 Author: Mike FABIAN Date: Sun Apr 27 06:10:13 2014 +0200 Improve documentation of tabsqlite commit 4600fc5b2c5dd129400650556b5dac7289c3836f Author: Mike FABIAN Date: Sun Apr 27 06:01:25 2014 +0200 Don’t try to open a user database if user_db = None in __init__() of tabsqlitedb If an in-memory user database is wanted, tabsqlitedb now needs to be constructed with user_db=':memory:', user_db=None now really means that no user database at all is needed. No user database is needed for example when creating a system database file or when just listing information about engines with /usr/libexec/ibus-engine-table --xml commit 51ea61a8b8df101019c7fd0e43c427dc69b918f6 Author: Mike FABIAN Date: Sat Apr 26 06:31:09 2014 +0200 Rename phrase_keys_len() to get_possible_tabkeys_lengths() and pkeylens to possible_tabkeys_lengths Also document it a bit and remove a useless try: ... except: commit 1ff41d6bae3ebc9014d17d12320f1c058daf7a3a Author: Mike FABIAN Date: Sat Apr 26 06:29:34 2014 +0200 Make sure the lookup table is hidden if there are no candidates to display commit 99d54e2ddb171f523ddbf73872617b40e05012b0 Author: Mike FABIAN Date: Fri Apr 25 17:46:13 2014 +0200 Improve code readability when writing and reading the ime properties Remove property cache, the performance benefit of this is completely negligible. commit 81ec0d8c8319da908d684ec05443557bc4c0ea8d Author: Mike FABIAN Date: Fri Apr 25 14:05:43 2014 +0200 Simplify get_start_chars() commit 93826f6508231a87eb93c8feba591eee849bd949 Author: Mike FABIAN Date: Fri Apr 25 14:02:43 2014 +0200 Simplify get_select_keys() commit f124f3fbcbdd778a80c99e8dc8ac90f3fc67205e Author: Mike FABIAN Date: Fri Apr 25 11:40:45 2014 +0200 Don’t use self._strings.pop() in pop_input() if self._strings is already empty commit 3d88a387de029616415d19236d2fb9b21894c8a8 Author: Mike FABIAN Date: Thu Apr 24 17:01:10 2014 +0200 Minor code cleanup commit 9b6359328ac0df9a37c32776672c708edc635161 Author: Mike FABIAN Date: Thu Apr 24 16:30:37 2014 +0200 Rename self._chars_valid to self._chars_valid_when_update_candidates_was_last_called Long name, but this makes the purpose of that variable clear. It is used *only* to make update_candidates() return fast when nothing has really changed. If the users input characters have not changed, usually no update_candidates() is necessary, but there are some exceptional cases for example when deleting a candidate from the user database when the candidate list changes while the user input has not changed. In these exceptional cases, an update of the lookup table needs to be forced. commit 1357f7468d9cd0dfa4adde7af623d614c0ae71f7 Author: Mike FABIAN Date: Thu Apr 24 14:03:59 2014 +0200 Fix remove_cand_from_userdb() and rename it to remove_candidate_from_user_database() After the database redesign, tabsqlitedb.remove_phrase() takes named arguments “tabkeys” and “phrase” instead of a complete candidate as an array. Also, instead of deleting a candidate from the user database only if it is user defined and thus not in the system database (candidates which have freq=-1 in the user database are user defined), delete the candidate always, if it is in the user database at all. This way, the user can not only use this function to remove user defined candidates but also to lower the priority of candidates which are already in the system database and have aquired a high priority by being used. Removing these candidates from the user database lowers their priority again. commit f6980e0d4a4c1176a5c4d3a88fcc979eac016b18 Author: Mike FABIAN Date: Thu Apr 24 10:18:29 2014 +0200 Small code readability improvement commit f89ecce98ae919c7f4077632c24c31fa0d216f3d Author: Mike FABIAN Date: Thu Apr 24 09:52:11 2014 +0200 Introduce an environment variable IBUS_TABLE_DEBUG_LEVEL for debugging Currently, if this variable is set to a number > 0, system frequency and user frequency data is shown in the lookup table. commit 79f12fcbbb9969f3b5f152407cafff350b4eb83b Author: Mike FABIAN Date: Thu Apr 24 09:02:59 2014 +0200 Instead of an array self._chars = [u'',u'',u''] use three separate strings Using self._chars_valid, self._chars_invalid, and self._chars_prevalid instead of self._chars[0], self._chars[1], self._chars[2] makes the code more readable because one does not have to remember what the indices 0, 1, 2 mean. commit 45823c5f7e0956d7070190f38236531ee4ddef29 Author: Mike FABIAN Date: Wed Apr 23 17:45:27 2014 +0200 Use strings instead of lists for the input characters typed by the user Makes the code more readable, avoids many complicated statements with join, list, map, ... The only places where it looks slightly less readable with strings is c = a[-1] a = a[:-1] when a is a string instead of c = a.pop() when a is a list. commit cd55dd5f2f0e79e4a5138858bdbab9a7590a6401 Author: Mike FABIAN Date: Thu Apr 24 05:37:45 2014 +0200 Remove unused function get_index() commit 313fee39a613c0d0391e636ea1d53b9cf8565208 Author: Mike FABIAN Date: Wed Apr 23 16:57:49 2014 +0200 Update copyright texts in headers commit 364307af21d3a15ab811acfdf81896ffd9038953 Author: Mike FABIAN Date: Wed Apr 23 17:44:41 2014 +0200 Remove unused functions get_invalid_input_chars() and get_invalid_input_string() commit 4fa966bc0651500bec38061ce4b33e22a15407dd Author: Mike FABIAN Date: Thu Apr 10 11:36:59 2014 +0200 Change the design of the database The old database used columns like id|mlen|clen|m0|m1|m2|m3|m4|category|phrase|freq|user_freq where “m0”, “m1”, “m2”, “m3”, “m4” did hold individual characters of the input string which was therefore limited to a fixed maximum (could be different for each table). In this case the maximum is 5 characters. “mlen” was the length of the input string actually used, for example if the input string was “adlt”, then “mlen = 3”, “m0 = a”, “m1 = d”, “m2 = l”, “m3 = t”, and “m4 = None”. “clen” was the length of the Chinese phrase matching this input string, for example, if “adlt” is the input string for the Chinese phrase “苦力”, then “clen = 2”. “category” was a bitmask indicating whether that Chinese phrase is simplified Chinese, traditional Chinese, used in both variants of Chinese, or is a mixture of simplified and traditional Chinese. Non-Chinese tables lacked that “category” column. I.e. in this example the database row in system database for the old design would have looked like: 345|4|2|a|d|l|t|None|1|苦力|3600000|0 (“345” is an abitrary row-id) The new database now uses only: id|tabkeys|phrase|freq|user_freq “tabkeys” is the combination of “m0” ... “m4”, it is of type TEXT and has no artificial limit (except the limit imposed by sqlite, which is huge). So the row in the above example would look like this in the new database design: 345|adlt|苦力|3600000|0 “mlen” and “clen” have been removed, they just duplicate information, the lengths can be calculated easily when needed. “category” has been removed as well, it can be calculated fast and easy at runtime, there is no need to save this at build time into the system database. Omitting “category” also makes the columns used in Chinese and non-Chinese databases identical, avoiding lots of special cases for Chinese and non-Chinese in the code. commit f973563cf3283a7adcff66c68068c2be3739a8a8 Author: Mike FABIAN Date: Wed Apr 23 16:51:30 2014 +0200 Remove useless “$Id: $” from comments in the file headers This is not used by git, it was only useful for older version control systems. commit 7cbf9e8a773c5d37bcad92f50b2f55d6a480c330 Author: Mike FABIAN Date: Thu Apr 17 09:40:56 2014 +0200 Don’t filter candidates in pinyin mode I may change that again later, but currently the format of the candidate tuples in pinyin mode is different from the format in non-pinyin mode which makes this filtering fail. Therefore, pinyin mode would not work at all at the moment if Chinese mode 2 or 3 is selected. commit 4b392e8c2723c5f20e4d13da5770204c53b9baa6 Author: Mike FABIAN Date: Wed Apr 16 17:07:38 2014 +0200 Simplify pinyin table commit 385e6df95830837cc0338d6bc7de5e32679a20a4 Author: Mike FABIAN Date: Thu Apr 17 13:04:56 2014 +0200 Don’t use try: and except: to decide whether to decode from UTF-8 in get_no_check_chars() commit ff310fb1f07eead2383461b22e6443dc93d78ef0 Author: Mike FABIAN Date: Wed Apr 16 08:49:16 2014 +0200 Simplify goucima database table and remove goucima cache The goucima cache is not really used anyway. Only in tabcreatedb.py db.cache_goucima() is called, but then not used there either. commit f5d77946d7acefdf89bb583036378354015c1071 Author: Mike FABIAN Date: Tue Apr 15 17:29:11 2014 +0200 Remove parse_phrase_to_tabkeys() and simplify parse_phrase() commit 117d2d3e3f68845940b146011b137a6acef7956f Author: Mike FABIAN Date: Tue Apr 1 17:51:16 2014 +0200 Remove tabdict Do not translate the typed characters into integers with tabdict. Use the characters themselves instead. Translating characters to integers doesn’t make anything faster, just more complicated. Even if a translation to integers were desirable, why use a custom table and not the Unicode code points? A custom table always needs to be extended when more characters are allowed as valid input characters. commit 081f61e5dc886dd8c897a9f4a2f5b75b7cb81cd6 Merge: 1347342 3f031f7 Author: Caius 'kaio' Chance Date: Wed Apr 16 19:06:33 2014 +1000 Merge pull request #33 from mike-fabian/do-not-fail-when-home-is-not-set Do not fail when home is not set commit 3f031f799256bee9cf93800d7b844310e825fb6f Author: Mike FABIAN Date: Wed Apr 16 09:28:44 2014 +0200 Do not fail when the environment variable HOME is not set Resolves: rhbz#1088138 - [abrt] ibus-table: posixpath.py:83:join:TypeError: unsupported operand type(s) for +=: 'NoneType' and 'str' See: https://bugzilla.redhat.com/show_bug.cgi?id=1088138 commit 5f6cc149803dd876fb773d8653cc30d2424cd25f Author: Mike FABIAN Date: Tue Apr 15 16:57:28 2014 +0200 Remove unused code commit 52af130ae18d84b6611834a298d4c8a92c76621c Author: Mike FABIAN Date: Tue Apr 15 16:36:51 2014 +0200 Return only tabkeylist in parse_phrase() The other stuff returned is never used, just thrown away. commit f0dbeb54d65d72451b1c56d91677a1edf6c08703 Author: Mike FABIAN Date: Mon Apr 14 13:14:44 2014 +0200 Remove unused function add_new_phrases() commit e24302cc9e85786c044fc1dc0b79c3a7d724c3c5 Author: Mike FABIAN Date: Mon Apr 14 11:21:52 2014 +0200 remove unused regular expression in parse_extra() in tabcreatedb.py This regular expression would not work with Python3 anymore. But it is not used anyway, so it can be just removed. commit 1347342cc71a719a168526e62d19d859bb5b0d97 Merge: ccb4b1b bd30def Author: Caius 'kaio' Chance Date: Mon Apr 14 19:02:28 2014 +1000 Merge pull request #32 from mike-fabian/fix-pinyin-mode-and-dconf-usage Fix pinyin mode and dconf usage commit bd30def611453ffbb065964006fe5a5c2ad525a0 Author: Mike FABIAN Date: Mon Apr 14 09:11:28 2014 +0200 Fix goucima parsing from the source, broken by Python3 port This regular expression: patt_s = re.compile(r' *([^\s]+) *\t *([\x00-\xff]{3}) *\t *[^\s]+ *$') which tries to match single Chinese characters as a sequence of 3 bytes does not match anymore after the Python3 port because Python strings are always unicode now and each Chinese character is thus a single character in a string. commit 599601db7fed46b6e21c227b62ec9145199ecef2 Author: Mike FABIAN Date: Wed Apr 9 16:03:07 2014 +0200 If keychar is empty, do not treat it as valid input This makes typing the right shift key toggle between pinyin mode and table mode, as intended. In Python >>> '' in 'abc' True Therefore, “keychar in self._valid_input_char” is True even if keychar is empty. But if keychar is empty, one should not treat it as valid input. This problem occured when pressing Shift-Right, it was treated as valid input and the following traceback was seen: Traceback (most recent call last): File "/local/mfabian/src/ibus-table/engine/table.py", line 1596, in do_process_key_event result = self._process_key_event (key) File "/local/mfabian/src/ibus-table/engine/table.py", line 1618, in _process_key_event return self._table_mode_process_key_event (key) File "/local/mfabian/src/ibus-table/engine/table.py", line 1856, in _table_mode_process_key_event res = self._editor.add_input ( keychar ) File "/local/mfabian/src/ibus-table/engine/table.py", line 398, in add_input res = self.update_candidates () File "/local/mfabian/src/ibus-table/engine/table.py", line 804, in update_candidates self.pop_input () File "/local/mfabian/src/ibus-table/engine/table.py", line 409, in pop_input self._tabkey_list.pop() IndexError: pop from empty list commit 2c145910964141a66724412e04d446c0298f0f6c Author: Mike FABIAN Date: Tue Apr 8 17:51:12 2014 +0200 Don’t try to colour system phrases and user phrases differently in pinyin mode In pinyin mode, there are no user defined phrases. Therefore, the array holding a candidate does not have two integers at the end, only one. candi[-2] is already the phrase, i.e. the chinese character in pinyin mode, not an integer specifying a frequency. Resolves: rhbz#1084684 - [abrt] ibus-table: table.py:670:ap_candidate:TypeError: unorderable types: str() < int() See: https://bugzilla.redhat.com/show_bug.cgi?id=1084684 commit f463ca439467ff29270fa09cd108fa8f02304385 Author: Mike FABIAN Date: Tue Apr 8 16:46:21 2014 +0200 Don’t use “try:” to call self._editor.clear() in do_focus_out() Why should self._editor.clear() ever fail? If problems can occur there, they should be handled properly there. commit 059061e3e76761dca6853610580c9c2549918fbb Author: Mike FABIAN Date: Tue Apr 8 16:34:58 2014 +0200 Don’t switch off pinyin mode in clear() clear() is called in do_focus_out(). And do_focus_out() is called after clicking into the gnome menu to switch to pinyin mode. This makes it almost impossible to enable pinyin mode and keep it when pinyin mode is switched off in clear(). commit 00a41b813adba4155f19a84706702f693c3e987c Author: Mike FABIAN Date: Tue Apr 8 11:16:16 2014 +0200 Make usage of engine name and dconf key consistent The setup tool did write to a different dconf key than the engine. Make this consistent. If the file name of the table is /usr/share/ibus-table/tables/wubi-jidian86.db use table:wubi-jidian as the ibus engine name (listed by “ibus list-engine” and used in the environment variable IBUS_ENGINE_NAME). As the dconf key, use: /desktop/ibus/engine/table/wubi-jidian86 The name found in the source of the table (i.e. in wubi-jidian86.txt in the source package of ibus-table-chinese), which looks like ### The default name of this table NAME = WuBi-Jidian (JiShuag) 86 should not be used for the dconf key or the engine name, it should only be used for display in the user interface. commit ccb4b1bc4a778381e013ef64838dc8292e61d436 Merge: 3255f48 8842b41 Author: Caius 'kaio' Chance Date: Thu Apr 10 22:13:35 2014 +1000 Merge pull request #31 from mike-fabian/fix-regression-caused-by-python3-port-causing-the-build-of-ibus-table-chinese-to-fail Fix a regression caused by the Python3 port in tabcreatedb.py commit 8842b411e32a7c10dce22ee578974bc37ee8081c Author: Mike FABIAN Date: Tue Apr 1 18:18:11 2014 +0200 Fix a regression caused by the Python3 port in tabcreatedb.py This fixes the build of ibus-table-chinese. commit 3255f48cb6cdd6311ca9ae0dadaee349b6f6ce72 Merge: cd317b7 0df841f Author: Caius 'kaio' Chance Date: Sat Mar 15 21:22:16 2014 +1000 Merge pull request #30 from mike-fabian/fix-bug1072940-comment18 filter returns a “filter object” in Python3, not a list directly as in Python2 commit 0df841f416f6bac13630c8eb6b6f711d312436a5 Author: Mike FABIAN Date: Wed Mar 12 15:04:30 2014 +0100 filter returns a “filter object” in Python3, not a list directly as in Python2 Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1072940#c18 commit cd317b7d473eb94554e79fe91f5417a4f9074b60 Merge: 1c437bf 19ee83e Author: Caius 'kaio' Chance Date: Wed Mar 12 22:12:34 2014 +1000 Merge pull request #29 from mike-fabian/fix-setup-tool-for-use-with-gnome Fix setup tool for use with gnome commit 19ee83e6d762d71f4fde8cebd59735e4f0b31529 Author: Mike FABIAN Date: Wed Mar 12 07:31:47 2014 +0100 Add generated .tar.gz to .gitignore commit 4bb405e984934980940758d58c4e112ae7be3dd6 Author: Mike FABIAN Date: Wed Mar 12 07:18:22 2014 +0100 Fix a spelling error in a variable name, a regression introduced by the Python3 port commit 5d1e95aeb9b75583e9caa841f27c68ec5765814b Author: Mike FABIAN Date: Tue Mar 11 13:25:12 2014 +0100 Fix regression introduced by the Python3 port ascii.ispunct() from “from curses import ascii” can take both characters or integers as the argument. My replacement ascii_ispunct() takes only a character. commit 0f6561fea4c2ca9aa90106e4529bc8d32a2a261c Author: Mike FABIAN Date: Fri Mar 7 12:46:00 2014 +0100 Add a .desktop file and make the setup tool work with Gnome Previously, the setup tool could be called from the command line, for example: /usr/libexec/ibus-setup-table cangjie3 /usr/libexec/ibus-setup-table wubi-jidian86 ... But it could not be called from “gnome-control-center region”, not setup icon did appear for the ibus-table engines. To make this work, a desktop files /usr/share/applications/ibus-setup-{...}.desktop need to be added where {...} is the engine name up to the first “:” character. When the engine names are just the table names (“cangjie3”, “wubi-jidian86”, ...), each table would need to supply its own .desktop file /usr/share/applications/ibus-setup-cangjie3.desktop /usr/share/applications/ibus-setup-wubi-jidian86.desktop ... That is not nice, especially as many tables are in different rpm packages. It is better to have just a single .desktop file /usr/share/applications/ibus-setup-table.desktop This can be used for all engines if the ibus engine names are changed like: cangjie3 → table:cangjie3 wubi-jidian86 → table:wubi-jidian86 ... because only the part before the first “:” in the ibus engine name is used by gnome to decide which desktop file to use. The desktop file contains a line like: Exec=/usr/libexec/ibus-setup-table and the setup tool is is called by Gnome without any command line arguments. But Gnome sets the enviromnent variable IBUS_ENGINE_NAME to the engine name when calling the setup tool. So I changed the setup tool to work like this: IBUS_ENGINE_NAME=table:cangjie3 /usr/libexec/ibus-setup-table or /usr/libexec/ibus-setup-table --engine-name table:cangjie (The command line option is preferred over the environment variable when both are given). commit 491a83fad777e3c451ba1bdecc8a0452d71176fa Author: Mike FABIAN Date: Fri Mar 7 14:56:36 2014 +0100 Make it possible to interrupt the setup tool with Control-C from the command line commit 668469998fafc4be52b6a51a290f8e998caa8034 Author: Mike FABIAN Date: Fri Mar 7 12:46:57 2014 +0100 add autogenerated files table.xml and ibus-table-createdb.1 to .gitignore commit c295c6f9a1d7de2e82ee92b4a38499af6f54ff8c Author: Mike FABIAN Date: Thu Mar 6 14:29:14 2014 +0100 add autogenerated files version.py ibus-setup-table to setup/.gitignore commit 7284a2b96d1b3905a29b28034feffbf16941bac3 Author: Mike FABIAN Date: Thu Mar 6 14:26:52 2014 +0100 Remove trailing whitespace and fix some spelling mistakes in comments commit 0adf55500aac6cda98e43f08561f59c78b254080 Author: Mike FABIAN Date: Thu Mar 6 08:46:09 2014 +0100 Correct description of toggle_tab_py_mode() and cycle_next_cand() commit 72cd5718c8e912ba14be220e5be7421bede02303 Author: Mike FABIAN Date: Thu Mar 6 08:33:45 2014 +0100 Fix spelling mistake in variable name commit 29666688c03590f285307aface392071f0b1f800 Author: Mike FABIAN Date: Thu Mar 6 08:37:52 2014 +0100 Remove unused speedmeter code which has already been commented out commit f7e9ae9b96aa79fb71e30c6a4c004e3833f87b9c Author: Mike FABIAN Date: Wed Mar 5 16:35:41 2014 +0100 Don’t try to set _prev_char in commit_string() when an empty string is committed Without this fix one can produce a backtrace by using “wubi-haifeng86” and typing “dkl” followed by “Shift” and “Space”. After “Shift” the preëdit is empty and “Space” commits and empty string then. This leads to the following backtrace: Traceback (most recent call last): File "/local/mfabian/src/ibus-table/engine/table.py", line 1589, in do_process_key_event result = self._process_key_event (key) File "/local/mfabian/src/ibus-table/engine/table.py", line 1611, in _process_key_event return self._table_mode_process_key_event (key) File "/local/mfabian/src/ibus-table/engine/table.py", line 1824, in _table_mode_process_key_event self.commit_string (sp_res[1]) File "/local/mfabian/src/ibus-table/engine/table.py", line 1516, in commit_string self._prev_char = string[-1] IndexError: string index out of range commit 053a37ad1f19f5affd02befbe2af52adac1e46d7 Author: Mike FABIAN Date: Wed Mar 5 16:19:34 2014 +0100 use editor.commit_to_preedit() instead of deleted editor.l_shift () Resolves: rhbz#1072940 - Left Shift stopped work for ibus-table-1.5.0.20140218-1.fc20.noarch See also: https://bugzilla.redhat.com/show_bug.cgi?id=1072940 Was broken by: https://github.com/kaio/ibus-table/commit/fb11d92439fe4bd55fcad480d3998a17434f6870 commit fb11d92439fe4bd55fcad480d3998a17434f6870 Author: Caius "kaio" CHANCE Date: Mon May 6 21:05:35 2013 +1000 Issue #17: Removed excessive instance creation of IBusLookupTable in editor class. Removed commit 0ebecfd0c97966f6c9d0b462cc93868f0a8f4077 Author: Mike FABIAN Date: Mon Mar 3 17:15:54 2014 +0100 Port ibus-table from Python2 to Python3 I kept it working with Python2 for the moment, but in the long run it is probably not worth the maintenance effort to keep it working with Python2. - I added stuff like if type(s) != type(u''): s = s.decode('UTF-8') for compatibility with Python2. http://docs.python.org/3/whatsnew/3.3.html says: > • The u'unicode' syntax is accepted again for str objects. So the above compatibility hack does not work for Python3 < 3.3. - define our own compatibility function def ascii_ispunct(character): if character in '''!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~''': return True else: return False instead of using ascii.ispunct() from “from curses import ascii” to get the intended behaviour both in Python2 and Python3: $ python3 Python 3.3.2 (default, Feb 19 2014, 14:35:19) [GCC 4.8.2 20131212 (Red Hat 4.8.2-7)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from curses import ascii >>> ascii.ispunct('.') True >>> ascii.ispunct('a') False >>> ascii.ispunct('☺') True >>> ascii.ispunct(u'a') False >>> ascii.ispunct(u'☺') True >>> ascii.ispunct(u'あ') True >>> $ python2 Python 2.7.5 (default, Feb 19 2014, 13:47:28) [GCC 4.8.2 20131212 (Red Hat 4.8.2-7)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from curses import ascii >>> ascii.ispunct('.') True >>> ascii.ispunct('a') False >>> ascii.ispunct('☺') Traceback (most recent call last): File "", line 1, in File "/usr/lib64/python2.7/curses/ascii.py", line 63, in ispunct def ispunct(c): return _ctoi(c) != 32 and not isalnum(c) File "/usr/lib64/python2.7/curses/ascii.py", line 50, in _ctoi return ord(c) TypeError: ord() expected a character, but string of length 3 found >>> ascii.ispunct(u'a') True >>> ascii.ispunct(u'☺') True >>> ascii.ispunct(u'あ') True >>> ascii.ispunct(u'a'.encode('ascii')) False >>> Python3 commit e52f7dfcf4c63024f3ab98084d7ddffeb5a8abdf Author: Mike FABIAN Date: Thu Mar 6 07:49:32 2014 +0100 Add profiling support Write profiling information into the debug log when started with “--profile”. The profiling information appears automatically in the debug log after “ibus restart” when profiling is enabled. commit 893b999bee1de649dd1864b551e43974e42808e8 Author: Mike FABIAN Date: Mon Mar 3 13:15:08 2014 +0100 Use @PYTHON@ instead of just 'python' in ibus-setup-table.in To get it replaced by the correct python interpreter when doing something like: PYTHON=python3 ./configure commit 18797b2f515c1669c89ff59fd0ab5050b741974f Author: Mike FABIAN Date: Tue Mar 4 13:57:01 2014 +0100 Fix directory for setup tool It is in /usr/libexec/ibus-setup-table on Fedora. commit 1c437bf6896874903a6c0b1b496b93b54790bcbc Merge: fc6ce51 16a4f1c Author: Caius 'kaio' Chance Date: Mon Mar 3 21:21:53 2014 +1000 Merge pull request #27 from mike-fabian/fix-saving-database-periodically-for-gobject-introspection-and-a-patch-from-leftmostcat Fix saving database periodically for gobject introspection and a patch from leftmostcat commit 16a4f1c5691f20141fba2ecf363b66945012defb Author: Seán de Búrca Date: Wed Sep 4 23:41:15 2013 -0600 Allow tables to specify a symbol for display commit cca58cc8ab2e6bff3081454b6028bb6c0ac798bf Author: Mike FABIAN Date: Tue Feb 18 20:15:13 2014 +0100 Fix the commit “Save user database periodically to avoid data loss” to use gobject introspection This fixes the following commit to use gobject introspection: commit 5d88bb3fef806f4feaef239e4fd78970e19d115a Author: mozbugbox Date: Sun Oct 28 19:32:22 2012 +0800 Save user database periodically to avoid data loss Periodically sync mudb content to usrdb so we don't loss user created phrase and freq when crash. Currently the interval is set to 16 input ops or 30 seconds between saving. commit fc6ce511c7eb483e8bee8e9cf5bb2b8f9e3881f8 Merge: f68e73c c888c5d Author: Caius 'kaio' Chance Date: Tue Feb 4 22:46:44 2014 -0800 Merge pull request #26 from mike-fabian/update-german-translations Update german translations commit c888c5d68d0fc03b9306520bec1528b168da0740 Author: Mike FABIAN Date: Mon Feb 3 11:14:27 2014 +0100 Update German translations commit 0ac3e535dd41db916ceebe73ef84b4e6fb7b98b6 Author: Mike FABIAN Date: Wed Feb 5 05:42:16 2014 +0100 Remove print statements for debugging I forgot to remove them in commit 7919d0326f1516164ea94b69137c88625b767f88 Author: Mike FABIAN Date: Tue Feb 4 15:52:45 2014 +0100 Make the property “Display Candidates/Hide Candidates” actually work commit f68e73c982dba42a984cd5cb7c497efb458b1b14 Merge: 9404fa6 0632dc9 Author: Caius 'kaio' Chance Date: Tue Feb 4 15:20:32 2014 -0800 Merge pull request #20 from mozbugbox/ascii-with-empty-canadidate Ascii with empty canadidate commit a4144337912c6e9fce1e321b2b0d1b94db89d689 Merge: c01120b 20913ab Author: Caius 'kaio' Chance Date: Tue Feb 4 15:18:38 2014 -0800 Merge pull request #21 from leftmostcat/master Allow tables to specify a symbol for display commit 9404fa6a9729d1b89524f7454bb7b6f4a3c43586 Merge: fe11a0c c5a60f6 Author: Caius 'kaio' Chance Date: Tue Feb 4 15:16:32 2014 -0800 Merge pull request #25 from mike-fabian/add-check-for-input-purpose-for-passwords Add check for input purpose for gnome-shell password dialog commit fe11a0c32124618a35f21bcc5d31c7c54d9b6477 Merge: 1d2f442 7919d03 Author: Caius 'kaio' Chance Date: Tue Feb 4 14:55:23 2014 -0800 Merge pull request #24 from mike-fabian/make-hide-candidates-work Make the property “Display Candidates/Hide Candidates” actually work commit 1d2f442be9754759339bdde90b6d492f67012bf5 Merge: d782b07 076bb39 Author: Caius 'kaio' Chance Date: Tue Feb 4 14:55:03 2014 -0800 Merge pull request #23 from mike-fabian/print-usage-message-when-tabcreate-is-called-without-options Print usage message when tabcreate is called without options commit c5a60f60578f681059e821f476e8e9f61102718d Author: Mike FABIAN Date: Tue Feb 4 16:20:11 2014 +0100 Add check for input purpose for gnome-shell password dialog Resolves: rhbz#1061345 - ibus-table shows entered text in password fields (See: https://bugzilla.redhat.com/show_bug.cgi?id=1061345) commit 7919d0326f1516164ea94b69137c88625b767f88 Author: Mike FABIAN Date: Tue Feb 4 15:52:45 2014 +0100 Make the property “Display Candidates/Hide Candidates” actually work - There is no set_candidates_list_visible() in ibus 1.5.5. use hide_lookup_table() instead to hide the candidates if requested - also hide the auxiliary text if hiding of the candidates is requested - make changing of that property by changing the gconf key work (name == u'AlwaysShowLookup' won’t work it needs to be all lower case) - There was a typo here: “self._new_property(u'always_show_loopup')” (“lookup”, not “loopup”) - The property menus show the current state, not the state which will be switched to when the menu entry is pressed. For example, one property says “Half-width punctuation” when half-width punctuation is in use, clicking it switches to full-width punctuation and then the menu displays “Full-width punctuation”. The property menu for displaying and hiding candidates did that reversed. Make it behave like the other property menus do. commit 076bb390705d2b8477323236dd997032fdb48db5 Author: Mike FABIAN Date: Thu Jan 23 23:26:57 2014 +0100 When tabcreatedb.py is called without any options, print a usage message Do not just show a cryptic backtrace. Resolves: rhbz#1049760 See: https://bugzilla.redhat.com/show_bug.cgi?id=1049760 commit d67c3f032fe4fa493de334bf1b5d4907293409e9 Author: Mike FABIAN Date: Wed Jan 22 12:11:18 2014 +0100 Fix typo in ibus-table-createdb man-page "for for" -> "for" commit 20913ab847d393dfbce07fcac8b5538a5b351605 Author: Seán de Búrca Date: Wed Sep 4 23:41:15 2013 -0600 Allow tables to specify a symbol for display commit 0632dc94931f73cffa99b3163c2cf7b15e48111a Author: mozbugbox Date: Sat May 18 20:21:34 2013 +0800 Remove accidentally added engine/* files Somehow, the engine directory was added. clean it up. commit 2413853c1a2ffc708250d2548cafe95792b22678 Author: mozbugbox Date: Sat May 18 20:04:03 2013 +0800 remove vim backup files commit 05a065b34970cdeb71c2e3f80312e6d0be967b19 Author: mozbugbox Date: Sat May 18 19:56:41 2013 +0800 Update setup to dconf with lower case options commit acd03a472215d43dc17bed4a2b9dbe29f7aa5817 Merge: 4d18a67 d782b07 Author: mozbugbox Date: Sat May 18 17:55:30 2013 +0800 Merge remote-tracking branch 'kaio/1.7' into ascii-with-empty-canadidate Conflicts: engine/table.py commit 4d18a67d8b0bc0fbe0999f330769707611d11eea Merge: cd11209 2467638 Author: mozbugbox Date: Sat May 18 17:46:20 2013 +0800 Merge remote-tracking branch 'kaio/1.7' into ascii-with-empty-canadidate Conflicts: engine/main.py engine/table.py commit d782b07861c40b22aafa81aa779f4eb76ed08fce Author: Caius 'kaio' Chance Date: Mon May 6 22:21:01 2013 +1000 Indent 4 spaces on README to support MarkDown on wiki page. commit 6f0702c742cd8ef30f375a3db28552b6e9bb9338 Author: Caius 'kaio' Chance Date: Mon May 6 21:43:08 2013 +1000 Removed unused commented-out code. commit ba990fe42d0ebab241f35a1f4f7cd1e1a911cc3f Author: Caius 'kaio' Chance Date: Mon May 6 21:37:15 2013 +1000 Clear all input when "focus-out" (switch to another window/input-fields, etc). commit cb6e11a222f44e985e0632f81c4b2622e25d215a Author: Caius 'kaio' Chance Date: Mon May 6 21:17:06 2013 +1000 Fixed mis-refactor of cursor_up as cursor_down in editor class. commit fb11d92439fe4bd55fcad480d3998a17434f6870 Author: Caius 'kaio' Chance Date: Mon May 6 21:05:35 2013 +1000 Issue #17: Removed excessive instance creation of IBusLookupTable in editor class. Removed commit 24676389e9f218b7972283493096acd3e1a13f8e Merge: 763f181 d246000 Author: Caius 'kaio' Chance Date: Sun May 5 21:14:19 2013 +1000 Merge branch 'rename_editor_func_from_key_combo_to_behavioral_naming_base' into 1.7 commit d246000eb6686316026572fb65888ad29337dcf4 Author: Caius 'kaio' Chance Date: Sun May 5 20:48:31 2013 +1000 Renamed funcs in editor class from keyboard-input based to behavior based. commit 763f181149dff0b84dc0dde0bb334903e40c0b8b Merge: 79fa67e d70d66f Author: Caius 'kaio' Chance Date: Thu May 2 14:41:26 2013 +1000 Issue #14: Merge branch 'refactor_convert_to_full_width' into 1.7 commit d70d66f25f8a4e9be1bfd6558dfde11a40bf4202 Author: Caius 'kaio' Chance Date: Thu May 2 14:35:21 2013 +1000 Added back unicode string spec to condition check in _convert_to_full_width (self, c). commit 2554d6091f413975dd4886b89c5d57776603f955 Author: Caius 'kaio' Chance Date: Thu May 2 14:26:02 2013 +1000 WIP: Removed excessive condition check. commit 24091c51a67e8b134b7db3dbe613990fdc44ab6f Author: Caius 'kaio' Chance Date: Thu May 2 14:21:23 2013 +1000 WIP: Combined two dicts into single dict. Simplified the condition checks. commit f748d5e51ad4b2c68c5d883b4819860389458c85 Author: Caius 'kaio' Chance Date: Thu May 2 11:15:16 2013 +1000 WIP: Extracted more condition checks to dict. commit 7e826b7d4e7b30bdbcfe867be2ca744e22380142 Author: Caius 'kaio' Chance Date: Thu May 2 10:22:12 2013 +1000 WIP: Jump right to later half of conditions when _mode isn't true. commit a2e6215d1fcf07aba6f03bc4b88bffee1a785884 Author: Caius 'kaio' Chance Date: Thu May 2 09:40:05 2013 +1000 WIP: Removed excessive condition check on char eligiblity. commit 79fa67e529dff3562580f16c5138ff4c54309eb7 Author: Caius 'kaio' Chance Date: Wed May 1 21:31:46 2013 +1000 Extract repeating code from _init_properties(self) to _new_property(self,key). commit c01120bb6856445327270b2e53ca36099196a326 Merge: 9745b53 a42c1d3 Author: Caius 'kaio' Chance Date: Mon Apr 29 20:26:36 2013 +1000 Merge remote-tracking branch 'bernardn/master' into 1.6 Conflicts: engine/table.py commit 9745b5384c3328cd7db994baab7301f6367b5ee4 Merge: 764a8c7 757a88e Author: Caius 'kaio' Chance Date: Sun Apr 28 22:05:24 2013 +1000 Merge remote-tracking branch 'origin/master' into 1.6 commit 757a88e4eee512e478c6692f39b8e346a95aba5a Merge: 7a3f0d9 04e3be2 Author: Caius 'kaio' Chance Date: Sun Apr 28 05:04:07 2013 -0700 Merge pull request #7 from luolimao/master Explicit python2 for compatibility commit 764a8c7251a9078bda22c544796c77b81ec2d581 Merge: 68f25cb 367c146 Author: Caius 'kaio' Chance Date: Sun Apr 28 21:25:56 2013 +1000 Merge remote-tracking branch 'anthonywong/master' into 1.6 commit 68f25cb5c82dc87bd18b84afc9146435c9490944 Merge: b7da6e8 02ddfba Author: Caius 'kaio' Chance Date: Sun Apr 28 21:12:43 2013 +1000 Merge remote-tracking branch 'mozbugbox/tooltip-show-hotkey' into 1.6 Conflicts: engine/table.py commit b7da6e8a66a455fc0ed9270fe1f2c0638c1b1211 Author: Anthony Wong Date: Tue Dec 4 00:39:06 2012 +0800 Catch exception when reading ~/.ibus/byo-tables so the process won't halt. Conflicts: engine/main.py commit 5f274590b27068cc3dca08899a8831aa38f647e6 Merge: e32bda3 f5e8e37 Author: Caius 'kaio' Chance Date: Sun Apr 28 20:36:52 2013 +1000 Merge remote-tracking branch 'bernardn/auto_select_two_candidates_inputs' into 1.6 commit e32bda3276868d140d74a9f4291b4bb475a2215d Merge: ea2795b 5d34900 Author: Caius 'kaio' Chance Date: Thu Apr 25 21:51:36 2013 +1000 Merge remote-tracking branch 'bernardn/candidates_list_visible' into 1.6 Conflicts: engine/table.py commit ea2795bdcd5ab6d67e865f3e5fc715096d59d0a6 Merge: c029e9f 99b16e2 Author: Caius 'kaio' Chance Date: Fri Apr 19 02:03:58 2013 -0700 Merge pull request #12 from mike-fabian/add-man-page-and-apply-autoselect-dconf-value-immediately Add man page and apply autoselect dconf value immediately commit 99b16e2159ba4234f4f804fe10348c9f3b2a8000 Author: Mike FABIAN Date: Thu Apr 18 12:10:50 2013 +0200 Add man page for ibus-table-createdb See https://bugzilla.redhat.com/show_bug.cgi?id=948454 commit 5d34900e60b4abd582b69feb3d843fe2e4cee695 Author: Bernard Nauwelaerts Date: Mon Mar 25 17:10:47 2013 +0100 Add always_show_lookup property commit f5e8e371d6738385e7a97b0f62994947c116a137 Author: Bernard Nauwelaerts Date: Mon Mar 25 12:22:51 2013 +0100 auto_select : commit when enter key pressed. commit ef81ce4ec029f3b03bda347e0e469d94d101937e Author: Bernard Nauwelaerts Date: Mon Mar 25 11:24:47 2013 +0100 auto_select : commit when tab key pressed. commit 3b78b86df6171ac4add0c4df7d7ae5eeb18a7e91 Author: Bernard Nauwelaerts Date: Mon Mar 25 11:23:51 2013 +0100 auto_select : commit previous entry when the last one has also candidates. commit c2fbde2fc7dcb0b2b09c8300ae079240ec790266 Author: Mike FABIAN Date: Tue Mar 5 07:37:43 2013 +0100 Apply change in autoselect dconf value immediately Changing the other dconf values was applied immediately but this did not yet work for the “autoselect” option, recently added by Bernard Nauwelaerts. commit 458420dda7e4a353b4d912641d12bda1731f01f0 Author: Mike FABIAN Date: Tue Mar 5 06:44:55 2013 +0100 Fix typos in comment commit c029e9f132a044265b92822e01e95df6165b9cd5 Merge: d31c8d9 9497457 Author: Caius 'kaio' Chance Date: Sun Feb 17 01:26:48 2013 -0800 Merge pull request #10 from mike-fabian/mike-collected-changes-on-kaio-1.6-branch Mike collected changes on kaio 1.6 branch commit 949745757b8028c40c30d9fb8f230536faacb98b Author: Mike FABIAN Date: Mon Feb 4 19:33:59 2013 +0100 Support uppercase umlauts Needed for translit.txt and translit-ua.txt. This should be solved in a better, more generic way. But at the moment this patch is better than nothing. commit 9eb482d08c541ed042a3946be8c9a4a343b532b4 Author: Mike FABIAN Date: Thu Jan 10 11:37:59 2013 +0100 Changes in dconf values now get applied immediately Changing values of dconf keys for example with dconf write /desktop/ibus/engine/table/cangjie3/chinesemode 3 was not applied immediately to the ibus-table engine, only when changing to a different input method and back this change was applied. This commit fixes this problem. commit 3b7a3530c42766b801cded26b3bc269222c3fb0a Author: Mike FABIAN Date: Thu Feb 14 18:21:57 2013 +0100 Preedit needs to be updated on page-up and page-down When paging through the lookup table, the preedit needs to be updated to show the phrase selected by the cursor in the lookup table. Before this patch, the preedit was not updated and when commiting the character selected in the lookup table suddenly replaced the character in the preedit. This differed from the behaviour when moving through the lookup table with the arrow-up and arrow-down keys. Using page-up and page-down or the arrow icons at the bottom of the lookup table should also update the preedit just like it is done when the arrow-up and arrow-down keys are used. commit a42c1d351e3b1264186f99e5d0febc784063ffb9 Author: Bernard Nauwelaerts Date: Thu Feb 7 10:30:23 2013 +0100 Defaults _auto_select to False for tables that doesnt contain this attribute commit 3d03bd8f8c558392db42897370cef65bdbad57bd Author: Mike FABIAN Date: Tue Feb 5 09:11:17 2013 +0100 Fall back to auto_select = False if neither dconf nor the table have a value for auto_select commit 2baa9c3ff258c0623b4777f2c537467339cdcef6 Author: Bernard Nauwelaerts Date: Sat Feb 2 17:22:40 2013 +0100 Update cmode pproperty in chinese mode only commit a55783887e757f02078143c2d12031a33c9e9223 Author: Bernard Nauwelaerts Date: Sat Feb 2 13:03:48 2013 +0100 Add auto_select functionality to select the first phrase when typing. Useful for Cyrillic transliteration. commit a85b8b90c21cafc13079c17b35cf021dbf0a6475 Author: Bernard Nauwelaerts Date: Sat Feb 2 17:22:40 2013 +0100 Update cmode pproperty in chinese mode only commit f0f4ee216788fd901c3ef91c90f9ce4bede88862 Author: Bernard Nauwelaerts Date: Sat Feb 2 13:03:48 2013 +0100 Add auto_select functionality to select the first phrase when typing. Useful for Cyrillic transliteration. commit 03cba776da99b05218c2b1c86f3e93d3373f253e Author: Mike FABIAN Date: Wed Jan 30 07:41:54 2013 +0100 Fix typo, thanks to Mathieu Bridon commit 5b434df882093a3def36585582c84950ce7e3b52 Author: Mike FABIAN Date: Mon Jan 28 15:15:10 2013 +0100 add engine/chinese_variants.py to engine/Makefile.am Needed by commit f17e9b3aecea7b6646da689a466341936bce1ee3 Author: Mike FABIAN Date: Thu Jan 24 17:37:27 2013 +0100 Improve detection of simplified and traditional Chinese commit 04e3be2bb27cf4e088e7c41f01356f10b29660ce Author: Limao Luo Date: Sun Jan 27 12:19:41 2013 -0500 explicitly call python2 in shebang line for more portability commit f17e9b3aecea7b6646da689a466341936bce1ee3 Author: Mike FABIAN Date: Thu Jan 24 17:37:27 2013 +0100 Improve detection of simplified and traditional Chinese Resolves: #857967 https://bugzilla.redhat.com/show_bug.cgi?id=857967 see also http://code.google.com/p/ibus/issues/detail?id=1492 “unable to write 晞 with any of the two Wubi input methods” 晞 (wubi code = JQDH) cannot be written. - add a script generate-chinese-variants.py which parses Unihan_Variants.txt from the Unihan database and generates another Python script. The generated Python script contains a hash table with information which characters are simplified, which characters are traditional and which characters are both and a small function using that hash table to detect whether a string is traditional or simplified Chinese or both. - use the generated script and function in tabsqlitedb.py instead of the old way to distinguish between simplified and tradtional Chinese which used test encoding to legacy encodings like gb2312 and big5hkscs. The new way of simplified/traditional detection should give better results. 晞 from issue 1492 is now classified as both traditional and simplified Chinese, not only traditional as it was with the old detection code. commit 1c316e066f88f9555de5407f00b4be0b076fd42c Author: Mike FABIAN Date: Thu Jan 24 12:47:19 2013 +0100 Make comments about _chinese_mode clearer There was one obvious typo and the comments did not explain the meaning of _chinese_mode clearly. commit d31c8d94eb05a33c9eaf6c79b24cdb0b289bba76 Author: Caius 'kaio' Chance Date: Wed Jan 16 07:54:56 2013 +1000 Fixed release flag check for if timestamp is suffixed. commit 7a3f0d9d75fd36575a5e581830c4a57b07b2e7ad Author: Caius 'kaio' Chance Date: Wed Jan 16 07:45:35 2013 +1000 Update author list. commit e663a176bf797cc523be7541e0dc7318eef7466e Merge: dca5eda 0b8bec0 Author: Caius 'kaio' Chance Date: Wed Jan 9 14:44:25 2013 -0800 Merge pull request #4 from mike-fabian/mike-fix-typo-in-chinese-mode-variable Mike fix typo in chinese mode variable commit dca5edae81cc70d82099e9ccdca38052523196f9 Merge: ea29e27 5ecc6d9 Author: Caius 'kaio' Chance Date: Wed Jan 9 14:42:31 2013 -0800 Merge pull request #3 from mike-fabian/mike-make-cursor-in-lookup-table-visible Make cursor in lookup table always visible commit 0b8bec02a2f510e91f1ecd4febd67fe0132e4414 Author: Mike FABIAN Date: Wed Jan 9 16:59:13 2013 +0100 When detecting the Chinese mode from the environment, also check LC_ALL LC_ALL has even higher priority then LC_CTYPE and should be checked first. commit 9e963b5c813090ca389f78740e60965104944d93 Author: Mike FABIAN Date: Wed Jan 9 16:53:20 2013 +0100 Fix typo in self._chinese_mode variable When porting to GObjectIntrospection, I made a typing mistake in the self._chinese_mode variable. This caused a problem when the dconf key for “chinesemode” was not yet set. Then the property for selecting the Chinese mode in the ibus menu was empty and and selecting the empty line with the mouse just caused an error. This commit fixes this. commit 5ecc6d941cbce800c96438c8c57bb8dc6fcf4525 Author: Mike FABIAN Date: Tue Jan 8 17:53:09 2013 +0100 Make cursor in lookup table always visible The cursor in the lookup table was always visible before porting to GObjectIntrospection. So it should behave the same way after porting. commit ea29e278c90b55f910e656f1b192df288e59d563 Merge: b899a0a 526b8cf Author: Caius 'kaio' Chance Date: Tue Jan 8 00:04:24 2013 -0800 Merge pull request #2 from mike-fabian/mike-porting Finished Xiaojun Ma’s work of porting to Gobject Introspection. commit 526b8cf4e395dd8c6333b3ed4185596b1196fad8 Author: Mike FABIAN Date: Mon Jan 7 01:49:09 2013 +0100 finish porting to gi commit 6d78cab7069d7873b90391a75aa5d2d15220913a Author: Mike FABIAN Date: Mon Jan 7 01:50:14 2013 +0100 add *.pyc to .gitignore commit ca049a01f21852586e5ebf894513a6e7a0539ba2 Author: Xiaojun Ma Date: Tue Nov 20 23:33:11 2012 -0600 start porting to gi commit b899a0a33f015606b43ee2b63eb999dadfbb3a0e Merge: 52ec65d 12abcdb Author: Caius 'kaio' Chance Date: Thu Jan 3 17:06:11 2013 +1000 Merge remote-tracking branch 'mike-fabian/some-fixes-for-rel20121101' into 1.5.0 commit 367c14657c203528dac72c085b10129c4a03f9f4 Author: Anthony Wong Date: Tue Dec 4 00:39:06 2012 +0800 Catch exception when reading ~/.ibus/byo-tables so the process won't halt. commit 52ec65d94b69f8f4e06325a7cb18f0d8ed4f707a Author: Caius 'kaio' Chance Date: Fri Nov 30 17:48:03 2012 +1000 Patch for regression of select_keys option on table sources. (bochecha) commit cd1120969f4a5cb1269f69b349f89b3b1c434e59 Author: mozbugbox Date: Wed Nov 21 01:04:13 2012 +0800 Direct input ascii char for English mode on empty Do the same input untranslated ascii directly when panel is empty for the English mode. commit 7a7c6fe600a917b989c514c1014047bf7c35e34f Author: mozbugbox Date: Tue Nov 20 23:53:15 2012 +0800 Input untranslated ascii directly when panel is empty Some applications only accept directly input ascii as command input. Character fed through xim commit will not work as intent. When there were no candidates, we treated all the un-translated (b/w half/full width) ascii chars as direct input chars. commit 5c5a2415680af7dee99e9bbce84872ba570ee1a4 Merge: b40c6f3 aadfdb0 Author: mozbugbox Date: Sun Nov 18 23:44:41 2012 +0800 Merge remote-tracking branch 'kaio/ibus-setup-table-639' into save-user-db Conflicts: engine/main.py commit b40c6f3c595498e55222ca126c2e808cabe145ee Merge: d5b9f9c d1b8d13 Author: mozbugbox Date: Sun Nov 18 21:44:22 2012 +0800 Merge remote-tracking branch 'kaio/1.5.0' into save-user-db Conflicts: engine/main.py commit 12abcdbdc55aa1f25fcbe725ce70765b8519674e Author: Mike FABIAN Date: Tue Nov 13 10:24:13 2012 +0100 Do not fail if the ~/.ibus/byo-tables/ directory does not exist “/usr/libexec/ibus-engine-table --xml” aborted with an error if ~/.ibus/byo-tables did not exist. commit 325158739a399c1137d48562bcee1550bd96953f Author: Mike FABIAN Date: Tue Nov 13 09:02:38 2012 +0100 Add some generated files to .gitignore commit 7fa914591d2f5be7b93100f7d5ef3798b1a41399 Author: Mike FABIAN Date: Tue Nov 13 08:34:54 2012 +0100 Add German translation commit 8099bc679dfb78f874d77a4188e34d572edae3b6 Author: Mike FABIAN Date: Tue Nov 13 08:32:24 2012 +0100 update zh_??.po files commit ab19e1a63f73040bd7f423923b0e886d8c87bd54 Author: Mike FABIAN Date: Tue Nov 13 07:59:07 2012 +0100 Fix marking of translatable strings for gettext was broken in: commit 6d2ab577c41c9b07a84c049137c8184bb67f5e30 Author: Caius 'kaio' Chance Date: Fri Oct 5 10:40:47 2012 +1000 Refactor _refresh_properties() function. commit d1b8d136a4371c77b377f9c4276c7783dc69df52 Merge: af0eb0a 37802fc Author: Caius 'kaio' Chance Date: Mon Nov 12 02:51:06 2012 +1000 Merge remote-tracking branch 'mozbugbox/tools' into rel201212 commit af0eb0a549a803d9bbfa297251bea2f3cf8ee440 Author: mozbugbox Date: Thu Nov 1 21:03:16 2012 +0800 Left ALT key to cycle candidates in the current page commit aadfdb095e313cc2446c1feb99f51cdaae40468d Merge: 56036a6 001ee4a Author: Caius 'kaio' Chance Date: Mon Nov 12 01:55:55 2012 +1000 Merge branch 'master' into ibus-setup-table-639 Conflicts: engine/main.py commit 001ee4acf2dc01e3b8291dbdb110bce005e4d0e8 Author: Caius 'kaio' Chance Date: Mon Nov 12 01:00:34 2012 +1000 Corrected release checking in configure.ac. commit d5b9f9caeb6cd5b0686590070d73ea8ac660b24b Author: mozbugbox Date: Thu Nov 1 12:22:16 2012 +0800 Sync user db on engine destroy commit b3e9a57f3dd8ac291adf3478a81ae8181e958e24 Author: mozbugbox Date: Sun Oct 28 23:30:54 2012 +0800 Avoid flashing by moving combobox renderer creation to front commit f78dffa470607b1137c629bac3f6ba01061acb47 Author: mozbugbox Date: Sun Oct 28 19:36:16 2012 +0800 Update debian/ content commit 5d88bb3fef806f4feaef239e4fd78970e19d115a Author: mozbugbox Date: Sun Oct 28 19:32:22 2012 +0800 Save user database periodically to avoid data loss Periodically sync mudb content to usrdb so we don't loss user created phrase and freq when crash. Currently the interval is set to 16 input ops or 30 seconds between saving. commit 06ea923b4dc989e7e18f14718a634c5712141207 Author: mozbugbox Date: Sun Oct 28 19:29:43 2012 +0800 Speedup sync_usrdb() * Remove unneeded commits * Clear in-memory mudb content once synced * return immediately if user_db is None (which means use in-memory db) commit 37802fc37ad8f559ffa16bcb4c59f3afa4f1e2a4 Author: mozbugbox Date: Sat Oct 20 15:38:37 2012 +0800 Skip None entries when print keyboard value. commit c642db82e2588a6b913a090c2b7ed0ed1cd220c4 Author: mozbugbox Date: Sat Oct 13 15:23:09 2012 +0800 Add a tool to dump ibus table database ibus-table-query is a handy tool to see what's in the phrase table database. $ ./ibus-table-query -t wubi-haifeng86 aeq Using table: /usr/share/ibus-table/tables/wubi-haifeng86.db mlen clen m0 m1 m2 m3 category user_freq freq phrase ================================================================== 4 2 a|1 e|5 q|17 d|4 3 0 2292000 菜肴 4 2 a|1 e|5 q|17 c|3 3 0 552200 菜色 4 2 a|1 e|5 q|17 n|14 1 0 1266000 菜馆 4 2 a|1 e|5 q|17 y|25 3 0 6350000 菜鸟 4 1 a|1 e|5 q|17 k|11 2 0 1000 葋[U+844B] $ ./ibus-table-query -t wubi-haifeng86 菜 Using table: /usr/share/ibus-table/tables/wubi-haifeng86.db mlen clen m0 m1 m2 m3 category user_freq freq phrase ================================================================== 2 1 a|1 e|5 3 0 1132 菜[U+83DC] 3 1 a|1 e|5 s|19 3 0 1132 菜[U+83DC] 4 1 a|1 e|5 s|19 u|21 3 0 1132 菜[U+83DC] commit bf91ed7464043b26fb9dbf4e33be220cb8dd09eb Merge: d4e9471 b60898c Author: Caius 'kaio' Chance Date: Fri Oct 12 07:56:49 2012 +1000 Merge branch 'byo-table-db-614' into rel20121101 commit b60898c58d4195cbfbd46f2de7b9adac9fb6cbc5 Author: Caius 'kaio' Chance Date: Fri Oct 12 07:54:18 2012 +1000 Improved naming of variables related to user provided (BYO) tables. commit cf17aa8d474f0f11141c9cf1a93bf2c1ca3cb1ae Author: Caius 'kaio' Chance Date: Fri Oct 12 00:08:06 2012 +1000 (WIP) Add database load in factory when it is not located in system table path, but in user's home directory. Path checking is still a dirty hack but worked at this stage. Need some tidy-up. commit 56036a6a755d133a65f56f08494b04de82ce73f2 Merge: d4e9471 7689c95 Author: Caius 'kaio' Chance Date: Thu Oct 11 22:07:40 2012 +1000 Merge remote-tracking branch 'mozbugbox/ibus-setup-table' into ibus-setup-table commit 7689c958238c18c86972cc7964d4cf7d26a29e51 Author: mozbugbox Date: Thu Oct 11 16:25:53 2012 +0800 Setup: Add table information to About page commit e05c13fecc7957433066e34027864f7fc6db66e7 Author: mozbugbox Date: Thu Oct 11 15:35:30 2012 +0800 Add an ibus-table-setup to set ibus table engine The setup app can be accessed from: ibus Preferences -> Input Method -> select a method -> Preferences The code and ui were adapted from * ibus-setup-pinyin * https://github.com/maxiaojun/ibus-table-setup commit d4e9471570481dd22a9a28e1473813ed4cf57582 Merge: e24b74a 87e2bf7 Author: Caius 'kaio' Chance Date: Thu Oct 11 10:29:14 2012 +1000 Merge branch 'space-key-for-lookup-next-page-861' into rel20121101 commit 87e2bf7288aae20a46cc76939a110b511fd60b79 Author: Caius 'kaio' Chance Date: Thu Oct 11 10:24:31 2012 +1000 Recognize space key as page_down/next-page, if a table specified it as one of the page_down_keys. commit e24b74a7243a946dff4639d9c686ac72d57e114e Merge: 7419897 eadb7bf Author: Caius 'kaio' Chance Date: Wed Oct 10 13:25:13 2012 +1000 Merge branch 'page-size-from-table' into rel20121101 commit eadb7bf9a833978a152d3537a73223ec45701025 Author: Caius 'kaio' Chance Date: Wed Oct 10 13:23:37 2012 +1000 Add fallback of lookup page size, determined by number of candidate select keys. commit 741989758a9f858897586158db18893a2bc0bab9 Author: mozbugbox Date: Tue Oct 9 00:11:45 2012 +0800 Add a "." to candidate label text commit 2ad241d7a32357b4783217be3035eb2597c30611 Author: mozbugbox Date: Mon Oct 8 17:26:24 2012 +0800 Make select_keys actually functional Tables can actually use the SELECT_KEYS setting to make select keys non-integer. Useful for Four Corner Input like IM. commit 02ddfba26e47bdffc5a6a22d299d06d49d7bc1ea Author: mozbugbox Date: Sun Oct 7 17:12:14 2012 +0800 Add button hotkey info to the input panel tooltip text commit 1c3d1d6be632539cbe05e5f7a51a907f4706285b Merge: 4f9689c b9cec4c Author: Caius 'kaio' Chance Date: Sun Oct 7 18:20:08 2012 +1000 Merge branch 'lookup-orient-from-table-1475' into rel20121101 commit b9cec4cef0d1ebf72a6922fd3c3a29315c0fd4eb Author: Caius 'kaio' Chance Date: Sun Oct 7 18:17:34 2012 +1000 Get default lookup orientation per table from table sources. commit 56bd4621e5f8713f790e5de0ed7b7740113bee1d Author: Caius 'kaio' Chance Date: Sat Oct 6 22:48:49 2012 +1000 WIP to get table .db files in user home directory. Path in factory.py also needs changes. commit 4f9689c395b78b22ae391d2e786f53670893bb20 Merge: 1925a75 97cee5a Author: Caius 'kaio' Chance Date: Sat Oct 6 18:16:29 2012 +1000 Merge branch 'page-size-from-table' into rel20121101 commit 1925a759c148147d508fb483a2b475cc2b3e931c Merge: 0d7670d 6d2ab57 Author: Caius 'kaio' Chance Date: Sat Oct 6 18:16:11 2012 +1000 Merge branch 'refactor-set-property' into rel20121101 commit 0d7670d32c86cd63a4f98beb05e095348607cb58 Author: Caius 'kaio' Chance Date: Sat Oct 6 18:15:11 2012 +1000 Update ChangeLog. commit 97cee5a8324ce2aca99f3465cc37a507bd8bbcf5 Author: Caius 'kaio' Chance Date: Sat Oct 6 17:35:09 2012 +1000 Add page_size property for the tables. commit 6d2ab577c41c9b07a84c049137c8184bb67f5e30 Author: Caius 'kaio' Chance Date: Fri Oct 5 10:40:47 2012 +1000 Refactor _refresh_properties() function. commit f118dba1b194a6adb6c4854da74d2fa297f077e7 Author: Caius 'kaio' Chance Date: Wed Oct 3 17:11:46 2012 +1000 Updated PO files. commit 3675a495799cfa68da825350e449c45f5ceeac68 Merge: f124c26 2cd1650 Author: Caius 'kaio' Chance Date: Wed Oct 3 17:01:32 2012 +1000 Merge remote-tracking branch 'mozbugbox/page-up-down-config' into rel20121001 commit 2cd1650663086e7a00f92a9eb7661c738351c39c Author: mozbugbox Date: Fri Sep 28 00:26:28 2012 +0800 Make page up/down keys configurable commit f124c2608e50796671ca518248dc68c716a7204d Author: mozbugbox Date: Thu Sep 27 22:45:30 2012 +0800 Fill input panel on demand. Huge GUI respond speedup Huge speedup on ibus-table GUI repsond time when using a large phrases table. Currently, all the candidate phrases are created in the input panel before shown to the users, while only 6 of the candidates actually show up on the panel. For a phrase table with a lot of phrases, the candidate list can contain more than 3000 entries, especially when only the 1st key is entried. 3000 candidates will cause 3000 input widgets being generated before the first 6 candidates were show to the users. This can make the GUI update lagging up to a few seconds depending on the speed of the CPU. This is at least O(n). In this optimzed code, only 6 candidate widgets were generated at a time. More candidate widgets will be generate on next-page/previous- page action. Now we are O(1) for the GUI part of panel update. commit 14d46a0f8cd9d565db3548166873548a0cff9f80 Author: mozbugbox Date: Thu Sep 27 22:41:25 2012 +0800 Remove unneeded sort in select_words(), speedup Since sql query statement already sorted (ORDER BY) the result, remove the unneeded sort operation. Sorting with a python compare function is terribly slow for large list. commit 2a9a21fc7da056dfd599145198f9d36b33171bd8 Merge: 4c358f7 9d8a722 Author: Caius 'kaio' Chance Date: Tue Sep 18 11:04:29 2012 +1000 Merge remote-tracking branch 'mike-fabian/acevery-master-fix-ipa-x-sampa-rhbz856903' into rel20121001 commit 4c358f755ddacf2117b91123490bad2fd85380cc Merge: e90dc05 c219fd9 Author: Caius 'kaio' Chance Date: Thu Sep 13 23:34:09 2012 +1000 Merge remote-tracking branch 'mike-fabian/acevery-master-improve-chinese-category-check-rhbz856320' into rel20121001 commit 9d8a7228fca7615b8a3b7f74f7bf8cfe7861fe8b Author: Mike FABIAN Date: Thu Sep 13 15:32:10 2012 +0200 Fix ipa-x-sampa table and phrases containing spaces in emoji-table Currently there is a regular expression which filters out several lines defining valid phrases. The emoji-table for example has phrases containing spaces which are currently filtered out and the ipa-x-sampa table has trailing comments which are filtered out as well. In phrase_parser, the phrases are parsed like: xingma, phrase, freq = unicode (l, "utf-8").strip ().split ('\t')[:3] Therefore, it seems reasonable to change the regular expression checking for a table line containing a phrase definition to accept every line which has 3 columns seperated by tabs followed optionally by more columns also separated by tabs (the optional columns are ignored, i.e. they are just comments in the table source). See: https://bugzilla.redhat.com/show_bug.cgi?id=856903 commit c219fd9aed3c24dc6405ef88991ef178caf29f91 Author: Mike FABIAN Date: Thu Sep 13 12:43:55 2012 +0200 Improve check whether a phrase is simplified or traditional Chinese The improvement is to ignore all non-Han characters when doing the check. This is to avoid classifying a simplified Chinese string as traditional just because it happens to include some non-Chinese characters, for example box drawing characters, which cannot be converted to gb2312 but happen to be convertible to big5hkscs. This fixes the problem in the emoji-table input method that most phrases cannot be input at all. See: https://bugzilla.redhat.com/show_bug.cgi?id=856320 commit e90dc055de4e5ecda91ae03144be9731c8376989 Merge: ce79966 84c287f Author: Caius 'kaio' Chance Date: Thu Sep 6 08:28:32 2012 +1000 Merge remote-tracking branch 'acevery/master' into rel20121001 Conflicts: engine/table.py commit 84c287f1a7e261c32e7b4a18d7f488ae3d78da75 Author: 余钰炜 Date: Wed Sep 5 20:46:09 2012 +0800 exclude control characters from input range commit edd01646dca3599f1e9a838b9ab9813e1477bd3d Author: 余钰炜 Date: Wed Sep 5 01:35:56 2012 +0800 remove repeat unichr; remove blank lines in table.py commit 50692ab9599c3845bc9f29cb0516ee78b6b0eda0 Author: 余钰炜 Date: Wed Sep 5 01:22:55 2012 +0800 fix non-ASCII input key bug commit ce7996600810421020c6904749213b73a7eb2dff Merge: d4c5fad 3ba23ba Author: Caius 'kaio' Chance Date: Tue Sep 4 22:35:46 2012 +1000 Merge commit '3ba23ba4667818c096639acb3920b50994263ef4' into rel20120901 Conflicts: tables/additional/latex.txt commit d4c5fad5ad5bd80ad34d8e96bd1d1d48dc21973d Author: Caius 'kaio' Chance Date: Tue Sep 4 21:58:01 2012 +1000 Updated version number and ChangeLog. Rebuilt PO files. commit 3ba23ba4667818c096639acb3920b50994263ef4 Author: Xiaojun Ma Date: Sat Aug 11 15:00:27 2012 +0800 further remove 'additional' stuff commit 2b9fb58e532ea9ea51800e7e177fb9c30d0ccb8f Author: Xiaojun Ma Date: Sat Aug 11 14:38:08 2012 +0800 remove compose.db, latex.db; fix #1026 commit 1bc85cd6e72eb0e30cd413ad0f4dde65dd8fc73f Merge: 7a28618 e015065 Author: Xiaojun Ma Date: Sat Aug 11 13:16:04 2012 +0800 Merge branch 'master' of github.com:maxiaojun/ibus-table commit 7a28618143bf702ea52858df2d0a54b185e9c400 Author: Xiaojun Ma Date: Sat Aug 11 13:11:02 2012 +0800 respect language_filter property; a better way to fix #1188 commit e0150650b3fbbaf3d4b97a48d95620caa2342786 Author: Xiaojun Ma Date: Sat Aug 11 13:11:02 2012 +0800 respect language_filter project; a better way to fix #1188 commit 932abeea7511ae733d029f466260d3710a09b5e1 Author: Mathieu Bridon Date: Sat Aug 11 12:45:58 2012 +0800 trivial change commit cb0abbd63040dd37f78628d595905faabd55de7f Author: Mathieu Bridon Date: Sat Aug 11 12:45:17 2012 +0800 add language_filter property commit 6f90e9c27491f169138abde9c85350838d28104e Author: Xiaojun Ma Date: Sat Aug 11 11:42:28 2012 +0800 a better way to fix #1474 commit d752b0274768e6d593c32cefebecdc24e197dbf0 Merge: eaa6927 2c8d938 Author: Caius 'kaio' Chance Date: Thu Aug 9 17:04:33 2012 +1000 Merge remote-tracking branch 'fujiwarat/master' into rel20120901 commit eaa692761096f527c5ae7c663612cce0dbfb5b56 Merge: f3a8c98 13d3f16 Author: Caius 'kaio' Chance Date: Wed Aug 8 21:07:23 2012 +1000 Merge remote-tracking branch 'maxiaojun/master' into rel20120901 commit f3a8c98972877dee89ed51c1a0a067eb5c84b4a9 Merge: e31b470 277814c Author: Caius 'kaio' Chance Date: Tue Aug 7 23:32:23 2012 +1000 Merge branch 'menu-label' into rel20120901 Conflicts: engine/table.py commit 277814cac5d5dcd46bfb17574553a744f7a61e78 Author: Caius 'kaio' Chance Date: Tue Aug 7 21:41:20 2012 +1000 Add labels for property for self-descriptive, when menus are embedded in traybar. commit 13d3f16498efc3683d7392d5c0e2342a01f90d35 Author: Xiaojun Ma Date: Sun Jul 1 22:28:28 2012 +0800 trivial change commit 8506e81fde93c5136d63888f6408dc5a88e23b4c Author: Xiaojun Ma Date: Sun Jul 1 22:23:32 2012 +0800 add value-changed signal handler for config; prepare for #639 commit 225fe2f4477ab7798dbbb753de60a1f748646d47 Author: Xiaojun Ma Date: Sun Jul 1 11:11:49 2012 +0800 trivial change commit c3236d649a13329fdf8e5067a5421bfbb27be9d0 Author: Xiaojun Ma Date: Sun Jul 1 11:08:07 2012 +0800 add per table lookup table orientation; fix #1475 commit edf6fc4c80dc98869e5db692a3e5126996de1b58 Author: Xiaojun Ma Date: Sun Jul 1 10:41:09 2012 +0800 fix #704 commit e092b5b65393a6795361823a69959b6ab46c5eba Author: Xiaojun Ma Date: Wed Jun 27 23:18:16 2012 +0800 add per table chinese mode; fix #1188 commit d93a3ff13f69c431c851fe663138e143bfe953e7 Author: Xiaojun Ma Date: Wed Jun 27 23:01:02 2012 +0800 add per table page size; fix #1474 commit e31b4706825cbf1c1256c555323c4d87ec1610d8 Merge: e04a10b 0e89c17 Author: Caius 'kaio' Chance Date: Sat Mar 10 00:15:15 2012 +1000 Merge remote-tracking branch 'mvv/python-path-fix' into rel20120309 commit e04a10b15dff4b3322cbe752e99e761b372d2c5b Merge: 820ee65 418ea16 Author: Caius 'kaio' Chance Date: Sat Mar 10 00:14:42 2012 +1000 Merge remote-tracking branch 'mvv/coloncolon' into rel20120309 commit 820ee65a18e8f966372959bab88a542d084e0357 Merge: 6ac623b 5eef930 Author: Caius 'kaio' Chance Date: Fri Mar 9 23:48:09 2012 +1000 Merge remote-tracking branch 'seanf/master' into 2012-03-09 Conflicts: po/zh_CN.po po/zh_HK.po po/zh_TW.po commit 6ac623ba7b7a59b7032d1916ee53bd249801dd28 Author: Caius 'kaio' Chance Date: Fri Mar 9 19:06:05 2012 +1000 - Add direct input of Chinese bracket to mid-brackets and large-brackets. commit a44d50c6face110c7cd1252067eade3f8a9193e8 Author: 余钰炜 Date: Wed Mar 7 15:16:49 2012 +0800 add _mo into locale test commit d4df7ed4c361a30f9c5d505e9ffc8b5fc7c163a7 Author: 余钰炜 Date: Tue Mar 6 01:06:50 2012 +0800 modify locale detecting code commit 487d9b6825492498cfc1f49b66e243c2eb4c5bcf Author: 余钰炜 Date: Mon Mar 5 08:57:08 2012 +0800 enable en_HK user to use chinese mode commit 24596c02c86a0453c59485f8b0031279803f1581 Author: 余钰炜 Date: Sun Oct 2 11:53:53 2011 +0800 add some key for translit; fix #1318 commit 8b54742f9648366abe8690513289337a43254621 Author: 余钰炜 Date: Mon Aug 1 23:53:46 2011 +0800 add NOSYMBOL to be a null target phrase commit 5eef930473edc31588444762bbbda5273fc6feff Author: Sean Flanigan Date: Tue Jul 26 17:31:19 2011 +1000 modify English text for clarity commit 418ea16b60614657285d23e31b511c41185322f8 Author: Mikhail Vorozhtsov Date: Sat Jun 18 17:10:31 2011 +0700 Added \coloncolon to the LaTeX table. commit 0e89c1738bf7722e1bd39c00b9d7f8e9214a05c5 Author: Mikhail Vorozhtsov Date: Sat Jun 18 16:20:49 2011 +0700 Use Python executable found by autotools in scripts. commit 4a35882e82c8d879252e4518974feba60ba802c1 Author: 余钰炜 Date: Wed Apr 27 10:14:43 2011 +0800 update reg pattern in tabcreatedb.py to allow leading or trailing space in tab separated columns commit 2a1bb20de7fd3373d1c9bf1d7f5305a93d663cf9 Merge: 1850d89 8d6e9ff Author: 余钰炜 Date: Tue Apr 26 18:39:25 2011 -0700 Merged pull request #4 from sagara-/master. Bugfix for issue 787 commit 8d6e9ff11307d05d336f696ceffa02ffb0a9cb8b Author: Kevin Tardif Date: Tue Apr 26 17:50:20 2011 -0400 Added detection of invalid table names - detects NAME attributes in table specifications that violate GConf keyname restrictions - see issue 787 (http://code.google.com/p/ibus/issues/detail?id=787) for details commit 1850d891300ce777b474d782b347ea1b05b8a7cc Author: 余钰炜 Date: Fri Feb 18 08:50:57 2011 +0800 update latex.txt from Giuseppe Castagna (gc@pps.jussieu.fr) commit 1e3e9139378e751570e3046bc1bfa27e6517b70f Author: 余钰炜 Date: Thu Dec 30 23:51:35 2010 +0800 update README; fix pinyin mode under direct commit mode commit 932f8b25737ace30859abac8972adb381c7287ab Author: 余钰炜 Date: Tue Dec 7 10:20:02 2010 +0800 add goucima use non chinese character commit ea4397b69cc63572bdb8f42478bbe319bfab95d3 Author: 余钰炜 Date: Thu Nov 11 16:35:17 2010 +0800 fix remove before char bug commit 1c51b7bdcdcb59bdfaf7f050eeb84316b2551f0e Author: 余钰炜 Date: Sun Sep 12 23:12:20 2010 +0800 fix config saving bug in Cangjie commit c7de864861c1259409c97fe4d8d6634c46383cef Author: 余钰炜 Date: Mon Sep 6 18:12:34 2010 +0800 fix py_mode tabkey length bug commit 8790fc860ee043168c3995e78cd070e0ffee4f19 Author: 余钰炜 Date: Sun Sep 5 00:34:06 2010 +0800 fix py_mode update bug commit b95f174efe70dc39d9558a9fb13903b48753ba1a Author: 余钰炜 Date: Tue Aug 31 15:52:59 2010 +0800 little hack to allow ibus-table to import space in gvim commit f64cf33e2e40a6b78338cf3c6f6f8fde51c5d146 Author: 余钰炜 Date: Sun Jun 13 08:43:23 2010 +0800 comment out a debug print commit c42319f81d63f5e4bf6dedaf12e130bfd26f2b20 Author: 余钰炜 Date: Wed Apr 7 15:32:08 2010 +0800 fix typo in issue836, thanks fujiwarat commit 2c8d93828af175bf06a0b30dc1146547005f70f4 Author: fujiwarat Date: Tue Apr 6 13:03:14 2010 +0900 Fix self.db._is_chinese in table.py by issue 836 commit 57e985f1748d9376be2c4c77854fb273579d7058 Author: 余钰炜 Date: Mon Mar 29 23:29:45 2010 +0800 fix phrase rule parsing for p-11. see issuse 827 commit ac190e3990bb03f52091cdce8e98093e0c1fd135 Author: 余钰炜 Date: Fri Jan 8 15:41:01 2010 +0800 only extract first 3 element from table source commit c6a36522c5db68d67c90599d1a608663901aefab Author: 余钰炜 Date: Fri Nov 13 10:31:51 2009 +0800 remove speedmeter from am commit 26eb25fa9b7f8469ab9d1fc0f8b4e3330be48dc0 Author: 余钰炜 Date: Fri Nov 13 10:08:27 2009 +0800 remove speedmeter, which cause ibus hang; commit 170e0934de4e3e2a1a4b72f9bd4a3f7998c53554 Author: 余钰炜 Date: Mon Oct 19 09:27:20 2009 +0800 improve ibus-engine-table file commit ae527927f8d9895b026f87567084bb23b12a61ac Author: 余钰炜 Date: Mon Oct 19 07:43:55 2009 +0800 add START_CHARS to latex engine commit 8066019f30926c971361c4e9a78033daa761fb39 Author: 余钰炜 Date: Mon Oct 19 07:35:07 2009 +0800 fix typo in tabsqlite; fix broken behaivor in latex engine. commit d06720dd03032a66af791af5183827830a6ddb68 Author: 余钰炜 Date: Sun Oct 18 11:11:31 2009 +0800 fix pkelen type error which cause latex engine encounters error commit a57878713c8c8477cf2221c7c8cd9c868f6cf79b Author: 余钰炜 Date: Wed Oct 14 13:46:17 2009 +0800 fix issue 584, thanks Huang :) commit 96722e02aafcf096f71dacdbbb3e9970edc91626 Author: 余钰炜 Date: Wed Oct 14 13:28:20 2009 +0800 output when no db under tables dir commit 24852aba91f14006c924e70d7699cc941164908c Author: 余钰炜 Date: Sun Sep 27 15:24:08 2009 +0800 fix bug in tabsqlitedb, which stop ibus-table to start commit 9d64913a4c17ad368a10590f604406659cdc06ac Author: 余钰炜 Date: Sun Sep 27 15:10:22 2009 +0800 add least_commit_length to db, which allow "autocommit" feature in Compose IME commit 92524c12444354025690d30c0c7f861a7d883096 Author: 余钰炜 Date: Fri Sep 25 22:31:11 2009 +0800 add acknowledgement for Ye, Yuan commit 2ccb94af0e2c575c1b327a95854e70f359e78a88 Author: 余钰炜 Date: Fri Sep 25 22:26:23 2009 +0800 add some key use - and = back to compose.txt; change max_key_length to 3 in compose.txt commit b965e5204644c0aa310149fd7429a589f3caed0b Author: 余钰炜 Date: Fri Sep 25 22:04:27 2009 +0800 fix bug in tabcreate.py to allow = as input key; improve table.py to allow filter out =/- from page_down/up keys commit d0909f926112284db508e338aabbc0a82ce1f0ec Author: 袁野 Date: Fri Sep 25 16:45:13 2009 +0800 compose: add more characters Add more characters, most important a-z, A-Z and German letters. Also avoid using - and = in input keys, as they are default page chage hotkeys. Signed-off-by: 袁野 commit 05373eafe0f5a171222e52922b29dc3852d7508d Author: 余钰炜 Date: Sat Sep 12 22:37:06 2009 +0800 fix typo... commit d3739a81ddf14d2344053feff92afde2485a3f75 Author: 余钰炜 Date: Sat Sep 12 14:38:43 2009 +0800 Save user config to gconf module :) commit dc4bebd5c459226c2cde3c55cc723a0ec7b96e25 Author: 余钰炜 Date: Fri Aug 21 22:02:36 2009 +0800 allow use last code in phrase construction commit 0d5f89654244fa90cff877537b6dc127baffd9e7 Author: 余钰炜 Date: Thu Jul 30 20:05:42 2009 +0800 try to fix spec.in commit d64df85de06b3b2074b5f4926b93c076ba5a08c1 Author: 余钰炜 Date: Thu Jul 23 02:07:53 2009 +0800 fix a editor.commit_string bug commit 1fd5242306b954787a28d4ae2afeda392b835b6f Author: 余钰炜 Date: Fri Jul 17 02:43:01 2009 +0800 do not recreat index when load user_db commit 19d8c81b2bf70e6b57a2513e5f1cce476324863e Author: 余钰炜 Date: Thu Jul 9 22:43:36 2009 +0800 do syncing after normal return from MainLoop.run() commit 77da827f603e70b2d6c0578f460a490c665fafbf Author: 余钰炜 Date: Mon Jun 22 23:13:03 2009 +0800 add SIGINT handler for ibus exits sync commit 1522707acceec09a8f0bbf6fef0df4ff3b5b0b3a Author: 余钰炜 Date: Mon Jun 15 16:39:21 2009 +0800 update to ibus-1.2.0 commit a6679cd443365abf792895cd0f9ffc84acf5c784 Author: 余钰炜 Date: Mon Jun 15 00:57:44 2009 +0800 update process_key_events as ibus commit 7e41759b9ea37b7ede5da541d4599333de1182b7 Author: 余钰炜 Date: Mon Jun 15 00:41:51 2009 +0800 fall back for ibus-1.1.0.20090612 commit 19d6cdf9348e4ba6cb18a50e6c07fb349dd7e8cf Author: 余钰炜 Date: Mon Jun 15 00:29:28 2009 +0800 port to new process_key_event commit 83b433d3f696601413a5a5afa2d18c189290116e Author: 余钰炜 Date: Tue Jun 2 12:08:09 2009 +0800 update compose.txt commit 8dd226c87542f3f1c1f237bf81972970f2f611f6 Author: 余钰炜 Date: Tue Jun 2 12:03:20 2009 +0800 update icons/Makefile.am; update template.txt commit 4d07083b7fac8372f942ebfe064ad269a20e507b Author: 余钰炜 Date: Tue Jun 2 11:58:56 2009 +0800 rename direct_commit to auto_commit; allow auto_commit with one candidates in non-Chinese IME commit a2eaa3b6b1e4e443916590fd64b0c68e131abf1e Author: 余钰炜 Date: Mon Jun 1 10:37:47 2009 +0800 use LANG as LC_CTYPE fallback commit 366761995e13b8df21db2bcfa3e16c8b9a0a0c6f Author: 余钰炜 Date: Sun May 31 23:41:00 2009 +0800 fix fresh new ibus-table startup failure commit 1bb92eeef08e275998d323908fe34af2ade017f2 Author: 余钰炜 Date: Sat May 30 15:38:25 2009 +0800 merge from kaio.git; fix tabsqlitedb.compare, which cause wrong ordering in tabsqlitedb.select_words commit 638275afccc68bb3c397f2a3953034912ca158c0 Author: 余钰炜 Date: Tue May 26 11:16:45 2009 +0800 merge from kaio.git commit c07348108b6fc4b17ca617a06d76f2637edfa491 Author: 余钰炜 Date: Tue May 5 01:12:45 2009 +0800 fix user phrase check bug commit 96f89769c5c1365802ab495335e7fc52e6235aab Author: 余钰炜 Date: Fri May 1 23:30:14 2009 +0800 allow the create_engine to fail commit e3b22b14602b55a5054a0224834eac7e24a8049e Author: 余钰炜 Date: Fri May 1 22:59:52 2009 +0800 replace all invalid character in engine_path to under_score commit 490daacfdee8aa5f9af1e67a6ef3c90fd649bb7c Author: 余钰炜 Date: Fri May 1 22:04:20 2009 +0800 replace the "-" to "_" in engine_path commit 751296ceede357d5010864298f21e408446ed751 Author: 余钰炜 Date: Thu Apr 30 16:14:41 2009 +0800 add sigterm handler to sync userdb commit 1c792bcb904df77c4873302e2042abca8eb19d94 Author: 余钰炜 Date: Wed Apr 29 11:32:39 2009 +0800 fix pinyin mode bug commit 3fab1911c5055505dced11842555f07d050e5e9e Author: 余钰炜 Date: Wed Apr 29 01:04:03 2009 +0800 fix xml mode bug cause by debug commit 6a13b9a02919f011ec83e7e78968945d379c4c4f Author: 余钰炜 Date: Wed Apr 29 00:53:28 2009 +0800 redirect stdout,stderr to debug.log; readd arrow_up, arrow_down for candidates selection commit b21289c1af9301ad9f8a398db35870380d2b392b Author: 余钰炜 Date: Fri Apr 24 13:42:34 2009 +0800 remove the id from user_db.desc commit 8b2e0db12ddf5c2a72111187c40c3fb999345176 Author: 余钰炜 Date: Thu Apr 23 14:55:56 2009 +0800 fix check_phrase bug, which caused by recording tabkeys commit 9a5602a8a90fc4e4a5dc826720d15ce07570aabd Author: 余钰炜 Date: Wed Apr 22 14:38:31 2009 +0800 support record user_freq of phrases with user inputted keys; fix bugs cause by last commit commit da76aa709497859a6e3989637429331ee249eeb6 Author: 余钰炜 Date: Mon Apr 20 20:57:29 2009 +0800 add id key in db to allow better phrase ordering. Users need to regenerate the .db files. commit 1e894cf358814f0972159b9bd44fc282dad387c6 Author: 余钰炜 Date: Thu Mar 12 16:42:57 2009 +0800 fix digit ignore when digit in valid_input_chars commit d819c40a693b7afbe8c8ec4cbf3faf678ffd8a5d Author: LI Daobing Date: Sun Mar 8 22:14:50 2009 +0800 fix order in pkgconfig commit 8ef53eb84c9866e77bcc9c28940b98b9972ca274 Merge: 768e4b8 e926b14 Author: 余钰炜 Date: Fri Mar 6 14:19:01 2009 +0800 merge from kaio'tree commit 768e4b851b4b7d6f542fc11d424f2bf483a7f1d6 Author: 余钰炜 Date: Fri Mar 6 14:08:00 2009 +0800 update Changlog commit a8e019d4582db1d9142a1efbecd945c4470b3fb0 Author: 余钰炜 Date: Fri Mar 6 14:07:12 2009 +0800 add Caius into project commit e926b14b0718c3e02df28d1efd5490a715b7d9e9 Author: Caius 'kaio' Chance Date: Fri Mar 6 15:23:47 2009 +1000 make pkgconfig noarch commit 193267080c33cd7aed19151f9199fbb35807d86b Author: Caius 'kaio' Chance Date: Fri Mar 6 15:17:13 2009 +1000 Corrected .spec form GPLv2+ to LGPLv2+. commit b7f63b016d148991cade9c62ea61254fbd390e87 Author: Caius 'kaio' Chance Date: Fri Mar 6 14:57:42 2009 +1000 Updated author list. Manually generate ChangeLog with `git log > ChangeLog`. commit a3f8a4667ace5be764973857f6833fff196d66e5 Merge: 2b0726c fe3f5dc Author: Caius 'kaio' Chance Date: Fri Mar 6 14:39:46 2009 +1000 Merge commit 'acevery/master' commit fe3f5dc73f9b7f3655ab15c4cf52e8fac9dbef1d Author: 余钰炜 Date: Wed Mar 4 15:27:46 2009 +0800 hide speedmeter when engine is destroied commit df131abd2a9a71478437d2efccc8c22f44e19a62 Merge: 728bf4c 6b7ed8a Author: 余钰炜 Date: Wed Mar 4 00:47:54 2009 +0800 Merge branch 'master' of git@github.com:acevery/ibus-table commit 728bf4c45ccf1dd79e8afac937f2291b03cbfff4 Author: 余钰炜 Date: Wed Mar 4 00:44:12 2009 +0800 fix error included by last commit commit 69027a7aa8e5ca40ad67fe6e6afe11ae896cfa3b Author: 余钰炜 Date: Wed Mar 4 00:38:45 2009 +0800 fix -t .db mode bug commit 6b7ed8ab2ab27daef9656be741d667cfbf7a007a Author: Huang Peng Date: Sun Mar 1 11:17:31 2009 +0800 Test more arguments in ibus-engine-table script. commit dbdbbc6df91672f12748db17261dcf9789a2a909 Author: 余钰炜 Date: Sun Mar 1 08:11:55 2009 +0800 fix ibus-engine-table --xml bug commit c18330f7933e2c972b16a1cde4420d18d9fca21e Author: 余钰炜 Date: Mon Feb 23 19:29:32 2009 +0800 fix a bug reported by Wenping Guo commit 3780ce03d1cd430aab8ddb359541a046a5ce557f Author: 余钰炜 Date: Mon Feb 23 19:09:01 2009 +0800 hide speedmeter as default commit 95b2ae32e6a555c39a16dead658df0d08ce518cc Author: 余钰炜 Date: Fri Feb 20 23:11:57 2009 +0800 put sm.Quit() into try commit ded9214f0ec7fa1577a11d62211886984e0d4ff7 Author: 余钰炜 Date: Fri Feb 20 23:08:26 2009 +0800 fix ime_property cache bug commit 8e062065efff58de5303c3f96c4b49fbb279d394 Author: 余钰炜 Date: Fri Feb 20 22:47:56 2009 +0800 improve db file usage, try to fix issue271 commit 8c0d24fc98dd8ca68ce6aaf69362ebf2c61cb838 Author: 余钰炜 Date: Fri Feb 20 09:40:01 2009 +0800 add ctrl+' as hotkey to show/hide speedmeter commit 111eb3fa30d801c58871713ee269e81395d5d29d Author: 余钰炜 Date: Fri Feb 20 08:48:35 2009 +0800 fix xml generating bug with cangjie and erbi commit 1956d74253fa861283e09f6bced3ca401529e344 Author: 余钰炜 Date: Thu Feb 19 21:16:09 2009 +0800 use xml.etree instead of elementtree commit 2b0726ce00c2a9512d58b90cb94e3b95481a1ec1 Merge: 3a5330a e8ccd01 Author: Caius 'kaio' Chance Date: Thu Feb 19 15:06:06 2009 +1000 RE-Merge commit 'acevery/master' Conflicts: doc/Makefile.am engine/Makefile.am engine/table.xml.in.in commit e8ccd0137d01f615dbd92fce41d1d49b77d39796 Author: 余钰炜 Date: Wed Feb 18 21:58:16 2009 +0800 fix typo commit 14e38433a759baf4d4559bfbbd0a598e310eea4f Author: 余钰炜 Date: Wed Feb 18 21:45:16 2009 +0800 add ibus version check commit 7742e4bb009d3872d38c888780fbf16b823fc127 Author: 余钰炜 Date: Wed Feb 18 21:36:24 2009 +0800 fix table/additional/Makefile.am commit 8b70a1596ad2802762394b358306f1280cfe3244 Author: 余钰炜 Date: Wed Feb 18 21:29:35 2009 +0800 update po commit 80fb3ff178e3bb85f759e1a9e9edf8969bcb13df Author: 余钰炜 Date: Wed Feb 18 21:27:14 2009 +0800 add Ctrl+; as chinese input mode hotkey commit 6fcc3a567746ab3fa17896dd46b873979cb36349 Author: 余钰炜 Date: Wed Feb 18 20:59:22 2009 +0800 fix speedmeter.py bug; readd latex.txt commit cb4192fc781003d04ca944e44cc21a497b337cec Author: 余钰炜 Date: Wed Feb 18 18:31:18 2009 +0800 update template.txt commit 9df5d19dab9762bd99caae496a0d5f5c4b2f194c Author: 余钰炜 Date: Wed Feb 18 16:55:52 2009 +0800 prepare to release commit 92103167a6ea103326d1dd00800e8f1a0c864bae Author: 余钰炜 Date: Wed Feb 18 15:52:16 2009 +0800 fix do_destroy bug commit 0193d86ae74ac34ee56d0038f426ffc759eb099a Merge: f7c1977 7c786b6 Author: 余钰炜 Date: Wed Feb 18 10:59:42 2009 +0800 update for ibus-1 commit 7c786b6d0e7e99252aa21ed7a5b3ede56e7fe654 Author: 余钰炜 Date: Wed Feb 18 10:14:08 2009 +0800 fix @VERSION@ commit e3a96308977de55853e0b6255f56d07572e5cdf6 Author: 余钰炜 Date: Wed Feb 18 10:07:34 2009 +0800 try to fix the xml eval bug commit 03db85e55a1b9c0ce5a4999ade7130e4a2195319 Author: 余钰炜 Date: Wed Feb 18 00:23:57 2009 +0800 fix configure.ac commit 0a0be88c6e33331491c50682fd13f550602af80b Author: 余钰炜 Date: Wed Feb 18 00:16:58 2009 +0800 step 4 commit 47f49932beac875f82fe93fc2b5ee9337c8e2d91 Author: 余钰炜 Date: Tue Feb 17 23:05:45 2009 +0800 step 3 commit 3a5330ace95f39020407492cdedf4262614a3042 Merge: f8b80b8 ffa04fe Author: Caius 'kaio' Chance Date: Mon Feb 16 18:11:05 2009 +1000 Merge commit 'acevery/for_c_ibus_daemon' Conflicts: configure.ac data/Makefile.am doc/Makefile.am engine/Makefile.am engine/factory.py engine/ibus-engine-table.in engine/main.py engine/speedmeter.py engine/table.py icons/Makefile.am icons/additional/Makefile.am tables/Makefile.am tables/additional/Makefile.am commit ffa04fe490dd89a0ef8de2335ef5ad8971a2c265 Author: 余钰炜 Date: Mon Feb 16 00:07:01 2009 +0800 second step for ibus-1 commit f8b80b85b7a774a734720dd973574b9b77dee482 Merge: b1a8593 198cf85 Author: Caius 'kaio' Chance Date: Mon Feb 16 01:37:05 2009 +1000 Merge commit 'lidaobing/master' commit b1a85938c0aa38db91fb4d0c4f3835e7e4d9a3c0 Author: Caius 'kaio' Chance Date: Mon Feb 16 00:50:20 2009 +1000 added table spec xml commit 24f5090106d6c7ea8ec203bc428654d9db0b64de Author: 余钰炜 Date: Sun Feb 15 21:00:40 2009 +0800 remove something outdated commit bf272e43758e90a95ff8cda2c0256b3c02760ac5 Author: 余钰炜 Date: Sun Feb 15 16:26:11 2009 +0800 first step for ibus-1 commit e5ff74536114bde07ea4667921518f107c72f2e1 Author: 余钰炜 Date: Tue Jan 27 20:53:45 2009 +0800 fix pinyin mode bug when come to pinyin like "xiong" commit f7c1977a430bce98ceeb6ca2bfe01a4fe6c45b33 Author: 余钰炜 Date: Tue Jan 27 20:50:48 2009 +0800 fix pinyin mode bug when encounter pinyin like "xiong" commit c8784688bdb663440617117937bb6cde3387f758 Author: 余钰炜 Date: Mon Jan 5 18:20:06 2009 +0800 add maintainer mode; update pinyin to unihan 5.1 commit 497435380d9c3cfaccc563cff298802dcc78c838 Author: 余钰炜 Date: Mon Jan 5 18:12:33 2009 +0800 * Add Maintainer Mode; * update pinyin_table.txt.bz2 from Unihan Database 5.1 commit fa77370f08301b975277bc2ddb29547688dcbeda Author: 余钰炜 Date: Sun Jan 4 20:38:59 2009 +0800 fix License conflict commit 11f2139b46a8a8f11369965edbab0f30894052a3 Author: 余钰炜 Date: Sun Jan 4 20:06:56 2009 +0800 update README about new keys in PinYin mode commit b53e47565fc136f76a88f7dd0d76910c3243ede6 Author: 余钰炜 Date: Sun Jan 4 19:41:09 2009 +0800 remove latex.txt commit 5bc53da3bbe70a1b429833a4562fb058b4c8d74d Author: 余钰炜 Date: Sun Jan 4 19:40:28 2009 +0800 remove latex.txt commit ac65a87869cf4e7958c0c35e2d823859a5c8e9d4 Author: 余钰炜 Date: Sun Jan 4 17:28:49 2009 +0800 use new pinyin_table commit 6e5e93676bfbbfbcca9aaf1bade658a2269f7a33 Author: 余钰炜 Date: Sun Jan 4 19:10:22 2009 +0800 use new pinyin_table commit e279dde95643f76a6d70162e58dd472baa957864 Author: 余钰炜 Date: Sat Jan 3 23:31:21 2009 +0800 fix License conflict commit 198cf85c7ec2f498a95f49e49fd4af8ebce834c4 Author: LI Daobing Date: Sat Jan 3 14:52:37 2009 +0800 fix typo in README ChangJie -> CangJie commit 3d4042fd2ff4072ef29a1b806b88aadd018b0206 Author: 余钰炜 Date: Sun Dec 28 21:59:13 2008 +0800 fix focus bug commit cf3ca9b8f56843c4ebab2eafead986f6fc079b83 Author: 余钰炜 Date: Sat Dec 27 16:01:41 2008 +0800 port to ibus c daemon commit 2ee28efac54a3cc64c09d276e28085e60aee2025 Author: 余钰炜 Date: Wed Dec 17 00:54:29 2008 +0800 * fix get_preedit_string bug commit 246c8f0ead0b2c719b197c61ba23c71452fcbcd1 Author: 余钰炜 Date: Wed Dec 17 00:38:24 2008 +0800 * fix auto_commit bug under one candidate * fix get_preedit_string bug commit f4b959fc1028a45bd02c71937dbd3878a58869cc Author: 余钰炜 Date: Sun Dec 14 23:16:18 2008 +0800 Add MAINTAINERCLEANFILES commit bd3b567cdf86583b76c3f0f5241420fa2ce74bd1 Author: 余钰炜 Date: Sun Dec 14 21:38:44 2008 +0800 fix additional table icon bug commit 65a39b547317ed0cec1f7743d63d1ee4ebe1b8f6 Author: 余钰炜 Date: Sun Dec 14 16:25:05 2008 +0800 reset speedmeter when enable IME commit a06375e46132a020d8115e57121b38c7d99df14c Author: 余钰炜 Date: Fri Dec 12 12:10:13 2008 +0800 fix select_words but under Chinese filter commit 5eb048ee35e6e382ca5d281fac6cc303112dcfea Author: 余钰炜 Date: Thu Dec 11 01:03:40 2008 +0800 * use 60s as speed calculation time span * daemonize after dbus name checking commit 4783a0cbb63bade2c725da298ce473aeb7581d82 Author: 余钰炜 Date: Thu Dec 11 00:37:55 2008 +0800 add daemonize in speedmeter.py commit 0bc6cc3d88f1614b68f7d2eb4f91b235db63daec Author: 余钰炜 Date: Wed Dec 10 14:43:50 2008 +0800 modify icons commit c931507238526213b23f0278ab98ea93e2942d11 Author: 余钰炜 Date: Wed Dec 10 12:58:13 2008 +0800 fix gdk.Color init way, allow low version of gtk+ commit 3e699f3d45eb14c52a63d0225d8b51b7031a1b38 Author: 余钰炜 Date: Wed Dec 10 04:22:24 2008 +0800 record and restore SpeedMeter position when Hide/Show commit b503315133efa40a5a0c903b94414874f90917e8 Author: 余钰炜 Date: Wed Dec 10 03:39:46 2008 +0800 hide speedmeter when start commit 5acd9b0ac05f68d5a1f66d2fc7fbc39f254c3530 Author: 余钰炜 Date: Wed Dec 10 03:12:39 2008 +0800 Add speedmeter.py to calculate the input speed for user, and display it in a small widget via gtk+ and dbus :) now, we only take the the characters from tables into account, not include the punctuation After 3 days' learning about dbus-python and pygtk, Finally, complete my first GUI work, the speedmeter.py. Although it is very very tiny and simple :D commit d105e02394d7c74838173131933efe27ffcd4e96 Author: 余钰炜 Date: Sun Dec 7 13:30:24 2008 +0800 migrate user phrases to new user_db commit 33069172b63d0ca40b6ec69d325561fe12ff4f6b Author: Huang Peng Date: Fri Dec 5 16:24:05 2008 +0800 Remove tables from ibus-table. commit 35ca25ea97c083dccc6ce5de2f0b045047adc4ca Author: 余钰炜 Date: Fri Dec 5 14:48:11 2008 +0800 remove icons as well. commit 6bc4c99ae1067b7ca064f64d49e7a31bcf7a89fc Author: 余钰炜 Date: Fri Dec 5 14:45:58 2008 +0800 split Chinese tables out commit 05913922b0c8380526db4ffd34e356946ad60db5 Author: 余钰炜 Date: Thu Dec 4 16:44:51 2008 +0800 add $extradatadir in .pc commit 08ada5d9461c9b36fff4e0154f2983bb186b6ef2 Author: 余钰炜 Date: Thu Dec 4 16:35:19 2008 +0800 use pkgconfig to record metainfo commit 719c4f5dc8b30df8f95b4d0ade2dd464baef4b32 Merge: 814fd89 ea21559 Author: 余钰炜 Date: Wed Dec 3 21:43:38 2008 +0800 Merge branch 'master' of git@github.com:acevery/ibus-table commit ea21559409fa2210e9f9a9c58c960d951ff6da4e Author: 余钰炜 Date: Wed Dec 3 17:00:22 2008 +0800 fix direct commit bug; do not show cursor now and do not use arrow_up/down to move cursor in lookup_table commit 814fd89b777668515a72dfd56c246091a6162ae2 Author: 余钰炜 Date: Tue Dec 2 23:27:45 2008 +0800 allow specify icon file with runtime commit 59ae5f81c243b6b94161ca9d92f68e9805e1a227 Author: 余钰炜 Date: Tue Dec 2 22:44:37 2008 +0800 allow specify table database with abs path commit 55abf4d76d6aae602f86c33c6f1e6b3d76491329 Author: 余钰炜 Date: Tue Dec 2 20:01:04 2008 +0800 update_ui after arrow_up & arrow_down commit a0ed04e852259b058c7e9a26fe7f32e6853b9b8b Author: 余钰炜 Date: Tue Dec 2 15:31:12 2008 +0800 fix icon Makefile.am, fix a bit in wubi86.txt commit 51009d46e74121cc5e9cc37b5d35aae2c3efa08b Author: 余钰炜 Date: Tue Dec 2 09:20:47 2008 +0800 fix cm_mode property bug commit 2997f327acf3c2e2f4b95b861f8189cfa65c72f3 Author: 余钰炜 Date: Sun Nov 30 13:06:47 2008 +0800 fix duplicate chars in zhengma.txt commit c40588c5f92eecf9cd7a39fe9f4c04a84dab48e4 Author: 余钰炜 Date: Sat Nov 29 21:02:40 2008 +0800 fix pinyin mode bug, call update_ui before commit_string commit 59f65b0e5ab973d3e6ce36b14312d64e4ccafaaa Author: 余钰炜 Date: Sat Nov 29 15:22:35 2008 +0800 put back the two incompatible phrases into wubi86 only commit 69fc666c94d504f85a5bf4f3b38caa4691b637a3 Author: 余钰炜 Date: Sat Nov 29 14:59:08 2008 +0800 remove incompatible phrases commit 404fbcb0be0f22588d1a49b0ea3223a397c55f2b Author: 余钰炜 Date: Sat Nov 29 12:52:27 2008 +0800 update wubi86 and cangjie5 tables commit e48ffc05548489d1e29414b30a1e3b2761cc23b2 Author: 余钰炜 Date: Sat Nov 29 12:47:29 2008 +0800 Add Chinese punctuations and other un-need-checked chars into tabdict commit 68ec5e8295aab51a2404e2b77f7b0890cff8392b Author: 余钰炜 Date: Sat Nov 29 09:55:25 2008 +0800 fix filter_candidate bug commit af5bda974cde8436f4ac4523ddc1c33e96bc2369 Author: 余钰炜 Date: Sat Nov 29 09:21:44 2008 +0800 group 〇 as Simplify Chinese as well commit 0fbf8fb630362bada3a5353e04e801c87b8ce26c Author: 余钰炜 Date: Fri Nov 28 17:09:12 2008 +0800 update canjie5 table by issue 158 commit b74d405ea55038032e884a02835ba28fc781ab9f Author: 余钰炜 Date: Wed Nov 26 21:50:45 2008 +0800 Update zh_CN.po commit 9a694d934f89f2c6194a41115910e104f8268cac Author: 余钰炜 Date: Wed Nov 26 21:50:06 2008 +0800 fix remove_phrase bug cause by "category" key commit dcdef990b0744511f83981d2b5a1e6c24686bbe7 Author: 余钰炜 Date: Wed Nov 26 11:39:25 2008 +0800 fix chinese mode bug in check_phrase, add normal big charset mode commit 0b88176c15283511a3445d8d8a5359b55f5b54f7 Author: 余钰炜 Date: Wed Nov 26 11:18:33 2008 +0800 reset after change Chinese mode commit b3975772916c2d3854d53ec7093f05114bd783a8 Author: 余钰炜 Date: Wed Nov 26 11:06:27 2008 +0800 fix a bit logical miss :) commit b56ec3280ffc7d39bb0c9e709972c0f52b287e64 Author: 余钰炜 Date: Wed Nov 26 11:02:48 2008 +0800 Add Simplify/Traditional Chinese input mode commit 663223e93ddf3dea3f9fbf4e28cfa3d6c1a49361 Author: 余钰炜 Date: Wed Nov 26 02:26:08 2008 +0800 fix bugs come along with \"category\" key, fix sys.stderr bug, fix lookuptable color bug commit 439ea7577c35729f09426efaad26a9612f097dd2 Author: 余钰炜 Date: Tue Nov 25 00:13:56 2008 +0800 add category bitmask integer into phrases table commit 36972649aff0807404635b9cbb8082a3374fe1d7 Author: 余钰炜 Date: Mon Nov 24 22:19:28 2008 +0800 replace tab with 4 space commit 55bcbdf5c2298d0b269b222eaf6b62a77d82b29a Author: 余钰炜 Date: Sun Nov 16 13:18:27 2008 +0800 use possible phrase key lengths to determine commit or not, fix some phrase in extra_phrase commit 1f54e735af72265e768805837d5f2027e9f93ca5 Author: 余钰炜 Date: Sat Nov 15 20:47:47 2008 +0800 add CJK-B, CJK-C support for ZhengMa commit aa0284854899a0dba613fcf307b2cb28653151e0 Author: 余钰炜 Date: Sat Nov 15 20:34:08 2008 +0800 fix pharse_phrase bug when no goucima available commit da9f8c4a0c41e44869dad084ce476f7582f7d586 Author: 余钰炜 Date: Fri Nov 14 20:24:29 2008 +0800 fix COPYING and update README commit 0a5c3224405d06866b77a107282d8b9657c8a559 Author: 余钰炜 Date: Wed Oct 29 19:21:59 2008 +0800 fix contrl+space bug commit cbe11141cc1c762de1c008df40d4db2230f3b954 Author: 余钰炜 Date: Thu Oct 23 00:31:23 2008 +0800 support punctuation direct commit in IME like ErBi commit fafda37d74eb293117281c145e98e9fde9ac4b82 Author: Huang Peng Date: Fri Oct 17 15:34:01 2008 +0800 Add some new icons in spec file. And rename extra_phrases file name. commit 5d58230816adad3dd56a243a2cccc5d0475065e0 Author: 余钰炜 Date: Thu Oct 9 21:59:35 2008 +0800 fix add_phrases logic error commit b869de8b79de16e17a80acf0c576eb084d0b5a25 Author: 余钰炜 Date: Thu Oct 9 21:30:13 2008 +0800 fix typo commit d65231aafa3fd5707b2f8d2555ad030bb6ba5f20 Author: 余钰炜 Date: Thu Oct 9 20:56:05 2008 +0800 apply hashao's patch commit 6afe7a0933e97223a1cf5d6cc6ef07b191e5fc92 Author: 余钰炜 Date: Tue Sep 23 09:44:58 2008 +0800 fix extra_phrase rename error in Makefile.am commit 74107088584f5b8fc8e60a1c94f0e5e69172b1b1 Merge: 5a6a517 ed88e42 Author: 余钰炜 Date: Mon Sep 22 21:03:04 2008 +0800 Merge branch 'master' of git@github.com:acevery/ibus-table commit 5a6a517e719c3d017b94067e5c5c457bd449447a Author: 余钰炜 Date: Mon Sep 22 21:01:28 2008 +0800 compress extra_phrase.txt commit ed88e422aecd3cf4d6e4b4671785e9f3d35743f1 Author: Huang Peng Date: Sat Sep 20 08:03:10 2008 +0800 Fix syntax error. commit 5afe835152ff9a363536e45187645a8be1eac708 Author: 余钰炜 Date: Thu Sep 18 22:47:50 2008 +0800 fix a direct commit bug commit 8b0b8f773146f2212a8e700ac1093dff96060cda Merge: 8760d94 bcf8109 Author: 余钰炜 Date: Thu Sep 18 22:44:56 2008 +0800 Merge branch 'master' of git@github.com:acevery/ibus-table commit bcf8109b174f170562a1c9e9b4a9ce6c9818ff0e Merge: b07dbaf 40eda9c Author: Huang Peng Date: Sun Sep 14 16:44:56 2008 +0800 Merge commit 'acevery/master' commit b07dbaf7de9092213b5ec84635d08b1fc9c5ea43 Author: Huang Peng Date: Fri Sep 12 07:52:12 2008 +0800 Add debian packaging files by 一叶 . commit 8760d94ddcc5063a1433a7eed994cd85883f509d Author: 余钰炜 Date: Fri Sep 12 00:28:54 2008 +0800 use new Cangjie5 icons as Caius Chance provided commit 40eda9c1fe2e93f3f6fe352a84c45d908aeec303 Author: 余钰炜 Date: Thu Sep 11 21:27:14 2008 +0800 fix user_define phrase related bugs commit 635fbae81756548cb30bbf39e0ee2f6621f3faeb Author: 余钰炜 Date: Thu Sep 11 11:00:47 2008 +0800 fix max input length error commit f2d8600ac8164d29c6a3f97074b94111ac40da16 Author: 余钰炜 Date: Mon Sep 8 07:36:09 2008 +0800 fix typos, fix invalid input bug commit 275c364a2738bbf4e83cc9ade6c93cf4ffd4055d Author: 余钰炜 Date: Sun Sep 7 02:25:16 2008 +0800 enhance direct input mode and fix some bugs commit f3ff6b02ab4158c2871cd004a84e4040f883ea81 Author: 余钰炜 Date: Sat Sep 6 14:08:32 2008 +0800 fix pinyin mode icon error via numkey commit commit b0d3889cb263e132fd545b432fbcae1d37661a9d Author: 余钰炜 Date: Sat Sep 6 13:12:58 2008 +0800 fix typo commit 6592e19ebdaf72905fb5ded44ac6da4053400808 Author: 余钰炜 Date: Fri Sep 5 11:48:07 2008 +0800 ignore numlock mask commit 0f48addc70c9beef5cc1f9aa3c7f917c097305e0 Author: 余钰炜 Date: Fri Sep 5 02:41:17 2008 +0800 update po commit 43c42c7420cca1de98b4dc33a2516418dcbccddb Author: 余钰炜 Date: Fri Sep 5 02:32:48 2008 +0800 Add direct commit function, fix pinyin mode panel refresh bug commit cb2df9bea0cfd5e67fac30b52feebf99692f6534 Author: 余钰炜 Date: Fri Sep 5 00:43:39 2008 +0800 fix po typos commit 1ff713d982aa84cc6934b34f7cea99f33d89bde9 Author: 余钰炜 Date: Thu Sep 4 17:05:11 2008 +0800 Add missing icons commit ee0e4ceb9b60d7180255fa79d0521a18c0b4f92a Author: Huang Peng Date: Mon Sep 1 10:52:47 2008 +0800 Fix problem in spec file. commit a40f0ac150e4a7acf77070a64e229cee417b8dfd Author: Huang Peng Date: Mon Sep 1 10:52:09 2008 +0800 Update po file. commit c37ea4692abb7fc4aa2cbd802a20576d617a6c60 Author: Huang Peng Date: Mon Sep 1 10:34:35 2008 +0800 Do not install ibus-table.engine commit dd957df4bc51b571be49b715701fe2a53478d528 Author: 余钰炜 Date: Sun Aug 31 13:44:34 2008 +0800 fix str encode error commit f09ead162bdc94fcff000aec6ce997e2c9b5518f Author: 余钰炜 Date: Sun Aug 31 13:14:26 2008 +0800 convert some tables for extra_phrase commit 4e98c9e4531caaa7d8419a4d3304f53c5c12ca32 Author: 余钰炜 Date: Sun Aug 31 12:05:30 2008 +0800 use memory to cache goucima commit f4a9bd6a5c35689cf30753e072ae25a8962ed84e Author: 余钰炜 Date: Sun Aug 31 10:59:18 2008 +0800 Add tabcreatedb.py from origin commit f7289fb312ec8cb421b4101cd928ab7849e86408 Merge: fb6858a 62af461 Author: 余钰炜 Date: Sun Aug 31 10:51:49 2008 +0800 remove conflict one commit fb6858af2a479838d2b7ec7cdbb7ec9bd6fd0878 Author: 余钰炜 Date: Sun Aug 31 10:46:41 2008 +0800 merge from origin commit 8d138bb09dccae010bac91e40a0b62ded613872d Author: 余钰炜 Date: Sun Aug 31 10:16:46 2008 +0800 fix extra phrases add error commit 62af4617c95d882826b32b3449689a4824713111 Author: Huang Peng Date: Sun Aug 31 09:21:24 2008 +0800 Change name of wubi86.txt commit 6539c694f32fe02b912c0fdacde380bfcb42569b Author: Huang Peng Date: Sun Aug 31 09:20:01 2008 +0800 Fix problem when create db commit c823c14075231331f9789239e60bce7db8fd7ac7 Author: Huang Peng Date: Sun Aug 31 08:57:07 2008 +0800 Get Name from .txt table files. commit 020920c335d9cd332820caadfe129ed724f8364a Author: 余钰炜 Date: Sat Aug 30 14:23:27 2008 +0800 fix latex.txt format error, improve table.py commit a25477589afddb0a8f4c4615f7e10c64d202f4ac Author: 余钰炜 Date: Sat Aug 30 02:32:20 2008 +0800 fix cangjie5.db generating error commit 82c814ff4cbf699366208f2bcc0cc4c813eb43e0 Author: 余钰炜 Date: Sat Aug 30 01:50:49 2008 +0800 change word adding method for extra_phrases commit ab8eb60c7a0c790989b81208662b9edf7c181db5 Author: 余钰炜 Date: Fri Aug 29 23:29:06 2008 +0800 remove swp file commit b4c2492f0dc8ea769a419d5d3830f734834668ab Author: 余钰炜 Date: Fri Aug 29 23:28:42 2008 +0800 Add chinese.svg and english.svg from ibus-pinyin commit 403a743e2d3febd807b5a05d85abb7f58a2c31da Author: Huang Peng Date: Fri Aug 29 19:03:55 2008 +0800 Rename erbi-qs.txt to erbi_qs.txt. commit 97738a27e1d3b2f7edb04ae1fbacbb917cbaff4f Author: Huang Peng Date: Fri Aug 29 17:02:04 2008 +0800 Update rpm spec file. commit 479eb0eaff02c233d969bdf01a440876542f06a0 Author: Huang Peng Date: Fri Aug 29 16:52:38 2008 +0800 Refine code style. commit 9a6d01547b3b4a656e6da28787eeb17e00fdce83 Author: Huang Peng Date: Fri Aug 29 16:51:51 2008 +0800 Fix a typo. commit fd1add4d979c3b9dc0c9af87435fc6ca3d0fb881 Author: Huang Peng Date: Fri Aug 29 16:51:35 2008 +0800 Fix a typo. commit dcdbf15740a6f2a9b005754add1d44deb1c01469 Author: Huang Peng Date: Fri Aug 29 16:09:47 2008 +0800 Add MAKEDISTFLAGS. commit cfae572b72c4a83127fe4b3ab22563f18ba8cd49 Author: Huang Peng Date: Fri Aug 29 16:09:34 2008 +0800 Fix `make dist` error. commit 9becfd13ed005ee2919482f9d6fca704cb782090 Author: Huang Peng Date: Fri Aug 29 15:49:52 2008 +0800 Fix wrong icon names. commit 809ad15300671bac782834824608aa0bdd8477f5 Author: Huang Peng Date: Fri Aug 29 15:49:33 2008 +0800 Clean *.engine when 'make distclean' commit ec71b915a73d3fdb7bd95f58490726b2f96a3aec Author: Huang Peng Date: Fri Aug 29 13:19:16 2008 +0800 Fix build errors. commit 24c40894f94a8f4b4ee8ef8d32df76880b41e2d8 Author: 余钰炜 Date: Fri Aug 29 09:13:15 2008 +0800 show configure options commit 050b4d01b8dd44492ae52caeaceb964ec0dacb49 Author: 余钰炜 Date: Fri Aug 29 03:10:53 2008 +0800 put all message of tabcreatedb.py into debug_print. First time, buildable :) commit 59760cf8c55d4801b5d48143b78b3b5ad5afdc82 Author: 余钰炜 Date: Fri Aug 29 03:03:25 2008 +0800 try to fix makefile rules commit ef01e73c8997e4a50e1138bdddd3a060c2dc79ec Author: 余钰炜 Date: Fri Aug 29 02:59:24 2008 +0800 try to fix makefile rules commit c0b3c546d73c508bf3810e93c8a1db196120f8cb Author: 余钰炜 Date: Fri Aug 29 02:50:49 2008 +0800 try to fix makefile rules commit b8644788b8c24f8922036bb5f05b57c0a2b39dd1 Author: 余钰炜 Date: Fri Aug 29 02:48:11 2008 +0800 try to fix makefile rules commit 1fb85e462333cf867eb05b5af48ec6c147f1c534 Author: 余钰炜 Date: Fri Aug 29 02:41:34 2008 +0800 try to fix makefile rules commit e17e79b756449b91fdef7cedc8e42a0728df6156 Author: 余钰炜 Date: Fri Aug 29 02:39:27 2008 +0800 try to fix makefile rules commit a869c9cac7dfa70bcba07171ce971171c6d32223 Author: 余钰炜 Date: Fri Aug 29 02:11:07 2008 +0800 try to fix makefile rules commit 46f56275fe1a836a66763afca9fbfc1bc74de889 Author: 余钰炜 Date: Fri Aug 29 02:09:30 2008 +0800 try to fix makefile rules commit 0fd11974099aa26ef965a7c4f2bc2ec2f5e4d8b5 Author: 余钰炜 Date: Fri Aug 29 01:58:37 2008 +0800 fix some error in tabcreatdb.py and some Makefile.am commit 66a3d0135c84c93c4a4030001370dd64454907cc Author: 余钰炜 Date: Fri Aug 29 01:56:33 2008 +0800 fix some error in tabcreatdb.py and some Makefile.am commit 83d6a3ee501c10bae8e05373bce2979c6a4e7680 Author: 余钰炜 Date: Fri Aug 29 01:50:04 2008 +0800 fix Makefile.am error commit e3423d49ba74862c06eef66618f0d29ed4481c0b Author: 余钰炜 Date: Fri Aug 29 01:41:55 2008 +0800 fix some error in tabcreatdb.py and some Makefile.am commit 68f7ca3cec3489bdbe88d71a1e5917dc17a101aa Author: 余钰炜 Date: Fri Aug 29 01:22:19 2008 +0800 fix some Makefile.am error commit 37abb85e16ec950f9bad0db5da0196c8357a754a Author: 余钰炜 Date: Fri Aug 29 01:18:42 2008 +0800 fix some Makefile.am error commit 03adc49608f96e56752f9b66e571f9172bfb61d3 Author: 余钰炜 Date: Fri Aug 29 01:15:15 2008 +0800 fix some Makefile.am error commit f030d8659cbaffe72d7cad5767c4eb105a488292 Author: 余钰炜 Date: Fri Aug 29 00:54:55 2008 +0800 add tables and icons into respo commit 5788a2abe5571ead36cef99b87853ffbb90f9652 Author: 余钰炜 Date: Thu Aug 28 01:35:27 2008 +0800 fix 0 freq entry bug commit 2f099bdbc2592528554edf4af5c19db364605c28 Author: Huang Peng Date: Wed Aug 27 09:31:30 2008 +0800 Update zh_CN.ppo commit 957bc692030deb1073fa4d7c2c6cc5dabe1c8b1e Author: Huang Peng Date: Wed Aug 27 09:08:59 2008 +0800 Fix problem when generate .engine. commit 871d6209ff271a7de564db308326b945dab0863e Author: Huang Peng Date: Wed Aug 27 08:36:41 2008 +0800 Replace -k with -d. commit f93486774275a62bb77f4d665bce55e9cb348ce5 Author: Huang Peng Date: Wed Aug 27 08:34:24 2008 +0800 Use absolute path for Icon in engine. commit c0d3a99ba310c22d4f85fc02702fcb7358ab0649 Author: Huang Peng Date: Wed Aug 27 07:48:05 2008 +0800 Use @datarootdir@ replace @datadir@ commit c28de9d2bb926e5837acd20d63e66dd61aca271d Author: 余钰炜 Date: Tue Aug 26 23:54:38 2008 +0800 update po file commit e2db33b07a91289863f3792045d59f7f76ee50e4 Author: 余钰炜 Date: Tue Aug 26 23:13:10 2008 +0800 try to remove ibus-table.pot commit 86382f1b44c682e3b2f7f88f418abb39b28333d2 Author: 余钰炜 Date: Tue Aug 26 23:00:17 2008 +0800 subtitute some @prefix@ in .in files commit 941184834b8bf672b7361afa1f0a0dad1bcc0e5c Author: 余钰炜 Date: Tue Aug 26 22:29:25 2008 +0800 fix @bindir@ error commit 76870cde13e89807bfdd9ccab5fc9780683c1efe Author: 余钰炜 Date: Tue Aug 26 21:59:41 2008 +0800 fix path error commit 8ddd5057fa53c203200f9a31c83e033d84f6a741 Author: 余钰炜 Date: Tue Aug 26 20:55:55 2008 +0800 add dynamic_adjust attribute in table database commit 091b9801c24881f8a654ae56b8355e8bf1d6e4bb Author: 余钰炜 Date: Tue Aug 26 19:59:59 2008 +0800 Directly generate table.engine from tabcreatedb.py commit d9f0a97d5d70712c01d4c79417344a7bdfc905fb Author: 余钰炜 Date: Tue Aug 26 11:12:04 2008 +0800 Optional commit in add_phrase commit a27d4509f81f7f2b98a6e152261a74ea7c6430ef Author: Huang Peng Date: Tue Aug 26 07:33:37 2008 +0800 Add maintainor-mode. commit be9692a7e4719779172f80291e1b80a20e56ec91 Author: 余钰炜 Date: Mon Aug 25 02:07:44 2008 +0800 remove extra a.patch commit ed093d011d391e694e755c05dfca6409befff645 Author: 余钰炜 Date: Mon Aug 25 01:51:18 2008 +0800 fix do_destroy bug and add freq fix support for special chars commit 0b76604e236b358423737b21da94eb3ccaf8b955 Author: Huang Peng Date: Sun Aug 24 07:51:25 2008 +0800 Change table-createdb to ibus-table-createdb in spec file. commit dc09bc78702d42e5f74b13d86a1d665b58e4423e Author: 余钰炜 Date: Sun Aug 24 02:14:32 2008 +0800 fix Makefile.am error commit 73c7265bca2aee9602ad5809192ce285d0153dd3 Author: 余钰炜 Date: Sun Aug 24 02:10:12 2008 +0800 support single character/phrase shift on fly commit 478f30eafd1b6990938ec57dd817a9725d0b1dd9 Author: Huang Peng Date: Sat Aug 23 11:19:00 2008 +0800 Fix errors of rpmlint checking. commit 312417db8c8f51488f9e3592921e14593db1715f Author: Huang Peng Date: Sat Aug 23 11:05:39 2008 +0800 Refine spec file. commit ecafcc887dd5b6c891ae382e29e2ebc10a216ca8 Author: Huang Peng Date: Fri Aug 22 12:37:28 2008 +0800 Fix make rpm error. commit 5c13ed994e5f5a8275a6a204c5b12824753f424b Author: 余钰炜 Date: Fri Aug 22 01:15:31 2008 +0800 support adding extra words during creating dababase commit cffbb866304cdec1654251958d9610eaba6d5065 Merge: 7010cda 3f1ee02 Author: 余钰炜 Date: Fri Aug 22 00:30:01 2008 +0800 Merge git://github.com/phuang/ibus-table commit 7010cda24d92b6468dd939f39b80e42d88baeb19 Author: 余钰炜 Date: Fri Aug 22 00:29:37 2008 +0800 remove swp file commit 459987343e890b36710e73e22feb474e275754e2 Author: 余钰炜 Date: Fri Aug 22 00:29:13 2008 +0800 prepare to support extra words source commit e334c1ddd254eafdbc4fa555ff7a3b038cd4aacf Author: 余钰炜 Date: Thu Aug 21 22:59:29 2008 +0800 prepare to support extra db commit 3f1ee021d8507af8f527d28cce844ce1d2a05c17 Author: Huang Peng Date: Thu Aug 21 22:33:49 2008 +0800 Fix error during `make distcheck` commit b931da2efd3345acaba041f11c7bcad87a731113 Author: 余钰炜 Date: Wed Aug 20 22:49:24 2008 +0800 know how to fix gvim, so roll back commit b7382ac546cd0dd408d8f06f99dac99cad01ee48 Author: 余钰炜 Date: Wed Aug 20 21:13:47 2008 +0800 fix to input space in gvim-7.2 commit 8f7dd83421203bf311a2544049a2d65a195944b9 Author: 余钰炜 Date: Wed Aug 20 01:03:08 2008 +0800 fix IBUS_TABLE_LOCATION commit 933d3de3ac2e460bdbec0799f8dba87019fd53e2 Author: 余钰炜 Date: Wed Aug 20 00:47:51 2008 +0800 remove swp file commit cf9a773fbc5c206933ca56f6bacf9434562a3114 Author: 余钰炜 Date: Wed Aug 20 00:46:57 2008 +0800 fix gettext missing in factory.py commit 1e277eb72e11b9fddfa39874577fc3a5ea51fc96 Author: 余钰炜 Date: Wed Aug 20 00:31:54 2008 +0800 fix tabcreatedb commit 7313136c82d0a41d9f569650975dabb28d6ebba8 Author: 余钰炜 Date: Wed Aug 20 00:17:58 2008 +0800 fix tabsqlitedb error when creatding db commit 0ec24318dc9294e427a0008c918e5395726a39b0 Author: 余钰炜 Date: Tue Aug 19 22:55:53 2008 +0800 fix Makefile.am error commit 7d265d1c62b097449a0e61b0c8198b6523a01a99 Author: 余钰炜 Date: Tue Aug 19 22:53:50 2008 +0800 add pinyin_table into resipotory commit fda45a06aa61bc9f55e93595e9dd61c4c7750262 Author: 余钰炜 Date: Tue Aug 19 22:44:29 2008 +0800 add table-createdb.in for database creation commit 6cf3c2d28cea1d6a158b478bb0edb0b5fac10e1b Author: 余钰炜 Date: Tue Aug 19 22:18:54 2008 +0800 modify icon commit b29366276264537a5ce7a2259ff57989b8143003 Author: 余钰炜 Date: Tue Aug 19 21:12:02 2008 +0800 transform charctor to path in ibus-table.svg commit 956cb9073fba5a08681e7193f72c1192c06fac96 Author: 余钰炜 Date: Tue Aug 19 21:07:40 2008 +0800 Modify some icons commit 8e4c8f7aedc0a77dccaaf0e970ca404c14969dab Author: 余钰炜 Date: Tue Aug 19 18:41:17 2008 +0800 try to fix po version warming commit fc32e94722f4d82638427ea6f05bf2cbbaa57185 Author: 余钰炜 Date: Tue Aug 19 18:39:42 2008 +0800 add doc into root Makefile.am commit dc624433ac32e3faf3f5d532a72d050a1605a683 Author: 余钰炜 Date: Tue Aug 19 18:36:28 2008 +0800 remove swp file commit 5b0e5647901b7802763e64b71fb7b16941d6d500 Author: 余钰炜 Date: Tue Aug 19 18:36:03 2008 +0800 fix Makefile.am error commit c1efb1b9a67b090a68df132e0c9e98631b15fc1b Author: 余钰炜 Date: Tue Aug 19 18:29:21 2008 +0800 move table.engine as doc file commit 26856137e940fdab3e946e2677234e0a997a44b4 Author: 余钰炜 Date: Tue Aug 19 16:18:31 2008 +0800 fix configure error commit d25074c7e1a4b8a904933ba4f048fba72e4ca76c Author: 余钰炜 Date: Tue Aug 19 16:12:52 2008 +0800 fix po verion commit 748157a6de1099e1487892ed36315f81cb16e3cf Author: 余钰炜 Date: Tue Aug 19 16:10:16 2008 +0800 add tables dir into configure.ac commit fd4bbd80e6c0456eb92b3e0856a662cc35ceb28b Author: 余钰炜 Date: Tue Aug 19 16:06:18 2008 +0800 fix icons/Makefile.am commit ee04390b1f8c2081317a551d47def5ca76498ff1 Author: 余钰炜 Date: Tue Aug 19 16:05:46 2008 +0800 Add ibus-table.svg commit cd3c5583987b2677098cdb72b6ede1791f251a05 Author: 余钰炜 Date: Tue Aug 19 15:36:15 2008 +0800 fix name error commit 9973c8f6953f02fb4855aa1d7baf5e48d694f8f7 Author: 余钰炜 Date: Tue Aug 19 15:28:44 2008 +0800 few correction commit a2d13d711ec725616b67d2b4a8f847e34cc6c357 Author: 余钰炜 Date: Tue Aug 19 15:25:27 2008 +0800 prepare to try the first make commit fd49ded87284c0a7d46282cb8f26d8f387161dcc Author: 余钰炜 Date: Tue Aug 19 10:20:48 2008 +0800 Add some files commit 3924a9befdb6a50b3e9344079242ae338488ccec Author: 余钰炜 Date: Tue Aug 19 09:51:48 2008 +0800 prepare to run aclocal and autoconf commit 4f68472801951c9cd9537c850d3d681571833908 Author: 余钰炜 Date: Tue Aug 19 09:25:32 2008 +0800 Init repository ibus-table-1.17.11/Makefile.am000066400000000000000000000056601475513533100157630ustar00rootroot00000000000000# vim:set noet ts=4 # # ibus-table - The Table engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # DISTCHECK_CONFIGURE_FLAGS = \ --enable-additional \ $(NULL) SUBDIRS = \ engine \ icons \ m4 \ tables \ data \ po \ setup \ tests \ $(NULL) ACLOCAL_AMFLAGS = -I m4 pkgconfig_DATA = \ ibus-table.pc \ $(NULL) pkgconfigdir = $(libdir)/pkgconfig # To register as an AppStream component to be visible in the software center # (See http://www.freedesktop.org/software/appstream/docs/ for more details): metainfodir = $(datadir)/metainfo metainfo_in_files = \ org.freedesktop.ibus.engine.table.metainfo.xml.in \ $(NULL) metainfo_DATA = $(metainfo_in_files:.in=) %.metainfo.xml: %.metainfo.xml.in $(wildcard po/*.mo) Makefile $(AM_V_GEN)$(MSGFMT) --xml --template $< -d $(top_srcdir)/po --output-file $@ schemas_DATA = \ org.freedesktop.ibus.engine.table.gschema.xml $(NULL) schemasdir = $(datadir)/glib-2.0/schemas/ install-data-hook: if test -z "$(DESTDIR)"; then \ glib-compile-schemas $(schemasdir); \ fi uninstall-hook: SCHEMAS_FILES=`ls $(schemasdir)/*.gschema.xml` || true; \ if test -z "$$SCHEMAS_FILES" && \ test -f $(schemasdir)/gschemas.compiled; then \ rm $(schemasdir)/gschemas.compiled; \ fi AUX_DIST = \ config.guess \ config.sub \ install-sh \ missing \ py-compile \ $(NULL) MAINTAINERCLEANFILES = \ Makefile.in \ aclocal.m4 \ configure \ $(AUX_DIST) \ $(NULL) EXTRA_DIST = \ config.rpath \ autogen.sh \ $(metainfo_in_files) \ $(metainfo_DATA) \ $(schemas_DATA) \ @PACKAGE_NAME@.spec \ $(NULL) noinst_DIST = \ $(NULL) #DISTCLEANFILES = \ # po/stamp-it \ # $(NULL) rpm: dist @PACKAGE_NAME@.spec rpmbuild -bb \ --define "_sourcedir `pwd`" \ --define "_builddir `pwd`" \ --define "_specdir `pwd`" \ --define "_rpmdir `pwd`" \ --define "_srcrpmdir `pwd`" \ @PACKAGE_NAME@.spec srpm: dist @PACKAGE_NAME@.spec rpmbuild -bs \ --define "_sourcedir `pwd`" \ --define "_builddir `pwd`" \ --define "_srcrpmdir `pwd`" \ --define "_rpmdir `pwd`" \ --define "_specdir `pwd`" \ @PACKAGE_NAME@.spec clean-rpm: $(RM) -r "`uname -i`" clean-local: clean-rpm ibus-table-1.17.11/NEWS000066400000000000000000000042261475513533100144230ustar00rootroot00000000000000July 3, 2014: ibus-table >= 1.8.x has many improvements over 1.5.x • The database format is simplified which makes better matching possible. But because of the changed database format, the tables have to be rebuilt, i.e. packages like ibus-table-chinese and ibus-table-others have to be rebuilt against ibus-table > 1.8.0. • Wildcard support added, wildcards like ? for single characters or * for many characters can be used. The wildcards can be configured in the setup tool, for example one can also use 'z' as a single character wildcard if desired. • Setup tool improved, several new options added, works with Gnome3 now. • Prompt characters are supported now, for example when using Cangjie, 日, 月, 金, ... are displayed while typing instead of a, b, c, ... • Moving around in the preëdit works correctly now. One can commit the current candidate to preëdit with the left shift key or with the arrow keys, commit more characters to preëdit that way, then move around in the preëdit and see the full key sequences of the characters in the preëdit. This way one can check the key sequences if one used wildcards or pinyin mode to enter the characters. • Fix many bugs. June 2, 2009: add auto_commit key into tabsqlitedb; only check phrase length during auto_commit mode in Chinese IME; rename dcommit.svg -> acommit.svg. May 26, 2009: merge from kaio.git -- add zh_TW.po, zh_HK.po; remove unused module in engine/table.py May 1, 2009: allow the create_engine to fail, so that ibus won't hang due to ibus-table failure. Apr 30, 2009: add sigterm handler to sync userdb Apr 29, 2009: redirect stdout,stderr to debug.log; readd arrow_up, arrow_down for candidates selection. Apr 24, 2009: remove id colomun from user_db.desc. Apr 22, 2009: add id key in db to allow better phrase ordering. ##################################################################### # Users need to regenerate the .db files. by recompile ibus-table-* # ##################################################################### ibus-table-1.17.11/README000066400000000000000000000316531475513533100146100ustar00rootroot00000000000000Ibus-table is a framework for table based input methods using IBus. Ibus-table is mostly used for Chinese, table based input methods like ZhengMa, WuBi, ErBi, CangJie and so on. But it can be used for other languages as well and some tables are available for other languages. Authors and contributors: • Yuwei YU (‘acevery’) acevery@gmail.com (Original Author) • Mike FABIAN mfabian@redhat.com (Current maintainer and Fedora package maintainer) • Caius ‘kaio’ CHANCE kaio@fedoraproject.org (Current maintainer) • Peng Huang • BYVoid • Peng Wu • koterpilla • Zerng07 • Bernard Nauwelaerts • Xiaojun Ma • mozbugbox • Seán de Búrca You can report bugs here: https://github.com/kaio/ibus-table/issues Online documentation can be found here: http://kaio.github.io/ibus-table/ http://kaio.github.io/ibus-table/documentation.html The keybindings are documented here: http://kaio.github.io/ibus-table/documentation.html#key-bindings A copy of that key-bindings documentation is included here for convenience: Key bindings ┏━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Key combination │ Effect ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Space │ Commit the preëdit string. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Escape │ Clear preëdit and discard contents. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Left (Arrow left) │ Move cursor one character left in the preëdit text. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Control+Left │ Move cursor to the left end of the preëdit text. ┃ ┃ (Control+Arrow_Left) │ ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Right (Arrow right) │ Move cursor one characater right in preëdit text. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Control+Right │ Move cursor to the right end of the preëdit text. ┃ ┃ (Control+Arrow_Right) │ ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Backspace │ Remove the character to the left of the cursor in ┃ ┃ │ the preëdit text. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Control+Backspace │ Remove everything left of the cursor in the preëdit ┃ ┃ │ text. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Delete │ Remove the character to the right of the cursor in ┃ ┃ │ the preëdit text. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Control+Delete │ Remove everything to the right of the cursor in the ┃ ┃ │ preëdit text. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Down (Arrow down) │ Select the next candidate. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Up (Arrow up) │ Select the previous candidate. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Page_Up │ Show next page of candidates. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Page_Down │ Show previous page of candidates. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ - │ When not being used as a valid input key, same as ┃ ┃ │ Page_Up. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ = │ When not being used as a valid input key, same as ┃ ┃ │ Page_Down. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ │ Commit the candidate labelled with that number. ┃ ┃ │ Note that a table can define other keys than the ┃ ┃ 1 … 9 │ numbers 1 … 9 as select keys to be able to use ┃ ┃ │ numbers as input. For example, the “latex” table ┃ ┃ │ needs number as input. Therefore, the “latex” table ┃ ┃ │ defines F1 … F9 as select keys. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Control+1 … Control+9 │ Commit the candidate labelled with that number to ┃ ┃ │ the preëdit. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Alt+1 … Alt+9 │ Remove the candidate labelled with that number from ┃ ┃ │ the database of learned user input. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ │ • When the preëdit is empty: toggle the input ┃ ┃ Shift_L (Left Shift │ mode between direct input mode (e.g. “English”) ┃ ┃ key) │ and table mode (e.g. “Chinese”). ┃ ┃ │ • When the preëdit is not empty: commit the first ┃ ┃ │ candidate to the preëdit. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Shift_R (Right Shift │ • When in table mode: Toggle between pinyin mode ┃ ┃ key) │ and normal mode. ┃ ┃ │ • When in direct input mode: No function. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Shift+1 … Shift+5 │ When in pinyin mode, input the tones. The tones are ┃ ┃ (Right or Left Shift │ displayed in the aux area as ↑1, ↑2, ↑3, ↑4, ↑5. 1 ┃ ┃ key) │ is YinPin, 2 is YangPin, 3 is ShangSheng, 4 is ┃ ┃ │ QuSheng, 5 is QingSheng. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ │ Toggle “one char mode”, i.e. toggle between showing ┃ ┃ Control+, │ only single characters and several characters at ┃ ┃ │ once in the candidate list. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Control+. │ Toggle between fullwidth and halfwidth punctuation. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Control+/ │ Toggle “autocommit mode”. ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ │ Toggle between the 5 Chinese modes: ┃ ┃ │ ┃ ┃ │ • Simplified Chinese ┃ ┃ Control+; │ • Traditional Chinese ┃ ┃ │ • Simplified Chinese first ┃ ┃ │ • Traditional Chinese first ┃ ┃ │ • All Chinese characters ┃ ┠───────────────────────┼─────────────────────────────────────────────────────┨ ┃ Shift+Space │ Toggle letter width between fullwidth and halfwidth ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ibus-table-1.17.11/autogen.sh000077500000000000000000000001211475513533100157130ustar00rootroot00000000000000#!/bin/sh set -e set -x autoreconf -fiv ./configure --enable-maintainer-mode $* ibus-table-1.17.11/configure.ac000066400000000000000000000053401475513533100162100ustar00rootroot00000000000000# Process this file with autoconf to produce a configure script. # vim:set et ts=4: # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # m4_define([package_name], [ibus-table]) # if not 1, append datestamp to the version number. m4_define([ibus_released], [1]) m4_define([ibus_major_version], [1]) m4_define([ibus_minor_version], [17]) m4_define([ibus_micro_version], [11]) m4_define(ibus_maybe_datestamp, m4_esyscmd([if test ]ibus_released[ != 1; then date +.%Y%m%d | tr -d '\n\r'; fi])) m4_define([ibus_version], ibus_major_version.ibus_minor_version.ibus_micro_version[]ibus_maybe_datestamp) AC_INIT([package_name],[ibus_version],[https://github.com/mike-fabian/ibus-table/issues],[package_name]) AM_INIT_AUTOMAKE([1.10]) AM_MAINTAINER_MODE # AC_USE_SYSTEM_EXTENSIONS # AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) #check python AM_PATH_PYTHON([3.6]) # check for ibus PKG_CHECK_MODULES([IBUS],[ibus-1.0 >= 1.1.0]) # define GETTEXT_* variables GETTEXT_PACKAGE=ibus-table AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Define to the read-only architecture-independent data directory.]) AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION(0.16.1) AC_ARG_ENABLE([installed-tests], [AS_HELP_STRING([--enable-installed-tests], [Enable to install tests])], [enable_installed_tests=$enableval], [enable_installed_tests=no] ) AM_CONDITIONAL([ENABLE_INSTALLED_TESTS], [test x"$enable_installed_tests" = x"yes"]) # OUTPUT files AC_CONFIG_FILES([po/Makefile.in Makefile engine/Makefile engine/ibus-engine-table engine/ibus-table-createdb engine/table.xml.in engine/version.py data/Makefile icons/Makefile tables/Makefile m4/Makefile setup/Makefile setup/ibus-setup-table setup/version.py tests/Makefile ibus-table.spec ibus-table.pc] ) AC_OUTPUT AC_MSG_RESULT([ Build options: Version $VERSION Install prefix $prefix ]) ibus-table-1.17.11/data/000077500000000000000000000000001475513533100146315ustar00rootroot00000000000000ibus-table-1.17.11/data/Makefile.am000066400000000000000000000021011475513533100166570ustar00rootroot00000000000000# vim:set noet ts=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # $Id: $ # pytable_DATA = pinyin_table.txt.bz2 phrase.txt.bz2 coin9.wav pytabledir = $(pkgdatadir)/data EXTRA_DIST = \ pinyin_table.txt.bz2 \ phrase.txt.bz2 \ coin9.wav \ $(NULL) MAINTAINERCLEANFILES = \ Makefile.in \ $(NULL) ibus-table-1.17.11/data/coin9.wav000066400000000000000000000544241475513533100164020ustar00rootroot00000000000000RIFF YWAVEfmt DXdataX28 p r  !"#$6&'()*+,-b0134567:;<=>?@CDEGHIJxMNOPQRST%VWXYZ\]^xI `abcdefgK iijklmnoq#stuvwxyz~}|{}~yxwvusrqonmlkjihfedca`_^\[ZYXWVU>RPONMLK" $ HGFEDCB/>=<;:987543210.-+*)('&%$"!         !"#$%&)*+,-.0$3456789:<=>?@ABC FGHIJKLM OPQRSTUVXZ[\]^_`Hcdefghi3lmopqrs9vwxyz{|]}|{zyxwvtrqponmlihgfedc _^]\[ZYVUTSRQPOLKJIHGFE,CBA@?=<;Y_98765432+0/-,+*)(&%$#"! U   F> > "#$%&'()` ,-./0123a  56789:;<?@ABCDEFIJKLMNOQRSUVWXYQ\]^_`ab efghiklmopqrstuv~}|{z9 xyz{|}~: wvutsrqmlkjihgfdcba`_^].dZYXWVUTSQPONMLKJdCGFEDCBA@>=;:98763210/.-  )('&%$# gw     w|t l  ^ !"q%&'()*+,/0123459:;<=>?BCDEFGHLMNOPQRS`UVWXYZ[\2 ^`abcdef #hijklmno^~qrstuvwx{zyxwvut|}~rqponmlk>Dhgfedcba_^]\[ZYXUTSRQPONMKJIHGFE A@?>=<;J87654321.-,+*)('$#"! dj)    9w w 6 M !"#$%()*+,-.b23456789&;<=>?@ABP EFGHIJKLQ uNOPQRSTU#XYZ[\]^_bcdefghlmnopqr~}|{zyuvwxyz{wvutsrqpmlkjihgfIbba`_^]) * YXWVUTS;ONMLKKJIFEDCBA@?<;:987653210/.-,)('&%$#"       "#$%&'() +,-./012 56789:;<>?@ABCDE3IJKLMNO$RSTUVWX)\]^_`abHefghijkl~opqrstuv{zyxwvu xyz{|}~ qponmlkhgfedcba^]\[ZYXWm"TTSRQPONJOKJIHGFED"A@??>=<;87654321a-,++*)( $#"! S    5qv5 'h h  !""%&'()*+,0123455H9:;<=>?ICDEFGHHLMNOPQRSVWXYZ[[\ A _`abcdefA  ijklmnno~}|{zyrstuvwxyvuttsrqp}~[mlkjihgfcba``_^]\/ZYXWVUTSPONMMLKJ FEDCBA@  <;:9987 3210/.-,)('&%%$#Tn oi     wy l  t  !"#$%&*+,-../3456789:d=>?@ABBC? FGHIJKLM2 PQRSTUUV`YZ[\]^_`defghhi1mnopqrs6|{zyxwvuwxyz{||rqpponmlihgfedcbP ^]\\[ZYUTSRQPO MKJIIHGFEBA@?>=<;87655432W\/.-,+*)(%$#""! =    :;~ P !*$%&'())* Z../01234Z 789:;<==&AABCDEFGuKLMNOPPUUVWXYZ^_`abcchhijklmn~}|{qrstuvwwX wvutsrr3{||}~3mmlkjihK dcba`__^ZYYXWVUTQPONMLKKGFFEDCBA>=<;:988432210/. *)('&%$              !"#$%()**+,-."2345678<=>>?@A EFGHIJ!NNOPQRS VWXXYZ[_`abbcdKhijkllP~}|{pqrstuvxwvutsryz{|}~ nnmlkji@feddcba]\[ZZYXDUTSRQPPx "LKJIHGFCBA@?>=:998765100/.-,'] ('&&%$#c g     D 4zr9 (  !"#$%& )**+,-.E2344567W;<=>>?NCDEFGHHKLMNOPQR UUVWXYZ^__`abcghiijkl~~} opqrsstWyxwvuttxyz{||}4ponmlkj#gffedcb+^]]\[ZY\ UTSSRQPMLKJIIHDCBA@??;;:9876 h2210/.-)(('&%$RW! n      xy q z      !"#$$U (()*+,- f1223456g :;<<=>? < BCDEFFG KLMNOOP TUVWXY ]]^_`ab fgghijk  ~ } nopqqrs6z y x w w v u Uwxyzz{|Vq p o n m m l :h h g f e d c  _ _ ^ ] \ [ Z V U U T S R Q N M L L K J I E D C B B A @ < ; : 9 9 8 7 Y4 3 2 1 0 / / CD* * ) ( ' & % ^" ! !               &*       | | 2 3    !"##a Z'()*+,_ Y0112345 9:;;<=> ABCDDEF JKLMNNO! STUVWWX i \\]^_`a effghij>   noopqr{ z y y x w v 5vwxyyz{r q p p o n m M i h g g f e d a ` _ ^ ] ] \ X W V U T T S O N N M L K J 5 F E E D C B A = < ; ; : 9 8 5 4 3 2 2 1 0 , + * ) ) ( '  # " !                           !!" ''()*++ /001234 89::;<= .ABCCDE2 IJKLMMN RSTUVVW [\\]^_`, deefghi 1mnoopqr| | { z y x x uvwxxyzs s r q p o o ~j j i h g f f bgb a ` ` _ ^ ] Y X W W V U T zP O N M M L K OH G F E D D C ? > = < ; ; : T6 5 5 4 3 2 1 b*- , , + * ) ( $ # " " !                0F      r   w -< k  c !! B&''()** ./00123 7899:;< @ABCCDE IIJKLLMM RRSTUVVH [\\]^_ @cdeefgh Slmnoopq} | | { z y x tuvwxxyu t s s r q p ~~l k j i i h g c c b a ` ` _ _Z Z Y X W W V %Q Q P O N M M 6:I H G G F E D @ ? > > = < ; e7 6 5 5 4 3 2 / . - , , + * & % $ # " " !        q           ko     ws  r r  [ ! %&''()* ./0012 67899:; @@ABCCD> HIIJKLL# `QRRSTUV` (Z[\\]^_ &bcdeefg klmnoop ~ } | | { z uuvwxxv v u t s s r }~~m m l k j j i d d c b a ` ` F\ [ Z Z Y X W OOS R Q Q P O N KK J I H H G F B A @ ? ? > = 8 8 7 6 5 5 4 0 / / . - , , ' & & % $ # #        i       =>  o      v>Cn  ,$%&''(),-./001267789::?@@ABCCSsHIIJKLwKPQRSSTUYZ[\\]^lbccdeefkllmnoo~}}|tuuvwxxxwwvuttT|}~onmmlkk0feddcbb^]\[[ZY(UTSRRQP7KKJIIHGCBBA@@?  :9987662100/.-)(''&%$        $%%&''(-../011567789:>?@AABCGHIJJKLPQQRSSTYZZ[\]]GbccdefKjklmmno~~stuvvwxyxxwvuu|}}~=qpoonmlhgfeedcC__^]\\["VVUTSSRMMLKJJI|EDCCBAA<;::988(e32110//`**)(('&!! fM3   y:0 #$%&&'(E,-.//01^667889V>??@AABLGHHIJKKOPQRRSTXYZ[[\]bbcddefjkklmmnWsttuvww;{zyyxww|}~~rrqppon3iihggfe^``_^^]\XWWVUUTONNMLLKGFEEDCCi>=<<;::5433211PT,,+**)(##"!! p~~ {z ^#$$%&&'m,-../00l5677899G>>?@@ABGGHIIJKPPQRRSXYZZ[\\abccdee*jjkllmn4[sstuuvw[}|{{zyy:||}~ttsrrqpkkjiihgbba``_^ZYYXWWVQPPONNMHGGFEEDX@?>>=<<JJ7655433^..-,,+*%%$##"!$'    {98 iY#$%%&'\b,--.//05667889=>??@AA'FGHHIJJ'PPQRRSSuXYYZ[[\abbcddeFjkklmm?rsttuvv~}}|{{||}~~Xvuttsrrmmlkkjiddcbba`\[[ZYYX@SRRQPPO#JIIHGGFBA@@?>>9877655#0/..-,,''&%%$#          #$%%&'',,-../0 5567789->??@@A0FGHHIJJOPQQRSSXXYZZ[\,abbccde2jkkllmnrsttuvv~~}{|}}~xwvvuutbeoonmmllffeedcc"]]\\[ZZPUTTSSRQLKKJJIHVDCBBAA@n-;:998872100//.))(''&&  4Qs    y:> tnF#$%%&&',,-..//5567789>>?@@ABFGHHIIJPOPQQRRSRXYZZ[[KaabccdeXjkkllmnrsttuuv{|}}~~zyyxwwvrqpponnbihggffe/`_^^]]\69WWVUUTT(NNMLLKKjEEDCCBB=<<;::94332110,+**)((t#"!!   kn|{ zh#$$%&&',-..//5567788>>?@@AAKFGHHIIJ$iOPQQRRSi+XYZZ[[\4aabccddjkkllmnsttuuv{|}}~~||{zzyyssrqqppHkjjihhgXWbaa`__^NYYXXWWVPPOONNMHGFFEED ??>==<<6654433--,++**k%$$#""!GFr    ?Cz 6#$%%&&'5,-..//05667788>??@@AA^uGHHIIJxWPPQQRRSYYZZ[[\yabbccde%jkkllmn$sttuuvwb||}}~~}}||{;vuttssrmmlkkjj4ddcbbaaE[[ZZYXXSRRQQPOJIIHHGFAA@@??>.98776650/..--,''&%%$$ ibus-table-1.17.11/data/phrase.txt.bz2000066400000000000000000023723651475513533100173720ustar00rootroot00000000000000BZh91AY&SY3r%>\y@@5(@ @TQU"IRT@*H*@ JAT(Z$Ae54(jZZH@QA jA`4RTVhHZP 4@ +1HTJl lk#Z2F( E-`@ijJk-iZ2mm4Ҵ7{ |Wj2JT֤VRDP:Q::((((%iF/v@Z5{O:j136VV4th=M[, )E)"HEXR(հ}$'ol)iT+FJu)x@D (DDgJU[mf %imD T\ۡ&[ k@"%Tp +UPf$WM*Rifj*m3*.ڨa`m*WքP0m(Z-)Mܩ6J kky*+D@ kH \g!"U;(}נaAoUMfW k6Nr62JP)wS((*@q՘jZ)R E$QBwoT)U"Di) pYvhT"Z70DwVa֡A5nmAZFp9Ar55*R@ vz:M6m  34CF6 "RE@79KXH**%p +$y"ʊPPQP" RBmUAqlٶ;C^ud$}"lRlVe6),#mMkta;3` P+sKAAһlD (,SekR)Ut-$j4[A-kx2&(iҪ n ptQ(%B(å[h*RrԂ`D`RPPvu+f̭2M!IƚhqR*U `g $*M('i, BEA`  Z%lǻ5@ &MF z SѠ R:2iJjUT!MF0 406T u F0L`4 m`s,g@#fj`%@m6`eSA@*[eBTvqڶ0lEnI@UՋ`Yf$ht9ʰ$ljAI2ѱ͢"#{l0JPUz<2k4ZbSJI JBјh`ClHք(+AF@P k4 QXAd(JHD4C"hkmV݆J%#[Tnt v:QPl *l(M PX5-2TiRq*M2[ m5FڂJEH-CTU4 )@%b 44ҳ ގic^lkZnP@*l фwn5@4ll*bcEj ۄh`hT2h͎ؠ-KQE@TJ.ڕQBf6H[T"( v4lƍVPtGJAF4rIسelQT kB EEJlJ l$PDЦ@Tm\ڒU. )vkMPu4l\@T%"Hd@RRV؍ hi 2vT:֍hIPU6dm2Z4@h*ƀh4 A!B k]fJD@*"i@A@J"T S @ 4L OJz' h =RJB*ѡ`Om)@= R LhҀ}BN?TvG%Tw'mS*҈]GytaԨ BSٲIX*P6,P]n̠Vc,66JSt F1S`nWc 5ùuΥn vs%h< y mNA w55n Bnur[hGmxJ̔VՓKFvZ4[^c V#ʹWη܍5 w\hR2ocM\Y\k5 "_]-|KlMD"TrsΫ}X8ڪu[i^P``ཬ`1n!-厕Amfޟ%RFʽJlm]="7R^nۗefRc=4k^9ʚ Ϋ0ݑ]QJUWWoo;:0Iº^y_? -`E > T iXɖU5ZhEnqyhJ6, [%m c@"dAuERW ֙B&+vFM+9PʲyV:{V;W A;W86Mq738^EENijיȴo1 ĹSnNnp֤lԥi4ͮ<Ҍm9-"rOpe|n&vqGu[)#:ެӷ[2D*N,ER. |$|RV6oVnfc +yPcu^sW]y;$ _s,f z:=z˭q;4n] /Qu;WW%pig-DI}NZ عڴaٖzmt8~#ATѾcvDC0eC2“$2ueYL~ۡ]Kx% L[8 1}˴EZ\ fv3 }J{~/r_-7pPt X1)w)ZT7 v0˜9s#ҷi }Zϐz/&a^31+޷YatR{sjSTim>!6bUSPoestܶ]nU|6X'Ddeݸڈޮ#A;xKxƉY}.v޽=AuMq1J3Qw\TչS*{: zҘU=Xs/et44Nw1vuPSv[;yWi]ET "kt\Պ-%|wR=VJOmLWGĭ/rUʆXw|0n#{1M6f8ʼݪ׋Ko+WXJo1m$Z\{ҋ>Zd߸'-TQ |]wS)]F@ oE)qn\y*u1qe,|b/Saj\"t릳AǷ$G-i #w\=]kbO&!lmčݱa/;A90fz;x*;rۭDʽu/w*$aZ<; *#Kݜ]@:ptxo6u'&@ޫWQE9w;L7ov(;ܟ U -7`yDQqV3*]IUkMhd_ѥ[F2^R_Uhx,Ӯd 6e:m UIƓe\Bt Z({^Cxx=;uiL1VqMSMsݦvar1q7qu"ҝ†+V hRlOK*V< iqD>Qk+Sçy`P\0hƩD!DTQaZhL֥z|kyh=q͕`NY.B1)+#+:'ʛ[Z,5f54 ydIЦ ]=E{IݷqV 쪪dlCvcYbe헵teZf]vASl7u{]ùp[U4+H0n-u+He*ȻkAtSmQn}+qz!j=[w`%9#y;ZR{KRlפm_.f^ErIg0\KmUDⱐC2i˞= qefqsV:cXbOj,KN*, X 8rNZlݠO3{*L8Ϊ Hy}n!fN):CM kԜH^ a}DygNgk -WTakzkaW{Ul]U1VKeKfYx8w4z̲)Wgr}̚eEuo=P|v^5lÝ\I vrn8BUVܿ5Wꮺ \x)yJ&$ ۩q #{ʬ<$T%,ņM⮹6 -6!T&Q$a{ϭz ^cCFqEž$ʍA#9j`O+*[\aʎK>[!w/:n*^|D4UWӫY|u.4A<Dm,مS]!F|8ERʦTld.ʅX-P[h-MlSP@2M g>;:Ƶ^cHTڛn$ii/hu'Lא#LZ<=TU KT֨Yݾȫj$=axM&qhwb{ k1Ua|HfUWjoYbLtݿiԴ#hl% ꮢT`pɳy Ԓa1Kӣ.[kJ9ה܊UX3%1qiBt(ϊKD%)ӱ\Tjs3XV2sk+u_ESM7\D;j(B<ϨAS(FxJGLʇiCHB {JaHq>5FpWO9N\A$Jݥ C7>vk\ d&12b:lmm#C@I ,Rshv*$a'g\*2Bkzq bhUee[G7t# t y6C0SaHIneKb/ [TrSN[˫t:ĐXQˎ3mB3]oъ0`J] .[哷R'F$:hϡުv,uҶFAΐ bW+ }%*)TM(D >QMD#W\΄=x}DXmQZD2S~Bd bg[-q\"S$6Ņt(#f4pjڴUsϻ WVI^:^ڪh\'e*aIӖp]\vjkWf;BO H|Բp"`@U@Th,I9+-mOeIaJ$CrJ YJ׸ְVUf zzVVܠ GĈIK# -B09|}SM̰oɩ`!ۤGƋJTMfeVĩL` Ll4"o!nYŹZތ^EF98Y=LMLjKv+]mq-tUK,p՝J:j1Éj"kT9eF5t.nF2䢨`]ƙ6UV$yEqjw[ˢGH{mVf1Csw`4o :Js6j.ꟶ|d25^ O'!j·%Uܫt0]>7c.t\DY㘂Kd].$u/lk ,n9w* ,h%Ya9{nf;Ecәdi2$}A$LZwpr|׽6r!ՍEJUPf3] |Sq@q!zgq >bGRAZu7Y{\p+Zo&;6,Vi @'.~V~dqѴ2.@ҴMp F1na!~ X*!GLwVW2fue-~dcV|Gީ̃[RQ#{NyfEauu92L&T)okc9f%Z&7,)fݙ#8qBU2'RXW.+ÆTh>̡L#ƹF(YH:H/Bݱ UޫCq ^ux>Ľ9u/ f03IuxxA#А6#UTC+oBwcdQ Ȁԅ(.`>!%>nr >*xԡ6GE7up`'v=b& 4p.lHAk ͫY,>'U-b@3jJe i{޸0[cծNnߴopgn:Utr3[r9hIYyCY¢! @dBn4$ >\RFAJ+Z{$I[T1|*k7#'3fwD)QW2U>ft+C ּ=aC$kav:lg 7zm.tJ!Z˻@"8:p–󗡱d[h2!`.LeԢ:B qi c'd}Yf<I@@5ϩ lΨm_HAH0:Ye.nraYqwG"x;\}sEgxFp(갴kS-*f{T.dҴEع)BY@ \*7uQ/W NCI$K׉|8 8RʁK"ڢj6=3dI0$C`ńQ#G@a 8_+wE.6BCʽYo %Ҳ^C(5^WgfU9,JO.t03u5 =kx[*侏xttj"pY 7ٙ2q&?C}u$[vi.vMTrыUA F"> :) zr;cO Y[uuN[ } *{HfSFA,ӷ50wYr^Os/pkx:'v[ٗE(w>*Xׅ//C[j,L%<ŹkVtr].Zv hLΐi+W>:#AKijV$ >&S@` (dۨaU7x}1_g W:Q:sCk%ĽjQXhƪ AC# jdJTbR+;4}Zdھͩ\[,5Rq!Zx8ktMjyy$2^XϙEf8 (W(9.1 WTK ="{ Cu6gS!ũљhUɦɨu\c.ƞ iȦ!"@Fvc#CJ YH$jhf&B(rJo.Tu5c}3{H,IMuCVS1YyZ]I[J+EoK4I)<+) I DZdv 4Ms6)/*?^{ e9 YqW/ :@[#}.Dd2?9eAF\e%Lae >R<'tQxwtuO1 rwL$6G y"G5y "4B[#~?#U`#]gqq^)qgu MXEWSitbf:$KTGyK兟Y:x^}hU*7݈i6MhwUC}c&n; VjbU 2]ս*+P{w20Bn'&:qS8h$8lo6䙒fA2>qk̂K mqxE\4n,>#=W^eh)ˁJ`ϯ.]n mZ4K>|!zc)`P JbQX9;d l$ZAMq"] xH9!\{{W Ԭdo<D-Alޑ@YZ!6!eT7IFU۹Et@#D #lO~G5z>+Wuw]nsR1W͕|[rXO,PȺK3/x(\;-PO ǐm"t",u( (q-m~k1@tz0 )}Pi T,I(],Yf NZvŇ{Iinvu_oe78CCPǞf9v e79*K/CHmq:{v7+A|(G+dd{")7p5.qikRFxS#2,2g Ipo3\aLyij0"Sp(XO%dbb 805-Pt:3pUUp?UBfn@,u$ *j !=lY0JhXղ(B4v߬$(g4'V"|I= 'ohVf' VwZ}yHy6e]P @<'mUNc 1Vc)m[TTWS=UF]ٵQS^Y-$uKܫ]YzɩHiu0Z'n-hMt%RbK/\^yCg sUn:cn 6q\"uaG,7S|N`Q7Dg`t#qCnZYn쇈p^x9)Mf|Q-".5 .70*%M&Vؠm*),˼ B(L&ełHv Q֡ظY'fD!ϘEwe XLMR:Li,m%E9՛@9, m)tƖjcz޲}$X$̕C;P7 Qeʨ!Ǎ$%xӳ񬆏)A W*M4qEzVuU)Ki4byE( |y:CEmuܩBT~tv(K2m6+v|s^nծK¡sY8*ۮ6}̽F;#NR6=) ʪִx|I'yPIZ {/{՜BFif6H-S1ZO"YwuU)aU-̗2avnjJP!lf;[OT+#xmQ6*P4ϡd@pS3^ UŽ * GGHbo&lۮ7Kk#Ȭ롊(+5QiHs^j\\thԻޒZdLo##it_`mߪgv{*l̢vRPZO]G٣aHgcSuQ5j3v^ݜ,<9S'A*#3oV1yW9R۽*hY$*jF &Zlm㘷5#mQE|z,H 85܅Ol|)ޢ<'d+D 7j֩Ljy28x#(y$ZR疍H".lntƀy/xVNW҄RW@o7@4aC@_=ݰ%m1hHhbBa 2DbxW@P#;d6]00t-;|!Tr[2cb"sZ eϺmzVuiR}Q<ĔֺZ{&X v*.9=(hx|imNbDQ8]y.gdm &G6ޛ@|H0g@KٕP27ma',(nL6x!/:ImٷWi0:vBi;X}F'vJ ț^vri5++äq&j?ht7K(OK4FVͰsYX &.וQLו  6v0>r=HtD70h >'+UM. ^,Υ/: 鄹/w]ɖMܖ4ekU7GwRtaMݬK(DN:׍ʻMU]wH{ח$0u0C8%FYU 5HUJ$1r<;.ZGܗ}UyYMYCHm^Dp%paaZ\l }[LlUvʙ d򠤺-1aS_dgZ$ CΛ'@d2݈b 4ȩWm58iRJ0KG7qR!e!-uKv!UnnA0UԱNhVX=uVZT2E^qQ٨Vk1pAbT6J~]u2 'JR5K]Jjg!4YMbz\JόL.H)N#+r$Hgvk`,h,/p\Pkth"_3.#hB +exZ M6d+cRޱԎFZ׹ 4Ij17#5qW./=ZD2WjX h!fQfuCJI5'>d)M3iCmny 1 sdqi7KHi GtOoHf{K9vaQ:jpV22) t;.y^6E|^9C27Խ9E\+r着i cI@2ϸФw7˂L;C#i4*\YDEܘwY>5I˔4 sL^oP\̭7|qC%cWmlPm!po!j$aGćm&fGPY C(CIxli;@:w^yZC#u':ܷ9-zPU!4$S!;2zm]Y*"+P(d-eK|pGOkodP!VxuըHCU TkU{5}mN7I"dݺRc !00a'յv͓o TS<ճ}@}sEZWLP6wI9fӼ]; ÛMdՆGQ3ХZ$BU]]TOwu4t#iQe,e$#H|3*5hTe:]BbFmE\v kjZz}f`@Y#Y3,z"(ȡj.ApD'SKYz;,c"Z)SQ"{[2yUv_… WlŶ7܇ h)A|pbV wwHFL\N(B~+v`ࣱ:J^[[!+oh:Z&&"VK4`e xh]rޔuSl%W=^_AeED bfUSH#%\ݢFSC)5_edu]XyqkH]x{eITI[IW(EV,f 7iV]@n+JV0Wir]:۾;hf D' KŚ/9ϸ % HZ}H"C S/nxt$EGHShzEGsbB}QN43FhnSl%ʜu͞f˖f wy[cjtf {@C;p9V,Yy.mCDkCU]K[]\&lw,# (W = []E c[hݦkndH}r٨.]#IJN15]y *z-ȯ|:J7rN VHq * ȒG8 Me-"ݖ DnܻjeHCg-[ƲEUx!λ5zhqfDzŤg/!F08E2U?3BLtYn xol5u+U8Ce1:eEXnnI ^,`+ue(Џ^6Q{nS6|㪭 /KuLJ/ :D^] i4/}O<%4V}TZ5w !RM^,<|#5lկ";`k54f 8%YvU 1boP!Aku4G&E2"=HfJBTx^<(Į/>Ը9*U;YZP*ӣ"0 дaCf]HEϠ# 0)xc&TrVL=f-sM CHQG]TgxBfMZFSujzR҇SBXVQ G}@>Wn>P>C>6i 76v͡@" PB̯_&,ak7~.&P@{j"zȣV1#tB$a@ԨYڕ F9 Ӈ̓=cLlqRE6A7r'"jB%x ub_3*d":Aⱇ) 8TN\Un夳Y{ƥ.OguF5W \g >-Fd [Ŗ Q5[59cpVT8滕 _^"-/f]mb)QyqVT`dЪFUL6Q7ǖi%,V8/ Puس'Ufё,0u32A(PZ[e{BF0hw 7'2muKٖ@q4娭jRh⼾ֆ>Ρ3fՂ&;BæB-(+%YR*C$iٵt|= 1 I$N>L [#DY7XhYFEi !j6 ef]I TGNpA" wA@x=H!Bq4'QԨl$q}9KƨJ,Ȱ-Y,r ajίiN& F$=Ym{* h s Q `h#KxaDC4Z4ξVjXFΡK<㲘|2>Yd^8ѱm]5#B9"kIӅ{KxF]6r=0Harx#qH'20=R5\FG!4 \r{n?׉ V>B[icdiPeGtJHZD,H2SÃZE"v^: ,t!˗RWܝZlrŹ]mN}9U[Wu-Iaue>J'aKtE#DF70Dfi?)!DOF Ϛ*ky0xd@qh#fZ* ֹ͆ :FY>xW}qkTYi h31 gV (Q$"8+HNr:8eZ| Oq;cS*ICZtEZ<1ybiDŽLE&0 Pt[YF+:5]sSM$@%Lv^.ԧOdMʼV{LvkUg LZޘʆJdm&3VtR#@X*^>fj۫S+ K!G)92U_:<(HHG2{TSC%eMKJ# %lJvy%@hFh+vc 'K$J%Ce8m&*y@I4xK:ƭpMyD:+܍/BtC f$EG%nd풰S4L a9g:PHVbZQ$B{;-XF9!+duftuAh2 $"XOS6s76\DoX:P ?q]2 42ilv:.]"\BH^fz3de=Ϙ:*շnr lt$41*ǬbGd`>z: 5^ |{GΊLpkuV 7 '.Ε{vpSW[Īl91--a %,"Ba]H01B(&'ձe䬫r[@Qf>YƨK4\|NO7¸a+ʐ9,0ROJL'tfZ$%8|ݞگR"kW'oe\D œa/+gffCQ*6gv00 xe)|Κ!MuoH !~C/f0ߴXH:PSDEC =!ؙFŢ6l|ӂXRNXtz{Z6ZD+1*Z5W&B^&Cdd^FMxC-Av"LP@"}YUyUvսbjh-\b03{`O*6JL 4=g^F@W 7$vpmd!N{H]N+tn4Yg٦<+zM5}wkS`TBQ]zB28K!!SQG+K y<7G|! qS +RqVk ]'v$IjC{%Ih\,ܲN@$2  Fu5sS Jto|DYq{K ߱;~{w 4\GVZ(Є֐ i]-t\^!=j%˙\e2@eJhqYINW0!k >2t'"oPbIӫi+-W"$3z@+YJͣӢ) ,HZN"^0C\{wi;<ƅFKA+q'kϚ땊yթ:FҤE,/UYC#H }Djj`>QבPh&Xhj{\(*U=sfچTk5{4&)R+d{գ0l@o+3۪W.޺[LCtlarmaB$c7nTooXC) Tt'6|8Z~͖퐌/r^/V/>|()+ S@F$sڲ `B(TW6ܞ >6-rUNTeyhj`0ּ+9XPiG*\m RN֦m_z:iAڇ ݨl^9.As.Bw؝{u2:tiz{]N!2َGM^*l #i0uIA,Yj}l3Dh!Ⱇ2& HlQ Ho R%j23`QwIv+)0Y-vM>{ӕGLQIG}UbE)EJ(wS /U̠6Ր@E5]W Ci¹zcg3 }ln7 +C%fՓk&r)[ 㕗ئqf!*$BEd!!FRqN}6ń[HM\+>rܷLH@SU4Uh(xk aQvuT"8!8Nv$TA\O3("bHJ1,X:+xr{QPhFnU7´mZ@|uƱ ܌E3يQlCݦ;O&!Ux[&wh-B1kE o9 }Nd a( Lu}Z"zZcj."4 F]έ,M(f 4dQ #\ѦO4v{HM\+*0dE$evKƓQa^J}j+3["A lI qVi_x lɛu7=C !6oH\5_) 47΋Y%,2n8,5yxxO_X]*j5W+5ʓ.wB|0E=);I.OH|HCW6Z,nF<3e6!sw !zw[-K*Cy;u)4u4>d^JSh4=xJ7#Oj'-0Gѡdq+5T؅vht\姥STkdU:BmV؁kD^PPAt{d*#@t8b6!@ERzjTTR&^&MTjD;2!GʎDY'd{f.Ai{k)jn=(:˦<*F$ftBlvk̍B?QX@LS]GfR)]e2fDRF4V66Ur}>ѿ@dCH{ &>杼Ҏ()D&8q,502Sl/q-W$EW 8@c}Fdt8uUKqYTI^)PZFI8{[[ָgoT UjR//rdoKIKx^yyr-3F0鴬Zl۸Bת^ KК 8kwUm]c.Vc,Pf{J¦ҍm}ؕ٦ZCYt%$whZW٨Yz]쨮{󌍄3S7VF;-HtW,rgٴ1u5^8ᬽ̵-8o%COoyU|DwF/̐ |y%ᛥ{ vY޷Gq.vQ<;C/f4dpY˽}@8켤 ,uau_Ct[gj/( LaAj 6{R}K9JqeO+42nuf>,í,;צ(kRh"qA!x፱Mx2m2=Zw6sU-(;-ݒ9@&ey 1 P. Ⱦi[aR.ɲyD{T q<9$YȌOV#wr%qDd5RJA#-{J#q hL(wk7ҳm.Wyp/#ikl+kdakѯq CZ H+:nۡD >WX`$y#0!f e⻱8iIʜ>G̳1ӋLb]na8. ' EV#3GD‚ii!d__e=-^1`gvFGHR@12oʢcNeJYmHJՄ*oMX}iXo[Vh`kV#8Ԉh8!fiyi(gWԫQsTMqJHa8f> b(#0 Y[#32 lZD>g| 86:vdsSVj/ $J2J|`EO;qݕUPh7E#McOTƠD-Clk4ri7Qi&cnHU/xJe"PL\V|B/MY] \%g]QV~އeyydOY~glpBOL GZ=GG"080o"v it1ӣ:@g*^1Wu\|3 ஠K}Exi^ #ӗ (_5qU}䐑 ";l/x3nk"7Slm $JTVG_W7nf!JŖqۯ9ly/ a21,:@ 7@$ @M |^UnQFǀ+w.G&'\C0R;WdiuHqLCIF"0)b^@oT< >Nwc@gDi*!25Qȼ<…@N\pYZB3e=bne+f<1.TT|9s@F#FvD}ؑ/2qZȵcTt@^)[uBFw I_U(AxPdCw96$缃 p9'N5NGxq[ʻT٪a|\v1Ô9[jT l1dM=datA^9ez bI :.! \z%) hS#%^oI E}/0vw-XEoJKv9yubWwΏd m *:s̽ԃ{ץrI)rjwQbzrXUGI]@V(3 !óTFxf6m&E:%4\QU9%ƳArWrB26$Ad) 1C(Ӡ0ZPI|-'Т0EclAC SXQˉl& Z9ݭ]#Qx; nA 01/C#K:Q 2^6׽/dGޮpcu SYT|꥜!{zvE[Хg,r ѳX"Ԭ-pbYGuCD#>-jARY9di0aKoݛ{H$"[Bj"&N."?q]BuVnmޓ15 &6 4tcK9xÀ HGbp{2BK@9N,[[A07f'*I. Z13zWuj B"dsljك\YKhEJbq13kMZJD3{R broMZ}CXAq]L%ZY>&B"%HZ$x/zBHGm,V.j9h[5V>@4U zY [[5+7a)~FW HAi Dp:Lκ+WT~$:2 VIl\i³5kŽD ;{v@ h8M{v&7anz+]ܲ5fUT@",|r aA>GAܼ8Eqade$YY4<8"0#E.j0,L2;> )$AvR| &:(dِC]i\k} h^1w>DeTy-W:* N;y*#}cVicn^^.:r])3D۸"PӂAx,3r*# P?,j0Y^(?a /xCUb ϩ/ BKģжH= 9+Rzy7Hn !b yz/:y~6{ ZdYG iH)mpŗ*E(#> k:|4bZ:7hNjxP6FD" -]j1!ESr=kV-t81]ܴ_VD)@Q />7{RXt*6N#(ʑKJ[{5,%OƐ'A j^tX1 ™E[٪H0daT1fg .c7FɸǙϓpF13qcI4x2=#gDIyrdNtUi7-#D2 ڙVm". *TbB,̽Hw0:@ɽbЀ*^ ,-ɻt\D(2P),`naj1@`-Z/H#^:.+4h* 2caYJ'sȂ@0e9ۚ734Ь)UW5FlA# -nU*4-Qdmb\mC˫|rSCK U#OeM]Cw$e4DYBJU6c. YPGL>,7XjPWiPhQôTϓ5}Ga!d*Q{/ouEquǻܣϘ mTD|JYPP8Wcgbph%aWHQǑtCɈSوQDLZl:ig̣dvk8Dcڶ>TLUT+.87E BBJ7O)팓x"T+ ޡw5G*Ō5!(RަLu ,̀%Z b@&"Iqg28G[P&  r' ՑXNyhB#\̄B* .I ڒ ʨRqd:T5Sp1V-sA#YwFk1z]WN^Uw&8A::=3J> q҆v&1χbC!\d>$8 v[n;X|j.ב(QmF-&l H-+ЀϛZDQ?R(`z04`G{L*0X"9$e}r|- (ʈ(&$} {k;:o+=/,Cr#!-TJITW*&L }F,Piܮ=$R߼nKlEl=T|vꛡy˧fwϵ]n$sg:2! HҠB9TB] ]E^ۮ׎'ƐØC+M+0J(YVt Y?y~_~obΦ3mQ<,mMmmf'(װ_ K\ĕwQpK٩VٙsJ͟JpoeVk["z?778-y)KK.Kl4ξ͍lOiPK0k۬=(;}hZEnNTlm/;(_W~jmZyW/eo\lzgJ8ƕ;Ji%ï Y-?M;҆Rύ6(vW'ҸRWKH{L1 #ãAKSCos.*`]ѷkea?zש9hͤ϶eg>~vj̎@PWQf3C BS\nR۹U]2~qX9~wOx"1>ik>}nmi%dg+ٖ:/VA;kT7GoEDw 3%^YzqQ j2q6 q!ϔ~e⾳H˟/bAwRpgw7(մ3*p.Vf݇5[OM9}Ap7C<ߦmMgRkZ4&7vo'ePQ-gյO #5|zNV6=J!طg $zQjU \&:sPe8vRH\Ry"טT{g).Vw[wRJ%cb8cGGzV堟~̝&{s˥ Qpz[=KrwYLg՟ o5y *~lr9NH]O~iD0/74,YZ<6z]ft%!zY}7sĭTn.h„ٕUrNE)U˾P~Kn~kߚў2D⻘;J'YI^"zM. 3~@y7Fz53^&}7g-Oؑ]ڼi=٥ F1>+/TJҾ8~ѳwHӷs}O,çU[ta a6P6w}zDlٹ*_P,CUh;!q?}9t-w{Lssf%zjgZ4~h:]xɝI*LmTqzk7q?jX{嚛A߮EX)6YĵoLӝiMsfh姳o%Ջ3+,,vzKJ&[ F6-eǾUۅ4o-eed5-(5 7n:)oOQ䲊͞I8?P+5I u3YaERv| J|VWJcM: Ѭh8䡁Nzh ^0]VېS%ÌJu_!v:KT"?8B}4_y\e]0a vG^قVY}>~#CtkӺ6z7E&2?am}{7x 0UXѯ ryh[VڟzI)3ѬꗳX Lt襟ð)o\Fv)_T=0RcZ pNC=.Z;J߀0 JP^B {;XٙJNX O1ӱۻorZ>Ӑ*ܒ츔it2bGppZk [LI k'*Z!!u(fΫ<6V5Lݘկ|*#ok=k`6 );E H@qy/Ӏ`'%^XU "?:",HSb:έ;3g5k׷nX{4LVz7s-No!atz/J 0l[^xS_fs]&C ?+K7Mq*t\c*.+;GhO]oاRi]I^[zg>חn%VqKfJ_jaz |F 7ep<uǟ. /X\V*h,tCĿjljBz<7٭nj$]>U\zP-w+ӥ/ި7H lwtM7f'!!|A>?_/_=wokWdSu(6_ rb&Zl zTyn d:v]ee "ZJпaBy|*R}yQMyC'Ms[u].–mAil>8M3CALejƅ3;r2VJu˝J8m:lհetP+m'FWG|SˎS:*BO>br'quQ 5W?7ooDa̴1K];P]+s r.uiզq<uܵ"ݱ ޽σu]/_! wqhu&z6HrZ ~9~ȷ2\yڙAoAho'oRM^XG*Fz^ 7H!f4:%r%cWƔ|8An"+Έ[߻yo>!nt'zQɦ@թ@kJ4H7sRf~<ռj}}j?Aڝr!彺/~noK*lDgf~3+]jKw(K 1f5{R5ȁ"hj1ڷ niGvUxx/h) =sTž{gQRyږd4AFO~o/:>ٸۇF L/ۿwT],7X|: {,Ns@%6XNxWܢgwoms[ l~ͱ?촗 CBUV$bzQ*9[GrC'~7eR)1-P{ywf qL} _LWĞ s'j w"y_.-J4}>h#?2%Xd_ԩjҏL]'εL%_[3ct;;7pH֯~ϲ :/3ɱ}t6Yp[ׅKb⠺Xx|k4VduތC{Mtp8Wz'fEn<:;A^Ri.5k3(C㭮S3 Ͼ?tMv;:BM;+@ (PX-6i0W6ǪzQ1ʹ{㫥FBY]RQV\ Ox}9|:( <7PhZ #>Zo> O*kϹ",rvR| r_)F3*7ceuG [)@ hi2/J'eghMsC>p2nAZD^m{I]Vы5>cZJQ_>k`Җ[ke:;F7^eja~*9Qޙٗ&p*YgM=Ғ7}ҡ׉Syπe`/ 9JMUZvzӼUl`(Ѣx{iuM3144Liÿ0b)+ӈa:_o/ALH|9lqm=i9=^m4K:=7xreq#}sw+,K{ђtʭE;*N{&+f-PmG 9m. 7hr/7޺}>\t#;2Dۥ6N -FxUNj rχ7 d%A3 ʔv8;zXX"ВI폰/<]61؁Phr6}m.qٴ?w8R3v}%Oo^~L@oB֟<=MֈwpTO,_jzV})6,Ī>~w/Z~hW9NW]fH]zᚕ<ʭHVRQM]}s?Kcz-׹wcu ]ȡ06g襐} -nx[ C {_FzׯQ>zFtO'R5ˣ2c6P+ $){dk->] nQO6mw-"WZª~&L~At}~8wo9@~B:1$ld' ,]XQG8/ SMmD[Gda9ٟW5OӜ f/)t\"O3;}tc6}rmY}C#<ڬ>ï*j7X>#b!!pSKTe,yrJ7=6&^|gߏ:hBàChaIAwQ&B$}C˯n%4xVαP9~`}N-(_l-й^lT"mˍ1Su;E[cl*Gޑ =໱[I;=?ɬ=qcxjl X6n~z|>խ7~֌QNV|۪QD7pe6t_'h>Rwv Oޅ§9|ݹĚ}>Q窒<&M F4^.q}(ͣڽt 4'1 ij "=Lt8=|V0_yBsAoXɓGO!"IRG14_KV3M<ط{RFP&w Fj@*mj fefvmTKGkc7*@UO{ONO=ed7kNQӾxFsU5V]/ksse}9:a cF}}jN@$:5ޅisZDfkߏg }^!^6H˻s#oe|0֭1)Mkˇ}6OCBxʈGrx7 SuboܣG^׹=9`?ڎ&p7i ˖`"ћJQ4h[yq4߈ú9yV>d}k6=i];;?qR7ьy)>hF> n_Sןݎn{{ص y{r~c5#}UN\$aMJV0D3 is!JџhmI~]Ճ HGv>D$>\6[?}P1ҵD>͜ncoL_'oIM^H{vr6 m,[Y<ǖ-$P6{8 i\ !x2GNi?\Sp+LH?v|T]=Wr8g+mD]!}Zz{B֫OϪzlZlߩ/2f-+^nM~k'Ջi-?W2(ա]UF&WӬe4k䋍ಥus^MiiOT|ԗփ7ڦ-|=0ƪ1 9F }|s L( `K}ڋ*"Mأˮf*ZgKA];2u1έطJ9'm͜D٤S4gv7žvqK{J;o rv9P-¦Q|@,s25M9FZsIB_Sc-sR*KD7A0ZZ$H|x談.tT$[{E3k-sz;M}[]g wDn..Nn2M ˙{u8uϊk*kG&y,E>-7gUs&c:43 .AAT:%DPP\ wkmI|;ǯ!䯄EywCmϙk~p1Z(y4h # 9Nq}`L# o-Ϡ˧d͜>:Pd\7Х1鷎fs|VhTOF8-I_;ݯ?[>)ц8v^F}.2J1ʕ.yLsҭ~4ثZ 4~8Ns>{_%at6X=[Ět+ `ȱ=~Ai{Ѭ:҄]nr O5>tl[|g6/MP)^5ܒ1+d7W?NzrͧK^6j|)MkrɚG ]iyu1ϡC׾!%jAUSxx}h)~|7mkۏ:--%Ç:m29ߕMjwn#}LG7#6<~aiMozm8"/]o_m+ {dE?ТRXpni+4j4M}[]rWu 7VnW8(>bC!5dqj#h3{e;5hR]v]qKHݷhS}R|Թe՞rӡ'-CDZ5 Iz,^<;w_E1X;^*]5,{ cpد}׻$u]yb|=}>=ӍӢ3.Pک/ϗa j!iq/煡Rkm_WRh<&nj^}6IS5=pbpتr ;[Tāpe_]/\"A{>Ti1=4BKCW{ H=NI>եeݷ;BSҎS^Vhg !;r_(Bg ,G~ Fm!_qzhK{]tQQCv Iæm[ܶrDϏ5S4'VD]ߗ[JbAJ=@sߪC _%ٺ{Xa(sZތ~ou~|̦K ]H_h |suMk$ '{Y_GLXb4I+Pino6)j ޒdAĜV0rwnﳨ"!f̹ԬVWs qcs5 |y=cgu;kަ&_ة c}|HkQO6brQeFneMR5v~aEo= rzo|qL6涡5[lzy`jbtex;{P8NX؇Mo޴芣xi_{^\iXsJ6C%%-JIER PT!h/͸'WS{ao& Bp1 YR(ΚicD^ϧ>X9 90ֹb]|5W;s[U3+~ j66{O~ILxe()«N_-Ɩ29M?#: l+L-\p_.9C䓍"/~|k+yK޴dG<"ʟ쁭JteM{g[uBl Tb=~= ?۾8;|sp; fSĺx]mkn%WT'w' ]?u?vTcķ]ٿ[["gj$ɾY#-!͢P.׭5Dز630v>.OUO!SZp]n6ysW'L"oK훰_>vUO|)M.Jy^6gѳVիIbL~bj,j[$A㎙w4Tk,8eͳ[3/k^~o0~>F3$KH-L*p6;N_N+ym5t*Nj9MRײ1ߴ0yXȫ|f(9~ Kxwxئ5+7I'MY6"SMuxo5M\|YTWNQ/4++oŹJ[Nb)ӟ|]byAAS`&t{oܖ>u6k-J>`my6l/>fK6[ۿ6&Q8ǡkͨyXG das4ݵg8[I_bFE9t/ vu]-өNɆˍELDUݙ Jv߸94侨e `v-q[_g(uRuQCZ$4gzؘˇ6}B?=n]:D@ϯEVgL%ּ9\Ԉj#owUuGXLp/9R8{,茺Efdo?z9{{Hf)tApY:*Dd֥ΈXGޟ==lǥ<›msK^|hI(ߢ_s:˓?w ^_r+ WW-ĽFmHu./vP[}%ѽT2o_J0*ǚ??K'})h+wNƻ>g_Siۥ^c6LEђljQ`{?۳֥,tPWXgFXf]5nN 4iCr0 Z &L9-$IsL?J~-9<ޝfLwz4]'+GA*5R ͣv3wc[ >UTa˛<)S?#`j쪥 qkFmǺv4G]@.O7Wl$*f|6괦cw^v/O2~e~[pr"oa߰3au?Ov5yJa}[}c54Z: ~W_o^l+һL0yqZ[=\5ՁjS \~zn\#BPk|^{nMWAw)nri/ڧ\.Կ>#K"Y摵 ֿS3ܼYs~si\`X S? Bͻ8>(ӫaԺ9?F+JEŌ14n+vgY6[-J:hywLѩX:dw)Ebqȥ N~iJ<=b>Vnx9'Jmqs>hb̮ѷ.g"ɷ-JnKpdMg8W:#ONˬw5YnZoImwk uHQ/7uY@ }̺\5ςs^-4yӭv >aDωb|"%̡QiToBFiz\L+MT"=AÂ0p?ܴbOK{<ҬwOgyY͸ [囏b}9qmQC,-k@\,WJܛ{{cX\ 7흳wXM4g&[:C}8=x%8yruGZ4y:wj>hż2p~2m۟ª[31xq3wڇ ݎ(ͩF7\uŇz31Kwx_#AqsmdsGVgK)/ҕj9y<*jf+Ҕ~^ϯB/:tx4fꐇw4!``Qdߋfޭ䫂 =VYxn4a8=qu~|T~sO6~XpV2uU ?,},7w t-vQȧynAZ ,\@a`.]MIy>XVe6:JL~+V2rg=~e\vċgސM϶gTx0F&ڢ3#z:si5ssU˩~ G:?+R(KGݧۊ*o\dLr3n+%KwvqʬrÃ?Z<:hԢC%sݛ9]}T)KxVO[.1un>=_~כ lkS8Eḫ]-h#m&iHBZf1=v$dd짅FW5>+m~ܡJ=W2g+^{&!ILY]aE)x#ޑ rD娾\xu}h)ۓB-n%nH- Y]2-V:w2 gGvס3B)`_,t"^R}q5_Xɳܑa J)^tcV̪vB| ^t;n֛{M]M>W1P}=F=/G];^>֣Z[$gBE$7f/Ζu.>xt?CvgkthO9hQd@vpoVJ-ayL[??"̟k~acZ]\S 7qݗPŧ#Jv)Oݺso,/PmUpe:OG}5Z#ɡdїҟwl>R˿g bvq/SS[K14̦zu;ik15OhVvP鲳^Q.m9"[|0ϖ5M,e+o>×gEdPz-KwɪJ; 6gj…ORX} FvI>znSf=Ԯ"}0xyy)y%T7ܧpzwqFEH eA5L>@lvQy7ܽ3~iwAfQ ?_a?L]<ĔUB3>~uG]Gz4{h;ouKʾm~JN/ w`[ |بUy4— 9E,e> uށxho|ES%:Z숂>nbۤEKzð!cm󹸙 9{+(p Zй=[zNjΧHT~U29%4=6hc,¼X4l/T׶]/9>ay0U࿪u4;2lVcV mIHbdP< 8PbP'i+v3]%;o5^3zwÝwޯδ!O <, qu+q~ۈ_swN @ϼ~d _}S){EV3'80iלq(1w6m-n:=]I+g0!\ o촔V6ۘbmB%N rϝ1g7Iz6TT7V-flVd̟_<kFxa G^9%+3Ī=k.'dNe^XOP#?hs3n. Xybm UǏvQ$$;xk"̋πjudڶ:}e7͞zߧ m4niPDzZӷ~JGaYt|y-b\VɟFqί=,7q{t)^ܮ)oAc1Vd'aCaq:sUu=۽ǒ?{N|Xpo땲ġ.vi}L\7wO3+G:nL~Y,뭟b#T3/*sNf=U~6z>4> dliʧN$;y 1n?YY&oKmZ'f ^hқa$'xߌ,;jv_ZAMa&e.]a s| P`lp,ҡS"Xŋo{^zYj}{6y\-7˛nNP >Z]3-p0~l{ŖEoM9zw-jO=pcw)·;%IVs񺉽l[.djYuc)6Ӟ&×L|%A[kd7קۅof5o>g!8svztAR"Iz׃g:y`ԪیgcY:>jJ$vTñ /X&7{''p?[]=|eڙnib2WM/Ad`4{TQ5}$!Z_amOhIzzj]^6j ~H͟2kzfFn4JGLeI\f] g[b F@N`[*ƽӈjmm?Oo"&'nY;zx KM]L`M!ek}}}=-_J,\Өꬽuc޼͟~ujѺ6~y T*3]mS%"Y:p^z'd%-ՑwUƁ@Zޤ%1td߫6C7 Y3 g֬ p} n+MéDo_FͯY/lsG-w۾ b鰷N2||Ojj.8]K{f.Zxa6:I1lb56VE2n,.y{UT۲zyg/b\vTJEC[>y~%<^N7/ӣylyuv)o[ NnxJ)۳Sٵbp%~wEv1*=c%3g&Ҋ"\]ڠFp-K:Tg`{KsIOОkz[VM'mo/tՖk\ZtIL}`w%T1͉SDs*S]F>p w?NL3Izs#AMt)se0ӵE3Ömؾwvg6v,C ~RםM?NK=~Ge2eyτ G#R[Нxh*cX#sC͟ߓi.^Wi?QiWLsE?gdg=+}aѻuÓT!˟%~knuw\l[î Vjԝ=q48GuܫZT{TI60Q6A_&$Won):J*Fz*Q`ruĆLk6$[\Odعo[8ǂ/,Vߓůeoѳd;0(v\(8<ts+^J=T1lQB tZXɜ PנzӔ(]Q&r &9ToN{<13<)Pg^\s{:T=W|boSe: wqbxҕ}Dߖ%y{rwĮuqFw-9|tu컧ð}}ϾgkK9uy`^{8ı?̋zus-l &rqӱid huc"t^{p4Mf48:aOZrvxgqEvQz%Yt,<{*rvC:b[ftSe[[4Ë[VS+.8ʮi?K"_Hņ`ǯ6VD4$xiѷ gw>qMڛaNk#OQ]'cD}@lǐut ѵDӠʫ&/8 aw"uÅՅۺnfzR}.7tͧHhiߏƁŠ {4‹V3$O:0\oL zpܼf{݋kt#oV2YWߩ,+mi]lU( 5z8:z//7d_txS=}7wII55l ܼG`O[{~| :-Z:=!._>CEňqmlڎiWFOfͮgc՗ʦ9afvT O-R9)e(-L?"`W5vիlۦOMGV*ףT^OcumbNqC}9B1y;a,+]|3S5*=ʛC7 Fd*UX f{>y;.A$=op2-OثRfΑ|8' ]omse]ջ[dtd+kM ){pnt1Bmh"}9%៾RO.VՍo?i{CkYS _c> T7\ܰW붎͟6S,"jU2gfT]z!ݶ+>:>3J'&{EnqD5ϗݵCZ]d>`l8&&ާ\tt֛0ot;58؝egN ?Pǧ/?^wZ O>f_[>~qfVs^䞾:24]֋ z^]N:ffC1.;_1ҽ^#d}cfR}=uI"W>|/eJo..-jf>8-kTu:oNr铮kw]ZywPaV%AJlB+/1M (t"ۣ+f6ɡ|QL|e}w~p[L?B =}?3d)NtҮ|K[3qvo|Umo~IeXiGKi|X4ujN-< 0 ZgѢJ\hTF r_tMa%Riwdp+A yk{`G-V_ Y,^$#߭D~gMaiSѷ_=)ZǶ~NЯJ RS[[MN+FTm\>WeݻS_ 7$~yx13h^71tZ٩i WJ |rlO:kͫq5z½\[<?a۠v[g<ɣN8Ky5vKk>WﶜZ޻vpsc+:Kcxݪv)% 0ntFh_fIW*BkG&v(O,]_%\Ǫ_WУyJauw:h~/sحWV}7Ƭ5K~{h)pwGڃz8Fg|1;Anr2 NfN{ƕӱكŬoG-= =UyVw7{ؗיnaӃ2ƍo?cb.&mh.[/&~Qյm ([ ÜT|/OǛ>v>YVe؃ޔ0Eu7^uczE.EkOE(V>L:wۉsN=Y+vcx[Z)j] mu*kQD 뢭|+Ve+omI} |um XV3,ʤ\_\gUzږlB߲>%{;3Ҡyb}!,?'/Inشm0/TjLw\YgD#wf>e= oEo'Xu!aD[:wF\n՛2ton^['[8 S>=܉=j8B,<j+-p۔prby]MtM(2ei؋W[w4p9˭E/C˓;10glֻ\%݌JP="ޏun}WT tIRzےi@]og:ff͵Н|Wm*7屢[U]n b3i5T\b$4=Owp{k);ɒ͢Mٌ|6]}?Co ?OGR]TҪj+j6fhw|Ҡ{oJK1O 7yXPm̓opzqOs 鏲hWhdWY~I7uhl&RQjY>C;I oNTRuO+S+8'KT"2>9q,xȺet٫Ni}UwK;uwpg!ܖsZZǞ4[{\ ri_F}ٽ+O%=skt,{zK:/4:55BsS48kUY/|>ɏ'#Lz+=q{ΎŽUilC᩵4çva>Y]]!^Icg̵mcůK7l/- ꮜf}:ueFήcsN8{ ,zVX 36!mw«Ǿ mz6Ϙ'穼U?4UoX/ڄ#~ jP})~Z؆N$7M&l=<^LK߷-6.R]sONIoׅ}CeFw ^kޜ)fͽwpMVq8} a( 3׷ϩzE} 2bl=yx@dكGspiM&n0ڼo9տZk~HzgmeN ޹]:TZ'Q0^[pM}}R OOv̞9 "3V^=bvLXSCU_|N9,. ϦY2ɪ(pwk:yjN;+(BG*n@3c%jys_`ZuʜpwK|~}lVvlڪv>!\󻷗x16厹훷O&OΦ?J^:*iRT_4gC;]#(F^n`}"q)?M秪R]b$+ɼS6)rYm6q֝ e"\[c0nWÍ[,|^>7Myב}*ow楽J~zfwGL<;%" "|^{}|2R֔P==LScxi0В ΗKm:1}ojv6zרpW0UR*=4S&†jZ늚^ܿwiz]mWSX)nv?DVso =ˮmˤnw˒eu-no$_nt3 vQ0W#K <6ܪz+vfkvّ{ 6.U_TlߏK lܶ_>$ssyKgIT٬SK}NJ].ߡ)ۛNmmjvm,M ߠ~3d1^Xe_;5x:E:Fw4ۇ4MWj_4z`߮Y`4=yh:T ^k7rzm?ѻ eCt;w^ l.4._[λ2V7ӵO[ʵn7!8OEwG_lWuI;٧kͽ_V3Sf;⟵z ~gOȄ 9%-v=[y]37Tv=l'w' i87zc/Wc] qfﻞGsR.{gZqꦬը}Rl[6}m~g{Z1SJ{G]Vܧa|6O5|Wg0:Ż73[_[Ik.M,R.xo&8w(4oqL3Fߚq~3NCM4/Wˮ~ seH;Ica>=~w6E:A;DLQ::_nyLKsU۵JoLO+y-yUۧOT%׀MgY"ѫduX]PU Yg+qҿ&iW|D]p,ܛ/?l{?w[ޚJAJMU5BR.ն=Q^q,qC~Pe\!K9{cěpo|UiֿG[epI5?dtx:#ouN~{~ B<ͧ"EaU6 \(U]:͵n) ف}%P_{SX6عdJ\8gPng4pÆ~&og1[4nU7o $_l7O7Lw67>MI3sijUR٘ j68챣UxUߩͪ,_>;Mͪ l yOδYvR>ޝ|sqeblwkM+/^ܿ8Zk`fM fγNf2{N&sz'>6LϏo.)קoPmD29l +ymwx+Wo4L)e(hӓtƭ>f}-u~.WON' nSz7[(˶PY%Xw?_% cB&/r-y+uwV߭ WS1n: iΔ|H$Ԝn7r֬:N3Oڠ]gMH͇3(SrvsOў7GAtAg^Gy盛H+ %dJ2׎LůꨩH)י{t(kY ԯkG 3:9h}Cvyn$/Eѱ.&d?=9/8Ek̀g?g>~Tjg ;Mhkۚ.6};#6؛I-4W9~/<)͜ZOs&Դ>[-ؤwRVc9߉Q s?dʜq} Q__6[w>^S(~M{"pzvzv b%OUh 5K*SJ=+|6[gox-Y}^ړo௉4QzGGG{Q3>({eS{pNj)] kM7S.`4υ=NOu_ҚK[g3W#gw8߯.~*OqD1LYbpQu/ ng̃yR,tnS9UWasͪ&VH-~S+Mh><}a;őTU]b է:gy1'Gx?bﹿYaI~zXЦĽ7;媕BIX|Rz| xY?sA D84I=$^&*NJ>he1sYs3Q xkSY}][&v;kOrKhmL|G4~SV{c} edƾeIëN]Z]UK:%jgt,ܽr*Km{x|xtW@Rs?eA3>L:|sK7݄cۏ/`ޏNnUv|a݅Rǽ2uӲ;+΂ đ yV|= RoĤFΜ휿3~zf{n 0޷&X|׃pOyOǿ_5mѱu4rucwcN2rC6՝@%ez(ͫu/n0}uַ/>pRitU9f廰: Yo9S853.xsT9)w]\:&K'7)4}z>]Ituoh&ᅞ#zڤn w$^O*=1-ȟj^𱫝x&U~e/bnZ'w1SgϪZc2Tij=U!o{^N>_CkDqxzKaj3,Ǟc+6?ﵚFXѲ$jfY2^o'Cn>zxgHW~-F؊Y՟)-]>X]'C0K} PhYǑ=ֱBwDע .QRuw+koijmLqrz{^g`ncpsVZ׎^|]+d'Z[!q{X◿y4˜ vXzQ|eN}S^j'޹ulhVf^{e'h5?;}2E'o(Uyx'ۅwjъ U(<:? ǯ1/So&$sBOޕOƘa\{ m1 _ 9xKK?Bs;&}{pY+|9Fc (w3n9Ƕ[ks=|hwMͳjY) |(enR0b`;٘3{Xf:jsR靀ٛE Hw ||*"e{d{6~D]qls$oq1}8{H.oٰ>yQMxkϣ[T}m5p'#2ܚZVa5ևYu~N*G"m^T.e2PP|_qX>f@iu0 #4KuQchS~GMOš%Ng|Q;2pkG_050&$9ԝ5I̟nDEڻo܈ ~1ˍdk7]vyc<ۍu>%aMK-g== vs娎eןZK:ozjǓjsߵTd۪L%vNor7d5eqrnm\i2P};=|6Ki,OEod,k*o|ɕF~K+AdE™eNRﷺoRZMgfwu3`sþ톭mwx\'v?c̻M“߾2Štх<뿒vJY5\vEu M-?ף9f}SZwI8lU}Y(KjsGLsYTRVC9>>;/[62}]wC g~ٳՌңYWGN]ܪ>:ÎTp!I>AP'ʼnZmK^ʍoǫvٝ~z37i| Tq:r)|Eg *gli%ӫYQ-׾$Շ]^cG2]KZq:zEJ4vg`^&΍:}xrMC]|>yv5~r{5eի2%VYO'nKmD/rt=to6ժ=VKϐ<`&,L8;y(Ӷ>}HLq˱(*v4]l okR=̶N;~|Yf>WjA(R5Z[318*4>H+TMhqImқa;zMRaſgen_ƧKBy81?A=rF\|o=mZ O7꺏jnrXAə۔;/>>{Lm,j|7;yK|,7=aWK{~kSfS{~"m5ONLˇ-;O^=J}KO;uɂP #w7+iɦ;S8Eb~kSg_VNȨ%Lb_cU9#ٗVc;7V|r|7i9F\Uau赮{Yzxmvi9Fdhds[.79KLxn,lͭ7a;0|ѡKf~}[cAb^dG3gWvbKfpRWY[=O~gї5]AnuM{"Kk]ޟ̩3n+ =*3u.Z=_%|?KxZÒp=fYs\5+?Zݭ H-jG^]FU^gexh猱3pk*ى5ě-k|؊8Wm[4%+[ZRad^`f6zi5\^4 ղn'YT( n?8{Fճ..sC/eug,:05D9 bBr6ܚjwQfpʈ턡 Sǫz GY43|,[ %ȫB'>}v==6%)l:6W5et*A>H~oԿko,x|bVwk?jqeh f7(^{:ټ~Хn+|_<=l_\Z؛u5Y{ʕ?"MVj7=25nuz^O\-w=0ˣOymm'ܪē)ʒj͞*y<Ԣ StmÉZsZWCuWS i/.ڛfmȧyj+Na IͩKBXwÔiK>mz77%Ǿ [6k}-}8EO}tںY_ 3[;}/4VUF367߾lQ=ǮhDWJ;ދ ES0E,5vs2gwridYswF[G,dYף/^Kc5ja/Kvq{4'پxE;y5M3;ÚF[[gaxu56y^jyk;ЫL̛9T)"j?S\gUpRmz^'NM5+I~=?Yڒbxftnaεr- oK>O|zrB tNܮdP͆YkD]buSCN!.I5cXoǒʵ\>6T`EJJϮ{[ F/ԧoVbsp&U7oL)jይa*ހp.5uE ky7nؙ{'14صS4jR׏u:(_֌$Ҫ;LK[SmaUYkGiJSncK;IכtV$މL}"Ë+PǏvz/ӇVꚮŞ|I%kӗVTem>gSϳk9]y>Uq>no;ŝ^Z?tO lUjFaKǼZ}oWwӱĩp?5 j[U2U?_Zy Zԕa]םD+Rτ֤Mfol´w^38yzMX SxZw"x9|Ryi9EFߧIyS|PXnEVT5~G>q)G[z4z4 /Gy7ߢvo[O;Eg ߱wΖƮu6w\}ιύ-.ˌϤmz+ᢸ3:.哲\Urghpx˿ka,j4SL^MKFmM6f-k|QD\,rkJ'_v^4MzX;DY8zw.uq679UόY2#icLQ=,Pwi*&#-\( ԕ>JsF˼gS<_߻)5Oq~LXmo0oѾWӺU?څtu_b~?<Wvv3qjWuǡrAM䌻e%ܵkQ s%W֗.2V, ~Z|C?+> iL皾Cζ_3FKw5!|qȡOӥ|}O4뻻;{F0)QYwPjJ4&ykpKdZ3A>} '֋svݍo{S8e?|ݢ'hV?kwyzyvPOd&m_<7N\pn}UUV&Y?7E*=6)vۍ^Fkܗ'lYӵ7Owuu"uc;'2z`gb0ퟌ=lfdc^r}R{sA[Vƹ7MzxmMS랊>e}U><ϏrǯO3ySr\lӟ7Ļ?KlKX.=ُ*M`}m:^;kx$_Op=_z.VDXk~_"z}xuUVۓi֞fsŊ.\"/E]+ﱳ9lN{ό廯:<0ŕ4+,Lk74^hhL<3)YlmKSʼ;韮̜b27szyAyKцlz[ϝۣ2譧c?:\s>$;4Ut~/VGUDwz1jglwlMQ:󝿜9;l0af[:JVtKaYhMziJCGTW%(ͳymj?knַ./l^LF>;BlY}\]4 {^7$EvU!=Xǽ:m\$oaa$fw^y><+읍8Afӷ/2տCJۭ YNfmY}:X^<|(qYc*.=# QKXab~nU2#:.)GUחdϥ4v%FaOws~9#.z#zt'XP0^7zuf*^0;}at>}=4(~Zt+O?&ۻmnUņb|XOsݎȶVsj}1`,I?2*}ٿ9Gbj[)x̽<<]I7⨣̶p#1Qr\DVSǞגN.S9&l#}K/"ێ9himM[ٿD;^ {W;C(h^ޭ>܊死[\9mCcoէ]^N*Tgb6}kae*xΈ/ҚteҖ<"bY?8C>ȳXwM6q~|4}wݒ=]5|Ϲ7՞"J0ړzSeD}|{=}ʯMOJkB4ߌJS35iPuUҽQExծMleؚ,IVcjr>J|>ރU/}~4l<;`ecWkbl&ׇrS!rl[} j|/wxwqJc~pe}^y܇f-,ԵϭvX1ܱe֟.I6?5g$QO{?_r٦6:|:֗C/z]Ent~Ige?kiS7$*;hNf4<,OGp;ԹYK 8ĪqY<8jꧫ/1ONIF.mٞY|W;em;)j^LͯU)S(WvZwU:m1יu5.jɼ:s!O.q +量ŖAW}]7Ҳc^Oz/ 9fշo/p>EE,w7kqg?{FW{pWIgSTXڸsvR雷m]y,ⲣ t?"Y#JOd}P]iMѭB?x܉&s@tY+a>v(*LWj'zfmѬ2o,]auLיv l?[R2o{wο7h$ aſ-B}TOIWelp'Cr4S!qM=m_JU!y.*g1Jv~VipKE+Q=ޱv1a:nՔu.3lW~MJÿؗ-ӟ5N|}5!^z5lݜб_w-[u">T%,ތvrH+*|ՖߙQGУYԵoJ9د3|ǚw{B2rsѩ!ytgMZ=[2|~u~qmhvv_6zt*9ٖj~Eط> <} Fx 4Keii}s9fhwzwrCr?7N[06Tp}ʭO#oN}z2 >>nM=*MUe5axIMlLmMf5˂ư aj߳RjS?,'^ߜkGm9a$TO4]On9sV9aezUQ6xĵ$,GjłӣM&]Ͷ 2)RcM&qw&_Xyvҭ < {3n9˧Zk آR56rɂ X?qc[}s] q4V]MJr.,06@)&fqWSQ!WzsC8Q3hiF)|.žQe^SWXJ%vSqWx*ufBL }M#߳VcaR_s*Eϫ :m3Ϻp,]mFRx %iկ[h4WƜ>w Pg6yٲ ܢf,ۿm6s[n>)“hE 5 xzJ9ڠ鱻VیK0gpjKUYZ={!𝑛}+-qBy і=Ƙ'h+.nWmfa$a?d .W~\dO`US5=yWtK5|٨XT⦚j2IIt5ʞN5N0vLM׮Rɛ:[=_A턿5R&6E,o4s%6S%jN; /(N8- p.3v |:tIڻ[9gJTj˵}u>)b43_|<>#iO5c].oBg=qm~SڦޔΛ-A׍vn\nG !`4^f;K&fQކMzG ׹*` فvW$ ;t]LKL7)Ϯ7M:Q%bKh*;i3t-]]JˠⲾJ|e{s{ECq`; hS4?GaeXx3CޠC7[]Z$2TGz~J>LfFswX?a sF쮲{ZRAyȻ3:0S-3&:DAlq#]$T.נVԘ'O[J%eEz[ZWkR02{Tf褺Ne&ݺ[,aS[z:B׳a \l,m[)\pM 6rUil$g؈_f1oo=r$7CތM>̵Q[({ua}tcO&٤0ОoNtΚW]2'Dly$.`E\|/|_.CwMYj:8g4SK}r&.iz3sNsE7qGu<;7eS5ǣҭǸ빷҇&6 wc^2oz\K|Z㛱,w {JEKyŜZٛ_哔kh`Y2E=jrgv>ӧAEXЛp(sQnn1s%Uz/Q~J5o{%zʴo2)l5V;[KO~otx3NQ>ItҼ#:&k֠8:IϺdsIQ0ׯ\ժ'oKu\ܫ 0wMUv_>{\/W  cy67ߴʹ7](\SϺO8{0GlglUNl`}9]=Sv< |l#cn)_G8P%N5ҍyQ5*5`WLq}MBئ eciOYRX~~ջǹ7[8g<+Y@]\|m;$_6K*tl \n^-i^}}T'V΢mzM#\[vmـ#C܃Mx\x^N&ot^L+\ c^?yOV z$eY7Zv`Wk4V68fgzoGUU>UrhSrνHOͭoz^5ޕ)3̔le^Gޛ[[fp}JZS/ \[ߙ\u_4sU~5/?^</;6sIG|yYX?5uj%-jOߐ8W/ӥ.m73 -9{<}r̡*aУoR*ps*6cϢ) :a'3)e3h%FMjS 1~nObί?VfmMTi}'q 'rRpڮ̓ȚuXTw鍗W!خJ௹5 pAT1MZE^_,am)u% nMan5Bϊ ;Yc^!ti]r^4GNl 3sR~j 4/j!rvlnNT6?\ aZux%lb.TWxOLxv5GSѥp}flv<DzIyWOJrc}ӷgCSw:i !Bp_6'{մn]G)*tk (fv)ʧ+MӎϒYAvu{ڗ:ݙSlWԫ/߮k=kާ_vh P]SUY dl/ (8i<\ѿ_ngLwĄқ ?3 ;o>7;ӬlͧZT<ݼSQ>oZ`U-Ү#q}q#~S%m,U<%bisqY%V},JVݏ.SS/{~ݼz͋NL3FKn,ntrS kfZ(QsnJ>%u6'tWbRۜ޳Zuޫ8& {=bo_'%)}{ ſGz{Z>UgH, iۥ'i_(q{}j(] J-*ecizөeFʝ+Nߺe"Ub9Nn5I.v;79ݘ+]o{9+oS1`wg3K_߶:yXyӝ}7r;4f*fpI)җA| I g݃JIE}r5F7ŵT}24c:=1ZslBV}n(ծ00ȘٞUCm?-mۦx{5] 81t{>Wp[ q;:wPX3;SWJ~o +k&|կj_GRltGR+-TIʙKKn*Xt穯F|~ǏF^۫f @d|SZ7-Pq+н߇m5T,58bV\=Fw-qm۵CZiRrkZ'j`EJv][vËQJ}j?w%;zZ1(oegKl}Ue}Ɓ4KA^+qs[R]|v;ogkuo? & On76DeV+A%y}6z6n~0Mn_L7x m=f|dm-uTB,T6m ?nU8j"RFֻ6֜#Hܯ:Źi:o2N]f.3Nw sze SqjfN'Z%0qv}8kOv`nK b|}L㡝߂\n nEwmWNg{ ue#OOߵ]3U}6O}|M4ץ7;ѭXlٽsspckrjSwSu+Ǻ)tOlٻc=z۱aڍ+3 *[+,ևzȞ\>nhs R~k9nM. ~O;2n-~'MIp0M!ӟ_DX3Z0孫!K,Q Zމ+n{2♛GjFRlOxǫ67vYon`rSUk..V6֒ǶcU~,Vm=\2 ]ۛeu)xۣ^R~9;vWg?h}>~U«zWKT~ ų`\nf`&Ӣx+[&T߄/մWcQ+ S* NT(.;]u6r{NU#PLT$Նp Rrw-y(uN˚g1y4pyf߳זʭ /Nv T;lZfuoʼJ[Ֆblnmݷޯ[<0,FZi b梸 d=mH:-ښX68hԞk浽+xP=bty&r쳷^SBo yjb].}1bfn`ǏӢaBZ3ÕV綦>gs#Q'LߣÂҿm21TgI;]%35vNi*_a.C)[x*렾U,r731o;9-w54UQ6,QYx/^7_MRzu銌 ^(z1eW݆ݩ;܃9K tijVusy+}īkCJo$k.Fr?Rwjgm9ƔF|ϋR|͓9~.uh_^F`g->ٺ =ͥED/{⚞]K{A3qy,.#>絁=޷;J_|!%$^+b9=GwVgbZ-wbEpsfɅ3T4n0j+~%էo-i(p4l)]RiUB[aff8}K1RTp6sݔ񈿃kI up?FLȫI~|u6ܝ?{DN3{qtN/j}K90Q#:}Ϛza~"b7nsruWˍ,e4^0G~<ΎqS}cҺ CF4iB͞E9GݺtU|Z[,{W<7F$ƚ` Δ!f|ѩ.b0_%brNm}rߟ&Xc:<{xttXXPsOڋPՆcG++[i=$e7_oŏdmJy/ԖtQ6p>'X`mT )gГVEݬ45%r[6&ss-nma3MkazwixW^a)>ieVңR7;K_i)θzx=n]|o·y|[Ǯ#uevsLk)۟ͱ;$)dVaOrq&48 /oKW hW6E5Ӭin:}^\RH@Aolr9o[ jHȣfx_,"˒|^D'VM/ӗ{:pyիw맾ouoXΘ2.G{ݹM=U4`?=WׂqZMOaiӌsbc wja|چp4-_xgkSkӵjz?|ǷWB}=kٲl5ݺ(_[u⍚v)oiNT޸峖mz>wd-+]"6Kw칑?nSjBʜ[4 ~ѻqwNc瘕lp,m!zmpPWM̮pcM ^M{%*)CyF3a՜ܶsFaO7ViT|gDF՛Y|_{RN846ܻt%EN+Fo"HrHnZ M-ܹjsH!9lU/m*0|27IOG\dɪ֟XuMN hR-v{ Ό6Z*wg\Sy_۽˾}L=_w!'\Fߦrޓ7唨tC>gLs/<&{.{jܨQڽl/Cܦyl[f :\:km* 1u<8zhwޓ?}ڜ\9.x5fj[e|.ڙK2ZOy mfC| qq&k|)3rBٯk1WWzc~oimyҾ>s1n+RܬrόV3l \}N{0HSŗv[l Y ڠ2|V.|utR.6fӶ]pP̊`mՊ~qM[ g|Epp\!Tj.՞{OG;%PR|P5Z][rqܚR]jަ-z_ǥ\U+,BLS9#Z{ضX-U|{ 6q9prxҢ+Իs[ƪsvOWCϧ}nQRBJ*O*:aV !uoT9?4-cFJZ3ˋ>S㉮x/Gt$;7?Qًb%t-MdzOUFyLߞ),1:؞|L\1tt3 Ih{6nAG|>0w^G45O1V'd]m۵Q'm`#&)2Zf|O%~{sؾf9:_ܣ{[8+'4'xsP3eه_6I^yh7/Tݳf|w? כ5=1xVt`ݗ r(ٯm< }J-凟^ZN,٪>Y'}wtO9лQ߿?;S~\SϤ,1]wDYwXQ)en ]6[qrc]kq"um&\|URZQv"ϪƘJLX;ɽeeMŗ͉jQGF3AdmLȧ*c44ֵaI?q*eܜQ}mm*ԗ:>j;j󺽻h'Ruގ1Ϩ4ܻЧw2g@jj~JYݚRuީ=do=,Z+M1\fS{ڱNF6%.׸f*ҿ!c.b4c]t .zg1jNmј6ͩj]߮ƣRԊ=w4|M݇U$ ;vH< of*_lLk:GNgv!WvU͟B}l\sS_^ճ}L]5[ò߿+mJ$::]럃pDE#5^^Ԯ>u}w*&YZcjLEǰPD{/)9ɚGЯ- uFp3hwsH3m|IlT,o~j#xhhcIH?a/ 8! Bڄ#q. @zL0¡, H%`RB\ fjL3ʳCu(fUA,S%ꠠ,RG=_ z^sBaD%}_(lP!?0%|aO/^-y(nqELm5fuAf)S *UP# nՑtK``YEvdCj]}D8{G(k䏚HY¤1i!uLm>4^4E?t $Pé鶄$ZYni"ٚh0b̜dD4I$ &(Yt44Bk@$COY ?>r e[l(zoطy>~/}/S Ųb6kIvY ET|ocT,Y&6i @YXM\o $ +L2b vmƍW6yyjI|(0.VY`\sa|h3ˆdF,e3,qbHS#j,).F뛛_]ڮ[_jmt_y\_Ư[shɒMP+5B(lL0Y_5_.ך*mՐ,d%7e0W"U6ox2b0ZLBȹ2Q*Uv[| m!)1m X0Ʉ tKWK$1`a!v6:ו6ڿkm7E[_}׻ǦB^Z,2ڶL5Y%2k 5Z%!RY]ɖa ZBV6% 5R( !LC$\DJTU jUA3d5[~j?וo4QkS:H].2.b2n40d%r6ms{Ů_uR gTCF`0H` ]bE!v. b$f&,V56_//rHYMP.RHh2n9$I&,@%RBSLFP0P)vD,j]U K9Td.kz -3H(SdZxi8:PBBJIgҡй%Y-0B үB,H+UU) d n)3KH)N(A@:^ցT F')2,ѓT-YMf] ed L.`C*].̗`UlkiXiS T :$5dɓFj1bMd˰.j&*aP2IUk_f yyZܶmv?CF* f!4`fŠ\Rh` @,d IL=5b6ZJ2RY,%0Z1=-ymrߊʨՊW6/[Zat+VudIu@!,H`)7 .UnkSy%򽣅X1eK-h|bU^Wcp^x[m[nW͠K34) Dŕz!fv]"$ dugVMXJE b˷I D N(u@& 5f f“*u@Ņ,%$ɺ1n,%َ8LYŴJ-sFrQdl^ϝ=4|-7y~EU{YCLLCTZњA&aW h%𫴄ݹSZ~5Vo-rRlTcwvuoowךkWNoE*?nUrmmy^ZZ;V*5{5o~ֿY&iL X0,T0K66\u`X󆢯o62T 0]%8K0B3rL2 *D3H]@6km[UQH ,1d]0I&)kVߍ_-b4VmkZ+V.mo-$ @J@Q `5a \XG Z` PXeaL;k|67ۚ}\~mͶljo_I! "S0փ<)e5*M|ůۖ7`́% h֕)b IfHJ`j5`3UcU~6:mmjj-k_[M͍EZ2V+DI!L3IL\b4L^dRhY$3d& 1jܯcOﭱyGuÖbnU_UscDVZ-O$!`rLB~65WcWm2K`] T핉3€1f (ֿmUk~_0Fo*KyZy#Fƀ$:n,Ja3`bɚRµ`ez  )͹QPSnb+oӛmW͍[[VyiTB M2i,hЎ.2eRRb!tt5l& B,1K0@`)2a1I Hfl ,J4Je&)IL jhU҂ MF-$ X׬ 0l&L &HH.څkxYUЈ,)0f p% +:I!kܶ>ܷo/ͩL) TL&`CD$Řb,)b$-HKi[\Vkrتm_J~փT/jd" I,mj(Mn[jߋ~صr5e f!& B5 KY! I$dF !BaEЁg$L1H,q .RY&l!$@B`-m^U[AHlbYlK1Lf*5W-ViI3`Iedd .d@] P 0$Փ&K0z*S%I1e"&i Jl ")?Jm|O[5NcME Jef2j B,C]$)h3 %f2E 2H  %0ŘP|ڷ6ط-^U G a2#Aj-zʯڶomrVTH4@5fx`3 Ņo͋mkWݵW$Y2HK$]qd! ճbk&@Y#@ K BAp ] RbX[J0$/K6azZQ⫛ѱo۽3o7cX` LM0@0/!fa& !8Z\I10sۚZVۛckIރb %NYP5Eq i"dCDkȓ2!H!Pijۀi) hCsaK6c eYZE$V6^SSaďfHC(D>5QQ~EGG݉ 2Ĉ*S2a~>T!>|\b2 Dh"VlEhiFvGDbZ jgbG]OyF];'ym"EY=j'֪4yx7@HpLBixX Q@@KQVU0lAŘ^ŤdI,a@|m{xR@4s¥]MC L $E/Mo"I 6QsOS,R^\EbnPSfu_j@!ITP>^ן(}:U~ 9MFA$YVu1R~(QڬҤ5 Tu?5V'͈iڥ4RH~X|,Y֧2ؿ]Y?br(5n5Y>CU*!P>)o "Dz}Z+St)"͂u鏙AB>}BWڭ:vE' Ljlݡ3bW&!t߅Vk!!VnOVM pT>9HxT2: ,KЀO!"P0>H7 in )²YYURY > `6}dy$t[f*))H'ĀR"D=OW|Nr[ * h L ƪe{I$*>>\*IPEa rK4K*]C#ϼ> "2}, 2Z5dkQN(JTJjH#4JLX%p\ R.baB(@Qzφ "/|U3Dj KEU99ՖL,% ALPųUabΩYU{iaM0mDWX>> Sbȳ%> > E|bt) 1Ɂte̒Rd}pF!tl qMgS Y5C!bg" H|Ϥ"D(68GѰZYG q`!K-Waf° L1A##Wp~/y̍` >#g͂EIfD(AGԐ'ި'DELՖdɔɃH λ+׾O_zw{ۚWȩ ov0^J0%ekT̐E)$X*'GiaY3@2d h09!"WA x˪(6ŲuL [ 6|<:Y wq, C&j98d,L,k\p^dXխ_rז|oҾgL,J֡m 8gr_ XzxQg8"dajTdLPedAA#^MB@ B?}FH{y(P0Oxc==d =QA F6EVG@eomI%,( ʹe(* #1zY[S!4#9\@ Z0ִ3ʦN.˪Z#!dcqZX DP B= ZCe*-$(UG~{ݹms}9_4>y^k^$n/ !4d+@J^ $"#0lƪ[UD 7V]ebGăfӧaL˴f^Xfy놷%U#3sId,%+HPTR.SJ֦1m e^0Jm4dYEdЩthf C&eJ:$#>9CPe|}>deaD4CDL@AJIjYZґV $FItY1LLmp\PTՅ#]_wW#G4W1iN[ER^8[K` a&Y[ZV@Œޡ2W}og6'ȀO*jb|kw:"}־@S|&+J N!x_z|OcqB>>6@g,stD d ӭ,,>O3N{O!mCDf&@xkR=VK2V:-X/Z%$UUC:]k!C}|x >`QDxeJ1–dИB˳KR{T,LI #HB͚`hlhZgbe},S$єoWo0T)Df.n VX$ə%exq'4eYTaY}>H4(q::i!(X] ])mBIC5W>s&̑ ̔CR-QDSZRaE.PqQ&2 %2ԳCFYŦڡeV.Zh!o((|lRB$`K !v(Egvk}澗j|!  VeW4/tV d5Ɓ҈dGFK0/M^_.hm^hFBh,0$)lW9[ܣmkWֹma%!P2I P&)$̀d,d:W6QvX38Id%$5M2h+_6FkbyXߥyǗ2l$Ր@Őd-Y5ֿkhjm毛miH`B] d`X@1`IdaHiS͐Lo)D)$PвL?,[V6Zm~5͍rۗ--o\,m~.Z75+~ͪE6O4jVoū~|mrjXֱXշ+y6Xض4a4k`&6 jVT!~//^n5[\5o5\E5[sK~[]_jҮUQMKU[E-ZߦlFZ4VEkU3h}k>,Ze !Z|`ˡ f*,B*Ifʫyƹbؒ )vI& ,4d f] kVUFb(Z߶k|o{Y2C4fUP,݄Ղ䐻-ך7KnFpƪ'u\XڢVͭ\mbj*͵bܵk!H,% u!h.BX,34dJdS uA0HsjW -mo/jT_WW4mb5RZU.U6|m6_7ΑD{qG!cz^3`b92Ad*$ 6AI"6ܯW|5 +rhVco 6lm{ڷ6\ܶI|= @QbÑZ*5DZ~ګXd$ѐ pɠ03B MYjѱk?*@͆ `1IBH)%BUE d$vw~th۟~75EQyX\EZ(1ܶ|Q~+V1j+]-snV嫛sQU쐳!.d,Xj4 .3|~+e/JWu}^leE 6V'rHCzj> wzŦSkԾ*Z g~[QQP`j:K^XCXֆ HL)=9@B#_M`}Z hڙ4q%e}`r>\uMH묪 -ܳuڕAڸE([QzH)]hF9l}`-CH>|p 4ьH r@| I0}9x<@7vw4)IhFꠘ>Ԭ1M;+~ (q$LlxD0ӄ{9 0] A%$1І մ}cDֹzGmKMdiD1PDv ۫1®L)&ΩI5m | $|GGQ5k(ѢיmFDD6S+XT1>tϙw~=^T(0¢A!F>ZǵTÔ@v؄/@l3&6AC >p/8@|8~v$K"I4/yZB++zuPM Z~4OzMs|>p"buK|A԰%Id IiDO $~skn$߼HLDQlQ ؎$׵eH 7D2JY7ϐӺWi~~!D/H2- hCE8p}藕&Z R1>y9R'[Kŀo[ULxiLiD|) C`B>mk| D# YIIIZ<*a,&7O>P4}Riú2<LJ0ݐE!DHk4hY3g< :EH}0Ÿ.˲wܾpn_(JqB@"4hBc( >f>طV/$Ϩ.#]1L0d3n˸%CnEZǕu'5sD7kld44l|Q - HQjx('J fW^d{N cbY0Qm">b`Q/)!I^]#@ں &>b5P)ՆZ@\ZyJHh|Gg^"c%]zT@ҫB>>D6pGр YGgЁ[Cr˲\U [ N^UE)} l[B>}"@k %b?xB!IB@-eU]1fCeKat=e . ݙ| JɂqVZ2e0dʦ #F(`l2QY>A!D.9pU_UìAbQ!KHBϬׄ 0OC@ 5Ih  %OD(Y&"D$++̭=dQc0RSjRH2QÄ0LTI- RPFe`TE(F,"肈Cޢ Nyh*(tB`Qܤk MҐE ȨL^5D&WFD!gȎcCh :|0Hck`Jr(`Uًf)_w\~=_[PxHEσ# YtwNF/޻@&Vl3O/YiFQtEԤ ȫ4+du@@KfU/U/=0iWdҚrh-%DŦKVl0"B!0OhD*O-ߍ7ء- /#IBZC YG[^eFOuwm^E~j67-MsUnAi\6^cU-_űms| nVK~)dL!bR)fH~] Ra#vez R&M ,|ͿW6F[湭ߝnU~+6jm\,ZsEj WR^h䙦QVK!wT!crmEhڸ%_ͷ6iݫ-~?)+MFֻ nLi L2@#MS"a| mi ,&n YL7 ߦ۟56;rمKU5sI.]" `!%UBY)$DP,Zi!#<Q !Di{@(ALIM k+IC$o'R4aYA!_;cz{dxaSFuΐL4mm"'p H JPfn>0TML)pF@a Rk1gi^uƂUpEaQF 6I1a0F| @" N>`$#p% ^d^F,P#R =(B@ɡW B#AOAV !{~h<,2KRV (\-!tja1̔eD-a 3!{GI*T 4n܋X ,C>tD" Y#b0eNG GR!e@YGռn?Q] b6ת}HV#TY}Ξ2 B$ a$ѴQm8am*~@3$ $QmTjV/:2z|>Pa\Q KO+XE '6Xr(A_$72'h)yC!5Dn&Jӗo1y:ӧ<,O )8=#K@ h0VC4hK+ (dPcby/HCvA8WGeG-#i(@ϙڄGn4VS2x3GרWV-:efϨ HP)|}"$iDr;>TLF##֗|daY"lrѬDQ5YYJNHM#QyP+aiMSZr# s]Q  WpiX.>|IJ M4#b+.za:B>8LO:ő!l`8̈ȈS&69խX,Di7Ѝd0|CH~(MՆD^dD>?X`aprÔJO}z}4 7Hg٦QHGIPTiBAI,>jRG 8IR}gRkQD謆 `" vT.Ҟ v7BHF??`8yOmzt N(F 2ѸYi ji F+!>ğY"d2Y'6jc!UD{d *`g>$B U L #>Nc,'R[(UC@d !$yb'v8@AL#mc3NC^ ia6@¹CqY>`Y<4 4~HT B|>i2TDDtKUAXRdP^6D>=+ ^$+BUKSd40imdg ? kTI?S7в(4!8FhG5 P 8yl~D"R#!g d"GdA GQ$~j$[ )셔Dv>GWCR|% "ך YFGRڦulUX+)~YDY!-`ݺOmk-sr5sF+Q~oUU@@MS6I.L`-Ђ݁9I-[F v2u\n+F1[mp+>-݂*+yb*_{Ұ։0LR))2E jt#Um{櫖-t45TX7򷕊ŢɃ$C[4ųXj02ItΪXRdTKj%f’صtu,Y6V5>y˿}|vzGc;cBtFj'蔛dKXO0X{٦&l}o-|عVcIYfE B[ZsjJR&)/""ҭYjo?H "!#~$tn0ƌѕ܅[]E'R 5{؇+@ ='D"L/(cfb̓ᆱ^sf4TNEb6-$RnĎChjD&yCO#G/ u4/̈́D0[Ku^D>U%/ylR"@͒e "!,b0Ԑd|E!@Hz>iD3)f FSc ">Ě|Fa]*~T8axmQѲPB2K?2  AsH( ,up!KfY.>liR >ਏ>kd"#|:6$M/uRQ QHh$ >a{dH"I- a옵jFЧ+^v \lblDJ6R"^ 1;؟}+UȀ3mLn"" h|EClȀP+ j\M!eI"'-eD yD$!hwuДCC,1C3_ O.Bi,܀Fj*!F I$i/ /ɫPYy F TGbl HXA! 4 (iքc">#D$}AGη.s_6|6hQ4'ģ@2w~f`^+P@@Ƒl2Q]#)ofGH~$[lZDHQB./# krF-o+`JLRL)}:>IdU0K/Ӣ˚v+ŹYW-r\s>}|vZ9}~ə7Id[ڠe` .u**\ܷFٖ@}gjxxbC+C+_.VE}Oӈ#ﻶsm۔mmsU:ѬVߞ1s_kb.hjU Y `ƿKX'5z/W5hxC򷇚5強rkP&!.K2`-D@G#H"~)t|*ޮ>#v+.S^s|W2Y{?]%se&MZ:eD ip0KiD&P o׻Eܾ~1,Wܮj4WT4$h*YTVV&L[SaMR , @) r(tI0L, zzv*:#9H&A#R{Q3éoã(TE3 KO4V,w"yk|uſyW>2E_b NV3or z&V[sv2R(Qb1q i:rO֋"͔P|d|X7L; *LN+_QX:t%p"9c ( mA5}}D8ГpźR(J8WƎ`(kV x %z_s/t"ec(C)N4DͶP^.!m?ÄUxCEZg+@P)g*%>m-D>$N4Z6B#/φTdM%H(Qcjaк h/aWX]T4Bu0r{B,$G P"Q!kkB)eC~:aj\ ;,՟Y G6R#!nNe'45/$!|! bVHSJdh*-/ 8h@3E#X^neB-:! "YҥzXiY-! !v~Gt,:a^Kʀzk(Ճ2@Pg< 07Hd1 "pĽG(.BЖEjT4{A>H{=K,D(ZT(} >߉S!$8?seYb֐d}oF!;Lo.l^dP*MCDWjsk.$=dYI"H |h|琝u%Q 3؛B;کHD{Wj:& C] >+_:EDaZ͌g"t#gRe|hQ6T<$4<4C"h>؈@ V/X$q|A HL&4˒dtQ/$>>%'U+z eY 0ב#%*#Gן,A|W_"`2⤍R^'""U-F,0Fm[fGWw|@R T5R4n $)}D3:EلLAERGoDl#uB!|BOq!|R m; ǤiM4mSω^!k|m|;#zH>"(D5e||uc$AWAFQٰCe|&dʭv EL!PrS([6JIQ>DxGg|>=tR>:UZ7+ߋ|o6 K;ߏ&!Xa u^\H! YfL. [ RdLtϻs~+9k-12Ȃ}!3z0C>٥Mj^E!h9c\6o~1/<V ">!K~ߋFҮbf)0*2Fbkb9f).1AB<nmݪ6׈d|d3B/TWFYi!!V IVf-vǟ{\~y\ۗ"ErkE)fJ*jO;"זo`y&aY)Y(fZ_ 剦%&G R}W;iv DLj>2v?IU'4E_,1%8ʊ͍\rPUUapm1+^RAOٿ[s[oc}>{>}CHl.Aw3FXRӾ1'M r/^mbbB>YEL!\鮎5g1abkىWZ1YUMc`>/#ED>0ܯJ #T!Ū)=9Y1~AH%C:R@4Dt.Zݱ.I|׼f?3ggm}/R LX R!eO5MYZ.ш ͂0ͤ<Q/J5*LaG͐,CHV5$E!.| %_Un-|h*rSi cOԈe0(O R!rbncI] ~ϭj/> H>!?QZ:q}dU>k!S:)+RK5#dm!ʐhnİXH;1+ 9E|hgEe`r:p.KPT[HUZ">.Ld26`mme;f  Hge3X ^h&0ϢMCD f8s&+!:N2"D*n%!,4a 0D~3 z*5=8 ('@%5 2M{[Q6,f/O1! 뺸D+@NΝh"R C`m(b2ۮZ(Z0t ,cde &8/dz+ ZXLL0>~L&"((|HrRR{(KN;CH?G ps9*ΡAELE?#RiRh7(µ6|&1zBKvbfBJUxfوY "dSVte'-umhK#>6ߕmYd~g/Rc 8d0AdB# H|\T 8~qG yP@; c'I?(%o SO9!0Ui"3%H8 EֽB {1}Ǝ[*`Y,E*\ɻKYri)LBItK$e sVhbz{TXނԺQN*3& j%j%$ f5DҘ,hg j)(O?]l%NZ  $ ,a|i);͔`:U 2Idpmj+~FϻڤrL-BVNi 1/X,(V],]k6MKBYߍ_t1{ޏ}5Hd:Т%/xy >do(ڿM_uIUŜB@G2R)g*0a-j,2H)|(xfm>%bkchp"+V2΃ kEhʊUXkW{T,э,%!",ċ(KP44!+pbizgF-8@Q.EI)NDKPqCr/ni2J̼ u V~:麂,a6v3H a:؈/}G6ԃe J#׮'Ji;d]T;$pPe'϶՚wB]~+[ ЎqA0("1N$tac87!zr7V03b-:6=cz!0OKԴPTpDdiO ks*viKLfÎzDIDQhH"v’#?,4&b y96YH71~@II*8k~ō zxV/uX)bn,"`% /^eUR:See%HɲFfΞ5]vZ3A$\C c֑!O#?4#$7l>t_*pjP0'@qjD]*|nK#>//➶[7IHQVi":˴*J;":pUOZÓ!sKj 4 \q^˃UPf@HEYtB(BYAiYD~J>z{MbavT5ܗVl|!P!N"lHqĐiA/fc)[GHC n"~(K"!<m#[D j'ş QIt"^".]I߉B#s@WkBk0|q/0MM (ͬю H IA2, ]&ҒC4DD'kP@xwSeEܿ~NƻQWR`>|Z3}u=taz_R"^E0fxUXEK7V@%4p:l|Ix~/8Wጘ̳>>u 7PUe2i1hBL\X`L0M.Qd "}_0/F̦ %=^(~$ %F> $p(F JCt`>'J#oOA/" ;>~ؽ6}Ӳ J"Hߘ=f ,ʊ4ѴnV)M84̚ƥU@5jCK h_( J&-3dAm߿]ھQPCo>%i7$!gG* }eМ-%>в[X%KP&m N%ſef -\Uqmd;ル.⚮Ϡ`6H侮q_?jwg)P@x\nDLF򂬹+hn77>A√=%F^1&>[jt'J檲;)ٜJ+8j Hmpٙ˕} &666˖}UÓ#\IGV1]CNW@̴"P։MTH@#oT 98B KaOƞJ)1&+aj@60,5z\ZXC)MA $i)"+# UR>6A8=>d2=(vDO4!9^$Hdy4Hߓ2 @z5؆Ϯ䒑x uTdW) 9yldV<K]Re:eqjϊB<}_GQ%XXZWS1^UJ(uǡG$>6D>`@~HIP7&1(($"쭩T9,rX;!9/ >B6C-/T0>8k1%Q!L)5Aj}!#u5~|, xB 6P>`"f欒H2ME$J{sD@$I_+κo?!m( R$1tڞz1Xܻ!2o!$F{?uy e+;>'D?+D> D/z*ê[$.*)7BڂUjו]P,l/+ƞ!>m^|k@U' B!)*VC)*tǨf Xt{_Z l|;1el'%D2ODmXQ-jF>#.$4 (OڐiK"J?Փ;40l6TR?<ԟƚ \CA 2 E5Mdk44H?,0ō40/'q#w]#5yX4P71bBx UɂA c$|G+Z4=Uۄm,R%DvNie]@P D?K}MjC;W@Q #TŔҰQ|k1T0C-(0wB~w?nƼ|[;z88 łV6 B=4rڰ۷>R{voƮm0J͖j>a@i$4KHI :m*2M&i",^Wy\h|b2T2aOueY0QB^pTguki"y~wTL!IMiDRj]?2(-BKZd""9I%#h/iCO)ȒZM}lHx5I$z{{#)@L@ H/7ȷz]gÑڮu_yUd_ֵ8y 7 uT^f nLHhg>rN\;^Gp6CM-I-au)HkP|ά`ꮥl>UݻVK'M 0Λ$d%QTPwv&dlwKJF߯[/,PÌatQ /YV̊8E~:;xaj1+RQ- 'U"q>.C {%BXe\qcUS8ޭ } TtI$橆pdڱai嫋rA>NbEˏi. r6D%T/aԅix}K_YdzCdTu ΄M(+4( /AWG@# f6FuQԫAwq{`uck>bOʙBJhZCƪtm}՗Q}s^Q|t3 TԼv\Lc ϤhV򑗽@vԎn( $pш? @knBp//J Odfsi†v0*ȮShR H :Y=VjpA1SC6i㻤N)*ÇصA?[DpS=+D"h U_msTAğFNj NźfV Kx~Ÿ7}v4WΨ`GBm 8aznKJSmGm R\ŏwtEXP٬"*Vz,ScB)j]7#IuH*3{%9cS.T#>DRT((JPJ C,diTagD&|YEĦaahim b\A0+U4(8WU0}5+Q7b efY!$tq0>OЋE(CJ  B c ^\Ur2 F$I3Q:0H0@IדCШ|g>_Y [+ EFK@|~+u<;g/ix$𝯕gDŽ a,U61YDW(R |uͤbȢ+6Q6Em2NWL sGF2}a)c`qz1Θ~C-OD-^h@婟hYָaZ0VYMcTJѫ+YvjiL`{O(:iC ƨd) A'IKu~.A_W 9iiBDtAW!OgЈF|D^>9kEpi?_G $|@݇1|Q0  (Y& @cE.L(.вG^/QDiHa!> Ra4->[UBqt_i hYX& $,D^NP,Yk|TH R?>fàƇa#2^܈e`ђ[#B& ł\P87.O=L0`m]Zlc &M~,W%[Fu&AUP@õ_t)_u Wn/16NqUTʡ`W1aْ^p[WYsQ5${.sXgfrs=&j95"=^:(B jbBs;K^w- so.uJ&nt;2c2T zYS<4icrh5Y^9\,tz#Z/ݒS[\:j6r1wF}p#6i1c/֥,S xqםw]%,5IcU.I XQav:08 l5L-No1d$+t9iط8Ƭ#[lںy}둜Uˬay5Zיz~ -4KQ]\].lNLɮf$[wuwn]ۚB7.3۲7wr6RZs&mWuw*6:S-rM.WTmpuumvsMrnQEVV݌ȍhLET[UssjڥjۦӻW TS@lhw]Qo.k[fH͔j4Mww;w\wd8˚Kb.vNW+.w'mMm{zı$ 6ݷ#ּXkW5Z656&FkTY.o%6h"+Ek!QB$Mِ &knkQUM\vVu[ksFҐlmWՖklVLKb[W[rwsi\6E5s]U\{X5P"RbײX(T\)G. ` \JbHz:ƬxcӅ_ťP靥iD*Bec%ѻYX1nå<&9  1b%QdhvfMm Ԣ$pDDDDZ!g}`Go`r b:܅''u(ñ&sJg!mmC%GGr#AwAFD[ MgfټG<@] 0\ U_7jzΑpNgz\C꣇J@8 2K͠)FDܭJN}VqFBy;2Ĝ{w>:q6\EXs@[mcU2vh*'F*HM 6#鏃X{!|$8*fٻNGݜjSzAAn/0 P[c`mF#P*N9<#6 rRHJab:TzY]m YNFg+v2?ut7 l9" H,oo@%D)ɻKC PXsW&4m%VQVŁ>f]ϼ "SMlNZˑ&Ҫ2 47悛CD ƪk+83raYG>qp[݆P8$xY/b67,S1*vsźB v/j IMYt pʰa*s\%9kn*qgqmiJ)|d"=xW֮tGʋ-w%y2G e =Ϲҫ#6d5ݰ41ٺ7[76}uK%cXV߷SI?-A~̨u$xE3El9u_&?c!ߞ_7wiЫ: wb;({i/v᪩-׼Z~Cۛbŗ,ûu$f1J2Ͼlϓ-in6OGMu% G4u+tnr4^ hɱ#+3 WYإV#dg]/AE/,EDZS7e=xyp74F*hz}L~@ǰ&;  \2u9ʃ9|GOTc(Qͮom9(kϭDgbr8ZntՏRww-.(G 7qnDyCFL)Xzg1+Mqf y@S~\XȚcyуr32@TY O$rv:x^ݡ! g:: t2C( Dp"d7@Z0ϛ4Cbua)!)p[;A߾V#wwe"tٺd`8hf@E{)-aʑҦwr|5 %%޼ܭP_MK_ض sq葲j\ԟ ~IVD,Ik" N;[WC&hЎT6I[Ͳœkmv}o:!ds7M\ffneKcrʛmH֯W_h\&{{ekOum5IQ%556*,hJ-.#@kb(&h6R]jzCc M^-j4oFmsfSLW.ZEumM"I2i7=۶$S+vSݢ*n-r4e2ۦܧTq$wms39_l^6(D}ۧuŃ(H‚BC2y7>[_\Nm&1p\;^~\]&@cQQn5WW6cZWtFUMvǛfcZ?hD(RUB[mlVmy[2ѵkZX4&=3%Qkor}umyhѤ-AZ6cF$+;"stUX5-mV5j/do|;ԤNk_59Urک6V1ETͫbyZzjs],uQsUrHIi+nb*UfX۪Vūm$Fj[knE+}U-m**(հSu1d(Y&&k)Y#<*~8awUa*XTYjvT2sO5w'ñWy.UJEh`i{CLP™!T D(YI4ʪw+T{.]*|<=~zq/I?;o%a]c&Lai\y]*ʼnٍ/#K.;d}$CFXތ`!u?t}M5zEzV1,D]}hZLXb\;wZsK 7$ xuS18qn2``Q,I5?}WƏf_zꂂmp!B`x73Ʌ}zw6%DBhF-vYAMT%1Ă t6,GUWJcon)@Ӑ(?!i)C&7̦acogkc03EK췋ZƷj\x fwma{FÇp3Csf⃨Q$sR'4v f,&^,fǬgdP=jj`8cL挛͢I胪wdTϷ.7V-ɗqS?2{sppl F,njN·Z]׍BEðL=\.w}Hll,MN6< 뒶מ%Mj |h)N3 Za^LXtF\WYxLNɀR+9 sSrKu$y\[LBf&Vfd<p@|S$tFp64vBFx+$yC4g':-mTȀϞ ZOG)걤Dg4t+:IXL̇^6<6jEQ y]f*gviǣƽbԀTPQHٱFO9`5OM(iHXP0td~ε}*B΁@Cq")v 7ވ?rro͂ͅqyk`f6$&A mimQ{ZZ13PM62AD1-hpIpխ f>I ƌIL&6[?ms!ӥeqS0Iҩ; μ2@lQ,eIpέ3PS^MxqpH7ƛ]auN/'IV|&'ΧIjӊ5la˂v,LItc󵴛D&$RՂ@S@J 9GT ŵ)E J\мY0e"0ѵy@[S]0kkU¸DzgUeGW'{~VonV?kL Θ=MJPs)oT +ARx/ҁ"0pV\-괺 Ҭr4S@M^}J{C𓗪ۙ9k):^kͶxݍB (Ƃch^!~9@D& "T$kҦYB"CDX[F5aH4""B A{eW}MOTDE{f;٩δFZh֍Z(mQXƴ+l[MVk5Pdsמ(5FW;Q7-+d˥nNmmmYrZZVQbh5E--AZ55T#6FѪSLL˻B=]2pu=[^q':^lb}ׇg[T2~5~Ò?ZhLe)4U!cvBS<lFn09)YYN!NsS4ƍ/_P6\[P75" mޙl٣ouDe Blp6KXn?,VX=g,\.cX$7 _a ֝AP]VccE{Fڼ%O냟H27_ ppܿ8pb-ގ0 QNfr1yagou [ Y;.ڥ-BF@h23p2"hdW昼 \8Q`w7"߀)'qQ㖻Ji,o0 MCX KNE0s]%k4'ǘJZIo%1or!,Q!ft .M z-xr\c7,\Px0D32"򠄂&@r-bŬa&c$$\L@D"s0N:x,) שؗ;Op6MӱpF8 ikȈDik#QnoRa.+dG"1/((N*chwCCGP +AK8U.i(oݕSxTŘ"H(jb7 G:GpvI #$) ף~1A4S#JBu4RoX;bGjZHPNIp١]Mp4թc JC<*5p~]EU fBr|=̉_ DET[wnMMWulbڿգFj[(ۛэTkyZVU@QޮZLI&mɽ([}ZMfJe%2N)+j6h&K}^Tʷz}+[Imt۳g2hA@A2EX"V6*EcXض(-_Rhm bF6]ﻻBԻ^ysptze׽֒ДZ;{Uͯ.˵Ы[ѯ[W>\65QVLmTdM2b5h-\ncIXY(ՋX#Rh)3DDH TmefGF2( J"ŭ5bƬU !K:J}NZ&*왖yI"B&LJIiBLf"|SQv.̋yL XNILLԲ9$MFF da\?-.<m4Ad'<҂_AQ˼R¹>^6evC({tة}bD@2r `(=6Lٕ [&aPƄ1NBat2nY2iZ$ϫ*c~R3sv!  zDknT ;rw䜾&JoZ2@ULŨ-c\" 3eaOuƁq0,CJJhUYnIt$[ iUuŸ b+. !C*FdEYbV[;mFP;[21dD !HJוZ}z}V٦A}(@Ƌol[iI}o7^@Vd.ql4puFGT, 6 ^MaxĘ3:L kb:89Z '؈^GBҸ=KnB1ڗl1u;rwwNTxQ hp\l"hf@nT3,1Qg"AIEޫ۝uL F֝NV^`[bI6`ӬI3XPkUC*Su1P5C"vas$f@C P2*;W[!~f 2͜ JmMal/-jejBeGR{9S8J"!(Br @JMə19˃|NdgQ;ڷu zVy¡eV a-m56*+דvAx ?vG{ QUK[?:n΍!ȏnK`|M[דlu6no,2+ܧ6U":NUxLt[_'CD˯!,_ bn?mmT tA0 ΣpbMEv_'ӓ0ܹE|wWLݩ( P*!F5FVL `|U+OB~cV;fG$NboqD.MYЙnh៞"ȟF ΤCf,C,=-Y@!Ll1D6*fp .+UKqE.O,Hw%*HEs ƭ2SD(W@UBFh[Q=NlJ׹c3i(tTt ,, ,c{0@(>͇FoKev9  d7Oޜ2< d!^!3=Y۫W]'P.q*Ze3ɷw߃ @WBN3(sAc c%0`[3,F 3g: Lrrauoϫ~_F&Moxei8x)GQ9#ں+@TGzu51UԸxʽOo&oKgQFE^Ȥ(N&dy$q`Oy+[olϭC0mtwl"!#5øE$B DwuŌoPk9 s͒*mmonm!溞dD[R7,gcR݌Y"}5i7~eoڰ%cJ^FdMoy Ʈ+%n+/I:a%U31xe"Ֆm,qf/nk9(,td!xHg8ii~~jkc&bcV(} [zhڣVb+hf5F5QckV5)X5["5lU B&-)TQcZU-mUzoZmٶ׭jM1%)lO6d4jڽjtE$F#Lpym9(- |Lsl|1bLQ> _WHT/E$Ia8y΅( 8D0 pY.mlyKӖN!`܄D:StP_2[v-=j ɌQ>{2DafT=.0i_0TNg17fr!BfH`$Lh,{ƇW5|FlbWzb=L OOW6' 6.56UvJ'bfQl?B\$&L4*mNUuEī"Wrռy(c6nS_[1%G.9'{A]moufIe<1yzlz ffɹmX8n!KhlFI)P͊Q @7?gI2%=]1]bh8ݸd1x}5 @i(2Bs z6ydOц\tJ4@WjiސhDd.;Mٞ+W{fmxy!ЋX_z"!ٱfd >ֳhBP̧%B:n"|IHeu ѮMu?''pm7@0zE8+2SVL.۲UY^z)]Q3LL)I+TvwDz*pKiz3?3M!זp7Po2NBf&Y_( .K% P)YwoxQDuR?L04=/[YO!5G_+D3}&h Ar`3wn V̀Rx@B<5Y 9EEuVAAHΫKmPC ǿoJdd{gPY=Pe1r aV }AႭ4(AQD w g\,X?&jlϭ8fTl7[ojn^@qp%#B&éj%".1lVʇ&12֝$@e1{ĆaI ~"Bd6"Ļu!X,q6 W`'d {,7Dzg+nVGgSf}^G".ݴzz,Kٵ(+*} @zHF[*2z o{[}-ٶL+7!mٷ\NS^fgQ^/f &2am̑6ͬ¢9>?==Z5/Ly~_`Eے_?v#~9h>\n,kD~"`2+b5W:Qt6۶-]-IufjmfVcլV֝v(*m5m eiY+XF,7MĨܮhk$rN۲]e\ֶ&*EDlZ%fх3+&Fh֨ŴRkrUk["Rnmjy#%;sQ5;])kk^)RIM1L[tMi-hlV-Qhѐh^ VŶ5Ej-IL65ܲkmEJUhr,ktM2SW]kwvOvҎMwurvֶ*`# IREOgO[gWO3Y#հ ||7r UdMZh:C~=>mIO\Ƣ-\A(a !o 0!d yfΌtJ[h"2ybpi dR4@n(f2dzЈc{kF8:5= n4^k͞1 33M;wV Cwn2+&׆\7 X\8Qс0I/ ꍞגO5m-qC$92ϲx4mi}ϩɘΚj-5& u\.Q*j4qѨ?iBE]7DvXנ2OFeK1*@^:U;t NƁWjtCU q#J,`VwJ]~+IE|4+@b͢8 >ME8)au4p㡳P;Y`>f.PRy_wM5ݠ@۳r=i:wN8,Ic#![] ȏxj[`##v kN˜2ׯWǔ"fP[y%{M0 8Nx 6B xŕLMc;`::hEsT));2bϪײG3qec$O)b5kGcae($7wr;f9mu6},vKw֓-聦 Io ;v_Yo̞cMK.rN!6Z[G8u#j6Eeqpfw90tuh[}E͛((9"a} Ǟy~[[o좶. 6G(eܣ霛 ۉצY7wͮg %شCT?rVR;)ٸrMڰ 5r m0gulǥ6 POg4xز*l!/1>b:>Aw,YFxE hz%,Z8}lh蘱Wso+Aqvw֠e+7&9ztnz[͌CY^,݌؎PNO;[@Gd[Pq;r^ m֝nEkΚ85Ɖȝ9r YQ]7*wrn\Ţ.d4s]5s\1Xs3lj5=jUU#@.\E r⤙Eŗv9ڍL9RQ4#CXY2fSFYj4ЊB`ڹk5"DdjjUujU[TjW9h"Ӻe졝-N3nmr]QZصEnU$;)jVڷ6usFm'u;M&Cv')c]:nwuur,ۮ,6تrҭrۛ\[rF5c[̕j޶m&ŊKl+hFZ1Si#feֺWZ̰4)JKmU":dQoTA`mFfJ]l3a{7V9 Go_;s_ZgI9+@OM' [7$UjO \9ШmHϏC 51!P:i%僪J%ɻn TɮpVjDyCC50"q{] y@21p,%ūw):eGaWα!8N*p4s~L8 juT» îd7"фN{AL(Y=:˫poY6Ur(9a]8rw 2 |KΎlZ;)0-$+9kv>s5:8bz߳ ܛ(x[{&]SFA&HE!%27ά1ZAE@8 ȡS4,Lu0OȮAiji,YUDe D O?Ro~rO= t `1IObR)yX$)4kkBP0}ZI=׭VGMNy{o&Biŗo8[L&PcǞ966]L&9Uۘ]>v 'WR- ~MA (FuPu 1Tҝp!NG>[!o/jx#Kd"R*N2?&Ce(Oa7fb@ fzLn1JA!ņM =NͮؕLϰď؞:0}0A!!›`XlnTN}WXPPc%ɢ! 33r3'! !Q#db<=BwE#';~wZtO3m]ٯ>a3hx=N#0Xd,b3 c\ . @Uo(n<;{7 j,e 8jЏ{Fܓj&|zr!=O:J#ʘZ0buyiYF [u:]fHcs{2sfd ]qS 41kDQ)F;B’7:zVڛk#'G+v, &yQn BX3{ 4o_>\e H$؎ =le+h/|<\w.v[;UGG$xkSS 77U/N2_:5 i@ c3ƕMʞN1GM'-LGC b:u;i)Rs=QS@TsH6'n]/N'ˈ D]z$bDz^ *1+xz^!?TT'z,z쮎#St}%+SBgr])4JmF&Q]wZ=*V38S!͢Ј17l0gQ'[XU٫dNuLY@DžـSr1!Ajl3̌\/A޸upcSڟ\ Y1-o{nt{{&WW eӍQgXFֱ qWg[;$9>n 3s% :sPhxoFo S/ͳZ|kW?nX6-|1ۍ,mdc-0]G[IHR@!"z[~Z\"nD҈bk{}嗘I#;4ځPi@nCP̨TnF ;6 E^FLd 6ȣ2#1i!)Uo ӗ& KÍRUr9%V([D8Kyrqn00g%6 `^LŇ1`ԟMh j2m+ GGDJ .9 OB}}r}o IvJ 7&YfWQJ%`j|3iGlHFn{S+Kz{ϕeWB޴~<":+7f\t>ٻ$k(y2= r[<3L.@4b~>Ufly򽙄Ś\p81ʘlX̥2.WffVCc2w[;;k׮:( K_CFbܿ0<;c9 Wi1uͅ]%fJ}[7\ñduє-{l|\ U>k 7.Ǖ':7h:v۞.u~ qUneXÂqz<@mRq0|ߖULk/Iϩ3*mG}c ,&Jgn?d(GꊡU+k9eshh?wj`Ð;v'6RhK=lK3},ou h}s0zV[Dl^=~q3K [޷ëf~R I`~d@@mz5WSX{wFhMZv)B!RYF"ʛk=e^\aiV4إݴkhm7*-w\Wufj+vZze-WMZ֊n2&9o7ZۮQbcZee% j+"mFjcTjeRfhb4dktQ$lBnj6V7wku*IzzcbhU:2fe-(بآAa8UPE\13U𫀑݄Qt^cZ):** *:~M!\XckU H|ְcAű<Ͱl(LmZgaM, oO*3-h 6)( Be> {.DzzX]Ʀr&yQ>%sT N?#{@4\ DB" WZ3I+8Dgz 1N!#GDhl_t4՚\66OMr-Oai7QI^5enLa= 0dFrU$ @ :j|=}FMu8th`AlfȰ-4J@ɷם}mlo(t 1k*澡?фJq[Ì"{),oqn'Am1ӗ, zቆ:ORɵ|ɰΰxV^j3(gOw0 5pC(r* q߉O72@t@˨SB0)L(\mH6Z!4^ΝF֭\­*8B:*{JSkfr:`M#à 9h Ȯ)vPBR)0W1@ΠLАx0R=I8IS N!MZoUHQ G tjtn@XWVP"Dy8T{T j=fa76Qs6=T zW_DHnd}ǴDvhC:Di_ԑg&sm͕TڥYYC#c7fުǹC yu^ԉ[;H( .^x[ޮeSnU{օ!W+-1 w9NDmѡ#Zhc~ro^I!b&]AO7$K,t]r AɌn\0AEfn\|JpDgd-4Y$#7_9G}vK:.Ξ=6Y fQ^ vgvY9ME6Qd__Iv+υN{q0<Nظlpʎ}!'`X$[jTmAi*Mmm)UW(^mU)6jM\drƪ{ڱUՆ2II+n,ǻw7y˷i].n;gZ[oJT*ةFF[hY&:m咂&o̧:MqW;9%F7;{s] vM[-`,F(&:  0*uHV{0n9Ad #SJEeZUq䁍e F@wReSapIGJUGQ59Ƴ=Õ6H Jxu4f㦹Ч>]A`DdK-Zm=6#4mMd>喇s+8x4d #j@R-XZ(4a\aJ{  -`d#ox ^C80(F9m3lzv(@|p@~@@ >^b`r7څx vOL{*X@lt%;6 LϢQ̑<˰^mQn.u,=nPJu ILd$h&VфNMbQ]Muwiı[m;7H'9@ @C!Ր!4#bNG6*җNظf o0ո땕so#:ԾҢlfZܕth IłQd?$-'ׄjI [h?S__9O^7*,1SˮB <ڡr+qK-WJ439 $7!D8QqA5Syu4c,aH "}?6IR:41rMٟm0}CdÌnۍEްחn@˟9y]ۧct=jsoVꢝjGfL3 5Gݫux m@X?ìiPGtnMX0I鋟LD[gW{`äpӔ?j3D^G,O_ͫ0vǏEiwW˝.a+]1+c|Ow}zjew۰s=U>J\"B/חu0mUru*1#Sz_5Z,Z"1qlRM55+go J/M4\ C(vȸ5C~!3"LY[uHlopʨoPwV((JH;)2poL5`e*ZIabUAeIëpYrU6ii Xxpw \/D]dC8TFӕ;. vU)@۶U\ \|\+k2Gflw09BʳJiskaZC^ ﶶk\L#:(0}~$x6+BDO Uz& `v ^aAlJ4Hw348 p kX,$vȬ!]q[ PfŴ022|trE)) WYI7T(DTϦGn XS49hXƅ4~BJ#3=8O:e(!YHnp5ٷo|VO 0@rucgg5<=m/hfy[v%^w:KlI4GPt#<[}1aS: =6e4m;mo5-0lv0 ecEŒ^e[ #QvVL! W דße;uo,fL!an,aT'KrV{Մ 5T"ʕ5lQCL Y5/zCedS 30 ߊ c̀REi_ߒ\^*7XJrF!tH$h b ýLz"vt 탊 "x2g 1}d'vJ_WJg\9~C&Bu_ꠅ p,;]`]>7.Sᐑ@Xǜ!:?/\)g9E6 F6L2ѮŎ_:Q#܄'#GD\.Oo~K#H|q7vX s#* D(TF78vlTi-$&'c6J}cO YɈڹzlT} ^2ϵߩAv1hޱ]O|a>#nլSܷN}魺yͤ=66koiJ? py5b_RM렆k:Jm fs_\ :ΓEpgDz&9!h [y:mvfm_%LjȈw?;hHB\@Mm~oJFc8u/$͠0 =0@YLlc53ytst}rFufV]B % ^hu&"l=QGpXۀ@6P8L2R/k~Dѻ:۞SJ6"V'Q `C jg H0hqLWA7r H!.-B?s5ĆC5gk 4A@m05J((eN{hsAi:,L@npum 58%5M 0o}rЃ:^ң$hr?l }XiE7!q&V؛.bԣy)c6 ATxevɷND .,Pҗ:TKהV^%c0;u=,zU҂.eEfe.GkiNÁ$XCaݹn?dyΏ02EB7b:'O;} 舌B(Ѩ"?@5%HB>K6<2Ld`x"OZwۂ,DJ8˺@ {͡T\ XjII.=c7 n'aomԐr$'iǒ%āӞ֪#d|&^vAuȀ $M=~ԙiҁsEۉ)UUP@ן+ ίi +ⱃ}Xej:tŸkxWvKVWmSL f/I ?{Ԝ:؃ ~wRv^^Qa-ua$҅-ir7:jkfvP/a G UE6 Le܌2<>ŅLK-F1S0f1:Jqm7\%c:@su~. ]j>=A倡M2ՠ4BA{rt*hj F3Q.GK$.2 3 wrR݋&EBxiӑ&SV H┶&f)*w%4Tfv+64{[0&fErKP=\NDoFVM*fě%kb0: ?V\cx#6-:R>EF7;#t2]̚rjNbWg'si~c/U{u\0 G|&ڻ]GJ$#g\?|_ZRz}?GZ}&&n+U կv*jT ,%}f:U wu$rOxsr/Z+,CCPZIj/lDEm|5`zU+륡S2⿹Uaoה׳V^MAЪ!+qɗJVWCkYrFYm eQkPD{p niwַj0"cj92z~D700WDV)F{;=QcZ~FHoLtxAg3ۚwӖwKergfS)?c})Z> 8bp\mK$??]76}~XA$:*dm(ݲtU?jonU_ݫͫIrt]Vwk\%r:[V*de6(#MJ+IEk`D$f&6J+IjlmPmeԚjj*۵#V5-T[\VŶkmm*LhEꫭDjZ7[Ehmlp5rrnwS.65 EW,kzږWe!0e꜌NV#zNlFM|dRPOPDȆcIoIrMfÞ + aA91zYhuIn.lxmYv8o53-Y@0(xx=,u%"Cv8DG~ {e ` ,( 0ȁCf(Nnmԅ0]MVB1efh]( #=+7#`` 8r0n\̥r"-r1Ր3&~8y!}=bhߒ O$N?V)q +? (P!$$1Aξ? =z ӓ:*k2ͥfg6XsvXRi)&k<T14㫢7 5vkD:Ѵh;ٽh7 d>~mKF-d8td|!"wʸh@K 88DuBYÅQc;jsiFLttD~7!g~tHjGt -Cշ1{TycXcgSf DnoD!so(,P>臥PϋBb 3"h"ՄC#`ja`fZ 9dog\奱71fί1SoŶ7!7{1[Fg~,aall4#L7VuE`ӵ{O8lNCJ(CGҧ"'W  6;}@~H6fڸdz%pު-=G" ˉj|If.Q YL /Y ؃'X8&B;-3Xڴ|*t=f*`w{98jd! &( Ťj%#7ɳd^M^4TAA_R/87jeAܗnk Hok $[5+k&s%hAlq:E%:(!pCA%"@?G$AT [(6 1rC)Ԡ74ؼ)K&ӄU^)KUK$$ i&A)+UHT%> $k4ثeXjmx{ٻIJR:𮗑1K{sy3Eϻw*(Qk؄&;tR"(i3(f26[22g;6ʱ!Tl׽ bڪkzjڶ&cFխ&mlVѭ(ԕV6ڲT[bנƛyMk-o^5EzvS]iBbmTm)knŷ7#SbII+FΪmkb1c!&4MmzY=P ,ld2m$xfBZC 9qi䧫Ǟ=ͨnhG!n2JɕrA * h{u 0} p@)"'B^2L1':+ * hdTi|Af7.;LK6#ՇU쿎~)&iRяϼ:ٺnsʵ0Dgr]adQ(lhV!@T=Dgɂ$ -Fln4M 4YCNoVtH07m èrB0H`S@ laРjBͧ>9`do7?1l\M;cd570thHTrqRXmmAa֬ d\0 )F7"DJ~Q*>G7e0+Хw/+W=mA `9j7W]F@\ `q#vf>%#z 2 o-_Q}GW8w~LⳔN᥶.2'mi0Uqٱ<~s6uQ =زXWYom>nun~\7;$ *Dck\۶b,jJVfшɮv޵n[yZ6VKAns)o-+J޴UuE-k>K)kh("AE^ H@uo3UeK_¦1fOUX$ :#wȚ@c@ Y_^<݈7KOÞW9XVoes}8u*Vd;(;po6p5(Fdgև3w-kL+vWp_`g2njb$&dñvt|"W1j 1zb;r41;໐_.h~nϯI9qb,?ٽM̧wEvfu! 0aUGU!"d)"! o nR;z> MQ@,[|*SU5H hkC )mjTnJ# f>"urA0I/)".{$4ic!#y') cQ-4;_"|"FCmG`+ DDbÑp/FC'#&Ff důoݲ5 '&0Ck&j`+ҹu?aag 4Je@.RjE'v5tJ' d@B^k8(4nj`d`); 9׳w0@S%e@ {Le=h la30rea|W j}FjYuRÉe%|DZ56&icMG6;R$䊦8/-Dwr ?zyQGp9x~Nm p՜QŰ-ksނ`4 <}{ }2'ٌ)oDoTyp.2vtߗ.]&d̖|&!v3"EЯ\S0OF2vJO6|GTRdͩu=0ֺT>vr%OZ9ؾuџIG#Rlǃ(Y(pi 2"g[fK՘L `@x?D Cpٵ dZ&8n@ދ^cIVcV2GwRok @/eo໵d޵qnd[y3`x 4HȦd ~܀Ǽ#P%DG8+M꿞|};~"֥eA7v6 1.E݄V B B>)$93.Q..kYv6 zI @*Tn}??S2W[0XVA61sRkωgTk{JO0ѻ-W*G[N) 1nu|K,KS}0TH 1,6R b[nԁVMb07 QM9sM!z>Zp4#oo Ʀ&$h٢nL[=N`Y?ݤ)4@y!rETʾ%cX]ބV/:R\•Bή6l1 9fͻRp8zDQ2U;/.vJQSH­Ő1D(F&?ajP/]~Y" $0@bpX1R 9dMZЩ_јՆ[.zg!ImFƟP?RHH]R;bKD ?}\eOEyN=B sE軘:JWzqhieԩS&V!K*N}+#h(($?Cȅ9sY'$D̨K"GetvYvUS%z76&Z/[kb,>M}ϺdaJ1qIM H։5Ej(cm@ C@$6ƑfKRٚ*oB:vtDMֽ{ai(f Llӻk+zy{_0liE)Y_RcP&;Ro.2W]L۬u*(;(eI+gh&]d(6Mf:L[Iݳ6T[lckK4)hUǣiMMS]/7G3\+Rm¹q RPE[#7mmպq6Q N5YE) GM_PnQNC(#η,tVyl -K`zFt $4oAjE#jn!~ʐJ9!c qJ3UI5+f-H00LZ"d҂[2 >kÆ54*w!CZ pEQRaw()_WZye{zbtt No_}SmDvw *R,=53s)r+B z im"\qW+DZg@J@ .,1/(y qsN >Ɓq0ʴ&`̔E ~]ϡe;(ETrnm,fٙpRueԅM%4lȬ1Xg45Fx V,MHp8V+ xx"l % ]Y>?TU_l-5AsKb Ff9W]fOddS =j?f.hH&F\g=+) '@(Q AUb\cr뎑qeUcloT@3V1 H,zjԳ31J( r0R X:]W.)UP$/Jnct\,<:Q9)DܶɊ\ G!Fɂvm[JPWƼG=K,8]TZbZlҨ^_ED}a%t;s8,G UL6+,BSS@]Q  ͋y%@AcFR)!ksL%nzrh7tY-T@%(}뇀sFj UA$sc6z8^ϊQܧ)`su)Aw" ?SlW"MfRcˠs)}uo+pEqh 1A<4^H2X"#J<*vB v E>;ݚ^9)܍Zr\8,{St?-bOc(rͰ0.? H $!2 `7#lE}E; G T9 mZa[V0ڦٚ]*'Y==9i:&D2ɞ[N4 /W 4(;0BDhnmTi/LZL?H]ȩBUT 7a+ڪq >j)RXh]̡eK$} q蚱:Y_+3MRq݈B<Sb 0T6cKhdo]ꂥ+|L(JB{2R>Pt_|*5RJQokUb׶dvbE`XZ1lFb$f66] dPSmWwlH&HJs]dƨZiK;Xɔ$Ҍ_krѫ*+zimT] e MoUdo}S6ӻF}#RMy f@ "m:z \gdINojotUxLT[ )dc7W[ѩBPQ2ˬ SW]h+禼܌fqLF`E5[A5Sʧ>Ş~Oz~3jvw 7eU<'R&[eɣW~C7B+ϋh&hL c bɑ~*=!؊W+_ؾ\k1Om:-EZ2tR&k(gm2׭r%&wu%vi0$ N Ȕljr/v(h йQB.:2fxzO~̈́䯁_/S :PH10:%#D)JN7vQ+ .Ywň{kkŗVuYG&wÄSdAҮ G+pqm ThP(]jfa%~MY"KQ^Q̧]<. ع]p+FʂQ Ṿ2R[ߚI7qz]#LIPv4џhՆoۧKU*JuY!*=_Z[wm=I/)q(N}ЭjoҰ#XZZnU-XˍQX*$EHfL0M4TS2LAiIL&jj1lUZ6mըoUثYJ&/wY*X+2QIbV7j[Uvr{op*-IbA$TmRmWfjVܛmikbѶ76ضۑ2UrKj-[vSMlbōm[FZZWk! *򅕖M +. VVqBȷ!Wpo"֏ `ןAe"cHI"lqkY(-炉Npx\ȧ@P+׌@a8Ksjs$5=AU6$b|ePR X F@5ǶT[-ô@7܄$vK!s2G]90 :M;L(6ʰhMވ ӕR0,U.C9 L\Aѳtkx j/&* qFR8&.[pd0Uc e42"R,Oi 3h=&P<%Fu Cj1+Zbd2 R 5Ӆ1J'XlNVa!B1)yx (5qݚkC$Tol?Iwz!/DP<wt IA1oy2CQ'X6 W̥;޷í Mx4 T $4BlHLi *ծpDv(wbʝ]$58+nO0߅@ /FtiU?ՎV@pYXx[٧L &o񞤂ÿssuՎjlg+sI/1=VgzƂ&}ۈ72.c WA"m^wH6vE {eørDHmޯrv<0 5>Uz;N{UqF$]l].gu^sw7ҵ'`0; oŗoÎE4xӯ ۾a+KpT`L\nsCpL,Ṕ5Ȼ}LeuǏ t㾷߭l:3Fi;/>j)9ۅ,Sl8IѾͦ\ A[[&,V,8zN.]JnJUT*v~qWb!gBG:.֕زz,F%V7W4.(V}'i^xNCd 4޷Jƻn GLAtg|qmk`~~ڪwڳWS|$[c|S60g-9%t׋&VLv 8yG6QCxkL+FfG`yb3ϯ'qFTφR볽Kk|lpѷgumٗ7C`#$QB(j+jR*ۖQɶmv\LmF*M6JBE %4b1IMּM3\޵kWzvo[mU6ѬnmE]܊6ֿhsU5m5i4Z-Qᆳru$IUfʭ!+K]^jص5em6ƽi铗`JZ#jD_6*-Q`ȫ ĂZ!c#Ut@CWq{GB>(KDz}>i1J1mTK/y%z9HL+Cf{{:b]g֯m}dc0hi{埗ZIqPyq梳.bGÎ^;.%ILbthb-]ae*眮׋鄓n:,zz8A ̀N4SC.&5,Wk9ߊ\RHsB;hdhd kSaF*XКv ?ƪM\uGO)٪.=MG}7dKl?&Ft}ˮۀ4rOw[GuilUNStʰܵ#hc ȴ׉offܿ\ q x廢[dũJPc*L lkba+rcyIOgR&svwQd ېdaܭ~C7mp3b/c^Vqp^@uY9fcS_v7Hc[.\U3Kq]/^ xwL}ӯAe;u$]`1|9yL!0\87S/omyԷAXOn5 87,y!|io]T.{H7XluvjjԈ'U $B*}׿O~~ #DݨJ)sy@ d)f-_Pžn>ܘmQfe#튋6;y\bp-#k_coy͸q 'm}w6<Tj@<݀Cda ܘ}W`^rrX kc|r$E';v3yhXv2g=񻎩(uO#9!I"Wu}7'r:q3߾cqǘdWbyH8$C#`.(N[;x^C۟.wv : ,$%2{o&qww]$CtTk݇FgߠَË+9,#Ƿ}ڢ[x6"㰫Mc'£nv]7\B|y o_^mIKS]3Zg|3m+Oj2Ae/`cu.bL晇E'Nѳb)S҇}N&s I3qF6 31ٺ=BLj7V,mO4<=8B '5:HKp|ITNϡ{LJk 젯Pr.fŻ<0Odp٭ tJSpeӚ ݩ4ۄv-f)5V%3Vu/>]?<,1H4C򱞊A-9\.l?XekzeьY6Ws?u\db:  l#%!|vHFT|G8@`,ykh/pބ\ÑH5]d*E15 '*FP@F 5sraޕ.^ H4z"QLCȇy!$Ux#6dc˗crᆤ{=O)L쌄x,VVAԫ!}Pnh?P='FϢԈ1S]*RSPn5& OdVJ\Q7F0GC SMM QUO*.5Y_S",MSAX1^GΙC6\-.$R>^XW6N3@lT/b(0Cot=i-{Uj떫mykr֬jfFmdbk[]4l/oݫI ŌLQD$lX"h ,I)$i]Wj`ۺƹm5[U6]env-UFkɴյI(m1&o;RL歌Ek3k`Y 0)ۮߢz@!ڨh,D:85܊u^ca?k.: #Era`d0FdgZhh )Jjuꨞ|mԭUr&i3,~,:])[E z]a[5(٢:(PI)xRMژ4}OoWENSJ19`ɕDwNߖvu=&/(C@ok w #eqsf \# gSM9¥;@!sH9aHfm'Wom n&CrLÈ[kJLc;P_MA;bHIuPw?) N12zL1H ! ~aM> ~iIԏsL8 u.:yQ@K 71QyTpk.gSvE$We&} A#j)0<rDϮ\̀tm~a@F`/ P!p%Kll cJ" $4/$mdj2(A)Yd/I$F.<V}n@7cN; ҷW *;UcOL:Kç]:(=m"Byv! LP*60׬TgF'O˅y3xqV APtٍ`]dQ~uCۏ!E:z- SNdaWfQPA!L]ڞZ'PL3t׾9U8RKis:jPT2Q._˨c2K p P]{ qq lt0IM2N{kD!vKt9C(@ 6NpM^$:i.ۛ"#̾hAxφ$fḄԊS$6U NR6Ile x,Cɝuӡn.zәoam>IErhQEKZu3N^T CSH ׍DQˍՐnyeB?.nI2~}dGb12Qp&4n~G깬*OMo 2 V[ Ŋ fCeA&`S-*VrS-MGXjN7xs*78B@ޑAfg4uxg:X&1G/Kkaz{,;3I)Zi{hͫ6 ldyŸD~WtH:d'=[sav]ф7 ^E όlٹ]3m0':amZT.e;4^REgo-HdF r QMm-rF_g*f(ҵ\#PH̚QT"&^@ZW6ޕZZ5Xڱ*֙Fܨ4ZmI%3Cm|6:׾ַkWk}U4 i`Na#$EoZƪ mm[V1k[R ! d3\rFT'Oai (-PYv-OedHʀ+Ȥ3,PU|S\TwUa. o2 |d1l! *7874>Os5'{ Aa5· d=fA̢\svN fw_u=SCb/&qP RG+MpiB w~#U> O UtDdTC^s}]b\0scCj&<ʼHP_gX]ǫ7p~D>T@BQGZmkUS/^SPprIP/XCM2otѣ'CeC{/0oUB=(CАt0-կ#d OD iS " ;"LWT!B= ʢ$rALeg Tl`K1fh8ތ6u.Bg NRϲr}'~Ig8jt땃ZYElԎV^^ݎc[: xi5+:DРb#t=^**Q "Ip]:Cuꎩ2hI :zHzB";ZUΪ `eXWY4SV/s}ODQNEjX(J,V\ČBz%ޏTZ涞Xtm^m^ki_={kXɍb1E[h0QDI-!k(@ÿWqCDtX#'T< /)ISo 0D/*'đzwNv xyҕB$FTE\ (C< :_E`Ҟ@LHƢgMahR"<ՈkҘ`_p3ݘBr (I`! e]YYƆ5jY6*~$2)H^,HU72} HBI`@luNvڈA ٯc2 0Oln֣SL(e-vy˹9dKN pb5ձ5Ƒ,kNAD.YMc?cЄEǡd$'[&EI[oHךJ Rۛ0ӺxE'a˶/,hA\$i4 <9\ H< p>F|@>ZX%i¶=Z{^@)+{Y@ҥJ@ ([#- Z^v^Avv'Br.=U|$4 xx$ՋDFf\T= e)WS7@ ЭIhz F{L[QBjGo⓽2vpNn>C5xElT0Jr_5>L߳<0iGè$l9Edц+r#3+1 Pexi#U~!!Tb ʊY˹h:6Qx?)Ĺ=15gMdY}p{Ϥ8zl|b^h*F32ri?\%Tϩhú_T[BMXxV>ZSC%rb0bHt4CA_Ot߇Kt9o/:ÃBl{7՞XʃÄ _UId Dž@79( FJE8bCmxeq2jp .PAM f.?3Iɭ)8UTMCGdjRz0Eҟȶ *R 1/ORd񅝝WC/,]Ȱs*o͛i3fJ1ǺvgVa|2ғ?E&kmEcA-3l1DQh7b(̦h,LzX;kmzI-:u[=[ j4.[U3XlF.Vعc7wmzV2k{mmZ6+FVEk=Wٵ{3kbecm*F5(]9nur1ۛtMRSWJNk;mʺn먒a׶ڮҭkw+6ڻ(#1nڶc}4k+ˑN)"޻N\.Wi^w]kl -TQt^, ^zN;.\AW5|9T! 'tHŦfPkV˾#/Xhb6!2i·bJ 1kTs+; +\j:v0RgQ**|('\x&$~ .:!$fw}w9ܸ?s飖 7͜O%D@j! |0c]Qؗ!0anku ''a|s:&'/e%I v|I;Q7Ɓi-gI^NLAʠ,R~|N7)虈ݹ\\^"/q!cR./Qxȷpr4֠cD\b8|`#X! lFf߂R&8ݽf<a!WC#] ;_մԶ)).GҎ`U[D e~ܛ 䗃&QJ` Ph6ĥ]8AlJ *P14񸜋t/DA4iwN-Y+IV~QXl@q`VTí@=i"xQ z:@;}V%F&lefv/3tu9bIP>J9͔4 V cW(=Gz UyeÎpp-Pg(=˚(MEĎH/J)?/NiݵқӁ҃eaNF傄DwL]zWJ0bs `cM.嫅X+f`#U/^fisVhcv̙CΘ6MW+0i81UE ]<!+*A -aG6<@0y\9/;@6M~FmS$pG$ht{aY+*#N> m\aUe]"@e?sÕtChAܾ)Mlr]sfFnuʍjc¨Ƴrzơ=hݴn <ҁ<쥣*U\-on%2RTNp_ O2~&lbsLY%*uVV#.A#f@tݼV6; :c5IXS/tC sy`c*&#IcG(:jΨƺ27(J5@"|V۝SX^`kMlPkZ=`+fa9nt&l嫛%|J7oe 5_yM/euMr; o:NƘ0l^YEj_`"__<ƗBEE)jeOSRE!4dMmjemWoVeQҵ}hbcDi $6nAQ2QV徛skɼa}.湱TV6cjUljr&ج[WܶX{lh.mr6dAmr5S{)Ū2"Y-VZ!Y6bX dZ^;fvfyvۑ .մڹ}|;\Ju;%*)ɹlEnbM9w-:n;(vwMw[[&;s;W;ste]\)+vJ;F"]KtˤNvɷZ4_Zz ѥ14$4bZ1bRaEBYICmAhdH"2\܉2B 53FݭذLWUmum]je(m V(*0A-΄3f) 2f@`(h P%I`@ R$IhH0Za*(MfmX21]ݭRhIDSԑ2 * \IbBЖݬzyݷu1[ůMxM||bX0r L ]FH Pcq]\ݺ|yT@dNvm~46ſ8ZcGߵ{Lx;w"" 9&]\%ω'YW :]~9H6;:&#,3IOwvtBò/JKzp)tfMn^M ̨ {ʝHn83mۍz9=%~Y9C)d5=jC DI_n%&PRr 0oi&H.E֏vEb7 R8bc&+0"\.9IЏ(:(vA=죳DNa[ma&1E=5g'kVZN>a1O6 dLAyA :Ql< R@I7q1(ݼE2:\Kc;Eo'?.qӡӑ-J;TׯiOt 鷏62 ^h UV hG7mکސ- 'n]OxnóJjS4e1jQkD5-sk 5~€ƐnޒyDo7M@YW$D%*:#VQ TA ǿ1 Z")#=܍䍮ۯ5*zz\e[_qZT&Զ콈J(߿\-?ϧc9L ]W=ee >)xɶC:ZMHT6̡T͈JFA _Kxk%<_1B5sNU#I  W uFM\(TnTkFVչ)DTQ2#drsTV+aL[\ʪbVj-4œB4DWTl%Y1%5-IAIkJXm5jWj(%*k\ƶ-(-%k;w]Fsuvn}ۇוr^t۽lowW<-yoSY{uy[mjZk{[[\Vث7lZ1oU{oyo7j9L_]mHj2|v 'ϕkJw65)=.CB^ zkZ,PYB,߂(ƃk I Lt0 ̏A{$D};)TMP8%ixY.ep鎐rzh§zr L {6S4uk^xXI!FN6Whv F"޷bO>~:3)|<dfة'5yوv&^g!{Y UlNK 7Q+BìCAM)Bj\UfAp}^4}mlu}c;ټ[GTQ.|  2?E\vÃCH`7ClC."!h%fEq.Y<8(xsIR]_vzپ}rk0})V v7[o6Fs %SQY~$S7{2VY;?$by 52 s'LWWgkbֻ6 :juC7#/A. EY9?sWeGx.2uzr]-hF^QEY 9 hh?d ^WRG:u"~`gSa=jt>֤?85p_`.b۪Vl9v`[۱!5nMaϯEma ~VE H!?yTB'$F*1lbC"(ך&-վ֬4emX_MV}(̲f7uu65A5v/}s^W6ȘDD 9lL0p&j%w1naD 0OF >0YQw_>V׎:%)@HQ_F%XIxO5۞J%T~aglğ&h ba񀿈C3ɅHF3-;oȊ%Fᗝ` m怢>[f.>$w l<5ƪ* Lh @TnThwM9zD41lm fXy (UfoBd6[M4@jMw[ÎnFvئxɭ΂Aac=r2>i oj^hӄt djPyY,"%R*m. yU9S N@sS N#džNip:)sń7 밄3pu;]WX]2sm|a(xYDDNކFD,b]a*JY\S˙αou͌.5ρp*WBxh5a㩷bQD/r}lػ%KV-({O>'Gp RI1ԒagkQ[Ag UՅJ,ı{:[@ Os0xOEUc(dY' J5ϫŃGѩT(Ʒor6.*yr⢏C3p̈xLݭ¸b((ebhJ=Hp}S(G S(K|>1HIiEH#b:;$N|":a~1{harJh`nXiiT}梀k!g$a]/Gٸ>'%n,FE~KfO"w䯖tݾ MٛuR̜KA@t d_(N:2~{^C8u*1)'"WڿgZS~֧H`0W_?^YjUcWjdzHDz^ 2rxnU6rEՒ嚨$."[ۚǿ0><{*WBG7g;;5S M#m˻ňF%2a%TzRTi P+CaoWt^ #2\owv^N]:]- /WmçH Vִֻ-֯uիw**AQ0da@X $ea,3H,bXɴYd4Cc%IEVi%Qic92Zƶ5VۮW7Mt1S˂.⻸ ]݄B)1p湮wnXfK)vWtF.r.EtQ-˓Rh+wsskuHBvHdgdS0  |yA!'3>("&HAa Xom׈nxQkt&{d\^NGD$m%\@d{ ޴$ڙbnskya!))ǣ̍im?F}9 w{z _pמjFl5 + ~].$鱶:`ȟ?W⡎ } c0wpB*RQىm|KRڈ,~04i(Jc/q! }iyl|vC-әkCxhqb+E=_L3&LFaU)L|;s;|W5\0Bf<%bd5AN& ZB Q`;\E70eUr+ {X-*(kqށIy O1At7?tʴ$!_ mRYpt=irΚ:3%c.@f=@霒;y! VCz؟MQ(c W9\+=>aŬX-i@emJ@c,$hp@vH p@؏F 4]X%tJ9 &i V* KsڕB`DWӏqOԄ=E(V{FŶ ѯㇴ@>cc309f"jfuqfQ&ݾ`t:>;\{v_?[bv1ʝA>l#Z-rg-5D{1hLr=ߩc֠br76챉>L+Τ )U@C"Sڒ h2<4œp kl7Y6(REAd0(;7Trߝw`-:3 1ДO;vY|o!D#-(؞wYHf5q^U性\5ZKZ)=ӁܧZe‰q*T ~1x3ެS '4|LRddbC!L zzP.}{kF@E~ƸrX>AZ p G8;4l%F֯-eR0A ==ex Ś4*ij0@!~ X,aX~TL5F߉3_#fR:`p&"~A b41r>rWZA*ǢhTˏAxvHVT`J:ΎgBɹەqK>Y ѥ]"2O.&ଡ଼k; A?|9V8Js4BxXѹE g2Ű1_Hߖ7p 4pVE_M͓{--#lv9zmkCG4`-{n>[cF}%&爗5[z/S_x8^x&e-BBєYMKc e I{ŗ peIcryse:7l\Ya}1+w6F7C6ֲs,wO4]iU/yv.؆ZbY~),fiS; =hj*i4tՕTZꦭr[jջ_捛!46ؒ& %ne Xl֪[kQIV[  H&,ڥqchOdÏH1n/d}>! D% ^w& iLGVso$da6YpE* /ZfN6F!s QV%FD&CAZU*ԯ2W!dQ(C *QDږZRMz)n 4A;#{tKtPrJ&P+&VNsfYk{ kY A%0) E/EFf܂L-GFr7(T@҃5Y29m6ͰgJ |K8247Gg&^/sf.4r3/{ߪnx2ņ2 >$j /7;tk ЩnV;ʝ%`Yh0Gsq _Bu'Ճ79$Qm!6U9rrV± fpIt8l0H:\0);kv$;Y^Y6ܣ.60.¥T@(`}Y{J FBB%ΨLޑ=$DvP rۑ㠤D$a̲y;cynkwS- 5P*lKd8l[h6$MT;.9C=]!Һ3P^fJxex!Xh=X7XJkq1+qRT)D 7Iɧݓ. &(O`C)R!ݴ.o3[G>1Nl|M4| 0'_plKD$wiHb0E/y(74R: aT(q4d ,ZՋѲX#3,3*^G}GrP!"Z3ܨo9bU@۝dAS#0oDԆ\J}1hչBI 7#xc Ӱ0un4/..hHw"==֓k9…WvtMhʘt獻-τl4,^yU:;kV"2^5:jT O)d) zo" AܜScHȞ44`<*NfL^ۣAȸjq&s_h>[Wಡ>*ޚ翤heޱQo76yT@ i5zrc cB9?ȟ@jwSCۦD5Ɣ}k~5Da vGL.y۪zdždGݤnȹwj▪#@rS@y#noF]:%ŊR;دCUܷϏ! AO<Ҧ 5DEo& lTNmf߻em9fwyo^T*e4po૿:D Q_Nza*+bݺ4$1/#GgtyZ[r -ktfjE=816,2\\o߲z3=%_E4 k Q1t8&؆w4N J0YsG5aÞ]NoFtL_k%Mt̽I:-]5Ki/*.dFǝ7^R[RWS )Q:UܪWeo: ޵6̛'HRoW:rO {4%9U7lf=vn vmkF:{g뎒!}/@n\ˆuh R5}l{!(TQ{a@H_LKH! TF5.jc15kܑ:UTZV[XSW6VV-\+Zmͽ#RI̶Fmkf VU]m6J,!QPFlmFٳVʑJbT!,bMi4MkV6m5yw)jELݺUI-#Z{cl%Ц J@Xn\wxu^ZkHFYktΧt́g [6}IgƐ`MP-]teBΪsws )ьj20R $ 1{."ܯ ջ9Vp&#y`APc޵B j;H ˏ2WM~8ME$.;kw+1,`,@tsTmE1=jpQ etuCVm]:v3Uiɜܻ!qўEBttȑu(VJ! 8.30Xxyߖ3/GX`0G;8܀a ׷k!`& M7o{nɈ 1zC\]  "l^ygX\owMF''q{zMztvCZj<=f1;") ۪+}oVƛl{ cq; ;HoM /,7f$ºZG24d $(;:\y0"bsKq9Zcgq2Pp31}bEl`|Lݐy &̺;Ïe5ɿ D> 7Ã=-6/]aHX[ݦ(5 R#>{7^7h:~7 :ey3;{?vW WT9˒W n+&Ҫ3!887i]+s9D2#4"3iƗ SZ1$ DA &x2lG f2aHEDO~`; ̃' -+UnÞf>rp%f@#p,f787=p2#~:ʼnNys2˘~>GNP<.Yfԧ}tRiAT%c"</RK  {8Yc*N `28oPe?MŬpbF0_oUGQ3LX=2+Ş,]į:' w~HĔS%j$?A+i_iUTԍ 4"OI]䊲J%l[/ vg0akޣ\~6TdbT}VH!pۮ1?v/UBoX6knUBR<^*fuT\+4Eڹ,v[9t4aFp/{_jY5XBht6kn gd0-Щ֟j[msչ[vW[EhV5oVnmٴRmދnuv^a;N]2iw7u&Ҧk}m}ebW[ZIjn֍(edlFQeSbDܴhj&Wk((*it#2gwr gO֖>ۤ*@ ]rT̪};3`se8RE$x y ,C**;ڮ)ԚB&Ԍсθ&y! WK@iE) [/A%F;:>A9WAga­ChA;_zT- }bU2}DpL-#.e3 ,+O”Ű ݙ9PNl(dyyyδgV&̺+ч#9wsMط)TH~.` R@NwٽσN[Qi)QQMmxz"=dm!Bq[8ib,Ѭ1v+QHjcC.ڬ=Ѷh 1J9h`0uā.*"ڴ&Ìg-ڨG#^۞Tu;lJMMEBVMd}2[Ue Gn7&宔~&CEV W Z +*<me@`žzou #  j :.|$}c0o %&nC;*`>3 PPSAL86 lӍw4Xcm&\P(Gd!c3&D1:099#>NgT~ܚu1';*î Uw5/c$$G08˕5TtC0BZBލ A[GC%Ӿbz0PX/[T@:l2mr8 qN*E#:M>͝HRQ^7b7 ROKans.m4T_ZdiM|(yۭ_yʱqZfF+d (cV/a{i]XrxV[wœk uzNA&,GPPci$GDjl }>2f4Pj[/*6B6Ig,gd3 _$5WBR (.2Ii< Ԃ߬瀘(* 7恝lPFB-pB8jJq OZ-uqA؈]"nUz&u\ Vi M:L̑sGwa,% 9j?fEf(e;hF.DH;͢"^(w!jEi^jH+k]nsx5_ ߌhs Rwwzqrsu!YKNѼʼ sˤ+7>,UѹV?1w&h:[\q:uf['7mB_);غlv?9V oE|)t孝x75f.퍄Q^ F}f.MѭmZA-_z_o)W>|Y!BlY-G|]p1:\*bޛx[c睢sT>㢨ǫ qrߚŚ61ZnaR]#,-_r~ŕ)+FKhE&ѣMM[ơlymj-k/]ƪƶmUѶf^oM,FJe1,ԱAo ƫ]9wOfzڤȔbFM ~3Ə8"L7y1h1 &(C[X!dځہʖZ&&`D@816; nsNQx[QTo,JSq2vK^W0#ac+`EsiĬ1eFdwg4Vys8$6\{$ˀ bYb8Θ9;s%3^z w2 (R0#ȹC RAye_V:tkrP0[p=E؃l+P.93fv)WeD;?@%Lh;e1wɄ0BI/Tj&_=&w߱[^5C=X;Xz97EϪw[`~ Y$ n@If(!VoLQD<9&ޭl `j c5(qF _)G6hh7fC鐆sMB@ 3kSt B@1kF Y;18]/RO^'Y-4 puYIM  gow+|Mfc:|Z1nz;Nۮ.ӅZr/='"<%iÁ9?t-xr-v㹖=Vn1]']U>.V]JJy1*쿉,Ք)=[kj%߫vTjЧn2=x ffń8ū>#0Uwe~ϗW,TWݒ*T*j9>Y]P]g,%/Nѳ1M[xQ/&U1k"+t^9,}ҕ޽sW{O}d/DQò e>mjs]ti^S{_Rfd,~=-v(lMYs93mb4lM%$=pVZ*yD+;خ3q>t[FJr6kq^ tj5̓\5ڊ%_;J]k=^rֿm֣Ͷ07r짌#=PUpZ*!+ z6R:/kN{%2d29|@InDD`5:;#/0y ؂G>v!'Z۠vSD=wXd|iRiƞ,-4±g;:Pb$KhP06D(vJcQ WU,EMܻSXo")z6r>|iHgLT6t齀{ud =fQI;RP`Ear)?K,u;XRVYb 'H۟ A̩,C(l DO0l]tH!)/jW k8phAzD .TP64!V:x@s ΐKp nLmtwJUUWtZ=TD ΫdM^b _ChPzAmQ%;:BlUa5ب/J *<:*B653۬*N{'JʂKJЕ8t jgU=12TD܄\/bfe:] ~}  *6(@JԒ (DOeEgtS[XhT B*PEX9S ;O@SΉ}_taY!GSy`l_ 9 `smT 🢡_> dQU" PaᾱRD\85U@)2vީLCTԤKovDi'GoR7Z H*B $/:0qw ȽJP#U 1Z+r~r%dK٩bhœ>Ւm`m-6jMZN(;侾Z-yםluׯrM۶L2ɷثc&5/DڍmYMhlQAB͊э4i2̔j]Z] K^tY1Ddj6! Z湋ՋFwj䆴6=z*r8yYn}Cmb5@e%Pހ0TvjUȉRso%,HZKv:XbSm--^Z8Zn)ff5 S^(O|dPS< P\[RhP=C٥?X8B!Nאo'swHy'J 3֞R^{qQpcA71ψsjg*bU,NZ2Sɫp(6a0wic}T~dǾGnB=l19c;coх@Tܳ@ؠ2e_EGޢ֫Qz>_#|Ld4Mmw;pH ޽1} aj> ?ՆFex$+PI V܄MpZo!`}"",9e@]fJWrVq^'ZQ*8(RQG-9Ck_3h쒎c> Y 8DbƶF6/rsHW/o\D\,pa3b=>'*?SO_1ʄ)).$Ѝp?ㅞCReYVUn۟S 1hzhR)L7 `hpH9k RڥYց?EHy{w4/Nf)AL:)j7m `C!R$1^0 O ( [9 ;]]iFUE%n5vdE )lblzNbyf!K;P2 Nۗ'2 w"~hݵN.Wwg+&V\h,!Ѵ ]qcuT%>kǔ䪣ngr(qmUd{ Cz ;M" Xx*{ù;bx"J+'zޤVSLfOF H)@,|oQɮMInLږH?U*QiB4Z߯D@|hA'c7ml YHtdt߇T_ġ Bja7SUݕCh % T2uVJAE@LW mʻtGʸtr3zk:1ObΜv6 ;YjrP\G2ʛ'X34*ѥŠUօ)Qkگf%4í,E80) V u 1 (uN 2ꬩSdb9SBitGvȰ=HIJ )θJՁ46EB%O5鐐)JtV*B1]1,d4y5+2kuϗvu30*d6ihcaZJdžb7?lRV$` Ҟ?Psk.l8@ɮhP%R+dq(UoC  U9z\ɍCu0DP ֳAI ]QDұ/L{ ل WӐbq䄲BLv9\D2u8Y :junC0iؚuZC2Il Q$.hA$ψ@:BQIνw/X<" v6ۢ\pkxR,T5y[K<] j[Kmғg=FlZM*KH)N,M\^{ny ㍅7U4Dv5S2VXĆbmQPQYmfV"PbXBb6R*} J3Ý>2mrzD( E0xBQ!x_UBt^O{=Xs6Tnu=ffGH<~IʨLr.UHS1wV$`\K,u.Z?N&~ q k·>K CcfxFw(mXB36kD 2 2φY z:ba.-j;jEJJ;ŘvҩՐBGA9 -MDgy33 1pb<qM'`G=ppA32}o<{6dOode#yUnpb% zy{y5SMo{!P+͜Ǖ 6!DR-7tft1]a)râ` 'mY2v #BA>U9QpM5i'u%t8MJ3 98JUT٨$ M,ڂ5T84> f='!PM)~BL `Md&,HzeӐРgԏ1Bvp 2U(t90_ Kq5j$:('A3d? KKǮ]y0$)ǩ5I[l[Ym{ mb[TDgꪫJ2Zxqrk֫^[K /D En nlE?0+v߱0D~?2~DPV[u5頫Uc^nSsvr,6#Fk`]Qmmt,owvu}xXJHIť\,]ڄv~LSȃeF^(Cݘa Ot&@X5!${Ȓ$ukg}8G2=6bkٽ);4^r*4_JWKpO'_'㙨_)B+dsT3@ȆS$F>wo1%nqGua@psJV|C@P]BC(#$kӱ)6o8'Byo"E*YL)6)8xl&ޛrXXF}[B%Z~_)Z=߉ &yUly^r'*JV*Uϻ( l@RCdzd5@]OPb0CH=7#ȡ4PK.#x4dL7,η!ថY*qwG&vqL&#JŬ0*҈TmY0kp>Gi #5J'вo0$Y+LrvtRߥU>Js3Rqػ78Oцp)^)^okƨ _,bẻ8|I09th]g(`2Q 1;ctxwIV )D 2{[]ĺj=Xο @=P ]M){3 oDb2qj8F@(9ⳁ< q@~ ABIZAmj1(PJ,g \dlٴYR/q\nt5pXliQyyȩؚi7us h6 ^mRẹYמdFN𐳢κ@DeVT6HF'7,/0=wϙtF9rO/iK`ñRpF $Ob;Tn|a79waQ,YhT*(-6)CGo=InN|Q]@q(pa$ wmF i޷1|{0MPŗ+(B.yո-a֏Yz esjtK ^7H4=kG͡8߮;w&p9u㛃ºiCpV69^果|rԭ'lwfks[V[TQx~bNޟBzFc:F$}c\p;E, L‡9ø=a۵GF=*VVpsGe@ϲq".ӽQ豛YE06ʥi5O[5vFaZ j_70LAw6L-il0! I`s$g=^7+Ơ.P8I)p?#ф"˘,(=[b}Gl] CR!#!MJ9%)A17YG0B^F4<6*ă3oW/ݯv{j'㨾-cے*Z]1vZq=gŎ~]AkJKAIEN.PHN|E}f1#<"'IյlCqƕ U#T |7*ᱧixp]__!aʜYPi2QЭ)׍ .kdl;˄!+mgdDLoeֹY:aMa߉~ Bumjm[R&a*BIL&g?n5)u(jBޤ fDa`2ڴ8Sb1uL (CȦ妝R BM :X)+wsXN 2Una Y|7Y_p)eepp`Al@nIDA!IY5 |@^.]n!N yP۱z<Z3ٗeDlAiNÊ:m 5ƙ p̄2:_!էALt33Z:dީ^H׶8ǶjxhER F ϕQW^%qu2Ӧ] arq╓y<@A<@ c zZ~Nsz^N2`r vk]Vۊ\:6y=;<8ҙfL1d$PpHħǐ[̀ 1H xKpkw ':˛¤n+rFhls~C8 ާO/2 ߣ^ =&ySAr[oQ޺;?oi:OIx7/G4#8g/Hڭ~*z9LǦ;U?}>I, H,9:/zpBQ5d…p@᠕+ I4mx"*B4=uڍ6Z6$ ;a+`wf!D=1rl]PippowßU,I3iK ׅe*UAu3F- Y F¦QOѫs(S>?NEsڑw%@2Pۣޢ_>Au$d$_{[?\1Uݫ [.wEFHLmZeddBDdQEX`ԐyL`HUo-vCmj>20@H9kkz F(-E)tPKqMۜ7k䄙4&KavMj;4Egg~KKOlfƄ5I$()u5[Cd 5p4*vUŔC:wVǐ3D@VTAbW? H1`Dƙ}$, ܼ^$^ SPz$ÑH2,GwGI!'}6޴P*w i<Ҏի[Ep\kQ;j{m6薦Y-!dG%_z+hЉ!Pyѹҩ2QĆ9@ƣ*VQ_ ̥7k,Sb6ePxeM401D%\SGy4KAy"]~w ČUdHg`n!Kf"j! b;U_<`G梛 W+@CTJMpvtJT QUzI,6{HP4ePw#+|:Dl6,-2<+=U9NDҭ \H4x4m"UJ*S`*AJA`z]y"GbV;Je la-Ϳ6޳Qb5x[5mD-MhR +(نY>M `.Tsk90R >jɆ7X'bGl)>*U˂jq%ꄦ #Kj=E/̄r,k{r(,+!Ll)ph&xK_ijE %ZA0O ]f vdLy0UʎCUЕo{BpU`&~}-lwrr]}(>l"+xEōI+gNt_hTpEE:]tEsնf^^{z ?< ܙAO2B j6&@җ oFZ|GMUyT( k^yP"R&Ӎaɹ.wMˏa6?e4UnP,'JQaSwK&ʬm/*dyVkzzWLJ!"n \c؉\)!Z̬ /ɋ+8-R\_ !Rz3S[G[X0yEemUk):~7p+or8 ؗGnX߾]&9UÕG.ϧɬMT'0q#Mal8\:=ɍ^v妨넼 Y!wmio~\MzWM)涷ᰥs]@,ۖT[TɵkmkEZmkiwn6@wN;wtv\E]]ۙݮm5[kͫ65RjIc4ѦbMZ*-R%PEUfZ#2Ai6#K)*I&ƑEA"2B(٫Z5`f\+j5(F6AܵrjEd[QTw\"֍5ݧ5 ۫w\wnn]4-bګEhvknln\6-&W5vl`͙i[e塔U)veBstqz*s!2lMyR#(!O!{LWkR1VzP a˝~Bdw +  4ەE=6|`k`{R3C:.XYv ło]ؾ:VSo5ee, ρFYvo'\tUl<{3=aa Z)5 rEv3P~7]q^lOv/ wcFv$i]aUH5}V_yhZDr]"d(TP &];͍>-nkK 1Cz-cOcیW: [eyS_)׼* FՉ籚F֓׳W$9 t]-jbA¢kJ6d sgN6ֶ( oȻ2_F[gLckʶ94Qk׼8+Y3ohqUjU! מ:GFnctxV-XyduSյd[P w,#s4|Wi_Hr]J3bb샂 x&zW](wGd *rjnݓk߄{,3%F5I c 0d֩-TIZKڣ&1QTf(Uݕ]*4Z5  e)6ZQmcx5"6QJ#iB[Ri32M͝f#3;BXn{jq$cfnWi\;ܹ5jTmiMBn]WmۺWU-F5Lٖ64Id*JHML6kfvƮۖQsv$hJfZ%j-F֐εn۵Dj6ZiZ 4V]Ոo5UhثQID%jA lƢBf-@UF6gL5:C*U:/3XÝ$UTeih#4wl8|..{*, {4W%DJtAo˥X e;ğɛjFOG5 /+|+n7ޥƅ*@t&=9^ 6SK 52(XbZ=hv89QW^GEX<w+}]u^6RZ]CP14;3=RІ.C)1Q\W&CЇMAP (v[i6=R zff!MǃHL c"B.4!IsN(HVL;3=Xpw^Nx<\ [idHM!- p$1p*`#{6[v;XBk-:., >C jZ4sx~MlF[L^Jsv`V *"mR*=`5q0>tPg8Ә]`ҩZ3;j-L}8&N0/p踌C0ֽ[G3ƨ̀x߻NHHcL9کw>xZ]lw [] IXL{%0xVL,gV )2";oC> λK)JBg> A{-q5uPbGCS faOt|KrLYl.Ç:ś r1_nz#K;;ۗ-y ##LƸm=o +6F4nX2P?}lҽpfS0F:pmqkmfq{;A>m gi_5m&>H-^!Gr/[~>c>?#Z s[6Rؾ-u!!#5]Vr 8Qm(/T 7ո"xs+öXIZτ|w3[Bo6[䐪5t1/ݑlL(eO$~+fVAUn7N=k#pp7j*kWf UX8EPh-uE|_7l0+ C+Kt@plr{/׵^* +c!1mctIܯHn3mm":Z=YHϢ9iZ=Qi6*ݻuvN0:l[BTXdOܮidF .ɰW.Rm h6ř͊ݢYbͳ1&l mA6L̻52ݶm\YbLD A13XlHAd,`l+cn"KIT- $!5jKXf4[F6Je*a5lm*MLZ,F[jw%*m[yһTM4L,&6#NV*KmjMW*[+b5kSn%eMfUl53TVڂI3l14B`HYuq[4b(ES#Ugrؿ~!¦xF޹aEh n1rnyLC3-P7),9{z7/5qL'2@ pp5frOg=/9d5BUAzkŀP%\]Q^}maIA<| G@  qA6[0afgmk#Tb(84eqU;nwj> ,/e 3`Eu0Wg xp&00؀xAÐg}37`W,d.W5B ,85oro[T:G2}bkiZFUF .:<Ԃ1aJyzkbx'wv9t1ֵ]_8|<.Տ~eȲ1 x.8YgQ[QqaԼHmb,2m,acNgs Hjz5y|fW ʌ|eڅ(T;+b ϗhL!'cY& >FJ,Kgf6 p-Jzm30򧦛OˣzbL<0ebe=02/YWC39Nt|; }qp9Fy?/ެ&uGa@OR2㳎#Xp3iHg1MD\[T} mm1Tt͌F5nk!~5#\vǷaUݴ$230de"bL`oF-x220Pc(:vm~tӒ@dQ稐.b}w:'mW3J/nnSyYȅC0Mkxw[n҆{#u _†A\ aTUN H@AUӌv MWwv^gs@[^ fAD}sQɧruu>L zEٯjÓN^Ѩ;LZ]L|AM W GA{z( 44ex:ɠϻxBhgiSCğfm q!f~q@2JmRbGmc^>ڲ,'&QkHnD`]us 㛲t:Ʋ|o⯽^X4b ]4aVPQM\w"ʺь&{~a% \wv|.X5T֒V8V3>V+^XRʌ7.5mXzdB ]ƹ42٪h2m9tƿk'h] u/I}:oApS t*w4r)sFWVGc"Jt(hHhTJ2.}:LRtn.8ec}W-/? d\-|XqBED1O5`cYET(N.}U4D0H=RMc)ܡ!y:Y(" Zjna ׅ`=Q V_6F 8 XPS&4Оxu&I$4n̒Gb0J uiD@J,v/@6NncDtF(Dx jG&pvMPc L4k+mM5,ڊԕ[kn(Qf]ۢ~j,ZѦZ IsZcXɬmU-e6ֹ"ƨb$ Z6؍I)12i"56͚$源Gut&)fJR$d wcЂMvPA0"ie(S2CI4hAH% lA)HHBA M QleIJ34Bl$lYL)S-R[)`fY$Qe(U#4LawF6j2juj\jhB ZJb#G;l{NVۤu+vzX+&՗g^ƵWLI-`H%65VUVjsM^nͨũ(, $)IH1v^mgsэ84x #uN_)HhcűXѤ%jD?Xm>O6t [ iZnpa(\BQߡ: q "QLƂe9;> ژ4 fS?C4߬/(S]8Pa_ GhwO]1xDD=nP:.X:V[1H E!$‘-xxIn5%!,6ߒc y<@I7EfE3Pۿ!堨ƺYM\p**%]%׭?̑mH_Io"L7X#BWArcx"hwӏK\-\g1IW(QarGTDя7fYDS_{>n48Ҁ<,.}02~o `y͹ᴬ0cmʻP`힜j6 4kmFDM̐̽J5`p eAvLo Zrջy6zl003Hjhaku-̌6cވ^(>AO?)=&ΰXw.ta&)eLKL+1;ԦKFC3ҔNCڎp)x ) = qypyLҔ밝+mt V^ צTnke2FR1߲ǁ% Rl3!^A! H( eAnǞw5 @`$(j 3 &ڡߏRHg.`Aewp=մsd~MT5J2̺r^,WcK@o1u4q5Z|*lKCzW]egAp.f+G}}CFBcDɇjgjcR*Pq=q;cX1~0u^su9ngz~ 83\PћcG~>--w.{{_i=)MI'ɻ]شܓ=e'(/u;JNihniPe9i{yҼCϫDnČCAۛSvf{g ^[ô+m F{ m:'m3;noݖQ4Ձ =_[2.ʽQU B@E|YߓQ:!ܢ7޺ N[ Bvi2+^-ch4Eؼ58rewbʼnyjQ\^Ք/KGG)AWB~5!=LgO5ݗ&{߷Zɡ))$Ync;׮Q ƃ$ QSQICijd2͍VmWVVҹkn1Vƣtcr$cUu6Q %*64F٪5"˭sc[-IcE0ƺjHݵ*iF:˷wqtm-BŢ͐ݶjVy ηnk[Ѫ@ %wUCh5X9=}~[T7 5z9T{[b!偙!3"(&D7>IXn[lkਈArMK;e}`!˄B"w0k~'ah˿DpJ4s4/`` 4c|)vS<!Jхs҂xyY_43?zPfx =tԀ{DfECb{ZQu#QR m=.tATta)v{y#ͨ p'3:6+)Vr!gzz6˟xJ )ȅd&Cv#T~R哝BLfQn=mT@$ ^F#Dfja@蚯?amy.t` 1N'V;7q'hu+{C!H*c_Fk*wZ]C}3!:wf#4[pOQ!+;f*UdDo2^W%YOe(KLF3Ql^S#+pB^\Ѯg"a*kv)g>8ҙo1`:چ07zkwL$\$NxǶ Aԧ1ŬfKHaT =.F߾z{Y9/Tsq8 jo4g<;0" Zzr?Ze\*q:pc6pQiQdzP|co-X\\%U }d1qWUk+p$ӌ58 A?iWOuk ;ry k^DG%Zq "lXkW]O ɝ,P9o e2lϙdGO.k1b$c:yw\vk_uKSק@ltYti7.zpk M|- 5m~IawJفied!wÎ|ixƵ B|K ^h[g ^S%5TVqM*іMZ,ή@M:^h''ֵi,c ,mU Bi];>¶WMb EMMCIZ8/TڨҚnⷭM:҈6DK1ed.MB %ktrCjRC7mUGU9]wty3(mc4qrAfD9(rKF& F:st,1_-32𽖰źx ZCe4m& QK6RX.mC{+eG~ETJATD幤ܺӭ9gnԚS=ݦRdQIKlHfM$YQګ卮FڷW0MHSecEƭںhXյ‚a"f5 [woky znm]W ޷26Vō]v:n抍[ʖ65mb" 955{ϔ2icX?y18hHxK|qꋰE%&H kJ@!%@ 2=YYYS 5̅W ;;VoBEd2@By‘羱AД. BVK: Qae+bV5d Fj>Qui,.tqonh!Z_ca6Ϸ k* a`ʣDK3250lٿx~.`"9me븳yS@@*CUx R$^6@G㥘e2cʛ=ͪ0ۑB&lȕ!\V-~Zֱ9 ¬ z7 972L/ vqp&lƁ9ltدjHF۵;/^|iW`I-"]̌(@AC_Prb!0ۼQ+ȑAړ ovNR;059i]f2Gq>ff'+mBX sƠMiz hsƏ[KOx`$2>+""[/*jwáNcuvgv1{a0oưQsM*:։BR\EL]`!k1B)"C\xk- 1[1PHԅM:>X\JƟ6|1 ۰Df{Ú".UؔӶӘǓf& aee0G*bP_a$I=X?h'iDBLǫajnV'd~"0#"J7yYj7n>H0ZW>V|#h&RD]CGNvW&T1 Lpd tU@ͯ+! !D? !G^Z]:`=q{-m3z׻ Sf|;;jP{ 5_h{(\Qg>޼00Brv Fz x#;CKv^NPfܫq:ַ ٶ*sHn^evΰ5һ_Yҩp{&Ů,ᤱG{.5(ncQ]qXlG|ZYU'/=kqS7K) Mκޣ\m7E^i V"c<1:8B 4m̈́.eDзsLv11{6-yútnjNCWN 4X$ sx̽oYm znS6utO5s~NrĤi>RWX-9pW[Ucsmk دh\n͡~4x,fRKhkv $%Hvxݧc4#o5a:1]4UCf_ u66ͳ8Fd#=ax{iNp_R"`/(m^o+2ZTUrՋmF;ѵbX6]sM{$o5me+bɪ6ѭ)zq61dHJ*LdglG6LQLB;6? /< &uXMP!(-t@]˙&!j<` $:D +fp8Jp hAzXUcXq(-SRSUVw6inSCUM U^IqjTRQ0K 5t{}+Z "=0FߙF3a[fDd$"|5a5*aPA7M&`QTŁ%oXϑi#EyeG1gl oL%m˒|Tu=.Dԇ/!^ưHcoܯ͙l:+ 2{Pbcocg.RUR?RN^ꃞ$~j\ X72 )ti`RI$БbemoA=ՁEK^3ۯzW]pڴ:xGsv},&Tjfyf&7nB(5DDj4bYHY/(#%#쾕 $3SzTͤSO!ٝ}M$`Y-~s:\cd. 6FP2ʆFg6&{L7<d+s6q X &n2\@jv#ߘ"zѪiAVL(#:]int3̑5t`yNU@ v7,ͥpR^:+ONMc @4ut1_&΍qPc86N+t wcM-niO8h[f2$r}?ʏ JAppO2C{ E!~uU'NM|zAQDezTpm߳@J!%}_ 0rAwC˟Oy%PqP(:P(&4;6A 7* n$p^fLA֯v (;Vk! v<2',mL,2sVt[yXauZi0^yIyCZx8?{F 44$?zEђCPn51=BCvgl1h9鳬-4#r_>Ӯ΂ۉooNZUPc%/};z֝DbCxVWFآJl5wn j_?066)ƍ¶8Qt=TtC:tνYH&mX^5QI(mTx6j!Xela_nG_uR-]*Ѥ@Dxn8s7[<hY-xcDypeβ םXX:LzKJ";·@QԘfj_ Q6]Sa%WhNLZX5^UV5yfIj뢸὚;%[A| X4Z:he=bɈ #06Ž5T 0HԄ!k{Vě A]!Њɡ Uhn\caWDnծ-VE$[]jyHynЮА"5Ö㢮PO8=r3xڵZÜN,-'Ok&ǜ_0q14[:A[dL!+AbaZbj8jp.d㞂c E 5kS7PcX>gN41o 1dV w!bӕn:& 7,lcf|3 J0Q#Ċ̢K1-Ϸ[ ؚ4B "D_Uoym^olEF\2 )lO&'E7GK}HLҽPd l!*VꈥNQI` F. hnz"];M \"őE+6d*#xԀ*MP#gDnh VקINp3`xY:Җ5M* ,Уtʥ ߕ/݂ E4uC{կǃ p2ЏgÎG 's>ydߌm\[2:)^$,w"E![M.}R|[G&;w6j^ZPPb|1?#XJ"z=>̭s^.A:9r`HDWaF$W<lC>1ꑻ""߾b1& n-F.>r pU8u<3C0(p X7m JiId'6 aԊ0([lƇt؈&\ /ĸ¸n7'yG3,pcí kࠇқ8;(m&:mE5jU;┬\'//f\t)Q6S#38],Eh2Y:(0 M:\a5JrN"|Hk@/;vz8HrA2)㑘Ya6({Fb0iFs״~S8 \Fu3q@ G 4^ 9oa-.?)<\[}#pjd>@C$+</cf.'`dgt;N~i}&0oސQ*ZrVV7֕S4.d-"$o 2%Unglqt|)q&2]v!v%fȜ\k{ ms79t!8E]1k+v{G.-D% -0ט4;{C9ܬXHg UrgSsgۊȷ %e. 7k."%36TlD[DN=n[Vc,\uCjO!8h/݋㊻UyshVࢠ%*}7P+6uqR5JiBT*B'9c37It 2ٴPI/,URTy#4 7l+nz([b8:CMT1Qn0YY.`\^= mWR_l׽\kzd.^xbfal8`v-՝N%At՛i5b ya226QºejYYgzUeQk㾉 X ^-&IzZ2/Df\)ܡ$E& ɶ`G$JCA9ި9whQ &enKgi͍c'>X 5bkjUYZ5]6 R6[o5Qګ <7~\nwH.xVT)PhL x}boqIlG&.!(*C0! #COZErAxq>$@wnc kIQ0z: 9V٫=h^5Dћ@ęil̠B5B"qÃ<*lHN =3A2j qM曹g] !4҂ }Ǿ0$nkFEw<{d])HNL.*B7'\)\y2Ȏd@ 'GGCO&b Bׅ#`%i hUkr`d9EĎ;VW&Pgc8kӒorARHa4!v=ʎFƗ#D&Uî%jwsl<%à=!M"}\(ofV LDŢ΃K|{&]7Q٬,qP upRB{" 3GeE#W4!ܼ՚t,;ʈBPixJ=ʴ I)ǫqDYD8/J5ܑb 42n|.kD'v}uQ/M57p5X׾ߓG0`Enʛ !B!KRI7`k>L٣@ \4ڤf$e\(Ak1S;4%h#t.N ⽲Dl~LæwMQH_; n2cy݋Q⽙v^F1<}LtS}Ta菳o0VKUJ%MDeEkY;2dҘ_g{B2#iP#6.Bk7gSE+`FAQDx%J5IO4oZHIUy 遨vP-({M\e~#|/+q;ۈAOwGҫKr7v?}uRf/fָ~5_AY57~ݴy,xp6:fFGIJw,FnJ1ٹ7:NDU HrsrCt ~`qfZcO  a\hq֣F_f>:Hf _U-" hivKFA08Vj\ B:a'ϦlQy2w ):Ǘ_Ɛ+gy$lr 0K^xA}6cwV+]nt{G2 =f5G'APy5qr_'VfziZxj.eNfœC09ea®HaћAޢޮխ}/V<!d}tFD9?nNG.펩޵#gNz/՗6"K7+<$dxbBW=+u2mv-3Y=W_ s+4k{H1l4ws1c#ZuFe2'U#l%" ChmQk5ZQR,fJ& $3i ()Z&#Q2c3_ڍY6F*j1TV6KQ&36%zlE65W5WJFE[b[j5m\[mۚԯZֵVFV[E%6yFv5vg9DӴ{[h5TZѶV4EQmjmj*Uk QFGwwsʣF6ԋ}$j)5$hmd5ɺ<э!kkjܵuxQQjMUFmokU쵺-,EIj$ dScW&-u`H9rѷڍQfZwsUsRVI3hs5QU[Sk\\kW+5Iʱ[|m5mו]A4k%T[Eo}oGdJ蛜,st9tq"#wtupcm"mҬܷnjSEf*R))mګhcm[4Y6j>;ېq#Tk^bڍ`HEx-\>_̰4Nfe UW@€{((lx&*uJB=@_#Tש TBf@)G%06VWBz9 OJkŪ8mQl=(GbJ`3Cs"aԞ>4@GqvZ\Sp5@^F B6Lͷd׍_82"- ,A~@@:SIӊ+}-<.5!a3GhzuBP)Lw$`Cg|ŌP,*Mѵ a@&$ǯw1H3 5Sb|]C\7ba\. Ns|Z] !txɐߡz,X-n j"a.Np &B3e> 0. V-Cmd$CTNf~En1<{mi*?]2T^Fd*J0]-~Ka&qe0C{O! 8'fBl8iVMɥ\lsrXΣpy)(D 8c`˅w;Shx!we88 l@f @ , FJW[$0d^.ĈKѿmx]Gkc*Oqo5dlA߮o\-[ib$%OWkVfcM!-mW5j57Lӫjm|6d,[jn+oѳ-'Ԛ-J3UͮmmmۖIVzջmk-k-\aw ym%eIXW-lQjELj k$͵5P Y6ɊI1@+54O5kPmdQbmm}kť˩!u뫾yٵvRlW;]*`=O'aџ鷤wŻ ˀFѮ^߄uê1Aӫ.%g6\SA{cZ23vbHR *14,3so{\ۋ4fB拚.Ck7zuFnP!RPhE{Ūh]7.f !AAC}A*)AɀHV W%cǧW@r4b\E|-1/4v- )`DG@4\i8dQ C27M6}ʻʉMZV@,J ot;u)i^` Q#'™\LBjaĶ l>'TrYzK CMw&ۤ=.=Zo}Oq)!q5*^-$<Վ :b):S 2 "x|\8"_!~AgMx{4y Gt1!a}ݐ`xjP&֢45P񒇣$A::8KR,BC+λ)9|7C3϶O\r-9tiIEL1Qi N.5  e9 +*x\ MΨ}P&7 cDy072;8 p"X'T(7Z0I@'B#\8k +՝!oJ¶`q[+p=\v7]j ŽFL o,Y {Z_@bxi0r"!m /;2T+h aN/Hsnk66DlARBWq{4ϿnHdDTxT;i^+w}߸޲*]It { YNɴ؃h 3y n 2Ǜ"†CnEޅ~v]zokP+ g8lHS{A!4tJ2e6 Em@`D~C+D^&-RnpSEՏ"j@h!=VUD=MZ1ENM^ü%7 9y,/- ?d0.y3|^+Md8J.C 4Gώq=YFټk qGďM0*ŗٔ(DJȏ_iQ[Ed)*ɲtw R `D : l[U!{䮩t[sA,!@Ɨ;B*Әj=5)`Ȃm«QuFx"2Er,z.Qz&$N׃o{ J5dm>;=!&:l2ƒrfBM]yN]YH{k`j}ȯ'VUE97(BbFJ)1jfWU춺">f$sENǻx{ &]xRw=;0wdTBeP>h`k.00@næIȔbD^P*b۫C}ъlWY_VPU[ЊD '3 BU8?* L,)TѶ*4@if~]TH,l#eJѥ@e/([dG]e1Q;L>ӛbh7 ՛AP*G6稏bU%A)dsET5\lT"8| A-iJuEnJR;%%$;{aD_C9dk["2 eM)yQBdi!- _M2(P>x tA!2vR+K,ãG^Cs@)SfMUfZ{Z-SUN8EP:, ^u\G >^E|qA®JjB0PΡ=' .UM~@>]pgQ-X4d4BW-$ (`ӑ v]HqfٜTFZThAr0DTLjG7DIdF%ЩJ0wZUnXX7FG|Q K .2G"v^b,S VF* .ncCeQg鶍J1fh"ѱlDXbXC uGitMPM&ե4(h'j<V9z/K9(TPK4e,3 !ޢH h CbP- %p $" %.1M!Q&f' !鿐]yt@EPa?Etgk烅(UBjҭKc1:*QlKCˆ:mL b, IviD˫xoT?g2 MrsB],NP֗OUz2 a z;(2ɓZtAAbx'|@ۺ;` s[/Q&;0\ ?x@2=("j3T˕.A+k_1 ZY8+s96;PeUy\ކhM~ AsN,h$4]Co8#Id(414Sr('eB\xQ lrͤ4$d+/sۦG<y5eU%ҙUT(;0}jA:Q:鲰!NVBGj-(Λ tE/J,#RFH@BTJvf+iAJv=(dr9Hi|0i'M-#7k.6u զ/.M7ԾLMK1j+p"yvND@ji[{֡uiJ9fD4kdrSdy2: ͋d-aXK@xj%ԇS@_ekiц\9V2MeͼvsiG: )Eevhmnw/]461`gx'M WO8N㾨AY=0m(4rq64P vf01r^]$Xޫ ܗy5]/p龂wӡc]c4&dOb2 !9+ny^)ɟQ,]T-`-#'r+8b2W5mv᮹,-d|;[,YR(Q ]+L&L3Gҁ!(NkQ\ɛ<%G$ Eqs&5~ޞ &cj7j ѷ\߀Jq"pg兌j4B7 `ih{G@쀛0E:!r T"ܥ mv̏Yͬ\fiZ glM}2{25{5ttnŵ] Lblk*l3 b4p< lj<7aAJ?gcOG}05n|k* VCp.8{n|fd]<$yMIv|0@1ۚRW(b2vcʻ\jSUs<.t ZGK|f7$~0uDߢh{,+`^7gUűB;Nfҙ7:+;ן=sxUʸ`am5(qUQwd_M;`Nozho{ѻ_-9.Dum:o-bb#„mk;4.:Y;D9m_:ZCsZ޺ iɲ[iI"}H RP*dhآəhMKc b6+dUڣbѭ:*MBdJŭƙ XPQc6*6L+hݿjy[$BeQ52_wvtU(m"jͩFmk`F{R-{JTh.\+ٮY̚j`ӗFͯEo 6TVkJwwm{k«Z,a5NRdsnnԖs8Yge!1I1!AM&KE۶5Ekg^wEmksUy$Vhb֒fɶSXL*4m[nXr6kت尕ͣEʫQv-m޶S0(!$ r[_(ڙ&jRV(aZ3cM]4S:nwksj5\+\ܵ˚:+]nujj65F]5D.)En]!/g򘼹x|}];L܀H)Z͢(|tj6$0D@5|(!,V-0f ²AMyO.أ3ra,r)$^P=wASB/r/\JAEU! p%HL8 !Hp}9U6%+43fBu{4jl}7A,xK6R<_l))7_֭wƥA&T7|37@p,ݿq) y #CMu7ĺM[ҡ K[G}@ca-,+j ؒ5|QaL6 Q)cA(imt3u|.X ?nv g6gxC)j BW Sx<(?9ˀ*[`\`vYYYWj-cMU18{"3,U/6)cuq hI)m)<8h,Tf[_mɨmMȨi: "!MVcʪY=l,&p҂`r.a} ǭ0۱:C7,Qq07,t [T]kqYp=hԭӳ੄-;7 gf[1}|zR `[@b,EX#Qm=nn(y8a~6 0MSFC+tҺSv4 =a .GPMt.ʶ# mϛkh y.[ _Bh \5{3͵ Ec6u% M{zpٌ!j!LXAqecXCڰ +u -څ}Oi`-<,hD ƈ|x㍶^"B s Ɲ+W"7wgPQ7`oX꤀H:"aμGn8`.K;n1kI8<Eq0FdXF7IXC78g4CTUTȒ"Τ’>B $!|eDV)d:J){: l>:3yI|$a4Ձ$͎3~'<-#aNVy^NfL7Zq /j-rƒ.g;:* IT_[?MF-lSb- mXs~]51Emm35Xv6J\vӽ?̵k]S[ɒSq|[]9"w~=Zƫcmosm66TV+Y]nW"[%AuWk6ۻ9kwUӚʹmb*7 vmw\ܷ]w.뒔t:מE˞o"޽]y.n5ƷNM^RI5mѨ65&6((LZJZ'77uk4j6_5ʍlm,lj[=Cmul!ʐJ4殲^tqz:iqvzu{+ws26֣<2al=W1CLKcfxYrl` Sz櫜=O%Mܸ]65slgUAZք 0C71BX\vRlj=kOB3,0aO*̇i^*``ae`=<kM:Y Mt@h4|o\D Ύ(+Z!F',\(Uo{&Ul53eªGw.K9 1nHN1\V`NQrqJ %wQ oZB?#v%TAZCVyO:]l[ao Y`U"J&.H[@ҋT1,?ұz֮,YIQdRy;]3$Fz YYj- !s]lX@ދ}s{ae^ڰWJOS{9$w~D";LE2Fa]3 \4,Y2*úJƗڹeul ㆍ0 Hժ-yt拺5u\msZ-bƨhح!dѢ5&@EA( dlFjR)6EE5-$U,6c  (Ҕb3KѣRTTXɔMiF\DwuɌie$Ŋ6SLً\\nmIZM梦ڷnV+jmjYMT3Z5h"mQlMԽz[&2Imnm-W6WYַ-QTTV]9V{W7<˫˗kvQ]9GFfm{n ('-m4rܻuܮFr;Nr+X:ݢ;)];d9 Dm6ecJkWfUzy5ksﵗrIJLX,j5o*V*`k'z,}$vg5bnkǖg68gdzr@5iN>-Cj%)Wtoٔzb9oQdwO?jqCfE$!1:U+ B }=ژʈ,Ь` MI:KXbG_Mp>(pk'`FUNƉ l Q,>'IdM1n/X dbCʉ‹ڏ<wqP- Yc%! @Hݽd5c}x}<9=#d6U`)rwh; o_DUH#7 K&T兩ICwD?4C20}ʽo۶c x핢6ywQ&e ֐iQf[t P"|dh؄` vc= UkA{=CUYKBѽ!E KB9\F~R4# \xMrg%J"im@*:΁O31զ%] Y"ȕ< +yhcJ! k 2Dǥq v9,z]m苃7C-Re3 0hտUOpSµ߹s qF5bA Gm%a8zQ:\Ďv39 ?lDVa|kMG7.4,Uwj,*"ĨѻU)K? Y;#wB[+?&gZQ^bykkPH@P|s[flw$0THaT`h*Bͧ }k] mX$G-<!OhW c cCӻcq | uMpPdιmnEk:tah..lXH$ПNbj~ ӅhLljƫgY5"B,-@L[^M4֩Qzh"12yj+^\^S9өP:nmO+\0@ym&'n⏓,f|_'>gƓ&ӫ/j]wnCwV[=+؋ځ覙\ ?vwzQ = 1s`]f]{ .!GቸsM,%5mx9KePo;(SAo勮 ˍG Ngu募u {G" #k#ޫ?nNz[JrW%2G[ټBFDHte,fuqyn8t6u^&]_k_ks*pl,J/KeGEE@GU!o.Slɤ<\i9#2q x-.KO 펧<ϕHVX^s/FMinMba&ku9W!²pm#1ٛ"\4oݱզhO٥ :`Lf2Ѧ9sNo>r~I$?EF* ek?Th5&cO}0y^}WS6mɣJlhhSs_z\33ݩUͼo+RcHX RY bŊ3BK H% $`IDX6jיyޫ[J[#~b ͮj sp\ͫkf]_0 1 2GkUjTfb7::7.Mu;^~*2]~UmnNv(T͍U7-[%Mky^}mI$XLcZmnĂ;snrŭkm^ȠDTo;L( Gr5X᪣|1AY୏KU" 0O4uvmN@9P_) 0wߴj+,9 ӕkWH4vg9[ǓLpvUdF4ѢBKoFi4Z"BQy DAUrj@,ϯ?je֪fI-!vGEpeRT 5Mعev'g\Af uH8'LS Mdū"c2GmY`WwxǺ50,/,^h-`3cOQ۞GvtF=hphS f LXFKtgF^ `P-I[oRs+92XV3fu.w Z)?Hˌ 뀥Xi_ `Q]MF,0p(v4#("5aTf][r,/3 RTQsE{,ws7zဋa ;k\ 2r@6P=x6)L1|h뷽j p\XWblgR ?8a!KQf4'lG|9ޅY24 kf Grz볕$T&lT9xo˱dDŽl:0"NS=ZtQAZquh7"C ReKDŽ02>9Z$Sa, *N[i_ Q0eJX rCL?Q9H Pz9ZxaΠ(@a =TO+*%C1y,PP\К>G㥒nBA9)HGОDiKeM*;p Wo3shI~meOjV2mLFYNqiN!7 YpϦUe)03>`f8z&[tc90@ɖ. -_lqf(5N=аn\yN-{ ]V|.DE90d=4aC72WdRw+6E`Ҭv_LJi)n@ݲcl6QeG)W6H`ۛhs k'.{[kd-3v2N-^P !+1Ġꚤ2O.rcS`7/K)>q`ޗ$)鮻ҿZ &nۢ2mΏ?wf(V)W[9ӑvʆ X=;\{F(SCT&%4t.HC,!>SLzuyYՅI<(xT:nij(gaKd:!g]7(1Ra@mwu3wLE9T2-RXש95w!ˎr"h" T6*E@MQT\}FVxdiE.ɝ3zar7gТ 8[XbD$=ukToF ńJVUMh/EUleQc]8lvXzd.L5v׳%?H fZHH%}WW"_}xk묫S0G`϶T}s6 F?2A.D#}P;XEGC RtsJtJdcSg,iuÅ0<Y@_+xC< oکo;Elձ]'ٚy{$u` TWxMU(2O(KTQ\U|02!D~c3NgOǢQ*uX TUf ۔a^yݭ5Ri> n}=9Tchs؆##rp܌ ̸n3ʼ܀s0m¶<4[ "06܏0qA Hk" 1 1[Oh&fcg ^H-7㕩"͉$ɹjr$Z9/v7.V~|Dilnp4ruMF}m&L͝Z펮֘,Q A'eźY} O1mMC"}gzTo22LrnӢVsV@#oSPqʈC FX xw54ʽ8 \] iXg̬ȨӹU캸ZnՎv=ٰ|L=}jSKSmxѧ1}nθG #B:tY۫.\Sa }~|Z] Nc~8żz Ip<Ż !J-: C 49Mϼ=8zKtʭ ,< 3zOl{M:0 o٪Kގrbh8.:SiAj;no8/0&4q! BfLFٕvEx3d} `bK!nN3=&Ca)͍%b\:"Ά|7t|`"eqCuiy/P}UGTˑI4΅_ #n@@7ՐTO+=yGPە Txă%-l =C.g@A\]گ Nd & |3n {Ս?6ȉt 4ڂRY2xY$,y]޽xq KEp0V&c&[JkQ4P!ˀ0 ?aJ`p= L =_dЁ?jw@ $.)]?IaMjz\ȚT  #?ԊkU ?D:` o# P jc R{c&#L G{!<(>)Z7Lߥ=?,'vV2ʓ;ҸÕ<=E=3rȈ'a8S:$@ ۍWe4YM1+b/!їjH|՘n?V&~Z=9z/< ňRs$y&xnZR%|l|'{А؋vϙCu5@gpRB H LDGbS h<UT OD>xWgᙁoM9:zHmIMXoAdpfJ '~|_4`^aXQߋ$ASDx/Vh gC̟omvn;U|y /i'*=@ ^fͼĤ(`H^$C!a0%@ "`@1o$XX=T|Mv&B{5\\=oB:G:ˆjzEw瑟N~6QɒSQ*zl=l9-^?x|QP? $YLON&I|̆7v[[iwHs;h+4)Y'Zw:X}bC3Ͷ|9'ACt?MY *Bq $8aH P~h'!N0 5̵D1wْ{ڍNY]^:൬:ВcXh)X OB5H (h)|hs}EtSj4݅FJk 1樫6Κ{a Dk(!u&"F)_ $P_EV }A6,yb㛧#mmBJFĄ`b 07z/4W袝ɊȟF6t}:O4anZ>]?ww'iaY^䩂{;ړ76Vg͆ocPqaUDB.j%|3 dR2 c?~p}H@ItP1A4>}b\C0rCtȪP@pa$H,wdNJ,y Hz4 HvM^+a({Lv 4.9Ծ8]ͥH 9qޅRgmMsoky.6w䉪3#0_s"C DwSu c3>o7Gw:DETɨgFN}9Ft9]SblD$gH|x89dm~.dɐa"g<t1}{ ֞RA})9r2jV'ZK>Mɣ߯'nߴYJ ˜/7ay@A1F g#ɺQFl@F D fr!2rl4&]vmxhTN$ X4@lI= )CؘdNə@ত#ЗS|B#?JH d𘁶K*HѴā;G(L WA&H{01?w* / >gœ޼ ȁ7}U=.<=eHFfX=]CԒu#ڻ$̾5bڢ*u%q ri ~x~"n{D)|@a'v e 1bQkEd'4+{͈GK/6-:~&`'9wI22<}m4=RދP"aL<#2fev6tʴ =}ԡڢP^H|dҴ#$@HK۹#jl2!+D`[ބQ#. JP>>_Pt! JPOŦҨe FD'0&_gm1IE:4ڳ*< B&އmt~k0l46U= 㲒Ly=}Ge76uv"cA Uӟb\U:ؒqCI`@bsHsi)ќN)pj嶼H qpPN$ Q  e&}O.' H$ĥ+Wc?SR}۞=hׅK .xlA[GzE%btH meA(RbsHu`\*lz^^{/DV3D5ŋ 5 xb[)7[,^t*E2 0)sNzb)E i8l>eOm>J11|ęTn;ӽA^jWq В,Mc9 H*vףN?_yhl.O!bA~`zSU0i"H%iðC|9Q@x:?]{ /n}$:_oq͘>P`Sϲ5{G3~q0 W#p٥e #Uq R8-k8USAzF@ $E78 .!&a\R2eE+ $H|4ND8  Xs(J j- i08ݓ}F\f[GH@0'}џMpP\{VJذt͔*eV{~8 .B"-H )5%GRC$IEPB%{ -9)^MbD 8]WSeT N@]-߉LpACE{.z76<wiCw.g36^&⨈ ̡޳1zoǵ37c|7؃p13@}uO ~46㥍\smKg'^v[tr}?]NN5c6,wMJKTT@Ġ"q"T \!vLri z>@y?:Q / F'7ZV:2ء-7l|q4 ]VegJ&Sc'KUM% kB_n2z1?FQw>q趃Z>,7b+ajsrFLKKvJӾh)X#!$zi 8 &̩3I,,@bUhe:>\'u/ȅiQk낀$pfo7M}s.me s]O#D^&;[;-4ONvΝ JC#5*r6$ MF 8rG_ɺV _@>8R+hJe $߸31GN&v d+u䴆,?5/]e]u |oOL81K }jx?4ǭ>2x¼9'G;=n?ߛp?6_&vtYOmTC`ȿ'K:5ސCϝ&\]J@aH_#;CERfAʁ#Éx#DO-6,Ӻ\ {3 f?EHIBs*sL = LR0kP:D_m:v|"; dyE7P.h;[49jh?WW{rqR};ϼh m D>9o# * x53$ x>|JN3穯y*ȶ!p71J/O>Mpe1f!$H@w( ֽѿȐ'˙n~`.d|7{:^7O|o5$7@ ĺrўY 2$6 J % !AA0!0"M#n/Ss)(c@G'! 7 |{S G#}!eOx>E ZdP?N'G5'T=(tOX>ĴH 'p(@@-[|V5O|>^z//ـM^` ڍwAh,@#>Q7A,i U{_Л?E@: Vj)P:~|0>{vTL]_a—!C#>?r.Z?Ę}=pL>sosOKyj87{Q< C}?)L4kœpwۊj q,3@@>mӧz}`usfs{.PHK(k]\),u 0́Z{`J4㪛Job;=Oݛ@%C5RaA& CKضnɬM2SI H^YSӭ `V0dp#B@D),}k?K[ C Â46 f^4 9*^.L F=4DD/GRHvZ bwU5P2\4M;3"j?l5. qi2mǰ4_u Dz Ũtn2cAi+tPd=m%$sM3ɳȦtf?{]o۽:$k\im)׋y|fPa'nt>`]\ aԍܞJb@O\{X~^ǂn֠Y"3M/Vv1%LJO7ksъ$#$9GӍ ]g9)!foa!s ґO-=N_/ہMl:N)~|lbT5~- ŷ"+ህ]0dǏ_TLfK¦z华ymV y0!O>«wiPgFaFrEmƌMT1D @eLnL832fYj 3!#$M鱆<<( Y7[< , v)g}iuoJ?[Y)ZRf=< cRK4Az r)Fb#{mN@CnM|u;U1F_1&xĊX\:fV=jG!93]534Ei[ub[$3[8xAssC}U0#owUY,M@ʔu`=n#}ƪF^ےIn(Z;խ\/s7,j|LhvMou3|_h%v_?[?IL:I\}6:vO6_v5Wx0sz֖ &(*ŞKEkkjS8:')A۪Kաqoʶ{[/fvI)BST!ؓ$g2C X$(JLx)&pH7mW:BYi\=}㥷T,ѰJq GPq Ue6JArҳ,.#⾙ܠ0%ʆ(?NArFS$h{<;\yLv'!gr`lfCQc,řۍqL5Z5寛Z=vGܷF^qL1sFMbn?wÊP[uégtR-O&Z>˷}K!x4ڊoyHJ@* oo~wk_mȨP%L"4ɞ&/OkA4i.AY'U`OjӍ:Esּ-G:3ʕUeI6 V.ifB(.[.DO+!IU>jt`3b0փrt7ZtX8 δ\ }b1u?yTOrL !p~/;C'ɡW.&Srݜ^ػYʪ\~>>@2h=§<&v/r0҇g<ܟTgGmylC[S׿<?WߥD2cg]&;Žjtdf2#Ey}MV%@W:qb=u`S7jNjEv]S38&U2!^GR^՝ Pm~ =f(K]2-Int J/A=s^ =X¤]_-0+LelQPpS Duf'>)=ָkir{y0C~h6/}90̧q%;̍L59m}*9G3r OٓJ׋_c]vD\y )xA]˾u'%IR4Oi.T?Tn4+)xTaSa95; 9l̾VP盓]shusRFg&WaVFR$7N?k6^q1(%NMw  SfrcgUZa)F%Q{ݎtHKKG`87FXݷ#'^L ^.WđR*8 –?* 'ƽ'}' Jn-cF:}UlapcT9(b¡× Fݠ*?%Ӥ Ĭgĥ^zCQA5^ hafҐeK,P6y'GҬ5Yvu ɲ+zP\oم׶;yiAݻe̲&l>o4R>jO>ۑ2)]Fge@(B93o#.Q͜imrv!*XZ.xq ZxZ&R߭CjH _MO!m5O;yPvhTݿϰ+o=Z#v|` U|,U JPb~W5w2j6Xy&zP/XnnEBrrT6;A^/]a7'y&=z_tfvqwzw*<(X[Ⱦ+AlYvK~+N'TāK/&^`^4ψ?Z%7g\>CΩgTAmo1t;ϼYEљ.ꀘ?3䡼߇vk8gH@Ǎ2ij1|3)U$M>p%*cqFشN)nN%Gi4K@+SڬC)6$饉}R ۫2(Ҫ7 oV@VPrMұ&l 0ART؉L z޶{v?Ki{[akT*ƂAB& ݎKco%>y {q%͠1m6!W0)&RyCzlii= ԊB6H@2sw]Dq1@ [9_%_rԷ҉BO}Ev_܂bH}|q@}D~gA<ޕ\$>nJfS$_7x!ÑG[\!NԸIkN΃XTE*T3n1( CLMM;w~7u h̳apBJCJdlyEP?љ[Cb%@"B?둞)}xR C1E;TLt5g,T`m?+4MEa_ 8XCN*>ce @d m"XaF'QԄ7wCب"?P@w: y_9 xbmO AJƒ'{ ~X)P{ңzzYfڲn?lN|ɟZ}-qWyJ8VnRDd:6ź jgn|]iv.^ћ/9/'qJO}t!"m8◮ j!dVrK(4TiZ'p nKiٓ.KX|g4JzǺj*gZcY+2RD;|g= hFZʽZOLH"A  D ~r(*`RDZ]M}wf+ 8·bGW_M N`@ P wtw6 W=zZܱcAF*2h#GU\%v42EH܆SFye);_2]d$Sc 2@)~OGwp0K8zYr@R+b4*}}`6P ֲ- LC,0ih {+IÛPތ`)a4gmlu;⨶O0d25g8<2Vn;r={&Y񺻓L0N@݃wSö]1=Ɇ\, Q^^:P`ԑ^B {>J ^F N_tOl))Esf@G8앬5b_m+f%@Aܚ +%k?gq[3 !s\*'[ rGpDaPʼ•!&WɹH([Dj@'q5@ ,WD$DpT>>Rðgj.5'k"` PSw/iݭH0DzTK]:au`;_ RWZ]jkkSxg2(Mr^!?3-sm[EаЕ2]a&w)1>TH" R7T' ~7zqSׯO ݟ?퇨ps:>‡S aP{ourq :B@7 'ѥ}9ջkH H+OyLŞokQP\ ۯG^Ýʐ ekޮpr ک>L޳v gBАtDL+1RZ-HG3Bbql^\C_Sblppq*΍_5{C SF?{TEfS..XX+>6;=:bwk5^wmwrnvMt8͘aw,?R qL-)r!d7!\0)L4*z?iΝo_<+wJAMڳr]}X#_ȡ5:fp\Wmaq3$xϷO? =$pI"MIK b!cqPN!>4qzΝFUNP40=0yT8zG@~jy(ǡ4ZDELԕS>ra4FpB: <9 t A.1c]3LGj~1/kypo}rm @q,3O1ynL4e lq[̣}疕غWA;H|snG'1:hs$i`2+/`_yocL͐0Gz~V&+!0%@LvLYY?7˻S!R*^⬤zђ6EpCK  :gd&Cng 7/߮A^E-=N:#Xxu[e uP2<6W$O^דOBuV2bb@|`P0ysQTtsϸ[Z TC}?0F%FOix^\7 j{>uO۪G^leUS,"`\p9Qkb9VwPn`WzLI1d!(莝{yRd7-WG{zExU~r d `3p>+տ8gtfy{RJeh~Z=5()1LRLU ױHu#TN!׮#T8V_9wЌR9| xQP~u0{8G+`? Qz&7=|~4S^Wzp9'|M5]}7>_H.G m V2oL<;ޑǏW<Ǵ/M`F6&!DDDx[|֍eKbI#QB3ԙcAL79@kKg3\($|@'?CLh|CAb}{ ϴp`A@}lAaβ~H!cr^ e-{~~g~(b a# DcoJ0sE{"o̿B MR8۞ i‚ZƴڠᇿS׬=maɇ>f ySp{X 6;t D>s''C %`ng_zHo$zk/(D&@mxڳ ПXM;Ƿ_.׽E(c5 RL'ѣL)z8LX!t̢8W2a{$Ǥ''`t{3&yO@\|( :P#z@xG6Bw) FId^IP u b s+)WDO"I$Ғyg\oSW}Bȅr*R)Jc$]I`rw%b쁏+3uj~rq1M|㥇{P۝~qW`r6cTM|IW(rYKhreuBmkuѿ~>y|`8~ϯQߪkU5,dCѻfO7& ]/Utn |8&۞؛F>ETĵP~T>`$?4;%ns V?0Er1tHKeaR${}4|m[kYu%>ފ}A?rv^~_|'oag_XUpUSD%ܛ"kya]`y sVq够 *zӱ,D:~ٚx77<2h7+cFzxunx&Nql5EH6WJY ᆚQhB{hzM٢M8ȬEh Gox9ưjM |aSdS m/_8Ģy @P]dINc9<.E{1*5w ҒKK]5$^ی{a](lXCW  CkJ&"{x# I澍Ɠ>e}{>JiBUYaˆXb"h0Ч*хQ3Do4 f]f>kxE O=re ~j5ļa|Y}C7 Ar:C߇)2|PW_腕,h}9]s 1KܨųJ$\ƲVpkLE ꃺƗ,Yr!pU!Gjɠ)>ꤩHuS22bMfB/o/NMqw6 p~Zza?_:TDcNY_ھ8_@io~V>j͹B?ԽL=8Їw.|>(C<<z?Wڵ8-U O"j}qwlL''M=۠JC`3f?@QRm0oBB7ωDMxYAq!=h¤p[H ^#ܒ MBx@(/juq'ѠCg}D" ]6a B @@T9'ɺ@9Gn8ˆo}A^k@o xC;N;f&'1$ln.葥B |Lå'=Xv /t{HvoBg[T0jkj6}Cpߋ@˧Ŧߪa誧:I;5x8WU{|_2>?D1(JUh)^弼=syN?x.Cy &!>.8,=Gvj|Hvg~쐜!Gvc!0dp߷E7Us{Ѿf1z*v@}!ΐ<ɖ>I3w/yOH`j>ho?LӓP_Z! (/MRsND3kBV?շ$3]Y% PCr!'dٶ\|-A$]?_[kvpOԙ:;5n"Y"V@sap+s`t ?7A)SMV.i, <)|H LR.tuhΰv5!Л(&; Zh3Ud D=CQTDDl8s0~ʏ\{n q j0m2h'})ZA/o(Az~uo8/&_a<43D`^4ps",Š[ffڬV %3cn%$ yhQDP5/\ќOQJ(K"7;, 6`Q#G j} Mms;Sb`S~_wwLi){I2RxN(xنI:|ߗ헛u|F?]h0HDt"2YE [Z3f_T`3j>S7N4Q$Jcm>wQB$LczAFOM& D!7 e27nˠnpzZy !h2ޣ6~ii@%[֭B M@[nAD+ &X|ڣ_iYU4w84wri^H a16=m p_y3/o‚}ego}!HfV2 Jߕ6)Wb}~=uqLOcw?$@sAX+ 28RdY?5e_ߏI$X[enQ>U'n9nزİ'˪z~)"УS\ ߳_Ѭz=vɣI>ABBLP1KZf(`Ԋtwh՗uk,n_g,ť͇X*lsLs79QGY<{QQ$]"CǁMe*,>61=`S :Co^7dO٘}:wETyGݨ.|Aݘrf)n Hŷ3E"F*l]~SS~q梙B֞{ir3IMf`FkB5\gtmg48cU0QτJ)Rw⢚$Ys:ٗ_f  Xdi;)@UIKOTZ4~ [#L:W/_PH$L*b? :v)V5~- "Sq˔y;X < >݂UBpoVj^-k(pI͋+ ,v_ɱtsN(hH)g`kS&E>;$ΰR&"@/vN-_'{̑A0o9^z,~hK}w{krHH u=/HX;eS.j[iF~M )uō`mOqz } D#iw4  8">в}ެp3׳`L-ʥN#[pF~+~FWUf-WӇˀEo BJą2|qsӒ_9y_u:&:WH{͡7E?.|><3Hq*NGԉN`R5  <ˬow9Fǝ$,:R@νRrԊ|ވL~y4oo t4Ÿ=ǵ j1]FeكN9)"ÂU2s@LA~9mꐶ^n,,"")Z$ₐIlϕI` C F (ѾD؄Nks 6X7 *~`F% 잒D1@i.PAOg.0(ҬApPƝM9uHuw讞Ig4E7FD@GU9b+NhX}aʡC^7{]JC; 8.nlO1lB~}/C@xa3&4}f+|7A @}rxz?`"i6rҙ54}Cn_z^Ԣлnj@q HTJ@p-WYVϧʴI%-&M[s1:; ( UNOm&QgMyl;ڟ٣yV(f_ތkUy;]EH@x͙0tKPYZ` c/ V\wN'rlFas`4CBD,bmË IfMjІ,jXCE Mȝͼb]iPݬpa:讈|D!&tnP3w.aȨᢝAoۖO\3xmwց;˼4< Ytdw!}w6.mnyPd'ó@^cRAV' h#67Aڔ|?U48 ֻ /;&t$(@B.w'bxW:`w@._wt{ wI~58^jWQn SOk"\fcGtzz{=wRāz0G.Y ?֞wIϻem.̳ޘi$OxA{;6uP{&mQK~ CyA`+t4 - (͕/] ߯g;" |w>:^WCw}1_maS_ !K ١{Iwna" @m[5iE|4"O0lRẕH0pUSW#%),i-@8{;ruأd5eO,z$KPp$$1vV B\q$O9N#Y:mkaڥ[gT&E_ꁿAo{& \5과ZwjB~-6"N>^t,hv30-7 P D^nr]N[[Tl) /3wE'yMިbRux'͵X_TV}멍%R/aޒu͹'_g(ziL彻 {|+ s.n]f "̤mQmՊ@vA=h<223UG+!eVyǢP3dE3#{pcmW%&Mn+ XEsnu:4Z#>C*i$'}k$(uY\u[2r4~0:D@|OO(V?`}Be]7 2Űp=4ZX# {Nj{լ/w4n_ 7=v6 O@4M*?ć_20XUi'mwFSW|<_;:q2= c))z @Fpi$wR.$z>PەJQ(}{ugGpmk~Bw̟%)t,Bmp4h</p {Q-:;~eT;K("Qi~C*2:N‚"!S+ ׹N`(y5d h;f z]7]&s`aPsR'z=h=zB>vhx[Cl ~O\P4hn~;Lx༪Ȣ.ǸgT>=tbDL^0s?DAzI_Ke,6@ 'PD_DՍuVg/GFCI0ۖ %ӝ LT/M~g?SR: *d|~L%"Jq0ڀ*j4\*NI=0xfҭ|3W CA)Bm$9N DF/tSAY0B+ٸtoFs9Dy:) d4ǫlQͪG`֭-SDP q(T꿥>=I*vZaLL?6 Z35o .r~*xo5 ՄœoAAVYkж6=*++&=?I7ٳu} ]EU=)К&ױS'ZuYӓ,WU:kL-*;`UGsvLf6пm{dz{_xODjyƱ qͩ/#\}1*k7i%/4E١ K4 yCf8] ڶeAmk` n>C;5`1%`6Lf!rܺC {*(G P ;'LB _˃?\7?|D~_.>SJtg}چ !T_.75"͊7т@^0H ZA/8L|jS+J+Tʘ*){+:=g$s_kV0CQSc |P)Sm6q +IHYCT \~HDku|X?Y>Zzsǽsc.8+t^ 4t kRdQ.-1?9@eO9К?2i ]nr)]5opǻ'|n17^娍nb g8"3VdWZȎS@jSڻPBܪ m03!}w!4ҿW-yNdb QHwi4- }fGҼ@=0I|ǘBy b5E(@ ؀utVAĺ6;"rV&Bj8{Kog(Ԟߺ좗m9ݗQ7燵%23! &ک迏sYU'8zVGWj0^%q.9@FGсRW+dAJ( 9X+ #!9K!a~l͕;5& Jb]ֳ -'_iH3=FcyG-8xFX1alɋLP u5s`aMj6GBC:Q[ݔjVxG.0`!= ڪ3]޹'`/1(a!GF љti v0aD {3M?x!3rLUDfz+څ읦".06 |}M~t<<yR Fs,>0.Fe}) TJt)oC W,h }Ȣ꽆,o2ua󆄖I bI

PfSւ.dX.E.i@,[u( ;=K,wˬ49Ɔ@12-LuYr)O5\0?:w盀OE4}qp뜵d!;zDZ9h^dwe&7 g"?ڠ$kaEHdYj#F=j}dE1͑1c|#Sg뜱\s¯[L&V e_Z-9w<!$}ՈuÜ"PU\ZJz%JT'"?P( ȧ/1nvfX,$&!KjJQQNSa?Hq֜hCwD(Į{X"{SkӓDCX1@;ڮe.ĚJԃrY@|hD f]TvVl9]/ɩ H G0U/hڥ_2kN.oL~Ǝ-?95fτt8RpW9 D;7hd$ 1_ bZ9 !}7 M҄pyo' o/<0tk0 :k)7ZinWQ}*EBd((,.>Ba肏ܖGASLP!|@Ig _oƜ>s9!fwl.z(9NqxaM&qj1r~ۦ7~] l>NAfVZ -h^źs^m4}8LSьYCX wZؤ1:~]D#lqKg[qc'ig-xP%8[3 fҞ> ´,>:CJ9V3Y]Y;h+rP19ZXu\&l侱lJl2Y^fV':vcHCw&45<(WlO<VXv]rC6.PwP܃ԇ0LWd`[jRGJA :(#0h~9;/kRHN?1o1qIdw)'Q 8_qyzz‰KX7oCmz>;ئ4XV]@q!0G&lKٗ{ݰ[^T +l|C6+)/Cߓ1_ΏֽGPm|6Kr_?K&#bRa0KLcϲ, J@mY :z >=G."X kOo:ϝknzm!{5NJ n#h.F N*2! q[-[YCfM^7jQk5ݽ?2w7BϽ{\~&Q' `vEq?Mdbqc޽ߜQnuKؘ  k؟Rt!d|(z:?چCx!!d5MWD+;G;_)O{hኄU  ֈ?•! 8M z9}_9yp0$ O "Ku'~"$ 0F']hO*X*()*R#b3F|ׯȅ˧ϛ b=0yz'RDivxqTbp2c7 {kPbҀtW_HпMG?ASW>,N_ NH/iׇ%L~VV}WaKPNb3'ihݙ,JN"}6MzD,yTnJj&J%l`.0 4e GPtEکR h2 7q#I^ [o}^\G n;mq..z-+TiwlIɗ9#9x6d ZةO@8SsfE4ުdTnn_DpbRt8i@!wɋMuVR)Up mB&kAC܎ĪL !nGkfYŠWQ9,"@U,ߺJ~?.e{ _./bQxFsX(bzCُikg/$qlDwt/G# jׯz]^zݵPBauR&=MJIa MbVw]zfs+䦖4 YrRj(,}X&-f[(Ԓ{Xu/'W+LHPܮ6$4 mћTgwE{M ߽u66n컲]*ׁĄMq8ڝRi5k*K%bIޙroz˔[wv`75L-6r:VwĎWbT;x2]xM5Ս McV#i䯯?Udu jYagCx8u.w&kBnY$Znwkt&w𫏨ԋ]%'q9kkMyLSU 4>G7J %tB.moq-XSS5ٯp %S2VOmnRz }gV:]lV m .R]x06J[rV&VpXy-f?twmO4>gLtr+*Ϲ0*rD+/tD&Dݍ]طʄ/d}{5*s$4G\6q%?U:R g(^\̹Oۭ>[L7u/Esoj734MJE-=ӝ +PEvN1M5 W3( ba=M?_G/?r|MzÝڬY\+oA #>/{+b -86 ?ΨԬxeʝ̭Dڔ#BII޲ ݯק;AVz{7vk'f2t>>Hȿ0v}~vhM9h?KM>^6'HdT.MBQ*wJ #bI KaI[e'@PGB֊ځϛ fro-Jz~{[:8?{O/cZR8@ȥFJ_mת|֊ ɭU|P_]~w=T}0(>W9ڊU:¿"cy8j'4*'EkTsCUWM0C=wmdKW~<>~HЧ#֝6yh2y_vnvՇځ_wّ_ tZ/ՙ.p[;^Lq{R.8y9d$|<8vN.`g)LoBx5ǗAeպSA3J>/Tuނ$˼yvQ9I3JVo /hg 8 1,ݦH 6j;ѵ`D f^_(^12L g*JZS5U=Sć5PatwY*FKabu@ۍ,ڳ*-JXڲd[〬#AiGۅ $NRLA${Sŋ08 ZbIѺmv|ܟZ!MoE\& ցYf{Al~XYz3ԃ#!{KT<0;ˆBK oԲh)[K| 9Y|LKTjYE5>Ҕ>QAģB @ $4H&Z~.x{zSŨTV**?N/\QRbLieZ*Y5^o%Ϧ3egC;JpރewW(YGHT}Xs/ݭd(zg'6 ENjK6R\l~}U5%'uR $^3A $6i]*g~jsosb(()ܘI8;zm.0$ ĉ-aQ_f1@.9'ídg 7MuHS#T4S1 E)h|l=!O!D,P' F뤪[i9 ܧ+.UﭟchTZز$ I6Cim^2VIya99r^ҋ֊^~ Od{o.8RQ'Ku(ے`goMkOc.,`<8 ǒ:_#-կã!;~=1dYw0^}O/1,~7N 9# ggT18&bx&zLx5 TTD-hs NPZ$GK1~ `:ިez(/߭܍S@XszO[2^Bq8`bF={ܠ`sjZwj-H%{}i _P}{i~BW0nXN3wFGyUKzMP$E`[-$2NPo3h~$Iյ Sy ;Tq"fr&SIviAd3nǂɂr@XOTs?X4q)1SϠgQ732yqMB2j]萩&(p' 0'o{*<8#=PPxFu_,;7tP^N^^*oՔ/Tq5Y ^V} χ^8;ZvytE fo^Wb2!rFcTaeA!\Z]4f/C•c{i]8H.} r g>F_秝 @<{iaqPshM I`F⃈(,@)1oqmCj .HjְS9I ~pYV&2J'OI0h]+4ӝ٢,(<I/.~9$`$=Y|aQsa |9+*ҩq}scKyf8*>1vW|+oXuz(7]ވ }<{`{_}V].T<[|,AK=pi] Hӭ!I{rta%sQ ]:T@Xwqۭ=JZVlHĚiH_vS>J |S ~dhKt3ڹ rduPefGN3:{Ei2T NQ"oOwՍDV=oPk1Q>&5@?jsQ ;z F؄wŝr$A@%`_" =ygp\k9(|LTA[p(n:\5/H*n>HťX/%8d>C<~!n:.!PruovC/&}^jWlFU/PҀtm>;*br@:Ni24 !2kz/th!J.`U4pZ: (pW R#2>{g{pN  md4sm(ŁDѴ*Htup6SJ.LJn[] ƺQqV  bucDt\oG͟˧ldAE&T**1|*.t{jpӇP4 <0>B[a@vj $PrHE1@mqЗLj lzЃ'%jDIIJ2d)OAZgH 9\b gs(j-W=;cxa(B-P_:ʷ uxZL3έGsp;4‘fa6z˜Mt䰂~8_dɟ.g1M5X+&SU9*w{렆"Dd/ܭDv t Eu Rl7 g]bgM8) 2"YhR ҒE8@T gҦOI%"MxۺAZ ~Hd-~8cbb|z?&7r*W9=V̌ßڡ\?fF* W5:^2W:ʯPG(-FVCy,[1OG]i+n ']oYo:Ock[C,O5FT[<UpO\ea4VV)ڐ㦹"S}˩ѕj>$X5ϭ8GRi mF@|>M=QI|5J]qYWpWɸ-qY0-n߈BwIBAH҉'w $-].n5*go5-O1F*r>!|(aé>8Jw4|S0_?hdPz_?vDtlv{6Ibn܎n(tl@Z\:Z|6գ y(py)*X[ݹ. [aTYPkzCDP|庿_ul>9˧ZDx˫mId *#^9ff`jHu5Mm+WpXh Gw$+EA|vH7?1Iz-V޹Rwa Qr[n](ٵ٭/Uqg˖ziyZ{:Sh)]GK$PiQ^.88+g,.x.Ga?ݘ̋r23\&K\^gr8K*FBI Ib=)_uƈ(*U?{Чq}>ge< .Y/x~}o?SoƪuSv>=Ww A6g,zw@Ko-Iv,/upDAݦoد!hJ%^ΦӺpYb!++H~Y{> O?ڮ͛ C̼l=U:XYm-g6=תa;֨5DoVK-b YZ:?Nr^9-C3ǵ-}靿P@$oKR +'֣&g3] 24ZK_Dw8<\2bIM] ď(;ς8 o@wHv9h 5ݏ L`MD.{1z(Hwi*{;S>:vT$URpW9v"l)K1z#6@HbF*VT-!?;6)(.J]sq'Jg]㿢ځf]Rc>RKNd_g0ըDςc> }>y+hE|\:yoJ)B`7@fq@ϟX0dNt/|KCbKQy-?#ѯ4z>b0_b v+nՓ9$@0ǾNN8pVrd^$- !!L÷Tq 6,~i|7}Z9_7Ϝ@;M$NqI DK ljU^<85An-hLp^UfZYw32%NFrdfk L26-|W)KLZe4/dC)aÏ*{Ŝ7"g lOgRyj}3`7Yl~Zd.RK9HM _Qﺔo11^fHMpEKX,%~*|4'N/]-kh2o~S8O7G}26=(h5n}RDI/WN$J |)%~;0{Lhpy6KiO$%O^/𔟫) ή C|> gǜnPi{y kk+z 9R5G_1W]s(<pBJm""*:a : z^8q5!.,ā&d>vk~E)Η NB/6m` Go!]ז{p;uш@9IWfy:ty7<_ve^sgu}%ˤv$ `?}=0IK'R;?z0P=3d\Y FĪ54 AֻYE2£!2ޣ6?ҸF^2 q8}P-Ob1W\@3j,ԢZ6m`TKٷ}2@L0socFP:\ 4_q˙-'P* &贩p,n:fnhpQ )2%(e_o$_*ydќ1*f1|[v.=ߗ#hǻ b~)U ]Tz9T"vϣԚEd~E]-~/ fdsxKOz/f`g @dZ@AQӛ94t ?Ǐi Zg5,>$A 428wl(b$,EXHGtB6nd@6öѓ 7Y@}5~K͝UC~) %y6w5 7 I@?d[Lq[sbBt9@#^ރ҄FҬsS.b'A7);iu9ECR1#Hs.ÿ\S謺OU}8"bna7Hs}X0@ B"L{(T%6 *8=Sg^B]zܨ7kIۅ?]X;P͇yl(t3rt50*>O@Q6Ґ im#~ё|@s 49=:,?]'fſnKC!s?d{.Guv$L[Su UTJl[B}'WMp<0{LND1IٱЀ 3.`N$?9y@05LhBɹM2d) H:wu҂??꩷{=ziupv9?D6^>_8J\Ryl8e=* ) urD"ęT_@W@qfkBA6cn\!ڵbLC50IoW^ b' kqgc нSC:uD|sU?'L;wJ~6#@Iy@PB /\p"SDk9k_'R͹>oP 54 pl{P.␉(LW.7hn~yti>J]SI#|Wy*m=/[TQgm\Yawyre|hte9.U,"~WZ'A|CwI*|og8nԠBR:sr0n} d _|DLP9$c$׭cen:TB]ZY).sFm 1$HZ֜y{1d% #T}3( (Baö2'I+!{˩VoWjv(p*1Zn;gF+4۲8P-(!' .%+t9DP|q310a)E#E cZ,RN:z 'x9XlMۼQZVHlrh]X ,A}}]rH2Yv?zq7E NKkEF$%a3 xFp$`>Ih{|zMfzWA4}ևy٫m>MTJȤploj ;]~.;'*d bJ }1^_gh, @C^>҈Iڤz .h~?-*t @;VLu՚ߢnC.{\_OA:/J`Î  VZ`"(m؞krצ[ڴpnM,Wk:;CW6-p]^|*4-%gĴyvI#.M̪C|d.H4m5[rF{z4f-9_aN8gUQ&K7WΌMz$ȵ8<5_-Vܽ?|I IZ5|++v]zgTm) .` z??qc-_^DN؅VRIޒI+y JE>2T+ \ݤsd(!?zjz ڣLfR{v@$0V,lIC49Ec mkUA&x!JITmTPI5[PHJNϽSjMr_>(*nY]if%Ga:Qb:7jv$8E@ߒ&r6$xIo_OuPc=g"'F~6.c~'vDz0`SعN UրǑw| @\A Ҷ쟡mXYSl:ʼC6'b 5us0(g bI0rS-SYduGU9nѣY+MiD\﨨0PKޕ,Kǫ:]3O5!HzA[~'QbCȑ @A$0I-{+>B޲؅A!Ac+oY)m0xOYKhcoQ2 0?٤7!fKCR]~kpڸ`plă2x@0Yr dƐ :T(1~jS1[ѾAD< 7z@O>{҉TH0U \90SI~8i}_MdE'LjA6Rf:Zg3LXҳ~lly2=}iE"ےfzi<7YqսZU ͽBSP>E 4bh9">? /߄fֻŰݛO~~B5{;ؠ Lךj/"E ]o9:]<` J#M-f_'a&˚nMm|kBjjVШ@]viT7S}=|lt,8%';G0$\]Fim)@KAv D'ӉN.ֳ@\5(Dý>/@sL\+wS0~A BWqp?;)r(wXj1lN$8nPc.brP7OխytsHN$aSW*~yJ%B_y7jg36$ }U84 jP)c]8ż@>'ݼD_)[Χ6F+-Â*p0  F@͝J59rzb#*딆Ś0^!wH= G`^E`g<1W3@}{ibV""WdTNf\(Yb4 E 's<b@jT㔪WZǗ:~p!mdn-9c퓿QFBmI9 u5Nh6nסK:SWb`ئFtY|T H; t%qZvg4\As_ߌ9pWdULb^ֶ݉jQZCyRƦ?',3홴\ zU}6C#6iL/ŗ}9E"#>d6,M̲e-kǾogÚЊڝQn}C*}y~.p9yچOApOКe,vgW8#LŸ ǕZSҴhf&Faҩ.CSlC036ʲ>䏧}?:[SضKo{rjMmzMV "*(xE¡"UsաR-֢ zm+Iy8JFwZ=gᤳ(W4l}p ?Po:ػ[TMMl:u͂5ӿ}00Bv0@B5 B+3\VPNz^%HBo_}@oߕry[qZO҄*BtT(G,^\ji8`vg=]{VFJ&^3۟s''gy[Rl=b=HOr}Sޠ.aJvR,1v&PðI'}= STp{`GJԍd&Fyo=MŎ-])Qd8wm={m1)O\6<*"op855[lNjeFR!tE֭zQyI+~R*>JN)n3#P{?.|F(/2CD$UySM2jG繍__7K&Cb;6gғ3Cs=xCXj_mcj+Dk\83GS"y&RB 0W}E׹wWhy $CJ/۫N/7 = sB&bƱll"R:iy`ZYU]=ߞcS4 !"f`#bR0b'Y\[Bj}>$ sU㝲ur|]6?X~_[':W~^=DOaJ !6| r~V>颉t_ۦ@+gANP"j0]6"]A6Y(v5)9\h0$Zy?ue a)9}Krΰ\"qNOb^EV;n 뷱'q/^\YOksA)H,`|@`jn]6xsCD*]{aTz%BEP$u"H Ia5_WזtZq` Sm)hnjhctmQ] 2>L wf:hr??-ѩjut!;sxzS(`|s qQhDsݹlzǙGըie ʃ6$8XXd|`|>zBAV%vGڞN m0;VPYU-AX&=*>o 3q(m[Ju!].VơK;"^E"H('^2/LӱB @;(R<1TplW F\ 8K\8Q\MU~aɌ(Oy,j?rzV3.v?3ӟۖ !i~x~2 C%]5ad}vQʡMK],(@YIL߬[㯳{[bxLQY T_($^Md.]s5F"I&2jevYsrQLL̚61VfJAk! a8܋"Qj˽_b09Jl&Ok~Q,7Zk\+؈7(%x gt%'e UZTcllmkh{U:p:P_wymA6 rOK F\琥2& D4'bǯ߻=^` l,eq7om3=ol]|8E߯yZWO!VϨ4Vb9Mt_joqjd˰iYVNj4aq ӥa4өUāx!(:n=,rLvσ AowCģ7@U'F[+ն{Req[0 Tz諅rX|J-]5[ ۜ#_\Q͗ PtRN8Ne>!1K<+ =1muu~?r,mN115A!>h}zu*f;seN $L7z7l)IHW+M*:0ju?F2gOs CgT"^1h3i;xU:8gS o'0Sl }/Xq~=dm\ku=_6|n\; P4RXSQ$(-6Ngh*ݺ x.q Շm;|PA:Ձ^Ί%AO?:906F '¹ĩYZ̝:)eGQ*jBO mTW-r7r,>|#XC䊺=88ӗ?n[M*(VcÛIjI'1_"f9:q7P gs4 {A Zb6@wpbisFHf*do<2Dl|H)hw*06q&WU  %rTǬɑ Jed*9P`'@KR1AP0w(Cȓi$C yDt⎤/bIﯿݷ+gsv(XD6fߤ@ i)#m0ɉAAH9(hlWi5GRRvMa<<0bMJe|hU[ߤ H  w|RpAL sNq{`_uV00+ZV5M]M+r2ck({z2]#էcQ^/D=; AQ`ȫ.XA]gfxlAbl~ _bC\?2S mOdP#^ueDm0 nf\$~F]]C/6*22~ܼ?.=44P6hQ36(.>LSSYFN(pBF&0bmt6lbZ n( )F\{K'v%#?@Ȕ)d8BJ!?g5<>6\O|.4p06y"}N.|nCjaZ^tMe3/utݍN{eK@b|OTmrl\M)t9*C?bb8oxuq ʿË6K0Ra5-xXA2 *}8 ʨ&9 sAu`2tEW:<+H3F*ƽ/P %z@4ҦBz3#9ʨ D޶vP( !&@R2B(c^XV-0ӭ7>QhDڒDN"$TCؐǫdi\*G*2qðI}o`iQNh7a@@@0#G0`wz;5ݷ67/"N_Qc7ґ'BO]O HD-r vM!"b@ lY!ˇRt@8&^H!)y`  [:R(*F=vЃZޛd*@sg~ WDp*}AM|Cuj*ڒt h|s4*3 ?Ω_onLirJf5p8!2G))_(V| SA**w_IPA}aw{c䫠 *¼&sfv n3we)a*کdlaQ2e*&ZrLEK K衕ds0Inޠ 6,]8wj*sAjsNz"շe[hV&n)չK8mYC*Ƙe+ʖZ@l7AR,w [,YFE'Mj ߷& "j@+K. `%~5ːp9J]m`NQBKde:6֐*+v(4?)$\5Jg-Iv7 *澐IP0xWR&Vr>~24|({pJp>P DXRDxrH:6eA)OY!*FPB%}$ gcm-7@(V.hL-qwR8K ? zPJ&i1S:!*uSDa>kSyX$Z1d53,c[ I4A%%;S2c'B(Pty+hMsOm Pt 6s)Xcs*5*FrzGzϹ] M-cD4⋛*y۝ad1֓{C,`!4TR A83@t$f*;+Zf 4kkoC˖iƸRbzxhm8U#.\;`L+_m-0i@G֒L&Rܕ HJWc2f7yM.!Rc&[=s1nyQJRK՚%TUzɃ^nHi>-fdk=Y16|s?OjG|m%26@$EI!1)M3T=-5l`SF|I[ډ+ '2U+\/Ia 2ϑ23N@OwU{&O%'*!F`td{BRZ@UYזns@dR¡E-m7|~3=pzh8GbL2/EA[0l9mƏS "u `=!xB7pJ6?х<>aM( SА>`ZҴѣI" $H?)ǔ@Mjk7h:-7V-0RFi׾M9T9戴")mKPQ%lŻA {N=P R eEM uXQT47!H~ZF9 Y@w ήh=PpWg[]ڧ1RRVlZ?5/Rs-ðy뛚Ȑk8dӫ 7 CCB] 0ΗuaTe_?Ϸsz*zsAZA7 kiO#Νn7{s::|.=m!\pnG+Wr(=:vs'9T* MLpA6ԙnm.l=ϲeL_I'bE9 ]'8$>U[N1LcF!׷e{چ/S[x2LSKK =pRvպ|_bܶ IǢIǸL h'zsliվ?u=z\2ٯ3ќ/y.l5yct>y7*=O5E9鏦utnЃ R/]j(6k._0ڬL2/'`N} C< le8nխfe[B]j)`M$o@yfCGUi&,5* (`NrZVۓ~:bBT$!EYϲ?/ͥ]5\F nc-\yOfՆ;yIYڭkoEQ|q¼Hl ԟ8ۺeWS Pw}F)mgX!wY§Q@2N%7}-~BML 'k2z. 5PQ96y!)n:^oZWQﮅW6zZ:ˑ֫gI4vFIh>.W. /s.}ۖ?*1?-UB]j:InB= sgAPF 2^x J4bͪS'Ϗ_@<(ٰO0SiY9k *7Ѯ4U^\ CH%np z t1*aCAY3>E<1to)2R/I^q_@@sPr E"Կƶ?3_ޟ-~BS& vs%`e- P-XÝ0uz&-QsA!ͬºq V̧V8$DT m2bZMoe 7fxuu_.漜3+ h4 A*hP ӣm`2B'$G@,%maѲk݊%ϴ^ ߾&8%# d*D U P>,AO(Dy[DβD@ L *GferkUգVw)߿Za4ls uߖ}r{]}^3tWعca2L4R@@hLD S_V Pe|2?۶jjA8j_ Ry c,gb9pvZsmlahNjۿ(뽒}PQ,p&1B(0!=}ʍ`s[fJPPkU+]zZ6>`0*9iU?upS$wrcX dO[6?# PR1u@J*e` oM:q}m};1 (gJEB`Dͅ("AOG~(hOT\+“G~N(Q _I.7aE$..G($S%C'0c_4J#p \’a% CÊ+E>R=3w{*N6C<ݴf Ag |u2Qp= ٳW W?gpR@7mbQr'4 ':jua5P5k|t}p o%ZBfC׹H!:(^[aO8C[V:71*٪IbߕoF{,Ev!;D~(@ӸP@|4sDDC{V,QL}ilrH[|L?YV ̞OBQ~X gWqVMksZ`| '`V7)mTi"4ja$M5b F&Ja(ib4&ۡDmJit@:P\OFTUY/) G1P?\XƟNcLǽEF9ٯ$h_3Or8) 1ϲ&zLG_˯t?7D^Hx'# WA'iU7f`sd9CE&%0]Z6gXy^&`Gd 3]I$($iĻB+ -Հ1TJ2B)E,95bvFg|qq;a-ޗi'2nC$evyܭWmb6mvۋXš^ ;dنT, )GbNOM#*Ր{Ⱦ>:5^z>6rxΕ'rS ރB^riO+;rᓩ8긘ܗ2Ɵ}ou_/ZR0P^ kJPЂj~RJ\1;d0Ω|>d.9K>]D,Vp/CM-tuS^o/# ˿R@&1t})c9E~ŚrV*u^~  2`V,p.zo̩ Uy.S?;E8%4}VT,Q2tRVSUBo(ٗ&&xP c UEH)'~%]tMI*]^۵FlYFoP$ubqCP}/y-%ux~tl'50!@HɓC9PN1ߢ{K(`KDyZbj E]AͩڊeStyHS JBawJ(aKat ~4?L32;[f)MEhu!$bG_ o˃_S2.YO1~az P@p̱N>')R/)'n#J]Bl&tTIA~H%~;Z\\6Ľ|aKxo 4;<Nnp ꏦ>Œ@)dI kw%N Z<O ”AN|\?@i+0q߀3*P*u&Go$$ މ NcJ-ޮ|rXڙW DPcHS l2C]F~V/c*-OxLB380 @/BmeIg3qM>|"!,''oP\)IeU?ހ$I-?פF'6t?K!pH h$;ڄ'ɒf_e{딊C?iɽ9z:۫uy{]״ݙ]%{ y{ky!oA)]bԤz/&@J; P# 3BJ<~4F)c388=kioSs.a"-bD:?M4LWӐg4pOT܈aba @F-Q \\~N c%`Gп¸!ԍ-:&@v#J)'†1!GBir n. )M2a/v&[:ȳP)K@@, } _K@CSyt\W*g f"wnƈ'XvCu,O0:tyO؆Cjgd bLA_1i[?noD<~~*s㠈oі~aCgiœvufcJl֣”U !xE·_A5;ˢ4T;܈hW_6ZW)M*Ȓڷ&W{㦃FK)qCJH!hwtٲlXK['0*V[2V/~1;Lgֽ=20/2f"rls8TZ?=}V"a7@{wWE&]i?(DDr jq*`U1'T ?iUI6tƞ[ ƌ=TU|جv. DXGa>\(-f0n1Z!{zX8r0b$&chM5yGw%9HzZ?-I;ciJٽىųD^n8 !u:`ßs >nXqHCv/XT80g*hԉӶ6lOG$+a|1UXpBgţyd@Ua]RJLNMx=H^6uHɞa{6W)!/&!wtt! '?ǩ=y'n}ǶLnHa?ڷt(@n\''_o$qp);U{dO?,'Oo_S0vJf4fA|(K<;Iv&u .e j=sJ}!K6zCIhowNhsqT&|WMpwUq|tbGɲwP̺_9fܞxjVt:֧x j<4{shӭtc]ǔ[H,2 ˋ: G_nCaĂ{p#*m{es=kKHj&Mg rO ҷjg)9쬩߭ΰGTtU/vh+,e!DTG?޿ÿMz_ϑ7$E.iXL$be\3 JA\AS(ɍuv8\qGOb:|Ј/Dݜ};H4+)OX{Xvdǎ,];7ziAӆ,cʧZ|MJVC8m qR* =uP%Γ!!} kbT>yTݭ00JJpN.;V$m=b 8Zܠy;?q9zՂ=Ru7'z-7XԼ.\XhKN8ޞl͝*wvlj7R?LpB&q.ʥ"ͱElSӮ4.S+Y_L]I ) HR#XW)V %;*T7?1Zo>LhΑ yKK{' `8¾,]Oaܭ{uA:3KZh xy_7iP1FҧMwafUQEDg`e1@f(0dۦϠ8&SI\:}RwZ5Ch/zhQ~Hsx8PoLh19@\]}זRKt'M) yX-R?Y@MsStC79I/d++w!7_Dlx{H`}᯦`"8(gXD4mEh)W:<:/ 2_Ƞzt*LQLzLQϝ[ذbb@x@BNɁ޿Ll3NGYן<"oM~M<}$^n, F ybWQ:h3@`T82]IP!<ϝTJ&xi",Τm#R7C 2 'a ϟMHE^" H meÍCiRA^8{D #_;_h}Vi,ОYΐi=z܇߃yI;==8>ŃHσy1LnͿl? s5 o"ZFT(an"ʱ>DR.B{mJ+tomSo;:>l!we6%)Kk oV~`'G(` \8(mJเ*poZ H 6C97R% b;B¯%(&a"/~K{ۂikx;E 9NP@D=FlSݏooYuq< &j0Gw:W3XRyߗ dd.MkP d{jZvzן7zMP(u[U>R)!3%֦YZCt=N\s}0;i|F3BW1&U3H:w$q\Sjk; xbWM]j*dؘ!~>Ir@)7#6tsi(RN@ݧy>9ݣ"F:C_S8 6`r@{ Ղ˝PJP (;rd2I'ldk(׆ut~KUr廂Fy/: }MV^(PeIS7HMˤ|Ąl %aOgM%Yv2vԶ$M'${GQ&vfpx@Ww~C>Qts8 ~Bs% &q(D3CR?@nJ<̞ЋF7E`Z1v*! s`44Bx%wϽSi K]kѭs4Ō{7ĚD 3?D #J7V~>= 4.Ϗǡw!u;LT>@6@ @L .Pn԰P8X^\gַX7.q=C:," +]bCۉI* ?֐zD"-яK@Ye'Y#|KV/%e$:brcب2TT3D daTb=Mpw\:_[yל{`Es(:p8X C21΂r;Ma:E?Qү ^sM=\(ܩjb@hX , m(i#]tB +2䛉/1CJAYpt( uEr%A{A)ľyA Cp9N Jt!PA"(D0وqYPd[xZ:4 IOӎfxK2[_qe9w!61ptgU:_!OɊMeWAѽ j~u5SM—\Cl#xf KT#Vxz;ޥ6-k&wO\OĄ "~M]mI p6R0oB6ۺTFSAt@B OR=ϯ!:eVWVg[3Pc3zNUVg) 5.IƩY5ŵi$C~<5lV z ;(5NÀy}̅ Kd B g饮2j fq>rsC$#q425G< X'« $ #C?0_Q5n%'IRnog s,#}Xx]SqH VAYKC@  &|p8L( HY8ǽ(39;!,'$ƍ3`d P, ;&&r&G {E33pY];Lvԭ"2炍JSꦑ3]8!p&' ٤7X5l0fs{Nxe#Zi[='±o/|0: Zr-OpE ԝG6 me &Ϯ$f]̽ G~yiŢ( tiU t\ V9UFr(4{qsL{?܃ːH"ԁ=o@ =&7j̠wS{vDe#Z{t;)lJ_eGɚY.n"q끸^4j޶X<~ߥy2@xf毺>L)e?մ0M3NТ*#bh" 5PM)#K'buUxwX17rTi@d1bsm_ $ÁqȾ@Yx8GRm^Jo0<%K`Ԯڪl J{}k 5sSpSC<- +%Bqfo?"xET#jۖYݶKfL (0]!P S[f}j's馈Bޜ)كb{M+6B Y\K"ʨLOpP,!M)uBt\6,f =&ZomT8fclќ1MܖiCI2b}K}%i0Ҟ*?@sazƌUO>tv>CUdJ}loz~c։qlQ $^T,iTbDpWz{]?;ToL!VgN_Ѻ4 < /$fM]<{EIKC ޟtxsq`a5O!Γ82١fƿ6O^>Pl_f-CZ %w1ll1Z#}+\7 :`P ]t5QxkZIv*DZr gBPGÌ m9Ur;_VWyd&IpOlY/Ej}!U !ҍ(ޣ7B;p(B4 G:Eg/!do=o@\8*S/@PGb<XA>-z9j雦J*wNߤiG 8Rׅ6o0Wzk,YV.ƍk}v'-VP2 R^y ҷƨ bJVy*&f8F $7Xc;E/'KRWӶMrpQS~ʶMF  P4=N,@bLÁCה5C 2%Pls1A 型1uSZ>uV<:D+HH}mTИP-|ДR}¡}<Ot$ -HR"bqCCBJB{Owfy|aY @LRV+slmi<j-Vn G! fd?Q퀄8~؝V _ /eGN@=͜@}ŀ t,8((w( f)( Nؤ Z Ռõ&=C#~(1hqْU+KilGSrRC9\9(+dHn-o1V6pZq9;ݟ?XA|P;~>fQA}m,܇PӇr|;]f~xVQԈ" Q2} m;wՏ(% vC=85owmoR'5~CJJ cOƀG<`ꈕ&OSuiwg {o߻eqrWɡЃ >b\w9rC@s¸hw )A ǨU >'aiSqaA4\M6@k3;΀̻D XTyxPC2>()$ N!Ix16D|,2t9 `=+VxN5gzܟ_ϯ<02^Mg<5'Y })s5O=Q }n҉V 8bl[Jq"!4\#ԠϏa`WQ %M /@-=EOx2 j_đ¹ޠ3?$:g2hH}<^qxz|ykCl@X_3ƿ/8@Jx|zuڔY*:0M]8&FNjs^Lt5<˳˗fԟ/HhX4yb%TISCm}u~ܣ9ҰHzv'%֏\(׶gY|}V=fǠmUE UE{,?g˜`%6jp'1i5_<] O-bUہ7(;K xyYJloh쀠TPNjSvM422{@Y-#)-]:' u@[`7Co1) $wGD]H TDvM>m3Awv׏C+o ~/I@*Н%(0D!y\z(TP(Ja xii^$68%혃@vbP/oz\5U뀤' ('X3bf.LS.[Q9yُNx-b˜:#oW+z=Û|`'ODXv.[(*.mwC`LW$}ȘZGHD>dKt!&DL(^:(Hce"1^.b,EaX@$1k BuQ5oĐR#ҘJU{L {@/|bO_;-\hZԞ7@뫠J ^W_{ĦBK4 *:㱇߉ͼ^OyRnءa~(,9}_Y!j^v>UI}qw?[gE 8 -^? n{yyvxهOoA'vVf{:1聎UE1@G=+s&Y7 _hKa0ip!Sh09 (%Y@* p|r/D,`!7vIF i]1Dڍ6\NVv!ۥ08BrZM" uz7Qy=!(1;H!s~-֝}' ,~uxxnj⚼O\\b`hxQ*0yݤ9 Oh-7tnH=%yP$k;B[<~_ꂫGk` ?MT Dk :9ߝ\vt+  *LPD$ܥqne^.:=ĄbXQ"@Dot* 9)x4O~9Ƨ7wk. (`.+/d/s\XHF1¹+ )¥5|ۨvB=Mi &db\KQ$)t8k)'hP/Pر1Ӿ[ÏtfUsl}!h3W[e>4N?nV!MSP!v%?vO`@V"UF[z OSЌzCD)/og7۷~NqгjbAVXqb7+R!<<Y ,%®ӵVwO9emolbD% A}W ,(HY\4{'C{,om})qREnu8֧¾=+ )If{";~oAv6{~nxf_^ cB$БAtrL)Wn ZnM2\Ӯ9 (5Uڳ@4!h*Ni˨FD)roo&THT(2P*qbTɩf[డJUHS&,٭ aájqQ$*Q)SnȭO!nFj{tGaFr2~;o_?տ 9p3ʋTTJNqqjI Ħ⪍T}21«ߙ -cc,\Jw$ 32@h6)~haÙfZm ҿTiܫ'{ Q#9b@/Nlǁ}zxV+*Fq*RDKsx Too)j$Oۑl?ge]ߤdcMiE<>9`߄#] “@0Z^ɆqyL`0+BH.ˀ+/)'1@t6{l=U| 6Q ~ɪT3gҹxquׂ =hS7aLK^>bmLC] qݷhe:v~Prf4~gw"b@~$5@;wHC 0$$XCHbnSN3XgN2B#?=RӋ(z)-ZYf3sn,}vm{d5v:C*4Ӊ38y.֙mO-i*}M\YtU=Dv"dCb;}L|.Au09x@LXiv'?9~[\Ϊ~;R0 H @UlxuAih%y?ikײ!]|HUP N:hHL;{J]~{i1@@( E ` ǥKfçoRh XD&ۻؐB0TgSO\T_Yl.dzP;:~حh*I%; lmsp Q]qq~7ǽcX,5"uBgAF+c 3M/2FD!w{.ۖ;//_ejq.m\d/w\P8otPGԇpzT#gnd}ήwO \w,맂wL%O5x| \浽қgXeZx@EdY<u,A2&!=T?syҲE@CP PãeI*Rk;Faͬ$Y ,yٞnTy@k |mq% kɪs@͟'~Pu%- E|ynOѤښc!ts?&S,tae=5 'S3oi9}=P蘽:J(0W9{m;50_Mw׶p \(fac-7ӵ%QgO$ׯof-\x 5lɫ#/ Yp },K(NGgnH ,/ ~ D݌g)R ˥VPp N:AE Qhq(c7:1υ00DNҊ֔mhClѿ ^+}0 ܮԝs:oZ87w2ooLU $* 1SH$/Wr˩ݵau6@/n[  FਸYU:B$;|vH*,V2l1T.7!%-0a$B}}fR4 DD?O@mvƨ $:~d?Q%jJB ̵``)Hj@9u{ξA052$0 B9} |O~f&7 GPRʗ3J}BPCuT 'rLZ!41TiԂZO(bF;5- -::b?Z")9)?2ew>a%+k0E>1CPB ?'16ғvPhO!AGۊr?#/# y&3ƍ. `Mq+۹ (|C1M\!0Pհ)R@( nfj@!.N?>|?}(}8^t?^jA>4p!,b_ތ!"{ JD0HpV.T{IvH <9캈Ht+yÑ* &dȠǤv<"`n^Cmc }.穵<Q#?0ԝu wThnd6fv9ZVqV˨ҴAǫ`z;Soᙋ'3뚍тn7  uLK?ޭR(JxU A@S4?%0o )?J! 6&Ȅz<9ۯA<]4#.5k9=jӟ2D]@"$_y9 '6ҽ7_SAaާMJEl',9-ŻW~0^xbݳi)gOnRE!#nSd:DTvrȇJimC8M@ՠBڬOHeK\ytᮋz#75+#I>۠E" W}iϢw +,t=\ے$B8 qDsͧl=` M"D.UMfSptsʙ挊Y]_yA:PbԼʪ̣!6"ۖ*-D1Y˫HӹHdf hB11D냆:bo 4>y&qrO)+غ~Jv `pI'`:SPo/'߅&7̀$-M Y?K4}$ e}.4OvTA+)n8uAdcR~|v$WKS'ȬOvsmn.-3 4SA3FvanξZgEϋT:E. ܭ|nr7gw,+oSZ>}$Үr-M sTJ`2$)@.(,"*Ta[RpAV7&8ɼy8q?"&zՔܵwJdž]BBfL:K7H;%CFh43oryQvdŮ!"1g5-waptq^(?XA(8$bS߶윆d9:Ct0fS;IX+~)^? i2VNfJ=JX#cp seE\q ]?޿:|W}O@+OLߙXCuxjNCU"/;ShKUw?O]=6OLxC !DԂOaahyTjgLAoF*GVb%X@/_M )mNݛ7-C ^Ⱇ؈'rݸ,uБq$ S#6cDz52|? BU,Yڭ0&ߑL7T%sLt>pΥ[;*s;~6VҢl=p<6oF2 4 m}'E,?Ck BkDc&_2@b{;5Oq~`3$˺4R)G! i_Y ÒPj 0`;rIS/F<̞Wᥟ~W=nTPۗ9BbuLNΔ#,<:&3?wB`P uqĬ}?}6†D8vmF|go HT0EY:21!IBDx{G?y C(@JoMrw"^ Uv?托2 " a!uaJM%Ђ0enNy)r#oޝVI'FRf$SZ:fm?3Փ`V"I2g䅙di g$p׭=Al !t,`^4R/n+/] O? K%hXsO?'J PSgXP?7_F8cgkTA<=u!'@◥KaojV}]@6y$;O%NN˽$U?u-M{.\i7}bOj )pHmb|l%1Sf2 & ÐZUhNPtA2%l3k\}WZ8lߒJo綮sRgd=*ACEB$f"ȓ,ڙHHhJO ' $@~ZD-"2t-y' ΘOnج!IUyW@ucP^eJe).7z E JP%hLh:K0쟮B7 @qyS"X9p)kH'뗈XxNa^Pρ:p[% H`6"!zJvs:ldg!OL8NUr"tOrݯ7~{[SɺdֱL'wqZO[Gj`Θ!~Lڻ7%_7זӆ&f|(v{,|?z&ݩ.s^:W=I:%HYN!dB$+Kb W AL̉0Jl1M?>JU\+Z5GK]KӼGzw i_\|֠rb!FUnS?wnY^p'ޜEd|Մ@@?B6zjRBJ%BQz̏ÍMer$֓8iD[){ E0KB ?Ϥ/p2=(ت v#ߕ:X n`G™4N@eQy`;3!94um1@_#F721d[>ɎOGT]7Jdd\03j2!T $l[NQrbsWԧDz:an=BGe?$`'+$_Q #ߑ"2[/Fɹ *x=-Pl4S?1@bOor%1f}qn~ynEtʩLj^`AqIHCɁk?^:Ж헳ő|ߑOHlg{5d0f}(pJݹjYI\aʖ,twE}b%!Y( Fg"S`(V_X]*u?SBZ5nQM %P%r]Njg* Xs#ZBTr6Ѝ3>רϟVq2[~y ) gޟgt?QzP7Ia7>NC?4]hx[^ۇn?V&UpcnGƊ}L܆Q5[eVZJ*1O,f!K`\E !zHLR=V[8fF羋kZ~W.ξbћ"ܾv~ F3ʕ,S)jBs[4g:# h4=R*Ņ 6XS >yx4e.ߞ6o QNz5!d3ʛ(XRQ54\ xW@\9kھeh >fc EV)Yr;eNe; MOS aɨ\S%+9RXS"'`wY$8erd)sWQĝBLhoJ_g7\ߍ+3 ֡hۇQ$Iƺ8Gbfo.6bju5P" *}unc8}>dР}p5d .({S'3WݺE/Ѥ$O@ ]@27, O<ߙlYB,g RCIUB@$ Ho HD8B" RzHLZʼL&9Nۧ$-9觪斘JagW/?MtcHQ xBTx `/t1 iIq] .f3,_9}@~|@\.i2:6]؆>an/dٓ|~XQsX?AX۟{aIӲj޵X^Vd*N] X XFlIEʧD2[]k?1}=>rnԪRr H8ge)*|@eE )Aꖓp'r'~*xv 2f; x}Lrl-H.W޽5Fv(>_{d#H+=񱿂>n{`#$iba7wA C8kol|"@1h/W5EϾQ1|JCr//U0$,doC6̀+%z.>C&Q㘕#]3T: g&e QfgϜh}ZyJϞD6f=ldD Uq\0˃ko 0եs!C՗3+: ebZUoqI7c}NVs R4赗0㶘5߳ IㇻXƽ1hAQ"=PR"R;2 la`dM}8+7$C1҇:]NڮSQhl:۶1@=i?!]C@> ?0xų-IH(|Tےe6lFo* VZ}#֣ljH_MR4 @@__rŃ* 2ۊ(^Lq*ыIfP^;JFiY0R ړYYxCޘՃ .?Lc߷1Q۹ś1g[Wlũ~خH1h 79N$9* nWYpX [ߌo~O[u5 ؚՙmUyWj+h3dZZ@@= ahRn-sL8URPywK8R,]@ƞj#&7ζA n-'.sTG ! Dtn@pV ;.a{p}lsM5߯{UP4ALe uB>GԠ$s~Ƅ1;u_r` $LCK/ًnr{>uۿ͏;ٝUcQmKf ;y`[gę-gX7:e |JT΁hJq0D{;&QH=s_HuM5MT! xgh2/2:HScj @b?G@$Aq`/5 qUNbv=# @pL׊$ࠁdH gW27T/!cETfy/P8 h]]N?o6t;mN4O*w3bƛɭC Қyur\~mن7ȢzSϸnfP@(©Ho錃O!gX MQzcRg9:ݛ)?֜t.~lK~~ 3+YUaD\"S)|cB$!{D&ΪY(ֻ?'n Bl 4Up>E5@(㗭gMMg}."L+`ĺ@pcr v+}H^v}N}Tprl!qhM)n ?g  ['=g2d`^XCCe)ٺqPL;  o sG P'YLxGH| i)k; bךNCn>cp%L((+y ( <0RKZeLH:#{uߪoKT2hB Htk=UTNкC%˦h OR4z&U㰑Ajh{adً=\sM/b˴v'?(: ͼG?o,'>Ɋ {REe@ĒǷ_*\ݱdwzM"A#&pLyU񰺘ܔ{ϙ<\L9"8,d۵ [n:~m'FNڼuCx\k/uQ$RAVZRur1M4͞PS=V`԰)]qٞ<9,o؟wB@[eV]xsPDס#zܳr7aέܨsw۲:P=~b_t%gٺz]ڲ(F^E KtA̐ǟs3ɀҐ(>'o|2d 8iQ$ o )ǧYD렠L9K=/XL`n1D.P%uJrꆺD% 52BQ^Ɉޜ5np568I EJO=?M "Q]x!W4DҤd 0ë )Td:0x "r/ Hqc !#",ABa>tu@N ``8nN[ةk Q K Dcl] \xsޅM6iq"$>?2K%4HO81''&tpPCc.GDu4LxaBo&q IdkkJ!8;t(g떦P5aFY-Iob˨_[F^,cl}VT)A^Gy.H'gnDOV,k/Dn{(YG~I\>+39r Ze/TRY %e?BPJ늚N1:0β:,}fpͣa͌24, {]. @D bK=6=I&48x?g5aU޾~ uopk~l23mc=IfϝE?ǽMc0O(!&Β]oO뙁KÊMɔ2c"^;ܫJa 6~NT8$5J'p rJZE!L.V[ʏCL}4É3gUF(HFiUgBSUd{] 'm\>.{֘;@g8uu[&-u蔩_e K ͥDњVއ^’(ٚגOz31ygÔ-@@ Lİ BH%k釒$ =,^6mp Z >0ȧn|(ݓ%J1CpkTJ!KJ ȟǏ͊Ӹu"D,C!2IXLdn_YD`鲚dfϓ)GV?SO{8o_QW:YB,t (>JMm0_pT PR 3{?l|OΨ7n{?_fKeEf>mK@L$/Z'a&bs˪UBS)%gt|^)?W>XDƫ| ̢7l`0EC0Fnqwx|>SA?<=_\Q }cV&0TkmBC qI_P(V͜`w!tm3*E}Bt07+ܞN,§RWŅ51d@|j͇i#v/wH\`yK}Uy)@C#ЃQyXl*%qvgq-(Bi u@ " oƦ^1*D6TtFVse"e t_"BHbY11jbNJ?ŤԌmٯ蒃b`- 22Hޓ3B"gHx}suK,XPB9]&;Z. s يJnU.(^zO2Wm%2oT!+t6dG&bHu$KC$U_}Uo;+ԆV|"*stiwG8.*کtե+m4aOa0&bodz?wX2tskفPɘ*jLRA*s1S1{U S%eoqtNAoEjvw}5;3Lw}Oj{;u柱gЪ M,]#Y /{,9lV&c:PNޭ?m^hf0V`,*a?tL8x@l.zzʀ"a䱁v'1 's|v(HkDϔq-vvҤ@8`dPhUsbirpv.Z NG_FNEZzd* 6$ %ۑ ;̿瀼RBd$m13"?Fƒ-So8C Oi7"0,7>rwOZ0HCYw N\0L ˦YAA#KRFU4 ҫpxm n32`Ϛ~oA·N~'cJ*j RăKIAcq{9HDKId>)o| z )z/F@8$NתIN3J@t#*~ݩIAߕ? sAÉA$6PPJۢk`-P'z^p.rQ;.[;ŒyB8rcz{ 7/пMn#0;Jbb}D7)tsfnr{y;uk^Zj _zIJ9.XV*B=yԶiojߞW=yz{B`l4NzZ=M:ðw,&~f!vȶ~ q)|]L@R)[db)OLGk1A S:Q`qa D 5~sυm@t)=>#($ k9_<ʅ Cnc&ERr'kN=5 ?*ʿoX}Dy5;SÓB>$~6;Y?P((#L˜ftiwyT )9H4& T޴n2QfP`OU.كvVB0K~9WT@6^OSm8 Hv("O"-O@K7db5W\cS0/_G/9[3Q wrlƶy{VX/2oC&h=[ډD c<24YyIŏaA! -_U) a'8@KKoX'2Wٕ[Ϛ9v::Y?;/]j<<PdAЅ_;%b"„[HS*g:%6ICE1LwF/E +z֞.#[RvjY yh1ހ'*@Q1zLP`?St{y;ن )xtZWȵ$$ C Q$a onGc@ e%&Gg}~Yc" DH[5rRm7ڧ_mzά'XT0 `0ʕQ],É} iU4sYxKQʼʽ53}O-Vѵי|1e6Vf_ 4{S[} 6: |'@.dmG]pmE6)?:;};|%Bb Fs Q79 и{Hkõv٭ث 8А4MO4DVs _'9͔GwvZKU>+Sl=ަ2xisavx^s'0ppfKP*xμ*J+ , vܰ(fڀ$HX$Ucm<{I34?|ˠC赡#}t-GĄN!At@ k@j O (LjkD]x+ >2C Nֵ]MB5}/0Bvzu3ӺZ^yvM2M&s x|@OON% $,08%] L:.&(DV_ ;`R8'< aD@DD@CƔ۝|u(HZeݤ7\gpjXl% L%iD}G"``ǡ):7l*ofWoɕ!>$|8z V”rM~rncAJa?o9d=Iyqd%\eHj: O@ cTS@_bҵ&PxZԡ&Ǚ(QpMN"@( @G-!?$[I9^(l ̜5Ħ  : $^bӺ-(vT* V[TXJ PG AcR` NwC0= =/+_v$di3O2̓ K=%Mנm74kbRԁ 5ΟNҮ G)/oMbTϔ(?»iu_Dޚ `h&c>1~ʼLa^tW^(%BaS)$]")q0pa4!qnU&c8u7Ҍn ۻ55Y@RIcTE|HЌ.YBZú@m,"&t{w9'B#ݬ "CzO &rHЗ4LX"B 4JyBW<ڑzˬre,>=P%pLeb\N¹bd,[ I1v3SԦlt%k O?|羡2gmBTڋ!gL<*v,)?,ޟх9{`5'q; $NO.`/h9 |ن%Td`ob_ gTຉ: h}LJ&q"|SsI|&g重S @$CU!Ns}-EG7j)K"iW](DZ7~^?CLFѢK[ u]y@6]( uu>7*PBΘ7@rpe g '`6) fL P>},GmJcWd$8C1LPKFfB=h.WrX=D+`ZveMCkU`<j@. "A1>haOdY=w[?+^LޞBZCv͆952cwzu ]ܠD&ȄISeW|٪wsZ*nُ˜unay#a-G jP8@ ]ޔ+u":>nL#Z%)H]^5_N}Bf= 8(WCE]}-QLI; 23~nROii}P:Ҥ\C੥~HzMDPIHS3`tCyR&#Y|]p@==~l;OZ읕wc_Go"R`OFO7>Mg`{((WVJ @>bZT32LD{5J`8? *y+n]9Pb49:j8:Rנ;,ts u]D;Hzvߠ@ÛaTj%ӭ9IO>`ތ9* F3d]n8/|"#dmfY'TpF(d֍Z:t0#4ޭdB(a L6`.i0) Hkp!Ȇh헴/IX,Tj$ydlIC(Rw-Vg>t/OQZA#3R[Aҝ,!HrNvwWzj>a$13 @l>s).nr$( {WgCJ~~Ũ:̽x3*d.ɳz+(D!{If /W?|oZ^I;ւh(,!W_cn`)% & 0G6wyg] ڄ `8l!HtZb d%BѤxfvItvCMV3XFYDVQ@S7~aaYǵ63r(> K6wplKrEBZW}FFiSQ$ EHCbrxJGu):f1MbzJ|vxfIo|=a yMç5%RyR% vp}=0:/-3}0B@9vf I`1B̼tNRx`9@КMz"% 40\":񒜖I%3f9zq@\#֖ĝ,UP9O!Sz7XŘ? NN܉UTH}5*dgؒDS~yH a 1 R$:sV<泥kɊءl ia&cymGͬަf$ =@'wf UxqpܦAaHJAyXؘ0 X2Ot4濤ĝZ[n:ŝeVxr:/D@u<2`a}RVzVe:J ]S\O5:x?w} Ap&T/pz5! u'*29Y2lu-LY}q&VD ,Q1T>m8>7V\%38CK1?oy-1EoU3Q{#ΰEֹ7@LKuLtb!5o(f{SCd J]gaG@CE2Ҫ,^8AQ\d` NջxYCL}:Tb;p ĦҴͫFP®XP1H'T߆yHS9Jo Mt?~(hܟ ? ٘6`)6+y0}K:cCK:pP#Bpt),Ńz@b$׃$6§E@ʀ)@S8x}]FCozjQLD@ßFz:w }~jC;o `(@!OJ- /ɆBE\Ѥ` L 4ovkt { ~YN/y=w>)}!g6PSQD˩Yx|i[j\W)ðy C#fe3 v ȵ,?RDT_T&CMe+Iv&t5Dr"A8-Z->E<kqF 뙟ke*(E,[S^KYV8"ӎç=Pe@'iޙ%?ܯ;`$J @YBdNC)CO/QyV/}<Qߞ!"SsRsв2ɳ#I*{XAM:O;}9={~.dH:L2LIGTyw3e(sMY|aၵie?orqm^m'SP{Ut "!"~s{{݇D5Dj|!)hϴHPBD+H,.d|W11T Fǝ) }8M >~0p$v0\mx&p@@,BG%PrW䨙]`{IR%dvb $jޤT?_dz&B 0MLylr0@dwD$ye" o#gY ԍLV ev\|9ZC(!P`v[dQJn)C0{L.Hq˦U% fy,R1'6QâuBN j 9RVb]@94j2qHvr @ rSeպO::[q5:SMɳR\P^+^AT@@5G>aE-_!<'OZ"K]-_-7GHWJ<`,v*D1́sv&2Zw 51ȽvM4M>cϾ`@CE\I sIgbq) </nT 'ti;1J;gOi]JCjEqM3&!* ?C7I_O[00Dh3U9:$> jm9{\ @!eP{}KįGG Q]$Iv4,A 6':rpZQ =[ %s*w]ۜvħ[XyuYt('( G?撎yp݅ʓ$:ڎ߰.V{/71`M%exls$q`C{J j X_YgWQ]tdM@m8(GfI|B9AqšRn X˔@d?n*#B "Ai[m :kd Ug@d@zqxs@ AHy4\ޟ3]ijAPXr V(K}426p}0sMFH/_.@E?ez甔''7n7Bj>p">*PzeIVoիRe+̆Xm)0T$}\R[^-ʴrO/)_YKiuL y$YSVڏY8[w[^m$35 Hd FXDޭt*$g4AYvNs W7d|L*Sސj^0Tk Y ;!@˝u?ٍx&ה0h$9-` j˽˙2YR_qA<-_ǖ =l6=3oZyP@@?x2)5`'E^R" /A`+qպžux'q)Ɲ^_4%Nfc4J]_Dc.PNVI099B ̐F`ـ;7`KH1I!EՓ?E=&نw@׿{F6 ;M6pU'<[& 9Ik{ٙ, A@+Qy*NMCv׶T8s¢;uƹRL<lkU)NU cWˬ_,ܹB\A hq~H1Si1fe^1@F+\Esw|PnjL/QOgCC "'T~1K@& @P Dتo :'}SdHOo9}JgՓ_V䟮604؂}~|Mr{NU {>~ްМ@'GW+w.΂=a2#5; xxR[4(X@Hy@l Ķi{Ys;g@ZnS%w8epؑ a",o axCDcbo/38t lB<\N)÷N}`W 0v7l}RRo(M1`SMٽY%q{(5\s5_ F{GUk?ˢ (]ژt!5#(:>f^3C}{;ۦRi@vJ& \!)%UAjZǩ?s= xVa܊[qoEntN34_{Jv9'ϧH40=;f9  /lHSC0&d2@p1:>Axuǟ=Faz- jnV8mGDتTqXIV]ƴ+v,0F>oΨOLCy6f|N躦O\/Kyk_>HYq\T9=q{cÍ{]W{7~]31.55D,e@m/'U}B J)uf2IY͟7CIa} N \;Q̥`U'O}w:_ )0jJꡛl a$8qYtަ^" \> Cg>BʏAV~19BFN> ?z-|_uwiɥH6⅓%+I0pQ 31ciQ"2sp7#!qӬ3Al'dLoyv<)3!&Р˃G.1UQf(nX){\UVRL+w@11He\QEzrlo<Nw/m0&nF\j5A~"ͯV$כ=>6H5:z(mY_E~1PX颇ZV;qȒLs E"y X5Qw~͂2l)Ŗ ںyEa<0P5bqpjo4}}S~HJG4/.Kl~C\`P*'{ hRF=N} ZS+ \Q<߮Mpe6o^AQ hU1Dg8A :Zrr27P<];׮3rgP|_h_t1/Ћb@;BX>ouYf=)$>O=1xT7Dl I8&^a˫]-(P?RT5{SWĀWlFվ{ʴiF1h̷gC<%Y^k-ϒiHk3J|OY>ɰ{pUևGrROWl?VB!fښ2 _$)l/h}M~rA;b>/IJ-͌ Ϟ\@ˁ@5h3tΖʽE0CW9Iqܓ*.[j n)y*Øxd2[!WhW?N1NȀ9@ $"uO@);_:ABp7(!r3tY>v XTn`,?m Kl$Mh؇5@V L utCOP{;lL.twϸBlҴ?wꇍV{Y=? zQDCdy2g{݄LfC<7]>yiGn_M>dݧpamS'j7M>V56=ف;Lad̰23Bz%$&BA7vdBLc':`,g])wwy2+H~:o"oˮh>njзr.̖N7|$;0|@Ό7R֚D SM0kZ#&?y{[}Oփޓ'Zy^[tSoáz5g$xC"p1L|NDf,'L>M[-^+MMmn:Ԑצ2pw{κ4:bYS} ԣۃɚMk 4MnkeG Fx>"3OWnat };AtQ'5r]_;C q?̻cvf_%FsY0O3}swgGd}'^ W,]&ÕF⟮33U2=/E-vηs{ 6/Z|tc\+m]ڱǏz'_r÷[侏2~Wa-pI8EwGfm-}fƼxs(O\=?,6FfA wa(h'L<U309:UaW8*9#(ەB_M,?-Z5U(oXY@Ǻ>SdN\q:FےvZlSc9Wr~74(`H,+! V @L+!SWhТAƁŝ jEpE֦SdQܽ(з8Piax}\hTܔ,W}C;ΖM9<}פux-h|OwOAT_ڋ쳔. yPxybmݷFo8|3srODۙ_>L.e _[D!n|{=[ޅG E"IӺ`$i!ЀRYe|E5o}]w^I0VR<9K G(I5Q .dmX삡B 63$CQpڏEB%_DjhǍQxuN#2j͍A+yf{wڬoϲ}7߱P%T"w_Qöˣ!&)$#bIǷ`aQ&Zj I <G('tѶAMdn7N\4hoTꜝ"p  JүJX̆DQ=!be](Ht c{m)ukK:ݬ'?b?cs@O(4rh?(}ZLoӋ?8?$ZR.|=)@ptu$ ,:5T6^\2(P[$ fbxJ۬ӟZm=׈;)|S{}Jk˔?|@mPXKMWGx҆UP=\Y@;,n'\#NsqAF  xp}uH3 `RHcΝam&PGyvI ~zET~k|^䜡_yY7)&1;BpWδ}ytƥ  Yr(D J5/1.K1ZRe`mdq~Sp2G&lW[6k ئEmY-`m]hd!#*AmTLi?g5 jZ/vjöa[pDLHam^%'Q<9ϋ  ?ځo xA@#cyOaۿ{L HeL "nG1DGzR?.ףFsLJxGT^NuaH0ZiXʢm,t25$f(g({'@ (q7A b!UE͙i";%Y @mb(J5慧ԉ[V=h&5T:&#?C*Бl&)d%80}BB ]/qi׽1:`C ??} =y:?_E~܇od{bd3,#'zP|(NRNn}7wO2]zj{HyӃf$kEa5[K"s̩M P3#q6s)mA@rTJt4򠧗hTpAٯnEUs nO$ZPcx)}%pGq)4|z)ɍgp?bބ|pCQ0TSU?BzErޥbw}Ц DL4ل'PB.)1&Pl]ʷ#Hpo^o+@ ɫe 7)x6O.(۪x@e4W+jy}*yLUg`y$Rfd.~T_.®W%WW#)) @GT1+AVG\ʓªЭ;[Mz7`W$YtYb|; Ioz BxΥ!s5fgi{%~v8z,ҤŝLOrF5:XܧoY?4*tzi7yǩ^V0jR$H(UB"ŰcW[ޛvP4X]"8hi .֩||qt*I@ZA\`%{Y@ہx]O/f_.ɣ]\ϻleKۿOǒdR}O!cB%au{ =ndʅ]`I"^Ϗ3 C ˳ھ9{*L&[d*LpBDANP( .w/w%2Һz f[1.^iG4wd#-姥q=,90KspH( g.Pς=ԾӁj4L`bQQ.g^ˆ[7<9Xr$@VxԦ%>T[ɴO}s3Ӈa2kU\?QX՜\Qu(Fbؑ D@hh Oin{쑟Dg)/X8 Ǝ#A> -^f&`)խPb`~.Xp|^ z]- 0a2 t%1P ƻ$ Ms94(|j;>_l9b]F@42czO^(.K7vZ1B!@p2]"؄u(n̩H?p>4)д`7^&U#ǵkRxڼ^曟Cj66M@Cm+73Jtn'&MXbcν"m뭠_d)M0, :Ht {hgT -e22Y>%]{6=H=;dԬK:ĒS>T|?!ÿ_g%2"d(T?"px{n\^fX8w5Xjl?cSzm?rؘyMO >\'L-d_ݡ-P+v0[ |Q/z2hkiv@/!!zEbš.eö\=>Ǜk Ђ?y^=(q՘Sn/wec#c^WY@'Õ䳽 ݹ4;0 qZ3HD zfDDgc(`@/0)%rjC`f)uL/_cN϶3c~qSTӥIAPvMVq[9Ҽy%k :$̪:OKiC`O@c)ř3˜;2*MjX,h>ܽ<A0o 4PjZ  5SIwrDvβʪ23# Mb ߫(YC]U|F$%D(ҥ ćRb*3R{;&{YoAz)daՖ=m!2j{EAIbmŭ_t>ZJʇո OK>(b;)wvP8)py(Rf ' @7i\ü >QLJz~qBG6漙 x{LsPG%E-)l=a<%*'$T_9 0>bY7(Zʫ۔)VWEYZ͌קR 1ܙ8/BV忴M)-6LI3 :7Zԉ&ATaaFny<ŌLL6HƊm tk0uꑀƒʂXle:Sׂ'Ԙpaj n/< ʡB< ]aq~ v4? f"Q,(X$ig:U5|um2 @ /Ns^!g BD %8Ԁky{0V]$S k<ҍSS|߷h*& ]-Ɉ/ҳW#7"es ,ixk4Ƞo%,j P1ٲ+far:{[aq/ɆA20Hc6G6S;N4&?#6%!{vuP3{>u ,N}~b"zME 4 ~~hPm+OebxCsL" _Z% !yGc7ES=~F.Xq<{ex{}m&߳\y#7!' QAO{[z[}JY&KiBG}7ԤUq=t/Ȳa ~ Aw$ y1:$7 %7TkrJn̕~]y*3N˅`G S)l*HX %=356 bȦ E:̝32[FZŮnȆκlB )Id=X8]j k1'IԈ8lg\kpދ y}4n}9e߲υ~&9rXSS͎ 'Zne xw X Uve;.s> TaH^C.`";h2u '܅  ~`l9ʁT$-Y:] 濩gOV\ƙ+]=hųz8gs<21uܛ CyP3PUC5Qibϓ+-F^ ' ̼x8/(~d?e wD֛YH4;nxsY6LSQ(ykO_$OO&}@:P-X>%h5ud3Zg  {&jN`Lܷ(.sm_Z/%sypg<-dt;ga¬ =PN@De7Ւ,bHQ71GD@7om0)W*rL:FxwfOG]{*j=YhwtKY{7h:[#Mg eiS܅= VV4އzx{/vvb{Pq{>SLC_. kp!7hBB]ŻۚyQܔuaKQ/T65B 2/kTPPGpC f?Б8 :|xЙ ^ܦ4nr.w3(."4h%wA,>ԼvO ƔBC}+/ΟR)6PxIR0!m$q^ kԒs~y:q > ʔuk:"8qrAg$k~9 ;_{^? dGo 7!>'Wѓ a7# qJQt}$Ȓ $Xޑ͆(2$ZA r(bM@DSQTŁ)ypMj,Qdƈ(Owen=Opz> {F)9 Ɨ#5XFu63Bi_ {3%{,~~ G w4aRAd&tYW?&mhF-^-kZ`JSsMay^ދxD]=N#VuvpqҲOGzxlN$LEdeyRjq]Ҙ 7B$p@ ΗI}#c^=wqα|W,FOuVEbҪ6;8(ۧ҅I S$> 0mqy MÏ![&N|gN%eQwB}_~"pA o^ϽHrCF<;j1hy=mauc5/y%ai@IÑ-;8OP{&!.*-hI8uP5cY¿ f4Lt)6.4ç0f(d@1]IDӲt5lqҬW((Vr٪G:R+R~I0(|qU <ő* jWۉĘ/շoʇ:_@/.܄<˲W4:r3֮=PWH>ۤ bq*9{pW `tg1ʣ@LP 6Ʊ y9JO=YWPy>ZՃ?y߽w0͘*҄}[6ǤyQeQ> 6O2cZ SތYA]dŬݙe>ooԉ}}Wn**v>[V8GPW*TY#{{v5Rޅ7D6y)jZRFb~($a4PBJS1&a珳k/LP.@2iR,_)Gi G/kM9?ھb#'kGL㙾ژ<AOu>p VŖW+e D#qtǤuQe`6&:ОaΙL$dVT f>W!wn$mblh1#ŕjBw~|9-;Lf,!18rr!H/l۳aͅQpӲ\d8z8'`_[Ke@%@gPAя<`f 맺&V!IAK6IcWϽ]{PL>^SGA{=?oiۻtd3zyLvTaLwzфQyTrL#Q7vsIzHN$d x \@-'RC в)?oGϥJHa(a[=)R:+|}"m|{\oC}r/S#xcJR:*s'wP(Y K֔;R mۆ\<}}/_Nq gɔ'U)ς| X4X0CF8T^Mc[^k`)6}(qwEoraLs3`*_<+5gD!Ie_'a0CHѫ;Mˏw%ݭrp$yR+*d񋱏HJdVlz&`n3ҝUiLgV  w(f. Ο~R]%>|<߶eE'w% ( ﳔl̋5f !L1;_̀0W5)/U\hb05ך*ĐugBm) Vh&Tw`/jkE!"0tfBs@pHb!s $|רQ-_d#1G0aK÷?ȼsj@\ " Q! J;D6T0>ʐ˫߃*:ôr2t,]}sdt XȺ^>8]ݢҪFLH QZR/ʸr)Mm7_^HYv ~ -g m~tDCl)$"rjF|0$&B<u2K'k@nBPv捿؃c)sKR_@&zlP]L~l$>(Uǟ-M£ݞHÛyƕQ%ؠunjxUNΌJ鑟]xob;& fv2 Tk)P‚L… ϓ i}D0B{_]y#o@wA@xsЉF'Q yXD'g&?\'?PG?~_ T;JR0$]8>ysS"Hy_bZD1$6iFҁ~#Vt$o]'F˛pc0 (h\ʹR|;m1A>۪BHOyhz7y͉ީ#ڪC7+}?IeDwGهZM^߿nv'Bsil>rOV3${y.}"=4!?6{P|} `{N~i\]z39ЕMJH_Z  #:]>˹dZ?tK8k:,._:l|7 VW0rO]8?ɇ`ͪJ|ӭ31囙=ŝC@sC>\ԃ}JԌ͖?TWyIpLJSV[vdTifr{ٴ[km3wo%\Ɨ3U5Mg,:T :{e=!@z6cSz.LKy翖۵>xh6 9V-UGqۅ75P=4z56g>WE,Wٲ'zlvvX>U.pxNUOnk/u?lTPm Xu{k;5  ܷ5;Ժ*t| ,jۛ߳ .>sGsn.,P/cN~MK_j.⼸CsPcķP_ '~ *ځRjaUK,b zxqwV= VݼŞ*,bP4ٯƙk{=8fĮk(p*ڥY4+&ф֢fju?4~bDv/AyCP(t\= dխD@D,` q'`\Q\$P t}l;dzԓEN68CK&K?o }IۻZ:Oܩĝl ׋ -EEbvMᴀP 5wU/?K]P$Yy HrӶҥi 9 ƜM"_@w! k.#?]x{W_Fo@(>D_/Ҩ͹Xljr J`|6҉cM` E$lo#gq"rnfimq߫Wз + W"9+@")l2 rx ]޻C||=+Cff;U fb}/'=0=;z'2x D_P3|,606O_8y}~[c>}SƁ]i#oMfiP>D"GfP]仧l| i@?(8I˦0Z~5/ 0f Z2Zv$ܣKkw (ݔV:VCw=B7ֈU@V;LP &u|1J_P4#zq"B&չӧt)fïZvkH|PUC8 6"}.:$PV ܊!Z s*UwS\ *1Wzu^YbΕВ +vxh/??wU7%_Y7}Gz:fPI#}UL:'boۉYl(,8Poun'+5RR7՛{G%K6vyú+w|Sșܥ9*E kc֛~,ΨVƷO3;s]h"g&S+;rVM@?sNKB&uMݓ\1$C>""kvs] Gǫ:يE?pJjꃂr89 "z~ze뮇ݼ2F!IQ{klQ1(*!@%a~DsG|Ϲ H 7 uoQmt9u Re̞F.r!@JmOB7vH,hY[>s=W?^S 2E Nh7*]2d Q A+ɍi(>R^8DMd|ByЇEF jAi~{q,`埄ڇ`=>LD6|*]3r|/y?}]0 D"DHTQ>:d%gFS`\stݟ;OWդ~)2 c_vE9:^i,4)\ɘzNxlֵi9ڴ"?L]A4.71"KөFjLص5XSflPh/\w=ǥ27to.^g~iy~IÈgVNd{,ByO:/<|}I?xWP ~AXie˻lMK͌jD YHn7:"Vb6 Io?O"8;L`֑l &U]stBZ e.-({S?kz Rk $>'#ݏޏTIxl ~0+q quS>7J7m|WHXKbBdHJEٙfW[PI&`3{x9Xf0ЛTA"Мä~0cğ[Z'/rw'!nf$) 2- J%A5|{',rwYޗ ŊN6:p@wUvܸ֯%~7'"4$1dɣ\ pXZlU Z/8JFX꘽c?'?#"xFxxS<)|ΙQlu[Ί>> YRlrDžg8}ń=Q T]‚(9> k/i]itt*|BrLl |AJ]QP8lu(dlm>#{xq6$c)[{*K KyRA]aKޮhZbC [Sz Pbi@ ^ZN" =?m*K^Ռ5Ihu4Q`ɠ_*'늑?Cz0h  ;}5#?,((WV,iU.=~ʁH*MCs hIB'm l(O ѰP[gU5#@Y+uЂvpRQ{Rg /j(ҌF84Ǩ` 8q,C:Qv6@kqr"jbzj&(b +-aaOg ~Ln~`?KĽqS~upyx+*Ͷh鵻6P: AyCM1! Mߘr-Xlqo ٹk:6m?Q;ТPxCr_ΐJݰ)v/k#q!6(C,>)xD!>7- W *^m%kcdB(De }cJ|"VP|F嚓+nWa)mY9r/mnBQLPXG# k϶uo O0BWؘ@H?(U_Jojtϥށ:`tD'=cHk^TB ήQk%j8N$HhuSUM掎|EF6_wlss1t;-HuH4.VpD]$@IǦI}pprŅnS#Dh!Ƀ\`yZ"hwH 2~)nǥspW̗ZCoUf7v8@V qzXs;T,ʹyYW9ަ բkBNSěqlhgU` .Nlv5d:n$:8$[Z]8@ .t6xI%~.d#):}.-Wd%s8J%Zxԯ@yNb1lAN{vw= WB}e[lU'pmx8?tߏC啽uX^q6ې>Et3 !Le%t Pg[_֯2owRWfp~ثDCNZna4t ^%^Y[=IQ0˯&M?w}@R=k[ ia P@ou6QBd{lZH@b)/fԢ׿='Y!}i+i61d&Ax$ҁ!P [a@Y\זIWӶ%O=FIV䃨c&t%(CԮp-\e6{UX LuAf uۚ\g7b 5k,&>~66QTK֋g$ΔzX"wPr;n$g:f!C2ߥS){ӫH=H ^ېyWR@#lOy>ŗ$52=ZYoIܶ@ /PCmϜhCtkO"SU?fRY>H(fP Bj@}<MA+|L*3hG5c|)?c:D݉ Zrta|J(0a@v QOi֐7MBҢ͢E`PTX+V%$7wztYcF=1͸Go^C`{xsީ?^gMgziiX}Kedoi$Snz8󧷆v~9|K`L}acUQAS|קw"O;vGgjbP)="^Nm 2ԙ:uHrE0b5$i͜> ګEQۍT[H\mU:B|VV  !L,OgVUv N-/ͼүs?kn-򹀳Vp: irS30 "mo(;LH%UK:6Q@Ƃ*El]\+ԕѻy5tH'm($1r WoG~`zSNv!^kU[3s(pW}0J+dYYIP̿O=lT^2%~`Bv~?2'KCYwybg9w6R0zd揀j`=wΊ[eܮϛe`MzBeNqNaŃ'ڟ8j X%Mv pLʿuE{?+2ReMAͥMqfۘP% 4 8 r?f^-j5řH?ߡR5Eì86HvF_Bʕ@Am`?0j_Ry*F7* 7Phsst7^q-XګXvP@`*%lpzPnQm=sJ jv#uTL۴PBe0.QH;קR[8lU6f !@9^ w B@:Ǡ8!XOAjqdT.E@N,^#m ^4|"q*Sٛnh[[K'ě4q/ Fvj-7*mԁ@!YwUCI8Z]$8F¼ӆYb؇-,WҐl+&eӭQq\~(N_WY>K /_ b5BC8ϭO:Wp\J>uU>k)U7خM>OT0\*|h Hsǰz`dETUOazka}/~ݰO(5)iUm_U Fsqi^F&/* }lG$ab;6Pfl% @p)R22G)d ^ŒSaCPJ$%._9ZJӖY1USWh HdZt:8dI|:p##^y5&mHZgy>w1?1?q_w͏0[/b{-i24(L3[XRC0}"eyC;9Ot0=+ۯ~l_TZn5DA]ϼ60w J`dyf԰j0^yҘ)H1$'mx DH^h „WT $zxA@(JQ#Q0s/i>" !') 7|biTğ s|9K!NT6v}BcoM. ?Q ncS!^; 3bCC޸Œ_T" Cc+bTܡRmO! V>-" N3c4B1& jdO Bd!Ӯ g9gDŲ;R؟i@*4'`I)lΫSf/ )&O%(u0ϯ8 QR+ǝ۝<|P:T+ @єHYųQtű0iSBͬ2, ܰに::y^?sgjBT]&WM ]sb`pl""J%&W">4@Dpw[MIbQ]CZawWIJqU/,³ + U'x0H$\THQI I F ԥ"al@lG-%+~S`MZ#8 ÷ NֿdS} C=4W^Sʃ7SK2}fqDV񮖴> F?(|F[DI+cOh' VףrǢ]C/@J{mߪ0ɏhp.i6:r=ؔ!X\fB4=ܜ@~3?}LDwhZvtPT0򡔾V&>ft'Ā'1/tI:-t&f~|2j[p8WHz_X2905"OV`d!7CH)Q>υA0R'p<;Rqa? n N`(Ja0![ 1&@\COSPK zΉW*HDP*p<裆H"ȀIq !LlyǢ]y(s2pxL$(qILB-N(&؜s.:? H)>7^gXnT0@Z h;ktqbArXsGJpPU;ok řB@WiWK#۟S_F‰t~rJ3 OD0T#{qr xvWh{b@9U>ذ8q, D?4=mjaCk }EyO򧊻ʂ;3cŖF_ MmoQ<ٴf;N ;j/2z#YUhHAs*\#c̜?I#@ 3egoiDᵫ\M^ٌSqPVƴ_0E[>A/#2 מ.&4;2p2*6e?&y+ `st2cE7EK&cȨlڟ2I.i0˥t|>G4)PUo2T~gi+ꂐ :oRL0 O}-@ɛ9_ >:~Lq:}=GjCM{Xn4򗃫Jo2Uw0,T˜NrjMBܚuw~&#!\|,˸pϬT֝sR]f,ErCJR qq-Ц▍%zh0GSS[ @dU/`n f88ϱ~9Y8YF%bk:&ǭƔUpG1~ 8(q͞*X`K;4vj4矏שּׂ3lceQ] FD4:j}p@ƺ käs9lWY?tkPjCM`swsdQN% L(!Lf_[##%l4u{OBhμG5Jmtj_Ŝ<}Kg pC 6] xX ,b(@wcv e`h&kK^'OwѦp[䦨 {hLm@ڞe? (~G#"Q&bcĠ̱ $qm&;߷?>=:Ox}6 J$R! W9x6劗}U##BpBjW1_JIw"'*DՎfSz[L4b['̵ MY@"KS.rX 7CODzH)ݘ `LLR@"Mwv_S$8dBxP{2WVj%cT!_400Fzr l! /Ny%a[OuQIUG IUTYC]1Y@m}H9*‘AĎܡpn`9'dN=tH "?]ItiZ]svcU"3 Y=A('¿gj$ B6ItH~E"?W^1kfr+dc_E~;O TIBl i#OAd(B?Q"BT@D2X&pY1r4*?k {+vSVl[twCZft9ODh6_N 2Rm#"\{E";ɢi0 O+' 枺S7beӉNLp[0㍰#[/O> Ccyskj4,!iP۟s>8ТD] #='SQ @U8K)^,~ W2p,8A\} )R!$yP+b|}^</~W>\hĽ1s'.M?]J *,Cz_lf_j"amz0_Ͻ?ƀڅ?oAb21w`XSL\;يT!>j$q>Zs\!@ꞷC-q.uȩIU }uidژѡ߬xMBWl1zYHD;H($ $Kf;T0"d[vB@Xs: G|V%Ԥ+yvҎ~,[u5鄜ּɋhfNnT14%p;ѳ')|'{gWnptJq}죎wsm@Z )A4l*m`[~tmM0JWw@Qs~]<AH.J$pb3Aa8+^/Wőggtٞ &48⪝C>}cQIhGGgO3=4[͝CBPHL a`@6& <迵&<~=?x5458Uh MqN)Sh̪ɍaoY~(q|o7tgjuY8Ž]T^7Wq6<"מF<ѡ8US{84p'O HJ紩Y5 :S^ИHG^5<9P|Y1$ j1ؚ_YCtY:5|df4H" TXo9*1IO4B"gj4F=>7t!(T G<%cW(\"bճfe[Q*[C(2Κ-4 0zdž(7g/ 3 !W|&Og{))g/Wߵ]G}Ơ WVpH*ᄜOW D তp0G_W ,EnW蚩n2kIa~MG% ˇ#뇻؀%?#(pqqٕ̽AeWXTXqJDU0>uw KĨRֺ`~%0CphyޞI-:W@ CZF XT&ED01ṗU КJ3 ¶N6 0FnlJ&pٔ-a )WAao%PZ\^~L=w<ČΕG#.h>=N5uU+XĠ F]J^x0v#i 2`Gk#Jʚ]3Ԧ̎~M"  j][nG``!R :*}&sD(VW󈡁|¼9|K&-a\Tz+i}eCK ;pc&/->r aLٟ׷@$ U==UøO2 oAG [hHMՎh!ă~c\~SGȜ|vlk"0Mc 6Fn_>M/f(ٳ˗>!NEU ~ .XeVP~6mɡ#]y{6!ZVX/Ѡg.xq1z =UJPM(omNm-`%3  ` k 8$$ o]Fᛨ ULBI(; T.y>g(|dLɮ'۶) C-YwaA,j(9< =2oߩ |D~SxȀ)2,* =X#jMQP@q=N&H h];ll++,*S;CG@H9+ݺ]( MV1N{(W5w oʎ3HCPʾ0q%LI|k8r WúH#ݝ:M lPܒriQ*>.oulԅ6.tSQ7r;?Te4q~d6zNZM#<5"(X4\tTsI,XxDb9:gP}yy{NhŜ.N:t(?=[3kKo=EYӗ/)Z"1'H~1M`nt[g2]HR3zX+@C!2v.AhwxHϗ2! ᰥQ~fw*ZxjJ K)oe␈zJn8Io5* "@A>%$sP.\}s2*A cQPfH@U,?(!h$ g/1 6$ o'`:*W=3Oh ^&DB|bF챡nG7^h؜5?(YE9/1VPuղk|JEeq7b*শSM/QV Pu҂')B-b[g 1&Mo$ROqWb㵧9s Qܙ? auZ M  @ ݪݔk/`DR C;~.g(l\ 94 zl2-8 [ap @ P!W8kKA[T񼕂Ԟ㧽 bUbo#}_O 4T1m͎3aT×(֛Td63ƶP S+d2]3+'0;,rB x @ !aDW[cWKWVRXZOsdk%GmbDuj(T,qgW/JymNwn.`뿞`67 *ݵ.u%xzBV}(.4h &G?GP +Z!""6O Q7`ÇqЋљ}cs˭5ov`z"IlMFT15rQrdvB?ʔ E٧3 OiM>jVр~Y1Wo!-HXBΖPR)t@)'f*yt]=߯r=pONL+\tk*zhO4#|7(%~ A ܲߜۧ`?VPu]M6 C|1jKo/i/GC +¯gkuv$,ˮ ϕY?ueTѿZ`\3xx lw!~Q~?-P۹5/};||* Ǝ%dPV~&q wO1ә2Lu(#VP}XӻRJ $m8^~Wsq̐HK)| 7oNP5BYEբ q:䮖S. ;J"*q:u7Z @POyⰖfZtGѩ[nLJAYc vS|+C6C$lwpqsh%#׮_)JNA.at] 9D9 1ůrȸ.^/ ?F2 )rߛ:'WǃXr[?-}k91ZU JTjKt zJws Xbm$gy{'c(xGzʥ`Cw>Ėf]Y0>j,cj0{騹zB^%K0HDnHt4gYs$ Y17 ; \:m6-xeka}T̲TƒeM"J::|+p6(i| >Qj@Z+~U @"[\H1cH#c~z SNqpjc' )0pmD ;i@y滠llJ|NM"=1 3_?_ 5,$av5`ݸB5SԒEQMG $@ּkХ" gW1VaOѲhAݝ!QjRTE遑  '1T?W ,״H3BE}~&nz@C'08S1oRD-|0(3,qBM!cc7Z⍳H4I! vbi4LA] Z* ;,S/w:3uwO"%]s=-?E؜Cզ6+{0>پaq㷱F^%'ْ7- Ǯ -yUC(a0 $ h+4Z, `F @#/T'kj \zsڂ`=?up#ϓxOuW8,N*NQQ7p "m=Sr}x0rdt,˜f@H1f`Nq%!Uv}ZCO59uh6!V~(̓@o_sJR3p0gFMܠ?o=s>z8DZI,p B${A <9 2c? pAUV+_hPU!?@=HP*)Gǯ aDx8HйA-M*Rj'JuDZMM8T'Q e˕(w{S|)U|SlňfqUOn{bܗ@?~O kCj$ E,fx߁B F({~ǀE"U6Z?o % [..0wL Ζ@ݻx@jy(,(| OTy;'/2Pǚ܅0dC/:wgD3QP|2 zS>lf XH|KaX5,ζe;Ѷ5@3vc⢕d JS,)gDŸ=]I\PY\̮*{γDJ$Kq)UN{½If2Q:ӍW{>q$X]{rO#GSҒ-1X|NK:lyJI{glπ7hm.vFW*}P"8m>{@mӻä{h YK/n{\w﹪JU_c/W!mM/(BÓ09afE!b!8rG 2{FڊLy*ꁇK?p.9x "T)l1I;PBIQrE8#j/ &Y6 }u!6Ս.κk9e # ]F`42GG :`~\^Zcm[J&ޖ@yMuưAUy`/jsv;`*9 $@F#]z~̤[榽Ld4&hJdzHP`Ġw>}1Xq D"T ?Ԋ ꥜eҡ.g:>Qze(wء/؎JO@Bg筤D=G@[\3)q%tRG3& P>Mks8w$!*a lHh9p೑ u85t"Ym,DxY=;m5;˕4́z*O"5t^зZrMmDg%n^[J.YX(Fz(c N+.w$Lɑ])^\#Zqr;*`[, gb`o3&(o>=kݛk?XtPה ,_s ۆ'O_T#rۺyIp2cYYנ@e(KEUM&:Fh I4%tb3Lu"N` @LIHaŀd D!MOcO'j|ϟ'}>ə\Im[iH ]G$(kHz^V'50M﹖\yoGy699[Mvo-(:'>TSdQt^4e8R7`N3}[YY_r\FLޖ^6 j(2e^u%KX5'32ZA&˨\k^VHbI&uCuMID*h"\)(yM;??Ln8ibs 6K=Tv_a`!2dq1 H )2pŰ0dJgMݍP;޾CRJ+MIZ4^4\ `ׁkg?W`M 8{[vebTgV `/Q޹GV}w0C- efeDfg*>-Z .GvfGMF[*UG@@Gؐ=O`&qq08 AYR!Ed2ʾUH Р]]'!  5k~%.b@<)H 6 sX*>dy><*@(ai*1<:uPeuƃ@(3!bz?iDu]GfM̓x4 s?AoX';to?OL\4`gB7k!AJ gq$ % +v0,]Íi ~` by$h|TCsQpI OGReNC;s^ TgJ[Tw,KdP,hm}ҹK_±i< `4<,wt9>-©Y0Kq& ׹jR a_\? EUJ0l}hӢfs&ES{Q]ҵcYsj%Pu0z^ܵ=b7?;ww<5u.k Aú*t 9P@)-NelgLr\p.wԻ~J}OCӈa!޾& C y V?v`oy~rp76͙$v?IJ3o+ ЂIJDry3z2ڷ~EoI?# ,~'{6<-GF;+CHL(r ^,ʮһŖc3 mnړ.tK4)FIFg4Rv:4ѝ"BI,twoY~'@_wB>54>LXTe)5vD}79{3gzO,cO@1m[t>8bkB7ёnH`g`o$H?*gbu)/ p? }4 S fc_Ϳ}RY!ޥS(< ef&_R&~կL'+sŭ6G0{9r?% іS܀LVrfU1*lN_1@J;owPSSp= o=zR62k֔\rcjM7j=c#jOėP1x/QU6[0hJs%TmBs`grj.EIB>??Kn ;Gna!'#aP{} Q}VϧX?ޜ$"cWS~GX)0h_χs[ 6*`Qw63J??7zɏXp= ca*!3xV䎴kd猘TR&r+Wڭ6gt/UÛNԫE]s/~ `'OD($7_ DK蛹&G}cQ?g6^^+\m/U(}ruS~aU10=Alpj%v9~11HHȎԄ!8_u I-M'|TQҼ|  ~J >*37h fL Dg?su`^!XL? p}}tUMS9Z`MT$[a?-ki܃?cw_ }}|K''q.g?ߥ6v̠FȔJR-d0M#HAr1G, uC b>6L? )FshXA˛"\ʤwJD$H1A ](-֊sy>ÎtsSBEGB9C-5g;ߖd7"wQ[:bD׼b!&ԗ]?>(Ł~p)}zmPXΦ:9?ʹG5pφfقF HqI9֡-QE B-򙂘XNƮOU =׍8fF.oIk#g~ھY0ݰ`QQދt{!uO:6>k<7CK4 Y˻#I㊠B[ti H{ºkrA hE߷Ý> ,I@O^h 铷?~gsfo;h>ߣan䜚g{S/w{wa?GVYhf;* Eٓ,S֟Cg쉍Omu3>?5|/* ^va kPNO|}a?bgw]l*]o)ZC`]HD&Qڟ0/=A4~rJ̪b)fWv:a^Np( ܨprҦ ^[Ol#z+4> @hN&3 6UEm\3hJ#k"%%19 _X1"w 1P~@k4.~j$S_%C695A`@y fFUR7JgCr;a]}Oc>]K3J|*_1 ϒ3+ឿk\ aB Az茹]EJq`|v(9eW~ؗ" Tz TU0_~4hV%]˓977oO^l͂5ݫR``(t2SUѴNO [Z9Re oW=V&ͨ8,Lxu6XZ<,`gɳ%RQפڸ?!|w @/<DyF8t=SuΙHR&eP)2b j1DxõnM {x7{ zn0G.D3}d:1Fߙf[SpA{s7"\}cHd\8G0â1{xvfo[zBM_Zߋ:3TGt(ͳ7mHXZ g)qXBJ$n.&Es{|ZS{I8Dߙ:Jz\WVdhZbRQǶ@*~irh~/CGGE 0e?z8Oͽ~$6<Ѫ};sI@@ri=QC49L (YԠ$Gam9'nq0C剻f < "r@I0ykYSvuLC|u`?_x ^k {L/-?o٤߿twnpZAsA%(%")N ~ܲO88h'Q~Z/I(2b#y'WÈA4}LCГ!3:(^|,r]Sb\kvy*L5m?͖fDmd3)tK799/6=jiJccGW̏ӬuQ SO9VvrmLNuyZ͖` z`mlRbeLv[0҉s|. JZ Հ$@ VSWP1uh2`:"+'G]:H95I}R/2|ٵ ^ޤ.@ߒl_@Q ʕ5v擲|~~%276bۡ83P$Í,( POX˞(J` @ [;?~OHaOz 0?ݚ"1BcT{HeI,}5恦UPs FYl}=|V06*Xh>H[Pnf9⑪ Hf[z^: FG CjT2Rq'U2A XPəpid>}g`GP^xϨф WҥX ,4^ @T9Q_u e k{S" } Q:iA :umT :8E][C _:R$# Z[~G{|*OSIf NU5I P~Iŕzo^-CAX]?>*]m yO( o*~Z}/|zPW J*g+P ;RV' nL5 -Ht So$33&OhB=eI&:~m<{Ԙ$ !a*4SB0p|"{E 06~Sn{~zP~7ihT U|o 8͈.9 \HsrC4'GC6k@qw4hW;cLgv [)\@Ԩ07WnwC%{ts!A |ma즩+Q7(tlSoF `$ _0@Q (i}9uP)U)w z2gn/jWLLs~oxL(yRjcQ맋Pl.]ˑ1@)({Ad, ]:jf=Yl0G>ZnSgR;j\ #Bsu~ |B!OR]/bP O n'"'IeӰ077Ɉِ5 gwˆMU;JD鶾U.Q]^~ٜsr3L5@D;``}uw U6kN|3JM;dN~_ O:w6CBDPtSHjVd9H~D'~}c>oty=m Sp_OI5*sT2@HBQA@+KtwC7cVlQfgA<-s JAm8@(Ys')y(2G#xze˻s1CS=Olд \2$Zr$ۙo[$ q9ݘ˶\S릠_TqV>=m)tS9^LDNd`4_t+=Ӓwn,wRǽ8͌sK1"K(.,I%ŪB )ˈ`2.j@0gǗ ذ_:X{Kn>̀pTi?%{sE" MQ@q(rg#gI\hOM&tIMȊs |ӳ'۸eגyQ0@ >5.XeI"A#ʿ#IW#Wە7'Gg0 axA:p`oC婑?Tf~^f# aV86*u^dй<]ꎍ=3.k}oK-e`?(+RlPXǸ & Uk x$pt_i*َto؜ 0U!J{fcQ6j~. R*5ͭkZO0 Q1`!Rh7IM znXp`D}czT* @>;}ȿ{ w3pAB:h'{kHOM|ܟwǎ {o&oDAHR@DTעtdPX9~{~%_{υcەf~$<\@̈Pds;/+zm;0OS/6rL<)1&NpwHm$4xfҡj;M-;FԺFhkA[LV? >|uI5!ӈ؀j=3Q<8h}NJSL&P+x|LkN_gZĝ1;__@#^\kżB-,!@3jϾX1ϘQ"1 [tO k.WgٔUXyIB\>eC.y@!&(ؠ@1Y桿u{cQOps_+B剕8h B=og* R)Lά'M4yyZ HơJ }-?7vʽK;3VfSNF}HS瓾$fpg 2W4@YA|'l0gɂvzNF1#J;WEB J8 @P!K=>‹I>*(N:zTN[fv(oG 02ȭKLߌgɢRsQhvJ̪R(|J;=JTl靝$7:E'w xbڀtvFQ hS`SևNPݪ3mMfĄ겓F׌@YBrSx4 _׻Nd8 ;7_|h!ӫn>*_m7(9#r1-l0P>!#-.~W/PxQL†x.8sM5mf^Ql(P |yOa ?9 8PC6X n`+xiQ I|PfC_I3'ز@5TB:S*P0/C%"8pC'u4+ƽAʜnvl@ƄPKxJdMd, haA| (H(@P (PP P($(P@(J EPPH@EP@@ P(PR_aih mH (Pͅ(AAQBLQ%$Q A*P QU%J RJ@ER(E@@@$"P"P UTD%QA$(P *@QjT!H RJ *RTJ* iH$ @A( @!Z!@*Q$!Q*Q)QJR1@TIUB)@UQHFaVHPP**J)I%R(DH M+I$U@!P--0THTҭdHJJQD(JB%ZhfƩQ`R*!Q!JU%JhSl2kC-ٖmm@QTBEERTMk*MM ^ 0Z@K@PU+@4TEB),)BƥB Q*Q#"UP*`4IցU*p) QJU(UP( "JABR`4*Uu*Sb UBR*U)@(0T)Hc =J*U tSU8RZhU*T`)R 44Rp*OXN1R&Ҁ A@iLQpLQC2@E*, T)(T t4Pj%TSEPUa$.ؠ8P(  * 20NS3( P(t*QTQE"(Va*%Tzꦚ%=Ix`ТJ-; 64@A!)@WaqhPTRC(*pt *84P@Ϊ%ED T`T ET "T@Q%Q(QE`c%){1B :$ʐ*U*)R,LTP'åQB P:s =Q DB4)T&XEU٢wH$$\D 2 T@M&0 M=AEO@ I2h4J JL  &SA(zM6@ڀb$S44M"TqcziOȮHeD %٩1uho"%]hϴ܎Sq ԋl^cN .Bo-{:V6=%g>8]#V>@GzVdQ5ۼh6Z[b-C ˇ`N`+uA `ȧ;UsjN'W7)fG|ΠJmXRݺ{Fa(pyQ./iJ雲/k"$\/UMYowo.+]v^}l,|6 @wq-i`6]1jލH(vFXs bUgn_`F2>y{|3EljVj]j]ܶgq[Btq }qKkYB2u@F+"7'k+MVJO.TְT$kuhkpzlLĸ͵驜eXuvt{1Y9؁i4'K-˳ϣt=b̓yO\dzofp;N)Vѻa+/r %}ͥ9Ɓ+]-g 4^瓞fwMxIDTb_kܜqސ$GcfdC z;幆[c2>̤ﻬ,6*#x\P37U:"Á*M(ܔ̬Z2eY9N$n fVIN>ZgX]3۲l$[TSFԩ=Rni]$"G+B;Zu4elT%ZK\$_V1ϵ*ԂrŐt͜ӲLȎ^f{8_i31e)N畼bTvv5{wYf\۬g] f64ZE6[T3Ϸt& Gd `wvPpHV^J!\] v,ϭ".;Fž=}N2-9ljͤYZx沭 _ 6FS'R.e¶lo"}q;TrxpʾΛh(%:W3nE5o8n}g J S]nO 3F@1. 婤gX-ʙ0rzP[υ`鶶5DAǛ;n[pe\7;9fshnx &gfm Bt"'"KPչvVPt tQ:+5JN\V(u5رaꧼrƘ ݦ.Qeu =GwEiD՚j9+9k=7抺=,4!Ѥ$km;kE!7^XvٯõI!͈qQ)%QS z^C8C;S=/Wg)P0;tT_Bɝx牜FQ#"cVoe6QƮ)ˉٙ.o.Ԇ\=&,z VaLG ַ֏bl2]06R۵&Ŷy81vg ϫ 5Qm w =t:. nڗoZNu:ERnv[G&EΏ*.O"|`7lB*۰xE5JUo9Q%p=}Koy ciӆ3,.R5]O0QX\V/~ݖOcz-#${"[ ca3ݜ+h[E:˔l[ loo;> -ݯx]hXv+hgWbU Ԧt:t ]NysQO{b7g+}~{ܕiV18JW׍]oKۘ.c޻{q(}*/aWT/2Wڻ{[/-skml̫}6c3UI,=vAӜKZk_#YU٠sBU(tg Lb!k͓q LGUZנvκ:|6 n\cuY wr݃- #彡2#Zbv@Nr67PS%:4[83vDuۮˤPMvkԂz$QJtCEXa!Zg(q:]8v\JF3n3/Ĩڦ]Y"kbY|L٧J&H;G)+;&a)_LP #9[G$j%cj f6*N%ldʸGYk4ݫu<͂9mʚ_q[>VW;We:MKs;]ζ莒Su'u 5o6zYʹwiGCy浜u嚙k.]J6Pfde];n7_'xΩKPzlu{;ma0]%Y;^RGsV^NuǶVzܨ/FY vbs7궧PƧiX$]uû"8lnAZnKwyIZOȸ^N:BtJc޳|PS/kJ  _G[0*ehIQ6{d)mjhz2g9ɝO]/uT cv@ 5`'M;ܳ|zXd *ɾulNIueqwni]wt|a}55>0YmP|"|0m7f n\hqmnhn+m2tfӨȇv:ŇT)q:%4C8;Ηq2ֿm^V+;1IY(mV\IYLjuaG9NKq=?]aJ*“05ʱB] M9j!RX7uv:`Ѱ0Dv_3d0X/8sstCОf1cqU y-ne Yzo &njp5ŋ&dp120,mh꽣rwX:žUVk" >!m̂+;YZw-+bͪZʒu_en)_&uӰjəD"U"1Q'x yjG{T3Fmk2*Ǭ[pwr=dhQH<`fQͫ3:\]zBzXFF7HMPMn&cF1Bgs ;];`f+~]X q%][9yɑmQO1` LnmhdSɯphM/Vp;>׈ 9{SpX5hrkA<%JNXf꭛5= yueǺ]ܸkܹvp] w`;njT+] u8ons,h+ڹJJ ]Wا_V1ݒg,77.d3KwhƝr齲__,Pp'^Q-uc`b*nG(>xӁm3{̻7b*Ũ̅<=&b._it3Hnrھ]J۱[6MSF 1sUPoTB<& B.K*l肮%L[)vM(mX]k6fk#э=\n¹p= &9sMe"fu9,\yђ+&LBRVX38e{+: D[4ٝsiӎ+T'7m'Y eJpN  q=[x{V9Ҹ\ T~)úv^Sa+TY8f!YD^r_N/z"nvgn Xpafs[xydj*д03ߎC:jOojXy&"4guv޸nZ;)F۔} qG9 w.39lj͜1%+_,}0[x%¡ 4[ WV-c1-DA9)ݞڰ_#xXvdTOj{-VbV9ښY#9;,tSwhZ~ޕ1p -r+ֻG:h OU66_0|!}wN6Jѻk 5(աljz=/,v]BջGg\~x3Z ]VfʀйEפ;˻2ZN.ĩ٘w.fs[[l!h=h#cbY-<</_KU].S{]һIN\/ktڡR[y*'n[*&zNN ]]rv$^>/Ø+7AM5]\7S:"ڨ*WhG1K{Mcn`k3ض3#[TAKVms) 7Aͺb͉h3lTaOx4kx^) >1y\,8vFHʂfáe`(n Nu9c=6J |Z%q;ju9c9M Y1 nwbۣO &k9ǣWL6YgN%;IXBXlj'3ᝏ9W7YfZ(we:)-q5 v- jkU!1Ԉr0]soU1A\:$EKa,f ܫ6̮e0ޛ~{ghGT_PP̴{1e՚!Q(a3f::f9Ӆ(ZK{Mh3q1eλ2K::~+)橹=VGNy\UrLU emњMQxN0;[bu@ZS5jfA<ޏ{Ekv͈C$;k&"3sf+9fE±RAMEm]a;.ŹVܩRvwCn]|] sqڝ\65b[Y:B#aVI5וڜ\ecPpٛV^-V$dY²봌='K')ک/D)nv5:A ԯpCH MXelYtY.۫H0dˡ*ۼ9IP}]bVūb}k;p^6ى1%CWZ%a[L/c̗}fU͸+/kVŭO0D*#|̃uE;8=&M h^n}ܲV8Ա7.Npх3^vҗbFw7ʏňtbOx ܾXJ,\-}f1lW7ҤvS1 :er٠(F1[}h2 l =%;%vfW`[U_Aܮܾqn.5uؼM04)aG}xoG+o`_Kּwc-֒KoTXt7s@¨vNRqnn*AM.ۼޡèkxƐ62Xɩ]c=|(:2 "k  -_Df5IQN54saJsBސ]#:}ܖە7 lt9-w-clCrE u+N\龪8{shPFS=lm= d :MC]w ΐk `s_SjJ vJU~дYɡ*Rj="gk1dɹ|sv Axw3+xŷd8r}]+oZrYZ=/9;T7V <'jٶ;& frׯ"͚WjvlNQ9+HWhVo(Cޥzn|ȝǀ{ճlJR=q.v,vQՊ:1 :uX;8:Q)emAqP#Ф˦]SVu1s8^:,N7h|ۖw WN2ȩlMnӻZi9`V7QNZ BA҄W}_\պs4BhiҩN,S:oe JhT fEA>XF 0'֬y5J4vl neiLb3_o!ONɶtLfUm9cb̲Urcli9$ fY =ZW3A& Qݽ4rh+a*t.W;.sq3mtFo _R6 PIېer,AAD%O3l@3G}d?eK6qV X.uth8S!2ѡv[.s"z'|kxM}{$x 'LmLH7U՚mAdV14.EX8]Ah"lዲӳtxrbSLudEST@dc!4dsBfwŮseYٚfbO6{2ɕMw iCt/de4Վ<[4:kA`ټ}+n$mY-٫s.MnuZ1 1 -k;CkPUhw ܧ:s#]ˠ_pSp-3f3{g8H >Y}5tgw{OnwI"wtC]yloWƆ/mɺV u3v`#8pʙ6z Z"YYf^ѬYAe,VsǍ\{J2|E*fc.-oM 6/.r#9!Z$& y ]ru-9Roܧ\쨇J,U툷VK/5Z.+}77y iu勗qۯWe%ˮtʄj2^=y%ˬdX;oxRmLs*KDπx2ֆ(bvCze/;n-Zu*vۤU<'7/_R{LSe:Jv(:V{۳x@9VЛ݁n* i.eWPR൮הn7R+VwYz`qtv`yvI5x'zcRŽ^BAg`I#[*+:k: l4n!x.k7 kkUܭyE^q LU0jc"bg v9Y-rz3cd\o7\Oep:\12ww̭k5ԈjWeg/$$PȂdF;Fi4Ny]F= `ѝ7PmG@ mpxdh ϕhwbv5FrݚF8vGx뗛5GBd;yH&.f T h{ݘ.f齆ՅsW4pB4GE.tb- HV3VȮ}BZ'(S9{ru<M̝Zi˚i2]P0Ofübt6C] 1y: $lm)s&Kܔ,ץX'q#4n;S+7]Yi'i];m7rڠ2vl'pL/pw|#;9U1XY&7w΃3$-IVR(Ņi'-TR\ ޭy@*ĽϥFpYɅ1X4 H9͝{s#5eFEmx-r,zvOIҀT٤dO_S)][M8DX65GCg'"k&G*2Flm= ) dYNGYΙK.6k-fSQ,}+7C w X#Y)f9ƥawx-N748ڻ&^QYbc@im`ҞB8+v WU3SW&ELo;_T؋|ڂv"K\I Zu؏RW{yRg!z,˒뻻;#Mmna!uhڵ(]}X|Wm2N[QofLTrB)un.Mej"󙧷L}q2n=$ԽL΅V97;4ԾBn+`:K}5J+RlL cڋ9f&7u`ŽMޜThom xO3.%H\凨\HFSdQe$V[60}9H~nL˵NǾ]gMsbt+=m4 'vfLUnoEtTIj;ɲ9^0 ojbtvevU}t=u1F5%}\\pb;F_ ;sh}xOK  [õe 7V ٩]LS6]Eo|ImSVIf=OUٹ rWQqbե+TNGH4֛t{)6iyշhprjuw6ĝl.2dwPFJ|kN6r]Q.R/L͏ Ƴc^'I}6ʷwRY&ou;8;F2ڙ~]Fsbx ʳ:7ђ:` Y]o&J3;{*󦑙/OX f]Pڅ_MIfñ+W; 72Aa׺"~<Ŝ7I=OT)7)せ\( %5b9w_d#,?7nǖy׭b9phtՓ~A8Y:ӊV99 + V.o[:)eek|`Fk=i]d@0>9c}KVν]ĩk/V4rm@fc|γHţk/L'Pʑ:se1۝(^8YiF^㖥mnv殇v Di{`t('*]G],,^+9y.Uν|s㱜6Z4*tp\F_aWC_2^͋|S5Wm`HIC;`AƱ] > ZʳK~;e0&;Kדs22Ix8[9,˧6g$2B@뱃V,geG"8n9Dܼ'y2r‚'7x\F@1^C!8:6hjA9n ]cj :TH%hoHnN]؏:Ussɺ;Z)*9BC0V毬 #5Y'2팫s'Un4jͱa[6BmM5]:J֤A{^:B;_t2I=拎[3y9P@!MAV(=䂰!ʀog`RtՑ:f7m\pAa 8Maͥc"lDl!S3}))#3[AHۆve "i&HC8p\hr ™]`C!gxpÔJ rSlej5܄L tνjcʶ7)hĖ^YV׃gέu/cL9_PWm7ح6sC%U3tmbjjUfGC飝/i˛ݪag6`:WutC5TB0rtBm'9gkW+] t徳n<ݧl2F[)`|:}sLN7!.EK5}½Ju:2 ]{x: he !]br-`gtX`f֨6z΀IfR3:Jm twTYXo/cc7)'-J$j52'WN06՛ul;S>t+K/fysow 4lJbbUa*fĺ:c衣 @Mwwfҍ\8}w=ǠiP)ۤJx$KoJu9tW8!wxU6Lz,eڡ"˭/xn-8P4Iۚy1 ϧnX2TÃr>:LVY]VVs]Ga@Wc(2Ĭ,QM<|LB7(k$ر2nK+, G.7w_۔gĊ#w6R0]a`%֫˼GkPr!;Yo$r6mW+yMf-ġIn&_lݲmasE +o5Ї9^Wjtk EDP 2IYF!d>Bޞwٹs{>GAAYQ?^㢄MP;k)!rK7 1 `c'Z!Rbn(͇zTm>NwB靔+_m/:rܫ ˷ HLJjT8haSu$ҠY˾bR5A 6H GWhOvu922a ׎6ʇlȭ 'C']cYmҸsHWV.$GYa;o{"ʺ[ڐ +:봲xf-jCw{cbHg 핻Xuxݻ[NI@B:qXfIRE2k2d 5չIЩqX-`'pm+\]Bw!-т}dtqj9;y:ګ7 čZx]V!U3gέG8ݻ˗]XA^f KEwCMWdL[kQ,gjs6*-Q>,_hr7ݬHRZ흦)ᚖeb(ʃvcha[̽0)ӳf986:w(ZjVa+fl)Zw7^uV*c]o.c YA>X9FJhܛ9'9k0]4sY!=duf*Uv 7jym%V 4 p*πm-dSq-nH?34m_hdI[wq>p{9] RHJ֧Pͩ FE+{vRT0GEfޑԭx nyuL۽vghpMMW@uՎYA&L \x4b9Sm]GR:VIi1TK÷vK5ȇ3&d%UpP VݸTٔTNQؠtᮧ> bJ1@㑣YwoFˮ7!‘N57#uvuWYn }P:7U^!Z@)2"m&ynIѪ&>ZoemN[r1WWTpN%Ybof0Øvt2wD"0$:L$ygiպU1g7Yxp vӇ6|"s i umvKSV]HVUor̻7NDeڪi`[!jȝ a(vozT_^Y+rRv*Vd Ak˭py/zV╙QnR&[Jر(%vbj*"JwlWC{BpM ƦN&*Jy[E*3@iwvZFmrVevl٥Gn]eu6FC[̘ڝxC.JΏ#q: dtURwlθfm,׉-xXH1W3F=kh47+/km2uuL=.ڣI:9kd0J4-+{WЭm*,D.Mkk q`ᡵv8uKzrZe9 hcqbƧ:MUn""5nBU|҈7H ᦹN.Mnfk;pWgq/XY(]%ph7%wfyfNtM20o^S$Mގ>wG^v MfՐKz3oȮrjӱѤ+Y.)C hPg+^N.ljt;CۢGRu;-a+&Eճ.ӱ.-U)B뫓Xi n9ז%Ko4Vm˙ /v Jn]Db*u %Ez1J-!QEoЮ 6iNl{wWiBe(2gJݕ6[<aW{zJkJoX8{Ļ${pŏDM85s@v6T5RT FRB^Z2Vt_SZE^c9v_9QEϹ3mi*rg^t[D)C4p݈k\{n9i N$;"zԉK)vї4.Mz邝ڶ0wVk^܍_4xKn`2'ڣΗ-ϐ9V,^F˰؄;ڸ1mkx@&][b]:i7NA#Z/v`rd@VV˔pTf5}l VVhaYBK }Y`tpe֍vQiXp1l*Yzh|ث[J4ڬ *w/\[g×gjW&T0V|rn:֭-j^}#@>Ʌ6•ևm'V-^],f\A^7uU"ȧF gv6Rec%Mٓ3e "*S{Bn*Γ~Zjj@ vjת#NLlofN8!6%,۪w] ͶMjЉ#pX¥Jʻͽn\Z}b^dgvf 65cՙq\8J "їի㧻ywmltn8DvtP{WJ7(EĉC3Vm'e^9vWXBVh屳sp'5ydޝܻ:\ߍZ)q 越,QYXxۀ\nvޘ4bkoAhUټmSY"(As2c`X[r^cؙTK1t5ګA+\c3sUog5o Okia[,"dkgY6ve3zCf&Ϋjǘ,dZ[H`ĻNoB{L&eqt{fm̸-)x_UY]> MA؟Kڴ"%NW\0! AnZCvre D+,eF⡌| 7ٸW[޷Ѓ69H3۶k6V|rykÎf:°hZw {rv)c*ӊWCTN:' ةVBly^^˳FSCFLm̗l[f64!:z/iKpaE_&2Lf;YyIWbA݄wDJӎز*i?Qsh;É6jrai88*ʁ7z:<δIju+k !ήkf`Ub˯;PHWAO^,rJ s eEg!J̜k O@ EX*LTtV՚_r5;]Y]EVqY:7-O-`w[ #ч V6v ;$(TCFOF, CO]lo{Pٮ6Z4GRo;rJA.]X;h^%4HlYEIUW[VV33c}MdqzsCVt޾Ը, 23E E1YdlU뽢xqg L: Y8lIܔ=-5m5uL4V:=ژI ے5aZ\a9gfNw-7I52geus%=)?lScwQVF՘1gt2ƭzвܐ:-S>Nxk=[y|v*GYr/; )ɯ Y+WUѮl#W(:5nh*|0.|@sR_lܾt\ŵHy:srjoLQi\j&a:3v7n˦ v٥NY3_L.?yk0wTx9PE3) s#d#Tt6,&D6TYf@S.|W2(' mö-S )Sz% Nt ۼ}fKdU6qFHW]QP$'BɛcHa  j^3Gs(@jNtcz Mc@TnQB% ̡>}K_mͫ fϽ(:9 #d۹wV*_CaC"Dj^<_=(a2YevACv Wp9W]!yWktdU +.oPOiz`Z]I|YڝC-9n_rYIN$T|1ʂ*Tׄ]=*;k;H,4JѰ"6wtVZ1kusrٲYm^5#;R?ua]C6[Y..Ki9mq]c['e[N.KhJ=۹Q|QJ.6h-KY`;yHڙPY8Vwa)XuQj u+o^zw2u=|(Vm/81VÝcYUוfH~KŒ2و l\]/,Z+Lg:r +sh;0&j)7m4;7)ݴ7LNNdv(%rv4y֨# Wے`{ 4 7Vg͓WUyYp8:*{shh+tG2w75/9A[/uV{r.m+MM+P 憎kݭV7 N1md]OX,UءwHǹHvcpvԍlT: Iֳ,om0huICf2qUӠ<]3qĦn"h9iP-'IQʳ4 ΢1euu-*QnL!\ phBϻj:qP*@ U. h+ @:ZV YZ`jD,&M`~5v@biJpaWU;hSk,`J YvR']\٤k#@V ,3 o kQF } Fq"P7O QAii*z nifŇZUPխͣe7knfoett]ƶ*nXbbRv?Q|u3*{'6ɣj${^rfS絣LNjS n]ӭ{*]fdsru}11x7.ǖVԂc $A.+XERe"(n|( "Hnӂ;}Kjk Tu>&;҆rsksFL# Ծ]cɑ*3fqtU(P֡ay4n^Hiܹ¨s>LqV"<ҶQX#L$bX' ˮ.*35dTqOnYqWۃE4᪁= a ^Z;I^Ws헮wxB9FzL|vp}CƵ OkF$N!@7/ZK%1I'MXV՜ԜYܥlzrm)\]%ʽaB,t.k)V{hKdJaZCJo+"} n,2ëKp<&k6^,\flMWۑ3ݾ]zMguS6.' y(]fL~NCt =ٺD;bkb7fm9e.2[Au//dJ4B\+:ò`4 ܫ6Jɭ́UFˤ+Y^hnPPpTjy=ʹ;j,#S-|o8V y3.ތwR.C]%,ͱh]%Vk0,oF-vsս6Tx^r.苺"˙k}Tb"mmZts|`W9෧]wfY?fJؔKruv*kȸ91\1X7TWk(BF5>E` uh=u{\6+۶ c+]OFw#Vv6dvӒd2`EW1 w뇥 Ֆ䮎pr@zv*vW.CIl\ )_VN\Γz/3PO'2 5_$Lۮ󔨣vbݬ1,k ݙ:)uFn΍iѝZ/z lv *l]^um֊ɰՊgF2=+je6 j[[**T듍ovYǹzw:ӵbmpn]kNh8`04)Y_oKk)dj&VU>U]7r媅fݧ t2K[IL$.{J\U!uug1SvVaT~!Bz{Xw脔A'j{dOK]ݝoq=dXOH7tޫڹµcSdBءL_Eܳ]m|:NtcכyLU!Z`˴ÝfZܗEm/:/= !kȣ`ۨ ZEdCa8qi Rfu hƚ~_[A 75g%Uw=[h,PGOi-e]N.|D՘0z5 iɄE$C.6ꌸ/cBV"Żn05`\2]a ki;Ɓk:W;7 Ds pvLobuޚX:xMXmXpp.{6_CnbwT?t;-WcҔ\ gj ꬂ-jt (EKÃ;:wQč[P\V5rnP4l4Άжӝ!onV"FEԡV !xuo+e v4+K1$;0FԹ*5ܕo"]>oL=9ӚͲ,ͻ[WK2]{lef5&_v( =zѩgzuo:z F =wIViwBXJaeY_ ΎuL\Rfa{1^YXQǏM͔bzhOsB7яL#cU'5QJ0xRw% cjF;Ƈ;!YK <5:x5aI=ܾKQt2N6^{Fյ1˶MOHUھ+s;9eT'apmL HXӡAMn]fvo^𮭂wc)mZ۰p d/jFB GהR6.̗ت.WӲLڐ۷ȬJ!n'rK#6p!q=@Mf3X6kYVv7NĸFvT/S5e-Faxsro8n-;8\QÖi]&d:λft[;VMkyit2 nftHKIج9_fwۦ*QDpԭg+Q1# QMm.9ضϱV `n @cWa+T"TyLVΕeiUNye =Zp ڐJVC[Pc@ c3j*e[{qI06`yK zw"gmJt1MA-vA y>C$k77 If#f3}@;mHWE-!Y(XÝYN`pn: 7i̝ )hhm  zY nX4{J.Ό&mo>6=ffW5&!Y[uV杁n`&U$ , =ǦQ+>z+%8 91(?u}NaBo?ߊWi;K@,1SR?3 ?TA ?! G5MN^*o?o; Ō>oy`luij-7Ҷߪ/L9HfI=߼rt3Zδ˟LWW|`ocj98O38?<B s,IpHΧ a8moeG;%ۣ'sJ`` )o-n>|Q%.W<ً/m%^Ӷ5Z#Hmo\[bu<6z"X}:f/qZw?^v}zBlz1GhvT~1Eۧuiei>ٳ\2y?<}>_TW)u-8B6ҙAW I~m/'OM|Y$H;Y;xNV-<绳8ӯ_lKkSfŮA;DƘyAc=v5R@,>XQh_>{E'e?jJﳮ^7%+,M523K\Ӑrg17oۤIӞ<Lj\,s؝ၛᄐb O+bBE_+~[w5˃F,mm[xHoye$2 gXx1)~+ZwJzh.rK8~U{j=tk|^]M~J[ߤj\kE׈wy?XYӨ|3I;Y3RqXcj):C-؎X]A>>ˆH8ʺL,[{/V<#qXѲں mHU$IL{Y떦.J )խ!#euLcpvCI3h]MXbցESV"5\~XjH5KG:ҜVlOv哏BdkF< MTM!9{1*V#ЍѪ3!$ZD5JJUa =ҧxYԲ!' w_՘ {3cO G/tntgIŊy}}`kf_ˉg9y |#M&e}:dK_-dYϝ6ѷOPC63燹=TM}?W|s$TMp~}#'1Us,#fw)սg6Q&'Gqx[7xů}cOH#Zc$Һ+'f)6>0~"#-$ÈN54 !eI9ȗ#Жe:- yts-ߞ6/KS@iO^}b<|\hdD>v4[̉tn4_v+>j4K:@3FV8?3jq' iizke828] jw/Koa}%;acrWbǕxj=0?]m;M9t2T:/k[\GUNV@˩ld1}bרּ,nºڤ E9+ ח?z,9x nb"ac,x{\^ْtu)&<Guu!r$+>0jXB~~r>ɯ&AZʫ1V_ؚ^Uf/I%w9@JFSreT1w/H\sϹ6H2Fٶ)TWՋ&C#v߫G?e N'8_ D*X:qoEz9eFzVQu:WRvaZIO3)ڡb+e}&x}{ԂXm ^ +%zXvC.P>jbS))e#^-b;79* .>QZqҹ:mK5|Fʞt*9S}U4t{;f%JE-⭷4baz~nݢN>_ I$\%R]3 N)w :O")*s,y&@܎xYa}6vKixϚ1X F,YYEq4#A5$M=dt)(~ч wv|9/`4wQדް]Qϼ b](Oo.|X<$GRnSLd7ܾcBʾ2? Wꑫ %.2jW΢j>Igr]&lvU>z&aVSQKCr21z6x*#Cwݔ'j-}w|)d436Ӓ:EuOi![#x彺]72y'ػt"N$3yG ]~䴊.bwJT'V+/nr 5dv2 -swT#!DwѡG?F2(|7 (ݠ2}[cD\;B!KqeU|!86VŞr-Lf}tzq>BK0m-F1Rf[dcMdGʙўa7ieY,phÂͭ`2ϼGo2'Y*!m֞#ߴS(ܩ?Y{7u=gٿk$v蚾G {zey|WU׭\dllWlzr[H'=͖nJ:/gS(h~M >UjjX|~x2qLН(JA=f bIdso(iйXsK07xf/;(S-@΁GCz!Els=ޚP`SXA FO}/l~{4#|6ȏV[}`ctVKIt('<_JGcW|:F.yy1yC/԰0gNWBx*?dZxj.~%B`A&&wLal̷%+14މ$ /vЇ8g *)h -#GS:KG5S$cO,>F~S;Q?hWG.5~rY,6`cLMj[/ *=b$%X'h)9?wFnD;Ot,6R-:{&_H2g(ָ7/̥];!ֱЃ?~;Qϖ~3y\&Mj ~,`L.B%HfWOSdÒv;`~{<>Z1ϾGן#}q9ןEۓ7l@Y>:%ʾwZ:w&ʗ8U8ƨ^DNj^>i)oƚ3`Qّ9ye.J*o$yXek,DCIq\j6)/ǟ0<T'_1C';OhEǹ $†b|p|9*F=6О%CMM<8vn +[IǨzf:NJA/PZ23g7! N_s'O{M/@$t_n sN7>`7Q<ej}i6f÷H:{%㎼YON$+=Y/_^Ny:2 {Ľyv1FGK~ѓ9Oe/ wr; Kmi)TW`ϬمdT*{R,WŜܺkioT%ޜͷI_76?srב-uζnnMXaIZ "5U * OfgS dgWW:tI_9KA\9-$;رć?6W!itìE#jӘs[:IbEwc98Z5rk\h B_ʯ(]ϐ;LZg\F$?hr oAj֩Iݺ_6=F鲉n]0f>+Ln1hﺝMې[8pc}@.޿=!!ߵG$]4l)B s4}BOL.S:|~}Y<zӚ&"@[d]Zƾӵ8>37g𷯦fDP59눜g ɱFkGV 4#^zxhN2$S%|~$KJVR:߄l r@Q~;# <}u3:K]ފL厒*˛6}rE1wTW~fՒ:5ؾ2=:(i٣h9 5'OeZ>E.?\5Lڳ4 +Db%ElF="[oO_ Tٓɩiv4l 95M"s^m6Gy1ن?zsoziRzGB}v]nq`jW%A)kӖ 8;f7EGh4AQN "7$/ Mc(iגLKDUt)|+w6 lފ]X1"rG~.ԯz9d wDrݢ>3rćuG^mm%p,t뮡+0{]SZ1ˏ>zᚖ<2&fvܝ !F~2fM?Gm;ئ^/pĤ6TG4@ںˆZt\uBy? SEY(TU qyJ83r& Q9/~]ҳWWu>x_n\Ƅɥ?Q`=nM]\k2]Vm>*2]Mze Ҁ6닮Zl^; c\ k x{Kq9ߦIXn߾HOՑW=}3 (c@-;>n$HLvWB 6=RUN0a`I13a³tT?R޿}usgc)\|-}m,wۺ;#k{C11~X^LuU'_]Nr%F}lmy̝JtDo?'|qyGSgvJYdǺv=+)jO}uu &nձO a,Lr]Śr+gk_1HX4H٤jS^h:8/vaK)P÷sfÃ;γkM&ewfE|s`-ǔ*Cypnuߍ)мV7߾5t-AS@Llc/oMMGA&A?3 (3"l3+,P6ȰuC/)V<]jo:ٕKZJe)N wuDn# .Rşz$,}i1p G܈_ډpjz]b{[J+o6WvCnŁ}(jwpꐴ1 D3 scr0+ӏ*G{z sD};'̣O}pzhe+~!'Gx~Z%zŒA51v3t@61^N7Qūm2tv${)/{BFCHtfX{LácyYSHO a?(؟۠)GήO[.ORYôYzk;0Vg3(XME= WLE^+ ~pGl{t$M\l\_coj98Og3ztxkt%MV7UW2w*>OHU@, }7e'Gڜi}'sær ǭ i]ϑr\<>ruR&cyHGiLņʢ4K>q}&b zi;4K>u)O\eOJ}Y"UF)/ ne2H@`d|S̅2']Ő1Tg}Lm4DQ3Ͽ6]#j$y1 =ul-D&k-rg:SV G:zOH7g]7kH ~"Ө|vjQkc.ZH{UQAܧ&?fu  W$]"1O[y6uaլ191;2'ygE. (L >H\IBi6->[Cr#}_&1S/bdf0ΓV#>`]<=`4gFޕs̏ />u.yn~#RڮO‚HQ9} KKx$W)w/R9 T<{Wt+`Hzoe:o>=O:f_L x7 8y=pI})Ӽ={-pisqF$Q2 s;_qm/Q=3N~!^; 󟮚քSjV/0Xy_Ά9<ߺkh=1 y/a|Q({T{\nc*Ʃ}gF%۝G<߷d6L_&?[˾}*G[+Dzs8bsWÊdRJ%5JW{XF?ޣNr`SJ%ZCgkHL{zڭszG:$ݧN=64δ{u5vGS˳ӠTi,zort@=DR KM}+~.ڽ5>W\WY$WWJ2>d[J%Y^BgCb)3]1 ^ei., tD;//x5 g :|1sT]˅Ƀ(v7s/\<vI-2`߰Cvbs&m<5<9`xg5[’E O\Xr\Ӳmqt{L_űJz{^2§&9N-o5u)7V)5]j_'OW=oJ[:iD|^<醾! ̿=; ~  NRQU{Ju xqqgU_zt]Bse$ځz*VzFZ>+ʘͦjq0=wNa#DءFSb.ZW 17.K+\忽bqP+R<{i7b'9=2;u3e`CKٚF}?oڎ| l0wUuR:Y>; ]՚h/'@Tǵgk[~=ZQ*55dDGHg󾳟²rLS:V^"$ԇRV8FYdB$ek}߲m &>ސmGㅗH;nxVɜŅtXcGy>$nuvT!C&f27ǒIQ֮'c~ئShm=U>twnTϻm ԩS6,3NE^Le@;\( r\rOZ辨I_QxMb p&6|K-<`5'kGĆ:է(]y=!ӖS{ҠY~I}͠~^NmZ~-Q}77Og>JCG3{tz;ٮ6cSQ@BlC dv'aN;^zDhδSsZزqnqK)=c~׫{"g /TaG:i|cZn11e}*vO*X 8g~!rG`Cpu$o9%9lF QϸUi=\sK'FU군Цwtgkx?n*f0 ǝ؆S>8郡w=I'f2=m-3uv\?uN+prM07qe->9]9.iuIbz[0uV4v , Aҋ w^&\@?Ę}/jtIx+[ܙo9xJ>ljSNdg d$&(6h׺!^[|r*Zc\a1%#3>+`DQwܬtKT9fI/7Fj~%|OfQL('`vo[7O#x_(e/=Km^|^˒?>|9U!eesZbfy2Q6zjJrMkigN]ts 䊗f Z6p Y3%!*V&ɥF82Rf$PU9$Z]A7'%B{eN3m͑ he<)!""3kToޯ׼-IZy%@c,Au'd-T~hjL/Z}eZa BznL~v_m]ozTW7uj2gSCK$_7S-I"-kļ7q%DDޔou*Xn@VsJ"V0C>v5]ӐoSer;:1Mkb'n='M~,"t:P(cew952{BF~sgв(yQk ^nuft|U'Y(UBMWjE/%7-N9URJưL{ﶷWK|_T`;Dc򷷂o~G.eÿkuJ-ݦ}&b{m>bxdL^ {<: Wk6-\҄^hJE,`xOps|}W*}2E{PɭaCNJ㘟<5}}V{Rh!%gۡx^$v4g]LOޓHq DEi)ѶW;>Jv*_ʟDMZXC?~ӿ^^@]=}߹oѮpUjEu uJ*qv3婌=9Ͼۯ<H-2YߛYc؎.-: JԎ6rdoh\~85K|4Iz'䔯ht O:wMK;K_^(#C_~("$h"ڗ<r4'Cbo^OŅ2Ph G6=> {^kVS#CS@vgΉo 8˚'Q 9 7Y¶}xJ~{'ai]IQԇ(ه;Q<$|f7o#9=|v\Hh11 KSz\K*)ISd9;<LnʦO^/bBA,/;M.w}byu1(ϘޔLtI`WތK,nAoV;;6C ȕxԥH{5 -DfhDd^+x|91EOЦ<ΝS %5qm&}=v2KzN.FW1eCQ{uI'T,"]%eUcfz)1IDMyNm}C;'W;E\[㿙u a6"j2#G֩(5lL>&#y\˭oGE ?͖_{{I< [!0kSOѮ{R87=b{-NJҋ;+97z<Dɛu%!'>O>?j>3 TeFf>c;zg- fFp)?}Nԏ$UKM_>7zoM 0j&>_}"S$LP~EaLIlpQ JN_F0\4꿝$4.Nk?1cz?cZ:G)ңȺߛ.AXSoZ=wҴdy Hs ݢE!wPOsCg%j&-<̆M`>Ýc4%cfƻ6}UF% MOeݿ,dˀLL5Jl"*~iI ­(_ )cS[m9G7^5g}G/n^wz*~ȣKXOq6{ FZm];tm^_Eiys2̚,4ouӒAߓ"Zrg&|ID|Եv^˲}uϵ]8<^nX'cou]?aW R{ܤdO蛥;L S{AEuw7t1%O}7wѥX+|swJi wG5ɆƳ?ytjԍW~(SBr`|}V9E3})1* 9$s#?%;$as;f޼ј $)ti7˻n1{a}۹JN=Pv_E6f|Uk""]ϔ(JGBXF`:VeaW!O_lBmK#JbPFeຊIYMxddxꝽ;ғӷas2ݲG0Kbx^Cў1z?6cqk8/(A ETyL&c%}==:7.o'Z&~]\PqxsIӹ]~%;`櫿9j;_mʥsڈ7[1pzN &׽S(IYdaե:k`i˻ncSI :C;ZN^6ԳVjyƧC]U޼v+Q\QDd4SW_ ~5';x탃q-î_Es\qLVYCՈ*/>ߒlDzG'f6b}>B}S̊xI!'liHI8 We/Jr̮vCB7.YOlfߣXqa y4YANt9;F.v[TPIGCj8\(gX-{KNA.> tWz#NcJ莗<ΓolA(J\%s!Q*\3G_q)l|nRI`(c}@:9=>yfΥ(v^1ĒFVT9gE9ޭo5.[?P>߳l53{#sdоOoϪHz%;ɿ$+_F~h)#7iZq:{ź93-*hz*HO O-)v2\:gtGLӀ Ꞻh)n`~QU<~F'oq=r}pSTÎ ރ5v٤sP1e|}1C=LuO#GDоw''#|%?GάTxfYWeERW.:dzՐ Wxo*hlI*ɾS2e}i~4)Lp0* +EjL]^xNa'3¸)AW:Ǟ6tʝ'|B?9Q nNf#,'=\c]ASf/!ARyUWINBrӏZVz{?wݓC8GX(!}n}'WGZX>|V%122tnT 뺄8ϧ#H'f'*C)Ϥvd`U|h{&iq㐣,`umzǷ,oRX/*J̘GTz1+ƏD7=ш垤vG~$4+c{~dZIp ♔iC 'Ha_7b3s{-B%/#ԸZe(}Kg7`uWx]P;e480دxTH0`zn`bi}j|}/$-T_*7!Ψ6ؓ^XFj/6UW3x̾_ziQU:"*䈗߱vӿ~kݪ5ryW3T36Kr\|Mw|ZU,eVOl.WpWg'RfzxJ%\ :m:-*p_YDM̼eVf\1A1ObG|6c ^`m:[] Z^|x?ua㽫4nnU4Y%}ϙ=pdYWUA̶+}>]t Zz?ZGx3{f=y6."ϒ+Yjv{W2B>Vf&űxv&i2Mq6P D{3B/Zrj3^Eޙ]v.p'NnPc9+|[CcW[;R1r~Nn;ru^qk9#|'n&2ۮsWV`vʦ!4W+EMΟu &c;5)`xaFK05l'7Q3+=4y\e/(;SIWʔO7wts$Ǵ7l%uYy;}99[{zto5'¦0GǮi{:ޛٽgۍoC ՙ$kl,mVpSxW̡JP3 ;t#&ofd [N#b+FӋs8Ց"mh)|n`h&2e-[=u`+6 G2+v+?ԾQ4!03fzv'~hn5|;cg(%d J7?>2*uK)=yZgx[-DivxCԊ4weODen9X9XǬ.|#y͞Qc msFR;GprMA֎߬;kBQ{Gfoh.,-L8|&VDZS!f[)z8LͪiH[K4I5h{?y STm3 @t){h?V8ޯ=uA~4ǒPrʽ9Y =,iCMQi*1;bRs=Ӭ`gգ0d RcH;cp7$u"1dj3Q8dAH#lF,\.FCy*ǜ!5T竕Iu[z9}ݗXn z#,-JHAt/`Rf߆kHAk^^^:Vn%R`(5 *«z{*2Ken'9ftIJw̛T&tӽ;8_L|Iё|yz_%T;jN5^dt=d{.QLw5TQ<@_L򧯗JW2\cdΤ+V%bG>鶳qI15o4e632yҺ~m)Emd"uKXR[W,{ >t)K#fOG 9Zk8ys]%döjZ~qI8|8~##hzCͷᆭdOݶcJr߿_q]YdGF?}3O~g(Xm3y Uv Sq/`b)J>\sG+e1zU-vfQ}U}voٓyǙ=*k<\;}g/ͺ9ߧ^#l0oï{[ez@W#j"v3k5Ym3l9!~ 韽04>/-JdV~X= td8PQlR\F7UXUt~ Zsx%Fr0{u2N}uAU3e׽ %g7ӾCbxqzHgy}=AWW؆dS'c'~99!3RP J }Ry ϸsʷY-G(d_׫`E=p|Qx$eJܖcr1|u각Z IMuhv!i|*d~ m_BG~2 %=-ی36Rkn{»OX7o(ʴxWɊT=>ҟBx*ZoSlt+3K zH=pN佧֔wRϩe]Zd1v&I.K'`,>E=[4+)w>RA?-kɽ`YۤIA(q-M~VݴuY{ t~d};=\LZ{T^פT+b:muRAaƛo^䃔U'RaP)ȃ7衻gT~6T'ڞa1"m{Y%k#>q!\|Mh|kj6n[?}Oҟ=kIO~% y)xt/@ F%|0M?s".U`G"﬎wƅ'yw=§ڙuMRG*d_(+Vfm 2~&KkaۻcLzgQ9YQsw;s龗WT)_bsR芗&0=LWr "6eE {c5{XX\r1BȀԏO_Hyn5ozҮz\uF7Ӟ'U5żR_DkyrLZNqL>ix"L=l,FV7grBҭɺBr[z˼ c'okOkδh/CPt#юZ]TuIS&MMUwYPwˢua'kۤsq:yLL] 7I'ˇVQɫolƄ#cn^}>do}}uZ?zą0 n`O1ۃ3lu9$Uè9J9WPD`><U3I][?[oL}tYM^E8K<`KLfB:5wħqdAvNX7͒U!2~ < 5ĥG,kJASN.ymgIWf|ɩ{i{}:W(`SM79-YeMLR):)0]}f^^/%Mzp!&>xR%g. tV1w䘗ygֽd>msr,Y-pZ7}D/=73:_=0 +*TooU~8JVyTgo(|SeMǯLS?Eoo=s-,OKVm7'^PATtUo)Yw))tjskOo~>4uD'>^S|GRcDv#] < r(KD'5>M)!6ߚgG/P$G{v[Ia!ԫMdvk(;dID];O_"nruا ^V<;"[ck$PzsØ;)E^)=v]!VΉE6l#V.V"G:;\..fl1Эf ]{U(kGQZ9( 9UƘ^*Cߝ=x[~Ȩ8dm?LvˤVV} zt%wl⥏uז-V;OCIXwdȃ91eff[cRwzk9QeQ~y*:5]*6U_xX=9D2hrW1FU'Y8ye}mR1=/gR,ӈZ:gj>z;qG[Nyg~$)_Qڞ8HqmA^LGxSQ٘n;p#xb~$~CoxWt5f DӢ6WR70?Q?-v#.[].=W]o$Dz5`xыKrx=fחPz}1=dj8:_$SZp~YK cyԿ׽M|IZ%c-!FoBN͒3~dy~qXA=$oy9Pţߔw6]ӕo~yo-p+{XgX'M24~[ -xp'ݸ¾= +մa1e OA7J#Я̡ tDꄷMiTT'Ku ~nX:hlkFI+iL3MmDF+iPѷC!CxӕF|=}mtjѤ(ӤhDc6NvcsbqZbKS<:{snG)wm]/.pjVz2K9vc|s2u_MeˣmKݭߧT&mc_Ww/I5f_␝L<-`=8h?_sݛwY/b"vߖhgۇIZMC犤#7e+|7 Q(tsy\ΝrWuo3o{2w#mA$>Qs:/r6[dW(?i~:%!CH, U%#hq "Ϥ F{bwnm10xTse\ةp2\ d? 3Ns;.w\\f*n!K~uίkgw"ڍ{ `}8˯Mݗ y )vaāLM%wXb;7ypovx G;Y" ; qt]o-+lVd;P =c,3E;# mJG.s5Ak~;;Jbэ]7 rCӯTv\)%n|jsh}nV?G54ͷ,9Fs/Vpfk9sw)v88P?N選؟Uw6!i87[ʺI1ki:ITfgA @> 2c_rЫ鯌,R%)#GͰ;?디hA:Of0~VjYJbzOpmlc"5xyu%L_!9}Z0aU—\m>f^A4D€:-Y)x]9lXLf7^.l>F[>o]]=l.hbZ#j㽮HRꡝ';i3_~-EG*y˚IQ`=.zޝ=},' ُ1|LG]u[{2J=,'qL;R>?K!*b繛 gIto39{'(k5[c\.jEFz>/rSWjb@ӼZ| >Jіh&99c.u 7M#z|?kyD3f w},[PkNюE684ƮB\ĮCjtnw~ǎhyxN V]rg=1)Ls3cn}X(Tzywk':հ_~xC==thh&JzYSb_V90w#qź )/ܑwl9U6ѕ,X]j΅zM1"W6c#\Уn\K2I3=]?{]-|hJ3{K~'Ms${/3ӿ#3R)n*u8õ~1IYTMwp8?+\[ԵX^ʫB.&ٝ$W̪}+LtCK\GI[ŗay9+WJC2mHL6kwSfq){L:ԁJo .,% ?$jĐ =gs&}=fjW#x.Fv8;xb:y۞}-ߢ$վB 힩n̡ފ~EXwYrq㵕CʞR7_l|W Jqsm``4G^M v@^fΌT䲾vw5'* |o/N}@vx1AepW!xywol:l*5 y= \0Dz%Ml1\ta޷}G8r˿F/Ww\٣Q7K_c $n=R: N. *0{|>;6{F|KT}ւ(Je@\idIbvLaMҎ|x*޵c8o0LTO ےLJot`,c^6}\ȶnl$Myai6rnbs$5.j}ɧ+cN5IE|\Y73߸4ݶLT>˂o .*a|]_CQ1RG ƪ/1b%Ŏ#`9=[IWq+]JXƚrpj2^rtK~a+FrڊXǒvnOT >7EŢ/뻬Pky3OMAbvuxUny?}_g|rj'gYo~o"ti^$amDiTnx ٌf#F7_fX+iWƏCѴG86?7/dF^-K ddn#]d!B=˯v)iUtڗ8iWd<Qc~)O%~O9&F^;&7ۯ.Pyu@o$޼0둥DJbxs-/$5CZ397}_ԣ̽jvcgOa5yGt}FO$1.EO/~6.ՈD[:f4zˍ੼uu H<\!rƁ/n oL֋/kWMo EIRXP|HpZ-"χnKrT¿+wP i.߾|*]bNJrLyʹTD7G^ط]4Nar*8`,|+ `iGoR6Jx7SXƻWC=f meϙOk-<*O5:Q)o4%֍=gujĈ'K-j.*iD{qIݭ-j"75߬D2QDJ?)5_kJBy7ro'q })-^GT)ܘi4@xh^2/O'Aae$g:RLE-a7Q5VCZl&oŐkpW%XǀbwR{W|9,;TՇfq&[oykG%AT1wG4yæWPHr?-I*=RcHWNQx/Ύ0/9L+ľ{@{+vgHܛƟ1MTƟHǕ~VFimLlE.C+u2׊򞘚V&{䲙n4YO10v1gmG=j~Q; —f&ThnF@LjNj\u@U7{QW՚j_obn_l#lz.߻a>i*$Mzt /Dï,č=-Gήo/7Zߥ~͕+|}vF('Y*3n*Gp3ˑؐ J&:c̩NZRCdCzlFZ9!2U|gYveR94oNVs]U')")hGR҇#~8٭+Ѕ,ҕҺLwTu&EƌqUMɏ Ԇ*!i?v$Q呭FhZ _6$ k_GZoɑ~?i"#zϛ4b6C]#Lp`d? Sղz~Wu='r\6 >'oK=q\ Nq{uYid Ng"㡯)sue<(.-JtkDK2R@Oji?mY!YM{=D\7j3w)r5_%z9UBzlup5O}ggڛihI?TTJ͡J.;kbRe?7#vJmүS]Zk˂uOA*OcocO" *LA:oeL3*(T(VOqYT( q%j' .{Xq9Z*%Qy 6'nZ]68F¤!3>Y9WcJҗnBR&y/FP̰QIm}ZUH?aŒ?sT_YBD Gzjq__̼,6 \[iRX(yf7H`s_)mr\&[Q'w:[?LJkFm1يV0l7]].dCEe vۃD}߿0X㢽[vr1]ʛte'QD99G&e>:~e{&ɧ{6 !3>.z՟rvj*kwљg ZSJ=q83-u Cj h|ݼHV(IDAA5? R'p%yŰN7J)K5Bt fWr~L Ffg$^78)š:Ynz>a<ra#\S>,}7^1u IN>7>{xWoc8nR cxnF{PChdd ɭ]Ȭ^&W5l:3q/x-Kt>^n|x"aO.8̇vgMgX#}qぃzL}#߳W%7AsA_5T nGܤ$\e1NJz8߸`cVP׆TT;C%}uq)mG][]7O>j~3 @Tg/-ዲ% H#LG$¢ޢSTuՃ=lxKT977iJZƖ;73EHH`4V˶Cr _y_t^A),'ieRjF6nODykӓ4?aNL2]<-;ͩUɠǗgVYk˽I|0məRhwl\:ގF}zyAxf:ẋڼԕ<=[[O̢\In'ۿ4bKgj'7M_$v2ٓ!کؾ8hZ O;ښGF/;EW1f n.ա&NBg):=ciFңP6K1X5$wxhTxki. #V'kZRhΏ|);IDvKo[0zEQO<VꬓgB#LjmߡV!Lqi[&nKbK񰘻ו2w?>rt˴:[2m蟹r>\'%nPuƀt=ܷ> I4ǒb#[GNwx ^/'fN*: ;I$PkPsX w8Qc&sԯf*\JI^uF_VԥoP*杻JýgxFttRALhv7~OD^B0+'%b(mHR(o><Ռ7Z=v0/VoJt$92zJ8Pϒ7kq6V#E3rVFx<іCe'V>/vhqZ,F"vNJL[~^m Wφg\#ɾ=09ZnA?YcĠ@MX>?/KNjq *Yv5Bp&Z?8ꚴ̳ ڟmvE.;Xd'VJ_YWtfZzɷOx/ƧNꑤL1Yz1R;7պa\ȪM`k}7x/^-Tgv/2̗pH;ukت%qSrM0V*AgnEOgWfɚ_"G{#Lk _q[P&ޏ87Tv.&K=(n5)xH2k^^нxG0l Ya눣3^1n/ 6:? ao8G<71׼tM;|{v'|N^,)'P1|#ljAtC}?QkAaOJ.j7jބwE.Hd~AH1to˚"'ujXq*zki|9 [1#bc{) d#/JswϯTDWn̓>)xMi#3Gd{榍İ"|5D?Q0o0;aZ28juViI6:S"7^^~h*ǁdJ$g$0vV}\J}fwBX/O"lj6M-! FBGUԻRU2εx30QK}gIpl09f+<:R\H5!Cʒq$]] 34is}QOv*]ſhiaUIX&)syU-Sޭn^ՉޟܑLP#n_7)G]zBEf]{7#'\5ug>}%RBK)33 ] JE}SBF*sY/_qҐ3Yt6|j'O|ɬOM K:~Lu9yObV{f'=Te}"n|,)ՆIYlryhO&pZGޯ]iIPF-6jZdkw+5/krT# f] zԥ6x{VJ21j&dbߍcS]3{a݆L(]_Y_cǮVt<d ƻ2d J0̛S7F!bGS0TxO޾96O>io-Nc=YԨݣ܌ֺOb-IY87 "\D#a^{iJ LLs1 %8_;-k6W$, xmғq/{x0bn{IԞ :7K|!"q8ߞt{~#}A4^EInrC=!:dR 3($tWv'}XQsEm_U_]1KspT?u/H0x=yjɦ zWZ 8.doH[\_A_l{^Ҙ5=C)%i~vKp~X_o}?u"=k9י|gPZļ4e迏Txf=Zd.5oU/f9sۻ#əU괿QK&"Z㣞)z^{)^ӝd)hLݖ9OO4ΖI)ƅOG4n̪~v pƇkK6#xk#/ZTIeLmm]n.ɶ!u8V0uwN\rWL 2^ a%A:H._LJ-f#EA}%b릩c_]}w~0 ]"2A>S{+u~)1$Bjbάxߟ N/Qr+Lepu7GaSPO_2nϕwE98aйz}('>^xַٚo~·ޢ0g(P7vzdカY\ #2r紎XEtAҊ3qf+IWD̪R%)&?5{U,=\Fu dk4k#f*y(˶a4S%(4\=>:5FzUȟf#Dq o%dJ74;#g򋩲[Gr8{bhUn~oA^ʶymLׄ& *em:>^狘t~FlOgAiJ3\p~ӣvڝ}>_FZ:8̧5SϮP(ʧsU.ʏ@Ptgᑾ\k% 3|lR$7E&3]R9 r$۽K<~=N FBPaчe2Qk.lt WKö́8ތN,-`4|=a~~$H>@+bg{R- ol⋶15EsVv9-AW~_K-0q%iWE'ktdns3f[:vȓn1!&\}9:knFl+#N}׈m c`gc+/j'/hI*@Wcq-^8SO^>L{%7ѷr1<.ރ5zٴo%_$xN VX/Q,L="ˠLzCJX˭tx}t 6֤J?é&>>=u}fï a#~EƷŲgyV Z^'01?tKcW3$F[ ;2d wc0 YG?fy0 I<ß}ף:tO=nCWGy]}1x]'u)`%ײZϹPevm@sxh9nfu5yD߮H,oTX7WA&Rf>{XT[+v-32Y3j:mzA.{.xڸN;C3)ZsطBn++g R1ɑ-!%;]eNYN9yfMoDܔZDU%b갏k7jS@~)?eOR_=3T(r;-ң>~-UcKXimZI.bɒdJٲx*sz+~#=է-{ ;̀gnb4gI >a)Z,jf;Aԛ/b? $?A QzLA6UCj1Ɏx%SOޏhRˑe}?_>iy*t7>kK+^'{g;Uqөm[g\JJ_kƎW.! ̙gorPSHpB7Sy&Ƞr=롴?c;RI7PX[/o,xh7s׿$>}NoQZ3s08$˱Uߕ7h4gXф>v;a&޻Ig'i}:Ll#?=TO|ĝy2j]SRu}:q o &z }VT- KIgQ"lKdEPV3V_YFAI mŎ~ZIVK?M1.}ޒ3y=y8Qs')v1m|ۺ81}7~Vʻ#P:k DՄU:VnA[zbGZ;b*= .ܥ8eM_kִ|~nnTQ×іǦ0PehФ|La~أ/8S!n@^a"7l==^"u~k|htmK?vB*Jb<nj>ձ|On+)TyF&֎{H,HserOI~nMZ~|x6 RQ`69LYO.7 `Ա1(UBh64XYU֊ZRZ26o#Jf&B }ьyroZU%E%_}Zƹ}.\#hHilfz9;:l󝹿Fm`}\F+om5{|`MqFUyI3(V+Lel{בv5cFk#aM,Ҟe]y:IUF+ܱݖ$sBиg\~i%0Z1=~`Wr۸?~hUF9?P>fyE{_;Cti,hYD]X % #gM2sճ?,W-}g,iB ;A+zH4{1.QeފN.OF&Cbc rY_`7NVI̴;uřy5~Ǎn|asCZּ#="BE;6+d~fe:+RVUoW FQPozWPGUQM$h,H~A.{Z*W0_ GFF(^uͬߏ@V#ȶPV) matIUo@'q|5 i9%:Gk.n ^}UoBDLe|~o<֯Wx~' bVͪ׹WĸgNcrLF=Dn=Ӧ)Cӊԉ2K\*7gAޮaᢜvW?k"=-KYP>}z}}uGsn;o*4?S<┧NmbpKo#]p٘SoH*i.w.]&!"7?<ɵ2Who9N_oϣNm U<$*{I_ e\wϢUm}G!ckpzLŐI>~B6R:_; ˇ,Edqi!X\u\ȼ>a wG]JBW&^M2hP%Gk߆d>a%!PVZdH4k;W6ތf.$reJ6-(-WUv?VWlU,+Z3O[-'$qmA5ߋl}accƩO+3Hmv"MuX(Atz*u7կ\ϯDuKh$z1BPS23,i-n=B8y{^Nv\'yO^R\9ois݌SP|M=a{ QR^) UW_X)nVT.GyKg/k-C68:Ι9tRs}fj)'q8ȘD\*HIJd P~h~;kQuN,ܺ&lf!Ȼ?e>ȩ %/٩o6/sM?&:Y2U~_L׾!Ɵ*IT˙wK:BHOS>Q5֡͛92_M0@~FBuO\E5Y8*t?Q;KI2Tv; UtQ#3_7)m:mk=eo>m=y5&ɵiꍬV_c?NQӳf%em\h?M r/ͺ–arfy3Hrǘ9oX lapü[@D9Ѩ}E1oop&ndgxlo̔{SR|}BKݬEar<+i39n/ sj({ &2Cvh ChU߆q6*ltkH-'nm=~_ђ"q{"pޙTU %gZg=|8m9Jħ^eݜtGroiz20/# b6ƳvqD ~w|#ZVhXsA׈Ir$xJb}EgRU~apkjem)ioB\%č:yMlj8șwcҍ+oz |64O ;u@7rtb{*ˇ=?SS)xx)%%/ss29jCQ%rܻg<*+LCA/2UFa>oACϺyu!7"7Oi,M\.I`rgj?Nd%=1I*هxHcJ5gleF74O)w0}d?X_| ~j7vhN[-k8ƴ m-qb] f8F1l<ze^W[ZM2!SuCi,kͽ3Iw :p >#fu''m>\k֝y%No.NI5(abys;X,_~9~\9YtwUSg?k!_+g6|'t]g΃50m+3`wKy ׄV%+]mıA/C6} L*R~qgyN~dB2"&dؖy:=}*>!ߘoЈƁ7;44}ٷUX~l=_}J{XPwT LP3S!U]dӲ3!THܡwG[wx;nb_ӽǾxZ,ϔӄW Ic{\g?ԅ}qKVmR~7P\씪x gݼ?off׫m%&߫`狧ei67o*LZ^@̇pQG*Ei%>4x}"8lCnJ\xq7o>’}|:~^J_@C%g@oouv1I,Onb.5s$+Rg/u(MСsExz{XDPHXw|tϤkpdENA'A60mKh?t6V]w~. @]ywhT%zȎU_u䞴w'EXheb ˖<;VǹM$Eu=ŨwYMM쿌6KY#*pE;C_=;%Q)(';qM`)S&5C9U'? 'uO{Z;DPG"-4)\;3QweeYpóUֽ~.trVa#7_GPDcB F(o+Ʉ_ͬ8us7ȏ c-E2z;۲H%#mDgvg[g% ),A}{ 8d3Mhs nͻ7yq#P\^ʼnhsC1#D&E8Y|R (oK|bjow{ũn`H^ޕB;0+D24}:+F-cY)cQ,.>[ u{=Qc*tȓ@{tV+{Xo׾}h޹X|\ҫQ-{hdqCg`Fܥ XWϛ8ɌXv_v{{uRQ'YvX3N_6-'FUSX-tRQMu"KMh|>|[/XDHG3#kpdڊ\l[z~ޙ=F{nƬ1\VT<2k Bv>%GuSv51\V]c4&O`Otݖ,Ĩ+~ xfP=Ɲl], G\s%j;ٮ)"Q;/arfoa&Ŗ6e1_g폯E؜+y8__Lխ1^˔_ihr_R9B(vxߞ_y &jl| ui_ƃw8jjߧI;_č+jy3% lH"dzΜ>H':YQ:,~5zg (o_d [=XdvrL20 7hл&ޤfalJM.{E#ªpշWn)"s5߳/\SQ\|2Tx U_R_,˟fj ֥~9HZ ճؑ)~0%HhK{,0tR ͗kSu";d7=`>Op\ߣM}/ԟ6wwRSӄn]%ﶾZ |(G8ˆ&l?ݹI{H#A|eI!kvv_ЀFڅw ی. {<0,XIELg2F~!T2?RtgGDH9-v*)r4bI'/>iY80J [Yv_L-ÄgHtՅş\AVO5_}|'4@6͙E_~"L+XdF"҄{5$9fQ述4ǐVzv{2+MiJN]|48_ޔDub^î]o?x.b2gfaq!v5qV{AEw3|prcsuX(W+"6,gqnY3tTzN>jy2_4n76 ]'.D>N=L'ZǝE 5OH(c UC((揬iF]syhd{r׶OܱS5jkA1Scosˤ4zϑ[ .GKh\:`0s}:>9X|GcOL?vך2xXe-/ dhL ?к 9+TQ;Pkuv>~\Frjb;9:܏qGE[Jc Ξd/D4%|(vtXT}|R Z Ib }o(pz#sRX#޵藏F.hL~?;v\Z~>KpA\g:~PVjW>J;S>>b:aUbyj!  xj[3=vb{l!&YFz0 ׹! p`3-Y43Czy ~tVOwݻW|^0hԃ*dtTA/R~i4KQTޏa~wٳE;Tˈ++䤄yk?f[wUT_?&!ϫ"1]֨ljoo5i,xQA6h;K,WKaMĬ+h"q[eVo2ݓQnI -h.ʐm"ld$YݫVYXH#Kd|!p-eƒUgF!؇@{2AVRyH\6DSKu-(e+k|yɞ"ϕ8Wwx%; J`.\\ZĠgwn\,`g2*4jzR%fO/H} f~%}7$|i V?t.VjW49aE޻6}ޞ5#դA>=m Sǹ.9>qcϷ8ڸhTeh*U^O<¾ދ/%MKZ+e?^X|R- iQcJ> UOL"DwavkwXC%NRWԑzչ&P8J]Fٚ_;$=D{掟9ZB^}2ˢ܌%z$D&U Y[VY;Th3eDb}X(ca8em*R2#4c8Gw|?H۱QN"ݹP;b`3<+ը`àޢ贆DZN>cBZ{%q]b%u{NǖmH'%wJCGCO<OW\ղP׺eۻ֙2[k-q+/}_BU)ъ_n^gF*arw Oe!Ga_^{ԢP!ou6fm,!{ d17ߚ8/uZc%sYn)rXt2 gMFnUڒC/?~U՛=QglN%~4flvD uڑKғ"߃{e[%II m˯q;L>6L׏֩-͊&[8$[Y䝤~&̹t.yD23=9d]ZtNsCD*qj6VH w(#D~|||wB_gޏ 'FK0^vo&,oSڄ2j}mK^JQ~{/Xj>޻|~tnGm7W_};}=>*l|Mw: MҚ+rKLi=op@ܥZCLK̝c|[-XCMeMvH猵G)/{h~Y6kj*^W˟]:c6%# eT9t=]j} >0[ZIP뛗Umݭb%b%Vo6Gd>3 J|RIKK8Rg%V&K2(*%#oN+dE[ӻQTXھmOX@~Gk7 ެ[);RG8]!9X|'ߛr^͹{̃ل<SMr{'|u)1]pN,Nzio,S%KhFKH:WT0suPwNdgpgSQG')_4UJ7YA]/ZE9S쐊9' =:}uŊtKg7ǜfCSg}YJe&򒣧\N#*?eHQzF>1ez*-a9˲^o~[2ï{naHy=i2M3掩򇸻YH*VI~b>Bջ[kv :wgI<^wl,z:.?;ND"B?09̴\݇)dSj 6|Y҈,=E>q'沵wikKpc´c4i&DZkʛ'twqT<]eU=^lY9do/kqfC2Y(ALwqanH; F@B,KW6 soՙ>&v16v-cȢHb" re[-ob b3=zh"uEi5vVuI3ODY9i1bv*T!FQB'sY<4ՈfK~qcXҧ]v%>T.펑X4 =1bSH/YLfd&x3IUg\K݆?SW4:\ttnEjauNJi\1r|J!=HD-w[npҥ6K ,;EHvK7p'gѴ>Ckrfz1ԑh9 <;Q() " EԷ J<e,5>Ý#L rd.,Ȃ 4]ׇ>br̖HI4҂!Ļ0sl'A٣2IPUoN fZ^bO xJGhUhdtKL gn:y^I_SvPGqq^ FFѪa4|-C]~s=$b]%LxYA6=- A >b,,$oecZ(<6^(mn׷o3L| RMGll؅my/X{Uu<ʢD&Ц>Es.9B=n ȟ) Ե5ǽ lm\9oN$ H .oQA>"jx1ebQn3'I)JjZ pC@6TCh/""Mota㲱(9 Ӂ!I5OXCOx]*| [@1I t34G "0/ [5E gO$4̰EF1YFe2Ms@(-q+, 5Il1=sƀ a`&eA)#SxR6DrwTB ؕ1Us%.&iB>$ixiEbۆDYoƴgQ# #Tղi21t \M!/r#Kn ,|QG5*#r-\LTG%QJ ԠDB^@P2Q@Mt4%" Pvp*hkB W jǀI23:'9x`cA{ E]0i^HY0uvLY@An03 Ex8 4eK \#aDRnfs%hƅSIBVcnxk߳j qVmDGqa -eBwbIJ@dՍ/ r@ez;b·CIU^ Kz bi#5I-iFaD3(fWfLz"XT:OVY{9a /Ynm]fAGޫ>R}-D U bROy{<_y˻a#.wޟ'ʓ׫MfaxF͗X`U.>{3]xA נ(FD01D$z@$)ө0QIκ3J(Y&ȓZj-}GXe~@܆@#@!V}Z[hzD![RH Q~o+Tm͝EG.I]4r/(N"1hZ\o"m)Z@iDز CTO +J-w7  3D |I^;}ܨtgvx}H^VE˞}Z$' 5l2.2 @I<@h#@񔏶|2:5!~(b!.}TYeWgvߖ5#~U#!-2> qiOHpy>%7dH'O5XYrqnӳF{ߝhM*!Ȣ<̨YB,GC`-K RNLz>FQ W|Cu vw|`ݓbytoyWgp^wa=\7s-smȃ#DzfHv|Pi}}*P^^'HP˸qlxS^@y^K>Q֢{@Ty3H4|ry4E2SH ("< {}&{ۉCNHOnqW6ӂalF N(; z9(q1h}V5+ yG HL,'ihrݯj@ad zG #DH A!Q< Ti:'5AOaqDlSqu,;+>6>g (DaL' @,`i 0Hg H 0@&أW/~AG||!윟>|]:P 4싓]FɬO$#S^!Da!Y}$ 0p g++s宫 lxA$MHQQϼ!8<ynlwܺC'_)Mi5O0oeh_%|č>ϙ'åyTut6e#؀dB #)$#V>-\΋>~p>F_7}O< xa0s &}jA4q3!#q%q5A_vU k@ꟽ{Q0@)?~)&8\MKDiOEm Y PHC;&a?3R= N2nA)0,$!j$IH@%g QPfB $ j| p@ #pr AgP! ^l&J"R&"Hקb=,}H@nH9AatJrOy0>>gqR9^<"KfQ |1 yi<KeA>$ "2AdrCB*!ğ"Ft8xf>7$QAϸD$x RC:|n,'j7(}R^ K5)Vj^7_Oav g_#yPv}߶drɡwrq4"H,%SY ;.$0DJ| sBX똔fC |Ǚ"-W58E *:mtHwMHPlF] #(4C5X*Ye4Bj#լ풀`ͺduF-c/W4TDnG! }mf%h!k#I-@l`"E~l%0A;)-QYHmxl8$eB(jW dCkA6AWr"'[ DMCDG̀  ITͪ' bVRc $\@T:npum1ezXzF 8TʨWI *,|e / "sf,`ڦl"ڢ( YeAHD2k,K8E! B؂ V-cM`̐Ȉ ?j50ܪF7PR*0"&up(acz|y=#A}REi1yEdRltÂڔX3@?20 ml2^GsU Qi#4 ڂ.$ &$w)A8U &.>NR@ +6`)s͂.5CEww?Bno[Ȩa";T!FX/$ [؆$ͪ 2@J I-ӆl4^q Bd6A {]"*Oj6F (,V}EB*HjIA sUuH}@FTj#aqm`Mj}'˙εGc6y>cSM%C+KERf1E!'@)|92h;8ɆRD$8B"0%"},*bi")6`Jaֆ Rҍ؃f^J?At@4IXte.8dYM )$ >'AJ!$N%lm00c΋g2!Ye 7V eXU DE9(̤H Hyıgΐ$zϬ1H!BvoK٣f={jFVKFYD2,EHqczEAX}DA`A\1D$}qZYDһ@IVM6#!C,AS2pDm"YDQ% ł-Ed'DY@9kGq;& 6{5Fes XS4(e߬kCd+jAYFsDa`eљv8v+{ \&vV>M8PgMșO1HL%N4b[|P3hꮶUʣ" dѾl mmasA,~dк Pr1`>sֲ%mpۻv|k}uESY c6=1x!ϦV:TyW1Wj9Jճ}dJ۶c/ٗ3kV |,;<b-jUp`H`K r]sLO%LTgq z?e[ - abL u U iJhȷ*3p9hC(NOMRAfH@KM_(wJiK9ܴ=[V9H{;& %rw =p#6%C$A&!I$Lx. `ZSڔ>sT %}HGQ"w6) (3:@\Iswz6Gu%+,ʿCo^yz3$V9GJٖcM{휆L}ˍ7c㝡jf9I{ј:gα^K+T_Y^絘 _fHu9+U#Tdtd"Nѓƨ qW+ :Pl 9BA-=&pC;a\A011hxH䊋bz UhT>IĶtGIЩ`:D]Rv;A3n>J.e!>&Cؐd@َu)HK}v=_9"vW$[ "CcbR!HAog=4C U`a9ՈŚzH6ϥf: &6a*L>]46{X+4r^=HΑ4y6_rrmmrxM}X! /MF>} 1𐘓F3> .%f}aM ޑF:[ 2h r#9S`X(6WJlKiV+ 3Z%l DE/NFZD#G6`$˨~8(BaֈGH%ZFxl64%M" a#l>ÝƇuN[n{q7CE_zCO4u*7`iӤA;YV:IM,kU!>61ᥣ%絛-Ejȗ[7zƈZhz' m¬,yp UӇ@v M2PҘ\7*P({MJ2i+D/0ޅsLQ{PWq:aW!s̊ 1ǵ$z^ }/3B3c$рaڔUl_P?\t #ERlqYBiH{ 8c2bnjY"$.nirzk AB NQ7b"pΛ;p`!Jk?7]ΏeLTA:A>Vrrnq8JXl0SBYp X&Ee<"uɫUd].qcݑ#vs2AfX &H$*Xq,Hɮ]G~9RC6PGӸ1l UKԶȒ'S$%AyW>" g~y(=8@%ѰW!+H'H80| +^Y$#tqrxk¸~\>G-(HUO"[cΩ4b&slnA)yw= %q"Y>A=(FO\1=0N޺zw14e,=x}:=A@|8ަA9kxc' T.ĤYl[1$a)*\w&<6>]{b;Hl!oڨu>1ŞHvu=آ-zȓ/z'bxƕ>BCTCl6߰bpa^JY,3y>q 5}%k&: gÏ!Oй*!6i'8x< N A͟f$.yn n#YiZC䝖P;˰c@{?#&;]J`CB@DеCBPкDc@-#6WP(vU?d!TͅRhH.윂&yC\'覍RRPkZcN^l;cC("|HLD H 5Tar 9<Ǜ<'hӣ-h^}y>QuP<8Є&YG̏/A7cC_'HQ_IOry?.H+~ܹvVZT% h4.9.A1|~/ 9rߙ4—0@ҁB@Z4h}s_~G'A'g_cu`NCW4}kO|)w Ey˝'/nO#?g1)<W2:G ֗l% P^]ݸ:AE=g{BhA.IE nNBStw;Ke G'v?`=@}j y:ICBPQ}OG'e QAO$ BBHZZ(P@B)Q &IA B'ȣ9 Hv]{޴4KQ{4t⦇r~lch;.Gw7xʐ0ry|nZI#Tn;*I;͠(䡣G!A˒@ppݴ`y>IwyPRNG;4|;/!r^E%Ovg̑!N~/nd*{v<~o>rgyalSFЖ|~!^Bւ$9 Rit/9(A/aȡFJyG^HJ';H-=Gy\4oxCUK>Bp{8r衛M^yiOt%?;e !ʚZG|}{<9/#~'m#]{~@=\^܏4r>#;0DU Kgxs. ?%B6y1ޝ0hr$/3ȼԧ|[ 4Q 9-)]iiB!]S@HJihP҉(;:кQt?.BP Tu=0\ݎI <]6ΐ5@~N#tb觞`? <纗J=&Ymx$P(A䔔s{<A䏐 @vPvM);Õ˓G9(G%6eäuʪvܽ{b6Zy;T%=BrMi(皾ݏ>|O%tE~^G#i RO {\?>4>Ik'ӆt/>)G|&w>#_?dVCCGrxm) *5!{!T4!\9! 9r(y"|Hv=(|ң "h y1/G!{=; @?{~ܔa䜓}_JJ;'d"(j > B "Hgb%?4rZ~{kHj;|| (Ã矿?{1|Cox>_'w=gy >[~.PH-~*~o8} Mi!;4%.P#H{riNBjhd(AhD҅ @).!Мڗ{~/y>ܗ†%7}}w9r /$9~R]sh9RrQeҍ+T!HRdy4  #HJ44"9 W'$V 耚*kc4 kuggۛ(*Gקޓa?-E-(?-5ۜ.) \PDI@B"\5O4'U xvocMEqyqa Z#uyzMǟ \i3z >s;^"4bY}#^96jae ;dByơn/__c+f^k|` *Tb;\GoVP>OWa6Ꮴ*}Y<BAdp۫"CdO1VEdm@CGt@H*M*ʳ2!-V" >"p`3aȞuPܹuhF]oPU`9 deʼ©S] gj*}73F)] JY+Ek] s7U6[eAJ6#S&./:[Wv۩j"D<RhPլzȌ>1 &Z P`0e262ˢbۈDC#1TYLalCPPPMY͊Nr Xx|( S(>g07*]H+evQ@s鉉 GB}-Hȡg,}vX&^}Hkhmosۺiރrvk _AGƫex@UJ0 Xl.2[VCli0gnƐfX G8H%1DP!:bRr#C/Vnr`"s''Z>)qFҗks'ઍql݈QH[|='ۊeex<[QQ ϼv1ΒWy}{I\DwEu X.иȽ n2qW#TV`k8^t="7qȍ~EqW.h81X{mK;0'ӼԨBaBP8F=0sjprj*TV;&Zs]QuKSF2oiq^ "R@jyd.[]7"J#)ML JdxuW;E$i&6bXyNT>) R=B:tNIX6E' E;eAhx@%qTbxgPGjۡ }F>+ G߽ٞ*$EZ9s̗:#M u1F%9-AKH#PeMG+[}>CRwM3൝u鄻\-v{vxc{#",YSg`UT-C2=cz GNA(|q n5"[Qdv% }lE-.x8;hp vkxqr\#g=yP}`/iuh-@iVlCe@ԗ3YB*PuĆ38%Ĩ%nċo ] ͱWqޣBpW|%$]6oOx ȃ`M/)Y❇O T"̞3c9cۻrvE|eETyf1ý~窟ܵWgA5'"&cη҄{e>?A\tl ѡtr ,D,(`yБAS-i7yHG\,xD C'b S̝N Z8.; h EjjXHKn0!W tV( @gNE yY2!GhbqfzkD]8!ŘΛ'qDTFZ:訪୉}>Z â,liN ƠР@X]ۦI:|  l9[<+WlVU7&Wy b_&`AB-#8V:^0c`LUQTAHH/A=<<]()99{y|CMym2Pv_HGKȒHbU0Ҩ {C_ WQć .l|< cy~rZߘ}Io2/ vМv\<8~w#))9>݃ͨ*gcEoBkg{4J)Кv(9/̀J䮔rQKB!) i$O<kws퓱{}\+yġ;9gy xx7/nƎۻc[< JԾ_avg¥'r-#KAM/gw/{ISCl6P{ӁDyߜC۵ {Wߙ\r/1-y8:;g|·9S%9ܝ'󻗤r`AG'~H-M Ph CH{ RrMvݗhC(4~H'FJy ϙW:B @C!z !b*5$2 2Y|=C@*ӪVE$$ϐl@L;W9:ݔ/\P+O9n6w ɯ}op!9- DPd.)s%ykגv>Ch{|qv4kTڿ$/2w̽=) El ;)V9r(䁤(C)< +;(.{v.Y?{,{{//ngN<&6$^&;i6_c{=h_N@ = /c1 44W]ˑ9gT?}󗚨|1[y}b?/^o'E\؋awgEDדWNv` 6i~ܻb=O{痞 |$9o6{r8ABb#CmICI=y>윀ʒw4u+041~;{:"D)V_![AB_(@{/~I[77/!V\$c'/yy &rѧ4ZFcwnwE<[hA!_gyG켍v7:Ui553o˄JCM$H2 ]@144~^{0}<@^A i` "i@ÒI QĂ_2pbkwM v({P?{#!  Z>ݻМCJy <ɹJvE(C~u~G$[Xh˓yk~tڡ5绑AvvCZo⍳_<G\H $`LM p'W6\8 ^`R]vZ]'n( wr5A}|A_=$}yĠZ_+e(JZSuC`4 %% -@sƼ"[h I$Dd #K2a0A>I 4" GH|fP k h 4|r_.ȮN'$4txםH ZȲO0|K=.ݏ)B) \yh(G=44laccF% Vۜ]5OnZsW@Zx18~*@TnkH"l[jZ-=ܗDiN3PE vuąܖ[/w;;t^tK[*+j| =̶[J7S>Cv;U]Y:iΔ?yKlW|Л~!QZFDkz|A.F H;=yo\:[s8h'NhXHKRFU݁ޓ2e^BѼ/3G۶:E39]/]]Wj`"d>O/fH}2;sb]2 R>=#H޼ ,#/vE-~֞<@DO|{-odZ-T-OƷN5V<^dL7Zx3lRk~ (1cb)0q,GM¬0/ߤ M吪|8ܼfe f3;R羨x*ʺ1ebzpjf 1q{ծiAL0'l][ *niR0`B~Fn*T`wYg׹SpZ9NTf بSLSVbўA5_tzsSd>d+Ɖ|a&QfKIAÃ"kZNt_I>"F搝)R!S.PdUa0@>L?ԥ&G@"T h*CTgŏU5 89;P9fԋ]R ]&]?j2ѴpZ@BSͻF=c|'j9F,t9󤆤~3uӅMޥ))X;;6.# òL`OᯤϺf,ucgHL7H='vGt8S2t'mvV)~< R"qss38׆S2Y$Q@HԹ6l/*jt_k 1~ e'Ґ@ V5ޒ:EM>cA11RxbYWQޞjkt)*䈽Yuwj y PIC^UaZd$Ք\lI7NY49)ӷ eTIEF_ښZY.iKbƚ %rlN8j13\|:I vUV殯=*NS q7V0;rS(ot[1Qɨm?; bS}l4wleCd 7$,[x0n#b/-ڦ`"Y0$]aMsv )H(}Y,Xݱ ³ĊW<=/+N;>2A!%y!V<*تP9zc%k$i'WC=83ʹƉDT1{8$E8GO XԂO!5dJ鲉' ALU0B\> o]E2SX y+eI1dY 1B5\յ\I4q\-e#/ F[/mSEQ2 Z{rBꝪ=2:nRBGwW]6 EO>CTc6kfnmȤ 橄iҁ$)(*^*-6ZEFo<Ǘ LZ4pIiQX"ly`ZiPr ,&VrfO"q86+8$T)cՐ*)A ]ʋ$;.uDnpQM&wBb0M9攡āf@nڞw+AMFP5]VW`"֊_kܘ VS f J1 d:$ϻd"ں FI5bv=A;lwA.A7C[iZMO |Ʃ>K"2{y<9{nAא[y)h4h #4u>^v ~C@'$i]vr@ h{:;Qw A4 ( (|9ǃ>E@,usyrHyURh-E!ii{sm{h>avoϜ;ڞrMG}x}):_v0nݨp`4${X"8P}' ϔd&S~IGr!q@<'#\=읎@rOeq*{"s)b (O$ta94& P]#Hvr=/dy:<$O +Ih:Z>cߛ_tjD])/ƄOŠ0p<,QgJfN1$bCG{v(y4?`דcG ;)` +KHP={)'CM4=ySACBw9'  %~)U{? ¦l~'h6<Cr$I-YhyQ;8S͋8{6o4\YDz%~DYH@k:5tƓw>ek/Qg)B '"H Zt6GXhݴA~ywg۸5v~\od(RM ~@rZO4c_y-D{!BrbSbz 4K( QI *9sJ([E~HD 5zX!(AO $XE+i8 GK{y&A"hoyrC|JyR'?'G`h(oqo0h-?9p~s%ab#]?dHrCO)G!4 )uKAM#B:>Iuo|Ȣ >A|+h0!ң* >}U3($"W2%(^DCBhc-@t0Ő(#HDݱ&vDrY8L>$ThZ9sͯGp֗8cWn䟑M $4b#ij@GxT;trE̟ ()4h _g^tG;^za ($=l:m}vI| b|%hQ'l ϴA;4ƭ@}iv7Q&@jILG!"繧61쟾qy>O9o?}((\C" *l1 >~}hq)}OyM~w'*} +ݓ9„byc_% Jǻ٦>s/%9JF#M%Uuے|yF#潺Q声~G=4AX˞e÷#٘y|Wn=/Q>X\&P,TQ4]K80zųڸhtHbBZ[ww:^eAG05N Ÿm,AnYH]؝_yL4}]1\fG.{%O}CVfv9zJǞ#ftwE7+2l)cCmïs>1Gդk]Η]ZX8kr)bw_ ɫBcm[B|WnsUcm:V|,hϯT uK_Exg=jxL78[ҬNQL~A0PDV`t(2﩮@2S-.jk@B6FbҶ5VבJ|`̨K{ O&P'Kjϋ7 055#Լ{mwE*^Nk7Ri 쓗c }.L<[W[uیoЖg`[ڎTI˷v`qyASF^$g1 >°uA q#RZaژ)6Εf V[&/tZ{aUNJGw;t뭭OGUu5VD<@͝QϟuuFY]Oj~psoZ.* D:/I;ng*O^us 1r{Ӟ#gW/ l6#$DN]-Qy"ÿFUfZEaceܫv>!hݡkhmle.Lgt822k){wp&J+RGy(dYY[p? ;7OX"3gMש4)Uuy[ { ,NDuΈ~pwfwƢ Z=;`SZ0,8 lAr>ju.P cwrlUE+Zf޾猙0/R.v &Ϡ?y^L2t"^ˆONzv8U6jFbJZoUalf?G-XUT5^bΚҎI4DW\U^ԗ»3Y*VLpat(Duu4gEwPpÂTyI`5GNX-ʣ'\;qتCԜolCC:W04frZk |4|jff>7 ut_hknhَ. H S#uPN#X+ gafql"E:`u3~H'  ۭB4RbgV yCeS3 ٟf}z]ṙKh^_TY:}r,f-,:&CZW՛Yʢǁi~v[;*5Z6k:勇t́ν{׃>yp:sδ.]#~[/m j(NedEsgAjqr ɽjXgeG+\&B,{U λNߜ*h钹vqGeDV0iHFZ w 8XPi/*X^w7ǯ؇GφS!/s2iҦj?\ ,6z2`KK#PB0`#pzUy@'g]%gAk{jלiS{Ͻxۤ2DgOq= WOo8D +7R唅!DYSS $FG@ldħm}05ܠDKg!tH21Ct/KVyNBܹw7:x x= |$SUxh܌w\eHHvyUd]u"5nW;pV:v9~H|Dk-I HȢ,TNbŸ"M󼹾ϲ~AZ#If*e ̥d `交GݪsDɯ<l0 QOh~ƹESd"O-.Kݍhh2e%hт $$ $|σꕔ@5+dQE%g|t Rab Hray ?o>Zby=&Ƥjhū`1r.ݞ&;>93`{h;9N;c妅y" ABhůa??sV7Q5vy<;r }syhy'4Es~Z|W#UEӼzOf#OptϙG͏d즗͇&h/ww͓UW0{om̿-@}R]iFȖ9lf1 !>9nAOy9ǸgUm;r\EChRCU Oҍ.5uCN䵯۾aCo0bJ%_~{N<ɶ~^^'GNx!GIʅ?`Ir=41ɠ(aQ?/>mV3~tˤ|oϞxPL|8H $˝ɶgoF2{IEDYDȻ{yߗ~ U"<0BK: (eaEwv( ]-!lɠ;s`5h ҕ{;-%~I;9Ť$QZcqn;߶ =y?nNG~cWa!+l/"c/nWj%I!  $) " !\&IBϤI'K$ξ>"u Rg 5J "j8rC{r941>P =EAiQgժFC~p5Ab<qqoR 3!4,`kYX[LJ@\/x % s.ϗ,6ͱͪs ^/7eri?cy_~s=͵Kh>s4P4Dy瘟M|<;ם-9ӅL)OzG)H"ձITyBLr@A'n}f #pihʤ#H~؈Ǒyb Ӈ9 >ϵ~{~b{|t~Ə'G^_?2h Əb9o9(9(( .hatX5Ƙ4z޺n_zg$Drh0 i*bˎɳxgz7@K`ŤNĜe UwElBRt]F^E M[ixj[ISCde!fLl^0/ocB}Z>4,ƫH>M3ce7˺4d![Xȍ͹&4 >#y [Y˒VM]h 0uk>oX968uf"'ïۑGFM}8 d@()*{]<^uŇK윴] &ŜUns/ZǸr GsCcs}9*o3n U' !uqZ^XP{N$)/dAD\=%p |L[YyS{떑 8ݸYu Uf/c{jW{lzMe(nO%FSbT_9j; PqhNk%j*Gf+*\=6",g>X2oKn40[/sIŹF>9qP{Y3]HU9XK(Sݯ{}=c]Ӱ$d@]r=#br B%d($cދ5Vcv]A:`6ؙ4*4g0syzM]p Y` 2slR/_ '" \tMƂO Q|yBu;rA"~ 꽴Wy׍% >ujL~\tJy[O5\ Vȴ]}k| aucpcQ0izR`.S}tCj iԅ?)o#6]ڨL6O 1M՚AnmO- 0Dc.nT6ݘ2Ooڧar;ϻ-ٹ8&L槶8ԍK燬* Y8yx^<^F>b?`F[&ٳQf#aY;YM,P>_}¸Z/:=Nj|-~H~In{Lg|*I*}AzFxtMEh&q$o.]*Ms[kKthZrd# GM/=W٩*[J$>m,2#) U!Y^3aI*ҩEKTʵqP 7҂=;co:/ਊnj^.5! ©ع:ݞ(Q—@o=e2 x* IQ^n5B.NNu%CٳF#`yWax([Y opJvlevgsÄd7zH4W F8knjP!\MHXX4,%B>o}g@;m F{2=C]pbtO<|e5eO3]%p)# {ݑURdHZ8f٤F'Tʨu,4$Rꌭ"kidQ}Pr ])>8w.83=+l0GL8B)d=bnf۷_NdE* -Z/VeݭUX#u l]xO*oal+3bֺ Z>lZs!K냇ƜU-TY}ְj)pR Q'q3+;o$/WlHY\*O[m((zNf042qAӮ<`0 哛bKӕ>@1+E0+VxW8ILLP"Ui1aU>쥲jʻEdUQb@[wwgKubILL ٳ$q(ţPc]uBzaKtAC׫QO״6P"pD4\:v5k'&y!ˈ9۳NY\!4HKxsڻŵ a[˗uozY|߅5C"+'jp&|vvZ e Gz[N B@+YEX#ObW%AM hFj3y0=_h Xy016cA"D 554>QNC\dҞ< i?#)̶|(^}iأia\vB;UŖiU-omנ9 ؙqg15M 9P&A>r6D( ِ}Iц1 EVۥVu8OT$ H$>V( 4܃ $A$0$C:Ġ.4PGC :^H `xdZѽ!s:c`y/#Viv{ 2Zf&t3e^z(IJ)0G DF;IOr)7O41UP~sʉ"|(ܡe2aK^&TI τ@ /E(vܯ 4獀Zw*{'gʒ{'HpLܣQFP$ ^0f Kh3GPEE&KH2k5,Ȓΐ@gvk?g P~DZ Ku4r;vFH3Ed,D,>2 &Z!A'!>]!iCB0BRey!Oa͒1Ry({>w#)7l+/e'Z4 >gry}?&)|Ѹߔ8ECd iU5}8}&2Fm"YX "@y w_DQTD4)}$|>IyO!Wp:lc\s/ T۷*Z|/ <":Dv/M->梜 A{RCdf8]>>P{p:@(2HGOtsEM$DT,GbqTB>'&A:_w|'4RQ?d=o*]!6 ֐U+,q4K& #$Jm=FGҲ`? %ᔫЈ3. #>v0 6}p6UK(k'qRD8[hC @@$b:= ­w !^Od/|Sl44r<ڔ4{>QF4"4|/ZzžV؆ KQALLTDT*tQŔ-ZY ¢XfMf2,IC̓vT]:1ӨL5 @C^^G j d> $Bi R/wsrt>_=ܩ>Uy'>乀5U[kw-tnSZN 0: @+7/#:xAyyys`0Е l|$!ɣdCEd)Sa)A@ I Q>/?}1>wzG8r=cA'ŠJF%Ė}% R>7+݋h$0|8,C|M GNѠHͿA,D}d&!i8DۄZ9H\MiXEi vG(˺?4g<>nl*#'7js]P#eNLSz0W!I$rK pu#gMzkxk&;dEfj0Q+W 9zh!a")Oyxsu#@Lqv@ebss%Y3mnz+sHg{3-](g8*w:HfK=yմڎ\P<YCV) w); JŰk;~(R GȒH-ķ=Ru:%;SL/ehW:Ħq*sѹ!M.vdX|GD x./ Tm fQ7er. ؗ4/mjmjD1N:c f큗pOnၰ_JC;[) O@}$ZE21^cy+^?.qenڱͷR٨ s).zFzƢ'Z6s'^Vf׬ KEq;8 h\¼V8_gz7{Z5M{ȩ Gom^5r$8{\+plW_eVge͘饜lFa=a |khYUX{y⊬ȹΪͽz6&^|Mmtkv_=rz/G2@R(PODTrTP^6ua67sveTs#DuA԰m0B룻4)sKBg[sW&v] zfݶF "ķh9TUӥ먪 YsghKDpe̺ۏϽK;ាYI8>Yo656eDsCgn櫉LmF.j/t6MP)e:%21|On؜b+onN3yna1~QC:cheaYwgV0}Vüٻ\A'mZ,ʃ  'ƼN#t2uFtg^^sF!.p"ɢ)!$ 4f斪jB$&:ƨW7%e87lc,3%D<91(Rtiq)ns6퐎iD"P6]m^@AnWrOg,05B W˒zͱ)ܚ#5Fy9"n)fT+BpDf@a> rh/9N~kL04J' G&Y 4|D`BdY>"'.ER$fЊɥw~y|gNkqmRԀVc`7OscKAMoO}I %#IIAݩ|F.HE׉4~}ԽII R%/Dmx1Fve# :״j࠮~kc$ &i,,!h}1*p@'sO)> E8PvG^˛h8;!A B>4ZM4kyh_3ẆF6KRc?>[mj@U)>߻4| HMyCe[ȚvhgHgI0|4RpaE(O  (Jd(!Xҡ|tiHV} )G|`I ׅdԽ̃ q;1?6#yE@PZiv' 3iB,\ ȍ>zRC$BF (d@zj,sHx|O"XǤ$gkh .6F!vr/G1{e%K"DT.' ,o"1t=ϻR@LyktC}{~Hh }%%F0MHԒq* PC'۬ kK "<&"Z&`X ZAbEbNb/I}˱Q-~/1׍Q[ C$I!0rkk"!Cg ^"-cjcr&e>Mx,KT2l+%-?~ݾmph9)Z+SW/-<9#5bb5拜4sA:`"ZL9dѓ,Z ,#0/%{ysRWnO*Zkq[`0y? yܜA)O0:f,JKBO "D Ų U Fe <[\eF)'~I$#b:kxMzUfXNM>`Lk#ѵNxHMDV94P&0.+Fʮ|b 40C;mIr׽g3 ^1,ސBWjUv8a1],L9|rLT74(tmmKti-WtQkIP'/}Ǎۣ kz/;hyvT88 -\c8.bktfj]:> [{묡iP hWsuvpl6}Q @,i߭Ș]z J " 0y'0.Dr!=LB۱t=+ :}ACϮ5.ɗ.B[慰οz:z<_"7VJnemݬxITprr:;x8m_ -vPQ57{Y&稇Ϸ1.g6xK**DV?)j<y !"4JlޱD+ue0tog8`DAuLI}3joDB6jK6Ii0-GvfeeH6GDH'Ԇ{Hws3u1#:64ydTse<]?6OXκuJ> rƽs}P|ikHee)Wq:Diz쾔غa$5i갟7{IÂ=z-jA(@HVC_a~xQͽJY%օ+;cSR̦*g)vk, RY{oYMR]md~e rV*mnӬ V g wuM:;ru$CwN&Z ,]Pл`I+5$5v+_cBENU4 ٲ^^Cݵ)Ƅu3"mBHvi;I*MIQ ޘTB"s7K1"~),dY8;=J+\|4emO3 A ZIQeS ހE'MAy{;>yQZǾ~u8qyrͤSIESC3tOKݟ8sII4XD0KG 8B-y҆߃m%4d>,):ێA.aifY >`FiD, +QTm ?|~nsDhS-4|I bP|{9h `f/,Q80 J6`YZ^O\`PIJ$-6@&rK2H>rJRzBKDa1BJ6<\v̗̜~o8>>ocs(Gh=g \ xDJ5 th0㣢B_12Z4×-"X2ҥG`?@SEڟA(H%A (L[$ $[V IHD(zHDb3i>ZŶB"s>O |s {:mTj(q~r) &CeQ3[ GQ&l AX$ 4E/GT7!( ,FU&gk;|{(RQr. åAœ4 ^d"O4#}۷˅N ܺZ 2@U,VDN1t.(qNeQW wX٥@oϼ++ړNƟ6c쟞jˋ=̗{>Odj|1;&.^KzAn-/!M&xVDHe]cEDE>FJ5j" "(E>h,]ɧ@Q^#Ё"V()>tfx*~]aL0J!z{< ^Q 1τ# l8G} > U£M@4ˆP #6!1H&CT0M*4@P 6"q d4>d/#O/iAIDO9%p5ޡ3J >ClA9ab"/y'/cp>H "?CL@ jU$FOR'xFMl*0H8GM{ N8A# k}- 6aktÊm@ FR(SP*/n$GIiN%% "5O!N\>Qk&J$ey `ǚrM1!=y0-Lߧi|sJϲ' rMez:\+XGvըzawӸku5(P7ĩ_fqiZ™5srIW8Y&/\Wm!ڳb͜/U\u]} 7S*FݓR0Ol2, oTu7a*;&NCEU͕j9HcOX9@K8噳,)#̎S[5O򊮫ēvd`W9f N- ʓcK&8ha:MiyBνx +=JȄCc.o$ E?dxC)~+]GzeW~=u"D_)v /^v}hUWWy[Fg/vdSO؈}zLmVr N+Jmwdֲ34O$wحct<2\u-U6Ϻ^[ v܃8nܔ3#XUMudGnAW44# τ&Q)jUWwvWIܖf,dZL^ŝN&,vВF¾˚ڍԍ X$/fĴ+n%gܿ.zD3lY6wn&F갲ݡ`[׀.O.x56snoZvr2"jUrJݗS}.gldRj*o=c$N^7U.Ip~L۱Qrd<}$BɃܸ]\}wo6p߽Kr ׻Jjs;;ELh,ozfܫ{4(M "yJN @C28OeݲlK-Y&Pt ܤJ`33Vq粧(#?-.ҕw33T- 9o֗1אIVALkfuB$764`Ih6&s(@Α!h$K 96=C~d !| Pļ}wmJB Ԉe{-\bei&Բ1 Ih4  ba Wv$?1bJKykqˤCyQx^D RŚ"GBS"{m/Z*g/H 4-Sa6 3ωG#%dxCb$4iQ(a @BÖ^ケ1e(ɪԡMXXH p5dA$ AaAHQd_/Ij$@p0 dLyrMyPr)䛛0E_$2 gPU0W]#$5Dzj,OZXIP M/ߓf|=٢\N ,j#)iAiMі==u߼4DPML" $/YD&ϠҹhP$L D s) ?QI} ,A)4)P>>>(Jv+\׮SD|"AB0DJA*p(H(ȲyxF4}J[!p${LNIZWL1 L BK!rL"ΈYCtU};Ux$M&} "ſ;V|!_rC6(˒*v|$U!Ȩ(6vP [W(l#NLVB|OcHIaI`M{(L:@}F=-`7?8o{Ñ)$ sH4/-QP>2' %d_Bjj׺#}.0*ǭ*P(",Dy)-TiP~Z>D"ae7JH#(RW C ! R זNLM*bZ#|~n^s Y€*ʣL܅a,}w8'EGagŊ>4ɘBi#Й|HBO%+HVT!U̔ ,G(h bVbz*/UvA|ɪ~Bndפb}nq(@00  $H@2HKQ_FK*Y rXH220ly Q+& EaIPL,DG>mjw-:&ؿ6qD"bh!Xy}bh#LrE6Gv:kaY8hkkL6;^'lZ!cۛk<~)W1ˋZ&&ѳUN3{R kQSHZ7UDX.$AoXuzXg.[WptXչ 3J"7Ʉ&1=.Yᛕ/4*Nh,q]303.mZiLGh T}Z )໪8g xx&zxn}3P\ik}ұ릧;/^~}japAg@U9=R uW@-jC=&2:60=<%W94pEXVi-FԺiM**y\ȷG-P"*6vOkm)4l1X@k 62짛w[7ˎU/ܫaq|w:kp"溲0*i`c' 镹XھeuL7UeN45WP"bl|^RFPGł²AΏAԅ^nW]­75Pk6r1F^b뭐ȹ]82ʭzj90 4@𵎝X* EVe j_A#!>5Y}slū!wr1 HC4ئ/ST6Q$ i= ptSKN`Y ATb 9Q{<FV-Z[}vDU5( ;(m[ʃ2Y \ r5bC94rWmh55NX $1dQ,^٪ɣ.U"a,$" 00pQM\t\1ZhO(+!>@5{ć X06X>vȉ; ̘KH 7 o !dJ6WLa:C3 Դr"3rT@2F\hR׼,%ir@DPhZ4@J$@-JʂKq $2Q,JO+$"IqR\(8Y " 7xbرN8$͐b6< xp5}Vcf|| C\e [DITA:|!>$s1/@Ez۠(?L:`PZs3v.vZ pݨӶqUvp-lkͨc:CYS~G$A`AD@fYReG}&$K @%Rj(~r& 4rD%}`;tiwf\| @0D$\)AxaT;‰>d&^aƦST+FPd4R|>eĦ!YHV#vAј+WD04Ț^p ^uPMTdr0|>H|a$L1o?{ʎn_e1p#{;=V. @®n!C"i < IQ}!JJAɎk9Ķ @+ֽ8i^-8>A",0)!H1nXIC-yJyqrf(Vl(Q ePzqn c<7鍈Ś^DjC 93#1"w^)C)."Vh+X1ɩ}.3mP M{1r9d>:Г I)hD Q-,6wLT ض..iI1p""nj$H,a (6("Ϸm] yP$T_˷y>O7(M~#LD jH !_Ǟ2>nWL~H %rj9~t:KNX/ŒQҸ>E 3.#Sd@#Y0L.cmoƽ2`C P1. H Ҝx'dd&PZ9 `Tz"NXi :BXq97VTTE1ba,1YMDczzS=T 殌^#ybf`c1F":ܤ9t]$AH z TWvhz*/p(fI8%T MĊ jBa[rWrƲPQ@ޮx9" #-Fמf@w}tA"! | -, }fZΙ:$̌w2 ڵmITkLD! T!.B"QZرTET;j$m!mQXj4jq [hqXڪZ*6JV4SA6R T4%!MDE5TD 1LQQKTE1UQEUQUڢ`(ҴPhGJ]&a$9*"n@CAlPQS$E:鍆 kRSfj`4b"MhjFNm;2JPb 4IUià&H)MAД%-*-RRҴGa9.(* ]D,MSAEK2UEE$DUQA rT鵐#N*O'ȱVM(UHR! g&iJ EW6ThSlpO1JJH44@UR4/N]82zqU١Wܧd9~IND_.*eL5&> wǫk>*'dr׏Yx W4Pۛ&!|>ģ5sgeQ&@RATU}MvIkHڠt~[,X.>4Cu[ |U7/Es~^w{["tC= ܒ ^e=?83Q]}n}7~k> 6AV&0U3̱"TY[Rd/W)H`P7zC)v;'BLɊ2_IA_ .)>nxd547^ڍC$\菅)2@-(8x E9 5/+ {嶿[3P>{ 0eo3y$ 0 i&b$H")(F"ihZi  j:/bIU#J4AQC@L/ &"&bRf)b**8᥄" ))!r!IP P'`2lVl[6ųE6Jfi*bj*""* hh((B!)Z $( *֍cF$5kmkaֱ aذj6(c.M1Se8\D ~X;z٣^]#8Rdn*I'HWꦪCt gdwi@^J!o/ICOXJy\=?^_&V8?m&:4Hro 1ak>DFTz%13v!` r=zAZo|hiwtm4\Q癜nMYs@m59 R$a~ zmN"]2${5U A2~#>e~#l51ܾ*}Ks?N<(z 4 xT#ʩU#hr `BTzܺ\]r&3!j7N׳f"QG)Eܛҥ>G41Su|!Swm4OYXCQ^/),),7F';!^%,b8wSɾB9ΌHAqy9e&yL>+Qk1,=f6;lu~aٲ褤f_Y ֔W;C4aO=U:"!l *tZq! FXţ%n-8)Gj8/hߐxYH8C_濭-*%6[zuu/4|EL;!WXOuNJ Dz1ue o5%;{<)^/4׿ɗ$v@U<Ǭ:mFbF4gs_͡VΑo(/ 21]5pTz.ޏjo(7n!g e 2: QԞG'"|5\~- u6=hm ]܏g_Ǟyt\o[)_%EU  [٤. 6^CC^98[[z+*M29(OޏgUQkh`BpBi'nkQP^mDzӭ~8Z-s`HZSr$* X[Z: +cR$ݎdIriCE:k&O^?矣-sNnNʛ$R]&8R}i{(B.̴h6(H1<9n0vi9MғkHu+//VNz1`?Cu;%F?1)cgQ'nǏ4y~jmA}KݺfػY~®aߢDz T~ӊvG# 9*Gj1Fr=|̗Z@TWƒ|ٖѪ.9{$X"Zk}+ =!lS7oPrqBlVlPC.TܖnHehY*ܹxV F,_܃lb; A@c ][!Q8(j( &ֲNk@šw8::ˠ b!F)yv`b nI50 E %Ej_+ǒ4#r \r]4$reqR*LPV~j;*_4j6C2$* XI5^ZlVV3n:&<4sv. $>0gE9uTS!9ě;/#G%"7ܚD'X׬:m(bCw91AP0Oyswm6 r틔yxey&'d%ލ~LbU!=!"m]0X1PI_CɃIЩH 6G 2|iGS aEUy3GWȾDU?N`W5HHF^}e+I%: tآ!E~@g *\#&|iE"rbJ)J̚BHG{"ulO:^H&{g`d9S7c < ʬJN`" &mϳXR'F.倎<WԌ< sMT0IK%0ȦG|kPa-cSU4A/;.qY WഉCYJӊ< L#j3̝.Crbd# oUx) x}_)4^TVgX-s~k~a:0ɻKN/^YԱR\C(zRc !x`s[k.9 h0}l7R3A{pr#4,i5 |HNyU-ERBU[֗ʉy7߿߸_S? HSK+(6k4IS?Ď RDR!T %P4SHT HLUGGIDTHvD[:60kEئ\SȇI0i $MAQM+3!ACCKAry ĪtٽuسIgXaŮ ÔCub~JpTSK}Ɔ! PP:wzLsH՞TX@~\tGe亨q޾hU}//߲5iR7yG%䛱!/8*G_?M+o.h3JDf/S^ޤ q,Tr8FvLJEz:4:˳:Ucf#Žn Nc^ӛ0l΋+`}=Cje]KByOEYKZ~,)zR~X{/nJ$1,qaeftL8,QpLt2J2^mZS"] )(5/ ue(3 9>4 t*sԘL0TN]Y=ԍN@f@j&1t|& rȪ>V4PIEz $ZDVܫ#{^/GȺvtK Fic]:r5Oou*( "Eg~#&kGyǧ[~;zׇpb/X]E;ZRm`9W S͟Q΁_h&N|@nL3_$L'J3--r[#s@|U{dJY_YDUdjC,o/D]"\#ڟoljٞ )v@΄Y/gYqO^ܑBZ5J b"=k_;r=#߳1Xd:h)=е6MUH&9EC\)΃;sKu󻋓5NCl pO `ܙxZ.ۘeƍeZ~j7Ioץy̆ ia<\ЙA)OqJlվu)0Â%k6wgl;/e€/V2ourf6Чԣ?kB?\ttߣ2M \#RH+͐=8tU5݁'y]G_M͗z,gN~QAz#йgq-"/Iox`1cUT!4yi >fV3O7˛7n"gJߚiK:}3Ea2CjhTtQE! y.\\@B*T&$ҋQؚN*y$rZFhH("((("(*) gN%*"i(*j8%55EI@I١ h¤pR#A0h=ZAKIA@Ҕk@z() A( JJ)B`;E`شQmki4UU[ōvm4jV3@ҔUDeQPh@{&b)" i)mRAHPTEAPTLIUTRUPLU%{(*(J)(.B<@y!""?xx }_¦5 oԩvbYH[T %+rh],E\Py5aT>f3w]vl.| Ɗ˘N^|4Pၠa 6dtd,y7 r(~4s\xF詒!Ѫa#u$=@dcL\t$MDJ^WdSŠi`oRͷ6Y[A8`PQTfS|Oa*Nq)7#rhމ7sJYq92s{\L.} a/LTnJ{l#?2r@VH=QLbņi4EL:L}ԀO;"aH5gpH>$ZE*LZBH҂C`oS=,z1AQC/M~fhXdK7 !?&!dgh dzaEU }1Jí[U#A…̩ XE.2 j vSF A$d_o%ړ?I2usa2,kT]6c5 ?J_l +ݷ ޣLa#Mj=g J 㝽VXXMIO2<"d5F?Z+=`$K-:n˿Ù.ʙ5WeRBf˫3UH\W5e;; Э>/s[DG?zmHmc}pIa_zGBA%8ş~L{;de cǒ.޺I8Cګ#r/ƦR'348ԭ X`=;p=F"@USt{5U$NdGȪI&VT醯Bh+T762/ !˼W{$jR99oS00L3m(?31!1ȖSUc%+.n7зaXz ˛Sg~?RF~|z#{|  %F&x+D끛 hi-t℘(J&㡻 (]f2Ab7}n15"5K g|CP;yi}fae;P6X4R4I=:U6?zS91[5#ٽCҾ _8W)(uV)%tDN`hQCҐ.HrBL. }f~EZ\Ÿ7" x]d BsFK䔮uqV{=\f~D栙qּZX)wA|Ū"=;U!j&!\̆*ʪ8k(/,]h*g0V9) +|@#eU?pH0pw]p  VLѼPB筎?ثf7Chu*$m;ulƿ}Tu{2df_A{<ӌwө$Ŗ9k0q8g?_8w&RCTYz7)~Zjra;Pq}*F SޜX\[GoqtׂD~]TVlHi t,EHכHP(1F cz΢SGR8tb ͗5NFTrD\L:Q|K8سzw>(6KHX7G, 8D?"0q׭uN4w0j*]qMEOeAuWI OGE2NHRWr1jc 2y`W>{, f϶ bFH%V7zqÆ|7gl,\$ tޮIpLKb- 7#)s)MNh ? $0iRH5lҖ7tx,ý2hA ªUz=&"7U]!1w߬2!2uJg*"""s:Is~u+8]EHpG!g vHlq'Wo?OQ5UUTPWb)@zC@PNZ- 4@EE EQDTBM +CKM CTPQ@CQQD4UL319mк4hZJI) 8{@0s #ʢ a(Za]).\9 rϷIA;~i;ۡpU'35TO<Pw *^lU_9Q|u|<])v_5.xBw4Bk*"ZU𸦋WN>^a\1wK]YaԐZFojs_-ފ}W.M ُVM׼׋vHs+IL?#Ij9Ĕv;S}W;smuTv^y6}gRf放 ?$Uɸ0-"0*B8u-p:~:X>*"M C'yU`V{F0 )NQX9UK1]wS:$ eu(5Q!C4e]O5d> IEi^[Oɽ]d/_2ȪpO -&&wORrI\Ʉ =6vPo?uaS~2S;sZ&q\EQWoTQ!Qs˾ϳ_.rp^DE>ӌ']eD ]&#J|/$~&ex7tv?ٗFQ^BQM C &}pmlaAxSo,6AD(m2H"'4V)jmЭsQ,40lVӡkB".~},` R.%mrzT?9TTݒL 1,jE#>P oz_d颞ayfjV'<<9 1 Ѥκ.RϪBGHO\! GmD)V@hь`ZTҕM J PpeU-PЦ+M., @*&jbZh)bh+3EUNm+V,Xi))B P$CSLQM5$LII 0T)CJ! S Dj--ѵVjk(T9F CBR"P!JLE1"Z RjJ:VUPPQAAS)EBRSE%QM#Z TU-ĺ+KK5br`m\-h9QDXt4 ĚRbH@hEPB'`Syro[ۥ> О_j T9+ӿg3KF)(~w|%ҟݭƔS0j_TBVwD&QEq!B*_s:ʪtfou}V/d9^ªl4 O?"c3ϭuꎝ<#t %e5%BEdsBRg- έql@QP^g=03*Iڽ~•CHxB 3aCkvU'h*7WA1/%|c|L ouM܅ȼRa5Ĕ7 O!>Tw4LS ݦéR~1!7r@$?zTy䪟=-nto ZEhدn/6iN'`umO?0tgQ7mc:2sה@8^#x;y(q&!jJ})mnǛcį/ 2D~tpu%[W1V%fIuWstvHNhFiru#A.ģYO@k8ĖxCU Ax@&EC uDؔD"~yPe-1&yYHǕձ`VtFw2hf`VhBK8襰^{nM uoүfz,l]AE:62 V$F8SCG EiB{=3kXu7!%+7;a !uGL*,^zaid+ ߅NWHxYVnvE*{SG>@TX0· }nOe5M` zQ"lz:Um4 } QkS?mI.z衻C2V-9F)L6f؛?PL[Kf[egi 5{>k22xb'~P֘K*0I&Q$-x@e !J䈣~NP֩٭'fgWSG'\_"#Nul1A;:+Ijd4s4{p:?'.hZRam+PB +݋}~,Ӿr\*64/hj(X#|S]u,+Su} {&DRW.WkhowtLᔊ)Lszkk%Ҍry$kUNNN tj !<8(VTM&h֚ *bF(%Z"i)fi)(*!Yh(&H  @!S!(Ѡ4Fcm6cmkkkjfs%y BPhWM,KN&$kF@lJ[m[jlV191pI(E P4%4R- -.D14hUȪ$"<ZB")R(( I+NG !@SM-1KHC˗!<z!O:fBUep \05e#P?3˫<,9o-U n篤?ͧ.k,h!I5^:gfaHb Ԕ(_V72C QA;z?eЌ7[(-c>. pNKLbf֛^%HY0sidT'|  WQu7WucIK/m 6ZQYTu;o2ϡL*61%/ -WBF!p+ BsusQ26RGIbmi9z(Kq&'DF 2Dۤ]z:!4HCbo+Oc/fˡ5<.I7M^(KQ[/b-<t'uZ}v'A;Iq-^WDV7fQ*+tX>ZLCϰz+QDX??I?PPXƢQ2i&$zlz?VGe_9CGu1ӧɇlj>%l#ea;Ypګ1`wH}.Kq9_GG-6@h QԀh#2^q1jѐo5ȆV7b%Y{䙉\Fr^RR 2/A<>:6|Q3%ZzΚ^=g`'8&]S@1x:e{(l-= '3RֳZ8$Z@n2_GqW ;{$=E֣g-!y\u\1C '%oojsdX]w.B`"y @\YX UO22 !!}C[k4 Y(Kx`rmseyQ\wu4 =;zkV0z\4Rq4PжU\,Ŀ7_rfXN5'm|Ґ@@( SA KeC@-&.Qr "5S415TQ\E KB(X J%hP($ D V ` B h N jkQ3lkl YF  Z 4@] )  ) 5QCE!BDAAH5AJX!%f*"+ UtT:CST??O7?z}8LR,x.>Rނ<es LbW!k.}RC!&ٵ3nS!y7/Ęodj$G}qlWX$!r#UbDpGNҧQcƼ}7Nv )-?G}5'Rb0`ܼ٨{1RmW*yH1,nU$ 6i D?t,E- _1T#tU#',e9Q˘YWS:s$G'r$xl&H2Cϫd]?ӕ#XdTE ]>#iA9ߏ0DM1A>i8 E߾A4l3W9#GB:KWhLEݏV^B&%]" I-hXb 3d;Y%`Qh<35I zO߯{TqZSJȾ9SGEAژء[a}Uyu]wkw`@n)<"(zciI ݢUׅh+=@= `a3 [ PȖl1$m5s1E$jejTäEqS.JűFYt?)3 ^ hÈfמ)%07I:ޫsszg+Uʛmgdl{&+qe\$е &HTbS(B<ߋZ[N֝sÞ-rW~AC $u)v&1;ݖ2tXOJjYH9ǘe?)E^XzsMyi?yYtNS9Q>ɭ.g<䞀KVz:CׯDž tVG#:, J<[k^ :?P<[8#@h!<Ռ) y?~IJ-P%9 40rqTA@Q@DRUP DKUD\& U6( -Ƃ((DA\ebhJyILMlbmUEUTF`DQf :*kpi(" JJh(iMEDV-5lbh$0d"J"h"RC3TMHDElD5lδkS6uRu["gVXw $")b*94EA1M1Pry\DE9xI"72z_]|;⏕WH7Ohkʊ1yr3L)#UJ&BɀfVGdi48Qeyzmz\pQK%8dXdD.lR\=ZQNtw2Mq}3r[ߡ#>9˭gߢivdhiI 瀐Z$0֗=OS#tzvDV ?ToA^2Gn"XQnDV7g᱖K[骪@,|:#( 84u|cOP.}*/H\$?$dcxGP5EpI'/ɬ>Tn9zن(Q_G0[Oj"Ѩ~$ 镟FAʦ.s}xt172.! =h0  w Fx!HDZ>߽˽(M}>o*An@dߪ%t~eij8 ^f/)/[}X;pd e_{X "}HpӼd(P-9\b#32Z1ևa\÷2 /l[:2 !qvۣ^R5N^| vW a }@N&B*?"9>g гIu΁=z/2t&%\Z RO;xYH+^\]oRQCʨ|fYwB|`x"}%N0`,my]w7ѻaTz~kl\]%5is!7PC51ƣ#f-,蔅ޗ#HJw:a$4-2.x i'ާwfyYn,O]9:O֨&yNeL4ZbTSH4G_}[gl?rT@:єDX!B?rMPxt%`$WRi2Z1LYvRHn~w BXhU4EK3QY6Gb& -cs4u2?ԍE#E B@X((J!bTAUTt tG8c"Q1 phCJ/i\')((4m)&8$SHP`L5iEF`Fh4cEj4Q' [KZCHPM` 4H*Д#0B`=dǞ-P#+LSŏ:E x "dph &ئl<>`}fQ|fYSiZ1ty8u]<3f<ݱ,'w9:6<@I\bU|Y('δѰ\ߊ't9PKVV)QARxךIC{*XzEUN@pNC1!52Cz6cn!(;!L¤dʯ]\޷,="mܴط?8θb(*)TH##s˜ȉqcIJrxAp (9 >riNxa /|$).3z>0T3Ն)tdbX4ǟk%Je폾'GG4ĊH??~fVOL&35aA "hҳOP5Dб g9-@}! <`;ge'{Nyg>kZW)]s32Q$,Ǫ)yDۊD6G(#8m)95["E\JjKQ 'oL@Dԭ{ tc|FpEM%~ٓkiRX_B}G9/N~̉6 EiR耽k8D g;g5C)] \Q$~I+*T1[֒8FF֕Qenw}ʷ4eEbJܖ.]/Se&0J,'đd %u1Qt`NnAB e#&4S JQYۭ]<^eW&-xvGzj׼#`. v"Ra!RҲuh&ؾDL)b5q@ۦ"?_9s6A4s0GֽBP[Q1P[D DDIڵr$*ݝY#;j\Tw7ޙfr[F 60 \qgA1~2HQTUh#IIrcšh}Jx3auXl=_AX~醧-l<.@?@cLTKl.) 4"h*@ AI@-4эS?P\)$`E5T-RUDUQ CHP Q P9#T- \Z Riu҇ @MPDs((ԸAA F6MTčU(Y4IBUULUDP:M+X,Mhō91EM%DQIQ^T)HPJBH#Dccm:kMj"5cEBD8z M=l/B??G}9RR`ǣO4ғTNYYȺW[KEAYV(M xD$Q.c|"^X9c-5 RKF'GhӔB)Q5LK}N6D/j432Yy9/ ͻΨ~D-Y7Uao%tk:TvN q-@_t7. F,~)n8&2qyJ%:!I،|ywZ4ZuCy^mKg`:`Y|I^}4"]3evҰ&ZI#4sELBj%ěAoAī9` D۱bz 7) d2~e6*N$LĚݘı:HmI̾7Ūİ~:hbHd.sf6rU>㿟K W[vRP:<$ͩ%ַ#Ic/AjC hx62upt| ,eG~! +s-*TEr_6jc\ޱC`r:N|$SʹB/λw@ 0lȄ˃8R>(HR[3$8da9+4i]PA\gy_Ɉ-h0_&M:3lxО-ʤ Y316P"r ]]HI2S`T Gy|)hd&‏+ArI1sBSUF|)V M_Æ{ĮyHO>\ngABPfȸZ >5J~f. s1 "4=5F:8 <L(8̿Kq'hN;\IiY $ ٔ4R=aoEyIK6XE(A R . A@+̤^ wعAuӱ4 gOx]J,f@|`UoBnb'mɧtmi~eykj0d;眯Y)R!eIePxb KF1 a0p'/QjhTH$F< n[cr"AgW9Abjut@-j5u***h" )`j"dPU)M1A7p b"x5jWSRIB<E%sj֨R4kJK͚h)"*0@ 1S!A@ q)(3 %3S+ːr խ>StH++,CoByb'S돚0R}h:dZ.c7tSF|(mK%BZAS5"ptA0Enwa13QmK}8/)M}X5OB;dgdwE [Dœ>(x7^8Kc$9=|O? IeƸyC;Is3]a).#]5M~rPcԵ s\0$n9g Ǻw9AC>15,fN';kv$eB asCwMM:y%.(<Tb1ԷJm\+q8VI OJu`֎OFg^a?1 % !lU8y;{KɓJ+5sy.T齋c2ьUБO^&3.z<`Wy5!o2f6QMqכSKjuY@r]#e;y_ '։y</uesûr~"w\QE/14lj>چ}0 ybw; u.5ACn}3Wtq9W:.(YHQ1 Qte8&< xΨ ",Uay8褘7 >eɐuk̝H?<\6ef^{\ʬe1ofe,yALS{-r} ]Z,@ڪ*R79  CIIN՗.H$矶8NaᡦJڊصư=q? >RaHA]F8=?B瓩yվ%H(鯋o?ųĺPg&)mŴiO7$*"sߚrD M4Z CV>"^:t">Goy ۞`{ilވ wy_fTd/I}Tjǚ\c"( l LY~TU@!w,eYs4YrlXfz8>\8X90Xyy IRd LBp^J"ʂD>b j GUPg2!, BU@BSa@ se:(Ʀr *`p\j\ oK?s`lC"FR9XAs.T̼S*aU6Úb!I~lFK["a1}ɓbR>=gͬY/C A#|Vc3!z B2fs͌Xȇ1!t.@UEB%H=QeHMc^_A4/r;|B VZhn,^brF\^dnDfr.B.\YɍkHQ)$f.9A~x4Ff+$)Ok]?D]414E3.S5;h*((b-NqPrBDfi(hhJH)ZP))hD(PZ%UQpј:4m@$G 5L*hb"phntE-$MJ($)JPU5SM#RR (dJhHlBBD ӳ',!kW]O||/4*oV.^m%nO.ZR.7¨'nsLP넖 7 ?ОU0u.'"zB<y`ΚcgؒB.5P^l":#͵-tzN fK`Wmbt g$I㉅֖Wl1l=l ֺu~]wɌiUlTO?- 55,UScԣ2# x5X:ԇ6 x~{Ta,~"}K_:t$=$sTNX@19C$:#duQYR /NPۻGIlUE1ǟ?$Eĵ F!/W#݃>\#uSת#ktouu.کlO&RGٻH.YvL)oE`_g[ n^QmX^7xZ5&BI9}`ߋ'Hv3S:E3=} y!4Sv_wۍ~+,;0N )eK7;H9߾6ݘed';{-srC[]*V4MI ]j7rМkI,FԶH kd01]6,.%JK;]sӡIa443¤2rJ jndPD`x9K<|>鳷i/GtCYc$MBLr$! 4YXq8{7ss7<%"NV?䍒?yrQ;QUERQ Д-4LIKDT1DPIQE SnB-#K+ql02Ā4SOdHQ ˑ.AD×.@|ow!?S64 y_X EH'Qo:]-#&'H^)fU/$ف(~ \ՋuCX7+9VdgZ E~i{)kSUcqOԲD2r˺㠛L&2jV7(m#X>h[&ysSK_Z'c,f)x󄪷Tꌝ 21w4$k3+ћW;xHB H:T&əV|!F+mqL:;mL,ǣnwiOy S njd'aJs,d_3?\WRWؐڋz~m20QoPT}"g*K&@1 Ȃd|h~qza SH+4t%|J6׾t\!̫ZzxPAz9Gcƾ֟{떒i諗&fRb:opt({U} dQRtN9ct74kTo˯j,wO_dS'uq -}/?- Q;$RG1m>EƅR-BRFIK JtF] jI0$ a]󹿵 :Aa}w:E ?M.9|Zs\d4ƪ:A02HRGBF\:")u#2m'C_ -0 &j nF1oC@cF_[:r3#c zLlDI;mJ{pk4=;(6@G b BhWgEk+Y+g{5p7 ث$o@dk)K4l u .434<5[Z(ׄ1W\ax24=N!6l \E_/ڞN@g-NS ص5 ml1ǡsudJb7M%$g W8DƂf`Ν7EP_NrU˙E1ZTC#i@t̚ g4 ®&.K ք&O+wv%ηOJG:ⶕ I{EP=sbj*pCcM5 ܮo E^(9&2tGIq4NBj`$s3[Ho4[ m웭0 uGApn.JO s=~p|.g{,1A=uG NkCLWx"Ya-{‚G< 1CޱTlsuZ *FYLE dRi4Kq6&E40݅40J+F3m^TĔM K" P4PұU "fc8USTT̠d,?|$F'(ه[A Sfn ÛMB=6)tJ3iًoDV"W)H76u H :0% if%ġ2gP cW!%) !/ԕ*(Bb]e'iH|bqfAė Td5β$i 5dL՟F 9`9 4BD@ rXDAQz 2 tŅ9KT\JdFd"j2FB<'ɔ&j3GؾY m9~H&А9CBp%D K8%dS G A[\X3%O$1$-~ y̨ /!3"ɗEB@7F2^5~~= h"(J("*Z("J@G&-EEEE1,F8;p**jy`sép$&`fe* !5CA LuBL\ƂgEEW4tr4QwV,XXtUS!IM%R44*x3&P*>G_ 3F|ْ=SѦ44Cꪯ6^B" 6#ܞP (cfZ| dr?a+%h錴f'7ʷIei`ad?scß#rn!)gxL}D%H+#UНn$NݗZo{*{-J`dBZ3gʲ՛3! ̂ @`%䋁M|uWV [Q e$Hz؉eC 㼌:|dkSY!r{qT¹x. -0惁wۣV{#Rv7r#-l wz|$ĵSiQkDRbJ":37GѦv`]ӟOX,,jOQ9kr4G\D?iq̺祐HfQCl^?(v`\7${.?,;MOHi$Q7P2- Ur)ƨϗļMÅ >.!_BbvOTF;Z";sƓ<#W&@C*?;2b'+,h߿˛ݜII u7-/\ B /!wķgLP8Dh}%(1_qKd/)PRXg~#4f?%DH z4R$Z bոiQdUȊH `@Sg{T@`TVS RAqa D" iҥ̨+Sk?p\6`I:0Kff<P@l23$ngvOWHOc_/(V~eZr5#2eFi-nJ%CvKEED)s%: j4\94D(SDۻP*U_ۀq723Ij󜓪6oZϒЛ{ B֫h4&vŷ4G3)`h]$Þ:Tor%}LXt6 /*c&2r*?l7B͎Ln1̽td]ҽuPR;ybaRIU%}/D؁#Wܗh~r+4(ŪUu`w>2lүآ`cNHR?sGS \SсM/ɬ( qc ;E5 JCLDX=:WqPTޗ[ARX) KDf`j$R rMW&"oǚwIx$3N cdRZ\RǐHKQ-ppYc'r8-y): A^X'5QttL*YɝX |p]٥rSTfϬ10*ҋpL[H_o-z& vp3t@77Ŵy[+!_kW<5r 2%vtHeZX6^X =U9ח$ځeF>0%6ZTN>^ +g78""7F8 $!z)J%H1}}1]2m-[Ab1U`Yqns#L>p+ ΠlUֲJ8K&w2B~,)R`T`@_rоUtT.Znn>WB[E?ǒk:H4G;៪=~RDOS/Gq{γpu4 |rPꖱ'<#F#sҘ´n-O?ĥL "31dYN)oꏎbVs,$|n3L̃BVLަ3Me-%Y.6݃>Tu4U26n\"“kM|Sw+@WixK{Àбn$A#røjm:it0Ėc+6ԤϒW"E ]i륛J%2!!, "(tYӘ7&J!12ZF&+'L"` l 8< X i?V;+9OOi/ȸy_-oސo0R\c9b2̕OFRpШ'نL!h!!1- EjfVpq*gKX7G7lVΗ--LLo{_kE#D:;I~&+< ,t&jA1/yB; z_Bڂg24 Z2=Rۥ}1AZ}C(ŧV+TH :!03#uګR8?QY="=7h< OQl5nnvOIߺl*mNw]oi†o4&8,zso%T}ɝ̖JA!hBp+#s4SwI92.Mv>kau)$t;Z'9 q97F#oSK,_r5)dLP^.ڹq iB U`UU\VTD)21we[]&h0ŪN,"wenD|J6k[A8O=_9]TdM? ph67 d<=NfKds C |JG1H%*NcNr14PtscɊzmv鿠5-t۶:[yק>-ן@f8ۍ(u.@ ź]K{-+D oL$Mb߹3aw!a}.x'q5AqJ'Ȧ( M# "-ƸFjj("H "X*4Q(ЕqCp(pGF&Q/PU" _]tRRE HH% R44P;'j䆒h `JE v3XthQ C@RSPK1QIQ)d"g[WEYT%QT0PCq:p s b~X6ٴ1LrҾυa+g=ysi/)PE9xo;k^7\~B|Z3BݢxL>q)]e6P 5}㫯UBI.5bϟmul7Mol\zbs-ڇR4şW/7uOw]FΔe l6CCKv|+tu9IKs!Dq7ޔ$ZL+| cFI5|a"?[yQgֳ@M{g~lJo$1YTNac\h IVnh^{5*^3}ޝm_ X0Bѹҽ6?]hjci ԋ!y-,võ['[3_)9e79vZ214p1d|0IwwsY<~_6|,?YNbZg럋dEQZ7$$ҡx"3Ōǿyfoχn%I/<wWuD&dU.jGۖUK R=) }}7~nXSm5?6P Ů3OyϚKQ UFx&qkmN3YsTK(lc)3j-֧ȨZIųRðH滺skWsNOTo w{(JؑY:BӺIO?:O;1S NQ7ǡDU^i1_Q BʼnF-ዜC I1 i͵JU ^"[]npzC[TZiQuR*X0=OL`{qI1e3)PIP?esgk'OdGbc(,% <o7z\:a qUIkJ|ެ{BH[+8qVpD脫cmFWnY$p4讙_Zsnӳ>YihD i,dmi1\?114|Set{^%7W㽐$JxKHpu$R2o~,9iU, ۄ.VZ6nY&\Ul۳nk9 gIăײ};8ḢR63wQoy s LfcliWSY4T˅J'Ƕ[La;gLLҶ BS1QG缀iVE BJzc:2-" PX ,Ze4^Ol5kn SXiȪesolDUE_4]b>՟=uTq]L!cY<Ԑ^ 6+r</,w!Jy+Hit z""c4,JPgFzKg\q\c+4RGԼ baF`*: a*.*%'Y_*DHS`H;8Ib.2lW>e:٩ jT@N뜖ԖWB ۥ.D9dz[c0\+w#'2HcQv|/z\9ϳr~ˮqm; .,yŅ_wT*k Ñ3gn&.[;Pjnˋ*Q )*.6VFBkoimbuo7-E?жZss)4U] 22xDFTcŘh DRt<\Jhd/AwdǺX7gY+ltSʛ gxuU5Y2iʔkWBDtc4iK.?kJx,L]ҽѯ _ȫ&2{fxʃ c(d"op2C#rUse7-2cRfN7paEZEʭ?T/x㢊Hjޟ.7qe̹WdZ0 aオə0^?DƸ| tHx!rR%'iҐy&lwھif0tc_xxFߑ 8TI++ o] K]18HXRoGOPL)`iPurgcga6ƭEj.~K7ZO UۛV#t{ ݫ|oYio #BBHWh@IEMP@khkA#Rĭ6rYq[-Dl#1wʱӓɄf^i}Z<6[ nuKn}Ӓ^\2WDpgUA҉?+Sb'3@; /)䇓ǩz(c{D!C_{>,*6q_e~{{1PJ EHFL2lOx{__@?$(f#% ?Tā"(*)9SSsnxj)P:/!/ 9(! uM)P QK@R=yۍ-1CJ]sp䊝?_%nRR_s8Q49ߌ- 0%K A5AH Cw,G̾JIj]IZ?Z_A8gP[Tq!JkѠ S˾T`YsTYUH~:7m͙i@ş:h[K%yr`JKw z: eZ,P\ {iLvګMb)6-y2myj,OZ%iWݲ?!D(픱sζpON /DD~AM'VoL 1yd/%Da. V V.wu-FM'YRR@fC #?MN!UpNV4<>MoEyz ^サR͛y (t%qu霷_8k\jγy2膕Nu@S]٣=dq,ẂHAvI5 2&a-z%9j&9xjgX6/F𞧈ttHf"Bs]˖gs6yJ0=ԡ1F # Ҳ*Pc;$2AIzL,"KߍӞڸ"~q'z{K;/`rȴ23.5'WB`P#jQ{ HZ@ѴsX J:# 3S8.~%6Sk_lerֺu@Ѓ/pVoYZfdv|^:0I=P}zUdcO-%!+]oF7g2: P>7vTeE ZAtӷ_ګoa!Vi膫F]bT5%-w vY){B65z>ݰђOʌۊa 5b _2FKma23˼iד5C1['|r/wsmP8RlͲ(MNBV*%炍C ] y|"x╋D>yp{qu:_ mn{pO6Ф=W̷q:x!ۚ׼FÌqc F\Dl )k/N>8*z ^ji8 XCeDڐh{ cZkᡯTW-U&:a9g*!Eo1[IYizJMHקnoRcelOd|Bڡ+[qLxW 3|5q[$;Jeޚ` YdԺؑS&[s{KS 0//)I?( dVIrAi8ERR \Za"*f"jhh*%bf Bi* Jj ) 9!t`y!s!V4%#J[."Ik SJPP̏%TDJA0EUn`pQ%RVPCDOcX$ƳFUQhh#[j4kbm1f1:ui."Ʀ(I&"i-Ncb)sZT5f, i#qKUAQ4LE,LM$ԒHECACCPTų ]PhsD3LJD@W W;N)A*f*Zj*(")"I**"%"&)!IEDQM%15Rw {\-@!mVUxPbL=쥈ua>hm4kn2jz5ʹqJ*w&t^<UDQxʜ򣣚_: 'a{K研9)#M[-6%h:"!yfZ{e}ς4; #_> ݴN阒57_^\Kfl0p9TڛJ8p/n%6139/3!<}$݋UO-IV }O rHGZp".8hXHRM)c}3 ajHɇEMLghe tDtZ |S%׿=)^/M,.}K$aF#-2S_ѻI,DTEҕ7rB0Y6D3RY74Mۻ|ctC!IH8(Cάw+G%1È8j9J|<~RgcX H*οib`t<Ԁ3}1 SpjUM Yy(+_^eX NxA&0ڪFeR[,S"A9J|EyIʀ.Mضn"L^2l& SĆRunࣂnUj&OҼjI[10S.ZK O6ƊB=L%AIKc-%:R6eJ1HwgM T3-9@ɫƒU]3 k94 ɸP8-ƛ9(zmi,A>*Myі\S^\T˞6}8L3y{Ӥ,k%*eN  ˇ#%sJ*j 8݊^%k7ZSbh*rqzxM׮f|3uKY[l/p5jLMM%3_NsJx.c2$;^q8g›)Ih:~z Nn㬤[KtmI)(: ARB`ڞ gH`\kYe#?1p5}s_Jz}O,x@̧)bԞn}-&"%tʰfjWC L%%y*=_Bj]g1Gvkg2TXR_.\~!@$CCEh7?N֊9STDUEHE ]Um"=T:8Ju9˳ԴQLTUa#-VhBAJP/ FK 1!! ȹr@tcxU~ v'y~+~wz /ɜ]' 1IKMFҸ!OPWƱ?poP5s oxLhL%rmIJՙH=ne] I.ď33I|MUj1 kPAF0u_< v3wH (U0bXsѨhXC;+Ö1p7#R@#9BTՇY+/ d(9GUIFE8 w]&b(e/_V-D/Q0׋n]S 5,P$ngkv<o*9_u -,-NͶ7mhL9gTXsF\п4m楝 8$uu9L _};.r#?6u (dj]mޅMޒ<\Hب wDXӧJɢMs1؏wkiɤKu$`Dbu`YTVY5d'5Gz YM3%fQ; 0n^B+L;zppIes~?tV|J>/5gϩt|շNK'k(k?no>S}@֣ NÐj܎Zx+RK>AQ?' FyڭNPU& s<"(ЌѝVCy&/fe^Z\ C$;I- ;#3pDzچbq,WjM=!՚G/a鍏jb-[ܬRJ=p GB wq՚;Rp.^NvkFMR63#xU,dNЃ1<5vf σ,4'Jy$Ϛqobj .ꁗxQhQGR,]muc6{ 9gmמTVI1,/t;uBwz!cM F4~ri~UrHYe:h{5b65!Ej6Gz|}vpx#KcC |IxeG? L6L$ l>ѝĐZX,謊Lzf踄_2J|Ln:dDUm?OmN &5-,O\Q) _DGT0&Q\A:cVzö*Nc wv4QtJ<|r衃 W#D4@#Ed -!MtW Y/AN9~5`ME\ho,w#omi7u켕t?ߌ$ϤH7m Û%4k'?.Syj7s/-&4'[2((!iX6zߦ٥#Hd󻻋涠@e=d?%[{zY=[*&zkk$)݉8iC >28 96kGw;+65>PRNP9m<K2N^{ATogJ3"MG7e3uZ[\?*}  bqx&7Rpܹ"X`>c͇^TeblWaDefXyZkPUį)]bԇjGߚ,Gt$/iݚsֵA#ÐkW撗'yMw$1`DLJ#]FXSz>6mNKΧHUfGb}r7(1&g,ؔh e~n{12 =LX^(f/~mwh m)=mY &.Ps @W+2>և M 7n1P6oT2I`,d5wd1Q6az1 +#8d8Y d-@a$;Cw|HGM*.3a@9*)h `"hB@@!4<ȦU)W08S8 pA̤")j]]PCTAsdPPRCM% $@)lBrf*EW؊Ie\*xf (Cz+Lq 䮗^pVY1VHO6lO;VyU$-1 kNjN_Di!D]U,Y F!0W\cdYP (+$NEu<^mI UAMB B:IeDIW}i$`}9i]߭rzτ. X-cϛdwc?~ H vϡJэyjEP)l"Xc5Jb瀉 RJ; I(kzfOٲftdԎEn~u.DPaed}sKYS{Q<2fgR8|~(uvsn| #^ #ZԅxFS4]Y%nga&GL.ȯ:DjeJ-ڗƴIptGqE,J 0a>1Ij )c /?t2$[?n~ohk5# p:)ѬLYke Y띘@wZ1X2xW;% WH 0: ECw&~w\0|k,J8!ZrhNiV)\ɊI]hHIJAmri.FQ֋CQ?IQch*AЅ-QH@4-% !J4&5Nڊh WZl j"h!l V3lW LtETT@QJD4DJ 5UPDQARA1UDT4TP-RB5T#4q 1 Tňi)B )zڊ"*h QQ '<9r5F;RuM[,-Ukt* #]xs<(f{$6P|鵟xZ;l{z*D -Cܓ DS9Eײ󞫥N"54Zabː@mUNKQgO;#"9>K-tH/]AÞY\7x(fnk|3CVKqٺ^sF5zn4M4?4y&O_ˋe`c|hDec dU z \)Kr^iYUPF?j&R.t]uL-KqmNscˁWTR3|>[}pSQ&TC%!j?'kLmw#+ gùײ( 6WUf`DZVnoUZWb,Co;WBfR`d`>q]S^ L-'6KpPXSgV}8ޡsH-l9 $S&QaHTd<,jL4=&l1]#pyd 8sW!Or:6F؇=nXbS5l@e8jԳju\OێqL_h"wuըM[HWqa-z7gR'[Lq C4]`w[+ZrhcUEXF14 @H/( jk ҥ Nd2X"1Bhjbb*9'XMZZraẖ[hֲT%!=p^m**N\bF] xHcHhbJ!z( XDAI@:]PAU\@[vL|Sm 0tZe6SXܦrY ^á&jr>ӫB()uZ/|sb)6Lr]/]^\_2㴲$۹:,'{"AbV>W|;i㨒 wxs[b8]o41.ŨRd{b*[&01/j>P( Z# Ɗ0Z43h^وʇt/w9ѴO0dНn|; Vsy-V(_jtHAJ'8M I.&<H컎.dy_E)e'D-6otpa@3jQRdD2><2s)?3 o*; GUREֈ&Հ.m>E{JQ%P)%֘ +Iꃡ({tXߝ=sžXy{'YI~-Š oG> I;S(sb.vxEl!d^hD6B?;]uX`ꃨPnx$aRҁ1cx]BLQgSm@p92!KmFY_3cd] i ?g}[=gn,ؿinl.of&W*oٕ9! w{yު վ=V^FZ pAlm0ǽ ,ȉqF2 `M1dd\'q9ٶ`z gce3 <¨wfZH$!3²;ě-e&ᶝTr~Klaq>} }&QLM͹K+ݡvqwt1)yev~A~s^?D7W`ɴ4&rDT%ejj.-^|2_0EX5tsuw׭%W6Oϸ!+kǜ#4ʃ1LYR]0/NYy !뗚?̏Qzk؋-8LAk4(i.:kxzNA%ΏH\UDriݾ!IF x@HK HJJ`zSϏ1q1mSMT:9hIKF`]937 4z)Z)Bkd_rAF%rHXݞГݥzh.L*Ui壹,Ŧcpy2Ig AB B885E4$EE*R@DH9*CIUbPbUN9(JGE eH)&"*aQLJ>~?q7Zg+z >Rq}_&Y|}Z!&CAp= XNS4!ƒ 9Dcs% NҀ/y~w,2kDn8٨ׁ}q>C^&3_>?{"-'D?N~ZB Zz=g`~B~}=X- x4>7yԸ^q=1 WpB*9Fh 0P% C:a6F?{erTJ|o,a␙'qhӉ jfp5+Dc_ShZ16 Eo1Ft) œ FfP] ZsVy -o6g<}*"`3F(2dk l׾~$}s)1#2R/jHۄovR֭̎\$;5եgH)0c:`H1(+cD~0:ҘBjj4cɿDL͕# 8yyDgK~9[&.,Zw^YN&O^3B ]D릙*ևGNڞcu]1o},g[*R39hpebNAbEH5WORʕlk :5+_z.R̳s4;8[c83]~ߙtyabjPS~l@)@xFH4^-p5V6ʦ<0ׇ/G\ h,U;NG};Ykss 1N#߶B0, ?@!+zڝqӵz'e()>^%Eomn ӎ}_V+=-^s|z1wJV/z;@˛[K=,qV-u^bN]C:֛%&9ss{q/k( 3LI5Ѽx @Qڤm1]T,W7rtKp|[zSͻ+r-yr5~r_6n]! =/R}f=Rd 9v'>'Uv;!]K)Jڪv8f7g佛{ E/8TgU/J--lP뚻݅v 61cF}PÛ_Q2JWp}v?{$ k`ODlWK` B (}Q҈W0il1WjѤ IM )zI:'SHTޒGjk9  IozMΝQgfdAtue@2'E1݋.ѹSF,]_yr>ƳAp1h _|Q,z A ,$T3 nPD+JjL43O+-Ed9Y:$}9SbQjPDV3'͟~"&SsIXH CѓTTSY[a JHu"l34@C"S T]U`H,ļ2,S~Za$K" qhFoNkKDѩCu!AAwd NFR#d-Ӵ~ )\B$AuG:1eBfqoO F5 ѥ]1`FH6B&; "cs= iGuڂ¨ob Kd&lZ<}5N#ENhC 5Oew)QOn_5%9pI`\`'7(!wKpBb]?gzhxOjKt>z̵lU&'7Tf Y>^PBML^\`4=OG+``J G&ta{[ํP1 کmf{^p0T`4,r 0s<z;C['|Ceïq:}`[}J!1/MkY젴K"a9)KjкN廃-  0/OlyJ䨪h6o9m k[vXˡ3t M`$#h#ZoFiY-~,*a)"RǐzmQSTĀrƉsPD#Ze?i! b"c@! @"/F9L~kfbSfGgCL F&ZR);?ȅ )LJbx' CQ]?l z p+#ƛ-q%^#q֜%Ǩ>9RI04tS6* q - _BþGMM_)!wBXcOT3*8b8%2Iݓnʔ ])c$BoIJ W!'Ct=z1uZ(L'i^W/vdR(DTDR Zx.aJPhn e+/AeQPhcI#s|<"} NX 7#G^Q!B06 [?Fơ="h&]`DF,Ƶ 6B+ݏw 8l/wG~UQTA'u 촯b1 JTrdk1䉜l@CȄ>$:e !$HB yH"rW".R1Q 4{=a_*\ˑ[m )a "=Q!.a ,_܃#}oDH%CdB=U x2~@)!Ld/E#ᑗďN)Q_&?>H$[W5ڬuz`br a{WxT5AڇJ@#n q* ñMdh}R@y\q.ZX+c2~ϢQ ǗF/39׏N$3f04bА" |IK0.H< =nY* 48DA-f9i#Xn9J'!\KR d|]%Jy4bO'@ KyP7^0O7ٯ0{ vQ f_Do[q^耿mpbe<A3fʟk/2_^2nu;!T4g)}AzZ7.RDQk)^ھ謏

1$Ls J )GlKnsLvȄPTR݈$㡢ѐ}Z7Xo4uQBa~R.fIνN,Ĵ[W8m:{DhLj,0ɞ#Yh4DjC"E+$D޾xYU{SHyWȃ5 5ܻH>-Έ IͭyC[1}~$vOx]f(X+*Iuښ2dY Cb8aIX[ p_h o,:_D/\}6 ERmFSqtO'J1?=g-oh7]O7 %#[!4OUR ׈ J%sCKOxZpoT $+40O:CH th=+eY%gaqSIT q 2N ^ ^e(ϩ߹||l >^)g;`EG1tR.UPU@xW[8ȩЧu(;z:BH\4@쫌[J{IANe<> y 6{{ѩ(G(X@0D5OG̈́֊D̕t܀,s 4N=km;qq~ yd&MYx8lf|IHL|Z 1I%c '& zؗ6CqGWi6`f}CDC$Is25&_@w.x]sÆc P6Z'8X'503Mٿ? X rex)YbPAHr*pȶ*mLPh(5ge !JcG Шr'bNhtMyb΋`8E-L9լXEN?:л< /qXUHfDle'٨ Q5I/G/T'+ tՌQ_#J)i(p>mcbs$gd cmWp0H,bVDC,c^6CR(y ɋdAAo_:zj\WaJ 2Ԧ=d'јﻫm?Oybnh!O#D 8k͂Qf(liCy>95~P L%e1wuFzA4c.>T~_X(iV$o#Pui_`K[c̨LG1#{: M7j[MZaO"i/Gzn+2бzgs7/F+!'5$D"`Wڍ8]Uc -W<ڬ/+!ro˧ѮOQ?WUӜAD: XFEC5xKey1\I8{,~+dgP 雎"DڹE[ZAm#FzNJ#_'n.pIvoYH7e7 S0Q}kk{ *,^ǎ[ro,1VtT엊ϢDY C TLO?;c=HK\Ţ [h(JY#'Ti<^ 1зOv: >,ZrY[_6jlq@]^~v3<9>\▅2I1ݬ ^R$:pU}s;wMiWXfYRZk6r.-'y B1!*LhB"aQTQE'&@2 j f ("E-UAFtPPt9.@ȃ͝;EXjO|ۯ_{})D{04KigG{I#]L?aVխE;Y̪g_iunxӯ8S7<}r !,,䅿-v*s\@b#{Z T3J[ Kxkj9AG24'[ ɚ|_#a-<*܏% :ĆA4X?]}ޤs8VHQ_^JߝO~o?\ʑ+F_ˣ?2fABPQWSO$CEns_Aj=I R̙6J*IĀR:ap&)s*]+uK5g@wL9_1RսG3Y8J+;uO]k**{F9'u?{Ƚ gTp\>`FV%%$1z!3Q&3mY Kn ݳ[NaReiZ~Aj%=j!/Λ`N!>H)p'mZp\KbcQ RjZ੆MQ1Ԁt2v4K~آH4wϾmb&(D\ 3պ JyaM۱<|0*W/N6.ԑp5*[w%_njb[GI>|RXKRU0^_Ӿ|W}r J3Qb'h@ S0>BDGfV'v-?ir!X>l[ ^qC%iEd8@)S-,cqĿB {C<-Uk;<GMBls;(%ZxϧXYV`p挜]b dJd34Zn3鑉ͿRź9b@JIO]34s=p+sZɕ$IԶO1#>ơmyONtXg c鞻_t eĹVz|ܴYtA\+25``WvtH=H*Ǜ\i `K@1r`]kFd8JT`{6#VLv@A2JlXWΘNCL]={=\L[SS4!!15#S9%3y)loc?|`g)Zeʣ0`2 G+O<(## V͡l'3{2c&!M,.@N零%])Fȥr .2{*<['¸&϶7 Ք*tB6 0Xl{Fɍ΁1j*X?#-)2 $U'‚TSe pE‚(j((@@@yrD,N׌O5iXj ,w Q9 .`$Vdezsa!Qb aڃ8S2ƓS AƄ|)m(ϼLZJMLD6%ט~d&n9 v`#,1"g?Vdzd>SP.P`{LkR͙1=1)Mys ڪDAWUVi"Ly5l"#a<q $*6U[h#:U4|΂mԮd"Rֱ<35F[RekAFKg01 ]‡ XЃ6?t2Xϲbc~5&i yi@q\)T`Bt̃U:~GɫoO ._ʝ/xEw˜tϹA1T`OY L]5[?XXcvT;x8ܖ!L?eYʅ(8qrk Y%t*4ȁ*U5.Gr(؆&oi)}5_)ĢײNؐ)h7&#u]I3XK ]UrV ღBMnrqPxq oA=TmSҌ1 E#Oծv:Bh4 Y3`fW!2 m=%jZ܈)L~Z)e!bpfm/<\ۧxMqt$ Ok<ɃqS!UJf[nVk1=Ⴝ7zelq%r0$du-n0UJuq6 $8d]v혂v'9)wޛxU% &]1jKz]P3b_B̩ZjcX-NSi/%]w/W^n[u0(riIϾI1,LU4dLg 'd~JWΨFLXB)tzyTE:|׀fM9?eJCr$#]}*zxaj[N إg>F;e҆\\L:C=_̅lƯ<A d7)E%Wĵʄj!lpD E?fL^^ƅ8Q B Ăqj!P![*" x,V/toW[Rf}%Xn3`dQTS|;_Y-$`dPufxq! AE@GBDR5 P(Pҥ 404I%MSTRS) 48BHj24KDKHLUIQQEQDH l:щ`E5Z9\-ն#b(G "m4AO Xصsp4pf(h*!j )"i*"i  i (Xd !@b%Zh DQCL$@D"@ȆTr E*ď!s**hE()ڠ) J@S5$2CCE  STKCE%1$HDUuuQ;c6ֶ8DDDDDv})FN#^3dSK#6o&CY߇5vC%kAs_+|[]/tG_M cY6([/8I RI~J$&`='z/ {}=MmhJ+se{tdDu-#zf.=?On:HGyI@̉a!sJ7./kDaҽE0+? B4629x^ /OrPbygr:}cc]^Anr7LPWڞYҷ)~Xx E jr(QDi{C3i6bCjB_C12 M&U\p7 }(5u lr*~ݵQX80@Zth(/_G|-j8eYYdRպ%a4";?2j:B54W(^6fCя۱Ҧ#==Zסݴ[d$:]|A^u?^Hb6;JTc))S</~ƭ~|!꿻vږ{9PK sb>|@xwޜՖ:#{L D=#ɟ:17oG}8K|T:OwFdK 'Ko~NPwU1xr&0KS,U N4=NMQPN>Pѿ *qCǛqK. 7m^-OFTf*M?}){F'f .n^ZPbL2AtU=˳HKa6.Fl¥!*%&&߅]w`6X'zLAsJZp` [LᝑpX"n +$.V~CK,m;Qdج(H&]ݩ}De*E^\:Z#צ%S"cTs`׎jg&"zͲb9bYTPcDAroj|B yTHkZD6`z $A0 \r^4FC_E?l;&EV?$=rQ^-V\Eftݒw.Wv&Q/#Cɵ-$;_\kU/\d(/-tFnQvd^)ro4**&_9.=xldA&dgd2 '!5v`s̕=Za =feFIDSWQXB.l_+jcϘPF3^ b!_D,xDyEDk:'58sAb̆>\|H/ LjЮ=;y&vKxԢ*+HSyi)B-2NuA/k_G;{vWE6Xm0Kدlyr,J:?9eZJctlKK::lHl] Q7wV3~K;>8>`c\WjiJjߒwQfS45@0mE]e#9Żf<2M j^?BB~_U~'rZ?_9T~ Yf^)B\/r7r%i QW@ YC;;d&BĬs2[no#x^L]^cS)<`Qc-; nK&>||ec%$J 6Cq+RXKհ|{4&yF6B`JO2g \}7HRWO*u>oJ ?ӱn b0P` ""Hjb( J *& ) VU(8h)iBM\"rD 13HRLȓU RE#QRUTETl,HIh fA!6訴RE5@9o~O6Q.k/=\pJ÷F"0-5L JWUPNl1 *Ȅ!˙v\1> Y]/G4;(AFN=&u-J~e>_ Hŷ^g΍c??y:R֭}pp3 1XEb=0e!U<#B0Yh:qf_?E/ \U}]0^X5zA #<<^:h-cdcvnfI귚XVD'bU H8ƦPPFuaroqAL-2ljc0kU YXTPҀTGv$xvuTe>B%""`=OPJ- +펬nH4A0HB7Q:[l+2K%0y2cJ>UEՎCi-%6͊Jd!6ey_ܠd.ƼL7mi/<82lRSՈ;8 ȪO4tG÷:O5?H3 ewPx"uiP J mkJ(VFob[)gyYMnjؕ>U5\G;usdU„TOcmiZ*{:K)в: τiS"R{pD#h12 0R\18иϖFE)_)1Ci*ˇB f9& a0MB[J"GjŐ,P;)4 f4VJkrNdC HHGTկmy!^<μe` @8|ot֗Xm (SxσF+s6a3mTux32AO)Ɗ#! LaΙmqN wH 5}LPxQJM3iF!',OW^P"%2Q8.qsE@yPLFƀ ;8cQo $A@TTTEL<٠"j*$",j=p&-׍@q{1%*("J"){ɡ^i)Ju2ETKan%94MM-Qs[:4C@ĭ5CMP@UȜcbUThZukE2*iQ(h@(iB")J\yr< >̙^eR7Cr{W6 ^id{%c1㧪\(>TYEVbl_Ԇ SF}#e $`Xc!M BL7MFnD kG͏ktԟư"EˡV5Od',fFhP'.ٱzce=D !Jưɖdi)up16kԲyuޫomJc r[gt& u`#~^ e4V ˡvR eV? HGR$ 3<$Q< ##j__9^Cˎ ;WpqؽMEVCfDgx?)((D-ҁXWNv!-&Ny ;z3:]܄u2 9$V2?tNÀ(ɮ 0G޻64ۚ%;0RWJuĐP8  8M'PB<"$}BH-;z|ve=?#gG?~?-d5 I@`Q`\qۥy19 6|D0fW"t]Mud}`X$9'sκ//H7ɸ׈%- R/)Nw퍨YqO#WOHL@Ѩ*l&++A2_{LV(TBS0udE` pJ$`@nˏ.wѭnAGhlkBAt2U;Ƅ\`R1stkbO{! @zR)V(*.A%wOƉ6ܑ2cG dhb"r=WJjjB{ិA97建j7auL>}9/{6gvj޷CLvan/kOJ)~;öjXVA"q.A?Qsfֳ I@4AG29P~#>';z .1#"&r< B%}7*-rWp-Q뱔B* g"ReLA%H7|OZXc'WkWShk1h*0][ݭ Ơ&_ Quu1 ?E8Krk2&tsk'?U DҊ)+mI3 FN|f]X/3Q{b$Sr h.l5a-tBي~K_}oQDLDX̀dJR J(FHP +TLsn*5 P88HPU1D4( @*PȆ`1% PQPKER!f-`hgcb"@?Kĭ~~7C2(Ncel[RӃ \g䏆"rY;G_IiMBzi=!~'ނUbY[30YP'ե!e}boփRLC-`o/2o a=_ S;bQ2 4z1G2PӲ6b7 YpKs|ttR Ϫ}.؀Q\0al~KΎ{:)8y# Жs/R\k_zVطC e6z7WP\ Xci{ Oa)A2}[ƫ,BG9 K$84TRFB"9[/d:^Y<}?U*T }I1.o]Y:?8)oA%SOav{ xSث2Us庙=|@FN\:2 GD/p!Q:E&` !^H O*ޖF:EGB7L#w!"yv2F`-לdqIG_뎬BC9ޯ7 ]˰d386k!Sqzih)vUM>R7:BB3EiIĻ#dK(RS怅qp ݸZhN"hXtq ʻAز׺V{5y-ر w_?j>BaӮ Ȇ3^&aʹJe$ˠkYZIYzqK!B OV]J"69@XT @_9N ZtAx.jbcV;V=2QNZ(-d-$i2òAA=PAOr6)#*e6C1D6\,\G9dD5ڞf!vƇ<3 dFc*HXhfysWn!z7ry S1nBdǛfS cvMXm{^Չ{C6Y4 I ƂiọgvnwrîV\쨫1Ieb@= bwp˥s㱬@~6ĐEhvY72TLD $Zc=|3%ah7ʄ4XEz jtJ >ץsQYwHZ˛!ຢfƸmI7($>O,,hE\RX7rsi r]rINž$ 4Xě܇H2#09{7WT3>D:! %-6fb 0ǖ-?N)NT?{m~UP͟5,}JvNǙc˕W`9bi A\IOz"a 3zF@qӛ+pTRI\FSH. 4?:Wi'!4 nO-~09pE+)m6M%[ID?f l(HyBho&£ɣs:(Oi_\ϊyl8MPYav2 =Ȧ^_cetԘy$: M1u{:F,d{jA Pg1 pYW =$l{p0-9cD'TRnJJdF7`L+>-aoB&PHj+nz>dD(!bJ,Yc2_Fՙd"׫8EI+m Pa vsݫ, ߲dqPH$E;Đ6 IB{snb.<>Z ;Aݯ"b7Iɯ"R =RR==uz9o 8 d!n=-(E\)"!+ PKD4DU RҀ(uDQ142Q*Fe (h* M5(J d"ȫB"&Dhf@ cX"klJ@ 6j6% Eb1"a\%8^@lF8jokI7mO 3MMXqX~pR]ԓȓ g}fN- w;/Gl8 e3h%qʜ%nۀ0MRĀɓֻn/eZ(ԓ5vpʦ2 UD;(J^ߟ+w_p$,uWJ36썕z: |"Lc k1zC)hih:Vt?l񖹾蝲?,[4!EW1FE~MohDqHz\u[X%rH;zP!KOgGzZ9Y2dEnP4ٶ,?T7i-w2s-S/4ؗ2ήQX;, ?qŰJ3[> .3ȏDa#dѠ^,WܗlZL>:cZ,fY# u HXCQx$pՊBC_ W<[;YB#]u&J?ߙ<X69HCǒc&gvu2'5W!!A)&B@ #42`ڞe#@w,!yy^>2&_I"8CIl[|fGYH)/z_[B4W9 oa a؝9wO W@Onͷ'RR,tb"c˴QTx^INzxCb/i4ݳH0>5ӟFx$ܙ=c\n] 3'_y ɧ_H4, 5G#!4"s_a 4ߓIE Sm)*wx^Z4Z"6pw eQIpgs#RaI*=(tzBU@lynr?TIATEL"4D4 %h(B*hh14J4(s!C<ա#JHR.( yRM%8 bZHB*N^J̴ԥDHSETQA1ID\&f)Bhhh)*οb: TASA1LA5 MUJQGBNQ4UI K5CnBR%)H+@e,񻂕(]Es#EQTAcv%* "M$X*&))!b9(v PU$U3*&zΑȭU[`* Z kTMAIQEPA0PQ1M- J(ZQ _a<;bFтcTEQpG!dC.ղ}I-[h=P;?.2Zjy]d/Dzh~6(Efc,PD  t} K;{qr,6\䋯U\*{j7yȄ3DMvr bd/tϧg=w ^W˂2!;?כe?})!9QV-Z<+9tWH2憴'L@@W'+L|͊_jjj#~$E?ӝ`|iIs-דDx$>˿N arrttLM^ÈᏖ% CѥoY{"Ù:TEdzu5$cY~=x-!(f2쿴, kON}nݟN7.D>!EDDξ>>|秶,yKJ+WA;f@I&h,G 2C) yֽMRzt[wAW?m(U+.gOm0Uo&K{>[E]2GI{CvT:J"YeKQ|&P$w= :۝j+3<9u".&X$6Y9ɷơ90gqJ!I;<V U<<|z<+:ck(wK-ύR'.h,/.T}Wy<{@ZK͕QGe'dA;?KsRjMJ8gvW:1((fV!b@&.w>l{b/eK5ͩɣ žrs_711K`;7?Z퓐{~&\[' W>N~okH(t7`@y+xTӥ6AOYjy !s}NJ&*^dяO$R44,!AO\0WyvYf4-6~QyߘOO'/ʂ`?) !0mAB (j:RT =wHNH*M3ٻޏUbD2dP {V'ڷs^5˪yKP-~{ tY;uVA}kW$[f7 ]oEfAnf*3̙kiGA:ό5"Yl}7C,UTH"v8h: ]K!} 3JP/!$ױ0WꧥjSbI /ݍglb,t3Jۄ(;,O|a U#E$ vOcI8pޖAZ2BF$$AE0"cn"ebrުv H XKyIL(# ΧcPAzvMA %M,uE4"EcU;pw >F@B .Ub: \-S񯨻 mklY&`u]o&u].&4T@G 2gb=# Z'vdzDHN۝qk`ls6\ro lHOJ`~jM}GNh4"HȑIt/}qʮo[>8ͭ/4 'u0?=(+;\E $K7>B&UEU%2]q v nژ@x<y2$yM 2·atYWwUS,fhr2;Sq^bv7 \*؀9Jl:JGHĂnu܆ӗ0"D ±i).ވuꩍ &,)y * fp."K蟁܄FYiCؘڝP.T xD0y6Rsd3 |vdzBz-w%.YEL _ QLu)0`A)8~҉˘(=hB<2O!0Ǖ`M6Ct)ti 覂9z$hċ%榿Jf:lGΓ@d/(2x%AD3jH SPS VMVw O5~vN4lsiE;FYh@t!v~(ezTJ&+Ǭ@u! f>D6f:aRIŌ:" iut0+ipN@4Ka,\3ZQWGqH#dsc`m ?l%/WQs貐MY0j1DTQ?]t ΨR("L (zUL>eAHl{,8l?LKKM:jL׺JSƙT'XF]' Yu=Y~]1}n:Ф!:}4i)X\!RwЄU]EN8WTɢRTR4Slwn/SׄN3ib%,xK GYv 9$oN)[A<KTda QѤO.,@2J1x,ݺ`*gXT܂)URz_4 ?KtV$nVLL0#AB[A?X@+U Rmtf2!a#U<Ϟ|zTBZBeCRn @_]GO&5<%jN҈Єs$I$ B+9Ă~ŚbxBTY!1 Q~YD8ȷ,J2 OAJ{!t^ˠwan=oT'C,A JQ Id@S#F)8O8 e|~Jsx"?Z|ȮZAe> @^?z,?uJ{vemawoW% %z# ȫ6XQ3^)= KJAl[9wr{"5SyM7A)+ImNBWa$ A±W>nĆt7 {vb֐XÄqꪫ D6cFGghw IB  <JgSިSjL(\ pz.A9g󿶶;poK4Ѳ-a@%Jof,eA[YQEki]YiYGmdYsH>!uI|4G:AuJ<Ɲ1ya/v5ǚL藊zRy5]Yl\-cl_z^%2Zb'Xjj׼9߯z߅05tE%(<ν9;?6Z-*x4lg|f<"H QK݃mhmBR/FA nZd6Gnfj\P{C~:]zM&3wm~G{ a:s\wZejA8Iå~W}ͽi Q1BF'i!Z m&%J*&j)h*$%&@ԅ# MDPS0JTDs&)T%C(2QDV ) #CjJ"ڍ5Th RCQQ% UJihbbJ(F\ͩhԖ)4i4ј&Fv5@UETQ 9rѢt 9+Ek8cT4s]j@!@ECH{%:ձAՍPjA@CLEPQEt JsTEU-*c@Q pPМL h( JV"Y&)N!ӠmLlQȜ"&DtPP"SAژ %fSJt2DİM)(`J4CBb6TS(h"P$SUD1S}}>My#ςUNL/so}'W8# sfQх./D 軋4"C(e=ys ꮚ\mkkre;w_i{b0ԋϞ^yhs[}Ilu:<iS 0> ~us\cedwiC,FkwRKi1~un)=F%:-sJ[xVohbt " sK|,Iy-SyxVʳVBYu陼<)m 'n'Z2(%MNO_Ey q)i-JQ,+ڰ9"OFrЊ݉$}Qr܉ɒ5vZfҽE#:F<gsUͪwǔT]xF* }B8!62f :qRK ) h=nZF7$}I{cvk犮=yk^T;K%W۱(}"r+gM! 3^7Navu펌n)-j eKf ]+]XW[$܉@w"$Z xh'"3oE^ĵ'MS/CLٻ.Qj9I|. ȸR/DUXheL gB@*^S[mc-4~3}XW&~WzWK!٭E/ݼyN[.%1W@Ǫ:1 !C% qx6_.RN&SW),7#mjV\IBR N8pvxy?jh k)`G: B"w#fd6;بt։B K5UjÈz${L2C$b0|FE*)IF{[*1K~8J n~7a\A6s@B]I9mVim:-(ؖ3+pR3tW5"gS9ԡs+X&oϤa9oƹ\vR/vFwJ$еXƑ@^ ;S@J#%G\H*/lYF03 hHs29GSG^ǍfªDapԾ1\PLsv7QLb Fż5 ysR0 t3Y65Q>:*,bAξ7)2 (Ȧ7y,tgx$4;]B;\5VdÎֳ)m?oJ K:DRWQmWzR UI wLYbZjy9H RW)1+t;9F@QVd"~s3ɔBAh0r[%! 0r$ SL @&* :}זC4E Ԓ=A2 s?b6eM֧IFNUj6ˆ  x\=0ZƤ83&bvGnU_YJ[c1nwY/؝TDFGI0@dˍOᨃeOT˙Mc +%gjʍ#qHBzM9)R5›gsHR_80 ,rϹ"OrCDj2"?Ns{yMmY!\,⡆-J#sA֊C8_ B:.e0UuZ 2Ԓq(A#?x mR x@!rgRuN}ߛwGeC@ ˢogrgp+BRI}ENR2" n5IUg3} t*W{us1wͶfE:1vW" 3 6 DR4RfcFWД*aǤG횾j_4lNO ůI5: f%B3ϝuLE d R[bJ UKBV%KF/6"Ah>SuZٖbND `bVv 6pr'?}JTS,j6G'a^{!c7 g1pdr'WCqxΖgB@迉ZrSd̷0C=Ur?7AXa=p,ԍ4m2)>.ΎD$g;!um?Qz,*|xEِ$|`t^ u(bxbVH*CڱUisD\zqnqqb AL˟ԗ0ZpF( B`tU|Ԯlm%^`Y섨b'~eS{~L}=m*;t)êY,}XO):2z㗈skMD)֤)Mb:Y p`?iCdN-9ڧ; ݜۨv|ڿ/*(vKQP`iEvd#dZCkhr^h.RjDJ g;[wx䥣DvHZWIrX'JQW&*dPxw8=5l#csfOgH]{*akE6J^ssh2qz>~𓮜wTM DqLN^Ecl~Rȷ89 :FsaRuԲ"h#0C{?ƅk4oS@gynPݺsFl%ED1)cPh{W;8ATm7#w5#T4M!Փs5I' Jsڢ$&a)*""yGjy/5PRSP!"q CMUk-%+AHjBI:(*%ז '34P$UI+h[<EᵍP<d{ѶV'ݦ*phplP @ !ʆ4 uxեZhDᴆv"VN+dq@ 8G9+U7Ŷ= mqaI匩?mE޹ هQii*I%Oߞ"H/&#3KZ=S|9*ёT<6Xb?vY po; ,o b~M?1g~>9V(E?KڂҜ2ļoq]8U!WJ8ݖFV-yF*k?w~MyIiӳL]YTacS(3V3C`sms6։bDG`Zܗk۬3 RuZsȲ9+PA]Oqku?2N K˯zzwAM`aL؇;bKſ/}1KRRQ|nEBׂ1-PW7p H 0ۺTBmo#,&Sk#N\;\U#^Ԅ-iÙ|x_H fVѓ}F佂Lyo6bV淗pDʔNr"-:zU{n,F}䘫a!%$*%a׶1]hrww$Bꮃr8Q^Y-gqUO>{|56a?KYPT4$X0$b[OU__u]#4t>F02UЛAsTWrdn,0.yY"Q |عr^2ߚ~}>q,Z79gi)mΆES.v39SE~.s9by2QTOzܻn'r:#[@ ^o؁YRB'bSp1HLޱwvz߸5Oi +af~T=>@MM8Ϧyy'N]s)}/#,p0Jx"Y4>TǬ_Cx47OHUczn1t^ _}0gUJ9YT<E5k_"\Rrs&s;3 `*LwT4/HZWo.h ѱd \n3@QV}l= !U)oP3uKëF0%Itܘ:mE5[\#x$ zWG^`ynSJ@y22|YPIgC- T\zRp ,|ks$|^d)AHgp)ىZ1AcpҨ"OhCgji=>x8E9㟦R:-Rwji/t==ۅUk j }TDC|Rs؉+󯀹(kvmb .@""j)&XIi)b@hJ)R( ( LAp 45AZ" #ީwMR9:btAt(%j:*&H"J(* * KST"u\PsI .dĚ1p+4%AA%DP)JQq$(Bh BJ*j((/1Q5Cq윁@4RRr`.t\YsMh )" jJTNHRnP0t+\Zc<&B)hZOe]ҞRIOJQf}Z~s={wm"؏Ic%ܚdH9#} B~,pYh%;z6WL /b4QHO7tfGǾ)ΗW>$Mؖ&]Ք5& tIdVoG6هD@joE>UJ+6eߵG_8OE;((f쳨䀏#+?^O;Kޫm:2<[T̞ߎ8 (ü(_e)%X{_i7Ovy䀘}{,݁^ț)(̸OĩZW(I}^Q$YjHa( 7g($N5uۇ.ܸJwlr'{i@\_cU/}^wRiS |iaw <K}+^ⓚ.2ȹwu4:R=}ĿrhsX虶`4RkQ\\~#0_}+.;o~~)BύOyZWL ׎vՙߓ9e%{X񷓑4wc^z?ŕph1O9#8z,$W8^5·~үme> y>ɯ~jl(GkR`s!qBY!IJmY'YnP<7O ]~AKE^RU<p3ABWIKkrnl]V@88:hׄ;?'iRB͞Ùc6RIJ>?Hk#Uaz%)y޿y P =e_S7C?pBɿ$\OhJK?ezy7tRDMAZWA1""n:~~5$ |@o_>O+と^|՛kLelOMԁ  ~J*T l/nӞ' ?u^ (ص_ЕhKX0͍{lSXtFŹ\2e5n(ϛ} hEgk3 HjfQs酤kc^o4tt);gҬD9B2뷢uRq?kڿTF_KLG̲~*+'۾rW6,B{nQgs<"#+Y>&먑|f|].e]vnpRեaq-\Zhq~fQc~{n sjg‘{*{OF'"^cU+o%ob5R{).Ɵ.∷"dCcnbGWʾYRl :wwІl'I\$~q3M0S]HZToz5BDaAwcau5S < mU0"Cog?4ryhW@U5W 1@a {m5AۗVB~~-}dGiZ1Py>7\#T=c8;͠br.g fw"_QHB ̹JMG4NHDkEtwEҩB;0 ozfcU߃^O)Aah#Q\@_.  ڒThm|QqFgrwKGO +=?e}ƒ*>f\UǨ< `0n,8rY\s(A2]|  n]lߝ۴x muo??xO(*)ekk3)3O<Ӕ[>ZLlce[:rݤYca*#@PdnPO !G(ri奇4?WQGb{ʲ58 [|KJ`~~B !{!_jnv]4Sw%53HVQ$zrjl:,ED$swz|IczoW M@eC}h4)N](S͇eY<_WADOʲE߿=Ǭb$hsF(_&Lw9Y:ĒKɛdcM֝O`tغK(%U滮|O -zVC8x q\2|F}$l>>8'Cw?5E67nKL G֟$aF}R }(4-GLlajVt=ob-!D;<_~eX{R/f~flp5 ~jAS+d+Þ%H̘ uCdRܵa}"VΪ2=Z!aHXF oWB< E&ɸj L8R71?Z0 ;o.!Go3.vWw- W'jLqtxǃGk[.DB}GL| }kh|~tf)GR⃦Y^0u.H(![_]7 }=Á5N0@!b0%"@ <`Z8^Y[P8c[e@tLd+FMF:S ȷ + IH^kO3:yIS)g218@ Ǹ?'LN 7]:sxzk%Zh]Tk-ŽGQђjQyaƘǀ?HS.85S 4fRx~=._CaQՄW[dsye#ѽ +Ėߋ^ĺ!ktT'dgiI}*b@dy@~IQU?Ʉ)hIKrKM}@/umzZ]zQ ӽݰ .ߘZýV I!vM#իOJ7 zx~qrw _}{5ÏH.z_ښ2 .ubj+3+AXf "ڙ|ƿ^߳B]O'8M^gӖS`c;f~mwOsg2GH&Eg ^hK#0 ΏY0eJj+B͟U1K3߿Bi?_AC4@.ĎwGl< ]4B1w&aELi>y|ȅ9Ӡn7"nC zro*?@!mR!TaW| UfuWU~ǩ*|1j@?rsrSyt# ل1F]t?h5n/э#KA?CRk 1ٱH߷w9o !\Z "wdɧ/hE<88p<4# κ G8<4P.*4S籊ﭔI[j[֬ٯd _4mSV!*)>`M'MİgY ˄Swk Aӕ(B9jTߖ7=z9c[.$f ͤh/{h2_ eO} @$F=PYD HL2AEm <\;:_ѹdT@΄,P qKU.ZJ뿚=뢋V=;;puΏt0CaDx0Q Ħk~;2d '.EÞ׌40W!:G_< w=1$7]<#b0>2||4e:v(3kYv BӰڛq) WcfozfNπ&' &Nv%dkɤ^ުc>)ކmκFRZϦ84w[)DB,j ݭ[BX@y?6DP loM^yZ/Ε^a>kx#$K_9x~K0u՝#-oxˍ1HD]m& GWGӧ۾+r鿌OUbd2~qs2Yd1/->zW?5t7g1]&F=NSY'N]U eƳ'-\AfK]Hy~8T Y_jGCnGko7zoVU,ޯ+y~*_T` 8C+ e%)Du'&sǿ{rVEQ~ &ce@-{>K>E*~2:Z[XJTpg+x~w3IڪYx$…n-A> 906ۋN(\IA;᠇aw\Ad(f\x }KthLna|䪜IK/ &= Se?~&7֯2Z>]Q5tm7cMyH>[* 3t?E!mはGmxQ@ jsy _g:4dF٦&7 e5iU)u 4-o *}-T3ZM?~QBtD|,(+J's :W4QۙY'}O/m̜y—z?yU~ OSOOz[Q..Ch<Ϟ{ Ӫ{&k?.s+o@DC-zWDqebt4rCh0ӊ])6F^_romUŪ½vX`/~U#\ǸA :\ 9V H`a3kT@,grVXe ~8]xi?ل.雏&OCY¥DkEo!GM.y荗Վ ^TOѠ!x5F0kZt'2Mx#3Ʉe+׿,3iADb}WؚDbS+q͓tپr2.gG ݥ )1׮hΤ$~^R@O0/#i}$>{WZ؄j0wChn .^&dSŏ2IOyX  5S(.5gp-RhwH뱖AnEvl;NTco7 ŋ@j6mI,yC Ū<,H `тS=HJ HŞ=$BqicݞMߦϺs"e=Or<,$Ǻ&k @,/e,λQd X8>#(eX!LプVJ7LС+Ul |`4vo{8~&[sg>FϨrz'OLBY6>%5~`vvk$z Z̡k>effp@Al30K@+l j<'n+[ _Q7'(@6߄6mrgsqnth %{X&Zz$!t8IF({AddWk'SPoh~T2ϼ̣Y:KչG\W^Wf=$NM9ae*2:|+I:x=^ ʂٴ@;_Lr?_`WJIA2vz߮=v;,] }y?\2D܃qdfW2El3.4@ <9DW: DW0_(f/f3W uRNDv8fMWpx]ϓd?I/1ܛ;i|5RkU,̔aM3'!p3oJ{쌞e'5A +j6oEz3D2w h퐀B L׾"i}|j3o{ͯ~ ALKC6.2 c' 3bKZ$w8gGگRÜ(g7+z|g3)]NrM]{5V<ɹ` %BZ35`/;Q]ljUW%~ S x+/L3*`:x>ijyYf l l.]=hv9+_̹ONb;/xs"L v1kY ! (٠ wZz޶NbޚF HH|BHZZRoXʸS9xW6;lgcY_U{3!x N7b "a6 @ (;|'9#<s˷BJ~Z#KTC*3{jO[n6*h  ֛Y3}E(`q9{@wsY~`y(`y!XV-u$?OMb PҲ@u@ $5w-Mu>9 F@K}Kq t?P`)Q@ ɏ4 ߡTH4~t/)#cr^_ge;^R$MW<360I_#! @qpHxsW(B\ܱij~sș HIL&剉 Aڜ˂xc$I!yv`9hNdO=H\\hmv[]?arB}vVC)t=PrJH)*h>I@q /W`mW48&a gG5)Y>Nx#]x4t0Ak\}.hBUclBM̥pSww>g⻫ƪwєK۠^y20;Q݄J÷_lIMoK9Mc~+%Cg 9gKyQ dy"+hS/$@~ r>"K}1gDެaxܓ8u:5&<<]au{c$KD!=_b;|,zrT]NW3[R3U{6K-fd=088_D^M6V`OhcWfj.{C!E Ժx "4jX=}m$?w"R|sd4'AlLz KO~X[/ϊ[*U' w9_>r&az3bWO3蚥 ‡df~PAnH@wԤ+t,[/@!3a,V5t%puQGrB mwȳ#99)q<"OVpUDWnn5~z)~S%>#c~LfYP3I@[8|ߌ'aU@*-9_O:n'u Y~QRR!kboޒSDeѝ6BWl )ӝ#9;7OT˼ʐ7).nI%N@&-hZ!òKɿ}XfqKlw4,J 6i.3LwzO~Xq% Ku|A.lU&yפb0gnȩ) x{!N'}]Alyr3$HYӎWظMq"k=Ba˞K@/Ce*>wdwo.\gb4oܜR9؉|D2JpIʇH_/O %ḽ&tA"[Ϋ|k|sJۢx NInLM;M̤ !q>MC 蚠ζy9$^ˇw8g"Zy4aBTzx5 ~q/Z1!>2]6"; O{gZNtMo G>!PhNҗO" w6Eo|r_Ӎ;ob c`|dl0~A`P29] kjNz}{|\/BЄ)fZi#s5@T管oE@L%g`J_h 2hޙOA AU 8Uw8e2˷zyٷ_p5 lȽHa!$|`HR#̈HSL%PELT% Ռl4GtJ- Oy|\-3QsĽx;Rµ}3V+Ӊ\kC;}$!_Je't´C$\%jM#.fڭuJFx}mٴ[ek;+PoIدoNCOa7/z:lBzS9Ct-/RD*Z}l{T_0%TjECoq |; ~9=DZ]b$t$gvOyŕdewaŷN%z61|-DŃ&fVM3IuAj3LY78@&NsXgFLY ~B!m{>oEc3HΟȋn@߼bWB#:Y>v s5K8M,+.5 HLsb켶/a^S\Ѻ!3Zq+egl#beuSorGώ6ʗBh̎'Ln4 nU}EeA/݈/$ʐש|gA?]D)rA 2] = c?xT̈́!0(0Hˍ@/gO[n.MF~y>RAr×ĸK\ H1a.!(0{\2n5W~N8 dO0l;$4Wne,ɸ)cKi{qg8P9YG뗍=r\dgo@W∫yOjg;ĭŷMmNB?V{O QlzO|%eK+yǞykdj}+mc:MϕO>TG)WN;*{>U_+B7A@MȺ[vThv'XԚ "I  WDYۣ}OԐEp yZKǑh.nh#XBVK7%1^SδBv<5#@^E#?YPqj ȹ,uyrni\w=1# + xRP op?ŀqw!Mi#c|-=2:׻#QMcWON Q.Mdh:ޟ0MM#Ӣ !,G+m1S|λt%5*'GvV|҃;?c^3ƻ:~$~%W#otq'&py +1 axv^8]Ei`1rĂ{HiaMh?IkS|n1oֻfqM7^AĽ1zbO4B҈'T,L[^'#pww;~`6ag Ab̹BJTs̗ك2Nc)._(dD0B#2z.e (G"ġ_2+Ȕ7E~{w}Ez >{|# GG]SKMSXd }M<'ߒt"12i!"QHC M{)ۖ>1?CT sŮgo# %~%hk.wpOzE*CDzYPc1S!,Ҍw}4 nUŷCфߟF׼(.W'! 8t_{4^3֏=_XC_t8/4;.rnz}ZN:NY w(3gC|S?Glmm~ONFkΑx˕ Yl33a[ey+_Ig4lT=W{W^>eϧںoْ~u$˴|xէ}#2@~prZAqU#* 7wE[|Z\ir=r>;nB>+/}h^1?J=2:ٓ׳K=e6N6mvEWψSżUae3sԍ柲14[p$d&G7X)>~8'|4dVF}9WØj7!dwRۡ+yo޲s}ʹL绽`CJroqySy zI32 m{fd䭻[ibOg|̽uR>n!2m4" r[Yͱo/޽=\#Ԕ0YJj}!  :sn;SpFLٝ"z].\' UaGk{jaGgHU"G/Nmb_Tj֧Ѽ?Z U38.m{,vr6ykۃ!(:1C42r.xkZpC@R,Y _iYMѢ#n҅jWSu|m[ :,@tx0qH@/7 ;E-SA㠭OW<z~%|/}b`(U:]q1@OqhRV/zr;bQ;j7'Dc2gA7В5Ln^GW)1nV0U_dksv-+a^תaLݠ!vw Ly_}rSEq/XU3mTUϱZ@ܵzu#7ϝ0pwJN3ɥ܃58[Kvz6x>PU{>yɰ*EU> 6c\>9}<9oӞu>gP@*?7l44<3|? ?~IUdw!"hktNv-Nèm x*[tzgi!(cW=[~e3H ;߉h.i"nme靃.@ 4fė[dʏcYW1` bxtl55+.\j؁b+Ϻ6Bc:4lE T;q۽\+ލqx{}nMY嗳::>q$d/ }NkZuG/ j7ؤ:?؅hoSG[@! X].Iz͛{$ L޼y-hh}m0MQu>/n F0yX5ؑkȭD!JL(UY/eTa\B b@>hN˪r?tz;#b0oϞUtϦ-1m@G?>lGl;Y}Wǻ;Rj D _pgΗ@ 1{fXv}LdA !! O&6og[L!򍯝b5ӛiIGKVJF[Pi]1cXJsǯ['=~'r_d?rٛ<;[LΟ|s]BiEUnə1KyVrI+7rxᾯGw@ߡ|ݚYos< },D<^PΏmMwH;"?CGHD R_j̍]dc;f7ph@! a .FoV&N"/Q?5}ê>@6!@28YߙD[lH~5ޚ! FG7JjK3eSB WKt<Ùd@Zu/w|@ZC.=h|ݠ+/{SۀA6:>Duw7n/#= ncUf؉m8q%!RD< cҫTGoޟ/^LPV}/z |%wĝuz%#{gZF`B'a5=kk@u8+؄00U>.=ɇ04o?\qN:?S9&%[đYM1;撀^wz.ߥG[G=/(.`g$@[쒑N^޾fG䝺.!|ϫF-?[wzgGa6xRӫ!dy aYY'Q[w[cR:1,S#G_<1DGZ_Zω(=%;j-=8dͤ?c`O?ţ yrO+Cp /hwhmqkr+h$ۅ y?P[yYg5 ԭY{i^5."Rk3>GT[Uɖj.CB3!h!kYȀ@YɓZ _e{>~*މmJ>LY+/Yc wsIu~9hbK|ģ& hKF/(}2Te/cYR+T}R q>h(#6,tj)|hgN'OP zF0h@!w7z5tV3 9c@NRu[s4 Dc1BG m%$Pnfv+G>c*U&vtJzWzZCt6YΩ#APyvcAN7Bm\}qOLht-Pg$6 mfs'| { zD̗0F[6"y01F!Di4 `_/xŌ 'Fj<VſE@/P}5ozi}#s\Uˆ`SSXe~ӻ+M~;UzxZb}i.W#t̨κl0,B0D- 賧/K Wͽgݳc3d8f&h*-.>U8lĀ0Dk9GVBoq@xt 92",c][uK~-06qFe T IEWұ߄yר,,&)]TVuQ.:dEы*8 =5 U4 8lF(owF)rS1wm 1Dשfɇ/4遲gxǧ):=oܻ]vdG)N|̧U؃9n[V Rz`st,@ K3r]:3 A)k6ϙe8"Dj"(H+RsckF#19gLI42Ze(q?7\Ot1u:g^,z~*UY(;;nù|KݫT'] aپC}D@ ]); GEGz}B֪';g&*[xސNVqyzf]:z(Y/et}+u'd;'F}P}F>:esM6juN;KKO "2ʹX+']TL.HVA^a97b3DF|>o挞Fzv w@[E!&'~CZ ?o] ;17 ϛBJ!G!>i%_ +(@ 7dq3#m=3m4yks./ԭS+ kA~V$B |-9!1^s|ѽ4G,k5lI F^rT>= -H87'oů@%@ Ҫr!oLDtu]H!+kxh~ӧ+ !l(K54pD8B0A־mya[=`^_p@h@ A{>㘔EW}ǘh,A#jضN'[K`&B>@C&|<(hS{HK;Hl@.ngOPs9j.u<,wG׳=mQQBm(ġͪiQAj4@ux_B%+T?zs `@-4I`!cDsq!#t1T `op|(@@i %31ҴA,H?AaH !.}s=1Q@B!h $F "F v>0Bd+ 0G=& _Vɪ3uAѫH^l~U*2R8@eA[fEH‰Z@%[ N9,}1?j1 =@!x@yhd0w?s3n xC20p8@(}pҹ׵>;\%p`ea  we! x1vVtiY>"YMC?x ,Pũ%kjvSb.oS'%#^QZe$h}$z ҡE/]Mz6A gn"y{2L!KosI7M"c}}bgs'qm+@1[v7d_K517_. +7;XMmQTѱ]X/gm1JwTA* d} .xvE_#4J0MN&}f9ceW|dcŕcU?s DMde'^'Y}7/+\O]i4{5!iĶif>AJ NkWnNHVjЬ}7]I~plg%'Y/Rmq{]%9;p{`GΚGSCqGfsEϸC%@*I@ȈaM1lPBYt( j}0e2/K6׻Mt/.䚁%=Nag3yN,W};ǚ=.1¹LcY]؅A|p0@ zC`q;ŲݾXϿ$uɾܤ;89_}&_b:GT=Zd(~Ja%3\̣㠸d!86@{)7ƴ@wn> ٱn\kMJ㬻⟽ y3֢w[z*ASn??lQԨ2jAWACfÓD(\!A[4lEg,5Lzm=eiŜ>0rlA@8_ہsiujwKm0q@ S^9Kx2FdwB[՟*6D/e!A/tBKcWcA%8̻}H0MPOڍx@#@ QӪy e<#:iU\&xΝ;AџR|3OQsPqٓܯ7w2 +s(D}/kTh~~4 ~rk,wc89(%L'jrB/WCU`%0Ȅ/@7d䞍l#ͣ0i߄ ![/J FyhP'Z nqgoݕ5Yb =F${F:@_rxH֠҄T M!:[OޟX@pdi~{GgzjoŰR}YY'ﲗ.SJkp&#|ĚG};kq{gz ¸`CϨ oT=AUW%eGݗL]=v!Aq<|{G {W9þ JsU !m…jeOƿQ^\"M{͝poU!e!7>5p#_VtL=_m*@Q8-w7gX$%'ƦQ6US h`wbq@|Z!Wmn?`s؞+U=#GM !fe}Uw$.@o Z|bI[F7,U?g0PADxY#_>F5"ipߥݠXBi2sm;ް)0E0&tsp3D~Doc\?2$ҭT}!O)w];lnǺ(;: j S!A1s;(_}ΊOB煿*b_-2IH7%4WJ2KHo BR?&=TLFi?\Y"xYVX.Ȏ)ٓ8B%vaOӼhaBF7fl`u3͡5x@!|ςmn{r4n7 n_{i͑Tl5YyBv[kMWjUiewZ#i3뱀 LEe@8;*D_ ԞRC|9>C-а ]']HB\4HBj@//0qfo"xսvJr̳ ;S!Y/nuS5Rk'aTZ @!WffwNϑJ,Y[䔋Dxo?U7w!rZ /Y2'qݽ ~1=7@aEN@ fX#k<d$K^:yr-/DƱy J&Z詸\_<݁YuK#Lb/}z{W7+A)jaS)!ٛ;!@W|Cbʽɺ '*Wyⲅoӭ8ƞ RV{07 ԟf?l.x)ח kɓBj-h-OB0J^n EXu+5R&ଏ+x7|!Ƌ!BA7;!oͨx}N@# Jm~=֒? ;%|ҙY|t^&ʦBFH W ])A<%tuM̿YEiA7z)Q~MjO}Wnɞi%|#=>!0Aw$_SU#p#4#r7 =6"JWO/%Wnwu `{O[R%2C3ȺUwh ~0V~nbϼN~FL8j%t6#@@\Q#@@c%ַ7;Q>s{!IW"d) /D%?b?`x/`WjRS&.%a2vYpM 6fGx'ᔝX .wsF Ls(* !KQ6?z[ AVd^e tP:]C߅d{oC@6S"pN+mɭ̟Nklג5@ CSW! y!:KQy"Ep}k f%Lb &NE]fݮbhwTkרsZWS }[w52va+gA`\gkS1È7љS ZYȤ$Wۿ9Ee&z:ɠa0 (mD|,|*V<4dbᇼӱ M/׽+d6B\+:I6߽JvPLߧ- 5dv(^!ĒPI[-!wׇh@ r#ol@B$閿\YeK/IS8|,MFLJ׬1_tayh<#(YCukD/G\y /)/z0Hk0\BF&!>`Z>n Ef2WmPq@.k]XzZOȞg~o ruM3Cz4rG M0e$\d@@#Û]pѽZ15I~3B!\HTAw? =p1.({afe8";P8p Q|j$}>"]K#ZUj)aU= pW֭73uʏz`@ʥR{DQ lqL U ;{._{g( kg]6zvW&l]Ch,:I1rj@Qwea !]E'cf'偌ǔ,^WɳFO'jbךD~m݉m3_Ѱޓbt"S02Z]z*m[,w>l?w= ^3fvx)X` %BeELey"8ҡ,@。*]s 򿋞g&dμMR^~ବ6Ƞ|]KJag3r6;}uՑ6<QT os^VS n+G2KGcv-ST}}6W-K#rOz+- *>+lC=TX>ATy'ЁJ>,9pJ ;7('v4? V]++Vb$"鄋7^d0 vCV\VNx{X>]O^{5S{ a!e̤3nܬ? WƨRg9Cc5 Cu5NQ[|Z[C&rsIbz3lOaф&5Аcݤ@a2iY" QQ3(XϺ8T` ɑVϧiX NeŐ?MP Irn$$TΨw9v[F6198a,V8 8Li^2wŤV6cEGg{0!GÄ[Ӎ87R9GBFKKĴ(E%Q/h=ݷNk T;=V ĬV/}zy{~zox/,SbY0Eݿ\`pm0@&cX%bgjS&KR/-l; ,FOJKڿl=1>;;GAw ӾnEk}h׷ п?ódfJν?i{mw/W!=hL>imtU=t&zˍɒԷ9E𩞊/gG&B1- }.Z-)7bn'ȔЄ!+gI2p%CL:N϶lWZw'}y]v| a1`l!Oy|~7 %pOk駈֞(1sF 7{6MOÿr Vf4&{_;b8CУ: KC~ߗ*8Ƈ6?up {N![ LdT}$VлBPI%F#aH2@9^Z%& ĬM,T RR‚zܿ'VRwpb }yt,$vF% Rx P؝>^ix"]͆tûmPh@ X.u&mW7zqb}S{%lcShݾW~9rHf!Z0`!o/cs A@HD .<&eSG%6tT`RsI`pr¾[}ü}0f`}q#]U @qWxAaDjEw2 -s ŊdG:s3iNHnU0]?}($Ȋ\G kG$i!V<g%D&X_,bk7  P4aب# aOJ2ip2X KM^ >CHL/Hua B40x]P&e6gk! o n}U"3;mQD m\PqƺV>Ӗ3K:tՍk整7KP[ebbݏ:0yYYs_7>4@,s%v㿦LuFFՌ{/wpQm,DHAOc\< 8~謊D/cbYi.ZhKZ[9Lga5#~BƟ%,B B! -?ֺ~H3rXp_ÈAtҪ q ^Ȓ탪gNB0#Q'8 ,)S% ?ԖX[IU@ S:hùhZ !&p Q1Mpl׸AGPy/m̻}]S&Uƈ jiԦG7= \H}cծ:0uݳ  C/_f҂׉XX`]:wycaZߨJ~5BE<BVЄwH@,5A %&uA"#XC'k{{;:@lhimNwk?Z]P`; l9k^>l m+h>el|m~IA|{sIY|8.6`fl:BcW' 0& ,aW`QI`8_灆[?,t<ͤ.}}bWݚjr|h{-`kjcuy'ec*D9 ^B6#!5{J+?N2$(ItΟvCP ݑwr }Gz P0@J4$eɃc1& #R(<8<ƕc8*8śPC2;P ȇ,WYm)!_Ҁ%w 8v&O6;qB2}mO8? 2, F ,q=կc2rw lN!_{sK2j/)4\QFc]5%21+㫻'XNdZ&`Řxuf?ru2_&e#H@H }; %A6'㫖pN` Q c=wx]\WxTjڰt vJ IoΊ!fX t-‘ uI=_$POOк]&|m\&34Ysk2 2cX088sl|sF[U{uN ~ѽCոp%Fh[=fjSB߭G7zw ӏ?!ٚ!7'!jN0H @₯t{<¿|&WLʊ_,SW]'*Y&XA_9$q q5U$i%_8 OVQ'>RT@ +] z T/IӉTТ@@@:d&ڮ|`B]r${E  aJn]R Ut,JJ1sh':|{kųh$L@d*Y_71]s6hːO%WÅd*l I>b~7$uRD c&[}8䔧z{3RN([!&UvO<`oaYnd]v56(C! mg eܙ-緤 %u+K.=먀 ]wM=t`%Nۻ2qTv:Ӕ$7>5+~/ pt[|v YTYK&t=b@gc‰lFf$= SD"〾.D>,H Ō:i zcŅz?뉠q=5G]J9\sO*\mG"TF`${ K$ k|w Dɤhxx< 6mHe D[HEuƵN_ղ}12N8]L:Ůw/^u䑅EQDiz3) {q!E^N)/ sk;{G;hxs ?ѵZ>5yDDlCk'QlrM/4 OQKz&_c gGYA$stQ|Jȟ.ƨwWW`W&1LS~TR~v1Vѥ dao? RrX]mtN"V/(h>~C#/>:~pgޫb,_c-!؏3ۦ2kL|K4xW"MhD!`V 0Z8w2EsAv&X޶n^HsX^oCy;[8%Wkb`(sB}KκU9;XWS\S ~ۻ{4d|%UK0 ;?nߢ}ŹN䪤e(AF4D4tޙw8.]j6 1cm N K~gXAprT`v}jfRR$̩l߰SXvR>E+X*|l!<'Lߧ|_4%s+UՅAߧ[u m-MږzsBC8撬l7gr+fW:ූdFc0HY4N.jF 5sXU r/׎?+:MZXiCEe֦d5t_f ;iDUܺ[ӵ ^7;eco鶎nw*c5 5H%7!Pc5.Oɍ'ފa;'ʊ۔E\lo/.d:,dǽ/'t%C{@+C=B$}D<)k0%!gTO2Ri"\#zjhY <,@  =Jiݫ=[⧇JķK dU]LȐαwz)I/{*A~\GWWG*sՕܼCAcqeW/KC#g^4]L;e_Z$$WB,goN`S=˲Br=#+1ۣU?ƩgR/x}X grt 2׷؀$7G)EŒJ<. 0ߞ|9 c/::#]wxMYzƸ`8`y$B )JZjd6 D%3jXlKmC]{i @E)baeI~E=qќ.'?XEtw\D?T7  ~|v3֔gW@|> F9gBjI< ˚~^SsmښVk[0\y9ib+ #u/ =-JRX]z\@AVBF}t 2n:9ߦPq.FAQaYyh!t㏏߻3s4mGD!xJ =R!w%_eϒ!a]B ՗ VO-,` 7֒'w)Ż~kk4BTx6![r.)^9!T(5/2cad@.@R .yOLI};P Bݠ "$n$X˲:WǬc 0'@awȧ Tt9q@z$( qJI_zDxo|%,-d)Xbj Е$7( ⡷j Pa*O+g= e׹o%)lu/BK>6:?)U~Q5pwwdX@(E$@XX|Y閈Jc 1J||dG$K,L8:Gf1Nah4l|G@ ICAIq0b[2dd|g5?wZS!-QxY.uI - YE8}]`HzD;oMM%}j&uՌO񶝦{'E!VF܁cD(Dpvrn1=@&@GS`a ؠDƍcq盋\pcЀ0/  ;]+ŝ?bcGr$ v'~6Ӌij]yM}mĸrwJ,|'"n!~?@]εxS KKWY`2@t7\W$! 'd%2wtQ˓Nˀ]<uD X@ M~Ua#*GЕj!nDb5G>^=HLgr_ҳ.9ɮv<$9>؃] B%`F:?|9bݎ2]+!K9i80BsOmہk_?[1  !40 ,r>01c鵌 ! 2"ׇfuئ5 u/gPKGAk$gW{VDa"0j8;K`' [ &|$W$wMkgW /b^6/WxXh'(WFַ'͒Y 9Y jaAW>RqW}A ͰfGɻ CьL~G+K04CحVB ^R@y@1q*=UsǽA&n-t)S $BD"2v97]Fw5;k?yB :*WvDoh܀ !~{ *3}}F";&Io?*[Ǧ@|@+tn՛]E픟 ? '$"]Q O+?ǡiBs,5ƽ8@,ȥ|'_!E%0}vL#fgXNR/J">YW~FOhMHB1VD8K2,y8^ td!z9QH[Ѣ't`=qi+e>6 N|I߈qjܐԜv'D³}ԥtW1k_Ri6.'7tjup#Zn'7ʲtr` 7?"Y$c}\0)QAт ~~B/{=_^JK 9D:00m4!6Y*zO`j΀et69uK*j4ń!A4UYnMe9WbneH`~n}Hf@[Q(ԟj4BF?J`U&;v$_J||_}O9zsEfm{u#LIoE\Lfz,K+dPteBSBD7U_~a >(v_k5$^RkLvYۦbI@BlUc3I]tՀB 9+;%"{&r ?d Cd~4ѥC/~k|vR7O< PxX?oNfpu\0[K˵gkh:0J@@/FI_gg_[WrdM?j|_3T~ea'DK~:`a!>tT:T`ئ7SfBqE~߯GB@NOݞ5DAlFrk.s k.RhZf:_CBsk,PouՋjO)r1Ҵo>oՀ\J}dCJO ZFk88 :3.EqZO:K^9:rNhS1LYc7=b7| _{tyўJNbǯYf Gv;ݏ{TTn=x1 vBuO0eoJ@ YH/i?Ar DAZ׆'H{7,%!z9;۞\A>ȷt)b9\PBa= L'An@CZU)$م#"э([8a,SZ;F K}_SfU+ 8B0JFˇсϦRn#?d4lzU17'^J&]GU'] Rv8TeE%Ҟ=KZ@]m.Ų*v0!Ѯ`IW=`j~@ l6oS0%vx^,|{h Ԍ.Ur<H&Ә 9\(NH”~s_Om>p@GT>= :ZD_\ {x@])8E!w_ňB™?,zluQT‡&޽$Snfwq{Mt>{`MZc2ZSC9՟ ɞѻ" ы !}``D0>2Oo9m҄)R؀@#:p*UKvz{3wZC f*%GG=]y=2m9i`rG U&IHp?d:qQ_z<SB hZAu#ҥoC7*A * 'Az9|0 :% x?P L bA41g|&X%GꁢYz8+ofq虙< n%n!%Op7b`W R0A't]"|?QP?+JB!88Hp$/HzDLjQ ? 飀=,}vp@_ FիrwIր@$5.F]|$!tDZ#sHRwӀcC (sn#ٵ L)[BEo$ϣMx}%Qp}Km3.k3xK54(o1KX00@َyDR3XjKwU"ƈaRpFϞ%s$dVu]`-=TxVz9GN[ W1a;2 3P:6맔iP+Թb '+ʧ{2%]DFBXR0.V5?6ŪBVՍq@<3o0 Od@ FԐ^1n4җ-.B* }t?}=%mf kxtzHD/bf#{lQ{E,=3][P`,B) +Ca@l7r)߁9a䑱wRO>FΖHm7R:إ _{W`#[6}"1Kԕ{hϑ:j@};T dLEϏv+z"]).~@ćs - ]rHͿ XZoll%?~~Y6eO>3ŗ/# v_vC ;?E- |C.z{;Y%S@J0ae"OgJ⼜d~R}w֣~8 p:~&Gg#"HD@ ~qTs}?5:QlDZ0rA#$O`hd+tf҅A%/^5x|b>)0: {䀥 P rAACY}03&K2LX^ Ugw@< j9 rc7a~ >4T^UΈ9\3,_T_w^ ]%nNqѭp=OkW~Uzep60sN0>ESH"@ uƖ<tPBJZ((h2 ~ YOUi`8ڥ(jǂ߷rjKj! DF q,?z!IB/cRW68T0@:33*szT@b'ST>h TMŠp!\G4rer *:k|;^gQllu?H"}B񏹇59awK2(!t}zD#20QaĽ64zH)0jd {ф¢t:\@!n1vVWXz=~S;}W? jX&!@#7h{-/6 .f}.9\<|x+h%G]ܾ!^ r<>.뽟tM ){(񛨀7/:P4ϊ b]Jp |y=e ()m8 OÈ'qюW"w'zO^IAu%IZ0+ZPh*@?WYkY:agIY-U~94|P4 H4 !Z ?}abL8NR㮘!r57!3x0 $!ڔ. QeʔoН%-@@/"0.uaA(C60Dqw,q0.4vwqӔ&':Wr?q'UE_tʴBb/W'ƇyLgu=D_3ۆ\%#CĿN}*vyMǷ?5#x~b}qMwL 6k黅Pq/iԽOU ChX @a0S"L@ 1_ֶ[my^8 Y1R7׫ǐa zNO@>iv-.?07FdS .Bsݵ_dG ??0t9'bn#';h__Bxw4G7>r?x_dhDё)}$3sAdƘcIL]2} 8SntXEsמC& A?MXd@0 8Ba&fFRwҩ,q1#N:Ig(r@ȱ9L:LXye#@1Q ,aX!- qy8A@Z>4l4Heץg{PŦq?5kX \H.6qOu?uB}5@-Oȡ^ߥQ _;P{'7hKJd7MWbU?=ʄYMGhVr(݉6E.hTl}lxs3B7)>.K;yۚuyψ]K47k>;# eޡ-@B9(u?5MŰlk"5oWNnԹtN}.~bER-qp1x8 yB>W6X3ڹaiz<}0zZ :;z~K \VGGa^ExoL!%{|lwViHïC 0L5Nr?YmBZN:Ӥ3M3M؍p_V/2O%߯ðdL+d5l#O6dM̾|ΰ?˲Dƾ<X!d0kx\#ʿԑ7:TǚueMSx5ҫ:5'6}dz.DD79xײԍ `?+GqԵyF D>:l!7ߝYZo="ݧq,WkUV.ϒ[sET߰ףe3,.~Fap$ e(Al2Et%L6>!X7 _tMlc,t;/~z5o![P1 f0bݽJ&4nlOYQhX7AgԃL=eq(3d@&>?EGgLmޛ5f~}oꔒqmS\;J l{vwtˊK>|,4RV9wY~LԊߋۦG.2[ÌwKO`@ [oGP(pYHoO1eW*qzA 0p`sr:L2b  )X̘ECף_2YMf>bT/B3gw)!pߴȮeȟ΀ yn0@ƈ0+C:Ę\aт pCof59]A_/h ¥H}?xg{A5nO|{f(}Y 9Q֪"R@4Œoo;54͋Bih0@qc^f:j[zb9\>CDYn5N<:Vm{| p^]xHVX97=q@*>…Е"V}M 8! U*dޤ\ogH_ܲG:v${wo~D1o+@@%U,\Se.NO3ۘnOhBz,(ƛW]'j?:ޞE-0ybjUs%#m?y9R5!AܬOq>toŦO'̋0zUs/܈ZDg=>-J&j Xk˼B>AQcfHe͈1F="qчTZJ#Cx K`W@"R(҄Mſ7q]7@^n/dAgbOw|,!6S/h,W[{xJrH8wGN8{CgaϾql=2M1Y@& w#xK`rl\=Uv +DCpRd`I+FD9OH?`~JGɆ`!g}3] nX`0'hwf?Z , mr0!]_y(EVu׈3c#Gkf@&M64BP]u/PxyɋЀBWa(J cF&MǤ_k'QfO!6f#]_ble3WXV2qsQχy<;K.9!t -cF&\D!t2IKDҞ.2qK]ʘZ^L]xA xb0AYUYT+{>tQ1NoQS\.3qU5H5(p_0;x]^14`4t"ŗ ,+lJV|J[f|{g6,>m͸V/)o&"g+$p ;v-{~@ xa2fQ>7BJ[~f D<@Wj=2TvVר V~j,Qk!'}2ZTptϹc9b/Y'F(L< ơ;y*; 0'0Džׯ,7<0q pxW}lQň V} !P ?CY7{Hjܲ;ﲮt޳ȳspdFrd٥WBjBW= e &yomNmWT ?Ӿ f ˣ.r @- ~~Wf ˱bEQ}FR8# lp9|؇# (mai2D ^=[v+簚Xyz-!!OҥB*xv;Nhˆ+WwWLtݾ̞24;t]F/R8W5v+췿))Zor )@#W$r2=,VDof̍VX܇oSjnm!VZk㬅4G:_;cOvh~@OIFU3[Rn h8udGa;Ǒ8U"=qv$]SHvr#cMX;]ɵm,M;΄A'Apd'wNnW5J\A]u@3k@8"0tY UL,HƀNHNFPYf9), OKI57#[l=uW*>ΈB*je?=S$.`/H9~0 ttNyU 󍙔1t/h#?Ucױҕs}yʧy5ד:E rטbn" 8i+Ԧ>8MwuWI9(zW ttL@!cSSHDS]>n1ix7?\oSN&[_.|@LtFϺ9=&^mTKj5֌w.bbD_0sڦH,J;i <4U?} 3\/3*{cJOoe[|\|!e¾};:5ݝɍ6Rj,t@! yB S$L._}HQ+~R\^؟PXv7;,`B!F0ks̴8B*'=SC^VD Q 7$H<K .޿ p',p'5'H+?{M*u: G?{3䓒Ea;@J9eiHbכtHYD(xi 'K+nu>4V;VZg: = ]o zX |{?NJu? >k 8? SgjQD=R,X!c=POTȯk7FC4|&w575Dha.@pytB3؉\V\88Ǎ[ÀDjyo癒6PDpDX@#[oT5vvVĴ2/،o}C!|_|C"cCiVkB(`e3F_9*K#!bi 4CBܒӫp&6/쾼d1ڨ{rD d.;|+UN!xT|~y2طƒhۥ,/{5a3 כQ?[ LBj5ˤC1 `XUuGh@~1D뒦yXNN4D_ {VOx]/UaG3wN]uap2H ӏ{.~gm~ `h`+ϟ];N!#aa|'!AHF hWh Sm?i9X ueX1Mb XeOJLzl-o6XE`! ܴE2|^㐣hZ@C_6g^6 s7/iN1!.bGAċ:6mAlugbgP9 _08xXM1tw(ݟlە߮9g/d᷊)M*rE z?=[ꇹX/Wz:}@ ǝ3R-"g®YPopB#EP2O^duks Qʡ?V;H+ !Tqy;6]::Lt0@ `WZ( [nמ׊5B&F#Nә< 9a*ǼR{e 8o?@QS% !]TE;_RKۅTH>bx o#x[NN9Wl ;^ִf! GFO!| ܌7V~@*1\ЌXXT匥?4!BH1@}:O,L8]ivne)8X'H8 0R+H$r@FJ8"0x 09iRDB Peo_|Nb (sE4XnL@.oJGhGbܣfäxݢR_)Q/rCeӁ~3bP$@sh@]׫<&#FZ_=bQ)Q&j%myJ8`!ڥX*GvkՐ復!t U,f {mF @GU,t#:tzޞzOZbtu7=@~8^o冷!FGgFDH>Hezy3g_g˭of->[C#}.ov}a\G?jXI&965PB =2;!(⾛{SqsxsASM>wP;OoŎ%r!ϷyWVL؟}'*,>n+V攠o0c8!#;XAؽdWC{7>Hh8/eaɵr&NMMT#R!:1/1,/JѤ?o=Nz ZOY֟.B%(ξ/]{'4ǒ~$8q7ƚw &dtj}u | xaEt %QIr8T{){)vkdũso B]F %}oiuƫK /iw0aݽJsP6\` FqA,~fW֞pۼ0kΔo5={Pƀ*e{J ;ffbT f9#^pt{mP{ oQqgˉ`f҃U}~s.S1[hyXv:Bxк ->+VxR$GaハaQ/ ~g'I !@Y3Х;+fZ@B̕z7Ry%'4~UlJJ!A AvB@ 0o cj0 &\8UpoL3V9'{ ^ƀ@Fu?MUK<0 VNL#i^pf,ˤ)g 쵈g "&1_$ Ct#mO[~I`{Hi%}~̈@#|Q" /b}Q6^tu1Є{&p OGp:Lj f$}Z=AcT@=(!ƏPB2uI!a5XJ? vI0FQة.Ā$YӺTC'c}<ը816A'(=g{@B *x[nb(Z^2R .7\=x+ަ#_t!.C*XZ?*oinC^1,B6@A68$@AvcG6U w-Ϸq?>MO@ kB܃WbUgCbY՗O;J$!f ϵq[&< &0=Nsn,$A[?yE7=``fu)S?$6hbErAˆhids${" vYoDzBJ]'1c{,]3_' X{LʮAv]7򅏹GcRuI2/: Ʌ-Q*VfyOyϝi_~l_qWOs>B)Ԭ{مY͂'-5`ځb5;B؀Z8!)  @&A[Y .0K \2:zJ'kOQ,$e<ɡjw~x0Ř}oֹߝ靓KsD;8 s24wӺn~a @ ZblAg\| . .:9?}ZÊB=kIg>u =SVnp皇JbvTx>枝1uHt0Wy4)4QW o %gNa{‡0l;VIziơ;IQ,D !"BWKGݿ%ųR87Htu!owݜ\w/Vynq,'x7\F a "b>wq 9-Nz'^8<SrGDyzIЛEEǖ0*+ vhI}_=i(csoξTxO[C*avbQ* ez p 4J@@ -rNs|m\e@{щBGgoStص3eo+}o׏D.:~ֿX~/@֜ŶN9Obv `Wz=88K< jӽX&7ܛ\t*p+NK@Xgo3G,Y8m3r;AkrzdAK+<6PC](%P$;=cD(|(+Ԁ(dڤ,LRYwu?7S"{6=svW؁ =g@Bz@E\sfTwӿzF&D *dw,gXmoyu;2ewgqTWSRMtF;Q@ .B 5s@9brϡ n5da_S5@_-mx>1,P-@/*_@L7Da(=_ !8 Q+WF3#OOZ8Ph=PM? ˖Luf_a}yLXJcty1Q|W|7.Ձg8E66Gԅ5i?@*u6c?Mt:8KBۓGNJ_ѮK͛ {Sp/G~yzq6ݤD>OqU4ɰ8CWgI HmVcX3y`3m THmw1J0"h:0)8\s=W `N$+t?@T g$W$M9pKX,FGzFbZT.FBhpx!"[ х~q;?dU;M:}t!5|ST=~վ]5w`H t~k}ل  Zi3/so ~dgg7IBO]Roƀ pHV8#9/L4w/˺ E;O&gKU!VPQi8."ac_<@ Aq^77K_sBHVduܕyjγnbnr8|tN@Q#ߤ1'ݍ<kgU%z줐wD(D軒)„W'pibus-table-1.17.11/data/pinyin_table.txt.bz2000066400000000000000000004226161475513533100205560ustar00rootroot00000000000000BZh91AY&SY@xt0Lg{ޠ?cx(P(p]JiTFKCB$jPTB  P(JHM`*EhP `QBP(((  RRPP )AJP@@(( U ()Z+ (PP *`d v+@ +Np@  Z4,7g66mBLep4AZ4((HMҺ馨:[4ʥ T݅4@iAm@@ c6hM DBTP6ƅBBE$PE B(B $P(@(QE n!B(BA@( P (|¹mjRYr[*4xzT@Qv" Ri6Vj78 PXvpHPn;f pӵmusI =,`BB(lM UҢlM6ZR<P PP % BK=<: uwi+VMCh(O@ @@ @@  @ @ @ @# h0@  ` @ @ @@ @xʪ0 ` P af!P5O""$#)@)iR 6d 4 ɛ 4RR"z4I꒒I=5OI156bLF C 0&<5OA$"D BI(SOPd@@hi=CF $$I,n5JRT$-!`HN[ ͺ0C1!P:Bș1Jj8Qj^`EYV2f\`65ꥫ#Mp4Peilv!4:2N7kjjbP`q:˅Ěv5cChY39ӚpbhZՊ!6raxM"%rc:CY0a8*v1 kXelNf!E'ʜ1U"֫SSѰa25T]B\4S"YNDEIFƄ!k"'2d 216@ ˧;C)0Q4"KeX6XyXrlY238i4:04@ qSjF E"R 4֙ALqJgcx@yϗ'xo.LlÇtzcŋ F0 : .6NB3RY4s#Tay*5 #98kb6 ljS6rBCJC cM=&yUq3 <9irk/Zl0fl$GSC4'*ӑiUAt읨-9Y]L.' ^iy}D0\Tδ4FºBA%.m':L\ӡA7 pV Z$Z u.ϯY B/gy5»:ɠс3\-Y3&I8ӝdc00ЦB"u\\e;"A)Q9-dYEI9\lHxB 8G¶4[IZW!APӌFQLN'%0,NLrIS("dHyc &KE27k#Z ^AsadP y@ (0kPC81%XD `mYs4*F)&['xVܐT [0p.]m&Xt1Γ(abִME$:a$=syf Xa1b68s׽x}{=×([9B0lR R9:ˣBXVtpgˣIaqgn%q\á"БSlYځz#YPj9LHMXXM :RkI S]-'YV);F5@L-VC{gLE<&VРv$88HbH鲩2b 6lr'2 ˜q1dĈu8$ g3LdÁGPr≀D䀤\M<.Kz88}bqjY+0)Ό1"63rqLQ1z xծ$IMɱgMɮ aPy^R"\Eū @N+ 8!m(e4/z|٬G8zYqPq0fC-:Fե6(:Z rjE3OSXtY8 ),d@\@,g&ԺqjŠV G*`p8bI.͍tS-c ä HgGvv&WD NLZI pDi Y:YJ'\ZS+ڭXrFv9k#1'9)P9᜺V֧#p)A\FXÆrVL!l2hƒh38ڎ4؝K!Te1[HU ̦&1%EuqЃi$#[VDd%IdVq9S16ʖrpc@-FutK؅S啳+49ɰKR8H1Aγ&p`9WhE4i5E qɁ0xLX5 .DDWom͚t-E1.g3Xr+,3RMA.:&-:.N :͍D)ٔfbYFj2'FA% jc5I)hte1r4Vu¸lⴠ .hBSjKl#tPTb``Ƨ-&T$-+6V&$I,tv6PASrK3 r`gAJjmMf ū.=Kh*ʚ-b!j!*i"®138CHdqZ*Mga : F8'P+!q"4UgD%,ҧ'9V'-a1g;J.*8!ufUF hJ8uc[,4XQF0VF6-jfqR9bb@A]J(Њ9,X0$ptp(hiU1kReirq<zca+9HBhZxpSКX"J7ibM5 *GDW! 8kAj[Ù2F\iVo1r̄Fqfy6uu9Өԕftx*,Nlc l9"vg"$AFP@uIZ,Ό;,@`-F@ W` uKX@8Y F- h 6qrsOF"SZ#)6j-i*Цmd86Uz1ɪU\h9(dˎ]l$XeچB cF4\p&]rkzY32bLudG m0gPK,Snf\<#ɤ̈́Ӑ.KD$c/CJ`M 4.\:",9 SGmeZౡ@Zюfk=]B8lA`@tk"HLi; k8v,1U!&Jsd@ɪXs{:G?~??C~?~~'??O36/ LbI 2+PU"Lc?A"?&l_(PbT63HMJחIK樳=nu&.A m?CiRT ^gYTen3Ny:@39 9}4Q[ቬل %f3%;'r[V@ ${m "F ye~bjWEpSṄ5럟9r{?T07'"e>΋ *0; J!+|+q}i_R5NMÿdGDI@4%i Oi\8L ծc,B= i`FL,ۥ繴x}OzvA/_=p 5mYݥ*+ǐ|a׾y},k6xI_hUĒ?]5yX fL(o 9Z=,FyoR+_E" 5|Є4H<ˎ`S_]CfW5Ogw㱚Q3?AןЪ '"6Ky6D`JN2Ze:RpӃWؽet?]`c'i҈pxGTY{%qi Ǥeŧn:tOc֩c"[Ӆ[_3lSӏձf7W'APNmNbbY#LD0^ UΡ<ӿ26A Ee>Z޾Nk loCQ`NMJT>AnNk0gjBx NޒgI^gNM> b8U[D,V ^^B:**F$paqX88@X5I@69b6ib3ʟhs!KY kQW7F/t"q"NG;C_/|2H2`2QKZl,τWw-3XO6ڮ;Ŵ/[md'yRZ \8QZ(JJ=ݘs2~ӏ̣ݞ 4^&ն&xXt^!`VU+7ko*R.6;'~^ơIQR3ŲZȱ*^# ӇWf< M| Uo@%"č 60Y$NOXE5&U~OՂ6PSr y 2VƭG]8VKKM ]9byAialׯ'KjI7j.K"1a^-h[LfObs!?e{5䴝2KPl`Q =}nԇpX3PBֆ?#tc^^aIw<5.Z HPIM؛{HNK"LtCMK!yĹ\*~6kJ1 ܱ8P`5`N |vmXa >5;zҸi錳鎾wj7 %CmsVdz@nGj rL-lPp֥O=y#QwrᡴyD"LѲ6e Y-{mf:46P_VF-)=UV23"^dW:Ku/`^oAINWkjܗ u&VJ6WƂOxhlrM egoS."#{ACtz]&XJd$Iw2~s!4aN%!Bm-5K@0]YBmF \t\WY54oc@/Bw +w6u/3Ђ Q%nBߏ;yBŎv߳ݱwQl?p/$*QH^/ȘO@%D" 1YY b1k+鼽6tUV(P|%!-&!+$yD6(wls>6(@&;J5L d.#,)覫I ?>wƳ4iپHMF[@\(lحN٬r5P@메W^ CIU}9VRAM$ (օf(Y6yf KS[ᢧ׺4yit48j2B'|9YhQlvʍhrMTj怾ӾqK2)J@?i&}g V 5UDB]ʓf3T) ?nYoE GSJY^~ݪ-Q dGr1@¡h0/npОMPM'cId2| 1=5A KjVu_=4=&P+4haPjKzdcr͵4}Y9!8v9N}㬵MHfxۄa%Yx'dO?~U†9xHP%׊QCaoS7[u[(L*ď8M)BwDb  3Tq10| :yvK׌Yt4 jW\`gcڧ{}׈13,ꀩkt|v(ϟ1'l#?“:7 e3hzN4wL2FdsFJ}4!L}/w,kTCC8O/Hnd[8xAӒWXm(&@ů%# vSC1+;X2r:y3b+sl{{QG>W۩ꑊJ΢)($pX[%X8J(14A-u3$ ʭ]."IoɑtyݺGk9n^NOo0W/݉YyUbHLw<,-nnY·#y2bY>ʦ21tx ,]TtQp]y8m[;ߌZUh'k:lai)P99K;Hz{zT &(#AHq6TTN ] :=0{Az KV4kLe}wA-0جqysKu{"/&4\da!Z&kUɖ7&Fa[(B40jȼwl0\ M+A.#OzSЅW޻^gOzsWCPL,2tu]c;$ Z9gE@'_F"; "u}hB&*lt( ɑ[20+'րM:%׫zgtz /)YXz=owZVQJ͜qQɾu&-\4}|&2~ժÎ I;/i-NJrQZTR9HmS9[`%W^^+$ҟhDO4Z`b^/Ȓ u۹B}]H@Sr6\ pHf޸??0r>U)] IܯjWiGөz|+[=rߢMoyf9c0gg8ccO=inH@vZ T0ŔZ[ HC$w'<2 %=9Y.w֗΄9i<"ъMo@ t%cX8ZX!1MşJFt%x.%(ht~yp L^@b.=d! <>dݻ3ZftkBU ӟ,)c[5 IEG) dЗ8ϞXT;s&|* 424Jy*Jۇ} O p#r vN)"",]*vdz¤\CmRi,q3, 5-`n؉.u79k2 N W&a$|KtNun:PlKR =Ŵ.HZ6 Ɇ{ ?GKB1ıUxX9s@LVSlF!T7oV&a6>GMdK%"r95swKIcc~>|)`<֓6-*qҬדjzOS޾Dσ05NuӉ p16lu霪RbKHڐ#u/?B,w|%vz4S$g9,*!ZeQJ">$5kݼaK!G$2V%8C.gUEP[1{,U_sU䬊'-ZEX4QovaAi"5 Xb=ӬޱF!|iƶO`B¢뱞Y G UW'3G3xEˊ oQD= w4l`J+%LEQydeIHlvWdMe i;^ x a>"8G 9nc=6BWDākQO}3 r}],xVS'UtJW)%w֘fմzU*ao4 mWM]FxHgNe MyDRR5X`}4E¡8z* M=t3fnzyA Eѝƌ`_X77`CD!2!Я*dZ/>* f2ֆ(fz=kR*F;tjC˅zb6Rh`hڡ ˢ_|*QII9 (rlzBrO˧EOy,|sem4Q3ޏL?\+C/fb*zmU- l&RcJ& "cJ$clc6&>A+㓒E̎&͐@]bwJo^ƒE7 {oz4=,էZSE) cɧviP A ܵxde͎=m/ FEkP`AL0Pn;3'H>jmqq. H5о*$!r'"H @4 %Կi@ְ;u,G©cy,ĕ>^!wk7ᑕ9uWf-z jD8yd aj_ 9(ҺڿXGAg/[88KDn.&G9Wy >Ά"]R,v{#!^ћ?#2jNS֋J8e:vUz6ŋIG`rSM4NiāaGd:yޣpDbRo܂vSt|lGa7dqNdg#O|= P>)/XU|#JZ +:EY,] %MܝԸ6jyJ( j"n 5vԒc;|&SK#p&U):-x4u^Yc|-L+yFu8p C-D֫oͽ$]}gb\dqtsQP3WmwQݏ*n_ܳ+ġs+R!\JI%;v=^|iuz"i!^ Vcٕ`]Hr?=y)SB/}`bnÖlQz-Km0Fސ`+.+dC;u@/9шw8@n$S^g>t!z|=gϮa{@ GK\Tj:c߄S'EMǥ@Hc Ǧ Z]3FEaD[AKw AcMml~vC߱d I|S`NufwMN:}Lz},橗ʼn&ˤ d[Nư=NhGGM[ Z])= !2 %-f,Øa):ە 1Ҙ}H˵`GR7o/#y/FlRپOCY& qĠ)8}Hmܯ))_7 IvC_(7FN#܀TMªz%ҵi N%t%FffZۏ^@P Lir)E[_!Ӹ9 GC##)?Q&OՌ#ALNdI! R;xG"D|2kҀtZ\qǓM] ZfD?G/kCt'tM&f<+ Ts 7wK^zxWӮFA{Um-V M|9Nw%`74WKF?o)% rd[#qlKY=e9xNxsgK'|>(vmshQ{Sσ|nqH^E.,RZsWy% vB W1jv7ŮBlC~F$9AE M=c9+)4ƞ;=yc|2;-6^biǤՇ+St'z6js*9x6\>XS6O{Gi ^U *{]Q-@:婘/Ǡ cӊK=cRw/bCwTr'VRSϠMDTx5Z6n 3E/OנLxx&tY|_fV'@Tʸ >vˆQ,fM$Ydq%)2WhYn[c Phx#):svvXJ\xIU0ɚx>Cr*95u>六>2aM?$T%=߈ k3O8bĊ=EklU s-7QG!uSLc;/ck*X5 MƯD WFׁ`^e>mXuM*I$Ư k0' ;;ب(5$1dMf+,`DM>n)#PT(A 7v [1:uےkĶf^[K7Yl^d9d6*-VҨ0, ħ?Y0к,[[~\:-ʃG!.COKAF%# ,Mo}|6^UkV5 e@)-wnqP!k]LJJW7@rwtт8f4K \E"R)[C9p==Yqg&_Fƺ fSa3p.7p< m~<a#lWVG#vYv4ڝDi(i)a7]+) dUgN%J?|KVբ/v`|5KiH=p-m9~:X9Z5ރUKw-Иv4u0ὤ p VJ,|%zpԻ:p8Rf7F<y =qpЙD-R۬z1A ^VR}Gxz9OhH|Q5ӣF6ÂIZ{UnW! !r ﺅ,Z=Kޥ}3x jSq_'^He֜`߹ɝ +8UlVVB3i035 ^/$_@jtmWQW9G^ [D`J7DU;\G' 5TboR"˜q+:(<)ȓ@-}Eqq\lֆ^ę:.47chGtڍ֣,RZ ΀AHШXGKщ+$?IۅЇЃվ@ña)s =+ea:vZZΐK`RJ+oO<,c1xm0܄!M=ApJVoI{  PQ!gb+JLӵX@MqZs94KN}Cӂ( ΙDʼ|̞7epPNYs;t L9^g{|w@y>؆pjdEb sc2=,WF_zkY0DÌŦu3pn{? %K甅~°𧇓!/oz4T;N9.+"1먒PȎZ\ I YW &Y we|Վ<3<% w{Wi?  c_fyJ E=Cu)sq85^'sJ)oƓgヽiDn6(lG=4ECK/kƅaqpxc33gfb.w= OK-RpX69QrFnGWo#wD\, hBgYsnZthIPޠ!Vif'5$%r#ä_TG' 5+ue DQ>L*䊄)nwll 3O!!qߑ5|]9;ݡٮ RU}GRxn~s fp̟+Ӕ@wF`D×CkV_;t6A'D&u ;KX #{y Emdx7qz9bj x6'ɝb$A̴4$U0bV29{CZi$DG Pd*~Aa%T}?f{KmXbnUr_0{ω2`C&ŀ#^J+?C؂FH8ffp]O Bh#`*;qsxrʢʉXp,PVÖa҅'lj eD aYmA<2琉LpiCM@wo'(TSJ3[6Kvw "'o9A HZ3fWJU-<ƨOb<^f-Qw膱Aɖe/ܨ'5a0js̑ roײ裳^]=[{-Il)F6U$xՎXGBۗ&+d05j[@ =m=A$,/*DeIco4e-Y 2fډ= o܆[L(kH`>mDx, u|p\$n9,ǃg]}zު.F2n~a0׍,c&vd}-v^Ba@IB#hY1&]=˟MMTI#ӂ|K5n"aW\mk>u Z1i7ta $hmI]h|@=DAshq 5M\g&P<?V|Gz-Db?YA#1\Q郚@puY2D͏$k~7称>?7?knEےfEqD|v* jECR`jbS]8U *a Zhqk#j 3D/cuAFT&vXNv"Cƚ5ᒜن~1]{DS?36 `C %w |P7afbYܖ ETԤɈCjzh_2+T3 >c3džg;1I\ıφ_Mbprx! YC㈏CvH lo8Y2:8Nx15;*S=>y@_S#"D;D U2Z>)"ZyPUmO#eK֟;M!`b!Z%# :b{g>/-5 D ^ZĊ!u HQ'6ozoI&/q >52xإq@x91(asP}f; kRuՠAx)40l~z&щW `7g9g<TNKp`&Q~/n]VNvCD+C% 4U_+}J`o^239 u%ÌͤZG8*pMSyap= Lx2svo=AP xr슌ܜlQybrPޓWn4&RdO>TAQs#>: #og5[cbn{HFr4t+_ zRAY@Ҏ٧Z:G[Qwy6n*rϤ{Z-/btT*=#;<@B̻`oCiw{)|h%T )ԑ; zeOOXD;! .Kɸ6\{y6`#86:pXP = m:5'T >rH pL18$@3}טWFE=w {%4sBlx5~\ p2'~њwL@OM4%BVG&8{,+?&-Z&%zTpS紤ѳ?4]<|H#!Jly7!u3yͿ՜ #1 eW@`^DBpHѸޯ=; f{\ِ4 !3 {grka@[;e8J|Ep/,V }lC8&*C(@qy22|:|5ac2`RVҐNA?"SKΛ)eB\RD};:~]T=@(kC,81΁{b<\V;k }*E3lSWZG۩ "]@1(O{pB^[jpl}gF{p$H8_#v7R*bh ]1k9;51'W `': Vިw 7uFx"~C+5%pTKn`sLCQRuF :&]}Z#+6u1BUpZ3*3U7@0(D$(H {V[)Ykw]W«yWu8-y-PXA;:3G6RλUNW`X+zv45 $mT*3pvk-bd ۞/Vs,@'mP1ƧilwI>Ӥt~"w;LV&Zh| okw>Į;I?Fr2{?K?=FEE0hC]A-q'e~GFJtfZm\,k3&hv^8q#n`5 :_BV9$ K̤㻑e9Km1 0#ݗVsh1 {*$?P:}B%(LՃBp~鈻!z&6ӏh: yf _euI/@L% t{ >qj.Gjx{S97$LY(< yx>P -d1" K$5QZ6xl{4&ƸûKڸ! ptN }ltXQ&"1d4 7Md{l)&kgMFrT=%s㴍;/ m~!(g+N|Oalx׿~bs:Sj@uHD0(}_˽mw-5Y~شdXFUzt6SP2ܴ&FUd`EΒv65 ;V 9p u20nߕ bA?x/4*W& TQhO'9;r[W#qX0mnDkPf wAG"6BI}4ζU跢̠][4Q1f#4W\ z$DBh%{BxS~qDB.*L|TLKց~zջy(-|nLXC|(d)*e)%G{In%(^cnV[滑v]&1 BxM@?DWtBM LRGSx=_ g \YDq_ v xs A2#d%^>B֕l~Z 8F* |M.M'Tw,IH<%Y$}NCt- 7wtO=6!}G#vqN -C/CFXBҁ33aVV)0 ^ v7%}"6iB->Be:֯'BݿqvEc 濥?F!qf萲G,@T+c^B0H|'3RZo ڙ&T(tPCl^D%u{ߡgu%o@J)<,bLṀtJ|Fj>`"f:ם҆2`3S)F+'$APxv<^T!!y>@%: ('J4*?A{ vyHc G,!*s1Q~< H=? Mһz]Fn|hb4I9jhtu m[G(2{'z.&OўS5fow!fg̥egB.id[_-iǖu>zBWi]`Jyh"},jDtf3UcwU1qi_!fF=ݪ[85D* !)Dș]`]Nm]2ܹ҇J:4&7@HVZ'Ca>r}.gV%V;A:=_D"iS $ƦG 1_%u<$pz;^D1O{n"fݎ}v!zqsCu*{u?4n^V =O,V=(-Ad7z̊|~_",I_?Þܶ~ѧ"5wЂq mlH` vBo)Q"#AuaСĭ萧8wI9AͳS)qdxֵ#Lɠh1 2s5ڰQNЬܜ,t@:/P[q\p3q=$kßG2S{PiX wϘΑ|` ݹ&n vL{<{^ Yhν> S2z @q[ӟ=^>h5sπxpM>TP —S3Yh˨#.Z=p#҉bLu&2\cA|zr\4#1i5kz벫澱|kL`V S= φP#G{G 8(WH}ɵz %GN͆uϔAPO*qژDch'dohNR nԘow6:mw>wr:q끎;ݔlyYz0z1=16{)x5>١H1E~xClOZ6ѝ͍ IsSaʌ[Y]Hwdv ̣ݏd@Nj-:ݥd*=uGΧy[, `tڗRbk_)4LnsZ_[=|VG U E?5NnbNeӧ]mHk®a󕝅>p]^2@^0QAY \P%Zº)Ͷ>&@{) pج}/AKNE,gg,SHNZU1̫yAXy=M4>aÏO6,J Ҿ`xڃ@LkPqa4MNO3Bko6&Tfk kXDt”sQ*k+ K Q,cېujEDv$~K4QLG C/^C)A g,Wl/MTnf"wsQUsQ"=g% >Z0e@]KO6Uf=Q9V͂Cl阱FUl|Z8!8=OnQGF< V ~oF:C8Hi+-G t"()[~S(yO?{&Il:}^&/8gɽ A zZkspQ=(vXQ[Ƭ&.{޳EsS(`?~s7U[U~ڶ2m6B HOĿnlmsnKbIywޡ'|v˼V-2cNrͭ(@8JYs"K2FZ!o{A0e_.ꠌ㩢&-['1ΨhC Oyք%3{c X@ SRF5D,C3rw$G݅!9 p"6o5!>d4<=Oo`ެWFx+87})QH0p@ >h%M< 㷣λ.x05 m96;98 s>t `ːcUA)he"u-Kλ@BZNɃ(WCn 鉮Rw{zW){ϸ]s SP\`{RrhsYe{ȩ9,"czVgq9֒lWr*nL Y&{#K bK(a8NYH7<`Mme)'{8ǝ]:z0RPgxÌhɲⳲ`33,X IPJVeNɣ^vGTRӴl]nE{s,b6ws==5\r *u^cOcz*D޲FC ; hLz@^ Lh *eq˗4FN9Z.ݳ :: tnv\du&x= c92tvNE&8v*Gco4kƇ>.N@q{Ee61/`<0PMk;|OWwAF7$<ܹbwmUˉPn NZ&5` --͹;[GGNNtblίy7٠ѣCgwYG "R1,x3QyDsb1l`K '8pwXhc0`@uN{&˓+N VOIKxFq 𾱷˒Ǝ=F6o ch$\FLD8nMmprȺ8½GvDG'hLT6 appnyd4`rc󢹷sˢ6생HB`g;erm%ctۖ9@k/+k_"n\hۻlFܫ1!QE BX*EK5 ¸fvBSD:tc`;z1wi݂2F!W`4rvɓn U@G W9^< rc1rhɧRclH.Se t+69y03Z㝇r$ y;INN{&O3Q4jBD[h`\0c3k:#Myr<뛁n9OhHdɷ`W2e\fLӜvpO&;+Cck4 rTF˗*ȷt묤]%\F- 31Fg` R&vWv1}^pɸ5;nwܴu+ʽ^W1nFiח˘ƹ/5Wwe;w]]I`AHj`bVES+\1Z0N)5V;F *6k<6{<+96g۶srs\܈{(1h{׎.@w`LeFwɣd=뮮pCk(c,a,\ѱ;t-rraќ3>Jă:FFg+0,-2KXeSrʻyú//36 stb 1ן^ 6L]Qi.0wǝ%MѰ17v݃wyw`\NEWa\!^t^,z,`ݕ61 2 syw7<7eEж"-ݔvʩ#0tgctNM^J(܌Uo75.C|sō+p15+v{nV'-熙vbrbh\yת7ϝ>utLiw]4lkd퓃 v`p]wfDQnUv.܌W9%wAN.Fh\e\r]F i(Fcdw[;9_NH] Ƈx79ŸW74s_WwWw]&#r7Mv%Fp*G.EtdXlvv)O`ɹTd8jguG9^=2vD|'odoy52ss ʸs+(nks\tn0.|SV QБKbX4>8!pcG'&;xӗkG+ʹnU5˧m;1M.^zpwkvYݮ%ιkrص$J5wv"ы\P 79bhcoTɇ~ŭ4aKL}-װ\3FxBMgiCƌ1vƐ1fTgàjxMr/)RBzgVz_ oQ~svs9q# 2a\WWF lacYI 4t%c$iE5v ]MZr14)f.i1Q+U-8D_8w(DTժ:q]8ӕƐΖIDZR)3.*n0YƊ[.NMBʘiUwB gPMZfnx<ɜiASه/{H*Y{Xi)͛QLVJeLݨ,8l8\M:G=~9WCݨ@֪8fslM(aՕvTɓVBD,l,%sF&0H-ŀivj#6CjQ̫cd{6]11::GY&ɞ5-J0Z2A"CpƒL9#YuAC$fÉpc-9 88Z]iseƉ"s.r 0H2cH8s] XֺteFnamK߲}m#9"@cd&Q\v;㰹#1bdywkm(X ͪ8!8Rּo$u@q+J¥*baÌH흚ڱΟ!nWDeR4!pc`64\9\.vDof 㽯88\gAy :$<ΐr.SdA\<;\khɴd@Dv S; Gh+("̭+vfNC\EE6E2(9/^_*vMtq vywĦcqKIT߱ZTe_9r\qW'-zZ0s=Y̗.y&˙u\<&yOL4]skQʮX3cW=6Le8t1<"4hDtO'&4Rd/.p#SZZ`1,=154,9vA!duc1'2֓6Nl$ct&tpK*uj2q"Z2q53V1EhFqM$8ͅząd՝XaFRg16RҷC1/`. l GUL;6 "ڶNz*wMhY)L@@oM&ufrdW.ڃ(f@ct;e>{xC.qTә|cA.(#w[ϷE[3[v*}󝼰F^cwZ`5SS!.̘;-¬avpZL쓱AަvaQ+zESGݐuy2h㈽5k;M`8e#jÌ/BՊܕ235UwN9{kU*9K]4WeuZytP9Wu[|gț}/'ͱmZoIc&ҙGbon9#7AKDytrɲ@J9۶axoAb%a_3%ZAL.![&ۭ|0gBfqy;u/Zi,Z7ǍRe w]Cof t/ξLu~W݋wgdjMz@lod]HNi[e4wJUnMtѷyV"Jʛc]ײ.,rgWcɻǯEUlBvk1!u(-wXڶo-VѕnŷTnEݥviݧZN3_=Ǘ5T]Uˎ| ;他JYʫRճmm:,eP THj;辎)V[¨CTvn,YUu[ĕUnSb^z\n㨲dM%aKKvr]cUT8dFZ RVaέǣ =6L jQ݋:',fMrZRfe ,4|Oo[ymv :8UU]Qak-eK;o"f6+_$1f4~UgR/XK+n;{U"Qgh4ۮ* U jgQZbѠYǹIu\]丶y:7`ˑڊ7UUMbk}4.5Z# h3Q*8|,qb6])YcfflQaɓa4.\D%JQ#H|c@qdUC!"~^FX n.퇒eoM7r &Z#;)՞2\g J<}H͚_y@7Yᰠ8!jȰ5qU@>|1i̠Xٮ9IWk10QDFI=ΖYmhUԠ t<`J#폞dͣgGD[XH/1 8omCp>-VAX,W/0v񑫥G>]@8*>LM|KIX{%+O1!aD3+ I1t}׻(G1P|*0#$:Yil0U8Kd{k MA۽+~QBC1WX]֮[<qƆ#( U)zQbîySw,n$ѢPX 6soMmIgXNy|}2cl*Vgd ^ß6"Ր90ѼUA4vxY0ұV mωa.#YkC>;͚_,4PPԢ:wP{`;("L#zi#Q4\pX}/^t^4^KJ>N51Y@ ZZK' pu0CҠ#U$bhas i*;U/7F6eF|E$J[.ۻbu)xHg{q㹶wk g镞#.=uho{*o:鲌/9o wKݦ. uf3U\W*T.Qf9)Bo f^73A]YB>h0UVJ=v3+Q5+|(q2pB40ʎ ,vI!Q yv#W(KhprҲNJ_FyÔ[viCHO!#6Ǒg'k]LGd咡`5y•2 k:smD#Da>QW@&N]4e'HI {Y݆苫hU G qY*q6ЁkU2 bKD&R#9K #Wٛb?<B+|h4PVv# Y`w1> jjɪ/V"vQ3wwQ@~H SbYڴĢ=+[ZEmO51Wrlٸ䪒P' |H-(6g8r[ۤWG51f[GG"> p7j˽:pۺ r3vPWyuL)B4RfVZVv =:F;|~!šsZWY0θʄf\h1At{w&•l.7:;!U)a$73paB8l5[QZu]Jb ޱVK0[gnڠk]v \→e@e^4@wr<#] AjX4"*QeY̻zp"`>V]0jloVM^q duSE:vB̻[J8ݟ%.θt%j %zȯdu}N0=0OLu5x0ܧ.,u>v晌d@ f"Iv+TE]ldi$)tA$A yB+ sCSOjtoUQCj~^xR%/`R2[DLaH hY8W R0j3!gCDBU#;UyFYcpUOPE5 [S5AY xv;i;vO7 ?ɇ4Ǚ2%Dn;7M p8@H%7.iIOLB:zD*jm?'l N\G<͢C,KV!^5hhZ@^6.xi:Yqنh;)kClB1N>x!ρTU@9arh:Zx T^O4SA9i)w&K1/}G\ZcX (-=-8,eT{]^ k^!Ѧ M|E0<]0o/Xrv㼤8v|G!y >B<'<ֈ2qb2HR@˅lHPƦӆƻBiIltuFᕖuL5[~Z+3rEUno:}ټ;{2g T5T;;/yVu淛o48oR8B"tr<9f`z-iUt.EJ40n/"[RHpC!ψZZQ|^]sW{ \3(&EݴW[]زpPl5IubУ[[fn*Hc6T=Rh;40U\vnwEXMW Q]+#OCE0m7Ŧ#*yPfunPjmp5 ঍|][\QJs);0\``@UѠUQz3FntW%̹gox<  uwI+Qɨs] mN!۹oDR֙՛̭Me;@zBuEIX5k6V]Fi4 wh4&VͦNⱫ5ɨ5ZB5Q׫cG`Bт#EX,Uts;k<'lbu^2ڬj #$ )C<.Ϛ1,~Qt^nlXl,[.f.1o=af"{:<=y<}wqzAzX(% i]* tͧb-6d,FL0UZYE<;|F+ۡ ڹw ^rA(K-5uTm^$CG:G ffswޛcSvѻnIA96@>L@.G)DiNp5MriKZ!-JV 3sQgQRwO޺.s)sD$57)*Էj@D)5:xSG۹$T%(qS{|.JP\f&G2:UM&󠟕J}CfeY~sai'>Qͭ\s\gRtK'5B7G|ǫ`I]<39~m+Ҵ12{U# \?"yrD η+#NbT>3.RIw'+:Fyix2fz.,ͯi;]7;.bcGح^NZ]Wc-i"]( yƶ//i/Q?/f[{ك.yԄSDs|h\tO(ʯLk5scNr$>cwm+PGnύJBI\Tj#oLqH|.KΏ9ĶGS)xu{ރRc~+/QC":usʢ^/iuT ʎK[,VƓOvWuJGpNCRqG}cYE6k(tJIKΨIn(jxӢ +.^9kWJ{VY/<*-\"K'HP^Obg3>xCL,}$d޾4Mj'.sFss($Ny_4TmM;W] UӢC48ϒ|&I sun*'9l|˘ڳ6-[ZMM9Nپy8򓓊ʮZwNa4:܎Z{!-5¶6K:Mÿ=wޓ/wHȆ~͒Zi׹>:&Wbyׇ("rіNΊĤzbj++Hs#Qw\Ki펙+wgTE|S1NܺۚϣSqg xu_&2|z_{1jWqmZIY:sIE]S]\ouJ۶kkȽ\5TURȲ\ϑl͐,3rVӱ9tur9JRY0u`sQE~::">=WZj>z-Lӑ㇏Sroͺ //sHNd7ZBHhJ8}1n}ȟr(.K.Cϝp6Fm3g |LU %R.'\Bˢ?uM߂7uγ8/4))'u"^ &̺Wy8ܑ,Z<:!F`(H0I0).Q"^9lJ-[e[,Ok5.y=Lԝi#6y M 3q;әw XvN q՜"d;G˻32욇g3ji76A!d;g%9N &vY7L8屔s;sy&yp͕q3,:Pz)*7,uz7$=Y W2r ک]fv{Rk.VSowBstЦKf6nx0Mm32eVVTtzy/XJ72>M#6T;fu2xeE9uP0F9벉z ީԍu&[uڨ^=j 憖lWYDog #&xj^=V]72t=v˲8镐{Eef 1^!r̳٘kymFbW{tJsѪnd몱̬4_Mw)ys+9A=ɤ,en,rD̬6V>wT]Z}3n՞mI%nylF`iu^ݵ ӿYӈaB#s;+p/zy<tl\pB*(`wT|=/`gu +b˓a|Ckj$Vs&V)( `;_y}s>Q娷]UL@!=Rb(#>GAHS>ɾLb2C|ZWu 6~9u!%WM*%A!|'JTZjC:?.He@2eȯJ/A #-Qs!PU+='ɫo[Y*Ct(HJ n4hKBTVm 4 [l,y /k6$r++akOct| BH8򢢈=żk8`"oYۣ(Iy'P>,P ZĎ/k p}۲cU̺Ɇxj".@v!܉QNkM],L#K" KtG&<<Թq~qJaqc5E2 * ;ۑO $YeF[ AB4 IF<1Anڪʺ1 DH>ewwqjmr`Wt/p6 3I; SO-N#v92Rȴ!qxltC:ʹ~ce#.QPqj{,Tu%!X]VG[q1)! Mܼ雫\Cu#OLV!&@f9 ː\Bl甄~n*3 4DQknxY ߈2xoZK`%ӗlH "X-HrDthش ,a,WdYķE5t0¸O(I!"z)SawF ~'pZuQ =ĔW nVYsOC\aS*'o,QD0{<|{2UK1Agn( !W$ ,!d9 {fjt $> 0 K:mXJIV8 ̻U"m 0">")vHY3tGO=ʫKcc)ɲNAv4utdy$~Uv/ W97bC`7p7j.˔ LUHSLiϫeϊEĕZ!B jwAv״D !z̝/Iەg+_VIۤ׬:S<~Ȼcbd"ȁ&n8-N SJ˧&"yw'hQH)kUk k\$.9^65F*Ԗ)Z*xv='&vx1ij3Dީ٤wNU+NKMT%9Fs 2.uv/$ew4N.[&ɮ)?sS!9EW*:ro&WYL74C%R5$Ku:kii\NӲy:93K\j%6th]D#eןfڔy_m]*sҪWa$Tk0?|-0!VOeK*ʡ;|9nq$m;6ŗk톯%HG9h^g8rr]KF^؝ϱ9s?={}G$,/d]Uq-@xR-M3N'+*)c ^|g=ʫ]g2%K''l>"r4=46ޑY vپܠx=XrtgWג`?9O~MWɾm4Z޾+}TvVsK%fV}_jP*Ag.{tjt;;z̈́Vl*ה:rg)]>ˤS'Zy^ >}ڑ/}/ODL xB JDnUOz|5W?M¦EAH/kvHiIN MZKv#0p] Vtp kPV^Ϫ\MӣkuiWېbzwb/79{?nBebOɲ#K&HeN qb\7ϩVWp;fޕdxW1^Ș 2f m$ʝbϱg^uٗ(M%9$k>G:upV.^*4Nf`?,$f$ dQ9mioL'rMn,8hyv*[(' 2swWpۼ =?n뤋mJGyU.VEɂ]$2zgȗIEe$&VpI~7][+L^:β/OHYGo\`H.̵ˆ-h̕uZ3/řM9XQkm׈ל6@-x٭Φ[*卋+ʶNsN:KOTpQ"vN>E+l0Ͷ\rH~W#~9sWO.ȫTYHJK[RIڽ:[dsX|!)y벮vwYj; 9eӮkqT$*X453"вRU?MY0neGSO>zehӜw'Ri^Q3esJ~'F͞mNG ux2Uw;3i(I]$JY'7[tcg]4*~;3oHms\g--ks;dMҭ;r^Ȭ+ \VDuZ[r Ӛjui5^5 Hϯ='nZHEtm)"k_,銞Wt$bxZrr/: "B"AR! UY+P^g.Vfyļj={yjmG-Y$ ^r'.B 5W M-M1q⑮C EX5dѺn"g(gˤe2gnzxPJE/Y'6ڎLM=tnԺvKŽNb7DLjg!Dj(\vѵQZV\_H܋O]كFys[:b[lVXnYUNtZ6܉EGkwLo].J%񰭅Sv^;TKٱ=fRY"^^L@n1Lͤvo7zlݹp4^rIPY;1+G6nm6Kၜ-o9r*mݓW0g2,ۘ^`wDh ќ 2bӰݬ] ᦆǚKdfFsl+c%NRvp%\V,x+ÝJib'IN$Sv٬s-prA;n<}pAa%9YVIn46bJ0Lt/ۖfuiJӠPÎGyd:If)gU㧌}v]kVƾ2X{1;. |֐Mfp¦'vPJ9ڨ3FEfaTq'"*oPm^Z=&&cfgl >y9O%4MӏútX6)Y,ad3 U;18V`uKutg.󷦺Cd*MQ089%JM\z$M{P7 WrcwiNM$pİ:e8r.%BUCgDYPFi[Sͽ(Lg\ACCRXg{^,z,vWZpEUކYeEbi#ɒhXzh!9\)簽o޸f,vu͛x&sw? _.CFeu/;vilFUk76=koVWr[bB4[,rf v_̡|S%uDlMY((uuѻR\ueۗHS5혫EľՃdfUy[Ӫ9˫beV:qe yHUV , .+cDyR!`f+ 8|Gá:eH5E$+US wەgs9HJnl\쬳h63 ;_grtbץ,7* y+]V+n@b,fz;q[ȩIeح,Scءn4 b3n2ª&y3[LJSu5yJwe幯)lz ȬjV;ɼvsjCݩ=7`f -z9:-֙MŻ!bzW&(UU\gUy^0vuս+m-4($ܫu6YoM^x$gl 2!4$NXDb`fu/{^ Q<8WS+1;\XppҠti xl;Mnwjp/V)ktա=;eygYxtnJw8¬VخXkbIȮ(nUD!%$xb؈t봬lnUCsvLVۚ9ynJyґ3IkVc9Wq5$N7/qo 9*fNu,L~j&ٗPKﺋXkOjx_!YG"֭R x6; h9R&κV^x)TnچpZM^Paƽ~ݨ]gSwTy P.׻鮋BM,gR@>2Oh#|,ʩ *vijNlc!&cP|^iEV`%EhGF qgB{&a)>v:MDS2߄q] 'ÉL>CYE +X䄶t0;K2d,hIW܃V*,6Z07i&59_k 0FsG32IHu[jgoeD8¥u[[-b^f&pخ]杢Iz sN >(hx0SîeR(@xzӵ)-kꈇ#3s|xO,[AG)Jܸh՛[ͦԾ*^I&JL^ڷx.wD-ԡ Qm՞iQVבh Pt҄G*x 巗ImY zp ȼsHvxĘ'l:%"+hFl٣a98xU j1!vE]YCN *56gXjY]Jۺ W1|CV] x<-CJ"tC`mόV]T.!svg)K2NxS)->cHio']F=8mM Rp(H!bTBja+x^MED-l,яv2HFK~Q"TG`kX*TrTxŊ֨5VdobzPÓ_F7,,z}0|,LLʡP'\E" \eЮ^"Ը*IHiR2^0TZEՊ FfƮ`@9t 'ylUN# d6:H@Shvnn^`@~ Z/Mm9$툵H(~TcNybuF- Wz޼k]˲E}Z.w@d*ۦs bE  yhcf+UDi!e NI XF6K`@x]I^i针IH$^3em?/Na8@մUQ6`T.*R;L6<۳iW<ۖZSWJ')K+<%Wt5 [$) aX\UQ$3#"d#x4I4/ 0֕eshn+E,7wwnL`x(}R,4'C8x BqBI2 hdlQ jR|rH`NH#IaPBURK8ӤSixOgޚW[O!ϟA5_SY;Z}"^R[ҵ.XMsÉm|Ǟyot^'Ѽy$kp6Q;R$(}^B1*ӷAƇc FN(~ g.K+ͷ91ܢ9A2UZؼSjE]Q׭XI.^ЊtC/5D{t }`>r)'QLDoyL4DdbHdkm3_>;ǏϜm2HyzU#v֋ڑOqHߞ5{^7XSZ(mΗ6UUKUz+^+"X/\Ӭ;od/7{7<+ϣy%s(POk}>\r_.m|wC-y3)o>q%%6 F)D L VmZ-S/i{x{x$Ix|h^ A4g~ t>ֲl`go{qx=_'K;B%em^xNxxEOyʑz{$cW+ģ*UݕUsȗDK57kn0JXnN]yk{._ҹl_e Kݦ㝟 z**DT9!c$½/BsI$itUm>CZܜHJtVsDC~{ɼcuNGɼyb}";Ѝ>$u)oDS>^Y޺cNp l+a .\4gy3M0μ!lXdk̲Lsƞp*e3w9r" :x{{ʳ*xjMIJmf)g17a9 p@|^<9N"wg;aa:Badn;ͧOn9x."Cacn>rsr %vwwIէCNf$׌@YS:kpXeA2QhR:~$jRVhŚ)1d 3 3kyYG!MS) ,'lp38s{5%d 9;;ETk0`F!eG-6C cso7EFCd[7rTq4׭qwre*G?ٿ`?ܘvNG_ k:N Bȭ$wu&I%ݚs=<pʧvҁio]Xj)]Aו ]UPuD$dYR9;p"UŖm7V݊ηOGA>l*z`ُ oo.7Webf:Rrs\T,Ǻ;Y18h3Z DaƉ> `#@|nUEʥWڷu͚[zr[|bX6.엳%Ru҆g"J凄[u]}Q;!7/N;+(ԙ]Ym[ѣW睶e"ԃFl!yI8j9<=:맽v Z7`qdLʺD\ӥB!ۨeZ6ХT;eX'gM<ɥ1F׶ Vm^ݍ]UuCbU{G87Gseq|ޢCyб=^ǦRsѵ «s]+ۆCfLtR5UzzTW:vib̰\+E^il#UǮk鉾rڝ%:,ʾۦ6+[Av݊QC7rUM+qL#.U=@,\[WO .8Tpr#/(q.sJJh1ZNTSʍ n"6ުF8^3^Cڸ>|դ葚=X9jUgv NMŎ,{H%(nRoW`S\Ŵ+wMuVnOkM;Sx'UALH*:CTUػ,惩UNWPa4FFtbE1YfUcN|ф.ڎ,k1yK1ӡ{u.4{ypsۣRU@upܧdw|=hYԁQ;^gkkv UC}e DY~eYe׺=Q=L9^/v]CviUoT0%s~Hr;}6.D+qU릍u=0(0mtmeߵ^ebqgSeNofYc] lqRk^sR/GMw.zW^g4&yuھ>L^iɞ~﷯`e{dU)w'9翏~sr|`$9젢Q(Зy5om!]OVkøK",ψ2v6jQ'=#)%TB =6WH(A81Y( kc֬s5,݅Uj!dqBo=mgWƎ<ǒuQdե$jk ^̙9ˮ1ur^ޑ*w<ʪ˱k*vE,CJq1q ϙK26PAё0ֱ 졖1fa=R@#d!!=U\!.um %2MVPgh T5P;5L&֜T-e"[kKvQK#2^Z:[ޗ =v+x#rqxnO7rȣ)pF'V:p@{9IؽCOAJhܺGnPBt-"U]Vtt^^yaѵ_ -<@/wpo åy%dfJCش9XV0H%V.ƐoU̒*]YxlsuFJϛx'mrK(7EX3͵O/sIĨBzN28sߊw0>. _ @}3R";ć|oSxm̳ByMnB$$m/c$kNέ@h]b ŊaݺFHWP#i Q2u:)|kg6! OBxXiXp$k R'^thҶ˧4$7h" ⳋؗ]u$>:|5'+[R sQAjQmRR_n6yRET[y|O2C}g}g2y|ҪtJV{/5gJws9||"nW+R ^FV%fY<˰&/ uk9pWVG:NbZbebBe(3&@}Uέ2`SS!; C !GIT\uq8\ncvn}af.>q%:xS]<=gN͟hLXXm&$4zڵ"ۉ.OZxgX}}889&ף[C'\[ F>vBڱt+CE|?'_=WAIxRqMEAz Ij&a}NQ1QC4YyήbJqzhWo|EU$N>sFr ŤڼYޘ\}#>l'JyϚJUi#Q},@zWQt]gb Zp뭏.i]-{҃K:;v6=tTZO yA4Q"L*e $(4Oon&ngjj7w&}WYf/op/UUr꣒U:Xx<\um\{.Vf][|x8ܫ&C5ueq(wc҆lWkQx>AGu6kcwTD\s2=˺М.ݓ\Y"綻IIoR*߄xI3mS2qչ$Ꮶ U%Ui6^'Fs-{;:#۹)W,mR^1ɏ9oZiUE:]+Zkt+W:;׽ln\ oKʲ^{zÛBYG^|'R󫘹tN#ĬQU97KND!QusFQ5˼4DNf\m],+d2ZTP$"`i]%Sg~]Uy3\Ugr~aI]N%,#GgQrM(8vڷ7/m-bgYg>%*%H HBElp*, =[G v){yy^<8TLɉIu58|.j?=M[Ѣ3~YA{6~N* v_<{ *E\e&^uEKe6rIf煋!%7We:Bъ'J*Ww8tWVݨ/O'Mk1s .m>!̏q{9m\GRt}R䢍Kϐ]a{XMp-FO=8NUua 9^J~%WUP7RAʶ[l}y! %C:#)|UepR>Ov/g BSlFd >XjBO+.q%R'%^^K$o>ފYrr)vW'!vqcN7YcŜ &W˟e#+lSWG蒋m!K-Bx,WW9JźچS҄NN{;T참U6m.>Z9:||όkvKGôi,,.iLv N|kl˒ 7.kɹ'E^f]/>B3ͤ:WF;'MhsabG3A*>jxnJT#n(S>o َ6[7^¾w7B:Ԍ;g:+ gOE+ vTaDe:xt.nlg\S!eA2JQ"L aaMx@E㪧 r>~H֋3qxIŒImZUXyەϙ˚]N:.pjW:d4n%ʭ:)9 Sg`3;j- 8@V(-r\EܗkaH`;LO/Hn5*rEdqW܊:s_o{:Ǵd~>]CĠC^RtyE9kgjf|ⷫzS9lhʐ7)~eE0inSyj]a5];vKι$᝽"A'YXU|猜 e6&9<6彻nfnf"zMr)LMMy9w 0 6V̛45I&$*y .^ެy9UܙsNugf[<*.s ^,8蓈pK(жvGGӍ34xc 7W<xw]nLe8onw N3N\N#J^9gY-T agkn|{/ɛ#(RosƽNK3\3U8ӧs{VESEL9`aرq qyx0wX `g)q)xӍ~~/;T:\Z5.g.uV=鬚ՙԄYy~E•t;k8QY+37K]VnV,|Oj_h n@UV欵0SI;tZڲkZ/B.ϝqF|q=۩p'yzMQmVnnfnX˹V-ۋ4aW.mA9iuQ[0U-Gl"<יy8gLh{a*yr>)ad]Pou8tiB-*]Qxo7.d˺d5*઻<2%~weꕥP)v[w@]`pX4qڸaaN㋦]۵ptkvWCS}Yy[o]5bAEܷ="ؑ&pՎuEwP̝:ڼ^ 4 w^rӳ6^M૶Ъs㼯z:[ZqD͗өi6됼uJA ۇ3iMtZQr3d+Mګ`ޅۭ3kvU }Hh]9=4ÛKfŎVj6iKLaEWE*] n%r'׷eѨfl4!{`Է0/_/oհtY_gui.+WBN m᎖)}suٛ(N]z걽j>xXvFߦU^Pٷy uU4_x7V:R\YD1^ cP zǺe-M,YuV[:\)4^F&.n.k*U(dUZ4B'dB4(߭ev+± y ޝ)]-3W"n p8Y[EuGC ,k|T^ Τ b1,]s#iu׬W)˕BI!P=,8=h}pS'|\//yb1;VAW@.D=nVc's;&;nQ#;hp/H#tG-`$\An)<Ǜ'Ɠ=PQCߞic39q&Zda:iAl;9K-+׸㺫쎆 "Yn'=(466,Z=r˖vCө'+x@\0[C5-4-8Nڰ,I$ `еiE6Fz-Vk JSG̋>QyJ. \omc ӻJf/r2MaG<#dlhb+`QmxHHbV|C$E>/N3sEշR.SmS`y2 ՛tFJTby}m爲`yJ'c۶m{dUBu93)<57:SIZ}ìVշen ˉ}uc 狙0l4Qf!5j;^]We Z^,QW<ŇRy@V]֫lu Ur]O{"&S7 G*<#3%ȥP9WuϵTj$`FRoB뎬`ӝ Ùӏ^[N9fz2h{tm]C76W`7K ҭ]P^+.Ct<- TWrybue*cN:o>ψP Ao C]ƩlDxѾk)[7euty9tqQY⦌kd1/&Vr)-j]d{]{ͥ݉!+S.j!R=U& ѕ22.w+q\d.:,4.Ƅ*.~޷:@x^ UeU*URzCswRWÿvI.)5^3:cn]^eS2uMCPrGYAzFnq{ѫT_y-+%9;-|McŮ ؆6Nu{0Gˍ>T׾dXVmͪ/x@ýv/%vj"/ M7Yf+(zCx=qRՉ;lmv{UYU`9wowm7RókYԑ흧9Koze[Z<hYXfbCΐS={_NͶe1 հBa&! kY n>1R4VZX0n+\S36 |%˅K1"pj[E笗Gt1e=44c"A>Mѣ=Rӆq4!B׎iݒȭBb˩odk6"j䆞;OR!) †f.}3s(Ba"m ݑxq%n"J^ , bdU:¾T8ݸtO%u2f.Ji$=ې+פ4<ɤ xEV&% `l׭:±9ߔdB$ (ш_z]"3tO5⦕-Yl, Il gu\ZHf] 9KB7Jy"!hh *$xDcqTRopgMTQn*86"rI3n{aڃ ?j[bnBҺzi>;ic3quJ:_]mGg^_vL #t)=gz'bWnmGV]%n_{;8c)fVv ꮗYU%pF:]6_?^N[願sŕϺŋj`</ >~i5 O3R7 Ӈ?LX@Q?ۂR A[^DH9iq6BlwtwevQUZp/׏8\Y$4Epdx!4&^?/I8QHeuX"$ Rn#On&M YɆ^A#J݆~ncv$xCt p9c!P=Xo^\葫n 0%Y wq4% h"k-y!m% <)I ba Ƶ-e!%;aVeh0wd!\;mIZ > `4뀒|躌x@$QNɚɒW)  I$ҶU2KTAC>Rj\$L [V5SU)IQ䯛|gǾRB&ήmGѼ# ~$V2aX\P4!Ny%I* V*U-0[ۦo2>c "DQu2`5). D@B4JJ$pjTx ŷ3:qiюR<2n<<:۱EHC*DZbL&A4P(esw1e H]\ EGeg6A"+P(5XXU͚prI7Uˏ1(-x>\(@9YU0'YXr[oٷ ߙW6> 2.x8xiA8P5veEH4'edViߛhEit/|lƵBǞyR֚X.1]B5K1&F]Dut(Ѵ޽^}4[xJ_uڃ3E|U}m+r$yz{RkΫf8*}BDTln݇ה'R;{&5һ%;WVu4##iUlS{Tq4jKNkl2o$3)}!(IX|4Mu 9r \;u@blΠrZespz{>\ (٫-Cn0E(Mx $B@klxD0rsnfbNU *6*nV5YuF($:wCuص+5zB^dak04zfv Ȏ*ptm躢Ǻvr,s㖕RD{x^D(++RN/]ɘ&JctWRq۾fe^kK78lзU5.UabY$|6/sN69)%귶1c+,A5zDOkyrR˅)rN9T=K2SL-d>+ui-t|t*Yg6{v>{^}8햆4#Mnلˮᗶ- } lv}랊YS ;zc/sRhcxJpߋ9n4a̲@ mmi*H|ioKiN)Ldy`F졊Bغ OgJݠ`}#0vdGQ[eVTcqIN*lh=6оL&r6RTZ ڃ[}V{ 9بG՗(# "NF#]m΍.b 6TR< P @ESrj Qrw!@muvNx`FOzq=}^!X].+=z3v*]FtowFm\D1T]h+F h$w\,Ӌ(%hֲv[ڣʩkIsCLtC n4<k,PO'nQʙ!p÷ZQxKj|Zu. nr]rT[eyѳ(g9SgyurEPo'z-*w<>:BduI!Eզ]wrlaެ!&Z۸ss4Zp CN\'ݖX3;u 0ThTz8u].=g3ûX(HWcW6 +Y]p]qqܥN+k̜ uƇ,Y%փ{o0fgm::֑h!`K-P؈dkcrȭ5k$͘[ T r:r%/VX]!U\ 4^3SV:3J0d'jVUܲai.iWffKedWQQ@ZuZjwׇo)u >o0L*qFuV%Ûݒ]Rfr :nL"_՚ݣ0+Buam^irIST庪nwį]{޺9g GV:z'Ltr,Z5ӔeZuIdpU+v%^H }Ԯj!ޢ^WCaW^(jdž-OM![7hNb6qHł֫zb% ȇeI3UFJTpN8pꔯ7iܓ]s]FfѰ}XK2Nzm/]teκ+]$H+LW{^ ]=gb+w ys&Y;MsZ|V QgTt:}+ PtsZ1Ϊ|Pf8v;,vWhk01=m]QR6^o8w*MhYmwRҗ3s`~nL>UB>݀Βh:d諲ZJ- .:7S}ۏM&/ e|3ɫ١fR/fS1˃GgwuVz@ѰXƆ{M[!}7'JuĆ:47os rn~WyeuկT}# 3|X>㧫m TWՅi+ w:> {9=>yrK.!x WKv6b/ .qaYj,TyL}q.wLw<*ZYXGc7aowgmTM pTaeyu\ Z ޾/bAD6J;m^ܯ*8H; !X,vXU|JzDatơ ̺a,( r0'2̉UU~n8XUu5*:-KX\AчJ8x %eX=x\l6"ݶ1VfDBs.TL c6RYYwMu9+r| ! =; ]gZci6ƤATYƚ+01 Jr`|=5 ]a8,%ѐoЅ9#MqT<x _4ne)O=S6g^ L6sv\-y8ͭkq!AϋD4)^̬Ffr8o:*gURv&8Z3s+0fJUz9rw=b)nvάcY\82mk}(p, V {ueͷ#i ܨN~gc6i6a&RcFOqÃ;=^a{Mr|y" kX*|quv$ R4Wbdh{-Pp,v}Lx7+X7w.ygV3k/l(iZ+k72{[[Wz<*R&-p#ry׮I Y<퇍QŻ;ADuдq \0PKY]+ZlegVt.[ڳ7g QH=:yw^ t͉/̕T4fWqn8ZL̃hYbg/nAEh/298]ory4=bHj"٪>7U^Dĸرvpnsnnuem]hwbuBm>.eQdGa97aOoY~W=DOTn{X_;ܮWs+ڗgzu1oUVQ|\s,^Y']uj;&g 6 [7̺(VVwn%@&55wsVKhݬՕVeB ]S%̻j,hΓCBY^(st7/E+VxNv )#WZ}[S;4\.ƩonMkV\u;SbmZSqC䋯8jwnC3 Aww)YNL0C96]_j|v쬽}\/d:K7XWI}׻SxkV HV!vA3իn[-󦏚H [;gOwقQa[lm-J6M$1JHY}v N2]֮IBz BxD;}:#0m6e* گj}i⃧E}j:c|d[cumyWέ-oN *UUe[ӽ3]*`ъȻ)T9g*Olm,dKxI| UZR*G;*х ;ͮD5LT'ܿDXyxq `s6h(E?3=ytȡ @21qvM׆ĊGAQbi1VWW:VLO rO$;Sˡ$6lSJKKA`q;dP,D|1bj)liBOj#jKA*p뱡}u20mnZ+: OobH_2Ʈ3*C=e;p84Tӛ[/Pd#f>Å$KIFֽVH(.]<(R^0zV?x*G)O.lBujUM%Y,5 D9ei̓\5B" Y1,B)4|5V2 =k=O~=UGU7Ky|70Qr!d/XㇱWa_4}=m}'ՈI}~z4Q~C?'HH}L<?'?'r}sd +7^\o϶ Kյ-$B~鈾N|֧c$9p߮^J&6;V} bX4o+aH_l '/֘$Qlҷ[+zN.$En&"ZPƆ1'>O9߶OYK }T+.Z}=cg3/^~}}[_>~J_?^~dne4ۦU}z`uYra ?k`|Og1=z|Q+>Q}|p!aELAA>ow )?Dfȶˏͺ(軭ꌱf,!s<_͡V#X̔p?sˆu#t.H)mC˄~`DWԅoޕb+].ߓ_n5D=ϧg?40>COo~~~ŧϟÀaC!c3*z)kWk }aͷᄏוt[uāV]y8I=z(85z?5O}cʟŏ샛٤13Dۍu}_TDؽ a넗l;u 6h=_Ǎ$Gs%%SI zcߩ}?3vKz }w=<9p{q |$IU_?k0U|۹ߝ߿~ssߙ=ˠ4p/ܭ>>rl|dzϼ@O|Mۼ{_6`c6, |1~/W௟}}^(A+/1?>|W>rexϟ ג=ư~^]O=^XC8D WP?B"Om?i#L#[ܙuy{gZ)9Y͈O[XpJU{ħΗ(x"|!>1$ Iq)=W.31ac럕Sr?gw}XK?5|?9Q.8z"'O߹DI#k/mz<~4Ouϟ~eWUD$HUuFC?q}sEΒ(yfCZ'l|`֔ܧB }EK_<ϝ-w~\{z8N9~,il~,(afqܠbG/;ex?ZHoDp%ڢYI{M˟!}nzv_?7YȂ,|DMy>!˹cpmkCҕKRF.չjs"if{/=¨@ː#lOOʿ'xT?azsQ)~/~3ߟr|k?ոUr{6E^}2SosL(~@p?/rI wsr((ޠ?U?ӿ~~,48%I ! ^/((?!:}2`=,>|OS/~VwZK=./X~~?KԚ4;f^L?kڤ$] pVS`~OΞ~r{ ca>3|a?o֏ghڔ0g4?]ԟ*/'a.6؊S9H}Nc9!'+R1(}3 IE$i"G@dl Fw@}шHGϔz_/"o^E ]w*#zݏ2ic PiR>a[h/OY%K7@/bhV\B i~#@2VPDѽD0֟]qg02'J eqh _F^Xbr ?^~=~D%!"6>~?r_0|6Gۋg4d2B0K?5"_/۳PVO;qAu?O6 G~v?5P?͝G謹0İ?od8¼h *_gEտogw߆(!k`Yu?T'$?uq4V|D}@5Q"Co|3> .wd5ۋ ,zMdr_O;Se鬧/}f3FY>r *1l3I<,%ן· Y\ܙsnQO*7=Ov7^_b*% gHXx7rJwUFZH*2gmbM8hGLh`ĭiu$8EF?}(hCgCjF#R)>o0~P*x 2I~y>~`s,X>n'@8P?3չ=kݳ%}>DO.U}?h"/޺zZ_=ul3, J\~ #̌${kiSqv}A~{%+WӵVwPRoP>gk{U +՝/p˟S.uuwA5'L'Kv<.(} =>/Iǿi|?絘x6˗0O{>cYyY&/ٲBϥc.ҩ<(>%wmmG7/ŽÝWK"D~ҔH]#ۦ++b?(ݕság|?'|} r~}|La|]~7)oJSUb{H)}j򟲱,+wz>+> *V/1Ѓł3 }UTyy c"V!z6,ߞ k$oş6G bl"7׺d=Qi?ߛZKJW@U.x'<2V9 Lϟg?=Wa~WͧPe'Ӊq7@fzs=8Ϥ:+?o¡]nlS)a5qq9}R"$OB=>i!g{⠆$a)/ ?nCHB@z$Q!YM ωک'ۓD>U+ @P|},Ȯƿ{ρI={"XTT穇5nܞ#3uiU<, p>?}\2]Պ }B,a^P^A^AЇ=?c? =6.Tu? 9QgX,)3ِ4{z;ʺ#!G_}ه \Wlfץ~Nxüw<ogڞ*C=2![ [JUأ?σ*L4W}{4OPdWe?ZB4PlaE)FLA K籌 |(H ϗ?O>AC>sϯ~&X>}{>*D;ߔR>MY>!Hxϡ~ύ'` >P^wHR84F ~Mϐojw}rk+Y5A^[^bybGz:^A'c8sŐ¿ jD_ç'o 4m .C)}A/w_] 9'.~hy/!^`Jac{}}UPg_]0;ٞ.'"G֟Y`^q~O/s?+GX#__~ 2A|r'ކh߶}O/ԟnQXV+7;dgZ|ϾYlF(P%KlhlV(تdI&QP5,h4XH j,Hj2bd%2XD@Q1!61a2j1QƋFEAFƊ41M#TIZ5m4Qh1011"ZM -P 7ǯoXLͥT[ b6b4C2!_{8I$Xcw#}Fb1j(ҚI3iQRXMO\&IoLEQ6S"@ƨm0Y-D6,FѱIh̚ʼn6M2`lAlmIFţRdL[D$hZAPTʒ1-"FH5(1Af dQmEQRQ HTQ6FFPj4m%4,lQ4FD-43h2jB4H&ƓQ%A`MOz1`cH3i" VhI%QIhk̄2Y!EId/_Q&lj&)"X$ dDɑQIŤ bh 2M5V,&Lj HQ L$xhbK%WbKjLIP&X& 2QjE dIh1e ƄE1F1j_bX"&Ѧ$DFƴlbj!6,Ph XőQIKi2!J h+I$UbdPQz~#?>WߏE?[\]ys0晋\!^\3]n)q ׽vq³ { Loj@# 4e.T$y_ۿ2 eYK;3z{[[J^3/9?../(7cib̢sKfog9.1Zzh,ҍ@ FϓٖR ゆSW<{^sv-.]`xpy+{];e`ĉ]NBӬr'o=h9yL\1^op<))!$O4T+HJFm}o8\*- dB7lCƏrfۅeY6>a)qa(2KB42iad U;Yg57&2aVJ3Ȱd΃cZV ZwNd8c3~b,ma al01Ļ9?2,\M}zsGj?8M+M&$i4 d& 'Ϯ q2Li咇rggP&=q>ϰ}kj|>g,b¤_!Yb}kM|\<8I_JIa]B~ }f"U !dOm}cٯN>o wyWͩ*>fά1x~RHR$؋{cz]jED_D}.}N'ߓg w_%/qOÀ4I~?QqLB(.DbK߲YD};,*?O&HE fbj2{VH$K >1Z|>O!3=b>KCzߟ+k#[dB )~T$^&E?^)|P9ʨ_ @$~"|xB~wϻ 'R;ݟ/;#4>0 Mϸ>|:yKKy0"_@Fxj1+6ZK΅Qޝ3wNc7sPwMݵ$O ʿcp~~Ԅ:u- NS(4?ncN9ƷLk׃~y$",zQ@49n˖ZQAuwѸdy9g3֨%xTk(p<0EbrsjgNsyt1 TLJ@P8˙Mv'W">rjŃ 1 ܆dGL~/mll}yjruƱy"^Ј/n?ӥ@ʋD ھ‰X@CJ١TMy{Ɍ^GsN f{0eZ`DbrѤoI1:p³FYڍN#ɀÄ~\ϳ }}*(đy󮾩}pyWN |,4RDU^HiXeP*N4\"X^]8w{f/`6n0J>([Bׄ4(hVp4 ӀޓЎO& b+E$lf5nTdžlm4$ N_=u i0xr+fsߌ&d2>F=ExT,5liu|?. ̌߰i$גwPgiߗpdxr${yU$ (-{o}d4h1TjKDhƤ6PlC2Z(%b6#`b1TQlma+B d {z6ڋB&M2XV6466Fe&ϟvj_7Ȇ-4cb&F %Lb6F-cDʍC2Œ#&RbCTdbł4V ){|QT[E"fRDFmb,g]()b5b2*6V(4b+J6" *hPBRbX6b(؂5 Jj5ƈ߄q28ˀ8vUA9>yIb0XLI|W_Tsr^mE`iÀC(3ps'KwΐWw/R3d<<8jj^bQr5p6BѬ@:_ymP86[wIss3܃F <pX aX+'>r868meD@Mo:^{Fw+0ޱ`9 ^UTS9NJm!UN]6ml:7P_Z-*Vm`Pl+DKg9{gLFl9|dM’=bν %Ry{C <390q e9O<vOq^[0eyɽgR̵Ͱ+S.9R[9pS56\Riٜ2bֳV"n1D3Wdr 4N5sn!kȋPem tib ^HA^! DLr$|yR=q`(wnn iTVdpōdwwur)Dvو[h(eBі1+RPm*CP62YQ4l h@;B\4'w8\wp⋜J<( ܻ*QC.W9vpzw\L tj 7Uj/tǽӺܢX)p]K(Jsӻz;x1}hÔEL^TLP/(<c]!%ܧNu9ˮ;9nctsn㤜;Ls 91]]]ݹtS츖ܜ]rw9$hL*Ds]s%ݝvLd1Fww+\p rlc6eȊww\vsG';.m ?_wTKV,Kt<փPi\Ӯlww4:@#GKӇYStsuvqضykKoɕA&ۍHi+$q,Db0P]jK ͹ᇍ "8Nɝ_- bE]-o@ ~x)u Q֣z.ra'GOO❟>}=Yu~)-wGk[=jϰB>~[| u~ڛ,_u?  {{]NJ ?_һ>P>gsCPCߵ>|FJN5¾  @'B=(O;8s3ޜ1O>{M:2Y5_| ϛ#c3}YG~^ml*tlUוW^^ `y=M9SV[t}_B>~]\`\`RZ׵TYO>w~z/W<~vy'`}1ޝ7~ϐY z~I~|~7z~撱+}3ƶo \ߙ̘?'fÏZ@O400X?,Pk4AE϶@]>2?w=?۳\h1_+8m{{C7UQ3ι=pp)~Pyy|;LNcӡ>پL_N>oo5_y+'ςcio寿~{ɹ>`orщ~ﲿsx ퟙsOϨU ߟ+~__~_+_ϕ~AoO^zセSVM*ǧ?7OR+ˮEx|~z{0{(ӝ{ߟeB!4F=[Wc{vwgρ|,oeѵl]v?3n~oIz5.s7dt.7(ϳE_=jpk?]Q ڵ>}eXZW?OQd&1~|4>mP_/QyvW{p0W3Ϣ~w_Øk˺}6+pI٦J>+.O$YZ/,ٳik'ܹtϕL5FLa䳯?=?^M_">+5Tth~~~cs}avd>/}~:ͮO*[k}};k &Y~|'^%"stc&}O ]҇SO<:ډb ù3SYOĄDO?-;6^[?^bzn*qOƼb;ÏBl!ϥuS~/3}eCijyϐsNﱙώ?7ݺ ϋoU]_ૃmEJQϿ[4 ^Ue?kݾw,{7v ?rY$<+ο =ɔ_*!u,"oxB>r/Ĵ WϞ?~i?v1 _f2)]ߏ+/_ _O_ۃHg򸏗!i!~;l; f? ?ۥFͪwT,^G.t>ɻ[Oc jn_Lf8? ~(\y,؅NeKAm|}1{z*}(Qc~W,Kc囬/gЏ{Y}Oʞr`~S[~ǟ}2ճ[_zo"v='844|V|G/0ϫϣQ.E>y]W?<^1_(A(E~~~ÿ ҝJϵP ŖϪ5QWW^>}biV+=_~:F?M~ ߌ{)z?kE"2bo3b|<;!YwHW}?]\W{ng_U}?km VˢN{۷_~;GC;V67HT&=b+Sogp'?,omY5 mw圧-/g)fX:|>E>{{C3},5o}dW?=y}[e}4ZBWo }3E ; G~&??O'}Yˢk (w߃ُ,y䕿buw wagx(sn}C~딩8>WQWY'Gr.\j&EDUD;}vqy^Iݿ/Oޟ_}T~_ʬ5)~FBH9 DSuA-to̞?ϷRc?/ͲC> ϗ%+0f6-+=^l_&en㱥)}?kM?~/2ڟ~gg>5;WT{U[+=[|3[d5fgWڮO OwO'WYg߹~u:׾ӧ Sd{oB>]%nh(gǵA'i}ۿf"}#qWn~wM??/Nf^t=>U_o?ݘد17c1먾~_JVEcSQ s$=Q,=n[CN9l=ӷNB˿wOȽ&{r}~>!n8WT/}'_ȯ:.הݓw`Ԛpi>úW?O?(W?𮫯~zN'߲U+c_׷]G?~~U]|+NU>|}=_?-"'Ow"x|ʈ4BY2nu_?cn_a>6~oԨ}}_QESy߯nZyK|cQq*Ojzَ2_c~0,YpO}YϵSsG| G "{>4>y#>}/qC.LEСÙDyfow>~;?*v6;T|_]ct_!}}|(^>$O3hΆ|~;e!_7Kqmn3#E$)$sr(IQaP 仦i $ʜ/S<~g* D% dAB"|"V*[i{Namϟ=O;קR?G$ܽ pXOɛ9iT#Ü%/g攐BĆ /Ba$>JF ^mr7ĵu۽Q+"DgmNr]kʄ3ș$o?}|;ûʣ{ 9A9Y4){6+ ;rгi# [[U5rfEY($3xVwg1Ȉ43&/^\Ɇ&WD lQZvln鋚ɺ<Ӯk CkːkTDa=Y>j,=,R 7ΌxlE9TUV-wk`6e:x6l:ga"K=gD=t=31"\ qoxG( 9\c`(66UHRg1yNv0M[HZXNS*"qv7ȦR&DP!!qC0xsV\G<]oDjd.^it2ciRs/Ν[vqðk>>NYT}`FS% @^%|UΣ9ESt.<6U9 |i<$Bx3LiyQ&oO 6ܶx|uMEi㌼/Nzv 8R Þ{γc@t;CaOS].D,X ]Xc5/f5Z뜂7m?!&TxyA\ӾtOf^}f0sx&RäG1c>SDۭiApٖQ˳ uw4< :#̩L(ao.uQ0:X"-xiνH\YmΥGZ9P.;xc5 \6$ɮZN Fև^#C 79],]:=N:9Mûn"R?o?} y)o˴k[Kڌ]%\wg#m%}O%t& yk &ndj"!/0omg1wpswS/6f/~x9~ҧɍq4],ꃢ󜥾YR"vx_?_{Vڅdf5/6dvf]s>T(4#A5 d {ϗBl޽csv/g'T͎gA HVe: T^ZFisJΝe*SN:Spf}\ߞMe2K3'geZUwbyx̳#9X:睂`I6?*-cժ-LgyLyUO[rZF E4--4 دdA"l\>~*]xf {\CA-7I<@d"ʵM ^SN "89 -D*XAʔD9ޢV鯬 _*z%NoqدoJ]θc0y +J+~vj +N&e(֘L|wAD$\ 4FazW^>^'Ba{ϙ*xl4v8]kliD,b\88ltO_>XU"i2XBQ&4RlZ(ح1F)(dPP$ EF IPDDI**M$Mcf4VCbYZHS 5cd0b h jLb)6ɓA(ѣF-ř$ K4j,j Fы C F X2%cĔli(J+HF"LبecQb5i"L6(EM`Ѩc&Ŷ$XY$HDԄXdZ-F,hHej"نVM-& @DXeD$&TX AcL4DFE1FDɲmL &,@Y6S)dE4(J\#(آ  l,Dhf,Tb$,F2"6L4hEDb4)JL"$IbcbEd(o[}f"*"PT MlbƢhh+-T&-E!b!& 4&=FSbPZScMH-.vBTLTXƴhƒȅcXlFQm6,hѲkXɈԑcbF4FID$!IX$B- 13Ph6) 4EDMD1ۺTY4I4j5/(FHV6LeՋlj#R!be a d3}kd(宙D(ALZcQhX-cFV#lhѴIT3M3`L4L4QLQ$b e61y6hC)h,D#hرo눨ĉZ1A`-* eAcBTk5j4IQci6)IHMDfDm2RS$0`@I-F $C*$ѱI`#J IfQdej#IFd%ThJ+I%,$J( FiMIFD(K&~7"Kkb"<~L~,)^tk sHՒrhU]T\8NN 7irq2m;4h l2`̋]NĦqrc0Hhc+6Jc"iΛdN1ml{DlANѕN .y4l(6NdO.\t%avԊ[]֊N9vBh;'`2gW'&M0Lqbm#.ɩ r`YCțSѬFɸXјA2eF, V:6 .1ɷ,Mpij[^rI*1ƯS{)<]Y7" ޺I3ʹ&R-0Snv \ҹ֔TӞBL\EхN2wphT%S,]Ō9+ !]Qݸ+mpsyK&ݰ$09ywu|k$QܣtwW^l1_=ޒD,O;IRhb"1fZK"IIF+j ʃ^t#$Ao)M5ܬZ+0-\dXMJ3SA1L>{'y0 "E:WI yv]<9>;BO;˞t#ggBk*12rqLeLKrac q*KX4$o^IÓ<]CrRe n6!XQ)Z3lṉ(q* \h7)wX#qi̢Dp  qG ҆:&ð!Swu˜\ &;h ( ,r]2J *ISXmlܓ'$*[yp ILVq1S1[_/n2KݮCca)}ߊq_??IoOnus3!NsXvYT@LV^V!LT:H%nU#rK 4LyQm5i1`02ƘDGFΜ;1N\}=[1: QZڬbBnk,ηOp̻Ӏz`7]IlϞmW.fm6}{!wox2D~al|oӖ>_e?({brWSr[qQ&$*V*VD*Tz=#۱]0bN dG׮U_ߐ ܛ?_Χ?ch(oU++{ұUB|__ni>9)ȢPI1`TD@IR!Svcdd# 4 7P6@Q6F#mļ&͗RDU| ɥEhtK +yľJ \9%D. ?]˗oW=bo-o5LZ}>˥Q&?P-_-#|~ _?UJzU GY! CPTOT(K-/ cK;xiO=} Ŀ&lӇR>lvQKZHN&|$A$!u+: 0:.85>$/oQ_e0'= S~ݘQ>힯uPb"J,$R%@IaF 2& !B0&62s$FAPF$d6LaLkF$ch˜v層 S3I!(1664E͊ 3FJ&*$Lb(2"1Aɢ*J *CQF~'te2`BHZCDE#CR"; 13Ie6*D%\l3"lQRXi ƈj-%A٘I1 e!$Y TX҈QK$Jf(,fS&ChT!fL&@h2j10f&)5f%B0TV0aDhƍ1ejD4FI*!$FDŒA,D1X,m&,mFCXư[2hb1%*)%LJƄ!bKF32i dFƤ$neZ׾,Q*BJ$A5)?_ٟpA'~82,"- d ]}V h-b}[@ ,(f-#K5̰hfg5=zAU c1&1IZSch™~>wP-+~")AJT "" L6$&e5FYŃELQe1ad!dB%"&iSKbœILbMb4Z*BIcdѢea1lE I)2֍ 4m%%FMAK1E" F1(`(`EbƱZ4Zb~-MXlj4Tw~Ʃ**FF($%hL  4DL(FE ",S |DTt̔RX=ɚɩ,Fah4Y@4A&Li3S 3P0"LQQb4+&I5cG׭5V# ?nR "10EQ,hAaaHI0a,h(ԛ$X%Ab hBa2hfci4i1M/ۖ[&XD64dRY56%Pli i3&j"d&C%-H3d6#XJ4c$s?(gTCn_ﳼ{/y}z= τѠ~/z ~:hDV?a*>?{:?v%6_NjmZ)UDmMgo ߷?>۾| OzDvOcZ7AogeS񯸿>aPߴ/8=\#.|ϮY_Mڳ&x9z h 3D3齫JJ׿oaϧ)}s>z;[.OG$e :¶W^J9HGyC ye>iٌ̹7>ϧ2a]Ε38ip~_12ykHl\WBOnAdm/BƾUz?_[':̨HYzvta?Tuno>#ӿ (оCIﺽ az??*Yo|1^z6|~)/;_=*t)1sKxl>߾м__x wuK7ǿgyω8Aޱ[Qv/|lY-z{ ~V~w͒>21Hcr{_?l?|Nݟ]/}?eO7g|1̵_/} X9TE\׶3??|īGg1Ќ:Ƌݩ*|?{?ϛ:ϫSG>;Pt)lC?~UQ+ߟ0ͰQʭ?Fg-_|W{V|~c?_ߢ_}O˭z_Hcr~h|R- zSfd=􇿴=Al>5\r}rtTR!6CwIW_A_ ?GEݨ~QIS~5=7r&{9a| X"j nk_ӟ_Q~>p~j~5,A>NcXڑ~G_ߟa]o_s ?~lGMک׳={c~РOЉ~oԧ_]~s~Q}B>}#ߛvGV=/_L56?)xܥ-{wE寑mwS 1{X!_{ !e_7rgGXz|b_AOTx?ۖ??Gawϝ/YM>VA!_g|MQ=ߺ}Ow6og-VdwGpaGsOG>^ͱUcwڋԻg?? ,mgݡ;۸3 1~#xZ3[/^>Y>IW0r/ e//~jI'O7?߫Y~1ymu9:O;?ϬkɧOl~,_}دWGr~W^}ow`ޱ? ۧ˯?˯p*Tob_wщ޼庨I譾az}@ه?-,? S+q]1g6o/s+o/~,jpg_@_IZ:]fW>!cWT|oc_u[rvF!*_ԯ;~^|[??__?`NNo ~ N4 ͡R'9{>Z?~W{SϢ_??S͠}^{pI{Wz>,z??+oOןծw~o݋+i?_]|Y{)R@Ao+.l9t~GáT ^^=3@{?ew:ɦy_|$5!=HH^Iox@>ԧ['xB_ mE98U[f?\l9ϑHߟV2G?ۋoXb, |Ϳ7¬Y(URpӝ8;u]wQss5ucI.3M09_}obN~ 8yKU[o文OL"_֟}_{ޥ{R()rtT>8d O4`Y}Օ ʪJƚ{ʬ_@4h)DfHP՛Y#<&Be+zڕ&I';օMPbaƢ3}ʼ/AQ%pL v!yB{ o Y1!DG1n9lXϳxsQ?iur-ɧWr*]tZ(&wv,t(F빉`E$;-u2c1̵W!bR,PF0lQ Ql,Fgyp/wƻ2s.L:Gwa`` 0jQs&e,Pğ^)Í [ Y ,/k˄ח8mB㒾柂!rFĨeH+Ȱ#3Nf9njU+[6>y:?u}8.bW,)s16]D1dKO>Ku䧮7bC*e\wV淏ɑ=soKX׀)"44bn pj8f<5JCH[t@/k>}‰T1pj>a%^KN]b ZF rYəVd`j ѣJ׌j2;Y7W˜-qv3 #PbD&/==^m<(=! OUpR1꺖&lUԀ,Oڪ%,V'`Tt $x[TQ $їF\'_KFiC~Y[jyDU6VYaЇm^\*{U!kT}!ğzUi#Q6 )b}׀CxtWxJ`aP8) ]Ba!4;9ʢ}Gl%zLQZxs րi~/ؼ^iyQu+ 0 HM 0f>'ᕯ__pǨeEl#(̺[F(NULd~54rW< x2.ԁ,\J Wž jby:'~3ee5\^;_{ߓ_Z* "ɿ1\F}_BT Ē*)0A&"TQP )~F (+ff`3-$Ѣ4fb066 k3Ei D"ت&$@fT hJ64h*- `6Ƃ5ForZLdc%Ph&dR4QiP#1+X@BdC0lPQPffb1hj 1DlBd2bɲ2`5Ij,FXd@ QEI"FiQAE-F#dhQ!"#cFdجFbQ! I%b"R"P$JLRFLPZĔZ,V6dFaF4V(b!,TIQb+10LcX6FEb44I b!L6DY(lEY lPT@DȢ*"K$hI($EQ~Oۇ|bAe5 b&EAQBʒ""Bh1EM-id0T0EBbH !K61X5"ЛE3DC6%)AY61b Y,RE "(Q`đ3@lmԉY(D&FІ )4Q%2eBc`2fJ" TQRhB"6bm(10i4X#bń6T1i6 `ԚKcS1D0DV!*HH& ebڋ`ь[TibfRIi~C)li&D1 cE Db%C1XL5F}.cDb&PkIѢhTX4(EM- #(FPHTci H)@%c- " 1Y1DBIT  &"h5Q2HƤJ"aBQdY(6d S f̩KH P 4i-d(EcBCLfB@#)a$Ģ"MJDPM HVdS !IZ &HM""ef!!JDX6&DJ",heDCdZ4Y!HeHhBbLVdIARE%&lE,hB,Dj$,cd*eج F$d"1&LA3@EDRZ R4٤ U%%,2F(ђ",J#d i`A"ѱfDkM$ (6LIBS")3#0-D%LFJɒ6EJ& H5)!c%m e)c,*LHQbĔȊ!$bd4`ؑ(?;'?o_ook?_@ig` TkK-jXHdC| ??KP2h7ځ_'U6?oG96YEϬ}ɳ^Ҹ0l,Q_ v<>rُI.%zptJ}+xP*Yq8Z0۪NlLkati#*|JjrLb[ٻV'b.V@[ qb>ubh^)W?g}G~g^e BaidlYEm65%òD OIhks%PР((BG*VX: Ie re+%HP%]X۵K(7mS)su%%e8-8OMwGІ^֌IϭU|?c#~χ4W,C}mqgwiܞ(΀c_ڀ-]M KI} `~ LmE L~_")&G6Ҍא>fM^+-ni)FM/&ɗø&:%[t0֣ҀV9U֋C쑶/T,|n(( -.ps]M5zIKHF/ܴnP2a(䡪,R]un2~2uN(hͿ:'_b SRDiKh`B% Ie ZݠWA-tRJ1rNERQ#t%}rYJV%(6ʜVP%eB@WBrԩE G\, $[rPPA1`聮>_5Z,/l?t?jBD;bh^_Y`R؁I~.k~ {w@?M.ƬoS֑EVP#ߘӏWLqq@H#z:߷Prb IMsӍV),Oaڮɋ;17)/Eh ƭ98޺m  QPOᣲ%oc90؊T5`A~"!E5Oe6R!ӓη }o$q ;-fԚ_~g//W|?2BB85 YeJt -$CVs]`WKl*r mz0": %4 B,$ •J %vDeJt7g߿~ْOpƾo{n)-&vwgzNtP 'Ei}Uv#MU+xHVX$[@ouKR/-ݸ¸R)迹Iӛ3O)w{D{ߧO{oiޕ;oh]ۻ' d'K9zFw u$«ԉ,]7vxX^Kz"*^k牦8Dվm=NtKO(NvWISٺۓB ((b:Q8R I->w IJ@l}v9G S2VZN-r@NʐVd8lP[HFuIdp)),)Ѐ8R9)lS)~O}}ďy|3WY[+ Sv0_8o*qdN4h$CVn \; 1 R H_(=dO#A`rse0 1EJL: =>agR{NHkn|ݻn)XvO+*tqGcfI[YlŨ[P0[lǶV;?f )]w?IlZꌈ:00Ʉ>*.ΕJ ՙZ5jhNiuhC~`Y6i㣗(BDP:b뵠`Q9m,PLB g)B*nP KJ)B9jШ[(0L2%eKBXPh ?mw Z"p @d_ a-\8Z:$G߯Xg},G8N1߯Kj6[a.c"~3s3DYGG|8ki螏?nj!!nL_e! !2N4f~&D=rldl#CqM` '|{w;νž*T33\k.oޙ&wX a6h?k`C vh:4Xr1{~p؁~KN Gȼ?w?/ e9IG E)NAHB!)SK&lv1! 9Aڤ(JRjХTdrW( IGH PPdФndF Ykvr@PADQDAP]gP i"{v}qIkc_n!5Nzamx(߉ٮEXT?W0X,WlS?zjPIr)yR膺m6k-|CfcfR]gH~Y8~rOhB>ޯf:ٌW=wM_zhNF9ǐ|3+B b b l)Dmit Y`sݽ:%cc(JBܠ8P@+6r-$`Lt:*J(ZFZTF9lm$p%tJ-AA?~'}|8W:$wHV KM*12{ 8*W%LSyz`1ZB׆U_D]wЖ_yʿ#So|+^.w)G4:`lcdl% `/KRr1q|C/YbWߋmD(j%x]S':${Ŭt[ y]QXI嘖5$te S$ 8KaǢ.3Kcn\I&4q~H6w_T׫& D%7ʲ b%90])%9l!H Z7`EJ"A R\8 @RABJs%G%J6Z')JriрөҊZ ]+(Zh?v._ d'n?"gU>`za2l6n0V4,T')#;ezo;~7Htْ'wo߫&"Z:chj^QEv6LI9c``QD}9R-ܻm-C=C'^)/^p]}a{ק.ґQK4 Nj6& R y] ^1|@ୡm/ˠqꒄ;A5ʀL:%$+(7R01Tsw|jV ?K~a%(l() JZrp9-8t#!-o(Q!̮ )j`2Z %-RI-vWKJYzE-Rڜ5iIC[J@)֖(( }lIHmLzj/ r|ۇK?¹ϯZ~*{7m~$NUJZ6]ĦB]Rtzd=~Ө_xߘY4%&}@nm})3v\:,5be1!l=i`| N8㦥 K'H!}q=(p9tw`2KQtu,{* SKJ-=8F>bh3\4O VG$Hy#-69g/ϙe0P%S$Kh^`RJteZQ'C"PX7@'@+VzXC(+C$ Xhe +(&H @a)š$aE6Z҄R- !( b b QRUJla.z 6C'aiO?Sa >{TE|a}S.ɭ D׶[l.QQxeH0tI<3@mQ#z+fbizCNn~z=.%9[rDŽQIf iRuȮIWVWAʮY%j6ѓKKmfٔ 0^ T\|Ac)t3w|`8iΔG[WBG)dL+IeQ%X eeDNe[+MT) )[ih:rpAv4vXܮG(Z̔Zge 2ePHAQs!+)DQPPQ8u_،zyp6M>}}${a(C,EOup[u_$Ȧafی!玟# )OeOg}&c#oGQޤOLSvk8\0X'~oXJI JMʛ+Tl:# 6m!`86L h(QРJX9-pQe(Pfԛ ` ImNpRvJ -pm (! wD5bƖq"GZEC|T!?ׯ$ki%(WI2X[=ꙞR p}b^7K>_۹0ustX/|P*րMѩC 3%JM AEAQPҒ $r FPrZVZtrZ$\-]XQ(8 D ,(9DYNs.ɒ2$p2-*n?Mq%+WHfPJZr9,P?q;>}a؝s0|<`UI,Z!A!ΛgKX\H۹Wy̙Uÿ[}6n0xҥ+,WoٕhDS?+oL9#u+b*z$)i~k_z,Qgfۡh5wdts |xaH1b MCbʉGN%B6Ce m"@3!FLA;4nRQC9ِMN>xpԌAp:Q*l7͠9*rQ(WBhՖФ% YHJoY/K-eN`2#- J)[))췫9iiidi#hg@̖JRp 7dd҅mB &}~𶟥MZB @1"Aҽ/4L~lGI?K+δ&H.th9 (T`qϋxJc'1^*Էl8g~$3w^QDf>=5Cmp\>Pu1˗ 0&tFI*"ʍNP~)h68z=I/Wwi?gCm`x޻Ό!Lg}u,Vг|6ܤ PPJ^P`- )G, 8INВ)i)Qhݡ\de pi)J2XBZ'(,@ X eJJB9:ݗ>7-:G$H( (bA!(3䤈 uW0VA+G6I8^=~O~_O THCM`ꣿ-Ի!jV_ խAǨkɄ: 9湶9|_!ve. -kݮ)g$oT'`nrX Uv ͝B͜_H`GL>?_?_nal)3v-hdL8m5A.˶m%+ zYg;src`fv _w: 8 s15j{Ko@/)mG1.63x B QFAP1Fx#_Ia"s!:.CI_| s7A[tᐛiLYvw0.]H)sb8|M\hsMMGRZoR_p m07ƟMN˷c4d3g\(9t&-պ7bAH]#M֚:W|w=g޹r==‰]s-/mspFbo:NM!0_Q8/L)ɿ(\sa$pw :G0 (b0(0A^rڶ+'!{jl9YCGo\vRBGCZk]Su -ܠ"mG6ٌLM )5.3Mv(҅@ BSLx'CU(l+9%50aaQPEQ0Z0X$NĞ&>e6Cuie)_I|ksNeD?@/5,`> +WFeWHC_ӺqfI!u1xk4r0ׯR[տ4 $R"BdTrUIdIns^\ ˾2KvrM`g]Qϳ̘sPmcV= M]g t]b6 ~=&f1(P|EM-NGvJ3x_aآ(/(Ghm%7;BvxbhlhJͶrmnI.\XқPhM0Bۮ&kvZmu3X M.rKaL PRo6{= rt -%7ClJ( ;v{z@QQa_ģ_ 8rD@KH4_CίV?d5geΰAVkuBh ߡiԅLJ۽D"[ۧ}z_XK-ߨ)p~:_<Vn!(RQ0ۙv́[cr&1oluҚm1i4Ͳ'=c0eٳ6͵vvЃs/-ZT En-53m]Ʀ͗/~7ǿeRK6.9BݱT0lP0ŏ3jgUWׅLq|2jO?EObS} C7PzQf0߶h߽OZv_ۜFR &* 5gSOH奚J>}5y5Hm8uъ#ХY7ˬ_&]C1𣩚i%k=EokR~C0p(ݤy01v!7CrS@T_O 9mrMhHm,5)K  tp*J-1wm1f3abSr1tr+`uviW1 d=I6}=`lƲYocYD2R-JKw-)7in(j@ 00΢=̖5TdbCWp{jGτ;W5^+{,kꆘ.:羃ksfnIm(&n7͓g9~GF'tC}Nfq &Z j6h\I:u Q3;l%+L_(sy98o #Rz RWy~t=YNr_">(/}H'4Yxx~31c/Dg}߃ v_`hsd{ p(pr0ͅ$PQ5]Пά h{2Q\V h %{2)QK}r\.qMJ֨>|1~s$IGpE}!)cn a 79(ƶ˖+7zc_kW.4,-.I`5 PfYv@ݮW\M6ҁԯj˕][;Uƺ/njcdT2(xS+E0"%Z@vs9<+iHIG@ =zF kG 2 zfTqIpU_1 zPò)Yj" +o'݃{|{qҷ"jzh=KLNoyf(%~}/H LkeKw2Jzo-kM2,鱝l7)0Y)ڙj vj2v퇶K(Ke:3RK~ nߧEMkfXȏ~/g">QLCdHl {;/ §,ۗCuz! ws+ Y8w@7}|%) Hv?տYrvm65}ˏ.0te&+ºnuL#0?)j(Z+~8Y3,9 1ϛB[~ 8ULv.qԤno <J Ֆb%VBHTQp/'WӯB/_EJ<Ns*lUX^ȴUjcxKTK66r87Sf {몳{l}Un}M={XcKh|x{Jaנo]4]뷽4==x=ފ[{ R<!mv=).Z{۷} pcS{Y}?~6o{lL)i i|zz5}//5?G}_3''5UV6`3s?2%_,(H7㭰iL%cw,s^1GT*1wp)O=vs6e^5sPZe1ʕ>=!os} 6+3&"srb݅44JP}ޭAQS6(ޠߖ(RyW^E~> rT?SggV30a?ϰ2]W۸ՌAрO֖?z /&_\ڝ/!u~w4a/p91+]Tq"1{܆Xd9;zhyCн0 #$7k:/:O~ )RΈPs sPuLHfAA>Y [T]&e< /Ђ j(7"{齙`woZmo\iM5=ޛScKN@ltKss=ݽL.tnR+g}۽+8M@_rto{8doܯfoc৾̈́P¯ݸ cl.J sF6FѲޖjgOcKn0a!`Aa~ʺm6i]e??. ё3N&8 [ u?WZ?$l|s(|uI 4fTƔ~_n\60q}7WzXoT~Uv]0 }sBa4c)5-ϭH '6b},ly@sé,4vEH۬lM#4uZ͖uͷ80'+,3:̛-vcMWB PcL{| `sc>g}ϱ?Oʤ›Bǰ6R=6]{v޳mmLnRPRӭєow;v166%f01n$.vA˶](Q⇷$1 +)&g ]FGe`aF!AFPlt@}ql;}dڳ7z*'(qkOv˪Ƽ~{c"R{,0tb{Wy8xјgsaYC%Zlƒr[e;>G|"lLO 4(;d,_[vݩhv3#s nnyr;9Q 7_&. |. h0=R> M;s__O7CV)p1YMv=6G7[a!6_WΗyT^yXʺiM3onjkvSKPmOcr.0@ޢ}&,SNn)(6ޒw˲E6Je& iݶ0w3m oWzb(QFQAaUR+3O?; mE/ _SC[5Hu c pmAJo}HT&O >q] U/b ?9j\_D? iOO>EjN=D ק|ԮҚ6!#R %=ů(ݜK<a ,Pz-t=Sefr,Ma|Qbo}׸f2g-7ꑇ{J;y %K²k" d|z0__ 0B 7G1(O}C l{Ӹ{=ُU})v @U9M3Z{ov?ߏ/ǾݍLofsҎ7BmC]7v.CoF_wmػEԶ6!-a96m e3fsQA Q]51ݯ֫zL-%gv͌<!G搎ԛZ?Lq HG_'5]ohW~?j=1KFI|$bAm-6l$R3ďZ. R| 鋰b|1׶)h?]V5& g@μ &CW#ǙS~o&&.սF!>BYUt;7h. %=0n7AѤ<ćlDky3xa"y_}_O1+s0I}٥]{nvc} v勷Ջ;ޔ6$SS*˛l;0r%viOkMo}l?a=/~gU!:C5\fTeeqՁ6§@B Exmrpa9LZҌw%2jxPQU)9P׭+>Eȏ,$AiXGLOkR /G5gx'{> "`P›{JaF1r|( LjH7zn1aQQxڨٽ鎦) vsm}/^jx2ܨmJ1%(osrjm{[Th%rkn44ͮ s)`A[n,o-bۘ=mm%;Cmއﴤ}u;Z]Y o~γ}3O(s?N'ظK$B?w_e??Oݣu$ȝX%,Mf~E"R' [v`aQIՈI&o\ sPUsm| ).1noV.ZHS=5lW[A8k{|X`~Om3#rRݰYQpZ"jH?՘T!pT np\}Vyc#Y⼎oj ư+Ȍx,Ai=v˻醴iuY0  cd휴 $Ol9i  -~Yǿ>>|z>>4zUwZdʽ{[fVU\k*^^]Ve^b3ʕy̗23.VQCmHq=Ԕـ{}vw0ݶ{={j{9k0iMq1iwSon=bߟݮ~y.򽞅x*|yg?ϕ%_Dy?[s3[3?]$!>b/*EH6k/l;{1C#d` oKS(gKnn %»=2Qatl/8#`-ETeofQuveE՞g@;D5:OjM>nzٕcD;j %OGUrx< zjA v6lQioGݷgZcA1ƏU㩠[5x7?ϿAER (қawmz2})si.iiR[n@g6зav)%7ԺC}56 s qi`2[zRc{ J;meck Nk\&>z{ = oL)LAgt ӄ?۩l֯ʦ(}Of~C!?y{BcH/HMWz%q0;#?ƓgZ oJu 5eS})ʆd紇Ǖ.E܎Vyn"%PQ>sH ~nn+x4sP RhecdUjYY 2mx 1kw\%s萑 -)[t]lŨ#%'yeGt3[}>_/bv ~^= Eʆߺ͏jaŷmԸ}齖{Sm52LƗzS{)~[$nm4] n݌QUnP R_KzJ ,ˇi$YNS;c'd\SIv4]veJc+n AAaCQAQg ]i{+rH=[RC%M0 `FbUXd-(JWUs%33{暬9ॠ,_{*?kTBeG~nS?EzNwj X?Q$Pu6w_Фhw q.ىa | G*iՠXn;P"x)44;}(-]G̪ր懯=K_)IQAX6;aY(i~|+6ޯfӜ"0A`QM@2j[P(.Sd;i1l޲݇M(n10mn҂:k-{]MKۑhHm %9mc$Xis7S].5nKцq@Fa1E`DaF!FQAr1>nK~n+SM^g.OI0][c Oed떪̈kMM%@Rw3P9xa?T&>̬G|o<5l:XbFT"eJOJ=S?9huͯ}#ǰnRzWHXrwM`JPn4pi%o d*SVqQBwڣGEo CqPw6niǺL12V r!Chzq/2r| Ӑl- Ozء ~  (m^+`jW u&5mvUi dfZݔ.ɹM9%!Xƺ]}~Cm$)@4.Z56lnCmpmwIn1f?z{fҲam:0(A( Ša(#0;c1yn4(y? Gh }8}'JʱM91~Q+4^U;FN1/3r!</HϷ\a 5jD=qSDw"_nkwn r錪4`f[{O.]]9 >_E׬U-ii۪*g~g'͘L/xajT]X klev lwl箉?Z8 /Ű+Tmzgu49Z1z vnC%r;L{j}}} 00 a0 (j=4ŒGi1.5L7KBm+kuĚ$`y͓(K(vpۭ6Ʀ%x7nz[+(`' i Cmht퓷npt6%2RݹˌG\#(l( jhPd2bm?o|}|ƫ67zx(lߔuF!cl`U{ܤ ~?0?eyxJ})gw)T;A.{1?=Xl?MlHCnI_ E읉? t- ,1NQ?C?~_SgηVզmXmf /!L) n6 v=b[tˇ8ac ىpDuEţ㽄 M w<mBTthz-Bm{l B';5$=(N{s;pyΉ'ccTӞDωɣTt%xnRߧo?_q[ԍ `t5P{/Y X!|n& ŻmΞm7? Sm6E1 ]Pojhj>׻wv-5[S;i6DɺlZ^]i6ۣRû=.֒v-c-62ƴ)fbGC˷0n.61hmNZdmRPVKPEbfeIwцnΪ\B|4&G:EЯԿkY(` G9|WXB2YUr-(})}:?-EJK Mtg;_Е@?lǡSO Q-}~|£.*  RS>[`g̓F.oiHF2)e82'-1<69w_&ZS]#YH17yOD֏fܮh?w"cWa˕~ p2b]c# rey!&mwAAJס%}O>Kpݷwx\W1 #iQF2iJ=*X-p/6}ǤLHg?Ͽ`e&ڔ! +n J@S$Q6mqO/ga:":U9+D܌h]Dy>Ov۶fIn4(Cd6Ř-)^ ,ط] #t2[])t)m]up h2@ܫZq)WΔijzcdSn'Cl]zҲ +i$6횘6c L"\KV1~rۂK(+kn)Z#,-~ cSQlmY$,6y#W1QW?U#݌tN3!uY ?dGߙ:Zۡ37)?t}f_j7{v`ZJEŮ]q^t-TŒkہN:jwv(2bS֯ЎG1./:eQz!@g^\"]eiN,7N5;X|#__2> |\mU$U$X5Ҳβ|&~70^/ם&Oe)6m%ۣ.:]-tBYUٰcu67MژZI rmۥet*T H,r58F*ܦ]D 't\Ӂ3Ёt ֆ0L[LBm1Œ(WGwD؎pAT?9vsquk؉m^3M_ʨ+o~Ǡ L}֋!{Ce[8dy~ISCѮg$Vd>-Kyw l3hOqOM]A>GHg|3_`hߺߠ/-`h4U.$1ag_ /$S˶cr+HyLOC־[g89 sF_^:C^}w>}#ͶCkM)a-RLLr0m,))ںS+2Avuh [)dݵp)e즁XvZlܻ06464fmchjW]ƒ[/f2 ut`;KnaPaFaaF|d3?Ǻk4&I?_qkao| i(גˈumٸ[MIpo kskogMZ9KS079JߐܕƯF&dE/dA>Ǜg4y[.TOaz7NrrFXM-'G׻- ƔoRthZɖ /3b1}<{s ɓ"F66l5֗]96C\ݡ:vhZ z~;|_O>1"P6zVaq@9cb́8e8}t% ;Ml1 evG V\fYdCg{)7A۲VfIK Jlێ Jᇈei[oq},a֘*rʂRFPs ADAyNB'er:JmjJ ̋L-o?y6[X GOcza5t?ߥ"Oj/\vl^ Iʹ': w9JnK>/y>Xk6W8 vk ݧ(@Mq4ڽ޶,K `#t;R!VC }b[!L:S!4J``oȾxS<0/˖v\!u:ͦ["eJ$"jqccp Cx=RyE/|:&Ĵ-+mtRPd- :Jr 6V֤Kg%VPn R lv8K`s,rC;*VBp-!EQE1 o)܇41oBЗG,1n2˼?f_Q]ʵ Q]~Bn|l(-DYC_xtUg8A yKM_W}5$_mB{%$6 \|<W\횉pۤxMQUZ P;:g0}KFSl6'ϋﵪk${{|شjT*g }h?+یIy7jn`C??}9@ط=fåKe];6c(ڭ lb:6ˁvCPo=-R J9n\S( y=lwl FvJiޚkeиZQSLAmva6vl#mxClܱM?{~F:yY; 5>~7&ҍzÐ?^,+_tiN8^cp/p(a៵ߴYFd̒}CfQ~Y!k'"AШ+}4:L^/=_pڮ}-LĔО D?Bmo:a>6y$ۜ U'Ih+;\DĪzeMStc!ҾD܃ʜT0(Б ,XΜX;"Ju.z;*G]|*NQdFӽ j" !jl.ԖL91kMcT͵r3D̔֐8(mmmƭ`rkx ݀ոH&XH9M46NѲhZX::K^JnzK Kvm)vi&P!G56{@a{ŗwdyX||'% H?;Xu~~iO2}Qe077=y#[=Qom$J^btdO#֕aG~;"grNt*+=;)Ƒi4utʮViDr ~bc<n<T1V/pl1 1}a*7?{(+B[YU1#xzZG >T`)mffJaHV5 o3ԝq}{}}>M.g6P$ޖRiqiZݵ$b]KL"!aݓz lgM j9s'e5.۴JZKH!1Δ ;hmbQ3W@󍷾Md[lLAEPBaPK6_"|*dSU8Q,^a0g1!|'c( $_c9q?VFP^JOj(tFEL8SΩN3F$v>75^}v9kcN7(I̓@hȽ4WU3d&9^-΢K/Q##K#ce߶zU==2k .F57C`|mU ۋj'!eLi nۛlJl&@C7M Te-'02Cct u8%*rXN`\lID)nf`Bٍ&]mԠe& +݉p)[JX0R%@rцaaEADf^?RYf˸kC;rR[ '__N&;9s !o/K{hۜbmq#Ix0T ݗ$SW#;~R>ѽzobL//kǚъ*(rO|f۾h c_k$F{ +d,1hLL9^%1낖CD15SiJ\M3l4O0H8R7鞅,!Z2K?x7 Lu&?ǿ3'}#?x:Y%o.]rݪ3vKqCh"m\k܂m%l]LjmvKjjkLn4EdͶƖܤ6h%kqLdi] s }1罹p4 ml%e^sr]tH.(~DzzC= /<Ѽ{&.G% n#L [R g8,l߆қҼ&X”OрU#%zX=&=̯0vɟ۱ola;OljðT"gPkO7Ze+S%r}v1>\p^"U]6,iT]ᾫM[KdAbyuY"r; :&NpՓfCTI(0ʹ|'$sn Ňx̿ Ee}%ٹM.eSM.- &Zijji&ٽMTvV]ZFJhl)55uK&i [61Jn1cJ5J6e1l 6͛qlxǨ65p ez{v)z 2Q`A!_3\V3N]nJE|K>_u!78cuXD[yAZ?~}}:&~ kwC r{N@ ٛ<MSK1['k[ڹ^G^]X}o~O˥*`ږP¹(N$ aNWhhF EaN!IFe ABѻKlD l-X r`Xv*JUhW(suQPV[\kr+t{sx7H$rE8P@xtibus-table-1.17.11/debian/000077500000000000000000000000001475513533100151425ustar00rootroot00000000000000ibus-table-1.17.11/debian/README.Debian000066400000000000000000000002631475513533100172040ustar00rootroot00000000000000ibus-table for Debian --------------------- -- oneleaf Thu, 11 Sep 2008 10:45:56 +0800 ibus-table-1.17.11/debian/changelog000066400000000000000000000006151475513533100170160ustar00rootroot00000000000000ibus-table (1.4.99.20121012-1) unstable; urgency=low * Update version to git 1.4.99.20121012 * simplify rules with debhelper > 7. -- oneleaf Sun, 28 Oct 2012 09:19:59 +0000 ibus-table (0.1.1.20080901-1) unstable; urgency=low * Initial release (Closes: #nnnn) -- oneleaf Thu, 11 Sep 2008 10:45:56 +0800 ibus-table-1.17.11/debian/compat000066400000000000000000000000021475513533100163400ustar00rootroot000000000000005 ibus-table-1.17.11/debian/control000066400000000000000000000010431475513533100165430ustar00rootroot00000000000000Source: ibus-table Section: unknown Priority: extra Maintainer: oneleaf Build-Depends: debhelper (>= 7.0.50~), autotools-dev Standards-Version: 3.7.2 Package: ibus-table Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, ibus Description: IBus-Table IBus-Table is the IM Engine framework for table-based input methods, such as ZhengMa, WuBi, ErBi, ChangJie and so on. This package only provide the framwork and the specific input engine database need be install from ibus-table-zhengma, ibus-table-wubi and etc. ibus-table-1.17.11/debian/copyright000066400000000000000000000011111475513533100170670ustar00rootroot00000000000000This package was debianized by oneleaf on Thu, 11 Sep 2008 09:58:03 +0800. It was downloaded from Upstream Author(s): Shawn.P.Huang Copyright: License: GNU Lesser General Public License The Debian packaging is (C) 2008, oneleaf and is licensed under the GPL, see `/usr/share/common-licenses/GPL'. # Please also look if there are files or directories which have a # different copyright/license attached and list them here. ibus-table-1.17.11/debian/cron.d.ex000066400000000000000000000001311475513533100166560ustar00rootroot00000000000000# # Regular cron jobs for the ibus-table package # 0 4 * * * root ibus-table_maintenance ibus-table-1.17.11/debian/dirs000066400000000000000000000000211475513533100160170ustar00rootroot00000000000000usr/bin usr/sbin ibus-table-1.17.11/debian/docs000066400000000000000000000000141475513533100160100ustar00rootroot00000000000000NEWS README ibus-table-1.17.11/debian/emacsen-install.ex000066400000000000000000000023321475513533100205570ustar00rootroot00000000000000#! /bin/sh -e # /usr/lib/emacsen-common/packages/install/ibus-table # Written by Jim Van Zandt , borrowing heavily # from the install scripts for gettext by Santiago Vila # and octave by Dirk Eddelbuettel . FLAVOR=$1 PACKAGE=ibus-table if [ ${FLAVOR} = emacs ]; then exit 0; fi echo install/${PACKAGE}: Handling install for emacsen flavor ${FLAVOR} #FLAVORTEST=`echo $FLAVOR | cut -c-6` #if [ ${FLAVORTEST} = xemacs ] ; then # SITEFLAG="-no-site-file" #else # SITEFLAG="--no-site-file" #fi FLAGS="${SITEFLAG} -q -batch -l path.el -f batch-byte-compile" ELDIR=/usr/share/emacs/site-lisp/${PACKAGE} ELCDIR=/usr/share/${FLAVOR}/site-lisp/${PACKAGE} # Install-info-altdir does not actually exist. # Maybe somebody will write it. if test -x /usr/sbin/install-info-altdir; then echo install/${PACKAGE}: install Info links for ${FLAVOR} install-info-altdir --quiet --section "" "" --dirname=${FLAVOR} /usr/share/info/${PACKAGE}.info.gz fi install -m 755 -d ${ELCDIR} cd ${ELDIR} FILES=`echo *.el` cp ${FILES} ${ELCDIR} cd ${ELCDIR} cat << EOF > path.el (setq load-path (cons "." load-path) byte-compile-warnings nil) EOF ${FLAVOR} ${FLAGS} ${FILES} rm -f *.el path.el exit 0 ibus-table-1.17.11/debian/emacsen-remove.ex000066400000000000000000000007401475513533100204070ustar00rootroot00000000000000#!/bin/sh -e # /usr/lib/emacsen-common/packages/remove/ibus-table FLAVOR=$1 PACKAGE=ibus-table if [ ${FLAVOR} != emacs ]; then if test -x /usr/sbin/install-info-altdir; then echo remove/${PACKAGE}: removing Info links for ${FLAVOR} install-info-altdir --quiet --remove --dirname=${FLAVOR} /usr/share/info/ibus-table.info.gz fi echo remove/${PACKAGE}: purging byte-compiled files for ${FLAVOR} rm -rf /usr/share/${FLAVOR}/site-lisp/${PACKAGE} fi ibus-table-1.17.11/debian/emacsen-startup.ex000066400000000000000000000022231475513533100206120ustar00rootroot00000000000000;; -*-emacs-lisp-*- ;; ;; Emacs startup file, e.g. /etc/emacs/site-start.d/50ibus-table.el ;; for the Debian ibus-table package ;; ;; Originally contributed by Nils Naumann ;; Modified by Dirk Eddelbuettel ;; Adapted for dh-make by Jim Van Zandt ;; The ibus-table package follows the Debian/GNU Linux 'emacsen' policy and ;; byte-compiles its elisp files for each 'emacs flavor' (emacs19, ;; xemacs19, emacs20, xemacs20...). The compiled code is then ;; installed in a subdirectory of the respective site-lisp directory. ;; We have to add this to the load-path: (let ((package-dir (concat "/usr/share/" (symbol-name flavor) "/site-lisp/ibus-table"))) ;; If package-dir does not exist, the ibus-table package must have ;; removed but not purged, and we should skip the setup. (when (file-directory-p package-dir) (setq load-path (cons package-dir load-path)) (autoload 'ibus-table-mode "ibus-table-mode" "Major mode for editing ibus-table files." t) (add-to-list 'auto-mode-alist '("\\.ibus-table$" . ibus-table-mode)))) ibus-table-1.17.11/debian/ibus-table-default.ex000066400000000000000000000003641475513533100211540ustar00rootroot00000000000000# Defaults for ibus-table initscript # sourced by /etc/init.d/ibus-table # installed at /etc/default/ibus-table by the maintainer scripts # # This is a POSIX shell fragment # # Additional options that are passed to the Daemon. DAEMON_OPTS="" ibus-table-1.17.11/debian/ibus-table.doc-base.EX000066400000000000000000000010501475513533100210770ustar00rootroot00000000000000Document: ibus-table Title: Debian ibus-table Manual Author: Abstract: This manual describes what ibus-table is and how it can be used to manage online manuals on Debian systems. Section: unknown Format: debiandoc-sgml Files: /usr/share/doc/ibus-table/ibus-table.sgml.gz Format: postscript Files: /usr/share/doc/ibus-table/ibus-table.ps.gz Format: text Files: /usr/share/doc/ibus-table/ibus-table.text.gz Format: HTML Index: /usr/share/doc/ibus-table/html/index.html Files: /usr/share/doc/ibus-table/html/*.html ibus-table-1.17.11/debian/init.d.ex000066400000000000000000000100111475513533100166560ustar00rootroot00000000000000#! /bin/sh # # skeleton example file to build /etc/init.d/ scripts. # This file should be used to construct scripts for /etc/init.d. # # Written by Miquel van Smoorenburg . # Modified for Debian # by Ian Murdock . # Further changes by Javier Fernandez-Sanguino # # Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl # PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/ibus-table NAME=ibus-table DESC=ibus-table test -x $DAEMON || exit 0 LOGDIR=/var/log/ibus-table PIDFILE=/var/run/$NAME.pid DODTIME=1 # Time to wait for the server to die, in seconds # If this value is set too low you might not # let some servers to die gracefully and # 'restart' will not work # Include ibus-table defaults if available if [ -f /etc/default/ibus-table ] ; then . /etc/default/ibus-table fi set -e running_pid() { # Check if a given process pid's cmdline matches a given name pid=$1 name=$2 [ -z "$pid" ] && return 1 [ ! -d /proc/$pid ] && return 1 cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` # Is this the expected child? [ "$cmd" != "$name" ] && return 1 return 0 } running() { # Check if the process is running looking at /proc # (works for all users) # No pidfile, probably no daemon present [ ! -f "$PIDFILE" ] && return 1 # Obtain the pid and check it against the binary name pid=`cat $PIDFILE` running_pid $pid $NAME || return 1 return 0 } force_stop() { # Forcefully kill the process [ ! -f "$PIDFILE" ] && return if running ; then kill -15 $pid # Is it really dead? [ -n "$DODTIME" ] && sleep "$DODTIME"s if running ; then kill -9 $pid [ -n "$DODTIME" ] && sleep "$DODTIME"s if running ; then echo "Cannot kill $LABEL (pid=$pid)!" exit 1 fi fi fi rm -f $PIDFILE return 0 } case "$1" in start) echo -n "Starting $DESC: " start-stop-daemon --start --quiet --pidfile $PIDFILE \ --exec $DAEMON -- $DAEMON_OPTS if running then echo "$NAME." else echo " ERROR." fi ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --stop --quiet --pidfile $PIDFILE \ --exec $DAEMON echo "$NAME." ;; force-stop) echo -n "Forcefully stopping $DESC: " force_stop if ! running then echo "$NAME." else echo " ERROR." fi ;; #reload) # # If the daemon can reload its config files on the fly # for example by sending it SIGHUP, do it here. # # If the daemon responds to changes in its config file # directly anyway, make this a do-nothing entry. # # echo "Reloading $DESC configuration files." # start-stop-daemon --stop --signal 1 --quiet --pidfile \ # /var/run/$NAME.pid --exec $DAEMON #;; force-reload) # # If the "reload" option is implemented, move the "force-reload" # option to the "reload" entry above. If not, "force-reload" is # just the same as "restart" except that it does nothing if the # daemon isn't already running. # check wether $DAEMON is running. If so, restart start-stop-daemon --stop --test --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON \ && $0 restart \ || exit 0 ;; restart) echo -n "Restarting $DESC: " start-stop-daemon --stop --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON [ -n "$DODTIME" ] && sleep $DODTIME start-stop-daemon --start --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS echo "$NAME." ;; status) echo -n "$LABEL is " if running ; then echo "running" else echo " not running." exit 1 fi ;; *) N=/etc/init.d/$NAME # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2 exit 1 ;; esac exit 0 ibus-table-1.17.11/debian/init.d.lsb.ex000066400000000000000000000205771475513533100174570ustar00rootroot00000000000000#!/bin/sh # # Example init.d script with LSB support. # # Please read this init.d carefully and modify the sections to # adjust it to the program you want to run. # # Copyright (c) 2007 Javier Fernandez-Sanguino # # This is free software; you may redistribute it and/or modify # it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2, # or (at your option) any later version. # # This is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License with # the Debian operating system, in /usr/share/common-licenses/GPL; if # not, write to the Free Software Foundation, Inc., 59 Temple Place, # Suite 330, Boston, MA 02111-1307 USA # ### BEGIN INIT INFO # Provides: ibus-table # Required-Start: $network $local_fs # Required-Stop: # Should-Start: $named # Should-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: # Description: # <...> # <...> ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/ibus-table # Introduce the server's location here NAME=#PACKAGE # Introduce the short server's name here DESC=#PACKAGE # Introduce a short description here LOGDIR=/var/log/ibus-table # Log directory to use PIDFILE=/var/run/$NAME.pid test -x $DAEMON || exit 0 test -x $DAEMON_WRAPPER || exit 0 . /lib/lsb/init-functions # Default options, these can be overriden by the information # at /etc/default/$NAME DAEMON_OPTS="" # Additional options given to the server DODTIME=10 # Time to wait for the server to die, in seconds # If this value is set too low you might not # let some servers to die gracefully and # 'restart' will not work LOGFILE=$LOGDIR/$NAME.log # Server logfile #DAEMONUSER=ibus-table # Users to run the daemons as. If this value # is set start-stop-daemon will chuid the server # Include defaults if available if [ -f /etc/default/$NAME ] ; then . /etc/default/$NAME fi # Use this if you want the user to explicitly set 'RUN' in # /etc/default/ #if [ "x$RUN" != "xyes" ] ; then # log_failure_msg "$NAME disabled, please adjust the configuration to your needs " # log_failure_msg "and then set RUN to 'yes' in /etc/default/$NAME to enable it." # exit 1 #fi # Check that the user exists (if we set a user) # Does the user exist? if [ -n "$DAEMONUSER" ] ; then if getent passwd | grep -q "^$DAEMONUSER:"; then # Obtain the uid and gid DAEMONUID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $3}'` DAEMONGID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $4}'` else log_failure_msg "The user $DAEMONUSER, required to run $NAME does not exist." exit 1 fi fi set -e running_pid() { # Check if a given process pid's cmdline matches a given name pid=$1 name=$2 [ -z "$pid" ] && return 1 [ ! -d /proc/$pid ] && return 1 cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` # Is this the expected server [ "$cmd" != "$name" ] && return 1 return 0 } running() { # Check if the process is running looking at /proc # (works for all users) # No pidfile, probably no daemon present [ ! -f "$PIDFILE" ] && return 1 pid=`cat $PIDFILE` running_pid $pid $DAEMON_WRAPPER || return 1 return 0 } start_server() { # Start the process using the wrapper if [ -z "$DAEMONUSER" ] ; then start-stop-daemon --start --quiet --pidfile $PIDFILE \ --exec $DAEMON -- $DAEMON_OPTS errcode=$? else # if we are using a daemonuser then change the user id start-stop-daemon --start --quiet --pidfile $PIDFILE \ --chuid $DAEMONUSER \ --exec $DAEMON -- $DAEMON_OPTS errcode=$? fi return $errcode } stop_server() { # Stop the process using the wrapper if [ -z "$DAEMONUSER" ] ; then start-stop-daemon --stop --quiet --pidfile $PIDFILE \ --exec $DAEMON errcode=$ else # if we are using a daemonuser then look for process that match start-stop-daemon --stop --quiet --pidfile $PIDFILE \ --user $DAEMONUSER \ --exec $DAEMON errcode=$ fi return $errcode } reload_server() { [ ! -f "$PIDFILE" ] && return 1 pid=`cat $PIDFILE` # This is the daemon's pid # Send a SIGHUP kill -1 $pid return $? } force_stop() { # Force the process to die killing it manually [ ! -e "$PIDFILE" ] && return if running ; then kill -15 $pid # Is it really dead? sleep "$DIETIME"s if running ; then kill -9 $pid sleep "$DIETIME"s if running ; then echo "Cannot kill $NAME (pid=$pid)!" exit 1 fi fi fi rm -f $PIDFILE } case "$1" in start) log_daemon_msg "Starting $DESC " "$NAME" # Check if it's running first if running ; then log_progress_msg "apparently already running" log_end_msg 0 exit 0 fi if start_server && running ; then # It's ok, the server started and is running log_end_msg 0 else # Either we could not start it or it is not running # after we did # NOTE: Some servers might die some time after they start, # this code does not try to detect this and might give # a false positive (use 'status' for that) log_end_msg 1 fi ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" if running ; then # Only stop the server if we see it running stop_server log_end_msg $? else # If it's not running don't do anything log_progress_msg "apparently not running" log_end_msg 0 exit 0 fi ;; force-stop) # First try to stop gracefully the program $0 stop if running; then # If it's still running try to kill it more forcefully log_daemon_msg "Stopping (force) $DESC" "$NAME" force_stop log_end_msg $? fi ;; restart|force-reload) log_daemon_msg "Restarting $DESC" "$NAME" stop_server # Wait some sensible amount, some server need this [ -n "$DIETIME" ] && sleep $DIETIME start_server running log_end_msg $? ;; status) log_daemon_msg "Checking status of $DESC" "$NAME" if running ; then log_progress_msg "running" log_end_msg 0 else log_progress_msg "apparently not running" log_end_msg 1 exit 1 fi ;; # Use this if the daemon cannot reload reload) log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon" log_warning_msg "cannot re-read the config file (use restart)." ;; # And this if it cann #reload) # # If the daemon can reload its config files on the fly # for example by sending it SIGHUP, do it here. # # If the daemon responds to changes in its config file # directly anyway, make this a do-nothing entry. # # log_daemon_msg "Reloading $DESC configuration files" "$NAME" # if running ; then # reload_server # if ! running ; then # Process died after we tried to reload # log_progress_msg "died on reload" # log_end_msg 1 # exit 1 # fi # else # log_progress_msg "server is not running" # log_end_msg 1 # exit 1 # fi #;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2 exit 1 ;; esac exit 0 ibus-table-1.17.11/debian/manpage.1.ex000066400000000000000000000033411475513533100172500ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH IBUS-TABLE SECTION "九月 11, 2008" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME ibus-table \- program to do something .SH SYNOPSIS .B ibus-table .RI [ options ] " files" ... .br .B bar .RI [ options ] " files" ... .SH DESCRIPTION This manual page documents briefly the .B ibus-table and .B bar commands. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBibus-table\fP is a program that... .SH OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the Info files. .TP .B \-h, \-\-help Show summary of options. .TP .B \-v, \-\-version Show version of program. .SH SEE ALSO .BR bar (1), .BR baz (1). .br The programs are documented fully by .IR "The Rise and Fall of a Fooish Bar" , available via the Info system. .SH AUTHOR ibus-table was written by . .PP This manual page was written by oneleaf , for the Debian project (but may be used by others). ibus-table-1.17.11/debian/manpage.sgml.ex000066400000000000000000000110461475513533100200530ustar00rootroot00000000000000 manpage.1'. You may view the manual page with: `docbook-to-man manpage.sgml | nroff -man | less'. A typical entry in a Makefile or Makefile.am is: manpage.1: manpage.sgml docbook-to-man $< > $@ The docbook-to-man binary is found in the docbook-to-man package. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include docbook-to-man in your Build-Depends control field. --> FIRSTNAME"> SURNAME"> 九月 11, 2008"> SECTION"> oneleaf@gmail.com"> IBUS-TABLE"> Debian"> GNU"> GPL"> ]>

&dhemail;
&dhfirstname; &dhsurname; 2003 &dhusername; &dhdate; &dhucpackage; &dhsection; &dhpackage; program to do something &dhpackage; DESCRIPTION This manual page documents briefly the &dhpackage; and bar commands. This manual page was written for the &debian; distribution because the original program does not have a manual page. Instead, it has documentation in the &gnu; Info format; see below. &dhpackage; is a program that... OPTIONS These programs follow the usual &gnu; command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the Info files. Show summary of options. Show version of program. SEE ALSO bar (1), baz (1). The programs are documented fully by The Rise and Fall of a Fooish Bar available via the Info system. AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the &gnu; General Public License, Version 2 any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. ibus-table-1.17.11/debian/manpage.xml.ex000066400000000000000000000106721475513533100177150ustar00rootroot00000000000000 .
will be generated. You may view the manual page with: nroff -man .
| less'. A typical entry in a Makefile or Makefile.am is: DB2MAN=/usr/share/sgml/docbook/stylesheet/xsl/nwalsh/\ manpages/docbook.xsl XP=xsltproc -''-nonet manpage.1: manpage.dbk $(XP) $(DB2MAN) $< The xsltproc binary is found in the xsltproc package. The XSL files are in docbook-xsl. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include xsltproc and docbook-xsl in your Build-Depends control field. --> FIRSTNAME"> SURNAME"> 九月 11, 2008"> SECTION"> oneleaf@gmail.com"> IBUS-TABLE"> Debian"> GNU"> GPL"> ]>
&dhemail;
2007 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; program to do something &dhpackage; DESCRIPTION This manual page documents briefly the &dhpackage; and bar commands. This manual page was written for the &debian; distribution because the original program does not have a manual page. Instead, it has documentation in the &gnu; Info format; see below. &dhpackage; is a program that... OPTIONS These programs follow the usual &gnu; command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the Info files. Show summary of options. Show version of program. SEE ALSO bar (1), baz (1). The programs are documented fully by The Rise and Fall of a Fooish Bar available via the Info system. AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the &gnu; General Public License, Version 2 any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
ibus-table-1.17.11/debian/menu.ex000066400000000000000000000002071475513533100164430ustar00rootroot00000000000000?package(ibus-table):needs="X11|text|vc|wm" section="Applications/see-menu-manual"\ title="ibus-table" command="/usr/bin/ibus-table" ibus-table-1.17.11/debian/postinst.ex000066400000000000000000000017021475513533100173630ustar00rootroot00000000000000#!/bin/sh # postinst script for ibus-table # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `configure' # * `abort-upgrade' # * `abort-remove' `in-favour' # # * `abort-remove' # * `abort-deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in configure) ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 ibus-table-1.17.11/debian/postrm.ex000066400000000000000000000016471475513533100170340ustar00rootroot00000000000000#!/bin/sh # postrm script for ibus-table # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `purge' # * `upgrade' # * `failed-upgrade' # * `abort-install' # * `abort-install' # * `abort-upgrade' # * `disappear' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 ibus-table-1.17.11/debian/preinst.ex000066400000000000000000000012671475513533100171720ustar00rootroot00000000000000#!/bin/sh # preinst script for ibus-table # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `install' # * `install' # * `upgrade' # * `abort-upgrade' # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in install|upgrade) ;; abort-upgrade) ;; *) echo "preinst called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 ibus-table-1.17.11/debian/prerm.ex000066400000000000000000000015621475513533100166310ustar00rootroot00000000000000#!/bin/sh # prerm script for ibus-table # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `upgrade' # * `failed-upgrade' # * `remove' `in-favour' # * `deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in remove|upgrade|deconfigure) ;; failed-upgrade) ;; *) echo "prerm called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 ibus-table-1.17.11/debian/rules000077500000000000000000000000541475513533100162210ustar00rootroot00000000000000#!/usr/bin/make -f %: dh $@ --with python2 ibus-table-1.17.11/debian/watch.ex000066400000000000000000000012611475513533100166060ustar00rootroot00000000000000# Example watch control file for uscan # Rename this file to "watch" and then you can run the "uscan" command # to check for upstream updates and more. # See uscan(1) for format # Compulsory line, this is a version 3 file version=3 # Uncomment to examine a Webpage # #http://www.example.com/downloads.php ibus-table-(.*)\.tar\.gz # Uncomment to examine a Webserver directory #http://www.example.com/pub/ibus-table-(.*)\.tar\.gz # Uncommment to examine a FTP server #ftp://ftp.example.com/pub/ibus-table-(.*)\.tar\.gz debian uupdate # Uncomment to find new files on sourceforge, for debscripts >= 2.9 # http://sf.net/ibus-table/ibus-table-(.*)\.tar\.gz ibus-table-1.17.11/engine/000077500000000000000000000000001475513533100151655ustar00rootroot00000000000000ibus-table-1.17.11/engine/.gitignore000066400000000000000000000001441475513533100171540ustar00rootroot00000000000000table.xml table.xml.in version.py ibus-engine-table ibus-table-createdb ibus-table-createdb.1 *.pyc ibus-table-1.17.11/engine/Makefile.am000066400000000000000000000040341475513533100172220ustar00rootroot00000000000000# vim:set noet ts=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # DOC2MAN = docbook2man SGML = ibus-table-createdb.sgml BUILT_MANS = ibus-table-createdb.1 man_MANS = $(BUILT_MANS) engine_table_PYTHON = \ chinese_variants.py \ ibus_table_location.py \ factory.py \ main.py \ table.py \ tabcreatedb.py \ tabsqlitedb.py \ it_util.py \ it_active_window.py \ it_sound.py \ version.py \ $(NULL) engine_table_DATA = \ $(NULL) engine_tabledir = $(datadir)/ibus-table/engine bin_SCRIPTS = ibus-table-createdb libexec_SCRIPTS = ibus-engine-table engine_DATA = table.xml enginedir = $(datadir)/ibus/component EXTRA_DIST = \ version.py.in \ ibus-table-createdb.in \ ibus-engine-table.in \ table.xml.in \ $(SGML) \ $(BUILT_MANS) \ $(NULL) CLEANFILES = \ *.pyc \ *.pyo \ ibus-engine-table \ ibus-table-createdb \ table.xml \ $(NULL) MAINTAINERCLEANFILES = \ Makefile.in \ $(NULL) ${man_MANS}: ${SGML} $(AM_V_GEN) $(RM) $@; \ $(DOC2MAN) ${SGML}; \ $(RM) manpage.* table.xml: table.xml.in ( \ libexecdir=${libexecdir}; \ pkgdatadir=${pkgdatadir}; \ s=`cat $<`; \ eval "echo \"$${s}\""; \ ) > $@ test: $(ENV) \ IBUS_TABLE_LOCATION=$(abs_top_srcdir) \ DBUS_DEBUG=true \ LANG=en_US \ PYTHONPATH=$(abs_top_srcdir) \ $(PYTHON) $(srcdir)/main.py ibus-table-1.17.11/engine/chinese_variants.py000066400000000000000000005621651475513533100211030ustar00rootroot00000000000000# auto-generated by “generate-chinese-variants.py”, do not edit here! # # Copyright (c) 2013 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 3.0 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . VARIANTS_TABLE = { # Meaning of the bits in the values: # 1 = 1 << 0 simplified Chinese # 2 = 1 << 1 traditional Chinese # 3 = (1 | 1 << 1) used both in simplified *and* traditional Chinese # 4 = 1 << 2 mixture of simplified and traditional Chinese '〇': 3, '㐷': 1, '㐹': 1, '㐽': 1, '㑇': 1, '㑈': 1, '㑔': 1, '㑩': 1, '㑮': 2, '㑯': 2, '㑳': 2, '㑶': 2, '㑺': 1, '㒓': 2, '㒖': 2, '㒜': 2, '㒣': 2, '㒿': 2, '㓄': 2, '㓖': 2, '㓥': 1, '㓨': 2, '㔃': 2, '㔅': 2, '㔉': 1, '㔋': 2, '㔝': 2, '㔢': 2, '㕒': 2, '㕢': 2, '㖊': 1, '㖞': 1, '㖦': 2, '㖮': 2, '㗙': 2, '㗢': 2, '㗣': 2, '㗰': 2, '㗲': 2, '㗶': 2, '㗻': 2, '㗼': 2, '㗿': 2, '㘎': 1, '㘓': 2, '㘔': 2, '㘖': 2, '㘙': 2, '㘚': 2, '㘤': 2, '㙔': 2, '㙡': 2, '㙢': 2, '㙬': 2, '㙺': 2, '㙾': 2, '㚯': 1, '㛀': 1, '㛍': 2, '㛝': 2, '㛟': 1, '㛠': 1, '㛣': 1, '㛤': 1, '㛿': 1, '㜄': 2, '㜏': 2, '㜐': 2, '㜕': 2, '㜗': 2, '㜞': 2, '㜢': 2, '㜥': 2, '㜭': 2, '㜮': 2, '㜰': 2, '㜷': 2, '㜺': 2, '㝞': 2, '㝟': 2, '㝦': 1, '㞞': 2, '㟆': 1, '㟜': 1, '㟥': 1, '㟦': 2, '㟺': 2, '㠁': 2, '㠆': 2, '㠏': 2, '㠠': 2, '㠣': 2, '㡎': 1, '㡓': 2, '㡞': 2, '㢗': 2, '㢝': 2, '㤖': 1, '㤘': 1, '㤭': 1, '㤲': 2, '㤽': 1, '㥪': 1, '㥮': 2, '㥷': 2, '㦈': 1, '㦊': 2, '㦎': 2, '㦖': 2, '㦛': 2, '㦞': 2, '㦡': 2, '㦦': 2, '㦬': 2, '㦭': 2, '㧏': 1, '㧐': 1, '㧑': 1, '㧛': 1, '㧟': 1, '㧰': 1, '㨛': 2, '㨟': 2, '㨥': 2, '㨫': 1, '㨻': 2, '㩇': 2, '㩋': 2, '㩌': 2, '㩜': 2, '㩣': 2, '㩭': 2, '㩳': 2, '㩵': 2, '㩷': 2, '㩹': 2, '㪎': 2, '㪹': 2, '㬢': 2, '㬣': 2, '㬮': 2, '㭎': 1, '㭏': 1, '㭣': 1, '㭤': 1, '㭴': 1, '㮓': 2, '㮝': 2, '㮠': 1, '㮲': 2, '㮿': 2, '㯂': 2, '㯆': 2, '㯤': 2, '㯸': 2, '㯼': 2, '㰂': 2, '㰄': 2, '㰅': 2, '㰍': 2, '㰰': 2, '㰳': 2, '㱩': 1, '㱮': 1, '㲯': 2, '㲰': 2, '㲲': 2, '㲿': 1, '㳔': 1, '㳕': 1, '㳠': 1, '㳡': 1, '㳢': 1, '㳽': 3, '㴋': 1, '㴸': 2, '㴿': 2, '㵍': 2, '㵑': 2, '㵒': 2, '㵗': 2, '㵤': 2, '㵾': 2, '㶆': 2, '㶉': 1, '㶌': 2, '㶍': 2, '㶏': 2, '㶒': 2, '㶕': 2, '㶶': 1, '㶽': 1, '㷃': 2, '㷍': 2, '㷪': 1, '㷲': 2, '㷶': 2, '㷻': 2, '㷿': 2, '㸅': 2, '㸊': 2, '㸐': 2, '㹓': 2, '㹽': 2, '㺍': 1, '㺏': 2, '㺑': 2, '㺜': 2, '㻅': 1, '㻏': 1, '㻘': 1, '㻪': 1, '㻶': 2, '㻽': 2, '㼀': 2, '㼁': 2, '㼆': 2, '㼈': 2, '㼻': 2, '㾡': 1, '㾵': 2, '㾺': 2, '㿉': 2, '㿎': 2, '㿖': 2, '㿗': 2, '㿧': 2, '㿹': 2, '䀉': 2, '䀍': 2, '䀥': 1, '䀴': 2, '䀹': 2, '䁖': 1, '䁝': 2, '䁪': 2, '䁱': 2, '䁻': 2, '䂎': 2, '䂓': 2, '䂵': 1, '䃁': 2, '䃅': 1, '䃕': 2, '䃘': 2, '䃢': 2, '䃣': 2, '䃤': 2, '䃮': 2, '䃴': 2, '䅉': 1, '䅐': 2, '䅘': 2, '䅟': 1, '䅪': 1, '䅳': 2, '䆅': 2, '䆉': 2, '䇓': 2, '䇚': 1, '䇲': 1, '䉆': 2, '䉍': 2, '䉐': 2, '䉑': 2, '䉙': 2, '䉤': 1, '䉬': 2, '䉱': 2, '䉲': 2, '䉶': 2, '䊜': 2, '䊟': 2, '䊭': 2, '䊲': 2, '䊵': 2, '䊷': 2, '䊺': 2, '䋃': 2, '䋆': 2, '䋍': 2, '䋎': 2, '䋏': 2, '䋐': 2, '䋑': 2, '䋔': 2, '䋙': 2, '䋚': 2, '䋦': 2, '䋫': 2, '䋹': 2, '䋺': 2, '䋻': 2, '䋼': 2, '䋽': 2, '䋾': 2, '䋿': 2, '䌁': 2, '䌇': 2, '䌈': 2, '䌋': 2, '䌌': 2, '䌐': 2, '䌖': 2, '䌝': 2, '䌞': 2, '䌟': 2, '䌥': 2, '䌪': 2, '䌰': 2, '䌶': 1, '䌷': 1, '䌸': 1, '䌹': 1, '䌺': 1, '䌻': 1, '䌼': 1, '䌽': 1, '䌾': 1, '䌿': 1, '䍀': 1, '䍁': 1, '䍤': 2, '䍷': 2, '䍽': 2, '䎘': 2, '䎙': 2, '䎬': 1, '䎱': 2, '䏊': 2, '䏝': 1, '䐢': 2, '䐣': 2, '䐪': 1, '䐷': 2, '䐹': 2, '䐽': 2, '䑗': 2, '䑼': 2, '䓓': 1, '䓕': 1, '䓖': 1, '䓣': 2, '䓨': 1, '䔇': 2, '䔈': 2, '䔡': 2, '䕏': 2, '䕡': 2, '䕤': 2, '䕳': 2, '䕹': 2, '䕼': 2, '䖀': 2, '䖅': 2, '䖚': 2, '䖼': 1, '䗃': 2, '䗅': 2, '䗖': 1, '䗥': 2, '䗻': 2, '䗽': 2, '䗿': 2, '䘛': 1, '䘞': 1, '䙊': 1, '䙌': 1, '䙓': 1, '䙔': 2, '䙡': 2, '䙱': 2, '䙼': 2, '䚆': 2, '䚉': 2, '䚕': 2, '䚞': 2, '䚩': 2, '䚳': 2, '䚵': 2, '䚽': 2, '䛀': 2, '䛄': 2, '䛌': 2, '䛍': 2, '䛓': 1, '䛘': 2, '䛛': 2, '䛞': 2, '䛠': 2, '䛤': 2, '䛬': 2, '䛭': 2, '䛳': 2, '䛴': 2, '䛽': 2, '䛿': 2, '䜀': 2, '䜄': 2, '䜉': 2, '䜋': 2, '䜍': 2, '䜎': 2, '䜏': 2, '䜒': 2, '䜖': 2, '䜚': 2, '䜝': 2, '䜣': 1, '䜤': 1, '䜥': 1, '䜧': 1, '䜩': 1, '䝏': 2, '䝕': 2, '䝙': 1, '䝭': 2, '䝯': 2, '䝻': 2, '䝼': 2, '䞀': 2, '䞁': 2, '䞂': 2, '䞈': 2, '䞉': 2, '䞋': 2, '䞌': 1, '䞍': 1, '䞎': 1, '䞐': 1, '䞓': 2, '䞶': 2, '䟃': 2, '䟆': 2, '䟏': 2, '䟐': 2, '䟢': 1, '䟺': 2, '䠆': 2, '䠟': 2, '䠠': 2, '䠩': 2, '䠮': 2, '䠱': 2, '䡁': 2, '䡄': 2, '䡅': 2, '䡇': 2, '䡊': 2, '䡐': 2, '䡗': 2, '䡘': 2, '䡝': 2, '䡟': 2, '䡦': 2, '䡩': 2, '䡰': 2, '䡴': 2, '䡵': 2, '䡶': 2, '䡷': 2, '䡻': 2, '䡾': 2, '䢀': 1, '䢁': 1, '䢂': 1, '䢈': 2, '䢨': 2, '䤌': 2, '䤍': 2, '䤠': 2, '䤤': 2, '䤥': 2, '䤨': 2, '䤩': 2, '䤪': 2, '䤬': 2, '䤭': 2, '䤵': 2, '䤸': 2, '䤻': 2, '䤼': 2, '䥄': 2, '䥇': 2, '䥑': 2, '䥓': 2, '䥕': 2, '䥖': 2, '䥗': 2, '䥛': 2, '䥝': 2, '䥞': 2, '䥩': 2, '䥯': 2, '䥱': 2, '䥴': 2, '䥶': 2, '䥷': 2, '䥸': 2, '䥺': 1, '䥽': 1, '䥾': 1, '䥿': 1, '䦀': 1, '䦁': 1, '䦂': 1, '䦃': 1, '䦅': 1, '䦆': 1, '䦌': 2, '䦎': 2, '䦖': 2, '䦘': 2, '䦛': 2, '䦝': 2, '䦟': 2, '䦣': 2, '䦪': 2, '䦯': 2, '䦱': 2, '䦳': 2, '䦶': 1, '䦷': 1, '䧞': 2, '䧢': 2, '䨴': 2, '䩄': 1, '䩤': 2, '䩫': 2, '䪊': 2, '䪍': 2, '䪏': 2, '䪐': 2, '䪓': 2, '䪗': 2, '䪘': 2, '䪜': 2, '䪝': 2, '䪥': 2, '䪴': 2, '䪼': 2, '䪾': 2, '䫀': 2, '䫂': 2, '䫈': 2, '䫉': 2, '䫌': 2, '䫏': 2, '䫐': 2, '䫜': 2, '䫟': 2, '䫠': 2, '䫥': 2, '䫩': 2, '䫴': 2, '䫶': 2, '䫻': 2, '䫼': 2, '䫾': 2, '䬀': 2, '䬂': 2, '䬅': 2, '䬍': 2, '䬎': 2, '䬐': 2, '䬓': 2, '䬔': 2, '䬘': 2, '䬝': 2, '䬞': 2, '䬟': 2, '䬣': 2, '䬧': 2, '䬪': 2, '䬫': 2, '䬬': 2, '䬯': 2, '䬲': 2, '䬳': 2, '䬶': 2, '䬹': 2, '䬾': 2, '䭀': 2, '䭃': 2, '䭅': 2, '䭇': 2, '䭈': 2, '䭉': 2, '䭑': 2, '䭒': 2, '䭓': 2, '䭔': 2, '䭕': 2, '䭘': 2, '䭞': 2, '䭡': 2, '䭢': 2, '䭣': 2, '䭪': 1, '䭭': 2, '䭿': 2, '䮂': 2, '䮄': 2, '䮈': 2, '䮗': 2, '䮝': 2, '䮞': 2, '䮠': 2, '䮧': 2, '䮫': 2, '䮰': 2, '䮲': 2, '䮳': 2, '䮸': 2, '䮽': 2, '䮾': 2, '䮿': 2, '䯀': 2, '䯃': 1, '䯄': 1, '䯅': 1, '䯤': 2, '䰎': 2, '䰐': 2, '䰖': 2, '䰫': 2, '䰲': 2, '䰷': 2, '䰻': 2, '䰽': 2, '䰾': 2, '䱀': 2, '䱁': 2, '䱂': 2, '䱅': 2, '䱇': 2, '䱌': 2, '䱍': 2, '䱎': 2, '䱐': 2, '䱒': 2, '䱓': 2, '䱗': 2, '䱙': 2, '䱚': 2, '䱛': 2, '䱜': 2, '䱟': 2, '䱡': 2, '䱤': 2, '䱥': 2, '䱧': 2, '䱬': 2, '䱭': 2, '䱰': 2, '䱱': 2, '䱴': 2, '䱵': 2, '䱷': 2, '䱸': 2, '䱹': 2, '䱻': 2, '䱽': 2, '䱾': 2, '䲁': 2, '䲅': 2, '䲉': 2, '䲏': 2, '䲕': 2, '䲖': 2, '䲗': 2, '䲘': 2, '䲙': 2, '䲚': 2, '䲛': 2, '䲝': 1, '䲞': 1, '䲟': 1, '䲠': 1, '䲡': 1, '䲢': 1, '䲣': 1, '䲤': 1, '䲨': 2, '䲰': 2, '䲸': 2, '䲹': 2, '䲼': 2, '䳅': 2, '䳇': 2, '䳍': 2, '䳏': 2, '䳒': 2, '䳓': 2, '䳕': 2, '䳚': 2, '䳜': 2, '䳟': 2, '䳢': 2, '䳤': 2, '䳥': 2, '䳧': 2, '䳨': 2, '䳫': 2, '䳭': 2, '䳮': 2, '䳲': 2, '䳺': 2, '䳽': 2, '䴇': 2, '䴈': 2, '䴉': 2, '䴋': 2, '䴏': 2, '䴓': 1, '䴔': 1, '䴕': 1, '䴖': 1, '䴗': 1, '䴘': 1, '䴙': 1, '䴚': 2, '䴝': 2, '䴬': 2, '䴭': 2, '䴮': 2, '䴱': 2, '䴲': 2, '䴳': 2, '䴴': 2, '䴵': 2, '䴷': 2, '䴸': 2, '䴹': 2, '䴺': 2, '䴽': 2, '䵂': 2, '䵃': 2, '䵆': 2, '䵐': 2, '䵘': 2, '䵳': 2, '䵴': 2, '䵶': 2, '䵷': 2, '䶕': 2, '䶗': 2, '䶢': 2, '䶣': 2, '䶦': 2, '䶧': 2, '䶨': 2, '䶪': 2, '䶮': 1, '䶱': 2, '䶲': 2, '万': 3, '与': 1, '丑': 3, '专': 1, '业': 1, '丛': 1, '东': 1, '丝': 1, '丟': 2, '丢': 3, '两': 3, '严': 1, '並': 2, '丧': 1, '个': 3, '丰': 3, '临': 1, '为': 1, '丽': 1, '举': 1, '么': 3, '义': 3, '乌': 1, '乐': 3, '乔': 3, '习': 1, '乡': 1, '书': 1, '买': 1, '乱': 3, '乾': 3, '亂': 2, '了': 3, '争': 3, '于': 3, '亏': 3, '云': 3, '亚': 1, '亞': 2, '产': 1, '亩': 1, '亲': 1, '亵': 1, '亸': 1, '亿': 1, '仅': 3, '仆': 3, '从': 3, '仑': 1, '仓': 1, '仪': 3, '们': 1, '价': 3, '众': 3, '优': 3, '伙': 3, '会': 3, '伛': 1, '伞': 1, '伟': 1, '传': 1, '伡': 1, '伣': 1, '伤': 3, '伥': 1, '伦': 1, '伧': 1, '伪': 1, '伫': 1, '佇': 2, '体': 3, '余': 3, '佣': 3, '佥': 1, '併': 2, '來': 2, '侖': 2, '侠': 3, '侣': 1, '侥': 1, '侦': 1, '侧': 1, '侨': 1, '侩': 3, '侪': 1, '侬': 1, '侶': 2, '俁': 2, '係': 2, '俓': 2, '俔': 2, '俠': 2, '俣': 1, '俥': 2, '俦': 3, '俨': 1, '俩': 1, '俪': 1, '俫': 1, '俭': 1, '倀': 2, '倆': 2, '倈': 2, '倉': 2, '個': 2, '們': 2, '借': 3, '倫': 2, '倲': 2, '债': 1, '倾': 1, '偉': 2, '偑': 2, '偩': 2, '偬': 3, '側': 2, '偵': 2, '偻': 3, '偽': 2, '偾': 1, '偿': 1, '傌': 2, '傑': 2, '傖': 2, '傘': 2, '備': 2, '傢': 2, '傥': 1, '傧': 1, '储': 1, '傩': 1, '傪': 2, '傭': 2, '傯': 2, '傱': 2, '傳': 2, '傴': 2, '債': 2, '傷': 2, '傾': 2, '僀': 2, '僂': 2, '僅': 2, '僆': 2, '僉': 2, '働': 2, '僑': 2, '僓': 2, '僕': 2, '僗': 2, '僞': 2, '僤': 2, '僥': 2, '僨': 2, '僩': 2, '僴': 2, '價': 2, '僾': 2, '儀': 2, '儁': 2, '儂': 2, '億': 2, '儅': 2, '儈': 2, '儉': 2, '儐': 2, '儔': 2, '儕': 2, '儖': 2, '儘': 2, '償': 2, '儢': 2, '儣': 2, '儥': 2, '儩': 2, '優': 2, '儮': 2, '儰': 2, '儱': 2, '儲': 2, '儷': 2, '儸': 2, '儹': 2, '儺': 2, '儻': 2, '儼': 2, '儿': 3, '克': 3, '兌': 2, '兑': 3, '兒': 2, '兖': 1, '兗': 2, '党': 3, '內': 2, '兩': 2, '兰': 1, '关': 1, '兴': 1, '兹': 1, '养': 1, '兽': 1, '冁': 1, '内': 3, '冈': 1, '冊': 2, '册': 3, '写': 1, '军': 1, '农': 1, '冪': 2, '冬': 3, '冯': 1, '冲': 3, '决': 1, '况': 3, '冻': 1, '净': 1, '准': 3, '凈': 2, '凉': 3, '凍': 2, '减': 3, '凑': 3, '凔': 2, '凙': 2, '凛': 1, '凜': 2, '凟': 2, '几': 3, '凤': 3, '凫': 1, '凭': 3, '凯': 1, '凱': 2, '凴': 2, '出': 3, '击': 1, '凿': 1, '刍': 1, '划': 3, '刘': 3, '则': 1, '刚': 1, '创': 1, '删': 3, '別': 2, '刪': 2, '别': 3, '刬': 1, '刭': 1, '刮': 3, '制': 3, '刹': 3, '刽': 1, '刾': 3, '刿': 1, '剀': 1, '剂': 1, '剄': 2, '則': 2, '剋': 2, '剎': 2, '剐': 1, '剑': 1, '剗': 2, '剛': 2, '剝': 2, '剥': 1, '剧': 3, '剮': 2, '剴': 2, '創': 2, '剸': 2, '剾': 2, '劃': 2, '劇': 2, '劉': 2, '劊': 2, '劌': 2, '劍': 2, '劏': 2, '劑': 2, '劗': 2, '劚': 2, '劝': 3, '办': 3, '务': 1, '劢': 1, '动': 3, '励': 3, '劲': 1, '劳': 3, '势': 3, '勁': 2, '勋': 1, '勑': 2, '動': 2, '務': 2, '勚': 1, '勛': 2, '勝': 2, '勞': 2, '勢': 2, '勣': 2, '勩': 2, '勱': 2, '勴': 2, '勵': 2, '勸': 2, '勻': 2, '匀': 3, '匦': 1, '匭': 2, '匮': 1, '匯': 2, '匰': 2, '匱': 2, '匵': 2, '区': 3, '医': 3, '區': 2, '千': 3, '华': 1, '协': 1, '協': 2, '单': 3, '卖': 1, '卜': 3, '卢': 1, '卤': 1, '卨': 2, '卫': 1, '却': 3, '卷': 3, '卻': 2, '厂': 3, '厅': 1, '历': 3, '厉': 3, '压': 3, '厌': 1, '厍': 1, '厐': 1, '厕': 1, '厘': 3, '厙': 2, '厠': 2, '厢': 1, '厣': 1, '厦': 3, '厨': 3, '厩': 3, '厭': 2, '厮': 3, '厱': 2, '厲': 2, '厴': 2, '县': 1, '叁': 1, '参': 3, '參': 2, '叄': 2, '叆': 1, '叇': 1, '双': 3, '发': 1, '变': 1, '叙': 3, '叠': 3, '叢': 2, '只': 3, '台': 3, '叶': 3, '号': 3, '叹': 1, '叽': 1, '吁': 3, '合': 3, '同': 3, '后': 3, '向': 3, '吒': 2, '吓': 3, '吕': 1, '吗': 1, '吣': 1, '吨': 1, '听': 3, '启': 1, '吳': 2, '吴': 3, '吶': 2, '呂': 2, '呐': 1, '呒': 1, '呓': 1, '呕': 1, '呖': 1, '呗': 1, '员': 1, '呙': 1, '呛': 1, '呜': 1, '咏': 3, '咙': 1, '咛': 1, '咝': 1, '咤': 3, '咸': 3, '咼': 2, '响': 3, '哑': 1, '哒': 1, '哓': 1, '哔': 1, '哕': 1, '哗': 1, '哙': 1, '哜': 1, '哝': 1, '哟': 1, '員': 2, '哯': 2, '唄': 2, '唊': 2, '唓': 2, '唚': 2, '唛': 1, '唝': 1, '唠': 1, '唡': 1, '唢': 1, '唤': 1, '唻': 2, '問': 2, '啓': 2, '啞': 2, '啟': 2, '啢': 2, '啧': 1, '啬': 1, '啭': 1, '啮': 1, '啯': 1, '啰': 3, '啴': 1, '啸': 1, '喎': 2, '喚': 2, '喡': 2, '喪': 2, '喬': 2, '單': 2, '喲': 2, '喷': 1, '喽': 3, '喾': 1, '嗆': 2, '嗇': 2, '嗊': 2, '嗎': 2, '嗚': 2, '嗧': 2, '嗩': 2, '嗫': 1, '嗳': 1, '嗶': 2, '嗹': 2, '嗿': 2, '嘄': 2, '嘆': 2, '嘇': 2, '嘍': 2, '嘓': 2, '嘔': 2, '嘖': 2, '嘗': 2, '嘘': 1, '嘜': 2, '嘤': 1, '嘩': 2, '嘪': 2, '嘮': 2, '嘯': 2, '嘰': 2, '嘱': 3, '嘳': 2, '嘵': 2, '嘸': 2, '嘺': 2, '嘽': 2, '噁': 2, '噅': 2, '噓': 2, '噚': 2, '噜': 1, '噝': 2, '噞': 2, '噠': 2, '噥': 2, '噦': 2, '噯': 2, '噲': 2, '噴': 2, '噸': 2, '噹': 2, '嚀': 2, '嚂': 2, '嚇': 2, '嚈': 2, '嚌': 2, '嚍': 2, '嚐': 2, '嚕': 2, '嚙': 2, '嚛': 2, '嚝': 2, '嚠': 2, '嚣': 1, '嚦': 2, '嚧': 2, '嚨': 2, '嚩': 2, '嚪': 2, '嚫': 2, '嚬': 2, '嚮': 2, '嚱': 2, '嚲': 2, '嚳': 2, '嚴': 2, '嚶': 2, '嚸': 2, '嚽': 2, '嚿': 2, '囀': 2, '囁': 2, '囂': 2, '囃': 2, '囅': 2, '囇': 2, '囈': 2, '囉': 2, '囋': 2, '囌': 2, '囐': 2, '囑': 2, '囒': 2, '囕': 2, '回': 3, '团': 1, '囪': 2, '园': 3, '困': 3, '囱': 1, '围': 1, '囵': 1, '国': 1, '图': 3, '圆': 1, '圇': 2, '國': 2, '圍': 2, '園': 2, '圓': 2, '圖': 2, '團': 2, '圞': 2, '圣': 1, '圹': 1, '场': 1, '坂': 3, '坏': 3, '块': 3, '坚': 1, '坛': 3, '坜': 1, '坝': 1, '坞': 1, '坟': 1, '坠': 1, '垄': 1, '垅': 1, '垆': 1, '垒': 1, '垦': 1, '垩': 1, '垫': 1, '垭': 1, '垯': 1, '垱': 1, '垲': 1, '垴': 1, '垵': 2, '垷': 2, '垻': 2, '埉': 2, '埘': 1, '埙': 1, '埚': 1, '埡': 2, '埨': 2, '埬': 2, '埯': 1, '埰': 2, '執': 2, '堅': 2, '堈': 2, '堊': 2, '堑': 1, '堕': 3, '堖': 2, '堚': 2, '堝': 2, '堯': 2, '報': 2, '場': 2, '塆': 1, '塊': 2, '塋': 2, '塏': 2, '塒': 2, '塗': 2, '塢': 2, '塤': 2, '塵': 2, '塸': 2, '塹': 2, '塼': 2, '塿': 2, '墆': 2, '墊': 2, '墋': 2, '墏': 2, '墙': 1, '墜': 2, '墝': 2, '墠': 2, '墢': 2, '墧': 2, '墮': 2, '墳': 2, '墶': 2, '墷': 2, '墻': 2, '墾': 2, '墿': 2, '壇': 2, '壈': 2, '壋': 2, '壍': 2, '壏': 2, '壐': 2, '壒': 2, '壓': 2, '壔': 2, '壗': 2, '壘': 2, '壙': 2, '壚': 2, '壛': 2, '壝': 2, '壞': 2, '壟': 2, '壠': 2, '壢': 2, '壣': 2, '壧': 2, '壩': 2, '壪': 2, '壮': 3, '壯': 2, '声': 3, '壳': 3, '壶': 1, '壸': 1, '壺': 2, '壼': 2, '壽': 2, '处': 1, '备': 1, '复': 3, '够': 3, '夠': 2, '夢': 2, '夥': 3, '头': 3, '夸': 3, '夹': 1, '夺': 1, '夾': 2, '奁': 1, '奂': 1, '奋': 1, '奐': 2, '奖': 1, '奥': 1, '奧': 2, '奨': 1, '奩': 2, '奪': 2, '奫': 2, '奬': 2, '奮': 2, '奯': 2, '奲': 2, '奸': 3, '奼': 2, '妆': 1, '妇': 1, '妈': 1, '妝': 2, '妩': 1, '妪': 1, '妫': 1, '姍': 2, '姗': 3, '姜': 3, '姦': 2, '姹': 3, '娄': 3, '娅': 1, '娆': 1, '娇': 3, '娈': 3, '娙': 2, '娛': 2, '娱': 3, '娲': 1, '娴': 1, '婁': 2, '婡': 2, '婦': 2, '婭': 2, '婳': 1, '婴': 1, '婵': 1, '婶': 1, '婸': 2, '媁': 2, '媈': 2, '媜': 2, '媧': 2, '媪': 1, '媭': 1, '媯': 2, '媰': 2, '媼': 2, '媽': 2, '嫈': 2, '嫒': 1, '嫔': 1, '嫗': 2, '嫢': 2, '嫥': 2, '嫧': 2, '嫱': 1, '嫵': 2, '嫻': 2, '嫿': 2, '嬀': 2, '嬃': 2, '嬅': 2, '嬇': 2, '嬈': 2, '嬋': 2, '嬌': 2, '嬐': 2, '嬒': 2, '嬙': 2, '嬝': 2, '嬟': 2, '嬡': 2, '嬣': 2, '嬤': 2, '嬦': 2, '嬧': 2, '嬪': 2, '嬮': 2, '嬰': 2, '嬷': 1, '嬸': 2, '嬻': 2, '嬾': 2, '孄': 2, '孆': 2, '孇': 2, '孋': 2, '孌': 2, '孎': 2, '孏': 2, '孙': 3, '学': 1, '孪': 3, '孫': 2, '孲': 2, '學': 2, '孻': 2, '孾': 2, '孿': 2, '宁': 3, '宝': 3, '实': 3, '宠': 1, '审': 1, '宪': 1, '宫': 1, '宮': 2, '家': 3, '宽': 1, '宾': 3, '寝': 1, '寠': 2, '寢': 2, '實': 2, '寧': 2, '審': 2, '寪': 2, '寫': 2, '寬': 2, '寯': 2, '寵': 2, '寶': 2, '寷': 2, '对': 3, '寻': 1, '导': 1, '寿': 3, '将': 1, '將': 2, '專': 2, '尋': 2, '對': 2, '導': 2, '尔': 3, '尘': 1, '尝': 3, '尧': 1, '尴': 1, '尷': 2, '尸': 3, '尽': 3, '层': 1, '屃': 1, '屆': 2, '屉': 1, '届': 3, '屍': 2, '屓': 2, '屜': 2, '属': 3, '屡': 3, '屢': 2, '層': 2, '屦': 1, '屨': 2, '屩': 2, '屬': 2, '屿': 1, '岁': 3, '岂': 1, '岖': 1, '岗': 1, '岘': 1, '岙': 1, '岚': 1, '岛': 1, '岡': 2, '岭': 1, '岽': 1, '岿': 1, '峃': 1, '峄': 1, '峡': 1, '峣': 1, '峤': 1, '峥': 1, '峦': 3, '峴': 2, '島': 2, '峽': 2, '崂': 1, '崃': 1, '崄': 1, '崍': 2, '崗': 2, '崙': 2, '崠': 2, '崢': 2, '崬': 2, '崭': 1, '崱': 2, '崵': 2, '嵐': 2, '嵘': 1, '嵚': 1, '嵝': 1, '嵷': 2, '嵸': 2, '嵼': 2, '嵽': 2, '嵾': 2, '嶁': 2, '嶄': 2, '嶇': 2, '嶈': 2, '嶔': 2, '嶗': 2, '嶠': 2, '嶢': 2, '嶤': 2, '嶧': 2, '嶨': 2, '嶩': 2, '嶪': 2, '嶮': 2, '嶴': 2, '嶸': 2, '嶹': 2, '嶺': 2, '嶼': 2, '嶽': 2, '巃': 2, '巅': 1, '巆': 2, '巊': 2, '巋': 2, '巑': 2, '巒': 2, '巔': 2, '巖': 2, '巗': 2, '巘': 2, '巚': 2, '巠': 2, '巩': 1, '巯': 1, '巰': 2, '币': 1, '帅': 1, '师': 3, '帏': 1, '帐': 1, '帘': 3, '帜': 1, '帥': 2, '带': 1, '帧': 1, '師': 2, '帮': 3, '帱': 1, '帳': 2, '帴': 2, '帶': 2, '帻': 1, '帼': 1, '幀': 2, '幂': 3, '幃': 2, '幓': 2, '幗': 2, '幘': 2, '幟': 2, '幠': 2, '幣': 2, '幩': 2, '幫': 2, '幬': 2, '幰': 2, '幱': 2, '干': 3, '并': 3, '幹': 2, '幺': 2, '幾': 2, '广': 3, '庄': 3, '庆': 1, '庐': 3, '庑': 1, '库': 1, '应': 3, '庙': 3, '庞': 1, '废': 1, '庫': 2, '庲': 2, '庼': 1, '廁': 2, '廂': 2, '廄': 2, '廈': 2, '廎': 2, '廔': 2, '廕': 2, '廗': 2, '廚': 2, '廝': 2, '廞': 2, '廟': 2, '廠': 2, '廡': 2, '廢': 2, '廣': 2, '廥': 2, '廧': 2, '廩': 2, '廪': 1, '廬': 2, '廮': 2, '廳': 2, '开': 3, '异': 1, '弃': 3, '弑': 1, '弒': 2, '张': 1, '弥': 1, '弪': 1, '弯': 3, '弳': 2, '張': 2, '強': 2, '弹': 3, '强': 3, '彄': 2, '彆': 2, '彈': 2, '彌': 2, '彍': 2, '彎': 2, '归': 3, '当': 3, '录': 1, '彙': 2, '彝': 1, '彞': 2, '彟': 1, '彠': 2, '彥': 2, '彦': 3, '彨': 1, '彲': 2, '彻': 1, '征': 3, '径': 1, '後': 2, '徑': 2, '徕': 1, '從': 2, '徠': 2, '御': 3, '復': 3, '徵': 3, '徹': 2, '徿': 2, '忆': 1, '忏': 1, '志': 3, '忧': 1, '忾': 1, '怀': 3, '态': 1, '怂': 1, '怃': 1, '怄': 1, '怅': 1, '怆': 1, '怜': 3, '总': 1, '怼': 1, '怿': 1, '恆': 2, '恋': 3, '恒': 3, '恥': 2, '恳': 1, '恶': 1, '恸': 1, '恹': 1, '恺': 1, '恻': 1, '恼': 3, '恽': 1, '悅': 2, '悏': 2, '悓': 2, '悞': 2, '悦': 1, '悫': 1, '悬': 1, '悭': 1, '悮': 1, '悯': 1, '悵': 2, '悶': 2, '惀': 2, '惊': 1, '惡': 2, '惧': 3, '惨': 1, '惩': 3, '惫': 1, '惬': 1, '惭': 1, '惮': 1, '惯': 1, '惱': 2, '惲': 2, '惻': 2, '愇': 2, '愛': 2, '愜': 2, '愠': 3, '愤': 1, '愦': 1, '愨': 2, '愩': 2, '愴': 2, '愷': 2, '愾': 2, '愿': 3, '慄': 2, '態': 2, '慍': 2, '慐': 2, '慑': 1, '慖': 2, '慘': 2, '慙': 2, '慚': 2, '慟': 2, '慣': 2, '慤': 2, '慪': 2, '慫': 2, '慭': 1, '慮': 2, '慯': 2, '慱': 2, '慲': 2, '慳': 2, '慶': 2, '慸': 2, '慹': 2, '慺': 2, '憂': 2, '憅': 2, '憊': 2, '憍': 2, '憐': 2, '憑': 2, '憒': 2, '憖': 2, '憚': 2, '憢': 2, '憤': 2, '憦': 2, '憪': 2, '憫': 2, '憮': 2, '憲': 2, '憴': 2, '憶': 2, '憸': 2, '憹': 2, '懀': 2, '懇': 2, '應': 2, '懌': 2, '懍': 2, '懑': 1, '懒': 1, '懓': 2, '懔': 1, '懕': 2, '懘': 2, '懙': 2, '懜': 2, '懞': 2, '懟': 2, '懠': 2, '懣': 2, '懤': 2, '懧': 2, '懨': 2, '懩': 2, '懫': 2, '懭': 2, '懰': 2, '懲': 2, '懶': 2, '懷': 2, '懸': 2, '懺': 2, '懼': 2, '懾': 2, '戀': 2, '戁': 2, '戃': 2, '戆': 1, '戇': 2, '戋': 1, '戏': 3, '戔': 2, '戗': 1, '战': 3, '戠': 3, '戧': 2, '戩': 2, '戬': 1, '戯': 1, '戰': 2, '戱': 2, '戲': 2, '戶': 2, '户': 3, '才': 3, '扑': 3, '执': 3, '扩': 1, '扪': 1, '扫': 1, '扬': 1, '扰': 1, '折': 3, '抚': 1, '抛': 3, '抟': 1, '抠': 1, '抡': 1, '抢': 1, '护': 1, '报': 3, '担': 3, '拋': 2, '拟': 1, '拢': 1, '拣': 1, '拥': 1, '拦': 1, '拧': 1, '拨': 1, '择': 1, '挂': 3, '挙': 1, '挚': 1, '挛': 3, '挜': 1, '挝': 1, '挞': 1, '挟': 3, '挠': 1, '挡': 3, '挢': 1, '挣': 1, '挤': 1, '挥': 1, '挦': 1, '挩': 2, '挽': 3, '挾': 2, '捝': 1, '捞': 1, '损': 1, '捡': 1, '换': 1, '捣': 1, '捨': 2, '捫': 2, '据': 3, '捲': 2, '掁': 2, '掃': 2, '掄': 2, '掆': 2, '掗': 2, '掙': 2, '掚': 2, '掛': 2, '採': 2, '掳': 1, '掴': 1, '掷': 3, '掸': 1, '掺': 1, '掼': 1, '揀': 2, '揚': 2, '換': 2, '揮': 2, '揽': 1, '揾': 3, '揿': 1, '搀': 1, '搁': 1, '搂': 1, '搅': 1, '搊': 2, '損': 2, '搎': 2, '搖': 2, '搗': 2, '搵': 2, '搶': 2, '携': 3, '摀': 2, '摃': 2, '摄': 1, '摅': 1, '摆': 3, '摇': 1, '摈': 3, '摊': 3, '摋': 2, '摐': 2, '摑': 2, '摕': 2, '摙': 2, '摜': 2, '摟': 2, '摪': 2, '摫': 2, '摯': 2, '摲': 2, '摳': 2, '摶': 2, '摺': 3, '摻': 2, '摼': 2, '撄': 1, '撈': 2, '撊': 2, '撋': 2, '撌': 2, '撏': 2, '撐': 2, '撑': 3, '撓': 2, '撝': 2, '撟': 2, '撣': 2, '撥': 2, '撧': 2, '撫': 2, '撲': 2, '撳': 2, '撵': 1, '撶': 2, '撷': 1, '撸': 1, '撺': 1, '撻': 2, '撾': 2, '撿': 2, '擁': 2, '擃': 2, '擄': 2, '擇': 2, '擈': 2, '擊': 2, '擋': 2, '擓': 2, '擔': 2, '據': 2, '擜': 1, '擞': 1, '擟': 2, '擠': 2, '擣': 2, '擥': 2, '擧': 2, '擪': 2, '擫': 2, '擬': 2, '擯': 2, '擰': 2, '擱': 2, '擲': 2, '擳': 2, '擴': 2, '擷': 2, '擺': 2, '擻': 2, '擼': 2, '擽': 2, '擾': 2, '攄': 2, '攆': 2, '攋': 2, '攎': 2, '攏': 2, '攑': 2, '攒': 1, '攔': 2, '攖': 2, '攙': 2, '攛': 2, '攜': 2, '攝': 2, '攞': 2, '攢': 2, '攣': 2, '攤': 2, '攦': 2, '攧': 2, '攩': 2, '攪': 2, '攬': 2, '攳': 2, '敌': 1, '敗': 2, '敘': 2, '敛': 1, '敩': 1, '数': 3, '敳': 2, '敵': 2, '數': 2, '敺': 2, '敿': 2, '斁': 2, '斂': 2, '斃': 2, '斄': 2, '斅': 2, '斆': 2, '斋': 3, '斓': 1, '斕': 2, '斗': 3, '斩': 1, '斬': 2, '断': 3, '斷': 2, '斸': 2, '於': 2, '旋': 3, '旝': 2, '旟': 2, '无': 3, '旧': 1, '时': 3, '旷': 3, '旸': 1, '昙': 1, '昜': 2, '昼': 3, '昽': 1, '显': 1, '時': 2, '晉': 2, '晋': 3, '晒': 3, '晓': 1, '晔': 1, '晕': 1, '晖': 1, '晛': 2, '晝': 2, '暂': 1, '暅': 1, '暈': 2, '暉': 2, '暊': 2, '暐': 2, '暘': 2, '暟': 2, '暢': 2, '暧': 1, '暫': 2, '曄': 2, '曆': 2, '曇': 2, '曉': 2, '曊': 2, '曏': 2, '曖': 2, '曠': 2, '曥': 2, '曨': 2, '曬': 2, '曭': 2, '曮': 2, '曲': 3, '書': 2, '會': 2, '朥': 2, '朧': 2, '术': 3, '朱': 3, '朴': 3, '机': 3, '杀': 1, '杂': 1, '权': 3, '杆': 3, '条': 1, '来': 1, '杨': 1, '杩': 1, '杰': 3, '東': 2, '松': 3, '板': 3, '极': 3, '构': 3, '枞': 1, '枢': 1, '枣': 1, '枥': 1, '枧': 1, '枨': 1, '枪': 1, '枫': 1, '枭': 1, '柜': 3, '柠': 1, '柵': 2, '柽': 1, '栀': 3, '栅': 3, '标': 3, '栈': 1, '栉': 1, '栊': 1, '栋': 1, '栌': 1, '栎': 1, '栏': 1, '树': 1, '栖': 3, '栗': 3, '样': 1, '栾': 3, '桠': 1, '桡': 1, '桢': 1, '档': 1, '桤': 1, '桥': 1, '桦': 1, '桧': 1, '桨': 1, '桩': 1, '桪': 1, '桱': 2, '桿': 2, '梔': 2, '梖': 2, '梘': 2, '梜': 2, '條': 2, '梟': 2, '梦': 3, '梲': 2, '梼': 1, '梾': 1, '梿': 1, '检': 1, '棁': 1, '棂': 1, '棄': 2, '棆': 2, '棖': 2, '棗': 2, '棟': 2, '棡': 2, '棧': 2, '棲': 2, '棶': 2, '椁': 1, '椏': 2, '椚': 2, '椝': 1, '椟': 1, '椠': 1, '椢': 1, '椤': 1, '椫': 1, '椭': 1, '椮': 1, '椲': 2, '楇': 2, '楊': 2, '楎': 2, '楓': 2, '楨': 2, '業': 2, '極': 2, '楼': 3, '榄': 1, '榅': 1, '榇': 1, '榈': 1, '榉': 1, '榝': 2, '榪': 2, '榮': 2, '榯': 2, '榲': 2, '榿': 2, '構': 2, '槍': 2, '槚': 1, '槛': 1, '槟': 1, '槠': 1, '槤': 2, '槧': 2, '槨': 2, '槫': 2, '槮': 2, '槳': 2, '槶': 2, '槻': 2, '槼': 2, '樁': 2, '樂': 2, '樅': 2, '樓': 2, '標': 2, '樞': 2, '樠': 2, '樢': 2, '樣': 2, '横': 1, '樫': 2, '樯': 1, '樱': 1, '樲': 2, '樳': 2, '樸': 2, '樹': 2, '樺': 2, '樻': 2, '樿': 2, '橃': 2, '橅': 2, '橈': 2, '橋': 2, '橚': 2, '機': 2, '橢': 2, '橥': 1, '橨': 2, '橫': 2, '橯': 2, '橱': 1, '橹': 1, '橼': 1, '檁': 2, '檂': 2, '檉': 2, '檋': 2, '檒': 2, '檔': 2, '檛': 2, '檜': 2, '檟': 2, '檡': 2, '檢': 2, '檣': 2, '檥': 2, '檩': 1, '檭': 2, '檮': 2, '檯': 2, '檰': 2, '檲': 2, '檳': 2, '檵': 2, '檸': 2, '檻': 2, '檾': 2, '檿': 2, '櫃': 2, '櫅': 2, '櫍': 2, '櫎': 2, '櫏': 2, '櫓': 2, '櫚': 2, '櫛': 2, '櫝': 2, '櫞': 2, '櫟': 2, '櫠': 2, '櫢': 2, '櫥': 2, '櫦': 2, '櫧': 2, '櫨': 2, '櫩': 2, '櫪': 2, '櫫': 2, '櫬': 2, '櫯': 2, '櫱': 2, '櫳': 2, '櫴': 2, '櫶': 2, '櫸': 2, '櫹': 2, '櫻': 2, '櫽': 2, '欄': 2, '欆': 2, '欇': 2, '權': 2, '欍': 2, '欏': 2, '欐': 2, '欑': 2, '欒': 2, '欓': 2, '欖': 2, '欘': 2, '欞': 2, '欢': 3, '欤': 3, '欧': 1, '欽': 2, '歄': 2, '歍': 2, '歐': 2, '歕': 2, '歗': 2, '歛': 2, '歞': 2, '歟': 2, '歡': 2, '歲': 2, '歷': 2, '歸': 2, '歼': 1, '歿': 2, '殁': 1, '殇': 1, '残': 1, '殒': 1, '殓': 1, '殘': 2, '殚': 1, '殞': 2, '殡': 3, '殢': 2, '殤': 2, '殨': 2, '殫': 2, '殮': 2, '殯': 2, '殰': 2, '殲': 2, '殴': 1, '殺': 2, '殻': 2, '殼': 2, '毀': 2, '毁': 1, '毂': 1, '毄': 2, '毆': 2, '毊': 2, '毕': 1, '毙': 1, '毡': 3, '毵': 1, '毶': 1, '毿': 2, '氀': 2, '氂': 2, '氇': 1, '氈': 2, '氌': 2, '气': 3, '氢': 1, '氣': 2, '氩': 1, '氫': 2, '氬': 2, '氭': 2, '氲': 1, '氳': 2, '汇': 1, '汉': 1, '汤': 1, '汹': 3, '決': 2, '沄': 3, '沈': 3, '沒': 2, '沖': 2, '沟': 1, '没': 3, '沣': 1, '沤': 1, '沥': 1, '沦': 1, '沧': 1, '沨': 1, '沩': 1, '沪': 3, '況': 2, '泞': 1, '注': 3, '泪': 3, '泶': 1, '泷': 1, '泸': 1, '泺': 1, '泻': 1, '泼': 1, '泽': 1, '泾': 1, '洁': 1, '洒': 3, '洶': 2, '洼': 3, '浃': 1, '浅': 3, '浆': 1, '浇': 1, '浈': 1, '浉': 1, '浊': 1, '测': 1, '浍': 1, '济': 1, '浏': 1, '浐': 1, '浑': 1, '浒': 1, '浓': 1, '浔': 1, '浕': 1, '浹': 2, '浿': 2, '涂': 3, '涇': 2, '涛': 3, '涝': 1, '涞': 1, '涟': 1, '涠': 1, '涡': 1, '涢': 1, '涣': 1, '涤': 1, '润': 1, '涧': 1, '涨': 1, '涩': 1, '涷': 2, '涼': 2, '淀': 3, '淚': 2, '淥': 2, '淪': 2, '淵': 2, '淶': 2, '淺': 2, '渊': 3, '渌': 1, '渍': 1, '渎': 1, '渐': 1, '渑': 1, '渔': 1, '渖': 1, '渗': 1, '渙': 2, '減': 2, '渢': 2, '渦': 2, '温': 3, '測': 2, '渾': 2, '湊': 2, '湋': 2, '湞': 2, '湯': 2, '湾': 3, '湿': 1, '溁': 1, '溃': 1, '溅': 1, '溆': 1, '溇': 1, '溈': 2, '準': 2, '溝': 2, '溡': 2, '溤': 2, '溫': 2, '溮': 2, '溰': 2, '溳': 2, '滄': 2, '滅': 2, '滌': 2, '滎': 2, '滗': 1, '滚': 3, '滞': 1, '滟': 1, '滠': 1, '满': 1, '滢': 1, '滤': 1, '滥': 1, '滦': 3, '滨': 3, '滩': 3, '滪': 1, '滬': 2, '滭': 2, '滯': 2, '滲': 2, '滷': 2, '滸': 2, '滻': 2, '滾': 2, '滿': 2, '漁': 2, '漊': 2, '漍': 2, '漎': 2, '漐': 2, '漓': 3, '漙': 2, '漚': 2, '漢': 2, '漣': 2, '漬': 2, '漲': 2, '漵': 2, '漸': 2, '漿': 2, '潁': 2, '潆': 1, '潇': 1, '潋': 1, '潍': 1, '潑': 2, '潔': 2, '潕': 2, '潙': 2, '潚': 2, '潛': 2, '潜': 1, '潣': 2, '潤': 2, '潬': 2, '潯': 2, '潰': 2, '潴': 1, '潷': 2, '潿': 2, '澀': 2, '澅': 2, '澆': 2, '澇': 2, '澐': 2, '澒': 2, '澕': 2, '澖': 2, '澗': 2, '澛': 1, '澜': 1, '澠': 2, '澢': 2, '澤': 2, '澦': 2, '澩': 2, '澫': 2, '澬': 2, '澮': 2, '澰': 2, '澱': 2, '澾': 2, '濁': 2, '濃': 2, '濄': 2, '濆': 2, '濇': 2, '濊': 2, '濑': 1, '濒': 1, '濕': 2, '濘': 2, '濚': 2, '濛': 2, '濜': 2, '濟': 2, '濤': 2, '濧': 2, '濫': 2, '濰': 2, '濱': 2, '濴': 2, '濺': 2, '濼': 2, '濾': 2, '濿': 2, '瀁': 2, '瀂': 2, '瀃': 2, '瀄': 2, '瀅': 2, '瀆': 2, '瀇': 2, '瀈': 2, '瀉': 2, '瀋': 2, '瀏': 2, '瀕': 2, '瀗': 2, '瀘': 2, '瀙': 2, '瀝': 2, '瀟': 2, '瀠': 2, '瀢': 2, '瀦': 2, '瀧': 2, '瀨': 2, '瀭': 2, '瀯': 2, '瀰': 2, '瀲': 2, '瀳': 2, '瀴': 2, '瀵': 2, '瀾': 2, '灃': 2, '灄': 2, '灍': 2, '灏': 1, '灑': 2, '灒': 2, '灓': 2, '灕': 2, '灘': 2, '灙': 2, '灝': 2, '灟': 2, '灠': 2, '灡': 2, '灣': 2, '灤': 2, '灦': 2, '灧': 2, '灭': 1, '灯': 3, '灵': 1, '灶': 3, '災': 2, '灾': 3, '灿': 1, '炀': 1, '炉': 3, '炜': 1, '炝': 1, '点': 3, '為': 2, '炼': 1, '炽': 1, '烁': 1, '烂': 1, '烃': 1, '烏': 2, '烛': 3, '烟': 3, '烦': 1, '烧': 1, '烨': 1, '烩': 3, '烫': 1, '烬': 3, '热': 3, '烴': 2, '焕': 1, '焖': 1, '焘': 1, '焛': 2, '無': 2, '煇': 2, '煈': 2, '煉': 2, '煒': 2, '煙': 2, '煢': 2, '煥': 2, '煩': 2, '煬': 2, '煱': 2, '煴': 1, '煼': 2, '熂': 2, '熅': 2, '熉': 2, '熌': 2, '熒': 2, '熓': 2, '熕': 2, '熗': 2, '熞': 2, '熡': 2, '熰': 2, '熱': 2, '熲': 2, '熾': 2, '燀': 2, '燁': 2, '燆': 2, '燈': 2, '燌': 2, '燒': 2, '燖': 2, '燘': 2, '燙': 2, '燜': 2, '營': 2, '燡': 2, '燦': 2, '燭': 2, '燰': 2, '燴': 2, '燵': 2, '燶': 2, '燼': 2, '燽': 2, '燾': 2, '爁': 2, '爃': 2, '爄': 2, '爍': 2, '爐': 2, '爓': 2, '爖': 2, '爗': 2, '爛': 2, '爣': 2, '爥': 2, '爧': 2, '爭': 2, '爱': 1, '爲': 2, '爷': 1, '爺': 2, '爾': 2, '牆': 2, '牋': 2, '牍': 1, '牘': 2, '牦': 1, '牵': 1, '牺': 1, '牼': 2, '牽': 2, '犅': 2, '犊': 1, '犓': 2, '犖': 2, '犞': 2, '犢': 2, '犤': 2, '犧': 2, '状': 1, '犷': 1, '犸': 1, '犹': 3, '狀': 2, '狈': 1, '狝': 1, '狞': 1, '独': 3, '狭': 1, '狮': 1, '狯': 3, '狰': 1, '狱': 1, '狲': 1, '狹': 2, '狽': 2, '猃': 1, '猌': 2, '猍': 2, '猎': 1, '猕': 3, '猙': 2, '猡': 1, '猧': 2, '猪': 3, '猫': 3, '猬': 3, '献': 3, '猶': 2, '猻': 2, '獁': 2, '獄': 2, '獅': 2, '獊': 2, '獎': 2, '獑': 2, '獖': 2, '獟': 2, '獢': 2, '獨': 2, '獩': 2, '獪': 2, '獫': 2, '獭': 1, '獮': 2, '獰': 2, '獱': 2, '獲': 2, '獵': 2, '獷': 2, '獸': 2, '獹': 2, '獺': 2, '獻': 2, '獼': 2, '玀': 2, '玁': 2, '玂': 2, '玑': 1, '玙': 1, '玚': 1, '玛': 1, '玮': 1, '环': 3, '现': 1, '玱': 1, '玺': 1, '珐': 3, '珑': 1, '珰': 1, '珲': 1, '珼': 2, '現': 2, '琎': 1, '琏': 1, '琐': 1, '琖': 2, '琺': 2, '琼': 3, '琿': 2, '瑋': 2, '瑒': 2, '瑙': 2, '瑣': 2, '瑤': 2, '瑩': 2, '瑪': 2, '瑲': 2, '瑶': 1, '瑷': 1, '瑸': 1, '瑻': 2, '瑽': 2, '璉': 2, '璊': 2, '璍': 2, '璎': 1, '璕': 2, '璗': 2, '璛': 2, '璝': 2, '璡': 2, '璣': 2, '璦': 2, '璫': 2, '璯': 2, '環': 2, '璵': 2, '璸': 2, '璹': 2, '璼': 2, '璽': 2, '璾': 2, '瓄': 2, '瓅': 2, '瓊': 2, '瓏': 2, '瓐': 2, '瓒': 1, '瓓': 2, '瓔': 2, '瓕': 2, '瓚': 2, '瓛': 2, '瓯': 1, '甊': 2, '甌': 2, '甒': 2, '甖': 2, '產': 2, '産': 2, '电': 3, '画': 3, '畅': 1, '畝': 2, '畢': 2, '畫': 2, '異': 2, '畴': 1, '當': 2, '疇': 2, '疊': 2, '疖': 1, '疗': 1, '疟': 1, '疠': 1, '疡': 1, '疬': 1, '疭': 1, '疮': 1, '疯': 1, '疱': 3, '疴': 3, '症': 3, '痈': 1, '痉': 1, '痒': 3, '痖': 1, '痙': 2, '痨': 1, '痪': 1, '痫': 1, '痮': 2, '痾': 2, '瘂': 2, '瘅': 1, '瘆': 1, '瘋': 2, '瘍': 2, '瘑': 2, '瘒': 2, '瘓': 2, '瘗': 1, '瘘': 3, '瘞': 2, '瘡': 2, '瘧': 2, '瘪': 1, '瘫': 1, '瘮': 2, '瘱': 2, '瘲': 2, '瘺': 2, '瘻': 2, '瘾': 1, '瘿': 1, '療': 2, '癆': 2, '癇': 2, '癈': 2, '癉': 2, '癎': 2, '癐': 2, '癘': 2, '癞': 1, '癟': 2, '癠': 2, '癢': 2, '癣': 1, '癤': 2, '癥': 2, '癧': 2, '癩': 2, '癪': 2, '癫': 1, '癬': 2, '癭': 2, '癮': 2, '癰': 2, '癱': 2, '癲': 2, '癴': 2, '發': 2, '皑': 1, '皚': 2, '皟': 2, '皪': 2, '皰': 2, '皱': 3, '皲': 1, '皸': 2, '皺': 2, '皾': 2, '盏': 1, '盐': 1, '监': 1, '盖': 3, '盗': 1, '盘': 1, '盜': 2, '盞': 2, '盡': 2, '監': 2, '盤': 2, '盧': 2, '盨': 2, '盪': 2, '眍': 1, '眥': 2, '眦': 3, '眬': 1, '眾': 2, '着': 3, '睁': 1, '睍': 2, '睏': 2, '睐': 1, '睑': 1, '睔': 2, '睜': 2, '睞': 2, '睪': 2, '睴': 2, '瞆': 1, '瞒': 1, '瞓': 2, '瞘': 2, '瞛': 2, '瞜': 2, '瞞': 2, '瞡': 2, '瞤': 2, '瞩': 1, '瞭': 3, '瞯': 2, '瞱': 2, '瞶': 2, '瞷': 2, '瞼': 2, '矇': 2, '矉': 2, '矊': 2, '矑': 2, '矓': 2, '矕': 2, '矖': 2, '矘': 2, '矚': 2, '矫': 3, '矯': 2, '矲': 2, '矶': 1, '矾': 1, '矿': 1, '砀': 1, '码': 1, '砖': 1, '砗': 1, '砚': 1, '砜': 1, '砺': 1, '砻': 1, '砾': 1, '础': 1, '硁': 1, '硃': 2, '硕': 1, '硖': 1, '硗': 1, '硙': 1, '硚': 1, '硜': 2, '硤': 2, '硨': 2, '确': 3, '硯': 2, '硵': 1, '硷': 1, '碍': 3, '碙': 2, '碛': 1, '碜': 1, '碢': 2, '碩': 2, '碭': 2, '碸': 2, '確': 2, '碼': 2, '碽': 2, '磑': 2, '磒': 2, '磚': 2, '磠': 2, '磣': 2, '磧': 2, '磯': 2, '磱': 2, '磵': 2, '磽': 2, '磾': 2, '礄': 2, '礆': 2, '礋': 2, '礎': 2, '礏': 2, '礐': 2, '礒': 2, '礙': 2, '礚': 2, '礛': 2, '礥': 2, '礦': 2, '礩': 2, '礪': 2, '礫': 2, '礬': 2, '礮': 2, '礰': 2, '礱': 2, '礲': 2, '礹': 2, '礼': 3, '祃': 1, '祎': 1, '祢': 3, '祯': 1, '祷': 3, '祸': 1, '祿': 2, '禀': 3, '禄': 1, '禅': 1, '禍': 2, '禎': 2, '禓': 2, '禕': 2, '禜': 2, '禡': 2, '禦': 2, '禪': 2, '禬': 2, '禮': 2, '禯': 2, '禰': 2, '禱': 2, '禵': 2, '离': 1, '禿': 2, '秃': 3, '秆': 3, '秈': 2, '秋': 3, '种': 3, '积': 1, '称': 3, '秽': 1, '秾': 1, '稅': 2, '稆': 1, '稈': 2, '税': 1, '稏': 2, '稟': 2, '稣': 1, '稦': 2, '種': 2, '稱': 2, '稳': 3, '穀': 2, '穇': 2, '穌': 2, '積': 2, '穎': 2, '穑': 1, '穖': 2, '穠': 2, '穡': 2, '穢': 2, '穧': 2, '穨': 2, '穩': 2, '穫': 2, '穬': 2, '穭': 2, '穷': 3, '窃': 3, '窍': 1, '窎': 1, '窑': 1, '窜': 1, '窝': 1, '窥': 1, '窦': 1, '窩': 2, '窪': 2, '窭': 1, '窮': 2, '窯': 2, '窱': 2, '窵': 2, '窶': 2, '窺': 2, '竀': 2, '竄': 2, '竅': 2, '竇': 2, '竈': 2, '竉': 2, '竊': 2, '竖': 1, '竞': 1, '竪': 2, '竱': 2, '競': 2, '笃': 1, '笋': 3, '笔': 3, '笕': 1, '笺': 1, '笼': 1, '笾': 1, '筆': 2, '筍': 2, '筑': 3, '筚': 1, '筛': 1, '筜': 1, '筝': 1, '筧': 2, '筴': 2, '筹': 1, '筼': 1, '签': 1, '简': 1, '箂': 2, '箋': 2, '箏': 2, '箓': 1, '箦': 1, '箧': 1, '箨': 1, '箩': 3, '箪': 1, '箫': 1, '箹': 2, '節': 2, '範': 2, '築': 2, '篋': 2, '篑': 1, '篓': 3, '篔': 2, '篘': 2, '篢': 2, '篤': 2, '篩': 2, '篮': 1, '篯': 1, '篱': 3, '篳': 2, '篵': 2, '篸': 2, '篿': 2, '簀': 2, '簂': 2, '簍': 2, '簖': 1, '簜': 2, '簞': 2, '簡': 2, '簢': 2, '簣': 2, '簥': 2, '簫': 2, '簵': 2, '簹': 2, '簻': 2, '簽': 2, '簾': 2, '籁': 1, '籃': 2, '籋': 2, '籌': 2, '籔': 2, '籙': 2, '籚': 2, '籛': 2, '籜': 2, '籟': 2, '籠': 2, '籣': 2, '籤': 2, '籦': 2, '籩': 2, '籪': 2, '籫': 2, '籬': 2, '籭': 2, '籮': 2, '籯': 2, '籲': 2, '籴': 3, '类': 1, '籼': 1, '粜': 3, '粝': 1, '粤': 1, '粪': 1, '粮': 3, '粯': 2, '粵': 2, '粻': 2, '糁': 1, '糇': 3, '糝': 2, '糞': 2, '糧': 2, '糮': 2, '糰': 2, '糲': 2, '糴': 2, '糶': 2, '糷': 2, '糹': 2, '糺': 2, '系': 3, '糽': 2, '糾': 2, '紀': 2, '紁': 2, '紂': 2, '紃': 2, '約': 2, '紅': 2, '紆': 2, '紇': 2, '紈': 2, '紉': 2, '紋': 2, '紌': 2, '納': 2, '紐': 2, '紑': 2, '紒': 2, '紓': 2, '純': 2, '紕': 2, '紖': 2, '紗': 2, '紘': 2, '紙': 2, '級': 2, '紛': 2, '紜': 2, '紝': 2, '紞': 2, '紟': 2, '紡': 2, '紧': 1, '紨': 2, '紩': 2, '紬': 2, '紭': 2, '累': 3, '細': 2, '紱': 2, '紲': 2, '紳': 2, '紵': 2, '紶': 2, '紸': 2, '紹': 2, '紺': 2, '紼': 2, '紽': 2, '紾': 2, '紿': 2, '絀': 2, '絁': 2, '終': 2, '絃': 2, '組': 2, '絅': 2, '絆': 2, '絇': 2, '絍': 2, '絎': 2, '結': 2, '絑': 2, '絓': 2, '絕': 2, '絖': 2, '絘': 2, '絙': 2, '絚': 2, '絛': 2, '絝': 2, '絞': 2, '絟': 2, '絠': 2, '絡': 2, '絢': 2, '絣': 2, '絤': 2, '絥': 2, '給': 2, '絧': 2, '絨': 2, '絪': 2, '絯': 2, '絰': 2, '統': 2, '絲': 2, '絳': 2, '絶': 2, '絷': 1, '絸': 2, '絹': 2, '絺': 2, '絻': 2, '絼': 2, '絽': 2, '絾': 2, '絿': 2, '綀': 2, '綁': 2, '綃': 2, '綄': 2, '綅': 2, '綆': 2, '綇': 2, '綈': 2, '綉': 2, '綊': 2, '綋': 2, '綌': 2, '綍': 2, '綎': 2, '綏': 2, '綐': 2, '經': 2, '綕': 2, '綖': 2, '綘': 2, '綜': 2, '綝': 2, '綞': 2, '綟': 2, '綠': 2, '綡': 2, '綢': 2, '綣': 2, '綧': 2, '綪': 2, '綫': 2, '綬': 2, '維': 2, '綯': 2, '綰': 2, '綱': 2, '網': 2, '綳': 2, '綴': 2, '綵': 2, '綷': 2, '綸': 2, '綹': 2, '綺': 2, '綻': 2, '綼': 2, '綽': 2, '綾': 2, '綿': 2, '緀': 2, '緁': 2, '緂': 2, '緄': 2, '緅': 2, '緆': 2, '緇': 2, '緉': 2, '緊': 2, '緋': 2, '緌': 2, '緍': 2, '緎': 2, '総': 2, '緑': 2, '緒': 2, '緓': 2, '緔': 2, '緗': 2, '緘': 2, '緙': 2, '線': 2, '緛': 2, '緝': 2, '緞': 2, '緟': 2, '締': 2, '緡': 2, '緢': 2, '緣': 2, '緤': 2, '緦': 2, '緧': 2, '編': 2, '緩': 2, '緪': 2, '緫': 2, '緬': 2, '緮': 2, '緯': 2, '緰': 2, '緱': 2, '緲': 2, '練': 2, '緵': 2, '緶': 2, '緷': 2, '緸': 2, '緹': 2, '緺': 2, '緻': 2, '緼': 2, '縈': 2, '縉': 2, '縊': 2, '縋': 2, '縌': 2, '縍': 2, '縎': 2, '縐': 2, '縑': 2, '縒': 2, '縓': 2, '縕': 2, '縖': 2, '縗': 2, '縚': 2, '縛': 2, '縜': 2, '縝': 2, '縞': 2, '縟': 2, '縡': 2, '縣': 2, '縧': 2, '縩': 2, '縪': 2, '縫': 2, '縬': 2, '縭': 2, '縮': 2, '縯': 2, '縰': 2, '縱': 2, '縲': 2, '縳': 2, '縴': 2, '縵': 2, '縶': 2, '縷': 2, '縸': 2, '縹': 2, '縺': 2, '縼': 2, '總': 2, '績': 2, '縿': 2, '繀': 2, '繂': 2, '繃': 2, '繅': 2, '繆': 2, '繈': 2, '繎': 2, '繏': 2, '繐': 2, '繑': 2, '繒': 2, '繓': 2, '織': 2, '繕': 2, '繖': 2, '繗': 2, '繘': 2, '繙': 2, '繚': 2, '繜': 2, '繞': 2, '繟': 2, '繡': 2, '繢': 2, '繣': 2, '繨': 2, '繩': 2, '繪': 2, '繫': 2, '繬': 2, '繭': 2, '繮': 2, '繯': 2, '繰': 2, '繲': 2, '繳': 2, '繵': 2, '繶': 2, '繷': 2, '繸': 2, '繹': 2, '繻': 2, '繼': 2, '繽': 2, '繾': 2, '繿': 2, '纀': 2, '纁': 2, '纃': 2, '纆': 2, '纇': 2, '纈': 2, '纊': 2, '纋': 2, '續': 2, '纍': 2, '纏': 2, '纑': 2, '纓': 2, '纔': 2, '纕': 2, '纖': 2, '纗': 2, '纘': 2, '纚': 2, '纜': 2, '纟': 1, '纠': 1, '纡': 1, '红': 1, '纣': 1, '纤': 1, '纥': 1, '约': 1, '级': 1, '纨': 1, '纩': 1, '纪': 1, '纫': 1, '纬': 1, '纭': 1, '纮': 1, '纯': 1, '纰': 1, '纱': 1, '纲': 1, '纳': 1, '纴': 1, '纵': 1, '纶': 1, '纷': 1, '纸': 1, '纹': 1, '纺': 1, '纻': 1, '纼': 1, '纽': 1, '纾': 1, '线': 1, '绀': 1, '绁': 1, '绂': 1, '练': 1, '组': 1, '绅': 1, '细': 1, '织': 1, '终': 1, '绉': 1, '绊': 1, '绋': 1, '绌': 1, '绍': 1, '绎': 1, '经': 1, '绐': 1, '绑': 1, '绒': 1, '结': 1, '绔': 1, '绕': 1, '绖': 1, '绗': 1, '绘': 1, '给': 1, '绚': 1, '绛': 1, '络': 1, '绝': 1, '绞': 1, '统': 1, '绠': 1, '绡': 1, '绢': 1, '绣': 1, '绤': 1, '绥': 1, '绦': 1, '继': 1, '绨': 1, '绩': 1, '绪': 1, '绫': 1, '绬': 1, '续': 1, '绮': 1, '绯': 1, '绰': 1, '绱': 1, '绲': 1, '绳': 1, '维': 1, '绵': 1, '绶': 1, '绷': 1, '绸': 1, '绹': 1, '绺': 1, '绻': 1, '综': 1, '绽': 1, '绾': 1, '绿': 1, '缀': 1, '缁': 1, '缂': 1, '缃': 1, '缄': 1, '缅': 1, '缆': 1, '缇': 1, '缈': 1, '缉': 1, '缊': 1, '缋': 1, '缌': 1, '缍': 1, '缎': 1, '缏': 1, '缐': 1, '缑': 1, '缒': 1, '缓': 1, '缔': 1, '缕': 1, '编': 1, '缗': 1, '缘': 1, '缙': 1, '缚': 1, '缛': 1, '缜': 1, '缝': 1, '缞': 1, '缟': 1, '缠': 1, '缡': 1, '缢': 1, '缣': 1, '缤': 1, '缥': 1, '缦': 1, '缧': 1, '缨': 1, '缩': 1, '缪': 1, '缫': 1, '缬': 1, '缭': 1, '缮': 1, '缯': 1, '缰': 1, '缱': 1, '缲': 1, '缳': 1, '缴': 1, '缵': 1, '缽': 2, '罂': 1, '罃': 2, '罆': 2, '罈': 2, '罌': 2, '罎': 2, '罏': 2, '网': 3, '罗': 3, '罚': 1, '罢': 3, '罰': 2, '罴': 1, '罵': 2, '罷': 2, '罼': 2, '羁': 1, '羂': 2, '羅': 2, '羆': 2, '羈': 2, '羋': 2, '羟': 1, '羥': 2, '義': 2, '羵': 2, '習': 2, '翘': 1, '翙': 1, '翚': 1, '翜': 2, '翬': 2, '翹': 2, '翽': 2, '翿': 2, '耢': 1, '耧': 1, '耬': 2, '耮': 2, '耸': 1, '耻': 3, '聂': 1, '聋': 1, '职': 3, '聍': 1, '联': 3, '聖': 2, '聞': 2, '聩': 1, '聪': 1, '聯': 2, '聰': 2, '聲': 2, '聳': 2, '聵': 2, '聶': 2, '職': 2, '聹': 2, '聻': 2, '聽': 2, '聾': 2, '肃': 1, '肅': 2, '肠': 1, '肤': 1, '肮': 3, '肴': 3, '肾': 1, '肿': 1, '胀': 1, '胁': 1, '胆': 3, '胜': 3, '胡': 3, '胧': 1, '胨': 1, '胪': 1, '胫': 1, '胶': 1, '脅': 2, '脈': 2, '脉': 3, '脍': 3, '脏': 1, '脐': 1, '脑': 1, '脓': 1, '脔': 3, '脚': 3, '脛': 2, '脥': 2, '脫': 2, '脱': 1, '脶': 1, '脸': 1, '脹': 2, '腊': 3, '腎': 2, '腖': 2, '腘': 1, '腡': 2, '腦': 2, '腪': 2, '腫': 2, '腭': 3, '腳': 2, '腸': 2, '腻': 1, '腼': 3, '腽': 1, '腾': 1, '膃': 2, '膑': 3, '膒': 2, '膕': 2, '膚': 2, '膞': 2, '膠': 2, '膢': 2, '膩': 2, '膮': 2, '膴': 2, '膶': 2, '膷': 2, '膹': 2, '膽': 2, '膾': 2, '膿': 2, '臇': 2, '臉': 2, '臍': 2, '臏': 2, '臗': 2, '臘': 2, '臚': 2, '臜': 1, '臟': 2, '臠': 2, '臡': 2, '臢': 2, '臤': 3, '臨': 2, '致': 3, '臺': 2, '舆': 1, '與': 2, '興': 2, '舉': 2, '舊': 2, '舍': 3, '舣': 1, '舰': 1, '舱': 1, '舻': 1, '艙': 2, '艛': 2, '艜': 2, '艤': 2, '艦': 2, '艫': 2, '艭': 2, '艰': 1, '艱': 2, '艳': 3, '艷': 2, '艺': 1, '节': 1, '芈': 1, '芗': 1, '芜': 1, '芦': 3, '芸': 3, '芻': 2, '苁': 1, '苇': 1, '苈': 1, '苋': 1, '苌': 1, '苍': 1, '苎': 1, '苏': 3, '苧': 2, '苹': 3, '范': 3, '茎': 1, '茏': 1, '茑': 1, '茔': 1, '茕': 1, '茧': 1, '茲': 2, '荆': 3, '荊': 2, '荐': 3, '荙': 1, '荚': 1, '荛': 1, '荜': 1, '荝': 1, '荞': 1, '荟': 1, '荠': 1, '荡': 1, '荣': 3, '荤': 1, '荥': 1, '荦': 1, '荧': 1, '荨': 1, '荩': 1, '荪': 1, '荫': 1, '荬': 1, '荭': 1, '荮': 1, '药': 1, '莅': 3, '莊': 2, '莖': 2, '莢': 2, '莧': 2, '莱': 1, '莲': 1, '莳': 1, '莴': 1, '莶': 1, '获': 1, '莸': 1, '莹': 1, '莺': 1, '莼': 1, '菕': 2, '華': 2, '萇': 2, '萊': 2, '萚': 1, '萝': 3, '萤': 1, '营': 1, '萦': 1, '萧': 1, '萨': 1, '萬': 2, '萯': 2, '萴': 2, '萵': 2, '葉': 2, '葒': 2, '著': 3, '葝': 2, '葤': 2, '葦': 2, '葯': 2, '葱': 3, '葷': 2, '葻': 2, '蒇': 1, '蒉': 1, '蒋': 1, '蒌': 1, '蒍': 2, '蒒': 2, '蒓': 2, '蒔': 2, '蒙': 3, '蒞': 2, '蒭': 2, '蒳': 2, '蒶': 2, '蒼': 2, '蓀': 2, '蓋': 2, '蓝': 1, '蓟': 1, '蓠': 1, '蓣': 1, '蓥': 1, '蓦': 1, '蓮': 2, '蓯': 2, '蓲': 2, '蓴': 2, '蓽': 2, '蔂': 3, '蔄': 2, '蔎': 2, '蔑': 3, '蔔': 2, '蔞': 2, '蔠': 2, '蔣': 2, '蔥': 2, '蔦': 2, '蔪': 2, '蔭': 2, '蔮': 2, '蔯': 2, '蔱': 2, '蔷': 1, '蔹': 1, '蔺': 1, '蔼': 1, '蔿': 2, '蕁': 2, '蕄': 2, '蕆': 2, '蕎': 2, '蕑': 2, '蕒': 2, '蕓': 2, '蕕': 2, '蕘': 2, '蕝': 2, '蕟': 2, '蕡': 2, '蕢': 2, '蕧': 2, '蕩': 2, '蕪': 2, '蕭': 2, '蕰': 1, '蕲': 1, '蕳': 2, '蕴': 1, '蕷': 2, '蕽': 2, '薀': 2, '薆': 2, '薈': 2, '薉': 2, '薊': 2, '薋': 2, '薌': 2, '薑': 2, '薔': 2, '薖': 2, '薘': 2, '薟': 2, '薠': 2, '薦': 2, '薩': 2, '薮': 1, '薱': 2, '薲': 2, '薳': 2, '薴': 2, '薵': 2, '薺': 2, '藇': 2, '藉': 3, '藍': 2, '藎': 2, '藓': 1, '藖': 2, '藘': 2, '藚': 2, '藝': 2, '藣': 2, '藥': 2, '藪': 2, '藬': 2, '藭': 2, '藰': 2, '藴': 2, '藶': 2, '藷': 2, '藹': 2, '藺': 2, '藾': 2, '蘀': 2, '蘄': 2, '蘆': 2, '蘇': 2, '蘈': 2, '蘊': 2, '蘋': 2, '蘖': 3, '蘚': 2, '蘞': 2, '蘟': 2, '蘡': 2, '蘢': 2, '蘫': 2, '蘬': 2, '蘭': 2, '蘱': 2, '蘵': 2, '蘹': 2, '蘺': 2, '蘿': 2, '虅': 2, '虆': 2, '虉': 2, '虏': 1, '虑': 1, '處': 2, '虚': 1, '虛': 2, '虜': 2, '號': 2, '虦': 2, '虧': 2, '虫': 3, '虬': 3, '虮': 1, '虯': 2, '虽': 1, '虾': 3, '虿': 1, '蚀': 1, '蚁': 3, '蚂': 1, '蚃': 1, '蚕': 3, '蚬': 1, '蛊': 1, '蛎': 1, '蛏': 1, '蛮': 3, '蛰': 3, '蛱': 1, '蛲': 1, '蛳': 1, '蛴': 1, '蛵': 2, '蛺': 2, '蛻': 2, '蛼': 2, '蜆': 2, '蜕': 1, '蜗': 1, '蜡': 3, '蜦': 2, '蜸': 2, '蜽': 2, '蝀': 2, '蝁': 2, '蝇': 1, '蝈': 1, '蝉': 1, '蝕': 2, '蝜': 2, '蝟': 2, '蝦': 2, '蝸': 2, '蝼': 3, '蝾': 1, '螀': 1, '螄': 2, '螘': 2, '螞': 2, '螢': 2, '螨': 1, '螮': 2, '螴': 2, '螹': 2, '螻': 2, '螿': 2, '蟂': 2, '蟄': 2, '蟈': 2, '蟎': 2, '蟏': 1, '蟘': 2, '蟜': 2, '蟡': 2, '蟣': 2, '蟦': 2, '蟬': 2, '蟯': 2, '蟱': 2, '蟲': 2, '蟳': 2, '蟶': 2, '蟷': 2, '蟻': 2, '蟽': 2, '蠀': 2, '蠁': 2, '蠅': 2, '蠆': 2, '蠈': 2, '蠌': 2, '蠐': 2, '蠑': 2, '蠒': 2, '蠙': 2, '蠞': 2, '蠟': 2, '蠣': 2, '蠦': 2, '蠨': 2, '蠪': 2, '蠱': 2, '蠳': 2, '蠶': 2, '蠻': 2, '蠾': 2, '衅': 3, '衆': 2, '衊': 2, '術': 2, '衔': 1, '衕': 2, '衚': 2, '衛': 2, '衝': 2, '补': 3, '表': 3, '衬': 1, '衮': 3, '衹': 2, '袄': 3, '袅': 1, '袆': 1, '袜': 3, '袞': 2, '袭': 1, '袯': 1, '装': 1, '裆': 1, '裈': 1, '裊': 2, '裌': 2, '裏': 2, '補': 2, '裝': 2, '裡': 3, '裢': 1, '裣': 1, '裤': 1, '裥': 1, '裲': 2, '製': 2, '複': 2, '褌': 2, '褘': 2, '褛': 1, '褝': 1, '褭': 2, '褲': 2, '褳': 2, '褴': 1, '褸': 2, '褺': 2, '褻': 2, '襀': 2, '襂': 2, '襇': 2, '襌': 2, '襏': 2, '襓': 2, '襕': 1, '襖': 2, '襗': 2, '襘': 2, '襛': 2, '襝': 2, '襠': 2, '襤': 2, '襨': 2, '襪': 2, '襬': 2, '襭': 2, '襯': 2, '襰': 2, '襱': 2, '襲': 2, '襴': 2, '襵': 2, '襸': 2, '襹': 2, '襼': 2, '覆': 3, '見': 2, '覎': 2, '規': 2, '覒': 2, '覓': 2, '覕': 2, '視': 2, '覗': 2, '覘': 2, '覛': 2, '覜': 2, '覟': 2, '覠': 2, '覡': 2, '覢': 2, '覤': 2, '覥': 2, '覦': 2, '覩': 2, '親': 2, '覬': 2, '覭': 2, '覯': 2, '覰': 2, '覲': 2, '覴': 2, '覶': 2, '覷': 2, '覸': 2, '覹': 2, '覺': 2, '覻': 2, '覼': 2, '覽': 2, '覿': 2, '觀': 2, '见': 1, '观': 1, '觃': 1, '规': 1, '觅': 1, '视': 1, '觇': 1, '览': 1, '觉': 1, '觊': 1, '觋': 1, '觌': 1, '觍': 1, '觎': 1, '觏': 1, '觐': 1, '觑': 1, '觞': 1, '触': 1, '觯': 1, '觴': 2, '觶': 2, '觷': 2, '觸': 2, '觹': 2, '觻': 2, '觽': 2, '訁': 2, '訂': 2, '訃': 2, '訆': 2, '計': 2, '訊': 2, '訌': 2, '討': 2, '訏': 2, '訐': 2, '訑': 2, '訒': 2, '訓': 2, '訕': 2, '訖': 2, '託': 2, '記': 2, '訚': 1, '訛': 2, '訜': 2, '訝': 2, '訞': 2, '訟': 2, '訢': 2, '訣': 2, '訥': 2, '訦': 2, '訧': 2, '訨': 2, '訩': 2, '訪': 2, '訬': 2, '設': 2, '訰': 2, '許': 2, '訴': 2, '訶': 2, '訸': 2, '訹': 2, '診': 2, '註': 2, '訽': 2, '詀': 2, '詁': 2, '詃': 2, '詄': 2, '詅': 2, '詆': 2, '詇': 2, '詉': 2, '詊': 2, '詌': 2, '詍': 2, '詎': 2, '詏': 2, '詐': 2, '詑': 2, '詒': 2, '詓': 2, '詔': 2, '評': 2, '詖': 2, '詗': 2, '詘': 2, '詛': 2, '詜': 2, '詝': 2, '詞': 2, '詟': 1, '詠': 2, '詡': 2, '詢': 2, '詣': 2, '詥': 2, '試': 2, '詨': 2, '詩': 2, '詪': 2, '詫': 2, '詬': 2, '詭': 2, '詮': 2, '詯': 2, '詰': 2, '話': 2, '該': 2, '詳': 2, '詴': 2, '詵': 2, '詶': 2, '詷': 2, '詺': 2, '詻': 2, '詼': 2, '詿': 2, '誂': 2, '誃': 2, '誄': 2, '誅': 2, '誆': 2, '誇': 2, '誉': 3, '誊': 1, '誋': 2, '誌': 2, '認': 2, '誎': 2, '誏': 2, '誐': 2, '誑': 2, '誒': 2, '誔': 2, '誕': 2, '誗': 2, '誘': 2, '誙': 2, '誚': 2, '誜': 2, '語': 2, '誠': 2, '誡': 2, '誣': 2, '誤': 2, '誥': 2, '誦': 2, '誧': 2, '誨': 2, '說': 2, '誫': 2, '説': 2, '誰': 2, '課': 2, '誳': 2, '誴': 2, '誶': 2, '誷': 2, '誹': 2, '誺': 2, '誻': 2, '誼': 2, '誽': 2, '誾': 2, '調': 2, '諁': 2, '諂': 2, '諃': 2, '諄': 2, '諆': 2, '談': 2, '諈': 2, '諉': 2, '請': 2, '諌': 2, '諍': 2, '諎': 2, '諏': 2, '諑': 2, '諒': 2, '諓': 2, '諔': 2, '諕': 2, '論': 2, '諗': 2, '諛': 2, '諜': 2, '諝': 2, '諞': 2, '諟': 2, '諠': 2, '諢': 2, '諣': 2, '諤': 2, '諥': 2, '諦': 2, '諧': 2, '諩': 2, '諫': 2, '諭': 2, '諮': 2, '諯': 2, '諰': 2, '諱': 2, '諲': 2, '諳': 2, '諴': 2, '諶': 2, '諷': 2, '諸': 2, '諹': 2, '諺': 2, '諻': 2, '諼': 2, '諾': 2, '謀': 2, '謁': 2, '謂': 2, '謄': 2, '謅': 2, '謆': 2, '謉': 2, '謊': 2, '謋': 2, '謌': 2, '謍': 2, '謎': 2, '謏': 2, '謐': 2, '謑': 2, '謔': 2, '謖': 2, '謗': 2, '謙': 2, '謚': 2, '講': 2, '謜': 2, '謝': 2, '謞': 2, '謟': 2, '謠': 2, '謡': 2, '謣': 2, '謥': 2, '謨': 2, '謫': 2, '謬': 2, '謭': 2, '謯': 2, '謰': 2, '謱': 2, '謲': 2, '謳': 2, '謴': 2, '謵': 2, '謸': 2, '謹': 2, '謻': 2, '謼': 2, '謾': 2, '譀': 2, '譂': 2, '譄': 2, '譅': 2, '譆': 2, '譇': 2, '譈': 2, '證': 2, '譊': 2, '譌': 2, '譎': 2, '譏': 2, '譐': 2, '譑': 2, '譒': 2, '譓': 2, '譔': 2, '譖': 2, '識': 2, '譙': 2, '譚': 2, '譜': 2, '譞': 2, '譟': 2, '譠': 2, '譡': 2, '譨': 2, '譩': 2, '譫': 2, '譯': 2, '議': 2, '譳': 2, '譴': 2, '護': 2, '譸': 2, '譹': 2, '譺': 2, '譻': 2, '譼': 2, '譽': 2, '譾': 2, '譿': 2, '讀': 2, '讂': 2, '讅': 2, '讆': 2, '讇': 2, '讉': 2, '變': 2, '讋': 2, '讌': 2, '讎': 2, '讑': 2, '讒': 2, '讓': 2, '讔': 2, '讕': 2, '讖': 2, '讘': 2, '讙': 2, '讚': 2, '讛': 2, '讜': 2, '讝': 2, '讞': 2, '讟': 2, '讠': 1, '计': 1, '订': 1, '讣': 1, '认': 1, '讥': 1, '讦': 1, '讧': 1, '讨': 1, '让': 1, '讪': 1, '讫': 1, '讬': 1, '训': 1, '议': 1, '讯': 1, '记': 1, '讱': 1, '讲': 1, '讳': 1, '讴': 1, '讵': 1, '讶': 1, '讷': 1, '许': 1, '讹': 1, '论': 1, '讻': 1, '讼': 1, '讽': 1, '设': 1, '访': 1, '诀': 1, '证': 1, '诂': 1, '诃': 1, '评': 1, '诅': 1, '识': 1, '诇': 1, '诈': 1, '诉': 1, '诊': 1, '诋': 1, '诌': 1, '词': 1, '诎': 1, '诏': 1, '诐': 1, '译': 1, '诒': 1, '诓': 1, '诔': 1, '试': 1, '诖': 1, '诗': 1, '诘': 1, '诙': 1, '诚': 1, '诛': 1, '诜': 1, '话': 1, '诞': 1, '诟': 1, '诠': 1, '诡': 1, '询': 1, '诣': 1, '诤': 1, '该': 1, '详': 1, '诧': 1, '诨': 1, '诩': 1, '诪': 1, '诫': 1, '诬': 1, '语': 1, '诮': 1, '误': 1, '诰': 1, '诱': 1, '诲': 1, '诳': 1, '说': 1, '诵': 1, '诶': 1, '请': 1, '诸': 1, '诹': 1, '诺': 1, '读': 1, '诼': 1, '诽': 1, '课': 1, '诿': 1, '谀': 1, '谁': 1, '谂': 1, '调': 1, '谄': 1, '谅': 1, '谆': 1, '谇': 1, '谈': 1, '谉': 1, '谊': 1, '谋': 1, '谌': 1, '谍': 1, '谎': 1, '谏': 1, '谐': 1, '谑': 1, '谒': 1, '谓': 1, '谔': 1, '谕': 1, '谖': 1, '谗': 1, '谘': 1, '谙': 1, '谚': 1, '谛': 1, '谜': 1, '谝': 1, '谞': 1, '谟': 1, '谠': 1, '谡': 1, '谢': 1, '谣': 1, '谤': 1, '谥': 1, '谦': 1, '谧': 1, '谨': 1, '谩': 1, '谪': 1, '谫': 1, '谬': 1, '谭': 1, '谮': 1, '谯': 1, '谰': 1, '谱': 1, '谲': 1, '谳': 1, '谴': 1, '谵': 1, '谶': 1, '谷': 3, '豄': 2, '豅': 2, '豈': 2, '豎': 2, '豐': 2, '豬': 2, '豮': 1, '豵': 2, '豶': 2, '貓': 2, '貗': 2, '貙': 2, '貝': 2, '貞': 2, '貟': 2, '負': 2, '財': 2, '貢': 2, '貣': 2, '貤': 2, '貦': 2, '貧': 2, '貨': 2, '販': 2, '貪': 2, '貫': 2, '責': 2, '貯': 2, '貰': 2, '貱': 2, '貲': 2, '貳': 2, '貴': 2, '貶': 2, '買': 2, '貸': 2, '貺': 2, '費': 2, '貼': 2, '貽': 2, '貾': 2, '貿': 2, '賀': 2, '賁': 2, '賂': 2, '賃': 2, '賄': 2, '賅': 2, '資': 2, '賈': 2, '賊': 2, '賑': 2, '賒': 2, '賓': 2, '賕': 2, '賗': 2, '賙': 2, '賚': 2, '賜': 2, '賝': 2, '賞': 2, '賟': 2, '賠': 2, '賡': 2, '賢': 2, '賣': 2, '賤': 2, '賥': 2, '賦': 2, '賧': 2, '賨': 2, '質': 2, '賫': 2, '賬': 2, '賭': 2, '賮': 2, '賰': 2, '賴': 2, '賵': 2, '賶': 2, '賸': 2, '賹': 2, '賺': 2, '賻': 2, '購': 2, '賽': 2, '賾': 2, '贃': 2, '贄': 2, '贅': 2, '贆': 2, '贇': 2, '贈': 2, '贉': 2, '贊': 2, '贋': 2, '贍': 2, '贏': 2, '贐': 2, '贑': 2, '贓': 2, '贔': 2, '贕': 2, '贖': 2, '贗': 2, '贙': 2, '贚': 2, '贛': 2, '贜': 2, '贝': 1, '贞': 1, '负': 1, '贠': 1, '贡': 1, '财': 1, '责': 1, '贤': 1, '败': 1, '账': 1, '货': 1, '质': 1, '贩': 1, '贪': 1, '贫': 1, '贬': 1, '购': 1, '贮': 1, '贯': 1, '贰': 1, '贱': 1, '贲': 1, '贳': 1, '贴': 1, '贵': 1, '贶': 1, '贷': 1, '贸': 1, '费': 1, '贺': 1, '贻': 1, '贼': 1, '贽': 1, '贾': 1, '贿': 1, '赀': 1, '赁': 1, '赂': 1, '赃': 1, '资': 1, '赅': 1, '赆': 1, '赇': 1, '赈': 1, '赉': 1, '赊': 1, '赋': 1, '赌': 1, '赍': 1, '赎': 1, '赏': 1, '赐': 1, '赑': 1, '赒': 1, '赓': 1, '赔': 1, '赕': 1, '赖': 1, '赗': 1, '赘': 1, '赙': 1, '赚': 1, '赛': 1, '赜': 1, '赝': 1, '赞': 1, '赟': 1, '赠': 1, '赡': 1, '赢': 1, '赣': 1, '赪': 1, '赬': 2, '赵': 1, '赶': 3, '趋': 3, '趕': 2, '趙': 2, '趨': 2, '趫': 2, '趬': 2, '趱': 1, '趲': 2, '趸': 1, '跃': 1, '跄': 1, '跞': 1, '跡': 2, '践': 1, '跶': 1, '跷': 1, '跸': 1, '跹': 1, '跻': 1, '踊': 3, '踌': 1, '踐': 2, '踚': 2, '踪': 3, '踬': 1, '踯': 1, '踴': 2, '蹌': 2, '蹑': 1, '蹒': 1, '蹔': 2, '蹕': 2, '蹛': 2, '蹡': 2, '蹣': 2, '蹤': 2, '蹥': 2, '蹪': 2, '蹰': 3, '蹳': 2, '蹺': 2, '蹻': 2, '蹿': 1, '躀': 2, '躂': 2, '躉': 2, '躊': 2, '躋': 2, '躍': 2, '躎': 2, '躏': 1, '躑': 2, '躒': 2, '躓': 2, '躕': 2, '躘': 2, '躚': 2, '躜': 1, '躝': 2, '躡': 2, '躥': 2, '躦': 2, '躧': 2, '躪': 2, '躯': 3, '軀': 2, '軂': 2, '軃': 2, '軇': 2, '軉': 2, '車': 2, '軋': 2, '軌': 2, '軍': 2, '軎': 2, '軏': 2, '軑': 2, '軒': 2, '軓': 2, '軔': 2, '軕': 2, '軖': 2, '軗': 2, '軘': 2, '軚': 2, '軛': 2, '軜': 2, '軝': 2, '軞': 2, '軟': 2, '軤': 2, '軥': 2, '軧': 2, '軨': 2, '軫': 2, '軬': 2, '軮': 2, '軯': 2, '軱': 2, '軲': 2, '軳': 2, '軵': 2, '軷': 2, '軸': 2, '軹': 2, '軺': 2, '軻': 2, '軼': 2, '軾': 2, '軿': 2, '輀': 2, '輁': 2, '輂': 2, '較': 2, '輄': 2, '輅': 2, '輆': 2, '輇': 2, '輈': 2, '載': 2, '輊': 2, '輋': 2, '輐': 2, '輑': 2, '輒': 2, '輓': 2, '輔': 2, '輕': 2, '輖': 2, '輗': 2, '輘': 2, '輙': 2, '輚': 2, '輛': 2, '輜': 2, '輝': 2, '輞': 2, '輟': 2, '輠': 2, '輡': 2, '輢': 2, '輣': 2, '輤': 2, '輥': 2, '輦': 2, '輨': 2, '輩': 2, '輪': 2, '輫': 2, '輬': 2, '輮': 2, '輯': 2, '輲': 2, '輳': 2, '輴': 2, '輵': 2, '輶': 2, '輷': 2, '輸': 2, '輹': 2, '輻': 2, '輼': 2, '輾': 2, '輿': 2, '轀': 2, '轁': 2, '轂': 2, '轃': 2, '轄': 2, '轅': 2, '轆': 2, '轇': 2, '轈': 2, '轉': 2, '轊': 2, '轍': 2, '轎': 2, '轏': 2, '轐': 2, '轑': 2, '轒': 2, '轓': 2, '轔': 2, '轕': 2, '轖': 2, '轗': 2, '轘': 2, '轙': 2, '轚': 2, '轛': 2, '轝': 2, '轞': 2, '轟': 2, '轠': 2, '轡': 2, '轢': 2, '轣': 2, '轤': 2, '轥': 2, '车': 1, '轧': 1, '轨': 1, '轩': 1, '轪': 1, '轫': 1, '转': 1, '轭': 1, '轮': 1, '软': 1, '轰': 1, '轱': 1, '轲': 1, '轳': 1, '轴': 1, '轵': 1, '轶': 1, '轷': 1, '轸': 1, '轹': 1, '轺': 1, '轻': 1, '轼': 1, '载': 1, '轾': 1, '轿': 1, '辀': 1, '辁': 1, '辂': 1, '较': 1, '辄': 1, '辅': 1, '辆': 1, '辇': 1, '辈': 1, '辉': 1, '辊': 1, '辋': 1, '辌': 1, '辍': 1, '辎': 1, '辏': 1, '辐': 1, '辑': 1, '辒': 1, '输': 1, '辔': 1, '辕': 1, '辖': 1, '辗': 1, '辘': 1, '辙': 1, '辚': 1, '辞': 3, '辟': 3, '辦': 2, '辩': 1, '辫': 1, '辭': 2, '辮': 2, '辯': 2, '農': 2, '边': 3, '辽': 1, '达': 1, '迁': 3, '过': 3, '迈': 1, '运': 1, '还': 3, '这': 3, '进': 1, '远': 3, '违': 1, '连': 1, '迟': 1, '迩': 3, '迳': 1, '迴': 2, '迹': 3, '适': 3, '选': 3, '逊': 3, '递': 3, '逕': 2, '這': 2, '連': 2, '逦': 1, '進': 2, '逻': 3, '逿': 2, '運': 2, '過': 2, '達': 2, '違': 2, '遗': 1, '遙': 2, '遜': 2, '遞': 2, '遠': 2, '遥': 1, '適': 2, '遰': 2, '遱': 2, '遲': 2, '遶': 2, '遷': 2, '選': 2, '遺': 2, '遼': 2, '邁': 2, '還': 2, '邇': 2, '邊': 2, '邏': 2, '邐': 2, '邓': 1, '邝': 1, '邬': 1, '邮': 1, '邹': 1, '邺': 1, '邻': 1, '郁': 3, '郏': 1, '郐': 1, '郑': 3, '郓': 1, '郟': 2, '郦': 1, '郧': 1, '郲': 2, '郵': 2, '郸': 1, '鄆': 2, '鄉': 2, '鄒': 2, '鄔': 2, '鄖': 2, '鄟': 2, '鄡': 2, '鄦': 2, '鄧': 2, '鄩': 2, '鄪': 2, '鄬': 2, '鄭': 2, '鄮': 2, '鄰': 2, '鄲': 2, '鄳': 2, '鄴': 2, '鄶': 2, '鄺': 2, '酂': 1, '酇': 2, '酈': 2, '酝': 1, '酦': 1, '酱': 1, '酽': 1, '酾': 1, '酿': 1, '醆': 2, '醖': 2, '醜': 2, '醞': 2, '醦': 2, '醧': 2, '醫': 2, '醬': 2, '醱': 2, '醲': 2, '醳': 2, '醶': 2, '釀': 2, '釁': 2, '釃': 2, '釅': 2, '采': 3, '释': 1, '釋': 2, '里': 3, '釐': 2, '釒': 2, '釓': 2, '釔': 2, '釕': 2, '釗': 2, '釘': 2, '釙': 2, '釚': 2, '釛': 2, '針': 2, '釟': 2, '釣': 2, '釤': 2, '釥': 2, '釦': 2, '釧': 2, '釨': 2, '釩': 2, '釪': 2, '釫': 2, '釬': 2, '釭': 2, '釱': 2, '釲': 2, '釳': 2, '釴': 2, '釵': 2, '釷': 2, '釹': 2, '釺': 2, '釽': 2, '釾': 2, '釿': 2, '鈀': 2, '鈁': 2, '鈂': 2, '鈃': 2, '鈄': 2, '鈆': 2, '鈇': 2, '鈈': 2, '鈉': 2, '鈋': 2, '鈍': 2, '鈎': 2, '鈏': 2, '鈐': 2, '鈑': 2, '鈒': 2, '鈓': 2, '鈔': 2, '鈕': 2, '鈖': 2, '鈗': 2, '鈚': 2, '鈛': 2, '鈜': 2, '鈞': 2, '鈠': 2, '鈣': 2, '鈤': 2, '鈥': 2, '鈦': 2, '鈧': 2, '鈨': 2, '鈪': 2, '鈮': 2, '鈯': 2, '鈰': 2, '鈲': 2, '鈳': 2, '鈴': 2, '鈵': 2, '鈶': 2, '鈷': 2, '鈸': 2, '鈹': 2, '鈺': 2, '鈼': 2, '鈽': 2, '鈾': 2, '鈿': 2, '鉀': 2, '鉁': 2, '鉅': 2, '鉈': 2, '鉉': 2, '鉊': 2, '鉋': 2, '鉌': 2, '鉍': 2, '鉎': 2, '鉏': 2, '鉐': 2, '鉑': 2, '鉒': 2, '鉔': 2, '鉕': 2, '鉗': 2, '鉘': 2, '鉙': 2, '鉚': 2, '鉛': 2, '鉜': 2, '鉝': 2, '鉞': 2, '鉟': 2, '鉠': 2, '鉡': 2, '鉢': 2, '鉤': 2, '鉥': 2, '鉦': 2, '鉧': 2, '鉨': 2, '鉬': 2, '鉭': 2, '鉮': 2, '鉲': 2, '鉴': 1, '鉵': 2, '鉶': 2, '鉷': 2, '鉸': 2, '鉹': 2, '鉺': 2, '鉻': 2, '鉼': 2, '鉽': 2, '鉾': 2, '鉿': 2, '銀': 2, '銁': 2, '銂': 2, '銃': 2, '銅': 2, '銈': 2, '銊': 2, '銋': 2, '銍': 2, '銏': 2, '銑': 2, '銓': 2, '銔': 2, '銖': 2, '銗': 2, '銘': 2, '銙': 2, '銚': 2, '銛': 2, '銜': 2, '銠': 2, '銡': 2, '銣': 2, '銥': 2, '銦': 2, '銧': 2, '銨': 2, '銩': 2, '銪': 2, '銫': 2, '銬': 2, '銮': 3, '銱': 2, '銲': 2, '銳': 2, '銶': 2, '銷': 2, '銸': 2, '銹': 2, '銻': 2, '銼': 2, '銾': 2, '鋁': 2, '鋂': 2, '鋃': 2, '鋅': 2, '鋇': 2, '鋉': 2, '鋊': 2, '鋋': 2, '鋌': 2, '鋍': 2, '鋏': 2, '鋐': 2, '鋑': 2, '鋒': 2, '鋓': 2, '鋗': 2, '鋘': 2, '鋙': 2, '鋜': 2, '鋝': 2, '鋟': 2, '鋠': 2, '鋡': 2, '鋣': 2, '鋤': 2, '鋥': 2, '鋦': 2, '鋧': 2, '鋨': 2, '鋩': 2, '鋪': 2, '鋭': 2, '鋮': 2, '鋯': 2, '鋰': 2, '鋱': 2, '鋶': 2, '鋸': 2, '鋹': 2, '鋼': 2, '鋾': 2, '錀': 2, '錁': 2, '錂': 2, '錄': 2, '錆': 2, '錇': 2, '錈': 2, '錋': 2, '錍': 2, '錏': 2, '錐': 2, '錑': 2, '錒': 2, '錔': 2, '錕': 2, '錗': 2, '錘': 2, '錙': 2, '錚': 2, '錛': 2, '錜': 2, '錝': 2, '錞': 2, '錟': 2, '錠': 2, '錡': 2, '錢': 2, '錣': 2, '錤': 2, '錥': 2, '錦': 2, '錧': 2, '錨': 2, '錩': 2, '錪': 2, '錫': 2, '錭': 2, '錮': 2, '錯': 2, '録': 2, '錳': 2, '錶': 2, '錸': 2, '錺': 2, '錽': 2, '錾': 1, '鍀': 2, '鍁': 2, '鍂': 2, '鍃': 2, '鍄': 2, '鍆': 2, '鍇': 2, '鍈': 2, '鍉': 2, '鍊': 2, '鍋': 2, '鍍': 2, '鍏': 2, '鍐': 2, '鍑': 2, '鍒': 2, '鍔': 2, '鍕': 2, '鍖': 2, '鍘': 2, '鍚': 2, '鍛': 2, '鍜': 2, '鍝': 2, '鍟': 2, '鍠': 2, '鍡': 2, '鍢': 2, '鍣': 2, '鍤': 2, '鍥': 2, '鍦': 2, '鍧': 2, '鍨': 2, '鍩': 2, '鍬': 2, '鍭': 2, '鍮': 2, '鍯': 2, '鍰': 2, '鍱': 2, '鍴': 2, '鍵': 2, '鍶': 2, '鍺': 2, '鍼': 2, '鍾': 2, '鎂': 2, '鎄': 2, '鎅': 2, '鎇': 2, '鎈': 2, '鎉': 2, '鎊': 2, '鎋': 2, '鎌': 2, '鎍': 2, '鎑': 2, '鎒': 2, '鎓': 2, '鎔': 2, '鎕': 2, '鎖': 2, '鎗': 2, '鎘': 2, '鎙': 2, '鎚': 2, '鎛': 2, '鎝': 2, '鎞': 2, '鎡': 2, '鎢': 2, '鎣': 2, '鎦': 2, '鎧': 2, '鎩': 2, '鎪': 2, '鎬': 2, '鎮': 2, '鎯': 2, '鎰': 2, '鎲': 2, '鎳': 2, '鎵': 2, '鎶': 2, '鎷': 2, '鎸': 2, '鎿': 2, '鏁': 2, '鏂': 2, '鏃': 2, '鏆': 2, '鏇': 2, '鏈': 2, '鏉': 2, '鏌': 2, '鏍': 2, '鏏': 2, '鏐': 2, '鏑': 2, '鏒': 2, '鏓': 2, '鏔': 2, '鏕': 2, '鏗': 2, '鏘': 2, '鏙': 2, '鏚': 2, '鏛': 2, '鏜': 2, '鏝': 2, '鏞': 2, '鏟': 2, '鏡': 2, '鏢': 2, '鏤': 2, '鏥': 2, '鏦': 2, '鏨': 2, '鏩': 2, '鏰': 2, '鏵': 2, '鏷': 2, '鏸': 2, '鏹': 2, '鏺': 2, '鏻': 2, '鏽': 2, '鏾': 2, '鐀': 2, '鐁': 2, '鐃': 2, '鐄': 2, '鐇': 2, '鐈': 2, '鐉': 2, '鐊': 2, '鐋': 2, '鐍': 2, '鐎': 2, '鐏': 2, '鐐': 2, '鐒': 2, '鐓': 2, '鐔': 2, '鐕': 2, '鐖': 2, '鐘': 2, '鐙': 2, '鐚': 2, '鐝': 2, '鐠': 2, '鐤': 2, '鐥': 2, '鐦': 2, '鐧': 2, '鐨': 2, '鐩': 2, '鐪': 2, '鐫': 2, '鐬': 2, '鐮': 2, '鐯': 2, '鐲': 2, '鐳': 2, '鐴': 2, '鐵': 2, '鐶': 2, '鐸': 2, '鐹': 2, '鐺': 2, '鐼': 2, '鐽': 2, '鐿': 2, '鑀': 2, '鑄': 2, '鑇': 2, '鑈': 2, '鑉': 2, '鑊': 2, '鑋': 2, '鑌': 2, '鑏': 2, '鑐': 2, '鑑': 2, '鑒': 2, '鑔': 2, '鑕': 2, '鑖': 2, '鑘': 2, '鑙': 2, '鑛': 2, '鑞': 2, '鑠': 2, '鑡': 2, '鑢': 2, '鑣': 2, '鑥': 2, '鑧': 2, '鑨': 2, '鑪': 2, '鑭': 2, '鑮': 2, '鑯': 2, '鑰': 2, '鑱': 2, '鑲': 2, '鑴': 2, '鑷': 2, '鑸': 2, '鑹': 2, '鑼': 2, '鑽': 2, '鑾': 2, '鑿': 2, '钀': 2, '钁': 2, '钂': 2, '钃': 2, '钅': 1, '钆': 1, '钇': 1, '针': 1, '钉': 1, '钊': 1, '钋': 1, '钌': 1, '钍': 1, '钎': 1, '钏': 1, '钐': 1, '钑': 1, '钒': 1, '钓': 1, '钔': 1, '钕': 1, '钖': 1, '钗': 1, '钘': 1, '钙': 1, '钚': 1, '钛': 1, '钜': 1, '钝': 1, '钞': 1, '钟': 1, '钠': 1, '钡': 1, '钢': 1, '钣': 1, '钤': 1, '钥': 1, '钦': 1, '钧': 1, '钨': 1, '钩': 1, '钪': 1, '钫': 1, '钬': 1, '钭': 1, '钮': 1, '钯': 1, '钰': 1, '钱': 1, '钲': 1, '钳': 1, '钴': 1, '钵': 1, '钶': 1, '钷': 1, '钸': 1, '钹': 1, '钺': 1, '钻': 1, '钼': 1, '钽': 1, '钾': 1, '钿': 1, '铀': 1, '铁': 1, '铂': 1, '铃': 1, '铄': 1, '铅': 1, '铆': 1, '铇': 1, '铈': 1, '铉': 1, '铊': 1, '铋': 1, '铌': 1, '铍': 1, '铎': 1, '铏': 1, '铐': 1, '铑': 1, '铒': 1, '铓': 1, '铔': 1, '铕': 1, '铖': 1, '铗': 1, '铘': 1, '铙': 1, '铚': 1, '铛': 1, '铜': 1, '铝': 1, '铞': 1, '铟': 1, '铠': 1, '铡': 1, '铢': 1, '铣': 1, '铤': 1, '铥': 1, '铦': 1, '铧': 1, '铨': 1, '铩': 1, '铪': 1, '铫': 1, '铬': 1, '铭': 1, '铮': 1, '铯': 1, '铰': 1, '铱': 1, '铲': 1, '铳': 1, '铴': 1, '铵': 1, '银': 1, '铷': 1, '铸': 1, '铹': 1, '铺': 1, '铻': 1, '铼': 1, '铽': 1, '链': 1, '铿': 1, '销': 1, '锁': 1, '锂': 1, '锃': 1, '锄': 1, '锅': 1, '锆': 1, '锇': 1, '锈': 1, '锉': 1, '锊': 1, '锋': 1, '锌': 1, '锍': 1, '锎': 1, '锏': 1, '锐': 1, '锑': 1, '锒': 1, '锓': 1, '锔': 1, '锕': 1, '锖': 1, '锗': 1, '锘': 1, '错': 1, '锚': 1, '锛': 1, '锜': 1, '锝': 1, '锞': 1, '锟': 1, '锠': 1, '锡': 1, '锢': 1, '锣': 1, '锤': 1, '锥': 1, '锦': 1, '锧': 1, '锨': 1, '锩': 1, '锪': 1, '锫': 1, '锬': 1, '锭': 1, '键': 1, '锯': 1, '锰': 1, '锱': 1, '锲': 1, '锳': 1, '锴': 1, '锵': 1, '锶': 1, '锷': 1, '锸': 1, '锹': 1, '锺': 1, '锻': 1, '锼': 1, '锽': 1, '锾': 1, '锿': 1, '镀': 1, '镁': 1, '镂': 1, '镃': 1, '镄': 1, '镅': 1, '镆': 1, '镇': 1, '镈': 1, '镉': 1, '镊': 1, '镋': 1, '镌': 1, '镍': 1, '镎': 1, '镏': 1, '镐': 1, '镑': 1, '镒': 1, '镓': 1, '镔': 1, '镕': 1, '镖': 1, '镗': 1, '镘': 1, '镙': 1, '镚': 1, '镛': 1, '镜': 1, '镝': 1, '镞': 1, '镟': 1, '镠': 1, '镡': 1, '镢': 1, '镣': 1, '镤': 1, '镥': 1, '镦': 1, '镧': 1, '镨': 1, '镩': 1, '镪': 1, '镫': 1, '镬': 1, '镭': 1, '镮': 1, '镯': 1, '镰': 1, '镱': 1, '镲': 1, '镳': 1, '镴': 1, '镵': 1, '镶': 1, '長': 2, '长': 1, '門': 2, '閂': 2, '閃': 2, '閄': 2, '閅': 2, '閆': 2, '閈': 2, '閉': 2, '開': 2, '閌': 2, '閍': 2, '閎': 2, '閏': 2, '閐': 2, '閑': 2, '閒': 2, '間': 2, '閔': 2, '閕': 2, '閗': 2, '閘': 2, '閛': 2, '閜': 2, '閝': 2, '閞': 2, '閟': 2, '閡': 2, '閣': 2, '閤': 2, '閥': 2, '閦': 2, '閧': 2, '閨': 2, '閩': 2, '閫': 2, '閬': 2, '閭': 2, '閯': 2, '閱': 2, '閲': 2, '閵': 2, '閶': 2, '閷': 2, '閹': 2, '閻': 2, '閼': 2, '閽': 2, '閾': 2, '閿': 2, '闃': 2, '闄': 2, '闆': 2, '闇': 2, '闈': 2, '闉': 2, '闊': 2, '闋': 2, '闌': 2, '闍': 2, '闐': 2, '闑': 2, '闒': 2, '闓': 2, '闔': 2, '闕': 2, '闖': 2, '闚': 2, '闛': 2, '關': 2, '闞': 2, '闟': 2, '闠': 2, '闡': 2, '闢': 2, '闤': 2, '闥': 2, '门': 1, '闩': 1, '闪': 1, '闫': 1, '闬': 1, '闭': 1, '问': 1, '闯': 1, '闰': 1, '闱': 1, '闲': 1, '闳': 1, '间': 1, '闵': 1, '闶': 1, '闷': 1, '闸': 1, '闹': 1, '闺': 1, '闻': 1, '闼': 1, '闽': 1, '闾': 1, '闿': 1, '阀': 1, '阁': 1, '阂': 1, '阃': 1, '阄': 1, '阅': 1, '阆': 1, '阇': 1, '阈': 1, '阉': 1, '阊': 1, '阋': 1, '阌': 1, '阍': 1, '阎': 1, '阏': 1, '阐': 1, '阑': 1, '阒': 1, '阓': 1, '阔': 1, '阕': 1, '阖': 1, '阗': 1, '阘': 1, '阙': 1, '阚': 1, '阛': 1, '队': 1, '阪': 2, '阳': 1, '阴': 1, '阵': 1, '阶': 1, '际': 3, '陆': 1, '陇': 1, '陈': 1, '陉': 1, '陕': 1, '陘': 2, '陝': 2, '陣': 2, '陦': 1, '陧': 1, '陨': 1, '险': 1, '陰': 2, '陳': 2, '陸': 2, '陽': 2, '陿': 2, '隉': 2, '隊': 2, '階': 2, '随': 3, '隐': 3, '隑': 2, '隕': 2, '隖': 2, '際': 2, '隤': 2, '隨': 2, '險': 2, '隫': 2, '隮': 2, '隯': 2, '隱': 2, '隲': 2, '隴': 2, '隶': 3, '隸': 2, '隻': 2, '隽': 3, '难': 3, '雋': 2, '雏': 1, '雖': 2, '雙': 2, '雛': 2, '雜': 2, '雞': 2, '雠': 1, '離': 2, '難': 2, '雲': 2, '雳': 1, '電': 2, '雾': 1, '霁': 1, '霉': 3, '霡': 3, '霢': 2, '霣': 2, '霧': 2, '霭': 1, '霼': 2, '霽': 2, '靂': 2, '靄': 2, '靅': 2, '靆': 2, '靈': 2, '靉': 2, '靓': 1, '静': 3, '靚': 2, '靜': 2, '面': 3, '靥': 1, '靦': 2, '靧': 2, '靨': 2, '鞀': 2, '鞏': 2, '鞑': 1, '鞒': 1, '鞝': 2, '鞦': 2, '鞯': 1, '鞸': 2, '鞻': 2, '鞼': 2, '鞽': 2, '鞾': 2, '韁': 2, '韃': 2, '韆': 2, '韇': 2, '韉': 2, '韊': 2, '韋': 2, '韌': 2, '韍': 2, '韏': 2, '韐': 2, '韒': 2, '韓': 2, '韔': 2, '韗': 2, '韘': 2, '韙': 2, '韚': 2, '韛': 2, '韜': 2, '韝': 2, '韞': 2, '韠': 2, '韡': 2, '韢': 2, '韣': 2, '韦': 1, '韧': 1, '韨': 1, '韩': 1, '韪': 1, '韫': 1, '韬': 1, '韵': 3, '韻': 2, '響': 2, '頁': 2, '頂': 2, '頃': 2, '頄': 2, '項': 2, '順': 2, '頇': 2, '須': 2, '頊': 2, '頌': 2, '頍': 2, '頎': 2, '頏': 2, '預': 2, '頑': 2, '頒': 2, '頓': 2, '頔': 2, '頕': 2, '頖': 2, '頗': 2, '領': 2, '頛': 2, '頜': 2, '頞': 2, '頟': 2, '頠': 2, '頡': 2, '頢': 2, '頤': 2, '頦': 2, '頩': 2, '頪': 2, '頫': 2, '頭': 2, '頮': 2, '頯': 2, '頰': 2, '頲': 2, '頴': 2, '頵': 2, '頷': 2, '頸': 2, '頹': 2, '頻': 2, '頽': 2, '顀': 2, '顁': 2, '顃': 2, '顄': 2, '顅': 2, '顆': 2, '顇': 2, '顉': 2, '顊': 2, '顋': 2, '題': 2, '額': 2, '顎': 2, '顏': 2, '顐': 2, '顑': 2, '顒': 2, '顓': 2, '顔': 2, '顖': 2, '顗': 2, '願': 2, '顙': 2, '顛': 2, '顜': 2, '顝': 2, '類': 2, '顠': 2, '顢': 2, '顣': 2, '顤': 2, '顥': 2, '顦': 2, '顧': 2, '顩': 2, '顪': 2, '顫': 2, '顬': 2, '顮': 2, '顯': 2, '顰': 2, '顱': 2, '顳': 2, '顴': 2, '页': 1, '顶': 1, '顷': 1, '顸': 1, '项': 1, '顺': 1, '须': 1, '顼': 1, '顽': 1, '顾': 1, '顿': 1, '颀': 1, '颁': 1, '颂': 1, '颃': 1, '预': 1, '颅': 1, '领': 1, '颇': 1, '颈': 1, '颉': 1, '颊': 1, '颋': 1, '颌': 1, '颍': 1, '颎': 1, '颏': 1, '颐': 1, '频': 1, '颒': 1, '颓': 1, '颔': 1, '颕': 1, '颖': 1, '颗': 1, '题': 1, '颙': 1, '颚': 1, '颛': 1, '颜': 1, '额': 1, '颞': 1, '颟': 1, '颠': 1, '颡': 1, '颢': 1, '颣': 1, '颤': 1, '颥': 1, '颦': 1, '颧': 1, '風': 2, '颩': 2, '颬': 2, '颭': 2, '颮': 2, '颯': 2, '颰': 2, '颱': 2, '颲': 2, '颳': 2, '颴': 2, '颶': 2, '颷': 2, '颸': 2, '颹': 2, '颺': 2, '颻': 2, '颼': 2, '颽': 2, '颾': 2, '颿': 2, '飀': 2, '飁': 2, '飂': 2, '飄': 2, '飆': 2, '飇': 2, '飈': 2, '飉': 2, '飊': 2, '飋': 2, '飍': 2, '风': 3, '飏': 1, '飐': 1, '飑': 1, '飒': 1, '飓': 1, '飔': 1, '飕': 1, '飖': 1, '飗': 1, '飘': 1, '飙': 1, '飚': 1, '飛': 2, '飝': 2, '飞': 1, '飠': 2, '飢': 2, '飣': 2, '飤': 2, '飥': 2, '飦': 2, '飨': 1, '飩': 2, '飪': 2, '飫': 2, '飭': 2, '飯': 2, '飰': 2, '飲': 2, '飴': 2, '飵': 2, '飶': 2, '飷': 2, '飼': 2, '飽': 2, '飾': 2, '飿': 2, '餀': 2, '餂': 2, '餃': 2, '餄': 2, '餅': 2, '餉': 2, '養': 2, '餌': 2, '餍': 1, '餎': 2, '餏': 2, '餑': 2, '餒': 2, '餓': 2, '餔': 2, '餕': 2, '餖': 2, '餗': 2, '餘': 2, '餚': 2, '餛': 2, '餜': 2, '餞': 2, '餟': 2, '餡': 2, '餢': 2, '餣': 2, '餤': 2, '餦': 2, '餧': 2, '館': 2, '餩': 2, '餪': 2, '餫': 2, '餬': 2, '餭': 2, '餯': 2, '餰': 2, '餱': 2, '餲': 2, '餳': 2, '餴': 2, '餵': 2, '餶': 2, '餷': 2, '餸': 2, '餹': 2, '餺': 2, '餼': 2, '餾': 2, '餿': 2, '饀': 2, '饁': 2, '饃': 2, '饅': 2, '饆': 2, '饇': 2, '饈': 2, '饉': 2, '饊': 2, '饋': 2, '饌': 2, '饎': 2, '饐': 2, '饑': 2, '饒': 2, '饗': 2, '饘': 2, '饙': 2, '饛': 2, '饜': 2, '饞': 2, '饟': 2, '饠': 2, '饡': 2, '饢': 2, '饣': 1, '饤': 1, '饥': 1, '饦': 1, '饧': 1, '饨': 1, '饩': 1, '饪': 1, '饫': 1, '饬': 1, '饭': 1, '饮': 1, '饯': 1, '饰': 1, '饱': 1, '饲': 1, '饳': 1, '饴': 1, '饵': 1, '饶': 1, '饷': 1, '饸': 1, '饹': 1, '饺': 1, '饻': 1, '饼': 1, '饽': 1, '饾': 1, '饿': 1, '馀': 1, '馁': 1, '馂': 1, '馃': 1, '馄': 1, '馅': 1, '馆': 1, '馇': 1, '馈': 1, '馉': 1, '馊': 1, '馋': 1, '馌': 1, '馍': 1, '馎': 1, '馏': 1, '馐': 1, '馑': 1, '馒': 1, '馓': 1, '馔': 1, '馕': 1, '馩': 2, '馪': 2, '馬': 2, '馭': 2, '馮': 2, '馯': 2, '馱': 2, '馲': 2, '馳': 2, '馴': 2, '馵': 2, '馹': 2, '馺': 2, '馼': 2, '馽': 2, '駁': 2, '駂': 2, '駃': 2, '駉': 2, '駊': 2, '駍': 2, '駎': 2, '駏': 2, '駐': 2, '駑': 2, '駒': 2, '駓': 2, '駔': 2, '駕': 2, '駗': 2, '駘': 2, '駙': 2, '駚': 2, '駛': 2, '駜': 2, '駝': 2, '駞': 2, '駟': 2, '駡': 2, '駢': 2, '駣': 2, '駤': 2, '駥': 2, '駧': 2, '駩': 2, '駪': 2, '駫': 2, '駬': 2, '駭': 2, '駮': 2, '駰': 2, '駱': 2, '駴': 2, '駶': 2, '駷': 2, '駸': 2, '駹': 2, '駺': 2, '駻': 2, '駼': 2, '駽': 2, '駾': 2, '駿': 2, '騀': 2, '騁': 2, '騂': 2, '騃': 2, '騄': 2, '騅': 2, '騆': 2, '騇': 2, '騉': 2, '騊': 2, '騋': 2, '騌': 2, '騍': 2, '騎': 2, '騏': 2, '騑': 2, '騔': 2, '騕': 2, '騖': 2, '騗': 2, '騙': 2, '騚': 2, '騛': 2, '騜': 2, '騝': 2, '騞': 2, '騟': 2, '騠': 2, '騢': 2, '騣': 2, '騤': 2, '騥': 2, '騧': 2, '騩': 2, '騪': 2, '騫': 2, '騬': 2, '騭': 2, '騮': 2, '騯': 2, '騰': 2, '騱': 2, '騲': 2, '騳': 2, '騴': 2, '騵': 2, '騶': 2, '騷': 2, '騸': 2, '騹': 2, '騺': 2, '騻': 2, '騼': 2, '騽': 2, '騾': 2, '驀': 2, '驁': 2, '驂': 2, '驃': 2, '驄': 2, '驅': 2, '驈': 2, '驉': 2, '驊': 2, '驋': 2, '驌': 2, '驍': 2, '驎': 2, '驏': 2, '驐': 2, '驒': 2, '驓': 2, '驔': 2, '驕': 2, '驖': 2, '驗': 2, '驙': 2, '驚': 2, '驛': 2, '驞': 2, '驟': 2, '驠': 2, '驡': 2, '驢': 2, '驤': 2, '驥': 2, '驦': 2, '驨': 2, '驩': 2, '驪': 2, '驫': 2, '马': 1, '驭': 1, '驮': 1, '驯': 1, '驰': 1, '驱': 1, '驲': 1, '驳': 1, '驴': 1, '驵': 1, '驶': 1, '驷': 1, '驸': 1, '驹': 1, '驺': 1, '驻': 1, '驼': 1, '驽': 1, '驾': 1, '驿': 1, '骀': 1, '骁': 1, '骂': 1, '骃': 1, '骄': 1, '骅': 1, '骆': 1, '骇': 1, '骈': 1, '骉': 1, '骊': 1, '骋': 1, '验': 1, '骍': 1, '骎': 1, '骏': 1, '骐': 1, '骑': 1, '骒': 1, '骓': 1, '骔': 1, '骕': 1, '骖': 1, '骗': 1, '骘': 1, '骙': 1, '骚': 1, '骛': 1, '骜': 1, '骝': 1, '骞': 1, '骟': 1, '骠': 1, '骡': 1, '骢': 1, '骣': 1, '骤': 1, '骥': 1, '骦': 1, '骧': 1, '骯': 2, '髅': 1, '髋': 1, '髌': 1, '髏': 2, '髐': 2, '髒': 2, '體': 2, '髕': 2, '髖': 2, '髮': 2, '鬆': 2, '鬍': 2, '鬓': 1, '鬖': 2, '鬗': 2, '鬚': 2, '鬜': 2, '鬝': 2, '鬞': 2, '鬠': 2, '鬡': 2, '鬢': 2, '鬥': 2, '鬧': 2, '鬩': 2, '鬮': 2, '鬱': 2, '鬶': 1, '鬹': 2, '鬺': 2, '魇': 1, '魉': 1, '魎': 2, '魗': 2, '魘': 2, '魚': 2, '魛': 2, '魜': 2, '魝': 2, '魟': 2, '魠': 2, '魡': 2, '魢': 2, '魣': 2, '魥': 2, '魦': 2, '魧': 2, '魨': 2, '魪': 2, '魫': 2, '魬': 2, '魭': 2, '魮': 2, '魯': 2, '魱': 2, '魴': 2, '魵': 2, '魶': 2, '魷': 2, '魺': 2, '魻': 2, '魼': 2, '魽': 2, '魾': 2, '鮀': 2, '鮁': 2, '鮂': 2, '鮃': 2, '鮄': 2, '鮅': 2, '鮆': 2, '鮇': 2, '鮈': 2, '鮊': 2, '鮋': 2, '鮌': 2, '鮍': 2, '鮎': 2, '鮏': 2, '鮐': 2, '鮑': 2, '鮒': 2, '鮓': 2, '鮗': 2, '鮘': 2, '鮚': 2, '鮛': 2, '鮜': 2, '鮝': 2, '鮞': 2, '鮟': 2, '鮠': 2, '鮡': 2, '鮣': 2, '鮤': 2, '鮥': 2, '鮦': 2, '鮧': 2, '鮨': 2, '鮪': 2, '鮫': 2, '鮬': 2, '鮭': 2, '鮮': 2, '鮯': 2, '鮰': 2, '鮳': 2, '鮵': 2, '鮶': 2, '鮷': 2, '鮸': 2, '鮹': 2, '鮺': 2, '鮻': 2, '鮿': 2, '鯀': 2, '鯁': 2, '鯄': 2, '鯅': 2, '鯆': 2, '鯇': 2, '鯈': 2, '鯉': 2, '鯊': 2, '鯌': 2, '鯒': 2, '鯔': 2, '鯕': 2, '鯖': 2, '鯗': 2, '鯚': 2, '鯛': 2, '鯝': 2, '鯞': 2, '鯠': 2, '鯡': 2, '鯢': 2, '鯤': 2, '鯥': 2, '鯦': 2, '鯧': 2, '鯨': 2, '鯩': 2, '鯪': 2, '鯫': 2, '鯬': 2, '鯮': 2, '鯰': 2, '鯱': 2, '鯴': 2, '鯶': 2, '鯷': 2, '鯸': 2, '鯹': 2, '鯻': 2, '鯼': 2, '鯽': 2, '鯾': 2, '鯿': 2, '鰁': 2, '鰂': 2, '鰃': 2, '鰅': 2, '鰆': 2, '鰇': 2, '鰈': 2, '鰉': 2, '鰊': 2, '鰋': 2, '鰌': 2, '鰍': 2, '鰏': 2, '鰐': 2, '鰑': 2, '鰒': 2, '鰓': 2, '鰕': 2, '鰗': 2, '鰛': 2, '鰜': 2, '鰝': 2, '鰟': 2, '鰠': 2, '鰡': 2, '鰣': 2, '鰤': 2, '鰥': 2, '鰦': 2, '鰧': 2, '鰨': 2, '鰩': 2, '鰫': 2, '鰬': 2, '鰭': 2, '鰮': 2, '鰯': 2, '鰱': 2, '鰲': 2, '鰳': 2, '鰴': 2, '鰵': 2, '鰶': 2, '鰷': 2, '鰹': 2, '鰺': 2, '鰻': 2, '鰼': 2, '鰽': 2, '鰾': 2, '鰿': 2, '鱀': 2, '鱁': 2, '鱂': 2, '鱃': 2, '鱄': 2, '鱅': 2, '鱆': 2, '鱇': 2, '鱈': 2, '鱉': 2, '鱊': 2, '鱋': 2, '鱌': 2, '鱍': 2, '鱎': 2, '鱏': 2, '鱐': 2, '鱑': 2, '鱒': 2, '鱓': 2, '鱔': 2, '鱕': 2, '鱖': 2, '鱗': 2, '鱘': 2, '鱚': 2, '鱝': 2, '鱞': 2, '鱟': 2, '鱠': 2, '鱢': 2, '鱣': 2, '鱤': 2, '鱥': 2, '鱦': 2, '鱧': 2, '鱨': 2, '鱬': 2, '鱭': 2, '鱮': 2, '鱯': 2, '鱲': 2, '鱴': 2, '鱵': 2, '鱷': 2, '鱸': 2, '鱹': 2, '鱺': 2, '鱻': 2, '鱼': 1, '鱽': 1, '鱾': 1, '鱿': 1, '鲀': 1, '鲁': 1, '鲂': 1, '鲃': 1, '鲄': 1, '鲅': 1, '鲆': 1, '鲇': 1, '鲈': 1, '鲉': 1, '鲊': 1, '鲋': 1, '鲌': 1, '鲍': 1, '鲎': 1, '鲏': 1, '鲐': 1, '鲑': 1, '鲒': 1, '鲓': 1, '鲔': 1, '鲕': 1, '鲖': 1, '鲗': 1, '鲘': 1, '鲙': 1, '鲚': 1, '鲛': 1, '鲜': 1, '鲝': 1, '鲞': 1, '鲟': 1, '鲠': 1, '鲡': 1, '鲢': 1, '鲣': 1, '鲤': 1, '鲥': 1, '鲦': 1, '鲧': 1, '鲨': 1, '鲩': 1, '鲪': 1, '鲫': 1, '鲬': 1, '鲭': 1, '鲮': 1, '鲯': 1, '鲰': 1, '鲱': 1, '鲲': 1, '鲳': 1, '鲴': 1, '鲵': 1, '鲶': 1, '鲷': 1, '鲸': 1, '鲹': 1, '鲺': 1, '鲻': 1, '鲼': 1, '鲽': 1, '鲾': 1, '鲿': 1, '鳀': 1, '鳁': 1, '鳂': 1, '鳃': 1, '鳄': 1, '鳅': 1, '鳆': 1, '鳇': 1, '鳈': 1, '鳉': 1, '鳊': 1, '鳋': 1, '鳌': 1, '鳍': 1, '鳎': 1, '鳏': 1, '鳐': 1, '鳑': 1, '鳒': 1, '鳓': 1, '鳔': 1, '鳕': 1, '鳖': 1, '鳗': 1, '鳘': 1, '鳙': 1, '鳚': 1, '鳛': 1, '鳜': 1, '鳝': 1, '鳞': 1, '鳟': 1, '鳠': 1, '鳡': 1, '鳢': 1, '鳣': 1, '鳤': 1, '鳥': 2, '鳦': 2, '鳧': 2, '鳩': 2, '鳬': 2, '鳭': 2, '鳱': 2, '鳲': 2, '鳳': 2, '鳴': 2, '鳶': 2, '鳷': 2, '鳸': 2, '鳺': 2, '鳻': 2, '鳼': 2, '鳽': 2, '鳾': 2, '鳿': 2, '鴀': 2, '鴁': 2, '鴂': 2, '鴃': 2, '鴅': 2, '鴆': 2, '鴇': 2, '鴉': 2, '鴍': 2, '鴐': 2, '鴒': 2, '鴓': 2, '鴔': 2, '鴕': 2, '鴗': 2, '鴘': 2, '鴙': 2, '鴚': 2, '鴛': 2, '鴜': 2, '鴝': 2, '鴞': 2, '鴟': 2, '鴠': 2, '鴡': 2, '鴢': 2, '鴣': 2, '鴥': 2, '鴦': 2, '鴨': 2, '鴩': 2, '鴫': 2, '鴮': 2, '鴯': 2, '鴰': 2, '鴱': 2, '鴲': 2, '鴳': 2, '鴴': 2, '鴶': 2, '鴷': 2, '鴸': 2, '鴹': 2, '鴺': 2, '鴻': 2, '鴽': 2, '鴾': 2, '鴿': 2, '鵀': 2, '鵁': 2, '鵂': 2, '鵃': 2, '鵄': 2, '鵅': 2, '鵊': 2, '鵋': 2, '鵌': 2, '鵎': 2, '鵏': 2, '鵐': 2, '鵑': 2, '鵒': 2, '鵓': 2, '鵔': 2, '鵕': 2, '鵖': 2, '鵗': 2, '鵙': 2, '鵚': 2, '鵛': 2, '鵜': 2, '鵝': 2, '鵟': 2, '鵠': 2, '鵡': 2, '鵧': 2, '鵩': 2, '鵪': 2, '鵫': 2, '鵬': 2, '鵮': 2, '鵯': 2, '鵰': 2, '鵱': 2, '鵲': 2, '鵳': 2, '鵴': 2, '鵵': 2, '鵶': 2, '鵷': 2, '鵸': 2, '鵹': 2, '鵻': 2, '鵼': 2, '鵽': 2, '鵾': 2, '鶀': 2, '鶂': 2, '鶃': 2, '鶄': 2, '鶅': 2, '鶆': 2, '鶇': 2, '鶉': 2, '鶊': 2, '鶋': 2, '鶌': 2, '鶒': 2, '鶓': 2, '鶔': 2, '鶕': 2, '鶖': 2, '鶗': 2, '鶘': 2, '鶙': 2, '鶚': 2, '鶛': 2, '鶝': 2, '鶞': 2, '鶟': 2, '鶠': 2, '鶡': 2, '鶢': 2, '鶣': 2, '鶤': 2, '鶥': 2, '鶦': 2, '鶨': 2, '鶩': 2, '鶪': 2, '鶬': 2, '鶭': 2, '鶯': 2, '鶰': 2, '鶱': 2, '鶲': 2, '鶴': 2, '鶵': 2, '鶶': 2, '鶷': 2, '鶹': 2, '鶺': 2, '鶻': 2, '鶼': 2, '鶽': 2, '鷀': 2, '鷁': 2, '鷂': 2, '鷃': 2, '鷄': 2, '鷅': 2, '鷇': 2, '鷈': 2, '鷉': 2, '鷊': 2, '鷋': 2, '鷎': 2, '鷏': 2, '鷐': 2, '鷑': 2, '鷒': 2, '鷓': 2, '鷔': 2, '鷕': 2, '鷖': 2, '鷗': 2, '鷙': 2, '鷚': 2, '鷛': 2, '鷜': 2, '鷞': 2, '鷟': 2, '鷢': 2, '鷣': 2, '鷤': 2, '鷥': 2, '鷦': 2, '鷧': 2, '鷨': 2, '鷩': 2, '鷫': 2, '鷭': 2, '鷮': 2, '鷯': 2, '鷰': 2, '鷲': 2, '鷳': 2, '鷵': 2, '鷶': 2, '鷷': 2, '鷸': 2, '鷹': 2, '鷺': 2, '鷽': 2, '鷾': 2, '鷿': 2, '鸀': 2, '鸁': 2, '鸂': 2, '鸃': 2, '鸄': 2, '鸅': 2, '鸆': 2, '鸇': 2, '鸉': 2, '鸊': 2, '鸋': 2, '鸌': 2, '鸎': 2, '鸏': 2, '鸐': 2, '鸑': 2, '鸒': 2, '鸓': 2, '鸕': 2, '鸖': 2, '鸗': 2, '鸘': 2, '鸙': 2, '鸚': 2, '鸛': 2, '鸜': 2, '鸝': 2, '鸞': 2, '鸟': 1, '鸠': 1, '鸡': 1, '鸢': 1, '鸣': 1, '鸤': 1, '鸥': 1, '鸦': 1, '鸧': 1, '鸨': 1, '鸩': 1, '鸪': 1, '鸫': 1, '鸬': 1, '鸭': 1, '鸮': 1, '鸯': 1, '鸰': 1, '鸱': 1, '鸲': 1, '鸳': 1, '鸴': 1, '鸵': 1, '鸶': 1, '鸷': 1, '鸸': 1, '鸹': 1, '鸺': 1, '鸻': 1, '鸼': 1, '鸽': 1, '鸾': 1, '鸿': 1, '鹀': 1, '鹁': 1, '鹂': 1, '鹃': 1, '鹄': 1, '鹅': 1, '鹆': 1, '鹇': 1, '鹈': 1, '鹉': 1, '鹊': 1, '鹋': 1, '鹌': 1, '鹍': 1, '鹎': 1, '鹏': 1, '鹐': 1, '鹑': 1, '鹒': 1, '鹓': 1, '鹔': 1, '鹕': 1, '鹖': 1, '鹗': 1, '鹘': 1, '鹙': 1, '鹚': 1, '鹛': 1, '鹜': 1, '鹝': 1, '鹞': 1, '鹟': 1, '鹠': 1, '鹡': 1, '鹢': 1, '鹣': 1, '鹤': 1, '鹥': 1, '鹦': 1, '鹧': 1, '鹨': 1, '鹩': 1, '鹪': 1, '鹫': 1, '鹬': 1, '鹭': 1, '鹮': 1, '鹯': 1, '鹰': 1, '鹱': 1, '鹲': 1, '鹳': 1, '鹴': 1, '鹵': 2, '鹹': 2, '鹺': 2, '鹼': 2, '鹽': 2, '鹾': 1, '麗': 2, '麡': 2, '麥': 2, '麦': 3, '麧': 2, '麨': 2, '麩': 2, '麬': 2, '麮': 2, '麯': 2, '麰': 2, '麱': 2, '麲': 2, '麳': 2, '麴': 2, '麵': 2, '麷': 2, '麸': 1, '麹': 1, '麼': 2, '麽': 2, '黂': 2, '黃': 2, '黄': 3, '黉': 1, '黌': 2, '點': 2, '黡': 1, '黨': 2, '黩': 1, '黪': 1, '黲': 2, '黴': 2, '黶': 2, '黷': 2, '黸': 2, '黽': 2, '黾': 3, '黿': 2, '鼀': 2, '鼁': 2, '鼄': 2, '鼅': 2, '鼆': 2, '鼈': 2, '鼉': 2, '鼊': 2, '鼋': 1, '鼍': 1, '鼕': 2, '鼗': 3, '鼚': 2, '鼲': 2, '鼴': 2, '鼹': 3, '齈': 2, '齊': 2, '齋': 2, '齌': 2, '齍': 2, '齎': 2, '齏': 2, '齐': 1, '齑': 1, '齒': 2, '齔': 2, '齕': 2, '齖': 2, '齗': 2, '齘': 2, '齙': 2, '齚': 2, '齜': 2, '齝': 2, '齞': 2, '齟': 2, '齠': 2, '齡': 2, '齣': 2, '齤': 2, '齥': 2, '齦': 2, '齧': 2, '齩': 2, '齪': 2, '齬': 2, '齭': 2, '齮': 2, '齯': 2, '齰': 2, '齱': 2, '齲': 2, '齳': 2, '齴': 2, '齵': 2, '齶': 2, '齷': 2, '齸': 2, '齹': 2, '齺': 2, '齻': 2, '齼': 2, '齽': 2, '齾': 2, '齿': 1, '龀': 1, '龁': 1, '龂': 1, '龃': 1, '龄': 1, '龅': 1, '龆': 1, '龇': 1, '龈': 1, '龉': 1, '龊': 1, '龋': 1, '龌': 1, '龍': 2, '龎': 2, '龏': 2, '龐': 2, '龑': 2, '龓': 2, '龔': 2, '龕': 2, '龖': 2, '龘': 2, '龙': 1, '龚': 1, '龛': 1, '龜': 2, '龝': 2, '龞': 2, '龟': 3, '龥': 2, '龭': 2, '龯': 2, '龲': 2, '龻': 2, '龽': 2, '鿁': 2, '鿂': 2, '鿎': 1, '鿏': 1, '鿐': 2, '鿒': 1, '鿓': 2, '鿔': 1, '鿕': 1, '鿟': 1, '鿠': 2, '鿭': 1, '鿰': 1, '鿲': 1, '鿳': 2, '鿴': 1, '鿵': 1, '鿶': 1, '鿷': 1, '鿸': 1, '鿹': 1, '鿺': 1, '𠀾': 1, '𠁔': 2, '𠁞': 2, '𠂲': 1, '𠃓': 1, '𠆲': 1, '𠆿': 1, '𠇐': 1, '𠇹': 1, '𠉂': 1, '𠉗': 1, '𠌥': 2, '𠎅': 2, '𠎒': 2, '𠏄': 2, '𠏢': 2, '𠏮': 2, '𠏵': 2, '𠐇': 2, '𠐊': 2, '𠐍': 2, '𠐮': 2, '𠐽': 2, '𠑇': 2, '𠑙': 2, '𠑲': 2, '𠖥': 2, '𠖫': 2, '𠗿': 2, '𠘥': 2, '𠚳': 1, '𠛅': 1, '𠛆': 1, '𠛾': 1, '𠜲': 2, '𠝿': 2, '𠞆': 2, '𠞭': 2, '𠟪': 2, '𠠎': 2, '𠠏': 2, '𠠝': 2, '𠠫': 2, '𠡠': 1, '𠩘': 2, '𠩬': 2, '𠬙': 2, '𠬤': 1, '𠯟': 1, '𠯠': 1, '𠰷': 1, '𠱞': 1, '𠲥': 1, '𠳞': 1, '𠴢': 1, '𠵔': 2, '𠵘': 2, '𠵸': 1, '𠵹': 2, '𠵾': 1, '𠶸': 2, '𠶹': 2, '𠷌': 2, '𠷏': 2, '𠹛': 2, '𠺖': 2, '𠺮': 2, '𠼗': 2, '𠼤': 2, '𠼮': 2, '𠽈': 2, '𠽸': 2, '𠾬': 2, '𠿕': 2, '𠿘': 2, '𠿿': 2, '𡀠': 2, '𡀿': 2, '𡁚': 2, '𡁯': 2, '𡂒': 2, '𡂡': 2, '𡂿': 2, '𡃄': 2, '𡃈': 2, '𡃤': 2, '𡄔': 2, '𡄖': 2, '𡄣': 2, '𡄤': 2, '𡄩': 2, '𡅏': 2, '𡅘': 2, '𡅥': 2, '𡅧': 2, '𡈛': 1, '𡊑': 1, '𡋀': 1, '𡋗': 1, '𡋤': 1, '𡍫': 2, '𡏆': 1, '𡑍': 2, '𡑎': 2, '𡑑': 2, '𡑭': 2, '𡑯': 2, '𡒄': 1, '𡒶': 2, '𡓁': 2, '𡓗': 2, '𡓦': 2, '𡓾': 2, '𡗆': 2, '𡝠': 1, '𡞋': 1, '𡞱': 1, '𡞵': 2, '𡟫': 2, '𡠚': 2, '𡠟': 1, '𡠪': 2, '𡠹': 2, '𡡇': 1, '𡢃': 2, '𡢄': 2, '𡢘': 2, '𡢿': 2, '𡣨': 2, '𡤠': 2, '𡤡': 2, '𡤢': 2, '𡤫': 2, '𡤶': 2, '𡥧': 1, '𡭜': 1, '𡭬': 1, '𡮉': 2, '𡮣': 2, '𡮤': 2, '𡳃': 1, '𡳒': 1, '𡳳': 2, '𡵝': 1, '𡶴': 1, '𡷨': 2, '𡸃': 1, '𡸗': 2, '𡹬': 2, '𡺃': 1, '𡺠': 2, '𡺨': 2, '𡻘': 1, '𡼱': 2, '𡼾': 2, '𡽗': 2, '𡽳': 2, '𡽵': 2, '𡾆': 2, '𡾱': 2, '𡿖': 2, '𢀖': 1, '𢄓': 2, '𢄼': 2, '𢅡': 2, '𢅣': 2, '𢉿': 2, '𢊃': 2, '𢋈': 1, '𢍰': 2, '𢐗': 2, '𢐟': 2, '𢓅': 1, '𢕩': 2, '𢖕': 2, '𢗓': 1, '𢘙': 1, '𢘝': 1, '𢘞': 1, '𢙐': 1, '𢙑': 1, '𢙒': 1, '𢙓': 1, '𢛔': 2, '𢛯': 1, '𢜭': 2, '𢞁': 2, '𢟼': 1, '𢠰': 2, '𢠼': 2, '𢢀': 2, '𢣏': 2, '𢣐': 2, '𢣚': 2, '𢣭': 2, '𢤌': 2, '𢤜': 2, '𢤧': 2, '𢤩': 2, '𢤱': 2, '𢤿': 2, '𢥠': 2, '𢧐': 1, '𢪓': 1, '𢪗': 1, '𢫊': 1, '𢫘': 1, '𢫞': 1, '𢫬': 1, '𢬍': 1, '𢬦': 1, '𢭏': 1, '𢯦': 2, '𢯩': 2, '𢯷': 2, '𢱡': 2, '𢲐': 2, '𢲩': 2, '𢲫': 2, '𢲸': 2, '𢲾': 2, '𢳂': 2, '𢳚': 2, '𢴦': 2, '𢴩': 2, '𢵣': 2, '𢵱': 2, '𢶑': 2, '𢶒': 2, '𢶣': 1, '𢶫': 2, '𢷃': 2, '𢷏': 2, '𢷞': 2, '𢷮': 2, '𢸁': 2, '𢸔': 2, '𢸙': 2, '𢸳': 2, '𢸴': 2, '𢸸': 2, '𢹏': 2, '𢹥': 2, '𢹼': 2, '𢹿': 2, '𢺎': 2, '𢺳': 2, '𢽾': 1, '𢿓': 2, '𢿡': 2, '𣀘': 2, '𣀷': 2, '𣀻': 2, '𣃁': 1, '𣄸': 2, '𣆐': 1, '𣈣': 1, '𣈶': 2, '𣉼': 1, '𣊯': 2, '𣋋': 2, '𣋞': 2, '𣋪': 2, '𣌂': 2, '𣍐': 2, '𣍨': 1, '𣍯': 1, '𣍰': 1, '𣎄': 2, '𣎑': 1, '𣎜': 2, '𣏢': 1, '𣐕': 1, '𣐤': 1, '𣑝': 1, '𣑶': 1, '𣒌': 1, '𣒗': 1, '𣓿': 1, '𣔿': 2, '𣕲': 1, '𣗊': 1, '𣗋': 1, '𣘐': 1, '𣘓': 1, '𣘴': 1, '𣘷': 1, '𣘾': 1, '𣙎': 2, '𣙥': 1, '𣙿': 2, '𣚙': 2, '𣚚': 1, '𣛣': 2, '𣝕': 2, '𣝡': 2, '𣞁': 2, '𣞎': 1, '𣞐': 2, '𣞻': 2, '𣞼': 2, '𣠕': 2, '𣠩': 2, '𣠲': 2, '𣡌': 2, '𣡶': 2, '𣤋': 2, '𣤿': 2, '𣨼': 1, '𣩕': 2, '𣫒': 2, '𣭤': 1, '𣯣': 1, '𣯩': 2, '𣯴': 2, '𣯶': 2, '𣰛': 2, '𣰨': 2, '𣱝': 1, '𣲗': 1, '𣲘': 1, '𣳆': 1, '𣴇': 1, '𣵾': 2, '𣶩': 1, '𣶫': 1, '𣶯': 2, '𣸣': 1, '𣺼': 1, '𣺽': 1, '𣻏': 2, '𣻑': 2, '𣼊': 2, '𣼩': 2, '𣼼': 2, '𣽏': 2, '𣽷': 1, '𣾍': 1, '𣾷': 2, '𣿉': 2, '𣿭': 2, '𤀪': 2, '𤁐': 2, '𤁣': 2, '𤁪': 2, '𤄙': 2, '𤄷': 2, '𤅊': 2, '𤅙': 2, '𤅩': 2, '𤅷': 2, '𤆡': 1, '𤆢': 1, '𤆼': 2, '𤇃': 1, '𤇄': 1, '𤇭': 1, '𤇻': 1, '𤇾': 2, '𤈶': 1, '𤈷': 1, '𤊀': 1, '𤋏': 1, '𤍖': 2, '𤍜': 2, '𤎤': 2, '𤎱': 2, '𤎺': 1, '𤎻': 1, '𤏐': 2, '𤏩': 2, '𤏳': 2, '𤑚': 2, '𤑳': 2, '𤑹': 2, '𤒎': 2, '𤒦': 2, '𤒨': 2, '𤒻': 2, '𤓌': 2, '𤓎': 2, '𤓓': 2, '𤘀': 2, '𤙯': 1, '𤚴': 2, '𤛮': 2, '𤛱': 2, '𤜆': 2, '𤜵': 1, '𤝢': 1, '𤞃': 1, '𤞤': 1, '𤟤': 2, '𤠋': 1, '𤠔': 2, '𤠮': 2, '𤡲': 2, '𤢟': 2, '𤣎': 2, '𤣤': 2, '𤥭': 2, '𤥵': 2, '𤦀': 1, '𤦎': 2, '𤦩': 2, '𤧑': 2, '𤧸': 2, '𤩂': 2, '𤩊': 2, '𤩑': 2, '𤩝': 2, '𤩽': 1, '𤪤': 2, '𤪧': 2, '𤪺': 2, '𤫎': 2, '𤫟': 2, '𤫩': 2, '𤬅': 2, '𤮦': 2, '𤲓': 2, '𤲢': 2, '𤳄': 1, '𤳷': 2, '𤳸': 2, '𤶊': 1, '𤶧': 1, '𤷃': 2, '𤷽': 2, '𤸫': 2, '𤹺': 1, '𤺉': 2, '𤺔': 2, '𤻊': 1, '𤻜': 2, '𤻝': 2, '𤻲': 2, '𤼈': 2, '𤽯': 1, '𤾀': 1, '𤾉': 2, '𤿲': 1, '𥀬': 2, '𥀲': 2, '𥁢': 1, '𥂫': 2, '𥂸': 2, '𥅘': 1, '𥅴': 1, '𥆧': 1, '𥇔': 2, '𥇢': 1, '𥉸': 2, '𥋝': 2, '𥋟': 2, '𥌃': 2, '𥌚': 2, '𥎝': 1, '𥏝': 2, '𥐟': 1, '𥐯': 1, '𥐰': 1, '𥐻': 1, '𥔂': 2, '𥔬': 2, '𥕤': 1, '𥕥': 2, '𥖅': 2, '𥖏': 2, '𥖩': 2, '𥖲': 2, '𥗇': 2, '𥗴': 2, '𥗹': 2, '𥗺': 2, '𥗽': 2, '𥘃': 2, '𥚗': 2, '𥜐': 2, '𥜰': 2, '𥞦': 1, '𥞵': 2, '𥟂': 1, '𥢊': 2, '𥢢': 2, '𥢶': 2, '𥢷': 2, '𥧂': 1, '𥨐': 2, '𥩺': 1, '𥪂': 2, '𥬀': 1, '𥬈': 1, '𥬞': 1, '𥬠': 1, '𥭉': 1, '𥮋': 1, '𥮜': 1, '𥮾': 1, '𥯤': 2, '𥱔': 1, '𥱸': 2, '𥳊': 2, '𥴨': 2, '𥴼': 2, '𥵃': 2, '𥵊': 2, '𥵛': 2, '𥵜': 2, '𥵝': 2, '𥸠': 2, '𥹥': 1, '𥺅': 1, '𥺇': 1, '𥺼': 2, '𥻤': 2, '𥻦': 2, '𥻵': 2, '𥼶': 2, '𥼽': 2, '𥽖': 2, '𥽭': 2, '𥽽': 2, '𥾂': 2, '𥾝': 2, '𥾯': 2, '𥿉': 2, '𥿊': 2, '𥿑': 2, '𥿯': 2, '𦀎': 2, '𦀖': 2, '𦁄': 2, '𦁕': 2, '𦁧': 2, '𦂅': 2, '𦂋': 2, '𦃄': 2, '𦃒': 2, '𦃘': 2, '𦃩': 2, '𦄋': 2, '𦄍': 2, '𦄧': 2, '𦄼': 2, '𦅇': 2, '𦅈': 2, '𦅋': 2, '𦅘': 2, '𦅷': 2, '𦆆': 2, '𦆈': 2, '𦆲': 2, '𦇎': 2, '𦇛': 2, '𦈈': 1, '𦈉': 1, '𦈋': 1, '𦈌': 1, '𦈎': 1, '𦈏': 1, '𦈐': 1, '𦈑': 1, '𦈒': 1, '𦈓': 1, '𦈔': 1, '𦈕': 1, '𦈖': 1, '𦈗': 1, '𦈘': 1, '𦈙': 1, '𦈚': 1, '𦈛': 1, '𦈜': 1, '𦈝': 1, '𦈞': 1, '𦈟': 1, '𦈠': 1, '𦈡': 1, '𦌾': 2, '𦍆': 2, '𦍠': 1, '𦎹': 2, '𦏑': 2, '𦒀': 2, '𦔖': 2, '𦘧': 2, '𦛨': 1, '𦜖': 2, '𦝛': 2, '𦝼': 1, '𦞌': 1, '𦞛': 2, '𦟐': 2, '𦟗': 1, '𦟼': 2, '𦠅': 2, '𦡏': 2, '𦡖': 2, '𦡝': 2, '𦡧': 2, '𦡶': 2, '𦢈': 2, '𦣇': 2, '𦣎': 2, '𦥯': 2, '𦧴': 2, '𦧺': 2, '𦨩': 1, '𦪭': 2, '𦪽': 2, '𦬙': 1, '𦰴': 1, '𦱌': 2, '𦳝': 2, '𦴇': 1, '𦴧': 2, '𦵕': 2, '𦶆': 2, '𦸷': 2, '𦺣': 2, '𦻕': 1, '𦽒': 2, '𦾏': 2, '𦾵': 2, '𦾶': 2, '𦿍': 2, '𦿭': 2, '𧀀': 2, '𧁿': 2, '𧂂': 2, '𧂅': 2, '𧃽': 2, '𧈴': 1, '𧈿': 1, '𧉐': 1, '𧉞': 1, '𧍕': 2, '𧏖': 1, '𧏗': 1, '𧏻': 2, '𧐐': 2, '𧐱': 2, '𧑏': 1, '𧒖': 2, '𧒭': 1, '𧒯': 2, '𧔥': 2, '𧕟': 2, '𧕦': 2, '𧖦': 2, '𧛸': 2, '𧜁': 2, '𧜂': 2, '𧜗': 2, '𧜘': 2, '𧜡': 1, '𧜣': 2, '𧜭': 1, '𧜵': 2, '𧜶': 2, '𧝝': 1, '𧝞': 2, '𧞅': 2, '𧞔': 2, '𧞣': 2, '𧞫': 2, '𧞶': 2, '𧟌': 2, '𧠈': 2, '𧠥': 2, '𧠳': 2, '𧠵': 2, '𧡍': 2, '𧡪': 2, '𧡴': 2, '𧡸': 2, '𧢃': 2, '𧢄': 2, '𧢍': 2, '𧢢': 2, '𧣴': 2, '𧤤': 1, '𧥅': 1, '𧥣': 2, '𧥺': 2, '𧦝': 2, '𧦦': 2, '𧦧': 2, '𧦭': 2, '𧦵': 2, '𧧝': 2, '𧧭': 2, '𧧵': 2, '𧧸': 2, '𧨊': 2, '𧨝': 2, '𧨳': 2, '𧨾': 2, '𧩎': 2, '𧩕': 2, '𧩙': 2, '𧩦': 2, '𧩧': 2, '𧩪': 2, '𧩼': 2, '𧪞': 2, '𧪡': 2, '𧪦': 2, '𧪪': 2, '𧪮': 2, '𧫚': 2, '𧫝': 2, '𧬁': 2, '𧬅': 2, '𧬇': 2, '𧬌': 2, '𧬤': 2, '𧬨': 2, '𧬪': 2, '𧬮': 2, '𧬯': 2, '𧬻': 2, '𧭈': 2, '𧭥': 2, '𧭹': 2, '𧮆': 2, '𧮇': 2, '𧮈': 2, '𧮓': 2, '𧮪': 1, '𧰆': 2, '𧰎': 2, '𧱻': 2, '𧳕': 1, '𧳟': 2, '𧴪': 2, '𧵊': 2, '𧵳': 2, '𧶄': 2, '𧶔': 2, '𧶟': 2, '𧶧': 2, '𧶲': 2, '𧷎': 2, '𧷛': 2, '𧸖': 2, '𧸘': 2, '𧸦': 2, '𧸪': 2, '𧸫': 2, '𧹈': 2, '𧹑': 1, '𧹒': 1, '𧹓': 1, '𧹔': 1, '𧹕': 1, '𧹖': 1, '𧹗': 1, '𧺣': 1, '𧽢': 2, '𧽯': 2, '𧽵': 2, '𧾥': 2, '𧿈': 1, '𧿛': 1, '𨀁': 1, '𨀱': 1, '𨁂': 2, '𨁴': 1, '𨂐': 2, '𨂺': 1, '𨃘': 2, '𨃜': 2, '𨄄': 1, '𨄉': 2, '𨄣': 2, '𨄰': 2, '𨅍': 2, '𨅛': 1, '𨅫': 1, '𨅬': 1, '𨆅': 2, '𨆉': 2, '𨆪': 2, '𨆱': 2, '𨇁': 2, '𨇍': 2, '𨇗': 2, '𨇞': 2, '𨇤': 2, '𨇯': 2, '𨇰': 2, '𨇽': 2, '𨈀': 2, '𨈆': 2, '𨈇': 2, '𨈊': 2, '𨈌': 2, '𨉖': 2, '𨉗': 1, '𨉹': 2, '𨊠': 2, '𨊰': 2, '𨊸': 2, '𨊹': 2, '𨊻': 2, '𨋁': 2, '𨋚': 2, '𨋢': 2, '𨋮': 2, '𨌄': 2, '𨌈': 2, '𨍈': 2, '𨍏': 2, '𨍐': 2, '𨍒': 2, '𨍰': 2, '𨍹': 2, '𨎌': 2, '𨎩': 2, '𨎪': 2, '𨎮': 2, '𨏒': 2, '𨏔': 2, '𨏠': 2, '𨏥': 2, '𨐅': 1, '𨐆': 1, '𨐇': 1, '𨐈': 1, '𨐉': 1, '𨐊': 1, '𨐶': 2, '𨑊': 2, '𨑹': 1, '𨘀': 2, '𨘌': 2, '𨝕': 1, '𨞨': 2, '𨞪': 2, '𨞺': 2, '𨟊': 2, '𨟑': 2, '𨟳': 1, '𨠨': 1, '𨡙': 1, '𨡺': 1, '𨢸': 1, '𨢿': 2, '𨣃': 2, '𨣈': 2, '𨣉': 2, '𨣞': 2, '𨣧': 2, '𨣨': 2, '𨤋': 2, '𨤡': 2, '𨤰': 1, '𨤻': 2, '𨥈': 2, '𨥕': 2, '𨥛': 2, '𨥜': 2, '𨥟': 2, '𨥤': 2, '𨥦': 2, '𨥭': 2, '𨥮': 2, '𨥺': 2, '𨦍': 2, '𨦡': 2, '𨦫': 2, '𨦱': 2, '𨧀': 2, '𨧐': 2, '𨧚': 2, '𨧜': 2, '𨧫': 2, '𨧮': 1, '𨧰': 2, '𨧱': 2, '𨨏': 2, '𨨛': 2, '𨨝': 2, '𨨢': 2, '𨨯': 2, '𨨹': 2, '𨩃': 2, '𨩎': 2, '𨩨': 2, '𨩰': 2, '𨪅': 2, '𨪋': 2, '𨪕': 2, '𨪜': 2, '𨪦': 2, '𨫀': 2, '𨫋': 2, '𨫒': 2, '𨫼': 2, '𨬂': 2, '𨬒': 2, '𨬖': 2, '𨬞': 2, '𨬟': 2, '𨭃': 2, '𨭆': 2, '𨭌': 2, '𨭎': 2, '𨭐': 2, '𨭖': 2, '𨭗': 2, '𨭚': 2, '𨭛': 2, '𨭥': 2, '𨭸': 2, '𨮁': 2, '𨮂': 2, '𨮅': 2, '𨮰': 2, '𨮳': 2, '𨯂': 2, '𨯅': 2, '𨯗': 2, '𨯙': 2, '𨯟': 2, '𨯵': 2, '𨰃': 2, '𨰋': 2, '𨰘': 2, '𨰠': 2, '𨰥': 2, '𨰭': 2, '𨰲': 2, '𨰵': 2, '𨰷': 2, '𨰹': 2, '𨰾': 1, '𨰿': 1, '𨱀': 1, '𨱁': 1, '𨱂': 1, '𨱃': 1, '𨱄': 1, '𨱅': 1, '𨱆': 1, '𨱇': 1, '𨱈': 1, '𨱉': 1, '𨱊': 1, '𨱋': 1, '𨱌': 1, '𨱍': 1, '𨱎': 1, '𨱏': 1, '𨱐': 1, '𨱑': 1, '𨱒': 1, '𨱓': 1, '𨱔': 1, '𨱕': 1, '𨱖': 1, '𨱥': 2, '𨲭': 2, '𨲳': 2, '𨳌': 2, '𨳐': 2, '𨳑': 2, '𨳒': 2, '𨳕': 2, '𨳙': 2, '𨳚': 2, '𨳨': 2, '𨳸': 2, '𨳿': 2, '𨴑': 2, '𨴗': 2, '𨴤': 2, '𨴹': 2, '𨵆': 2, '𨵌': 2, '𨵗': 2, '𨵤': 2, '𨵦': 2, '𨵩': 2, '𨵬': 2, '𨵸': 2, '𨶀': 2, '𨶏': 2, '𨶑': 2, '𨶮': 2, '𨶯': 2, '𨶰': 2, '𨶲': 2, '𨶻': 2, '𨶿': 2, '𨷈': 2, '𨷲': 2, '𨷻': 2, '𨷿': 1, '𨸀': 1, '𨸁': 1, '𨸂': 1, '𨸃': 1, '𨸄': 1, '𨸅': 1, '𨸆': 1, '𨸇': 1, '𨸉': 1, '𨸊': 1, '𨸋': 1, '𨸌': 1, '𨸎': 1, '𨸘': 1, '𨸟': 1, '𨻹': 1, '𨼳': 2, '𨽈': 2, '𨽏': 2, '𩀨': 2, '𩅙': 2, '𩅦': 2, '𩅾': 2, '𩇉': 2, '𩉍': 2, '𩉙': 2, '𩋌': 2, '𩋰': 2, '𩍜': 2, '𩎒': 2, '𩎕': 2, '𩎖': 2, '𩎟': 2, '𩎠': 2, '𩎢': 2, '𩏂': 2, '𩏌': 2, '𩏠': 2, '𩏪': 2, '𩏴': 2, '𩏷': 2, '𩏼': 1, '𩏽': 1, '𩏾': 1, '𩏿': 1, '𩐀': 1, '𩐌': 2, '𩐳': 2, '𩑃': 2, '𩑒': 2, '𩑔': 2, '𩑡': 2, '𩑣': 2, '𩑦': 2, '𩒎': 2, '𩒜': 2, '𩒝': 2, '𩒲': 2, '𩒺': 2, '𩒼': 2, '𩓣': 2, '𩓥': 2, '𩓸': 2, '𩓹': 2, '𩔇': 2, '𩔈': 2, '𩔊': 2, '𩔐': 2, '𩔑': 2, '𩔣': 2, '𩔳': 2, '𩕊': 2, '𩕰': 2, '𩖁': 2, '𩖕': 1, '𩖖': 1, '𩖗': 1, '𩖰': 2, '𩖿': 2, '𩗀': 2, '𩗓': 2, '𩗛': 2, '𩗡': 2, '𩗩': 2, '𩗴': 2, '𩗺': 2, '𩘀': 2, '𩘚': 2, '𩘝': 2, '𩘹': 2, '𩘺': 2, '𩘻': 2, '𩙈': 2, '𩙥': 1, '𩙦': 1, '𩙧': 1, '𩙨': 1, '𩙩': 1, '𩙪': 1, '𩙫': 1, '𩙬': 1, '𩙭': 1, '𩙮': 1, '𩙯': 1, '𩙰': 1, '𩚅': 2, '𩚚': 2, '𩚛': 2, '𩚥': 2, '𩚩': 2, '𩚵': 2, '𩛆': 2, '𩛌': 2, '𩛎': 2, '𩛞': 2, '𩛡': 2, '𩛩': 2, '𩛲': 2, '𩜇': 2, '𩜠': 2, '𩜦': 2, '𩜯': 2, '𩜰': 2, '𩜵': 2, '𩜶': 2, '𩝑': 2, '𩝔': 2, '𩝠': 2, '𩝡': 2, '𩝣': 2, '𩝧': 2, '𩝽': 2, '𩞃': 2, '𩞄': 2, '𩞆': 2, '𩞉': 2, '𩞡': 2, '𩞦': 2, '𩞧': 2, '𩞬': 2, '𩞯': 2, '𩟀': 2, '𩟂': 2, '𩟐': 2, '𩟗': 2, '𩟠': 2, '𩟿': 1, '𩠀': 1, '𩠁': 1, '𩠂': 1, '𩠃': 1, '𩠅': 1, '𩠆': 1, '𩠇': 1, '𩠈': 1, '𩠉': 1, '𩠊': 1, '𩠋': 1, '𩠌': 1, '𩠎': 1, '𩠏': 1, '𩠠': 1, '𩠴': 2, '𩡖': 1, '𩡚': 1, '𩡣': 2, '𩡤': 2, '𩡺': 2, '𩢀': 2, '𩢍': 2, '𩢖': 2, '𩢡': 2, '𩢰': 2, '𩢲': 2, '𩢴': 2, '𩢸': 2, '𩢼': 2, '𩢾': 2, '𩣊': 2, '𩣋': 2, '𩣏': 2, '𩣑': 2, '𩣔': 2, '𩣡': 2, '𩣫': 2, '𩣵': 2, '𩣺': 2, '𩤊': 2, '𩤙': 2, '𩤲': 2, '𩤵': 2, '𩤸': 2, '𩥃': 2, '𩥄': 2, '𩥅': 2, '𩥇': 2, '𩥈': 2, '𩥉': 2, '𩥎': 2, '𩥑': 2, '𩥲': 2, '𩥼': 2, '𩦃': 2, '𩦚': 2, '𩦠': 2, '𩦺': 2, '𩧆': 2, '𩧉': 2, '𩧐': 2, '𩧢': 2, '𩧦': 1, '𩧨': 1, '𩧩': 1, '𩧪': 1, '𩧫': 1, '𩧬': 1, '𩧭': 1, '𩧮': 1, '𩧯': 1, '𩧰': 1, '𩧱': 1, '𩧲': 1, '𩧳': 1, '𩧴': 1, '𩧵': 1, '𩧶': 1, '𩧸': 1, '𩧺': 1, '𩧻': 1, '𩧼': 1, '𩧿': 1, '𩨀': 1, '𩨁': 1, '𩨃': 1, '𩨄': 1, '𩨅': 1, '𩨆': 1, '𩨇': 1, '𩨈': 1, '𩨉': 1, '𩨊': 1, '𩨋': 1, '𩨌': 1, '𩨍': 1, '𩨎': 1, '𩨏': 1, '𩨐': 1, '𩩈': 1, '𩬣': 1, '𩬤': 1, '𩬾': 1, '𩭙': 2, '𩭯': 2, '𩭹': 1, '𩯁': 2, '𩯃': 2, '𩯆': 2, '𩯒': 1, '𩯳': 2, '𩰀': 2, '𩰰': 1, '𩰹': 2, '𩱈': 2, '𩲒': 1, '𩳤': 2, '𩴆': 2, '𩴌': 1, '𩴵': 2, '𩵚': 2, '𩵦': 2, '𩵩': 2, '𩵱': 2, '𩵳': 2, '𩵹': 2, '𩵺': 2, '𩶀': 2, '𩶁': 2, '𩶘': 2, '𩶯': 2, '𩶰': 2, '𩶱': 2, '𩷒': 2, '𩷓': 2, '𩷕': 2, '𩷰': 2, '𩷶': 2, '𩸃': 2, '𩸄': 2, '𩸆': 2, '𩸡': 2, '𩸣': 2, '𩸤': 2, '𩸦': 2, '𩸩': 2, '𩸬': 2, '𩹂': 2, '𩹊': 2, '𩹎': 2, '𩹝': 2, '𩹽': 2, '𩹾': 2, '𩺝': 2, '𩺞': 2, '𩻗': 2, '𩻛': 2, '𩻧': 2, '𩻬': 2, '𩻮': 2, '𩻰': 2, '𩻱': 2, '𩼔': 2, '𩼶': 2, '𩽅': 2, '𩽇': 2, '𩽈': 2, '𩽔': 2, '𩽷': 2, '𩽹': 1, '𩽺': 1, '𩽻': 1, '𩽼': 1, '𩽽': 1, '𩽾': 1, '𩽿': 1, '𩾁': 1, '𩾂': 1, '𩾃': 1, '𩾄': 1, '𩾅': 1, '𩾆': 1, '𩾇': 1, '𩾈': 1, '𩾊': 1, '𩾋': 1, '𩾌': 1, '𩾎': 1, '𩾐': 2, '𩾒': 2, '𩾝': 2, '𩿅': 2, '𩿊': 2, '𩿤': 2, '𩿧': 2, '𩿪': 2, '𩿱': 2, '𩿺': 2, '𪀉': 2, '𪀖': 2, '𪀗': 2, '𪀚': 2, '𪀛': 2, '𪀦': 2, '𪀻': 2, '𪀾': 2, '𪁈': 2, '𪁏': 2, '𪁐': 2, '𪁑': 2, '𪁖': 2, '𪁛': 2, '𪁜': 2, '𪁱': 2, '𪁿': 2, '𪂆': 2, '𪂈': 2, '𪂩': 2, '𪂫': 2, '𪃃': 2, '𪃍': 2, '𪃏': 2, '𪃒': 2, '𪃦': 2, '𪃧': 2, '𪃮': 2, '𪃿': 2, '𪄅': 2, '𪄆': 2, '𪄕': 2, '𪄠': 2, '𪄲': 2, '𪄳': 2, '𪅂': 2, '𪅃': 2, '𪅖': 2, '𪅜': 2, '𪅾': 2, '𪆃': 2, '𪆫': 2, '𪆰': 2, '𪆴': 2, '𪆷': 2, '𪇄': 2, '𪇖': 2, '𪇘': 2, '𪇰': 2, '𪇳': 2, '𪈏': 2, '𪈔': 2, '𪈗': 2, '𪈼': 2, '𪉂': 1, '𪉃': 1, '𪉄': 1, '𪉅': 1, '𪉆': 1, '𪉈': 1, '𪉉': 1, '𪉊': 1, '𪉋': 1, '𪉌': 1, '𪉍': 1, '𪉎': 1, '𪉏': 1, '𪉐': 1, '𪉑': 1, '𪉒': 1, '𪉔': 1, '𪉕': 1, '𪉖': 2, '𪉜': 2, '𪉣': 2, '𪉨': 2, '𪉮': 2, '𪉱': 2, '𪉸': 2, '𪉿': 2, '𪊉': 2, '𪋈': 1, '𪋼': 2, '𪋽': 2, '𪋿': 2, '𪌐': 2, '𪌒': 2, '𪌗': 2, '𪌘': 2, '𪌜': 2, '𪌣': 2, '𪌨': 2, '𪌬': 2, '𪌭': 2, '𪌮': 2, '𪌯': 2, '𪌰': 2, '𪌽': 2, '𪌾': 2, '𪌿': 2, '𪍀': 2, '𪍇': 2, '𪍍': 2, '𪍑': 2, '𪍒': 2, '𪍓': 2, '𪍘': 2, '𪍚': 2, '𪍞': 2, '𪍠': 2, '𪍣': 2, '𪍤': 2, '𪍬': 2, '𪍴': 2, '𪍶': 2, '𪍷': 2, '𪍿': 2, '𪎂': 2, '𪎈': 1, '𪎉': 1, '𪎊': 1, '𪎋': 1, '𪎌': 1, '𪑅': 1, '𪑚': 2, '𪑳': 2, '𪒬': 2, '𪒿': 2, '𪓛': 2, '𪓬': 2, '𪓰': 2, '𪓹': 2, '𪓽': 2, '𪔭': 1, '𪔵': 2, '𪕣': 2, '𪖨': 2, '𪗋': 2, '𪗜': 2, '𪗝': 2, '𪗪': 2, '𪗭': 2, '𪗳': 2, '𪗻': 2, '𪗽': 2, '𪘀': 2, '𪘅': 2, '𪘓': 2, '𪘞': 2, '𪘥': 2, '𪘧': 2, '𪘨': 2, '𪘩': 2, '𪘬': 2, '𪘯': 2, '𪘲': 2, '𪙉': 2, '𪙍': 2, '𪙏': 2, '𪙑': 2, '𪙕': 2, '𪙞': 2, '𪙤': 2, '𪚅': 2, '𪚏': 1, '𪚐': 1, '𪚔': 2, '𪚣': 2, '𪚭': 2, '𪚮': 2, '𪚰': 2, '𪛕': 2, '𪛞': 1, '𪜎': 1, '𪜺': 1, '𪝖': 2, '𪝵': 2, '𪞝': 1, '𪟎': 1, '𪟖': 2, '𪟝': 1, '𪟲': 1, '𪠀': 1, '𪠃': 1, '𪠏': 1, '𪠟': 1, '𪠡': 1, '𪠳': 1, '𪠵': 1, '𪠸': 1, '𪠽': 1, '𪡀': 1, '𪡃': 1, '𪡋': 1, '𪡏': 1, '𪡛': 1, '𪡞': 1, '𪡺': 1, '𪢈': 1, '𪢋': 1, '𪢌': 1, '𪢍': 2, '𪢐': 1, '𪢒': 1, '𪢕': 1, '𪢠': 1, '𪢥': 2, '𪢮': 1, '𪣆': 1, '𪣒': 1, '𪣻': 1, '𪤄': 1, '𪤅': 1, '𪤚': 1, '𪥠': 1, '𪥫': 1, '𪥰': 1, '𪥿': 1, '𪦯': 2, '𪧀': 1, '𪧘': 1, '𪨇': 1, '𪨊': 1, '𪨗': 1, '𪨧': 1, '𪨩': 1, '𪨶': 1, '𪨷': 1, '𪨹': 1, '𪩇': 1, '𪩎': 1, '𪩘': 1, '𪩛': 1, '𪩸': 1, '𪪑': 1, '𪪞': 1, '𪪴': 1, '𪫌': 1, '𪫡': 1, '𪫷': 1, '𪫸': 1, '𪫺': 1, '𪬚': 1, '𪬯': 1, '𪭝': 1, '𪭢': 1, '𪭧': 1, '𪭯': 1, '𪭵': 1, '𪭾': 1, '𪮃': 1, '𪮋': 1, '𪮖': 1, '𪮰': 2, '𪮳': 1, '𪮶': 1, '𪯂': 2, '𪯋': 1, '𪰶': 1, '𪱥': 1, '𪱷': 1, '𪲎': 1, '𪲔': 1, '𪲛': 1, '𪲮': 1, '𪳍': 1, '𪳷': 2, '𪴙': 1, '𪴥': 2, '𪴯': 1, '𪵇': 1, '𪵑': 1, '𪵢': 2, '𪵣': 1, '𪵱': 1, '𪶄': 1, '𪶒': 1, '𪶮': 1, '𪷈': 2, '𪷍': 1, '𪷽': 1, '𪸕': 1, '𪸩': 1, '𪹀': 1, '𪹠': 1, '𪹳': 1, '𪹹': 1, '𪺣': 1, '𪺪': 1, '𪺭': 1, '𪺷': 1, '𪺸': 1, '𪺻': 1, '𪺽': 1, '𪻐': 1, '𪻨': 1, '𪻲': 1, '𪻺': 1, '𪼋': 1, '𪼑': 2, '𪼴': 1, '𪽂': 1, '𪽝': 1, '𪽪': 1, '𪽭': 1, '𪽮': 1, '𪽴': 1, '𪽷': 1, '𪾔': 1, '𪾢': 1, '𪾦': 1, '𪾳': 2, '𪾸': 1, '𪿊': 1, '𪿞': 1, '𪿫': 1, '𪿵': 1, '𫀌': 1, '𫀓': 1, '𫀨': 1, '𫀬': 1, '𫀮': 1, '𫁂': 1, '𫁟': 1, '𫁡': 1, '𫁲': 1, '𫁳': 1, '𫁷': 1, '𫁺': 1, '𫂃': 1, '𫂆': 1, '𫂈': 1, '𫂖': 1, '𫂿': 1, '𫃐': 2, '𫃑': 2, '𫃗': 1, '𫃞': 2, '𫃥': 2, '𫃷': 2, '𫃻': 2, '𫄇': 2, '𫄙': 1, '𫄚': 1, '𫄛': 1, '𫄜': 1, '𫄝': 1, '𫄞': 1, '𫄟': 1, '𫄠': 1, '𫄡': 1, '𫄢': 1, '𫄣': 1, '𫄤': 1, '𫄥': 1, '𫄦': 1, '𫄧': 1, '𫄨': 1, '𫄩': 1, '𫄪': 1, '𫄫': 1, '𫄬': 1, '𫄭': 1, '𫄮': 1, '𫄯': 1, '𫄰': 1, '𫄱': 1, '𫄲': 1, '𫄳': 1, '𫄴': 1, '𫄵': 1, '𫄶': 1, '𫄷': 1, '𫄸': 1, '𫄹': 1, '𫅅': 1, '𫅗': 1, '𫅥': 1, '𫅭': 1, '𫅼': 1, '𫆏': 1, '𫆝': 1, '𫆫': 1, '𫇘': 1, '𫇠': 2, '𫇦': 1, '𫇪': 1, '𫇭': 1, '𫇴': 1, '𫇽': 1, '𫈉': 1, '𫈎': 1, '𫈟': 1, '𫈵': 1, '𫈹': 2, '𫉁': 1, '𫉄': 1, '𫉍': 2, '𫊪': 1, '𫊮': 1, '𫊱': 1, '𫊸': 1, '𫊹': 1, '𫊻': 1, '𫋇': 1, '𫋌': 1, '𫋐': 2, '𫋧': 2, '𫋲': 1, '𫋷': 1, '𫋹': 1, '𫋻': 1, '𫌀': 1, '𫌇': 1, '𫌋': 1, '𫌙': 2, '𫌨': 1, '𫌩': 1, '𫌪': 1, '𫌫': 1, '𫌬': 1, '𫌭': 1, '𫌯': 1, '𫍏': 1, '𫍐': 1, '𫍘': 2, '𫍙': 1, '𫍚': 1, '𫍛': 1, '𫍜': 1, '𫍞': 1, '𫍟': 1, '𫍠': 1, '𫍡': 1, '𫍢': 1, '𫍣': 1, '𫍤': 1, '𫍥': 1, '𫍦': 1, '𫍧': 1, '𫍨': 1, '𫍩': 1, '𫍪': 1, '𫍫': 1, '𫍬': 1, '𫍭': 1, '𫍮': 1, '𫍯': 1, '𫍰': 1, '𫍱': 1, '𫍲': 1, '𫍳': 1, '𫍴': 1, '𫍵': 1, '𫍶': 1, '𫍷': 1, '𫍸': 1, '𫍹': 1, '𫍺': 1, '𫍻': 1, '𫍼': 1, '𫍽': 1, '𫍾': 1, '𫍿': 1, '𫎆': 1, '𫎌': 1, '𫎦': 1, '𫎧': 1, '𫎨': 1, '𫎩': 1, '𫎪': 1, '𫎫': 1, '𫎬': 1, '𫎭': 1, '𫎱': 1, '𫎳': 1, '𫎸': 1, '𫎺': 1, '𫏃': 1, '𫏆': 1, '𫏋': 1, '𫏌': 1, '𫏐': 1, '𫏑': 1, '𫏕': 1, '𫏞': 1, '𫏨': 1, '𫐄': 1, '𫐅': 1, '𫐆': 1, '𫐇': 1, '𫐈': 1, '𫐉': 1, '𫐊': 1, '𫐋': 1, '𫐌': 1, '𫐍': 1, '𫐎': 1, '𫐏': 1, '𫐐': 1, '𫐑': 1, '𫐒': 1, '𫐓': 1, '𫐔': 1, '𫐕': 1, '𫐖': 1, '𫐗': 1, '𫐘': 1, '𫐙': 1, '𫐷': 1, '𫑘': 1, '𫑡': 1, '𫑷': 1, '𫒊': 2, '𫒋': 2, '𫒞': 2, '𫒟': 2, '𫒡': 2, '𫒢': 2, '𫒷': 2, '𫓔': 2, '𫓥': 1, '𫓦': 1, '𫓧': 1, '𫓨': 1, '𫓩': 1, '𫓪': 1, '𫓫': 1, '𫓬': 1, '𫓭': 1, '𫓮': 1, '𫓯': 1, '𫓰': 1, '𫓱': 1, '𫓲': 1, '𫓳': 1, '𫓴': 1, '𫓵': 1, '𫓶': 1, '𫓷': 1, '𫓸': 1, '𫓹': 1, '𫓺': 1, '𫓻': 1, '𫓼': 1, '𫓽': 1, '𫓾': 1, '𫓿': 1, '𫔀': 1, '𫔁': 1, '𫔂': 1, '𫔃': 1, '𫔄': 1, '𫔅': 1, '𫔆': 1, '𫔇': 1, '𫔈': 1, '𫔉': 1, '𫔊': 1, '𫔋': 1, '𫔌': 1, '𫔍': 1, '𫔎': 1, '𫔏': 1, '𫔐': 1, '𫔑': 1, '𫔒': 1, '𫔓': 1, '𫔔': 1, '𫔕': 1, '𫔖': 1, '𫔘': 2, '𫔡': 2, '𫔭': 1, '𫔯': 1, '𫔰': 1, '𫔱': 1, '𫔲': 1, '𫔴': 1, '𫔵': 1, '𫔶': 1, '𫔽': 1, '𫕚': 1, '𫕥': 1, '𫕨': 1, '𫖃': 1, '𫖅': 1, '𫖇': 1, '𫖑': 1, '𫖒': 1, '𫖓': 1, '𫖔': 1, '𫖕': 1, '𫖖': 1, '𫖞': 2, '𫖪': 1, '𫖫': 1, '𫖬': 1, '𫖭': 1, '𫖮': 1, '𫖯': 1, '𫖰': 1, '𫖱': 1, '𫖲': 1, '𫖳': 1, '𫖴': 1, '𫖵': 1, '𫖶': 1, '𫖷': 1, '𫖸': 1, '𫖹': 1, '𫖺': 1, '𫗇': 1, '𫗈': 1, '𫗉': 1, '𫗊': 1, '𫗋': 1, '𫗑': 2, '𫗕': 2, '𫗚': 1, '𫗞': 1, '𫗟': 1, '𫗠': 1, '𫗡': 1, '𫗢': 1, '𫗣': 1, '𫗤': 1, '𫗥': 1, '𫗦': 1, '𫗧': 1, '𫗨': 1, '𫗩': 1, '𫗪': 1, '𫗫': 1, '𫗬': 1, '𫗭': 1, '𫗮': 1, '𫗯': 1, '𫗰': 1, '𫗱': 1, '𫗲': 1, '𫗳': 1, '𫗴': 1, '𫗵': 1, '𫗻': 2, '𫘋': 2, '𫘛': 1, '𫘜': 1, '𫘝': 1, '𫘞': 1, '𫘟': 1, '𫘠': 1, '𫘡': 1, '𫘣': 1, '𫘤': 1, '𫘥': 1, '𫘦': 1, '𫘧': 1, '𫘨': 1, '𫘩': 1, '𫘪': 1, '𫘫': 1, '𫘬': 1, '𫘭': 1, '𫘮': 1, '𫘯': 1, '𫘰': 1, '𫘱': 1, '𫘽': 1, '𫙂': 1, '𫚈': 1, '𫚉': 1, '𫚊': 1, '𫚋': 1, '𫚌': 1, '𫚍': 1, '𫚎': 1, '𫚏': 1, '𫚐': 1, '𫚑': 1, '𫚒': 1, '𫚓': 1, '𫚔': 1, '𫚕': 1, '𫚖': 1, '𫚗': 1, '𫚘': 1, '𫚙': 1, '𫚚': 1, '𫚛': 1, '𫚜': 1, '𫚝': 1, '𫚞': 1, '𫚟': 1, '𫚠': 1, '𫚡': 1, '𫚢': 1, '𫚣': 1, '𫚤': 1, '𫚥': 1, '𫚦': 1, '𫚧': 1, '𫚨': 1, '𫚩': 1, '𫚪': 1, '𫚫': 1, '𫚬': 1, '𫚭': 1, '𫛚': 1, '𫛛': 1, '𫛜': 1, '𫛝': 1, '𫛞': 1, '𫛟': 1, '𫛠': 1, '𫛡': 1, '𫛢': 1, '𫛣': 1, '𫛤': 1, '𫛥': 1, '𫛦': 1, '𫛧': 1, '𫛨': 1, '𫛩': 1, '𫛪': 1, '𫛫': 1, '𫛬': 1, '𫛭': 1, '𫛮': 1, '𫛯': 1, '𫛰': 1, '𫛱': 1, '𫛲': 1, '𫛳': 1, '𫛴': 1, '𫛵': 1, '𫛶': 1, '𫛷': 1, '𫛸': 1, '𫛹': 1, '𫛺': 1, '𫛻': 1, '𫛼': 1, '𫛽': 1, '𫛾': 1, '𫜀': 1, '𫜁': 1, '𫜂': 1, '𫜃': 1, '𫜄': 1, '𫜅': 1, '𫜊': 1, '𫜑': 1, '𫜒': 1, '𫜓': 1, '𫜔': 1, '𫜕': 1, '𫜙': 1, '𫜟': 1, '𫜦': 2, '𫜨': 1, '𫜩': 1, '𫜪': 1, '𫜫': 1, '𫜬': 1, '𫜭': 1, '𫜮': 1, '𫜯': 1, '𫜰': 1, '𫜲': 1, '𫜳': 1, '𫜷': 1, '𫝈': 1, '𫝋': 1, '𫝡': 1, '𫝦': 1, '𫝧': 1, '𫝨': 1, '𫝩': 1, '𫝪': 1, '𫝫': 1, '𫝬': 1, '𫝭': 1, '𫝮': 1, '𫝵': 1, '𫞅': 1, '𫞗': 1, '𫞚': 1, '𫞛': 1, '𫞝': 1, '𫞠': 1, '𫞡': 1, '𫞢': 1, '𫞣': 1, '𫞥': 1, '𫞦': 1, '𫞧': 1, '𫞨': 1, '𫞩': 1, '𫞷': 1, '𫟃': 1, '𫟄': 1, '𫟅': 1, '𫟆': 1, '𫟇': 1, '𫟑': 1, '𫟕': 1, '𫟞': 1, '𫟟': 1, '𫟠': 1, '𫟡': 1, '𫟢': 1, '𫟤': 1, '𫟥': 1, '𫟦': 1, '𫟫': 1, '𫟬': 1, '𫟲': 1, '𫟳': 1, '𫟴': 1, '𫟵': 1, '𫟶': 1, '𫟷': 1, '𫟸': 1, '𫟹': 1, '𫟺': 1, '𫟻': 1, '𫟼': 1, '𫟽': 1, '𫟾': 1, '𫟿': 1, '𫠀': 1, '𫠁': 1, '𫠂': 1, '𫠅': 1, '𫠆': 1, '𫠇': 1, '𫠈': 1, '𫠊': 1, '𫠋': 1, '𫠌': 1, '𫠏': 1, '𫠐': 1, '𫠑': 1, '𫠒': 1, '𫠖': 1, '𫠜': 1, '𫡬': 1, '𫡶': 1, '𫢒': 1, '𫢔': 1, '𫢘': 1, '𫢙': 1, '𫢜': 1, '𫢟': 1, '𫢨': 1, '𫢪': 1, '𫢬': 1, '𫢭': 1, '𫢲': 1, '𫢸': 1, '𫢹': 1, '𫢺': 1, '𫣉': 1, '𫣊': 1, '𫣛': 1, '𫣫': 1, '𫣴': 2, '𫤸': 1, '𫤽': 1, '𫥍': 1, '𫥔': 1, '𫥝': 2, '𫥳': 1, '𫥵': 1, '𫥺': 1, '𫥼': 1, '𫥽': 1, '𫦁': 1, '𫦅': 1, '𫦉': 1, '𫦋': 1, '𫦌': 1, '𫦔': 2, '𫦙': 2, '𫦩': 1, '𫦰': 1, '𫦳': 1, '𫦸': 2, '𫧃': 1, '𫧝': 2, '𫧮': 1, '𫧯': 1, '𫧷': 1, '𫧿': 1, '𫨆': 1, '𫨑': 2, '𫩕': 1, '𫩖': 1, '𫩚': 1, '𫩛': 1, '𫩤': 1, '𫩥': 1, '𫩩': 1, '𫩫': 1, '𫩯': 1, '𫩳': 1, '𫩸': 1, '𫩺': 1, '𫪀': 1, '𫪁': 1, '𫪂': 1, '𫪃': 1, '𫪄': 1, '𫪅': 1, '𫪑': 1, '𫪘': 1, '𫪚': 1, '𫪛': 2, '𫪧': 1, '𫪪': 1, '𫪺': 1, '𫪽': 1, '𫫇': 1, '𫫏': 1, '𫫦': 1, '𫫵': 1, '𫫾': 1, '𫬆': 2, '𫬐': 1, '𫬙': 1, '𫬟': 1, '𫬱': 2, '𫭞': 1, '𫭟': 1, '𫭢': 1, '𫭨': 1, '𫭪': 1, '𫭮': 1, '𫭯': 1, '𫭲': 1, '𫭼': 1, '𫮃': 1, '𫮅': 1, '𫮜': 1, '𫯒': 1, '𫯓': 2, '𫯥': 1, '𫯶': 1, '𫰂': 1, '𫰍': 1, '𫰛': 1, '𫰠': 1, '𫰡': 1, '𫰢': 1, '𫰣': 1, '𫰨': 1, '𫰰': 1, '𫰹': 1, '𫱕': 1, '𫱿': 1, '𫲉': 2, '𫲗': 1, '𫲴': 2, '𫲸': 1, '𫳃': 1, '𫴼': 1, '𫵵': 1, '𫵶': 1, '𫵷': 1, '𫵸': 1, '𫵹': 1, '𫶄': 1, '𫶅': 1, '𫶇': 1, '𫶊': 1, '𫶕': 1, '𫶦': 2, '𫶲': 1, '𫷅': 1, '𫷈': 1, '𫷉': 1, '𫷌': 1, '𫷘': 1, '𫷬': 1, '𫷮': 1, '𫷷': 1, '𫷹': 1, '𫷾': 1, '𫸩': 1, '𫹮': 1, '𫹴': 1, '𫹷': 1, '𫹼': 1, '𫹽': 1, '𫺁': 1, '𫺂': 1, '𫺆': 1, '𫺊': 1, '𫺌': 1, '𫺒': 1, '𫺓': 1, '𫺘': 1, '𫺤': 2, '𫺪': 1, '𫺫': 1, '𫺷': 1, '𫺹': 1, '𫻁': 1, '𫻇': 1, '𫻑': 2, '𫼗': 1, '𫼝': 1, '𫼣': 1, '𫼤': 1, '𫼥': 1, '𫼧': 1, '𫼫': 1, '𫼮': 1, '𫼱': 1, '𫼲': 1, '𫼵': 1, '𫼶': 1, '𫼽': 1, '𫼾': 1, '𫽀': 1, '𫽁': 1, '𫽇': 1, '𫽊': 1, '𫽋': 1, '𫽐': 1, '𫽔': 1, '𫽙': 1, '𫽢': 1, '𫽣': 1, '𫽥': 1, '𫽧': 1, '𫽫': 1, '𫽮': 1, '𫽲': 1, '𫽳': 1, '𫾁': 1, '𫾃': 1, '𫾉': 1, '𫾏': 1, '𫾡': 2, '𫾲': 1, '𫾳': 1, '𫿂': 1, '𫿗': 1, '𬀥': 1, '𬀩': 1, '𬀪': 1, '𬀮': 1, '𬀱': 1, '𬁑': 1, '𬁘': 1, '𬁳': 1, '𬁵': 1, '𬁸': 1, '𬁺': 1, '𬁽': 1, '𬂀': 1, '𬂂': 1, '𬂅': 1, '𬂉': 1, '𬂠': 1, '𬂩': 1, '𬂮': 1, '𬂰': 1, '𬂱': 1, '𬂻': 1, '𬃀': 1, '𬃊': 1, '𬃏': 1, '𬃘': 1, '𬃛': 1, '𬃦': 1, '𬃫': 1, '𬃮': 1, '𬃲': 1, '𬃳': 1, '𬄝': 2, '𬄞': 1, '𬄩': 1, '𬄬': 1, '𬅁': 2, '𬅢': 1, '𬅥': 1, '𬅫': 1, '𬆂': 1, '𬆉': 2, '𬆙': 1, '𬆦': 1, '𬆮': 1, '𬆾': 1, '𬇃': 1, '𬇄': 1, '𬇇': 1, '𬇕': 1, '𬇘': 1, '𬇙': 1, '𬇬': 1, '𬇰': 1, '𬇹': 1, '𬇼': 1, '𬈁': 1, '𬈏': 1, '𬈕': 1, '𬈜': 1, '𬈧': 1, '𬈱': 1, '𬈾': 1, '𬉂': 1, '𬉇': 1, '𬉋': 1, '𬉠': 1, '𬉤': 2, '𬉧': 2, '𬉼': 1, '𬊂': 1, '𬊈': 1, '𬊉': 1, '𬊍': 1, '𬊎': 1, '𬊖': 1, '𬊗': 1, '𬊜': 1, '𬊤': 1, '𬊦': 1, '𬊵': 1, '𬊶': 1, '𬊺': 1, '𬊾': 1, '𬊿': 2, '𬋃': 1, '𬋍': 1, '𬌝': 1, '𬌠': 1, '𬌦': 2, '𬌮': 1, '𬌴': 1, '𬌵': 1, '𬌷': 1, '𬍁': 2, '𬍙': 1, '𬍛': 1, '𬍡': 1, '𬍤': 1, '𬎆': 1, '𬎑': 1, '𬎟': 2, '𬎧': 1, '𬎬': 1, '𬏜': 1, '𬏟': 1, '𬏤': 1, '𬏦': 1, '𬏫': 1, '𬏮': 1, '𬏲': 2, '𬏷': 1, '𬐠': 1, '𬑆': 1, '𬑇': 1, '𬑍': 1, '𬑏': 1, '𬑒': 1, '𬑓': 1, '𬑕': 1, '𬑗': 1, '𬑙': 1, '𬑡': 2, '𬑧': 1, '𬒄': 1, '𬒆': 1, '𬒇': 1, '𬒈': 1, '𬒊': 1, '𬒍': 1, '𬒎': 1, '𬒒': 2, '𬒓': 1, '𬒕': 1, '𬒗': 1, '𬓠': 1, '𬓡': 2, '𬓫': 1, '𬓱': 1, '𬓸': 1, '𬓼': 1, '𬔯': 1, '𬔹': 1, '𬕂': 1, '𬕄': 1, '𬕊': 1, '𬕛': 1, '𬕜': 2, '𬕦': 1, '𬕬': 1, '𬖃': 1, '𬖑': 1, '𬖖': 1, '𬖘': 1, '𬖞': 1, '𬖟': 1, '𬖠': 1, '𬖮': 1, '𬖺': 1, '𬗈': 2, '𬗏': 2, '𬗺': 2, '𬘓': 1, '𬘔': 1, '𬘕': 1, '𬘖': 1, '𬘗': 1, '𬘘': 1, '𬘙': 1, '𬘚': 1, '𬘛': 1, '𬘜': 1, '𬘝': 1, '𬘞': 1, '𬘟': 1, '𬘠': 1, '𬘡': 1, '𬘢': 1, '𬘣': 1, '𬘤': 1, '𬘥': 1, '𬘦': 1, '𬘧': 1, '𬘨': 1, '𬘩': 1, '𬘪': 1, '𬘫': 1, '𬘬': 1, '𬘭': 1, '𬘮': 1, '𬘯': 1, '𬘰': 1, '𬘱': 1, '𬘲': 1, '𬘳': 1, '𬘴': 1, '𬘵': 1, '𬘶': 1, '𬘷': 1, '𬘸': 1, '𬘹': 1, '𬘺': 1, '𬘻': 1, '𬘼': 1, '𬘽': 1, '𬘾': 1, '𬘿': 1, '𬙀': 1, '𬙁': 1, '𬙂': 1, '𬙃': 1, '𬙄': 1, '𬙅': 1, '𬙆': 1, '𬙇': 1, '𬙈': 1, '𬙉': 1, '𬙊': 1, '𬙋': 1, '𬙎': 1, '𬙏': 1, '𬙔': 2, '𬙝': 1, '𬙪': 1, '𬙫': 1, '𬙭': 1, '𬚄': 1, '𬛕': 2, '𬛹': 1, '𬛼': 1, '𬜔': 1, '𬜥': 1, '𬜧': 1, '𬜨': 1, '𬜬': 1, '𬜯': 1, '𬜸': 1, '𬜺': 1, '𬜾': 1, '𬜿': 1, '𬝁': 1, '𬝃': 1, '𬝊': 1, '𬝋': 1, '𬝖': 1, '𬝠': 1, '𬝯': 1, '𬝴': 1, '𬞋': 1, '𬞕': 1, '𬞘': 1, '𬞟': 1, '𬞣': 1, '𬞫': 1, '𬞼': 2, '𬟁': 1, '𬟪': 1, '𬟺': 1, '𬟽': 1, '𬠃': 1, '𬠅': 1, '𬠈': 1, '𬠐': 2, '𬠠': 1, '𬠱': 1, '𬠷': 1, '𬡇': 1, '𬡍': 1, '𬡎': 1, '𬡒': 1, '𬡓': 1, '𬡔': 1, '𬡕': 1, '𬡠': 1, '𬡦': 1, '𬡱': 1, '𬡷': 1, '𬡻': 1, '𬢇': 1, '𬢈': 1, '𬢉': 1, '𬢊': 1, '𬢋': 1, '𬢌': 1, '𬢍': 1, '𬢎': 1, '𬢏': 1, '𬢐': 1, '𬢑': 1, '𬢒': 1, '𬢓': 1, '𬢔': 1, '𬢕': 1, '𬢪': 1, '𬢯': 1, '𬢳': 1, '𬣀': 1, '𬣍': 2, '𬣘': 2, '𬣙': 1, '𬣚': 1, '𬣛': 1, '𬣜': 1, '𬣝': 1, '𬣞': 1, '𬣟': 1, '𬣠': 1, '𬣡': 1, '𬣢': 1, '𬣣': 1, '𬣤': 1, '𬣥': 1, '𬣦': 1, '𬣧': 1, '𬣨': 1, '𬣩': 1, '𬣪': 1, '𬣫': 1, '𬣬': 1, '𬣭': 1, '𬣮': 1, '𬣯': 1, '𬣰': 1, '𬣱': 1, '𬣲': 1, '𬣳': 1, '𬣴': 1, '𬣵': 1, '𬣶': 1, '𬣷': 1, '𬣸': 1, '𬣹': 1, '𬣺': 1, '𬣻': 1, '𬣼': 1, '𬣽': 1, '𬣾': 1, '𬣿': 1, '𬤀': 1, '𬤁': 1, '𬤂': 1, '𬤃': 1, '𬤄': 1, '𬤅': 1, '𬤆': 1, '𬤇': 1, '𬤈': 1, '𬤉': 1, '𬤊': 1, '𬤋': 1, '𬤌': 1, '𬤍': 1, '𬤎': 1, '𬤏': 1, '𬤐': 1, '𬤑': 1, '𬤒': 1, '𬤓': 1, '𬤔': 1, '𬤕': 1, '𬤖': 1, '𬤗': 1, '𬤘': 1, '𬤙': 1, '𬤚': 1, '𬤛': 1, '𬤜': 1, '𬤝': 1, '𬤞': 1, '𬤟': 1, '𬤠': 1, '𬤡': 1, '𬤢': 1, '𬤣': 1, '𬤤': 1, '𬤥': 1, '𬤦': 1, '𬤧': 1, '𬤨': 1, '𬤩': 1, '𬤪': 1, '𬤫': 1, '𬤬': 1, '𬤭': 1, '𬤮': 1, '𬤯': 1, '𬤰': 1, '𬤱': 1, '𬤷': 1, '𬥄': 1, '𬥈': 1, '𬥲': 2, '𬥳': 1, '𬥴': 1, '𬥵': 1, '𬥶': 1, '𬥷': 1, '𬥸': 1, '𬥹': 1, '𬥺': 1, '𬥻': 1, '𬥼': 1, '𬥽': 1, '𬥾': 1, '𬥿': 1, '𬦀': 1, '𬦅': 1, '𬦆': 1, '𬦣': 1, '𬦥': 1, '𬦧': 1, '𬦩': 1, '𬦫': 1, '𬦯': 1, '𬦴': 1, '𬦵': 1, '𬦹': 1, '𬦻': 1, '𬦾': 1, '𬧀': 1, '𬧃': 1, '𬧑': 1, '𬧔': 1, '𬧙': 2, '𬧚': 1, '𬧛': 1, '𬧢': 1, '𬧤': 1, '𬧩': 1, '𬨁': 1, '𬨂': 1, '𬨃': 1, '𬨄': 1, '𬨅': 1, '𬨆': 1, '𬨇': 1, '𬨈': 1, '𬨉': 1, '𬨋': 1, '𬨌': 1, '𬨍': 1, '𬨎': 1, '𬨏': 1, '𬨐': 1, '𬨑': 1, '𬨒': 1, '𬨓': 1, '𬨔': 1, '𬩎': 1, '𬩽': 1, '𬩾': 1, '𬪍': 1, '𬪧': 1, '𬪨': 1, '𬪩': 1, '𬪫': 1, '𬪯': 1, '𬪺': 1, '𬫉': 2, '𬫍': 2, '𬬇': 1, '𬬧': 1, '𬬨': 1, '𬬩': 1, '𬬪': 1, '𬬫': 1, '𬬬': 1, '𬬭': 1, '𬬮': 1, '𬬯': 1, '𬬰': 1, '𬬱': 1, '𬬲': 1, '𬬳': 1, '𬬴': 1, '𬬵': 1, '𬬶': 1, '𬬷': 1, '𬬸': 1, '𬬹': 1, '𬬺': 1, '𬬻': 1, '𬬼': 1, '𬬽': 1, '𬬾': 1, '𬬿': 1, '𬭀': 1, '𬭁': 1, '𬭂': 1, '𬭃': 1, '𬭅': 1, '𬭆': 1, '𬭇': 1, '𬭈': 1, '𬭉': 1, '𬭊': 1, '𬭋': 1, '𬭌': 1, '𬭍': 1, '𬭎': 1, '𬭏': 1, '𬭐': 1, '𬭑': 1, '𬭓': 1, '𬭔': 1, '𬭕': 1, '𬭖': 1, '𬭗': 1, '𬭘': 1, '𬭙': 1, '𬭚': 1, '𬭛': 1, '𬭜': 1, '𬭝': 1, '𬭞': 1, '𬭟': 1, '𬭠': 1, '𬭡': 1, '𬭢': 1, '𬭣': 1, '𬭤': 1, '𬭥': 1, '𬭦': 1, '𬭨': 1, '𬭩': 1, '𬭪': 1, '𬭫': 1, '𬭬': 1, '𬭭': 1, '𬭯': 1, '𬭰': 1, '𬭱': 1, '𬭲': 1, '𬭳': 1, '𬭴': 1, '𬭵': 1, '𬭶': 1, '𬭷': 1, '𬭸': 1, '𬭹': 1, '𬭺': 1, '𬭻': 1, '𬭼': 1, '𬭽': 1, '𬭾': 1, '𬭿': 1, '𬮀': 1, '𬮁': 1, '𬮂': 1, '𬮃': 1, '𬮄': 1, '𬮇': 2, '𬮍': 2, '𬮘': 1, '𬮙': 1, '𬮜': 1, '𬮝': 1, '𬮟': 1, '𬮠': 1, '𬮡': 1, '𬮢': 1, '𬮣': 1, '𬮤': 1, '𬮥': 1, '𬮧': 1, '𬮨': 1, '𬮩': 1, '𬮪': 1, '𬮬': 1, '𬮭': 1, '𬮮': 1, '𬮯': 1, '𬮰': 1, '𬮱': 1, '𬮲': 1, '𬮳': 1, '𬮴': 1, '𬮵': 1, '𬮸': 1, '𬮹': 1, '𬮺': 1, '𬮻': 1, '𬮿': 1, '𬯀': 1, '𬯅': 1, '𬯊': 1, '𬯎': 1, '𬯘': 2, '𬰡': 1, '𬰣': 1, '𬰤': 1, '𬰥': 1, '𬰱': 1, '𬰲': 1, '𬰳': 1, '𬰴': 1, '𬰵': 1, '𬰶': 1, '𬰷': 1, '𬰸': 1, '𬰺': 1, '𬱂': 2, '𬱈': 2, '𬱓': 1, '𬱔': 1, '𬱕': 1, '𬱖': 1, '𬱗': 1, '𬱘': 1, '𬱙': 1, '𬱚': 1, '𬱛': 1, '𬱜': 1, '𬱝': 1, '𬱞': 1, '𬱟': 1, '𬱠': 1, '𬱡': 1, '𬱢': 1, '𬱣': 1, '𬱤': 1, '𬱥': 1, '𬱦': 1, '𬱧': 1, '𬱨': 1, '𬱩': 1, '𬱪': 1, '𬱫': 1, '𬱬': 1, '𬱭': 1, '𬱮': 1, '𬱯': 1, '𬱰': 1, '𬱱': 1, '𬱲': 1, '𬱳': 1, '𬱵': 1, '𬱷': 1, '𬱸': 1, '𬱺': 1, '𬱼': 1, '𬱽': 1, '𬱾': 1, '𬱿': 1, '𬲀': 1, '𬲅': 1, '𬲆': 1, '𬲕': 1, '𬲚': 2, '𬲛': 2, '𬲥': 1, '𬲦': 1, '𬲧': 1, '𬲨': 1, '𬲩': 1, '𬲪': 1, '𬲫': 1, '𬲬': 1, '𬲭': 1, '𬲮': 1, '𬲯': 1, '𬲰': 1, '𬲱': 1, '𬲲': 1, '𬲳': 1, '𬲴': 1, '𬲵': 1, '𬲶': 1, '𬲷': 1, '𬲸': 1, '𬲹': 1, '𬲺': 1, '𬲻': 1, '𬲼': 1, '𬲽': 1, '𬲾': 1, '𬲿': 1, '𬳀': 1, '𬳁': 1, '𬳂': 1, '𬳃': 1, '𬳄': 1, '𬳅': 1, '𬳆': 1, '𬳇': 1, '𬳈': 1, '𬳉': 1, '𬳊': 1, '𬳋': 1, '𬳌': 1, '𬳍': 1, '𬳎': 1, '𬳐': 1, '𬳑': 1, '𬳒': 1, '𬳓': 1, '𬳔': 1, '𬳙': 1, '𬳟': 1, '𬳳': 1, '𬳴': 1, '𬳵': 1, '𬳶': 1, '𬳷': 1, '𬳸': 1, '𬳹': 1, '𬳺': 1, '𬳻': 1, '𬳼': 1, '𬳽': 1, '𬳾': 1, '𬳿': 1, '𬴀': 1, '𬴁': 1, '𬴂': 1, '𬴃': 1, '𬴄': 1, '𬴅': 1, '𬴆': 1, '𬴇': 1, '𬴈': 1, '𬴉': 1, '𬴊': 1, '𬴋': 1, '𬴌': 1, '𬴍': 1, '𬴎': 1, '𬴏': 1, '𬴐': 1, '𬴨': 1, '𬴩': 1, '𬵂': 2, '𬵃': 2, '𬵨': 2, '𬵮': 2, '𬶀': 1, '𬶁': 1, '𬶂': 1, '𬶃': 1, '𬶄': 1, '𬶅': 1, '𬶆': 1, '𬶇': 1, '𬶈': 1, '𬶉': 1, '𬶊': 1, '𬶋': 1, '𬶌': 1, '𬶍': 1, '𬶎': 1, '𬶏': 1, '𬶐': 1, '𬶑': 1, '𬶒': 1, '𬶓': 1, '𬶔': 1, '𬶕': 1, '𬶖': 1, '𬶗': 1, '𬶙': 1, '𬶚': 1, '𬶛': 1, '𬶜': 1, '𬶝': 1, '𬶞': 1, '𬶟': 1, '𬶠': 1, '𬶡': 1, '𬶢': 1, '𬶣': 1, '𬶤': 1, '𬶥': 1, '𬶦': 1, '𬶧': 1, '𬶨': 1, '𬶩': 1, '𬶪': 1, '𬶫': 1, '𬶬': 1, '𬶭': 1, '𬶮': 1, '𬶯': 1, '𬶰': 1, '𬶱': 1, '𬶲': 1, '𬶳': 1, '𬶴': 1, '𬶵': 1, '𬶶': 1, '𬶷': 1, '𬶸': 1, '𬶹': 1, '𬶺': 1, '𬶻': 1, '𬶼': 2, '𬷈': 2, '𬷕': 1, '𬷻': 1, '𬷼': 1, '𬷽': 1, '𬷾': 1, '𬷿': 1, '𬸀': 1, '𬸁': 1, '𬸂': 1, '𬸃': 1, '𬸄': 1, '𬸅': 1, '𬸆': 1, '𬸈': 1, '𬸉': 1, '𬸊': 1, '𬸋': 1, '𬸌': 1, '𬸍': 1, '𬸎': 1, '𬸏': 1, '𬸐': 1, '𬸑': 1, '𬸒': 1, '𬸓': 1, '𬸔': 1, '𬸕': 1, '𬸖': 1, '𬸗': 1, '𬸘': 1, '𬸙': 1, '𬸚': 1, '𬸛': 1, '𬸜': 1, '𬸝': 1, '𬸞': 1, '𬸟': 1, '𬸠': 1, '𬸡': 1, '𬸢': 1, '𬸣': 1, '𬸤': 1, '𬸥': 1, '𬸦': 1, '𬸧': 1, '𬸨': 1, '𬸩': 1, '𬸪': 1, '𬸫': 1, '𬸬': 1, '𬸭': 1, '𬸮': 1, '𬸯': 1, '𬸰': 1, '𬸱': 1, '𬸵': 1, '𬸶': 1, '𬸷': 1, '𬸸': 1, '𬸹': 1, '𬸾': 1, '𬹂': 2, '𬹅': 1, '𬹆': 1, '𬹇': 1, '𬹈': 1, '𬹉': 1, '𬹊': 1, '𬹋': 1, '𬹌': 1, '𬹍': 1, '𬹎': 1, '𬹕': 1, '𬹖': 1, '𬹗': 1, '𬹘': 1, '𬹣': 1, '𬹤': 1, '𬹭': 1, '𬹺': 1, '𬹻': 1, '𬹼': 1, '𬹽': 1, '𬹾': 1, '𬹿': 1, '𬺀': 1, '𬺁': 1, '𬺂': 1, '𬺃': 1, '𬺄': 1, '𬺅': 1, '𬺆': 1, '𬺇': 1, '𬺈': 1, '𬺉': 1, '𬺊': 1, '𬺋': 1, '𬺌': 1, '𬺍': 1, '𬺎': 1, '𬺏': 1, '𬺐': 1, '𬺑': 1, '𬺒': 1, '𬺓': 1, '𬺔': 1, '𬺕': 1, '𬺖': 1, '𬺛': 1, '𬺜': 1, '𬺝': 1, '𬺟': 1, '𬻮': 1, '𬾖': 1, '𬾣': 1, '𭂖': 2, '𭄛': 1, '𭇀': 1, '𭇉': 1, '𭇙': 1, '𭇜': 1, '𭇡': 1, '𭇯': 1, '𭇴': 1, '𭈈': 1, '𭈉': 1, '𭈜': 1, '𭈟': 1, '𭈮': 1, '𭉗': 1, '𭉨': 1, '𭉼': 1, '𭉾': 2, '𭊸': 1, '𭎂': 1, '𭎜': 1, '𭏦': 1, '𭏸': 1, '𭑙': 2, '𭑸': 1, '𭑹': 1, '𭓀': 1, '𭕆': 1, '𭗡': 2, '𭘓': 1, '𭘚': 1, '𭚦': 1, '𭜼': 2, '𭝋': 1, '𭝫': 1, '𭞄': 1, '𭠙': 1, '𭠽': 1, '𭡆': 1, '𭡜': 1, '𭡵': 1, '𭢋': 1, '𭢒': 2, '𭢕': 1, '𭢝': 1, '𭣇': 1, '𭣧': 1, '𭤎': 1, '𭤰': 1, '𭥓': 1, '𭧋': 1, '𭧒': 2, '𭧖': 2, '𭨡': 2, '𭩚': 1, '𭩛': 1, '𭩰': 1, '𭪆': 1, '𭫀': 1, '𭫙': 1, '𭫝': 1, '𭭈': 1, '𭰎': 1, '𭰒': 1, '𭰗': 1, '𭰥': 1, '𭱀': 1, '𭱊': 1, '𭱘': 2, '𭲫': 1, '𭴊': 1, '𭴳': 1, '𭶙': 2, '𭹜': 1, '𭹰': 2, '𭻍': 1, '𭻔': 1, '𮀡': 1, '𮀤': 1, '𮀪': 1, '𮀲': 1, '𮅎': 1, '𮆏': 1, '𮇔': 1, '𮇤': 1, '𮉠': 1, '𮉡': 1, '𮉢': 1, '𮉣': 1, '𮉤': 1, '𮉥': 1, '𮉧': 1, '𮉨': 1, '𮉩': 1, '𮉪': 1, '𮉫': 1, '𮉬': 1, '𮉭': 1, '𮉮': 1, '𮉯': 1, '𮌌': 1, '𮎍': 1, '𮏀': 1, '𮏺': 1, '𮐚': 1, '𮐨': 1, '𮔂': 1, '𮔅': 1, '𮔊': 1, '𮖁': 1, '𮖃': 1, '𮖱': 1, '𮙊': 1, '𮙋': 1, '𮛗': 1, '𮜗': 2, '𮜶': 1, '𮝴': 1, '𮝵': 1, '𮝷': 1, '𮝸': 1, '𮝹': 1, '𮝺': 1, '𮟽': 2, '𮠞': 1, '𮠳': 1, '𮡈': 2, '𮢅': 2, '𮢆': 2, '𮣲': 1, '𮣳': 1, '𮣴': 1, '𮣵': 1, '𮣶': 1, '𮤏': 2, '𮤒': 2, '𮤫': 1, '𮤬': 1, '𮤭': 1, '𮤮': 1, '𮤯': 1, '𮤲': 1, '𮤳': 1, '𮤶': 1, '𮤷': 1, '𮤸': 1, '𮦅': 1, '𮦗': 2, '𮦚': 1, '𮧴': 1, '𮧵': 1, '𮨭': 2, '𮨴': 1, '𮨵': 1, '𮨻': 2, '𮩛': 1, '𮩜': 1, '𮩝': 1, '𮩞': 1, '𮪡': 1, '𮪢': 1, '𮪣': 1, '𮪤': 1, '𮪥': 1, '𮫂': 1, '𮬛': 1, '𮬜': 1, '𮬝': 1, '𮬞': 1, '𮬟': 1, '𮬠': 1, '𮬡': 1, '𮬢': 1, '𮬣': 1, '𮬤': 1, '𮭡': 1, '𮭢': 1, '𮭤': 1, '𮭥': 1, '𮭦': 1, '𮭨': 1, '𮭪': 1, '𮭰': 1, '𮮅': 1, '𮮇': 1, '𮯙': 1, '𮯵': 1, '𮯸': 1, '𮯹': 1, '𮯻': 1, '𮰄': 1, '𮰉': 1, '𮰔': 1, '𮰠': 1, '𮰸': 1, '𮰻': 1, '𮰽': 1, '𮰾': 1, '𮰿': 1, '𮱁': 1, '𮱆': 1, '𮱇': 1, '𮱊': 1, '𮱐': 1, '𮱒': 1, '𮱔': 1, '𮱕': 1, '𮱚': 2, '𮱣': 2, '𮱦': 1, '𮱩': 1, '𮱯': 1, '𮱱': 2, '𮱵': 1, '𮲀': 1, '𮲁': 1, '𮲂': 1, '𮲃': 1, '𮲄': 1, '𮲅': 1, '𮲇': 1, '𮲏': 1, '𮲔': 1, '𮲛': 1, '𮲟': 1, '𮲨': 1, '𮲮': 1, '𮲰': 1, '𮲲': 1, '𮲶': 1, '𮲸': 1, '𮲺': 1, '𮳃': 1, '𮳅': 1, '𮳆': 1, '𮳈': 1, '𮳍': 1, '𮳏': 1, '𮳖': 1, '𮳗': 1, '𮳠': 1, '𮳢': 1, '𮳧': 1, '𮳬': 1, '𮳯': 1, '𮳱': 1, '𮳴': 1, '𮳶': 1, '𮳸': 1, '𮳺': 1, '𮴂': 1, '𮴅': 1, '𮴆': 1, '𮴇': 1, '𮴊': 1, '𮴌': 1, '𮴏': 1, '𮴑': 1, '𮴒': 1, '𮴓': 1, '𮴔': 1, '𮴗': 1, '𮴘': 1, '𮴚': 1, '𮴠': 1, '𮴥': 1, '𮴶': 1, '𮴿': 1, '𮵅': 1, '𮵆': 1, '𮵊': 1, '𮵙': 1, '𮵚': 1, '𮵠': 1, '𮵭': 1, '𮵮': 1, '𮵱': 1, '𮵿': 1, '𮶀': 1, '𮶁': 1, '𮶂': 1, '𮶅': 1, '𮶔': 1, '𮶝': 1, '𮶞': 1, '𮶩': 1, '𮶬': 1, '𮶳': 1, '𮶷': 1, '𮷁': 1, '𮷄': 1, '𮷅': 1, '𮷆': 1, '𮷇': 1, '𮷈': 1, '𮷉': 1, '𮷊': 1, '𮷖': 1, '𮷗': 1, '𮷙': 1, '𮷝': 1, '𮷥': 1, '𮷨': 1, '𮷵': 1, '𮷶': 1, '𮷷': 1, '𮷸': 1, '𮷹': 1, '𮷺': 1, '𮷻': 1, '𮷽': 1, '𮷿': 1, '𮸂': 1, '𮸃': 1, '𮸄': 1, '𮸅': 1, '𮸆': 1, '𮸈': 1, '𮸉': 1, '𮸊': 1, '𮸋': 1, '𮸌': 1, '𮸏': 1, '𮸐': 1, '𮸑': 1, '𮸒': 1, '𮸔': 1, '𮸕': 1, '𮸘': 1, '𮸙': 1, '𮸚': 1, '𮸝': 1, '𮸞': 1, '𮸟': 1, '𮸠': 1, '𮸣': 1, '𮸥': 1, '𮸦': 1, '𮸮': 1, '𮸶': 1, '𮸷': 1, '𮸻': 1, '𮸼': 1, '𮸽': 1, '𮸾': 2, '𮹀': 1, '𮹂': 1, '𮹄': 1, '𮹅': 1, '𮹉': 1, '𮹋': 1, '𮹌': 1, '𮹓': 1, '𮹕': 1, '𮹗': 1, '𮹙': 1, '𮹜': 1, '𮹝': 1, '𰀡': 1, '𰀢': 1, '𰁈': 1, '𰁜': 1, '𰁧': 1, '𰁸': 1, '𰁾': 1, '𰂁': 1, '𰂃': 1, '𰂋': 1, '𰂎': 1, '𰂏': 1, '𰂗': 1, '𰂜': 1, '𰂠': 2, '𰂦': 1, '𰂭': 1, '𰂴': 2, '𰂻': 1, '𰃆': 1, '𰃮': 1, '𰃳': 1, '𰃴': 2, '𰃶': 1, '𰃷': 1, '𰃻': 1, '𰃿': 1, '𰄁': 1, '𰄞': 1, '𰄭': 1, '𰅔': 1, '𰅥': 1, '𰅦': 1, '𰅻': 1, '𰆕': 1, '𰆙': 1, '𰆚': 1, '𰇀': 1, '𰇊': 1, '𰇎': 1, '𰇕': 1, '𰇖': 1, '𰇘': 1, '𰇠': 1, '𰇡': 1, '𰇣': 1, '𰇥': 1, '𰇲': 1, '𰇼': 1, '𰈆': 1, '𰈇': 1, '𰈊': 1, '𰈍': 1, '𰈓': 1, '𰈝': 2, '𰈮': 1, '𰈯': 1, '𰈶': 1, '𰉀': 2, '𰉁': 1, '𰉄': 1, '𰉘': 1, '𰉙': 1, '𰉚': 1, '𰉣': 1, '𰉥': 1, '𰉩': 1, '𰉪': 1, '𰉱': 1, '𰉽': 1, '𰊂': 1, '𰊅': 1, '𰊈': 1, '𰊑': 1, '𰊛': 1, '𰊟': 1, '𰊡': 1, '𰊢': 1, '𰋆': 2, '𰋖': 1, '𰋸': 1, '𰋹': 1, '𰋽': 1, '𰋾': 1, '𰌀': 1, '𰌂': 1, '𰌆': 1, '𰌇': 1, '𰌉': 1, '𰌙': 1, '𰌦': 1, '𰌷': 1, '𰎌': 1, '𰎎': 1, '𰎏': 1, '𰎐': 1, '𰎑': 1, '𰎔': 1, '𰎖': 1, '𰎛': 1, '𰎝': 1, '𰎞': 1, '𰎠': 1, '𰎢': 1, '𰎦': 1, '𰎫': 1, '𰎴': 1, '𰎷': 1, '𰎹': 1, '𰎼': 2, '𰏁': 1, '𰏓': 1, '𰏕': 1, '𰏜': 1, '𰏟': 1, '𰏲': 1, '𰏶': 1, '𰏼': 1, '𰏽': 1, '𰐚': 1, '𰐾': 1, '𰑁': 1, '𰑄': 1, '𰑅': 1, '𰑔': 1, '𰑕': 1, '𰑙': 1, '𰑟': 1, '𰑥': 1, '𰑧': 1, '𰑪': 1, '𰑫': 1, '𰑬': 1, '𰑵': 1, '𰑸': 1, '𰑿': 1, '𰒆': 1, '𰒒': 1, '𰒖': 1, '𰓄': 1, '𰓆': 1, '𰓔': 1, '𰓕': 1, '𰓗': 1, '𰓙': 1, '𰓜': 1, '𰓝': 1, '𰓟': 1, '𰓤': 1, '𰓧': 1, '𰓬': 1, '𰓱': 1, '𰓷': 1, '𰓻': 1, '𰓼': 1, '𰔇': 1, '𰔋': 1, '𰔠': 2, '𰔫': 2, '𰔲': 1, '𰔶': 1, '𰔺': 2, '𰕁': 1, '𰕅': 1, '𰕈': 1, '𰕐': 1, '𰕭': 1, '𰖈': 1, '𰖏': 1, '𰖚': 1, '𰖠': 1, '𰖩': 1, '𰖻': 2, '𰗅': 1, '𰗆': 1, '𰗓': 1, '𰗖': 1, '𰗘': 1, '𰗙': 1, '𰗚': 1, '𰗛': 1, '𰗜': 1, '𰗡': 1, '𰗢': 1, '𰗦': 1, '𰗨': 1, '𰗬': 1, '𰗵': 1, '𰗹': 1, '𰗺': 1, '𰘀': 1, '𰘅': 1, '𰘈': 1, '𰘓': 1, '𰘠': 1, '𰘣': 1, '𰘩': 1, '𰘯': 2, '𰘳': 1, '𰘶': 1, '𰘸': 1, '𰙋': 1, '𰙎': 1, '𰙑': 1, '𰙕': 1, '𰚂': 2, '𰚍': 1, '𰚔': 1, '𰚣': 2, '𰚦': 1, '𰚪': 1, '𰚬': 1, '𰚱': 1, '𰛉': 1, '𰛊': 1, '𰛏': 1, '𰛒': 1, '𰛛': 1, '𰛡': 1, '𰛣': 1, '𰛤': 1, '𰛥': 1, '𰛦': 1, '𰛨': 1, '𰛩': 1, '𰛪': 1, '𰛮': 1, '𰛱': 1, '𰛲': 1, '𰛵': 1, '𰛺': 1, '𰛻': 1, '𰛽': 1, '𰜐': 1, '𰜜': 1, '𰜝': 1, '𰜢': 1, '𰜨': 1, '𰜳': 1, '𰝅': 1, '𰝋': 1, '𰝍': 1, '𰝗': 1, '𰝜': 2, '𰝞': 1, '𰝟': 1, '𰝢': 2, '𰝤': 1, '𰝾': 1, '𰞇': 1, '𰞉': 1, '𰞍': 1, '𰞤': 1, '𰞲': 1, '𰞳': 1, '𰞷': 1, '𰞻': 1, '𰟄': 1, '𰟘': 1, '𰟫': 2, '𰠛': 1, '𰠫': 1, '𰠲': 1, '𰠴': 1, '𰠹': 1, '𰡄': 1, '𰡉': 1, '𰡊': 1, '𰡋': 1, '𰡎': 1, '𰡏': 1, '𰡐': 1, '𰡓': 2, '𰡔': 1, '𰡞': 1, '𰡢': 1, '𰡩': 1, '𰡰': 1, '𰡵': 1, '𰡻': 1, '𰡽': 1, '𰢄': 1, '𰢢': 1, '𰢤': 1, '𰢦': 1, '𰣢': 1, '𰣦': 1, '𰣩': 1, '𰣫': 1, '𰣬': 1, '𰣯': 1, '𰣶': 1, '𰣼': 1, '𰣽': 1, '𰤓': 1, '𰤕': 1, '𰤨': 1, '𰤫': 1, '𰤬': 1, '𰤽': 1, '𰥊': 1, '𰥒': 1, '𰥛': 1, '𰥞': 1, '𰥠': 1, '𰥢': 1, '𰥣': 1, '𰥨': 1, '𰥪': 1, '𰥭': 1, '𰥹': 1, '𰦔': 1, '𰦜': 1, '𰦦': 1, '𰦨': 1, '𰦭': 1, '𰦰': 1, '𰦴': 1, '𰦷': 1, '𰦾': 1, '𰦿': 1, '𰧃': 1, '𰧇': 1, '𰧈': 1, '𰧉': 1, '𰧎': 1, '𰧔': 1, '𰧘': 1, '𰧰': 1, '𰧻': 1, '𰧾': 1, '𰨖': 1, '𰨜': 1, '𰨦': 1, '𰨳': 1, '𰩅': 1, '𰩏': 1, '𰩓': 1, '𰩧': 1, '𰩮': 1, '𰩲': 1, '𰩸': 1, '𰩹': 1, '𰩺': 1, '𰩻': 1, '𰪊': 1, '𰪏': 1, '𰪣': 1, '𰪪': 1, '𰪫': 1, '𰪭': 1, '𰪶': 1, '𰪼': 1, '𰪿': 1, '𰫆': 2, '𰫋': 1, '𰫏': 2, '𰫖': 1, '𰫛': 2, '𰫳': 2, '𰫼': 1, '𰫽': 1, '𰫿': 1, '𰬀': 1, '𰬁': 1, '𰬂': 1, '𰬃': 1, '𰬅': 1, '𰬆': 1, '𰬇': 1, '𰬈': 1, '𰬉': 1, '𰬋': 1, '𰬌': 1, '𰬍': 1, '𰬎': 1, '𰬏': 1, '𰬐': 1, '𰬑': 1, '𰬒': 1, '𰬓': 1, '𰬔': 1, '𰬖': 1, '𰬗': 1, '𰬘': 1, '𰬙': 1, '𰬚': 1, '𰬛': 1, '𰬜': 1, '𰬝': 1, '𰬞': 1, '𰬟': 1, '𰬠': 1, '𰬡': 1, '𰬢': 1, '𰬣': 1, '𰬤': 1, '𰬥': 1, '𰬦': 1, '𰬧': 1, '𰬨': 1, '𰬩': 1, '𰬪': 1, '𰬫': 1, '𰬬': 1, '𰬭': 1, '𰬮': 1, '𰬯': 1, '𰬰': 1, '𰬱': 1, '𰬲': 1, '𰬳': 1, '𰬴': 1, '𰬵': 1, '𰬶': 1, '𰬷': 1, '𰬸': 1, '𰬹': 1, '𰬺': 1, '𰬻': 1, '𰬼': 1, '𰬽': 1, '𰬾': 1, '𰬿': 1, '𰭀': 1, '𰭁': 1, '𰭄': 1, '𰭔': 1, '𰭗': 1, '𰭚': 1, '𰭢': 1, '𰭣': 1, '𰭹': 1, '𰮅': 1, '𰮇': 1, '𰮙': 1, '𰮝': 1, '𰮭': 1, '𰮲': 1, '𰯂': 1, '𰯋': 1, '𰯎': 1, '𰯲': 2, '𰰆': 1, '𰰋': 1, '𰰌': 1, '𰰏': 1, '𰰑': 1, '𰰠': 1, '𰰢': 1, '𰰤': 1, '𰰨': 1, '𰰮': 1, '𰰱': 1, '𰰳': 1, '𰰴': 1, '𰰵': 1, '𰰶': 1, '𰰷': 1, '𰰹': 1, '𰰺': 1, '𰰾': 1, '𰰿': 1, '𰱀': 1, '𰱇': 1, '𰱈': 1, '𰱉': 1, '𰱊': 1, '𰱌': 1, '𰱍': 1, '𰱐': 1, '𰱑': 1, '𰱛': 1, '𰱝': 1, '𰱟': 1, '𰱦': 1, '𰱩': 1, '𰱮': 1, '𰱯': 1, '𰱱': 1, '𰱲': 1, '𰱾': 1, '𰲁': 1, '𰲂': 1, '𰲒': 1, '𰲖': 1, '𰲟': 1, '𰲠': 1, '𰲫': 1, '𰲬': 1, '𰲮': 1, '𰲯': 1, '𰲰': 1, '𰲲': 1, '𰲳': 1, '𰲴': 1, '𰲵': 1, '𰲶': 1, '𰲸': 1, '𰲹': 1, '𰲺': 1, '𰲻': 1, '𰳁': 1, '𰳂': 1, '𰳄': 1, '𰳆': 1, '𰳊': 1, '𰳗': 1, '𰳚': 1, '𰳲': 1, '𰳵': 1, '𰳸': 1, '𰳹': 1, '𰳺': 1, '𰳻': 1, '𰳼': 1, '𰴂': 1, '𰴏': 2, '𰴕': 1, '𰴖': 1, '𰴗': 1, '𰴘': 1, '𰴙': 1, '𰴚': 1, '𰴛': 1, '𰴜': 1, '𰴝': 1, '𰴞': 1, '𰴢': 1, '𰴣': 1, '𰴤': 1, '𰴥': 1, '𰴦': 2, '𰴯': 1, '𰴽': 2, '𰵊': 1, '𰵌': 1, '𰵍': 1, '𰵎': 1, '𰵏': 1, '𰵐': 1, '𰵑': 1, '𰵒': 1, '𰵓': 1, '𰵔': 1, '𰵖': 1, '𰵗': 1, '𰵘': 1, '𰵙': 1, '𰵚': 1, '𰵛': 1, '𰵜': 1, '𰵝': 1, '𰵞': 1, '𰵠': 1, '𰵡': 1, '𰵢': 1, '𰵣': 1, '𰵤': 1, '𰵥': 1, '𰵦': 1, '𰵧': 1, '𰵨': 1, '𰵩': 1, '𰵪': 1, '𰵫': 1, '𰵬': 1, '𰵭': 1, '𰵮': 1, '𰵯': 1, '𰵰': 1, '𰵱': 1, '𰵲': 1, '𰵳': 1, '𰵴': 1, '𰵵': 1, '𰵶': 1, '𰵷': 1, '𰵸': 1, '𰵹': 1, '𰵺': 1, '𰵻': 1, '𰵼': 1, '𰵽': 1, '𰵾': 1, '𰵿': 1, '𰶀': 1, '𰶁': 1, '𰶂': 1, '𰶃': 1, '𰶄': 1, '𰶅': 1, '𰶆': 1, '𰶇': 1, '𰶈': 1, '𰶉': 1, '𰶊': 1, '𰶋': 1, '𰶌': 1, '𰶍': 1, '𰶎': 1, '𰶏': 1, '𰶑': 1, '𰶔': 1, '𰶨': 1, '𰶬': 1, '𰷞': 1, '𰷠': 1, '𰷡': 1, '𰷢': 1, '𰷤': 1, '𰷥': 1, '𰷦': 1, '𰷧': 1, '𰷨': 1, '𰷩': 1, '𰷪': 1, '𰷫': 1, '𰷬': 1, '𰷭': 1, '𰷮': 1, '𰷴': 1, '𰷵': 1, '𰷶': 1, '𰷸': 1, '𰸇': 1, '𰸈': 1, '𰸊': 1, '𰸎': 1, '𰸐': 1, '𰸔': 1, '𰸚': 1, '𰸛': 1, '𰸞': 1, '𰸦': 1, '𰹀': 1, '𰹈': 2, '𰹯': 1, '𰹱': 1, '𰹲': 1, '𰹳': 1, '𰹴': 1, '𰹵': 1, '𰹶': 1, '𰹷': 1, '𰹸': 1, '𰹺': 1, '𰹻': 1, '𰹼': 1, '𰹽': 1, '𰹾': 1, '𰹿': 1, '𰺀': 1, '𰺁': 1, '𰺂': 1, '𰺃': 1, '𰺄': 1, '𰺅': 1, '𰺆': 1, '𰺇': 1, '𰺈': 1, '𰺉': 1, '𰺊': 1, '𰺋': 1, '𰺌': 1, '𰺍': 1, '𰺎': 1, '𰺏': 1, '𰺐': 1, '𰺑': 1, '𰺒': 1, '𰺓': 1, '𰺔': 1, '𰺕': 1, '𰺖': 1, '𰺗': 1, '𰺘': 1, '𰺙': 1, '𰺚': 1, '𰺛': 1, '𰺜': 1, '𰺝': 1, '𰺞': 1, '𰺟': 1, '𰺠': 1, '𰺡': 1, '𰺢': 1, '𰺣': 1, '𰺤': 1, '𰺨': 1, '𰺭': 1, '𰺲': 1, '𰺷': 1, '𰻆': 1, '𰻝': 1, '𰻞': 2, '𰻡': 1, '𰻦': 1, '𰻨': 1, '𰻮': 1, '𰻳': 1, '𰼅': 1, '𰼋': 1, '𰼏': 1, '𰼑': 1, '𰼻': 1, '𰽕': 1, '𰽖': 1, '𰽗': 1, '𰽘': 1, '𰽚': 1, '𰽛': 1, '𰽜': 1, '𰽝': 1, '𰽞': 1, '𰽠': 1, '𰽡': 1, '𰽢': 1, '𰽣': 1, '𰽥': 1, '𰽦': 1, '𰽧': 1, '𰽨': 1, '𰽩': 1, '𰽫': 1, '𰽬': 1, '𰽭': 1, '𰽮': 1, '𰽯': 1, '𰽰': 1, '𰽱': 1, '𰽲': 1, '𰽳': 1, '𰽴': 1, '𰽵': 1, '𰽶': 1, '𰽷': 1, '𰽸': 1, '𰽹': 1, '𰽺': 1, '𰽻': 1, '𰽼': 1, '𰽽': 1, '𰽾': 1, '𰽿': 1, '𰾀': 1, '𰾁': 1, '𰾃': 1, '𰾄': 1, '𰾅': 1, '𰾆': 1, '𰾇': 1, '𰾈': 1, '𰾉': 1, '𰾊': 1, '𰾋': 1, '𰾌': 1, '𰾍': 1, '𰾎': 1, '𰾏': 1, '𰾐': 1, '𰾑': 1, '𰾒': 1, '𰾓': 1, '𰾕': 1, '𰾖': 1, '𰾗': 1, '𰾘': 1, '𰾙': 1, '𰾚': 1, '𰾛': 1, '𰾜': 1, '𰾝': 1, '𰾞': 1, '𰾟': 1, '𰾡': 1, '𰾢': 1, '𰾣': 1, '𰾤': 1, '𰾥': 1, '𰾦': 1, '𰾧': 1, '𰾨': 1, '𰾩': 1, '𰾪': 1, '𰾫': 1, '𰾬': 1, '𰾭': 1, '𰾮': 1, '𰾯': 1, '𰾰': 1, '𰾱': 1, '𰾲': 1, '𰾳': 1, '𰾴': 1, '𰾵': 1, '𰾶': 1, '𰾷': 1, '𰾸': 1, '𰾹': 1, '𰾺': 1, '𰾻': 1, '𰾼': 1, '𰾽': 1, '𰾾': 1, '𰾿': 1, '𰿀': 1, '𰿁': 1, '𰿂': 1, '𰿃': 1, '𰿄': 1, '𰿅': 1, '𰿆': 1, '𰿇': 1, '𰿈': 1, '𰿉': 1, '𰿊': 1, '𰿖': 1, '𰿢': 2, '𰿥': 1, '𰿦': 1, '𰿧': 1, '𰿨': 1, '𰿩': 1, '𰿪': 1, '𰿫': 1, '𰿬': 1, '𰿭': 1, '𰿯': 1, '𰿰': 1, '𰿳': 1, '𰿴': 1, '𰿵': 1, '𰿸': 1, '𰿹': 1, '𰿺': 1, '𰿻': 1, '𰿾': 1, '𱀑': 1, '𱀡': 1, '𱁒': 1, '𱁞': 1, '𱁱': 1, '𱁳': 1, '𱁴': 1, '𱁶': 1, '𱁷': 1, '𱁹': 1, '𱁺': 1, '𱁽': 1, '𱁾': 1, '𱂃': 1, '𱂄': 1, '𱂅': 1, '𱂆': 1, '𱂇': 1, '𱂈': 1, '𱂉': 1, '𱂊': 1, '𱂋': 1, '𱂌': 1, '𱂍': 1, '𱂎': 1, '𱂐': 1, '𱂠': 1, '𱂡': 1, '𱂢': 1, '𱂣': 1, '𱂤': 1, '𱂥': 1, '𱂦': 1, '𱂧': 1, '𱂨': 1, '𱂩': 1, '𱂫': 1, '𱂬': 1, '𱂭': 1, '𱂮': 1, '𱂯': 1, '𱂰': 1, '𱂱': 1, '𱂲': 1, '𱂳': 1, '𱂴': 1, '𱂵': 1, '𱂶': 1, '𱂷': 1, '𱂸': 1, '𱂺': 1, '𱂻': 1, '𱃔': 1, '𱃕': 1, '𱃖': 1, '𱃗': 1, '𱃘': 1, '𱃙': 1, '𱃚': 1, '𱃛': 1, '𱃜': 1, '𱃝': 1, '𱃞': 1, '𱃟': 1, '𱃠': 1, '𱃡': 2, '𱃢': 2, '𱃪': 2, '𱃱': 1, '𱃲': 1, '𱃳': 1, '𱃴': 1, '𱃵': 1, '𱃷': 1, '𱃸': 1, '𱃹': 1, '𱃺': 1, '𱃼': 1, '𱃽': 1, '𱃾': 1, '𱃿': 1, '𱄀': 1, '𱄁': 1, '𱄂': 1, '𱄃': 1, '𱄄': 1, '𱄅': 1, '𱄆': 1, '𱄇': 1, '𱄈': 1, '𱄉': 1, '𱄊': 1, '𱄼': 1, '𱄽': 1, '𱄾': 1, '𱄿': 1, '𱅀': 1, '𱅁': 1, '𱅂': 1, '𱅃': 1, '𱅄': 1, '𱅅': 1, '𱅇': 1, '𱅈': 1, '𱅉': 1, '𱅊': 1, '𱅋': 1, '𱅍': 1, '𱅎': 1, '𱅏': 1, '𱅐': 1, '𱅒': 1, '𱅓': 1, '𱅔': 1, '𱅕': 1, '𱅖': 1, '𱅗': 1, '𱅘': 1, '𱅙': 1, '𱅚': 1, '𱅛': 1, '𱅜': 1, '𱅝': 1, '𱅞': 1, '𱅟': 1, '𱅠': 1, '𱅡': 1, '𱅢': 1, '𱅣': 1, '𱅤': 1, '𱅥': 1, '𱅦': 1, '𱅧': 1, '𱅨': 1, '𱅩': 1, '𱅪': 1, '𱅫': 1, '𱅬': 1, '𱅮': 1, '𱆀': 1, '𱆁': 1, '𱆃': 1, '𱆄': 1, '𱆅': 1, '𱆆': 1, '𱆈': 1, '𱆌': 1, '𱆍': 1, '𱆖': 1, '𱆙': 1, '𱆚': 1, '𱆛': 1, '𱆥': 2, '𱇋': 2, '𱇍': 1, '𱇎': 1, '𱇏': 1, '𱇐': 1, '𱇑': 1, '𱇒': 1, '𱇓': 1, '𱇔': 1, '𱇕': 1, '𱇖': 1, '𱇗': 1, '𱇘': 1, '𱇙': 1, '𱇚': 1, '𱇛': 1, '𱇜': 1, '𱇝': 1, '𱇞': 1, '𱇟': 1, '𱇠': 1, '𱇡': 1, '𱇢': 1, '𱇣': 1, '𱇤': 1, '𱇥': 1, '𱇦': 1, '𱇧': 1, '𱇨': 1, '𱇩': 1, '𱇪': 1, '𱇫': 1, '𱇬': 1, '𱇭': 1, '𱇮': 1, '𱇯': 1, '𱇰': 1, '𱇱': 1, '𱇲': 1, '𱇳': 1, '𱇴': 1, '𱇵': 1, '𱇶': 1, '𱇷': 1, '𱇸': 1, '𱇹': 1, '𱇺': 1, '𱇻': 1, '𱇼': 1, '𱇽': 1, '𱇾': 1, '𱇿': 1, '𱈀': 1, '𱈁': 1, '𱈂': 1, '𱈃': 1, '𱈄': 1, '𱈅': 1, '𱈆': 1, '𱈇': 1, '𱈈': 1, '𱈉': 1, '𱈊': 1, '𱈋': 1, '𱈌': 1, '𱈍': 1, '𱈎': 1, '𱈏': 1, '𱈐': 1, '𱈑': 1, '𱈒': 1, '𱈓': 1, '𱈔': 1, '𱈕': 1, '𱈖': 1, '𱈗': 1, '𱈘': 1, '𱈙': 1, '𱈚': 1, '𱈛': 1, '𱈜': 1, '𱉇': 1, '𱉈': 1, '𱉉': 1, '𱉊': 1, '𱉋': 1, '𱉌': 1, '𱉍': 1, '𱉎': 1, '𱉏': 1, '𱉐': 1, '𱉑': 1, '𱉒': 1, '𱉓': 1, '𱉔': 1, '𱉕': 1, '𱉖': 1, '𱉗': 1, '𱉘': 1, '𱉙': 1, '𱉚': 1, '𱉛': 1, '𱉜': 1, '𱉝': 1, '𱉞': 1, '𱉟': 1, '𱉠': 1, '𱉡': 1, '𱉢': 1, '𱉣': 1, '𱉤': 1, '𱉥': 1, '𱉦': 1, '𱉧': 1, '𱉨': 1, '𱉩': 1, '𱉪': 1, '𱉫': 1, '𱉬': 1, '𱉭': 1, '𱉮': 1, '𱉯': 1, '𱉱': 1, '𱉲': 1, '𱉳': 1, '𱉴': 1, '𱉵': 1, '𱉶': 1, '𱉷': 1, '𱉸': 1, '𱉹': 1, '𱉺': 1, '𱉻': 1, '𱉼': 1, '𱉽': 1, '𱉾': 1, '𱉿': 1, '𱊀': 1, '𱊁': 1, '𱊂': 1, '𱊃': 1, '𱊄': 1, '𱊅': 1, '𱊆': 1, '𱊇': 1, '𱊈': 1, '𱊉': 1, '𱊊': 1, '𱊋': 1, '𱊌': 1, '𱊍': 1, '𱊎': 1, '𱊏': 1, '𱊐': 1, '𱊑': 1, '𱊒': 1, '𱊓': 1, '𱊔': 1, '𱊕': 1, '𱊖': 1, '𱊗': 1, '𱊘': 1, '𱊙': 1, '𱊚': 1, '𱊛': 1, '𱊜': 1, '𱊝': 1, '𱊞': 1, '𱊟': 1, '𱊠': 1, '𱊡': 1, '𱊢': 1, '𱊣': 1, '𱊤': 1, '𱊥': 1, '𱊦': 1, '𱊧': 1, '𱊨': 1, '𱊩': 1, '𱊪': 1, '𱊫': 1, '𱊬': 1, '𱊭': 1, '𱊮': 1, '𱊯': 1, '𱊰': 1, '𱊱': 1, '𱊲': 1, '𱊳': 1, '𱊴': 1, '𱊵': 1, '𱊺': 1, '𱊻': 1, '𱊼': 1, '𱊽': 1, '𱋂': 2, '𱋄': 1, '𱋅': 1, '𱋆': 1, '𱋇': 1, '𱋈': 1, '𱋉': 1, '𱋊': 1, '𱋋': 1, '𱋌': 1, '𱋍': 1, '𱋎': 1, '𱋐': 1, '𱋑': 1, '𱋓': 1, '𱋔': 1, '𱋕': 1, '𱋖': 1, '𱋗': 1, '𱋘': 1, '𱋙': 1, '𱋚': 1, '𱋜': 1, '𱋝': 1, '𱋟': 1, '𱋠': 1, '𱋡': 1, '𱋢': 1, '𱋣': 1, '𱋤': 1, '𱋥': 1, '𱋦': 1, '𱋨': 1, '𱋪': 1, '𱋫': 1, '𱋬': 1, '𱋭': 1, '𱋮': 1, '𱋱': 1, '𱋴': 1, '𱋶': 1, '𱋾': 1, '𱋿': 1, '𱌀': 1, '𱌁': 1, '𱌃': 1, '𱌄': 1, '𱌅': 1, '𱌆': 1, '𱌇': 1, '𱌈': 1, '𱌉': 1, '𱌊': 1, '𱌏': 1, '𱌕': 1, '𱌖': 1, '𱌗': 1, '𱌘': 1, '𱌙': 1, '𱌫': 1, '𱌬': 1, '𱌭': 1, '𱌮': 1, '𱌯': 1, '𱌰': 1, '𱌱': 1, '𱌲': 1, '𱌳': 1, '𱌴': 1, '𱌵': 1, '𱌶': 1, '𱌷': 1, '𱌸': 1, '𱌹': 1, '𱌺': 1, '𱌼': 1, '𱌽': 1, '𱍁': 1, '𱍂': 1, '𱍄': 1, '𱍅': 1, '𱍆': 1, '𱍇': 1, '𱍈': 1, '𱍉': 1, '𱙋': 1, '𱵭': 2, '𲋢': 1, } def detect_chinese_category(phrase: str) -> int: ''' New function using Unihan data to guess whether a text is simplified Chinese, traditional Chinese, both, or something rare like a mixture of exclusively simplified with exclusively traditional characters. Meaning of the bits in the category value returned by this function: 1 = 1 << 0 simplified Chinese 2 = 1 << 1 traditional Chinese 3 = (1 | 1 << 1) used both in simplified *and* traditional Chinese 4 = 1 << 2 mixture of simplified and traditional Chinese ''' # make sure that we got a unicode string if phrase in VARIANTS_TABLE: # the complete phrase is in VARIANTS_TABLE, just return the # value found: return VARIANTS_TABLE[phrase] category = 0xFF for char in phrase: if char in VARIANTS_TABLE: category &= VARIANTS_TABLE[char] else: # If it is not listed in VARIANTS_TABLE, assume it is # both simplified and traditional Chinese. # It could be something non-Chinese as well then, but # if it is non-Chinese, it should also be allowed to # occur in any Chinese text and thus classified as # both simplified *and* traditional Chinese (the emoji # table for example uses many non-Chinese characters) category &= (1 | 1 << 1) if category == 0: # If category is 0 after binary & of the categories of all the # characters in the phrase, it means that the phrase contained # exclusively simplified *and* exclusively traditional # characters at the same time. For example if the phrase is # “乌烏” then “乌” gets category 1 (simplified Chinese) # and “烏” gets category 2 (traditional Chinese), the result # of the binary & is thus 0. In that case, classify it as # category 4 which is for weird, excentric, rare stuff. If the # user selects one of the modes “all characters but # simplified Chinese first” or “all characters but # traditional Chinese first”, phrases with category 4 will be # shown but filtered to be shown only at the end of the # candidate list. category = 1 << 2 return category ibus-table-1.17.11/engine/factory.py000066400000000000000000000110161475513533100172050ustar00rootroot00000000000000# vim:et sw=4 sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # Copyright (c) 2009-2014 Caius "kaio" CHANCE # Copyright (c) 2012-2015, 2021-2022 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see from typing import Dict from typing import Optional import os import re import logging from gettext import dgettext _ = lambda a: dgettext("ibus-table", a) N_ = lambda a: a from gi import require_version # type: ignore require_version('IBus', '1.0') from gi.repository import IBus # type: ignore import table import tabsqlitedb LOGGER = logging.getLogger('ibus-table') DEBUG_LEVEL = int(0) class EngineFactory(IBus.Factory): # type: ignore """Table IM Engine Factory""" def __init__(self, bus: IBus.Bus, db: str = '') -> None: global DEBUG_LEVEL try: DEBUG_LEVEL = int(str(os.getenv('IBUS_TABLE_DEBUG_LEVEL'))) except (TypeError, ValueError): DEBUG_LEVEL = int(0) if DEBUG_LEVEL > 1: LOGGER.debug('EngineFactory.__init__(bus=%s, db=%s)\n', bus, db) self.db: Optional[tabsqlitedb.TabSqliteDb] = None self.dbdict: Dict[str, tabsqlitedb.TabSqliteDb] = {} # db is the full path to the sql database if db: self.dbusname = os.path.basename(db).replace('.db', '') udb = os.path.basename(db).replace('.db', '-user.db') self.db = tabsqlitedb.TabSqliteDb(filename=db, user_db=udb) self.db.db.commit() self.dbdict = {self.dbusname:self.db} # init factory self.bus = bus super().__init__(connection=bus.get_connection(), object_path=IBus.PATH_FACTORY) self.engine_id = 0 self.engine_path = '' def do_create_engine(self, engine_name: str) -> table.TabEngine: if DEBUG_LEVEL > 1: LOGGER.debug( 'EngineFactory.do_create_engine(engine_name=%s)\n', engine_name) engine_name = re.sub(r'^table:', '', engine_name) engine_base_path = "/com/redhat/IBus/engines/table/%s/engine/" path_patt = re.compile(r'[^a-zA-Z0-9_/]') self.engine_path = engine_base_path % path_patt.sub('_', engine_name) try: if not self.db: # first check self.dbdict if engine_name not in self.dbdict: db_dir = '/usr/share/ibus-table/tables' if os.getenv('IBUS_TABLE_LOCATION'): db_dir = os.path.join( str(os.getenv('IBUS_TABLE_LOCATION')), 'tables') db = os.path.join(db_dir, engine_name+'.db') udb = engine_name+'-user.db' if not os.path.exists(db): byo_db_dir = os.path.expanduser('~/.ibus/byo-tables') db = os.path.join(byo_db_dir, engine_name + '.db') _sq_db = tabsqlitedb.TabSqliteDb(filename=db, user_db=udb) _sq_db.db.commit() self.dbdict[engine_name] = _sq_db engine = table.TabEngine(self.bus, self.engine_path + str(self.engine_id), self.dbdict[engine_name]) self.engine_id += 1 #return engine.get_dbus_object() return engine except: LOGGER.exception('failed to create engine %s', engine_name) raise Exception('Cannot create engine %s' %engine_name) def do_destroy(self) -> None: '''Destructor, which finish some task for IME''' if DEBUG_LEVEL > 1: LOGGER.debug('EngineFactory.do_destroy()\n') # ## we need to sync the temp userdb in memory to the user_db on disk for _db in self.dbdict: self.dbdict[_db].sync_usrdb() ##print "Have synced user db\n" super().destroy() ibus-table-1.17.11/engine/ibus-engine-table.in000066400000000000000000000035331475513533100210130ustar00rootroot00000000000000#!/bin/sh # vim:set et sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # prefix=@prefix@ exec_prefix=@prefix@ datarootdir=@datarootdir@ datadir=@datadir@ export IBUS_TABLE_LOCATION=@datarootdir@/ibus-table export IBUS_TABLE_LIB_LOCATION=@libexecdir@ # Set this variable to something > 0 to get more debug output. # (Debug output may show up in the log file and/or in the lookup table): # export IBUS_TABLE_DEBUG_LEVEL=1 # # Set this to something if you want benchmarking (The profiling output # will appear in the debug long when "ibus restart" is executed): # export IBUS_TABLE_PROFILE=yes for arg in $@; do case $arg in --xml | -x) exec @PYTHON@ @datarootdir@/ibus-table/engine/main.py --xml;; --help | -h) exec @PYTHON@ @datarootdir@/ibus-table/engine/main.py $@;; *) if [ "x${IBUS_TABLE_PROFILE}" != "x" ]; then exec @PYTHON@ @datarootdir@/ibus-table/engine/main.py --profile $@ else exec @PYTHON@ @datarootdir@/ibus-table/engine/main.py $@ fi exit 0 esac done ibus-table-1.17.11/engine/ibus-table-createdb.in000066400000000000000000000021261475513533100213140ustar00rootroot00000000000000#!/bin/sh # vim:set et sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ datarootdir=@datarootdir@ datadir=@datadir@ export IBUS_TABLE_DATA_DIR=@datarootdir@ export IBUS_TABLE_BIN_PATH=@bindir@ exec @PYTHON@ @datarootdir@/ibus-table/engine/tabcreatedb.py $@ ibus-table-1.17.11/engine/ibus-table-createdb.sgml000066400000000000000000000161521475513533100216540ustar00rootroot00000000000000 manpage.1'. You may view the manual page with: `docbook-to-man manpage.sgml | nroff -man | less'. A typical entry in a Makefile or Makefile.am is: manpage.1: manpage.sgml docbook-to-man $< > $@ The docbook-to-man binary is found in the docbook-to-man package. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include docbook-to-man in your Build-Depends control field. --> Mike"> FABIAN"> Apr 18, 2013"> 1"> mfabian@redhat.com"> ibus-table-createdb"> Debian"> GNU"> GPL"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2013 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; create ibus-table database from table source &dhpackage; DESCRIPTION &dhpackage; creates a database for ibus-table from a source table. OPTIONS This program follows the usual &gnu; command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. database-file specifies the file name for the binary database for the IME. The default is ''. If the file name of the database is not specified, the file name of the source file before the first '.' will be appended with '.db' and that will be used as the file name of the database. source-file specifies the file which contains the source of the IME. The default is ''. extra-words-file specifies the file name for the extra words for the IME. The default is ''. pinyin-file specifies the source file for the pinyin. The default is '/usr/share/ibus-table/data/pinyin_table.txt.bz2'. Do not create an index for a database (Only for distribution purposes, a normal user should not use this flag!) Only create an index for an existing database. Specifying the file name of the binary database with the -n or --name option is required when this option is used. Print extra debug messages. EXAMPLES ibus-table-createdb -n ipa-x-sampa.db -s ipa-x-sampa.txt Create the binary database ipa-x-sampa.db from the source file ipa-x-sampa.txt. ibus-table-createdb -i -n ipa-x-sampa.db Create an index for the database ipa-x-sampa.db. AUTHOR This manual page was written by &dhusername; &dhemail;.
ibus-table-1.17.11/engine/ibus_table_location.py000066400000000000000000000102111475513533100215330ustar00rootroot00000000000000# # ibus-table - The Tables engine for IBus # # Copyright (c) 2015-2018 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see ''' Get locations where ibus-table stores stuff. The directories used are according to the “XDG Base Directory Specification”, see: http://standards.freedesktop.org/basedir-spec/latest/index.html ''' from typing import Dict import os IBUS_TABLE_LOCATION: Dict[str, str] = { 'data': '', 'lib': '', 'data_home': '', 'cache_home': '', } def data() -> str: return IBUS_TABLE_LOCATION['data'] def lib() -> str: return IBUS_TABLE_LOCATION['lib'] def data_home() -> str: return IBUS_TABLE_LOCATION['data_home'] def cache_home() -> str: return IBUS_TABLE_LOCATION['cache_home'] def _init() -> None: if os.getenv('IBUS_TABLE_LOCATION'): IBUS_TABLE_LOCATION['data'] = str(os.getenv('IBUS_TABLE_LOCATION')) if (not IBUS_TABLE_LOCATION['data'] or not os.path.exists(IBUS_TABLE_LOCATION['data'])): IBUS_TABLE_LOCATION['data'] = "/usr/share/ibus-table/" if os.getenv('IBUS_TABLE_LIB_LOCATION'): IBUS_TABLE_LOCATION['lib'] = str(os.getenv('IBUS_TABLE_LIB_LOCATION')) if (not IBUS_TABLE_LOCATION['lib'] or not os.path.exists(IBUS_TABLE_LOCATION['lib'])): IBUS_TABLE_LOCATION['lib'] = "/usr/libexec" # $XDG_DATA_HOME defines the base directory relative to which user # specific data files should be stored. If $XDG_DATA_HOME is either # not set or empty, a default equal to $HOME/.local/share should be # used. if os.getenv('IBUS_TABLE_DATA_HOME'): IBUS_TABLE_LOCATION['data_home'] = str( os.getenv('IBUS_TABLE_DATA_HOME')) if (not IBUS_TABLE_LOCATION['data_home'] or not os.path.exists(IBUS_TABLE_LOCATION['data_home'])): if os.getenv('XDG_DATA_HOME'): IBUS_TABLE_LOCATION['data_home'] = str(os.getenv('XDG_DATA_HOME')) if (not IBUS_TABLE_LOCATION['data_home'] or not os.path.exists(IBUS_TABLE_LOCATION['data_home'])): IBUS_TABLE_LOCATION['data_home'] = os.path.expanduser('~/.local/share') IBUS_TABLE_LOCATION['data_home'] = os.path.join( IBUS_TABLE_LOCATION['data_home'], 'ibus-table') if not os.access(IBUS_TABLE_LOCATION['data_home'], os.F_OK): os.makedirs(IBUS_TABLE_LOCATION['data_home'], exist_ok=True) # $XDG_CACHE_HOME defines the base directory relative to which user # specific non-essential data files should be stored. If # $XDG_CACHE_HOME is either not set or empty, a default equal to # $HOME/.cache should be used. if os.getenv('IBUS_TABLE_CACHE_HOME'): IBUS_TABLE_LOCATION['cache_home'] = str( os.getenv('IBUS_TABLE_CACHE_HOME')) if (not IBUS_TABLE_LOCATION['cache_home'] or not os.path.exists(IBUS_TABLE_LOCATION['cache_home'])): if os.getenv('XDG_CACHE_HOME'): IBUS_TABLE_LOCATION['cache_home'] = str( os.getenv('XDG_CACHE_HOME')) if (not IBUS_TABLE_LOCATION['cache_home'] or not os.path.exists(IBUS_TABLE_LOCATION['cache_home'])): IBUS_TABLE_LOCATION['cache_home'] = os.path.expanduser('~/.cache') IBUS_TABLE_LOCATION['cache_home'] = os.path.join( IBUS_TABLE_LOCATION['cache_home'], 'ibus-table') if not os.access(IBUS_TABLE_LOCATION['cache_home'], os.F_OK): os.makedirs(IBUS_TABLE_LOCATION['cache_home'], exist_ok=True) class __ModuleInitializer: def __init__(self) -> None: _init() def __del__(self) -> None: return __module_init = __ModuleInitializer() ibus-table-1.17.11/engine/it_active_window.py000066400000000000000000000322221475513533100210760ustar00rootroot00000000000000# vim:et sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2022 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see '''Module to track the name of the program in the currently focused window On Wayland desktops: Tries AT-SPI first and falls back to xprop On X11 desktops: Uses only xprop AT-SPI: https://en.wikipedia.org/wiki/Assistive_Technology_Service_Provider_Interface - AT-SPI seems to work reasonably well in Gnome Wayland, KDE (Plasma) Wayland, and in some other cases. It even works in most X11 desktops, even in i3 (But as getting the active window via AT-SPI can sometimes fail, it is better to use xprop for that on X11 desktops, xprop is very reliable on X11 desktops). - Even in a Gnome Wayland or KDE (Plasma) Wayland session AT-SPI doesn‘t work for some old X11 programs like xterm, urxvt, ... But the fallback to xprop works in these cases. - To make AT-SPI work with Firefox and google-chrome, GNOME_ACCESSIBILITY=1 needs to be set in the environment. - To make AT-SPI work with Qt5, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1 needs to be set in the environment - To make AT-SPI work with Qt4, QT_ACCESSIBILITY=1 needs to be set in the environment In some cases, the name returned by AT-SPI may slightly differ from from the name acquired by ibus with or by xprop. For example in case of google-chrome: - AT-SPI: 'Google Chrome' - ibus focus id: 'google-chrome' - xprop: 'google-chrome' To test this module execute sleep 5 && python3 it_active_window.py in a terminal, and focus a different window and see whether the information from that active window is fetched correctly Then focus different windows and see whether the log output seen in the terminal shows correctly which window is currently active (This works only with AT-SPI). ''' from typing import Any from typing import Tuple import sys import os import subprocess import shutil import threading import logging IMPORT_PYATSPI_SUCCESSFUL = False try: import pyatspi # type: ignore IMPORT_PYATSPI_SUCCESSFUL = True except (ImportError,): IMPORT_PYATSPI_SUCCESSFUL = False LOGGER = logging.getLogger('ibus-table') class AtspiMonitor: ''' Class to monitor the program name in the currently focused window ''' def __init__(self) -> None: '''Initialization''' self._active_program_name = '' self._active_window_title = '' self._events_registered = False if not IMPORT_PYATSPI_SUCCESSFUL: LOGGER.info('“import pyatspi” failed.') return try: pyatspi.Registry.registerEventListener( self._on_window_activate, 'window:activate') pyatspi.Registry.registerEventListener( self._on_window_deactivate, 'window:deactivate') self._events_registered = True LOGGER.info('AtspiMonitor events registered.') except Exception as error: # pylint: disable=broad-except LOGGER.exception('%s: %s ', error.__class__.__name__, error) def start(self) -> None: '''Starts the monitoring''' if self._events_registered: LOGGER.info('Starting AtspiMonitor.') pyatspi.Registry.start() # pylint: disable=no-value-for-parameter def get_active_window(self) -> Tuple[str, str]: ''' Gets information about the currently active window. :return: A tuple (program_name, window_title) giving information about the currently focused window. ''' return (self._active_program_name, self._active_window_title) def _on_window_activate(self, event: Any) -> None: '''Called when a window gets activated.''' LOGGER.debug('%s', str(event)) try: self._active_program_name = event.host_application.name self._active_window_title = event.source_name except Exception as error: # pylint: disable=broad-except LOGGER.exception('%s: %s', error.__class__.__name__, error) LOGGER.info('window activated: %s currently active: %s title: %s', self._active_program_name, self._active_program_name, self._active_window_title) def _on_window_deactivate(self, event: Any) -> None: '''Called when a window gets deactivated.''' LOGGER.debug('%s', str(event)) program_name = '' try: program_name = event.host_application.name except Exception as error: # pylint: disable=broad-except LOGGER.exception('%s: %s', error.__class__.__name__, error) # There are some windows where the 'window:activate', # 'window:deactivate' signals do not work, for example windows # containing old X11 programs like xterm behave like that. # # If the focus moves from a window where the signals work to a # window where they do not, only the 'window:deactivate' # occurs. # # Therefore, we may want to set self._active_program_name = '' # when a window is deactivated because we may not be able to # get the true name of the program in the window which is # activated next and it is better to have an empty string than # a wrong program name left over from the previously active # program. # # *But*, sometimes the 'window:deactivate' signal for the old # window occurs *after* the 'window:activate' signal of the # new window! Weird! Therefore, set self._active_program_name # = '' only if the program name is still unchanged! # # Theoretically if there are two windows for the same program, # for example two 'soffice' windows (Libreoffice), moving from # one to the other could then reset the program name from # 'soffice' to '' if the 'window:deactivate' signal comes # last. # # Luckily, when testing this I never saw that the # 'window:deactivate' signal came last when moving the focus # between two windows for the same program, i.e. when moving # from 'soffice' to 'soffice' or from 'firefox' to 'firefox', # this never happened. But when moving from 'soffice' to # 'gnome-terminal' or from 'firefox' to 'gnome-terminal', it # *always* happened. This might be just an accident, but I # don’t have a better idea for a workaround at the moment. if self._active_program_name == program_name: self._active_program_name = '' self._active_window_title = '' LOGGER.info('window deactivated: %s currently active: %s title: %s', program_name, self._active_program_name, self._active_window_title) _ACTIVE_WINDOW: Tuple[str, str] = ('', '') def _get_active_window_atspi() -> None: ''' Internal function to get information about the currently active window. :return: A tuple (program_name, window_title) giving information about the currently focused window. ''' global _ACTIVE_WINDOW # pylint: disable=global-statement try: desktop = pyatspi.Registry.getDesktop(0) # pylint: disable=no-value-for-parameter for application in desktop: if application.getState().contains(pyatspi.STATE_DEFUNCT): continue for window in application: if window.get_state_set().contains(pyatspi.STATE_ACTIVE): _ACTIVE_WINDOW = (application.name, window.name) return except Exception as error: # pylint: disable=broad-except LOGGER.exception('%s: %s', error.__class__.__name__, error) _ACTIVE_WINDOW = ('', '') def get_active_window_atspi() -> Tuple[str, str]: ''' Get information about the currently active window. :return: A tuple (program_name, window_title) giving information about the currently focused window. ''' global _ACTIVE_WINDOW # pylint: disable=global-statement _ACTIVE_WINDOW = ('', '') if not IMPORT_PYATSPI_SUCCESSFUL: return ('', '') active_window_thread = threading.Thread( daemon=True, target=_get_active_window_atspi) active_window_thread.start() active_window_thread.join(timeout=0.5) if active_window_thread.is_alive(): LOGGER.error('timeout getting active window.') return ('', '') return _ACTIVE_WINDOW def get_active_window_xprop() -> Tuple[str, str]: ''' Gets information about the currently active window. :return: A tuple (program_name, window_title) giving information about the currently focused window. Works only in X11 sessions (and for some X11 programs like xterm, urxvt, ... in Wayland sessions) ''' program_name = '' window_title = '' if 'DISPLAY' not in os.environ or not os.environ['DISPLAY']: return (program_name, window_title) xprop_binary = shutil.which('xprop') if not xprop_binary: return (program_name, window_title) try: result = subprocess.run( [xprop_binary, '-root', '-f', '_NET_ACTIVE_WINDOW', '0x', ' $0', '_NET_ACTIVE_WINDOW'], check=True, encoding='utf-8', capture_output=True) except subprocess.CalledProcessError as error: LOGGER.exception( 'Exception when calling xprop: %s: %s stderr: %s', error.__class__.__name__, error, error.stderr) return (program_name, window_title) # result now looks like in this example: # # '_NET_ACTIVE_WINDOW(WINDOW) 0x1e02d79' if len(result.stdout.split()) < 2: LOGGER.error('Unexpected xprop output for id of active window') return (program_name, window_title) window_id = result.stdout.split()[-1:][0] if window_id == '0x0': return (program_name, window_title) try: result = subprocess.run( [xprop_binary, '-id', window_id, '-f', 'WM_CLASS', '0s', 'WM_CLASS'], check=True, encoding='utf-8', capture_output=True) except subprocess.CalledProcessError as error: LOGGER.exception( 'Exception when calling xprop: %s: %s stderr: %s', error.__class__.__name__, error, error.stderr) return (program_name, window_title) # result now looks like in this example # # 'WM_CLASS(STRING) = "xfce4-terminal", "Xfce4-terminal"\n' if '=' not in result.stdout or ',' not in result.stdout: LOGGER.error( 'Unexpected xprop output for program name of active window') return (program_name, window_title) program_name = result.stdout.split( '=', maxsplit=1)[1].split(',')[1].strip()[1:-1].lower() try: result = subprocess.run( [xprop_binary, '-id', window_id, '-f', '_NET_WM_NAME', '0t', '_NET_WM_NAME'], check=True, encoding='utf-8', capture_output=True) except subprocess.CalledProcessError as error: LOGGER.exception( 'Exception when calling xprop: %s: %s stderr: %s', error.__class__.__name__, error, error.stderr) return (program_name, window_title) # result now looks like in this example # # '_NET_WM_NAME(UTF8_STRING) = "☺foo = "bar"\n' if '=' not in result.stdout: LOGGER.error('Unexpected xprop output for title of active window') return (program_name, window_title) window_title = result.stdout.split('=', maxsplit=1)[1].strip()[1:-1] return (program_name, window_title) def get_active_window() -> Tuple[str, str]: ''' Gets information about the currently active window. :return: A tuple (program_name, window_title) giving information about the currently focused window. Tries AT-SPI first, if that doesn’t work falls back to xprop. ''' (program_name, window_title) = ('', '') if ('XDG_SESSION_TYPE' in os.environ and os.environ['XDG_SESSION_TYPE'].lower() == 'wayland'): (program_name, window_title) = get_active_window_atspi() if program_name: LOGGER.debug( 'Got active window from AT-SPI: %s', (program_name, window_title)) return (program_name, window_title) (program_name, window_title) = get_active_window_xprop() if program_name: LOGGER.debug( 'Got active window from xprop: %s', (program_name, window_title)) return (program_name, window_title) if __name__ == "__main__": LOG_HANDLER = logging.StreamHandler(stream=sys.stderr) LOGGER.setLevel(logging.DEBUG) LOGGER.addHandler(LOG_HANDLER) LOGGER.info('%s', get_active_window()) atspi_monitor = AtspiMonitor() atspi_monitor.start() ibus-table-1.17.11/engine/it_sound.py000066400000000000000000000434071475513533100173730ustar00rootroot00000000000000# vim:et sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2023 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see ''' Module to play simple error sounds ''' from typing import Optional from typing import Any import sys import os import logging import threading import wave import shutil import subprocess import mimetypes LOGGER = logging.getLogger('ibus-table') IMPORT_PYGAME_MIXER_SUCCESSFUL = False try: import pygame.mixer IMPORT_PYGAME_MIXER_SUCCESSFUL = True except (ImportError,): IMPORT_PYGAME_MIXER_SUCCESSFUL = False IMPORT_PYAUDIO_SUCCESSFUL = False try: import pyaudio # type: ignore IMPORT_PYAUDIO_SUCCESSFUL = True except (ImportError,): IMPORT_PYAUDIO_SUCCESSFUL = False IMPORT_SIMPLEAUDIO_SUCCESSFUL = False try: import simpleaudio # type: ignore IMPORT_SIMPLEAUDIO_SUCCESSFUL = True except (ImportError,): IMPORT_SIMPLEAUDIO_SUCCESSFUL = False class SoundObject: ''' Class to play sounds When pygames is used, this can play .wav and .mp3 files. When pyaudio is used, only .wav files work. ''' def __init__(self, path_to_sound_file: str, audio_backend: str = 'automatic') -> None: self._path_to_sound_file: str = path_to_sound_file self._wav_file: Optional[wave.Wave_read] = None self._paudio: Optional[pyaudio.PyAudio] = None self._play_pyaudio_thread: Optional[threading.Thread] = None self._simpleaudio_wave_o: Optional[simpleaudio.WaveObject] = None self._simpleaudio_play_o: Optional[simpleaudio.shiny.PlayObject] = None self._aplay_binary: Optional[str] = None self._aplay_stdin = b'' self._aplay_process: Optional[Any] = None self._play_aplay_thread: Optional[threading.Thread] = None self._supported_audio_backends = ('automatic', 'pygame', 'simpleaudio', 'aplay', 'pyaudio') self._requested_audio_backend = audio_backend self._audio_backend = '' if not os.path.isfile(self._path_to_sound_file): LOGGER.info('Sound file %s does not exist.', path_to_sound_file) return if not os.access(self._path_to_sound_file, os.R_OK): LOGGER.info('Sound file %s not readable.', path_to_sound_file) return if self._requested_audio_backend not in self._supported_audio_backends: LOGGER.error('Audio backend %s not supported, use one of %s', audio_backend, self._supported_audio_backends) return self._audio_backend = getattr(self, f'_init_{self._requested_audio_backend}')() if self._audio_backend: LOGGER.info('Using audio backend %s', self._audio_backend) else: LOGGER.error('Could not init audio backend %s', self._requested_audio_backend) def _init_automatic(self) -> str: # Try 'pygame' first if possible it seems to be the best: if self._init_pygame(): return 'pygame' # Try 'simpleaudio' for Python < 3.12.0, it used to work well # and has no dependencies. But it is broken in Fedora 39, # see: https://bugzilla.redhat.com/show_bug.cgi?id=2237680 # probably because Fedora 39 has Python 3.12.0rc2: if ((sys.version_info.major, sys.version_info.minor, sys.version_info.micro) < (3, 12, 0)): if self._init_simpleaudio(): return 'simpleaudio' # Try 'aplay', it seems reliable: if self._init_aplay(): return 'aplay' # Try 'pyaudio' as a last resort: # Broken for Python >= 3.10 if not updated to pyaudio >= 0.2.12 # See: https://stackoverflow.com/questions/70344884) # Sometimes it seems to hang. Not often, but when this happens this is really bad if (IMPORT_PYAUDIO_SUCCESSFUL and (((sys.version_info.major, sys.version_info.minor, sys.version_info.micro) < (3, 10, 0)) or (pyaudio.__version__ and tuple(int(x) for x in pyaudio.__version__.split('.')) >= (0, 2, 12)))): if self._init_pyaudio(): return 'pyaudio' # Nothing more to try ☹ return '' def _init_pygame(self) -> str: if not IMPORT_PYGAME_MIXER_SUCCESSFUL: return '' try: pygame.mixer.init() if pygame.mixer.get_init(): pygame.mixer.music.load(self._path_to_sound_file) return 'pygame' except Exception as error: # pylint: disable=broad-except LOGGER.exception( 'pygame: cannot load sound file %s: %s', error.__class__.__name__, error) return '' def _init_pyaudio(self) -> str: if not IMPORT_PYAUDIO_SUCCESSFUL: return '' (mime_type, encoding) = mimetypes.guess_type(self._path_to_sound_file) if mime_type not in ('audio/x-wav',): LOGGER.error( 'File %s has mime type %s and is not supported by simpleaudio', self._path_to_sound_file, mime_type) return '' try: self._wav_file = wave.open(self._path_to_sound_file, 'rb') self._paudio = pyaudio.PyAudio() self._stop_event_paudio: threading.Event = threading.Event() LOGGER.info('portaudio version = %s', pyaudio.get_portaudio_version_text()) return 'pyaudio' except Exception as error: # pylint: disable=broad-except LOGGER.exception( 'pyaudio: cannot init wave object %s: %s', error.__class__.__name__, error) return '' def _init_simpleaudio(self) -> str: if not IMPORT_SIMPLEAUDIO_SUCCESSFUL: return '' (mime_type, encoding) = mimetypes.guess_type(self._path_to_sound_file) if mime_type not in ('audio/x-wav',): LOGGER.error( 'File %s has mime type %s and is not supported by simpleaudio', self._path_to_sound_file, mime_type) return '' try: self._simpleaudio_wave_o = ( simpleaudio.WaveObject.from_wave_file(self._path_to_sound_file)) return 'simpleaudio' except Exception as error: # pylint: disable=broad-except LOGGER.exception( 'Initializing error sound object failed: %s: %s', error.__class__.__name__, error) return '' def _init_aplay(self) -> str: (mime_type, encoding) = mimetypes.guess_type(self._path_to_sound_file) if mime_type not in ('audio/x-wav',): LOGGER.error( 'File %s has mime type %s and is not supported by aplay', self._path_to_sound_file, mime_type) return '' self._aplay_binary = shutil.which('aplay') if not self._aplay_binary: return '' with open (self._path_to_sound_file, mode='rb') as aplay_input: self._aplay_stdin = aplay_input.read() if self._aplay_stdin: return 'aplay' return '' def __del__(self) -> None: if self._paudio: self._paudio.terminate() if self._wav_file: self._wav_file.close() def _play_pyaudio_thread_function(self, stop_event: threading.Event) -> None: if not self._wav_file: LOGGER.error('wave.open(%s, \'rb\') did not work.', self._path_to_sound_file) return if not self._paudio: LOGGER.error('pyaudio.PyAudio() did not work.') return LOGGER.info('Playing sound with pyaudio ...') chunk_size = 1024 stream = self._paudio.open( format=self._paudio.get_format_from_width( self._wav_file.getsampwidth()), channels=self._wav_file.getnchannels(), rate=self._wav_file.getframerate(), output=True, frames_per_buffer=chunk_size) self._wav_file.rewind() data = self._wav_file.readframes(chunk_size) while data and not stop_event.is_set(): try: if not stream.is_active(): LOGGER.error('pyaudio stream is_active() is False') break stream.write(data) data = self._wav_file.readframes(chunk_size) except (SystemError, OSError) as error: LOGGER.exception( 'Unexpected error playing wave object %s: %s', error.__class__.__name__, error) LOGGER.error('If you see the ' '"SystemError: PY_SSIZE_T_CLEAN macro ' 'must be defined for \'#\' formats" ' 'message here, updating to pyaudio >= 0.2.12 ' 'will probably fix the problem.' 'See https://stackoverflow.com/questions/70344884') break stream.stop_stream() stream.close() LOGGER.info('Done playing sound with pyaudio.') def _play_pyaudio(self) -> None: self._stop_event_paudio.clear() self._play_pyaudio_thread = threading.Thread( daemon=True, target=self._play_pyaudio_thread_function, args=(self._stop_event_paudio,)) self._play_pyaudio_thread.start() def _is_playing_pyaudio(self) -> bool: if not self._play_pyaudio_thread: return False return self._play_pyaudio_thread.is_alive() def _stop_pyaudio(self) -> None: if not self._play_pyaudio_thread: return if (self._play_pyaudio_thread.is_alive() and not self._stop_event_paudio.is_set()): self._stop_event_paudio.set() self._play_pyaudio_thread.join() self._stop_event_paudio.clear() def _wait_done_pyaudio(self) -> None: if not self._play_pyaudio_thread: return if self._play_pyaudio_thread.is_alive(): self._play_pyaudio_thread.join() def _play_simpleaudio(self) -> None: if not self._simpleaudio_wave_o: return try: self._simpleaudio_play_o = self._simpleaudio_wave_o.play() except Exception as error: # pylint: disable=broad-except LOGGER.exception( 'Initializing error sound object failed: %s: %s', error.__class__.__name__, error) def _is_playing_simpleaudio(self) -> bool: if not self._simpleaudio_play_o: return False return bool(self._simpleaudio_play_o.is_playing()) def _stop_simpleaudio(self) -> None: if not self._simpleaudio_play_o: return self._simpleaudio_play_o.stop() # wait until it is really stopped, otherwise a call to # __is_playing_simpleaudio() might still return True: self._simpleaudio_play_o.wait_done() def _wait_done_simpleaudio(self) -> None: if not self._simpleaudio_play_o: return self._simpleaudio_play_o.wait_done() @staticmethod def _play_pygame() -> None: pygame.mixer.music.rewind() pygame.mixer.music.play() @staticmethod def _is_playing_pygame() -> bool: return pygame.mixer.music.get_busy() @staticmethod def _stop_pygame() -> None: pygame.mixer.music.stop() @staticmethod def _wait_done_pygame() -> None: while pygame.mixer.music.get_busy(): pass def _play_aplay_thread_function(self) -> None: if not self._aplay_binary: return try: self._aplay_process = subprocess.Popen('aplay', shell=False, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, encoding=None, errors=None, text=None) except (OSError, ValueError) as error: LOGGER.exception( 'cannot start aplay process %s: %s', error.__class__.__name__, error) return try: self._aplay_process.communicate(input=self._aplay_stdin, timeout=1000) except subprocess.TimeoutExpired as error: LOGGER.exception( 'timeout piping sound file into aplay process%s: %s', error.__class__.__name__, error) self._aplay_process.kill() return try: self._aplay_process.terminate() except Exception as error: LOGGER.exception( 'cannot terminate aplay process %s: %s', error.__class__.__name__, error) try: LOGGER.info('Trying to kill aplay process') self._aplay_process.kill() LOGGER.info('aplay process killed') except Exception as error: LOGGER.exception( 'cannot kill aplay process%s: %s', error.__class__.__name__, error) def _play_aplay(self) -> None: self._play_aplay_thread = threading.Thread( daemon=True, target=self._play_aplay_thread_function) self._play_aplay_thread.start() def _is_playing_aplay(self) -> bool: if not self._play_aplay_thread: return False return self._play_aplay_thread.is_alive() def _stop_aplay(self) -> None: if not self._play_aplay_thread: return if (self._play_aplay_thread.is_alive() and self._aplay_process and self._aplay_process.poll() is None): try: self._aplay_process.terminate() except Exception as error: LOGGER.exception( 'cannot terminate aplay process %s: %s', error.__class__.__name__, error) try: LOGGER.info('Trying to kill aplay process') self._aplay_process.kill() except Exception as error: LOGGER.exception( 'cannot kill aplay process%s: %s', error.__class__.__name__, error) if self._play_aplay_thread.is_alive(): self._play_aplay_thread.join(timeout=0.1) if self._play_aplay_thread.is_alive(): LOGGER.error('timeout stopping aplay thread') def _wait_done_aplay(self) -> None: if not self._play_aplay_thread: return if self._play_aplay_thread.is_alive(): self._play_aplay_thread.join() def play(self) -> None: '''Play the sound''' if not self._audio_backend: LOGGER.error('Could not init any audio backend %s', self._requested_audio_backend) return getattr(self, f'_play_{self._audio_backend}')() def is_playing(self) -> bool: '''Check whether the sound is currently playing''' if not self._audio_backend: LOGGER.error('Could not init any audio backend %s', self._requested_audio_backend) return False return bool(getattr(self, f'_is_playing_{self._audio_backend}')()) def stop(self) -> None: '''Stop playing of the sound''' if not self._audio_backend: LOGGER.error('Could not init any audio backend %s', self._requested_audio_backend) return getattr(self, f'_stop_{self._audio_backend}')() def wait_done(self) -> None: '''Wait until the sound has been fully played''' if not self._audio_backend: LOGGER.error('Could not init any audio backend %s', self._requested_audio_backend) return getattr(self, f'_wait_done_{self._audio_backend}')() def run_tests() -> None: '''Run some simple tests''' audio_backend = 'automatic' # Testing a short sound: sound_object = SoundObject( #'/home/mfabian/sounds/japanese/今回もよろしくお願いします.wav', '/usr/share/ibus-table/data/coin9.wav', #'/home/mfabian/sounds/japanese/今回もよろしくお願いします.mp3', audio_backend=audio_backend) sound_object.play() sound_object.wait_done() sound_object.play() sound_object.wait_done() # Testing stopping in between with a longer sound file: import time # pylint: disable=import-outside-toplevel sound_object = SoundObject( '/home/mfabian/sounds/japanese/今回もよろしくお願いします.wav', audio_backend=audio_backend) sound_object.play() LOGGER.info('Sleeping ...') time.sleep(1) LOGGER.info('is playing %s', sound_object.is_playing()) sound_object.stop() LOGGER.info('is playing %s', sound_object.is_playing()) time.sleep(4) if __name__ == "__main__": LOG_HANDLER = logging.StreamHandler(stream=sys.stderr) LOGGER.setLevel(logging.DEBUG) LOGGER.addHandler(LOG_HANDLER) run_tests() ibus-table-1.17.11/engine/it_util.py000066400000000000000000001143021475513533100172110ustar00rootroot00000000000000# vim:et sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # Copyright (c) 2009-2014 Caius "kaio" CHANCE # Copyright (c) 2012-2022 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see ''' Utility functions used in ibus-table ''' from typing import Any from typing import List from typing import Tuple from typing import Dict from typing import Callable from enum import Enum, Flag import sys import os import re import logging import gettext from gi import require_version # type: ignore require_version('Gio', '2.0') from gi.repository import Gio # type: ignore require_version('GLib', '2.0') from gi.repository import GLib require_version('Gdk', '3.0') from gi.repository import Gdk require_version('Gtk', '3.0') from gi.repository import Gtk require_version('IBus', '1.0') from gi.repository import IBus import version import tabsqlitedb LOGGER = logging.getLogger('ibus-table') DOMAINNAME = 'ibus-table' _: Callable[[str], str] = lambda a: gettext.dgettext(DOMAINNAME, a) N_: Callable[[str], str] = lambda a: a # When matching keybindings, only the bits in the following mask are # considered for key.state: KEYBINDING_STATE_MASK = ( IBus.ModifierType.MODIFIER_MASK & ~IBus.ModifierType.LOCK_MASK # Caps Lock & ~IBus.ModifierType.MOD2_MASK # Num Lock & ~IBus.ModifierType.MOD3_MASK # Scroll Lock ) def variant_to_value(variant: GLib.Variant) -> Any: ''' Convert a GLib variant to a value ''' if variant is None: return None if not isinstance(variant, GLib.Variant): LOGGER.info('not a GLib.Variant') return variant type_string = variant.get_type_string() if type_string == 's': return variant.get_string() if type_string == 'i': return variant.get_int32() if type_string == 'u': return variant.get_uint32() if type_string == 'x': return variant.get_int64() if type_string == 't': return variant.get_uint64() if type_string == 'd': return variant.get_double() if type_string == 'b': return variant.get_boolean() if type_string == 'v': return variant.unpack() if type_string and type_string[0] == 'a': return variant.unpack() LOGGER.error('unknown variant type: %s', type_string) return variant def color_string_to_argb(color_string: str) -> int: ''' Converts a color string to a 32bit ARGB value :param color_string: The color to convert to 32bit ARGB Can be expressed in the following ways: - Standard name from the X11 rgb.txt - Hex value: “#rgb”, “#rrggbb”, “#rrrgggbbb” or ”#rrrrggggbbbb” - RGB color: “rgb(r,g,b)” - RGBA color: “rgba(r,g,b,a)” Examples: >>> print('%x' %color_string_to_argb('rgb(0xff, 0x10, 0x25)')) ffff1025 >>> print('%x' %color_string_to_argb('#108040')) ff108040 >>> print('%x' %color_string_to_argb('#fff000888')) ffff0088 >>> print('%x' %color_string_to_argb('#ffff00008888')) ffff0088 >>> print('%x' %color_string_to_argb('rgba(0xff, 0x10, 0x25, 0.5)')) 7fff1025 ''' gdk_rgba = Gdk.RGBA() gdk_rgba.parse(color_string) return (((int(gdk_rgba.alpha * 0xff) & 0xff) << 24) + ((int(gdk_rgba.red * 0xff) & 0xff) << 16) + ((int(gdk_rgba.green * 0xff) & 0xff) << 8) + (int(gdk_rgba.blue * 0xff) & 0xff)) def get_default_chinese_mode(database: tabsqlitedb.TabSqliteDb) -> int: ''' Use database value or LC_CTYPE in your box to determine the Chinese mode 0 means to show simplified Chinese only 1 means to show traditional Chinese only 2 means to show all characters but show simplified Chinese first 3 means to show all characters but show traditional Chinese first 4 means to show all characters If nothing can be found return 4 to avoid any special Chinese filtering or sorting. ''' # use db value, if applicable database_chinese_mode = database.get_chinese_mode() if database_chinese_mode >= 0: LOGGER.info( 'get_default_chinese_mode(): ' 'default Chinese mode found in database, mode=%s', database_chinese_mode) return database_chinese_mode # otherwise try: if 'LC_ALL' in os.environ: __lc = os.environ['LC_ALL'].split('.')[0].lower() LOGGER.info( 'get_default_chinese_mode(): ' '__lc=%s found in LC_ALL', __lc) elif 'LC_CTYPE' in os.environ: __lc = os.environ['LC_CTYPE'].split('.')[0].lower() LOGGER.info( 'get_default_chinese_mode(): ' '__lc=%s found in LC_CTYPE', __lc) else: __lc = os.environ['LANG'].split('.')[0].lower() LOGGER.info( 'get_default_chinese_mode(): ' '__lc=%s found in LANG', __lc) if '_cn' in __lc or '_sg' in __lc: # CN and SG should prefer traditional Chinese by default return 2 # show simplified Chinese first if '_hk' in __lc or '_tw' in __lc or '_mo' in __lc: # HK, TW, and MO should prefer traditional Chinese by default return 3 # show traditional Chinese first if database._is_chinese: # This table is used for Chinese, but we don’t # know for which variant. Therefore, better show # all Chinese characters and don’t prefer any # variant: LOGGER.info( 'get_default_chinese_mode(): last fallback, ' 'database is Chinese but we don’t know ' 'which variant, returning 4.') else: LOGGER.info( 'get_default_chinese_mode(): last fallback, ' 'database is not Chinese, returning 4.') return 4 # show all Chinese characters except: LOGGER.exception('Exception in get_default_chinese_mode(), ' 'returning 4.') return 4 def get_default_keybindings( gsettings: Gio.Settings, database: tabsqlitedb.TabSqliteDb) -> Dict[str, List[str]]: default_keybindings: Dict[str, List[str]] = {} default_keybindings = variant_to_value( gsettings.get_default_value('keybindings')) # Now update the default keybindings from gsettings with # keybindings found in the database: valid_input_chars = database.ime_properties.get('valid_input_chars') select_keys_csv = database.get_select_keys() if select_keys_csv is None: select_keys_csv = '1,2,3,4,5,6,7,8,9,0' select_keybindings = [ name.strip() for name in select_keys_csv.split(',')][:10] if len(select_keybindings) < 10: select_keybindings += [ 'VoidSymbol'] * (10 - len(select_keybindings)) commit_keybindings = default_keybindings['commit'] commit_keys_csv = database.ime_properties.get('commit_keys') if commit_keys_csv: commit_keybindings = [ name.strip() for name in commit_keys_csv.split(',')] default_keybindings['commit'] = commit_keybindings page_down_keybindings = default_keybindings['lookup_table_page_down'] page_down_keys_csv = database.ime_properties.get('page_down_keys') if page_down_keys_csv: page_down_keybindings = [ name.strip() for name in page_down_keys_csv.split(',')] page_up_keybindings = default_keybindings['lookup_table_page_up'] page_up_keys_csv = database.ime_properties.get('page_up_keys') if page_up_keys_csv: page_up_keybindings = [ name.strip() for name in page_up_keys_csv.split(',')] # If commit keys conflict with page up/down keys, remove them # from the page up/down keys (They cannot really be used for # both at the same time. Theoretically, keys from the page # up/down keys could still be used to commit when the number # of candidates is 0 because then there is nothing to # page. But that would be only confusing): for name in commit_keybindings: if name in page_down_keybindings: page_down_keybindings.remove(name) if name in page_up_keybindings: page_up_keybindings.remove(name) # Several tables have = and/or - in the list of valid input chars. # In that case they should be removed from the 'lookup_table_page_down' # and 'lookup_table_page_up' keybindings: if '-' in valid_input_chars: if 'minus' in page_up_keybindings: page_up_keybindings.remove('minus') if 'minus' in page_down_keybindings: page_down_keybindings.remove('minus') if '=' in valid_input_chars: if 'equal' in page_up_keybindings: page_up_keybindings.remove('equal') if 'equal' in page_down_keybindings: page_down_keybindings.remove('equal') default_keybindings['lookup_table_page_down'] = page_down_keybindings default_keybindings['lookup_table_page_up'] = page_up_keybindings for index, name in enumerate(select_keybindings): # Currently the cns11643 table has: # # SELECT_KEYS = 1,2,3,4,5,6,7,8,9,0 # # and # # VALID_INPUT_CHARS = 0123456789abcdef # # # Then the digit “1” could be interpreted either as an # input character or as a select key but of course not # both. If the meaning as a select key were preferred, # this would make some input impossible which probably # makes the whole input method useless. If the meaning as # an input character is preferred, this makes selection # using that key impossible. Making selection by key # impossible is not nice either, but it is not a complete # show stopper as there are still other possibilities to # select, for example using the arrow-up/arrow-down keys # or click with the mouse. # # And we don’t have to make selection by key completely # impossible, we can use F1, ..., F10 instead of the digits # if the digits are valid input chars. # # Of course one should maybe consider fixing the conflict # between the keys by using different SELECT_KEYS in that # table. if len(name) == 1 and name in list(valid_input_chars): if name in '123456789': name = 'F' + name elif name == '0': name = 'F10' default_keybindings[ 'commit_candidate_%s' % (index + 1) ] = [name] default_keybindings[ 'commit_candidate_to_preedit_%s' % (index + 1) ] = ['Control+' + name] default_keybindings[ 'remove_candidate_%s' % (index + 1) ] = ['Mod1+' + name] if name in ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0'): default_keybindings[ 'commit_candidate_%s' % (index + 1) ].append('KP_' + name) default_keybindings[ 'commit_candidate_to_preedit_%s' % (index + 1) ].append('Control+KP_' + name) default_keybindings[ 'remove_candidate_%s' % (index + 1) ].append('Mod1+KP_' + name) for command in default_keybindings: for keybinding in default_keybindings[command]: if 'VoidSymbol' in keybinding: default_keybindings[command].remove(keybinding) return default_keybindings def dict_update_existing_keys( pdict: Dict[Any, Any], other_pdict: Dict[Any, Any]) -> None: '''Update values of existing keys in a Python dict from another Python dict Using pdict.update(other_pdict) would add keys and values from other_pdict to pdict even for keys which do not exist in pdict. Sometimes I want to update only existing keys and ignore new keys. :param pdict: The Python dict to update :type pdict: Python dict :param other_pdict: The Python dict to get the updates from :type other_pdict: Python dict Examples: >>> old_pdict = {'a': 1, 'b': 2} >>> new_pdict = {'b': 3, 'c': 4} >>> dict_update_existing_keys(old_pdict, new_pdict) >>> old_pdict {'a': 1, 'b': 3} >>> old_pdict.update(new_pdict) >>> old_pdict {'a': 1, 'b': 3, 'c': 4} ''' for key in other_pdict: if key in pdict: pdict[key] = other_pdict[key] class Capabilite(Flag): '''Compatibility class to handle IBus.Capabilite the same way no matter what version of ibus is used. For example, older versions of ibus might not have IBus.Capabilite.SYNC_PROCESS_KEY (or maybe even do not have IBus.Capabilite at all). Then capabilities & IBus.Capabilite.SYNC_PROCESS_KEY will produce an exception. But when using this compatibility class capabilities & IBus.Capabilite.SYNC_PROCESS_KEY will just be False but not cause an exception. >>> int(Capabilite.PREEDIT_TEXT) 1 >>> Capabilite.PREEDIT_TEXT == 1 True >>> Capabilite.PREEDIT_TEXT | 2 3 >>> 2 | Capabilite.PREEDIT_TEXT 3 >>> int(Capabilite.PREEDIT_TEXT | Capabilite.AUXILIARY_TEXT) 3 >>> 3 == Capabilite.AUXILIARY_TEXT | Capabilite.PREEDIT_TEXT True >>> 3 == Capabilite.AUXILIARY_TEXT | IBus.Capabilite.PREEDIT_TEXT True >>> Capabilite.PREEDIT_TEXT == IBus.Capabilite.PREEDIT_TEXT True ''' def __new__(cls, attr: str) -> Any: obj = object.__new__(cls) if hasattr(IBus, 'Capabilite') and hasattr(IBus.Capabilite, attr): obj._value_ = int(getattr(IBus.Capabilite, attr)) else: obj._value_ = 0 return obj def __int__(self) -> int: return int(self._value_) def __eq__(self, other: Any) -> bool: if (self.__class__ is other.__class__ or other.__class__ is IBus.Capabilite): return bool(int(self) == int(other)) if other.__class__ is int or other.__class__ is float: return bool(int(self) == other) return NotImplemented def __or__(self, other: Any) -> Any: if self.__class__ is other.__class__: return self.value | other.value if (other.__class__ is IBus.Capabilite): return int(self) | int(other) if other.__class__ is int: return int(self) | other return NotImplemented def __ror__(self, other: Any) -> Any: # type: ignore[override] return self.__or__(other) def __and__(self, other: Any) -> Any: if self.__class__ is other.__class__: return self.value & other.value if (other.__class__ is IBus.Capabilite): return int(self) & int(other) if other.__class__ is int: return int(self) & other return NotImplemented def __rand__(self, other: Any) -> Any: # type: ignore[override] return self.__and__(other) PREEDIT_TEXT = ('PREEDIT_TEXT') AUXILIARY_TEXT = ('AUXILIARY_TEXT') LOOKUP_TABLE = ('LOOKUP_TABLE') FOCUS = ('FOCUS') PROPERTY = ('PROPERTY') SURROUNDING_TEXT = ('SURROUNDING_TEXT') OSK = ('OSK') SYNC_PROCESS_KEY = ('SYNC_PROCESS_KEY') class InputPurpose(Enum): '''Compatibility class to handle InputPurpose the same way no matter what version of ibus is used. For example, older versions of ibus might not have IBus.InputPurpose.TERMINAL and then input_purpose == IBus.InputPurpose.TERMINAL will produce an exception. But when using this compatibility class input_purpose == InputPurpose.TERMINAL will just be False but not cause an exception. See also: https://docs.gtk.org/gtk3/enum.InputPurpose.html https://docs.gtk.org/gtk4/enum.InputPurpose.html Examples: >>> int(InputPurpose.PASSWORD) 8 >>> 8 == InputPurpose.PASSWORD True >>> int(InputPurpose.PIN) 9 >>> InputPurpose.PASSWORD <= InputPurpose.PIN True >>> InputPurpose.PASSWORD == Gtk.InputPurpose.PASSWORD True >>> InputPurpose.PASSWORD == IBus.InputPurpose.PASSWORD True ''' def __new__(cls, attr: str) -> Any: obj = object.__new__(cls) if hasattr(Gtk, 'InputPurpose') and hasattr(Gtk.InputPurpose, attr): obj._value_ = int(getattr(Gtk.InputPurpose, attr)) else: obj._value_ = -1 return obj def __int__(self) -> int: return int(self._value_) def __eq__(self, other: Any) -> bool: if (self.__class__ is other.__class__ or other.__class__ is Gtk.InputPurpose or other.__class__ is IBus.InputPurpose): return int(self) == int(other) if other.__class__ is int or other.__class__ is float: return bool(int(self) == other) return NotImplemented def __gt__(self, other: Any) -> bool: if (self.__class__ is other.__class__ or other.__class__ is Gtk.InputPurpose or other.__class__ is IBus.InputPurpose): return int(self) > int(other) if other.__class__ is int or other.__class__ is float: return bool(int(self) > other) return NotImplemented def __lt__(self, other: Any) -> bool: if (self.__class__ is other.__class__ or other.__class__ is Gtk.InputPurpose or other.__class__ is IBus.InputPurpose): return bool(int(self) < int(other)) if other.__class__ is int or other.__class__ is float: return bool(int(self) < other) return NotImplemented def __ge__(self, other: Any) -> bool: if (self.__class__ is other.__class__ or other.__class__ is Gtk.InputPurpose or other.__class__ is IBus.InputPurpose): return bool(int(self) >= int(other)) if other.__class__ is int or other.__class__ is float: return bool(int(self) >= other) return NotImplemented def __le__(self, other: Any) -> bool: if (self.__class__ is other.__class__ or other.__class__ is Gtk.InputPurpose or other.__class__ is IBus.InputPurpose): return bool(int(self) <= int(other)) if other.__class__ is int or other.__class__ is float: return bool(int(self) <= other) return NotImplemented FREE_FORM = ('FREE_FORM') ALPHA = ('ALPHA') DIGITS = ('DIGITS') NUMBER = ('NUMBER') PHONE = ('PHONE') URL = ('URL') EMAIL = ('EMAIL') NAME = ('NAME') PASSWORD = ('PASSWORD') PIN = ('PIN') TERMINAL = ('TERMINAL') class InputHints(Flag): '''Compatibility class to handle InputHints the same way no matter what version of ibus is used. For example, older versions of ibus might not have IBus.InputHints.PRIVATE (or maybe even do not have IBus.InputHints at all). Then input_hints & IBus.InputHints.PRIVATE will produce an exception. But when using this compatibility class input_hints & InputHints.PRIVATE will just be False but not cause an exception. See also: https://docs.gtk.org/gtk3/flags.InputHints.html https://docs.gtk.org/gtk4/flags.InputHints.html Examples: >>> int(InputHints.SPELLCHECK) 1 >>> InputHints.SPELLCHECK == 1 True >>> InputHints.SPELLCHECK | 2 3 >>> 2 | InputHints.SPELLCHECK 3 >>> int(InputHints.NO_SPELLCHECK | InputHints.SPELLCHECK) 3 >>> 3 == InputHints.NO_SPELLCHECK | InputHints.SPELLCHECK True >>> 3 == InputHints.NO_SPELLCHECK | Gtk.InputHints.SPELLCHECK True >>> 3 == InputHints.NO_SPELLCHECK | IBus.InputHints.SPELLCHECK True >>> InputHints.SPELLCHECK == IBus.InputHints.SPELLCHECK True >>> InputHints.SPELLCHECK == Gtk.InputHints.SPELLCHECK True ''' def __new__(cls, attr: str) -> Any: obj = object.__new__(cls) if hasattr(Gtk, 'InputHints') and hasattr(Gtk.InputHints, attr): obj._value_ = int(getattr(Gtk.InputHints, attr)) else: obj._value_ = 0 return obj def __int__(self) -> int: return int(self._value_) def __eq__(self, other: Any) -> bool: if (self.__class__ is other.__class__ or other.__class__ is Gtk.InputHints or other.__class__ is IBus.InputHints): return bool(int(self) == int(other)) if other.__class__ is int or other.__class__ is float: return bool(int(self) == other) return NotImplemented def __or__(self, other: Any) -> Any: if self.__class__ is other.__class__: return self.value | other.value if (other.__class__ is Gtk.InputHints or other.__class__ is IBus.InputHints): return int(self) | int(other) if other.__class__ is int: return int(self) | other return NotImplemented def __ror__(self, other: Any) -> Any: # type: ignore[override] return self.__or__(other) def __and__(self, other: Any) -> Any: if self.__class__ is other.__class__: return self.value & other.value if (other.__class__ is Gtk.InputHints or other.__class__ is IBus.InputHints): return int(self) & int(other) if other.__class__ is int: return int(self) & other return NotImplemented def __rand__(self, other: Any) -> Any: # type: ignore[override] return self.__and__(other) NONE = ('NONE') SPELLCHECK = ('SPELLCHECK') NO_SPELLCHECK = ('NO_SPELLCHECK') WORD_COMPLETION = ('WORD_COMPLETION') LOWERCASE = ('LOWERCASE') UPPERCASE_CHARS = ('UPPERCASE_CHARS') UPPERCASE_WORDS = ('UPPERCASE_WORDS') UPPERCASE_SENTENCES = ('UPPERCASE_SENTENCES') INHIBIT_OSK = ('INHIBIT_OSK') VERTICAL_WRITING = ('VERTICAL_WRITING') EMOJI = ('EMOJI') NO_EMOJI = ('NO_EMOJI') PRIVATE = ('PRIVATE') class KeyEvent: '''Key event class used to make the checking of details of the key event easy ''' def __init__(self, keyval: int, keycode: int, state: int) -> None: self.val = keyval self.code = keycode self.state = state self.name = IBus.keyval_name(self.val) if re.match(r'U\+[0-9a-fA-F]{4,5}', self.name): # Older versions of ibus produce # # >>> IBus.keyval_name(0x0100263a) # 'U+263A' # # Convert this into the same name used by newer # versions of ibus which is: # # >>> IBus.keyval_name(0x0100263a) # '0x100263a' # # to make it possible for me to always work # with the same names, no matter the ibus version self.name = f'0x{0x1000000 + int(self.name[2:], 16):x}' self.unicode = IBus.keyval_to_unicode(self.val) self.shift = self.state & IBus.ModifierType.SHIFT_MASK != 0 self.lock = self.state & IBus.ModifierType.LOCK_MASK != 0 self.control = self.state & IBus.ModifierType.CONTROL_MASK != 0 self.super = self.state & IBus.ModifierType.SUPER_MASK != 0 self.hyper = self.state & IBus.ModifierType.HYPER_MASK != 0 self.meta = self.state & IBus.ModifierType.META_MASK != 0 # mod1: Usually Alt_L (0x40), Alt_R (0x6c), Meta_L (0xcd) self.mod1 = self.state & IBus.ModifierType.MOD1_MASK != 0 # mod2: Usually Num_Lock (0x4d) self.mod2 = self.state & IBus.ModifierType.MOD2_MASK != 0 # mod3: Usually Scroll_Lock self.mod3 = self.state & IBus.ModifierType.MOD3_MASK != 0 # mod4: Usually Super_L (0xce), Hyper_L (0xcf) self.mod4 = self.state & IBus.ModifierType.MOD4_MASK != 0 # mod5: ISO_Level3_Shift (0x5c), Mode_switch (0xcb) self.mod5 = self.state & IBus.ModifierType.MOD5_MASK != 0 self.button1 = self.state & IBus.ModifierType.BUTTON1_MASK != 0 self.button2 = self.state & IBus.ModifierType.BUTTON2_MASK != 0 self.button3 = self.state & IBus.ModifierType.BUTTON3_MASK != 0 self.button4 = self.state & IBus.ModifierType.BUTTON4_MASK != 0 self.button5 = self.state & IBus.ModifierType.BUTTON5_MASK != 0 self.release = self.state & IBus.ModifierType.RELEASE_MASK != 0 # MODIFIER_MASK: Modifier mask for the all the masks above self.modifier = self.state & IBus.ModifierType.MODIFIER_MASK != 0 def __eq__(self, other: object) -> bool: if not isinstance(other, KeyEvent): return NotImplemented if (self.val == other.val and self.code == other.code and self.state == other.state): return True return False def __ne__(self, other: object) -> bool: if not isinstance(other, KeyEvent): return NotImplemented if (self.val != other.val or self.code != other.code or self.state != other.state): return True return False def __str__(self) -> str: return repr( f'val={self.val:08x} ' f'code={self.code} ' f'state=0x{self.state:08x} ' f'name=“{self.name}” ' f'unicode=“{self.unicode}” ' f'shift={self.shift} ' f'lock={self.lock} ' f'control={self.control} ' f'super={self.super} ' f'hyper={self.hyper} ' f'meta={self.meta} ' f'mod1={self.mod1} ' f'mod2={self.mod2} ' f'mod3={self.mod3} ' f'mod4={self.mod4} ' f'mod5={self.mod5} ' f'button1={self.button1} ' f'button2={self.button2} ' f'button3={self.button3} ' f'button4={self.button4} ' f'button5={self.button5} ' f'release={self.release} ' f'modifier={self.modifier}') def keyevent_to_keybinding(keyevent: KeyEvent) -> str: # pylint: disable=line-too-long '''Calculates a keybinding string from a key event. Examples: >>> keyevent_to_keybinding(KeyEvent(IBus.KEY_Left, 0, 0)) 'Left' >>> keyevent_to_keybinding(KeyEvent(0x0100263a, 0, 0)) '0x100263a' >>> keyevent_to_keybinding(KeyEvent(0x0101F923, 0, 0)) '0x101f923' >>> keyevent_to_keybinding(KeyEvent(IBus.KEY_Left, 0, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.CONTROL_MASK)) 'Shift+Control+Left' >>> keyevent_to_keybinding(KeyEvent(0x0100263A, 0, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.CONTROL_MASK)) 'Shift+Control+0x100263a' >>> keyevent_to_keybinding(KeyEvent(0x0101F923, 0, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.CONTROL_MASK)) 'Shift+Control+0x101f923' ''' # pylint: enable=line-too-long keybinding = '' if keyevent.shift: keybinding += 'Shift+' if keyevent.lock: keybinding += 'Lock+' if keyevent.control: keybinding += 'Control+' if keyevent.super: keybinding += 'Super+' if keyevent.hyper: keybinding += 'Hyper+' if keyevent.meta: keybinding += 'Meta+' if keyevent.mod1: keybinding += 'Mod1+' if keyevent.mod2: keybinding += 'Mod2+' if keyevent.mod3: keybinding += 'Mod3+' if keyevent.mod4: keybinding += 'Mod4+' if keyevent.mod5: keybinding += 'Mod5+' keybinding += keyevent.name return keybinding def keybinding_to_keyevent(keybinding: str) -> KeyEvent: # pylint: disable=line-too-long '''Returns a key event object created from a key binding string. Examples: >>> keybinding_to_keyevent('Shift+Control+Left').val == IBus.KEY_Left True >>> keybinding_to_keyevent('Shift+Control+Left').name 'Left' >>> keybinding_to_keyevent('Shift+Control+Left').state == IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.CONTROL_MASK True >>> f"0x{keybinding_to_keyevent('Shift+Control+0x100263a').val:08x}" '0x0100263a' >>> f"0x{keybinding_to_keyevent('Shift+Control+0x101F923').val:08x}" '0x0101f923' >>> f"0x{keybinding_to_keyevent('Shift+Control+0x101G923').val:08x}" '0x00ffffff' >>> keybinding_to_keyevent('Shift+Control+0x101G923').val == IBus.KEY_VoidSymbol True ''' # pylint: enable=line-too-long name = keybinding.split('+')[-1] keyval = IBus.keyval_from_name(name) if keyval == IBus.KEY_VoidSymbol and re.match(r'0x10[0-9a-fA-F]{5}', name): keyval = int(name[2:], 16) state = 0 if 'Shift+' in keybinding: state |= IBus.ModifierType.SHIFT_MASK if 'Lock+' in keybinding: state |= IBus.ModifierType.LOCK_MASK if 'Control+' in keybinding: state |= IBus.ModifierType.CONTROL_MASK if 'Super+' in keybinding: state |= IBus.ModifierType.SUPER_MASK if 'Hyper+' in keybinding: state |= IBus.ModifierType.HYPER_MASK if 'Meta+' in keybinding: state |= IBus.ModifierType.META_MASK if 'Mod1+' in keybinding: state |= IBus.ModifierType.MOD1_MASK if 'Mod2+' in keybinding: state |= IBus.ModifierType.MOD2_MASK if 'Mod3+' in keybinding: state |= IBus.ModifierType.MOD3_MASK if 'Mod4+' in keybinding: state |= IBus.ModifierType.MOD4_MASK if 'Mod5+' in keybinding: state |= IBus.ModifierType.MOD5_MASK return KeyEvent(keyval, 0, state) class HotKeys: '''Class to make checking whether a key matches a hotkey for a certain command easy ''' def __init__(self, keybindings: Dict[str, List[str]]) -> None: self._hotkeys: Dict[str, List[Tuple[int, int]]] = {} for command in keybindings: for keybinding in keybindings[command]: key = keybinding_to_keyevent(keybinding) val = key.val state = key.state & KEYBINDING_STATE_MASK if command in self._hotkeys: self._hotkeys[command].append((val, state)) else: self._hotkeys[command] = [(val, state)] def __contains__( self, command_key_tuple: Tuple[KeyEvent, KeyEvent, str]) -> bool: if not isinstance(command_key_tuple, tuple): return False command = command_key_tuple[2] key = command_key_tuple[1] prev_key = command_key_tuple[0] if prev_key is None: # When ibus-table has just started and the very first key # is pressed prev_key is not yet set. In that case, assume # that it is the same as the current key: prev_key = key val = key.val state = key.state # Do not change key.state, only the copy! if key.name in ('Shift_L', 'Shift_R', 'Control_L', 'Control_R', 'Alt_L', 'Alt_R', 'Meta_L', 'Meta_R', 'Super_L', 'Super_R', 'ISO_Level3_Shift'): # For these modifier keys, match on the release event # *and* make sure that the previous key pressed was # exactly the same key. Then we know that for example only # Shift_L was pressed and then released with nothing in # between. For example it could not have been something # like “Shift_L” then “a” followed by releasing the “a” # and the “Shift_L”. if (prev_key.val != val or not state & IBus.ModifierType.RELEASE_MASK): return False state &= ~IBus.ModifierType.RELEASE_MASK if key.name in ('Shift_L', 'Shift_R'): state &= ~IBus.ModifierType.SHIFT_MASK elif key.name in ('Control_L', 'Control_R'): state &= ~IBus.ModifierType.CONTROL_MASK elif key.name in ('Alt_L', 'Alt_R'): state &= ~IBus.ModifierType.MOD1_MASK elif key.name in ('Super_L', 'Super_R'): state &= ~IBus.ModifierType.SUPER_MASK state &= ~IBus.ModifierType.MOD4_MASK elif key.name in ('Meta_L', 'Meta_R'): state &= ~IBus.ModifierType.META_MASK state &= ~IBus.ModifierType.MOD1_MASK elif key.name in ('ISO_Level3_Shift',): state &= ~IBus.ModifierType.MOD5_MASK state = state & KEYBINDING_STATE_MASK if command in self._hotkeys: if (val, state) in self._hotkeys[command]: return True return False def __str__(self) -> str: return repr(self._hotkeys) class ItKeyInputDialog(Gtk.MessageDialog): # type: ignore def __init__( self, # Translators: This is used in the title bar of a dialog window # requesting that the user types a key to be used as a new # key binding for a command. title: str = _('Key input'), parent: Gtk.Window = None) -> None: Gtk.Dialog.__init__( self, title=title, parent=parent) self.add_button(_('Cancel'), Gtk.ResponseType.CANCEL) self.set_modal(True) self.set_markup( '%s' # Translators: This is from the dialog to enter a key or a # key combination to be used as a key binding for a # command. % _('Please press a key (or a key combination)')) self.format_secondary_text( # Translators: This is from the dialog to enter a key or a # key combination to be used as a key binding for a # command. _('The dialog will be closed when the key is released')) self.connect('key_press_event', self.on_key_press_event) self.connect('key_release_event', self.on_key_release_event) if parent: self.set_transient_for(parent.get_toplevel()) self.show() def on_key_press_event(# pylint: disable=no-self-use self, widget: Gtk.MessageDialog, event: Gdk.EventKey) -> bool: widget.e = (event.keyval, event.get_state() & KEYBINDING_STATE_MASK) return True def on_key_release_event(# pylint: disable=no-self-use self, widget: Gtk.MessageDialog, _event: Gdk.EventKey) -> bool: widget.response(Gtk.ResponseType.OK) return True class ItAboutDialog(Gtk.AboutDialog): # type: ignore def __init__(self, parent: Gtk.Window = None) -> None: Gtk.AboutDialog.__init__(self, parent=parent) self.set_modal(True) # An empty string in aboutdialog.set_logo_icon_name('') # prevents an ugly default icon to be shown. # self.set_logo_icon_name('') # But it looks nicer if we do not use this and use # Gtk.Window.set_default_icon_from_file(icon_file_name) # in the main window of the setup tool self.set_title('码 IBus Table %s' %version.get_version()) self.set_program_name('码 IBus Table') self.set_version(version.get_version()) self.set_comments( _('Table input method for IBus.')) self.set_copyright( 'Copyright © 2009-2012 Peng Huang,\n' 'Copyright © 2012-2022 Mike FABIAN') self.set_authors([ 'Yuwei YU (“acevery”)', 'Peng Huang', 'BYVoid', 'Peng Wu', 'Caius ‘kaio’ Chance', 'Mike FABIAN ', 'Contributors:', 'koterpilla', 'Zerng07', 'Mike FABIAN', 'Bernard Nauwelaerts', 'Xiaojun Ma', 'mozbugbox', 'Seán de Búrca', ]) self.set_translator_credits( # Translators: put your names here, one name per line. # The list of names of the translators for the current locale # will be displayed in the “About ibus-table” dialog. _('translator-credits')) # self.set_artists('') self.set_documenters([ 'Mike FABIAN ', ]) self.set_website( 'http://mike-fabian.github.io/ibus-table') self.set_website_label( _('Online documentation:') + ' ' + 'http://mike-fabian.github.io/ibus-table') self.set_license(''' This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see ''') self.set_wrap_license(True) # overrides the above .set_license() self.set_license_type(Gtk.License.LGPL_2_1) self.connect('response', self.on_close_aboutdialog) if parent: self.set_transient_for(parent.get_toplevel()) self.show() def on_close_aboutdialog( # pylint: disable=no-self-use self, _about_dialog: Gtk.Dialog, _response: Gtk.ResponseType) -> None: ''' The “About” dialog has been closed by the user :param _about_dialog: The “About” dialog :param _response: The response when the “About” dialog was closed ''' self.destroy() if __name__ == "__main__": LOG_HANDLER = logging.StreamHandler(stream=sys.stderr) LOGGER.setLevel(logging.DEBUG) LOGGER.addHandler(LOG_HANDLER) import doctest (FAILED, ATTEMPTED) = doctest.testmod() if FAILED: sys.exit(1) else: sys.exit(0) ibus-table-1.17.11/engine/main.py000066400000000000000000000335661475513533100165000ustar00rootroot00000000000000# vim:et sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # Copyright (c) 2009-2014 Caius "kaio" CHANCE # Copyright (c) 2012-2015, 2021-2022 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see from typing import Any from typing import Union import os import re import sys import argparse from signal import signal, SIGTERM, SIGINT import logging import logging.handlers from gi import require_version # type: ignore require_version('IBus', '1.0') from gi.repository import IBus # type: ignore from gi.repository import GLib import tabsqlitedb import ibus_table_location LOGGER = logging.getLogger('ibus-table') DEBUG_LEVEL = int(0) try: DEBUG_LEVEL = int(str(os.getenv('IBUS_TABLE_DEBUG_LEVEL'))) except (TypeError, ValueError): DEBUG_LEVEL = int(0) DB_DIR = os.path.join(ibus_table_location.data(), 'tables') BYO_DB_DIR = os.path.join(ibus_table_location.data_home(), "byo-tables") ICON_DIR = os.path.join(ibus_table_location.data(), 'icons') SETUP_CMD = os.path.join(ibus_table_location.lib(), "ibus-setup-table") LOGFILE = os.path.join(ibus_table_location.cache_home(), 'debug.log') def parse_args() -> Any: '''Parse the command line arguments''' parser = argparse.ArgumentParser() parser.add_argument( '--table', '-t', action='store', type=str, dest='db', default='', help='Set the IME table file, default: %(default)s') parser.add_argument( '--daemon', '-d', action='store_true', dest='daemon', default=False, help='Run as daemon, default: %(default)s') parser.add_argument( '--ibus', '-i', action='store_true', dest='ibus', default=False, help='Set the IME icon file, default: %(default)s') parser.add_argument( '--xml', '-x', action='store_true', dest='xml', default=False, help='output the engines xml part, default: %(default)s') parser.add_argument( '--no-debug', '-n', action='store_false', dest='debug', default=True, help='Write log file to ' + LOGFILE + ', default: %(default)s') parser.add_argument( '--profile', '-p', action='store_true', dest='profile', default=False, help=('Print profiling information into the debug log. ' 'Works only when --no-debug is not used. ' 'default: %(default)s')) return parser.parse_args() _ARGS = parse_args() if _ARGS.profile: import cProfile import pstats import io _PROFILE = cProfile.Profile() if _ARGS.xml: import locale from xml.etree.ElementTree import Element, SubElement, tostring else: # Avoid importing factory when the --xml option is used because # factory imports other stuff which imports Gtk and that needs a # display. # # But by moving the import of factory here, it is possible to # use the --xml option in an environment where there is no # display without getting an error message like this: # # $ env -u DISPLAY python3 main.py --xml # Unable to init server: Could not connect: Connection refused # # The --xml option is used by “ibus write-cache” which is used # during rpm updates and then there is often no display and # the above error message appears. # # See: https://bugzilla.redhat.com/show_bug.cgi?id=1955283 # # Need to call IBus.init() before IBus.EngineSimple() is loaded # factory -> engine -> IBus.EngineSimple IBus.init() import factory class IMApp: def __init__(self, dbfile: str, exec_by_ibus: bool) -> None: if DEBUG_LEVEL > 1: LOGGER.debug('IMApp.__init__(dbfile=%s, exec_by_ibus=%s)\n', dbfile, exec_by_ibus) self.__mainloop = GLib.MainLoop() self.__bus: IBus.Bus = IBus.Bus() self.__bus.connect("disconnected", self.__bus_destroy_cb) self.__factory = factory.EngineFactory(self.__bus, dbfile) self.destroyed = False if exec_by_ibus: self.__bus.request_name("org.freedesktop.IBus.Table", 0) else: self.__component = IBus.Component( name='org.freedesktop.IBus.Table', description='Table Component', version='0.1.0', license='GPL', author='Yuwei Yu ', homepage='http://mike-fabian.github.io/ibus-table/', textdomain='ibus-table') # now we get IME info from self.__factory.db engine_name = '' name = '' longname = '' description = '' language = 'en' credit = '' author = '' icon = '' layout = 'us' symbol = '' if self.__factory.db: engine_name = os.path.basename( self.__factory.db.filename).replace('.db', '') name = 'table:'+engine_name longname = self.__factory.db.ime_properties.get("name") description = self.__factory.db.ime_properties.get( "description") language = self.__factory.db.ime_properties.get("languages") credit = self.__factory.db.ime_properties.get("credit") author = self.__factory.db.ime_properties.get("author") icon = self.__factory.db.ime_properties.get("icon") layout = self.__factory.db.ime_properties.get("layout") symbol = self.__factory.db.ime_properties.get("symbol") if icon: icon = os.path.join(ICON_DIR, icon) if not os.access(icon, os.F_OK): icon = '' setup_arg = "{} --engine-name {}".format(SETUP_CMD, name) engine = IBus.EngineDesc(name=name, longname=longname, description=description, language=language, license=credit, author=author, icon=icon, layout=layout, symbol=symbol, setupdsis=setup_arg) self.__component.add_engine(engine) self.__bus.register_component(self.__component) def run(self) -> None: if DEBUG_LEVEL > 1: LOGGER.debug('IMApp.run()\n') if _ARGS.profile: _PROFILE.enable() self.__mainloop.run() self.__bus_destroy_cb() def quit(self) -> None: if DEBUG_LEVEL > 1: LOGGER.debug('IMApp.quit()\n') self.__bus_destroy_cb() def __bus_destroy_cb(self, bus: Any = None) -> None: if DEBUG_LEVEL > 1: LOGGER.debug('IMApp.__bus_destroy_cb(bus=%s)\n', bus) if self.destroyed: return LOGGER.info('finalizing:)') self.__factory.do_destroy() self.destroyed = True self.__mainloop.quit() if _ARGS.profile: _PROFILE.disable() stats_stream = io.StringIO() stats = pstats.Stats(_PROFILE, stream=stats_stream) stats.strip_dirs() stats.sort_stats('cumulative') stats.print_stats('main', 25) stats.print_stats('factory', 25) stats.print_stats('tabsqlite', 25) stats.print_stats('table', 25) LOGGER.info('Profiling info:\n%s', stats_stream.getvalue()) def cleanup(ima_ins: IMApp) -> None: ima_ins.quit() sys.exit() def indent(element: Any, level: int = 0) -> None: '''Use to format xml Element pretty :)''' i = "\n" + level*" " if element is None: return if len(element): if not element.text or not element.text.strip(): element.text = i + " " for subelement in element: indent(subelement, level+1) if not subelement.tail or not subelement.tail.strip(): subelement.tail = i + " " if not subelement.tail or not subelement.tail.strip(): subelement.tail = i else: if level and (not element.tail or not element.tail.strip()): element.tail = i def write_xml() -> None: ''' Writes the XML to describe the engine(s) to standard output. ''' # 1. we find all dbs in DB_DIR and extract the infos into # Elements dbs = os.listdir(DB_DIR) dbs = list(filter(lambda x: x.endswith('.db'), dbs)) _all_dbs = [] for _db in dbs: _all_dbs.append(os.path.join(DB_DIR, _db)) try: byo_dbs = os.listdir(BYO_DB_DIR) byo_dbs = list(filter(lambda x: x.endswith('.db'), byo_dbs)) for _db in byo_dbs: _all_dbs.append(os.path.join(BYO_DB_DIR, _db)) except OSError: # BYO_DB_DIR does not exist or is not accessible pass egs = Element('engines') for _db in _all_dbs: _sq_db = tabsqlitedb.TabSqliteDb(_db, user_db='') _engine = SubElement(egs, 'engine') _name = SubElement(_engine, 'name') engine_name = os.path.basename(_db).replace('.db', '') _name.text = 'table:'+engine_name setup_arg = "{} --engine-name {}".format(SETUP_CMD, _name.text) _longname = SubElement(_engine, 'longname') _longname.text = '' # getdefaultlocale() returns something like ('ja_JP', 'UTF-8'). # In case of C/POSIX locale it returns (None, None) locale.setlocale(locale.LC_ALL, '') _locale = locale.getlocale(locale.LC_MESSAGES)[0] if _locale: _locale = _locale.lower() if not _locale: _locale = 'en' _longname.text = _sq_db.ime_properties.get( '.'.join(['name', _locale])) if not _longname.text: _longname.text = _sq_db.ime_properties.get( '.'.join(['name', _locale.split('_')[0]])) if not _longname.text: _longname.text = _sq_db.ime_properties.get('name') if not _longname.text: _longname.text = engine_name _language = SubElement(_engine, 'language') _languages = _sq_db.ime_properties.get('languages') if _languages: _langs = _languages.split(',') if len(_langs) == 1: _language.text = _langs[0].strip() else: # we ignore the place _language.text = _langs[0].strip().split('_')[0] _license = SubElement(_engine, 'license') _license.text = _sq_db.ime_properties.get('license') _author = SubElement(_engine, 'author') _author.text = _sq_db.ime_properties.get('author') _icon = SubElement(_engine, 'icon') _icon_basename = _sq_db.ime_properties.get('icon') if _icon_basename: _icon.text = os.path.join(ICON_DIR, _icon_basename) _layout = SubElement(_engine, 'layout') _layout.text = _sq_db.ime_properties.get('layout') _symbol = SubElement(_engine, 'symbol') _symbol.text = _sq_db.ime_properties.get('symbol') _desc = SubElement(_engine, 'description') _desc.text = _sq_db.ime_properties.get('description') _setup = SubElement(_engine, 'setup') _setup.text = setup_arg _icon_prop_key = SubElement(_engine, 'icon_prop_key') _icon_prop_key.text = 'InputMode' # now format the xmlout pretty indent(egs) egsout = tostring(egs, encoding='utf8').decode('utf-8') patt = re.compile(r'<\?.*\?>\n') egsout = patt.sub('', egsout) # Always write xml output in UTF-8 encoding, not in the # encoding of the current locale, otherwise it might fail # if conversion into the encoding of the current locale is # not possible: sys.stdout.buffer.write((egsout+'\n').encode('utf-8')) def main() -> None: '''Main program''' if _ARGS.xml: write_xml() return log_handler: Union[ logging.NullHandler, logging.handlers.TimedRotatingFileHandler] = ( logging.NullHandler()) if _ARGS.debug: log_handler = logging.handlers.TimedRotatingFileHandler( LOGFILE, when='midnight', interval=1, backupCount=7, encoding='UTF-8', delay=False, utc=False, atTime=None) log_formatter = logging.Formatter( '%(asctime)s %(filename)s ' 'line %(lineno)d %(funcName)s %(levelname)s: ' '%(message)s') log_handler.setFormatter(log_formatter) LOGGER.setLevel(logging.DEBUG) LOGGER.addHandler(log_handler) LOGGER.info('********** STARTING **********') if _ARGS.daemon: if os.fork(): sys.exit() if _ARGS.db: if os.access(_ARGS.db, os.F_OK): db = _ARGS.db else: db = '{}{}{}'.format(DB_DIR, os.path.sep, os.path.basename(_ARGS.db)) else: db = "" ima = IMApp(db, _ARGS.ibus) signal(SIGTERM, lambda signum, stack_frame: cleanup(ima)) signal(SIGINT, lambda signum, stack_frame: cleanup(ima)) try: ima.run() except KeyboardInterrupt: ima.quit() if __name__ == "__main__": main() ibus-table-1.17.11/engine/tabcreatedb.py000066400000000000000000000456021475513533100200060ustar00rootroot00000000000000# vim:et sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # Copyright (c) 2009-2014 Caius "kaio" CHANCE # Copyright (c) 2012-2015, 2021-2022 Mike FABIAN # Copyright (c) 2019 Peng Wu # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see ''' Program to create sqlite databases from the table sources ''' from typing import Tuple from typing import List from typing import Iterable from typing import Dict from typing import Any import os import sys import bz2 import re import argparse sys.path.append(os.path.dirname(os.path.abspath(__file__))) import tabsqlitedb _INVALID_KEYNAME_CHARS = " \t\r\n\"$&<>,+=#!()'|{}[]?~`;%\\" def gconf_valid_keyname(keyname: str) -> bool: """ Keynames must be ascii, and must not contain any invalid characters >>> gconf_valid_keyname('nyannyan') True >>> gconf_valid_keyname('nyan nyan') False >>> gconf_valid_keyname('nyannyan[') False >>> gconf_valid_keyname('nyan\tnyan') False """ return not any(char in _INVALID_KEYNAME_CHARS or ord(char) > 127 for char in keyname) class InvalidTableName(Exception): """ Raised when an invalid table name is given """ def __init__(self, name: str) -> None: super().__init__() self.table_name = name def __str__(self) -> str: return ('Value of NAME attribute (%s) ' % self.table_name + 'cannot contain any of %r ' % _INVALID_KEYNAME_CHARS + 'and must be all ascii') def parse_args() -> Any: '''Parse the command line arguments''' parser = argparse.ArgumentParser() parser.add_argument( '-n', '--name', action='store', dest='name', default='', help=('Specifies the file name for the binary database for the IME. ' 'The default is “%(default)s”. If the file name of the database ' 'is not specified, the file name of the source file before ' 'the first “.” will be appended with “.db” and that will be ' 'used as the file name of the database.')) parser.add_argument( '-s', '--source', action='store', dest='source', default='', help=('Specifies the file which contains the source of the IME. ' 'The default is “%(default)s”.')) parser.add_argument( '-e', '--extra', action='store', dest='extra', default='', help=('Specifies the file name for the extra words for the IME. ' 'The default is “%(default)s”.')) parser.add_argument( '-p', '--pinyin', action='store', dest='pinyin', default='/usr/share/ibus-table/data/pinyin_table.txt.bz2', help=('Specifies the source file for the pinyin. ' 'The default is “%(default)s”.')) parser.add_argument( '-g', '--suggestion', action='store', dest='suggestion', default='/usr/share/ibus-table/data/phrase.txt.bz2', help=('Specifies the source file for the suggestion candidate. ' 'The default is “%(default)s”.')) parser.add_argument( '-o', '--no-create-index', action='store_false', dest='index', default=True, help=('Do not create an index for a database ' '(Only for distribution purposes, ' 'a normal user should not use this flag!). ' 'The default is “%(default)s”.')) parser.add_argument( '-i', '--create-index-only', action='store_true', dest='only_index', default=False, help=('Only create an index for an existing database. ' 'Specifying the file name of the binary database ' 'with the -n or --name option is required ' 'when this option is used.' 'The default is “%(default)s”.')) parser.add_argument( '-d', '--debug', action='store_true', dest='debug', default=False, help=('Print extra debug messages. ' 'The default is “%(default)s”.')) return parser.parse_args() _ARGS = parse_args() if _ARGS.only_index: if not _ARGS.name: print('\nPlease specify the file name of the database ' 'you want to create an index on!') sys.exit(2) if not os.path.exists(_ARGS.name) or not os.path.isfile(_ARGS.name): print("\nThe database file '%s' does not exist." % _ARGS.name) sys.exit(2) if not _ARGS.name and _ARGS.source: _ARGS.name = os.path.basename(_ARGS.source).split('.')[0] + '.db' if not _ARGS.name: print('\nYou need to specify the file which ' 'contains the source of the IME!') sys.exit(2) class Section: '''Helper class for parsing the sections of the tables marked with BEGIN_* and END_*. ''' # Actually the “more exact” type for patt is re.Pattern[str] but # Python 3.8 fails parsing this, therefore use type “Any” for patt # to make it work with Pytyon 3.8 as well: patt: Any start: str end: str in_section: bool def __init__(self, patt: Any, start: str, end: str): self.patt = patt self.start = start.strip() self.end = end.strip() self.in_section = False def match(self, line: str) -> bool: ''' Returns True if the line is inside the section and matches the pattern of the section. ''' if self.in_section: if self.end == line.strip(): self.in_section = False elif self.patt.match(line): return True elif self.start == line.strip(): self.in_section = True return False def main() -> None: '''Main program''' def debug_print(message: str) -> None: if _ARGS.debug: print(message) if not _ARGS.only_index: try: os.unlink(_ARGS.name) except Exception: pass debug_print('Processing Database') db = tabsqlitedb.TabSqliteDb(filename=_ARGS.name, user_db='', create_database=True) def parse_source( f: Iterable[str]) -> Tuple[List[str], List[str], List[str]]: _attri: List[str] = [] _table: List[str] = [] _table_extra: List[str] = [] _gouci: List[str] = [] patt_com = re.compile(r'^###.*') patt_blank = re.compile(r'^[ \t]*$') patt_conf = re.compile(r'[^\t]*=[^\t]*') patt_table = re.compile(r'([^\t]+)\t([^\t]+)\t([0-9]+)(\t.*)?$') patt_gouci = re.compile(r' *[^\s]+ *\t *[^\s]+ *$') sec_conf = Section( patt_conf, "BEGIN_DEFINITION", "END_DEFINITION") sec_table = Section( patt_table, "BEGIN_TABLE", "END_TABLE") sec_table_extra = Section( patt_table, "BEGIN_TABLE_EXTRA", "END_TABLE_EXTRA") sec_gouci = Section( patt_gouci, "BEGIN_GOUCI", "END_GOUCI") for line in f: if (not patt_com.match(line)) and (not patt_blank.match(line)): for _sec, _list in ( (sec_table, _table), (sec_table_extra, _table_extra), (sec_gouci, _gouci), (sec_conf, _attri)): if _sec.match(line): _list.append(line) break if not _gouci: # The user didn’t provide goucima (goucima = 構詞碼 = # “word formation keys”) in the table source, so we use # the longest encoding for a single character as the # goucima for that character. # # Example: # # wubi-jidian86.txt contains: # # a 工 99454797 # aaa 工 551000000 # aaaa 工 551000000 # aaad 工期 5350000 # ... and more matches for compounds containing 工 # # The longest key sequence to type 工 as a single # character is “aaaa”. Therefore, the goucima of 工 is # “aaaa” (There is one other character with the same goucima # in wubi-jidian86.txt, 㠭 also has the goucima “aaaa”). gouci_dict: Dict[str, str] = {} for line in _table: res = patt_table.match(line) if res and len(res.group(2)) == 1: if res.group(2) in gouci_dict: if len(res.group(1)) > len(gouci_dict[res.group(2)]): gouci_dict[res.group(2)] = res.group(1) else: gouci_dict[res.group(2)] = res.group(1) for key in gouci_dict: _gouci.append('%s\t%s' %(key, gouci_dict[key])) _gouci.sort() _table += _table_extra return (_attri, _table, _gouci) def parse_pinyin(f: Iterable[str]) -> List[str]: _pinyins: List[str] = [] patt_com = re.compile(r'^#.*') patt_blank = re.compile(r'^[ \t]*$') patt_py = re.compile(r'(.*)\t(.*)\t(.*)') patt_yin = re.compile(r'[a-z]+[1-5]') for line in f: if (not patt_com.match(line)) and (not patt_blank.match(line)): res = patt_py.match(line) if res: yins = patt_yin.findall(res.group(2)) for yin in yins: _pinyins.append("%s\t%s\t%s" \ % (res.group(1), yin, res.group(3))) return _pinyins[:] def parse_suggestion(f: Iterable[str]) -> List[str]: _suggestions: List[str] = [] patt_com = re.compile(r'^#.*') patt_blank = re.compile(r'^[ \t]*$') patt_sg = re.compile(r'(.*)\s+(.*)') for line in f: if (not patt_com.match(line)) and (not patt_blank.match(line)): res = patt_sg.match(line) if res: phrase = res.group(1) freq = res.group(2) _suggestions.append("{} {}".format(phrase, freq)) return _suggestions[:] def parse_extra(f: Iterable[str]) -> List[str]: _extra: List[str] = [] patt_com = re.compile(r'^###.*') patt_blank = re.compile(r'^[ \t]*$') patt_extra = re.compile(r'(.*)\t(.*)') for line in f: if (not patt_com.match(line)) and (not patt_blank.match(line)): if patt_extra.match(line): _extra.append(line) return _extra def pinyin_parser(f: Iterable[str]) -> Iterable[Tuple[str, str, int]]: for pinyin_line in f: _zi, _pinyin, _freq = pinyin_line.strip().split() yield (_pinyin, _zi, int(_freq)) def suggestion_parser(f: Iterable[str]) -> Iterable[Tuple[str, int]]: for suggestion_line in f: _phrase, _freq = suggestion_line.strip().split() yield (_phrase, int(_freq)) def phrase_parser(f: Iterable[str]) -> List[Tuple[str, str, int, int]]: phrase_list: List[Tuple[str, str, int, int]] = [] for line in f: xingma, phrase, freq = line.split('\t')[:3] if phrase == 'NOSYMBOL': phrase = '' phrase_list.append((xingma, phrase, int(freq), 0)) return phrase_list def goucima_parser(f: Iterable[str]) -> Iterable[Tuple[str, str]]: for line in f: zi, gcm = line.strip().split() yield (zi, gcm) def attribute_parser(f: Iterable[str]) -> Iterable[Tuple[str, str]]: for line in f: try: attr, val = line.strip().split('=') except Exception: attr, val = line.strip().split('==') attr = attr.strip().lower() val = val.strip() yield (attr, val) def extra_parser(f: Iterable[str]) -> List[Tuple[str, str, int, int]]: extra_list: List[Tuple[str, str, int, int]] = [] for line in f: phrase, freq = line.strip().split() _tabkey = db.parse_phrase(phrase) if _tabkey: extra_list.append((_tabkey, phrase, int(freq), 0)) else: print('No tabkeys found for “%s”, not adding.\n' %phrase) return extra_list def get_char_prompts(f: Iterable[str]) -> Tuple[str, str]: ''' Returns something like ("char_prompts", "{'a': '日', 'b': '日', 'c': '金', ...}") i.e. the attribute name "char_prompts" and as its value the string representation of a Python dictionary. ''' char_prompts: Dict[str, str] = {} start = False for line in f: if re.match(r'^BEGIN_CHAR_PROMPTS_DEFINITION', line): start = True continue if not start: continue if re.match(r'^END_CHAR_PROMPTS_DEFINITION', line): break match = re.search( r'^(?P[^\s]+)[\s]+(?P[^\s]+)', line) if match: char_prompts[match.group('char')] = match.group('prompt') return ("char_prompts", repr(char_prompts)) if _ARGS.only_index: debug_print('Only create Indexes') debug_print('Optimizing database ') db.optimize_database() debug_print('Create Indexes ') db.create_indexes('main') debug_print('Done! :D') return # now we parse the ime source file debug_print('\tLoad sources "%s"' % _ARGS.source) patt_s = re.compile(r'.*\.bz2') _bz2s = patt_s.match(_ARGS.source) if _bz2s: source_str = bz2.open( _ARGS.source, mode='rt', encoding='UTF-8').read() else: source_str = open(_ARGS.source, encoding='UTF-8').read() source_str = source_str.replace('\r\n', '\n') source = source_str.split('\n') # first get config line and table line and goucima line respectively debug_print('\tParsing table source file ') attri, table, gouci = parse_source(source) debug_print('\t get attribute of IME :)') attributes = list(attribute_parser(attri)) attributes.append(get_char_prompts(source)) debug_print('\t add attributes into DB ') db.update_ime(attributes) db.create_tables('main') # second, we use generators for database generating: debug_print('\t get phrases of IME :)') phrases = phrase_parser(table) # now we add things into db debug_print('\t add phrases into DB ') db.add_phrases(phrases) if db.ime_properties.get('user_can_define_phrase').lower() == 'true': debug_print('\t get goucima of IME :)') goucima = goucima_parser(gouci) debug_print('\t add goucima into DB ') db.add_goucima(goucima) if db.ime_properties.get('pinyin_mode').lower() == 'true': debug_print('\tLoad pinyin source \"%s\"' % _ARGS.pinyin) _bz2p = patt_s.match(_ARGS.pinyin) if _bz2p: pinyin_s = bz2.open(_ARGS.pinyin, mode='rt', encoding='UTF-8') else: pinyin_s = open(_ARGS.pinyin, encoding='UTF-8') debug_print('\tParsing pinyin source file ') pyline = parse_pinyin(pinyin_s) debug_print('\tPreapring pinyin entries') pinyin = pinyin_parser(pyline) debug_print('\t add pinyin into DB ') db.add_pinyin(pinyin) if db.ime_properties.get('suggestion_mode').lower() == 'true': debug_print('\tLoad suggestion source \"%s\"' % _ARGS.suggestion) _bz2p = patt_s.match(_ARGS.suggestion) if _bz2p: suggestion_s = bz2.open( _ARGS.suggestion, mode="rt", encoding='UTF-8') else: suggestion_s = open( _ARGS.suggestion, encoding='UTF-8') debug_print('\tParsing suggestion source file ') sgline = parse_suggestion(suggestion_s) debug_print('\tPreapring suggestion entries') suggestions = suggestion_parser(sgline) debug_print('\t add suggestion candidates into DB ') db.add_suggestion(suggestions) debug_print('Optimizing database ') db.optimize_database() if (db.ime_properties.get('user_can_define_phrase').lower() == 'true' and _ARGS.extra): debug_print('\tPreparing for adding extra words') db.create_indexes('main') debug_print('\tLoad extra words source "%s"' % _ARGS.extra) _bz2p = patt_s.match(_ARGS.extra) if _bz2p: extra_s = bz2.open(_ARGS.extra, mode='rt', encoding='UTF-8') else: extra_s = open(_ARGS.extra) debug_print('\tParsing extra words source file ') extraline = parse_extra(extra_s) debug_print('\tPreparing extra words lines') extrawords = extra_parser(extraline) debug_print('\t we have %d extra phrases from source' % len(extrawords)) # first get the entry of original phrases from # phrases-[(xingma, phrase, int(freq), 0)] orig_phrases = {} for phrase in phrases: orig_phrases.update({"{}\t{}".format(phrase[0], phrase[1]): phrase}) debug_print('\t the len of orig_phrases is: %d' % len(orig_phrases)) extra_phrases = {} for extraword in extrawords: extra_phrases.update( {"{}\t{}".format(extraword[0], extraword[1]): extraword}) debug_print('\t the len of extra_phrases is: %d' % len(extra_phrases)) # pop duplicated keys for extra_phrase in extra_phrases: if extra_phrase in orig_phrases: extra_phrases.pop(extra_phrase) debug_print('\t %d extra phrases will be added' % len(extra_phrases)) new_phrases = list(extra_phrases.values()) debug_print('\tAdding extra words into DB ') db.add_phrases(new_phrases) debug_print('Optimizing database ') db.optimize_database() if _ARGS.index: debug_print('Create Indexes ') db.create_indexes('main') else: debug_print('We do not create an index on the database, ' 'you should only activate this function ' 'for distribution purposes.') db.drop_indexes('main') debug_print('Done! :D') if __name__ == "__main__": main() ibus-table-1.17.11/engine/table.py000066400000000000000000005510211475513533100166320ustar00rootroot00000000000000# vim:et sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # Copyright (c) 2009-2014 Caius "kaio" CHANCE # Copyright (c) 2012-2022 Mike FABIAN # Copyright (c) 2019 Peng Wu # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see ''' This file implements the ibus engine for ibus-table ''' __all__ = ( "TabEngine", ) from typing import Any from typing import List from typing import Tuple from typing import Iterable from typing import Dict from typing import Union from typing import Optional from typing import Callable import sys import os import re import copy import time import logging IMPORT_SIMPLEAUDIO_SUCCESSFUL = False try: import simpleaudio # type: ignore IMPORT_SIMPLEAUDIO_SUCCESSFUL = True except (ImportError,): IMPORT_SIMPLEAUDIO_SUCCESSFUL = False from gettext import dgettext _: Callable[[str], str] = lambda a: dgettext('ibus-table', a) N_: Callable[[str], str] = lambda a: a from gi import require_version # type: ignore require_version('IBus', '1.0') from gi.repository import IBus # type: ignore require_version('Gio', '2.0') from gi.repository import Gio require_version('GLib', '2.0') from gi.repository import GLib #import tabsqlitedb from gi.repository import GObject import it_util import it_active_window import it_sound LOGGER = logging.getLogger('ibus-table') DEBUG_LEVEL = int(0) def ascii_ispunct(character: str) -> bool: ''' Use our own function instead of ascii.ispunct() from “from curses import ascii” because the behaviour of the latter is kind of weird. In Python 3.3.2 it does for example: # >>> from curses import ascii # >>> ascii.ispunct('.') # True # >>> ascii.ispunct(u'.') # True # >>> ascii.ispunct('a') # False # >>> ascii.ispunct(u'a') # False # >>> # >>> ascii.ispunct(u'あ') # True # >>> ascii.ispunct('あ') # True # >>> あ isn’t punctuation. ascii.ispunct() only really works in the ascii range, it returns weird results when used over the whole unicode range. Maybe we should better use unicodedata.category(), which works fine to figure out what is punctuation for all of unicode. But at the moment I am only porting from Python2 to Python3 and just want to preserve the original behaviour for the moment. By the way, Python 3.6.6 does not seem the above bug anymore, in Python 3.6.6 we get # >>> from curses import ascii # >>> ascii.ispunct('あ') # False # >>> Examples: >>> ascii_ispunct('.') True >>> ascii_ispunct('a') False >>> ascii_ispunct('あ') False ''' return bool(character in '''!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~''') THEME: Dict[str, Union[bool, int]] = { "dark": False, "candidate_text": it_util.color_string_to_argb('#1973a2'), "system_phrase": it_util.color_string_to_argb('#000000'), "user_phrase": it_util.color_string_to_argb('#7700c3'), "system_phrase_unused": it_util.color_string_to_argb('#000000'), "debug_text": it_util.color_string_to_argb('#00ff00'), "preedit_left": it_util.color_string_to_argb('#f90f0f'), # bright red "preedit_right": it_util.color_string_to_argb('#1edc1a'), # light green "preedit_invalid": it_util.color_string_to_argb('#ff00ff'), # magenta "aux_text": it_util.color_string_to_argb('#9515b5'), } THEME_DARK: Dict[str, Union[bool, int]] = { "dark": True, "candidate_text": it_util.color_string_to_argb('#7bc8f0'), "system_phrase": it_util.color_string_to_argb('#ffffff'), "user_phrase": it_util.color_string_to_argb('#c078ee'), "system_phrase_unused": it_util.color_string_to_argb('#f0f0f0'), "debug_text": it_util.color_string_to_argb('#00ff00'), "preedit_left": it_util.color_string_to_argb('#f9f90f'), "preedit_right": it_util.color_string_to_argb('#1edc1a'), "preedit_invalid": it_util.color_string_to_argb('#ff00ff'), "aux_text": it_util.color_string_to_argb('#dd70f9'), } __HALF_FULL_TABLE: List[Tuple[int, int, int]] = [ (0x0020, 0x3000, 1), (0x0021, 0xFF01, 0x5E), (0x00A2, 0xFFE0, 2), (0x00A5, 0xFFE5, 1), (0x00A6, 0xFFE4, 1), (0x00AC, 0xFFE2, 1), (0x00AF, 0xFFE3, 1), (0x20A9, 0xFFE6, 1), (0xFF61, 0x3002, 1), (0xFF62, 0x300C, 2), (0xFF64, 0x3001, 1), (0xFF65, 0x30FB, 1), (0xFF66, 0x30F2, 1), (0xFF67, 0x30A1, 1), (0xFF68, 0x30A3, 1), (0xFF69, 0x30A5, 1), (0xFF6A, 0x30A7, 1), (0xFF6B, 0x30A9, 1), (0xFF6C, 0x30E3, 1), (0xFF6D, 0x30E5, 1), (0xFF6E, 0x30E7, 1), (0xFF6F, 0x30C3, 1), (0xFF70, 0x30FC, 1), (0xFF71, 0x30A2, 1), (0xFF72, 0x30A4, 1), (0xFF73, 0x30A6, 1), (0xFF74, 0x30A8, 1), (0xFF75, 0x30AA, 2), (0xFF77, 0x30AD, 1), (0xFF78, 0x30AF, 1), (0xFF79, 0x30B1, 1), (0xFF7A, 0x30B3, 1), (0xFF7B, 0x30B5, 1), (0xFF7C, 0x30B7, 1), (0xFF7D, 0x30B9, 1), (0xFF7E, 0x30BB, 1), (0xFF7F, 0x30BD, 1), (0xFF80, 0x30BF, 1), (0xFF81, 0x30C1, 1), (0xFF82, 0x30C4, 1), (0xFF83, 0x30C6, 1), (0xFF84, 0x30C8, 1), (0xFF85, 0x30CA, 6), (0xFF8B, 0x30D2, 1), (0xFF8C, 0x30D5, 1), (0xFF8D, 0x30D8, 1), (0xFF8E, 0x30DB, 1), (0xFF8F, 0x30DE, 5), (0xFF94, 0x30E4, 1), (0xFF95, 0x30E6, 1), (0xFF96, 0x30E8, 6), (0xFF9C, 0x30EF, 1), (0xFF9D, 0x30F3, 1), (0xFFA0, 0x3164, 1), (0xFFA1, 0x3131, 30), (0xFFC2, 0x314F, 6), (0xFFCA, 0x3155, 6), (0xFFD2, 0x315B, 9), (0xFFE9, 0x2190, 4), (0xFFED, 0x25A0, 1), (0xFFEE, 0x25CB, 1)] def unichar_half_to_full(char: str) -> str: ''' Convert a character to full width if possible. :param char: A character to convert to full width Examples: >>> unichar_half_to_full('a') 'a' >>> unichar_half_to_full('a') 'a' >>> unichar_half_to_full('☺') '☺' ''' code = ord(char) for half, full, size in __HALF_FULL_TABLE: if half <= code < half + size: return chr(full + code - half) return char def unichar_full_to_half(char: str) -> str: ''' Convert a character to half width if possible. :param char: A character to convert to half width :type char: String :rtype: String Examples: >>> unichar_full_to_half('a') 'a' >>> unichar_full_to_half('a') 'a' >>> unichar_full_to_half('☺') '☺' ''' code = ord(char) for half, full, size in __HALF_FULL_TABLE: if full <= code < full + size: return chr(half + code - full) return char SAVE_USER_COUNT_MAX = 16 SAVE_USER_TIMEOUT = 30 # in seconds IBUS_VERSION = (IBus.MAJOR_VERSION, IBus.MINOR_VERSION, IBus.MICRO_VERSION) class TabEngine(IBus.EngineSimple): # type: ignore '''The IM Engine for Tables''' def __init__( self, bus: IBus.Bus, obj_path: str, database: Any, # tabsqlitedb.TabSqliteDb unit_test: bool = False) -> None: global DEBUG_LEVEL try: DEBUG_LEVEL = int(str(os.getenv('IBUS_TABLE_DEBUG_LEVEL'))) except (TypeError, ValueError): DEBUG_LEVEL = int(0) if DEBUG_LEVEL > 1: LOGGER.debug( 'TabEngine.__init__(bus=%s, obj_path=%s, database=%s)', bus, obj_path, database) LOGGER.info('ibus version = %s', '.'.join(map(str, IBUS_VERSION))) if hasattr(IBus.Engine.props, 'has_focus_id'): super().__init__( connection=bus.get_connection(), object_path=obj_path, has_focus_id=True) LOGGER.info('This ibus version has focus id.') else: super().__init__( connection=bus.get_connection(), object_path=obj_path) LOGGER.info('This ibus version does *not* have focus id.') # Load $HOME/.XCompose file: self.add_table_by_locale(None) self._unit_test = unit_test self._input_purpose: int = 0 self._input_hints: int = 0 self._bus = bus # this is the backend sql db we need for our IME # we receive this db from IMEngineFactory #self.db = tabsqlitedb.TabSqliteDb( name = dbname ) self.database = database self._setup_pid = 0 self._icon_dir = '{}{}{}{}'.format(os.getenv('IBUS_TABLE_LOCATION'), os.path.sep, 'icons', os.path.sep) self._engine_name = os.path.basename( self.database.filename).replace('.db', '').replace(' ', '_') if DEBUG_LEVEL > 1: LOGGER.debug( 'self._engine_name = %s', self._engine_name) self._gsettings: Gio.Settings = Gio.Settings( schema='org.freedesktop.ibus.engine.table', path='/org/freedesktop/ibus/engine/table/%s/' %self._engine_name) self._gsettings.connect('changed', self.on_gsettings_value_changed) self._prop_dict: Dict[str, IBus.Property] = {} self._sub_props_dict: Dict[str, IBus.PropList] = {} self.main_prop_list: List[IBus.Property] = [] self.chinese_mode_menu: Dict[str, Any] = {} self.chinese_mode_properties: Dict[str, Any] = {} self.input_mode_menu: Dict[str, Any] = {} self.input_mode_properties: Dict[str, Any] = {} self.letter_width_menu: Dict[str, Any] = {} self.letter_width_properties: Dict[str, Any] = {} self.punctuation_width_menu: Dict[str, Any] = {} self.punctuation_width_properties: Dict[str, Any] = {} self.pinyin_mode_menu: Dict[str, Any] = {} self.pinyin_mode_properties: Dict[str, Any] = {} self.suggestion_mode_menu: Dict[str, Any] = {} self.suggestion_mode_properties: Dict[str, Any] = {} self.onechar_mode_menu: Dict[str, Any] = {} self.onechar_mode_properties: Dict[str, Any] = {} self.autocommit_mode_menu: Dict[str, Any] = {} self.autocommit_mode_properties: Dict[str, Any] = {} self._setup_property: Optional[IBus.Property] = None self._im_client: str = '' self.theme = THEME self._keybindings: Dict[str, List[str]] = {} self._hotkeys: Optional[it_util.HotKeys] = None # self._ime_py: Indicates whether this table supports pinyin mode self._ime_py = self.database.ime_properties.get('pinyin_mode') if self._ime_py: self._ime_py = bool(self._ime_py.lower() == 'true') else: LOGGER.info('We could not find "pinyin_mode" entry in database, ' 'is it an outdated database?') self._ime_py = False # self._ime_sg: Indicates whether this table supports suggestion mode self._ime_sg = self.database.ime_properties.get('suggestion_mode') if self._ime_sg: self._ime_sg = bool(self._ime_sg.lower() == 'true') else: LOGGER.info( 'We could not find "suggestion_mode" entry in database, ' 'is it an outdated database?') self._ime_sg = False self._symbol = self.database.ime_properties.get('symbol') if self._symbol is None or self._symbol == '': self._symbol = self.database.ime_properties.get('status_prompt') if self._symbol is None: self._symbol = '' # some Chinese tables have “STATUS_PROMPT = CN” replace it # with the shorter and nicer “中”: if self._symbol == 'CN': self._symbol = '中' # workaround for the translit and translit-ua tables which # have 2 character symbols. '☑' + self._symbol then is # 3 characters and currently gnome-shell ignores symbols longer # than 3 characters: if self._symbol == 'Ya': self._symbol = 'Я' if self._symbol == 'Yi': self._symbol = 'Ї' # now we check and update the valid input characters self._valid_input_chars = self.database.ime_properties.get( 'valid_input_chars') self._pinyin_valid_input_chars = 'abcdefghijklmnopqrstuvwxyz!@#$%' self._debug_level: int = it_util.variant_to_value( self._gsettings.get_value('debuglevel')) if self._debug_level < 0: self._debug_level = 0 # minimum if self._debug_level > 255: self._debug_level = 255 # maximum DEBUG_LEVEL = self._debug_level dynamic_adjust: Optional[bool] = it_util.variant_to_value( self._gsettings.get_user_value('dynamicadjust')) if dynamic_adjust is None: if self.database.ime_properties.get('dynamic_adjust'): dynamic_adjust = self.database.ime_properties.get( 'dynamic_adjust').lower() == 'true' LOGGER.info('Got "dynamic_adjust" entry from database.') else: LOGGER.info( 'Could not find "dynamic_adjust" entry from database, ' 'is it an outdated database?') if dynamic_adjust is None: dynamic_adjust = it_util.variant_to_value( self._gsettings.get_value('dynamicadjust')) self._dynamic_adjust: bool = dynamic_adjust single_wildcard_char: Optional[str] = it_util.variant_to_value( self._gsettings.get_user_value('singlewildcardchar')) if single_wildcard_char is None: if self.database.ime_properties.get('single_wildcard_char'): single_wildcard_char = self.database.ime_properties.get( 'single_wildcard_char') else: single_wildcard_char = it_util.variant_to_value( self._gsettings.get_value('singlewildcardchar')) self._single_wildcard_char: str = single_wildcard_char if len(self._single_wildcard_char) > 1: self._single_wildcard_char = self._single_wildcard_char[0] multi_wildcard_char: Optional[str] = it_util.variant_to_value( self._gsettings.get_user_value('multiwildcardchar')) if multi_wildcard_char is None: if self.database.ime_properties.get('multi_wildcard_char'): multi_wildcard_char = self.database.ime_properties.get( 'multi_wildcard_char') else: multi_wildcard_char = it_util.variant_to_value( self._gsettings.get_value('multiwildcardchar')) self._multi_wildcard_char: str = multi_wildcard_char if len(self._multi_wildcard_char) > 1: self._multi_wildcard_char = self._multi_wildcard_char[0] auto_wildcard: Optional[bool] = it_util.variant_to_value( self._gsettings.get_user_value('autowildcard')) if auto_wildcard is None: if self.database.ime_properties.get('auto_wildcard'): auto_wildcard = self.database.ime_properties.get( 'auto_wildcard').lower() == 'true' LOGGER.info('Got "auto_wildcard" entry from database.') else: auto_wildcard = it_util.variant_to_value( self._gsettings.get_value('autowildcard')) self._auto_wildcard: bool = auto_wildcard self._max_key_length = int( self.database.ime_properties.get('max_key_length')) self._max_key_length_pinyin = 7 self._remember_input_mode: bool = it_util.variant_to_value( self._gsettings.get_value('rememberinputmode')) # 0 = Direct input, i.e. table input OFF (aka “English input mode”), # most characters are just passed through to the application # (but some fullwidth ↔ halfwidth conversion may be done even # in this mode, depending on the settings) # 1 = Table input ON (aka “Table input mode”, “Chinese mode”) self._input_mode: int = 1 if self._remember_input_mode: self._input_mode = it_util.variant_to_value( self._gsettings.get_value('inputmode')) self._sound_backend: str = it_util.variant_to_value( self._gsettings.get_value('soundbackend')) self._error_sound_object: Optional[it_sound.SoundObject] = None self._error_sound_file: str = '' self._error_sound: bool = it_util.variant_to_value( self._gsettings.get_value('errorsound')) self.set_error_sound_file( it_util.variant_to_value( self._gsettings.get_value('errorsoundfile')), update_gsettings=False) # self._prev_key: hold the key event last time. self._prev_key: Optional[it_util.KeyEvent] = None self._prev_char: Optional[str] = None self._double_quotation_state = False self._single_quotation_state = False # self._prefix: the previous commit character or phrase self._prefix = '' self._py_mode = False # suggestion mode self._sg_mode = False self._sg_mode_active = False self._full_width_letter: List[Optional[bool]] = [None, None] self._full_width_letter = [ it_util.variant_to_value( self._gsettings.get_value('endeffullwidthletter')), it_util.variant_to_value( self._gsettings.get_user_value('tabdeffullwidthletter')) ] if self._full_width_letter[1] is None: if self.database.ime_properties.get('def_full_width_letter'): self._full_width_letter[1] = self.database.ime_properties.get( 'def_full_width_letter').lower() == 'true' if self._full_width_letter[1] is None: self._full_width_letter[1] = it_util.variant_to_value( self._gsettings.get_value('tabdeffullwidthletter')) self._full_width_punct: List[Optional[bool]] = [None, None] self._full_width_punct = [ it_util.variant_to_value( self._gsettings.get_value('endeffullwidthpunct')), it_util.variant_to_value( self._gsettings.get_user_value('tabdeffullwidthpunct')) ] if self._full_width_punct[1] is None: if self.database.ime_properties.get('def_full_width_punct'): self._full_width_punct[1] = self.database.ime_properties.get( 'def_full_width_punct').lower() == 'true' if self._full_width_punct[1] is None: self._full_width_punct[1] = it_util.variant_to_value( self._gsettings.get_value('tabdeffullwidthpunct')) auto_commit: Optional[bool] = it_util.variant_to_value( self._gsettings.get_user_value('autocommit')) if auto_commit is None: if self.database.ime_properties.get('auto_commit'): auto_commit = self.database.ime_properties.get( 'auto_commit').lower() == 'true' else: auto_commit = it_util.variant_to_value( self._gsettings.get_value('autocommit')) self._auto_commit: bool = auto_commit # self._commit_invalid_mode: This selects what is committed # when a character which is not in the set of valid input # characters for the current table is typed. # # 0 means to commit the current candidate # 1 means to commit the raw characters typed so far self._commit_invalid_mode: int = it_util.variant_to_value( self._gsettings.get_value('commitinvalidmode')) # If auto select is true, then the first candidate phrase will # be selected automatically during typing. Auto select is true # by default for the stroke5 table for example. auto_select: Optional[bool] = it_util.variant_to_value( self._gsettings.get_user_value('autoselect')) if auto_select is None: if self.database.ime_properties.get('auto_select'): auto_select = self.database.ime_properties.get( 'auto_select').lower() == 'true' LOGGER.info('Got "auto_select" entry from database.') else: auto_select = it_util.variant_to_value( self._gsettings.get_value('autoselect')) self._auto_select: bool = auto_select always_show_lookup: Optional[bool] = it_util.variant_to_value( self._gsettings.get_user_value('alwaysshowlookup')) if always_show_lookup is None: if self.database.ime_properties.get('always_show_lookup'): always_show_lookup = self.database.ime_properties.get( 'always_show_lookup').lower() == 'true' LOGGER.info('Got "always_show_lookup" entry from database.') else: always_show_lookup = it_util.variant_to_value( self._gsettings.get_value('alwaysshowlookup')) self._always_show_lookup: bool = always_show_lookup # The values below will be reset in # self.clear_input_not_committed_to_preedit() self._chars_valid = '' # valid user input in table mode self._chars_invalid = '' # invalid user input in table mode self._chars_valid_update_candidates_last = '' self._chars_invalid_update_candidates_last = '' # self._candidates holds the “best” candidates matching the user input # [(tabkeys, phrase, freq, user_freq), ...] self._candidates: List[Tuple[str, str, int, int]] = [] self._candidates_previous: List[Tuple[str, str, int, int]] = [] # self._u_chars: holds the user input of the phrases which # have been automatically committed to preedit (but not yet # “really” committed). self._u_chars: List[str] = [] # self._strings: holds the phrases which have been # automatically committed to preedit (but not yet “really” # committed). # # self._u_chars and self._strings should always have the same # length, if I understand it correctly. # # Example when using the wubi-jidian86 table: # # self._u_chars = ['gaaa', 'gggg', 'ihty'] # self._strings = ['形式', '王', '小'] # # I.e. after typing 'gaaa', '形式' is in the preedit and # both self._u_chars and self._strings are empty. When typing # another 'g', the maximum key length of the wubi table (which is 4) # is exceeded and '形式' is automatically committed to the preedit # (but not yet “really” committed, i.e. not yet committed into # the application). The key 'gaaa' and the matching phrase '形式' # are stored in self._u_chars and self._strings respectively # and 'gaaa' is removed from self._chars_valid. Now self._chars_valid # contains only the 'g' which starts a new search for candidates ... # When removing the 'g' with backspace, the 'gaaa' is moved # back from self._u_chars into self._chars_valid again and # the same candidate list is shown as before the last 'g' had # been entered. self._strings: List[str] = [] # self._cursor_precommit: The cursor # position in the array of strings which have already been # committed to preëdit but not yet “really” committed. self._cursor_precommit = 0 self._prompt_characters = eval( self.database.ime_properties.get('char_prompts')) # self._onechar: whether we only select single character self._onechar: bool = it_util.variant_to_value( self._gsettings.get_value('onechar')) # self._chinese_mode: the candidate filter mode, # 0 means to show simplified Chinese only # 1 means to show traditional Chinese only # 2 means to show all characters but show simplified Chinese first # 3 means to show all characters but show traditional Chinese first # 4 means to show all characters # we use LC_CTYPE or LANG to determine which one to use if # no default comes from the user GSettings. chinese_mode: Optional[int] = it_util.variant_to_value( self._gsettings.get_user_value('chinesemode')) if chinese_mode is None: chinese_mode = it_util.get_default_chinese_mode( self.database) elif DEBUG_LEVEL > 1: LOGGER.debug( 'Chinese mode found in Gsettings, mode=%s', chinese_mode) self._chinese_mode: int = chinese_mode # If auto select is true, then the first candidate phrase will # be selected automatically during typing. Auto select is true # by default for the stroke5 table for example. self._auto_select = it_util.variant_to_value( self._gsettings.get_user_value('autoselect')) if self._auto_select is None: if self.database.ime_properties.get('auto_select') is not None: self._auto_select = self.database.ime_properties.get( 'auto_select').lower() == 'true' if self._auto_select is None: self._auto_select = it_util.variant_to_value( self._gsettings.get_value('autoselect')) self._default_keybindings: Dict[str, List[str]] = {} self._default_keybindings = it_util.get_default_keybindings( self._gsettings, self.database) self._page_size: int = it_util.variant_to_value( self._gsettings.get_default_value('lookuptablepagesize')) for index in range(1, 10): if not self._default_keybindings[ 'commit_candidate_%s' % (index + 1)]: self._page_size = min(index, self._page_size) break user_page_size: Optional[int] = it_util.variant_to_value( self._gsettings.get_user_value('lookuptablepagesize')) if user_page_size is not None: self._page_size = user_page_size orientation: Optional[int] = it_util.variant_to_value( self._gsettings.get_user_value('lookuptableorientation')) if orientation is None: orientation = self.database.get_orientation() self._orientation: int = orientation user_keybindings = it_util.variant_to_value( self._gsettings.get_user_value('keybindings')) if not user_keybindings: user_keybindings = {} self.set_keybindings(user_keybindings, update_gsettings=False) use_dark_theme = it_util.variant_to_value( self._gsettings.get_user_value('darktheme')) if use_dark_theme: self.set_dark_theme(True, update_gsettings=False) self._lookup_table = self.get_new_lookup_table() self.chinese_mode_properties = { 'ChineseMode.Simplified': { 'number': 0, 'symbol': '簡', 'icon': 'sc-mode.svg', # Translators: This is the menu entry to select # when one wants to input only Simplified Chinese. 'label': _('Simplified Chinese'), 'tooltip': _('Switch to “Simplified Chinese only”.')}, 'ChineseMode.Traditional': { 'number': 1, 'symbol': '繁', 'icon': 'tc-mode.svg', # Translators: This is the menu entry to select # when one wants to input only Traditonal Chinese 'label': _('Traditional Chinese'), 'tooltip': _('Switch to “Traditional Chinese only”.')}, 'ChineseMode.SimplifiedFirst': { 'number': 2, 'symbol': '簡/大', 'icon': 'scb-mode.svg', # Translators: This is the menu entry to select when # one wants to input both Simplified and Traditional # Chinese but wants the Simplified Chinese to be # preferred, i.e. shown higher up in the candidate # lists. 'label': _('Simplified Chinese first'), 'tooltip': _('Switch to “Simplified Chinese before traditional”.')}, 'ChineseMode.TraditionalFirst': { 'number': 3, 'symbol': '繁/大', 'icon': 'tcb-mode.svg', # Translators: This is the menu entry to select when # one wants to input both Simplified and Traditional # Chinese but wants the Traditional Chinese to be # preferred, i.e. shown higher up in the candidate # lists. 'label': _('Traditional Chinese first'), 'tooltip': _('Switch to “Traditional Chinese before simplified”.')}, 'ChineseMode.All': { 'number': 4, 'symbol': '大', 'icon': 'cb-mode.svg', # Translators: This is the menu entry to select when # one wants to input both Simplified and Traditional # Chinese and has no particular preference whether # simplified or traditional characters should be higher # up in the candidate lists. 'label': _('All Chinese characters'), 'tooltip': _('Switch to “All Chinese characters”.')} } self.chinese_mode_menu = { 'key': 'ChineseMode', 'label': _('Chinese mode'), 'tooltip': _('Switch Chinese mode'), 'shortcut_hint': repr( self._keybindings['switch_to_next_chinese_mode']), 'sub_properties': self.chinese_mode_properties } if self.database._is_chinese: self.input_mode_properties = { 'InputMode.Direct': { 'number': 0, 'symbol': '英', 'icon': 'english.svg', 'label': _('English'), 'tooltip': _('Switch to English input')}, 'InputMode.Table': { 'number': 1, 'symbol': '中', 'symbol_table': '中', 'symbol_pinyin': '拼音', 'icon': 'chinese.svg', 'label': _('Chinese'), 'tooltip': _('Switch to Chinese input')} } else: self.input_mode_properties = { 'InputMode.Direct': { 'number': 0, 'symbol': '☐' + self._symbol, 'icon': 'english.svg', 'label': _('Direct'), 'tooltip': _('Switch to direct input')}, 'InputMode.Table': { 'number': 1, 'symbol': '☑' + self._symbol, 'icon': 'ibus-table.svg', 'label': _('Table'), 'tooltip': _('Switch to table input')} } # The symbol of the property “InputMode” is displayed # in the input method indicator of the Gnome3 panel. # This depends on the property name “InputMode” and # is case sensitive! self.input_mode_menu = { 'key': 'InputMode', 'label': _('Input mode'), 'tooltip': _('Switch Input mode'), 'shortcut_hint': repr( self._keybindings['toggle_input_mode_on_off']), 'sub_properties': self.input_mode_properties } self.letter_width_properties = { 'LetterWidth.Half': { 'number': 0, 'symbol': '◑', 'icon': 'half-letter.svg', 'label': _('Half'), 'tooltip': _('Switch to halfwidth letters')}, 'LetterWidth.Full': { 'number': 1, 'symbol': '●', 'icon': 'full-letter.svg', 'label': _('Full'), 'tooltip': _('Switch to fullwidth letters')} } self.letter_width_menu = { 'key': 'LetterWidth', 'label': _('Letter width'), 'tooltip': _('Switch letter width'), 'shortcut_hint': repr( self._keybindings['toggle_letter_width']), 'sub_properties': self.letter_width_properties } self.punctuation_width_properties = { 'PunctuationWidth.Half': { 'number': 0, 'symbol': ',.', 'icon': 'half-punct.svg', 'label': _('Half'), 'tooltip': _('Switch to halfwidth punctuation')}, 'PunctuationWidth.Full': { 'number': 1, 'symbol': '、。', 'icon': 'full-punct.svg', 'label': _('Full'), 'tooltip': _('Switch to fullwidth punctuation')} } self.punctuation_width_menu = { 'key': 'PunctuationWidth', 'label': _('Punctuation width'), 'tooltip': _('Switch punctuation width'), 'shortcut_hint': repr( self._keybindings['toggle_punctuation_width']), 'sub_properties': self.punctuation_width_properties } self.pinyin_mode_properties = { 'PinyinMode.Table': { 'number': 0, 'symbol': '☐ 拼音', 'icon': 'tab-mode.svg', 'label': _('Table'), 'tooltip': _('Switch to table mode')}, 'PinyinMode.Pinyin': { 'number': 1, 'symbol': '☑ 拼音', 'icon': 'py-mode.svg', 'label': _('Pinyin'), 'tooltip': _('Switch to pinyin mode')} } self.pinyin_mode_menu = { 'key': 'PinyinMode', 'label': _('Pinyin mode'), 'tooltip': _('Switch pinyin mode'), 'shortcut_hint': repr( self._keybindings['toggle_pinyin_mode']), 'sub_properties': self.pinyin_mode_properties } self.suggestion_mode_properties = { 'SuggestionMode.Disabled': { 'number': 0, 'symbol': '☐ 联想', 'icon': 'tab-mode.svg', 'label': _('Suggestion disabled'), 'tooltip': _('Switch to suggestion mode')}, 'SuggestionMode.Enabled': { 'number': 1, 'symbol': '☑ 联想', 'icon': 'tab-mode.svg', 'label': _('Suggestion enabled'), 'tooltip': _('Switch to suggestion mode')} } self.suggestion_mode_menu = { 'key': 'SuggestionMode', 'label': _('Suggestion mode'), 'tooltip': _('Switch suggestion mode'), 'shortcut_hint': repr( self._keybindings['toggle_suggestion_mode']), 'sub_properties': self.suggestion_mode_properties } self.onechar_mode_properties = { 'OneCharMode.Phrase': { 'number': 0, 'symbol': '☐ 1', 'icon': 'phrase.svg', 'label': _('Multiple character match'), 'tooltip': _('Switch to matching multiple characters at once')}, 'OneCharMode.OneChar': { 'number': 1, 'symbol': '☑ 1', 'icon': 'onechar.svg', 'label': _('Single character match'), 'tooltip': _('Switch to matching only single characters')} } self.onechar_mode_menu = { 'key': 'OneCharMode', 'label': _('Onechar mode'), 'tooltip': _('Switch onechar mode'), 'shortcut_hint': repr( self._keybindings['toggle_onechar_mode']), 'sub_properties': self.onechar_mode_properties } self.autocommit_mode_properties = { 'AutoCommitMode.Direct': { 'number': 0, 'symbol': '☐ ↑', 'icon': 'ncommit.svg', 'label': _('Normal'), 'tooltip': _('Switch to normal commit mode ' + '(automatic commits go into the preedit ' + 'instead of into the application. ' + 'This enables automatic definitions of new shortcuts)')}, 'AutoCommitMode.Normal': { 'number': 1, 'symbol': '☑ ↑', 'icon': 'acommit.svg', 'label': _('Direct'), 'tooltip': _('Switch to direct commit mode ' + '(automatic commits go directly into the application)')} } self.autocommit_mode_menu = { 'key': 'AutoCommitMode', 'label': _('Auto commit mode'), 'tooltip': _('Switch autocommit mode'), 'shortcut_hint': repr( self._keybindings['toggle_autocommit_mode']), 'sub_properties': self.autocommit_mode_properties } self._init_properties() self._save_user_count = 0 self._save_user_start = time.time() self._save_user_count_max = SAVE_USER_COUNT_MAX self._save_user_timeout = SAVE_USER_TIMEOUT self.reset() self.sync_timeout_id = GObject.timeout_add_seconds( 1, self._sync_user_db) self.connect('process-key-event', self.__do_process_key_event) LOGGER.info( '********** Initialized and ready for input: **********') def get_new_lookup_table(self) -> IBus.LookupTable: ''' Get a new lookup table ''' lookup_table = IBus.LookupTable() lookup_table.clear() lookup_table.set_page_size(self._page_size) lookup_table.set_orientation(self._orientation) lookup_table.set_cursor_visible(True) lookup_table.set_round(True) for index in range(0, 10): label = '' if self._keybindings['commit_candidate_%s' % (index + 1)]: keybinding = self._keybindings[ 'commit_candidate_%s' % (index + 1)][0] key = it_util.keybinding_to_keyevent(keybinding) label = keybinding if key.unicode and not key.name.startswith('KP_'): label = key.unicode lookup_table.append_label(IBus.Text.new_from_string(label)) return lookup_table def clear_all_input_and_preedit(self) -> None: ''' Clear all input, whether committed to preëdit or not. ''' if DEBUG_LEVEL > 1: LOGGER.debug('clear_all_input_and_preedit()') self.clear_input_not_committed_to_preedit() self._u_chars = [] self._strings = [] self._cursor_precommit = 0 self._prefix = '' self._sg_mode_active = False self.update_candidates() def is_empty(self) -> bool: '''Checks whether the preëdit is empty Returns True if the preëdit is empty, False if not. ''' return self._chars_valid + self._chars_invalid == '' def clear_input_not_committed_to_preedit(self) -> None: ''' Clear the input which has not yet been committed to preëdit. ''' if DEBUG_LEVEL > 1: LOGGER.debug('clear_input_not_committed_to_preedit()') self._chars_valid = '' self._chars_invalid = '' self._chars_valid_update_candidates_last = '' self._chars_invalid_update_candidates_last = '' self._lookup_table.clear() self._lookup_table.set_cursor_visible(True) self._candidates = [] self._candidates_previous = [] def add_input(self, char: str) -> bool: ''' Add input character and update candidates. Returns “True” if candidates were found, “False” if not. ''' if (self._chars_invalid or (not self._py_mode and (char not in self._valid_input_chars + self._single_wildcard_char + self._multi_wildcard_char)) or (self._py_mode and (char not in self._pinyin_valid_input_chars + self._single_wildcard_char + self._multi_wildcard_char))): self._chars_invalid += char else: self._chars_valid += char res = self.update_candidates() return res def pop_input(self) -> str: '''remove and display last input char held''' last_input_char = '' if self._chars_invalid: last_input_char = self._chars_invalid[-1] self._chars_invalid = self._chars_invalid[:-1] elif self._chars_valid: last_input_char = self._chars_valid[-1] self._chars_valid = self._chars_valid[:-1] if (not self._chars_valid) and self._u_chars: self._chars_valid = self._u_chars.pop( self._cursor_precommit - 1) self._strings.pop(self._cursor_precommit - 1) self._cursor_precommit -= 1 self.update_candidates() return last_input_char def get_input_chars(self) -> str: '''get characters held, valid and invalid''' return self._chars_valid + self._chars_invalid def split_strings_committed_to_preedit( self, index: int, index_in_phrase: int) -> None: head = self._strings[index][:index_in_phrase] tail = self._strings[index][index_in_phrase:] self._u_chars.pop(index) self._strings.pop(index) self._u_chars.insert(index, self.database.parse_phrase(head)) self._strings.insert(index, head) self._u_chars.insert(index+1, self.database.parse_phrase(tail)) self._strings.insert(index+1, tail) def remove_preedit_before_cursor(self) -> None: '''Remove preëdit left of cursor''' if self._chars_invalid: return if self.get_input_chars(): self.commit_to_preedit() if not self._strings: return if self._cursor_precommit <= 0: return self._u_chars = self._u_chars[self._cursor_precommit:] self._strings = self._strings[self._cursor_precommit:] self._cursor_precommit = 0 def remove_preedit_after_cursor(self) -> None: '''Remove preëdit right of cursor''' if self._chars_invalid: return if self.get_input_chars(): self.commit_to_preedit() if not self._strings: return if self._cursor_precommit >= len(self._strings): return self._u_chars = self._u_chars[:self._cursor_precommit] self._strings = self._strings[:self._cursor_precommit] self._cursor_precommit = len(self._strings) def remove_preedit_character_before_cursor(self) -> None: '''Remove character before cursor in strings comitted to preëdit''' if self._chars_invalid: return if self.get_input_chars(): self.commit_to_preedit() if not self._strings: return if self._cursor_precommit < 1: return self._cursor_precommit -= 1 self._chars_valid = self._u_chars.pop(self._cursor_precommit) self._strings.pop(self._cursor_precommit) self.update_candidates() def remove_preedit_character_after_cursor(self) -> None: '''Remove character after cursor in strings committed to preëdit''' if self._chars_invalid: return if self.get_input_chars(): self.commit_to_preedit() if not self._strings: return if self._cursor_precommit > len(self._strings) - 1: return self._u_chars.pop(self._cursor_precommit) self._strings.pop(self._cursor_precommit) def get_preedit_tabkeys_parts( self) -> Tuple[Tuple[str, ...], str, Tuple[str, ...]]: '''Returns the tabkeys which were used to type the parts of the preëdit string. Such as “(left_of_current_edit, current_edit, right_of_current_edit)” “left_of_current_edit” and “right_of_current_edit” are strings of tabkeys which have been typed to get the phrases which have already been committed to preëdit, but not “really” committed yet. “current_edit” is the string of tabkeys of the part of the preëdit string which is not committed at all. For example, the return value could look like: (('gggg', 'aahw'), 'adwu', ('ijgl', 'jbus')) See also get_preedit_string_parts() which might return something like (('王', '工具'), '其', ('漫画', '最新')) when the wubi-jidian86 table is used. ''' left_of_current_edit: Tuple[str, ...] = () current_edit = '' right_of_current_edit: Tuple[str, ...] = () if self.get_input_chars(): current_edit = self.get_input_chars() if self._u_chars: left_of_current_edit = tuple( self._u_chars[:self._cursor_precommit]) right_of_current_edit = tuple( self._u_chars[self._cursor_precommit:]) return (left_of_current_edit, current_edit, right_of_current_edit) def get_preedit_tabkeys_complete(self) -> str: '''Returns the tabkeys which belong to the parts of the preëdit string as a single string ''' (left_tabkeys, current_tabkeys, right_tabkeys) = self.get_preedit_tabkeys_parts() return (''.join(left_tabkeys) + current_tabkeys + ''.join(right_tabkeys)) def get_preedit_string_parts( self) -> Tuple[Tuple[str, ...], str, Tuple[str, ...]]: '''Returns the phrases which are parts of the preëdit string. Such as “(left_of_current_edit, current_edit, right_of_current_edit)” “left_of_current_edit” and “right_of_current_edit” are tuples of strings which have already been committed to preëdit, but not “really” committed yet. “current_edit” is the phrase in the part of the preëdit string which is not yet committed at all. For example, the return value could look like: (('王', '工具'), '其', ('漫画', '最新')) See also get_preedit_tabkeys_parts() which might return something like (('gggg', 'aahw'), 'adwu', ('ijgl', 'jbus')) when the wubi-jidian86 table is used. ''' left_of_current_edit: Tuple[str, ...] = () current_edit = '' right_of_current_edit: Tuple[str, ...] = () if self._candidates: current_edit = self._candidates[ int(self._lookup_table.get_cursor_pos())][1] elif self.get_input_chars(): current_edit = self.get_input_chars() if self._strings: left_of_current_edit = tuple( self._strings[:self._cursor_precommit]) right_of_current_edit = tuple( self._strings[self._cursor_precommit:]) return (left_of_current_edit, current_edit, right_of_current_edit) def get_preedit_string_complete(self) -> str: '''Returns the phrases which are parts of the preëdit string as a single string ''' if self._sg_mode_active: if self._candidates: return self._candidates[ int(self._lookup_table.get_cursor_pos())][0] return '' (left_strings, current_string, right_strings) = self.get_preedit_string_parts() return (''.join(left_strings) + current_string + ''.join(right_strings)) def get_caret(self) -> int: '''Get caret position in preëdit string''' caret = 0 if self._cursor_precommit and self._strings: for part in self._strings[:self._cursor_precommit]: caret += len(part) if self._candidates: caret += len( self._candidates[int(self._lookup_table.get_cursor_pos())][1]) else: caret += len(self.get_input_chars()) return caret def arrow_left(self) -> None: '''Move cursor left in the preëdit string.''' if self._chars_invalid: return if self.get_input_chars(): self.commit_to_preedit() if not self._strings: return if self._cursor_precommit <= 0: return if len(self._strings[self._cursor_precommit-1]) <= 1: self._cursor_precommit -= 1 else: self.split_strings_committed_to_preedit( self._cursor_precommit-1, -1) self.update_candidates() def arrow_right(self) -> None: '''Move cursor right in the preëdit string.''' if self._chars_invalid: return if self.get_input_chars(): self.commit_to_preedit() if not self._strings: return if self._cursor_precommit >= len(self._strings): return self._cursor_precommit += 1 if len(self._strings[self._cursor_precommit-1]) > 1: self.split_strings_committed_to_preedit( self._cursor_precommit-1, 1) self.update_candidates() def control_arrow_left(self) -> None: '''Move cursor to the beginning of the preëdit string.''' if self._chars_invalid: return if self.get_input_chars(): self.commit_to_preedit() if not self._strings: return self._cursor_precommit = 0 self.update_candidates() def control_arrow_right(self) -> None: '''Move cursor to the end of the preëdit string''' if self._chars_invalid: return if self.get_input_chars(): self.commit_to_preedit() if not self._strings: return self._cursor_precommit = len(self._strings) self.update_candidates() def append_table_candidate( self, tabkeys: str = '', phrase: str = '', freq: int = 0, user_freq: int = 0) -> None: '''append table candidate to lookup table''' assert self._input_mode == 1 if DEBUG_LEVEL > 1: LOGGER.debug( 'tabkeys=%s phrase=%s freq=%s user_freq=%s', tabkeys, phrase, freq, user_freq) if not tabkeys or not phrase: return mwild = self._multi_wildcard_char swild = self._single_wildcard_char if ((mwild and mwild in self._chars_valid) or (swild and swild in self._chars_valid)): # show all tabkeys if wildcard in tabkeys remaining_tabkeys = tabkeys else: regexp = self._chars_valid regexp = re.escape(regexp) match = re.match(r'^' + regexp, tabkeys) if match: remaining_tabkeys = tabkeys[match.end():] else: # This should never happen! For the candidates # added to the lookup table here, a match has # been found for self._chars_valid in the database. # In that case, the above regular expression should # match as well. remaining_tabkeys = tabkeys if DEBUG_LEVEL > 1: LOGGER.debug( 'remaining_tabkeys=%s ' 'self._chars_valid=%s phrase=%s', remaining_tabkeys, self._chars_valid, phrase) table_code = '' if not self._py_mode: remaining_tabkeys_new = '' for char in remaining_tabkeys: if char in self._prompt_characters: remaining_tabkeys_new += self._prompt_characters[char] else: remaining_tabkeys_new += char remaining_tabkeys = remaining_tabkeys_new candidate_text = phrase + ' ' + remaining_tabkeys if table_code: candidate_text = candidate_text + ' ' + table_code attrs = IBus.AttrList() attrs.append(IBus.attr_foreground_new( self.theme["candidate_text"], 0, len(candidate_text))) if freq < 0: # this is a user defined phrase: attrs.append( IBus.attr_foreground_new( self.theme["user_phrase"], 0, len(phrase))) elif user_freq > 0: # this is a system phrase which has already been used by the user: attrs.append(IBus.attr_foreground_new( self.theme["system_phrase"], 0, len(phrase))) else: # this is a system phrase that has not been used yet: attrs.append(IBus.attr_foreground_new( self.theme["system_phrase_unused"], 0, len(phrase))) if DEBUG_LEVEL > 0: debug_text = ' ' + str(freq) + ' ' + str(user_freq) candidate_text += debug_text attrs.append(IBus.attr_foreground_new( self.theme["debug_text"], len(candidate_text) - len(debug_text), len(candidate_text))) text = IBus.Text.new_from_string(candidate_text) i = 0 while attrs.get(i) is not None: attr = attrs.get(i) text.append_attribute(attr.get_attr_type(), attr.get_value(), attr.get_start_index(), attr.get_end_index()) i += 1 self._lookup_table.append_candidate(text) self._lookup_table.set_cursor_visible(True) @staticmethod def get_common_prefix_sorted_list(asc_table_codes: List[str]) -> List[int]: prefix_tree: List[List[Tuple[Any, ...]]] = [] idx = -1 count = 1 ''' (branch from, node index of branch from), (code, asc table codes index, same prefix count), ... for input ["w","wx","wxa","wxb","wxbc","wccd", "wxbd", "ilonga"] build a tree like this (-1, 0),('w', 0, 1),('wx', 1, 2),('wxa', 2, 3), (0, 2),('wxb', 3, 3),('wxbc', 4, 4), (0, 1),('wccd', 5, 2), (1, 1),('wxbd', 6, 4), (-1, 0),('ilonga', 7, 1), ''' for code_idx in range(len(asc_table_codes)): branch_count = len(prefix_tree) code = asc_table_codes[code_idx] branch_idx = branch_count - 1 node_idx = 0 # traverse branches while branch_idx >= 0: prefix_branch = prefix_tree[branch_idx] branch_count = len(prefix_branch) node_idx = branch_count - 1 # traverse nodes while node_idx > 0: node = prefix_branch[node_idx] if code.startswith(node[0]): # make a leaf if node_idx == branch_count - 1: # extends branch prefix_branch.append((code, code_idx, node[2] + 1)) else: # in a new branch new_branch = [(branch_idx, node_idx), (code, code_idx, node[2] + 1)] prefix_tree.append(new_branch) break else: # next node node_idx -= 1 if node_idx > 0: break else: # next branch branch_idx -= 1 if node_idx == 0: # new root branch new_branch = [(branch_idx, node_idx), (code, code_idx, 1)] prefix_tree.append(new_branch) # tree leaf holds the max same-prefix count code nodes = [branch[-1] for branch in prefix_tree] # sort by max same-prefix count then idx nodes = sorted(nodes, key=lambda n: int(n[2]) * 16 + int(n[1]), reverse=True) idx_array = [node[1] for node in nodes] return idx_array def select_best_idx_from_prefix_list(self, asc_table_codes: List[str], sorted_idx_list: List[int]) -> int: if self._engine_name == 'erbi-qs': # for erbi-qs, code start with i/u/v is auxiliary for i in sorted_idx_list: first_char = asc_table_codes[i][0] if first_char in ('i', 'u', 'v'): continue else: return i return sorted_idx_list[0] def append_pinyin_candidate( self, tabkeys: str = '', phrase:str = '', freq: int =0, user_freq: int = 0) -> None: '''append pinyin candidate to lookup table''' assert self._input_mode == 1 assert self._py_mode if DEBUG_LEVEL > 1: LOGGER.debug( 'tabkeys=%s phrase=%s freq=%s user_freq=%s', tabkeys, phrase, freq, user_freq) if not tabkeys or not phrase: return regexp = self._chars_valid regexp = re.escape(regexp) match = re.match(r'^'+regexp, tabkeys) if match: remaining_tabkeys = tabkeys[match.end():] else: # This should never happen! For the candidates # added to the lookup table here, a match has # been found for self._chars_valid in the database. # In that case, the above regular expression should # match as well. remaining_tabkeys = tabkeys if DEBUG_LEVEL > 1: LOGGER.debug( 'remaining_tabkeys=%s ' 'self._chars_valid=%s phrase=%s', remaining_tabkeys, self._chars_valid, phrase) table_code = '' if self.database._is_chinese and self._py_mode: # restore tune symbol remaining_tabkeys = remaining_tabkeys.replace( '!', '↑1').replace( '@', '↑2').replace( '#', '↑3').replace( '$', '↑4').replace( '%', '↑5') # If in pinyin mode, phrase can only be one character. # When using pinyin mode for a table like Wubi or Cangjie, # the reason is probably because one does not know the # Wubi or Cangjie code. So get that code from the table # and display it as well to help the user learn that code. # The Wubi tables contain several codes for the same # character, therefore self.database.find_zi_code(phrase) may # return a list. The last code in that list is the full # table code for that characters, other entries in that # list are shorter substrings of the full table code which # are not interesting to display. Therefore, we use only # the last element of the list of table codes. possible_table_codes = self.database.find_zi_code(phrase) if possible_table_codes: idx_array = self.get_common_prefix_sorted_list(possible_table_codes) idx = self.select_best_idx_from_prefix_list(possible_table_codes, idx_array) table_code = possible_table_codes[idx] table_code_new = '' for char in table_code: if char in self._prompt_characters: table_code_new += self._prompt_characters[char] else: table_code_new += char table_code = table_code_new candidate_text = phrase + ' ' + remaining_tabkeys if table_code: candidate_text = candidate_text + ' ' + table_code attrs = IBus.AttrList() attrs.append(IBus.attr_foreground_new( self.theme["candidate_text"], 0, len(candidate_text))) # this is a pinyin character: attrs.append(IBus.attr_foreground_new( self.theme["system_phrase"], 0, len(phrase))) if DEBUG_LEVEL > 0: debug_text = ' ' + str(freq) + ' ' + str(user_freq) candidate_text += debug_text attrs.append(IBus.attr_foreground_new( self.theme["debug_text"], len(candidate_text) - len(debug_text), len(candidate_text))) text = IBus.Text.new_from_string(candidate_text) i = 0 while attrs.get(i) is not None: attr = attrs.get(i) text.append_attribute(attr.get_attr_type(), attr.get_value(), attr.get_start_index(), attr.get_end_index()) i += 1 self._lookup_table.append_candidate(text) self._lookup_table.set_cursor_visible(True) def append_suggestion_candidate( self, prefix: str = '', phrase: str = '', freq: int = 0, user_freq: int = 0) -> None: '''append suggestion candidate to lookup table''' assert self._input_mode == 1 assert self._sg_mode if DEBUG_LEVEL > 1: LOGGER.debug( 'tabkeys=%s phrase=%s freq=%s user_freq=%s', prefix, phrase, freq, user_freq) if not prefix or not phrase: return if not phrase.startswith(prefix): return candidate_text = phrase attrs = IBus.AttrList() attrs.append(IBus.attr_foreground_new( self.theme["candidate_text"], 0, len(candidate_text))) # this is a suggestion candidate: attrs.append(IBus.attr_foreground_new( self.theme["system_phrase"], 0, len(phrase))) if DEBUG_LEVEL > 0: debug_text = ' ' + str(freq) + ' ' + str(user_freq) candidate_text += debug_text attrs.append(IBus.attr_foreground_new( self.theme["debug_text"], len(candidate_text) - len(debug_text), len(candidate_text))) text = IBus.Text.new_from_string(candidate_text) i = 0 while attrs.get(i) is not None: attr = attrs.get(i) text.append_attribute(attr.get_attr_type(), attr.get_value(), attr.get_start_index(), attr.get_end_index()) i += 1 self._lookup_table.append_candidate(text) self._lookup_table.set_cursor_visible(True) def update_candidates(self, force: bool = False) -> bool: ''' Searches for candidates and updates the lookuptable. :param force: Force update candidates even if no change to input Returns “True” if candidates were found and “False” if not. ''' if DEBUG_LEVEL > 1: LOGGER.debug( 'self._chars_valid=%s ' 'self._chars_invalid=%s ' 'self._chars_valid_update_candidates_last=%s ' 'self._chars_invalid_update_candidates_last=%s ' 'self._candidates=%s ' 'self.database.startchars=%s ' 'self._strings=%s', self._chars_valid, self._chars_invalid, self._chars_valid_update_candidates_last, self._chars_invalid_update_candidates_last, self._candidates, self.database.startchars, self._strings) if (not force and not self._sg_mode_active and self._chars_valid == self._chars_valid_update_candidates_last and self._chars_invalid == self._chars_invalid_update_candidates_last): # The input did not change since we came here last, do # nothing and leave candidates and lookup table unchanged: return bool(self._candidates) self._chars_valid_update_candidates_last = self._chars_valid self._chars_invalid_update_candidates_last = self._chars_invalid self._lookup_table.clear() self._lookup_table.set_cursor_visible(True) if not self._sg_mode_active: if self._chars_invalid or not self._chars_valid: self._candidates = [] self._candidates_previous = self._candidates return False if (not self._sg_mode_active and self._py_mode and self.database._is_chinese): self._candidates = ( self.database.select_chinese_characters_by_pinyin( tabkeys=self._chars_valid, chinese_mode=self._chinese_mode, single_wildcard_char=self._single_wildcard_char, multi_wildcard_char=self._multi_wildcard_char)) elif not self._sg_mode_active: self._candidates = self.database.select_words( tabkeys=self._chars_valid, onechar=self._onechar, chinese_mode=self._chinese_mode, single_wildcard_char=self._single_wildcard_char, multi_wildcard_char=self._multi_wildcard_char, auto_wildcard=self._auto_wildcard, dynamic_adjust=self._dynamic_adjust) elif self._sg_mode_active and self._sg_mode: self._candidates = self.database.select_suggestion_candidate( self._prefix) else: assert False # If only a wildcard character has been typed, insert a # special candidate at the first position for the wildcard # character itself. For example, if “?” is used as a # wildcard character and this is the only character typed, add # a candidate ('?', '?', 0, 1000000000) in halfwidth mode or a # candidate ('?', '?', 0, 1000000000) in fullwidth mode. # This is needed to make it possible to input the wildcard # characters themselves, if “?” acted only as a wildcard # it would be impossible to input a fullwidth question mark. if not self._sg_mode_active: if (self._chars_valid in [self._single_wildcard_char, self._multi_wildcard_char]): wildcard_key = self._chars_valid wildcard_phrase = self._chars_valid if ascii_ispunct(wildcard_key): if self._full_width_punct[1]: wildcard_phrase = unichar_half_to_full(wildcard_phrase) else: wildcard_phrase = unichar_full_to_half(wildcard_phrase) else: if self._full_width_letter[1]: wildcard_phrase = unichar_half_to_full(wildcard_phrase) else: wildcard_phrase = unichar_full_to_half(wildcard_phrase) self._candidates.insert( 0, (wildcard_key, wildcard_phrase, 0, 1000000000)) if self._candidates: self.fill_lookup_table() self._candidates_previous = self._candidates return True # There are only valid and no invalid input characters but no # matching candidates could be found from the databases. The # last of self._chars_valid must have caused this. That # character is valid in the sense that it is listed in # self._valid_input_chars, it is only invalid in the sense # that after adding this character, no candidates could be # found anymore. Add this character to self._chars_invalid # and remove it from self._chars_valid. if self._chars_valid: self._chars_invalid += self._chars_valid[-1] self._chars_valid = self._chars_valid[:-1] self._chars_valid_update_candidates_last = self._chars_valid self._chars_invalid_update_candidates_last = self._chars_invalid return False def commit_to_preedit(self) -> bool: '''Add selected phrase in lookup table to preëdit string''' if not self._sg_mode_active: if not self._chars_valid: return False if self._candidates: if not self._sg_mode_active: phrase = self._candidates[self.get_cursor_pos()][1] self._u_chars.insert( self._cursor_precommit, self._candidates[self.get_cursor_pos()][0]) self._strings.insert( self._cursor_precommit, phrase) self._prefix = phrase elif self._sg_mode_active: phrase = self._candidates[self.get_cursor_pos()][0] phrase = phrase[len(self._prefix):] self._u_chars.insert(self._cursor_precommit, '') self._strings.insert(self._cursor_precommit, phrase) self._prefix = '' self._sg_mode_active = False else: assert False self._cursor_precommit += 1 self.clear_input_not_committed_to_preedit() self.update_candidates() return True def commit_to_preedit_current_page(self, index: int) -> bool: ''' Commits the candidate at position “index” in the current page of the lookup table to the preëdit. Does not yet “really” commit the candidate, only to the preëdit. ''' cursor_pos = self._lookup_table.get_cursor_pos() cursor_in_page = self._lookup_table.get_cursor_in_page() current_page_start = cursor_pos - cursor_in_page real_index = current_page_start + index if real_index >= len(self._candidates): # the index given is out of range we do not commit anything return False self._lookup_table.set_cursor_pos(real_index) return self.commit_to_preedit() def get_aux_strings(self) -> str: '''Get aux strings''' input_chars = self.get_input_chars() if input_chars: aux_string = input_chars if DEBUG_LEVEL > 0 and self._u_chars: (tabkeys_left, dummy_tabkeys_current, tabkeys_right) = self.get_preedit_tabkeys_parts() (strings_left, dummy_string_current, strings_right) = self.get_preedit_string_parts() aux_string = '' for i in range(0, len(strings_left)): aux_string += ( '(' + tabkeys_left[i] + ' '+ strings_left[i] + ') ') aux_string += input_chars for i in range(0, len(strings_right)): aux_string += ( ' (' + tabkeys_right[i]+' '+strings_right[i] + ')') if self._py_mode: aux_string = aux_string.replace( '!', '1').replace( '@', '2').replace( '#', '3').replace( '$', '4').replace( '%', '5') else: aux_string_new = '' for char in aux_string: if char in self._prompt_characters: aux_string_new += self._prompt_characters[char] else: aux_string_new += char aux_string = aux_string_new return aux_string # There are no input strings at the moment. But there could # be stuff committed to the preëdit. If there is something # committed to the preëdit, show some information in the # auxiliary text. # # For the character at the position of the cursor in the # preëdit, show a list of possible input key sequences which # could be used to type that character at the left side of the # auxiliary text. # # If the preëdit is longer than one character, show the input # key sequence which will be defined for the complete current # contents of the preëdit, if the preëdit is committed. aux_string = '' if self._strings: if self._cursor_precommit >= len(self._strings): char = self._strings[-1][0] else: char = self._strings[self._cursor_precommit][0] aux_string = ' '.join(self.database.find_zi_code(char)) cstr = ''.join(self._strings) if self.database.user_can_define_phrase: if len(cstr) > 1: aux_string += ('\t#: ' + self.database.parse_phrase(cstr)) aux_string_new = '' for char in aux_string: if char in self._prompt_characters: aux_string_new += self._prompt_characters[char] else: aux_string_new += char return aux_string_new def fill_lookup_table(self) -> None: '''Fill more entries to self._lookup_table if needed. If the cursor in _lookup_table moved beyond current length, add more entries from _candidiate[0] to _lookup_table.''' looklen = self._lookup_table.get_number_of_candidates() psize = self._lookup_table.get_page_size() if (self._lookup_table.get_cursor_pos() + psize >= looklen and looklen < len(self._candidates)): endpos = looklen + psize batch = self._candidates[looklen:endpos] for candidate in batch: if (self._input_mode and not self._py_mode and not self._sg_mode_active): self.append_table_candidate( tabkeys=candidate[0], phrase=candidate[1], freq=candidate[2], user_freq=candidate[3]) elif (self._input_mode and self._py_mode and not self._sg_mode_active): self.append_pinyin_candidate( tabkeys=candidate[0], phrase=candidate[1], freq=candidate[2], user_freq=candidate[3]) elif self._input_mode and self._sg_mode_active: self.append_suggestion_candidate( prefix=self._prefix, phrase=candidate[0], freq=int(candidate[1])) else: assert False def cursor_down(self) -> bool: '''Process Arrow Down Key Event Move Lookup Table cursor down''' self.fill_lookup_table() res = bool(self._lookup_table.cursor_down()) if not res and self._candidates: return True return res def cursor_up(self) -> bool: '''Process Arrow Up Key Event Move Lookup Table cursor up''' res = bool(self._lookup_table.cursor_up()) if not res and self._candidates: return True return res def page_down(self) -> bool: '''Process Page Down Key Event Move Lookup Table page down''' self.fill_lookup_table() res = bool(self._lookup_table.page_down()) if not res and self._candidates: return True return res def page_up(self) -> bool: '''Process Page Up Key Event move Lookup Table page up''' res = bool(self._lookup_table.page_up()) if not res and self._candidates: return True return res def remove_candidate_from_user_database(self, index: int) -> bool: '''Remove the candidate shown at index in the lookup table from the user database. If that candidate is not in the user database at all, nothing happens. If this is a candidate which is also in the system database, removing it from the user database only means that its user frequency data is reset. It might still appear in subsequent matches but with much lower priority. If this is a candidate which is user defined and not in the system database, it will not match at all anymore after removing it. :param index: The index in the current page of the lookup table. The topmost candidate has the index 0 (and usually the label “1”) :return: True if successful, False if not ''' if DEBUG_LEVEL > 1: LOGGER.debug('index=%s', index) cursor_pos = self._lookup_table.get_cursor_pos() cursor_in_page = self._lookup_table.get_cursor_in_page() current_page_start = cursor_pos - cursor_in_page real_index = current_page_start + index if len(self._candidates) > real_index: # this index is valid candidate = self._candidates[real_index] self.database.remove_phrase( tabkeys=candidate[0], phrase=candidate[1], commit=True) # call update_candidates() to get a new SQL query. The # input has not really changed, therefore we must clear # the remembered list of characters to # force update_candidates() to really do something and not # return immediately: self._chars_valid_update_candidates_last = '' self._chars_invalid_update_candidates_last = '' self.update_candidates() return True return False def get_cursor_pos(self) -> int: '''get lookup table cursor position''' return int(self._lookup_table.get_cursor_pos()) def get_lookup_table(self) -> IBus.LookupTable: '''Get lookup table''' return self._lookup_table def remove_char(self) -> None: '''Process remove_char Key Event''' if DEBUG_LEVEL > 1: LOGGER.debug('remove_char()') if self.get_input_chars(): self.pop_input() return self.remove_preedit_character_before_cursor() def delete(self) -> None: '''Process delete Key Event''' if self.get_input_chars(): return self.remove_preedit_character_after_cursor() def select_next_candidate_in_current_page(self) -> bool: '''Cycle cursor to next candidate in the page.''' total = len(self._candidates) if total > 0: page_size = self._lookup_table.get_page_size() pos = self._lookup_table.get_cursor_pos() page = int(pos/page_size) pos += 1 if pos >= (page+1)*page_size or pos >= total: pos = page*page_size self._lookup_table.set_cursor_pos(pos) return True return False def select_previous_candidate_in_current_page(self) -> bool: '''Cycle cursor to previous candidate in the page.''' total = len(self._candidates) if total > 0: page_size = self._lookup_table.get_page_size() pos = self._lookup_table.get_cursor_pos() page = int(pos/page_size) pos -= 1 if pos < page*page_size or pos < 0: pos = min(((page + 1) * page_size) - 1, total) self._lookup_table.set_cursor_pos(pos) return True return False def one_candidate(self) -> bool: '''Return true if there is only one candidate''' return len(self._candidates) == 1 def reset(self) -> None: '''Clear the preëdit and close the lookup table ''' self.clear_all_input_and_preedit() self._double_quotation_state = False self._single_quotation_state = False self._prev_key = None self._update_ui() def do_destroy(self) -> None: '''Called when this input engine is destroyed ''' if self.sync_timeout_id > 0: GObject.source_remove(self.sync_timeout_id) self.sync_timeout_id = 0 self.reset() self.do_focus_out() if self._save_user_count > 0: self.database.sync_usrdb() self._save_user_count = 0 super().destroy() def set_debug_level( self, debug_level: int, update_gsettings: bool = True) -> None: '''Sets the debug level :param debug_level: The debug level (>= 0 and <= 255) :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' global DEBUG_LEVEL if DEBUG_LEVEL > 1: LOGGER.debug( '(%s, update_gsettings = %s)', debug_level, update_gsettings) if debug_level == self._debug_level: return if 0 <= debug_level <= 255: self._debug_level = debug_level DEBUG_LEVEL = debug_level self.reset() if update_gsettings: self._gsettings.set_value( 'debuglevel', GLib.Variant.new_int32(debug_level)) def get_debug_level(self) -> int: '''Returns the current debug level''' return self._debug_level def set_dynamic_adjust( self, dynamic_adjust: bool, update_gsettings: bool = True) -> None: '''Sets whether dynamic adjustment of the candidates is used. :param dynamic_adjust: True if dynamic adjustment is used, False if not :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' if DEBUG_LEVEL > 1: LOGGER.debug( '(%s, update_gsettings = %s)', dynamic_adjust, update_gsettings) if dynamic_adjust == self._dynamic_adjust: return self._dynamic_adjust = dynamic_adjust self.database.reset_phrases_cache() if update_gsettings: self._gsettings.set_value( 'dynamicadjust', GLib.Variant.new_boolean(dynamic_adjust)) def get_dynamic_adjust(self) -> bool: '''Returns whether dynamic adjustment of the candidates is used.''' return self._dynamic_adjust def set_error_sound( self, error_sound: bool, update_gsettings: bool = True) -> None: '''Sets whether a sound is played on error or not :param error_sound: True if a sound is played on error, False if not :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' if DEBUG_LEVEL > 1: LOGGER.debug( '(%s, update_gsettings = %s)', error_sound, update_gsettings) if error_sound == self._error_sound: return self._error_sound = error_sound if update_gsettings: self._gsettings.set_value( 'errorsound', GLib.Variant.new_boolean(error_sound)) def get_error_sound(self) -> bool: '''Returns whether a sound is played on error or not''' return self._error_sound def set_error_sound_file( self, path: str = '', update_gsettings: bool = True) -> None: '''Sets the path of the .wav file containing the sound to play on error. :param path: The path of the .wav file containing the error sound :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if DEBUG_LEVEL > 1: LOGGER.debug( '(%s, update_gsettings = %s)', path, update_gsettings) if path == self._error_sound_file: return self._error_sound_file = path if update_gsettings: self._gsettings.set_value( 'errorsoundfile', GLib.Variant.new_string(path)) self._error_sound_object = it_sound.SoundObject( os.path.expanduser(path), audio_backend=self._sound_backend) def get_error_sound_file(self) -> str: ''' Return the path of the .wav file containing the error sound. ''' return self._error_sound_file def set_sound_backend( self, sound_backend: Union[str, Any], update_gsettings: bool = True) -> None: '''Sets the sound backend to use :param sound_backend: The name of sound backend to use :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if DEBUG_LEVEL > 1: LOGGER.debug( '(%s, update_gsettings = %s)', sound_backend, update_gsettings) if not isinstance(sound_backend, str): return if sound_backend == self._sound_backend: return self._sound_backend = sound_backend if update_gsettings: self._gsettings.set_value( 'soundbackend', GLib.Variant.new_string(sound_backend)) self._error_sound_object = it_sound.SoundObject( os.path.expanduser(self._error_sound_file), audio_backend=self._sound_backend) def get_sound_backend(self) -> str: ''' Return the name of the currently used sound backend ''' return self._sound_backend def set_keybindings(self, keybindings: Union[Dict[str, List[str]], Any], update_gsettings: bool = True) -> None: '''Set current key bindings :param keybindings: The key bindings to use :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' if DEBUG_LEVEL > 1: LOGGER.debug( '(%s, update_gsettings = %s)', keybindings, update_gsettings) if not isinstance(keybindings, dict): return keybindings = copy.deepcopy(keybindings) self._keybindings = copy.deepcopy(self._default_keybindings) # Update the default settings with the possibly changed settings: it_util.dict_update_existing_keys(self._keybindings, keybindings) # Update hotkeys: self._hotkeys = it_util.HotKeys(self._keybindings) # New keybindings might have changed the keys to commit candidates # from the lookup table and then the labels of the lookup table # might need to be updated: self._lookup_table = self.get_new_lookup_table() # Some property menus have tooltips which show hints for the # key bindings. These may need to be updated if the key # bindings have changed. # # I don’t check whether the key bindings really have changed, # just update all the properties anyway. # # But update them only if the properties have already been # initialized. At program start they might still be empty at # the time when self.set_keybindings() is called. if self._prop_dict: if self.chinese_mode_menu: self.chinese_mode_menu['shortcut_hint'] = ( repr(self._keybindings['switch_to_next_chinese_mode'])) if self.input_mode_menu: self.input_mode_menu['shortcut_hint'] = ( repr(self._keybindings['toggle_input_mode_on_off'])) if self.letter_width_menu: self.letter_width_menu['shortcut_hint'] = ( repr(self._keybindings['toggle_letter_width'])) if self.punctuation_width_menu: self.punctuation_width_menu['shortcut_hint'] = ( repr(self._keybindings['toggle_punctuation_width'])) if self.pinyin_mode_menu: self.pinyin_mode_menu['shortcut_hint'] = ( repr(self._keybindings['toggle_pinyin_mode'])) if self.suggestion_mode_menu: self.suggestion_mode_menu['shortcut_hint'] = ( repr(self._keybindings['toggle_suggestion_mode'])) if self.onechar_mode_menu: self.onechar_mode_menu['shortcut_hint'] = ( repr(self._keybindings['toggle_onechar_mode'])) if self.autocommit_mode_menu: self.autocommit_mode_menu['shortcut_hint'] = ( repr(self._keybindings['toggle_autocommit_mode'])) self._init_properties() if update_gsettings: variant_dict = GLib.VariantDict(GLib.Variant('a{sv}', {})) for command in sorted(self._keybindings): variant_array = GLib.Variant.new_array( GLib.VariantType('s'), [GLib.Variant.new_string(x) for x in self._keybindings[command]]) variant_dict.insert_value(command, variant_array) self._gsettings.set_value( 'keybindings', variant_dict.end()) def get_keybindings(self) -> Dict[str, List[str]]: '''Get current key bindings''' # It is important to return a copy, we do not want to change # the private member variable directly. return self._keybindings.copy() def set_input_mode(self, input_mode: int = 1, update_gsettings: bool = True) -> None: '''Sets whether direct input or the current table is used. :param input_mode: Whether to use direct input. 0: Use direct input. 1: Use the current table. ''' if input_mode == self._input_mode: return self._input_mode = input_mode if update_gsettings: self._gsettings.set_value( "inputmode", GLib.Variant.new_int32(self._input_mode)) self._init_or_update_property_menu( self.input_mode_menu, self._input_mode) # Letter width and punctuation width depend on the input mode. # Therefore, the properties for letter width and punctuation # width need to be updated here: self._init_or_update_property_menu( self.letter_width_menu, self._full_width_letter[self._input_mode]) self._init_or_update_property_menu( self.punctuation_width_menu, self._full_width_punct[self._input_mode]) self.reset() def set_remember_input_mode(self, remember_input_mode: bool = True, update_gsettings: bool = True) -> None: '''Sets whether the input mode (direct or table) is remembered :param remember_input_mode: Whether to remember the input mode. False: Do not remember True: Remember. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', remember_input_mode, update_gsettings) remember_input_mode = bool(remember_input_mode) if remember_input_mode == self._remember_input_mode: return self._remember_input_mode = remember_input_mode if update_gsettings: self._gsettings.set_value( 'rememberinputmode', GLib.Variant.new_boolean(remember_input_mode)) def get_remember_input_mode(self) -> bool: ''' Return whether the input mode is remembered. ''' return self._remember_input_mode def set_dark_theme( self, use_dark_theme: bool = False, update_gsettings: bool = True) -> None: '''Set theme to dark theme on request''' if use_dark_theme: theme = THEME_DARK else: theme = THEME if theme is not self.theme: self.theme = theme self._update_ui() if update_gsettings: self._gsettings.set_value( "darktheme", GLib.Variant.new_boolean(use_dark_theme)) def get_input_mode(self) -> int: ''' Return the current input mode, direct input: 0, table input: 1. ''' return self._input_mode def set_pinyin_mode(self, mode: bool = False) -> None: '''Sets whether Pinyin is used. :param mode: Whether to use Pinyin. True: Use Pinyin. False: Use the current table. :type mode: Boolean ''' if not self._ime_py: return if mode == self._py_mode: return # The pinyin mode is never saved to GSettings on purpose self._py_mode = mode self._init_or_update_property_menu( self.pinyin_mode_menu, mode) if mode: self.input_mode_properties['InputMode.Table']['symbol'] = ( self.input_mode_properties['InputMode.Table']['symbol_pinyin']) else: self.input_mode_properties['InputMode.Table']['symbol'] = ( self.input_mode_properties['InputMode.Table']['symbol_table']) self._init_or_update_property_menu( self.input_mode_menu, self._input_mode) self._update_ui() def get_pinyin_mode(self) -> bool: '''Return the current pinyin mode''' return self._py_mode def set_suggestion_mode(self, mode: bool = False) -> None: '''Sets whether Suggestion is used. :param mode: Whether to use Suggestion. True: Use Suggestion. False: Not use Suggestion. ''' if not self._ime_sg: return if mode == self._sg_mode: return self.commit_to_preedit() self._sg_mode = mode self._init_or_update_property_menu( self.suggestion_mode_menu, mode) self._update_ui() def get_suggestion_mode(self) -> bool: '''Return the current suggestion mode''' return self._sg_mode def set_onechar_mode( self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets whether only single characters should be matched in the database. :param mode: Whether only single characters should be matched. True: Match only single characters. False: Possibly match multiple characters at once. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if mode == self._onechar: return self._onechar = mode self._init_or_update_property_menu( self.onechar_mode_menu, mode) self.database.reset_phrases_cache() if update_gsettings: self._gsettings.set_value( "onechar", GLib.Variant.new_boolean(mode)) def get_onechar_mode(self) -> bool: ''' Returns whether only single characters are matched in the database. ''' return self._onechar def set_autocommit_mode( self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets whether automatic commits go into the preëdit or into the application. :param mode: Whether automatic commits go into the preëdit or into the application. True: Into the application. False: Into the preëdit. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if mode == self._auto_commit: return self._auto_commit = mode self._init_or_update_property_menu( self.autocommit_mode_menu, mode) if update_gsettings: self._gsettings.set_value( "autocommit", GLib.Variant.new_boolean(mode)) def get_autocommit_mode(self) -> bool: '''Returns the current auto-commit mode''' return self._auto_commit def set_commit_invalid_mode( self, mode: int = 0, update_gsettings: bool = True) -> None: '''Sets the commit invalid mode This selects what is committed when a character which is not in the set of valid input characters for the current table is typed. 0 means to commit the current candidate 1 means to commit the raw characters typed so far :param mode: The mode (0 <= mode <= 1) :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if DEBUG_LEVEL > 1: LOGGER.debug('mode=%s', mode) if mode == self._commit_invalid_mode: return self._commit_invalid_mode = mode if update_gsettings: self._gsettings.set_value( "commitinvalidmode", GLib.Variant.new_int32(mode)) def get_commit_invalid_mode(self) -> int: '''Return the current comimt invalid mode''' return self._commit_invalid_mode def set_autoselect_mode( self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets whether the first candidate will be selected automatically during typing. :param mode: Whether to select the first candidate automatically. :type mode: Boolean :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. :type update_gsettings: Boolean ''' if mode == self._auto_select: return self._auto_select = mode if update_gsettings: self._gsettings.set_value( "autoselect", GLib.Variant.new_boolean(mode)) def get_autoselect_mode(self) -> bool: '''Returns the current auto-select mode''' return self._auto_select def set_autowildcard_mode( self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets whether a wildcard should be automatically appended to the input. :param mode: Whether to append a wildcard automatically. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if mode == self._auto_wildcard: return self._auto_wildcard = mode self.database.reset_phrases_cache() if update_gsettings: self._gsettings.set_value( "autowildcard", GLib.Variant.new_boolean(mode)) def get_autowildcard_mode(self) -> bool: '''Returns the current automatic wildcard mode''' return self._auto_wildcard def set_single_wildcard_char( self, char: str = '', update_gsettings: bool = True) -> None: '''Sets the single wildchard character. :param char: The character to use as a single wildcard (String of length 1). :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if char == self._single_wildcard_char: return self._single_wildcard_char = char self.database.reset_phrases_cache() if update_gsettings: self._gsettings.set_value( "singlewildcardchar", GLib.Variant.new_string(char)) def get_single_wildcard_char(self) -> str: ''' Return the character currently used as a single wildcard. (String of length 1.) ''' return self._single_wildcard_char def set_multi_wildcard_char( self, char: str = '', update_gsettings: bool = True) -> None: '''Sets the multi wildchard character. :param char: The character to use as a multi wildcard. (String of length 1.) :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if len(char) > 1: char = char[0] if char == self._multi_wildcard_char: return self._multi_wildcard_char = char self.database.reset_phrases_cache() if update_gsettings: self._gsettings.set_value( "multiwildcardchar", GLib.Variant.new_string(char)) def get_multi_wildcard_char(self) -> str: ''' Return the character currently used as a multi wildcard. (String of length 1.) ''' return self._multi_wildcard_char def set_always_show_lookup( self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets the whether the lookup table is shown. :param mode: Whether to show the lookup table. True: Lookup table is shown False: Lookup table is hidden :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if mode == self._always_show_lookup: return self._always_show_lookup = mode if update_gsettings: self._gsettings.set_value( "alwaysshowlookup", GLib.Variant.new_boolean(mode)) def get_always_show_lookup(self) -> bool: '''Returns whether the lookup table is shown or hidden''' return self._always_show_lookup def set_lookup_table_orientation( self, orientation: int, update_gsettings: bool = True) -> None: '''Sets the orientation of the lookup table :param orientation: The orientation of the lookup table 0 <= orientation <= 2 IBUS_ORIENTATION_HORIZONTAL = 0, IBUS_ORIENTATION_VERTICAL = 1, IBUS_ORIENTATION_SYSTEM = 2. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if DEBUG_LEVEL > 1: LOGGER.debug('orientation(%s)', orientation) if orientation == self._orientation: return if 0 <= orientation <= 2: self._orientation = orientation self._lookup_table.set_orientation(orientation) if update_gsettings: self._gsettings.set_value( 'lookuptableorientation', GLib.Variant.new_int32(orientation)) def get_lookup_table_orientation(self) -> int: '''Returns the current orientation of the lookup table''' return self._orientation def set_page_size( self, page_size: int, update_gsettings: bool = True) -> None: '''Sets the page size of the lookup table :param page_size: The page size of the lookup table 1 <= page size <= number of select keys :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if DEBUG_LEVEL > 1: LOGGER.debug('page_size=%s', page_size) if page_size == self._page_size: return for index in range(1, 10): if not self._default_keybindings[ 'commit_candidate_%s' % (index + 1)]: page_size = min(index, page_size) break if page_size < 1: page_size = 1 self._page_size = page_size # get a new lookup table to adapt to the new page size: self._lookup_table = self.get_new_lookup_table() self.reset() if update_gsettings: self._gsettings.set_value( 'lookuptablepagesize', GLib.Variant.new_int32(page_size)) def get_page_size(self) -> int: '''Returns the current page size of the lookup table''' return self._page_size def set_letter_width( self, mode: bool = False, input_mode: int = 0, update_gsettings: bool = True) -> None: ''' Sets whether full width letters should be used. :param mode: Whether to use full width letters :param input_mode: The input mode (direct input: 0, table: 1) for which to set the full width letter mode. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' if mode == self._full_width_letter[input_mode]: return self._full_width_letter[input_mode] = mode if input_mode == self._input_mode: self._init_or_update_property_menu( self.letter_width_menu, mode) if update_gsettings: if input_mode: self._gsettings.set_value( "tabdeffullwidthletter", GLib.Variant.new_boolean(mode)) else: self._gsettings.set_value( "endeffullwidthletter", GLib.Variant.new_boolean(mode)) def get_letter_width(self) -> List[Optional[bool]]: '''Return the current full width letter modes: [Boolean, Boolean]''' return self._full_width_letter def set_punctuation_width( self, mode: bool = False, input_mode: int = 0, update_gsettings: bool = True) -> None: ''' Sets whether full width punctuation should be used. :param mode: Whether to use full width punctuation :param input_mode: The input mode (direct input: 0, table: 1) for which to set the full width punctuation mode. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' if mode == self._full_width_punct[input_mode]: return self._full_width_punct[input_mode] = mode if input_mode == self._input_mode: self._init_or_update_property_menu( self.punctuation_width_menu, mode) if update_gsettings: if input_mode: self._gsettings.set_value( "tabdeffullwidthpunct", GLib.Variant.new_boolean(mode)) else: self._gsettings.set_value( "endeffullwidthpunct", GLib.Variant.new_boolean(mode)) def get_punctuation_width(self) -> List[Optional[bool]]: '''Return the current full width punctuation modes: [Boolean, Boolean] ''' return self._full_width_punct def set_chinese_mode( self, mode: int = 0, update_gsettings: bool = True) -> None: '''Sets the candidate filter mode used for Chinese 0 means to show simplified Chinese only 1 means to show traditional Chinese only 2 means to show all characters but show simplified Chinese first 3 means to show all characters but show traditional Chinese first 4 means to show all characters :param mode: The Chinese filter mode, 0 <= mode <= 4 :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' if DEBUG_LEVEL > 1: LOGGER.debug('mode=%s', mode) if mode == self._chinese_mode: return self._chinese_mode = mode self.database.reset_phrases_cache() self._init_or_update_property_menu( self.chinese_mode_menu, mode) if update_gsettings: self._gsettings.set_value( "chinesemode", GLib.Variant.new_int32(mode)) def get_chinese_mode(self) -> int: ''' Return the current Chinese mode. 0 means to show simplified Chinese only 1 means to show traditional Chinese only 2 means to show all characters but show simplified Chinese first 3 means to show all characters but show traditional Chinese first 4 means to show all characters ''' return self._chinese_mode def _init_or_update_property_menu( self, menu: Dict[str, Any], current_mode: Union[int, bool, None] = 0) -> None: ''' Initialize or update a ibus property menu ''' if DEBUG_LEVEL > 1: LOGGER.debug( 'menu=%s current_mode=%s', repr(menu), current_mode) if not current_mode: current_mode = 0 menu_key = menu['key'] sub_properties_dict = menu['sub_properties'] for prop in sub_properties_dict: if sub_properties_dict[prop]['number'] == int(current_mode): symbol = sub_properties_dict[prop]['symbol'] icon = sub_properties_dict[prop]['icon'] label = '{label} ({symbol}) {shortcut_hint}'.format( label=menu['label'], symbol=symbol, shortcut_hint=menu['shortcut_hint']) tooltip = '{tooltip}\n{shortcut_hint}'.format( tooltip=menu['tooltip'], shortcut_hint=menu['shortcut_hint']) visible = True self._init_or_update_sub_properties( menu_key, sub_properties_dict, current_mode=current_mode) if menu_key not in self._prop_dict: # initialize property self._prop_dict[menu_key] = IBus.Property( key=menu_key, prop_type=IBus.PropType.MENU, label=IBus.Text.new_from_string(label), symbol=IBus.Text.new_from_string(symbol), icon=os.path.join(self._icon_dir, icon), tooltip=IBus.Text.new_from_string(tooltip), sensitive=visible, visible=visible, state=IBus.PropState.UNCHECKED, sub_props=self._sub_props_dict[menu_key]) self.main_prop_list.append(self._prop_dict[menu_key]) else: # update the property self._prop_dict[menu_key].set_label( IBus.Text.new_from_string(label)) self._prop_dict[menu_key].set_symbol( IBus.Text.new_from_string(symbol)) self._prop_dict[menu_key].set_icon( os.path.join(self._icon_dir, icon)) self._prop_dict[menu_key].set_tooltip( IBus.Text.new_from_string(tooltip)) self._prop_dict[menu_key].set_sensitive(visible) self._prop_dict[menu_key].set_visible(visible) self.update_property(self._prop_dict[menu_key]) # important! def _init_or_update_sub_properties( self, menu_key: str, modes: Dict[str, Any], current_mode: int = 0) -> None: ''' Initialize or update the sub-properties of a property menu entry. ''' if menu_key not in self._sub_props_dict: update = False self._sub_props_dict[menu_key] = IBus.PropList() else: update = True visible = True for mode in sorted(modes, key=lambda x: (int(modes[x]['number']))): if modes[mode]['number'] == int(current_mode): state = IBus.PropState.CHECKED else: state = IBus.PropState.UNCHECKED label = modes[mode]['label'] if 'tooltip' in modes[mode]: tooltip = modes[mode]['tooltip'] else: tooltip = '' if not update: # initialize property self._prop_dict[mode] = IBus.Property( key=mode, prop_type=IBus.PropType.RADIO, label=IBus.Text.new_from_string(label), icon=os.path.join(modes[mode]['icon']), tooltip=IBus.Text.new_from_string(tooltip), sensitive=visible, visible=visible, state=state, sub_props=None) self._sub_props_dict[menu_key].append( self._prop_dict[mode]) else: # update property self._prop_dict[mode].set_label( IBus.Text.new_from_string(label)) self._prop_dict[mode].set_tooltip( IBus.Text.new_from_string(tooltip)) self._prop_dict[mode].set_sensitive(visible) self._prop_dict[mode].set_visible(visible) self._prop_dict[mode].set_state(state) self.update_property(self._prop_dict[mode]) # important! def _init_properties(self) -> None: ''' Initialize the ibus property menus ''' self._prop_dict = {} self._sub_props_dict = {} self.main_prop_list = IBus.PropList() self._init_or_update_property_menu( self.input_mode_menu, self._input_mode) if self.database._is_chinese and self._chinese_mode != -1: self._init_or_update_property_menu( self.chinese_mode_menu, self._chinese_mode) if self.database._is_cjk: self._init_or_update_property_menu( self.letter_width_menu, self._full_width_letter[self._input_mode]) self._init_or_update_property_menu( self.punctuation_width_menu, self._full_width_punct[self._input_mode]) if self._ime_py: self._init_or_update_property_menu( self.pinyin_mode_menu, self._py_mode) if self._ime_sg: self._init_or_update_property_menu( self.suggestion_mode_menu, self._sg_mode) if self.database._is_cjk: self._init_or_update_property_menu( self.onechar_mode_menu, self._onechar) if self.database.user_can_define_phrase and self.database.rules: self._init_or_update_property_menu( self.autocommit_mode_menu, self._auto_commit) self._setup_property = IBus.Property( key='setup', label=IBus.Text.new_from_string(_('Setup')), icon='gtk-preferences', tooltip=IBus.Text.new_from_string( _('Configure ibus-table “%(engine-name)s”') % {'engine-name': self._engine_name}), sensitive=True, visible=True) self.main_prop_list.append(self._setup_property) self.register_properties(self.main_prop_list) def do_property_activate( self, ibus_property: str, prop_state: IBus.PropState = IBus.PropState.UNCHECKED) -> None: ''' Handle clicks on properties ''' if DEBUG_LEVEL > 1: LOGGER.debug( 'ibus_property=%s prop_state=%s', ibus_property, prop_state) if ibus_property == "setup": self._start_setup() return if prop_state != IBus.PropState.CHECKED: # If the mouse just hovered over a menu button and # no sub-menu entry was clicked, there is nothing to do: return if ibus_property.startswith(self.input_mode_menu['key']+'.'): self.set_input_mode( self.input_mode_properties[ibus_property]['number']) return if (ibus_property.startswith(self.pinyin_mode_menu['key']+'.') and self._ime_py): self.set_pinyin_mode( bool(self.pinyin_mode_properties[ibus_property]['number'])) return if (ibus_property.startswith(self.suggestion_mode_menu['key']+'.') and self._ime_sg): self.set_suggestion_mode( bool(self.suggestion_mode_properties[ibus_property]['number'])) return if (ibus_property.startswith(self.onechar_mode_menu['key']+'.') and self.database._is_cjk): self.set_onechar_mode( bool(self.onechar_mode_properties[ibus_property]['number'])) return if (ibus_property.startswith(self.autocommit_mode_menu['key']+'.') and self.database.user_can_define_phrase and self.database.rules): self.set_autocommit_mode( bool(self.autocommit_mode_properties[ibus_property]['number'])) return if (ibus_property.startswith(self.letter_width_menu['key']+'.') and self.database._is_cjk): self.set_letter_width( bool(self.letter_width_properties[ibus_property]['number']), input_mode=self._input_mode) return if (ibus_property.startswith(self.punctuation_width_menu['key']+'.') and self.database._is_cjk): self.set_punctuation_width( bool(self.punctuation_width_properties[ ibus_property]['number']), input_mode=self._input_mode) return if (ibus_property.startswith(self.chinese_mode_menu['key']+'.') and self.database._is_chinese and self._chinese_mode != -1): self.set_chinese_mode( self.chinese_mode_properties[ibus_property]['number']) return def _start_setup(self) -> None: ''' Start the setup tool if it is not running yet. ''' if self._setup_pid != 0: pid, dummy_state = os.waitpid(self._setup_pid, os.P_NOWAIT) if pid != self._setup_pid: # If the last setup tool started from here is still # running the pid returned by the above os.waitpid() # is 0. In that case just return, don’t start a # second setup tool. return self._setup_pid = 0 setup_cmd = os.path.join( str(os.getenv('IBUS_TABLE_LIB_LOCATION')), 'ibus-setup-table') self._setup_pid = os.spawnl( os.P_NOWAIT, setup_cmd, 'ibus-setup-table', '--engine-name table:%s' %self._engine_name) def _play_error_sound(self) -> None: '''Play an error sound if enabled and possible''' if self._error_sound and self._error_sound_object: try: self._error_sound_object.play() except: LOGGER.exception('Playing error sound failed.') def _update_preedit(self) -> None: '''Update Preedit String in UI''' if self._sg_mode_active: self.hide_preedit_text() return preedit_string_parts = self.get_preedit_string_parts() left_of_current_edit = ''.join(preedit_string_parts[0]) current_edit = preedit_string_parts[1] right_of_current_edit = ''.join(preedit_string_parts[2]) if self._input_mode and not self._sg_mode_active: current_edit_new = '' for char in current_edit: if char in self._prompt_characters: current_edit_new += self._prompt_characters[char] else: current_edit_new += char current_edit = current_edit_new preedit_string_complete = ( left_of_current_edit + current_edit + right_of_current_edit) if not preedit_string_complete: # Not using super().update_preedit_text_with_mode() because # IBus.EngineSimple does not have that method. IBus.Engine.update_preedit_text_with_mode( self, IBus.Text.new_from_string(''), 0, False, IBus.PreeditFocusMode.COMMIT) return color_left = self.theme["preedit_left"] # bright red color_right = self.theme["preedit_right"] # light green color_invalid = self.theme["preedit_invalid"] # magenta attrs = IBus.AttrList() attrs.append( IBus.attr_foreground_new( color_left, 0, len(left_of_current_edit))) attrs.append( IBus.attr_foreground_new( color_right, len(left_of_current_edit) + len(current_edit), len(preedit_string_complete))) if self._chars_invalid: self._play_error_sound() attrs.append( IBus.attr_foreground_new( color_invalid, len(left_of_current_edit) + len(current_edit) - len(self._chars_invalid), len(left_of_current_edit) + len(current_edit) )) attrs.append( IBus.attr_underline_new( IBus.AttrUnderline.SINGLE, 0, len(preedit_string_complete))) text = IBus.Text.new_from_string(preedit_string_complete) i = 0 while attrs.get(i) is not None: attr = attrs.get(i) text.append_attribute(attr.get_attr_type(), attr.get_value(), attr.get_start_index(), attr.get_end_index()) i += 1 # Not using super().update_preedit_text_with_mode() because # IBus.EngineSimple does not have that method. IBus.Engine.update_preedit_text_with_mode( self, text, self.get_caret(), True, IBus.PreeditFocusMode.COMMIT) def _update_aux(self) -> None: '''Update Aux String in UI''' if self._sg_mode_active: return aux_string = self.get_aux_strings() if self._candidates: aux_string += ' (%d / %d)' % ( self._lookup_table.get_cursor_pos() +1, self._lookup_table.get_number_of_candidates()) if aux_string: if DEBUG_LEVEL > 0 and not self._unit_test: client = f'🪟{self._im_client}' aux_string += client attrs = IBus.AttrList() attrs.append(IBus.attr_foreground_new( self.theme["aux_text"], 0, len(aux_string))) text = IBus.Text.new_from_string(aux_string) i = 0 while attrs.get(i) is not None: attr = attrs.get(i) text.append_attribute(attr.get_attr_type(), attr.get_value(), attr.get_start_index(), attr.get_end_index()) i += 1 visible = True if not aux_string or not self._always_show_lookup: visible = False super().update_auxiliary_text(text, visible) else: self.hide_auxiliary_text() def _update_lookup_table(self) -> None: '''Update Lookup Table in UI''' if not self._candidates: # Also make sure to hide lookup table if there are # no candidates to display. On f17, this makes no # difference but gnome-shell in f18 will display # an empty suggestion popup if the number of candidates # is zero! self.hide_lookup_table() return if self._input_mode and not self._sg_mode_active: if self.is_empty(): self.hide_lookup_table() return if not self._always_show_lookup: self.hide_lookup_table() return self.update_lookup_table(self.get_lookup_table(), True) def _update_ui(self) -> None: '''Update User Interface''' self._update_lookup_table() self._update_preedit() self._update_aux() def _check_phrase(self, tabkeys: str = '', phrase: str = '') -> None: """Check the given phrase and update save user db info""" if not tabkeys or not phrase: return self.database.check_phrase( tabkeys=tabkeys, phrase=phrase, dynamic_adjust=self._dynamic_adjust) if self._save_user_count <= 0: self._save_user_start = time.time() self._save_user_count += 1 def _sync_user_db(self) -> bool: """Save user db to disk""" if self._save_user_count >= 0: now = time.time() time_delta = now - self._save_user_start if (self._save_user_count > self._save_user_count_max or time_delta >= self._save_user_timeout): self.database.sync_usrdb() self._save_user_count = 0 self._save_user_start = now return True def commit_string(self, phrase: str, tabkeys: str = '') -> None: ''' Commit the string “phrase”, update the user database, and clear the preëdit. :param phrase: The text to commit :param tabkeys: The keys typed to produce this text ''' if DEBUG_LEVEL > 1: LOGGER.debug('phrase=%s', phrase) self.clear_all_input_and_preedit() self._update_ui() self._prefix = phrase super().commit_text(IBus.Text.new_from_string(phrase)) if phrase: self._prev_char = phrase[-1] else: self._prev_char = None self._check_phrase(tabkeys=tabkeys, phrase=phrase) def commit_everything_unless_invalid(self) -> bool: ''' Commits the current input to the preëdit and then commits the preëdit to the application unless there are invalid input characters. Returns “True” if something was committed, “False” if not. ''' if DEBUG_LEVEL > 1: LOGGER.debug('self._chars_invalid=%s', self._chars_invalid) if self._chars_invalid: return False if self._input_mode and self._sg_mode_active: self.commit_to_preedit() if not self.is_empty(): self.commit_to_preedit() self.commit_string(self.get_preedit_string_complete(), tabkeys=self.get_preedit_tabkeys_complete()) return True def _convert_to_full_width(self, char: str) -> str: '''Convert half width character to full width''' # This function handles punctuation that does not comply to the # Unicode conversion formula in unichar_half_to_full(char). # For ".", "\"", "'"; there are even variations under specific # cases. This function should be more abstracted by extracting # that to another handling function later on. special_punct_dict = {"<": "《", # 《 U+300A LEFT DOUBLE ANGLE BRACKET ">": "》", # 》 U+300B RIGHT DOUBLE ANGLE BRACKET "[": "「", # 「 U+300C LEFT CORNER BRACKET "]": "」", # 」U+300D RIGHT CORNER BRACKET "{": "『", # 『 U+300E LEFT WHITE CORNER BRACKET "}": "』", # 』U+300F RIGHT WHITE CORNER BRACKET "\\": "、", # 、 U+3001 IDEOGRAPHIC COMMA "^": "……", # … U+2026 HORIZONTAL ELLIPSIS "_": "——", # — U+2014 EM DASH "$": "¥" # ¥ U+FFE5 FULLWIDTH YEN SIGN } # special puncts w/o further conditions if char in special_punct_dict.keys(): if char in ["\\", "^", "_", "$"]: return special_punct_dict[char] if self._input_mode: return special_punct_dict[char] # special puncts w/ further conditions if char == ".": if (self._prev_char and self._prev_char.isdigit() and self._prev_key and chr(self._prev_key.val) == self._prev_char): return "." return "。" # 。U+3002 IDEOGRAPHIC FULL STOP if char == "\"": self._double_quotation_state = not self._double_quotation_state if self._double_quotation_state: return "“" # “ U+201C LEFT DOUBLE QUOTATION MARK return "”" # ” U+201D RIGHT DOUBLE QUOTATION MARK if char == "'": self._single_quotation_state = not self._single_quotation_state if self._single_quotation_state: return "‘" # ‘ U+2018 LEFT SINGLE QUOTATION MARK return "’" # ’ U+2019 RIGHT SINGLE QUOTATION MARK return unichar_half_to_full(char) def do_candidate_clicked( self, index: int, _button: int, _state: int) -> bool: if DEBUG_LEVEL > 1: LOGGER.debug('index=%s _button=%s state=%s', index, _button, _state) if self.commit_to_preedit_current_page(index): # commits to preëdit self.commit_string( self.get_preedit_string_complete(), tabkeys=self.get_preedit_tabkeys_complete()) return True return False def _command_setup(self) -> bool: '''Handle hotkey for the command “setup” :return: True if the key was completely handled, False if not. ''' self._start_setup() return True def _command_toggle_input_mode_on_off(self) -> bool: '''Handle hotkey for the command “toggle_input_mode_on_off” :return: True if the key was completely handled, False if not. ''' if not self.is_empty(): commit_string = self.get_preedit_tabkeys_complete() self.commit_string(commit_string) self.set_input_mode(int(not self._input_mode)) return True def _command_toggle_letter_width(self) -> bool: '''Handle hotkey for the command “toggle_letter_width” :return: True if the key was completely handled, False if not. ''' if not self.database._is_cjk: return False self.set_letter_width( not self._full_width_letter[self._input_mode], input_mode=self._input_mode) return True def _command_toggle_punctuation_width(self) -> bool: '''Handle hotkey for the command “toggle_punctuation_width” :return: True if the key was completely handled, False if not. ''' if not self.database._is_cjk: return False self.set_punctuation_width( not self._full_width_punct[self._input_mode], input_mode=self._input_mode) return True def _command_cancel(self) -> bool: '''Handle hotkey for the command “cancel” :return: True if the key was completely handled, False if not. ''' if self.is_empty(): return False self.reset() self._update_ui() return True def _command_toggle_suggestion_mode(self) -> bool: '''Handle hotkey for the command “toggle_suggestion_mode” :return: True if the key was completely handled, False if not. ''' if not self._ime_sg: return False self.set_suggestion_mode(not self._sg_mode) return True def _command_commit_to_preedit(self) -> bool: '''Handle hotkey for the command “commit_to_preedit” :return: True if the key was completely handled, False if not. ''' if self.is_empty(): return False res = self.commit_to_preedit() self._update_ui() return res def _command_toggle_pinyin_mode(self) -> bool: '''Handle hotkey for the command “toggle_pinyin_mode” :return: True if the key was completely handled, False if not. ''' if not self._ime_py: return False self.set_pinyin_mode(not self._py_mode) if not self.is_empty(): # Feed the current input in once again to get # the candidates and preedit to update correctly # for the new mode: chars = self._chars_valid + self._chars_invalid self._chars_valid = '' self._chars_invalid = '' for char in chars: self.add_input(char) self.update_candidates(force=True) self._update_ui() return True def _command_select_next_candidate_in_current_page(self) -> bool: '''Handle hotkey for the command “select_next_candidate_in_current_page” :return: True if the key was completely handled, False if not. ''' res = self.select_next_candidate_in_current_page() self._update_ui() return res def _command_select_previous_candidate_in_current_page(self) -> bool: '''Handle hotkey for the command “select_previous_candidate_in_current_page” :return: True if the key was completely handled, False if not. ''' res = self.select_previous_candidate_in_current_page() self._update_ui() return res def _command_toggle_onechar_mode(self) -> bool: '''Handle hotkey for the command “toggle_onechar_mode” :return: True if the key was completely handled, False if not. ''' if not self.database._is_cjk: return False self.set_onechar_mode(not self._onechar) if not self.is_empty(): self.update_candidates(True) self._update_ui() return True def _command_toggle_autocommit_mode(self) -> bool: '''Handle hotkey for the command “toggle_autocommit_mode” :return: True if the key was completely handled, False if not. ''' if self.database.user_can_define_phrase and self.database.rules: self.set_autocommit_mode(not self._auto_commit) return True return False def _command_switch_to_next_chinese_mode(self) -> bool: '''Handle hotkey for the command “switch_to_next_chinese_mode” :return: True if the key was completely handled, False if not. ''' if not self.database._is_chinese: return False self.set_chinese_mode((self._chinese_mode+1) % 5) if not self.is_empty(): self.update_candidates(True) self._update_ui() return True def _command_commit(self) -> bool: '''Handle hotkey for the command “commit” :return: True if the key was completely handled, False if not. ''' if (self._u_chars or not self.is_empty() or self._sg_mode_active): if self.commit_everything_unless_invalid(): if self._auto_select: self.commit_string(' ') if (self._sg_mode and self._input_mode and not self._sg_mode_active): self._sg_mode_active = True self.update_candidates() self._update_ui() return True return False def _command_lookup_table_page_down(self) -> bool: '''Handle hotkey for the command “lookup_table_page_down” :return: True if the key was completely handled, False if not. ''' if not self._candidates: return False res = self.page_down() self._update_ui() return res def _command_lookup_table_page_up(self) -> bool: '''Handle hotkey for the command “lookup_table_page_up” :return: True if the key was completely handled, False if not. ''' if not self._candidates: return False res = self.page_up() self._update_ui() return res def _execute_commit_candidate_to_preedit_number(self, number: int) -> bool: '''Execute the hotkey command “commit_candidate_to_preedit_” :return: True if the key was completely handled, False if not. :param number: The number of the candidate ''' if self.client_capabilities & it_util.Capabilite.OSK: LOGGER.info( 'OSK is visible: ' 'do not commit candidate to preedit by number %s', number) return False if not self._candidates: return False index = number - 1 res = self.commit_to_preedit_current_page(index) self._update_ui() return res def _command_commit_candidate_to_preedit_1(self) -> bool: '''Handle hotkey for the command “commit_candidate_to_preedit_1” :return: True if the key was completely handled, False if not. ''' return self._execute_commit_candidate_to_preedit_number(1) def _command_commit_candidate_to_preedit_2(self) -> bool: '''Handle hotkey for the command “commit_candidate_to_preedit_2” :return: True if the key was completely handled, False if not. ''' return self._execute_commit_candidate_to_preedit_number(2) def _command_commit_candidate_to_preedit_3(self) -> bool: '''Handle hotkey for the command “commit_candidate_to_preedit_3” :return: True if the key was completely handled, False if not. ''' return self._execute_commit_candidate_to_preedit_number(3) def _command_commit_candidate_to_preedit_4(self) -> bool: '''Handle hotkey for the command “commit_candidate_to_preedit_4” :return: True if the key was completely handled, False if not. ''' return self._execute_commit_candidate_to_preedit_number(4) def _command_commit_candidate_to_preedit_5(self) -> bool: '''Handle hotkey for the command “commit_candidate_to_preedit_5” :return: True if the key was completely handled, False if not. ''' return self._execute_commit_candidate_to_preedit_number(5) def _command_commit_candidate_to_preedit_6(self) -> bool: '''Handle hotkey for the command “commit_candidate_to_preedit_6” :return: True if the key was completely handled, False if not. ''' return self._execute_commit_candidate_to_preedit_number(6) def _command_commit_candidate_to_preedit_7(self) -> bool: '''Handle hotkey for the command “commit_candidate_to_preedit_7” :return: True if the key was completely handled, False if not. ''' return self._execute_commit_candidate_to_preedit_number(7) def _command_commit_candidate_to_preedit_8(self) -> bool: '''Handle hotkey for the command “commit_candidate_to_preedit_8” :return: True if the key was completely handled, False if not. ''' return self._execute_commit_candidate_to_preedit_number(8) def _command_commit_candidate_to_preedit_9(self) -> bool: '''Handle hotkey for the command “commit_candidate_to_preedit_9” :return: True if the key was completely handled, False if not. ''' return self._execute_commit_candidate_to_preedit_number(9) def _command_commit_candidate_to_preedit_10(self) -> bool: '''Handle hotkey for the command “commit_candidate_to_preedit_10” :return: True if the key was completely handled, False if not. ''' return self._execute_commit_candidate_to_preedit_number(10) def _execute_remove_candidate_number(self, number: int) -> bool: '''Execute the hotkey command “remove_candidate_” :return: True if the key was completely handled, False if not. :param number: The number of the candidate ''' if self.client_capabilities & it_util.Capabilite.OSK: LOGGER.info( 'OSK is visible: do not remove candidate by number %s', number) return False if not self._candidates: return False index = number - 1 res = self.remove_candidate_from_user_database(index) self._update_ui() return res def _command_remove_candidate_1(self) -> bool: '''Handle hotkey for the command “remove_candidate_1” :return: True if the key was completely handled, False if not. ''' return self._execute_remove_candidate_number(1) def _command_remove_candidate_2(self) -> bool: '''Handle hotkey for the command “remove_candidate_2” :return: True if the key was completely handled, False if not. ''' return self._execute_remove_candidate_number(2) def _command_remove_candidate_3(self) -> bool: '''Handle hotkey for the command “remove_candidate_3” :return: True if the key was completely handled, False if not. ''' return self._execute_remove_candidate_number(3) def _command_remove_candidate_4(self) -> bool: '''Handle hotkey for the command “remove_candidate_4” :return: True if the key was completely handled, False if not. ''' return self._execute_remove_candidate_number(4) def _command_remove_candidate_5(self) -> bool: '''Handle hotkey for the command “remove_candidate_5” :return: True if the key was completely handled, False if not. ''' return self._execute_remove_candidate_number(5) def _command_remove_candidate_6(self) -> bool: '''Handle hotkey for the command “remove_candidate_6” :return: True if the key was completely handled, False if not. ''' return self._execute_remove_candidate_number(6) def _command_remove_candidate_7(self) -> bool: '''Handle hotkey for the command “remove_candidate_7” :return: True if the key was completely handled, False if not. ''' return self._execute_remove_candidate_number(7) def _command_remove_candidate_8(self) -> bool: '''Handle hotkey for the command “remove_candidate_8” :return: True if the key was completely handled, False if not. ''' return self._execute_remove_candidate_number(8) def _command_remove_candidate_9(self) -> bool: '''Handle hotkey for the command “remove_candidate_9” :return: True if the key was completely handled, False if not. ''' return self._execute_remove_candidate_number(9) def _command_remove_candidate_10(self) -> bool: '''Handle hotkey for the command “remove_candidate_10” :return: True if the key was completely handled, False if not. ''' return self._execute_remove_candidate_number(10) def _execute_command_commit_candidate_number(self, number: int) -> bool: '''Execute the hotkey command “commit_candidate_” :return: True if the key was completely handled, False if not. :param number: The number of the candidate ''' if self.client_capabilities & it_util.Capabilite.OSK: LOGGER.info( 'OSK is visible: do not commit candidate by number %s', number) return False if not self._candidates or number > len(self._candidates): return False index = number - 1 if not 0 <= index < self._page_size: return False if self.commit_to_preedit_current_page(index): self.commit_string( self.get_preedit_string_complete(), tabkeys=self.get_preedit_tabkeys_complete()) if (self._sg_mode and self._input_mode and not self._sg_mode_active): self._sg_mode_active = True self.update_candidates() self._update_ui() return True return False def _command_commit_candidate_1(self) -> bool: '''Handle hotkey for the command “commit_candidate_1” :return: True if the key was completely handled, False if not. ''' return self._execute_command_commit_candidate_number(1) def _command_commit_candidate_2(self) -> bool: '''Handle hotkey for the command “commit_candidate_2” :return: True if the key was completely handled, False if not. ''' return self._execute_command_commit_candidate_number(2) def _command_commit_candidate_3(self) -> bool: '''Handle hotkey for the command “commit_candidate_3” :return: True if the key was completely handled, False if not. ''' return self._execute_command_commit_candidate_number(3) def _command_commit_candidate_4(self) -> bool: '''Handle hotkey for the command “commit_candidate_4” :return: True if the key was completely handled, False if not. ''' return self._execute_command_commit_candidate_number(4) def _command_commit_candidate_5(self) -> bool: '''Handle hotkey for the command “commit_candidate_5” :return: True if the key was completely handled, False if not. ''' return self._execute_command_commit_candidate_number(5) def _command_commit_candidate_6(self) -> bool: '''Handle hotkey for the command “commit_candidate_6” :return: True if the key was completely handled, False if not. ''' return self._execute_command_commit_candidate_number(6) def _command_commit_candidate_7(self) -> bool: '''Handle hotkey for the command “commit_candidate_7” :return: True if the key was completely handled, False if not. ''' return self._execute_command_commit_candidate_number(7) def _command_commit_candidate_8(self) -> bool: '''Handle hotkey for the command “commit_candidate_8” :return: True if the key was completely handled, False if not. ''' return self._execute_command_commit_candidate_number(8) def _command_commit_candidate_9(self) -> bool: '''Handle hotkey for the command “commit_candidate_9” :return: True if the key was completely handled, False if not. ''' return self._execute_command_commit_candidate_number(9) def _command_commit_candidate_10(self) -> bool: '''Handle hotkey for the command “commit_candidate_10” :return: True if the key was completely handled, False if not. ''' return self._execute_command_commit_candidate_number(10) def _handle_hotkeys( self, key: it_util.KeyEvent, commands: Iterable[str] = ()) -> Tuple[bool, bool]: '''Handle hotkey commands :return: True if the key was completely handled, False if not. :param key: The typed key. If this is a hotkey, execute the command for this hotkey. :param commands: A list of commands to check whether the key matches the keybinding for one of these commands. If the list of commands is empty, check *all* commands in the self._keybindings dictionary. ''' if DEBUG_LEVEL > 1: LOGGER.debug('KeyEvent object: %s\n', key) if DEBUG_LEVEL > 5: LOGGER.debug('self._hotkeys=%s\n', str(self._hotkeys)) if not commands: # If no specific command list to match is given, try to # match against all commands. Sorting shouldn’t really # matter, but maybe better do it sorted, then it is done # in the same order as the commands are displayed by # default in the setup tool. commands = sorted(self._keybindings.keys()) for command in commands: if (self._prev_key, key, command) in self._hotkeys: # type: ignore if DEBUG_LEVEL > 1: LOGGER.debug('matched command=%s', command) command_function_name = '_command_%s' % command try: command_function = getattr(self, command_function_name) except (AttributeError,): LOGGER.exception('There is no function %s', command_function_name) return (False, False) if command_function(): if key.name in ('Shift_L', 'Shift_R', 'Control_L', 'Control_R', 'Alt_L', 'Alt_R', 'Meta_L', 'Meta_R', 'Super_L', 'Super_R', 'ISO_Level3_Shift'): return(True, False) return (True, True) return (False, False) def _return_false(self, keyval: int, keycode: int, state: int) -> bool: '''A replacement for “return False” in do_process_key_event() do_process_key_event should return “True” if a key event has been handled completely. It should return “False” if the key event should be passed to the application. But just doing “return False” doesn’t work well when trying to do the unit tests. The MockEngine class in the unit tests cannot get that return value. Therefore, it cannot do the necessary updates to the self._mock_committed_text etc. which prevents proper testing of the effects of such keys passed to the application. Instead of “return False”, one can also use self.forward_key_event(keyval, keycode, keystate) to pass the key to the application. And this works fine with the unit tests because a forward_key_event function is implemented in MockEngine as well which then gets the key and can test its effects. Unfortunately, “forward_key_event()” does not work in Qt5 applications because the ibus module in Qt5 does not implement “forward_key_event()”. Therefore, always using “forward_key_event()” instead of “return False” in “do_process_key_event()” would break ibus-typing-table completely for all Qt5 applictions. To work around this problem and make unit testing possible without breaking Qt5 applications, we use this helper function which uses “forward_key_event()” when unit testing and “return False” during normal usage. ''' if self._unit_test: self.forward_key_event(keyval, keycode, state) return True return False def __do_process_key_event( self, _obj: IBus.EngineSimple, keyval: int, keycode: int, state: int) -> bool: '''This function is connected to the 'process-key-event' signal.''' return self._do_process_key_event(keyval, keycode, state) def _do_process_key_event( self, keyval: int, keycode: int, state: int) -> bool: '''Process Key Events Key Events include Key Press and Key Release, modifier means Key Pressed ''' key = it_util.KeyEvent(keyval, keycode, state) if DEBUG_LEVEL > 1: LOGGER.debug('KeyEvent object: %s', key) if (self._input_purpose in [it_util.InputPurpose.PASSWORD.value, it_util.InputPurpose.PIN.value]): if DEBUG_LEVEL > 0: LOGGER.debug( 'Disable because of input purpose PASSWORD or PIN') return self._return_false(keyval, keycode, state) result = self._process_key_event(key) self._prev_key = key return result def _process_key_event(self, key: it_util.KeyEvent) -> bool: ''' Internal method to process key event Returns True if the key event has been completely handled by ibus-table and should not be passed through anymore. Returns False if the key event has not been handled completely and is passed through. ''' (match, return_value) = self._handle_hotkeys( key, commands=['toggle_input_mode_on_off', 'toggle_letter_width', 'toggle_punctuation_width', 'setup']) if match: return return_value if self._input_mode: (match, return_value) = self._handle_hotkeys(key) if match: return return_value return self._table_mode_process_key_event(key) return self._english_mode_process_key_event(key) def cond_letter_translate(self, char: str) -> str: '''Converts “char” to full width *if* full width letter mode is on for the current input mode (direct input or table mode) *and* if the current table is for CJK. :param char: The character to maybe convert to full width ''' if self._full_width_letter[self._input_mode] and self.database._is_cjk: return self._convert_to_full_width(char) return char def cond_punct_translate(self, char: str) -> str: '''Converts “char” to full width *if* full width punctuation mode is on for the current input mode (direct input or table mode) *and* if the current table is for CJK. :param char: The character to maybe convert to full width ''' if self._full_width_punct[self._input_mode] and self.database._is_cjk: return self._convert_to_full_width(char) return char def _english_mode_process_key_event(self, key: it_util.KeyEvent) -> bool: ''' Process a key event in “English” (“Direct input”) mode. ''' # Ignore key release events if key.state & IBus.ModifierType.RELEASE_MASK: return self._return_false(key.val, key.code, key.state) if key.val >= 128: return self._return_false(key.val, key.code, key.state) # we ignore all hotkeys here if (key.state & (IBus.ModifierType.CONTROL_MASK |IBus.ModifierType.MOD1_MASK)): return self._return_false(key.val, key.code, key.state) keychar = IBus.keyval_to_unicode(key.val) if ascii_ispunct(keychar): trans_char = self.cond_punct_translate(keychar) else: trans_char = self.cond_letter_translate(keychar) if trans_char == keychar: return self._return_false(key.val, key.code, key.state) self.commit_string(trans_char) return True def _table_mode_process_key_event(self, key: it_util.KeyEvent) -> bool: ''' Process a key event in “Table” mode, i.e. when the table is actually used and not switched off by using direct input. ''' if DEBUG_LEVEL > 0: LOGGER.debug('repr(key)=%s', repr(key)) # Ignore key release events (Should be below all hotkey matches # because some of them might match on a release event) if key.state & IBus.ModifierType.RELEASE_MASK: return self._return_false(key.val, key.code, key.state) keychar = IBus.keyval_to_unicode(key.val) # Section to handle leading invalid input: # # This is the first character typed, if it is invalid # input, handle it immediately here, if it is valid, continue. if (self.is_empty() and not self.get_preedit_string_complete()): if ((keychar not in ( self._valid_input_chars + self._single_wildcard_char + self._multi_wildcard_char) or (self.database.startchars and keychar not in self.database.startchars)) and (not key.state & (IBus.ModifierType.MOD1_MASK | IBus.ModifierType.CONTROL_MASK))): if DEBUG_LEVEL > 0: LOGGER.debug( 'leading invalid input: ' 'keychar=%s', keychar) if ascii_ispunct(keychar): trans_char = self.cond_punct_translate(keychar) else: trans_char = self.cond_letter_translate(keychar) if trans_char == keychar: self._prev_char = trans_char return self._return_false(key.val, key.code, key.state) self.commit_string(trans_char) return True if key.val in (IBus.KEY_Return, IBus.KEY_KP_Enter): if (self.is_empty() and not self.get_preedit_string_complete()): # When IBus.KEY_Return is typed, # IBus.keyval_to_unicode(key.val) returns a non-empty # string. But when IBus.KEY_KP_Enter is typed it # returns an empty string. Therefore, when typing # IBus.KEY_KP_Enter as leading input, the key is not # handled by the section to handle leading invalid # input but it ends up here. If it is leading input # (i.e. the preëdit is empty) we should always pass # IBus.KEY_KP_Enter to the application: return self._return_false(key.val, key.code, key.state) if self._auto_select: self.commit_to_preedit() commit_string = self.get_preedit_string_complete() self.commit_string(commit_string) return self._return_false(key.val, key.code, key.state) commit_string = self.get_preedit_tabkeys_complete() self.commit_string(commit_string) return True if key.val in (IBus.KEY_Tab, IBus.KEY_KP_Tab) and self._auto_select: # Used for example for the Russian transliteration method # “translit”, which uses “auto select”. If for example # a file with the name “шшш” exists and one types in # a bash shell: # # “ls sh” # # the “sh” is converted to “ш” and one sees # # “ls ш” # # in the shell where the “ш” is still in preëdit # because “shh” would be converted to “щ”, i.e. there # is more than one candidate and the input method is still # waiting whether one more “h” will be typed or not. But # if the next character typed is a Tab, the preëdit is # committed here and “False” is returned to pass the Tab # character through to the bash to complete the file name # to “шшш”. self.commit_to_preedit() self.commit_string(self.get_preedit_string_complete()) return self._return_false(key.val, key.code, key.state) if key.val in (IBus.KEY_Down, IBus.KEY_KP_Down): if not self.get_preedit_string_complete(): return self._return_false(key.val, key.code, key.state) res = self.cursor_down() self._update_ui() return res if key.val in (IBus.KEY_Up, IBus.KEY_KP_Up): if not self.get_preedit_string_complete(): return self._return_false(key.val, key.code, key.state) res = self.cursor_up() self._update_ui() return res if (key.val in (IBus.KEY_Left, IBus.KEY_KP_Left) and key.state & IBus.ModifierType.CONTROL_MASK): if not self.get_preedit_string_complete(): return self._return_false(key.val, key.code, key.state) self.control_arrow_left() self._update_ui() return True if (key.val in (IBus.KEY_Right, IBus.KEY_KP_Right) and key.state & IBus.ModifierType.CONTROL_MASK): if not self.get_preedit_string_complete(): return self._return_false(key.val, key.code, key.state) self.control_arrow_right() self._update_ui() return True if key.val in (IBus.KEY_Left, IBus.KEY_KP_Left): if not self.get_preedit_string_complete(): return self._return_false(key.val, key.code, key.state) self.arrow_left() self._update_ui() return True if key.val in (IBus.KEY_Right, IBus.KEY_KP_Right): if not self.get_preedit_string_complete(): return self._return_false(key.val, key.code, key.state) self.arrow_right() self._update_ui() return True if (key.val == IBus.KEY_BackSpace and key.state & IBus.ModifierType.CONTROL_MASK): if not self.get_preedit_string_complete(): return self._return_false(key.val, key.code, key.state) self.remove_preedit_before_cursor() self._update_ui() return True if key.val == IBus.KEY_BackSpace: if not self.get_preedit_string_complete(): return self._return_false(key.val, key.code, key.state) self.remove_char() self._update_ui() return True if (key.val == IBus.KEY_Delete and key.state & IBus.ModifierType.CONTROL_MASK): if not self.get_preedit_string_complete(): return self._return_false(key.val, key.code, key.state) self.remove_preedit_after_cursor() self._update_ui() return True if key.val == IBus.KEY_Delete: if not self.get_preedit_string_complete(): return self._return_false(key.val, key.code, key.state) self.delete() self._update_ui() return True # now we ignore all other hotkeys if (key.state & (IBus.ModifierType.CONTROL_MASK |IBus.ModifierType.MOD1_MASK)): return self._return_false(key.val, key.code, key.state) if key.state & IBus.ModifierType.MOD1_MASK: return self._return_false(key.val, key.code, key.state) # Section to handle valid input characters: if (keychar and (keychar in (self._valid_input_chars + self._single_wildcard_char + self._multi_wildcard_char) or (self._input_mode and self._py_mode and keychar in self._pinyin_valid_input_chars))): if DEBUG_LEVEL > 0: LOGGER.debug( 'valid input: keychar=%s', keychar) # Deactivate suggestion mode: if self._input_mode and self._sg_mode_active: self.clear_all_input_and_preedit() self._sg_mode_active = False if self._input_mode and self._py_mode: if ((len(self._chars_valid) == self._max_key_length_pinyin) or (len(self._chars_valid) > 1 and self._chars_valid[-1] in '!@#$%')): if self._auto_commit: self.commit_everything_unless_invalid() else: self.commit_to_preedit() elif self._input_mode and not self._py_mode: if ((len(self._chars_valid) == self._max_key_length) or (len(self._chars_valid) in self.database.possible_tabkeys_lengths)): if self._auto_commit: self.commit_everything_unless_invalid() else: self.commit_to_preedit() else: assert False res = self.add_input(keychar) if not res: if self._auto_select and self._candidates_previous: # Used for example for the Russian transliteration method # “translit”, which uses “auto select”. # The “translit” table contains: # # sh ш # shh щ # # so typing “sh” matches “ш” and “щ”. The # candidate with the shortest key sequence comes # first in the lookup table, therefore “sh ш” # is shown in the preëdit (The other candidate, # “shh щ” comes second in the lookup table and # could be selected using arrow-down. But # “translit” hides the lookup table by default). # # Now, when after typing “sh” one types “s”, # the key “shs” has no match, so add_input('s') # returns “False” and we end up here. We pop the # last character “s” which caused the match to # fail, commit first of the previous candidates, # i.e. “sh ш” and feed the “s” into the # key event handler again. self.pop_input() self.commit_everything_unless_invalid() return self._table_mode_process_key_event(key) self.commit_everything_unless_invalid() self._update_ui() return True if (self._auto_commit and self.one_candidate() and (self._chars_valid == self._candidates[0][0])): self.commit_everything_unless_invalid() self._update_ui() return True # Section to handle trailing invalid input: # # If the key has still not been handled when this point is # reached, it cannot be a valid input character. Neither can # it be a select key nor a page-up/page-down key. Adding this # key to the tabkeys and search for matching candidates in the # table would thus be pointless. # # So we commit all pending input immediately and then commit # this invalid input character as well, possibly converted to # fullwidth or halfwidth. if keychar: if DEBUG_LEVEL > 0: LOGGER.debug( 'trailing invalid input: keychar=%s', keychar) if not self._candidates or self._commit_invalid_mode == 1: self.commit_string(self.get_preedit_tabkeys_complete()) else: self.commit_to_preedit() self.commit_string(self.get_preedit_string_complete()) if ascii_ispunct(keychar): self.commit_string(self.cond_punct_translate(keychar)) else: self.commit_string(self.cond_letter_translate(keychar)) return True # What kind of key was this?? # # keychar = IBus.keyval_to_unicode(key.val) # # returned no result. So whatever this was, we cannot handle it, # just pass it through to the application by returning “False”. return self._return_false(key.val, key.code, key.state) def do_focus_in(self) -> None: ''' Called for ibus < 1.5.27 when a window gets focus while this input engine is enabled ''' if DEBUG_LEVEL > 1: LOGGER.debug('entering do_focus_in()\n') self.do_focus_in_id('', '') def do_focus_in_id(self, object_path: str, client: str) -> None: '''Called for ibus >= 1.5.27 when a window gets focus while this input engine is enabled :param object_path: Example: '/org/freedesktop/IBus/InputContext_23' :param client: Possible values and examples where these values occur: '': unknown 'fake': focus where input is impossible (e.g. desktop background) 'xim': XIM (Gtk3 programs in a Gnome Xorg session when GTK_IM_MODULE is unset also use xim) 'gtk-im:': Gtk2 input module 'gtk3-im:': Gtk3 input module 'gtk4-im:': Gtk4 input module 'gnome-shell': Entries handled by gnome-shell (like the command line dialog opened with Alt+F2 or the search field when pressing the Super key.) When GTK_IM_MODULE is unset in a Gnome Wayland session all programs which would show 'gtk3-im' or 'gtk4-im' with GTK_IM_MODULE=ibus then show 'gnome-shell' instead. 'Qt': Qt4 input module 'QIBusInputContext': Qt5 input module In case of the Gtk input modules, the name of the client is also shown after the “:”, for example like 'gtk3-im:firefox', 'gtk4-im:gnome-text-editor', … ''' if DEBUG_LEVEL > 1: LOGGER.debug('object_path=%s client=%s\n', object_path, client) self._im_client = client if ':' not in self._im_client: (program_name, _window_title) = it_active_window.get_active_window() if program_name: self._im_client += ':' + program_name if DEBUG_LEVEL > 1: LOGGER.debug('self._im_client=%s\n', self._im_client) self.register_properties(self.main_prop_list) self._update_ui() def do_focus_out(self) -> None: ''' Called for ibus < 1.5.27 when a window loses focus while this input engine is enabled ''' if DEBUG_LEVEL > 1: LOGGER.debug('entering do_focus_out()\n') self.do_focus_out_id('') def do_focus_out_id(self, object_path: str) -> None: ''' Called for ibus >= 1.5.27 when a window loses focus while this input engine is enabled ''' if DEBUG_LEVEL > 1: LOGGER.debug('object_path=%s\n', object_path) self._im_client = '' # Do not do self._input_purpose = 0 here, see # https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5966#note_1576732 # if the input purpose is set correctly on focus in, then it # should not be necessary to reset it here. self.clear_all_input_and_preedit() self._update_ui() def do_reset(self) -> None: '''Called when the mouse pointer is used to move to cursor to a different position in the current window. Also called when certain keys are pressed: Return, KP_Enter, ISO_Enter, Up, Down, (and others?) Even some key sequences like space + Left and space + Right seem to call this. ''' if DEBUG_LEVEL > 1: LOGGER.debug('do_reset()\n') self.reset() def do_set_content_type(self, purpose: int, hints: int) -> None: '''Called when the input purpose or hints change''' LOGGER.debug('purpose=%s hints=%s\n', purpose, format(hints, '016b')) self._input_purpose = purpose self._input_hints = hints if DEBUG_LEVEL > 1: if (self._input_purpose in [int(x) for x in list(it_util.InputPurpose)]): for input_purpose in list(it_util.InputPurpose): if self._input_purpose == input_purpose: LOGGER.debug( 'self._input_purpose = %s (%s)', self._input_purpose, str(input_purpose)) else: LOGGER.debug( 'self._input_purpose = %s (Unknown)', self._input_purpose) for hint in it_util.InputHints: if self._input_hints & hint: LOGGER.debug( 'hint: %s %s', str(hint), format(int(hint), '016b')) def do_enable(self) -> None: '''Called when this input engine is enabled''' if DEBUG_LEVEL > 1: LOGGER.debug('do_enable()\n') # Tell the input-context that the engine will utilize # surrounding-text: self.get_surrounding_text() self.do_focus_in() def do_disable(self) -> None: '''Called when this input engine is disabled''' if DEBUG_LEVEL > 1: LOGGER.debug('do_disable()\n') self.clear_all_input_and_preedit() self._update_ui() def do_page_up(self) -> bool: '''Called when the page up button in the lookup table is clicked with the mouse ''' if self.page_up(): self._update_ui() return True return False def do_page_down(self) -> bool: '''Called when the page down button in the lookup table is clicked with the mouse ''' if self.page_down(): self._update_ui() return True return False def do_cursor_up(self) -> bool: '''Called when the mouse wheel is rolled up in the candidate area of the lookup table ''' res = self.cursor_up() self._update_ui() return res def do_cursor_down(self) -> bool: '''Called when the mouse wheel is rolled down in the candidate area of the lookup table ''' res = self.cursor_down() self._update_ui() return res def on_gsettings_value_changed( self, _settings: Gio.Settings, key: str) -> None: ''' Called when a value in the settings has been changed. ''' value = it_util.variant_to_value(self._gsettings.get_value(key)) LOGGER.debug('Settings changed for engine “%s”: key=%s value=%s', self._engine_name, key, value) set_functions = { 'debuglevel': {'set_function': self.set_debug_level, 'kwargs': {}}, 'dynamicadjust': {'set_function': self.set_dynamic_adjust, 'kwargs': {}}, 'errorsound': {'set_function': self.set_error_sound, 'kwargs': {}}, 'errorsoundfile': {'set_function': self.set_error_sound_file, 'kwargs': {}}, 'soundbackend': {'set_function': self.set_sound_backend, 'kwargs': {}}, 'keybindings': {'set_function': self.set_keybindings, 'kwargs': {}}, 'autoselect': {'set_function': self.set_autoselect_mode, 'kwargs': {}}, 'autocommit': {'set_function': self.set_autocommit_mode, 'kwargs': {}}, 'commitinvalidmode': {'set_function': self.set_commit_invalid_mode, 'kwargs': {}}, 'chinesemode': {'set_function': self.set_chinese_mode, 'kwargs': {}}, 'lookuptableorientation': {'set_function': self.set_lookup_table_orientation, 'kwargs': {}}, 'lookuptablepagesize': {'set_function': self.set_page_size, 'kwargs': {}}, 'onechar': {'set_function': self.set_onechar_mode, 'kwargs': {}}, 'alwaysshowlookup': {'set_function': self.set_always_show_lookup, 'kwargs': {}}, 'singlewildcardchar': {'set_function': self.set_single_wildcard_char, 'kwargs': {}}, 'multiwildcardchar': {'set_function': self.set_multi_wildcard_char, 'kwargs': {}}, 'autowildcard': {'set_function': self.set_autowildcard_mode, 'kwargs': {}}, 'endeffullwidthletter': {'set_function': self.set_letter_width, 'kwargs': dict(input_mode=0)}, 'endeffullwidthpunct': {'set_function': self.set_punctuation_width, 'kwargs': dict(input_mode=0)}, 'tabdeffullwidthletter': {'set_function': self.set_letter_width, 'kwargs': dict(input_mode=1)}, 'tabdeffullwidthpunct': {'set_function': self.set_punctuation_width, 'kwargs': dict(input_mode=1)}, 'inputmode': {'set_function': self.set_input_mode, 'kwargs': {}}, 'rememberinputmode': {'set_function': self.set_remember_input_mode, 'kwargs': {}}, 'darktheme': {'set_function': self.set_dark_theme, 'kwargs': {}}, } if key in set_functions: set_function = set_functions[key]['set_function'] kwargs = set_functions[key]['kwargs'] if key != 'inputmode': kwargs.update(dict(update_gsettings=False)) # type: ignore set_function(value, **kwargs) # type: ignore return LOGGER.debug('Unknown key') return if __name__ == "__main__": LOG_HANDLER = logging.StreamHandler(stream=sys.stderr) LOGGER.setLevel(logging.DEBUG) LOGGER.addHandler(LOG_HANDLER) import doctest (FAILED, ATTEMPTED) = doctest.testmod() sys.exit(FAILED) ibus-table-1.17.11/engine/table.xml.in.in000066400000000000000000000011421475513533100200060ustar00rootroot00000000000000 org.freedesktop.IBus.Table Table Component ${libexecdir}/ibus-engine-table --ibus @VERSION@ Yuwei Yu <acevery@gmail.com> LGPL https://github.com/mike-fabian/ibus-table ibus-table ${pkgdatadir}/tables/ ibus-table-1.17.11/engine/tabsqlitedb.py000066400000000000000000002057101475513533100200420ustar00rootroot00000000000000# vim:et sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # Copyright (c) 2009-2014 Caius "kaio" CHANCE # Copyright (c) 2012-2022 Mike FABIAN # Copyright (c) 2019 Peng Wu # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see ''' Module for ibus-table to access the sqlite3 databases ''' from typing import List from typing import Tuple from typing import Iterable from typing import Dict from typing import Union from typing import Optional from typing import Callable import os import os.path as path import shutil import sqlite3 import uuid import time import re import logging import json import chinese_variants import ibus_table_location LOGGER = logging.getLogger('ibus-table') DEBUG_LEVEL = int(0) DATABASE_VERSION = '1.00' CHINESE_NOCHECK_CHARS = "“”‘’《》〈〉〔〕「」『』【】〖〗()[]{}"\ ".。,、;:?!…—·ˉˇ¨々~‖∶"'`|"\ "⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛"\ "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯЁ"\ "ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ"\ "⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛"\ "㎎㎏㎜㎝㎞㎡㏄㏎㏑㏒㏕"\ "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ"\ "⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇"\ "€$¢£¥"\ "¤→↑←↓↖↗↘↙"\ "ァアィイゥウェエォオカガキギクグケゲコゴサザシジ"\ "スズセゼソゾタダチヂッツヅテデトドナニヌネノハバパ"\ "ヒビピフブプヘベペホボポマミムメモャヤュユョヨラ"\ "リルレロヮワヰヱヲンヴヵヶーヽヾ"\ "ぁあぃいぅうぇえぉおかがきぎぱくぐけげこごさざしじ"\ "すずせぜそぞただちぢっつづてでとどなにぬねのはば"\ "ひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらり"\ "るれろゎわゐゑをん゛゜ゝゞ"\ "勹灬冫艹屮辶刂匚阝廾丨虍彐卩钅冂冖宀疒肀丿攵凵犭"\ "亻彡饣礻扌氵纟亠囗忄讠衤廴尢夂丶"\ "āáǎàōóǒòêēéěèīíǐìǖǘǚǜüūúǔù"\ "+-<=>±×÷∈∏∑∕√∝∞∟∠∣∥∧∨∩∪∫∮"\ "∴∵∶∷∽≈≌≒≠≡≤≥≦≧≮≯⊕⊙⊥⊿℃°‰"\ "♂♀§№☆★○●◎◇◆□■△▲※〓#&@\^_ ̄"\ "абвгдежзийклмнопрстуфхцчшщъыьэюяё"\ "ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹβγδεζηαικλμνξοπρστυφθψω"\ "①②③④⑤⑥⑦⑧⑨⑩①②③④⑤⑥⑦⑧⑨⑩"\ "㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩"\ "ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄧㄨㄩ"\ "ㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦ" class ImeProperties: ''' A class to cache the properties of an input method. ''' def __init__( self, db: Optional[sqlite3.dbapi2.Connection] = None, default_properties: Optional[Dict[str, str]] = None) -> None: ''' “db” is the handle of the sqlite3 database file obtained by sqlite3.connect(). ''' if default_properties is None: default_properties = {} if not db: return self.ime_property_cache = default_properties sqlstr = 'SELECT attr, val FROM main.ime;' try: results = db.execute(sqlstr).fetchall() except: LOGGER.exception('Cannot get ime properties from database') for result in results: self.ime_property_cache[result[0]] = result[1] def get(self, key: str) -> str: ''' Return the value for a key from the property cache :param key: The key to lookup in the property cache ''' if key in self.ime_property_cache: return self.ime_property_cache[key] return '' def __str__(self) -> str: return 'ime_property_cache = %s' %repr(self.ime_property_cache) class TabSqliteDb: '''Phrase database for tables The phrases table in the database has columns with the names: “id”, “tabkeys”, “phrase”, “freq”, “user_freq” There are 2 databases, sysdb, userdb. sysdb: System database for the input method, for example something like /usr/share/ibus-table/tables/wubi-jidian86.db “user_freq” is always 0 in a system database. “freq” is some number in a system database indicating a frequency of use of that phrase relative to the other phrases in that database. user_db: Database on disk where the phrases used or defined by the user are stored. “user_freq” is a counter which counts how many times that combination of “tabkeys” and “phrase” has been used. “freq” is equal to 0 for all combinations of “tabkeys” and “phrase” where an entry for that phrase is already in the system database which starts with the same “tabkeys”. For combinations of “tabkeys” and “phrase” which do not exist at all in the system database, “freq” is equal to -1 to indidated that this is a user defined phrase. ''' def __init__( self, filename: str = '', user_db: str = '', create_database: bool = False, unit_test: bool = False) -> None: global DEBUG_LEVEL try: DEBUG_LEVEL = int(str(os.getenv('IBUS_TABLE_DEBUG_LEVEL'))) except (TypeError, ValueError): DEBUG_LEVEL = int(0) self.old_phrases: List[Tuple[str, str, int, int]] = [] self.filename = filename self._user_db = user_db self.reset_phrases_cache() if create_database or os.path.isfile(self.filename): self.db: sqlite3.dbapi2.Connection = sqlite3.connect(self.filename) else: print('Cannot open database file %s' %self.filename) try: self.db.execute('PRAGMA encoding = "UTF-8";') self.db.execute('PRAGMA case_sensitive_like = true;') self.db.execute('PRAGMA page_size = 4096;') # 20000 pages should be enough to cache the whole database self.db.execute('PRAGMA cache_size = 20000;') self.db.execute('PRAGMA temp_store = MEMORY;') self.db.execute('PRAGMA journal_size_limit = 1000000;') self.db.execute('PRAGMA synchronous = NORMAL;') except: LOGGER.exception('Error while initializing database') # create IME property table self.db.executescript( 'CREATE TABLE IF NOT EXISTS main.ime (attr TEXT, val TEXT);') # Initalize missing attributes in the ime table with some # default values, they should be updated using the attributes # found in the source when creating a system database with # tabcreatedb.py self._default_ime_attributes = { 'name':'', 'name.zh_cn':'', 'name.zh_hk':'', 'name.zh_tw':'', 'author':'somebody', 'uuid':'%s' % uuid.uuid4(), 'serial_number':'%s' % time.strftime('%Y%m%d'), 'icon':'ibus-table.svg', 'license':'LGPL', 'languages':'', 'language_filter':'', 'valid_input_chars':'abcdefghijklmnopqrstuvwxyz', 'max_key_length':'4', 'commit_keys':'space', # 'forward_keys':'Return', 'select_keys':'1,2,3,4,5,6,7,8,9,0', 'page_up_keys':'Page_Up,KP_Page_Up,KP_Prior,minus', 'page_down_keys':'Page_Down,KP_Page_Down,KP_Next,equal', 'status_prompt':'', 'def_full_width_punct':'true', 'def_full_width_letter':'false', 'user_can_define_phrase':'false', 'pinyin_mode':'false', 'suggestion_mode':'false', 'dynamic_adjust':'false', 'auto_select':'false', 'auto_commit':'false', 'auto_wildcard': 'true', # 'no_check_chars': '', 'description':'A IME under IBus Table', 'layout':'us', 'symbol':'', 'rules':'', 'least_commit_length':'0', 'start_chars':'', 'orientation':'true', 'always_show_lookup':'true', 'char_prompts':'{}', # we use this entry for those IME, which don't # have rules to build up phrase, but still need # auto commit to preedit } if create_database: select_sqlstr = ''' SELECT val FROM main.ime WHERE attr = :attr;''' insert_sqlstr = ''' INSERT INTO main.ime (attr, val) VALUES (:attr, :val);''' for attr in sorted(self._default_ime_attributes): sqlargs = { 'attr': attr, 'val': self._default_ime_attributes[attr] } if not self.db.execute(select_sqlstr, sqlargs).fetchall(): self.db.execute(insert_sqlstr, sqlargs) self.ime_properties = ImeProperties( db=self.db, default_properties=self._default_ime_attributes) # shared variables in this class: self._mlen = int(self.ime_properties.get("max_key_length")) self._snum = self.ime_properties.get("serial_number") self._is_chinese = self.is_chinese() self._is_cjk = self.is_cjk() self.user_can_define_phrase = (self.ime_properties.get( 'user_can_define_phrase').lower() == 'true') self.rules = self.get_rules() self.possible_tabkeys_lengths = self.get_possible_tabkeys_lengths() self.startchars = self.get_start_chars() tables_path = path.join(ibus_table_location.data_home(), 'tables') cache_name = os.path.basename(self.filename).replace('.db', '.cache') self.cache_path = path.join(tables_path, cache_name) if not unit_test: self.load_phrases_cache() if not user_db or create_database: # No user database requested or we are # just creating the system database and # we do not need a user database for that return if user_db != ":memory:": # Do not move this import to the beginning of this script! # If for example the home directory is not writeable, # ibus_table_location.py would fail because it cannot # create some directories. # # But for tabcreatedb.py, no such directories are needed, # tabcreatedb.py should not fail just because # ibus_table_location.py cannot create some directories. # # “HOME=/foobar ibus-table-createdb” should not fail if # “/foobar” is not writeable. if not path.isdir(tables_path): old_tables_path = os.path.expanduser('~/.ibus/tables') if path.isdir(old_tables_path): if os.access(os.path.join( old_tables_path, 'debug.log'), os.F_OK): os.unlink(os.path.join(old_tables_path, 'debug.log')) if os.access(os.path.join( old_tables_path, 'setup-debug.log'), os.F_OK): os.unlink(os.path.join( old_tables_path, 'setup-debug.log')) shutil.copytree(old_tables_path, tables_path) shutil.rmtree(old_tables_path) os.symlink(tables_path, old_tables_path) else: os.makedirs(tables_path, exist_ok=True) user_db = path.join(tables_path, user_db) if not path.exists(user_db): LOGGER.debug( 'The user database %s does not exist yet.', user_db) else: try: desc = self.get_database_desc(user_db) phrase_table_column_names = [ 'id', 'tabkeys', 'phrase', 'freq', 'user_freq'] if (desc is None or desc["version"] != DATABASE_VERSION or (self.get_number_of_columns_of_phrase_table( user_db) != len(phrase_table_column_names))): LOGGER.debug( 'The user database %s seems to be incompatible.', user_db) if desc is None: LOGGER.debug( 'There is no version information in ' 'the database.') self.old_phrases = self.extract_user_phrases( user_db, old_database_version='0.0') elif desc["version"] != DATABASE_VERSION: LOGGER.debug( 'The version of the database does not match ' '(too old or too new?). ' 'ibus-table wants version=%s ' 'But the database actually has version=%s', DATABASE_VERSION, desc['version']) self.old_phrases = self.extract_user_phrases( user_db, old_database_version=desc['version']) elif (self.get_number_of_columns_of_phrase_table( user_db) != len(phrase_table_column_names)): LOGGER.debug( 'The number of columns of the database ' 'does not match. ' 'ibus-table expects %s columns. ' 'But the database actually has %s columns. ' 'But the versions of the databases are ' 'identical. ' 'This should never happen!', len(phrase_table_column_names), self.get_number_of_columns_of_phrase_table( user_db)) self.old_phrases = [] timestamp = time.strftime('-%Y-%m-%d_%H:%M:%S') LOGGER.debug( 'Renaming the incompatible database to "%s".', user_db+timestamp) if os.path.exists(user_db): os.rename(user_db, user_db+timestamp) if os.path.exists(user_db+'-shm'): os.rename(user_db+'-shm', user_db+'-shm'+timestamp) if os.path.exists(user_db+'-wal'): os.rename(user_db+'-wal', user_db+'-wal'+timestamp) LOGGER.debug( 'Creating a new, empty database "%s".', user_db) self.init_user_db(user_db) LOGGER.debug( 'If user phrases were successfully recovered from ' 'the old, ' 'incompatible database, they will be used to ' 'initialize the new database.') else: LOGGER.debug( 'Compatible database %s found.', user_db) except: LOGGER.exception( 'Unexpected error trying to find user database') # open user phrase database try: LOGGER.debug( 'Connect to the database %s.', user_db) self.db.executescript(''' ATTACH DATABASE "%s" AS user_db; PRAGMA user_db.encoding = "UTF-8"; PRAGMA user_db.case_sensitive_like = true; PRAGMA user_db.page_size = 4096; PRAGMA user_db.cache_size = 20000; PRAGMA user_db.temp_store = MEMORY; PRAGMA user_db.journal_mode = WAL; PRAGMA user_db.journal_size_limit = 1000000; PRAGMA user_db.synchronous = NORMAL; ''' % user_db) except: LOGGER.debug('Could not open the database %s.', user_db) timestamp = time.strftime('-%Y-%m-%d_%H:%M:%S') LOGGER.debug('Renaming the incompatible database to "%s".', user_db+timestamp) if os.path.exists(user_db): os.rename(user_db, user_db+timestamp) if os.path.exists(user_db+'-shm'): os.rename(user_db+'-shm', user_db+'-shm'+timestamp) if os.path.exists(user_db+'-wal'): os.rename(user_db+'-wal', user_db+'-wal'+timestamp) LOGGER.debug('Creating a new, empty database "%s".', user_db) self.init_user_db(user_db) self.db.executescript(''' ATTACH DATABASE "%s" AS user_db; PRAGMA user_db.encoding = "UTF-8"; PRAGMA user_db.case_sensitive_like = true; PRAGMA user_db.page_size = 4096; PRAGMA user_db.cache_size = 20000; PRAGMA user_db.temp_store = MEMORY; PRAGMA user_db.journal_mode = WAL; PRAGMA user_db.journal_size_limit = 1000000; PRAGMA user_db.synchronous = NORMAL; ''' % user_db) self.create_tables("user_db") if self.old_phrases: sqlargs_old_phrases: List[Dict[str, Union[str, int]]] = [] for phrase in self.old_phrases: sqlargs_old_phrases.append( {'tabkeys': phrase[0], 'phrase': phrase[1], 'freq': phrase[2], 'user_freq': phrase[3]}) sqlstr = ''' INSERT INTO user_db.phrases (tabkeys, phrase, freq, user_freq) VALUES (:tabkeys, :phrase, :freq, :user_freq) ''' try: self.db.executemany(sqlstr, sqlargs_old_phrases) except: LOGGER.exception('Error inserting old phrases') self.db.commit() self.db.execute('PRAGMA wal_checkpoint;') # try create all tables in user database self.create_indexes("user_db") self.generate_userdb_desc() def update_phrase( self, tabkeys: str = '', phrase: str = '', user_freq: int = 0, database: str = 'user_db', commit: bool = True) -> None: '''update phrase freqs''' if DEBUG_LEVEL > 1: LOGGER.debug( 'tabkeys=%s phrase=%s user_freq=%s database=%s', tabkeys, phrase, user_freq, database) if not tabkeys or not phrase: return sqlstr = ''' UPDATE %s.phrases SET user_freq = :user_freq WHERE tabkeys = :tabkeys AND phrase = :phrase ;''' % database sqlargs = {'user_freq': user_freq, 'tabkeys': tabkeys, 'phrase': phrase} try: self.db.execute(sqlstr, sqlargs) if commit: self.db.commit() self.invalidate_phrases_cache(tabkeys) except: LOGGER.exception('Unexpected error updating phrase in user_db.') def sync_usrdb(self) -> None: ''' Trigger a checkpoint operation. ''' self.save_phrases_cache() if self._user_db is None: return self.db.commit() self.db.execute('PRAGMA wal_checkpoint;') def reset_phrases_cache(self) -> None: ''' Make the phrases cache empty ''' if DEBUG_LEVEL > 1: LOGGER.debug('reset_phrases_cache()') self._phrases_cache: Dict[str, Union[str, Iterable[Tuple[str, str, int, int]]]]= {} def invalidate_phrases_cache(self, tabkeys: str = '') -> None: ''' Delete all phrases starting with “tabkeys” from the phrases cache. :param tabkeys: The keys typed ''' if DEBUG_LEVEL > 1: LOGGER.debug('invalidate_phrases_cache()') for i in range(1, self._mlen + 1): if self._phrases_cache.get(tabkeys[0:i]): self._phrases_cache.pop(tabkeys[0:i]) def load_phrases_cache(self) -> None: ''' Load phrases cache from disk ''' if DEBUG_LEVEL > 1: LOGGER.debug('load_phrases_cache()') try: self._phrases_cache = json.load(open(self.cache_path)) snum = self._phrases_cache.get('serial_number') if not snum or (snum != self._snum): self._phrases_cache = {} except FileNotFoundError: if DEBUG_LEVEL > 1: LOGGER.debug( 'File %s not found', self.cache_path) except PermissionError: if DEBUG_LEVEL > 1: LOGGER.debug( 'Permission error reading %s', self.cache_path) except: LOGGER.debug('Unknown error reading %s', self.cache_path) def save_phrases_cache(self) -> None: ''' Save phrases cache from disk ''' if DEBUG_LEVEL > 1: LOGGER.debug('save_phrases_cache()') try: self._phrases_cache['serial_number'] = self._snum _cache_path = self.cache_path + '.tmp' # The system may be break stores on rebooting, so # dump to temporary file and then replace it. json.dump(self._phrases_cache, open(_cache_path, 'w')) os.replace(_cache_path, self.cache_path) except: LOGGER.exception('Unexpected error in save_phrases_cache().') def is_chinese(self) -> bool: ''' Check whether this input method is classified as Chinese in the the database. ''' languages = self.ime_properties.get('languages') if languages: langs = languages.split(',') for lang in langs: if lang.lower().find('zh') != -1: return True return False def is_cjk(self) -> bool: ''' Check whether this input method is classified as Chinese, Japanese, or Korean in the database. ''' languages_str = self.ime_properties.get('languages') if languages_str: languages = languages_str.split(',') for language in languages: for lang in ['zh', 'ja', 'ko']: if language.strip().startswith(lang): return True return False def get_chinese_mode(self) -> int: ''' Get the default Chinese mode from the database 0 means to show simplified Chinese only 1 means to show traditional Chinese only 2 means to show all characters but show simplified Chinese first 3 means to show all characters but show traditional Chinese first 4 means to show all characters If no mode is specified in the database, return 4 to avoid all filtering of characters. ''' language_filter = self.ime_properties.get('language_filter') if language_filter in ('cm0', 'cm1', 'cm2', 'cm3', 'cm4'): return int(language_filter[-1]) return 4 def get_select_keys(self) -> str: ''' Get the keys used to select a candidate from the database ''' ret = self.ime_properties.get("select_keys") if ret: return ret return "1,2,3,4,5,6,7,8,9,0" def get_orientation(self) -> int: '''Get the default orientation of the lookup table from the database''' try: return int(self.ime_properties.get('orientation')) except (TypeError, ValueError): return 1 def create_tables(self, database: str) -> None: '''Create tables that contain all phrase''' if database == 'main': sqlstr = ''' CREATE TABLE IF NOT EXISTS %s.goucima (zi TEXT PRIMARY KEY, goucima TEXT); ''' % database self.db.execute(sqlstr) sqlstr = ''' CREATE TABLE IF NOT EXISTS %s.pinyin (pinyin TEXT, zi TEXT, freq INTEGER); ''' % database self.db.execute(sqlstr) sqlstr = ''' CREATE TABLE IF NOT EXISTS %s.suggestion (phrase TEXT, freq INTEGER); ''' %database self.db.execute(sqlstr) sqlstr = ''' CREATE TABLE IF NOT EXISTS %s.phrases (id INTEGER PRIMARY KEY, tabkeys TEXT, phrase TEXT, freq INTEGER, user_freq INTEGER); ''' % database self.db.execute(sqlstr) self.db.commit() def update_ime(self, attrs: Iterable[Tuple[str, str]]) -> None: '''Update or insert attributes in ime table, attrs is a iterable object Like [(attr,val), (attr,val), ...] This is called only by tabcreatedb.py. ''' select_sqlstr = 'SELECT val from main.ime WHERE attr = :attr' update_sqlstr = 'UPDATE main.ime SET val = :val WHERE attr = :attr;' insert_sqlstr = ( 'INSERT INTO main.ime (attr, val) VALUES (:attr, :val);') for attr, val in attrs: sqlargs = {'attr': attr, 'val': val} if self.db.execute(select_sqlstr, sqlargs).fetchall(): self.db.execute(update_sqlstr, sqlargs) else: self.db.execute(insert_sqlstr, sqlargs) self.db.commit() # update ime properties cache: self.ime_properties = ImeProperties( db=self.db, default_properties=self._default_ime_attributes) # The self variables used by tabcreatedb.py need to be updated now: self._mlen = int(self.ime_properties.get('max_key_length')) self._is_chinese = self.is_chinese() self.user_can_define_phrase = (self.ime_properties.get( 'user_can_define_phrase').lower() == 'true') self.rules = self.get_rules() def get_rules(self) -> Dict[Union[str, int], Union[int, List[Tuple[int, int]]]]: '''Get phrase construct rules Example: The wubi-jidian86.txt table source contains: RULES = ce2:p11+p12+p21+p22;ce3:p11+p21+p31+p32;ca4:p11+p21+p31+p-11 and the return value of this function becomes: {2: [(1, 1), (1, 2), (2, 1), (2, 2)], 3: [(1, 1), (2, 1), (3, 1), (3, 2)], 'above': 4, 4: [(1, 1), (2, 1), (3, 1), (-1, 1)]} ''' rules: Dict[Union[str, int], Union[int, List[Tuple[int, int]]]] = {} patt_r = re.compile(r'c([ea])(\d):(.*)') patt_p = re.compile(r'p(-{0,1}\d)(-{0,1}\d)') if not self.user_can_define_phrase: return {} try: _rules_str = self.ime_properties.get('rules') _rules: List[str] = [] if _rules_str: _rules = _rules_str.strip().split(';') for rule in _rules: res = patt_r.match(rule) if res: cms = [] if res.group(1) == 'a': rules['above'] = int(res.group(2)) _cms = res.group(3).split('+') if len(_cms) > self._mlen: print('rule: "%s" over max key length' %rule) break for _cm in _cms: cm_res = patt_p.match(_cm) if cm_res: cms.append((int(cm_res.group(1)), int(cm_res.group(2)))) rules[int(res.group(2))] = cms else: print('not a legal rule: "%s"' %rule) except Exception: LOGGER.exception('Unexpected error in get_rules().') return rules def get_possible_tabkeys_lengths(self) -> List[int]: '''Return a list of the possible lengths for tabkeys in this table. Example: If the table source has rules like: RULES = ce2:p11+p12+p21+p22;ce3:p11+p21+p22+p31;ca4:p11+p21+p31+p41 self._rules will be set to self._rules = { 2: [(1, 1), (1, 2), (2, 1), (2, 2)], 3: [(1, 1), (1, 2), (2, 1), (3, 1)], 4: [(1, 1), (2, 1), (3, 1), (-1, 1)], 'above': 4} and then this function returns “[4, 4, 4]” Or, if the table source has no RULES but LEAST_COMMIT_LENGTH=2 and MAX_KEY_LENGTH = 4, then it returns “[2, 3, 4]” I cannot find any tables which use LEAST_COMMIT_LENGTH though. ''' if self.rules: max_len = self.rules["above"] return [len(self.rules[x]) for x in range(2, max_len+1)][:] # type: ignore try: least_commit_len = int( self.ime_properties.get('least_commit_length')) except (TypeError, ValueError): least_commit_len = 0 if least_commit_len > 0: return list(range(least_commit_len, self._mlen + 1)) return [] def get_start_chars(self) -> str: '''return possible start chars of IME''' return self.ime_properties.get('start_chars') def get_no_check_chars(self) -> str: '''Get the characters which engine should not change freq''' _chars = self.ime_properties.get('no_check_chars') return _chars def add_phrases( self, phrases: Iterable[Tuple[str, str, int, int]], database: str = 'main') -> None: '''Add many phrases to database fast. Used by tabcreatedb.py when creating the system database from scratch. “phrases” is a iterable object which looks like: [(tabkeys, phrase, freq ,user_freq), (tabkeys, phrase, freq, user_freq), ...] This function does not check whether phrases are already there. As this function is only used while creating the system database, it is not really necessary to check whether phrases are already there because the database is initially empty anyway. And the caller should take care that the “phrases” argument does not contain duplicates. ''' if DEBUG_LEVEL > 1: LOGGER.debug('len(phrases)=%s', len(list(phrases))) insert_sqlstr = ''' INSERT INTO {database}.phrases (tabkeys, phrase, freq, user_freq) VALUES (:tabkeys, :phrase, :freq, :user_freq); '''.format(database=database) insert_sqlargs = [] for (tabkeys, phrase, freq, user_freq) in phrases: insert_sqlargs.append({ 'tabkeys': tabkeys, 'phrase': phrase, 'freq': freq, 'user_freq': user_freq}) self.invalidate_phrases_cache(tabkeys) self.db.executemany(insert_sqlstr, insert_sqlargs) self.db.commit() self.db.execute('PRAGMA wal_checkpoint;') def add_phrase( self, tabkeys: str = '', phrase: str = '', freq: int = 0, user_freq: int = 0, database: str = 'main', commit: bool = True) -> None: '''Add phrase to database, phrase is a object of (tabkeys, phrase, freq ,user_freq) ''' if DEBUG_LEVEL > 1: LOGGER.debug( 'add_phrase tabkeys=%s phrase=%s ' 'freq=%s user_freq=%s', tabkeys, phrase, freq, user_freq) if not tabkeys or not phrase: return select_sqlstr = ''' SELECT * FROM {database}.phrases WHERE tabkeys = :tabkeys AND phrase = :phrase; '''.format(database=database) select_sqlargs = {'tabkeys': tabkeys, 'phrase': phrase} results = self.db.execute(select_sqlstr, select_sqlargs).fetchall() if results: # there is already such a phrase, i.e. add_phrase was called # in error, do nothing to avoid duplicate entries. if DEBUG_LEVEL > 1: LOGGER.debug( 'select_sqlstr=%(sql)s select_sqlargs=%(arg)s ' 'already there!: results=%(r)s ', select_sqlstr, select_sqlargs, results) return insert_sqlstr = ''' INSERT INTO {database}.phrases (tabkeys, phrase, freq, user_freq) VALUES (:tabkeys, :phrase, :freq, :user_freq); '''.format(database=database) insert_sqlargs = { 'tabkeys': tabkeys, 'phrase': phrase, 'freq': freq, 'user_freq': user_freq} if DEBUG_LEVEL > 1: LOGGER.debug( 'insert_sqlstr=%s insert_sqlargs=%s', insert_sqlstr, insert_sqlargs) try: self.db.execute(insert_sqlstr, insert_sqlargs) if commit: self.db.commit() self.invalidate_phrases_cache(tabkeys) except: LOGGER.exception('Unexpected error in add_phrase()') def add_goucima(self, goucimas: Iterable[Tuple[str, str]]) -> None: '''Add goucima into database, goucimas is iterable object Like goucimas = [(zi,goucima), (zi,goucima), ...] ''' sqlstr = ''' INSERT INTO main.goucima (zi, goucima) VALUES (:zi, :goucima); ''' sqlargs = [] for zi, goucima in goucimas: sqlargs.append({'zi': zi, 'goucima': goucima}) try: self.db.commit() self.db.executemany(sqlstr, sqlargs) self.db.commit() self.db.execute('PRAGMA wal_checkpoint;') except: LOGGER.exception('Unexpected error in add_goucima().') def add_pinyin( self, pinyins: Iterable[Tuple[str, str, int]], database: str = 'main') -> None: '''Add pinyin to database, pinyins is a iterable object Like: [(zi,pinyin, freq), (zi, pinyin, freq), ...] ''' sqlstr = ''' INSERT INTO %s.pinyin (pinyin, zi, freq) VALUES (:pinyin, :zi, :freq); ''' % database count = 0 for pinyin, zi, freq in pinyins: count += 1 pinyin = pinyin.replace( '1', '!').replace( '2', '@').replace( '3', '#').replace( '4', '$').replace( '5', '%') try: self.db.execute( sqlstr, {'pinyin': pinyin, 'zi': zi, 'freq': freq}) except Exception: LOGGER.exception( 'Error when inserting into pinyin table. ' 'count=%s pinyin=%s zi=%s freq=%s', count, pinyin, zi, freq) self.db.commit() def add_suggestion( self, suggestions: Iterable[Tuple[str, int]], database: str = 'main') -> None: '''Add suggestion phrase to database, suggestions is a iterable object Like: [(phrase, freq), (phrase, freq), ...] ''' sqlstr = ''' INSERT INTO %s.suggestion (phrase, freq) VALUES (:phrase, :freq); ''' % database count = 0 for phrase, freq in suggestions: count += 1 try: self.db.execute( sqlstr, {'phrase': phrase, 'freq': freq}) except Exception: LOGGER.exception( 'Error when inserting into suggestion table. ' 'count=%s phrase=%s freq=%s', count, phrase, freq) self.db.commit() def optimize_database(self) -> None: ''' Optimize the database by copying the contents to temporary tables and back. ''' sqlstr = ''' CREATE TABLE tmp AS SELECT * FROM main.phrases; DELETE FROM main.phrases; INSERT INTO main.phrases SELECT * FROM tmp ORDER BY tabkeys ASC, phrase ASC, user_freq DESC, freq DESC, id ASC; DROP TABLE tmp; CREATE TABLE tmp AS SELECT * FROM main.goucima; DELETE FROM main.goucima; INSERT INTO main.goucima SELECT * FROM tmp ORDER BY zi, goucima; DROP TABLE tmp; CREATE TABLE tmp AS SELECT * FROM main.pinyin; DELETE FROM main.pinyin; INSERT INTO main.pinyin SELECT * FROM tmp ORDER BY pinyin ASC, freq DESC; DROP TABLE tmp; CREATE TABLE tmp as SELECT * FROM main.suggestion; DELETE FROM main.suggestion; INSERT INTO main.suggestion SELECT * FROM tmp ORDER by phrase ASC, freq DESC; DROP TABLE tmp; ''' self.db.executescript(sqlstr) self.db.executescript("VACUUM;") self.db.commit() def drop_indexes(self, _database: str) -> None: '''Drop the indexes in the database to reduce its size We do not use any indexes at the moment, therefore this function does nothing. ''' if DEBUG_LEVEL > 1: LOGGER.debug('drop_indexes()') def create_indexes(self, _database: str, _commit: bool = True) -> None: '''Create indexes for the database. We do not use any indexes at the moment, therefore this function does nothing. We used indexes before, but benchmarking showed that none of them was really speeding anything up, therefore we deleted all of them to get much smaller databases (about half the size). If some index turns out to be very useful in future, it could be created here (and dropped in “drop_indexes()”). ''' if DEBUG_LEVEL > 1: LOGGER.debug('create_indexes()') def big5_code(self, phrase: str) -> bytes: ''' Encode a string in Big5 or, if that is not possible, return something higher than any Big5 code. :param phrase: String to be encoded in Big5 encoding ''' try: big5 = phrase.encode('Big5') except UnicodeEncodeError: big5 = b'\xff\xff' # higher than any Big5 code return big5 def best_candidates( self, typed_tabkeys: str = '', candidates: Iterable[Tuple[str, str, int, int]] = (), chinese_mode: int = 4) -> Iterable[Tuple[str, str, int, int]]: ''' “candidates” is an array containing something like: [(tabkeys, phrase, freq, user_freq), ...] “typed_tabkeys” is key sequence the user really typed, which maybe only the beginning part of the “tabkeys” in a matched candidate. ''' maximum_number_of_candidates = 100 engine_name = os.path.basename(self.filename).replace('.db', '') code_point_function: Callable[[str], bytes] = lambda x: (b'\xff\xff') if engine_name in [ 'cangjie3', 'cangjie5', 'cangjie-big', 'quick-classic', 'quick3', 'quick5']: code_point_function = self.big5_code if self._is_chinese: pinyin_exact_match_function: Callable[[str], int] = lambda x: ( - int(typed_tabkeys == x[:-1] and x[-1] in '!@#$%') ) else: pinyin_exact_match_function = lambda x: (1) if chinese_mode in (2, 3) and self._is_chinese: if chinese_mode == 2: bitmask = (1 << 0) # used in simplified Chinese else: bitmask = (1 << 1) # used in traditional Chinese return sorted(candidates, key=lambda x: ( - int( typed_tabkeys == x[0] ), # exact matches first! pinyin_exact_match_function(x[0]), -1*x[3], # user_freq descending # Prefer characters used in the # desired Chinese variant: -(bitmask & chinese_variants.detect_chinese_category( x[1])), -1*x[2], # freq descending len(x[0]), # len(tabkeys) ascending x[0], # tabkeys alphabetical code_point_function(x[1][0]), # Unicode codepoint of first character of phrase: ord(x[1][0]) ))[:maximum_number_of_candidates] return sorted(candidates, key=lambda x: ( - int( typed_tabkeys == x[0] ), # exact matches first! pinyin_exact_match_function(x[0]), -1*x[3], # user_freq descending -1*x[2], # freq descending len(x[0]), # len(tabkeys) ascending x[0], # tabkeys alphabetical code_point_function(x[1][0]), # Unicode codepoint of first character of phrase: ord(x[1][0]) ))[:maximum_number_of_candidates] def select_words( self, tabkeys: str = '', onechar: bool = False, chinese_mode: int = 4, single_wildcard_char: str = '', multi_wildcard_char: str = '', auto_wildcard: bool = False, dynamic_adjust: bool = False) -> Iterable[Tuple[str, str, int, int]]: ''' Get matching phrases for tabkeys from the database. ''' if not tabkeys: return [] # query phrases cache first best = self._phrases_cache.get(tabkeys) if best: return best # type: ignore one_char_condition = '' if onechar: # for some users really like to select only single characters one_char_condition = ' AND length(phrase)=1 ' if self.user_can_define_phrase or dynamic_adjust: sqlstr = ''' SELECT tabkeys, phrase, freq, user_freq FROM ( SELECT tabkeys, phrase, freq, user_freq FROM main.phrases WHERE tabkeys LIKE :tabkeys ESCAPE :escapechar {one_char_condition} UNION ALL SELECT tabkeys, phrase, freq, user_freq FROM user_db.phrases WHERE tabkeys LIKE :tabkeys ESCAPE :escapechar {one_char_condition} ) '''.format(one_char_condition=one_char_condition) else: sqlstr = ''' SELECT tabkeys, phrase, freq, user_freq FROM main.phrases WHERE tabkeys LIKE :tabkeys ESCAPE :escapechar {one_char_condition} '''.format(one_char_condition=one_char_condition) escapechar = '☺' for char in '!@#': if char not in [single_wildcard_char, multi_wildcard_char]: escapechar = char tabkeys_for_like = tabkeys tabkeys_for_like = tabkeys_for_like.replace( escapechar, escapechar+escapechar) if '%' not in [single_wildcard_char, multi_wildcard_char]: tabkeys_for_like = tabkeys_for_like.replace('%', escapechar+'%') if '_' not in [single_wildcard_char, multi_wildcard_char]: tabkeys_for_like = tabkeys_for_like.replace('_', escapechar+'_') if single_wildcard_char: tabkeys_for_like = tabkeys_for_like.replace( single_wildcard_char, '_') if multi_wildcard_char: tabkeys_for_like = tabkeys_for_like.replace( multi_wildcard_char, '%%') if auto_wildcard: tabkeys_for_like += '%%' sqlargs = {'tabkeys': tabkeys_for_like, 'escapechar': escapechar} if DEBUG_LEVEL > 1: LOGGER.debug('sqlstr=%s sqlargs=%s', sqlstr, repr(sqlargs)) unfiltered_results = self.db.execute(sqlstr, sqlargs).fetchall() bitmask = None if chinese_mode == 0: bitmask = (1 << 0) # simplified only elif chinese_mode == 1: bitmask = (1 << 1) # traditional only if not bitmask: results = unfiltered_results else: results = [] for result in unfiltered_results: if (bitmask & chinese_variants.detect_chinese_category(result[1])): results.append(result) # merge matches from the system database and from the user # database to avoid duplicates in the candidate list for # example, if we have the result ('aaaa', '工', 551000000, 0) # from the system database and ('aaaa', '工', 0, 5) from the # user database, these should be merged into one match # ('aaaa', '工', 551000000, 5). phrase_frequencies = {} for result in results: key = (result[0], result[1]) if key not in phrase_frequencies: phrase_frequencies[key] = result else: phrase_frequencies.update([( key, key + ( max(result[2], phrase_frequencies[key][2]), max(result[3], phrase_frequencies[key][3])) )]) best = self.best_candidates( typed_tabkeys=tabkeys, candidates=phrase_frequencies.values(), chinese_mode=chinese_mode) if DEBUG_LEVEL > 1: LOGGER.debug('best=%s', repr(best)) self._phrases_cache[tabkeys] = best return best def select_chinese_characters_by_pinyin( self, tabkeys: str = '', chinese_mode: int = 4, single_wildcard_char: str = '', multi_wildcard_char: str = '') -> Iterable[Tuple[str, str, int, int]]: ''' Get Chinese characters matching the pinyin given by tabkeys from the database. ''' if not tabkeys: return [] sqlstr = ''' SELECT pinyin, zi, freq FROM main.pinyin WHERE pinyin LIKE :tabkeys ORDER BY freq DESC, pinyin ASC; ''' tabkeys_for_like = tabkeys if single_wildcard_char: tabkeys_for_like = tabkeys_for_like.replace( single_wildcard_char, '_') if multi_wildcard_char: tabkeys_for_like = tabkeys_for_like.replace( multi_wildcard_char, '%%') tabkeys_for_like += '%%' sqlargs = {'tabkeys': tabkeys_for_like} results = self.db.execute(sqlstr, sqlargs).fetchall() # now convert the results into a list of candidates in the format # which was returned before I simplified the pinyin database table. bitmask = None if chinese_mode == 0: bitmask = (1 << 0) # simplified only elif chinese_mode == 1: bitmask = (1 << 1) # traditional only phrase_frequencies: List[Tuple[str, str, int, int]] = [] for (pinyin, zi, freq) in results: if not bitmask: phrase_frequencies.append((pinyin, zi, freq, 0)) else: if bitmask & chinese_variants.detect_chinese_category(zi): phrase_frequencies.append((pinyin, zi, freq, 0)) return self.best_candidates( typed_tabkeys=tabkeys, candidates=phrase_frequencies, chinese_mode=chinese_mode) def select_suggestion_candidate( self, prefix: str = '') -> List[Tuple[str, int]]: ''' Get Chinese phrase matching the prefix from the database. ''' if not prefix: return [] sqlstr = ''' SELECT phrase, freq FROM main.suggestion WHERE phrase LIKE :prefix ORDER BY length(phrase) DESC, freq DESC, phrase ASC; ''' prefix_for_like = prefix + '%%' sqlargs = {'prefix': prefix_for_like} results = self.db.execute(sqlstr, sqlargs).fetchall() phrase_frequencies = {} # merge the same phrase in suggestion candidates for phrase, freq in results: if phrase not in phrase_frequencies: phrase_frequencies[phrase] = (phrase, freq) else: phrase_frequencies.update( [(phrase, (phrase, max(freq, phrase_frequencies[phrase][1])))]) candidates = phrase_frequencies.values() if DEBUG_LEVEL > 1: LOGGER.debug('candidates=%s', repr(candidates)) maximum_number_of_candidates = 100 engine_name = os.path.basename(self.filename).replace('.db', '') code_point_function: Callable[[str], bytes] = lambda x: (b'\xff\xff') if engine_name in [ 'cangjie3', 'cangjie5', 'cangjie-big', 'quick-classic', 'quick3', 'quick5']: code_point_function = self.big5_code return sorted(candidates, key=lambda x: ( - int(len(x[0])), # longest matches first! -1*x[1], # freq descending code_point_function(x[0][0]), code_point_function(x[0][1]), # Unicode codepoint of first character of phrase: ord(x[0][0]), # Unicode codepoint of second character of phrase: ord(x[0][1]) ))[:maximum_number_of_candidates] def generate_userdb_desc(self) -> None: ''' Add a description table to the user database This adds the database version and the create time ''' try: sqlstring = ( 'CREATE TABLE IF NOT EXISTS user_db.desc ' + '(name PRIMARY KEY, value);') self.db.executescript(sqlstring) sqlstring = 'INSERT OR IGNORE INTO user_db.desc VALUES (?, ?);' self.db.execute(sqlstring, ('version', DATABASE_VERSION)) sqlstring = ( 'INSERT OR IGNORE INTO user_db.desc ' + 'VALUES (?, DATETIME("now", "localtime"));') self.db.execute(sqlstring, ("create-time", )) self.db.commit() except: LOGGER.exception('Unexpected error in generate_userdb_desc().') def init_user_db(self, db_file: str) -> None: ''' Initialize the user database unless it is an in-memory database :param db_file: Full path of the database file. :type db_file: String ''' if db_file == ':memory:': return if not path.exists(db_file): db = sqlite3.connect(db_file) # 20000 pages should be enough to cache the whole database db.executescript(''' PRAGMA encoding = "UTF-8"; PRAGMA case_sensitive_like = true; PRAGMA page_size = 4096; PRAGMA cache_size = 20000; PRAGMA temp_store = MEMORY; PRAGMA journal_mode = WAL; PRAGMA journal_size_limit = 1000000; PRAGMA synchronous = NORMAL; ''') db.commit() def get_database_desc(self, db_file: str) -> Optional[Dict[str, str]]: ''' Get the description table from the database :param db_file: Full path of the database file. :type db_file: String :rtype: Dictionary ''' if not path.exists(db_file): return None try: db = sqlite3.connect(db_file) desc = {} for row in db.execute("SELECT * FROM desc;").fetchall(): desc[row[0]] = row[1] db.close() return desc except: return None def get_number_of_columns_of_phrase_table(self, db_file: str) -> int: ''' Get the number of columns in the 'phrases' table in the database in db_file. Determines the number of columns by parsing this: sqlite> select sql from sqlite_master where name='phrases'; CREATE TABLE phrases (id INTEGER PRIMARY KEY, tabkeys TEXT, phrase TEXT, freq INTEGER, user_freq INTEGER) sqlite> This result could be on a single line, as above, or on multiple lines. :param db_file: Full path of the database file. :rtype: Integer ''' if not path.exists(db_file): return 0 try: db = sqlite3.connect(db_file) tp_res = db.execute( "select sql from sqlite_master where name='phrases';" ).fetchall() # Remove possible line breaks from the string where we # want to match: string = ' '.join(tp_res[0][0].splitlines()) res = re.match(r'.*\((.*)\)', string) if res: tp = res.group(1).split(',') return len(tp) return 0 except: return 0 def get_goucima(self, zi: str) -> str: '''Get goucima of given character''' if not zi: return '' sqlstr = 'SELECT goucima FROM main.goucima WHERE zi = :zi;' results = self.db.execute(sqlstr, {'zi': zi}).fetchall() goucima = '' if results: goucima = results[0][0] if DEBUG_LEVEL > 1: LOGGER.debug('goucima=%s', goucima) return goucima def parse_phrase(self, phrase: str) -> str: '''Parse phrase to get its table code Example: Let’s assume we use wubi-jidian86. The rules in the source of that table are: RULES = ce2:p11+p12+p21+p22;ce3:p11+p21+p31+p32;ca4:p11+p21+p31+p-11 “ce2” is a rule for phrases of length 2, “ce3” is a rule for phrases of length 3, “ca4” is a rule for phrases of length 4 *and* for all phrases with a length greater then 4. “pnm” in such a rule means to use the n-th character of the phrase and take the m-th character of the table code of that character. I.e. “p-11” is the first character of the table code of the last character in the phrase. Let’s assume the phrase is “天下大事”. The goucima (構詞碼 = “word formation keys”) for these 4 characters when using the wubi-jidian86 table are: character goucima 天 gdi 下 ghi 大 dddd 事 gkvh (If no special goucima are defined by the user, the longest encoding for a single character in a table is the goucima for that character). The length of the phrase “天下大事” is 4 characters, therefore the rule ca4:p11+p21+p31+p-11 applies, i.e. the table code for “天下大事” is calculated by using the first, second, third and last character of the phrase and taking the first character of the goucima for each of these. Therefore, the table code for “天下大事” is “ggdg”. ''' if DEBUG_LEVEL > 1: LOGGER.debug('phrase=%s rules%s', phrase, self.rules) # Shouldn’t this function try first whether the system database # already has an entry for this phrase and if yes return it # instead of constructing a new entry according to the rules? # And construct a new entry only when no entry already exists # in the system database?? if not phrase: return '' if len(phrase) == 1: return self.get_goucima(phrase) if not self.rules: return '' if len(phrase) in self.rules: rule = self.rules[len(phrase)] elif (isinstance(self.rules['above'], int) and len(phrase) > self.rules['above']): rule = self.rules[self.rules['above']] else: LOGGER.debug( 'No rule for this phrase length. phrase=%s rules=%s', phrase, self.rules) return '' if not isinstance(rule, int) and len(rule) > self._mlen: LOGGER.debug( 'Rule exceeds maximum key length. ' 'rule=%s self._mlen=%s', rule, self._mlen) return '' tabkeys = '' if isinstance(rule, int): return '' # should never happen! for (zi, ma) in rule: if zi > 0: zi -= 1 if ma > 0: ma -= 1 tabkey = self.get_goucima(phrase[zi])[ma] if not tabkey: return '' tabkeys += tabkey if DEBUG_LEVEL > 1: LOGGER.debug('tabkeys=%s', tabkeys) return tabkeys def is_in_system_database( self, tabkeys: str = '', phrase: str = '') -> bool: ''' Checks whether “phrase” can be matched in the system database with a key sequence *starting* with “tabkeys”. ''' if DEBUG_LEVEL > 1: LOGGER.debug('tabkeys=%s phrase=%s', tabkeys, phrase) if not tabkeys or not phrase: return False sqlstr = ''' SELECT * FROM main.phrases WHERE tabkeys LIKE :tabkeys AND phrase = :phrase; ''' sqlargs = {'tabkeys': tabkeys+'%%', 'phrase': phrase} results = self.db.execute(sqlstr, sqlargs).fetchall() if DEBUG_LEVEL > 1: LOGGER.debug( 'tabkeys=%s phrase=%s results=%s', tabkeys, phrase, results) return bool(results) def user_frequency(self, tabkeys: str = '', phrase: str = '') -> int: ''' Return how often a conversion result “phrase” for the typed keys “tabkeys” has been happened by checking the user database. :param tabkeys: The keys typed :param phrase: A conversion result for these tabkeys ''' if DEBUG_LEVEL > 1: LOGGER.debug('tabkeys=%s phrase=%s', tabkeys, phrase) if not tabkeys or not phrase: return 0 sqlstr = ''' SELECT sum(user_freq) FROM user_db.phrases WHERE tabkeys = :tabkeys AND phrase = :phrase GROUP BY tabkeys, phrase; ''' sqlargs = {'tabkeys': tabkeys, 'phrase': phrase} result = self.db.execute(sqlstr, sqlargs).fetchall() if DEBUG_LEVEL > 1: LOGGER.debug('result=%s', result) if result: return int(result[0][0]) return 0 def check_phrase( self, tabkeys: str = '', phrase: str = '', dynamic_adjust: bool = False) -> None: '''Adjust user_freq in user database if necessary. Also, if the phrase is not in the system database, and it is a Chinese table, and defining user phrases is allowed, add it as a user defined phrase to the user database if it is not yet there. ''' if DEBUG_LEVEL > 1: LOGGER.debug('tabkey=%s phrase=%s', tabkeys, phrase) if not tabkeys or not phrase: return if self._is_chinese and phrase in CHINESE_NOCHECK_CHARS: return if not dynamic_adjust: if not self.user_can_define_phrase or not self._is_chinese: return tabkeys = self.parse_phrase(phrase) if not tabkeys: # no tabkeys could be constructed from the rules in the table return if self.is_in_system_database(tabkeys=tabkeys, phrase=phrase): # if it is in the system database, it does not need to # be defined return if self.user_frequency(tabkeys=tabkeys, phrase=phrase) > 0: # if it is in the user database, it has been defined before return # add this user defined phrase to the user database: self.add_phrase( tabkeys=tabkeys, phrase=phrase, freq=-1, user_freq=1, database='user_db') else: if self.is_in_system_database(tabkeys=tabkeys, phrase=phrase): user_freq = self.user_frequency(tabkeys=tabkeys, phrase=phrase) if user_freq > 0: self.update_phrase( tabkeys=tabkeys, phrase=phrase, user_freq=user_freq+1) else: self.add_phrase( tabkeys=tabkeys, phrase=phrase, freq=0, user_freq=1, database='user_db') else: if not self.user_can_define_phrase or not self._is_chinese: return tabkeys = self.parse_phrase(phrase) if not tabkeys: # no tabkeys could be constructed from the rules # in the table return user_freq = self.user_frequency(tabkeys=tabkeys, phrase=phrase) if user_freq > 0: self.update_phrase( tabkeys=tabkeys, phrase=phrase, user_freq=user_freq+1) else: self.add_phrase( tabkeys=tabkeys, phrase=phrase, freq=-1, user_freq=1, database='user_db') def find_zi_code(self, phrase: str) -> List[str]: ''' Return the list of possible tabkeys for a phrase. For example, if “phrase” is “你” and the table is wubi-jidian.86.txt, the result will be ['wq', 'wqi', 'wqiy'] because that table contains the following 3 lines matching that phrase exactly: wq 你 597727619 wqi 你 1490000000 wqiy 你 1490000000 ''' sqlstr = ''' SELECT tabkeys FROM main.phrases WHERE phrase = :phrase ORDER by length(tabkeys) ASC; ''' sqlargs = {'phrase': phrase} results = self.db.execute(sqlstr, sqlargs).fetchall() list_of_possible_tabkeys = [x[0] for x in results] return list_of_possible_tabkeys def remove_phrase( self, tabkeys: str = '', phrase: str = '', database: str = 'user_db', commit: bool = True) -> None: '''Remove phrase from database ''' LOGGER.info('Removing tabkeys=%s, phrase=%s, database=%s commit=%s', tabkeys, phrase, database, commit) if not phrase: return if tabkeys: delete_sqlstr = ''' DELETE FROM {database}.phrases WHERE tabkeys = :tabkeys AND phrase = :phrase; '''.format(database=database) else: delete_sqlstr = ''' DELETE FROM {database}.phrases WHERE phrase = :phrase; '''.format(database=database) delete_sqlargs = {'tabkeys': tabkeys, 'phrase': phrase} self.db.execute(delete_sqlstr, delete_sqlargs) if commit: self.db.commit() self.invalidate_phrases_cache(tabkeys) def remove_all_phrases_from_user_db(self) -> None: ''' Remove all phrases from the user database, i.e. delete all the data learned from user input. ''' LOGGER.info('Removing all phrases from the user database.') try: self.db.execute('DELETE FROM user_db.phrases;') self.db.commit() self.db.execute('PRAGMA wal_checkpoint;') self.reset_phrases_cache() except Exception: LOGGER.exception( 'Unexpected error removing all phrases from database.') def extract_user_phrases( self, database_file: str = '', old_database_version: str = '0.0' ) -> List[Tuple[str, str, int, int]]: '''extract user phrases from database''' LOGGER.debug( 'Trying to recover the phrases from the old, ' 'incompatible database.') try: db = sqlite3.connect(database_file) db.execute('PRAGMA wal_checkpoint;') if old_database_version >= '1.00': phrases = db.execute( ''' SELECT tabkeys, phrase, freq, sum(user_freq) FROM phrases GROUP BY tabkeys, phrase, freq; ''' ).fetchall() db.close() phrases = sorted( phrases, key=lambda x: (x[0], x[1], x[2], x[3])) LOGGER.debug( 'Recovered phrases from the old database: phrases=%s', repr(phrases)) return phrases[:] # database is very old, it may still use many columns # of type INTEGER for the tabkeys. Therefore, ignore # the tabkeys in the database and try to get them # from the system database instead. phrases = [] results = db.execute( 'SELECT phrase, sum(user_freq) ' + 'FROM phrases GROUP BY phrase;' ).fetchall() for result in results: sqlstr = ''' SELECT tabkeys FROM main.phrases WHERE phrase = :phrase ORDER BY length(tabkeys) DESC; ''' sqlargs = {'phrase': result[0]} tabkeys_results = self.db.execute( sqlstr, sqlargs).fetchall() if tabkeys_results: phrases.append( (tabkeys_results[0][0], result[0], 0, result[1])) else: # No tabkeys for that phrase could not be # found in the system database. Try to get # tabkeys by calling self.parse_phrase(), that # might return something if the table has # rules to construct user defined phrases: tabkeys = self.parse_phrase(result[0]) if tabkeys: # for user defined phrases, the “freq” # column is -1: phrases.append((tabkeys, result[0], -1, result[1])) db.close() phrases = sorted( phrases, key=lambda x: (x[0], x[1], x[2], x[3])) LOGGER.debug( 'Recovered phrases from the very old database: ' 'phrases=%s', repr(phrases)) return phrases[:] except: LOGGER.exception('Unexpected error in extract_user_phrases()') return [] ibus-table-1.17.11/engine/version.py.in000066400000000000000000000020041475513533100176250ustar00rootroot00000000000000# vim:set et ts=4 sts=4: # # ibus-table - The Chinese Table engine for IBus # # Copyright (c) 2008-2010 Peng Huang # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. ''' Contains a function to return the current version number of ibus-table. ''' def get_version() -> str: ''' Returns the current version number of ibus-table. ''' return '@VERSION@' ibus-table-1.17.11/ibus-table.pc.in000066400000000000000000000007041475513533100167010ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ datarootdir=@datarootdir@ libdir=@datadir@ datadir=@datadir@ extradatadir=@datadir@/ibus-table/data tabledir=@datadir@/ibus-table/tables icondir=@datadir@/ibus-table/icons enginedir=@datadir@/ibus/engine ibus_table_version=@PACKAGE_VERSION@ Name: IBus-Table Description: Table Based Input Method Framework for Intelligent Input Bus for Linux / Unix OS Version: @PACKAGE_VERSION@ Requires: Libs: Cflags: ibus-table-1.17.11/ibus-table.spec.in000066400000000000000000000052711475513533100172350ustar00rootroot00000000000000Name: @PACKAGE_NAME@ Version: @PACKAGE_VERSION@ Release: 1%{?dist} Summary: The Table engine for IBus platform License: LGPLv2+ Group: System Environment/Libraries URL: http://mike-fabian.github.io/ibus-table/ Source0: https://github.com/mike-fabian/ibus-table/releases/download/%{version}/ibus-table-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildArch: noarch BuildRequires: gettext-devel Requires: ibus %description The package contains general Table engine for IBus platform. %package additional Summary: Additional tables for general table engine of IBus. Group: System Environment/Libraries Requires: %{name} = %{version}-%{release} %description additional This package contains additional tables. %prep %setup -q %build %configure \ --disable-static \ --enable-additional make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make DESTDIR=${RPM_BUILD_ROOT} NO_INDEX=true install %find_lang %{name} %clean rm -rf $RPM_BUILD_ROOT %post additional ibus-table-createdb -i -n %{_datadir}/ibus-table/tables/additional/compose.db ibus-table-createdb -i -n %{_datadir}/ibus-table/tables/additional/latex.db %files -f %{name}.lang %defattr(-,root,root,-) %doc AUTHORS COPYING README %{_libdir}/pkgconfig/ibus-table.pc %{_datadir}/ibus-table/engine %{_datadir}/ibus-table/data %{_datadir}/ibus-table/setup %{_datadir}/ibus-table/tables/template.txt %dir %{_datadir}/ibus-table/tables %{_datadir}/ibus-table/icons/ibus-table.svg %{_datadir}/ibus-table/icons/full-letter.svg %{_datadir}/ibus-table/icons/full-punct.svg %{_datadir}/ibus-table/icons/half-letter.svg %{_datadir}/ibus-table/icons/half-punct.svg %{_datadir}/ibus-table/icons/onechar.svg %{_datadir}/ibus-table/icons/phrase.svg %{_datadir}/ibus-table/icons/py-mode.svg %{_datadir}/ibus-table/icons/tab-mode.svg %{_datadir}/ibus-table/icons/chinese.svg %{_datadir}/ibus-table/icons/dcommit.svg %{_datadir}/ibus-table/icons/english.svg %{_datadir}/ibus-table/icons/ncommit.svg %{_datadir}/ibus-table/icons/cb-mode.svg %{_datadir}/ibus-table/icons/sc-mode.svg %{_datadir}/ibus-table/icons/scb-mode.svg %{_datadir}/ibus-table/icons/tc-mode.svg %{_datadir}/ibus-table/icons/tcb-mode.svg %dir %{_datadir}/ibus-table/icons %{_bindir}/ibus-engine-table %{_bindir}/ibus-table-createdb %{_bindir}/ibus-setup-table %files additional %defattr(-,root,root,-) %{_datadir}/ibus-table/tables/compose.db %{_datadir}/ibus-table/tables/latex.db %{_datadir}/ibus-table/icons/compose.svg %{_datadir}/ibus-table/icons/latex.svg %{_datadir}/ibus/engine/compose.engine %{_datadir}/ibus/engine/latex.engine %changelog * Wed Aug 19 2008 Yu Yuwei - @VERSION@-1 - The first version. ibus-table-1.17.11/icons/000077500000000000000000000000001475513533100150335ustar00rootroot00000000000000ibus-table-1.17.11/icons/128x128/000077500000000000000000000000001475513533100157705ustar00rootroot00000000000000ibus-table-1.17.11/icons/128x128/ibus-table.png000066400000000000000000000170751475513533100205370ustar00rootroot00000000000000PNG  IHDR>aiCCPICC profile(};HPE*v:Yq*BZu0 4$).kbYWWA|8:9)H&1^8܏s^f1hmq1]^@5aYƜ$%Ỿ]gs9xMAiU88F PӜ'rjbbKGD pHYs B(xtIME5g&t:IDATx]yWy{Z/Id[e>;BcʀmpH>@HR* 2X^&ȀmLزյ:ÒV]=^ϱҾ?zz_}1=ǹ;عoӥ<%q r5in*Nuƀ2 CYrE 84iqѸu p4FJ,ω8>&MO<ȜLsDAEI H64b=WkZh`FTIe/y/9޻KD{ yiLyAj`=,cbOQ;aK,z<PN-D!cbʴޞ~v*E$ᎌ<'ƃ;F'F9á;˦ܽ9 n@jHi|vOx0&cO1@I#cb|pxl$R# _Du;wV?>er81R,,+IO~k{es䚗^+6XK9n y$jm$S)Is붿 *^QW_=N5pXujAM1LQSUZdx+n[m]=W-E@M6.Zbx4|~W29̒͂Q}qfCk;ShQn{;fX4tO9\;[Phn lIR4/1m~q?b`n|Mw\󯜗N6V#k%Y <ː Tj=`tܵnrc8% J+d!㞾~>yPYQ#p8Zh;4K>mk<8Yti㶄+d> |`Wofprֲ+#waz:ǕUJk; I^D.Llk:Nᷚ2 ژrԇd=T: GMNw)z4+ >ϹsYn_s!N$)iNJ9~0n?ܫSH!TD}9V|ZVtk5d [h딺fJM&?DMG#e-sY-0 ͛D^+A 0r5ca :Q&@29+Fx@"xDiSdހku:XemuaLٙUXNW#L7!cEKiS+O7)dJRٻ{@8x -ґNX4FM^?`+zQ0f X+>֛Ǻphp8U7p*᥽C2m +Τ q6uSu]q p  4\_k*1ݜMl_u*{FA`z]n~:;1)l8>ҩ='N onUf%Nz]8g41g&FZ'ky!\Qnw7y?\JL,mps2:.s͍z XUbH($uК= x M @9.O)T=&xZޮР)a*`Bb jĎ#(!I0N!k _ GX%ntꎭ/)x~NMdXOHXU ZۃG:쨟NF---ޏl_sa, j9G_09EMOwt)$6*?Kw'z<1#0jy;@f}g";mU_߰ߙaz4JDe#QK'{vn)W&KE8]`!s,VN J\>>hދrqZ%q<۱fO`z/}pD<B"T4JEG ^z)甪 cߡ%9{:Pb?PBTDkb +\|EM.iJfm" Dt\4T WZ$i-t\J7P 9Фf?7]/,iJձqa= ݩ㭓sTG>) 6\yY(q!C2w@8C/ TtN2I_:¸HȰc/ :Y 7{ B="ЪZԴ&CJj&lhMX dp^k&PQ t K:&DUnxճWIc"quwjP*"T,,,e5W&B.82 ?H 9TpRִ @Uùmn))GnpM Z>  T#Z/d.=:4XPJ#!eEa2L0FP͍lDrw'뺚Z4CkIkg'9w&rb|u^lF } -B-"ZY҅F# |Gm"{Ǥz[-+ ']3^~UeQ#rþ-Zj,ܖ+Fɴ4d/ 7 xTL̞5w8X~Ԁ=Ʉ WsϢX: M?z_BQ W8T U^YRF)PpJI2q~ov8,O'>{9pu×?h۶vԝ`<n1@IuGS wɂbvRM8,_ jGr5[ݰ_Z%K"t#)g-!޴eLPr+"Ae5GHZ.hXybMx^ K7 ܌soӯ*MIRI o pI[zdLP}%4&|үf{om|agϱyυ3ߔhx&)kBQë;0Dy NNU . 1#YIs$n=|oGmVoOO=@g S<XB)D߄/mt_t3qZ%]Ac lY;հ=5JQuh׉`~ow]0=b;Q۞ѐQVQrRgzMF}Dm"Y`U bibX}''pʌ`yF8Y8'5:=@bYKLVnLa&+ {Ȣcg. '/c%dOc3k"==)$@QÂWqNf0fL%̛wl",` :c:'qȘfrp|cIϬjɉA,Uudm9i&t>Vk{"ѷ t:sYel#q|Dk‘- OQpg6])|; ܁X5ђ!")1 ,84 MYOkb+cc u,(fn9޾զD#_^eEtzg'Ž5 NI8\v+/z> T#q<|;;rY|C90?:5OקnJ e A:Z3 0M8Ac z_?~`9:ضm` <5k܎엩9>;h Hf 7dnm=I/,e}g`v)㇣ b5yuW%iR*Y߈ʷd p(zזcϽi`{E3 r8ox}Gw8H^LNJ"f`ύc} u5:;P4p,chfǿ&eb֒b:6uGpQNnZ/=7|oL) 4SP;5Qv@W~r _3_xtWfj`/"1IGxڢ\ۻ?Vzѧh,vA1yKJcI>bar.摕2L#1ԍMصkw_ m;M&PKsh+{ミJg0<\TW4iq4aaRJ7GI'3<ŞGIFf ~$C͍#JSRF' 4, %kIXӬ~5ӣd_'߿Bs ( >va4˟%Oh ]xD8} 9}eTH`K BA%a#FN}_"B9PZ /):_c5>v |Rf>Iл \\4e ٔ])H%}S׼5qiV)PϻCsNs~?Jr3bKGD pHYs B(xtIME97 IDAT8˥mhuyxvԽlNƴ¢+~B(foC(^lˊ-ùec`TiS8ێ39q<Nѷ?.~[t eba\ P+O86Ƶ1! :y6%Od;-VQ [ѡCF |@0آ,]\FqaHMYT*`{o<_್w==pwTr'}݌Ո\to`9=va<t_EQaQKOf.^Uѿ7fc&.b$,ba. :xG"qv76 G*Љakh4-g5ʱx$#XWS{r┾;Д x4hEE7.v)-+;H:?@mNR\i֑.[Vb<+YɆTV׉]~׽󱈩oHU./eʪR: {'gy\ g;$` [8 XyFz#ʵ[grd|l"+O>l `~cu,AU 2N~ ϕwoL"\󎭵Fdb;3*SpYm Rm'_d,˽1 ]C?$"u~=_>kxi}s܈9z2PZ ?eN]?7l2@׷U/%e 7sIENDB`ibus-table-1.17.11/icons/22x22/000077500000000000000000000000001475513533100156125ustar00rootroot00000000000000ibus-table-1.17.11/icons/22x22/ibus-table.png000066400000000000000000000032601475513533100203500ustar00rootroot00000000000000PNG  IHDRĴl;iCCPICC profile(}=HPOS";dNDE EjVL^MGbYWWAqtrRtK -b|pys>@funD\dWŮW P Of1'II{~Y\=jb@@$eioOo}+*9I ?r]segFtj8B,XicV45)⨪/dF]QscigJo+u`ZKuKS`ɐMٕTB>7e[{͛[@fe;>4r-RbKGD pHYs B(xtIME!LIDAT8˵mhe~Nl,2R35K$(SP؇(ч4ZE9ee*VRZns.g*#9?r]}pKс ϟsss RUc 4Ж2e ʔ˶ear@i-m\0Hceo;E}F ;waMꌥ+Z 76ͺ@Qޛ˅ M Ovl_=*ZnH\[5}*9蹂)D]Sa@G,m(]7,#Glj +J *ގ?oP2ܖn.^3ڀ^*-cce[W}f{{qFWׅ ^TU"o)/ -/QLhmIENDB`ibus-table-1.17.11/icons/256x256/000077500000000000000000000000001475513533100157745ustar00rootroot00000000000000ibus-table-1.17.11/icons/256x256/ibus-table.png000066400000000000000000000402031475513533100205300ustar00rootroot00000000000000PNG  IHDR\rfiCCPICC profile(}=HPOS";hqP,8jP! :4$).kŪ "%ޗZ>{p}Ш046Ʉͭ=AbHf1'I){~Y\}jb@@$eioOo}+*9I ?r]segFLz8B,;X`V25)☪/d=V9oq*5꓿0WN5$ "PF6XHyurȱ*4Ȯ~*LNxI8#@.Ь;4O3p0IzŎm⺭){0dȦJA*Pr-лͭu CJh}ۿwZ~r1bKGD pHYs B(xtIME G IDATx}i\WuwnUϚ c-Ð@ ,y$+ [8l0mْ-IjIVk{y?֭3ޡVvս}ηcƌ3f̘1cƌ3f̘1cƌ5ksmw}& w?_9r .f_ŵ0?.ݶei* q,}E@-_^y.y}$iI\+ P`_/ϰS#0-[ӏ~.\/=ü~ft$q@M2äma Ҳ^?C~DG)ߏz~]]#|?0G!&g)Zj; 4 8Y b> ^XG5!] \W2DA@яRU 8FC~*[V>!0 9dXaPzM~ 5Pc fk2[s@ )ߏ%' @cDkjAu&F ({r#|iI:g< gB)PYH OKYJVz{ro6/9F ǯAB-~Z[7e- jw{1 =_^{5 w/f/@ٽХ-ׅBuV\㞼95 xMƗk'(.8sJůԙ)c{Eįu%^p  * Pցe΀)l)*X7~pa/hXBB)֑"bOTVNJ?YvDm_>PxM`C$_鏔 tk_@Bi%2rӀ x脿vTs 1sq@m_:m:C:e @^i%sM"Y Y*&8^nIXŽU }٥8@ k\PrAX,h?,x6Kť{ãmo qղ@ր Wс5: BqYkUUv2Cb.Ծ[#A&*BȏD ^V[7:6aX"޿s謰1 4FWXVP%`Lg(-K^`nt;"hB'h''—kP\: 3y ?3<nxXwƐg,?l>`l讥kztݹ?=WtݤI'ѪK`(Ó?e X~bv`݇툚=:)ú~#j=ƍO~K ntnq"޺=2<:1RzX@3FTDkC]=C&2+m7877A纶C =VKnJ#=D[yPa2LjKָ5|Άղ;7#Íp ]f 8x@ruT1 &cU Kc2?8rIj2Ƭ2@I ĘtxXu,L`ժ5JAFu-v®@4e D3TXv- Vp yLMφB>GVa% ^mkeC2<r ®[H8?$ ]%J_N-|Т6!/ 6oeOWݞﭡDA# 78oӹPnr.(=/4=`P. _]Gf.cz1XU2#J޶yAt-@1 @M´h(RTtr&EN3+}ے-nub[䙳!vSÐ?I}:yfw!3+td*+S|6陹0=ȅDb uI[DaOvpiΈ86>`,{̤ e)hzE+0\oht4\$h@byuj A< hǚCipїL睯"3RlamByȡ=]da C!jVƕ'pOIGRB6t Id )b6@(w¨: p?KS`%m7y*4x+л3T #$jJ|Ővy+ _Ԟ4;TkI Zg[/"*/j̜۩3N$z枼cQ~-~>nv?hgjߎ* M.(X]tԶm \5[>\:̥{o> 82jpIHOonH`%\E__g?6Xk[;8 bt]%^ĤQpaztkTY)Ҁf`⾨f.`PӆL38duGE9 H{R'{~j3!5 q.kW3ھ%w\H.ZtB 04<R l2wR>f|#:?=|OЋ.奒ed\&WoxPG`H.`Zqm5O[Rx(c '5׾GYa9qr]OHh57V܋"}g\2෣ ܐsjB2m*HXw@"Cu{! @)E_-D1mpUZl:^_$3YxvpY+dJg\lF ltC >Pux\jC"8mO,x5󴨤´ ff&]H;u ?:B/cC a{Ӛσ܇%漶oObאbE.VLSSY漃+th!ОﵮecYlԥC4ˢ.otefw%XxV,]+.-w xu9BG+Cff4>s$ݥ*itW [̙`_lR?2{#Sn`8wq%`^~ MBodt {"`wj7 %y<; Eem(5R#0UvBd{S ix;Bȥ E@T>qfɢ =H\w* .{ c:9D9""_rbQ @%![[l4?b48a#)`KYDA 概/Բ.gAɤ͇ivH7V],a9ViKsXY`qEdR;[RZ'j9P_5Zj̄./S{ p MU.tF2 =o?y R$*ڐ*m`,bՌ@K( `bb '5W3z% zo3Pa\/f`ΟP0-.5D U2]zd>X]\ygDL`@98o~_o$3y.='V,{Y25䊸߁yk\ȥ`4Xtp쀏xᾐ;1`<Pm "Kfr,΁X?w$(؎17ERyW`yGhOjpdz`_R`mny~`?P<#Zq~LWgl++f1h` p1=5yV^-Z"ҔW M8ٔ0ʠ}~Vi]IGg1L0;YK*Hg^Ք\&!lfNoNOPVvl]Ú"@ѝ/b<`z6"8b̉s@W|}[ S֥tG.Rl} O 09,Hmet d50V9` v&UYxߕHYl4ݓ~f+9句l=s:`jz(W6`/;yr^iuG ݰ4au,B4ޢ_ß|erfsםa˃&Ky \2mxCW6C0*yx@ p1Y曩'! ?pJyΞ H&% G=~SvȪKA-}=y"!Po{kG8ٶ-bN3`/\}qj}omQ NtD-NL}*O_{x|!OkLe8cl{(M X+j]& rK2 r6ktEO+t.e8(!V n/: *?QNU;&x@GI&cg7x(Åu)mREdn?F (p?8鶗ʳТ([ +]%HjNiv^&:3XUB: s93M3-gIK3y׊XRV\WeX*8c"_"@~[{ˀp܏R?ʦ Jv4<yn8:ߓ ~v`*J$$0J)׆ǎE]\K\S5:p\ C&+ѥn 2,+wҌ2ElUe\V܋?I?ÏgvwrElGY Х5e'G^2!)s~?pwuJ㗞]uݍiuLRl템wog(-׽t)tAphH!Pކ)|s:@?~ 8~7<I3fGԥ&eXS s؂%\&$[IS=r˰3mNm)^j"2Y P̆$'[ZE9Yh6$:˿ނ O@|o}|{M~F\_6_Qx/R\.6ʔtrT s66W, v"y6hvbk~كv,Qb' 8W09x{[kT /屉%F* Lmt` Ҥ՝S_/k]3G <*^F;!hΎͯ|qe[f>&ݙ^(ϊ̷˰,j-38=q7'0i*3sW^g C!ɲO |k36"/]Nx0׏*۷J@V`8 $mw!B|E65 } #x}fgI)ÈR0x%DCܒ%|/T:j ۞EB*/Sz) tIDAT:(+URPpae4DtX6ԑe!,g_+UfF"P#Ny.h4GU~@t"SځڼmX^2 J@L(uo^5bQoE~TR +wg(Y9i;eza޶r KᙐCR: NaNVԿZ:G4D&uתըޚZsuȶ5(X)4?Fu\ ]|M+cT!“V|I1ߏ$L=7 vޏq3ZV spDl5>v~}<yX:onWCLW)Nnpe(Wj?u.MkZl\'T9AnMGBM乷_ P } 2p):*q'"QV23\H)v1fȨ|-[gmSx؊ Ǽ #DP"@#RʰS"c\5 {`g,!a|a@m&,QCP`&rľj[y_wSN`Y^xb>{TfB=iV-b ^nkhiUV eC5l'[,Aow]z_{Ou(2a,Dm:2/S^Kv<ȚJ=>}Adu mնWߴyfFk6Wb}'JXkm3x׿>͆P{GK_#˵fX׮D. l&l_OŎ[N גp!0ɶ Lp-,;R!I@4 #db6GC\x%P ՗0gyλ¨YbkV2H`u{@>y3A)pN_u{OUq@1AVeD#تU+!\Ⱦc$`g?({t@"ĉB>%\*1u\HX3,#dܹny߹/UV`4v^`kٹBU nIޝEPh()) Ɇ-Hisml`[>Bs`ªfcvJ>0ޛٷ!":*\ BlAXcX2!OT*U};}G~Q8ÂO9Ԝgq5H|֟17&T2XIP<Ϝ {Pԥ5PC70f/+exfz&\0zqq| AOzu7DK$0 PS'=t h` U(,@Z3;z(7'? +8IG$j*Z`e!̡X_\yr8/exlb2@ݷǝo|;S{w>*a+ +hF/&0a)wmV=im[*dz%d\{ b<(!zrZ#dfMgs$Ui.dEĩӱ91KE<J_%oy_5I6a~kBRGqp %c*dZKE{[t2^  { ʃC8H,/XЫ0ԊV(N1JpԢS`-UZyT@C!ѥa@ (C<>9^EgcM,/8j?*K)!څ2rȄW܋tH@wTrqۀЩc^  2Yw:dK6A_:]FFC&TK xb FelX^Aa>`E~~0u>teXtt\6aG$e8bh۷^$Lz&|%DUB<T*d WTN GPut#fU\Uґ=8oΜ۵{tBଡH۞w/rw3 7%]k!@: ydVC"ϯyO4X :{e sljShɉ$ X=x9rg4csTd^脛lAepP ԖtˠmcX T`ttUյV-2\LG8YV3?Tt鉢$+RK2ԤQl$+ʰ!FqT12_w6C$Q>: N`P_@jok׭  ;PoP,i+C7VP:ʰ\ܑ#G r _[jʰ\q k i#-<`HL7 Xt<_A 3( ?'=Eh,GP r@ m8oGSlmAkʓeR?cgt]| ֟UV!y鹨jqb@40yOrq p}̲^1H,-E =90}#d^?fRtDc 659!uOiyi$\VjEl `8.V4OZ¿'\2`.em\R5HPb%픢 ]p3Ihhs]$ :@@ "IP@ziz3=FP$6<ۨ0^f x!|[?@W9uX63Bb177U>"$ek+$C/ؗ3Nd(a VcNu&Q84!a\2ؘx% t"5wС[4`nBM]3]U:@?(lGm R419rM 0nk;L"Qbͫ=Kf#LMg=cXiK%&c]ӆeMW̬@)KG3#C#C4.MVI@+R{:sz|Wtl_$"n'.W7kȃsn"ƵM]8q˥[skBq 2j~|/ ;:b3yBV0ֵawEee+6|,0"Q5](Ź/ @?z1Ne=1C%ȸ,!H݇$Ohn&vn >cPYK`YKW5"t^zg, EV4òz6w{ %N5u7*SC?aJ7t]wJ~8Ȣ0֐vNvkI;ųqS[ gy>{1" KXU_K=}V.[t*xZ v!Jդ}(=eV>xyӿڣ~ :Hs͌artO ?m״m(0^ 0v&6$JӏMPPW_yvfssA._ Ciԁ3&0.;Cyw5dhsG0PB.nS4%_^a2`mv^h;&/e ,`cX GV]r?]+EĮ9"[ɝ|c gmhя} 9}eTH`K BA%a#FN}_"B9PZ /):_c5>v |Rf>Iл \\4e ٔ])H%}S׼5qiV)PϻCsNs~?Jr6]bKGD pHYs B(xtIME>1IDATX}l_﮽Y- (C38pH[\fLtO&fsl R9{PnS4fnZJ27a̢lyjR޵쏻+WJ+Y~?s9E!Vz08<<:y%|(*AH~Ra~y|NO3 lH+8x\U P\|Pw=:\1k~ZE.?^nlR`cq!`)Jk9Aj$V wJ9Xt:1Z-Op[|#Bwn̆ |_JM"GU;;Y<`p P$Z&AnL_K*Fu?@2l=[%0 +cT4R~EEl^n)K'c]](dv>^V*O  I5p:)c$rDTIRӛdz_i779i묂SO"Xp'!ίu:*H! w[DJ+ _aTf\mxRU]U}͚65Fu \{nqEEKw~a7@gCP@2 !r>6i}>S~cP%N2=f߈'1;aa5[$ixk'Bu=a5TXm*_JsK%rƈ U+ ԙp%2`XR=/*?K}@Pxf׺.C[: rEaŏyp&qW+5__<؟ /[Z1ePG.[>}wq*bhO =--=oK6#[ DUjo>ϧ ?;<2<%"u'3.* W5((U44C<"yU 7aٜU4{׾ǗI=DOtpfH[HGB۩=>2.PvAdKYycI+QIENDB`ibus-table-1.17.11/icons/48x48/000077500000000000000000000000001475513533100156325ustar00rootroot00000000000000ibus-table-1.17.11/icons/48x48/ibus-table.png000066400000000000000000000062101475513533100203660ustar00rootroot00000000000000PNG  IHDR00WiCCPICC profile(}=HPOSE*vQP,8jP! :4$).kŪ "%ޗZ>{p}Ш046ɄͭW!P # 3˘|=|,{^5o1 2ô77m>qdx̤xƹ3f&=O%t0+qLt8kk_+\BX j(quR,<trȱ*4Ȯ~*LNxI8#@hhq'@j$bG@6pq֔=rx2dSv P(gM9Y:YnC`H>w;4robKGD pHYs B(xtIME!+ IDAThY{pT}1 A( -qlkSaXD N:CG;P:ck-_(bmmi񁢄<P$H${=ݻM Gg<3;|}Y 8ÇB%,X DG9g-+glO~| 5 A`2afGp0xb- I` !ke Pl޳@ p|#TGA{K XM/0$2uS#уp=e z2ZW ac]{*oM.?p\y8I`oZ&2lF^:{gGԀV cXd҈ ' A [+_֛7z+c? ŪUmzSVqb֟3nNxz;rmz+I(v#deԹv2 `hD)y0sGP`4y6c)Lx}h1D˒g\Dv]D׏yɏ&.ȶ@0h$d4[ЀcW*1j\c LԘ܋'06`o]FBDqɢx3qJ;=u 0@=-цb?YvMz@ ;>`Wg@>Uv f`b@;M<#:ߝ9%,1=7%,̙-8  N?fLn@YV2p5ye|J;1F%E(}vhqM`3}D#+hFdp jfՀklǂAe2e.[.b躎nZ['=?03S~Y݀6I*Sە\-NDzL;JBsNmL6A> OgDoq@qd&p#2}tϝzwQ jڲ7~P5RW}-<>Ǖ2 "PRRSPPiG'%&ET 3fui$!qTyFqmDW&c1|.0'&^RۙbRh`Th%#.DΦmAɕ4"MnpV,Nij Z(Y9e&?W3Eڴӫ4% t 2# `(m#-;wkWnδp]&UUzЦ0+ BӐYDlVvlmv-rP";KLf,ff$q?~s'0ٛ N ᆽISn; ZfY:z"{^5sva'T"inq Y;$nvX2就;myְ@=7lו 2m=FBrym{Qy EV\:2THqjL `o_}͓UdwBfI%š@4Tr) 9)(e鞁c '*>0b3w NS/|۝|[VP=SݗA w(D"H4ݮ,90_0v]b:1peD&%4D5lqe]2r;gЎ#0RN9H4|hi3׼tr{->㢳g s]jť/-Ƹ_˅h~c{3 P:( ><|8|'3 ;^l@Q @ T' 1RWySVq @x" #5^`46-8"잨 -^A!^SN"F{͏:cg.R/Ds[RZ~/3 f! f#<+t];9r v ."aW~"K{=i0Lq+1ne۾pGv&|,`y~p\5iejX| }_7%] :IENDB`ibus-table-1.17.11/icons/64x64/000077500000000000000000000000001475513533100156265ustar00rootroot00000000000000ibus-table-1.17.11/icons/64x64/ibus-table.png000066400000000000000000000077661475513533100204030ustar00rootroot00000000000000PNG  IHDR@@iqiCCPICC profile(}=HPOS";P,8jP! :4$).kŪ "%ޗZ>{p}Ш046Ʉͭ=AbXf1'I){~Y\}jb@@$eioOo}+*9I ?r]segFLz8B,;X`V25)☪/d=V9oq*5꓿0WNEX j(quR,<rrȱ*4Ȯ~*LNxI8#@.Ь;4O3p0IzŎm⺭){0dȦJA*Pr-лͭu CJh}ۿwZ,rK"bKGD pHYs B(xtIME1/ ݪ IDATx[{l\W}1~%nJs^bsteLl}?Tׂu.ɥMN; 4@]\ٳr\m[lEc6z=@Kާ=zh7yfݍrr Nc`Ec!E4V_g7/\H׵D @% ʪ)8ͮ[{etS^zK26t"Iw4~x{|AOcgg@pMy6?bO,m l(dfV0,ʊu~x_͂GzvصTV_cǖi?M3ѣ^wYǗn.«'^E%KAxq ܘq3y^IC9jC홓|ӱ)l d o9Qp #]&3-"o'ΣF\Q ]ݙZ7:ݝ*iMۜ\\2OvV[˝PnQ^1EQսD^|8rILl=g0y](w0E3;yaZD6 C 0J13읛W `,>䒎Um'QЙWUT'[cTT5ҸJ*3 [-];q|YG1p,ZHqNYᶴU*-a>!ꛪ{s!>N=XpfơSޒќ H;v@/*`2Vo(lk%04|tdTdYfMhYZ3Q|QU19v\eG!JU@L_}1&SZ?+G> h1C8d$-83`&A >]YϤjgcjNXf^8F3֪).fg( 5'!QW{&Y  uޏZFf ʿ~+~+aVrV-!Ms 21@9"ds@,$-;T. {3>xĆX aD6/GJy P@,4arR*BMĄz{P_c09Vj~빺ܗbAP %y00<@ЖL'\.y\)$Xnbu]ۿдON$F61<:WdϛzuX_[Gs;VJ1zGwdx.D'l akSp F* i*<g)p4XueG\ \;u"я݁59?<{X&sx,WG”nOJLYFr=;Y@jRib7UWת8 u6շe(0 "7FRPLpY"_ (G-A]JJ ڀ}x cخpE4z j[%`-_` G;w)4s@Zވh0V!w//+ U]t*vwu:6LJ:|We2f[hCV wal"܊v1mDf;6SC8 r|ʩڛ*UVS ׷R= y9 %||kN($qBnBǷ/|\?AgL9gE2m7oXJQsSs]H&}Wϟa*/RP-7Td4x a"]V(5="7q߼4yQ9rb*sƸt ڎ'kUCP ;b|+_,xi˯piY7e+]N'z|~W)1D#iE^{@ |ז=~x:2TY睑p-Rs}SRy0{a2"<}ezMPTZ 'm{Hѣ %lf>Ho( XAr/ĭbb!Jh}I'yUKl:BUW%+:e֐*:=<s ouh@ł|Lmh |lcD:gJe錩Lt l#x4-|@: 44;Kܦ ,'V|"ݦ L5=OyZ) AHjjn4Բa<CNU:1h]V@sK3Dn:VП4 keѶQJ`P<-+m<,F8Z Y:AxZ dҍTEJ@V*e.„@z;hn[yd4 ccY2W7a@ W JaLE݆J1+ڋek &h'rKOw:[s49ځ_ߘjcHe8qv ] (.=Ee!cg~\ :[[mu0VJACJYX7'&֌ OvLg4ѿz|9ڶ/׏{__}R&\"׬6d#Gڴ%6Ď8nI˱f/ą ) OQiʻ%OWTuzz|snv \\}cA\S*9״{;tނ xf|h'(-9.1ٶ=_+8( O?ؽ*=WBpj1g Wbl(#J N>Ho?<e|Ҫ#I풥J zٙte%Ep\5Gw.8xlϠx_sXej>υްh(j4럞awǻݡn|ȆKIENDB`ibus-table-1.17.11/icons/Makefile.am000066400000000000000000000044461475513533100170770ustar00rootroot00000000000000# vim:set noet ts=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # SUBDIRS = \ $(NULL) icons_DATA = \ ibus-table.svg \ full-letter.svg \ half-letter.svg \ full-punct.svg \ half-punct.svg \ tab-mode.svg \ py-mode.svg \ onechar.svg \ phrase.svg \ chinese.svg \ english.svg \ acommit.svg \ ncommit.svg \ cb-mode.svg \ sc-mode.svg \ tc-mode.svg \ scb-mode.svg \ tcb-mode.svg \ $(NULL) iconsdir = $(pkgdatadir)/icons hicolor_icon_scalable_DATA = ibus-table.svg hicolor_icon_scalabledir = $(datadir)/icons/hicolor/scalable/apps hicolor_icon_16_DATA = 16x16/ibus-table.png hicolor_icon_16dir = $(datadir)/icons/hicolor/16x16/apps hicolor_icon_22_DATA = 22x22/ibus-table.png hicolor_icon_22dir = $(datadir)/icons/hicolor/22x22/apps hicolor_icon_32_DATA = 32x32/ibus-table.png hicolor_icon_32dir = $(datadir)/icons/hicolor/32x32/apps hicolor_icon_48_DATA = 48x48/ibus-table.png hicolor_icon_48dir = $(datadir)/icons/hicolor/48x48/apps hicolor_icon_64_DATA = 64x64/ibus-table.png hicolor_icon_64dir = $(datadir)/icons/hicolor/64x64/apps hicolor_icon_128_DATA = 128x128/ibus-table.png hicolor_icon_128dir = $(datadir)/icons/hicolor/128x128/apps hicolor_icon_256_DATA = 256x256/ibus-table.png hicolor_icon_256dir = $(datadir)/icons/hicolor/256x256/apps EXTRA_DIST = \ $(icons_DATA) \ $(hicolor_icon_16_DATA) \ $(hicolor_icon_22_DATA) \ $(hicolor_icon_32_DATA) \ $(hicolor_icon_48_DATA) \ $(hicolor_icon_64_DATA) \ $(hicolor_icon_128_DATA) \ $(hicolor_icon_256_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ Makefile.in \ $(NULL) ibus-table-1.17.11/icons/acommit.svg000066400000000000000000000166311475513533100172140ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/cb-mode.svg000066400000000000000000000162651475513533100170740ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/chinese.svg000066400000000000000000000204721475513533100171770ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/english.svg000066400000000000000000000251211475513533100172060ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/full-letter.svg000066400000000000000000000154461475513533100200250ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/full-punct.svg000066400000000000000000000242221475513533100176470ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/half-letter.svg000066400000000000000000000103671475513533100177720ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/half-punct.svg000066400000000000000000000214451475513533100176230ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/ibus-table.svg000066400000000000000000000112671475513533100176120ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/ncommit.svg000066400000000000000000000145151475513533100172300ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/onechar.svg000066400000000000000000000160171475513533100172000ustar00rootroot00000000000000 image/svg+xml 1 ibus-table-1.17.11/icons/phrase.svg000066400000000000000000000145121475513533100170410ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/py-mode.svg000066400000000000000000000267261475513533100171430ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/sc-mode.svg000066400000000000000000000217641475513533100171150ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/scb-mode.svg000066400000000000000000000302601475513533100172460ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/tab-mode.svg000066400000000000000000000131751475513533100172530ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/tc-mode.svg000066400000000000000000000313551475513533100171130ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/icons/tcb-mode.svg000066400000000000000000000426241475513533100172560ustar00rootroot00000000000000 image/svg+xml ibus-table-1.17.11/its/000077500000000000000000000000001475513533100145175ustar00rootroot00000000000000ibus-table-1.17.11/its/Makefile.am000066400000000000000000000002251475513533100165520ustar00rootroot00000000000000NULL = EXTRA_DIST = \ $(gettextits_DATA) \ $(NULL) gettextitsdir = $(datadir)/gettext/its gettextits_DATA = \ ibus-table.its \ ibus-table.loc ibus-table-1.17.11/its/ibus-table.its000066400000000000000000000015701475513533100172720ustar00rootroot00000000000000 ibus-table-1.17.11/its/ibus-table.loc000066400000000000000000000005221475513533100172440ustar00rootroot00000000000000 ibus-table-1.17.11/m4/000077500000000000000000000000001475513533100142405ustar00rootroot00000000000000ibus-table-1.17.11/m4/.gitignore000066400000000000000000000005241475513533100162310ustar00rootroot00000000000000codeset.m4 glibc2.m4 glibc21.m4 intdiv0.m4 intl.m4 intldir.m4 intmax.m4 inttypes-pri.m4 inttypes_h.m4 lcmessage.m4 lock.m4 longdouble.m4 longlong.m4 printf-posix.m4 size_max.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 visibility.m4 wchar_t.m4 wint_t.m4 xsize.m4 gettext.m4 iconv.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 nls.m4 po.m4 progtest.m4 ibus-table-1.17.11/m4/Makefile.am000066400000000000000000000016701475513533100163000ustar00rootroot00000000000000# vim:set noet ts=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # EXTRA_DIST = \ as-version.m4 \ $(NULL) MAINTAINERCLEANFILES = \ Makefile.in \ $(NULL) ibus-table-1.17.11/m4/as-version.m4000066400000000000000000000037701475513533100165770ustar00rootroot00000000000000dnl as-version.m4 0.2.0 dnl autostars m4 macro for versioning dnl Thomas Vander Stichele dnl $Id: as-version.m4,v 1.4 2004/06/01 09:40:05 thomasvs Exp $ dnl AS_VERSION dnl example dnl AS_VERSION dnl this macro dnl - AC_SUBST's PACKAGE_VERSION_MAJOR, _MINOR, _MICRO dnl - AC_SUBST's PACKAGE_VERSION_RELEASE, dnl which can be used for rpm release fields dnl - doesn't call AM_INIT_AUTOMAKE anymore because it prevents dnl maintainer mode from running correctly dnl dnl don't forget to put #undef PACKAGE_VERSION_RELEASE in acconfig.h dnl if you use acconfig.h AC_DEFUN([AS_VERSION], [ PACKAGE_VERSION_MAJOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f1) PACKAGE_VERSION_MINOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f2) PACKAGE_VERSION_MICRO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f3) AC_SUBST(PACKAGE_VERSION_MAJOR) AC_SUBST(PACKAGE_VERSION_MINOR) AC_SUBST(PACKAGE_VERSION_MICRO) ]) dnl AS_NANO(ACTION-IF-NO-NANO, [ACTION-IF-NANO]) dnl requires AC_INIT to be called before dnl For projects using a fourth or nano number in your versioning to indicate dnl development or prerelease snapshots, this macro allows the build to be dnl set up differently accordingly. dnl this macro: dnl - parses AC_PACKAGE_VERSION, set by AC_INIT, and extracts the nano number dnl - sets the variable PACKAGE_VERSION_NANO dnl - sets the variable PACKAGE_VERSION_RELEASE, which can be used dnl for rpm release fields dnl - executes ACTION-IF-NO-NANO or ACTION-IF-NANO dnl example: dnl AS_NANO(RELEASE="yes", RELEASE="no") AC_DEFUN([AS_NANO], [ AC_MSG_CHECKING(nano version) NANO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f4) if test x"$NANO" = x || test "x$NANO" = "x0" ; then AC_MSG_RESULT([0 (release)]) NANO=0 PACKAGE_VERSION_RELEASE=1 ifelse([$1], , :, [$1]) else AC_MSG_RESULT($NANO) PACKAGE_VERSION_RELEASE=0.`date +%Y%m%d.%H%M%S` ifelse([$2], , :, [$2]) fi PACKAGE_VERSION_NANO=$NANO AC_SUBST(PACKAGE_VERSION_NANO) AC_SUBST(PACKAGE_VERSION_RELEASE) ]) ibus-table-1.17.11/mypy.sh000077500000000000000000000015251475513533100152600ustar00rootroot00000000000000#!/bin/bash CURRENT_DIR="$(pwd)" # get the full path of the directory where the current script is: SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" RETVAL=0 echo "running $SCRIPT_DIR/mypy.sh" cd $SCRIPT_DIR/engine echo "Checking $SCRIPT_DIR/engine" mypy --strict *.py ENGINE_RETVAL=$? if [ ${ENGINE_RETVAL} != 0 ] ; then RETVAL=$((${RETVAL} + ${ENGINE_RETVAL})) fi cd $SCRIPT_DIR/setup echo "Checking $SCRIPT_DIR/setup" mypy --strict ../engine/{tabsqlitedb,it_util}.py *.py SETUP_RETVAL=$? if [ ${SETUP_RETVAL} != 0 ] ; then RETVAL=$((${RETVAL} + ${SETUP_RETVAL})) fi cd $SCRIPT_DIR/tests echo "Checking $SCRIPT_DIR/tests" mypy --strict ../engine/{tabsqlitedb,it_util}.py test_*.py SETUP_RETVAL=$? if [ ${SETUP_RETVAL} != 0 ] ; then RETVAL=$((${RETVAL} + ${SETUP_RETVAL})) fi cd $CURRENT_DIR exit $RETVAL ibus-table-1.17.11/org.freedesktop.ibus.engine.table.gschema.xml000066400000000000000000000125201475513533100244440ustar00rootroot00000000000000 { 'cancel': <['Escape']>, 'commit': <['space']>, 'commit_to_preedit': <['Control+Shift_R', 'Control+Shift_L']>, 'commit_candidate_1': <['1', 'KP_1']>, 'commit_candidate_2': <['2', 'KP_2']>, 'commit_candidate_3': <['3', 'KP_3']>, 'commit_candidate_4': <['4', 'KP_4']>, 'commit_candidate_5': <['5', 'KP_5']>, 'commit_candidate_6': <['6', 'KP_6']>, 'commit_candidate_7': <['7', 'KP_7']>, 'commit_candidate_8': <['8', 'KP_8']>, 'commit_candidate_9': <['9', 'KP_9']>, 'commit_candidate_10': <['0', 'KP_0']>, 'commit_candidate_to_preedit_1': <['Control+1', 'Control+KP_1']>, 'commit_candidate_to_preedit_2': <['Control+2', 'Control+KP_2']>, 'commit_candidate_to_preedit_3': <['Control+3', 'Control+KP_3']>, 'commit_candidate_to_preedit_4': <['Control+4', 'Control+KP_4']>, 'commit_candidate_to_preedit_5': <['Control+5', 'Control+KP_5']>, 'commit_candidate_to_preedit_6': <['Control+6', 'Control+KP_6']>, 'commit_candidate_to_preedit_7': <['Control+7', 'Control+KP_7']>, 'commit_candidate_to_preedit_8': <['Control+8', 'Control+KP_8']>, 'commit_candidate_to_preedit_9': <['Control+9', 'Control+KP_9']>, 'commit_candidate_to_preedit_10': <['Control+0', 'Control+KP_0']>, 'lookup_table_page_down': <['Page_Down', 'KP_Page_Down', 'KP_Next', 'equal']>, 'lookup_table_page_up': <['Page_Up', 'KP_Page_Up', 'KP_Prior', 'minus']>, 'remove_candidate_1': <['Mod1+1', 'Mod1+KP_1']>, 'remove_candidate_2': <['Mod1+2', 'Mod1+KP_2']>, 'remove_candidate_3': <['Mod1+3', 'Mod1+KP_3']>, 'remove_candidate_4': <['Mod1+4', 'Mod1+KP_4']>, 'remove_candidate_5': <['Mod1+5', 'Mod1+KP_5']>, 'remove_candidate_6': <['Mod1+6', 'Mod1+KP_6']>, 'remove_candidate_7': <['Mod1+7', 'Mod1+KP_7']>, 'remove_candidate_8': <['Mod1+8', 'Mod1+KP_8']>, 'remove_candidate_9': <['Mod1+9', 'Mod1+KP_9']>, 'remove_candidate_10': <['Mod1+0', 'Mod1+KP_0']>, 'select_next_candidate_in_current_page': <['Alt_L']>, 'select_previous_candidate_in_current_page': <['Control+Alt_L']>, 'setup': <['Super+Mod4+F10']>, 'switch_to_next_chinese_mode': <['Control+semicolon']>, 'toggle_autocommit_mode': <['Control+slash']>, 'toggle_input_mode_on_off': <['Shift_L']>, 'toggle_letter_width': <['Shift+space']>, 'toggle_onechar_mode': <['Control+comma']>, 'toggle_pinyin_mode': <['Shift_R']>, 'toggle_punctuation_width': <['Control+period']>, 'toggle_suggestion_mode': <['Super+Mod4+F6']> } List of keybindings The list of configurable keybindings false false false 0 1 true 4 false false 1 6 false false false true '' '' true true true '/usr/share/ibus-table/data/coin9.wav' 'automatic' 0 Debug level When greater than 0, debug information may be printed to the log file and debug information may also be shown graphically. ibus-table-1.17.11/org.freedesktop.ibus.engine.table.metainfo.xml.in000066400000000000000000001241561475513533100252550ustar00rootroot00000000000000 org.freedesktop.ibus.engine.table CC0-1.0 Ibus Table Table based input method

Ibus-table is an input method framework for table-based input methods. Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, CangJie, …. But some tables for other languages are available as well.

input-method Chinese https://mike-fabian.github.io/ibus-table/ibus-table-cangjie5.png Screenshot of ibus-table using the cangjie5 table https://raw.githubusercontent.com/mike-fabian/ibus-table/main/icons/64x64/ibus-table.png https://raw.githubusercontent.com/mike-fabian/ibus-table/main/icons/128x128/ibus-table.png https://raw.githubusercontent.com/mike-fabian/ibus-table/main/icons/256x256/ibus-table.png https://raw.githubusercontent.com/mike-fabian/ibus-table/main/icons/ibus-table.svg LGPL-2.1+ Mike FABIAN mfabian@redhat.com https://kaio.github.io/ibus-table/ https://github.com/kaio/ibus-table/issues https://kaio.github.io/ibus-table/documentation.html https://translate.fedoraproject.org/projects/ibus-table/ https://github.com/mike-fabian/ibus-table/releases/tag/1.17.11

This new stable release includes these changes:

  • Fix to load EN compose file Now EN compose file is loaded in the class init of IBus.EngineSimple and IBus.init() needs to be called before the init. This fix is needed for ibus version newer or equal than 1.5.32~beta2.
  • Translation update from Weblate (es 96.7%, fr 100%, ru 98.6%)
https://github.com/mike-fabian/ibus-table/releases/tag/1.17.10

This new stable release includes these changes:

  • Generate translations into metainfo.xml files with autotools (Resolves: github-mike-fabian-issue#171)
  • Rename ibus-table.appdata.xml to org.freedesktop.ibus.engine.table.metainfo.xml
  • Make desktop file translatable and generate translations into desktop file
  • Translation update from Weblate (de 100%, ja 48.0%, ru 98.6%, tr 100%, uk 100%)
github-mike-fabian-issue#171
https://github.com/mike-fabian/ibus-table/releases/tag/1.17.9

This new stable release includes these changes:

  • Make the setup tool use the wrapper itb_sound.py instead of using simpleaudio unconditionally (Resolves: github-mike-fabian-issue#162)
  • Translation update from Weblate (new language Kabyle: kab 29.3%)
github-mike-fabian-issue#162
https://github.com/mike-fabian/ibus-table/releases/tag/1.17.8

This new stable release includes these changes:

  • Update Unihan_Variants.txt and regenerate engine/chinese_variants.py for Unicode 16.0.0 release
  • Translation update from Weblate (el 17.3%)
https://github.com/mike-fabian/ibus-table/releases/tag/1.17.7

This new stable release includes these changes:

  • Translation update from Weblate (fr 100%, ru 93.3%)
https://github.com/mike-fabian/ibus-table/releases/tag/1.17.6

This new stable release includes these changes:

  • Yet another fix to make it possible again to use keys with Unicode keysyms in keybindings and make it work with all known versions of ibus (Resolves: github-kaio-issue#85)
  • Translation update from Weblate (cs 40%)
github-kaio-issue#85
https://github.com/mike-fabian/ibus-table/releases/tag/1.17.5

This new stable release includes these changes:

  • Drop Python2 support (using pyupgrade --py3-plus *.py)
  • Make it possible to use keys with Unicode keysyms in keybindings (requires ibus > 1.5.30) (Resolves github-mike-fabian-typing-booster-issue#497, same problem for ibus-table)
  • Use `frames_per_buffer=chunk_size` option in `self._paudio.open()` (Resolves: rhbz#2238746)
  • Translation update from Weblate (cs 36.6%, ja 45.3%, zh_CN 92.0%)
github-mike-fabian-typing-booster-issue#497 rhbz#2238746
https://github.com/mike-fabian/ibus-table/releases/tag/1.17.4

This new stable release includes these changes:

  • Fix compose support for ibus >= 1.5.28 (Resolves: github-mike-fabian-issue#145)
  • Translation update from Weblate (New language, Russian (ru) 80%)
github-mike-fabian-issue#145
https://github.com/mike-fabian/ibus-table/releases/tag/1.17.3

This new stable release includes these changes:

  • Support several backends for playing sounds (Resolves: rhbz#2237674)
  • Update Unihan_Variants.txt and regenerate engine/chinese_variants.py for Unicode 15.1.0 release.
rhbz#2237674
https://github.com/mike-fabian/ibus-table/releases/tag/1.17.2

This new stable release includes these changes:

  • Translation update from Weblate (de 100%, tr 100%)
https://github.com/mike-fabian/ibus-table/releases/tag/1.17.1

This new stable release includes these changes:

  • Fix mypy warnings
  • Return empty program_name and window_title in get_active_window_xprop() when xprop results are unexpected (Resolves: rhbz#2215466)
  • Translation update from Weblate (si 10.0%)
rhbz#2215466
https://github.com/mike-fabian/ibus-table/releases/tag/1.17.0

This new stable release includes these changes:

  • New option commit_invalid_mode: Choose what happens when a character not in valid input characters is typed (Resolves: github-mike-fabian-issue#133)
  • Translation update from Weblate (de 100%, uk 100%)
github-mike-fabian-issue#130

This new stable release includes these changes:

https://github.com/mike-fabian/ibus-table/releases/tag/1.16.14 github-mike-fabian-issue#130: Fix a problem in C/POSIX and invalid locales: Use lower() on LC_MESSAGES only if it is a string and not None

This new stable release includes these changes:

https://github.com/mike-fabian/ibus-table/releases/tag/1.16.13 Get program name of focused window also when ibus cannot get it Use focus id if available (it is available for ibus >= 1.5.27) github-mike-fabian-issue#129: Use IBus.PreeditFocusMode.COMMIT and make sure the input is cleared and the UI updated when the focus changes Do not reset input purpose on focus out github-mike-fabian-issue#128: Do not commit by index when OSK is visible

This new stable release includes these changes:

https://github.com/mike-fabian/ibus-table/releases/tag/1.16.12 github-mike-fabian-issue#120: Stop using locale.getdefaultlocale() because it is deprecated in Python 3.11 and will be removed in Python 3.13 Add 128x128, 256x256, and svg (remote) icons to ibus-table.appdata.xml

This new stable release includes these changes:

https://github.com/mike-fabian/ibus-table/releases/tag/1.16.11 github-mike-fabian-issue#118: Remove hashbang from chinese_variants.py and tabcreatedb.py

This new stable release includes these changes:

https://github.com/mike-fabian/ibus-table/releases/tag/1.16.10 Add png versions of the ibus-table.svg icon

This new stable release includes these changes:

https://github.com/mike-fabian/ibus-table/releases/tag/1.16.9 github-kaio-issue#79: Use a less exact type hint to make building tables from sources work with Python 3.8 as well Require Python >= 3.6 in configure.ac

This new stable release includes these changes:

https://github.com/mike-fabian/ibus-table/releases/tag/1.16.8 Update Unihan_Variants.txt from “2021-12-01 Unicode 15.0.0 draft” to “2022-04-26 Unicode 15.0.0 draft” and regenerate chinese_variants.py. All our fixes to Unihan_Variants.txt are included upstream. Because of the new Unihan_Variants.txt, the following 4 characters are added to the VARIANTS_TABLE in chinese_variants.py: u'囃': 2, u'戠': 3, u'臤': 3, u'鰛': 2. And because of the new Unihan_Variants.txt, the following character is removed from VARIANTS_TABLE in chinese_variants.py: u'𫝜': 2 1 = simplified Chinese, 2 = traditional Chinese, 3 = used both in simplified *and* traditional Chinese Update translations from Weblate (fa, fr updated)

This new stable release includes these changes:

https://github.com/mike-fabian/ibus-table/releases/tag/1.16.7 github-mike-fabian-issue#102: Ignore MOD3_MASK (Scroll Lock) when matching key bindings github-mike-fabian-issue#98: When a Modifier key release matches a hotkey command, return False not True.

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.16.4 github-mike-fabian-issue#100: Fix more errors in Unihan_Variants.txt by checking against a Traditional Chinese dictionary github-mike-fabian-issue#97: Fix some errors in Unihan_Variants.txt Update translations from Weblate (es updated to 100%)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.16.3 github-mike-fabian-issue#96: Fix a few errors in Unihan_Variants.txt github-mike-fabian-issue#95: 栗 U+6817 is used in Traditional Chinese as well. Update Unihan_Variants.txt from “2021-08-06 Unicode 14.0.0 final” to “2021-12-01 Unicode 1 5.0.0 draft” and regenerate engine/chinese_variants.py

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.16.0 Make true the default for rememberinputmode. github-mike-fabian-issue#85: Save “inputmode” to gsettings and add a “rememberinputmode” gsettings. This makes it possible to change the current input mode from the command line. And with “rememberinputmode” one can choose whether the last used input mode should be remembered and be used again when a new session starts or whether a new session should always start in table mode. Skip cangjie5 and erbi-qs test cases if the tables are too old Replace deprecated module “optparse” with “argparse” Update translations from Weblate (updates for ca, cs, de, uk)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.15.0 github-kaio-issue#77: Fix problems with goucima for erbi-qs table Update Unihan_Variants.txt to “2021-08-06 Unicode 14.0.0 final” and regenerate engine/chinese_variants.py Fix typo in translatable message, by Rafael Fontenelle

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.14.1 If an exception happens when trying to play a sound, catch it. I have no idea how to reproduce that bug. But catching the exception should fix it, it should make ibus-table continue working normally if any such serious problem with playing sounds occurs. Without sound of course but it should not stop working. When changing the error sound file with the setup tool, play it. To make the user hear immediately what kind of sound was selected. Remove colons after “Auto select:”, “Auto wildcard:”, and “Use dark theme:” Update translations from Weblate

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.14.0 github-mike-fabian-issue#70: Add option to choose whether to use DYNAMIC_ADJUST at runtime github-kaio-issue#75: Add options to play sound file on error Use checkbuttons instead of [Yes/No] comboboxes Hide options which make no sense for certain tables instead of just graying them out Update translations from Weblate (updates for ca, cs, de (100%), pt_BR, tr (100%), uk (100%), zh_CN)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.13.3 github-ibus-issue#2323: Fix a few more bugs in Unihan_Variants.txt, the characters 着枱云裡復采吓尸揾 are used both in simplified and traditional Chinese (some of them in traditional Chinese in Hong Kong only).

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.13.2 github-kaio-issue#74: Fix bug in Unihan_Variants.txt, 只 U+53EA is both simplified *and* traditional Chinese Update Chinese variant detection by Unihan_Variants.txt to the version “2021-05-18 Unicode 14.0.0” (draft version of Unicode 14) Update translations from Weblate (updates for es (100%), pt_BR (100%))

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.13.1 Make switch to pinyin mode also happen immediately even when the preedit is not empty (For consistency) Update translations from Weblate (updates for ca, fr)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.13.0 Make switch to pinyin mode also happen immediately even when the preedit is not empty (For consistency) Make rolling the mouse wheel in the candidate area of the lookup table work Commit English input and then switch into direct mode Apply a couple modes immediately when changed When change mode for Chinese_mode or onechar_mode, if the input is not empty, update the candidates with the new mode setting. Add a dark theme option Show all the tabkeys when using wildcards When wildcards were used, most likely the user would like to learn the exact tabkeys. Remove Python2 compatibility stuff (ibus-table doesn’t work with Python2 for a long time already) Start adding some type hints to improve code readability and to enable checking type related errors using mypy Update translations from Weblate (update for de, ja, tr, uk, zh_CN)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.12.6 In main.py “import factory” only when the --xml option is not used Make the keybindings treeview sortable by clicking the column headers Update translations from Weblate (update for pt_BR, now 100%)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.12.5 github-moebiuscurve-issue#21: Return False in _execute_command_commit_candidate_number(self, number) if number out of range. Was reported as an issue in ibus-table-others with the ipa-x-sampa table. But it is actually and ibus-table bug. When using a keybinding to commit a candidate with a certain number, ibus-table crashed when the number was out of range of the currently displayed lookup table. Update translations from Weblate (New translation for Sinhala (si) started)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.12.4 Update translations from Weblate (updated es, cs, fa, pt_BR, zh_CN). zh_CN is 100% complete now.

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.12.3 github-kaio-issue#64: Pass the key for the command 'cancel' (default Esc) through if the preedit is empty

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.12.2 Update translations from Weblate (updated ca, cs, es, fa, ja, pt_BR, pt_PT, tr, zh_CN, zh_HK, zh_TW)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.12.1 Enable compose support. Add buttons to move key bindings for a command up or down. Fix the code which resolves conflicts between SELECT_KEYS and VALID_INPUT_CHARS Make translations of 'Edit key bindings for command “%s”' work Added it_util.py to POTFILES, it had translatable strings for the “About” dialog and the key settings dialog. Update translations from Weblate (updated ca, de, fr, tr, uk)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.12.0 github-kaio-issue#57: New setup tool, now keybindings can be configured with a GUI. rhbz#1133127: The new setup tool also solves this bug, the hotkey for switching to direct input mode is also configurable now. github-kaio-issue#63: Put exact (except tone) pinyin matches next after exact matches in the candidate list. Allow lookup table orientation “System Default” in the setup Remove “spacekeybehavior” option. Now all keybindings are configurable. Therefore, the option to choose the behaviour of the space key makes no sense anymore. In the setup tool, there is now a new tab to configure all the keybindings, one can configure the behaviour of the space key there as well. Added a 'debuglevel' option Update translations from Weblate (updated ca, cs, de, es, fa, fr, ja, pt_BR, pt_PT, uk, zh_TW, zh_HK, zh_CN)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.11.0 github-ibus-issue#2241: Make key bindings configurable. Only via the command line for the moment, not yet easy to do for normal users. I have to rewrite the setup tool eventually to make that possible. This rewrite of the handling of the key bindings also fixes the problem reported in github-ibus-issue#2241 that the Shift_L key cannot switch between Chinese and English mode when using google-chrome.

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.10.1 Add GUI test Make output of ibus-table-createdb deterministic Update translations from Weblate (updated fr, tr, zh_CN)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.10.0 rhbz#835376: Add suggestion mode feature github-pull#9: Add suggestion mode feature Add test cases for suggestion mode feature Fix problems with the behaviour of the property menus Use python logging module with log file rotation instead of writing to stdout/stderr Update translations from Weblate (updated de, es, fr, pt_BR, pt_PT, tr, uk)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.25 github-mike-fabian-issue#26: Fix crash when changing some options using the menu or the floating panel Translation updates (pt_PT)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.24 Fixed two typos in message ids (Thanks to Rafael Fontenelle) Translation updates (tr, fr, fa, pt, uk) New test cases for ibus-table-others

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.23 rhbz#1786652: Add exist_ok=True in os.makedirs(path, exist_ok=True) to avoid failure due to race condition. Move MockEngine classes into a separate file and make test_itb.py runnable standalone Add new test case for ibus-table-others-1.3.10 (latex table additions) Translation updates for several languages (French at 100% now, Brazilian Portuguese at 100% now, Porguguese (Portugal) new and now at 31.5%)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.22 Added Turkish translation from Weblate, 100% translated Minor translation updates some other languages (Punctuation fixes).

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.21 Migrate IBusConfig to GSettings. Resolves: https://github.com/mike-fabian/ibus-table/issues/4 Add a test suite Add missing tags to ibus-table-createdb.sgml. Resolves: https://github.com/mike-fabian/ibus-table/issues/3

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.20 github-mike-fabian-issue#6: Draw InputMode text instead of icon into panel on non-Gnome desktops. Make it work with Python2 again

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.19 Sync phrases cache from/to external storage (thanks to heiher). Update translations from zanata (cs new)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.18 Update translations from zanata (pt_BR updated, es new) Don't query user database if user define phrase and dynamic adjust are disabled (thanks to heiher) Enable hash map based cache for user database enabled (thanks to heiher) Import hash map based cache for table database (thanks to heiher) Install appstream metadata to /usr/share/metainfo/ (thanks to jbicha) Fix some appdata validation issues (thanks to jbicha) Fix bug in Unihan_Variants.txt, 著 U+8457 is both simplified *and* traditional Chinese (thanks to heiher)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.17 Load .desktop file for ibus-setup-table correctly under Gnome Wayland Set WM_CLASS of ibus-setup-table correctly

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.16 Avoid running initialization code of ibus_table_location.py when using ibus-table-createdb. rhbz#1413580: Make it work on Python 3.6 (Unbreak sqlite on Python 3.6)

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.15 Update translations from zanata (ca, de, fr, uk updated) Improve README Point to new home-page in the “About” tab.

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.14 Fix bug in Unihan_Variants.txt, 乾 U+4E7E is both simplified and traditional Chinese (thanks to heiher) Update Unihan_Variants.txt from “2015-04-30 Unicode 8.0.0” to “2016-06-01 Unicode 9.0.0” Regenerate engine/chinese_variants.py Add test case for 乾 to make sure it is detected as both traditional and simplified Chinese

This new stable release includes these changes:

https://github.com/kaio/ibus-table/releases/tag/1.9.13 rhbz#1369514: When ignoring key release events, “False” should be returned, not “True”
ibus-table
ibus-table-1.17.11/po/000077500000000000000000000000001475513533100143365ustar00rootroot00000000000000ibus-table-1.17.11/po/.gitignore000066400000000000000000000003321475513533100163240ustar00rootroot00000000000000*.gmo Makefile Makefile.in Makefile.in.in Makevars.template POTFILES Rules-quot boldquot.sed en@boldquot.header en@quot.header insert-header.sin quot.sed remove-potcdate.sed remove-potcdate.sin stamp-po .zanata-cache/ ibus-table-1.17.11/po/LINGUAS000066400000000000000000000001111475513533100153540ustar00rootroot00000000000000ca cs de es fr ja pt_BR uk zh_CN zh_TW zh_HK tr pt_PT fa si ka ru el kab ibus-table-1.17.11/po/Makevars000066400000000000000000000035411475513533100160350ustar00rootroot00000000000000# 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 = -c --keyword=_ --keyword=N_ # 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 = Yu Yuwei # 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 = $(DOMAIN).pot-update: export GETTEXTDATADIR = $(top_srcdir) ibus-table-1.17.11/po/POTFILES.in000066400000000000000000000003241475513533100161120ustar00rootroot00000000000000engine/table.py engine/main.py engine/tabsqlitedb.py engine/tabcreatedb.py engine/factory.py engine/it_util.py org.freedesktop.ibus.engine.table.metainfo.xml.in setup/ibus-setup-table.desktop.in.in setup/main.py ibus-table-1.17.11/po/ca.po000066400000000000000000001045131475513533100152650ustar00rootroot00000000000000# Robert Antoni Buj Gelonch , 2015. #zanata # Mike FABIAN , 2016. #zanata, 2019, 2020, 2021. # Robert Antoni Buj Gelonch , 2016. #zanata # Adolfo Jayme Barrientos , 2020. # Anonymous , 2020. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2022-01-12 17:33+0000\n" "Last-Translator: Anonymous \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" "X-Generator: Weblate 4.10.1\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "Xinès simplificat" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "Commuta a «Només xinès simplificat»." #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "Xinès tradicional" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "Commuta a «Només xinès tradicional»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "Primer el xinès simplificat" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "Commuta a «Xinès simplificat abans del tradicional»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "Primer el xinès tradicional" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "Commuta a «Xinès tradicional abans del simplificat»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "Tots els caràcters del xinès" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "Commuta a «Tots els caràcters del xinès»." #: engine/table.py:735 msgid "Chinese mode" msgstr "Mode xinès" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "Commuta el mode xinès" #: engine/table.py:747 msgid "English" msgstr "Anglès" #: engine/table.py:748 msgid "Switch to English input" msgstr "Commuta a entrada en anglès" #: engine/table.py:755 msgid "Chinese" msgstr "Xinès" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "Commuta a entrada en xinès" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "Directe" #: engine/table.py:765 msgid "Switch to direct input" msgstr "Commuta a entrada directa" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "Taula" #: engine/table.py:771 msgid "Switch to table input" msgstr "Commuta a l'entrada per taula" #: engine/table.py:779 msgid "Input mode" msgstr "Mode d'entrada" #: engine/table.py:780 msgid "Switch Input mode" msgstr "Commuta el mode d'entrada" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "Mitjana" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "Commuta a l'amplada mitjana de lletres" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "Completa" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "Commuta a l'amplada completa de lletres" #: engine/table.py:801 msgid "Letter width" msgstr "Amplada de la lletra" #: engine/table.py:802 msgid "Switch letter width" msgstr "Commuta l'amplada de la lletra" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "Commuta a l'amplada mitjana de la puntuació" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "Commuta a l'amplada completa de la puntuació" #: engine/table.py:823 msgid "Punctuation width" msgstr "Amplada de la puntuació" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "Commuta l'amplada de la puntuació" #: engine/table.py:835 msgid "Switch to table mode" msgstr "Commuta al mode de taula" #: engine/table.py:840 msgid "Pinyin" msgstr "Pinyin" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "Commuta al mode pinyin" #: engine/table.py:845 msgid "Pinyin mode" msgstr "Mode pinyin" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "Commuta el mode pinyin" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "Suggeriment desactivat" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "Commuta al mode de suggeriments" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "Suggeriment activat" #: engine/table.py:867 msgid "Suggestion mode" msgstr "Mode de suggeriments" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "Commuta el mode de suggeriments" #: engine/table.py:878 msgid "Multiple character match" msgstr "Coincidència de caràcters múltiples" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "Commuta a fer coincidir múltiples caràcters alhora" #: engine/table.py:885 msgid "Single character match" msgstr "Coincidència de caràcter individual" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "Commuta a fer coincidir tan sols caràcters individuals" #: engine/table.py:891 msgid "Onechar mode" msgstr "Mode d'un caràcter" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "Commuta el mode d'un caràcter" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "Normal" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" "Commuta al mode normal de consignació (les consignacions automàtiques van a " "la preedició en lloc de l'aplicació. Això permet la definició automàtica de " "noves dreceres)" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" "Commuta al mode directe de consignació (les consignacions automàtiques va " "directament a l'aplicació)" #: engine/table.py:919 msgid "Auto commit mode" msgstr "Mode automàtic de consignació" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "Commuta el mode automàtic de consignació" #: engine/table.py:2946 msgid "Setup" msgstr "Ajusta" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "Configura l'ibus-table “%(engine-name)s”" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "Entrada de tecles" #: engine/it_util.py:943 msgid "Cancel" msgstr "Cancel·la" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "Premeu una tecla (o una combinació de tecles)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "El diàleg es tancarà quan es deixi anar la tecla" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "Mètode d'entrada de taula per a l'IBus" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "" "Josep Puigdemont Casamajó , 2006\n" "Xavier Conde Rueda , 2006\n" "Josep Torné Llavall ,2009\n" "Albert Carabasa Giribet , 2009" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "Documentació en línia:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "Ibus Table" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "Mètode d'entrada de taula per a l'IBus" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" "Ibus-table és un marc de treball de mètode d'entrada per als mètodes " "d'entrada basats en taules. Sobretot s'utilitza per als mètodes d'entrada " "xinesos com ara ZhengMa, WuBi, ErBi, CangJie, …. No obstant això, també hi " "ha disponible algunes taules per a altres idiomes." #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "Preferències" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 #, fuzzy #| msgid "Inital state" msgid "Initial state" msgstr "Estat inicial" #: setup/main.py:115 msgid "Direct input" msgstr "Entrada directa" #: setup/main.py:116 msgid "Table input" msgstr "Entrada de taula" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Preferències" #: setup/main.py:212 msgid "About" msgstr "Quant a" #: setup/main.py:220 msgid "Restore all defaults" msgstr "Restableix-ho tot al predeterminat" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "Tan_ca" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Ajustos" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Detalls" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "Vinculació de tecles" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "Recorda el mode d’entrada" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 #, fuzzy #| msgid "" #| "“Direct input” is almost the same as if the\n" #| "input method were off, i.e. not used at all, most\n" #| "characters just get passed to the application.\n" #| "But some conversion between fullwidth and\n" #| "halfwidth may still happen in direct input mode.\n" #| "“Table input” means the input method is on." msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" "“Entrada directa” és gairebé el mateix que si el\n" "mètode d'entrada estigués apagat, és a dir, no\n" "s'utilitza en absolut, la majoria dels caràcters\n" "simplement es passen a l'aplicació. Però en el\n" "mode directe d'entrada encara es poden\n" "produir algunes conversions entre l'amplada\n" "completa i la mitjana. “Entrada de taula” significa\n" "que el mètode d'entrada està engegat." #: setup/main.py:323 msgid "No" msgstr "No" #: setup/main.py:325 msgid "Yes" msgstr "Sí" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "Mode xinès:" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" "“Xinès simplificat” mostra tan sols els caràcters\n" "utilitzats en el xinès simplificat. “Xinès tradicional”\n" "mostra tan sols els caràcters en el xinès tradicional.\n" "“Xinès tradicional abans del simplifica” mostra trots\n" "tots els caràcters però fica els caràcters simplificats\n" "més amunt en la llista de candidats. “Xinès tradicional\n" "abans del simplificat” fica els caràcters simplificats\n" "més amunt en la llista de candidats. “Tots els caràcters”\n" "només mostra totes les coincidències sense cap filtre\n" "en particular sobre el xinès tradicional o el simplificat." #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "Xinès simplificat abans del tradicional" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "Xinès tradicional abans del simplificat" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "Amplada de la lletra de l'entrada de taula:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" "Si utilitzar l'amplada total o mitjana de les\n" "lletres en el mode d'entrada de taula." #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "Amplada de la puntuació de l'entrada de taula:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" "Si utilitzar l'amplada total o mitjana de la\n" "puntuació en el mode d'entrada de taula." #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "Amplada de la lletra de l'entrada directa:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" "Si utilitzar l'amplada total o mitjana de les\n" "lletres en el mode directe d'entrada." #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "Amplada de la puntuació de l'entrada directa:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" "Si utilitzar l'amplada total o mitjana de la\n" "puntuació en el mode directe d'entrada." #: setup/main.py:590 #, fuzzy #| msgid "Candidate list" msgid "Candidate list" msgstr "Llista de candidats" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "Mostra la llista de candidats" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" "Si les llistes de candidats s'han de mostrar o ocultar.\n" "Per als mètodes d'entrada xinesos en general es vol\n" "mostrar les llistes de candidats. Però per alguns\n" "mètodes d'entrada no xinesos com el rus “translit”,\n" "el millor és ocultar les llistes de candidats." #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "Orientació:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" "Si la taula de consulta que mostra els candidats\n" "ha de ser vertical o horitzontal." #: setup/main.py:640 msgid "Horizontal" msgstr "Horitzontal" #: setup/main.py:642 msgid "Vertical" msgstr "Vertical" #: setup/main.py:644 msgid "System default" msgstr "Valor per defecte de sistema" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Mida de la pàgina:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" "El nombre màxim de candidats en una pàgina de\n" "la taula de consulta. Podeu commutar la pàgina en\n" "la taula de consulta utilitzant les tecles de pàgina\n" "cap amunt/avall o la fletxa cap amunt/avall." #: setup/main.py:696 msgid "Current key bindings:" msgstr "Assignacions de tecles actuals:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Ordre" #: setup/main.py:752 msgid "Edit" msgstr "Edita" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "Edita la drecera de teclat de l’ordre seleccionada" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "Defineix com a per defecte" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "Estableix les dreceres per defecte de l’ordre seleccionada" #: setup/main.py:778 msgid "Set all to default" msgstr "Estableix-les totes als valors per defecte" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "Suprimeix les dades que s’han après" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "Compon:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" "Si s'estableix a «caràcter individual», apareixeran\n" "només els candidats d'un sol caràcter. Si s'estableix\n" "a «frase», es poden mostrar els candidats que consten\n" "de diversos caràcters." #: setup/main.py:862 msgid "Phrase" msgstr "Frase" #: setup/main.py:864 msgid "Single Char" msgstr "Caràcter individual" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "Autoselecciona" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" "Si s'estableix a «Sí», això fa les 4 coses següents:\n" "1) En escriure «Retorn», consigna el \n" " candidat + avanç de línia\n" "2) En escriure Tabulador, consigna el candidat\n" "3) En consignar mitjançant una tecla de consignació,\n" " consigna el candidat + « »\n" "4) Si en escriure el següent caràcter no coincideix amb\n" " cap candidat es consigna el primer candidat de\n" " l'anterior coincidència. (Majorment necessari per \n" " mètodes d'entrada no xinesos com el rus «translit»)" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "Mode automàtic de consignació:" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" "Consignar amb les tecles de consignació o amb el\n" "ratolí sempre consigna a l'aplicació. Aquesta opció és\n" "sobre les consignacions “automàtiques” que poden\n" "ocórrer quan un només continua escrivint l'entrada\n" "sense la consignació manual. De tant en tant, les\n" "consignacions “automàtiques” es produiran.\n" "“Directe” significa que com en la consignació\n" "“automàtica” les consignacions van directament a\n" "l'aplicació, “Normal” significa que s'envien en la preedició." #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "Comodí automàtic" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" "Si és així, un comodí múltiple s'afegirà\n" "automàticament al final de la cadena d'entrada." #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "Comodí de caràcter individual:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "El comodí per cercar qualsevol caràcter individual.\n" "Teclegeu RETORN per a confirmar després de canviar el comodí." #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "Caràcter de comodí múltiple:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "El comodí utilitzat per cercar qualsevol nombre de caràcters.\n" "Teclegeu RETORN per a confirmar després de canviar el comodí." #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "Nivell de depuració:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" #: setup/main.py:1529 msgid "Are you sure?" msgstr "N'esteu segur?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_Cancel·la" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "D'ac_ord" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "Ja s'està executant una altra instància d'aquesta aplicació." #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "Seleccioneu un fitxer de so .wav:" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 #, fuzzy #| msgid "Key bindings" msgid "Move key binding up" msgstr "Vinculació de tecles" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 #, fuzzy #| msgid "Key bindings" msgid "Move key binding down" msgstr "Vinculació de tecles" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" #: setup/main.py:3037 msgid "ibus is not running." msgstr "L'ibus no s'està executant." #~ msgid "IBUS_ENGINE_NAME environment variable is not set." #~ msgstr "No està establerta la variable d'entorn IBUS_ENGINE_NAME." #~ msgid "" #~ "Cannot determine the engine name. Please use the --engine-name option." #~ msgstr "" #~ "No es pot determinar el nom del motor. Si us plau, utilitzeu l'opció --" #~ "engine-name." #~ msgid "IBus Table engine %s is not available" #~ msgstr "El motor de la taula d'IBus %s no està disponible" #~ msgid "Next Page" #~ msgstr "Pàgina següent" #~ msgid "Restore defaults as specified in the database for this engine." #~ msgstr "" #~ "Restaura els valors predeterminats com s'especifica a la base de dades " #~ "per a aquest motor." #~ msgid "Input mode:" #~ msgstr "Mode d'entrada:" #~ msgid "" #~ "If you choose the space key to do “Next page”,\n" #~ " you can only commit using the selection keys\n" #~ "(i.e. the labels in front of the candidates in the\n" #~ "lookup table) or using the mouse." #~ msgstr "" #~ "Si trieu la tecla d'espai per fer “Pàgina següent”,\n" #~ "tan sols podeu consignar mitjançant les tecles de\n" #~ "selecció (p. ex. les etiquetes davant dels candidats\n" #~ "en la taula de consulta) o mitjançant el ratolí." #~ msgid "Behavior of space key:" #~ msgstr "Comportament de la tecla espaiadora:" #~ msgid "Details" #~ msgstr "Detalls" #~ msgid "" #~ "\n" #~ "Authors:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contributors:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgstr "" #~ "\n" #~ "Autors:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contribuïdors:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgid "Mike FABIAN" #~ msgstr "Mike FABIAN" ibus-table-1.17.11/po/cs.po000066400000000000000000000701661475513533100153150ustar00rootroot00000000000000# Zdenek , 2017. #zanata # Anonymous , 2019, 2020. # Mike FABIAN , 2019. # Weblate Translation Memory , 2024. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2024-06-26 15:36+0000\n" "Last-Translator: Weblate Translation Memory \n" "Language-Team: Czech \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Generator: Weblate 5.5.5\n" # auto translated by TM merge from project: System Administrator's Guide, version: master, DocId: Colophon #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "Zjednodušená čínština" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "" # auto translated by TM merge from project: System Administrator's Guide, version: master, DocId: Colophon #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "Tradiční čínština" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "Přepnout do módu tradiční čínštiny" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "" #: engine/table.py:735 msgid "Chinese mode" msgstr "" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "Přepnout do čínského módu" # auto translated by TM merge from project: ibus-libpinyin, version: master, DocId: ibus-libpinyin #: engine/table.py:747 msgid "English" msgstr "Angličtina" #: engine/table.py:748 msgid "Switch to English input" msgstr "" # auto translated by TM merge from project: ibus-libpinyin, version: master, DocId: ibus-libpinyin #: engine/table.py:755 msgid "Chinese" msgstr "Čínština" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "Přímé" #: engine/table.py:765 msgid "Switch to direct input" msgstr "" # auto translated by TM merge from project: system-config-firewall, version: master, DocId: po/system-config-firewall #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "Tabulka" #: engine/table.py:771 msgid "Switch to table input" msgstr "" #: engine/table.py:779 msgid "Input mode" msgstr "Metoda vstupu" #: engine/table.py:780 msgid "Switch Input mode" msgstr "" # auto translated by TM merge from project: ibus-libpinyin, version: master, DocId: ibus-libpinyin #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "Poloviční" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "" # auto translated by TM merge from project: ibus-libpinyin, version: master, DocId: ibus-libpinyin #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "Plná" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "" #: engine/table.py:801 msgid "Letter width" msgstr "" #: engine/table.py:802 msgid "Switch letter width" msgstr "" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "" #: engine/table.py:823 msgid "Punctuation width" msgstr "" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "" #: engine/table.py:835 msgid "Switch to table mode" msgstr "" #: engine/table.py:840 msgid "Pinyin" msgstr "" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "" # auto translated by TM merge from project: ibus-libpinyin, version: master, DocId: ibus-libpinyin #: engine/table.py:845 msgid "Pinyin mode" msgstr "Mód pinyinu" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "" #: engine/table.py:867 msgid "Suggestion mode" msgstr "" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "" #: engine/table.py:878 msgid "Multiple character match" msgstr "" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "" #: engine/table.py:885 msgid "Single character match" msgstr "" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "" #: engine/table.py:891 msgid "Onechar mode" msgstr "" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "" # auto translated by TM merge from project: Entangle, version: master, DocId: entangle #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "Původní" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" #: engine/table.py:919 msgid "Auto commit mode" msgstr "" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "" # auto translated by TM merge from project: tvtime, version: 1.0.7, DocId: tvtime #: engine/table.py:2946 msgid "Setup" msgstr "Nastavení" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "Vstup klávesy" #: engine/it_util.py:943 msgid "Cancel" msgstr "Zrušit" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "Stiskněte prosím klávesu (či kombinaci kláves)." #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "Po uvolnění klávesy bude dialog zavřen" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "Kredit-překladatelům" # auto translated by TM merge from project: system-config-printer, version: master, DocId: system-config-printer #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "Dokumentace na Internetu:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "Předvolby" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "" #: setup/main.py:115 msgid "Direct input" msgstr "" #: setup/main.py:116 msgid "Table input" msgstr "" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Předvolby" #: setup/main.py:212 msgid "About" msgstr "O aplikaci" #: setup/main.py:220 msgid "Restore all defaults" msgstr "Obnovit vše na výchozí" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "Z_avřít" # auto translated by TM merge from project: FreeIPA, version: ipa-4-5, DocId: po/ipa #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Nastavení" # auto translated by TM merge from project: Cockpit, version: rhel-7.4, DocId: cockpit #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Podrobnosti" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "Navázání na klávesy" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "Zapamatovat si metodu vstupu" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" #: setup/main.py:323 msgid "No" msgstr "Ne" # auto translated by TM merge from project: Cockpit, version: rhel-7.4, DocId: cockpit #: setup/main.py:325 msgid "Yes" msgstr "Ano" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" #: setup/main.py:590 msgid "Candidate list" msgstr "" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" # auto translated by TM merge from project: system-config-printer, version: master, DocId: system-config-printer #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "Orientace:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" # auto translated by TM merge from project: ibus-libpinyin, version: master, DocId: ibus-libpinyin #: setup/main.py:640 msgid "Horizontal" msgstr "Vodorovně" # auto translated by TM merge from project: ibus-libpinyin, version: master, DocId: ibus-libpinyin #: setup/main.py:642 msgid "Vertical" msgstr "Svisle" #: setup/main.py:644 msgid "System default" msgstr "Systémové výchozí" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Velikost stránky:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" #: setup/main.py:696 msgid "Current key bindings:" msgstr "Stávající navázání kláves:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Příkaz" #: setup/main.py:752 msgid "Edit" msgstr "Upravit" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "Upravit navázání kláves pro označený příkaz" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "Nastavit na výchozí" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "Nastavit výchozí navázání na klávesy pro označený příkaz" #: setup/main.py:778 msgid "Set all to default" msgstr "Nastavit vše na výchozí" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "Nastavit výchozí navázání na klávesy pro všechny příkazy" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "Smazat naučená data" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" #: setup/main.py:862 msgid "Phrase" msgstr "" #: setup/main.py:864 msgid "Single Char" msgstr "" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "Automatický výběr" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "Přehrát zvukový soubor při chybě" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" "Zde můžete zvolit, zda se v případě chyby přehraje zvukový soubor. Pokud " "není nainstalován modul simpleaudio pro Python3, tato volba nedělá nic." #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "Úroveň podrobnosti ladících údajů:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" "Když je vyšší než nula, mohou být souboru se záznamem událostí vypisovány " "ladící informace a být také zobrazovány graficky." #: setup/main.py:1529 msgid "Are you sure?" msgstr "Opravdu?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_Zrušit" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "_OK" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "Už je spuštěná jiná instance této aplikace." #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "Opravdu chcete obnovit všechna výchozí nastavení?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "Vyberte zvukový soubor .wav:" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "Upravit navázání kláves pro příkaz „%s“" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "Přidat navázání klávesy" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "Odebrat označené navázání klávesy" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 #, fuzzy #| msgid "Add a key binding" msgid "Move key binding up" msgstr "Přidat navázání klávesy" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 #, fuzzy #| msgid "Add a key binding" msgid "Move key binding down" msgstr "Přidat navázání klávesy" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" "Opravdu chcete nastavit navázání kláves pro všechny příkazy na výchozí " "hodnoty?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "ibus není spuštěné." #~ msgid "Input mode:" #~ msgstr "Metoda vstupu:" ibus-table-1.17.11/po/de.po000066400000000000000000001102021475513533100152620ustar00rootroot00000000000000# IBus-Table Translation file: de.po # Copyright (C) 2012 Mike FABIAN # This file is distributed under the same license as the ibus-table package. # Mike FABIAN , 2012, 2019, 2020, 2021, 2022, 2023, 2025. # Mike FABIAN , 2016. #zanata, 2019, 2020, 2021, 2022, 2023, 2025. # Mike FABIAN , 2017. #zanata, 2019, 2020, 2021, 2022, 2023, 2025. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2025-01-19 01:44+0000\n" "Last-Translator: Mike FABIAN \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" "X-Generator: Weblate 5.9.2\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "Vereinfachtes Chinesisch" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "Wechseln zu “Vereinfachtes Chinesisch”." #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "Traditionelles Chinesisch" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "Wechseln zu “Traditionelles Chinesisch”." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "Vereinfachtes Chinesisch zuerst" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "Wechseln zu “Vereinfachtes Chinesisch vor traditionellem”." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "Traditionelles Chinesisch zuerst" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "Wechseln zu “Traditionelles Chinesisch vor vereinfachtem”." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "Alle chinesischen Zeichen" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "Wechseln zu “Alle chinesischen Zeichen”." #: engine/table.py:735 msgid "Chinese mode" msgstr "Chinesischer Modus" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "Chinesischen Modus ändern" #: engine/table.py:747 msgid "English" msgstr "Englisch" #: engine/table.py:748 msgid "Switch to English input" msgstr "Wechseln zur Eingabe von Englisch" #: engine/table.py:755 msgid "Chinese" msgstr "Chinesisch" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "Wechseln zur Eingabe von Chinesisch" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "Direkt" #: engine/table.py:765 msgid "Switch to direct input" msgstr "Wechseln zum “Direkteingabe Modus”" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "Tabelleneingabe" #: engine/table.py:771 msgid "Switch to table input" msgstr "Wechseln zum Tabelleneingabemodus" #: engine/table.py:779 msgid "Input mode" msgstr "Eingabemodus" #: engine/table.py:780 msgid "Switch Input mode" msgstr "Eingabemodus ändern" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "Halbe Breite" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "Wechseln zu “Buchstaben in halber Breite”" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "Volle Breite" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "Wechseln zu “Buchstaben in voller Breite”" #: engine/table.py:801 msgid "Letter width" msgstr "Buchstabenbreite" #: engine/table.py:802 msgid "Switch letter width" msgstr "Buchstabenbreite ändern" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "Wechseln zu “Zeichensetzung in halber Breite”" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "Wechseln zu “Zeichensetzung in voller Breite”" #: engine/table.py:823 msgid "Punctuation width" msgstr "Zeichensetzungsbreite" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "Zeichensetzungsbreite ändern" #: engine/table.py:835 msgid "Switch to table mode" msgstr "Zum “Tabellen Modus” wechseln" #: engine/table.py:840 msgid "Pinyin" msgstr "Pinyin" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "Zum “Pinyin Modus” Modus wechseln" #: engine/table.py:845 msgid "Pinyin mode" msgstr "Pinyin Modus" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "Pinyinmodus ändern" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "Vorschläge deaktiviert" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "Zum „Vorschlagsmodus“ wechseln" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "Vorschläge aktiviert" #: engine/table.py:867 msgid "Suggestion mode" msgstr "Vorschlagsmodus" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "Vorschlagsmodus ändern" #: engine/table.py:878 msgid "Multiple character match" msgstr "Mehrere Zeichen auf einmal" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "Zur Eingabe mehrerer Zeichen auf einmal wechseln" #: engine/table.py:885 msgid "Single character match" msgstr "Nur einzelne Zeichen" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "Zur Eingabe einzelner Zeichen wechseln" #: engine/table.py:891 msgid "Onechar mode" msgstr "Einzelzeichenmodus" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "Einzelzeichenmodus ändern" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "Normal" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" "Wechseln zum normalen Commitmodus (automatische Commits gehen in das Preedit " "anstatt in die Applikation. Das ermöglicht automatische Definitionen neuer " "Kürzel)" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" "Wechseln zum direkten Commitmodus (automatische Commits gehen direkt in die " "Applikation)" #: engine/table.py:919 msgid "Auto commit mode" msgstr "Autocommitmodus" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "Autocommitmodus ändern" #: engine/table.py:2946 msgid "Setup" msgstr "Einstellungen" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "Konfiguration von ibus-table “%(engine-name)s”" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "Tasteneingabe" #: engine/it_util.py:943 msgid "Cancel" msgstr "Abbrechen" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "Bitte drücken Sie eine Taste (oder eine Tastenkombination)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "Dieser Dialog wird geschlossen sobald die Taste losgelassen wird" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "Tabellenbasierte Eingabemethode für IBus." #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "Mike FABIAN , 2018-2020" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "Online Dokumentation:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "Ibus Table" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "Tabellenbasierte Eingabemethode" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" "Ibus-table ist eine Inputsystem für tabellenbasierte Inputmethoden. Es wird " "hauptsächlich für chinesiche Inputmethoden wie ZhengMa, WuBi, ErBi, CangJie " "usw. benutzt. Aber es gibt auch einige Tabellen für andere Sprachen." #: setup/ibus-setup-table.desktop.in.in:3 msgid "IBus Table Preferences" msgstr "Einstellungen für IBus Table" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "IBus Table -Optionen festlegen" #: setup/main.py:114 msgid "Initial state" msgstr "Zustand beim Start" #: setup/main.py:115 msgid "Direct input" msgstr "Direkteingabemodus" #: setup/main.py:116 msgid "Table input" msgstr "Tabelleneingabemodus" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Einstellungen" #: setup/main.py:212 msgid "About" msgstr "Info über IBus Table" #: setup/main.py:220 msgid "Restore all defaults" msgstr "Alles auf Standardeinstellungen zurücksetzen" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "S_chließen" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Einstellungen" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Details" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "Tastenbelegungen" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "Merken des zuletzt benutzten Eingabemodes" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" "Ob der zuletzt genutzte Eingabemodus gemerkt werden soll, oder ob ibus-table " "nach einem Neustart immer im “Tabelleneingabemodus” starten soll. " "“Tabelleneingabemodus” bedeutet, daß die Eingabemethode aktiv ist. " "“Direkteingabemodus” ist beinahe dasselbe als ob die Eingabemethode " "überhaupt nicht verwendet würde, die meisten Zeichen werden einfach an die " "Applikation durchgereicht. Aber auch im Direkteingabemodus werden Zeichen in " "voller Breite eventuell in Zeichen in halber Breite konvertiert oder " "umgekehrt." #: setup/main.py:323 msgid "No" msgstr "Nein" #: setup/main.py:325 msgid "Yes" msgstr "Ja" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "Chinesischer Modus:" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" "“Vereinfachtes Chinesisch” zeigt nur Zeichen, die in\n" "vereinfachtem Chinesisch benutzt werden. “Traditionelles\n" "Chinesisch” zeigt nur Zeichen, die in traditionellem\n" "Chinesisch benutzt werden. “Vereinfachtes Chinesisch zuerst”\n" "zeigt die vereinfachten Zeichen höher oben in der\n" "Kandidatenliste. “Traditionelles Chinesisch zuerst” zeigt\n" "die traditionellen Zeichen höher in der Kandidatenliste.\n" "“Alle chinesischen Zeichen” zeigt alle Kandidaten ohne\n" "daß die Reihenfolge irgendwie gefiltert wird." #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "Vereinfachtes Chinesisch vor traditionellem" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "Traditionelles Chinesisch vor vereinfachtem" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "Buchstabenbreite im Tabelleneingabemodus:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" "Ob Buchstaben in voller oder halber\n" "Breite im Tabelleneingabemodus benutzt werden\n" "sollen." #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "Zeichensetzungsbreite im Tabelleneingabemodus:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" "Ob Zeichensetzung in voller oder halber\n" "Breite im Tabelleneingabemodus benutzt\n" "werden soll." #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "Buchstabenbreite im Direkteingabemodus:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" "Ob Buchstaben in voller oder halber\n" "Breite im Direkteingabemodus benutzt werden\n" "sollen." #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "Zeichensetzungsbreite im Direkteingabemodus:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" "Ob Zeichensetzung in voller oder halber\n" "Breite im Direkteingabemodus benutzt\n" "werden soll." #: setup/main.py:590 msgid "Candidate list" msgstr "Kandidatenliste" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "Kandidatenliste zeigen" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" "Ob Kandidatenlisten gezeigt werden sollen oder nicht.\n" "Für chinesische Inputmethoden will man Kandidatenlisten\n" "normalerweise sehen. Aber für einige nicht-chinesische\n" "Inputmethode, wie zum Beispiel die russische Inputmethode\n" "“translit” ist es besser die Kandidatenlisten zu\n" "verstecken." #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "Orientierung:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" "Ob die Kandidatenliste horizontal oder\n" "vertikal angezeigt werden soll." #: setup/main.py:640 msgid "Horizontal" msgstr "Horizontal" #: setup/main.py:642 msgid "Vertical" msgstr "Vertikal" #: setup/main.py:644 msgid "System default" msgstr "Standardeinstellung" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Kandidaten pro Seite:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" "Die maximale Anzahl an Kandidaten in einer\n" "Seite der Kandidatenliste. Man kann in der\n" "Kandidatenliste mit den Seite hoch/runter oder\n" "den Pfeil hoch/runter Tasten blättern." #: setup/main.py:696 msgid "Current key bindings:" msgstr "Aktuelle Tastenbelegungen:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Befehl" #: setup/main.py:752 msgid "Edit" msgstr "Editieren" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "Editieren der Tastenbelegungen für den ausgewählten Befehl" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "Auf Standard setzen" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "" "Zurücksetzen der Tastenbelegungen für den ausgewählten Befehl auf die " "Voreinstellung" #: setup/main.py:778 msgid "Set all to default" msgstr "Alle auf Standard setzen" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "" "Zurücksetzen der Tastenbelegungen für alle Befehle auf die Voreinstellung" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "Dynamische Anpassung" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" "Hier kann man wählen ob die Reihenfolge der Kandidaten dynamisch angepasst " "wird, basierend darauf wie häufig Kandidaten benutzt werden." #: setup/main.py:824 msgid "Delete all learned data" msgstr "Gelernte Daten löschen" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "Komposition:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" "Wenn dies auf “Einzelzeichenmodus” gesetzt wird,\n" "werden nur Kandidaten gezeigt, die nur aus einem\n" "einzigen Zeichen bestehen. Wenn dies auf\n" "“Satz- bzw. Wortmodus” gesetzt wird, können auch\n" "längere Kandidaten angezeigt werden, ganze Wörter\n" "oder gar Sätze." #: setup/main.py:862 msgid "Phrase" msgstr "Satzmodus" #: setup/main.py:864 msgid "Single Char" msgstr "Einzelzeichenmodus" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "Automatische Auswahl" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" "Wenn diese Option auf “Ja” gesetzt ist, werden die\n" "folgenden 4 Dinge gemacht, bei “Nein” nicht:\n" "1) Beim tippen der “Return”-Taste wird der Kandidat\n" " und ein Zeilenumbruch committed.\n" "2) Beim tippen der “Tab”-wird der Kandidat committed.\n" "3) Beim Committen mittels einer “Commit-Taste” (meist\n" " Leertaste) wird der Kandidat gefolgt von “ ” committed.\n" "4) Wenn das Tippen eines weiteren Zeichens dazu führt,\n" " daß es keine Kandidaten mehr gibt, wird der erste\n" " Kandidat der Kandidatenliste vor dem Tippen diese\n" " Zeichens committed (Hauptsächlich nützlich für\n" " nicht-chinesische Eingabemethoden, zum Beispiel die\n" " Russische Eingabemethode “translit”)" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "Autocommitmodus:" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" "Wenn man manuell mittels Commit-Tasten oder mit der\n" "Maus committed, geht der Text immer direkt in die\n" "Applikation. In dieser Option geht es um\n" "“automatische” Commits, die ab und zu vorkommen wenn\n" "man einfach immer weiter tippt ohne manuell zu\n" "committen.\n" "“Direkt” bedeutet, daß solche “automatischen” Commits\n" "direkt in die Applikation committed werden, “Normal”\n" "bedeutet, daß sie zunächst nur ins “Preedit” committed\n" "werden, wo sie weiter editiert werden können und später\n" "manuell committed." #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "Aktion bei der Eingabe ungültiger Zeichen:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" "Legt fest, was passiert, wenn ein Zeichen eingegeben wird, das nicht im Satz " "der gültigen Eingabezeichen für diese Tabelle enthalten ist: Bei Auswahl von " "„Aktuellen Kandidaten übernehmen“ wird der aktuell ausgewählte Kandidat " "eingefügt. Bei Auswahl von „Eingegebene Tasten übernehmen“ werden die bisher " "während des Kandidatenauswahlprozesses eingegebenen Zeichen anstelle des " "ausgewählten Kandidaten eingefügt. In allen Fällen endet die " "Kandidatenauswahl, wenn ein ungültiges Zeichen eingegeben wird und das " "betreffende Zeichen unmittelbar nach dem Text eingefügt wird, der aus den " "oben genannten Optionen resultiert." #: setup/main.py:983 msgid "Commit current candidate" msgstr "Aktuellen Kandidaten übernehmen" #: setup/main.py:985 msgid "Commit typed keys" msgstr "Eingegebene Tasten übernehmen" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "Automatischer Platzhalter" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" "Wenn diese Option auf “ja” gesetzt ist wird\n" "automatich ein Platzhalter für beliebig viele\n" "Zeichen ans Ende des Eingabetextes angehängt." #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "Platzhalter für ein Zeichen:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "Das Platzhalterzeichen für ein beliebiges einzelnes\n" "Zeichen. Nach Ändern dieser Option mit RETURN oder ENTER bestätigen." #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "Platzhalter für beliebig viele Zeichen:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "Das Platzhalterzeichen für beliebig viele Zeichen.\n" "Nach Ändern dieser Option mit RETURN oder ENTER bestätigen." #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "Dunkles Theme benutzen" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "Wenn ja werden Farben passend für ein dunkles Theme benutzt." #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "Sounddatei bei Fehler abspielen" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" "Hier kann man wählen, ob eine Sounddatei abgespielt wird, wenn ein Fehler " "passiert. Wenn das simpleaudio-Modul für Python3 nicht installiert ist, tut " "diese Option nichts." #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "Debug-Level:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" "Wenn dieser Wert größer als 0 ist, wird vielleicht Debug-Information in die " "Log-Datei ausgegeben und vielleicht wird auch Debug-Information graphisch " "angezeigt." #: setup/main.py:1529 msgid "Are you sure?" msgstr "Sind Sie sicher?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_Abbrechen" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "_OK" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "Eine Instanz dieses Programms läuft schon." #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "Wollen Sie wirklich alles auf die Voreinstellungen zurücksetzen?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" "Wollen Sie wirklich alle Daten, die beim Tippen und Kandidaten selektieren " "gelernt wurden, auf die Voreinstellungen zurücksetzen?" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr ".wav Sounddatei auswählen:" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "Editieren der Tastenbelegungen für den Befehl „%s“" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "Tastenbelegung hinzufügen" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "Ausgewählte Tastenbelegung entfernen" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "Tastenbelegung aufwärts schieben" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "Tastenbelegung abwärts schieben" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" "Wollen Sie wirklich die Tastenbelegungen für alle Befehle auf die " "Voreinstellungen zurücksetzen?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "Ibus läuft nicht." #~ msgid "IBUS_ENGINE_NAME environment variable is not set." #~ msgstr "Die Umgebungsvariable IBUS_ENGINE_NAME ist nicht gesetzt." #~ msgid "" #~ "Cannot determine the engine name. Please use the --engine-name option." #~ msgstr "" #~ "Der Name für diesen Input-Engine kann nicht gefunden werden. Bitte " #~ "benutzen Sie die --engine-name Option." #~ msgid "IBus Table engine %s is not available" #~ msgstr "IBus Table Engine %s ist nicht verfügbar" #~ msgid "Next Page" #~ msgstr "Nächste Seite" #~ msgid "Restore defaults as specified in the database for this engine." #~ msgstr "" #~ "Auf Standardeinstellungen zurücksetzen, so\n" #~ "wie sie in der Datenbank für diesen Inputengine\n" #~ "definiert sind." #~ msgid "Input mode:" #~ msgstr "Eingabemodus:" #~ msgid "" #~ "If you choose the space key to do “Next page”,\n" #~ " you can only commit using the selection keys\n" #~ "(i.e. the labels in front of the candidates in the\n" #~ "lookup table) or using the mouse." #~ msgstr "" #~ "Wenn man die Leertaste benutzt um zur nächsten Seite\n" #~ "in der Kandidatenliste zu blättern, kann man nur noch\n" #~ "mit den Auswahltasten (d.h. die Tasten, die in der\n" #~ "Kandidatenliste vor den Kandidaten angezeigt werden)\n" #~ "oder mit der Maus committen." #~ msgid "Behavior of space key:" #~ msgstr "Verhalten der Leertaste:" #~ msgid "Details" #~ msgstr "Details" #~ msgid "" #~ "\n" #~ "Authors:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contributors:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgstr "" #~ "\n" #~ "Autoren:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Mitwirkende:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgid "Mike FABIAN" #~ msgstr "Mike FABIAN" ibus-table-1.17.11/po/el.po000066400000000000000000000640751475513533100153120ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Yu Yuwei # This file is distributed under the same license as the PACKAGE package. # Giannis Antypas , 2024. # Weblate Translation Memory , 2024. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2024-09-08 10:38+0000\n" "Last-Translator: Weblate Translation Memory \n" "Language-Team: Greek \n" "Language: el\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: Weblate 5.7.2\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "" #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "" #: engine/table.py:735 msgid "Chinese mode" msgstr "" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "" #: engine/table.py:747 msgid "English" msgstr "Ελληνικά" #: engine/table.py:748 msgid "Switch to English input" msgstr "" #: engine/table.py:755 msgid "Chinese" msgstr "" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "" #: engine/table.py:765 msgid "Switch to direct input" msgstr "" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "" #: engine/table.py:771 msgid "Switch to table input" msgstr "" #: engine/table.py:779 msgid "Input mode" msgstr "Λειτουργία εισαγωγής" #: engine/table.py:780 msgid "Switch Input mode" msgstr "Εναλλαγή λειτουργίας εισαγωγής" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "" #: engine/table.py:801 msgid "Letter width" msgstr "" #: engine/table.py:802 msgid "Switch letter width" msgstr "" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "" #: engine/table.py:823 msgid "Punctuation width" msgstr "" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "" #: engine/table.py:835 msgid "Switch to table mode" msgstr "" #: engine/table.py:840 msgid "Pinyin" msgstr "" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "" #: engine/table.py:845 msgid "Pinyin mode" msgstr "" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "" #: engine/table.py:867 msgid "Suggestion mode" msgstr "" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "" #: engine/table.py:878 msgid "Multiple character match" msgstr "" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "" #: engine/table.py:885 msgid "Single character match" msgstr "" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "" #: engine/table.py:891 msgid "Onechar mode" msgstr "" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "Κανονικά" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" #: engine/table.py:919 msgid "Auto commit mode" msgstr "" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "" #: engine/table.py:2946 msgid "Setup" msgstr "Διαρρύθμιση" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "" #: engine/it_util.py:943 msgid "Cancel" msgstr "Ακύρωση" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "Παρακαλούμε πατήστε ένα κουμπί (ή ένα συνδυασμό κουμπιών)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "Το παράθυρο διαλόγου θα κλείσει όταν απελευθερωθεί το κουμπί" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "" "Nikos Charonitakis , 2002-2004\n" "Dimitrios Michelinakis , 2006\n" "Dimitrios Typaldos , 2007\n" "Dimitris Glezos , 2006-2007\n" "Kostas Papadimas , 2008-2009\n" "thalia , 2009\n" "Dimitris Glezos , 2011\n" "jiannis bonatakis , 2011\n" "Dimitris Glaros , 2012\n" "Nikos Roussos , 2012\n" "ioza1964 , 2013\n" "mitzie , 2013\n" "Vangelis Skarmoutsos , 2015." #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "Προτιμήσεις" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "" #: setup/main.py:115 msgid "Direct input" msgstr "" #: setup/main.py:116 msgid "Table input" msgstr "" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Προτιμήσεις" #: setup/main.py:212 msgid "About" msgstr "Σχετικά" #: setup/main.py:220 msgid "Restore all defaults" msgstr "" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "_Κλείσιμο" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Επιλογές" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Λεπτομέρειες" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" #: setup/main.py:323 msgid "No" msgstr "Όχι" #: setup/main.py:325 msgid "Yes" msgstr "Ναι" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" #: setup/main.py:590 msgid "Candidate list" msgstr "" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "Προσανατολισμός:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" #: setup/main.py:640 msgid "Horizontal" msgstr "Οριζόντιος" #: setup/main.py:642 msgid "Vertical" msgstr "Κάθετος" #: setup/main.py:644 msgid "System default" msgstr "Προεπιλογή συστήματος" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Μέγεθος σελίδας" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" #: setup/main.py:696 msgid "Current key bindings:" msgstr "" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Εντολή" #: setup/main.py:752 msgid "Edit" msgstr "Επεξεργασία" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "" #: setup/main.py:778 msgid "Set all to default" msgstr "" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" #: setup/main.py:862 msgid "Phrase" msgstr "" #: setup/main.py:864 msgid "Single Char" msgstr "" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" #: setup/main.py:1529 msgid "Are you sure?" msgstr "" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_Ακύρωση" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "_Εντάξει" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" #: setup/main.py:3037 msgid "ibus is not running." msgstr "Το ibus δεν εκτελείται." ibus-table-1.17.11/po/es.po000066400000000000000000001052361475513533100153140ustar00rootroot00000000000000# Máximo Castañeda Riloba , 2017. #zanata # Mike FABIAN , 2019, 2020, 2021. # Adolfo Jayme Barrientos , 2020. # Anonymous , 2020. # Emilio Herrera , 2021, 2022. # N M , 2025. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2025-02-04 17:38+0000\n" "Last-Translator: N M \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" "X-Generator: Weblate 5.9.2\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "Chino simplificado" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "Cambiar al modo «solo chino simplificado»." #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "Chino tradicional" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "Cambiar al modo «solo chino tradicional»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "Chino simplificado primero" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "Cambiar al modo «chino simplificado antes que el tradicional»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "Chino tradicional primero" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "Cambiar al modo «chino tradicional antes que el simplificado»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "Todos los caracteres chinos" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "Cambiar al modo «todos los caracteres chinos»." #: engine/table.py:735 msgid "Chinese mode" msgstr "Modo chino" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "Cambiar al modo chino" #: engine/table.py:747 msgid "English" msgstr "Inglés" #: engine/table.py:748 msgid "Switch to English input" msgstr "Cambiar a la entrada en inglés" #: engine/table.py:755 msgid "Chinese" msgstr "Chino" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "Cambiar a la entrada en chino" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "Directa" #: engine/table.py:765 msgid "Switch to direct input" msgstr "Cambiar a la entrada directa" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "Tabla" #: engine/table.py:771 msgid "Switch to table input" msgstr "Cambiar a la entrada por tabla" #: engine/table.py:779 msgid "Input mode" msgstr "Modo de entrada" #: engine/table.py:780 msgid "Switch Input mode" msgstr "Cambiar el modo de entrada" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "Media" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "Cambiar a caracteres de anchura media" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "Completa" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "Cambia a caracteres de anchura completa" #: engine/table.py:801 msgid "Letter width" msgstr "Anchura de caracteres" #: engine/table.py:802 msgid "Switch letter width" msgstr "Cambiar la anchura de caracteres" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "Cambiar a puntuación de anchura media" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "Cambiar a puntuación de anchura completa" #: engine/table.py:823 msgid "Punctuation width" msgstr "Anchura de puntuación" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "Cambiar la anchura de la puntuación" #: engine/table.py:835 msgid "Switch to table mode" msgstr "Cambiar a modo por tabla" #: engine/table.py:840 msgid "Pinyin" msgstr "Pinyin" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "Cambia al modo pinyin" #: engine/table.py:845 msgid "Pinyin mode" msgstr "Modo pinyin" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "Cambia el modo pinyin" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "Sugerencia desactivada" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "Cambiar al modo de sugerencias" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "Sugerencia activada" #: engine/table.py:867 msgid "Suggestion mode" msgstr "Modo de sugerencias" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "Cambiar modo de sugerencias" #: engine/table.py:878 msgid "Multiple character match" msgstr "Coincidencia de varios caracteres" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "Pasa a la búsqueda de coincidencias de varios caracteres a la vez" #: engine/table.py:885 msgid "Single character match" msgstr "Coincidencia de un solo carácter" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "Pasa a la búsqueda de coincidencias para caracteres individuales" #: engine/table.py:891 msgid "Onechar mode" msgstr "Modo de carácter" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "Cambia el modo de coincidencia de carácter" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "Normal" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" "Cambia al modo normal (los asentamientos automáticos van a preedición en vez " "de a la aplicación, de forma que se permita la definición automática de " "nuevos atajos)" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" "Cambia al modo directo (los asentamientos automáticos van directamente a la " "aplicación)" #: engine/table.py:919 msgid "Auto commit mode" msgstr "Modo automático de asentamiento" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "Cambia el modo de asentamiento automático" #: engine/table.py:2946 msgid "Setup" msgstr "Ajustes" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "Configura ibus-table “%(engine-name)s”" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "Entrada de tecla" #: engine/it_util.py:943 msgid "Cancel" msgstr "Cancelar" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "Por favor, presione una tecla (o una combinación de teclas)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "El diálogo se cerrará cuando la tecla sea liberada" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "Método de entrada basado en tabla para IBus." #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "Daniel Cabrera " #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "_Documentación en línea:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "Tabla de IBus" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "Método de entrada basado en tabla" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" "Ibus-table es un marco común para métodos de entrada basados en tablas. Se " "usa sobre todo para métodos de entrada de chino, como ZhengMa, WuBi, ErBi o " "CangJie, aunque también hay tablas para otros idiomas." #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "Preferencias" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "Estado inicial" #: setup/main.py:115 msgid "Direct input" msgstr "Entrada directa" #: setup/main.py:116 msgid "Table input" msgstr "Entrada de tabla" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Preferencias" #: setup/main.py:212 msgid "About" msgstr "Acerca de" #: setup/main.py:220 msgid "Restore all defaults" msgstr "Restablecer valores predeterminados" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "Ce_rrar" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Ajustes" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Detalles" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "Atajos de teclado" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "Recordar modo de entrada" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" "Si se debe recordar el último modo de entrada usado o si ibus-table debe " "comenzar en “Modo de tabla” de forma predeterminada después de un reinicio. " "Hay dos métodos de entrada: “Entrada de tabla” significa que el método de " "entrada está activado. “Entrada directa” es casi lo mismo que si el método " "de entrada estuviera desactivado, es decir, no se usa en absoluto, la " "mayoría de los caracteres simplemente pasan a la aplicación. Pero aún puede " "ocurrir alguna conversión entre ancho completo y medio ancho en el modo de " "entrada directa." #: setup/main.py:323 msgid "No" msgstr "No" #: setup/main.py:325 msgid "Yes" msgstr "Sí" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "Modo de chino:" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" "«Chino simplificado» muestra solo caracteres usados\n" "en el chino simplificado. «Chino tradicional» muestra\n" "solo caracteres usados en el chino tradicional.\n" "«Chino simplificado antes que el tradicional» muestra\n" "todos los caracteres pero da preferencia a los del\n" "simplificado en la lista de candidatos. «Chino\n" "tradicional antes que el simplificado» da preferencia\n" "a los del tradicional. «Todos los caracteres chinos»\n" "muestra todas las coincidencias sin filtrar por el\n" "tipo de carácter del que se trate." #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "Chino simplificado antes que el tradicional" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "Chino tradicional antes que el simplificado" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "Anchura de letra con entrada de tabla:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" "Si se deben usar letras de anchura media o\n" "completa en el modo de entrada de tabla." #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "Anchura de puntuación con entrada de tabla:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" "Si se debe usar puntuación de anchura media\n" "o completa en el modo de entrada de tabla." #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "Anchura de letra con entrada directa:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" "Si se deben usar letras de anchura media o\n" "completa en el modo de entrada directa." #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "Anchura de puntuación con entrada directa:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" "Si se debe usar puntuación de anchura media\n" "o completa en el modo de entrada directa." #: setup/main.py:590 msgid "Candidate list" msgstr "Lista de candidatos" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "Mostrar la lista de candidatos" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" "Si debe mostrarse o no la lista de candidatos.\n" "Para métodos de entrada de chino lo normal\n" "es que quiera visualizarse la lista, pero\n" "para otros como el “translit” ruso, suele ser\n" "mejor ocultarla." #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "Orientación:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" "Si la tabla de consulta con los candidatos\n" "debe ser vertical u horizontal." #: setup/main.py:640 msgid "Horizontal" msgstr "Horizontal" #: setup/main.py:642 msgid "Vertical" msgstr "Vertical" #: setup/main.py:644 msgid "System default" msgstr "Predeterminado del sistema" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Tamaño de página:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" "El número máximo de candidatos por página.\n" "Puede moverse entre página con las teclas\n" "de página siguiente/anterior o con las de\n" "flecha abajo/arriba." #: setup/main.py:696 msgid "Current key bindings:" msgstr "Atajos de teclado actuales:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Orden" #: setup/main.py:752 msgid "Edit" msgstr "Editar" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "Editar los atajos de teclado de la orden seleccionada" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "Establecer valor predeterminado" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "" "Establecer los atajos de teclado predeterminados de la orden seleccionada" #: setup/main.py:778 msgid "Set all to default" msgstr "Establecer todo a valores predeterminados" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "Establecer los atajos de teclado predeterminados de todas las órdenes" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "Ajuste dinámico" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" "Aquí puede usted elegir si el orden de los candidatos se ajusta " "dinámicamente de acuerdo a la frecuencia con la que se utilizan los " "candidatos." #: setup/main.py:824 msgid "Delete all learned data" msgstr "Eliminar datos aprendidos" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "Generación de candidatos:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" "Con “carácter” sólo se muestran candidatos\n" "de caracteres individuales.\n" "Con “frase” pueden aparecer candidatos de\n" "varios caracteres." #: setup/main.py:862 msgid "Phrase" msgstr "Frase" #: setup/main.py:864 msgid "Single Char" msgstr "Carácter único" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "Selección automática" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" "S se establece a “Yes”, hace una de las 4 cosas siguientes:\n" "1) Al escribir “Return”, confirma el \n" " candidato + alimentación de línea\n" "2) Cuando teclea Tab, confirma el candidato\n" "3) Al confirma usando una clave de confirmación, confirma\n" " el candidato + \" \"\n" "4) Si al teclear el siguiente carácter no hay coincidencia de candidatos,\n" " confirma el primer candidato de la anterior coincidencia.\n" " (Necesario mayormente para métodos de entrada no Chinos como\n" " el Ruso “translit”)" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "Modo de asentamiento automático:" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" "Al confirmar con las teclas de confirmación con el ratón\n" "siempre confirma a la aplicación. Esta opción es para\n" "las confirmaciones “automáticas” que pueden producirse cuando\n" "uno sigue tecleando en la entrada sin confirmar.\n" "manualmente. De vez en cuando, se producirán confirmaciones\n" "\"automáticas\" entonces.\n" "“Directa” significa que esas confirmaciones \"automáticas\" vayan " "directamente\n" "a la aplicación, “Normal” significa que se confirman\n" "para preeditar." #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "Acción para cuándo escribe un caracter invalido:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "Comodín automático" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" "Cuando está activo se añade automáticamente el comodín\n" "de coincidencia múltiple al final de la cadena de entrada." #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "Comodín de carácter único:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "El comodín para coincidencias de un solo carácter.\n" "Pulse INTRO para confirmar el cambio de comodín." #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "Comodín de cadena:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "El comodín para coincidencias de cualquier número de caracteres.\n" "Pulse INTRO para confirmar el cambio de comodín." #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "Usar tema oscuro" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "Sí si, el esquema de color para un tema oscuro será usado." #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "Reproducir sonido al producirse errores" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" "Aquí puede usted elegir si se reproduce un archivo de sonido cuando sucede " "un error. Si no está instalado el módulo simpleaudio para Python3, esta " "opción no hace nada." #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "Nivel de depuración:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" "Cuando es superior a 0, es posible guardar la información de depuración en " "el archivo de registro e incluso mostrarla gráficamente." #: setup/main.py:1529 msgid "Are you sure?" msgstr "¿Lo confirma?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_Cancelar" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "_Aceptar" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "Ya está ejecutándose otro ejemplar de la aplicación." #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "¿Realmente quiere recuperar los ajustes predeterminados?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" "¿Realmente quiere borrar los datos aprendidos de lo tecleado y seleccionar " "candidatos?" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "Seleccione un archivo de sonido .wav:" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "Editar los atajos de teclado de la orden «%s»" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "Añadir un atajo de teclado" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "Quitar el atajo de teclado seleccionado" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "Mover la vinculación de teclas hacia arriba" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "Mover la vinculación de teclas hacia abajo" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" "¿Confirma que quiere restablecer los valores predeterminados de los atajos " "de todas las órdenes?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "ibus no está ejecutándose." #~ msgid "IBUS_ENGINE_NAME environment variable is not set." #~ msgstr "No se ha establecido la variable de entorno IBUS_ENGINE_NAME." #~ msgid "" #~ "Cannot determine the engine name. Please use the --engine-name option." #~ msgstr "" #~ "No se pudo determinar el nombre del motor. Use el parámetro --engine-name." #~ msgid "IBus Table engine %s is not available" #~ msgstr "El motor de IBus Table %s no está disponible" #~ msgid "Next Page" #~ msgstr "Siguiente página" #~ msgid "Restore defaults as specified in the database for this engine." #~ msgstr "" #~ "Vuelve a poner los valores predeterminados de la base de datos para este " #~ "motor." #~ msgid "Input mode:" #~ msgstr "Modo de entrada:" #~ msgid "" #~ "If you choose the space key to do “Next page”,\n" #~ " you can only commit using the selection keys\n" #~ "(i.e. the labels in front of the candidates in the\n" #~ "lookup table) or using the mouse." #~ msgstr "" #~ "Si usa la tecla espaciadora como\n" #~ "“siguiente página”, sólo podrá\n" #~ "asentar con las teclas de selección\n" #~ "(las etiquetas que aparecen en la\n" #~ "lista junto a los candidatos) o con\n" #~ "el ratón." #~ msgid "Behavior of space key:" #~ msgstr "Comportamiento de la tecla espaciadora:" #~ msgid "Details" #~ msgstr "Detalles" #~ msgid "" #~ "\n" #~ "Authors:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contributors:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgstr "" #~ "\n" #~ "Autores:\n" #~ "Yuwei YU («acevery»)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contribuidores:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius «kaio» Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgid "Mike FABIAN" #~ msgstr "Mike FABIAN" ibus-table-1.17.11/po/fa.po000066400000000000000000000615401475513533100152720ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Yu Yuwei # This file is distributed under the same license as the PACKAGE package. # Ahmad Haghighi , 2020. # Anonymous , 2020. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2022-03-30 07:56+0000\n" "Last-Translator: Anonymous \n" "Language-Team: Persian \n" "Language: fa\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: Weblate 4.11.2\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "" #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "" #: engine/table.py:735 msgid "Chinese mode" msgstr "" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "" #: engine/table.py:747 msgid "English" msgstr "پارسی" #: engine/table.py:748 msgid "Switch to English input" msgstr "" #: engine/table.py:755 msgid "Chinese" msgstr "" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "" #: engine/table.py:765 msgid "Switch to direct input" msgstr "" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "" #: engine/table.py:771 msgid "Switch to table input" msgstr "" #: engine/table.py:779 msgid "Input mode" msgstr "" #: engine/table.py:780 msgid "Switch Input mode" msgstr "" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "" #: engine/table.py:801 msgid "Letter width" msgstr "" #: engine/table.py:802 msgid "Switch letter width" msgstr "" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "" #: engine/table.py:823 msgid "Punctuation width" msgstr "" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "" #: engine/table.py:835 msgid "Switch to table mode" msgstr "" #: engine/table.py:840 msgid "Pinyin" msgstr "" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "" #: engine/table.py:845 msgid "Pinyin mode" msgstr "" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "" #: engine/table.py:867 msgid "Suggestion mode" msgstr "" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "" #: engine/table.py:878 msgid "Multiple character match" msgstr "" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "" #: engine/table.py:885 msgid "Single character match" msgstr "" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "" #: engine/table.py:891 msgid "Onechar mode" msgstr "" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" #: engine/table.py:919 msgid "Auto commit mode" msgstr "" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "" #: engine/table.py:2946 msgid "Setup" msgstr "" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "" #: engine/it_util.py:943 msgid "Cancel" msgstr "انصراف" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "مترجم‌ها" #: engine/it_util.py:1019 #, fuzzy #| msgid "Orientation:" msgid "Online documentation:" msgstr "جهت:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "ترجیحات" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "" #: setup/main.py:115 msgid "Direct input" msgstr "" #: setup/main.py:116 msgid "Table input" msgstr "" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "ترجیحات" #: setup/main.py:212 msgid "About" msgstr "درباره" #: setup/main.py:220 msgid "Restore all defaults" msgstr "" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "_بستن" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "جزییات" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" #: setup/main.py:323 msgid "No" msgstr "نه" #: setup/main.py:325 msgid "Yes" msgstr "بله" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" #: setup/main.py:590 msgid "Candidate list" msgstr "" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "جهت:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" #: setup/main.py:640 msgid "Horizontal" msgstr "افقی" #: setup/main.py:642 msgid "Vertical" msgstr "عمودی" #: setup/main.py:644 msgid "System default" msgstr "" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "اندازه صفحه" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" #: setup/main.py:696 msgid "Current key bindings:" msgstr "" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "فرمان" #: setup/main.py:752 msgid "Edit" msgstr "ویرایش" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "" #: setup/main.py:778 msgid "Set all to default" msgstr "" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" #: setup/main.py:862 msgid "Phrase" msgstr "" #: setup/main.py:864 msgid "Single Char" msgstr "" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" #: setup/main.py:1529 msgid "Are you sure?" msgstr "" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_لغو" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "_تأیید" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" #: setup/main.py:3037 msgid "ibus is not running." msgstr "" ibus-table-1.17.11/po/fr.po000066400000000000000000001075711475513533100153200ustar00rootroot00000000000000# Alexandre Moine , 2016. #zanata # Jean-Baptiste Holcroft , 2016. #zanata, 2019, 2020. # Mike FABIAN , 2019, 2020, 2021, 2024, 2025. # Julien Humbert , 2019, 2020, 2021. # Anonymous , 2020. # Côme Borsoi , 2020. # Léane GRASSER , 2024. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2025-01-21 09:15+0000\n" "Last-Translator: Mike FABIAN \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" "X-Generator: Weblate 5.9.2\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "Chinois simplifié" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "Basculer vers « Chinois simplifié uniquement »." #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "Chinois traditionnel" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "Basculer vers « Chinois traditionnel uniquement »." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "Chinois simplifié d’abord" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "Basculer vers « Chinois simplifié avant traditionnel »." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "Chinois traditionnel d’abord" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "Basculer vers « Chinois traditionnel avant simplifié »." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "Tous les caractères chinois" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "Basculer vers « Tous les caractères chinois »." #: engine/table.py:735 msgid "Chinese mode" msgstr "Mode chinois" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "Basculer le mode chinois" #: engine/table.py:747 msgid "English" msgstr "Anglais" #: engine/table.py:748 msgid "Switch to English input" msgstr "Basculer vers la saisie anglaise" #: engine/table.py:755 msgid "Chinese" msgstr "Chinois" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "Basculer vers la saisie chinoise" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "Direct" #: engine/table.py:765 msgid "Switch to direct input" msgstr "Basculer vers la saisie directe" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "Table" #: engine/table.py:771 msgid "Switch to table input" msgstr "Passer en saisie par table" #: engine/table.py:779 msgid "Input mode" msgstr "Mode de saisie" #: engine/table.py:780 msgid "Switch Input mode" msgstr "Changer de mode de saisie" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "Demie" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "Basculer en lettres de demi-chasse" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "Pleine" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "Basculer en lettres de pleine chasse" #: engine/table.py:801 msgid "Letter width" msgstr "Largeur des lettres" #: engine/table.py:802 msgid "Switch letter width" msgstr "Changer la largeur des lettres" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "Passer en ponctuation de demi-chasse" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "Passer en ponctuation de pleine chasse" #: engine/table.py:823 msgid "Punctuation width" msgstr "Largeur de ponctuation" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "Changer la largeur de ponctuation" #: engine/table.py:835 msgid "Switch to table mode" msgstr "Passer en mode table" #: engine/table.py:840 msgid "Pinyin" msgstr "Pinyin" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "Basculer vers le mode pinyin" #: engine/table.py:845 msgid "Pinyin mode" msgstr "Mode pinyin" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "Basculer le mode pinyin" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "Suggestion désactivée" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "Basculer vers le mode de suggestion" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "Suggestion activée" #: engine/table.py:867 msgid "Suggestion mode" msgstr "Mode de suggestion" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "Changer de mode de suggestion" #: engine/table.py:878 msgid "Multiple character match" msgstr "De multiples caractères correspondent" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "Passez à la correspondance de plusieurs caractères à la fois" #: engine/table.py:885 msgid "Single character match" msgstr "Correspondance mono caractère" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "Passez à la correspondance mono caractère" #: engine/table.py:891 msgid "Onechar mode" msgstr "Mode mono caractère" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "Passer en mode mono caractère" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "Normal" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" "Passer au mode de validation normal (les validations automatiques vont dans " "la pré-édition plutôt que dans l’application. Ceci permet la définition " "automatique de nouveaux raccourcis)" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" "Passer au mode de validation direct (les validations automatiques vont " "directement dans l’application)" #: engine/table.py:919 msgid "Auto commit mode" msgstr "Mode de validation automatique" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "Passer en mode validation automatique" #: engine/table.py:2946 msgid "Setup" msgstr "Configuration" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "Configurer ibus-table « %(engine-name)s »" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "Entrez une touche" #: engine/it_util.py:943 msgid "Cancel" msgstr "Annuler" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "Appuyez sur une touche (ou une combinaison de touches)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "La boite de dialogue se fermera quand la touche sera relâchée" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "Méthode de saisie en table pour IBus." #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "Julien Humbert , 2020" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "Documentation en ligne :" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "Ibus Table" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "Méthode de saisie en table" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" "Ibus-table est un cadriciel pour les méthodes de saisie basées sur des " "tables. Il est principalement utilisé pour les méthodes de saisie Chinoises " "telles que ZhengMa, Wubizixing, ErBi, CangJie… Mais des tables pour d’autres " "langues sont également disponibles." #: setup/ibus-setup-table.desktop.in.in:3 msgid "IBus Table Preferences" msgstr "Préférences d'IBus Table" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "Définir les options d'IBus Table" #: setup/main.py:114 msgid "Initial state" msgstr "État initial" #: setup/main.py:115 msgid "Direct input" msgstr "Saisie directe" #: setup/main.py:116 msgid "Table input" msgstr "Saisie en table" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Préférences" #: setup/main.py:212 msgid "About" msgstr "À propos" #: setup/main.py:220 msgid "Restore all defaults" msgstr "Restaurer les valeurs par défaut" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "_Fermer" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Paramètres" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Détails" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "Raccourcis clavier" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "Se rappeler du mode de saisie" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" "Choisissez si l'on doit se souvenir du dernier mode de saisie, ou si ibus-" "table doit démarrer par défaut en mode Table. Il existe deux modes de " "saisie : « Saisie par table » signifie que la méthode de saisie est activée, " "tandis que « Saisie directe » est presque comme si la méthode de saisie " "était désactivée, c’est-à-dire pas du tout utilisée. Dans ce mode, la " "plupart des caractères sont simplement passés à l’application, mais " "certaines conversions pleine-chasse et demi-chasse peuvent encore se " "produire." #: setup/main.py:323 msgid "No" msgstr "Non" #: setup/main.py:325 msgid "Yes" msgstr "Oui" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "Mode chinois :" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" "« Chinois simplifié » ne montre que les caractères utilisés en chinois " "simplifié.\n" "« Chinois traditionnel » montre seulement les caractères utilisés en\n" "chinois traditionnel.\n" "« Chinois simplifié avant traditionnel » montre tous les caractères, mais " "place\n" "les caractères simplifiés plus haut dans la liste des candidats.\n" "« Chinois traditionnel avant simplifié » place les caractères traditionnels\n" "plus haut dans la liste des candidats.\n" "« Tous les caractères » montre uniquement toutes les correspondances sans\n" "filtrage particulier sur le chinois traditionnel par rapport au chinois " "simplifié." #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "Chinois simplifié avant traditionnel" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "Chinois traditionnel avant simplifié" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "Largeur des lettres en table :" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" "S’il faut utiliser des caractères pleine\n" "ou demi-chasse lors de la saisie en table." #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "Largeur de la ponctuation en table :" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" "S’il faut utiliser une ponctuation pleine\n" "ou demi-chasse lors de la saisie en table." #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "Largeur des lettres en saisie directe :" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" "S’il faut utiliser des lettres pleine\n" "ou demi-chasse lors de la saisie en table." #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "Largeur des signes de ponctuation en saisie directe :" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" "S’il faut utiliser une ponctuation pleine\n" "ou demi-chasse lors de la saisie directe." #: setup/main.py:590 msgid "Candidate list" msgstr "Liste des candidats" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "Affiche la liste des candidats" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" "Si la liste des candidats doit être montrée ou cachée.\n" "Pour les méthodes de saisie chinoises, on souhaitera\n" "voir la liste. Mais pour certaines méthodes de saisie\n" "non chinoises, telle que le Russe « translit », cacher\n" "la liste des candidats est plus pratique." #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "Orientation :" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" "Si la table de recherche montrant les candidats\n" "doit être verticale ou horizontale." #: setup/main.py:640 msgid "Horizontal" msgstr "Horizontale" #: setup/main.py:642 msgid "Vertical" msgstr "Verticale" #: setup/main.py:644 msgid "System default" msgstr "Par défaut pour le système" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Taille de la page :" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" "Le nombre maximum de candidats dans une\n" "page de recherche de table. Vous pouvez\n" "changer de page en utilisant les touches\n" "page suivante/précédente ou les flèches haut/bas." #: setup/main.py:696 msgid "Current key bindings:" msgstr "Raccourcis clavier actuels :" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Commande" #: setup/main.py:752 msgid "Edit" msgstr "Modifier" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "Modifier les raccourcis clavier pour la commande sélectionnée" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "Réinitialiser" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "" "Remettre le raccourcis clavier par défaut pour la commande sélectionnée" #: setup/main.py:778 msgid "Set all to default" msgstr "Tout réinitialiser" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "Remettre le raccourcis clavier par défaut pour toutes les commandes" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "Ajustement dynamique" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" "Ici, vous pouvez décider d'ajuster dynamiquement ou non l'ordre des " "candidats en fonction de leur fréquence d'utilisation." #: setup/main.py:824 msgid "Delete all learned data" msgstr "Supprimer les données apprises" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "Composer :" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" "Si défini à « Mono caractère », seuls les\n" "candidats mono caractères seront montrés.\n" "Si défini à « Phrase », les candidats constitués\n" "de plusieurs caractères pourront être montrés." #: setup/main.py:862 msgid "Phrase" msgstr "Phrase" #: setup/main.py:864 msgid "Single Char" msgstr "Mono caractère" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "Auto sélection" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" "Si défini à « Oui », cela fait les 4 choses suivantes :\n" "1) Lorsque vous tapez « Entrée », valide le candidat + saut de ligne\n" "2) Lorsque vous tapez « Tab », valide le candidat\n" "3) Lors de la validation avec une clef, valide le candidat + « ».\n" "4) Si la saisie du caractère suivant ne correspond à aucun candidat,\n" " valide le premier candidat de la correspondance précédente.\n" " (Principalement nécessaire pour les méthodes de saisie non chinoises\n" " comme le « translit » russe)" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "Mode de validation auto :" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" "La validation avec les touches de validation ou la souris va\n" "toujours être transmise à l’application. Cette option concerne\n" "les validations « automatiques » qui peuvent survenir lors ce\n" "qu’on continue à saisir sans valider manuellement.\n" "De temps\n" "en temps, des validations « automatiques » auront lieux.\n" "« Direct » signifie que les validations « automatiques » vont\n" "directement à l’application, « Normal » signifie qu’elles sont\n" "validées dans la pré-édition." #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "Action lors de la saisie d'un caractère invalide :" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" "Détermine ce qu'il se produit lorsqu'un caractère est tapé et qu'il ne fait " "pas partie des caractères valides de la table actuelle. Avec « valider le " "candidat actuel », le candidat déjà sélectionné est inséré. Avec « valider " "les touches appuyées », les caractères bruts saisis pendant le processus de " "sélection d'un candidat seront insérés à la place. Quelle que soit l'option " "choisie, la sélection d'un candidat se termine dès lors qu'un caractère " "invalide est tapé et le caractère en question est inséré immédiatement à la " "suite du texte résultant de l'option choisie parmi celles énumérées " "précédemment." #: setup/main.py:983 msgid "Commit current candidate" msgstr "Valider le candidat actuel" #: setup/main.py:985 msgid "Commit typed keys" msgstr "Valider les touches appuyées" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "Métacaractère auto" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" "Si oui, un métacaractère multiple sera\n" "automatiquement ajouté à la fin de la chaine saisie." #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "Métacaractère simple :" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "Le métacaractère pour la correspondance de n’importe quel caractère.\n" "Saisissez RETOUR ou ENTRÉE pour confirmer après le changement du " "métacaractère." #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "Métacaractère multi :" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "Le métacaractère pour la correspondance pour un nombre quelconque de " "caractères.\n" "Saisissez RETOUR ou ENTRÉE pour confirmer après le changement du " "métacaractère." #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "Utilisez le thème sombre" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "Si activé, un schéma de couleurs pour thèmes sombres sera utilisé." #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "Lecture d’un fichier son en cas d’erreur" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" "Vous pouvez choisir ici si un fichier son est joué en cas d’erreur. Si le " "module simpleaudio pour Python3 n’est pas installé, cette option ne fait " "rien." #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "Niveau de débogage :" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" "Quand supérieur à 0, les informations de débogue peuvent être imprimées dans " "le fichier journal et les informations de débogage peuvent également être " "montrées graphiquement." #: setup/main.py:1529 msgid "Are you sure?" msgstr "Confirmez-vous ?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_Annuler" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "_OK" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "Une autre instance de cette application est déjà en cours d’exécution." #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "Souhaitez-vous vraiment rétablir tous les paramètres par défaut ?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" "Voulez-vous vraiment supprimer toutes les données récoltées en tapant et en " "sélectionnant des candidats ?" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "Sélectionnez le fichier son .wav :" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "Modifier le raccourcis clavier pour la commande \"%s\"" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "Ajouter un raccourcis claviers" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "Supprimer le raccourcis clavier sélectionné" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "Monter le raccourci clavier" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "Descendre le raccourci clavier" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" "Voulez-vous vraiment redéfinir les raccourcis claviers pour toutes les " "commandes ?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "Ibus n’est pas lancé." #~ msgid "IBUS_ENGINE_NAME environment variable is not set." #~ msgstr "IBUS_ENGINE_NAME n’est pas définie." #~ msgid "" #~ "Cannot determine the engine name. Please use the --engine-name option." #~ msgstr "" #~ "Impossible de déterminer le nom du moteur. Merci d’utiliser l’option --" #~ "engine-name." #~ msgid "IBus Table engine %s is not available" #~ msgstr "Le moteur de tables IBus %s n’est pas disponible" #~ msgid "Next Page" #~ msgstr "Page suivante" #~ msgid "Restore defaults as specified in the database for this engine." #~ msgstr "" #~ "Restaure les valeurs par défauts tels que définis dans la base de données " #~ "pour ce moteur." #~ msgid "Input mode:" #~ msgstr "Mode de saisie :" #~ msgid "" #~ "If you choose the space key to do “Next page”,\n" #~ " you can only commit using the selection keys\n" #~ "(i.e. the labels in front of the candidates in the\n" #~ "lookup table) or using the mouse." #~ msgstr "" #~ "Si vous choisissez la barre espace pour la\n" #~ "page suivante, vous ne pourrez valider\n" #~ "qu’avec les touches de sélection\n" #~ "(p. ex. les libellés en face des candidats dans\n" #~ "la table de recherche) ou en utilisant la souris." #~ msgid "Behavior of space key:" #~ msgstr "Comportement de la touche espace :" #~ msgid "Details" #~ msgstr "Détails" #~ msgid "" #~ "\n" #~ "Authors:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contributors:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgstr "" #~ "\n" #~ "Auteurs :\n" #~ "Yuwei YU (« acevery »)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contributeurs :\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius « kaio » Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" ibus-table-1.17.11/po/ibus-table.pot000066400000000000000000000606351475513533100171230ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Yu Yuwei # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\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" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "" #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "" #: engine/table.py:735 msgid "Chinese mode" msgstr "" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "" #: engine/table.py:747 msgid "English" msgstr "" #: engine/table.py:748 msgid "Switch to English input" msgstr "" #: engine/table.py:755 msgid "Chinese" msgstr "" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "" #: engine/table.py:765 msgid "Switch to direct input" msgstr "" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "" #: engine/table.py:771 msgid "Switch to table input" msgstr "" #: engine/table.py:779 msgid "Input mode" msgstr "" #: engine/table.py:780 msgid "Switch Input mode" msgstr "" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "" #: engine/table.py:801 msgid "Letter width" msgstr "" #: engine/table.py:802 msgid "Switch letter width" msgstr "" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "" #: engine/table.py:823 msgid "Punctuation width" msgstr "" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "" #: engine/table.py:835 msgid "Switch to table mode" msgstr "" #: engine/table.py:840 msgid "Pinyin" msgstr "" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "" #: engine/table.py:845 msgid "Pinyin mode" msgstr "" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "" #: engine/table.py:867 msgid "Suggestion mode" msgstr "" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "" #: engine/table.py:878 msgid "Multiple character match" msgstr "" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "" #: engine/table.py:885 msgid "Single character match" msgstr "" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "" #: engine/table.py:891 msgid "Onechar mode" msgstr "" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" #: engine/table.py:919 msgid "Auto commit mode" msgstr "" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "" #: engine/table.py:2946 msgid "Setup" msgstr "" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "" #: engine/it_util.py:943 msgid "Cancel" msgstr "" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" #: setup/ibus-setup-table.desktop.in.in:3 msgid "IBus Table Preferences" msgstr "" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "" #: setup/main.py:115 msgid "Direct input" msgstr "" #: setup/main.py:116 msgid "Table input" msgstr "" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "" #: setup/main.py:212 msgid "About" msgstr "" #: setup/main.py:220 msgid "Restore all defaults" msgstr "" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" #: setup/main.py:323 msgid "No" msgstr "" #: setup/main.py:325 msgid "Yes" msgstr "" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" #: setup/main.py:590 msgid "Candidate list" msgstr "" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" #: setup/main.py:640 msgid "Horizontal" msgstr "" #: setup/main.py:642 msgid "Vertical" msgstr "" #: setup/main.py:644 msgid "System default" msgstr "" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" #: setup/main.py:696 msgid "Current key bindings:" msgstr "" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "" #: setup/main.py:752 msgid "Edit" msgstr "" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "" #: setup/main.py:778 msgid "Set all to default" msgstr "" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" #: setup/main.py:862 msgid "Phrase" msgstr "" #: setup/main.py:864 msgid "Single Char" msgstr "" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" #: setup/main.py:1529 msgid "Are you sure?" msgstr "" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" #: setup/main.py:3037 msgid "ibus is not running." msgstr "" ibus-table-1.17.11/po/ja.po000066400000000000000000000665331475513533100153050ustar00rootroot00000000000000# Ooyama Yosiyuki , 2015. #zanata # Anonymous , 2019, 2020. # Mike FABIAN , 2019, 2020, 2021, 2023, 2025. # Weblate Translation Memory , 2024. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2025-01-19 01:44+0000\n" "Last-Translator: Mike FABIAN \n" "Language-Team: Japanese \n" "Language: ja\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 5.9.2\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "中国語(簡体)" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "" #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "中国語(繁体)" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "" #: engine/table.py:735 msgid "Chinese mode" msgstr "" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "" #: engine/table.py:747 msgid "English" msgstr "英語" #: engine/table.py:748 msgid "Switch to English input" msgstr "英数入力に切り替える" #: engine/table.py:755 msgid "Chinese" msgstr "中国語" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "ダイレクト" #: engine/table.py:765 msgid "Switch to direct input" msgstr "" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "テーブル" #: engine/table.py:771 msgid "Switch to table input" msgstr "" #: engine/table.py:779 msgid "Input mode" msgstr "入力モード" #: engine/table.py:780 msgid "Switch Input mode" msgstr "入力モードを切り替えます" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "半" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "全" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "" #: engine/table.py:801 msgid "Letter width" msgstr "" #: engine/table.py:802 msgid "Switch letter width" msgstr "" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "" #: engine/table.py:823 msgid "Punctuation width" msgstr "" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "句読点の半角/全角を切り替える" #: engine/table.py:835 msgid "Switch to table mode" msgstr "" #: engine/table.py:840 msgid "Pinyin" msgstr "ピンイン" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "ピンイン入力モードに切り替える" #: engine/table.py:845 msgid "Pinyin mode" msgstr "ピンインモード" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "" #: engine/table.py:857 engine/table.py:863 #, fuzzy #| msgid "Switch Input mode" msgid "Switch to suggestion mode" msgstr "入力モードを切り替えます" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "" #: engine/table.py:867 msgid "Suggestion mode" msgstr "" #: engine/table.py:868 #, fuzzy #| msgid "Switch Input mode" msgid "Switch suggestion mode" msgstr "入力モードを切り替えます" #: engine/table.py:878 msgid "Multiple character match" msgstr "" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "" #: engine/table.py:885 msgid "Single character match" msgstr "" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "" #: engine/table.py:891 msgid "Onechar mode" msgstr "" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "普通" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" #: engine/table.py:919 msgid "Auto commit mode" msgstr "" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "" #: engine/table.py:2946 msgid "Setup" msgstr "設定" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "キーの入力" #: engine/it_util.py:943 msgid "Cancel" msgstr "取り消し" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "キー (もしくはキーの組み合わせ) を押してください" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "このダイアログはキーを離すと閉じられます" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "翻訳者クレジット" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "オンラインドキュメント:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" #: setup/ibus-setup-table.desktop.in.in:3 msgid "IBus Table Preferences" msgstr "IBus Tableの設定" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "IBus Tableのオプションを設定する" #: setup/main.py:114 msgid "Initial state" msgstr "初期状態" #: setup/main.py:115 msgid "Direct input" msgstr "直接入力" #: setup/main.py:116 msgid "Table input" msgstr "テーブル入力" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "設定" #: setup/main.py:212 msgid "About" msgstr "このアプリケーションについて" #: setup/main.py:220 msgid "Restore all defaults" msgstr "全て初期設定に戻す" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "閉じる(_C)" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "設定" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "詳細" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "キー割り当て" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "入力モードを記憶する" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" #: setup/main.py:323 msgid "No" msgstr "いいえ" #: setup/main.py:325 msgid "Yes" msgstr "はい" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" #: setup/main.py:590 msgid "Candidate list" msgstr "" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "表示方向:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" "変換候補を表示する際に縦と横の\n" "どちらに続けて並べるか選択します。" #: setup/main.py:640 msgid "Horizontal" msgstr "横" #: setup/main.py:642 msgid "Vertical" msgstr "縦" #: setup/main.py:644 msgid "System default" msgstr "システムのデフォルト" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "表示数:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" #: setup/main.py:696 msgid "Current key bindings:" msgstr "現在のキーバインディング:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "コマンド" #: setup/main.py:752 msgid "Edit" msgstr "編集" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "選択したコマンドのキーバインディングを編集します" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "デフォルトに設定する" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "選択したコマンドのキーバインディングを初期設定に戻します" #: setup/main.py:778 msgid "Set all to default" msgstr "すべてをデフォルトに設定する" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "すべてのコマンドのキーバインディングをデフォルトに戻す" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "すべての学習データを削除" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" #: setup/main.py:862 msgid "Phrase" msgstr "フレーズ" #: setup/main.py:864 msgid "Single Char" msgstr "" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "候補の自動選択" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "ダークテーマを適用" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "有効にすると、ダークテーマに合わせた配色が適用されます。" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "エラー音を有効にする" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" "エラー音を再生するかどうか選択できます。Python3のsimpleaudioモジュールがイン" "ストールされていない場合、エラー音は再生されません。" #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "デバッグレベル:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" "0より大きい場合、デバッグ情報はログファイルに出力され、またグラフィカルに表示" "されることがあります。" #: setup/main.py:1529 msgid "Are you sure?" msgstr "本当によろしいでしょうか?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "キャンセル(_C)" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "OK(_O)" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "このアプリケーションの別のインスタンスがすでに実行されています。" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "すべて初期設定に戻してもよろしいですか?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "入力と変換の学習データをすべて削除してもよろしいですか?" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr ".wavファイルを選択:" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "コマンド %s のキー割り当ての編集" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "キー割り当てを追加する" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "キー割り当てを削除する" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 #, fuzzy #| msgid "Add a key binding" msgid "Move key binding up" msgstr "キー割り当てを追加する" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 #, fuzzy #| msgid "Add a key binding" msgid "Move key binding down" msgstr "キー割り当てを追加する" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "すべてのコマンドのキー割り当てをデフォルトに戻してもよろしいですか?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "ibus が起動していません。" #~ msgid "Input mode:" #~ msgstr "入力モード:" ibus-table-1.17.11/po/ka.po000066400000000000000000000717441475513533100153060ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Yu Yuwei # This file is distributed under the same license as the PACKAGE package. # Temuri Doghonadze , 2022, 2023. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2023-02-05 18:20+0000\n" "Last-Translator: Temuri Doghonadze \n" "Language-Team: Georgian \n" "Language: ka\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: Weblate 4.15.2\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "გამარტივებული ჩინური" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "" #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "ტრადიციული ჩინური" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "\"მხოლოდ ტრადიციულ ჩინურზე\" გადართვა." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "" #: engine/table.py:735 msgid "Chinese mode" msgstr "ჩინური რეჟიმი" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "ჩინურის რეჟიმის გადართვა" #: engine/table.py:747 msgid "English" msgstr "ინგლისური" #: engine/table.py:748 msgid "Switch to English input" msgstr "" #: engine/table.py:755 msgid "Chinese" msgstr "ჩინური" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "პირდაპირი" #: engine/table.py:765 msgid "Switch to direct input" msgstr "" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "ცხრილი" #: engine/table.py:771 msgid "Switch to table input" msgstr "" #: engine/table.py:779 msgid "Input mode" msgstr "შეყვანის რეჟიმი" #: engine/table.py:780 msgid "Switch Input mode" msgstr "შეყვანის რეჟიმის გადართვა" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "ნახევარი" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "სრული" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "" #: engine/table.py:801 msgid "Letter width" msgstr "" #: engine/table.py:802 msgid "Switch letter width" msgstr "" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "" #: engine/table.py:823 msgid "Punctuation width" msgstr "" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "" #: engine/table.py:835 msgid "Switch to table mode" msgstr "" #: engine/table.py:840 msgid "Pinyin" msgstr "პინინი" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "" #: engine/table.py:845 msgid "Pinyin mode" msgstr "" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "" #: engine/table.py:867 msgid "Suggestion mode" msgstr "" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "" #: engine/table.py:878 msgid "Multiple character match" msgstr "" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "" #: engine/table.py:885 msgid "Single character match" msgstr "" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "" #: engine/table.py:891 msgid "Onechar mode" msgstr "" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "ჩვეულებრივი" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" #: engine/table.py:919 msgid "Auto commit mode" msgstr "" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "" #: engine/table.py:2946 msgid "Setup" msgstr "მორგება" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "ღილაკის შეყვანა" #: engine/it_util.py:943 msgid "Cancel" msgstr "გაუქმენა" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "დააწექით ღილაკს (ან მათ კომბინაციას)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "ეს ფანჯარა დაიხურება, როცა ღილაკს გაუშვებთ" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "თემური დოღონაძე" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "ონლაინ დოკუმენტაცია:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "მორგება" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "საწყისი მდგომარეობა" #: setup/main.py:115 msgid "Direct input" msgstr "" #: setup/main.py:116 msgid "Table input" msgstr "" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "მორგება" #: setup/main.py:212 msgid "About" msgstr "შესახებ" #: setup/main.py:220 msgid "Restore all defaults" msgstr "ყველა მნიშვნელობის ნაგულისხმებამდე აღდგენა" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "და_კეტვა" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "მორგება" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "დეტალები" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "კლავიატურის ბმები" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "შეტანის მეთოდის დამახსოვრება" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" #: setup/main.py:323 msgid "No" msgstr "არა" #: setup/main.py:325 msgid "Yes" msgstr "კი" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "ჩინური რეჟიმი:" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" #: setup/main.py:590 msgid "Candidate list" msgstr "" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "ორიენტაცია:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" #: setup/main.py:640 msgid "Horizontal" msgstr "ჰორიზონტალური" #: setup/main.py:642 msgid "Vertical" msgstr "ვერტიკალური" #: setup/main.py:644 msgid "System default" msgstr "სისტემის ნაგულისხმები" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "გვერდის ზომა:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" #: setup/main.py:696 msgid "Current key bindings:" msgstr "მიმდინარე ღილაკის ბმები:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "ბრძანება" #: setup/main.py:752 msgid "Edit" msgstr "ჩასწორება" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "მონიშნული ბრძანების ღილაკის ბმების ჩასწორება" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "ნაგულისხმები მნიშვნელობების დაყენება" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "მონიშნული ბრძანებისთვის ნაგულისხმები ღილაკების მიბმის დაყენება" #: setup/main.py:778 msgid "Set all to default" msgstr "ყველას ნაგულისხმებ მნიშვნელობებზე დაყენება" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "" "ყველა ბრძანების ყველა ღილაკის მიბმის ნაგულისხმებ მნიშვნელობებზე დაყენება" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "ნასწავლი მონაცემების წაშლა" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" #: setup/main.py:862 msgid "Phrase" msgstr "ფრაზა" #: setup/main.py:864 msgid "Single Char" msgstr "" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "ავტომატური არჩევა" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "შეცდომისას ხმოვანი ფაილის დაკვრა" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" "შეგიძლიათ აირჩიოთ, იქნება დაკრული ხმოვანი ფაილი შეცდომის დაშვებისას, თუ არა. " "თუ Python3-ის მოდული simpleaudio დაყენებული არაა, ეს პარამეტრი არაფერს " "აკეთებს." #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "გამართვის დონე:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" "როცა ნულზე მეტია, გამართვის ინფორმაცია ჟურნალის ფაილში ჩაიწერება. მისი " "ჩვენება გრაფიკულადაც შეიძლება." #: setup/main.py:1529 msgid "Are you sure?" msgstr "დარწმუნებული ბრძანდებით?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_გაუქმება" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "_დიახ" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "ამ აპის სხვა ასლი უკვე გაშვებულია." #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "მართლა გნებავთ ყველა პარამეტრის ნაგულისხმებ მნიშვნელობაზე დაყენება?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "აირჩიეთ .wav ხმოვანი ფაილი:" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "ღილაკების მიბმის შეცვლა ბრძანებისთვის \"%s\"" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "ღილაკების მიბმის დამატება" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "მონიშნული ღილაკის მიბმის წაშლა" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" "მართლა გნებავთ ყველა ბრძანების ღილაკებზე მიბმის ნაგულისხმებ მნიშვნელობებზე " "დაყენება?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "ibus გაშვებული არაა." ibus-table-1.17.11/po/kab.po000066400000000000000000000632021475513533100154360ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Yu Yuwei # This file is distributed under the same license as the PACKAGE package. # ButterflyOfFire , 2024. # Weblate Translation Memory , 2024. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2024-11-21 16:38+0000\n" "Last-Translator: ButterflyOfFire \n" "Language-Team: Kabyle \n" "Language: kab\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: Weblate 5.8.2\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "" #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "" #: engine/table.py:735 msgid "Chinese mode" msgstr "" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "" #: engine/table.py:747 msgid "English" msgstr "Taglizit" #: engine/table.py:748 msgid "Switch to English input" msgstr "" #: engine/table.py:755 msgid "Chinese" msgstr "Tacinwatt" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "" #: engine/table.py:765 msgid "Switch to direct input" msgstr "" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "Tafelwit" #: engine/table.py:771 msgid "Switch to table input" msgstr "" #: engine/table.py:779 msgid "Input mode" msgstr "Askar n unekcum" #: engine/table.py:780 msgid "Switch Input mode" msgstr "" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "" #: engine/table.py:801 msgid "Letter width" msgstr "" #: engine/table.py:802 msgid "Switch letter width" msgstr "" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "" #: engine/table.py:823 msgid "Punctuation width" msgstr "" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "" #: engine/table.py:835 msgid "Switch to table mode" msgstr "" #: engine/table.py:840 msgid "Pinyin" msgstr "Pinyin" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "" #: engine/table.py:845 msgid "Pinyin mode" msgstr "" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "" #: engine/table.py:867 msgid "Suggestion mode" msgstr "" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "" #: engine/table.py:878 msgid "Multiple character match" msgstr "" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "" #: engine/table.py:885 msgid "Single character match" msgstr "" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "" #: engine/table.py:891 msgid "Onechar mode" msgstr "" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" #: engine/table.py:919 msgid "Auto commit mode" msgstr "" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "" #: engine/table.py:2946 msgid "Setup" msgstr "Asbeddi" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "Sekcem yiwet n tqeffalt" #: engine/it_util.py:943 msgid "Cancel" msgstr "Sefsex" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "Ttxil-k sit ɣef tqeffalt (neɣ taggayt n tqeffalin)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "Adiwenni ad yemdel mi ara d-teffeɣ tqeffalt" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "Athmane Mokraoui , 2024" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "Tasemlit srid:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "Imenyafen" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "" #: setup/main.py:115 msgid "Direct input" msgstr "" #: setup/main.py:116 msgid "Table input" msgstr "" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Imenyafen" #: setup/main.py:212 msgid "About" msgstr "Ɣef" #: setup/main.py:220 msgid "Restore all defaults" msgstr "Err-d akk imezwer" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "Mdel (_C)" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Iɣewwaṛen" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Talqayt" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "Inegzumen n unasiw" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "Cfu ɣef uskar n unekcum" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" #: setup/main.py:323 msgid "No" msgstr "Uhu" #: setup/main.py:325 msgid "Yes" msgstr "Ih" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" #: setup/main.py:590 msgid "Candidate list" msgstr "" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" #: setup/main.py:640 msgid "Horizontal" msgstr "Aglawan" #: setup/main.py:642 msgid "Vertical" msgstr "Ubdid" #: setup/main.py:644 msgid "System default" msgstr "Anagraw amezwer" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Teɣzi n usebter:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" #: setup/main.py:696 msgid "Current key bindings:" msgstr "Tuqqniwin n tsura-a:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Taladna" #: setup/main.py:752 msgid "Edit" msgstr "Ẓreg" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "Sbadu ɣer umezwer" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "" #: setup/main.py:778 msgid "Set all to default" msgstr "Sbadu kullec ɣer umezwer" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" #: setup/main.py:862 msgid "Phrase" msgstr "" #: setup/main.py:864 msgid "Single Char" msgstr "" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "Taɣuri n ufaylu n yimesli mi ara tili tuccḍa" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "Aswir n temseɣtayt:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" #: setup/main.py:1529 msgid "Are you sure?" msgstr "D tidet?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "Sefsex (_C)" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "IH (_O)" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "Tummant niḍen n usnas-a la tettwaselkam yakan." #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "D tidet tebɣiḍ ad d-terreḍ akk iɣewwaren imezwer?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "Fren afaylu n yimesli .wav:" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "Ẓreg tuqqna n tsura i tladna “%s”" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "Rnu tuqqna n tsura" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "Kkes tuqqna n tsura i yettwafernen" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" "D tidet tebɣiḍ ad tesbaduḍ tuqqniwin n tsura i meṛṛa tiludna ɣer yimezwer-" "nsent?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "ibus ur iteddu ara." ibus-table-1.17.11/po/pt_BR.po000066400000000000000000001056161475513533100157150ustar00rootroot00000000000000# Marco Aurélio Krause , 2015. #zanata # Rodrigo de Araujo Sousa Fonseca , 2017. #zanata # Mike FABIAN , 2019, 2020, 2021. # Anonymous , 2019, 2020. # Rafael Fontenelle , 2020, 2021. # Adolfo Ketzer , 2020. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2021-09-28 12:00+0000\n" "Last-Translator: Mike FABIAN \n" "Language-Team: Portuguese (Brazil) \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: Weblate 4.8\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "Chinês Simplificado" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "Alterna para “apenas chinês simplificado”." #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "Chinês Tradicional" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "Alterna para “somente chinês tradicional”." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "Chinês Simplificado primeiro" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "Alterna para “chinês simplificado antes do tradicional”." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "Chinês Tradicional primeiro" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "Alterna para ”chinês tradicional antes do simplificado”." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "Todos os caracteres chineses" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "Alterna para “Todos os caracteres chineses”." #: engine/table.py:735 msgid "Chinese mode" msgstr "Modo chinês" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "Alterna para o modo chinês" #: engine/table.py:747 msgid "English" msgstr "Inglês" #: engine/table.py:748 msgid "Switch to English input" msgstr "Alterna para entrada em inglês" #: engine/table.py:755 msgid "Chinese" msgstr "Chinês" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "Alterna para entrada em chinês" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "Direto" #: engine/table.py:765 msgid "Switch to direct input" msgstr "Alterna para entrada direta" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "Tabela" #: engine/table.py:771 msgid "Switch to table input" msgstr "Alterna para entrada da tabela" #: engine/table.py:779 msgid "Input mode" msgstr "Modo de entrada" #: engine/table.py:780 msgid "Switch Input mode" msgstr "Alterna o modo de entrada" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "Metade" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "Alterna para letras em meia largura" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "Completa" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "Alterna para letras em largura completa" #: engine/table.py:801 msgid "Letter width" msgstr "Largura de letras" #: engine/table.py:802 msgid "Switch letter width" msgstr "Alterna a largura das letras" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "Alterna para pontuação em meia largura" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "Alterna para pontuação em largura completa" #: engine/table.py:823 msgid "Punctuation width" msgstr "Largura de pontuações" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "Alterna a largura das pontuações" #: engine/table.py:835 msgid "Switch to table mode" msgstr "Alterna para modo da tabela" #: engine/table.py:840 msgid "Pinyin" msgstr "Pinyin" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "Alterna para modo pinyin" #: engine/table.py:845 msgid "Pinyin mode" msgstr "Modo pinyin" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "Alterna o modo pinyin" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "Sugestões desabilitadas" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "Alterna para modo sugestão" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "Sugestão habilitada" #: engine/table.py:867 msgid "Suggestion mode" msgstr "Modo sugestão" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "Alterna o modo sugestão" #: engine/table.py:878 msgid "Multiple character match" msgstr "Correspondência de várias caracteres" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "Alterna para corresponder vários caracteres de uma vez" #: engine/table.py:885 msgid "Single character match" msgstr "Correspondência de um caractere" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "Alterna para corresponder um só caractere" #: engine/table.py:891 msgid "Onechar mode" msgstr "Modo um caractere" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "Alterna o modo de um caractere" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "Normal" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" "Alterna para o modo de envio normal (os envios automáticos entram em pré-" "edição, e não no aplicativo. Isso permite definições automáticas de novos " "atalhos)" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" "Alterna para o modo de envio direto (envios automáticos vão diretamente para " "o aplicativo)" #: engine/table.py:919 msgid "Auto commit mode" msgstr "Modo de envio automático" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "Alterna o modo de envio automático" #: engine/table.py:2946 msgid "Setup" msgstr "Configuração" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "Configura “%(engine-name)s” do ibus-table" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "Entrada de teclado" #: engine/it_util.py:943 msgid "Cancel" msgstr "Cancelar" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "Pressione uma tecla (ou uma combinação de teclas)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "O diálogo será fechado quando a chave é liberada" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "O método de entrada da tabela para IBus." #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "Glaucia Cintra" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "Documentação online:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "Tabela do Ibus" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "Método de entrada baseado em tabela" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" "Ibus-table é uma framework de método de entrada para métodos de entrada " "baseados em tabela. É usado principalmente para métodos de entrada chineses, " "como ZhengMa, WuBi, ErBi, CangJie, …. Mas algumas tabelas para outros " "idiomas também estão disponíveis." #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "Preferências" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "Estado inicial" #: setup/main.py:115 msgid "Direct input" msgstr "Entrada direta" #: setup/main.py:116 msgid "Table input" msgstr "Entrada da tabela" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Preferências" #: setup/main.py:212 msgid "About" msgstr "Sobre" #: setup/main.py:220 msgid "Restore all defaults" msgstr "Restaurar o padrão" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "_Fechar" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Configurações" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Detalhes" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "Associações de tecla" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 #, fuzzy #| msgid "Input mode" msgid "Remember input mode" msgstr "Modo de entrada" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 #, fuzzy #| msgid "" #| "“Direct input” is almost the same as if the\n" #| "input method were off, i.e. not used at all, most\n" #| "characters just get passed to the application.\n" #| "But some conversion between fullwidth and\n" #| "halfwidth may still happen in direct input mode.\n" #| "“Table input” means the input method is on." msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" "“Entrada direta” é quase o mesmo que se o método\n" "de entrada estivesse desativado, ou seja, não\n" "fosse usado, a maioria dos caracteres é passada\n" "para o aplicativo. Mas algumas conversões entre\n" "meia largura e largura completa ainda podem\n" "ocorrer no modo de entrada direta.\n" "“Entrada da tabela” significa que o método de\n" "entrada está ativado." #: setup/main.py:323 msgid "No" msgstr "Não" #: setup/main.py:325 msgid "Yes" msgstr "Sim" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "Modo Chinês:" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" "“Chinês simplificado” mostra apenas caracteres usados\n" "no chinês simplificado. “Chinês tradicional” mostra\n" "apenas caracteres usados no chinês tradicional.\n" "“Chinês simplificado antes do tradicional” mostra todos\n" "os caracteres, mas coloca os caracteres simplificados\n" "mais altos na lista de candidatos. “Chinês tradicional\n" "antes de simplificado” coloca os caracteres tradicionais\n" "mais altos na lista de candidatos. “Todos os caracteres”\n" "mostra apenas todas as correspondências sem nenhum filtro\n" "específico em chinês tradicional versus simplificado." #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "Chinês simplificado antes do tradicional" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "Chinês Tradicional antes do simplificado" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "Largura da letra da entrada da tabela:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" "Se deve-se usar letras com meia largura\n" "ou largura completa no modo entrada da\n" "tabela." #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "Largura da pontuação da entrada da tabela:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" "Se deve-se usar pontuações com meia largura\n" "ou largura completa no modo entrada da\n" "tabela." #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "Largura da letra da entrada direta:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" "Se deve-se usar letras com meia largura\n" "ou largura completa no modo entrada\n" "direita." #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "Largura da pontuação da entrada direita:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" "Se deve-se usar pontuações com meia largura\n" "ou largura completa no modo entrada\n" "direita." #: setup/main.py:590 msgid "Candidate list" msgstr "Lista de candidatos" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "Mostrar lista de candidatos" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" "Se as listas de candidatos devem ser mostradas ou\n" "ocultadas. Para métodos de entrada em chinês,\n" "geralmente se deseja que as listas de candidatos sejam\n" "mostradas. Mas, para alguns métodos de entrada não\n" "chineses, como o “translit” russo, é melhor ocultar as\n" "listas de candidatos." #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "Orientação:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" "Se a tabela de pesquisa que mostra os candidatos\n" "deve ser vertical ou horizontal." #: setup/main.py:640 msgid "Horizontal" msgstr "Horizontal" #: setup/main.py:642 msgid "Vertical" msgstr "Vertical" #: setup/main.py:644 msgid "System default" msgstr "Padrão do sistema" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Tamanho da página:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" "O número máximo de candidatos em uma página\n" "da tabela de pesquisa. Você pode alternar as\n" "páginas na tabela de pesquisa usando as teclas\n" "para cima/baixo da página ou as teclas de seta\n" "para cima/baixo." #: setup/main.py:696 msgid "Current key bindings:" msgstr "Associações de tecla atual:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Comando" #: setup/main.py:752 msgid "Edit" msgstr "Editar" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "Edita as associações de tecla para o comando selecionado" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "Definir com o padrão" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "Define associações de teclas padrão para o comando selecionado" #: setup/main.py:778 msgid "Set all to default" msgstr "Definir todos com o padrão" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "Define associações de teclas padrão para todos os comandos" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "Ajuste dinâmico" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" "Aqui você pode escolher se a ordem dos candidatos é ajustada dinamicamente " "de acordo com a frequência em que os candidatos são usados." #: setup/main.py:824 msgid "Delete all learned data" msgstr "Excluir dados aprendidos" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "Compor:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" "Se isso estiver definido como “caractere único”,\n" "apenas candidatos a caracteres únicos serão\n" "mostrados. Se estiver definido como “Frase”,\n" "poderão ser exibidos candidatos que consistem\n" "em vários caracteres." #: setup/main.py:862 msgid "Phrase" msgstr "Frase" #: setup/main.py:864 msgid "Single Char" msgstr "Caractere único" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "Selecionar automaticamente" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" "Se definido como “Sim”, isso faz as 4 coisas a seguir:\n" "1) Ao digitar “Enter”, envia o\n" " candidato + o feed de linha\n" "2) Ao digitar Tab, envia o candidato\n" "3) Ao enviar usando uma tecla de envio, envia\n" " o candidato + “ ”\n" "4) Se digitar o próximo caractere não corresponder\n" " a um candidato, envia o primeiro candidato da\n" " correspondência anterior.\n" " (Principalmente necessário para métodos de entrada\n" " não chineses, como o “translit” russo)" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "Modo de envio automático:" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" "O envio com as teclas de envio ou com o mouse sempre se\n" "envia no aplicativo. Esta opção é sobre envios\n" "“automáticos”, que podem ocorrer quando alguém continua\n" "digitando a entrada sem enviar manualmente. De tempos\n" "em tempos, envios “automáticos” acontecerão.\n" "“Direto” significa que esses envios “automáticos” vão\n" "diretamente para o aplicativo, “Normal” significa que\n" "elas se comprometem a pré-edição." #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "Curinga automático" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" "Se sim, um curinga múltiplo será automaticamente\n" "anexado ao final da sequência de entrada." #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "caractere curinga único:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "O curinga para corresponder a qualquer caractere único.\n" "Digite ENTER para enviar após alterar o curinga." #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "Caractere curinga múltiplo:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "O curinga usado para corresponder qualquer número de caracteres.\n" "Digite ENTER para enviar após alterar o curinga." #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "Usar tema escuro" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "Se sim, o esquema de cores para um tema escuro será usado." #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "Reproduzir arquivo de som ao ocorrer erro" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" "Aqui você pode escolher se um arquivo de som é reproduzido se ocorrer um " "erro. Se o módulo simpleaudio para Python3 não estiver instalado, esta opção " "faz nada." #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "Nível de depuração:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" "Quando maior que 0, as informações de depuração podem ser impressas para o " "arquivo de log e também podem ser mostradas graficamente." #: setup/main.py:1529 msgid "Are you sure?" msgstr "Você tem certeza?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_Cancelar" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "_OK" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "Outra instância deste aplicativo já está em execução." #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "Você realmente deseja restaurar todas as configurações padrão?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" "Você realmente deseja excluir todos os dados aprendidos a partir da " "digitação e seleção de candidatos?" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "Selecionar arquivo de som .wav:" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "Editar associações de tecla para o comando “%s”" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "Adicionar uma associação de tecla" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "Remover associação da tecla selecionada" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "Mover associação de tecla para cima" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "Mover associação de tecla para baixo" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" "Deseja realmente definir as associações de teclas de todos os comandos para " "o padrão?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "ibus não está em execução." #~ msgid "IBUS_ENGINE_NAME environment variable is not set." #~ msgstr "A variável de ambiente IBUS_ENGINE_NAME não está definida." #~ msgid "" #~ "Cannot determine the engine name. Please use the --engine-name option." #~ msgstr "" #~ "Não é possível determinar o nome do mecanismo. Por favor, use a opção --" #~ "engine-name." #~ msgid "IBus Table engine %s is not available" #~ msgstr "O motor do Tabela IBus %s não está disponível" #~ msgid "Next Page" #~ msgstr "Próxima página" #~ msgid "Restore defaults as specified in the database for this engine." #~ msgstr "" #~ "Restaura o padrão conforme especificado no banco de dados para este motor." #~ msgid "Input mode:" #~ msgstr "Modo de entrada:" #~ msgid "" #~ "If you choose the space key to do “Next page”,\n" #~ " you can only commit using the selection keys\n" #~ "(i.e. the labels in front of the candidates in the\n" #~ "lookup table) or using the mouse." #~ msgstr "" #~ "Se você escolher a tecla de espaço para executar a “Próxima página”, " #~ "poderá confirmar apenas com as teclas de seleção (ou seja, os rótulos na " #~ "frente dos candidatos na tabela de pesquisa) ou com o mouse." #~ msgid "Behavior of space key:" #~ msgstr "Comportamento da tecla de espaço:" #~ msgid "Details" #~ msgstr "Detalhes" #~ msgid "" #~ "\n" #~ "Authors:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contributors:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgstr "" #~ "\n" #~ "Autores:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contribuidores:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" ibus-table-1.17.11/po/pt_PT.po000066400000000000000000001031321475513533100157240ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Yu Yuwei # This file is distributed under the same license as the PACKAGE package. # Manuela Silva , 2020. # Anonymous , 2020. # Mike FABIAN , 2021, 2022. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2022-08-10 07:19+0000\n" "Last-Translator: Mike FABIAN \n" "Language-Team: Portuguese (Portugal) \n" "Language: pt_PT\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: Weblate 4.13\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "Chinês Simplificado" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "Mudar para “chinês simplificado”." #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "Chinês Tradicional" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "Mudar para “chinês tradicional”." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "Primeiro, chinês simplificado" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "Mudar para \"chinês simplificado antes de tradicional\"." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "Primeiro, chinês tradicional" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "Mudar para \"chinês tradicional antes de simplificado\"." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "Todos os carateres chineses" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "Mudar para “todos os carateres chineses”." #: engine/table.py:735 msgid "Chinese mode" msgstr "Modo chinês" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "Mudar modo chinês" #: engine/table.py:747 msgid "English" msgstr "Inglês" #: engine/table.py:748 msgid "Switch to English input" msgstr "Mudar para entrada em inglês" #: engine/table.py:755 msgid "Chinese" msgstr "Chinês" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "Mudar para entrada em chinês" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "Direta" #: engine/table.py:765 msgid "Switch to direct input" msgstr "Mudar para entrada direta" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "Tabela" #: engine/table.py:771 msgid "Switch to table input" msgstr "Mudar para entrada de tabela" #: engine/table.py:779 msgid "Input mode" msgstr "Modo de entrada" #: engine/table.py:780 msgid "Switch Input mode" msgstr "Mudar modo de entrada" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "Metade" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "Mudar para letras de metade da largura" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "Completa" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "Mudar para letras de largura completa" #: engine/table.py:801 msgid "Letter width" msgstr "Largura da letra" #: engine/table.py:802 msgid "Switch letter width" msgstr "Mudar largura da letra" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "Mudar para pontuação com meia largura" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "Mudar para pontuação de largura completa" #: engine/table.py:823 msgid "Punctuation width" msgstr "Largura de pontuação" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "Mudar largura de pontuação" #: engine/table.py:835 msgid "Switch to table mode" msgstr "Mudar para modo de tabela" #: engine/table.py:840 msgid "Pinyin" msgstr "Pinyin" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "Mudar para modo pinyin" #: engine/table.py:845 msgid "Pinyin mode" msgstr "Modo pinyin" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "Mudar modo pinyin" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "Sugestão desativada" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "Mudar para modo de sugestão" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "Sugestão ativada" #: engine/table.py:867 msgid "Suggestion mode" msgstr "Modo de sugestão" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "Mudar modo de sugestão" #: engine/table.py:878 msgid "Multiple character match" msgstr "Correspondência de vários carateres" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "Mudar para corresponder vários carateres ao mesmo tempo" #: engine/table.py:885 msgid "Single character match" msgstr "Correspondência de um caráter" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "Mudar para corresponder apenas carateres únicos" #: engine/table.py:891 msgid "Onechar mode" msgstr "Modo um caráter" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "Mudar modo de um caráter" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "Normal" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" "Mude para o modo de confirmação normal (as confirmações automáticas entram " "no pré-editar, e não na aplicação. Isto permite definições automáticas de " "novos atalhos)" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" "Mude para o modo de confirmação direta (as confirmações automáticas entram " "diretamente na aplicação)" #: engine/table.py:919 msgid "Auto commit mode" msgstr "Modo de confirmação automática" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "Mudar modo de confirmação automática" #: engine/table.py:2946 msgid "Setup" msgstr "Configuração" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "Configurar tabela ibus “%(engine-name)s”" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 #, fuzzy #| msgid "Table input" msgid "Key input" msgstr "Entrada de tabela" #: engine/it_util.py:943 msgid "Cancel" msgstr "Cancelar" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "Método de entrada de tabela para IBus" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "Manuela Silva" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "Documentação on-line:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "Tabela Ibus" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "Tabela baseada no modo de entrada" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" "Tabela Ibus é uma estrutura de método de entrada para métodos de entrada " "baseados em tabela. É utilizado principalmente para os métodos de entrada " "chineses, tais como ZhengMa, WuBi, ErBi, CangJie, …. Mas também estão " "disponíveis algumas tabelas para outros idiomas." #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "Preferências" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "Estado inicial" #: setup/main.py:115 msgid "Direct input" msgstr "Entrada direta" #: setup/main.py:116 msgid "Table input" msgstr "Entrada de tabela" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Preferências" #: setup/main.py:212 msgid "About" msgstr "Sobre" #: setup/main.py:220 msgid "Restore all defaults" msgstr "Restaurar todas as predefinições" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "_Fechar" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Definições" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Detalhes" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 #, fuzzy #| msgid "Input mode" msgid "Remember input mode" msgstr "Modo de entrada" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 #, fuzzy #| msgid "" #| "“Direct input” is almost the same as if the\n" #| "input method were off, i.e. not used at all, most\n" #| "characters just get passed to the application.\n" #| "But some conversion between fullwidth and\n" #| "halfwidth may still happen in direct input mode.\n" #| "“Table input” means the input method is on." msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" "“Entrada direta” é quase o mesmo que o método de\n" "entrada, onde, por exemplo, não utilizado, a maioria dos\n" "carateres passam apenas para a aplicação. Mas ainda\n" "poderá ocorrer alguma conversão entre a largura total e\n" "a metade no modo de entrada direta. “Entrada de Tabela”\n" "significa que o método de entrada está ativado." #: setup/main.py:323 msgid "No" msgstr "Não" #: setup/main.py:325 msgid "Yes" msgstr "Sim" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "Modo chinês:" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" "“Chinês Simplificado” mostra apenas carateres \n" "utilizados no chinês simplificado. “Chinês Traditional”\n" "mostra apenas carateres utilziados no chinês tradicional.\n" "“Chinês Simplificado antes do tradicional” mostra todos\n" "os carateres mas coloca os carateres simplificados\n" "no topo da lista de candidatos. “Chinês Tradicional antes\n" "do simplificado” coloca os carateres tradicionais no topo\n" "da lista de candidatos. “Todos os carateres” mostra apenas\n" "todas as correspondências sem qualquer filtragem em\n" "particular no chinês tradicional ''versus'' o chinês simplificado." #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "Chinês Simplificado antes do tradicional" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "Chinês Tradicional antes do simplificado" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "Largura da letra da entrada de tabela:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" "Se utiliza as letras de largura total ou metade\n" "da largura no modo de entrada de tabela." #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "Largura de pontuação de entrada de tabela:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" "Se utiliza a pontuação de largura total ou metade\n" "da largura no modo de entrada de tabela." #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "Largura da letra de entrada direta:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" "Se utiliza as letras de largura total ou metade\n" "da largura no modo de entrada direta." #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "Largura de pontuação de entrada direta:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" "Se utiliza a pontuação de largura total ou metade\n" "da largura no modo de entrada direta." #: setup/main.py:590 #, fuzzy #| msgid "Candidate list" msgid "Candidate list" msgstr "Lista de candidatos" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "Mostrar lista de candidatos" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" "Se as listas de candidato deverão ser mostradas ou ocultadas.\n" "Para os métodos de entrada chineses, normalmente requerem\n" "as listas de candidato para serem mostradas. Mas para alguns\n" "métodos de entrada não chineses, tal como russo “translit”, \n" "ocultar as listas de candidato é o melhor." #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "Orientação:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" "Se a tabela de pesquisa que mostra os candidatos\n" "deverá ser vertical ou horizontal." #: setup/main.py:640 msgid "Horizontal" msgstr "Horizontal" #: setup/main.py:642 msgid "Vertical" msgstr "Vertical" #: setup/main.py:644 msgid "System default" msgstr "Predefinição do sistema" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Tamanho da página:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" "O número máximo de candidatos numa\n" "página da tabela de pesquisa. Pode mudar de\n" "páginas nesta tabela utilizando as teclas\n" " \"PgUp\"/\"PgDn\" ou as teclas seta para cima/baixo." #: setup/main.py:696 msgid "Current key bindings:" msgstr "" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Comando" #: setup/main.py:752 msgid "Edit" msgstr "Editar" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "Definir para predefinição" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "" #: setup/main.py:778 msgid "Set all to default" msgstr "Definir tudo para predefinição" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "Compor:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" "Se isto estiver definido para “único caráter”, será\n" "mostrado apenas o caráter candidato. Se isto\n" "estiver definido para “Frase” poderão ser mostrados\n" "os candidatos consistindo em vários carateres." #: setup/main.py:862 msgid "Phrase" msgstr "Frase" #: setup/main.py:864 msgid "Single Char" msgstr "Caráter Único" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "Auto-selecionar" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" "Se definido para “Sim”, isto faz as 4 coisas seguintes:\n" "1) Quando digita “Return”, confirma o \n" " candidato + linha fonte\n" "2) Quando digitar \"Tab\", confirma o candidato\n" "3) Quando confirmar utilizando uma tecla ''confirmar'', \n" " confirma o candidato + \" \"\n" "4) Se digitar o caráter seguinte não corresponde candidatos,\n" " confirma o primeiro candidato da correspondência anterior.\n" " (Principalmente necessário para métodos de entrada não \n" " chineses, tal como russo “translit”)" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "Modo de confirmação automática:" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" "Confirmando com as teclas de confirmação ou com o rato\n" "confirma sempre com a aplicação. Esta opção é sobre\n" "confirmações “automáticas” que podem acontecer quando\n" "um só continua a digitar a entrada sem confirmar\n" "manualmente. De tempos em tempos, então, as confirmações \n" "“automáticas” irão ocorrer.\n" "“Direto” significa que tais confirmações “automáticas” vão diretamente\n" "para a aplicação, \"Normal\" significa que elas são comprometem\n" "confirmadas para pré-editar." #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "Caráter de substituição automático" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" "Se sim, um caráter de substituição será anexado\n" "automaticamente no final da sequência de entrada." #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "Caráter de substituição único:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "O caráter de substituição para corresponder qualquer caráter único.\n" "Toque RETURN ou ENTER para confirmar depois de alterar este cárater." #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "Caráter de substituição múltiplo:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "O caráter de substituição utilizado para corresponder qualquer número de " "carateres. \n" "Digite \"RETURN\" ou pressione \"ENTER\" para confirmar depois de alterar o " "caráter de substituição." #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "Nível de depuração:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" #: setup/main.py:1529 msgid "Are you sure?" msgstr "" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "Cancelar" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" #: setup/main.py:3037 msgid "ibus is not running." msgstr "" #~ msgid "IBUS_ENGINE_NAME environment variable is not set." #~ msgstr "A variável de ambiente IBUS_ENGINE_NAME não está definida." #~ msgid "" #~ "Cannot determine the engine name. Please use the --engine-name option." #~ msgstr "" #~ "Não é possível determinar o nome do mecanismo. Por favor, use a opção --" #~ "engine-name." #~ msgid "IBus Table engine %s is not available" #~ msgstr "O mecanismo %s da Tabela IBus não está disponível" #~ msgid "Next Page" #~ msgstr "Página Seguinte" #~ msgid "Restore defaults as specified in the database for this engine." #~ msgstr "" #~ "Restaurar as predefinições como especificado na base de dados para este " #~ "mecanismo." #~ msgid "Input mode:" #~ msgstr "Modo de entrada:" #~ msgid "" #~ "If you choose the space key to do “Next page”,\n" #~ " you can only commit using the selection keys\n" #~ "(i.e. the labels in front of the candidates in the\n" #~ "lookup table) or using the mouse." #~ msgstr "" #~ "Se escolher a tecla de espaço para executar a \"Página Seguinte\", \n" #~ "só pode confirmar utilizando as chaves de seleção (ou seja, as \n" #~ "etiquetas na frente dos candidatos na tabela de pesquisa) \n" #~ "ou utilizando o rato." #~ msgid "Behavior of space key:" #~ msgstr "Comportamento da tecla de espaço:" #~ msgid "Details" #~ msgstr "Detalhes" #~ msgid "" #~ "\n" #~ "Authors:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contributors:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgstr "" #~ "\n" #~ "Autores:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Colaboradores:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" ibus-table-1.17.11/po/ru.po000066400000000000000000001154441475513533100153350ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Yu Yuwei # This file is distributed under the same license as the PACKAGE package. # "Sergey A." , 2023, 2024. # "Sergey A." , 2025. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2025-02-15 15:51+0000\n" "Last-Translator: \"Sergey A.\" \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 5.9.2\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "Упрощенный китайский" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "Переключиться в режим «Только упрощенный китайский»." #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "Традиционный китайский" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "Переключиться в режим «Только традиционный китайский»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "Сначала упрощенный китайский" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "Переключиться в режим «Упрощенный китайский перед традиционным»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "Сначала традиционный китайский" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "Переключиться в режим «Традиционный китайский перед упрощённым»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "Все китайские иероглифы" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "Переключиться в режим «Все китайские иероглифы»." #: engine/table.py:735 msgid "Chinese mode" msgstr "Китайский режим" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "Переключить в режим китайского языка" #: engine/table.py:747 msgid "English" msgstr "Английский" #: engine/table.py:748 msgid "Switch to English input" msgstr "Переключиться на английский ввод" #: engine/table.py:755 msgid "Chinese" msgstr "Китайский" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "Переключиться на китайский ввод" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "Прямой" #: engine/table.py:765 msgid "Switch to direct input" msgstr "Переключиться на прямой ввод" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "Таблица" #: engine/table.py:771 msgid "Switch to table input" msgstr "Переключиться на ввод по таблице" #: engine/table.py:779 msgid "Input mode" msgstr "Режим ввода" #: engine/table.py:780 msgid "Switch Input mode" msgstr "Переключить режим ввода" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "Половинная" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "Переключиться на буквы половинной ширины" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "Полная" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "Переключиться на буквы полной ширины" #: engine/table.py:801 msgid "Letter width" msgstr "Ширина буквы" #: engine/table.py:802 msgid "Switch letter width" msgstr "Переключить ширину буквы" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "Переключиться на полуширинную пунктуацию" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "Переключиться на полноширинную пунктуацию" #: engine/table.py:823 msgid "Punctuation width" msgstr "Ширина знаков препинания" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "Переключить ширину знаков препинания" #: engine/table.py:835 msgid "Switch to table mode" msgstr "Переключиться в режим таблицы" #: engine/table.py:840 msgid "Pinyin" msgstr "Пиньинь" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "Переключиться на режим пиньинь" #: engine/table.py:845 msgid "Pinyin mode" msgstr "Режим пиньинь" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "Переключить режим пиньинь" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "Предложения отключены" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "Переключиться на режим предложений" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "Предложения включены" #: engine/table.py:867 msgid "Suggestion mode" msgstr "Режим предложений" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "Переключить режим предложений" #: engine/table.py:878 msgid "Multiple character match" msgstr "Совпадение нескольких символов" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "Переключиться на совпадение сразу по нескольким символам" #: engine/table.py:885 msgid "Single character match" msgstr "Совпадение по одному символу" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "Переключиться на совпадение только по одному символу" #: engine/table.py:891 msgid "Onechar mode" msgstr "Односимвольный режим" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "Переключить односимвольный режим" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "Обычный" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" "Переключиться на обычный режим передачи (автоматическая отправка выполняется " "в средство предварительного редактирования, а не в саму программу. С помощью " "этого пункта можно включить автоматическое определение новых клавиатурных " "комбинаций)" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" "Переключиться в режим прямой передачи (автоматическая передача данных " "выполняется непосредственно в приложении)" #: engine/table.py:919 msgid "Auto commit mode" msgstr "Режим автопередачи" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "Переключить режим автопередачи" #: engine/table.py:2946 msgid "Setup" msgstr "Настройка" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "Настройка «%(engine-name)s» для ibus-table" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "Ввод клавиши" #: engine/it_util.py:943 msgid "Cancel" msgstr "Отменить" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "Нажмите клавишу (или комбинацию клавиш)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "Диалоговое окно будет закрыто, когда клавиша будет отпущена" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "Табличный метод ввода для IBus." #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "Ser82-png , 2023" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "Онлайн-документация:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "Таблица Ibus" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "Метод ввода основанный на таблице" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" "Ibus-table - это фреймворк способов ввода символов основанных на таблицах. В " "основном используется для методов ввода китайских символов, таких как " "ZhengMa, WuBi, ErBi, CangJie, …. Но также доступны некоторые таблицы для " "других языков." #: setup/ibus-setup-table.desktop.in.in:3 msgid "IBus Table Preferences" msgstr "Параметры таблицы IBus" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "Установить параметры таблицы IBus" #: setup/main.py:114 msgid "Initial state" msgstr "Начальное состояние" #: setup/main.py:115 msgid "Direct input" msgstr "Прямой ввод" #: setup/main.py:116 msgid "Table input" msgstr "Ввод по таблице" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Параметры" #: setup/main.py:212 msgid "About" msgstr "О приложении" #: setup/main.py:220 msgid "Restore all defaults" msgstr "Восстановить все настройки по умолчанию" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "_Закрыть" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Настройки" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Детали" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "Привязки клавиш" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "Запомнить режим ввода" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" #: setup/main.py:323 msgid "No" msgstr "Нет" #: setup/main.py:325 msgid "Yes" msgstr "Да" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "Китайский режим:" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" "В режиме «Упрощённый китайский» будут показаны символы,\n" "используемые в упрощённой китайской записи. В режиме\n" "«Традиционный китайский» будут показаны традиционные\n" "китайские иероглифы. В режиме «Упрощённый китайский\n" "перед традиционным» будут показаны все символы,\n" "но упрощённые окажутся в верхней части списка вариантов.\n" "В режиме «Традиционный китайский перед упрощённым»\n" "будут показаны все символы, но традиционные окажутся в\n" "верхней части списка вариантов. В режиме «Все символы»\n" "будут показаны все совпадения без какой-либо фильтрации." #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "Упрощенный китайский перед традиционным" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "Традиционный китайский перед упрощённым" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "Ширина букв в режиме ввода по таблице:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" "Определяет, использовать ли полноширинные или\n" "полуширинные буквы в режиме ввода по таблице." #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "Ширина знаков препинания в режиме ввода по таблице:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" "Определяет, использовать ли полноширинные или\n" "полуширинные знаки препинания в режиме ввода по таблице." #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "Ширина букв в режиме прямого ввода:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" "Определяет, использовать ли полноширинные или\n" "полуширинные буквы в режиме прямого ввода." #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "Ширина знаков препинания в режиме прямого ввода:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" "Определяет, использовать ли полноширинные или\n" "полуширинные знаки препинания в режиме прямого ввода." #: setup/main.py:590 msgid "Candidate list" msgstr "Список вариантов" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "Показать список вариантов" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" "Определяет, следует ли показывать список вариантов.\n" "Для методов китайского ввода следует видеть список\n" "вариантов. Но для некоторых способов введения\n" "языков отличных от китайского, в частности кириллического\n" "«translit», потребности в показе списка вариантов нет." #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "Ориентация:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" "Определяет, таблица вариантов должна\n" "быть вертикальной или горизонтальной." #: setup/main.py:640 msgid "Horizontal" msgstr "Горизонтальная" #: setup/main.py:642 msgid "Vertical" msgstr "Вертикальная" #: setup/main.py:644 msgid "System default" msgstr "Системные по умолчанию" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Размер страницы:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" "Максимальное количество вариантов на одной\n" "странице таблицы поиска. Переход между страницами\n" "в таблице поиска осуществляется с помощью\n" "клавиш «Page Up/Down» или стрелками «Вверх/Вниз»." #: setup/main.py:696 msgid "Current key bindings:" msgstr "Текущие привязки клавиш:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Команда" #: setup/main.py:752 msgid "Edit" msgstr "Редактировать" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "Редактировать привязки клавиш для выбранной команды" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "Установить по умолчанию" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "Установить привязки клавиш по умолчанию для выбранной команды" #: setup/main.py:778 msgid "Set all to default" msgstr "Установить по умолчанию для всех" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "Установить привязки клавиш по умолчанию для всех команд" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "Динамическая корректировка" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" "Здесь вы можете выбрать, будет ли динамически корректироваться порядок " "вариантов в зависимости от частоты их использования." #: setup/main.py:824 msgid "Delete all learned data" msgstr "Удалить все изученные данные" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "Составление:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" "Если установлено значение «Одиночный символ»,\n" "будут показаны варианты только из одного символа.\n" "Если установлено значение «Фраза», будут\n" "показаны и варианты, состоящие из нескольких символов." #: setup/main.py:862 msgid "Phrase" msgstr "Фраза" #: setup/main.py:864 msgid "Single Char" msgstr "Одиночный символ" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "Автовыбор" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" "Если установлено значение «Да», то будет выполняться одно из 4 действий:\n" "1) При нажатии «Enter», будет отправлен \n" " вариант + символ перехода на новую строку\n" "2) При нажатии «Tab», будет отправлен вариант\n" "3) При использовании кнопки отправки,\n" " будет отправлен вариант + \" \"\n" "4) Если при вводе следующего символа не будет совпадений ни с одним\n" " из возможных вариантов, будет отправлен первый вариант предыдущего " "совпадения.\n" " (В основном это необходимо для некитайских\n" " методов ввода, таких как русский «translit»)" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "Режим автопередачи:" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "Действия при вводе недопустимого символа:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" "Определяет, что произойдет, когда будет введён символ, отсутствующий в " "наборе допустимых входных символов для этой таблицы: если выбрать «Передать " "текущее предложение», будет вставлен текущий выделенный вариант. Если " "выбрать «Передать введённые символы», будут вставлены символы без обработки, " "которые были введены в процессе выбора варианта. В любом случае, выбор " "варианта завершается при вводе некорректного символа, и соответствующий " "символ будет немедленно вставлен после текста, который является результатом " "применения параметров из приведенного выше списка." #: setup/main.py:983 msgid "Commit current candidate" msgstr "Передать текущее предложение" #: setup/main.py:985 msgid "Commit typed keys" msgstr "Передать введённые символы" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "Автозамена" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" "При включении в конце строки ввода автоматически\n" "будет добавлен символ множественной замены." #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "Заменитель для одиночного символа:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "Заменитель любого одиночного символа.\n" "Нажмите RETURN или ENTER для подтверждения после смены заменителя." #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "Заменитель для любого количества символов:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "Заменитель произвольного количества символов.\n" "Нажмите RETURN или ENTER для подтверждения после смены заменителя." #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "Использовать тёмную тему" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "Если указано «да», будет использоваться цветовая схема тёмной темы." #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "При возникновении ошибки воспроизвести звуковой файл" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" "Здесь вы можете выбрать, будет ли воспроизводиться звуковой файл в случае " "возникновения ошибки. Если модуль simpleaudio для Python3 не установлен, это " "пункт ни на что не будет влиять." #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "Уровень отладки:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" "Если значение больше 0, к файлу журнала могут быть добавлены диагностические " "данные, отладочная информация, которые также могут быть показаны в " "графическом интерфейсе." #: setup/main.py:1529 msgid "Are you sure?" msgstr "Вы уверены?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_Отменить" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "_OK" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "Другой экземпляр этого приложения уже запущен." #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "" "Вы действительно хотите восстановить все настройки до значений, " "установленных по умолчанию?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" "Вы действительно хотите удалить все данные, которые были получены на основе " "введённых и выбранных вариантов?" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "Выбрать звуковой файл .wav:" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "Изменить привязку клавиш для команды «%s»" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "Добавить привязку клавиш" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "Удалить выбранную привязку клавиш" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "Переместить привязку клавиш выше" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "Переместить привязку клавиш ниже" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" "Вы действительно хотите установить для всех команд привязки клавиш, " "установленные по умолчанию?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "ibus не запущено." ibus-table-1.17.11/po/si.po000066400000000000000000000616531475513533100153240ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Yu Yuwei # This file is distributed under the same license as the PACKAGE package. # Hela Basa , 2021. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2023-05-30 06:20+0000\n" "Last-Translator: Anonymous \n" "Language-Team: Sinhala \n" "Language: si\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: Weblate 4.17\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "" #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "" #: engine/table.py:735 msgid "Chinese mode" msgstr "" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "" #: engine/table.py:747 msgid "English" msgstr "" #: engine/table.py:748 msgid "Switch to English input" msgstr "" #: engine/table.py:755 msgid "Chinese" msgstr "චීන" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "" #: engine/table.py:765 msgid "Switch to direct input" msgstr "" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "වගුව" #: engine/table.py:771 msgid "Switch to table input" msgstr "" #: engine/table.py:779 msgid "Input mode" msgstr "ආදාන ක්‍රමය" #: engine/table.py:780 msgid "Switch Input mode" msgstr "ආදාන ක්‍රමය මාරුව" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "" #: engine/table.py:801 msgid "Letter width" msgstr "" #: engine/table.py:802 msgid "Switch letter width" msgstr "" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "" #: engine/table.py:823 msgid "Punctuation width" msgstr "" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "" #: engine/table.py:835 msgid "Switch to table mode" msgstr "" #: engine/table.py:840 msgid "Pinyin" msgstr "" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "" #: engine/table.py:845 msgid "Pinyin mode" msgstr "" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "" #: engine/table.py:867 msgid "Suggestion mode" msgstr "" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "" #: engine/table.py:878 msgid "Multiple character match" msgstr "" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "" #: engine/table.py:885 msgid "Single character match" msgstr "" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "" #: engine/table.py:891 msgid "Onechar mode" msgstr "" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" #: engine/table.py:919 msgid "Auto commit mode" msgstr "" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "" #: engine/table.py:2946 msgid "Setup" msgstr "" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "" #: engine/it_util.py:943 msgid "Cancel" msgstr "අවලංගු කරන්න" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "පරිවර්තන ස්තුතිය" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "අභිප්‍රේත" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "" #: setup/main.py:115 msgid "Direct input" msgstr "" #: setup/main.py:116 msgid "Table input" msgstr "" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "අභිප්‍රේත" #: setup/main.py:212 msgid "About" msgstr "පිළිබඳව" #: setup/main.py:220 msgid "Restore all defaults" msgstr "" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "වසන්න" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" #: setup/main.py:323 msgid "No" msgstr "නැත" #: setup/main.py:325 msgid "Yes" msgstr "ඔව්" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" #: setup/main.py:590 msgid "Candidate list" msgstr "" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" #: setup/main.py:640 msgid "Horizontal" msgstr "තිරස්" #: setup/main.py:642 msgid "Vertical" msgstr "සිරස්" #: setup/main.py:644 msgid "System default" msgstr "" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" #: setup/main.py:696 msgid "Current key bindings:" msgstr "" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "විධානය" #: setup/main.py:752 msgid "Edit" msgstr "" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "" #: setup/main.py:778 msgid "Set all to default" msgstr "" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" #: setup/main.py:862 msgid "Phrase" msgstr "" #: setup/main.py:864 msgid "Single Char" msgstr "" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" #: setup/main.py:1529 msgid "Are you sure?" msgstr "" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "අවලංගු කරන්න" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" #: setup/main.py:3037 msgid "ibus is not running." msgstr "" ibus-table-1.17.11/po/tr.po000066400000000000000000001060541475513533100153310ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Yu Yuwei # This file is distributed under the same license as the PACKAGE package. # Oğuz Ersen , 2019, 2020, 2021, 2022. # Mike FABIAN , 2019, 2021. # Anonymous , 2020. # Oğuz Ersen , 2022, 2023, 2025. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2025-01-19 19:57+0000\n" "Last-Translator: Oğuz Ersen \n" "Language-Team: Turkish \n" "Language: tr\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: Weblate 5.9.2\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "Basitleştirilmiş Çince" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "“Sadece Basitleştirilmiş Çince”ye geç." #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "Geleneksel Çince" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "“Sadece Geleneksel Çince”ye geç." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "Önce Basitleştirilmiş Çince" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "“Gelenekselden önce Basitleştirilmiş Çince”ye geç." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "Önce Geleneksel Çince" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "“Basitleştirilmişten önce Geleneksel Çince”ye geç." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "Tüm Çince karakterler" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "“Tüm Çince karakterler”e geç." #: engine/table.py:735 msgid "Chinese mode" msgstr "Çince modu" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "Çince modunu değiştir" #: engine/table.py:747 msgid "English" msgstr "İngilizce" #: engine/table.py:748 msgid "Switch to English input" msgstr "İngilizce girişe geç" #: engine/table.py:755 msgid "Chinese" msgstr "Çince" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "Çince girişe geç" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "Doğrudan" #: engine/table.py:765 msgid "Switch to direct input" msgstr "Doğrudan girişe geç" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "Tablo" #: engine/table.py:771 msgid "Switch to table input" msgstr "Tablo girişe geç" #: engine/table.py:779 msgid "Input mode" msgstr "Giriş modu" #: engine/table.py:780 msgid "Switch Input mode" msgstr "Giriş modunu değiştir" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "Yarım" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "Yarım genişlikteki harflere geç" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "Tam" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "Tam genişlikteki harflere geç" #: engine/table.py:801 msgid "Letter width" msgstr "Harf genişliği" #: engine/table.py:802 msgid "Switch letter width" msgstr "Harf genişliğini değiştir" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "Yarım genişlikteki noktalama işaretlerine geç" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "Tam genişlikteki noktalama işaretlerine geç" #: engine/table.py:823 msgid "Punctuation width" msgstr "Noktalama işareti genişliği" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "Noktalama işareti genişliğini değiştir" #: engine/table.py:835 msgid "Switch to table mode" msgstr "Tablo moduna geç" #: engine/table.py:840 msgid "Pinyin" msgstr "Pinyin" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "Pinyin moduna geç" #: engine/table.py:845 msgid "Pinyin mode" msgstr "Pinyin modu" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "Pinyin modunu değiştir" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "Öneri devre dışı bırakıldı" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "Öneri moduna geç" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "Öneri etkinleştirildi" #: engine/table.py:867 msgid "Suggestion mode" msgstr "Öneri modu" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "Öneri moduna geçiş yap" #: engine/table.py:878 msgid "Multiple character match" msgstr "Çoklu karakter eşleşmesi" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "Aynı anda birden fazla karakter eşleşmesine geç" #: engine/table.py:885 msgid "Single character match" msgstr "Tekli karakter eşleşmesi" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "Aynı anda sadece bir karakter eşleşmesine geç" #: engine/table.py:891 msgid "Onechar mode" msgstr "Tek karakter modu" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "Tek karakter modunu değiştir" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "Normal" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" "Normal seçim moduna geç (otomatik seçimler, uygulama yerine önce ön-" "düzenlemeye gider. Bu, yeni kısayolların otomatik olarak tanımlanmasını " "sağlar)" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" "Doğrudan seçim moduna geç (otomatik seçimler doğrudan uygulamaya gider)" #: engine/table.py:919 msgid "Auto commit mode" msgstr "Otomatik seçim modu" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "Otomatik seçim modunu değiştir" #: engine/table.py:2946 msgid "Setup" msgstr "Kurulum" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "Ibus-table \"%(engine-name)s\" yapılandır" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "Tuş girişi" #: engine/it_util.py:943 msgid "Cancel" msgstr "İptal" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "Lütfen bir tuşa (veya tuş dizisine) basın" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "Tuş serbest bırakıldığında iletişim kutusu kapatılacaktır" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "IBus için tablo giriş yöntemi." #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "Oğuz Ersen " #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "Çevrim içi belgelendirme:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "Ibus Tablosu" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "Tablo tabanlı giriş yöntemi" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" "Ibus-table, tablo tabanlı giriş yöntemleri için bir giriş yöntemi " "çerçevesidir. Çoğunlukla ZhengMa, WuBi, ErBi, CangJie, ... gibi Çince giriş " "yöntemleri için kullanılır. Ancak diğer diller için de kullanılabilir bazı " "tablolar bulunmaktadır." #: setup/ibus-setup-table.desktop.in.in:3 msgid "IBus Table Preferences" msgstr "IBus Tablosu Tercihleri" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "IBus Tablosu Seçeneklerini Ayarlayın" #: setup/main.py:114 msgid "Initial state" msgstr "Başlangıç durumu" #: setup/main.py:115 msgid "Direct input" msgstr "Doğrudan giriş" #: setup/main.py:116 msgid "Table input" msgstr "Tablo girişi" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Tercihler" #: setup/main.py:212 msgid "About" msgstr "Hakkında" #: setup/main.py:220 msgid "Restore all defaults" msgstr "Tüm öntanımlıları geri yükle" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "_Kapat" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Ayarlar" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Ayrıntılar" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "Tuş atamaları" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "Giriş modunu hatırla" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" "En son kullanılan giriş modunun hatırlanması mı yoksa ibus-table'ın yeniden " "başlatma sonrasında öntanımlı olarak “Tablo modunda” mı başlaması gerektiği. " "İki giriş modu vardır: “Tablo girişi”, giriş yönteminin açık olduğu anlamına " "gelir. “Doğrudan giriş”, giriş yönteminin kapalı olduğu durumla neredeyse " "aynıdır, yani hiç kullanılmaz, çoğu karakter uygulamaya iletilir. Ancak, " "doğrudan giriş modunda tam genişlik ve yarım genişlik arasında bir miktar " "dönüşüm gerçekleşebilir." #: setup/main.py:323 msgid "No" msgstr "Hayır" #: setup/main.py:325 msgid "Yes" msgstr "Evet" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "Çince modu:" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" "“Basitleştirilmiş Çince” sadece basitleştirilmiş \n" "Çince'de kullanılan karakterleri gösterir. “Geleneksel\n" "Çince” sadece geleneksel Çince'de kullanılan karakterleri\n" "gösterir. “Gelenekselden önce Basitleştirilmiş Çince” tüm\n" "karakterleri gösterir, ancak basitleştirilmiş karakterleri aday\n" "listesinde daha yukarı koyar. “Basitleştirilmişten önce\n" "Geleneksel Çince” geleneksel karakterleri aday listesinde\n" "daha yukarı koyar. “Tüm karakterler” geleneksel ile\n" "sadeleştirilmiş Çince arasında belirli bir filtreleme olmadan\n" "tüm eşleşmeleri gösterir." #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "Gelenekselden önce Basitleştirilmiş Çince" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "Basitleştirilmişten önce Geleneksel Çince" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "Tablo girişi harf genişliği:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" "Tablo giriş modunda tam genişlikli mi\n" "yarım genişlikli mi harflerin kullanılacağı." #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "Tablo girişi noktalama işareti genişliği:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" "Tablo giriş modunda tam genişlikli mi yarım\n" "genişlikli mi noktalama işaretlerinin kullanılacağı." #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "Doğrudan giriş harf genişliği:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" "Doğrudan giriş modunda tam genişlikli mi\n" "yarım genişlikli mi harflerin kullanılacağı." #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "Doğrudan giriş noktalama işareti genişliği:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" "Doğrudan giriş modunda tam genişlikli mi yarım\n" "genişlikli mi noktalama işaretlerinin kullanılacağı." #: setup/main.py:590 msgid "Candidate list" msgstr "Aday listesi" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "Aday listesini göster" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" "Aday listelerin gösterilip gösterilmemesi gerektiği.\n" "Çince giriş yöntemleri için genellikle aday listelerinin\n" "gösterilmesi istenir. Ancak, Rusça “translit” gibi Çince\n" "dışındaki bazı giriş yöntemleri için aday listelerini\n" "gizlemek daha iyidir." #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "Yön:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" "Adayları gösteren arama tablosunun dikey mi yatay\n" "mı olması gerektiği." #: setup/main.py:640 msgid "Horizontal" msgstr "Yatay" #: setup/main.py:642 msgid "Vertical" msgstr "Dikey" #: setup/main.py:644 msgid "System default" msgstr "Sistem ön tanımlı değeri" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Sayfa boyutu:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" "Arama tablosunun bir sayfasındaki en fazla\n" "aday sayısı. Page up/down tuşlarını veya yukarı/aşağı\n" "ok tuşlarını kullanarak arama tablosundaki sayfalar\n" "arasında geçiş yapabilirsiniz." #: setup/main.py:696 msgid "Current key bindings:" msgstr "Mevcut tuş atamaları:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Komut" #: setup/main.py:752 msgid "Edit" msgstr "Düzenle" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "Seçili komut için tuş atamalarını düzenle" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "Ön tanımlıya ayarla" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "Seçili komut için ön tanımlı tuş atamalarını ayarla" #: setup/main.py:778 msgid "Set all to default" msgstr "Tümünü ön tanımlıya ayarla" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "Tüm komutlar için ön tanımlı tuş atamalarını ayarla" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "Dinamik olarak ayarla" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" "Burada adayların sırasının, adayların ne sıklıkla kullanıldığına göre " "dinamik olarak ayarlanıp ayarlanmadığını seçebilirsiniz." #: setup/main.py:824 msgid "Delete all learned data" msgstr "Öğrenilen tüm verileri sil" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "Oluştur:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" "Bu “tek karakter” olarak ayarlanmışsa,\n" "sadece tek karakterli adaylar gösterilecektir.\n" "“İfade” olarak ayarlanmışsa, birkaç karakterden\n" "oluşan adaylar gösterilebilir." #: setup/main.py:862 msgid "Phrase" msgstr "İfade" #: setup/main.py:864 msgid "Single Char" msgstr "Tek Karakter" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "Otomatik seçim" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" "“Evet” olarak ayarlanmışsa, şu 4 şeyi yapar:\n" "1) “Return” tuşuna basıldığında, adayı \n" " seç + yeni satıra geç\n" "2) Tab tuşuna basıldığında, adayı seç\n" "3) Seçim tuşu kullanılarak seçildiğinde,\n" " adayı seç + \" \"\n" "4) Bir sonraki karakterin yazılması bir adayla eşleşmiyorsa,\n" " önceki eşleşmenin ilk adayını seç.\n" " (Genellikle Rusça \"translit\" gibi Çince dışındaki giriş\n" " yöntemleri için gereklidir)" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "Otomatik seçim modu:" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" "Seçim tuşları veya fare ile seçmek, her zaman\n" "seçimi uygulamaya gönderir. Bu seçenek, elle\n" "seçim yapmadan sadece yazmaya devam\n" "edildiğinde gerçekleşebilecek “otomatik” seçimlerle\n" "ilgilidir. Zaman zaman “otomatik” seçimler\n" "gerçekleşecektir.\n" "“Doğrudan”, böyle bir “otomatik” seçimin doğrudan\n" "uygulamaya gitmesi, “Normal” ise ön-düzenlemeye\n" "gönderilmesi anlamına gelir." #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "Geçersiz karakter yazıldığında yapılacak eylem:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" "Bu tablo için geçerli giriş karakterleri kümesinde olmayan bir karakter " "yazıldığında ne olacağını belirler: “geçerli adayı seç” ile, o anda seçili " "olan aday eklenir. “yazılan tuşları seç” ile, aday seçme işlemi sırasında o " "ana kadar yazılan karakterlerin kendisi eklenir. Her durumda, geçersiz bir " "karakter yazıldığında aday seçimi sona erer ve söz konusu karakter yukarıda " "listelenen seçeneklerden kaynaklanan metinden hemen sonra eklenir." #: setup/main.py:983 msgid "Commit current candidate" msgstr "Geçerli adayı seç" #: setup/main.py:985 msgid "Commit typed keys" msgstr "Yazılan tuşları seç" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "Otomatik joker" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" "Eğer evet ise, giriş dizgesinin sonuna otomatik\n" "olarak çoklu bir joker karakter eklenecektir." #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "Tekli joker karakteri:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "Herhangi bir tek karakterle eşleşen joker karakter.\n" "Joker karakteri değiştirdikten sonra onaylamak için RETURN veya ENTER tuşuna " "basın." #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "Çoklu joker karakteri:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "Herhangi bir sayıda karakterle eşleştirmek için kullanılan joker karakter.\n" "Joker karakteri değiştirdikten sonra onaylamak için RETURN veya ENTER tuşuna " "basın." #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "Koyu tema kullan" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "Evetse, koyu bir renk şeması kullanılacaktır." #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "Hata durumunda ses dosyası oynat" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" "Burada bir hata oluştuğunda bir ses dosyasının çalınıp çalınmayacağını " "seçebilirsiniz. Python3 için simpleaudio modülü kurulu değilse, bu seçenek " "hiçbir şey yapmaz." #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "Hata ayıklama seviyesi:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" "0'dan büyük olduğunda, hata ayıklama bilgisi log dosyasına yazdırılabilir ve " "hata ayıklama bilgisi grafiksel olarak da gösterilebilir." #: setup/main.py:1529 msgid "Are you sure?" msgstr "Emin misiniz?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_İptal" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "_Tamam" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "Bu uygulamanın başka bir örneği zaten çalışıyor." #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "Tüm öntanımlı ayarları gerçekten geri yüklemek istiyor musunuz?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" "Adayları yazarken ve seçerken öğrenilen tüm verileri gerçekten silmek " "istiyor musunuz?" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr ".wav ses dosyasını seçin:" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "“%s” komutu için atanan tuşları düzenle" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "Tuş ataması ekle" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "Seçilen tuş atamalarını kaldır" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "Tuş atamasını yukarı taşı" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "Tuş atamasını aşağı taşı" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" "Tüm komutların tuş atamalarını ön tanımlılarına ayarlamayı gerçekten istiyor " "musunuz?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "ibus çalışmıyor." #~ msgid "IBUS_ENGINE_NAME environment variable is not set." #~ msgstr "IBUS_ENGINE_NAME ortam değişkeni tanımlı değil." #~ msgid "" #~ "Cannot determine the engine name. Please use the --engine-name option." #~ msgstr "Motor adı belirlenemiyor. Lütfen --engine-name seçeneğini kullanın." #~ msgid "IBus Table engine %s is not available" #~ msgstr "%s IBus Tablo motoru kullanılamıyor" #~ msgid "Next Page" #~ msgstr "Sonraki Sayfa" #~ msgid "Restore defaults as specified in the database for this engine." #~ msgstr "" #~ "Bu motor için veri tabanında belirtildiği şekilde öntanımlıları geri " #~ "yükle." #~ msgid "Input mode:" #~ msgstr "Giriş modu:" #~ msgid "" #~ "If you choose the space key to do “Next page”,\n" #~ " you can only commit using the selection keys\n" #~ "(i.e. the labels in front of the candidates in the\n" #~ "lookup table) or using the mouse." #~ msgstr "" #~ "“Sonraki sayfa” için boşluk tuşunu seçerseniz,\n" #~ " sadece seçim tuşlarını (yani arama tablosundaki\n" #~ "adayların önündeki etiketler) veya fareyi kullanarak\n" #~ "seçim yapabilirsiniz." #~ msgid "Behavior of space key:" #~ msgstr "Space tuşunun davranışı:" #~ msgid "Details" #~ msgstr "Ayrıntılar" #~ msgid "" #~ "\n" #~ "Authors:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contributors:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgstr "" #~ "\n" #~ "Yazarlar:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Katkıda bulunanlar:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" ibus-table-1.17.11/po/uk.po000066400000000000000000001255111475513533100153220ustar00rootroot00000000000000# Yuri Chornoivan , 2015. #zanata, 2020, 2021, 2022, 2023, 2025. # Yuri Chornoivan , 2016. #zanata, 2020, 2021, 2022, 2023, 2025. # Mike FABIAN , 2019, 2020. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2025-01-20 23:19+0000\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 5.9.2\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "Спрощена китайська" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "Перемкнутися у режим «Спрощена китайська»." #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "Традиційна китайська" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "Перемкнутися у режим «Традиційна китайська»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "Спрощена китайська — перша" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "Перемкнутися у режим «Спрощена китайська до традиційної»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "Традиційна китайська — перша" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "Перемкнутися у режим «Традиційна китайська до спрощеної»." #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "Усі символи китайської" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "Перемкнутися у режим «Усі символи китайської»." #: engine/table.py:735 msgid "Chinese mode" msgstr "Режим китайської" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "Перемкнутися у режим китайської мови" #: engine/table.py:747 msgid "English" msgstr "Англійська" #: engine/table.py:748 msgid "Switch to English input" msgstr "Перемкнутися на введення англійської" #: engine/table.py:755 msgid "Chinese" msgstr "Китайська" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "Перемкнутися на введення китайської" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "Безпосередньо" #: engine/table.py:765 msgid "Switch to direct input" msgstr "Перемкнути на безпосереднє введення" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "Таблиця" #: engine/table.py:771 msgid "Switch to table input" msgstr "Перемкнути на введення за таблицею" #: engine/table.py:779 msgid "Input mode" msgstr "Режим введення" #: engine/table.py:780 msgid "Switch Input mode" msgstr "Перемкнути режим введення" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "Половинна" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "Перемкнутися на півширинні літери" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "Повна" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "Перемкнутися на повноширинні літери" #: engine/table.py:801 msgid "Letter width" msgstr "Ширина літер" #: engine/table.py:802 msgid "Switch letter width" msgstr "Перемкнути ширину літер" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "Перемкнутися на півширинну пунктуацію" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "Перемкнутися на повноширинну пунктуацію" #: engine/table.py:823 msgid "Punctuation width" msgstr "Ширина пунктуації" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "Перемкнути ширину пунктуації" #: engine/table.py:835 msgid "Switch to table mode" msgstr "Перемкнутися на режим таблиці" #: engine/table.py:840 msgid "Pinyin" msgstr "Піньїнь" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "Перемкнутися на режим піньїну" #: engine/table.py:845 msgid "Pinyin mode" msgstr "Режим піньїну" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "Перемкнути режим піньїну" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "Пропозиції вимкнено" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "Перемкнутися на режим пропозицій" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "Пропозиції увімкнено" #: engine/table.py:867 msgid "Suggestion mode" msgstr "Режим пропозицій" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "Перемкнути режим пропозицій" #: engine/table.py:878 msgid "Multiple character match" msgstr "Відповідність декільком символам" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "Перемкнутися на встановлення відповідності одразу декільком символам" #: engine/table.py:885 msgid "Single character match" msgstr "Відповідність одному символу" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "Перемкнутися на встановлення відповідності одному символу" #: engine/table.py:891 msgid "Onechar mode" msgstr "Односимвольний режим" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "Перемкнути односимвольний режим" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "Звичайний" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" "Перемкнутися на звичайний режим надсилання (автоматичне надсилання " "виконується до засобу попереднього редагування, а не до самої програми. За " "допомогою цього пункту можна увімкнути автоматичне визначення нових " "клавіатурних скорочень)" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" "Перемкнутися у режим безпосереднього надсилання (автоматичне надсилання " "даних безпосередньо до програми)" #: engine/table.py:919 msgid "Auto commit mode" msgstr "Режим автонадсилання" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "Перемкнути режим автонадсилання" #: engine/table.py:2946 msgid "Setup" msgstr "Налаштовування" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "Налаштувати «%(engine-name)s» для ibus-table" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "Введення за клавішами" #: engine/it_util.py:943 msgid "Cancel" msgstr "Скасувати" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "Натисніть клавішу (або комбінацію клавіш)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "Вікно буде закрито, коли клавіші буде відпущено" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "Спосіб введення за допомогою таблиці для IBus." #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "Юрій Чорноіван, " #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "Документація в інтернеті:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "Таблиця Ibus" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "Спосіб введення на основі таблиці" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" "Ibus-table — оболонка способів введення символів за допомогою таблиці. " "Здебільшого використовується для способів введення символів китайської, " "зокрема ZhengMa, WuBi, ErBi, CangJie, … Але передбачено і таблиці для деяких " "інших мов." #: setup/ibus-setup-table.desktop.in.in:3 msgid "IBus Table Preferences" msgstr "Налаштування таблиці IBus" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "Встановити параметри роботи таблиці IBus" #: setup/main.py:114 msgid "Initial state" msgstr "Початковий стан" #: setup/main.py:115 msgid "Direct input" msgstr "Безпосереднє введення" #: setup/main.py:116 msgid "Table input" msgstr "Введення за таблицею" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "Налаштування" #: setup/main.py:212 msgid "About" msgstr "Про програму" #: setup/main.py:220 msgid "Restore all defaults" msgstr "Відновити усі типові значення" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "З_акрити" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "Параметри" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "Подробиці" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "Прив'язки клавіш" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 msgid "Remember input mode" msgstr "Запам'ятовувати спосіб введення" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" "Визначає, слід запам'ятовувати останній використаний режим введення чи ibus-" "table має типово запускатися у режимі «Введення за таблицею» після " "перезапуску. Передбачено два режими введення: «Введення за таблицею» " "означає, що спосіб введення увімкнено, режим «Безпосереднє введення» працює " "майже так, як працювала б система, якби способи введення було вимкнено, " "тобто взагалі не використано. Більшість символів безпосередньо передаються " "програми. Втім, у цьому режимі все ж здійснюється певне перетворення між " "символами повної і половинної ширини." #: setup/main.py:323 msgid "No" msgstr "Ні" #: setup/main.py:325 msgid "Yes" msgstr "Так" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "Режим китайської:" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" "У режимі «Спрощена китайська» буде показано лише символи, \n" "які використовуються у спрощеному записі китайської. У режимі \n" "«Традиційна китайська» буде показано лише символи із \n" "традиційного набору китайських ієрогліфів. У режимі \n" "«Спрощена китайська до традиційної» буде показано усі символи, \n" "але спрощені символи будуть у верхній частині списку варіантів. \n" "У режимі «Традиційна китайська до спрощеної» символи традиційного \n" "запису передуватимуть символам спрощеного у списку варіантів. \n" "У режимі «Усі символи» буде показано усі відповідники без \n" "фільтрування за формою запису." #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "Спрощена китайська до традиційної" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "Традиційна китайська до спрощеної" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "Ширина літер панелі введення за таблицею:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" "Визначає, які літери слід використовувати\n" "у режимі введення за таблицею: повноширинні чи півширинні." #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "Ширина пунктуації панелі введення за таблицею:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" "Визначає, яку пунктуацію слід використовувати\n" "у режимі введення за таблицею: повноширинну чи півширинну." #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "Ширина літер безпосереднього введення:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" "Визначає, які літери слід використовувати\n" "у режимі безпосереднього введення: повноширинні чи півширинні." #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "Ширина пунктуації безпосереднього введення:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" "Визначає, яку пунктуацію слід використовувати\n" "у режимі безпосереднього введення: повноширинну чи півширинну." #: setup/main.py:590 msgid "Candidate list" msgstr "Список варіантів" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "Показувати список варіантів" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" "Визначає, чи має бути показано список варіантів.\n" "Для способів введення китайської варто бачити\n" "список варіантів. Втім, для деяких способів введення\n" "мов відмінних від китайської, зокрема кириличного\n" "«трансліту», потреби у показі списку варіантів\n" "немає." #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "Орієнтація:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" "Визначає, буде таблиця із варіантами\n" "вертикальною чи горизонтальною." #: setup/main.py:640 msgid "Horizontal" msgstr "Горизонтально" #: setup/main.py:642 msgid "Vertical" msgstr "Вертикально" #: setup/main.py:644 msgid "System default" msgstr "Типові для системи" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "Розмір сторінки:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" "Максимальна кількість варіантів на одній\n" "сторінці таблиці пошуку. Перехід між сторінками\n" "у таблиці пошуку можна здійснювати за допомогою\n" "клавіш page up/down та клавіш зі стрілками вгору\n" "і вниз." #: setup/main.py:696 msgid "Current key bindings:" msgstr "Поточні прив'язки клавіш:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "Команда" #: setup/main.py:752 msgid "Edit" msgstr "Змінити" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "Змінити прив'язки клавіш для позначеної команди" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "Встановити типові" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "Встановити типові прив'язки клавіш для позначеної команди" #: setup/main.py:778 msgid "Set all to default" msgstr "Встановити типові для усіх" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "Встановити типові прив'язки клавіш для усіх команд" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "Динамічне коригування" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" "Тут ви можете вибрати, чи буде програма динамічно коригувати порядок " "варіантів, відповідно до частоти використання варіантів." #: setup/main.py:824 msgid "Delete all learned data" msgstr "Вилучити вивчені дані" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "Створення:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" "Якщо встановлено варіант «Один символ», буде\n" "показано лише варіанти, що складаються з одного\n" "символу. Якщо встановлено «Фраза», буде показано\n" "і варіанти, що складаються із декількох\n" "символів." #: setup/main.py:862 msgid "Phrase" msgstr "Фраза" #: setup/main.py:864 msgid "Single Char" msgstr "Окремий символ" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "Автовибір" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" "Якщо встановлено варіант «Так», усе працюватиме так:\n" "1) Після натискання клавіші «Enter» буде надіслано\n" " варіант і символ переходу на новий рядок\n" "2) Після натискання клавіші Tab, варіант буде просто\n" " надіслано до програми\n" "3) Після натискання кнопки надсилання буде надіслано\n" " варіант і пробіл\n" "4) Якщо буде введено символ, для якого не вдасться\n" " знайти відповідників, буде надіслано перший із\n" " варіантів, які відповідали попередньому введенню.\n" " (Здебільшого це використовується для\n" " некитайських способів введення, зокрема\n" " кириличного «трансліту»)" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "Режим автонадсилання:" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" "Надсилання за допомогою клавіш надсилання або кнопок\n" "миші надсилає дані до програми. Цей пункт стосується\n" "«автоматичного» надсилання, яке може виконуватися,\n" "якщо користувач продовжує введення символів, без\n" "надсилання результатів вручну. У такому режимі\n" "час від часу результати надсилаються «автоматично».\n" "Варіант «Безпосередній» означає безпосереднє\n" "надсилання даних програмі, а варіант «Звичайний» —\n" "надсилання до засобу попереднього редагування." #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "Дія у відповідь на введення некоректного символу:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" "Визначає, що трапиться, коли буде введено символ, якого немає у наборі " "коректних вхідних символів для цієї таблиці: якщо вибрати «надіслати поточну " "пропозицію», буде вставлено поточну позначену пропозицію. Якщо вибрати " "«надіслати введені символи», буде надіслано без обробки символи, які було " "введено у процесі вибору пропозиції. За будь-яких умов, вибір пропозиції " "завершується, якщо введено некоректний символ, і відповідний символ буде " "негайно вставлено після тексту, який є результатом застосування параметрів з " "наведеного вище списку." #: setup/main.py:983 msgid "Commit current candidate" msgstr "Надіслати поточну пропозицію" #: setup/main.py:985 msgid "Commit typed keys" msgstr "Надіслати введені символи" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "Автошаблон" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" "Якщо увімкнено, наприкінці рядка введення\n" "буде автоматично дописано символ кратного\n" "замінника." #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "Символ одинарного замінника:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "Замінник будь-якого одного символу.\n" "Натисніть ENTER для підтвердження після зміни замінника." #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "Символ кратного замінника:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "Замінник довільної кількості будь-яких символів.\n" "Натисніть ENTER для підтвердження після зміни замінника." #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "Темна тема" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "Якщо вказано «так», буде використано схему кольорів темної теми." #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "Відтворювати звуковий файл при помилці" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" "Тут ви можете вибрати, чи відтворюватиме програма звуковий файл, якщо " "станеться помилка. Якщо у системі не встановлено модуля simpleaudio для " "Python3, цей пункт ні на що не впливатиме." #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "Рівень діагностики:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" "Якщо має значення більше за 0, до файла журналу може бути виведено " "діагностичні дані, діагностичні дані також може бути показано у графічному " "інтерфейсі." #: setup/main.py:1529 msgid "Are you sure?" msgstr "Ви серйозно?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "_Скасувати" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "_Гаразд" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "Уже запущено інший екземпляр цієї програми." #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "Ви справді хочете відновити усі типові параметри?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" "Ви справді хочете вилучити усі дані, які було вивчено на основі введеного та " "вибраних варіантів?" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "Виберіть звуковий файл .wav:" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "Змінити прив'язку клавіш для команди «%s»" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "Додати прив'язку клавіш" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "Вилучити позначену прив'язку клавіш" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "Пересунути прив'язку клавіш вище" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "Пересунути прив'язку клавіш нижче" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "Ви справді хочете встановити типові прив'язки клавіш для усіх команд?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "ibus не запущено." #~ msgid "IBUS_ENGINE_NAME environment variable is not set." #~ msgstr "Змінну середовища IBUS_ENGINE_NAME не визначено." #~ msgid "" #~ "Cannot determine the engine name. Please use the --engine-name option." #~ msgstr "" #~ "Не вдалося встановити назву рушія. Будь ласка, скористайтеся параметром --" #~ "engine-name." #~ msgid "IBus Table engine %s is not available" #~ msgstr "Не виявлено рушія таблиці IBus %s" #~ msgid "Next Page" #~ msgstr "Наступна сторінка" #~ msgid "Restore defaults as specified in the database for this engine." #~ msgstr "" #~ "Відновити типові значення параметрів, вказані у базі даних для цього " #~ "рушія." #~ msgid "Input mode:" #~ msgstr "Режим введення:" #~ msgid "" #~ "If you choose the space key to do “Next page”,\n" #~ " you can only commit using the selection keys\n" #~ "(i.e. the labels in front of the candidates in the\n" #~ "lookup table) or using the mouse." #~ msgstr "" #~ "Якщо ви використаєте клавішу пробілу для\n" #~ "переходу на наступну сторінку, ви зможете\n" #~ "надсилати дані лише за допомогою клавіш вибору\n" #~ "(тобто міток перед варіантами у таблиці) або\n" #~ "за допомогою кнопок миші." #~ msgid "Behavior of space key:" #~ msgstr "Поведінка клавіші пробілу:" #~ msgid "Details" #~ msgstr "Подробиці" #~ msgid "" #~ "\n" #~ "Authors:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contributors:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgstr "" #~ "\n" #~ "Автори:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contributors:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgid "Mike FABIAN" #~ msgstr "Mike FABIAN" ibus-table-1.17.11/po/zanata.xml000066400000000000000000000004231475513533100163350ustar00rootroot00000000000000 https://fedora.zanata.org/ ibus-table master gettext ibus-table-1.17.11/po/zh_CN.po000066400000000000000000000777001475513533100157120ustar00rootroot00000000000000# Pany , 2014. #zanata # Tian Shixiong , 2014. #zanata # Anonymous , 2019, 2020. # Boyuan Yang <073plan@gmail.com>, 2020. # Dingzhong Chen , 2021. # Mike FABIAN , 2021. # Liu Tao , 2023. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2023-12-26 14:36+0000\n" "Last-Translator: Liu Tao \n" "Language-Team: Chinese (Simplified) \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 5.3\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "简体字" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "切换为“仅简体字”。" #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "繁体字" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "切换为“仅繁体字”。" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "简体字优先" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "切换为“简体字先于繁体字”。" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "繁体字优先" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "切换为“繁体字先于简体字”。" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "全部汉字" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "切换为“全部汉字”。" #: engine/table.py:735 msgid "Chinese mode" msgstr "中文模式" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "切换为中文模式" #: engine/table.py:747 msgid "English" msgstr "英文" #: engine/table.py:748 msgid "Switch to English input" msgstr "切换为英文输入" #: engine/table.py:755 msgid "Chinese" msgstr "中文" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "切换为中文输入" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "直接" #: engine/table.py:765 msgid "Switch to direct input" msgstr "切换为直接输入" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "码表" #: engine/table.py:771 msgid "Switch to table input" msgstr "切换为码表输入" #: engine/table.py:779 msgid "Input mode" msgstr "输入模式" #: engine/table.py:780 msgid "Switch Input mode" msgstr "切换输入模式" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "半角" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "切换为半角字母" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "全角" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "切换为全角字母" #: engine/table.py:801 msgid "Letter width" msgstr "字母宽度" #: engine/table.py:802 msgid "Switch letter width" msgstr "切换字母宽度" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "切换为半角标点" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "切换为全角标点" #: engine/table.py:823 msgid "Punctuation width" msgstr "标点宽度" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "切换标点宽度" #: engine/table.py:835 msgid "Switch to table mode" msgstr "切换为码表模式" #: engine/table.py:840 msgid "Pinyin" msgstr "拼音" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "切换为拼音模式" #: engine/table.py:845 msgid "Pinyin mode" msgstr "拼音模式" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "切换拼音模式" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "已禁用联想" #: engine/table.py:857 engine/table.py:863 msgid "Switch to suggestion mode" msgstr "切换为联想模式" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "已启用联想" #: engine/table.py:867 msgid "Suggestion mode" msgstr "联想模式" #: engine/table.py:868 msgid "Switch suggestion mode" msgstr "切换联想模式" #: engine/table.py:878 msgid "Multiple character match" msgstr "多字匹配" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "切换为一次匹配多个字符" #: engine/table.py:885 msgid "Single character match" msgstr "单字匹配" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "切换至仅匹配单字符" #: engine/table.py:891 msgid "Onechar mode" msgstr "一字模式" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "切换一字模式" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "普通" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" "切换为普通上屏模式(键盘打字进入预编辑框,而不进入应用程序。使用此模式会启用" "新快捷键)" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "切换为直接上屏模式(键盘打字直接进入应用程序)" #: engine/table.py:919 msgid "Auto commit mode" msgstr "自动上屏模式" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "切换自动上屏模式" #: engine/table.py:2946 msgid "Setup" msgstr "设置" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "配置 ibus-table“%(engine-name)s”" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 msgid "Key input" msgstr "输入的键盘码" #: engine/it_util.py:943 msgid "Cancel" msgstr "取消" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "请按下一个键盘按键(或者按键组合)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "当按键被按下,这个对话框将会自动关闭" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "IBus 的码表输入法。" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "" "黄鹏 \n" "Pany \n" "Tian Shixiong \n" "Boyuan Yang <073plan@gmail.com>\n" "Dingzhong Chen \n" "mozbugbox " #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "在线文档:" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "IBus 码表" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "码表输入法" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" "Ibus-table 是个适用于码表输入法的输入法框架。通常用在中文输入法上,比如郑码、" "五笔、二笔、仓颉等等……但也有其他语言的码表使用此框架。" #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "首选项" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "初始状态" #: setup/main.py:115 msgid "Direct input" msgstr "直接输入" #: setup/main.py:116 msgid "Table input" msgstr "码表输入" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "首选项" #: setup/main.py:212 msgid "About" msgstr "关于" #: setup/main.py:220 msgid "Restore all defaults" msgstr "全部恢复为默认" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "关闭(_C)" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "设置" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "细节" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "快捷键" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 #, fuzzy #| msgid "Input mode" msgid "Remember input mode" msgstr "输入模式" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 #, fuzzy #| msgid "" #| "“Direct input” is almost the same as if the\n" #| "input method were off, i.e. not used at all, most\n" #| "characters just get passed to the application.\n" #| "But some conversion between fullwidth and\n" #| "halfwidth may still happen in direct input mode.\n" #| "“Table input” means the input method is on." msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" "“直接输入”几乎等于关闭输入法,即不用输入法,\n" "大多数字符直接传递给应用程序。但在此模式下\n" "还是会进行全角和半角的转换。\n" "“码表输入”表示开启输入法。" #: setup/main.py:323 msgid "No" msgstr "否" #: setup/main.py:325 msgid "Yes" msgstr "是" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "中文模式:" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" "“简体字”只显示简体中文中使用的字符。\n" "“繁体字”只显示繁体中文中使用的字符。\n" "“简体字先于繁体字”显示全部字符并将简体字放在候选列表上方。\n" "“繁体字先于简体字”显示全部字符并将繁体字放在候选列表上方。\n" "“全部汉字”显示全部匹配字符且不对繁体或简体字筛选排序。" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "简体字先于繁体字" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "繁体字先于简体字" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "码表输入的字母宽度:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "在码表输入模式下使用全角还是半角字母。" #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "码表输入的标点宽度:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "在码表输入模式下使用全角还是半角标点符号。" #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "直接输入的字母宽度:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "在直接输入模式下使用全角还是半角字母。" #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "直接输入的标点宽度:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "在直接输入模式下使用全角还是半角标点符号。" #: setup/main.py:590 msgid "Candidate list" msgstr "候选列表" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "显示候选列表" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" "候选列表是要显示还是隐藏。\n" "对于中文输入法通常需要显示候选列表。\n" "但对于一些非中文输入法,如俄语“转写”,\n" "隐藏候选列表更好。" #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "方向:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "显示候选字词的查找窗口应该横排还是竖排。" #: setup/main.py:640 msgid "Horizontal" msgstr "横向" #: setup/main.py:642 msgid "Vertical" msgstr "纵向" #: setup/main.py:644 msgid "System default" msgstr "系统默认" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "页面大小:" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" "候选窗口里每个页面的候选项的最大数量。\n" "你可以使用上/下翻页键或者上/下方向键来切换页面。" #: setup/main.py:696 msgid "Current key bindings:" msgstr "当前绑定的快捷键:" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "命令" #: setup/main.py:752 msgid "Edit" msgstr "编辑" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "编辑所选命令的快捷键" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "设为默认" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "重置所选命令绑定的快捷键为默认" #: setup/main.py:778 msgid "Set all to default" msgstr "全部设为默认" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "重置所有命令绑定的快捷键为默认" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "删除学习的数据" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "组合:" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" "如果此选项设为“单字”,只显示单个字符的候选列表。\n" "如果设为“词组”,则包含多个字符的候选词也会显示。" #: setup/main.py:862 msgid "Phrase" msgstr "词组" #: setup/main.py:864 msgid "Single Char" msgstr "单字" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "自动选择:" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" "如果设为“是”,将执行以下 4 个规则:\n" "1) 当按下“回车键”时,上屏候选字词并换行\n" "2) 当按下“制表(Tab)键”时,上屏候选字词\n" "3) 当使用上屏键时,上屏候选字词并附加空格\n" "4) 如果打字输入的下个字符没有匹配的候选词时,\n" " 上屏之前匹配候选词的第一个。(非中文输入法\n" " 如俄语“转写”最需要)" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "自动上屏模式:" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" "使用上屏键或鼠标上屏的内容总是传递给应用程序。\n" "此选项是关于“自动”上屏的。当用户持续打字而\n" "不手动上屏时,就可能发生“自动”上屏。\n" "“直接”表示此“自动”上屏的内容直接传递给\n" "应用程序,“普通”则表示内容会进入预编辑框。" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "自动通配符" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "如果设为是,则在输入字符串的末尾自动附加多匹配通配符。" #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 msgid "Single wildcard character:" msgstr "单匹配通配符:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "用于匹配任意单个字符的通配符。\n" "更改通配符后按回车键或返回键确认。" #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "多匹配通配符:" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" "用于匹配任意数量字符的通配符。\n" "更改通配符后按回车键或返回键确认。" #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "使用深色主题" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "如果选择“是”,将使用匹配深色主题的色彩方案。" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "调试级别:" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" "当大于 0 时,调试信息可以打印到日志文件,并且调试信息也可以图形方式显示。" #: setup/main.py:1529 msgid "Are you sure?" msgstr "你确定吗?" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "取消(_C)" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "确定(_O)" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "此应用已有另一实例在运行中。" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "你真的要将所有设置恢复为默认吗?" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 #, fuzzy #| msgid "Do you really want to restore all default settings?" msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "你真的要将所有设置恢复为默认吗?" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "编辑“%s”命令绑定的快捷键" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "添加快捷键" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "移除所选快捷键" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "上移快捷键" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "下移快捷键" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "你真的要将所有命令绑定的快捷键恢复为默认吗?" #: setup/main.py:3037 msgid "ibus is not running." msgstr "IBus 没有运行。" #~ msgid "IBUS_ENGINE_NAME environment variable is not set." #~ msgstr "IBUS_ENGINE_NAME 环境变量尚未设置。" #~ msgid "" #~ "Cannot determine the engine name. Please use the --engine-name option." #~ msgstr "无法确定引擎名称。请使用 --engine-name 选项。" #~ msgid "IBus Table engine %s is not available" #~ msgstr "IBus Table 引擎 %s 不可用" #~ msgid "Next Page" #~ msgstr "下一页" #~ msgid "Restore defaults as specified in the database for this engine." #~ msgstr "重置为该引擎数据库中指定的预设值。" #~ msgid "Input mode:" #~ msgstr "输入模式:" #~ msgid "Behavior of space key:" #~ msgstr "空格键的行为:" #~ msgid "Details" #~ msgstr "详情" #~ msgid "" #~ "\n" #~ "Authors:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "Peng Wu\n" #~ "\n" #~ "Contributors:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" #~ msgstr "" #~ "\n" #~ "作者:\n" #~ "Yuwei YU (‘acevery’)\n" #~ "Peng Huang\n" #~ "BYVoid\n" #~ "吴鹏\n" #~ "\n" #~ "贡献者:\n" #~ "koterpilla\n" #~ "Zerng07\n" #~ "Caius ‘kaio’ Chance\n" #~ "Mike FABIAN\n" #~ "Bernard Nauwelaerts\n" #~ "Xiaojun Ma\n" #~ "mozbugbox\n" #~ "Seán de Búrca\n" #~ "" ibus-table-1.17.11/po/zh_HK.po000066400000000000000000000727301475513533100157120ustar00rootroot00000000000000# IBus-Table Translation file: zh_TW.po # Copyright (C) 2009 Caius 'kaio' Chance # This file is distributed under the same license as the ibus-table package. # Caius 'kaio' Chance , 2009.05.21 # Anonymous , 2019, 2020. msgid "" msgstr "" "Project-Id-Version: 0.1.20080819\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2020-12-30 13:36+0000\n" "Last-Translator: Anonymous \n" "Language-Team: Chinese (Hong Kong) \n" "Language: zh_HK\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 4.4\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "簡體中文" #: engine/table.py:687 #, fuzzy msgid "Switch to “Simplified Chinese only”." msgstr "切換成簡體模式" #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "繁體中文" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "切換至繁體中文模式" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 #, fuzzy msgid "Simplified Chinese first" msgstr "切換成簡體模式" #: engine/table.py:708 #, fuzzy msgid "Switch to “Simplified Chinese before traditional”." msgstr "切換成簡體模式" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 #, fuzzy msgid "Traditional Chinese first" msgstr "切換成繁體模式" #: engine/table.py:720 #, fuzzy msgid "Switch to “Traditional Chinese before simplified”." msgstr "切換成繁體模式" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "" #: engine/table.py:731 #, fuzzy msgid "Switch to “All Chinese characters”." msgstr "切換成繁體模式" #: engine/table.py:735 #, fuzzy msgid "Chinese mode" msgstr "切換到大字集模式(預設結果順序)" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "切換至中文模式" #: engine/table.py:747 msgid "English" msgstr "英文" #: engine/table.py:748 msgid "Switch to English input" msgstr "" #: engine/table.py:755 msgid "Chinese" msgstr "中文" #: engine/table.py:756 #, fuzzy msgid "Switch to Chinese input" msgstr "切換到大字集模式(預設結果順序)" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "" #: engine/table.py:765 #, fuzzy msgid "Switch to direct input" msgstr "切換成拼音反查模式" #: engine/table.py:770 engine/table.py:834 #, fuzzy msgid "Table" msgstr "切換成形碼模式" #: engine/table.py:771 #, fuzzy msgid "Switch to table input" msgstr "切換成形碼模式" #: engine/table.py:779 #, fuzzy msgid "Input mode" msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #: engine/table.py:780 #, fuzzy msgid "Switch Input mode" msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "半形" #: engine/table.py:791 #, fuzzy msgid "Switch to halfwidth letters" msgstr "切換成半形標點" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "全形" #: engine/table.py:797 #, fuzzy msgid "Switch to fullwidth letters" msgstr "切換成全形標點" #: engine/table.py:801 msgid "Letter width" msgstr "" #: engine/table.py:802 #, fuzzy msgid "Switch letter width" msgstr "切換成全形標點" #: engine/table.py:813 #, fuzzy msgid "Switch to halfwidth punctuation" msgstr "切換成半形標點" #: engine/table.py:819 #, fuzzy msgid "Switch to fullwidth punctuation" msgstr "切換成全形標點" #: engine/table.py:823 msgid "Punctuation width" msgstr "" #: engine/table.py:824 #, fuzzy msgid "Switch punctuation width" msgstr "切換成全形標點" #: engine/table.py:835 #, fuzzy msgid "Switch to table mode" msgstr "切換成形碼模式" #: engine/table.py:840 msgid "Pinyin" msgstr "" #: engine/table.py:841 #, fuzzy msgid "Switch to pinyin mode" msgstr "切換到中文模式" #: engine/table.py:845 msgid "Pinyin mode" msgstr "拼音模式" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "" #: engine/table.py:857 engine/table.py:863 #, fuzzy msgid "Switch to suggestion mode" msgstr "切換到中文模式" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "" #: engine/table.py:867 msgid "Suggestion mode" msgstr "" #: engine/table.py:868 #, fuzzy msgid "Switch suggestion mode" msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #: engine/table.py:878 msgid "Multiple character match" msgstr "" #: engine/table.py:880 #, fuzzy msgid "Switch to matching multiple characters at once" msgstr "切換成單字元模式" #: engine/table.py:885 #, fuzzy msgid "Single character match" msgstr "切換成單字元模式" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "" #: engine/table.py:891 #, fuzzy msgid "Onechar mode" msgstr "切換到大字集模式(預設結果順序)" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "" #: engine/table.py:919 #, fuzzy msgid "Auto commit mode" msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #: engine/table.py:920 #, fuzzy msgid "Switch autocommit mode" msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #: engine/table.py:2946 msgid "Setup" msgstr "" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 #, fuzzy msgid "Key input" msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #: engine/it_util.py:943 msgid "Cancel" msgstr "取消(_C)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "請按快捷鍵" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "" #: engine/it_util.py:987 msgid "Table input method for IBus." msgstr "" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "" "Ding-Yi Chen 陳定彞 , 2009\n" "Cheng-Chia Tseng , 2010\n" "Terry Chuang , 2014\n" "tomoe_musashi , 2015" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 #, fuzzy msgid "Ibus Table" msgstr "切換成形碼模式" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "偏好設定" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 msgid "Initial state" msgstr "" #: setup/main.py:115 #, fuzzy msgid "Direct input" msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #: setup/main.py:116 msgid "Table input" msgstr "" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "偏好設定" #: setup/main.py:212 msgid "About" msgstr "關於" #: setup/main.py:220 msgid "Restore all defaults" msgstr "" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "關閉(_C)" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 #, fuzzy msgid "Remember input mode" msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" #: setup/main.py:323 msgid "No" msgstr "" #: setup/main.py:325 msgid "Yes" msgstr "" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 #, fuzzy msgid "Chinese mode:" msgstr "切換到大字集模式(預設結果順序)" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 #, fuzzy msgid "Simplified Chinese before traditional" msgstr "切換成簡體模式" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 #, fuzzy msgid "Traditional Chinese before simplified" msgstr "切換成繁體模式" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" #: setup/main.py:590 msgid "Candidate list" msgstr "" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" #: setup/main.py:640 msgid "Horizontal" msgstr "水平" #: setup/main.py:642 msgid "Vertical" msgstr "垂直" #: setup/main.py:644 msgid "System default" msgstr "" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" #: setup/main.py:696 msgid "Current key bindings:" msgstr "" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "" #: setup/main.py:752 msgid "Edit" msgstr "編輯" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "" #: setup/main.py:765 setup/main.py:2213 msgid "Set to default" msgstr "" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "" #: setup/main.py:778 msgid "Set all to default" msgstr "" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" #: setup/main.py:862 msgid "Phrase" msgstr "" #: setup/main.py:864 #, fuzzy msgid "Single Char" msgstr "切換成單字元模式" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 #, fuzzy msgid "Auto commit mode:" msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 #, fuzzy msgid "Single wildcard character:" msgstr "切換成單字元模式" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" #: setup/main.py:1529 msgid "Are you sure?" msgstr "" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "取消(_C)" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "確定(_O)" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" #: setup/main.py:3037 msgid "ibus is not running." msgstr "" #, fuzzy #~ msgid "Input mode:" #~ msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #, fuzzy #~ msgid "Chinese input (Left Shift)" #~ msgstr "切換成拼音反查模式" #, fuzzy #~ msgid "Direct input (Left Shift)" #~ msgstr "切換成拼音反查模式" #, fuzzy #~ msgid "Switch to “Chinese input” (Left Shift)" #~ msgstr "切換成拼音反查模式" #, fuzzy #~ msgid "Fullwidth letters (Shift-Space)" #~ msgstr "切換成全形字元" #, fuzzy #~ msgid "Switch to “Halfwidth letters” (Shift-Space)" #~ msgstr "切換成半形字元" #, fuzzy #~ msgid "Halfwidth letters (Shift-Space)" #~ msgstr "切換成半形字元" #, fuzzy #~ msgid "Switch to “Fullwidth letters” (Shift-Space)" #~ msgstr "切換成全形字元" #, fuzzy #~ msgid "Halfwidth punctuation (Ctrl-.)" #~ msgstr "切換成半形標點" #, fuzzy #~ msgid "Table mode (Right Shift)" #~ msgstr "切換成形碼模式" #, fuzzy #~ msgid "Switch to “Phrase mode” (Ctrl-,)" #~ msgstr "切換成詞組模式" #, fuzzy #~ msgid "Phrase mode (Ctrl-,)" #~ msgstr "切換成詞組模式" #, fuzzy #~ msgid "Direct commit mode (Ctrl-/)" #~ msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #, fuzzy #~ msgid "Switch to “Normal commit mode” (uses space to commit) (Ctrl-/)" #~ msgstr "切換成標準輸出模式,亦即按空格鍵執行輸出" #, fuzzy #~ msgid "Normal commit mode (Ctrl-/)" #~ msgstr "切換成直接輸出模式,亦即單項結果即時輸出" #, fuzzy #~ msgid "Simplified Chinese (Ctrl-;)" #~ msgstr "切換成簡體模式" #, fuzzy #~ msgid "Traditional Chinese (Ctrl-;)" #~ msgstr "切換成繁體模式" #, fuzzy #~ msgid "Simplified Chinese before traditional (Ctrl-;)" #~ msgstr "切換成簡體模式" #, fuzzy #~ msgid "Traditional Chinese before simplified (Ctrl-;)" #~ msgstr "切換成繁體模式" #, fuzzy #~ msgid "All Chinese characters (Ctrl-;)" #~ msgstr "切換成繁體模式" #, fuzzy #~ msgid "English Mode" #~ msgstr "切換到中文模式" #, fuzzy #~ msgid "PinYin Mode" #~ msgstr "切換成拼音反查模式" #, fuzzy #~ msgid "Switch to Simplify Chinese first Big Charset Mode - Ctrl-;" #~ msgstr "切換成大字集模式(簡體結果優先)" #, fuzzy #~ msgid "Simplified Chinese First Big Charset Mode" #~ msgstr "切換成大字集模式(簡體結果優先)" #, fuzzy #~ msgid "Switch to Traditional Chinese first Big Charset Mode - Ctrl-;" #~ msgstr "切換成大字集模式(繁體結果優先)" #, fuzzy #~ msgid "Traditional Chinese First Big Charset Mode" #~ msgstr "切換成大字集模式(繁體結果優先)" #, fuzzy #~ msgid "Switch to Big Charset Mode - Ctrl-;" #~ msgstr "切換到大字集模式(預設結果順序)" #, fuzzy #~ msgid "Big Chinese Mode" #~ msgstr "切換到大字集模式(預設結果順序)" #~ msgid "CN" #~ msgstr "中" #~ msgid "EN" #~ msgstr "英" ibus-table-1.17.11/po/zh_TW.po000066400000000000000000000711021475513533100157320ustar00rootroot00000000000000# Cheng-Chia Tseng , 2014. #zanata # Mike FABIAN , 2019. # Anonymous , 2019, 2020. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://github.com/mike-fabian/ibus-table/issues\n" "POT-Creation-Date: 2025-01-21 01:39+0100\n" "PO-Revision-Date: 2022-09-30 23:20+0000\n" "Last-Translator: Anonymous \n" "Language-Team: Chinese (Traditional) \n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 4.14.1\n" #. Translators: This is the menu entry to select #. when one wants to input only Simplified Chinese. #. Translators: This is the setting to use only #. simplified Chinese #: engine/table.py:685 setup/main.py:369 msgid "Simplified Chinese" msgstr "簡體字中文" #: engine/table.py:687 msgid "Switch to “Simplified Chinese only”." msgstr "切換至「僅簡體字中文」" #. Translators: This is the menu entry to select #. when one wants to input only Traditonal Chinese #. Translators: This is the setting to use only #. traditional Chinese #: engine/table.py:694 setup/main.py:373 msgid "Traditional Chinese" msgstr "正體字中文" #: engine/table.py:696 msgid "Switch to “Traditional Chinese only”." msgstr "切換至「正體字中文」" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Simplified Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:706 msgid "Simplified Chinese first" msgstr "簡體字中文優先" #: engine/table.py:708 msgid "Switch to “Simplified Chinese before traditional”." msgstr "切換至「簡體字中文先於正體字」" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese but wants the Traditional Chinese to be #. preferred, i.e. shown higher up in the candidate #. lists. #: engine/table.py:718 msgid "Traditional Chinese first" msgstr "正體字中文優先" #: engine/table.py:720 msgid "Switch to “Traditional Chinese before simplified”." msgstr "切換至「正體字中文先於簡體字」" #. Translators: This is the menu entry to select when #. one wants to input both Simplified and Traditional #. Chinese and has no particular preference whether #. simplified or traditional characters should be higher #. up in the candidate lists. #. Translators: This is the setting to use both #. simplified and traditional Chinese in no #. particular order #: engine/table.py:730 setup/main.py:388 msgid "All Chinese characters" msgstr "所有中文字元" #: engine/table.py:731 msgid "Switch to “All Chinese characters”." msgstr "切換至「所有中文字元」" #: engine/table.py:735 msgid "Chinese mode" msgstr "中文模式" #: engine/table.py:736 msgid "Switch Chinese mode" msgstr "切換中文模式" #: engine/table.py:747 msgid "English" msgstr "英文" #: engine/table.py:748 msgid "Switch to English input" msgstr "切換至英文輸入" #: engine/table.py:755 msgid "Chinese" msgstr "中文" #: engine/table.py:756 msgid "Switch to Chinese input" msgstr "切換至中文輸入" #: engine/table.py:764 engine/table.py:912 setup/main.py:939 msgid "Direct" msgstr "直接" #: engine/table.py:765 msgid "Switch to direct input" msgstr "切換至直接輸入" #: engine/table.py:770 engine/table.py:834 msgid "Table" msgstr "表格" #: engine/table.py:771 msgid "Switch to table input" msgstr "切換至表格輸入" #: engine/table.py:779 msgid "Input mode" msgstr "輸入模式" #: engine/table.py:780 msgid "Switch Input mode" msgstr "切換輸入模式" #. Translators: This is the mode to use half width letters #. while in “Table input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use half width letters #. while in “Direct input” mode. #. Translators: This is the mode to use half width punctuation #. while in “Direct input” mode. #: engine/table.py:790 engine/table.py:812 setup/main.py:425 setup/main.py:469 #: setup/main.py:514 setup/main.py:559 msgid "Half" msgstr "半形" #: engine/table.py:791 msgid "Switch to halfwidth letters" msgstr "切換至半形字母" #. Translators: This is the mode to use full width letters #. while in “Table input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Table input” mode. #. Translators: This is the mode to use full width letters #. while in “Direct input” mode. #. Translators: This is the mode to use full width punctuation #. while in “Direct input” mode. #: engine/table.py:796 engine/table.py:818 setup/main.py:429 setup/main.py:473 #: setup/main.py:518 setup/main.py:563 msgid "Full" msgstr "全形" #: engine/table.py:797 msgid "Switch to fullwidth letters" msgstr "切換至全形字母" #: engine/table.py:801 msgid "Letter width" msgstr "字母寬" #: engine/table.py:802 msgid "Switch letter width" msgstr "切換字母寬度" #: engine/table.py:813 msgid "Switch to halfwidth punctuation" msgstr "切換至半形標點" #: engine/table.py:819 msgid "Switch to fullwidth punctuation" msgstr "切換至全形標點" #: engine/table.py:823 msgid "Punctuation width" msgstr "標點寬" #: engine/table.py:824 msgid "Switch punctuation width" msgstr "切換標點寬度" #: engine/table.py:835 msgid "Switch to table mode" msgstr "切換至表格模式" #: engine/table.py:840 msgid "Pinyin" msgstr "拼音" #: engine/table.py:841 msgid "Switch to pinyin mode" msgstr "切換至拼音模式" #: engine/table.py:845 msgid "Pinyin mode" msgstr "拼音模式" #: engine/table.py:846 msgid "Switch pinyin mode" msgstr "切換拼音模式" #: engine/table.py:856 msgid "Suggestion disabled" msgstr "" #: engine/table.py:857 engine/table.py:863 #, fuzzy #| msgid "Switch to pinyin mode" msgid "Switch to suggestion mode" msgstr "切換至拼音模式" #: engine/table.py:862 msgid "Suggestion enabled" msgstr "" #: engine/table.py:867 msgid "Suggestion mode" msgstr "" #: engine/table.py:868 #, fuzzy #| msgid "Switch Input mode" msgid "Switch suggestion mode" msgstr "切換輸入模式" #: engine/table.py:878 msgid "Multiple character match" msgstr "多字元比對" #: engine/table.py:880 msgid "Switch to matching multiple characters at once" msgstr "切換至一次比對多字元" #: engine/table.py:885 msgid "Single character match" msgstr "切換字元比對" #: engine/table.py:887 msgid "Switch to matching only single characters" msgstr "切換至僅比對單一字元" #: engine/table.py:891 msgid "Onechar mode" msgstr "一字模式" #: engine/table.py:892 msgid "Switch onechar mode" msgstr "切換一字模式" #: engine/table.py:902 setup/main.py:937 msgid "Normal" msgstr "一般" #: engine/table.py:904 msgid "" "Switch to normal commit mode (automatic commits go into the preedit instead " "of into the application. This enables automatic definitions of new shortcuts)" msgstr "" "切換至一般提交模式 (自動提入預先編輯區內而非程式內。這會啟用新快捷鍵的自動定" "義)" #: engine/table.py:914 msgid "" "Switch to direct commit mode (automatic commits go directly into the " "application)" msgstr "切換至直接提交模式 (直接自動提入程式內)" #: engine/table.py:919 msgid "Auto commit mode" msgstr "自動提交模式" #: engine/table.py:920 msgid "Switch autocommit mode" msgstr "切換自動提交模式" #: engine/table.py:2946 msgid "Setup" msgstr "設置" #: engine/table.py:2949 #, python-format msgid "Configure ibus-table “%(engine-name)s”" msgstr "設定 ibus-table「%(engine-name)s」" #. Translators: This is used in the title bar of a dialog window #. requesting that the user types a key to be used as a new #. key binding for a command. #: engine/it_util.py:937 #, fuzzy #| msgid "Table input" msgid "Key input" msgstr "表格輸入" #: engine/it_util.py:943 msgid "Cancel" msgstr "取消" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:950 msgid "Please press a key (or a key combination)" msgstr "請按鍵盤按鍵 (或是按鍵組合)" #. Translators: This is from the dialog to enter a key or a #. key combination to be used as a key binding for a #. command. #: engine/it_util.py:955 msgid "The dialog will be closed when the key is released" msgstr "" #: engine/it_util.py:987 #, fuzzy #| msgid "Table input letter width:" msgid "Table input method for IBus." msgstr "表格輸入字母寬度:" #. Translators: put your names here, one name per line. #. The list of names of the translators for the current locale #. will be displayed in the “About ibus-table” dialog. #: engine/it_util.py:1011 msgid "translator-credits" msgstr "" "Whired Planck , 2020\n" "莊佳儒 \n" "Cheng-chia Tseng , 2013" #: engine/it_util.py:1019 msgid "Online documentation:" msgstr "線上文件(_O)" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:6 msgid "Ibus Table" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:7 msgid "Table based input method" msgstr "" #: org.freedesktop.ibus.engine.table.metainfo.xml.in:9 msgid "" "Ibus-table is an input method framework for table-based input methods. " "Mostly it is used for Chinese input methods such as ZhengMa, WuBi, ErBi, " "CangJie, …. But some tables for other languages are available as well." msgstr "" #: setup/ibus-setup-table.desktop.in.in:3 #, fuzzy #| msgid "Preferences" msgid "IBus Table Preferences" msgstr "偏好設定" #: setup/ibus-setup-table.desktop.in.in:4 msgid "Set IBus Table Options" msgstr "" #: setup/main.py:114 #, fuzzy #| msgid "Inital state" msgid "Initial state" msgstr "初始狀態" #: setup/main.py:115 msgid "Direct input" msgstr "直接輸入" #: setup/main.py:116 msgid "Table input" msgstr "表格輸入" #: setup/main.py:129 setup/main.py:189 msgid "Preferences" msgstr "偏好設定" #: setup/main.py:212 msgid "About" msgstr "關於" #: setup/main.py:220 msgid "Restore all defaults" msgstr "全部還原至預設值" #: setup/main.py:229 setup/main.py:2984 msgid "_Close" msgstr "關閉 (_C)" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some options which influence the #. behaviour of ibus-table. #: setup/main.py:252 msgid "Settings" msgstr "設定" #. Translators: This is the label of a tab in the setup tool. #. Here the user can set up some more advanced options. #: setup/main.py:267 msgid "Details" msgstr "詳情" #. Translators: This is the label of a tab in the setup tool. #. Here the user can customize the key bindings to execute #. certain commands of ibus-table. For example which key to use #. to commit, which key to use to move to the next candidate #. etc... #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:283 setup/main.py:729 msgid "Key bindings" msgstr "" #. Translators: A combobox to choose whether the input mode #. (“Direct input” or “Table input”) should be remembered #. or whether ibus-table should always use “Table input” by #. default after a restart. #: setup/main.py:303 #, fuzzy #| msgid "Input mode" msgid "Remember input mode" msgstr "輸入模式" #. Translators: A tooltip for the label of the combobox to #. choose whether the input mode (“Direct input” or “Table #. input”) should be remembered or whether ibus-table #. should always use “Table input” by default after a #. restart. #: setup/main.py:310 #, fuzzy #| msgid "" #| "“Direct input” is almost the same as if the\n" #| "input method were off, i.e. not used at all, most\n" #| "characters just get passed to the application.\n" #| "But some conversion between fullwidth and\n" #| "halfwidth may still happen in direct input mode.\n" #| "“Table input” means the input method is on." msgid "" "Whether the last used input mode should be remembered or whether ibus-table " "should start in “Table mode” by default after a restart. There are two input " "modes: “Table input” means the input method is on. “Direct input” is almost " "the same as if the input method were off, i.e. not used at all, most " "characters just get passed to the application. But some conversion between " "fullwidth and halfwidth may still happen in direct input mode." msgstr "" "「直接輸入」幾乎與關閉輸入法相同,\n" "如同未使用輸入法,大多數字元直接送\n" "入程式中。但有些全形、半形的轉換,\n" "在直接輸入模式中仍會處理。「表格輸\n" "入」則代表開啟輸入法。" #: setup/main.py:323 msgid "No" msgstr "否" #: setup/main.py:325 msgid "Yes" msgstr "是" #. Translators: A combobox to choose the variant of #. Chinese which should be preferred. #: setup/main.py:349 msgid "Chinese mode:" msgstr "中文模式:" #. Translators: A tooltip for the label of the combobox to #. choose which variant of Chinese should be preferred. #: setup/main.py:353 msgid "" "“Simplified Chinese” shows only characters \n" "used in simplified Chinese. “Traditional Chinese”\n" "shows only characters used in traditional Chinese.\n" "“Simplified Chinese before traditional” shows all\n" "characters but puts the simplified characters higher\n" "up in the candidate list. “Traditional Chinese before\n" "simplified” puts the traditional characters higher up\n" "in the candidate list. “All characters” just shows all\n" "matches without any particular filtering on traditional\n" "versus simplified Chinese." msgstr "" "「正體字中文」僅會顯示正體字。\n" "「簡體字中文」僅會顯示簡體字。\n" "「正體字中文先於簡體字」在候選清單中先顯示正體字。\n" "「簡體字中文先於正體字」在候選清單中先顯示簡體字。\n" "「所有字元」則顯示所有符合項目,不會特地過濾正體字\n" "或簡體字。" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. simplified Chinese #: setup/main.py:378 msgid "Simplified Chinese before traditional" msgstr "簡體字中文先於正體字" #. Translators: This is the setting to use both #. simplified and traditional Chinese but prefer #. traditional Chinese #: setup/main.py:383 msgid "Traditional Chinese before simplified" msgstr "繁體字中文先於簡體字" #. Translators: A combobox to choose the letter width #. while in “Table input” mode. #: setup/main.py:413 msgid "Table input letter width:" msgstr "表格輸入字母寬度:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Table input” mode. #: setup/main.py:417 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in table input mode." msgstr "" "表格輸入模式要使用全形字母\n" "或半形字母。" #. Translators: A combobox to choose the punctuation width #. while in “Table input” mode. #: setup/main.py:456 msgid "Table input punctuation width:" msgstr "表格輸入標點寬度:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Table input” mode. #: setup/main.py:460 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in table input mode." msgstr "" "表格輸入模式要使用全形標點\n" "或半形標點。" #. Translators: A combobox to choose the letter width #. while in “Direct input” mode. #: setup/main.py:502 msgid "Direct input letter width:" msgstr "直接輸入字母寬度:" #. Translators: A tooltip for the label of the combobox to #. choose the letter width while in “Direct input” mode. #: setup/main.py:506 msgid "" "Whether to use fullwidth or halfwidth\n" "letters in direct input mode." msgstr "" "直接輸入模式要使用全形字母\n" "或半形字母。" #. Translators: A combobox to choose the punctuation width #. while in “Direct input” mode. #: setup/main.py:546 msgid "Direct input punctuation width:" msgstr "直接輸入標點寬度:" #. Translators: A tooltip for the label of the combobox to #. choose the punctuation width while in “Direct input” mode. #: setup/main.py:550 msgid "" "Whether to use fullwidth or halfwidth\n" "punctuation in direct input mode." msgstr "" "直接輸入模式要使用全形標點\n" "或半形標點。" #: setup/main.py:590 msgid "Candidate list" msgstr "" #. Translators: A combobox to choose whether #. a candidate list should be shown or hidden. #. For Chinese input methods one usually wants the #. candidate list to be shown. But for some non-Chinese #. input methods like the Russian “translit”, hiding #. the candidate lists is better. #: setup/main.py:605 msgid "Show candidate list" msgstr "" #. Translit: A tooltip for the label of the combobox to #. choose whether a candidate list should be shown or #. hidden. #: setup/main.py:610 msgid "" "Whether candidate lists should be shown or hidden.\n" "For Chinese input methods one usually wants the\n" "candidate lists to be shown. But for some non-Chinese\n" "input methods like the Russian “translit”, hiding the\n" "candidate lists is better." msgstr "" #. Translators: A combobox to choose whether the candidate #. window should be drawn horizontally or vertically. #: setup/main.py:629 msgid "Orientation:" msgstr "方向:" #. Translators: A tooltip for the label of the combobox to #. choose whether the candidate window should be drawn #. horizontally or vertically. #: setup/main.py:634 msgid "" "Whether the lookup table showing the candidates\n" "should be vertical or horizontal." msgstr "" "顯示候選字詞的查詢表格是要\n" "垂直排列或水平排列。" #: setup/main.py:640 msgid "Horizontal" msgstr "水平" #: setup/main.py:642 msgid "Vertical" msgstr "垂直" #: setup/main.py:644 msgid "System default" msgstr "系統預設" #. Translators: Here one can choose how many suggestion #. candidates to show in one page of the candidate list. #: setup/main.py:669 msgid "Page size:" msgstr "頁面大小" #. Translators: A tooltip for the label of the adjustment #. for the number of candidates to show in one page of the #. candidate list. #: setup/main.py:674 msgid "" "The maximum number of candidates in\n" "one page of the lookup table. You can switch\n" "pages in the lookup table using the page up/down\n" "keys or the arrow up/down keys." msgstr "" #: setup/main.py:696 msgid "Current key bindings:" msgstr "" #. Translators: Column heading of the table listing the #. existing key bindings #: setup/main.py:721 msgid "Command" msgstr "指令" #: setup/main.py:752 msgid "Edit" msgstr "編輯" #. Translators: A tooltip for the button to edit #. the keybindings for the selected command. #: setup/main.py:758 msgid "Edit the key bindings for the selected command" msgstr "" #: setup/main.py:765 setup/main.py:2213 #, fuzzy #| msgid "Restore all defaults" msgid "Set to default" msgstr "全部還原至預設值" #. Translators: A tooltip for the button to set #. the default key bindings for the selected command. #. Translators: This is a tooltip for the button to set #. the key bindings for the selected command to the default. #: setup/main.py:771 setup/main.py:2220 msgid "Set default key bindings for the selected command" msgstr "" #: setup/main.py:778 #, fuzzy #| msgid "Restore all defaults" msgid "Set all to default" msgstr "全部還原至預設值" #. Translators: A tooltip for the button to set the #. key bindings to default for all commands. #: setup/main.py:784 msgid "Set default key bindings for all commands" msgstr "" #. Translators: A checkbox where one can choose whether the #. order of the candidates is dynamically adjusted according #. to how often the candidates are used. #: setup/main.py:809 msgid "Dynamic adjust" msgstr "" #: setup/main.py:811 msgid "" "Here you can choose whether the order of the candidates is dynamically " "adjusted according to how often the candidates are used." msgstr "" #: setup/main.py:824 msgid "Delete all learned data" msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:849 msgid "Compose:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:854 msgid "" "If this is set to “single char”, only single\n" "character candidates will be shown. If it is\n" "set to “Phrase” candidates consisting of\n" "several characters may be shown." msgstr "" #: setup/main.py:862 msgid "Phrase" msgstr "詞彙" #: setup/main.py:864 msgid "Single Char" msgstr "一字" #. Translators: A combobox to choose whether the first #. candidate will be automatically selected during typing. #: setup/main.py:889 msgid "Auto select" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the first candidate will be automatically #. select during typing. #: setup/main.py:894 msgid "" "If set to “Yes”, this does the following 4 things:\n" "1) When typing “Return”, commit the \n" " candidate + line-feed\n" "2) When typing Tab, commit the candidate\n" "3) When committing using a commit key, commit\n" " the candidate + \" \"\n" "4) If typing the next character matches no candidates,\n" " commit the first candidate of the previous match.\n" " (Mostly needed for non-Chinese input methods like\n" " the Russian “translit”)" msgstr "" #. Translators: A combobox to choose whether automatic #. commits go into the preëdit or into the application #: setup/main.py:919 msgid "Auto commit mode:" msgstr "自動提交模式" #. Translators; A tooltip for the label of the combobox to #. choose whether automatic commits go into the preëdit or #. into the application. #: setup/main.py:924 msgid "" "Committing with the commit keys or with the mouse\n" "always commits to the application. This option is about\n" "“automatic” commits which may happen when\n" "one just continues typing input without committing\n" "manually. From time to time, “automatic” commits will\n" "happen then.\n" "“Direct” means such “automatic” commits go directly\n" "into the application, “Normal” means they get committed\n" "to preedit." msgstr "" #. Translators: A combobox to choose whether only single #. character candidates should be shown. #: setup/main.py:965 msgid "Action when typing invalid character:" msgstr "" #. Translators: A tooltip for label of the combobox to #. choose whether only single character candidates should #. be shown. #: setup/main.py:970 msgid "" "Determines what happens when a character which is not in the set of valid " "input characters for this table is typed: With “commit current candidate”, " "the currently selected candidate is inserted. With “commit typed keys”, the " "raw characters typed so far during the candidate selection process will be " "inserted instead. In all cases, the candidate selection ends when an invalid " "character is typed and the character in question is inserted immediately " "after the text that results from the options listed above." msgstr "" #: setup/main.py:983 msgid "Commit current candidate" msgstr "" #: setup/main.py:985 msgid "Commit typed keys" msgstr "" #. Translators: A combobox to choose whether a wildcard #. should be automatically appended to the input. #: setup/main.py:1009 msgid "Auto wildcard" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether a wildcard should be automatically #. appended to the input. #: setup/main.py:1014 msgid "" "If yes, a multi wildcard will be automatically\n" "appended to the end of the input string." msgstr "" #. Translators: This single character is a placeholder #. to match a any single character #: setup/main.py:1031 #, fuzzy #| msgid "Single character match" msgid "Single wildcard character:" msgstr "切換字元比對" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match a #. single character. #: setup/main.py:1036 msgid "" "The wildcard to match any single character.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: This single character is a placeholder #. to match a any number of characters #: setup/main.py:1057 msgid "Multi wildcard character:" msgstr "" #. Translators: This is a tooltip for the label of the #. entry where one can choose the wildcard to match any #. number of candidates. #: setup/main.py:1062 msgid "" "The wildcard used to match any number of characters.\n" "Type RETURN or ENTER to confirm after changing the wildcard." msgstr "" #. Translators: A combobox to choose whether #. the color scheme for a dark theme should be used. #: setup/main.py:1082 msgid "Use dark theme" msgstr "" #. Translators: A tooltip for the label of the combobox to #. choose whether the color scheme for a dark theme should #. be used. #: setup/main.py:1087 msgid "If yes, the color scheme for a dark theme will be used." msgstr "" #. Translators: A checkbox where one can choose whether a #. sound is played on error #: setup/main.py:1102 msgid "Play sound file on error" msgstr "" #: setup/main.py:1104 msgid "" "Here you can choose whether a sound file is played if an error occurs. If " "the simpleaudio module for Python3 is not installed, this option does " "nothing." msgstr "" #. Translators: When the debug level is greater than 0, #. debug information may be printed to the log file and #. debug information may also be shown graphically. #: setup/main.py:1145 msgid "Debug level:" msgstr "除錯層級" #. Translators: This is a tooltip for the label for the #. adjustment of the debug level. #: setup/main.py:1149 msgid "" "When greater than 0, debug information may be printed to the log file and " "debug information may also be shown graphically." msgstr "" #: setup/main.py:1529 msgid "Are you sure?" msgstr "" #: setup/main.py:1531 setup/main.py:1857 msgid "_Cancel" msgstr "取消(_C)" #: setup/main.py:1532 setup/main.py:1858 msgid "_OK" msgstr "確定(_O)" #: setup/main.py:1564 msgid "Another instance of this app is already running." msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to restore all default settings. #: setup/main.py:1628 msgid "Do you really want to restore all default settings?" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to to delete all the data #. ibus-table has learned from typing and selecting candidates. #. Deleting this learned data cannot be reversed. So #. the user should be really sure he really wants to do that. #: setup/main.py:1832 msgid "" "Do you really want to delete all data learned from typing and selecting " "candidates?" msgstr "" #: setup/main.py:1854 msgid "Select .wav sound file:" msgstr "" #: setup/main.py:2136 #, python-format msgid "Edit key bindings for command “%s”" msgstr "" #. Translators: This is a tooltip for the button to add a #. key binding. #: setup/main.py:2166 msgid "Add a key binding" msgstr "" #. Translators: This is a tooltip for the button to remove #. the selected key binding. #: setup/main.py:2180 msgid "Remove selected key binding" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding up (higher in priority). #: setup/main.py:2195 msgid "Move key binding up" msgstr "" #. Translators: This is a tooltip for the button to move #. the selected key binding down (lower in priority). #: setup/main.py:2208 msgid "Move key binding down" msgstr "" #. Translators: This is the text in the centre of a small #. dialog window, trying to confirm whether the user is #. really sure to reset the key bindings for *all* commands #. to their defaults. This cannot be reversed so the user #. should be really sure he wants to do that. #: setup/main.py:2275 msgid "" "Do you really want to set the key bindings for all commands to their " "defaults?" msgstr "" #: setup/main.py:3037 msgid "ibus is not running." msgstr "客端未執行。" #~ msgid "IBUS_ENGINE_NAME environment variable is not set." #~ msgstr "IBUS_ENGINE_NAME 環境變數尚未設定。" #~ msgid "" #~ "Cannot determine the engine name. Please use the --engine-name option." #~ msgstr "無法判定引擎名稱。請使用 --engine-name 選項。" #~ msgid "IBus Table engine %s is not available" #~ msgstr "IBus Table 引擎 %s 無法使用" #~ msgid "Next Page" #~ msgstr "下一頁" #~ msgid "Restore defaults as specified in the database for this engine." #~ msgstr "還原至此引擎資料庫中指定的預設值。" #~ msgid "Input mode:" #~ msgstr "輸入模式:" ibus-table-1.17.11/pylintrc000066400000000000000000000177541475513533100155250ustar00rootroot00000000000000[MASTER] # Specify a configuration file. #rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Pickle collected data for later comparisons. persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= [MESSAGES CONTROL] # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time. See also the "--disable" option for examples. #enable= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once).You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" #disable= [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html. You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. output-format=text # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Tells whether to display a full report or only the messages reports=no # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the massage information. See doc for all details #msg-template= [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=4 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no [BASIC] # List of builtins function names that should not be used, separated by a comma bad-functions=map,filter,apply,input # Regular expression which should only match correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression which should only match correct module level names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression which should only match correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Regular expression which should only match correct function names function-rgx=[a-z_][a-z0-9_]{2,50}$ # Regular expression which should only match correct method names method-rgx=[a-z_][a-z0-9_]{2,50}$ # Regular expression which should only match correct instance attribute names attr-rgx=[a-z_][a-z0-9_]{2,50}$ # Regular expression which should only match correct argument names argument-rgx=[a-z_][a-z0-9_]{2,50}$ # Regular expression which should only match correct variable names variable-rgx=[a-z_][a-z0-9_]{2,50}$ # Regular expression which should only match correct attribute names in class # bodies class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,50}|(__.*__))$ # Regular expression which should only match correct list comprehension / # generator expression variable names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Good variable names which should always be accepted, separated by a comma # f is a useful name for a file descriptor good-names=f,i,j,k,ex,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=__.*__ # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 [VARIABLES] # Tells whether we should check for unused import in __init__ files. init-import=no # A regular expression matching the beginning of the name of dummy variables # (i.e. not used). dummy-variables-rgx=_$|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins=FileNotFoundError, PermissionError [FORMAT] # Maximum number of characters on a single line. max-line-length=79 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Maximum number of lines in a module max-module-lines=5000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' [TYPECHECK] # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). ignored-classes=SQLObject, Popover, ScrolledWindow, ListBox, FlowBox, Grid, SearchBar, HeaderBar, SearchEntry, Window, IconSize, Button, StyleContext, Label, FileChooserDialog, HelpWindow, MessageDialog, Dialog # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E0201 when accessed. Python regular # expressions are accepted. generated-members=client_capabilities,update_property,register_properties,hide_lookup_table,update_lookup_table,forward_key_event,get_surrounding_text,delete_surrounding_text [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules=regsub,TERMIOS,Bastion,rexec # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= [DESIGN] # Maximum number of arguments for function / method max-args=10 # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.* # Maximum number of locals for function / method body max-locals=50 # Maximum number of return / yield for function / method body max-returns=50 # Maximum number of branch for function / method body # https://www.logilab.org/137226 “fix spelling of max-branchs option, now max-branches” max-branchs=100 max-branches=100 # Maximum number of statements in function / method body max-statements=200 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=100 # Minimum number of public methods for a class (see R0903). min-public-methods=0 # Maximum number of public methods for a class (see R0904). max-public-methods=60 [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception ibus-table-1.17.11/setup/000077500000000000000000000000001475513533100150605ustar00rootroot00000000000000ibus-table-1.17.11/setup/.gitignore000066400000000000000000000001441475513533100170470ustar00rootroot00000000000000version.py ibus-setup-table ibus-setup-table.desktop ibus-setup-table.desktop.in __pycache__/ *.pyc ibus-table-1.17.11/setup/Makefile.am000066400000000000000000000034631475513533100171220ustar00rootroot00000000000000# vim:set noet ts=4: # # ibus-table - The Chinese Table engine for IBus # # Copyright (c) 2008-2010 Peng Huang # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. setup_table_PYTHON = \ main.py \ version.py \ i18n.py \ $(NULL) setup_tabledir = $(datadir)/ibus-table/setup libexec_SCRIPTS = ibus-setup-table desktop_in_in_files = ibus-setup-table.desktop.in.in desktop_in_files = $(desktop_in_in_files:.in.in=.in) $(desktop_in_files): %.desktop.in: %.desktop.in.in Makefile ( \ PKGDATADIR=$(pkgdatadir); \ LIBEXECDIR=$(libexecdir); \ s=`cat $<`; \ eval "echo \"$${s}\""; \ ) > $@ desktopdir=$(datadir)/applications desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) $(desktop_DATA): $(desktop_in_files) Makefile $(AM_V_GEN)$(MSGFMT) --desktop --template $< -d $(top_srcdir)/po -o $@ CLEANFILES = \ $(desktop_DATA) \ $(desktop_in_files) \ *.pyc \ $(NULL) EXTRA_DIST = \ version.py.in \ ibus-setup-table.in \ $(desktop_in_in_files) \ $(desktop_in_files) \ $(desktop_DATA) \ $(NULL) test-table: $(ENV) DBUS_DEBUG=true \ IBUS_LOCALEDIR=@localedir@ \ PYTHONPATH=$(abs_top_srcdir):$(pyexecdir) \ $(PYTHON) $(srcdir)/main.py ziranma4 ibus-table-1.17.11/setup/i18n.py000066400000000000000000000024421475513533100162130ustar00rootroot00000000000000# vim:et sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2020 Mike FABIAN # # 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 from typing import Callable import locale import gettext import os DOMAINNAME = "ibus-table" _: Callable[[str], str] = lambda a: gettext.dgettext(DOMAINNAME, a) N_: Callable[[str], str] = lambda a: a def init() -> None: localedir = os.getenv("IBUS_LOCALEDIR") # Python's locale module doesn't provide all methods on some # operating systems like FreeBSD try: # for non-standard localedir locale.bindtextdomain(DOMAINNAME, localedir) except AttributeError: pass gettext.bindtextdomain(DOMAINNAME, localedir) ibus-table-1.17.11/setup/ibus-setup-table.desktop.in.in000066400000000000000000000003071475513533100226520ustar00rootroot00000000000000[Desktop Entry] Name=IBus Table Preferences Comment=Set IBus Table Options Exec=${LIBEXECDIR}/ibus-setup-table Icon=${PKGDATADIR}/icons/chinese.svg NoDisplay=true Type=Application StartupNotify=true ibus-table-1.17.11/setup/ibus-setup-table.in000066400000000000000000000020461475513533100205770ustar00rootroot00000000000000#!/bin/sh # vim:set noet ts=4: # # ibus-tmpl - The Input Bus template project # # Copyright (c) 2007-2012 Peng Huang # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. prefix=@prefix@ exec_prefix=@exec_prefix@ datarootdir=@datarootdir@ export IBUS_PREFIX=@prefix@ export IBUS_DATAROOTDIR=@datarootdir@ export IBUS_LOCALEDIR=@localedir@ cd @prefix@/share/ibus-table/setup/ exec @PYTHON@ main.py $@ ibus-table-1.17.11/setup/main.py000066400000000000000000004307201475513533100163640ustar00rootroot00000000000000# vim:et sts=4 sw=4 # # ibus-table-setup - Setup UI for ibus-table # # Copyright (c) 2008-2010 Peng Huang # Copyright (c) 2010 BYVoid # Copyright (c) 2012 Ma Xiaojun # Copyright (c) 2012 mozbugbox # Copyright (c) 2014-2022 Mike FABIAN # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 2.1 of the License, or # (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see ''' The setup tool for ibus-table. ''' from typing import Union from typing import Any from typing import Dict from typing import List import sys import os import re import html import signal import argparse import locale import copy import logging import logging.handlers import dbus # type: ignore import dbus.service # type: ignore from gi import require_version # type: ignore require_version('Gio', '2.0') from gi.repository import Gio # type: ignore require_version('GLib', '2.0') from gi.repository import GLib # set_prgname before importing other modules to show the name in warning # messages when import modules are failed. E.g. Gtk. GLib.set_application_name('IBus Table Preferences') # This makes gnome-shell load the .desktop file when running under Wayland: GLib.set_prgname('ibus-setup-table') require_version('Gdk', '3.0') from gi.repository import Gdk require_version('Gtk', '3.0') from gi.repository import Gtk require_version('Pango', '1.0') from gi.repository import Pango require_version('IBus', '1.0') from gi.repository import IBus from i18n import N_, _, init as i18n_init IMPORT_SIMPLEAUDIO_SUCCESSFUL = False try: import simpleaudio # type: ignore IMPORT_SIMPLEAUDIO_SUCCESSFUL = True except (ImportError,): IMPORT_SIMPLEAUDIO_SUCCESSFUL = False sys.path = [sys.path[0]+'/../engine'] + sys.path import tabsqlitedb import ibus_table_location import it_util import it_sound LOGGER = logging.getLogger('ibus-table') GTK_VERSION = (Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version()) PARSER = argparse.ArgumentParser( description='ibus-table setup tool') PARSER.add_argument( '-n', '--engine-name', action='store', type=str, dest='engine_name', default='', help=('Set the name of the engine, for example “table:cangjie3” ' 'or just “cangjie3”. Default: "%(default)s". ' 'If this option is not used, the value of the environment ' 'variable IBUS_ENGINE_NAME is tried instead. ' 'If the variable IBUS_ENGINE_NAME is also not set or empty, ' 'this help is printed.')) PARSER.add_argument( '-q', '--no-debug', action='store_true', default=False, help=('Do not write log file ' '~/.cache/ibus-table/setup-debug.log, ' 'default: %(default)s')) _ARGS = PARSER.parse_args() # Keep some translatable strings which are not used anymore here # so that the translations which have been done already are not lost. # I might want to use these strings again later. UNUSED_OLD_TRANSLATIONS = [ N_('Initial state'), N_('Direct input'), N_('Table input'), ] class SetupUI(Gtk.Window): # type: ignore ''' User interface of the setup tool ''' def __init__(self, engine_name: str = '') -> None: self._engine_name = engine_name Gtk.Window.__init__( self, title='码 IBus Table ' + self._engine_name + ' ' + _('Preferences')) Gtk.Window.set_default_icon_from_file( os.path.join( ibus_table_location.data(), 'icons', 'ibus-table.svg')) self.set_name('IBusTablePreferences') self.set_modal(True) style_provider = Gtk.CssProvider() style_provider.load_from_data( b''' #IBusTablePreferences { } row { /* This is for listbox rows */ border-style: groove; border-width: 0.05px; } ''') Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) database_filename = os.path.join( os.path.join(ibus_table_location.data(), 'tables'), self._engine_name + '.db') if not os.path.exists(database_filename): LOGGER.error('Cannot open database %s', database_filename) sys.exit(1) user_database_filename = os.path.basename(database_filename).replace( '.db', '-user.db') self.tabsqlitedb = tabsqlitedb.TabSqliteDb( filename=database_filename, user_db=user_database_filename, create_database=False) self.__is_chinese = False self.__is_cjk = False languages_str = self.tabsqlitedb.ime_properties.get('languages') if languages_str: languages = languages_str.split(',') for language in languages: if language.strip().startswith('zh'): self.__is_chinese = True for lang in ['zh', 'ja', 'ko']: if language.strip().startswith(lang): self.__is_cjk = True self.__user_can_define_phrase = False user_can_define_phrase = self.tabsqlitedb.ime_properties.get( 'user_can_define_phrase') if user_can_define_phrase: self.__user_can_define_phrase = ( user_can_define_phrase.lower() == 'true') self.__rules = self.tabsqlitedb.ime_properties.get('rules') self._gsettings = Gio.Settings( schema='org.freedesktop.ibus.engine.table', path='/org/freedesktop/ibus/engine/table/%s/' % self._engine_name) self._fill_settings_dict() self.set_title( '码 IBus Table ' + self._engine_name + ' ' + _('Preferences')) self.connect('destroy-event', self.__class__._on_destroy_event) self.connect('delete-event', self.__class__._on_delete_event) self._main_container = Gtk.Box() self._main_container.set_orientation(Gtk.Orientation.VERTICAL) self._main_container.set_spacing(0) self.add(self._main_container) # pylint: disable=no-member self._notebook = Gtk.Notebook() self._notebook.set_visible(True) self._notebook.set_can_focus(False) self._notebook.set_scrollable(True) self._notebook.set_hexpand(True) self._notebook.set_vexpand(True) self._main_container.pack_start(self._notebook, True, True, 0) self._dialog_action_area = Gtk.Box() self._dialog_action_area.set_orientation(Gtk.Orientation.HORIZONTAL) self._dialog_action_area.set_visible(True) self._dialog_action_area.set_can_focus(False) self._dialog_action_area.set_hexpand(True) self._dialog_action_area.set_vexpand(False) self._main_container.pack_end(self._dialog_action_area, True, True, 0) self._about_button = Gtk.Button(label=_('About')) self._about_button.set_hexpand(True) self._about_button.connect('clicked', self.__class__._on_about_button_clicked) self._dialog_action_area.add(self._about_button) self._restore_all_defaults_button = Gtk.Button() self._restore_all_defaults_button.set_hexpand(True) self._restore_all_defaults_button_label = Gtk.Label() self._restore_all_defaults_button_label.set_text( _('Restore all defaults')) self._restore_all_defaults_button.add( self._restore_all_defaults_button_label) self._restore_all_defaults_button.connect( 'clicked', self._on_restore_all_defaults_button_clicked) self._dialog_action_area.add(self._restore_all_defaults_button) self._close_button = Gtk.Button() self._close_button.set_hexpand(True) self._close_button_label = Gtk.Label() self._close_button_label.set_text_with_mnemonic(_('_Close')) self._close_button.add(self._close_button_label) self._close_button.connect('clicked', self.__class__._on_close_clicked) self._dialog_action_area.add(self._close_button) grid_border_width = 10 grid_row_spacing = 10 grid_column_spacing = 10 self._options_grid = Gtk.Grid() self._options_grid.set_visible(True) self._options_grid.set_can_focus(False) self._options_grid.set_border_width(grid_border_width) self._options_grid.set_row_spacing(grid_row_spacing) self._options_grid.set_column_spacing(grid_column_spacing) self._options_grid.set_row_homogeneous(False) self._options_grid.set_column_homogeneous(True) self._options_grid.set_hexpand(True) self._options_grid.set_vexpand(False) self._options_label = Gtk.Label() # Translators: This is the label of a tab in the setup tool. # Here the user can set up some options which influence the # behaviour of ibus-table. self._options_label.set_text(_('Settings')) self._options_details_grid = Gtk.Grid() self._options_details_grid.set_visible(True) self._options_details_grid.set_can_focus(False) self._options_details_grid.set_border_width(grid_border_width) self._options_details_grid.set_row_spacing(grid_row_spacing) self._options_details_grid.set_column_spacing(grid_column_spacing) self._options_details_grid.set_row_homogeneous(False) self._options_details_grid.set_column_homogeneous(True) self._options_details_grid.set_hexpand(True) self._options_details_grid.set_vexpand(False) self._options_details_label = Gtk.Label() # Translators: This is the label of a tab in the setup tool. # Here the user can set up some more advanced options. self._options_details_label.set_text(_('Details')) self._keybindings_vbox = Gtk.Box() self._keybindings_vbox.set_orientation(Gtk.Orientation.VERTICAL) self._keybindings_vbox.set_spacing(0) margin = 10 self._keybindings_vbox.set_margin_start(margin) self._keybindings_vbox.set_margin_end(margin) self._keybindings_vbox.set_margin_top(margin) self._keybindings_vbox.set_margin_bottom(margin) self._keybindings_label = Gtk.Label() # Translators: This is the label of a tab in the setup tool. # Here the user can customize the key bindings to execute # certain commands of ibus-table. For example which key to use # to commit, which key to use to move to the next candidate # etc... self._keybindings_label.set_text(_('Key bindings')) self._notebook.append_page( self._options_grid, self._options_label) self._notebook.append_page( self._options_details_grid, self._options_details_label) self._notebook.append_page( self._keybindings_vbox, self._keybindings_label) _options_grid_row = -1 self._remember_input_mode_label = Gtk.Label() self._remember_input_mode_label.set_text( # Translators: A combobox to choose whether the input mode # (“Direct input” or “Table input”) should be remembered # or whether ibus-table should always use “Table input” by # default after a restart. _('Remember input mode')) self._remember_input_mode_label.set_tooltip_text( # Translators: A tooltip for the label of the combobox to # choose whether the input mode (“Direct input” or “Table # input”) should be remembered or whether ibus-table # should always use “Table input” by default after a # restart. _('Whether the last used input mode should be remembered ' 'or whether ibus-table should start in “Table mode” ' 'by default after a restart. There are two input modes: ' '“Table input” means the input method is on. ' '“Direct input” is almost the same as if the ' 'input method were off, i.e. not used at all, most ' 'characters just get passed to the application. ' 'But some conversion between fullwidth and ' 'halfwidth may still happen in direct input mode.')) self._remember_input_mode_label.set_xalign(0) self._remember_input_mode_combobox = Gtk.ComboBox() self._remember_input_mode_store = Gtk.ListStore(str, bool) self._remember_input_mode_store.append( [_('No'), False]) self._remember_input_mode_store.append( [_('Yes'), True]) self._remember_input_mode_combobox.set_model( self._remember_input_mode_store) renderer_text = Gtk.CellRendererText() self._remember_input_mode_combobox.pack_start( renderer_text, True) self._remember_input_mode_combobox.add_attribute( renderer_text, "text", 0) for index, item in enumerate(self._remember_input_mode_store): if self._settings_dict['rememberinputmode']['user'] == item[1]: self._remember_input_mode_combobox.set_active(index) self._remember_input_mode_combobox.connect( "changed", self._on_remember_input_mode_combobox_changed) _options_grid_row += 1 self._options_grid.attach( self._remember_input_mode_label, 0, _options_grid_row, 1, 1) self._options_grid.attach( self._remember_input_mode_combobox, 1, _options_grid_row, 1, 1) self._chinese_mode_label = Gtk.Label() self._chinese_mode_label.set_text( # Translators: A combobox to choose the variant of # Chinese which should be preferred. _('Chinese mode:')) self._chinese_mode_label.set_tooltip_text( # Translators: A tooltip for the label of the combobox to # choose which variant of Chinese should be preferred. _('“Simplified Chinese” shows only characters \n' 'used in simplified Chinese. “Traditional Chinese”\n' 'shows only characters used in traditional Chinese.\n' '“Simplified Chinese before traditional” shows all\n' 'characters but puts the simplified characters higher\n' 'up in the candidate list. “Traditional Chinese before\n' 'simplified” puts the traditional characters higher up\n' 'in the candidate list. “All characters” just shows all\n' 'matches without any particular filtering on traditional\n' 'versus simplified Chinese.')) self._chinese_mode_label.set_xalign(0) self._chinese_mode_combobox = Gtk.ComboBox() self._chinese_mode_store = Gtk.ListStore(str, int) self._chinese_mode_store.append( # Translators: This is the setting to use only # simplified Chinese [_('Simplified Chinese'), 0]) self._chinese_mode_store.append( # Translators: This is the setting to use only # traditional Chinese [_('Traditional Chinese'), 1]) self._chinese_mode_store.append( # Translators: This is the setting to use both # simplified and traditional Chinese but prefer # simplified Chinese [_('Simplified Chinese before traditional'), 2]) self._chinese_mode_store.append( # Translators: This is the setting to use both # simplified and traditional Chinese but prefer # traditional Chinese [_('Traditional Chinese before simplified'), 3]) self._chinese_mode_store.append( # Translators: This is the setting to use both # simplified and traditional Chinese in no # particular order [_('All Chinese characters'), 4]) self._chinese_mode_combobox.set_model( self._chinese_mode_store) renderer_text = Gtk.CellRendererText() self._chinese_mode_combobox.pack_start( renderer_text, True) self._chinese_mode_combobox.add_attribute( renderer_text, "text", 0) for index, item in enumerate(self._chinese_mode_store): if self._settings_dict['chinesemode']['user'] == item[1]: self._chinese_mode_combobox.set_active(index) self._chinese_mode_combobox.connect( "changed", self._on_chinese_mode_combobox_changed) if self.__is_chinese: _options_grid_row += 1 self._options_grid.attach( self._chinese_mode_label, 0, _options_grid_row, 1, 1) self._options_grid.attach( self._chinese_mode_combobox, 1, _options_grid_row, 1, 1) self._table_full_width_letter_mode_label = Gtk.Label() self._table_full_width_letter_mode_label.set_text( # Translators: A combobox to choose the letter width # while in “Table input” mode. _('Table input letter width:')) self._table_full_width_letter_mode_label.set_tooltip_text( # Translators: A tooltip for the label of the combobox to # choose the letter width while in “Table input” mode. _('Whether to use fullwidth or halfwidth\n' 'letters in table input mode.')) self._table_full_width_letter_mode_label.set_xalign(0) self._table_full_width_letter_mode_combobox = Gtk.ComboBox() self._table_full_width_letter_mode_store = Gtk.ListStore(str, bool) self._table_full_width_letter_mode_store.append( # Translators: This is the mode to use half width letters # while in “Table input” mode. [_('Half'), False]) self._table_full_width_letter_mode_store.append( # Translators: This is the mode to use full width letters # while in “Table input” mode. [_('Full'), True]) self._table_full_width_letter_mode_combobox.set_model( self._table_full_width_letter_mode_store) renderer_text = Gtk.CellRendererText() self._table_full_width_letter_mode_combobox.pack_start( renderer_text, True) self._table_full_width_letter_mode_combobox.add_attribute( renderer_text, "text", 0) for index, item in enumerate(self._table_full_width_letter_mode_store): if self._settings_dict['tabdeffullwidthletter']['user'] == item[1]: self._table_full_width_letter_mode_combobox.set_active(index) self._table_full_width_letter_mode_combobox.connect( "changed", self._on_table_full_width_letter_mode_combobox_changed) if self.__is_cjk: _options_grid_row += 1 self._options_grid.attach( self._table_full_width_letter_mode_label, 0, _options_grid_row, 1, 1) self._options_grid.attach( self._table_full_width_letter_mode_combobox, 1, _options_grid_row, 1, 1) self._table_full_width_punct_mode_label = Gtk.Label() self._table_full_width_punct_mode_label.set_text( # Translators: A combobox to choose the punctuation width # while in “Table input” mode. _('Table input punctuation width:')) self._table_full_width_punct_mode_label.set_tooltip_text( # Translators: A tooltip for the label of the combobox to # choose the punctuation width while in “Table input” mode. _('Whether to use fullwidth or halfwidth\n' 'punctuation in table input mode.')) self._table_full_width_punct_mode_label.set_xalign(0) self._table_full_width_punct_mode_combobox = Gtk.ComboBox() self._table_full_width_punct_mode_store = Gtk.ListStore( str, bool) self._table_full_width_punct_mode_store.append( # Translators: This is the mode to use half width punctuation # while in “Table input” mode. [_('Half'), False]) self._table_full_width_punct_mode_store.append( # Translators: This is the mode to use full width punctuation # while in “Table input” mode. [_('Full'), True]) self._table_full_width_punct_mode_combobox.set_model( self._table_full_width_punct_mode_store) renderer_text = Gtk.CellRendererText() self._table_full_width_punct_mode_combobox.pack_start( renderer_text, True) self._table_full_width_punct_mode_combobox.add_attribute( renderer_text, "text", 0) for index, item in enumerate( self._table_full_width_punct_mode_store): if self._settings_dict['tabdeffullwidthpunct']['user'] == item[1]: self._table_full_width_punct_mode_combobox.set_active( index) self._table_full_width_punct_mode_combobox.connect( "changed", self._on_table_full_width_punct_mode_combobox_changed) if self.__is_cjk: _options_grid_row += 1 self._options_grid.attach( self._table_full_width_punct_mode_label, 0, _options_grid_row, 1, 1) self._options_grid.attach( self._table_full_width_punct_mode_combobox, 1, _options_grid_row, 1, 1) self._direct_full_width_letter_mode_label = Gtk.Label() self._direct_full_width_letter_mode_label.set_text( # Translators: A combobox to choose the letter width # while in “Direct input” mode. _('Direct input letter width:')) self._direct_full_width_letter_mode_label.set_tooltip_text( # Translators: A tooltip for the label of the combobox to # choose the letter width while in “Direct input” mode. _('Whether to use fullwidth or halfwidth\n' 'letters in direct input mode.')) self._direct_full_width_letter_mode_label.set_xalign(0) self._direct_full_width_letter_mode_combobox = Gtk.ComboBox() self._direct_full_width_letter_mode_store = Gtk.ListStore(str, bool) self._direct_full_width_letter_mode_store.append( # Translators: This is the mode to use half width letters # while in “Direct input” mode. [_('Half'), False]) self._direct_full_width_letter_mode_store.append( # Translators: This is the mode to use full width letters # while in “Direct input” mode. [_('Full'), True]) self._direct_full_width_letter_mode_combobox.set_model( self._direct_full_width_letter_mode_store) renderer_text = Gtk.CellRendererText() self._direct_full_width_letter_mode_combobox.pack_start( renderer_text, True) self._direct_full_width_letter_mode_combobox.add_attribute( renderer_text, "text", 0) for index, item in enumerate( self._direct_full_width_letter_mode_store): if self._settings_dict['endeffullwidthletter']['user'] == item[1]: self._direct_full_width_letter_mode_combobox.set_active(index) self._direct_full_width_letter_mode_combobox.connect( "changed", self._on_direct_full_width_letter_mode_combobox_changed) if self.__is_cjk: _options_grid_row += 1 self._options_grid.attach( self._direct_full_width_letter_mode_label, 0, _options_grid_row, 1, 1) self._options_grid.attach( self._direct_full_width_letter_mode_combobox, 1, _options_grid_row, 1, 1) self._direct_full_width_punct_mode_label = Gtk.Label() self._direct_full_width_punct_mode_label.set_text( # Translators: A combobox to choose the punctuation width # while in “Direct input” mode. _('Direct input punctuation width:')) self._direct_full_width_punct_mode_label.set_tooltip_text( # Translators: A tooltip for the label of the combobox to # choose the punctuation width while in “Direct input” mode. _('Whether to use fullwidth or halfwidth\n' 'punctuation in direct input mode.')) self._direct_full_width_punct_mode_label.set_xalign(0) self._direct_full_width_punct_mode_combobox = Gtk.ComboBox() self._direct_full_width_punct_mode_store = Gtk.ListStore( str, bool) self._direct_full_width_punct_mode_store.append( # Translators: This is the mode to use half width punctuation # while in “Direct input” mode. [_('Half'), False]) self._direct_full_width_punct_mode_store.append( # Translators: This is the mode to use full width punctuation # while in “Direct input” mode. [_('Full'), True]) self._direct_full_width_punct_mode_combobox.set_model( self._direct_full_width_punct_mode_store) renderer_text = Gtk.CellRendererText() self._direct_full_width_punct_mode_combobox.pack_start( renderer_text, True) self._direct_full_width_punct_mode_combobox.add_attribute( renderer_text, "text", 0) for index, item in enumerate( self._direct_full_width_punct_mode_store): if self._settings_dict['endeffullwidthpunct']['user'] == item[1]: self._direct_full_width_punct_mode_combobox.set_active( index) self._direct_full_width_punct_mode_combobox.connect( "changed", self._on_direct_full_width_punct_mode_combobox_changed) if self.__is_cjk: _options_grid_row += 1 self._options_grid.attach( self._direct_full_width_punct_mode_label, 0, _options_grid_row, 1, 1) self._options_grid.attach( self._direct_full_width_punct_mode_combobox, 1, _options_grid_row, 1, 1) self._candidate_list_section_heading_label = Gtk.Label() self._candidate_list_section_heading_label.set_text( '' + _('Candidate list') + '') self._candidate_list_section_heading_label.set_use_markup(True) self._candidate_list_section_heading_label.set_xalign(0) _options_grid_row += 1 self._options_grid.attach( self._candidate_list_section_heading_label, 0, _options_grid_row, 2, 1) self._always_show_lookup_checkbutton = Gtk.CheckButton( # Translators: A combobox to choose whether # a candidate list should be shown or hidden. # For Chinese input methods one usually wants the # candidate list to be shown. But for some non-Chinese # input methods like the Russian “translit”, hiding # the candidate lists is better. label=_('Show candidate list')) self._always_show_lookup_checkbutton.set_tooltip_text( # Translit: A tooltip for the label of the combobox to # choose whether a candidate list should be shown or # hidden. _('Whether candidate lists should be shown or hidden.\n' 'For Chinese input methods one usually wants the\n' 'candidate lists to be shown. But for some non-Chinese\n' 'input methods like the Russian “translit”, hiding the\n' 'candidate lists is better.')) self._always_show_lookup_checkbutton.set_hexpand(False) self._always_show_lookup_checkbutton.set_vexpand(False) self._always_show_lookup_checkbutton.set_active( self._settings_dict['alwaysshowlookup']['user']) self._always_show_lookup_checkbutton.connect( "clicked", self._on_always_show_lookup_checkbutton) _options_grid_row += 1 self._options_grid.attach( self._always_show_lookup_checkbutton, 0, _options_grid_row, 2, 1) self._lookup_table_orientation_label = Gtk.Label() self._lookup_table_orientation_label.set_text( # Translators: A combobox to choose whether the candidate # window should be drawn horizontally or vertically. _('Orientation:')) self._lookup_table_orientation_label.set_tooltip_text( # Translators: A tooltip for the label of the combobox to # choose whether the candidate window should be drawn # horizontally or vertically. _('Whether the lookup table showing the candidates\n' 'should be vertical or horizontal.')) self._lookup_table_orientation_label.set_xalign(0) self._lookup_table_orientation_combobox = Gtk.ComboBox() self._lookup_table_orientation_store = Gtk.ListStore(str, int) self._lookup_table_orientation_store.append( [_('Horizontal'), int(IBus.Orientation.HORIZONTAL)]) self._lookup_table_orientation_store.append( [_('Vertical'), int(IBus.Orientation.VERTICAL)]) self._lookup_table_orientation_store.append( [_('System default'), int(IBus.Orientation.SYSTEM)]) self._lookup_table_orientation_combobox.set_model( self._lookup_table_orientation_store) renderer_text = Gtk.CellRendererText() self._lookup_table_orientation_combobox.pack_start( renderer_text, True) self._lookup_table_orientation_combobox.add_attribute( renderer_text, "text", 0) for index, item in enumerate(self._lookup_table_orientation_store): if (self._settings_dict['lookuptableorientation']['user'] == item[1]): self._lookup_table_orientation_combobox.set_active(index) self._lookup_table_orientation_combobox.connect( "changed", self._on_lookup_table_orientation_combobox_changed) _options_grid_row += 1 self._options_grid.attach( self._lookup_table_orientation_label, 0, _options_grid_row, 1, 1) self._options_grid.attach( self._lookup_table_orientation_combobox, 1, _options_grid_row, 1, 1) self._page_size_label = Gtk.Label() # Translators: Here one can choose how many suggestion # candidates to show in one page of the candidate list. self._page_size_label.set_text(_('Page size:')) self._page_size_label.set_tooltip_text( # Translators: A tooltip for the label of the adjustment # for the number of candidates to show in one page of the # candidate list. _('The maximum number of candidates in\n' 'one page of the lookup table. You can switch\n' 'pages in the lookup table using the page up/down\n' 'keys or the arrow up/down keys.')) self._page_size_label.set_xalign(0) self._page_size_adjustment = Gtk.SpinButton() self._page_size_adjustment.set_visible(True) self._page_size_adjustment.set_can_focus(True) self._page_size_adjustment.set_increments(1.0, 1.0) self._page_size_adjustment.set_range(1.0, 10.0) self._page_size_adjustment.set_value( self._settings_dict['lookuptablepagesize']['user']) self._page_size_adjustment.connect( 'value-changed', self._on_page_size_adjustment_value_changed) _options_grid_row += 1 self._options_grid.attach( self._page_size_label, 0, _options_grid_row, 1, 1) self._options_grid.attach( self._page_size_adjustment, 1, _options_grid_row, 1, 1) self._keybindings_label = Gtk.Label() self._keybindings_label.set_text( '' + _('Current key bindings:') + '') self._keybindings_label.set_use_markup(True) self._keybindings_label.set_margin_start(margin) self._keybindings_label.set_margin_end(margin) self._keybindings_label.set_margin_top(margin) self._keybindings_label.set_margin_bottom(margin) self._keybindings_label.set_hexpand(False) self._keybindings_label.set_vexpand(False) self._keybindings_label.set_xalign(0) self._keybindings_treeview_scroll = Gtk.ScrolledWindow() self._keybindings_treeview_scroll.set_can_focus(False) self._keybindings_treeview_scroll.set_hexpand(False) self._keybindings_treeview_scroll.set_vexpand(True) #self._keybindings_treeview_scroll.set_shadow_type(in) self._keybindings_treeview = Gtk.TreeView() self._keybindings_treeview_model = Gtk.ListStore(str, str) self._keybindings_treeview.set_model(self._keybindings_treeview_model) user_keybindings = self._settings_dict['keybindings']['user'] for command in sorted(user_keybindings): self._keybindings_treeview_model.append( (command, repr(user_keybindings[command]))) keybindings_treeview_column_0 = Gtk.TreeViewColumn( # Translators: Column heading of the table listing the # existing key bindings _('Command'), Gtk.CellRendererText(), text=0) keybindings_treeview_column_0.set_sort_column_id(0) self._keybindings_treeview.append_column(keybindings_treeview_column_0) keybindings_treeview_column_1 = Gtk.TreeViewColumn( # Translators: Column heading of the table listing the # existing key bindings _('Key bindings'), Gtk.CellRendererText(), text=1) keybindings_treeview_column_1.set_sort_column_id(1) self._keybindings_treeview.append_column(keybindings_treeview_column_1) self._keybindings_treeview.get_selection().connect( 'changed', self._on_keybindings_treeview_row_selected) self._keybindings_treeview.connect( 'row-activated', self._on_keybindings_treeview_row_activated) self._keybindings_treeview_scroll.add(self._keybindings_treeview) self._keybindings_vbox.pack_start( self._keybindings_label, False, False, 0) self._keybindings_vbox.pack_start( self._keybindings_treeview_scroll, True, True, 0) self._keybindings_action_area = Gtk.Box() self._keybindings_action_area.set_orientation( Gtk.Orientation.HORIZONTAL) self._keybindings_action_area.set_can_focus(False) self._keybindings_vbox.add( self._keybindings_action_area) self._keybindings_edit_button = Gtk.Button() self._keybindings_edit_button_label = Gtk.Label() self._keybindings_edit_button_label.set_text( _('Edit')) self._keybindings_edit_button.add( self._keybindings_edit_button_label) self._keybindings_edit_button.set_tooltip_text( # Translators: A tooltip for the button to edit # the keybindings for the selected command. _('Edit the key bindings for the selected command')) self._keybindings_edit_button.set_sensitive(False) self._keybindings_edit_button.connect( 'clicked', self._on_keybindings_edit_button_clicked) self._keybindings_default_button = Gtk.Button() self._keybindings_default_button_label = Gtk.Label() self._keybindings_default_button_label.set_text( _('Set to default')) self._keybindings_default_button.add( self._keybindings_default_button_label) self._keybindings_default_button.set_tooltip_text( # Translators: A tooltip for the button to set # the default key bindings for the selected command. _('Set default key bindings for the selected command')) self._keybindings_default_button.set_sensitive(False) self._keybindings_default_button.connect( 'clicked', self._on_keybindings_default_button_clicked) self._keybindings_all_default_button = Gtk.Button() self._keybindings_all_default_button_label = Gtk.Label() self._keybindings_all_default_button_label.set_text( _('Set all to default')) self._keybindings_all_default_button.add( self._keybindings_all_default_button_label) self._keybindings_all_default_button.set_tooltip_text( # Translators: A tooltip for the button to set the # key bindings to default for all commands. _('Set default key bindings for all commands')) self._keybindings_all_default_button.set_sensitive(True) self._keybindings_all_default_button.connect( 'clicked', self._on_keybindings_all_default_button_clicked) self._keybindings_action_area.add(self._keybindings_edit_button) self._keybindings_action_area.add(self._keybindings_default_button) self._keybindings_action_area.add(self._keybindings_all_default_button) self._keybindings_selected_command = '' self._keybindings_edit_popover_selected_keybinding = '' self._keybindings_edit_popover_selected_keybinding_index = -1 self._keybindings_edit_popover_listbox = None self._keybindings_edit_popover = None self._keybindings_edit_popover_scroll = None self._keybindings_edit_popover_add_button = None self._keybindings_edit_popover_remove_button = None self._keybindings_edit_popover_default_button = None self._keybindings_edit_popover_up_button = None self._keybindings_edit_popover_down_button = None _options_details_grid_row = -1 self._dynamic_adjust_checkbutton = Gtk.CheckButton( # Translators: A checkbox where one can choose whether the # order of the candidates is dynamically adjusted according # to how often the candidates are used. label=_('Dynamic adjust')) self._dynamic_adjust_checkbutton.set_tooltip_text( _('Here you can choose whether the order of the candidates is ' + 'dynamically adjusted according to how often the candidates ' + 'are used.')) self._dynamic_adjust_checkbutton.set_hexpand(False) self._dynamic_adjust_checkbutton.set_vexpand(False) self._dynamic_adjust_checkbutton.set_active( self._settings_dict['dynamicadjust']['user']) self._dynamic_adjust_checkbutton.connect( 'clicked', self._on_dynamic_adjust_checkbutton) self._dynamic_adjust_forget_button = Gtk.Button() self._dynamic_adjust_forget_button_box = Gtk.HBox() self._dynamic_adjust_forget_button_label = Gtk.Label() self._dynamic_adjust_forget_button_label.set_text( _('Delete all learned data')) self._dynamic_adjust_forget_button_label.set_use_markup(True) self._dynamic_adjust_forget_button_label.set_max_width_chars( 40) self._dynamic_adjust_forget_button_label.set_line_wrap(False) self._dynamic_adjust_forget_button_label.set_ellipsize( Pango.EllipsizeMode.START) self._dynamic_adjust_forget_button_box.pack_start( self._dynamic_adjust_forget_button_label, False, False, 0) self._dynamic_adjust_forget_button.add( self._dynamic_adjust_forget_button_box) self._dynamic_adjust_forget_button.connect( 'clicked', self._on_dynamic_adjust_forget_button) _options_details_grid_row += 1 self._options_details_grid.attach( self._dynamic_adjust_checkbutton, 0, _options_details_grid_row, 1, 1) self._options_details_grid.attach( self._dynamic_adjust_forget_button, 1, _options_details_grid_row, 1, 1) self._onechar_mode_label = Gtk.Label() self._onechar_mode_label.set_text( # Translators: A combobox to choose whether only single # character candidates should be shown. _('Compose:')) self._onechar_mode_label.set_tooltip_text( # Translators: A tooltip for label of the combobox to # choose whether only single character candidates should # be shown. _('If this is set to “single char”, only single\n' 'character candidates will be shown. If it is\n' 'set to “Phrase” candidates consisting of\n' 'several characters may be shown.')) self._onechar_mode_label.set_xalign(0) self._onechar_mode_combobox = Gtk.ComboBox() self._onechar_mode_store = Gtk.ListStore(str, int) self._onechar_mode_store.append( [_('Phrase'), False]) self._onechar_mode_store.append( [_('Single Char'), True]) self._onechar_mode_combobox.set_model( self._onechar_mode_store) renderer_text = Gtk.CellRendererText() self._onechar_mode_combobox.pack_start( renderer_text, True) self._onechar_mode_combobox.add_attribute( renderer_text, "text", 0) for index, item in enumerate(self._onechar_mode_store): if self._settings_dict['onechar']['user'] == item[1]: self._onechar_mode_combobox.set_active(index) self._onechar_mode_combobox.connect( "changed", self._on_onechar_mode_combobox_changed) if self.__is_cjk: _options_details_grid_row += 1 self._options_details_grid.attach( self._onechar_mode_label, 0, _options_details_grid_row, 1, 1) self._options_details_grid.attach( self._onechar_mode_combobox, 1, _options_details_grid_row, 1, 1) self._autoselect_mode_checkbutton = Gtk.CheckButton( # Translators: A combobox to choose whether the first # candidate will be automatically selected during typing. label=_('Auto select')) self._autoselect_mode_checkbutton.set_tooltip_text( # Translators: A tooltip for the label of the combobox to # choose whether the first candidate will be automatically # select during typing. _('If set to “Yes”, this does the following 4 things:\n' '1) When typing “Return”, commit the \n' ' candidate + line-feed\n' '2) When typing Tab, commit the candidate\n' '3) When committing using a commit key, commit\n' ' the candidate + " "\n' '4) If typing the next character matches no candidates,\n' ' commit the first candidate of the previous match.\n' ' (Mostly needed for non-Chinese input methods like\n' ' the Russian “translit”)')) self._autoselect_mode_checkbutton.set_hexpand(False) self._autoselect_mode_checkbutton.set_vexpand(False) self._autoselect_mode_checkbutton.set_active( self._settings_dict['autoselect']['user']) self._autoselect_mode_checkbutton.connect( 'clicked', self._on_autoselect_mode_checkbutton) _options_details_grid_row += 1 self._options_details_grid.attach( self._autoselect_mode_checkbutton, 0, _options_details_grid_row, 2, 1) self._autocommit_mode_label = Gtk.Label() self._autocommit_mode_label.set_text( # Translators: A combobox to choose whether automatic # commits go into the preëdit or into the application _('Auto commit mode:')) self._autocommit_mode_label.set_tooltip_text( # Translators; A tooltip for the label of the combobox to # choose whether automatic commits go into the preëdit or # into the application. _('Committing with the commit keys or with the mouse\n' 'always commits to the application. This option is about\n' '“automatic” commits which may happen when\n' 'one just continues typing input without committing\n' 'manually. From time to time, “automatic” commits will\n' 'happen then.\n' '“Direct” means such “automatic” commits go directly\n' 'into the application, “Normal” means they get committed\n' 'to preedit.')) self._autocommit_mode_label.set_xalign(0) self._autocommit_mode_combobox = Gtk.ComboBox() self._autocommit_mode_store = Gtk.ListStore(str, int) self._autocommit_mode_store.append( [_('Normal'), False]) self._autocommit_mode_store.append( [_('Direct'), True]) self._autocommit_mode_combobox.set_model( self._autocommit_mode_store) renderer_text = Gtk.CellRendererText() self._autocommit_mode_combobox.pack_start( renderer_text, True) self._autocommit_mode_combobox.add_attribute( renderer_text, "text", 0) for index, item in enumerate(self._autocommit_mode_store): if self._settings_dict['autocommit']['user'] == item[1]: self._autocommit_mode_combobox.set_active(index) self._autocommit_mode_combobox.connect( "changed", self._on_autocommit_mode_combobox_changed) if self.__user_can_define_phrase and self.__rules: _options_details_grid_row += 1 self._options_details_grid.attach( self._autocommit_mode_label, 0, _options_details_grid_row, 1, 1) self._options_details_grid.attach( self._autocommit_mode_combobox, 1, _options_details_grid_row, 1, 1) self._commit_invalid_mode_label = Gtk.Label() self._commit_invalid_mode_label.set_text( # Translators: A combobox to choose whether only single # character candidates should be shown. _('Action when typing invalid character:')) self._commit_invalid_mode_label.set_tooltip_text( # Translators: A tooltip for label of the combobox to # choose whether only single character candidates should # be shown. _('Determines what happens when a character which is not ' 'in the set of valid input characters for this table ' 'is typed: With “commit current candidate”, the currently ' 'selected candidate is inserted. With “commit typed keys”, ' 'the raw characters typed so far during the candidate ' 'selection process will be inserted instead. In all cases, ' 'the candidate selection ends when an invalid character is ' 'typed and the character in question is inserted immediately ' 'after the text that results from the options listed above.')) self._commit_invalid_mode_label.set_xalign(0) self._commit_invalid_mode_combobox = Gtk.ComboBox() self._commit_invalid_mode_store = Gtk.ListStore(str, int) self._commit_invalid_mode_store.append( [_('Commit current candidate'), 0]) self._commit_invalid_mode_store.append( [_('Commit typed keys'), 1]) self._commit_invalid_mode_combobox.set_model( self._commit_invalid_mode_store) renderer_text = Gtk.CellRendererText() self._commit_invalid_mode_combobox.pack_start( renderer_text, True) self._commit_invalid_mode_combobox.add_attribute( renderer_text, "text", 0) for index, item in enumerate(self._commit_invalid_mode_store): if self._settings_dict['commitinvalidmode']['user'] == item[1]: self._commit_invalid_mode_combobox.set_active(index) self._commit_invalid_mode_combobox.connect( "changed", self._on_commit_invalid_mode_combobox_changed) _options_details_grid_row += 1 self._options_details_grid.attach( self._commit_invalid_mode_label, 0, _options_details_grid_row, 1, 1) self._options_details_grid.attach( self._commit_invalid_mode_combobox, 1, _options_details_grid_row, 1, 1) self._autowildcard_mode_checkbutton = Gtk.CheckButton( # Translators: A combobox to choose whether a wildcard # should be automatically appended to the input. label=_('Auto wildcard')) self._autowildcard_mode_checkbutton.set_tooltip_text( # Translators: A tooltip for the label of the combobox to # choose whether a wildcard should be automatically # appended to the input. _('If yes, a multi wildcard will be automatically\n' 'appended to the end of the input string.')) self._autowildcard_mode_checkbutton.set_hexpand(False) self._autowildcard_mode_checkbutton.set_vexpand(False) self._autowildcard_mode_checkbutton.set_active( self._settings_dict['autowildcard']['user']) self._autowildcard_mode_checkbutton.connect( 'clicked', self._on_autowildcard_mode_checkbutton) _options_details_grid_row += 1 self._options_details_grid.attach( self._autowildcard_mode_checkbutton, 0, _options_details_grid_row, 2, 1) self._single_wildcard_char_label = Gtk.Label() self._single_wildcard_char_label.set_text( # Translators: This single character is a placeholder # to match a any single character _('Single wildcard character:')) self._single_wildcard_char_label.set_tooltip_text( # Translators: This is a tooltip for the label of the # entry where one can choose the wildcard to match a # single character. _('The wildcard to match any single character.\n' 'Type RETURN or ENTER to confirm after changing the wildcard.')) self._single_wildcard_char_label.set_xalign(0) self._single_wildcard_char_entry = Gtk.Entry() self._single_wildcard_char_entry.set_max_length(1) self._single_wildcard_char_entry.set_text( self._settings_dict['singlewildcardchar']['user']) self._single_wildcard_char_entry.connect( 'notify::text', self._on_single_wildcard_char_entry) _options_details_grid_row += 1 self._options_details_grid.attach( self._single_wildcard_char_label, 0, _options_details_grid_row, 1, 1) self._options_details_grid.attach( self._single_wildcard_char_entry, 1, _options_details_grid_row, 1, 1) self._multi_wildcard_char_label = Gtk.Label() self._multi_wildcard_char_label.set_text( # Translators: This single character is a placeholder # to match a any number of characters _('Multi wildcard character:')) self._multi_wildcard_char_label.set_tooltip_text( # Translators: This is a tooltip for the label of the # entry where one can choose the wildcard to match any # number of candidates. _('The wildcard used to match any number of characters.\n' 'Type RETURN or ENTER to confirm after changing the wildcard.')) self._multi_wildcard_char_label.set_xalign(0) self._multi_wildcard_char_entry = Gtk.Entry() self._multi_wildcard_char_entry.set_max_length(1) self._multi_wildcard_char_entry.set_text( self._settings_dict['multiwildcardchar']['user']) self._multi_wildcard_char_entry.connect( 'notify::text', self._on_multi_wildcard_char_entry) _options_details_grid_row += 1 self._options_details_grid.attach( self._multi_wildcard_char_label, 0, _options_details_grid_row, 1, 1) self._options_details_grid.attach( self._multi_wildcard_char_entry, 1, _options_details_grid_row, 1, 1) self._use_dark_theme_checkbutton = Gtk.CheckButton( # Translators: A combobox to choose whether # the color scheme for a dark theme should be used. label=_('Use dark theme')) self._use_dark_theme_checkbutton.set_tooltip_text( # Translators: A tooltip for the label of the combobox to # choose whether the color scheme for a dark theme should # be used. _('If yes, the color scheme for a dark theme will be used.')) self._use_dark_theme_checkbutton.set_hexpand(False) self._use_dark_theme_checkbutton.set_vexpand(False) self._use_dark_theme_checkbutton.set_active( self._settings_dict['darktheme']['user']) self._use_dark_theme_checkbutton.connect( 'clicked', self._on_use_dark_theme_checkbutton) _options_details_grid_row += 1 self._options_details_grid.attach( self._use_dark_theme_checkbutton, 0, _options_details_grid_row, 2, 1) self._error_sound_checkbutton = Gtk.CheckButton( # Translators: A checkbox where one can choose whether a # sound is played on error label=_('Play sound file on error')) self._error_sound_checkbutton.set_tooltip_text( _('Here you can choose whether a sound file is played ' + 'if an error occurs. ' + 'If the simpleaudio module for Python3 is not installed, ' + 'this option does nothing.')) self._error_sound_checkbutton.set_hexpand(False) self._error_sound_checkbutton.set_vexpand(False) self._error_sound_checkbutton.set_active( self._settings_dict['errorsound']['user']) self._error_sound_checkbutton.connect( 'clicked', self._on_error_sound_checkbutton) self._error_sound_file_button = Gtk.Button() self._error_sound_file_button_box = Gtk.HBox() self._error_sound_file_button_label = Gtk.Label() self._error_sound_file_button_label.set_text( self._settings_dict['errorsoundfile']['user']) self._error_sound_file_button_label.set_use_markup(True) self._error_sound_file_button_label.set_max_width_chars( 40) self._error_sound_file_button_label.set_line_wrap(False) self._error_sound_file_button_label.set_ellipsize( Pango.EllipsizeMode.START) self._error_sound_file_button_box.pack_start( self._error_sound_file_button_label, False, False, 0) self._error_sound_file_button.add( self._error_sound_file_button_box) self._error_sound_file_button.connect( 'clicked', self._on_error_sound_file_button) _options_details_grid_row += 1 self._options_details_grid.attach( self._error_sound_checkbutton, 0, _options_details_grid_row, 1, 1) self._options_details_grid.attach( self._error_sound_file_button, 1, _options_details_grid_row, 1, 1) self._error_sound_object = it_sound.SoundObject( os.path.expanduser(self._settings_dict['errorsoundfile']['user']), audio_backend=self._settings_dict['soundbackend']['user']) self._debug_level_label = Gtk.Label() self._debug_level_label.set_text( # Translators: When the debug level is greater than 0, # debug information may be printed to the log file and # debug information may also be shown graphically. _('Debug level:')) self._debug_level_label.set_tooltip_text( # Translators: This is a tooltip for the label for the # adjustment of the debug level. _('When greater than 0, debug information may be ' 'printed to the log file and debug information ' 'may also be shown graphically.')) self._debug_level_label.set_xalign(0) self._debug_level_adjustment = Gtk.SpinButton() self._debug_level_adjustment.set_visible(True) self._debug_level_adjustment.set_can_focus(True) self._debug_level_adjustment.set_increments(1.0, 1.0) self._debug_level_adjustment.set_range(0.0, 255.0) self._debug_level_adjustment.set_value( self._settings_dict['debuglevel']['user']) self._debug_level_adjustment.connect( 'value-changed', self._on_debug_level_adjustment_value_changed) _options_details_grid_row += 1 self._options_details_grid.attach( self._debug_level_label, 0, _options_details_grid_row, 1, 1) self._options_details_grid.attach( self._debug_level_adjustment, 1, _options_details_grid_row, 1, 1) self.show_all() # pylint: disable=no-member self._notebook.set_current_page(0) # Has to be after show_all() self._gsettings.connect('changed', self._on_gsettings_value_changed) def _fill_settings_dict(self) -> None: '''Fill a dictionary with the default and user settings for all settings keys. The default settings start with the defaults from the gsettings schema. Some of these generic default values may be overridden by more specific default settings coming from the specific database of this table input method. After this possible modification from the database we have the final default settings for this specific table input method. The user settings start with a copy of these final default settings, then they are possibly modified by user gsettings. Keeping a copy of the default settings in the settings dictionary makes it easy to revert some or all settings to the defaults. ''' self._settings_dict = {} default_single_wildcard_char = it_util.variant_to_value( self._gsettings.get_default_value('singlewildcardchar')) if self.tabsqlitedb.ime_properties.get('single_wildcard_char'): default_single_wildcard_char = self.tabsqlitedb.ime_properties.get( 'single_wildcard_char') user_single_wildcard_char = it_util.variant_to_value( self._gsettings.get_user_value('singlewildcardchar')) if user_single_wildcard_char is None: user_single_wildcard_char = default_single_wildcard_char self._settings_dict['singlewildcardchar'] = { 'default': default_single_wildcard_char, 'user': user_single_wildcard_char, 'set_function': self.set_single_wildcard_char} default_multi_wildcard_char = it_util.variant_to_value( self._gsettings.get_default_value('multiwildcardchar')) if self.tabsqlitedb.ime_properties.get('multi_wildcard_char'): default_multi_wildcard_char = self.tabsqlitedb.ime_properties.get( 'multi_wildcard_char') user_multi_wildcard_char = it_util.variant_to_value( self._gsettings.get_user_value('multiwildcardchar')) if user_multi_wildcard_char is None: user_multi_wildcard_char = default_multi_wildcard_char self._settings_dict['multiwildcardchar'] = { 'default': default_multi_wildcard_char, 'user': user_multi_wildcard_char, 'set_function': self.set_multi_wildcard_char} default_keybindings = it_util.get_default_keybindings( self._gsettings, self.tabsqlitedb) # copy the updated default keybindings, i.e. the default # keybindings for this table, into the user keybindings: user_keybindings = copy.deepcopy(default_keybindings) user_keybindings_gsettings = it_util.variant_to_value( self._gsettings.get_user_value('keybindings')) if not user_keybindings_gsettings: user_keybindings_gsettings = {} it_util.dict_update_existing_keys( user_keybindings, user_keybindings_gsettings) self._settings_dict['keybindings'] = { 'default': default_keybindings, 'user': user_keybindings, 'set_function': self.set_keybindings} default_always_show_lookup = it_util.variant_to_value( self._gsettings.get_default_value('alwaysshowlookup')) if self.tabsqlitedb.ime_properties.get('always_show_lookup'): default_always_show_lookup = ( self.tabsqlitedb.ime_properties.get( 'always_show_lookup').lower() == 'true') user_always_show_lookup = it_util.variant_to_value( self._gsettings.get_user_value('alwaysshowlookup')) if user_always_show_lookup is None: user_always_show_lookup = default_always_show_lookup self._settings_dict['alwaysshowlookup'] = { 'default': default_always_show_lookup, 'user': user_always_show_lookup, 'set_function': self.set_always_show_lookup} default_page_size = it_util.variant_to_value( self._gsettings.get_default_value('lookuptablepagesize')) for index in range(1, 10): if not default_keybindings['commit_candidate_%s' % (index + 1)]: default_page_size = min(index, default_page_size) break user_page_size = it_util.variant_to_value( self._gsettings.get_user_value('lookuptablepagesize')) if user_page_size is None: user_page_size = default_page_size self._settings_dict['lookuptablepagesize'] = { 'default': int(default_page_size), 'user': int(user_page_size), 'set_function': self.set_page_size} default_lookup_table_orientation = it_util.variant_to_value( self._gsettings.get_default_value('lookuptableorientation')) default_lookup_table_orientation = self.tabsqlitedb.get_orientation() user_lookup_table_orientation = it_util.variant_to_value( self._gsettings.get_user_value('lookuptableorientation')) if user_lookup_table_orientation is None: user_lookup_table_orientation = default_lookup_table_orientation self._settings_dict['lookuptableorientation'] = { 'default': default_lookup_table_orientation, 'user': user_lookup_table_orientation, 'set_function': self.set_lookup_table_orientation} default_chinese_mode = it_util.variant_to_value( self._gsettings.get_default_value('chinesemode')) default_chinese_mode = it_util.get_default_chinese_mode( self.tabsqlitedb) user_chinese_mode = it_util.variant_to_value( self._gsettings.get_user_value('chinesemode')) if user_chinese_mode is None: user_chinese_mode = default_chinese_mode self._settings_dict['chinesemode'] = { 'default': default_chinese_mode, 'user': user_chinese_mode, 'set_function': self.set_chinese_mode} default_input_mode = it_util.variant_to_value( self._gsettings.get_default_value('inputmode')) user_input_mode = it_util.variant_to_value( self._gsettings.get_value('inputmode')) self._settings_dict['inputmode'] = { 'default': default_input_mode, 'user': user_input_mode, 'set_function': self.set_input_mode} default_remember_input_mode = it_util.variant_to_value( self._gsettings.get_default_value('rememberinputmode')) user_remember_input_mode = it_util.variant_to_value( self._gsettings.get_value('rememberinputmode')) self._settings_dict['rememberinputmode'] = { 'default': default_remember_input_mode, 'user': user_remember_input_mode, 'set_function': self.set_remember_input_mode} default_dark_theme = it_util.variant_to_value( self._gsettings.get_default_value('darktheme')) user_dark_theme = it_util.variant_to_value( self._gsettings.get_value('darktheme')) self._settings_dict['darktheme'] = { 'default': default_dark_theme, 'user': user_dark_theme, 'set_function': self.set_dark_theme} default_dynamic_adjust = it_util.variant_to_value( self._gsettings.get_default_value('dynamicadjust')) if self.tabsqlitedb.ime_properties.get('dynamic_adjust'): default_dynamic_adjust = ( self.tabsqlitedb.ime_properties.get( 'dynamic_adjust').lower() == 'true') user_dynamic_adjust = it_util.variant_to_value( self._gsettings.get_user_value('dynamicadjust')) if user_dynamic_adjust is None: user_dynamic_adjust = default_dynamic_adjust self._settings_dict['dynamicadjust'] = { 'default': default_dynamic_adjust, 'user': user_dynamic_adjust, 'set_function': self.set_dynamic_adjust} default_error_sound = it_util.variant_to_value( self._gsettings.get_default_value('errorsound')) user_error_sound = it_util.variant_to_value( self._gsettings.get_value('errorsound')) self._settings_dict['errorsound'] = { 'default': default_error_sound, 'user': user_error_sound, 'set_function': self.set_error_sound} default_error_sound_file = it_util.variant_to_value( self._gsettings.get_default_value('errorsoundfile')) user_error_sound_file = it_util.variant_to_value( self._gsettings.get_value('errorsoundfile')) self._settings_dict['errorsoundfile'] = { 'default': default_error_sound_file, 'user': user_error_sound_file, 'set_function': self.set_error_sound_file} default_sound_backend = it_util.variant_to_value( self._gsettings.get_default_value('soundbackend')) user_sound_backend = it_util.variant_to_value( self._gsettings.get_value('soundbackend')) self._settings_dict['soundbackend'] = { 'default': default_sound_backend, 'user': user_sound_backend, 'set_function': self.set_sound_backend} default_debug_level = it_util.variant_to_value( self._gsettings.get_default_value('debuglevel')) user_debug_level = it_util.variant_to_value( self._gsettings.get_value('debuglevel')) self._settings_dict['debuglevel'] = { 'default': default_debug_level, 'user': user_debug_level, 'set_function': self.set_debug_level} default_table_full_width_letter_mode = it_util.variant_to_value( self._gsettings.get_default_value('tabdeffullwidthletter')) if self.tabsqlitedb.ime_properties.get('def_full_width_letter'): default_table_full_width_letter_mode = ( self.tabsqlitedb.ime_properties.get( 'def_full_width_letter').lower() == 'true') user_table_full_width_letter_mode = it_util.variant_to_value( self._gsettings.get_user_value('tabdeffullwidthletter')) if user_table_full_width_letter_mode is None: user_table_full_width_letter_mode = ( default_table_full_width_letter_mode) self._settings_dict['tabdeffullwidthletter'] = { 'default': default_table_full_width_letter_mode, 'user': user_table_full_width_letter_mode, 'set_function': self.set_table_full_width_letter_mode} default_table_full_width_punct_mode = ( it_util.variant_to_value( self._gsettings.get_default_value('tabdeffullwidthpunct'))) if self.tabsqlitedb.ime_properties.get('def_full_width_punct'): default_table_full_width_punct_mode = ( self.tabsqlitedb.ime_properties.get( 'def_full_width_punct').lower() == 'true') user_table_full_width_punct_mode = it_util.variant_to_value( self._gsettings.get_user_value('tabdeffullwidthpunct')) if user_table_full_width_punct_mode is None: user_table_full_width_punct_mode = ( default_table_full_width_punct_mode) self._settings_dict['tabdeffullwidthpunct'] = { 'default': default_table_full_width_punct_mode, 'user': user_table_full_width_punct_mode, 'set_function': self.set_table_full_width_punct_mode} default_direct_full_width_letter_mode = it_util.variant_to_value( self._gsettings.get_default_value('endeffullwidthletter')) user_direct_full_width_letter_mode = it_util.variant_to_value( self._gsettings.get_value('endeffullwidthletter')) self._settings_dict['endeffullwidthletter'] = { 'default': default_direct_full_width_letter_mode, 'user': user_direct_full_width_letter_mode, 'set_function': self.set_direct_full_width_letter_mode} default_direct_full_width_punct_mode = it_util.variant_to_value( self._gsettings.get_default_value('endeffullwidthpunct')) user_direct_full_width_punct_mode = it_util.variant_to_value( self._gsettings.get_value('endeffullwidthpunct')) self._settings_dict['endeffullwidthpunct'] = { 'default': default_direct_full_width_punct_mode, 'user': user_direct_full_width_punct_mode, 'set_function': self.set_direct_full_width_punct_mode} default_onechar_mode = it_util.variant_to_value( self._gsettings.get_default_value('onechar')) user_onechar_mode = it_util.variant_to_value( self._gsettings.get_value('onechar')) self._settings_dict['onechar'] = { 'default': default_onechar_mode, 'user': user_onechar_mode, 'set_function': self.set_onechar_mode} default_autoselect_mode = it_util.variant_to_value( self._gsettings.get_default_value('autoselect')) if self.tabsqlitedb.ime_properties.get('auto_select'): default_autoselect_mode = ( self.tabsqlitedb.ime_properties.get( 'auto_select').lower() == 'true') user_autoselect_mode = it_util.variant_to_value( self._gsettings.get_user_value('autoselect')) if user_autoselect_mode is None: user_autoselect_mode = default_autoselect_mode self._settings_dict['autoselect'] = { 'default': default_autoselect_mode, 'user': user_autoselect_mode, 'set_function': self.set_autoselect_mode} default_autocommit_mode = it_util.variant_to_value( self._gsettings.get_default_value('autocommit')) if self.tabsqlitedb.ime_properties.get('auto_commit'): default_autocommit_mode = ( self.tabsqlitedb.ime_properties.get( 'auto_commit').lower() == 'true') user_autocommit_mode = it_util.variant_to_value( self._gsettings.get_user_value('autocommit')) if user_autocommit_mode is None: user_autocommit_mode = default_autocommit_mode self._settings_dict['autocommit'] = { 'default': default_autocommit_mode, 'user': user_autocommit_mode, 'set_function': self.set_autocommit_mode} default_commit_invalid_mode = it_util.variant_to_value( self._gsettings.get_default_value('commitinvalidmode')) user_commit_invalid_mode = it_util.variant_to_value( self._gsettings.get_value('commitinvalidmode')) self._settings_dict['commitinvalidmode'] = { 'default': default_commit_invalid_mode, 'user': user_commit_invalid_mode, 'set_function': self.set_commit_invalid_mode} default_autowildcard_mode = it_util.variant_to_value( self._gsettings.get_default_value('autowildcard')) if self.tabsqlitedb.ime_properties.get('auto_wildcard'): default_autowildcard_mode = ( self.tabsqlitedb.ime_properties.get( 'auto_wildcard').lower() == 'true') user_autowildcard_mode = it_util.variant_to_value( self._gsettings.get_user_value('autowildcard')) if user_autowildcard_mode is None: user_autowildcard_mode = default_autowildcard_mode self._settings_dict['autowildcard'] = { 'default': default_autowildcard_mode, 'user': user_autowildcard_mode, 'set_function': self.set_autowildcard_mode} @staticmethod def __run_message_dialog( message: str, message_type: Gtk.MessageType = Gtk.MessageType.INFO) -> None: '''Run a dialog to show an error or warning message''' dialog = Gtk.MessageDialog( flags=Gtk.DialogFlags.MODAL, message_type=message_type, buttons=Gtk.ButtonsType.OK, message_format=message) dialog.run() dialog.destroy() def _run_are_you_sure_dialog(self, message: str) -> Gtk.ResponseType: ''' Run a dialog to show a “Are you sure?” message. Returns Gtk.ResponseType.OK or Gtk.ResponseType.CANCEL (an enum) ''' confirm_question = Gtk.Dialog( title=_('Are you sure?'), parent=self) confirm_question.add_button(_('_Cancel'), Gtk.ResponseType.CANCEL) confirm_question.add_button(_('_OK'), Gtk.ResponseType.OK) box = confirm_question.get_content_area() label = Gtk.Label() label.set_text( '' + html.escape(message) + '') label.set_use_markup(True) label.set_max_width_chars(40) label.set_line_wrap(True) label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR) label.set_xalign(0) margin = 10 label.set_margin_start(margin) label.set_margin_end(margin) label.set_margin_top(margin) label.set_margin_bottom(margin) box.add(label) confirm_question.show_all() response = confirm_question.run() confirm_question.destroy() while Gtk.events_pending(): Gtk.main_iteration() return response def check_instance(self) -> bool: ''' Check whether another instance of the setup tool is running already ''' if (dbus.SessionBus().request_name("org.ibus.table") != dbus.bus.REQUEST_NAME_REPLY_PRIMARY_OWNER): self.__class__.__run_message_dialog( _("Another instance of this app is already running."), Gtk.MessageType.ERROR) sys.exit(1) else: return False @staticmethod def _on_delete_event(*_args: Any) -> None: ''' The window has been deleted, probably by the window manager. ''' Gtk.main_quit() @staticmethod def _on_destroy_event(*_args: Any) -> None: ''' The window has been destroyed. ''' Gtk.main_quit() @staticmethod def _on_close_clicked(_button: Gtk.Button) -> None: '''The button to close the dialog has been clicked.''' Gtk.main_quit() def _on_gsettings_value_changed( self, _settings: Gio.Settings, key: str) -> None: ''' Called when a value in the settings has been changed. :param settings: The settings object :type settings: Gio.Settings object :param key: The key of the setting which has changed :type key: String ''' value = it_util.variant_to_value(self._gsettings.get_value(key)) LOGGER.info('Settings changed: key=%s value=%s\n', key, value) if key in self._settings_dict: self._settings_dict[key]['set_function'](value, update_gsettings=False) return LOGGER.error('Unknown key\n') return @staticmethod def _on_about_button_clicked(_button: Gtk.Button) -> None: ''' The “About” button has been clicked :param _button: The “About” button ''' it_util.ItAboutDialog() def _on_restore_all_defaults_button_clicked( self, _button: Gtk.Button) -> None: ''' Restore all default settings ''' self._restore_all_defaults_button.set_sensitive(False) response = self._run_are_you_sure_dialog( # Translators: This is the text in the centre of a small # dialog window, trying to confirm whether the user is # really sure to restore all default settings. _('Do you really want to restore all default settings?')) if response == Gtk.ResponseType.OK: LOGGER.info('Restoring all defaults.') for key in self._settings_dict: self._settings_dict[key]['set_function']( self._settings_dict[key]['default'], update_gsettings=True) self._settings_dict[key]['set_function']( self._settings_dict[key]['default'], update_gsettings=False) else: LOGGER.info('Restore all defaults cancelled.') self._restore_all_defaults_button.set_sensitive(True) def _on_single_wildcard_char_entry( self, widget: Gtk.Entry, _property_spec: Any) -> None: ''' The character to be used as a single wildcard has been changed. ''' self.set_single_wildcard_char( widget.get_text(), update_gsettings=True) def _on_multi_wildcard_char_entry( self, widget: Gtk.Entry, _property_spec: Any) -> None: ''' The character to be used as a multi wildcard has been changed. ''' self.set_multi_wildcard_char( widget.get_text(), update_gsettings=True) def _on_page_size_adjustment_value_changed( self, _widget: Gtk.SpinButton) -> None: ''' The page size of the lookup table has been changed. ''' self.set_page_size( self._page_size_adjustment.get_value(), update_gsettings=True) def _on_lookup_table_orientation_combobox_changed( self, widget: Gtk.ComboBox) -> None: ''' A change of the lookup table orientation has been requested with the combobox ''' tree_iter = widget.get_active_iter() if tree_iter is not None: model = widget.get_model() orientation = model[tree_iter][1] self.set_lookup_table_orientation( orientation, update_gsettings=True) def _on_remember_input_mode_combobox_changed( self, widget: Gtk.ComboBox) -> None: ''' A change of the remember input mode has been requested with the combobox ''' tree_iter = widget.get_active_iter() if tree_iter is not None: model = widget.get_model() remember_input_mode = model[tree_iter][1] self.set_remember_input_mode( remember_input_mode, update_gsettings=True) def _on_chinese_mode_combobox_changed(self, widget: Gtk.ComboBox) -> None: ''' A change of the Chinese mode has been requested with the combobox ''' tree_iter = widget.get_active_iter() if tree_iter is not None: model = widget.get_model() chinese_mode = model[tree_iter][1] self.set_chinese_mode( chinese_mode, update_gsettings=True) def _on_onechar_mode_combobox_changed(self, widget: Gtk.ComboBox) -> None: ''' A change of the onechar mode has been requested with the combobox ''' tree_iter = widget.get_active_iter() if tree_iter is not None: model = widget.get_model() mode = model[tree_iter][1] self.set_onechar_mode( mode, update_gsettings=True) def _on_autoselect_mode_checkbutton(self, widget: Gtk.CheckButton) -> None: '''The checkbutton for autoselect mode has been clicked''' self.set_autoselect_mode(widget.get_active(), update_gsettings=True) def _on_autocommit_mode_combobox_changed( self, widget: Gtk.ComboBox) -> None: ''' A change of the autocommit mode has been requested with the combobox ''' tree_iter = widget.get_active_iter() if tree_iter is not None: model = widget.get_model() mode = model[tree_iter][1] self.set_autocommit_mode( mode, update_gsettings=True) def _on_commit_invalid_mode_combobox_changed(self, widget: Gtk.ComboBox) -> None: ''' A change of the commit invalid mode has been requested with the combobox ''' tree_iter = widget.get_active_iter() if tree_iter is not None: model = widget.get_model() commit_invalid_mode = model[tree_iter][1] self.set_commit_invalid_mode( commit_invalid_mode, update_gsettings=True) def _on_autowildcard_mode_checkbutton( self, widget: Gtk.CheckButton) -> None: '''The checkbutton for autocommit mode has been clicked''' self.set_autowildcard_mode(widget.get_active(), update_gsettings=True) def _on_table_full_width_letter_mode_combobox_changed( self, widget: Gtk.ComboBox) -> None: ''' A change of the letter width when in “Table input” mode has been requested with the combobox ''' tree_iter = widget.get_active_iter() if tree_iter is not None: model = widget.get_model() mode = model[tree_iter][1] self.set_table_full_width_letter_mode( mode, update_gsettings=True) def _on_table_full_width_punct_mode_combobox_changed( self, widget: Gtk.ComboBox) -> None: ''' A change of the letter width when in “Table input” mode has been requested with the combobox ''' tree_iter = widget.get_active_iter() if tree_iter is not None: model = widget.get_model() mode = model[tree_iter][1] self.set_table_full_width_punct_mode( mode, update_gsettings=True) def _on_direct_full_width_letter_mode_combobox_changed( self, widget: Gtk.ComboBox) -> None: ''' A change of the letter width when in “Direct input” mode has been requested with the combobox ''' tree_iter = widget.get_active_iter() if tree_iter is not None: model = widget.get_model() mode = model[tree_iter][1] self.set_direct_full_width_letter_mode( mode, update_gsettings=True) def _on_direct_full_width_punct_mode_combobox_changed( self, widget: Gtk.ComboBox) -> None: ''' A change of the letter width when in “Direct input” mode has been requested with the combobox ''' tree_iter = widget.get_active_iter() if tree_iter is not None: model = widget.get_model() mode = model[tree_iter][1] self.set_direct_full_width_punct_mode( mode, update_gsettings=True) def _on_always_show_lookup_checkbutton( self, widget: Gtk.CheckButton) -> None: '''The checkbutton for always show lookup has been clicked''' self.set_always_show_lookup(widget.get_active(), update_gsettings=True) def _on_use_dark_theme_checkbutton(self, widget: Gtk.CheckButton) -> None: '''The checkbutton for the dark theme has been clicked''' self.set_dark_theme(widget.get_active(), update_gsettings=True) def _on_dynamic_adjust_checkbutton(self, widget: Gtk.CheckButton) -> None: ''' The checkbutton whether to dynamically adjust the candidates :param widget: The check button clicked ''' self.set_dynamic_adjust(widget.get_active(), update_gsettings=True) def _on_dynamic_adjust_forget_button( self, _widget: Gtk.Button) -> None: ''' The button to select forget how often candidates were used ''' self._dynamic_adjust_forget_button.set_sensitive(False) response = self._run_are_you_sure_dialog( # Translators: This is the text in the centre of a small # dialog window, trying to confirm whether the user is # really sure to to delete all the data # ibus-table has learned from typing and selecting candidates. # Deleting this learned data cannot be reversed. So # the user should be really sure he really wants to do that. _('Do you really want to delete all ' + 'data learned from typing and selecting candidates?')) if response == Gtk.ResponseType.OK: self.tabsqlitedb.remove_all_phrases_from_user_db() self._dynamic_adjust_forget_button.set_sensitive(True) def _on_error_sound_checkbutton(self, widget: Gtk.CheckButton) -> None: ''' The checkbutton whether to play a sound file on error. :param widget: The check button clicked ''' self.set_error_sound(widget.get_active(), update_gsettings=True) def _on_error_sound_file_button( self, _widget: Gtk.Button) -> None: ''' The button to select the .wav sound file to be played on error. ''' self._error_sound_file_button.set_sensitive(False) filename = '' chooser = Gtk.FileChooserDialog( title=_('Select .wav sound file:'), parent=self, action=Gtk.FileChooserAction.OPEN) chooser.add_button(_('_Cancel'), Gtk.ResponseType.CANCEL) chooser.add_button(_('_OK'), Gtk.ResponseType.OK) chooser.set_current_folder(os.path.dirname( self._settings_dict['errorsoundfile']['user'])) response = chooser.run() if response == Gtk.ResponseType.OK: filename = chooser.get_filename() chooser.destroy() while Gtk.events_pending(): Gtk.main_iteration() if filename: self._error_sound_file_button_label.set_text( filename) self.set_error_sound_file( filename, update_gsettings=True) self._error_sound_file_button.set_sensitive(True) def _on_debug_level_adjustment_value_changed( self, _widget: Gtk.SpinButton) -> None: '''The value for the debug level has been changed.''' self.set_debug_level( self._debug_level_adjustment.get_value(), update_gsettings=True) def _on_keybindings_treeview_row_activated( self, _treeview: Gtk.TreeView, treepath: Gtk.TreePath, _treeviewcolumn: Gtk.TreeViewColumn) -> None: ''' A row in the treeview listing the key bindings has been activated. :param treeview: The treeview listing the key bindings :param treepath: The path to the activated row :param treeviewcolumn: A column in the treeview listing the key bindings ''' model = self._keybindings_treeview_model iterator = model.get_iter(treepath) command = model[iterator][0] if command != self._keybindings_selected_command: # This should not happen, if a row is activated it should # already be selected, # i.e. on_keybindings_treeview_row_selected() should have # been called already and this should have set # self._keybindings_selected_command LOGGER.error( 'Unexpected error, command = "%s" ' % command + 'self._keybindings_selected_command = "%s"\n' % self._keybindings_selected_command) return self._create_and_show_keybindings_edit_popover() def _on_keybindings_treeview_row_selected( self, selection: Gtk.TreeSelection) -> None: ''' A row in the treeview listing the key bindings has been selected. ''' (model, iterator) = selection.get_selected() if iterator: self._keybindings_selected_command = model[iterator][0] self._keybindings_default_button.set_sensitive(True) self._keybindings_edit_button.set_sensitive(True) else: # all rows have been unselected self._keybindings_selected_command = '' self._keybindings_default_button.set_sensitive(False) self._keybindings_edit_button.set_sensitive(False) def _on_keybindings_edit_listbox_row_selected( self, _listbox: Gtk.ListBox, listbox_row: Gtk.ListBoxRow) -> None: ''' Signal handler for selecting one of the key bindings for a certain command :param _listbox: The list box used to select a key binding :type _listbox: Gtk.ListBox object :param listbox_row: A row containing a key binding :type listbox_row: Gtk.ListBoxRow object ''' if listbox_row: keybinding = listbox_row.get_child().get_text() index = listbox_row.get_index() user_keybindings = self._settings_dict['keybindings']['user'] command = self._keybindings_selected_command if (keybinding and command and keybinding in user_keybindings[command]): self._keybindings_edit_popover_selected_keybinding = keybinding self._keybindings_edit_popover_selected_keybinding_index = ( index) if self._keybindings_edit_popover_remove_button: self._keybindings_edit_popover_remove_button.set_sensitive( True) if self._keybindings_edit_popover_up_button: self._keybindings_edit_popover_up_button.set_sensitive( index > 0) if self._keybindings_edit_popover_down_button: self._keybindings_edit_popover_down_button.set_sensitive( index < len(user_keybindings[command]) - 1) return # all rows have been unselected self._keybindings_edit_popover_selected_keybinding = '' self._keybindings_edit_popover_selected_keybinding_index = -1 if self._keybindings_edit_popover_remove_button: self._keybindings_edit_popover_remove_button.set_sensitive(False) if self._keybindings_edit_popover_up_button: self._keybindings_edit_popover_up_button.set_sensitive(False) if self._keybindings_edit_popover_down_button: self._keybindings_edit_popover_down_button.set_sensitive(False) def _on_keybindings_edit_popover_add_button_clicked( self, _button: Gtk.Button) -> None: ''' Signal handler called when the “Add” button to add a key binding has been clicked. ''' key_input_dialog = it_util.ItKeyInputDialog(parent=self) response = key_input_dialog.run() key_input_dialog.destroy() if response == Gtk.ResponseType.OK: keyval, state = key_input_dialog.e key = it_util.KeyEvent(keyval, 0, state) keybinding = it_util.keyevent_to_keybinding(key) command = self._keybindings_selected_command user_keybindings = self._settings_dict['keybindings']['user'] if keybinding not in user_keybindings[command]: user_keybindings[command].append(keybinding) self._fill_keybindings_edit_popover_listbox() self.set_keybindings(user_keybindings) def _on_keybindings_edit_popover_remove_button_clicked( self, _button: Gtk.Button) -> None: ''' Signal handler called when the “Remove” button to remove a key binding has been clicked. ''' keybinding = self._keybindings_edit_popover_selected_keybinding command = self._keybindings_selected_command user_keybindings = self._settings_dict['keybindings']['user'] if (keybinding and command and keybinding in user_keybindings[command]): user_keybindings[command].remove(keybinding) self._fill_keybindings_edit_popover_listbox() self.set_keybindings(user_keybindings) def _on_keybindings_edit_popover_up_button_clicked( self, _button: Gtk.Button) -> None: ''' Signal handler called when the “up” button to move a key binding up has been clicked. ''' index = self._keybindings_edit_popover_selected_keybinding_index command = self._keybindings_selected_command keybinding = self._keybindings_edit_popover_selected_keybinding user_keybindings = self._settings_dict['keybindings']['user'] if not 0 < index < len(user_keybindings[command]): # This should not happen, one should not be able # to click the up button in this case, just return return user_keybindings[command] = ( user_keybindings[command][:index - 1] + [user_keybindings[command][index]] + [user_keybindings[command][index - 1]] + user_keybindings[command][index + 1:]) self.set_keybindings(user_keybindings, update_gsettings=True) self._fill_keybindings_edit_popover_listbox() self._keybindings_edit_popover_selected_keybinding_index = index - 1 self._keybindings_edit_popover_selected_keybinding = keybinding if self._keybindings_edit_popover_listbox: self._keybindings_edit_popover_listbox.select_row( self._keybindings_edit_popover_listbox.get_row_at_index( index - 1)) def _on_keybindings_edit_popover_down_button_clicked( self, _button: Gtk.Button) -> None: ''' Signal handler called when the “down” button to move a key binding down has been clicked. ''' index = self._keybindings_edit_popover_selected_keybinding_index command = self._keybindings_selected_command keybinding = self._keybindings_edit_popover_selected_keybinding user_keybindings = self._settings_dict['keybindings']['user'] if not 0 <= index < len(user_keybindings[command]) - 1: # This should not happen, one should not be able # to click the up button in this case, just return return user_keybindings[command] = ( user_keybindings[command][:index] + [user_keybindings[command][index + 1]] + [user_keybindings[command][index]] + user_keybindings[command][index + 2:]) self.set_keybindings(user_keybindings, update_gsettings=True) self._fill_keybindings_edit_popover_listbox() self._keybindings_edit_popover_selected_keybinding_index = index + 1 self._keybindings_edit_popover_selected_keybinding = keybinding if self._keybindings_edit_popover_listbox: self._keybindings_edit_popover_listbox.select_row( self._keybindings_edit_popover_listbox.get_row_at_index( index + 1)) def _on_keybindings_edit_popover_default_button_clicked( self, _button: Gtk.Button) -> None: ''' Signal handler called when the “Default” button to set the keybindings to the default has been clicked. ''' default_keybindings = self._settings_dict['keybindings']['default'] user_keybindings = self._settings_dict['keybindings']['user'] command = self._keybindings_selected_command if command and command in default_keybindings: user_keybindings[command] = default_keybindings[command].copy() self._fill_keybindings_edit_popover_listbox() self.set_keybindings(user_keybindings) def _fill_keybindings_edit_popover_listbox(self) -> None: ''' Fill the edit listbox to with the key bindings of the currently selected command ''' if self._keybindings_edit_popover_scroll is None: LOGGER.debug('self._keybindings_edit_popover_scroll is None') return for child in self._keybindings_edit_popover_scroll.get_children(): self._keybindings_edit_popover_scroll.remove(child) self._keybindings_edit_popover_listbox = Gtk.ListBox() self._keybindings_edit_popover_scroll.add( self._keybindings_edit_popover_listbox) self._keybindings_edit_popover_selected_keybinding = '' self._keybindings_edit_popover_selected_keybinding_index = -1 self._keybindings_edit_popover_listbox.set_visible(True) self._keybindings_edit_popover_listbox.set_vexpand(True) self._keybindings_edit_popover_listbox.set_selection_mode( Gtk.SelectionMode.SINGLE) self._keybindings_edit_popover_listbox.set_activate_on_single_click( True) self._keybindings_edit_popover_listbox.connect( 'row-selected', self._on_keybindings_edit_listbox_row_selected) user_keybindings = self._settings_dict['keybindings']['user'] for keybinding in user_keybindings[self._keybindings_selected_command]: label = Gtk.Label() label.set_text(html.escape(keybinding)) label.set_use_markup(True) label.set_xalign(0) margin = 1 label.set_margin_start(margin) label.set_margin_end(margin) label.set_margin_top(margin) label.set_margin_bottom(margin) self._keybindings_edit_popover_listbox.insert(label, -1) self._keybindings_edit_popover_remove_button.set_sensitive(False) self._keybindings_edit_popover_up_button.set_sensitive(False) self._keybindings_edit_popover_down_button.set_sensitive(False) self._keybindings_edit_popover_listbox.show_all() def _create_and_show_keybindings_edit_popover(self) -> None: ''' Create and show the popover to edit the key bindings for a command ''' self._keybindings_edit_popover = Gtk.Popover() if self._keybindings_edit_popover is None: LOGGER.debug('self._keybindings_edit_popover is None') return self._keybindings_edit_popover.set_relative_to( self._keybindings_edit_button) self._keybindings_edit_popover.set_position(Gtk.PositionType.RIGHT) self._keybindings_edit_popover.set_vexpand(True) self._keybindings_edit_popover.set_hexpand(True) keybindings_edit_popover_vbox = Gtk.Box() keybindings_edit_popover_vbox.set_orientation( Gtk.Orientation.VERTICAL) margin = 12 keybindings_edit_popover_vbox.set_margin_start(margin) keybindings_edit_popover_vbox.set_margin_end(margin) keybindings_edit_popover_vbox.set_margin_top(margin) keybindings_edit_popover_vbox.set_margin_bottom(margin) keybindings_edit_popover_vbox.set_spacing(margin) keybindings_edit_popover_label = Gtk.Label() keybindings_edit_popover_label.set_text( _('Edit key bindings for command “%s”') %self._keybindings_selected_command) keybindings_edit_popover_label.set_use_markup(True) keybindings_edit_popover_label.set_visible(True) keybindings_edit_popover_label.set_halign(Gtk.Align.FILL) keybindings_edit_popover_vbox.pack_start( keybindings_edit_popover_label, False, False, 0) self._keybindings_edit_popover_scroll = Gtk.ScrolledWindow() self._keybindings_edit_popover_scroll.set_hexpand(True) self._keybindings_edit_popover_scroll.set_vexpand(True) self._keybindings_edit_popover_scroll.set_kinetic_scrolling(False) self._keybindings_edit_popover_scroll.set_overlay_scrolling(True) keybindings_edit_popover_vbox.pack_start( self._keybindings_edit_popover_scroll, True, True, 0) keybindings_edit_popover_button_box = Gtk.Box() keybindings_edit_popover_button_box.set_orientation( Gtk.Orientation.HORIZONTAL) keybindings_edit_popover_button_box.set_can_focus(False) keybindings_edit_popover_vbox.add( keybindings_edit_popover_button_box) self._keybindings_edit_popover_add_button = Gtk.Button() keybindings_edit_popover_add_button_label = Gtk.Label() keybindings_edit_popover_add_button_label.set_text( '+') keybindings_edit_popover_add_button_label.set_use_markup(True) self._keybindings_edit_popover_add_button.add( keybindings_edit_popover_add_button_label) self._keybindings_edit_popover_add_button.set_tooltip_text( # Translators: This is a tooltip for the button to add a # key binding. _('Add a key binding')) self._keybindings_edit_popover_add_button.connect( 'clicked', self._on_keybindings_edit_popover_add_button_clicked) self._keybindings_edit_popover_add_button.set_sensitive(True) self._keybindings_edit_popover_remove_button = Gtk.Button() keybindings_edit_popover_remove_button_label = Gtk.Label() keybindings_edit_popover_remove_button_label.set_text( '-') keybindings_edit_popover_remove_button_label.set_use_markup(True) self._keybindings_edit_popover_remove_button.add( keybindings_edit_popover_remove_button_label) self._keybindings_edit_popover_remove_button.set_tooltip_text( # Translators: This is a tooltip for the button to remove # the selected key binding. _('Remove selected key binding')) self._keybindings_edit_popover_remove_button.connect( 'clicked', self._on_keybindings_edit_popover_remove_button_clicked) self._keybindings_edit_popover_remove_button.set_sensitive(False) self._keybindings_edit_popover_default_button = Gtk.Button() self._keybindings_edit_popover_up_button = Gtk.Button() keybindings_edit_popover_up_button_label = Gtk.Label() keybindings_edit_popover_up_button_label.set_text( '') keybindings_edit_popover_up_button_label.set_use_markup(True) self._keybindings_edit_popover_up_button.add( keybindings_edit_popover_up_button_label) self._keybindings_edit_popover_up_button.set_tooltip_text( # Translators: This is a tooltip for the button to move # the selected key binding up (higher in priority). _('Move key binding up')) self._keybindings_edit_popover_up_button.connect( 'clicked', self._on_keybindings_edit_popover_up_button_clicked) self._keybindings_edit_popover_down_button = Gtk.Button() keybindings_edit_popover_down_button_label = Gtk.Label() keybindings_edit_popover_down_button_label.set_text( '') keybindings_edit_popover_down_button_label.set_use_markup(True) self._keybindings_edit_popover_down_button.add( keybindings_edit_popover_down_button_label) self._keybindings_edit_popover_down_button.set_tooltip_text( # Translators: This is a tooltip for the button to move # the selected key binding down (lower in priority). _('Move key binding down')) self._keybindings_edit_popover_down_button.connect( 'clicked', self._on_keybindings_edit_popover_down_button_clicked) keybindings_edit_popover_default_button_label = Gtk.Label() keybindings_edit_popover_default_button_label.set_text( _('Set to default')) keybindings_edit_popover_default_button_label.set_use_markup(True) self._keybindings_edit_popover_default_button.add( keybindings_edit_popover_default_button_label) self._keybindings_edit_popover_default_button.set_tooltip_text( # Translators: This is a tooltip for the button to set # the key bindings for the selected command to the default. _('Set default key bindings for the selected command')) self._keybindings_edit_popover_default_button.connect( 'clicked', self._on_keybindings_edit_popover_default_button_clicked) self._keybindings_edit_popover_default_button.set_sensitive(True) keybindings_edit_popover_button_box.add( self._keybindings_edit_popover_add_button) keybindings_edit_popover_button_box.add( self._keybindings_edit_popover_remove_button) keybindings_edit_popover_button_box.add( self._keybindings_edit_popover_up_button) keybindings_edit_popover_button_box.add( self._keybindings_edit_popover_down_button) keybindings_edit_popover_button_box.add( self._keybindings_edit_popover_default_button) self._keybindings_edit_popover.add(keybindings_edit_popover_vbox) self._fill_keybindings_edit_popover_listbox() if GTK_VERSION >= (3, 22, 0): self._keybindings_edit_popover.popup() self._keybindings_edit_popover.show_all() def _on_keybindings_edit_button_clicked( self, _button: Gtk.Button) -> None: ''' Signal handler called when the “edit” button to edit the key bindings for a command has been clicked. ''' self._create_and_show_keybindings_edit_popover() def _on_keybindings_default_button_clicked( self, _button: Gtk.Button) -> None: ''' Signal handler called when the “Set to default” button to reset the key bindings for a command to the default has been clicked. ''' default_keybindings = self._settings_dict['keybindings']['default'] user_keybindings = self._settings_dict['keybindings']['user'] command = self._keybindings_selected_command if command and command in default_keybindings: user_keybindings[command] = default_keybindings[command].copy() self.set_keybindings(user_keybindings) def _on_keybindings_all_default_button_clicked( self, _button: Gtk.Button) -> None: ''' Signal handler called when the “Set all to default” button to reset the all key bindings top their defaults has been clicked. ''' self._keybindings_all_default_button.set_sensitive(False) response = self._run_are_you_sure_dialog( # Translators: This is the text in the centre of a small # dialog window, trying to confirm whether the user is # really sure to reset the key bindings for *all* commands # to their defaults. This cannot be reversed so the user # should be really sure he wants to do that. _('Do you really want to set the key bindings for ' + 'all commands to their defaults?')) if response == Gtk.ResponseType.OK: self.set_keybindings(self._settings_dict['keybindings']['default']) self._keybindings_all_default_button.set_sensitive(True) def set_single_wildcard_char(self, single_wildcard_char: str, update_gsettings: bool = True) -> None: '''Sets the single wildchard character. :param single_wildcard_char: The character to use as a single wildcard :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', single_wildcard_char, update_gsettings) self._settings_dict['singlewildcardchar']['user'] = ( single_wildcard_char) if update_gsettings: self._gsettings.set_value( 'singlewildcardchar', GLib.Variant.new_string(single_wildcard_char)) else: self._single_wildcard_char_entry.set_text(single_wildcard_char) def set_multi_wildcard_char(self, multi_wildcard_char: str, update_gsettings: bool = True) -> None: '''Sets the single wildchard character. :param multi_wildcard_char: The character to use as a single wildcard :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', multi_wildcard_char, update_gsettings) self._settings_dict['multiwildcardchar']['user'] = multi_wildcard_char if update_gsettings: self._gsettings.set_value( 'multiwildcardchar', GLib.Variant.new_string(multi_wildcard_char)) else: self._multi_wildcard_char_entry.set_text(multi_wildcard_char) def set_page_size(self, page_size: int, update_gsettings: bool = True) -> None: '''Sets the page size of the lookup table :param page_size: The page size of the lookup table (1 <= page size <= 10) :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', page_size, update_gsettings) page_size = int(page_size) if 1 <= page_size <= 10: self._settings_dict['lookuptablepagesize']['user'] = page_size if update_gsettings: self._gsettings.set_value( 'lookuptablepagesize', GLib.Variant.new_int32(page_size)) else: self._page_size_adjustment.set_value(page_size) def set_lookup_table_orientation(self, orientation: int, update_gsettings: bool = True) -> None: '''Sets the page size of the lookup table :param orientation: The orientation of the lookup table (0 < =orientation <= 2) :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', orientation, update_gsettings) orientation = int(orientation) if 0 <= orientation <= 2: self._settings_dict['lookuptableorientation']['user'] = orientation if update_gsettings: self._gsettings.set_value( 'lookuptableorientation', GLib.Variant.new_int32(orientation)) else: for index, item in enumerate( self._lookup_table_orientation_store): if orientation == item[1]: self._lookup_table_orientation_combobox.set_active( index) def set_input_mode(self, input_mode: int = 1, update_gsettings: bool = True) -> None: '''Sets whether direct input or the current table is used. :param input_mode: Whether to use direct input. 0: Use direct input. 1: Use the current table. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', input_mode, update_gsettings) input_mode = int(input_mode) if 0 <= input_mode <= 1: self._settings_dict['inputmode']['user'] = input_mode if update_gsettings: self._gsettings.set_value( 'inputmode', GLib.Variant.new_int32(input_mode)) def set_remember_input_mode(self, remember_input_mode: bool = True, update_gsettings: bool = True) -> None: '''Sets whether the input mode (direct or table) is remembered :param remember_input_mode: Whether to remember the input mode. False: Do not remember True: Remember. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', remember_input_mode, update_gsettings) remember_input_mode = bool(remember_input_mode) self._settings_dict['rememberinputmode']['user'] = remember_input_mode if update_gsettings: self._gsettings.set_value( 'rememberinputmode', GLib.Variant.new_boolean(remember_input_mode)) else: for index, item in enumerate(self._remember_input_mode_store): if remember_input_mode == item[1]: self._remember_input_mode_combobox.set_active(index) def set_chinese_mode(self, chinese_mode: int = 0, update_gsettings: bool = True) -> None: '''Sets the candidate filter mode used for Chinese 0 means to show simplified Chinese only 1 means to show traditional Chinese only 2 means to show all characters but show simplified Chinese first 3 means to show all characters but show traditional Chinese first 4 means to show all characters :param chinese_mode: The Chinese filter mode (0 <= mode <= 4) :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', chinese_mode, update_gsettings) chinese_mode = int(chinese_mode) if 0 <= chinese_mode <= 4: self._settings_dict['chinesemode']['user'] = chinese_mode if update_gsettings: self._gsettings.set_value( 'chinesemode', GLib.Variant.new_int32(chinese_mode)) else: for index, item in enumerate(self._chinese_mode_store): if chinese_mode == item[1]: self._chinese_mode_combobox.set_active(index) def set_onechar_mode(self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets whether only single characters should be matched in the database. :param mode: Whether only single characters should be matched. True: Match only single characters. False: Possibly match multiple characters at once. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', mode, update_gsettings) mode = bool(mode) self._settings_dict['onechar']['user'] = mode if update_gsettings: self._gsettings.set_value( 'onechar', GLib.Variant.new_boolean(mode)) else: for index, item in enumerate(self._onechar_mode_store): if mode == item[1]: self._onechar_mode_combobox.set_active(index) def set_autoselect_mode(self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets whether the first candidate will be selected automatically during typing. :param mode: Whether to select the first candidate automatically. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', mode, update_gsettings) mode = bool(mode) self._settings_dict['autoselect']['user'] = mode if update_gsettings: self._gsettings.set_value( 'autoselect', GLib.Variant.new_boolean(mode)) else: self._autoselect_mode_checkbutton.set_active(mode) def set_autocommit_mode(self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets whether automatic commits go into the preëdit or into the application. :param mode: Whether automatic commits go into the preëdit or into the application. True: Into the application. False: Into the preedit. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', mode, update_gsettings) mode = bool(mode) self._settings_dict['autocommit']['user'] = mode if update_gsettings: self._gsettings.set_value( 'autocommit', GLib.Variant.new_boolean(mode)) else: for index, item in enumerate(self._autocommit_mode_store): if mode == item[1]: self._autocommit_mode_combobox.set_active(index) def set_commit_invalid_mode(self, mode: int = 0, update_gsettings: bool = True) -> None: '''Sets the commit invalid mode This selects what is committed when a character which is not in the set of valid input characters for the current table is typed. 0 means to commit the current candidate 1 means to commit the raw characters typed so far :param mode: The mode (0 <= mode <= 1) :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', mode, update_gsettings) mode = int(mode) if 0 <= mode <= 1: self._settings_dict['commitinvalidmode']['user'] = mode if update_gsettings: self._gsettings.set_value( 'commitinvalidmode', GLib.Variant.new_int32(mode)) else: for index, item in enumerate(self._commit_invalid_mode_store): if mode == item[1]: self._commit_invalid_mode_combobox.set_active(index) def set_autowildcard_mode(self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets whether a wildcard should be automatically appended to the input. :param mode: Whether to append a wildcard automatically. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', mode, update_gsettings) mode = bool(mode) self._settings_dict['autowildcard']['user'] = mode if update_gsettings: self._gsettings.set_value( 'autowildcard', GLib.Variant.new_boolean(mode)) else: self._autowildcard_mode_checkbutton.set_active(mode) def set_table_full_width_letter_mode( self, mode: bool =False, update_gsettings: bool = True) -> None: '''Sets whether full width letters should be used while in “Table input” mode :param mode: Whether to use full width letters :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', mode, update_gsettings) mode = bool(mode) self._settings_dict['tabdeffullwidthletter']['user'] = mode if update_gsettings: self._gsettings.set_value( 'tabdeffullwidthletter', GLib.Variant.new_boolean(mode)) else: for index, item in enumerate( self._table_full_width_letter_mode_store): if mode == item[1]: self._table_full_width_letter_mode_combobox.set_active( index) def set_table_full_width_punct_mode( self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets whether full width punctuation should be used while in “Table input” mode :param mode: Whether to use full width punctuation :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', mode, update_gsettings) mode = bool(mode) self._settings_dict['tabdeffullwidthpunct']['user'] = mode if update_gsettings: self._gsettings.set_value( 'tabdeffullwidthpunct', GLib.Variant.new_boolean(mode)) else: for index, item in enumerate( self._table_full_width_punct_mode_store): if mode == item[1]: self._table_full_width_punct_mode_combobox.set_active( index) def set_direct_full_width_letter_mode( self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets whether full width letters should be used while in “Direct input” mode :param mode: Whether to use full width letters :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', mode, update_gsettings) mode = bool(mode) self._settings_dict['endeffullwidthletter']['user'] = mode if update_gsettings: self._gsettings.set_value( 'endeffullwidthletter', GLib.Variant.new_boolean(mode)) else: for index, item in enumerate( self._direct_full_width_letter_mode_store): if mode == item[1]: self._direct_full_width_letter_mode_combobox.set_active( index) def set_direct_full_width_punct_mode( self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets whether full width punctuation should be used while in “Direct input” mode :param mode: Whether to use full width punctuation :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', mode, update_gsettings) mode = bool(mode) self._settings_dict['endeffullwidthpunct']['user'] = mode if update_gsettings: self._gsettings.set_value( 'endeffullwidthpunct', GLib.Variant.new_boolean(mode)) else: for index, item in enumerate( self._direct_full_width_punct_mode_store): if mode == item[1]: self._direct_full_width_punct_mode_combobox.set_active( index) def set_always_show_lookup( self, mode: bool = False, update_gsettings: bool = True) -> None: '''Sets the whether the lookup table is shown. :param mode: Whether to show the lookup table :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', mode, update_gsettings) self._settings_dict['alwaysshowlookup']['user'] = mode if update_gsettings: self._gsettings.set_value( 'alwaysshowlookup', GLib.Variant.new_boolean(mode)) else: self._always_show_lookup_checkbutton.set_active(mode) def set_dark_theme( self, use_dark_theme: bool = False, update_gsettings: bool = True) -> None: '''Sets the whether to use the color scheme for dark theme. :param use_dark_theme: Whether to use the color scheme for dark theme :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', use_dark_theme, update_gsettings) self._settings_dict['darktheme']['user'] = use_dark_theme if update_gsettings: self._gsettings.set_value( 'darktheme', GLib.Variant.new_boolean(use_dark_theme)) else: self._use_dark_theme_checkbutton.set_active(use_dark_theme) def set_dynamic_adjust( self, dynamic_adjust: bool, update_gsettings: bool = True) -> None: '''Sets the whether dynamically adjust the candidates according to how often they are used. :param dynamic_adjust: Whether to dynamically adjust the candidates :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', dynamic_adjust, update_gsettings) self._settings_dict['dynamicadjust']['user'] = dynamic_adjust if update_gsettings: self._gsettings.set_value( 'dynamicadjust', GLib.Variant.new_boolean(dynamic_adjust)) else: self._dynamic_adjust_checkbutton.set_active(dynamic_adjust) def set_error_sound( self, error_sound: bool, update_gsettings: bool = True) -> None: '''Sets the whether to play a sound on error. :param error_sound: Whether to play a sound on error :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', error_sound, update_gsettings) self._settings_dict['errorsound']['user'] = error_sound if update_gsettings: self._gsettings.set_value( 'errorsound', GLib.Variant.new_boolean(error_sound)) else: self._error_sound_checkbutton.set_active(error_sound) def set_error_sound_file( self, path: Union[str, Any], update_gsettings: bool = True) -> None: '''Sets the path of file containing the sound to play on error. :param path: Full path of the .wav file containing the error sound. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', path, update_gsettings) if not isinstance(path, str): return self._settings_dict['errorsoundfile']['user'] = path if update_gsettings: self._gsettings.set_value( 'errorsoundfile', GLib.Variant.new_string(path)) else: self._error_sound_file_button_label.set_text(path) self._error_sound_object = it_sound.SoundObject( os.path.expanduser(self._settings_dict['errorsoundfile']['user']), audio_backend=self._settings_dict['soundbackend']['user']) if self._error_sound_object: try: self._error_sound_object.play() except Exception as error: # pylint: disable=broad-except LOGGER.exception('Playing error sound failed: %s: %s', error.__class__.__name__, error) def set_sound_backend( self, sound_backend: Union[str, Any], update_gsettings: bool = True) -> None: '''Sets the sound backend to use :param sound_backend: The name of sound backend to use :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the dconf key changed to avoid endless loops when the dconf key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', sound_backend, update_gsettings) if not isinstance(sound_backend, str): return if sound_backend == self._settings_dict['soundbackend']['user']: return self._settings_dict['soundbackend']['user'] = sound_backend if update_gsettings: self._gsettings.set_value( 'soundbackend', GLib.Variant.new_string(sound_backend)) self._error_sound_object = it_sound.SoundObject( os.path.expanduser(self._settings_dict['errorsoundfile']['user']), audio_backend=self._settings_dict['soundbackend']['user']) def set_debug_level(self, debug_level: int, update_gsettings: bool = True) -> None: '''Sets the debug level :param debug level: The debug level (0 <= level <= 255) :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', debug_level, update_gsettings) debug_level = int(debug_level) if 0 <= debug_level <= 255: self._settings_dict['debuglevel']['user'] = debug_level if update_gsettings: self._gsettings.set_value( 'debuglevel', GLib.Variant.new_int32(debug_level)) else: self._debug_level_adjustment.set_value(debug_level) def set_keybindings( self, keybindings: Union[Dict[str, List[str]], Any], update_gsettings: bool = True) -> None: '''Set current key bindings :param keybindings: The key bindings to use Commands which do not already exist in the current key bindings dictionary will be ignored. :param update_gsettings: Whether to write the change to Gsettings. Set this to False if this method is called because the Gsettings key changed to avoid endless loops when the Gsettings key is changed twice in a short time. ''' LOGGER.info( '(%s, update_gsettings = %s)', keybindings, update_gsettings) if not isinstance(keybindings, dict): return keybindings = copy.deepcopy(keybindings) user_keybindings = self._settings_dict['keybindings']['user'] # Update the default settings with the possibly changed settings: it_util.dict_update_existing_keys(user_keybindings, keybindings) # update the tree model model = self._keybindings_treeview_model iterator = model.get_iter_first() while iterator: for command in user_keybindings: if model.get_value(iterator, 0) == command: model.set_value(iterator, 1, repr(user_keybindings[command])) iterator = model.iter_next(iterator) if update_gsettings: variant_dict = GLib.VariantDict(GLib.Variant('a{sv}', {})) for command in sorted(user_keybindings): variant_array = GLib.Variant.new_array( GLib.VariantType('s'), [GLib.Variant.new_string(x) for x in user_keybindings[command]]) variant_dict.insert_value(command, variant_array) self._gsettings.set_value( 'keybindings', variant_dict.end()) class HelpWindow(Gtk.Window): # type: ignore ''' A window to show help :param parent: The parent object :param title: Title of the help window :param contents: Contents of the help window ''' def __init__(self, parent: Gtk.Window = None, title: str = '', contents: str = '') -> None: Gtk.Window.__init__(self, title=title) if parent: self.set_parent(parent) self.set_transient_for(parent) # to receive mouse events for scrolling and for the close # button self.set_modal(True) self.set_destroy_with_parent(False) self.set_default_size(600, 500) self.vbox = Gtk.Box() self.vbox.set_orientation(Gtk.Orientation.VERTICAL) self.vbox.set_spacing(0) self.add(self.vbox) self.text_buffer = Gtk.TextBuffer() self.text_buffer.insert_at_cursor(contents) self.text_view = Gtk.TextView() self.text_view.set_buffer(self.text_buffer) self.text_view.set_editable(False) self.text_view.set_cursor_visible(False) self.text_view.set_justification(Gtk.Justification.LEFT) self.text_view.set_wrap_mode(Gtk.WrapMode.WORD) self.scrolledwindow = Gtk.ScrolledWindow() self.scrolledwindow.set_hexpand(True) self.scrolledwindow.set_vexpand(True) self.scrolledwindow.add(self.text_view) self.vbox.pack_start(self.scrolledwindow, True, True, 0) self.close_button = Gtk.Button() self.close_button_label = Gtk.Label() self.close_button_label.set_text_with_mnemonic(_('_Close')) self.close_button.add(self.close_button_label) self.close_button.connect("clicked", self._on_close_button_clicked) self.hbox = Gtk.HBox(spacing=0) self.hbox.pack_end(self.close_button, False, False, 0) self.vbox.pack_start(self.hbox, False, False, 5) self.show_all() def _on_close_button_clicked(self, _button: Gtk.Button) -> None: ''' Close the input method help window when the close button is clicked ''' self.destroy() if __name__ == '__main__': if _ARGS.no_debug: LOG_HANDLER_NULL = logging.NullHandler() else: LOGFILE = os.path.join( ibus_table_location.cache_home(), 'setup-debug.log') LOG_HANDLER_TIME_ROTATE = logging.handlers.TimedRotatingFileHandler( LOGFILE, when='H', interval=6, backupCount=7, encoding='UTF-8', delay=False, utc=False, atTime=None) LOG_FORMATTER = logging.Formatter( '%(asctime)s %(filename)s ' 'line %(lineno)d %(funcName)s %(levelname)s: ' '%(message)s') LOG_HANDLER_TIME_ROTATE.setFormatter(LOG_FORMATTER) LOGGER.setLevel(logging.DEBUG) LOGGER.addHandler(LOG_HANDLER_TIME_ROTATE) LOGGER.info('********** STARTING **********') # Workaround for # https://bugzilla.gnome.org/show_bug.cgi?id=622084 # Bug 622084 - Ctrl+C does not exit gtk app signal.signal(signal.SIGINT, signal.SIG_DFL) try: locale.setlocale(locale.LC_ALL, '') except locale.Error: LOGGER.exception("IBUS-WARNING **: Using the fallback 'C' locale") locale.setlocale(locale.LC_ALL, 'C') i18n_init() if IBus.get_address() is None: DIALOG = Gtk.MessageDialog( flags=Gtk.DialogFlags.MODAL, message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK, message_format=_('ibus is not running.')) DIALOG.run() DIALOG.destroy() sys.exit(1) ENGINE_NAME = _ARGS.engine_name if not ENGINE_NAME and 'IBUS_ENGINE_NAME' in os.environ: ENGINE_NAME = os.environ['IBUS_ENGINE_NAME'] ENGINE_NAME = re.sub(r'^table:', '', ENGINE_NAME).replace(' ', '_') if not ENGINE_NAME: PARSER.print_help() SETUP_UI = SetupUI(engine_name=ENGINE_NAME) Gtk.main() ibus-table-1.17.11/setup/version.py.in000066400000000000000000000020041475513533100175200ustar00rootroot00000000000000# vim:set et ts=4 sts=4: # # ibus-table - The Chinese Table engine for IBus # # Copyright (c) 2008-2010 Peng Huang # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. ''' Contains a function to return the current version number of ibus-table. ''' def get_version() -> str: ''' Returns the current version number of ibus-table. ''' return '@VERSION@' ibus-table-1.17.11/tables/000077500000000000000000000000001475513533100151725ustar00rootroot00000000000000ibus-table-1.17.11/tables/Makefile.am000066400000000000000000000021521475513533100172260ustar00rootroot00000000000000# vim:set noet ts=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # $Id: $ # SUBDIRS = \ $(NULL) template_DATA = \ template.txt \ $(NULL) templatedir = $(datadir)/ibus-table/tables EXTRA_DIST = \ template.txt \ $(NULL) MAINTAINERCLEANFILES = \ Makefile.in \ $(NULL) install-data-local: $(MKDIR_P) $(DESTDIR)$(pkgdatadir)/tables ibus-table-1.17.11/tables/template.txt000066400000000000000000000117651475513533100175600ustar00rootroot00000000000000### File header must not be modified ### This file must be encoded into UTF-8. ### This table under LGPL ### comments start with ### not single # ### Derive from the format of SCIM Table, so you can modify the table from ### scim-tables' table SCIM_Generic_Table_Phrase_Library_TEXT VERSION_1_0 ### Begin Table definition. BEGIN_DEFINITION ### License LICENSE = LGPL ### An unique id to distinguish this table among others. ### Use uuidgen to generate this kind of id. UUID = c9851827-0abe-12ed-8db5-010b9d51ffed ### A unique number indicates the version of this file. ### For example the last modified date of this file. ### This number must be less than 2^32. ### Just make your table version-able SERIAL_NUMBER = 20090218 ### ICON can be any format as long as your pygtk can recognized ### the most widely ones are "png" and "svg", letter one is recommended ICON = ibus-table.svg ### The symbol to be displayed in IM switchers SYMBOL = 码 ### The default name of this table, this is needed NAME = Table ### The local names of this table, this is optional NAME.zh_CN = 形码 NAME.zh_HK = 形碼 NAME.zh_TW = 形碼 ### Description DESCRIPTION = This is a template engine table for IBus Table. ### Supported languages of this table ### sigle "zh_CN" just be recognized as zh_CN, ### but "zh_CN, zh_HK" or more zh_XX will be recognized as zh; ### and "en_US, zh_CN" will be just ignored. LANGUAGES = zh_CN,zh_SG,zh_TW,zh_HK ### The author of this table AUTHOR = Yu Yuwei ### Prompt string to be displayed in the status area, CN will be replaced by ### the gettext tools in runtime as 中. STATUS_PROMPT = CN ### Valid input chars. VALID_INPUT_CHARS = abcdefghijklmnopqrstuvwxyz ### Layout LAYOUT = us ### The max number of input keys for every phrase or character. MAX_KEY_LENGTH = 4 ### Use auto_commit mode as default AUTO_COMMIT = FALSE ### Automatically selects the first phrase when typing AUTO_SELECT = FALSE ### Use full width punctuation by default DEF_FULL_WIDTH_PUNCT = TRUE ### Not use full width letter by default DEF_FULL_WIDTH_LETTER = FALSE ### Whether user are allow to define phrase, default is true ### You have to define the word construction rules below. ### For input methods which do not input phrases, set this to False USER_CAN_DEFINE_PHRASE = TRUE ### Whether support PinYin Mode, default is true. ### this feature is just for Chinese, set it to False if your IM is not ### Chinese. PINYIN_MODE = TRUE ### If true then the phrases' frequencies will be adjusted dynamically ### according your using frequency. DYNAMIC_ADJUST = TRUE ### Some characters whose frequencies should be fix all the time, e.g. ### some punctuations ### NO_CHECK_CHARS = ### Rules for constructing user defined phrase ### "ce" stands for "ci equal", a Chinese English :), means "phrase length ### equal to", thus ce2 -> phrase length equal to 2; and "ca" means "phrase ### length equal or above", so ca4 -> phrase length equal or above 4. ### p21 -> the 1st key of 2nd character in the phrase, and so on. ### Each rule separate via ";". ### Example below is a complete rule-set, ### becuase [2,2] ∩ [3,3] ∩ [4,+∞] = [2,+∞], which is the range of length ### of phrase. This have to be satisfied if you need ibus-table to build up ### your own inputed phrase via your daily using. RULES = ce2:p11+p12+p21+p22;ce3:p11+p21+p22+p31;ca4:p11+p21+p31+p41 ### The key strokes to page up the lookup table. ### PAGE_UP_KEYS = Page_Up,KP_Page_Up,minus,comma ### The key strokes to page down. ### PAGE_DOWN_KEYS = Page_Down,KP_Page_Down,equal,period ### The key strokes to select candidiate phrases. ### Usually "1,2,3,4,5,6,7,8,9" but if this conflicts with ### characters one wants to use for input one can also ### use something like “F1,F2,F3,F4,F5,F6,F7,F8,F9” SELECT_KEYS = 1,2,3,4,5,6,7,8,9 ### The default orientation of the candidate list ### TRUE means the candidate list is vertical, FALSE means it is vertical ORIENTATION=TRUE END_DEFINITION ### Begin Table data. ### Format of every line whose formated in "input_keys\tphrase\tfreq\n" is an ### entry. ### From left to right, the 1st column are the input key combination that you ### entered via keyboard; the 2nd column are presented character or phrase of ### the key combination you want; the 3rd column are frequency of the character ### or phrase. BEGIN_TABLE input_keys aim_chars freq input_keys aim_chars freq input_keys aim_chars freq END_TABlE ### Since some input methods use different table for every character to make ### phrase, such as ZhengMa, they need explict define the goucima (the ### phrase-building code for the given character), the format of every entry is ### "character\tgoucima\n". ### For the input method which just use the full code as word-building code ### just skip this field. The ibus-table will build the codes needed from ### above TABLE. ### if you don't need different word-building code, please comment out the ### next few lines with ###, just like these lines you are look at now. BEGIN_GOUCI character_1 goucima_1 character_1 goucima_2 END_GOUCI ibus-table-1.17.11/tests/000077500000000000000000000000001475513533100150625ustar00rootroot00000000000000ibus-table-1.17.11/tests/.gitignore000066400000000000000000000000511475513533100170460ustar00rootroot00000000000000run_tests *.log *.trs *.tap __pycache__/ ibus-table-1.17.11/tests/Makefile.am000066400000000000000000000036601475513533100171230ustar00rootroot00000000000000# vim:set noet ts=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2018 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TESTS = \ test_it.py \ test_0_gtk.py \ $(NULL) check_SCRIPTS = run_tests LOG_COMPILER = $(builddir)/run_tests TESTS_ENVIRONMENT = \ IBUS_TABLE_LOCATION=../ test_meta_in = meta.test.in test_metas = if ENABLE_INSTALLED_TESTS test_metas += $(patsubst %.py, %.test, $(TESTS)) test_source_DATA = $(test_metas) test_sourcedir = $(datadir)/installed-tests/ibus-table test_exec_SCRIPTS = \ $(TESTS) \ gtkcases.py \ mock_engine.py \ run_tests \ $(NULL) test_execdir = $(libexecdir)/installed-tests/ibus-table $(test_metas): $(test_meta_in) @TEST_EXEC=`echo $@ | sed -e 's&\.test&\.py&'`; \ sed -e "s&@TEST_EXECDIR@&$(test_execdir)&g" \ -e "s&@TEST_EXEC@&$$TEST_EXEC&g" $< > $@.tmp; \ mv $@.tmp $@; \ $(NULL) endif run_tests: run_tests.in sed -e 's&@PYTHON_BIN@&$(PYTHON)&g' \ -e 's&@PKGDATADIR@&$(pkgdatadir)&g' \ -e 's&@SRCDIR@&$(srcdir)&g' $< > $@ chmod +x $@ EXTRA_DIST = \ $(test_meta_in) \ __init__.py \ gtkcases.py \ mock_engine.py \ run_tests.in \ $(TESTS) \ $(NULL) CLEANFILES = \ $(test_metas) \ run_tests \ $(NULL) MAINTAINERCLEANFILES = \ Makefile.in \ $(NULL) ibus-table-1.17.11/tests/__init__.py000066400000000000000000000000001475513533100171610ustar00rootroot00000000000000ibus-table-1.17.11/tests/gtkcases.py000077500000000000000000000026441475513533100172510ustar00rootroot00000000000000#!/usr/bin/python3 # 'init' has one array which is [keysym, keycode, modifier] and to be run # before the main tests. E.g. # Ctrl-space to enable Hiragana mode # # 'tests' cases are the main test cases. # 'preedit' case runs to create a preedit text. # 'lookup' case runs to update a lookup table. # 'commit' case runs to commit the preedit text. # 'result' case is the expected output. # 'preedit', 'lookup', 'commit' can choose the type of either 'string' or 'keys' # 'string' type is a string sequence which does not need modifiers from gi import require_version as gi_require_version # type: ignore gi_require_version('IBus', '1.0') from gi.repository import IBus # type: ignore TestCases = { #'init': [IBus.KEY_j, 0, IBus.ModifierType.CONTROL_MASK], 'tests': [ {'preedit': {'string': 'a'}, 'lookup': {'keys': [[IBus.KEY_Down, 0, 0]]}, 'commit': {'keys': [[IBus.KEY_space, 0, 0]]}, 'result': {'string': '区'} }, {'preedit': {'string': 'ijgl'}, 'commit': {'keys': [[IBus.KEY_space, 0, 0]]}, 'result': {'string': '漫画'} }, {'preedit': {'string': 'wgl'}, 'lookup': {'keys': [[IBus.KEY_Down, 0, 0]]}, 'commit': {'keys': [[IBus.KEY_space, 0, 0]]}, 'result': {'string': '全国'} }, ] } ibus-table-1.17.11/tests/meta.test.in000066400000000000000000000001111475513533100173070ustar00rootroot00000000000000[Test] Type=session Exec=@TEST_EXECDIR@/run_tests @TEST_EXEC@ Output=TAP ibus-table-1.17.11/tests/mock_engine.py000066400000000000000000000224231475513533100177150ustar00rootroot00000000000000# ibus-table - The Tables engine for IBus # # Copyright (c) 2018-2020 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # ''' Define some mock classes for the unittests. ''' from typing import Any from typing import List from typing import Optional from gi import require_version # type: ignore require_version('IBus', '1.0') from gi.repository import IBus # type: ignore class MockEngine: props = None def __init__( self, engine_name: str = '', connection: Any = None, object_path: str = ''): self.mock_auxiliary_text = '' self.mock_preedit_text = '' self.mock_preedit_text_cursor_pos = 0 self.mock_preedit_text_visible = True self.mock_preedit_focus_mode = IBus.PreeditFocusMode.COMMIT self.mock_committed_text = '' self.mock_committed_text_cursor_pos = 0 self.client_capabilities = ( IBus.Capabilite.PREEDIT_TEXT | IBus.Capabilite.AUXILIARY_TEXT | IBus.Capabilite.LOOKUP_TABLE | IBus.Capabilite.FOCUS | IBus.Capabilite.PROPERTY) # There are lots of weird problems with surrounding text # which makes this hard to test. Therefore this mock # engine does not try to support surrounding text, i.e. # we omit “| IBus.Capabilite.SURROUNDING_TEXT” here. def update_auxiliary_text(self, text: IBus.Text, visible: bool) -> None: self.mock_auxiliary_text = text.text def hide_auxiliary_text(self) -> None: pass def hide_preedit_text(self) -> None: pass def commit_text(self, text: IBus.Text) -> None: self.mock_committed_text = ( self.mock_committed_text[ :self.mock_committed_text_cursor_pos] + text.text + self.mock_committed_text[ self.mock_committed_text_cursor_pos:]) self.mock_committed_text_cursor_pos += len(text.text) def forward_key_event(self, val: int, code: int, state: int) -> None: if (val == IBus.KEY_Left and self.mock_committed_text_cursor_pos > 0): self.mock_committed_text_cursor_pos -= 1 return unicode = IBus.keyval_to_unicode(val) if unicode: self.mock_committed_text = ( self.mock_committed_text[ :self.mock_committed_text_cursor_pos] + unicode + self.mock_committed_text[ self.mock_committed_text_cursor_pos:]) self.mock_committed_text_cursor_pos += len(unicode) def update_lookup_table( self, table: IBus.LookupTable, visible: bool) -> None: pass def update_preedit_text( self, text: IBus.Text, cursor_pos: int, visible: bool) -> None: self.mock_preedit_text = text.get_text() self.mock_preedit_text_cursor_pos = cursor_pos self.mock_preedit_text_visible = visible def update_preedit_text_with_mode( self, text: IBus.Text, cursor_pos: int, visible: bool, focus_mode: IBus.PreeditFocusMode) -> None: self.mock_preedit_focus_mode = focus_mode self.update_preedit_text(text, cursor_pos, visible) def register_properties(self, property_list: List[IBus.Property]) -> None: pass def update_property(self, property: IBus.Property) -> None: pass def hide_lookup_table(self) -> None: pass def connect(self, signal: str, callback_function: Any) -> None: pass def add_table_by_locale(self, locale: str) -> None: pass class MockLookupTable: def __init__( self, page_size: int = 9, cursor_pos: int = 0, cursor_visible: bool = False, round: bool = True): self.clear() self.mock_page_size = page_size self.mock_cursor_pos = cursor_pos self.mock_cursor_visible = cursor_visible self.cursor_visible = cursor_visible self.mock_round = round self.mock_candidates: List[str] = [] self.mock_labels: List[str] = [] self.mock_page_number = 0 def clear(self) -> None: self.mock_candidates = [] self.mock_cursor_pos = 0 def set_page_size(self, size: int) -> None: self.mock_page_size = size def get_page_size(self) -> int: return self.mock_page_size def set_round(self, round: bool) -> None: self.mock_round = round def set_cursor_pos(self, pos: int) -> None: self.mock_cursor_pos = pos def get_cursor_pos(self) -> int: return self.mock_cursor_pos def get_cursor_in_page(self) -> int: return (self.mock_cursor_pos - self.mock_page_size * self.mock_page_number) def set_cursor_visible(self, visible: bool) -> None: self.mock_cursor_visible = visible self.cursor_visible = visible def cursor_down(self) -> None: if len(self.mock_candidates): self.mock_cursor_pos += 1 self.mock_cursor_pos %= len(self.mock_candidates) def cursor_up(self) -> None: if len(self.mock_candidates): if self.mock_cursor_pos > 0: self.mock_cursor_pos -= 1 else: self.mock_cursor_pos = len(self.mock_candidates) - 1 def page_down(self) -> None: if len(self.mock_candidates): self.mock_page_number += 1 self.mock_cursor_pos += self.mock_page_size def page_up(self) -> None: if len(self.mock_candidates): if self.mock_page_number > 0: self.mock_page_number -= 1 self.mock_cursor_pos -= self.mock_page_size def set_orientation(self, orientation: int) -> None: self.mock_orientation = orientation def get_number_of_candidates(self) -> int: return len(self.mock_candidates) def append_candidate(self, candidate: IBus.Text) -> None: self.mock_candidates.append(candidate.get_text()) def get_candidate(self, index: int) -> str: return self.mock_candidates[index] def append_label(self, label: IBus.Text) -> None: self.mock_labels.append(label.get_text()) class MockPropList: def __init__(self, *args: Any, **kwargs: Any) -> None: self._mock_proplist: List[IBus.Property] = [] def append(self, property: IBus.Property) -> None: self._mock_proplist.append(property) def get(self, index: int) -> Optional[IBus.Property]: if index >= 0 and index < len(self._mock_proplist): return self._mock_proplist[index] else: return None def update_property(self, property: IBus.Property) -> None: pass class MockProperty: def __init__(self, key: str = '', prop_type: IBus.PropType = IBus.PropType.RADIO, label: IBus.Text = IBus.Text.new_from_string(''), symbol: IBus.Text = IBus.Text.new_from_string(''), icon: str = '', tooltip: IBus.Text = IBus.Text.new_from_string(''), sensitive: bool = True, visible: bool = True, state: IBus.PropState = IBus.PropState.UNCHECKED, sub_props: Optional[List[IBus.Property]] = None) -> None: self.mock_property_key = key self.mock_property_prop_type = prop_type self.mock_property_label = label.get_text() self.mock_property_symbol = symbol.get_text() self.mock_property_icon = icon self.mock_property_tooltip = tooltip.get_text() self.mock_property_sensitive = sensitive self.mock_property_visible = visible self.mock_property_state = state self.mock_property_sub_props = sub_props def set_label(self, ibus_text: IBus.Text) -> None: self.mock_property_label = ibus_text.get_text() def set_symbol(self, ibus_text: IBus.Text) -> None: self.mock_property_symbol = ibus_text.get_text() def set_tooltip(self, ibus_text: IBus.Text) -> None: self.mock_property_tooltip = ibus_text.get_text() def set_icon(self, icon_path: str) -> None: self.mock_property_icon = icon_path def set_sensitive(self, sensitive: bool) -> None: self.mock_property_sensitive = sensitive def set_visible(self, visible: bool) -> None: self.mock_property_visible = visible def set_state(self, state: IBus.PropState) -> None: self.mock_property_state = state def set_sub_props(self, proplist: List[IBus.Property]) -> None: self.mock_property_sub_props = proplist def get_key(self) -> str: return self.mock_property_key ibus-table-1.17.11/tests/run_tests.in000066400000000000000000000040051475513533100174370ustar00rootroot00000000000000#!@PYTHON_BIN@ # ibus-table - The Tables engine for IBus # # Copyright (c) 2018 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see import sys import os import unittest # pip3 install tap.py --user IMPORT_TAP_SUCCESSFUL = False try: from tap import TAPTestRunner IMPORT_TAP_SUCCESSFUL = True except (ImportError,): pass if 'IBUS_TABLE_LOCATION' in os.environ: location_path = os.environ['IBUS_TABLE_LOCATION'] if location_path != None and location_path != '': engine_path = os.path.join(location_path, 'engine') sys.path.append(engine_path) sys.path.append('@PKGDATADIR@/engine') # -- Load and run our unit tests --------------------------------------------- pattern = 'test*.py' start_dir = os.path.dirname(__file__) if len(sys.argv) > 1: pattern = sys.argv[-1] dir = os.path.dirname(pattern) pattern = os.path.basename(pattern) if dir != '.': start_dir = os.path.join(start_dir, dir) loader = unittest.TestLoader() suite = loader.discover(start_dir=start_dir, pattern=pattern) if IMPORT_TAP_SUCCESSFUL: runner = TAPTestRunner(stream=sys.stderr, verbosity=255) runner.set_outdir('.') runner.set_format('Hi: {method_name} - {short_description}') runner.set_combined(True) else: runner = unittest.TextTestRunner(stream=sys.stderr, verbosity=255) result = runner.run(suite) if result.failures or result.errors: sys.exit(1) ibus-table-1.17.11/tests/test_0_gtk.py000077500000000000000000000412011475513533100175000ustar00rootroot00000000000000#!/usr/bin/python3 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2020 Takao Fujiwara # Copyright (c) 2020 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see ''' This file implements the test cases using GTK GUI ''' # “Wrong continued indentation”: pylint: disable=bad-continuation # pylint: disable=attribute-defined-outside-init # pylint: disable=missing-function-docstring # pylint: disable=missing-class-docstring # pylint: disable=global-statement # pylint: disable=wrong-import-order # pylint: disable=wrong-import-position from typing import List from typing import Dict from typing import Any from typing import Optional import argparse import os import signal import sys import unittest from gi import require_version as gi_require_version # type: ignore gi_require_version('GLib', '2.0') gi_require_version('Gdk', '3.0') gi_require_version('Gio', '2.0') gi_require_version('Gtk', '3.0') gi_require_version('IBus', '1.0') from gi.repository import GLib # type: ignore from gi.repository import Gdk from gi.repository import Gio from gi.repository import Gtk from gi.repository import IBus # Get more verbose output in the test log: os.environ['IBUS_TABLE_DEBUG_LEVEL'] = '255' sys.path.insert(0, "../engine") IMPORT_TABLE_SUCCESSFUL = False try: import table IMPORT_TABLE_SUCCESSFUL = True except (ImportError,): pass IMPORT_TABSQLITEDB_SUCCESSFUL = False try: import tabsqlitedb IMPORT_TABSQLITEDB_SUCCESSFUL = True except (ImportError,): pass # FIXME: #sys.path.pop(0) DONE_EXIT = True ENGINE_NAME = 'wubi-jidian86' from gtkcases import TestCases # Need to flush the output against Gtk.main() def printflush(sentence: str) -> None: try: print(sentence, flush=True) except OSError: pass def printerr(sentence: str) -> None: try: print(sentence, flush=True, file=sys.stderr) except OSError: pass @unittest.skipUnless( os.path.isfile( os.path.join('/usr/share/ibus-table/tables', ENGINE_NAME + '.db')), '%s.db is not installed.' % ENGINE_NAME + '.db') @unittest.skipUnless( 'XDG_SESSION_TYPE' in os.environ and os.environ['XDG_SESSION_TYPE'] in ('x11', 'wayland'), 'XDG_SESSION_TYPE is neither "x11" nor "wayland".') @unittest.skipIf(Gdk.Display.open('') is None, 'Display cannot be opened.') class SimpleGtkTestCase(unittest.TestCase): global DONE_EXIT global ENGINE_NAME ENGINE_PATH = '/com/redhat/IBus/engines/table/Test/Engine' _flag: bool = False _gsettings: Optional[Gio.Settings] = None _orig_chinesemode: int = 4 @classmethod def setUpClass(cls) -> None: cls._flag = False IBus.init() cls._gsettings = Gio.Settings( schema='org.freedesktop.ibus.engine.table', path='/org/freedesktop/ibus/engine/table/%s/' % ENGINE_NAME) cls._orig_chinesemode = cls._gsettings.get_int('chinesemode') signums: List[Optional[signal.Signals]] = [ getattr(signal, s, None) for s in 'SIGINT SIGTERM SIGHUP'.split()] for signum in filter(None, signums): original_handler = signal.getsignal(signum) GLib.unix_signal_add(GLib.PRIORITY_HIGH, signum, cls.signal_handler, (signum, original_handler)) @classmethod def tearDownClass(cls) -> None: if cls._gsettings is not None: cls._gsettings.set_int('chinesemode', cls._orig_chinesemode) @classmethod def signal_handler(cls, user_data: Any) -> None: (signum, original_handler) = user_data cls.tearDownClass() Gtk.main_quit() signal.signal(signum, original_handler) cls._flag = True assert False, 'signal received: ' + str(signum) def setUp(self) -> None: self.__id = 0 self.__rerun = False self.__test_index = 0 self.__preedit_index = 0 self.__lookup_index = 0 self.__inserted_text = '' self.__commit_done = False self.__reset_coming = False if self._gsettings is not None: self._gsettings.set_int('chinesemode', 4) def register_ibus_engine(self) -> bool: self.__bus = IBus.Bus() if not self.__bus.is_connected(): self.fail('ibus-daemon is not running') return False self.__bus.get_connection().signal_subscribe( 'org.freedesktop.DBus', 'org.freedesktop.DBus', 'NameOwnerChanged', '/org/freedesktop/DBus', None, 0, self.__bus_signal_cb, self.__bus) self.__factory = IBus.Factory( object_path=IBus.PATH_FACTORY, connection=self.__bus.get_connection()) self.__factory.connect('create-engine', self.__create_engine_cb) self.__component = IBus.Component( name='org.freedesktop.IBus.Table.Test', description='Test Table Component', version='1.0', license='GPL', author=('Mike FABIAN , ' + 'Caius "kaio" CHANCE '), homepage='http://mike-fabian.github.io/ibus-table/', command_line='', textdomain='ibus-table') desc = IBus.EngineDesc( name=ENGINE_NAME, longname='Test Table %s' % ENGINE_NAME, description='Test Table Component', language='t', license='GPL', author=('Mike FABIAN , ' + 'Caius "kaio" CHANCE '), icon='', symbol='T') self.__component.add_engine(desc) self.__bus.register_component(self.__component) self.__bus.request_name('org.freedesktop.IBus.Table.Test', 0) return True def __bus_signal_cb( self, connection: Gio.DBusConnection, sender_name: str, object_path: str, interface_name: str, signal_name: str, parameters: GLib.Variant, user_data: IBus.Bus) -> None: if signal_name == 'NameOwnerChanged': pass if signal_name == 'UpdateLookupTable': table = self.__engine.get_lookup_table() if table.get_number_of_candidates() == 0: return self.__lookup_test() def __create_engine_cb( self, factory: IBus.Factory, engine_name: str) -> Optional[Any]: if engine_name != ENGINE_NAME: return None if (not IMPORT_TABLE_SUCCESSFUL or not IMPORT_TABSQLITEDB_SUCCESSFUL): with self.subTest(i='create-engine'): self.fail('NG: ibus-table not installed?') Gtk.main_quit() return None self.__id += 1 object_path = '%s/%d' % (self.ENGINE_PATH, self.__id) db_dir = '/usr/share/ibus-table/tables' db_file = os.path.join(db_dir, engine_name + '.db') database = tabsqlitedb.TabSqliteDb( filename=db_file, user_db=':memory:', unit_test=True) self.__engine = table.TabEngine( self.__bus, object_path, database) self.__engine.connect('focus-in', self.__engine_focus_in) self.__engine.connect('focus-out', self.__engine_focus_out) # FIXME: Need to connect 'reset' after TabEngine.clear_all_input_and_preedit() # is called. self.__engine.connect_after('reset', self.__engine_reset) self.__bus.get_connection().signal_subscribe( None, IBus.INTERFACE_ENGINE, 'UpdateLookupTable', object_path, None, 0, self.__bus_signal_cb, self.__bus) return self.__engine def __engine_focus_in(self, _engine: IBus.Engine) -> None: if self.__test_index == len(TestCases['tests']): if DONE_EXIT: Gtk.main_quit() return # Workaround because focus-out resets the preedit text # ibus_bus_set_global_engine() calls bus_input_context_set_engine() # twice and it causes bus_engine_proxy_focus_out() if self.__rerun: self.__rerun = False self.__main_test() def __engine_focus_out(self, _engine: IBus.Engine) -> None: self.__rerun = True self.__test_index = 0 self.__entry.set_text('') def __engine_reset(self, _engine: IBus.Engine) -> None: if self.__reset_coming: self.__reset_coming = False self.__main_test() def __entry_focus_in_event_cb( self, entry: Gtk.Entry, event: Gdk.EventFocus) -> bool: if self.__test_index == len(TestCases['tests']): if DONE_EXIT: Gtk.main_quit() return False self.__bus.set_global_engine_async(ENGINE_NAME, -1, None, self.__set_engine_cb) return False def __set_engine_cb(self, _object: IBus.Bus, res: Gio.Task) -> None: with self.subTest(i=self.__test_index): if not self.__bus.set_global_engine_async_finish(res): self.fail('set engine failed.') return # rerun always happen? #self.__main_test() def __get_test_condition_length(self, tag: str) -> int: tests: Dict[str, Any] = TestCases['tests'][self.__test_index] try: cases = tests[tag] except KeyError: return -1 case_type = list(cases.keys())[0] return len(cases[case_type]) def __entry_preedit_changed_cb( self, entry: Gtk.Entry, preedit_str: str) -> None: if len(preedit_str) == 0: return if self.__test_index == len(TestCases['tests']): if DONE_EXIT: Gtk.main_quit() return self.__preedit_index += 1 if self.__preedit_index != self.__get_test_condition_length('preedit'): return if self.__get_test_condition_length('lookup') > 0: return self.__run_cases('commit') def __main_test(self) -> None: self.__preedit_index = 0 self.__lookup_index = 0 self.__commit_done = False self.__run_cases('preedit') def __lookup_test(self) -> None: lookup_length = self.__get_test_condition_length('lookup') # Need to return again even if all the lookup is finished # until the final Engine.update_preedit() is called. if self.__lookup_index > lookup_length: return self.__run_cases('lookup', self.__lookup_index, self.__lookup_index + 1) if self.__lookup_index < lookup_length: self.__lookup_index += 1 return self.__lookup_index += 1 self.__run_cases('commit') def __run_cases(self, tag: str, start: int = -1, end: int = -1) -> None: tests: Dict[str, Any] = TestCases['tests'][self.__test_index] if tests is None: return try: cases = tests[tag] except KeyError: return case_type = list(cases.keys())[0] i = 0 if case_type == 'string': printflush('test step: %s sequences: "%s"' % (tag, str(cases['string']))) for character in cases['string']: if start >= 0 and i < start: i += 1 continue if 0 <= end <= i: break self.__typing(ord(character), 0, 0) i += 1 if case_type == 'keys': if start == -1 and end == -1: printflush('test step: %s sequences: %s' % (tag, str(cases['keys']))) for key in cases['keys']: if start >= 0 and i < start: i += 1 continue if 0 <= end <= i: break if start != -1 or end != -1: printflush('test step: %s sequences: [0x%X, 0x%X, 0x%X]' % (tag, key[0], key[1], key[2])) self.__typing(key[0], key[1], key[2]) i += 1 def __typing(self, keyval: int, keycode: int, modifiers: int) -> None: self.__engine.emit('process-key-event', keyval, keycode, modifiers) modifiers |= IBus.ModifierType.RELEASE_MASK self.__engine.emit('process-key-event', keyval, keycode, modifiers) def __buffer_inserted_text_cb( self, buffer: Gtk.EntryBuffer, position: int, chars: str, nchars: int) -> None: tests: Dict[str, Any] = TestCases['tests'][self.__test_index] cases = tests['commit'] case_type = list(cases.keys())[0] if case_type == 'keys': # space key is sent separatedly later if cases['keys'][0] == [IBus.KEY_space, 0, 0]: self.__inserted_text += chars # FIXME: Return key emits 'reset' signal in GTK and it calls # TableEngine.clear_all_input_and_preedit(). elif cases['keys'][0] == [IBus.KEY_Return, 0, 0] or \ cases['keys'][0] == [IBus.KEY_KP_Enter, 0, 0] or \ cases['keys'][0] == [IBus.KEY_ISO_Enter, 0, 0] or \ cases['keys'][0] == [IBus.KEY_Escape, 0, 0]: self.__inserted_text = chars self.__reset_coming = True else: self.__inserted_text = chars cases = tests['result'] if cases['string'] == self.__inserted_text: printflush('OK: %d "%s"' % (self.__test_index, self.__inserted_text)) else: if DONE_EXIT: Gtk.main_quit() with self.subTest(i=self.__test_index): self.fail('NG: %d "%s" "%s"' % (self.__test_index, str(cases['string']), self.__inserted_text)) self.__inserted_text = '' self.__test_index += 1 if self.__test_index == len(TestCases['tests']): if DONE_EXIT: Gtk.main_quit() return self.__commit_done = True self.__entry.set_text('') if not self.__reset_coming: self.__main_test() def create_window(self) -> None: window = Gtk.Window(type=Gtk.WindowType.TOPLEVEL) self.__entry = entry = Gtk.Entry() window.connect('destroy', Gtk.main_quit) entry.connect('focus-in-event', self.__entry_focus_in_event_cb) entry.connect('preedit-changed', self.__entry_preedit_changed_cb) buffer = entry.get_buffer() buffer.connect('inserted-text', self.__buffer_inserted_text_cb) window.add(entry) window.show_all() def main(self) -> None: # pylint: disable=no-self-use # Some ATK relative warnings are called during launching GtkWindow. flags = GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_CRITICAL) Gtk.main() GLib.log_set_always_fatal(flags) def test_typing(self) -> None: if not self.register_ibus_engine(): sys.exit(-1) self.create_window() self.main() if self._flag: self.fail('NG: signal failure') def main() -> None: parser = argparse.ArgumentParser() parser.add_argument('-k', '--keep', action='store_true', help='keep this GtkWindow after test is done') parser.add_argument('-F', '--unittest-failfast', action='store_true', help='stop on first fail or error in unittest') parser.add_argument('-H', '--unittest-help', action='store_true', help='show unittest help message and exit') args, unittest_args = parser.parse_known_args() sys.argv[1:] = unittest_args if args.keep: global DONE_EXIT DONE_EXIT = False if args.unittest_failfast: sys.argv.append('-f') if args.unittest_help: sys.argv.append('-h') unittest.main() unittest.main() if __name__ == '__main__': main() ibus-table-1.17.11/tests/test_it.py000077500000000000000000002356321475513533100171250ustar00rootroot00000000000000#!/usr/bin/python3 # ibus-table - The Tables engine for IBus # # Copyright (c) 2018, 2021 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # ''' This file implements the test cases for the unit tests of ibus-table ''' import sys import os import logging import time import unittest import importlib from unittest import mock from gi import require_version # type: ignore require_version('IBus', '1.0') from gi.repository import IBus # type: ignore LOGGER = logging.getLogger('ibus-table') # Get more verbose output in the test log: os.environ['IBUS_TABLE_DEBUG_LEVEL'] = '255' # Monkey patch the environment with the mock classes: from mock_engine import MockEngine from mock_engine import MockLookupTable from mock_engine import MockProperty from mock_engine import MockPropList sys.path.insert(0, "../engine") import table import tabsqlitedb import ibus_table_location sys.path.pop(0) ENGINE_PATCHER = mock.patch.object( IBus, 'Engine', new=MockEngine) ENGINE_SIMPLE_PATCHER = mock.patch.object( IBus, 'EngineSimple', new=MockEngine) LOOKUP_TABLE_PATCHER = mock.patch.object( IBus, 'LookupTable', new=MockLookupTable) PROPERTY_PATCHER = mock.patch.object( IBus, 'Property', new=MockProperty) PROP_LIST_PATCHER = mock.patch.object( IBus, 'PropList', new=MockPropList) IBUS_ENGINE = IBus.Engine IBUS_ENGINE_SIMPLE = IBus.EngineSimple IBUS_LOOKUP_TABLE = IBus.LookupTable IBUS_PROPERTY = IBus.Property IBUS_PROP_LIST = IBus.PropList ENGINE = None TABSQLITEDB = None ORIG_INPUT_MODE = None ORIG_CHINESE_MODE = None ORIG_LETTER_WIDTH = None ORIG_PUNCTUATION_WIDTH = None ORIG_ALWAYS_SHOW_LOOKUP = None ORIG_LOOKUP_TABLE_ORIENTATION = None ORIG_PAGE_SIZE = None ORIG_ONECHAR_MODE = None ORIG_AUTOSELECT_MODE = None ORIG_AUTOCOMMIT_MODE = None ORIG_COMMIT_INVALID_MODE = None ORIG_AUTOWILDCARD_MODE = None ORIG_SINGLE_WILDCARD_CHAR = None ORIG_MULTI_WILDCARD_CHAR = None ORIG_PINYIN_MODE = None ORIG_SUGGESTION_MODE = None ORIG_KEYBINDINGS = None ORIG_DYNAMIC_ADJUST = None ORIG_DEBUG_LEVEL = None def backup_original_settings() -> None: global ENGINE global ORIG_KEYBINDINGS global ORIG_INPUT_MODE global ORIG_CHINESE_MODE global ORIG_LETTER_WIDTH global ORIG_PUNCTUATION_WIDTH global ORIG_ALWAYS_SHOW_LOOKUP global ORIG_LOOKUP_TABLE_ORIENTATION global ORIG_PAGE_SIZE global ORIG_ONECHAR_MODE global ORIG_AUTOSELECT_MODE global ORIG_AUTOCOMMIT_MODE global ORIG_COMMIT_INVALID_MODE global ORIG_AUTOWILDCARD_MODE global ORIG_SINGLE_WILDCARD_CHAR global ORIG_MULTI_WILDCARD_CHAR global ORIG_PINYIN_MODE global ORIG_SUGGESTION_MODE global ORIG_DYNAMIC_ADJUST global ORIG_DEBUG_LEVEL assert(ENGINE is not None) ORIG_KEYBINDINGS = ENGINE.get_keybindings() ORIG_INPUT_MODE = ENGINE.get_input_mode() ORIG_CHINESE_MODE = ENGINE.get_chinese_mode() ORIG_LETTER_WIDTH = ENGINE.get_letter_width() ORIG_PUNCTUATION_WIDTH = ENGINE.get_punctuation_width() ORIG_ALWAYS_SHOW_LOOKUP = ENGINE.get_always_show_lookup() ORIG_LOOKUP_TABLE_ORIENTATION = ENGINE.get_lookup_table_orientation() ORIG_PAGE_SIZE = ENGINE.get_page_size() ORIG_ONECHAR_MODE = ENGINE.get_onechar_mode() ORIG_AUTOSELECT_MODE = ENGINE.get_autoselect_mode() ORIG_AUTOCOMMIT_MODE = ENGINE.get_autocommit_mode() ORIG_COMMIT_INVALID_MODE = ENGINE.get_commit_invalid_mode() ORIG_AUTOWILDCARD_MODE = ENGINE.get_autowildcard_mode() ORIG_SINGLE_WILDCARD_CHAR = ENGINE.get_single_wildcard_char() ORIG_MULTI_WILDCARD_CHAR = ENGINE.get_multi_wildcard_char() ORIG_PINYIN_MODE = ENGINE.get_pinyin_mode() ORIG_SUGGESTION_MODE = ENGINE.get_suggestion_mode() ORIG_DYNAMIC_ADJUST = ENGINE.get_dynamic_adjust() ORIG_DEBUG_LEVEL = ENGINE.get_debug_level() def restore_original_settings() -> None: global ENGINE global ORIG_KEYBINDINGS global ORIG_INPUT_MODE global ORIG_CHINESE_MODE global ORIG_LETTER_WIDTH global ORIG_PUNCTUATION_WIDTH global ORIG_ALWAYS_SHOW_LOOKUP global ORIG_LOOKUP_TABLE_ORIENTATION global ORIG_PAGE_SIZE global ORIG_ONECHAR_MODE global ORIG_AUTOSELECT_MODE global ORIG_AUTOCOMMIT_MODE global ORIG_COMMIT_INVALID_MODE global ORIG_AUTOWILDCARD_MODE global ORIG_SINGLE_WILDCARD_CHAR global ORIG_MULTI_WILDCARD_CHAR global ORIG_PINYIN_MODE global ORIG_SUGGESTION_MODE global ORIG_DYNAMIC_ADJUST global ORIG_DEBUG_LEVEL assert(ENGINE is not None) ENGINE.set_keybindings( ORIG_KEYBINDINGS, update_gsettings=False) ENGINE.set_input_mode(ORIG_INPUT_MODE) ENGINE.set_chinese_mode( ORIG_CHINESE_MODE, update_gsettings=False) ENGINE.set_letter_width( ORIG_LETTER_WIDTH[0], input_mode=0, update_gsettings=False) ENGINE.set_letter_width( ORIG_LETTER_WIDTH[1], input_mode=1, update_gsettings=False) ENGINE.set_punctuation_width( ORIG_PUNCTUATION_WIDTH[0], input_mode=0, update_gsettings=False) ENGINE.set_punctuation_width( ORIG_PUNCTUATION_WIDTH[1], input_mode=1, update_gsettings=False) ENGINE.set_always_show_lookup( ORIG_ALWAYS_SHOW_LOOKUP, update_gsettings=False) ENGINE.set_lookup_table_orientation( ORIG_LOOKUP_TABLE_ORIENTATION, update_gsettings=False) ENGINE.set_page_size( ORIG_PAGE_SIZE, update_gsettings=False) ENGINE.set_onechar_mode(ORIG_ONECHAR_MODE, update_gsettings=False) ENGINE.set_autoselect_mode( ORIG_AUTOSELECT_MODE, update_gsettings=False) ENGINE.set_autocommit_mode( ORIG_AUTOCOMMIT_MODE, update_gsettings=False) ENGINE.set_commit_invalid_mode( ORIG_COMMIT_INVALID_MODE, update_gsettings=False) ENGINE.set_autowildcard_mode( ORIG_AUTOWILDCARD_MODE, update_gsettings=False) ENGINE.set_single_wildcard_char( ORIG_SINGLE_WILDCARD_CHAR, update_gsettings=False) ENGINE.set_multi_wildcard_char( ORIG_MULTI_WILDCARD_CHAR, update_gsettings=False) ENGINE.set_pinyin_mode(ORIG_PINYIN_MODE) ENGINE.set_suggestion_mode(ORIG_SUGGESTION_MODE) ENGINE.set_dynamic_adjust(ORIG_DYNAMIC_ADJUST) ENGINE.set_debug_level(ORIG_DEBUG_LEVEL, update_gsettings=False) def set_default_settings() -> None: global ENGINE global TABSQLITEDB assert(ENGINE is not None) assert(TABSQLITEDB is not None) ENGINE.set_input_mode(input_mode=1) chinese_mode = 4 language_filter = TABSQLITEDB.ime_properties.get('language_filter') if language_filter in ('cm0', 'cm1', 'cm2', 'cm3', 'cm4'): chinese_mode = int(language_filter[-1]) ENGINE.set_chinese_mode( mode=chinese_mode, update_gsettings=False) letter_width_mode = False def_full_width_letter = TABSQLITEDB.ime_properties.get( 'def_full_width_letter') if def_full_width_letter: letter_width_mode = (def_full_width_letter.lower() == 'true') ENGINE.set_letter_width( mode=False, input_mode=0, update_gsettings=False) ENGINE.set_letter_width( mode=letter_width_mode, input_mode=1, update_gsettings=False) punctuation_width_mode = False def_full_width_punct = TABSQLITEDB.ime_properties.get( 'def_full_width_punct') if def_full_width_punct: punctuation_width_mode = (def_full_width_punct.lower() == 'true') ENGINE.set_punctuation_width( mode=False, input_mode=0, update_gsettings=False) ENGINE.set_punctuation_width( mode=punctuation_width_mode, input_mode=1, update_gsettings=False) always_show_lookup_mode = True always_show_lookup = TABSQLITEDB.ime_properties.get( 'always_show_lookup') if always_show_lookup: always_show_lookup_mode = (always_show_lookup.lower() == 'true') ENGINE.set_always_show_lookup( always_show_lookup_mode, update_gsettings=False) orientation = TABSQLITEDB.get_orientation() ENGINE.set_lookup_table_orientation( orientation, update_gsettings=False) page_size = 6 select_keys_csv = TABSQLITEDB.ime_properties.get('select_keys') # select_keys_csv is something like: "1,2,3,4,5,6,7,8,9,0" if select_keys_csv: page_size = len(select_keys_csv.split(",")) ENGINE.set_page_size( page_size, update_gsettings=False) onechar = False ENGINE.set_onechar_mode( onechar, update_gsettings=False) dynamic_adjust = False dynamic_adjust = TABSQLITEDB.ime_properties.get('dynamic_adjust') if dynamic_adjust: dynamic_adjust = (dynamic_adjust.lower() == 'true') else: dynamic_adjust = True ENGINE.set_dynamic_adjust( dynamic_adjust, update_gsettings=False) auto_select_mode = False auto_select = TABSQLITEDB.ime_properties.get('auto_select') if auto_select: auto_select_mode = (auto_select.lower() == 'true') ENGINE.set_autoselect_mode( auto_select_mode, update_gsettings=False) auto_commit_mode = False auto_commit = TABSQLITEDB.ime_properties.get('auto_commit') if auto_commit: auto_commit_mode = (auto_commit.lower() == 'true') ENGINE.set_autocommit_mode( auto_commit_mode, update_gsettings=False) commit_invalid_mode = 0 ENGINE.set_commit_invalid_mode( commit_invalid_mode, update_gsettings=False) page_down_keys_csv = TABSQLITEDB.ime_properties.get( 'page_down_keys') if page_down_keys_csv: page_down_keys = [ IBus.keyval_from_name(x) for x in page_down_keys_csv.split(',')] commit_keys_csv = TABSQLITEDB.ime_properties.get('commit_keys') if commit_keys_csv: commit_keys = [ IBus.keyval_from_name(x) for x in commit_keys_csv.split(',')] auto_wildcard_mode = True auto_wildcard = TABSQLITEDB.ime_properties.get('auto_wildcard') if auto_wildcard: auto_wildcard_mode = (auto_wildcard.lower() == 'true') ENGINE.set_autowildcard_mode( auto_wildcard_mode, update_gsettings=False) single_wildcard_char = TABSQLITEDB.ime_properties.get( 'single_wildcard_char') if not single_wildcard_char: single_wildcard_char = '' if len(single_wildcard_char) > 1: single_wildcard_char = single_wildcard_char[0] ENGINE.set_single_wildcard_char( single_wildcard_char, update_gsettings=False) multi_wildcard_char = TABSQLITEDB.ime_properties.get( 'multi_wildcard_char') if not multi_wildcard_char: multi_wildcard_char = '' if len(multi_wildcard_char) > 1: multi_wildcard_char = multi_wildcard_char[0] ENGINE.set_multi_wildcard_char( multi_wildcard_char, update_gsettings=False) ENGINE.set_pinyin_mode(False) ENGINE.set_suggestion_mode(False) page_up_keys_csv = TABSQLITEDB.ime_properties.get( 'page_up_keys') if page_up_keys_csv: page_up_keys = [ IBus.keyval_from_name(x) for x in page_up_keys_csv.split(',')] ENGINE._commit_key_names = [ IBus.keyval_name(keyval) for keyval in commit_keys] ENGINE._page_down_key_names = [ IBus.keyval_name(keyval) for keyval in page_down_keys] ENGINE._page_up_key_names = [ IBus.keyval_name(keyval) for keyval in page_up_keys] user_keybindings={} ENGINE.set_keybindings(user_keybindings, update_gsettings=False) # Get more verbose output in the test log: ENGINE.set_debug_level(255) def set_up(engine_name: str) -> bool: ''' Setup an ibus table engine :param engine_name: The name of the engine to setup :return: True if the engine could be setup successfully, False if not. ''' global ENGINE_PATCHER global ENGINE_SIMPLE_PATCHER global LOOKUP_TABLE_PATCHER global PROPERTY_PATCHER global PROP_LIST_PATCHER global IBUS_ENGINE global IBUS_ENGINE_SIMPLE global IBUS_LOOKUP_TABLE global IBUS_PROPERTY global IBUS_PROP_LIST global TABSQLITEDB global ENGINE ENGINE_PATCHER.start() ENGINE_SIMPLE_PATCHER.start() LOOKUP_TABLE_PATCHER.start() PROPERTY_PATCHER.start() PROP_LIST_PATCHER.start() assert IBus.Engine is not IBUS_ENGINE assert IBus.Engine is MockEngine assert IBus.EngineSimple is not IBUS_ENGINE_SIMPLE assert IBus.EngineSimple is MockEngine assert IBus.LookupTable is not IBUS_LOOKUP_TABLE assert IBus.LookupTable is MockLookupTable assert IBus.Property is not IBUS_PROPERTY assert IBus.Property is MockProperty assert IBus.PropList is not IBUS_PROP_LIST assert IBus.PropList is MockPropList # Reload the table module so that the patches # are applied to TabEngine: sys.path.insert(0, '../engine') importlib.reload(table) sys.path.pop(0) bus = IBus.Bus() db_dir = '/usr/share/ibus-table/tables' db_file = os.path.join(db_dir, engine_name + '.db') if not os.path.isfile(db_file): TABSQLITEDB = None ENGINE = None tear_down() return False TABSQLITEDB = tabsqlitedb.TabSqliteDb( filename=db_file, user_db=':memory:', unit_test=True) ENGINE = table.TabEngine( bus, '/com/redhat/IBus/engines/table/%s/engine/0' %engine_name, TABSQLITEDB, unit_test=True) backup_original_settings() set_default_settings() return True def tear_down() -> None: global ENGINE_PATCHER global ENGINE_SIMPLE_PATCHER global LOOKUP_TABLE_PATCHER global PROPERTY_PATCHER global PROP_LIST_PATCHER global IBUS_ENGINE global IBUS_LOOKUP_TABLE global IBUS_PROPERTY global IBUS_PROP_LIST global TABSQLITEDB global ENGINE if ENGINE: restore_original_settings() TABSQLITEDB = None ENGINE = None # Remove the patches from the IBus stuff: ENGINE_PATCHER.stop() ENGINE_SIMPLE_PATCHER.stop() LOOKUP_TABLE_PATCHER.stop() PROPERTY_PATCHER.stop() PROP_LIST_PATCHER.stop() assert IBus.Engine is IBUS_ENGINE assert IBus.Engine is not MockEngine assert IBus.EngineSimple is IBUS_ENGINE_SIMPLE assert IBus.EngineSimple is not MockEngine assert IBus.LookupTable is IBUS_LOOKUP_TABLE assert IBus.LookupTable is not MockLookupTable assert IBus.Property is IBUS_PROPERTY assert IBus.Property is not MockProperty assert IBus.PropList is IBUS_PROP_LIST assert IBus.PropList is not MockPropList def require_serial_number(required_serial_number: int) -> bool: if TABSQLITEDB is None: return False serial_number = int(TABSQLITEDB.ime_properties.get('serial_number')) return serial_number >= required_serial_number class ErbiQsTestCase(unittest.TestCase): def setUp(self) -> None: engine_name = 'erbi-qs' if not set_up(engine_name): self.skipTest('Could not setup “%s”, skipping test.' % engine_name) def tearDown(self) -> None: tear_down() def test_dummy(self) -> None: self.assertEqual(True, True) def test_get_goucima(self) -> None: if not require_serial_number(20220111): self.skipTest('serial_number too small') assert(TABSQLITEDB is not None) self.assertEqual( 'sxr.', TABSQLITEDB.get_goucima('松')) self.assertEqual( 'thr', TABSQLITEDB.get_goucima('天')) self.assertEqual( 'xjv', TABSQLITEDB.get_goucima('下')) self.assertEqual( 'dkv', TABSQLITEDB.get_goucima('大')) self.assertEqual( 'sjnb', TABSQLITEDB.get_goucima('事')) def test_parse_phrase(self) -> None: if not require_serial_number(20220111): self.skipTest('serial_number too small') assert(TABSQLITEDB is not None) self.assertEqual( 'txds', TABSQLITEDB.parse_phrase('天下大事')) class WubiJidian86TestCase(unittest.TestCase): def setUp(self) -> None: engine_name = 'wubi-jidian86' if not set_up(engine_name): self.skipTest('Could not setup “%s”, skipping test.' % engine_name) def tearDown(self) -> None: tear_down() def test_dummy(self) -> None: self.assertEqual(True, True) def test_parse_phrase(self) -> None: assert(TABSQLITEDB is not None) self.assertEqual( 'ggdg', TABSQLITEDB.parse_phrase('天下大事')) def test_single_char_commit_with_space(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, '工') def test_toggle_suggestion_mode_with_keybinding(self) -> None: assert(ENGINE is not None) if not ENGINE._ime_sg: self.skipTest("This engine does not have a suggestion mode.") self.assertEqual(ENGINE.get_suggestion_mode(), False) ENGINE._do_process_key_event( IBus.KEY_F6, 0, IBus.ModifierType.SUPER_MASK | IBus.ModifierType.MOD4_MASK) self.assertEqual(ENGINE.get_suggestion_mode(), True) ENGINE._do_process_key_event( IBus.KEY_F6, 0, IBus.ModifierType.SUPER_MASK | IBus.ModifierType.MOD4_MASK) self.assertEqual(ENGINE.get_suggestion_mode(), False) def test_toggle_input_mode_with_keybinding(self) -> None: assert(ENGINE is not None) self.assertEqual(ENGINE.get_input_mode(), 1) ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) # This should have successfully switched, although there was # only a key release, no key press. Matching on modifiers keys # like Shift_L matches only on key release and checks whether # the previous key pressed was exactly the same key (To avoid # matching on something like “Shift_L” + “a”). But when this # is very first key event after the startup of ibus-table, the # previous key is still empty. The it_util.HotKey class then # assumes that the previous key was the same automatically. self.assertEqual(ENGINE.get_input_mode(), 0) ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Control_L, 0, IBus.ModifierType.CONTROL_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) # This should have failed to switch because the key before the # release of “Shift_L” was not a “Shift_L” key. self.assertEqual(ENGINE.get_input_mode(), 0) ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) # This switch should succeed because the previous key was # also a “Shift_L” (also a key release, but this doesn’t matter # I don’t check for this case as it cannot happen in reality). self.assertEqual(ENGINE.get_input_mode(), 1) def test_switch_to_next_chinese_mode_with_keybinding(self) -> None: assert(ENGINE is not None) self.assertEqual(ENGINE.get_chinese_mode(), 2) # Now change with the keybinding: ENGINE._do_process_key_event(IBus.KEY_semicolon, 0, IBus.ModifierType.CONTROL_MASK) self.assertEqual(ENGINE.get_chinese_mode(), 3) def test_toggle_onechar_mode_with_keybinding(self) -> None: assert(ENGINE is not None) self.assertEqual(ENGINE.get_onechar_mode(), False) ENGINE.set_onechar_mode(True, update_gsettings=False) self.assertEqual(ENGINE.get_onechar_mode(), True) ENGINE.set_onechar_mode(False, update_gsettings=False) self.assertEqual(ENGINE.get_onechar_mode(), False) # Now change with the keybinding: ENGINE._do_process_key_event( IBus.KEY_comma, 0, IBus.ModifierType.CONTROL_MASK) self.assertEqual(ENGINE.get_onechar_mode(), True) # Using the keybinding updates gsettings, # wait until the update is effective: time.sleep(1) self.assertEqual(ENGINE.get_onechar_mode(), True) ENGINE._do_process_key_event( IBus.KEY_comma, 0, IBus.ModifierType.CONTROL_MASK) self.assertEqual(ENGINE.get_onechar_mode(), False) # Using the keybinding updates gsettings, # wait until the update is effective: time.sleep(1) self.assertEqual(ENGINE.get_onechar_mode(), False) def test_toggle_autocommit_mode_with_keybinding(self) -> None: assert(ENGINE is not None) self.assertEqual(ENGINE.get_autocommit_mode(), False) ENGINE.set_autocommit_mode(True, update_gsettings=False) self.assertEqual(ENGINE.get_autocommit_mode(), True) ENGINE.set_autocommit_mode(False, update_gsettings=False) self.assertEqual(ENGINE.get_autocommit_mode(), False) # Now change with the keybinding: ENGINE._do_process_key_event( IBus.KEY_slash, 0, IBus.ModifierType.CONTROL_MASK) self.assertEqual(ENGINE.get_autocommit_mode(), True) # Using the keybinding updates gsettings, # wait until the update is effective: time.sleep(1) self.assertEqual(ENGINE.get_autocommit_mode(), True) ENGINE._do_process_key_event( IBus.KEY_slash, 0, IBus.ModifierType.CONTROL_MASK) self.assertEqual(ENGINE.get_autocommit_mode(), False) # Using the keybinding updates gsettings, # wait until the update is effective: time.sleep(1) self.assertEqual(ENGINE.get_autocommit_mode(), False) def test_change_letter_width(self) -> None: assert(ENGINE is not None) # The defaults come from the wubi-jidian86.txt source: # DEF_FULL_WIDTH_LETTER = FALSE self.assertEqual(ENGINE.get_letter_width(), [False, False]) ENGINE.set_letter_width(mode=True, input_mode=0, update_gsettings=False) self.assertEqual(ENGINE.get_letter_width(), [True, False]) ENGINE.set_letter_width(mode=True, input_mode=1, update_gsettings=False) self.assertEqual(ENGINE.get_letter_width(), [True, True]) # Restore the default: ENGINE.set_letter_width(mode=False, input_mode=0, update_gsettings=False) ENGINE.set_letter_width(mode=False, input_mode=1, update_gsettings=False) self.assertEqual(ENGINE.get_letter_width(), [False, False]) # Now change it for input mode 1 with the default keybinding: self.assertEqual(ENGINE.get_input_mode(), 1) ENGINE._do_process_key_event(IBus.KEY_space, 0, IBus.ModifierType.SHIFT_MASK) self.assertEqual(ENGINE.get_letter_width(), [False, True]) # Restore it for input mode 1 with the default keybinding: ENGINE._do_process_key_event(IBus.KEY_space, 0, IBus.ModifierType.SHIFT_MASK) self.assertEqual(ENGINE.get_letter_width(), [False, False]) # Now change it for input mode 0 with the default keybinding: ENGINE.set_input_mode(0) self.assertEqual(ENGINE.get_input_mode(), 0) ENGINE._do_process_key_event(IBus.KEY_space, 0, IBus.ModifierType.SHIFT_MASK) self.assertEqual(ENGINE.get_letter_width(), [True, False]) # Restore it for input mode 0 with the default keybinding: ENGINE._do_process_key_event(IBus.KEY_space, 0, IBus.ModifierType.SHIFT_MASK) self.assertEqual(ENGINE.get_letter_width(), [False, False]) def test_change_punctuation_width(self) -> None: assert(ENGINE is not None) # The defaults come from the wubi-jidian86.txt source: # DEF_FULL_WIDTH_PUNCT = TRUE self.assertEqual(ENGINE.get_punctuation_width(), [False, True]) ENGINE.set_punctuation_width(mode=True, input_mode=0, update_gsettings=False) self.assertEqual(ENGINE.get_punctuation_width(), [True, True]) ENGINE.set_punctuation_width(mode=False, input_mode=1, update_gsettings=False) self.assertEqual(ENGINE.get_punctuation_width(), [True, False]) # Restore the default: ENGINE.set_punctuation_width(mode=False, input_mode=0, update_gsettings=False) ENGINE.set_punctuation_width(mode=False, input_mode=1, update_gsettings=False) self.assertEqual(ENGINE.get_punctuation_width(), [False, False]) # Now change it for input mode 1 with the default keybinding: self.assertEqual(ENGINE.get_input_mode(), 1) ENGINE._do_process_key_event(IBus.KEY_period, 0, IBus.ModifierType.CONTROL_MASK) self.assertEqual(ENGINE.get_punctuation_width(), [False, True]) # Restore it for input mode 1 with the default keybinding: ENGINE._do_process_key_event(IBus.KEY_period, 0, IBus.ModifierType.CONTROL_MASK) self.assertEqual(ENGINE.get_punctuation_width(), [False, False]) # Now change it for input mode 0 with the default keybinding: ENGINE.set_input_mode(0) self.assertEqual(ENGINE.get_input_mode(), 0) ENGINE._do_process_key_event(IBus.KEY_period, 0, IBus.ModifierType.CONTROL_MASK) self.assertEqual(ENGINE.get_punctuation_width(), [True, False]) # Restore it for input mode 0 with the default keybinding: ENGINE._do_process_key_event(IBus.KEY_period, 0, IBus.ModifierType.CONTROL_MASK) self.assertEqual(ENGINE.get_punctuation_width(), [False, False]) def test_next_and_previous_candidates_in_page(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) print(ENGINE._lookup_table.mock_candidates) self.assertEqual(ENGINE._lookup_table.mock_candidates, ['工 99454797 0', '区 qi 1730000000 0', '或 kg 1250000000 0', '或 kgd 1250000000 0', '其 dw 1150000000 0', '其 dwu 1150000000 0', '其他 dwb 685000000 0', '世界 nlw 684000000 0', '花 wx 598000000 0', '花 wxb 598000000 0']) self.assertEqual(ENGINE.mock_preedit_text, '工') self.assertEqual(ENGINE.mock_committed_text, '') # Go one candidate down in the candidate list: ENGINE._do_process_key_event( IBus.KEY_Alt_L, 0, IBus.ModifierType.MOD1_MASK) ENGINE._do_process_key_event( IBus.KEY_Alt_L, 0, IBus.ModifierType.MOD1_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '区') self.assertEqual(ENGINE.mock_committed_text, '') # Go one candidate up in the candidate list: ENGINE._do_process_key_event( IBus.KEY_Alt_L, 0, IBus.ModifierType.MOD1_MASK | IBus.ModifierType.CONTROL_MASK) ENGINE._do_process_key_event( IBus.KEY_Alt_L, 0, IBus.ModifierType.MOD1_MASK | IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '工') self.assertEqual(ENGINE.mock_committed_text, '') # Go three candidates up in the candidate list # (should wrap around in the current page): # # 1 ENGINE._do_process_key_event( IBus.KEY_Alt_L, 0, IBus.ModifierType.MOD1_MASK | IBus.ModifierType.CONTROL_MASK) ENGINE._do_process_key_event( IBus.KEY_Alt_L, 0, IBus.ModifierType.MOD1_MASK | IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.RELEASE_MASK) # 2 ENGINE._do_process_key_event( IBus.KEY_Alt_L, 0, IBus.ModifierType.MOD1_MASK | IBus.ModifierType.CONTROL_MASK) ENGINE._do_process_key_event( IBus.KEY_Alt_L, 0, IBus.ModifierType.MOD1_MASK | IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.RELEASE_MASK) # 3 ENGINE._do_process_key_event( IBus.KEY_Alt_L, 0, IBus.ModifierType.MOD1_MASK | IBus.ModifierType.CONTROL_MASK) ENGINE._do_process_key_event( IBus.KEY_Alt_L, 0, IBus.ModifierType.MOD1_MASK | IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '世界') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '世界') def test_cancel_key_binding_changed(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工') self.assertEqual(ENGINE.mock_committed_text, '') # This 'Insert' does not 'cancel' because the default key for # 'cancel' is 'Escape': ENGINE._do_process_key_event(IBus.KEY_Insert, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, '工') # Changing the key binding for 'cancel': ENGINE.set_keybindings({ 'cancel': ['Insert'], }, update_gsettings=False) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工') self.assertEqual(ENGINE.mock_committed_text, '工') # Now this 'Insert' should cancel, i.e. empty the preedit: ENGINE._do_process_key_event(IBus.KEY_Insert, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工') # And as the preedit is empty now, there is nothing to commit # and the 'space' key just adds a space: ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, '工 ') def test_pinyin_mode(self) -> None: assert(ENGINE is not None) # Pinyin mode is False by default: self.assertEqual(ENGINE.get_pinyin_mode(), False) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工') ENGINE.set_pinyin_mode(True) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '啊') self.assertEqual(ENGINE._lookup_table.mock_candidates, ['啊 ↑5 kbsk 464000000 0', '阿 ↑1 bskg 319000000 0', '阿 ↑3 bskg 319000000 0', '阿 ↑4 bskg 319000000 0', '阿 ↑5 bskg 319000000 0', '吖 ↑1 kuhh 9910000 0', '腌 ↑1 edjn 4100000 0', '锕 ↑1 qbsk 1690000 0', '嗄 ↑2 kdht 1510000 0', '錒 ↑1 qbsk 503000 0']) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工啊') ENGINE.set_pinyin_mode(False) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工啊工') def test_pinyin_mode_chinese_mode(self) -> None: assert(ENGINE is not None) # Pinyin mode is False by default: self.assertEqual(ENGINE.get_pinyin_mode(), False) ENGINE.set_pinyin_mode(True) ENGINE.set_chinese_mode(0) # simplified only ENGINE._do_process_key_event(IBus.KEY_m, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_numbersign, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '吗') self.assertEqual(ENGINE._lookup_table.mock_candidates, ['吗 kcg 959000000 0', '码 dcg 274000000 0', '马 cnng 236000000 0', '玛 gcg 51300000 0', '蚂 jcg 3110000 0', '杩 scg 1280000 0', '犸 qtcg 120000 0', '鰢 qocy 36500 0', '鷌 wvgc 25500 0', '㐷 wcg 9070 0']) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '吗') ENGINE.set_chinese_mode(1) # traditional only ENGINE._do_process_key_event(IBus.KEY_m, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_numbersign, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '嗎') self.assertEqual(ENGINE._lookup_table.mock_candidates, ['嗎 kcy 148000000 0', '馬 cghy 99400000 0', '碼 dcy 38600000 0', '瑪 gcy 15900000 0', '鎷 qcy 1650000 0', '螞 jcy 662000 0', '榪 scy 142000 0', '獁 qtcy 41200 0', '溤 icy 38700 0', '鰢 qocy 36500 0']) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '吗嗎') ENGINE.set_chinese_mode(2) # simplified first ENGINE._do_process_key_event(IBus.KEY_m, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_numbersign, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '吗') self.assertEqual(ENGINE._lookup_table.mock_candidates, ['吗 kcg 959000000 0', '码 dcg 274000000 0', '马 cnng 236000000 0', '玛 gcg 51300000 0', '蚂 jcg 3110000 0', '杩 scg 1280000 0', '犸 qtcg 120000 0', '鰢 qocy 36500 0', '鷌 wvgc 25500 0', '㐷 wcg 9070 0']) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '吗嗎吗') ENGINE.set_chinese_mode(3) # traditional first ENGINE._do_process_key_event(IBus.KEY_m, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_numbersign, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '嗎') self.assertEqual(ENGINE._lookup_table.mock_candidates, ['嗎 kcy 148000000 0', '馬 cghy 99400000 0', '碼 dcy 38600000 0', '瑪 gcy 15900000 0', '鎷 qcy 1650000 0', '螞 jcy 662000 0', '榪 scy 142000 0', '獁 qtcy 41200 0', '溤 icy 38700 0', '鰢 qocy 36500 0']) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '吗嗎吗嗎') ENGINE.set_chinese_mode(4) # all characters ENGINE._do_process_key_event(IBus.KEY_m, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_numbersign, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '吗') self.assertEqual(ENGINE._lookup_table.mock_candidates, ['吗 kcg 959000000 0', '码 dcg 274000000 0', '马 cnng 236000000 0', '嗎 kcy 148000000 0', '馬 cghy 99400000 0', '玛 gcg 51300000 0', '碼 dcy 38600000 0', '瑪 gcy 15900000 0', '蚂 jcg 3110000 0', '鎷 qcy 1650000 0']) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '吗嗎吗嗎吗') def test_suggestion_mode(self) -> None: assert(ENGINE is not None) if not ENGINE._ime_sg: self.skipTest("This engine does not have a suggestion mode.") # Suggestion mode is False by default: self.assertEqual(ENGINE.get_suggestion_mode(), False) self.assertEqual(ENGINE.get_pinyin_mode(), False) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工') self.assertEqual(ENGINE._lookup_table.mock_candidates, []) ENGINE.set_suggestion_mode(True) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工工') self.assertEqual(ENGINE._lookup_table.mock_candidates, ['工作人员 673 0', '工作会议 310 0', '工作报告 267 0', '工人阶级 146 0', '工作重点 78 0', '工作小组 73 0', '工业企业 71 0', '工业大学 69 0', '工作单位 61 0', '工业生产 58 0']) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工工作人员') ENGINE.set_pinyin_mode(True) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '啊') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工工作人员啊') self.assertEqual(ENGINE._lookup_table.mock_candidates, ['啊呀 145 0', '啊哈 103 0', '啊哟 23 0', '啊唷 7 0']) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工工作人员啊呀') ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '爱') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工工作人员啊呀爱') self.assertEqual(ENGINE._lookup_table.mock_candidates, ['爱因斯坦 1109 0', '爱情故事 519 0', '爱国主义 191 0', '爱尔兰语 91 0', '爱好和平 62 0', '爱情小说 58 0', '爱不释手 39 0', '爱国热情 35 0', '爱莫能助 34 0', '爱理不理 32 0']) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工工作人员啊呀爱因斯坦') def test_commit_to_preedit_switching_to_pinyin_defining_a_phrase(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) # commit to preëdit needs a press and release of either # the left or the right shift key: ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '工') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_b, 0, 0) ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '工了') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_c, 0, 0) ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '工了以') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_d, 0, 0) ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '工了以在') self.assertEqual(ENGINE.mock_committed_text, '') # Move left two characters in the preëdit: ENGINE._do_process_key_event(IBus.KEY_Left, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Left, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工了以在') self.assertEqual(ENGINE.mock_committed_text, '') self.assertEqual(ENGINE._chars_valid, '') self.assertEqual(ENGINE._chars_invalid, '') # Switch to pinyin mode by pressing and releasing the right # shift key: ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.get_pinyin_mode(), True) self.assertEqual(ENGINE.mock_preedit_text, '工了以在') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_n, 0, 0) ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) ENGINE._do_process_key_event(IBus.KEY_numbersign, 0, 0) self.assertEqual(ENGINE.mock_committed_text, '') self.assertEqual(ENGINE.mock_preedit_text, '工了你以在') ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '工了你以在') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_h, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_o, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工了你好以在') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_numbersign, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工了你好以在') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '工了你好以在') self.assertEqual(ENGINE.mock_committed_text, '') # Move right two characters in the preëdit # (triggers a commit to preëdit): ENGINE._do_process_key_event(IBus.KEY_Right, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Right, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工了你好以在') self.assertEqual(ENGINE.mock_committed_text, '') self.assertEqual(ENGINE.mock_auxiliary_text, 'd dhf dhfd\t#: abwd') # commit the preëdit: ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '工了你好以在') # Switch out of pinyin mode: ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.get_pinyin_mode(), False) # “abwd” shown on the right of the auxiliary text above shows the # newly defined shortcut for this phrase. Let’s try to type # the same phrase again using the new shortcut: ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工') ENGINE._do_process_key_event(IBus.KEY_b, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '节') ENGINE._do_process_key_event(IBus.KEY_w, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工了你好以在') ENGINE._do_process_key_event(IBus.KEY_d, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工了你好以在') # commit the preëdit: ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, '工了你好以在工了你好以在') def test_switch_to_direct_mode_and_commit_english(self) -> None: ''' When in Chinese mode and the preedit is not empty, switching to direct mode should be possible and it should not discard the input but commit as English. See: https://github.com/kaio/ibus-table/issues/68 ''' assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '工') self.assertEqual(ENGINE.mock_committed_text, '') # Shift_L is the default key binding to switch to direct mode ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_L, 0, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'a') def test_switch_between_table_and_pinyin_mode(self) -> None: ''' The switch between table and pinyin mode should happen immediately even if the preedit is not empty ''' assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '东') self.assertEqual(ENGINE.mock_committed_text, '') # Shift_R is the default key binding to switch between table # and pinyin mode ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '爱') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.SHIFT_MASK) ENGINE._do_process_key_event( IBus.KEY_Shift_R, 0, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) self.assertEqual(ENGINE.mock_preedit_text, '东') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, '东') def test_chinese_mode(self) -> None: assert(ENGINE is not None) ENGINE.set_chinese_mode( mode=0, update_gsettings=False) # show simplified Chinese only ENGINE._do_process_key_event(IBus.KEY_c, 0, 0) ENGINE._do_process_key_event(IBus.KEY_g, 0, 0) self.assertEqual(['对不起 fh 44400000 0', '能不能 ce 21400000 0', '又不是 jg 19000000 0', '马来西亚 sg 14100000 0', '参与者 ft 6390000 0', '骊 m 5420000 0', '骊 my 5420000 0', '邓丽君 vt 4160000 0', '对不对 cf 2720000 0', '对不住 wy 2110000 0'], ENGINE._lookup_table.mock_candidates,) ENGINE._do_process_key_event(IBus.KEY_BackSpace, 0, 0) ENGINE._do_process_key_event(IBus.KEY_BackSpace, 0, 0) self.assertEqual(ENGINE._lookup_table.mock_candidates, []) ENGINE.set_chinese_mode( mode=1, update_gsettings=False) # show traditional Chinese only ENGINE._do_process_key_event(IBus.KEY_c, 0, 0) ENGINE._do_process_key_event(IBus.KEY_g, 0, 0) self.assertEqual(['驪 0 0', '馬 gy 99400000 0', '馬 hy 99400000 0', '对不起 fh 44400000 0', '能不能 ce 21400000 0', '又不是 jg 19000000 0', '对不对 cf 2720000 0', '对不住 wy 2110000 0', '难不成 dn 1990000 0', '巴不得 tj 1420000 0'], ENGINE._lookup_table.mock_candidates) ENGINE._do_process_key_event(IBus.KEY_BackSpace, 0, 0) ENGINE._do_process_key_event(IBus.KEY_BackSpace, 0, 0) self.assertEqual(ENGINE._lookup_table.mock_candidates, []) ENGINE.set_chinese_mode( mode=2, update_gsettings=False) # show simplified Chinese first ENGINE._do_process_key_event(IBus.KEY_c, 0, 0) ENGINE._do_process_key_event(IBus.KEY_g, 0, 0) self.assertEqual(['驪 0 0', '对不起 fh 44400000 0', '能不能 ce 21400000 0', '又不是 jg 19000000 0', '马来西亚 sg 14100000 0', '参与者 ft 6390000 0', '骊 m 5420000 0', '骊 my 5420000 0', '邓丽君 vt 4160000 0', '对不对 cf 2720000 0'], ENGINE._lookup_table.mock_candidates) ENGINE._do_process_key_event(IBus.KEY_BackSpace, 0, 0) ENGINE._do_process_key_event(IBus.KEY_BackSpace, 0, 0) self.assertEqual(ENGINE._lookup_table.mock_candidates, []) ENGINE.set_chinese_mode( mode=3, update_gsettings=False) # show traditional Chinese first ENGINE._do_process_key_event(IBus.KEY_c, 0, 0) ENGINE._do_process_key_event(IBus.KEY_g, 0, 0) self.assertEqual(['驪 0 0', '馬 gy 99400000 0', '馬 hy 99400000 0', '对不起 fh 44400000 0', '能不能 ce 21400000 0', '又不是 jg 19000000 0', '对不对 cf 2720000 0', '对不住 wy 2110000 0', '难不成 dn 1990000 0', '巴不得 tj 1420000 0'], ENGINE._lookup_table.mock_candidates) ENGINE._do_process_key_event(IBus.KEY_BackSpace, 0, 0) ENGINE._do_process_key_event(IBus.KEY_BackSpace, 0, 0) self.assertEqual(ENGINE._lookup_table.mock_candidates, []) ENGINE.set_chinese_mode( mode=4, update_gsettings=False) # show all characters ENGINE._do_process_key_event(IBus.KEY_c, 0, 0) ENGINE._do_process_key_event(IBus.KEY_g, 0, 0) self.assertEqual(['驪 0 0', '馬 gy 99400000 0', '馬 hy 99400000 0', '对不起 fh 44400000 0', '能不能 ce 21400000 0', '又不是 jg 19000000 0', '马来西亚 sg 14100000 0', '参与者 ft 6390000 0', '骊 m 5420000 0', '骊 my 5420000 0'], ENGINE._lookup_table.mock_candidates) ENGINE._do_process_key_event(IBus.KEY_BackSpace, 0, 0) ENGINE._do_process_key_event(IBus.KEY_BackSpace, 0, 0) self.assertEqual(ENGINE._lookup_table.mock_candidates, []) class Stroke5TestCase(unittest.TestCase): def setUp(self) -> None: engine_name = 'stroke5' if not set_up(engine_name): self.skipTest('Could not setup “%s”, skipping test.' % engine_name) def tearDown(self) -> None: tear_down() def test_dummy(self) -> None: self.assertEqual(True, True) def test_single_char_commit_with_space(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_comma, 0, 0) ENGINE._do_process_key_event(IBus.KEY_slash, 0, 0) ENGINE._do_process_key_event(IBus.KEY_n, 0, 0) ENGINE._do_process_key_event(IBus.KEY_m, 0, 0) ENGINE._do_process_key_event(IBus.KEY_m, 0, 0) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, '的') class TelexTestCase(unittest.TestCase): def setUp(self) -> None: engine_name = 'telex' if not set_up(engine_name): self.skipTest('Could not setup “%s”, skipping test.' % engine_name) def tearDown(self) -> None: tear_down() def test_dummy(self) -> None: self.assertEqual(True, True) def test_telex(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_o, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'o') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'o') ENGINE._do_process_key_event(IBus.KEY_o, 0, 0) ENGINE._do_process_key_event(IBus.KEY_f, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'oò') ENGINE._do_process_key_event(IBus.KEY_o, 0, 0) ENGINE._do_process_key_event(IBus.KEY_o, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'ô') self.assertEqual(ENGINE.mock_committed_text, 'oò') ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'oòô') ENGINE._do_process_key_event(IBus.KEY_o, 0, 0) ENGINE._do_process_key_event(IBus.KEY_o, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'ô') self.assertEqual(ENGINE.mock_committed_text, 'oòô') ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'oòôô') ENGINE._do_process_key_event(IBus.KEY_o, 0, 0) ENGINE._do_process_key_event(IBus.KEY_o, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'ô') self.assertEqual(ENGINE.mock_committed_text, 'oòôô') ENGINE._do_process_key_event(IBus.KEY_j, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'oòôôộ') class TranslitTestCase(unittest.TestCase): def setUp(self) -> None: engine_name ='translit' if not set_up(engine_name): self.skipTest('Could not setup “%s”, skipping test.' % engine_name) def tearDown(self) -> None: tear_down() def test_dummy(self) -> None: self.assertEqual(True, True) def test_sh_multiple_match(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_s, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'с') ENGINE._do_process_key_event(IBus.KEY_h, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'ш') ENGINE._do_process_key_event(IBus.KEY_s, 0, 0) self.assertEqual(ENGINE.mock_committed_text, 'ш') self.assertEqual(ENGINE.mock_preedit_text, 'с') ENGINE._do_process_key_event(IBus.KEY_h, 0, 0) self.assertEqual(ENGINE.mock_committed_text, 'ш') self.assertEqual(ENGINE.mock_preedit_text, 'ш') ENGINE._do_process_key_event(IBus.KEY_h, 0, 0) self.assertEqual(ENGINE.mock_committed_text, 'шщ') self.assertEqual(ENGINE.mock_preedit_text, '') ENGINE._do_process_key_event(IBus.KEY_s, 0, 0) self.assertEqual(ENGINE.mock_committed_text, 'шщ') self.assertEqual(ENGINE.mock_preedit_text, 'с') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, 'шщс ') def test_sh_multiple_match_slavic(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_scaron, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'ш') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_h, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'щ') ENGINE._do_process_key_event(IBus.KEY_scaron, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'ш') self.assertEqual(ENGINE.mock_committed_text, 'щ') ENGINE._do_process_key_event(IBus.KEY_ccaron, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'щщ') class Cangjie5TestCase(unittest.TestCase): def setUp(self) -> None: engine_name = 'cangjie5' if not set_up(engine_name): self.skipTest('Could not setup “%s”, skipping test.' % engine_name) def tearDown(self) -> None: tear_down() def test_dummy(self) -> None: self.assertEqual(True, True) def test_single_char_commit_with_space(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, '日') def test_type_one_char_and_check_auxiliary(self) -> None: if not require_serial_number(20220111): self.skipTest('serial_number too small') assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_d, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '木') self.assertEqual(ENGINE._lookup_table.mock_candidates[6], '林 木 1000 0') ENGINE._do_process_key_event(IBus.KEY_v, 0, 0) ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '機') self.assertEqual(ENGINE.mock_auxiliary_text, '木女戈戈 (1 / 1)') self.assertEqual(ENGINE._lookup_table.mock_candidates, ['機 1000 0']) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, '機') def test_dynamic_adjust(self) -> None: if not require_serial_number(20220111): self.skipTest('serial_number too small') assert(ENGINE is not None) ENGINE.set_dynamic_adjust(False) ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) ENGINE._do_process_key_event(IBus.KEY_r, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) self.assertEqual('感', ENGINE.mock_preedit_text) # Big5 code of 怠 is ABE5 (see # https://www.unicode.org/cgi-bin/GetUnihanData.pl?codepoint=%E6%84%9F) # Big5 code of 感 is B750 (see # https://www.unicode.org/cgi-bin/GetUnihanData.pl?codepoint=%E6%80%A0) # # In the improved cangjie5 table, 感 has higher priority now. self.assertEqual( ['感 1000 0', '怠 900 0'], ENGINE._lookup_table.mock_candidates) ENGINE._do_process_key_event(IBus.KEY_2, 0, 0) self.assertEqual( [], ENGINE._lookup_table.mock_candidates) self.assertEqual('', ENGINE.mock_preedit_text) self.assertEqual('怠', ENGINE.mock_committed_text) # repeat the same input, result should be the same # because dynamic adjust is False: ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) ENGINE._do_process_key_event(IBus.KEY_r, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) self.assertEqual('感', ENGINE.mock_preedit_text) self.assertEqual( ['感 1000 0', '怠 900 0'], ENGINE._lookup_table.mock_candidates) ENGINE._do_process_key_event(IBus.KEY_2, 0, 0) self.assertEqual( [], ENGINE._lookup_table.mock_candidates) self.assertEqual('', ENGINE.mock_preedit_text) self.assertEqual('怠怠', ENGINE.mock_committed_text) # Now set dynamic adjust to True: ENGINE.set_dynamic_adjust(True) # repeat the same input, result should still be the same # because no dynamic adjustment has happened yet: ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) ENGINE._do_process_key_event(IBus.KEY_r, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) self.assertEqual('感', ENGINE.mock_preedit_text) self.assertEqual( ['感 1000 0', '怠 900 0'], ENGINE._lookup_table.mock_candidates) ENGINE._do_process_key_event(IBus.KEY_2, 0, 0) self.assertEqual( [], ENGINE._lookup_table.mock_candidates) self.assertEqual('', ENGINE.mock_preedit_text) self.assertEqual('怠怠怠', ENGINE.mock_committed_text) # Try once again, now 怠 should be preferred because # 怠 has been selected once while dynamic adjustment was used # whereas 感 has not been selected: ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) ENGINE._do_process_key_event(IBus.KEY_r, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) self.assertEqual('怠', ENGINE.mock_preedit_text) self.assertEqual( ['怠 900 1', '感 1000 0'], ENGINE._lookup_table.mock_candidates) ENGINE._do_process_key_event(IBus.KEY_1, 0, 0) self.assertEqual( [], ENGINE._lookup_table.mock_candidates) self.assertEqual('', ENGINE.mock_preedit_text) self.assertEqual('怠怠怠怠', ENGINE.mock_committed_text) # Try once again with dynamic adjust, now 怠 should have # user count 2: ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) ENGINE._do_process_key_event(IBus.KEY_r, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) self.assertEqual('怠', ENGINE.mock_preedit_text) self.assertEqual( ['怠 900 2', '感 1000 0'], ENGINE._lookup_table.mock_candidates) ENGINE._do_process_key_event(IBus.KEY_1, 0, 0) self.assertEqual( [], ENGINE._lookup_table.mock_candidates) self.assertEqual('', ENGINE.mock_preedit_text) self.assertEqual('怠怠怠怠怠', ENGINE.mock_committed_text) # 怠 should have user count 3 now. This should be remembered # in the user data base, i.e. if we switch off dynamic adjust # and later switch it back on, the previous user count should # still be there. # # Switch dynamic adjust off again: ENGINE.set_dynamic_adjust(False) # And try again, now 感 should be preferred again # because of its higher weight in the cangjie5 table and the user counts # displayed should be 0: ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) ENGINE._do_process_key_event(IBus.KEY_r, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) self.assertEqual('感', ENGINE.mock_preedit_text) self.assertEqual( ['感 1000 0', '怠 900 0'], ENGINE._lookup_table.mock_candidates) ENGINE._do_process_key_event(IBus.KEY_2, 0, 0) self.assertEqual( [], ENGINE._lookup_table.mock_candidates) self.assertEqual('', ENGINE.mock_preedit_text) self.assertEqual('怠怠怠怠怠怠', ENGINE.mock_committed_text) # Switch dynamic adjust on again: ENGINE.set_dynamic_adjust(True) # Try once again with dynamic adjust, now 感 should be preferred # again and have user count 3: ENGINE._do_process_key_event(IBus.KEY_i, 0, 0) ENGINE._do_process_key_event(IBus.KEY_r, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) self.assertEqual('怠', ENGINE.mock_preedit_text) self.assertEqual( ['怠 900 3', '感 1000 0'], ENGINE._lookup_table.mock_candidates) ENGINE._do_process_key_event(IBus.KEY_1, 0, 0) self.assertEqual( [], ENGINE._lookup_table.mock_candidates) self.assertEqual('', ENGINE.mock_preedit_text) self.assertEqual('怠怠怠怠怠怠怠', ENGINE.mock_committed_text) class IpaXSampaTestCase(unittest.TestCase): def setUp(self) -> None: engine_name = 'ipa-x-sampa' if not set_up(engine_name): self.skipTest('Could not setup “%s”, skipping test.' % engine_name) def tearDown(self) -> None: tear_down() def test_dummy(self) -> None: self.assertEqual(True, True) def test_single_char_commit_with_space(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_at, 0, 0) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, 'ə ') def test_single_char_commit_with_f3(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_at, 0, 0) self.assertEqual(ENGINE._lookup_table.mock_candidates, ['ə 0 0', 'ɘ \\ 0 0', 'ɚ ` 0 0']) ENGINE._do_process_key_event(IBus.KEY_F3, 0, 0) self.assertEqual(ENGINE.mock_committed_text, 'ɚ') class LatexTestCase(unittest.TestCase): def setUp(self) -> None: engine_name = 'latex' if not set_up(engine_name): self.skipTest('Could not setup “%s”, skipping test.' % engine_name) def tearDown(self) -> None: tear_down() def test_dummy(self) -> None: self.assertEqual(True, True) def test_single_char_commit_with_space(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_l, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) ENGINE._do_process_key_event(IBus.KEY_h, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'α') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'α') def test_single_char_commit_with_space_fraktur(self) -> None: # needs ibus-table-others-1.3.10 which adds # most of Unicode 9.0 block Mathematical Alphanumeric Symbols assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) ENGINE._do_process_key_event(IBus.KEY_m, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_t, 0, 0) ENGINE._do_process_key_event(IBus.KEY_h, 0, 0) ENGINE._do_process_key_event(IBus.KEY_f, 0, 0) ENGINE._do_process_key_event(IBus.KEY_r, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_k, 0, 0) ENGINE._do_process_key_event(IBus.KEY_F, 0, 0) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, '𝔉') def test_commit_invalid_mode(self) -> None: assert(ENGINE is not None) self.assertEqual(ENGINE.get_commit_invalid_mode(), 0) ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_l, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) ENGINE._do_process_key_event(IBus.KEY_h, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'α') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_exclam, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'α!') ENGINE.set_commit_invalid_mode(1, update_gsettings=False) self.assertEqual(ENGINE.get_commit_invalid_mode(), 1) ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_l, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) ENGINE._do_process_key_event(IBus.KEY_h, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'α') self.assertEqual(ENGINE.mock_committed_text, 'α!') ENGINE._do_process_key_event(IBus.KEY_exclam, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'α!\\alpha!') def test_toggle_input_mode_on_off(self) -> None: assert(ENGINE is not None) ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_l, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) ENGINE._do_process_key_event(IBus.KEY_h, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, 'α') self.assertEqual(ENGINE.mock_committed_text, '') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'α') ENGINE._do_process_key_event(IBus.KEY_Shift_L, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Shift_L, 0, IBus.ModifierType.RELEASE_MASK) ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) ENGINE._do_process_key_event(IBus.KEY_l, 0, 0) ENGINE._do_process_key_event(IBus.KEY_p, 0, 0) ENGINE._do_process_key_event(IBus.KEY_h, 0, 0) ENGINE._do_process_key_event(IBus.KEY_a, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'α\\alpha') ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_preedit_text, '') self.assertEqual(ENGINE.mock_committed_text, 'α\\alpha ') def test_single_char_commit_with_f3(self) -> None: assert(ENGINE is not None) # The latex.txt table in ibus-table-others-1.3.12 has # SELECT_KEYS = F1,F2,F3,F4,F5,F6,F7,F8,F9,F10 # the older version in ibus-table-others-1.3.11 # has SELECT_KEYS = F1,F2,F3,F4,F5,F6,F7,F8,F9 # To make this test work for both versions, set the page size to 9: ENGINE.set_page_size(9) ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) ENGINE._do_process_key_event(IBus.KEY_b, 0, 0) # Lookup table shows only the first page, subsequent # pages are added on demand as a speed optimization: self.assertEqual(ENGINE._lookup_table.mock_candidates, ['¯ ar 0 0', '⊥ ot 0 0', 'β eta 0 0', 'ℶ eth 0 0', '⋂ igcap 0 0', '⋃ igcup 0 0', '⋁ igvee 0 0', '⋈ owtie 0 0', '⊡ oxdot 0 0']) ENGINE._do_process_key_event(IBus.KEY_F3, 0, 0) self.assertEqual(ENGINE.mock_committed_text, 'β') ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) ENGINE._do_process_key_event(IBus.KEY_b, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Page_Down, 0, 0) self.assertEqual(ENGINE._lookup_table.mock_candidates, ['β eta 0 1', # user freq for β increased to 1 '¯ ar 0 0', '⊥ ot 0 0', 'ℶ eth 0 0', '⋂ igcap 0 0', '⋃ igcup 0 0', '⋁ igvee 0 0', '⋈ owtie 0 0', '⊡ oxdot 0 0', '• ullet 0 0', '∙ ullet 0 0', '≏ umpeq 0 0', '∽ acksim 0 0', '∵ ecause 0 0', '≬ etween 0 0', '⊞ oxplus 0 0', '⊼ arwedge 0 0', '⋀ igwedge 0 0']) self.assertEqual(ENGINE._lookup_table.get_cursor_pos(), 9) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) self.assertEqual(ENGINE._lookup_table.get_cursor_pos(), 15) self.assertEqual(ENGINE._lookup_table.mock_candidates[0:18], ['β eta 0 1', # user freq for β increased to 1 '¯ ar 0 0', '⊥ ot 0 0', 'ℶ eth 0 0', '⋂ igcap 0 0', '⋃ igcup 0 0', '⋁ igvee 0 0', '⋈ owtie 0 0', '⊡ oxdot 0 0', '• ullet 0 0', '∙ ullet 0 0', '≏ umpeq 0 0', '∽ acksim 0 0', '∵ ecause 0 0', '≬ etween 0 0', '⊞ oxplus 0 0', '⊼ arwedge 0 0', '⋀ igwedge 0 0']) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, 'β⊞') ENGINE._do_process_key_event(IBus.KEY_backslash, 0, 0) ENGINE._do_process_key_event(IBus.KEY_b, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Page_Down, 0, 0) self.assertEqual(ENGINE._lookup_table.mock_candidates, ['β eta 0 1', # user freq for β increased to 1 '⊞ oxplus 0 1', # user freq for ⊞ increased to 1 '¯ ar 0 0', '⊥ ot 0 0', 'ℶ eth 0 0', '⋂ igcap 0 0', '⋃ igcup 0 0', '⋁ igvee 0 0', '⋈ owtie 0 0', '⊡ oxdot 0 0', '• ullet 0 0', '∙ ullet 0 0', '≏ umpeq 0 0', '∽ acksim 0 0', '∵ ecause 0 0', '≬ etween 0 0', '⊼ arwedge 0 0', '⋀ igwedge 0 0']) self.assertEqual(ENGINE._lookup_table.get_cursor_pos(), 9) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) ENGINE._do_process_key_event(IBus.KEY_Down, 0, 0) self.assertEqual(ENGINE._lookup_table.get_cursor_pos(), 15) ENGINE._do_process_key_event(IBus.KEY_space, 0, 0) self.assertEqual(ENGINE.mock_committed_text, 'β⊞≬') if __name__ == '__main__': LOG_HANDLER = logging.StreamHandler(stream=sys.stderr) LOGGER.setLevel(logging.DEBUG) LOGGER.addHandler(LOG_HANDLER) unittest.main() ibus-table-1.17.11/tools/000077500000000000000000000000001475513533100150605ustar00rootroot00000000000000ibus-table-1.17.11/tools/.gitignore000066400000000000000000000000151475513533100170440ustar00rootroot00000000000000__pycache__/ ibus-table-1.17.11/tools/Unihan_Variants.txt000066400000000000000000024434001475513533100207210ustar00rootroot00000000000000# Unihan_Variants.txt # Date: 2024-07-31 00:00:00 GMT [KL] # Unicode Version 16.0.0 # # Unicode Character Database # © 2024 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use and license, see https://www.unicode.org/terms_of_use.html # # For documentation, see https://www.unicode.org/reports/tr38/ # # This file contains data on the following fields from the Unihan database: # kSemanticVariant # kSimplifiedVariant # kSpecializedSemanticVariant # kSpoofingVariant # kTraditionalVariant # kZVariant # U+3400 kSemanticVariant U+4E18 U+3405 kSemanticVariant U+4E94 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 3.0 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from typing import Any import re import logging # Unihan_Variants.txt contains the following 2 lines: # # U+50DE kSimplifiedVariant U+4F2A # U+50DE kTraditionalVariant U+507D U+50DE # # This seems to be currently the only case in Unihan_Variants.txt where # a character which has entries for kTraditionalVariant and # the same character is listed again among the traditional variants # is *not* simplified Chinese. # # U+50DE 僞 is traditional Chinese. # U+507D 偽 is also traditional Chinese. # U+4F2A 伪 is simplified Chinese # # This does not cause a problem with the current parsing code # of Unihan_Variants.txt because the line # # U+50DE kSimplifiedVariant U+4F2A # # is read first and thus the character is already inserted in the # “VARIANTS_TABLE_ORIG” dictionary as traditional Chinese, which is correct. # If a character is already in the dictionary and more lines for the # same character are read from Unihan_Variants.txt, these extra lines # are ignored. # # But maybe for some corner cases more tweaking of the code is # necessary. One can also add overrides manually to the # initial content of “VARIANTS_TABLE_ORIG”. VARIANTS_TABLE_ORIG = { # Meaning of the bits in the values: # 1 = 1 << 0 simplified Chinese # 2 = 1 << 1 traditional Chinese # 3 = (1 | 1 << 1) used both in simplified *and* traditional Chinese # 4 = 1 << 2 mixture of simplified and traditional Chinese # # overrides can be added manually here. For example the following # line marks the 〇 character as used in both # simplified and traditional Chinese: '〇': 3 # simplified *and* traditional Chinese } # keep the lines from Unihan_Variants.txt which were used for debugging VARIANTS_TABLE_ORIG_UNIHAN_VARIANTS_ENTRY_USED = {} def read_unihan_variants(unihan_variants_file) -> None: ''' Read the Unihan_Variants.txt file downloaded from Unicode.org. ''' for line in unihan_variants_file: line = line.strip() if not re.match('^#', line): if re.search('(kTraditionalVariant|kSimplifiedVariant)', line): match = re.match(r'^U\+([0-9A-F]{4,5})', line) if match: char = chr(int(match.group(1), 16)) category = 0 # should never stay at this value if re.match(re.escape(match.group(0)) + r'.*' + re.escape(match.group(0)), line): # is both simplified and traditional category = 1 | 1 << 1 elif re.search('kTraditionalVariant', line): category = 1 # simplified only elif re.search('kSimplifiedVariant', line): category = 1 << 1 # traditional only logging.debug( 'char=%s category=%d line=%s', char, category, line) if char not in VARIANTS_TABLE_ORIG: VARIANTS_TABLE_ORIG[char] = category if (char not in VARIANTS_TABLE_ORIG_UNIHAN_VARIANTS_ENTRY_USED): VARIANTS_TABLE_ORIG_UNIHAN_VARIANTS_ENTRY_USED[ char] = line def detect_chinese_category_old(phrase: str) -> int: ''' Old function using encoding conversion to guess whether a text is simplified Chinese, traditional Chinese, both, or unknown. Does not work well, is included here for reference and for comparing with the results of the new, improved function using the data from the Unihan database. ''' # this is the bitmask we will use, # from low to high, 1st bit is simplified Chinese, # 2nd bit is traditional Chinese, # 3rd bit means out of gbk category = 0 # make sure that we got a unicode string tmp_phrase = ''.join(re.findall('[' + '\u4E00-\u9FCB' + '\u3400-\u4DB5' + '\uF900-\uFaFF' + '\U00020000-\U0002A6D6' + '\U0002A700-\U0002B734' + '\U0002B740-\U0002B81D' + '\U0002F800-\U0002FA1D' + ']+', phrase)) # first whether in gb2312 try: tmp_phrase.encode('gb2312') category |= 1 except: if '〇' in tmp_phrase: # we add '〇' into SC as well category |= 1 # second check big5-hkscs try: tmp_phrase.encode('big5hkscs') category |= 1 << 1 except: # then check whether in gbk, if category & 1: # already know in SC pass else: # need to check try: tmp_phrase.encode('gbk') category |= 1 except: # not in gbk pass # then set for 3rd bit, if not in SC and TC if not category & (1 | 1 << 1): category |= (1 << 2) return category def write_variants_script(script_file) -> None: ''' Write the generated Python script. ''' script_file.write('''# auto-generated by “generate-chinese-variants.py”, do not edit here! # # Copyright (c) 2013 Mike FABIAN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 3.0 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ''') script_file.write(''' VARIANTS_TABLE = { # Meaning of the bits in the values: # 1 = 1 << 0 simplified Chinese # 2 = 1 << 1 traditional Chinese # 3 = (1 | 1 << 1) used both in simplified *and* traditional Chinese # 4 = 1 << 2 mixture of simplified and traditional Chinese ''') for phrase in sorted(VARIANTS_TABLE_ORIG): script_file.write( " '" + phrase + "': " + "%s" %VARIANTS_TABLE_ORIG[phrase] + ",\n") script_file.write(''' } ''') script_file.write(''' def detect_chinese_category(phrase: str) -> int: \'\'\' New function using Unihan data to guess whether a text is simplified Chinese, traditional Chinese, both, or something rare like a mixture of exclusively simplified with exclusively traditional characters. Meaning of the bits in the category value returned by this function: 1 = 1 << 0 simplified Chinese 2 = 1 << 1 traditional Chinese 3 = (1 | 1 << 1) used both in simplified *and* traditional Chinese 4 = 1 << 2 mixture of simplified and traditional Chinese \'\'\' # make sure that we got a unicode string if phrase in VARIANTS_TABLE: # the complete phrase is in VARIANTS_TABLE, just return the # value found: return VARIANTS_TABLE[phrase] category = 0xFF for char in phrase: if char in VARIANTS_TABLE: category &= VARIANTS_TABLE[char] else: # If it is not listed in VARIANTS_TABLE, assume it is # both simplified and traditional Chinese. # It could be something non-Chinese as well then, but # if it is non-Chinese, it should also be allowed to # occur in any Chinese text and thus classified as # both simplified *and* traditional Chinese (the emoji # table for example uses many non-Chinese characters) category &= (1 | 1 << 1) if category == 0: # If category is 0 after binary & of the categories of all the # characters in the phrase, it means that the phrase contained # exclusively simplified *and* exclusively traditional # characters at the same time. For example if the phrase is # “乌烏” then “乌” gets category 1 (simplified Chinese) # and “烏” gets category 2 (traditional Chinese), the result # of the binary & is thus 0. In that case, classify it as # category 4 which is for weird, excentric, rare stuff. If the # user selects one of the modes “all characters but # simplified Chinese first” or “all characters but # traditional Chinese first”, phrases with category 4 will be # shown but filtered to be shown only at the end of the # candidate list. category = 1 << 2 return category ''') TEST_DATA = { # Meaning of the bits in the values: # 1 = 1 << 0 simplified Chinese # 2 = 1 << 1 traditional Chinese # 3 = (1 | 1 << 1) used both in simplified *and* traditional Chinese # 4 = 1 << 2 mixture of simplified and traditional Chinese '乌': 1, '烏': 2, '晞': 3, '䖷': 3, '乌烏': 4, 'a☺α乌': 1, 'a☺α烏': 2, '台': 3, '同': 3, '表': 3, # U+8868 '面': 3, # U+9762 # Characters below this comments probably have buggy entries # in Unihan_Variants.txt: '覆': 3, # U+8986 '杰': 3, # U+6770 '系': 3, # U+7CFB '乾': 3, # U+4E7E '著': 3, # U+8457 Patch by Heiher '只': 3, # U+53EA, see: https://github.com/kaio/ibus-table/issues/74 # Problems reported in https://github.com/ibus/ibus/issues/2323 '着': 3, # U+7740, used in HK '枱': 3, # U+67B1, used in HK (correct already, no SC variant entry in Unihan_Variants.txt) '云': 3, # U+4E91, used in HK and TW '裡': 3, # U+88E1, (Untypable in S) used in all places same meaning as 裏 '復': 3, # U+5FA9, (Untypable in S) used in all places same meaning in S, diff in T '采': 3, # U+91C7, (Untypable in T) used in Hong Kong, not sure about TW # http://dict.revised.moe.edu.tw/cgi-bin/cbdic/gsweb.cgi has 采, i.e. probably # it is used in TW '吓': 3, # U+5413, (Untypable in T) used in Cantonese. '尸': 3, # U+5C38, (Untypable in T) idk where it is used, but Cangjie has that as a radical. '揾': 3, # U+63FE, used in HK # (TW seems to use only 搵, see http://dict.revised.moe.edu.tw/cgi-bin/cbdic/gsweb.cgi) '栗': 3, # U+6817 https://github.com/mike-fabian/ibus-table/issues/95 '了': 3, # U+4E86 https://github.com/mike-fabian/ibus-table/issues/96 '伙': 3, # U+4F19 https://github.com/mike-fabian/ibus-table/issues/96 '借': 3, # U+501F https://github.com/mike-fabian/ibus-table/issues/96 '冬': 3, # U+51AC https://github.com/mike-fabian/ibus-table/issues/96 '千': 3, # U+5343 https://github.com/mike-fabian/ibus-table/issues/96 '卜': 3, # U+535C https://github.com/mike-fabian/ibus-table/issues/96 '卷': 3, # U+5377 https://github.com/mike-fabian/ibus-table/issues/96 '吁': 3, # U+5401 https://github.com/mike-fabian/ibus-table/issues/96 '合': 3, # U+5408 https://github.com/mike-fabian/ibus-table/issues/96 '回': 3, # U+56DE https://github.com/mike-fabian/ibus-table/issues/96 '夥': 3, # U+5925 https://github.com/mike-fabian/ibus-table/issues/96 '姜': 3, # U+59DC https://github.com/mike-fabian/ibus-table/issues/96 '家': 3, # U+5BB6 https://github.com/mike-fabian/ibus-table/issues/96 '才': 3, # U+624D https://github.com/mike-fabian/ibus-table/issues/96 '折': 3, # U+6298 https://github.com/mike-fabian/ibus-table/issues/96 '摺': 3, # U+647A https://github.com/mike-fabian/ibus-table/issues/96 '旋': 3, # U+65CB https://github.com/mike-fabian/ibus-table/issues/96 '朱': 3, # U+6731 https://github.com/mike-fabian/ibus-table/issues/96 '灶': 3, # U+7076 https://github.com/mike-fabian/ibus-table/issues/96 '秋': 3, # U+79CB https://github.com/mike-fabian/ibus-table/issues/96 '蒙': 3, # U+8499 https://github.com/mike-fabian/ibus-table/issues/96 '蔑': 3, # U+8511 https://github.com/mike-fabian/ibus-table/issues/96 '霉': 3, # U+9709 https://github.com/mike-fabian/ibus-table/issues/96 '沄': 3, # U+6C84 https://github.com/mike-fabian/ibus-table/issues/97 # https://dict.revised.moe.edu.tw/search.jsp?md=1&word=%E6%B2%84&qMd=0&qCol=1 '干': 3, # U+5E72 https://github.com/mike-fabian/ibus-table/issues/97 # See https://github.com/mike-fabian/ibus-table/issues/100 especially: # https://github.com/mike-fabian/ibus-table/issues/100#issuecomment-1020358521 # These characters were classified as “Simplified only” but they are in # this dictionary: https://dict.revised.moe.edu.tw/ '时': 3, # U+65F6 https://github.com/mike-fabian/ibus-table/issues/100 '旷': 3, # U+65F7 ... '晒': 3, # U+6652 ... '幂': 3, # U+5E42 ... '胆': 3, # U+80C6 ... '册': 3, # U+518C ... '脚': 3, # U+811A ... '胜': 3, # U+80DC ... '脉': 3, # U+8109 ... '膑': 3, # U+8191 ... '网': 3, # U+7F51 ... '删': 3, # U+5220 ... '腼': 3, # U+817C ... '脍': 3, # U+810D ... '腭': 3, # U+816D ... '腊': 3, # U+814A ... '眦': 3, # U+7726 ... '肮': 3, # U+80AE ... '谷': 3, # U+8C37 ... '兑': 3, # U+5151 ... '单': 3, # U+5355 ... '栅': 3, # U+6805 ... '松': 3, # U+677E ... '梦': 3, # U+68A6 ... '权': 3, # U+6743 ... '楼': 3, # U+697C ... '栀': 3, # U+6800 ... '机': 3, # U+673A ... '栖': 3, # U+6816 ... '杆': 3, # U+6746 ... '标': 3, # U+6807 ... '构': 3, # U+6784 ... '柜': 3, # U+67DC ... '朴': 3, # U+6734 ... '温': 3, # U+6E29 ... '泪': 3, # U+6CEA ... '对': 3, # U+5BF9 ... '双': 3, # U+53CC ... '叠': 3, # U+53E0 ... '滩': 3, # U+6EE9 ... '洼': 3, # U+6D3C ... '没': 3, # U+6CA1 ... '沪': 3, # U+6CAA ... '戏': 3, # U+620F ... '浅': 3, # U+6D45 ... '沪': 3, # U+6CAA ... '滨': 3, # U+6EE8 ... '劝': 3, # U+529D ... '沈': 3, # U+6C88 ... '渊': 3, # U+6E0A ... '洒': 3, # U+6D12 ... '㳽': 3, # U+3CFD ... '欢': 3, # U+6B22 ... '难': 3, # U+96BE ... '涂': 3, # U+6D82 ... '涛': 3, # U+6D9B ... '汹': 3, # U+6C79 ... '滦': 3, # U+6EE6 ... '湾': 3, # U+6E7E ... '滚': 3, # U+6EDA ... '漓': 3, # U+6F13 ... '尝': 3, # U+5C1D ... '党': 3, # U+515A ... '誉': 3, # U+8A89 ... '粮': 3, # U+7CAE ... '糇': 3, # U+7CC7 ... '娄': 3, # U+5A04 ... '炉': 3, # U+7089 ... '烛': 3, # U+70DB ... '灯': 3, # U+706F ... '烩': 3, # U+70E9 ... '当': 3, # U+5F53 ... '烬': 3, # U+70EC ... '数': 3, # U+6570 ... '烟': 3, # U+70DF ... '声': 3, # U+58F0 ... '壳': 3, # U+58F3 ... '块': 3, # U+5757 ... '坂': 3, # U+5742 ... '却': 3, # U+5374 ... '坏': 3, # U+574F ... '坛': 3, # U+575B ... '赶': 3, # U+8D76 ... '趋': 3, # U+8D8B ... '制': 3, # U+5236 ... '秃': 3, # U+79C3 ... '种': 3, # U+79CD ... '秆': 3, # U+79C6 ... '称': 3, # U+79F0 ... '稳': 3, # U+7A33 ... '篓': 3, # U+7BD3 ... '丢': 3, # U+4E22 ... '笔': 3, # U+7B14 ... '躯': 3, # U+8EAF ... '么': 3, # U+4E48 ... '乔': 3, # U+4E54 ... '筑': 3, # U+7B51 ... '惩': 3, # U+60E9 ... '几': 3, # U+51E0 ... '凤': 3, # U+51E4 ... '风': 3, # U+98CE ... '御': 3, # U+5FA1 ... '刮': 3, # U+522E ... '乱': 3, # U+4E71 ... '辞': 3, # U+8F9E ... '笋': 3, # U+7B0B ... '衅': 3, # U+8845 ... '毡': 3, # U+6BE1 ... '鼹': 3, # U+9F39 ... '乐': 3, # U+4E50 ... '箩': 3, # U+7BA9 ... '篱': 3, # U+7BF1 ... '术': 3, # U+672F ... '应': 3, # U+5E94 ... '祢': 3, # U+7962 ... '祷': 3, # U+7977 ... '礼': 3, # U+793C ... '庄': 3, # U+5E84 ... '咸': 3, # U+54B8 ... '庐': 3, # U+5E90 ... '义': 3, # U+4E49 ... '参': 3, # U+53C2 ... '划': 3, # U+5212 ... '庙': 3, # U+5E99 ... '减': 3, # U+51CF ... '冲': 3, # U+51B2 ... '准': 3, # U+51C6 ... '凑': 3, # U+51D1 ... '况': 3, # U+51B5 ... '凉': 3, # U+51C9 ... '户': 3, # U+6237 ... '献': 3, # U+732E ... '穷': 3, # U+7A77 ... '帘': 3, # U+5E18 ... '窃': 3, # U+7A83 ... '灾': 3, # U+707E ... '宝': 3, # U+5B9D ... '宁': 3, # U+5B81 ... '宾': 3, # U+5BBE ... '胡': 3, # U+80E1 ... '克': 3, # U+514B ... '实': 3, # U+5B9E ... '郁': 3, # U+90C1 ... '刹': 3, # U+5239 ... '瘘': 3, # U+7618 ... '犹': 3, # U+72B9 ... '猪': 3, # U+732A ... '独': 3, # U+72EC ... '猕': 3, # U+7315 ... '狯': 3, # U+72EF ... '猫': 3, # U+732B ... '猬': 3, # U+732C ... '夸': 3, # U+5938 ... '疴': 3, # U+75B4 ... '症': 3, # U+75C7 ... '疱': 3, # U+75B1 ... '办': 3, # U+529E ... '刾': 3, # U+523E ... '痒': 3, # U+75D2 ... '袜': 3, # U+889C ... '隶': 3, # U+96B6 ... '袄': 3, # U+8884 ... '蝼': 3, # U+877C ... '蚁': 3, # U+8681 ... '虾': 3, # U+867E ... '虬': 3, # U+866C ... '师': 3, # U+5E08 ... '归': 3, # U+5F52 ... '壮': 3, # U+58EE ... '虫': 3, # U+866B ... '鼗': 3, # U+9F17 ... '儿': 3, # U+513F ... '电': 3, # U+7535 ... '补': 3, # U+8865 ... '厩': 3, # U+53A9 ... '霡': 3, # U+9721 ... '晋': 3, # U+664B ... '于': 3, # U+4E8E ... '珐': 3, # U+73D0 ... '压': 3, # U+538B ... '环': 3, # U+73AF ... '琼': 3, # U+743C ... '厂': 3, # U+5382 ... '动': 3, # U+52A8 ... '蚕': 3, # U+8695 ... '历': 3, # U+5386 ... '无': 3, # U+65E0 ... '厉': 3, # U+5389 ... '厨': 3, # U+53A8 ... '厦': 3, # U+53A6 ... '亏': 3, # U+4E8F ... '殡': 3, # U+6BA1 ... '两': 3, # U+4E24 ... '碍': 3, # U+788D ... '确': 3, # U+786E ... '万': 3, # U+4E07 ... '励': 3, # U+52B1 ... '开': 3, # U+5F00 ... '厮': 3, # U+53AE ... '画': 3, # U+753B ... '厘': 3, # U+5398 ... '堕': 3, # U+5815 ... '弹': 3, # U+5F39 ... '孙': 3, # U+5B59 ... '尔': 3, # U+5C14 ... '丑': 3, # U+4E11 ... '际': 3, # U+9645 ... '隐': 3, # U+9690 ... '随': 3, # U+968F ... '强': 3, # U+5F3A ... '争': 3, # U+4E89 ... '皱': 3, # U+76B1 ... '龟': 3, # U+9F9F ... '复': 3, # U+590D ... '内': 3, # U+5185 ... '佣': 3, # U+4F63 ... '叙': 3, # U+53D9 ... '体': 3, # U+4F53 ... '仅': 3, # U+4EC5 ... '籴': 3, # U+7C74 ... '偻': 3, # U+507B ... '凭': 3, # U+51ED ... '隽': 3, # U+96BD ... '仪': 3, # U+4EEA ... '优': 3, # U+4F18 ... '矫': 3, # U+77EB ... '侠': 3, # U+4FA0 ... '个': 3, # U+4E2A ... '舍': 3, # U+820D ... '会': 3, # U+4F1A ... '气': 3, # U+6C14 ... '从': 3, # U+4ECE ... '伤': 3, # U+4F24 ... '价': 3, # U+4EF7 ... '侩': 3, # U+4FA9 ... '众': 3, # U+4F17 ... '偬': 3, # U+506C ... '俦': 3, # U+4FE6 ... '仆': 3, # U+4EC6 ... '愠': 3, # U+6120 ... '惧': 3, # U+60E7 ... '匀': 3, # U+5300 ... '恒': 3, # U+6052 ... '怀': 3, # U+6000 ... '怜': 3, # U+601C ... '够': 3, # U+591F ... '恼': 3, # U+607C ... '担': 3, # U+62C5 ... '静': 3, # U+9759 ... '摊': 3, # U+644A ... '撑': 3, # U+6491 ... '挡': 3, # U+6321 ... '挂': 3, # U+6302 ... '热': 3, # U+70ED ... '势': 3, # U+52BF ... '蛰': 3, # U+86F0 ... '丰': 3, # U+4E30 ... '艳': 3, # U+8273 ... '摈': 3, # U+6448 ... '寿': 3, # U+5BFF ... '执': 3, # U+6267 ... '抛': 3, # U+629B ... '挟': 3, # U+631F ... '帮': 3, # U+5E2E ... '麦': 3, # U+9EA6 ... '挽': 3, # U+633D ... '携': 3, # U+643A ... '据': 3, # U+636E ... '报': 3, # U+62A5 ... '掷': 3, # U+63B7 ... '摆': 3, # U+6446 ... '扑': 3, # U+6251 ... '喽': 3, # U+55BD ... '响': 3, # U+54CD ... '听': 3, # U+542C ... '咏': 3, # U+548F ... '叶': 3, # U+53F6 ... '咤': 3, # U+54A4 ... '黾': 3, # U+9EFE ... '踪': 3, # U+8E2A ... '吴': 3, # U+5434 ... '蹰': 3, # U+8E70 ... '踊': 3, # U+8E0A ... '号': 3, # U+53F7 ... '嘱': 3, # U+5631 ... '别': 3, # U+522B ... '啰': 3, # U+5570 ... '屡': 3, # U+5C61 ... '属': 3, # U+5C5E ... '职': 3, # U+804C ... '联': 3, # U+8054 ... '耻': 3, # U+803B ... '区': 3, # U+533A ... '届': 3, # U+5C4A ... '昼': 3, # U+663C ... '医': 3, # U+533B ... '尽': 3, # U+5C3D ... '剧': 3, # U+5267 ... '荣': 3, # U+8363 ... '劳': 3, # U+52B3 ... '范': 3, # U+8303 ... '盖': 3, # U+76D6 ... '芦': 3, # U+82A6 ... '蘖': 3, # U+8616 ... '荆': 3, # U+8346 ... '荐': 3, # U+8350 ... '郑': 3, # U+90D1 ... '苏': 3, # U+82CF ... '黄': 3, # U+9EC4 ... '苹': 3, # U+82F9 ... '芸': 3, # U+82B8 ... '莅': 3, # U+8385 ... '葱': 3, # U+8471 ... '并': 3, # U+5E76 ... '荆': 3, # U+8346 ... '萝': 3, # U+841D ... '蔂': 3, # U+8502 ... '岁': 3, # U+5C81 ... '粜': 3, # U+7C9C ... '姗': 3, # U+59D7 ... '断': 3, # U+65AD ... '娇': 3, # U+5A07 ... '姹': 3, # U+59F9 ... '奸': 3, # U+5978 ... '娱': 3, # U+5A31 ... '困': 3, # U+56F0 ... '里': 3, # U+91CC ... '图': 3, # U+56FE ... '罢': 3, # U+7F62 ... '罗': 3, # U+7F57 ... '园': 3, # U+56ED ... '累': 3, # U+7D2F ... '兑': 3, # U+5151 ... '栀': 3, # U+6800 ... '构': 3, # U+6784 ... '双': 3, # U+53CC ... '洒': 3, # U+6D12 ... '滚': 3, # U+6EDA ... '娄': 3, # U+5A04 ... '壳': 3, # U+58F3 ... '术': 3, # U+672F ... '庐': 3, # U+5E90 ... '义': 3, # U+4E49 ... '郁': 3, # U+90C1 ... '刹': 3, # U+5239 ... '疴': 3, # U+75B4 ... '压': 3, # U+538B ... '历': 3, # U+5386 ... '亏': 3, # U+4E8F ... '随': 3, # U+968F ... '内': 3, # U+5185 ... '仪': 3, # U+4EEA ... '气': 3, # U+6C14 ... '掷': 3, # U+63B7 ... '别': 3, # U+522B ... '荣': 3, # U+8363 ... '郑': 3, # U+90D1 ... '并': 3, # U+5E76 ... '萝': 3, # U+841D ... '困': 3, # U+56F0 ... '堕': 3, # U+5815 ... '头': 3, # U+5934 ... '欤': 3, # U+6B24 ... '逊': 3, # U+900A ... '点': 3, # U+70B9 ... '韵': 3, # U+97F5 ... '銮': 3, # U+92AE ... '栾': 3, # U+683E ... '衮': 3, # U+886E ... '蛮': 3, # U+86EE ... '弯': 3, # U+5F2F ... '孪': 3, # U+5B6A ... '递': 3, # U+9012 ... '脔': 3, # U+8114 ... '恋': 3, # U+604B ... '挛': 3, # U+631B ... '峦': 3, # U+5CE6 ... '娈': 3, # U+5A08 ... '过': 3, # U+8FC7 ... '广': 3, # U+5E7F ... '选': 3, # U+9009 ... '彦': 3, # U+5F66 ... '迁': 3, # U+8FC1 ... '适': 3, # U+9002 ... '弃': 3, # U+5F03 ... '斗': 3, # U+6597 ... '头': 3, # U+5934 ... '刘': 3, # U+5218 ... '斋': 3, # U+658B ... '边': 3, # U+8FB9 ... '还': 3, # U+8FD8 ... '远': 3, # U+8FDC ... '欤': 3, # U+6B24 ... '逊': 3, # U+900A ... '迩': 3, # U+8FE9 ... '点': 3, # U+70B9 ... '战': 3, # U+6218 ... '逻': 3, # U+903B ... '禀': 3, # U+7980 ... '这': 3, # U+8FD9 ... '迹': 3, # U+8FF9 Last of https://github.com/mike-fabian/ibus-table/issues/100 } def test_detection(generated_script) -> int: ''' Test whether the generated script does the detection correctly. Returns the number of errors found. ''' logging.info('Testing detection ...') error_count = 0 for phrase in TEST_DATA: if (generated_script.detect_chinese_category(phrase) != TEST_DATA[phrase]): print('phrase', phrase, repr(phrase), 'detected as', generated_script.detect_chinese_category(phrase), 'should have been', TEST_DATA[phrase], 'FAIL.') error_count += 1 else: logging.info('phrase=%s %s detected as %d PASS.', phrase, repr(phrase), TEST_DATA[phrase]) return error_count def compare_old_new_detection(phrase, generated_script) -> None: ''' Only for debugging. Compares results of the Chinese category detection using the old and the new function. ''' if (detect_chinese_category_old(phrase) != generated_script.detect_chinese_category(phrase)): logging.debug( '%s %s old=%d new=%d', phrase.encode('utf-8'), repr(phrase), detect_chinese_category_old(phrase), generated_script.detect_chinese_category(phrase)) if phrase in VARIANTS_TABLE_ORIG_UNIHAN_VARIANTS_ENTRY_USED: logging.debug( VARIANTS_TABLE_ORIG_UNIHAN_VARIANTS_ENTRY_USED[phrase]) def parse_args() -> Any: '''Parse the command line arguments''' import argparse parser = argparse.ArgumentParser( description=( 'Generate a script containing a table and a function ' + 'to check whether a string of Chinese characters ' + 'is simplified or traditional')) parser.add_argument('-i', '--inputfilename', nargs='?', type=str, default='./Unihan_Variants.txt', help='input file, default is ./Unihan_Variants.txt') parser.add_argument('-o', '--outputfilename', nargs='?', type=str, default='./chinese_variants.py', help='output file, default is ./chinese_variants.py') parser.add_argument('-d', '--debug', action='store_true', help='print debugging output') return parser.parse_args() def main() -> None: '''Main program''' args = parse_args() log_level = logging.INFO if args.debug: log_level = logging.DEBUG logging.basicConfig(format="%(levelname)s: %(message)s", level=log_level) with open(args.inputfilename) as inputfile: logging.info("input file=%s", inputfile) read_unihan_variants(inputfile) with open(args.outputfilename, 'w') as outputfile: logging.info("output file=%s", outputfile) write_variants_script(outputfile) import imp generated_script = imp.load_source('dummy', args.outputfilename) logging.info('Testing detection ...') error_count = test_detection(generated_script) if error_count: logging.info('FAIL: %s tests failed, exiting ...', error_count) exit(1) else: logging.info('PASS: All tests passed.') for phrase in generated_script.VARIANTS_TABLE: # type: ignore compare_old_new_detection(phrase, generated_script) if __name__ == '__main__': main() ibus-table-1.17.11/tools/ibus-table-query000077500000000000000000000112671475513533100202070ustar00rootroot00000000000000#!/usr/bin/python3 # vim:fileencoding=utf-8:sw=4:et # query-ibus-table # # Copyright (c) 2012 mozbugbox # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 3.0 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA from __future__ import print_function, unicode_literals, absolute_import import sys import os import io import logging as log import sqlite3 TABLE_DIR = "/usr/share/ibus-table/tables/" def list_tables(cursor): """List sql tables in a given sqlite database""" tables = cursor.execute("SELECT * FROM sqlite_master WHERE type='table';") for row in tables: log.debug("Table: {}".format(" ".join(row[1:3]))) log.debug(row[4]) def get_table_sql(cursor, name): """Given a table name, return the creation sql statement of the table.""" tables = cursor.execute("SELECT * FROM sqlite_master WHERE type='table' AND tbl_name = ? ;", [name]) sql = None for row in tables: sql = row[4] return sql def get_table_path(name): """Given a filename, return the full path to the ibus table sqlite file.""" if name.startswith("/"): if os.path.exists(name): return name else: return None else: tablename = None for fname in os.listdir(TABLE_DIR): if fname.startswith(name) and fname.endswith('.db'): tablename = fname break if not tablename or ( os.path.splitext(tablename)[0] != os.path.splitext(name)[0]): print("Known tables:") for fname in os.listdir(TABLE_DIR): print(" {}".format(fname)) if not tablename: print("No table: {}".format(name)) sys.exit(2) return os.path.join(TABLE_DIR, tablename) def query_keys(cursor, tabkeys): sqlstr = ''' SELECT tabkeys, phrase, freq, user_freq FROM main.phrases WHERE tabkeys LIKE :tabkeys ORDER BY phrase ASC, freq DESC; ''' sqlargs = {'tabkeys': tabkeys+'%%'} log.debug("sqlstr: {}".format(sqlstr)) log.debug("sqlargs: {}".format(sqlargs)) result = cursor.execute(sqlstr, sqlargs) return list(result) def print_result(table_sql, result): """@result: sqlite execute result. @table_sql: table creation sql statement """ pidx = table_sql.find("(") + 1 pidx2 = table_sql.find(")", pidx) headers = [x.split()[0] for x in table_sql[pidx:pidx2].split(",")][1:] format_str = "{}".format("{:16s}"*4) headers = format_str.format(*headers) print(headers) print("="*len(headers.rstrip())) for row in result: row = list(row) row_str = [str(x).strip() for x in row] if len(row_str[1]) == 1: row_str[1] += "[U+{:X}]".format(ord(row_str[1])) line = format_str.format(*row_str) print(line) def parse_args(): import argparse parser = argparse.ArgumentParser(description="Query ibus table database") parser.add_argument("--debug", action="store_true", help="DEBUG") parser.add_argument("-t", "--table-name", required=True, help="table database name") parser.add_argument("keys", metavar="Input-Keys", nargs=1, help="a string of input keys, e.g. hjik") args = parser.parse_args() return args NATIVE=sys.getfilesystemencoding() def main(): args = parse_args() log_level = log.INFO if args.debug: log_level = log.DEBUG log.basicConfig(format="%(levelname)s>> %(message)s", level=log_level) table_prefix = args.table_name keys = args.keys[0] if type(keys) != type(u''): keys = keys.decode(NATIVE) table_path = get_table_path(table_prefix) if not table_path: print('Table "{}" does not exist.'.format(table_prefix)) sys.exit(1) print("Using table: {}".format(table_path)) log.debug("table path: {}".format(table_path)) db = sqlite3.connect(table_path) cursor = db.cursor() #list_tables(cursor) table_sql = get_table_sql(cursor, "phrases") result = query_keys(cursor, keys) print_result(table_sql, result) if __name__ == '__main__': main()