tkabber-plugins000075500000000000000000000000001500237002100134325ustar00nobodynobodytkabber-plugins/COPYING000064400000000000000000000432611500237002100145520ustar00nobodynobody GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. tkabber-plugins/ChangeLog000064400000000000000000002466721500237002100153040ustar00nobodynobody2025-04-24 Sergei Golovan * aniemoticons/aniemoticons.tcl: Fix redefining ::plugins::emoticons::create_image. 2025-04-14 Sergei Golovan * latex/latex.tcl: Get the foreground and background colors from the chat window itself and not from the options. * ctcomp/ctcomp.tcl, spy/spy.tcl: Add another set of colors for dark themes. 2025-04-07 Sergei Golovan * poker/poker.tcl: Switch to Tcl 8.6 [lmap]. * tkabber-khim/khim/khim.tcl, whiteboard/svgrender.tcl: Allow loading into Tcl 9 interpreter. Fix relative namespaces. 2025-04-01 Sergei Golovan * aniemoticons/aniemoticons.tcl, aniemoticons/anigif.tcl, receipts/receipts.tcl: Fix image handling for high DPI displays. 2025-03-30 Sergei Golovan * *: Fix discrepancies between Tcl 8 and Tcl 9 using suggestions of a static code analyzer. 2025-03-29 Sergei Golovan * battleship/battleship.tcl, checkers/checkers.tcl, chess/chess.tcl, poker/poker.tcl, renju/renju.tcl, reversi/reversi.tcl: Multiply cell sizes and all other items on a canvas by $::icons_scale for high DPI displays. * latex/latex.tcl: Do not scale images from LaTeX. Use a separate option to choose their DPI. * debug/debug.tcl, georoster/georoster.tcl: Fix some variables referenced by relative namespace to work with Tcl 9 (unfinished yet). 2025-03-22 Sergei Golovan * *: Replace calls to [trace variable] and similar to calls to [trace add variable] etc. (porting to Tcl 9). 2025-03-19 Sergei Golovan * *: Specify widget sizes, borderwidth etc. in physical units instead of pixels. This helps with using Tkabber on high DPI displays. * openurl/msgs/de.msg, openurl/msgs/es.msg, openurl/msgs/ru.msg, openurl/msgs/uk.msg, openurl/openurl.tcl, tkabber-khim/khim/khim.tcl: Do not use tilde as a synonym for the user's home directory (helps with porting to Tcl 9). 2025-03-17 Sergei Golovan * latex/latex.tcl: Fix the default image resolution and RGB page color. 2016-10-11 Sergei Golovan * otr/otr.tcl, otr/trans/ru.msg, otr/trans/uk.msg: Do not include own JID into the OTR request message. 2016-07-10 Sergei Golovan * otr/otr.tcl: Do not send the message if the OTR code returns an error (this prevents leaking unencrypted material due to bugs in the OTR plugin). 2016-02-04 Sergei Golovan * otr/otr.tcl: Fixed rendering OTR icons in chat windows. 2016-02-01 Sergei Golovan * ctcomp/msgs/ru.msg: Fixed typo. 2016-01-11 Sergei Golovan * debug/debug.tcl: Do not rename and replace various debug commands if they don't exist in the first place. 2016-01-02 Sergei Golovan * receipts/receipts.tcl: Adjusted priority for the icon drawing procedure. * otr/otr.tcl: Use own procedures to store, discard and resend messages after refreshing broken OTR conversation. Moved drawing OTR message icon for outgoing messages to draw_message_hook where it is more appropriate. 2015-12-27 Sergei Golovan * otr/otr.tcl: Display more appropriate error messages in case of received OTR request but without any OTR key configured. * otr/msgs/ru.msg, otr/msgs/uk.msg: Updated Russian and Ukrainian translations. 2015-12-22 Sergei Golovan * custom-urls/custom-urls.tcl: Added custom URL for the Tkabber Fossil repository artifacts, like [3cd34577a3]. Modified the custom URL procedure to allow more flexible URL definitions. In particular, regexps with more than one capture group are permitted. 2015-12-19 Sergei Golovan * ejabberd/msgs/uk.msg: Updated Ukrainian translations. * cyrillize/cyrillize.tcl, cyrillize/engrus.tbl: Added the Ukrainian keyboard layout support. * cyrillize/msgs/ru.msg, bc/msgs/ru.msg: Updated Russian translations. * cyrillize/msgs/uk.msg, aniemoticons/msgs/uk.msg, bc/msgs/uk.msg, chess/msgs/uk.msg, ctcomp/msgs/uk.msg, custom-urls/msgs/uk.msg, cyrillize/msgs/uk.msg, browser/msgs/uk.msg, battleship/msgs/uk.msg: Updated Ukrainian translations. 2015-12-14 Sergei Golovan * floatingcontact/msgs/uk.msg, floatinglog/msgs/uk.msg: Updated Ukrainian translations. 2015-12-13 Sergei Golovan * quotelastmsg/msgs/uk.msg, receipts/msgs/uk.msg, renju/msgs/uk.msg, reversi/msgs/uk.msg, singularity/msgs/uk.msg, socials/msgs/uk.msg, spy/msgs/uk.msg, stripes/msgs/uk.msg, tclchat/msgs/uk.msg, tkabber-khim/msgs/uk.msg, traffic/msgs/uk.msg, unixkeys/msgs/uk.msg, whiteboard/msgs/uk.msg: Updated Ukrainian translations. * otr/msgs/ru.msg: Updated Russian translations. * checkers/msgs/uk.msg, debug/msgs/uk.msg, otr/msgs/uk.msg, otr/trans/uk.msg, poker/msgs/uk.msg, presencecmd/msgs/uk.msg, quiz/msgs/uk.msg, whiteboard/msgs/uk.msg: Updated Ukrainian translations. * jidlink/msgs/uk.msg, jidlink/trans/uk.msg, latex/msgs/uk.msg, mute/msgs/uk.msg, openurl/msgs/uk.msg, osd/msgs/uk.msg: Updated Ukrainian translations. * gmail/msgs/ru.msg: Updated Russian translations. * georoster/msgs/uk.msg, gmail/msgs/uk.msg, iconsets/msgs/uk.msg: Updated Ukrainian translations. 2015-12-10 Sergei Golovan * custom-urls/custom-urls.tcl: Added custom url for the Tkabber Wiki page, for example wiki:index or wiki:en/Main_Page. 2015-11-20 Sergei Golovan * custom-urls/custom-urls.tcl: Fixed determining if a string consists of digits only. 2015-08-28 Sergei Golovan * otr/otr.tcl: Do not try to add OTR icon for messages without any type set. 2015-08-08 Sergei Golovan * otr/otr.tcl: Fixed typo (added missing line continuation backslash). 2015-07-10 Sergei Golovan * Makefile: Added 'fossil pull' call to the 'up' Makefile target for those who use fossil in manual merge mode. 2015-06-11 Sergei Golovan * battleship/battleship.tcl, battleship/msgs/ru.msg: Fixed a message and its translation. 2015-06-01 Sergei Golovan * otr/otr.tcl: Do not add an OTR icon to the chatlog window if the message sending was aborted in rewrite_outgoing_message_hook. 2015-05-28 Sergei Golovan * otr/key.tcl: Prettified the progressbar appearance for Ttk based interface. 2015-05-26 Sergei Golovan * otr/msgs/ru.msg, otr/otr.tcl, otr/trans/ru.msg: Clarified the error message, fixed typo. 2015-05-25 Sergei Golovan * debug/debug.tcl: Added new gpg debug category which prints debug logs for the gpg package. 2015-05-24 Sergei Golovan * COPYING, aniemoticons/msgs/de.msg, attline/msgs/de.msg, attline/msgs/es.msg, attline/msgs/pl.msg, attline/msgs/ru.msg, attline/msgs/uk.msg, battleship/msgs/ru.msg, bc/msgs/ru.msg, checkers/README, checkers/proto, chess/proto, cyrillize/msgs/ru.msg, floatinglog/ChangeLog, iconsets/amibulb/roster/icondef.xml, tkabber-khim/INSTALL: Reformatted the code. 2015-05-10 Sergei Golovan * ChangeLog, aniemoticons/anigif.tcl, attline/README, battleship/battleship.tcl, bc/bc.tcl, checkers/checkers.tcl, checkers/proto, chess/chess.tcl, chess/proto, custom-urls/custom-urls.tcl, filters/filters.tcl, floatinglog/ChangeLog, floatinglog/floatinglog.tcl, georoster/howto.txt, georoster/msgs/es.msg, georoster/msgs/nl.msg, gmail/gmail.tcl, jidlink/plugins/filetransfer.tcl, jidlink/plugins/ibb.tcl, latex/latex.tcl, mute/mute.tcl, osd/osd.tcl, otr/auth.tcl, otr/otr.tcl, poker/poker.tcl, poker/proto, quiz/quiz.tcl, renju/proto, renju/renju.tcl, reversi/proto, reversi/reversi.tcl, singularity/README, socials/socials.en, socials/socials.ru, tclchat/tclchat_messages.tcl, tkabber-khim/khim/ROOT.msg, tkabber-khim/khim/cs.msg, tkabber-khim/khim/da.msg, tkabber-khim/khim/en.msg, tkabber-khim/khim/es.msg, tkabber-khim/khim/khim.tcl, tkabber-khim/khim/pl.msg, tkabber-khim/tklib_licence.terms, traffic/msgs/ru.msg, traffic/msgs/uk.msg, whiteboard/svgrender.tcl, whiteboard/whiteboard.tcl: Removed the trailing whitespaces. 2015-05-09 Sergei Golovan * whiteboard/whiteboard.tcl: Adapted the Whiteboard plugin to the Ttk based interface. * whiteboard/ChangeLog, whiteboard/msgs/de.msg, whiteboard/msgs/es.msg, whiteboard/msgs/nl.msg, whiteboard/msgs/pl.msg, whiteboard/msgs/ro.msg, whiteboard/msgs/ru.msg, whiteboard/msgs/uk.msg, whiteboard/svgrender.tcl, whiteboard/whiteboard.tcl: Reformatted the code. * unixkeys/INSTALL, unixkeys/README, unixkeys/TODO, unixkeys/msgs/ru.msg, unixkeys/unixkeys.tcl: Reformatted the code. Bind all events to TEntry also. * traffic/traffic.tcl: Adapted the Traffic accounting plugin to the Ttk based interface. * traffic/msgs/de.msg, traffic/msgs/es.msg, traffic/msgs/pl.msg, traffic/msgs/ru.msg, traffic/msgs/uk.msg, traffic/traffic.tcl: Reformatted the code. * tkabber-khim/ChangeLog, tkabber-khim/INSTALL, tkabber-khim/msgs/es.msg, tkabber-khim/msgs/pl.msg, tkabber-khim/msgs/ru.msg, tkabber-khim/tkabber-khim.tcl: Reformatted the code. Adapted the Tkabber KHIM plugin to the Ttk based interface. * tkabber-khim/khim/ROOT.msg, tkabber-khim/khim/cs.msg, tkabber-khim/khim/da.msg, tkabber-khim/khim/de.msg, tkabber-khim/khim/en.msg, tkabber-khim/khim/es.msg, tkabber-khim/khim/khim.tcl, tkabber-khim/khim/ru.msg: Updated the KHIM package. * tclchat/tclchat.tcl: Adapted the Tclchat plugin to the Ttk based interface. * tclchat/msgs/es.msg, tclchat/msgs/ru.msg, tclchat/tclchat.tcl, tclchat/tclchat_commands.tcl, tclchat/tclchat_messages.tcl: Reformatted the code. * stripes/INSTALL, stripes/README, stripes/msgs/de.msg, stripes/msgs/ru.msg, stripes/stripes.tcl: Reformatted the code. * spy/spy.tcl: Adapted the Spy presence plugin to the Ttk based interface. Cleaned up the code. * spy/msgs/de.msg, spy/msgs/es.msg, spy/msgs/pl.msg, spy/msgs/ru.msg, spy/msgs/uk.msg, spy/spy.tcl: Reformatted the code. * socials/ChangeLog, socials/msgs/de.msg, socials/msgs/ru.msg, socials/socials.tcl: Reformatted the code. * singularity/INSTALL, singularity/README, singularity/msgs/pl.msg, singularity/msgs/ru.msg, singularity/singularity.tcl: Reformatted the code. * reversi/reversi.tcl: Adapted the Reversi game plugin to the Ttk based interface. * reversi/msgs/es.msg, reversi/msgs/nl.msg, reversi/msgs/pl.msg, reversi/msgs/ru.msg, reversi/msgs/uk.msg, reversi/pixmaps/checkers/icondef.xml, reversi/pixmaps/xboard/icondef.xml, reversi/proto, reversi/reversi.tcl: Reformatted the code. * renju/renju.tcl: Adapted the Renju/Gomoku game plugin to the Ttk based interface. * poker/poker.tcl: Fixed the dialog messages background. * renju/msgs/es.msg, renju/msgs/ru.msg, renju/pixmaps/black/icondef.xml, renju/pixmaps/stones/icondef.xml, renju/proto, renju/renju.tcl: Reformatted the code. * receipts/INSTALL, receipts/README, receipts/TODO, receipts/msgs/de.msg, receipts/msgs/es.msg, receipts/msgs/pl.msg, receipts/msgs/ru.msg, receipts/receipts.tcl: Reformatted the code. * quotelastmsg/INSTALL, quotelastmsg/msgs/de.msg, quotelastmsg/msgs/ru.msg, quotelastmsg/quotelastmsg.tcl: Reformatted the code. * quiz/msgs/ru.msg, quiz/quiz.tcl: Reformatted the code. * presencecmd/INSTALL, presencecmd/TODO, presencecmd/msgs/de.msg, presencecmd/msgs/es.msg, presencecmd/msgs/pl.msg, presencecmd/msgs/ru.msg, presencecmd/presencecmd.tcl: Reformatted the code. * poker/poker.tcl: Adapted the Poker game plugin to the Ttk based interface. * poker/msgs/ru.msg, poker/pixmaps/classic/icondef.xml, poker/pixmaps/doods/icondef.xml, poker/poker.tcl, poker/proto: Reformatted the code. Fixed the crash with the newer Tk for the case when a canvas tag doesn't exist. * otr/auth.tcl, otr/key.tcl, otr/msgs/ru.msg, otr/otr.tcl, otr/trans/ru.msg: Reformatted the code. * osd/ChangeLog, osd/msgs/ru.msg, osd/osd.tcl: Reformatted the code, added external requirement to the plugin description. * openurl/msgs/de.msg, openurl/msgs/es.msg, openurl/msgs/pl.msg, openurl/msgs/ru.msg, openurl/openurl.tcl: Reformatted the code. Removed unnecessary [eval]. * mute/mute.tcl: Adapted the MUTE plugin to the Ttk based interface. Added a list of external requirements for the MUTE to work. * mute/msgs/ru.msg, mute/mute.tcl: Reformatted the code. * latex/latex.tcl, latex/msgs/de.msg, latex/msgs/es.msg, latex/msgs/ru.msg, latex/msgs/uk.msg: Reformatted the code. Removed unnecessary [expr]. * jidlink/plugins/filetransfer.tcl, jidlink/plugins/ibb.tcl: Adapted the Jidlink filetransfer plugin to the Ttk based interface. Fixed namespace issues. * jidlink/jidlink.tcl, jidlink/msgs/de.msg, jidlink/msgs/es.msg, jidlink/msgs/pl.msg, jidlink/msgs/ru.msg, jidlink/plugins/dtcp.tcl, jidlink/plugins/filetransfer.tcl, jidlink/plugins/ibb.tcl, jidlink/trans/ru.msg: Reformatted the code. * iconsets/amibulb/icondef.xml, iconsets/gabber/icondef.xml, iconsets/gush/icondef.xml, iconsets/iconsets.tcl, iconsets/icq/icondef.xml, iconsets/jajc/icondef.xml, iconsets/jarl/icondef.xml, iconsets/kroc/icondef.xml, iconsets/msgs/ru.msg, iconsets/psi/icondef.xml: Reformatted the code. 2015-05-08 Sergei Golovan * gmail/gmail.tcl: Adapted the Gmail notifications plugin to the Ttk interface. * gmail/gmail.tcl, gmail/msgs/de.msg, gmail/msgs/es.msg, gmail/msgs/pl.msg, gmail/msgs/ru.msg: Reformatted the code. * georoster/georoster.tcl: Adapted the Georoster plugin to the Ttk based interface. * georoster/ChangeLog, georoster/cities/earth, georoster/cities/earth.ru, georoster/coords/de.coords, georoster/coords/jm.coords, georoster/coords/nl.coords, georoster/coords/ru.coords, georoster/coords/ua.coords, georoster/coords/us.coords, georoster/georoster.tcl, georoster/maps/bwmap2.gif, georoster/maps/bwmap4.gif, georoster/maps/colormap.jpg, georoster/maps/darkmap.gif, georoster/msgs/de.msg, georoster/msgs/es.msg, georoster/msgs/nl.msg, georoster/msgs/pl.msg, georoster/msgs/ro.msg, georoster/msgs/ru.msg, georoster/msgs/uk.msg: Reformatted the code, moved data files into subdirectories. * floatinglog/ChangeLog, floatinglog/floatinglog.tcl, floatinglog/msgs/de.msg, floatinglog/msgs/es.msg, floatinglog/msgs/pl.msg, floatinglog/msgs/ru.msg: Reformatted the code. * floatingcontact/README, floatingcontact/floatingcontact.tcl, floatingcontact/msgs/de.msg, floatingcontact/msgs/ru.msg: Reformatted the code. Douplicated the % sign in bindings. * filters/filters.tcl, filters/msgs/ca.msg, filters/msgs/de.msg, filters/msgs/eo.msg, filters/msgs/es.msg, filters/msgs/eu.msg, filters/msgs/fr.msg, filters/msgs/it.msg, filters/msgs/nl.msg, filters/msgs/pl.msg, filters/msgs/pt.msg, filters/msgs/ro.msg, filters/msgs/ru.msg, filters/msgs/uk.msg: Reformatted the code. Fixed work with the wrapped ttk::treeview as a listbox widget. * ejabberd/ejabberd.tcl: Adapted the Ejabberd config plugin to the Ttk based interface. * ejabberd/ejabberd.tcl, ejabberd/msgs/ca.msg, ejabberd/msgs/de.msg, ejabberd/msgs/es.msg, ejabberd/msgs/fr.msg, ejabberd/msgs/it.msg, ejabberd/msgs/nl.msg, ejabberd/msgs/pl.msg, ejabberd/msgs/pt.msg, ejabberd/msgs/ru.msg, ejabberd/msgs/uk.msg: Reformatted the code. * debug/debug.tcl, debug/msgs/de.msg, debug/msgs/es.msg, debug/msgs/pl.msg, debug/msgs/ru.msg, debug/msgs/uk.msg: Reformatted the code, fixed posting menu for debug category with :: in it. Adapted the debug window to the Ttk based interface. * cyrillize/cyrillize.tcl, cyrillize/msgs/ru.msg: Reformatted the code. * custom-urls/custom-urls.tcl, custom-urls/msgs/pl.msg, custom-urls/msgs/ru.msg: Reformatted code, updated the tclbug and tkbug examples, fixed processing non-digital variable URL parts. * ctcomp/ChangeLog, ctcomp/INSTALL, ctcomp/README, ctcomp/TODO, ctcomp/ctcomp.tcl, ctcomp/msgs/de.msg, ctcomp/msgs/ru.msg: Reformatted the code. * README: Added a few words about enabling plugins. * battleship/battleship.tcl, checkers/checkers.tcl: Fixed the board canvas size, moved relief changing code into a separate procedure. * chess/chess.tcl: Adapted the Chess plugin to the Ttk interface. * chess/chess.tcl, chess/msgs/es.msg, chess/msgs/nl.msg, chess/msgs/pl.msg, chess/msgs/ro.msg, chess/msgs/ru.msg, chess/msgs/uk.msg, chess/pixmaps/classic/icondef.xml, chess/pixmaps/wooden/icondef.xml, chess/pixmaps/xboard/icondef.xml, chess/proto: Reformatted code. * checkers/checkers.tcl: Adapted the Checkers plugin to the Ttk interface. * checkers/README, checkers/checkers.tcl, checkers/msgs/es.msg, checkers/msgs/nl.msg, checkers/msgs/pl.msg, checkers/msgs/ru.msg, checkers/msgs/uk.msg, checkers/pixmaps/checkers/icondef.xml, checkers/pixmaps/xboard/icondef.xml, checkers/proto, checkers/rules/brasilian.txt, checkers/rules/italian.txt, checkers/rules/pool.txt, checkers/rules/russian.txt, checkers/rules/spanish.txt, checkers/rules/straight.txt: Reformatted code. * browser/browser.tcl: Adapted the Jabber Browser plugin to the Ttk interface. 2015-05-07 Sergei Golovan * bc.tcl, bc/msgs/ru.msg, browser/browser.tcl, browser/msgs/de.msg, browser/msgs/es.msg, browser/msgs/pl.msg, browser/msgs/ru.msg: Fit code into 80 column limit, replaced tabs by spaces, added the corresponding Vim modeline. * battleship/battleship.tcl: Adapted the Battleship game to Ttk. * battleship/battleship.tcl: Fit the cone into 80 characters limit. * aniemoticons/msgs/de.msg, aniemoticons/msgs/ru.msg, attline/msgs/de.msg, attline/msgs/es.msg, attline/msgs/pl.msg, attline/msgs/ru.msg, attline/msgs/uk.msg, battleship/battleship.tcl, battleship/msgs/ru.msg, battleship/pixmaps/copybook/icondef.xml, battleship/proto: Replaced tabs by spaces, added Vim modelines which instruct the editor to expand tabs. * aniemoticons/aniemoticons.tcl, aniemoticons/anigif.tcl, attline/attline.tcl: Fit the code into 80 characters line limit. Added Vim modeline which expands tabs into spaces. Actually replaced tabs by spaces in the code. * aniemoticons/aniemoticons.tcl: Extended the file description, cleaned up the code. 2015-05-04 Sergei Golovan * ejabberd/ejabberd.tcl, ejabberd/msgs/ca.msg, ejabberd/msgs/de.msg, ejabberd/msgs/es.msg, ejabberd/msgs/fr.msg, ejabberd/msgs/it.msg, ejabberd/msgs/nl.msg, ejabberd/msgs/pl.msg, ejabberd/msgs/pt.msg, ejabberd/msgs/ru.msg, ejabberd/msgs/uk.msg: Moved processing the ejabberd:config disco feature to the Ejabberd admin plugin. 2015-04-29 Sergei Golovan * socials/socials.ru, socials/socials.tcl: Converted the socials plugin from KOI8-R to UTF-8. * quiz/quiz.tcl, quiz/quizdata.txt: Converted the quiz game plugin from KOI8-R to UTF-8 encoding. * georoster/earth: Fixed encoding for the fallback cities file. * cyrillize/cyrillize.tcl, cyrillize/engrus.tbl: Converted cyrillize plugin from KOI8-R to UTF-8. * bc/bc.tcl, bc/ru.dic: Converted bulls&cows game plugin from KOI8-R to UTF-8. * attline/msgs/de.msg, browser/msgs/de.msg, ctcomp/msgs/de.msg, debug/msgs/de.msg, ejabberd/msgs/de.msg, floatinglog/msgs/de.msg, georoster/msgs/de.msg, gmail/msgs/de.msg, jidlink/msgs/de.msg, latex/msgs/de.msg, openurl/msgs/de.msg, presencecmd/msgs/de.msg, quotelastmsg/msgs/de.msg, receipts/msgs/de.msg, spy/msgs/de.msg, stripes/msgs/de.msg, tkabber-khim/khim/da.msg, traffic/msgs/de.msg: Fixed encoding in translated messages. Converted from latin1 to UTF-8. 2015-04-17 Sergei Golovan * otr/auth.tcl, otr/key.tcl, otr/otr.tcl: Adapted OTR plugin dialog windows to Ttk interface. * otr/auth.tcl: Now the context menu works for both Tk and Ttk mclistboxes. * otr/auth.tcl: Use the improved mclistbox API. 2015-04-16 Sergei Golovan * browser/browser.tcl: Fixed the drop command arguments. * Makefile: Added filters subdirectory to the installed directories list. 2015-04-13 Sergei Golovan * README, filters/filters.tcl, filters/msgs/ca.msg, filters/msgs/de.msg, filters/msgs/eo.msg, filters/msgs/es.msg, filters/msgs/eu.msg, filters/msgs/fr.msg, filters/msgs/it.msg, filters/msgs/nl.msg, filters/msgs/pl.msg, filters/msgs/pt.msg, filters/msgs/ro.msg, filters/msgs/ru.msg, filters/msgs/uk.msg: Split out Jabberd 1.4 mod_filter support into an external plugin. 2015-04-12 Sergei Golovan * otr/otr.tcl: Changed buttons a little bit to adapt them to Ttk. 2015-04-08 Sergei Golovan * whiteboard/whiteboard.tcl: Fixed plugin unloading for the case when there was no whiteboards open during the current session. * whiteboard/svgrender.tcl: Removed forgotten TODO leftover. 2015-04-07 Sergei Golovan * floatingcontact/README: Removed Subversion keyword placeholder. 2015-03-30 Sergei Golovan * debug/debug.tcl, debug/msgs/de.msg, debug/msgs/es.msg, debug/msgs/pl.msg, debug/msgs/ru.msg, debug/msgs/uk.msg: Relocated the profiling menu items from the main Tkabebr code to the Debug plugin. * battleship/battleship.tcl, browser/browser.tcl, checkers/checkers.tcl, chess/chess.tcl, georoster/georoster.tcl, gmail/gmail.tcl, jidlink/plugins/dtcp.tcl, jidlink/plugins/filetransfer.tcl, mute/mute.tcl, osd/osd.tcl, quiz/quiz.tcl, renju/renju.tcl, reversi/reversi.tcl, socials/socials.tcl, tclchat/tclchat.tcl, tclchat/tclchat_messages.tcl, traffic/traffic.tcl: Got rid of all commands from TclX (namely, [cequal], [cindex], [crange], [lcontain], [lempty], [lmatch], [lvarpush], [lrmdups], [random]) because the TclX requirement will be removed from Tkabber soon. 2015-03-29 Sergei Golovan * */*: Added headers with short description. Removed no longer needed SVN keywords placeholders. * otr/auth.tcl, otr/key.tcl, otr/msgs/ru.msg, otr/otr.tcl: Added headers with short description. * otr/tclotr/auth.tcl, otr/tclotr/crypto.tcl, otr/tclotr/data.tcl, otr/tclotr/key.tcl, otr/tclotr/message.tcl, otr/tclotr/otr.tcl, otr/tclotr/pkgIndex.tcl, otr/tclotr/smp.tcl, otr/trans/ru.msg: Removed no longer needed SVN keywords placeholders. * otr/tclotr/ChangeLog, otr/tclotr/README: Added separate ChangelLog and README for the TclOTR package. * whiteboard/svgrender.tcl: Fixed variable name. * whiteboard/msgs/de.msg: Fixed encoding. * whiteboard/msgs/de.msg, whiteboard/msgs/es.msg, whiteboard/msgs/nl.msg, whiteboard/msgs/pl.msg, whiteboard/msgs/ro.msg, whiteboard/msgs/ru.msg, whiteboard/msgs/uk.msgwhiteboard/svgrender.tcl, whiteboard/whiteboard.tcl: Added headers with short description. * whiteboard/svgrender.tcl: Dropped Tcl/Tk 8.4 support. 2015-03-28 Sergei Golovan * whiteboard/whiteboard.tcl: Fixed image adding for private chats. Added support for skewing transformations. * whiteboard/msgs/ru.msg: Updated Russian translations. 2015-03-27 Sergei Golovan * whiteboard/whiteboard.tcl: Fixed moving and transforming whiteboard items in private chats. 2015-03-25 Sergei Golovan * otr/tclotr/otr.tcl: Returned [eval] instead of [uplevel #0] for calling back since [eval] allows to look up the call stack anf find something useful there (see [otr::send] procedure). Switch the OTR state to plaintext after an OTR error message is received. Otherwise, if the other side disables OTR in the middle of an encrypted conversation we cannot tell her anything at all - all messages will be encrypted, and she'll never read them. * ctcomp/msgs/ru.msg, spy/msgs/ru.msg: Updated Russian translations. * otr/tclotr/license.terms: Fixed copyright year. 2015-03-24 Sergei Golovan * Makefile: Add 'up' target which updates Tkabber plugins from their Fossil repository. 2014-12-13 Sergei Golovan * battleship/battleship.tcl: Fixed error with creating windows with the same names. Fixed errors when flipping and/or dragging ships with mouse pointer exactly between the edges of two adjacent cells. 2014-11-12 Sergei Golovan * otr/tclotr/otr.tcl: Evaluate external callback procedures at the top stack level. 2014-11-02 Sergei Golovan * otr/otr.tcl, otr/auth.tcl: Got rid of avoidable [eval] calls, deduplicated setting properties for chat and message OTR buttons. 2014-07-16 Sergei Golovan * otr/otr.tcl: Added scrollbar for the OTR userinfo page. It helps when there are many user's resources using OTR. 2014-05-06 Sergei Golovan * otr/tclotr/auth.tcl: Fixed recreating the reveal signature message. 2014-04-28 Sergei Golovan * otr/msgs/ru.msg: Fixed typo. 2014-02-25 Sergei Golovan * otr/otr.tcl: Fixed reporting SMP progress when the SMP dialog window is already destroyed. 2014-02-19 Sergei Golovan * otr/tclotr/smp.tcl: Added a debug print procedure instead of plain puts calls. * debug/debug.tcl: Use ::otr::smp::Debug for printing OTR authentication debug info. 2014-02-15 Sergei Golovan * otr/README: Fixed the requirements list. 2014-02-14 Sergei Golovan * *: 1.1 is released. 2014-02-07 Sergei Golovan * battleship/*, Makefile, README: Added a new battleship game plugin. 2014-02-02 Sergei Golovan * otr/key.tcl, otr/tclotr/key.tcl: Moved key generation procedure to the otr::key package. * otr/otr.tcl, otr/auth.tcl, otr/key.otr: Copy keys fingerprints to clipboard in authentication dialog, in manage key dialog, in edit authentication dialog. * otr/otr.tcl: Fixed bugs in switching OTR icons after authentication. * otr/msgs/ru.msg: Updated Russian translation. 2014-01-31 Sergei Golovan * otr/otr.tcl: Fixed typo in creating OTR button for normal message windows. * README: Added short description for floatingcontact and otr plugins. * otr/otr.tcl: Toggle the OTR message state on clicking OTR button in a chat tab. 2014-01-30 Sergei Golovan * otr/key.tcl: Fixed typo in error message. * otr/msgs/ru.msg: Updated Russian translation. * otr/otr.tcl: Disable OTR contact menu if the contact is myself. Don't add fake script to the list of scripts executed on message state changes. 2014-01-29 Sergei Golovan * Makefile: Added otr subdirectory to the install list. * otr/otr.tcl, otr/auth.tcl: Moved resetting auth icons to the otr.tcl. 2014-01-28 Sergei Golovan * otr/key.tcl, otr/otr.tcl: Drop existing OTR cnversations only if the key is really is changed or deleted. Show an info message when this happens. * otr/auth.tcl: Change OTR icons on all existing windows acorrding to the authentication changes. * otr/otr.tcl: Added fingerprint and SSID to the roster and OTR button help text. Do cleanup after the authentication dialog is closed. * otr/auth.tcl: Fixed changing icons, renamed cancel button to close for the case when there's nothing to cancel. * otr/otr.tcl: Unset a few global variables when they aren't in use. * otr/otr.tcl: Don't add not-private icon to incoming messages when the message state is plaintext. 2014-01-27 Sergei Golovan * otr/otr.tcl: Fail to load OTR plugin if Tkabber doesn't support the necessary features. * otr/otr.tcl: Added heartbeat-interval option. * otr/key.tcl: Fixed collecting jids from current connections to show in key management dialog. * otr/key.tcl: Show dialog if importing DSA key fails. * otr/tclotr/key.tcl: Fixed typo. * otr/tclotr/key.tcl: Use unix line endings when exporting the DSA private key. Refuse to import keys which aren't 1024 bit long. * otr/README: Fixed info on how to use private keys. * otr/tclotr/message.tcl: Treat human readable message part as HTML (strip tags for incoming messages, escape HTML entities for outgoing ones). * otr/otr.tcl, otr/trans/ru.msg: Removed repeated link. 2014-01-26 Sergei Golovan * otr/tclotr/otr.tcl: Fixed refreshing private connection if the peer has changed his instance tag. Clear messages subject to resend when the message state switches from encrypted. * otr/tclotr/auth.tcl: Fixed recreating D-H commit message. * otr/otr.tcl: Implemented disabling logs for encrypted OTR messages. * otr/auth.tcl: Replaced combobox by option menu to match edit keys dialog. * otr/otr.tcl: Add the corresponding OTR icon to outgoing chat messages. * floatinglog/floatinglog.tcl, whiteboard/whiteboard.tcl, browser/browser.tcl, gmail/gmail.tcl, georoster/georoster.tcl: Replaced direct bindings to mouse buttons 2 and 3 by virtual events <> and <>, because in MacOSX and in Unix buttons 2 and 3 correspond to different mous buttons (thanks to Vitaly Takmazov). * spy/spy.tcl, spy/msgs/ru.msg: Added sound notification. 2014-01-25 Sergei Golovan * otr/key.tcl, otr/tclotr/crypto.tcl: Code cleanup, made DSA key generation more clear. * otr/*: Added short description to procedures definitions. * otr/otr.tcl, otr/tclotr/otr.tcl: Use the sender's instance tag included into the Diffie-Hellman commit message. Resend the last data message if it was replied by an OTR error message (resend it after a new successful AKE). * otr/tclotr/otr.tcl: Fixed processing message state changes. Show an info message when private conversation is started. * otr/msgs/ru.msg: Updated Russian translations. * otr/tclotr/otr.tcl: Show an info message when private conversation is finished. * otr/otr.tcl: Translate outgoing OTR error messages. * otr/msgs/ru.msg, otr/trans/ru.msg: Update Russian translatinos. * otr/otr.tcl, otr/tclotr/otr.tcl: Show SSID and fingerprint in the userinfo dialog. * otr/msgs/ru.msg: Updated Russian translations. 2014-01-24 Sergei Golovan * otr/key.tcl, otr/otr.tcl: Finish all existing OTR sessions for a given connection if the associated private key is imported or deleted. * otr/key.tcl, otr/tclotr/crypto.tcl: Implemented generating new DSA private key. * otr/msgs/ru.msg, otr/otr.tcl, otr/trans/ru.msg: Added Russian translation. 2014-01-23 Sergei Golovan * otr/otr.tcl, otr/tclotr/message.tcl, otr/tclotr/otr.tcl: Code cleanup. Moved most of the interaction with the calling program to callbacks. Fixed OTR labels for incoming chat messages. Disabled some OTR menu items depending on the current message state. * otr/auth.tcl: Remove profile with empty fingerprints list from the stored authentications. * otr/otr.tcl: Assign the message icon directly while rewriting its body and not when drawing. * otr/tclotr/otr.tcl: Fixed typos in callback invocations. * otr/pixmaps/otr/notprivate.gif: Fixed the right edge. * otr/key.tcl, otr/tclotr/key.tcl, otr/otr.tcl: Implemented simple GUI for managing OTR private DSA keys (currently importing, exporting, deleting keys are supported). 2014-01-22 Sergei Golovan * otr/auth.tcl, otr/otr.tcl, otr/tclotr/otr.tcl: Store the authentication data after peer verification using question & answer, shared secret or manual verification. Provisionally implemented a dialog where user can edit auth info. * otr/otr.tcl: Dont filter groupchat, error and headline stanzas. 2014-01-21 Sergei Golovan * otr/tclotr/key.tcl, otr/tclotr/pkgIndex.tcl: Added a new subpackage which currently encodes and decodes DSA private keys in PEM format. * otr/otr.tcl, otr/README: Use ~/.tkabber/otr.private.key.pem file for DSA private key instead of ::OTRPrivateKey variable from the config. * otr/otr.tcl: Fixed updating default OTR policy from GUI. * otr/otr.tcl, otr/tclotr/otr.tcl: Tell the OTR plugin about state changes and SMP progress using callbacks and only in case of actual change. * otr/tclotr/otr.tcl: Attach the OTR whitespace tag only if there weren't received plaintext messages from the peer before. * otr/auth.tcl: Implemented authentication storing and restoring infrastructure for future use (untested yet). 2014-01-20 Sergei Golovan * otr/tclotr/otr.tcl: Do not send the OTR query message after an OTR error if no ALLOW_V2 or ALLOW_V3 is in the policy flags. * otr/tclotr/data.tcl: Removed already done todo item. * otr/tclotr/otr.tcl, otr/tclotr/message.tcl: Implemented the old MAC keys revelation, checking for the peer's counter monotonicity, ignoring verification and decryption errors if IGNORE_UNREADABLE message flag is set. * otr/tclotr/data.tcl, otr/tclotr/otr.tcl: Implemented assembling incoming messages from fragments. * otr/tclotr/otr.tcl, otr/otr.tcl: Implemented sending heartbeat messages (the OTR plugin doesn't use this yet). * otr/tclotr/otr.tcl: Fixed typo in code which stores old MAC keys. * otr/otr.tcl: Don't filter outgoing messages with empty body (or without body at all). Don't allow the user to send messages in finished OTR state. * otr/otr.tcl, otr/tclotr/otr.tcl: Removed unnecessary field from OTR procedures' result. * otr/tclotr/otr.tcl: Fixed typo in ::otr::configure. * otr/otr.tcl, otr/tclotr/otr.tcl: Warn user if plaintext message is received while encryption is required. 2014-01-19 Sergei Golovan * otr/tclotr/otr.tcl: Fixed checking data message hash for protocol version 3. * otr/tclotr/message.tcl: Fixed typo in processing SMP message 4. Fixed error reporting. * otr/otr.tcl: Enabled starting SMP with shared secret. * otr/*: Continue developing OTR plugin. * otr/*: SMP protocol is now working, but its outcome isn't utilised anywhere. * otr/otr.tcl, otr/tclotr/message.tcl: Got rid of eval and uplevel calls. * otr/tclotr/otr.tcl: Don't attach the OTR whitespace tag if policy doesn't allow using any protocol version. * otr/otr.tcl, otr/tclotr/message.tcl, otr/tclotr/otr.tcl, otr/tclotr/smp.tcl: Roughly finished SMP implementation. No peer authentication status storing yet though. 2014-01-18 Sergei Golovan * otr/*: Better error reporting. Continue implementing peer authentication. 2014-01-17 Sergei Golovan * otr/*: Added pre-alpha of the new OTR plugin. No key management, peer authentication, SMP, proper error reporting, resending messages yet. Not for regular usage yet. * debug/debug.tcl: Added the otr debug category. * otr/tclotr/crypto.tcl: Added procedure which computes binary DSA public key fingerprint. * otr/tclotr/otr.tcl: Don't compute DSA key fingerprint directly, but convert the one computed in the otr::crypto package. * otr/tclotr/smp.tcl: Initially implemented parsing, creating and verifying OTR SMP messages. 2014-01-01 Sergei Golovan * *: 1.0 is released. 2013-12-31 Sergei Golovan * browser/browser.tcl, gmail/gmail.tcl: Use the default values for -deltax and -deltay Tree options. * Makefile: Changed mkdir and cp to install where it makes sense. Don't mirror echo commands. 2013-12-30 Sergei Golovan * singularity/singularity.tcl: Fixed concatenation of histories. 2013-12-03 Sergei Golovan * debug/debug.tcl: Added xmpp::transport::bosh debug category. 2012-06-12 Konstantin Khomoutov * attline/msgs/uk.msg: Added Ukrainian translation for the attline plugin. 2012-05-05 Sergei Golovan * poker/msgs/ru.msg, poker/poker.tcl: Added Russian translation for the poker plugin. 2012-05-04 Sergei Golovan * poker/poker.tcl, poker/proto: Fixed cryptographic weakness in the shuffling cards procedure. Therefore the game type attribute has been changed to 'poker:th:1'. * Makefile, README: Added poker plugin to the plugins list. 2010-12-03 Konstantin Khomoutov * receipts/receipts.tcl: Implement support for XEP-0184 v1.1. 2010-12-01 Sergei Golovan * latex/latex.tcl: Fixed processing blacklisted words. 2010-11-18 Sergei Golovan * stripes/msgs/de.msg: Added German translation (thanks to Roger Sondermann). * quotelastmsg/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2010-11-17 Sergei Golovan * ctcomp/ctcomp.tcl: Added message catalog support. * ctcomp/msgs/de.msg, latex/msgs/de.msg, presencecmd/msgs/de.msg: Updated German translation (thanks to Roger Sondermann) 2010-11-17 Konstantin Khomoutov * unixkeys/unixkeys.tcl: Make unixkeys plugin dynamically loadable, provide Russian message catalog. * quotelastmsg/quotelastmsg.tcl: Explicitly require msgcat package. 2010-11-16 Konstantin Khomoutov * stripes/stripes.tcl: Make stripes plugin dynamically loadable, provide Russian message catalog. 2010-11-15 Konstantin Khomoutov * quotelastmsg/quotelastmsg.tcl: Make quotelastmsg plugin dynamically loadable. 2010-11-12 Konstantin Khomoutov * presencecmd/presencecmd.tcl: Make presencecmd plugin dynamically loadable (thanks to Serge Yudin). * checkers/msgs/ru.msg: Fix typo (thanks to Serge Yudin). 2010-11-11 Sergei Golovan * openurl/openurl.tcl: Fixed typo and added Google Chrome browser. 2010-11-11 Konstantin Khomoutov * singularity/singularity.tcl: Make singularity plugin dynamically loadable. 2010-11-10 Konstantin Khomoutov * latex/latex.tcl: Make latex plugin dynamically loadable. * osd/osd.tcl: Make osd plugin dynamically loadable. 2010-11-09 Konstantin Khomoutov * ctcomp/ctcomp.tcl: Make ctcomp plugin dynamically loadable, remove dead code. 2010-04-21 Sergei Golovan * quotelastmsg/msgs/de.msg: Added German translation (thanks to Roger Sondermann) 2010-03-08 Sergei Golovan * quotelastmsg/msgs/ru.msg: Fixed typo (thanks to Serge Yudin). 2010-02-14 Sergei Golovan * debug/msgs/pl.msg, gmail/msgs/pl.msg, floatinglog/msgs/pl.msg, spy/msgs/pl.msg, receipts/msgs/pl.msg, reversi/msgs/pl.msg, checkers/msgs/pl.msg, whiteboard/msgs/pl.msg, custom-urls/msgs/pl.msg, ejabberd/msgs/pl.msg, attline/msgs/pl.msg, chess/msgs/pl.msg, georoster/msgs/pl.msg, singularity/msgs/pl.msg, traffic/msgs/pl.msg: Updated Polish translation (thanks to Irek Chmielowiec). 2010-01-31 Sergei Golovan * tclchat/tclchat_messages.tcl: Fixed typo. 2010-01-30 Sergei Golovan * tclchat/tclchat_messages.tcl: Adapted to changes in Tkabber's MUC. 2010-01-24 Sergei Golovan * jidlink/jidlink.tcl, jidlink/trans/ru.msg: Added translations to the text of outgoing error messages. 2010-01-23 Sergei Golovan * bc/msgs/ru.msg, browser/msgs/ru.msg, checkers/msgs/ru.msg, chess/msgs/ru.msg, custom-urls/msgs/ru.msg, cyrillize/msgs/ru.msg, ejabberd/msgs/ru.msg, floatingcontact/msgs/ru.msg, floatinglog/msgs/ru.msg, georoster/msgs/ru.msg, gmail/msgs/ru.msg, iconsets/msgs/ru.msg, jidlink/msgs/ru.msg, mute/msgs/ru.msg, openurl/msgs/ru.msg, quiz/msgs/ru.msg, quotelastmsg/msgs/ru.msg, receipts/msgs/ru.msg, renju/msgs/ru.msg, reversi/msgs/ru.msg, singularity/msgs/ru.msg, spy/msgs/ru.msg, tclchat/msgs/ru.msg, traffic/msgs/ru.msg, whiteboard/msgs/ru.msg: Updated Russian translation. * Makefile: Added floatingcontact plugin to plugins list. * quotelastmsg/quotelastmsg.tcl: Fixed escaping % in bind scripts. 2010-01-16 Sergei Golovan * spy/spy.tcl: Fixed adding new spy watch if some of them were added and removed already. 2010-01-14 Sergei Golovan * latex/latex.tcl: Use -output-directory latex option instead of changing working directory. Use dvigif if available to produce an image to insert into a chat window. 2009-12-29 Sergei Golovan * floatinglog/floatinglog.tcl: Check if the floatinglog window exists before setting its geometry (thanks to Ruslan Rakhmanin). 2009-12-25 Sergei Golovan * gmail/gmail.tcl: Got rid of using global NS variable. * floatinglog/floatinglog.tcl: Destroy floatinglog window if there's no messages to show. Otherwise some earlier messages were displayed and confuse a user on arriving a new message (thanks to Ruslan Rakhmanin). 2009-10-27 Sergei Golovan * debug/debug.tcl: Moved menu to debug tools submenu. 2009-09-12 Sergei Golovan * attline/attline.tcl: Fixed removing expired attention line if it isn't drawn (thanks to Jan Zachorowski). 2009-08-16 Sergei Golovan * attline/msgs/es.msg, browser/msgs/es.msg, checkers/msgs/es.msg, chess/msgs/es.msg, debug/msgs/es.msg, ejabberd/msgs/es.msg, floatinglog/msgs/es.msg, georoster/msgs/es.msg, gmail/msgs/es.msg, jidlink/msgs/es.msg, openurl/msgs/es.msg, receipts/msgs/es.msg, renju/msgs/es.msg, reversi/msgs/es.msg, spy/msgs/es.msg, tclchat/msgs/es.msg, traffic/msgs/es.msg, whiteboard/msgs/es.msg: Updated Spanish translation (thanks to Badlop). * receipts/README: Fixed typos (thanks to Badlop). 2009-04-23 Sergei Golovan * receipts/receipts.tcl: Enabled receipts even if the confirmation message is received from a resource different from the resource where the initial message was sent to. It is useful if one sends a message to an offline resource and server reroutes it to an available one. 2009-04-01 Sergei Golovan * jidlink/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2009-03-31 Sergei Golovan * jidlink/jidlink.tcl, jidlink/plugins/*: Made Jidlink plugin unloadable. 2009-03-29 Sergei Golovan * georoster/georoster.tcl, tclchat/tclchat.tcl: Restored calls to ::http::geturl because it's finally fully wrapped and adopted for work with proxies. * tclchat/tclchat.tcl: Added version to http package requirement to prevent version 1.0 loading. 2009-03-27 Sergei Golovan * georoster/georoster.tcl: Use new proxied HTTP query for downloading US locations data. * receipts/receipts.tcl: Made receipts plugin unloadable. * tclchat/tclchat.tcl: Use new proxied HTTP query for downloading Tclers' chat history. * receipts/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2009-03-26 Sergei Golovan * spy/spy.tcl, tclchat/tclchat.tcl, tclchat/tclchat_commands.tcl, tclchat/tclchat_messages.tcl, traffic/traffic.tcl: Made Tclchat, Presence Spy and Traffic Counter plugins unloadable. * traffic/traffic.tcl: Fixed closing brackets (thanks to Roger Sondermann). * gmail/msgs/de.msg, spy/msgs/de.msg, traffic/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2009-03-25 Sergei Golovan * gmail/gmail.tcl, iconsets/iconsets.tcl, mute/mute.tcl: Made Gmail, iconsets and MUTE plugins unloadable. * checkers/checkers.tcl, chess/chess.tcl, poker/poker.tcl, renju/renju.tcl, reversi/reversi.tcl: Removed useless procedures from postload and finload hooks. 2009-03-22 Sergei Golovan * aniemoticons/msgs/de.msg, floatingcontact/msgs/de.msg, socials/msgs/de.msg, whiteboard/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2009-03-14 Sergei Golovan * floatingcontact/floatingcontact.tcl: Moved loading message catalog to a root namespace because the plugin uses several namespaces. * whiteboard/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). * openurl/openurl.tcl: Fixed popup menu in chat windows if it openes not over a URL. 2009-03-13 Sergei Golovan * whiteboard/svgrender.tcl, whiteboard/whiteboard.tcl: Fixed cid: URI usage. * openurl/openurl.tcl: Made plugin unloadable. Also, added a few browsers and a custom browser (thanks to Serge Yudin). * custom-urls/custom-urls.tcl, cyrillize/cyrillize.tcl, ejabberd/ejabberd.tcl, floatingcontact/floatingcontact.tcl, floatinglog/floatinglog.tcl, georoster/georoster.tcl: Made plugins unloadable. * georoster/georoster.tcl: Fixed reloading the plugin. * cyrillize/cyrillize.tcl: Fixed reading recoding table on the package loading. * whiteboard/whiteboard.tcl: Made whiteboard plugin unloadable. * ejabberd/msgs/de.msg, floatingcontact/msgs/de.msg, floatinglog/msgs/de.msg, georoster/msgs/de.msg, openurl/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2009-03-12 Sergei Golovan * whiteboard/svgrender.tcl, whiteboard/whiteboard.tcl: Switched to Bits of Binary (Xep-0231) interface when sending bitmaps. 2009-03-10 Sergei Golovan * poker/poker.tcl: Fixed bug with pot splitting. * poker/pixmaps/doods/*: Added another cards theme. 2009-03-09 Sergei Golovan * poker/*: Added new game plugin for playing heads up Poker (Texas hold'em). It is unfinished yet, but mostly usable. It uses long arithmetics, so requires Tcl/Tk 8.5 to work. * checkers/checkers.tcl, chess/chess.tcl, poker/poker.tcl, renju/renju.tcl, reversi/reversi.tcl: Adjusted priorities in games popup menu. 2009-03-08 Sergei Golovan * debug/debug.tcl: Fixed bug with plugin unloading. 2009-03-07 Sergei Golovan * checkers/checkers.tcl, chess/chess.tcl, renju/renju.tcl, reversi/reversi.tcl: Made Checkers, Chess, Renju and Reversi plugins unloadable. 2009-03-02 Sergei Golovan * aniemoticons/aniemoticons.tcl: Reload emoticons theme after enabling animated GIFs support. 2009-02-28 Sergei Golovan * whiteboard/whiteboard.tcl: Adapted to a change in output format in ::xmpp::delay::parse procedure. 2009-02-27 Sergei Golovan * debug/debug.tcl: Added calling procedure name to debug info. Also, added caps debug category. 2009-02-23 Sergei Golovan * browser/browser.tcl: Made Jabber Browser plugin unloadable. * attline/attline.tcl: Fixed typo. * browser/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). * attline/attline.tcl: Removed reconfiguring attention line script from event in chatlog windows on plugin unload. Also, changed attention line color definition to match dark themes as well, and adapted the plugin to Tcl/Tk 8.3. 2009-02-20 Sergei Golovan * aniemoticons/aniemoticons.tcl, attline/attline.tcl, debug/debug.tcl, socials/socials.tcl: Moved plugin preloading code to the main plugin files. * bc/bc.tcl, quiz/quiz.tcl: Made B&C and Quiz plugins unloadable. 2009-02-19 Sergei Golovan * attline/msgs/de.msg, debug/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2009-02-18 Sergei Golovan * socials/preload.tcl, socials/msgs/ru.msg: Added translation to plugin description in plugins management group. * debug/debug.tcl, debug/preload.tcl: Made debug plugin unloadable and let it collect TclXMPP related debug information. * debug/msgs/ru.msg: Update Russian translation. * aniemoticons/aniemoticons.tcl, aniemoticons/preload.tcl, aniemoticons/msgs/ru.msg: Made aniemoticons plugin unloadable. * attline/attline.tcl, attline/preload.tcl, attline/msgs/ru.msg: Made attention line plugin unloadable. 2009-02-17 Sergei Golovan * georoster/georoster.tcl: Fixed typo. * georoster/georoster.tcl: Fixed retrieving stored georoster data. * stripes/stripes.tcl: Lowered priority of tags which set background color for odd and even messages. Otherwise they overlayed the selection tag. 2009-02-16 Sergei Golovan * georoster/georoster.tcl: Deleted references to roster aliases as they were removed from Tkabber. 2009-02-13 Sergei Golovan * floatingcontact/floatingcontact.tcl: Slightly optimized roster rendering. 2009-02-11 Sergei Golovan * georoster/georoster.tcl: Use private XML storage interface from TclXMPP. 2009-01-10 Sergei Golovan * socials/preload.tcl, socials/socials.tcl: Made socials plugin unloadable without requiring Tkabber restart. 2008-11-15 Sergei Golovan * whiteboard/svgrender.tcl, whiteboard/whiteboard.tcl: Added preliminary bitmap support (though it doesn't conform SVG specifications, so it's currently intended to polish interface part and subsequently rewrite XML part). * whiteboard/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2008-11-09 Sergei Golovan * traffic/traffic.tcl: Adapted traffic plugin to new log callback from XMPP library. 2008-11-03 Sergei Golovan * jidlink/jidlink.tcl: Rewritten to use xmpp::negotiate package for method negotiation. * jidlink/plugins/filetransfer.tcl: A few bugfixes. 2008-10-26 Sergei Golovan * floatingcontact/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2008-10-25 Sergei Golovan * floatingcontact/msgs/de.msg, floatinglog/msgs/de.msg, debug/msgs/de.msg, openurl/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). * checkers/checkers.tcl, chess/chess.tcl, renju/renju.tcl, reversi/reversi.tcl: Rewrote invitation dialog to remove unnecessary vwait. * receipts/receipts.tcl: Added packet ID to function for chat_send_message_xlist_hook hook. Fixed packet ID processing for receipts. * tclchat/tclchat.tcl: Added packet ID to add_color function arguments. 2008-10-24 Sergei Golovan * tkabber-khim/tkabber-khim.tcl: Fixed settind option type. * floatingcontact/floatingcontact.tcl: Use normalized JID for storing floating contacts properties. 2008-10-23 Sergei Golovan * floatingcontact/floatingcontact.tcl: Fixed saving floating windows coordinates on disconnect and moved restoring them from loading stage to connected stage. 2008-10-22 Sergei Golovan * floatingcontact/*: Added a new plugin which allows roster contacts to float in separate small windows. 2008-10-20 Sergei Golovan * floatinglog/floatinglog.tcl: Added messages about following reconnect to an ignored messages list (thanks to Ruslan Rakhmanin). 2008-10-19 Sergei Golovan * browser/browser.tcl, floatinglog/floatinglog.tcl, georoster/georoster.tcl, receipts/receipts.tcl, singularity/singularity.tcl, tclchat/tclchat_messages.tcl, traffic/traffic.tcl: Replaced JID related procedures from utils.tcl (node_from_jid, server_from_jid, resource_from_jid, node_and_server_from_jid, tolower_node_and_domain) by procedures from xmpp::jid package (::xmpp::jid::node, ::xmpp::jid::server, ::xmpp::jid::resource, ::xmpp::jid::stripResource, ::xmpp::jid::normalize). * tclchat/tclchat_messages.tcl: Adapted client callback invocations to the changed syntax. 2008-10-18 Sergei Golovan * georoster/georoster.tcl: Fixed balloon text setting. * jidlink/jidlink.tcl: Fixed query namespace. * checkers/checkers.tcl, chess/chess.tcl, ejabberd/ejabberd.tcl, georoster/georoster.tcl, jidlink/jidlink.tcl, jidlink/plugins/filetransfer.tcl, renju/renju.tcl, reversi/reversi.tcl, spy/spy.tcl, whiteboard/whiteboard.tcl: Removed unnecessary call to format command. * georoster/georoster.tcl: Fixed typo. * checkers/checkers.tcl, mute/mute.tcl, renju/renju.tcl, reversi/reversi.tcl: Fixed XML elements creation and IQ query. * openurl/openurl.tcl: Optionally use flat menu for all browsers. * openurl/msgs/ru.msg: Updated Russian translation. 2008-10-17 Sergei Golovan * *: 0.11.1 is released. * *: Massive update caused by moving to an external XMPP library TclXMPP (http://code.google.com/p/tclxmpp/). * bc/bc.tcl, browser/browser.tcl, presencecmd/presencecmd.tcl, quiz/quiz.tcl, singularity/singularity.tcl, socials/socials.tcl, spy/spy.tcl: Fixed connections notation. * whiteboard/whiteboard.tcl: Fixed typo. * whiteboard/svgrender.tcl: Fixed typo. 2008-10-15 Sergei Golovan * quotelastmsg/*, singularity/*, stripes/*: Added three new plugins (thanks to Konstantin Khomoutov). 2008-08-26 Sergei Golovan * whiteboard/whiteboard.tcl: Converted draw actions back to radio buttons (it's too inefficient to use popup menu for them). Transform and remove actions are left in the popup menu. * whiteboard/msgs/ru.msg: Updated Russian translation. * README: Added description fo receipts and unixkeys plugins, cleared description for ctcomp plugins (thanks to Konstantin Khomoutov). * whiteboard/whiteboard.tcl: Fixed width of tools radiobuttons. * whiteboard/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2008-08-08 Sergei Golovan * checkers/checkers.tcl, chess/chess.tcl, renju/renju.tcl, reversi/reversi.tcl: Don't warn user about not received move replies on disconnect. * chess/chess.tcl: Added draw by repetition. * chess/msgs/ru.msg: Updated Russian translation. * chess/chess.tcl: Fixed bug with forbidden castling in case when pieces has moved. * chess/chess.tcl: Added possibility of castling and capture en passant to position code when counting repetitions. 2008-07-12 Sergei Golovan * whiteboard/whiteboard.tcl: Fixed typo. 2008-07-09 Sergei Golovan * whiteboard/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2008-07-08 Sergei Golovan * whiteboard/svgrender.tcl: Fixed rotation transform. Changed id canvas tags from id$id to [list id $id] form. * whiteboard/whiteboard.tcl: Added several object transformations. 2008-07-07 Sergei Golovan * whiteboard/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2008-07-06 Sergei Golovan * whiteboard/svgrender.tcl: Reworked SVG rendering, made all existing shapes transformable (except text), implemented all transformations, added several new attributes (stroke-linecap, stroke-linejoin etc.). Broken compatibility (the default outline color is empty now and not black). * whiteboard/whiteboard.tcl: Use svgrender for all elements rendering. Added a new rectangular shape. Moved all actions to a popup menu instead of radiobuttons. Added very preliminary (without user interface yet) tranformation support. 2008-06-18 Sergei Golovan * cyrillize/cyrillize.tcl: Added cyrillize bindings to all text and entry widgets. 2008-06-08 Sergei Golovan * unixkeys/README, unixkeys/TODO, unixkeys/unixkeys.tcl: Added bindings to entry widgets also (thanks to Konstantin Khomoutov). * Makefile: Added receipts and unixkeys to plugins list. * *: 0.11.0 is released. 2008-06-04 Sergei Golovan * receipts/msgs/pl.msg: Updated Polish translation (thanks to Irek Chmielowiec). * tclchat/msgs/es.msg, browser/msgs/es.msg, renju/msgs/es.msg, jidlink/msgs/es.msg, receipts/msgs/es.msg: Added Spanish translation (thanks to Badlop). * unixkeys/*: Added a small plugin which provides alternative bindings in Text widget close to Emacs and readline bindings (thanks to Konstantin Khomoutov). 2008-05-22 Sergei Golovan * floatinglog/msgs/ru.msg, receipts/msgs/ru.msg: Updated Russian translation. 2008-05-20 Sergei Golovan * receipts/msgs/ru.msg: Added Russian translation (thanks to Konstantin Khomoutov). 2008-05-18 Sergei Golovan * receipts/receipts.tcl: Allowed to return message receipts to private chat partners in a conference room. Removed per-user receipts customization (thanks to Konstantin Khomoutov). * receipts/TODO, receipts/README: Clarified receipts requesting/responding behavior (thanks to Konstantin Khomoutov). * receipts/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2008-05-14 Sergei Golovan * receipts/receipts.tcl: Fixed a bug with cleanup for JIDs that contain %. 2008-05-13 Sergei Golovan * receipts/receipts.tcl: Allowed to disable receipt queries and answers. Don't send receipts to users which aren't subscribed to our presence (thanks to Konstantin Khomoutov). * receipts/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2008-05-12 Sergei Golovan * tkabber-khim/khim/es.msg: Added Spanish transpation (thanks to Badlop). * receipts/msgs/pl.msg: Added Polish translation (thanks to Irek Chmielowiec). 2008-05-11 Sergei Golovan * receipts/*: Added new plugin which implements XEP-0184 (Message Receipts). Thanks to Konstantin Khomoutov. * debug/debug.tcl: Do not crash if debug messages are coming when main window and mainnotebook aren't created yet. * receipts/receipts.tcl: Added message catalogs support. * receipts/msgs/de.msg: Added German translation (thanks to Roger Sondermann). 2008-05-05 Sergei Golovan * openurl/openurl.tcl, openurl/msgs/*.msg: Open URL in a separate tab in Opera, and moved menu items for different browsers to a submenu (thanks to Alex Smirnov, closes http://www.jabber.ru/bugzilla/show_bug.cgi?id=379). 2008-04-16 Sergei Golovan * renju/renju.tcl: Implemented Renju game (without openings). 2008-03-23 Sergei Golovan * attline/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). * traffic/traffic.tcl, osd/osd.tcl: Removed usage of global font variable. 2008-01-28 Sergei Golovan * browser/browser.tcl, checkers/checkers.tcl, chess/chess.tcl, ejabberd/ejabberd.tcl, georoster/georoster.tcl, gmail/gmail.tcl, mute/mute.tcl, renju/renju.tcl, reversi/reversi.tcl, spy/spy.tcl, tclchat/tclchat.tcl: Removed usage of global font variable. 2008-01-20 Sergei Golovan * attline/attline.tcl: Fixed bug with leaving chatlog window in normal state if an attention doesn't need to be redrawn (thanks to Konstantin Khomoutov). 2008-01-16 Sergei Golovan * attline/attline.tcl: Removed tags ATLINE, made the line more thin, optimized line redrawing, state clearing moved to chat_close_post_hook (thanks to Konstantin Khomoutov). * attline/attline.tcl: Changed default line color from red to black. * floatinglog/floatinglog.tcl: Fixed bug with displaying message with empty body (thanks to Ruslan Rakhmanin). 2007-12-31 Sergei Golovan * gmail/gmail.tcl: Removed opening notifications window at Tkabber start and added it to Tkabber state saving/restoring. * browser/browser.tcl, checkers/checkers.tcl, chess/chess.tcl, ejabberd/ejabberd.tcl, georoster/georoster.tcl, gmail/gmail.tcl, renju/renju.tcl, reversi/reversi.tcl, spy/spy.tcl, traffic/traffic.tcl, whiteboard/whiteboard.tcl: Do not raise new tabs (when raise_new_tab is off) only if it isn't created by a Tkabber user himself, but by some external event (incoming message etc.). 2007-12-30 Sergei Golovan * ejabberd/msgs/de.msg: Added German translation (thanks to Roger Sondermann). 2007-12-26 Sergei Golovan * attline/attline.tcl: Fixed bug with processing Configure events which come before attention line is placed to its chat window. 2007-12-19 Sergei Golovan * floatinglog/floatinglog.tcl, latex/latex.tcl, tkabber-khim/khim/khim.tcl: Added -- to all switch commands. 2007-12-15 Sergei Golovan * checkers/checkers.tcl, chess/chess.tcl, renju/renju.tcl, reversi/reversi.tcl: Fixed invitation dialogs. 2007-12-06 Sergei Golovan * attline/attline.tcl: Fixed attention line width calculation (thanks to Konstantin Khomoutov). 2007-11-30 Sergei Golovan * attline/attline.tcl: Fixed attline state cleanup after closing chat window. 2007-11-29 Sergei Golovan * attline/attline.tcl: Fixed crash after closing chat tab/window before attline is expired if option 'remove expired attline' is turned on (thanks to Konstantin Khomoutov). 2007-11-25 Sergei Golovan * latex/latex.tcl: use [winfo rgb] to get RGB color instead of creating temporary image. * tclchat/tclchat.tcl: Fixed plugins::nickcolors::get_color call. * tclchat/tclchat_messages.tcl: Fixed processing Tkchat colors. 2007-11-14 Sergei Golovan * ctcomp/README: Added info about keybindings (thanks to Konstantin Khomoutov). * attline/BUGS: Removed since bugs mentioned in it are fixed (thanks to Konstantin Khomoutov). * attline/TODO: Removed already done tasks (thanks to Konstantin Khomoutov). * attline/README, attline/INSTALL: Added info about plugin and installation instructions (thanks to Konstantin Khomoutov). * ctcomp/README: A small fix (thanks to Konstantin Khomoutov). 2007-11-13 Sergei Golovan * checkers/checkers.tcl, chess/chess.tcl, renju/renju.tcl, reversi/reversi.tcl: Turned invitation dialogs to non-modal ones. 2007-11-08 Sergei Golovan * floatinglog/msgs/pl.msg, gmail/msgs/pl.msg, openurl/msgs/pl.msg, presencecmd/msgs/pl.msg: Added Polish translation (thanks to Irek Chmielowiec). * gmail/msgs/de.msg: Added German translation (thanks to Roger Sondermann). * spy/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-10-31 Sergei Golovan * attline/msgs/es.msg, chess/msgs/es.msg, ejabberd/msgs/es.msg, floatinglog/msgs/es.msg, georoster/msgs/es.msg, gmail/msgs/es.msg, openurl/msgs/es.msg, presencecmd/msgs/es.msg, tkabber-khim/msgs/es.msg: Added and updated Spanish translation (thanks to Badlop). 2007-10-28 Sergei Golovan * *: Tagged 0.10.1-beta2 for release. 2007-10-27 Sergei Golovan * floatinglog/floatinglog.tcl: Added an option for the height of floating log window, and made it ignore IBB file transfer requests (thanks to Ruslan Rakhmanin). * floatinglog/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-10-26 Sergei Golovan * ctcomp/ctcomp.tcl: Fixed definition of word edges (thanks to Konstantin Khomoutov). 2007-10-23 Sergei Golovan * floatinglog/floatinglog.tcl: Raise floatinlog window. It helps to keep it on top (thanks to Denis Shaposhnikov). 2007-10-14 Sergei Golovan * attline/attline.tcl: Changed atline namespace to attline, the same for debug type. Switched to chat::winid_to_chatid. Bound cleanup procedure to Chat window class instead of specific windows (thanks to Konstantin Khomoutov). * attline/msgs/ru.msg: Fixed Russian translation (thanks to Konstantin Khomoutov). * debug/debug.tcl: Added attline and tclchat debug types. Reorganized debug types menu into two-level menu. 2007-10-10 Sergei Golovan * floatinglog/floatinglog.tcl: Added new options which allow to show only personal messages (or MUC highlights) and allow not to show status changes (thanks to Konstantin Khomoutov). * floatinglog/floatinglog.tcl, floatinglog/msgs/ru.msg: Fixed processing (ignoring) idle status messages (thanks to Konstantin Khomoutov) * floatinglog/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-10-07 Sergei Golovan * floatinglog/floatinglog.tcl: Fixed doubleclick bindings to JIDs which contain %. Removed unused variables and useless message options. * floatinglog/TODO: Removed tasks which are already done or will never be done. * ctcomp/*: Added new plugin which allow to complete words from chat log windows (thanks to Konstantin Khomoutov). * Makefile, README: Added ctcomp plugin. * *: Tagged 0.10.1-beta for release. * floatinglog/floatinglog.tcl: Added extra geometry settings to fix the behavior under control of some window managers (openbox, ion3). 2007-10-06 Sergei Golovan * browser/browser.tcl: Replaced ::jlib::route by the first connection in cinnection list. * floatinglog/*, README, Makefile: Added new plugin which reports about incoming messages in a floating log window (thanks to Ruslan Rakhmanin). * openurl/openurl.tcl, openurl/msgs/ru.msg: Added support for translations and Russian message file. * floatinglog/floatinglog.tcl: Cleaned up messages. Changed time units for hide delay from milliseconds to seconds. * floatinglog/msgs/ru.msg: Added Russian translation. * floatinglog/msgs/de.msg, openurl/msgs/de.msg: Added German translation (thanks to Roger Sondermann). * floatinglog/floatinglog.tcl: Removed explicit usage of background and foreground resources. 2007-10-05 Sergei Golovan * README: Added missing descriptions. * Makefile: Added custom-urls to a list of plugins to install. 2007-09-23 Sergei Golovan * aniemoticons/anigif.tcl: Fixed some GIF images processing (thanks to Ruslan Rakhmanin). 2007-09-21 Sergei Golovan * georoster/georoster.tcl: Use separated public XML storage interface. 2007-09-10 Sergei Golovan * presencecmd/msgs/de.msg: Added German translation (thanks to Roger Sondermann). 2007-09-08 Sergei Golovan * jidlink/msgs/de.msg: Added German translation (thanks to Roger Sondermann). 2007-09-05 Sergei Golovan * attline/msgs/pl.msg, browser/msgs/pl.msg, ejabberd/msgs/pl.msg, georoster/msgs/pl.msg, jidlink/msgs/pl.msg: Updated Polish translation (thanks to Irek Chmielowiec). * gmail/gmail.tcl, presencecmd/presencecmd.tcl: Made user messages translateable. * gmail/msgs/ru.msg, presencecmd/msgs/ru.msg: Added Russian translation. 2007-09-03 Sergei Golovan * gmail/gmail.tcl: Fixed bug with empty disabledForeground option. 2007-09-02 Sergei Golovan * tkabber-khim/tkabber-khim.tcl: Removed unnecessary namespace level. * gmail/gmail.tcl: Added new plugin which allows users of Google Talk service to get Gmail notifications. * openurl/openurl.tcl: Added new plugin which allows to open URLs in any installed browser found in PATH environment variable. 2007-09-01 Sergei Golovan * browser/msgs/de.msg, browser/msgs/ru.msg: Added SVN Id attribute. * jidlink/msgs/ru.msg: Fixed SVN Id attribute. 2007-08-31 Sergei Golovan * jidlink/*: New Jidlink support plugin. Jidlink support is removed from main Tkabebr distribution because it is obsolete and undocumented and superseeded by Stream Initiation. * Makefile: Added browser and jidlink plugins to a plugin list. 2007-08-30 Sergei Golovan * browser/*: New Jabber Browser (XEP-0011) support plugin. It was removed from main Tkabber distribution because it is deprecated. * browser/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-08-18 Sergei Golovan * attline/attline.tcl: Code cleanup. Do not expire attention line if it is already expired. * presencecmd/presencecmd.tcl: Code cleanup. * attline/attline.tcl: Added support for message catalogs. * attline/msgs/ru.msg: Added Russian translation. * attline/msgs/de.msg, debug/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-08-17 Sergei Golovan * attline/*: Added new plguin which draws an attention line in chat windows (thanks to Konstantin Khomoutov). * presencecmd/*: Added new plugin which introduces several chat commands changing user's presence information (thanks to Konstantin Khomoutov). * README: Added short descriptions of attline and presencecmd plugins. * Makefile: Added new plugins. * attline/*, presencecmd/*: Changed eol style to native. * attline/attline.tcl: Removed using control package to not force adding it to a strapacks, and unconditionally use real priority value in hook::add because it isn't necessary to use this plugin in earlier Tkabber versions. 2007-08-11 Sergei Golovan * bc/bc.tcl, checkers/checkers.tcl, chess/chess.tcl, mute/mute.tcl, quiz/quiz.tcl, renju/renju.tcl, reversi/reversi.tcl, whiteboard/whiteboard.tcl: Renamed [random] procedure to [rand] to prevent clash with one from Memchan package, which is loaded for JISP support. 2007-08-09 Sergei Golovan * quiz/quiz.tcl: Fixed hinting and added displaying the correct answer if nobody has found it (thanks to Alexander Kupcov). 2007-06-24 Sergei Golovan * tclchat/tclchat.tcl: Changed loginconf options according to changes in login.tcl. 2007-06-12 Sergei Golovan * georoster/georoster.tcl: Fixed typo. * custom-urls/custom-urls.tcl, README: Added new plugin, which allows to specify custom URLs based on regular expressions. * georoster/georoster.tcl: Fixed variable initialization. * custom-urls/custom-urls.tcl: Added an example of custom URLs. 2007-06-11 Sergei Golovan * georoster/georoster.tcl: Fixed drag'n'drop of JIDs over Georoster window. Store georoster contacts separately for each Tkabber connection (while showing them in one window). * georoster/msgs/ru.msg, georoster/msgs/uk.msg: Updated. * georoster/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-06-10 Sergei Golovan * ejabberd/ejabberd.tcl: Added connection choice to a dialog of selecting ejabberd server to administrate. Also, allowed opening several windows to the same JID from different connections. Also, clean up data variables on page close. * ejabberd/msgs/ru.msg, ejabberd/msgs/uk.msg: Updated. 2007-06-09 Sergei Golovan * tkabber-khim/khim/khim.tcl: Added khim package forgetting command to load really newest khim version. 2007-06-04 Sergei Golovan * whiteboard/svgrender.tcl: Ignore surrounding spaces in point lists. * ChangeLog: Fixed year in recent changelog entry dates. 2007-04-12 Sergei Golovan * *: 0.10.0 is released. * README: Added description for renju and tclchat plugins. 2007-04-08 Sergei Golovan * tclchat/tclchat.tcl: Fixed init routine priority. * renju/renju.tcl: Do not reply to game type 'renju' calls because this type is not implemented yet. 2007-04-02 Sergei Golovan * georoster/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-03-28 Sergei Golovan * traffic/traffic.tcl: Added scrolling by mousewheel (thanks to Artem Borodin). 2007-03-27 Sergei Golovan * mute/mute.tcl: Fixed bug with breaking messages into separate words in message dialogs. * tclchat/tclchat.tcl: Fixed restoring disabled state of Tclers' chat window. 2007-03-22 Sergei Golovan * traffic/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-03-17 Sergei Golovan * debug/msgs/es.msg, spy/msgs/es.msg: Updated Spanish translation (thanks to Badlop). 2007-03-14 Sergei Golovan * debug/msgs/pl.msg, spy/msgs/pl.msg: Updated Polish translation (thanks to Irek Chmielowiec). 2007-03-11 Sergei Golovan * debug/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-03-10 Sergei Golovan * georoster/georoster.tcl: Added -connection argument to jlib::send_iq call. * debug/debug.tcl: Made jlib module debug messages more clear. 2007-03-08 Sergei Golovan * tclchat/tclchat.tcl: Load translated messages. * tclchat/msgs/ru.msg, mute/msgs/ru.msg: Added Russian translation. * debug/msgs/ru.msg, renju/msgs/ru.msg: Updated Russian translation. 2007-03-06 Sergei Golovan * latex/msgs.de.msg, spy/msgs/de.msg, traffic/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-03-04 Sergei Golovan * aniemoticons/aniemoticons.tcl, aniemoticons/anigif.tcl: Bugfix. Fixed creating and destroying images. * debug/debug.tcl, spy/spy.tcl: Use new unified search panel interface. * aniemoticons/anigif.tcl: Code cleanup. Fixed bugs with image names, which contain semicolon. * Makefile: Added installing of aniemoticons plugin. * *: 0.10.0-beta2 is released. * spy/msgs/de.msg, traffic/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-03-03 Sergei Golovan * aniemoticons/*: Added new external plugin (moved from the main Tkabber tree). Also applied patch by Ruslan Rakhmanin, which fixes some animated GIFs processing and improves performance. * README: Added short description of aniemoticons plugin. 2007-02-26 Sergei Golovan * renju/pixmaps/black/*: Added high contrast Gomoku/Renju theme. * whiteboard/msgs/de.msg: Added German translation (thanks to Roger Sondermann). 2007-02-25 Sergei Golovan * debug/msgs/de.msg, georoster/msgs/de.msg, spy/msgs/de.msg, traffic/msgs/de.msg: Added German translation (thanks to Roger Sondermann). * georoster/msgs/de.msg: Updated German translation (thanks to Roger Sondermann). 2007-02-23 Sergei Golovan * Makefile: Added tclchat and renju plugins. * *: 0.10.0-beta is released. 2007-02-17 Sergei Golovan * renju/renju.tcl: Added tournament Gomoku variant (with 5x5 forbidden zone for black at the second turn). 2007-02-16 Sergei Golovan * checkers/checkers.tcl, chess/chess.tcl, renju/renju.tcl, reversi/reversi.tcl: Fixed bug with sometimes undeleted cell border on mouse leave. * renju/renju.tcl: Added standard Gomoku variant (where overline is not a win). 2007-02-15 Sergei Golovan * renju/*: New game plugin Gomoku/Renju (unfinished yet, only free-style Gomoku is implemented). 2007-02-14 Sergei Golovan * tclchat/tclchat.tcl: Added customize group Tclchat. * tclchat/tclchat_messages.tcl: Made bridge nick and JID, and Tclers' chat room JID customizable. Added processing of nickname changes on the IRC side. * reversi/msgs/pl.msg, debug/msgs/pl.msg, whiteboard/msgs/pl.msg, spy/msgs/pl.msg: Updated Polish translation (thanks to Irek Chmielowiec). 2007-02-13 Sergei Golovan * debug/msgs/es.msg, spy/msgs/es.msg, whiteboard/msgs/es.msg: Updated Spanish translation (thanks to Badlop). * tclchat/tclchat.tcl, tclchat/tclchat_commands.tcl, tclchat/tclchat_messages.tcl: Added modified tclchat plugin by Pat Thoyts for more comfortable use of Tclers' chat (unfinished yet). * tclchat/tclchat.tcl: Moved adding color to more suitable hook. * tclchat/tclchat_messages.tcl: Added IRC users, connected to Tclers' chat, to the conference roster. 2007-02-11 Sergei Golovan * iconsets/icq/icondef.xml, iconsets/icq/tkabber/tkabber-logo.gif: Removed logo (it must be only one). * iconsets/icq/tkabber/new-msg.gif: Removed unused icon. * iconsets/kroc/tkabber/new-msg.gif, iconsets/kroc/tkabber/search_bk.gif, iconsets/kroc/tkabber/search_case.gif, iconsets/kroc/tkabber/search_exact.gif, iconsets/kroc/tkabber/search_fw.gif: Removed unused icons. * whiteboard/whiteboard.tcl: Made using jlib::x_delay for computing message time. * georoster/georoster.tcl, spy/spy.tcl, traffic/traffic.tcl: Save tabs on exit and restore on start. * bc/bc.tcl, quiz/quiz.tcl, osd/osd.tcl, mute/mute.tcl: Made working with current Tkabber version. * quiz/quizdata.txt: Added short quiz data sample. * COPYING, Makefile: Added license file and Makefile. 2007-02-10 Sergei Golovan * whiteboard/whiteboard.tcl, whiteboard/svgrender.tcl: Added balloons, which show when the whiteboard item was created, and who has drawn it. Also redone text input dialog. * whiteboard/msgs/ru.msg: Updated. * README, checkers/README, debug/debug.tcl, debug/msgs/pl.msg, debug/msgs/ru.msg, socials/README, spy/spy.tcl, tkabber-khim/INSTALL: Made more accurate references to Tkabber config directory. 2007-02-09 Sergei Golovan * iconsets/iconsets.tcl, iconsets/*: Moved borrowed iconsets to a separate plugin. * README: Updated. * whiteboard/whiteboard.tcl: Removed spacers from whiteboard toolbar to make it fit 800x600 window. 2007-01-29 Sergei Golovan * spy/spy.tcl: Fixed a typo (thanks to Pavel Borzenkov). 2007-01-27 Sergei Golovan * spy/spy.tcl: Added search in spy presence window. * debug/debug.tcl: Added search in debug window. * quiz/quiz.tcl: Added check for existence of file 3hauka.txt. 2007-01-26 Sergei Golovan * checkers/checkers.tcl, chess/chess.tcl, debug/debug.tcl, ejabberd/ejabberd.tcl, georoster/georoster.tcl, reversi/reversi.tcl, whiteboard/whiteboard.tcl: Removed explicit tab updates on raise. * debug/debug.tcl: Added richtext and mucignore modules to debug modules. Fixed bug with unknown debug module. 2007-01-11 Sergei Golovan * cyrillize/cyrillize.tcl: Added backward conversion from russian to english (bound to ). Also, added bindings for cyrillic layout in Windows. 2007-01-06 Sergei Golovan * debug/debug.tcl, traffic/traffic.tcl: Changed config directory references to $::configdir. 2007-01-05 Sergei Golovan * debug/msgs/pl.msg, tkabber-khim/khim/pl.msg, whiteboard/msgs/pl.msg: Updated (thanks to Irek Chmielowiec). 2007-01-03 Sergei Golovan * debug/debug.tcl: Made plugin options customizeable via GUI. * debug/msgs/ru.msg: Updated. * debug/msgs/es.msg, debug/msgs/pl.msg, debug/msgs/uk.msg: Added VIM modeline. * tkabber-khim/tkabber-khim.tcl, tkabber-khim/khim/pl.msg, tkabber-khim/khim/ru.msg, tkabber-khim/msgs/pl.msg, tkabber-khim/msgs/ru.msg: Added newline to a message, which is printed to the terminal when KHIM cannot be loaded, to fit 80 symbol width. 2007-01-01 Sergei Golovan * tkabber-khim/msgs/ru.msg, whiteboard/msgs/ru.msg: Updated. 2006-12-30 Sergei Golovan * checkers/msgs/es.msg, chess/msgs/es.msg, reversi/msgs/es.msg, whiteboard/msgs/es.msg: Updated (thanks to Badlop). * traffic/traffic.tcl, traffic/msgs/pl.msg, traffic/msgs/ru.msg, traffic/msgs/uk.msg: Bugfix in translated string (thanks to Badlop). 2006-12-29 Sergei Golovan * tkabber-khim/khim/pl.msg, tkabber-khim/msgs/pl.msg: Added Polish translation (thanks to Irek Chmielowiec). * whiteboard/msgs/pl.msg: Updated (thanks to Irek Chmielowiec). * tkabber-khim/khim/uk.msg: Added Ukrainian translation (thanks to Artem Bondarenko). 2006-12-28 Sergei Golovan * whiteboard/whiteboard.tcl: Added whiteboard saving option. 2006-12-24 Sergei Golovan * reversi/msgs/uk.msg, debug/msgs/uk.msg, checkers/msgs/uk.msg, ejabberd/msgs/uk.msg, chess/msgs/uk.msg, georoster/msgs/uk.msg, spy/msgs/uk.msg, latex/msgs/uk.msg, traffic/msgs/uk.msg: Added Ukrainian translation (thanks to Artem Bondarenko). 2006-12-17 Sergei Golovan * tkabber-khim/khim/khim.tcl: Bumped khim version number to ensure its loading. 2006-12-15 Sergei Golovan * tkabber-khim/khim/khim.tcl: Changed Unicode charmap colors. 2006-12-13 Sergei Golovan * tkabber-khim/*: Added tkabber-khim plugin by Konstantin Khomoutov. It allows to input Unicode characters using KHIM package by Kevin Kenny. KHIM package is included, but it can be also obtained as part of tklib. 2006-12-05 Sergei Golovan * osd/osd.tcl: Don't notify on history messages read from the log files. 2006-12-03 Sergei Golovan * whiteboard/svgrender.tcl, whiteboard/whiteboard.tcl, whiteboard/msgs/ru.msg: Added circle and polygon whiteboard figures (thanks to Pavel Arajums). 2006-11-27 Sergei Golovan * debug/debug.tcl: Added loading translation messages. * reversi/msgs/pl.msg, debug/msgs/pl.msg, checkers/msgs/pl.msg whiteboard/msgs/pl.msg, ejabberd/msgs/pl.msg, chess/msgs/pl.msg, georoster/msgs/pl.msg, spy/msgs/pl.msg, traffic/msgs/pl.msg: Added Polish translation (thanks to Irek Chmielowiec). 2006-11-25 Sergei Golovan * georoster/georoster.tcl: Replaced erroneous user_from_jid by node_and_server_from_jid. 2006-11-24 Sergei Golovan * whiteboard/whiteboard.tcl: Use mousewheel to scroll whiteboard window. 2006-11-04 Sergei Golovan * latex/latex.tcl: Updated to match current emoticons engine. Changed LaTeX expression regexp to allow spaces in it. 2006-10-22 Sergei Golovan * whiteboard/svgrender.tcl: Check color existence before rendering whiteboard item using this color. 2006-10-08 Sergei Golovan * checkers/msgs/ru.msg, chess/msgs/ru.msg, reversi/msgs/ru.msg: Updated (thanks to Pavel Borzenkov). * README: Added new plugins description. Replaced JEP abbreviation by XEP. 2006-10-05 Sergei Golovan * checkers/checkers.tcl, chess/chess.tcl, ejabberd/ejabberd.tcl, georoster/georoster.tcl, latex/latex.tcl, reversi/reversi.tcl, traffic/traffic.tcl, whiteboard/whiteboard.tcl: Removed changing of system encoding when loading translated messages because msgcat itself uses UTF-8. * osd/osd.tcl: Removed encoding configuring of osdcat pipe because it is a system encoding by default. * whiteboard/msgs/uk.msg: Added Ukrainian translation (thanks to Mykola Dzham). 2006-10-02 Sergei Golovan * reversi/reversi.tcl: Fixed typo (thanks to Irek Chmielowiec). 2006-09-30 Sergei Golovan * georoster/georoster.tcl: Use options menu with nonfixed border width. 2006-09-29 Sergei Golovan * checkers/checkers.tcl, chess/chess.tcl, georoster/georoster.tcl, reversi/reversi.tcl: Replaced customizeable radio variables by options variables. 2006-09-27 Sergei Golovan * checkers/checkers.tcl, chess/chess.tcl, reversi/reversi.tcl: Added sound notification of opponent's move (thanks to Pavel Borzenkov). 2006-09-25 Sergei Golovan * debug/debug.tcl: Added several debug categories. * latex/msgs/es.msg, traffic/msgs/es.msg: Added Spanish translation (thanks to Badlop). * whiteboard/msgs/es.msg: Updated (thanks to Badlop). 2006-09-19 Sergei Golovan * traffic/traffic.tcl: Code cleanup. * checkers/checkers.tcl, chess/chess.tcl, mute/mute.tcl, reversi/reversi.tcl: Added lang parameter to procedures registered via iq:register. 2006-09-16 Sergei Golovan * chess/chess.tcl, checkers/checkers.tcl, reversi/reversi.tcl: Made games using hook::run with upvar instead of hook::foldl (it looks more "ticklish"). Improved packing of game history windows. * traffic/*: Added new traffic accounting plugin. It counts total length of unencrypted and/or uncompressed XML stanzas only (thanks to Artem Borodin). tkabber-plugins/Makefile000064400000000000000000000030461500237002100151540ustar00nobodynobody# Tkabber plugins Makefile PREFIX = /usr/local TKABBERPLUGINSDIR = $(PREFIX)/share/tkabber-plugins DOCDIR = $(PREFIX)/share/doc/tkabber-plugins SUBDIRS = aniemoticons \ attline \ battleship \ bc \ browser \ checkers \ chess \ ctcomp \ custom-urls \ cyrillize \ debug \ ejabberd \ filters \ floatingcontact \ floatinglog \ georoster \ gmail \ iconsets \ jidlink \ latex \ mute \ openurl \ osd \ otr \ poker \ presencecmd \ quiz \ quotelastmsg \ receipts \ renju \ reversi \ singularity \ socials \ spy \ stripes \ tclchat \ tkabber-khim \ traffic \ unixkeys \ whiteboard install: install-bin install-doc install-bin: install -d $(DESTDIR)/$(TKABBERPLUGINSDIR) cp -dr --no-preserve=ownership $(SUBDIRS) $(DESTDIR)/$(TKABBERPLUGINSDIR) @echo "" @echo "" @echo "" @echo "To enable desired plugins copy or link their directories to ~/.tkabber/plugins/" @echo "" @echo "" @echo "" install-doc: install -d $(DESTDIR)/$(DOCDIR) install -m 644 COPYING ChangeLog README $(DESTDIR)/$(DOCDIR) # Update Tkabber plugins from Fossil repository up: test -f .fslckout -o -f _FOSSIL_ && fossil pull && fossil update .PHONY: install install-bin install-doc up tkabber-plugins/README000064400000000000000000000147551500237002100144050ustar00nobodynobodyExternal Plugins for Tkabber To install the desired plugins copy the plugin directories to $HOME/.tkabber/plugins (on UNIX), to %APPDATA%\Tkabber\plugins (on Windows), or to $HOME/Library/Application Support/Tkabber (on MacOS X) directory. Tkabber will automatically load the plugins when it's started. To actually use them you'll have to enable the desired plugins in Tkabber plugins management interface. The plugins that you will surely want to try are: Chess, OTR, and Whiteboard. Short Description of the Included Plugins aniemoticons Plugin which adds support of animated emoticons. attline Plugin which draws so-called attention line - a line before the first message in a chat window where the window has lost keyboard focus. All messages after the line are unread messages. battleship A paper & pencil board game of battleship where players try to sink the opponent's ships. When installed, you can send an invitation to your contact (contextual menu on the roster). If the other player has also Tkabber and the plugin installed, he will recieve the invitation. If he accepts, a window will open on both. bc A word game. Inludes a russian file. browser Plugin which implements Jabber Browser (XEP-0011). This protocol is deprecated in favor of Service Discovery (XEP-0030), but may be useful for pre-XMPP servers/transports. checkers Checkers game for two players (including Straight, Russian, Spanish, Brazilian, Pool, Italian checkers). When installed, you can send an invitation to your contact (contextual menu on the roster). If the other player has also Tkabber and the plugin installed, he will recieve the invitation. If he accepts, a window will open on both. chess Chess game for two players. When installed, you can send an invitation to your contact (contextual menu on the roster). If the other player has also Tkabber and the plugin installed, he will recieve the invitation. If he accepts, a window will open on both. ctcomp Plugin adds support for "text completion" in Tkabber's chat input windows which works like the similar features of the Vim and Emacs text editors. The matching words are picked from the corresponding chat log and input windows. custom-urls Provides regexp-based mechanism to convert strings with numbers to URLs in chat windows. cyrillize Utility to translate misprinted characters to cyrillic pressing Ctrl+'. debug Allows to see debug messages in separate tab/window. ejabberd Utility to check your Ejabberd Jabber server remotely. filters Provides support for long time obsolete Jabberd 1.4 mod_filter rules. floatingcontact Allows roster items to float in separate small windows. floatinglog Plugin reports incoming messages, presence changes, status changes in a separate floating window. georoster World map. It tries to position your contacts using the data on vcard. You can also drag and drop your contacts from the roster on their possitions. gmail Plugin allows Gmail/Googlemail users to receive mail notifications. iconsets Several iconsets, borrowed from other Jabber clients, now are represented in this plugin. jidlink Implements Jidlink file transfer protocol. It's undocumented and obsolete, but may be useful for transferring files to old Tkabber versions. latex Displays formulas in LaTeX notation as embedded images, generated by LaTeX and ImageMagick. mute Experimental implementation of XEP-0058: Multi-User Text Editing, now deferred. openurl Plugin which adds several items to a URL popup menu. Each item allows to open the URL in a certain browser. osd Displays certain events (presence and chat messages) notification using osd_cat utility. otr Off-the-Record cryptographic protocol that provides strong encryption for instant messaging conversations (https://otr.cypherpunks.ca/). poker Heads up Texas holdem. When installed, you can send an invitation to your contact (from the popup menu in the roster). If the other player has also Tkabber and the plugin installed, he will recieve the invitation. If he accepts, a window will open on both and game will start. presencecmd Plugin which adds several commands in a chat window. They change user's presence information (global or directed). quiz Adaptation of He3hauka (a russian quiz game for IRC). quotelastmsg Quote the very last message in a chat window. receipts Implements XEP-0184 "Message receipts": in one-to-one chat sessions it is able to request confirmations of reception of outgoing messages and reply to such requests coming from remote party. renju Gomoku and Renju game for two players. When installed, you can send an invitation to your contact (from a popup menu in the roster). If the other player has also Tkabber and the plugin installed, he will recieve the invitation. If he accepts, a window will open on both. reversi Reversi (Othello) game for two players. When installed, you can send an invitation to your contact (contextual menu on the roster). If the other player has also Tkabber and the plugin installed, he will recieve the invitation. If he accepts, a window will open on both. singularity Keep conversation with one user in one window/tab. socials Adds many 'social' commands like /dance. Includes english and russian files. spy Logs your contacts presence changes to a window or to a file. Allows to setup alert window for certain contacts. stripes Colorises chat window background for odd and even messages differently. tclchat Plugin, which makes chatting in Tclers' chat (tcl@tach.tclers.tk) easier. It recognises a bot, which connects Jabber room with IRC channel, and maps IRC users to Jabber conference participants. tkabber-khim Plugin that adds KHIM (an alternative input method by Kevin Kenny) support to Tkabber. traffic Approximately accounts incoming and outgoing XMPP traffic by addressees. Traffic estimation is good only if no stream compression or encryption is used. But even if the absolute values are incorrect, it still allows to find which remote JID consumes the highest traffic amount. unixkeys Adds support for "Unix-style" (in fact, GNU Readline and GNU bash -style) keyboard shortcuts for text editing to all text entry widgets in Tkabber. whiteboard Shared whiteboard, allows two contacts or a whole chatroom to draw collaboratively. tkabber-plugins/aniemoticons000075500000000000000000000000001500237002100161225ustar00nobodynobodytkabber-plugins/aniemoticons/aniemoticons.tcl000064400000000000000000000051141500237002100213760ustar00nobodynobody# aniemoticons.tcl -- # # This file is a part of Aniemoticons plugin for the Tkabber XMPP # client. This plugin replaces the ::plugins::emoticons::create_image # and ::plugins::emoticons::delete_image by the animated GIFs aware # procedures. The plugin can be loaded and unloaded dynamically. package require msgcat namespace eval aniemoticons { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered aniemoticons]} { ::plugins::register aniemoticons \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the animated\ GIFs support plugin\ is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } } namespace eval :: { source [file join [file dirname [info script]] anigif.tcl] } proc aniemoticons::load {} { rename ::plugins::emoticons::create_image \ ::plugins::emoticons::create_image:anigif rename ::plugins::emoticons::delete_image \ ::plugins::emoticons::delete_image:anigif proc ::plugins::emoticons::create_image {name args} { if {[dict exists $args -file]} { set file [dict get $args -file] if {[catch {::anigif::anigif $name $file} res]} { ::create_image $name {*}$args return $name } else { return $res } } else { ::create_image $name {*}$args return $name } } proc ::plugins::emoticons::delete_image {name} { ::anigif::destroy $name } ::plugins::emoticons::on_theme_changed return } proc aniemoticons::unload {} { if {[llength [info procs \ ::plugins::emoticons::create_image:anigif]] == 0 || \ [llength [info procs \ ::plugins::emoticons::delete_image:anigif]] == 0} { return } rename ::plugins::emoticons::create_image "" rename ::plugins::emoticons::delete_image "" rename ::plugins::emoticons::create_image:anigif \ ::plugins::emoticons::create_image rename ::plugins::emoticons::delete_image:anigif \ ::plugins::emoticons::delete_image foreach name [image names] { ::anigif::stop $name } namespace delete ::anigif } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/aniemoticons/anigif.tcl000064400000000000000000000143251500237002100201470ustar00nobodynobody# AniGif Package written in pure Tcl/Tk # # anigif.tcl v1.3 2002-09-09 (c) 2001-2002 Ryan Casey # # AniGif is distributed under the same license as Tcl/Tk. As of # AniGif 1.3, this license is applicable to all previous versions. # # Modified by Alexey Shchepin # # ############################### USAGE ################################# # # ::anigif::anigif IMAGE FILENAME INDEX # FILENAME: appropriate path and file to use for the animated gif # INDEX: what image to begin on (first image is 0) (Default: 0) # # ::anigif::stop IMAGE # ::anigif::restart IMAGE INDEX # INDEX: defaults to next index in loop # ::anigif::destroy IMAGE # # NOTES: # There is currently a -zoom and -subsample hack to keep transparency. # Anigif does not handle interlaced gifs properly. The image will look # distorted. # A delay of 0 renders as fast as possible, per the GIF specification. # This is currently set to 40 ms to approximate the IE default. # If you experience a problem with a compressed gif, try uncompressing # it. Search the web for gifsicle. # # ############################## HISTORY ################################# # # 1.3: Fixed error in disposal flag handling. # Added handling for non-valid comment/graphic blocks. # Searches for actual loop control block. If it extists, loops. # Added more comments. # 1.2: Now handles single playthrough gifs or gifs with partial images # Fixed bug in delay time (unsigned int was being treated as signed) # 1.1: Reads default timing instead of 100 ms or user-defined. # You can no longer set the delay manually. # 1.0: Moved all anigif variables to the anigif namespace # 0.9: Initial release # namespace eval ::anigif { variable image_number 0 } proc ::anigif::anigif2 {img list delay {idx 0}} { if {$idx >= [llength $list]} { set idx 0 if {$::anigif::img(repeat,$img) == 0} { # Non-repeating GIF ::anigif::stop $img return } } set disposal_idx $idx incr disposal_idx -1 if {$disposal_idx <= 0} { set disposal_idx 0 } if {$idx == 0} { set dispflag "010" } else { set dispflag [lindex $::anigif::img(disposal,$img) $disposal_idx] } switch -- "$dispflag" { "000" { # Do nothing } "100" { # Do not dispose } "010" { # Restore to background $::anigif::img(curimage,$img) blank } "110" { # Restore to previous - not supported # As recommended, since this is not supported, it is set to blank [set ::anigif::img(curimage,$img)] blank } default { puts "no match: $dispflag" } } $::anigif::img(curimage,$img) copy [lindex $list $idx] if {[lindex $delay $idx] == 0} { ::anigif::stop $img return } # # # update set ::anigif::img(asdf,$img) [list ::anigif::anigif2 $img $list] set ::anigif::img(loop,$img) \ [after [lindex $delay $idx] \ [list eval $::anigif::img(asdf,$img) \ [list $delay [expr {$idx + 1}]]]] set ::anigif::img(idx,$img) [incr idx] } proc ::anigif::anigif {img fnam {idx 0}} { variable image_number ::anigif::stop $img set n 0 set images {} set delay {} set disposal {} set reserved {} #set img anigifimage[incr image_number] #set img [image create photo] image create photo $img set fin [open $fnam r] fconfigure $fin -translation binary set data [read $fin [file size $fnam]] close $fin # Find Loop Record set start [string first "\x21\xFF\x0B" $data] if {$start < 0} { set repeat 0 } else { set repeat 1 } # Find Control Records set start [string first "\x21\xF9\x04" $data] while {![catch {create_image xpic$n$img \ -file $fnam \ -format [list gif89 -index $n]}]} { set stop [expr $start + 7] set record [string range $data $start $stop] binary scan $record @4s thisdelay if {[info exists thisdelay]} { # Change to unsigned integer #set thisdelay [expr {$thisdelay & 0xFF}]; binary scan $record @3b5 disposalval set disposalval [string range $disposalval 2 end] lappend images pic$n$img image create photo pic$n$img pic$n$img copy xpic$n$img image delete xpic$n$img lappend disposal $disposalval # Convert hundreths to thousandths for after set thisdelay [expr {$thisdelay * 10}] # If 0, set to fastest (25 ms min to seem to match browser default) if {$thisdelay == 0} {set thisdelay 40} lappend delay $thisdelay unset thisdelay incr n } if {($start >= 0) && ($stop >= 0)} { set start [string first "\x21\xF9\x04" $data [expr {$stop + 1}]] } else { break } } set ::anigif::img(repeat,$img) $repeat set ::anigif::img(delay,$img) $delay set ::anigif::img(disposal,$img) $disposal set ::anigif::img(curimage,$img) $img $img blank $img copy pic0${img} #$img configure -image [set ::anigif::img(curimage,$img)] anigif2 $img $images $delay $idx return $img } proc ::anigif::stop {img} { catch { after cancel $::anigif::img(loop,$img) } } # TODO proc ::anigif::restart {img {idx -1}} { if {$idx == -1} { if {[lindex $::anigif::img(delay,$img) $idx] < 0} { set idx 0 } else { set idx $::anigif::img(idx,$img) } } catch { ::anigif::stop $img eval $::anigif::img(asdf,$img) [list $::anigif::img(delay,$img) $idx] } } proc ::anigif::destroy {img} { catch { ::anigif::stop $img foreach imagename [image names] { if {[regexp {^pic\d+(.*)} $imagename -> tail] && \ [string equal $tail $img]} { image delete $imagename } } image delete $img array unset ::anigif::img *,$img } } package provide anigif 2.0 # vim:ts=8:sw=4:sts=4:et tkabber-plugins/aniemoticons/msgs000075500000000000000000000000001500237002100170735ustar00nobodynobodytkabber-plugins/aniemoticons/msgs/de.msg000064400000000000000000000004241500237002100202520ustar00nobodynobody# de.msg -- # # German messages for Aniemoticons Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 15.03.2009 ::msgcat::mcset de "Whether the animated GIFs support plugin is loaded." \ "Animierte-GIFs-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/aniemoticons/msgs/ru.msg000064400000000000000000000005471500237002100203160ustar00nobodynobody# ru.msg -- # # Russian messages for Aniemoticons Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Whether the animated GIFs support plugin is loaded." \ "Загружено ли раÑширение обеÑпечивающее поддержку анимационных GIFов." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/aniemoticons/msgs/uk.msg000064400000000000000000000005311500237002100203000ustar00nobodynobody# uk.msg -- # # Ukrainian messages for Aniemoticons Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Whether the animated GIFs support plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ñ€Ð¸Ð¼ÐºÐ¸ анімаційних GIFів." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/attline000075500000000000000000000000001500237002100150725ustar00nobodynobodytkabber-plugins/attline/AUTHORS000064400000000000000000000000661500237002100162230ustar00nobodynobodyKonstantin Khomoutov tkabber-plugins/attline/INSTALL000064400000000000000000000006251500237002100162050ustar00nobodynobodyAs usually, copy this directory under the ~/.tkabber/plugins directory so that you get a hierarchy like this: ~/.tkabber/plugins ~/.tkabber/plugins/attline/ ~/.tkabber/plugins/attline/attline.tcl Restart Tkabber, to get the plugin loaded. Visit the Tkabber->Customize->Chat->Attention Line block of settings, customize as you wish. Consult the README file for the details about using this plugin. tkabber-plugins/attline/README000064400000000000000000000123121500237002100160300ustar00nobodynobody"Attention line" -- chat plugin for Tkabber. I. The idea This plugin helps to track discussion flow in high-volume chats by remembering the last message you have read in each chat window when you're leaving it and drawing a horizontal line just below that message when you return back to that chat window. This line is called the "attention line" since its task is to draw your attention to the point at which you stopped to attend the chat when you're back. "Leaving of the chat window" described above applies not only to the physical top-level chat windows in windowed mode but also to switching between chat tabs in tabbed mode. In tabbed mode leaving the main window is also considered as leaving the currently active chat tab, if any. So everywhere in this document, when you see "chat window" you can safely interpret it as "chat tab" if you're using tabbed mode in Tkabber. II. Usage The behaviour of the attention line is governed by its "expiration timeout". When you switch to a chat window and the chat log in that window contains unread messages, expiration line is placed just below the last read message. At that time the attention line expiration timer starts to tick. If you leave the chat window again until the timeout expires, the attention line is left intact as if you haven't switched to that window at all. Otherwise, if the timeout expires while you're in this chat window its attention line is considered "expired" and the chat log is considered as read. Normally the attention line doesn't do anything when it expires but you can make it disappear, if you so like (see the "Configuration" section below). When you leave the chat window with expired attention line and then switch back to it later the attention line will be placed just above the first message arrived while you haven't attending that chat window and the expiration timer starts again. The expiration timeout is configurable and can be disabled. If it's still not quite clear, you can consider this "expiration timeout" as "time to read", i.e. the time which must tick before the chat window you're currently attending is considered "read" (by you). When the chat window is active and its attention line is expired any new messages arriving in this chat are considered "read" immediately and doesn't affect the attention line. Chat input window is given one special Tk virtual event [1] named <> which is unbound by default but can be bound [2] to any Tk event (usually, a keyboard shortcut) and then used to move the chat log viewport to the place where the attention line is currently located. III. Configuration. You can configure the behavior of the attention line via Tkabber's Customize mechanism and its visual appearance via Tk option database [3]. Configuration parameters are available in the "Chat" -> "Attention Line" group of Customize settings (which are accessible via the "Tkabber" -> "Customize" main menu entry. There are two options to configure: * ::plugins::attline::options(expires_after) -- sets the attention line expiration timeout (in milliseconds). If set to 0 or a negative value attention line is considered expired right after you switch to a chat window it's placed in. The default value is 1000. * ::plugins::attline::options(remove_expired) -- when set, makes the attention line disappear when it's expired. (Note that when attention line is removed the text in the chat window is shifted to fill the gap which may be visually disturbing.) This flag is off by default. There's almost no sense to use removal of expired attention line along with its immediate expiration. Visual appearance is controlled by a set of Tk option database parameters: * Chat.attentionLineHeight -- controls the thickness (in pixels) of the attention line. (Note that some amount of white space is added above and below the attention line by the text widget which draws the attention line.) The default value is 1. * Chat.attentionLineColor -- color of the attention line. Can be specified in any form described in [4]. The default value is "red". * Chat.attentionLinePadX -- amount of extra white space to pad the attention line from left and right. The default value is 5. * Chat.attentionLinePadY -- amount of extra white space to pad the attention line above and below. The default value is 0. Example: # Expire attention line after 5 seconds of attending # the chat window: set ::plugins::attline::options(expires_after) 5000 # Make attention line green-coloured: option add *Chat.attentionLineColor green IV. Limitations. The attention line mechanism doesn't take into account the actual number of unread messages that exist in the chat window when you switch into it: after the expiration timeout is over the chat window is considered read no matter whether you have actually seen any unread messages. You can use the "chat bookmarks" builtin facility to attach a bookmark to any message in a chat window (this action can be accessed from the context menu of the widget that renders chat messages). V. Links 1. http://www.tcl.tk/man/tcl8.4/TkCmd/event.htm 2. http://www.tcl.tk/man/tcl8.4/TkCmd/bind.htm 3. http://www.tcl.tk/man/tcl8.4/TkCmd/option.htm 4. http://www.tcl.tk/man/tcl8.4/TkLib/GetColor.htm # vim:tw=64:noet tkabber-plugins/attline/TODO000064400000000000000000000004011500237002100156340ustar00nobodynobody* Remove att. line when a buffer marked as read loses focus instead of moving it to the bottom may be? * Calculation of line width isn't quite correct: left padding seems to be more than right. * Check whether the att. line can be made even thinner. tkabber-plugins/attline/attline.tcl000064400000000000000000000236271500237002100173270ustar00nobodynobody# attline.tcl -- # # "Attention line" -- chat plugin for Tkabber. # Draws horizontal line in chat windows separating read and unread # messages. # # Author: Konstantin Khomoutov # # See license.terms for the terms of distribution. package require msgcat namespace eval attline { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered attline]} { ::plugins::register attline \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Attention\ Line plugin is\ loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } frame .fakeframe -class Chat text .fakeframe.faketext option add *Chat.attentionLineHeight [winfo pixels .fakeframe 0.25m] widgetDefault option add *Chat.attentionLineColor [get_conf .fakeframe.faketext -foreground] widgetDefault option add *Chat.attentionLinePadX [winfo pixels .fakeframe 1.25m] widgetDefault option add *Chat.attentionLinePadY 0 widgetDefault destroy .fakeframe variable state variable options proc my what { return [uplevel 1 namespace current]::$what } proc mycmd args { lreplace $args 0 0 [uplevel 1 namespace current]::[lindex $args 0] } custom::defgroup Plugins [::msgcat::mc "Plugins options."] -group Tkabber custom::defgroup {Attention Line} \ [::msgcat::mc "Attention Line chat plugin options.\ This plugin draws horizontal line separating\ read and unread messages in chat windows."] \ -group Plugins \ -group Chat custom::defvar options(expires_after) 1000 \ [::msgcat::mc "Time (in milliseconds) after which unread messages\ in the currently active chat window are considered read\ and the attention line is considered expired."] \ -group {Attention Line} \ -type integer custom::defvar options(remove_expired) false \ [::msgcat::mc "Remove the attention line after it was expired\ from its chat window."] \ -group {Attention Line} \ -type boolean } proc attline::load {} { hook::add open_chat_post_hook [mycmd setup_chat_win] # must perform after the hook from 'log on open' plugin: hook::add open_chat_post_hook [mycmd draw_chat_history_separator] 101 hook::add close_chat_post_hook [mycmd cleanup] # must perform earlier than drawing of timestamp: hook::add draw_message_hook [mycmd on_draw_message] 5.5 hook::add got_focus_hook [mycmd on_focused] hook::add lost_focus_hook [mycmd on_lost_focus] foreach chatid [chat::opened] { setup_chat_win $chatid "" } } proc attline::unload {} { variable state hook::remove open_chat_post_hook [mycmd setup_chat_win] hook::remove open_chat_post_hook [mycmd draw_chat_history_separator] 101 hook::remove close_chat_post_hook [mycmd cleanup] hook::remove draw_message_hook [mycmd on_draw_message] 5.5 hook::remove got_focus_hook [mycmd on_focused] hook::remove lost_focus_hook [mycmd on_lost_focus] foreach chatid [chat::opened] { set cw [chat::chat_win $chatid] set iw [chat::input_win $chatid] bind $iw <> {} set al [attline $cw] set script [split [bind $cw ] \n] set idx [lsearch -exact $script \ [mycmd reconfigure_attention_line $cw $al]] if {$idx >= 0} { bind $cw [join [lreplace $script $idx $idx] \n] } if {[drawn $cw]} { delete_attention_line $cw } cleanup $chatid } catch {unset state} } proc attline::attline {cw} { return $cw.attention_line } proc attline::unread {cw {val ""}} { variable state if {$val == ""} { return $state($cw,unread) } else { set state($cw,unread) $val } } proc attline::atbottom {cw {val ""}} { variable state if {$val == ""} { return $state($cw,atbottom) } else { set state($cw,atbottom) $val } } proc attline::isvisible {text index} { expr {[llength [$text bbox $index]] > 0} } proc attline::setup_chat_win {chatid type} { variable state set cw [chat::chat_win $chatid] set iw [chat::input_win $chatid] set state($cw,mainwindow) [chat::winid $chatid] #unread $cw [expr {![has_focus $chatid]}] unread $cw false atbottom $cw false bind $iw <> [mycmd see_attention_line $cw] return } proc attline::cleanup {chatid} { variable state set cw [chat::chat_win $chatid] cancel_attline_expiration $cw unset state($cw,mainwindow) unset state($cw,unread) unset state($cw,atbottom) } proc attline::getopt {cw opt} { variable state chat::query_optiondb $state($cw,mainwindow) $opt } proc attline::on_draw_message {chatid from type body x} { if {[::xmpp::delay::exists $x]} return set cw [chat::chat_win $chatid] if {![has_focus $chatid] && ![unread $cw]} { unread $cw true if {[drawn $cw]} { redraw_attention_line $cw } else { draw_attention_line $cw } } atbottom $cw false return } proc attline::drawn {cw} { winfo exists [attline $cw] } proc attline::draw_chat_history_separator {chatid type} { if {[string equal $type chat]} { set cw [chat::chat_win $chatid] # Draw only if text widget isn't empty (has some history lines): if {[$cw compare 1.0 < end-1c]} { draw_attention_line $cw } } return } proc attline::draw_attention_line {cw} { set al [attline $cw] frame $al bind $cw +[mycmd reconfigure_attention_line $cw $al] # Prevent destructed attention line from killing its parent # in windowed mode when there's no explicit handler and the # event is forwarded upstream: bind $al +break $cw window create end -window $al reconfigure_attention_line $cw $al debugmsg attline "drawn" } proc attline::delete_attention_line {cw} { set state [$cw cget -state] $cw configure -state normal $cw delete [attline $cw] $cw configure -state $state debugmsg attline "deleted" } proc attline::redraw_attention_line {cw} { set al [attline $cw] set ix [$cw index $al] if {[atbottom $cw]} { debugmsg attline "at bottom, won't redraw" return } set state [$cw cget -state] $cw configure -state normal $cw window configure $ix -window {} $cw delete $ix $cw window create end -window $al reconfigure_attention_line $cw $al $cw configure -state $state debugmsg attline "redrawn" } proc attline::see_attention_line {cw} { set al [attline $cw] if {[winfo exists $al] && ![isvisible $cw $al]} { $cw see $al } } proc attline::internal_width {cw} { # We assume $cw is mapped... expr { [winfo width $cw] - 2 * [winfo pixels $cw [$cw cget -borderwidth]] - 2 * [winfo pixels $cw [$cw cget -padx]] - 2 * [winfo pixels $cw [$cw cget -highlightthickness]] } } proc attline::reconfigure_attention_line {cw al} { if {![winfo exists $al]} return set padx [winfo pixels $cw [getopt $cw attentionLinePadX]] $al configure \ -background [getopt $cw attentionLineColor] \ -height [getopt $cw attentionLineHeight] \ -width [expr {[internal_width $cw] - 2 * $padx }] $cw window configure $al \ -padx $padx \ -pady [getopt $cw attentionLinePadY] \ } proc attline::has_focus {chatid} { global usetabbar if {$usetabbar} { expr {![string equal [focus -displayof .] ""] && \ [string equal [chat::winid $chatid] [ifacetk::nbpath [.nb raise]]]} } else { set fw [focus -displayof .] expr {![string equal $fw ""] && \ [string equal [winfo toplevel $fw] [chat::winid $chatid]]} } } proc attline::on_focused {w} { set chatid [chat::winid_to_chatid $w] if {$chatid == ""} return set cw [chat::chat_win $chatid] debugmsg attline "focused; unread? [unread $cw]" if {[unread $cw]} { see_attention_line $cw schedule_attline_expiration $cw } } proc attline::on_lost_focus {w} { set chatid [chat::winid_to_chatid $w] if {$chatid == ""} return set cw [chat::chat_win $chatid] debugmsg attline "lost focus; unread? [unread $cw]" if {[unread $cw]} { cancel_attline_expiration $cw } elseif {[drawn $cw]} { redraw_attention_line $cw atbottom $cw true } } proc attline::schedule_attline_expiration {cw} { variable state variable options set exptime $options(expires_after) if {$exptime <= 0} { # Immediate expiration: unread $cw false debugmsg attline "expired immediately" return } set state($cw,expiring) [after $exptime [mycmd expire_attention_line $cw]] debugmsg attline "expiration scheduled for after $exptime" } proc attline::cancel_attline_expiration {cw} { variable state if {[info exists state($cw,expiring)]} { after cancel $state($cw,expiring) unset state($cw,expiring) debugmsg attline "expiration cancelled" } } proc attline::expire_attention_line {cw} { variable state variable options if {[info exists state($cw,expiring)]} { unread $cw false unset state($cw,expiring) if {$options(remove_expired) && [drawn $cw]} { delete_attention_line $cw } debugmsg attline "expired" } } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/attline/license.terms000064400000000000000000000021121500237002100176430ustar00nobodynobodyCopyright (c) 2007 Konstantin Khomoutov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tkabber-plugins/attline/msgs000075500000000000000000000000001500237002100160435ustar00nobodynobodytkabber-plugins/attline/msgs/de.msg000064400000000000000000000023051500237002100172220ustar00nobodynobody# de.msg -- # # German messages for Attention line Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 18.02.2009 ::msgcat::mcset de "Attention Line chat plugin options. This plugin draws\ horizontal line separating read and unread messages in chat\ windows." "Optionen für das Aufmerksamkeits-Linien-Plugin.\nDieses\ zeichnet in Chat-Fenstern eine horizontale Linie zur Trennung\ gelesener und ungelesener Nachrichten." ::msgcat::mcset de "Plugins options." "Optionen für Plugins." ::msgcat::mcset de "Remove the attention line after it was expired from its\ chat window." "Aufmerksamkeits-Linie entfernen, nachdem sie\ verfallen ist." ::msgcat::mcset de "Time (in milliseconds) after which unread messages in\ the currently active chat window are considered read and the attention\ line is considered expired." "Zeitraum nach dem ungelesene Nachrichten\ im aktiven Chat-Fenster als gelesen und die Aufmerksamkeits-Linie als\ verfallen betrachtet wird (in Millisekunden)." ::msgcat::mcset de "Whether the Attention Line plugin is loaded." \ "Aufmerksamkeits-Linien-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/attline/msgs/es.msg000064400000000000000000000023121500237002100172370ustar00nobodynobody# es.msg -- # # Spanish messages for Attention line Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "Attention Line chat plugin options. This plugin draws\ horizontal line separating read and unread messages in chat windows." \ "Opciones del plugin de charla Attention Line. Este plugin dibuja una\ línea horizontal que separa los mensajes viejos leídos de los nuevos\ mensajes aún no leídos en la ventana de charla." ::msgcat::mcset es "Plugins options." "Opciones de plugins." ::msgcat::mcset es "Remove the attention line after it was expired from its\ chat window." "Borra la línea de atención de la ventana de charla\ cuando expire." ::msgcat::mcset es "Time (in milliseconds) after which unread messages in the\ currently active chat window are considered read and the attention\ line is considered expired." "Tiempo (en milisegundos) desde que un\ mensaje no leído en la ventana de charla activa se considera leído y\ se borra la línea de atención se considera expirada." ::msgcat::mcset es "Whether the Attention Line plugin is loaded." \ "Cargar el plugin Attention Line." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/attline/msgs/pl.msg000064400000000000000000000023121500237002100172430ustar00nobodynobody# pl.msg -- # # Polish messages for Attention line Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Attention Line chat plugin options. This plugin draws\ horizontal line separating read and unread messages in chat windows." \ "Ustawienia wtyczki separatora aktywnoÅ›ci. Wtyczka ta wstawia wstawia\ poziomÄ… liniÄ™ oddzielajÄ…cÄ… przeczytane i nieprzeczytane wiadomoÅ›ci w\ rozmowie." ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "Remove the attention line after it was expired from its\ chat window." "UsuÅ„ separator nieaktywnoÅ›ci po tym jak straciÅ‚ ważność\ w oknie rozmowy." ::msgcat::mcset pl "Time (in milliseconds) after which unread messages in the\ currently active chat window are considered read and the attention\ line is considered expired." "Czas (w milisekundach), po którym\ nieprzeczytane wiadomoÅ›ci w aktywnym oknie rozmowy zostanÄ… uznane za\ przeczytane i separator starci ważność." ::msgcat::mcset pl "Whether the Attention Line plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ separatora nieaktywnoÅ›ci." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/attline/msgs/ru.msg000064400000000000000000000030321500237002100172560ustar00nobodynobody# ru.msg -- # # Russian messages for Attention line Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru \ "Attention Line chat plugin options. This plugin draws horizontal\ line separating read and unread messages in chat windows." \ "ÐаÑтройки раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Attention Line. Это раÑширение отделÑет\ непрочитанные ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð² окнах разговора от прочитанных\ горизонтальной линией." ::msgcat::mcset ru "Plugins options." "Параметры раÑширений." ::msgcat::mcset ru "Remove the attention line after it was expired from its\ chat window." "УдалÑть линию, разделÑющую ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾ иÑтечении\ времени её дейÑтвиÑ." ::msgcat::mcset ru \ "Time (in milliseconds) after which unread messages in the currently\ active chat window are considered read and the attention line is\ considered expired." "Ð’Ñ€ÐµÐ¼Ñ (в миллиÑекундах) по иÑтечении которого\ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð² активном окне разговора ÑчитаютÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ‹Ð¼Ð¸, и\ Ñ€Ð°Ð·Ð´ÐµÐ»Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ ÑчитаетÑÑ Ð½ÐµÐ´ÐµÐ¹Ñтвующей." ::msgcat::mcset ru "Whether the Attention Line plugin is loaded." \ "Загружено ли раÑширение Attention Line." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/attline/msgs/uk.msg000064400000000000000000000027671500237002100172650ustar00nobodynobody# uk.msg -- # # Ukrainian messages for Attention line Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk \ "Attention Line chat plugin options. This plugin draws horizontal\ line separating read and unread messages in chat windows." \ "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð»Ð°Ð³Ñ–Ð½Ñƒ Attention Line. Цей плагін відділÑÑ” непрочитані\ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð² вікнах розмов від прочитаних горизонтальною лінією." ::msgcat::mcset uk "Plugins options." "Параметри плагінів." ::msgcat::mcset uk "Remove the attention line after it was expired from its\ chat window." "Видалити лінію, що відділÑÑ” Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ–ÑлÑ\ Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‡Ð°Ñу Ñ—Ñ— дії." ::msgcat::mcset uk \ "Time (in milliseconds) after which unread messages in the currently\ active chat window are considered read and the attention line is\ considered expired." "Ð§Ð°Ñ (в міліÑекундах), піÑÐ»Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñкого\ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð² активному вікні розмови вважаютьÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ð½Ð¸Ð¼Ð¸, Ñ–\ роздільна Ð»Ñ–Ð½Ñ–Ñ Ð²Ð²Ð°Ð¶Ð°Ñ”Ñ‚ÑŒÑÑ Ð½ÐµÐ´Ñ–ÑŽÑ‡Ð¾ÑŽ." ::msgcat::mcset uk "Whether the Attention Line plugin is loaded." \ "Чи завантажений плагін Attention Line." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/battleship000075500000000000000000000000001500237002100155715ustar00nobodynobodytkabber-plugins/battleship/battleship.tcl000064400000000000000000002036421500237002100205220ustar00nobodynobody# battleship.tcl -- # # This file implements a Battleship game plugin for the Tkabber XMPP # client. package require msgcat namespace eval battleship { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered battleship]} { ::plugins::register battleship \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Battleship\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable winid 0 package require sha1 variable square_size [expr {27*$::icons_scale}] variable line_width $::icons_scale variable board_size 10 variable ships \ {carrier 1 battleship 1 destroyer 1 cruiser 2 submarine 2} variable sizes \ {carrier 5 battleship 4 destroyer 3 cruiser 2 submarine 1} variable themes variable dirs \ [glob -nocomplain -directory [file join [file dirname [info script]] \ pixmaps] *] variable dir foreach dir $dirs { pixmaps::load_theme_name [namespace current]::themes $dir } variable values {} variable theme foreach theme [lsort [array names themes]] { lappend values $theme $theme } variable options custom::defgroup Plugins [::msgcat::mc "Plugins options."] -group Tkabber custom::defgroup Battleship [::msgcat::mc "Battleship plugin options."] \ -group Plugins custom::defvar options(theme) Copybook \ [::msgcat::mc "Battleship pixmaps theme."] \ -group Battleship \ -type options \ -values $values \ -command [namespace code load_stored_theme] custom::defvar options(show_last_move) 0 \ [::msgcat::mc "Show last move by default."] \ -type boolean -group Battleship custom::defvar options(show_tooltips) 1 \ [::msgcat::mc "Show tooltips with short instructions."] \ -type boolean -group Battleship \ -command [namespace code set_tooltips] } proc battleship::load {} { hook::add postload_hook [namespace current]::load_stored_theme 70 hook::add roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.5 hook::add chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.5 hook::add roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.5 hook::add games_board_create_hook [namespace current]::iq_create hook::add games_board_init_hook [namespace current]::iq_init hook::add games_board_turn_hook [namespace current]::iq_turn ::xmpp::iq::register set create games:board \ [namespace parent]::iq_games_board_create ::xmpp::iq::register set board games:board \ [namespace parent]::iq_games_board_init ::xmpp::iq::register set turn games:board \ [namespace parent]::iq_games_board_turn load_stored_theme } proc battleship::unload {} { hook::remove postload_hook [namespace current]::load_stored_theme 70 hook::remove finload_hook [namespace current]::calc_moves 100 hook::remove roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.5 hook::remove chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.5 hook::remove roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.5 hook::remove games_board_create_hook [namespace current]::iq_create hook::remove games_board_turn_hook [namespace current]::iq_turn if {[hook::is_empty games_board_create_hook]} { ::xmpp::iq::unregister set create games:board rename [namespace parent]::iq_games_board_create "" } if {[hook::is_empty games_board_init_hook]} { ::xmpp::iq::unregister set board games:board rename [namespace parent]::iq_games_board_init "" } if {[hook::is_empty games_board_turn_hook]} { ::xmpp::iq::unregister set turn games:board rename [namespace parent]::iq_games_board_turn "" } foreach var [info vars [namespace current]::*] { upvar #0 $var flags if {[info exists flags(window)]} { destroy_win $flags(window) } } foreach w [winfo children .] { if {[regexp {^\.battleship_invite} $w]} { catch { set wf [$w getframe] bind $wf {} } destroy $w } } foreach var [info vars [namespace current]::*] { if {$var ne "[namespace current]::options"} { unset $var } } foreach img [image names] { if {[string first battleship/ $img] == 0} { image delete $img } } } proc battleship::load_stored_theme {args} { variable options variable themes pixmaps::load_dir $themes($options(theme)) } proc battleship::invite_dialog {xlib jid} { variable winid set w .battleship_invite[incr winid] Dialog $w -title [::msgcat::mc "Battleship Invitation"] \ -anchor e \ -default 0 set wf [$w getframe] Message $wf.message -aspect 50000 \ -text [::msgcat::mc "Sending Battleship game invitation\ to %s (%s)" \ [chat::get_nick $xlib $jid chat] \ $jid] pack $wf.message -pady 2m $w add -text [::msgcat::mc "I want to move first"] \ -command [namespace code [list invite $w $xlib $jid true]] $w add -text [::msgcat::mc "I want to move second"] \ -command [namespace code [list invite $w $xlib $jid false]] $w add -text [::msgcat::mc "Cancel invitation"] \ -command [list destroy $w] $w draw } proc battleship::invite {w xlib jid first} { destroy $w set id battleship[rand 1000000000] # FIX #set rjid [get_jid_of_user $jid] ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create create \ -xmlns games:board \ -attrs [list type battleship \ id $id \ first $first]] \ -to $jid \ -command [namespace code [list invite_res $xlib $jid $id $first]] } proc battleship::invite_res {xlib jid id first status xml} { variable winid if {![string equal $status ok]} { set w .battleship_invite_error[incr winid] after idle [list NonmodalMessageDlg $w -aspect 50000 -icon error \ -message [::msgcat::mc "%s (%s) has refused Battleship\ invitation: %s" \ [chat::get_nick $xlib $jid chat] \ $jid [error_to_string $xml]]] return "" } start_play $xlib $jid $id $first } proc battleship::invited_dialog {xlib jid iqid id first} { variable winid set w .battleship_invited[incr winid] Dialog $w -title [::msgcat::mc "Battleship Invitation from %s" $jid] \ -modal none -anchor e -default 0 set wf [$w getframe] bind $wf \ [namespace code [list invited_res $w $xlib $jid $iqid $id $first 0]] set nick [chat::get_nick $xlib $jid chat] set message1 [::msgcat::mc "Battleship game invitation from %s (%s)\ is received." \ $nick $jid] switch -- $first { true - 1 { set message2 [::msgcat::mc "%s wants to move first." $nick] } false - 0 { set message2 [::msgcat::mc "%s wants to move second." $nick] } default { return [list error modify bad-request] } } Message $wf.message1 -aspect 50000 -text $message1 Message $wf.message2 -aspect 50000 -text $message2 pack $wf.message1 -pady 1m pack $wf.message2 -pady 1m $w add -text [::msgcat::mc "Agree to play"] \ -command [namespace code \ [list invited_res $w $xlib $jid $iqid $id $first 1]] $w add -text [::msgcat::mc "Refuse to play"] \ -command [namespace code \ [list invited_res $w $xlib $jid $iqid $id $first 0]] $w draw return } proc battleship::invited_res {w xlib jid iqid id first result} { catch { set wf [$w getframe] bind $wf {} destroy $w } if {$result} { switch -- $first { true - 1 { start_play $xlib $jid $id false } false - 0 { start_play $xlib $jid $id true } default { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify bad-request] \ -to $jid \ -id $iqid } } ::xmpp::sendIQ $xlib result \ -query [::xmpp::xml::create create \ -xmlns games:board \ -attrs [list type battleship \ id $id]] \ -to $jid \ -id $iqid } else { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify not-acceptable] \ -to $jid \ -id $iqid } return } proc battleship::start_play {xlib jid id first} { set gid [make_gid $jid $id] variable $gid upvar 0 $gid state set state(window) [win_id battleship $gid] set state(xlib) $xlib set state(opponent) $jid set state(id) $id set state(move_first) $first trace add variable [namespace current]::${gid}(position,turn) write \ [namespace code [list set_label_move $gid]] open_win $gid } proc battleship::set_label_move {gid args} { variable $gid upvar 0 $gid state switch -- $state(position,turn) { first - second { set move 1 } default { set move 0 } } if {$move && [is_my_move $gid]} { if {$state(board_is_sent) && $state(board_is_received)} { set state(move_label) [::msgcat::mc "You"] } else { set state(move_label) \ [::msgcat::mc "You (after all parties freeze boards)"] } } else { if {$state(board_is_sent) && $state(board_is_received)} { set state(move_label) [::msgcat::mc "Opponent"] } else { set state(move_label) \ [::msgcat::mc "Opponent (after all parties freeze boards)"] } } } proc battleship::save_position {gid} { variable $gid upvar 0 $gid state set state(saved_position) [array get state position,*] } proc battleship::restore_position {gid} { variable $gid upvar 0 $gid state array set state $state(saved_position) draw_position $gid update_controls $gid find_reasonable_moves $gid $state(position,turn) } proc battleship::make_gid {jid id} { jid_to_tag [concat $jid $id] } proc battleship::board_recv {gid xmlElements} { variable board_size variable options variable $gid upvar 0 $gid state if {[llength [array names state hash,*]] == 0} { # Receiving hashes set numhashes 0 set state(shiphashes) {} foreach element $xmlElements { ::xmpp::xml::split $element tag xmlns attrs cdata subels switch -- $tag { cell { set c [::xmpp::xml::getAttr $attrs col] set r [::xmpp::xml::getAttr $attrs row] set hash [::xmpp::xml::getAttr $attrs hash] if {![string is integer -strict $c] || \ $c < 0 || $c >= $board_size} { return [list error modify bad-request] } if {![string is integer -strict $r] || \ $r < 0 || $r >= $board_size} { return [list error modify bad-request] } if {$hash != "" && ![info exists state(hash,$c,$r)]} { set state(hash,$c,$r) $hash incr numhashes } else { return [list error modify bad-request] } } ship { lappend state(shiphashes) \ [::xmpp::xml::getAttr $attrs hash] } } } if {$numhashes == [expr {$board_size * $board_size}]} { set state(board_is_received) 1 set_label_move $gid update_controls $gid find_reasonable_moves $gid $state(position,turn) return [list result {}] } else { array unset state hash,* array unset state shiphashes return [list error modify bad-request] } } else { # Checking hashes set numhashes 0 set cells {} foreach element $xmlElements { ::xmpp::xml::split $element tag xmlns attrs cdata subels switch -- $tag { cell { set c [::xmpp::xml::getAttr $attrs col] if {![string is integer -strict $c] || \ $c < 0 || $c >= $board_size} { attention_message $gid \ [::msgcat::mc "\n\n Opponent sent incorrect\ cell column"] return [list error modify bad-request] } set r [::xmpp::xml::getAttr $attrs row] if {![string is integer -strict $r] || \ $r < 0 || $r >= $board_size} { attention_message $gid \ [::msgcat::mc "\n\n Opponent sent incorrect\ cell row"] return [list error modify bad-request] } set seed [::xmpp::xml::getAttr $attrs seed] if {[::xmpp::xml::getAttr $attrs ship]} { set ship 1 } else { set ship 0 } if {[sha1::sha1 $seed$ship] ne $state(hash,$c,$r)} { attention_message $gid \ [::msgcat::mc "\n\n Opponent sent incorrect\ cell seed"] return [list error modify bad-request] } lappend cells [list $c $r] set board($c,$r) $ship incr numhashes } } } if {$numhashes != $board_size*$board_size || [llength [lsort -unique $cells]] != $board_size*$board_size} { attention_message $gid \ [::msgcat::mc "\n\n Opponent sent incorrect number\ of cells"] return [list error modify bad-request] } if {![test_legal [array get board]]} { attention_message $gid \ [::msgcat::mc "\n\n Opponent sent illegal board"] return [list error modify bad-request] } return [list result {}] } } proc battleship::test_legal {boardlist} { variable board_size variable ships variable sizes array set board $boardlist foreach c [list -1 $board_size] { for {set r -1} {$r <= $board_size} {incr r} { set board($c,$r) 0 set board($r,$c) 0 } } array set size $sizes foreach {name number} $ships { for {set i 1} {$i <= $number} {incr i} { lassign [find_ship board $size($name)] status c1 r1 c2 r2 if {!$status} { return 0 } for {set c $c1} {$c <= $c2} {incr c} { for {set r $r1} {$r <= $r2} {incr r} { set board($c,$r) 0 } } for {set c [expr {$c1-1}]} {$c <= $c2+1} {incr c} { for {set r [expr {$r1-1}]} {$r <= $r2+1} {incr r} { if {$board($c,$r) == 1} { return 0 } } } } } return 1 } proc battleship::find_ship {vboard size} { variable board_size upvar $vboard board for {set c1 0} {$c1 < $board_size} {incr c1} { for {set r1 0} {$r1 <= $board_size} {incr r1} { if {$board($c1,$r1) == 0} continue set q 1 set c2 $c1 for {set r2 $r1} {$r2 < $r1+$size} {incr r2} { if {$board($c2,$r2) == 0} { set q 0 break } } if {$q} { return [list 1 $c1 $r1 $c2 [incr r2 -1]] } set q 1 set r2 $r1 for {set c2 $c1} {$c2 < $c1+$size} {incr c2} { if {$board($c2,$r2) == 0} { set q 0 break } } if {$q} { return [list 1 $c1 $r1 [incr c2 -1] $r2] } } } return {0} } proc battleship::turn_recv {gid xmlElements} { variable board_size variable options variable $gid upvar 0 $gid state set move 0 set draw 0 foreach element $xmlElements { ::xmpp::xml::split $element tag xmlns attrs cdata subels switch -- $tag { shot { set c [::xmpp::xml::getAttr $attrs col] set r [::xmpp::xml::getAttr $attrs row] if {![string is integer -strict $c] || \ ![string is integer -strict $r] || \ $c < 0 || $c >= $board_size || \ $r < 0 || $r >= $board_size} { return [list error modify not-acceptable] } set move 1 } resign { end_game $gid 1 [::msgcat::mc "You win (Opponent resigned)"] update_controls $gid draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type battleship \ id $state(id)]]] } accept { if {$state(position,draw)} { end_game $gid 0.5 [::msgcat::mc "Draw (Opponent accepted)"] update_controls $gid draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type battleship \ id $state(id)]]] } else { return [list error modify not-acceptable] } } draw { set draw 1 } } } if {$move} { set hit 0 foreach ship $state(position,ships) { set sunk 1 foreach {sc sr} [coordinates $ship] { if {$c == $sc && $r == $sr} { set hit 1 } elseif {$state(position,oshot,$sc,$sr) != 1} { set sunk 0 } } if {$hit} { break } } if {$hit && $sunk} { set result destroy lappend state(position,destroyed_my_ships) $ship } elseif {$hit} { set result hit } else { set result miss } if {[do_move $gid $c $r $result $draw]} { update_controls $gid $draw draw_position $gid highlight_last_move $gid set subel [::xmpp::xml::create shot \ -attrs [list result $result \ seed $state(seed,$c,$r)]] return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type battleship \ id $state(id)] \ -subelement $subel]] } else { return [list error modify not-acceptable] } } else { return [list error modify not-acceptable] } } ############################################################################### proc battleship::center {c r} { variable square_size variable line_width list [expr {$line_width + ($square_size * 0.5) + \ (($square_size + $line_width) * $c)}] \ [expr {$line_width + ($square_size * 0.5) + \ (($square_size + $line_width) * $r)}] } proc battleship::nw {c r} { variable square_size variable line_width list [expr {$line_width + ($square_size + $line_width) * $c}] \ [expr {$line_width + ($square_size + $line_width) * $r}] } proc battleship::onw {c r} { variable board_size variable square_size variable line_width list [expr {($square_size + $line_width) * ($board_size + 1) + \ $line_width + ($square_size + $line_width) * $c}] \ [expr {$line_width + ($square_size + $line_width) * $r}] } proc battleship::close {gid} { variable $gid upvar 0 $gid state array unset state catch {unset state} } proc battleship::exists {gid} { variable $gid info exists $gid } proc battleship::button_update_relief {b flag} { set rstate [expr {$flag? {pressed} : {!$pressed}}] if {[catch {$b state $rstate}]} { set relief [expr {$flag? "sunken" : "raised"}] $b configure -relief $relief } } proc battleship::open_win {gid} { variable options variable board_size variable square_size variable line_width variable $gid upvar 0 $gid state set jid $state(opponent) set w $state(window) if {[winfo exists $w]} { return } set title [::msgcat::mc "Battleship with %s" \ [chat::get_nick $state(xlib) $jid chat]] add_win $w -title $title \ -tabtitle $title \ -class Battleship \ -raise 1 catch {grid anchor $w center} set mylabel [Label $w.mylabel -text [::msgcat::mc "My ships"]] set theirlabel [Label $w.theirlabel -text [::msgcat::mc "Opponent ships"]] grid $mylabel -row 0 -column 0 -sticky w grid $theirlabel -row 0 -column 1 -sticky e if {[catch {lindex [$w configure -background] 4} bg]} { # Ttk set bg [ttk::style lookup TFrame -background] } set board [canvas $w.board \ -borderwidth 0 \ -highlightthickness 0 \ -background $bg \ -width [expr {($square_size + $line_width) * (2 * $board_size + 1) + $line_width}] \ -height [expr {($square_size + $line_width) * $board_size + $line_width}]] grid $board -row 1 -column 0 -columnspan 2 -sticky nw -padx 2m -pady 2m set state(board) $board set state(show_last_move) $options(show_last_move) Frame $w.move grid $w.move -row 2 -column 0 -columnspan 2 -sticky wn Label $w.move.title -text [::msgcat::mc "Move: "] pack $w.move.title -side left Label $w.move.label -anchor w \ -textvariable [namespace current]::${gid}(move_label) pack $w.move.label -side left -anchor w set bbox [ButtonBox $w.bbox -orient vertical -spacing 0] $bbox add -text [::msgcat::mc "Freeze ships position"] \ -command [namespace code [list send_board $gid]] set state(show_last_move_button) \ [$bbox add -text [::msgcat::mc "Show last move"] \ -command [namespace code [list toggle_show_last_move $gid]]] button_update_relief $state(show_last_move_button) $state(show_last_move) set state(propose_draw_button) \ [$bbox add -text [::msgcat::mc "Propose a draw"] \ -state disabled \ -command [namespace code [list toggle_draw $gid]]] $bbox add -text [::msgcat::mc "Accept the draw proposal"] \ -state disabled \ -command [namespace code [list accept_draw $gid]] $bbox add -text [::msgcat::mc "Resign the game"] \ -state disabled \ -command [namespace code [list send_resign $gid]] grid columnconfigure $bbox 0 -weight 1 grid $bbox -row 3 -column 1 -sticky wen set state(bbox) $bbox set_tooltips #label $w.history -text [::msgcat::mc "History"] #pack $w.history -side top -anchor w set hsw [ScrolledWindow $w.hsw] grid $hsw -row 3 -column 0 -sticky nwes set ht [Text $w.text -wrap word -height 5 -width 25 -state disabled] set font [$ht cget -font] set tabstop1 [font measure $font "100.."] set tabstop2 [font measure $font "100..[::msgcat::mc Opponent] "] $ht configure -tabs "$tabstop1 $tabstop2" $ht tag configure attention \ -foreground [option get $ht errorForeground Text] $hsw setwidget $ht set state(hw) $ht grid columnconfigure $w 0 -weight 0 grid columnconfigure $w 1 -weight 0 grid rowconfigure $w 0 -weight 0 grid rowconfigure $w 1 -weight 0 grid rowconfigure $w 2 -weight 0 grid rowconfigure $w 3 -weight 0 for {set c 0} {$c < $board_size} {incr c} { for {set r 0} {$r < $board_size} {incr r} { set x1 [expr {$line_width + (($square_size + $line_width) * $c)}] set x2 [expr {($square_size + $line_width) * ($c + 1)}] set y1 [expr {$line_width + (($square_size + $line_width) * $r)}] set y2 [expr {($square_size + $line_width) * ($r + 1)}] $board create image $x1 $y1 -image battleship/field -anchor nw \ -tags [list mbackground [list cr $c $r]] $board create rectangle $x1 $y1 $x2 $y2 \ -outline {} -width $line_width \ -tags [list olast [list cr $c $r]] } } for {set c 0} {$c < $board_size} {incr c} { for {set r 0} {$r < $board_size} {incr r} { set x1 [expr {($square_size + $line_width) * ($board_size + 1) + \ $line_width + (($square_size + $line_width) * $c)}] set x2 [expr {($square_size + $line_width) * ($board_size + 1) + \ ($square_size + $line_width) * ($c + 1)}] set y1 [expr {$line_width + (($square_size + $line_width) * $r)}] set y2 [expr {($square_size + $line_width) * ($r + 1)}] $board create image $x1 $y1 -image battleship/field/shaded \ -anchor nw \ -tags [list obackground [list cr $c $r]] $board create rectangle $x1 $y1 $x2 $y2 \ -outline {} -width $line_width \ -tags [list mlast [list cr $c $r]] $board create rectangle $x1 $y1 $x2 $y2 \ -outline {} -width $line_width \ -tags [list square [list cr $c $r]] } } $board bind figure <1> \ [namespace code [list start_drag_figure $gid %x %y]] $board bind figure \ [namespace code [list drag_figure $gid %x %y]] $board bind figure \ [namespace code [list drag_end $gid %x %y]] $board bind figure <> \ [namespace code [list flip_figure $gid %x %y]] bind $w [namespace code [list close $gid]] for {set c 0} {$c < $board_size} {incr c} { for {set r 0} {$r < $board_size} {incr r} { set state(position,mshot,$c,$r) "" set state(position,oshot,$c,$r) "" } } set state(board_is_sent) 0 set state(board_is_received) 0 set state(position,turn) first catch {unset state(position,last_move)} set state(position,draw) 0 set state(position,halfmove) 0 set state(position,history) {} set state(position,ships) {} set state(position,destroyed_ships) {} set state(position,destroyed_my_ships) {} for {set c 0} {$c < $board_size} {incr c} { for {set r 0} {$r < $board_size} {incr r} { set state(seed,$c,$r) \ [rand 1000000000][rand 1000000000][rand 1000000000][rand 1000000000] } } make_random_position $gid predraw_position $gid update_controls $gid attention_message $gid \ [::msgcat::mc "\nDrag and drop ships to desired locations, then\ click the 'Freeze ships position'\ button.\nRight mouse button switches horizontal\ and vertical ship orientation."] } proc battleship::predraw_position {gid} { variable board_size variable sizes variable $gid upvar 0 $gid state $state(board) delete figure foreach ship $state(position,ships) { lassign $ship name dir c r $state(board) create image [nw $c $r] \ -anchor nw \ -image battleship/$name/$dir \ -tags [list figure [list ship $name $dir $c $r]] } } proc battleship::flip_figure {gid x y} { variable board_size variable sizes variable $gid upvar 0 $gid state array set size $sizes set board $state(board) lassign [lsearch -inline -regexp [$board gettags current] ^ship] ship \ name dir c r set x [$board canvasx $x] set y [$board canvasy $y] $board dtag dst $board addtag dst overlapping [expr {$x-1}] [expr {$y-1}] $x $y lassign [lsearch -inline -regexp [$board gettags dst&&mbackground] ^cr] \ cr c1 r1 $board dtag dst set c2 [expr {$c1 - $r1 + $r}] if {$c2 < 0} { set c2 0 } if {$dir == "vertical" && $c2 > $board_size - $size($name)} { set c2 [expr {$board_size - $size($name)}] } set r2 [expr {$r1 - $c1 + $c}] if {$r2 < 0} { set r2 0 } if {$dir == "horizontal" && $r2 > $board_size - $size($name)} { set r2 [expr {$board_size - $size($name)}] } if {$dir == "horizontal"} { set dir2 vertical } else { set dir2 horizontal } set idx [lsearch -exact $state(position,ships) [list $name $dir $c $r]] set state(position,ships) [lreplace $state(position,ships) $idx $idx] lappend state(position,ships) [list $name $dir2 $c2 $r2] predraw_position $gid if {[position_is_legal $gid 0]} { $state(bbox) itemconfigure 0 -state normal } else { $state(bbox) itemconfigure 0 -state disabled } } proc battleship::start_drag_figure {gid x y} { variable $gid upvar 0 $gid state set board $state(board) set state(lastx) [$board canvasx $x] set state(lasty) [$board canvasy $y] $board dtag dst $board addtag dst overlapping [expr {$x-1}] [expr {$y-1}] $x $y lassign [lsearch -inline -regexp [$board gettags dst&&mbackground] ^cr] \ cr state(startc) state(startr) $board dtag dst $board raise current $board addtag drag withtag current $board config -cursor hand2 } proc battleship::drag_figure {gid x y} { variable board_size variable square_size variable line_width variable $gid upvar 0 $gid state set board $state(board) set minx $line_width set maxx [expr {($square_size + $line_width) * $board_size}] set miny $line_width set maxy [expr {($square_size + $line_width) * $board_size}] set x [$board canvasx $x] set y [$board canvasy $y] set dx [expr {$x - $state(lastx)}] set dy [expr {$y - $state(lasty)}] lassign [$board bbox drag] x1 y1 x2 y2 if {$x1 + $dx < $minx} { set dx [expr {$minx - $x1}] } if {$x2 + $dx > $maxx} { set dx [expr {$maxx - $x2}] } if {$y1 + $dy < $miny} { set dy [expr {$miny - $y1}] } if {$y2 + $dy > $maxy} { set dy [expr {$maxy - $y2}] } $board move drag $dx $dy if {$x < $minx} { set state(lastx) $minx } elseif {$x > $maxx} { set state(lastx) $maxx } else { set state(lastx) $x } if {$y < $miny} { set state(lasty) $miny } elseif {$y > $maxy} { set state(lasty) $maxy } else { set state(lasty) $y } } proc battleship::drag_end {gid x y} { variable square_size variable $gid upvar 0 $gid state set board $state(board) lassign [lsearch -inline -regexp [$board gettags drag] ^ship] ship \ name dir c r lassign [$board bbox drag] x1 y1 $board dtag drag set x [expr {$x1 + $square_size/2}] set y [expr {$y1 + $square_size/2}] $board dtag dst $board addtag dst overlapping [expr {$x-1}] [expr {$y-1}] $x $y lassign [lsearch -inline -regexp [$board gettags dst&&mbackground] ^cr] \ cr c1 r1 $board dtag dst set idx [lsearch -exact $state(position,ships) [list $name $dir $c $r]] set state(position,ships) [lreplace $state(position,ships) $idx $idx] lappend state(position,ships) [list $name $dir $c1 $r1] predraw_position $gid if {[position_is_legal $gid 0]} { $state(bbox) itemconfigure 0 -state normal } else { $state(bbox) itemconfigure 0 -state disabled } } proc battleship::make_random_position {gid} { variable board_size variable ships variable sizes variable $gid upvar 0 $gid state array set tmp $sizes set state(position,ships) {} foreach {name num} $ships { for {set i 0} {$i < $num} {incr i} { while {1} { set c [rand $board_size] set r [rand $board_size] set dir [lindex {horizontal vertical} [rand 2]] set ship [list $name $dir $c $r] set saved $state(position,ships) lappend state(position,ships) $ship if {[position_is_legal $gid 0]} { break } else { set state(position,ships) $saved } } } } } proc battleship::position_is_legal {gid checkSizesOfShips} { variable board_size variable ships variable sizes variable $gid upvar 0 $gid state if {$checkSizesOfShips} { array set tmp $ships foreach ship $state(position,ships) { set name [lindex $ship 0] if {![info exists tmp($name)]} { return 0 } incr tmp($name) -1 } foreach name [array names tmp] { if {$tmp($name) != 0} { return 0 } } } set max -1 foreach ship $state(position,ships) { foreach {c r} [coordinates $ship] { if {$c < 0 || $c >= $board_size || $r < 0 || $r >= $board_size} { return 0 } foreach ship2 [lrange $state(position,ships) 0 $max] { foreach {c1 r1} [coordinates $ship2] { if {abs($c1 - $c) <= 1 && abs($r1 - $r) <= 1} { return 0 } } } } incr max } return 1 } proc battleship::coordinates {ship} { variable sizes array set tmp $sizes lassign $ship name dir c r set coords {} for {set i 0} {$i < $tmp($name)} {incr i} { lappend coords $c $r switch -- $dir { horizontal { incr c } vertical { incr r } default { return -code error } } } return $coords } proc battleship::set_tooltips {args} { variable options if {$options(show_tooltips)} { set tooltip0 "" set tooltip1 "" set tooltip2 [::msgcat::mc "Press button and make move if you want\ to propose draw"] set tooltip3 [::msgcat::mc "Press button if you want to accept the\ draw proposal"] set tooltip4 [::msgcat::mc "Press button if you want to resign"] } else { set tooltip0 "" set tooltip1 "" set tooltip2 "" set tooltip3 "" set tooltip4 "" } foreach var [info vars [namespace current]::*] { upvar 0 $var state if {[info exists state(bbox)]} { catch { $state(bbox) itemconfigure 0 -helptext $tooltip0 $state(bbox) itemconfigure 1 -helptext $tooltip1 $state(bbox) itemconfigure 2 -helptext $tooltip2 $state(bbox) itemconfigure 3 -helptext $tooltip3 $state(bbox) itemconfigure 4 -helptext $tooltip4 } } } } proc battleship::toggle_show_last_move {gid} { variable $gid upvar 0 $gid state set state(show_last_move) [expr {!$state(show_last_move)}] button_update_relief $state(show_last_move_button) $state(show_last_move) highlight_last_move $gid } proc battleship::toggle_draw {gid} { variable $gid upvar 0 $gid state set state(position,draw) [expr {!$state(position,draw)}] button_update_relief $state(propose_draw_button) $state(position,draw) } proc battleship::update_controls {gid {draw_proposed 0}} { variable $gid upvar 0 $gid state if {!$state(board_is_sent)} { $state(bbox) itemconfigure 0 -state normal return } else { $state(bbox) itemconfigure 0 -state disabled } if {!$state(board_is_received)} { return } button_update_relief $state(propose_draw_button) 0 if {[is_my_move $gid]} { $state(board) config -cursor "" set state(position,draw) 0 if {$draw_proposed} { $state(bbox) itemconfigure 2 -state disabled $state(bbox) itemconfigure 3 -state normal $state(bbox) itemconfigure 4 -state disabled } else { $state(bbox) itemconfigure 2 -state normal $state(bbox) itemconfigure 3 -state disabled $state(bbox) itemconfigure 4 -state normal } } else { if {$state(position,turn) ne "first" && \ $state(position,turn) ne "second"} { $state(board) config -cursor "" } else { set state(position,draw) $draw_proposed $state(board) config -cursor watch } $state(bbox) itemconfigure 2 -state disabled $state(bbox) itemconfigure 3 -state disabled $state(bbox) itemconfigure 4 -state disabled } } proc battleship::end_game {gid my_score message} { variable $gid upvar 0 $gid state set opponent_score [expr {1 - $my_score}] if {$state(move_first)} { set score "$my_score : $opponent_score" } else { set score "$opponent_score : $my_score" } set state(position,turn) none set state(move_label) $message set hw $state(hw) $hw configure -state normal catch {$hw delete attention.first attention.last} $hw delete {end -1 char} end $hw insert end "\n\t\t$score\n" $hw see end $hw configure -state disabled after idle [namespace code [list send_board2 $gid]] } proc battleship::draw_position {gid} { variable board_size variable sizes variable $gid upvar 0 $gid state $state(board) delete figure $state(board) delete unshaded $state(board) delete oshot $state(board) delete mshot foreach ship $state(position,ships) { lassign $ship name dir c r $state(board) create image [nw $c $r] \ -anchor nw \ -image battleship/$name/$dir \ -tags [list figure [list ship $name $dir $c $r]] } for {set c 0} {$c < $board_size} {incr c} { for {set r 0} {$r < $board_size} {incr r} { switch -- $state(position,oshot,$c,$r) { 1 { set image battleship/hit } 0 { set image battleship/miss } default { continue } } $state(board) create image [nw $c $r] \ -anchor nw \ -image $image \ -tags [list oshot [list cr $c $r]] } } array set tmp $sizes foreach ship $state(position,destroyed_ships) { lassign $ship name dir c r switch -- $dir { vertical { for {set c1 [expr {$c - 1}]} {$c1 <= $c + 1} {incr c1} { if {$c1 < 0 || $c1 >= $board_size} continue for {set r1 [expr {$r - 1}]} {$r1 <= $r + $tmp($name)} \ {incr r1} { if {$r1 < 0 || $r1 >= $board_size} continue $state(board) create image [onw $c1 $r1] \ -anchor nw \ -image battleship/field \ -tags [list unshaded $c1 $r1] set unshaded($c1,$r1) 1 } } } horizontal { for {set c1 [expr {$c - 1}]} {$c1 <= $c + $tmp($name)} \ {incr c1} { if {$c1 < 0 || $c1 >= $board_size} continue for {set r1 [expr {$r - 1}]} {$r1 <= $r + 1} {incr r1} { if {$r1 < 0 || $r1 >= $board_size} continue $state(board) create image [onw $c1 $r1] \ -anchor nw \ -image battleship/field \ -tags [list unshaded $c1 $r1] set unshaded($c1,$r1) 1 } } } } $state(board) create image [onw $c $r] \ -anchor nw \ -image battleship/$name/$dir \ -tags [list figure [list ship $name $dir $c $r]] } for {set c 0} {$c < $board_size} {incr c} { for {set r 0} {$r < $board_size} {incr r} { switch -- $state(position,mshot,$c,$r) { 1 { set image battleship/hit } 0 { set image battleship/miss } default { continue } } if {![info exists unshaded($c,$r)]} { $state(board) create image [onw $c $r] \ -anchor nw \ -image battleship/field \ -tags [list unshaded $c $r] } $state(board) create image [onw $c $r] \ -anchor nw \ -image $image \ -tags [list mshot [list cr $c $r]] } } $state(board) raise mlast $state(board) raise olast $state(board) raise square } proc battleship::motion {gid x y} { variable line_width variable $gid upvar 0 $gid state set board $state(board) set x [$board canvasx $x] set y [$board canvasy $y] $board itemconfigure dst_sq&&square -outline "" -width $line_width $board dtag dst_sq $board addtag dst_sq overlapping [expr {$x-1}] [expr {$y-1}] $x $y set tags [$board gettags dst_sq&&obackground] lassign [lindex $tags [lsearch $tags cr*]] cr c r $board addtag dst_sq withtag [list cr $c $r]&&square if {[is_my_move $gid] && [info exists state(position,mshot,$c,$r)] && \ $state(position,mshot,$c,$r) == ""} { $board itemconfigure dst_sq&&square -outline red -width $line_width $board itemconfigure dst_sq&&reasonable&&square -outline blue -width $line_width } } proc battleship::leave {gid x y} { variable line_width variable $gid upvar 0 $gid state set board $state(board) $board itemconfigure dst_sq&&square -outline "" -width $line_width $board dtag dst_sq highlight_last_move $gid } proc battleship::release {gid x y} { variable options variable line_width variable $gid upvar 0 $gid state set board $state(board) set x [$board canvasx $x] set y [$board canvasy $y] $board dtag dst_sq $board addtag dst_sq overlapping [expr {$x-1}] [expr {$y-1}] $x $y set tags [$board gettags dst_sq&&obackground] lassign [lindex $tags [lsearch $tags cr*]] cr c r $board dtag dst_sq if {[is_my_move $gid]} { if {[start_do_move $gid $c $r $state(position,draw)]} { $board itemconfigure [list cr $c $r]&&square -outline "" -width $line_width } } update_controls $gid draw_position $gid highlight_last_move $gid } proc battleship::highlight_last_move {gid} { variable line_width variable $gid upvar 0 $gid state $state(board) itemconfigure mlast -outline "" -width $line_width $state(board) itemconfigure olast -outline "" -width $line_width if {[catch {lassign $state(position,last_move) c r}]} { return } if {$state(show_last_move)} { set color white } else { set color {} } if {$state(position,my_last_move)} { $state(board) itemconfigure [list cr $c $r]&&mlast -outline $color -width $line_width } else { $state(board) itemconfigure [list cr $c $r]&&olast -outline $color -width $line_width } } proc battleship::start_do_move {gid c r draw} { variable $gid upvar 0 $gid state if {$c == "" || $r == ""} { return 0 } set my_move [is_my_move $gid] if {!$my_move} { return 0 } save_position $gid set state(position,mshot,$c,$r) -1 set state(position,last_move) [list $c $r] set state(position,my_last_move) 1 update_controls $gid draw_position $gid highlight_last_move $gid send_move $gid $c $r $draw return 1 } proc battleship::do_move {gid c r result draw} { variable options variable ships variable $gid upvar 0 $gid state if {$c == "" || $r == ""} { return 0 } switch -- $result { destroy - hit { set hit 1 } default { set hit 0 } } set my_move [is_my_move $gid] if {!$my_move} { save_position $gid set state(position,oshot,$c,$r) $hit set state(position,last_move) [list $c $r] set state(position,my_last_move) 0 } else { set state(position,mshot,$c,$r) $hit if {$result == "destroy"} { set ship [find_destroyed_ship $gid $c $r] if {[llength $ship] > 0} { lappend state(position,destroyed_ships) $ship } } } add_move_to_history $gid $c $r $result $draw if {$draw && !$my_move} { attention_message $gid \ [::msgcat::mc "\n\n Opponent proposes a draw\n\n"] } switch -glob -- $state(position,turn)/$hit/$draw { first/1/0 { # Add skipping move to history add_move_to_history $gid set state(position,turn) first } second/1/0 { # Add skipping move to history add_move_to_history $gid set state(position,turn) second } first/1/1 - first/0/* { set state(position,turn) second } second/1/1 - second/0/* { set state(position,turn) first } } find_reasonable_moves $gid $state(position,turn) set endgame 0 if {[llength $state(reasonable_moves)] == 0} { set endgame 1 } if {$endgame} { set total 0 foreach {name size} $ships { incr total $size } if {[llength $state(position,destroyed_ships)] >= $total && [llength $state(position,destroyed_my_ships)] < $total} { # I win end_game $gid 1 [::msgcat::mc "You win"] } elseif {[llength $state(position,destroyed_my_ships)] >= $total && [llength $state(position,destroyed_ships)] < $total} { # Opponent wins end_game $gid 0 [::msgcat::mc "Opponent wins"] } else { # Can't be here end_game $gid 0.5 [::msgcat::mc "Impossible draw"] } } tab_set_updated [winfo parent $state(board)] 1 mesg_to_user return 1 } proc battleship::accept_draw {gid} { variable $gid upvar 0 $gid state ::xmpp::sendIQ $state(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type battleship \ id $state(id)] \ -subelement [::xmpp::xml::create accept]] \ -to $state(opponent) \ -command [namespace code [list accept_draw_result $gid]] end_game $gid 0.5 [::msgcat::mc "Draw (You accepted)"] update_controls $gid draw_position $gid highlight_last_move $gid } proc battleship::accept_draw_result {gid status xml} { variable $gid upvar 0 $gid state if {![string equal $status ok]} { attention_message $gid \ [::msgcat::mc "\n\n Opponent rejected accepted\ draw:\n %s\n\n" \ [error_to_string $xml]] } } proc battleship::send_resign {gid} { variable $gid upvar 0 $gid state ::xmpp::sendIQ $state(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type battleship \ id $state(id)] \ -subelement [::xmpp::xml::create resign]] \ -to $state(opponent) end_game $gid 0 [::msgcat::mc "Opponent wins (You resigned)"] update_controls $gid draw_position $gid highlight_last_move $gid } proc battleship::send_board {gid} { variable board_size variable $gid upvar 0 $gid state for {set c 0} {$c < $board_size} {incr c} { for {set r 0} {$r < $board_size} {incr r} { set pos($c,$r) 0 } } set shipSubels {} foreach ship $state(position,ships) { set size 0 set seed "" foreach {c r} [coordinates $ship] { incr size append seed $state(seed,$c,$r) set pos($c,$r) 1 } lappend shipSubels [::xmpp::xml::create ship \ -attrs [list length $size \ hash [sha1::sha1 $seed]]] } set subels {} for {set c 0} {$c < $board_size} {incr c} { for {set r 0} {$r < $board_size} {incr r} { lappend subels \ [::xmpp::xml::create cell \ -attrs [list col $c \ row $r \ hash [sha1::sha1 \ $state(seed,$c,$r)$pos($c,$r)]]] } } set state(board_is_sent) 1 set_label_move $gid draw_position $gid update_controls $gid find_reasonable_moves $gid $state(position,turn) set hw $state(hw) $hw configure -state normal $hw delete 0.0 end $hw configure -state disabled $state(board) bind figure <1> {} $state(board) bind figure {} $state(board) bind figure {} bind $state(board) [namespace code [list motion $gid %x %y]] bind $state(board) [namespace code [list motion $gid %x %y]] bind $state(board) [namespace code [list leave $gid %x %y]] bind $state(board) \ [namespace code [list release $gid %x %y]] ::xmpp::sendIQ $state(xlib) set \ -query [::xmpp::xml::create board \ -xmlns games:board \ -attrs [list type battleship \ id $state(id)] \ -subelements $subels \ -subelements $shipSubels] \ -to $state(opponent) \ -command [namespace code [list send_result board $gid]] } proc battleship::send_board2 {gid} { variable board_size variable $gid upvar 0 $gid state for {set c 0} {$c < $board_size} {incr c} { for {set r 0} {$r < $board_size} {incr r} { set pos($c,$r) 0 } } foreach ship $state(position,ships) { foreach {c r} [coordinates $ship] { set pos($c,$r) 1 } } set subels {} for {set c 0} {$c < $board_size} {incr c} { for {set r 0} {$r < $board_size} {incr r} { lappend subels [::xmpp::xml::create cell \ -attrs [list col $c \ row $r \ ship $pos($c,$r) \ seed $state(seed,$c,$r)]] } } ::xmpp::sendIQ $state(xlib) set \ -query [::xmpp::xml::create board \ -xmlns games:board \ -attrs [list type battleship \ id $state(id)] \ -subelements $subels] \ -to $state(opponent) \ -command [namespace code [list send_result board2 $gid]] } proc battleship::send_move {gid c r draw} { variable $gid upvar 0 $gid state set els [list [::xmpp::xml::create shot -attrs [list row $r col $c]]] if {$draw} { lappend els [::xmpp::xml::create draw] } ::xmpp::sendIQ $state(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type battleship \ id $state(id)] \ -subelements $els] \ -to $state(opponent) \ -command [namespace code [list send_turn_result $gid $c $r $draw]] } proc battleship::send_turn_result {gid c r draw status xml} { variable $gid upvar 0 $gid state if {![string equal $status ok]} { attention_message $gid \ [::msgcat::mc "\n\n Opponent rejected move:\n %s\n\n" \ [error_to_string $xml]] restore_position $gid } else { ::xmpp::xml::split $xml tag xmlns attrs cdata subels foreach subel $subels { ::xmpp::xml::split $subel stag sxmlns sattrs scdata ssubels switch -- $stag { shot { set result [::xmpp::xml::getAttr $sattrs result] set seed [::xmpp::xml::getAttr $sattrs seed] set state(oseed,$c,$r) $seed switch -- $result { hit { set hit 1 set destroy 0 } destroy { set hit 1 set destroy 1 } default { set hit 0 set destroy 0 } } if {[sha1::sha1 $seed$hit] ne $state(hash,$c,$r)} { attention_message $gid \ [::msgcat::mc "\n\n Opponent returned\ incorrect cell seed"] return } if {$hit} { # Checking if the currenlty hit ship is destroyed set ship [find_destroyed_ship $gid $c $r] set acc "" foreach {c1 r1} [coordinates $ship] { append acc $state(oseed,$c1,$r1) } set hash [sha1::sha1 $acc] if {$destroy && \ [lsearch -exact $state(shiphashes) $hash] < 0} { attention_message $gid \ [::msgcat::mc "\n\n Opponent returned\ incorrect destroy answer"] return } elseif {!$destroy && $hit && \ [lsearch -exact $state(shiphashes) $hash] >= 0} { attention_message $gid \ [::msgcat::mc "\n\n Opponent returned\ inconrrect hit answer"] return } } do_move $gid $c $r $result $draw update_controls $gid $draw draw_position $gid highlight_last_move $gid return } } } attention_message $gid \ [::msgcat::mc "\n\n Opponent returned incorrect answer"] } } proc battleship::find_destroyed_ship {gid c r} { variable sizes variable board_size variable $gid upvar 0 $gid state set r1 $r while {$r1 >= 0 && ($state(position,mshot,$c,$r1) == 1 || $state(position,mshot,$c,$r1) == -1)} { incr r1 -1 } incr r1 set r2 $r while {$r2 < $board_size && ($state(position,mshot,$c,$r2) == 1 || $state(position,mshot,$c,$r2) == -1)} { incr r2 } incr r2 -1 if {$r2 > $r1} { set size [expr {$r2 - $r1 + 1}] foreach {name s} $sizes { if {$s == $size} { return [list $name vertical $c $r1] } } return } set c1 $c while {$c1 >= 0 && ($state(position,mshot,$c1,$r) == 1 || $state(position,mshot,$c1,$r) == -1)} { incr c1 -1 } incr c1 set c2 $c while {$c2 < $board_size && ($state(position,mshot,$c2,$r) == 1 || $state(position,mshot,$c2,$r) == -1)} { incr c2 } incr c2 -1 set size [expr {$c2 - $c1 + 1}] foreach {name s} $sizes { if {$s == $size} { return [list $name horizontal $c1 $r] } } return } proc battleship::send_result {type gid status xml} { variable $gid upvar 0 $gid state switch -- $type { board { if {![string equal $status ok]} { set state(board_is_sent) 0 set_label_move $gid update_controls $gid attention_message $gid \ [::msgcat::mc "\n\n Opponent rejected\ board:\n %s\n\n" \ [error_to_string $xml]] } } board2 { if {![string equal $status ok]} { attention_message $gid \ [::msgcat::mc "\n\n Opponent rejected\ board:\n %s\n\n" \ [error_to_string $xml]] } } } } proc battleship::add_move_to_history {gid {c ""} {r ""} {result ""} {draw 0}} { variable board_size variable $gid upvar 0 $gid state incr state(position,halfmove) if {$c != "" && $r != ""} { lappend state(position,history) [list $c $r $result $draw] } else { lappend state(position,history) skip } set hw $state(hw) $hw configure -state normal $hw delete 0.0 end if {$state(move_first)} { $hw insert end "\t[::msgcat::mc You]\t[::msgcat::mc Opponent]\n" } else { $hw insert end "\t[::msgcat::mc Opponent]\t[::msgcat::mc You]\n" } set i 1 foreach {b w} $state(position,history) { $hw insert end "${i}.\t" if {$b == "skip"} { $hw insert end "--\t" } elseif {$b != {}} { lassign $b c r res d set r [expr {$board_size - $r}] set l [format %c [expr {$c+97}]] switch -- $res { destroy { set s # } hit { set s + } default { set s "" } } if {$d} { set e "=" } else { set e "" } $hw insert end "$l$r$s$e\t" } if {$w == "skip"} { $hw insert end "--\n" } elseif {$w != {}} { lassign $w c r res d set r [expr {$board_size - $r}] set l [format %c [expr {$c+97}]] switch -- $res { destroy { set s # } hit { set s + } default { set s "" } } if {$d} { set e "=" } else { set e "" } $hw insert end "$l$r$s$e\n" } else { $hw insert end "\n" } incr i } $hw see end $hw configure -state disabled } proc battleship::find_reasonable_moves {gid color} { variable board_size variable ships variable $gid upvar 0 $gid state set state(reasonable_moves) {} set total 0 foreach {name number} $ships { incr total $number } if {[llength $state(position,destroyed_my_ships)] < $total && [llength $state(position,destroyed_ships)] < $total} { for {set c 0} {$c < $board_size} {incr c} { for {set r 0} {$r < $board_size} {incr r} { if {$state(position,mshot,$c,$r) == ""} { lappend state(reasonable_moves) [list $c $r] } } } } highlight_reasonable_moves $gid } proc battleship::is_move_reasonable {gid c r} { variable $gid upvar 0 $gid state expr {[lsearch -regexp $state(reasonable_moves) ^[list $c $r]] >= 0} } proc battleship::highlight_reasonable_moves {gid} { variable $gid upvar 0 $gid state set board $state(board) $board dtag reasonable foreach move $state(reasonable_moves) { lassign $move c r $board addtag reasonable withtag [list cr $c $r]&&square } } proc battleship::attention_message {gid message} { variable $gid upvar 0 $gid state set hw $state(hw) $hw configure -state normal $hw delete {end -1 char} end $hw insert end $message attention $hw see end $hw configure -state disabled } proc battleship::is_my_move {gid} { variable $gid upvar 0 $gid state if {$state(move_first) && $state(position,turn) == "first"} { return 1 } elseif {!$state(move_first) && $state(position,turn) == "second"} { return 1 } else { return 0 } } ####################################################################### proc battleship::add_groupchat_user_menu_item {m xlib jid} { set mm $m.gamesmenu if {![winfo exists $mm]} { menu $mm -tearoff 0 $m add cascade -label [::msgcat::mc "Games"] -menu $mm } $mm add command -label [::msgcat::mc "Battleship..."] \ -command [namespace code [list invite_dialog $xlib $jid]] } proc battleship::iq_create {varname xlib from iqid xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- [::xmpp::xml::getAttr $attrs type] { battleship { if {[::xmpp::xml::isAttr $attrs first]} { set first [::xmpp::xml::getAttr $attrs first] switch -- $first { true - 1 { set first true } false - 0 { set first false } default { set var [list error modify bad-request] } } } else { set first true } set var [invited_dialog $xlib $from $iqid \ [::xmpp::xml::getAttr $attrs id] \ $first] } } return } proc battleship::iq_init {varname xlib from xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- [::xmpp::xml::getAttr $attrs type] { battleship { set gid [make_gid $from [::xmpp::xml::getAttr $attrs id]] if {[exists $gid]} { set var [board_recv $gid $subels] } else { set var [list error cancel item-not-found] } } } return } proc battleship::iq_turn {varname xlib from xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- [::xmpp::xml::getAttr $attrs type] { battleship { set gid [make_gid $from [::xmpp::xml::getAttr $attrs id]] if {[exists $gid]} { set var [turn_recv $gid $subels] } else { set var [list error cancel item-not-found] } } } return } # Common games:board part proc iq_games_board_create {xlib from xml args} { set res [list error cancel feature-not-implemented] set iqid [::xmpp::xml::getAttr $args -id] hook::run games_board_create_hook res $xlib $from $iqid $xml return $res } proc iq_games_board_init {xlib from xml args} { set res [list error cancel feature-not-implemented] hook::run games_board_init_hook res $xlib $from $xml return $res } proc iq_games_board_turn {xlib from xml args} { set res [list error cancel feature-not-implemented] hook::run games_board_turn_hook res $xlib $from $xml return $res } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/battleship/msgs000075500000000000000000000000001500237002100165425ustar00nobodynobodytkabber-plugins/battleship/msgs/ru.msg000064400000000000000000000155601500237002100177660ustar00nobodynobody# ru.msg -- # # Russian messages for the Battleship Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Plugins options." "Параметры раÑширений." ::msgcat::mcset ru "Show last move by default." \ "По умолчанию показывать поÑледний ход." ::msgcat::mcset ru "You" "Ð’Ñ‹" ::msgcat::mcset ru "Opponent" "Оппонент" ::msgcat::mcset ru "Battleship plugin options." \ "Параметры раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ ÐœÐ¾Ñ€Ñкой бой." ::msgcat::mcset ru "Battleship pixmaps theme." "Тема фигурок кораблей." ::msgcat::mcset ru "Show tooltips with short instructions." \ "Показывать вÑплывающие подÑказки к Ñлементам интерфейÑа." ::msgcat::mcset ru "Battleship Invitation" "Приглашение Ñыграть в морÑкой бой" ::msgcat::mcset ru "Sending Battleship game invitation to %s (%s)" \ "ПоÑылаем приглашение Ñыграть в морÑкой бой Ñ %s (%s)" ::msgcat::mcset ru "I want to move first" "Хочу ходить первым" ::msgcat::mcset ru "I want to move second" "Хочу ходить вторым" ::msgcat::mcset ru "Cancel invitation" "Отменить приглашение" ::msgcat::mcset ru "%s (%s) has refused Battleship invitation: %s" \ "%s (%s) отказалÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ в морÑкой бой: %s" ::msgcat::mcset ru "Battleship Invitation from %s" \ "Приглашение Ñыграть в морÑкой бой Ñ %s" ::msgcat::mcset ru "Battleship game invitation from %s (%s) is received." \ "Получено приглашение Ñыграть в морÑкой бой Ñ %s (%s)" ::msgcat::mcset ru "%s wants to move first." "%s хочет ходить первым." ::msgcat::mcset ru "%s wants to move second." "%s хочет ходить вторым." ::msgcat::mcset ru "Agree to play" "СоглаÑитьÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ" ::msgcat::mcset ru "Refuse to play" "ОтказатьÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ" ::msgcat::mcset ru "Battleship with %s" "МорÑкой бой Ñ %s" ::msgcat::mcset ru "Show last move" "Показывать поÑледний ход" ::msgcat::mcset ru "Move: " "Ход: " ::msgcat::mcset ru "Propose a draw" "Предложить ничью" ::msgcat::mcset ru "Accept the draw proposal" "ПринÑть предложенную ничью" ::msgcat::mcset ru "Resign the game" "Сдать партию" ::msgcat::mcset ru "History" "ЗапиÑÑŒ партии" ::msgcat::mcset ru "Battleship..." "МорÑкой бой..." ::msgcat::mcset ru "Opponent wins" "Оппонент выиграл" ::msgcat::mcset ru "You win" "Ð’Ñ‹ выиграли" ::msgcat::mcset ru "Opponent wins (You resigned)" \ "Оппонент выиграл (Ð’Ñ‹ ÑдалиÑÑŒ)" ::msgcat::mcset ru "You win (Opponent resigned)" \ "Ð’Ñ‹ выиграли (Оппонент ÑдалÑÑ)" ::msgcat::mcset ru "Impossible draw" "ÐÐµÐ²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð°Ñ Ð½Ð¸Ñ‡ÑŒÑ" ::msgcat::mcset ru "Draw (You accepted)" "ÐÐ¸Ñ‡ÑŒÑ (Ð’Ñ‹ принÑли)" ::msgcat::mcset ru "Draw (Opponent accepted)" "ÐÐ¸Ñ‡ÑŒÑ (Оппонент принÑл)" ::msgcat::mcset ru "Press button and make move if you want to propose draw" \ "Ðажмите кнопку и Ñделайте ход, еÑли хотите предложить ничью" ::msgcat::mcset ru "Press button if you want to accept the draw proposal" \ "Ðажмите кнопку, еÑли хотите принÑть предложенную ничью" ::msgcat::mcset ru "Press button if you want to resign" \ "Ðажмите кнопку, еÑли хотите ÑдатьÑÑ" ::msgcat::mcset ru "\n\n Opponent proposes a draw\n\n" \ "\n\n Оппонент предлагает ничью\n\n" ::msgcat::mcset ru "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Оппонент отверг ход:\n %s\n\n" ::msgcat::mcset ru "Games" "Игры" ::msgcat::mcset ru "Freeze ships position" "ЗафикÑировать положение кораблей" ::msgcat::mcset ru "My ships" "Мои корабли" ::msgcat::mcset ru "Opponent (after all parties freeze boards)" \ "Оппонент (поÑле того, как вÑе зафикÑируют Ñвои доÑки)" ::msgcat::mcset ru "Opponent ships" "Корабли оппонента" ::msgcat::mcset ru "Whether the Battleship plugin is loaded." \ "Загружено ли раÑширение МорÑкой бой." ::msgcat::mcset ru "You (after all parties freeze boards)" \ "Ð’Ñ‹ (поÑле того, как вÑе зафикÑируют Ñвои доÑки)" ::msgcat::mcset ru "\n\n Opponent rejected board:\n %s\n\n" \ "\n\n Оппонент не принÑл доÑку:\n %s\n\n" ::msgcat::mcset ru "\n\n Opponent returned inconrrect hit answer" \ "\n\n Оппонент вернул неправильный ответ 'попал'" ::msgcat::mcset ru "\n\n Opponent returned incorrect answer" \ "\n\n Оппонент вернул неправильный ответ" ::msgcat::mcset ru "\n\n Opponent returned incorrect cell seed" \ "\n\n Оппонент вернул неправильный Ñид Ñчейки" ::msgcat::mcset ru "\n\n Opponent returned incorrect destroy answer" \ "\n\n Оппонент вернул неправильный ответ 'убил'" ::msgcat::mcset ru "\n\n Opponent sent incorrect cell column" \ "\n\n Оппонент приÑлал неправильную колонку" ::msgcat::mcset ru "\n\n Opponent sent incorrect cell row" \ "\n\n Оппонент вернул неправильную Ñтроку" ::msgcat::mcset ru "\n\n Opponent sent incorrect cell seed" \ "\n\n Оппонент вернул неправильный Ñид Ñчейки" ::msgcat::mcset ru "\n\n Opponent sent incorrect number of cells" \ "\n\n Оппонент вернул неправильное чиÑло Ñчеек" ::msgcat::mcset ru "\n\n Opponent rejected accepted draw:\n %s\n\n" \ "\n\n Оппонент отверг принÑтие ничьей:\n %s\n\n" ::msgcat::mcset ru "\n\n Opponent sent illegal board" \ "\n\n Оппонент приÑлал доÑку, не удовлетворÑющую правилам" ::msgcat::mcset ru "\nDrag and drop ships to desired locations, then click\ the 'Freeze ships position' button.\nRight mouse button switches\ horizontal and vertical ship orientation." "\nПередвиньте корабли,\ куда хотите, потом нажмите кнопку 'ЗафикÑировать положение\ кораблей'.\nÐŸÑ€Ð°Ð²Ð°Ñ ÐºÐ½Ð¾Ð¿ÐºÐ° мыши переключает вертикальное и\ горизонтальное положение кораблÑ." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/battleship/msgs/uk.msg000064400000000000000000000156521500237002100177610ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Battleship Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Plugins options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½ÑŒ." ::msgcat::mcset uk "Show last move by default." \ "За замовчуваннÑм показувати оÑтанній хід." ::msgcat::mcset uk "You" "Ви" ::msgcat::mcset uk "Opponent" "Опонент" ::msgcat::mcset uk "Battleship plugin options." \ "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ ÐœÐ¾Ñ€Ñький бій." ::msgcat::mcset uk "Battleship pixmaps theme." "Тема фігурок кораблів." ::msgcat::mcset uk "Show tooltips with short instructions." \ "Показувати Ñпливаючі підказки до елементів інтерфейÑу." ::msgcat::mcset uk "Battleship Invitation" "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ у морÑький бій" ::msgcat::mcset uk "Sending Battleship game invitation to %s (%s)" \ "ÐадÑилаємо Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ у морÑький бій з %s (%s)" ::msgcat::mcset uk "I want to move first" "Хочу ходити першим" ::msgcat::mcset uk "I want to move second" "Хочу ходити другим" ::msgcat::mcset uk "Cancel invitation" "Відмінити запрошеннÑ" ::msgcat::mcset uk "%s (%s) has refused Battleship invitation: %s" \ "%s (%s) відмовивÑÑ Ð³Ñ€Ð°Ñ‚Ð¸ у морÑький бій: %s" ::msgcat::mcset uk "Battleship Invitation from %s" \ "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ у морÑький бій з %s" ::msgcat::mcset uk "Battleship game invitation from %s (%s) is received." \ "Отримане Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ у морÑький бій з %s (%s)" ::msgcat::mcset uk "%s wants to move first." "%s хоче ходити першим." ::msgcat::mcset uk "%s wants to move second." "%s хоче ходити другим." ::msgcat::mcset uk "Agree to play" "ЗгодитиÑÑ Ð³Ñ€Ð°Ñ‚Ð¸" ::msgcat::mcset uk "Refuse to play" "ВідмовитиÑÑ Ð³Ñ€Ð°Ñ‚Ð¸" ::msgcat::mcset uk "Battleship with %s" "МорÑький бій з %s" ::msgcat::mcset uk "Show last move" "Показувати оÑтанній хід" ::msgcat::mcset uk "Move: " "Хід: " ::msgcat::mcset uk "Propose a draw" "Запропонувати нічию" ::msgcat::mcset uk "Accept the draw proposal" "ПрийнÑти запропоновану нічию" ::msgcat::mcset uk "Resign the game" "Здати партію" ::msgcat::mcset uk "History" "Ð—Ð°Ð¿Ð¸Ñ Ð¿Ð°Ñ€Ñ‚Ñ–Ñ—" ::msgcat::mcset uk "Battleship..." "МорÑький бій..." ::msgcat::mcset uk "Opponent wins" "Опонент виграв" ::msgcat::mcset uk "You win" "Ви виграли" ::msgcat::mcset uk "Opponent wins (You resigned)" \ "Опонент виграв (Ви здалиÑÑ)" ::msgcat::mcset uk "You win (Opponent resigned)" \ "Ви виграли (Опонент здавÑÑ)" ::msgcat::mcset uk "Impossible draw" "Ðеможлива нічиÑ" ::msgcat::mcset uk "Draw (You accepted)" "ÐÑ–Ñ‡Ð¸Ñ (Ви прийнÑли)" ::msgcat::mcset uk "Draw (Opponent accepted)" "ÐÑ–Ñ‡Ð¸Ñ (Опонент прийнÑв)" ::msgcat::mcset uk "Press button and make move if you want to propose draw" \ "ÐатиÑніть кнопку Ñ– зробіть хід, Ñкщо хочете запропонувати нічию" ::msgcat::mcset uk "Press button if you want to accept the draw proposal" \ "ÐатиÑніть кнопку, Ñкщо хочете прийнÑти запропонованц нічию" ::msgcat::mcset uk "Press button if you want to resign" \ "ÐатиÑніть кнопку, Ñкщо хочете здатиÑÑ" ::msgcat::mcset uk "\n\n Opponent proposes a draw\n\n" \ "\n\n Опонент пропонує нічию\n\n" ::msgcat::mcset uk "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Опонент відкинув хід:\n %s\n\n" ::msgcat::mcset uk "Games" "Ігри" ::msgcat::mcset uk "Freeze ships position" "ЗафікÑувати Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð°Ð±Ð»Ñ–Ð²" ::msgcat::mcset uk "My ships" "Мої кораблі" ::msgcat::mcset uk "Opponent (after all parties freeze boards)" \ "Опонент (піÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк уÑÑ– зафікÑують Ñвої дошки)" ::msgcat::mcset uk "Opponent ships" "Кораблі опонента" ::msgcat::mcset uk "Whether the Battleship plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ ÐœÐ¾Ñ€Ñький бій." ::msgcat::mcset uk "You (after all parties freeze boards)" \ "Ви (піÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк уÑÑ– зафікÑують Ñвої дошки)" ::msgcat::mcset uk "\n\n Opponent rejected board:\n %s\n\n" \ "\n\n Опонент не прийнÑв дошку:\n %s\n\n" ::msgcat::mcset uk "\n\n Opponent returned inconrrect hit answer" \ "\n\n Опонент повернув неправильну відповідь 'вцілив'" ::msgcat::mcset uk "\n\n Opponent returned incorrect answer" \ "\n\n Опонент повернув неправильну відповідь" ::msgcat::mcset uk "\n\n Opponent returned incorrect cell seed" \ "\n\n Опонент повернув неправильний Ñід клітинки" ::msgcat::mcset uk "\n\n Opponent returned incorrect destroy answer" \ "\n\n Опонент повернув неправильну відповідь 'вбив'" ::msgcat::mcset uk "\n\n Opponent sent incorrect cell column" \ "\n\n Опонент приÑлав неправильний Ñтовпець" ::msgcat::mcset uk "\n\n Opponent sent incorrect cell row" \ "\n\n Опонент приÑлав неправильний Ñ€Ñдок" ::msgcat::mcset uk "\n\n Opponent sent incorrect cell seed" \ "\n\n Опонент приÑлав неправильний Ñід клітинки" ::msgcat::mcset uk "\n\n Opponent sent incorrect number of cells" \ "\n\n Опонент приÑлав неправильну кількіÑть клітинок" ::msgcat::mcset uk "\n\n Opponent rejected accepted draw:\n %s\n\n" \ "\n\n Опонент відкинув прийнÑÑ‚Ñ‚Ñ Ð½Ñ–Ñ‡Ð¸Ñ”Ñ—:\n %s\n\n" ::msgcat::mcset uk "\n\n Opponent sent illegal board" \ "\n\n Опонент приÑлав дошку, Ñка не узгоджуєтьÑÑ Ð· правилами" ::msgcat::mcset uk "\nDrag and drop ships to desired locations, then click\ the 'Freeze ships position' button.\nRight mouse button switches\ horizontal and vertical ship orientation." "\nПереÑуньте кораблі,\ куди завгодно, потім натиÑніть кнопку 'ЗафікÑувати положеннÑ\ кораблів'.\nПрава кнопка миші переключає вертикальне Ñ–\ горизонтальне Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð°Ð±Ð»Ñ." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/battleship/pixmaps000075500000000000000000000000001500237002100172525ustar00nobodynobodytkabber-plugins/battleship/pixmaps/copybook000075500000000000000000000000001500237002100210775ustar00nobodynobodytkabber-plugins/battleship/pixmaps/copybook/battleship-h.gif000064400000000000000000000002201500237002100242230ustar00nobodynobodyGIF87ap€ÿÿÿ,po„©Ëí£œ´Ú‹iؼû†âH–æÉ!èʶî›ðL×­jçúàü\ù‚ÄâghL‘ÊæŽéŒÒ ÒêMf;¨Ú®ˆë wÀb1¹ì=£µêµµí–ÂãÎ9]i¿óú%¶Æø“Qhxˆ˜¨¸ÈP;tkabber-plugins/battleship/pixmaps/copybook/battleship-v.gif000064400000000000000000000003601500237002100242460ustar00nobodynobodyGIF87ap€ÿÿÿ,pÏ„©Ëí¢œ´Jd³ÆºOîy`¸Ad7žUª~f»¾°kÌqmÓ@®ó—œcÍ„0b˨Bž”$fÈ)Ú (éÐZĵIîÒÛ?ÅQœZ2óжÅ}ÛùpJ½7¿ÿÔAr•?å—&w&Øfø†7G§hçˆWx5™U¹uÙ•ùµÖ9öYF¸¹7Úúw˜:ȨÛØzH›h»˜W»;»JùkŒ9¬YÌyì™ º,úÚ+ =ûXIzmú¬ÍÛíËݬN®û-}þ ¾Î¾P;tkabber-plugins/battleship/pixmaps/copybook/carrier-h.gif000064400000000000000000000002361500237002100235220ustar00nobodynobodyGIF87aŒ€ÿÿÿ,Œ}„©Ëí£œ´Ú‹³Þ*ø†âH–扦êÊ"ì ÇòLnçúnÞü ¶¢ñèñ!—Lš² ¢žÒª5I¼j­Ô­÷ØýŠá±9W>«eéµ{Õ~Ë{Ù¹^¿ë醽¿÷7(øFX¸vˆx¦¸8ÖèøÅ1IYiy‰™©‰Y;tkabber-plugins/battleship/pixmaps/copybook/carrier-v.gif000064400000000000000000000004271500237002100235420ustar00nobodynobodyGIF87aŒ€ÿÿÿ,Œö„©Ëí¢œ´Jd³ÆºOîy`¸Ad7žUª~f»¾°kÌqmÓ@®ó—œcÍ„0b˨Bž”$fÈ)Ú (éÐZĵIîÒÛ?ÅQœZ2óжÅ}ÛùpJ½7¿ÿÔAr•?å—&w&Øfø†7G§hçˆWx5™U¹uÙ•ùµÖ9öYF¸¹7Úúw˜:ȨÛØzH›h»˜W»;»JùkŒ9¬YÌyì™ º,úÚ+ =ûXIzmú¬ÍÛíËݬN®û-}N-îj¾^ë~ Ÿ+)o]z¿Ý^Nߟ­Ï[@pü ú3ð_>…¬>x1"ƒ;tkabber-plugins/battleship/pixmaps/copybook/cruiser-h.gif000064400000000000000000000001631500237002100235460ustar00nobodynobodyGIF87a8€ÿÿÿ,8R„©Ëí£l¡Ú‹³Þ\£†böæIèŠ–ì ºðœôÉ8­ïpïcƒ-q6<Ž’Ê³ÙyB7Òi `-Ú²¦*·âý†¹ãlÙ:I«×ìv£;tkabber-plugins/battleship/pixmaps/copybook/cruiser-v.gif000064400000000000000000000002221500237002100235600ustar00nobodynobodyGIF87a8€ÿÿÿ,8q„©Ëí¢œ´Jd³ÆºOîy`¸Ad7žUª~f»¾°kÌqmÓ@®ó—œcÍ„0b˨Bž”$fÈ)Ú (éÐZĵIîÒÛ?ÅQœZ2óжÅ}ÛùpJ½7¿ÿÔAr•?å—&w&Øfø†÷ÀØèˆP;tkabber-plugins/battleship/pixmaps/copybook/destroyer-h.gif000064400000000000000000000002031500237002100241050ustar00nobodynobodyGIF87aT€ÿÿÿ,Tb„©Ëí£œ´Ö€³Þ¼û†"†Œæ‰¦[©¶î°ðLrãwο{Dý‚Äаˆä“ÌØ¡ ]=£Ô%5h½ö²Ú·[û‚gâ±oj&–Óª5[ˆ~óÜò½n´è÷ü¾ÿßW;tkabber-plugins/battleship/pixmaps/copybook/destroyer-v.gif000064400000000000000000000003071500237002100241300ustar00nobodynobodyGIF87aT€ÿÿÿ,T¦„©Ëí¢œ´Jd³ÆºOîy`¸Ad7žUª~f»¾°kÌqmÓ@®ó—œcÍ„0b˨Bž”$fÈ)Ú (éÐZĵIîÒÛ?ÅQœZ2óжÅ}ÛùpJ½7¿ÿÔAr•?å—&w&Øfø†7G§hçˆWx5™U¹uÙ•ùµÖ9öYF¸¹7Úúw˜:ȨÛØzH›h»˜W»;»Jù,<œP;tkabber-plugins/battleship/pixmaps/copybook/field-shaded.gif000064400000000000000000000015721500237002100241630ustar00nobodynobodyGIF89açœ333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~€€€‚‚‚ƒƒƒ„„„………†††‡‡‡ˆˆˆ‰‰‰ŠŠŠ‹‹‹ŒŒŒŽŽŽ‘‘‘’’’“““”””•••–––———˜˜˜™™™ššš›››œœœžžžŸŸŸ   ¡¡¡¢¢¢£££¤¤¤¥¥¥¦¦¦§§§¨¨¨©©©ªªª«««¬¬¬­­­®®®¯¯¯°°°±±±²²²³³³´´´µµµ¶¶¶···¸¸¸¹¹¹ººº»»»¼¼¼½½½¾¾¾¿¿¿ÀÀÀÁÁÁÂÂÂÃÃÃÄÄÄÅÅÅÆÆÆÇÇÇÈÈÈÉÉÉÊÊÊËËËÌÌÌÍÍÍÎÎÎÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,_H° Áƒ@)\Ȱ¡Ã†Jœ¨0"Å‹ -bĨq#ÅŽ%‚ ép$ÉŒ OŠL©²$Ë–(aº” ñ%M“-qªÔy’'IŸ!zº‘(G›2^Tú)L„P£ ;tkabber-plugins/battleship/pixmaps/copybook/field.gif000064400000000000000000000001361500237002100227300ustar00nobodynobodyGIF89a€sssÞÞÞ,=„© ᣌfÚë*ÞPsî}X(Zd)h׬fë¦pÌÒ²M͸ó®¿¢„%¢ÈøA‚t6åÆ9bÒÔª¡;tkabber-plugins/battleship/pixmaps/copybook/hit.gif000064400000000000000000000001701500237002100224270ustar00nobodynobodyGIF89a€ÿÿÿ!ù ,O‚©ËißbƒPÚ°]:›Í}L'‘Žx¡‘y ËN*¯j]Šxú¸`>ûv›^Pèq‡¾$’\:eM ¯x UK“tÚzB}_Í> ;tkabber-plugins/battleship/pixmaps/copybook/icondef.xml000064400000000000000000000041101500237002100233030ustar00nobodynobody Copybook 1.0 Battleship Copybook Theme 2006-02-02 battleship/field field.gif battleship/field/shaded field-shaded.gif battleship/hit hit.gif battleship/miss miss.gif battleship/submarine/horizontal submarine-h.gif battleship/submarine/vertical submarine-v.gif battleship/cruiser/horizontal cruiser-h.gif battleship/cruiser/vertical cruiser-v.gif battleship/destroyer/horizontal destroyer-h.gif battleship/destroyer/vertical destroyer-v.gif battleship/battleship/horizontal battleship-h.gif battleship/battleship/vertical battleship-v.gif battleship/carrier/horizontal carrier-h.gif battleship/carrier/vertical carrier-v.gif tkabber-plugins/battleship/pixmaps/copybook/miss.gif000064400000000000000000000001141500237002100226140ustar00nobodynobodyGIF89a€ÿÿÿ!ù ,#Œ©Ëí£œ´Ú‹³Þ<Ð}ß&ŠZ9ž&—vî ÇòL×6W;tkabber-plugins/battleship/pixmaps/copybook/submarine-h.gif000064400000000000000000000001371500237002100240600ustar00nobodynobodyGIF87a€ÿÿÿ,>„©Ëí¢œ´Jd³ÆºOîy`¸Ad7žUª~f»¾°kÌqmÓ@®ó—œcÍ„0b˨Bž”$fÈ)ÚÔª•Q;tkabber-plugins/battleship/pixmaps/copybook/submarine-v.gif000064400000000000000000000001371500237002100240760ustar00nobodynobodyGIF87a€ÿÿÿ,>„©Ëí¢œ´Jd³ÆºOîy`¸Ad7žUª~f»¾°kÌqmÓ@®ó—œcÍ„0b˨Bž”$fÈ)ÚÔª•Q;tkabber-plugins/battleship/proto000064400000000000000000000106161500237002100167420ustar00nobodynobodyShort protocol description for the Battleship Tkabber plugin. Request: Positive response: ? After that the encrypted field must be sent by both players. Hash is SHA1 digest of concatenated random string seed and symbol 0 (if the field is empty) or 1 (if the field is occupied by a ship). Example1: seed qscercxifvrt gives 3ebe9d6974e3a2815271553605b3d3b74008e8d4 for free field and 7cdb05fd65cd3d943a7ff937cc0da5f31b990f76 for occupied field. Also, the ship hashes are to be included: each is a SHA1 hash of concatenated seeds for the positions where the ship is located. The cells go sequentially with one coordinate fixed and the other is growing. Seed MUST NOT be the same for different board cells. ... ... Response for the game board: Move: 'row' and 'col' attributes contain coordinates of cell to be shot. Coordinate is an integer between 0 and 9. Response MUST include the result ('miss', 'hit' or 'destroy') and the seed of the cell to check the result. Consistency check: SHA1(qwerty0) = 97e471491d08463424b97ea495218a67cfc339ca or: or (some ship is destroyed): Proposing draw (if you want to terminate game before someone wins): The move turn then unconditionally goes to the opponent. Accepting draw proposal: Resigning: Response: if move accepted, or error 'Not Acceptable' if other side thinks that this move illegal. After the game is over (either someone have lost all his/her ships, or someone resigned, or game was tied) both players MUST send uncovered boards with seeds: ... ... Response: if the board is consistent with the initial hashes. Otherwise client should return error 'Not Acceptable' tkabber-plugins/bc000075500000000000000000000000001500237002100140165ustar00nobodynobodytkabber-plugins/bc/bc.tcl000064400000000000000000000265721500237002100152010ustar00nobodynobody# bc.tcl -- # # This file implements Bulls & Cows game plugin for the Tkabber XMPP # client. The word game variant is used. And currently, only Russian # words are to be guessed. package require msgcat namespace eval bc { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered bc]} { ::plugins::register bc \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc \ "Whether the 'Bulls & Cows' plugin is\ loaded. The plugin implements game\ variant where players guess Russian\ words instead of numbers as usual."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable prefix {[B&C]: } } package require textutil proc bc::load_file {filename {enc utf-8}} { variable words set fd [open $filename] fconfigure $fd -encoding $enc set words {} while {![eof $fd]} { lappend words [string trim [gets $fd]] } close $fd } namespace eval bc { # A hack (reload the script in UTF-8 encoding) if {![info exists words]} { variable file [file join [file dirname [info script]] ru.dic] load_file $file utf-8 variable fd [open [info script]] fconfigure $fd -encoding utf-8 uplevel 1 [read $fd] close $fd return } } proc bc::load {} { hook::add draw_message_hook [namespace current]::handle_messages 79 hook::add generate_completions_hook \ [namespace current]::commands_comps hook::add chat_send_message_hook \ [namespace current]::handle_commands 50 } proc bc::unload {} { variable prefix variable words variable game variable word variable attempts variable top hook::remove draw_message_hook [namespace current]::handle_messages 79 hook::remove generate_completions_hook \ [namespace current]::commands_comps hook::remove chat_send_message_hook \ [namespace current]::handle_commands 50 foreach chatid [chat::opened] { if {[info exists game($chatid)]} { stop $chatid } } catch {unset prefix} catch {unset words} catch {unset game} catch {unset word} catch {unset attempts} catch {unset top} } proc bc::get_question {} { variable words if {![info exists words] || ![llength $words]} return while {![info exists w]} { set w [lindex $words [rand [llength $words]]] if {[regexp {(.).*\1} $w]} { unset w } } return $w } proc bc::commands_comps {chatid compsvar wordstart line} { upvar 0 $compsvar comps if {!$wordstart} { lappend comps "/bcstart " "/bcstop " "/bcnext " "/bctop " } } proc bc::handle_commands {chatid user body type} { variable game if {$type != "groupchat"} return if {[string index $body 0] != "/"} return set jid [chat::get_jid $chatid] lassign [textutil::splitx [string trim $body] {[\t \r\n]+}] command nick switch -- $command { /bcstart { start $chatid return stop } /bcstop { stop $chatid return stop } /bcnext { if {$nick != ""} { # Стоило бы проверить, что юзер в чате... next $chatid "$jid/$nick" $type } return stop } /bctop { top $chatid return stop } } return } proc bc::get_nick {chatid jid type} { if {[catch {chat::get_nick [chat::get_xlib $chatid] $jid $type} nick]} { return [chat::get_nick $jid $type] } else { return $nick } } proc bc::handle_messages {chatid from type body x} { variable game variable words variable word variable attempts variable prefix set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] set s [string trim $body] switch -- $s { !bctop { top $chatid return } !bcrules { printrules $chatid $from return } !bcstart - !bsnext { next $chatid $from $type } } if {![info exists game($chatid)] || ![info exists word($chatid,$from)]} { return } switch -- $s { default { set nick [get_nick $chatid $from $type] set w [filter $body] if {[string length $w] != 5} { return } set ww [filter $word($chatid,$from)] if {$w == $ww} { incr attempts($chatid,$from) set at $attempts($chatid,$from) message::send_msg $xlib $jid -type groupchat \ -body "$nick: ${prefix}Молодец! Задуманное Ñлово\ \"$word($chatid,$from)\" было отгадано за $at\ [lindex {. попытку попытки попыток} [numgrp $at]]." add_score $chatid $nick $ww $at unset word($chatid,$from) next $chatid $from $type return } if {[lsearch -exact $words $w] == -1} { message::send_msg $xlib $jid -type groupchat \ -body "$nick: ${prefix}Я не знаю Ñлова \"$w\"." return } set l [string length $w] set matches 0 for {set i 0} {$i < $l} {incr i} { incr matches \ [expr {[string first [string index $w $i] $ww] != -1}] } if {[info exists attempts($chatid,$from)]} { incr attempts($chatid,$from) } else { set attempts($chatid,$from) 1 } message::send_msg $xlib $jid -type groupchat \ -body "$nick: ${prefix}$w: $matches" } } } proc bc::start {chatid} { variable game variable prefix set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] if {![info exists game($chatid)]} { set game($chatid) "" message::send_msg $xlib $jid -type groupchat \ -body "${prefix}Добро пожаловать на игру \"Отгадай Ñлово\"!\ Чтобы узнать правила игры, введите !bcrules." } else { chat::add_message $chatid $jid error "Игра уже запущена" {} } } proc bc::stop {chatid} { variable game variable word variable attempts variable prefix set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] if {[info exists game($chatid)]} { foreach n [array names word "$chatid,*"] { unset word($n) } foreach n [array names attempts "$chatid,*"] { unset attempts($n) } foreach id [after info] { if {[string first [list [namespace current]::ask $chatid] \ [lindex [after info $id] 0]] == 0} { after cancel $id } } unset game($chatid) message::send_msg $xlib $jid -type groupchat \ -body "${prefix}Игра оÑтановлена." top $chatid } else { chat::add_message $chatid $jid error "Игра не запущена" {} } } proc bc::next {chatid jid type} { variable game variable word variable prefix set xlib [chat::get_xlib $chatid] set jid1 [chat::get_jid $chatid] if {[info exists game($chatid)]} { if {[info exists word($chatid,$jid)]} { set nick [get_nick $chatid $jid $type] message::send_msg $xlib $jid1 -type $type \ -body "$nick: ${prefix}Предыдущее Ñлово: $word($chatid,$jid)." } catch {unset word($chatid.$jid)} after idle [list [namespace current]::ask $chatid $jid] } else { chat::add_message $chatid $jid1 error "Игра не запущена" {} } } proc bc::ask {chatid jid} { variable game variable word variable attempts variable prefix set xlib [chat::get_xlib $chatid] set jid1 [chat::get_jid $chatid] after cancel [list [namespace current]::ask $chatid $jid] set word($chatid,$jid) [get_question] set attempts($chatid,$jid) 0 set nick [get_nick $chatid $jid groupchat] message::send_msg $xlib $jid1 -type groupchat \ -body "$nick: ${prefix}Слово загадано. Угадывай." } proc bc::filter {text} { regsub -all {[;:()\[\]!?.,/\\{}]} [string tolower $text] "" text return [string trim $text] } proc bc::numgrp {number} { switch -glob -- $number { *11 {return 3} *12 {return 3} *13 {return 3} *14 {return 3} *1 {return 1} *2 {return 2} *3 {return 2} *4 {return 2} default {return 3} } } proc bc::top {chatid} { variable top variable prefix set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] if {[info exists top($chatid)]} { set t [lsort -integer -increasing -index 2 $top($chatid)] set ts "" foreach item $t { lassign $item nick word score append ts "$score\t$word\t$nick\n" } message::send_msg $xlib $jid -type groupchat \ -body "${prefix}Top scores:\n$ts" } else { chat::add_message $chatid $jid error "Ðет данных о top scores" {} } } proc bc::add_score {chatid nick word attempts} { variable top if {![info exists top($chatid)]} { set top($chatid) {} } set t {} set b 1 foreach item $top($chatid) { lassign $item n w a if {$n == $nick} { if {$a > $attempts} { set a $attempts set w $word } set b 0 } lappend t [list $n $w $a] } if {$b} { lappend t [list $nick $word $attempts] } set top($chatid) $t } proc bc::printrules {chatid to} { variable game set xlib [chat::get_xlib $chatid] if {[info exists game($chatid)]} { message::send_msg $xlib $to -type chat \ -body "Правила игры \"Отгадай Ñлово\"\n\ 1) ВодÑщий (бот) загадывает пÑтибуквенное Ñлово\ (нарицательное ÑущеÑтвительное единÑтвенного чиÑла) в котором\ буквы не повторÑÑŽÑ‚ÑÑ.\n\ 2) Пока Ñлово не отгадано, игрок называет Ñвой вариант\ (в оригинале Ñлово любой длины, здеÑÑŒ пока тоже 5-буквенное)\ ВодÑщий Ñообщает ему, Ñколько букв из задуманного Ñлова ÑодержитÑÑ\ в названном.\n\ 3) ЕÑли Ñлово угадано, то игра заканчиваетÑÑ.\n\ \n\ Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы запуÑтить игру, вернитеÑÑŒ в конференцию и наберите !bcstart" } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/bc/msgs000075500000000000000000000000001500237002100147675ustar00nobodynobodytkabber-plugins/bc/msgs/ru.msg000064400000000000000000000011231500237002100162010ustar00nobodynobody# ru.msg -- # # Russian messages for the Bulls & Cows Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Whether the 'Bulls & Cows' plugin is loaded. The\ plugin implements game variant where players guess Russian\ words instead of numbers as usual." "Загружено ли раÑширение\ 'Быки и коровы'. Ð’ Ñтом раÑширении реализован вариант игры, в\ котором игроки угадывают пÑтибуквенное руÑÑкое Ñлово." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/bc/msgs/uk.msg000064400000000000000000000011241500237002100161730ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Bulls & Cows Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Whether the 'Bulls & Cows' plugin is loaded. The\ plugin implements game variant where players guess Russian\ words instead of numbers as usual." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ 'Бики та корови'. Це Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ñ”\ грою, де гравці вгадують Ñлово роÑійÑькою мовою, Ñкладене з\ п’Ñтьох літер." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/bc/ru.dic000064400000000000000000000517121500237002100152120ustar00nobodynobodyаббат абзац аборт абрек Ð°Ð±Ñ€Ð¸Ñ Ð°Ð±Ñ…Ð°Ð· Ð°Ð²Ð°Ð½Ñ Ð°Ð²Ð³ÑƒÑ€ авеню авизо аврал автол автор агава агент агнец адепт Ð°Ð´Ñ€ÐµÑ Ð°Ð·Ð°Ñ€Ñ‚ азиат айран актер актив акула акциз Ð°ÐºÑ†Ð¸Ñ Ð°Ð»ÐµÑƒÑ‚ алиби аллах аллюр алмаз алыча альфа амбар амбре амвон амеба амина ампер ампир ангар ангел Ð°Ð½Ð¾Ð½Ñ Ð°Ð½Ñ‚Ð¸Ðº Ð°Ð½Ñ„Ð°Ñ Ð°Ð¾Ñ€Ñ‚Ð° апорт арбуз аргон ареал арена ареÑÑ‚ ариец аркан Ð°Ñ€Ð¼Ð¸Ñ Ð°Ñ€Ð¼Ñк архив аршин аÑкет аÑпид аÑтма аÑтра атака Ð°Ñ‚Ð»Ð°Ñ Ð°Ñ‚Ð»ÐµÑ‚ атолл аудио афера афиша ацтек бабка багаж багет багор Ð±Ð°Ð´ÑŒÑ Ð±Ð°Ð·Ð°Ñ€ Ð±Ð°Ð·Ð¸Ñ Ð±Ð°Ð¹ÐºÐ° бакен балда балет балка балык банан банда банка барак баран баржа барий барин барич барон барыш баÑма баÑÐ½Ñ Ð±Ð°Ñ‚Ð¾Ð½ батуд батут бахча бачок башка Ð±Ð°ÑˆÐ½Ñ Ð±ÐµÐ³ÑƒÐ½ бедро Ð±ÐµÐºÐ°Ñ Ð±ÐµÐºÐ¾Ð½ белка белье белÑк белÑш берег бетон бивак бидон бизон билет билль бином биржа бирка бирюк биÑер битва биток битум битье битюг благо блажь бланк бленд блеÑк блоха блуза блюдо блÑха бобер богач божба божок Ð±Ð¾Ð¹Ð½Ñ Ð±Ð¾ÐºÐ°Ð» болид бомба бонза борец боров боÑÑк ботва ботик бочка бочок брага брань браÑÑ Ð±Ñ€ÐµÐ¼Ñ Ð±Ñ€ÐµÑˆÑŒ бридж бровь Ð±Ñ€Ð¾Ð½Ñ Ð±Ñ€Ð¾ÑˆÑŒ брюки брюхо бубен бугай бугор будка буква букет булат булка бурав бурак буран бурда бурка бурÑа бурун бутон буфер буфет бухта быдло былье бытие бытье бычок бьюик бювар вагон вазон вакÑа валет валик валун Ð²Ð°Ð»ÑŒÑ Ð²Ð°Ð½Ð½Ð° варка варÑг ватин ватка Ð²Ð°Ñ„Ð»Ñ Ð²Ð°Ñ…Ñ‚Ð° вдова ведро ведун венгр венец веник венок вепрь верба верфь верша веÑло веÑна веÑть ветвь ветер ветка ветла вечер вешка вещун взвод вздор вздох взлет взлом взмах Ð²Ð·Ð½Ð¾Ñ Ð²Ð·Ñ€Ñ‹Ð² видео визир визит вилка вилла винил винцо вираж Ð²Ð¸Ñ€ÑƒÑ Ð²Ð¸Ñок виток вихор вихрь Ð²Ð¸ÑˆÐ½Ñ Ð²ÐºÐ»Ð°Ð´ влага вобла водка вожак вождь вожжа Ð²Ð¾Ð·Ð½Ñ Ð²Ð¾Ð·Ð¾Ðº война вокал волна волхв вольт вопль ворох ворье вошка воÑка вплыв враль врата Ð²Ñ€ÐµÐ¼Ñ Ð²Ñ‚Ð¾Ñ€Ð° вуаль въезд выбор вывих вывод вывоз выгиб выгон выгул выдох выдра выдув выезд выжиг вызов выкуп вылет Ð²Ñ‹Ð½Ð¾Ñ Ð²Ñ‹Ð¿Ð°Ð´ вырез выход вычет вышка вьюга вÑзка газик газон гайка галка галоп галун гамак гамма гараж гарем гауÑÑ Ð³Ð°ÑˆÐ¸Ñˆ гвалт гейша гелий гемма гений геном герой гетто гидра гиена глава главк гладь глина глиÑÑ‚ глушь глыба гнида гниль гнуÑÑŒ гобой говор гогот годок голод Ð³Ð¾Ð»Ð¾Ñ Ð³Ð¾Ð»ÑŒÑ„ голÑк гомон гонец гонка гонор гопак горец горка горло город горох гоÑть грамм гранд грань греза греча грива грипп гроза груда грудь грунт груша грыжа грÑда грÑзь гуашь губка гудок гузка гулÑш гумно Ð³ÑƒÐ¼ÑƒÑ Ð³ÑƒÑ€Ð¸Ñ Ð³ÑƒÑак гуÑар гуÑли гюрза давка дамба дамка дачка дверь дебет дебил дебош дебри дебют девиз девка декан декор дележ делец демон денек дерби деÑна детка Ð´ÐµÑ„Ð¸Ñ Ð´Ð¶Ð¸Ð½Ð½ диван диета динар длань длина днище добро довод догма дождь дозор дойка докер долив домик домна донна донор Ð´Ð¾Ð½Ð¾Ñ Ð´Ð¾Ñка доÑуг доÑье доход дочка драга драка драма дрейф дрель дрема дробь дрова дрожь дрозд друза дрÑнь дубль дубок дубье дудка дужка думец дупло дурак дутье душка душок дуÑль дщерь дылда дымка дымок дырка дышло Ð´ÑŽÑˆÐµÑ Ð´Ñтел евнух еврей егерь егоза ездка ездок ереÑÑŒ ершик жабры жажда жакан жакет жарка жатва жатка желоб желчь жених жердь жерло жеÑть жетон живот живец жизнь жилет жилец жилка жилье жираф жирок житие житье жница жокей жрица жулик жулье жупел жучка жучок забег забой забор завал завет завод завуч загар загиб загон загул задел задок задор заезд зажим зазор заика зайка заказ закал закат закон закут залив залог замах замер Ð·Ð°Ð¼ÐµÑ Ð·Ð°Ð¼Ð¾Ðº замор замша Ð·Ð°Ð½Ð¾Ñ Ð·Ð°Ð¿Ð°Ð´ запал Ð·Ð°Ð¿Ð°Ñ Ð·Ð°Ð¿Ð°Ñ… запев запой запор зарок зарÑд заÑов Ð·Ð°Ñ‚ÐµÑ Ð·Ð°Ñ‚Ð¾Ð½ затор заумь заход зачет звено зверь зебра зелье зельц Ð·ÐµÐ¼Ð»Ñ Ð·ÐµÐ½Ð¸Ñ‚ зерно зефир зипун злато злоба злюка Ð·Ð½Ð°Ð¼Ñ Ð·Ð½Ð°Ñ‚ÑŒ зраза зубец зубок зÑтек ивнÑк игрек игрок идеал идиот ижица извив изгиб изгой излом Ð¸Ð·Ð½Ð¾Ñ Ð¸Ð·ÑŠÑн изыÑк икона икота имидж ингуш индий Ð¸Ð½Ð´ÑƒÑ Ð¸Ð½Ð´ÑŽÐº инжир иприт иÑкра иÑÐºÑƒÑ Ð¸Ñлам иÑпуг иÑтец иÑток иÑход иудей Ð¸ÑˆÐ¸Ð°Ñ ÐºÐ°Ð±Ð°Ðº кабан кагор кадет кадка кадык казак казан казах казна казнь ÐºÐ°Ð·ÑƒÑ ÐºÐ°Ð¹Ð»Ð¾ кайма какао калач калий калым ÐºÐ°Ð¼ÐµÑ ÐºÐ°Ð¼Ð¸Ð½ камыш канал канат канва канон ÐºÐ°Ð½Ð¾Ñ ÐºÐ°Ð½ÑƒÐ½ ÐºÐ°Ð¿Ð»Ñ ÐºÐ°Ð¿Ð¾Ñ€ капот каппа карат карга карма карта каÑка каÑÑа каÑта катар катер катет каток качка кашка кашне каюта квант кварц квота кегль ÐºÐµÐ³Ð»Ñ ÐºÐµÐ»ÑŒÑ ÐºÐµÐ¿ÐºÐ° кефир кивок кизил киоÑк кирка киÑет киÑÐµÑ ÐºÐ¸Ñка киÑта киÑть кишка кладь клаÑÑ ÐºÐ»ÐµÑ€Ðº клика клинч клише клоун клуша клюка клÑча книга кнÑзь кобра ковер ковка кожух козел козни койка койот кокон ÐºÐ¾ÐºÐ¾Ñ ÐºÐ¾Ð»Ð±Ð° колер ÐºÐ¾Ð»ÐµÑ ÐºÐ¾Ð»ÐºÐ° колок ÐºÐ¾Ð»Ð¾Ñ ÐºÐ¾Ð»ÑƒÐ½ колье кольт комар комик комод комок конек конец конка ÐºÐ¾Ð½ÑƒÑ ÐºÐ¾Ð½ÑŽÑ… ÐºÐ¾Ð¿Ð¸Ñ ÐºÐ¾Ð¿Ð½Ð° копье корка корма короб коÑец коÑмы коÑть коÑÑк котел котик кофта кочан кочка кошка кошма кощей кража краÑа кредо креÑÑ ÐºÑ€ÐµÑÑ‚ кровь кроль крона кроÑÑ ÐºÑ€Ð¾Ñ…Ð° крупа крыло крыÑа крыша кубик кубок кудри кузен ÐºÑƒÐ·Ð½Ñ ÐºÑƒÐ·Ð¾Ð² кукиш кукла кулак кулич культ кумач кумир ÐºÑƒÐ¼Ñ‹Ñ ÐºÑƒÐ½Ð°Ðº купец ÐºÑƒÐ¿Ð»Ñ ÐºÑƒÐ¿Ð¾Ð» купон кураж курва курок куÑок кутеж ÐºÑƒÑ…Ð½Ñ ÐºÑƒÑ‡ÐºÐ° кушак кювет лабаз лаваш лавка лавра ладан Ð»Ð°Ð´ÑŒÑ Ð»Ð°Ð·ÐµÑ€ лайка лакей лампа ландо ланит лапка лапша ларек ларец лаÑка лаÑÑо латыш лафет лафит левша легат ледок лежак лежка лейка лемма лемур лента лепет лепка лепта леÑка леÑок леÑть летун леший лиана ливер лидер ликер Ð»Ð¸Ð»Ð¸Ñ Ð»Ð¸Ð¼Ð°Ð½ лимит лимон лимфа линза Ð»Ð¸Ð½Ð¸Ñ Ð»Ð¸Ð¿ÐºÐ° лирик литий литье лихач лицей лишай лобби лобик лобок ловец Ð»Ð¾Ð²Ð»Ñ Ð»Ð¾Ð´ÐºÐ° ложка локон ломик ломка лопух лоток Ð»Ð¾Ñ‚Ð¾Ñ Ð»Ð¾Ñ†Ð¸Ñ Ð»ÑƒÐ±Ð¾Ðº лужок лучик лучок Ð»Ñ‹Ð¶Ð½Ñ Ð»ÑŽÑ‚Ð½Ñ Ð»Ñжка лÑмка Ð¼Ð°Ð³Ð¸Ñ Ð¼Ð°Ð³Ð¼Ð° мадам маета мажор Ð¼Ð°Ð·Ð½Ñ Ð¼Ð°Ð·Ð¾Ðº мазут майка майор макет малек малец малыш малÑÑ€ мамка манго манеж Ð¼Ð°Ð½Ð¸Ñ Ð¼Ð°Ð½Ð½Ð° манок манто марка Ð¼Ð°Ñ€Ð»Ñ Ð¼Ð°Ñка маÑло маÑон маÑÑа маÑть матка Ð¼Ð°Ñ„Ð¸Ñ Ð¼Ð°Ñ‡Ñ‚Ð° медок медÑк мезга мелок мерин мерка меÑÑа меÑто меÑть меÑÑц метан Ð¼ÐµÑ‚Ð¸Ñ Ð¼ÐµÑ‚ÐºÐ° метла метод метро мечта мешок Ð¼Ð¸Ð´Ð¸Ñ Ð¼Ð¸Ð»ÐºÐ° милок минор Ð¼Ð¸Ð½ÑƒÑ Ð¼Ð¸Ñ€Ð°Ð¶ мирок мирра миÑка митра мишка модем Ð¼Ð¾Ð´ÑƒÑ Ð¼Ð¾Ð¹Ð²Ð° мойка мокко молва молот монах мопед морда мороз морÑк моÑье мотив моток мотор мочка мошка мошна мразь мужик музей мулат мулла мулÑж Ð¼ÑƒÐ¼Ð¸Ñ Ð¼ÑƒÑ€Ð»Ð¾ муÑор муфта мушка мымра мыÑль мыÑок мытье мышка мышца мÑÑ€Ð¸Ñ Ð¼Ñкиш мÑлка мÑÐ¼Ð»Ñ Ð¼Ñтеж мÑчик набат набег набоб набор навар Ð½Ð°Ð²ÐµÑ Ð½Ð°Ð²ÐµÑ‚ навоз навык наган нагар надир наезд наказ накал налет налим налог намаз намек Ð½Ð°Ð½Ð¾Ñ Ð½Ð°Ð¿ÐµÐ² напор нарды народ нарыв нарÑд наÑÐ¾Ñ Ð½Ð°ÑƒÐºÐ° нахал Ð½Ð°Ñ†Ð¸Ñ Ð½Ð°Ñ‡ÐµÑ Ð½Ð°Ñда невод недра недуг некто немец немка ненец нефть нечет нечто никто нимфа нитка ничто Ð½Ð¸Ñ‡ÑŒÑ Ð½Ð¸Ñ‰Ð¸Ð¹ ножик ножка ножны нолик номер норка норма норов ноÑик ноÑка ноÑок нотка ночка нужда нутро нырок нытик нытье Ð½ÑŽÐ°Ð½Ñ Ð¾Ð°Ð·Ð¸Ñ Ð¾Ð±Ð²Ð°Ð» Ð¾Ð±Ð²Ð¸Ñ Ð¾Ð±Ð²Ð¾Ð´ обгон обдир обзор обида обком облет облик облом обман обмен обмер образ обрат обрез оброк обруч обрыв обрÑд обувь обуза обход объем обыÑк овраг огонь одежа одурь озеро озимь озноб океан окиÑÑŒ оклад оковы окрик округ октан октет окунь олень олива олифа олово ольха омега омела омлет омуль Ð¾Ð½Ð¸ÐºÑ Ð¾Ð¿Ð°Ð»Ð° опека опера опиÑÑŒ опиум оплот опора Ð¾Ð¿Ñ€Ð¾Ñ Ð¾Ð¿Ñ‚Ð¸Ðº Ð¾Ð¿Ñ†Ð¸Ñ Ð¾Ñ€Ð°Ð²Ð° орган Ð¾Ñ€Ð³Ð¸Ñ Ð¾Ñ€Ð´ÐµÐ½ ордер ореол оÑада оÑетр оÑина оÑкал оÑмий оÑоба оÑобь оÑока оÑтов отара отбой отбор отвал отвар ответ отвод отгон отгул отдел отдых отель отзыв отказ откат Ð¾Ñ‚ÐºÐ¾Ñ Ð¾Ñ‚ÐºÑƒÐ¿ отлет отлив отлов отлог отпад отпор отрез отрог отрок отрÑд отÑев отток отход отчет отчим офÑет охват охота очерк падеж пайка пакет Ð¿Ð°ÐºÐ»Ñ Ð¿Ð°Ð»Ð°Ñ Ð¿Ð°Ð»Ð°Ñ‡ палаш палец палка пампа панда панно папка парад парез парик Ð¿Ð°Ñ€Ð¸Ñ Ð¿Ð°Ñ€ÐºÐ° парок парта Ð¿Ð°Ñ€ÑƒÑ Ð¿Ð°Ñ€Ñ‡Ð° парша паÑта паÑха патер патлы пауза Ð¿Ð°Ñ„Ð¾Ñ Ð¿Ð°Ñ…Ð°Ð½ пацан пачка Ð¿Ð°ÑˆÐ½Ñ Ð¿ÐµÐ²ÐµÑ† певун Ð¿ÐµÐ³Ð°Ñ Ð¿ÐµÐºÐ»Ð¾ пемза пенал пенек пение пенка пенни пенье пепел перед перец перÑÑ‚ пеÑец пеÑик пеÑнь пеÑÐ½Ñ Ð¿ÐµÑок петит Ð¿ÐµÑ‚Ð»Ñ Ð¿ÐµÑ‚ÑƒÑ… печка пешка пиала пивко пивцо пижон пикап пикет пикша пилка пилот пинок пинта пират пирог пиÑец питон питье Ð¿Ð¸Ñ„Ð¸Ñ Ð¿Ð¸Ñ…Ñ‚Ð° Ð¿Ð»Ð°Ð¼Ñ Ð¿Ð»Ð°ÑÑ‚ плата плато плаха Ð¿Ð»ÐµÐ±Ñ Ð¿Ð»ÐµÐ²Ð° Ð¿Ð»ÐµÐ¼Ñ Ð¿Ð»ÐµÑ‚ÑŒ плечо плешь плита плоть плюха побег побои побор повар повод погон подол поезд пожар позер позор позыв поиÑк пойло пойма показ покат покой Ð¿Ð¾ÐºÐ¾Ñ Ð¿Ð¾Ð»Ð¸Ð² Ð¿Ð¾Ð»Ð¸Ñ Ð¿Ð¾Ð»ÐºÐ° полог полоз полок Ð¿Ð¾Ð»ÑŽÑ Ð¿Ð¾Ð»Ñк помет помои помол помпа Ð¿Ð¾Ð½Ð¾Ñ Ð¿Ð¾Ð½Ñ‡Ð¾ попка порез порей порка порог порок порох порты порча поÑев поÑол поÑох поток потоп поход почва почет почин почка почта пошив поÑма право праща преÑÑ Ð¿Ñ€Ð¸ÐµÐ¼ прима принц приют проба проем проза проÑо прыть прÑдь прÑжа прÑха пÑарь пÑина птаха птица пудра Ð¿ÑƒÐ»ÑŒÑ Ð¿ÑƒÐ»ÑŒÑ‚ пункт пупок пурга пуфик пучок пушка пушок пчела пшено пыжик пырей пырни пытка пышка пьеÑа пÑтак пÑтка пÑтно радар раджа радий радио радон разок разор разум район ралли рамка рампа ранец ранка ранчо раунд Ñ€Ð°Ñ„Ð¸Ñ Ñ€Ð°Ñ…Ð¸Ñ‚ Ñ€Ð°Ñ†Ð¸Ñ Ñ€Ð°Ñ‡Ð¾Ðº рвань рвота ребро Ñ€ÐµÐ±ÑƒÑ Ñ€ÐµÐ²ÑƒÐ½ регби Ñ€ÐµÐ´Ð¸Ñ Ñ€ÐµÐ´ÑƒÑ‚ резак резец резка Ñ€ÐµÐ·Ð½Ñ Ñ€ÐµÐ·ÑƒÑ Ñ€ÐµÐ¹ÐºÐ° Ñ€ÐµÐ»ÑŒÑ Ñ€ÐµÐ½Ð¸Ð¹ рента репка речка решка риÑка рифма робот Ñ€Ð¾Ð²Ð½Ñ Ñ€Ð¾Ð´ÐµÐ¾ родий Ñ€Ð¾Ð´Ð½Ñ Ñ€Ð¾Ð¶Ð¾Ðº рожон розга рознь рокер рокот ролик роман рондо ропот ротик ротор Ñ€Ð¾Ñ…Ð»Ñ Ñ€Ð¾Ñль ртуть рубеж рубец рубин рубка рубль ружье рукав рулет рулон румба румын Ñ€ÑƒÐ¿Ð¸Ñ Ñ€ÑƒÐ¿Ð¾Ñ€ руÑак руÑло ручей ручка рыбак рыбка рывок рынок рыÑак рычаг Ñ€Ñкет рюмка Ñ€Ñдок Ñ€ÑÑка ÑÐ°Ð±Ð»Ñ Ñаван Ñадик Ñадок Ñайга Ñайда Ñайра ÑÐ°ÐºÐ»Ñ Ñалат Ñалон Ñалоп Ñалют Ñамбо Ñамец Ñамка Ñанки Ñапер Ñапог Ñарай Ñаржа Ñатин Ñатир Ñауна Ñахар Ñачок Ñброд ÑÐ±Ñ€ÑƒÑ Ñвара Ñваха Ñвеча ÑвиÑÑ‚ Ñвита Ñвора ÑвоÑк ÑвÑзь Ñглаз Ñдача Ñдвиг Ñдоба ÑÐµÐ°Ð½Ñ Ñевер Ñедло Ñедок Ñезам Ñезон Ñекта Ñелен Ñемга Ñемит ÑÐµÐ¼ÑŒÑ Ñенат ÑÐµÑ€Ð¸Ñ Ñерна Ñетка Ñигма Ñилач Ñилок Ñинод ÑинÑк Ñироп Ñитец Ñифон Ñкала Ñкарб Ñквер Ñкетч Ñклад Ñклеп Ñклон Ñкоба Ñкрип Ñкука Ñкула ÑÐºÑƒÐ½Ñ Ñлава Ñлайд Ñлеза Ñлива Ñлизь Ñлово Ñлуга Ñлюда Ñлюна Ñмена Ñмерч ÑмеÑÑŒ Ñмета Ñмола Ñмоль Ñмотр Ñмрад Ñмута ÑмыÑл Ñнедь Ñноха Ñобор Ñовет Ñовка Ñовок Ñодом Ñозыв Ñойка Ñокол Ñонет Ñопка Ñопло ÑÐ¾Ð¿Ð»Ñ Ñорго ÑоÑед ÑоÑец ÑоÑка ÑоÑна ÑоÑок ÑоÑуд ÑÐ¾Ñ‚Ð½Ñ Ñофит Ñошка Ñпазм ÑпеÑÑŒ Ñпирт Ñплав Ñплин Ñпорт ÑÐ¿Ñ€Ð¾Ñ Ñпрут ÑпуÑк Ñреда ÑÑора ÑÑуда Ñтадо Ñталь Ñтарт Ñтать Ñтвол ÑÑ‚ÐµÐ·Ñ Ñтена Ñтенд Ñтепь Ñтило Ñтиль Ñтолб Ñтраж Ñтраз Ñтрах Ñтрой ÑÑ‚Ñ€ÑƒÑ Ñтужа Ñтупа Ñудно ÑÑƒÐ´ÑŒÑ Ñукно Ñумка Ñумма Ñурик Ñурок Ñутки Ñуфле Ñучок Ñушка Ñфера Ñхема Ñхима Ñцена Ñъезд Ñынок Ñырец Ñырок Ñырье Ñыщик Ñюжет табак табло табор табун тазик тайга тайна такÑа такÑи талер Ñ‚Ð°Ð»Ð¸Ñ Ñ‚Ð°Ð»Ð¾Ð½ тальк танго танец тапер тапир тапок таран тариф тахта тачка тварь театр Ñ‚ÐµÐ·Ð¸Ñ Ñ‚ÐµÐ·ÐºÐ° текÑÑ‚ телец телка тембр тенор тепло терем терка теÑак теÑто теÑть тетка типаж типун тираж тиран тиÑки титан титул ткань товар толпа томат томик тоник тонна Ñ‚Ð¾Ð½ÑƒÑ Ñ‚Ð¾Ð¿Ð°Ð· топка топор топот торба торец торий Ñ‚Ð¾Ñ€Ð¾Ñ Ñ‚Ð¾Ñка точка трава тракт Ñ‚Ñ€Ð°Ð½Ñ Ñ‚Ñ€Ð°Ñ‚Ð° траур трель треÑк треÑÑ‚ треть треух трефа триба трико тропа троÑк труба труÑÑ‹ трюмо Ñ‚ÑƒÐ±ÑƒÑ Ñ‚ÑƒÐ·Ð¸Ðº тулуп Ñ‚ÑƒÐ»ÑŒÑ Ñ‚ÑƒÐ¼Ð°Ðº туман тумба тунец тупик турка турне турок Ñ‚ÑƒÑ„Ð»Ñ Ñ‚ÑƒÑ‡ÐºÐ° тушка тщета тыква тюбик тюфÑк тючок Ñ‚Ñгач Ñ‚Ñжба уголь угорь удаль удача узбек уздцы узник уклад уклон укроп укÑÑƒÑ ÑƒÐ»Ð¸ÐºÐ° улица умора унтер ÑƒÐ½Ñ†Ð¸Ñ ÑƒÐ¿Ñ€ÐµÐº упырь уÑпех уÑтав уÑтой уÑтуп уÑтье утеха учеба ущерб фавор фагот фазан факел факир фалда фаÑад фаÑон фатум фауна фаÑÐ½Ñ Ñ„ÐµÑ€Ð·ÑŒ ферма феÑка фетиш фидер физик фикÑа Ñ„Ð¸ÐºÑƒÑ Ñ„Ð¸Ð»ÐµÑ€ филин фильм финал финик финиш финка фиорд фирма фишка фланг флирт флора флюид флÑга Ñ„Ð¾Ð±Ð¸Ñ Ñ„Ð¾ÐºÑƒÑ Ñ„Ð¾Ð¼ÐºÐ° форма форум фотон фраза франк франт фрахт фреза френч фронт фрукт Ñ„ÑƒÐ³Ð°Ñ Ñ„ÑƒÐ¶ÐµÑ€ фулÑÑ€ фураж Ñ„ÑƒÑ€Ð¸Ñ Ñ„ÑƒÑ€Ð¾Ñ€ фьорд фюрер Ñ…Ð°ÐºÐ°Ñ Ñ…Ð°Ð»Ð°Ñ‚ халва халиф хамка хамье ханжа харчо хвала хворь хвоÑÑ‚ Ñ…ÐµÑ€ÐµÑ Ñ…Ð¸Ð¼Ð¸Ðº Ñ…Ð¸Ð¼Ð¸Ñ Ñ…Ð¸Ð½Ð´Ð¸ хинин хиппи хитин хитон хлыÑÑ‚ хлюÑÑ‚ хлÑбь хмель хмырь хобби хобот ходок холка холод холоп холÑÑ‚ холуй хомут хомÑк хорал хорда хорек хохма хохол хохот хруÑÑ‚ хунта хурма хутор Ñ†Ð°Ð¿Ð»Ñ Ñ†Ð°Ð¿Ñ„Ð° цацка цедра центр церий цинга циник циÑта цифра цокот цукат цуцик цыган цыпка чагой чайка чалма чарка чаÑик чаÑок чаÑть чашка чекан челка чепец червь череп черта чеÑть четки чехол чешка Ñ‡ÐµÑˆÑƒÑ Ñ‡Ð¸Ð¶Ð¸Ðº чирей чиÑло чрево чтиво чтица чубук чуваш чугун чудак чужак чукча чулан чулок чурка чушка шабаш шавка шажок шайба шайка шакал шалаш шалун шаман шапка шарик шаÑÑи шатен шатер шатун шафер шахта шашка шашни шваль шейка шельф шепот шериф ширма шитье шифер шифон шишка шкала шквал школа шкура шланг шлейф шлюха шлÑпа шмель ÑˆÐ½Ð°Ð¿Ñ ÑˆÐ¾Ñ€Ð¾Ñ… шорты шоÑÑе шофер шпага шпала шпана шпиль шпион шпора шприц шпрот шрифт штамм штамп штаны штиль штора шторм штраф штрек штрих штука штурм штырь шубка шулер шурин шуруп шутка шхуна щебет щегол щелка щенок щепка щетка щечка щипок щипцы щиток Ñклер Ñкран Ñлита Ñмаль Ñпоха Ñрбий Ñрзац ÑÑкиз ÑÑтет Ñтика Ñфиоп юдоль юниор юнкер юннат юноша юриÑÑ‚ Ñбеда Ñгода Ñгуар Ñичко Ñкорь Ñмщик Ñрлык ÑÑень ÑÑтво Ñхонт tkabber-plugins/browser000075500000000000000000000000001500237002100151155ustar00nobodynobodytkabber-plugins/browser/browser.tcl000064400000000000000000000610341500237002100173670ustar00nobodynobody# browser.tcl -- # # Jabber Browser (XEP-0011) implementation for Tkabber XMPP client. # This XEP is deprecated, so its code has been moved to a plugin. package require msgcat namespace eval browser { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered browser]} { ::plugins::register browser \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Jabber\ Browser plugin is\ loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable brwid 0 custom::defvar browse_list {} [::msgcat::mc "List of browsed JIDs."] \ -group Hidden image create photo "" } proc browser::load {} { if {[winfo exists [set m .b2popmenu]]} { destroy $m } menu $m -tearoff 0 $m add command -label [::msgcat::mc "Join group..."] -command { join_group_dialog \ $::plugins::browser::browser(xlib,$::plugins::browser::headwindow) \ -server [::xmpp::jid::server $::plugins::browser::headjid] \ -group [::xmpp::jid::node $::plugins::browser::headjid] } $m add command -label [::msgcat::mc "Add conference..."] -command { plugins::conferences::add_conference_dialog \ $::plugins::browser::browser(xlib,$::plugins::browser::headwindow) \ -group [::xmpp::jid::node $::plugins::browser::headjid] \ -server [::xmpp::jid::server $::plugins::browser::headjid] } $m add separator $m add command -label [::msgcat::mc "Browse"] \ -command {::plugins::browser::browser_action browse \ $::plugins::browser::headwindow \ $::plugins::browser::headnode} $m add command -label [::msgcat::mc "Sort items by name"] \ -command {::plugins::browser::browser_action sort \ $::plugins::browser::headwindow \ $::browser::headnode} $m add command -label [::msgcat::mc "Sort items by JID"] \ -command {::plugins::browser::browser_action sortjid \ $::plugins::browser::headwindow \ $::plugins::browser::headnode} if {[winfo exists [set m .b3popmenu]]} { destroy $m } menu $m -tearoff 0 $m add command -label [::msgcat::mc "Browse"] \ -command {::plugins::browser::browser_action browse \ $::plugins::browser::headwindow \ $::plugins::browser::headnode} $m add command -label [::msgcat::mc "Sort items by name"] \ -command {::plugins::browser::browser_action sort \ $::plugins::browser::headwindow \ $::plugins::browser::headnode} $m add command -label [::msgcat::mc "Sort items by JID"] \ -command {::plugins::browser::browser_action sortjid \ $::plugins::browser::headwindow \ $::plugins::browser::headnode} if {[winfo exists [set m .b4popmenu]]} { destroy $m } menu $m -tearoff 0 $m add command -label [::msgcat::mc "Browse"] \ -command {::plugins::browser::browser_action browse \ $::plugins::browser::headwindow \ $::plugins::browser::headnode} hook::add finload_hook [namespace current]::setup_menu # Register disco#info and disco#items in browser only. register_ns_handler http://jabber.org/protocol/disco#info \ disco::browser::open_win \ -desc [list * [::msgcat::mc "Discover service"]] register_ns_handler http://jabber.org/protocol/disco#items \ disco::browser::open_win \ -desc [list * [::msgcat::mc "Discover service"]] if {![catch {set m [.mainframe getmenu services]}] && $m != "" && \ ![catch {set idx [$m index [::msgcat::mc "Service\ Discovery"]]}] && \ $idx != "none"} { $m insert $idx command -label [::msgcat::mc "Jabber Browser"] \ -command [list [namespace current]::open] } } proc browser::unload {} { variable brwid variable browser variable headwindow variable headnode variable headjid if {![catch {set m [.mainframe getmenu services]}] && $m != "" && \ ![catch {set idx [$m index [::msgcat::mc "Jabber Browser"]]}] && \ $idx != "none"} { $m delete $idx } foreach bw [winfo children .] { if {[info exists browser(xlib,$bw)]} { destroy_win $bw } } if {[winfo exists [set m .b2popmenu]]} { destroy $m } if {[winfo exists [set m .b3popmenu]]} { destroy $m } if {[winfo exists [set m .b4popmenu]]} { destroy $m } hook::remove finload_hook [namespace current]::setup_menu catch {unset brwid} catch {unset browser} catch {unset headwindow} catch {unset headnode} catch {unset headjid} } proc browser::open {{xlib ""}} { variable brwid variable browser variable browse_list variable brwserver$brwid if {[llength [connections]] == 0} return if {$xlib == ""} { set xlib [lindex [connections] 0] } set brwserver$brwid [connection_server $xlib] set bw .brw$brwid set browser(xlib,$bw) $xlib add_win $bw -title [::msgcat::mc "Jabber Browser"] \ -tabtitle [::msgcat::mc "Browser"] \ -raisecmd [list focus $bw.tree] \ -class JDisco \ -raise 1 set config(nscolor) [option get $bw featurecolor JDisco] bind $bw [list [namespace current]::destroy_state $bw $brwid] Frame $bw.navigate Button $bw.navigate.back -text <- -width 3 \ -command [list [namespace current]::history_move $bw 1] Button $bw.navigate.forward -text -> -width 3 \ -command [list [namespace current]::history_move $bw -1] Label $bw.navigate.lab -text [::msgcat::mc "JID:"] set c [Combobox $bw.navigate.entry \ -textvariable [namespace current]::brwserver$brwid \ -command [list [namespace current]::go $bw] \ -values $browse_list] if {[winfo exists $c.e]} { #HACK: For BWidget combobox set c $c.e } DropSite::register $c -droptypes {JID {}} \ -dropcmd [list [namespace current]::entrydropcmd $bw] Button $bw.navigate.browse -text [::msgcat::mc "Browse"] \ -command [list [namespace current]::go $bw] #bind $bw.navigate.entry [list [namespace current]::go $bw] pack $bw.navigate.back $bw.navigate.forward $bw.navigate.lab -side left pack $bw.navigate.browse -side right pack $bw.navigate.entry -side left -expand yes -fill x pack $bw.navigate -fill x set sw [ScrolledWindow $bw.sw] set tw [MyTree $bw.tree] $sw setwidget $tw if {[winfo exists $tw.c]} { DragSite::register $tw.c \ -draginitcmd [list [namespace current]::draginitcmd $bw] } else { DragSite::register $tw \ -draginitcmd [list [namespace current]::draginitcmd $bw] } $tw tag configure ns -foreground $config(nscolor) pack $sw -side top -expand yes -fill both set browser(tree,$bw) $tw $tw tag bind Text \ [list [namespace current]::activate_node [double% $bw] \ [double% $tw]] # Override the default action which toggles the non-leaf nodes bind $tw break $tw tag bind Text <> \ [list [namespace current]::textpopup [double% $bw] %x %y] balloon::setup $tw -command [list [namespace current]::textballoon $bw] if {[winfo exists $tw.c]} { # HACK bind $tw.c \ [list [namespace current]::activate_node [double% $bw] \ [double% $tw]] } else { $tw tag bind Text \ [list [namespace current]::activate_node [double% $bw] \ [double% $tw]] # Override the default action which toggles the non-leaf nodes bind $tw break } set browser(ypos,$bw) 1 set browser(width,$bw) 0 set browser(hist,$bw) {} set browser(histpos,$bw) 0 hook::run open_browser_post_hook $bw $sw $tw incr brwid go $bw } proc browser::enter {bw} { variable browser set jid [$bw.navigate.entry get] ::xmpp::sendIQ $browser(xlib,$bw) get \ -query [::xmpp::xml::create query \ -xmlns jabber:iq:browse] \ -to $jid -command [list [namespace current]::recv $bw $jid] } proc browser::go {bw} { variable browser variable browse_list if {[winfo exists $bw]} { set jid [$bw.navigate.entry get] history_add $bw $jid set browse_list [update_combo_list $browse_list $jid 20] $bw.navigate.entry configure -values $browse_list ::xmpp::sendIQ $browser(xlib,$bw) get \ -query [::xmpp::xml::create query \ -xmlns jabber:iq:browse] \ -to $jid -command [list [namespace current]::recv $bw $jid] } } proc browser::recv {bw jid status xml} { variable browser debugmsg browser "$status $xml" if {[winfo exists $bw]} { if {![string equal $status ok]} { add_item_line $bw 0 $jid {} {} {} {} $jid set tw $browser(tree,$bw) $tw delete [$tw children [jid_to_tag $jid]] set tnode [jid_to_tag "error $jid"] set data [list error $jid] set parent_tag [jid_to_tag $jid] set desc [::msgcat::mc "Browse error: %s" [error_to_string $xml]] set icon "" add_line $tw $parent_tag $tnode $icon $desc $data -tags {Text} set browser(nchildren,$bw,$jid) 1 } else { process $bw $jid $xml 0 } } } proc browser::process {bw from item level} { variable browser ::xmpp::xml::split $item tag xmlns attrs cdata subels switch -- $tag { ns { debugmsg browser "$level; ns $cdata" if {![string equal $cdata ""]} { return [add_ns_line $bw $from $level $cdata] } return "" } query - item { set category [::xmpp::xml::getAttr $attrs category] } default { set category $tag } } set jid [::xmpp::xml::getAttr $attrs jid] if {$jid eq ""} { set jid $from } set type [::xmpp::xml::getAttr $attrs type] set name [::xmpp::xml::getAttr $attrs name] set version [::xmpp::xml::getAttr $attrs version] debugmsg browser "$level; $jid; $category; $type; $name; $version" add_item_line $bw $level $jid $category $type $name $version $from set tw $browser(tree,$bw) set children {} set nchildren 0 foreach subel $subels { lappend children [process $bw $jid $subel [expr {$level+1}]] incr nchildren } set browser(nchildren,$bw,$jid) $nchildren set node [jid_to_tag $jid] if {![info exists browser(sort,$bw,$node)]} { set browser(sort,$bw,$node) sort } set curchildren [$tw children $node] if {$level == 0} { foreach c $curchildren { if {[lsearch -exact $children $c] < 0} { $tw delete [list $c] } } browser_action $browser(sort,$bw,$node) $bw $node update idletasks } debugmsg browser [list $children $curchildren] return $node } proc browser::item_icon {category type} { switch -- $category { service - gateway - application { if {[lsearch -exact [image names] browser/$type] >= 0} { return browser/$type } else { return "" } } default { if {[lsearch -exact [image names] browser/$category] >= 0} { return browser/$category } else { return "" } } } } proc browser::add_line {tw parent node icon desc data args} { if {[$tw exists $node]} { if {[$tw parent $node] != $parent && [$tw exists $parent] && \ $parent != $node} { if {[catch {$tw move $node $parent end}]} { debugmsg browser "MOVE FAILED: $parent $node" } else { debugmsg browser "MOVE: $parent $node" } } if {[$tw item $node -values] != $data} { debugmsg browser RECONF $tw item $node -text $desc -image $icon -values $data } } elseif {[$tw exists $parent]} { $tw insert $parent end -id $node -text $desc -open 1 -image $icon \ -values $data {*}$args } else { $tw insert {} end -id $node -text $desc -open 1 -image $icon \ -values $data {*}$args } } proc browser::add_item_line {bw level jid category type name version parent} { variable browser set icon [item_icon $category $type] set tw $browser(tree,$bw) set desc [item_desc $jid $name] set data [list jid $jid $category $type $name $version] set parent_tag [jid_to_tag $parent] set node [jid_to_tag $jid] add_line $tw $parent_tag $node $icon $desc $data -tags {Text} } proc browser::item_text {jid name} { if {$name ne ""} { return $name } else { return $jid } } proc browser::item_desc {jid name} { if {$name ne ""} { return "$name ($jid)" } else { return $jid } } proc browser::item_balloon_text {bw jid category type name version} { variable browser set text "$jid: " set delim "" if {$category ne "" || $type ne ""} { append text "$delim$category/$type" set delim ", " } if {$name ne ""} { append text "$delim[::msgcat::mc Description:] $name" set delim ", " } if {$version ne ""} { append text "$delim[::msgcat::mc Version:] $version" } append text "\n[::msgcat::mc {Number of children:}]\ $browser(nchildren,$bw,$jid)" return $text } proc browser::add_ns_line {bw jid level ns} { variable browser set tw $browser(tree,$bw) set node ${ns}\#[jid_to_tag $jid] set parent_tag [jid_to_tag $jid] lassign [$tw item $parent_tag -values] ignore1 ignore2 category type set data [list ns $jid $ns $category $type] set desc $ns if {[info exists browser(ns_handler_desc,$ns)]} { array set tmp $browser(ns_handler_desc,$ns) if {[info exists tmp($category)]} { set desc "$tmp($category) ($ns)" } elseif {[info exists tmp(*)]} { set desc "$tmp(*) ($ns)" } } elseif {[info exists \ ::disco::browser::browser(feature_handler_desc,$ns)]} { array set tmp $::disco::browser::browser(feature_handler_desc,$ns) if {[info exists tmp($category)]} { set desc "$tmp($category) ($ns)" } elseif {[info exists tmp(*)]} { set desc "$tmp(*) ($ns)" } } set icon "" add_line $tw $parent_tag $node $icon $desc $data -tags {Text ns} return $node } proc browser::history_move {bw shift} { variable browser set newpos [expr {$browser(histpos,$bw) + $shift}] if {$newpos < 0} { return } if {$newpos >= [llength $browser(hist,$bw)]} { return } set newjid [lindex $browser(hist,$bw) $newpos] set browser(histpos,$bw) $newpos $bw.navigate.entry set $newjid enter $bw } proc browser::history_add {bw jid} { variable browser set browser(hist,$bw) [lreplace $browser(hist,$bw) 0 \ [expr {$browser(histpos,$bw) - 1}]] set browser(hist,$bw) [linsert $browser(hist,$bw) 0 $jid] set browser(histpos,$bw) 0 debugmsg browser $browser(hist,$bw) } proc browser::parse_items {from item} { variable browser debugmsg browser "BR: $item" ::xmpp::xml::split $item tag xmlns attrs cdata subels switch -- $tag { ns { return } item { set category [::xmpp::xml::getAttr $attrs service] } default { set category $tag } } set jid [::xmpp::xml::getAttr $attrs jid] if {[string equal $jid ""]} { set jid $from } set type [::xmpp::xml::getAttr $attrs type] set name [::xmpp::xml::getAttr $attrs name] set version [::xmpp::xml::getAttr $attrs version] debugmsg browser "$jid; $category; $type; $name; $version" set browser(name,$jid) $name set browser(category,$jid) $category set browser(type,$jid) $type foreach subel $subels { parse_items $jid $subel } } proc browser::goto {bw jid} { $bw.navigate.entry set $jid go $bw } proc browser::activate_node {bw tw} { set node [lindex [$tw selection] 0] if {$node != ""} { textaction $bw $node } } proc browser::textaction {bw node} { variable browser set tw $browser(tree,$bw) set data [$tw item $node -values] set data2 [lassign $data type] switch -- $type { jid { lassign $data2 jid goto $bw $jid } ns { lassign $data2 jid ns category subtype debugmsg browser "$jid $ns" if {[info exists browser(ns_handler,$ns)]} { if {$browser(ns_handler_node,$ns)} { {*}$browser(ns_handler,$ns) $browser(xlib,$bw) $jid "" \ -category $category -type $subtype } else { {*}$browser(ns_handler,$ns) $browser(xlib,$bw) $jid \ -category $category -type $subtype } } elseif {[info exists \ ::disco::browser::browser(feature_handler,$ns)]} { if {$::disco::browser::browser(feature_handler_node,$ns)} { {*}$::disco::browser::browser(feature_handler,$ns) \ $browser(xlib,$bw) $jid "" \ -category $category -type $subtype } else { {*}$::disco::browser::browser(feature_handler,$ns) \ $browser(xlib,$bw) $jid \ -category $category -type $subtype } } } } } proc browser::textpopup {bw x y} { variable browser variable headwindow $bw variable headjid set tw $browser(tree,$bw) $tw selection set [list [$tw identify item $x $y]] set node [lindex [$tw selection] 0] variable headnode $node if {[catch {$tw item $node -values} data]} { return } set type [lindex $data 0] switch -- $type { jid { switch -- [lindex $data 2] { user { message::subject_menu [set bm .b1popmenu] \ $browser(xlib,$bw) [lindex $data 1] message } conference { if {[string first @ [set headjid [lindex $data 1]]] > 0} { set bm .b2popmenu } else { set bm .b3popmenu } } service - default { set bm .b3popmenu } } } ns { set bm .b4popmenu } } tk_popup $bm [winfo pointerx .] [winfo pointery .] } proc browser::browser_action {action bw node} { variable browser if {[catch {[set tw $browser(tree,$bw)] item $node -values} data]} { return } set type [lindex $data 0] switch -glob -- $type/$action { jid/browse - ns/browse { textaction $bw $node } jid/sort { set browser(sort,$bw,$node) sort set namespaces {} set children {} foreach child [$tw children $node] { set data [$tw item $child -values] switch -- [lindex $data 0] { ns { lappend namespaces [list $child [lindex $data 4]] } default { lappend children [list $child [lindex $data 4]] } } } set neworder {} foreach child [concat $namespaces \ [lsort -dictionary -index 1 $children]] { lappend neworder [lindex $child 0] } $tw children $node $neworder foreach child [$tw children $node] { browser_action $action $bw $child } } jid/sortjid { set browser(sort,$bw,$node) sortjid set namespaces {} set children {} foreach child [$tw children $node] { set data [$tw item $child -values] switch -- [lindex $data 0] { ns { lappend namespaces [list $child [lindex $data 1]] } default { lappend children [list $child [lindex $data 1]] } } } set neworder {} foreach child [concat $namespaces \ [lsort -dictionary -index 1 $children]] { lappend neworder [lindex $child 0] } $tw children $node $neworder foreach child [$tw children $node] { browser_action $action $bw $child } } default { } } } proc browser::textballoon {bw args} { variable browser set tw $browser(tree,$bw) if {[llength $args] == 1} { set node [lindex $args 0] } else { set bd [ttk::style lookup Treeview -borderwidth {} 1] set x [expr {[winfo pointerx $tw] - [winfo rootx $tw] - $bd}] set y [expr {[winfo pointery $tw] - [winfo rooty $tw] - $bd}] set node [$tw identify item $x $y] if {$node eq ""} { return [list $bw:$node ""] } } set data [lassign [$tw item $node -values] \ type jid category subtype name version] if {$type == "jid"} { return [list $bw:$node \ [item_balloon_text \ $bw $jid $category $subtype $name $version]] } else { return [list $bw:$node ""] } } proc browser::draginitcmd {bw t x y top} { if {[winfo exists [winfo parent $tw].c]} { # HACK for BWidget Tree set tw [winfo parent $tw] } set node [lindex [$tw identify item [expr {$x-[winfo rootx $tw]}] \ [expr {$y-[winfo rooty $tw]}]] 0] set xlib browser(xlib,$bw) set data [$t item $node -values] set data2 [linsert [lassign $data type] 0 $xlib] if {$type == "jid"} { if {[set img [$t item $node -image]] != ""} { pack [Label $top.l -image $img -padx 0 -pady 0] } return [list JID {copy} $data2] } else { return {} } } proc browser::entrydropcmd {bw target source x y op type data} { set jid [lindex $data 1] after idle [list [namespace current]::goto $bw $jid] } proc browser::register_ns_handler {ns handler args} { variable browser set node 0 set desc "" foreach {attr val} $args { switch -- $attr { -node {set node $val} -desc {set desc $val} } } set browser(ns_handler,$ns) $handler set browser(ns_handler_node,$ns) $node if {$desc != ""} { set browser(ns_handler_desc,$ns) $desc } } # Destroy all (global) state assotiated with the given browser window. # Intended to be bound to a event handler for browser windows. proc browser::destroy_state {bw brwid} { variable browser variable brwserver$brwid array unset browser *,$bw array unset browser *,$bw,* unset brwserver$brwid } # Menu setup proc browser::setup_menu {} { catch { set m [.mainframe getmenu services] set idx [$m index [::msgcat::mc "Service Discovery"]] $m insert $idx command -label [::msgcat::mc "Jabber Browser"] \ -command [list [namespace current]::open] } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/browser/msgs000075500000000000000000000000001500237002100160665ustar00nobodynobodytkabber-plugins/browser/msgs/de.msg000064400000000000000000000023021500237002100172420ustar00nobodynobody# de.msg -- # # German messages for the Browser Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 23.02.2009 ::msgcat::mcset de "Add conference..." "Konferenz hinzufügen..." ::msgcat::mcset de "Browse error: %s" "Durchsuchen-Fehler: %s" ::msgcat::mcset de "Browse" "Durchsuchen" ::msgcat::mcset de "Browser" "Jabber-Browser" ::msgcat::mcset de "Description:" "Beschreibung:" ::msgcat::mcset de "Discover service" "Service-Discovery" ::msgcat::mcset de "JID:" "JID:" ::msgcat::mcset de "Jabber Browser" "Jabber-Browser" ::msgcat::mcset de "Join group..." "Konferenz beitreten..." ::msgcat::mcset de "List of browsed JIDs." "Liste durchsuchter JIDs." ::msgcat::mcset de "Number of children:" "Anzahl Einträge:" ::msgcat::mcset de "Service Discovery" "Service-Discovery" ::msgcat::mcset de "Sort items by JID" "Nach JID sortieren" ::msgcat::mcset de "Sort items by name" "Nach Namen sortieren" ::msgcat::mcset de "Version:" "Version:" ::msgcat::mcset de "Whether the Jabber Browser plugin is loaded." \ "Jabber-Browser-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/browser/msgs/es.msg000064400000000000000000000020451500237002100172650ustar00nobodynobody# es.msg -- # # Spanish messages for the Browser Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "Add conference..." "Añadir sala..." ::msgcat::mcset es "Browse error: %s" "Error navegando: %s" ::msgcat::mcset es "Browse" "Navegar" ::msgcat::mcset es "Browser" "Navegador" ::msgcat::mcset es "Description:" "Descripción:" ::msgcat::mcset es "Discover service" "Descubrir servicio" ::msgcat::mcset es "JID:" "JID:" ::msgcat::mcset es "Jabber Browser" "Navegador Jabber" ::msgcat::mcset es "Join group..." "Entrar en grupo..." ::msgcat::mcset es "List of browsed JIDs." "Lista de JIDs navegados." ::msgcat::mcset es "Number of children:" "Número de hijos:" ::msgcat::mcset es "Service Discovery" "Descubridor de servicios" ::msgcat::mcset es "Sort items by JID" "Ordenar elementos por JID" ::msgcat::mcset es "Sort items by name" "Ordenar elementos por nombre" ::msgcat::mcset es "Version:" "Versión:" ::msgcat::mcset es "Whether the Jabber Browser plugin is loaded." \ "Cargar el plugin Jabber Browser." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/browser/msgs/pl.msg000064400000000000000000000020101500237002100172610ustar00nobodynobody# pl.msg -- # # Polish messages for the Browser Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Add conference..." "Dodaj konferencjÄ™..." ::msgcat::mcset pl "Browse" "PrzeglÄ…daj" ::msgcat::mcset pl "Browse error: %s" "Błąd przeglÄ…dania: %s" ::msgcat::mcset pl "Browser" "PrzeglÄ…darka usÅ‚ug" ::msgcat::mcset pl "Description:" "Opis:" ::msgcat::mcset pl "Discover service" "PrzeglÄ…daj usÅ‚ugÄ™" ::msgcat::mcset pl "JID:" "JID:" ::msgcat::mcset pl "Jabber Browser" "PrzeglÄ…darka usÅ‚ug" ::msgcat::mcset pl "Join group..." "Dołącz do konferencji..." ::msgcat::mcset pl "List of browsed JIDs." "Lista przeglÄ…danych JabberID" ::msgcat::mcset pl "Number of children:" "Ilość elementów:" ::msgcat::mcset pl "Service Discovery" "PrzeglÄ…darka usÅ‚ug (protokół‚\ Discovery)" ::msgcat::mcset pl "Sort items by JID" "Sortuj wedÅ‚ug JID" ::msgcat::mcset pl "Sort items by name" "Sortuj wedÅ‚ug nazwy" ::msgcat::mcset pl "Version:" "Wersja:" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/browser/msgs/ru.msg000064400000000000000000000024611500237002100173060ustar00nobodynobody# ru.msg -- # # Russian messages for the Browser Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Add conference..." "Добавить конференцию..." ::msgcat::mcset ru "Browse" "ПроÑмотреть" ::msgcat::mcset ru "Browse error: %s" "Ошибка проÑмотра: %s" ::msgcat::mcset ru "Browser" "ПроÑмотр" ::msgcat::mcset ru "Description:" "ОпиÑание:" ::msgcat::mcset ru "Discover service" "ПроÑмотреть возможноÑти" ::msgcat::mcset ru "Jabber Browser" "ПроÑмотр Ñлужб" ::msgcat::mcset ru "JID:" ::msgcat::mcset ru "Join group..." "ПриÑоединитьÑÑ Ðº группе..." ::msgcat::mcset ru "List of browsed JIDs." "СпиÑок проÑмотренных JID." ::msgcat::mcset ru "Number of children:" "ЧиÑло ветвей:" # Using translation from Tkabber itself #::msgcat::mcset ru "Service Discovery" "Обзор Ñлужб" ::msgcat::mcset ru "Sort items by JID" "Сортировать по JID" ::msgcat::mcset ru "Sort items by name" "Сортировать по имени" ::msgcat::mcset ru "Version:" "ВерÑиÑ:" ::msgcat::mcset ru "Whether the Jabber Browser plugin is loaded." \ "Загружено ли раÑширение Jabber Browser." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/browser/msgs/uk.msg000064400000000000000000000024241500237002100172760ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Browser Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Add conference..." "Додати конференцію..." ::msgcat::mcset uk "Browse" "ПереглÑнути" ::msgcat::mcset uk "Browse error: %s" "Помилка переглÑду: %s" ::msgcat::mcset uk "Browser" "ПереглÑд" ::msgcat::mcset uk "Description:" "ОпиÑ:" ::msgcat::mcset uk "Discover service" "ОглÑнути можливоÑті" ::msgcat::mcset uk "Jabber Browser" "ПереглÑд Ñлужб" ::msgcat::mcset uk "JID:" ::msgcat::mcset uk "Join group..." "ПриєднатиÑÑ Ð´Ð¾ групи..." ::msgcat::mcset uk "List of browsed JIDs." "СпиÑок переглÑнутих JID." ::msgcat::mcset uk "Number of children:" "ЧиÑло гілок:" # Using translation from Tkabber itself #::msgcat::mcset uk "Service Discovery" "ОглÑд Ñлужб" ::msgcat::mcset uk "Sort items by JID" "Сортувати за JID" ::msgcat::mcset uk "Sort items by name" "Сортувати за им’Ñм" ::msgcat::mcset uk "Version:" "ВерÑÑ–Ñ:" ::msgcat::mcset uk "Whether the Jabber Browser plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Jabber Browser." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/checkers000075500000000000000000000000001500237002100152215ustar00nobodynobodytkabber-plugins/checkers/README000064400000000000000000000007171500237002100161650ustar00nobodynobodyCheckers Plugin for Tkabber Installation: Just put all checkers directory to $HOME/.tkabber/plugins (on UNIX), to %APPDATA%\Tkabber\plugins (on Windows), or to $HOME/Library/Application Support/Tkabber (on MacOS X) directory. Then after Tkabber restart new submenu "Games" with "Checkers" option will appear in roster user context menu. Checkers rules included in distribution are taken from http://ourworld.compuserve.com/homepages/Arthur_H_Olsen/checkers.htm tkabber-plugins/checkers/checkers.tcl000064400000000000000000001742761500237002100176140ustar00nobodynobody# checkers.tcl -- # # This file implements Checkers game plugin for the Tkabber XMPP client. # Quite a few game variants are supported. package require msgcat namespace eval checkers { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered checkers]} { ::plugins::register checkers \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Checkers\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable square_size [expr {48*$::icons_scale}] variable line_width $::icons_scale variable themes variable dirs \ [glob -nocomplain -directory [file join [file dirname [info script]] \ pixmaps] *] variable dir foreach dir $dirs { pixmaps::load_theme_name [namespace current]::themes $dir } variable values {} variable theme foreach theme [lsort [array names themes]] { lappend values $theme $theme } variable game_names_list \ [list \ straight [::msgcat::mc "Straight checkers (English draughts)"] \ russian [::msgcat::mc "Russian checkers"] \ pool [::msgcat::mc "Pool checkers"] \ brazilian [::msgcat::mc "Brazilian checkers"] \ spanish [::msgcat::mc "Spanish checkers"] \ italian [::msgcat::mc "Italian checkers"] \ ] variable game_names variable short_game_names array set game_names $game_names_list array set short_game_names $game_names_list set short_game_names(straight) [::msgcat::mc "Straight checkers"] variable options custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup Checkers [::msgcat::mc "Checkers plugin options."] \ -group Plugins custom::defvar options(theme) Checkers \ [::msgcat::mc "Checkers figures theme."] -group Checkers \ -type options -values $values \ -command [namespace current]::load_stored_theme custom::defvar options(game) russian \ [::msgcat::mc "Default game variant."] -group Checkers \ -type options \ -values $game_names_list custom::defvar options(flip_black_view) 1 \ [::msgcat::mc "Flip board view when playing black (Russian, Spanish,\ Italian) or white (Straight, Pool, Brazilian) by\ default."] \ -type boolean -group Checkers custom::defvar options(show_last_move) 0 \ [::msgcat::mc "Show last move by default."] \ -type boolean -group Checkers custom::defvar options(show_tooltips) 1 \ [::msgcat::mc "Show tooltips with short instructions."] \ -type boolean -group Checkers \ -command [list [namespace current]::set_tooltips] custom::defvar options(sound) "" \ [::msgcat::mc "Sound to play after opponent's turn"] \ -type file -group Checkers custom::defvar options(allow_illegal) 0 \ [::msgcat::mc "Allow illegal moves (useful for debugging)."] \ -type boolean -group Checkers custom::defvar options(accept_illegal) 0 \ [::msgcat::mc "Accept opponent illegal moves (useful for\ debugging)."] \ -type boolean -group Checkers } proc checkers::load {} { hook::add roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.1 hook::add chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.1 hook::add roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.1 hook::add games_board_create_hook [namespace current]::iq_create hook::add games_board_turn_hook [namespace current]::iq_turn ::xmpp::iq::register set create games:board \ [namespace parent]::iq_games_board_create ::xmpp::iq::register set turn games:board \ [namespace parent]::iq_games_board_turn load_stored_theme calc_moves } proc checkers::unload {} { hook::remove roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.1 hook::remove chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.1 hook::remove roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.1 hook::remove games_board_create_hook [namespace current]::iq_create hook::remove games_board_turn_hook [namespace current]::iq_turn if {[hook::is_empty games_board_create_hook]} { ::xmpp::iq::unregister set create games:board rename [namespace parent]::iq_games_board_create "" } if {[hook::is_empty games_board_turn_hook]} { ::xmpp::iq::unregister set turn games:board rename [namespace parent]::iq_games_board_turn "" } foreach var [info vars [namespace current]::*] { upvar #0 $var flags if {[info exists flags(window)]} { destroy_win $flags(window) } } foreach var [info vars [namespace current]::*] { if {$var ne "[namespace current]::options"} { unset $var } } foreach img [image names] { if {[string first checkers/ $img] == 0} { image delete $img } } } proc checkers::load_stored_theme {args} { variable options variable themes pixmaps::load_dir $themes(Checkers) pixmaps::load_dir $themes($options(theme)) } proc checkers::get_nick {xlib jid type} { if {[catch {chat::get_nick $xlib $jid $type} nick]} { return [chat::get_nick $jid $type] } else { return $nick } } proc checkers::invite_dialog {xlib jid} { variable options set w .checkers_invite if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Checkers Invitation"] \ -modal none -anchor e -default 0 set wf [$w getframe] Message $wf.message -aspect 50000 \ -text [::msgcat::mc "Sending checkers game invitation to %s (%s)" \ [get_nick $xlib $jid chat] \ $jid] pack $wf.message -pady 2m variable game $options(game) Radiobutton $wf.straight \ -text [::msgcat::mc "Straight checkers (English draughts)"] \ -value straight -variable [namespace current]::game pack $wf.straight -padx 15m -anchor w Radiobutton $wf.russian -text [::msgcat::mc "Russian checkers"] \ -value russian -variable [namespace current]::game pack $wf.russian -padx 15m -anchor w Radiobutton $wf.pool -text [::msgcat::mc "Pool checkers"] \ -value pool -variable [namespace current]::game pack $wf.pool -padx 15m -anchor w Radiobutton $wf.brazilian -text [::msgcat::mc "Brazilian checkers"] \ -value brazilian -variable [namespace current]::game pack $wf.brazilian -padx 15m -anchor w Radiobutton $wf.spanish -text [::msgcat::mc "Spanish checkers"] \ -value spanish -variable [namespace current]::game pack $wf.spanish -padx 15m -anchor w Radiobutton $wf.italian -text [::msgcat::mc "Italian checkers"] \ -value italian -variable [namespace current]::game pack $wf.italian -padx 15m -anchor w $w add -text [::msgcat::mc "I want play white"] \ -command [list [namespace current]::invite $xlib $jid white] $w add -text [::msgcat::mc "I want play black"] \ -command [list [namespace current]::invite $xlib $jid black] $w add -text [::msgcat::mc "Cancel invitation"] \ -command [list destroy $w] $w draw } proc checkers::invite {xlib jid color} { variable game destroy .checkers_invite set id checkers[rand 1000000000] # FIX #set rjid [get_jid_of_user $jid] ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create create \ -xmlns games:board \ -attrs [list type checkers:$game \ id $id \ color $color]] \ -to $jid \ -command [list [namespace current]::invite_res $game $xlib $jid \ $id $color] } proc checkers::invite_res {game xlib jid id color status xml} { if {![string equal $status ok]} { after idle \ [list NonmodalMessageDlg .checkers_invite_error \ -aspect 50000 -icon error \ -message [::msgcat::mc "%s (%s) has refused checkers\ invitation: %s" \ [get_nick $xlib $jid chat] \ $jid [error_to_string $xml]]] return "" } start_play $game $xlib $jid $id $color } proc checkers::invited_dialog {game xlib jid iqid id color} { variable game_names set w .checkers_invited if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Checkers Invitation from %s" $jid] \ -modal none -anchor e -default 0 set wf [$w getframe] bind $wf [namespace code [list invited_res $w $game $xlib $jid \ $iqid $id $color 0]] set nick [get_nick $xlib $jid chat] set message1 [::msgcat::mc "Checkers game invitation from %s (%s)\ is received." $nick $jid] set message2 [::msgcat::mc "%s wants play %s." $nick $game_names($game)] switch -- $color { white { set message3 [::msgcat::mc "%s wants play white." $nick] } black { set message3 [::msgcat::mc "%s wants play black." $nick] } default { return [list error modify bad-request] } } Message $wf.message1 -aspect 50000 -text $message1 Message $wf.message2 -aspect 50000 -text $message2 Message $wf.message3 -aspect 50000 -text $message3 pack $wf.message1 -pady 1m pack $wf.message2 -pady 1m pack $wf.message3 -pady 1m $w add -text [::msgcat::mc "Agree to play"] \ -command [namespace code [list invited_res $w $game $xlib $jid \ $iqid $id $color 1]] $w add -text [::msgcat::mc "Refuse to play"] \ -command [namespace code [list invited_res $w $game $xlib $jid \ $iqid $id $color 0]] $w draw return } proc checkers::invited_res {w game xlib jid iqid id color res} { catch { set wf [$w getframe] bind $wf {} destroy $w } if {$res} { switch -- $color { white { start_play $game $xlib $jid $id black } black { start_play $game $xlib $jid $id white } default { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify bad-request] \ -to $jid \ -id $iqid } } ::xmpp::sendIQ $xlib result \ -query [::xmpp::xml::create create \ -xmlns games:board \ -attrs [list type checkers:$game \ id $id]] \ -to $jid \ -id $iqid } else { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify not-acceptable] \ -to $jid \ -id $iqid } } proc checkers::start_play {game xlib jid id color} { set gid [make_gid $jid $id] variable $gid variable options upvar 0 $gid flags set flags(window) [win_id checkers $gid] set flags(xlib) $xlib set flags(opponent) $jid set flags(id) $id set flags(flip) 0 set flags(game) $game set flags(our_color) $color switch -- $game { straight { set flags(board_type) 0 set flags(start) black } russian { set flags(board_type) 0 set flags(start) white } pool { set flags(board_type) 0 set flags(start) black } brazilian { set flags(board_type) 0 set flags(start) black } spanish { set flags(board_type) 1 set flags(start) white } italian { set flags(board_type) 1 set flags(start) white } } trace add variable [namespace current]::${gid}(position,turn) write \ [list [namespace current]::set_label_move $gid] make_default_position $gid open $gid } proc checkers::set_label_move {gid args} { variable $gid upvar 0 $gid flags switch -- $flags(position,turn) { white { set flags(move_label) [::msgcat::mc "White"] set move 1 } black { set flags(move_label) [::msgcat::mc "Black"] set move 1 } default { set move 0 } } if {$move && [is_my_move $gid]} { append flags(move_label) [::msgcat::mc " (You)"] } else { append flags(move_label) [::msgcat::mc " (Opponent)"] } } proc checkers::make_default_position {gid} { variable $gid upvar 0 $gid flags switch -- $flags(start) { white { set p1 wp set p2 bp } black { set p1 bp set p2 wp } } for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { set cr [list $c $r] set flags(position,$cr) "" if {($c + $r) % 2 == $flags(board_type)} { if {$r < 3} { set flags(position,$cr) $p1 } elseif {$r > 4} { set flags(position,$cr) $p2 } } } } set flags(position,turn) $flags(start) catch {unset flags(position,last_move)} set flags(position,draw) 0 set flags(position,halfmove) 0 set flags(position,history) {} } proc checkers::save_position {gid} { variable $gid upvar 0 $gid flags set flags(saved_position) [array get flags position,*] } proc checkers::restore_position {gid} { variable $gid upvar 0 $gid flags array set flags $flags(saved_position) draw_position $gid unhighlight_legal_moves $gid update_controls $gid find_legal_moves $gid $flags(position,turn) } proc checkers::make_gid {jid id} { jid_to_tag [concat $jid $id] } proc checkers::turn_recv {gid xmlList} { variable options variable $gid upvar 0 $gid flags set move {} set draw 0 foreach xml $xmlList { ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- $tag { move { set pos [::xmpp::xml::getAttr $attrs pos] set poss [split $pos ";"] if {[llength $poss] >= 2} { foreach pos1 $poss { set pos2 [split $pos1 ","] if {[llength $pos2] == 2} { lappend move $pos2 } else { return [list error modify not-acceptable] } } } else { return [list error modify not-acceptable] } if {$options(sound) != "" && ![::sound::is_mute]} { ::sound::play $options(sound) } } resign { end_game $gid 1 [::msgcat::mc "You win (Opponent resigned)"] update_controls $gid draw_position $gid highlight_last_move $gid return [list result \ [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type checkers:$flags(game) \ id $flags(id)]]] } accept { if {$flags(position,draw)} { end_game $gid 0.5 [::msgcat::mc "Draw (Opponent accepted)"] update_controls $gid draw_position $gid highlight_last_move $gid return [list result \ [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type checkers:$flags(game) \ id $flags(id)]]] } else { return [list error modify not-acceptable] } } draw { set draw 1 } } } if {[llength $move] > 0 && [do_move $gid $move $draw]} { update_controls $gid $draw draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type checkers:$flags(game) \ id $flags(id)]]] } else { return [list error modify not-acceptable] } } ############################################################################### proc checkers::calc_moves {} { variable moves variable jumps for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { set cr [list $c $r] set moves(up,$cr) {} if {$r <= 6} { if {$c <= 6} { lappend moves(up,$cr) \ [list [expr {$c + 1}] [expr {$r + 1}]] } if {$c >= 1} { lappend moves(up,$cr) \ [list [expr {$c - 1}] [expr {$r + 1}]] } } set moves(dn,$cr) {} if {$r >= 1} { if {$c <= 6} { lappend moves(dn,$cr) \ [list [expr {$c + 1}] [expr {$r - 1}]] } if {$c >= 1} { lappend moves(dn,$cr) \ [list [expr {$c - 1}] [expr {$r - 1}]] } } set jumps(up,$cr) {} if {$r <= 5} { if {$c <= 5} { lappend jumps(up,$cr) \ [list [expr {$c + 1}] [expr {$r + 1}]] \ [list [expr {$c + 2}] [expr {$r + 2}]] } if {$c >= 2} { lappend jumps(up,$cr) \ [list [expr {$c - 1}] [expr {$r + 1}]] \ [list [expr {$c - 2}] [expr {$r + 2}]] } } set jumps(dn,$cr) {} if {$r >= 2} { if {$c <= 5} { lappend jumps(dn,$cr) \ [list [expr {$c + 1}] [expr {$r - 1}]] \ [list [expr {$c + 2}] [expr {$r - 2}]] } if {$c >= 2} { lappend jumps(dn,$cr) \ [list [expr {$c - 1}] [expr {$r - 1}]] \ [list [expr {$c - 2}] [expr {$r - 2}]] } } for {set moves(d1,$cr) {}; \ set x [expr {$c+1}]; set y [expr {$r+1}]} \ {($x < 8) && ($y < 8)} {incr x; incr y} { lappend moves(d1,$cr) [list $x $y] } for {set moves(d2,$cr) {}; \ set x [expr {$c-1}]; set y [expr {$r+1}]} \ {($x >= 0) && ($y < 8)} {incr x -1; incr y} { lappend moves(d2,$cr) [list $x $y] } for {set moves(d3,$cr) {}; \ set x [expr {$c-1}]; set y [expr {$r-1}]} \ {($x >= 0) && ($y >= 0)} {incr x -1; incr y -1} { lappend moves(d3,$cr) [list $x $y] } for {set moves(d4,$cr) {}; \ set x [expr {$c+1}]; set y [expr {$r-1}]} \ {($x < 8) && ($y >= 0)} {incr x; incr y -1} { lappend moves(d4,$cr) [list $x $y] } } } } proc checkers::center {c r} { variable square_size variable line_width set r [expr {7 - $r}] list [expr {$line_width + ($square_size * 0.5) + \ (($square_size + $line_width) * $c)}] \ [expr {$line_width + ($square_size * 0.5) + \ (($square_size + $line_width) * $r)}] } proc checkers::close {gid} { variable $gid upvar 0 $gid flags array unset flags } proc checkers::exists {gid} { variable $gid info exists $gid } proc checkers::button_update_relief {b flag} { set rstate [expr {$flag? {pressed} : {!$pressed}}] if {[catch {$b state $rstate}]} { set relief [expr {$flag? "sunken" : "raised"}] $b configure -relief $relief } } proc checkers::open {gid} { variable options variable square_size variable line_width variable short_game_names variable $gid upvar 0 $gid flags set jid $flags(opponent) set w $flags(window) if {[winfo exists $w]} { raise_win $w return } set title [::msgcat::mc "%s with %s" \ $short_game_names($flags(game)) [get_nick $flags(xlib) $jid chat]] add_win $w -title $title \ -tabtitle $title \ -class Checkers \ -raise 1 set board [canvas $w.board \ -borderwidth 0 \ -highlightthickness 0 \ -width [expr {8 * $square_size + 9 * $line_width}] \ -height [expr {8 * $square_size + 9 * $line_width}]] pack $board -side left -anchor w -padx 2m set flags(board) $board set flags(show_last_move) $options(show_last_move) set slm [Button $w.show_last_move -text [::msgcat::mc "Show last move"] \ -command [list [namespace current]::toggle_show_last_move $gid]] button_update_relief $slm $flags(show_last_move) pack $slm -side top -anchor w -fill x set flags(show_last_move_button) $slm set flags(flip) 0 set slm [Button $w.flip -text [::msgcat::mc "Flip view"] \ -command [list [namespace current]::toggle_flip_view $gid]] pack $slm -side top -anchor w -fill x set flags(flip_button) $slm Frame $w.move pack $w.move -side top -anchor w Label $w.move.title -text [::msgcat::mc "Move: "] pack $w.move.title -side left Label $w.move.on_move -anchor w \ -textvariable [namespace current]::${gid}(move_label) pack $w.move.on_move -side left -anchor w set bbox [ButtonBox $w.bbox -orient vertical -spacing 0] set flags(propose_draw_button) \ [$bbox add -text [::msgcat::mc "Propose a draw"] \ -command [list [namespace current]::toggle_draw $gid]] $bbox add -text [::msgcat::mc "Accept the draw proposal"] \ -state disabled \ -command [list [namespace current]::accept_draw $gid] $bbox add -text [::msgcat::mc "Resign the game"] \ -command [list [namespace current]::send_resign $gid] grid columnconfigure $bbox 0 -weight 1 pack $bbox -side bottom -anchor w -fill x set flags(bbox) $bbox set_tooltips #label $w.history -text [::msgcat::mc "History"] #pack $w.history -side top -anchor w set hsw [ScrolledWindow $w.hsw] pack $hsw -side top -fill x -expand yes set ht [Text $w.text -wrap word -height 60 -state disabled] set font [$ht cget -font] set tabstop1 [font measure $font "99.."] set tabstop2 [font measure $font "99..Qa8-a8+= "] $ht configure -tabs "$tabstop1 $tabstop2" $ht tag configure attention \ -foreground [option get $ht errorForeground Text] $hsw setwidget $ht set flags(hw) $ht set dsq_color #77a26d set lsq_color #c8c365 for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { set x1 [expr {$line_width + (($square_size + $line_width) * $c)}] set x2 [expr {($square_size + $line_width) * ($c + 1)}] set y1 [expr {$line_width + (($square_size + $line_width) * $r)}] set y2 [expr {($square_size + $line_width) * ($r + 1)}] set color [expr {($c+$r) % 2 ? $dsq_color : $lsq_color}] switch -- $flags(board_type) { 0 { set img [expr {($c+$r) % 2 ? "bf" : "wf"}] } 1 { set img [expr {($c+$r) % 2 ? "wf" : "bf"}] } } $board create image $x1 $y1 -image checkers/$img -anchor nw \ -tags [list background [list cr [list $c [expr {7-$r}]]]] $board create rectangle $x1 $y1 $x2 $y2 \ -outline {} -width $line_width \ -tags [list square [list cr [list $c [expr {7-$r}]]]] } } $board bind figure <1> \ [list [namespace current]::start_drag_figure $gid %x %y] $board bind figure \ [list [namespace current]::drag_figure $gid %x %y] $board bind figure \ [list [namespace current]::drag_end $gid %x %y] bind $w [list [namespace current]::close $gid] if {![is_same_color $flags(our_color) $flags(start)] && \ $options(flip_black_view)} { toggle_flip_view $gid } draw_position $gid update_controls $gid find_legal_moves $gid $flags(position,turn) } proc checkers::toggle_flip_view {gid} { variable $gid upvar 0 $gid flags set flags(flip) [expr {!$flags(flip)}] set board $flags(board) for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { $board addtag [list temp [expr {7-$c}] [expr {7-$r}]] \ withtag [list cr [list $c $r]] $board dtag [list cr [list $c $r]] } } for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { $board addtag [list cr [list $c $r]] withtag [list temp $c $r] $board dtag [list temp $c $r] } } button_update_relief $flags(flip_button) $flags(flip) draw_position $gid highlight_last_move $gid } proc checkers::set_tooltips {args} { variable options if {$options(show_tooltips)} { set tooltip0 \ [::msgcat::mc \ "Press button and make move if you want propose draw"] set tooltip1 \ [::msgcat::mc "Press button if you want accept the draw proposal"] set tooltip2 [::msgcat::mc "Press button if you want resign"] } else { set tooltip0 "" set tooltip1 "" set tooltip2 "" } foreach var [info vars [namespace current]::*] { upvar 0 $var flags if {[info exists flags(bbox)]} { catch { $flags(bbox) itemconfigure 0 -helptext $tooltip0 $flags(bbox) itemconfigure 1 -helptext $tooltip1 $flags(bbox) itemconfigure 2 -helptext $tooltip2 } } } } proc checkers::toggle_show_last_move {gid} { variable $gid upvar 0 $gid flags set flags(show_last_move) [expr {!$flags(show_last_move)}] button_update_relief $flags(show_last_move_button) $flags(show_last_move) highlight_last_move $gid } proc checkers::toggle_draw {gid} { variable $gid upvar 0 $gid flags set flags(position,draw) [expr {!$flags(position,draw)}] button_update_relief $flags(propose_draw_button) $flags(position,draw) } proc checkers::update_controls {gid {draw_proposed 0}} { variable $gid upvar 0 $gid flags button_update_relief $flags(propose_draw_button) 0 if {[is_my_move $gid]} { $flags(board) config -cursor "" set flags(position,draw) 0 if {$draw_proposed} { $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state normal $flags(bbox) itemconfigure 2 -state disabled } else { $flags(bbox) itemconfigure 0 -state normal $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state normal } } elseif {![is_white $flags(position,turn)] && \ ![is_black $flags(position,turn)]} { $flags(board) config -cursor "" $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state disabled } else { $flags(board) config -cursor watch $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state disabled } } proc checkers::end_game {gid my_score message} { variable $gid upvar 0 $gid flags set opponent_score [expr {1 - $my_score}] if {[is_same_color $flags(our_color) $flags(start)]} { set score "$my_score : $opponent_score" } else { set score "$opponent_score : $my_score" } set flags(position,turn) none set flags(move_label) $message set hw $flags(hw) $hw configure -state normal catch {$hw delete attention.first attention.last} $hw delete {end -1 char} end $hw insert end "\n\t\t$score\n" $hw see end $hw configure -state disabled } proc checkers::draw_position {gid} { variable $gid upvar 0 $gid flags $flags(board) delete figure for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { set cr [list $c $r] if {$flags(position,$cr) != ""} { if {$flags(flip)} { set c1 [expr {7 - $c}] set r1 [expr {7 - $r}] } else { set c1 $c set r1 $r } $flags(board) create image [center $c1 $r1] \ -image checkers/$flags(position,$cr) \ -tags [list figure $flags(position,$cr) [list cr $cr]] } } } } proc checkers::start_drag_figure {gid x y} { variable $gid upvar 0 $gid flags set board $flags(board) lassign [lsearch -inline -regexp [$board gettags current] ^cr] \ cr currentcr set flags(current_move) [list $currentcr] set flags(last_x) [$board canvasx $x] set flags(last_y) [$board canvasy $y] $board raise current $board config -cursor hand2 highlight_legal_moves $gid $flags(current_move) } proc checkers::drag_figure {gid x y} { variable line_width variable $gid upvar 0 $gid flags set board $flags(board) set x [$board canvasx $x] set y [$board canvasy $y] $board move current \ [expr {$x - $flags(last_x)}] [expr {$y - $flags(last_y)}] set flags(last_x) $x set flags(last_y) $y $board itemconfigure dst_sq&&square -outline {} -width $line_width $board dtag dst_sq $board itemconfigure intermediate1&&square -outline yellow -width $line_width $board itemconfigure intermediate2&&square -outline green -width $line_width $board itemconfigure legal&&square -outline blue -width $line_width $board addtag dst_sq overlapping $x $y $x $y lassign [lsearch -inline -regexp [$board gettags dst_sq&&background] ^cr] \ -> cr $board addtag dst_sq withtag [list cr $cr]&&square $board itemconfigure dst_sq&&square -outline red -width $line_width $board itemconfigure dst_sq&&legal&&square -outline blue -width $line_width if {[lindex $flags(current_move) end] != $cr} { set current [concat $flags(current_move) [list $cr]] if {[is_move_prefix_legal $gid $current]} { set flags(current_move) $current highlight_legal_moves $gid $flags(current_move) } elseif {[is_move_legal $gid $current]} { $board itemconfigure dst_sq&&legal&&square -outline white -width $line_width } } $board itemconfigure dst_sq&&intermediate1&&square -outline yellow -width $line_width $board itemconfigure dst_sq&&intermediate2&&square -outline green -width $line_width } proc checkers::drag_end {gid x y} { variable options variable line_width variable $gid upvar 0 $gid flags set board $flags(board) set x [$board canvasx $x] set y [$board canvasy $y] $board itemconfigure dst_sq&&square -outline {} -width $line_width $board dtag dst_sq $board addtag dst_sq overlapping $x $y $x $y lassign [lsearch -inline -regexp [$board gettags dst_sq&&background] ^cr] \ -> cr $board dtag dst_sq lappend flags(current_move) $cr if {$options(allow_illegal) || [is_my_move $gid]} { do_move $gid $flags(current_move) $flags(position,draw) } update_controls $gid draw_position $gid unhighlight_legal_moves $gid highlight_last_move $gid } proc checkers::highlight_last_move {gid} { variable line_width variable $gid upvar 0 $gid flags $flags(board) itemconfigure square -outline {} -width $line_width $flags(board) itemconfigure square -outline {} -width $line_width if {![info exists flags(position,last_move)]} { return } if {$flags(show_last_move)} { set color white set color2 yellow } else { set color {} set color2 {} } foreach pos [lrange $flags(position,last_move) 1 end-1] { $flags(board) itemconfigure [list cr $pos]&&square -outline $color -width $line_width } $flags(board) itemconfigure \ [list cr [lindex $flags(position,last_move) 0]]&&square -outline $color -width $line_width $flags(board) itemconfigure \ [list cr [lindex $flags(position,last_move) end]]&&square \ -outline $color -width $line_width } proc checkers::do_move {gid move draw} { variable options variable $gid upvar 0 $gid flags if {([llength $move] < 2) || ([lindex $move 0] == [lindex $move 1])} { return 0 } set endgame 0 set opt "-" set suffix "" set my_move [is_my_move $gid] if {![is_move_legal $gid $move]} { if {$my_move && !$options(allow_illegal)} { return 0 } if {!$my_move && !$options(accept_illegal)} { return 0 } } save_position $gid set figure $flags(position,[lindex $move 0]) if {![is_move_legal $gid $move]} { set flags(position,[lindex $move end]) $figure set flags(position,[lindex $move 0]) "" } else { set origin [lindex $move 0] foreach step [lrange $move 1 end] { lassign $origin originx originy lassign $step stepx stepy set dx [expr {$originx < $stepx ? 1 : -1}] set dy [expr {$originy < $stepy ? 1 : -1}] for {set x $originx; set y $originy} \ {($x != $stepx) && ($y != $stepy)} \ {incr x $dx; incr y $dy} { set xy [list $x $y] if {![is_same_color $flags(position,$xy) $figure]} { set opt ":" } set flags(position,$xy) "" } switch -- $flags(game) { straight { switch -- $figure,$stepy { bp,7 { set figure bk } wp,0 { set figure wk } } } pool - brazilian { switch -- $figure,$stepy { bp,7 { if {[lindex $move end] == $step} { set figure bk } } wp,0 { if {[lindex $move end] == $step} { set figure wk } } } } russian - spanish - italian { switch -- $figure,$stepy { wp,7 { set figure wk } bp,0 { set figure bk } } } } set flags(position,$step) $figure set origin $step } } set flags(position,last_move) $move if {[is_white $flags(position,turn)]} { set flags(position,turn) black } else { set flags(position,turn) white } find_legal_moves $gid $flags(position,turn) if {[llength $flags(legal_moves)] == 0} { set draw 0 set endgame 1 } if {$draw} { set suffix "=" } add_move_to_history $gid $move $opt $suffix if {$draw && !$my_move} { attention_message $gid \ [::msgcat::mc "\n\n Opponent proposes a draw\n\n"] } if {$my_move} { send_move $gid $move } if {$endgame} { if {$my_move} { # I win end_game $gid 1 [::msgcat::mc "You win"] } else { # Opponent wins end_game $gid 0 [::msgcat::mc "Opponent wins"] } } tab_set_updated [winfo parent $flags(board)] 1 mesg_to_user return 1 } proc checkers::accept_draw {gid} { variable $gid upvar 0 $gid flags ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type checkers:$flags(game) \ id $flags(id)] \ -subelement [::xmpp::xml::create accept]] \ -to $flags(opponent) end_game $gid 0.5 [::msgcat::mc "Draw (You accepted)"] update_controls $gid draw_position $gid highlight_last_move $gid } proc checkers::send_resign {gid} { variable $gid upvar 0 $gid flags ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type checkers:$flags(game) \ id $flags(id)] \ -subelement [::xmpp::xml::create resign]] \ -to $flags(opponent) end_game $gid 0 [::msgcat::mc "Opponent wins (You resigned)"] update_controls $gid draw_position $gid highlight_last_move $gid } proc checkers::send_move {gid move} { variable $gid upvar 0 $gid flags set move_tags [list [make_move_tag $gid $move]] if {$flags(position,draw)} { lappend move_tags [::xmpp::xml::create draw] } ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type checkers:$flags(game) \ id $flags(id)] \ -subelements $move_tags] \ -to $flags(opponent) \ -command [list [namespace current]::send_result $gid] } proc checkers::send_result {gid status xml} { if {$status == "error"} { attention_message $gid \ [::msgcat::mc "\n\n Opponent rejected move:\n %s\n\n" \ [error_to_string $xml]] restore_position $gid } } proc checkers::make_move_tag {gid move} { set move1 {} foreach pos $move { lappend move1 [join $pos ","] } ::xmpp::xml::create move -attrs [list pos [join $move1 ";"]] } proc checkers::add_move_to_history {gid move opt suffix} { variable piece_name variable $gid upvar 0 $gid flags incr flags(position,halfmove) 1 lappend flags(position,history) [list $move $opt $suffix] set hw $flags(hw) $hw configure -state normal $hw delete 0.0 end if {[is_white $flags(start)]} { $hw insert end "\t[::msgcat::mc White]\t[::msgcat::mc Black]\n" } else { $hw insert end "\t[::msgcat::mc Black]\t[::msgcat::mc White]\n" } set i 1 foreach {w b} $flags(position,history) { $hw insert end "${i}.\t" if {$w != {}} { lassign $w move opt suffix set move1 {} foreach pos $move { lassign $pos c r incr r set l [format %c [expr {$c+97}]] lappend move1 "$l$r" } $hw insert end "[join $move1 $opt]$suffix\t" } if {$b != {}} { lassign $b move opt suffix set move1 {} foreach pos $move { lassign $pos c r incr r set l [format %c [expr {$c+97}]] lappend move1 "$l$r" } $hw insert end "[join $move1 $opt]$suffix\n" } incr i } $hw see end $hw configure -state disabled } proc checkers::find_legal_moves {gid color} { variable moves variable jumps variable $gid upvar 0 $gid flags set flags(legal_moves) {} find_legal_jumps $gid $color if {[llength $flags(legal_moves)] == 0} { find_legal_moves1 $gid $color } } proc checkers::find_legal_jumps {gid color} { variable moves variable $gid upvar 0 $gid flags for {set cf 0} {$cf < 8} {incr cf} { for {set rf 0} {$rf < 8} {incr rf} { set cr [list $cf $rf] if {![is_same_color $flags(position,$cr) $color]} { continue } set figure $flags(position,$cr) set flags(position,$cr) "" find_legal_jumps1 $gid $cr $figure [list $cr] {} set flags(position,$cr) $figure } } clean_jumps $gid } proc checkers::clean_jumps {gid} { variable $gid upvar 0 $gid flags switch -- $flags(game) { brazilian - spanish { set jumps {} set l 0 foreach m $flags(legal_moves) { set l1 [llength $m] if {$l1 > $l} { set jumps [list $m] set l $l1 } elseif {$l1 == $l} { lappend jumps $m } } set flags(legal_moves) $jumps } italian { set jumps {} set l 0 set captor b set nkings 0 set pking 0 foreach m $flags(legal_moves) { set l1 [llength $m] set captor1 [string index $flags(position,[lindex $m 0]) end] lassign [count_kings $gid $m] nkings1 pking1 if {($l1 > $l) || (($l1 == $l) && ($captor1 == "k" && $captor == "b")) || (($l1 == $l) && ($captor1 == $captor) && \ ($nkings1 > $nkings)) || (($l1 == $l) && ($captor1 == $captor) && \ ($nkings1 == $nkings) && ($pking1 < $pking))} { set jumps [list $m] set l $l1 set captor $captor1 set nkings $nkings1 set pking $pking1 } elseif {($l1 == $l) && ($captor == $captor1) && \ ($nkings1 == $nkings) && ($pking1 == $pking)} { lappend jumps $m } } set flags(legal_moves) $jumps } } } proc checkers::count_kings {gid move} { variable $gid upvar 0 $gid flags set nkings 0 set pking 0 set crf [lindex $move 0] set i 1 foreach crt [lrange $move 1 end] { lassign $crf cf rf lassign $crt ct rt set crm [list [expr {($cf + $ct)/2}] [expr {($rf + $rt)/2}]] if {[string index $flags(position,$crm) end] == "k"} { incr nkings if {$pking == 0} { set pking $i } } incr i } return [list $nkings $pking] } proc checkers::find_legal_jumps1 \ {gid cr figure current forbidden {simulate 0}} { variable moves variable jumps variable $gid upvar 0 $gid flags set jump 0 switch -- $figure { "" { continue } bp { switch -- $flags(game) { straight { foreach {crdel crt} $jumps(up,$cr) { if {[lsearch -exact $forbidden $crdel] < 0 && \ [is_white $flags(position,$crdel)] && \ $flags(position,$crt) == ""} { find_legal_jumps1 $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } spanish { foreach {crdel crt} $jumps(dn,$cr) { if {[lsearch -exact $forbidden $crdel] < 0 && \ [is_white $flags(position,$crdel)] && \ $flags(position,$crt) == ""} { find_legal_jumps1 $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } italian { foreach {crdel crt} $jumps(dn,$cr) { if {[lsearch -exact $forbidden $crdel] < 0 && \ $flags(position,$crdel) == "wp" && \ $flags(position,$crt) == ""} { find_legal_jumps1 $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } russian { foreach {crdel crt} \ [concat $jumps(up,$cr) $jumps(dn,$cr)] { if {[lsearch -exact $forbidden $crdel] < 0 && \ [is_white $flags(position,$crdel)] && \ $flags(position,$crt) == ""} { find_legal_jumps1 $gid $crt \ [expr {[lindex $crt 1] == 0 ? "bk" : "bp"}] \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } pool - brazilian { foreach {crdel crt} \ [concat $jumps(up,$cr) $jumps(dn,$cr)] { if {[lsearch -exact $forbidden $crdel] < 0 && \ [is_white $flags(position,$crdel)] && \ $flags(position,$crt) == ""} { find_legal_jumps1 $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } } } wp { switch -- $flags(game) { straight { foreach {crdel crt} $jumps(dn,$cr) { if {[lsearch -exact $forbidden $crdel] < 0 && \ [is_black $flags(position,$crdel)] && \ $flags(position,$crt) == ""} { find_legal_jumps1 $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } spanish { foreach {crdel crt} $jumps(up,$cr) { if {[lsearch -exact $forbidden $crdel] < 0 && \ [is_black $flags(position,$crdel)] && \ $flags(position,$crt) == ""} { find_legal_jumps1 $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } italian { foreach {crdel crt} $jumps(up,$cr) { if {[lsearch -exact $forbidden $crdel] < 0 && \ $flags(position,$crdel) == "bp" && \ $flags(position,$crt) == ""} { find_legal_jumps1 $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } russian { foreach {crdel crt} \ [concat $jumps(dn,$cr) $jumps(up,$cr)] { if {[lsearch -exact $forbidden $crdel] < 0 && \ [is_black $flags(position,$crdel)] && \ $flags(position,$crt) == ""} { find_legal_jumps1 $gid $crt \ [expr {[lindex $crt 1] == 7 ? "wk" : "wp"}] \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } pool - brazilian { foreach {crdel crt} \ [concat $jumps(dn,$cr) $jumps(up,$cr)] { if {[lsearch -exact $forbidden $crdel] < 0 && \ [is_black $flags(position,$crdel)] && \ $flags(position,$crt) == ""} { find_legal_jumps1 $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } } } wk - bk { switch -- $flags(game) { straight - italian { foreach {crdel crt} \ [concat $jumps(dn,$cr) $jumps(up,$cr)] { if {[lsearch -exact $forbidden $crdel] < 0 && \ ![is_same_color $flags(position,$crdel) \ $figure] && \ $flags(position,$crt) == ""} { find_legal_jumps1 $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } russian - pool - brazilian - spanish { set canjump {} set cantjump {} foreach d {d1 d2 d3 d4} { set state empty foreach crt $moves($d,$cr) { switch -- $state { empty { if {($flags(position,$crt) != "")} { if {[lsearch -exact $forbidden \ $crt] < 0 && \ ![is_same_color \ $flags(position,$crt) \ $figure]} { set crdel $crt set state jump } else { break } } } jump { if {($flags(position,$crt) == "")} { if {[find_legal_jumps1 \ $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden \ [list $crdel]] 1]} { lappend canjump $crdel $crt } else { lappend cantjump $crdel $crt } } else { break } } } } } if {[llength $canjump] > 0} { foreach {crdel crt} $canjump { find_legal_jumps1 $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } else { foreach {crdel crt} $cantjump { find_legal_jumps1 $gid $crt $figure \ [concat $current [list $crt]] \ [concat $forbidden [list $crdel]] set jump 1 } } } } } } if {!$simulate && !$jump && [llength $current] >= 2} { lappend flags(legal_moves) $current } return $jump } proc checkers::find_legal_moves1 {gid color} { variable moves variable $gid upvar 0 $gid flags for {set cf 0} {$cf < 8} {incr cf} { for {set rf 0} {$rf < 8} {incr rf} { set cr [list $cf $rf] if {![is_same_color $flags(position,$cr) $color]} { continue } switch -- $flags(position,$cr) { "" { continue } bp { switch -- $flags(game) { straight - pool - brazilian { foreach crt $moves(up,$cr) { if {$flags(position,$crt) == ""} { lappend flags(legal_moves) [list $cr $crt] } } } russian - spanish - italian { foreach crt $moves(dn,$cr) { if {$flags(position,$crt) == ""} { lappend flags(legal_moves) [list $cr $crt] } } } } } wp { switch -- $flags(game) { straight - pool - brazilian { foreach crt $moves(dn,$cr) { if {$flags(position,$crt) == ""} { lappend flags(legal_moves) [list $cr $crt] } } } russian - spanish - italian { foreach crt $moves(up,$cr) { if {$flags(position,$crt) == ""} { lappend flags(legal_moves) [list $cr $crt] } } } } } wk - bk { switch -- $flags(game) { straight - italian { foreach crt \ [concat $moves(up,$cr) $moves(dn,$cr)] { if {$flags(position,$crt) == ""} { lappend flags(legal_moves) [list $cr $crt] } } } russian - pool - brazilian - spanish { foreach d {d1 d2 d3 d4} { foreach crt $moves($d,$cr) { if {$flags(position,$crt) == ""} { lappend flags(legal_moves) \ [list $cr $crt] } else { break } } } } } } } } } } proc checkers::is_move_legal {gid move} { variable $gid upvar 0 $gid flags expr {[lsearch -exact $flags(legal_moves) $move] >= 0} } proc checkers::is_move_prefix_legal {gid move} { variable $gid upvar 0 $gid flags expr {[lsearch -glob $flags(legal_moves) "$move *"] >= 0} } proc checkers::highlight_legal_moves {gid prefix} { variable line_width variable $gid upvar 0 $gid flags unhighlight_legal_moves $gid set len [llength $prefix] set lenm1 [expr {$len - 1}] foreach move $flags(legal_moves) { if {[lrange $move 0 $lenm1] != $prefix} { continue } foreach pos [lrange $move 1 $lenm1] { $flags(board) addtag intermediate1 withtag [list cr $pos]&&square } foreach pos [lrange $move $len end-1] { $flags(board) addtag intermediate2 withtag [list cr $pos]&&square } $flags(board) addtag legal withtag [list cr [lindex $move end]]&&square } $flags(board) itemconfigure legal&&square -outline blue -width $line_width $flags(board) itemconfigure intermediate1&&square -outline yellow -width $line_width $flags(board) itemconfigure intermediate2&&square -outline green -width $line_width } proc checkers::unhighlight_legal_moves {gid} { variable line_width variable $gid upvar 0 $gid flags $flags(board) itemconfigure square -outline {} -width $line_width $flags(board) dtag legal $flags(board) dtag intermediate1 $flags(board) dtag intermediate2 } proc checkers::attention_message {gid message} { variable $gid upvar 0 $gid flags set hw $flags(hw) $hw configure -state normal $hw delete {end -1 char} end $hw insert end $message attention $hw see end $hw configure -state disabled } proc checkers::is_my_move {gid} { variable $gid upvar 0 $gid flags is_same_color $flags(position,turn) $flags(our_color) } proc checkers::is_white {f} { string equal -length 1 $f w } proc checkers::is_black {f} { string equal -length 1 $f b } proc checkers::is_same_color {f1 f2} { string equal -length 1 $f1 $f2 } proc checkers::add_groupchat_user_menu_item {m xlib jid} { set mm $m.gamesmenu if {![winfo exists $mm]} { menu $mm -tearoff 0 $m add cascade -label [::msgcat::mc "Games"] -menu $mm } $mm add command -label [::msgcat::mc "Checkers..."] \ -command [list [namespace current]::invite_dialog $xlib $jid] } proc checkers::iq_create {varname xlib from iqid xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels lassign [split [::xmpp::xml::getAttr $attrs type] ":"] category game if {$category != "checkers"} { return } switch -- $game { straight - russian - pool - brazilian - spanish - italian { if {[::xmpp::xml::isAttr $attrs color]} { set color [::xmpp::xml::getAttr $attrs color] switch -- $color { white - black { } default { set var [list error modify bad-request] } } } else { set color white } set var [[namespace current]::invited_dialog \ $game $xlib $from $iqid \ [::xmpp::xml::getAttr $attrs id] \ $color] } } return } proc checkers::iq_turn {varname xlib from xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels lassign [split [::xmpp::xml::getAttr $attrs type] ":"] category game if {$category != "checkers"} { return } switch -- $game { straight - russian - pool - brazilian - spanish - italian { set gid [make_gid $from [::xmpp::xml::getAttr $attrs id]] if {[exists $gid]} { set var [[namespace current]::turn_recv $gid $subels] } else { set var [list error cancel item-not-found] } } } return } # Common games:board part proc iq_games_board_create {xlib from xml args} { set res [list error cancel feature-not-implemented] set iqid [::xmpp::xml::getAttr $args -id] hook::run games_board_create_hook res $xlib $from $iqid $xml return $res } proc iq_games_board_turn {xlib from xml args} { set res [list error cancel feature-not-implemented] hook::run games_board_turn_hook res $xlib $from $xml return $res } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/checkers/msgs000075500000000000000000000000001500237002100161725ustar00nobodynobodytkabber-plugins/checkers/msgs/es.msg000064400000000000000000000110341500237002100173670ustar00nobodynobody# es.msg -- # # Spanish messages for the Checkers Tkabber plugin. # # Author: Badlop ::msgcat::mcset es " (Opponent)" " (Oponente)" ::msgcat::mcset es " (You)" " (Tu)" ::msgcat::mcset es "%s (%s) has refused checkers invitation: %s" "%s (%s) ha\ rechazado la invitación: %s" ::msgcat::mcset es "%s wants play %s." "%s quiere jugar %s." ::msgcat::mcset es "%s wants play black." "%s quiere jugar con las negras." ::msgcat::mcset es "%s wants play white." "%s quiere jugar con las blancas." ::msgcat::mcset es "%s with %s" "%s con %s" ::msgcat::mcset es "Accept opponent illegal moves (useful for debugging)." \ "Aceptar movimientos ilegales del oponente (útil para depuración)." ::msgcat::mcset es "Accept the draw proposal" "Aceptar la propuesta de empate" ::msgcat::mcset es "Agree to play" "Aceptar la invitación" ::msgcat::mcset es "Allow illegal moves (useful for debugging)." "Permitir\ movimientos ilegales (útil para depuración)." ::msgcat::mcset es "Black" "Negra" ::msgcat::mcset es "Brazilian checkers" "Damas brasileñas" ::msgcat::mcset es "Cancel invitation" "Cancelar la invitación" ::msgcat::mcset es "Checkers Invitation from %s" "Invitación a las Damas de %s" ::msgcat::mcset es "Checkers Invitation" "Invitación a las Damas" ::msgcat::mcset es "Checkers figures theme." "Tipo de figuras." ::msgcat::mcset es "Checkers game invitation from %s (%s) is received." \ "Se ha recibido una invitación de %s (%s) para jugar a las damas." ::msgcat::mcset es "Checkers plugin options." "Opciones del plugin de las\ Damas." ::msgcat::mcset es "Checkers..." "Damas..." ::msgcat::mcset es "Default game variant." "Variante del juego por defecto." ::msgcat::mcset es "Draw (Opponent accepted)" "Empate (el oponente aceptó)" ::msgcat::mcset es "Draw (You accepted)" "Empate (aceptaste)" ::msgcat::mcset es "Flip board view when playing black (Russian, Spanish,\ Italian) or white (Straight, Pool, Brazilian) by default." "Rotar\ por defecto el tablero si juegas con las negras (rusas, españolas,\ italianas) o las blancas (Straight, Pool, brasileñas)." ::msgcat::mcset es "Flip view" "Rotar tablero" ::msgcat::mcset es "Games" "Juegos" ::msgcat::mcset es "History" "Historia" ::msgcat::mcset es "I want play black" "Quiero jugar con las negras" ::msgcat::mcset es "I want play white" "Quiero jugar con las blancas" ::msgcat::mcset es "Italian checkers" "Damas italianas" ::msgcat::mcset es "Move: " "Movimiento: " ::msgcat::mcset es "Opponent wins (You resigned)" "El oponente gana (te\ rendiste)" ::msgcat::mcset es "Opponent wins" "El oponente gana" ::msgcat::mcset es "Plugins options." "Opciones de plugins." ::msgcat::mcset es "Pool checkers" "Damas Pool" ::msgcat::mcset es "Press button and make move if you want propose draw" \ "Pulsa el botón y haz un movimiento si quieres proponer un empate" ::msgcat::mcset es "Press button if you want accept the draw proposal" \ "Pulsa el botón si quieres aceptar la propuesta de empate" ::msgcat::mcset es "Press button if you want resign" "Pulsa el botón si\ quieres rendirte" ::msgcat::mcset es "Propose a draw" "Proponer un empate" ::msgcat::mcset es "Refuse to play" "Rechazar la invitación" ::msgcat::mcset es "Resign the game" "Rendirte" ::msgcat::mcset es "Russian checkers" "Damas rusas" ::msgcat::mcset es "Sending checkers game invitation to %s (%s)" "Enviando\ invitación para jugar a las damas a %s (%s)" ::msgcat::mcset es "Show last move by default." "Mostrar el último movimiento\ por defecto." ::msgcat::mcset es "Show last move" "Mostrar el último movimiento" ::msgcat::mcset es "Show tooltips with short instructions." "Mostrar pequeñas\ instrucciones de ayuda." ::msgcat::mcset es "Sound to play after opponent's turn" "Sonido a reproducir\ cuando el oponente haya movido" ::msgcat::mcset es "Spanish checkers" "Damas españolas" ::msgcat::mcset es "Straight checkers (English draughts)" "Damas Straight\ (inglesas)" ::msgcat::mcset es "Straight checkers" "Damas Straight" ::msgcat::mcset es "Whether the Checkers plugin is loaded." "Cargar el\ plugin Checkers." ::msgcat::mcset es "White" "Blanca" ::msgcat::mcset es "You win (Opponent resigned)" "Tu ganas (el oponente\ se rindió)" ::msgcat::mcset es "You win" "Tu ganas" ::msgcat::mcset es "\n\n Opponent proposes a draw\n\n" \ "\n\n El oponente propone un empate \n\n" ::msgcat::mcset es "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n El oponente rechazó el movimiento:\n %s\n\n" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/checkers/msgs/nl.msg000064400000000000000000000106431500237002100173760ustar00nobodynobody# nl.msg -- # # Dutch messages for the Checkers Tkabber plugin. # # Author: Sander Devrieze ::msgcat::mcset nl "Straight checkers (English draughts)" "Engels dammen" ::msgcat::mcset nl "Russian checkers" "Russisch dammen" ::msgcat::mcset nl "Pool checkers" "Pools dammen" ::msgcat::mcset nl "Brazilian checkers" "Braziliaans dammen" ::msgcat::mcset nl "Spanish checkers" "Spaans dammen" ::msgcat::mcset nl "Italian checkers" "Italiaans dammen" ::msgcat::mcset nl "Straight checkers" "Engels dammen" ::msgcat::mcset nl "Plugins options." "Pluginopties." ::msgcat::mcset nl "Checkers plugin options." "Pluginopties voor dammen." ::msgcat::mcset nl "Checkers figures theme." \ "Thema voor afbeeldingen van stenen." ::msgcat::mcset nl "Default game variant." "Standaard spel." ::msgcat::mcset nl "Flip board view when playing black (Russian, Spanish,\ Italian) or white (Straight, Pool, Brazilian) by default." "Het\ speelbord standaard omkeren bij het spelen met zwart (Russisch,\ Spaans, Italiaans) of wit (Engels, Pools, Braziliaans)." ::msgcat::mcset nl "Show last move by default." \ "Laatste zet standaard laten zien." ::msgcat::mcset nl "Show tooltips with short instructions." \ "Tekstballonnen met korte instructies laten zien." ::msgcat::mcset nl "Allow illegal moves (useful for debugging)." \ "Niet-toegelaten zetten toestaan (bruikbaar voor debuggen)." ::msgcat::mcset nl "Accept opponent illegal moves (useful for debugging)." \ "Niet-toegelaten zetten van tegenstander accepteren (bruikbaar voor\ debuggen)." ::msgcat::mcset nl "Checkers Invitation" "Uitnodiging voor een damspel" ::msgcat::mcset nl "Sending checkers game invitation to %s (%s)" \ "Bezig met verzenden van uitnodiging voor een damspel naar %s (%s)" ::msgcat::mcset nl "I want play white" "Ik wil met wit spelen" ::msgcat::mcset nl "I want play black" "Ik wil met zwart spelen" ::msgcat::mcset nl "Cancel invitation" "Uitnodiging annuleren" ::msgcat::mcset nl "%s (%s) has refused checkers invitation: %s" \ "%s (%s) ging niet in op de uitnodiging om met hem te dammen: %s" ::msgcat::mcset nl "Checkers Invitation from %s" \ "Uitnodiging voor een damspel met %s" ::msgcat::mcset nl "Checkers game invitation from %s (%s) is received." \ "Uitnodiging voor een damspel met %s (%s) werd ontvangen." ::msgcat::mcset nl "%s wants play %s." "%s wil %s spelen." ::msgcat::mcset nl "%s wants play %s." "%s wil spelen met %s." ::msgcat::mcset nl "Agree to play" "Spelen" ::msgcat::mcset nl "Refuse to play" "Niet spelen" ::msgcat::mcset nl "White" "Wit" ::msgcat::mcset nl "Black" "Zwart" ::msgcat::mcset nl " (You)" "(Jij)" ::msgcat::mcset nl " (Opponent)" "(Tegenstander)" ::msgcat::mcset nl "You win (Opponent resigned)" \ "Jij hebt gewonnen (de tegenstander gaf het op)" ::msgcat::mcset nl "Draw (Opponent accepted)" \ "Gelijkspel (de tegenstander accepteerde de uitslag)" ::msgcat::mcset nl "%s with %s" "%s met %s" ::msgcat::mcset nl "Show last move" "Laatste zet laten zien" ::msgcat::mcset nl "Flip view" "Beeld omkeren" ::msgcat::mcset nl "Move: " "Zet: " ::msgcat::mcset nl "Propose a draw" "Gelijkspel voorstellen" ::msgcat::mcset nl "Accept the draw proposal" \ "Het voorstel voor gelijkspel accepteren" ::msgcat::mcset nl "Resign the game" "Geef het op" ::msgcat::mcset nl "History" "Geschiedenis" ::msgcat::mcset nl "Press button and make move if you want propose draw" \ "Druk op de knop en doe een zet als je gelijkspel wilt voorstellen" ::msgcat::mcset nl "Press button if you want accept the draw proposal" \ "Druk op de knop als je het voorstel voor gelijkspel wilt accepteren" ::msgcat::mcset nl "Press button if you want resign" \ "Druk op de knop als je wilt opgeven" ::msgcat::mcset nl "\n\n Opponent proposes a draw\n\n" \ "\n\n De tegenstander stelt een gelijkspel voor\n\n" ::msgcat::mcset nl "You win" "Jij hebt gewonnen" ::msgcat::mcset nl "Opponent wins" "De tegenstander heeft gewonnen" ::msgcat::mcset nl "Draw (You accepted)" \ "Gelijkspel (jij accepteerde de uitslag)" ::msgcat::mcset nl "Opponent wins (You resigned)" \ "De tegenstander heeft gewonnen (jij gaf het op)" ::msgcat::mcset nl "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n De tegenstander weigerde de zet:\n %s\n\n" ::msgcat::mcset nl "Games" "Spelletjes" ::msgcat::mcset nl "Checkers..." "Dammen..." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/checkers/msgs/pl.msg000064400000000000000000000115251500237002100174000ustar00nobodynobody# pl.msg -- # # Polish messages for the Checkers Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Straight checkers (English draughts)" "Warcaby angielskie" ::msgcat::mcset pl "Brazilian checkers" "Warcaby brazylijskie" ::msgcat::mcset pl "Russian checkers" "Warcaby rosyjskie" ::msgcat::mcset pl "Pool checkers" "Warcaby tradycyjne" ::msgcat::mcset pl "Spanish checkers" "Warcaby hiszpaÅ„skie" ::msgcat::mcset pl "Italian checkers" "Warcaby wÅ‚oskie" ::msgcat::mcset pl "Straight checkers" "Warcaby klasyczne" ::msgcat::mcset pl "Checkers plugin options." \ "Ustawienia wtyczki do gry w warcaby." ::msgcat::mcset pl "Checkers figures theme." "Motyw graficzny bierek." ::msgcat::mcset pl "Default game variant." "DomyÅ›lny wariant gry." ::msgcat::mcset pl "Flip board view when playing black (Russian, Spanish,\ Italian) or white (Straight, Pool, Brazilian) by default." \ "Odwróć widok warcabnicy podczas gry czarnymi (warcaby rosyjskie,\ hiszpaÅ„skie, wÅ‚oskie) lub biaÅ‚ymi (tradycyjne, klasyczne,\ brazylijskie)." ::msgcat::mcset pl "Checkers Invitation" "Zaproszenie do gry w warcaby" ::msgcat::mcset pl "Sending checkers game invitation to %s (%s)" \ "WysyÅ‚anie zaproszenia do gry w warcaby do %s (%s)" ::msgcat::mcset pl "%s (%s) has refused checkers invitation: %s" \ "%s (%s) odrzuca zaproszenie do gry w warcaby: %s" ::msgcat::mcset pl "Checkers Invitation from %s" \ "Zaproszenie do gry w warcaby od %s" ::msgcat::mcset pl "Checkers game invitation from %s (%s) is received." \ "Otrzymano zaproszenie do gry w warcaby od %s (%s)." ::msgcat::mcset pl "%s wants play %s." "%s wybraÅ‚ %s." ::msgcat::mcset pl "%s wants play white." "%s chce grać biaÅ‚ymi." ::msgcat::mcset pl "%s wants play black." "%s chce grać czarnymi." ::msgcat::mcset pl "%s with %s" "%s: %s" ::msgcat::mcset pl "You win" "Twoja wygrana" ::msgcat::mcset pl "Opponent wins" "Wygrana przeciwnika" ::msgcat::mcset pl "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Przeciwnik odrzuciÅ‚ ruch:\n %s\n\n" ::msgcat::mcset pl "Checkers..." "Warcaby..." ::msgcat::mcset pl "White" "BiaÅ‚e" ::msgcat::mcset pl "Move: " "Ruch: " ::msgcat::mcset pl "History" "Historia" ::msgcat::mcset pl "Black" "Czarne" ::msgcat::mcset pl "Show last move by default." "Pokazuj ostatni ruch." ::msgcat::mcset pl "Show tooltips with short instructions." \ "Pokazuj dymki podpowiedzi z krótkimi instrukcjami." ::msgcat::mcset pl "Allow illegal moves (useful for debugging)." \ "Pozwalaj na nieprawidÅ‚owe ruchy (użyteczne przy debugowaniu)." ::msgcat::mcset pl "Accept opponent illegal moves (useful for debugging)." \ "Pozwalaj na nieprawidÅ‚owe ruchy przeciwnika (użyteczne przy\ debugowaniu)." ::msgcat::mcset pl "I want play white" "ChcÄ™ grać biaÅ‚ymi" ::msgcat::mcset pl "I want play black" "ChcÄ™ grać czarnymi" ::msgcat::mcset pl "Cancel invitation" "Anuluj zaproszenie" ::msgcat::mcset pl "Agree to play" "Przyjmij zaproszenie" ::msgcat::mcset pl "Refuse to play" "Odrzuć zaproszenie" ::msgcat::mcset pl " (You)" " (Ty)" ::msgcat::mcset pl " (Opponent)" " (Przeciwnik)" ::msgcat::mcset pl "You win (Opponent resigned)" \ "WygaÅ‚eÅ› (przeciwnik zrezygnowaÅ‚)" ::msgcat::mcset pl "Draw (Opponent accepted)" "Remis (za zgodÄ… przeciwnika)" ::msgcat::mcset pl "Show last move" "Pokaż ostatni ruch" ::msgcat::mcset pl "Flip view" "Odwróć widok" ::msgcat::mcset pl "Propose a draw" "Zaproponuj remis" ::msgcat::mcset pl "Accept the draw proposal" "Zaakceptuj remis" ::msgcat::mcset pl "Resign the game" "Zrezygnuj z gry" ::msgcat::mcset pl "Press button and make move if you want propose draw" \ "NaciÅ›nij przycisk i wykonaj ruch jeżeli chcesz zaproponować remis" ::msgcat::mcset pl "Press button if you want accept the draw proposal" \ "NaciÅ›nij przycisk jeżeli chcesz zaakceptować propozycjÄ™ remisu" ::msgcat::mcset pl "Press button if you want resign" \ "NaciÅ›nij przycisk jeżeli chcesz zrezygnować z gry" ::msgcat::mcset pl "\n\n Opponent proposes a draw\n\n" \ "\n\n Przeciwnik proponuje remis\n\n" ::msgcat::mcset pl "Draw (You accepted)" "Remis (Za mojÄ… zgodÄ…)" ::msgcat::mcset pl "Opponent wins (You resigned)" \ "WygraÅ‚ przeciwnik (ZrezygnowaÅ‚eÅ› z gry)" ::msgcat::mcset pl "Games" "Gry planszowe" ::msgcat::mcset pl "Sound to play after opponent's turn" \ "Odtwórz dźwiÄ™k po ruchu przeciwnika" ::msgcat::mcset pl "%s wants play white." "%s chce grać biaÅ‚ymi." ::msgcat::mcset pl "%s wants play black." "%s chce grać czarnymi." ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Przeciwnik odrzuciÅ‚ ruch:\n %s\n\n" ::msgcat::mcset pl "Whether the Checkers plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ do gry w warcaby." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/checkers/msgs/ru.msg000064400000000000000000000132661500237002100174170ustar00nobodynobody# ru.msg -- # # Russian messages for the Checkers Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Plugins options." "Параметры раÑширений." ::msgcat::mcset ru "Show last move by default." \ "По умолчанию показывать поÑледний ход." ::msgcat::mcset ru " (You)" " (Ð’Ñ‹)" ::msgcat::mcset ru " (Opponent)" " (Оппонент)" ::msgcat::mcset ru "Flip view" "Развернуть доÑку" ::msgcat::mcset ru "Checkers plugin options." "Параметры раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð¨Ð°ÑˆÐºÐ¸." ::msgcat::mcset ru "Checkers figures theme." "Внешний вид шашек." ::msgcat::mcset ru "Show tooltips with short instructions." \ "Показывать вÑплывающие подÑказки к Ñлементам интерфейÑа." ::msgcat::mcset ru "Allow illegal moves (useful for debugging)." \ "Разрешать неправильные ходы (иÑпользуетÑÑ Ð¿Ñ€Ð¸ отладке)." ::msgcat::mcset ru "Accept opponent illegal moves (useful for debugging)." \ "Принимать неправильные ходы от оппонента (иÑпользуетÑÑ Ð¿Ñ€Ð¸ отладке)." ::msgcat::mcset ru "Checkers Invitation" "Приглашение Ñыграть в шашки" ::msgcat::mcset ru "Sending checkers game invitation to %s (%s)" \ "ПоÑылаем приглашение Ñыграть в шашки Ñ %s (%s)" ::msgcat::mcset ru "I want play white" "Хочу играть белыми" ::msgcat::mcset ru "I want play black" "Хочу играть чёрными" ::msgcat::mcset ru "Cancel invitation" "Отменить приглашение" ::msgcat::mcset ru "%s (%s) has refused checkers invitation: %s" \ "%s (%s) отказалÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ в шашки: %s" ::msgcat::mcset ru "Checkers Invitation from %s" \ "Приглашение Ñыграть в шашки Ñ %s" ::msgcat::mcset ru "Checkers game invitation from %s (%s) is received." \ "Получено приглашение Ñыграть в шашки Ñ %s (%s)" ::msgcat::mcset ru "%s wants play white." "%s хочет играть белыми" ::msgcat::mcset ru "%s wants play black." "%s хочет играть чёрными" ::msgcat::mcset ru "Agree to play" "СоглаÑитьÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ" ::msgcat::mcset ru "Refuse to play" "ОтказатьÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ" ::msgcat::mcset ru "Show last move" "Показывать поÑледний ход" ::msgcat::mcset ru "Move: " "Ход: " ::msgcat::mcset ru "Propose a draw" "Предложить ничью" ::msgcat::mcset ru "Accept the draw proposal" "ПринÑть предложенную ничью" ::msgcat::mcset ru "Resign the game" "Сдать партию" ::msgcat::mcset ru "History" "ЗапиÑÑŒ партии" ::msgcat::mcset ru "Checkers..." "Шашки..." ::msgcat::mcset ru "White" "Белые" ::msgcat::mcset ru "Black" "Чёрные" ::msgcat::mcset ru "Opponent wins" "Оппонент выиграл" ::msgcat::mcset ru "You win" "Ð’Ñ‹ выиграли" ::msgcat::mcset ru "Opponent wins (You resigned)" \ "Оппонент выиграл (Ð’Ñ‹ ÑдалиÑÑŒ)" ::msgcat::mcset ru "You win (Opponent resigned)" \ "Ð’Ñ‹ выиграли (Оппонент ÑдалÑÑ)" ::msgcat::mcset ru "Draw (You accepted)" "ÐÐ¸Ñ‡ÑŒÑ (Ð’Ñ‹ принÑли)" ::msgcat::mcset ru "Draw (Opponent accepted)" "ÐÐ¸Ñ‡ÑŒÑ (Оппонент принÑл)" ::msgcat::mcset ru "Press button and make move if you want propose draw" \ "Ðажмите кнопку и Ñделайте ход, еÑли хотите предложить ничью" ::msgcat::mcset ru "Press button if you want accept the draw proposal" \ "Ðажмите кнопку, еÑли хотите принÑть предложенную ничью" ::msgcat::mcset ru "Press button if you want resign" \ "Ðажмите кнопку, еÑли хотите ÑдатьÑÑ" ::msgcat::mcset ru "\n\n Opponent proposes a draw\n\n" \ "\n\n Оппонент предлагает ничью\n\n" ::msgcat::mcset ru "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Оппонент отверг ход:\n %s\n\n" ::msgcat::mcset ru "Games" "Игры" ::msgcat::mcset ru "Straight checkers (English draughts)" \ "Ð§ÐµÐºÐµÑ€Ñ (английÑкие шашки)" ::msgcat::mcset ru "Russian checkers" "РуÑÑкие шашки" ::msgcat::mcset ru "Pool checkers" "Пул-чекерÑ" ::msgcat::mcset ru "Spanish checkers" "ИÑпанÑкие шашки" ::msgcat::mcset ru "Italian checkers" "ИтальÑнÑкие шашки" ::msgcat::mcset ru "Straight checkers" "ЧекерÑ" ::msgcat::mcset ru "Brazilian checkers" "БразильÑкие шашки" ::msgcat::mcset ru "Default game variant." "Вариант игры в шашки по умолчанию." ::msgcat::mcset ru "Flip board view when playing black (Russian, Spanish,\ Italian) or white (Straight, Pool, Brazilian) by default." \ "Разворачивать доÑку по умолчанию при игре чёрными (руÑÑкие,\ иÑпанÑкие, итальÑнÑкие шашки) или белыми (чекерÑ, пул-чекерÑ,\ бразильÑкие шашки)." ::msgcat::mcset ru "%s wants play %s." "%s хочет играть в %s" ::msgcat::mcset ru "%s with %s" "%s Ñ %s" ::msgcat::mcset ru "Sound to play after opponent's turn" \ "Звук, который проигрываетÑÑ Ð¿Ð¾Ñле хода оппонента" ::msgcat::mcset ru "Whether the Checkers plugin is loaded." \ "Загружено ли раÑширение Шашки." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/checkers/msgs/uk.msg000064400000000000000000000133011500237002100173760ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Checkers Tkabber plugin. # # Author: Artem Bondarenko # Author: Sergei Golovan ::msgcat::mcset uk "Plugins options." "Параметри плагінів." ::msgcat::mcset uk "Show last move by default." \ "Показувати оÑтанній хід за замовчуваннÑм." ::msgcat::mcset uk " (You)" " (Ви)" ::msgcat::mcset uk " (Opponent)" " (Опонент)" ::msgcat::mcset uk "Flip view" "Розгорнути дошку" ::msgcat::mcset uk "Checkers plugin options." "Параметри плагіна Шашки." ::msgcat::mcset uk "Checkers figures theme." "Зовнішній виглÑд шашок." ::msgcat::mcset uk "Show tooltips with short instructions." \ "Показувати Ñпливаючі підказки до елементів інтерфейÑу." ::msgcat::mcset uk "Allow illegal moves (useful for debugging)." \ "ДозволÑти неправильні ходи (викориÑтовуєтьÑÑ Ð¿Ñ€Ð¸ налагодженні)." ::msgcat::mcset uk "Accept opponent illegal moves (useful for debugging)." \ "Приймати неправильні ходи від опонента (викориÑтовуєтьÑÑ Ð¿Ñ€Ð¸\ налагодженні)." ::msgcat::mcset uk "Checkers Invitation" "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в шашки" ::msgcat::mcset uk "Sending checkers game invitation to %s (%s)" \ "ВідÑилаєтьÑÑ Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в шашки з %s (%s)" ::msgcat::mcset uk "I want play white" "Хочу грати білими" ::msgcat::mcset uk "I want play black" "Хочу грати чорними" ::msgcat::mcset uk "Cancel invitation" "СкаÑувати запрошеннÑ" ::msgcat::mcset uk "%s (%s) has refused checkers invitation: %s" \ "%s (%s) відмовивÑÑ Ð³Ñ€Ð°Ñ‚Ð¸ в шашки: %s" ::msgcat::mcset uk "Checkers Invitation from %s" \ "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в шашки з %s" ::msgcat::mcset uk "Checkers game invitation from %s (%s) is received." \ "Отримано Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в шашки з %s (%s)" ::msgcat::mcset uk "%s wants play white." " %s хоче грати білими" ::msgcat::mcset uk "%s wants play black." " %s хоче грати чорними" ::msgcat::mcset uk "Agree to play" "ПогодитиÑÑ Ð³Ñ€Ð°Ñ‚Ð¸" ::msgcat::mcset uk "Refuse to play" "ВідмовитиÑÑ Ð³Ñ€Ð°Ñ‚Ð¸" ::msgcat::mcset uk "Show last move" "Показувати оÑтанній хід" ::msgcat::mcset uk "Move: " "Хід: " ::msgcat::mcset uk "Propose a draw" "Запропонувати нічию" ::msgcat::mcset uk "Accept the draw proposal" "ПрийнÑти запропоновану нічию" ::msgcat::mcset uk "Resign the game" "Здати партію" ::msgcat::mcset uk "History" "Ð—Ð°Ð¿Ð¸Ñ Ð¿Ð°Ñ€Ñ‚Ñ–Ñ—" ::msgcat::mcset uk "Checkers..." "Шашки..." ::msgcat::mcset uk "White" "Білі" ::msgcat::mcset uk "Black" "Чорні" ::msgcat::mcset uk "Opponent wins" "Опонент виграв" ::msgcat::mcset uk "You win" "Ви виграли" ::msgcat::mcset uk "Opponent wins (You resigned)" "Опонент виграв (Ви здалиÑÑ)" ::msgcat::mcset uk "You win (Opponent resigned)" "Ви виграли (Опонент здавÑÑ)" ::msgcat::mcset uk "Draw (You accepted)" "ÐÑ–Ñ‡Ð¸Ñ (Ви прийнÑли)" ::msgcat::mcset uk "Draw (Opponent accepted)" "ÐÑ–Ñ‡Ð¸Ñ (Опонент прийнÑв)" ::msgcat::mcset uk "Press button and make move if you want propose draw" \ "ÐатиÑніть кнопку й зробіть хід, Ñкщо хочете запропонувати нічию" ::msgcat::mcset uk "Press button if you want accept the draw proposal" \ "ÐатиÑніть кнопку, Ñкщо хочете прийнÑти запропоновану нічию" ::msgcat::mcset uk "Press button if you want resign" \ "ÐатиÑніть кнопку, Ñкщо хочете здатиÑÑ" ::msgcat::mcset uk "\n\n Opponent proposes a draw\n\n" \ "\n\n Опонент пропонує нічию\n\n" ::msgcat::mcset uk "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Опонент відкинув хід:\n %s\n\n" ::msgcat::mcset uk "Games" "Ігри" ::msgcat::mcset uk "Straight checkers (English draughts)" \ "Ð§ÐµÐºÐµÑ€Ñ (англійÑькі шашки)" ::msgcat::mcset uk "Russian checkers" "РоÑійÑькі шашки" ::msgcat::mcset uk "Pool checkers" "Пул-чекерÑ" ::msgcat::mcset uk "Brazilian checkers" "БразильÑькі шашки" ::msgcat::mcset uk "Spanish checkers" "ІÑпанÑькі шашки" ::msgcat::mcset uk "Italian checkers" "ІталійÑькі шашки" ::msgcat::mcset uk "Straight checkers" "ЧекерÑ" ::msgcat::mcset uk "Default game variant." \ "Варіант гри в шашки за замовчуваннÑм." ::msgcat::mcset uk "%s wants play %s." " %s хоче грати в %s" ::msgcat::mcset uk "%s with %s" "%s з %s" ::msgcat::mcset uk "Sound to play after opponent's turn" \ "Звук, Ñкий буде програватиÑÑ Ð¿Ñ–ÑÐ»Ñ Ñ…Ð¾Ð´Ñƒ опонента" ::msgcat::mcset uk "Flip board view when playing black (Russian, Spanish,\ Italian) or white (Straight, Pool, Brazilian) by default." "Розвертати\ дошку за замовчуваннÑм при грі чорними (роÑійÑькі, Ñ–ÑпанÑькі, італійÑькі\ шашки) або білими (чекерÑ, пул-чекерÑ, бразильÑкі)." ::msgcat::mcset uk "Whether the Checkers plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð¨Ð°ÑˆÐºÐ¸." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/checkers/pixmaps000075500000000000000000000000001500237002100167025ustar00nobodynobodytkabber-plugins/checkers/pixmaps/checkers000075500000000000000000000000001500237002100204715ustar00nobodynobodytkabber-plugins/checkers/pixmaps/checkers/bf.gif000064400000000000000000000015651500237002100216350ustar00nobodynobodyGIF89a11ó sQ1sY1{U1{Y1kUBsYJ{YB„YB„aBŒaJŒiBÿÿÿ!ù ,11þÐ"€ ¦˜m„AöQã¦!Hn ’x&HLÕ•qݲdj~©•ÎË  …C¨ˆÌiŒCbátŸ€†•B.… 3=õ®BN Á7B+A'(„7«ža ˆy@\V§7—6¶°!~°2 ™(Š©H¥ºRƒš«99 / ’j§¸ͺbi8*ŸÃ¤8n…¨Î$/b8ž´ãÂ,0{¤Ú‰Î#ÉŸT{VXkA„ Bl¬:iΖ"üP“òð¶.Àäã@-™¸"þC$€ PäÁ "Þh6ÅŠ WÜ©Ååž©¶pTðγ5;$ˆf ¥½&q ¸pS?Žs|4:RÌÍMPX´(‚ ¬¡ ò€8ÁXœLy@Ù–f µ<2] ëjBN@ãΉ¡i8¡-(”E‚„ÎA˜¦Ð’÷%X?B‡¶ô—jg Ÿ:ÖÎ ;t°±4¹‹BÈž ¼½"@ŽduÌØ¹:,‡m« K»šndS‘F€‚pULWó6óÂ7ÿ¹¼‚õÅ5j8›*œ«à;I0ŽÜ‰‹»vw¯ËK=¸ž¹ýµIô¯¿¢g ’i¤sú<þ÷ÝtiìÕš@¥UÚ.¿ ÷H(&¤´_8çÁCöôI0 P·ŽÁ»m%t(éÕ¬‚¹ ðM€7 ßÀÑœ˜¢‚X;Ž%°\À7_£¾ð~=‰r•B\?IJ%÷}ß[û®À{Ef%‡ŸY*Aã{xgÔøÖV ¼±€K²%)ÐÓï!PÀià 2þÈ0qG%*„PFÖ…[|¾À1È@^[L8 –TОmú5@†Z&C Š$"A¼ü_X`‹B‡ÏèA€Ð !蕎w§ý¨a”t(à ºÖÄJ%˜‚Š „É”x`f ÐøÄ,¥p 'ô¦ËEéÛ”²% B¡c¤àB P‹-f¦¢.NáÊ ”ÐQL.˜P¬ Ž ¼Ý¹èoT˜õL1©f™e¼Å( hvjEiöØšk«2†`(jZQp%¨`Õx*s,£yÁwÊð¤y"›m€7'¸Q6î+€ªëÆ+ï¼ôÖkï½E;tkabber-plugins/checkers/pixmaps/checkers/bp.gif000064400000000000000000000017011500237002100216370ustar00nobodynobodyGIF89a11õ!  '''/0/00/777??@?@??@@@??@?@@@?FFFOPOOPPPOOPOPPPOWWW__`_`_`__`_`gggoopopppoopopppovvvÿÿÿ!ù!,11þÀpH,ȤrÉl:ŸÐ¨tJ­Z™MgÃÕT*W§Dþ|6štÖ ÉpÐ9MÿÚ!îáΩ vnq ‚’ƒ… ŒVq“”„©œžSq¤’]…† °p£pi¾¿¿Q{ ¢pstÐ_Ò ÖÂOp²¢qhÏvš‹  ÁÖOd*H5wuZhîÀ'p&)ˆÃaž³DÊKÐ „ 4Ùó`”Š-$ŠaaƒÖ@˜Ð @H&p*xfþ›D $€©Žå©p‚¨@ꤟ,üTÄPÝ›¾\-°¤‚’¼™a†ð‹¢ æ¦,ðà˃T\“ŒÙp@Ò„žíy\ˆ€è´\¨aÀ€¸H¸l$@òRíTØ LZ¸. &`X šŒzQi­e‡p ¸ µ’ç4§òڛટU̪á”:±ëkÅpÁéÔ¹Ãô; k$S}ÐÀ¶Ã­T*œy’ 4PMA²&Õý"E~ÊÀ– ¾¿{á…`¶+ê~Q§pJÐ.H‚^H9ÜgvÆ_$¸€P€$Xh•J[÷ÁÔÏupàÈ$p‚“TèGH‡Ü—‡û=XŠc €5HLCÖ(dÙ_©pö`$<@F9Aiý²âZ rÊ$ˆ‚´<±—5 ,¤~Ù= %ˆ2uBT:­—]r‘ð€”IB@hÉ_¸yÀÀ9PS¤ó€–› ù‡n ° Œd„ÉMéÄ”‘d¢m ¥T>jÅiLð…ÐÁÅ#ʨéÖ¤+k¨ñÖ$Må!€íwI¥Ì(+[ñ÷c›ºîzÄUln'ì±È&«ì²Ì6[D;tkabber-plugins/checkers/pixmaps/checkers/icondef.xml000064400000000000000000000016221500237002100227020ustar00nobodynobody Checkers 1.0 Checkers Theme. 2006-01-23 checkers/bf bf.gif checkers/bk bk.gif checkers/bp bp.gif checkers/wf wf.gif checkers/wk wk.gif checkers/wp wp.gif tkabber-plugins/checkers/pixmaps/checkers/wf.gif000064400000000000000000000014721500237002100216570ustar00nobodynobodyGIF89a11ó Ö¢{Þ®{ç®sç¶{ï¶sÖ¦„Þ®ŒÞ²„Þ¶Œç¶„羌÷¾„ÿÿÿ!ù ,11þ0œ3Р#‡À>r(Ê4IÀ!«p¤Þû™”…iœ'…ci¢*ë%“Ih¾D q RÇáÛ=9œ•–š(.‰DfÛ!}´Ø Ûf&4ó’ÅJJ Ño£¬w€]&_bYo1qz f(EG‹dk+oQy4 :-ŽŽ3_adl£^ŒhX¢mm4„‡KuXqh ›:¬ b©|:ž€v‘BД a«Ô> f’Ь Æ×JÁ|”R'd¥ÓÒeÔÖת,PH'ÝŽÀ°¹pãc°ñ!eBO @î:Ø G)9db²`‚ïÇ!( ßy:±Œ‹]þ{&ð›¶bä‘ƬÍA´¤â‰} áÙÙ8Ï4œFÐxö®§ ‡×nÅP§Ó Nh !­1Q`ŠZ5êÕ³ª¼šªŽåõ©IRƒJü7b*O«âP5ˆ®@»\§ÅÔ'2¡‘*í,5÷AKÅœC÷Ä ®hGmÃX "D%îeÉR@§lÙP\7âˆI]O)3FÙqàÒEzHÚÉ@„]̆ê=ùKegOU .Q°ŒR¥Ma «Dƒv‰N¯×Öʱmñ_êoBêaȽ{´c6e¶“u»»ºo`½\jIÂ.)¡3Ç:öÌÀP{9æ%øG'Ž™Þ}„mé°Àëpßúù–™_­„„ÑbŽÄVÝ cƒÝX°/ñ`±.N!xN…%ƒTA{Èd`/!wxä¤BI³d‘BÐC!‚ŒíÆ`3é•ÎjÕ Æã?’æ‰Ì©c–B«©G:4;ñÅ‘dÒèvY*£29ü…‡düT·"NíVMS¤‘ç#®œ·šx®(˜e–pDæÃèÄiÖ³ž`/ZÆ·°àVdÂ%äÝÕâIcƒÁ€@eâŽ%Ã|çæ›lÖ犵ݶ¦–Äe¦ˆêAï°I«ð2@;tkabber-plugins/checkers/pixmaps/checkers/wk.gif000064400000000000000000000017711500237002100216660ustar00nobodynobodyGIF89a11õ5&&&//0777@@?FFFPOPWWW`__gggopoopppooppouuu€€€ˆˆˆ˜˜˜ŸŸ Ÿ Ÿ ŸŸ¨¨¨¯¯°¯°¯°¯¯···¿¿À¿À¿¿ÀÀÀ¿¿À¿ÀÀÀ¿ÇÇÇÏÏÐÏÐÏÏÐÐÐÏÏÐÏÐÐÐÏ×××ßßàßàßßàààßßààßçççöõõÿÿÿ!ù5,11þÀšpH,ȤrÉl:ŸÐ¨tJ­Z™¦ÖlF›µNŸ«³E+s»Ûm¬#Ïf´Ú»n±Lî!«Ìÿ< ‚-),Šnp4“‚‚,*'&aV|4“•––˜˜&® S¢ ’’ ,[-& Á ® °Pp•|\iu ÅQ&|´ Ži^^-» ÓÕŸP|³“¢rãä,(® ýOd46Т/Ü %,xÒ5HpÙsŸiY“]ê('p¤@ùb$SYj9›;>Á“Dñj(`À¦H`ßpŒçŽ<ùÀ€÷MhÁp€2ÐÀŽrÎié` ðQW¯Mœ¬&–:¨u”¼"0z ˜8!¥n\ðÖMø5°ì¬'¢XkBl0ÞW}ª×#˜Ün¸X`›ä–{Ä«÷)éî¼ôÖkï½øæ[D;tkabber-plugins/checkers/pixmaps/checkers/wp.gif000064400000000000000000000016601500237002100216700ustar00nobodynobodyGIF89a11õ ‰‰‰———ŸŸ  ŸŸ  Ÿ§§§°°¯···¿¿À¿À¿¿ÀÀÀ¿¿À¿ÀÇÇÇÏÐÏÏÐÐÐÏÏÐÏÐÐÐÏ×××ßßàßàßßàààßàçççïðïïðððïïððïööõÿÿÿ!ù ,11þ@pH,ȤrÉl:ŸÐ¨tJ­Z™šlg“­T®ÎÍçÃùl³K÷ >Žß­ñÚ!í¡æ=®$ vm| ”ƒƒ†ŠŒV| ‘’•–„§«U|’’ t…† »S|°cµ^ Ê» Q{cÀ’edÆk^Ë ÉËPo¯’ÃÄsuu^ ÎáÐa}° péëì‹ñ¼ròf>bgÔ±›0a•e :AHu I‡1 bñѦ!C†…8uzøðA„ S1y#*™bÇø‰„˜r–¢S—Ø 0`Ìþ†l×0ìçoY*¼àZRLÆø¶h«°ïäªo)`€ §’=šð Õ…D:3ªõT‚ `ʉäç†@4èûÈ.íƒß(ž"t. ºG4 4€Î¾ ŠVL‰Ó! 4XRÔ’Y ‰"ôKÀ€í)¨-gÖ<èkÏ ùù{PZ™à–-7~Ý: @΂>I´¶í¶§-@³9ÉY„Ù!ÎëáqœtB ·‚ J*|üC A¢ œþY?Ú–@)J6xx@ ñªrOÉthúà‚H¢—b ÀD µõ€_­G‘˜XBIÖx Á„LPà¹ÏˆTTV87È„yyàÁ•4ÁÎQ»<`Ýuƒ½'€9|°ÁŒ8ÁPCßLv[ŒxU#ÆÌh ŽœôØßaâ˜@D  v²@i Xboard 1.0 Checkers Xboard Theme. 2006-01-23 checkers/bf bf.gif checkers/bk bk.gif checkers/bp bp.gif checkers/wf wf.gif checkers/wk wk.gif checkers/wp wp.gif tkabber-plugins/checkers/pixmaps/xboard/wf.gif000064400000000000000000000001331500237002100213400ustar00nobodynobodyGIF89a11ðÈÃeÿÿÿ!ù,112„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇòL×öçúÎ÷þ ‡Ä¢ñˆÜ;tkabber-plugins/checkers/pixmaps/xboard/wk.gif000064400000000000000000000004271500237002100213530ustar00nobodynobodyGIF89a11ñÿÿÌÿÿÿ!ù,11蔩Ëí£œ´Ú‹³†¡{¿IßH†ÌØ ¦ñ$È›ü–q0wwmËÈ ê| P( r†ÇcRWÄ5§ÏènÊ‹‰¤ØfuyíÖ´f€ý:ÌG4šâòÜzÀþR/Ø/ýW·'7WçWç4¨Àׇæ÷(ˆ÷Dx‡ˆ˜˜·˜Ðx ™ÚIyR8¢ É™å‰zØJ»iº–ªZÛ¤Ghy¹ËúzZ$l{[F)æä‹ ܬ -  m=a¤mVÑmmy.6ŽqÝu“sêµÒF£¤¡BHo’¶‚›·ïÿ0 À1;tkabber-plugins/checkers/pixmaps/xboard/wp.gif000064400000000000000000000003521500237002100213550ustar00nobodynobodyGIF89a11ñÿÿÌÿÿÿ!ù,11»”©Ëí£œ´Ú‹³†¡{¿IßH†ÌØ ¦ñ$È›ü–q0wwmËÈ ê| P( r†ÇcRWÄ5§ÏènÊ‹‰¤ØfuyíÖ´¦Ø u˜ÏÁoŠËFãÞÏ82½XÛÇx…~_Ò—ðØ"ˆ@XȤ§ˆrèÒèhÄX7IYy‰™©Éf©HV&Yè6f' 6iºDÊVWa”ª1{‹#v“3:ÖÒ‚šF¼¢’w¼éÅüöò,=M]m}Q;tkabber-plugins/checkers/proto000064400000000000000000000037271500237002100163770ustar00nobodynobodyRequest: 600 -- for all players 10 -- if on black side played Kasparov Known types: checkers:russian, checkers:pool, checkers:spanish, checkers:straight, checkers:italian Positive response: or simply ? Move: 'pos' attribute contain column-separated list of coordinates of piece, that moved from first to last one. Coordinate is a comma-separated list of integers >= 0. Jump move: Proposing draw: Accepting draw proposal: Resigning: Response: if move accepted, or error 'Not Acceptable' if other side think that this move illegal (to avoid evil hackers that write clients that can do few moves instead of one or can move King like Queen) tkabber-plugins/checkers/rules000075500000000000000000000000001500237002100163535ustar00nobodynobodytkabber-plugins/checkers/rules/brasilian.txt000064400000000000000000000073501500237002100211440ustar00nobodynobodyBrazilian Checkers Rules of Play 1. Brazilian checkers is played on the dark squares only of a standard checkerboard of 64 alternating dark and light squares, (eight rows, eight files) by two opponents having 12 checkers each of contrasting colors, nominally referred to as black and white. 2. The board is positioned squarely between the players and turned so that a dark square is at each player's near left side. Each player places his checkers on the dark squares of the three rows nearest him. The player with the darker checkers makes the first move of the game, and the players take turns thereafter, making one move at a time. 3. The object of the game is to prevent the opponent from being able to move when it is his turn to do so. This is accomplished either by capturing all of the opponent's checkers, or by blocking those that remain so that none of them can be moved. If neither player can accomplish this, the game is a draw. 4. Single checkers, known as men, move forward only, one square at a time in a diagonal direction, to an unoccupied square. Men capture by jumping over an opposing man on a diagonally adjacent square to the square immediately beyond, but may do so only if this square is unoccupied. Men may jump forward or backward, and may continue jumping as long as they encounter opposing checkers with unoccupied squares immediately beyond them. Men may never jump over checkers of the same color. 5. A man which reaches the far side of the board becomes a king. However, if it reaches the far side by means of a jump, and is able to jump backward away from the far side over another man or king, it must do so, and does not become a king. A man reaching the far side by jumping becomes a king only if its jump, or series of jumps, terminates there. When a man becomes a king the turn to move passes to the other player, who must crown the new king by placing a checker of the same color atop it. A player is not permitted to make his own move until he crowns his opponent's king. 6. Kings move forward or backward any number of squares on a diagonal line to an unoccupied square. Kings capture from any distance along a diagonal line by jumping, forward or backward, over an opposing man or king with at least one unoccupied square immediately beyond it. The capturing king then lands on any one of these unoccupied squares (except as noted in rule 7) and continues jumping, if possible, either on the same line, or by making a right angle turn onto another diagonal line. Kings may never jump over checkers of the same color. 7. Whenever a player is able to make a capture he must do so. When there is more than one way to jump, a player must choose a sequence of jumps which results in the capture of the greatest possible number of opposing units, men and kings each counting as one unit. A "huff" of a checker for failure to jump properly is not permitted. The incorrect move must be retracted, and a correct move must be made. If possible, the correct move must be made with the man or king originally moved incorrectly. 8. A man or king may not jump over the same opposing man or king more than once. 9. Captured checkers are not removed from the board until all jumps made on the move are completed, and the hand is removed from the capturing man or king. (It is only in rare instances that rules 8 or 9 affect the play of a game. They can have the effect of reducing the number of captures possible on a move. In most of these cases a king is the capturing piece. On very rare occasions these rules, either separately or in combination, will result in a king being forced to terminate a series of jumps on a square from which it will then be captured by an opposing man or king which itself would have been captured were it not for these rules.) tkabber-plugins/checkers/rules/italian.txt000064400000000000000000000064011500237002100206150ustar00nobodynobodyItalian Checkers Rules of Play 1. Italian checkers is played on the dark squares only of a standard checkerboard of 64 alternating dark and light squares, (eight rows, eight files) by two opponents having 12 checkers each of contrasting colors, nominally referred to as black and white. 2. The board is positioned squarely between the players and turned so that a dark square is at each player's near right side. Each player places his checkers on the dark squares of the three rows nearest him. The player with the lighter checkers makes the first move of the game, and the players take turns thereafter, making one move at a time. 3. The object of the game is to prevent the opponent from being able to move when it is his turn to do so. This is accomplished either by capturing all of the opponent's checkers, or by blocking those that remain so that none of them can be moved. If neither player can accomplish this, the game is a draw. 4. Single checkers, known as men, move forward only, one square at a time in a diagonal direction, to an unoccupied square. Men capture by jumping over an opposing man on a diagonally adjacent square to the square immediately beyond, but may do so only if this square is unoccupied. Men may jump forward only, and may continue jumping as long as they encounter opposing checkers with unoccupied squares immediately beyond them. Men may never jump over checkers of the same color. Men may never jump over kings. 5. A man which reaches the far side of the board, whether by means of a jump or a simple move, becomes a king, and the move terminates. The opponent must then crown the new king by placing a checker of the same color atop it. A player is not permitted to make his own move until he crowns his opponent's king. 6. Kings move forward or backward, one square at a time in a diagonal direction to an unoccupied square. Kings capture by jumping, forward or backward, over an opposing man or king on a diagonally adjacent square to the square immediately beyond, but may do so only if this square is unoccupied. Kings may continue jumping as long as they encounter opposing checkers with unoccupied squares immediately beyond them. Kings may never jump over checkers of the same color. They may never jump over the same opposing man or king more than once. 7. Whenever a player is able to make a capture he must do so. a) If there is more than one way to jump, a player must choose a sequence of jumps which results in the capture of the greatest possible number of opposing units, men and kings each counting as one unit. b) If there is more than one way to capture the greatest possible number of opposing units, the capture must be made with a king, if possible, rather than with a single man. c) If there is more than one way for the greatest possible number of units to be captured by a king, the most kings must be captured. d) If there is more than one way for the greatest and most powerful forces to be captured, a capture which results in a king being captured earliest in the sequence of jumps must be chosen. A "huff" of a checker for failure to jump properly is not permitted. The incorrect move must be retracted, and a correct move must be made. If possible, the correct move must be made with the man or king originally moved incorrectly. tkabber-plugins/checkers/rules/pool.txt000064400000000000000000000126161500237002100201520ustar00nobodynobodyPool Checkers Rules of Play 1. Pool checkers, also known as Spanish pool checkers, is played on the dark squares only of a standard checkerboard of 64 alternating dark and light squares, (eight rows, eight files) by two opponents having 12 checkers each of contrasting colors, nominally referred to as black and white. 2. The board is positioned squarely between the players and turned so that a dark square is at each player's near left side. Each player places his checkers on the dark squares of the three rows nearest him. The player with the darker checkers makes the first move of the game, and the players take turns thereafter, making one move at a time. 3. The object of the game is to prevent the opponent from being able to move when it is his turn to do so. This is accomplished either by capturing all of the opponent's checkers, or by blocking those that remain so that none of them can be moved. If neither player can accomplish this, the game is a draw. 4. Single checkers, known as men, move forward only, one square at a time in a diagonal direction, to an unoccupied square. Men capture by jumping over an opposing man on a diagonally adjacent square to the square immediately beyond, but may do so only if this square is unoccupied. Men may jump forward or backward, and may continue jumping as long as they encounter opposing checkers with unoccupied squares immediately beyond them. Men may never jump over checkers of the same color. 5. A man which reaches the far side of the board becomes a king. However, if it reaches the far side by means of a jump, and is able to jump backward away from the far side over another man or king, it must do so, and does not become a king. A man reaching the far side by jumping becomes a king only if its jump, or series of jumps, terminates there. When a man becomes a king the turn to move passes to the other player, who must crown the new king by placing a checker of the same color atop it. A player is not permitted to make his own move until he crowns his opponent's king. 6. Kings move forward or backward any number of squares on a diagonal line to an unoccupied square. Kings capture from any distance along a diagonal line by jumping, forward or backward, over an opposing man or king with at least one unoccupied square immediately beyond it. The capturing king then lands on any one of these unoccupied squares (except as noted in rule 7) and continues jumping, if possible, either on the same line, or by making a right angle turn onto another diagonal line. Kings may never jump over checkers of the same color. 7. Whenever a player is able to make a capture he must do so. When there is more than one way to jump, a player may choose any way he wishes, not necessarily the one which results in the capture of the greatest number of opposing units. When a king jumps over an opposing man or king with more than one unoccupied square immediately beyond it, it must land on a square from which it is possible to continue jumping, if there is such a square. If there is more than one such square, any may be chosen. However, once a player chooses a sequence of captures, he must make all the captures possible in that sequence. He may not leave one or more checkers uncaptured that he could capture simply by continuing to jump. A "huff" of a checker for failure to jump properly is not permitted as it was in the past. The incorrect move must be retracted, and a correct move must be made. If possible, the correct move must be made with the man or king originally moved incorrectly. 8. A man or king may not jump over the same opposing man or king more than once. 9. Captured checkers are not removed from the board until all jumps made on the move are completed, and the hand is removed from the capturing man or king. (It is only in rare instances that rules 8 or 9 affect the play of a game. They can have the effect of reducing the number of captures possible on a move. In most of these cases a king is the capturing piece. On very rare occasions these rules, either separately or in combination, will result in a king being forced to terminate a series of jumps on a square from which it will then be captured by an opposing man or king which itself would have been captured were it not for these rules.) 10. Whenever a situation arises in which one player has three kings and the other one king, no other checkers remaining on the board, a count is begun of the moves made by the lone king. If the lone king is able to make 13 moves the game is a draw, even if the next move by the opponent would be the capture of the lone king. (In general, a win is possible only if the side with three kings has possession of the diagonal line running from the lower left corner to the upper right corner.) 11. Time limits for play may be based on a fixed amount of time for each move, with less time allowed for situations in which there is one, and only one, capturing move possible, or on a fixed amount of time for a given number of moves, without regard to how much of this time is used on any one move. When the latter method is used, and the given number of moves has been made by each player, with neither having used up the allotted time, an additional allotment of time and moves is given to each. This continues until the conclusion of the game. Unused time is retained when a new allotment is given. A player loses a game if his time expires before he has completed the required number of moves. tkabber-plugins/checkers/rules/russian.txt000064400000000000000000000120171500237002100206600ustar00nobodynobodyRussian Checkers Rules of Play 1. Russian checkers is played on the dark squares only of a standard checkerboard of 64 alternating dark and light squares, (eight rows, eight files) by two opponents having 12 checkers each of contrasting colors, nominally referred to as black and white. 2. The board is positioned squarely between the players and turned so that a dark square is at each player's near left side. Each player places his checkers on the dark squares of the three rows nearest him. The player with the lighter checkers makes the first move of the game, and the players take turns thereafter, making one move at a time. 3. The object of the game is to prevent the opponent from being able to move when it is his turn to do so. This is accomplished either by capturing all of the opponent's checkers, or by blocking those that remain so that none of them can be moved. If neither player can accomplish this, the game is a draw. 4. Single checkers, known as men, move forward only, one square at a time in a diagonal direction, to an unoccupied square. Men capture by jumping over an opposing man on a diagonally adjacent square to the square immediately beyond, but may do so only if this square is unoccupied. Men may jump forward or backward, and may continue jumping as long as they encounter opposing checkers with unoccupied squares immediately beyond them. Men may never jump over checkers of the same color. 5. A man which reaches the far side of the board becomes a king. If it reaches the far side by means of a jump, it continues jumping as a king on the same move, if possible, and remains a king at the end of the jumping sequence. When a man becomes a king the turn to move passes to the other player, who must crown the new king by placing a checker of the same color atop it. A player is not permitted to make his own move until he crowns his opponent's king. 6. Kings move forward or backward any number of squares on a diagonal line to an unoccupied square. Kings capture from any distance along a diagonal line by jumping, forward or backward, over an opposing man or king with at least one unoccupied square immediately beyond it. The capturing king then lands on any one of these unoccupied squares (except as noted in rule 7) and continues jumping, if possible, either on the same line, or by making a right angle turn onto another diagonal line. Kings may never jump over checkers of the same color. 7. Whenever a player is able to make a capture he must do so. When there is more than one way to jump, a player may choose any way he wishes, not necessarily the one which results in the capture of the greatest number of opposing units. When a king jumps over an opposing man or king with more than one unoccupied square immediately beyond it, it must land on a square from which it is possible to continue jumping, if there is such a square. If there is more than one such square, any may be chosen. However, once a player chooses a sequence of captures, he must make all the captures possible in that sequence. He may not leave one or more checkers uncaptured that he could capture simply by continuing to jump. A "huff" of a checker for failure to jump properly is not permitted. The incorrect move must be retracted, and a correct move must be made. If possible, the correct move must be made with the man or king originally moved incorrectly. 8. A man or king may not jump over the same opposing man or king more than once. 9. Captured checkers are not removed from the board until all jumps made on the move are completed, and the hand is removed from the capturing man or king. (It is only in rare instances that rules 8 or 9 affect the play of a game. They can have the effect of reducing the number of captures possible on a move. In most of these cases a king is the capturing piece. On very rare occasions these rules, either separately or in combination, will result in a king being forced to terminate a series of jumps on a square from which it will then be captured by an opposing man or king which itself would have been captured were it not for these rules.) 10. Whenever a situation arises in which one player has three kings and the other one king, no other checkers remaining on the board, a count is begun of the moves made by the stronger side. If the lone king is not captured by the end of the fifteenth move by the stronger side, the game is a draw. (In general, a win is possible only if the side with three kings has possession of the diagonal line running from the lower left corner to the upper right corner.) 11. Time limits for play are based on a fixed amount of time for a given number of moves, without regard to how much of this time is used on any one move. When the given number of moves has been made by each player, with neither having used up the allotted time, an additional allotment of time and moves is given to each. This continues until the conclusion of the game. Unused time is retained when a new allotment is given. A player loses a game if his time expires before he has completed the required number of moves. tkabber-plugins/checkers/rules/spanish.txt000064400000000000000000000066121500237002100206450ustar00nobodynobodySpanish Checkers Rules of Play 1. Spanish checkers is played on the dark squares only of a standard checkerboard of 64 alternating dark and light squares, (eight rows, eight files) by two opponents having 12 checkers each of contrasting colors, nominally referred to as black and white. 2. The board is positioned squarely between the players and turned so that a dark square is at each player's near right side. Each player places his checkers on the dark squares of the three rows nearest him. The player with the lighter checkers makes the first move of the game, and the players take turns thereafter, making one move at a time. 3. The object of the game is to prevent the opponent from being able to move when it is his turn to do so. This is accomplished either by capturing all of the opponent's checkers, or by blocking those that remain so that none of them can be moved. If neither player can accomplish this, the game is a draw. 4. Single checkers, known as men, move forward only, one square at a time in a diagonal direction, to an unoccupied square. Men capture by jumping over an opposing man on a diagonally adjacent square to the square immediately beyond, but may do so only if this square is unoccupied. Men may jump forward only, and may continue jumping as long as they encounter opposing checkers with unoccupied squares immediately beyond them. Men may never jump over checkers of the same color. 5. A man which reaches the far side of the board, whether by means of a jump or a simple move, becomes a king, and the move terminates. The opponent must then crown the new king by placing a checker of the same color atop it. A player is not permitted to make his own move until he crowns his opponent's king. 6. Kings move forward or backward any number of squares on a diagonal line to an unoccupied square. Kings capture from any distance along a diagonal line by jumping, forward or backward, over an opposing man or king with at least one unoccupied square immediately beyond it. The capturing king then lands on any one of these unoccupied squares (except as noted in rule 7) and continues jumping, if possible, either on the same line, or by making a right angle turn ontoanother diagonal line. Kings may never jump over checkers of the same color. 7. Whenever a player is able to make a capture he must do so. When there is more than one way to jump, a player must choose a sequence of jumps which results in the capture of the greatest possible number of opposing units, men and kings each counting as one unit. A "huff" of a checker for failure to jump properly is not permitted. The incorrect move must be retracted, and a correct move must be made. If possible, the correct move must be made with the man or king originally moved incorrectly. 8. A king may not jump over the same opposing man or king more than once. 9. Captured checkers are not removed from the board until all jumps made on the move are completed, and the hand is removed from the capturing man or king. (It is only in rare instances that rules 8 or 9 affect the play of a game. They can have the effect of reducing the number of captures a king can make. On very rare occasions these rules, either separately or in combination, will result in a king being forced to terminate a series of jumps on a square from which it will then be captured by an opposing man or king which itself would have been captured were it not for these rules.) tkabber-plugins/checkers/rules/straight.txt000064400000000000000000000100501500237002100210140ustar00nobodynobodyStraight Checkers or English Draughts Rules of Play 1. Straight checkers, also known as English draughts, is played on the dark squares only of a standard checkerboard of 64 alternating dark and light squares, (eight rows, eight files) by two opponents having 12 checkers each of contrasting colors, nominally referred to as black andwhite. (Serious checker players generally use red and white checkers, and green and yellow checkerboards. These colors have been designated as official by the American Checker Federation. In any case, colors of the checkers and the board should be different in order to provide good contrast, and especially to avoid such combinations as black checkers on black squares.) 2. The board is positioned squarely between the players and turned so that a dark square is at each player's near left side. Each player places his checkers on the dark squares of the three rows nearest him. The player with the darker checkers makes the first move of the game, andthe players take turns thereafter, making one move at a time. 3. The object of the game is to prevent the opponent from being able to move when it is his turn to do so. This is accomplished either by capturing all of the opponent's checkers, or by blocking those that remain so that none of them can be moved. If neither player can accomplish this, the game is a draw. 4. Single checkers, known as men, move forward only, one square at a time in a diagonal direction, to an unoccupied square. Men capture by jumping over an opposing man on a diagonally adjacent square to the square immediately beyond, but may do so only if this square is unoccupied. Men may jump forward only, and may continue jumping as long as they encounter opposing checkers with unoccupied squares immediately beyond them. Men may never jump over checkers of the same color. 5. A man which reaches the far side of the board, whether by means of a jump or a simple move, becomes a king, and the move terminates. The opponent must then crown the new king by placing a checker of the same color atop it. A player is not permitted to make his own move until he crowns his opponent's king. 6. Kings move forward or backward, one square at a time in a diagonal direction to an unoccupied square. Kings capture by jumping, forward or backward, over an opposing man or king on a diagonally adjacent square to the square immediately beyond, but may do so only if this square is unoccupied. Kings may continue jumping as long as they encounter opposing checkers with unoccupied squares immediately beyond them. Kings may never jump over checkers of the same color. They may never jump over the same opposing man or king more than once. 7. Whenever a player is able to make a capture he must do so. When there is more than one way to jump, a player may choose any way he wishes, not necessarily the one which results in the capture of the greatest number of opposing units. However, once a player chooses asequence of captures, he must make all the captures possible in that sequence. He may not leave one or more checkers uncaptured that he could capture simply by continuing to jump. A "huff" of a checker for failure to jump properly is not permitted as it was in the past. Theincorrect move must be retracted, and a correct move must be made. If possible, the correct move must be made with the man or king originally moved incorrectly. 8. Time limits for play may be based on a fixed amount of time for each move, with less time allowed for situations in which there is one, and only one, capturing move possible, or on a fixed amount of time for a given number of moves, without regard to how much of this time is used on any one move. When the latter method is used, and the given number of moves has been made by each player, with neither having used up the allotted time, an additional allotment of time and moves is given to each. This continues until the conclusion of the game. Unused time is retained when a new allotment is given. A player loses a game if his time expires before he has completed the required number of moves. tkabber-plugins/chess000075500000000000000000000000001500237002100145375ustar00nobodynobodytkabber-plugins/chess/chess.tcl000064400000000000000000001677471500237002100164550ustar00nobodynobody# chess.tcl -- # # This file implements Chess game plugin for the Tkabber XMPP client. package require msgcat namespace eval chess { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered chess]} { ::plugins::register chess \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Chess\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable square_size [expr {48*$::icons_scale}] variable line_width $::icons_scale variable piece_name variable prom_name variable prom_rev array set piece_name [list \ wk [::msgcat::mc "K"] \ wq [::msgcat::mc "Q"] \ wr [::msgcat::mc "R"] \ wb [::msgcat::mc "B"] \ wn [::msgcat::mc "N"] \ wp {} \ bk [::msgcat::mc "K"] \ bq [::msgcat::mc "Q"] \ br [::msgcat::mc "R"] \ bb [::msgcat::mc "B"] \ bn [::msgcat::mc "N"] \ bp {}] array set prom_name [list q queen r rook b bishop n knight] array set prom_rev [list queen q rook r bishop b knight n] variable themes variable dirs dirs \ [glob -nocomplain -directory [file join [file dirname [info script]] \ pixmaps] *] variable dir foreach dir $dirs { pixmaps::load_theme_name [namespace current]::themes $dir } variable values {} variable theme foreach theme [lsort [array names themes]] { lappend values $theme $theme } variable options custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup Chess [::msgcat::mc "Chess plugin options."] \ -group Plugins custom::defvar options(theme) Classic \ [::msgcat::mc "Chess figures theme."] -group Chess \ -type options -values $values \ -command [namespace current]::load_stored_theme custom::defvar options(flip_black_view) 1 \ [::msgcat::mc "Flip board view when playing black by default."] \ -type boolean -group Chess custom::defvar options(show_last_move) 0 \ [::msgcat::mc "Show last move by default."] \ -type boolean -group Chess custom::defvar options(always_queen) 0 \ [::msgcat::mc "Promote pawns always as queens."] \ -type boolean -group Chess custom::defvar options(show_tooltips) 1 \ [::msgcat::mc "Show tooltips with short instructions."] \ -type boolean -group Chess \ -command [list [namespace current]::set_tooltips] custom::defvar options(sound) "" \ [::msgcat::mc "Sound to play after opponent's turn"] \ -type file -group Chess custom::defvar options(allow_illegal) 0 \ [::msgcat::mc "Allow illegal moves (useful for debugging)."] \ -type boolean -group Chess custom::defvar options(accept_illegal) 0 \ [::msgcat::mc "Accept opponent illegal moves (useful for\ debugging)."] \ -type boolean -group Chess } proc chess::load {} { hook::add roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48 hook::add chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48 hook::add roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48 hook::add games_board_create_hook [namespace current]::iq_create hook::add games_board_turn_hook [namespace current]::iq_turn ::xmpp::iq::register set create games:board \ [namespace parent]::iq_games_board_create ::xmpp::iq::register set turn games:board \ [namespace parent]::iq_games_board_turn load_stored_theme calc_moves } proc chess::unload {} { hook::remove roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48 hook::remove chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48 hook::remove roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48 hook::remove games_board_create_hook [namespace current]::iq_create hook::remove games_board_turn_hook [namespace current]::iq_turn if {[hook::is_empty games_board_create_hook]} { ::xmpp::iq::unregister set create games:board rename [namespace parent]::iq_games_board_create "" } if {[hook::is_empty games_board_turn_hook]} { ::xmpp::iq::unregister set turn games:board rename [namespace parent]::iq_games_board_turn "" } foreach var [info vars [namespace current]::*] { upvar #0 $var flags if {[info exists flags(window)]} { destroy_win $flags(window) } } foreach var [info vars [namespace current]::*] { if {$var ne "[namespace current]::options"} { unset $var } } foreach img [image names] { if {[string first chess/ $img] == 0} { image delete $img } } } proc chess::load_stored_theme {args} { variable options variable themes pixmaps::load_dir $themes($options(theme)) } proc chess::get_nick {xlib jid type} { if {[catch {chat::get_nick $xlib $jid $type} nick]} { return [chat::get_nick $jid $type] } else { return $nick } } proc chess::invite_dialog {xlib jid} { set w .chess_invite if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Chess Invitation"] \ -modal none -anchor e -default 0 set wf [$w getframe] Message $wf.message -aspect 50000 \ -text [::msgcat::mc "Sending chess game invitation to %s (%s)" \ [get_nick $xlib $jid chat] \ $jid] pack $wf.message -pady 2m $w add -text [::msgcat::mc "I want play white"] \ -command [list [namespace current]::invite $xlib $jid white] $w add -text [::msgcat::mc "I want play black"] \ -command [list [namespace current]::invite $xlib $jid black] $w add -text [::msgcat::mc "Cancel invitation"] \ -command [list destroy $w] $w draw } proc chess::invite {xlib jid color} { destroy .chess_invite set id chess[rand 1000000000] # FIX #set rjid [get_jid_of_user $jid] ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create create \ -xmlns games:board \ -attrs [list type chess \ id $id \ color $color]] \ -to $jid \ -command [list [namespace current]::invite_res $xlib $jid $id $color] } proc chess::invite_res {xlib jid id color status xml} { if {![string equal $status ok]} { after idle [list NonmodalMessageDlg .chess_invite_error \ -aspect 50000 -icon error \ -message [::msgcat::mc "%s (%s) has refused chess invitation: %s" \ [get_nick $xlib $jid chat] \ $jid [error_to_string $xml]]] return "" } start_play $xlib $jid $id $color } proc chess::invited_dialog {xlib jid iqid id color} { set w .chess_invited if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Chess Invitation from %s" $jid] \ -modal none -anchor e -default 0 set wf [$w getframe] bind $wf [namespace code [list invited_res $w $xlib $jid \ $iqid $id $color 0]] set nick [get_nick $xlib $jid chat] set message1 \ [::msgcat::mc "Chess game invitation from %s (%s) is received." \ $nick $jid] switch -- $color { white { set message2 [::msgcat::mc "%s wants play white." $nick] } black { set message2 [::msgcat::mc "%s wants play black." $nick] } default { return [list error modify bad-request] } } Message $wf.message1 -aspect 50000 -text $message1 Message $wf.message2 -aspect 50000 -text $message2 pack $wf.message1 -pady 1m pack $wf.message2 -pady 1m $w add -text [::msgcat::mc "Agree to play"] \ -command [namespace code [list invited_res $w $xlib $jid \ $iqid $id $color 1]] $w add -text [::msgcat::mc "Refuse to play"] \ -command [namespace code [list invited_res $w $xlib $jid \ $iqid $id $color 0]] $w draw return } proc chess::invited_res {w xlib jid iqid id color res} { catch { set wf [$w getframe] bind $wf {} destroy $w } if {$res} { switch -- $color { white { start_play $xlib $jid $id black } black { start_play $xlib $jid $id white } default { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify bad-request] \ -to $jid \ -id $iqid } } ::xmpp::sendIQ $xlib result \ -query [::xmpp::xml::create create \ -xmlns games:board \ -attrs [list type chess \ id $id]] \ -to $jid \ -id $iqid } else { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify not-acceptable] \ -to $jid \ -id $iqid } return } proc chess::start_play {xlib jid id color} { set gid [make_gid $jid $id] variable $gid variable options upvar 0 $gid flags set flags(window) [win_id chess $gid] set flags(xlib) $xlib set flags(opponent) $jid set flags(id) $id set flags(flip) 0 set flags(our_color) $color trace add variable [namespace current]::${gid}(position,turn) write \ [list [namespace current]::set_label_move $gid] make_default_position $gid open $gid } proc chess::set_label_move {gid args} { variable $gid upvar 0 $gid flags switch -- $flags(position,turn) { white { set flags(move_label) [::msgcat::mc "White"] set move 1 } black { set flags(move_label) [::msgcat::mc "Black"] set move 1 } default { set move 0 } } if {$move && [is_my_move $gid]} { append flags(move_label) [::msgcat::mc " (You)"] } else { append flags(move_label) [::msgcat::mc " (Opponent)"] } } proc chess::make_default_position {gid} { variable $gid upvar 0 $gid flags for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { set flags(position,$c,$r) "" } } for {set c 0} {$c < 8} {incr c} { set flags(position,$c,1) wp set flags(position,$c,6) bp } set c 0 foreach f {r n b q k b n r} { set flags(position,$c,0) w$f set flags(position,$c,7) b$f incr c } set flags(position,wk,c) 4 set flags(position,wk,r) 0 set flags(position,bk,c) 4 set flags(position,bk,r) 7 set flags(position,wk,kcastling) 1 set flags(position,wk,qcastling) 1 set flags(position,bk,kcastling) 1 set flags(position,bk,qcastling) 1 set flags(position,enpassant) {} set flags(position,turn) white catch {unset flags(position,last_move)} set flags(position,draw) 0 set flags(position,halfmove) 0 set flags(position,history) {} set flags(position,repetitions) [list [code_position $gid] 1] } proc chess::save_position {gid} { variable $gid upvar 0 $gid flags set flags(saved_position) [array get flags position,*] } proc chess::restore_position {gid} { variable $gid upvar 0 $gid flags array set flags $flags(saved_position) draw_position $gid unhighlight_legal_moves $gid update_controls $gid find_legal_moves $gid $flags(position,turn) } proc chess::code_position {gid} { variable $gid upvar 0 $gid flags set code "" for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { switch -- $flags(position,$c,$r) { wk {append code K} wq {append code Q} wr {append code R} wb {append code B} wn {append code N} wp {append code P} bk {append code k} bq {append code q} br {append code r} bb {append code b} bn {append code n} bp {append code p} default {append code .} } } } append code $flags(position,wk,kcastling) append code $flags(position,wk,qcastling) append code $flags(position,bk,kcastling) append code $flags(position,bk,qcastling) if {[llength $flags(position,enpassant)] > 0} { lassign $flags(position,enpassant) c r set cp1 [expr {$c + 1}] set cm1 [expr {$c - 1}] if {$r == 2} { if {($cp1 < 8 && $flags(position,$cp1,3) == "bp") || \ ($cm1 >= 0 && $flags(position,$cm1,3) == "bp")} { append code $c$r } } elseif {$r == 5} { if {($cp1 < 8 && $flags(position,$cp1,4) == "wp") || \ ($cm1 >= 0 && $flags(position,$cm1,4) == "wp")} { append code $c$r } } } return $code } proc chess::make_gid {jid id} { jid_to_tag [concat $jid $id] } proc chess::turn_recv {gid xmlList} { variable options variable prom_rev variable $gid upvar 0 $gid flags set move 0 set draw 0 foreach xml $xmlList { ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- $tag { move { set pos [::xmpp::xml::getAttr $attrs pos] set poss [split $pos ";"] if {[llength $poss] == 2} { set pos1 [split [lindex $poss 0] ,] set pos2 [split [lindex $poss 1] ,] if {[llength $pos1] == 2 && [llength $pos2] == 2} { set cf [lindex $pos1 0] set rf [lindex $pos1 1] set ct [lindex $pos2 0] set rt [lindex $pos2 1] set prom "" foreach subel $subels { ::xmpp::xml::split $subel \ stag sxmlns sattrs scdata ssubels if {$stag == "promotion"} { if {[info exists prom_rev($scdata)]} { set prom $prom_rev($scdata) } } } set move 1 if {$options(sound) != "" && ![::sound::is_mute]} { ::sound::play $options(sound) } } } } resign { end_game $gid 1 [::msgcat::mc "You win (Opponent resigned)"] update_controls $gid draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type chess \ id $flags(id)]]] } accept { if {$flags(position,draw)} { end_game $gid 0.5 [::msgcat::mc "Draw (Opponent accepted)"] update_controls $gid draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type chess \ id $flags(id)]]] } else { return [list error modify not-acceptable] } } draw { set draw 1 } } } if {$move && [do_move $gid $cf $rf $ct $rt $prom $draw]} { update_controls $gid $draw draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type chess \ id $flags(id)]]] } else { return [list error modify not-acceptable] } } ############################################################################### proc chess::calc_moves {} { variable moves for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { for {set moves(d1,$c,$r) {}; \ set x [expr {$c+1}]; set y [expr {$r+1}]} \ {($x < 8) && ($y < 8)} {incr x; incr y} { lappend moves(d1,$c,$r) $x $y } for {set moves(d2,$c,$r) {}; \ set x [expr {$c-1}]; set y [expr {$r+1}]} \ {($x >= 0) && ($y < 8)} {incr x -1; incr y} { lappend moves(d2,$c,$r) $x $y } for {set moves(d3,$c,$r) {}; \ set x [expr {$c-1}]; set y [expr {$r-1}]} \ {($x >= 0) && ($y >= 0)} {incr x -1; incr y -1} { lappend moves(d3,$c,$r) $x $y } for {set moves(d4,$c,$r) {}; \ set x [expr {$c+1}]; set y [expr {$r-1}]} \ {($x < 8) && ($y >= 0)} {incr x; incr y -1} { lappend moves(d4,$c,$r) $x $y } for {set moves(h1,$c,$r) {}; set x [expr {$c+1}]} \ {$x < 8} {incr x} { lappend moves(h1,$c,$r) $x $r } for {set moves(h2,$c,$r) {}; set x [expr {$c-1}]} \ {$x >= 0} {incr x -1} { lappend moves(h2,$c,$r) $x $r } for {set moves(v1,$c,$r) {}; set y [expr {$r+1}]} \ {$y < 8} {incr y} { lappend moves(v1,$c,$r) $c $y } for {set moves(v2,$c,$r) {}; set y [expr {$r-1}]} \ {$y >= 0} {incr y -1} { lappend moves(v2,$c,$r) $c $y } set moves(n,$c,$r) {} foreach {dx dy} {1 2 -1 2 -2 1 -2 -1 -1 -2 1 -2 2 -1 2 1} { set x [expr {$c + $dx}] set y [expr {$r + $dy}] if {($x >= 0) && ($x < 8) && ($y >= 0) && ($y < 8)} { lappend moves(n,$c,$r) $x $y } } set moves(wpt,$c,$r) {} if {$r <= 6} { if {$c <= 6} { lappend moves(wpt,$c,$r) [expr {$c + 1}] [expr {$r + 1}] } if {$c >= 1} { lappend moves(wpt,$c,$r) [expr {$c - 1}] [expr {$r + 1}] } } set moves(bpt,$c,$r) {} if {$r >= 1} { if {$c <= 6} { lappend moves(bpt,$c,$r) [expr {$c + 1}] [expr {$r - 1}] } if {$c >= 1} { lappend moves(bpt,$c,$r) [expr {$c - 1}] [expr {$r - 1}] } } set moves(k,$c,$r) {} foreach {dx dy} {0 1 -1 1 -1 0 -1 -1 0 -1 1 -1 1 0 1 1} { set x [expr {$c + $dx}] set y [expr {$r + $dy}] if {($x >= 0) && ($x < 8) && ($y >= 0) && ($y < 8)} { lappend moves(k,$c,$r) $x $y } } } } } proc chess::center {c r} { variable square_size variable line_width set r [expr {7 - $r}] list [expr {$line_width + ($square_size * 0.5) + \ (($square_size + $line_width) * $c)}] \ [expr {$line_width + ($square_size * 0.5) + \ (($square_size + $line_width) * $r)}] } proc chess::close {gid} { variable $gid upvar 0 $gid flags array unset flags } proc chess::exists {gid} { variable $gid info exists $gid } proc chess::button_update_relief {b flag} { set rstate [expr {$flag? {pressed} : {!$pressed}}] if {[catch {$b state $rstate}]} { set relief [expr {$flag? "sunken" : "raised"}] $b configure -relief $relief } } proc chess::open {gid} { variable options variable square_size variable line_width variable piece_name variable $gid upvar 0 $gid flags set jid $flags(opponent) set w $flags(window) if {[winfo exists $w]} { raise_win $w return } set title [::msgcat::mc "Chess with %s" [get_nick $flags(xlib) $jid chat]] add_win $w -title $title \ -tabtitle $title \ -class Chess \ -raise 1 set board [canvas $w.board \ -borderwidth 0 \ -highlightthickness 0 \ -width [expr {8 * $square_size + 9 * $line_width}] \ -height [expr {8 * $square_size + 9 * $line_width}]] pack $board -side left -anchor w -padx 2m set flags(board) $board set flags(show_last_move) $options(show_last_move) set slm [Button $w.show_last_move -text [::msgcat::mc "Show last move"] \ -command [list [namespace current]::toggle_show_last_move \ $gid]] button_update_relief $slm $flags(show_last_move) pack $slm -side top -anchor w -fill x set flags(show_last_move_button) $slm set flags(flip) 0 set slm [Button $w.flip -text [::msgcat::mc "Flip view"] \ -command [list [namespace current]::toggle_flip_view $gid]] pack $slm -side top -anchor w -fill x set flags(flip_button) $slm Frame $w.move pack $w.move -side top -anchor w Label $w.move.title -text [::msgcat::mc "Move: "] pack $w.move.title -side left Label $w.move.on_move -anchor w \ -textvariable [namespace current]::${gid}(move_label) pack $w.move.on_move -side left -anchor w set bbox [ButtonBox $w.bbox -orient vertical -spacing 0] set flags(propose_draw_button) \ [$bbox add -text [::msgcat::mc "Propose a draw"] \ -command [list [namespace current]::toggle_draw $gid]] $bbox add -text [::msgcat::mc "Accept the draw proposal"] \ -state disabled \ -command [list [namespace current]::accept_draw $gid] $bbox add -text [::msgcat::mc "Resign the game"] \ -command [list [namespace current]::send_resign $gid] grid columnconfigure $bbox 0 -weight 1 pack $bbox -side bottom -anchor w -fill x set flags(bbox) $bbox set_tooltips #label $w.history -text [::msgcat::mc "History"] #pack $w.history -side top -anchor w set hsw [ScrolledWindow $w.hsw] pack $hsw -side top -fill x -expand yes set ht [Text $w.text -wrap word -height 60 -state disabled] set font [$ht cget -font] set tabstop1 [font measure $font "99.."] set tabstop2 [font measure $font "99..Qa8-a8+= "] $ht configure -tabs "$tabstop1 $tabstop2" $ht tag configure attention \ -foreground [option get $ht errorForeground Text] $hsw setwidget $ht set flags(hw) $ht set dsq_color #77a26d set lsq_color #c8c365 for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { set x1 [expr {$line_width + (($square_size + $line_width) * $c)}] set x2 [expr {($square_size + $line_width) * ($c + 1)}] set y1 [expr {$line_width + (($square_size + $line_width) * $r)}] set y2 [expr {($square_size + $line_width) * ($r + 1)}] set color [expr {($c+$r) % 2 ? $dsq_color : $lsq_color}] set img [expr {($c+$r) % 2 ? "bf" : "wf"}] $board create image $x1 $y1 -image chess/$img -anchor nw \ -tags [list background [list cr $c [expr {7-$r}]]] $board create rectangle $x1 $y1 $x2 $y2 \ -outline {} -width $line_width \ -tags [list square [list cr $c [expr {7-$r}]]] } } $board bind figure <1> \ [list [namespace current]::start_drag_figure $gid %x %y] $board bind figure \ [list [namespace current]::drag_figure $gid %x %y] $board bind figure \ [list [namespace current]::drag_end $gid %x %y] bind $w [list [namespace current]::close $gid] if {[is_black $flags(our_color)] && $options(flip_black_view)} { toggle_flip_view $gid } draw_position $gid update_controls $gid find_legal_moves $gid $flags(position,turn) } proc chess::toggle_flip_view {gid} { variable $gid upvar 0 $gid flags set flags(flip) [expr {!$flags(flip)}] set board $flags(board) for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { $board addtag [list temp [expr {7-$c}] [expr {7-$r}]] \ withtag [list cr $c $r] $board dtag [list cr $c $r] } } for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { $board addtag [list cr $c $r] withtag [list temp $c $r] $board dtag [list temp $c $r] } } button_update_relief $flags(flip_button) $flags(flip) draw_position $gid highlight_last_move $gid } proc chess::set_tooltips {args} { variable options if {$options(show_tooltips)} { set tooltip0 [::msgcat::mc "Press button and make move\ if you want propose draw"] set tooltip1 [::msgcat::mc "Press button if you want\ accept the draw proposal"] set tooltip2 [::msgcat::mc "Press button if you want resign"] } else { set tooltip0 "" set tooltip1 "" set tooltip2 "" } foreach var [info vars [namespace current]::*] { upvar 0 $var flags if {[info exists flags(bbox)]} { catch { $flags(bbox) itemconfigure 0 -helptext $tooltip0 $flags(bbox) itemconfigure 1 -helptext $tooltip1 $flags(bbox) itemconfigure 2 -helptext $tooltip2 } } } } proc chess::toggle_show_last_move {gid} { variable $gid upvar 0 $gid flags set flags(show_last_move) [expr {!$flags(show_last_move)}] button_update_relief $flags(show_last_move_button) $flags(show_last_move) highlight_last_move $gid } proc chess::toggle_draw {gid} { variable $gid upvar 0 $gid flags set flags(position,draw) [expr {!$flags(position,draw)}] button_update_relief $flags(propose_draw_button) $flags(position,draw) } proc chess::update_controls {gid {draw_proposed 0}} { variable $gid upvar 0 $gid flags button_update_relief $flags(propose_draw_button) 0 if {[is_my_move $gid]} { $flags(board) config -cursor "" set flags(position,draw) 0 if {$draw_proposed} { $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state normal $flags(bbox) itemconfigure 2 -state disabled } else { $flags(bbox) itemconfigure 0 -state normal $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state normal } } elseif {![is_white $flags(position,turn)] && \ ![is_black $flags(position,turn)]} { $flags(board) config -cursor "" $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state disabled } else { $flags(board) config -cursor watch $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state disabled } } proc chess::end_game {gid my_score message} { variable $gid upvar 0 $gid flags set opponent_score [expr {1 - $my_score}] if {[is_white $flags(our_color)]} { set score "$my_score : $opponent_score" } else { set score "$opponent_score : $my_score" } set flags(position,turn) none set flags(move_label) $message set hw $flags(hw) $hw configure -state normal catch {$hw delete attention.first attention.last} $hw delete {end -1 char} end $hw insert end "\n\t\t$score\n" $hw see end $hw configure -state disabled } proc chess::draw_position {gid} { variable $gid upvar 0 $gid flags $flags(board) delete figure for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { if {$flags(position,$c,$r) != ""} { if {$flags(flip)} { set c1 [expr {7 - $c}] set r1 [expr {7 - $r}] } else { set c1 $c set r1 $r } $flags(board) create image [center $c1 $r1] \ -image chess/$flags(position,$c,$r) \ -tags [list figure $flags(position,$c,$r) [list cr $c $r]] } } } } proc chess::start_drag_figure {gid x y} { variable $gid upvar 0 $gid flags set board $flags(board) lassign [lsearch -inline -regexp [$board gettags current] ^cr] cr \ flags(currentc) flags(currentr) set flags(last_x) [$board canvasx $x] set flags(last_y) [$board canvasy $y] $board raise current $board config -cursor hand2 highlight_legal_moves $gid $flags(currentc) $flags(currentr) } proc chess::drag_figure {gid x y} { variable line_width variable $gid upvar 0 $gid flags set board $flags(board) set x [$board canvasx $x] set y [$board canvasy $y] $board move current \ [expr {$x - $flags(last_x)}] [expr {$y - $flags(last_y)}] set flags(last_x) $x set flags(last_y) $y $board itemconfigure dst_sq&&square -outline "" -width $line_width $board dtag dst_sq $board itemconfigure legal&&square -outline blue -width $line_width $board addtag dst_sq overlapping $x $y $x $y lassign [lsearch -inline -regexp [$board gettags dst_sq&&background] ^cr] \ cr c r $board addtag dst_sq withtag [list cr $c $r]&&square $board itemconfigure dst_sq&&square -outline red -width $line_width $board itemconfigure dst_sq&&legal&&square -outline white -width $line_width } proc chess::drag_end {gid x y} { variable options variable line_width variable $gid upvar 0 $gid flags set board $flags(board) set x [$board canvasx $x] set y [$board canvasy $y] $board itemconfigure dst_sq&&square -outline "" -width $line_width $board dtag dst_sq $board addtag dst_sq overlapping $x $y $x $y lassign [lsearch -inline -regexp [$board gettags dst_sq&&background] ^cr] \ cr c r $board dtag dst_sq if {$options(allow_illegal) || [is_my_move $gid]} { do_move $gid $flags(currentc) $flags(currentr) \ $c $r "" $flags(position,draw) } update_controls $gid draw_position $gid unhighlight_legal_moves $gid highlight_last_move $gid } proc chess::highlight_last_move {gid} { variable line_width variable $gid upvar 0 $gid flags $flags(board) itemconfigure square -outline "" -width $line_width $flags(board) itemconfigure square -outline "" -width $line_width if {[catch {lassign $flags(position,last_move) cf rf ct rt}]} { return } if {$flags(show_last_move)} { set color white } else { set color {} } $flags(board) itemconfigure [list cr $cf $rf]&&square -outline $color -width $line_width $flags(board) itemconfigure [list cr $ct $rt]&&square -outline $color -width $line_width } proc chess::do_move {gid cf rf ct rt prom draw} { variable options variable $gid upvar 0 $gid flags if {$cf == $ct && $rf == $rt || $ct == "" || $rt == ""} { return 0 } set opts "-" set prm "" set suffix "" set checkmate 0 set stalemate 0 set my_move [is_my_move $gid] if {![is_move_legal $gid $cf $rf $ct $rt]} { if {$my_move && !$options(allow_illegal)} { return 0 } if {!$my_move && !$options(accept_illegal)} { return 0 } } save_position $gid if {$flags(position,$ct,$rt) != ""} { set opts ":" } set f $flags(position,$cf,$rf) set flags(position,$ct,$rt) $flags(position,$cf,$rf) set flags(position,$cf,$rf) "" if {$flags(position,$ct,$rt) == "wk"} { set flags(position,wk,c) $ct set flags(position,wk,r) $rt } elseif {$flags(position,$ct,$rt) == "bk"} { set flags(position,bk,c) $ct set flags(position,bk,r) $rt } if {[is_white $flags(position,turn)]} { set p "w" set opp "b" set r 0 } else { set p "b" set opp "w" set r 7 } if {$rt == (7 - $r)} { if {$ct == 0} { set flags(position,${opp}k,qcastling) 0 } elseif {$ct == 7} { set flags(position,${opp}k,kcastling) 0 } } if {$flags(position,$ct,$rt) == "${p}k"} { set flags(position,${p}k,kcastling) 0 set flags(position,${p}k,qcastling) 0 if {($ct - $cf) == 2} { set opts {0-0} set flags(position,5,$r) "${p}r" set flags(position,7,$r) "" } elseif {($ct - $cf) == -2} { set opts {0-0-0} set flags(position,3,$r) "${p}r" set flags(position,0,$r) "" } } elseif {$flags(position,$ct,$rt) == "${p}r"} { if {($cf == 0) && ($rf == $r)} { set flags(position,${p}k,qcastling) 0 } elseif {($cf == 7) && ($rf == $r)} { set flags(position,${p}k,kcastling) 0 } } set enpassant 0 if {$flags(position,$ct,$rt) == "${p}p"} { if {(($p == "w") && ($rt == 7)) || \ (($p == "b") && ($rt == 0))} { if {$my_move} { set promote [promote_pawn $gid $p] if {$promote == -1} { set flags(position,$ct,$rt) "${p}q" } else { set flags(position,$ct,$rt) $promote } } else { if {$prom != ""} { set flags(position,$ct,$rt) "${p}$prom" } # If we are here, then it's an error... } set prm $flags(position,$ct,$rt) } elseif {$flags(position,enpassant) == [list $ct $rt]} { if {[is_white $flags(position,turn)]} { set flags(position,$ct,4) "" } else { set flags(position,$ct,3) "" } set opts ":" } else { if {($rt - $rf) == 2} { set flags(position,enpassant) [list $ct [expr {$rt - 1}]] set enpassant 1 } elseif {($rt - $rf) == -2} { set flags(position,enpassant) [list $ct [expr {$rt + 1}]] set enpassant 1 } } } if {!$enpassant} { set flags(position,enpassant) {} } set flags(position,last_move) [list $cf $rf $ct $rt] if {[is_white $flags(position,turn)]} { set flags(position,turn) black set check [test_check $gid \ $flags(position,bk,c) $flags(position,bk,r) \ $flags(position,bk,c) $flags(position,bk,r)] } else { set flags(position,turn) white set check [test_check $gid \ $flags(position,wk,c) $flags(position,wk,r) \ $flags(position,wk,c) $flags(position,wk,r)] } find_legal_moves $gid $flags(position,turn) if {$check} { if {[llength $flags(legal_moves)] == 0} { set suffix "#" set draw 0 set checkmate 1 } else { set suffix "+" } } else { if {[llength $flags(legal_moves)] == 0} { set stalemate 1 } } if {$draw} { append suffix "=" } lappend opts $prm $suffix add_move_to_history $gid $cf $rf $ct $rt $f $opts set repetitions [add_to_repetitions $gid] if {$draw && !$my_move} { attention_message $gid \ [::msgcat::mc "\n\n Opponent proposes a draw\n\n"] } if {$my_move} { send_move $gid $cf $rf $ct $rt $prm } if {$stalemate} { # Draw by stalemate end_game $gid 0.5 [::msgcat::mc "Draw (Stalemate)"] } elseif {$repetitions >= 3} { # Draw by repetition end_game $gid 0.5 [::msgcat::mc "Draw (Repetition)"] } elseif {$checkmate} { if {$my_move} { # I win end_game $gid 1 [::msgcat::mc "You win (Checkmate)"] } else { # Opponent wins end_game $gid 0 [::msgcat::mc "Opponent wins (Checkmate)"] } } tab_set_updated [winfo parent $flags(board)] 1 mesg_to_user return 1 } proc chess::promote_pawn {gid color} { variable options variable square_size variable line_width variable $gid upvar 0 $gid flags if {$options(always_queen)} { return -1 } set w .promote if {[winfo exists $w]} { destroy $w } Dialog .promote -title [::msgcat::mc "Pawn promotion"] \ -anchor e -default 0 set fr [Frame $w.fr] set select [canvas $w.select \ -borderwidth 0 \ -highlightthickness 0 \ -width [expr {($square_size + $line_width) * 4 + $line_width}] \ -height [expr {($square_size + 2 * $line_width)}]] pack $fr -padx 3m -pady 1m pack $select -padx 3m -pady 1m set c 0 foreach fig {q r b n} { set img [expr {$c % 2 ? "bf" : "wf"}] set x1 [expr {$line_width + (($square_size + $line_width) * $c)}] set x2 [expr {($square_size + $line_width) * ($c + 1)}] set y1 [expr {$line_width + (($square_size + $line_width) * 0)}] set y2 [expr {($square_size + $line_width) * (0 + 1)}] $select create image $x1 $y1 -image chess/$img -anchor nw \ -tags [list background fg$fig] $select create image $x1 $y1 -image chess/$color$fig -anchor nw \ -tags [list figure fg$fig] $select create rectangle $x1 $y1 $x2 $y2 \ -outline {} -width $line_width \ -tags [list square fg$fig] incr c } bind $select \ [list [namespace current]::promotion:motion %W %x %y] bind $select \ [list [namespace current]::promotion:motion %W %x %y] bind $select \ [list [namespace current]::promotion:leave %W %x %y] foreach fig {q r b n} { $select bind fg$fig \ [list Dialog::enddialog $w $color$fig] } $w draw } proc chess::promotion:motion {c x y} { variable line_width set x [$c canvasx $x] set y [$c canvasy $y] $c itemconfigure dst_sq&&square -outline "" -width $line_width $c dtag dst_sq $c addtag dst_sq overlapping $x $y $x $y set tags [$c gettags dst_sq&&background] set tag [lindex $tags [lsearch $tags fg*]] if {$tag != ""} { $c addtag dst_sq withtag $tag&&square } $c itemconfigure dst_sq&&square -outline blue -width $line_width } proc chess::promotion:leave {c x y} { variable line_width $c itemconfigure dst_sq&&square -outline "" -width $line_width $c dtag dst_sq } proc chess::accept_draw {gid} { variable $gid upvar 0 $gid flags ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type chess \ id $flags(id)] \ -subelement [::xmpp::xml::create accept]] \ -to $flags(opponent) end_game $gid 0.5 [::msgcat::mc "Draw (You accepted)"] update_controls $gid draw_position $gid highlight_last_move $gid } proc chess::send_resign {gid} { variable $gid upvar 0 $gid flags ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type chess \ id $flags(id)] \ -subelement [::xmpp::xml::create resign]] \ -to $flags(opponent) end_game $gid 0 [::msgcat::mc "Opponent wins (You resigned)"] update_controls $gid draw_position $gid highlight_last_move $gid } proc chess::send_move {gid cf rf ct rt prom} { variable $gid upvar 0 $gid flags set move_tags [list [make_move_tag $gid $cf $rf $ct $rt $prom]] if {$flags(position,draw)} { lappend move_tags [::xmpp::xml::create draw] } ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type chess \ id $flags(id)] \ -subelements $move_tags] \ -to $flags(opponent) \ -command [list [namespace current]::send_result $gid] } proc chess::send_result {gid status xml} { if {$status == "error"} { attention_message $gid \ [::msgcat::mc "\n\n Opponent rejected move:\n %s\n\n" \ [error_to_string $xml]] restore_position $gid } } proc chess::make_move_tag {gid cf rf ct rt prom} { variable prom_name if {$prom == ""} { ::xmpp::xml::create move \ -attrs [list pos "$cf,$rf;$ct,$rt"] } else { set f [string index $prom 1] ::xmpp::xml::create move \ -attrs [list pos "$cf,$rf;$ct,$rt"] \ -subelement [::xmpp::xml::create promotion \ -cdata $prom_name($f)] } } proc chess::add_to_repetitions {gid} { variable $gid upvar 0 $gid flags array set repetitions $flags(position,repetitions) set code [code_position $gid] if {[info exists repetitions($code)]} { incr repetitions($code) } else { set repetitions($code) 1 } set flags(position,repetitions) [array get repetitions] return $repetitions($code) } proc chess::add_move_to_history {gid cf rf ct rt f opts} { variable piece_name variable $gid upvar 0 $gid flags incr flags(position,halfmove) 1 lappend flags(position,history) [list $cf $rf $ct $rt $f $opts] set hw $flags(hw) $hw configure -state normal $hw delete 0.0 end $hw insert end "\t[::msgcat::mc White]\t[::msgcat::mc Black]\n" set i 1 foreach {w b} $flags(position,history) { $hw insert end "${i}.\t" if {$w != {}} { lassign $w cf rf ct rt f opts lassign $opts opt prom check if {$prom == ""} { set m "" } else { set m $piece_name($prom) } if {($opt == "0-0") || ($opt == "0-0-0")} { $hw insert end "$opt$check\t" } else { incr rf incr rt set lf [format %c [expr {$cf+97}]] set lt [format %c [expr {$ct+97}]] set n $piece_name($f) $hw insert end "$n${lf}$rf${opt}${lt}$rt$m$check\t" } } if {$b != {}} { lassign $b cf rf ct rt f opts lassign $opts opt prom check if {$prom == ""} { set m "" } else { set m $piece_name($prom) } if {($opt == "0-0") || ($opt == "0-0-0")} { $hw insert end "$opt$check\n" } else { incr rf incr rt set lf [format %c [expr {$cf+97}]] set lt [format %c [expr {$ct+97}]] set n $piece_name($f) $hw insert end "$n${lf}$rf${opt}${lt}$rt$m$check\n" } } incr i } $hw see end $hw configure -state disabled } proc chess::find_pseudo_legal_moves {gid color callback} { variable moves variable $gid upvar 0 $gid flags set c [string index $color 0] for {set cf 0} {$cf < 8} {incr cf} { for {set rf 0} {$rf < 8} {incr rf} { if {[string index $flags(position,$cf,$rf) 0] != $c} { continue } switch -- $flags(position,$cf,$rf) { "" { continue } wp { set rt [expr {$rf + 1}] if {$rf < 7 && $flags(position,$cf,$rt) == ""} { if {$rf == 6} { eval $callback $gid $cf $rf $cf $rt promotion } else { eval $callback $gid $cf $rf $cf $rt } } if {$rf == 1 && $flags(position,$cf,2) == "" && \ $flags(position,$cf,3) == ""} { eval $callback $gid $cf $rf $cf 3 } foreach {ct rt} $moves(wpt,$cf,$rf) { if {[is_black $flags(position,$ct,$rt)] || \ ($flags(position,enpassant) == [list $ct $rt])} { if {$rf == 6} { eval $callback $gid $cf $rf $ct $rt promotion } else { eval $callback $gid $cf $rf $ct $rt } } } } bp { set rt [expr {$rf - 1}] if {$rf > 0 && $flags(position,$cf,$rt) == ""} { if {$rf == 1} { eval $callback $gid $cf $rf $cf $rt promotion } else { eval $callback $gid $cf $rf $cf $rt } } if {$rf == 6 && $flags(position,$cf,5) == "" && \ $flags(position,$cf,4) == ""} { eval $callback $gid $cf $rf $cf 4 } foreach {ct rt} $moves(bpt,$cf,$rf) { if {[is_white $flags(position,$ct,$rt)] || \ $flags(position,enpassant) == [list $ct $rt]} { if {$rf == 1} { eval $callback $gid $cf $rf $ct $rt promotion } else { eval $callback $gid $cf $rf $ct $rt } } } } wn - bn { foreach {ct rt} $moves(n,$cf,$rf) { if {[is_same_color $flags(position,$cf,$rf) \ $flags(position,$ct,$rt)]} \ continue eval $callback $gid $cf $rf $ct $rt } } wb - bb { foreach d {d1 d2 d3 d4} { foreach {ct rt} $moves($d,$cf,$rf) { if {[is_same_color $flags(position,$cf,$rf) \ $flags(position,$ct,$rt)]} \ break eval $callback $gid $cf $rf $ct $rt if {$flags(position,$ct,$rt) != ""} \ break } } } wr - br { foreach d {h1 h2 v1 v2} { foreach {ct rt} $moves($d,$cf,$rf) { if {[is_same_color $flags(position,$cf,$rf) \ $flags(position,$ct,$rt)]} \ break eval $callback $gid $cf $rf $ct $rt if {$flags(position,$ct,$rt) != ""} \ break } } } wq - bq { foreach d {d1 d2 d3 d4 h1 h2 v1 v2} { foreach {ct rt} $moves($d,$cf,$rf) { if {[is_same_color $flags(position,$cf,$rf) \ $flags(position,$ct,$rt)]} \ break eval $callback $gid $cf $rf $ct $rt if {$flags(position,$ct,$rt) != ""} \ break } } } wk { foreach {ct rt} $moves(k,$cf,$rf) { if {[is_same_color $flags(position,$cf,$rf) \ $flags(position,$ct,$rt)]} \ continue eval $callback $gid $cf $rf $ct $rt } if {($cf == 4) && ($rf == 0)} { if {$flags(position,wk,kcastling) && \ $flags(position,5,0) == "" && \ $flags(position,6,0) == ""} { eval $callback $gid 4 0 6 0 kcastling } if {$flags(position,wk,qcastling) && \ $flags(position,3,0) == "" && \ $flags(position,2,0) == "" && \ $flags(position,1,0) == ""} { eval $callback $gid 4 0 2 0 qcastling } } } bk { foreach {ct rt} $moves(k,$cf,$rf) { if {[is_same_color $flags(position,$cf,$rf) \ $flags(position,$ct,$rt)]} \ continue eval $callback $gid $cf $rf $ct $rt } if {($cf == 4) && ($rf == 7)} { if {$flags(position,bk,kcastling) && \ $flags(position,5,7) == "" && \ $flags(position,6,7) == ""} { eval $callback $gid 4 7 6 7 kcastling } if {$flags(position,bk,qcastling) && \ $flags(position,3,7) == "" && \ $flags(position,2,7) == "" && \ $flags(position,1,7) == ""} { eval $callback $gid 4 7 2 7 qcastling } } } } } } } proc chess::find_legal_moves {gid color} { variable $gid upvar 0 $gid flags set flags(legal_moves) {} find_pseudo_legal_moves $gid $color check_legal_callback } proc chess::check_legal_callback {gid cf rf ct rt {opt ""}} { variable $gid upvar 0 $gid flags if {![test_check $gid $cf $rf $ct $rt $opt]} { lappend flags(legal_moves) [list $cf $rf $ct $rt $opt] } } proc chess::test_check {gid cf rf ct rt {opt ""}} { variable $gid upvar 0 $gid flags set enpassantback "" set enpassantx "" set enpassanty "" if {[is_white $flags(position,turn)]} { set color black set f wk set of bk if {($rf == 4) && \ ($flags(position,$cf,$rf) == "wp") && \ ($flags(position,enpassant) == [list $ct $rt])} { set enpassantback "bp" set enpassantx $ct set enpassanty [expr {$rt - 1}] set flags(position,$enpassantx,$enpassanty) "" } } else { set color white set f bk set of wk if {($rf == 3) && \ ($flags(position,$cf,$rf) == "bp") && \ ($flags(position,enpassant) == [list $ct $rt])} { set enpassantback "wp" set enpassantx $ct set enpassanty [expr {$rt + 1}] set flags(position,$enpassantx,$enpassanty) "" } } set checks 0 set back $flags(position,$ct,$rt) set flags(position,$ct,$rt) $flags(position,$cf,$rf) set flags(position,$cf,$rf) "" if {$flags(position,$ct,$rt) == "wk"} { set flags(position,wk,c) $ct set flags(position,wk,r) $rt } elseif {$flags(position,$ct,$rt) == "bk"} { set flags(position,bk,c) $ct set flags(position,bk,r) $rt } set kc $flags(position,$f,c) set kr $flags(position,$f,r) set okc $flags(position,$of,c) set okr $flags(position,$of,r) if {$opt == "kcastling"} { set kcs [list 4 5 6] } elseif {$opt == "qcastling"} { set kcs [list 4 3 2] } else { set kcs [list $kc] } foreach c $kcs { incr checks [test_figures $gid $color $c $kr] incr checks [test_pawns $gid $color $c $kr] if {[info exists okc]} { set dx [expr {abs($c-$okc)}] set dy [expr {abs($kr-$okr)}] if {($dx <= 1) && ($dy <= 1)} { incr checks } } } set flags(position,$cf,$rf) $flags(position,$ct,$rt) set flags(position,$ct,$rt) $back if {$flags(position,$cf,$rf) == "wk"} { set flags(position,wk,c) $cf set flags(position,wk,r) $rf } elseif {$flags(position,$cf,$rf) == "bk"} { set flags(position,bk,c) $cf set flags(position,bk,r) $rf } if {$enpassantback != ""} { set flags(position,$enpassantx,$enpassanty) $enpassantback } return $checks } proc chess::test_pawns {gid color c r} { variable moves variable $gid upvar 0 $gid flags if {[is_white $color]} { foreach {x y} $moves(bpt,$c,$r) { if {$flags(position,$x,$y) == "wp"} { return 1 } } } else { foreach {x y} $moves(wpt,$c,$r) { if {$flags(position,$x,$y) == "bp"} { return 1 } } } return 0 } proc chess::test_figures {gid color c r} { variable moves variable $gid upvar 0 $gid flags if {[is_white $color]} { foreach i {d1 d2 d3 d4} { foreach {x y} $moves($i,$c,$r) { switch -- $flags(position,$x,$y) { "" {continue} wq - wb {return 1} default {break} } } } foreach i {h1 h2 v1 v2} { foreach {x y} $moves($i,$c,$r) { switch -- $flags(position,$x,$y) { "" {continue} wq - wr {return 1} default {break} } } } foreach {x y} $moves(n,$c,$r) { switch -- $flags(position,$x,$y) { wn {return 1} default {continue} } } } else { foreach i {d1 d2 d3 d4} { foreach {x y} $moves($i,$c,$r) { switch -- $flags(position,$x,$y) { "" {continue} bq - bb {return 1} default {break} } } } foreach i {h1 h2 v1 v2} { foreach {x y} $moves($i,$c,$r) { switch -- $flags(position,$x,$y) { "" {continue} bq - br {return 1} default {break} } } } foreach {x y} $moves(n,$c,$r) { switch -- $flags(position,$x,$y) { bn {return 1} default {continue} } } } return 0 } proc chess::is_move_legal {gid cf rf ct rt} { variable $gid upvar 0 $gid flags expr {[lsearch -regexp $flags(legal_moves) ^[list $cf $rf $ct $rt]] >= 0} } proc chess::highlight_legal_moves {gid cf rf} { variable line_width variable $gid upvar 0 $gid flags foreach move \ [lsearch -all -inline -regexp $flags(legal_moves) ^[list $cf $rf]] { lassign $move cft rft ct rt $flags(board) addtag legal withtag [list cr $ct $rt]&&square } $flags(board) itemconfigure legal&&square -outline blue -width $line_width } proc chess::unhighlight_legal_moves {gid} { variable line_width variable $gid upvar 0 $gid flags foreach sq [$flags(board) find withtag legal&&square] { $flags(board) itemconfigure $sq \ -outline [$flags(board) itemcget $sq -fill] -width $line_width } $flags(board) dtag legal } proc chess::attention_message {gid message} { variable $gid upvar 0 $gid flags set hw $flags(hw) $hw configure -state normal $hw delete {end -1 char} end $hw insert end $message attention $hw see end $hw configure -state disabled } proc chess::is_my_move {gid} { variable $gid upvar 0 $gid flags is_same_color $flags(position,turn) $flags(our_color) } proc chess::is_white {f} { string equal -length 1 $f w } proc chess::is_black {f} { string equal -length 1 $f b } proc chess::is_same_color {f1 f2} { string equal -length 1 $f1 $f2 } proc chess::add_groupchat_user_menu_item {m xlib jid} { set mm $m.gamesmenu if {![winfo exists $mm]} { menu $mm -tearoff 0 $m add cascade -label [::msgcat::mc "Games"] -menu $mm } $mm add command -label [::msgcat::mc "Chess..."] \ -command [list [namespace current]::invite_dialog $xlib $jid] } proc chess::iq_create {varname xlib from iqid xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[::xmpp::xml::getAttr $attrs type] == "chess"} { if {[::xmpp::xml::isAttr $attrs color]} { set color [::xmpp::xml::getAttr $attrs color] switch -- $color { white - black { } default { set var [list error modify bad-request] } } } else { set color white } set var [[namespace current]::invited_dialog \ $xlib $from $iqid \ [::xmpp::xml::getAttr $attrs id] \ $color] } return } proc chess::iq_turn {varname xlib from xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[::xmpp::xml::getAttr $attrs type] == "chess"} { set gid [make_gid $from [::xmpp::xml::getAttr $attrs id]] if {[exists $gid]} { set var [[namespace current]::turn_recv $gid $subels] } else { set var [list error cancel item-not-found] } } return } # Common games:board part proc iq_games_board_create {xlib from xml args} { set res [list error cancel feature-not-implemented] set iqid [::xmpp::xml::getAttr $args -id] hook::run games_board_create_hook res $xlib $from $iqid $xml return $res } proc iq_games_board_turn {xlib from xml args} { set res [list error cancel feature-not-implemented] hook::run games_board_turn_hook res $xlib $from $xml return $res } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/chess/msgs000075500000000000000000000000001500237002100155105ustar00nobodynobodytkabber-plugins/chess/msgs/es.msg000064400000000000000000000104171500237002100167110ustar00nobodynobody# es.msg -- # # Spanish messages for the Chess Tkabber plugin. # # Author: Badlop ::msgcat::mcset es " (Opponent)" " (Oponente)" ::msgcat::mcset es " (You)" " (Tu)" ::msgcat::mcset es "%s (%s) has refused chess invitation: %s" \ "%s (%s) Ha rechazado tu invitación de jugar al ajedrez: %s" ::msgcat::mcset es "%s wants play black." "%s quiere jugar con las negras." ::msgcat::mcset es "%s wants play white." "%s quiere jugar con las blancas." ::msgcat::mcset es "Accept opponent illegal moves (useful for debugging)." \ "Permitir movimientos ilegales del oponente (útil para depurar)." ::msgcat::mcset es "Accept the draw proposal" "Aceptar la propuesta de empate" ::msgcat::mcset es "Agree to play" "Aceptar la partida" ::msgcat::mcset es "Allow illegal moves (useful for debugging)." \ "Permitir movimientos ilegales (útil para depurar)." ::msgcat::mcset es "B" "B" ::msgcat::mcset es "Black" "Negras" ::msgcat::mcset es "Cancel invitation" "Cancelar invitación" ::msgcat::mcset es "Chess Invitation from %s" "Invitación de Ajedrez de %s" ::msgcat::mcset es "Chess Invitation" "Invitación de Ajedrez" ::msgcat::mcset es "Chess figures theme." "Tema de las figuras de ajedrez." ::msgcat::mcset es "Chess game invitation from %s (%s) is received." \ "Se ha recibido una invitación de %s (%s) para jugar al ajedrez." ::msgcat::mcset es "Chess plugin options." "Opciones del ajedrez." ::msgcat::mcset es "Chess with %s" "Ajedrez con %s" ::msgcat::mcset es "Chess..." "Ajedrez..." ::msgcat::mcset es "Draw (Opponent accepted)" "Empate (el oponente aceptó)" ::msgcat::mcset es "Draw (Repetition)" "Empate (Repetición)" ::msgcat::mcset es "Draw (Stalemate)" "Empate (Tablas)" ::msgcat::mcset es "Draw (You accepted)" "Empate (Aceptaste)" ::msgcat::mcset es "Flip board view when playing black by default." \ "Voltear el tablero cuando se juega con negras." ::msgcat::mcset es "Flip view" "Voltear el tablero" ::msgcat::mcset es "Games" "Juegos" ::msgcat::mcset es "History" "Historial" ::msgcat::mcset es "I want play black" "Quiero jugar con las negras" ::msgcat::mcset es "I want play white" "Quiero jugar con las blancas" ::msgcat::mcset es "K" "K" ::msgcat::mcset es "Move: " "Movimiento: " ::msgcat::mcset es "N" "N" ::msgcat::mcset es "Opponent wins (Checkmate)" \ "El oponente gana (por jaque mate)" ::msgcat::mcset es "Opponent wins (You resigned)" \ "El oponente gana (te rendiste)" ::msgcat::mcset es "Pawn promotion" "Promoción del peón" ::msgcat::mcset es "Plugins options." "Opciones de plugins." ::msgcat::mcset es "Press button and make move if you want propose draw" \ "Pulsa el botón y haz un movimiento si quieres proponer un empate" ::msgcat::mcset es "Press button if you want accept the draw proposal" \ "Pulsa el botón si quieres aceptar la propuesta de empate" ::msgcat::mcset es "Press button if you want resign" \ "Pulsa el botón si quieres rendirte" ::msgcat::mcset es "Promote pawns always as queens." \ "Promover peones a reinas siempre." ::msgcat::mcset es "Propose a draw" "Proponer empate" ::msgcat::mcset es "Q" "Q" ::msgcat::mcset es "R" "R" ::msgcat::mcset es "Refuse to play" "Rechazar la partida" ::msgcat::mcset es "Resign the game" "Rendirte" ::msgcat::mcset es "Sending chess game invitation to %s (%s)" \ "Enviando invitación de ajedrez a %s (%s)" ::msgcat::mcset es "Show last move by default." \ "Mostrar el último movimiento por defecto." ::msgcat::mcset es "Show last move" "Mostrar el último movimiento" ::msgcat::mcset es "Show tooltips with short instructions." \ "Mostrar tooltips con pequeñas instrucciones." ::msgcat::mcset es "Sound to play after opponent's turn" \ "Sonido a reproducir cuando el oponente haya movido" ::msgcat::mcset es "Whether the Chess plugin is loaded." \ "Cargar el plugin Chess." ::msgcat::mcset es "White" "Blancas" ::msgcat::mcset es "You win (Checkmate)" "Tu ganas (por jaque mate)" ::msgcat::mcset es "You win (Opponent resigned)" \ "Tu ganas (el oponente se ha rendido)" ::msgcat::mcset es "\n\n Opponent proposes a draw\n\n" \ "\n\n El oponente propone un empate\n\n" ::msgcat::mcset es "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n El oponente rechazó el movimiento:\n %s\n\n" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/chess/msgs/nl.msg000064400000000000000000000102341500237002100167100ustar00nobodynobody# nl.msg -- # # Dutch messages for the Chess Tkabber plugin. # # Author: Sander Devrieze ::msgcat::mcset nl "Chess with %s" "Schaken met %s" ::msgcat::mcset nl "Move: " "Aan zet:" ::msgcat::mcset nl "History" "Geschiedenis" ::msgcat::mcset nl "Pawn promotion" "Promotie van pion" ::msgcat::mcset nl "White" "Wit" ::msgcat::mcset nl "Black" "Zwart" ::msgcat::mcset nl "K" "K" ::msgcat::mcset nl "Q" "Q" ::msgcat::mcset nl "R" "R" ::msgcat::mcset nl "B" "B" ::msgcat::mcset nl "N" "N" ::msgcat::mcset nl "Plugins options." "Pluginopties." ::msgcat::mcset nl "Chess plugin options." "Pluginopties voor schaken." ::msgcat::mcset nl "Chess figures theme." \ "Thema voor afbeeldingen van pionnen." ::msgcat::mcset nl "Flip board view when playing black by default." \ "Het speelbord standaard omkeren bij het spelen met zwart." ::msgcat::mcset nl "Show last move by default." \ "Laatste zet standaard laten zien." ::msgcat::mcset nl "Promote pawns always as queens." \ "Pionnen steeds promoveren tot koninginnen." ::msgcat::mcset nl "Show tooltips with short instructions." \ "Tekstballonnen met korte instructies laten zien." ::msgcat::mcset nl "Allow illegal moves (useful for debugging)." \ "Niet-toegelaten zetten toestaan (bruikbaar voor debuggen)." ::msgcat::mcset nl "Accept opponent illegal moves (useful for debugging)." \ "Niet-toegelaten zetten van tegenstander accepteren (bruikbaar voor\ debuggen)." ::msgcat::mcset nl "Chess Invitation" "Uitnodiging voor een schaakspel" ::msgcat::mcset nl "Sending chess game invitation to %s (%s)" \ "Bezig met verzenden van uitnodiging voor een schaakspel naar %s (%s)" ::msgcat::mcset nl "I want play white" "Ik wil met wit spelen" ::msgcat::mcset nl "I want play black" "Ik wil met zwart spelen" ::msgcat::mcset nl "Cancel invitation" "Uitnodiging annuleren" ::msgcat::mcset nl "%s (%s) has refused chess invitation: %s" \ "%s (%s) ging niet in op de uitnodiging om met hem te schaken: %s" ::msgcat::mcset nl "Chess Invitation from %s" \ "Uitnodiging voor een schaakspel met %s" ::msgcat::mcset nl "Chess game invitation from %s (%s) is received." \ "Uitnodiging voor een schaakspel met %s (%s) werd ontvangen." ::msgcat::mcset nl "%s wants play %s." "%s wil spelen met %s." ::msgcat::mcset nl "Agree to play" "Spelen" ::msgcat::mcset nl "Refuse to play" "Niet spelen" ::msgcat::mcset nl " (You)" "(Jij)" ::msgcat::mcset nl " (Opponent)" "(Tegenstander)" ::msgcat::mcset nl "You win (Opponent resigned)" \ "Jij hebt gewonnen (de tegenstander gaf het op)" ::msgcat::mcset nl "Draw (Opponent accepted)" \ "Gelijkspel (de tegenstander accepteerde de uitslag)" ::msgcat::mcset nl "Show last move" "Laatste zet laten zie" ::msgcat::mcset nl "Flip view" "Beeld omkeren" ::msgcat::mcset nl "Propose a draw" "Gelijkspel voorstellen" ::msgcat::mcset nl "Accept the draw proposal" \ "et voorstel voor gelijkspel accepteren" ::msgcat::mcset nl "Resign the game" "Geef het op" ::msgcat::mcset nl "Press button and make move if you want propose draw" \ "Druk op de knop en doe een zet als je gelijkspel wilt voorstellen" ::msgcat::mcset nl "Press button if you want accept the draw proposal" \ "Druk op de knop als je het voorstel voor gelijkspel wilt accepteren" ::msgcat::mcset nl "Press button if you want resign" \ "Druk op de knop als je wilt opgeven" ::msgcat::mcset nl "\n\n Opponent proposes a draw\n\n" \ "\n\n De tegenstander stelt een gelijkspel voor\n\n" ::msgcat::mcset nl "Draw (Stalemate)" "Gelijkspel (pat)" ::msgcat::mcset nl "You win (Checkmate)" "Jij hebt gewonnen (schaakmat)" ::msgcat::mcset nl "Opponent wins (Checkmate)" \ "De tegenstander heeft gewonnen (schaakmat)" ::msgcat::mcset nl "Draw (You accepted)" \ "Gelijkspel (jij accepteerde de uitslag)" ::msgcat::mcset nl "Opponent wins (You resigned)" \ "De tegenstander heeft gewonnen (jij gaf het op)" ::msgcat::mcset nl "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n De tegenstander weigerde de zet:\n %s\n\n" ::msgcat::mcset nl "Games" "Spelletjes" ::msgcat::mcset nl "Chess..." "Schaken..." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/chess/msgs/pl.msg000064400000000000000000000104451500237002100167160ustar00nobodynobody# pl.mdg -- # # Polish messages for the Chess Tkabber plugin # # Author: Irek Chmielowiec ::msgcat::mcset pl "White" "BiaÅ‚e" ::msgcat::mcset pl "Chess with %s" "Szachy: %s" ::msgcat::mcset pl "Move: " "Ruch: " ::msgcat::mcset pl "History" "Historia" ::msgcat::mcset pl "Black" "Czarne" ::msgcat::mcset pl "Pawn promotion" "Promocja piona" ::msgcat::mcset pl "K" "K" ::msgcat::mcset pl "Q" "H" ::msgcat::mcset pl "R" "W" ::msgcat::mcset pl "B" "G" ::msgcat::mcset pl "N" "S" ::msgcat::mcset pl "Chess plugin options." \ "Ustawienia wtyczki do gry w szachy." ::msgcat::mcset pl "Chess figures theme." "Motyw graficzny szchownicy." ::msgcat::mcset pl "Flip board view when playing black by default." \ "Odwróć widok szachownicy podczas gry czarnymi." ::msgcat::mcset pl "Show last move by default." "Pokazuj ostatni ruch." ::msgcat::mcset pl "Promote pawns always as queens." \ "Promocja piona zawsze do hetmana." ::msgcat::mcset pl "Show tooltips with short instructions." \ "Pokazuj dymki podpowiedzi z krótkimi instrukcjami." ::msgcat::mcset pl "Allow illegal moves (useful for debugging)." \ "Pozwalaj na nieprawidÅ‚owe ruchy (użyteczne przy debugowaniu)." ::msgcat::mcset pl "Accept opponent illegal moves (useful for debugging)." \ "Pozwalaj na nieprawidÅ‚owe ruchy przeciwnika (użyteczne przy\ debugowaniu)." ::msgcat::mcset pl "Chess Invitation" "Zaproszenie do gry w szachy" ::msgcat::mcset pl "Sending chess game invitation to %s (%s)" \ "WysyÅ‚anie zaproszenia do gry w szachy do %s (%s)" ::msgcat::mcset pl "I want play white" "ChcÄ™ grać biaÅ‚ymi" ::msgcat::mcset pl "I want play black" "ChcÄ™ grać czarnymi" ::msgcat::mcset pl "Cancel invitation" "Anuluj zaproszenie" ::msgcat::mcset pl "%s (%s) has refused chess invitation: %s" \ "%s (%s) odrzuca zaproszenie do gry w szachy: %s" ::msgcat::mcset pl "Chess Invitation from %s" \ "Zaproszenie do gry w szachy od %s" ::msgcat::mcset pl "Chess game invitation from %s (%s) is received." \ "Otrzymano zaproszenie do gry w szachy od %s (%s)." ::msgcat::mcset pl "Agree to play" "Przyjmij zaproszenie" ::msgcat::mcset pl "Refuse to play" "Odrzuć zaproszenie" ::msgcat::mcset pl " (You)" " (Ty)" ::msgcat::mcset pl " (Opponent)" " (Przeciwnik)" ::msgcat::mcset pl "You win (Opponent resigned)" \ "WygaÅ‚eÅ› (przeciwnik zrezygnowaÅ‚)" ::msgcat::mcset pl "Draw (Opponent accepted)" "Remis (za zgodÄ… przeciwnika)" ::msgcat::mcset pl "Show last move" "Pokaż ostatni ruch" ::msgcat::mcset pl "Flip view" "Odwróć widok" ::msgcat::mcset pl "Propose a draw" "Zaproponuj remis" ::msgcat::mcset pl "Accept the draw proposal" "Zaakceptuj remis" ::msgcat::mcset pl "Resign the game" "Zrezygnuj z gry" ::msgcat::mcset pl "Press button and make move if you want propose draw" \ "NaciÅ›nij przycisk i wykonaj ruch jeżeli chcesz zaproponować remis" ::msgcat::mcset pl "Press button if you want accept the draw proposal" \ "NaciÅ›nij przycisk jeżeli chcesz zaakceptować propozycjÄ™ remisu" ::msgcat::mcset pl "Press button if you want resign" \ "NaciÅ›nij przycisk jeżeli chcesz zrezygnować z gry" ::msgcat::mcset pl "\n\n Opponent proposes a draw\n\n" \ "\n\n Przeciwnik proponuje remis\n\n" ::msgcat::mcset pl "Draw (Stalemate)" "Remis (Pat)" ::msgcat::mcset pl "Draw (Repetition)" "Remis (Powtórzenie)" ::msgcat::mcset pl "You win (Checkmate)" "WygraÅ‚eÅ› (Szach i Mat)" ::msgcat::mcset pl "Opponent wins (Checkmate)" \ "WygraÅ‚ przeciwnik (Szach i Mat)" ::msgcat::mcset pl "Draw (You accepted)" "Remis (Za mojÄ… zgodÄ…)" ::msgcat::mcset pl "Opponent wins (You resigned)" \ "WygraÅ‚ przeciwnik (ZrezygnowaÅ‚eÅ› z gry)" ::msgcat::mcset pl "Chess..." "Szachy..." ::msgcat::mcset pl "Games" "Gry planszowe" ::msgcat::mcset pl "Sound to play after opponent's turn" \ "Odtwórz dźwiÄ™k po ruchu przeciwnika" ::msgcat::mcset pl "%s wants play white." "%s chce grać biaÅ‚ymi." ::msgcat::mcset pl "%s wants play black." "%s chce grać czarnymi." ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Przeciwnik odrzuciÅ‚ ruch:\n %s\n\n" ::msgcat::mcset pl "Whether the Chess plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ do gry w szachy." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/chess/msgs/ro.msg000064400000000000000000000014651500237002100167250ustar00nobodynobody# ro.msg -- # # Romanian messages for the Chess Tkabber plugin. ::msgcat::mcset ro "Let's play chess, %s!" "Hai să jucăm ÅŸah, %s!" #::msgcat::mcset ru "Invite" "Invită" #::msgcat::mcset ru "Cancel" "Anulare!" ::msgcat::mcset ro "Opponent %s refuse our request: %s" \ "Oponentul %s a refuzat cererea noastră: %s" ::msgcat::mcset ro "%s want to play chess!" "%s vrea să joace ÅŸah!" ::msgcat::mcset ro "Play" "Joacă" ::msgcat::mcset ro "Chess with %s" "Åžah cu %s" ::msgcat::mcset ro "Allow illegal moves" "Permite mutări ilegale" ::msgcat::mcset ro "Move: " "Mutare: " ::msgcat::mcset ro "History" "Istoric" ::msgcat::mcset ro "Pawn promotion" "Transformare pion" ::msgcat::mcset ro "Chess" "Åžah" ::msgcat::mcset ro "White" "Alb" ::msgcat::mcset ro "Black" "Negru" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/chess/msgs/ru.msg000064400000000000000000000125001500237002100167230ustar00nobodynobody# ru.msg -- # # Russian messages for the Chess Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Plugins options." "Параметры раÑширений." ::msgcat::mcset ru "Flip board view when playing black by default." \ "Разворачивать по умолчанию доÑку при игре чёрными." ::msgcat::mcset ru "Show last move by default." \ "По умолчанию показывать поÑледний ход." ::msgcat::mcset ru " (You)" " (Ð’Ñ‹)" ::msgcat::mcset ru " (Opponent)" " (Оппонент)" ::msgcat::mcset ru "Flip view" "Развернуть доÑку" ::msgcat::mcset ru "R" "Л" ::msgcat::mcset ru "N" "К" ::msgcat::mcset ru "B" "С" ::msgcat::mcset ru "Q" "Ф" ::msgcat::mcset ru "K" "Кр" ::msgcat::mcset ru "Chess plugin options." "Параметры раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð¨Ð°Ñ…Ð¼Ð°Ñ‚Ñ‹." ::msgcat::mcset ru "Chess figures theme." "Тема шахматных фигур." ::msgcat::mcset ru "Promote pawns always as queens." \ "Ð’Ñегда превращать проведённую пешку в ферзÑ." ::msgcat::mcset ru "Show tooltips with short instructions." \ "Показывать вÑплывающие подÑказки к Ñлементам интерфейÑа." ::msgcat::mcset ru "Allow illegal moves (useful for debugging)." \ "Разрешать неправильные ходы (иÑпользуетÑÑ Ð¿Ñ€Ð¸ отладке)." ::msgcat::mcset ru "Accept opponent illegal moves (useful for debugging)." \ "Принимать неправильные ходы от оппонента (иÑпользуетÑÑ Ð¿Ñ€Ð¸ отладке)." ::msgcat::mcset ru "Chess Invitation" "Приглашение Ñыграть в шахматы" ::msgcat::mcset ru "Sending chess game invitation to %s (%s)" \ "ПоÑылаем приглашение Ñыграть в шахматы Ñ %s (%s)" ::msgcat::mcset ru "I want play white" "Хочу играть белыми" ::msgcat::mcset ru "I want play black" "Хочу играть чёрными" ::msgcat::mcset ru "Cancel invitation" "Отменить приглашение" ::msgcat::mcset ru "%s (%s) has refused chess invitation: %s" \ "%s (%s) отказалÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ в шахматы: %s" ::msgcat::mcset ru "Chess Invitation from %s" \ "Приглашение Ñыграть в шахматы Ñ %s" ::msgcat::mcset ru "Chess game invitation from %s (%s) is received." \ "Получено приглашение Ñыграть в шахматы Ñ %s (%s)" ::msgcat::mcset ru "%s wants play white." "%s хочет играть белыми" ::msgcat::mcset ru "%s wants play black." "%s хочет играть чёрными" ::msgcat::mcset ru "Agree to play" "СоглаÑитьÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ" ::msgcat::mcset ru "Refuse to play" "ОтказатьÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ" ::msgcat::mcset ru "Chess with %s" "Шахматы Ñ %s" ::msgcat::mcset ru "Show last move" "Показывать поÑледний ход" ::msgcat::mcset ru "Move: " "Ход: " ::msgcat::mcset ru "Propose a draw" "Предложить ничью" ::msgcat::mcset ru "Accept the draw proposal" "ПринÑть предложенную ничью" ::msgcat::mcset ru "Resign the game" "Сдать партию" ::msgcat::mcset ru "History" "ЗапиÑÑŒ партии" ::msgcat::mcset ru "Pawn promotion" "Превращение пешки" ::msgcat::mcset ru "Chess..." "Шахматы..." ::msgcat::mcset ru "White" "Белые" ::msgcat::mcset ru "Black" "Чёрные" ::msgcat::mcset ru "Opponent wins (Checkmate)" "Оппонент выиграл (Мат)" ::msgcat::mcset ru "You win (Checkmate)" "Ð’Ñ‹ выиграли (Мат)" ::msgcat::mcset ru "Opponent wins (You resigned)" \ "Оппонент выиграл (Ð’Ñ‹ ÑдалиÑÑŒ)" ::msgcat::mcset ru "You win (Opponent resigned)" \ "Ð’Ñ‹ выиграли (Оппонент ÑдалÑÑ)" ::msgcat::mcset ru "Draw (Stalemate)" "ÐÐ¸Ñ‡ÑŒÑ (Пат)" ::msgcat::mcset ru "Draw (Repetition)" "ÐÐ¸Ñ‡ÑŒÑ (Повторение позиции)" ::msgcat::mcset ru "Draw (You accepted)" "ÐÐ¸Ñ‡ÑŒÑ (Ð’Ñ‹ принÑли)" ::msgcat::mcset ru "Draw (Opponent accepted)" "ÐÐ¸Ñ‡ÑŒÑ (Оппонент принÑл)" ::msgcat::mcset ru "Press button and make move if you want propose draw" \ "Ðажмите кнопку и Ñделайте ход, еÑли хотите предложить ничью" ::msgcat::mcset ru "Press button if you want accept the draw proposal" \ "Ðажмите кнопку, еÑли хотите принÑть предложенную ничью" ::msgcat::mcset ru "Press button if you want resign" \ "Ðажмите кнопку, еÑли хотите ÑдатьÑÑ" ::msgcat::mcset ru "\n\n Opponent proposes a draw\n\n" \ "\n\n Оппонент предлагает ничью\n\n" ::msgcat::mcset ru "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Оппонент отверг ход:\n %s\n\n" ::msgcat::mcset ru "Games" "Игры" ::msgcat::mcset ru "Sound to play after opponent's turn" \ "Звук, который проигрываетÑÑ Ð¿Ð¾Ñле хода оппонента" ::msgcat::mcset ru "Whether the Chess plugin is loaded." \ "Загружено ли раÑширение Шахматы." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/chess/msgs/uk.msg000064400000000000000000000124231500237002100167200ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Chess Tkabber plugin. # # Author: Artem Bondarenko # Author: Sergei Golovan ::msgcat::mcset uk "Draw (Repetition)" "ÐÑ–Ñ‡Ð¸Ñ (ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ð¾Ð·Ð¸Ñ†Ñ–Ñ—)" ::msgcat::mcset uk "Whether the Chess plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð¨Ð°Ñ…Ð¸." ::msgcat::mcset uk "Plugins options." "Параметри плагінів." ::msgcat::mcset uk "Flip board view when playing black by default." \ "Розвертати дошку при грі чорними за замовчуваннÑм." ::msgcat::mcset uk "Show last move by default." \ "Показувати оÑтанній хід за замовчуваннÑм." ::msgcat::mcset uk " (You)" " (Ви)" ::msgcat::mcset uk " (Opponent)" " (Опонент)" ::msgcat::mcset uk "Flip view" "Розгорнути дошку" ::msgcat::mcset uk "R" "Т" ::msgcat::mcset uk "N" "К" ::msgcat::mcset uk "B" "С" ::msgcat::mcset uk "Q" "Ф" ::msgcat::mcset uk "K" "Кр" ::msgcat::mcset uk "Chess plugin options." "Параметри плагіна Шахи." ::msgcat::mcset uk "Chess figures theme." "Тема шахових фігур." ::msgcat::mcset uk "Promote pawns always as queens." \ "Завжди перетворювати проведений пішак у ферзÑ." ::msgcat::mcset uk "Show tooltips with short instructions." \ "Показувати Ñпливаючі підказки до елементів інтерфейÑу." ::msgcat::mcset uk "Allow illegal moves (useful for debugging)." \ "ДозволÑти неправильні ходи (викориÑтовуєтьÑÑ Ð¿Ñ€Ð¸ налагодженні)." ::msgcat::mcset uk "Accept opponent illegal moves (useful for debugging)." \ "Приймати неправильні ходи від опонента (викориÑтовуєтьÑÑ Ð¿Ñ€Ð¸\ налагодженні)." ::msgcat::mcset uk "Chess Invitation" "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в шахи" ::msgcat::mcset uk "Sending chess game invitation to %s (%s)" \ "ВідÑилаєтьÑÑ Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в шахи з %s (%s)" ::msgcat::mcset uk "I want play white" "Хочу грати білими" ::msgcat::mcset uk "I want play black" "Хочу грати чорними" ::msgcat::mcset uk "Cancel invitation" "СкаÑувати запрошеннÑ" ::msgcat::mcset uk "%s (%s) has refused chess invitation: %s" \ "%s (%s) відмовивÑÑ Ð³Ñ€Ð°Ñ‚Ð¸ в шахи: %s" ::msgcat::mcset uk "Chess Invitation from %s" "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в шахи з %s" ::msgcat::mcset uk "Chess game invitation from %s (%s) is received." \ "Отримано Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в шахи з %s (%s)" ::msgcat::mcset uk "%s wants play white." " %s хоче грати білими" ::msgcat::mcset uk "%s wants play black." " %s хоче грати чорними" ::msgcat::mcset uk "Agree to play" "ПогодитиÑÑ Ð³Ñ€Ð°Ñ‚Ð¸" ::msgcat::mcset uk "Refuse to play" "ВідмовитиÑÑ Ð³Ñ€Ð°Ñ‚Ð¸" ::msgcat::mcset uk "Chess with %s" "Шахи з %s" ::msgcat::mcset uk "Show last move" "Показувати оÑтанній хід" ::msgcat::mcset uk "Move: " "Хід: " ::msgcat::mcset uk "Propose a draw" "Запропонувати нічию" ::msgcat::mcset uk "Accept the draw proposal" "ПрийнÑти запропоновану нічию" ::msgcat::mcset uk "Resign the game" "Здати партію" ::msgcat::mcset uk "History" "Ð—Ð°Ð¿Ð¸Ñ Ð¿Ð°Ñ€Ñ‚Ñ–Ñ—" ::msgcat::mcset uk "Pawn promotion" "ÐŸÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ–ÑˆÐ°ÐºÐ°" ::msgcat::mcset uk "Chess..." "Шахи..." ::msgcat::mcset uk "White" "Білі" ::msgcat::mcset uk "Black" "Чорні" ::msgcat::mcset uk "Opponent wins (Checkmate)" "Опонент виграв (Мат)" ::msgcat::mcset uk "You win (Checkmate)" "Ви виграли (Мат)" ::msgcat::mcset uk "Opponent wins (You resigned)" "Опонент виграв (Ви здалиÑÑ)" ::msgcat::mcset uk "You win (Opponent resigned)" "Ви виграли (Опонент здавÑÑ)" ::msgcat::mcset uk "Draw (Stalemate)" "ÐÑ–Ñ‡Ð¸Ñ (Пат)" ::msgcat::mcset uk "Draw (You accepted)" "ÐÑ–Ñ‡Ð¸Ñ (Ви прийнÑли)" ::msgcat::mcset uk "Draw (Opponent accepted)" "ÐÑ–Ñ‡Ð¸Ñ (Опонент прийнÑв)" ::msgcat::mcset uk "Press button and make move if you want propose draw" \ "ÐатиÑніть кнопку й зробіть хід, Ñкщо хочете запропонувати нічию" ::msgcat::mcset uk "Press button if you want accept the draw proposal" \ "ÐатиÑніть кнопку, Ñкщо хочете прийнÑти запропоновану нічию" ::msgcat::mcset uk "Press button if you want resign" \ "ÐатиÑніть кнопку, Ñкщо хочете здатиÑÑ" ::msgcat::mcset uk "\n\n Opponent proposes a draw\n\n" \ "\n\n Опонент пропонує нічию\n\n" ::msgcat::mcset uk "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Опонент відкинув хід:\n %s\n\n" ::msgcat::mcset uk "Games" "Ігри" ::msgcat::mcset uk "Sound to play after opponent's turn" \ "Звук, Ñкий буде програватиÑÑ Ð¿Ñ–ÑÐ»Ñ Ñ…Ð¾Ð´Ñƒ опонента" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/chess/pixmaps000075500000000000000000000000001500237002100162205ustar00nobodynobodytkabber-plugins/chess/pixmaps/classic000075500000000000000000000000001500237002100176415ustar00nobodynobodytkabber-plugins/chess/pixmaps/classic/bb.gif000064400000000000000000000007471500237002100210020ustar00nobodynobodyGIF89a00ô$$D$D$DDD$D$DDDDDdDdDDddDdd„„d„„„„¤¤¤ÄÄÄÄÜÄüüôüüüÿÿÿ!ù,00þà$Ždižhª®lë¾p,Ïtmßø*I9H/ö ÂaK4:<¥®)8@¥,f ŪŠÀ®÷¤mÄãQD`n&Ó" »í†OÊm>˜–Ózsh=~TT{gR~[fTlƒ6Zms@Vzo8ZŠMVfUF–3¢t ¨Tž|¡€œM ¦G¯ª0¢µ@ £ [¼/Z› VÎV™Ä a³VFΠХÓÕ7~žµ œ Ç9?V˶ì€ Ų¡zðœÝôê  €º±æ9¥ª(XPÀ)’3‚J!´‡X Nê4 ˆ/Eª 2²°ªîe(:kS A‡PÎúC‡ÌU;rîh@³„@uÖÀóçM3ÈRíÉóh“¤d©k°.Z€;)±× *¨%–Úˆ5NӚ؀%±ãŒÎ?w°ÍA'¹«BÙÙË·¯ß¿=B;tkabber-plugins/chess/pixmaps/classic/bf.gif000064400000000000000000000015651500237002100210050ustar00nobodynobodyGIF89a11ó sQ1sY1{U1{Y1kUBsYJ{YB„YB„aBŒaJŒiBÿÿÿ!ù ,11þÐ"€ ¦˜m„AöQã¦!Hn ’x&HLÕ•qݲdj~©•ÎË  …C¨ˆÌiŒCbátŸ€†•B.… 3=õ®BN Á7B+A'(„7«ža ˆy@\V§7—6¶°!~°2 ™(Š©H¥ºRƒš«99 / ’j§¸ͺbi8*ŸÃ¤8n…¨Î$/b8ž´ãÂ,0{¤Ú‰Î#ÉŸT{VXkA„ Bl¬:iΖ"üP“òð¶.Àäã@-™¸"þC$€ PäÁ "Þh6ÅŠ WÜ©Ååž©¶pTðγ5;$ˆf ¥½&q ¸pS?Žs|4:RÌÍMPX´(‚ ¬¡ ò€8ÁXœLy@Ù–f µ<2] ëjBN@ãΉ¡i8¡-(”E‚„ÎA˜¦Ð’÷%X?B‡¶ô—jg Ÿ:ÖÎ ;t°±4¹‹BÈž ¼½"@ŽduÌØ¹:,‡m« K»šndS‘F€‚pULWó6óÂ7ÿ¹¼‚õÅ5j8›*œ«à;I0ŽÜ‰‹»vw¯ËK=¸ž¹ýµIô¯¿¢g ’i¤sú<þ÷ÝtiìÕš@¥UÚ.¿ ÷H(&¤´_8çÁCöôI0,:S‘G„|(`Àt¤¢]˜-Kgíž®x’h¹*æµ¥^!DxpO&G‹è(H§n¨¥"Lé"Öà0·¾ü˜Ýk /i^ª Êða}#KžÌ¦²å˘3kÞÌ&;tkabber-plugins/chess/pixmaps/classic/bp.gif000064400000000000000000000006411500237002100210110ustar00nobodynobodyGIF89a00ô$$D$DDD$D$DDDDDdDdDDddDdd„„„„¤¤„¤¤¤¤ÄÄĤÄÄÄÄüüüÿÿÿ!ù,00þ $Ždižhª®lë¾p,Ïtmßx®ï|ïÿ¥ˆpD !Ȥ°HŠ 4ЀD˜gÊ ¬Em—k0 à_¤1æ êÕ'nC išW·ã¡{;}m €s|vPo‡tŠ‹xq‚v™•ˆ[v žq„¢Lm q£=ƒc–t³V±¶‘]¸XNl¡µ—„q¯¹8N”RœeRȲÌÎQ pPÉ3u¯ØŒÚ”Â2àe¦„ åÞ/b¯×’ yÓ6NwЋ¯ Úe2çbY”2ÔùI àAN2Éó·È‹ÄN4â!¼&΂* }Ûµ‘ã”1Z%ynW—Má*ry¸bˆÍ›8s¾Ã³§ÏŸ@ƒÞ;tkabber-plugins/chess/pixmaps/classic/bq.gif000064400000000000000000000011471500237002100210140ustar00nobodynobodyGIF89a00ô$$D$D$DDD$D$DDDDDdDdDDddDdd„d„„„d„„„„¤„„¤¤¤ÄÄÄÄÜÄüüôüüüÿÿÿ!ù,00þ`%Ždižhª®lë¾p,ÏtmßøJíùL@Jö.¡i—$‰Ù{6ŸÇ+PzÃr+“Cà 5~iÏèb€LFé³o›%A)]>’& co#@MDIJijå+‰”9XÐÇ# ȤK¢¨ZòyQDÀIT ¶ŒyêRŒ@•Ð! Ȥ-68À5hÏOºJe$ ì‚“ °æx²VjÛ‡@8kcغ†ð>ŒµK`®mÃ><oaòóÐ`_ “$•[ŒÊnÍ¥}#HÜ9pQJд2 0´nÆ;Q¥Žñ#li»6ìL†–¨‚Û÷lörðÀÁïpZù=Ø»A× €€3s£º+ÎnA7@Ñ`y(½“óèÓ£×̾½û÷ðã+ ;tkabber-plugins/chess/pixmaps/classic/br.gif000064400000000000000000000007631500237002100210200ustar00nobodynobodyGIF89a00ô$$D$D$DDD$D$DDDDDdDdDDddDdd„d„„„d„„„„„¤„ÄÄÄÄÜÄüüôüüüÿÿÿ!ù,00þ %Ždižhª®lë¾p,Ïtmßx®ï|¯N p,NˆAˆ$7QÅqâ€BÓªuy›‡Ã@èµŃ ¡Dp’@XP°ÚÏwE—Ïí€V`zn}sOvag\6^j‰Š’5eˆ”_O™šPŸŠ‰¢6q¦œ¨=›ˆuœŸ©L~€’ b|>^a€ƒj¸¹Äv’ gcÁºÌΡÑÃx‚Ö˜ÑqË‚ ×ÁÙÅՓɆÚP` ëØ~œêœì7qŒõaÖùF±rg¯²Xf ¤Ófše™ ÀHÁ‚ 8‚cžê$:  xq8B‚òÇ8;Å„'LòTí¤µ*g”éuì• 0$/ör4ÆP¢,^œz‘ÏM_ÄAÀ’8'Ä{’Õ8†"½"Úë¡ÐbF h†+e]Ùˈ„¿ƒ‰F¸°áÈ+~;tkabber-plugins/chess/pixmaps/classic/icondef.xml000064400000000000000000000033441500237002100220550ustar00nobodynobody Classic 1.0 Chess Classic Theme. 2006-01-23 chess/bb bb.gif chess/bf bf.gif chess/bk bk.gif chess/bn bn.gif chess/bp bp.gif chess/bq bq.gif chess/br br.gif chess/wb wb.gif chess/wf wf.gif chess/wk wk.gif chess/wn wn.gif chess/wp wp.gif chess/wq wq.gif chess/wr wr.gif tkabber-plugins/chess/pixmaps/classic/wb.gif000064400000000000000000000007711500237002100210240ustar00nobodynobodyGIF89a00ô$$DD$D$DDDDDdDdDDddDdd„„d„„„„„¤„¤¤¤Ä¤ÄÄÄÄÄÜÄüüôüüüÿÿÿ!ù,00þà$Ždižhª®lë¾p,Ïtmßø*I9-^ö[,‚CWqw&UÅH¤ùd‚H• Èmêwx<aq)"4 nZ=‘‹ÇNi;Åv z{@Ovo…;‡sCvo;{~Š q{ …’7? R—¤Ž ©5?–…±¦‰¶¬—›»›³µ2?­İ¥Ž´ÉD¤ÎÄÆ› Ô/? Ù™™ ä—ÒÝÀÊᮤFòò¯`ì1àyŽÆ®³ÖåøÁˆØ(hÛÈ×î@W˜J èMŸ°ƒD%(%ÅLƒ (* Ü¤w <ø˜@A‘U–(pŽœ¯[– 8À³'‚ @Ó]KŒfÌ”ü‰Ša0 P£J­ø­Ÿ„#AAèèéTDXK}…êt "«; ‚–l»yp@“WÕËÆnrU¯["?Ðî !8pÙ18ÓY̸±ãÇ4B;tkabber-plugins/chess/pixmaps/classic/wf.gif000064400000000000000000000014721500237002100210270ustar00nobodynobodyGIF89a11ó Ö¢{Þ®{ç®sç¶{ï¶sÖ¦„Þ®ŒÞ²„Þ¶Œç¶„羌÷¾„ÿÿÿ!ù ,11þ0œ3Р#‡À>r(Ê4IÀ!«p¤Þû™”…iœ'…ci¢*ë%“Ih¾D q RÇáÛ=9œ•–š(.‰DfÛ!}´Ø Ûf&4ó’ÅJJ Ño£¬w€]&_bYo1qz f(EG‹dk+oQy4 :-ŽŽ3_adl£^ŒhX¢mm4„‡KuXqh ›:¬ b©|:ž€v‘BД a«Ô> f’Ь Æ×JÁ|”R'd¥ÓÒeÔÖת,PH'ÝŽÀ°¹pãc°ñ!eBO @î:Ø G)9db²`‚ïÇ!( ßy:±Œ‹]þ{&ð›¶bä‘ƬÍA´¤â‰} áÙÙ8Ï4œFÐxö®§ ‡×nÅP§Ó Nh !­1Q`ŠZ5êÕ³ª¼šªŽåõ©IRƒJü7b*O«âP5ˆ®@»\§ÅÔ'2¡‘*í,5÷AKÅœC÷Ä ®hGmÃX "D%îeÉR@§lÙP\7âˆI]O)3FÙqàÒEzHÚÉ@„]̆ê=ùKegOU .Q°ŒR¥Ma «Dƒv‰N¯×Öʱmñ_êoBêaȽ{´c6e¶“u»»ºo`½\jIÂ.)¡3Ç:öÌÀP{9æ%øG'Ž™Þ}„mé°Àëpßúù–™_­„„ÑbŽÄVÝ cƒÝX°/ñ`±.N!xN…%ƒTA{Èd`/!wxä¤BI³d‘BÐC!‚ŒíÆ`3é•ÎjÕ Æã?’æ‰Ì©c–B«©G:4;ñÅ‘dÒèvY*£29ü…‡düT·"NíVMS¤‘ç#®œ·šx®(˜e–pDæÃèÄiÖ³ž`/ZÆ·°àVdÂ%äÝÕâIcƒÁ€@eâŽ%Ã|çæ›lÖ犵ݶ¦–Äe¦ˆêAï°I«ð2@;tkabber-plugins/chess/pixmaps/classic/wk.gif000064400000000000000000000011141500237002100210250ustar00nobodynobodyGIF89a00ô$$D$D$DDD$D$DDDDddDdd„„„„„¤„¤„„¤¤„¤¤¤¤¤ÄĤÄÄÄÄÄÜÄüüôüüüÿÿÿ!ù,00þ`%Ždižhª®lë¾p,Ïtmßx®£µË”@À÷sõ„½"+(l•¼¦ª:ŸÔè0»bb¹%¦` Ǭì¹}AôdYÃ'½¹í¸vsWggx3 ‘c€s Mjv1Ai„ B§ §H0Œ¯ii ™›t®¥¹ž€„_U·¥¥£¾™¶Ìn€ -hžsn˃›̺xo ¥ÆQžÒoË}Ëon»l]ëäoƒƒBÌÍëA-‚€t'þ`’°/σàLÈ5ЃfŒ$pÞÄ HT 6¡„•Ê–5ôÅLH©mo´£%„3< ܨ€bS„†ª9HµXžj6¬Ô'U’À€”R€Ñi@¬@¢LÒpê“UÓœ¤_÷œé©F %€À0èrPP0¦‘¥† pd@䎽‡9¢ÔcG†u0Iõježa³p0)Õg©µº·HÈιn©^­ofAtÖõ¹¡2:XƒÀ1êž¹,N¼g‚VQ—”]¾ÜÒ@*J—^¦ºõëØ³×;tkabber-plugins/chess/pixmaps/classic/wn.gif000064400000000000000000000011061500237002100210310ustar00nobodynobodyGIF89a00ô$$D$DD$DDDDDdDddDdd„d„„„d„„„„„¤„¤„„¤¤„¤¤¤¤ÄÄĤÄÄÄÄÄÜÄüüôüüüÿÿÿ!ù,00þ %Ždižhª®lë¾p,Ïtm§Õ]çUë±^¥çˆA¡hlÊÁ÷kâ(e²¤ZQ•‚rB¡<SæwD.ÈeÉã±€V¿A`¯”'r wF=eCŠ~[‚„V=‰‹eqK…;P•C|jœ”–sdª3D”ŒdŠ[t”¤ š«¡‹ÉÅöS›.DÈÀ‰ ÃĹ/=ÓŒ—tSÛ×ÝNP¿Œ€rs·iç ÆA·—¶t ¸PP@8çÀÞP|æ4€R ‹€JæÁ!Åà™.PuôP²DI‚yâäX¼Xà@E"Äž”\à+¤\Тù¹CD ‚ õIh@ý"ló3¶t4ÂØÄYª):oô(psN JÖ(°djÕ¦FÅÀ“«TT™N «ªÙ•(ŽmA]bzSr€ÁUQÖÞ!Èk#L'µ¢ÚI€@gpTIÒÒ k‰Ô» dX Nx 8HAª·÷Xmy©r;Rë]qhƒÛ¸sëfÐÏ6.N¼¸ñÙ´“)_¾|óçУKŸN}M;tkabber-plugins/chess/pixmaps/classic/wp.gif000064400000000000000000000007321500237002100210370ustar00nobodynobodyGIF89a00ô$$D$DDD$D$DDDDDdDddDdd„„d„„„„„¤„¤¤¤¤¤Ä¤ÄÄĤÄÄÄÄÄÜÄüüôüüüÿÿÿ!ù,00þ`%Ždižhª®lë¾p,Ïtmßx®ï|ïÿ%ŠpD #Èä„R$Q€` 4"ÌæS€H$©[ÜZ#“ô$²0Œ³>J#°,…éH"à€óÌhCxlRd=[ w‚ {†a‰Šx ;ˆ”y ˜~:€”y—¡?O vi` —™‡a  Q ¢´Ä{¾Zǯ¬¿‘QÕÖ¨Z[ ġӇ[ i ÞMOs hk¼Wß9OÑWwk—³£ ­ŠkºÞш· ‚EÿÔ¦ „ â0ÓJÐ5ÏFÁ'c‹C‹Ô€ˆ­Æ“VX8]tÖ€A‚*_Ä맦fÍ‘ºd \¡Š¿"<*”賜/KÆØ’àÍW_ F…¥†¶X±`e µ«V¬c²0s­¬YkbÇ‚\ËV¹·pãÊK·H;tkabber-plugins/chess/pixmaps/classic/wq.gif000064400000000000000000000011301500237002100210310ustar00nobodynobodyGIF89a00ô$$D$D$DDD$DDDDdDddDdd„„„„„¤„¤¤¤Ä¤ÄÄÄÄÄÜÄüüôüüüÿÿÿ!ù,00þ $Ždižhª®lë¾p,ÏtmßøíùÀHöK0áдSŠ~Œ#Ijö~ÁQQtb©·â,‰oÀØ ¢SïCðPÃÉ4q{ä8ªkcN5_ƒ †@x/VZ† Š€d:Œj–O~’Z `…šl¥’˜I˜ªBf¨ƒLoR¥ PJ?º#q ¯w²%z¥q¥¬¹¬Qe{)_·»s?ŸÓµY,µ¡ei´RiQµÙ~*ÝT‡Š” iò¾Ì}š IÆaùñîAáÌùI /†.~º Z‹À/@€~¦9ÌÈO’®Œ@Dv¨Ÿ‹{µÖ€òÎÁ”4H2:“ñCÁ;*!XÐ2.Šê h°ƒ9sMŽîÐi’H›;Þ5™JÕ©¦D(I¥èÒ([­~ñÒ+ƒŒ0»ëF4iã¦=ã–&J@²wMÞ n*€@x*„JŠP ’Ç"˜ü˜ÇFF@ ºÔe̺-°H`SófÃ\VÚFˆÒ ÌÊ6[éŒâÐþjúôR„=Óµñc2lÈ,X€¼¹óns“·1uÈÒ¹qÞÎÝò’ïàËO~|;tkabber-plugins/chess/pixmaps/classic/wr.gif000064400000000000000000000010211500237002100210310ustar00nobodynobodyGIF89a00ô$$DD$DDDDdDDddDdd„d„„„d„„„„„¤„¤„„¤¤„¤¤¤¤¤Ä¤ÄÄĤÄÄÄÄÄÜÄüüôüüüÿÿÿ!ù,00þ %Ždižhª®lë¾p,Ïtmßx®ï|¯V@à(s•C @PT,Åré„"–ÃóViV$‚`À  “2W Ó€èˆkÕlweâè§+{}Rk\D‹ŒAR[6m„Œ–fyY } ¡K‘”—•›Jž:m¡ Âþ°=m³¢««ÆÈ>m”•×|DZ<½ר»ÓL ßà›ãÛ;½ç•€¸pí¼Þñ×›öH&¡×\²€úñãd éÔ1ü—gÄt|üù!©ÁÀJš8 (k‚çéj˜‡@­òBcY£M–„3åb‡„À€ >æÔÄÍ]\ZˉM‚ž‘hâ-åPM H%É¢—aÞ$LK–¬„MY „©yÌ) †É+¬Ø±£]–ráìÅ[cÏ:(Æ5…$a è.X¬`1ãÆu×ÎP§²åËÒ&7Ú̹ðÆÏ C‹MºôŠ;tkabber-plugins/chess/pixmaps/wooden000075500000000000000000000000001500237002100175135ustar00nobodynobodytkabber-plugins/chess/pixmaps/wooden/bb.gif000064400000000000000000000010641500237002100206450ustar00nobodynobodyGIF89a11ô@ @ @` @@@@``@  € @  @€`@ @@À à À @À@@à@@à`@à€@à €àÀ€àà€ÿÿÿ!ù,11þ`%Ždižhª®lë¾p,Ïtm¿@žßtÎ,ˆ/h$ `ˆË-Œß’¹Ò1’ˆƒ@GM9 !Ü.É—˜D¢‹€`òCOÕl ýL @vj oqPYJ„†?gwT b ¤œžL Qpp@ZA“ ¡?±u´eBx³¯¼Ye«„"9³ËÄA¬­:@YZÎ:Ð79 z–P²Q¿CE`áb¼’Ÿ:¡äÃZ¾ix ¨® ØöI”;^@8@°•¨v˜bx ™¡ñ-D×Å geQˆ¦¢G—²4 (y+ JY´°=›¥’›ˆ®l8£ÞÇviåÌÆ±G‘ì€ÂCHÙ 9  G©°efuQ/P4HA+MA,MB,OD6KC:TE7TI7ZK=YN8ÿÿÿ!ù ,11þ°3ÀÅ”]FAöQã¦!ˆn ’x&LÕ•qݲdj~©•ÎË  †C¨ˆÌi™ŒCbát†•B.† 3=õ®BN Á7B+A'(„7«ža ˆy@\V§7—6¶°!~°2 ™(Š©H¥ºRƒš«99 / ’j§¸ͺbi8*ŸÃ¤8n…¨Î$/b8ž´ãÂ,0{¤Ú‰Î#ÉŸT{VXkA„ Bl¬:iΖ"üP“òð¶.Àäã@-™¸"þC$€ PäÁ "Þh6ÅŠ WÜ©Åå^©¶pTðγ5;$ˆV ¥½&q¸pS?Žs|4:RÌÍÍPX´(‚ ¬¡ ò€8ÁXœLy@Ù–f µ<2] ëjBN@ãΉ¡i8¡-(”E‚$NA˜¦Ð’÷%X?B‡¶ô—jg Ÿ:ÖÎ ;t°±4¹‹BÈž ¼½2@ŽduÌØ¹:,‡m« K»šndS‘f€‚pULWó6óÂ7ÿ¹¼‚õÅ5j8›*œ«à;I0ŽÜ‰‹»vw¯ËK=¸ž¹ýµIô¯¿¢g ’i¤sú<þ÷ÝtiìÕš@¥UÚ.¿ ÷H(&¤´_8çÁCöôI0}Ü™v@-žV¡hÉV§>Œ!PHÀ@£‚êÙeéâ:'ÚÛšiL6k”5`F@M´X,Æ–3pï±!Z4Á‚A÷ðQAkŠ«ßfþN¡£ÞÑO+ûd*Ãc2e³³:¢ÂÈ0fšÕ5U¥“,+`3ôÆE=¸ª¸lPÚj1§‡z¦Œ™ÕÞDu`S;ÐEíÂ(}茜០ì *Vžê?U÷2A‚„}¸^._Z¼3„âË—ŸÆ©ÄûÊP•5ÚS¹õ2©†{?Øe@ç¡k·Ž£1WÆkH™!Ÿ0ØSëeH…Øå  ¡Ì§L|iàÔˆ(ª!¡ òP^‚xøã{¨åwÚp1¨ãà}¢ %º.'Ç‘?–äˆÍ±ÐÙ“PF¹TViå•Xf©å–\–;tkabber-plugins/chess/pixmaps/wooden/bp.gif000064400000000000000000000007711500237002100206670ustar00nobodynobodyGIF89a11ô@ @ @` @@@@``@  € @  @€`@ @@À à À @À@@à@@à`@à€@à €àÀ€àà€ÿÿÿ!ù,11þ`%Ždižhª®lë¾p,Ïtmßx®ï|ŸÀ Ðw 6È…Ò$Ž€Eò@2‡Á謈d"‘@ˆìÖ d@& 9R] ®p•ÄãdgvjD|nprtWiL† nesg„†’–vwz{JVIƒZ…lšJ®Ž©[«{AJi©yM=P €fUV’£:_ ÁÃT¦I ³ÉµÆ¨C‘ eWƒ×Ò‘bÞ¸¢]"šoæé]mdïèȾHcî¶ðb‰ãqÈ>pk2õ»g ž}ɼ™P®a„oPóWTl¼2΢  w,U[¢bŒZ¥VzL.ÕY"Y´a¦È™)W nÝj™S€*]êÞ.¤ aAïV>pX¯iŦUë&E‹,K„² 1™@­bIª¤gp™MóqÞ‹Vr™°êô¢Í°&„L¸°Kuˆ+^̸±ãÇ#B;tkabber-plugins/chess/pixmaps/wooden/bq.gif000064400000000000000000000011121500237002100206560ustar00nobodynobodyGIF89a11ô@ ` @ @` @`@@€€   € @  @À à à@@à`@à€@à €àÀ€àà€ÿÿÿ!ù,11þà$Ždižhª®lë¾p,Ïtm·@®·œÄâëÁ‡ÄÁòŒ« °X(RhiÌ)—‡ê°»I‘]Iòp4p±øì+,B¸q0 Mby d>c Lro€ U ™€‹1^r ¦y™˜©¨SdOŸ9‡pƒb ¤¥§™Š:69’´V·§˜¼¯¾Cö§ÈZ9 ~’£Å®Z"Ë~³Ø¼ÜÝËÖqâXÉÓ náØXåæîKñµWEÓ9Ô°—®J/#Þ0\ÓfV8‡°«±cƒ7ùJ¥ÊÂMƒ{£4v¡×­Z„ÎÈHašGòÜš”¥°,G ÂKq ºLì±lM)U’£iñgМ<ñ+z3ŸJ‰vR¬âÀ&Jl*w)5óëãHN:H 5¾6“#ÆÐ69X˜vI³aµÆ¼=KˆC¼ÏÄ¢2•ÀYÔ€,„À¾Œ”’(Õ¢ØjÞl륒·¦Ð9«®Ó˜Œ­J§ð>0DËØîÝÍ–² [n9B: 7€³L™;fŽ>ü¹s:$£KŸN½ºõë7B;tkabber-plugins/chess/pixmaps/wooden/br.gif000064400000000000000000000010541500237002100206640ustar00nobodynobodyGIF89a11ô @@ @ @` @@@@`@@€ @  @€@@ @@À à à@@à`@à€@à €àÀ€àà€ÿÿÿ!ù,11þà$Ždižhª®lë¾p,Ïtmßx®ï:àÿÀ ˆ0 Æ€à;.ˆÃÀW`ˆ È`8¦qA~Š ‹kv{3z•a‚“Œ, V[\x_sOd]yzl6~  ‡ePPj‹5]’”t—RaXœ4~ ¢„–˜™z©3« ®eO—™š¨Ež “¯Q±šŠµ¶?¿ÉÓÓS?; ‘‚Æ]á~ ÌâO˜Kvv™><>~_»Q¾Öñ"ž‚¯ëaÊõÁõàŸ/Zûø1xTð>=Ûx‰t “„ûšäª(…VDUŸ(:Ä7€O<7ªGJ è$J‘•zAüà   c’,IóÅ<\‘ìé¼²Äc HÐMÐ B»´ôTácØÒ¦žB-´fª‰eÂâueeœ+R½ò˶)VpcÕ•µDN-€=Qóæ-UËŸžõjGxIvìd%‚×@‚®zs*V/Y€Z6'¶ó‘­¤ÊÆèâ\ËY,©î+ú FCbËž­6¡íÛ¸sëÞÍ»÷Œ;tkabber-plugins/chess/pixmaps/wooden/icondef.xml000064400000000000000000000033421500237002100217250ustar00nobodynobody Wooden 1.0 Chess Wooden Theme. 2006-01-23 chess/bb bb.gif chess/bf bf.gif chess/bk bk.gif chess/bn bn.gif chess/bp bp.gif chess/bq bq.gif chess/br br.gif chess/wb wb.gif chess/wf wf.gif chess/wk wk.gif chess/wn wn.gif chess/wp wp.gif chess/wq wq.gif chess/wr wr.gif tkabber-plugins/chess/pixmaps/wooden/wb.gif000064400000000000000000000007021500237002100206700ustar00nobodynobodyGIF89a11ó €`@€€@ €@ €€À €ÀÀ€àÀ€àà€ÿûðÿÿÿ!ù ,11þPÉI«½8ëÍ»ÿ`(Ždi~@šždjÄʆÀ‘$ˆÌhZ†×Ž·QrA@E̸P!˜MÊ,P/Ý0»¿¾‡LœUŽ·œ7€ª ]ûàÎë/wW{GrTrw„d†Ag]j0T1{j]“0J2š‘”ITŽ˜”ª0Œ¡M*0J–±d5}7q€“A¯,¼¾¿‘¤šc3±†€¥TTº{QªÑKmZpŠj¸ËÔ}Þ­ Û[9žáâDopf¥¸¨dA½¦®Û.ÝøµŠ˜¾8íXEÃG̽r¶p,("… cPØ%\5¬"€^p¾2"[ƒRG*(!Kˆg@«l³®œÔP&$°d¥\º¤eh&qRÇR¡àÛ=9œ•–š(.DæÛ!}´Ø Ûf&4ó’ÅJJ Ño£¬w€]&_bYo1qz f(EG‹dk+oQy4 :-ŽŽ3_adl£^ŒhX¢mm4„‡KuXqh ›:¬ b©|:ž€v‘BД a«Ô> f’Ь Æ×JÁ|”R'd¥ÓÒeÔÖת,PH'ÝŽÀ°¹pãc°ñ!eBO @î:Ø G 9db²`‚ïÇ!( ßy:±Œ‹]þ{&ð›¶bä‘ƬÍA´¤â‰} áÙÙ8Ï4œFÐxö®§ ‡×nÅP§Ó Nh !­1Q`ŠZ5êÕ³ª¼šªŽåõ©IRƒJü7b*O«âP5ˆ.@»\§ÅÔ'2¡‘*í,5÷AKÅœC÷Ä ®hGmÃX "D%îeÉR@§lÙP\7âˆI]O)3FÙqàÒEzHÚÉ@„]̆ê=ùKegOU .Q°ŒR¥Ma «Dƒv‰N¯×Öʱmñ_êoBêaȽ{´c6e¶“u»»ºo`½\jIÂ.)¡3Ç:öÌÀP{9æ%øG'Ž™Þ}„mé°Àëpßúù–™_­„„ÑbŽÄVÝ cƒÝX°/ñ`±.N!xN…%ƒTA{Èd`/!wxä¤BI³d‘BÐC!‚ŒíÆ`3é•ÎjÕ Æã?’æ‰Ì©c–B«©G:4;ñÅ‘dÒèvY*£29ü…‡düT·"NíVMS¤‘ç#®œ·šx®(˜e–pDæÃèÄiÖ³ž`/ZÆQ·°àVdÂ%äÝÕâIcƒÁP@eâŽ%Ã|çæ›lÖ犵ݶ¦–Äe¦ˆêAï°I«ðr@;tkabber-plugins/chess/pixmaps/wooden/wk.gif000064400000000000000000000007261500237002100207070ustar00nobodynobodyGIF89a11ó@@@``@€`@€€@ €@€€€ €€  €À €ÀÀ€àÀ€àà€ÀÜÀÿûðÿÿÿ!ù,11þðÉI«½8ëÍ»ÿ`(Ždiz@šž¡š.Éà,(Iž(<ŸÐ5ÍŒ›Q‡â±3C$ Æåd¶hXs‹Þ"ZšU«ÃÁ`ì|gžW8„Åå²V§; xü  vx…†‡ˆ?@-)=8uw„‰Œ#n=t‚–‡Œ5)n ž”¡˜+A¥eY“9 …£Km r²³•¬R¯ ±t•­Rm Âh©P¿Àɺ»ÅPš,* cÛ°¨jÇ'¸UÛd§’²j®* Y©ˆ.È rŸ‡ÖGm d»v–ò¹:ÀïÔ§;…œýz5Æ_¯€ÃÙáçÀáK{E¢hcÄ.„mèõ;x±Ðp×&Ž1H a­ŽÌ£È’×{N¢ä“@ ·ëåØùáEråÌ­£ƒè†uÒ â…çR$*Š&;úSÚ4jy’ìpj€LBÓ”'ìP& €§×¥»—ˆ2i KªS‚—È~Ƹ±ãÇ#Kf;tkabber-plugins/chess/pixmaps/wooden/wn.gif000064400000000000000000000011461500237002100207070ustar00nobodynobodyGIF89a11ó €`@€€@ €@ €€  €À €ÀÀ€àÀ€àà€ÿûðÿÿÿ!ù ,11þpÉI«½8ëÍ»ÿ`(Ždib@ª®é¹­‰’$È<+¬[¥2rüÃï`“%T:•/H‚ú „@R$ µ˜1qÂU)E 1 h¸žãYí 8¼xA€a‚z"|1K†d_~S\gŠ!l~‘g2w\@RU-4g\h¯ F?pshœŒ¤W\²6K¢3gOº¬1™ÐcmÏ̪ ËN1®ÔÂ3KSO_‰{DzÞ~ÕcÄNfÏÉ» ˜ ë¡6t•B‰ó8°ê7ª™¡ž`ñãF޾`WHÏÈ- âDȉþ\*GF¿:ÈR©V£È )pÔ¤¯ÏÉ~¹DÖɈð%ÌpVºÇåf¥˜žùñ‰â™Œ ‚döç(€~–²­ÐÌÛ 6¡EaÁºkÐÀñq©Ò'9Oè2k:• ¼- SßQDh°mÔ$ ¹±|/ “ÚèW§ ýP ±•bî9²¸/2“/–/³’•©Iº’ëÄ]3šô4:©™ì =ݸ*¸sëÆM[…Ç!° ½Í=àK­Êœv¸ç?oßÏ£ÍxçØckÿÁ7Å“(ÅoïÛ òŸ®IË®]¸øT»bwÞÐð*›â·ßÿÙ¾ø7e‘%à€æ Ã&¨à‚ 6èàƒD;tkabber-plugins/chess/pixmaps/wooden/wp.gif000064400000000000000000000006631500237002100207140ustar00nobodynobodyGIF89a11ó`@@``@€`@€€@ €@ €€  €À €ÀÀ€àÀ€àà€ÀÜÀÿûðÿÿÿ!ù,11þÐÉI«½8ëÍ»ÿ`(Ždižhª®l›p,»W¬¸¡1=Á7ÅB‘("Ìç(„è‚Q<’ì°ˆz‡ „aÀ˺8…Wº ƒ¹…Nt×`ñ˜G¸w mnJ}~ Bƒ„zdK}:E”b‡sg~––X›,2ž:˜£¡3tNOx`78r¦(°j_`”µr¯0•—£™®gƒabÅ·tjm ¢¤Ï§ ‚ËoÅ×*[wÜÕ‘}8â ˜XLuºãň‰ RÜ¡Þß&h\÷ ù2Í[#Ù?=« ™;D¡a–üY8¢ 'JË&lfkŸ†-aºØÁøIÏŸ1=b@€@É—0®;IàWÈ̬V¬§ÏŸen†t82ãKU£4݆±©‘˜:ÞÅD§¨X³FÅ•”äTYA†Ù³hÓRd¶­Û·pãÊë!;tkabber-plugins/chess/pixmaps/wooden/wq.gif000064400000000000000000000007311500237002100207110ustar00nobodynobodyGIF89a11ó @@ @€`@€€@ €@ €€À €ÀÀ€àÀ€àà€ÿûðÿÿÿ!ù ,11þÉI«½8ëÍ»ÿ`(Ždiv@ª§˜* ‚$i É¢(²ÂÚ› p8 B`e[8uŠ„ qX„¸æs'•§¬‹WàP¡@=_üwk—ÛÅîz@4¾ßpU.CgF‚ŒD5…`‰FGŽoU‘$)”]x—™œ6);S‰‡¤Œ§@©\^g®¥±J3«µE·sJ³Q¾¿˜Â» ÅÆ£tÊ˽¢ÏÐ-*ÌON´µR*²¼Úi`x2Ö%+2R¶GVÊ”«­‹oçà0<­¥ö¨ª:D¹zƒDذ]MbÐÏŸ‰]cèÛ·É!ºNR  c>v‡ $»†1àDz„P}ŠøñØ‘E"GÊ!ng–d~x!ÊMœFÎè òé 9}è1*€è›‡Y5mV²ä*)Ó/C-@d©«×QV­rµxðͦ¥4©ÕD WZ´ÙœF iZŽ&‘Û;ÕkU¥"9`LXˆ€Ã(p˜¬ÁÇ#KžL¹²Á;tkabber-plugins/chess/pixmaps/wooden/wr.gif000064400000000000000000000007051500237002100207130ustar00nobodynobodyGIF89a11ó €`@€€@ €@ €€À €ÀÀ€àÀ€àà€ÿûðÿÿÿ!ù ,11þPÉI«½8ëÍ»ÿ`(Ždižhª®*à¾p,Ã(`ˆ®Qü0?@í–Ûõ€Á!¢ •'N· ø€ÂÝ4p,`M€‘@ä¾?¤Ú·˜kêq¸A €]vg%iL }pA€„wY?8ŠŒ]U†$ij{˜`€‘’ž#.¡m£q‚¦df¨©/d›¸N/+nŠŠnŒŒ~7³‡ˆ~Aƒ¹º, ªk°CΈnÒËNÖ×jmÚ]ÆKà™¦äY–9™ËêÝ=lEï‘ê량õ¤Ó;“,´Ð“Vê_>=Úô ÓA-ܰ6‰™-s˜Â…¹_sm²%ƒÄE–^ C¾ ¦äà /€Ü˜ùn¡+&!Г2ØL–Ê•c §rH*UúH¨S9/ŸØ!`(5fXÅÉ:J¯§›•ìmª¨Ùϳ4—6µÙéèÒ·$i¤vä医xóFíÆ·¯ß¿€ L";tkabber-plugins/chess/pixmaps/xboard000075500000000000000000000000001500237002100174775ustar00nobodynobodytkabber-plugins/chess/pixmaps/xboard/bb.gif000064400000000000000000000002661500237002100206340ustar00nobodynobodyGIF89a11ñ ÿÿÿ!ù,11‡”©Ëí£œ´Ú‹³ž¡oÝ…z£Uç%®¨éJ)7s[+÷œ#ûÝüv¹á/6WÉäɨ\~€ ê´é¼¡#(WKü‚<&™è:—‘jZÚ­ƒ›ÏÁ(9Ø–w9=]U“‡3—‡wW—‚¸ õ$H'#h§ö éShÓÆ¨é ×¸*:JêP;tkabber-plugins/chess/pixmaps/xboard/bf.gif000064400000000000000000000001331500237002100206310ustar00nobodynobodyGIF89a11ðw¢mÿÿÿ!ù,112„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇòL×öçúÎ÷þ ‡Ä¢ñˆÜ;tkabber-plugins/chess/pixmaps/xboard/bk.gif000064400000000000000000000003631500237002100206430ustar00nobodynobodyGIF89a11ñ ÿÿÿ!ù,11Ä”©Ëí£œ´Ú‹³¦a{Ñ}X@’âxfaj­,÷r¥3¦q׋Y‚´Žóõ~ÀÎÌø:æŒ3ÐAI|ôÂáz@ðØK­ˆGTѲlÞdœ˜Ô÷œ v×èÆÙÅfÂM*†\Î:Ðܩڃ–šµäöðˆ_ç½ýNRÇ„„Ç58ô“¦Âƒ”'Ç"´IYfÓe™‰È)WhÅãùsYWhs*˜Úç· ¥ÇR%;ûU›dTk;¶+©ë [º+¼è+ª“¬¼ÌÜì\Q;tkabber-plugins/chess/pixmaps/xboard/bp.gif000064400000000000000000000002451500237002100206470ustar00nobodynobodyGIF89a11ñ ÿÿÿ!ù,11v”©Ëí£œ´Ú‹³Þœ†ÿuHЉšZª º/È]Û ¬ïtŸÀµz±Ó!²åÐåL6£¹iTI=.‚-×€û‚‘Ü+Ö ¥†Tê'§-}Ããš9cw_ò÷¿Š÷·(X'èW˜qˆ(æø)9‰Q;tkabber-plugins/chess/pixmaps/xboard/bq.gif000064400000000000000000000004021500237002100206430ustar00nobodynobodyGIF89a11ñ ÿÿÿ!ù,11Ó”©Ëí£œ´Ú‹[Øyî |\òu‡"()šÂª¶qiÂs(K¹A‡LÏžlNýìê²ÎÞîþïR;tkabber-plugins/chess/pixmaps/xboard/br.gif000064400000000000000000000002621500237002100206500ustar00nobodynobodyGIF89a11ñ ÿÿÿ!ù,11ƒ”©Ëí£œ´Ú‹³Þ…Iø$F–Þ¹†hjº-ø¦ö _ø¾×üOÓ‰8*!ð·9ò:Ê[Ç0¬D™MÙ³j¥b§Ä-7é}BÃbïWc ÒeòխŪÙWÝœ6Ÿ¥úà ŒÖçg$(¸'H‘qè4áh³É’Hɨ–©¹ÉÙéù ÚP;tkabber-plugins/chess/pixmaps/xboard/icondef.xml000064400000000000000000000033421500237002100217110ustar00nobodynobody Xboard 1.0 Chess Xboard Theme. 2006-01-23 chess/bb bb.gif chess/bf bf.gif chess/bk bk.gif chess/bn bn.gif chess/bp bp.gif chess/bq bq.gif chess/br br.gif chess/wb wb.gif chess/wf wf.gif chess/wk wk.gif chess/wn wn.gif chess/wp wp.gif chess/wq wq.gif chess/wr wr.gif tkabber-plugins/chess/pixmaps/xboard/wb.gif000064400000000000000000000002661500237002100206610ustar00nobodynobodyGIF89a11ñÿÿÌÿÿÿ!ù,11‡”©Ëí£œ´Ú‹³ž¡oÝ…z£Uç%®¨éJ)7s[+÷œ#ûÝüv¹á/6WÉäɨ\~€ ê´é¼¡#(WKü‚<&™è:—‘jZÚ­ƒ›ÏÁ(9Ø–w9=]U“‡3—‡wW—‚¸ õ$H'#h§ö éShÓÆ¨é ×¸*:JêP;tkabber-plugins/chess/pixmaps/xboard/wf.gif000064400000000000000000000001331500237002100206560ustar00nobodynobodyGIF89a11ðÈÃeÿÿÿ!ù,112„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇòL×öçúÎ÷þ ‡Ä¢ñˆÜ;tkabber-plugins/chess/pixmaps/xboard/wk.gif000064400000000000000000000003631500237002100206700ustar00nobodynobodyGIF89a11ñÿÿÌÿÿÿ!ù,11Ä”©Ëí£œ´Ú‹³¦a{Ñ}X@’âxfaj­,÷r¥3¦q׋Y‚´Žóõ~ÀÎÌø:æŒ3ÐAI|ôÂáz@ðØK­ˆGTѲlÞdœ˜Ô÷œ v×èÆÙÅfÂM*†\Î:Ðܩڃ–šµäöðˆ_ç½ýNRÇ„„Ç58ô“¦Âƒ”'Ç"´IYfÓe™‰È)WhÅãùsYWhs*˜Úç· ¥ÇR%;ûU›dTk;¶+©ë [º+¼è+ª“¬¼ÌÜì\Q;tkabber-plugins/chess/pixmaps/xboard/wp.gif000064400000000000000000000002451500237002100206740ustar00nobodynobodyGIF89a11ñÿÿÌÿÿÿ!ù,11v”©Ëí£œ´Ú‹³Þœ†ÿuHЉšZª º/È]Û ¬ïtŸÀµz±Ó!²åÐåL6£¹iTI=.‚-×€û‚‘Ü+Ö ¥†Tê'§-}Ããš9cw_ò÷¿Š÷·(X'èW˜qˆ(æø)9‰Q;tkabber-plugins/chess/pixmaps/xboard/wq.gif000064400000000000000000000004021500237002100206700ustar00nobodynobodyGIF89a11ñÿÿÌÿÿÿ!ù,11Ó”©Ëí£œ´Ú‹[Øyî |\òu‡"()šÂª¶qiÂs(K¹A‡LÏžlNýìê²ÎÞîþïR;tkabber-plugins/chess/pixmaps/xboard/wr.gif000064400000000000000000000002621500237002100206750ustar00nobodynobodyGIF89a11ñÿÿÌÿÿÿ!ù,11ƒ”©Ëí£œ´Ú‹³Þ…Iø$F–Þ¹†hjº-ø¦ö _ø¾×üOÓ‰8*!ð·9ò:Ê[Ç0¬D™MÙ³j¥b§Ä-7é}BÃbïWc ÒeòխŪÙWÝœ6Ÿ¥úà ŒÖçg$(¸'H‘qè4áh³É’Hɨ–©¹ÉÙéù ÚP;tkabber-plugins/chess/proto000064400000000000000000000036761500237002100157200ustar00nobodynobodyRequest: 600 -- for all players 10 -- if on black side played Kasparov Positive response: or simply ? Move: queen 'pos' attribute contain column-separated list of coordinates of piece, that moved from first to last one. Coordinate is a comma-separated list of integers >= 0. Each turn can have few tags. Proposing draw: Accepting draw proposal: Resigning: Also we need and tags for games where we must put or remove pieces. can have 'type' and 'color' attributes. move, put & destroy tags can have some game-specific subtags Response: if move accepted, or error 'Not Allowed' if other side think that this move illegal (to avoid evil hackers that write clients that can do few moves instead of one or can move King like Queen) tkabber-plugins/ctcomp000075500000000000000000000000001500237002100147175ustar00nobodynobodytkabber-plugins/ctcomp/AUTHORS000064400000000000000000000000661500237002100160500ustar00nobodynobodyKonstantin Khomoutov tkabber-plugins/ctcomp/ChangeLog000064400000000000000000000021331500237002100165470ustar00nobodynobody2007-10-07 Konstantin Khomoutov * Heavily redone using bindtags and virtual events. * Behaviour and keybindings are made more close to Vim/Emacs. * Added possibility to show a menu with possible completions. * Numerous bugfixes. * README re-written. * Now at version 2.0. 2007-02-25 Konstantin Khomoutov * Fixed bug occured when chatting with JIDs containing the "%s" character. * Stub ChangeLog file rewritten to reflect this project' state. 2007-02-18 Konstantin Khomoutov * Added support for Customize. * Misc bugfixes. * Added preliminary support for virtual events. * Added preliminary support for event validity checking. * Support for per-chat state. * Matching algorythm reworked. * Added keybindings for committing and cancelling the current match. * Proper deinitialization of completion mode. * Added files: AUTHORS, README, TODO, INSTALL, ChangeLog and license.terms 2007-02-15 Konstantin Khomoutov * Initial version. tkabber-plugins/ctcomp/INSTALL000064400000000000000000000004641500237002100160330ustar00nobodynobodyAs usually, copy this directory under the ~/.tkabber/plugins directory so that you get a hierarchy like this: ~/.tkabber/plugins ~/.tkabber/plugins/ctcomp/ ~/.tkabber/plugins/ctcomp/ctcomp.tcl Restart Tkabber, to get the plugin loaded. Consult the README file for the details about using this plugin. tkabber-plugins/ctcomp/README000064400000000000000000000320361500237002100156620ustar00nobodynobody"Chat text completions" -- chat plugin for Tkabber. I. The idea This plugin adds support for "text completion" in Tkabber's chat input windows, i.e. it's possible to make Tkabber offer you possible completions of a current partially typed word in a chat input window. Possible completions are looked up in both the input window and the chat log window (also it's possible to provide custom list of matches, see the "Customization" section). This feature is loosely modeled after the text completion implementations found in Vim [1] and Emacs [2] text editors; default text completion key bindings of this plugin are the same as default key bindings for this feature in those editors (see the "Using" section). Note though, that while both Vim and Emacs offer you possible completions in a "recently typed -- first" manner, this plugin offers them in a dictionary-sorted order. II. Using At first, note that we'll use "Emacsish" notation of describing keystrokes for the sake of brevity. For those who isn't familiar with it here's a quick explanation: * "C" stands for "Control" key (also known as "Ctrl"). * "M" stands for "Meta" key (also known as "Alt" on some computers/OSes). * Any other key symbols stand for themselves. * Key combinations (groups of keys that are required to be pressed simultaneously) are specified as a list of appropriate key symbols joined by dashes ("-"). For example, "C-M-a" stands for Control, Meta (Alt) and "a" keys pressed simultaneously. There are two major modes of operation possible: * Requesting menu with possible completions. * Traversing the list of possible completions "in place". Entering each mode is requested by pressing one of the available keystrokes (discussed below) just after the first character(s) of a word you want to complete. For example, suppose the current chat log window and/or the current input window contain these words: abba, abbot, abbatisse. Now suppose you have just typed "ab" and want to complete it -- type C-M-/ to get the menu listing top 20 words starting from "ab" found in mentioned windows or type C-n to enter the "in place" mode and get the first proposed completion right at your insert cursor (with the completed part visually emphasized). Any completion mode can be cancelled -- you return to that piece of the word you started with. The completion keybindings will be described just in a moment. So, let's recap: * Type some first letters of the word you want to complete, * Engage one of the available completion modes. * Pick the required completion or chancel the completion mode. 1. Using the completion menu The menu presenting the first 20 completions can be by default posted using C-M-/ gesture. Select whatever completion you're happy with or cancel the menu by clicking outside of it or pressing the key. If you have selected a completion, the word being completed in the input window will be replaced by the selected completion. If you have cancelled the completion menu no change will be made to the input window. This gesture is modeled after the Emacs text editor. 2. Using the "in place" traversing of possible completions This mode is modeled after the similar Vim text editor's facility and so the C-n and C-p keystrokes are used. They switch the input windows into the "completion mode" and insert the first or the last completion from the list of proposed completions at the insert cursor. The completed part of the inserted word is highlighted. Also the M-/ keystroke is equivalent to C-n -- this one is taken from Emacs. While being in the completion mode you can: * Continue using the C-n (and/or M-/) and C-p keystrokes to iterate through the list of proposed completions "up" and "down", respectively. * Hit the Return (Enter) key to accept the currently displayed completion and return to the normal editing mode. * Hit the Escape key to remove the currently displayed completion and return to the normal mode. In other words this cancels the completon mode. Hitting any other key not listed above (i.e. a key which doesn't have special meaning in the completion mode) accepts the currently displayed completion, returns the input window to the normal mode, and then this keystroke is passed to the input window so that if it would result in a printable character being inserted this character will be inserted just after the completed word. III. Customization 1. Keystrokes All the relevant bindings in Tkabber's chat input windows are done via Tk virtual events [3] so they are easily customizable. Here are these events and their default bindings: * Event: <> Default bindings: , , Action: show next possible completion "in place", activate the "in place" completion mode beforehang, if currently in the normal mode. * Event: <> Default bindings: Action: same as above but shows the previous possible completion. * Event: <> Default keybindings: Action: accept the completion currently proposed "in place" and return to normal mode. * Event: <> Default keybindings: Action: remove the completion currently proposed "in place" and return to normal mode. * Event: <> Default keybindings: , Action: show menu with possible completions. If you're not familiar with Tk [event] [3] and [bind] [4] commands, here's a quick reference: * To bind your keystroke to a virtual event use event add <<...event name...>> <...keystroke spec...> For example, to bind posting of the completion menu to the F5 key, put this in the Tkabber's config file: event add <> * To unbind existing binding from a virtual event use event delete <<...event name...>> <...keystroke spec...> For example to make the completion menu only be posted by the F5 key, add also this lines to the config file: event delete <> event delete <> * To "substitute" (all) the default bindings for a virtual event by yours you can use something like this: event delete <> event add <> The first line kills all bindings for the virtual event, the second adds one new. Be sure to read and understand [3] and [4] before proceeding! Specification of keystrokes is explained in [4], all keysyms known to Tk are listed in [5]. Note that due to a bug in the Windows port of Tk users of non-US keymaps in this OS can have problems with these shortcuts. Please read "Working around Tk Windows keyboard bug" below for the (partial) solution to this problem. 2. Highlighting colors of "in place" completion Two Tk option database resources are used, both are of class "Chat": * Resource: Chat.textCompletionForeground Default: black Meaning: foreground color of the "proposed" tail of the word being completed "in place". * Resourec: Chat.textCompletionBackground Default: pink Meaning: same as above but for the background color. 3. Search pattern The search pattern used to search for possible completions in Tk Text widgets is available via the ::plugins::ctcomp::options(pattern) setting. This is an ARE [6] pattern containing the "%s" token which is replaced before searching by the part of the word being completed. This pattern makes the searching engine to look for "any word starting with the specified letters". Note that you should think twice before changing this pattern: for example the "in place" completion mode assumes that completions start from the prefix being completed and if you, say, change the pattern so that it will match in a middle of words, you'll get unexpected results in this completion mode. 4. Hooks This plugin has four "hooks" [7] that run when certain chat text completion events occur. They can be used to fine-tune the operation of this plugin. Beware though that using them requires some knowledge of Tcl. These hooks are: * chat_text_completion_start_hook This hook is run when the plugin enters the "in place" completion mode and is about to show the first proposed completion. Two arguments are appended to the hook script before evaluation: * handle to the chat in which the completion mode is entered (usually referred to as "chatid"). * word being completed. Primary intent of this hook (and its "mirror" hook chat_text_completion_end_hook) is to be used to provide some sort of additional visual hint to the user indicating active "in place" completion mode. * chat_text_completion_end_hook This hook is run when the plugin leaves the "in place" completion mode. One argument is appended to the hook script before evaluation -- handle to the chat ("chatid"). * chat_text_completion_matches_hook This hook is run when the plugin builds a list of possible completions for the word being completed, just after the proposed completions have been gathered from the relevant input and chat log windows. Four arguments are appended to the hook script before evaluation: * handle to the chat in which the completion mode is entered ("chatid"). * word being completed. * stack level containing the variable with proposed completions. * name of the variable holding a list with proposed completions. To modify this variable inside a proc use the [upvar] command, for example: proc gencomp {chatid what level compsName} { upvar $level $compsName comps lappend comps ${what}not ${what}sup } hook::add chat_text_completion_matches_hook gencomp Note that scripts handling this hook must not do any assumptions about the list of proposed completions they operate on (like sorted/unsorted, uniquennes of the words, etc). Also note that while any strings can be added to the list of possible completions using this hook, the "in place" completion mode assumes that each proposed completion starts from the word being completed; when this assumption is not honored, strange things may happen. * chat_text_completion_menu_hook This hook is run just before the menu with proposed completions is shown to the user. Three arguments are appended to the hook script before evaluation: * handle to the chat in which the completion mode is entered ("chatid"). * word being completed. * name of the menu window populated with proposed completions. This hook can be used to tweak the menu before it will be popped up. IV. Limitations and bugs Default keybindings and used by this plugin effectively "hijack" the same keybindings built into the chat input windows (they are used for moving forth and back through the history of outgoing messages). The and keybindings can be used for the input history management but if you want to continue using and for this while using this plugin, you should unbind and from the ctcomp plugin (and possibly bind the relevant actions to some other combinations of keys), like this: # Take and away from ctcomp: event delete <> event delete <> # Use and to do the same actions: event add <> event add <> No "automatic" completion ("propose completions as I type" found in certain text editing tools like Writer from the OpenOffice.org suite or some mobile phones) is possible. The same holds for the "in place" completion mode: typing a regular keystroke terminates the completion mode, not narrows the list of possible completions (this is Vim-like). No guarantees of proper work are made if the user fiddles with the searching regexp pattern. The same is true for the case when the user modifies the list of proposed completion via the relevant hook. Not all completions will be shown in the completion menu if its number exceeds the hard-coded limit. V. Working around Tk Windows keyboard bug Tk has unfortunate long-standing bug which prevents certain key combinations involving "letter keys" from working with "non-ASCII" keymaps (e.g. Russian keymap) in Windows. For example, C-n, C-p, M-/ and C-M-/ work when the US keymap is active but don't work when a Russian keymap is. Users of Russian keymaps may add following lines to their config.tcl file to work around this bug: event add <> event add <> event add <> event add <> This will make C-n, C-p and C-M-/ to work as expected on both US and Russian ("QWERTY") keymaps. Note that if you change the default bindings you may also need to modify these "mirror" bindings. Please refer to the Russian Tkabber wiki [8] for more info. VI. Links 1. http://vim.sf.net 2. http://www.gnu.org/software/emacs/ 3. http://www.tcl.tk/man/tcl8.4/TkCmd/event.htm 4. http://www.tcl.tk/man/tcl8.4/TkCmd/bind.htm 5. http://www.tcl.tk/man/tcl8.4/TkCmd/keysyms.htm 6. http://www.tcl.tk/man/tcl8.4/TclCmd/re_syntax.htm 7. http://tkabber.jabber.ru/files/doc/tkabber.html#s.extensibility 8. http://ru.tkabber.jabe.ru # vim:tw=64:et tkabber-plugins/ctcomp/TODO000064400000000000000000000006131500237002100154660ustar00nobodynobody* Some way should be invented to allow foreground color to be picked up from the input window itself, if not specified directly by the user. * Finding of a word being completed is a bit broken: for the string "mumble ??_" with the cursor denoted by "_" pressing C-n will yield "mumble ??" instead of "??" or "". So probably something needs to be rethought/fine-tuned. # vim:tw=64:et tkabber-plugins/ctcomp/VERSION000064400000000000000000000000371500237002100160460ustar00nobodynobodyVersion: 2.0 Date: 07-Oct-2007 tkabber-plugins/ctcomp/ctcomp.tcl000064400000000000000000000262161500237002100167760ustar00nobodynobody# ctcomp.tcl -- # # "Chat text completion -- Tkabber plugin. # # Author: Konstantin Khomoutov # # See "lisence.terms" for details about distribution. # Consult README for the information and usage guidelines. option add *Chat.textCompletionForeground $::defaultforeground widgetDefault if {$::darktheme} { option add *Chat.textCompletionBackground HotPink4 widgetDefault } else { option add *Chat.textCompletionBackground pink widgetDefault } package require msgcat namespace eval ctcomp { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered ctcomp]} { ::plugins::register ctcomp \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Chat text completion\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } } proc ctcomp::load {} { variable options set options(pattern) {\m%s\w+\M} bind_events bind_tags hook::add open_chat_post_hook [namespace current]::prepare hook::add close_chat_post_hook [namespace current]::cleanup foreach chatid [chat::opened] { prepare $chatid } } proc ctcomp::unload {} { foreach chatid [chat::opened] { unprepare $chatid } hook::remove open_chat_post_hook [namespace current]::prepare hook::remove close_chat_post_hook [namespace current]::cleanup unbind_tags unbind_events variable options unset options } proc ctcomp::bind_events {} { event add <> event add <> event add <> event add <> event add <> event add <> event add <> event add <> } proc ctcomp::unbind_events {} { event delete <> event delete <> event delete <> event delete <> event delete <> event delete <> event delete <> event delete <> } proc ctcomp::bind_tags {} { bind ChatTextCompInactive <> [namespace code { if {[matches in %W]} { activate %W match first next in %W } break }] bind ChatTextCompInactive <> [namespace code { if {[matches in %W]} { activate %W match first prev in %W } break }] bind ChatTextCompInactive <> [namespace code { if {[matches in %W]} { show_matches in %W reset_state %W } break }] bind ChatTextCompActive <> [namespace code { match next next in %W break }] bind ChatTextCompActive <> [namespace code { match next prev in %W break }] bind ChatTextCompActive <> [namespace code { accept %W deactivate %W break }] bind ChatTextCompActive <> [namespace code { cancel %W deactivate %W break }] bind ChatTextCompActive [namespace code { accept %W deactivate %W }] } proc ctcomp::unbind_tags {} { bind ChatTextCompInactive <> {} bind ChatTextCompInactive <> {} bind ChatTextCompInactive <> {} bind ChatTextCompActive <> {} bind ChatTextCompActive <> {} bind ChatTextCompActive <> {} bind ChatTextCompActive <> {} bind ChatTextCompActive {} } proc ctcomp::initialize iw { set btags [bindtags $iw] set ix [lsearch -exact $btags $iw] bindtags $iw [linsert $btags $ix ChatTextCompInactive] reset_state $iw } proc ctcomp::deinitialize iw { set btags [bindtags $iw] delete_from_list btags ChatTextCompInactive if {[delete_from_list btags ChatTextCompActive]} { cancel $iw } bindtags $iw $btags } proc ctcomp::delete_from_list {listVar elem} { upvar 1 $listVar L set ix [lsearch -exact $L $elem] if {$ix >= 0} { set L [lreplace $L $ix $ix] return 1 } else { return 0 } } proc ctcomp::activate iw { variable $iw upvar 0 $iw state set btags [bindtags $iw] set ix [lsearch -exact $btags ChatTextCompInactive] bindtags $iw [lreplace $btags $ix $ix ChatTextCompActive] hook::run chat_text_completion_start_hook $state(chatid) $state(what) } proc ctcomp::deactivate iw { variable $iw upvar 0 $iw state set btags [bindtags $iw] set ix [lsearch -exact $btags ChatTextCompActive] bindtags $iw [lreplace $btags $ix $ix ChatTextCompInactive] hook::run chat_text_completion_end_hook $state(chatid) reset_state $iw } proc ctcomp::prepare {chatid args} { set iw [chat::input_win $chatid] variable $iw upvar 0 $iw state set state(chatid) $chatid initialize $iw } proc ctcomp::unprepare {chatid} { set iw [chat::input_win $chatid] deinitialize $iw delete_state $iw } # NOTE This proc is called *after* the chat window is destroyed, # by the means of the close_chat_post_hook hook. # Getting the input window's name can be considered a hack # as there's no implied guarantee that this name can be obtained # and/or will have sensible meaning after the chat is closed. proc ctcomp::cleanup {chatid} { set iw [chat::input_win $chatid] delete_state $iw } proc ctcomp::delete_state {iw} { variable $iw unset $iw } proc ctcomp::reset_state iw { variable $iw upvar 0 $iw state set state(matches) [list] set state(last) "" set state(what) "" } proc ctcomp::accept iw { $iw tag remove ctcomp/submatch comp_start comp_end $iw mark unset comp_start $iw mark unset comp_end } proc ctcomp::cancel iw { $iw delete comp_start comp_end $iw mark unset comp_start $iw mark unset comp_end } proc ctcomp::pattern what { variable options format $options(pattern) [string map { \\ \\\\ [ \\[ ] \\] \{ \\\{ \} \\\} ( \\( ) \\) $ \\$ . \\. * \\* ? \\? } $what] } proc ctcomp::matches {"in" iw} { variable $iw upvar 0 $iw state upvar 0 state(what) what upvar 0 state(matches) matches set what [word from $iw] if {[string length $what] == 0} { return false } set matches [get_matches for $what in $iw] if {[llength $matches] == 0} { show info $iw "No match for $what" return false } return true } proc ctcomp::startOfPreviousWord {str start} { if {[string equal $start end]} { set start [string length $str] } if {[regexp -indices {\m(\w+)\W*$} \ [string range $str 0 [expr {$start - 1}]] -> word]} { return [lindex $word 0] } return -1 } proc ctcomp::word {"from" t} { set from [tk::TextPrevPos $t insert \ [namespace current]::startOfPreviousWord] $t get $from insert } proc ctcomp::get_matches {"for" what "in" iw} { variable $iw upvar 0 $iw state upvar 0 state(chatid) chatid set completions [concat \ [get_text_matches for $what in [chat::chat_win $chatid]] \ [get_text_matches for $what in $iw]] hook::run chat_text_completion_matches_hook \ $chatid $what #[info level] completions lsort -dictionary -unique $completions } proc ctcomp::get_text_matches {"for" what "in" t} { set pos 1.0 set matches [list] while 1 { set at [$t search -count len -regexp [pattern $what] $pos end] if {$at == {}} break lappend matches [$t get $at "$at + $len chars"] set pos [$t index "$at + 1 char"] } set matches } proc ctcomp::last L { expr {[llength $L] - 1} } proc ctcomp::getopt {iw opt} { variable $iw upvar 0 $iw state option get [chat::winid $state(chatid)] $opt Chat } proc ctcomp::tail {what match} { string range $match [string length $what] end } proc ctcomp::match {seq dir "in" iw} { variable $iw upvar 0 $iw state upvar 0 state(what) what upvar 0 state(matches) matches upvar 0 state(last) last switch -- $seq { first { switch -- $dir { next { set last 0 } prev { set last [last $matches] } } $iw mark set comp_start insert $iw mark gravity comp_start left } next { advance to $dir in $iw $iw delete comp_start comp_end } } set submatch [tail $what [lindex $matches $last]] $iw tag configure ctcomp/submatch \ -foreground [getopt $iw textCompletionForeground] \ -background [getopt $iw textCompletionBackground] $iw insert comp_start $submatch ctcomp/submatch $iw mark set comp_end insert $iw mark gravity comp_end right } proc ctcomp::advance {"to" where "in" iw} { variable $iw upvar 0 $iw state upvar 0 state(last) last upvar 0 state(matches) matches set end [last $matches] switch -- $where { next { incr last if {$last > $end} { set last 0 wraparound in $iw } } prev { incr last -1 if {$last < 0} { set last $end wraparound in $iw } } } } proc ctcomp::wraparound {"in" iw} { show info $iw "Wrapped around" } proc ctcomp::show_matches {"in" iw} { set m $iw.matches if {![winfo exists $m]} { menu $iw.matches -tearoff no -postcommand [list \ [namespace current]::repopulate_matches_menu $iw $m] } lassign [lrange [$iw bbox insert] 0 1] x y set x [expr {[winfo rootx $iw] + $x}] set y [expr {[winfo rooty $iw] + $y}] tk_popup $m $x $y 0 } proc ctcomp::repopulate_matches_menu {iw m} { variable $iw upvar 0 $iw state upvar 0 state(what) what $m delete 0 end set i 0 foreach match $state(matches) { if {[incr i] > 20} break $m add command -label $match -command [list \ [namespace current]::menu_insert_match $iw [tail $what $match]] } hook::run chat_text_completion_menu_hook $state(chatid) $state(what) $m } proc ctcomp::menu_insert_match {iw tail} { variable $iw $iw insert insert $tail } # $type should be either "info" or "error" proc ctcomp::show {type iw msg} { variable $iw upvar 0 $iw state upvar 0 state(chatid) chatid set jid [chat::get_jid $chatid] set cw [chat::chat_win $chatid] chat::add_message $chatid $jid $type $msg {} } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/ctcomp/license.terms000064400000000000000000000021121500237002100174700ustar00nobodynobodyCopyright (c) 2007 Konstantin Khomoutov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tkabber-plugins/ctcomp/msgs000075500000000000000000000000001500237002100156705ustar00nobodynobodytkabber-plugins/ctcomp/msgs/de.msg000064400000000000000000000004441500237002100170510ustar00nobodynobody# de.msg -- # # German messages for the Chat completion Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 13.11.2010 ::msgcat::mcset de "Whether the Chat text completion plugin is loaded." \ "Text-Vervollständigungs-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ctcomp/msgs/ru.msg000064400000000000000000000005641500237002100171120ustar00nobodynobody# ru.msg -- # # Russian messages for the Chat completion Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Whether the Chat text completion plugin is loaded." \ "Загружено ли раÑширение, включающее автодополнение в окнах разговора." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ctcomp/msgs/uk.msg000064400000000000000000000005651500237002100171040ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Chat completion Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Whether the Chat text completion plugin is loaded." \ "Чи завантажене розширеннÑ, Ñке вмикає Ð°Ð²Ñ‚Ð¾Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ñƒ вікнах розмов." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/custom-urls000075500000000000000000000000001500237002100157275ustar00nobodynobodytkabber-plugins/custom-urls/custom-urls.tcl000064400000000000000000000132261500237002100210130ustar00nobodynobody# custom-urls.tcl -- # # Custom URL Processing -- converts some strings into clickable URLs. # # Predefined examples include: # 1) XEP links: # xep-0013 or jep-0013 or jep-13 or xep-13 or jep13 or xep13 -> # http://www.xmpp.org/extensions/xep-0013.html # 2) RFC links: # rfc-1111 -> http://tools.ietf.org/html/rfc1111 # 3) Debian BTS links: # bug-345678 or #345678 -> # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=345678 # 4) Tkabber wiki links: # wiki:en/Main_Page -> # http://chiselapp.com/user/sgolovan/repository/tkabber-wiki/doc/tip/wiki/en/Main_Page.md # 5) Tkabber tickets or check-ins: # [3cd34577a3] -> # http://chiselapp.com/user/sgolovan/repository/tkabber/info/3cd34577a3 # # Matching is case insensitive. # # To define your own custom numbered URL add its definition (similar to URLs # below) to postload section of Tkabber config file. Note that the number must # match the second regexp match variable, and the whole link must match the # first match variable, so look closely at (?:) modifiers in the examples. # Also, note that the plugin uses extended regexp syntax. # # Example for config.tcl: # #proc postload {} { # set re {\y(bug(?:-|\s+)?\#?([0-9a-f]+))\y} # set ::plugins::custom-urls::url(tclbug) \ # [list [string map {bug tclbug} $re] \ # "http://core.tcl.tk/tcl/tktview?name=%s"] # set ::plugins::custom-urls::url(tkbug) \ # [list [string map {bug tkbug} $re] \ # "http://core.tcl.tk/tk/tktview?name=%s"] #} package require msgcat namespace eval custom-urls { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered custom-urls]} { ::plugins::register custom-urls \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Custom\ URLs plugin is\ loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable url array set url {} } ############################################################################### proc custom-urls::load {} { variable url set url(xep) [list {\y((?:jep|xep)(?:-|\s+)?(\d+))\y} \ "http://www.xmpp.org/extensions/xep-%04d.html"] set url(rfc) [list {\y(rfc(?:-|\s+)?(\d+))\y} \ "http://tools.ietf.org/html/rfc%d"] set url(debbug) [list {(?:^|\s)((?:(?:bug(?:-|\s+)?\#?)|\#)(\d+))\y} \ "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%d"] set url(wiki) [list {\y(wiki:([\w/]+)((?:\#[-._\w]+)?))\y} \ "https://chiselapp.com/user/sgolovan/repository/tkabber-wiki/doc/tip/wiki/%s.md%s"] set url(artifact) [list {(\[([0-9a-f]{4,40})\])} \ "https://chiselapp.com/user/sgolovan/repository/tkabber/info/%s"] ::richtext::register_entity custom-url \ -parser [namespace current]::process_urls \ -parser-priority 55 ::richtext::entity_state custom-url 1 } proc custom-urls::unload {} { variable url ::richtext::unregister_entity custom-url array unset url } ############################################################################### # This proc actually uses "url" rich text entity and relies on its # ability to render "titled" URLs. proc custom-urls::process_urls {atLevel accName} { upvar #$atLevel $accName chunks set out {} foreach {s type tags} $chunks { if {$type != "text"} { # pass through lappend out $s $type $tags continue } set ix 0; set xs 0; set xe 0; set num {} while {[spot_url $s $ix xs xe t num]} { if {$xs - $ix > 0} { # dump chunk before URL lappend out [string range $s $ix [expr {$xs - 1}]] $type $tags } set text [string range $s $xs $xe] set url [make_url $text $t $num] lappend out $url url $tags ::richtext::property_update url:title,$url $text set ix [expr {$xe + 1}] } if {[string length $s] - $ix > 0} { # dump chunk after URL lappend out [string range $s $ix end] $type $tags } } set chunks $out } ############################################################################### proc custom-urls::spot_url {what at startVar endVar typeVar numVar} { variable url upvar 1 $startVar xs $endVar xe $typeVar type $numVar num set res 0 foreach idx [array names url] { if {[regexp -expanded -nocase -indices -start $at -- \ [lindex $url($idx) 0] $what -> all \ match(1) match(2) match(3) match(4)]} { set type $idx set res 1 break } } if {!$res} { return false } lassign $all xs xe set num {} for {set i 1} {$i <= 4} {incr i} { lassign $match($i) ds de set str [string range $what $ds $de] if {[regexp {^\d+$} $str]} { lappend num [::force_integer $str] } else { lappend num $str } } return true } ############################################################################### proc custom-urls::make_url {text type num} { variable url if {[catch {set curl [format [lindex $url($type) 1] {*}$num]}]} { return "" } else { return $curl } } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/custom-urls/msgs000075500000000000000000000000001500237002100167005ustar00nobodynobodytkabber-plugins/custom-urls/msgs/pl.msg000064400000000000000000000004031500237002100200770ustar00nobodynobody# pl.msg -- # # Polish messages for Custom URLs Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Whether the Custom URLs plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ Custom URLs." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/custom-urls/msgs/ru.msg000064400000000000000000000005621500237002100201200ustar00nobodynobody# ru.msg -- # # Russian messages for Custom URLs Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Whether the Custom URLs plugin is loaded." \ "Загружено ли раÑширение реализующее Ñпециальные ÑÑылки в окне\ разговора." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/custom-urls/msgs/uk.msg000064400000000000000000000006321500237002100201070ustar00nobodynobody# uk.msg -- # # Ukrainian messages for Custom URLs Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Whether the Custom URLs plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ñке дозволÑÑ” викориÑтовувати Ñпеціальні\ поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ñƒ вікнах розмов." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/cyrillize000075500000000000000000000000001500237002100154405ustar00nobodynobodytkabber-plugins/cyrillize/cyrillize.tcl000064400000000000000000000124551500237002100202400ustar00nobodynobody# cyrillize.tcl -- # # This file iplements Cyrillize plugin for the Tkabber XMPP client. # It allows to fix English words accidentally typed in Russian keyboard # layout and vice versa. Only QWERTY/JCUKEN conversion is supported. package require msgcat namespace eval cyrillize { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered cyrillize]} { ::plugins::register cyrillize \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Cyrillize\ plugin is loaded."] \ -loadcommand \ [namespace code \ [list load [file join \ [file dirname [info script]] \ engrus.tbl]]] \ -unloadcommand [namespace code unload] return } custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup Cyrillize [::msgcat::mc "Cyrillize plugin options."] \ -group Plugins custom::defvar options(cyr) rus \ [::msgcat::mc "Cyrillic layout to switch to/from."] -group Cyrillize \ -type options -values [list rus [::msgcat::mc "Russian"] \ ukr [::msgcat::mc "Ukrainian"]] } proc cyrillize::load {filename} { load_table $filename event add <> event add <> event add <> event add <> bind Text <> \ [list [namespace current]::wordInText %W eng cyr] bind Text <> +break bind Text <> \ [list [namespace current]::wordInText %W cyr eng] bind Text <> +break bind Entry <> \ [list [namespace current]::wordInEntry %W eng cyr] bind Entry <> +break bind Entry <> \ [list [namespace current]::wordInEntry %W cyr eng] bind Entry <> +break bind BwEntry <> \ [list [namespace current]::wordInEntry %W eng cyr] bind BwEntry <> +break bind BwEntry <> \ [list [namespace current]::wordInEntry %W cyr eng] bind BwEntry <> +break } proc cyrillize::unload {} { variable convert bind Text <> {} bind Text <> {} bind Entry <> {} bind Entry <> {} bind BwEntry <> {} bind BwEntry <> {} event delete <> event delete <> event delete <> event delete <> catch {unset convert} } proc cyrillize::load_table {filename} { variable convert set fd [open $filename] fconfigure $fd -encoding utf-8 set convert_table [read $fd] close $fd foreach {e r u} $convert_table { set convert(eng,rus,$e) $r set convert(rus,eng,$r) $e set convert(eng,ukr,$e) $u set convert(ukr,eng,$u) $e } } proc cyrillize::do {s from to} { variable convert variable options if {$from eq "cyr"} { set from $options(cyr) } if {$to eq "cyr"} { set to $options(cyr) } set res "" foreach c [split $s ""] { if {[info exists convert($from,$to,$c)]} { append res $convert($from,$to,$c) } elseif {[info exists convert($from,$to,[string tolower $c])]} { append res [string toupper $convert($from,$to,[string tolower $c])] } else { append res $c } } return $res } proc cyrillize::wordInText {w from to} { if {[$w cget -state] != "normal"} return set ins [lindex [split [$w index insert] .] 1] set line [$w get "insert linestart" "insert lineend"] set wordstart [string wordstart $line [expr {$ins-1}]] set wordend [string length \ [string trimright \ [string range $line 0 [expr {$wordstart-1}]]]] set word [string range $line $wordstart [expr {$ins-1}]] set newword [do $word $from $to] $w delete "insert linestart +$wordstart chars" insert $w insert insert $newword $w mark set insert "insert linestart +$wordend chars" } proc cyrillize::wordInEntry {w from to} { if {[$w cget -state] != "normal"} return set ins [$w index insert] set line [$w get] set wordstart [string wordstart $line [expr {$ins-1}]] set wordend [string length \ [string trimright \ [string range $line 0 [expr {$wordstart-1}]]]] set word [string range $line $wordstart [expr {$ins-1}]] set newword [do $word $from $to] $w delete $wordstart insert $w insert insert $newword $w icursor $wordend } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/cyrillize/engrus.tbl000064400000000000000000000010121500237002100175170ustar00nobodynobodyq й й w ц ц e у у r к к t е е y н н u г г i ш ш o щ щ p з з \[ Ñ… Ñ… \{ Ð¥ Ð¥ \] ÑŠ Ñ— \} Ъ Ї a Ñ„ Ñ„ s Ñ‹ Ñ– d в в f а а g п п h Ñ€ Ñ€ j о о k л л l д д ; ж ж : Ж Ж ' Ñ Ñ” \" Э Є z Ñ Ñ x ч ч c Ñ Ñ v м м b и и n Ñ‚ Ñ‚ m ÑŒ ÑŒ , б б < Б Б . ÑŽ ÑŽ > Ю Ю ` Ñ‘ ’ ~ Ð ' ? , , / . . \ \ Ò‘ | / Ò tkabber-plugins/cyrillize/msgs000075500000000000000000000000001500237002100164115ustar00nobodynobodytkabber-plugins/cyrillize/msgs/ru.msg000064400000000000000000000016611500237002100176320ustar00nobodynobody# ru.msg -- # # Russian messages for the Cyrillize Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Cyrillic layout to switch to/from." \ "КирилличеÑÐºÐ°Ñ Ñ€Ð°Ñкладка Ñ/на которую надо переключатьÑÑ." ::msgcat::mcset ru "Cyrillize plugin options." "Параметры раÑширениÑ,\ переключающего раÑкладку поÑледнего набранного Ñлова." ::msgcat::mcset ru "Plugins options." "ÐаÑтройки раÑширений." ::msgcat::mcset ru "Russian" "РуÑÑкаÑ" ::msgcat::mcset ru "Ukrainian" "УкраинÑкаÑ" ::msgcat::mcset ru "Whether the Cyrillize plugin is loaded."\ "Загружено ли раÑширение, реализующее переключение раÑкладки\ Ð´Ð»Ñ Ð¿Ð¾Ñледнего набранного Ñлова." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/cyrillize/msgs/uk.msg000064400000000000000000000016501500237002100176210ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Cyrillize Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Cyrillic layout to switch to/from." \ "Розкладка до/з Ñкої потрібно переключатиÑÑ." ::msgcat::mcset uk "Cyrillize plugin options." "ÐалаштуваннÑ\ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ñке змінює розкладку оÑтаннього набраного Ñлова." ::msgcat::mcset uk "Plugins options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½ÑŒ." ::msgcat::mcset uk "Russian" "РоÑійÑька" ::msgcat::mcset uk "Ukrainian" "УкраїнÑька" ::msgcat::mcset uk "Whether the Cyrillize plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ñке дозвлÑÑ” змінити розкладку\ клавіатури Ð´Ð»Ñ Ð¾Ñтаннього набнаного Ñлова." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/debug000075500000000000000000000000001500237002100145205ustar00nobodynobodytkabber-plugins/debug/debug.tcl000064400000000000000000000265551500237002100164060ustar00nobodynobody# debug.tcl -- # # This file implements Debug plugin for the Tkabber XMPP client. # It allows one to log Tkabber debug messages into a file or a # log window. # # Author: Marshall T. Rose # Modifications: Badlop # Modifications: Sergei Golovan package require msgcat catch {package require Tclx} namespace eval debug { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered debug]} { ::plugins::register debug \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Debug live\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup Debug [::msgcat::mc "Debug live plugin options."] \ -group Plugins custom::defvar options(log_to_file) 0 \ [::msgcat::mc "Log debug messages to file %s." \ [file join $::configdir tkabber.log]] \ -group Debug \ -type boolean custom::defvar options(log_to_window) 0 \ [::msgcat::mc "Log debug messages to a separate tab/window."] \ -group Debug \ -type boolean variable modules {attline avatar browser browseurl caps chat conference custom disco emoticons filetransfer filters georoster gpg headlines hook http iface iq jidlink logger login message mucignore negotiate nick otr pconnect::https pconnect::socks4 pconnect::socks5 pep plugins popupmenu presence privacy pubsub register richtext roster search si ssj sw tclchat tkabber userinfo utils warning xmpp xmpp::transport::bosh xmpp::transport::poll zerobot} variable module foreach module $modules { custom::defvar debug($module) 0 \ [::msgcat::mc "Log debug messages for module %s to a tab/window." \ $module] \ -group Debug -type boolean } } proc debug::load {} { if {[llength [info procs ::debugmsg:debug]] == 0} { rename ::debugmsg ::debugmsg:debug proc ::debugmsg {module msg} \ "[namespace current]::debugmsg \$module \$msg" } foreach ns {otr pconnect::https pconnect::socks4 pconnect::socks5 xmpp xmpp::transport::bosh xmpp::transport::poll} { if {[llength [info procs ::${ns}::Debug]] > 0 && \ [llength [info procs ::${ns}::Debug:debug]] == 0} { rename ::${ns}::Debug ::${ns}::Debug:debug proc ::${ns}::Debug {xlib level str} \ "[namespace current]::debugmsg $ns \"\$xlib \$str\"" } } foreach ns {gpg} { if {[llength [info procs ::${ns}::Debug]] > 0 && \ [llength [info procs ::${ns}::Debug:debug]] == 0} { rename ::${ns}::Debug ::${ns}::Debug:debug proc ::${ns}::Debug {level str} \ "[namespace current]::debugmsg $ns \"\$str\"" } } if {[llength [info procs ::otr::smp::Debug]] > 0 && \ [llength [info procs ::otr::smp::Debug:debug]] == 0} { rename ::otr::smp::Debug ::otr::smp::Debug:debug proc ::otr::smp::Debug {level str} \ "[namespace current]::debugmsg otr \$str" } hook::add finload_hook [namespace current]::setup_menu if {![catch {.mainframe getmenu debug}]} { setup_menu } } proc debug::unload {} { variable debug_fd if {![catch {.mainframe getmenu debug}]} { destroy_menu } if {[info exists debug_fd]} { close $debug_fd unset debug_fd } if {[winfo exists .debug]} { destroy_win .debug } hook::remove finload_hook [namespace current]::setup_menu foreach ns {gpg otr pconnect::https pconnect::socks4 pconnect::socks5 xmpp xmpp::transport::bosh xmpp::transport::poll} { if {[llength [info procs ::${ns}::Debug:debug]] > 0} { rename ::${ns}::Debug "" rename ::${ns}::Debug:debug ::${ns}::Debug } } if {[llength [info procs ::otr::smp::Debug:debug]] > 0} { rename ::otr::smp::Debug "" rename ::otr::smp::Debug:debug ::otr::smp::Debug } if {[llength [info procs ::debugmsg:debug]] > 0} { rename ::debugmsg "" rename ::debugmsg:debug ::debugmsg } namespace delete [namespace current]::search } proc debug::destroy_menu {} { set m [.mainframe getmenu debug] if {![catch {$m index [::msgcat::mc "Debug"]} idx] && \ ![string equal $idx none]} { set mm [$m entrycget $idx -menu] $m delete $idx destroy $mm } if {![catch {$m index [::msgcat::mc "Profile on"]} idx] && \ ![string equal $idx none]} { $m delete $idx } if {![catch {$m index [::msgcat::mc "Profile report"]} idx] && \ ![string equal $idx none]} { $m delete $idx } } proc debug::setup_menu {} { variable options variable modules variable debug set m [.mainframe getmenu debug] if {![catch {$m index [::msgcat::mc "Debug"]} idx] && \ ![string equal $idx none]} { return } set buttons [menu $m.devel -tearoff $::ifacetk::options(show_tearoffs)] $buttons add checkbutton -label [::msgcat::mc "Log to file"] \ -variable [namespace current]::options(log_to_file) $buttons add checkbutton -label [::msgcat::mc "Log to window"] \ -variable [namespace current]::options(log_to_window) $buttons add separator set n 0 foreach module $modules { if {$n == 0} { set submodules [list $module] } else { lappend submodules $module } incr n if {$n == 8 || $module == [lindex $modules end]} { set n 0 set me [menu $buttons.[string map {:: #} [lindex $submodules 0]] \ -tearoff $::ifacetk::options(show_tearoffs)] $buttons add cascade \ -label [lindex $submodules 0]-[lindex $submodules end] \ -menu $me foreach mod $submodules { $me add checkbutton -label $mod \ -variable [namespace current]::debug($mod) } } } $m add cascade -label [::msgcat::mc "Debug"] -menu $buttons if {[llength [info commands profile]] > 0} { $m add command -label [::msgcat::mc "Profile on"] \ -command { profile -commands -eval on } $m add command -label [::msgcat::mc "Profile report"] \ -command { profile off profil profrep profil real profresults } } } proc debug::debugmsg {module msg} { variable options variable debug variable debug_fd if {$options(log_to_file)} { if {![info exists debug_fd]} { catch { file rename -force -- $::configdir/tkabber.log \ $::configdir/tkabber0.log } set debug_fd [open $::configdir/tkabber.log w] fconfigure $debug_fd -buffering line } puts $debug_fd [format "%s %-12.12s %s %s" \ [clock format [clock seconds] -format "%m/%d %T"] \ $module [lindex [info level -2] 0] $msg] } if {!$options(log_to_window) || ![info exists debug($module)] || \ !$debug($module)} { return } set dw .debug if {![winfo exists $dw]} { if {[catch { add_win $dw \ -title [::msgcat::mc Debug] \ -tabtitle [::msgcat::mc Debug] \ -class Chat \ -raisecmd [list [namespace current]::focus_body $dw] }]} { # Main window isn't created yet return } [ScrolledWindow $dw.sw] setwidget \ [Text $dw.body -yscrollcommand [list $dw.scroll set] \ -state disabled -takefocus 1] bind [Wrapped $dw.body] <1> [list [namespace current]::focus_body \ [double% $dw]] pack $dw.sw -side bottom -fill both -expand yes $dw.body tag configure module \ -foreground [option get $dw theyforeground Chat] $dw.body tag configure proc \ -foreground [option get $dw meforeground Chat] $dw.body tag configure error \ -foreground [option get $dw errforeground Chat] search::setup_panel $dw } $dw.body configure -state normal set scroll [expr {[lindex [$dw.body yview] 1] == 1}] $dw.body insert end \ [format "%s: %-12.12s" \ [clock format [clock seconds] -format "%m/%d %T"] \ $module] module " " set tag normal $dw.body insert end [lindex [info level -2] 0] proc " " $dw.body insert end [string trimright $msg] $tag $dw.body insert end "\n\n" if {$scroll} { $dw.body see end } $dw.body configure -state disabled } proc debug::focus_body {w} { focus [Wrapped $w.body] } namespace eval debug::search {} proc debug::search::open_panel {w sf} { pack $sf -side bottom -anchor w -fill x -before $w.sw update idletasks $w.body see end } proc debug::search::close_panel {w sf} { $w.body tag remove search_highlight 0.0 end pack forget $sf [namespace parent]::focus_body $w } proc debug::search::setup_panel {w} { set body $w.body $body mark set sel_start end $body mark set sel_end 0.0 set sf [plugins::search::spanel [winfo parent $body].search \ -searchcommand [list ::plugins::search::do_text_search $body] \ -closecommand [list [namespace current]::close_panel $w]] bind [Wrapped $body] <> \ [double% [list [namespace current]::open_panel $w $sf]] } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/debug/msgs000075500000000000000000000000001500237002100154715ustar00nobodynobodytkabber-plugins/debug/msgs/de.msg000064400000000000000000000020521500237002100166470ustar00nobodynobody# de.msg -- # # German message for the Debug Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 18.02.2009 ::msgcat::mcset de "Debug live plugin options." \ "Optionen für das 'Debug'-Plugin." ::msgcat::mcset de "Debug" "Debuggen" ::msgcat::mcset de "Log debug messages for module %s to a tab/window." \ "'Debug'-Nachrichten für Modul '%s' in Tab/Fenster schreiben." ::msgcat::mcset de "Log debug messages to a separate tab/window." \ "'Debug'-Nachrichten in separates Tab/Fenster schreiben." ::msgcat::mcset de "Log debug messages to file %s." \ "'Debug'-Nachrichten in Datei %s schreiben." ::msgcat::mcset de "Log to file" "In Datei schreiben" ::msgcat::mcset de "Log to window" "In Tab/Fenster schreiben" ::msgcat::mcset de "Plugins options." "Optionen für Plugins." ::msgcat::mcset de "Profile on" "'Profiling' aktivieren" ::msgcat::mcset de "Profile report" "'Profiling'-Bericht" ::msgcat::mcset de "Whether the Debug live plugin is loaded." \ "'Debug'-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/debug/msgs/es.msg000064400000000000000000000020271500237002100166700ustar00nobodynobody# es.msg -- # # Spanish message for the Debug Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "Debug live plugin options." \ "Opciones del plugin de depurado en vivo." ::msgcat::mcset es "Debug" "Depurar" ::msgcat::mcset es "Log debug messages for module %s to a tab/window." \ "Mostrar mensajes de depurado para el módulo %s en una\ pestaña/ventana." ::msgcat::mcset es "Log debug messages to a separate tab/window." \ "Mostrar mensajes de depurado en una pestaña/ventana separada." ::msgcat::mcset es "Log debug messages to file %s." \ "Guardar mensajes de depurado en el fichero %s." ::msgcat::mcset es "Log to file" "Guardar en fichero" ::msgcat::mcset es "Log to window" "Mostrar en ventana" ::msgcat::mcset es "Plugins options." "Opciones de plugins." ::msgcat::mcset es "Profile on" "Perfil" ::msgcat::mcset es "Profile report" "Informe de perfil" ::msgcat::mcset es "Whether the Debug live plugin is loaded." \ "Cargar el plugin Debug live." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/debug/msgs/pl.msg000064400000000000000000000020231500237002100166700ustar00nobodynobody# pl.msg -- # # Polish messages for the Debug Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Debug" "Debugowanie" ::msgcat::mcset pl "Debug live plugin options." \ "Ustawienia wtyczki debugowania." ::msgcat::mcset pl "Log debug messages for module %s to a tab/window." \ "Zapisuj komunikaty debugowania dla moduÅ‚u %s do karty/okna." ::msgcat::mcset pl "Log debug messages to a separate tab/window." \ "Zapisuj komunikaty debugowania do oddzielnej karty/okna." ::msgcat::mcset pl "Log debug messages to file %s." \ "Zapisuj komunikaty debugowania do pliku %s." ::msgcat::mcset pl "Log to file" "Zapisuj do pliku" ::msgcat::mcset pl "Log to window" "Zapisuj do okna" ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "Profile on" "Włącz profil" ::msgcat::mcset pl "Profile report" "Raport profilu" ::msgcat::mcset pl "Whether the Debug live plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ debugowania." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/debug/msgs/ru.msg000064400000000000000000000024551500237002100167140ustar00nobodynobody# ru.msg -- # # Russian messages for the Debug Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Debug" "Отладка" ::msgcat::mcset ru "Debug live plugin options." "ÐаÑтройки раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð¾Ñ‚Ð»Ð°Ð´ÐºÐ¸." ::msgcat::mcset ru "Log debug messages for module %s to a tab/window." \ "СохранÑть отладочные ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ %s во вкладку или окно." ::msgcat::mcset ru "Log debug messages to a separate tab/window." \ "СохранÑть отладочные ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð² отдельную вкладку или окно." ::msgcat::mcset ru "Log debug messages to file %s." \ "СохранÑть отладочные ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð² файл %s." ::msgcat::mcset ru "Log to file" "СохранÑть в файл" ::msgcat::mcset ru "Log to window" "СохранÑть в окно" ::msgcat::mcset ru "Plugins options." "ÐаÑтройки раÑширений." ::msgcat::mcset ru "Profile on" "Включить профилирование" ::msgcat::mcset ru "Profile report" "Отчет о профилировании" ::msgcat::mcset ru "Whether the Debug live plugin is loaded." \ "Загружено ли раÑширение отладки." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/debug/msgs/uk.msg000064400000000000000000000026131500237002100167010ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Debug Tkabber plugin. # # Author: Artem Bondarenko # Author: Sergei Golovan ::msgcat::mcset uk "Profile on" "Увімкнути профілюваннÑ" ::msgcat::mcset uk "Profile report" "Звіт про профілюваннÑ" ::msgcat::mcset uk "Debug" "ÐалагодженнÑ" ::msgcat::mcset uk "Debug live plugin options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð½Ð°Ð»Ð°Ð³Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ." ::msgcat::mcset uk "Log debug messages for module %s to a tab/window." \ "Зберігати налагоджувальні Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ %s у вкладку чи вікно." ::msgcat::mcset uk "Log debug messages to a separate tab/window." \ "Зберігати налагоджувальні Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñƒ вікрему вкладку чи вікно." ::msgcat::mcset uk "Log debug messages to file %s." \ "Зберігати налагоджувальні Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñƒ файл %s." ::msgcat::mcset uk "Log to file" "Зберігати в файл" ::msgcat::mcset uk "Log to window" "Зберігати у вікно" ::msgcat::mcset uk "Plugins options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½ÑŒ." ::msgcat::mcset uk "Whether the Debug live plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð½Ð°Ð»Ð°Ð³Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ejabberd000075500000000000000000000000001500237002100151705ustar00nobodynobodytkabber-plugins/ejabberd/ejabberd.tcl000064400000000000000000000404061500237002100175150ustar00nobodynobody# ejabberd.tcl -- # # Ejabebrd administration plugin. package require msgcat namespace eval ejabberd { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered ejabberd]} { ::plugins::register ejabberd \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Ejabberd\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } custom::defvar ejabberd_server_list {} \ [::msgcat::mc "List of ejabberd servers."] \ -group Hidden } proc ejabberd::load {} { variable NS_ECONFIGURE variable data set data(windows) {} set NS_ECONFIGURE "http://ejabberd.jabberstudio.org/protocol/configure" hook::add finload_hook [namespace current]::setup_menu disco::browser::register_feature_handler $NS_ECONFIGURE \ [namespace current]::open_win \ -desc [list * [::msgcat::mc "Administrate ejabberd"]] disco::browser::register_feature_handler ejabberd:config \ [list ::data::request_data ejabberd:config] -node 1 \ -desc [list * [::msgcat::mc "Configure service"]] setup_menu } proc ejabberd::unload {} { variable NS_ECONFIGURE variable data disco::browser::unregister_feature_handler ejabberd:config disco::browser::unregister_feature_handler $NS_ECONFIGURE catch { set m [.mainframe getmenu admin] set idx [$m index [::msgcat::mc "Administrate ejabberd..."]] $m delete $idx } catch { destroy .ejabberdserver } foreach w $data(windows) { destroy_win $w } hook::remove finload_hook [namespace current]::setup_menu catch {unset data} catch {unset NS_ECONFIGURE} } proc ejabberd::setup_menu {} { catch { set m [.mainframe getmenu admin] $m add command -label [::msgcat::mc "Administrate ejabberd..."] \ -command [namespace current]::ask_server_dialog } } proc ejabberd::ask_server_dialog {} { global ejabberd_server global ejabberd_xlib variable ejabberd_server_list set gw .ejabberdserver catch { destroy $gw } if {[llength [connections]] == 0} return set ejabberd_xlib [connection_jid [lindex [connections] 0]] Dialog $gw -title [::msgcat::mc "ejabberd server"] -anchor e \ -default 0 -cancel 1 set gf [$gw getframe] grid columnconfigure $gf 1 -weight 1 if {[llength $ejabberd_server_list]} { set ejabberd_server [lindex $ejabberd_server_list 0] } Label $gf.ljid -text [::msgcat::mc "Server JID:"] Combobox $gf.jid \ -textvariable ejabberd_server \ -values $ejabberd_server_list \ -width 35 grid $gf.ljid -row 0 -column 0 -sticky e grid $gf.jid -row 0 -column 1 -sticky ew if {[llength [connections]] > 1} { foreach c [connections] { lappend connections [connection_jid $c] } set ejabberd_xlib [lindex $connections 0] Label $gf.lxlib -text [::msgcat::mc "Connection:"] Combobox $gf.xlib \ -textvariable ejabberd_xlib \ -values $connections \ -editable 0 grid $gf.lxlib -row 1 -column 0 -sticky e grid $gf.xlib -row 1 -column 1 -sticky ew } $gw add -text [::msgcat::mc "Administrate"] \ -command "[namespace current]::administrate $gw" $gw add -text [::msgcat::mc "Cancel"] -command "destroy $gw" $gw draw $gf.jid } proc ejabberd::administrate {gw} { global ejabberd_server global ejabberd_xlib variable ejabberd_server_list destroy $gw set ejabberd_server_list \ [update_combo_list $ejabberd_server_list $ejabberd_server 10] foreach c [connections] { if {[connection_jid $c] == $ejabberd_xlib} { set xlib $c } } if {![info exists xlib]} return open_win $xlib $ejabberd_server } proc ejabberd::open_win {xlib jid args} { variable data set w [win_id ejabberd $xlib:$jid] if {[winfo exists $w]} { raise_win $w return } lappend data(windows) $w set title [::msgcat::mc "%s administration" $jid] add_win $w -title $title \ -tabtitle $jid \ -class Ejabberd \ -raise 1 set nb [Notebook $w.nb] pack $nb -fill both -expand yes # Binding $nb, not $w to avoid multiple calls if $w is a toplevel bind $nb [list [namespace current]::cleanup $xlib $jid $w] foreach {page title} \ [list main [::msgcat::mc "Main"] \ nodes [::msgcat::mc "Nodes"] \ reg [::msgcat::mc "Registration"] \ access [::msgcat::mc "Access"] \ last [::msgcat::mc "Last Activity"]] { set f [$nb insert end $page -text $title] fill_page_$page $f $xlib $jid } $nb raise main } proc ejabberd::cleanup {xlib jid w} { variable data catch {unset data($xlib,$jid,total_users)} catch {unset data($xlib,$jid,online_users)} catch {unset data($xlib,$jid,running_nodes)} catch {unset data($xlib,$jid,stopped_nodes)} catch {unset data($xlib,$jid,outgoing_s2s)} catch {unset data($xlib,$jid,welcome_subj)} catch {unset data($xlib,$jid,welcome_body)} catch {unset data($xlib,$jid,reg_watchers)} catch {unset data($xlib,$jid,acls)} catch {unset data($xlib,$jid,access_rules)} catch {unset data($xlib,$jid,last)} catch {unset data($xlib,$jid,last_int)} set idx [lsearch -exact $data(windows) $w] if {$idx >= 0} { set data(windows) [lreplace $data(windows) $idx $idx] } } proc ejabberd::add_grid_record {xlib jid info name desc row} { Label $info.l$name -text $desc Label $info.v$name \ -textvariable [namespace current]::data($xlib,$jid,$name) grid $info.l$name -row $row -column 0 -sticky e grid $info.v$name -row $row -column 1 -sticky w } proc ejabberd::add_grid_edit {xlib jid info name desc row} { Label $info.l$name -text $desc Entry $info.v$name \ -textvariable [namespace current]::data($xlib,$jid,$name) grid $info.l$name -row $row -column 0 -sticky e grid $info.v$name -row $row -column 1 -sticky we } proc ejabberd::add_grid_text {xlib jid info name desc row} { Label $info.l$name -text $desc set sw [ScrolledWindow $info.s$name -scrollbar vertical] Text $info.v$name -height 6 -wrap word $sw setwidget $info.v$name grid $info.l$name -row $row -column 0 -sticky e grid $info.s$name -row $row -column 1 -sticky we } proc ejabberd::fill_page_main {f xlib jid} { variable data set info [Frame $f.info] pack $info -side top -anchor w -fill both grid columnconfigure $info 1 -weight 2 add_grid_record $xlib $jid $info total_users \ [::msgcat::mc "Registered users:"] 0 add_grid_record $xlib $jid $info online_users \ [::msgcat::mc "Online users:"] 1 add_grid_record $xlib $jid $info running_nodes \ [::msgcat::mc "Running nodes:"] 2 add_grid_record $xlib $jid $info stopped_nodes \ [::msgcat::mc "Stopped nodes:"] 3 add_grid_record $xlib $jid $info outgoing_s2s \ [::msgcat::mc "Outgoing S2S:"] 4 set reload \ [Button $f.reload -text [::msgcat::mc "Reload"] \ -command [list [namespace current]::reload_page_main \ $f $xlib $jid]] pack $reload -side bottom -anchor e reload_page_main $f $xlib $jid } proc ejabberd::reload_page_main {f xlib jid} { variable NS_ECONFIGURE ::xmpp::sendIQ $xlib get \ -query [::xmpp::xml::create info \ -xmlns $NS_ECONFIGURE] \ -to $jid \ -command [list [namespace current]::parse_main_info $f $xlib $jid] } proc ejabberd::parse_main_info {f xlib jid status xml} { variable data if {![string equal $status ok]} { return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels set data($xlib,$jid,total_users) \ [::xmpp::xml::getAttr $attrs registered-users] set data($xlib,$jid,online_users) \ [::xmpp::xml::getAttr $attrs online-users] set data($xlib,$jid,running_nodes) \ [::xmpp::xml::getAttr $attrs running-nodes] set data($xlib,$jid,stopped_nodes) \ [::xmpp::xml::getAttr $attrs stopped-nodes] set data($xlib,$jid,outgoing_s2s) \ [::xmpp::xml::getAttr $attrs outgoing-s2s-servers] } proc ejabberd::fill_page_nodes {f xlib jid} { } proc ejabberd::fill_page_reg {f xlib jid} { variable data set info [Frame $f.info] pack $info -side top -anchor w -fill both grid columnconfigure $info 1 -weight 2 add_grid_edit $xlib $jid $info welcome_subj \ [::msgcat::mc "Welcome message subject:"] 0 add_grid_text $xlib $jid $info welcome_body \ [::msgcat::mc "Welcome message body:"] 1 add_grid_text $xlib $jid $info reg_watchers \ [::msgcat::mc "Registration watchers:"] 2 #set set_b [button $f.set -text [::msgcat::mc "Set"]] #pack $set_b -side right -anchor se set reload \ [Button $f.reload -text [::msgcat::mc "Reload"] \ -command [list [namespace current]::reload_page_reg \ $f $xlib $jid]] pack $reload -side right -anchor se reload_page_reg $f $xlib $jid } proc ejabberd::reload_page_reg {f xlib jid} { variable NS_ECONFIGURE ::xmpp::sendIQ $xlib get \ -query [::xmpp::xml::create welcome-message \ -xmlns $NS_ECONFIGURE] \ -to $jid \ -command [list [namespace current]::parse_welcome_message \ $f $xlib $jid] ::xmpp::sendIQ $xlib get \ -query [::xmpp::xml::create registration-watchers \ -xmlns $NS_ECONFIGURE] \ -to $jid \ -command [list [namespace current]::parse_registration_watchers \ $f $xlib $jid] } proc ejabberd::parse_welcome_message {f xlib jid status xml} { variable data set wsubj $f.info.vwelcome_subj set wbody $f.info.vwelcome_body if {![winfo exists $wsubj]} { return } if {![string equal $status ok]} { return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels set subj "" set body "" foreach subel $subels { ::xmpp::xml::split $xml stag sxmlns sattrs scdata ssubels switch -- $stag { subject {set subj $scdata} body {set body $scdata} } } set data($xlib,$jid,welcome_subj) $subj set data($xlib,$jid,welcome_body) $body $wbody delete 0.0 end $wbody insert 0.0 $body } proc ejabberd::parse_registration_watchers {f xlib jid status xml} { variable data set wwatchers $f.info.vreg_watchers if {![winfo exists $wwatchers]} { return } if {![string equal $status ok]} { return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels set jids {} foreach subel $subels { ::xmpp::xml::split $xml stag sxmlns sattrs scdata ssubels switch -- $tag1 { jid {lappend jids $scdata} } } set data($xlib,$jid,reg_watchers) $jids $wwatchers delete 0.0 end $wwatchers insert 0.0 [join $jids \n] } proc ejabberd::fill_page_access {f xlib jid} { variable data set info [Frame $f.info] pack $info -side top -anchor w -fill both grid columnconfigure $info 1 -weight 2 add_grid_text $xlib $jid $info acls \ [::msgcat::mc "ACLs:"] 0 add_grid_text $xlib $jid $info access_rules \ [::msgcat::mc "Access rules:"] 1 #set set_b [button $f.set -text [::msgcat::mc "Set"]] #pack $set_b -side right -anchor se set reload \ [Button $f.reload -text [::msgcat::mc "Reload"] \ -command [list [namespace current]::reload_page_access \ $f $xlib $jid]] pack $reload -side right -anchor se reload_page_access $f $xlib $jid } proc ejabberd::reload_page_access {f xlib jid} { variable NS_ECONFIGURE ::xmpp::sendIQ $xlib get \ -query [::xmpp::xml::create acls \ -xmlns $NS_ECONFIGURE] \ -to $jid \ -command [list [namespace current]::parse_access acls $f $xlib $jid] ::xmpp::sendIQ $xlib get \ -query [::xmpp::xml::create access \ -xmlns $NS_ECONFIGURE] \ -to $jid \ -command [list [namespace current]::parse_access access_rules \ $f $xlib $jid] } proc ejabberd::parse_access {var f xlib jid status xml} { variable data set w $f.info.v$var if {![winfo exists $w]} { return } if {![string equal $status ok]} { return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels set data($xlib,$jid,$var) $cdata $w delete 0.0 end $w insert 0.0 $cdata } proc ejabberd::fill_page_last {f xlib jid} { variable data set info [Frame $f.info] pack $info -side top -anchor w -fill both -expand yes #grid columnconfigure $info 1 -weight 2 #add_grid_text $xlib $jid $info acls \ # [::msgcat::mc "ACLs:"] 0 #add_grid_text $xlib $jid $info access_rules \ # [::msgcat::mc "Access rules:"] 1 Label $info.lplot \ -text [::msgcat::mc \ "Number of users that used this service N days ago:"] pack $info.lplot -side top -anchor w set sw [ScrolledWindow $info.sw] pack $sw -side top -fill both -expand yes set plot [Canvas $info.plot -background white] $sw setwidget $plot set data($xlib,$jid,last) {} set data($xlib,$jid,last_int) 0 set integral \ [Checkbutton $f.integral -text [::msgcat::mc "Integral"] \ -variable [namespace current]::data($xlib,$jid,last_int) \ -command [list [namespace current]::redraw_last $f $xlib $jid]] pack $integral -side left -anchor se set reload \ [Button $f.reload -text [::msgcat::mc "Reload"] \ -command [list [namespace current]::reload_page_last \ $f $xlib $jid]] pack $reload -side right -anchor se } proc ejabberd::reload_page_last {f xlib jid} { variable NS_ECONFIGURE ::xmpp::sendIQ $xlib get \ -query [::xmpp::xml::create last \ -xmlns $NS_ECONFIGURE] \ -to $jid \ -command [list [namespace current]::parse_last $f $xlib $jid] } proc ejabberd::parse_last {f xlib jid status xml} { variable data set plot $f.info.plot if {![winfo exists $plot]} { return } if {![string equal $status ok]} { return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels set data($xlib,$jid,last) $cdata redraw_last $f $xlib $jid } proc ejabberd::redraw_last {f xlib jid} { variable data set plot $f.info.plot set maxdays 0 foreach t $data($xlib,$jid,last) { set days [expr {$t / (60*60*24)}] if {$days > $maxdays} {set maxdays $days} if {![info exists last($days)]} { set last($days) 0 } incr last($days) } set xscale [expr {$::tk_scale * 20}] set yscale [expr {$::tk_scale * 200}] $plot delete all set val 0 for {set i 0} {$i <= $maxdays} {incr i} { if {[info exists last($i)]} { set v $last($i) } else { set v 0 } if {$data($xlib,$jid,last_int)} { incr val $v } else { set val $v } set x1 [expr {$xscale * $i}] set x2 [expr {$xscale * ($i+1)}] set x [expr {($x1 + $x2)/2}] set y [expr {-$yscale * $val}] $plot create rectangle $x1 0 $x2 $y -fill red $plot create text $x 0 -text $i -anchor n $plot create text $x $y -text $val -anchor s } set bbox [$plot bbox all] set y1 [lindex $bbox 1] set y2 [lindex $bbox 3] set height [winfo height $plot] $plot scale all 0 0 1 [expr {0.9 * $height / (0.0 + $y2 - $y1)}] $plot configure -scrollregion [$plot bbox all] } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ejabberd/msgs000075500000000000000000000000001500237002100161415ustar00nobodynobodytkabber-plugins/ejabberd/msgs/ca.msg000064400000000000000000000015361500237002100173200ustar00nobodynobody# ca.msg -- # # Catalan messages for the Tkabber XMPP client (Ejabberd plugin). # http://www.softcatala.org/projectes/eines/recull/recull.htm # http://www.softcatala.org/projectes/eines/guiaestil/guiaestil.htm # # Author: Luis Peralta # Revised by: Carles Bellver ::msgcat::mcset ca "%s administration" "%s administració" ::msgcat::mcset ca "Administrate ejabberd" "Administrar ejabberd" ::msgcat::mcset ca "Administrate" "Administrar" ::msgcat::mcset ca "ejabberd server" "servidor ejabberd" ::msgcat::mcset ca "List of ejabberd servers." "Llista de servidors ejabberd." ::msgcat::mcset ca "Integral" "Integral" ::msgcat::mcset ca "Reload" "Recarregar" ::msgcat::mcset ca "Cancel" "Cancel·lar" ::msgcat::mcset ca "Configure service" "Configurar servei" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ejabberd/msgs/de.msg000064400000000000000000000044431500237002100173250ustar00nobodynobody# de.msg -- # # German messages for the Ejabberd Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 13.03.2009 ::msgcat::mcset de "%s administration" "%s Administrierung" ::msgcat::mcset de "Access rules:" "Zugriffs-Regeln:" ::msgcat::mcset de "Access" "Zugriff" ::msgcat::mcset de "ACLs:" "Zugriffs-Kontrolllisten:" ::msgcat::mcset de "Administrate ejabberd" "ejabberd administrieren" ::msgcat::mcset de "Administrate ejabberd..." "ejabberd administrieren..." ::msgcat::mcset de "Administrate" "Administrieren" ::msgcat::mcset de "Cancel" "Abbrechen" ::msgcat::mcset de "Configure service" "Dienst konfigurieren" ::msgcat::mcset de "Connection:" "Verbindung:" ::msgcat::mcset de "ejabberd server" "ejabberd-Server" ::msgcat::mcset de "Integral" "Integriert" ::msgcat::mcset de "Server JID:" "Server-JID:" ::msgcat::mcset de "Last Activity" "Letzte Aktivität" ::msgcat::mcset de "List of ejabberd servers." "Liste von ejabberd-Servern." ::msgcat::mcset de "Main" "Allgemein" ::msgcat::mcset de "Nodes" "Knoten" ::msgcat::mcset de "Number of users that used this service N days ago:" \ "Anzahl der Benutzer, die diesen Service innerhalb der letzten N Tage\ genutzt haben:" ::msgcat::mcset de "Online users:" "'Online'-Benutzer:" ::msgcat::mcset de "Outgoing S2S:" "Ausgehende S2S:" ::msgcat::mcset de "Registered users:" "Registrierte Benutzer:" ::msgcat::mcset de "Registration watchers:" "Registrierungs-Beobachter:" ::msgcat::mcset de "Registration" "Registrierung" ::msgcat::mcset de "Reload" "Neu laden" ::msgcat::mcset de "Running nodes:" "Laufende Knoten:" ::msgcat::mcset de "Set" "Setzen" ::msgcat::mcset de "Stopped nodes:" "Angehaltene Knoten:" ::msgcat::mcset de "Welcome message body:" "Text der 'Willkommen'-Nachricht:" ::msgcat::mcset de "Welcome message subject:" \ "Subjekt der 'Willkommen'-Nachricht:" ::msgcat::mcset de "Whether the Ejabberd plugin is loaded." \ "ejabberd-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ejabberd/msgs/es.msg000064400000000000000000000035671500237002100173520ustar00nobodynobody# es.msg -- # # Spanish messages for the Ejabberd Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "%s administration" "administración de %s" ::msgcat::mcset es "ACLs:" "ACLs:" ::msgcat::mcset es "Access rules:" "Reglas de acceso:" ::msgcat::mcset es "Access" "Accesi" ::msgcat::mcset es "Administrate ejabberd" "Administrar ejabberd" ::msgcat::mcset es "Administrate ejabberd..." "Administrar ejabberd..." ::msgcat::mcset es "Administrate" "Administrar" ::msgcat::mcset es "Cancel" "Cancelar" ::msgcat::mcset es "Configure service" "Configurar servicio" ::msgcat::mcset es "Connection:" "Conexión:" ::msgcat::mcset es "Integral" "Integral" ::msgcat::mcset es "Last Activity" "Última Actividad" ::msgcat::mcset es "List of ejabberd servers." "Lista de servidores ejabberd." ::msgcat::mcset es "Main" "Principal" ::msgcat::mcset es "Nodes" "Nodos" ::msgcat::mcset es "Number of users that used this service N days ago:" \ "Número de usuarios que usaron este servidor hace N días:" ::msgcat::mcset es "Online users:" "Usuarios conectados:" ::msgcat::mcset es "Outgoing S2S:" "Conexiones S2S salientes:" ::msgcat::mcset es "Registered users:" "Usuarios registrados:" ::msgcat::mcset es "Registration watchers:" "Visores de registros:" ::msgcat::mcset es "Registration" "Regitro" ::msgcat::mcset es "Reload" "Recargar" ::msgcat::mcset es "Running nodes:" "Nodos funcionando:" ::msgcat::mcset es "Server JID:" "JID del servidor:" ::msgcat::mcset es "Set" "Poner" ::msgcat::mcset es "Stopped nodes:" "Nodos detenidos:" ::msgcat::mcset es "Welcome message body:" \ "Contenido del mensaje de bienvenida:" ::msgcat::mcset es "Welcome message subject:" \ "Asunto del mensaje de bienvenida:" ::msgcat::mcset es "Whether the Ejabberd plugin is loaded." \ "Cargar el plugin Ejabberd." ::msgcat::mcset es "ejabberd server" "servidor ejabberd" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ejabberd/msgs/fr.msg000064400000000000000000000003311500237002100173340ustar00nobodynobody# fr.msg -- # # French messages for the Tkabber XMPP client. # # Author: Vincent Ricard ::msgcat::mcset fr "Configure service" "Configurer les services" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ejabberd/msgs/it.msg000064400000000000000000000003271500237002100173460ustar00nobodynobody# it.msg -- # # Italian messages for the Tkabber XMPP client # # Author: Antonino Iacono # Updated: Mikhail Zakharenko ::msgcat::mcset it "Configure service" "Configurazione" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ejabberd/msgs/nl.msg000064400000000000000000000003431500237002100173410ustar00nobodynobody# nl.msg -- # # Dutch messages for the Tkabber XMPP client. # # Author: Sander Devrieze ::msgcat::mcset nl "Configure service" "Dienst configureren" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ejabberd/msgs/pl.msg000064400000000000000000000037311500237002100173470ustar00nobodynobody# pl.msg -- # # Polish messages for the Ejabberd Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "List of ejabberd servers." "Lista serwerów ejabberd." ::msgcat::mcset pl "Administrate ejabberd" "ZarzÄ…dzanie serwerem ejabberd" ::msgcat::mcset pl "Administrate ejabberd..." \ "ZarzÄ…dzanie serwerem ejabberd..." ::msgcat::mcset pl "Number of users that used this service N days ago:" \ "Liczba osób korzystajÄ…cych z usÅ‚ugi N dni temu:" ::msgcat::mcset pl "ejabberd server" "Serwer ejabberd" ::msgcat::mcset pl "Administrate" "ZarzÄ…dzaj" ::msgcat::mcset pl "%s administration" "ZarzÄ…dzanie serwerem %s" ::msgcat::mcset pl "Reload" "PrzeÅ‚aduj" ::msgcat::mcset pl "Integral" "Razem" ::msgcat::mcset pl "Main" "Główny" ::msgcat::mcset pl "Nodes" "WÄ™zÅ‚y" ::msgcat::mcset pl "Registration" "Rejestracja" ::msgcat::mcset pl "Access" "DostÄ™p" ::msgcat::mcset pl "Last Activity" "Ostatnia aktywność" ::msgcat::mcset pl "Registered users:" "Użytkownicy zarejestrowani:" ::msgcat::mcset pl "Online users:" "Użytkownicy połączeni:" ::msgcat::mcset pl "Running nodes:" "DziaÅ‚ajÄ…ce wÄ™zÅ‚y:" ::msgcat::mcset pl "Stopped nodes:" "Zatrzymane wÄ™zÅ‚y:" ::msgcat::mcset pl "Outgoing S2S:" "WychodzÄ…cy ruch S2S:" ::msgcat::mcset pl "Welcome message subject:" "Temat wiadomoÅ›ci powitalnej:" ::msgcat::mcset pl "Welcome message body:" "Treść wiadomoÅ›ci powitalnej:" ::msgcat::mcset pl "Registration watchers:" "Obserwatorzy rejestracji:" ::msgcat::mcset pl "ACLs:" "ACL-e:" ::msgcat::mcset pl "Access rules:" "ReguÅ‚y dostÄ™pu:" ::msgcat::mcset pl "JID:" "JID:" ::msgcat::mcset pl "Set" "Ustaw" ::msgcat::mcset pl "Cancel" "Anuluj" ::msgcat::mcset pl "Connection:" "Połączenie:" ::msgcat::mcset pl "Server JID:" "JID serwera:" ::msgcat::mcset pl "Whether the Ejabberd plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ administracji serwerem Ejabberd" ::msgcat::mcset pl "Configure service" "Konfiguracja usÅ‚ugi" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ejabberd/msgs/pt.msg000064400000000000000000000010651500237002100173550ustar00nobodynobody# pt.msg -- # # Portuguese messages for the Ejabberd plugin for Tkabber XMPP client. # # Author: Miguel ::msgcat::mcset pt "List of ejabberd servers." "Lista de servidores ejabberd." ::msgcat::mcset pt "Administrate ejabberd" "Administrar ejabberd" ::msgcat::mcset pt "ejabberd server" "servidor ejabberd" ::msgcat::mcset pt "Administrate" "Administrar" ::msgcat::mcset pt "%s administration" "Administração de %s" ::msgcat::mcset pt "Reload" "Recarregar" ::msgcat::mcset pt "Integral" "Integral" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ejabberd/msgs/ru.msg000064400000000000000000000047371500237002100173710ustar00nobodynobody# ru.msg -- # # Russian messages for the Ejabberd Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "%s administration" "ÐдминиÑтрирование %s" ::msgcat::mcset ru "Access rules:" "Правила доÑтупа:" ::msgcat::mcset ru "Access" "ДоÑтуп" ::msgcat::mcset ru "ACLs:" "СпиÑки ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð´Ð¾Ñтупом:" ::msgcat::mcset ru "Administrate ejabberd" "ÐдминиÑтрировать ejabberd" ::msgcat::mcset ru "Administrate ejabberd..." "ÐдминиÑтрировать ejabberd..." ::msgcat::mcset ru "Administrate" "ÐдминиÑтрировать" ::msgcat::mcset ru "Cancel" "Отменить" ::msgcat::mcset ru "Configure service" "КонфигурациÑ" ::msgcat::mcset ru "Connection:" "Соединение:" ::msgcat::mcset ru "ejabberd server" "Сервер ejabberd" ::msgcat::mcset ru "Integral" "Интегральный" ::msgcat::mcset ru "Server JID:" "JID Ñервера:" ::msgcat::mcset ru "Last Activity" "ПоÑледнее подключение" ::msgcat::mcset ru "List of ejabberd servers." "СпиÑок Ñерверов ejabberd." ::msgcat::mcset ru "Main" "ГлавнаÑ" ::msgcat::mcset ru "Nodes" "Узлы" ::msgcat::mcset ru "Number of users that used this service N days ago:" \ "ЧиÑло пользователей, которые подключалиÑÑŒ к Ñерверу N дней назад:" ::msgcat::mcset ru "Online users:" "Подключённые пользователи:" ::msgcat::mcset ru "Outgoing S2S:" "ИÑходÑщие S2S-ÑоединениÑ:" ::msgcat::mcset ru "Registered users:" "ЗарегиÑтрированные пользователи:" ::msgcat::mcset ru "Registration watchers:" "Ðаблюдатели за региÑтрацией:" ::msgcat::mcset ru "Registration" "РегиÑтрациÑ" ::msgcat::mcset ru "Reload" "Обновить" ::msgcat::mcset ru "Running nodes:" "Запущенные узлы:" ::msgcat::mcset ru "Set" "УÑтановить" ::msgcat::mcset ru "Stopped nodes:" "ОÑтановленные узлы:" ::msgcat::mcset ru "Welcome message body:" "Тело приветÑтвенного ÑообщениÑ:" ::msgcat::mcset ru "Welcome message subject:" "Тема приветÑтвенного ÑообщениÑ:" ::msgcat::mcset ru "Whether the Ejabberd plugin is loaded."\ "Загружено ли раÑширение админиÑÑ‚Ñ€Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñервера ejabberd." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/ejabberd/msgs/uk.msg000064400000000000000000000045241500237002100173540ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Ejabberd Tkabber plugin. # # Author: Artem Bondarenko # Author: Sergei Golovan ::msgcat::mcset uk "%s administration" "адмініÑÑ‚Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ %s" ::msgcat::mcset uk "Access rules:" "Правила доÑтупу:" ::msgcat::mcset uk "Access" "ДоÑтуп" ::msgcat::mcset uk "ACLs:" "ACLs:" ::msgcat::mcset uk "Administrate ejabberd" "ÐдмініÑтрувати ejabberd" ::msgcat::mcset uk "Administrate ejabberd..." "ÐдмініÑтрувати ejabberd..." ::msgcat::mcset uk "Administrate" "ÐдмініÑтрувати" ::msgcat::mcset uk "Cancel" "Відміна" ::msgcat::mcset uk "Configure service" "Ðалаштувати Ñлужбу" ::msgcat::mcset uk "Connection:" "З'єднаннÑ:" ::msgcat::mcset uk "ejabberd server" "Ñервер ejabberd" ::msgcat::mcset uk "Integral" "Integral" ::msgcat::mcset uk "Server JID:" "JID Ñервера:" ::msgcat::mcset uk "Last Activity" "ОÑÑ‚Ð°Ð½Ð½Ñ Ð°ÐºÑ‚Ð¸Ð²Ð½Ñ–Ñть" ::msgcat::mcset uk "List of ejabberd servers." "СпиÑок ejabberd Ñерверів." ::msgcat::mcset uk "Main" "Головна" ::msgcat::mcset uk "Nodes" "Node" ::msgcat::mcset uk "Number of users that used this service N days ago:" \ "КількіÑть кориÑтувачів, Ñкі викориÑтовували цей ÑÐµÑ€Ð²Ñ–Ñ N днів тому:" ::msgcat::mcset uk "Online users:" "КориÑтувачі он-лайн:" ::msgcat::mcset uk "Outgoing S2S:" "Вихідні S2S з’єднаннÑ:" ::msgcat::mcset uk "Registered users:" "ЗареєÑтровані кориÑтувачі:" ::msgcat::mcset uk "Registration watchers:" "ÐаглÑдачі реєÑтрацій:" ::msgcat::mcset uk "Registration" "РеєÑтраціÑ" ::msgcat::mcset uk "Reload" "Оновити" ::msgcat::mcset uk "Running nodes:" "Запущені nodes:" ::msgcat::mcset uk "Set" "Ð’Ñтановити" ::msgcat::mcset uk "Stopped nodes:" "Зупинені nodes:" ::msgcat::mcset uk "Welcome message body:" "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· привітаннÑм:" ::msgcat::mcset uk "Welcome message subject:" \ "Тема Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· привітаннÑм:" ::msgcat::mcset uk "Whether the Ejabberd plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñервером Ejabberd." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters000075500000000000000000000000001500237002100151025ustar00nobodynobodytkabber-plugins/filters/filters.tcl000064400000000000000000000344711500237002100173460ustar00nobodynobody# filters.tcl -- # # Obsolete jabberd 1.4 mod_filter (which has never been documented in # any XEP) support. package require msgcat namespace eval filters { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered filters]} { ::plugins::register filters \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Jabberd\ 1.4 mod_filter plugin\ (obsolete) is\ loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable condtags {unavailable from resource subject body show type} variable acttags {settype forward reply offline continue} variable fromtag set fromtag(unavailable) [::msgcat::mc "I'm not online"] set fromtag(from) [::msgcat::mc "the message is from"] set fromtag(resource) [::msgcat::mc "the message is sent to"] set fromtag(subject) [::msgcat::mc "the subject is"] set fromtag(body) [::msgcat::mc "the body is"] set fromtag(show) [::msgcat::mc "my status is"] set fromtag(type) [::msgcat::mc "the message type is"] set fromtag(settype) [::msgcat::mc "change message type to"] set fromtag(forward) [::msgcat::mc "forward message to"] set fromtag(reply) [::msgcat::mc "reply with"] set fromtag(offline) [::msgcat::mc "store this message offline"] set fromtag(continue) [::msgcat::mc "continue processing rules"] variable totag set totag($fromtag(unavailable)) unavailable set totag($fromtag(from)) from set totag($fromtag(resource)) resource set totag($fromtag(subject)) subject set totag($fromtag(body)) body set totag($fromtag(show)) show set totag($fromtag(type)) type set totag($fromtag(settype)) settype set totag($fromtag(forward)) forward set totag($fromtag(reply)) reply set totag($fromtag(offline)) offline set totag($fromtag(continue)) continue variable rulecondmenu [list $fromtag(unavailable) $fromtag(from) \ $fromtag(resource) $fromtag(subject) $fromtag(body) \ $fromtag(show) $fromtag(type)] variable ruleactmenu [list $fromtag(settype) $fromtag(forward) $fromtag(reply) \ $fromtag(offline) $fromtag(continue)] variable m set m [menu .rulecondmenu -tearoff 0] $m add command -label $fromtag(unavailable) $m add command -label $fromtag(from) $m add command -label $fromtag(resource) $m add command -label $fromtag(subject) $m add command -label $fromtag(body) $m add command -label $fromtag(show) $m add command -label $fromtag(type) set m [menu .ruleactmenu -tearoff 0] $m add command -label $fromtag(settype) $m add command -label $fromtag(forward) $m add command -label $fromtag(reply) $m add command -label $fromtag(offline) $m add command -label $fromtag(continue) } proc filters::load {} { hook::add finload_hook [namespace current]::setup_menu if {![catch {.mainframe getmenu privacy}]} { setup_menu } } proc filters::unload {} { hook::remove finload_hook [namespace current]::setup_menu destroy_menu if {[winfo exists .rulecondmenu]} { destroy .rulecondmenu } if {[winfo exists .ruleactmenu]} { destroy .ruleactmenu } foreach var [info vars [namespace current]::*] { unset $var } } proc filters::setup_menu {args} { set mlabel [::msgcat::mc "Edit message filters"] set m [.mainframe getmenu privacy] catch { set idx [$m index $mlabel] } if {![info exists idx]} { $m add separator $m add command -label $mlabel -command [namespace code open] return } } proc filters::destroy_menu {args} { set mlabel [::msgcat::mc "Edit message filters"] set m [.mainframe getmenu privacy] catch { set idx [$m index $mlabel] } if {[info exists idx]} { $m delete [expr {$idx - 1}] $idx return } } proc filters::open {} { variable rf if {[winfo exists .filters]} { .filters draw return } set xlib [lindex [connections] 0] ::xmpp::sendIQ $xlib get \ -query [::xmpp::xml::create item -xmlns jabber:iq:filter] \ -command [list [namespace current]::recv] } proc filters::recv {res child} { variable rf variable rule variable rulelist debugmsg filters "$res $child" if {![string equal $res ok]} { MessageDlg .filters_err \ -aspect 50000 \ -icon error \ -message [::msgcat::mc "Requesting filter rules: %s" \ [error_to_string $child]] \ -type user \ -buttons ok \ -default 0 \ -cancel 0 return } Dialog .filters \ -title [::msgcat::mc "Filters"] \ -anchor e \ -modal none \ -default 0 \ -cancel 1 set f [.filters getframe] set bf [Frame $f.bf] pack $bf -side right -anchor n set bb [ButtonBox $bf.bb -orient vertical -spacing 0] $bb add -text [::msgcat::mc "Add"] -command [list [namespace current]::add] $bb add -text [::msgcat::mc "Edit"] \ -command [list [namespace current]::edit] $bb add -text [::msgcat::mc "Remove"] \ -command [list [namespace current]::remove] $bb add -text [::msgcat::mc "Move up"] \ -command [list [namespace current]::move -1] $bb add -text [::msgcat::mc "Move down"] \ -command [list [namespace current]::move 1] pack $bb -side top set sw [ScrolledWindow $f.sw] set rf [Listbox $sw.rules -exportselection 0] pack $sw -expand yes -fill both $sw setwidget $rf .filters add -text [::msgcat::mc "OK"] \ -command [list [namespace current]::commit] .filters add -text [::msgcat::mc "Cancel"] -command {destroy .filters} $rf delete 0 end array unset rule set rulelist {} ::xmpp::xml::split $child tag xmlns attrs cdata subels if {[string equal $xmlns jabber:iq:filter]} { foreach child $subels { process_rule $child } } $rf selection set 0 .filters draw } proc filters::process_rule {child} { variable rf variable rulelist ::xmpp::xml::split $child tag xmlns attrs cdata subels set rname [::xmpp::xml::getAttr $attrs name] $rf insert end $rname lappend rulelist $rname foreach data $subels { process_rule_data $rname $data } } proc filters::process_rule_data {name child} { variable rule ::xmpp::xml::split $child tag xmlns attrs cdata subels lappend rule($name) $tag $cdata debugmsg filters [array get rule] } proc filters::edit {} { variable rf set idx [lindex [$rf curselection] 0] if {$idx eq ""} return set name [$rf get $idx] debugmsg filters $name if {$name != ""} { open_edit $name } } proc filters::open_edit {rname} { variable rule variable tmp set w [win_id rule $rname] if {[winfo exists $w]} { focus -force $w return } Dialog $w -title [::msgcat::mc "Edit rule"] \ -anchor e \ -modal none \ -default 0 \ -cancel 1 set f [$w getframe] Label $f.lrname -text [::msgcat::mc "Rule Name:"] Entry $f.rname -textvariable [namespace current]::tmp($rname,name) set tmp($rname,name) $rname grid $f.lrname -row 0 -column 0 -sticky e grid $f.rname -row 0 -column 1 -sticky ew set cond [Labelframe $f.cond -text [::msgcat::mc "Condition"]] set fc $cond Button $fc.add -text [::msgcat::mc "Add"] pack $fc.add -side right -anchor n set swc [ScrolledWindow $fc.sw] pack $swc -expand yes -fill both set sfc [ScrollableFrame $swc.f -height [winfo pixels $fc 3c]] $swc setwidget $sfc grid $cond -row 1 -column 0 -sticky news -columnspan 2 -pady 1m set act [Labelframe $f.act -text [::msgcat::mc "Action"]] set fa $act Button $fa.add -text [::msgcat::mc "Add"] pack $fa.add -side right -anchor n set swa [ScrolledWindow $fa.sw] pack $swa -expand yes -fill both set sfa [ScrollableFrame $swa.f -height [winfo pixels $fc 3c]] $swa setwidget $sfa grid $act -row 2 -column 0 -sticky news -columnspan 2 -pady 1m grid columnconfig $f 1 -weight 1 -minsize 0 grid rowconfig $f 1 -weight 1 grid rowconfig $f 2 -weight 1 set fcond [$sfc getframe] set fact [$sfa getframe] $w add -text [::msgcat::mc "OK"] \ -command [list [namespace current]::accept_rule $w $rname $fcond $fact] $w add -text [::msgcat::mc "Cancel"] -command [list destroy $w] variable ruleactmenu variable rulecondmenu $fc.add configure \ -command [list [namespace current]::insert_item \ $fcond unavailable "" $rulecondmenu] $fa.add configure \ -command [list [namespace current]::insert_item \ $fact settype "" $ruleactmenu] fill_rule $rname $fcond $fact $w draw } proc filters::fill_rule {rname fcond fact} { variable rule variable condtags variable acttags variable ruleactmenu variable rulecondmenu variable items set items($fcond) {} set items($fact) {} foreach {tag value} $rule($rname) { if {$tag in $condtags} { debugmsg filters "C $tag $value" insert_item $fcond $tag $value $rulecondmenu } elseif {$tag in $acttags} { debugmsg filters "A $tag $value" insert_item $fact $tag $value $ruleactmenu } } } proc filters::insert_item {f tag val menu} { variable items variable fromtag if {[llength $items($f)]} { set n [lindex $items($f) end] incr n } else { set n 0 } # TODO: hiding entry for some tags eval [list OptionMenu $f.mb$n $f.mb$n.var] $menu global $f.mb$n.var set $f.mb$n.var $fromtag($tag) Entry $f.e$n $f.e$n insert 0 $val Separator $f.sep$n -orient vertical Button $f.remove$n -text [::msgcat::mc "Remove"] \ -command [list [namespace current]::remove_item $f $n] grid $f.mb$n -row $n -column 0 -sticky ew grid $f.e$n -row $n -column 1 -sticky ew grid $f.sep$n -row $n -column 2 -sticky ew grid $f.remove$n -row $n -column 3 -sticky ew lappend items($f) $n debugmsg filters $items($f) } proc filters::remove_item {f n} { variable items set idx [lsearch -exact $items($f) $n] set items($f) [lreplace $items($f) $idx $idx] eval destroy [grid slaves $f -row $n] debugmsg filters $items($f) } proc filters::accept_rule {w rname fcond fact} { variable items variable totag variable rule variable tmp variable rf variable rulelist set newname $tmp($rname,name) if {$newname == ""} { MessageDlg .rname_err \ -aspect 50000 \ -icon error \ -message [::msgcat::mc "Empty rule name"] \ -type user \ -buttons ok \ -default 0 \ -cancel 0 return } if {$rname != $newname && $newname in $rulelist} { MessageDlg .rname_err \ -aspect 50000 \ -icon error \ -message [::msgcat::mc "Rule name already exists"] \ -type user \ -buttons ok \ -default 0 \ -cancel 0 return } set rule($newname) {} foreach n $items($fcond) { set tag $totag([set ::$fcond.mb$n.var]) set val [$fcond.e$n get] debugmsg filters "$tag $val" lappend rule($newname) $tag $val } foreach n $items($fact) { set tag $totag([set ::$fact.mb$n.var]) set val [$fact.e$n get] debugmsg filters "$tag $val" lappend rule($newname) $tag $val } debugmsg filters [array get rule] set idx [lsearch -exact $rulelist $rname] set rulelist [lreplace $rulelist $idx $idx $newname] $rf delete 0 end foreach r $rulelist { $rf insert end $r } set items($fcond) {} set items($fact) {} destroy $w } proc filters::add {} { variable rule set rule() {} open_edit "" } proc filters::remove {} { variable rf variable rulelist set idx [lindex [$rf curselection] 0] if {$idx eq ""} return set name [$rf get $idx] debugmsg filters $name if {$name != ""} { set idx [lsearch -exact $rulelist $name] set rulelist [lreplace $rulelist $idx $idx] $rf delete $idx debugmsg filters $rulelist } } proc filters::commit {} { variable rulelist variable rule set result {} foreach rname $rulelist { set rtags {} foreach {tag val} $rule($rname) { lappend rtags [::xmpp::xml::create $tag -cdata $val] } lappend result [::xmpp::xml::create rule \ -attrs [list name $rname] \ -subelements $rtags] } debugmsg filters $result set xlib [lindex [connections] 0] ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create item \ -xmlns jabber:iq:filter \ -subelements $result] destroy .filters } proc filters::move {shift} { variable rulelist variable rf set idx [lindex [$rf curselection] 0] if {$idx eq ""} return set name [$rf get $idx] set idx [lsearch -exact $rulelist $name] set rulelist [lreplace $rulelist $idx $idx] set newidx [expr {$idx + $shift}] set rulelist [linsert $rulelist $newidx $name] debugmsg filters $rulelist $rf delete 0 end foreach r $rulelist { $rf insert end $r } $rf selection set $newidx } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs000075500000000000000000000000001500237002100160535ustar00nobodynobodytkabber-plugins/filters/msgs/ca.msg000064400000000000000000000035221500237002100172270ustar00nobodynobody# ca.msg -- # # Catalan messages for the Tkabber Filters plugin. # http://www.softcatala.org/projectes/eines/recull/recull.htm # http://www.softcatala.org/projectes/eines/guiaestil/guiaestil.htm # # Author: Luis Peralta # Revised by: Carles Bellver ::msgcat::mcset ca "Action" "Acció" ::msgcat::mcset ca "Add" "Afegir" ::msgcat::mcset ca "Cancel" "Cancel·lar" ::msgcat::mcset ca "Condition" "Condició" ::msgcat::mcset ca "Edit" "Editar" ::msgcat::mcset ca "Edit rule" "Editar regla" ::msgcat::mcset ca "Empty rule name" "Nom de la regla buit" ::msgcat::mcset ca "Filters" "Filtres" ::msgcat::mcset ca "I'm not online" "No estic connectat" ::msgcat::mcset ca "Move down" "Desplaçar cap avall" ::msgcat::mcset ca "Move up" "Desplaçar cap amunt" ::msgcat::mcset ca "OK" "OK" ::msgcat::mcset ca "Remove" "Eliminar" ::msgcat::mcset ca "Requesting filter rules: %s" \ "Demanant regles de filtres: %s" ::msgcat::mcset ca "Rule name already exists" "El nom de la regla ja existeix" ::msgcat::mcset ca "Rule Name:" "Nom de la regla:" ::msgcat::mcset ca "change message type to" "canviar el tipus del missatge a" ::msgcat::mcset ca "continue processing rules" "continuar processant regles" ::msgcat::mcset ca "forward message to" "reenviar el missatge a" ::msgcat::mcset ca "my status is" "el meu estat és" ::msgcat::mcset ca "reply with" "contestar amb" ::msgcat::mcset ca "store this message offline" \ "guardar aquest missatge fora de línia" ::msgcat::mcset ca "the body is" "el cos del missatge és" ::msgcat::mcset ca "the message is from" "el missatge és de" ::msgcat::mcset ca "the message is sent to" "el missatge és per a" ::msgcat::mcset ca "the message type is" "el tipus de missatge és" ::msgcat::mcset ca "the subject is" "l'assumpte és" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/de.msg000064400000000000000000000036711500237002100172410ustar00nobodynobody# de.msg -- # # German messages for the Tkabber XMPP client. # # Author: Roger Sondermann # Last-Modified: 06.03.2011 ::msgcat::mcset de "Action" "Aktion" ::msgcat::mcset de "Add" "Hinzufügen" ::msgcat::mcset de "Blocking communication options." \ "Optionen für das Blockieren der Kommunikation." ::msgcat::mcset de "Cancel" "Abbrechen" ::msgcat::mcset de "Condition" "Bedingung" ::msgcat::mcset de "Edit" "Ändern" ::msgcat::mcset de "Edit message filters" "Nachrichten-Filter ändern" ::msgcat::mcset de "Edit rule" "Regel ändern" ::msgcat::mcset de "Empty rule name" "Leerer Regel-Name" ::msgcat::mcset de "Enable jabberd 1.4 mod_filter support (obsolete)." \ "'jabberd 1.4 mod_filter'-Unterstützung aktivieren (veraltet)." ::msgcat::mcset de "Filters" "Filter" ::msgcat::mcset de "I'm not online" "Ich bin nicht 'Online'" ::msgcat::mcset de "Move down" "Nach unten" ::msgcat::mcset de "Move up" "Nach oben" ::msgcat::mcset de "OK" "OK" ::msgcat::mcset de "Remove" "Entfernen" ::msgcat::mcset de "Requesting filter rules: %s" "Fordere Filter-Regeln an: %s" ::msgcat::mcset de "Rule Name:" "Regel-Name" ::msgcat::mcset de "Rule name already exists" "Regel-Name existiert bereits" ::msgcat::mcset de "change message type to" "ändere Nachrichten-Typ zu" ::msgcat::mcset de "continue processing rules" "Regel-Verarbeitung fortsetzen" ::msgcat::mcset de "forward message to" "Nachricht weiterleiten an" ::msgcat::mcset de "my status is" "mein Status ist" ::msgcat::mcset de "reply with" "antworte mit" ::msgcat::mcset de "store this message offline" \ "speichere diese Nachricht Offline" ::msgcat::mcset de "the body is" "der Nachrichten-Text ist" ::msgcat::mcset de "the message is from" "die Nachricht ist von" ::msgcat::mcset de "the message is sent to" "die Nachricht ist gesendet an" ::msgcat::mcset de "the message type is" "der Nachrichten-Typ ist" ::msgcat::mcset de "the subject is" "der Betreff ist" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/eo.msg000064400000000000000000000031101500237002100172400ustar00nobodynobody# eo.msg -- # # Esperanto messages for the Tkabber XMPP client. # # Author: Mike Mintz # Last-Modified: December 30, 2002 ::msgcat::mcset eo "I'm not online" "Mi ne estas enreta" ::msgcat::mcset eo "the message is from" "la mesaÄo estas de" ::msgcat::mcset eo "the message is sent to" "la mesaÄo estas sendita al" ::msgcat::mcset eo "the subject is" "la subjekto estas" ::msgcat::mcset eo "the body is" "la korpo estas" ::msgcat::mcset eo "my status is" "mia retastato estas" ::msgcat::mcset eo "the message type is" "la mesaÄotipo estas" ::msgcat::mcset eo "change message type to" "ÅanÄu mesaÄotipon por esti" ::msgcat::mcset eo "forward message to" "resendu mesaÄon al" ::msgcat::mcset eo "reply with" "respondu kun" ::msgcat::mcset eo "store this message offline" \ "storu tiun ĉin mesaÄon malenrete" ::msgcat::mcset eo "continue processing rules" "adu trakti regulojn" ::msgcat::mcset eo "Filters" "Filtriloj" ::msgcat::mcset eo "Add" "Aldonu" ::msgcat::mcset eo "Edit" "Redaktu" ::msgcat::mcset eo "Remove" "Elprenu" ::msgcat::mcset eo "Move up" "Transloku suben" ::msgcat::mcset eo "Move down" "Transloku supren" ::msgcat::mcset eo "Edit rule" "Redaktu regulon" ::msgcat::mcset eo "Rule Name:" "Nomo de Regulo:" ::msgcat::mcset eo "Empty rule name" "Malplena nomo de regulo" ::msgcat::mcset eo "Rule name already exists" "Nomo de regulo jam ekzistas" ::msgcat::mcset eo "Condition" "Kondiĉo" ::msgcat::mcset eo "Action" "Agado" ::msgcat::mcset eo "Cancel" "Nuligu" ::msgcat::mcset eo "OK" "Bone" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/es.msg000064400000000000000000000033741500237002100172600ustar00nobodynobody# es.msg -- # # Spanish messages for the Tkabber XMPP client. # # Author: Luis Peralta # Updates: Badlop (JID: badlop AT jabberes.org) ::msgcat::mcset es "Action" "Acción" ::msgcat::mcset es "Add" " Añadir " ::msgcat::mcset es "Cancel" " Cancelar " ::msgcat::mcset es "Condition" "Condición" ::msgcat::mcset es "Edit" "Editar" ::msgcat::mcset es "Edit message filters" "Editar filtros de mensajes" ::msgcat::mcset es "Edit rule" "Editar regla" ::msgcat::mcset es "Empty rule name" "Nombre de la regla vacío" ::msgcat::mcset es "Filters" "Filtros" ::msgcat::mcset es "I'm not online" "No estoy conectado" ::msgcat::mcset es "Move down" "Desplazar abajo" ::msgcat::mcset es "Move up" "Desplazar arriba" ::msgcat::mcset es "OK" " Aceptar " ::msgcat::mcset es "Remove" "Eliminar" ::msgcat::mcset es "Requesting filter rules: %s" \ "Solicitando reglas de filtrado: %s" ::msgcat::mcset es "Rule Name:" "Nombre de la regla:" ::msgcat::mcset es "Rule name already exists" "El nombre de la regla ya existe" ::msgcat::mcset es "change message type to" "cambiar el tipo del mensaje a" ::msgcat::mcset es "continue processing rules" "seguir procesando reglas" ::msgcat::mcset es "forward message to" "reenviar el mensaje a" ::msgcat::mcset es "my status is" "mi estado es" ::msgcat::mcset es "reply with" "responder con" ::msgcat::mcset es "store this message offline" \ "guardar este mensaje fuera de linea" ::msgcat::mcset es "the body is" "el cuerpo del mensaje es" ::msgcat::mcset es "the message is from" "el mensaje es de" ::msgcat::mcset es "the message is sent to" "el mensaje se envía a" ::msgcat::mcset es "the message type is" "el tipo del mensaje es" ::msgcat::mcset es "the subject is" "el asunto es" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/eu.msg000064400000000000000000000031171500237002100172550ustar00nobodynobody# eu.msg -- # # Basque messages for Tkabber XMPP client. # # Author: Euskalerria.org # http://www.euskalerria.org/jalgitalki # JID: jalgitalki@jalgitalki.euskalerria.org ::msgcat::mcset eu "I'm not online" "Ez nago konekatuta" ::msgcat::mcset eu "the message is from" "Norena den mezua:" ::msgcat::mcset eu "the message is sent to" "norentzat den mezua:" ::msgcat::mcset eu "the subject is" "zein den gaia:" ::msgcat::mcset eu "the body is" "zein den mezuaren muina" ::msgcat::mcset eu "my status is" "nire egoera da..." ::msgcat::mcset eu "the message type is" "zein den mezuaren tankera" ::msgcat::mcset eu "change message type to" "mezuaren tankera aldatu" ::msgcat::mcset eu "forward message to" "mezua nori berbidali..." ::msgcat::mcset eu "reply with" "erantzun" ::msgcat::mcset eu "store this message offline" "mezu hau lerrotik at gorde" ::msgcat::mcset eu "continue processing rules" "jarrai arauak lantzen" ::msgcat::mcset eu "Filters" "Iragazkiak" ::msgcat::mcset eu "Add" "Gehitu" ::msgcat::mcset eu "Edit" "Editatu" ::msgcat::mcset eu "Remove" "Ezabatu" ::msgcat::mcset eu "Move up" "gora eraman" ::msgcat::mcset eu "Move down" "Behera eraman" ::msgcat::mcset eu "Edit rule" "Araua editatu" ::msgcat::mcset eu "Rule Name:" "Arauaren izena:" ::msgcat::mcset eu "Empty rule name" "Arauaren izena hutsik" ::msgcat::mcset eu "Rule name already exists" "Arauaren izena erabilita dago" ::msgcat::mcset eu "Condition" "baldintza" ::msgcat::mcset eu "Action" "Ekintza" ::msgcat::mcset eu "Cancel" "Deuseztatu" ::msgcat::mcset eu "OK" "Ondo" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/fr.msg000064400000000000000000000031041500237002100172470ustar00nobodynobody# fr.msg -- # # French messages for the Tkabber XMPP client. # # Author: Vincent Ricard ::msgcat::mcset fr "I'm not online" "Je ne suis pas connecté" ::msgcat::mcset fr "the message is from" "le message est de" ::msgcat::mcset fr "the message is sent to" "le message est envoyé à" ::msgcat::mcset fr "the subject is" "le sujet est" ::msgcat::mcset fr "the body is" "le corps est" ::msgcat::mcset fr "my status is" "mon statut est" ::msgcat::mcset fr "the message type is" "le type du message est" ::msgcat::mcset fr "change message type to" "changer le type du message pour" ::msgcat::mcset fr "forward message to" "transférer le message à" ::msgcat::mcset fr "reply with" "Répondre avec" ::msgcat::mcset fr "store this message offline" \ "stocker ce message hors connexion" ::msgcat::mcset fr "continue processing rules" \ "continuer l'application des règles" ::msgcat::mcset fr "Filters" "Filtres" ::msgcat::mcset fr "Add" "Ajouter" ::msgcat::mcset fr "Edit" "Editer" ::msgcat::mcset fr "Remove" "Supprimer" ::msgcat::mcset fr "Move up" "Déplacer vers le haut" ::msgcat::mcset fr "Move down" "Déplacer ver le bas" ::msgcat::mcset fr "Edit rule" "Editer la règle" ::msgcat::mcset fr "Rule Name:" "Nom de la rèle :" ::msgcat::mcset fr "Empty rule name" "Le nom de la règle est vide" ::msgcat::mcset fr "Rule name already exists" "Le nom de la règle existe déjà" ::msgcat::mcset fr "Condition" "Condition" ::msgcat::mcset fr "Action" "Action" ::msgcat::mcset fr "OK" "OK" ::msgcat::mcset fr "Cancel" "Annuler" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/it.msg000064400000000000000000000005041500237002100172550ustar00nobodynobody# it.msg -- # # Italian messages for the Tkabber XMPP client # # Author: Antonino Iacono # Updated: Mikhail Zakharenko ::msgcat::mcset it "Edit message filters" "Modifica filtro dei messagi" ::msgcat::mcset it "Requesting filter rules: %s" \ "Regole del filtro richiesti: %s" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/nl.msg000064400000000000000000000031641500237002100172570ustar00nobodynobody# nl.msg -- # # Dutch messages for the Tkabber XMPP client. # # Author: Sander Devrieze ::msgcat::mcset nl "I'm not online" "Ik ben niet online¸" ::msgcat::mcset nl "the message is from" "het bericht is van" ::msgcat::mcset nl "the message is sent to" "het bericht werd verzonden naar" ::msgcat::mcset nl "the subject is" "het onderwerp is" ::msgcat::mcset nl "the body is" "de inhoud van het bericht is" ::msgcat::mcset nl "my status is" "mijn status is" ::msgcat::mcset nl "the message type is" "het berichttype is" ::msgcat::mcset nl "change message type to" "wijzig berichttype in" ::msgcat::mcset nl "forward message to" "bericht doorsturen naar" ::msgcat::mcset nl "reply with" "antwoorden met" ::msgcat::mcset nl "store this message offline" "dit bericht offline opslaan" ::msgcat::mcset nl "continue processing rules" \ "verder gaan met uitvoeren van regels" ::msgcat::mcset nl "Filters" "Filters" ::msgcat::mcset nl "Add" "Toevoegen" ::msgcat::mcset nl "Edit" "Bewerken" ::msgcat::mcset nl "Remove" "Verwijderen" ::msgcat::mcset nl "Move up" "Omhoog" ::msgcat::mcset nl "Move down" "Omlaag" ::msgcat::mcset nl "Edit rule" "Instellingregel bewerken" ::msgcat::mcset nl "Rule Name:" "Regelnaam:" ::msgcat::mcset nl "Empty rule name" "Lege regelnaam" ::msgcat::mcset nl "Rule name already exists" "Regelnaam bestaat al" ::msgcat::mcset nl "Condition" "Toestand" ::msgcat::mcset nl "Action" "Actie" ::msgcat::mcset nl "Requesting filter rules: %s" \ "Aanvragen van filterregels: %s" ::msgcat::mcset nl "Cancel" "Annuleren" ::msgcat::mcset nl "OK" "OK" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/pl.msg000064400000000000000000000035021500237002100172550ustar00nobodynobody# pl.msg -- # # Polish messages for the Tkabber XMPP client. # # Author: Irek Chmielowiec # Contact: xmpp:irek(at)chmielowiec.org ::msgcat::mcset pl "I'm not online" "nie jestem dostÄ™pny" ::msgcat::mcset pl "the message is from" "wiadomość jest od" ::msgcat::mcset pl "the message is sent to" "wiadomość jest do" ::msgcat::mcset pl "the subject is" "temat" ::msgcat::mcset pl "the body is" "treść" ::msgcat::mcset pl "my status is" "status" ::msgcat::mcset pl "the message type is" "typ wiadomoÅ›ci" ::msgcat::mcset pl "change message type to" "zmieÅ„ typ wiadomoÅ›ci na" ::msgcat::mcset pl "forward message to" "przekaż wiadomość do" ::msgcat::mcset pl "reply with" "odpowiedz na" ::msgcat::mcset pl "store this message offline" "zachowaj wiadomość" ::msgcat::mcset pl "continue processing rules" "kontynuuj przetwarzanie reguÅ‚" ::msgcat::mcset pl "Requesting filter rules: %s" \ "Pobieranie reguÅ‚ filtrowania: %s" ::msgcat::mcset pl "Filters" "Filtry" ::msgcat::mcset pl "Edit" "Edytuj" ::msgcat::mcset pl "Move up" "Do góry" ::msgcat::mcset pl "Move down" "Na dół" ::msgcat::mcset pl "Edit rule" "Edytuj regułę" ::msgcat::mcset pl "Rule Name:" "Nazwa reguÅ‚y:" ::msgcat::mcset pl "Condition" "Warunek" ::msgcat::mcset pl "Action" "Akcja" ::msgcat::mcset pl "Empty rule name" "Wyczyść nazwÄ™ reguÅ‚y" ::msgcat::mcset pl "Rule name already exists" \ "ReguÅ‚a o takiej nazwie już istnieje" ::msgcat::mcset pl "Enable jabberd 1.4 mod_filter support (obsolete)." \ "Włącz obsÅ‚ugÄ™ moduÅ‚u mod_filter serwera jabberd 1.4 (przestarzaÅ‚y)." ::msgcat::mcset pl "Edit message filters" "Edycja filtrów wiadomoÅ›ci" ::msgcat::mcset pl "Add" "Dodaj" ::msgcat::mcset pl "Cancel" "Anuluj" ::msgcat::mcset pl "OK" "OK" ::msgcat::mcset pl "Remove" "UsuÅ„" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/pt.msg000064400000000000000000000031131500237002100172630ustar00nobodynobody# pt.msg -- # # Portuguese messages for the Tkabber XMPP client. # # Author: Miguel ::msgcat::mcset pt "I'm not online" "Não estou ligado" ::msgcat::mcset pt "the message is from" "a mensagem é de" ::msgcat::mcset pt "the message is sent to" "a mensagem é para" ::msgcat::mcset pt "the subject is" "o assunto é" ::msgcat::mcset pt "the body is" "o corpo da mensagem é" ::msgcat::mcset pt "my status is" "o meu estado é" ::msgcat::mcset pt "the message type is" "o tipo da mensagem é" ::msgcat::mcset pt "change message type to" "mudar tipo da mensagem para" ::msgcat::mcset pt "forward message to" "reenviar mensagem para" ::msgcat::mcset pt "reply with" "responder com" ::msgcat::mcset pt "store this message offline" "guardar esta mensagem" ::msgcat::mcset pt "continue processing rules" "continuar a processar regras" ::msgcat::mcset pt "Filters" "Filtros" ::msgcat::mcset pt "Add" "Adicionar" ::msgcat::mcset pt "Edit" "Editar" ::msgcat::mcset pt "Remove" "Eliminar" ::msgcat::mcset pt "Move up" "Mover para cima" ::msgcat::mcset pt "Move down" "Mover para baixo" ::msgcat::mcset pt "Edit rule" "Editar regra" ::msgcat::mcset pt "Rule Name:" "Nome da regra:" ::msgcat::mcset pt "Empty rule name" "Nome de regra vazio" ::msgcat::mcset pt "Rule name already exists" "O nome da regra já existe" ::msgcat::mcset pt "Condition" "Condição" ::msgcat::mcset pt "Action" "Acção" ::msgcat::mcset pt "Requesting filter rules: %s" \ "A pedir regras de filtros: %s" ::msgcat::mcset pt "Cancel" "Cancelar" ::msgcat::mcset pt "OK" "OK" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/ro.msg000064400000000000000000000030621500237002100172630ustar00nobodynobody# ro.msg -- # # Romanian messages for the Tkabber XMPP client. # # Author: Adrian Rapa (e-mail & JID: adrian@dtedu.net) # Last-Updated: 25-07-2003 ::msgcat::mcset ro "I'm not online" "Nu sunt conectat" ::msgcat::mcset ro "the message is from" "mesajul este de la" ::msgcat::mcset ro "the message is sent to" "mesajul este trimis către" ::msgcat::mcset ro "the subject is" "subiectul este" ::msgcat::mcset ro "the body is" "corpul este" ::msgcat::mcset ro "my status is" "starea mea este" ::msgcat::mcset ro "the message type is" "tipul mesajului este" ::msgcat::mcset ro "change message type to" "schimbă tipul mesajului in" ::msgcat::mcset ro "forward message to" "înaintează mesajul către" ::msgcat::mcset ro "reply with" "răspunde cu" ::msgcat::mcset ro "store this message offline" "salvează acest mesaj" ::msgcat::mcset ro "continue processing rules" "continuă prelucrarea regulilor" ::msgcat::mcset ro "Filters" "Filtre" ::msgcat::mcset ro "Add" "Adaugă" ::msgcat::mcset ro "Edit" "Modifică" ::msgcat::mcset ro "Remove" "Åžterge" ::msgcat::mcset ro "Move up" "Mută mai sus" ::msgcat::mcset ro "Move down" "Mută mai jos" ::msgcat::mcset ro "Edit rule" "Modifică regulă" ::msgcat::mcset ro "Rule Name:" "Nume regulă" ::msgcat::mcset ro "Empty rule name" "Åžterge numele regulei" ::msgcat::mcset ro "Rule name already exists" \ "O regulă cu acelasi nume există deja" ::msgcat::mcset ro "Condition" "CondiÅ£ie" ::msgcat::mcset ro "Action" "AcÅ£iune" ::msgcat::mcset ro "Cancel" "Renunţă" ::msgcat::mcset ro "OK" "OK" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/ru.msg000064400000000000000000000045711500237002100172770ustar00nobodynobody# ru.msg -- # # Russian messages for the Filters Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Action" "ДейÑтвие" ::msgcat::mcset ru "Add" "Добавить" ::msgcat::mcset ru "Cancel" "Отменить" ::msgcat::mcset ru "Condition" "УÑловие" ::msgcat::mcset ru "Edit" "Изменить" ::msgcat::mcset ru "Edit message filters" "Изменить фильтры Ñообщений" ::msgcat::mcset ru "Edit rule" "Изменение правила" ::msgcat::mcset ru "Empty rule name" "Ðазвание правила не должно быть пуÑтым" ::msgcat::mcset ru "Filters" "Фильтры" ::msgcat::mcset ru "I'm not online" "Ñ Ð½Ðµ в Ñети" ::msgcat::mcset ru "Move down" "ПеремеÑтить вниз" ::msgcat::mcset ru "Move up" "ПеремеÑтить вверх" ::msgcat::mcset ru "OK" "Продолжить" ::msgcat::mcset ru "Remove" "Удалить" ::msgcat::mcset ru "Requesting filter rules: %s" "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» фильтрованиÑ:\ %s" ::msgcat::mcset ru "Rule Name:" "Ðазвание правила:" ::msgcat::mcset ru "Rule name already exists" "Правило Ñ Ñ‚Ð°ÐºÐ¸Ð¼ названием уже\ ÑущеÑтвует" ::msgcat::mcset ru "Whether the Jabberd 1.4 mod_filter plugin (obsolete) is\ loaded." "Загружено ли (уÑтаревшее) раÑширение поддержки mod_filter\ Ñервера Jabberd 1.4." ::msgcat::mcset ru "change message type to" "изменить тип ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð½Ð°" ::msgcat::mcset ru "continue processing rules" "продолжить применение правил" ::msgcat::mcset ru "forward message to" "переÑлать Ñообщение" ::msgcat::mcset ru "my status is" "мой ÑÑ‚Ð°Ñ‚ÑƒÑ Ñ€Ð°Ð²ÐµÐ½" ::msgcat::mcset ru "reply with" "ответить" ::msgcat::mcset ru "store this message offline" "Ñохранить Ñообщение на\ Ñервере" ::msgcat::mcset ru "the body is" "текÑÑ‚ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ€Ð°Ð²ÐµÐ½" ::msgcat::mcset ru "the message is from" "Ñообщение от" ::msgcat::mcset ru "the message is sent to" "Ñообщение адреÑовано" ::msgcat::mcset ru "the message type is" "тип ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ€Ð°Ð²ÐµÐ½" ::msgcat::mcset ru "the subject is" "тема ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ€Ð°Ð²Ð½Ð°" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/filters/msgs/uk.msg000064400000000000000000000046151500237002100172670ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Tkabber XMPP client. # # Author: Mykola Dzham # Updated: Artem Bondarenko # Last-Modified: 28.10.2010 ::msgcat::mcset uk "Action" "ДіÑ" ::msgcat::mcset uk "Add" "Додати" ::msgcat::mcset uk "Cancel" "Відмінити" ::msgcat::mcset uk "Condition" "Умова" ::msgcat::mcset uk "Edit" "Редагувати" ::msgcat::mcset uk "Edit message filters" "Редагувати фільтри повідомлень" ::msgcat::mcset uk "Edit rule" "Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°" ::msgcat::mcset uk "Empty rule name" "ÐŸÐ¾Ñ€Ð¾Ð¶Ð½Ñ Ð½Ð°Ð·Ð²Ð° правила" ::msgcat::mcset uk "Filters" "Фільтри" ::msgcat::mcset uk "I'm not online" "Я не в мережі" ::msgcat::mcset uk "Move down" "ПереміÑтити донизу" ::msgcat::mcset uk "Move up" "ПереміÑтити догори" ::msgcat::mcset uk "OK" "Добре" ::msgcat::mcset uk "Remove" "Видалити" ::msgcat::mcset uk "Requesting filter rules: %s" "Запит правил фільтрації: %s" ::msgcat::mcset uk "Rule name already exists" "Така назва правила вже Ñ–Ñнує" ::msgcat::mcset uk "Rule Name:" "Ðазва правила:" ::msgcat::mcset uk "change message type to" "змінити тип Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ð°" ::msgcat::mcset uk "continue processing rules" "продовжити обробку правил" ::msgcat::mcset uk "forward message to" "переÑлати Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð´Ð¾" ::msgcat::mcset uk "my status is" "мій ÑтатуÑ" ::msgcat::mcset uk "reply with" "ВідповіÑти" ::msgcat::mcset uk "store this message offline" \ "зберегти це Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ð° Ñервері" ::msgcat::mcset uk "the body is" "текÑÑ‚ повідомленнÑ" ::msgcat::mcset uk "the message is from" "Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð²Ñ–Ð´" ::msgcat::mcset uk "the message is sent to" "Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð°Ð´Ñ€ÐµÑовано" ::msgcat::mcset uk "the message type is" "тип повідомленнÑ" ::msgcat::mcset uk "the subject is" "тема повідомленнÑ" ::msgcat::mcset uk "Whether the Jabberd 1.4 mod_filter plugin (obsolete) is\ loaded." "Чи завантажене (заÑтаріле) розширеннÑ, Ñке підтримує\ mod_filter Ñервера Jabberd 1.4." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/floatingcontact000075500000000000000000000000001500237002100166115ustar00nobodynobodytkabber-plugins/floatingcontact/README000064400000000000000000000006071500237002100175530ustar00nobodynobody"Floating contact" - allows certain roster items to float in separate small windows. This plugin adds a new checkbox item in roster popup menu - "Floating contact". If it's checked then a small window appears with a copy of the contact from the roster. It is stayed on top and allows to follow the selected roster item presence even if Tkabber itself is hidden or covered by other windows. tkabber-plugins/floatingcontact/floatingcontact.tcl000064400000000000000000000220771500237002100225630ustar00nobodynobody# floatingcontact.tcl -- # # Floating Contact plugin for the Tkabber XMPP client. It implements # a small roster for a single contact in a separate little window. package require msgcat namespace eval :: { ::msgcat::mcload [file join [file dirname [info script]] msgs] } namespace eval floatingcontact { if {![::plugins::is_registered floatingcontact]} { ::plugins::register floatingcontact \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Floating\ Contact plugin is\ loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } } proc floatingcontact::load {} { hook::add connected_hook ::ifacetk::roster::load_float_list hook::add disconnected_hook ::ifacetk::roster::save_float_list hook::add client_presence_hook \ ::ifacetk::roster::float_on_change_jid_presence 100 hook::add roster_service_popup_menu_hook \ ::ifacetk::roster::float_create_menu 80 hook::add roster_jid_popup_menu_hook \ ::ifacetk::roster::float_create_menu 80 foreach xlib [connections] { ::ifacetk::roster::load_float_list $xlib } } proc floatingcontact::unload {} { foreach xlib [connections] { ::ifacetk::roster::save_float_list $xlib } hook::remove connected_hook ::ifacetk::roster::load_float_list hook::remove disconnected_hook ::ifacetk::roster::save_float_list hook::remove client_presence_hook \ ::ifacetk::roster::float_on_change_jid_presence 100 hook::remove roster_service_popup_menu_hook \ ::ifacetk::roster::float_create_menu 80 hook::remove roster_jid_popup_menu_hook \ ::ifacetk::roster::float_create_menu 80 foreach proc {load_float_list save_float_list float_toggle float_redraw float_on_change_jid_presence float_start_drag float_motion_drag float_stop_drag float_create_menu} { rename ::ifacetk::roster::$proc "" } foreach var {float_winid float_savex float_savey float_x float_y float_is_float float_floats} { catch {unset ::ifacetk::roster::$var} } } namespace eval ::ifacetk::roster { variable float_winid 0 # {jid1 {rjid1 1 x y rjid2 0 x y} jid2 {rjid3 0 x y rjid4 0 x y}} custom::defvar floating_jids_list {} \ [::msgcat::mc "Stored floating JIDs."] \ -type string \ -group Hidden } proc ::ifacetk::roster::load_float_list {xlib} { variable floating_jids_list variable float_is_float variable float_x variable float_y array set fl $floating_jids_list set bjid [::xmpp::jid::normalize [connection_bare_jid $xlib]] if {![info exists fl($bjid)]} return foreach {jid float x y} $fl($bjid) { set float_is_float($xlib,$jid) $float set float_x($xlib,$jid) $x set float_y($xlib,$jid) $y float_toggle $xlib $jid } } proc ::ifacetk::roster::save_float_list {xlib} { variable floating_jids_list variable float_is_float variable float_x variable float_y variable float_floats array set fl $floating_jids_list set bjid [::xmpp::jid::normalize [connection_bare_jid $xlib]] set fl($bjid) {} foreach idx [array names float_is_float $xlib,*] { set jid [string range $idx [string length $xlib,] end] set float $float_is_float($xlib,$jid) set float_is_float($xlib,$jid) 0 float_toggle $xlib $jid if {[info exists float_x($xlib,$jid)] && \ [info exists float_y($xlib,$jid)]} { lappend fl($bjid) $jid \ $float \ $float_x($xlib,$jid) \ $float_y($xlib,$jid) unset float_x($xlib,$jid) unset float_y($xlib,$jid) } unset float_is_float($xlib,$jid) } if {[llength $fl($bjid)] == 0} { unset fl($bjid) } set floating_jids_list [array get fl] } proc ::ifacetk::roster::float_toggle {xlib jid} { variable float_is_float variable float_x variable float_y variable float_winid variable float_floats variable config variable iroster if {![info exists float_is_float($xlib,$jid)] || \ !$float_is_float($xlib,$jid)} { if {[info exists float_floats($xlib,$jid)]} { set w $float_floats($xlib,$jid) unset float_floats($xlib,$jid) catch {destroy $w} array unset iroster $w,* } } else { set w [toplevel .float[incr float_winid] \ -relief flat -bd 0.25em -class Balloon] $w configure -bg [option get $w foreground Balloon] set float_floats($xlib,$jid) $w wm withdraw $w wm overrideredirect $w 1 catch { if {[lsearch -exact [wm attributes $w] -topmost] >= 0} { wm attributes $w -topmost 1 } } if {![info exists float_x($xlib,$jid)] || \ ![info exists float_y($xlib,$jid)]} { set float_x($xlib,$jid) [expr {[winfo screenwidth $w] / 2}] set float_y($xlib,$jid) [expr {[winfo screenheight $w] / 2}] } wm geometry $w +$float_x($xlib,$jid)+$float_y($xlib,$jid) canvas $w.canvas -bg $config(background) \ -highlightthickness 0 \ -scrollregion {0 0 0 0} \ -width 0 -height 0 pack $w.canvas set iroster($w,ypos) 1 set iroster($w,width) 0 set iroster($w,grouppopup) {} set iroster($w,popup) [namespace current]::popup_menu set iroster($w,singleclick) {} set iroster($w,doubleclick) [namespace current]::jid_doubleclick float_redraw $xlib bind $w \ [list [namespace current]::float_start_drag %x %y] bind $w \ [list [namespace current]::float_motion_drag \ [double% $w] [double% $xlib] [double% $jid] %X %Y] bind $w \ [list [namespace current]::float_stop_drag %x %y] wm deiconify $w } } proc ::ifacetk::roster::float_redraw {xlib} { variable float_floats variable config variable iroster foreach idx [array names float_floats $xlib,*] { lassign [split $idx ,] xlib jid set w $float_floats($idx) if {![winfo exists $w]} continue clear $w 0 set cjid [list $xlib $jid] set jids [get_jids_of_user $xlib $jid] set numjids [llength $jids] addline $w jid [roster::get_label $xlib $jid] $cjid {} {} 0 $jids \ [get_jid_icon $xlib $jid] \ [get_jid_foreground $xlib $jid] if {$numjids > 1} { foreach subjid $jids { set csubjid [list $xlib $subjid] set subjid_resource [::xmpp::jid::resource $subjid] if {$subjid_resource != ""} { addline $w jid2 $subjid_resource $csubjid {} {} 0 \ [list $subjid] \ [get_jid_icon $xlib $subjid] \ [get_jid_foreground $xlib $subjid] } } } $w.canvas configure \ -width [expr {$iroster($w,width) + $config(jidindent)}] \ -height $iroster($w,ypos) update_scrollregion $w } } proc ::ifacetk::roster::float_on_change_jid_presence {xlib jid type x args} { after idle [list [namespace current]::float_redraw $xlib] } proc ::ifacetk::roster::float_start_drag {x y} { variable float_savex $x variable float_savey $y } proc ::ifacetk::roster::float_motion_drag {w xlib jid X Y} { variable float_x variable float_y variable float_savex variable float_savey set float_x($xlib,$jid) [expr {$X-$float_savex}] set float_y($xlib,$jid) [expr {$Y-$float_savey}] wm geometry $w +$float_x($xlib,$jid)+$float_y($xlib,$jid) } proc ::ifacetk::roster::float_stop_drag {x y} { variable float_savex variable float_savey catch {unset float_savex} catch {unset float_savey} } proc ::ifacetk::roster::float_create_menu {m xlib jid} { set rjid [roster::find_jid $xlib $jid] if {$rjid == ""} { set rjid [::xmpp::jid::stripResource $jid] } $m add checkbutton -label [::msgcat::mc "Floating contact"] \ -variable [namespace current]::float_is_float($xlib,$rjid) \ -command [list [namespace current]::float_toggle $xlib $rjid] } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/floatingcontact/msgs000075500000000000000000000000001500237002100175625ustar00nobodynobodytkabber-plugins/floatingcontact/msgs/de.msg000064400000000000000000000006431500237002100207440ustar00nobodynobody# de.msg -- # # German messages for the Floating Contact Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 15.03.2009 ::msgcat::mcset de "Floating contact" "Floating Contact" ::msgcat::mcset de "Stored floating JIDs." "Gespeicherte 'Floating Contacts'." ::msgcat::mcset de "Whether the Floating Contact plugin is loaded." \ "'Floating Contact'-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/floatingcontact/msgs/ru.msg000064400000000000000000000007631500237002100210050ustar00nobodynobody# ru.msg -- # # Russian messages for the Floating Contact Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Floating contact" "Плавающий контакт" ::msgcat::mcset ru "Stored floating JIDs." "Сохранённые плавающие контакты." ::msgcat::mcset ru "Whether the Floating Contact plugin is loaded."\ "Загружено ли раÑширение 'Плавающий контакт'." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/floatingcontact/msgs/uk.msg000064400000000000000000000007631500237002100207760ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Floating Contact Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Floating contact" "Плаваючий контакт" ::msgcat::mcset uk "Stored floating JIDs." "Збережені плаваючі контакты." ::msgcat::mcset uk "Whether the Floating Contact plugin is loaded."\ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ 'Плаваючий контакт'." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/floatinglog000075500000000000000000000000001500237002100157375ustar00nobodynobodytkabber-plugins/floatinglog/AUTHORS000064400000000000000000000001361500237002100170660ustar00nobodynobodyRakhmanin Ruslan Thanks to Konstantin Khomoutov for is_delayed function. tkabber-plugins/floatinglog/ChangeLog000064400000000000000000000023441500237002100175730ustar00nobodynobodyVersion 0.4 2007-08-26 Rakhmanin Ruslan * Double click on FloatingLog opens Tkabber window * You can off incoming message body show (it will show "Incoming message" string). Option "show_message_body". Default is on. * New default scheme of incoming message view. You can use old (simple) scheme by checking "simple_show_scheme" option. * Some bags fixed Version 0.3.1 2007-06-28 Rakhmanin Ruslan * You can off FloatingLog in away, xa, dnd status * You can choose if FloatingLog will show messages on active Tkabber window Version 0.3 2007-06-28 Rakhmanin Ruslan * Hide FloatingLog window on rigth button mouse click * Do not show messages on active Tkabber window * Use default colors from Tkabber for FloatingLog window Version 0.2 2007-06-06 Rakhmanin Ruslan * Do not show history messages from groupchat (on connecting to groupchat). * Do not show idle messages. * Options for on/off messages from chat, groupchat, other messages. Version 0.1 2007-06-03 Rakhmanin Ruslan * Initial version (0.1). For test only. * Show incoming messages and status messages in popup window tkabber-plugins/floatinglog/INSTALL000064400000000000000000000005021500237002100170440ustar00nobodynobodyCopy this directory under the ~/.tkabber/plugins directory so that you get a hierarchy like this: ~/.tkabber/plugins ~/.tkabber/plugins/floatinglog/ ~/.tkabber/plugins/floatinglog/floatinglog.tcl Restart Tkabber, to get the plugin loaded. Set option Tkabber -> Plugins -> FloatingLog -> show_log to enable plugin. tkabber-plugins/floatinglog/TODO000064400000000000000000000003251500237002100165060ustar00nobodynobodyDo not show messages from set_status hook but get all of them from other hooks Open chat window on left click on message Log grows up or down depends on position Do not show messages for selected groups in roster tkabber-plugins/floatinglog/VERSION000064400000000000000000000000421500237002100170620ustar00nobodynobodyVersion: 0.4 Date: 2007-August-26 tkabber-plugins/floatinglog/floatinglog.tcl000064400000000000000000000340661500237002100210400ustar00nobodynobody# floatinglog.tcl -- # # This file implements Floating Log plugin for the Tkabber XMPP client. package require msgcat namespace eval floatinglog { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered floatinglog]} { ::plugins::register floatinglog \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Floating\ Log plugin is\ loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable id 0 variable winname .floatinglog variable ignore_message_list {} lappend ignore_message_list [string map {%s *} \ [::msgcat::mc "Idle for %s"]] variable request_from [string map {%s *} [::msgcat::mc "%s request from %s"]] lappend ignore_message_list [string replace $request_from \ [string first * $request_from] \ [string first * $request_from] iqibb] lappend ignore_message_list [string replace $request_from \ [string first * $request_from] \ [string first * $request_from] ibb] lappend ignore_message_list [string map {%s *} \ [::msgcat::mc "Login retry for %s in %s"]] unset request_from # # Options section # custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup {Floating Log} \ [::msgcat::mc "Floating Log plugin options."] \ -group Plugins custom::defgroup {Floating Log Window} \ [::msgcat::mc "Floating Log window properties."] \ -group {Floating Log} custom::defgroup {Floating Log Control} \ [::msgcat::mc "Message types to show."] \ -group {Floating Log} custom::defvar options(show_log) 0 \ [::msgcat::mc "Show floating log."] \ -type boolean -group {Floating Log} custom::defvar options(show_chat) 1 \ [::msgcat::mc "Show chat messages."] \ -type boolean -group {Floating Log Control} custom::defvar options(show_groupchat) 1 \ [::msgcat::mc "Show groupchat messages."] \ -type boolean -group {Floating Log Control} custom::defvar options(show_other_messages) 1 \ [::msgcat::mc "Show other messages."] \ -type boolean -group {Floating Log Control} custom::defvar options(show_only_personal) 0 \ [::msgcat::mc "Show only personal messages and MUC highlights."] \ -type boolean -group {Floating Log Control} custom::defvar options(show_notifications) 1 \ [::msgcat::mc "Show notifications (presence state changes,\ chat state events, IQ queries etc)."] \ -type boolean -group {Floating Log Control} custom::defvar options(show_when_tkabber_is_active) 0 \ [::msgcat::mc "Show when Tkabber is active."] \ -type boolean -group {Floating Log Control} custom::defvar options(show_on_away_status) 1 \ [::msgcat::mc "Show in \"Away\" status."] \ -type boolean -group {Floating Log Control} custom::defvar options(show_on_xa_status) 1 \ [::msgcat::mc "Show in \"Extended away\" status."] \ -type boolean -group {Floating Log Control} custom::defvar options(show_on_dnd_status) 0 \ [::msgcat::mc "Show in \"Do not disturb\" status."] \ -type boolean -group {Floating Log Control} custom::defvar options(show_message_body) 1 \ [::msgcat::mc "Show incoming message body."] \ -type boolean -group {Floating Log Control} custom::defvar options(simple_show_scheme) 0 \ [::msgcat::mc "Use simple view scheme."] \ -type boolean -group {Floating Log Window} custom::defvar options(alpha) 80 \ [::msgcat::mc "Window opacity (in percent)."] \ -command [list [namespace current]::set_window] \ -type integer -group {Floating Log Window} custom::defvar options(position) "-0-60" \ [::msgcat::mc "Window position."] \ -command [list [namespace current]::set_window] \ -type string -group {Floating Log Window} custom::defvar options(max_height) [winfo pixels . 18c] \ [::msgcat::mc "Maximum window height."] \ -command [list [namespace current]::set_window] \ -type integer -group {Floating Log Window} custom::defvar options(width) [winfo pixels . 8c] \ [::msgcat::mc "Window width."] \ -command [list [namespace current]::set_window] \ -type integer -group {Floating Log Window} custom::defvar options(livetime) 5 \ [::msgcat::mc "Delay before message hide (in seconds)."] \ -type integer -group {Floating Log} } proc floatinglog::load {} { hook::add set_status_hook [namespace current]::process_status hook::add process_message_hook [namespace current]::process_message } proc floatinglog::unload {} { variable id variable winname variable ignore_message_list hook::remove set_status_hook [namespace current]::process_status hook::remove process_message_hook [namespace current]::process_message catch {destroy $winname} catch {unset id} catch {unset winname} catch {unset ignore_message_list} } # # Floating window initialization # proc floatinglog::window_initialization {} { variable options variable winname if {[winfo exists $winname]} { destroy $winname } toplevel $winname -bd 0 -class Balloon if {$::tcl_platform(platform) == "macintosh"} { catch {unsupported1 style $winname floating sideTitlebar} } elseif {$::aquaP} { ::tk::unsupported::MacWindowStyle style $winname help none } else { wm transient $winname . wm overrideredirect $winname 1 } catch { if {[lsearch -exact [wm attributes $winname] -topmost] >= 0} { wm attributes $winname -topmost 1 } } set_window bind $winname <> [namespace current]::right_click bind $winname [namespace current]::left_double_click } proc floatinglog::right_click {} { variable winname foreach id [after info] { if {[string first [namespace current]::del_text \ [after info $id]] >= 0} { after cancel $id } } if {[winfo exists $winname]} { destroy $winname } } proc floatinglog::left_double_click {} { ::ifacetk::systray::restore if {[focus] == ""} { focus -force . } } proc floatinglog::left_double_click_message {xlib jid type} { switch -- $type { groupchat { } chat { chat::open_to_user $xlib $jid } message { #message::send_dialog -to $jid } } } proc floatinglog::add_text {text {from ""} {xlib ""} {type ""} \ {is_subject ""} {subject ""}} { variable options variable id variable winname variable logfileId if {!($options(show_log))} {return} set active_window "" set active_window [focus] if {$active_window != "" && !$options(show_when_tkabber_is_active)} return if {!$options(show_on_away_status) && $::curuserstatus == "away"} return if {!$options(show_on_xa_status) && $::curuserstatus == "xa"} return if {!$options(show_on_dnd_status) && $::curuserstatus == "dnd"} return if {![winfo exists $winname]} { window_initialization } incr id if {$options(simple_show_scheme)} { add_text_scheme_simple $text $from $xlib $type $is_subject $subject } else { add_text_scheme_01 $text $from $xlib $type $is_subject $subject } } proc floatinglog::add_text_scheme_simple \ {body from xlib type is_subject subject} { variable options variable id variable winname variable logfileId if { $from != "" } { if {[catch {::chat::get_nick $xlib $from $type} nick]} { set nick [chat::get_nick $from $type] } if {!$options(show_message_body)} { set body [::msgcat::mc "Incoming message"] } set text [::msgcat::mc "From: "] set formattext [append text $nick " (" $from ")\n" "\n" $body] } else { set text $body } if {$text != ""} { set message_name $winname.msg$id message $message_name \ -text $text \ -width [expr $options(width) - 10] \ -justify left \ -relief solid -bd 0.25em -padx 0.75m -pady 0.75m set first_message [lindex [pack slaves $winname] 0] if {$first_message == ""} { pack $message_name -side bottom -fill x -padx 0.5m -pady 0.5m } else { pack $message_name -before $first_message \ -side bottom -fill x -padx 0.5m -pady 0.5m } if {($xlib != "") && ($from != "") && ($type != "")} { bind $message_name \ +[list [namespace current]::left_double_click_message \ $xlib [double% $from] [double% $type]] } after [expr {$options(livetime) * 1000}] \ [namespace current]::del_text "$message_name" } } proc floatinglog::add_text_scheme_01 {text from xlib type is_subject subject} { variable options variable id variable winname variable logfileId if {$text != ""} { if { ! $options(show_message_body) && $from != "" } { set text [::msgcat::mc "Incoming message"] } set message_name $winname.msg$id message $message_name \ -text $text \ -width [expr {$options(width) - 10}] \ -justify left \ -relief solid -bd 0.25em -padx 1m -pady 1m } if {$from != ""} { if {[catch {::chat::get_nick $xlib $from $type} nick]} { set nick [chat::get_nick $from $type] } if {$nick != "" } { append nick " (" $from ")" } else { set nick $from } set message_name_head $winname.msg${id}head message $message_name_head \ -text $nick \ -width [expr {$options(width) - 10}] \ -justify left \ -relief flat -bd 0.25em -padx 0 -pady 0 } set first_message [lindex [pack slaves $winname] 0] if {$first_message == ""} { if {$text != ""} { pack $message_name -side bottom -fill x -padx 0.5m -pady 0.5m } if {$from != ""} { pack $message_name_head -side bottom -fill x -padx 0.5m -pady 0 } } else { if {$text != ""} { pack $message_name -before $first_message \ -side bottom -fill x -padx 0.5m -pady 0.5m } if {$from != ""} { pack $message_name_head -before $first_message \ -side bottom -fill x -padx 0.5m -pady 0 } } if {($xlib != "") && ($from != "") && ($type != "")} { if {$from != ""} { bind $message_name_head \ +[list [namespace current]::left_double_click_message \ $xlib [double% $from] [double% $type]] } if {$text != "" } { bind $message_name \ +[list [namespace current]::left_double_click_message \ $xlib [double% $from] [double% $type]] } } if {$text != ""} { after [expr {$options(livetime) * 1000}] \ [namespace current]::del_text "$message_name" } } proc floatinglog::process_status {text} { variable ignore_message_list variable options if {!$options(show_notifications)} return foreach ignore_message $ignore_message_list { if {[string match $ignore_message $text]} return } add_text $text } proc floatinglog::del_text {{msg ""}} { variable winname if {[winfo exists $msg]} { pack forget $msg destroy $msg } append msg head if {[winfo exists $msg]} { pack forget $msg destroy $msg } if {[winfo children $winname] == ""} { if {[winfo exists $winname]} { destroy $winname } } } proc floatinglog::process_message {xlib from id type is_subject \ subject body err thread priority x} { variable options if {$body != ""} { switch -exact -- $type { chat { if {!$options(show_chat)} return } groupchat { if {!$options(show_groupchat)} return if {[::xmpp::delay::exists $x]} return if {![catch { ::plugins::mucignore::is_ignored $xlib $from $type } ignore] && $ignore != ""} return if {$options(show_only_personal)} { set chatid [chat::chatid $xlib \ [::xmpp::jid::stripResource $from]] set myjid [chat::our_jid $chatid] set mynick [chat::get_nick $xlib $myjid $type] if {![check_message $mynick $body]} return } } default { if {!$options(show_other_messages)} return } } catch { add_text $body $from $xlib $type $is_subject $subject } } } proc floatinglog::set_window {args} { variable options variable winname if {![winfo exists $winname]} { return } catch { if {[lsearch -exact [wm attributes $winname] -alpha] >= 0} { wm attributes $winname -alpha [expr $options(alpha) / 100.0] } } wm minsize $winname $options(width) 10 wm maxsize $winname $options(width) $options(max_height) wm geometry $winname $options(position) raise $winname } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/floatinglog/license.terms000064400000000000000000000020721500237002100205150ustar00nobodynobodyCopyright (c) 2007 Rakhmanin Ruslan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tkabber-plugins/floatinglog/msgs000075500000000000000000000000001500237002100167105ustar00nobodynobodytkabber-plugins/floatinglog/msgs/de.msg000064400000000000000000000051351500237002100200730ustar00nobodynobody# de.msg -- # # German messages for the Tkabber Floating Log plugin. # # Author: Roger Sondermann # Last-Modified: 13.03.2009 ::msgcat::mcset de "%s request from %s" "%s-Anfrage von %s" ::msgcat::mcset de "Delay before message hide (in seconds)." \ "Verzögerung bevor das 'Floating Log'-Fenster verborgen wird (in\ Sekunden)." ::msgcat::mcset de "Floating Log plugin options." \ "Optionen für das 'Floating Log'-Plugin." ::msgcat::mcset de "Floating Log window properties." \ "Eigenschaften des 'Floating Log'-Fensters." ::msgcat::mcset de "From: " "Von: " ::msgcat::mcset de "Idle for %s" "Leerlauf seit %s" ::msgcat::mcset de "Incoming message" "Eingehende Nachricht" ::msgcat::mcset de "Login retry for %s in %s" \ "Anmeldungs-Wiederholung für %s in %s" ::msgcat::mcset de "Maximum window height." "Maximale Höhe des Fensters." ::msgcat::mcset de "Message types to show." "Anzuzeigende Nachrichten-Typen." ::msgcat::mcset de "Plugins options." "Optionen für Plugins." ::msgcat::mcset de "Show chat messages." "Chat-Nachrichten anzeigen." ::msgcat::mcset de "Show floating log." "'Floating Log'-Fenster anzeigen." ::msgcat::mcset de "Show groupchat messages." "Konferenz-Nachrichten anzeigen." ::msgcat::mcset de "Show in \"Away\" status." "Bei Status 'Abwesend' anzeigen." ::msgcat::mcset de "Show in \"Do not disturb\" status." \ "Bei Status 'Bitte nicht stören' anzeigen." ::msgcat::mcset de "Show in \"Extended away\" status." \ "Bei Status 'Länger abwesend' anzeigen." ::msgcat::mcset de "Show incoming message body." \ "Eingehenden Nachrichten-Text anzeigen." ::msgcat::mcset de "Show notifications (presence state changes, chat state\ events, IQ queries etc)." "Benachrichtigungen\ (Präsenz-Status-Änderungen, Chat-Status-Ereignisse, IQ-Anfragen, etc.)\ anzeigen." ::msgcat::mcset de "Show only personal messages and MUC highlights." \ "Nur persönliche Nachrichten und markierte MUC-Nachrichten anzeigen." ::msgcat::mcset de "Show other messages." "Andere Nachrichten anzeigen." ::msgcat::mcset de "Show when Tkabber is active." \ "Bei aktivem Tkabber-Fenster anzeigen." ::msgcat::mcset de "Use simple view scheme." \ "Einfache Art der Anzeige benutzen." ::msgcat::mcset de "Whether the Floating Log plugin is loaded." \ "'Floating Log'-Plugin laden." ::msgcat::mcset de "Window opacity (in percent)." \ "Transparenz des Fensters (in Prozent)." ::msgcat::mcset de "Window position." "Position des Fensters." ::msgcat::mcset de "Window width." "Breite des Fensters." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/floatinglog/msgs/es.msg000064400000000000000000000050441500237002100201110ustar00nobodynobody# es.msg -- # # Spanish messages for the Tkabber Floating Log plugin. # # Author: Badlop ::msgcat::mcset es "%s request from %s" "Petición %s de %s" ::msgcat::mcset es "Delay before message hide (in seconds)." \ "Retraso antes de ocultar el mensaje (en segundos)." ::msgcat::mcset es "Floating Log plugin options." \ "Opciones del plugin Floating Log." ::msgcat::mcset es "Floating Log window properties." \ "Propiedades de la ventana Floating Log." ::msgcat::mcset es "From: " "De: " ::msgcat::mcset es "Idle for %s" "Inactivo para %s" ::msgcat::mcset es "Incoming message" "Mensaje entrante" ::msgcat::mcset es "Login retry for %s in %s" \ "Intento de reconectar para %s en %s" ::msgcat::mcset es "Maximum window height." "Altura máxima de ventana." ::msgcat::mcset es "Message types to show." "Tipos de mensajes a mostrar." ::msgcat::mcset es "Plugins options." "Opciones de plugins." ::msgcat::mcset es "Show chat messages." "Mostrar mensajes de charla." ::msgcat::mcset es "Show floating log." "Mostrar log (histórico) flotante." ::msgcat::mcset es "Show groupchat messages." \ "Mostrar mensajes de grupos de charla." ::msgcat::mcset es "Show in \"Away\" status." \ "Mostrar en el estado \"Ausente\"." ::msgcat::mcset es "Show in \"Do not disturb\" status." \ "Mostrar en el estado \"No molestar\"." ::msgcat::mcset es "Show in \"Extended away\" status." \ "Mostrar en el estado \"Muy Ausente\"." ::msgcat::mcset es "Show incoming message body." \ "Mostrar cuerpo del mensaje de entrada." ::msgcat::mcset es "Show notifications (presence state changes, chat state\ events, IQ queries etc)." "Mostrar notificaciones (cambios en el\ estado de la presencia, eventos del estado de la charla, peticiones\ IQ, etc)." ::msgcat::mcset es "Show only personal messages and MUC highlights." \ "Mostrar solo mensajes personales y resaltados de las salas de charla." ::msgcat::mcset es "Show other messages." "Mostrar otros mensajes." ::msgcat::mcset es "Show when Tkabber is active." \ "Mostrar cuando Tkabber está activo." ::msgcat::mcset es "Use simple view scheme." \ "Usar esquema de visionado simple." ::msgcat::mcset es "Whether the Floating Log plugin is loaded." \ "Cargar el plugin Floating Log." ::msgcat::mcset es "Window opacity (in percent)." \ "Opacidad de la ventana (en porcentaje)." ::msgcat::mcset es "Window position." "Posición de la ventana." ::msgcat::mcset es "Window width." "Ancho de la ventana." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/floatinglog/msgs/pl.msg000064400000000000000000000050271500237002100201160ustar00nobodynobody# pl.msg -- # # Polish messages for the Tkabber Floating Log plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Delay before message hide (in seconds)." \ "OdstÄ™p czasu, po którym widomość zostanie ukryta (w sekundach)" ::msgcat::mcset pl "Floating Log plugin options." \ "Ustawienia wtyczki FloatingLog." ::msgcat::mcset pl "Floating Log window properties." \ "WÅ‚aÅ›ciowoÅ›ci okna FloatingLog." ::msgcat::mcset pl "From: " "Od: " ::msgcat::mcset pl "Idle for %s" "Bezczynny przez %s" ::msgcat::mcset pl "Incoming message" "Wiadomość przychodzÄ…ca" ::msgcat::mcset pl "Message types to show." "Typy pokazywanych wiadomoÅ›ci." ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "Show chat messages." "Pokaż wiadomoÅ›ci z rozmów." ::msgcat::mcset pl "Show floating log." "Pokaż okno FloatingLog." ::msgcat::mcset pl "Show groupchat messages." "Pokaż wiadomoÅ›ci z konferencji." ::msgcat::mcset pl "Show in \"Away\" status." \ "Pokaż przy statusie \"Zaraz wracam\"." ::msgcat::mcset pl "Show in \"Do not disturb\" status." \ "Pokaż przy statusie \"Nie przeszkadzać\"." ::msgcat::mcset pl "Show in \"Extended away\" status." \ "Pokaż przy statusie \"Nieobecny\"." ::msgcat::mcset pl "Show incoming message body." \ "Pokaż treść przychodzÄ…cej wiadomoÅ›ci." ::msgcat::mcset pl "Show other messages." "Pokaż inne wiadomoÅ›ci." ::msgcat::mcset pl "Show when Tkabber is active." \ "Pokaż gdy aktywne jest główne okno Tkabbera." ::msgcat::mcset pl "Use simple view scheme." "Używaj prostego schematu widoku." ::msgcat::mcset pl "Window opacity (in percent)." \ "Przeźroczystość okna (w procentach)." ::msgcat::mcset pl "Window position." "Pozycja okna." ::msgcat::mcset pl "Window width." "Szerokość okna." ::msgcat::mcset pl "Show notifications (presence state changes, chat state\ events, IQ queries etc)." "Pokaż powiadomienia (zmiany statusów,\ zdarzenia wiadomoÅ›ci, zapytania IQ itp.)." ::msgcat::mcset pl "Show only personal messages and MUC highlights." \ "Pokaż tylko wiadomoÅ›ci do mnie i podkreÅ›lone wiadomoÅ›ci MUC." ::msgcat::mcset pl "Maximum window height." "Maksymalna szerokość okna." ::msgcat::mcset pl "%s request from %s" "Zapytanie %s od %s" ::msgcat::mcset pl "Login retry for %s in %s" \ "Ponowna próba połączenia dla %s za %s" ::msgcat::mcset pl "Whether the Floating Log plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ FloatingLog" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/floatinglog/msgs/ru.msg000064400000000000000000000065561500237002100201410ustar00nobodynobody# ru.msg -- # # Russian messages for the Tkabber Floating Log plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "%s request from %s" "Ð—Ð°Ð¿Ñ€Ð¾Ñ %s от %s" ::msgcat::mcset ru "Delay before message hide (in seconds)." \ "Задержка перед тем, как Ñообщение иÑчезнет (в Ñекундах)." ::msgcat::mcset ru "From: " "От: " ::msgcat::mcset ru "Floating Log plugin options." \ "ÐаÑтройки раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ ÐŸÐ»Ð°Ð²Ð°ÑŽÑ‰Ð¸Ð¹ журнал." ::msgcat::mcset ru "Floating Log window properties." \ "СвойÑтва окна плавающего журнала." ::msgcat::mcset ru "Idle for %s" "Ð’Ñ€ÐµÐ¼Ñ Ð±ÐµÐ·Ð´ÐµÐ¹ÑтвиÑ: %s" ::msgcat::mcset ru "Incoming message" "ВходÑщее Ñообщение" ::msgcat::mcset ru "Maximum window height." "МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð²Ñ‹Ñота окна." ::msgcat::mcset ru "Message types to show." \ "Типы Ñообщений, которые Ñледует показывать." ::msgcat::mcset ru "Plugins options." "ÐаÑтройки раÑширений." ::msgcat::mcset ru "Show chat messages." "Показывать ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð³Ð¾Ð²Ð¾Ñ€Ð°." ::msgcat::mcset ru "Show floating log." "Показывать плавающий журнал." ::msgcat::mcset ru "Show groupchat messages." "Показывать групповые ÑообщениÑ." ::msgcat::mcset ru "Show in \"Away\" status." \ "Показывать в ÑоÑтоÑнии \"Отошёл\"." ::msgcat::mcset ru "Show in \"Do not disturb\" status." \ "Показывать в ÑоÑтоÑнии \"Ðе беÑпокоить\"." ::msgcat::mcset ru "Show in \"Extended away\" status." \ "Показывать в ÑоÑтоÑнии \"Отошёл давно\"." ::msgcat::mcset ru "Show incoming message body." \ "Показывать текÑÑ‚ входÑщих Ñообщений." ::msgcat::mcset ru "Show notifications (presence state changes, chat state\ events, IQ queries etc)." "Показывать ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ (изменение\ приÑутÑтвиÑ, ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð² окне разговора, запроÑÑ‹ и Ñ‚.п.)" ::msgcat::mcset ru "Show only personal messages and MUC highlights." \ "Показывать только перÑональные ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸ выделенные ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð²\ конференциÑÑ…." ::msgcat::mcset ru "Show other messages." "Показывать другие ÑообщениÑ." ::msgcat::mcset ru "Show when Tkabber is active." \ "Показывать, когда окно Tkabber'а активно." ::msgcat::mcset ru "Use simple view scheme." \ "ИÑпользовать упрощенный вывод Ñообщений." ::msgcat::mcset ru "Window position." "Положение окна." ::msgcat::mcset ru "Window opacity (in percent)." \ "ÐепрозрачноÑть окна (в процентах)." ::msgcat::mcset ru "Window width." "Ширина окна." ::msgcat::mcset ru "Login retry for %s in %s" "Ð¡Ð»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ Ð¿Ð¾Ð¿Ñ‹Ñ‚ÐºÐ° подключениÑ\ %s через %s" ::msgcat::mcset ru "Whether the Floating Log plugin is loaded."\ "Загружено ли раÑширение 'Плавающий журнал Ñообщений'." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/floatinglog/msgs/uk.msg000064400000000000000000000065601500237002100201250ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Tkabber Floating Log plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "%s request from %s" "Запит %s від %s" ::msgcat::mcset uk "Delay before message hide (in seconds)." \ "Затримка перед тим, Ñк Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð·Ð½Ð¸ÐºÐ½Ðµ (в Ñекундах)." ::msgcat::mcset uk "From: " "Від: " ::msgcat::mcset uk "Floating Log plugin options." \ "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ ÐŸÐ»Ð°Ð²Ð°ÑŽÑ‡Ð¸Ð¹ журнал." ::msgcat::mcset uk "Floating Log window properties." \ "ВлаÑтивоÑті вікна плаваючого журналу." ::msgcat::mcset uk "Idle for %s" "Ð§Ð°Ñ Ð±ÐµÐ·Ð´Ñ–ÑльноÑті: %s" ::msgcat::mcset uk "Incoming message" "Вхідне повідомленнÑ" ::msgcat::mcset uk "Maximum window height." "МакÑимальна виÑота вікна." ::msgcat::mcset uk "Message types to show." \ "Типи повідомлень, Ñкі треба показувати." ::msgcat::mcset uk "Plugins options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½ÑŒ." ::msgcat::mcset uk "Show chat messages." "Показувати Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·Ð¼Ð¾Ð²." ::msgcat::mcset uk "Show floating log." "Показувати плаваючий журнал." ::msgcat::mcset uk "Show groupchat messages." "Показувати групові повідомленнÑ." ::msgcat::mcset uk "Show in \"Away\" status." \ "Показувати у Ñтані \"Відійшов\"." ::msgcat::mcset uk "Show in \"Do not disturb\" status." \ "Показувати у Ñтані \"Ðе турбувати\"." ::msgcat::mcset uk "Show in \"Extended away\" status." \ "Показувати у Ñтані \"Відійшов давно\"." ::msgcat::mcset uk "Show incoming message body." \ "Показувати текÑÑ‚ вхідних повідомлень." ::msgcat::mcset uk "Show notifications (presence state changes, chat state\ events, IQ queries etc)." "Показувати нотфікації (зміну\ приÑутноÑті, події у вікнах розмов, запити Ñ– Ñ‚.Ñ–.)" ::msgcat::mcset uk "Show only personal messages and MUC highlights." \ "Показувати тільки оÑобиÑті Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ– виділені Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð²\ конференціÑÑ…." ::msgcat::mcset uk "Show other messages." "Показувати інші повідомленнÑ." ::msgcat::mcset uk "Show when Tkabber is active." \ "Показувати, коли вікно Tkabber'а активне." ::msgcat::mcset uk "Use simple view scheme." \ "ВикориÑтовувати Ñпрощений вивід повідомлень." ::msgcat::mcset uk "Window position." "ÐŸÐ¾Ð»Ð¾Ð¶ÐµÐ½Ð½Ð½Ñ Ð²Ñ–ÐºÐ½Ð°." ::msgcat::mcset uk "Window opacity (in percent)." \ "ÐепрозоріÑть вікна (в процентах)." ::msgcat::mcset uk "Window width." "Ширина вікна." ::msgcat::mcset uk "Login retry for %s in %s" "ÐаÑтупна Ñпроба підключеннÑ\ %s через %s" ::msgcat::mcset uk "Whether the Floating Log plugin is loaded."\ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ 'Плаваючий журнал повідомлень'." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/georoster000075500000000000000000000000001500237002100154435ustar00nobodynobodytkabber-plugins/georoster/ChangeLog000064400000000000000000000107611500237002100173010ustar00nobodynobody2006-04-27 Alexey Shchepin * msgs/ru.msg: Updated (thanks to Sergei Golovan) 2006-04-09 Alexey Shchepin * msgs/es.msg: Updated (thanks to Badlop) 2006-02-26 Alexey Shchepin * georoster.tcl: Updated (thanks to Sergei Golovan) 2005-08-14 Alexey Shchepin * msgs/nl.msg: Updated (thanks to Sander Devrieze) 2005-05-15 Alexey Shchepin * msgs/: Updated (thanks to Sergei Golovan) * georoster.tcl: Replaced "GeoRoster" with "Georoster" (thanks to Sergei Golovan) 2005-03-03 Alexey Shchepin * msgs/ru.msg: Updated (thanks to Sergei Golovan) * georoster.tcl: Don't store translated strings in options, better labels placement (thanks to Sergei Golovan) * earth.ru: Better aligment (thanks to Sergei Golovan) * earth: More cities (thanks to Sergei Golovan) 2004-12-22 Alexey Shchepin * georoster.tcl: Allows translation of more strings (thanks to Badlop) 2004-07-17 Alexey Shchepin * msgs/nl.msg: Dutch translation (thanks to Sander Devrieze) 2004-04-03 Alexey Shchepin * georoster.tcl: Fix to prevent some spurious bgerrors (thanks to Marshall T. Rose) 2004-02-17 Alexey Shchepin * georoster.tcl: Updated to latest tkabber cvs version (thanks to Badlop) 2003-11-17 Alexey Shchepin * georoster.tcl: Don't ask for a vcard if we're looking at the presence from a conference room (thanks to Marshall T. Rose) 2003-10-01 Alexey Shchepin * msgs/es.msg: Spanish translation (thanks to Badlop) 2003-08-16 Alexey Shchepin * georoster.tcl: Minor fix (thanks to Marshall T. Rose) 2003-07-22 Alexey Shchepin * georoster.tcl: Bugfix (thanks to Marshall T. Rose) 2003-06-26 Alexey Shchepin * bwmap4.gif: Update (thanks to Marshall T. Rose) * georoster.tcl: Added a -timeout to one of the http calls (thanks to Marshall T. Rose) 2003-06-24 Alexey Shchepin * georoster.tcl: Now works with latest tkabber cvs version 2003-06-17 Alexey Shchepin * de.coords: Updated (thanks to Roger Sondermann) 2003-06-16 Alexey Shchepin * georoster.tcl (georoster::retrieve): Updated due to changes in connected_hook call * georoster.tcl: Removed canvas background setting (thanks to Marshall T. Rose) 2003-05-20 Alexey Shchepin * de.coords: Fixed tabs (thanks to Roger Sondermann) 2003-05-19 Alexey Shchepin * georoster.tcl: More debugging (thanks to Marshall T. Rose) * jm.coords: Coordinates for Jamaica (thanks to Roger Sondermann) * earth: Updated (thanks to Roger Sondermann) * de.coords: Likewise 2003-05-17 Alexey Shchepin * msgs/ru.msg: Updated (thanks to Sergei Golovan) 2003-04-29 Alexey Shchepin * georoster.tcl: Make the http lookup for US localities asynchronous 2003-04-19 Alexey Shchepin * de.coords: Coords for German cities (thanks to Roger Sondermann) 2003-04-17 Alexey Shchepin * (ru|ua|nl).coords: Not-completed coords files (thanks to Marshall T. Rose) * iso3166: Updated (thanks to Marshall T. Rose) * georoster.tcl: Updated (thanks to Marshall T. Rose) 2003-04-12 Alexey Shchepin * georoster.tcl: New option show_last_known (thanks to Marshall T. Rose) 2003-04-10 Alexey Shchepin * us.coords: Coords for US cities (thanks to Marshall T. Rose) * iso3166: ISO3166 country codes (thanks to Marshall T. Rose) * howto.txt: GeoRoster HOWTO (thanks to Marshall T. Rose) * bwmap4.gif: New map image (thanks to Marshall T. Rose) * darkmap.gif: Likewise * colormap.jpg: New color map (thanks to Roger Sondermann) * georoster.tcl: More methods to find coordinates, many other changes (thanks to Marshall T. Rose) 2003-04-07 Alexey Shchepin * georoster.tcl: Now uses customization interface, added option to make vCard lookups optional (and off by default) 2003-04-06 Alexey Shchepin * georoster.tcl: Now this plugin also looks at vCard to find user coordinates (LAT/LON fields or REGION/LOCALITY and/or PCODE for US) (thanks to Marshall T. Rose) * earth.ru: Added russian translation * earth: Removed overlapped cities, added some new cities (thanks to Roger Sondermann) tkabber-plugins/georoster/cities000075500000000000000000000000001500237002100167235ustar00nobodynobodytkabber-plugins/georoster/cities/earth000064400000000000000000000170271500237002100200370ustar00nobodynobody# Longitudes and latitudes are available from: # http://www.heavens-above.com/countries.asp # http://www.getty.edu/research/tools/vocabulary/tgn/index.html 90.00 0.00 "North Pole" # North Pole -90.00 0.00 "South Pole" # South Pole # 23.05 72.67 "Ahmadabad" timezone=Asia/Calcutta # India # 31.20 29.90 "Alexandria" timezone=Africa/Cairo # Egypt 43.25 76.95 "Almaty" timezone=Asia/Almaty # Kazakhstan 61.22 -149.90 "Anchorage" timezone=America/Anchorage # Canada # 39.92 32.83 "Ankara" timezone=Asia/Istanbul # Turkey 37.97 23.72 "Athens" timezone=Europe/Athens # Greece 33.35 44.42 "Baghdad" timezone=Asia/Baghdad # Iraq # 12.97 77.58 "Bangalore" timezone=Asia/Calcutta # India 13.73 100.50 "Bangkok" timezone=Asia/Bangkok # Thailand 52.53 13.42 "Berlin" timezone=Europe/Berlin # Germany # 39.92 116.43 "Beijing" timezone=Asia/Shanghai # China 4.63 -74.08 "Bogotá" timezone=America/Bogota # Colombia # 42.35 -71.05 "Boston" timezone=US/Eastern # USA -34.67 -58.50 "Buenos Aires" timezone=America/Buenos_Aires # Argentina 30.05 31.25 "Cairo" timezone=Africa/Cairo # Egypt 22.50 88.33 "Calcutta" timezone=Asia/Calcutta # India 10.50 -66.92 "Caracas" timezone=America/Caracas # Venezuela # 30.62 104.10 "Chengdu" timezone=Asia/Chongqing # China # 13.08 80.30 "Chennai" timezone=Asia/Calcutta # India 41.85 -87.65 "Chicago" timezone=America/Chicago # USA # 30.65 103.68 "Chongqing" timezone=Asia/Chongqing # China 32.78 -96.80 "Dallas" timezone=America/Chicago # USA 14.67 -17.43 "Dakar" timezone=Africa/Dakar # Senegal 28.67 77.22 "Delhi" timezone=Asia/Calcutta # India # 42.32 -83.03 "Detroit" timezone=America/Detroit # USA # 23.72 90.37 "Dhaka" timezone=Asia/Dhaka # Bangladesh # 51.15 7.00 "Düsseldorf" timezone=Europe/Berlin # Germany # 51.45 6.95 "Essen" timezone=Europe/Berlin # Germany # 23.13 113.33 "Guangzhou" timezone=Asia/Shanghai # China # 45.75 126.68 "Harbin" timezone=Asia/Harbin # China # 10.75 106.67 "Ho Chi Minh City" timezone=Asia/Saigon # Vietnam 22.28 114.15 "Hong Kong" timezone=Hongkong # China # 17.37 78.43 "Hyderabad" timezone=Asia/Calcutta # India 52.27 104.33 "Irkutsk" timezone=Asia/Irkutsk # Russia 41.03 28.95 "Istanbul" timezone=Asia/Istanbul # Turkey -6.13 106.75 "Jakarta" timezone=Asia/Jakarta # Indonesia -26.17 28.03 "Johannesburg" timezone=Africa/Johannesburg # South Africa # 51.15 6.37 "Kaarst" timezone=Europe/Berlin # Germany 24.85 67.03 "Karachi" timezone=Asia/Karachi # Pakistan 27.72 85.32 "Katmandu" timezone=Asia/Katmandu # Nepal 15.55 32.53 "Khartoum" timezone=Africa/Khartoum # Sudan 50.43 30.52 "Kiev" timezone=Europe/Kiew # Ukraine 18.00 -76.80 "Kingston" timezone=America/Jamaica # Jamaica -4.30 15.30 "Kinshasa" timezone=Africa/Kinshasa # Congo 6.45 3.47 "Lagos" timezone=Africa/Lagos # Nigeria # 31.57 74.37 "Lahore" timezone=Asia/Karachi # Pakistan -12.05 -77.05 "Lima" timezone=America/Lima # Peru 51.50 -0.17 "London" timezone=Europe/London # United Kingdom 34.05 -118.23 "Los Angeles" timezone=US/Pacific # USA 40.42 -3.72 "Madrid" timezone=Europe/Madrid # Spain 14.62 120.97 "Manila" timezone=Asia/Manila # Philippines -37.75 144.97 "Melbourne" timezone=Australia/Melbourne # Australia 19.40 -99.15 "Mexico City" timezone=America/Mexico_City # Mexico 45.52 -73.57 "Montreal" timezone=America/Montreal # Canada 55.75 37.70 "Moscow" timezone=Europe/Moscow # Russia # 18.93 72.85 "Mumbai" timezone=Asia/Calcutta # India # 35.13 136.88 "Nagoya" timezone=Asia/Tokyo # Japan -1.28 36.82 "Nairobi" timezone=Africa/Nairobi # Kenia 40.70 -74.00 "New York" timezone=US/Eastern # USA 55.07 83.08 "Novosibirsk" timezone=Asia/Novosibirsk # Russia 55.00 73.37 "Omsk" timezone=Asia/Omsk # Russia 34.67 135.50 "Osaka" timezone=Asia/Tokyo # Japan 48.87 2.33 "Paris" timezone=Europe/Paris # France 53.02 158.65 "Petropavlovsk-K." timezone=Asia/Kamchatka # Russia # 39.95 -75.15 "Philadelphia" timezone=US/Eastern # USA # 35.08 129.03 "Pusan" timezone=Asia/Seoul # South Korea # 39.00 125.78 "Pyongyang" timezone=Asia/Pyongyang # North Korea -22.88 -43.28 "Rio de Janeiro" timezone=America/Sao_Paulo # Brazil 41.90 12.48 "Rom" timezone=Europe/Rom # Italy 37.77 -122.42 "San Francisco" timezone=America/Los_Angeles # USA -33.45 -70.67 "Santiago" timezone=Chile/Continental # Chile -23.55 -46.65 "São Paulo" timezone=America/Sao_Paulo # Brazil 37.53 127.00 "Seoul" timezone=Asia/Seoul # South Korea 44.50 34.00 "Sevastopol" timezone=Europe/Simferopol # Ukraine 31.10 121.37 "Shanghai" timezone=Asia/Shanghai # China # 41.83 123.43 "Shenyang" timezone=Asia/Shanghai # China 1.28 103.85 "Singapore" timezone=Asia/Singapore # Singapore 59.88 30.25 "St. Petersburg" timezone=Europe/Moscow # Russia 59.33 18.08 "Stockholm" timezone=Europe/Stockholm # Russia -33.92 151.17 "Sydney" timezone=Australia/Sydney # Australia # 25.02 121.37 "Taipei" timezone=Asia/Taipei # Taiwan 35.67 51.43 "Teheran" timezone=Asia/Tehran # Iran # 39.13 117.20 "Tianjin" timezone=Asia/Shanghai # China 35.75 139.50 "Tokyo" timezone=Asia/Tokyo # Japan # 43.70 -79.42 "Toronto" timezone=America/Montreal # Canada 49.27 -123.12 "Vancouver" timezone=America/Vancouver # Canada 43.15 131.88 "Vladivostok" timezone=Asia/Vladivostok # Russia 38.88 -77.03 "Washington" timezone=US/Eastern # USA # 30.58 114.32 "Wuhan" timezone=Asia/Shanghai # China # 34.27 108.90 "Xian" timezone=Asia/Shanghai # China 56.87 60.58 "Yekaterinburg" timezone=Asia/Yekaterinburg # Russia # 35.47 139.63 "Yokohama" timezone=Asia/Tokyo # Japan tkabber-plugins/georoster/cities/earth.ru000064400000000000000000000171741500237002100204670ustar00nobodynobody# Longitudes and latitudes are from # http://www.getty.edu/research/tools/vocabulary/tgn/index.html # http://www.gnu.org/manual/glibc-2.2.3/html_node/libc_431.html 90.00 0.00 "Северный полюÑ" color=LightBlue # North Pole -90.00 0.00 "Южный полюÑ" color=LightBlue # South Pole 43.25 76.95 "Ðлматы" timezone=Asia/Almaty # Kazakhstan 37.97 23.72 "Ðфины" timezone=Europe/Athens # Greece 61.22 -149.90 "Ðнкоридж" timezone=America/Anchorage # Canada 33.35 44.42 "Багдад" timezone=Asia/Baghdad # Iraq 12.97 77.58 "Бенгалуру" timezone=Asia/Calcutta # India 13.73 100.50 "Бангкок" timezone=Asia/Bangkok # Thailand 52.53 13.42 "Берлин" timezone=Europe/Berlin # Germany 39.92 116.43 "Пекин" timezone=Asia/Shanghai # China 4.63 -74.08 "Богота" timezone=America/Bogota # Colombia # 42.35 -71.05 "БоÑтон" timezone=US/Eastern # USA -34.67 -58.50 "БуÑноÑ-ÐйреÑ" timezone=America/Buenos_Aires # Argentina 30.05 31.25 "Каир" timezone=Africa/Cairo # Egypt 22.50 88.33 "Калькутта" timezone=Asia/Calcutta # India 10.50 -66.92 "КаракаÑ" timezone=America/Caracas # Venezuela # 13.08 80.30 "МадраÑ" timezone=Asia/Calcutta # India 41.85 -87.65 "Чикаго" timezone=America/Chicago # USA 30.65 103.68 "ЧÑнду" timezone=Asia/Chongqing # China 32.78 -96.80 "ДаллаÑ" timezone=America/Chicago # USA 28.67 77.22 "Дели" timezone=Asia/Calcutta # India # 42.32 -83.03 "Детройт" timezone=America/Detroit # USA 23.72 90.37 "Дакка" timezone=Asia/Dhaka # Bangladesh # 51.45 6.95 "ЭÑÑен" timezone=Europe/Berlin # Germany 22.28 114.15 "Гонконг" timezone=Hongkong # China 17.37 78.43 "Хайдарабад" timezone=Asia/Calcutta # India 52.27 104.33 "ИркутÑк" timezone=Asia/Irkutsk # Russia 41.03 28.95 "Стамбул" timezone=Asia/Istanbul # Turkey -6.13 106.75 "Джакарта" timezone=Asia/Jakarta # Indonesia -26.17 28.03 "ЙоханнеÑбург" timezone=Africa/Johannesburg # South Africa 24.85 67.03 "Карачи" timezone=Asia/Karachi # Pakistan 15.55 32.53 "Хартум" timezone=Africa/Khartoum # Sudan 50.43 30.52 "Киев" timezone=Europe/Kiew # Ukraine -4.30 15.30 "КиншаÑа" timezone=Africa/Kinshasa # Congo 6.45 3.47 "ЛагоÑ" timezone=Africa/Lagos # Nigeria # 31.57 74.37 "Лахор" timezone=Asia/Karachi # Pakistan -12.05 -77.05 "Лима" timezone=America/Lima # Peru 51.50 -0.17 "Лондон" timezone=GB # United Kingdom 34.05 -118.23 "ЛоÑ-ÐнжелеÑ" timezone=US/Pacific # USA 40.42 -3.72 "Мадрид" timezone=Europe/Madrid # Spain 14.62 120.97 "Манила" timezone=Asia/Manila # Philippines -37.75 144.97 "Мельбурн" timezone=Australia/Melbourne # Australia 19.40 -99.15 "Мехико" timezone=America/Mexico_City # Mexico 45.52 -73.57 "Монреаль" timezone=America/Montreal # Canada 55.75 37.70 "МоÑква" timezone=Europe/Moscow # Russia 18.93 72.85 "Бомбей" timezone=Asia/Calcutta # India 40.70 -74.00 "Ðью-Йорк" timezone=US/Eastern # USA 55.07 83.08 "ÐовоÑибирÑк" timezone=Asia/Novosibirsk # Russia 55.00 73.37 "ОмÑк" timezone=Asia/Omsk # Russia 34.67 135.50 "ОÑака" timezone=Asia/Tokyo # Japan 48.87 2.33 "Париж" timezone=Europe/Paris # France 53.02 158.65 "ПетропавловÑк-К." timezone=Asia/Kamchatka # Russia # 39.95 -75.15 "ФиладельфиÑ" timezone=US/Eastern # USA -22.88 -43.28 "Рио-де-Жанейро" timezone=America/Sao_Paulo # Brazil 37.77 -122.42 "Сан-ФранциÑко" timezone=America/Los_Angeles # USA -33.45 -70.67 "СантьÑго" timezone=Chile/Continental # Chile 44.50 34.00 "СеваÑтополь" timezone=Europe/Simferopol # Ukraine -23.55 -46.65 "Сан-Паулу" timezone=America/Sao_Paulo # Brazil 37.53 127.00 "Сеул" timezone=Asia/Seoul # South Korea -33.92 151.17 "Сидней" timezone=Australia/Sydney # Australia 1.28 103.85 "Сингапур" timezone=Asia/Singapore # Singapore 59.33 18.08 "Стокгольм" timezone=Europe/Stockholm # Russia 31.10 121.37 "Шанхай" timezone=Asia/Shanghai # China 59.88 30.25 "Санкт-Петербург" timezone=Europe/Moscow # Russia 25.02 121.37 "ТайбÑй" timezone=Asia/Taipei # Taiwan 35.67 51.43 "Тегеран" timezone=Asia/Tehran # Iran # 39.13 117.20 "Таншань" timezone=Asia/Shanghai # China 35.75 139.50 "Токио" timezone=Japan # Japan # 43.70 -79.42 "Торонто" timezone=America/Montreal # Canada 49.27 -123.12 "Ванкувер" timezone=America/Vancouver # Canada 43.15 131.88 "ВладивоÑток" timezone=Asia/Vladivostok # Russia 38.88 -77.03 "Вашингтон" timezone=US/Eastern # USA 56.87 60.58 "Екатеринбург" timezone=Asia/Yekaterinburg # Russia # Some other big cities # 23.05 72.67 "Ðхмадабад" timezone=Asia/Calcutta # India # 31.20 29.90 "ÐлекÑандриÑ" timezone=Africa/Cairo # Egypt # 39.92 32.83 "Ðнкара" timezone=Asia/Istanbul # Turkey # 30.62 104.10 "ЧÑнду" timezone=Asia/Chongqing # China # 23.13 113.33 "Гуанчжоу" timezone=Asia/Shanghai # China # 45.75 126.68 "Харбин" timezone=Asia/Harbin # China # 10.75 106.67 "Хо-Ши-Мин" timezone=Asia/Saigon # Vietnam # 35.13 136.88 "ÐагоÑ" timezone=Asia/Tokyo # Japan # 35.08 129.03 "ПуÑан" timezone=Asia/Seoul # South Korea # 39.00 125.78 "ПхеньÑн" timezone=Asia/Pyongyang # North Korea # 41.83 123.43 "ШеньÑн" timezone=Asia/Shanghai # China # 30.58 114.32 "Ухань" timezone=Asia/Shanghai # China # 34.27 108.90 "Сиань" timezone=Asia/Shanghai # China # 35.47 139.63 "Йокогама" timezone=Asia/Tokyo # Japan tkabber-plugins/georoster/coords000075500000000000000000000000001500237002100167345ustar00nobodynobodytkabber-plugins/georoster/coords/de.coords000064400000000000000000000034061500237002100206210ustar00nobodynobody# a coords file has two parts: # # - a section that normalizes region names # 0: normalized name # 1: any variation # # - a section that maps a region/locality to a lat/lon pair # 0: normalized region name # 1: locality name # 2: latitude # 3: longitude # # all fields must be tab-separated # all strings must are lower-case # # region normalization # # # locality coordinates # http://www.heavens-above.com/countries.asp # aachen 50.77 6.10 baden-baden 48.75 8.25 bamberg 49.87 10.87 bayreuth 49.95 11.58 berlin 52.52 13.40 bielefeld 52.03 8.53 bocholt 51.83 6.60 bonn 50.73 7.10 bremen 53.08 8.80 celle 52.62 10.08 cuxhaven 53.88 8.70 coburg 50.25 10.97 darmstadt 49.87 8.65 dortmund 51.52 7.45 dresden 51.05 13.75 duisburg 51.43 6.75 düsseldorf 51.22 6.76 emsdetten 52.18 7.53 erfurt 50.98 11.03 essen 51.45 7.02 flensburg 54.78 9.43 frankfurt 50.12 8.68 friedrichshafen 47.65 9.48 fulda 50.55 9.67 gera 50.73 10.85 hannover 52.37 9.72 hamburg 53.55 10.00 heilbronn 49.14 9.22 jena 50.93 11.58 kaarst 51.23 6.62 karlsruhe 49.01 8.39 kleve 52.08 8.30 konstanz 47.67 9.18 köln 50.93 6.95 krefeld 51.33 6.57 leipzig 51.30 12.33 lingen 52.52 7.32 magdeburg 52.17 11.67 mannheim 49.49 8.47 marburg 50.82 8.77 meerbusch 51.28 6.67 minden 52.28 8.92 moers 51.45 6.65 mönchengladbach 51.20 6.43 münchen 48.15 11.58 neuss 51.20 6.68 norderstedt 53.70 10.02 nürnberg 49.45 11.08 nütterden 51.78 6.05 passau 48.58 13.48 recklinghausen 51.62 7.20 regensburg 49.02 12.10 schwerin 52.20 13.88 siegen 50.87 8.03 stade 53.60 9.48 stralsund 54.30 13.10 stuttgart 48.77 9.18 trier 49.75 6.63 viersen 51.25 6.38 weitramsdorf 50.25 10.88 wetzlar 50.55 8.50 wiesbaden 50.08 8.25 winzerhausen 49.02 9.26 würzburg 49.80 9.95 tkabber-plugins/georoster/coords/jm.coords000064400000000000000000000007031500237002100206340ustar00nobodynobody# a coords file has two parts: # # - a section that normalizes region names # 0: normalized name # 1: any variation # # - a section that maps a region/locality to a lat/lon pair # 0: normalized region name # 1: locality name # 2: latitude # 3: longitude # # all fields must be tab-separated # all strings must are lower-case # # region normalization # # # locality coordinates # http://www.heavens-above.com/countries.asp # kingston 18.00 -76.80 tkabber-plugins/georoster/coords/nl.coords000064400000000000000000000006351500237002100206430ustar00nobodynobody# a coords file has two parts: # # - a section that normalizes region names # 0: normalized name # 1: any variation # # - a section that maps a region/locality to a lat/lon pair # 0: normalized region name # 1: locality name # 2: latitude # 3: longitude # # all fields must be are tab-separated # all strings must are lower-case # # region normalization # # # locality coordinates # eindhoven 51.75 5.62 tkabber-plugins/georoster/coords/ru.coords000064400000000000000000000006331500237002100206560ustar00nobodynobody# a coords file has two parts: # # - a section that normalizes region names # 0: normalized name # 1: any variation # # - a section that maps a region/locality to a lat/lon pair # 0: normalized region name # 1: locality name # 2: latitude # 3: longitude # # all fields must be are tab-separated # all strings must are lower-case # # region normalization # # # locality coordinates # moscow 55.75 37.70 tkabber-plugins/georoster/coords/ua.coords000064400000000000000000000006371500237002100206410ustar00nobodynobody# a coords file has two parts: # # - a section that normalizes region names # 0: normalized name # 1: any variation # # - a section that maps a region/locality to a lat/lon pair # 0: normalized region name # 1: locality name # 2: latitude # 3: longitude # # all fields must be are tab-separated # all strings must are lower-case # # region normalization # # # locality coordinates # sevastopol 47.62 33.52 tkabber-plugins/georoster/coords/us.coords000064400000000000000000000523211500237002100206600ustar00nobodynobody# a coords file has two parts: # # - a section that normalizes region names # 0: normalized name # 1: any variation # # - a section that maps a region/locality to a lat/lon pair # 0: normalized region name # 1: locality name # 2: latitude # 3: longitude # # all fields must be are tab-separated # all strings must are lower-case # # region normalization # al alabama ak alaska as american samoa az arizona ar arkansas ca california co colorado ct connecticut de delaware dc district of columbia fm federated states of micronesia fl florida ga georgia gu guam hi hawaii id idaho il illinois in indiana ia iowa ks kansas ky kentucky la louisiana me maine mh marshall islands md maryland ma massachusetts mi michigan mn minnesota ms mississippi mo missouri mt montana ne nebraska nv nevada nh new hampshire nj new jersey nm new mexico ny new york nc north carolina nd north dakota mp nothern mariana islands oh ohio ok oklahoma or oregon pw palau pa pennsylvania pr puerto rico ri rhode island sc south carolina sd south dakota tn tennessee tx texas ut utah vt vermont va virginia wa washington wv west va wi wisconsin wy wyoming # # locality coordinates # al alexander city 32.95 -85.95 al anniston 33.58 -85.85 al auburn 32.60 -85.50 al birmingham 33.57 -86.75 al decatur 34.62 -86.98 al dothan 31.32 -85.45 al florence 34.80 -87.67 al gadsden 34.02 -86.00 al huntsville 34.70 -86.58 al mobile 30.68 -88.25 al mobile co 30.67 -88.25 al montgomery 32.38 -86.37 al selma-craig afb 32.33 -87.98 al talladega 33.45 -86.10 al tuscaloosa 33.22 -87.62 ak anchorage 61.17 -150.02 ak barrow 71.30 -156.78 ak fairbanks 64.82 -147.87 ak juneau 58.37 -134.58 ak kodiak 57.75 -152.48 ak nome 64.50 -165.43 az douglas 31.45 -109.60 az flagstaff 35.13 -111.67 az fort huachuca 31.58 -110.33 az kingman 35.20 -114.02 az nogales 31.35 -110.92 az phoenix 33.43 -112.02 az prescott 34.65 -112.43 az tucson 32.12 -110.93 az winslow 35.02 -110.73 az yuma 32.65 -114.62 ar blytheville afb 35.95 -89.95 ar camden 33.60 -92.82 ar el dorado 33.22 -92.82 ar fayetteville 36.00 -94.17 ar fort smith 35.33 -94.37 ar hot springs 34.48 -93.10 ar jonesboro 35.83 -90.70 ar little rock 34.73 -92.23 ar pine bluff 34.30 -92.08 ar texarkana 33.45 -93.98 ca bakersfield 35.42 -119.05 ca barstow 34.85 -116.78 ca blythe 33.62 -114.72 ca burbank 34.20 -118.35 ca chico 39.80 -121.85 ca concord 37.97 -121.98 ca covina 34.08 -117.87 ca crescent city 41.77 -124.20 ca downey 33.93 -118.13 ca el cajon 32.82 -116.97 ca el cerrito 32.82 -115.67 ca escondido 33.12 -117.08 ca eureka/arcata 40.98 -124.10 ca fairfield-trafis afb 38.27 -121.93 ca fresno 36.77 -119.72 ca hamilton afb 38.07 -122.50 ca laguna beach 33.55 -117.78 ca livermore 37.70 -121.95 ca lompoc 34.72 -120.57 ca vandenberg afb 34.72 -120.57 ca long beach 33.82 -118.15 ca los angeles 33.93 -118.40 ca los angeles co 34.05 -118.23 ca merced-castle afb 37.38 -120.57 ca modesto 37.65 -121.00 ca monterey 36.60 -121.90 ca napa 38.22 -122.28 ca needles 34.60 -114.62 ca oakland 37.82 -122.32 ca oceanside 33.23 -117.42 ca ontario 34.05 -117.60 ca oxnard 34.20 -119.18 ca palmdale 34.63 -118.10 ca palm springs 33.82 -116.53 ca pasadena 34.15 -118.15 ca petaluma 38.23 -122.63 ca pomona co 34.05 -117.75 ca redding 40.52 -122.30 ca redlands 34.05 -117.18 ca richmond 37.93 -122.35 ca riverside-march afb 33.90 -117.25 ca sacramento 38.52 -121.50 ca salinas 36.67 -121.60 ca san bernadino 34.13 -117.27 ca norton afb 34.13 -117.27 ca san diego 32.73 -117.17 ca san fernando 34.28 -118.47 ca san francisco 37.62 -122.38 ca san francisco co 37.77 -122.43 ca san jose 37.37 -121.93 ca san louis obispo 35.33 -120.72 ca santa ana 33.75 -117.87 ca santa barbara map 34.43 -119.83 ca santa cruz 36.98 -122.02 ca santa maria 34.90 -120.45 ca santa monica cic 34.02 -118.48 ca santa paula 34.35 -119.08 ca santa rosa 38.52 -122.82 ca stockton 37.90 -121.25 ca ukiah 39.15 -123.20 ca visalia 36.33 -119.30 ca yreka 41.72 -122.63 ca yuba city 39.13 -121.60 co alamosa 37.45 -105.87 co boulder 40.00 -105.27 co co springs 38.82 -104.72 co denver 39.75 -104.87 co durango 37.28 -107.88 co fort collins 40.75 -105.08 co grand junction 39.12 -108.53 co greeley 40.43 -104.63 co lajunta 38.05 -103.50 co leadville 39.25 -106.30 co pueblo 38.30 -104.48 co sterling 40.62 -103.20 co trinidad 37.25 -104.33 ct bridgeport 41.18 -73.18 ct hartford 41.73 -72.65 ct brainard field 41.73 -72.65 ct new haven 41.32 -73.92 ct new london 41.35 -72.10 ct norwalk 41.12 -73.42 ct norwick 41.53 -72.07 ct waterbury 41.58 -73.07 ct widsor locks 41.93 -72.68 ct bradley fld 41.93 -72.68 de dover afb 39.13 -75.47 de wilmington 39.67 -75.60 dc andrews afb 38.08 -76.08 dc washington 38.85 -77.03 fl belle glade 26.65 -80.65 fl cape kennedy 28.48 -80.57 fl daytona beach 29.18 -81.05 fl e fort lauderdale 26.07 -80.15 fl fort myers 26.58 -81.87 fl fort pierce 27.47 -80.35 fl gainsville 29.68 -82.27 fl jacksonville 30.50 -81.70 fl key west 24.55 -81.75 fl lakeland co 28.03 -81.95 fl miami 25.80 -80.27 fl miami beach co 25.78 -80.28 fl ocala 29.18 -82.13 fl orlando 28.55 -81.38 fl panama city 30.07 -85.58 fl tyndall afb 30.07 -85.58 fl pensacola co 30.42 -87.22 fl st. augustine 29.97 -81.33 fl st. petersburg 27.77 -83.33 fl stanford 28.77 -81.28 fl sarasota 27.38 -82.55 fl tallahassee 30.38 -84.37 fl tampa 27.97 -82.53 fl west palm beach 26.68 -80.10 ga albany 31.60 -84.08 ga turner afb 31.60 -84.08 ga americus 32.05 -84.23 ga athens 33.95 -83.32 ga atlanta 33.65 -84.43 ga augusta 33.37 -81.97 ga brunswick 31.25 -81.48 ga columbus 32.52 -84.93 ga lawson afb 32.52 -84.93 ga dalton 34.57 -84.95 ga dublin 32.33 -82.90 ga gainsville 34.18 -83.68 ga griffin 33.22 -84.27 ga lagrange 33.02 -85.07 ga macon 32.70 -83.65 ga marietta 33.92 -84.52 ga dobbins afb 33.92 -84.52 ga savannah 32.13 -81.20 ga valdosta-moody afb 30.97 -83.20 ga waycross 31.25 -82.40 hi hilo 19.72 -155.08 hi honolulu 21.33 -157.92 hi kaneohe bay mcas 21.45 -157.77 hi wahiawa 21.05 -158.03 id boise 43.57 -116.22 id burley 42.53 -113.77 id coeur d'alene 47.77 -116.82 id id falls 43.52 -112.07 id lewiston 46.38 -117.02 id moscow 46.73 -116.97 id mountain home afb 43.03 -115.90 id pocatello 42.92 -112.60 id twin falls 42.48 -114.48 il aurora 41.75 -88.33 il belleville 38.55 -89.85 il scott afb 38.55 -89.85 il bloomington 40.48 -88.95 il carbondale 37.78 -89.25 il champaign/urbana 40.03 -88.28 il chicago 41.88 -87.63 il danville 40.20 -87.60 il decatur 39.83 -88.87 il dixon 41.83 -89.48 il elgin 42.03 -88.27 il freeport 42.30 -89.62 il galesburg 40.93 -90.43 il greenville 38.88 -89.40 il joliet 41.52 -88.17 il kankakee 41.08 -87.92 il la salle/peru 41.32 -89.10 il macomb 40.47 -90.67 il moline 41.45 -90.52 il mt vernon 38.32 -88.87 il peoria 40.67 -89.68 il quincy 39.95 -91.20 il rantoul 40.30 -88.13 il chanute afb 40.30 -88.13 il rockford 42.35 -89.05 il springfield 39.83 -89.67 il waukegan 42.35 -87.88 in anderson 40.10 -85.62 in bedford 38.85 -86.50 in bloomington 39.13 -86.62 in columbus 39.27 -85.90 in bakalar afb 39.27 -85.90 in crawfordsville 40.05 -86.90 in evansville 38.05 -87.53 in fort wayne 41.00 -85.20 in goshen 41.53 -85.80 in hobart 41.53 -87.25 in huntington 40.88 -85.50 in inpolis 39.73 -86.28 in jeffersonville 38.28 -85.75 in kokomo 40.42 -86.05 in lafayette 40.03 -86.08 in la porte 41.60 -86.72 in marion 40.48 -85.68 in muncie 40.18 -85.35 in peru 40.65 -86.15 in grissom afb 40.65 -86.15 in richmond 39.77 -84.83 in shelbyville 39.52 -85.78 in south bend 41.70 -86.32 in terre haute 39.45 -87.30 in valparaiso 41.52 -87.03 in vincennes 38.68 -87.53 ia ames 42.03 -93.80 ia burlington 40.78 -91.12 ia cedar rapids 41.88 -91.70 ia clinton 41.83 -90.22 ia council bluffs 41.33 -95.82 ia des moines 41.53 -93.65 ia dubuque 42.40 -90.70 ia fort dodge 42.55 -94.18 ia ia city 41.63 -91.55 ia keokuk 40.40 -91.40 ia marshalltown 42.07 -92.93 ia mason city 43.15 -93.33 ia newton 41.68 -93.03 ia ottumwa 41.10 -92.45 ia sioux city 42.40 -96.38 ia waterloo 42.55 -92.40 ks atchison 39.57 -95.12 ks chanute 37.67 -95.48 ks dodge city 37.77 -99.97 ks el dorado 37.82 -96.83 ks emporia 38.33 -96.20 ks garden city 37.93 -100.73 ks goodland 39.37 -101.70 ks great bend 38.35 -98.87 ks hutchinson 38.07 -97.87 ks liberal 37.05 -100.97 ks manhattan 39.05 -96.77 ks ft riley 39.05 -96.77 ks parsons 37.33 -95.52 ks russell 38.87 -98.82 ks salina 38.80 -97.65 ks topeka 39.07 -95.63 ks wichita 37.65 -97.42 ky ashland 38.55 -82.73 ky bowling green 35.97 -86.47 ky corbin 36.95 -84.10 ky covington 39.05 -84.67 ky hopkinsville 36.67 -87.48 ky ft campbell 36.67 -87.48 ky lexington 38.03 -84.60 ky louisville 38.18 -85.73 ky madisonville 37.32 -87.48 ky owensboro 37.75 -87.17 ky paducah 37.07 -88.77 la alexandria 31.40 -92.30 la baton rouge 30.53 -91.15 la bogalusa 30.78 -89.87 la houma 29.52 -90.67 la lafayette 30.20 -92.00 la lake charles 30.12 -93.22 la minden 32.60 -93.30 la monroe 32.52 -92.03 la natchitoches 31.77 -93.08 la new orleans 29.98 -90.25 la shreveport 32.47 -93.82 me augusta 44.32 -69.80 me bangor 44.80 -68.83 me dow afb 44.80 -68.83 me caribou 46.87 -68.02 me lewiston 44.03 -70.25 me millinocket 45.65 -68.70 me portland 43.65 -70.32 me waterville 44.53 -69.67 md baltimore 39.18 -76.67 md baltimore co 39.33 -76.42 md cumberland 39.62 -78.77 md frederick 39.45 -77.42 md hagerstown 39.70 -77.73 md salisbury 38.33 -75.50 ma boston 42.37 -71.03 ma clinton 42.40 -71.68 ma fall river 41.72 -71.13 ma framingham 42.28 -71.42 ma gloucester 42.58 -70.68 ma greenfield 42.05 -72.07 ma lawrence 42.70 -71.17 ma lowell 42.65 -71.32 ma new bedford 41.68 -70.97 ma pittsfield 42.43 -73.30 ma springfield 42.20 -72.53 ma westover afb 42.20 -72.53 ma taunton 41.90 -71.07 ma worcester 42.27 -71.87 mi adrian 41.92 -84.02 mi alpena 45.07 -83.43 mi battle creek 42.32 -85.25 mi benton harbor 42.13 -86.43 mi detroit 42.42 -83.02 mi escanaba 45.73 -87.08 mi flint 42.97 -83.73 mi grand rapids 42.88 -85.52 mi holland 42.70 -86.10 mi jackson 42.27 -84.47 mi kalamazoo 42.28 -85.60 mi lansing 42.78 -84.60 mi marquette co 46.57 -87.40 mi mt pleasant 43.58 -84.77 mi muskegon 43.17 -86.23 mi pontiac 42.67 -83.42 mi port huron 42.98 -82.42 mi saginaw 43.53 -84.08 mi sault ste. marie 46.47 -84.37 mi traverse city 44.75 -85.58 mi ypsilanti 42.23 -83.53 mn albert lea 43.65 -93.35 mn alexandria 45.87 -95.38 mn bemidji 47.52 -94.93 mn brainerd 46.40 -94.13 mn duluth 46.83 -92.18 mn fairbault 44.30 -93.27 mn fergus falls 46.27 -96.07 mn international falls 48.57 -93.38 mn mankato 44.15 -93.98 mn minneapolis/st. paul 44.88 -93.22 mn rochester 43.92 -92.50 mn st. cloud 45.58 -94.18 mn va 47.50 -92.55 mn willmar 45.12 -95.08 mn winona 44.05 -91.63 ms biloxi--keesler afb 30.42 -88.92 ms clarksdale 34.20 -90.57 ms columbus afb 33.65 -88.45 ms greenville afb 33.48 -90.98 ms greenwood 33.50 -90.08 ms hattiesburg 31.27 -89.25 ms jackson 32.32 -90.08 ms laurel 31.67 -89.17 ms mccomb 31.25 -90.47 ms meridian 32.33 -88.75 ms natchez 31.55 -91.38 ms tupelo 34.27 -88.77 ms vicksburg co 32.40 -90.78 mo cape girardeau 37.23 -89.58 mo columbia 38.97 -92.37 mo farmington 37.77 -90.40 mo hannibal 39.70 -91.35 mo jefferson city 38.57 -92.18 mo joplin 37.15 -94.50 mo ks city 39.12 -94.58 mo kirksville 40.10 -92.55 mo mexico 39.18 -91.90 mo moberly 39.40 -92.43 mo poplar bluff 36.77 -90.42 mo rolla 37.98 -91.72 mo st. joseph 39.77 -94.92 mo st. louis 38.75 -90.38 mo st. louis co 38.65 -90.63 mo sikeston 36.88 -89.60 mo sedalia--whiteman afb 38.72 -93.55 mo sikeston 36.88 -89.60 mo springfield 37.23 -93.38 mt billings 45.80 -108.53 mt bozeman 45.78 -111.15 mt butte 45.95 -112.50 mt cut bank 48.62 -112.37 mt glasgow 48.42 -106.53 mt glendive 47.13 -104.80 mt great falls 47.48 -111.37 mt havre 48.57 -109.67 mt helena 46.60 -112.00 mt kalispell 48.30 -114.27 mt lewiston 47.07 -109.45 mt livingstown 45.70 -110.43 mt miles city 46.43 -105.87 mt missoula 46.92 -114.08 ne beatrice 40.27 -96.75 ne chadron 42.83 -103.08 ne columbus 41.47 -97.33 ne fremont 41.43 -96.48 ne grand island 40.98 -98.32 ne hastings 40.60 -98.43 ne kearney 40.73 -99.02 ne lincoln co 40.85 -96.75 ne mccook 40.20 -100.63 ne norfolk 41.98 -97.43 ne north platte 41.13 -100.68 ne omaha 41.30 -95.90 ne scottsbluff 41.87 -103.60 ne sidney 41.22 -103.10 nv carson city 39.17 -119.77 nv elko 40.83 -115.78 nv 39.28 -114.85 nv las vegas 36.08 -115.17 nv lovelock 40.07 -118.55 nv reno 39.50 -119.78 nv reno co 39.50 -119.78 nv tonopah 38.07 -117.08 nv winnemucca 40.90 -117.80 nh berlin 44.05 -71.02 nh claremont 43.03 -72.03 nh concord 43.20 -71.50 nh keene 42.92 -72.28 nh laconia 43.05 -71.05 nh manchester 42.93 -71.43 nh grenier afb 42.93 -71.43 nh portsmouth 43.07 -70.82 nh pease afb 43.07 -70.82 nj atlantic city co 39.38 -74.43 nj long branch 40.32 -74.02 nj newark 40.70 -74.17 nj new brunswick 40.48 -74.43 nj paterson 40.90 -74.15 nj phillipsburg 40.68 -75.18 nj trenton co 40.22 -74.77 nj vineland 39.48 -75.00 nm holloman afb 32.85 -106.10 nm albuquerque 35.05 -106.62 nm artesia 32.77 -104.38 nm carlsbad 32.33 -104.27 nm clovis 34.38 -103.32 nm farmington 36.73 -108.23 nm gallup 35.52 -108.78 nm grants 35.17 -107.90 nm hobbs 32.75 -103.22 nm las cruces 32.30 -106.92 nm los alamos 35.87 -106.32 nm raton 36.75 -104.50 nm roswell 33.30 -104.53 nm walker afb 33.30 -104.53 nm santa fe co 35.62 -106.08 nm silver city 32.63 -108.17 nm socorro 34.05 -106.88 nm tucumcari 35.18 -103.60 ny albany 42.75 -73.80 ny albany co 42.65 -73.75 ny auburn 42.90 -76.53 ny batavia 43.00 -78.18 ny binghamton 42.22 -75.98 ny buffalo 42.93 -78.73 ny cortland 42.60 -76.18 ny dunkirk 42.48 -79.27 ny elmira 42.17 -76.90 ny geneva 42.75 -76.90 ny glens falls 43.33 -73.62 ny gloversville 43.03 -74.35 ny hornell 42.35 -77.70 ny ithaca 42.45 -76.48 ny jamestown 42.12 -79.23 ny kingston 41.93 -74.00 ny lockport 43.15 -79.25 ny massena 44.93 -74.85 ny newburgh 41.50 -74.10 ny stewart afb 41.50 -74.10 ny nyc-central park 40.78 -73.97 ny nyc-kennedy 40.65 -73.78 ny nyc-la guardia 40.77 -73.90 ny niagara falls 43.10 -79.95 ny olean 42.23 -78.37 ny oneonta 42.52 -75.07 ny oswego co 43.47 -76.55 ny plattsburg afb 44.65 -73.47 ny poughkeepsie 41.63 -73.92 ny rochester 43.12 -77.67 ny rome 43.23 -75.42 ny griffiss afb 43.23 -75.42 ny schenectady 42.85 -73.95 ny suffolk county afb 40.85 -72.63 ny syracuse 43.12 -76.12 ny utica 43.15 -75.38 ny watertown 43.98 -76.02 nc asheville 35.43 -82.53 nc charlotte 35.22 -80.93 nc durham 35.87 -78.78 nc elizabeth city 36.27 -76.18 nc fayetteville 35.17 -79.02 nc pope afb 35.17 -79.02 nc goldsboro 35.33 -77.97 nc seymour-johnson 35.33 -77.97 nc greensboro 36.08 -79.95 nc greenville 35.62 -77.42 nc henderson 36.37 -78.42 nc hickory 35.75 -81.38 nc jacksonville 34.83 -77.62 nc lumberton 34.62 -79.07 nc new bern 35.08 -77.05 nc raleigh/durham 35.87 -78.78 nc rocky mount 35.97 -77.80 nc wilmington 34.27 -77.92 nc winston-salem 36.13 -80.22 nd bismarck 46.77 -100.75 nd devils lake 48.12 -98.90 nd dickinson 46.80 -102.80 nd fargo 46.90 -96.80 nd grand forks 47.95 -97.40 nd jamestown 46.92 -98.68 nd minot 48.42 -101.35 nd williston 48.15 -103.58 oh akron-canton 40.92 -81.43 oh ashtabula 41.85 -80.80 oh athens 39.33 -82.10 oh bowling green 41.38 -83.63 oh cambridge 40.07 -81.58 oh chillicothe 39.35 -83.00 oh cincinnati co 39.15 -84.52 oh cleveland 41.40 -81.85 oh columbus 40.00 -82.88 oh dayton 39.90 -84.22 oh defiance 41.28 -84.38 oh findlay 41.02 -83.67 oh fremont 41.33 -83.12 oh hamilton 39.40 -84.58 oh lancaster 39.73 -82.63 oh lima 40.70 -84.03 oh mansfield 40.82 -82.52 oh marion 40.60 -83.17 oh middletown 39.52 -84.42 oh newark 40.02 -82.47 oh norwalk 41.27 -82.62 oh portsmouth 38.75 -82.92 oh sandusky co 41.45 -82.72 oh springfield 39.83 -83.83 oh steubenville 40.38 -80.63 oh toledo 41.60 -83.80 oh warren 41.33 -80.85 oh wooster 40.78 -81.92 oh youngstown 41.27 -80.67 oh zanesville 39.95 -81.90 ok 34.78 -96.68 ok altus afb 34.65 -99.27 ok ardmore 34.30 -97.02 ok bartlesville 36.75 -96.00 ok chickasha 35.05 -97.92 ok enid 36.35 -97.92 ok vance afb 36.35 -97.92 ok lawton 34.57 -98.42 ok mcalester 34.83 -95.92 ok muskogee 35.67 -95.37 ok norman 35.25 -97.48 ok ok city 35.40 -97.60 ok ponca city 36.73 -97.10 ok seminole 35.23 -96.67 ok stillwater 36.17 -97.08 ok tulsa 36.20 -95.90 ok woodward 36.60 -99.52 or albany 44.63 -123.12 or astoria 46.15 -123.88 or baker 44.83 -117.82 or bend 44.07 -121.32 or corvallis 44.50 -123.28 or eugene 44.12 -123.22 or grants pass 42.43 -123.32 or klamath falls 42.15 -121.73 or medford 42.37 -122.87 or pendleton 45.68 -118.85 or portland 45.60 -122.60 or portland co 45.53 -122.67 or roseburg 43.23 -123.37 or salem 44.92 -123.02 or the dalles 45.60 -121.20 pa allentown 40.65 -75.43 pa altoona co 40.30 -78.32 pa butler 40.87 -79.90 pa chambersburg 39.93 -77.63 pa erie 42.08 -80.18 pa harrisburg 40.20 -76.77 pa johnstown 40.32 -78.83 pa lancaster 40.12 -76.30 pa meadville 41.63 -80.17 pa new castle 41.02 -80.37 pa philadelphia 39.88 -75.25 pa pittsburgh 40.50 -80.22 pa pittsburgh co 40.45 -80.00 pa reading co 40.33 -75.63 pa scranton/wilkes-barre 41.33 -75.73 pa state college 40.80 -77.87 pa sunbury 40.88 -76.77 pa uniontown 39.92 -79.72 pa warren 41.85 -79.13 pa west chester 39.97 -75.63 pa williamsport 41.25 -76.92 pa york 39.92 -76.75 ri newport 41.50 -71.33 ri providence 41.73 -71.43 sc anderson 34.50 -82.72 sc charleston afb 32.90 -80.03 sc charleston co 32.90 -79.97 sc columbia 33.95 -81.12 sc florence 34.18 -79.72 sc georgetown 33.38 -79.28 sc greenville 34.90 -82.22 sc greenwood 34.17 -82.12 sc orangeburg 33.50 -80.87 sc rock hill 34.98 -80.97 sc spartanburg 34.97 -82.00 sc sumter 33.90 -80.37 sc shaw afb 33.90 -80.37 sd aberdeen 45.45 -98.43 sd brookings 44.30 -96.80 sd huron 44.38 -98.22 sd mitchell 43.68 -98.02 sd pierre 44.38 -100.28 sd rapid city 44.05 -103.07 sd sioux falls 43.57 -96.73 sd watertown 44.92 -97.15 sd yankton 42.92 -97.38 tn athens 35.43 -84.58 tn bristol-tri city 36.48 -82.40 tn chattanooga 35.03 -85.20 tn clarksville 36.55 -87.37 tn columbia 35.63 -87.03 tn dyersburg 36.02 -89.40 tn greenville 36.07 -82.83 tn jackson 35.60 -88.92 tn knoxville 35.82 -83.98 tn memphis 35.05 -90.00 tn murfreesboro 34.92 -86.47 tn nashville 36.12 -86.68 tn tullahoma 35.38 -86.08 tx abilene 32.42 -99.68 tx alice 27.73 -98.03 tx amarillo 35.23 -100.70 tx austin 30.30 -97.70 tx bay city 29.00 -95.97 tx beaumont 29.95 -94.02 tx beeville 28.37 -97.67 tx big spring 32.30 -101.45 tx brownsville 25.90 -97.43 tx brownwood 31.80 -98.95 tx bryan 30.67 -96.55 tx corpus christi 27.77 -97.50 tx corsicana 32.08 -96.47 tx dallas 32.85 -96.85 tx del rio 29.37 -100.78 tx laughlin afb 29.37 -100.78 tx denton 33.20 -97.10 tx eagle pass 28.87 -100.53 tx el paso 31.80 -106.40 tx fort worth 32.83 -97.05 tx galveston 29.30 -94.80 tx greenville 33.07 -96.05 tx harlingen 26.23 -97.65 tx houston 29.97 -95.35 tx houston co 29.98 -95.37 tx huntsville 30.72 -95.55 tx killeen aaf 31.08 -97.68 tx robert gray aaf 31.08 -97.68 tx lamesa 32.70 -101.93 tx laredo afb 27.53 -99.45 tx longview 32.47 -94.73 tx lubbock 33.65 -101.82 tx lufkin 31.42 -94.80 tx mcallen 26.20 -98.22 tx midland 31.95 -102.18 tx mineral wells 32.78 -98.07 tx palestine co 31.78 -95.63 tx pampa 35.53 -100.98 tx pecos 31.42 -103.50 tx plainview 34.18 -101.70 tx port arthur 29.95 -94.02 tx goodfellow afb 31.43 -100.40 tx san antonio 29.53 -98.47 tx sherman 33.72 -96.67 tx perrin afb 33.72 -96.67 tx snyder 32.72 -100.92 tx temple 31.10 -97.35 tx tyler 32.35 -95.27 tx vernon 34.17 -99.30 tx victoria 28.85 -96.92 tx waco 31.62 -97.22 tx wichita falls 33.97 -98.48 ut cedar city 37.70 -113.10 ut logan 41.75 -111.82 ut moab 38.60 -109.60 ut ogden 41.20 -112.02 ut price 39.62 -110.83 ut provo 40.22 -111.72 ut richfield 38.77 -112.08 ut st george co 37.03 -113.52 ut salt lake city 40.77 -111.97 ut vernal 40.45 -109.52 vt barre 44.20 -72.52 vt burlington 44.47 -73.15 vt rutland 43.60 -72.97 va charlottesville 38.03 -78.52 va danville 36.57 -79.33 va fredericksburg 38.30 -77.47 va harrisonburg 38.45 -78.90 va lynchburg 37.33 -79.20 va norfolk 36.90 -76.20 va petersburg 37.18 -77.52 va richmond 37.50 -77.33 va roanoke 37.32 -79.97 va staunton 38.27 -78.90 va winchester 39.20 -78.17 wa aberdeen 46.98 -123.82 wa bellingham 48.80 -122.53 wa bremerton 47.57 -122.67 wa ellensburg 47.03 -120.52 wa everett 47.92 -122.28 wa paine afb 47.92 -122.28 wa kennewick 46.22 -119.13 wa longview 46.17 -122.93 wa moses lake 47.20 -119.32 wa larson afb 47.20 -119.32 wa olympia 46.97 -122.90 wa port angeles 48.12 -123.43 wa seattle-boeing field 47.53 -122.30 wa seattle co 47.65 -122.30 wa seattle-tacoma 47.45 -122.30 wa spokane 47.63 -117.52 wa tacoma 47.25 -122.50 wa mcchord afb 47.25 -122.50 wa walla walla 46.10 -118.28 wa wenatchee 47.42 -120.32 wa yakima 46.57 -120.53 wv beckley 37.78 -81.12 wv bluefield 37.30 -81.22 wv charleston 38.37 -81.60 wv clarksburg 39.27 -80.35 wv elkins 38.88 -79.85 wv huntington co 38.42 -82.50 wv martinsburg 39.40 -77.98 wv morgantown 39.65 -79.92 wv parkersburg co 39.27 -81.57 wv wheeling 40.12 -80.70 wi appleton 44.25 -88.38 wi ashland 46.57 -90.97 wi beloit 42.50 -89.03 wi eau claire 44.87 -91.48 wi fond du lac 43.80 -88.45 wi green bay 44.48 -88.13 wi la crosse 43.87 -91.25 wi madison 43.13 -89.33 wi manitowoc 44.10 -87.68 wi marinette 45.10 -87.63 wi milwaukee 42.95 -87.90 wi racine 42.72 -87.85 wi sheboygan 43.75 -87.72 wi stevens point 44.50 -89.57 wi waukesha 43.02 -88.23 wi wausau 44.92 -89.62 wy casper 42.92 -106.47 wy cheyenne 41.15 -104.82 wy cody 44.55 -109.07 wy evanston 41.27 -110.95 wy lander 42.82 -108.73 wy laramie 41.32 -105.68 wy newcastle 43.85 -104.22 wy rawlins 41.80 -107.20 wy rock springs 41.60 -109.00 wy sheridan 44.77 -106.97 wy torrington 42.08 -104.22 tkabber-plugins/georoster/georoster.tcl000064400000000000000000001002771500237002100202460ustar00nobodynobody# georoster.tcl -- # # This file implements Georoster plugin for the Tkabber XMPP client. package require msgcat option add *GeoRoster.cityforeground green3 widgetDefault namespace eval georoster { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered georoster]} { ::plugins::register georoster \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Georoster\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable georoster variable options if {![info exists options(citiesfile)]} { set options(citiesfile) [file join [file dirname [info script]] \ cities earth] variable pr variable f foreach pr [::msgcat::mcpreferences] { set f [file join [file dirname [info script]] cities "earth.$pr"] if {[file exists $f]} { set options(citiesfile) $f break } } unset pr f } if {![info exists options(3166file)]} { set options(3166file) [file join [file dirname [info script]] iso3166] } if {![info exists georoster(3166)]} { set georoster(3166) {} } variable file variable c foreach file [glob -nocomplain \ [file join [file dirname [info script]] \ coords ??.coords]] { set c [file tail [file rootname $file]] if {![info exists options(coords,$c)]} { set options(coords,$c) $file } } if {![info exists options(mapfile)]} { set options(mapfile) \ [file join [file dirname [info script]] maps bwmap2.gif] proc lo {x y} {expr {($x - 649)*18/65 + 10}} proc la {x y} {expr {(371 - $y)*9/40}} proc x {lo la} {expr {649+(($lo-10)*65/18)}} proc y {lo la} {expr {371-($la * 40/9)}} } custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup Georoster [::msgcat::mc "Georoster plugin options."] \ -group Plugins custom::defvar options(automatic) 0 \ [::msgcat::mc "Automatically open Georoster window."] \ -group Georoster -type boolean custom::defvar options(check_vcard) 0 \ [::msgcat::mc "Automatically look at vCard to find users\ coordinates."] \ -group Georoster -type boolean custom::defvar options(show_last_known) 0 \ [::msgcat::mc "Display users who are no longer available."] \ -group Georoster -type boolean custom::defvar options(default_country) us \ [::msgcat::mc "Default country to use when looking at a vCard."] \ -group Georoster -type string variable opt2label_list [list none [::msgcat::mc "Don't show cities"] \ markers [::msgcat::mc "Show only city markers"] \ all [::msgcat::mc "Show city markers and names"]] variable opt2label array set opt2label $opt2label_list variable label2opt array set label2opt [list [::msgcat::mc "Don't show cities"] none \ [::msgcat::mc "Show only city markers"] markers \ [::msgcat::mc "Show city markers and names"] all] custom::defvar options(showcities) all \ [::msgcat::mc "Specify how to show cities at the map."] \ -group Georoster -type options \ -values $opt2label_list -command [namespace current]::set_showcities variable showcities $opt2label($options(showcities)) } package require http 2 package require xmpp::private proc georoster::load {} { hook::add finload_hook [namespace current]::setup hook::add client_presence_hook [namespace current]::presence_change hook::add connected_hook [namespace current]::init 1 hook::add connected_hook [namespace current]::retrieve hook::add save_session_hook [namespace current]::save_session trace add variable [namespace current]::showcities write \ [namespace current]::set_option_showcities setup foreach xlib [connections] { init $xlib retrieve $xlib } } proc georoster::unload {} { hook::remove finload_hook [namespace current]::setup hook::remove client_presence_hook [namespace current]::presence_change hook::remove connected_hook [namespace current]::init 1 hook::remove connected_hook [namespace current]::retrieve hook::remove save_session_hook [namespace current]::save_session trace remove variable [namespace current]::showcities write \ [namespace current]::set_option_showcities catch { set m [.mainframe getmenu roster] set idx [$m index [::msgcat::mc "Georoster"]] $m delete $idx } destroy_win .georoster variable mapimage variable georoster variable status variable geo3166 variable move variable cities variable options image delete $mapimage catch {unset options(mapfile)} catch {unset mapimage} catch {unset georoster} catch {unset status} catch {unset geo3166} catch {unset move} catch {unset cities} } ############################################################################### proc georoster::set_showcities {args} { variable options variable showcities variable opt2label set showcities $opt2label($options(showcities)) redraw .georoster.c } ############################################################################### proc georoster::set_option_showcities {args} { variable options variable showcities variable label2opt set options(showcities) $label2opt($showcities) } ############################################################################### proc georoster::setup {} { variable mapimage variable options set mapimage [image create photo -file $options(mapfile)] load_cities load_3166 set m [.mainframe getmenu roster] $m add command \ -label [::msgcat::mc "Georoster"] \ -command [list [namespace current]::open_georoster -raise 1] } ############################################################################### proc georoster::open_georoster {args} { variable options variable mapimage set raise 0 foreach {key val} $args { switch -- $key { -raise { set raise $val } } } set w .georoster if {[winfo exists $w]} { if {$raise} { raise_win $w } return } set title [::msgcat::mc "Georoster"] add_win $w -title $title \ -tabtitle $title \ -class GeoRoster \ -raise $raise set sw [ScrolledWindow $w.sw] pack $sw -side top -fill both -expand yes set c [Canvas $w.c] $sw setwidget $c set c [Wrapped $c] bindscroll $c DropSite::register $c -droptypes {JID {}} \ -dropcmd [list [namespace current]::drop_jid $c] set tb [Frame $w.tb] pack $tb -side bottom -fill x set status [Label $tb.status -textvariable [namespace current]::status] pack $status -side left -anchor w set store [Button $tb.store -text [::msgcat::mc "Store"] \ -command [namespace current]::store] pack $store -side right set cities [OptionMenu $tb.cities \ [namespace current]::showcities \ [::msgcat::mc "Don't show cities"] \ [::msgcat::mc "Show only city markers"] \ [::msgcat::mc "Show city markers and names"]] pack $tb.cities -side right $w.c create image 0 0 -image $mapimage -anchor nw -tags map $w.c configure -scrollregion [$w.c bbox all] bind $c [list [namespace current]::on_mouse_move [double% $w.c] \ %x %y] bind $c [list set [namespace current]::status ""] bind $c \ [list [namespace current]::move_b1p \ [double% $w.c] %x %y] bind $c [list [namespace current]::move_b1m \ [double% $w.c] %x %y] bind $c \ [list [namespace current]::move_b1r [double% $w.c]] bind $c <> \ [list [namespace current]::delete [double% $w.c] %x %y] bind $c \ [list [namespace current]::delete [double% $w.c] %x %y] redraw $w.c } ############################################################################### proc georoster::on_mouse_move {c x y} { variable georoster variable status set x [$c canvasx $x] set y [$c canvasy $y] set lo [lo $x $y] set la [la $x $y] set georoster(cur_lo) $lo set georoster(cur_la) $la set status [::msgcat::mc "Latitude: %.2f Longitude: %.2f" $la $lo] } ############################################################################### proc georoster::drop_jid {c target source x y op type data} { variable georoster lassign $data xlib jid set x [$c canvasx [expr {$x - [winfo rootx $c]}]] set y [$c canvasy [expr {$y - [winfo rooty $c]}]] set lo [lo $x $y] set la [la $x $y] update_jid $c $xlib $jid $la $lo } ############################################################################### proc georoster::redraw {c} { variable georoster if {![winfo exists $c]} return $c delete icon redraw_cities $c foreach nxlib [array names georoster jids,*] { set xlib [string range $nxlib 5 end] foreach jid $georoster(jids,$xlib) { set lo $georoster(lo,$xlib,$jid) set la $georoster(la,$xlib,$jid) set x [x $lo $la] set y [y $lo $la] set icon roster/user/unavailable catch {set icon [ifacetk::roster::get_jid_icon $xlib $jid]} set tag [jid_to_tag $jid] $c create image $x $y -image $icon \ -tags [list icon xlib$xlib jid$tag] -anchor c set doubledjid [double% $jid] set jids [ifacetk::roster::get_jids_of_user $xlib $jid] if {[llength $jids] > 0} { set doubledjids [double% $jids] } else { set jids [list $jid] # TODO: Turn into metacontacts #if {$::ifacetk::roster::use_aliases && \ # [info exists ::roster::aliases($jid)]} { # set jids [concat $jids $::roster::aliases($jid)] #} set doubledjids [double% $jids] } #$c bind jid$tag \ # +[list eval balloon::set_text \ # \[roster::jids_popup_info [list $doubledjids]\]] # #$c bind jid$tag \ # [list eval balloon::on_mouse_move \ # \[roster::jids_popup_info [list $doubledjids]\] %X %Y] $c bind jid$tag \ +[list [namespace current]::set_balloon_text \ balloon::set_text \ $xlib $doubledjid %X %Y] $c bind jid$tag \ [list [namespace current]::set_balloon_text \ balloon::on_mouse_move \ $xlib $doubledjid %X %Y] $c bind jid$tag {+ balloon::destroy } } } } ############################################################################### proc georoster::set_balloon_text {op xlib jid sx sy} { set c .georoster.c set x [$c canvasx [expr {$sx - [winfo rootx $c]}]] set y [$c canvasy [expr {$sy - [winfo rooty $c]}]] set ids [$c find overlapping \ [expr {$x-2}] [expr {$y-2}] \ [expr {$x+2}] [expr {$y+2}]] set city_prefix "" foreach id $ids { set tags [$c gettags $id] if {[lsearch -exact $tags city] >= 0 && \ [lsearch -exact $tags oval] >= 0} { set name [string range [lsearch -inline -glob $tags name*] 4 end] append city_prefix "$name\n" } } set all_jids {} foreach id $ids { set tags [$c gettags $id] if {[lsearch -exact $tags icon] < 0} continue set xlib [string range [lsearch -inline -glob $tags xlib*] 4 end] set jidtag [string range [lsearch -inline -glob $tags jid*] 3 end] set jid [tag_to_jid $jidtag] set jids {} foreach j [ifacetk::roster::get_jids_of_user $xlib $jid] { lappend jids [list $xlib $j] } if {[llength $jids] == 0} { if {[catch { list [list $xlib $jid] } jids]} { set jids {} } # TODO: Turn into metacontacts #if {$::ifacetk::roster::use_aliases && \ # [info exists ::roster::aliases($jid)]} { # foreach j $::roster::aliases($jid) { # lappend jids [list $xlib $j] # } #} } set all_jids [concat $all_jids $jids] } set all_jids [lsort -unique $all_jids] set text "" set i 0 foreach cj $all_jids { lassign $cj xlib j append text "\n" append text [::msgcat::mc "Connection: %s" [connection_jid $xlib]] append text "\n" append text [ifacetk::roster::user_popup_info $xlib $j $i] incr i } set text [string trimleft $text "\n"] if {$op == "balloon::set_text"} { $op "${city_prefix}$text" } else { $op "${city_prefix}$text" $sx $sy } } ############################################################################### proc georoster::presence_change {xlib from type x args} { variable options variable georoster if {![info exists georoster(jids,$xlib)]} { set georoster(jids,$xlib) {} } set jid [::xmpp::jid::stripResource $from] switch -- $type { error - subscribe - subscribed - unsubscribe - unsubscribed - probe { return } unavailable { if {!$options(show_last_known)} { set x [lsearch -exact $georoster(jids,$xlib) $jid] if {$x >= 0} { set georoster(jids,$xlib) \ [lreplace $georoster(jids,$xlib) $x $x] } return } set to $jid } available - default { set to $from } } if {($options(check_vcard)) \ && ([lsearch -exact $georoster(jids,$xlib) $jid] < 0) \ && ([string compare conference \ [lindex [roster::get_category_and_subtype $xlib \ $jid] 0]])} { ::xmpp::sendIQ $xlib get \ -query [::xmpp::xml::create vCard -xmlns vcard-temp] \ -to $to \ -command [list [namespace current]::parse_vcard .georoster.c \ $xlib $jid] } if {$options(automatic)} { open_georoster -raise 0 } redraw .georoster.c } ############################################################################### proc georoster::parse_vcard {w xlib jid status xml} { variable geo3166 variable georoster variable options if {$status ne "ok"} { return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels array set info [list CTRY "" COUNTRY ""] foreach item $subels { ::xmpp::xml::split $item tag xmlns attrs cdata subels switch -- $tag { ADR { foreach item $subels { ::xmpp::xml::split $item tag xmlns attrs cdata subels array set info [list $tag [string trim $cdata]] } } EMAIL { set georoster(email,$xlib,$jid) [string trim $cdata] } GEO { foreach item $subels { ::xmpp::xml::split $item tag xmlns attrs cdata subels array set info [list $tag [string trim $cdata]] } if {([info exists info(LAT)]) \ && ([string is double -strict $info(LAT)]) \ && ([info exists info(LON)]) \ && ([string is double -strict $info(LON)])} { update_jid $w $xlib $jid $info(LAT) $info(LON) return } } } } if {($info(CTRY) ne "") && ($info(COUNTRY) eq "")} { set info(COUNTRY) $info(CTRY) } unset info(CTRY) if {$info(COUNTRY) eq ""} { set args [list $jid] if {[info exists georoster(email,$xlib,$jid)]} { lappend args $georoster(email,$xlib,$jid) } foreach addr $args { if {([set x [string last . $addr]] > 0) \ && ([lsearch -exact $georoster(3166) \ [set c [string range $addr [expr $x+1] \ end]]] >= 0)} { set info(COUNTRY) $c break } } if {$info(COUNTRY) eq ""} { set info(COUNTRY) $options(default_country) } } set info(COUNTRY) [set c [string tolower $info(COUNTRY)]] if {[info exists geo3166($c)]} { set info(COUNTRY) $geo3166($c) } foreach {k v} [array get info] { if {$v eq ""} { unset info($k) } } switch -- $info(COUNTRY) { us { set args {} foreach {k v} [list PCODE zip REGION state LOCALITY city] { if {([info exists info($k)]) && ($info($k) ne "")} { lappend args $v $info($k) } } if {[llength $args] > 0} { set query [eval ::http::formatQuery $args] if {![catch { ::http::geturl \ http://www.census.gov/cgi-bin/gazetteer?$query \ -timeout 300 \ -command [list [namespace current]::parse_vcard_aux \ $w $xlib $jid [array get info]] }]} { debugmsg georoster "async http: $xlib $jid" return } } } default { } } parse_vcard_aux2 $w $xlib $jid [array get info] } ############################################################################### proc georoster::parse_vcard_aux {w xlib jid xinfo httpT} { debugmsg georoster " aux http: $xlib $jid" set data "" if {[set status [::http::status $httpT]] ne "ok"} { debugmsg georoster " gazetteer: $status" } elseif {![string match 2* [::http::ncode $httpT]]} { debugmsg georoster " gazetteer: [::http::code $httpT]" } else { set data [::http::data $httpT] } catch { ::http::cleanup $httpT } if {([set x [string first "lat=" $data]] > 0) \ && ([set x \ [string first "&wid" \ [set data [string range $data \ [expr $x+4] \ end]]]] > 0) \ && ([set x \ [string first "&lon=" \ [set data \ [string range $data 0 \ [expr $x-1]]]]] > 0) \ && ([string is double -strict \ [set la [string range $data 0 [expr $x-1]]]]) \ && ([string is double -strict \ [set lo [string range $data [expr $x+5] end]]])} { debugmsg georoster " gazetteer: $xlib $jid $la $lo" update_jid $w $xlib $jid $la $lo return } parse_vcard_aux2 $w $xlib $jid $xinfo } ############################################################################### proc georoster::parse_vcard_aux2 {w xlib jid xinfo} { variable options debugmsg georoster " vcard: $xlib $jid $xinfo" array set info $xinfo if {([info exists info(LOCALITY)]) \ && ([info exists options(coords,$info(COUNTRY))]) \ && (![catch { open $options(coords,$info(COUNTRY)) \ { RDONLY } } fd])} { if {[catch { string tolower $info(REGION) } region]} { set region "" } set locality [string tolower $info(LOCALITY)] fconfigure $fd -encoding utf-8 while {[gets $fd line] >= 0} { if {[set x [string first "#" $line]] >= 0} { set line [string range $line 0 [expr $x-1]] } if {[catch { split $line "\t" } elems]} { continue } switch -- [llength $elems] { 0 - 3 { continue } 2 { if {$region eq [lindex $elems 1]} { set region [lindex $elems 0] debugmsg georoster \ " vcard: normalize region to $region" } continue } 4 - default { if {($region eq [lindex $elems 0]) \ && ($locality eq [lindex $elems 1])} { if {([string is double -strict \ [set la [lindex $elems 2]]]) \ && ([string is double -strict \ [set lo [lindex $elems 3]]])} { close $fd debugmsg georoster " coords: $xlib $jid $la $lo" update_jid $w $xlib $jid $la $lo return } debugmsg georoster " vcard: invalid line: $line" break } } } } close $fd } hook::run georoster:locate_hook $xlib $jid \ [list [namespace current]::update_jid $w $xlib $jid] } ############################################################################### proc georoster::update_jid {w xlib jid latitude longitude} { variable georoster if {[lsearch -exact $georoster(jids,$xlib) $jid] < 0} { lappend georoster(jids,$xlib) $jid } set georoster(la,$xlib,$jid) $latitude set georoster(lo,$xlib,$jid) $longitude redraw $w } ############################################################################### proc georoster::move_b1p {c x y} { variable move set tags [$c gettags current] #puts $tags if {[lsearch -exact $tags icon] >= 0} { set x [$c canvasx $x] set y [$c canvasy $y] set move(startx) $x set move(starty) $y set move(lastx) $x set move(lasty) $y set xlib [string range [lsearch -inline -glob $tags xlib*] 4 end] set move(xlib) $xlib set jidtag [string range [lsearch -inline -glob $tags jid*] 3 end] set jid [tag_to_jid $jidtag] set move(jid) $jid } else { catch {unset move(jid)} } } ############################################################################### proc georoster::move_b1m {c x y} { variable move variable georoster variable status if {[info exists move(jid)]} { set ctag xlib$move(xlib) set tag jid[jid_to_tag $move(jid)] set x [$c canvasx $x] set y [$c canvasy $y] set xlib $move(xlib) set jid $move(jid) set lo $georoster(lo,$xlib,$jid) set la $georoster(la,$xlib,$jid) set oldx [x $lo $la] set oldy [y $lo $la] set newx [expr {$oldx + $x - $move(startx)}] set newy [expr {$oldy + $y - $move(starty)}] set newlo [lo $newx $newy] set newla [la $newx $newy] set status [::msgcat::mc "Latitude: %.2f Longitude: %.2f" \ $newla $newlo] $c move icon&&$ctag&&$tag [expr {$x - $move(lastx)}] \ [expr {$y - $move(lasty)}] set move(lastx) $x set move(lasty) $y } } ############################################################################### proc georoster::move_b1r {c} { variable move variable georoster if {[info exists move(jid)]} { set ctag xlib$move(xlib) set tag jid[jid_to_tag $move(jid)] set xlib $move(xlib) set jid $move(jid) set x $move(lastx) set y $move(lasty) set lo $georoster(lo,$xlib,$jid) set la $georoster(la,$xlib,$jid) set oldx [x $lo $la] set oldy [y $lo $la] set newx [expr {$oldx + $x - $move(startx)}] set newy [expr {$oldy + $y - $move(starty)}] set newlo [lo $newx $newy] set newla [la $newx $newy] update_jid $c $xlib $jid $newla $newlo } } ############################################################################### proc georoster::delete {c x y} { variable georoster set tags [$c gettags current] #puts $tags if {[lsearch -exact $tags icon] >= 0} { set x [$c canvasx $x] set y [$c canvasy $y] set xlib [string range [lsearch -inline -glob $tags xlib*] 4 end] set jidtag [string range [lsearch -inline -glob $tags jid*] 3 end] set jid [tag_to_jid $jidtag] set idx [lsearch -exact $georoster(jids,$xlib) $jid] set georoster(jids,$xlib) [lreplace $georoster(jids,$xlib) $idx $idx] redraw $c } } ############################################################################### proc georoster::store {} { variable georoster foreach nxlib [array names georoster jids,*] { set xlib [string range $nxlib 5 end] set items($xlib) {} foreach jid $georoster(jids,$xlib) { set lo $georoster(lo,$xlib,$jid) set la $georoster(la,$xlib,$jid) lappend items($xlib) [::xmpp::xml::create item \ -attrs [list jid $jid lo $lo la $la]] } } foreach xlib [array names items] { ::xmpp::private::store $xlib [list [::xmpp::xml::create query \ -xmlns tkabber:georoster \ -subelements $items($xlib)]] } } ############################################################################### proc georoster::init {xlib} { variable georoster if {![info exists georoster(jids,$xlib)]} { set georoster(jids,$xlib) {} } } ############################################################################### proc georoster::retrieve {xlib} { ::xmpp::private::retrieve $xlib [list [::xmpp::xml::create query \ -xmlns tkabber:georoster]] \ -command [list [namespace current]::recv $xlib] } ############################################################################### proc georoster::recv {xlib status xmllist} { variable georoster if {$status != "ok"} { return } set georoster(jids,$xlib) {} foreach element $xmllist { ::xmpp::xml::split $element tag xmlns attrs cdata subels foreach item $subels { ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels set jid [::xmpp::xml::getAttr $sattrs jid] if {$jid != ""} { lappend georoster(jids,$xlib) $jid set georoster(lo,$xlib,$jid) [::xmpp::xml::getAttr $sattrs lo] set georoster(la,$xlib,$jid) [::xmpp::xml::getAttr $sattrs la] } } } after idle [list [namespace current]::redraw .georoster.c] } ############################################################################### proc georoster::compare_lo {namex namey} { variable cities set x $cities(lo,$namex) set y $cities(lo,$namey) if {$x < $y} { return 1 } if {$x > $y} { return -1 } return 0 } proc georoster::load_cities {} { variable options variable cities set cities(list) {} set fd [open $options(citiesfile) r] fconfigure $fd -encoding utf-8 while {![eof $fd]} { set s [gets $fd] if {[string index $s 0] == "#"} continue set la [lindex $s 0] set lo [lindex $s 1] set name [lindex $s 2] if {![string is double -strict $lo]} continue if {![string is double -strict $la]} continue lappend cities(list) $name set cities(lo,$name) $lo set cities(la,$name) $la } close $fd set cities(list) \ [lsort -command [namespace current]::compare_lo $cities(list)] } ############################################################################### proc georoster::redraw_cities {c} { variable georoster variable cities variable options set moves [list -3 6 -9 12 -15 18 -21 24 -12] if {![winfo exists $c]} return $c delete city if {$options(showcities) == "none"} return foreach name $cities(list) { set lo $cities(lo,$name) set la $cities(la,$name) #puts "$name: LO: $lo LA: $la" set x [x $lo $la] set y [y $lo $la] #set tag [jid_to_tag $name] set id [$c create oval \ [expr {$x-2}] [expr {$y-2}] \ [expr {$x+2}] [expr {$y+2}] \ -tags [list city oval name$name] \ -outline red] $c bind $id \ +[list balloon::set_text $name] $c bind $id \ [list balloon::on_mouse_move $name %X %Y] $c bind $id {+ balloon::destroy } if {$options(showcities) == "all"} { set txt [$c create text [expr {$x+4}] $y -text $name -anchor w \ -fill [option get [winfo parent $c] cityforeground \ GeoRoster] \ -tags [list city text name$name]] lassign [$c bbox $txt] x1 y1 x2 y2 set overlap [$c find overlapping $x1 $y1 $x2 $y2] foreach ym $moves { if {[llength $overlap] > 2} { $c move $txt 0 $ym lassign [$c bbox $txt] x1 y1 x2 y2 set overlap [$c find overlapping $x1 $y1 $x2 $y2] } else { break } } } } catch {$c lower city icon} catch {$c lower text oval} } ############################################################################### proc georoster::load_3166 {} { variable options variable geo3166 variable georoster if {[catch { open $options(3166file) { RDONLY } } fd]} { return } while {[gets $fd line] >= 0} { if {[set x [string first "#" $line]] >= 0} { set line [string range $line 0 [expr $x-1]] } if {[catch { split $line "\t" } elems]} { continue } switch -- [llength $elems] { 0 - 1 { continue } 2 - default { set geo3166([lindex $elems 1]) [set c [lindex $elems 0]] if {[lsearch -exact $georoster(3166) $c] < 0} { lappend georoster(3166) $c } } } } close $fd } ############################################################################## proc georoster::restore_window {args} { open_georoster -raise 1 } proc georoster::save_session {vsession} { upvar 2 $vsession session global usetabbar # We don't need JID at all, so make it empty (special case) set user "" set server "" set resource "" # TODO if {!$usetabbar} return set prio 0 foreach page [.nb pages] { set path [ifacetk::nbpath $page] if {[string equal $path .georoster]} { lappend session [list $prio $user $server $resource \ [list [namespace current]::restore_window] \ ] } incr prio } } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/georoster/howto.txt000064400000000000000000000062661500237002100174350ustar00nobodynobody[ howto.txt - Wed Apr 9 14:49:00 2003 - the georoster plugin - /mtr ] 0. configuration options: # automatically open GeoRoster window set georoster::options(automatic) 1 # show cities on map (none, markers, or all) set georoster::options(showcities) all # file defining city names & locations, localized for XX set georoster::options(citiesfile) .../earth.XX # file defining ISO 3166 country codes set georoster::options(3166file) iso3166 # default country to use, if unspecified in vCard set georoster::options(default_country) us # file defining region/locality names & locations, for country XX set georoster::options(coords,XX) .../XX.coords # file containing gif to use as background for map set georoster::options(mapfile) .../bwmap2.gif # procedures to map from x/y to lo/la, and back again proc georoster::lo {x y} proc georoster::la {x y} proc georoster::x {lo la} proc georoster::y {lo la} # hook to locate a given jid: proc XX {jid update} { if {$success} { eval $update [list $la $lo] return stop } } hook::add georoster:locate_hook [namespace current]::XX 1. how it works (manual mode) you are free to drag-and-drop entries from your roster to arbitrary locations on the GeoRoster window. click on "Store" to save those values. 2. how it works (automatic mode) set georoster::options(check_vcard) 1 whenever someone on your roster updates their presence, tkabber with fetch their vCard. if the vCard contains lat/long coordinates, those values are used directly. otherwise, tkabber tries to figure out the country associated with the user using: - country information from the vCard, if present - country information from the jid (e.g., fred@example.XX), if it's a 3166 code - country information from the vCard email address, if present - otherwise, the georoster::options(default_country) is used now, there's a switch statement that knows how to find someone, based on the addressing information in the vCard (locality, region, pcode) for a given country code. at present, there's only one case in the switch, for "us" -- it does an HTTP lookup at www.census.gov. if you know of a similar service for other countries, please contribute code! if there isn't a lookup routine, or if the routine fails, then a coordinates file for the country code is consulted. this file maps region/locality information to coordinates. if you know of coordinate information for a given country code, please contribute to the relevant the coordinates file. finally, if there isn't a match based on the vCard, then the georoster:locate_hook is invoked. 3. coordinates files a coordinates file contains two parts. the first part does normalization of region names, and the second part maps region/locality name pairs to coordinates. the file itself consists of tab-separated fields, containing lower-case strings take a look at .../us.coords for an example. ####### tkabber-plugins/georoster/iso3166000064400000000000000000000126151500237002100165640ustar00nobodynobody# # the iso3166 file has mappings for 2-letter iso3166 codes # # 0: normalized code # 1: any variation # # all fields must be are tab-separated # all strings must are lower-case # af afg af afghanistan al alb al albania dz dza dz algeria as asm as american samoa ad and ad andorra ao ago ao angola ai aia ai anguilla aq ata aq antarctica ag atg ag antigua and barbuda ar arg ar argentina am arm am armenia aw abw aw aruba au aus au australia at aut at austria az aze az azerbaijan bs bhs bs bahamas bh bhr bh bahrain bd bgd bd bangladesh bb brb bb barbados by blr by belarus be bel be belgium bz blz bz belize bj ben bj benin bm bmu bm bermuda bt btn bt bhutan bo bol bo bolivia ba bih ba bosnia and herzegowina bw bwa bw botswana bv bvt bv bouvet island br bra br brazil io iot io british indian ocean territory bn brn bn brunei darussalam bg bgr bg bulgaria bf bfa bf burkina faso bi bdi bi burundi kh khm kh cambodia cm cmr cm cameroon ca can ca canada cv cpv cv cape verde ky cym ky cayman islands cf caf cf central african republic td tcd td chad cl chl cl chile cn chn cn china cx cxr cx christmas island cc cck cc cocos islands cc keeling islands co col co colombia km com km comoros cg cog cg congo ck cok ck cook islands cr cri cr costa rica ci civ ci cote d'ivoire hr hrv hr croatia hr hrvatska cu cub cu cuba cy cyp cy cyprus cz cze cz czech republic dk dnk dk denmark dj dji dj djibouti dm dma dm dominica do dom do dominican republic tp tmp tp east timor ec ecu ec ecuador eg egy eg egypt sv slv sv el salvador gq gnq gq equatorial guinea er eri er eritrea ee est ee estonia et eth et ethiopia fk flk fk falkland islands fk malvinas fo fro fo faroe islands fj fji fj fiji fi fin fi finland fr fra fr france fx fxx fx metropolitan france gf guf gf french guiana pf pyf pf french polynesia tf atf tf french southern territories ga gab ga gabon gm gmb gm gambia ge geo ge georgia de deu de germany gh gha gh ghana gi gib gi gibraltar gr grc gr greece gl grl gl greenland gd grd gd grenada gp glp gp guadeloupe gu gum gu guam gt gtm gt guatemala gn gin gn guinea gw gnb gw guinea-bissau gy guy gy guyana ht hti ht haiti hm hmd hm heard and mc donald islands va vat va holy see va vatican city state hn hnd hn honduras hk hkg hk hong kong hu hun hu hungary is isl is iceland in ind in india id idn id indonesia ir irn ir iran iq irq iq iraq ie irl ie ireland il isr il israel it ita it italy jm jam jm jamaica jp jpn jp japan jo jor jo jordan kz kaz kz kazakhstan ke ken ke kenya ki kir ki kiribati kp prk kp democratic people's republic of korea kr kor kr republic of korea kw kwt kw kuwait kg kgz kg kyrgyzstan la lao la lao people's democratic republic lv lva lv latvia lb lbn lb lebanon ls lso ls lesotho lr lbr lr liberia ly lby ly libyan arab jamahiriya li lie li liechtenstein lt ltu lt lithuania lu lux lu luxembourg mo mac mo macau mk mkd mk macedonia mg mdg mg madagascar mw mwi mw malawi my mys my malaysia mv mdv mv maldives ml mli ml mali mt mlt mt malta mh mhl mh marshall islands mq mtq mq martinique mr mrt mr mauritania mu mus mu mauritius yt myt yt mayotte mx mex mx mexico fm fsm fm micronesia fm federated states of micronesia md mda md moldova md republic of moldova mc mco mc monaco mn mng mn mongolia ms msr ms montserrat ma mar ma morocco mz moz mz mozambique mm mmr mm myanmar na nam na namibia nr nru nr nauru np npl np nepal nl nld nl netherlands nl the netherlands an ant an netherlands antilles nc ncl nc new caledonia nz nzl nz new zealand ni nic ni nicaragua ne ner ne niger ng nga ng nigeria nu niu nu niue nf nfk nf norfolk island mp mnp mp northern mariana islands no nor no norway om omn om oman pk pak pk pakistan pw plw pw palau pa pan pa panama pg png pg papua new guinea py pry py paraguay pe per pe peru ph phl ph philippines pn pcn pn pitcairn pl pol pl poland pt prt pt portugal pr pri pr puerto rico qa qat qa qatar re reu re reunion ro rom ro romania ru rus ru russia ru russian federation rw rwa rw rwanda kn kna kn saint kitts and nevis lc lca lc saint lucia vc vct vc saint vincent and the grenadines ws wsm ws samoa sm smr sm san marino st stp st sao tome and principe sa sau sa saudi arabia sn sen sn senegal sc syc sc seychelles sl sle sl sierra leone sg sgp sg singapore sk svk sk slovakia sk slovak republic si svn si slovenia sb slb sb solomon islands so som so somalia za zaf za south africa gs sgs gs south georgia and the south sandwich islands es esp es spain lk lka lk sri lanka sh shn sh st. helena pm spm pm st. pierre and miquelon sd sdn sd sudan sr sur sr suriname sj sjm sj svalbard and jan mayen islands sz swz sz swaziland se swe se sweden ch che ch switzerland sy syr sy syrian arab republic tw twn tw taiwan tj tjk tj tajikistan tz tza tz tanzania th tha th thailand tg tgo tg togo tk tkl tk tokelau to ton to tonga tt tto tt trinidad and tobago tn tun tn tunisia tr tur tr turkey tm tkm tm turkmenistan tc tca tc turks and caicos islands tv tuv tv tuvalu ug uga ug uganda ua ukr ua ukraine ae are ae united arab emirates gb gbr gb united kingdom us usa us united states um umi um united states minor outlying islands um u.s. minor outlying islands um us minor outlying islands uy ury uy uruguay uz uzb uz uzbekistan vu vut vu vanuatu ve ven ve venezuela vn vnm vn viet nam vg vgb vg british virgin islands vi vir vi united states virgin islands vi u.s. virgin islands vi us virgin islands wf wlf wf wallis and futuna islands eh esh eh western sahara ye yem ye yemen yu yug yu yugoslavia zr zar zr zaire zm zmb zm zambia zw zwe zw zimbabwe tkabber-plugins/georoster/maps000075500000000000000000000000001500237002100164035ustar00nobodynobodytkabber-plugins/georoster/maps/bwmap2.gif000064400000000000000000000316701500237002100203500ustar00nobodynobodyGIF89a£¡ÿÿÿÿÿÿÿÿÿ!ù ,£þŒ©Ëí£œ´Ú‹³Þ¼û†â”æ‰ãʶî ÇòL×öçúÎ÷þ ‡Äb(…L*—*£ó J§ÔªõŠÍj·\#óÛ|Çä²ÙN«×ì¶û ËçtÚùžêâ÷||ý(8HXhxˆøÔ·ÈÄøY–8IYiy‰™©¹iéiVS¢ðIZz‰šªºÊÚêúj* I’1‹‹ »ËÛëû ¼&ŠkÌ·p¬¼ *ìü -=MÍÀ|­mZqVíKü->N^Nµž®¾®t€RŒl¾Š&_o/þÏßï/™Ò’€  ÆÝ¿… j;hh †&˜ò@¼ˆñ@þ%è²aÆ,9†»EFá»Q§5 3f0?!ý°¬‰sL)MÂÙB™Ò¤Exô"ÞÙ‰4鼜¥’1}ŠNZÉS¹¨ØèÔ[»M{”zýj ª'kbË.{FËj€„dÉzãڬܹoN~4O Þ½cw­lÚæjU S‡¢"E7±b+ƒUò zá±ä£aÞ=Öª±&À‹;{¾2Ùr†Ð¤·^ú÷JßÔ¬[! ¢´ì•û¹žÒç¶îݶÚhøìá3)ãÍÆ¦PÑÈ›ÓÅ*üidâÔM×6æ\ÍKèÙ»“3¬÷åò–ns:¨ŽòéãÞá_û¶½ühÅÃLJoý2HªéþûKä„Ù|sP&`3G~ÿG[Võ”MyþMÈœq ÆåØ{¦q߆ºÂ„Ö…Ôy×<@aŠH€H Q+~¨GƒEÁHãRõq@ÛŒúå×[€¨¤f›‰·cƒ5‰¤kB^øbx+Üx™ƒ²à䄯pçb…In¡å–^’D"¿Õ2&•Kf(%b£ V¥,²…¢‘_‚Fäœv:¥ˆ:v°§„Eªif›éÁæt`hh¢<('T7±z6 Z]/MvÖ%\y)Ê© Œjhb™£ÄÉ&|>¨S‚RZÚ/r>å}†êc§¶þ¨˜¯Fzw±Àêd Ý:L‡uhÉþ±ÊÒ:eš³f¹)ƒ¶,_ËjI ÿù3É™×F£Òò¸ˆ‰¼JªÏ®ÌV{â·Šd«­µî™† »ª@(G f±¹¹åìYX°+°½Ž¤lózd0/½¶»Ö© ó[0¶ëÒpÑ8h]«eì0Äø­»"œQÅx17 ã°±.üȹ¢®\ {*ui¡Ûp˜r®4§Û¢Ë@ =1´™þ\„㊻Á˜:?ÄsÏ#ÝÓ0«xè¿$«Ku·p.Z¡ÈQKp×Oæéq› ?kve±âZ¯Þ~d“ÆÙð¶=ÚWÉ÷‘{k‡÷•z—¸ž ¢¶Qs'ÎñàBàþ ªÝo³r8¢7íwä€F¦(o^,gGN1sV/ý›E—æ¹±¤Ã½¸lJ­/“œs³ÿ-9ŸG[.šÕMgìÿN*¤„+´}µw2<ó(粦ó2¿N<²è‚ =÷Öw3ý£3;šzø_7_'мÏe­çI\ùö¾µ¿3øê³ ?ξÏP½éìï¬+ß P×?ýåOw\Õ[ò¤ª/´ûŸûH˜rë‚ü£ c~¥½î-h}én48: ªÇ|—›Ù{P8-,σxúW·6Â÷‰ð{çÐ {t9únO#‚á>ª¦²ìS7ÔV¸Ãõp€Jdþ©U¾%ĈüÀâ,ª¨±(Êèˆ@|Z x2žìŒN´  Õó".2E»ÃupŸ.†Ž^Ptˆ×xG£¹Ñù‰Í£«èÈ/,ìR²2ª–p!Dð!#'©Ã؈LJ¬Ioǯ]ñ]gÈðRÉ€ñN:C â%ÑXJᨓò¢ß~Ä(¨”¥$a‰/P®gI]ŽêW:~@k´| 0CR 1¦°•ʬdÌBöÈI Rš”|Íáv2ÌFœšDT3Ï µäA¦[NŒCxHï—Ü %Ø 7’$Ún›Ú|":ÿÉCjd³ Èô@0+¸KLÞ²wø„I³þ„¡µzt¢ˆ›Æ~ÐÉrj1’çÛc<ý—Pûyò ÅÇ)òõÐCˆ’-¢¨K±óÆA8óÇ4RA=ªÇù)ô¦Ñ çB©—9„4iët _ŠÔ/úR¤#Æ4…š¦‰Ô˜MJE²*‰vT•®+žIÌ|l0^Õ|fU“ŠÖ/¶c0÷CÞ ©R­ÚBs\MãTW‡Ce§kµ 2Vv>U‘Y4gZ{P¹ærr«kNmiB¾>°£ô LYÆ®‚°ÒSEÕ@ô$[ÄŠö±Š¥§§Y©»~Ô¬SmðP+¾–6¤BšI#6[»Æ`”½q-÷ò8Úà6ñ« nTqþ[7Ðö¶xckJ‹û9(Œ¦KzŸe®)YÈw»x!)wËÒ–h*7¢ÌݕӔŠÙ* U6»ia"¤œïÊwºœ¯t¦É ßRå“>«o âSú–‘§å/kí‹à_Õ6Á~d)qAiZí¨ÃÉgn9`ëÎf¼ îpbwëá’j§qìoߎ –—Y±~èápˆ_LZBÂø›r%1M|:ÉÈÂMÓŠÙ{à y Ô²3,*ô*n/sQ¯ùÛªyÊd\0•Ç伾¶ŽÁIqã|ìXaIùÊdN§Ë<Á/2{]ö «Ö智Ít6³šEd@Þù²ýœãW‚õþc+͹΄*N}{H£&zÏã2†Uã1sÉ…®4ƒ”´jÙ’Œn´g¡ræÁžt°°Ó1”ûtcK«úÅ›. bÝqjk4²limÇÜÙdšÚ—«îõcýÝyêùÄל¡ƒêšâ5Qv´¯ŸÍj o—nƒk§5GÛZw“Âúô{œªdòA{Ü0ö´÷zá‹eÑâä§¶íºU/¶–hÄe÷²ÍMî|c9Ýñö°´Ãa{/—·„5ô=à <ãš®ÂַÇ­èŒ.üá(Îö¿'|!+ó™±O[Ç'Þ²VS|äêvïJMNò ›•Ò6ã¬Á—¨ðçÕ;ÎØåÈSŽsþA‹{±7LÎ7+;cܯ3·æÐ½Ýmš#ïçL§ñ§ONì¦7X¹ Ï/Ñç]Ã-{üãy&o×¥v•óúêaoâ×Ù§t†yÍÞôz]ªí7)^¼ìtoöÀênv¡å5O6Ö³~o™[]ï} 0Þ_a "~ð=-Ôûý\·üƒÛäo¾øÌ»òIÊ%¾5y+lô;/·¹>EÏsˆß•½ë'*ïu¾>ÆÍÛMúv&†íúš½ïÿIÓÒÿ^îŽ^»Úý>5XñžõÃo> ©éü— ŸÔÔþ¼»á©û?ÓóÑïþóëýË?=–¿Eæ&¯rðä»Yú_¿ûm þ÷þ£>:b9Ëãír­sûÜ—¿ÿU¶@òôÏ6wöd>ƒFbЧ2A|"nÿ÷~ýxñ·jhÔ7~ýG;É%7ê‡væ€IáwÆs–ÖxX…G¸w¤×}§ h}4¡=#vW‚™Ÿ&*’Xƒ¢)Š9s5žThd6÷S·ŸSyµ†[®9˜8 5:º£¼9$qŒóOø–ÈÖm˜¡ô—¤ë¹¤LÚ.Nê„Pê6mé¸É]úSŸÁGGú#7,È ¦”"£R3fJVe¦¦Ð„)ZX}§šJ}:§èU§J›\q6BfIé§ŠÑB[ZA„š;þÙþ¥‡Ze‚ò¤ ê6–Z7š¦Ã‰¥Êw4”úžQb©šŠÌi`?ªqfiJ6JcDc>(ª0º‡¿ä¦6F<®Êª6C)—:}¹¢î«kÓ:z¬µØ¬UƒÇ ¢¼X£4¬­ú¬bÁ:ÆZŸTZ*ؤ p…¦ '®ÑšP2šMu­n’­b÷Ÿé…ª*%«™«©Õ®«I^BÙ¹®ÑuìêN𪧲Âx ©-6®Ù‡j NûŠ˜ý ÿªsJÊk›0Ä am«°-J{1Q;<ê±K¤#[®ÝÚg8')“°Ù—¯ëç<àɱ$ûS´Dž›8,{¯Ëµ°Qذy§&þK³åœ±‰³j±«µ³hè® x]ù‰C+iB±Þu´vê¥æ€;TÛ2‰G„žRk¯\Û1óú¢\â(YK[»m=˰¢ØŠÇ'¶©E’$j´Éúꊷҥ³d4/[œ ¸ƒK¸…;¸¤j¸‰«¸‹Ë¸ë¸ ¹‘+¹“K¹•k¹—‹¹™«¹›Ë¹ë¹Ÿ º›«÷J-º§[¹3û¹~‹º…›%EJ¹áÚº³K»µk»·‹»¹«»»Ë»¹›®±Yº²Û»¶ËºÃk¼„»#°+¹¦{¼Íë¼Ï ½Ñ+½ÓK½Î%¸Ÿ¼K[½±[¼ÛK»É‹ŽµÞK¾åk¾ç‹¾é+½þ’^Ù˼ê¹Ì×½çË+á{¸! ¿ù«¿ûË¿ýë¿÷ ¾¡à¾õú¿·ë¶ÓÛSzëºì¸<“ Á,ÁLÁž+%L”½<¼ ¡øâ';‰LÂ%lÂ'Á ŒÁi‰ÂÍ;¿¨‹DÈ»%-LÃ5lÃ7 ½`¶Â ¨ž8ìÄC*^Í¡?lÄGŒÄIl¹:¼Ãá¨ÄO¬¸µðÀ·£¼ ÅWŒÅYÜ¿ÛÄ줺Z¼¿Ø'¾û¹/`lÆgŒÆÿËÅ]˜i¿úë,}ÅdüÂnlÇwŒÇcÌll—y<Ç™Z¾ª¤†«$ÂëLJŒÈ‰¼¸áÅÇ­T7ŠìÀ†ºò´þÈĘÉ™¬É›lÁ<‡‡<¾Î«À‰ëÁ»ùÈÉ©¬Ê«Éž i¼XÇþ{,Ç—|ʬŒË¹ÌÉ®<¦¨lÆ–L¾ûž+ºlÌÇ|Ǽ¬¨n|½\E¬ÌÓLÍX¬Ì@šÌ#Œ¾1LÊYZÍŒËß,έ'×Ìqy\ËÁÌÍ„¬$ã|¿î ÏÄæÌÂxü®ÂŒ¸ÇÛ ö[ÍïÏÿL¼z±{Ú—Ì@ÙÊ’lÀ÷œ wÒÏþܸ†ªÎÆ Ðò| §LÐè Î+Ê =ÄvâÇ#†ÐÏëÒ½»ü8Ð0›ËἺø¼/ ͰÊœ{¥±ÛÁ_lÒÆK­Ò¬þœ\‡kÐÁŒ¼AíÑvL¨"]Òìü¥Ô Ó9Í»‘yÑ»|ÐÎåРÛ{=a(Ìüc=¹qÉÔWýÐO Õºû¡*ÍÒ)Œ‡5í½¥L#Ï›Özì@^MÌ`ÔÚûÇe­ÆHÏàÇÁ7\ÎlÐÌe+.Œ×ÜûyýÌK-×I Îz-ËÔ××j-€2L×¢[`n$†­Ø˜ËØB;Ëñ›ÙK Ùü‹+“ÍX•½× ½À¥¹ôÃÙ3ìÙd}¹Â6Òc=ÓíØ§=Á·§Ú/ÈÚ]B»}ºó-µýÙËK>‚½ÄÆ­ÛìÛ(Ì¥ÁMžÃÝÚ€ÚÛ¶ ¡ö²ÑÛÍÝQ×ɹÙà=ÝþÄ}›ÖÍP¶ Ø“tW-H3»°Ñ--yšËØumÞçÙªÞë­Ê›ßõýÇ‘²20<×xxÓ±ªß佨bÍßÙ¿{ûßàå-þ­üqà“¼_ÝìÚ Nš¨èÜáÝŽÀÚüÎ[árªÉÚ%¤=»Ó³Ý)XíQ°ýÜÆwÛùâ»<ÈJÝâ³¶ÉÆÞåÒ‰276Žr8þÕ”n%Þãöìž*þÚÞ⸠á©ë.èçË ‰Øµ ݱ ]9æQ~Æ.Í¡¼äâíãs¬×bÚb>£ ž®ƒmµd^æf®Å°\±@¾æùâ(ÉÉmÖ×6Ûó}³_åz®Ä,.äFþþç2–Êöö¾É]¼/ ÔvçcÎÜšÎèPLãÚé{™È¶Ù®Þ»œÃU¾ã.ùÆ£ýé ÎA£NꊼS½Mè©î–$êòËížç±náFë n뤽Ü~+…è¯ÍäOEçÀŒìÁ.ì[|fÅnìÈœìV£NÝìÎ.Ý®e½w‹^íÃ¾ÏØžíç^Üþ—v>qI틬±|5¤ŠNàìnÂê¾Oú®æpþ½ç(ï>Ô™Zà Úóîï¿-Àü~ß _à¨NÎ3Šð­ìá8í· ñ– bÿð?¥ ðøyïÊÞä¼íˆþìï»ã-C¿îzN5*Oò%ßÔÑþŸþMÁùÎòQÝÃÓ|0/Æ ?óÇ­fìYÞ¯îå¼ò=?ñ  TB?ô o6Fo •úiJØÊžò½ËãNïõçÂM.'õ:~î]ƒà7!¶×Ñ"tõ'nßöo4£ŒóTöëÌîUO÷j7²´äMŸÃæ>÷ð>|׳ž÷.~öhoõN1s>î‚ÿÝ_øJþºŠ&°\¿øéÌèŽÿøUNƒ ªLïé—?ò~o½ÿñÏøÂÎ÷iOî Mñ¤ÏóÛ[ñ¨Ÿú®µ`åú˜ëm#ûKTÓý¨ó€üɯüËÏüÍïüÏýÑý6/ýÕoý×ýÙ¯ýÛÏýÝïýß?ý}¾üþôûlþçþé¯þëïü|ÃþÉïM£ý ïOÿÜOýõÿù¯ÿûÏÿÌ?çíOñ1uá!h“V{qÖ›wÿÁPI':ÑT]ÙÖ}áXži´¼ñ\ßy°n{ˆ#ð(f$«#ã×tÎ6Oé”Zµ^±ÍÏ+˜8uÁañ˜\6‡²iõšý=¿áq¹÷ wu€ÌöÞ†äÿÙðŠòºRæu#%Û+-/-°ìX & ýDKMOéH=Áú0_ace[Qkm•fsuÍ47Yñ\ACo«V‰‘“‡‡$„8ƒ–w§©«§•±K…­¹»£¦ÄŒ&~9¤õ²k4Ð×Ù•Ÿq!Éþ½çéëÃÚñ)í÷ù™ÅÓi ¡ ˜8UòAÉ”aÃTå×bE‹ïfüq‘#=…ê’,0ãCÎD¢ÔÈåÜJ—/\ˆˆ¦ÙÄŽ7qÖƒ¹sfNŸ±”8C‰!ËÂC½(H’ÇaKžO¡\MÄx?±fÕ•+R­_E(¸–ÊfJ ú뺖­¨rT·œì –nÝ9myÚÕGà7}d¼ŽK Q*B¼‡ÿñ{u,˽!‡K¬1råp 㜼™3•Np?ǰ<š4‰Î K§Æ¸A$ͧaÇv¼Ø\c ¬UçÖmB6ºm»ÅÈNëªh{'ïíôTµw‚G®›þtë„ ƒšä ÷Û¾†©‡ç¼e.Ï×ѧ,}{ðîøº±r}ý¶Ì;•aˆ¿{ÿí«å?÷|›G>óLð)üÒ¢o£!ŒLÁA"lo×&̦Ðjsp¿ A„LÃÌB”®À›FLq%¿cB.’JŒQ¯¥T¬CÆéNì¨Æb;¦²»QÈŸÌâñ‰!ƒ»C#™Ì&–ZDRJ"›hJõòѱÊ-“áA´+Á¬‹Kô¬¡‹ÆLó/Ë+Ó͜ԴéM1)£(Î;MY-¨ çìSK<»ó3+—ìÔPA$ò„OAåçÐFg䊦ï9ÔRo°!$H9­ÐNéb‹¼Ÿþ¼ÔÔQôŒÔUuRó7VQÄ ³üz8ÕV5âQÖ]«‰“W¬3¦¹\o-ÖŠTuýUYY\]ÎÄ Yc©•"ÑEÍÖ’4µýZ™h`³ÚqcJ´ÛsËZ¦Ft-Ú \pÆ¡ô=réýÈ´þØÍב`RÔ·Ðñâ-ÆC±Bª×àp3ÝÔß…å hD†÷Y¹ƒ)Î1Sˆ1~ƒß‡3ö&¹‰+™ŽIîÆá K6Y¹yEnYÀMYf³U)–‡™ÙzŸsÙç‘tú•“»r.g¡11¸çŸFÚé})E áYÅz(¥áÙéÎаÚëI[ÌR?l‡#ûë†~Ñ*·ÜškæþÎŽÛ»ªñ);怫–»‘Š—¦Ñ5Ývî»õÖ[]%1z•(y ç.í=%;pYÁn\î˜û@\ˆÁ泜¼ÓV{¤ížœòQ ÷!¿ìõ/#t äÖ§>Šï C ÿu?ª‚ì[Ûj·ˆzpn‹`‡·Av…!_¼úmð„(þL¡ ³ÆÂº0r{#• ݇ÃJ°„BÁ!1t˜Ä´ô0, …âþwÄ!ÑEA:¢-’˜Ey1±‰y ¯XD*EWcw%.Â0Y-4ãÓÆƒÌÎŒÄA£Õø·.ÊуucŸÁ:òáŽxÌ£áE"€Ñ `I9È=R‰Š,£©+Ý5opD$Þ4(ÉIRÒ–¼äy2‰­MžÜÈ„e˜ŠÒ<¤4 ô^¹7[Ò2’/Ô"DÉÃUÚÒpô£#&÷%˜aª.˜æ{KÕÌÀ˜’˜ÓÃå(“©Ì>ó¹¯)yÍN—uÒ‹)L&-¥jãþ*ÎÀötd‹ëS ›Ù´¶ uˆÍA#[³É ¶& œ þ «YÕ ÒJ&ùæÜbèÙ……V´…¦°Hµg¾gµ½%êÔXôºÎR°p´¦KWÓž6·Èó­j…J3cJ—¸— ­GÙ3?ìÁÏ—z®f£ÜéRw¼ëŒ,vQ QmÀv»ôùî@†+ñ>v¾Ý».zO±ÇîêV|/7è»+ùÚ¦¨GI'‹ùW úNËåî'=ôß^ñWæoyÇàŒÑ–¦•mðzÉ›KœIf•…ìþv쾎Íî‡×blŽÄ×0ñ‰ÃkÙ×–!®$3n› c®±)\á3·º<ŠÐ8Üá}âóŒ`±èŽlX2¹ÇÛq|þìâÝ ùÊÃq“³üP³Íî2‹£Œß!“yÆ”uèÄÒ ]\IÅšrN¾ŒÛC­Ê¦™3oó ÞA{ù9&£³½àGšÑ,s’G•hŒN`E‚uÃ,g{V¢Ò·-4` ¬iÏ9˜«V%§Q:j~ÚÐqªÞtŒ[íjIÓ:Öwžõ¡Q}c[›w¿¹Öµ¨›4Y[ºÌÉÅô°\dÊVŸù¬ö’/±fSóÚÉ©†öXíTWÓUÚWÃ6³›íljÛj§¦'8ÇQwmË’IDyámvûuÙz·Hÿ2á¶Æî@ï¶¾÷ÍïõVÑñ–¬¯K¼×ƒ °ßèNø6‰þÜÁ¬›žßbÅw!ñ‰äâzöÅK*eTÎÓã¯·Êø|1œÙ(g9Ä)Ùr—'æZ ·Á·Íq›ËUÛ¬´rË»Ép•ëç%ìÐoþò]êÜ’çî¹ÒInC#êi,º©Þ!¨öƒéÊÆ·¥»uM=§a¯zÌÑäs¾ý×lO;ó¤žs·SëízÐÜénòEÞ½´³V5÷îŲ{ëÙÖzÂøsrÂõðäL|_úι7ýìâ2§'_øÅ“2@›-Ú)C•yJw¾VL ý=UTûömdúÊæÍø{ äõÿl<égÏfh½Xç<Îù)U»÷¾œÐ±|éMþW,KHãŽÏÍ£q3×3øÎ'¦‚„?| ¿úÖÇ<Ï]·|î+œø«áܽVuù6Óé÷©üøÊ½,ùõßZ¸¹úšüç/õ¼êø ^æÇÑöÏëÚÞÞŠ÷dÇÏ.êÏþʪò²ï‰ÒI ô/‰n‰Ì,œ…íýüÎöro¤,°õ@9ð¾,wiDP¶¸ÎUÎû.ð‹ü¬§®99XÐfp¸³VïnpfÈgÅ|‘€6þÁ ‰°,¯îÉì€>Äuèè 0 ¹pm¨pû”etäï ±ÀL°éÆPZxì ÁPïP ÛP¢HPÀÒöîìúþ0ëëÕK çp|Êð [KÞÂÒ0üú/bà°×(,[OбA«wm# ÎÔ/Ffpô31CS&ÃÍ‹%e2ó§ý«5Õ­âïñ|†6óèªôC7Ÿ*€ùfŽ\ff3F¸ÖÑþ8s-8%ïL±Zh5×4LS:ƒèt¥<Š„CF_0Ç9q’;½3¯¾¥:ƒ“½xf1 ¬mÓ%׳ál!>Çå\Ñ ÓÓï3³&c¥¤ÂXÐ:TÆÞs@[21øÏPª0YÿÐAÅMp–RBÍÑ“À>COC3ñQüeºkSD™1X‚H6×Ì(´Õí-YtDIÔš`´_0¦AB”éñFÕìm"”K|ì6ë‰ËHHÙó4n OJÆœŠR ™t«$fCÇ$JèG…°—¦´JŸ6”[€s‹Šç9‘ÂðØLÇ”HKÔHuF §Ò>Å’M7êcÞ´Jdþ°WÔydI½ÄNÙ/6ò”Iž&?öÓ%Ç3EkIPW: •G¼Q1ò@IM•7õQWÆ·„wà¢?òþ‚Ô;6²ÄÃS›„؈áºQ05SóçTA-½TYGð;Òô`6õjü0Ö=¥ob•õ_%¶`þÅ<2­8ý1c#dMve:VPNd'PdGv])*gtú^Ve­ãSÛÕaeV•Kƒ¢ ¿”gC„[’69ùµ_g1WmÔf71Y#V÷SieÄW°òi£ojµ•UôB§êѸlgµ8¸vO¶*…²¦h¾ØÕm…®€5mÁäNÂvBð.hu9_ëXuÑ™P”Kóo+Co‰³LÑ•Xç¶eSlWPÒwJ,%N6RµP+kY“p!e+×./m·6s5·9¦‰nÉ"kôÚF·DLåLg+øì+hÅi5Y”L–5ë4’ ¶Bc·4™óD·uÚqqP*þ¥@’O.\Lwxi±x;Z§í·ê³uGÕl.5"4ª©×D¾¶Y&OPxijråM?õÆ—t)¦v;ãÔ7`~ÊOñ±(¦7~w¦<¯÷JÓ×pap^$BûXw ©Çý€ÙRÁnvˆ#ãðë6’«WdXL=rzÏÏs•·;0˜(eç|F‰$853„ù“sǰ„3¸iº…PW±OOÖ€9 ^Q†g˜†ÓIžy]X!•ÊVÌ|ø‡x_³K9K©iýui¡Àïw‰%Ñ„‚Ø,X…¥¸±"3eEØn X‹)‹»ø‰¿ •Q34ÕŠÂ|Ž ÑþØÎ~S>/ Š#˜v©$P¾ÎŽïxaISs4 Yvøˆ¹µÊ¹ðV˜HÎÖZ¹‘·3!¹@w“Fý¸$ÇV»“/R“×B]3‰É±hIù]Æ?Ýt:gvE®•Ÿ¥7ÙEa/ÙüjÙ–§Ñ”O¹=Iª´ÄÖ„FQ€ù–›Ø‰‰ÙØŽÙ#–ðŒ—ù°„Ù™Á“@o*˜ sFr«9ä®Y9¹·èçÏ“¹ùb†šÃ™ç–#ù½î5xÇÍÌC‹øÑk8–¬…'Ùnô+ÕpøhùY*‰'Azýš5@ï™`.#¡3ž:…ð =¯‡)Ú‘úþ1Ú¡5‰/¹£··?wžÙí<÷™ÎL™QzƒQ™ûð¹ÏJú¥Q2¦eºGDùîZºÓP§[…^z´N¢vèz(„º$‰ZF¨§».©™e©Ù;áì©¡©ošªÕÖª7Œ2`8.{y«¹:ߨEK±Úø®ÒR•ÊšþfóH+«Ûñƒ_M^ßúö­ K­×ڮߑ`óZ¯o…¯]ʯÇr z°Kùr {.Ãú½y„ṉ̃µ¢°åÚ¨»''ÛÈ0{P.…q9û¨Iðü[C[´Mt³Áš®ç?pV›µ9ôªmxëÈšS»Ãj›ü>%²CÚµ¤ZËz›rÛþ'n·s;@£z¶×'¹™Yq]›ƒ!ZÕ´w霥{+–û«8Ÿ5ÍG;»;˜×–¹›DwÛ¾ ÷HtçÉλ©[½­»¾²Ì]Ë[Žç›–ͼÑWnóÛùTÙø¿1K«{½o±¸o~«ÖÁ<ýÒ»¨ë÷…üÁuOŽÛ{ÂóyUíÛI?<Ãy›Û"œÄuÔßÀecÄ;Ü@M<éŠYÏà”ÅïûÂFZ–cÜ“dêÅ'µÆ-¼Å¼¦¹ØxÜÃãÄm\į³±}2¿8ÜÇ‘\8UdÁ‡;Ê<ŠÁÑž%|ʵ«ÊC|¦›<Ç5Ü,ÃÊË]™o­ü™u,yµ9&éÍÑþeÖœ:]œÈ4‡L[ÎmGÃZ½õä=^ÈÖá=Ëi¶Xaž™|æWþÎú[õ4çu¾Ý¡Œ7©\ãyñ¿…Þ¦üÇižÖèÉté zçYu°°éa|꩞¤žçm+ëéý敾ëœ:ûÅÉëÅþ神ëÍž…“}âóã>êß¾ìã¾¢·ÜFËçÕ¾[ƒ{ï)¼ï¶çÿ×ážð3Ùâ]>ìïÞæ§µ¾_¡ó‚îýÄèY^ò¯J+¿ñÓˆÙ¾í»|ò=ÿó7vE_Ö›²àÝÞrNõ÷ñE.Ÿ½ôMŸòeß(i¿Mµ1_žG{÷sÑþîk_sŠ?ø/zv•ßÃ]}€[/*®‰ÿö!¿‚þÒæ°vð«ÿ¤Gû[ê¶_÷»ó_Ó ]ü©¿üEþú¡ŸÁÔýÙ?ò³_Ë£ÿ¹5{þé¿þ¡Ðb´:ÿ >¦.·?ŒrÒj/Îzóî?ŠPš'šª+Ûº/0Ê3]Û#œë;zû?0(FxÆ#2©\–ˆÎ'4*R«V3«M]»Þ/c+^Ëæsw¬^³‘è7<.ŸÓmí;¬®ßkð[>`` a!› b¢â"#‡ácS£$dÒä%¦På&g^æ'h¨hT§ßèéT©*k+„*¬ªë,mmmì¡­.nËîoh¯°!pþ±ññܰ2s…rOsôà3õ˜ô5vvMõ’¶÷÷·xw9Ó8zººùÑz6õ»°ýŽ>󳿀vø$#ð ÂOï%Ô5¬!D 'žˆhñ"%Š1ÎÆñãA’,IE$“¨z©l‰%A—2gÒ€Y‘&(\8UÚ¬·ó'P =M½«(È¡í2mÊN©SF°¢FTº”*Vš6³J-ŵ¡Õp_Ç–„I6‘¬³ÃÆSëÖ¢Ùo÷tšë­2»z¢ÜK—“_|x=.¼®¯ád¿Ì’1doˆ#£YL9ÝÑ0f/sn&²³™G Çy}õy4ê_S“+þÄZr%¡#_Ónµº¶b¸¥™’`áîà™n —âºø¿;¼ì!o¾ˆ¸s"½£k3ƒõ쀀ËÕ÷b¹d0oÎìó>”«whm ¹öò¿Ÿc¼}WjÖ—Ëï?ULÿÕôž€¶ñð” ¿ñ×V ~Wƒ8üvN„æ@JBsTwz„‚苈â1T4¦U"‹Ž<¦b‚-ŽH”Œ&’˜–V#¼øÒM= yPŒ¡u#`C*éaK: Q†­a¨£eOZ‰äTWj)\ ÝŶ¥“y9&kGb9]Wd%¦šm¾Ve#AºÉ›sÚé—\fêfTŽwrÄ Ÿþ2¶ç$r @‡*¡’¤¸hBÕ@:é\„äÔ'¥wIš)§_¡‰É£Î#–¨¥6õ)¨˜šŠ©«ººª|Fò*«€Òz«Kàc(®Ø´Ú+°eígfª¼›œ­Ç*‹‘úeHì²¶l-µÌº3++.T»OÛz‹hE,Ürã·ã6Y.º`õeGä¦k¡Wо;oU»¸KïJuá»ï• b˯(_<ðGò޲ÁÙ0Ã2ŠÛpÀB,+Ì]£ç´Øe‹0Æ¡šý{k»ýÜ×…ªý¶ÖÖ¹L7Þu£çÜy{qœß³7ß} Žbm¾8{+â8ãR¹Lä•ãx2Z[žŠ‚gf±9與½¿¡ÓG¹é©?1:«>Ŀ;>»twˬ9íôÈž;ïâhÛ»t“S<ñ¼ý^|&ÿ<ó6BÞü€y¢=õκ^ýuÂ+=÷ùÞ}MT>ùr__>Êwƒ>û¿ÐþÛÃ??"'ÒÿôîÜ¿ëÇóßAþô÷¿!ÙŽ6ö`Ƈ@±7ï[`º´>¶Èþp<C2Á ’g7P³Y9ø€ZB„&<¡Õ6ˆÂ²°ij! cx¹éɰ†6¬Ý o¨ÃJÈs ä!ƒè¢ý±ˆFtÆÖލÄ%.€ˆL|â%¸<(Ž­sTŒœ¯X¬i‘n9ìbk,F³MqŒa ¡£&E¦ñobl£ÔhÇpŽLûœóÈB<ê±\£ü(H²q†äŸü©Èÿ2‹|dê™ÀÒA²’x“äügÉM–-‘Žða9)Jšy€Ï%*y†ÉI~0•®¬Y)_)Ë×År–¶]-o©ËÅår—¾ô[ )LÁõr˜Æ[1©L5ºáþh\&4µÈV'qѼ¦¤J.J«•Øü&u—" òœæ”ÏFByÎun¬K:b'<ã)ÏyFô¼'>ó©Ï}ò³Ÿþü'@*д =(BªÐ…2´¡}(D#*щR´¢½(F3ªÑr´£ý(HC*Ò‘’´¤&=)JSªÒ•²´¥.})Lc*Ó™Ò´¦6½)NsªS–Ús§>ÅÊ3*Ô¨ps¨F- 措ÔS-µ©”y£S£ÊRªV qwÕ­b•Ûä*X¡Ô°’US,+Z[öô²Õx|I[㪷ʵ®°YÅP½iWViƒ4ÕªiÈéL½*u•5¼}Þ8k®žæÔ°eìŒÈF‚ Ž²¦$l^“ Á¾ ³äѾZË6±Ž”ml_©IHº& kš” àŠp¡æHµš fa³Š×Õâöl޽íΰÐ[ÙÒˆ³O+ãM¿¸ÙÝù·!Rnis93žB÷~C.ØS%qæ0-¼*ªC“hÝØ’–ŽÚ=o0*^ð)Iåzã›Þ‹Z§}iœ|󛬊֗{ç=nòô+àniTŽÀ0TY‰à_Å$;tkabber-plugins/georoster/maps/bwmap4.gif000064400000000000000000000370601500237002100203510ustar00nobodynobodyGIF89aŠR÷±±±¯¯¯­­­«««©©©§§§¥¥¥£££¡¡¡ŸŸŸ›››™™™———•••“““‘‘‘‹‹‹‰‰‰‡‡‡………ƒƒƒ}}}{{{yyywwwuuusssqqqooommmkkkiiigggeeecccaaa___]]][[[YYYWWWUUUSSSQQQOOOMMMþþþKKKüüüIIIúúúGGGøøøEEEöööCCCôôôAAAòòò???ððð===îîî;;;ììì999êêê777èèè555æææ333äää111âââ///ààà---ÞÞÞ+++ÜÜÜ)))ÚÚÚ'''ØØØ%%%ÖÖÖ###ÔÔÔ!!!ÒÒÒÐÐÐÎÎÎÌÌÌÊÊÊÈÈÈÆÆÆÄÄÄÂÂÂÀÀÀ ¾¾¾ ¼¼¼ ººº¸¸¸¶¶¶´´´²²²°°°®®®¬¬¬ªªª¨¨¨¦¦¦¤¤¤¢¢¢   žžžœœœššš˜˜˜–––”””’’’ŽŽŽŒŒŒŠŠŠˆˆˆ†††„„„‚‚‚€€€~~~|||zzzxxxvvvtttrrrpppnnnllljjjhhhfffdddbbb```^^^\\\ZZZXXXVVVTTTRRRPPPNNNÿÿÿLLLýýýJJJûûûHHHùùùFFF÷÷÷DDDõõõBBBóóó@@@ñññ>>>ïïï<<<ííí:::ëëë888ééé666ççç444ååå222ããã000ááá...ßßß,,,ÝÝÝ***ÛÛÛ(((ÙÙÙ&&&×××$$$ÕÕÕ"""ÓÓÓ ÑÑÑÏÏÏÍÍÍËËËÉÉÉÇÇÇÅÅÅÃÃÃÁÁÁ¿¿¿ ½½½ »»»¹¹¹···µµµ³³³!ù³,ŠRþg H° Áƒ*\Ȱ¡Ã‡#JœH±"A9™2fÀ±#G 3YI²¤É“(Sª\ɲ¥Ë—0cÊœ‰£F89#°œ@ƒ Í)’¦Ñ£H“*]Ê´©Ó§Pü™:uèPªX§¸5SU«`ÃrĺªÙ³hÓª]˶íJ9rfÈJU¬] SÊÉÀW*U¾€ç¨{·pX·ˆ+^̸±c‰¾üù›*Ù°å¡’'_Þ̹c\¾q÷FÎL:îc¶rü^ͺµk‰˜bË®µ¡³íÛ¸mÿñ7VsÐ 4^7‡)ó ã%ŽI¹ðçÐ]Ç‹œ³yî°A6Ôªµñº÷ï²þo®R9¦yÄ#;'èë8ÎY2;ÿÇétÉîwû"Ï¿Ûx¼ xm`ƒ 4ôÐG6Ø™Á¹Å\²ÉFas0Ññ} HA=h°Áˆ8õ`Òpàpæäß‹0*õAÝ9(”0vØ@Лlbãb £ãS‰Áz öA‡`ùÓL*hÇ” )PŽ6ر ŽFU|C-ØÇ“1–iæJ^ÎBƒ@vÔcŽiÔC›tæ'T v䘆 ÉVœf©Ø£Ciè¡ ñ£(?¼4ºžA·Ü"ŒvÜrP<¼,ªhœv„Ö¤…騑ւèJ·Ø*NÂÌ‚¦þŒ>z꬧ÁqÉ¢pôNþ0*¦—äZË-(Ì<]’©¢-vê,¹šµA±…]BkLÃŽz÷Ô‚ Pþ`rí¸Œ]ò-GÚ„ÛrÀÁª{Ì‚ƒG}D+¯»ãî=÷Ôv¦ ä˳UTüR ”0÷¬ÛÑÖ’;& ê;©»8,ñÆOÙ+Ð8i<4ˆ8àÁ ¥Ì G}ìï@õ`0Å…­¼nAµàðrÁ@÷Á@ ¡±¿íà1Ç+õœñ,µÔsÁÔK3mõK$Ë,s̹ŒÇÎÕ2ÄU#TÛº,Ä ¸®†‡BóÌôÜl«õsGFÔ3þ'|?}µKplÝQÌJÿmxJúè“g³À¡Í] K•¹˜6Ð$“,Џ>T_°Q‰¦Bör2ÄÜ×ÓV.D0„•/¡Ëç“/¥ùAp,žSºL-¼ð‡ß%¥E:ƒ=XòÎ@œs”;A¤ëc òf¯.6ä’Ïïå’ B´Ûð=ëtnK‰‰O»p×_{â¾o Ô;º0¸½%³ OÿeÛ{žSh¼Ä ¡²@V€| ^úxž <ò¹Î" üÍ@r õyïA_>:Ð|ˆï„'! Ñ·™>°€(±Äüô”š0ïƒÉõþ‡âFhþFáîGºø½†gÑ‘l ƒYØ :x?„Â<ä!(v˜Eæ¡.'üè¯Èç½£39L‰ÎÇ ‰±D®˜“êàŽKœÉ;,1F+Öé(S´ ?Õ¿øÁq-Lì1IŒ°tBéDb=t¢x¤ Å~8±32ÑC c¹CNÄtÄ 1:‘Gš¼•y¤³ iQ…´œ… €1BΔ2±€0‡‰Q±©#—Ü…2—¹ ‡4S ·Øå%;!]\r•àeN®É‘U>3&œ%X€̉œq›»°ÔQnź#Êd–Ô3—©ÎÜbžõþ,§Kð‘|øóŸ¸pA˜Y7¸¡ÕK%ŠÐJX*ó\&4•™Ï˜ÜÂâ 1*ªO…T–ÝÜÇRn±+ qÔ%5>šÒŽ2Enaá>Zº7´ 6ÅǦ8b-7€Ô#„<è?ý‰‹YTDEª?“ŒZå¤.5;=BŒ}@u%Å…Rÿ‰>|U©¸H(BÚPš*ä¤>RÔL£ª”KÜew¸ÃARzƒ;€¬›¹P.á9E¤³pÃ]qr°ÜÁ¬*Q˜S;²ð€­ ¹Ä`9bÕ‚Öõ° !äb­r‡†–Õ Ak%(B¬nÞ²G¹Ádí׸ޠv½þC €z¶6(™¸GN<ñØÀ®¶0{¸KôºYO¡V!ªÅIo)’\Ž— (H¢;‹â¾õ·8‰XDš»ƒé"ö¸,Jø@Û°¬¶¥<àƒPÈI-8– Ø5Œl[RÞŒ‚! U®EÜê"¸U °-,„[RëÚffqC\×Öº–º÷-É<úààñ}kAzÑ ãD$;àH)r{Pb%ó*.9#Lvü¶ù-fa {€löÈIŽ Œ›¤¶€qM c Óª”81Z:\|€e8èE“;S2ƒHà°v €=Ø¢ SÎ=Æld“|ÀºBf±þ¼Âü°‰™Ë‰‹G(ÁcíàÇ óò˜÷¼ç [eöH³RÞ¼ç/³$É”¨ƒëPD+Ù)8ð¤}Prf‚H¤R£ŽT¹el¾Ž>j@‰LSDÒýèGYx:ò´c5`t£cÝhS»ýujKçät®óv]_ƒG¦­eÍhR¿¤ÀøJÚA 0:,5¨v¬³M—Ô¡Ûñ1lƒìYé4GFݵq7Ù¶†H;dQcø!:ŒF¶P]‡x£Ø~ø„À?qoˆ¬ú=Õ¶ÂmS‡O«$Ò“ž¶¢oÃìm3šþNȼ=‹vp„׳¸@¿þ’âÛ ÛáŸEìr"èHûÁ0?öÈ)¢îQ¦5Í®A¬íŒ›/eÍ^ÈP8ò…3ºÈ¸@¨-ä pãÔNyLŒM }ЃÕ7AªM jÓ‚–¦EØÛAC}Pàëô¸z¦Ý›·-ìWŠ>º^²½#œx¹À€‡_æYyñ‰_¸†œI{Úùg’v(½î€âÓžõܽ‡*?ºæ-cu´§X¯6Ø=7_—îW¯6JØ IÐâY´`½@¿î°P½#VOû$.ø‹Ë_æ™Äí¢I\½ ºøõgÁ†V×÷CY1E~ñãã[ Øþ` Ú›|ò±§GÆ3Dö~ =&Á†\üânß¼üÁÃúƒå껉ØÓ´Ü{ÿ;Š7|`ø+69éWô@A±A+ö 57Ó#~öÇ)×—}§Á`—ÁòЈ?ÒÁ0 ȸŠÎè¯8:ª¸yGPÂ ÜØ‹ëÐŒC!Ð@þ±ò€>¡;˜’ðŽMØ)G ë Ïx"ú¸ë€뀎ú( ³ÐEÖØì¸p!°Œ ŽàhѸ”H ²(ëðŽ ! ’ðL1G@ Ü ™ 9 ):À:ypŒø¸’@’Iëþþä2 ü¤yø0ŽÈ¢B ufŽaKVq@” ŠqЋ±7ýR9•qÀøLq“@2ŽÑ“^)a“0•,Y–e99 •qô(³ RYg„të !U w à:€I· ¡¡À–¡–ø—B!ýˆŒiÈp˜‚)øð˜—fÙ™3X˜a `i’B€ ¢(P cY\Èà“4éüD–bš³`š†É” ˜!š1šQšn”†ÁJ … š‰‰ž¹œš‡ ³ð•®‰=y»" ÌY'»þ š8±nœr0 Ã0Õ¹Öd"ðM31ÆYî™pÁiTðà‘ Ù¹Ÿ† 0 ó9 à ¶Ésiä™  Jbüé ÈPžñ™± e›×I wáUQ †±»À¡@ "žF¡³ jÎ9j–&º Р4Z\#f2zå)jP£Þ!D@ÍÄ!¢:Zz±D0»@ :w`¢æyÀpO*Bz•ðwð†Ñž¡^ºw1 >º¦£x a¢j@¦1pP§eʦ¶Q¥¤! ÍÔ¤¢ þß„ 7 Mšb !–X-!¨¢ Ašóp†1©‚0¦1 `zú©ó¥±àw Kj zIÀ¨³P©dúo€£©Ê¢Lê¨V±©«b‘µÚjp§`Zºš„žºªÈztnª¿JŰ\ ñÒ:`¢àÜj§wà°0Å0©¢€û0®J¼ êÇzI ªÐ:¯?’ŠºI@®Ð®±­žy®P¯@­ ÁÓ:"Q®Q Å0#r &q¯`#éð¬—A°³€±—±K¯$«\~eI0+Å`þêÕ™Ð[ {Ið^Á1[‹CaF0ñZ<²Aá 0g…a´´C‘0±a±³à %û©#à³>‹# ³v1Fà±(1f©´Ð¢ `Ks`Ñl›‘¶ÁT+h #œx3«_³`bÛ̽h@õËö7Uìg&¾vA¯Ð»½k ¼kÃe Ä¼Æ Œ¿|½&†¯gFûnñ£KÁ@ñeÈ‚ó;þHÐÅpø`Ç$±…Q[LgQZ¼kÐ éšÍÛàÇ`LŒñhP8Áa¡’Éh¼pÊÀÉÑ H°Ê«üÇñ8¡ ½°HÜ­¼Êó°Ê@Qð%Ñ „°¢XH@ ‰ É Œk°ÅóÉX ¤ ÌÊ!Í@‘eÈ„`Ìñ°|ä„¥,l~¬ßÜØLͤ »r>@z¨u#̸¡ÈCÎÌ”> í\5KÐÏÀ% >PÖ<ƒuÐÒŽàaÓý|6M+ç€Ó8!máê°bKg@ým³p;ýŒICÔŒqi@{% qJ@×,៰Ši Õ ái u×AW}*>@M =iÀcpŸÀÔÈ´GqÖ«ø +ñAAÏmq@{ÌPaÐ-¡Õ£è…½ÞA ã"iÌà (@ÍWí:‘Õx}³ÙÎÈ J`Ú&qÛBÁ ÌðØk×´W …@Ü3ñÛ«þhÙ …0ÜÑØÞá)ªÝ‘Üóà`Ò¥ iG ÜR ssÞ,ñzCÞmá­€xÈý ­°¿ðÛÒ-Š­àèà°ÚgÝ ‚Õ}(à­0{MÛ®éç(Àð Ëàœ­Þ·Á h]0¤Ýý n1 èÐ&ð *žáúm˰ß,¹&ŽîèÐfbfà™ð &`Û1 {¿ )ž`aàîÿ°½6¢Ù.±½ùW“ŒKž LÀ`fÁä!å @Þ-ðÈ-@H0 b.þ-p0Ð}þäÞæmþ,sp´°ç)Q}9ñ]Îongp’>éf g°{ÿÐNŦpt’è/2 gp衜r®:n 0 FÈs0èaë•Nè6b ³0 ¬3r0 ÐgÐŒ>¤Ž˜¨Þ¦Àmñ MPŽ>J+f¹qå³·ßqþ!íýÅç9¡íÑsh„~.ª®ëb³`ëN0žØs  0ç±îîŽ0€Ð Í@ðbÞ ÉÎB+6¹±ˆrìСn+f¬3ñ Ïî¬ÓîÞñÞFó°ã‹þí±ï¡ã*…Ž„³žÞFå0 €pæ0 $.Oë~1ë@13O@¯ñÓ@Pæ`]æÐæ;?Q,_CO€óè3ŒPUÏíÞáKÏÐ >Ï AôQñF_0'ŒðñâÔžÞ$ÑgßU_åPŒ0  èÆ?JòÎ9 _'Yþ§p ‡à BQeÐö ,°ùæ Xò@‰¿‰/ñô³7VHù1’Q`¹Q,Ž?2ù–?Ù‡ŠÈRµÏùôŠ„–¿÷ ‡ ú& • `Ÿømþt‘ލo(厑ù‡ð ÚýÀO²œ‹O²`”j6ÁQ¶o pþmâ (ðþÚ €îÎð A¡†"(€1KàÀ«D˜PáB† >„QâDŠ-^ĘQ#Æ™8#RäÈ`#MžD™RåJ–-]¾ ù ÁGgmb”gð¦DP% ÊXò™ÏY²®HæR¦MQ>#¨t ™E;­^ÅšUëV®6;'ÉéX²eÍže ˜Ç®mÝ¢ :0À<“ Ǭˆ#í^¾ÉZA5Ž[Â… F|õ+”¸}?†Œ6X€Ä;=AÅ”YdÆ|þ^‘RC‘M/U@€Á•]¿†›kˆŽ´O߯;åfTˆdK|‚hVIµZÉx–ð‰Ô‘’Z/ ­[zRYcâ|~þ[ûvîݬñtòå÷ÎS$NQï S -E ¬qž‹&¾Éì Íç‚­ö$°À¶RHà?Ü‹=Ö|"š“æiK•@PŠ&ù4TˆÁÓ„Ï@‹ž±D%IWdQ%|BˆqšQ$·^Ò0…'ž «EȤ ÑĆžHA x„D²½C ¥FÑBñI²„¥ÀXTC…0à ÃIÜš1J{²€j¼p"Ž«¢Yp×ó5„Š$LH&6(ô ±" bD‚T#‰&À ÔwF“yR £ f á„c!QX€ÂwP$4‹æ." ”„ã‘Y€àŽLè0$V°ÂD,H–&Ä(ÐÚùÈ—x‘Ä`™$F.„P˜%E¤A&X2EJ„þh³Mº£ ¨$ˆ!%âO†d‘]€&š™Ê‡L\ª%—" ið±—’+ÆÝÁ ‹ˆâÅàå7ari,B%§É5®!„Às ᜈ; !MF— qG:‚€SDÖ¤'6M¤M˜È¡ê¼ B%BOi ¢NƒE¤ñP”€¡ #)  nØ aAJÊ‚s“¹T7dz ™Ê”"îÉ$›‘>KÃ.ú¾BdçjSép%:ÀIŠ‘Pzª † À99ˆ"5- ,ÈtÒ¢"F `ÀU§¶ úLêõzZÖ„ÄÕ)«á@ñþӑ̃ž()Æ€Q ,HC #PHZ †L´!1mÅ'] ³Qœà #˜+X€¦x„¯v½›Z% ΂v)ŽˆE2:†¤ ŒHI8O0 Ž£w[H1DK¡†±£m GÉʈbv hKØ2[ÓvM’£BsaBÖ‰À@ [-®Iæ¡Ú” ·aDBÚðÙY”²-­¥ío‹•)°¢´³Èİ@&Ô„¹§=w¥»²ãW¿ûU‰*Ò[#X%˜B …d™;€y¹2ÿi½Y©°@ŒáYø¨á0€«%àѶ@Ä.ÙmCìShÆhñ Bl„þ$0ËF6Ó“àõÂVц)¾q+dÈ0A~O̲HV KVîDÐû’þd(©rŒðàY0ø0G¶ð±bÝodÁ`žÅ†« ë¾ä †r¼\ÖäÆY$xm…C¨¡…§ÄY³AƒLy ƒ 454l€Y 1¯`tHH,æ«daG$­¸d—>ˆçe„QЕˢ>‰´ðäF$„¯nEŸ `ZÀÖY0AtéS§¹Õ}Ž¢+< º¼Z!ÆæJ"¹,Pš+­h„H¸’2gaÎQEuµŽAWvd›%¥nÄ6Ž1î”ç¦È1D²•þÌêžÅ1änj@{ÜÛÈ3½ G[åÜèv¶VØ=’i§¤¯À4B®ìm^9 ¬ŠfxJޱðxÁÜñBSàxo| Û8|^¢‹¤ÔuM‰yGñMz§™¨3Ëgá…W”b ÷¨1bè–”¢CI! ñ,uäÛ)¹HŽr‚½Ø(E)âq™KÉÇØ¤ªn¶\Áëk¸ÂÒ5.¸@HÉ@ xýè²!AwB „¤! P÷­ êŽÀ& ¸@õ¾ÏâbÇJï. ~ ˆ»wÖqí"¤ Z¿ù#RG8¾ðº"#ª @G þáó"üUxnšÈhò'q„+\aú<` ©¿<Júj™ž/`\7xORXc+k ÅtHÑz­^$¶OH^€$ø {»ª`ýë¿-Öàþm˜ïú–¼ò$¨í¯Ï²ç )ýëŸ £Ž*Ô?î(AýÃï’ì@û? $=xBP?ø[™åCR øëר‚‰nÀƒPÌ{ Wð¿q…–Ð@lCÀ®!„$9ÀáûÀÊè@‘¤ú{‰ $ \ /°kÁ»ñ>køïDÀØ…A3†xµWÂ…W…Æã‚“sAïp¾p„LxÂ,”8þˆL†IAøûWã‚¢›ˆ!t9 Tuh™ÂYH†d(*ô„ˆk;  Ck€LˆÁíHƒ„4Ј$;C‘ƒ/d‰˜sC])ƒp„kÚ µcCL5„X¨D„p=¼#.ÈŠ+€XÄ›HƒLL CLÄ®IµK‹’°›€…dƒX¤®˜D“XÄPƒ?õR L€Äƒ¸EhÃYøÅPÌ=D‰(4ÅS¬–dTHt€a¼ òˆ°ÄÕS8,¼Æ#‡S¥4°B„p;‰ˆk$FP‚”poTÆy9G‚hFHƒBèŸkˆvlÇ“€D†ª:9ÈGQþDlrH¼‚pŒˆƒÆrœcD `X£uì¶Ø†w܉ÈG¦È›ˆ„Û†Ÿ›AȬ$ŠÇƒ(„€ÔRœrTÈŠ¸H“¸$ˆô™(@‡ƒh…”Ć›°9²˜Éƒ"Qƒs¤‹sÜ,Â&ˆlè°›¹X¸É•”ˆœ„É*`7•4Dz@œÂ3HŠ‚s´Œ@‡S‚¦tJ‡À†–ŒÊ "—ƒ@ñ ³ ˃†ˆÛ†”¬#KhËX©Kª)KX†´„¤qˆ}¿Ìˆ³0„Lº€hË6-°KÉ‚™Æ¼ Ɉe0L‡qÐÅ\I¨$Ì@"—½\†þÐLRÂE¾ô¶Ê”¬½œ…¼Ìt…¹‰FÈ„Ô,ËÁ,MX:É ˆJØ \Pƒ½((‹¨„ ¦—Œ@ ‚a˜ðˆ$`à@z¶ w‚¿þ-«ý½ nè‹Æå᥀`ŒØ_¦€ß•‹á*Z‡Ðn€ŠlCþÒ€_æ3¢ªXâ@€¾x†Š8…&†‰(Æ#fжá#£u°Œ¸b†{â¤d¾ž…g⊰€uàâ¾ nHc˜ b’²€8Žr°‚±Ð °%ã0bƒ3Fˆ`?Æ*‚ä@þ¼Pò¿#èÈb‹`ƒÓ`d†`b¥:ˆNž‰ŠH^ °€:.dC¶KÈä7f‡8‚X>‚1˜å# åªÓ¤ ´a‹è‚Ûå‡`T~‰g`Kà⋃¦äL塲QŽ3$=C³AŠÐa~ ˆ@¦½Àˆ|` llæ¸zfŠX[f¸\ÞÀdž(ˆ]°„vÐjvQM‰.¸0þn ygк{nYÎ9v>CN€×…€çéèøå ^€¥€‚"è}*(pƒðg‡èª;X×€¦íà€YÈè„Ø póéëaŒ‡#í9ƒPQŠ®h7¸„bˆÂƒ"î‹éá^¸„1º–æ‹„®Th Eáàú¡é¸òiÛºòކæjyÙ„Pj¾¤KØiˆP…¦¸ΘDÀ稆(œfº—¨†Mˆ5^ãyëíbàUx‡¾f‘hpk…¾ÐëP‹†wàq$%q !¶Nªh ê—h y ©kìI€r\‰ÚÑÌÎi;çþYèˆX Ëî‘=Q„µvlXz‡ÀioX ½Æ€Yˆq Ά(bTí°b0jé0/Ç€"Ø& xˆÁv *HÛ¡‚M‡ƒXîÕ*(´ä®‡!8EØìž•‘¸í@B›PT‚ ‚!0oìffÜX¾á Ï–bZˆ/xo—˜o)|kéÎ탖P„! „øo„°Ü΄0ï÷‰†h€ƒA »ÙnÿþléðlöÞ‹ HïYÀ„ø†ƒùn‰ïˆ A`Àmüþ¦´9ˆ7‰wˆ0Є0M˜…?§g^Yo„ñ‡ˆòXLpŒÅ1 _Hˆ/0•¥‚~qþDB6ñ^’‚Ðoˆ™—aPaØï*’̦%.€P_è ˆõ>r³éIó&W§xH›Ma `qr ’‚.¯nòèL‚LÈš³ès ®;ˆ ` M(ôŽ) ¸l7Ÿœ-ßš  ƒ €´ j¡p° ® #0wÊ6× L€H§ÝvŠƒPí;aò NT) ‹LpxtK‡$)è9ÈQ¿•¬Ð€=~»Tø`ö/!un>ˆ:›õ–˜[‡iu/÷uuöP«Iáô¬H…J‡`LlÏ IOóƒÝ6s§þ`wnß„xöoW'{ïe—W¿›r_É|÷ÐŽ¤‚Á 9ЀDЀûnw}7i {ç %ŸyxbDöAtW ͹ñ‘°øŽ˜jÁ÷òØx´ðx_÷÷ˆø‚j¿ž†'Æ¢iƒ7 ) nø›7‘‡Í9vˆ-§i F¯"MÐa ƒ¥_ú<¿£”W:ЄDç‹iP:8ˆs' Ï€4¿B¦••zì!Œ0ûèú÷¡ñŠˆq‘˜‰Êrˆ¢•/0ú¦p•ƒ@™yƒyØói ù±·«Äø_ðvg<¿ò:Çr+€¯‡“ÈyUêu>g1|•H0÷…åž2þüü®Œ÷‘ò>xü°›z8}”`UŠ{JÂnÈ›‡ ×å¶Ï1ÈvÁ÷pÉQ}Ïo‰W}§O’7!*øïÙçò×o‰h0u(kâç}»¢‚Ø n(“)kH¢‚çþjØ„Pþ(S¹¾þ%ó}ذ³ÈþZ±í^ À€ùFˆÙg‰h8qûõˆY,hð „ 24è Ĉ'R¬hñ"Äh 7rìèñãÆj³Äa,iò$JŠ"A²léò`5’Þ4ÎÚ$“à¼y ("ÑÛË B‡-jô(Ò¤-y¥lê˜Ò¨RfrjõjIS·‚þ¨ÀªxélÈëRXŸ¹²mëö-ܸ ±Òµˆ ŠÜ¼ÖíëTÜ=½ycBäåfaˆÌ7 ‘±k=âlù2æÌBwøí  ‹æÐ³<“Æ(n¥h®‰\@̪„nðB¸bV¦Lˆ$îèˆtêà‡ǭ]ºoeâqwo‘jåJ%ØÑn4€äkw"¶udŠ‹7V•nþ<ú–]œÓ]¾-uöo¿Gj…"Ûå3Öe=Dº `DœXA%(XÒN;Úá€%Ô7!…èY"VÏT(U|ÒÕÁ5Ï­·€„8ÏI]¸ÊG€XÐzc„("Žþ9õ zäáU(<㣎C¡äDùäÓASE ußD f¢P‹]˜OBÏÐ0ÏÌ#!‘NŠ9æA‹ °ŠG,"é7ܰÁF˜dr¤åš¡)Jct gKzLdÁ,7dÁ‘%݉ç¡Tè"¢p`œ|J*â<È|”CXqcAŠ“.Ô¡‡ÎB§I¢zúãD´È)%‘cª–›®i ä”%0äÀMë¨z*°rª™©¦º{”uÔªIäÛÑ*qC+£% ÊDÀ¬CÕ­ó,‚ 9Aõ,¹NëµÀ†[g%ëT‚’©å4†×PtÊÙ{Q¢ØAD¶¸ÄyMþA.²î)8­ƒ .•l”®¼·µî¹X¢F%N”»oÅ%í#qBû+7‡tFSô/™$ñ2 ‰|M¸Àh,©¡Cr€ü3\4w\ײ3ÏÀ&1ôEÎ}ÆX”°@&Ïr KWäó@(“ƒ5Õ9±ó,c#=Ð<[@dõ ÝpƒB"?=·TN¨Í4]wpÃÍž–7ErÓ-Èeü=‘Ü1> Ê(ã‰D‚WµÅƒ}‡@WKtCxFTA¢±åƒ›®Ô!îÙVOzÍ᫳pºA×0@ÑF|°€2·Îrû¢UPÐ5|ˆÌò+#Ðã±c´þÅ7láDé´[”W«³^=™ vŒÅõ8ÑìaÑÏA»?÷ó¢…2ãŸýF„?Bzkï×”xŠÅV—9ü  ’žKšq‚E1"lˆïf,,ÁyyàAšA [¨Œ€Üßqla‹fLÊ94 ×<ˆ…à °%X@ùþö Pp~$4l¡¶2€Ïƒáq´qC9±¢9rh }XÀ”AAa#Â?|ä†ö#HMr ä5€H–ÐC%âˆÍé ™^xœ#¦Ä‰dˆ˜Ap‘%cdIç!Ä‚¤„WÄÂ'Xñ‰;¾1|ÿ0‡IƒF25þGN¢³¡:ˆœC/æˆ"AŠˆ`b Ù(d$™H¿,rLšÚ¸Þ˜SÒb“0-bi†Yn¥ÉFJðI‚Òt ¥_ÜÈ'\2M˜ªd…(+’‰Ä… )éd/A ̾¤’Ox³e/³‘ @€  H&Df`†·0! 1¾ SD0šÄ4é‚MIá­”ÑÜ&(ÎàŒ3@dÐ$ÊQ&„ (Hp}‚‚"»Ì?0w2¢ñtJ<…7Pô ŸÜ& @Ñ€N2a¦˜9Ï0ÏL ¥»üˆ6ÒЈœ ÙpDÚvôXÞ»èEVjM¼õ”þ!Z˜…Ô(µ ËžÐT¡„à 8C# H$:9jQƒ¥ ¦ä `T ˆÖŽ,é)EÊT ‚ˆ¶u­ákYO’ÕSý´4¥ˆ캑³ QÝ«QêzFXÕ‚½^#òZ’jNj¬@bcE€¡ØÇn­P aˆ@Ìc³œ:$k‘VâXxõP_±qZŽ@#´ YÆ8Ø:ØÙ.{ªÈ6žÕWÏd"µá-QbÑVlh– Ë(DB2 ä*Ñ¿ÈgŸU 9à§Ù¥îK¢ [¯`#b˜…°aÏÂR¼w½nD‚{,% I ¾¥ˆlÝë’íFb"þ±0ìzé»(ýâoi€¯ Èu$e¢áH "@`‚,ø"ë t'¾áŽ2 ä*Äš*l3D v†gâ”!¤Â%Hñõ0+Y.(xuWhˆ|cä*A qfSÈLjÀØzޏn¹ö—Œ…$CÄÈî‹%Ï“òÊ"’ *ypV-¹’±¿õD2íµ+,$r…%›d4>ˆš¯‰.Ž ¿%‡ëDæY$Ùm(b ˜„J¸£(—): 0?ËÏ«sÅ›Òg‰Œb¶Ž¶ ¾q@OäÌdœ–Ý9uä•\û‹tA’KO汪 ªŽvc­Ýþ YM½:u Ä ¬ŽKˆ_cåÁ.sEŽMgÓ  ñäõ³§ÔÚ H¸Hµ×ŠbÓů·°lëá˜{–ÓÔAˆl„yÁc}qâÝÂQö,ð=n¶Ô{”çfdÇÖÀnƒ ‹"ÿ.äµóyW$5ó „n5p┥ tw"'®ÑŽi|È·]óÜœàt£ãûvË Y®5TŒ ayÃËðLàä´9±Êå…s­a#°ˆ`\±*8Âæ¦Ãy¾]®Wdê ^àHEz¾ÖcàÍF§ÛÎøôrý|MJ‡:EQÔm¸ÀÔœ ä{õŸÑÓÀbþÇš>ë”Ç8Æ6¶á˜qí@!;1¤×…DEØaqâìÀ¬¹ß%B€ìpGÒ 6²hƒ÷Ò²Ó¬tQyá€hX“áb‹ÈÝtFˆ,P3?zr­^{Yxš²â=Ê¿q yBŒ0{ŸjÏsk’`ÐÓS¤ …D¼jC=|>`h¦€€)²O7ÂcEîá=eLÖ)ú¯Xæ†Óqÿ*#è,ED¿áë¶ÞüBÿ Öó5mùeû΃ýÑS¦´,èŸõ€’`Bt—4àP­É!€^‡¸CØ0J,D | þŽI¸ƒü Ž|”L6Dš7œB úP®Ž4 @ ŠILà9G "D8 À¯‘ Ôàê¸]NÈ úÐ Žœ†…ƒ4ÀDˆBêÔI8Ð {ÀX Ha«UᆡSDÇý„ƒsÄŒ™¡‚!Žˆ@ ¡uáqÔŸ`½&ÞŸž)‘œQ‘‰a=å¡®Ét)Q ÇyÁXJ! bf@$@!Éag¤E|Å@":bz"JÀ(-¢_¤Â²‰¢jAÃr¢hxâIlâÁƒ_ľÁâoÉ¢*¦4ð_/õW_äÖ¸…ÂuAÃ-¦Àƒ(€;õ…-Ž[,\—þ #z‰¤âý4#]øâ¸-J4F£‡ôÔ8`<(‚ÑÝV„:†Á6ʇ tãyȆ8FOÅÁU`ãÉI]Ä*ã@Œƒ8У|Ø£;GÈG„•U9…*¬] (¤"<¤@ö£*dsPã@ EúaQ9E¸ÇÚá\Gr+N}\$q$dsÄ„UF–„JFžÈÉÀJr´¤_¤IG0ÈÇLU&Ø$EŒÁ ôäGVD¬À DÄt•GADÄP:…Eæ¤\x¢@¢IàC!ŽìF”ìǨläU>œDÒ¸lCT2ˆÍ®t‚IàBÎn„@„Ïþ¬Í¹‹I Ñ2„HÀ¶$í¾ÍÏ^D0¥ÓV­ý•D€„X-×.[Iœ„€Ø†@t­Ùê¦XXC\HDäÁÙ¾-rõþÄÌÀÌÀ­ÞräÁEA.ì­àvÛ²ÞànŠéÃECà"®ã‚W;Ѓâ*“fàÁ'`ÉãfC è‚.DDè0àAf´\'h®ê: ƒèƒë~‚\Àu„Æì®®í⃴ƒìÞ.ïžVíö.ð¯ð/ñ¯ñ/ò&¯ò./ó6¯ó>/ôF¯ôN/õV¯õ^/öf¯ön/÷o-t/øÖG-p‚/„¯ùG-h€úÂZœ¯ûŠF-ÀÁAÜpÀ=|ïûæo\ÄÃ,ÔB-hB-l‚C?`ÿê/³ Ø€ƒ ƒD`@OðTЀCðDøCô?þP°+EË–' cOÖ™å[—óÌË—ê)jºŽÉèÉšÚ'ç~1ïNTD¿ëP©¼€øUïžµcìöó¡çžpÝêZê1¬Íüg¶1U§ÜyWaAÖ¥m>!¸¨“žþa¦0W 4¨GS¸…KLjÄ)œgÌo¡¨å“Ì?J|Ö—rç§Qþ µ—fñý²þ•:• ¿#(̬sêi4`rç¯>•RKkÅ$Ç}œödT[èw ƒ¨èP"M ® —fhÀ±@Û£êRjar Àlþ5×.s´Ó5¼…uëÎ(M+6MÊŽ¯M7ó»­c<É–y@g$ô®RøÁ¡Z^^[ÛËöˆtäÍÔèã¶GÉŽç4Jj°PrØõpà}i¿jUùKàûדÝ|b’ßÂ3øÂ×Ã×€7a§P~ðã€G9¦øoãG‡¼m¦5þƒ ’xãS$.Øh‰Ï>àÔ:Ñé¸ý›½™ëýNìúSóIÂgòÍyïÄïOc¨6Ÿ¦Ãoöa¶6d%Ÿ üÊIÃ`+Ϭþ'jZ­»©Õ$Ÿ~Ù¤ºœEnÌ2OyÇ #ô¬^2)ÚÆßWv»gÓm{r ;[ã•4©q{'@8ÝÍy–›ñ§JÑ]ÿá'¶”K$FXâƒsÆSÛ$œó“Ínø{㇅ä`Øê[ž=1\‰¼Cð×Tžk{­Vé.mfͽ˱$wÆz`dÖrÄM$’4To³¹ë:—‰í4x˜Þ&Þ‚XÛg¦ìûW5'Æ Ø‹S©iå“\Èc!ìËùGý­…¸éÈÈäWxSYÓõ«=f'S{{Hex£¸¸Œ Ô6H+Ðcе? O«j¶º™‚1rD®Ñ—Àt.:dö®Žy4¬eÊ–ç£?ÄoYÃÍðºîJŽŠ¹#ƺ sJ¿e6:¼á—x1JmõÈí^-4^ñ§†§]ºÏ.ÙLw{Š£œedBxŽ+ ðŸÃm^])Eÿˆ ²cµ¼» }…îIb§?Þ£ÚIik¿"ycÜô«­'I¾f¸kˆÕŸ«+ŽkÔü1d·-üG§’Ęã{€ã®±«VŸ uý2Ûì:‹½‘%ü¹!ó˜1ä€ÎIÆ}rG­fGðk]†®µf— 4­+µ¹6'‚Y‰Sœ”ŠèZ‹dN‹©‰áMM. `Â[°(-ÎÆy¬}Wú͊ . Û¡*›¦‘Tdœc“êEz<ÿ o/cÒåÔ¯bº¹Ò]šÝÔÉÎA\áòÃŽC튽ÃýgP¸’^Øj6“û¯!•ö*Ûºƒê l±UWÙ2îyKx?Å~G™‹4kÁ`AÈõëÍs'°ñ.•£ý¶ÓÉóZcKs/”›†s–环¥ô¿ -#/¦–KW#<žç¾3Šf¡à» VàIV{-»~Èñ!MßÞéœþ4ã‹­½¬.e±ós|,ø‰ãoYâ¨<=u&÷™âòî"tÀÁVÜCéŠä|]û*üW¹ÕøÅ¬o¹¶/æÂ[ r2ŽH$“Ž9¯¯ôßèD›¬l™c(bòË–@§°§NÕÐÛÚÁn¡c·XÇL(ª†*²w9ªÑ…]dßÞ~sIû8þÔ÷w²hQ|TÓä[CØin¢“ËnÜ®bÚçi= Á5èƒöÐuN¬ø«UžÏÏó®L—òÈ× œì ð¹õÏzûB}.Òá‹È “ê9¨æÑ­6«²ºÆµxÚ½41X*M{×~­Ÿ1Ø~Ç¿|;«[j6žžÚkBYny'Ôšê­¾ø6Òí iuÝ’ÑòÀpϽ7UðÜHlÊ¡²2ÄÐ×7uðëAŠÚç&ò5¸Á“eÌ™À9Àç"lä¯)»›FŒ!¤"‘Çj¿ ¾\Â.u¹"Š-Ýd¾ Œtë\mÇì£ðŠûSM~ÃÄú¡·f$-¶´ÞXõƒÇÒ»ø>ø þâH^Úþñ=¥gžFŒ½ÏZVøM¥išLšNk5²¶õ‰&f,qØ’qÒµS³·;DTƒž®)¯SǼ_û*iz†y„~&kMÓ6ÂMFIaA² ç#ÛŒ×Ïþ,ý’>0Û]O§øw⎉©éÒ0*—³G7ÊË&7LÚ¾˜ñoÁ”Òìõ mÓW½÷˨ʆcü)òŸ”3ǽ|Å xTƒÇ0ÛèŸ u/:Ê7:ÌzŒò;ÆÅv¬lNÔ9ÁÎÓ]ÔUF¯§ò<ÌJ‚’SƒWìßù_ñAø¿ð¤E¥ëþ=ŠM»Y"±ÕüìÏ;G#îúzV‘ñ·â®‚»lÜ‚w1$axÊ—ÛÉÎzú×b²V–çžãUIºm¥êp¿ kox^d_ZM¯D¬ïæùŸ¾É#æê=ý+Ý-?m߃~Lm>âH¥üÈ"FTϯï:}3^5á~Ï~Õ¦“WñÊk÷QFØÊƒfç*T‚ÄëPx³Å³ö‹#A¥xjÛUrêÅ gUë¸÷8ÅD¨B£Ôê§ŒÄQ†³_=OfÕÿkß‚ŠŒk‹3c ÖãËÔüÙÇá\¾©ûfxGLÔ~Ë£éÚ¥Ì0Ó¬H#?/ð«0=xä ù“Äþ#ð¶­—£x: 5Ë3´‹<ŒÙ$ñÉÆ1ŽÕÊ0âˆááb%›b—_q÷‡¿l? ëºÝ†‹gi©4Ú„‚ ÍQˆ›ý¢_§^™>ÕíºŽn^wsÄS~7y½½kòÉãu’7dd9VS‚ïšÖ_ø±>çˆõÏ Û§z™a¢ôFôsyÅ?j¯ø®¶&°‘A7Ÿb k®»fpw‚zq_v~!X+%§Œu8à ç–þy« ñ{â‚°eñΪ;‡ï{þUÊð ìÎíªox3õàkåwn÷çôö¨ú[n‹YÅÌý8þÙŒ ùÁú ­&«ÁÄú×åÞ±ûS|sÖ^6“Ʋ[ÆÛÛD€ç×*j¨ý¥~8}‰ì?á=º(ï¼¹‚-ÿ@vt£êTOöÍô‹üÔWÕâFT“Ì`ßÝ< tZ„ž?Zü¤¹øåñz솟ÇÚ™+ÓiEþKK/Ç/ŒmßãýSå]£‚ÓþÏŸtÛTÿ•Ÿ¬¶úŒª¥°}O§m¬îÏ0¯ÇË‹Ÿnð.e¯µ¼Ãód\±Ûîk°ð÷í_ñãÃqyqøÅîâ)±ݺ>:òçêM/šZH#œÓYúš· lK¤„–èAéR§ˆnåàí_—q~Ù¢Ü?á)·pÙ8k8øúq[0~Ý_áÓþÈçD–mÙûKÙ¶üc¦…ý*^§‘Úøwºgécëw/ŒHëÓŠdºÔÁ ’\F|œWå?ˆj¿Žþ$¶—ž8–Þ.r-`Ž2sêBçò®Nïâ矄7^:Ö } åе—Ï«FrÎ)m³õâï^˜FLR+ÍcK⛕ɑT¨êA¯Éõøµñ9 ²øëX×k¤F1ŠâçŶû#xçU1c|Þß\fìùwöÅ?ågê‹øÄ’AŽsž*ñ°œuëšüµ?þ'£€ø×RÙyj7»õÆO^´Eñkâd0%´~4ÔDqd¨,§‰4ÿ³åÜÛ¿•Ÿ¨ÒxȲ²¢œw5uñ;LÒ6«­ØA•'l× „P ¯Ìé~+üNÔZKã+÷ ÆU'ñÏÔ¡ñn­¾Õõ9®6®šà³cÐRð ?¬7Œ¿‡ÏÓ™>8ø!`û\ž)Ò|œà?ÛƒíÖ±æý¢~µ»Þ§ôµ‰[Ë'ÍÉÏÓüq_›ðøij¸¶6æ8¼±>÷r# {ç¥SÖ<56Œ¨ò]ÚLA"9C{ñM`èÉòóêg,Ò´W7³²?D¯kO…šm´× âëyü€NÈb³{—š¯ÿ “ð”Z¤ßð”Þt_³K¸cÔm¯Î‹}2âá,D 7aˆã“]&™á æg†ó_YX€B;ŒœóU<kÞlˆæ˜šÝŠþ¾gݧöÐøJ2á%b1œ}–_þ&³u?Û£ávœ\Aw©ßÞÓ×¶\¯Jøö i6V‹y`U’H‹oRÃøCtÏ•—¢ü;Ô¼J>ݱ[A9cv¸<ð1Y–¦Ûv4–7~T•ÿ¯3í}öêø[©L#º—T±ãvë›a§ÈÍÍtß¶oÁY\$ž&™»›Y1ü«óÞ÷Ã¢ë ¥]^é²³L†l¢ÿ¼AàûTwÚ—mm,í¯ÚI8$¤0 àþ9âµú¥k7©’Ìñ*饧õÜýLð·Æ_øÎ.<1â/Òyž^w&IÆAÁ®ŠÚIò­ÂþuùKðÇâoˆ~kë«èޝÅVòÕÇË: ðOPFN¯¦ì¿ko†÷6ñ=ìZ…¬Ì¹‘ Þ™ÍsVÁT¤ýÍQß…ÌéVï_+>Â$µSƒr€“óS_ÄöJK•'ýêù_Ú³átgrÜ_ÈJöˆþUü5§ÃL–1j€b<ÖKWùYÒñ˜eöÑõòx²É”›ÔËâYK,™ç©¯ŠÓöÃð’Ì"þǾ0D¡¸Ï¦ÜU-wöѶ6‰¡\yåNÖyPÜã#:U¬-fþ7Â¥~t}¾?rmcòÆ=8Ïë[,O#šY®=.ÏÓÁâUÜ>v§ÇÞaëÅ~dÝ~Öÿ®6‹^¶·ÙÔGj¸o®ìÖ[~Ó¿äøÚAžx¶‡ÿ‰¥õ ¯ªͨ-“?R›ÄÖänÞÃð5ž%¶E,Óp+òÖOÚWãt„–ñÕÇ'qÞ,tÇ÷jä´ÏÆh”lñœ“ÉÓd–‘ú-QuBYµÏð?MdñuŽÜ³³zqPÿÂ]dåI0;œ~xKÇß´§Œí&¹Ó¼F©b =´côùk¥²öÑlþÑ/Œâœ±/åM l¼ý?­rÔT©¾YTW:é×uR”iÊß/ó>ÚÅ0oÀÜ Y“ßi—W&êíD®nXñ_èßµ/<=¯I¥üD³µžÝÆk0RX¯Rü+Ó´?ÚÂZè oª$1±*L²€Aÿv¶TjGÞŽÝÑPÄQ¨ùogÙèϧí|M§ÛÑÙÄŸî|¤Õ±â0‚Ë¥ÄIþ.¦¾eÔ>>xI½ñD¯e`I¬ˆ¿kO‡I+ºÉT o)´ê=j*’Õ&\«Qƒ´¦¾óëè¼ca´·(Ä|Ø sO¹ñžŸå)†9‘œŒ×Ìzwíðæé†ßÚÃqJ«ðþÑ n.’;é‘Ä­´æaúóKÙIn™^Ö“ûKï=Õ¾!^ÄøŽu+œá—Ò­/¥š3Î'8\×›xWÆ?¼o(m Ä–7°K’1Ÿc]Ši:²æÚáÙs†Ã |ÐZ48®uuª./ˆ !1ÜÊž£'¥Bú±¹ÎéšMÃo9ÏëN}*Áp«+}I«¥ør"`ÆAÔîæ©U„u!@m„¯Íض*¤épâ ½3Ã]Çö%¸û¶Á¸ãŠ‚M"×Ì´2 …Èq–н©Þ‡$3žjÌŸo¹ «æ'OŸnk¨MLrÌ0ÙˆÇëRǤ( #’-¾ÎÆœ±7Ô=™Æ.íuÞ©€Í’qš¸ ¬ˆ|¹ÐõÍtÇKÓÂÿ¥GnÃ<ù¹'ùÓ£°ðùȈ@’@Z™bAìÒ0­´Õ™O•4%‰é¼çZhš¤k¸Ažx"E?Ö¬ý‹O÷$éÁé´b¬™Â¨ÜFö ùÖN«cä!¶‹R‰~H#Ôf®¤zmÒ¡\zÕ)µ{‹Gù#g^ä1$~Uf }nSl‰*œuÏøÔ]…‹bY“-´Ò=äØù[?SŠb^y»Ls#Œ}ÆàÔ2\ÎT°²+Ž9üh¸X²÷," Üò:Õh50•fÃŒdçY·×q’«nsŒ‚_³eÔïÃn–Êaõ}‡U+È9N·í;Žß˜c¾sRùnܶO¥r+®CÆÉ0Ààäô­xu»–PnÎGÚi ”Õ6‘†zñLû>¹ôªñj0•‰µ*jHAz€iÞB劂J°ô4§Ì‹‚û³êjÍ™µ»Î\FG}Õå›@»±½yù… wz…ˆÌŠ«øÀ©áhnaÄsr2 P¤Ùéô¨ä‹ð1V/z«Ü\¦€†Hä-€ÁºcœU4‘ÍÑ&b1،՛}IB¬W AdñOx ÄˆÃžõ-´Çb‚'qÎGNÕ$^jð$ld)³@bc¹ŽCRB»@ùù>Ô¯ X½ÀÝÖ–Y¤¾µx8ç#«ƒ£0Æ(LV0$R²3äßš$vÉ̸ëô«×öã%cU!¿Ú¬dƒiêpxëZ't4i¥äK€gÉ<äšš)7|âAކ±‚ f>ZÓ—RxqF ϧj‡t(ÜÞW€ÔV@½¼›æ†ßrôÎÓEŒ4:'‚XA+Ó8ǯ½[µ†G…„­òœt«SÄKŸ”Ò›ˆ—äJØ«( °:yRÒdžíP›”Ë¢£û@s’~lt=ª9‚ÄÌdW@>´¢á„;‚{ÅU°3ÀöïM IÀ㊋Ÿh‘ ÇN´áx) ‡>¢©y¥”dåqƒŽ´nˆãéƒÒ“zŠÆ’Ýmm “’rjPÁˆv>ÜVRÈÇ'8ãó©£¹;@sÓŽ)\,h,ª­†,r8æ¤G,Äíã¶OVx¹Ìƒ §}©Æð ¶rØ=éÜ\¥§pÒ`8ð¹53/îܹ/cT¦¼¶-‚Ø+Æ}êµÞ®Ö±ÈòÉämcœ`~$þ”œÁDè\Zí/¶2qÈ"‘.£ UL c­aÅ©Êì¹EVg œý1ØÖ]ç‰ePÑÛÉm†)KŸœŒdg17³˜V9-ãU d'ƒóŒÜÖ²jÐÈr‘‰’0qžphvcå5&1«‡–lìËœS,qò‚0?•dÉ©JòíT<ŇÝÿëU ŸÛXcÌW3m+ÜA þœR 3ze…™^Ý'–ˆ‚*Ô+m?ÎAÓ¼ÓQøÏàê[½HK:HCÌÃ8<úuý)ãã6“-ìVV3Kq02,`mb:{úŠÅÕ‚v¹²¡RK™-Q ¡vîüê…óØAk‹´7rKãõ®VëY×5[w–'þÍû7Ï—ù„€œ`ûcž+.]Ä·mP¶›D»OÞy‹ºEHÉäǵhö¹švoMâ=//®ZÂd)’à o¡=jôÖe!ób¿m­†$1ajò™>kitÖº»ÛK„430ÜË •ÀÇçÖ½Ê =>ìtÉekh™ í#±&•8snTŸºY»´˜Ú—¶¼áw*«`1÷®_ø“‹l%º°ºg‘¢…Œ`óŠë5ëjÓM¸¸ÐlaºÔ¡Q,v²JUfLòº}?JÇ}ß[µ{›Ýì/n# :°;”g3Á$¸ïDé= ’OÞ2ÏÅOÅu´º›þö1.ÿ$”Làa™rçô¨-,tOÝ·‰<;â{«‡ŠUW{[’Ñ‚¸%6dcßÖ‹¯xqšæ/²@¶RÄÑ˜Š•u Îìã9éÅcøSáîŸðúi¯¼#}u¹o6{IfV„œ}ÿºé×5*œ–’±¤œ4p¹«ý¯á I/t™|UnæpmçŠIÄl‡pIàמë_.î5‹mGB×-$‚ÅÖVkÉçš4;„l@lŒã©è+KÅÚOÁokoa}®YéÚóÊ’IkÀ;> —¯ vÅrúV¥ã?‡W·¯k¦¦®“ʱ#È#Û¼eRÄŽ2IÉË9rÉ)«£Ì®Ž…þ9k> Ñ.4;m¿·c‚;‹o.'à‚ì=AçÓ­xÃPÔ5htÙ>!|$ÐãÓ¯ˆ´š}2úºŠfŒ•ù[`äóÅjx{Sð÷Å/ I«júM”°Ç;År„2y,ƒNíÙõï^MªüOð±âX­tÝ럗öœW²lŠD{nHù3÷³žjÔ\—½ª3i\Ðñ¾‰áïjz>…câY51$ŒðÚ˜Ë>žÉ†*àgaÁ$g’G®^×Y»i¦M*ãTÔî ºýžH?+µKãÏûÕÞëÒxfÒßZÕ¼4»nñiä»/ pFÐNm>\ׂ<'â´¹õ½EžKôYH;˜¼öÇI÷WJ1½—^ž‡e*’Z>†N“¨]ÛÜC«ê^ÕS æ4p¹}™YN3ÜŽžõÞhÌþ#ÕMøy«Å:³+˜¼©#1î$·˜6à.F23\â[|V†6¶¶Ò—9 ®²¸dG#®çŽƒŽ½ë¤øGuà/ÚLšLúŒ:µŠÁr܆Ubwå@OYirë7ËÏ OgÒ`ñ—†´¨ãÔíK rßb¶‡Ë>¥<xªçÇþ2cöûm šÎ%e}èŠÎàŒ`g8ëÚ­xŸâ–Ÿa§ý¡­ï£2·•ˆÆìî œxãõ¯ø³ûFÇðúÁ®|\Y%¸f[ (P¥ÃNYùÀ^;k×'9*tïò<×%º•l’îz&³ñ‹Ä0¬7ºœÍ¦‰¶Àò2`ØŽÇü+Xñv¿¬Þý©¯"(à4|à õÉî8¯…¼AûPøïÅ~'MZâ->Õ¼»tub°¦ãÉËm-ƒŒ‘Ž:V{~Ð^41¶Ôô7:}œû£´º$À}KŠ3œr8®ïì|D´“üNíœ$UâŸÜ}­ªi°k ‹©^»…|¤|FäžIQÔæ¹» ž¼¸Õ´Ý9Ë€ùˆ¹`¨ €yíYŸ >;ø£ÆºÔ"ø{á)£¶%ž9§Ä÷¤m¿CœŸJúAñ·LÑ|%ÓÞ¼ ²}ù;‚X= pTÃT¤ùHô)c#V<ñGá [×™M¾…¨E͹dyb1ª©Œž{שøoÁzÜjˆcA‘›$¨õª~ øñXÖåÒ5φðØCQ–Ò³ Rz’F8Á¯XW8U qèLªÉîs¶¾Ðí„Ì,S}Ë™%`0]ˆ“ù µ¡ø/ÃÚ¿hÓtÈá”±bà|ÄžrMlù‹žA©XÆ1ÞµQKTŒ¹™f GJ™sœäÔÏ­Iöˆ€úU¤+“ŒŠ\óœU_µ©"õ8äÔOzQ¶·Ö«•ˆ½Á#=)1îj—öŠ$cŽÔ‚û 7?J,À¼>½éKy5L]Ãpõô¥KèÜàΕ€¹¸žsG˜1÷EW[”/·#ó¥3¨8+š6'X$ldVmçñ„QóÆ*üÓ&0ª9E­ƒ[<Ô¶‹Šeµ x'ó¦N<žkEmÔqÎhòrOËÒ“}˹‘s¥G2ìp Žµuá 2pwÚÃÏÞu®žâ@ƒåV&¹¿ê“é¶3] ™ª‹’ziîyߌ´}ÃJÒ·ÙÐ6NÍ£ŸQ¾ý¢üoàÃu-Ƈ}£«ÍqºX摦Š_”¢)PçqÞ¾ŸÖ¼IŠ5Û›;½JÜÝG‘á/Œ¯·¥|£ñá×€ïµíwû2ò®^ƒô‡¼AÔ€n:ьӱÅzPÏ<Ð:Rã4¤qÅq´R‘žÔcÚ€RŠ6š\JU\ñšï|¡xGSŽ;-v „»¸;’o1DAÎs»¯+\àæ¦IæE ’° ÏO𨫠T,])T9sI]òß¼.#U:ä_Ù±Ó®âvoñǪZ'Ã_Úk× ÷¶úž‹; tH Ã!çýá‚9çñ¯4Ð|[}þÎÕo$ŸO“ïG#1P}~R ôë^Éà{ÿµ¬ aqbTÆ(”ƒÆ2C3µãb#‰Ã§Í&×—õ¹ïa%ƒÄÉrÁ&»½ዺŸÁ#O7:—†î-`u‹lPÊ7DÏ×/ž1ÓÖ°nµŸiÐ¥–¦š>¥' Œ‘ùéµIŒsšËø‹ñm¢’ëAðÓ¸Øûçp*㸮kÊ´ZëLÔá¿K©‘ÁfûÇúÕápØŠç¬ïÚûýæxÌ^”ù0é®öÛîêzl_|;¦_?Û|,2H&Ê(gÆpH'žüÔ·<3$fƒÁˆQcÚždiÁíߥcê>=ðOˆ¯†¤B°Úád̲ÀqÔœâ¼îùìÚæC§Ç*AŸJÁ›äü«¢–¿Ÿ®Ÿ™Ë[:K÷sMzkùZÿ‰.õ×Y%µµ·EmȰD«ƒõŽÈG%ÁϽ!=Ö¯ÜÀó}îqô«Z§„µdFŠçÄ—ÓLA–~¹£Ž•)òÕ©è™´°j¬9©S’õhó-”…•nÞxVÓ£yf²•`^w¼xâ²¼—c€‡¦zW­ ‘¨¯tyrŒ í$}ðgöŽðO…^Ox&;71¤r^Ø[£* ãƒß¶zšû+ÁŸü?ã-.-WA½[‹y<ü®¿U<Æ¿+sF7…e÷é]oƒ~,øóÀrïðö°cŒãtRFØ÷ýkоT|ÐÜõ𙳤¹*«¯#õ\XJw¨H°rHk¦ÓtÜÇ+R›Àž ºµkm2ybß÷ˆ|þÖÑöjáË.ƒµ?Œ6VèŸ4®1’¸%~œÖ{|h¹i”[XªoÉb¤Ž‡çéLôfB‘ëW%å ²än)Á[X'‰¥ÀuU$b¶O ·!Æ©MøÙ26w”D¤}Aéšê4ŸŒº|òæ[âòÐíÿ¯\¿äxÝíüIlp»9f µylž!¶ ‚Ã)ŽOn¾Ô¤°ÍhÃ÷—ÕÅ/ŽÒFb»·1Àen?š}—Œm œÅyÁ{ÈŠZ?Óü+È­> ø‰ŒK½ y$Œî=øÏÒ¶ øCãÛTŒGâa<8>œYrQ_mþG®Eªhzš¬ÖW0¶,9ñV”pØÜѼ`ôÈÆ?Jò'Á~.Ñ÷o >å9#'ŸN+bÞMOM‘c»T$çz“òŸB3Pá±+ŽÇ¡2áX=´á³èÕbDÔ# “[ï\¥¥ýüÒ¬Zv­äñ·x5 uïià%ݶT¶ÐÀdYÝì˜XÞŒ•'ΰàzdU˜ná‹pÈ»šæãñܱÊ`¸„^ ŒUøüce8Û5º¥—`q6‚é—‚²FHëךˆAä¶Ä;Ôž ã"ª[xƒG•¶24g8µ^[½5ÿÔÝ(9ç&‡t+!ÿeŠhÌNYsêj’Ûý¶9ÆA÷«ÑË óö¸Ÿ°ª)$‰¤'ŒqÏ®ö‰£ØOï ' [H"À`síšÎ ¢PêrqŽzUëRD|à“úQv+"Âà 嗠İ mõ4…‚±ö¨'·–bJ^qiAîßýj¸-üÈÄ–ÖàÎF(æ¶ácœ‰¼ý§ì.»ºîÅ"i‘^MƒÒzäcŠèb†BøšmÀUÈí#Œå£þ´¹ßA™–z\qÛª#¨4VÒD›x·Í<ìV!¸”·ˆîk>îäÆŒÛ¾QÉïÅMsrï61Î1X÷—£®ðF:Vnå¤X’íƒðÃ$qQ%ê6X··ZÈ’øÃô5» Ð;g¥XÝÉ•%ÇJŸí#æ`õÀ=«šXn¹ç8§@‡ÇÌ<ûÒh,t^x1|zsMjIŽ3Î{Šç_TÁ;‰#š5eòÌÑ»Š”éMÙ\š‡ ùNµ8”iB ã$þö‘‘ï 9É'’?ƹ©¯’O‘Ó*9#õ§½Ñ©n¹Îj›‡)±s}¬7&vËžyç½Es~B#´LÎ1…Èù½½+ ]@«?< mö¨F°…R+©†ç?ÏRc±³® ié‘ ¡’\ž‹ÛžóɬÅñµÅÄÆÚHÚ5!f˜HbF[ÔÖ&»oqªÛ\À‹ Í \6FHìpAô®^×TÔRUÒØ¤RÀË‘€í×4^å¨Ýýþ‘xÖͫڶ!‘ )Y1H9-ÔñÛšÖ²ñmµÙ‰,íŒk*«•\œàô9ÏQÈÅqºv«4öŠšœ¡–G;™1Ÿ›å9úú×€~ÓßüGð•l¼=á],ÛÞj6ÆDÕ Ï–UøU`õþU¥r­5N;³õaB¤öG×÷šö“¡i“jZ¶£oco†š{©UFxËÇ$W|Cý²>x/Â×Öƒâ¨u»èó@´’9b2K`$œôg"¿<ümñïâ¯Ä]<é^,ñ<·6€ñ"„ƒžqןå\N’Ö6º­Ö¥dníb™hì2 ?2îÁÆGÅ{r«kUýǃ_:mÚ’ù³ôÿàoǣㇱøïâF¿§iorRÞIR5³ ʧ‚1ÐWA§ø³Á>'·1ÂG&£¼:ˆ!‘§S°`äG¹A ÝÎkã‰~ü=ñ–:žm©G£j©<6RLø³l уžFsÎvÞ Ðt¿Ä`ð¤—ÚtÌwHÑ˸œõ#p8¯œÆcðtjJ »§µ•¾ûŸQÀã+ÓŒ¬­mï®Ý­ÔúJ? xEw‹ÃÚ%´×‘.èLàGR;ã“ô#­ZÔÖÿNh5§ZÏâ D…g·#É„/ÍÁlùv¯µñgŽçº¸·_K O•ß,1»«tý;Võ®«­LÖPÉâKDX3¼ÀíG•9èÀcŒã€8¬cÃOH»|޹`q÷¤´õ=‘üsâuÅÜ3ó|±Q’²Ë÷H$p9êN[ŸÇ“Üý”ÚÚÄÖÌî3"F®qŒÄü«˜Òügáy4‹?2æXZòï2AvÛ\™8#Œ`dd} ^_†~¹¿k·Žåãl¿’×nPç>ùïëZ¨ËxJç3qŶ_¼%¯é ¦êRÞGy$eæ†Wt9 FÇ?p>×µ‡ºî¥kimu{gy;Ý@¦'”Ç;xàçh'Ú½?Eðç„´X‰°ðý©ÜrTo,=rÙíZ—º¶‰¦¤Þ,¤äFÅGSü#òý*§ ·w+ÓZrßær:Å/ø«ÆqèÖ~Nœ nn&ÏÌGÌsÀ4ÏÛÙx‡Æ7׊u ;S³ˆCp« ±Å9Ã`Ç3WµxH¹xím_ˉ¶å„‘³ÈsƒšétË=rÙ5›x£6óÿ©W‡l‘í%['<䃎kJJK‘Ê슊ÏFÈócEñö½, }*·’¦$“Í$7/b{œzW m|Júæ«§Ãks¶*°ÎDn#)8 @Ã(?•{÷Š[“η±™ *TŽNy<Œt­?úΪ˜´oj÷zš5ŽÚé|ͰÿfÜx8Íw ¾ ÅñÎòâm"öÞ"D1É!]‚GÊ6Žzä÷ô¨¼Câ? è~$“Ã6šH{èÞ9®ZG*¤² cê(¯Ý«ì»«Š“R«fµ}ˆ|G¡éº7€®n¼-,±\i­#Œ¡"åH§ïd`rF+„öZ‡…®f±Ñì­ïf¶xLq*¦Ñ"áxzîÛIJΒZ5¢Ãæ0'üÓÔ÷Íx'Æß¦nGÃûûˆu¯0 †š$,NËg@•ÅÉõº‘Xy¤ÿ¢Qx:rx¶¿·Ð¼g$¯ ÚÞ¦¢[8ẇíŽÑÊùBŒðéÆxé]§†ü)>‰ªÝ\ÚjšµÌ×pÌ2]HèÈ:1Á5ò§ƒ ýªumh¶˜æ6Ï›qsn$““Œ3ÓŠè¼_/í à­3ûkÄ¿´ëv"(¼¥ ìbñÞ°uUNU`Ûí{ž\ññtÜ£Ji.ö>žÑþèÉ“Kgbó‘VòéDë´ü¤.Iôª_¾|Z’ÞKÿxÓÃö‹æ%Á[¤ ±d—Ø}+â»;¿Ú_âl–Ð[jŒè¯¶’Cä9`3é]‰5¿ÚëÃúµÿŒo^ÄNcU‹c2–8!‰\àf½ x8ÒšSœ9½O>y„ªÁ¸ÂvòVýCâçÇŸ~¾¹ð§Šþ Új ¡6t<¸œÃÇL}Ó_?xÅ#ñ~¢Ú·‰µ›­Jí¸2ÜJÎÀz ö¯T›öcøÇâHÄZ\V:ÿÚ˜Ë,–wAÛq<’®3Æÿ>#|;Hdño†nl’u,ŽA#׊÷°Ï¹\y¼±3o™K—ÌâH¤ús ÜyäÐÏ5¹Ý ¬‡ ðzã¥{Ã/Ú{Æ„‘K§ÙkP¼"ÝRðgËAŸ»ÁÇʼc4f±©FoâFæÔ«U¢ïMØúÈÿÁB>"ZØCc¤è¶ö±Á¨²¡…GéNƒþ ñ¦†[Ëi â8ç#$ª{sÚ¾L'Ò—>•Îòü;VåüYÔ³LRwæüõ¬ŸðPωƒR‘­mó§`ˆã•”zdóüëÒ|û|¶«}mo¬Ÿ³Ç<« Ü2T±ã>ݸ¯€ÃSÕ™HŒU”äØö¨žYEü3Zy¾"/ß³^‡í†~!iºÝº2^ªÌT­Çåšë-ïÙ“ÆêOZüªøOûHø‚²ðþ¹+Ésy·kÕ€è{ž:þ•÷oÀÏŠºOŒ´õ±–ýþß9Šg˜§··ç^UZR¥?g5ÿ÷èV§‰§í)½?#ܲ™VOZq<ñUíä“å8èNjÒAíÓ5‹F€pÁ¥*9àRÇN)ÁsÁ=iÒ„ýÓŒtÍ4(<°÷©†1ŠM‹éÛ‘ë@ ÎBŒ~Tó+pÔÅP„Njhe>6ñëFèb‘³Í)ÏrEXàR㯵1*9UK“À÷¥ddx cò®;žƒÄ¶’YÞ4¾S™VBJÓÕ!ð­Ê]Ü£•¼‚pO˜3•`¬9QÈ'é_`øÛö„ð“_¿Ú6üh´ñ†¡¨è–ÞÑÝaso§ Êd(§ªaöàûƒ^® ÚJw<ÌÎT£K–o^‡ŽÞØÝéó/!1¸þÀàväUldS¤’It’3ŸV9¦×®|Ø›M%:zn3KŽqN¢€‚)q‘KÞ–€Š1Jh Á¤Å>Šh¼úÒÑHA»èç–E+#ŽŒ§SïF)€âå²Ä’O9=飚T;1PØ9Áèhc–-´ œàt‚ÂsAÈ£8ëK@Æœš6Ó©9Í0A¥ÛN¢€Š1ž”¦Š@!_J6Ó¨¦qÎ(Á§RLQÐu§c=)vãšq½95-µ­ÕäžU¬ +ÿuy'œt«Ú…s®ßÇe Ȫç "Ç»oá^ñà‡š‚¡mcS‘d’H‰ t0ªG'Æ·5ÁÇÓÁ«=eјLLSºÒ=YÂx_öyñïˆ'S}m›l@c$ÎG¹õï]•çÀ/‡žæñWŽ—)‚DjF=@éžõ™ãÿšƒѼ) Ž$ù~Ð ÈãœWjz毬Úž¡5Î:l× (f8ËN¤½œ{-ÎÊ•08_vç—w±éºÅßìñbÅ,´Ý^ùãàÉEÌŠÈ>ø}§HeÑ~ÄNݠݰ|ƒžþ•ç\RW|pJÒ”Ÿ¬™Ç,läïÅz$z#|qñ…¼ i¢4È!j“œ:d׬ëÚLjnþݬßËu60F'Ú¨N IÀ'[QÂТïN)3˜šµtœ›DgšOƯÞi7ö(îÙ£Žj ÙÍm)«ÅÝI8»43 OØp[s@^j‰¸ÌZ°`Ž8"™Š·™»å ÈÇ­>ÎÆâúá-m£Ý#œ(õ®†?‡>)eÞtâAÈnŸ¥aWF‹µI¥ó6¥F­UxE³” IÅM ¥Äî$‘@ªI®¨|?ñ«©{XÕ‰È Ù­ïXê63…–XÅòï ‚õõ®Ì]Ù˜‘ì t+­C •Np21ùœÔ—šþ”#C ¦éãN;šâžk^r»¨Î˜`pp¹?x~'å¹¹=ÀR«œTñxsE·E$†vN>µ§yªÌîÌ-aˆ7l“Ï·5‹|Ó^3-Åø°Øß€äU—Ãu6vcŠCÞ €+RÓZЬghnf2ËòÅ‹‘ô®BÖÚBóÞÎHÁÆî3ZY[I%ù-Üþ5“”©M¹+#¯-à YKݨ—ª¼CpÏ×ë[–º'‚%³SÙ‚ G+Íe¾Ñ´–2^1VS³lcqªÒøªægh:=ÄÑ“óO"œ/ÑG_Ϊ8zÕUâ´óÑJ½ oÞzùjÎÃÄ^ÑBŸ³\ÛªÀ+É<_¦i6qË*MNλmœŒc‘Ø…t·žñmúý¤ê­ Èe×`#ç5ƒâ? j¯%²Å¦[C,…²#vnžäšôrøBTÝUòûõ¿ùn9έ6•'óÿ€pû:Rlö®¶†Þ%š?0E?Ý/Uîü â;5i&³Pˆ2X7¯¢XÜ4Ÿ*šûÏ á1WpqSÁúͧ‡(üAÝâ½Að0LÇúÓ!ð.³=šÞGåêw$j›øO^FÚÚ{çþU„qGt¤´ô4qÆ-_6¾¥=W]ÖµÛƒsªêSÜÈØæG'§Jm¶¯¬X§—gª]@¤cÊÊ?JKÍ6òÅö]Û¼gÜUjé,ãxêŽYJj^õîméž4ñfp—V> ½I8ÌÌGåšßƒâÿÄCçJÞ/º‰•AEÜØcž€•ÃsÞœ Ÿ¼¶)J”%º*8бÚOïgÔ¿~#Éâ­1ìuïÏ&«¿ %—iîóÈú׳éž4µÐä{[›¦¸|nÛ'>Þµùù¥j—š=ü:–Ÿ1†xz0õþµèWˆìµÍJ×H²JÞ13·  1÷ò+S¬þÃû^"‡ó¯¼ö˜´½"í2m^?uÈÁ¥ «-5£¸q^+í±ð eòLjîFA;¾Î6ÿ:ÚÒ¿k€ºÔ^t^:·µ9Û‹‚#o®2j½uöX–&‹Úkï=9¼)¨Æ8ºŽLõƱu?Ä:aft’ î…ƒ~™ÍRÓ>1|<–Í®ô— 6<£4ÈÊl?tZGŽb¼šö{%PY"Ÿr¿¾;~f§žqø‘¬d¥¶¦&›â @`OÄ@uY®?:ë4fi@f ªØæëV ¸Ó¯—Îòá™ø†5£ke£J@6Šž˜8£Ú'²)ŠÍ®¥ó8aÏÍSÇjÊ1ž+E4[ULÃ;¯¦O C4.ÈÜ î{ÕnAL[K$§*Ãñâ¶-ámʽ:v^Ì9f\eAÉ&µmaÞ ÇžHîj[î)nH$œÓ%TŒï$d µ$¨„¿x àõª7 Ü žâ–à0ÌrzþTUf˜îÎzúÑGÈv>hñ—í±ðoÂþ-¸ð}ÕõõÄÐ\}žââ V1DàŒä‘“‚{ÐצI­Y_ÚE}e/ À2º žGé_“ß¼UkãŸk~0±Ó³áÕnÂ[ïÝåä×9#=;Õ­;âïÄÍ&ÄišwŒõm—8Œ8 g¯$f½yå|Ñ‹ƒ³ës§rÎJ¢ºécôò÷YU*­¸(Þpõõ¬-sâG‡ˆ† À™vo•IdëÊàŽy¤µðÎ¥§mkÚ"¤e— ãë\51¸%¥6ÛùôpØù4êò¥ó?F"ñz¯%ž§ ©Ë'ï1°ã¿µHڲəÑ:$nü1Ö¾Ó|kã­ I¥¶ÔîIºØ³¯H«ÐtãŽ+Dø»ñÃ÷w¦H%ÎËi×tižxÆÁbiïs»êóè´/¼Gc¤ØM¨_ܬV¶±³ÌØ'j’pOJ§£üTð>­§ÁªÚx«K6·#÷r½Â céó`çÛ­|ÁoñóÇörÃu§i×V÷(ë%»Äß2žnŸx¶»à‰®™n<=ö«+wrÑÚ K¬ožHéŽÕ¥:øGmS”äÆC‡JTá̽l~“Íâ­ O„OªjövƒÖ{…AúšàõßÚCá…3Aqã}>GFÚâ&iqïò |¨ø↢;›FðÂpÈò¿ZÀ›á¿‰áÏÚlºs]Tã—ÉsJºùÁ<ª˜Übv…ó>ï»ý¯>E(Š?Èä»ÒÆ|ÿ|Wj_·oƒmînÓLðž¯rŠÁ+yh®8ä‚ù¯l×Ç×^Õ¬›lú|Êsºjœ¶“@{ §Ôb½JY~zÆ\ß?ò<ê¹¶2:5Ëòÿ3êýºµ¨µ5·…„VŒ4^næéÁ8ˆÿn^þêÒ}Ãò[¬ Už@|Ð#‚qøWÌãOŽÙå;c‰˜û èynw™fø·¢—à ï¿mÿ‰ÒÈçOÓôûhUJ2ùùäŽãŠñ¿üGñW­b±×5¸¶¶žIàI»F\ò¡;}JÅ‹L¼•Äik&Oµi'„uB2ȪOaÉö£—†i»&'[Š‹¼Ñ„«š×ðËèëvÓx€ËöÜ3ˆ×q8éÇ¥jèþ¹¼Ža~²@ØÛ;7©•{ êVölöβ±xáèj–/ˆs£ê–¶ý—Õ«Ðå¬á¥ô¿êªüâx­¾ÃáÝb7tMÍ ˆ«…ä:}+¥ÔF¦Î߈, ” b­p¨Èž¤+ã˜íµÿ kǧÜKë( ðœpÝE[Ô<7㩃jú~£ aÌ­¹²?¾V\1†^u[Ý{msëèqV*•'BòO]ì}O«üDøu¤[]XÃâË).nªynζr‚29è{ÔzMÕ¼6ékk­â¥dw› òdçé_¼R#bEe`{Œ^çð›ÇÞ-ñ> ,./tED"Qs8Çpyè2k\Ç  T‹r²¾&–"»†":½ºžßaê3[[Á~¬»ÙʲŽ: ã‘ZzÞ±­Þjr\éW3 D"hä`í·Ž÷ükFDdŽký)7DQY` úçœVö¯ãHnÊHöhŠXíFSÐÈo©éÞ¾eÁÁZ3G×)©ÊòƒûQ¾ñ^¥©höš}æ·"ûn–ÊÁ!ùNŸvaèªlu"»rSUµ™´Ä²¿‚h].9r8ÉéÖ¼1ô[‹H„v¶ò¤¶ä¢¤@ï žF\W=wñóGœYEwy(J°ð®2)*Ug>h#^hB>ó= Bøuâ2§OÖ¤‚á£Óo~Ìp,§ ¤ðÀgý‘^à­ ÒãLÔ´?êZãZË”©qy,ÎÄŽv²39õ¯šo2É,°¹•íØÌ±¼s1`£ûÙ=«ÐŒñ1÷ítpºt&ù[±ÙxŸöVøbˆ–ºN£2À±í…fye9%‹—j€AÜÃÚ¼ÓÄÿ±¿ŒìÛÍ𖵦ë«@fMå·aGç_Qé>/ø{&¡i êZ‡–³ÆÑË|¸1‰p}3“]Š M+ìÓèÍkªéò2slÛ%` 0,yÂ’¼ñßµ{s{8ÀÒÀÎ*“zÜQ•;•ˆ#¸í_@|½Ÿìë²x¦×L¹±™€aq¶vNæ’'N8Ïà#½v |™¨`2G*¤ŽH®[ÄzÍÝŠ2 îê¿;B鑟bÃ5ÑÜJŸ+íšó¯OãØdCk£-ݰpXAåy8öíÍ íØç~7Õ|3«=͵ÍÅΙ(@ï!•#S´ýâFÞjó3¦Øxq/Žƒ}i«ØFåå†HÃ29PIWœqÓ5ê~7ðwŒ¼{ ]iÒYÙi¶×–²{̼±¹c‚¾ÜׯIኳ~£wsy«é¾"Òî‘^tk¢¤•Ï sƒÍwR§)ÁÆ/^ÆU±*ƒ‹”nŸ^ß#Í>8ø«QÕ5G²O^hö©+)3E´Ê@ànþ!ƒž}kÉdõ¯Qø«ñ’O‰VI§Ë Cd-îÚxäY7¶Â¸Úxç¿¥y‘N {t"ãM&¬|¦2ª«YÉK™w؇â€)á9£f jsó ã¥-;i£oÆõÎJ1V#žhá’ÈU‘v¿$dè:T8çŠ5 ŒüixéJH  ÒÄ"Œ \ â~”\.­ž3KFßj.+‰zL{Ó±íF3ÚÜm§í§,tÅr<{ÑzѰѯµ)DVv²HHÎ@8ÖºÈ> |A¹¹û%¿‡nd›æÂªœcøêYʬ!¤ä‘q§R¦°Mœ&ÊO/Ž+ßcý•‡øo'…´½;u¿‚[ £ÌòÆÍÜñÓú×ñ·_Ö¯o`´W™tÍž¼;ûþçZv¯¦\ ‹YHuéZwþ6Öu( µ÷“$d†Oþ½|ô2¬F± Ó^{žäó*5°®ƒ¼_‘Í0 õâŒf­~æâá7(†2@m¼€=jäš#HàiÓ-Ú1Âíá¿*÷gZiOOËïØñ£NSÖ:ÿ]Œ}¾ô»kVMVˆ3Nœcýš¦Ð¼D¬‘•>„UFpŸÂïó”ãñ+Co4î#‚'‘ð¢’Jô¿x0Ee%æ¯d¾tç’¨%T{v$ÿJç¾Ë4ZÐuòÄ Ìźã ~5êÍ|–¹{‚ ܼõóùÞ>t_Õã¥úþ‡½“a)T_X¨öèsº·‡´{xž{ÛH”K¯:H›YÔ®$Ñ"òàFùI;p+Õ'Ö­µHŠ}Ÿ=‚·9÷® LK¹|kã ¼'y äz…¥Ò<±²° Бô®šÇǾ%±…àÕ­Ú ¬œþɪéeV;q‘×¥G5ОO=ÑŠíÜC!ìU.d,ÈXŽqÔŠ}”L yžC¶>Aö¯²’“^gg;š¹z;çEGÍÐc½&Ǹ‘ZGÚëü9Å[Òô–¼·eÒ(z‡cÖ·´ï ‹àZäô pk'+ Ýf`Ãýc¯< V|„’Àr¹ÉÉÅw‡€æ]¤ ƨ/çÀ.dXÛ‚Å9úâˆ4L¹“µŽ>Ww8ëǵB« vàžÝ«­>i$Ìw.TgwËQÅáH" ”šb¹ã8®•.Uk yœ¶gbDà¬Ç5~ÓûVeXÒLÁLãõvå ‚È(QÃ`óÞ¥ÒḒPR\nààgùšWF|Ö•‡:ÞÈ:陘î"5?­_’æÑá n“9=x«:TïnÊ÷»¿ ½µ»$!‘õ¢Sœ•ѧ´ävHÁÔvÒ {¨e±ÇAŽ3Wî-íî K×pQzsÍfks›ËY¬ ì¸Ã:W<÷ú˜¶Q3:¢pTñŠj£ûFÄéiÌfئa`ŒR•’ä1Ï—Þ$ð+–µÖÍ´"'!†{v£ûNä)µ¶˜âs¬xÏ_éG´»ØÙâ"ÖÇCu¦ÛÊ›gû?–¤oAÝPO¢xn+a,-j<Ôû‚-ÙöàV\Zv£<+3Hc–EÜbÉ'n:þ•%¾™wlñ\Ëpª‘à¸àñÇsV«Î:#šR§=yGZ u°™UzqÓӎª^\_Ãt†xÊÄç‘Üô­ GÅÆâÜ[Áù˜ÚÒ€lb«éú^»âKwÈ@AQ·8¹¨U\]Ù*Rµ®axÍœi“Göy$ Þ€`}{×™yyû½M}Woð¼êÖÆòäåTŒ`¥y׌¾hº«æÃ Bƽ¼·:¡„ƒ§4ûèy˜ü¾®&j¢v<¦ïÃz½¤1M%«²Ê»¾A»o±ÇJdÖîṠM˜¨îWüëÚ,t)>Ê/.Ž,dîp1úæšd·˜c ß+/JÑq%D¾r?±©7¤Ý_k- ‹û>`ÍЃ[š…¡»2G¨ÛO °0Ý’FãÏNǵzdZ6¡ræD•ÎzŽãÂú¤Q™žx€Î6“ƒšÎ¿T«H®WÝ\ÖŽSF””¤î»3øcK ·UÀà*…Ï„´é‰-²ƒ–5×Zé÷jÌ.ãȃëW>Ãlï·v<Šà†>ªÚ£ûÏMáhT_ û=‡¶R…1I$Y듚ÍÕ<€/ '€ÍzV¡kmÞÎÛWФÖwƒ{)n›>jéY¶&•œ¦Ú9ªå¸k?u\ñû­.öÙÙd·“j“óm8#Ö«ùy¯_Ô4"°nŒ ÀœŠË‹ÂZY µŠnOÌx¯NQk÷±×ÈñªåO÷rÓÌó?/Þ“ËÇzöh´ Q›îù¨çÑtVI¦ÂËùb©ñ-þøÉê2©Zqqc2vù–«›iCm16OlVêp’ºf-InŽÆŒž0œZ ºb‹ lŒ_º`ùx8ï@øÕñc¦ºDK‘ø×-&y &y#  dÜ´ôk>&‚ItÁ 1œlwÁ†¾ÿ‚xŠº»{‚ðf¡‘p·sh§S÷áÏb;×Üú·Ã?ø‚ù¯5=4ݼ¸fc;cò¼›Y×§ÔM2x§G×/¦“«ÚÜ0 Å"18ïÍvÖŠ"b˜Ì3ןzçü7à/xjûûCBÑb´º °º³Ä×Gwp¢– ëι”¤×¼tË–þéRîê™2'æcÝܬ,™É<‘Ò¾IÖ¿à¡Zo†¾+ë> ñ_‚®­42õ¬Òå%ÌÀ«gt+‚$GÍnë·§À˜íe¹³Ô¯î8-¸ Ä÷wJìXJÊÞëÔäXì;ºçZAÉ©F®@—òÅò¯û}ü3´¹EÓe“‘¡íã9}Ÿ½S“ÎçÊ`ܽ§»OŸÈúÂÿ¼£C¨Í§Ç"i¶àïWxÉ÷ÉÈéÒ½+Â:gÃÍ6 «é.ìæ¸””?d‘P&ìmÝ·®kå«)¼kát¸¶µÝGrJ¬œãƒ]ÆâO_èÈ—óR µ·Có–þ"r8ëãñ['VSS{ëøŸaƒÅÚÔT%ÚÚ}ûBü6³žx[Z+äKå™>ÌÌ­‘r=ûúVf³¡xXÆ_N¾’áÆTªÛ2 '•y¼šÍÄl‘ÛÛ\†ŸlòJXc |Üc×ô«Px¯T·e‹Wµ‰7¼Øàjñ樧ËÊR3œ•Û=N‚–ßÙ–ÚŽ­wocæÌ’£EÇÓ=k9þhxútš…¤‚5óŒÄLg#=+ƒOŠþ)Õ.R ® Äd4F&ÏÌØÇ_ÀTgÇ>)0[ÛZZ¼‰çùœÖS¥†”cø‚©R/F{n‰ðGÁ6è·Òx‹Ià ‘6öØ “ÃðãïIã½»máM©z‘ŽxäWœÛxÁ¡û>ésÂ.lµXây »þP¹ãÒ¹‰4…ðÅú錑Ha8/púŠõM*:ö«»Á,G#gdÿ¬Mrž9ÑßûQîÒHJòªõ#­vÿib«%J¬ÛFðØz2ç„e!´»•®n¥U@€oj·åÚÂŒÐÈ ç5ÏÇ äJH£ÏqÁ«&ónŽ 0ÊOÔ¹9=ΨÔIjnZꮤ–Uv‚Wc?Ö§ ™º‰¯(Ywöô®u/äILÑÆ>cÒ´mo%.ò21ÀÎÃ÷}ÿJÒ)§Øj¢kTuº&•áõ™ofŠÕ¤«„S^“á­~Î8ÚtÇ ¿‚1ÓŸZðK¯Xé1ͽÔÈHEà‚GzĽøÑuùZEƒ$#øe~AüuÐÊñ˜µzqºïs)fØl½ù[ËSÚ¼{¥x+U°‘îü?`×%¶FÑ[®üg©Ú3^Qÿ ç±ȳ”¼³pß)VtÛî .•ñ.„]jzÔḩtQÂr?Þ'úW[¤xš^Æ&KÜã*f`XŒúcŒÖµ%˜eê×imÖ߉.¦ 0i¸Å¿Mϼmž— ºF¯«‰£ Å<²!oRr@4ËO‰ ¶qÁui©™5^ a˜c“Í{Ò£e»ÓbŽàÜ 9ô¥Ñ.çùâŒ"Ày`bª• ”•Ñz2ã™ $õù*¹­ø‡ÃrxNâÖ÷ÆM#G ‚sgv ’ë„Fäv¾fÓ­­¼°äghϧ­ZitË{”ýó±ÀÝŽ€ûúò*ÿ´’Ó”Ö8eÌÙ4±G ×w~vCéó\&æe݆ݳ8#Ò½³Sñ׃´ Ÿ?‰æžab‘<668i¸ÚH!B† c9â¾ñÝ´¡!†vÂ’U?…sלÕý"âæöÚ9µ%f•_åtÂÓ=ë*xÅ»-^ĺ3­$›Ñ e=Ô:ýÖ´ÒKgnn%’Îåä†7 [Ÿ›uí]“m©xZ_é¶ôl^Te Ùˆ©C$6ŽÓº¤‘“‚­ÈøkZOGz‹:!%÷pk–uª·tõ;#B,NÇá§Ä/êÞ(GÔ–k»HÑ®®]Ô@Aaî7cNÕßëž.Ó5½/VÐa_6éUìîb|¯”Y~mÇØÈãÒ¼*=STÒâ—VÒµŠXFq¾Þ£5È_|CÕ-5DÔõ+ã%õÜ›^elafP9þ|õ®¼>.NŸ"W‘ÉS £.g¤NâËÁºÎta𫸠¦)w©{q^yqà¿|BÔîüŒztÐΗSMr;ÇLqËd“ÏJÜÒü¯É|òèK5ÔsoŽØ ÆYW%H$öî=+nÔxË]ñ-¼Þ#ñ^¥ÿeË÷vè@ŸÊ=·zã¨ÁÅiƒ‹…G;XX‰FqQ#ñŸì½¤xkÁÚ~´¹ÔüEnQ]7‚³nà•V8Ï景|)M?á6޾(Xt=JÆŽÖ4%å0¹ÉI<¬ïn²s€zŠïu_^²i^EÔ&·ž;r’Iå·'†ÝÓÚ¸‰Ÿ¼5«YiÖƒE¸¾0±ºDy…¼‹ÁCƒµÃ½Øt¯Nó©§S‹•A]ìyu¥¦¿%åŦŸ<Ñ®™µ&c%$ˆ÷Ø^HõÎ+¯žûÅ^žÇûjãÌ·ÔEìRŒí8axõÁÁÀé]ÏÀ™tIü5­øÒëI^Ÿ<¢2&&I›o9f ¿0ÇÊ+“ñïˆOŒ5c¥ieÑ-Ý HØÂ°.0'&¸±á7WGú›R­$ÒZ¦u×îínçœUdÃ嘀wÚêZWŒ|i{h©¯bѤW”@ådÛÞ0F1ùô5áqéÃM³M^ÏSnUä_²¹?.ÞÃI~u·¦ü^ñ‡­¢iÆÄ’›z±k‚›­E¨ÅÝ>‡£%F´\­fºÕ´Ÿ>ë÷²\ÝjúÞŸIoi)%eqóçhÆpqÃzWeð»ÇŸ5½:ñümá.D˜›YmZ6Yàòž£'§½¿j¿üBº ø£H³FxÞ"û°Üpr§×¯ZèÓË­ê’Ýø_\–ÖÞÛÎò¦818$, î¨òsÀ¯g5k>—*ÿjÞêˆÑÇáÉm  Îæéÿ¼G¾?<ûWÆ¿´ï†¼áÏ[Åá/Ý_]'Úoà,ä®õR­“òóÉàç&¾àƒWI/ÛG‘ÞåãE7¶F»À'9é_'þÛ~Òl5ïø‚Ò6ŽïP·šÞàd`¬E6>ŽGå]ÙKK›ÖÿÓ<ìé_'e¥¿>žgÌØ©m®.læ[‹K‰!•y#ñÁšq¯¯²{Ÿv¶=F‰Ÿ¬VËPñV¡’dÍ<žS6ýÑN8é^¿û:xJÒ¼w¤XÞøÒã‚ðÍ ‘wÌ@Ú€ò:œt©>é~*ñ¿‚¬´Ï øsC½kHöò¸ubY€èx?vºÃoiº¨†‡©·s+¥¸8ž§$}kãñ¸Êꤩ¨Ú)ì¼·Ààèû(ÖRnmnßsîí xƒ\íãælÖìAHÈä×3àùnn4»K‰ížšsòÑ’£ƒï]Dc‚@«ó6c€#׊“Í;EFòªN Bžôƒ­SŸPH·R2@­sÏñDŠG†i n‡ ¼€¯4rÜ,uláy,õ®+â?Ä­?áæ7ˆ5;ûe·¶Þ6™U˜œ ‘Íy¿Å_ÚïáŸÃ‹B·×†âõÉÛÂAcŽÿN+ó¿ã×íâ?ŒºÜ‡ÍšÏGS˜í<̇lŸ¸Jé¡‚©]ö]Î,V:–/[˱÷ ïü7áöL:¥Œ—R—8’Ù e• .+†ñoüÃÃЄ<}u'üõ¸Ú‘þœúv¯Ï®ý(Àô¯V9mõÔñ%›â$’V_#éþÞŸÜRí"¥Á¥ÛëO”W! [ŠxŒµ QÛìÞšBr¬x =Äq)#‚I8=øÍz‡€¾¿Žm£±Ò<5«Ý\ÜHU.c@!O—å,I¯Šè¾|Ò¼k:ë5ºº·±VÌVðÆ ËƒÉ$ôZú×B¶ðŸÁøŸNÒL·&ók• 0£à×Ïf™¼h?gIÞHú,³)•eík/uýç?ðóöx°Ð|=Ôµîu9$ˆäùk/–qŽ•Î^øƒNš-¤í’^üö¯;Õõâ×( <9(]N =Gj~•ö†Q4ƒ‚TŽIü;v®fÔyš7SŒô¾¦þ¬¨~áµ'€ä(ÇœVqÑ ˜Ü®.8;‡-êG­2y.®eȈ£“wv…\µ–x"ó m<{×e:íÂÉ“‹æv3ŽýòçÌ·DèÛÛcm޽j¯…4Ùo®n.l"™"Ê3y@¨=1ÓÑ}¬j7p½³YB3!× ýkãĽš*‹6’%9‘¢r7óÁ*sÏãÚ½J›øtoÎÇgk5ués~_‡¾¾iCX$g8>B?*åuÏ„—/Ÿ¢]‰<Å)ÁëWí¾#i²œË#ÄIË#‡ë[zo‹t‡S'öœeÌC61]*¾aƒ•í+yêŽg–㗚ўE©øk\ѹÔtÉ¢RN{ŠÍ 3É⽇Ä~:ðûZÉkíFIT¯–½9µæ£ÃZ¤–ßká“…'+ßÁæ.tù±iCµô¿ß©ácp0¥S— .uù~††‰à´×ìÚö R+dRA\cß§ëXš®—.“tm%–qÈx¤¤zäë´+9ntfÓõ1åG»lax<¦ OƳ,xÒ.AÆ;zä†m 5¦«TÑl­ÅO-•J0•j÷wý :n§®\iƒHÓ´e‘q´¸„õ$Š>ë&>æHaÜ mÎOÓŠô›o ”cÈXÙX‚ê0MUÕÞIaev ÁBõ¯\BâßÕà£wësÒ†QE:òr¶Ýæá°Ñm”ÉrÉ'å÷«6¹¹„É=À‰ñ•]¤ó]~“lŒæYbߌչ/m×(Œp88 æŸãRpƒù—ý‘A»´r‡c›É›ÌFû¼€E3Mð½å¾ óC)ÑþP­€WÜ×gDåv’KôÁäÔ±º3£„¼ÀòAõ5Ï,ï5%)_˜Ò9e´ã„µÔ5 TŠÊêÁÎÝÀqÏztÞ¶ÔwÏ,brIÀ“žÝjö¥ßêW,m¹1™[…AÜÖ’ë‹9–MBEùzl@ß^sÒ¼ºs¨¥ÍNV;½Šš´ö9o|‚ÒÈ\Gp–³H>â¹*{â²t˜5[{7Óuk¤Åû¸r¼ªŽù<ó]n·ñãT‰aû j¨’y®u¤ži–w ÏÞéé^³Ìq5©û Žë»Ý|ÎYa(Ò©ÏIYùl6k›{p–­_âPqùׯ*èú¢^X]Ê—3eÜÿt:×O©êZŒ®öºr™c,s·?ΰ,ô‚—¢òþo´89*G5éå¾Ï¥^¼Õšk–÷¹çc9«Ú5­Ö»XÓ‘%hãºMNîFd ‘†3ÓŒÔV3ê’K,ÍpÏååXü²»mßcm‘©$P–Þ]7Mqx8`°ß…uºMæ£o*Êñù¶9;@ϰiu*,6ò„P2¡GaZ\êú„Iq#´dròv`yÀüª]N`“Ðôo¤¸€íS½GÓwÕÆÔ-ä¶M»s·°è=>¢¹ë#8‚[«+64ûÑŸ¼ì= h4qÍo6Öf ¤t|ŽþÆke”ä÷$-YgŒµ‰«Å ­«mtpÅsŒjÚ3sÕ³95k4yž«ô.9?tŸNôù|o([Òd2ªòÓ}y>™¦æú˜*iê‡èºLWq¬bᜱÚ'ŠMÀ7¿9ÅE©Øé³XÜéú•Üv׎Q™º·£ vÆ+gÃ>–9£ºµœ(à4D~¿ZêµØëšl«sóJÿ¬A¤›LÙRæÒŸ{ù{}.#]“|¾Z°'*çïµxoš(JÇïHFO«ºžiYAÑ”Ÿ/n†rÃÑSUœ}îç(–3y*÷2.åÆ@óLÐ,¤2Èί“¸¨8ééíTŠlΤ—´I$õôüNÛY»´µÒŒÉ${ÝÉØ¤ÈèúW+WÈ.fPÑ–ÎÆ*Hà`ô¨gžmbàÏ>\IµAÈ¿Ž+sMÓ- ‹íWìÌ#c&{ŸÔñ_;ìô[žÅܵ$ƒÄ6¶e¡]'gMªì Hë‘Þ¥´×|J»¿³vÆpX…rlÕ[Hï®T¥–Œ7?*îI(;0+³ðW‚î5_³Í­·´,VI±–-Óõý+hSö…¤Ò»9IµmcPß5í ¿’'sëàp:=*Í–£â=!eÑõ9 ‹ŒÀzó^ïj_ | okáß”ÕoîOÌLb4Œ·V'¿§J¹£êgLÓ…Ìv/5žJq*3ÔžzñC‚‹³èTeÍðžk§xžÛQ•µí-`bªXÕ_§¸Î}ëEð>‰3=ý¼­r9wçÌ ö89•Òßêõ µ:‡…íãÝ€mÈÜqÃ}A4–^Yàk\ÝÚ¡ŒH°Î¹Gð?S8FÛÝ 7xÉÔ¼uá¸ãÔ!šÈFï1#Ã2“Ѱ½jXî´‹Õ’).Q\òÊ˰“zŠæó^°y¬ä¢T+¿ržÕ‹om<Ò»©F$äŒdƒÓñW3‚NÑ)¥öM+­O’Bž\/¨ÁëëÅfGá=+–¼_)¤lW·4]Iqh~Ï'ž¡Î cÆ–4ˆÐ³Æ›Ô:‰A=Ë1hzFÏ(ÛDq´pIÏ8ëToü ¤5š´°DYòN8 “žÕqm¦—h`8ç?hØÝ™ÉÀdÆǽidµE¸Çª8 ‡z“¾Öñ­¥*»²?×1«iºÞ‘¸Fñ/ø‘‡Î¹éŽüšöøìmu‘œd±P¬1É+\ðÂܳÊ0ÜÊŠx8\Ö±¾æNž—G‘ÛÅ|,¤ˆ’$‹°`î¾=+œÓ¼"Õg’þu4À²›•ùW=ðz×{{m…ï áß ¿—${¸,NT§ ÷V¯rUUä|ä9ç úV´±µðÊJ“·1ÍW J³Nª½Œë/éúV’l­¾Ëq<Ÿ8D­ß$tâŸcvm]ÕãÉUaÆ3ÔJ·<·¶êKÙ:D@ù¶äÖ%ð.Vå2z‘Q:õ+¶êJí—B’Q‚µŽïMÕ,îEpƒÍ#*Xgéô­D¹™‘qrçÊùxàc5æÖºƒÂûZTÊ੨ÿõ×Q¡ëQ…a;¨d¶zzV¦ÓÔÙ;és«†XøHÉp¿eêM0hã\9mÍÓ§AYxûN’`–uÕØŒqý+¥Ñ¤‡S¶k³j`fäÇ'ÞQÇëN½ÐÖª².”£[ønö1#·u&?/æÏZŠêÙ§¹ŽÑçS+¶6¨ãÍtÙJò“Ÿ(©õëÖ¶4=/N³Ûu~ÊÒžrFrOO¹jUTõFð›‰^ÓÂz}Žšv+\üª<Æ_”A\N°-tó#ýšId ª~˜Çc]ýíö«4öú}¬q 9¥-0ÉÈSÇ}¦i gwQ»•™0„õ<ÿZÎŒÛW˜Þ"]çÓ^BÉ!UNÇ °ÏcK§x’[lAÉPÌU—¯ùï[é Úsvö¦,K؉Î9ù¾xü«0GcË–ÓÄM¿hSÉèÆº •í`§VkVié³´‹æMvŽ:­–Ç­tZF©á?U©8Ú#o/pOsëÔàWš^êV>;ï1 Jí÷OÌùÁãò5ÅøÃÆßN‹ \\,[X9 œã§ë^¾ )¯Žšäºs fsCMû[9v[žÏâ‹¿ é:$Íc«¶¶ß)q#;€äôÉý+‹øD-õ­C[ñ¯Úàeû¼mɈœ7™ŽØ|šñ纺u(÷22¶Ž:WKá/jÕ­îÞ!5”dy¶¨v @RN }'ö L6¢¤ùªIo·ÝæÏ›—RÅâiº‘å§‹[½®ü—cÙu=ÖÆÊÞ=7ÄM½R’ §a…¸däò¹=>µÇø÷\×|9yÖ±§éWú¥Ø{•¾µ`ÈU˜¬ƒ€:ŒÜ×/¬øƒÄ5¹…š%¬ó#·|©Ž[ž½ª£ø£Ä>’M)¯moG”b`éæ<ëÎk<[V“Pªã)nãÕÛËþ¬foNªs£Íì¥Ñëü¬ÓÒ~+Ç¥ëzÌ^±I®<öAàFÏÂcÐ(,1ß<×SàÿÚÚBuÔ›AóLJÞæÖJIÈ)çœqίdây#;\ðq€k Õ¯´ÆÔ´ ]9);ö°<• ¦ zx¼¶„â”#ï§Ý©æá3ŒTdÜýõmµûô=cÅ?´6­®iz,­e¤¹IÝTn\| `p·­Iá-kÚ¶×z\¬5“k#0ŽoóšðSgtFÖÒ†'h_J[UÐîH{IGPAS\x®§^±¨ùº_c« Äu)Uç©Mrõ¶ÿyï>еÛ)d¼Ôt²Ö›™”u½:šõ áÞ‰ãXm ¾)%»1òö?17¾:uï^CàÿŽ:v—¦¤Z‚Ë(DX¤ó˜;ŽOq^›öKo[Câ…ž0‹LÔ&±^0òf ðC”<ÍøWÊVÀâ)Ö娹5ß[}çÙQ̰ӣÍIóév´¿Üp¾!ý“üoá«ÝOÅ>Ô x4âÓ‡ DŠ3Û¿<ׯü?Ö®|e§½¦•âq’öïv‚V†e–0¹p£+a”ö9¬wý¤¯¼)}6…ñÃ’iwW*LÈÞe¼ËžNQŸÒ¾sø‰ñ C^𳨣ïÜÀåLêHÆGnƒ>õîá°8œKQ¨¬ûô<Fe…ÂÅΛ¿—_øÕÿ>/xkág†%ŠÂt¹Ôå –pî2â`å8PCï_üEø™âŸ‰ú¬¯‰î–Gµ‹É‚4P«ç'{÷ë\ýÖ£}z¡o.æ˜)ÈÞû±ÀÈ ¨H¯£ÁeðÂ{ÏYw>c0Í*cŸ*Ò=ƒ a<ñKŸ^k¼òìw þ"x“À'´¸Ðõ!ŠâeŠâ=ûUÑŽÖÉìpO=«ë|[ÔôÏéºÛ Z{ÞLŠ'’H|²Çw pxÁ^üWÂåNrké¿Ù«ãM¥´VŸüI¦E¨0”=ä` 7eoU÷ï^.m†“J½5¶ÿæ}KŒP“ÃÔz=¿Èý:Ñæ†úÚ Ëg&9H¤‚ ddv­¨øŠçü#m¢XÞG4 e…¼£”ì:WD˜¯.öG¼Äq‘šç|U~Úm‘•. †W8ŒÌp„ŽpOÒ·o®ÒÎÖ[—Ve‰ £’|qûI~Ôh¤v¬&ÎW‹È‘2òHž3î9÷¢*RiE]‰Ê0NSvHò_Žß¶_Œ´Ïjðäocw§È#7N9V  # ‚;œŠùçVý >-ë7s}ã ²ÏBag®àWâM~óĺÕî½~ˆ./e2ɰar}+/q5ô”p´éÅ]j|Ž'^´ÛRvéÓBÍþ¡y¨Ý˨]Kss3’Y³1=É5X¹Í'9¤Ç¥tÜâëv.æè)G=ièi@¡ ’( Óðþ±u êK¨ÙÝ=¼È¥VDPYsÝsÐûÖ`Í€ÚMY‚“‹º>øaymñF¹´ñGˆïõ y¥0Éä*ÂÜù÷Î+ݼ/àÿ‡Úp²±ðüVæX¡ŽHa<Œã''ê+à›kd~M†¡4NJ¡À&½Ÿ´_|$žU¨³¸Sœ™£%³Ó ƒÇå^'.¯*ŽTß»ÛcèpyµA*±Õußþ ú%¦|7ð‡—̶pL‘°%ØrIaÏ=I®âÍÿÁ-/@¿Ò|Qâ}çʈ‡µ$²7}ªpp1ê+áüqø‡â›ï·O®\Z’>ä:b¸{›Ë»É{©ä–G;™‰$Ó¥”·g7oB«ç‘Ö4£uækøÊë÷Þ$½ºð­›Úé’HZ›øG· ¬29}úÒñ^ÜW*HùÉK™¹6Gæ¬íô¥šÎx•ZXYŒ©aŒŠMe,rqJ«ëS˜˜ âGŠ,Êæ#ÛJ Ô ;`ô¢ÄÜjóN Þ•#$€$öÛø3áŒüm4i¥i3”€¯å’ Èü‡#šš•aF<Õ‘t©T¯.ZjìâBäà “é]ç~ͨk6¿ð‘o°¶d3m‘Fç ÚyçëÜ4¿ØßÄV^‹_¿_³ÞÆÅ|¦)ÏGz×Ñ>>Ÿâ7kíT__·Ê“?^€WÎf9äU7 >þŸ‘ô’jjuÕ×oó:(u»kX­íô«G¶¶UP¨ÚùUÛ“Ž¿JÍÕuïµNw\Hòç«7?N•SÖm®mTŽësFNWn2{s\Íã#ÂeiK8n{ʾJ£÷ªsmÙõ»ù¬"ûDn’ ?€Toð®/Äz¤·Z\³KJ­“¹ˆR¿ex³ÇÐi0ˆÖêéxES…÷'Ðó^c©ø—X×e\ϲ7lykÂŒšöòÜ“‹Š©?v=ß_DyìÚ–ºiÞ]—êSÔ5KëË—/; UTnü+¨ðvâ’=WÍž8•ƒyNç®x«¾ð­”Þlÿ¿oqÀ#­ué¨Ùæ„‹l’!ÉŠôs,Ú>Ïê¸(&¶½´<ü_5?¬bg®ö¿æhÅzÒBp¦ìû{Uy/Æ<³ ÝÑyç?OJÏ:„òBóy%ýÐ=j¼“¼Î6Ço”œzwõóØ|4Ó|ÊÇ»*Ò–¥’Ç Žçd¥yá?®*Ö˜wðïÎx«¶–ó Åå,HÝÞ¬4$0ÎãcƒÈçÚ·©9«E=… wGêz5îŸu(½¶™c‘æ•8#=jòøVF@š¡ÁÁà®{W±Ak£^²ÎÂé@Éó>ýjφt72ij-¤aÉÏ5éÕâyÓœZ’ûŸªÜò?°à¤Ýï÷¯CÏô6÷GI"ÔtÔÊ’UÂàûŸJÜ·‘mðæAŸ˜dн}š3*Æ`0NzŸZƌɧÈZáŽÿëŠð1xÙfièû#®†8x*qÙAk3¶ØÇ#°íZv¦9•Ì<ÄÀÚx'Ž¼Ò¤ö7N²ÛáùNi×j÷Á  ã‚ pûNmÒš4læÓeÛÉ^2Cþ}ªþ“Šè~ðü€I@í×ùÕ_š—Kã'¾*™»wîá°ç­-Sº¨î6ê;¤@ó±U^qǵ&Ъ#\mó«Æ.ã3¬ãxãæ=).íY§RÒ §1WÌÙJZ–4Kh§¼[!£èÒ¯¡ãêWïàoi0I5šåF];‰í‘Ö¸/ Ikh7ÉlK,¨ùªƒÈ¤øw;ê‘ ” iS̉È»ÿ:¥.cxK–ê;Ä^9Ÿ]½+¦­l@ |¹õ'oõ®bøÈ–É+*…RT’ÙÜj¼Ò Ä'=óÏ_ʘë%Ë‚äìFÁP:zšÑFÒÜÎSlÒ·ˆ\¦ä\ûSg…ÃpÙ8ÀëXbT)ÀéÁ¥BeÆBä÷³PäÓ1©+•.b›Œ'd÷ª>l±Iò®ñžA­S=£'ëU|ý1I*ò|¹'iÖ‘›êŒv¹MïYЮÑÁâ˜IR&ÙÓëS¼– …‘q=êÚ$ f>óTª(슌9·d YÐ0 çÔ¶¶êì]±¸Ÿð«PÛÚ0>t˜' Ñ@Ì ¼ØÎ2{T:—ѣ˹r …Â:ãµZ…|– ŽØëT-ÐîÛ¿Vº+åGÌEfh›hÞÐà‚XÞ)péÁ8ùxëùÖ¥ŒvñJ«% qÏÊ»²}k™†åãu·$§=kZÂTÞ¦K³êw§üІìõE˜µy-.d–Ù^ Œ„Çj²ðNAà÷­¨u»iv & Ä“$LÀ)÷Áþc½Hú]ÍŠJ6;çv~£­cÜhwò"²€ I ¤tÆ?*Å5!É8lnBÖáR1*ÀÄÉ9Èvç #¡õª]E ß—…~¹ŠE+׌sY÷öWÊÖÙ•U±Ð‚2}øâ¡WqùW­²Ê«£êNGZê§µFSŸ´ÐÓ°¿¹µ%î/" êÒ Ç¥hÝ]Ù\Ź’ ËÇ<ö5q{c}kq±J¨1È7dwb³olo£µi-'1E‘òç*FzAU~m ŠåZjoÜlùvó/™œ__oQô©ŸP›ND?jVGÁÚÜ…ëÏãMIçaÑ9Ú£ÐV„³j0œí1>Þ¹zÕÉÉ+¶g{ìwúY Gú²8úóP]Üy|¶»Œúƹ£«\ÚÌ–˜i àsÔ ¶ºì‘³yaòîNH¬¦åÔÙFÅ]Fçì$¨2T¸~Ù¬¯íSSéí+]ÒRÛì¶š’K»|Ì7¢°ç“Éǧ½Iý•¤j·_jºÕc™­FÕ B€Àÿˆüëæ틳•I¤V#†Æ Ig¯kVÓä_Ís‚ÇÞ—-µ¹ÔëÅ­¤‡‚¤kg†'„G-ÉŠC^>˜5’þºŠRÒ\—ËT“ÃÔμ‚ËâŠìbRvEÚp}³þ&´ ø³¯Êñ5ôk;$€£rp1ý}))0ö°=Z×D»-º$+ªÃ¯LÕÉ"Õì„“M ʉ…ä=}©~x•µ«t{¢Vá¸ç…éÎ=z×¢]ékÓÊÛª3‘ò©g#šj¤^§E;µ¡ãZÊÇu&Ùat`Œ§ Ô+ioäÂnlÀ#Ÿ`ïzïuj‚ä•—!”esÀÆóü«-tYÕ,¦µ]®¹2?J˲oS tT s§ªç‹'î+7ÄV¶WvsÛËkä´ªB³.J·¨5Ñ®,!ŒÆsMUÔC\Â&@vîAïøW4¥wrf“VG†ßhº¶‹|†UÀ_™]ŽA×é[Éy-­·Úf·v<0>Tnꮤ´”^­æ˜òKD—O™[ŽŸs¶¶°_Dc–Å£p›R –ëÇR ·7k³‰Ã]FHukùäN.áA¸"9QžçcšêtßÜê±¥¼ö©…¬‹¸ >‡Ó®ƒCð‚ϤÛ8%dµs¸óJë`±‹LµG’u_)]û¸ôãŠqwwe*]Ï7¿ðõÿ‡`KÛËÿ«-¸ÓOÿvZ.YÄÕL.‘"ü özÔ¿Œ¼/¦B`¸·‘ ¤çnÎ+‹O‰ò¤ïq4諳x?»eÇ¥98ËDÇnGäz_öžŸ£Êéq¯dÂ7y,OÎ{c=GzÇÖ/®µ Ò²@¹;ÙÔ…_¦kˇÅêWkj±¡š0AÜILûž¢«kþ'¹xÞ;„ȇk$¤€=z{Ñ:)ÊÓ‹^¤ûxÍ{ŽçCy$¶·fRÂì£H¯¿\{Wu}©jW,'”F¤áFîwÆ?¥Xдû«ÖhÚGbàwíõ5ÝØ|4{²íuP ¹ÆFsÓò¤¦¢õ¹µGÞi¬Q\y>Ó„|’Hü{S5UÕîa×D¢!7œ3qü?•z±£ Dh#»#Ú»Jr=º×/y¦ØI#Ãy|Ë·£» ôüª¡Y'ªÇ ?ˆÞÒa6¥i; y;Fóòž‡Ïx“Ç1j‹-½…ŠÅ®ÌÇ­u­/‚Þé­—ZfÇË–Ü~5ç#Óm´ÝM⵸Yc|¸ÇU硯¯É0Øjõ­Z“RZ­ìÿ¯SÄÌñ5iÓ½)§ž×gâ]{O³û –§<0äªäcé]/„>%Ýh~lâϨÛ:E-ó&=Éϧå\N(¯¯«„£Z.3Š×sÀ£¯BJP“ÐúEñŸÃkÝÿP¸œGvŸ³Û<›8ä’?¼ƒWñ¿ˆ®.'‚Û[»[O1¼´YX½=}+žÀÎjÕµÜ0,aì!˜£î%óóîœW*¡ƒnP5ú;hvâszøÈÆ|©vêS9',r}Mzit—}éi:nä¨`ôt¢»ÕGo…þæyîšþeøÿ‘PÖLJo"¶¸òZØ;ÌB«’3Ú²Ór8‘pJœŒÕÛÍZâöax¢Èû­àŸ­g‹¢ñ0ö-{¯w{[üà WØMUOU¶‡fש{`Ò ½G#?:Õï®àK ˜÷”½úw®:Q†!ºžÛ˜d×mà}WK¶ÓSRÕç&H]†ÞœþýE|N;&­‚¦êZú¤­©õØLÚŽ&\žWÔìtï ^XÀ«;†X|òUrwŠ{÷&³§·Ô®îAÑÁ(ÎÆ1ç‘×Z»ªxæÇQÑ ŠÖå"&QÊœ”õ—c«K-îDÒ\30;7Àéšð]Êò’=8N3Ñ3Ó<w=ݹ¹ƒíð†BB€¹+јõäzפü@>ð/ÂÝAµymÜÞ´bÖD›\‚Ìx?62qŒž+Åtû?}”ë1ÚÇq¸ËÛFä³’paÖ¼ÛâÄ­oÇž"µƒÄñ%­–›(­–iÁÝØœq^ÎO–Ëtþ¿‘ǘf+ W¬žÝAÐmîÇžsQ*ª>ðFWêxÖ©àÿ벋[(¢…tnÄ+ÛžµØÛèq›E‡P%¶„Þ¤“œ„ž£ü+Õ›Ãú]µ¬³5êƒãpÀÏ¥r·¶ö3!–6p{`WElÞµhF”b¢£µ–¤Ò•ITm·-îdÛŠ%†T]»Whí]-™*£2€k•7W„­ ÃìókÆO¹íÈ­='W×.~Ó¢2³ “æýßo»Íq¾f¯#±UIÙ#K#Ãå·ï xã"·K,«n]UPà±^qéŸÎ³[P’)„sXM˜ù‘óU›ZT‘&„ªI‚ryË+ZȺ#©Ò<•¹E ¬]ùã8ãžÂ²¼Gd«m±µVܦBFN­úÓ"• y"·˜¨a¹˜Žý*¼­qoz/س p¯ÐÔQ‚S¿‘¤c̬Ê0¸iRÉ…\óÆ=+™ñ ¶“¥Z]ê’^y1©ñ!Ü[~£¥ušŽ³gs)Àb#$HRâ¼›âL—Ú–™wöX÷[‹¨ÛjòOŸóë^¾WEWÄ”ݓi3•¿àÏ ]x£_²Ó£·‘¡–eYXq…ÈÏ5î?þféV>$ðµ¹d´¶H®bª0Ô~µßS0ÂàñÂhœµò_ðçŸOŠÆaå‹Õòéæÿá›ð:â¡~¹«;OFê;T.ƒ5é³ÍLŠŒSˆ½¬ËRA<¶ò a‘‘Ç!”ࡨÈ÷ s@Y~Í_¶%×Ãéô¿ ø¾âS¡‰6\Ls!E á€äŒqÀ÷¯©nno†×[Ùø<ɬO. ¥1‘ÇÍ‚O9ÀÏC_•8Yµ½¹³•g·™ã‘ee8 Šókep©wMò¿ÀõðùÅZIF¢æKï?hï~.h#Áñë77–Ñ\Ìm‘Y£r¤àŒôÇ5ù¡û_ø†ûÄ~;µÕ¦Š$µ½·óíö… Á(wc¿Ê¾EqÑ|ø–Ú[ê«$f/'{.[gç×Þ¸ßx¯Yñv 5-nèÍ* {QØ Ï€«BªF¬qùENšwv1OLzRbSFÚõÙá¡´ciØæ”.M ÄQNÛN ëHzÕq ŠNMfq@Àœ BIâ1Þ€¹íHÑšQÒž"ÀÉ8§´XCT:R…8Í8ñIŸÂ™7 zUÝGV½ÕÙo.e—ìÑW{Àãö ~HS¶ô¢×Ô9šVÃ#èm¥™ü¸cgn¸Qœ{Ô±[Ë+¬h¤8øfšÊY à²4lGu#“}ã]ÞÅp¼ãÓÒ¯­;n8 U’uß à±¸ñ­ŒwðE4Là“<û×é¿ÃmÓF[H4}ÂLJýâ7’„.@ç#¢þUùWáÛ±c¬[Ü—tÃ`lž+õàwŠôè¾Zk׈–ó,_¾ódÙ€Ææ>æ¾S<ƒXˆÉ½>· «a*ikscâ'‹4­\$÷ C2©ÑõþuóO‹|s ]j\i2I¼¨àòʈeèJœ`†í‚zV?ÇÏŽ6> ÖZ×y²¶e*Á>çRG< x½‡‹N§m$êÚ·áPN1ôóõ•IAÕŒ}Õ¥ÏbXˆF~ÉKSÔµ½m–/4[¼êܨSó)ôÏ­r×Wò5¼—/'ÙŽÍÞYr¥”ŸAÞ³4o<—B+y)¼ŸáëU|A©=ܯº0©·€½q¹ÔîÜlkÎšç¹æ>$sj÷77Q¸Üü9åY˜'u=+°Õ5H´Ù-d)+ &yÊ4²4K ?*r=E~‰•â'_¯[iÿ |.cF4«;J÷×ñ;ÛV¿B–ðJ\lBX ‚Øç_[º€¡°9®'EÖu½?töLï< èÿ²¼I©!–çYòrrV4ãù×Ïb°ÂTrX¨¾÷ü‘ía±Yîá&þ_›:««„…ùA’6«°è¥T±Yå pKó»9]Þ™Ìkž¹ÓÝd›[2y€žTç>koCÓ-tèvɨݡ$:…#ÉUa¨Pç§[™¿î³Ò£WR§%JVK»DxºöÎý­oã*¡ÇËëé]}¥íµä(V7:’nÐçµs·§Kuö©­°Ëu>õ­i«[õaD‚$Œ;œò?Zò1Øšr¦8Ú_×gIµ7 û}+TÓîÖín ¤¤–G#*¼gù}j]CS·=ͬ»Ç I<ýZÏ×5‹§B¿{æàõ¬»ŠöCci\Áñ^}Z³ÅZU©W9ÝF½Ø›°'š:Ÿ™qº©êQ½ÕÔr\B]#Ós}im¥šó"0Æ221R7v ¬cmäŸZáæqw ²·Ùm$ÚvÎTAü;R¿ÚĦ¯BÄäš·8VIc*Ý›ÛéRɈ‰ŽòÉïíBªÓ°ÑšlÞá]¤“säòHü©–zc˾aÉ»VŽmØÚC–Ý·°Å !$´QäçÒ«ÚË ÖæmÄ ádWÀI~´Ø•äýâäÇ ~>•²ö Ñ<³G¹þ÷¶+>hàŽ0¬6³cÖ¶E- ·s«ðîž¾l,Ò“ÝGéïøÔ_u3òÐ@¼coòéZž)nÁ:†ÈMÕ“ã¹ëQ¹‘“9|ì?ýtFiltéÉc†FŽÔH©}Þ„u¦Ã}¦ò€e°yêsSù Lˆ26žýêŲG9"·V{œÒorIâbí,i?0ÛÆxªopÁrça'qвEÂ}Ù6ªô]!{™>|áH9­SV÷‰’L«2»‘ óÓ­7ìAI'ä`ƒZ’ Ý–=¸ÅE1ãnxˆÕÒÄ(ؤª­óc¥YVÀùHÁ8ÏÆM§æ^:Td´c*:Ž”^ûš- ci‰8èzt§*a°§Ž¼Ô³nb)àpXŸ¡ô¦Ñz3RÉðq‘ÐV„WPB¥ÇŽ9õ¬Xî U d¥OöÅØ(#¶+'•¢6Ro4yŒÊ¬8¢´ì´›éÓíæUš5åP $œzW.·KænŽ2:“Ö®YkÚŽvIˆòTõ©”Ñ͵©Ñ.³-¢Ê·ðÝ:ÅóB› Û‚8Í\µñ Ÿd2iÒȤ7Éæ€=¯‰,®í–>ÐK1S¸¹À$ÿõꜺ–ž³$Qn{Œãüš\ŠÛº²Ð™uÞS4k>Nå$ qÎCëÅA, VŽéN?„°9ŽÚÕŠÆs˜£ëÛ&³ïoåºlqypŸºIç®Ïrág¹ÑÉunn<âcÅX¸W–Ü.åQÈ`ŠãÒ[YH—Ê— 8$šë´ ›”'qXл𪔚6о†> ÷[<¨Ð`ƒ¥W‚ÖSjòÜžµÕ^hñC7–ŒX•ûÞýøªP[­ºel4oŒ‘ßüšžkèW²&³Ó”*͈¼ä)$w¦Ý@Öñ¿œáÚC»ð? ­"OÙ òÊþœWIáo \øŒ™ï§CM¹gÉïRѤcÑ•Ä v14;a eعíY#E„†’'`Aè¿6kÞ'ð6•k›†Þ¨ €péõ®Tð•­€–kkö Ä6ݘ8ÏsÖ„ú\™AÄã^ÖêΘÌaåwzt÷Á½HöÉrÒ‡PÜî<þU$^‚ì$ú‚?î÷þäpÄt_Äâ®è29‹û7ìoº90 üûâœéÝ]ï]ÌÆ²IÈã-פŸÈS$ѵ3 ¼€…îpkªžÑì²ëÏüéÉ5ôÑê#¥}ûVZ¢9;œKéZ‹±ß '®HÍ'“$o™ˆ$q…êk¥¾µ\»µß™Œ– 6ÿ:Ã’xRàÅk’‘×¹¦äÞ€•´ÖÄ&ö~¾žæµ|!´š›‹Æ4; —vúƬèþÔï­ÞûVO³ZC¨Çæ|çöâ¤Ó¬î ¿EØŽ¡ÀWÆ©#jÒi• î{^€ÑYÙYÃm´–” @ÉÎ8àWc¥ø‘¤°Op¬èPîÈÆÒxéô¯-¯w(¬YEˆD§sI$猵5½N/ hóJ-*þíNí£×Þ±Zjz¢Š·SÐ5¯A¥´W :y~b#ÁÁÈüsO›Æ<–ÆK‰C³*í#81øþUò‡Ä‰–П& û;Ìä”dsÎjŒã[O±ÜésHŒ 3,Kœ‡A^†+Çbaí(Óm?ë©ÇW4ÃRŸ,æ“>§–]QµI^å-âR¯´­ŽÀþ½eßhš]Ôñ?P]Q\$˜“ùŒŠùrûãÛvÇ4³Hޤ’ËóFCqЎب¤øÉq§ZÛ¶‡-ɹ³ûóòžžŸtÓȳ)IGÙØçžmƒµùÏ­ÓÃÖ6å`Š+xxT%ˆàõ=ÿj›x{L·º–K»ˆTÚù`:÷Çá_6h?¼O«:XHR9$v–yž~ˆû£yéŸÊµ¼QñZÎçOŽh<Ö.æ•5‡‚ʬh ¿—\W%¬N×—Fy5»y>ffÚ}:Õ £kíržÃaió×\ò}Ö‹Ñ3æqÙÅzòå¦ùb»?Õ‡†4ø½u¨^Κ ²Gæ'n¤dòþuçú—ˆumQÌ—ú„ò’r~náÒ³O馾“•á01JŒû½_Þxõñ•ñ-º’ùt÷T¡ƒ`æ«óëNkÒR9\Iñ@\óB0aÉéÅ?jÌÆ…$àOµ&9Å8wŽù¥Æ(¸¢·?ÅE8©£JU*xïNÀ ‘xëNÜàmóo¦x©ÞiHXâfÏL Ú>‚ÞD‹PÕaŠCÊQFî;sëŸÄV5qéYMþ¿‘­:S¨Ÿ*ý k8/.æK;4’I&`ª‰Éfí^‰£XŸ éÂó[ha‚í„o•‰à<šÆÿ„«EÑíE¶‡¢2N—íRÈ7ãq­r×w·W’o.^V<åyUðµ³[F¬y)§7÷lz414òëÊ›æ›VòG¥7ÄígÅÜxoKšËD°¸LHé$Ò.y]àdgŽõÌø² J²‹MÑõ8o%'|÷ñ×ñ®H\ˆ d|:¬ó»/ºi`)áä½›´WEß»}LjcjW‹öšÉõòò&gUêj•›€)„däæ—»Ü®r(¤7®iiÝ4`g¥ âiêÌ:M àŽ)ØÅOS¢ðïu­/ì¶Ô¯H™³qb³°ŠAßåàs^££xçTðà>!Ñõ;˜Z{f·‚E¸'ý\€ˆ99V Ðf¼8 Ô±Ön­­Eˆ|Â%óBŸïm+üpbð+Ôã¿_3» Ž–r½ºynx+Ä7޾ßk2ZÚÿlé,ÒÀp’3ó0Ýx>Ù©…4wP4úœ2_ÜÇö•h µUp‘œ’ÄsÏó‡­\é±[ëwŸÄ#‘wô 7ª·é^ëá¯麽‘]H({©ã¶IaûËÁ9PO÷ÂçžÕñ˜Ì,[»_ðçÚa1*¤lÞº´Ú%Ϙ¦ ¨d?ăO^`:Ôzv¯§é—jÓ&-ðǪíèÜzW'§xŠöín533\Ku$rËa\ Û•²A<úÖÔ·0_G#CMÄü¬{‚½yj<š#½Ë©ÓøÏÂÖ:¼_m·X¤I“wÝÜ6Ò¼nûÁþEäðˆ<¥f8Uî+Ð-/u-*±’ã6rœ$§Ÿ,“ÂãÓž½WÔ,.-ˆ¸¹”2/PÊOLûõ–#k¥{™ÕIëmN!|?jTQ‘Ë7¥E§i·–ðÈF·|“Žäô Xlå.q†V…UÔmì>ÊÆD‘H}õÏ¿jò*TÓcgk3œ“FK»‰‘æ!KdnoZÑ i0XK#îó|®œéE»8O0¤Fá×µiAk-öÐIXÇ$þ4G™= #ilsº^€R8®¯b’ø»ƒZqµŒÑÉäá[qà‘[¶µÄSXÔ®^kŒ·µÔ´ë—¹™”ÄO;Ž2¾¿•JZßQÊ\’±¢öh÷bêçqÂü§ÜŒp*…úFìNÐÀíS‚Ã= qµx-Ãy§'5‘>¹ha/»ÍœçŸÂœ'-ìT¤’³e­.âîæs=Ücj¾Õéõ­›ûè§´–Ù¿vYShÉúq\Ͷ´ï&‰ Al}ø«Éª¤F;’‡VµMUïó-… –ZÒª%¨ûJyÁ 08>¿Z¾DžÝå„"¢7hcž:š×Ô5+y¦ÛèÔ ïëÅbÝ5»Þ†I›j éœÖžô¥u åQHà¼Ö’ÚiïlË$žµôØ%«—Q(¯¿Ðò1y%eGUÊÍö>mhÙGb1IŠöxGHÔöÙ"윒EQ•5ÂêŸ5ËÞ{p.98o~9¯¯Ëø‡ ŽŠæ|’ìÿÌùÜ^I‰ÃkÍëüŽKoJ6ñÖ¯6‘© ÜöRîµUÑ‘Š:•#¨#½¸Î3ø]Ï"P”>%aX`H=Aé^ƒð߯z‡öͶ‡ªLn-î˜D…ðY[°Ï\v®.;›e±6ÿeÝ+¾OAì+©øuàûý[Y·¿w6ÐÛ8‘®K0è¯#:ú³ÁTx»$“³{ߥK+•zx˜}]Þí^ݺÜ÷Ñš9üût‘™ñµc.;“Òº´˜Ûly à-I'­&›Í‘ €Q@ éîkÙÛÍr,ÁTއv3_*¯f~¯µ£F.¡¢C*ù–V¦l6J“Ãc·=Mqš×„,uÜZ^ÛFϵœ'!Ï#ÿ­ô¯TŠÌL’“)HälÇ´sT,¼,óê/3(*A)•äs“߯5­,DéIJÍv1¯MUV’ºêŒOxcJðý´&ÖÕSaÜ~\N2?Ï¥{µiµ¥µ£6ø¤Œ#ïéï\Í®’ÑN“8R±_zèìÞ/ÙL«Ä7ììzQ*Ó”¹Û»6§(û+YXøÓãGÄð¦¢Úž›§ÜEk;î˜1 ‘;rÀÏ¥ys¯¯®~2|7}}dqªy`% T•݃yë‘úWËú׆µ]îkKËgÄLFð§iã#Ú¿OáÜÒÌ:¥Rw©ûÿÁ?3Ï2éa1tãh3¯ziõeâÈàsQ´dv¯¢hñˆ6ÐFHWÔbšWŠVÑҜړôà£ð '9 rqJG¥拘ÍA§Šp‹ÆçŠ~§)¨¦Mî!SiÙⓎô B3IƒJy¥Ué Lfž£Ò䔣¥RD¶z…±J½9¥.žÂàv=i8¥'¹  ÇS¸ìH£#Šèô ×]»µÓ„Ñlj„n|òp~aíÇëXvÖwL"¶…ä|g ¹5¹¡‹½ üËy¶À0GfNƒ’yíЊäÆIªo‘ûËdtaö‰ÔWõ=CÅ¿º³[ÆÂ(QMuä¡, =±šñýoDþÅ™mÞí%“£ ¯[¶×oµí/2hí` É'“è}ëͼY¡]i÷n’s2Ns¸®å“Çã_/’cª,SÃÖšZ½:·Úÿ×cÜÎiR©mE_ô^‡6WQ´ÓñíF3Å}©óFå`ÊÄràŠélþ$øÞÇO“K‡ÄW†Ö@£iK?çö£VUhR®­V)úšR­R‹½95èh -_[ºYîLŽÓr%“8ÅO¡Ý.•ª5¬“©ØÆÌ§å$pÒ¶t™£©p0Ê€"®q’{{U+/ 6§wr×—ZùȈ2HÆI×ÏÒÆÇ´+Ç’šVI—–‡·<+ éÔ ù¦õþ¿ÐmåÒ®,ŪD¶ÆP ´j3ŽüŠÂñŒÖvow;¡\†<ý1PÛk žöˆ¯su.yb9=½k–¾ñF­x† dÚ™û£Ò¾wã'__†2ëÖÇ£ˆÌèÒ‚»»k¦¦}•¤3´ïup±¬(_“Ë·`?©´³a’xŸŽ9«ZY ¨ÚÌÊJ$È[ŒðÍ~†ïå¿‘òjÓq…­ænÿÂ-­Å¤·u.‹½âDÃyÆ{‘í[¾]Vò-—¥ÌÀD”íù@÷÷®ê;[‚ûJ‡‘@ÇvÀëMMÎâLGI?¾§Ò¿4ÅçÒÅÑW½ïmÐð™40õcVœ’µ¯¹‰ªh©wi5ä{dFÜ ’{N”û_ ÈñF2ŠBå˜ûúWQg¦äs ùÄ6ÕcëŠT‚ûO»)"â)Fàqë^±rQå¾Ç±R’¤ÑÅëº ™+PÒ:ãpƒëŸJtš½ª,a^X#’y>º$µ—íì<¼$“ÜÕ‰"Â]ËÛ=E)bŠOSÊ®¹›là¯a,TM ;—9¿Â —0ź;eÀ ŽH5Q¨áªg³z‰EÀÿF“i –ÉÅZ7Io4)Æ9ÁçëXI.ÙA? ÏÍÊ´c]ϱIc8Èæ¹gž¦±wÝÌT´¬Ø§€)þ{c™†OÒšÚcKƒìuúõ]tÖ·NŽ”% l˹dHP4“&üô"o¨E•eB ÊœUhåk°Ý¶àÌUO®1Ú¬¢Q%´D‚¿2°ãëUÊí¨â_}D%³$· Wã#wN™ª±¿Ú|ÖE…D‹òry=Ï5JXu K¡…xpsžŸäfŸi3ÇsäÍ!AÜÃ)òr«õ#¤ðì÷ Ç–VKp2:ÿJÓÖíÐ8ûË1Ð÷ô«=ˆt·™;1 ò‹Úµ¼Ckö=2 €1Îgάͣ~CÊ5$yŒj˜ÛÎìôöªR‚Àù€exÈ<ñ]¶S;¹2m$ñÆjµæ™ˆ™ÜòpŽæµ…~†<®Jç †I¦¶¼r¤ »L攫AnËP•µ0C+¦ôõàSb–IüÎF0ÕÙØü)ÔþË-Ôs£CÔ~ïÖˆ<"Ö1\K©6ÕFË-‚.žýk/oM»'q8Iœƒé×1Çæé—”ÉtOáÎ*?RUYEô"iqºBIúJë-|;q+iØJ[¡WØúñÁéYºÆ–f½ógˆÂå°ác8 Zókfdàž¨ÉI¬^6‰c žp$¯Z,­nžO”!b |­ƒÆGAZ³xfæ2D<ÅA¿pŸðê*m®­!y®y’˜ÛótÇãK[@QW)¦\­Ä±»Åde?(íéé]VŸ«,¬VP2ƨ=ƒïøÖe’Lnf‰KØ—xqÔý+­ÑôÈ7<œy?8Æ>^x§-¬m ­Š˜²Ñ!Û‘´äŽ?J­¤hš—Š'hS9i6ÌÇîFqÐúž•Ù.‹z4Ò¢¢I$XOn þ˜¥¶Õtÿ†ž·Ö/liïnL0DŒwë¹³ÓÓ¿éS•i(SWlÖRökšnÈŠZÛ"ÞÞ'•ÿ,ÀÂ’½8Òiú6±R˧E弎«€~S›úä{úUë­+Å÷¶ÖpÛ˥ؽÒoŸhi]R«¼ôæ¶ôÛ[‹XÊ]A™™v™ÙrGvûqßµ¤é»6oMslŒk;T€ˆ/íÊ:†wuÈ*9'8íVõ¿Z^Ãk©y‘[µ»+«LÀ##iõÿëÓo´é4ÍZÛS—V¼‘JoÜm \OZêmµH®dŠV´GP¤©wÉç¾1ÇZÍ®_R쥣9ûï éIåjú…¬0¡ ’ œöë×RÇÂZ 6òùq¢ ÌbqÁU<ŒrksÄ>&µ‘Á-Mâc<`ì+›ÒòÊP“Ä3¾LE²ÊÈ"¥6e8ÁiZ5ªÝ;ßÂèÀå ©Ç=:Ö¤^·ÕgV-ÕÈß³ŸÃÿ­ZºŽ¹bmKåG±—nzç°5R}JÖïËyoÿvOÄ6ŒdŽO­+\K—©GPðg‡-<Én4È/',ÏcÖªiš>—c,oq¤Ãk«cµ7|–Ç'§9ï]>‘.†³Ë0’?5—hËg þqWç[/±´ñÎ$–7 èFA òµ –/drºf‹æ#žY §aI7u<‚L åæÐïc½{}dªv©a±»ÏÍÛé^‘4Pjê¾dñ r¢nÆoÃõ®Ä~&ðÇ„¬&ºšæöx‰tÞluý)Æòj1Wo N4ÔyÞŸ–¶ñxnÕïµKˆC…{‚ÇçÇœöÇá^#ñSã5…÷Ú4Ÿ ¼Žä•7!¾Uçø}~µÏüOø¹©xãu¦m%®˜„ Ç;›ØöÁ¯2ÀÏ5ö9? 'lF9kÒ?çþ_yòyžtµ¥…Û¿ù˜K$³ÈežW‘ÏVc’LÇ S˜ 3“Ú¾Ý%d|ÍÛÕ‰·Ö¾”§sKÆ)ŠãëF8§àB CB–`I>•Úøoáüš¥´w2£´ŽAg G9ã®8¬Ù-æ°ŠFJ© c¿Jú›á¯ƒ´Ãïâ^UÞyjËØ õúƒ_ĹÕ\-E„ ù^íþ‡ÑdÙl1uª«­’ýHþ øKðÆïx†´†Ú-ÞL«´;s€¹êN;WŸüx×nþ#êÒkËs“dÎb±Lcn1]xÖçÆºÍÆ•wor4˜A[qnÛs)þ2Hû Åy§ÄÞøbêÛB2ÍuUyüÌ*¸ÆŒg·¯—Ëéâ*ã`è;Î÷ÿ=_[î6¥*8GN_õøK>Ê‚J®BçÒ¢ÅKsp.n^b¡7±lƒ&•­¤TY6å¡ ~®µÜø]ˆ”`š™¾ï$T8§–Èǵ5¡/R2;æ’éF*ãqŠR=)Û÷h¢Áq¢œ¬@¤À4b#åiÛyÆj$séO0ëT™.$¸Çj)žkv¢Åf[ƒM½™e„R>Á!/¹Ï «š•–“tÖ¢ú+ã­…‡§½dM¨Ï(T2¹6¨ì¥W-#u8¬}æîÞ,­±¿}âkÛ¥òwE*r±Ã¦Ü{“øšÉ’÷yÜIb{žj¨Bz’iÁGJpŒ`­`“sÖNä­y#Ž„ýj6y›©Q´PéNý Ý§©£ž@¤Àõ¢À¦È£ô£ŒQŒu¦€n3K´ÒÍ;oh¸8úRòM8 1Þ˜€zS†Wši«@û ®´‰n ¾!bVó¢;GQùâ»/„ºÜ6š‡™¨ÞC²¹V˜/RHŽ ¯=ÒµK"s,d‘JH‡£)¡¤Ž9‹ÙHázŒŒí^}|±P©JOGªvØî¡ŒŽp«ªÝ_sì ¥·ˆÆ¡¨Âêñ»%$P ¿; c%˜F«Ëg.vñÈ'“œv=ûcÖ¼SàïÄ-Lj‘Ø#U #)'(p0  úJ-îú͵[2¬Í#D¹ƒ±Iú…lþ𸬠°Õ\&µGÜá1”ñTÕHì`]ª:@d`¡€1ê8äç¦?¶4–{Am©ªÝBv¾î`:p:þUÍêz…Ø‘¢žÚHÉù[þx¬½÷SÒ¤†hî]Ò6s•qϵpJ:êtÊ´z#Ñï|²#se\DFwc€8ã?rú†"]ä4j§œŽ ®£KñêÞ$WS¦É „ˆ§‰ˆuúwõ®£ìZ.½`Ú\a„ñ¾õÝ…*§±9äßÜTÊ„d–¢—,ö<ŽÄ³Ê#¸TÝŸt ´MáaNuQÈíWï´©t}f8<°ìÎW=çð=iÆÂT¦r0FN?•xÕ¨ÍMês¥);·°ÝÜBÑË+0'=ñëY:¥¶µ{¶0CC´ ؃z‘]$–äÉ‘+`÷½EöULÖ²ísÊÃ!¿ ªT_Úeûö93dêñ¤°FÙsŒ“ŽG5¬+¤I=½˜u ò¤0y8®¾+&º/u*2ãäSŽ´ŸÙ«g+‡]©°Ûsþ{ÖÒ‚Zõ¤Ö§Ÿ%Íàg…¢u‚:NqŽ>•‰­xÍ4¨VæDó>Ò€òyÿëWy«è–WQK4k'›µšN6œqÇå^_âmC‘qÇœätïÇ#ñÍv`áBs_XZ_§c“ícMònméz•¾¿Þ-ÀbÊ (þu\•tér–ù¢‘÷uö®À¿kÒ5Y´é÷p6÷ô5êö§t;̇y; 3JÁb\h»Áꟗü,yV§y«K¯¨Ëm.o,dã,Oöð^0Á§)𨶱Ä&Bÿ)†EI6ÊRY›°ê+ÈriÜôbÎj]:0á’3¸ò ?mÜ3‘2¶JäÁü mMd†`¬c'ך£x°Ää:åq3Þ¶§YÇE©Ð¦â´9íRçr™BO*ÑŽO·×’x¾)×_¹i€Üá_…À¨ÅzÖªðm+ßjã|K¥ÝÌZîËc.%Fèã}Wã!…ÄÞoâV×Õ‘äg˜ybðö޶wÐæ¼ä>¯­Ìë/BÃ8"½£O»ƒJX 6æÆÀ#ŽÙõö÷¯ Ñ ¼þÓ·{d;㔞Ÿç­}á]5xU¼øÄ«Œ«vã¯ëúUñ„"±1“wMm~½Ì8n£xwj™¹§ê©iŒL>b¥¶íþºµ%åäÎfU|psŒñþsZfßM„ 9£ˆˆ,>¿­oéPhÚ²ˆ-­¼µ ]±“ì|Ci=O¦s ÊV7êmD €3Œ~5}õìW0 ÌЏ8ÀÇSìk”Ytoê—>ÐüúšÄÞîîtÅ´|gïG 5¥©Ê÷ú•ô0¸%ü¶l+/ðãð*ç†.b´·Ÿ1´1HYä`q–´ÃbcJmÍ]ôÖÖ0©?lÔo§^§‚üTø!¯ÚßÅ>‡§A9uf’;8ˆXÀÆÐOLóŒwÅx½ÝÍ…Ì–w<3ÂÛdG\2ŸB+î½C\Ò¦ÑÖí,­àU2C±n0pq_øö[[¯jW6SÉ<ÌJI"í.0ìzq_¦p¾i‰ÆÅѬ´ŠÑŸ!Ä8 >ªÔ^­ê¿S™’<ò*¯`TÄXt¯­hù¨»±í@éŠ{.)¤R.âRò9Å%(Çz(âŽM£x4;Ð+Å!Üž™£>ôÍ&84à¤ÐF(Æt"”“F9é@y©z T{HäsJX㊂zŽïš,pF<Ôð`š ô!º’*ͪMs ÛDŽ’@Çâj<ŒÕÝ&Î ýB[‹¥¶ŽFÁ‘†@¥U¨BMéd(^RH÷‡>³ÐemR ¿´‰Ð®ß•†lÖ_ÆË»(¬cXlÆûŒBvà"ùºzõ溳â¿xDµŠ-UnŠÂŠ#O˜äÏè:ñÏxõübÑű‚Þ) I'Ïå_šåXlni™ÇV2tÓøŸ»¶ÇÚfœ6ðÔšRìµßsŸ±Ôo£šÚM“\Å bbJ6;qô•z¯=†±¢YI-œecn'¤ŽF+ÀÁnóÅs¨Â±© ?„ç9ÉïŠë P][ `Z¡ù€þ.1šÓ‰1X˜Æ”9\Ä´½õ8òª/Ù77{ôg“k"Âí–8Ùbnw§§5DsÚ»írÒÁ¤–îgFHÁP¸Î>•Âɱæo)HRÇhö¯­ÈsG˜Ð\ÉÞ+WѳÇÌðqÂÔ¼^d4+1T’{ ™,/$m‚Vë†þu{MÒ.§ul˜€ù·cô®¦=$Ë2Œ’ÅGÉdžiŸG/gFÒ‘Ñ€ÉçŠ=K¥ù˜ztL¶ ovƒk»Ü »oáÉå˜E¢"†QŽysê3×®| zðý©Ûböyâ´G‡¦ÓÀ‚Ààt¯ŽþÛ­³©M¥Ìöé™ôòÊr„aQ|?yÍkßmbÒ’óF˜K$M‰—–sžøôWMðIw÷—"HÙ¹RÛúõÔÖ³nEl°Á#éÔÔ¶"}BDŠMÑÄÁÇùõ«ÿX±þÇ“Ÿç×RÖQƒöœüŸ.…+ïhÃIûiê$˜.e‚O?Jµ¤xcFÐôâ³B\ÈØ2ȹÁÇOA[œdC¢!>¬¦œ–w©VL‚Fã÷‡Óךàyž.T½›ªìÝ÷=—áã?h ®•¶F[+˜wGg$…ˆØƒÃJ³iò^$"ÆhƒK°ãñÍ^ð퀎ßÌ9ea¸.Üm5u55žÜ7Ê m]»Šžü×—*š´µ=,:ŽœÅý>ÆÚ"­²hTA•-ß&©ÝJ‘M›‡Yº²àçÕ;MgTŽCϺ,“‚3Š‚îç{Ku9Hã#½béJOÞ:j¯h´'r’ÂÍ ª¶3œô¬mB΢ŽyXää|¬}©j2¶òÉ”B9†õÅA¨}x’,á`ž¦´…>Gn‡—Z’ºFF –¨ Š=„6y5^4Û cŽ•{T€OºX˜#¯_z̓ÌøP¹ë[Ê/–çR-NÅG¶Ý—ËÁ>™«vÑy®#ˆëŸoZ†„ÄÈÎ6»p=1W"·òR26 cŽ¿JÆIìTS±§in‰´J‰?(äóÒœÖ1ÂMÁ ¤åvƒ×‚súÒÂKà³n-ŒJ£s®[©6è™ã“ßp=+8BR4L͹¶0ê!]ÖC"–BzD;©õ«Ú{G ¤}稜¥fÈÌïq$[ÉÇ==¿* Ü 9\3`žžõÙR.VEÆIj›‰£•ÐFª„èAÝNk:ï@’Kˆ` ‰¦`#\d…'‚R±¿…®½ÐeN?ÎkRÛYÏEgÿªb0sÚ¹œe[åjç¢x{N¶ÐmlVO(nϯùúÖˆïå¾]¡ƒ )¡¢ëTŽ=,Ë Üo®=j¬r5äJ§…ëÍfõ]ýÔC&™V~kƾf~¦¹K-äR0܌̪£øX5Þ:{‚D»v2;šäu;º¯Ùâb¢,²„è Ýy¯6¿ñ:üHñþ”¶Jë¡hÒ‡†,³JSæfÛŒ’ÄÖ’ò/øÒò+jÒ[ÌVk&Ùôðzæ»ÿÙéþµ[}DXÊÒÍpFçcØzkÕ£ì²È9KÞ¨Õ´Ù_õ1’©’ŽÐ]÷ðÏâù­¤ñ¿'—¨^1[ž>Ëxhãwrzæ¬Ïw<ïäØÇ¸¯'hÍS:Ž Ñ¼±Æ9ùiú; Õ’Fbª>vQÂg ÷5ãÎ|ÌõÔ#dCt²Èw]]“$ Ø!N:}zc~7km=¦8ÚÜdeì=óÖ°5MT ¹³IŒ°·Ê…@ÊXóÖ¡›S¿Ô-e·•#‚3»q–mÙãÏšÁÍ#)U×B}CUÓíŸý6쪦Ç óÕ˜t'>µBûÇz\Vý•žqaûÀ¥°lœã¥Q¸³ŽÞX<ˆ¼â£28 Óè?Zܱ·±¼ŠIc³H*¤g“þ9¢ê[ÊR0añnsn¦öki$•òÑÈJ°tÉ ‚ ük \×´ø-ã{»e˜n‹d…‚¹êsÎ}kSÄZoÛ!”ÿg[3~e\vô5Á%©‘ÂtpèÅ’Cõ9ÅB|»˜·&ìmé·­Â)ñ°Àg“s»­/ÄZ¢Û³èÚµÑÿXLñׯ­y¶ŸktÖén(u`w5ÐxK¾šCoa.ÍŸë1Æx©Tµ7Šœc©©d¾4Õ¥tv†Ú9‰¸ò` <) ô㚣ãO†>ac>­qqrýg•¦89è8“úWo¦KdÊ–èKÍœ:÷R8ªnL6 i $ƒ‚rïÝ ©¡ˆ­ óÓ“OºÐUUìê$×f|ë«xcÄ6Ìúm½µÒÛ\Ü4‚/-ˆTäç¿qV5_†sZéæ}>éî®Óækp„–OUã·õ¯XÒçµ°Vb%Œ”•À =û’qP%þ“¦k^[Z™mÝ›t‡îÛÈÇ·Ö¾Ž[µvÎñŒ )¦…fUÀ4 f—bÁ©,Åç4à)1@„Ç_z@9§`~t;Ð`ã˜&žqŠn9cšP´¸¥¦WŽ”ir`P 1@¥ëÚŠ éKŒs@¥ÇµŠzðr) zr)Àvª:OÞéÖºžûû¶³“º¹\‡Üt=ú×ÑÞñï‹ü7¡E}iªbÖ%i$H×s(êO¶³~B¾NÁ5ÔøgÇšç‡"’ÒÚrö³.Ç…ÏÎN=+ÅÍ2ÉâÚ«IûË£ýOÈõòÌÎ85ìæ´}W꺟cè_¼3âÏ üÐZ>¡$I› “¸mQljç>ÕÇêÀØ_¬6÷–Ti(Êb@*G±þuâM,¦Ò[B²¼…ÕƒÌ#ÆÊGSÏlšî¼öš º7ÊeØfi²þ¯ë×Ú¾KC•)-ך±ô´1n«äk^ýΉQ‡V·K¬‹m­/#oÌq® œ{Šíôo½Ü0Áöƒž\ÆÞRvº¨û™þð* çùWYn%U‘‚@ÏMÁ¹ôÆ+2ÞöêÑQÙYefGGÜlí#é·9ö¯)Í'c­óSÔöƒso¯hÖŠØ»a±ˆbOgóëT5&hÉAÉïgÒ¹Ÿë7:Zù«tiUž2xàûñÛµvk60Ymb}’)'Øö­qÕ3»5§+ÊÝÎqã»vÚªŠ£øy'ò§%Ë:ÎK( p}ÞkVâUYGÙ‹düønâ«Ü^ÊbPÑeÁ<ƒÅ8Þ:)5ÔÎû<¡Þ4F Üúó쀩ũpU†òWæ 9Ï4öÔ­<½®ç~pFÚ©üx&@Û‰Àlr=êe'sH´Õ¤UÔ¬¢¶–…|¶áÈ÷®?ÄZ™qXI™‡Ìv6°ší/,n'Ù(c4YíúÕ[û#+:¨Bùàvç½eªv]yÒçØñÕÐî²`*L² CpHXgߊèô˸¢Ž$¸.ÀäÄöþUjò-µY,ãæ7i#1‘úÖcÙ3jööîŽ~`Gqš%ïËÞÙ\áœU&¹NŽ[‹¤ p?(vTÛy-•ÞKç¯n(Š[¨ BaÜ™À~ÿM{¬[Z†¹˜Æœ±ÆO¶k•9KD®'>Wv̵Õìî/ÛMŒ:0Y…ÖFâ2#œp@5æºÇÅ+[=yîô]4>IIYÈ]Ý:c>•Ö|8ø…i¯ÜÝ[ݬvR'ï™ !žqÓ¥z¸Œ‹B‚Å{6£dÞºýÛœ´sJ5*û%-FÏcöTÛwg&wð[# Õk7í×eŒla]ެ±^©’'© ‚VmœX̲…Ü£8×”«N÷gw¶×È«kà 8ï3o¢JáØc¿­vú…ÖELë(àíãržÇðþtš>«d%o9Tqƒ·Ôt®¶Òâ$hN6}îÃÒ²«Œ©){í³¦œéÇáF?‰-â·Œ²?.þ8ç§5_ÚœlðÉ4™“ ¾öÀÀ gÙÏáF§1º™à•N@;ONOJÂ×t{»£ÐçF’(÷˜ßÄ`ã4ùÛÜ%;ϙͥëÖ×/,Bæ'XÉ$ŽrM¦¸¯kÖÚf ×PÈ!¢@H<ªo%€íÎó¬ß xÏOðÞ…}‹tù­eŸíFu¨ôï^=¯Kâ߈šÌ×âäé:Q;b Nöœ?ÔWv õ„çRJ[·ù+ný qXÏg¬ŸEýh]Ôh¶¼¹TI®ÆÑ1µNz¡&«Añîæ@~Ïaqòœ®qQ’xã#­Eÿ·Â­%¥ÿÚ'’PG'|}:gÞ¼»Z›O³Ö¤—Ã’É*~RxÁÏò¯«Ëòœ§2½:æÚWæwIŸ5‰Çcp¾ýIFÝ–­—ƸݤšpðÊÙ»3žj§‰þ:êWš|š‡Õ­šdÚóÊŽáAèMy…õõÅü†{¦BrÌ ëWü%á›ÿë–Ú.m,òÌã*€d.FO$``×·C…òÌ#XªÖ:êî—à¯ó8gœc+~æ›ßM§¬üðD—Z6£ñCÅv—š•­¾ë{ 2]šî〻GñN=>•ä¾,þÕ—ÄW§Uµò.üÓæB£ˆùû ˜¯ºü3àÇ🇬´¸.#’+T #-¹QHçêz±µ†žÖïdÕ¦ÓíZáx-´qÇ_Äu¯‡S£Œ©Vp¼^ŠÝÙ[ñð¡«ÃÓ¯†§F³Z¿6÷g½ù¤nzWQñHþÌñ5èQ ¤“>"4Áû£éßß5ͯÑ(ÔU©ª‘Ù£â*ÁÒ›„º]9¦:1V3éMäàŠ« HªGj6œÕ‰a È-Xµ$ÆéG·­/8£P11Þ—½±@U₤ÒãŠp¦„EŠ1Žiì¸4˜õš¹ݼbŸAŠˆ±Ž*H˜¡È¤ÛëHÐ=É÷3rZ™ÛÏZ¯mêx©’`:Õ¦g$JA=M ›˜)` œdö¥ ÐÒ1ҴЃ{OÔô="Úh–Ì]Ü`î¹G9çÜ zU—ñæ®mµ­¼qD‹ƒµ2=³RxCÀð•DÓ®©ÖVëøsô®Ãõ+m@­íå¼Ö²)WTÉÜ;óë_%˜ÕÊ(9¼O¿5­¥}û.Ÿ¡ïahãêÆ.’åƒíoÇ©çQ^ëš¶mì¬ÚO_.Øý+Ðôo‡6iÑ\ÜÛ*\”S"Éëø×g¦xGFѦ’ÞÆÐ#L2p:ZcÆË©-´Ò‰"U9 Ôc¹¯Ì3èÖ^Ëg Ý´oÖÇ»Ëý”½¦%óËÏeèsƒÁ¶Òα»ˆÉäl V¬:­…òÞiS9òÐ$¨Ë¸ê }º×M%¥ÈŠÞÔ&@oŸÐö²n­.´•žê?šM豻ܟÿ]x´±3¨Ü$î{º|½ luhõ— +,XTe\î­&Ò¬on ¶ÄÎC7úu«ð»if9MÌAyú³žN_ºµg|ÄM#X÷ÅT”y´ØÞÑj×2¯´Ý;-.h@,íóÏB?õ>—áÈ¥Ž[iü>Ðd ÛsØúVõزWÄ\daâ$QLñ/‰ä°·F±eViŠcŸLg¯ÎÞ¾êT»9=S·zsBQVî9Wr².ìþ]ê݆šÙG[˜’Y"*è+_BñM‰)o,˜ßûÇeé¸öÙýk¨‹ÅºJ@ٰܪ¿ë²0NqÇ|~6ìÓZšé{£šµµ¸°$¾ž† [å dƒLH´’fM!‰;x·o¬Yß]k„o/Ìcœ®xÏáüêåþ‘w¥¹´ < Ÿ¨ÿ?Ö¹ùdtFo¯C6zfŸ,‘[¹¼Ö‰d°¸Gü…” Ì=¾”ßëÂ×R‘ ®vnÛžMq’x 5¼Žñ6OJé¥Ié3޶5E¸2Þ®š<& Û°Äõíž•˜úâJQÿÖ ¶OÝöªZúêl]âcÉ繬µ·Eˆ”f°Ûžz×§ÆK]Ï"¦*Sv[Bj@Û-— Ô±¦ËyÄ´q˜ÆÐÙèzV%•½Ê‚¥·,™ÈÍoØi+p¦C8L¯º)Í(­B*Rܯon@|¶d='½o[ÚÇËùU†=H²Ú89Æ ž+B9vÃ#´{È =zW;¼Ý‘Ñ vZ•)´âÓ–Þ‹’1Ö¹2Ò‰šY²0ÄœZëoã¸ò#)¹Éyò1Ø•ÌÝ­šÁ&âT™•Žc¨¿QßšíÃàêTà¯wc“(QvnÅK»äŒåOAÖ«É|²cqsÍdÝL?xøê¤õ4Øæ…˜Œ*¯†¸ÝöÖ7>ww?0ô=«½Ñí¤EÇ>˜êk籸IáæãQYùžÎýª TÝÑÑÅf·S¡€«Ž¶î>ÙÅiÛÛ}†‰Ó÷¬¡¹?OëQé·&ÕÛ{nIrØÎ@éPÍ,÷%õu*¬P šòÚìzø|½fO>´Ö²„|1Î3Žyô®v[§¾Ô^T‰—kûät­;m2çP¹i§aåã#>ôØ´èâœÇ,¹ÇFQŒZÞãI_©ÜðÛ%±aìŸQ¶ûAŽO3;aÀãµgêëöiññ¹ægÐw®ãM†+;º˜[•¹ª—š•«y6³6pƒµU£ï8§êy¸¼rm3›xG—–âCÏ •z{{{äŠ8¶íˆÄ'úV‚ÛO|ñÇöt!ÎO ­˜4جdÍÚG>†­F+CÏqiØáïüoªZÊ®û&ÆTŒôôÇåX¾ ÔôÛ`«²2AÏ^+Øü«bÎç @Âã¥%Ì:k*hò c8ê Z“†‘ظBIÜðÄðýÌiö‡„0$ÚAÎ3ï]§„YtÙ¡CfTÌF×n^©àWjt 5å ºJ“(T’1ëTµ©eðŒE’ÈŽ7Ã8ÈíÇ­gQºªÍjXîwV:¶‘qr¶¶wÒÜ…ß$qÇ¥lØÅy#< h¢Þó!ƒ¨Æóè}Æ:W‰x7Å:M5êN’«’ÊO\/oνcÁž5Òf‘#ŠG!Æãã¦zRTÚ¢%)4šGS¥xcRŠb³ÆLCåQ·îÐ –]=3¨ÙéeŒJArxÁäçO×Ùê2]ÇæD£`ª«çwcŸJžò(ìl¤Š]Þ[’Î;©ÇëZT¨Ôt=l=%e©æš4z¶¸³ô{KHÕÚ"²ZydöÏAœŽ•¹7†ôÙ­A–µd Îxê;ÕÝ%¸Õ3kw(„€D,¸ s]ä-¥Ì@\Á¶B1¹pk–U¤¦uNœc3̬ü#,kæÃ‹¨Õˆ]œü½óŠÌÖtæµ %º¸a(—>ÃÚ½.òÉôå™­ jÈÄ)g"¸¿\=Ò…¸áŽNzzšê§Zwç‰ÇUEEÄ䮼At³œÆ‘30`d@U›Ó‘Á¬\‹›·Ó,Vì#”Â ŽŸtVÕÖŸk3ð†i<*ñ\.³i,wßbˆ, Íó:wÃ?o)=åJÍ_¡Ê²]^ê§SŸqHw2çåˆQÈž•ÔÚÚ\Îc’4f ÷|Ðpp}:þu&¤iöd¤×ŠU`Pr’qï[ж!|û{·‚|£o¿õ®‰§-Î~rh4éÚ?.MÑedL¢ý=¿úÕ•{v¶Ï%¶Ÿ F(ÀS# ïaÁëéW俟Q@sH0Å¿ž+6[;h²KgaàžõçÎmìis’3..–a¾vV0€ÀpzöÿŠïV†$óR4žéVš;iÉÛqT¡ÒËjFK©†ÂU@ùGΡ¨Ë}«¥)ÚÚÑâùäx,˜ºs¹†p=­»¸%µ²ò ê™ÑòzÐqNð¦ÚY&t‰QËŽçþµWñN¥oeVIˆœž…O@=ëOÙ]­Œ9dô9]bøÄì—»&3*àc#'=*•·pª¼€–ßמEs×Þ †òálQ@€äãå=³ë]V›}o<+§JG)Èù³ƒé\õHµ7qGFEom Ó2B¹êoZ~“{ýŸÛÅIó ½XƒÀ•_þÅÓ˶bg ç-ŒŠÉ”]éž{DˆKTž§°Ç¿¯µ.uQÝTŸ2Ðë<)>e‰ÒâX®/%vi%Q¸÷#ŒA®k~¹Àšo6L“ »È2x$r2Oë\f¢šåÕÄs}¬#"09ù±ŸåP¶•*¨C¿õ$õ5ÙM(îɦ¥ KþŽÎîâö#†Ø#Iå á°r¡ˆôôÏ5ŸñZèÛx^dµµ†É…’4ÁÆåŸ¡"ºÿ hZ^‹ž×¬²\ä1'ýgQažŸ…yŸÆŸéR[.‹hÙº~ô«gåÎp!^ÞUIÖÅÒ„UýäߥõlàÌ1*8j’nÚ4Žoá$^j7Wñï[D†RáJy 6àk3â~‘—ã+ãc[+¶ûM±^T£z{g"¤ðF¯£øŽvF2Íeä¯|Ìçë\ÕÍõÝèE»¥Ù…Lö¯»Ãák<Þ®*?”_ž‰ééúŸ)Z½%—S þ+·øµ©Q—Šn;S˜Œ`šBË×5ïèyí@8Ã'¥,1Ý ÊƒÍ"¬héñiÞLóêNr‹ˆá\‡v àç õúqUµ-^îõ•ïnd™£Ao9Ú `PÝÜfù‚…ÀVÍ!,ÙÅf┹ž¯òô4ޱ·OÌG>aÉéš\b”(íIõ¢Ã S€Ù¦žôzP€’CŽHëMÀ=ù§¬™Æp)ŠFyª œbÇèHÍ; cúÒ‘Å+ bùª8 âœfœŽI㥧Qk†Y˜’ÜÒ”öÓ¨Ï4ͯԟÀRyy“RhÅ+ÈÂ-&Ú)Ø./¶)@ç4¸ç4qŠÀ \bŒÆ—©’7èÅ;m&Ú˜Üq@´b—€¸ÞÜÒíÍ¥ Bmâ”})}ûQJ\´b——Ðvš¥;t¢‹ ŠxSM*E隢XúS—ŠB9¥·áLLî¼3ªê ¡µ•½ãÆŒÆ)OÞ^õÇÒ½;Ã6PXØeÚi°drJð uŽqÍyßÛT¸·’ݘnšc·=°¹&½_ÂZ¼‰Á‘ämîÇ(QÛñùžrù1õa ¯™öÙDeR…7"aâ;­2þ2KFŽ5+· yÚxÎAõæµnæûeˆIì;æ&Cå¯ðÇ#Áýjk]Æ2³µ¼(féKdt­È4»“knñ–I<Éeœ×ì“wzCUÞ>ÍjŒÍ owÍ"˜òõ'ëœf»7N¼{D0@ÁìU''Óõ¤ðö‰¡û1W2¯Î1»$·Jï×OŽÑepÁYSdIèqŽ?ƪp¶ìæ£MÚç{¦Ia"=ÈýÄ‹ƒ¸N{g×½b]K ȥЅÜI# µé) ž³3[\[I,[G“zô&²o>›Øn^ÒäùÑ#Ñ×Fîç·¢¹•‘¬ov×CЬT2¬Ì~QŠžÖÖß÷§,NXã ¨-4¹Ä’\ÆWkìe#¡Î*ÕÀeX¢FVn‹ÿ¯YN÷-ÔnÏ¡(Š+H‰´b óŒð}xªúžžÒZ¥‰ À?/¥„yA³IÇJŠöæEÒC[n$(Yášãœy_5Ë”,®y¾¡²MX €.G·}$m‰òÈEÂòÀë[²é±ß,il¹qó䎧<ŠŠ]íKȰë•È1©mÏ>p•Eh”u ~îÇEk´¶Wf@ÈN'¶I¯/Ö¦QÃÎvV×sè†Iäx£Va1W=:çðþµÙXê–ò[¬jâA·%Aî;W›|?Ô5ïìa§kV2Aqlæ¿W Iý+vòâÂöÈ¥epr8Æ=kã1˜w†ÄJ‹wqvÓTüÏj_i4´gQ¥X>¢ïu4ɼeל`Óüû×=¯ë¶ú]Ä2i*g}‡Ì ð[<ŒþB£±—WÕadµ„l ™7aUƪéÖQK4ñ;€-&ò·Ü`–èE'¥ÜíÐësVЇTWñY†ã\E†ÖÑr¶`2œ™ý†:~uF[Ñqr"gQPã‚}>€ùVljõ[-&É¢PäÈ=˜ƒÏá^gâ¶š{™î]˜mP~çÿ:릫bÔiÅ^Û$Ž)¸Ó|Ò~§Gâ¥Ó¯!‡N‚(œ¡Þ_ƒ–ÇZò OE¾´¾–ã*娩q´0õ¿*é쯿Ðãb5E|ºð½ÎkŒ:%Æ=ÝȵI wäíìtðê:„Ö!í¤2/8é׊鴨Åþí¨ª$Çõ¯Ä*FPº¾‡èu¡v¹NÞÕî$²±²·0»ŸžCž `Ž}묱ðõ¦¦æÚÎÏÌ‘pZF —`FY;=EaO{hºìv°‘àI^B?…ŽÜ~¿©®çQ½»Ò<‘øl™.îg÷àüЂ0Hñýkz¹_4öB§ /á½6Òê;IõÛynâbå`6à—9ç¯éMÔÓB†ð‹—b"\–yû¸>µçØíº½¸—^ŽMJ93,Fq½òyãò©µˆæ}6æY„Á–—wØã#<‘Ž+¹Zê<¶okù”©©¦âïo3¨»×´vŠW²Š%Ž6!¤ó€ÁïžzW=ªëòÚK U%…ðs÷ˆ?\ô¯ðÇÄ»Ý2æú}SuÓ\Foõhr3ÇÒ½^ÃßðYÁ¬éªö÷¬©˜œ¨%®k·5Éñ9ZN®±}VÛv2£ŒþýŠãÖGû:ÝUc-ºlnb8ü*{$p.Ù‹JJðNF1[wžÖ£µ1}‰Pª™IùÆHÉã¯Ë6¨Azìò‘‡;‡&¼ÚRŒ·g·]j{GßǬ؛ÍUÄ3Ýá€G C]æžRŠKy6É,˜ãós\‹â /Ãz40ßYù×R„•ÎÐ6ŽyôÁW[Ä=4kµÓâPq…CÐmõükÍŸ3âtAßDx×Åï-¥é¸Cµܤqœÿ¿~+ÇïݲcX‚!Lõç½{OÅ¿Eâ´¶ŠÍ8­ØáG\ŸzðÏÞÁb~Áå¦hÔ‚£îäW¿–a*ãjFŒV¯ðG™U§†ŒªË¡†—6ëwög~7`ç§ç[ ¤«üÑH²”ä„9þUÅœw?v~Ô´øÍÌw²ÅkQfå˜Àw5öŸÇ ‡ö¸{¶­ußúì|Î_›ûjÞβI>½ŠSë0iï䪇eÎTsƒRiz¾¡«\}ž "ˆ/@Ü};Ö>±u£O¨ÜKb“4R¡pçè ­ß6”Û„s¢M×cœûõuòÜ6 íý“s²ß[?@¥Ž«‰Åû7Q(_¦—^§]c§ÈJ f8É÷®–ÓN¶„¬Ò*‡ÚÓéUô=W»ÚÑÛ9E` >ý+²o ´vñÜM‹³qpøèé_ŸÕ¬¹·û¶£É.S„ñ‹¤ZI¨y!Õçr1šòÏë:V³p·6̲·úÆ9éÐ }1^ós¢Û]ÚÜ G01á†q‘ƒ_8jv‚ËP¹³ýÄÍäq_oÁêg'¯<|÷O¹óœZëQ„·$—mší÷•±JÂí@=…:ÖÆ›á-wWÁ±±iA]Á}8ï_sR¥:*õZKÌøšTª×•©E·ädÛÍ%¬éq áq^Õ¡mÕ´Èõ+@2UŽr?<×ំšÿ‰¯.-"QköBÍ:²ícØqɯrð„Úi3\yÎÏ–$aAöôëâ8·ƒ©¨É:‘íÙë¯è}Çá1°”¥8Ú”º¾ëM?_Ck«hš’B¬F}1íþ{U-KÄ–ÖÃV®ñÁÌ‘¨ÜsŽ­zè~,ØÜèÞ›S´æ@Ëù}Ww¿ ùþéîµ xA¦ù×2bV嘀8>£ ׋’dk4‹¯RVŠoðKîÜ÷3¼éeRTiFòvüo÷ì} Ímy¦,Ѐw¦òÁ¡}9X4Â#Ç9ªÆ™ir`…f‚8ï<¥„9@Øç›¨­ÞŸ(•nc@îÔWƒ8òÍÆ=Ï£„Ÿ"“Eyg¸‚ߌ…ÄHàÖLvßhm»±·îñøÖ¡Õí5Ž;xI`§Ì "©‰ÕŸ) z ~…O#DIBjƽï’c‰]YÔsÇè*‡‰üj¶qHd+ Ÿ_oz¥9pvà ]¹lçšË×,4ÿ¥º¤…n ‘]–>¥95цQu#íþ¶<Ì]H7E.n‰ˆ|iâ;ÛUº]%ñ‚ø\ŽÄµlxêò;6·ºÒnd‘Мí<¶:qÀªÚÍanúuìfp”• {ƒ]/…ô+R5ºÔíSìr–V—Ü~­ªU¥})Ùz¿ó0†Å^SwôF^—¨ëögÕ F2¶\C€Ä{êü;ñ.ßÄIu£áï·½œ€H" #Ñ€úw®ÓAм¢+Émp&œ®BÌÃ*éß½s·—³h>&mCBðÀk‹Õò§HÛ)ppsŽÞ°·:”e>–˜Ôܧº–âÜÀ©¬èñZÛÊäAÈ‘±Ý±Î3ПÄÉ jºtRx]RÝ£‘ (£$wÁ<ôô®KÄæ§â9ÏSÓÖ8XjNHõ8­?\Ûªym˜ÑFHaÞ±ªÜR}QêЄcŸSÔü6Ú†§A'žã oŸ_ƽ&ÃTÓõ[—B<¿Ë’yüýëÈ-,ìÐ-„×Id 6{ðzŠ×´ñ•å­ºÙ躊»–`Q‚;~•ÅJ¥X­QÔéBnñ=ßH·´™®-Ÿ¶ÔrßtzÓ­Ûj6Ï"ÁÑy3±ðÜ1Çon+Ïìþ'iV-µõ®¡m!`©ç"í9÷ ô®ÃMÖ#—Oû]³ZݹçU8çáZJÒw–‚qv±±5¥äl²JѰ9àõíX#Óì¼–f¶ŀμ}8ª÷7VÖÅBy–­9[*=kP½ºbc–BÑñœœçµ½5($Óº2ö jÌÀ¿·Š;•‚¯€{úÓÃpêö[wa—•`£·Lq[wMš%PIÆÜw«šv˜c· mLŒªx‡ V„ÑË욨î<µðäd(1ÎGs]ø*Þ0Ø1®{·jì#Ó\  *€OíL:]¿öá çåë“QS)šÃ/ÃÓÖÇ ?ƒ\ðJ­Î¥e¿‡d™Å’0rA9ÏO­zmö”R2N8ãfGá9¯Ë\[0Ôu=êiâe=…SN¼ç3h?e$¼#Žk"ÿOž ¬ ÜÜe@õè+ÑüAámV(cù¼ÙãOZ¡/‚®/<»©]£Œœû³UÆnOÞ<ìR”áËØÈŽµÐP7ÊÒWqÇä×–øÙ®&O,LZ8¸ÉàƒÎ3ù×­xŠæ+K'·F)ä)Ú£©õ¯.¸²¾ÔÉkˆ‰Fc·ðïYÆ–¯DsÒÂ'£8-2[µhÒ=…ËÔýkZÕ."ŸÈˆmòGgëøæº&ðÍűv·uŽ"¥ßëTôË9„í¶9Ôï`߯+lLá%tE\7³è^³#‚Éî‘®!•]T€è¿¡üj³Ùß_+Ý[”œ®ÜãoSþ5ÑiÚÛÉý©uo{¨Y-¢XõÇcþ5^ÑÊÉ®‰H¤R…O˜ã§?˜ü+ÍehîrS—-ìqv«"۳ݲ•ç>ŸJ}„³^êqÓœÁ *ìWÁ|`õ÷Á¦øTjz¥´—º½°ŒÉ4ˆƒ9$ üÕ½ª^h~ÒäÖ.¥!Œ˜¥|q~µÙ8ÏëÁ{Ò½´×îîg^²”9›²ß]>óâ'‰-´/\¼°­­Øeж7nÇد›îï./ºÉ,Î]Ø÷&¶3Çýr¥£ð¯êçaá+ÝNðΰ5¨„ñ^Ë ºÂ¼:‘–ß‘Îq×J`”Æ®Œ:ë´O\ø‹ÃWº¾˜›g!6?ë {šåf÷ymÎ6ãšìÁÊŒñ¥Nw•ýåÙ¤’ÓÓ¯_‘Ž#ÚF•8Î:[GÞïúþ™EóœŠLWàÓžCN¤ÉÞÞƒ©ÅO<Ö6έe(FWW“²§¦y®þk»#›¥ÙžmžQq&pH#¡¦ÏÏ^´ÃÔàcšp6Aǽ>d‡?xQÐ]H¾´¼Ò‘Ç bˆ2qÅ¥”b€Š\w¥ÆO&ŒsÖ€)psš]£­Ž”ÀC×¥¼Ž€~Ó­b—ô¸™7ŽsKŽôìzÐE¸Ú1NâŽ(„NÛÉ¥£Þ€ 0¥{Pj)ÀP@íN¸bŒôb•@èy¢Áq£zÓÈÚšÄô£à8 B šQÇ8¥zQ‘LHð6’Íoku»\±Ãミð¯}ðu„Érrz úæ¼gák™4˜’eùá¾fÿ<þUìš±gzßg€b d#ï0àâ¿-ÍT–:²nú³ïr‹*k²;?°@ê+Žúf£]65ò®!';°WGqZºE¨¿f“p"ä$d:cëÅh=°·aàªcó¯>qÓ•ŸI§ó+é~lJ+VUfK˜<ý+¡‚ææí\¡>X!Hî3“ƒU4û[‰còã ‚ã äV–«LJõ{[9­Ì©t£î6I;‡`zþuIÅÛb&£MiÔ·¢Aq<æU¶ #³ltþèç§sW¬a vÞ|­Œ™ ÉgíʤðûGin³Ü1¹ò£§9ÅoX\ÚL²JY7JA]éíü©Ó\«VeA$¯s̵]&8^K†ÄSÊ\¶Þ2O<þ5›}áÑ$‘MnT4$ºžç=kÑuëHeÓ'Vs\ç‚Ýx®N%›`”G‚B¥EiòûÑ4‹S\©\ÃAÊn~GBéïXÚ¦Žðû4Lêà†\v5Ü9’þènÔzUÈâ?Ü€IÁãâj4®Œª¹[s̬¡®¸·p&Cº:ôÏç]Öi2 ûœ}9ü)ºò½œ9ãå†ÖõÍeÙß·öh]Ø–0NãíÚ¹=¿%›FP|›+ZÛO°¼JVDr¥y–­¦-̶¬¨6>ô,pØ>™ôäWO‰K¢C9;±ž9®'âTòC ¶©ÛUdò‰Ï^)(º²æ‰•weÐÀñäià­M¢U ,{7dä©8?5Ê|¹Œ­å ˆ+Æþi~ìmðÁüëNçU·×¬®4kÐééåƒÔ†ìkwá·‚-´kirÍ+îi á˜Çá_E‡Æáèdu°u/í%$×áþLñÞ¥lm:ÐøRi›—¾Óu»¸gÖe&Æóžø|½ŽHÏ8¬o…þÑ<â=gÄú­å„:Mã¼:vùTnóIéÚ»=o@Õu}&k&åmd‘6,Œ>é¯8_€¾(¾[źí·Ù¡åÃjÌÛNrpÏZ¼®´%‚«C‰ötÞœ¶mÛ{¥Ý½/ÛämŽ¡*UaRi-o{.ÚùX»ñ;Æ/¬k1é^ ñ ”m+*Mä*É&îœx늻ð®/ Ö¹+Äî›q#5éo†tO J¶º-¤`…ä<»ýM^mR2ë¶Ä´Ÿ(e#ƒùûQO9†_ÒËb¹Rø¥ó7ßm<µg°ï.lCײnËÈݳ3[hð©ÒR?.$„ •ÈÉüæ°ÌfßK†ëþ[_M$ÜöF3ø…©ïõw¶ÒžÓí±fR:/9àúâ¸ý{â‡4ñ µµ½ÄÂÒ)YBíÉÆ{ç·¥xØl&+7 <Ÿ‘èÕ­N”yª;/Ä/ß ˆâY_Í”wnN:c«‚‘䙋ÈìÌÇ$šÝñ?ˆ ñ ÇÚ>Â"+‡<í÷¬,WìÜ?—,¿Nµ:í¼øœËõŠÍÆWBÆŸ¨Ýér4¶¬™vœŒÔÝL÷v9$Ôr¶ÁŒóUÚJõ•Pªë(®g£}~óžrŠƒz"bê:ÔO8 ‰Øž†˜Õ£(2äÓK`äoAïK{T\«X–)°jÀu<çK8Iú~5Zæ *òÑleéQFÌ£$sžõã>$ÌjAÓ©RêJÏE±î®ÀÓ¨¥ª×®ç;§øUà¶qco…²% wúWñÅz·ƒô¹ìÒ#F7ñüC pzcšèÈhåðXœ4¯ =oŸTz9FgS7F´m(êÿáºÚ‡ÿ¶ôÖ]AZ)`>L'*ƒ‚@ë‘ʼï\Ð5¤RcÔÕ~â 18çŸzï5­BëL»m!d3¹c4*_q†ÁÏRyçþ+ñ'ƒÍÄݺyîÛ Š>lû×Ïa¨T¨íI7è®{Xªñ¤­'eÜÃÔžÇMÓŒ®ðHv–|MœïœWŽë“êWò^\â”§r’ô¯zñgìðd´“Uðó‹f Œ-¦'»HÝÀæ¼âëàÿÄ. ¼~žs¿nè°Ëí]LóŒáQ'Ùèÿ,NW‹ÂÊÓƒùjvß þ=§…­F‹âë¨Z+(†eÀxÆyÉÆOlWÓ¾×üâí=nl.#’)@`¥dÈ=G^‚¾9²øñBóSHO ËÏ™#¥…}eð«àµ§†ü9oc©žößïÝs· ç ‘œvé_ÅL¶«ád¹äõIÝzé±ôÙ\t›§V.Ëf×áæGwð¦úCw%¤¬^FÝJý+É~/þÎ>$ƒJ%Òíc’x’K‹¨¡BL‹“õ¯¤+ý£IÐÄ+§÷§Ý˜=Ç5Ø|8ñŒþÖ­…ÍéŠÃÌ/(ÆGÝ#ëé]ÿíðUü ¨§Št†çDÔ\’ðˆœòʼH®F=kö*°Ùö ™k+5Õ?óGæU)âr,m¶”]ךÿ&}i‰ôë›â /Ë5DŒ›GïóÀ#¾ku–ÆîÚ#!Xä@9ØÝǽ|àx¿UMvÎúâÊêëO<£i ’6„Û‘Û àײêþ$kX-¼»I­âxøqóF îÞ¿3Ͳ:™uHGu.·ÿÉ_§§Sõ £;¥™BRZ8ôkÿ&^O×N¦ÿˆ®­­t{­>ì,ñ2‡Á} ó†öö³jŸÚÐhqîÜQ¦U#fIÎ;tô«Ú2Iâ Ée¼¸– ·bêü¨,Cé€?J»7„u}"è]øFñV9Ï’ÔW/µ–JŒ*;5æ—š:gM×”+N Ýo³~M†cŒ°.×|:šç|K Þ»°xÜ9”ÖÆ™öƒf†è8X7¯­k\”Š!aö§šw˜”ÁèÒ¼îf¥¡ê«5©ä¶M§ÝHCˆÝ9RzîÍmÚë6:Ìöö:µ´Q4ÌTÜD|¶ôÉíúS|Mç¤â³x¶C²ýkÁÚÍŒ:å­œ–Ây¥”©f\ì’ÕÓ%ιºœ5jF“Õš7>Õ­¯ Œ<Ÿ.Rÿ+_j©ÿ~¿§j°êv{3 2Ì™t‘ÐWwâOŠº&±k‘=¯1Æ™ Øé×kSÁZÜž$¶šïNÔ$•™¿ÔÏ@£žøãUÆ/«ðÒ¬qÅl'aÖ¾fo~•·"IÝê]JútU»0ubšÕÞÈ߆âÛV½kfRÍòü¼àÖ–á»;Wx¢24ÁÊI6I]¥³Àõ®kÂV£GÕ ö£t¡ÂùžG\ç ôÍzÄ‘Cå ¸”Á ŒHà¯aëŠËuîÁîsâêÞ«æPM-ã–ò¥¸-‘Fï,ñÛ·­r¿üy௠øk÷ù—XÈE¶iH~¿{h=1žH­ïø°ø{Ã:Ž©í¼ù/¹v‰0výOñ±¬ê:åüÚŽ§w%ÅÄÌYÝÎIÍ{¼5Ã_ÚÕ]lD­NÑnßoó>W4Ìþ¡ kÞ—à}1¢üoøui¡ ›˜bKµ„f„·™’p=±ß×àÿ¾ ßxÖÿ”-ícbcOOsïŠä{ç4…y¯ÐòÎÀeuž"’n].ïoOóÜù¬VkˆÆC’vK­º‰’kcÃzúåÃBÊ‚1ûÉÛîÆH;r}ÈÅdàWGá¯3uciiö”¸UѲ 6A#×®=Í{¹Î J›³îúyüŽ:Œê(É]»à´ÑVç@W‚{,»KŸµVËN  {W)â?x1n.×HE¼’9““å3qòöÜzàn^ëGÕdki¥ŠH¤Ê°á‡z˽»g‘É/!,O©'&¾{Ñx‡‹©Uµ-tѶÿO#Ö«œµIaáM&´×]êKsz9$çÓ?çŠËšY'8^­8†~Yºö§A_OÒÈñ’³¿R%‰W¶M?{S±ßvÅq¤qIƒšy“¦·biš&‹vâg·^Ãó¬Ïèöj"º™ö!,ò:õVäãéQ%¥‘ÉQ¸S´Jì—úT´þt†/õJyÏëÔV^œ`•AxØ2¼Äàµjx~+ ‹yD&hJ‚ÈIÆGùª‚K[x ‹1Ëm}kŇzÝ‹q§³ŒÈß1ç5Buû*dÜÖ™‘ä‰Uœ0ß©^Ú#liÇ]§Øö¯+ʕΉ¸Øâ|_8fY€ÈeÆk¼å€Ç‘F~oν'IJ¡¶¸ · $gÒ¼©®šú4ŽÞ@œ•cžµÃöÑÅ_F:Á\^IJ¸”Ïãý+Ç—)yèÊ¥Œ_:¸?.sRÜÚjÒ*³Ý€¤àÇžF?ýf°u››xzÝ Nݸ?…tÒ²–‡ ª«8#. *å¼ \ p8Ç9í^¿¡\Z²A§",rCܨ¿ç­y¶M;­¤½ˆÆ}  éRc"¯ë@î0Š1šq_zn2iX.­lQ·Œ{ѰÇa€E8a×4ÌfŒÒ˜˜¤ i^´ð êivs@†”ìS¤RìƪœäÔ¨™æ)ÍJ©Š¤‰lV@R­’G#=©» <ƒšv;ç:]Ë»Û# ’r}i’™RDdl2GTDJ¿ŠæãuôÒl—u›?‰VD Ä‘žõ,¤È©„R°Ü8¦•ǤPÆv¤Á<âžSž (ˆ“Á¢Ã#=éÐÄųŒJÃo”¨ìîÅLôÿéëjÖï冸œ‡@rgN;ú⽦Ã]Ö¡ŸÊ]aRKr(Švñ‚@=׉ü0»Xg’êêøF±#áYÀÈ ž3^¡üDÓb·)gdn¤PÜqÇ­~MŸÐ®±Õ\ÕÕ÷¶šŸ¤äŽƒÁÂÚ6­nºÕàIaÖäêS<¨3ºN¼{/ôk­>iõ-ìOÌg#|GѼ ¦Æ—:ÄÓ]J „OœÜuô¯Ž®&ºÛìb|”éóW|©ugÍõíkTÖÂò9ÀhÓó ½ïé\­…®•²í5yfŠdCä„o7‰|GâMRmJúååfcå†?q2HQíXìÅú÷¯Û°8_«a!Cf’½»õÿ‚~M‹Ä*ø™ÖZ¦Ý¯ØYŒlTÅÁŒ’r}j50§²:Œ²°²)ßf¸Û¼A&ÜÃŒz×eÒ9lÙ隉4õøS‰=ÒË},q€oº‹!%HH÷õ¯-lžÕ©e¢êº„M-µœÒ"˜…â«1Œ©ö®\&žž0•îÜŸ«:qxŠ˜‡Î6I$¾Ehã9RFr {—ÁÏxƒ^Òõ‡óë0Ú©ÓݬnfJ’O#ô¬ßü;øYã;x’?^XÞÆ14Ä3!8ÀR[¿¥cø«RÒ<¨kÞðΗqÜF–utÃÌòÊ“"íÆwœôõçbçC3æÂ(ûëUu¶«]MÏS K•ò㜗³zhï{§¦Ÿ®Ç'©êz‚ ­P¸žT»W;Ší'îŸC^«ðoârÙÚÇ ê7+Ú¨£çLýÏ~£žµáîwgsJ¿m>v•–B£c¯U!ÏéŠêÇåÔ±¸wFKÏçÜáÁfp˜…Y?/—c蟊×wšÎ“½cwöKû CBcmÆPËÀ#Óξ{»¼¸º»{»  »$qó÷?\šö­Rê3à?ÄK$±ÐKÿ2–( “‚JöÔW“k·Öúíë^Û[˜]€Âç9À>kÉáÚ_W¦éZé7¯o/Ôô³êžÚj¥ìÚZwóíäv¾µÒõ;A¦KHТÍ#îÜ2Iè;Šö/|2ÓÝ0ÖK ͆b§›ÀüëÂþk±Å« [%äÍ· Ç ƾ¦øu¨¢ÂlÈ…ÿ„,o¸† }1ø×Èñ4q8\T£ùe®îÞ‰ô™¡‰ÃÅÊÜËOëäuÞøc¦"$Ÿåá‘°;qÐVü¾H™c1ÂäV‹ã« µ›&ƒOhÞ\‰žAÚ­zDWV·šKKæÝ€Y³Âñœšù)Æ¢•¦÷ØúÊnIÓµŽJãÁ‘<©…e ŒŽxÿ9«xZ -€@÷ÝÀ®J_ž_ Oy.%ÉMá~]ã¶}8ë]¯ü$©Ú@!¶>aˆ8iЧIý(›•$¹·**Ih“-ÙYØÇû©!ç'ükB1$P…êxà ÁÓïà{)R¹u9éZC¢ëw6–z”ÂCiuä&"F*sõ+WŒê(ÉÙw*PtÓpŽ¥Ùô–I±—’0ÜôÇ ŒWñ»Ãk☭lô ï}íÀƒ Ž1Ëc®@Æk³ø‹¨]ÙxNûYðÒù·úl_jŽ%]Ìê„3(ÉPÀ\WA¦]izæ‹i«Ijéö˜áâuÚêH __Æ»iBj’«­Å[üÌeR©ìÚÖß™ùÑñ‹Uñƒ.gøg{xÖž\S:ÝXðAÚqÐãô¯#Çô÷í½¦\j~8Òu‹ GtK3e(U%ƒ‡,8ô!¸?Zù‘£xÛdˆÊÀò¬0E~ÁÃS£S/„ ’“ø­½ö»õ±ù?*±ÇN3o•|7í½—¥Î»áÿˆ5‹mRÓI°¶¬…‡”‰ó‘Ô~™¯cŸGÕîm_ívR4³)ÂJs'óÞ¼sá<Ööþ<Óšäy€…êNÂ@üH¾Ž³ð§‰µ ^mmå>D !‰AéÓÐ{WÌñ\iQÄÅ(Úê÷îÛg×pj•0ŽSìì—edpš&§kfÂÒòÙsÊ݈#ŒWYk¨é/*5¬¡ ã(ÇùV¶§ðÍu –ÕôÖŠÚìòÆëû©}pFp 䮵ѵþÔÒäpvÙœ8#Ôë_!Z›¼O¯§Z-k¥Ž‡_Ô-ôË /™ƒP'Ú¹ëw7·sk7È"cÏ ÎsõéU¯oŸ\2AöRcˆæÈu>Õ>‰fÖÚ„péÊÍÕ^ÏöfÓ-fÒÃwœ·ö’˜tãsþV…•†›,WO˜]Ê|¨qç÷«Z>«ΰº]ƒÍtŠa·Énd$îÄð@ïXS©* kžv"œ¤ÛÜBýŸþê×Àç½ó…ßC&ƒÝ‰ þ5ØßxFДÛÚXÛXË䱜óÀî+¶ðÕ¹†ÞÝVIYƒHù@Íoßø&~io©)rü¸ì?*ö¨r×¥ÍmNfŸÄ|õ©_øƒKYBˆüÛLcï ‡ð¨´{íWí1H²+Í0ë!%sÓ­{oˆ¾\Þé±Ú,ñÅ´´ƒvsŽÃí\­Ÿƒ—GḬ́ƒó °;ãÆ*~G§‚…4ô2eÒ#šÔ5Ü ÈG'Ò¨Md° U^@+­º{k‰þÏärÕ-œq»36G@1^4“½jœ¯¹Ê\ZQ¾< V&¬ÛC™Hï€GZïL¹½“É‚†þkQcðzÚÞ6»{©ÍË#Èyö®ª×áö—g§n†0ÒóÕ‰õ®¦çÊY¼®ÑǶi&¸¶²÷¬²1‘ÔVQŒ^¶*X‰ËDy]æ—-¹16䕳´6@ëŒ~•›i¡[IyöI×0ܬÇ9®ÿT¶¹Õ 3ˆþeåëŠçgÐubû{D7Ž=M£ /qÙ— ò‹÷µ+G 417ãÓŠ}Ôó²¡*pjÜÒ]B!¾XÎÐÃ×Þ¯\i°Þ&NXt¼ÚœÔ¥Êu*—Ôó÷’ÎÁ焚áT—Ï%r8ȧf[\+ܾ˜²™<ç¡«ÏᵎKó:,¹`çªÕ¼ì¡£Œ¯àŽzU9òkGß»hç¯4&$ƒÂpYðÇž:ûÖ%óiöÒKNñ$I‰0àŽyÍjëw)qw=Ô— Ñ+NxUÇ|ñ\f³`úŒWq´¶­.éØó³ÀöÀǽkNvîrW›ƒåŠ8øƒûbYôM¹\µÒHAàŸ”qžœã5ÃOxt7´³Ö5©-­Ô³DñóXç©ük¿´¶Š2.|¥ ŒŒMcøÃÁZ‹³\»E$°ëÜqúW¡‚–U”1M¨ukVpci×öxt¥>—ÑIãßê×2iºmáþÎ|¤`>iä’zòkSšþƒà 5X—íÍÖsƒ”8À<ÏSXZW€5}oY¹Ó¬b1ÅŒ¾l ¨ÆN?)êRêÞÂ6iÄ$‚xzâ½f?xÎ_ ê ý®hÐ"®ÀXžIÚ`1ø×ÎZMâiºŒÏ•amÛzõ¿xù¯nd1Ûº¸‹<2ç >¼æ¾{ˆò*x^ZøZ>ìVºž¶G™KÍKSß{+gâÿxŸÄw-o®ÝH.ÑñµPçœ_­rì õÏ‹> ¼6pøÎ„2¤whXçk^Ãò¯)1©ç=këòzø|N3ÃEF=—GÔù¬Æ…l6"P®Û}ßTDˆ $Ž)싎@Í9So&š–ú×§c†ãvdð+оÁrÚô†+vš JŠØÏÍxôÁ?…rÖZ¡5ìVÑXKpΪÛ"ãpùrG¨5î¾ðׇ<$¶Ó¤ky{™üÆP†B¸'¯ I鎕òÜQ™QÃà¥B÷”ì—§sÛÉp•*bUV­ïëØòÿŠŸÙ2Ýé·v \Oi¾é#=± ŸByý+Î.y” t¯¨O,ò´·¹ÇÊO°àV;¶ùYÇÒ½¬X<%:wi_%²<üEe‰ÄN¬U“cqF0iÄt¤Åu!=(ÛN>ÔœúÐ10hÚzÓ±@Ð=)@'¥?g­=tÇZvdL§µ&*V4ݽ谓V‘ع ªB¦”ªÎø£O´”h·èM)ÚìOï6{c÷¯+Ÿ¥[Óî^Òæ;„ûѸqõ5ËŽÁÇ• õüú˜ö—itðJCòȸÀ#ãÖ´o5[há„\_ Ïμí^8ëô¯=¾Gª=‰.xè{Mž«i©ZC¨XȪAÔuòªÒêWö¦*|æ~O¶sÅyŸ‡¼Cz“ XadPÜ’0<}sýk£3I,°Ìб “»qêGùïW£gq½‘§›5‹I<Ó~æðˆ±Æ?Zåæ–F¼t*6Æ PQÇùü+°kÖÅ—.aß™®eáµK‰UÝO͵IïžÕÍZv…Ñ‹‚§ª,[_e#) ŒÊ»›qÂcY7±-ôŒÉ¦C/Ý5~þôf¸òü¿œÑa\|ºÔ¶ð¼ío—zsž:þâɺº“ž¬ÂñõÔ–zsy A‘•$ƒÅxõž¬–“Å™ÉL8ç +мMrú¤2,#;T9û§Ö¼®ïG½·‘™QNÃócŽŸá]hs§Îpâ¥&îKD\Þ,ö7lÇ9dcÇ©ãµC.‘Ák«æ!ƒô£üâ¹øf–ÊûÊ”þò92Àzœ×]©ªÉ¡Ý^mdòÉÏ.X©þgõ®ØÑŒetaB ¦ßC2ædKëk{S¹ƒç+Ó¦1ú×Ckg}p× ¨ŠG˜@Úvÿú댶šms12Éb§øøâ»Ý:î VÁVÙ~o/î°ÀQê}O¥qâ!f™ ¹¶™B9oofu±„F™+æ1ûÜžƒò¨¯5ÔÓ‹YÛÓ ®Ç§¶?©â=BëL´[N‘B³)äŠãMÌ÷CÌŽ_™ îzæº#Éîœò‹æ±Ñß\<î²´…Ì­ÈzÏÕf·†ÏçPY¾R[¦*©í­,²Ü 9>ÇJäumzkɲ˜ÆæœŠõòl—™UNš´SÕôÿ‡2Æci`¡i?{±‘¨óå)¥³ÇJÏcS\HK`V5ûcÉì|]ù›—qæšE8æ’‘ij¥ïKŒÐŠ1ÓŠ~0 &;SÆ`t¤ÇµHA›HcBäà÷¥òðiiëÇQšŒ) ø2D—LMUXØ‘…ä/uÏ÷y¯Yñ’]IdÂ6 ÆvŽø¯ð^¯ñRÂ÷T¼ñ¬ ™þÉ›,ñî%CqÇçš0¿Y¯IÉT~ëZ9wíúnj3Qö{õK·ÐÎ×¾hz…q,@Æ@ åž„õ?ξPñ­Õˆ.-§QŸ$*àyy8â¾ÔñÆ·¨ê:\ŸdÒ™îŒ[Ö0xÎ3´üמ2º×/õ—¿×­ŒÎ2±ã…QÀòýkìxF5ž"¤ª5·W¯Ëñ>o‹Ýá)Æœ]ïÑin·ü $– Òh¥hÝ2ºœGzn¯{{©^>¡¨\Éq<¸/#œ³Sˆ¦H1_|⛿SóèÍ¥ËТyíNÇqéOtÅ 9¨)³B×]ÔRÍôƺ‘­ä]¦2xèþCòzOxšÈ’ú=Ú…–œ ÃŽ}ñXf<ô5z×WÕl3ö;ùáÜ9òÜ®jWîìÔŸï.ÓIm.öÜŠóáˆ'µužøÃâê—7¶H·) >\s’BÇ‚;W5Ä÷2n%iã,Ç&£èsÞ¢¾Ž*<•¢šePÄÕÃIJŒšhêáex¶/Üø¾×R{{뙚g(>ROQ´ñŠôßþÒ>9×4+»MLm& ØÄWX‚£ƒ‚xRy¯ ˜uŠÝ׃Ěƥ¯jZ›Z[D«hªúÒHfØ`~'Ú¾Ö½€ÛÙGkax‰§ŒœWæc*Ún4íh¥§gÔý …¹Ö_=äÛ×·CË/îFšñÚj6m ׋9Ë-Cyâ?#ÊkXBÿuŽOæzSü]Ẻ×,̤ìzŠäü@÷U¡f‹Î¦@ˆ|Ì=ï_=†¥N«QŠÔúz‰Æ<òØôŸkך…¨k{„Ì ùåÉ%Æ P9ã¾Æ½—Ñêp*VIåaÓŽù‹M×n!šHìåxä+µÂÿtŽkè? ßÛ­¤–óQ€Ã¿½'MÒv{8ó+¡>'ü2ÒüV°ê@©sláüÕ†zއ©ë_>ø¿àw„õË©VçG´±®íò‡§ T|¹ô¯¨¤º½y6‘eµš>\g*}ë—žÍ4Èf¹kxöIÎõ–ìÔw¯O ‹¯‡w£&Ÿ“<üF_Gޤϟ¾|ðǃõ«J­¨º:´SN‡óè0 æ½3T¸¼Ÿ}µ…ç™iäª0p:jÜššé­D>RÆOÊz†ãP¸ÒËÐÃ2“8Sü8ÏOΧÄb*^½Ûów:0Ù}>Z*Æ%¥ÅÕªæ[ˆÝs÷HÅR×tk=vÉ–ê4f ÊÓ­upÛAŠÎ6YÎõ=•ÀªzœR ‘Ý69!þl~?¥a*šh‹Í{žQeá[½î/"ͮñ9Á¦=+»Ð¾6¯qäó}ˆ´xÄj7Œ‘ÜÖ½„mà(àg-׆«êpc,‰©H²[Ê» <âµ Pñ.—uåºÛ]EpÄ£¶åm¤“Œucóª#Ö®l[MÔ"œÃmA $çç×ð5ì«T‡1¼"”’‰ÕGá8¦f¸Ò§Fi0|–;™O|{sR ›UòîÑYË0Xõ"¹ÿ ø’ÀÏÞó*û£ ¨ƒÏ¯­tê–Rª=&•Ö\…s‚·=ëŠt)9sJ*çZ©Uh›±v Þ2Ÿ±0ä¸çéíSÚÙÉ¢I²H…Ñ•Häð=ª{;˶2wýõlóíš·&ûEó ·  ““žä~•qKBy¦Ý¤WµÊЯ!ÎDœúõ«H_é«¶Ý3*dkŸÔ.dò̯9_(ƒžI®_ÍmVRͳ9ÝÉç¡Ö³³’æ±n îÎÎî89»3ryÙ‘XdA3‰e`Ìÿlö¬†Ôæ˜#¡äæ¤û]Ád+•nrµÍ&š½ÍRÒçCj<·*@tÀÛŠIÐͺß&+É\µ#–SÆ àŠžýßÌŽH$+2ó‘Æy⳺[*ÊÜÇ5«i·š çà¬Æ@Tü§ž•Ði:’\Ƴ\º‚Ýè=ªÎ´lµ ·’å|ð»—ž^[ˆÅÁ³ž) |–;ÇÞ_Zά9×1´qºHì|]osX[¸Îýù§µrúf—®5ÍÒ¬…cB61.:òkš¾Öu›Qf²Ž9P¡[;±8â£oxß_›û2ùaÓ,£R­d%n==k %¾íåÍdoëÉoinú\(fº½¼_0íÊ"© Øõäâ¹ïX\É¥K²*YbHݶ³ç†8úÔTÙΑÍxf’EØL͆#9ä¼÷öã5NÑ ³Ýß½¹ˆ’@r­ô¥9X%ðó½Ì?즶³°ËåUítèŠ.bàð˜'$÷ý+¦šæÇŸç\ÅÄŒ·í5´€Ä‡*™Çnµ¬ãu£dåÐâ~$x²ÏÀÊt­8Fú¥Â’áå’v1÷é^!¨jú¦«+ͨ_M;9ÜÛÛ‚~;šõOŠÞ×~5·™Îà÷QœÃ nN+ȱ_ªð¶jPÖ_i½ïÛÐü³‰ëc>¸éb4ŽñKkwõG5êôÛWRºµòÉÊ1¡$ð¿åøÅuþñæ­àýî*Ô©¹`†ã¯ö<þ•èç˜Z¸Ü°ôRæ•–½5<ü›O Œz¯Ýöô=ßâ¶ocðï_{‹µUKÀ€ÜäWÊ>Q'¥oê~$Ö|C ]VökžK‚z~“WôMÞÅWñ6›zÖa¾äiÔ»²F:­yÙ> ý^Â:uçÍ);ÙuÑh»ìvæ˜ÇžâUJ1²JÍ¿ÍöÜÉÓ¼'âZÕgÓ´[»”nCÇaÁýk¢Ñþø–]zÓNÖ´é­-ÚU[™˜aaRp7Ó5è¶>.ñ­¦Z[X ;CÑî¤t…¦“w¦Õ§OΠð7,âÓ¼E¨x·Äfèi@µ¬×2„e'ý ¿Jà­œæ•#?gN*ÚY6嫲ÛK¦oO.ÀÂPç›wÖú%¢¿­š=/J³ðž‡lÐx_L ‘²´“2ïi<µ 9=²¼»Ç~*Ôã›S³}P¹´·h¼ÕŒ ç8¯3»ñþ¿-”Ú\ZŒÂÊRø˜“†9Á?•bßj—4Í7úæ"¯ HéǶk›Â5•ok‹©{;÷z[{›Wâjc½×k\˽r\òj Rާ­9Ùž}­ØSÙF=ëóIr«ŸAIŽiäQÅ.ƒô£ŒRОjXÀiª{SÀÈÅ4&#h©<¼sQÉÇÓz ;‘“ëKÖ‚3F) *H¢2UsÅ0zT°³+´Öúƒ½´"òðqŠpùAüià‡v-ÆM.Â(°¯ÜoQ’)›9©Âñ¶†@ƒšv&ö Ùž{ õ¬¬’DÀ©¹s "Ça§AõZzô:°§ÄºÙ=}:ŸTøoÂÉ£M&™{zmV;©¦µfnFXü‹Ÿázê´½LÔ`º1LÒɸF¹=Ãs^/ñnéüGðëÃ~#¶–IܪHA9@ÉÉ>ƒ ~$×Aû:ø‡PÖ¬&Ñ~Ødº³rçͽ^'Ói¯ÎñyeJ˜ŽR¼“´•¶Ôý ›B–1eü¶‹ŠqwÑéÿ{m¥œp²YÃ# ጠ9ÎXgŸ¨ü«EÝÚ$‘YÚùã¯JæŸW– …šI³#q#¹9æ´ü7­Ã}¶g ‰¸Àÿ>õáAéd{'oxéìî ºŒÈPOucÛ¥f_ÙùIržp!‰êG-´‘´eÏ™gyïÍf‰d2ù/32¡;Ær9èÏ­eRVFr¦‹¾¤·vɰmËóªÿc¯±ë\oˆmá†ÊàÆŸ1R;úWA¨ v‰cIRG-ƒógÒ¸Ï4ÛÉ´š1ò¡Ž9¸¯ù]¢Žj¾â0$ò­ÙíäLº)Üý÷Åy¶·¨‹©£Šb±•À^¹ÁÍv³ëÄ—"ebJqÉàrGã^o{2Þj?è¤F ’¡ø'ZïÃÓrQ8ë¿u$KÝÃvˆÍÀSæg¡î O®ëêïq¥Eó(Ú~CüCáQéòB–'œ¾da¾ö:·÷›ö9iÉËc8ëœþUêS¡)Ý$îqÊ|‘ºê>Öê ‰a³¹a2 :ƒŽOòü«Ðt„‚ZÜï'†‚qÐÿ*ó{ýÞñ%šâBb”³‡¿1]‡ƒüq¢­Ø·eùä9_1z“ØUâòL|iûOc+-^‡%vRPçWâ6Yƒ2¹l(?îñ\¤q­¼r]ÌÛ Æ»¯x—Nº½{kWŒ»`°SœdWâ…eÒ>C€e]ÃÔsýqYex9WÄÓÃVN*Myiÿ¡¦*q£Fu©ëdÎgRÔä¾mvBBŽçÔÖ{6J‘…C08WìØ|=,%5JŒm| J³¯>zŽí”暌õ©ØîT$`óM— ÜJ1ÞF3ަø›I8§º;TçÞqKÞªÂïIŠqô4ÜbÄ94KŠ1Í!¦7m-8ZçÂâi@¥ô§…æšD¶&ÓÛ¥;o=)@§…ÇZ¤‰loݤ4ìg­!çš Îçµ ü©¹ÇJ@8]¥øãÁÍHKøg­@ÝqïMÁ§°î)J–Zm*€9#¥(‚)Ø,[Ën‚A=¸ºa $lo_z…²Ä‘Þ€¹Å<'­;r0¹íOXK0TÂ<ŠžÏ丈”݇uæ¬.kžÓðÃá‚Ocþ R:ØøÉ' #°Å{w‡<5/™1iÑ[ÚÛò$‹øºzôéW< ©Ýë=¥ÛhpYØ UGîëœWB5I·}žÍ×n@fPO8ê;×áøºÕq¸¹×ÄÎ÷{vì½Ö°X*t©Æ”Ça¢¥Õ¼1µˆ8ö†dý~½k¢ƒUvbÄÝ—éÞ¹Ï ÚÞ@c’ê阺î*Iç=5Ðh©`.f‘¦ ùÆ äþJåw­;Ü­N%æc"¹rÄŒíbˆ&XÁ¨54¯n7ñŒuúU;ûµx#R¸nÆ )R•Ü™‡µº±ÏkZ®ö`Gºý+¼1HÉ"¹†Y}+y´Ùn§´ƒ’ÇÒ²ßLctD§hîý+£/eNìÎÊs±›qaä̲Éó… £¡¯.ñOÁè|Le†m#Ì,IŽDmúöû˜¡VÀ¾ÜÔ‹{ Ç­c ul=_kNM?#·êôëÒöU"šó>Z׿f'JÑ$škÉ¡¼ ùXpGücùb¼Åžºð¶ªÚ]Ó‡`‹"¸Ü }ÿâ]55™ku\(s×ë^k¬|,Ò/)ê+Ó> |â]ÜóêíkagÔÆçlžGnõÞxóöh¸ŠÆMOÂhÅÓ“ö­O„Õ>hzŽ­¯ÌI,jðDÛŒm¸ t?0ϵ}V7<¥‰ÀÊx)ÚnÉ.»ö>OÖÃc•;îÖ÷ã~»ü™õؾÀãUè¾I[¦ß4|)"º6×R¡¡šúóâ-ŸÂm'JÅv¤×1E;¦cìãêp+„Ò>øKZhõko¡·t °N¸ÜOCŒþ•õXn(£R‡·¯NPGº~Cäñ+^Þ…HÎKu³^«SÁ;OåG–IÀ^M{­×ë¹uY4¸´ôxUä$IÅw¾øàãia¬Ãh'óǘ;€ç½JËýpÁÆS‹O§_øbÿÔìd¦£+uéÿfü е2…¶¢ÐGigì‘bí'-Üýßå^÷á=[P’Ñ­/Œó¶Çn2¹®oÁÞþÍ:ÝÒRöe³¶R0VÞ ?6,k Š Bb¶ŽbOeOøüÓ2­õºÒªþÕŸÎÚþ'è¹v8J*Ÿk¯’z~õÊ$°¶ØòqÅy߉íƒO$!ê=ºu¯G‚)ÚØÃ$€ËÉú ãµ.o´3¸ù‡¨Ïjó©?c4ÏE¯hœO¼kÏjÙf»D¥ÈçÒºMâ¥Î”³ª+îýÜ€•wäu«â \´C•nT㕯/ñg€5 눤·»o² o6Ý«VËI]>+‹¦³Œ#¶ÀðºA8÷kj°¾©ÝÅL%¥Ëk›ÄRu *Ÿ˜ŒJ¸÷ÒÝÄ Œ&HÅ`]£sqäü¤N­»+ƒŒŒôô¨&ñibr<³esŽ>¹®MÜÚ÷WHÖ–ÒëP´wsÓpÉ5“=¸´ŒÃo&ò{Æ~îj®Ÿâ?‡¿ëU¦¸f>C¡!j–—“mw˶`ùl‚29SŸÒ­-«\D’@ÌåAx¬*Óå¼Bi¤¢ÌíZóì’8hŸ«g©Åy_ŠuË;ýr FU·‚$ Ò/aë·ê.[GðìºýÀó|ˆÀXÂç$á““éÍ|£{­_k/5ôŒÏ Qœ\ôZÞœW&»”cÏh½fÓµ?k­ž.f¶”‚E6Ñ»>˜ªWÚŠ´»É#ÓŸízIÜTNG@üúzWèÊs$ÛÀ  rr§Zï¬õMm³\Å Š˜HÎX•èyÆ3\U#Èt×妹¯cÿk ˆî¦"Õ•@x—Ô²»ŸQOké"¸aŸœϽk¥Î©y¹o‘Þ›?½p]}:ÅRÔ¤¶±ç1ª–yQƒ–ÄB£©ägj/À2E.ÕdzšÎ¸V‚2îàŽ3T¥¾E˜¾Ä1¸åä·ô¬Ë­@\Ì–îà*6túUEwÐ%‰©èÝBK ý.âÆè&hZ6Ç8 ?Ö¾uñ&/‡uY4ögïC2ô‘2@?¥{Tó4‰˜Rghk¬#; '×–üBþÕ›[yµ])l$Œ¶ ~§qÇSÏ5öœV¤jΚ~ëצþKsã8ÅÐÄááZ)ó-n·{žÚw›0‡ìþcy[·lÏõÅ;›x¯ÑOsó•&‡[NÖ’$ѨóÕÁ>ݫ׮µˆ¬¾^_Ý2]Í©º²FFV0xíÈçßÐv¯n¾µnóRº}: )/7ÄŸ2 Î¶ä+É̲ÈãåM½9d›ô]S/Ì "¾Ò²õîCw­ÞÝZZÙÜ\1ŠÈ…zmÉÉþCò¬·žBHQÁ¤—,sž)u¯B1Œ ¬¿¦q¶åïI݈¹cÍZ' ŒUu\3VqòãÔ’æ[8î¢àp2= žÄW­ê/áß‹ì}ÂE©Ú°{¤M²òã>‡ŠùìÂ+‰æœ?s5iµ·“}½{E—Iâ0¼°Ÿï ï÷óK¿¡Öêž&†÷J—YÓ®U™F͇…äcô⺟J¶×Pù×jë&ÂXÿ sí_6xÅóxBöçKÔão³Lû&“.z­zî­]Û_Goä9·`Œ&re9éÏ_»ùWÅæ¹TòºÚk³î}F 5†eITÚkuÛþúÍŽ0‡ÌjsÀ8þF±ï´ù¥›6,É/—*Žp3¸‘øŠ¯áíKíq"G'ï£ËGUëù×Mº$ê³n‘‘‘S®îx>Õä/‹SÞRR§Ì ñî£5Ž¢šf˜JÝD¢b¡¾ú Ãß\G¬^ÝÄò\7Ì:u5ê~ Ðωåó›÷rĦ8äÏÏ»’=†ýÚâ,,üÉ$± ™`bœñœëù×5jK™¶q¯}ûÆ»©éÞÝ_®T´ËôàWø‡ÄÚš„·µ¼%›bƒÈ»_ŽÖú®µ§Ey Ž&·fÐÜþXýkËËó_¤p¾I†£‡†6^ô寒ùŸfu¥^XXiýì™nnNÙÜnëóUûj6±,qÁQÄdž~¿QøÖNúFr+êêaèU³œ·‘óôëÖ¥ðI¯˜û›„’w‘bTr@úgšŠÈØ#GPj»Ò#2° ñšÑi¡oRý½Üö·î&ÌŠs–ç?Zô]OI:–žþv#& Xcøˆãy°5è6> mOBŠ-„½ºª¸ÏV©¯âÚ3§8Ê+X=_m­ò¹ô\=R3u0õ’[~gº•'¦EC?1ÕÕ`OíI£V ®û¹è¹æ¨ÝÛíÞE‘ H=ÈÈþF¾®•hÖ§‹í$þóÀ©NTª8>Žßq–¾‚‚ Šp^ôÍy  Ó±Ú€;Ò±MˆëE;ý)ïL.4ûSqJsž”b•€JQK@Íàiqɧ¢ÀØ€O"ÆiÊ*‘ Š«ê)Œô§ž2˜†œtšNiÇŽiµ%~”ù¹Å7¯4½ºÒ—;Jv¦â”Šn(Ú)øÉ¤ÛJÅ\@9æ—ÒÍ< Šd¶_Ó´9õY­m´æM8;Ã|«Ë`ƫ½…ÊÉجĈ›8£4†YHQ¼ªcÐTñI{x`´F–RŸ»†<“ŒžŠ=É¢Ï{èMZÅ‹›Öñ¬ì”Ëå~í™Ná#¬=jô¿†_ æ}FÓ\×à’8¢1-ÌD—ÇLóëŠôo€ß gÓ´èõ gLk¹”HÀ$&>QŸ×ßZÛøŠ×Äך•®™ˆ$“Êd$c©ð9çÍÊx<.ËG+ïÞݽOÐr>‡,1˜½Þª6µ»_¿¡§ Zjþ"+aodtý>#´|§ž™8üëÐtï YiŒ°Ûâ}Éœ°ç"²ô ë¤&CjÀ#dg€Ù­§ÔîRxî™4Æ8ïøWÁ¦çvϹœ\,†Ä‘¤ÑÝJ¾YàŒtâ²>ÝlÓÉ,cË‘GÞSÃJÏÔ|KÜ-5¹!ƒ¼Ô¶ û¦ ù€ß4ÝàìgìýÞi­µÉdy·²$C€[©ö«×w¦æß T“Âjã5‹Ç° 7ã¦3üë&ÎïTÔ5ºžå¡…X,J:)ΤÚa v‘éiqo1̮Ъ0*‚ÀòHîp9À'¯åPéSÅ,×3ù„HqéœÕí.êÔ›‡óÕˆœÆ:‘Ó þUœ#&µ3”#M¶Šš¨H¡,‘“—ÆqíYoos,Fw¶w²õ½¨Þ71ViéÎMTIçF]¨BÛŽk ‰ÅìuQ“Œt0’g—Ž#޼ÍG¼ÚÒȶʰG VŽý+F}2ÚíåžßYÛ£S’úV…¼;¬¥-!\$žž¦;ZöܹԾÇ7kª.n¬V`î[*88ã$cð¬Í^ʰÉwû¢dÀ–#å‡V>¹…q÷šF·aãÈV"Ø-æ;)$mÇþµèèn¬XKHWæÈé^Š›¢ùSß©Í()µ&Œ)`¾„ˆ¥¢ãÒ¥žÆ)à ì¬AÁ^«î)t]h ‰U°àñж¶Íi}û¿›gð‘Ç5«i$ŠäNö<³Å_›Å~$ÓõÍK[¸?aŽ8±µys“Æ2NsÅvRÁ“1p' ÷A®¶çL ¼d „sžÂ¨Åb÷¶­è@s‚+LN2®*§7xÃD»…ÂÑÂÊu)«Jz¿3ð6˜÷ö¡:ÏæGtv“p7:œò*x±|kâøÔ>ƒçÝéù཮7.=HÎ+¦´¶ Þ ÉÛ;†#$}ÇÇ@kǾ=iCPÐO‰¬®n¬¦hË¿  ã¶0>•Ù•¨cqV¬ýÙµ¯f¶ÿ/™Ç™¹a0ïE^TÓÓº{þä{gÃØê~±»û@¸»…wÜ’G1ÜÙüOå]EÌW7r>ß¾A…|MðÇ·¾ÔŸNûL‚Þí”ìÜv–‘øŒ×Ø¿|E ´Š/ååf‡'ŒOóYæS,¿8=ž«Ñ‘‘æÌpQ«ªÑ®ÍW="ÓFA\2‘¼Ícjº<³Œ V–³ã ‘Åip$.͇Ž=ëœKû›‰ÚFl†$Œ·?LWÎNž‡§GûÌÂÔôx§r;OqÚ¹ wKŠ]6¬ ñ×ê W\»ºzçõ¼»É‘U‡©ìšÔݾe©ð§4)4ßX;³®ÿ27n¥‘ùtü+Ý¿e,&ãJ½v2Ú…òÈc“sÓó•Yø³ð¸xšÑ®íÕc¿´Œ˜Üôe•&¾k´ºÔô‹¡qcw=¥ÄMÄ‘9FsÔ}3_®Röõä÷´‹{+ÍÍ7%#äç§8Å:ÿÆxKk[‡2¶ÐÁTð¤†8ÿ€õük—ð‘d·2Ovè÷EÉ ýT~4ÕÆ³E¤î¥_ð§m¤“û[U€™f“zÄz(ì½u‘x3Lu•æäîŒqÎ+fÉìå°ŒÎÔõËn¯Çn¯ùþTêü7fP½h£Ï|eá]&Úó̵Œa’ ï\Ý–‡ Ï›kp›ÒAߨ®ßÄ—vó³(uÄ,ÔžÿçÚ°ìu;r»Aî;{Ö4¥)Dup°”Ž~ÓI×ôKè›I¸˜´ ìÁ!·véøW±|)øÉ¬hÛlpÜäkÁSÃ,š«]G<°±?'uéší4?x×Öá­nZhç*• zƒ× ®¨ãcuÍ»üŠŒ1ôÝNŸá­]Ði–“ù“Y¾Y~dê?¯éW.<ª\Ïæ]ꇌ’¥€û§Ëõ®fÛö‹¹´Õ$»Õ¼2ͽ ° z}ÿ«'ínuO´ÜiÅd¶D¬î$œ~>•ÜëÒ}t"¥9ËâEÏønM8½º) :`ŽçëÅs¾ Õm¢Õ£vÕaŠi'’ÞQ b2U€=A=O®k3âwįèÍ$¶ª¹›ÍPí‡?^žµç6ÚMª[/ˆuÍFoµîC ƒŸ”ñŸn€ á«]6’f¦¡#íáy¢>©öÅ :†1)ààŒú×Gá#N¶±¹RâB9=Sµ|ÃáO‰wÞ#ñ”-i©Ý saÛ”$ªÛmÎ0Bçñ¯qðί¤Û^^͉"’_(å‡ qÏá]ÅÓ¨õZ-ÉW’nú’|IÒ,uKxlá™à†Ü2‘ƒGZùãÂÖÐj×:%ÅÖÉ¢-$oŸõ‘äõÃôõ»¨Ï¬M>ÂÑ2-IÊ¥¹#ßוx³K·ÿ„ƒÌq´jqÉÇZáöê¥FÖÇD_±JF†ü&Ÿq$–ÅoC÷£9½ÅM¯Û_i6,d†S$¸ÿ¨Çå“úWSáÁ ¯™!‘àÜ2ÛsXÞ.Ó Ê9XƒÇ·<»šãI9Ùª‘¹ÄE¬j^ÅäZ¼ð²aA?0^9>Ýiþ!ÔÕ´aã\°9±Ïj·qv†;i­¼¡*R‰?çÐ çoÊÎA…e‘ÀÏ”AI9í[Æo–ÈÂrQ¤ä7K°Gg™ŒœÙg=½±Yñøyžþim˜•®Tdà’zôÇç[iú“Û†·CJ»öglôöã5.“g|Æ™¾ðÞIùy8ç_Ò²k+'±æÖ©UM­K:‘cdX–Þ%mìü.ãÇ_jðŠZêk¾,¹’ #x"8äòRkØþ=ø¾ÛÃ:[ø:ÉÚnb@²+`Šáç"¾nÆNIÎkôN Êeó½U¢¼»þ‡Æñ.bœV5åúÅS±ïL ³`túÐøñ`…çf •K’}æ©Ü’NÑÚ¯_)²Ì *’@fÚzCî+1™ÙŒƒ8=+&îk`UÚ0ãŠoCŒRî-÷JV®ìóH¡Mœçj–3¸Š2¼ð—…˜V¡RA­¿º•sœôªQDB€ÀûÒ’*2ºG´Í 8Ž´ ç‚)0}éËëBp(^~÷¦)y4¸¢Â¸4\¼æšÈGj­9‰ ·p=éÙ ;ñ€õ (4ý„v¥PEd{=¨©€ô¢€¹`EFx\‚ H$tû§!tuù—õ5m&gª+þcÐæ¦hP±¸Å#BÈ:ƒô4¹G̈ñžÔâ”S€Í ‘ö¤Á©Šgð¦0Å&¬4îGjP=©G¥(âÄ)hô¥3@\NÔ£éE.08 WƒKŽ9¥šaq f”n”¡OZ^ôì+‰éIøSÂÑŠ,ƒš\S±KŽôÄ7P¥Ç½(ÔÀdWYðæöOé·77?g$!ß8þëŠå@8Í>1œçŠÎ­5Zœ©=¤šûË£UЫÑÞ-?¹÷Åý Å?o°4z”bè¨þ$†BA?oøGÇòk¢=3Q‚¹‰?w($íŒzó\÷„üU¦O¦ßø{ÅoæÙÉg"ÛNÀ¼IT)êGJâa™à”FŸ›?Åü¿_Hø7Äwn‘L¢3&8Çlãüõ¯Î1¸j˜:®…EïGñó>ë-ÅÓÄÓ¼^cföÊydvhãA†daÆê:÷xÒjñMþy1–5j6ߘÄIÁúŽE}»ÃfÒÊÁÄd…Ï9ãõÅx?ʼn ›Åzf£mº)%[°BGÊ9$ý ~µÅ7íS¹Õˆ²³G“|wñlšö½k£ù1´¨/Þw‘¶~„~µäò·ÍÅtÞ:žyüGw-Ë1Ø¡Es >nµûSN4²ú1‚û)ýêïñ?-Ìjʶ6¬æú¿ÃEø ¤êiqïNŽ&sÇ»Î;¡€3t£¢¯$òjbù» Ur“Ì®>ƒÔu­ 2ý¬&,Ùh›ï 8ÉíQè¾Öµ–a¦XI2 Ë¸ÀEïËçZ©à}~XÄ‘}šLã+Â3/Ô\X¼F‘ÑÅM$÷M8j8¥5Wu³HÅ»˜ÝÝI9|änÔj:{ÛMö9dùHWã§#ƒúŸÊ¬_é7úT« õ³DÌ23Þ –I&«ã÷k³ß'úÖô¹%{œ-Ó_K3*ŽQ”½ª|×ÿ‡1Ý lU‡ÓÜTU«qb1¹†TLÖ{ÄѱV5MX¹ìPWÞî6ƒÒ”A½è\živ sOÚh+ï@íÇjP¾ÔüQ·Þ€Ú” 1žE8À UÍ=SЏ"ƒëT‘ Œ>˜¦ƒ‘R•#šŒõ¦a¤"œqMïÖ ´4æ“sOÛïI´æ€©¥â—oJP1@;Rà\t§c€*/^:SBñÍH¼f©"[G¸€z_À¯ ¯ˆ>!XG%»<›®$`8~îúWž@›ˆÀç«r†ÔªI—`@ {×5¢è¨óÊó¶ü'ã\³‡,”V¤aê4¥:‡d%ÊÎ ;¬¥yÉ?ýzì-ôx-íÞW@ä¯z_ªØ[É-µ¢´IPª3šÅðéÕïîŒSÝ™íƒn9þŽWõ©wM³YÏÚ%Ð"ˆ£«y{v’ãŒüµ‡¨ƒQûL-$ìÒÀŸá>ÕÜy0ßܲy"—änŸ1ÇJ…4˜­¢C"I¸“ÆTv©åç’³6…EûÄWšò[m»JíeôÊýŸPÒ©jRX”·Ë(Éîÿ®½òþã!W ¡î¸MrðÆ“†ÐÃ$šµÙ œ›ÜƒK¶]ÐŒœ~smÄž<ñé­4ÝRêçC¾‹ÜDc–È$ç;c?¥z–—®Ç¤Àêû$SºGm«œp9®'BÓmµ'¸{Ù;¤”¼\½3Ô}k¢”åJNk¹¢Œfœe³>MÖô˯ x†çO$‰lnVõÁà×ÐÔäÖü=¤k·~]Ë1ŒÂ­XðG¨ xöâ¸Z^¡ÿ zŒº{DžHÛÉà±£}+—øyã ¿ k¶¦K¹‹ÈhË?Æb Îkõ ^çùe¤,†ž‡%âM2Š@S˜5òŸÄYxC·¸?hŸW&ÝØd´A8ôõõ‰$!`x³±‡ÍÏ®/ÄÓ—'•õJÛr9îFs^»mðëÁ¶SÅs‡ì’HðTˆW9…vš;G%ɶš5’ÞT1Kn+éó+uÔc†•îüìöÿ3ç2ÞŽÎx™);Y[¥Öþ½ŠtO‰~*ðý‚é—ŠöqpÊ™ 3’0kj×âüÉ"µÞ‹në»."‘“#ó5î>8ý•¼-¨Þ]ÜhZ¯Ø§“sÇÐçldõ¯”µÝUðÖ±w¡ë6¯owg+C*7fSŒƒÐB8¯w <¯;MÆ ›v¶zún|ö.9¾EËT|¯gºÓ×oCÐ/>'è†F{/Ⱦa$“qÓ“ŒqUÏÅ«™-¥ÎŸç*‘°°3Ï5çoït§éÖº£åñÚŸâÿÌäŸæSÞ§à¿È÷?…?-õ-lYjQEnìàÛì'‘´‚ÏZômçĉ}cH›žÍØ×ËÚ^£s¥ÞA¨YHcžÝ·#{â½Àÿá¼’+ÍsR sf§ä¬=Gb}«åx‹‡y'õœ,}Û$ÒÖß.ÇÖðׯ´~«Œ—¿wfôMy¾ÿ¡îË{%´;Ûp’x kžûlÝM<ŠÂä±èkUøk®Z² E Áæ¹+½Fi¡x`wÌ'‚ÇãÅ|-jR¿³ì}´jÂ1Uµ,x®ì¨gY¶îo˜zg§òªÖ°"ÙÃunä³c õ /?ÈÔ瑩¡§ ‹‡A¹s1šÈŸW°¶x äG•ÛÎhPqŠK¡Á,SsçgKc­É ¸%Ô`íÅuöž##ó_-Ÿ~Õæú4ó\Þù/ ¤¼ou!ˆ?ÃÇjí ðوǦÜÏå™›rÈzÔ‚{qëYUii$uÑÄû]–¦¢k²Ý¾ØãU r ô­õ9ÒÖEF_ˆíÅAoá7OI'ŸWׄSΡ™ªV÷×3Ã$yaÃ1Žk8¸Ïc«âW/ÙÚXKo$·¾^î7Iª/kf.JŦ¤Ñäm;Ê•?Ö±µ=URVA9Å€vž†«¶¿ºÞVžù!’2B&pÌ€g#Öº Ê-Á\ã¯[“FípÕdÓZçìF)B7Íå3d)'ϧ9ü+™½Ô¡–ä›t©T-üC¹üëbü Ÿ Üë–ÊÌÒ~ä7|ž+‘kÖvmo)vâ8Ã2àqÖ°„9úèy3n¤œ‘蟥ӓÄëW‘3F#XbD8ÃŒþƒþú5î~ÖLЦœïò3+¶ïùéŸë^?à¿7‡4Qh`/{ Ÿk +2¿QÇ5ÞiW7Z^˶‰Y¦• ìà)èA´©ÔOš1fØyk©Ýê’Df3[#|¤€z¸ãçŸ$´²ÔÜFÅ¥@ì¨rsžß¥oͨ-ÄÏ ÃkHdx‹a‰îFx õ<õ²5§Ó5h亼“1†4g† ÇoÆŸ5¶4¯ïFÑÜç4mJòXãœÄEº1œž[æàã¶µU¼Ao,¢ò`JD¼ü¥F1ǩʒM>-*9 ¥óG¹÷}Ÿ¦F;ÓšXmš`…ˆrç|ˆÞlõüEe}»8X^‘~[TÕ^7f͹¼ÃÔ €ú}Me[h%I%¡’[ˆÙ$•N6¨ÎTé]=µŽ­u/žbe‰˜ ÉéØ tÿëUÔH-n‘õŠ6¹ýÒ4„Îß¿ãØÐ£Ro–ʼ4³Øäîô·µRÀáPò1Ø—5^Ú}Ö³jº­ÌPGò:yœH=þŸÎµ5Ÿ|?ЭdŽ÷ÄV-,jÎB¶ö9íòç&¾`ø‰ñ'UñÕß’q¦ÂçÉxºXzâ½l“†q¹ÍoÞ§ kvÕ¾îçÌæÙ­ ou)ôWüû"·üO{ñ'Å‹s§ï%ammd’»¾QõäÕ?ø*ÿÀ:¤:>§&ë™-’wP¸Ù¸ž?Jì?g=3IÔ¾(é°ê²Õ~h‰8ùò9@M`üzñe¿Š>+kº¥…ߟf“‹ki$ãAÄ‚ýb…YPÇG/ÃÆÔ©ÂïÕ»%½ŸV’­„xÊÎõ'+/E¿õèq%er¿.ÐÇž”Ç"%Îyõ ß¹YÙ¶ð¥WžW›á}=kÙr±æ¨ ,¯s!$œ:’5!8¨¨ÔÅIæ”8 Ì·µ‡cB`Ò0U—­;r¿±¦•*Ã=zÓó0=jh€¥4€Oôâ…¸=Q#©Rj4cgQÖ¬È7/µRdhò{NZ@[,ÔÈqÎphÇ9Å<­&h¤sÒ“n{SöäQŒPqF¥<­;a#ŽÝhÈÆ{ÒŽiÅNzÒ4ÀZP¹4 p oÊ+‘Òž¦À2pZŒ~tc±5I‘dH#‚…½óE484P€QךCÍ9”¯ üé½i‚ Pry$Ö’ŒŠµ,ÖÓǸ"’ ®w6NyçœtíR>‰q!™´Ònbˆ 1\œvàU ;Õ›Kë«G Ä‘Átb0z{Qn½Š;¿…¨85Ü|Wð·…ü1­ÛÛø[]‹Q†[tyÂÞL¸—=çµq8ì+*Uh)ÇgßFkR›¥' n»â—í´md 8£Ž”þؤٓšãqŽiF=)qÈ  'µ—=(ÛNÃZ¥Çq@éNíô¦!¨¾ô¡M&=©qíNÅ7´ãÅô§`S†)0iàv Ò—ñN Ži ;‰™G,ƒÏÓ× §ŠíšÛpœ²ðÄ¡Îzw®šÍt­VÕc¼ rDw!œžŸ@kâ¡&îš>º¯ïÕ“³>'ñõ¢ÿh¦§ݽMÄz2€ r,¼ô¯¨~3ü°Ñtyµ iÀs³Ù[÷[h8€ôü«æfÖR’)VS‚ýS†±Ë7ñCGéÑýÇæùÞXLS“ÚZÿŸù‘C »á‡AšÕÓt«ÍRàZØ[™ vªqÇ´äW ü-¶•/fÁQ8 ñ3Ò»óŒö^x•k­¯Õœyvc±Q£/…îQ‡á†²ño¹¹Š$B3šå5»Ò5:WWkw(Xt8¯W×5ià’îhä+äÃ#/= ñ­BæK©šIX³±Ë1êMxÜ3šcsXÔ¯‰k•h’]OK:ÁápNè'wÖý «O^ÚéÑh–ó5µbfXñºL‘œŸÂ«ÛxŠãM™ÛM¹t]ù]Üý3XŠ¥¸©#Œ`’Gy¯¢xj2N2Šiï¦þ§“õбi©;­¼ŽÙüt5»x-µm6 v‘r·ÍõëùÕýKáÅÕê%熥aÑ\Ä>ðȯ=Y"Y@#°®«ÁŸSÂ=ävòfR¸yAéÀ¯•ÕÁ~û*|­o³+ú½>G£COû¬z¼›ªû–¿3ŸÔ,¯ô›Ö¶¾¶’ á8eaÈ=j9íö~Ó‚&Àœ{×mâŠÇÅv’Ú]xnÁL¡s'–7£.pCc=êü:ÇÖóÛiº“C©Û'œRaˆÙsŒõéÖ½bêSÃûlly-¿Uë¦ÈåxhT¯ì°ræ¾Ýã¹ÀÜ[Üì©4 ù©ÖæÒÍ[Ó¯â}÷bmN­Ç[§^Ÿ+©k¤è"IþÑç:ª±þñcصáxuXàXwcØÝë¼¶‰/#¯¦@ö¯„…>dÏ´©Qß™»³t[a—h†}«'V‚;V]©¼¹ÁÏjí%E.ÞMQ–Ê!y#Œò+/«I¿"¡ˆqÜà†™w:ȶ±2qϦk§ÒìΗ F™y óšÓ–Ì€%تsjkKÈØ 1;~•RÃ:z¶\±Nªµ‰8XŒŽ@aÎ=ꬌ·$š=Å~ï½>{IÌl­!o›©ïPDncòŽ™#Ú°›¸éÁZ÷,I¦Bà«dç ô¤†Ú(=˜]¼šp¸™‰®ÝØÈü+>êêqp unž”* e-.tª‘²‰€@ÛôªfæUfTëÓ&§Ón!ã "‘Qž­Þ§Ô-ã*ëĘⶊm\åæQŸ+2cMÓÞá¶žœô¨îµ ­>Öê[DÞÐE¹Tðøf¥—÷q¡Á/Ð}E(Óÿ´l¦·º-åR7ê¥òÍy•7x¶Ï;×üW¨ê“’ËäÄ‘«…–'‚+¡ð“ªhw.wg,Qƒ¼õÇ_¥qZÿ†µ Ë{$³}¢(Ñc·Ëd¸<Ž=±ÏÖ»¯Klþ‚ÖfHæibb’‰TÔ¤¹žÆœe¡hâLã©Ï$Õ£,öm È ;zÕjÂÒÞÍHY’?#¸-ÔjyäãŠæQq^e¹©;t3¯£€ÛHø=êMs:Ž›‰‹„žOÒº½á p;2@®?Ä:„‘#;–aëIKï6¦Îet½3ÄÚ¹´{&k+|lˆ³ËJ£®YÚéšêZÛ@̱à$€caÇJ×ð”ÊÖjJWcCåPj¾y£gqÔ¶r¸­”¹d¯²:`®ìq~+Ñ·ÕÅô+42E"22rÄ¨çØ‘_#j6o¦êWr Ý¬Œ¿CҾ濕.-Ú¡S9QÕ_æ|]ãxe‹Å:šËâá‰È¯Ñx/9N¥&ôµÿ~§çÜ{†Š£J²Zݯ½_ô>¸ø6-%¼ŽîâîÄB{uÏ ¹IÀ>Ý+Ñ­µÄ—R’Ö´(YH<7Oå_ü<ñö§¤_éúEÍô«b²ìˆ‡ ÂXö>™==Í}à­VÖê·Ð±ÉÃ’@ÚÀÃ×Ö¾wv.Ûš¿KálµQ¥õÙï5§’¹ù—掽o¨Ãáƒ×ÍÛOºãH×=iri½(õ§ÆØz±"¶tN->è4Ф¹ò9_qùÖ/j’µ5iƽ7J{2©U• Ь7Zž¥q¨ZÛ@ÒµÔey€ƒÎqÀ¨4-KRÔ"‚ žæGˆHÊ­· Écƒ^xwb@è3Ò½«á§Ja9žXsæ`0Ø žÙÍ~ä´²Œ´O™¹-ûYŸw•g•³|_$—*Q}|ÑÌĨðI ÷—°ÿ4,r¡½wqÀçµtÞ›A³Š$RâPy§…SŽ„÷éí] ô6vò´ú|A˜¶æØ“õ®j++{¨ßì‹ jƒ-‘È÷õü«ãæÜàå±ô©GE†ªZÏ©-Ä6‘â8ˆ“=sÔøñøÖìV×ï™÷ ŒsߟּÿDšãH×-c˜²â?0r0OZö Ý.Y´ÔþÇÌŠdö\‘íּʩÂiw=¬3‡+ŠV8éo/_˜,à±AþJÊñÇ‹`ðž“ý¤–RN—´*íßœIÁÇ­xÇR´Ðt+-SRÄQGæ(Çßš@p^9¯ñÏÄ ¿¬‹‚ÎØ–XÁûÏýãøWÔðöE<μjÔ‡î–ý¢ÿ€|ÿg°Ëpò¥N½kE¿ÍôûÍk¿Šï=‹ÛÇ¢F²É÷œÊHéëXW^0ÔµfÖïP”G r(ÙW85͉3FñÐ×éÔrŒ5JšWÓï?1­œc±6öµJ߇¡ô£¥÷ƒîôkgЯ“Ñö°%~‡­n¾Ÿxº ”+K*º´#u㟠ü_wö¨t‹ $PDÌÍÉŒ°ZõiüT±_XY²„xçò¥q´)·ç¿ Ìòº¹N"t%¯Tû£õ ›G†uc¥÷õ:¨õc¦YºÞZ¼L²”v'%—éþqWî5xR2ÊÄ%ØDŒ“®NA÷ç5¬Ü¾«¯Me$¿»‰|Ý©È!°r~€Œ}kÝ.o5 kï5ÖÖÁ!OnÝÓè+Ç…Æ<ëvtS‹K™nzY‹ûFX¯”Å1ùNÖä¶@?ñTuí âXÃFX<-‰‰?}Ýú ¯cSèð½ÅæÆÔ-³°EcÉ~2G®:~ukÄ·Ù$1F•‘9V$ô$qž¼T&âîtÒƒ½3Öõè­©ø†ó)´í!‚³`tÖ¼ãIý í·åGṺ¤8œoÜHü½9¯?ø­âûŸøŠ{E|Yiòɧ<±ü©~ü3Ôþ#ëRÛÙÌÐAd¢Y¦_¼§íÓ^ûì·=߯?´Ž‘àÉn´ /J’öíB䙯Žpx$ûô¯ñÏÆŸxÞX„Ò%”8–8 ÏÊø#vO˜ÒüfѬ´?ý59¯5)MóH¸Ãmzu8×Ûšú “&ËéP§‰¥ É«Ýßð¿á¦Ç‰føê˜Š˜yÎÑOeoÅ®½õÜÞF/#319$œÓ$m½)LqQI.ã_DÝŸI¶YÒµ‹í'Q‹P°¡ž¹OJιpüGëNÎ\b¥¹…ãC÷ɈW¿SDÚ²èf‘è)p3Šq\~»j,h# S1‘ïO9ÏZN”0C@éOÉ'RS£lЀR1ÔP)ÄzÑßéT!êÃ`¨¥hÄ‹Àü(ˆ|Ø=Å9 ÇJ{‘³Ð¥å˜Û³N+ÍY¸\Œcž¢˜6±ËòŽžµ<¶/šå|P2A9â§uˆ*@Èüª0‡ä Ò°Ó¸…HÇÏJSÏФ†òHß6Jžœã4ì…{ ¤àÐxïKŒî$c®zpPÄ¿¥.DË´GJn3Š™†ö!T RËp? ‘v"€9ÏéRÇœR¬eˆÇ#4Xw<É=jo%Bìç'½" »±Ó8§)$óT‘ û:ãæ$š¢Úp+’xÉÅ!ù‡>”š@›+•µ튔®i6“ÁíJÈ»Œ¥=zԱøäô Œ`xÒ%²=(©0O*œQE‚àãôÏÆ¤<®Ò0V“ô0¹(ÉàRàt¥ühªpiIàSçñ§gµa!y3¹'ÖšE:“9<šo£ìPG8¥`¸Ìw¥ü)Þ”s@\n;Òvö§bŒÅ ‡áF:Ó¶·Ò—nOZaq˜ö¥ÇozwáJ:PE(Jp¦„!m=©Ô£µ1 ÛJ^)zô¥(Ä{¥(â–”f€œON”Ò})äfšq@€@â·Ïôæ}F‰gM(buóÿ€}mñbÞó]ð¢5€3½Œ‹,eNH#¯ÔŸÈWÏzݶ¬Z˜ï4岺‚ànuwÏUôë]·Ã¯Žúžo®M(WB¬® ¨È#޾µ‡­|^ðÄúß™gáèn¬÷îg’ÜNy#<úW„Êól=oÜBQ’ëÓü™êbñø T9ªÎ->ŸÖ¨ç­ü'b" Œ¬’‚·==?ÑðëÃi¬­ª#ªZÆGv f½“Áú¿ƒ¼a¦¤:LŒŽ 'ëØd{ú×%¨xcTÓuwž÷LÂYˇ—`—¦A5àfXœenjX©I´öofuP¡F JŠVktygޝd‰6ÏgR7uÚ¼á°\±ã'5ê~>³×üMª¥¶¥inL6ÁÜœóÜœæ×á—ŠŠï}*Lñòä}qÒ¿EáÌN–Sj‘Œž­]uz~Éf´«â1r” ÚZ-Dr"B ´,NÀàÖºÒî4ù½Ì{ ’§ÀjúÊR…x)Ó•Óê§5)rMY™ÑÚ<Šê$—Á’é1Eý‹qo| ,S ‚9ÉþuŠHRÀ¨ÙÉàÑR„gk¶­ÙØp­(ÞÖ×¹6ŸsŸy ܶpÝ$G- ¹Úã0{×Yᯉ־ÔWSÒü3l’¡ ¨•¶•8ÈǯJâdq¥D«“¹ºTÖ¡Oœj+§£.iÑjPvhõÏ~Ð>#Õf¸²Ò¥ò,¤‘‰pò#ó`€;tè+ƒñ‹ï|P¶£T–µVEtM¤ƒƒÏåú×>Ãq9¨Ù@ï\˜L³ ·°¦“]zö:1üN.þÖm§Ó¡ÔjšŸ‚®tÈáÓ<3-­ê… 1»Þ¬@äíØ1Ÿ­b4pLøòÆÐ:)ªxãƒV-‰óé]”©Æš²ü[™ËVr¨ùŸà­ù]XùYuèN1U@9ÇzÞ ö3+³ùªT¨6ž¤ûôüë!¯>”Ú×@OMH€Çœ1À4mä ç4ŠJgšUéN^:ÓDÜõ©ÀâuóÓê‰dMŒf™Š‘¹éLÝ)gÕux¢·yP9fÇxàVwÕ¢ík ¦d%N0y¬KíQRhÛË3Ö¡´×M£\1+žžÕ£›g|¬¬ªA9šž¶:#OÙë2[HÖh“È‘•¦?‡æí]E¢É0~[hÍSÓtë{Xr  ãž*qªÅj¸ ƒ»Åz˜X©k#ÍÄK™ûˆv¡`¢íÆx¬[­]b!ýÁÏ5§©^Ísn|¦ìk›L–VWi6–ûÄžõ½x'hÀÊž×™—®ÞC«í/`­ƒî>µ£¡Ùù0o†/•qÉîV‹@XnƒM! Ç­tBt·`ˆ§ŒsŠá­-YÒ«7î@µ§"2´ªÑ£9èNk^{D6ÃpõéTôË(Ã* IÏ=«fáâH‚nŠ* >cž«|ú¤åmË«.wƒµs:¤:„RÄà±ÁP¾ÕÛÝ[ÄÌ\`‚Ͻr·Ð2ù»[–°pqšãœuº;©JçÖ“[Blá»%¶íêÞ¢¤½™,|€ãcd`Ë€}?ÞÕì­¬ °ˆ|›‹îþèEršöË»6¸k‚ó?g þ½ªá-lÎø®eryÊÚÞkÇ$ª¡Ó¥x'ÄoE¬x®ÂßìòÛÜñÞ\ÎéÞ½Ji/'Kk–-Âcœ)#“úÖ„¾[jöŠ Ët$Tã9‘åøW³–cê`+*”Þ«òìpæy}~Tk«¦¿§ò>Œ˜Ø$ û×Ô_~(Û_Û®™¨Û™™#wߌɷãöʾq×´{+P¹·¹ d™”# ¤£¡Ò|$¹¸‹Å¬R”P…Î?¼¤8îsüëõ ÿ K1ËÝU¼W2ŸÞ~CÃxÊÙnd¨=¦ùZóèþOð¹úáÝÍ_ºÿ(é]‘ù˜qšãt)eTµº’UC:©`§Û¡®·í-ä–S»õøÅX5&ÏÖdº£ýYŒ0€Ïƒ‘éDz,R"e°qÈÇzͼ²J 23rqÏã¿ÃáOÜë)}knÑÆÅRr³HPsŠšT]y¨Å]³IËÙC™»%ÔÔ¼ÐѺȡœž+Ã~7|bÒ¾ßÝøBÚÆKÍFk-âu”*BÎ^0s޽«À¼sû@|LñÎè/¼A=¥¡`ÂÞÍÌ+ÇLìÆó»ëëíFá®ïï&¹±ºI¤.Ǥòkôœ§‚¡Bj®5©u_SóÌÓ'Z–8ÿyÛoAÚ…íÕãoº¹’g'%‰95A;qJ@*+ï}‚»ê7­: Q@î/QŠPH9Í ë@ëÅ-ÄÁ×9潓àÕòÿc^Zô1¾IöÈÁÿÇå^- +Jô?„ú´Vº»éÓ>Õ½]ŠÚÁõÅxœKCëdôÖ6wü×áúÞÃ0ŽºJëü¿Õõ(¥ŽP³ÿªqŒ‘œšg„´Ë{rYU¡u(HÒ´­ío¦ì—%èø'õë[º-­§…íÁ½°BÃ)cÇ5ùjê]7«?W¡„u¦¦´Hâ¼]§[Ø]n³rdûÑŒ~¡­Í7Ç֞ѮouËðÓÏ–cè±äq|ŸJàüm®ÃÿÛ&y-à’VHC žßA^_âoϮŎ8™qÕ‰îk×É8z¶lã*ŠÔÖïô]ÿCÈÎóÊ9g4iëS¢ý_nþeŸøî÷Å÷¨YL6–ÙX!Ýœïr®Ožš£EZ+d~[ˆ¯WUÖ¬ï'»(4Q[–,og²e‚FF Ǩ9þ•ô>»:•…–­gŸÉvç’J®óÿ} ùÚÏËûLM0Ìjนæ½R_Š0éº|M¥¨šáADVlc®H5ñüU–b3QŽwi¾‰;o÷SÃY… ­,D쬴ûöG§%êjwRKÒÅp¶KÕ(?_—‹¢ê¦MDÙ+æ7Û¦p»x'ÙT}Iü+—øQ©Ük×evdyMÆ]Ð|Ûd%¹Ç`üâ·üQ¦§„üKp#Œ41N%üƒÀoË­~ÀK.ÅÏ7w½:u”â㢱0꿎šóX¿²¾7ðoIÖI.r ‡õUø–ëȹÓõhYà»c¹»©9<{ääV~“äÞÇor_ åFIÊŸ—9üsúV •We°E>^vãŒçßó¯2¤c(òž¤—54íkžñWÁ7ÞÕÿ´3o©3LŽ'ôÏ5›àˆž$ø}qsqáùãCr¸p둜QÓ&¾µ¹ð‰ñÃR躓fsI Û:ÁÁÇ8'·zù#ÇÞ ¾ð7ˆ'Ñ®C¼@“ÅH&HÏ׊ý3…óšÖû;iTŠÕ=¤–ÏÕÁ?0ϲÚÙ^'ë˜gh·Ó££ÿ€aëzÖ¥¯jw¾«r×wN^YsYÎ팞=ª`¼dÓ$Ø(êkíÔT"£dº,äå.ijÊ„µ 椗åm¹ `ã*K:²ñ/ÄGÔ![\\~ö23½@'oëŠëþ7øI𨻟IÓ¤…¯%£ùH€MÊ c¾z“ü57ìÛ§¬>._²,©¡03Æz„•Y£:»ûIxÆÂmBãÁúX‘Ø^Gy;Ÿ½!‹åQéíŸsí_7ˆÄמuNùTo%ÓúÕIC B,ë×KšR÷_^ŸäÏ 1’ÇÒ‚»{sV2zÔRX€E}R!"“m<ŽÔ„TØ¡˜ô©p¹õ¤š•†0=4$&ÆbŒdӀͦ+Ž‹ïJAÜGNhŒ|ù©Ë®„·¨’݈ªHKvâ¯Ï€}ETŽ=«» Ò{• áÉ¿?ALd8·j{Hå—ëHYË’{”´¤eOLQ‚:•ÃeÆ8¨ñÅ&5¨˜É§g=絚rd0Áö昘€í;¨]½qŠq\3ÐÐ ’8í@†œgÖ§‘TäsÒ¡ zƒBvW&8Ï\çÒ€1QœŒ`õæž¹b4Ó&Ànôƒ Üò)ÌÎqC<„oº1NH“©¨Æá‚:Òd÷n´\5$wP»W¥F—€i =è¥+ŽÖ¼ž€ÑR(!@( ¢…t7$‚3Þ‘†FìsÞqNíÓÚ€#¥ã?….1F=iâqϘýiÁA£úPÚŒw§ãŒÒc"‹b qKߥ(äQ@ ŠM´î´cQ`°¥Àô RÓÇ|R`RçœQE€n1Íî{ŠAÅh£4h@ Py¥ùS%…£¨&—0x¥à~`Ð9ü(è(À¥ïA«íKŽø tÎx¥ U-@iQI´wú)  D•á9^WÒ•³Î(ï@?ƒ¼i©xWQQÒ®HÜ™à׺xoãF“âÔN¹n-®¦R2%ù$nÙÈâ¾cÛ“•8"¦ŽîHÈßÎ;Šð3nÂfòö“¼gm×êO›WÀ.HûÑìÿCìF_ GlŽñ­¼°²È¢L77#¿ó¨uXöeÅÂÄv…ê[§å_-[x“S(°JâHT†òÚR@ǧcˆf¥ŒQ] |3QÊFî;S›,rzTxíÖ¾©ž2CÏZx R•$â´tm÷Z¾ŠÂÆ$²°QÇÜúTJJ ÊNɹµ«¶eNiŒG¥t·þ¸³Ôï4°ÑO%š»»Dà®dóXÒÙí—ktèiFq¨” îŸß°åSmIYí÷Ç-À«Vê9¨L¡iÅXˆ0•=*ÒÔ™;¢[¢ïkÆY\-á89ö<þVH°rÁ«Vá<¿/f;ƒÐ~hÜ|¿/–ÎqN×w7C5׿ nÜU™“Ö¢+ŒT4Zcž¬GÓÒ›ƒKžy¢Ã$RniØÉ¨Á©¥2Z@: ŒŽjb28¨Ú† ‘‘L9ò?ZB;TØ¡„Ð Ï"´ç4bÜ3éJ=é - ^‡SšÞ/.DÌf7 rÃpn*€ãšp9§náè9›?9HÍGJ§ÉkCµøcªXé>'µ¹½¶WV&5ryB=}?÷mgÄËŠ 9RI ß¾mЧK{ÈfrGÉ$gß Nxö»LÅ›9ÿ?ã,-ëÓ®“Û^Ú3ô Ç*xz”$×ÅußTv– ¼´sq,¥’>6“×ÜVö™âóÞââë,±ÆQ{m=\ô®Iµ¿Ön€á7•a€G=~•ÑéÕ±X®£ѰŒ9 ŒrGáýkáêE=¾£‹I\ô{5ýÊÙÀ¥c e¿oAvÑæ&o•rs\%Œëè‘®ŠW=?Öý½Ø³K'EÈ9®9ÓåZ­Šª¹Ñi†»¸½¸V’(Æ&<1Ïý­lÚKq*‡iÈOî©è>µçWšÄÊ‘C˜VrÎ3ƒ­miZÛµªÉçlýà+žJijJ„]ÎÕ.6;[~\óÒ™.¥ÊRGÈ`@_î“\µÞ± ªN&M‡© +2m}-¤IG1žrO×”¥c)RG BÖ"Æ0Q¸8<ÖÞŒÉ2 B¹ Ú¼îÓY·’%a(¸¹ï]LJ%Ù»?.3žÃÚ²ö3*‘vÜèšô[ƲNÜ/QT®µ‹)WˆÊó÷½ª¦§p’‚ZE @kž’îq.ÓŒ`ç½ióZ£(ÐRZšSøëK³ÕF’`ndŒÈ¨N7(<ãéÅZºñ%±Xö€7{׌|OÒfÕíínôûÓg©ØK›{¨Ü©[ïŽ:‚J·¥^Þiz=¤Sjo~ꤦ9w'½z5%Ba?yèãé×Óo=Ì©á¦ëJœáî­T¯¿•»ïåk›q¯ºÈR-¬Or~ï¥_Ó/>Ò<ÒùÉÈ&¼ßG½¹½ ,ŠwžõÐÚx›OI„Ü `pyï\2U'¾§bÃF™e¨˜â9=2;U§ÔRHLxÎ8ëÞ¸ÈuÈã†2®Þ?È«–7f30š\ÇŸ7'¨úÓŒšŽ¦3Ã-Ëìëc渖C½÷NqŸJÌ™ž`  —åÿϿחæËƒÏ~Þ•^r‘q  Ì[Ò¡IÉ›ÆƒŠ¹Ÿâ›Ù­mç,ùX”äc‘Ó?μÕ59KeÁ(Í”¾èô®ÛÅ:§Ÿb×l7m¤Jó7db³^ÿ8­©úN1Ôë÷º\E}%B¸í‘ï]f’âiò_c¤néƒ\G‡Þ[¬Û°@Q󽸮ÛM»°¹K›M.a;XËö[¢&7m™öÈéë]0…F®–ßÅ®©¸Âú³È?hhçÅú;]ªE³#Ì«ƒƒhW'§< W‡éÖ¾ñµµøhÂÌ?MêNÌúWãž—ý³öh®O— y*Ç8G\ýkÊüGᣩèßo¾¿Œ\éQ ’âf ¹Š3Ôð8ï_q“g cƒ«w'å{Ù¯¾Ïï>+8ÉjFÊpjK¥ík§÷]?;l}#á­fÚ-"Ô\\ùR¢‡Øp1ÅM©|cð×…ìî?µo#ó-Ô;Ø à¼×Çz÷Åý{W°ŠÆ0-ü¨„Aãl§Zánµ ûÛ»Ùç=y!nZa¸.¥gÏŠ—/’ÕÛò9q¼m‡¥îáaÎí»Ñ_ógÑ¿k Ûè¡°ðû0 ™îXr}¿:ùÿ]ñˆ¼K+Ï­ê×7nÍœ;qŸ¥d“ëV$Ó/íà†êæÎha¸ŠI#*²PO¾Ë”àòȨP‚O»ÝüψÌ3|fg'*Òvì¶_/ó);Ó~SÛ­ké–Z$°]6±{q¨£ìënyÈ0k\ß™ºYåûCwùp@ýOé^Nzýo…9ÖUK[ÍŸ—qC‹Í*r»í[ Í(ëEëèÑà(ïJ:ÑÔŒS4)å®ö{¥M•n†­ê£d:|jÙj ÁË37ò"³‰ÃD%Ì®LágcÔ>^ˆ¼dtæŸÉûl8Fô‘NSõþUÝ|Aûf£};ÜC¶h‰B¤ãv8Èþuâ^’xuë›yZ9bzäé^³ñÿVEºð½ì$$²[‹‰¢S´’¬Ü©­~{ÄKÅç””½¤]ôÙÅ~«Cí²×êYeIÉ]AþmÁfÕ–»¤YiKå\[IK”ʱx§ÛxžÖù>M>da70ãôïýkšÐü[§üG»þÀ¸‚ :êL c°íÏ©Æ?*¾ÞÕ<5«Çczé+ÆÌdRá™GÎ? f¾7—UÀUtq –[ú¯#ì°™…pO+ƒ÷æºjún£â SWðè’ÏM¸»g·…Pª „$qÀägþ^]l$ž5W¥£åjûõZ?–Ç©K‚öu\É¥¶–z¯žç'âjZ &ö)–Cî?É…b›&½fo ÿÂÂÔ~Í­köñUÀ]aOOF0Aäד•h]¢n º¨b=¯»/%uëÿ rÖ¡ì½èü-»?A¤`Òv§‘Ö›ŒVæ(r‘éN|dñÒ˜½}ªYqФ'¹+Šp…⟳ÜQa7`Œd椊2òtã’~”¡B¯Ö½û `†a´éÞžÈÙ¡1f>¸ Œ¸äÁ¦ id2¿áR8°½*|Í6Ðaëžôõ§cÖ’‹Ì‡nìÙ¤erÎ>´æ  ÐzúѸ¶`HÍ*ßʸëOù±’¹u¦HŒ„ Äu¤Ø…SÉý)ÊÔ¨çŠ_-Ôg"‹Ã¢‡YÝ—¿­2¦Ú[,ON´Ò…N8õ¥a¦F}êXÀ<ú a®)rB•è@Åg4μPGJRrF}‚@£½&*D‰ÖXtÇ4¹=;b×ñ¤#§¡ Ü?:) ÒŠ~ÑÓ4å\©âõ§#ÁZ¢DÚ8ýiŸw¥Mœÿ^”Ö88?Jã6ñœõ¤Ç5.Ð¦Ž”cqÚ—ñ£»s@î!¤ÀÅ?h¦ô¥a\@)h Šapǽ.=)1Šw° wô¥Ç)Àg¥'¾h ˆGzÍ:€( ‰¶ŒNÛA¨Ä¥c´)H4»h€g½(_zÅ.{zÐ!6æ—n:Ñô¥'=j„ÄZpÆ(Çz^Hô i§ÖœA48¤Š1Jõ¥¢Ã¸˜£´ w¢ÂWi § ]†ÖNàé÷rH–î¬ÎS“ïßž•ŒT–òËo(–*Àõ°ÅáþµBtok­û>æØzÞ´jögoã ëZUµÄ€Þ[*·qŒ«¯@O§¸w?Zôo‡Ÿ¥ÑÒM]D»Ò.Wd‘J2PÞüçµGwà-Z¾šïÃzõ’ØyÅBË&ÖEíyõ¯šË+¼‹›ŽvŠÖ3èÓèû3×ÅÑþÔ¶+ ½ç£]:ús‚xÇÁÇzïnàðŽ‘so£,PßÄq%ÅÐ$21Ï·¤ºøm©É{isci:i׮ɲ)•aŸ§#ڽŚPM{KÅ4ÚoDÒßüí½ŽìêÎê¤ÓI¥Ñ¿ê×3<=£X'Øu FÒ[¸å˜3‡hòÕ¹÷Î?^Óâ/øFÒËS×|3iZ]¥ÏØÑ¥;]|›äl6…wä×™ë:°šìÐäG…ä¶ò²Hãs~ü4ðÖµ¤¿ˆÞù¥”9»·>`FxÎ}ë‘ñÃ;Ý_\v‹e»¤†9$‘ð„óÏÛõï^©gi¢üðLš-­ä—>%¾‡Ì˜>|¨·;Aã9Ï×µy¬þ#ÕíÞá'hî$“'æä–ÎOóüë–YÎ+ ˜OJ«š»µö·K¯™K+£[ 3‚ŽŠöï¥ìÎWÄ¿ µŸ3Æd‹PòA3µ¶JÇRzÖÏ‚¾ ø—ƾ›ÄvqÇkcm+£ÜJÙÉQ’ñê;×_=í—Š´w´Ó5ÈŒ†Ã¸“ÈaßžkÐt¿i:O€­ü1i©´a3%Ó‡ÛæLq¸ŸQÀëé^”8Ï:|œ«žûÿÀØæ‡ áý¯5Û¶ÿƒ¹ó,Þ‚Öæþ ‹·Qe0-Ñ+Ž‹÷¸žkAó·¹¹†EÔ¥¾$E$¬ ÊÿÏ3ùô÷¯Ÿu-ÿOùn eÀqÊ“é‘Å}¦O›,Æ-MÚZi¦ºt>g7Êe—8ò+Åß]{õ1%˜ÔE=sV^6î1MX÷ {6•øÖi€yuyQ“½Ÿü1ú†_Žúå8ÕŽ‰ÿV6-a‘€(Y¤5¯mçZ´‰0ýÉQ¸M  ¸a!H?(=MX¿”:˜Ý9ÚAt5ç¹Xúœ.!ÆÑ‡u42LÂÞ2ª™Î[9›yâ%ÓìÒ0§pÁwcøv©.GvÁ)$úwÊëÑ\!XrÊÇrÆÈþ¥Lb¥¸ãŠ“•βÛY¶½KK¦c4ÒXýÕúž+gPÆâÎ2ð7góþµÃøUãkĺ`Cü¯ðœŽ=ŽN+©´ÔÅÅóà3÷DZ¨$ž†’ÅßSGF¼6÷r æ¹'¾ýUßh¾.µ’ܱo—°kÌæµ˜µYHû@€àþ½V²Õ&ÓÙ­öáSžx;¿ÎjUÉÜÙ>xž¥qâQs8(Œ#ä®O¥g\k²YÏ›…‡a\cø·Ê„Ñ*bž™>•[KÔgÔ-$¹hV3¹ûÇ994½‚Z¢!YÅ{ì좰Ér÷·YóЬkºqÿê®VæK8Éd§&1¨aÔç´i6Í#¦â3¸ŒjžþâÞõMÅË&2s»ëMSw:c]5{‘i^"»‚³3îVÎìûÔòj‰·Ç+,‡$ãµsòʫ嘶«Fa½OÓ-¥¹f"`Kzš®C/m}Yèz°ñ¢´³3 ÇË]4Þ%­Ûç*_çÚ¸­2؈—2X¸·"!>â@8VR¥Í¹²«u-~ÜÜ8°ªI>â¹—ñZ³0yzóØS5HÛ ˆøÆORkºU…Èä·+ŽôS¤¢\ªivuÚ§‰Eý«ygj2` õ¬ï ^¬’ +… ’|™î2k”™á`$(¨¤ã8¥ðV·\Kv£lg,§šÞ4Ó\ÆR¯UÊ{e ”ÇÌrJHË ó2Žrùé]¼ aöw¸²]†Y·LŠ.xË|XKú¥Å·!|Äþ%Çcé]Nž–è¯2 .oÇïëž(m¤Ï6¬½«ækSŠøŸbo· /ó`wÛÐn roð¶][G¼ŽGÞ0ˆcjƒœuç½z¦±j·—Ÿq¬H›"ÆGsùš¡&§RÜ.q[aëÊ ðz£Zp„ér5~çÉ×?µ5®ŸfÆÅd8¸a¯8ï^“à/Ù꺔Íâ_b‘«ÅäA†¶{–ãzõ¯£tÑm ‚´Þ[1• ~µ­¤_ÛÉ …[ ^¯v·f"©Á¥¥¯oÄùØp~[JN§#zÝ&Ý——šõ<¿Lý—þxjõ/?³¥Ô‚FcÙpAÉ#¸ïÖ¼#ö¨žÎé:”BÞ=:È…€(Q˜…<{/è+ìÍcTµ°¥¸"(¥‰vcë_ž?üj|kã½SY º/3ìðœäЧñäþ5éð­l^e˜{|DÜ”ô»Ñ~§—ÅTð¹vX¨P‚‹¨ÖË¢ÕþŸyÃÉ;2ž”ÒK|ÀQäÓ—¡ú×é?4µ‡mõéL+R¯ÍM+Ö‹ÆpM-¢ÂñKÖƒÚ€&€ÅLq×µV†¬6qV¶!­N›ÀºåÆ«Ç-¼¡7•1œ08>ÜW¸_~þÞ9>ѼóE™FâáƒcœñØšùÇOŸì÷ 1çkQÞ½+Ä^,h쬵[kˆä>Lq¢€¸l޹ÊóøWçüY“ÕÅã)N‚Öz|×—ä}ç f´°˜j‘¯-!¯Éöùþg7ñìFò-.Dò[FÑLT}Ö x®#ž+ªÓ­äÕ-î‹(o9Ë–#'p“ž½ë˜–6†V‰º©Å}V[*4"òø;Ê’Iüõ>c3ö¸™ý~jÊ«my[K~£I£›Œõ¥¯RÇ–/CÖœœºŒSG4å!\MjòP_å‘TRF8«Æ <Ô³©hêð8'Þ‘2 vªò&ú\Üð­©½×ì,„Ÿqe€é–ÐübÖ­ãËè£VXtí¶1s€œø¶MUøYƒxóH}JhⶆS;´µ~@X~ WKñ«Áqè—x†Ô»^æin²>XäÎTb 5á×ÄP§œÒ¥Sâp|½®Þ¿;/êç¯F…Z™MJ”öSWôKüÙçuìšeý¶¡ ;íåYF3ƒœW¸hôO¤ ~Ûu'·e•Às¹ˆÇÐb¼ŒÖ¿…u M'W]Bðe"ŠL3–#UgÙ=ÏäÓçŠ|¶ßÓæ<‡6«–â#®I5{ínÿq_ lÔ¯RDÜû#¶I gÈ ò¯ŠŸuÿŠ€“PýÅŒ.ϸmØ'Œ“Î+šñ‰/üG:Kuµ#‹"(|©ŸÿUc¸;x®,‹†0ùo.&´o[¾ézŸÜvgÜGS3¨èÐv¥ø¿_òûÊ“…íÖ£XØ‘‘ÅXòòÙj]½í_Mk³ç#_38àT›<×UU$žÐzçÖ¶4¹­4‹í&U–ù²°FË•ŒG˜{g=?:S—"Ñ]Žçz»!º­¬Zx‚Óx$é 9Ã’O_¡Ùü,Õ4©!¸ðœúxžïX½b™×rÛ  c¿úÌõtz×›<¸åÎMmxÄÖ‰â»[ÍÑ®§•–\ù¨Ì2¾ÙÀ種L]i†•6î÷íªÕ~?ðN¼uK–²Û¾›?¿àÆ›m‚õKìû…”,2Ïmy*mTš2æ5#<–ŒŒŒñ¿Ú¼›]ŠK}fu–0ŒìI 99Ú½vÓáßÄokÓxsQŽêÚÞûFæËC ²&ñÓŽGÙŠæ~9xnÄRÛ@ð¥ÕªHèÊ@YGË \öÜ ükÏÃâ¨Ç¨¹)Tš¾–߃Øï¯‡­,?µPq§e~ïÅyzL ^ÀQÉ8¯\ò„=LÊJj¡=êvS¸ ¤‰oRHÎiñ$¦2ÛÜð}êO,Çò ù„Æ>¤sÇÒœ$j#9ۜⅮÂznQx¦fÞd#ØSá¶S’Ù$úÕúñQÝ[rÙ‡=Ñ ]¤€;b˜W¹zÕ¦ˆ·N :Krʽ€8£”|Å…t—+–1"4±1À‘Tçíõ÷¬VcœÔ»ŽÝ g&³«N éÔWO¡tç:2Sƒ³EÍOU[Ûé¯b·‰\¾Å<.M}MðÇ_¶ø¹áßXO·¸Ó¤:}ÐC…,Pí—§ÞeÜ=|–Ct#ô_ì,wu§ÛϲiuYP1Âåw<œû ðx‹NY{m|6·—CßáÊóXþ[üw¿ækü^Òô?‡Z€ñn“u$÷1$ÖÍlçæ‘Ÿt[ƒ»-Œ­v?`½Ð~Xéë¬ÛZMwjøÁ·óp\úާë]?ŇþñŠ|,ê±IýåÅÀBùVòòGîÌÇßÿx‡HÓ|=y¦iñG£5Ã#«¸¤uçÔqô¯Ê«Õ‚ýݶ>öœ'9³æy5kÍpM­ë÷>l¶Á­B‘Ì?‹5NÿKU×2*KÞžyéúb·õßßj[þÍl°«I» =j—†¼-׉ì›ZºEi§HÄLØ Î}«-º:'ÊÖ‡OàEc§Zòã *ù¯…ÃÁÀúäν#Ã7^Ô4§ÔžÈÉGöi£“©›8'üö¦Y&™¦kJñ¸kyüÆTÿW´ýÓÆ0)ºM¾©¥ßÉ$¶‘¦Ÿy?Ú@E†bóÚ¼Öã(½ÎJ8‰mÐÝñ.³¤iÚ:Ík£‹ûMÊ«ncÙ䜨ùNzó\N©àÿ k^Ôì`³aÓ‘ÔS(jJ:? ø—ûé¥ka^W9ùq€2s\Oƒ|m¦ø¦$6÷1Eu°oœFö¨÷­¯|Fðdža ªëµÈ<Á $Ô¨É~]<³ÿVTÛšéoëï?S§À¬2ÄÆ¢P}[þµ(ßéÉ&ù&ÚwpqøšK­*+Ëi¾`¬`Häã¶{u5ËMñ³Âw7cÍ·ºòÇñÀÉõüjíÇÄïC`Ú‡ö€œHJ tIøŽ {ž+z™g ^ŒµÛCgyeK¸ÖŽždzf&¨êI争mÕ@=7œÃgl6쮣 @ä¸=ëÌ|Qñ{XÕ'š-RÊÙ£1 ª ã×wP~•ÂI¨^LŦ¹’Bz–rM}.ƒkWŠž*|¯²Õüÿ¦|î+ŒhÑ—.^oEòþ‘õN—¬)²ÂñÌåùXV&«›¹¥“nÏ”19ÎqØ~¥yÃͤøŠ Y®vÙߟ³Ê®ß('î·  ÿ3^í>ŠËlòLB€q–8væ¼ç'–K]SOš2WLú¬ƒ9Žs„s·,¢ìÕþær0ÙÉ1ù‹6 ]­˜+Æ=jÕ¬¢7ž9ãbÄÅddœ}*xíQÙ—‰7cžµãÖ¼4–†õ¥Ì®ž…u»iÆçøxëÚ¤(2%%H<¶Ê#fDëÓ¨ªªìÀï9e©Œ¯ª*Œ§%¸ÜA$îjÅÔǃÏZd¬"Â’ïÒ£Šv¬ áAÆ~•wèj¦ïc§¶¾hâ¿OøUÄÕ7ü˜!Hàg½bZ2=¸Ž {Œw«ÛTG˜Œ{~µ“”nÓܺx„½Ò­ðßPÄó“ùW7¨+± ˆr„ û×T-¦œ7ËŽ ãõ§C¢Çv@ÝIÇz¦“Ôë§>dp“[Ìðº0Ãp1õ¬íHºMF!½‹—Ê…ï׊ô‹ ÊGgt¼Ž?ÏZ¡ÿýî•3^Â…šÕƒ·Œ8M¯u#GMXô¯j±Øi6‘ÌA,K’Ø ~•Øé7QÝLÈêG˜Å±þÈÇÿ^¼ºßR7z¦“s"‡Í8 Æ@É'û@üë»Ñï'[1tÃ÷¦$ÀŒ‘XNëTqÔ„£±ÄZ–œÓ¸Žá¤™A!T}ÞœV~\<Ò¶PÃqïÏòR¹>}Ùx¦1®GNx5‘g|Ú‘¸Óu ùroçå=FG¥ rDëÂPöq×s¢ÕÃÿ£ ds‘Ú’;éãf”Jp§;¿^kôͤÏ+r®¬Hä‚@í»ßùÖºÝÜ·n%&2û=«.IT•£¡ÖÒJìÍøßñQ±ð¤ú|’. ÆÞ/›î®>cù:ùJá‹IÍz7ÆO¯‰5ñefàÚiªaB:;ççoÓ…y«džköŽË¿³²øÆJÒ–¯ôüø§2Y–e'xCÝ_-ßßøXm8p1Þ{Ò€NxîŸ:J§)Ä)€‘Æ)ê{U&KÀg®)µ1\ç¥0­&†˜Ê)Øõ£½¸«€Â¬¸!AíU—ï*ãsã½TQœ·>I‰@¹•ÈøÀX.·0Óßt$ c&¨Yê×Ö ,v·Ì»\)ûÃÐÕY¤bò“^ ©ÑÌêfÚIZßvÿv‡±[1Upð|ºÅÞÿ~ßx™¢ƒÚ€Hí^Ý*ÂŽ´é8äR)§HIÇűnÕ£– „Ò2 »ÎçqíÁ5|dŽ´Ë|ydzôo‡ÿ l¾!èK§k6öºå¬à-´Ò*‰¢+Á\õ9ãŠÃŠ¥ƒ§í«»G«ìkCS?eI]öîp°ÌÈwÆå[dW­é7wß¼ ÿ»Ü¯öžžáá.s梯Ëôî;õÄøÛáψþ]­ž»jÈXà6Þÿʵ> jéÿôÉ.g1ÆìW’6ö<çé^Nhèã°^ÂÉIÓ÷âֺǧÏfz9g´Áã~§ˆMF§»%äúÿ‘Ëkº§á»öÓµ[sª¡½ˆ=ÅgWØ_¾é9²š/³¬WÑZG-¬È!Âî+ô*z{WÈ3C-´ò[L¥d‰Š8=˜GgÐÏpîMZq·2ýW³ÌžYMd–°–ÏôdtÒI_Dxd’riÍJcÉÍ'ò8TRÄð&¥«jZwÐm½¼·3$q«;;U$“Ú·¼MácÃSA±i$ |Eñ^­£ï½d»´»Ö\ÎÁ~{pª$#Üœtûµæ|y¦x×MðûE¦Ém©Z}¬^³‘ÔÎB®;`!?pÞñ¿ˆü!pÍ¢ê3C ä á òH3ÜzöÏZ©®]Þkw—ºáß=ÌÏq!s¶OÍx¸|’qóÆiýÛimjÛÃÎ':•l 0šßí_[êšwÜÉÈÆ)S¹ÕÉX`ŽÖž¨ÙW¸x„¨¡˜p)Ó˲³Â…WŒ)9è1HT·¹¨Ôb›ZÜIè<3ºŽ€T†AŽj!KNâhc9ñíËǯJ#ž•1Ï*‰Ý’‰P(8äS¼Ðà©ô'ëUºœãàØ±EÂÁ peé² 2œŠF$¶HëO‹aÜ$ãŽ1ëRPÝÊcÚSæ';©be'tp¥†{àt /Ӏܠc¥ d;HäjCÈôÅI‚´ÆîžM ¹¥ôâ¼ñHTã4 °.íü™³®mœm\äŒw¢ÜDìVYZ5=Âç½23±ÖU\íõéš@å$ dô¥m‡}ScœœSéSNÌîe |üž1ÍDÜ=ø§ê+öH {Ò`sBôÇ¥-IC¢POµ,¡~èíH¬GãHryÅWAuÆ)G4¤Ä)X` ¢EœâŠPÁ¦!A4üú`Æx£¾E,ŒH½y­DzÒ£sš|¢2¡“9ïŸZ{‰hDqŠm.=ivûRÚ:ÓȤ›ip(¢€ô¢’”PF(&ŒžÔ€œQJ:(;õ¢Š(hŒRQ@úRâ“<çéL¤Æ:RôëE2XœÓ€Å7¥8œb… RJ¼Ó@:šA ðsï@~zS;ò)ÀsK¸R†h6æœÚ”sNSÀi®ÙéA'Ò;Рךr€£'©¦{Rî$}) VØ*ç&¾’ý“|?ª´ºÆµå·²·fƒ+‚g#bóÿãé^3ðÓÂ7¾(ñ^k”ÒBó©gNpN1ÏJûz?†öi‘ˆmW»¸*œ;“¶ ǰ¶8Î=«äx«1* ·–­öÔú®ËܧõÉ;(è—{¯Èç§¾³“â|ú¶­º3ÃV‹mi ¢»©PÄúàç§zƽ];R½–øÊ’‚ÌòäåGOÓÏë^!Ò¯4Ùô¤~Ï,Á%”0̇p$“×@ÓÇ_M J¶vso{)–FÝÊ©ÎÜŸOjüšueVMAm©÷4jºçj÷-øƒ]¿‘d[+# #laØn9=€è1\’ÍâKk¸u÷I çd¿ÄAëüªú\BæÿÏ’S;GQÓåÏãÍh.«io¢Û˾VsˆÖF,7rqÛ=x­ã7ÊÝ®úƒn¢»dº'ÄË *ÚâûÄwíqzÃh†ZSÛw·#ò®ÓUÔõkX­õ-44ºmÚ·mØI9ÈÐg8¯;ð§Áï¥Ö¹q)A$Æ£ÔaW硯@]Dh6«à°‘^ÙØ¶ÉK°Û*Œìyª­8¨òîÎ7FJ[X¡áßøªÃV¹ÍÀW‰òß7ðœü¸öõÏjµö<)™Ç „$ýÙ._ŸOÄó8‹ ñø(/z:ÿŸàyƒ ÇªÈ¸$Õ«cÈ>•#C±IdžW¨IDÌxlÒ1iNwg¸¦ªÔ~é¬e+Ú執Ç»º¦çWZúF© ʬR-ˆ8ÉÈ5Ï«.×2ãŒÕ˜\.бcË^8ë\3œ¢ïrc¥¹ÖÚžg–%ûÝ:ó[¶úk‚ >ìŒd•Éiͨ!†i1"Æ×icq#Gæc A`Ücߟjµ‹š—¼tÆ´àîÂçNh®-¼£¹‚—\œc'®]إͼ±ù;U]À2;ÔZ-ÝÖ½©Érðˆ¬­ŠÝ±‡”ç—>Üq] a'VÈemÛxÝéŠôS}NèbcR)½Ï-ñŸ&“>ƒx%1ÙXÞ±¹ãûÈT~?©®›IñBI<èÏœdehÏ@þþÕÄ_ê7÷2]]JÒI!Ë3u5öü?ÃnsŽ/½ÝÒïëåùúÅU P– ï7£ËÞÞ—©Ó$žIïUO&ž[Ži•úw?.JÂ~4 àæŠP¤ö¤0$ÓÔóÖ›Š4*·j\ÍFãO^Rd±J€2i‡“R,*,`ÐÐgž=jçÅT«*s¥8„†9À¨Ç̤YOjv & h!ÏzQÏZJAÖ¤±ôSsKšrŒµ:Q‚â’&祷ÍJ®„õ_kí'ƒ[Z&¡©h÷‰©érH’[!d=9ïøÖµX³Ô®¬\´R° 6·¡±ÅDãt䮟F\¡58»5ØúÖ-wIý£üm£Ëo¶»j¹šWlÊ9Ç_?øÂš÷ÃOÅöèòa”˜äÁäJŸÀ~.ñë»/éˆgvZ)PË&Óó+z*õ¿‹:φ¼K{]ÚH¶÷Åpƒ‡lrA |J“á|[§ña*_Mìökåø¯3í(R‡á“øq4Ò×kõ_'é£ò:]_–òÓHñ,NdVkÄ6pB]»#_.kk*k7ÂRK}ª\’1“¸óŠôÝ?U×¾ÌN”²Þè²Íhã{)Á%×=Àö®kâƒéZž«½¡Fâ ˆ”OòŸâ¥o¸e€ÅÔt½êUUã%Òßeöz™q$Þ+ QrÔ¦õ]ï¥Óê´8Ù#(,2G v扞9LqyaT)ç9 rekø_ÃòøŠý­#ß…Bß"å‰èS_o‰¯O I׬죻>7B¦*ª¡I]Ëc*8ä•Äq#;ÀW¢|2ð+]ß_Y“ì°À ‡zçsc©üÅZð€®tm^i5Å)Ö$ÙÀeäçÛµwu†¥ªj± "ÿM½³Pb–8Ù1,I$u,1œ×çÜEÅNª–g%yzî—ä}ÎEÃJ—.+Ÿ2oÝôÙ¿Ìôï¥Å—….ïDAœ¦#„Ÿ•ÀïŸSô¯ž¾2ëÞ(¶¿6W·òì›%™äqýßÃ5ô¶ŒcâÉî“ìš\^S:‡e\êGp+Å>1øz wF·›IE™åަžsßò|;Z–5¥:éríwÓMôYÝ µòÚ‘§~o.ºŸ9M!bI9¨{ÕÛm*òÿPK X^I¥F¨;‰ÌÕýWÀ¾+Ѥ‘5ê0ùryešÙÂîÎ1»5û\ªEK•µsòˆÓ“2NÆ4C2/ù…iK"Æ×0ÂIŠF$`¹Ç]Ð<#«jÚ†«$fÚÏKˆË4ò«¿øcõbz½}*¥£ê7ÖÖ(ÁZædˆpæÆOçN3‹¾»où“(I[Mö3fE2‡PpÞÝèE$àv5ÙüAðôþ6ê-þÈÍ9³(˜ðùœHýðßÂOaÇÆíp ªhÕx*‘Ù—Z”¨MÓžè ’zž*=§Ÿž‚‘† ŠÑ™¡¢”K×4“@Ù1ÀN <ç51ÉLTb›&!ÅåzÒR½U¤PÜ9§¨¨ÀíS ä™&À@Å.â”g)jˆ¹ R)ÐT„dTT™Hn(>”£‚i¥I@=)4¸Àͨ\%XFH½GŽœÕƒd2ò\É·Û¨'8¡;…¬DF–‚;ÑÏj ­;ŒSpHëÒŒã‚(àG9Í%ïFh¢Ž(¤1GÖ€}E7ÈëKɦ+ÈíÅî)¾´@Xx8§äõiUºP!çëB·­4¶{c½´‡’=h4Ìž” â€qŒE lñ@9 Eø ãÖ—Ši<âŠZJÍí@gÒ“$úPŒu¥ÔdQ‘EÀvî:â·µ¶œ«%¼ÂxdH¥VÆqÇ_¼ðÖ¹ìö«nºly³<¥@U.Ä• ÕSrN.˪î\\TZjï 2°$£ŠaÎ1A›¨¤ó3Ö´3Ô@„œT‰ârYˆÍ qÖ´<=s·ˆtÛ™‚ẊGÝÓh`N R|±r*+šI=¶gÏ iú'„ô«K± ÷¶–¯~ÙLaËåFO÷sŠåÿhëZ]ÏödÒœ^Û™YÁN?ŸÕßü6¿´×5«Øì6²ò†e£ …ÏL`šñ?Œ‘OÄzÉ‹k´S°XËUpsÇQù×áù®&Ug)Ïy;¿™úç±q£Kd’_$y\šÕÕå’AíO7Îã tþuØk>7?ðƒéú|ñÃ#JÛŽ~þÐNúg­y•ÕÃÛ ·òÊä[*y¤¸‘<ÝíœA\‚KRc6•Ž—þ ~Ò–­&m݆÷¿_SÉ­K5–ÞÝ-^f|lA^¹úb¸±…•‚£:£dx®ÂÚêúG³½·¼ù! ¬¡FݽJôô5Q‚W±tÙ§Äø~7G‘!·¸uŒàžpqž•˜eñ î©öɇœ×;òèÜïøš‡Y¸GŽuuiˆ\¤s´c½kAhiV÷Ú$òI#œ…œ€q‘Žø#¥Z‚^ñ¤Sr3RMFÎ夹ØmظçœþµfZÈ·f[+M£žYy ÿ{éþ5µcdó¤–÷÷’ QYŠàaAÏõ¬ gCþÆSW#K„N›”¤zqCŠnÄT‡2¿C¼ð&™§è·1jº¶¦þH…×=¿ gñ­;Û¨j¯ö²¼Ž«Óõ?y}ƱâO4V’[}–@ýä&à95¯¥ø†ãHC—ªGp#c*Ø,YðšÆ¦ïviÅE- MQ/­í<¿´"F‰¸euSíß>•Èjw“Þ˜-¯Ýp@‹~xÏbjÞ±®_jR™î¥%äbYPaG§‘4èEM‚7OâÇJì˪¼ÕM9ºyÕ骰p{2®¡ ÝXΰ©o=+:X$ˆ•š6SèEz."ØÊÖºŒEÐX…•z¾‡8ÍmÂ9¡ë–Ãjªí ‡?¼ûý+î0Üfé¸ÓÄÇ™[V¿ÈùªÜ+ ÉÏ.WÑ?êçŠ\@n^ê0k²ñ„olu©ôÝ>ÖiÑT•Kq’8ï\ÄÖÃ!I£hØË‚+ípøª8¸*”]î“ó×ÈùJøj¸Y8UV³jý4)ÇzÕ†·t䌊ÐÕ»FI¢<ÑŸz]¦“œûT”;qõ¥ OSQœÒaÁ§pµÉ²8â•”PcKæzµ;‹”yÇ­0êN)»‡­86jG°å_ö@§2ûÓwúRîÏZb°„{Rzv©;t¦ž;u¢Áq„w¦àfžy¦ž¢Äâ¥ÖÇjaE>šZQ×4}Yi"h¢"Úè÷ÏßÉã銪§©Êø5Dêw"û=ÌÚ”Ñ!#1ïa‘¸öü«£›Q¿½s©„Š”Ï$D=ÜvüEz„o-ï-eVCb·–­·“Éóü…~_ÅÊ¢Ì9ª-,­éÿ}þAìÞ_Mëw_øk:‘KfàNI`zŽùªïw$wQÛ†ÈÜFGÔsZ6ööð»ÇmÕu=ùÅgMnö·JfŒìP?aÔ“ù øÇ ¶Ï¢‹q²5E«ÝÑ²ì ¹¹éþsLÀ ´Œl<ÖªÚ¶ÇdÀ¬‹Ãœ}Ïjbé²,iB᜞¤f‰ZÊHôI£.Îsuå°;s“мöÌŒAc×Ò·ôÉ•ŠÇ¸È8㥥¬0Må’É ‘ÐŒdb¸œzšBšœÙ5žä¶A2…#çð®Š"^ÞmÍÁ’dFQÓ’ÇØcùV$–¶&;G2ÊäÅ’÷8ôô®«A¹eµX¾Ì¹UÜXõÎ@ÿrQøí{uª>{-‰u Zß¾¼Ö¯@òlá.{#œ~5äí©øŸÅzn‘†|»k‰¼²©>ù;à€@™æ»ÿ‹GP›áÞª–v-q4Ñ,QÆ©»%˜/O\òo€5K/Ï®ø‹F¾³}66¢{fEiT¶HÆ@éõÍ}‡`2õ•WÆã"¥%u|–ÊýÞçÏf˜¬rÇÐÂáeh»7§ŸWnÈú’8¡žy%O.EL€Ny=?­q>7šf´Îxs!Ûê0:Õ˽fé ¤A™žO™ˆÎÔQ“ÏåQxªòð´þ|hK®ÑAÞ¾F¤ªÙ#êés¦µv²Ì7ÕèK÷²üWú/¿¡RyÚg2Hij’{š®O\šqjˆžÕúuÏɤÒRö¤<ñH«Òž1·¯4ÑÈ>Ô¤Jó@£š:S¸õ¦ƒšZ`Jœ½i§­ vÒ±ö¦HÃÅYˆ†U&¥ˆÿ 4FÍÉúÓ\Rž´€Ô•aôdSrh探›š\“@‡Æ <FàóKL$î9§Ð]E à©¤'4g†i铼±}ŠiØD¥¤ ذSÏ¥}ð«Z³ø›áKŸj²Gm¨è¶%”€i£nÇù÷¯›¬®ÞÊö+¸À&'Wà ŒƒžEw¾ñ¬Þøaã}*$ŽwûèG*"s‡Œç±\ãé^.}–G4ÂJ•½ä›‹þòÿ=W'ÇK/ÄÆ¥ônÍyÀ=O±«Û4‡}¤Ÿf•XtÆkʵµŽ;«û5€ŠçljAäsŸ§JúâÆ‘¤xvîøDHúv¹¸$Ñ—nH?L×xÇÃÛö¶:•¥ž$Gc|ò£c<¤cõ¯ƒáҿӮﭖ¢†â<„‘bs¸îç<ן֛ éZg„ÍïØ4å´¹$§˜UK<3üU…¤jòͣ ¸a5ÀI%*Øc•ÂíôèGµ‡¬]Þ6 ÷¢WÛ*~õ]‰ÆO§¯Ä9S›¤ú·¾\Lc8íþg Þx†ïPiÆ—<òÛ$D!oUN>•äŸuKƒ}ad—E¬xSŒ9<þ˜¯DÐ5£¦x_S¹Ó!Fžß÷Ÿh#„ÏÝç ÿëW€ê—·šÔ——’´²ÊÅs_]Á¹{¯Œž.Vµ=-Öí!ÆXÕ‡ÃG·›ßÉ4t¾Ôu_xRó_Ò¢hî./âƒí{~hÕU› }Î3ô­?øXŸ5khaåÝÒ™A/Î$ñŒôæ½ßáWƒ4fø,|_ik¦¡æ4Ÿia+n ±Áhõ¯.øÇâ KÃ7W„¡ðí–Ÿ¦ÙF­°®~Ú‹¥›<Ô^M} Ö†ažT¦¤ÕÝ­emºßÉ7[/­‚¼ªµ¢¾ïúÝžã/ˆ¾+ñB'Xh¡† ²ðB»TÈ ®O©ëXÞ·–÷\´¶Šâ(egÌo)†ŒžÜÓÚóÃ÷Oyq¨ ‘q) Â@PÄÛ²j³O¦ÙßÛ\À­qedt‘¾ÿ<¯¯¦§N©ºt£o–‡9Ê­ER¤¯ù›þ<Ö¯5zC¨:Iå°Ì«ËEüóØ`{sT$ðì]¼úmÔ·7·/ƒmä`(ïÏ=»wª77Ö÷·ò][Úýš²D `‹œà$ŸÄšÙ±ñ,š=ȇK™¤³y«ó »éœ~•œ¡RõKm—¦Îũӭ^SÄ=ßv¼ú_úЃ_økâÿ ÇúŽšZw› Þ«ÆH$t®wì/Ï3ª ¿µ}¦üMûN‰7‡ì-Öèݣñí7X´ñÆ:ׇépʺšéÓAsæH|ƒ|9ÝÆ?á^nS˜âq©U5 Âß4ïþG~g—ÑÁ΄ù£/ÏOó9Á‘Ôb¤]½«Ùàµm¡>©¬ÚËfï"ˆƒú1Âþ&¸ [áç‰t‹»‹oìÙ¦ ÌÑÆH5чΰš’¥N¢ºï§ÝÜÏ’ã°ôãV¥7gøz®‡5šiÁ< Ô’E$2´SÄèêyV#ê*TÛŒm׬µ<—¡XÆÝ–£*À©+Œü«^ÖÒÞt™§¼XZ5Ê)B|ÃéíP)HåRʲ9 ôjVOAßDÌî˜Ïj‘Oj¹w¥MnWÍ·x÷€ËpA¡ª‹@V@r:K]PßfX_nivÒG€)ÞõD·*àâ¬8¨Y0¤Ç:QEš’Àýi3N"“´ô“hØË¸g vÍG"ÀVk¦økq§øÊÆki631MÛöðAšÃRtèNtþ$›^¶:0”áV¼!Sám'èÙö€<'|"šE–£ö¥yRâêìmÀ gÓoAÚ¼Ÿâ Ö­®jâæ®ƒÆ‡víìËÓò¯Hð’ê>-ðùðóÎ`,¥¶à”bF ïÁlé\ׯ¿…QèÞ“VÑæ¹)¥Û.abNóŸ˜óÎps_…âjÏYÔªîÛÔýYRv E·Èù³PŒC wvÛr0¹ø¤ºöPÛ' ¥ŸŽM¿»[¹mŒ›¿ÑÓcç» ­,‹q+4„[h¶j“Ôçr]¼É.7Á Áõ­-T¸‚ÞHĆ6<‚};þ|W-}(IŒVêr™æ´ôÙ—=Ć49ªpåWî(OÞ6TIöXno›+Ç=êô~"ž$kDuŠ;sæîƒŒÄD¶ie[ˆ÷:üÛ»})«µ³ï ’¸U¨VlÓšQØèmîâ—YéÔ†Qû°:çƒV'¾Ò®îËßD_Ëcã©ÏZÂil£‰ØvNO'½A+"!ÈÏ+`FàsNl¯iec Õ®v´iÑD+±zøûVz5ì!'ŽÀ30`À`g9ªßhœÊepÁíUSþx®ŠÖúI¬‹½¸ ¸!pGFýý+9Öî‘9)ne}¼È‰l¶ã!ŽëüñQÛÚ´’‰Â‘´üùè: ÖòèóCs„ 9\Œ‘œ~Yüªe±”ZI§$)$à}¼|¥±ù’kÖÑ8õ2sÔÊ„Êú¼Ý4¿,@ç=?×´ÔMœñ›1e'2?A¿œ/àµCJ7Ñ]>Ý’ýœH0ëvòF}ë~÷N¼¼hÓNµ2 ØÊ|¡žsÐzuýj*UJVeÅÊ÷E«=kPþÒY$ÓÙ' 󻑆õjô øVÛÅe­õ‹.^E/ íºb¤ßˆÇã^n§Ä0L‘\Áæ2«,®S¨è½“áÔ-=¬V¨Ï Pº@ã>ÕrÆÎ)Êœ¬ýNêUokê`ø«àvâ/-b[—Ç$iò “º¾iñáíFm3Q€Ç4-ƒèÃÔzŠûëYŽht8-í‚»"ùl£GAë^c⯆v1ž-OKßtÍ„‘ W‘ž‡Nkéxk‹jàdèã•7·V½<¼¾ãÏÏ8^„Ul*Q©ø?_ó>=uÚ:ÓHQÑ«Ó~5|7²ðÕ¢i¢_&áY[Ì9î3Ïã^ZOZýW£˜a㉡ðËoÈü׃«€¯,=oŠ?ðàÌ{Sr{šF'4‡­tÜÀ\š:qM£š.½ ¥ôÜ:Ó€ôÀxëŠpé âüè$‘OzFäÒ+JVìqÍWBl4€)¦•˜Q–ÉÆ*JBž” c­3,iT¤æÜ¦–ü)HÉõãð ðÇó§j,äóOSŠ. -§1CGB+ÐtŸ¤šBPEy•‘ÿ\Ýcî yºÓÒ¥ò®¢$áIÚßCÁ¯+:Ë)æ˜W/z:Åùöôg¡•c¥€Ä&¾h×ëê\Ð5Ë‘KÍ)qóv'×ò­+Ûu(‰ŽÃ¹ý7cµrúEÌ’-¼|(ðç¡fÏLýu¨±ÛF¥òŽÊzžÝëñ©Ó’“±ú:ª­flhZ¼V&Úç!‰.‡É®–Òhî£O-r‘€yšæü=£hÂ’Å#ˆãßÿ×]:@¶ªÃË&¹œ]Ïg ç8'д—¿(o3g–ÃæÇjKãixEäL`HùÍWû;°’T·õ«š]ÄVb»¸Ç•ZqoCj°çi#2ÚÅ÷«,›@Î}Çóâ¶ôíVmSOÓ¥'ý&9Â`1ùJ®}p¬j´ñà ÁR¬­·wÐý+ñ€»‚çÃÚ¬ò¤–z¬`Fƒ;ÄŸ)ý ýk¯„Ž&¯°–Í?¾Î߉æc`ðÐöÉ^Öûºž«ÜP•óN@ê¤gšžúï퀭µüë$g`Çž?:“{ eVí»ñ¯2[MG¡×ªd’±#mÀm;±Ž3ïøV¾Ö²i—n¹û㌿äÖ˜ži„ŒNǸ‰º¼~’Ém&éÄdÈ€gå=±Û§é8s¾U»ÐÞ¢(:“èx7Ľe/õu³‰ŽÕVçùb¸W$w«úƒÊÓ³L˜rÌIÎsÏò"³˜òk÷L¿ žE}ï«ù³ñ<Ã,~.¦"iýËd¾HkaÍ-4‘]G2hhQ“H'2p9ÍNö¤) ôö¨”ì‰\1ä}*xœÕ¤º™;Ž;ÒŒÕ4ÈoQÅAœ–¬Rwæœ8ïMbI£œâÉ¥n™<ÓØškaXg$ÓÜ2ÆIô§@››;sŽi.ÎÜu4í¥ÂúجO½(4Âhüj ŸSOŒòséQsÅ*±¢à8œ´gÞ˜;Px§tˆ°$Ôn~n)cÉ\Ó­ZŽ'¾i7w¦çj3ÅÕO½[°¼’’зÉ0Cj‘íJL•!‡jNÁcè/„ßíµo]|2ñ,‘…’04ˉ%Ï x8¾ÕÓ¦‰­èÿñ+Ô#Hæ€/(Û•ç¾g¶¹‘»¬ÊAR1ÿׯiðÿÆû[ß E¥x¾“P±“÷±¯*¾0O¯Ö¾‰xb¥J¿]ËÕîýèþ«õ>Û‡¸Ž4’Ãcek-íÙúõ‰ÖRÈzdV.x£=sW[,Á×|Õ)Eü…K4ÆÐ\´êÉ/S¾½ñõ€ð©ðÕ¤2µ>åÇ>Ò¸Ïë^+``u4óÅ0€ÜÖyvW‡Êá(aÓ÷ÝßR³ ξi5Œ©ãû®}«_âÝÝÄïhš¿‡mã€$0LÀHŠ2Œ¯=q×ö¯._YŸ†àˆ­$ûS^µãË‘·håÇàáT|9ãìÛt¶¾ó¥KxgH6‘û²ÀÛéó¾õâ,¢tŸ´¡W ’”WtÒOïg´óJuW³­+©ÓŠ“í$Ûü8Ù8•Ô#5ÔÙkž mëÃÄë å’ùHùÔ’@nãÆ9ϵsÒÇ âE8'’=ê-Ã;qÀ¯¤©MN×{;é¡óðªéÞÝUµW;«_‰gO±‚ÂÓC±ž8£xÈž!÷˜GÐç^Õ‹­júf±$Z~œ¶¤A'Š?¸Ì?‰~½þ•Í–Üß&F(Ëx¤IÆêÎzTçí ¬Í'ˆ«VÎnëå¡ë>øc¤[é:¦©1½º†áÒæ»YcQ„rݯOökÑ|  ü6ñ‰Ç—:ÔƼ›)xy¦á×ÓŸþ½|í5¼oöh­œÉ4í‚ }Üœõ«Ú¬º6¥5”w º:’3Åx˜¼†j’–£„äû5}U»\õpùÕjP·‚œ#kwNÚ;÷µÏ¹õÁþ: ø™M¬‰¶t—`CÈ÷®zãáÕþ˜ßdŠd½².Vyä9“aNsêzù›Àþ7½ŽìiZÃ2N6Ç(á‘» ¥z¿‚~"x‹GÕ Ój/=ŒÛ–H¥;ÀàãïÒ¿<Ír™åU=•^º¦ºŸ eXøæ´}µ¶>†V½àßë!Ô´6K²Åâ0¶ÒP’rN1^eâ?†÷6a¯´’îÛòÊâDõçv?ȯ«<;¯ø{ÅîÖK£Áo*£†$¬£ÓÓå[gáΛ$ ÖÇisïbl÷Ü{?áS—q;.’´¹¢¾ËÛüÑŽ?#Àã¯ÖOí-ÿàŸéò²•=Á„8¯yø¡û:øäj×¾$Ðôá¨ÛÜÌò;Hñ-¾î@(9ÆOaŠòíšVµ+ÙŸAex%XÖ+”ØpIÀ$¿UÂç\Vb#-,¯k»zÛSó|FU‰Ã×tu»·Kú\ÉÐ$Ô¥Ô"±°¶ûcLØû3t“ŒãëÇcÄžºÒ­¬¯æEHµ4F„üñIí’6 ‘Ïp ô{]À¿®Ï‰$-þ°z½šò _Ä—ºíô—z…̲y·Î7p¤l±p2}lg×*óÐ_»îÓWzí馿"±OªRä¬ÿyÙ4ì´ß×]>c8Çœq[·‡&´Ñ4ßZH³ÙjV]œ›yí(þ…±¸g¨5ˆd­zPœj+ÇÐó§NTÝšóûÅni’Õ `ÊŠF펕D¡¦>ý©6ã¥(”ô#Š ihǨqëM4ãLfÅ&1¬p GœçšFlð:RXqž)\»$žsÒšH¬Þ#©¦ã# t¥p þ4sHOnôfǹÀ&žÙµ¸þ•6àz '©§qXpéÖŠBØ8QÅî0QëR§TcžqÞž8ê(H–Ï4Œ£œÍ#äv DGåàšLæ†Îüžhr¥ŽÁÅIbŒS”öϣݎÔîOn(OLÐy$u¢€¥ÏZŒý)Á±B ¨,p´W©¦£í`qSÉÈàSµ,zõª&ÄÆ9⑈<ŠLóŒQœf‹šCŒæ“>ÔrGJ,1ÞôgÞ“ŠŸJ(¥R`ƒøPE£‘Ú€i™9éJ9‡Œw4 wÍ0xâ‚EiÙÇÚ Å0ž)»© ÒH¤÷zÒ$æ£ÝÇJh‰KQ»š`>´êûÒdbšMv iš Å4I’h‡çÞžTê᱓֢Í5³Ôu«ÿdŸC­^è:µËItm¶Ú†92.G÷üv_íµáo6‡o$ïaqp!•G,„ò1þ{WÉ^ñM×…¼K¥øŽÎVì®FÚq•æê3_  zý•ž·’Éj÷ŸwyÃ#}Ab+òþ+ÊãƒÆ{zJÑ©¯£[ÿ™÷Ü?Œ–7éT~ô4ó³Ûü¾GÃ>4²†Ë]žÞ;eE‚‚ª@sØ@ÇϽ`L‘G1@„“85é_tIõ STÉÕ4òn.a-®W í€Ùü+†¸Ón¾Ô( ²Ç“"Ž¡¯”o—Vz[hs·M;ÜȰ¨PxÈMIe+H¤ aÅIªC%½Äqù›S9$w§Xà ­-ìHä7ÊsÞº›R¥~„-$LnŽí¥s¼ã¥OÜ6“´*86¬ÛÀ?Úô§.fv‚ß±Ž\w®wkhird—p9‹ä©舩-r…wGÎÖàþn&žKdþXUbÍòòz‘“øb–ÛMYP\‚r6ä=Šú}k TVܺ4 kmB3:ÂÂâLŸ.U”ôürk~- VHbHp¯ÄŒu_ÿ_ç\üòj“{`ØŽëå+´uÿZëômdjºLÒ^E ¼¶ç cqöÕJ.pç‹ëý~&2©­Š·Q:ù0ùÛ¦‰°Ì>l•Æ1éÔ~F¬­¤É#_eâßWøˆ9Áük"Äyð^HÏçù͵;:–çõæ­ÞjoåCd¡ZYÅ$Ÿ¼F3ô3¡(û… )Y÷!ÓÚ“É4ÅãØ£†íôèZeüztV’ZFÊ®6»H Ð`c­qˆöM¦@Öå¤C$¬Øé“ú×s{e,ÑiÒò%ùËŸr1ù“X¸©´z4×"ºEétÓ4onüÎ]aµ}}ÉÅt¾†ö ˜ÕYC( Žã$~X¬ß X^Esºí7[ðnOŸnkª²³’ÊG’Î-ÞcÏ!8æ“ôH÷°”c8^Hîå±Ó¥ŒÏöµó ¨Ä8üªt˜bºmM®YÆDC qßð?sq™$ <“ºMó c8=Gå[>×ì‹Åãl¦=Ò+žœvÍc+R÷™Õ~Hò¶xoíSÚ4h®ç„Æëz¡òŒ?…|°ÇŸJ÷ïÚ—â%·ˆuØ<;¦Ì 9Ùåð$¼RŽ3LÝŽÔ “Ú‚¬Hõ§;Ô@Jx#Ñ,xÁ§Œ±ã­F ïR)¦CèhcŽ /n0ñÉéM€Œy¦3Ö”šiçšCBñJõ¦öúSKv£b¬=˜<õ¨Éâ’3ùSAç¥K‰7ÔàíGÚœ L¬Z·˜&³ÔÕ˜O5¤YG°x*âKJFÍ2ŸR?3Åwv‰.« ·ÌˆmäôÏ&¼×áݼk§GvŒíþ”DŠ ~X¯sÓtÈôå–í\í™0ñ†Ò¿ÎéG « z+¿ëüÔrª3Äa©V©­Ò¹WÃZmÖ‘o,à&G¸õ«“+™¨ùæ­DÆ\HFìŽGqQ\Cò RFã†ö¯*.ïSêð‘Œ)¨-‰ •NÑ÷°1Ïz¸÷³ Wƒ’žµ™±•0¼:æœn q¯–2GÊrzT4“¹Uލtûç¦' G9íUÄ=ûð)4ÿí[Û»¯64‚Ú'Tƒ,ã³ïœ¥mFR¥5Zœ¹\lÿ?ãV›¥Ui-¼â ‹¿[\ߣ½Í˜6×§et;wï€ê¡•&@ÊÙïYšG‡íôyïîí˜j%L¨Ç+1=ð?*.5[]ž’7qÙ'†:4q—* w¿§Éèsa£:pŒj½´õ·_™oS»û-:΋ ÁŽ9=ëÊüOw ÕÄ n ŠÙy˜ŽI'¡®ãÄÖÏ©ÜÚª‚m£2dÆzúšÄÔ4d·ÓDXäy÷¹ÎÀ½bê«¥ØëœMÏœ[¯zyùxªòMzX"µ¸ÃF@¦šT;#8¥â›š\ûPä`ûRšLÐ>”26šŒ¶I4àt~µr)±íŠLö¦‚Gj3ÇãHcÏ×¥!aŒgšBx¦œÐ’ŽåÎ=*Üʲ+`B85HŠn ä iØ-sÛ<ñ›IÓ¡4D½·Œ·hb]Ñ®AÚrFGð«(Ô~kšüs‡–+VIxç–$‚0@$~UâÜíÂÈ?°žQëÁ©Ã¸YWxš•9=ù]¿׆y‰T}…hÆq_Ì®}§ü<ð.¡¦¼zeßÛ,—2Ç4 ,‹¹K7=<¼uî+†ñ7Ãm_EÔ%Ól´ nCB·N'_¸@þPN? óû}gU²O*Úúâ$#RVòÍhEã¯ÛÌ.“Y¹g4wÜ6A=:ŸzæÃäù– ´ªCÎô•Ö½ôð<«æ˜](ÓVºÆÛ|ÑJE’5HrH TŒû Œn(d åWˆSõ­ ?jKhÓÇÄv2™¡ŽH•”1猰éÁÏJ¿/ŒôôŠÑtÍ]"Ùr\–[†ë¸®p9Î1Šú^¼,½ýŸ‰âª4e¯=¾_äs"ä‰~tm½ñÖË.|€ÌÇ'k¾Ð.5}"ÞçÅqøcIÕm¿Ò£2•¾c•åý«Rñ´;M¢øcLÒݼÁ¾5w8sèìç)Sĺ²j éuºß³ê9aãN)ÍÙö³Ûº9såK¬2¼’ð=MZ—Dº†Æ ùæ#¸m¨¾f_¦r@è9kÕ¼!àkÙü3ÿ Çš´v^™Éx!DY®ñÀEÀÊ‚F8÷®kÆ^5ð¾¢ÇÁ¾ µÒ­\idgšvÄÌ@èzy®zxïoYÑ£k;I­“íwm|’fÓÂ{^Ò£µÖ‰îüí®ž­D²É$vÐÙäm£w'§Z»¦iVæ+ËË»…Cn™ G.ç€VÌäîg$úçž)À¶Ü1%sœg½z. ­Ž%4Ú¹%³˜&K„8t`Àú`ñROq%ÌÏq3–w9$Ô ãŠRA«åW润NRåå¾…í.Îæîãu°æHOÐñø×kk«Ê²ýž`b-Ž3‘ÿÖ®ÚöêÓ?f™£Ý×-®§smx·ė'pcÀõóÙæMW5ÕI.Uî«uó>“"Ωe*Ü­¹?yô·’=÷Áþ#›O–Vr²K,m$}ÓÀëøfº©h«)áÒoeÑ€É\˜Ç=ûŠðíÇšŸŠâÊy6†eÏ\ ŽEpÚïÛog¼ ¨‘‰U'8†{×Èe¼SZoœ#m-mÿê3^*¡B”^ ©É¾·Ñ~Úþ.×&ñ÷„nõ‡ZóAâ ]> U¢r0|ÈXzå‡å_ kGSmJâ}@H/$‘žbàî.NI5é¿~(KàF—l­§êA:ÊÇb‚zúWoñ“àÒÝÜÏâïõ&·2Ä›÷9~ØèõúW¥•(ðÎ6X GÁ=c;uÑY¿êß3ÉÌy³ü$q´>8i(ßñ_Ö¿#æ×I )f÷4Œªë·µnßXý’Ö)ÌÊ’œ0S–‡UaÛ­gË ÑÝœ™Ïjûˆµ-w‹´‹š?ˆu3H½ÐÒsöMCa•F(ÙR~†®ë:}¹šÖÜÚ >Iæã‚ÊGc×â¹öäçkB-~ê=2M&UI­œîPã%ûÀö=G§?J‡O–\Ð[½~ë_×Dhªs+T{-?;~,KÝ6÷L—˸ˆ€Ü©«P{Š®ÁYISÈ®›ÃÖ:ޱaö»wKÈt©¿dwÈà°©RàzV»•®©1Ó$g³‘‹ÀO]§¸éøQNº”7ºÜU(¸ÅT[=Š 1ƒM%›€£Êlç5±3ÕcÜÓŽG£ Ô± Í êhɨÉô¤U‡íÜF æ“tlÒ)#¥8Àp(‡¹¤ëÞœTŽ(Pzb€Ø@20:õ§‚)@éíN`Ïæ)ØDDsÀ¢œEY g™ƒŽÔàû»Ô9™ç#µ+ŽÅÄ84¯ÐŸj‚Ëdö©dq³ëUr-©9ïHµ&x¤ÍA ¹4õ$¹ÅFzR‚)…‰3¥CÍ4fLP!Øéš1MÝž)NOzóïR#”ÍB½iÔÓâAç<Ò0x¤Ïz@h¸$;¿4tïIE;€à}isÛ4ÌÑך.+ƒëšgZZŸjÅÞ…>´áŠ~rE3¥šI;Ó RéM=>´B“ëM&šCÉŰ½éG´gµ éœÐN)\bç¥ûÓ7Q‘Ò•Çbki|·Ùž }Ëû-xÊßÇ~> ¾™RÒ˜"œù#qøW‡=GQ^¡ð âTÿ¼§êÆM¶W-ïG¬dõü xÙö_ý£‚”R¼£ªùn¾kñ±ëäxÕÆ'?†Z?ÑüŸásèxf+jž&×4 5«YKqÿxŒ7ãŒÐóÚ¼:ûÃzƘd¶ó!¸‡b²Ã(9òü}³âýÓÅž¼»íîSaòHä0<ûýïÒ¼ÓJø@†îÒÿQµ‚Xü‘m2üÃ;x,yêç¥~E(òÊÝÏÐja[v>7×-Þ;è¡ -ÆI¢šÞÙ1‡$ùg·?ʽWãoÂI|-ªC¨ZÇ/ØäÝ ÎqÓÐÿ?¥y¶®‘Ap-äOÉœƒ‘άS•5½N>NYµ&P6ñ-»‚^AÓ³áÿìë¨î|àѸY2 ¾ëÜw5µ•£¹€Q¨nt´{E2C+0n{õâ¢tý¤ZêlèÊÜÈÕ†8Ú9­á@à Ü$œþ5¾“¨+‘å«)Œ°ÉÆ;S´ëäx¢³º‘ ºåHÀ+'¨'½z6Ÿ¡Ã«Û'ØQÚ\nN>•åÕ”¨»XŽVÝ‘Ãiñù–PÛÞD’Imµ—$Žzlʤ’ûû: Á"É#±2vqé] æŠ|?­[´‘‘Œ3òç†â©xËI¼¶ŒCWE9“×·×úVÔœe4žÏ_™”á%ûÆ—¨‹é¤q¼*¢öàóÖµ5gm‚ò8¹ªªžxÒ¨i:eíë}…,Ý\I˜›*sÒ·-t©/u¨ln§acÛƒÛñ­1-F\Ïqá“¶Ú:4"îîÞ9ÕT4*ÿ»Û°,W®A¦ÃkáÛ³*I·‘ޱ·9 ×›Þi·úuä2EfË!B™9ÇКô}.å ðÍÎÉÖV ¤`t¯>mØö0ö´¢ûYܳ[;H–"x-y?‰®“E°d¤šbÒ*äÿx»úW7c¶8¼£ÌRí ç'ß­t<ÖÖ+å$±¶ ¢°ÿ[»Æ:Í*ßìêI5]FêÑÊ$›j)-ÎHëþ5ä_¾& iPæ¢ ûŒ¢ óÇÌÓë]õ[ÍMo_ÜÆ±©E=@éÖ¾Yøã9ÏnŠŸb…•;gh8ýi’éw ,w,ª¬…ˆP0>µÇŒP§Šœc²nßyцŸ5(¹oeù_ñÂÊÍ´øµ)-BÏ)ŒÇ&C1R9Éü+Å#æ’8"]Ï! w$àW²üdE‡G0 C”‘ ä’qùu¯2:8xÉVSAÁwú÷T•L©_£gçôðÄsQiÊèF- sV­äÚOZ¦*X ßÀéM=I’еpÀ(&©“ÉÇ4é݉æ£ZmÜQVD™qM'ž´¤½iŸ!¤HÍ…À5 zV´ØðA'“C¸QŠÐάrH­, æ>N:W.u›  t¥KÛw$]#¬N~V\uµI£ ŽqP°Ï"¢QæÔ¸ÊÉ¡Þ{pB­[óRxƒÃ‘°|ÙõîjšÆÍÒŸjކEíœãëM6&•‡0ÉúÓ]èsíNrGj@ئ-Fù{¾ï_JQ `H#Šqù˜Áõ qÈ¢È.ÈÒ&c·¡÷©Q\cžy¦’z‚iÈä6@Í wñIíM%WÍJÍ€C.j)>è;pJ /éHXžô¥K°XÔØæ’Xä†CªUÔàƒØÒl´†–>´SM†7"ñM'Œö57*ÔóÖž\°ô¨ôüð(LV$õ¢›žÔ¹Á¡0°à3GJPF:ŽiQU› ØÍP‡$›r1Ö¥XV@X7½C${ !±éB;!ú”Óî&»ˆTpÙõ¦°ñÒ¦YÕÆZ‘£Œœ‚9íNĦú‘*gƒCŒu4ó ^‚‘°üC@ˆ³Ficµ75%X;u¦š\ûÐ ÈíKž)œRƒÆ(‡:f—#Ö›Å\,;>ô¹ÇJaç¥ÐÁ4ìñÖ˜ W¹÷¤'½7#=(ÍMÇaN)7Å&zàÒs@Xu(Îi»‡z7ö ,?Å!#4ÝüÒzÑqØvìQº™ži Pžx¤-Î)»€ žÔ 3FzÓA)Aë@¬Z\=Äw*ØÁ°zpsU—$Ô¥€^Ô ß¡ú'ðâ‡Ä] I¦Ì‘#Úbc–Y02„u댘¯HX¾g¶½¶’"äuÀÇnëóÀÿüUðçZ‹ZðΤöÒÆÁ¶õý™{Œ~5ö·ÂoÚëÃ?&·Ð«tá…¿q!Áò¼ãŒšüó4áÙáå*”#Í÷£ô\¯ˆ©âb©b,ÿÿõí{š'‰ô™tjÙd„&̸/9WÉ~éê–ɳí6’¤¶è5  þ#c_bÜÉ Š`ÃÍ#eOË #¨¯8øŸðö?øp\lñdÛ½K)<)ü«æ½ø¾SØÆa½´yâ½ä|Q ³³…»°hÕã ÈÀȤÕo®à8‘–=ÂU*Üê?þø—Lðºëö­$ï`Ù’Œa£ÉñÏçê+Él.dÕa*"!ã8*}ºÖao~;p”Üyg£,ÛÜÉuukrÇ|qm]€t穯dø]®išl×úLò™­Ne³ÀÆÕ<ã§_Ð×á­ÃåæeºhÔÂeÇÈùè}yÇçQßL†ê¢;î@q&q´ ü£¼~•åU~Ñò%©Ó R§iu:ß|D°ÕïçÒÀyvr!QŸ/]߈zÖ¶gý­]Iiµ#m¥¥ ƒ23šò6½û“Í<û§o;ŽªÛýk¶ð޳©M£A§ØÊY£važylc>ÀÖ¢­>Uq¶ïynuºXé5Õ­ª´ÌA°d(ç¿ÐŠå|/¦Í¨Þ=Á(¡‰<`úþØjºl÷¦8–_,4edÚ2;qþ}*Æ‹¡ÛéûYò ±é»üšçrnè|²“5`ÓŒ·1_K±‘}G­K&+RᔟÞjô€ “…æ³u9„’ÈÊFåõ±NÎÚåÉ,$ž1s#¹HŒšÔÕíç˜ü®UD`ã9üª…¨Û6Î%¾¸¥¿Ö|Í0KmŸ;¼Ã÷1בéßð®ˆ>oSº¹)¨G[kñÁß“‹IÌ«…V ü#¦}ý=+æiÌkèÿÚ¢>‚þk[I1·K@ ¡ÜÀŽ2}ùö¯œ%bÀ`t¯Õ8¹tüæÿ$~eÆ <|lþÊüØÂF);SIëõ¤-Ö¾Èù`,i ïšMÔ‡­Kc°¤â€i¤àæ•M‡ûšpcŠe(=E4I &¤SŒTBžjhD‡i¼SKgÚ“A³Ã±ç¬moâó¢ˆ0¨1’{z·=j·Š¼¿S“ÚªCâüvÃ÷P$¡D{_îòϑμ ›½v~?ñwöÌâÊÖ}ðÆs#gï·oÀW´¹¯Ø¸S[—(Wø¤Û·kØü爱”ñ¸Þjz¨¤¯ß¯ê&IéZþЯ5½B+hí.»ß Qž¹üëoÁ ÿ„¥ÙFÿ‘‚€¿Åþs^±á2H4‹K#ŠìÒ0p}ÒO¯ÿ^³Îx–†[ÍBžµÜòŽ«å­WJoïg©hš=”Eœ!#–êRàÜÄâ@?Zø»\²—MÕï4û…Û-´òDãЫý+ì/‰qÛøsáÅìV×ÍÙ!FÉù¼Õ`È?~5ñ¶¯¨\jz•Ρvû繕¦‘½YŽOêkÇàhÕš¯ˆ›ÒNß5¯êvñ\áÏN’Z«¿–ß¡[#4¹â£Ýš\×ß#aàæ­Y¯Þoª''¥],Æ1Œã¥T{‘.ÄœÒ:zSY‹}i¥qØ”€F¦P)®qÅ …„bj2ߥ)4ÜàãÖ¤¤ƒñ£4„ö£4®1ÀÒç"™ŸjBrh¸X”juD)ÉÍTÝRFíž§I‰¡÷@¨[9Á©.O+ïQÁö¥'¨EhÒ«`u¦œé7 Øô¤Q#6x¦gž´›»ã©¤cÅ ±!~1Mç­Gš\žÔîžž´ñ&#*ZˆRæ‹……^N=j_—'š…­X¬ˆ[½4&A@=ªC `ŽhH¸\qJÌ.‹0)À«h»F3QF›1‘W´í:ïU¸û5œLî¹Àè\§Ps›²FQ„ªÉB íôO³ŸQ¼ŽÒÝYžF 03Œ×Ñ ýšRóNYµ‡´Ð»q×¾+›ø àe¹Ô#׿xæ·*Bã•`zƒùþUõޱÈ<´ÓØŽ:ü·‹x£õŸªàgËîÖ÷íò?JᎦ¨}g ¹lžÉÁ>Õþk¾ÖçŽK_µXZÞ<ä`7Îp_¥zn™im*A{d<§Œ(eÈÀkÔ—Ãô2Že‡¿¾ïéoÐÒñOˆ’M4ыɻWø®ö÷ì¾_–Å7Äòñ¯Y¼ÓLa•ãp=kÕt‹{¢ñÇo»ÏuŒ‚8Ïùâ°É±T°˜U”y¹]ÿ¯Ìœ~XÜ<ðð—,šµÏ’A,&î$àv¤Ïk­ñolœÍim' †Œ¯#ò®JhšÞO*PCŽHåO¥~Õ—fx\Æ’žWòê½OÇó³—UpÄGçÑú¿ð—P[m67Väÿ½Ú©øÛáõÆ»¬kZŤٸ•ÞíQ†.2Üú÷­/hsãØE$Gv7Žäçú×·x{F³Õt¹RêÇ÷»"þœÏ·Jü“œTÊóz¸¼#ø¤ÓóW¿ãcõHäÔñYU˜Ý¨¯TùmøíÚÅsLxC|ÀÖ§ˆôkÏë—šEüífhÙnxüÆ g©ûE9F¬Tãªz¯™øü£*rq–6_znNzÕÒ¾Õ^HþlŽ”Ül5+‰ Í(ù›s)ª¤R±ÀëH,8¶FïQ´§:R3t¢ï׊M"ÂÊêF jhºeö¤—š¥ŒFQ¥Æ“΃¨<·Ð3õŠiü+GCÖeÒîÈ3˵ÒýžìFØ2BHܧòÏáSQË—Ýܨ(ó{Û ºó»¥FBãx® A»­kìlÐIcpóD;ŸœáÛŽÜcŠÍªŒ®®CVvúÒîô¦RŽ™ª"œw¥/ïDq™è8É­ÍWÃö]š2ëV÷wc™aˆ‚#qžç&¢U# (½ÞÅFœ¦œ—CëQÉnAÆ)HÚHíHò;U‘bç[¸ž&9Œ†pAõ«7Zœ×å^𬯖fýç$ç,zžiŽtxíT"<LœTI$îiÚh²eþyŠ*¿Z(æcåÔëL 1Š\óíRU‰ÑïFìTa½isÍ?‘Ö‚iŒóøÒŸÃ@ ¤wéJ9èÕ4¹ÅbÝд¸Žf†9B0%e[ØŠŠWVve] ’@ª-ÝóFñéÒ1t°ÿ0Á¥2ò FÏ4™ê;Qp±dJ¬ÃwB?Zj¹¡ ´ñOÈ+¹GÔS½Åkä?Væ£*{SÇJPç=h¸X^é7ÅíM'š~M(c޵ìÒƒ@É2M.îÕ# Š`?w½â™¸PyâdúÐ[ŠIÍ)=(…Ï^i¬Ni '4ÝÜæ•Ê“Fx¦äþt™ CóFsÞ™»"Œö¢ãžù¥ÝL'ƒ@9<Ò¸$õ¤É=é3Æ(‹ˆZ ÷¤ÍŠ.0Í/QÖ›ÛŠz úѨO•i¬äõ4Ö~p)»©¶ ÎF ¢)Zܬvçò¨É4£`÷¤;bþÊ¿õ¯ß[|=Ö Ì¶VLmç/’q>•õšn|"Õ ÿ9,=ÀüëóëöN½šßâÝ„HØÛÜÄç=ÂÃõQ_¡~Ò&y=àŽ7ˆ;6~ñíùó_œgØZt1î5neÍów¹ú_âê×ËÔê»ò¾_’µŽ/Äu‰¹›Oë c†S€ŸÐ׈øóLðä±l6‹kex+#Úd8''8¯¤> ÛA¦\¬s+¥“Êò…$ÿ*ð‰sCÌ‹l‘»[¦âp:‚ù¬U9EÙÅE(Ô^G‡iÐÈ–é4ˆ@w9#Ú·o“M¨2<-‘!(ãùŒñø×3¬j±‹Ñ /åÆä  öëV“S•àhC.AŽGJáÄQ’’›êp1ë_·ðöêye85fÕßÏþË3ìOÖ³“Néh¾_ðnDÄÀÅ7šR„ߌÓN{×®y(SêM4ššk|µ% &€M4žôg4Ä»»f”5Cšp9æ4N¬iÛ­@Ö—wëT™6'Sž¦Ÿzb°ìhsLVµ4µ7=©¬Þ•7)!Ù4S7R‡aÇ>´”ÒÔ›±Æh‡ÒƒM=©B–8‘O=kÒ>øªËÂtÍ[T!m_}¼ŽGpóÇç^wj˜,rjÌn£ ©«B8ŠR¥=¤šûÊ£ˆ–´kCx´þãîMb1ö…d!‘¤ ô àõ­»k[Këco_¾Û’Ãr1øW—ü,ñŒž0ð>á¯l?Ðç'«”)ÿ¾Hük­7…’y{š9¤Y}«ñ¼vá+ÊN—Gî8LD1˜hâií$™aÛʸkv‘IÜAÇ=êäk$q— í#*¥cév—7HÁNCç'Ÿ­u×vÅtÔ „ðHÅy’J摦ں1D¨¥pWnƒ=sLžÈ•ªG¯_zƒZ²H³FÍLÁõíúU¸í®.¡1¢1*¿14’oDf©Ë™©Z‹ÖŽÚm¾H`v穌×@-"‚ÝDe[-Ž? ÆŠ6ûWÙX|ÙÝ‘ØtzÑ父ü²©ÚÜtÅi«\¬¾Dž†ªª*ù‡=¨Zãg‡k9;œŽŸ‡¥D©óÉEõéò¥c’Ô5mmZ[û…ŽÞÒñc Ïjòm{Ä7º½ÃÉ$Œ±gäˆvãÖ¦ñF»{ª_º\.;rbHÆF0zŸs\ûÉ’kõnÈc–ÒUëYÔ—áä¿V~UœæòÆÍÒ§¤ãëþB–'½=N0j ƒOVÏô÷<ùðH^Ò6…c:à ¥ø9ú‘ù×ÐööøxWÌ?xÝKsÜþuò×Á;}L,ÒÁ•Y[t`ŒîÛƒÇâå_UÀðÅüÃh;N?Æ¿â8*y¥nW}oÿä~§“Ô“ÀRm[D¾ãÅ?iý^Î×Ã6ºI=ÕÄÊãÙFkå–$œæ½[ö‡ñ!Ö|cöEpRÊ12ȯ&'Þ¿Fá\3Ãep¾ó¼¾ý¿‰Ïë¬F>Vû6_vÿ‹cƒRæ˜:â‚;Hôhñ™´²ÊÄàôéN™|›$óQš`Çh<¦9ª¹÷¦¤žÄò»êJšp÷4ÄuÈÜ£ð§Rr£ÁŽÖ9æ‚A¤ö IXgÖö¥n´ÂjYB÷ÍÓOcFr) v}OÒxÆi3š3ͤõ5$y-Ö¡Ï8©a 6)­ÄöprÞ‚ 'µ>vùª2x¡î aÙ {Ó:w£p4R*Á¸I»­57=ÍaàûÓ‰¨ÁçŠQ@Xv}èÎi€ŒÓÚ3@X“i½[…p„õ%Xuæ­.UÅu2“è Aš‘#ÁÝH€Žƒ$ô­-?AÖu;ƒkga+¸#Š'VÍRI/0§J¥irÓ‹oȤNkÕ~øoXÔo.o!VÒá<í×9ç_Aø«_΃Q¾H• ª¿1Ϧkéø*ÏÁXF¡ãÚ1»¨8Îs_Å|M„©ƒ– %)K~Éo÷ŸuÃ<7Š£ŠX¬\\Tv][ÿ"¿†|;ÿôð¼V‡ !yíøæ»­+PògO1vs½Gzºm-¯PInL©÷¬øl.a.÷;|Üô¯Ëg79s3õ J)r™º‚_É#ËH e^ûy®Pðôöš“ÜLÇ ÛTúœ×©²XXã*À7¸õªï£.£rLÀ°9\ñǽ5S•Y#¥Ù´Ùæ—:D o$±Â<ÁËϵ˜–‘4Ë#G¬g¦k¾×tiô»·ùG— Ú;€ r·¶/Û8ÏQèjÓº=‹•š9Ý^Òñ¥’XÒ&GM¡œdƒžžÕÅê>ѧº†îþÕ|Õs¹€À~{úó^©ul$D² ŸŸ êjŽ©¡¬ûVhö°o¦?È®ì:®óÑ“‹ÙÛ{ج· ‰J5"¤·ÔÍð¼²Ü02(˜Ôôë^¿£*é¶»‹ePÙúö¯1ÐíEµÒÂÃ={Šô{mBm¼ y)¸q¼m˜ã!:PI-–hÛIâøs}:€·±#¡ä(ÆNÞ•åƒ f¾Ãñß…4?Z5xcyáܶò/ ¹ ‘úW;ê»..R{kœ›yÁpÉÇã_¬ð‡a±xZx ;TŠ·­»|È8‹%¯†­dC‘ÔóíSÍ^Ïb­(Ùµ¹n ÷va"…ÑÕØc%r:úòEVfÇJm…Ѷ™” eda†'‚;zg?€¢\+ÐúÓ[ ­EÔÒçŒf£Qj®+Ï€¼QáM NÕmüAᡪ]]E²ÑÙ„G½:õ•Ǽ¡äÜ™{zsUÄÌ„ƒŠ¹ã½aN„iÔ•DÝåk릗CYÕ”á4­ôïß¹fs’'&£'¢F;Tri–®ƒ/åÄGLƒT“åP ½?R“•Aß VⳓÔÖ BÆÓߊ*6™‰åºqE ñ{朣ÎiAÅE˱ >”ìÔE±Ò—vzhMÉÒ‚pp8ïL‚sLVº—>ü‹p¥ÜHÅbBHùM&G­7xÈ,3ëïJ¿6sÇ ò=hÜ:Ôg¿zMÝh‰A§¦2rتù§ƒŒâ+¨O"ƒ°çmB8Å;pÁ~4î+ óM Fî=èz” N Q“@ÇŠ3Í4š{PÁ€qM>ÔgÚ˜šžù¤'=é¹âÆ‹ŠÂ–Ïz íHM¤Ê“Ó4Óõ¤'š2)RƒÍ&x£½)>”dúÓr@¥ 'ó£'Ö“#­!ÏjvMãÞ›š\ŠrüÇ“R—¤ƒPdÓ¥#IšiØV¸¥±MÝÍ#zÒÓ4†?4£šhçëJ[‚(Öÿe‹u‹v*’2,ÜJåz‘°æÂ¿AíšÖÎþx–B ¹U}§†Ç?ø×ñ•™“ÆÖ©©’[+•ó÷7Èãðý+íÍ5nd¹ûEÞB£'–Aè¸ÁÏâ~sÄ•”³>^ÑKõýOÓxZ…²Ç'´¤ÿEú|\÷ZÓE¢Ùï.±’ÞksÎr{÷¯˜¾9êúm¥üöpÞÉöÈ¢ò%ØÄ†!³N¿¥}I¯ß[i×ޝ<«v¶åÓÕ†ïð­| ãûëOźÙYßP½škTsŸÝîÛüÔ׉R<í\ö+µ¨#Q»Ý{ ¹.Ò¼qÄž?úõÔÁn¬±œF,zW8-þÓ¼­Éâç=qÏÒº}*h¤gG˜µºòʽN c‹\ñQ] ÷m3SÃvº<º…ÃA#É$O1ïÏLã'ð¯Y’áðݤš[F±4JI“å^TÚyoø˜Ú;,m0vªZé|/â«]sB·Ò•™f¶‘Ñ×88ÎGá^f"›’æ5Èù_QÓ.ë“™¤o˜žÝ?çµY† Ò7–PÇÀ#®*Í®š“Z]O;ÌoÎx#<ä…Htû[yJ®U¥ÁQžŸý|×-8¨½5g5IrèD³„Œ„È1óÏ&·,ñ,1bBÒm%õ¬K©­-æY¯na##%¸ì+œñÅ/ è·/j/žâEyP8èOjìÃàkãj{:0mï¡•\M:ö•$’6õÍzÚIM±—͜Ȧ@¬>Uúž?Zã|sâ‹í3K¹·Ôu`²Ý# hÖ]ä(.väMyž¹ñ^ÕïdºGŽÖ7'dq¨€1ž§§zçµb÷Qa%íÃJÊ0¤ö÷˜©Óž%¤–­-ý6·©óuø–š„ÕÜžŠûzïO2¬íÏ'5Y©â†’j2kñéY ¸Á£yîsïMÏÂÞÕ%$=ÛŽ´ÐÙi¾ôn©¹i Ÿz\ŸÎ™œž(Ú‹&GLÒƒz`8¥ÓBhÒ‚*0}éôÉ0;â†cI4šwÇzi<ÓI šE$.GZnO"ŸÒŒãµ!¤/ÔâŽ3ɤ>âi <RchÍG ¥>rzU­53{Øhcœæ§ŠB3UÝ*DnA¡;G®üñ•·‡¼km¥j’•Óuy#úáe,7·'÷¯­üg§ˆn•⫯v?ä×Á~‘WÄš3?*º…±`N8óV¿A|aoºM´ÈåUYGÞûÜWÁqŽœjªÞKò?FàœEJ˜z”%ðÅéó9½6Y¡Ëá1»ò®²Ùî™ b¶`ƒéXúL0y¥DÕŽÖöãÿ¯ZSXÀ˜+8¯ÏunçÝ¥ÐÀu·K—i›•ãþ¢4sIhY–6ÆHldóL6wŽÊÊÛ›œV¯ÜÛGdUPsÓqïZÁ¸»Ä›+»œ¹–[{ÔTc$óŽ™55ö¡rÑí·*ýÒÁ±ùÖ~§s¾èÊFÜä}jkymçµ`d)&íÀãýjÞ+[³.e 3“×/…»È%÷ª’Ôtü ®ÖâötÎv“ÕŽq“Íu¾*ù‰,O$Oùã½sEæÎCòƒœÖÑ´̱lÓG™|KÒΙâ‘AÙw̤÷ãõÅîçšôoqO­ØEݰÙ8õ,ÄÿJóbÃ&¿\ɪʮ_FSß•’üƳzq†>ª†ÜÏñÔ°ìj{(þÑu ¾à<Ù3õ8ª{©É+FË"’ œ‚;^‹½´<ôµ×cëÿ‡¾—IÒmmí-Q5ùecÉV=¿ú× kz”Z7†îïnTeÛ㨾‚¹…_ÚÚö¥]Nc[si»÷éž+¥øÍw¤Xü&ÖnLà5E]¤ ÉØ~'ø zUqXÇFOÞ”­ólýnð…4­¯òHøgź³kõî Ì[Ι˜n‚± 4é9æ£'šýæ•(ЧPÚ)%òÐü¢s•Yº’Ý»ýãÁ«òjÓK¤Å¤¼P˜á•¦WØ7å€êGŠÍ ƒJ_#Š»&N£÷´¥³Š‹4§p±0lsK¼æ¡ßŠPÀŒ´\V&ÝOÝÅA»S·U&&…cÔæšO9 œæzÒc@M!$PO“q€ íéFi3@4 pÆ)èÜÔ%…>.N(BbÈÙni¥²)%êsM"‹ê4…Í(n)„šBpi\v‘¸óGÔÓxÁ4w©ñÇ~*ÀT)ÜÕbN1Š7ñŽ•KBZ¹"¨'éNaŽ•Z¦p6ÓÑ‘‡*r¦µô›+½Rqok<›ZLž•eEr é^ðcH¹Ôükjm]P[£<…º#n?ZæÇb~¥…©ˆþTßϧâtàðëЧ‡_i¥òëøwƒ>Kmö]KQ•g þS–2™¯\ƒH³±_1!@$˜®ŸUðד§y‘ “Ëäúÿ*Ã\¼+ ¢70è+ñ vk‰Í«:Õå§äذÙu<®Š¥…VêüÙ£0µ6RÏÊí/Ìê»zcÞº*Y¯4Ø~Ðß4‹ÁcíŠçô-7È·š7a)à(ôµÒÛ©³h¶ìRšà©N/ÝG«†­*‘¼Õ‹:|ÇGY#šè¸$`ÀúVΙuktŽdu2¯ Àä×®ÍåØmAœÜž†™à›¦ 1º«‡9â³Tí6t¤›·S®¹¾‰Š£¨åG\ÿúªÐм܆\‘ƒ…úUT’;‰|`〺j}™C+K„à~š‹µ‹»FºAebņ ®r+™Ô@.’«ƒ±y'­ojr‡ G(bF•É5ã;È’‚»2ñÁÅ)Ú*çYµPŒL­tâ$±Îü{Õ­EDT¹;Wœöÿ9¬ ÝQKuêÎ#­GwtHD™r@Ïû'ŒÕ·2=5T “è6òüÛêñŒî<ûbºíÀч+ ˆõ®2îâ_>8"÷8”¹Éô­=>Hæº ÒdIÐ Ú¤W/1Uª%Mó÷òÿ¦Gsn›e9‘Ž{àð?:Àø§£Ãâ]Øw]Ø@×6À˜0Á }@®•£V•žBÇ8O§ëYäÝs$ë!U‚°ûÊOÝ>µŽ<xb)ïšù+‰¥M)QŸÂÓGʺ}ö—7Ùïí¤ñ®1‘íU[kÜþ8ø'WÕRÓÄthàŒ«Gr’Äœzcõ¯‘ö¯5ûÎI›ÓÎpqÄF×ê—F~Išå³Ëq.‹Û£îDÎF~´ýûrEB&BìqÖ•ŸÒ½Kö8lLÏ’z· 0àÔ*IQO'å§qXÓ𷊵okëz<å%ˆítÏË*¼Œ;©î tºêøgX²oøFátÛÅ›Ý)Î<½Üo„ôd%±·¨ôÅpL}iÐHQ¸®yQRššÑõó]™Ñò>Gªéäû¯ëQ÷!‰bMŒ dzœsLY|Å÷÷§³g5UÔ;IVÏC®äû—¹žbT䚯Ïsš7cµ+ŽÄÅ\õ§Drj Þ¢¦ˆŠ2wnƒ4èäæCŒÞ¡l“Ï¥Ey)ŽÛ©ªn×%+Ù¤Í9lð8»¹ñQ¢íQùšvsX›Xp9¢ )ÜdúÒƒQƒŠvA¤Pìš\ûÓ2=iAäs@X~hÎ{Ó æŒâX^)A÷¨÷{ÒƒNáaç§ZíéM=( )¡8eùIëLïKæ)êvÑÙcµ2v#Î)AçšsLÉç4‡¸üšPÄTy¥ÏZw èiw~5=©wP$ÉÏZ\ûÔ[©A ,JXç“ÖŒÔd÷¥Èõ VŸzQõ¨²)CQqfniÙi€‡žô2¼PÄdã>Ù¤AÍ-&ïZBÔà ¥yÍ3pô¦äS \“ úqG¯"£‚iÃÉëAeÆ)…j3@X“+ŒøÐ88Ü0j0}é f€±!?íŽi©qÍFëŠ ¢ã°ãžÔc©¦î'“ÇJ]À°àqÇzBÃœÓ HÄm'½ ±ôÇìQ=ÖŸ¨xžýY~Îö°BWc'˜Jð;cwç_bKt±ßE>×X81Á E±Ó´Äh"–îG8?(d8þB¿5Î&ªfU¥ÚËðGêy}Ž[J/ww÷»£Î~/Ë4vÒÛG Ž#j¾p3 ÙúúׯÞ6k†ÖŒO$aã‰cTNj¤€¿^§ñ¯©¾8øº#á;ëË;2óËþŠ3£ç÷‡Ô‚¸ÇE|©«ZÍwu<óI›‡mÏžNæyZOcÕ+ëØ¯nÐÚÚ¡¼œ™æmªJ•ãƒúÕÝ.—UX‚Ž7dáïz©öe¸³û9?U=Á­¡‹´ø^=Ð^Ù).:†ç•Eh³ ;?‘ÒÇ3Â’ÅÊ}œåC’­ÇÊ?OÖ é“ ‹ì…åRÒF9ÊÄ`s×úUh,–x€iv¹a ¡9æ¥:z U!Ó ifD.ºI±ö¯>Nú6-«Øô3y¨ÞZ¥å½¹‚)±•r3òäRGöu¹ÍÅËJÇîž»IŸnj†›q­X1Uù6Ñ®õ‘Ô~ ÖÔ®š¸›M²XÞP2ŒŒÖp¦¡²ÐÂX{ÊdžüYԢЮE¶Dyå"s6òY ÎG·^Õå2HÎÌï!fnI'$ŸZïþ5i²išý´s±iZ"\ŸâmÇŸéø óydÇÊ+õΡJž] ÐZÏVþv?8ÏjNXÉRoÝŽËåqZB{ÓIÉëQ }¨gÇJ÷¯sɰ3ãŠazF`4ÂE+–òǦ’i¹¥'¹¤õÏoJ)¿J9îjK3Kžy¦ïK‘LMüiAã⣜RçœS¸š$x§j yëO˜š$&˜X⃌qM8í@OJ MÈÍ&1rhÍ&yÅ!4†)<ã4éH=éÉÉÈí@= ` sÞpÞÕJá*6bO'5W²±6»¸àHÇ5"± SÃc½+•cFÞG@†SAèkôM¾m{ះµÒ\<¶6óHýwÉ?ŽkóÎìkí?Ù‡Æêÿ %ðëL¿lÓËA†äªÿèJù~- êaaU}—ùÿÃYÁ•Õ,\é?´¿'þLî¼3a]\‚å]ˆdRzJïlô二[Ë´’ y5ÀYi÷Þ<ÐÊÊÈp휯áú~u×èš«$A¤!ž$ùÎy5ù½Zi¦ë±Ö‹`ÒH!RC{úá¼Kr×DG’»ÂûWeâ=V; X¯ I¤)ì3^{ªßÇ5Üb×0dv9¬ã–¡)¨­Nbånüç39m­Ž;VΛG*Ìç$€¼úCé3‰Á¹à»ol ˆJÍ€‡ žµ¢i>SÎG4Î+â;Mªˆc]»ŽÀÎIç½xoˆÁÿJúÎÀÑÅÕ“¯d•õÚçÌñ..¶JVrv}ìV¿¾¹¿¸k›¹ÚY«1ɪØ=EI»éw= æøÉáÖS÷Ÿ.×ìW,ri7PêV£Íz¬áKBLñÖÞµsKHvŸz3ïL'¹“@¬?qõ¥õ¦ŠSŒsøU"G‚I§†ç¨r.ìqLV&¤4ÀÜu4»²h $RÇÖž)8ØwãI¸ÓAæ“#µaÙ㊖Cg5_954L^”-Áì$Çæö¦gRÈAlÓ8Îj^ãCiÍÒ€ODã,~”ÕRÇà{Q°7qOÖ“ŒRwü(&ŽÜsœóO–& &íRý»sÅuþÖæðþ»¢’ ~êl¤€;àãõ® ¶°É®›ÂW–ÐëV±ÝÃæÁ<‚6\ô'€ß5Í‚«„©¯£Ó¿üÆØ)ººu³Mj}—àÝ}õ] \³©ýÞsÏsýkY´Ó4.\6Òr8èk…økщӤÞéæ±ä¡éŸÖ½ZkÆš$H¢P1“´ó_Ï÷P›QØýÖöÔbç¹ÏéËdm›2¶r£¨cí7RÎNÀP0äzša°¯Úå©$Ž1ŠŽ4¸·—ÎINF:Í«-N%UÅÙ ªDÀ‚ÒnFoº*¶žTÜ*±À‰‰ äUSrOÇóê¤ñš£ i *Ìù94ãW™Yšªò¾‡G¡æ#þYëÉÅ$×óÇóG!eÏñXO*Ï?–¥°^Ô²\m+†$ôÁ­RRÍùæÑ,Ú‚`Í&’k/TV½³i¬Ê°ç Fk?Z‘cuµy°eŒò=«.×Äie?ÙZH²ˆé×ü*eAÉ¦ŽªSƒs6χVo*ìe^ 8õ8¬ÝV4…L“ I½{]¼æ#§E<»vçŽüW qeq¨[\Ý]»ÜvíÍv{[sJk¢3 öÒüªÄ'/íÿÖæ§1É>Æê 0`sÛÓüú×'{{%³ˆÕrsÆxãÒ¶­µk3(`À€g©ïSV›¦¯ÜåÄÔsƒLëíµi‘d}­å°É=Mhݵ¥Õ¿Û¡spª¡@Àµæ‘êrÄíå· Þ•Ði^/·Kh­dm 6Ð}rOø×Zo“Ü´ÂĽEc¯ZvZRÁ»P²;R†¦K¸w D›³IMfÔ‡çŒR‡#¿ê7zQp±6òzÒ‘L Å( ŽiŠÃ³Æhɤ,)sÒXvGZPx¦u¥àÃíš\ši8éFïjaaÛ¹£9¦Žih¸¬;uŽ)´€Ól 7P‘LŒNÅaÀÒn¤ÏÓs@X~ú@ÜÓi2)\v»Š ô¦gf•ÂËÔdÓsŠ7{S¸Xx=èÝíL&”ž”&–ô£4ÜŠ7R¸ì.s@9æŒãšLÐ¥ÒnÜç‘H,; àR1äSŠN§šoœ³·<ÐØXý ý“”â+Vø%ÔOÐÃê:~uGÇÚðö‚£Us4’^$†5wu†+–”ýË5gs¯—ÞvØò»‰"%Ý‚r §?ýj§{­ {“ykˆY„ezdwþY®›ÅQh’5¼ú-¤‘[y 8sÉsœœÖ6¡¤Y,VöbV-0 ØÇñ[M¨´aˆ‹i[C°Ñ¼:µñwtuó1ËsÛÞµô™t¤¸ŽKY­',:æ+A·h>Ïg,¦H q(0:ŸÒ´¯­âmDídXcÉy@õëøW™>YK”× Ù›úçŠ4kKK˜./ÒvUQVÝæCùÖŸ‹í4Ÿ Þ\‹øið;‘¿{.;Œ×©è:—·²G4°e]7LF<àç¥y_ˆ¼K-ÔWV°¸X.¥Ê"ž‘ƒÔýN+ØÊr¹æST¡ð¦®ÿËÎ×<ÜãK,ƒ©?‰§eýt¹KÅ>$»ñ.¦Ú…Ó´l@NN2OæIÍsòÈO&•çÇ /¸×êôhÓÃSJÑZ$~MV¤ñZŽíîŽhÞi3ŠMÞÕm‰ oZnㄎ*HÙE$' åKÆ0y©w.sŠÂžAªµ…q2¤ŒS`ñFyÁ¤jÊJÃsØÒƒÞ›Ö—8) p8£&™ŸJp÷ VÅ;84ÁÚ–šIèi¥±JOÌŽN)°HRqÖ“§4n¦“ÏÖ¤vu¦‚y8£¯JÇ4ð®E00Qަœµ M ¡…¹æžy¦ç®i7{R(~qN^™¨ÉÇjr¶hZ…°Ãë]g¼o«xZMOM¹‘"|%ÌAˆYcîõô®9Õ”}ËÍ:”á^EtÅN­L=EV“´–©Ÿ¢?ä‹V²‡UŽhå†t±±êÏ>½k¢¾Òí­¤ûLW‚'*v²`sØs_4~Ïß=iWN["wÌTð¤~ʽµ.šø}¥·ä“Á=ÿȯÇ1ØiáqÃÏì¿Ãþ ûf e x˜=$¿áþæ^ñèö ¦Ü“\s’ÿåíô·ÞÓ:ዌð¢·e™™ q“ØÕI©ÉeéŒ}x®V¬tKUÌÄŠßåòÛ,ÍÐU-M#†#S„U?;zŸAS=Ë[¿˜Ä’£#¹-ÄZ~aq}©IäC³.ãØ3JÔÝÚ»è ZòÜóÿŒbѬ¢Ó"Kw(. pBòïA_9Ë3É#Èä³9,IîMix»Ä³xŸ_ºÕe8Yˆ×û¨: ÅÜkõ|“,Ž[†I¯~ZËü¾Gçy¾c<µ›÷#¤ÏæJNU›''Ö§,ôíUK þ5ì3ËŠ¥(æ£ “ŒT‘óÖ¤¦XCµqM$ƒš^)’0éÍYš # =¨'&“5&‰Xp”Ž”€ädÑœÒÎißÒ”æ`0šBäœTe¨\V¸š_Æ™»ÚÃ¥bMÿ¥;uE¸Sã4\,<œŠnx ¦*·Rc·­â“9ëR; E=9♟Zt{4Ö¢jÙÒ„sOwU4Ã(ô£A+±QxÉ¥*1ZT=ˆ§6È¡ HÙÝœS—­5Ån0¶9¤Ï­#2)¡njKœšB{RnHÅ(l6jýË«#+•e9VÏä|0Å ØRW>¼ø_¯I⟠Zê/#5íº}Ù$¯¿|õ®Ù|Mq¦£ý®ÝÒT#~:(< ŸzðŸ€>)ò­fÑÂ2Iç‚OOQù×¾ÜAaªX²ÌŒLʤ°<ät¯Ã³¼,pYZ-Y^ëÑêØ2šÓÌ0ëB^úZùµ§æ\¶×¬¾Ç‚@Ï1ØØ<î=½ª6ž[¢ñÆÛ …½q·Ö?Ø÷ Ü“€\~Æ´íµ+˜-¤¼lº2Œq׎¿¨¯6­(ZðÔªx†ß-Ef‹Z•õÔsyóg-ÁÁàc½>ÛQ’x¥d(7µ‹{¨i´1ÈáUæ Üö­Ý'ĺMµ±ÓZ5-Îâzçµr¨ßdz˜ZqŸ¼ÌÙüF,¥yXÁÁ=óïUn¼Lèû­CÍб@NÜÓuÍCBq%üaä8Õ¤xHŠI-K"4£³ç8ô®Êtj8¹Y›Ç–´ä®K¬Aupoâv*WŽy¥Ò£,eûmÖÉÃW5-­ì7&(ŒòO â û$—GíVd¼jÀ0#Ž*£9luÂt¢›¹ÙXßÃ;]ù‘Ë*€ôÀíZ6O¥¡=Í´,­üñã±ïXú3i颺Ïj ݼ !!ëÇ·õªø‰ì"Ô/S†¸!cz*ýkª-Ï~Ç<ùtQݘ—^š{ão-»äȸçè¥qÚÓØ»Ø–å[½Ïí¾”d¸„y²ÄŒq³Œ×žxŸÁöWñ-Äw"%'œ.N÷ÿå†#›Ý™ž; Ý7(jrÌ"s»o'5±§µÔRùR+7?3M›Ãßc¸ŽâÄ„È$véþÔ6‰}‘ìÙY“¹~ò‘Çô©©R›Ñu<Gk½Í ^X'Ár‚™ç·jòÏŒ¾$Ž÷B¹±xT¹¾Ú®dÏ>ü:öì%²Þ4*’D ¹íÓÿÕ_8|q¾”jÚyŽ8€2NU;–=Oå^ç aã_3§²ï÷&Ï:«*xZžjß{HòòçæûÔèwúb¡nªD;S¿fGÀ5¡:ŽjA“Q¡ùyìֈ͌”äõ¤K&OJjdŒŠ‘­‰dçÔS:ñéL”á³ì(Y9ïEÆ“°òNÜ{ÔLÜÔ¬p š„õ¤ôÔU>•4|sÚ µJ¬Ï&„&‰°„ÕmòŸöx«RLgµT‹…ÉêiIßBମL¬v‘I»½46=(a´ãñ©‡æŠh9¢‹…†R‚}i8£ùÒ(\œæŽ´Üä÷ sÚŒ‘ÐÒ¢€&Œö¦†£u ÝFóÒ›‘AÇz.+ÝIšLóŠ(¸Xpjp'4Âh LM 6*<ûÑ»ÖÀ—'±§Ç|ÔkÇ~)Ù)ˆvy¥'E.{æ-ÔѺ¢Ý““Ï4 çšĨ&£$Òîç­bNzŠ\š`9 7¤ÅaÄóš ¦ç½Ò MÞ7™ÎsH,-Ÿ^”™Å bî£=é4px }i3“HO4”âqA4‚ÀPóÆM&ênìÑœr:Šv{P ©¤SK{Ð÷P ¼ ô¦nëš½¡[¤ú”r3E¼4€p·éS)(''²Ô¨Åͨ­ÙúWû-x¯Ho‡1xVîx¾Ý„m,(A' ´œÿ.+Šø³ª@úœVVì±=†Ô ŽN \ôÈ8®cölˆÙjÒê àE)†än ÇÜ|ÀcÛ5sâÏ›%ì—þYòI[=AÃ>¼W䨩ûHß»oñ?bÀG–ϵ“ùhsíáËêL& ö¬$Œ)‡` äû`~•7Äù#¿’ͼï6H¬º©À“ì+‘Ó5ß°ÙÏ$23ß»Ðp*›êWÎÛ©e2 !I¡¿Zó*]M.‡¢ªÆ›wêcjÍu=¯Ù­ö–Œœ)àriþÒ-çÒîïý&Ù‹21ù¶õ…l]ÚGp¦{m `dãƒô¤GŠâÖImÉŽí‘€Ç\c¡öªu(òìpbjÆsMt4m-ÙTO ,À†`}ïLþU,:V«sbÒÜÙµ¸¶®CÈ ò+˜Ò¾&¿†žÅz;Ú¸ó³”'¦G1]¤_~Ûh—/q©‰$‰ˆHcêüzŸ~õ´òÌu)%NIìÖ©¯U¡Ï†ÍpŠuktôsÔòo륶•åjªJˆmÑ$w8úW˜HìÙfrIîMjx§Ä—&ÕæÔæ#cˆbÎDh: Á’^zœWêy._ý›†Q—Å-_ù|ͳÌËûWêGáZ/óùƒ1Í0žj6“4Ýõé¶yV%,sI¾£,OzMØëEÆI¸úÒ‡ õ¨·Š7Qq ‡¨cI¼ž3Pg¡±ÜÐ&šûÓUøÈ8¦3dð;úв:Ñž”ÌãÞœ:PóJ9ÌûQž8  Å8T\ãà@ ¦–=© ç­0·¥ðzš;õ¨÷Z$Ð2^G½ã#½' 'éLH=è÷ÀÀïÞ‰OȼçðrM&IëøPØì;9¦æ“>ôdv¥qØvâiÊHïQÒƒŽ´\'ÅK¤Njžìw§£óÖ©;ãsÔ> ,£Äu«µ"*ñ“Ëg¡ü1×Þ¾¬ÓïfǪ́÷[Y0ðÙ# wüëâ? øŽ_ ê±j‘Eæ˜Î ÆåÈÏéšôëï*–‘›mò †^ÜŸ¸{óøšøŽ!Êqx¼j­F<ɤ½-ßüϸáÌß „Áº5¥ÊÓo^¾‡Ñ ­O8v“Æ…‚ƲõEas²yò­òƒ…#‘“Ð~5ólŸg_“q–‰ÌS§IôJÚß§Cî¸wK AZk­ú[¯S¢ñž¢ Õ­æ9xe_-ÀtõK§;iŠ-LoáXqIÀú+ç|ZÖµ‹¿2ÖO& ¿tòsYößüUilÖ±j+±ÎNW'¿½uÑá táIÆ.Û?øSˆpq«6¹š}]ñwmü{-¥ì¬.Šïò@$óúƼÚëâLj%žI XãNÞr@÷õ®7\ñö»¨I©js™î%Ææ5šn˜×ÕeÜ1€ÂS^Þ s{ßo‘ábøƒZv£7­­¿Ìè5?kZľeö¥;ã¢ï!GáÒ©Gws«4W2£¡Ê²¹cY‚ãžI©’Pzú*t©S$"’ì‘áÔ©V¤ý¤äÛï}NÇLñþ½m*Euxf‰Ÿ-¼òààõê¶ Ô%HHîVR±•FùH®{œ×Ï¡ÁkµðgŒAÑï÷ÊZxFëDÏñÿæ¾[?È¡V1¯ƒ‚SNÖJÉßOÃò>%ÎgNNŽ*o•ë{ê­¯ãùžÃ¡ø‚êßÄ© ÞÞŸ:x‹lÜp0Tsú¶5-oKѼخv½Ódp3ŽJðÿ ø’êÞ÷û{R s¨jQÁÈŒå‰ýìÆ»½X6µ«Îé(_.@¤õñ»ò9¯ˆÍ2·€ª©½­¿FúÛÉ^ß#î2ŒÖX¨sÁëÙïn—õÜíldl±Ûü윅€GzÚÓ5guX&M¹äžä÷¯&¥kÄúÕU×$Ž‹ÂQ_Z 'Œù£%Ë!OÔþ×iúQ»µ9”î °BAƒúW7 ÝF²¬(êBF6õã×ð®ËFBMm,Û7sø~UäΓSm5p²Œ[¾ˆò?ø‹QðÄÚ•®£yˆ2ì„Ø'Œc¹â¾vñ‡ˆ§ñ±6¡4®ÛÎ;µAþ}kÔ¿hÝYa×%°ûA–yÜK7Ø‹Â/ëšðÖbıêkõ®ËaC ±²^ôöò_ðZûÍ8ƒ*µ~­†;úÿÀC׿`¹ëR)Êâ ÈíJöHùÛ¢f=OJ”sÞªC'PMLÏZ´È’L†Àô¥‰ð{Ðß=F>Sšº Ü)¸ ÒðzR«zÓrHÆyÅEõ­84«›ëWº³¥òreU¢ã†úuüªƒ&:ŠžhÉ´ž¨«8¤ÚÜ`4‡®i mRhW¼—{ì©Å Î*6;¥,iÙª74µ•‡g4¤ð 0RäýÑ@Éõ¢›Ï­g­p)p —ÏNÔÍÙ8 ¢›œ É gœPO©¤ÀŠN¸Í.zÒgÚ‚hµ7µ.ìóL¤ Ú€°üÒçŒTy§@XvisL'ÞÂXx=¨dÓA£=è@ÃÒŒÓ3ž†ŒÐ™ô G4Å#4¾ôîäö¥Ïµ0M(õ\š7sMÍæ„ÄÉÁ£lb¸cÞ™#³Å7<Ò³ Tdàзc­À¦IEÇb\ñšLç4Ìâ“$Qp±/8ƒœdu¨÷paÞ€°âx÷¦äÒäi8 4„çš ¨ bƒÎ(æ›Fh¸Xp¤¤Í®; rF~+¸ð ¬ÂT%îYaLc%A ÿž~&¸tåÔv¯Uð]œ÷Ú\‹wHAWS»yÈíÆË^be†ÁK—íhz¹5(ÔÅ©Kìê}UðÎ ?xJåg„n•0¸ùóÓ¾jËgy¢Éc'îšØ• xÎ2r=ÿ³<15ÅÔ6„±w©=A*px¬ÿÜÜÜÚ–b¶™%1ˆ‹f H/ÓŒã8ç¯Züî·ºÔ_Cõl¹)ÑMu<Þ)aº±‘ma2]t*:àw¬ýòÞ2Ñ\)‡~ò<óžæBæÞ;õ{uû# òÎAÇ­G¥ê:<:àKçÞÌûr£ óÖ±öwM½Nš°ŒäއR•v²KÆD|cšÚ´±Ž;5·S·$WAo¨hqY ,¤YYùô¬-OÇú-ŽcŸÉò‰Æíà=Íy®5jK–lǃ§JŸ´sýãŽuy¤ÚêÑÍ“hÌd^76pÿ>µâ¯Aø©ã›OO•¢JÏcÏ#Ÿã~xú ó¶aŠýw†(b0Ùl!ˆVz´º¤ûùŸ‘gµ¨â1²•v»ó]†Ë.Vfäæ’GŽOµDÍž•îIÜó#!ÙæÔÌÑ“š’¬?wµÍ0ŠPÔâhÎi¹÷ 7=(ÙÅ8žj<Òîäf€œ QI»Ž´g<Ðæ”qøSzQ“ëNà;qöü)TçŠe.qNâh˜c™¤VÍ!#Ô' ¦õàÒ†+œdSFGJ;úPN ÛúÒ3ÅŽ”1Ȧ– žÝ©¬ùíIŒRzÒfž)7Râs@Îri2(Ý@Î:PO4ÜæŒó@Í(84Þ}8õ£#<•$eç5n9.Mgîýi|Î1Î*”¬K˲L pj«;1ëÇjˆ±ïNCC•ÁG”qR:ÒŠ‘Žj<‚i44î Úœ¬¦æŠØ’¶OÒš Æi ù©z AÐP9§)ö¤8§(¡/Eɦ3dÐǰ¡ Q íÞ”ZwÊ:ÓY× 8P¦i¥ºSKRŠMŽÀH™ç4ÒhÏzC± "—9¨ƒNÜ=(àŽô§ÚšŽÔ¹¥Í4žã¥íšx=éêsЉ}*uÀP{Õ-HzÀæ¢-¸óK#e¸íMÈúP4&})I<Ór .xÅÜќґÖt gƒIŠN=1FqÚÂŒñÇz8£ð¤žqM#¾iI™ç4RwÅ) ÒŒPwc"€sKòƒGP–FÍ;ÏŒj,Š3Ï"‹°°âæÆ™Ö‚}¨Û¹Å!4Ú^(n4«#)ãµ74‡ذ·-Š–+œ6ª[½úÑšjL—ΩµØ‚m;O†ÚkqòȬXçלò;zW¡|7Õîµ›imær.-X.>úœõõ´¹"¥85 굌® 9äö§ßÓšnsKõ CÉ_â4ST1Š(¡˜Pzn#d”ÐÅOØ3ÿÖ¥Í' ½i Å$ }h&£Ž´ ÷¤“ILÏïۧ“IA>© 4ÊšNG>”ÜóšQÍ+€ìšPÞ´Â}èÏ\äƒK¸â£ÝÅ.}è‡ç»Gš\Ð+ }©O=é€óJ¦;½&›ŸzPE°½ *Óõ§ P!ÝéCx¦uëNR8æšb°æ4ÞùÍŒSi…‡uƒMÏ™©c“ÐÒSI÷¦’AâØ”(Ïz`9ëK¸v4\V% è)çŠfïzç4î+ Žh>žôÝÇ<\òhÜb‚qíFi9Å%sK“IGj@IßÁì+ؾøWT»kY¢ˆI .ŠÄd•wÚØ8ä­œôרÅ%ÅÂAÌ’:¢RN}ðò{ý{Æ7Ú…µ“J°óï"ßòË,xÞÃŽ»FqšùÞ#U*Q…8+«Ýù%ÿ{Y$aíe)?%ó×ô=+ÃóÜX©µ‰:JÁG$d~U{]ÓÎ¥¦É=Ë+Ü–,$ÚAŽüsõªÞ‚;½5.`”‡Ê·'vy¡wrJ&„ ã8éŒWÁU‹¨Û?QÀ5B„Wtx·ˆ´è";HDoCn\zæo4ø<Å]>rgC—Î2¬céÅz·Š-´û»&º*±)ˆÀùŽ3ýkæèõ¯i 9¼´“Ë-*äƒÛ½zYV]®Äÿ:[ëû½Jå¯/f2Ìø· Ýï_¤`ðÑÂÑ…;+¤•Ïɱعc+έݤÛKæ?8Ò`Y$uªrHXäšè“±ÍÜFzni™ÏZ\ûÖw5HvãFãLÝÜÓ²(¸ÅÝK“M'Ҍ拀¹4nÅ&E!oJ."@h'4ÀsK»9 VŸÒœ=ª0M(4Çaù¥£ÝøR†õ Vš1šJ3ÚšñJ[µ0SZb°½:$àw¦“èi ¥p°ðøê(ùvƒŸZe&}è¸XRy¦šLœÒ¨R(Oz5/”0zÔl»O+1¤ž”™Í)¤Î((p&ŠA’y¥Çå@¬9I$ ïÍ#)SƒI¿oJib{ÐjB~”ÌѺì;'5*c¡¨GZ”½M4)±Èâ¢9éÚ0zÓ½é±$<ͱӽC»<šÍ!ØpÉ9§ ô¦Ž

‹ä•íZ^ëOKjôü5ùh/Äê¾½ÕešÍG”÷yQØtà短q|žiYÙÉɤqšúì.J1£Od’õ²µýOµYW¨êËv'4ÖÖœE&mc1˜#µÓöæ“iâ•€i$QG'µXz y7)€)¹À œÔÜ«9ê)ܰíš&—š.挚LúÒã4g&‚IíHyRdŠvph'ž”ÒM4€QÍ.qMíŸz3ƒÍ--4‘ÅÓ¸¢›ºŒäR  Rz1Í4Àvâ)A㦊QÇ4&æžÔy÷¥Àyö¢šjwµ2l(ÏñÖ˜ ) BšJB} Ð;ãHM&áHZ€°ãÍ7œçgšLš8ž8¤èi ÑŸSHc·\šaìsK‘@dŠh 7úÓ&ÄŽ1Šâ˜4»ø ,.I£Sƒó7®>\×À7)iÏÓ©(Ó‚æÚÇ3â óµ¼Îø£:§˜N°²÷"ú^ã‹qMwÂÑœŽµžµôíŸ ‘ ®}*sN˜š‹w“fñC‰ÅçoJPÄ÷©*Ä””ÐM(4aÙ¢›š7SÔqœSsß4gÒXvOjÅ3&ÆÂÄ ñJ E¸çŠvîô\äÑœSsК3NàH (=ª0Ø¥ÝLV%öÍ3u8`‚h…Í 4”P Òö£8â“<Ð;X\ž”ᓜ ri¹i¥‡­?óH\žÂ˜sj3Žù¤ñJy=) qI’8 c‰èqAlñMÏjLÑpš3Æ)¹zR¸ê:R¥â”ûS¸ìqAbzÓO\曞٥pMæ™’hy¢ã°ãéNèSMôõÉü(B$qR*Ò.?€¥ÐÕ"[¸å?­79 zf—Š¢Cm\Ž‚šO¡¥` ¤

cC¡^¢ÆžE0¶){SXûPRši'¨¥É¤9©¸Ã>Ô¢’Ž”&÷S…5U‰éJr*€Zǽ74¹ Cò£uGº—"X~îÔ»ª=ÜÑœq@Xw£wz4™&€±6}(ÝëQäzÒæ€°ãHi2hÍ œRdRz(…Í&M!>”( IœqIšA@Ã&Œ‘H}¨Îh¹'Š)3ëM怜QÍ4ŸÎ—& Iô£4ÞèÎh¸'4 “‘E*ñHœçsÎhÍž´ÀE»;bõ &¥‚FFܧr*tg-׊.&Žâ7öA‚RÿjS˜ÝxÆF ÏcÒ¹Kû©.î^iÌç-õ5_$ E¼î®L6ƒ”§F6oúû*V©Y%7{8Ú3QƒëC94ÓÍu³4‡IÎsŠCÖ“EÆ)9£Þš -@ÙH§!5ë]wÃO¯ŒüIŸs)ŽÎ?Þ\0ÆvŽÂ³«Z4 êOdT)ʬ”#»žñ7Œ®c·Ñ4¹¥W$yÅqã®Xñú×Ñ~øyà߃¶‘ø›Z½³Ô/Á(òÊãˉ¸Ê èO¿4–úž§i–-”°éÖðåXSœüë€X²r}ë‰ý£¼S§Hšg…´‰Õ£„½Äè‡"7ÉÏ¿\WÃâsRcµj6—h¨Ra&¥Èj$þpô¢«’{QK˜»!(¦ƒïI»=êJJ 3 Ñž( ÏcH 7<õ Ö€œœÐqŠhj^ô§Ú“š>”gv “ùQÇj(ê0hîM'×½õ ,RÒ{zÑÇJxæŠh>”¹í@ Îh­ #šhLu.M3'4´Ä8Pqõ¦Ž)F昵)'¦g½=(ÙÇÒØ4„õæ˜M Nh'×ï-cHÓ4øbKµÙus <Äç'ò1þ5öÕ¶› hÖ~ð\WwšMÖêKY7bBƒq 9ÎA85òw€t´Ôm4Ðå¤yi[nN „zð•}]ãM DøYâ躒®•{¤Gw$~oﺶH^˜$cïžkáó®ZÕdâ­g¯Èûœ’§J NéÙ¯ŸCŒÓô+éìÞÉ5=DEn@í,Ï<‘Ð{×=âí •™/î>ÕÂ`Ž6“ U²…ÀϾ+BoǣݻÜohÚVá`}Ò}ý« Åþ9³¹¯íµ­¬eÜ]°8ö¼/}Í*{·¥¬ýÚ¦ý¯Â–·ìx¯‰¼!‹m%üGËó¤2 8¦}k—Íkx‡Å7Þ!˜™¿wmË?©õ¬mÇÖ¿MÀÇ)bçä~E˜Ë ,Cx4Ô<É3QHI§g­4à×YÄŠÎy9T-ëW jzÔ/ž‡,ÕH¬xâ”V‰ÇcLÚÝÁ¨ÔÓF<69 =3ÞάKºšçÜšP½ði€ìñFìŠLRP!Àž” æ›:šP@ïBÝ)sLÜ 8Ž)€ïJ­7=¨ÏlкÒçœSsšLûÓ¸¬H 85Ež˜£4î+©FHô¨Cš?šb9Í!=è&˜s@Çšm&{QéHRN(Î)=(z€½)èÀðqLæ…=(@Ç0ä…¦Œ÷ ¶Oµæ“ñFy¤¤É†)$ôgçµ-Ï4i@Å7¿^´¤ö£>ÔÓèiËÒ€½3Oonß­Gž2zRçÞÅb]øü)ÞjÀÁß“ŸLTíFyëEÂľaãÅ(•‡T Ò¬J$#ñ¥ó2*ô£w½ ,̇Ҥ[² b¡ûC5TœÐOh¸X‘›'8Å0œRdø¤ÍCºŠ\šfH£w½HÇsOEÉæ‘v‘Zxâ©"&EÀÍ#G“‘H­ž ®ïÁ¿ u/øWUñ—©Z¤úmÔP}–g Ò‡RK)>˜§)(«±F2›´w8O(Ž;TdzVŽ·¦Ï£jWTóE,¶Ï±Ú&% Ç8$ Ï'Ö¨Ó³ƒGµ¦îÅé“A4Âß•!8=x¤»ÚÞÔÌûÒæ‹…‡n 54CÓéEÂŧëQ÷¥Ï½0$õ4{S7w&‚Æ€$4ÃI¸Š7Z)¹÷¥&€ ž†’ŒóMúÒhsAëH:Š\òh&ƒŒRgÖ“gµ(4™àÑŸz,úQÔÒ R})€t¥¤(ŽhgÒ‚yæƒÒƒŒýh`‚”¦›Í&MHË*r)äTBL rËëWtMŸA‡ â“4ùqÁ#¥”…ÝAëMõ šC°¿JpéLšPqÀ Ž õ¡a{bå¬.æ·f]¬Ñ9RG¾:ÖrgvîËV"`}j’RVdIÛTuƒÆ—úl²&7Ú!x‚ºŒ9S´@#×8®fææk©š{‰I噎I?Zfîi0+*JvåJ)7»¶¯Ôº•êVVœ®„'ÐQKÅÕÐb7i44mƒÅ*“JÏŽô¬=JÍòœ´ÍØ4®rÄÓGZƒT<œÒS3ïFsÞ¦à;¢“&Š`G»4¹¦fœ <W.È\‘K׌SI P+ ÍiAé08æŽEþt™À惊`83Æ 7wµ¨Ê ‘Ú1“@ƒ,9"ŒæŽ)¸žE(8£=é3Ž´™èš:ÒгÎ(Í74 Ð!Ù¥€æŠx<ô£´\ÝFE7=©3ǽ Z“u34(‡–â“w4Ò}i¼ŠMŽÃ÷{S²EFoJ7EÂÃóKœÔ`š2GJ.$¥ôÀÔ¡©ŠÄ™Å*œ0â£Ýš\šcÒ< ©Éoe ÆíZL®Ì@pîQØcnkè¿^.·Õ|Iá˵¿›}Ήæ H#—ìì U%X…êO­|Ÿá­J(’K)­u‘’UËT©çõô¯QíüM¢é×ÂêF¹´…á8}Œr~ßÈWËæøvª6ºŸQ”bÚ¢’Þ65_ı]F#»»I‘•ƒDŠÌ8àáG5æ~6ñÜZ®¡¡ØDm,˜ðwH¸'ž}±Åt:x´ÕéöÚ}úÞZÆn·HBŒ1$ä×8®;Æ–w÷Ñ\\Ǽá‰hä.€zÕÍ’PŒq_¾M/ß½¾GVwlîdÖºÛ¶Ö02?*LÒg­&H¯¶>ÃòsVWLÔœ®Ý>á·ýÜFyÿ<ÔÓ‹yÖVeª·B+ªâV³ ¡Š%k–ÛÒô¤ú×=yÖ𢟫±ÓB ßÛI¯Es•’9!cÑ28þ‰ºÕKT¼Õo$¿Ô'2Í)ù˜ÿ*¤Î=kdÝ—6æ-+û» OÒG¥4¹íI¸Ò¸ì;AFöÅ0¾;Q¸úQqØ‘B“ÒœÅWµC¸ÐÌÔ®+¶j.x8Í;'¿4í£Ú‘KA½@ãœÒí#µ !n9(@Fxˆ8÷§ñҚ؊?é½ "ÉŠ:çïPîïFi™3F}è £9âš(Î9 CéCS3Ú€iÜ sš)¡¸¥Þš…éÚœñŠ9Ç4œ÷ Bí'§4˜Ç4dƒÖ‚}é1¡IŒSw#dšh¸ìçŠSÍ7§&‘ŒÒ0@ÉíGÒ—9ëÞŒý)€ LÒðE'éH9¦šp„ çPsCqFqÉüi›»žô !婹ÏçL,I4Jã± =Í8Œ✠14IA(^G4ãÀéM!\Ž‚MHT•Î*3ŒqE€7QœÓXy¤9æì:œxê)€úÐ[Ö€°â}i7 S3@9¥qØxcÖ§Yý@ª¹æ¸œqM2\nYsÒ¬Á©^Û –÷“Ä¡·b9 Ý3ÁëïYÂOr)ÂCØÕ\\¥×‘ärò³3±%˜œ’Ori¤Æ*ž§­XX¥hZà!1¡ Í‘Á9Çò5I‘fBÈTdT$“Ú¬¦¢tqI®Å'}ÆBh縦îÇÝFE3pͨ‡äQ‘LŒŽ HhŽi¡»fŒš8éK»4Ê3ŽiÜ,?<æŒÓõ¥&Xq>ô¹M4‡îŦ–ÇJMÞôîš@qMßAn9¤ǽ&îØ¦“ïI¸PºÜûS7P4ĹéšqQóJ §qX“ éG”ÍÔnõ4\,H ¦·4nÍs@¬&N)iM†!#‘FNH¤ F{ГHN)9¤ëÞ€8æ—>´ÜàdÑž2(áÁãšP^‚š‡×¥.sÉü(!aŒ/AV‚ưÆQÉr a»ÏAy5iIK¹/kÏ)i¼rHãŠíWrSöŒÒ±üª¬’–8ÏJ™;v8Î{`SL¤õ5È9¤Ï95×4åDË 'µ$’†íQÔR{R¸ì;4¤ÓzÐÒ¸Xv}h¦“ïE;…„÷§g½0ŸzR}êF)'?ZQÏÜzÑ)€î½iqŠoJ3êi¦Ç'­{SG¤ÓƒÙ¥Î9¤ÈÍ8sÔP&&r1N““§C@!à÷§u¨³žôàØï@XqRéHO½!n¾” RsÚ“wj í@ì;œò)EG¼ŽôoÇ4 Ä¿JuBšQ*ôÍ t4èi›×Ö·h $ÐMFXc©£vE°âý&ìšnhÍ+…‡óHOJi8ïIžh¸XwjLÒ{Px¥q‹ž(/žÔœɦœg­;´ày¦+g®irj<ðNzRo÷§q$KÎ3H‡qœTEøë@~œò)\v&'âš[œãè*?0g­!Ñp±&OVàÒÅB_'­ üõ¥r¹I7Ѽô¨³þÕúšWRo3õ-”íÝèɦäcŽ4®PìœPµ78ïK‘@š]ئfŒóŠ.+ÉëFHõëMÝšBÝê®’9£qïLÏ`hÍ+…‡ç»ª<óÖŒç½ -žÔ™̌◭ Îis‘Qþ4ÏZW Î8¦æ“ ÷£=0h¸ÅüiA晟CA8¢à?w½8â¢Þœqš.F{S÷£8ïUqX“vN)Aê=ê,àç4¡½è d Z‹w|҆Ͱæ3LœO©¨Ï¯Z¤ÏzLãð£ñ vš;ãÒiTàfP°é>G(:çM,H¤'““Îi3ÅMØìKROáVºUrsÅKç`qT¤‰”[-õ¦4á}ê«ÎHàÔy$Žhrì ËrÍÓ¥F“œT(úÔ¶Ù\¶[“IœÒžôcž´‡aA i=èÀéœÐu(9¦Š8ìh ÆyÅÒyàÑ@†îö£'=)CFqAV“KœÓ2iV4:’Š^)ˆPiiN)i¦ŽiÙ8¦FqÁ¢â°íÞ”™ÏZnh8#š.;X £qPOÍ0œw®›ý©7LÉ£Ô@õ¦çgš÷í@cùS &ƒõ¦›³FïlTY>´¹¤OZ3MÈõ¤ÏÒ€±&î:Rn¦î£=( µ<àSr3Š\çŒÐsKM'ÞÔ ui3G½(÷¥èr)»…  Qœt¦æŒ“@‡dç&œµ38£&€h~y¥á4À}iý;’+M'”f’€>”Ú›¸çu<š.ç œö£ƒÍ'9ëEÀZ3íF Ð  Í.3Ú™ÍIH䄉ܸ…Rp=h Çj8¨Úe<Š“NàHŠN§í¸i£¨"˜ ‚?:B4ãÓ4`q3ÇJLóš•FãHcÙKDñU\l¯eÜ( 0檻yšLqœ{ÑžhÀ­(­'Oz\÷Å.02M4Ù 7 !aÚš[„ç¥b@Ã<ŒS¼ÌÔÐO½ —ö¤, GšMÆ‹ŽÄ¡¨'õ¨÷9 µ °ýÞÔ™æš):PÍ4œ7Ru bƒJN)´PèÎ)¹âŒæ$¥!lÒšLàvêLûRQ@Çn£"›K@}©r:M¸ãµ(ëÅ-0Š3@éøÐOµ&}é(Àçµ&O¥%.{Pƒš\ÓrJ\ŠZ3ëHM&hùíJÌÒæXHÀ`J'?Ä*ãŠ^)ÝŠÈ›Ïã§4oÜ* ÔѰH¢âjÄŠ 8náFñTHãƒQ4~©Û³N>ôЭŒv¤ÍJê1‘QŠ–¬Zw4E47çKšC°ìÒî¦Çj2}h‡æŒÓ2hÎ( ›‡ZnsÞ“<õ ,Iš3LÎŒÐNz @}©Åó‘@ì.p3A㇚>¦€°§ƒG8¤ühÏ #Ú“¾M¤æ€8§gŒÓ /4àqÍÍ6ŠÃÏçKQ硻☚œ½G‘ÖŒÑqX—w œóQŽ{Óíž”î½):u¢ƒÖ€´Õ`%äv¥ã4Î=}hþ.´Òx¥Á Ö˜y®4ñÒŒÑÀɤ¤1 AÁ£œÑÞ†y£4Qôí@ KÓœSsK»4\ãƒ@ïIøÐs@ O¥‚“Ú€u”P(ÆM/¯4t¦`ãëF .G­àÐ:Rö¤çš3ïHC¥ÝëL'¶E&}é…‡îçŠLçšnx#4›ñô¤;>†“ð¦–õ4në@Çg™•7#¦hÅ8‘×4™àâšHõ¤Ïj.·c­ñқש¤ ñÚŒäÓ ÇzÖ•ÂÉ#¥.O¥7ñ£ñ¢áarhç­ éÖŒú.H !'Ö“4\,8ýhÏJnp(Ñp°ìàÐN)§š3šAaØ÷£œšA×­&îÙ§p×­ ¦ôïF}è 1Ù¥ÞÙÍš`.qÖ€i)3Þ€ &hëŠ=h¸£§4Ÿ9Í;4M ë@ P)9õ¥èÛ‰=(&“Æ) q¹¿ i D3?Ý«šN‹ªk·Ñiº]¤—3¶ÔŽ5$“ZvvZ¤•šÙhò$÷MÙRD$»meÏPǸãšõMà7íñRî=>ÓÂ6JZK…¶ñ¢¨P[<±À€IëS)(«·b¡ TvŠmž;ªèWÚóéÚ’„Πçiô>üP’éâÖ;y4ðÒ‰K<ÁØ3'(ÀèyÇzúŽçö&±ø} Eâì,l­åCy ¼Rºìn«„ÎíÄvǽx—Ľá.•äÉð߯Wú¹“⸲1,c'Ääž=;ÔÓ­ ŽÑÔÒ®¥Í=<®®yûmóL,:(üiÌ¡ŽIÁ¨È<Ö¬çC·ôÈ«v—·neµ”£²•$rQÍQÈÇ^”›°zâ„ÇbÜæ¶é“Ó…ùT.ªàJý*/0ÿzÉžô] EËçñ¥``/>µ ~1M$žõ7±V'Ýž§¯j íT!»f‚Üç4\,MæÒšºÔ[»š3ïNábF;¹=i½:SsïGãJã°üÒî>µi3Ï&•ÂÄ…&OqLÞ—4\,8·<ÒgÚ(¸Xq4ž{Sh¢à8Ò´gŸÙ"ri¹¥æÆ.hÎi:RR¸‡gŠ9ëM£>ô\,;4}{ÒÇÖ“ñ¢ãÔwÔ”f“4…£4Ÿ­!<Ò`.h™"‚y¤4/áIœP­ä Qi3íA<ÐІO¥ö œÒš8ÒGj Rš\úŠQžâ“œW¸þϱ7¾\¯Š|U}»ªY¹@íût<ª‘ÉpØWÐ×Úä6 ¦‹€!ìàò+ÎÄcT¿wKï=lZàý¥gò<»Dýžþx#ÄZÜÚtÚ¾©¥ZCmo-ó+,+*¦ÔUUÈ œy'ÛíKûEê|xwìçYÕ%òlc™w"¨Á’FPFp0¹J÷îÅÓe9Ú ±ÆOšü‹øÝâËßüQñ¯uy¨Ë¾• ŽýJÍ `à!L˜Æ1Q…¦ëÏ÷šØß]aiÚ’³f׌ÿio‹ž?Ðu ø§\†ïNÔÙHM²/k†är\×—Å7woJc¹ëÖŒch«?9Ê£¼ÝÄ$õ¦±Å&ãÞ‘˜ÐØ$!jnIëAõ¤Éô¤1h¤9ëFiX,-„õæŒô¤1{ô£4›¨ïŠ ‘ùP4„ñIžÔ \äÒ“ŠhëKÏ­Í( dRn¤£œÐî¹ãŠoZ3ï@Ȥ'™4dÐÖŒûRFNhèrjBT ‡yÏZi’ÐöaéL8íAnÔ™¦“ÍôiààdR° Ú}(ÚAæœOi„š,` PsIž(ÏáJÀxÍ&{P qsIÞŒŸJ^´X.‘N SŠA׊”ä!ªHM÷¢Œ’sG8¤ÐÀÑFZ|Q¼Ž©3³£$Ÿ@)¤GOÆ;f¬®™¨É3[¦ŸreA–ŒDÅ€õ#Òi_ ¾#k~“ÅzGƒ5[Ý&'d{¨`,ªÊ2xð=¨m-Ä“z$r[FzR„É.M}¡~ÃÿüGà»éÚm¼s^!“û>âuŽ}œÃøF@ƒÏJû[àì§ðÃá¼6š½×ƒþÝ­­¬kqsx H@-°6BóÆEsÔÅS‚ÓS®ŽµWf¬¼ÏÊd°»‘Dµªc$)ÀÏJì³LO×ûµû»§hº3¶·Ñí¡GûÈ"6=iº×ƒü*¶~gö%‘àR<þUÉ,˕ۗñÿ€v¬¥¿·øÁ?Y ðA{SIôúåñ·öIøeñ{OMJMXkèþUÅŠ,M6W€ø#v©¯ƒ|yûüxðsMskáC«Ù+3+ÙÜFòä‚ɸ6qØÏJ飋§W}™ÉˆÀU îµ]ÑàŽ˜§]×ïÙ×~ÖኂրHê>íW¼ð_‹4ãÛ¼5ªÛùã1y–r.ñí‘ÍuVf(àc§¯J³.™¨[î3Ù\Ç·®øYqõȨlN_jvÆvàP§…\ãp'Ò—n{Ñ`¹Ç¥ÇQRyd÷®ÿàÁ{㇎að^‰u 0Éqs{8>U´j>ó2pMLš‚æ{ç%îÏ;ç< \Ú¿J>ÿÁ>>x^;K¯êSø‹R·ŸÏc 1Û0\àç#œ×{¢~Æ?4ë)¸ð¥µúê¬ðZ]€ðZžKS‘‚NzvÇ,u5µÎøå•¥kÙ“²Å,24RÆQÐíea‚½uÿ~|Fø£qäø'Â÷z‚«˜ÚdCå#c8fÆWé×?cƒÿhÇAð–™;*þò_w~¦´`д6öâûNÒíã¼½Ûö‰•™.Q–ëÀP? ëfЧAΞ¦³gðþ©wnëòÛoH3‘\Šq–ìõ•5d¶0¯í-™›8äÈÁV@ËÏ·zùcö€ýŒôßê7ðv¥“«Kc§ìQoq(î1„Ž=3ھʷЭ,P3’OâsÕ©FƒfòµÊÙ ‘† ê;ROe+Å…\­á‹kK˜˜Ÿ>Ä]ý˜¨Õ rO.¦RÒ½9_Ôü•TcÑM\:.ª¶‹¨6›p¶Ìv‰Lga>™¯Ö…ÿ³_ÃσÉp¾Ñ »–é÷Ë=Ú %²«¥zÂZióY›;‹žÆØŒ`¨ÇN*§Œ~ra”ÎKß•™øÏ¤ü%ø¯YK©i^ Õ'µ†#3J¶í·`î+¹ñ·ì—ñ{Á¿ØêÚ8ÔåÖF#ŠÈ7Û¸«Ó½~­Ü[¤¤*)T U³^Ês4ŠÈ«´#©úŠÇëòz¤l²˜-ä~Xj?²ÇÄÝ#ámÇÅ=ZK;;]í%œÏ¶ácW(X©ï‘ÓÅyt×nty¼A‘u&›nþ\·K1£qÁnÇç_}|wý”>9|F–âM7âA¿Óe”̺]ôq¶â@P\ŒgÙüýœ|oáƒúω·:tÚn¨&Hb³cæB²©K•99g“K³ƒ^·XwÅ5¤¡~êÈCø_¨:„7+Xí¤ÞØ@F0¤÷5~ÏMmWÍÎâ0Ä÷¬žaU{ÚePJÍ»÷?#tŸØ§ã†«á;ï·‡þÈöŠZ; ò³Ì«ÛTóž8æ¼6m6òÞiašÚT’DªÈAB0}9â¿z¡Ðô”Ê¡cÜŽj”þð´<¯¦Y™n¹…wIþñÇ5QÌä¾(ÜÊyL\’±øKý‹ª—Xÿ³® :ïQåžWÔ{UGŠHؤ‘²‘Ár+÷VïÃ6aGLñ®ÀÛG Ÿ»ôö¯?ñWÀŸx²õ5 kÁz-ôñTi­P¶Öê "¶Žaw¬)eM/vøÑ´Ž¢ƒô¯ÓŸÁ?¾ë×S_i¶ré-q“å[Mˆ£>¡rá^-âÿø'N·beÿ„Wƶ·R©ùaºFBGÔ]ÅÑ—[³ÀW†Êþ‡ÅÀJæ¾§ÔàŸ¿­4¨¯mµmâàÄÏ%¸”«Š PG½s^ýŠþ2kz¤öZÕ–…mÿÇÕÕÒ2;•ʪ„,OüP³MÏz3Žô›½hÙ£4Âþô›ÍbL÷ ·lS7RÍJbŠ‹>ôP×£­RCè¤ (¦.£M4ÑE‹ÞŒsE"E¥ïE#[ëŠCÒŠ) ¾)¢Š(@‡¦ƒÞŠ(`€ŽE!ëEº NâŠ(hêER¢Š)€” ( –EáÒƒÒŠ(´QE6¥#(¢„z}ip2(¢„àzRàc¥S` LQE&0£§J(¦ÉD±€y"¦袟bÖë_¡_²5¬1þÏ:%ò‡óîoï¼Ç21$$¥T žp0(¢°Äü+×ôg¡•ÿ^óGÖþøXŽJ‚Orp+*U]Îp;ÿ:(¯_Ä—©ôOb%ù F^ ï_#þß~ðŽ™ðþÃź~im«Ýk1Ç5ÜKµäVŽBÁ±ÁÉ稢»0íª‘8ñ©<<®|!ü4É:Š(¯aŸ0†Í7¿ãE,°=i?‹ó¢Š’ÃÖÿJ(¡n!äPh¢Ÿ@AÚŠ(¤. z (¢‚„î){ÑEõi½(¢Žƒ©(¢†5-PAš( ŠNôQ@ëŠAÚŠ(ꥢŠlèEHESD±Ž1Ò›üBŠ(Š QEçñ¥ÀQR.¢ãùPh¢šÜ:Ä'"‰‰UÈõ¢Š´CÜ`~¬GQI ¸W¸~Åzâ?ÚE¦¹§Ã{=ÄqÊ2¢EÛ†Ç|dðx¢ŠŠÚR—¡¥ kE>çéý¯ÃÁ¯\j±x?I[©aHÞO²§* cïé]¦‰£i3C¤éšU¥­”‰óÛà ¤mœç*(¢¾~£nÞ‡Ö¨¤•‘[T·†ßP+k¦ÕU^˜­H‡–Š©ÀcÛŠ(ª_É3ÜKF?mAž sùU»Ð l¤p_¢ŠÎ_…k5”#Žx¨™ÏvÚ3ŒfŠ*Öä"­Æ¤\*,úe¬ƒ;°Ð©çòª·šƒq´Üh–y`ìó-‘¶ý28¢Š´õ-%c&ox&ô2ÝøGG”H~}ÖQóúVr|"ø_4éà- I!efûd‚p{qÅV’mDÎ0‹Ý{ñOà_Â-+áWŒuÍ;À:TÑh—î“,g(ÞCò9À5ù+ÜÚŠ+»Ü£+ž>iÆQåVÐpë]€uíkGñ5…¦“ªÝYEªÝAgx-å1™¡i(HçØÑEw4žç—$~Ðé#ÊÒ¬`Lì[hÔrq´w<šê¢²µ’ß9©4Q_5Ssì VoÝJR?•W +³8ÜÇ$õ¢Š¤ŒÛÕ^”øù<ûÑE1à‚*húâŠ)1 Ô ò¶ölI"ªÂªrÃQI|(¨•äU'§z·  ÊŠ)È®…’I#±ª «½x#½V؇¸Ø¿x?'jÒضäc󢊙ná8Ž0Í„†Ž5l…"Š+8š"IqÓ½1‘I9QIl bhvôèx«‘…úÑE)ìEBÃ’Tê(ÀØÔQYöØÎk>•5 iϱãpÉ–Ùÿy0Z(­¹šz2"é;£ó[Å–°iÞ&Õ,l£Aô±F€’`k."[;¹æŠ+Ù['/ˆWÒ›Ûñ¢ŠLhR);E!‹ŠŒõ¢ŠBh=(¢ˆ{})J(¤Ê[  u¢Š 9¤¢ŠÐõŽEQHƒÿÙtkabber-plugins/georoster/maps/darkmap.gif000064400000000000000000000316521500237002100205770ustar00nobodynobodyGIF87a£€^^^,£þŒ©Ëí£œ´Ú‹³Þ¼û†â”æ‰ãʶî ÇòL×öçúÎ÷þ ‡Äb(…L*—*£ó J§ÔªõŠÍj·\#óÛ|Çä²ÙN«×ì¶û ËçtÚùžêâ÷||ý(8HXhxˆøÔ·ÈÄøY–8IYiy‰™©¹iéiVS¢ðIZz‰šªºÊÚêúj* I’1‹‹ »ËÛëû ¼&ŠkÌ·p¬¼ *ìü -=MÍÀ|­mZqVíKü->N^Nµž®¾®t€RŒl¾Š&_o/þÏßï/™Ò’€  ÆÝ¿… j;hh †&˜ò@¼ˆñ@þ%è²aÆ,9†»EFá»Q§5 3f0?!ý°¬‰sL)MÂÙB™Ò¤Exô"ÞÙ‰4鼜¥’1}ŠNZÉS¹¨ØèÔ[»M{”zýj ª'kbË.{FËj€„dÉzãڬܹoN~4O Þ½cw­lÚæjU S‡¢"E7±b+ƒUò zá±ä£aÞ=Öª±&À‹;{¾2Ùr†Ð¤·^ú÷JßÔ¬[! ¢´ì•û¹žÒç¶îݶÚhøìá3)ãÍÆ¦PÑÈ›ÓÅ*üidâÔM×6æ\ÍKèÙ»“3¬÷åò–ns:¨ŽòéãÞá_û¶½ühÅÃLJoý2HªéþûKä„Ù|sP&`3G~ÿG[Võ”MyþMÈœq ÆåØ{¦q߆ºÂ„Ö…Ôy×<@aŠH€H Q+~¨GƒEÁHãRõq@ÛŒúå×[€¨¤f›‰·cƒ5‰¤kB^øbx+Üx™ƒ²à䄯pçb…In¡å–^’D"¿Õ2&•Kf(%b£ V¥,²…¢‘_‚Fäœv:¥ˆ:v°§„Eªif›éÁæt`hh¢<('T7±z6 Z]/MvÖ%\y)Ê© Œjhb™£ÄÉ&|>¨S‚RZÚ/r>å}†êc§¶þ¨˜¯Fzw±Àêd Ý:L‡uhÉþ±ÊÒ:eš³f¹)ƒ¶,_ËjI ÿù3É™×F£Òò¸ˆ‰¼JªÏ®ÌV{â·Šd«­µî™† »ª@(G f±¹¹åìYX°+°½Ž¤lózd0/½¶»Ö© ó[0¶ëÒpÑ8h]«eì0Äø­»"œQÅx17 ã°±.üȹ¢®\ {*ui¡Ûp˜r®4§Û¢Ë@ =1´™þ\„㊻Á˜:?ÄsÏ#ÝÓ0«xè¿$«Ku·p.Z¡ÈQKp×Oæéq› ?kve±âZ¯Þ~d“ÆÙð¶=ÚWÉ÷‘{k‡÷•z—¸ž ¢¶Qs'ÎñàBàþ ªÝo³r8¢7íwä€F¦(o^,gGN1sV/ý›E—æ¹±¤Ã½¸lJ­/“œs³ÿ-9ŸG[.šÕMgìÿN*¤„+´}µw2<ó(粦ó2¿N<²è‚ =÷Öw3ý£3;šzø_7_'мÏe­çI\ùö¾µ¿3øê³ ?ξÏP½éìï¬+ß P×?ýåOw\Õ[ò¤ª/´ûŸûH˜rë‚ü£ c~¥½î-h}én48: ªÇ|—›Ù{P8-,σxúW·6Â÷‰ð{çÐ {t9únO#‚á>ª¦²ìS7ÔV¸Ãõp€Jdþ©U¾%ĈüÀâ,ª¨±(Êèˆ@|Z x2žìŒN´  Õó".2E»ÃupŸ.†Ž^Ptˆ×xG£¹Ñù‰Í£«èÈ/,ìR²2ª–p!Dð!#'©Ã؈LJ¬Ioǯ]ñ]gÈðRÉ€ñN:C â%ÑXJᨓò¢ß~Ä(¨”¥$a‰/P®gI]ŽêW:~@k´| 0CR 1¦°•ʬdÌBöÈI Rš”|Íáv2ÌFœšDT3Ï µäA¦[NŒCxHï—Ü %Ø 7’$Ún›Ú|":ÿÉCjd³ Èô@0+¸KLÞ²wø„I³þ„¡µzt¢ˆ›Æ~ÐÉrj1’çÛc<ý—Pûyò ÅÇ)òõÐCˆ’-¢¨K±óÆA8óÇ4RA=ªÇù)ô¦Ñ çB©—9„4iët _ŠÔ/úR¤#Æ4…š¦‰Ô˜MJE²*‰vT•®+žIÌ|l0^Õ|fU“ŠÖ/¶c0÷CÞ ©R­ÚBs\MãTW‡Ce§kµ 2Vv>U‘Y4gZ{P¹ærr«kNmiB¾>°£ô LYÆ®‚°ÒSEÕ@ô$[ÄŠö±Š¥§§Y©»~Ô¬SmðP+¾–6¤BšI#6[»Æ`”½q-÷ò8Úà6ñ« nTqþ[7Ðö¶xckJ‹û9(Œ¦KzŸe®)YÈw»x!)wËÒ–h*7¢ÌݕӔŠÙ* U6»ia"¤œïÊwºœ¯t¦É ßRå“>«o âSú–‘§å/kí‹à_Õ6Á~d)qAiZí¨ÃÉgn9`ëÎf¼ îpbwëá’j§qìoߎ –—Y±~èápˆ_LZBÂø›r%1M|:ÉÈÂMÓŠÙ{à y Ô²3,*ô*n/sQ¯ùÛªyÊd\0•Ç伾¶ŽÁIqã|ìXaIùÊdN§Ë<Á/2{]ö «Ö智Ít6³šEd@Þù²ýœãW‚õþc+͹΄*N}{H£&zÏã2†Uã1sÉ…®4ƒ”´jÙ’Œn´g¡ræÁžt°°Ó1”ûtcK«úÅ›. bÝqjk4²limÇÜÙdšÚ—«îõcýÝyêùÄל¡ƒêšâ5Qv´¯ŸÍj o—nƒk§5GÛZw“Âúô{œªdòA{Ü0ö´÷zá‹eÑâä§¶íºU/¶–hÄe÷²ÍMî|c9Ýñö°´Ãa{/—·„5ô=à <ãš®ÂַÇ­èŒ.üá(Îö¿'|!+ó™±O[Ç'Þ²VS|äêvïJMNò ›•Ò6ã¬Á—¨ðçÕ;ÎØåÈSŽsþA‹{±7LÎ7+;cܯ3·æÐ½Ýmš#ïçL§ñ§ONì¦7X¹ Ï/Ñç]Ã-{üãy&o×¥v•óúêaoâ×Ù§t†yÍÞôz]ªí7)^¼ìtoöÀênv¡å5O6Ö³~o™[]ï} 0Þ_a "~ð=-Ôûý\·üƒÛäo¾øÌ»òIÊ%¾5y+lô;/·¹>EÏsˆß•½ë'*ïu¾>ÆÍÛMúv&†íúš½ïÿIÓÒÿ^îŽ^»Úý>5XñžõÃo> ©éü— ŸÔÔþ¼»á©û?ÓóÑïþóëýË?=–¿Eæ&¯rðä»Yú_¿ûm þ÷þ£>:b9Ëãír­sûÜ—¿ÿU¶@òôÏ6wöd>ƒFbЧ2A|"nÿ÷~ýxñ·jhÔ7~ýG;É%7ê‡væ€IáwÆs–ÖxX…G¸w¤×}§ h}4¡=#vW‚™Ÿ&*’Xƒ¢)Š9s5žThd6÷S·ŸSyµ†[®9˜8 5:º£¼9$qŒóOø–ÈÖm˜¡ô—¤ë¹¤LÚ.Nê„Pê6mé¸É]úSŸÁGGú#7,È ¦”"£R3fJVe¦¦Ð„)ZX}§šJ}:§èU§J›\q6BfIé§ŠÑB[ZA„š;þÙþ¥‡Ze‚ò¤ ê6–Z7š¦Ã‰¥Êw4”úžQb©šŠÌi`?ªqfiJ6JcDc>(ª0º‡¿ä¦6F<®Êª6C)—:}¹¢î«kÓ:z¬µØ¬UƒÇ ¢¼X£4¬­ú¬bÁ:ÆZŸTZ*ؤ p…¦ '®ÑšP2šMu­n’­b÷Ÿé…ª*%«™«©Õ®«I^BÙ¹®ÑuìêN𪧲Âx ©-6®Ù‡j NûŠ˜ý ÿªsJÊk›0Ä am«°-J{1Q;<ê±K¤#[®ÝÚg8')“°Ù—¯ëç<àɱ$ûS´Dž›8,{¯Ëµ°Qذy§&þK³åœ±‰³j±«µ³hè® x]ù‰C+iB±Þu´vê¥æ€;TÛ2‰G„žRk¯\Û1óú¢\â(YK[»m=˰¢ØŠÇ'¶©E’$j´Éúꊷҥ³d4/[œ ¸ƒK¸…;¸¤j¸‰«¸‹Ë¸ë¸ ¹‘+¹“K¹•k¹—‹¹™«¹›Ë¹ë¹Ÿ º›«÷J-º§[¹3û¹~‹º…›%EJ¹áÚº³K»µk»·‹»¹«»»Ë»¹›®±Yº²Û»¶ËºÃk¼„»#°+¹¦{¼Íë¼Ï ½Ñ+½ÓK½Î%¸Ÿ¼K[½±[¼ÛK»É‹ŽµÞK¾åk¾ç‹¾é+½þ’^Ù˼ê¹Ì×½çË+á{¸! ¿ù«¿ûË¿ýë¿÷ ¾¡à¾õú¿·ë¶ÓÛSzëºì¸<“ Á,ÁLÁž+%L”½<¼ ¡øâ';‰LÂ%lÂ'Á ŒÁi‰ÂÍ;¿¨‹DÈ»%-LÃ5lÃ7 ½`¶Â ¨ž8ìÄC*^Í¡?lÄGŒÄIl¹:¼Ãá¨ÄO¬¸µðÀ·£¼ ÅWŒÅYÜ¿ÛÄ줺Z¼¿Ø'¾û¹/`lÆgŒÆÿËÅ]˜i¿úë,}ÅdüÂnlÇwŒÇcÌll—y<Ç™Z¾ª¤†«$ÂëLJŒÈ‰¼¸áÅÇ­T7ŠìÀ†ºò´þÈĘÉ™¬É›lÁ<‡‡<¾Î«À‰ëÁ»ùÈÉ©¬Ê«Éž i¼XÇþ{,Ç—|ʬŒË¹ÌÉ®<¦¨lÆ–L¾ûž+ºlÌÇ|Ǽ¬¨n|½\E¬ÌÓLÍX¬Ì@šÌ#Œ¾1LÊYZÍŒËß,έ'×Ìqy\ËÁÌÍ„¬$ã|¿î ÏÄæÌÂxü®ÂŒ¸ÇÛ ö[ÍïÏÿL¼z±{Ú—Ì@ÙÊ’lÀ÷œ wÒÏþܸ†ªÎÆ Ðò| §LÐè Î+Ê =ÄvâÇ#†ÐÏëÒ½»ü8Ð0›ËἺø¼/ ͰÊœ{¥±ÛÁ_lÒÆK­Ò¬þœ\‡kÐÁŒ¼AíÑvL¨"]Òìü¥Ô Ó9Í»‘yÑ»|ÐÎåРÛ{=a(Ìüc=¹qÉÔWýÐO Õºû¡*ÍÒ)Œ‡5í½¥L#Ï›Özì@^MÌ`ÔÚûÇe­ÆHÏàÇÁ7\ÎlÐÌe+.Œ×ÜûyýÌK-×I Îz-ËÔ××j-€2L×¢[`n$†­Ø˜ËØB;Ëñ›ÙK Ùü‹+“ÍX•½× ½À¥¹ôÃÙ3ìÙd}¹Â6Òc=ÓíØ§=Á·§Ú/ÈÚ]B»}ºó-µýÙËK>‚½ÄÆ­ÛìÛ(Ì¥ÁMžÃÝÚ€ÚÛ¶ ¡ö²ÑÛÍÝQ×ɹÙà=ÝþÄ}›ÖÍP¶ Ø“tW-H3»°Ñ--yšËØumÞçÙªÞë­Ê›ßõýÇ‘²20<×xxÓ±ªß佨bÍßÙ¿{ûßàå-þ­üqà“¼_ÝìÚ Nš¨èÜáÝŽÀÚüÎ[árªÉÚ%¤=»Ó³Ý)XíQ°ýÜÆwÛùâ»<ÈJÝâ³¶ÉÆÞåÒ‰276Žr8þÕ”n%Þãöìž*þÚÞ⸠á©ë.èçË ‰Øµ ݱ ]9æQ~Æ.Í¡¼äâíãs¬×bÚb>£ ž®ƒmµd^æf®Å°\±@¾æùâ(ÉÉmÖ×6Ûó}³_åz®Ä,.äFþþç2–Êöö¾É]¼/ ÔvçcÎÜšÎèPLãÚé{™È¶Ù®Þ»œÃU¾ã.ùÆ£ýé ÎA£NꊼS½Mè©î–$êòËížç±náFë n뤽Ü~+…è¯ÍäOEçÀŒìÁ.ì[|fÅnìÈœìV£NÝìÎ.Ý®e½w‹^íÃ¾ÏØžíç^Üþ—v>qI틬±|5¤ŠNàìnÂê¾Oú®æpþ½ç(ï>Ô™Zà Úóîï¿-Àü~ß _à¨NÎ3Šð­ìá8í· ñ– bÿð?¥ ðøyïÊÞä¼íˆþìï»ã-C¿îzN5*Oò%ßÔÑþŸþMÁùÎòQÝÃÓ|0/Æ ?óÇ­fìYÞ¯îå¼ò=?ñ  TB?ô o6Fo •úiJØÊžò½ËãNïõçÂM.'õ:~î]ƒà7!¶×Ñ"tõ'nßöo4£ŒóTöëÌîUO÷j7²´äMŸÃæ>÷ð>|׳ž÷.~öhoõN1s>î‚ÿÝ_øJþºŠ&°\¿øéÌèŽÿøUNƒ ªLïé—?ò~o½ÿñÏøÂÎ÷iOî Mñ¤ÏóÛ[ñ¨Ÿú®µ`åú˜ëm#ûKTÓý¨ó€üɯüËÏüÍïüÏýÑý6/ýÕoý×ýÙ¯ýÛÏýÝïýß?ý}¾üþôûlþçþé¯þëïü|ÃþÉïM£ý ïOÿÜOýõÿù¯ÿûÏÿÌ?çíOñ1uá!h“V{qÖ›wÿÁPI':ÑT]ÙÖ}áXži´¼ñ\ßy°n{ˆ#ð(f$«#ã×tÎ6Oé”Zµ^±ÍÏ+˜8uÁañ˜\6‡²iõšý=¿áq¹÷ wu€ÌöÞ†äÿÙðŠòºRæu#%Û+-/-°ìX & ýDKMOéH=Áú0_ace[Qkm•fsuÍ47Yñ\ACo«V‰‘“‡‡$„8ƒ–w§©«§•±K…­¹»£¦ÄŒ&~9¤õ²k4Ð×Ù•Ÿq!Éþ½çéëÃÚñ)í÷ù™ÅÓi ¡ ˜8UòAÉ”aÃTå×bE‹ïfüq‘#=…ê’,0ãCÎD¢ÔÈåÜJ—/\ˆˆ¦ÙÄŽ7qÖƒ¹sfNŸ±”8C‰!ËÂC½(H’ÇaKžO¡\MÄx?±fÕ•+R­_E(¸–ÊfJ ú뺖­¨rT·œì –nÝ9myÚÕGà7}d¼ŽK Q*B¼‡ÿñ{u,˽!‡K¬1råp 㜼™3•Np?ǰ<š4‰Î K§Æ¸A$ͧaÇv¼Ø\c ¬UçÖmB6ºm»ÅÈNëªh{'ïíôTµw‚G®›þtë„ ƒšä ÷Û¾†©‡ç¼e.Ï×ѧ,}{ðîøº±r}ý¶Ì;•aˆ¿{ÿí«å?÷|›G>óLð)üÒ¢o£!ŒLÁA"lo×&̦Ðjsp¿ A„LÃÌB”®À›FLq%¿cB.’JŒQ¯¥T¬CÆéNì¨Æb;¦²»QÈŸÌâñ‰!ƒ»C#™Ì&–ZDRJ"›hJõòѱÊ-“áA´+Á¬‹Kô¬¡‹ÆLó/Ë+Ó͜ԴéM1)£(Î;MY-¨ çìSK<»ó3+—ìÔPA$ò„OAåçÐFg䊦ï9ÔRo°!$H9­ÐNéb‹¼Ÿþ¼ÔÔQôŒÔUuRó7VQÄ ³üz8ÕV5âQÖ]«‰“W¬3¦¹\o-ÖŠTuýUYY\]ÎÄ Yc©•"ÑEÍÖ’4µýZ™h`³ÚqcJ´ÛsËZ¦Ft-Ú \pÆ¡ô=réýÈ´þØÍב`RÔ·Ðñâ-ÆC±Bª×àp3ÝÔß…å hD†÷Y¹ƒ)Î1Sˆ1~ƒß‡3ö&¹‰+™ŽIîÆá K6Y¹yEnYÀMYf³U)–‡™ÙzŸsÙç‘tú•“»r.g¡11¸çŸFÚé})E áYÅz(¥áÙéÎаÚëI[ÌR?l‡#ûë†~Ñ*·ÜškæþÎŽÛ»ªñ);怫–»‘Š—¦Ñ5Ývî»õÖ[]%1z•(y ç.í=%;pYÁn\î˜û@\ˆÁ泜¼ÓV{¤ížœòQ ÷!¿ìõ/#t äÖ§>Šï C ÿu?ª‚ì[Ûj·ˆzpn‹`‡·Av…!_¼úmð„(þL¡ ³ÆÂº0r{#• ݇ÃJ°„BÁ!1t˜Ä´ô0, …âþwÄ!ÑEA:¢-’˜Ey1±‰y ¯XD*EWcw%.Â0Y-4ãÓÆƒÌÎŒÄA£Õø·.ÊуucŸÁ:òáŽxÌ£áE"€Ñ `I9È=R‰Š,£©+Ý5opD$Þ4(ÉIRÒ–¼äy2‰­MžÜÈ„e˜ŠÒ<¤4 ô^¹7[Ò2’/Ô"DÉÃUÚÒpô£#&÷%˜aª.˜æ{KÕÌÀ˜’˜ÓÃå(“©Ì>ó¹¯)yÍN—uÒ‹)L&-¥jãþ*ÎÀötd‹ëS ›Ù´¶ uˆÍA#[³É ¶& œ þ «YÕ ÒJ&ùæÜbèÙ……V´…¦°Hµg¾gµ½%êÔXôºÎR°p´¦KWÓž6·Èó­j…J3cJ—¸— ­GÙ3?ìÁÏ—z®f£ÜéRw¼ëŒ,vQ QmÀv»ôùî@†+ñ>v¾Ý».zO±ÇîêV|/7è»+ùÚ¦¨GI'‹ùW úNËåî'=ôß^ñWæoyÇàŒÑ–¦•mðzÉ›KœIf•…ìþv쾎Íî‡×blŽÄ×0ñ‰ÃkÙ×–!®$3n› c®±)\á3·º<ŠÐ8Üá}âóŒ`±èŽlX2¹ÇÛq|þìâÝ ùÊÃq“³üP³Íî2‹£Œß!“yÆ”uèÄÒ ]\IÅšrN¾ŒÛC­Ê¦™3oó ÞA{ù9&£³½àGšÑ,s’G•hŒN`E‚uÃ,g{V¢Ò·-4` ¬iÏ9˜«V%§Q:j~ÚÐqªÞtŒ[íjIÓ:Öwžõ¡Q}c[›w¿¹Öµ¨›4Y[ºÌÉÅô°\dÊVŸù¬ö’/±fSóÚÉ©†öXíTWÓUÚWÃ6³›íljÛj§¦'8ÇQwmË’IDyámvûuÙz·Hÿ2á¶Æî@ï¶¾÷ÍïõVÑñ–¬¯K¼×ƒ °ßèNø6‰þÜÁ¬›žßbÅw!ñ‰äâzöÅK*eTÎÓã¯·Êø|1œÙ(g9Ä)Ùr—'æZ ·Á·Íq›ËUÛ¬´rË»Ép•ëç%ìÐoþò]êÜ’çî¹ÒInC#êi,º©Þ!¨öƒéÊÆ·¥»uM=§a¯zÌÑäs¾ý×lO;ó¤žs·SëízÐÜénòEÞ½´³V5÷îŲ{ëÙÖzÂøsrÂõðäL|_úι7ýìâ2§'_øÅ“2@›-Ú)C•yJw¾VL ý=UTûömdúÊæÍø{ äõÿl<égÏfh½Xç<Îù)U»÷¾œÐ±|éMþW,KHãŽÏÍ£q3×3øÎ'¦‚„?| ¿úÖÇ<Ï]·|î+œø«áܽVuù6Óé÷©üøÊ½,ùõßZ¸¹úšüç/õ¼êø ^æÇÑöÏëÚÞÞŠ÷dÇÏ.êÏþʪò²ï‰ÒI ô/‰n‰Ì,œ…íýüÎöro¤,°õ@9ð¾,wiDP¶¸ÎUÎû.ð‹ü¬§®99XÐfp¸³VïnpfÈgÅ|‘€6þÁ ‰°,¯îÉì€>Äuèè 0 ¹pm¨pû”etäï ±ÀL°éÆPZxì ÁPïP ÛP¢HPÀÒöîìúþ0ëëÕK çp|Êð [KÞÂÒ0üú/bà°×(,[OбA«wm# ÎÔ/Ffpô31CS&ÃÍ‹%e2ó§ý«5Õ­âïñ|†6óèªôC7Ÿ*€ùfŽ\ff3F¸ÖÑþ8s-8%ïL±Zh5×4LS:ƒèt¥<Š„CF_0Ç9q’;½3¯¾¥:ƒ“½xf1 ¬mÓ%׳ál!>Çå\Ñ ÓÓï3³&c¥¤ÂXÐ:TÆÞs@[21øÏPª0YÿÐAÅMp–RBÍÑ“À>COC3ñQüeºkSD™1X‚H6×Ì(´Õí-YtDIÔš`´_0¦AB”éñFÕìm"”K|ì6ë‰ËHHÙó4n OJÆœŠR ™t«$fCÇ$JèG…°—¦´JŸ6”[€s‹Šç9‘ÂðØLÇ”HKÔHuF §Ò>Å’M7êcÞ´Jdþ°WÔydI½ÄNÙ/6ò”Iž&?öÓ%Ç3EkIPW: •G¼Q1ò@IM•7õQWÆ·„wà¢?òþ‚Ô;6²ÄÃS›„؈áºQ05SóçTA-½TYGð;Òô`6õjü0Ö=¥ob•õ_%¶`þÅ<2­8ý1c#dMve:VPNd'PdGv])*gtú^Ve­ãSÛÕaeV•Kƒ¢ ¿”gC„[’69ùµ_g1WmÔf71Y#V÷SieÄW°òi£ojµ•UôB§êѸlgµ8¸vO¶*…²¦h¾ØÕm…®€5mÁäNÂvBð.hu9_ëXuÑ™P”Kóo+Co‰³LÑ•Xç¶eSlWPÒwJ,%N6RµP+kY“p!e+×./m·6s5·9¦‰nÉ"kôÚF·DLåLg+øì+hÅi5Y”L–5ë4’ ¶Bc·4™óD·uÚqqP*þ¥@’O.\Lwxi±x;Z§í·ê³uGÕl.5"4ª©×D¾¶Y&OPxijråM?õÆ—t)¦v;ãÔ7`~ÊOñ±(¦7~w¦<¯÷JÓ×pap^$BûXw ©Çý€ÙRÁnvˆ#ãðë6’«WdXL=rzÏÏs•·;0˜(eç|F‰$853„ù“sǰ„3¸iº…PW±OOÖ€9 ^Q†g˜†ÓIžy]X!•ÊVÌ|ø‡x_³K9K©iýui¡Àïw‰%Ñ„‚Ø,X…¥¸±"3eEØn X‹)‹»ø‰¿ •Q34ÕŠÂ|Ž ÑþØÎ~S>/ Š#˜v©$P¾ÎŽïxaISs4 Yvøˆ¹µÊ¹ðV˜HÎÖZ¹‘·3!¹@w“Fý¸$ÇV»“/R“×B]3‰É±hIù]Æ?Ýt:gvE®•Ÿ¥7ÙEa/ÙüjÙ–§Ñ”O¹=Iª´ÄÖ„FQ€ù–›Ø‰‰ÙØŽÙ#–ðŒ—ù°„Ù™Á“@o*˜ sFr«9ä®Y9¹·èçÏ“¹ùb†šÃ™ç–#ù½î5xÇÍÌC‹øÑk8–¬…'Ùnô+ÕpøhùY*‰'Azýš5@ï™`.#¡3ž:…ð =¯‡)Ú‘úþ1Ú¡5‰/¹£··?wžÙí<÷™ÎL™QzƒQ™ûð¹ÏJú¥Q2¦eºGDùîZºÓP§[…^z´N¢vèz(„º$‰ZF¨§».©™e©Ù;áì©¡©ošªÕÖª7Œ2`8.{y«¹:ߨEK±Úø®ÒR•ÊšþfóH+«Ûñƒ_M^ßúö­ K­×ڮߑ`óZ¯o…¯]ʯÇr z°Kùr {.Ãú½y„ṉ̃µ¢°åÚ¨»''ÛÈ0{P.…q9û¨Iðü[C[´Mt³Áš®ç?pV›µ9ôªmxëÈšS»Ãj›ü>%²CÚµ¤ZËz›rÛþ'n·s;@£z¶×'¹™Yq]›ƒ!ZÕ´w霥{+–û«8Ÿ5ÍG;»;˜×–¹›DwÛ¾ ÷HtçÉλ©[½­»¾²Ì]Ë[Žç›–ͼÑWnóÛùTÙø¿1K«{½o±¸o~«ÖÁ<ýÒ»¨ë÷…üÁuOŽÛ{ÂóyUíÛI?<Ãy›Û"œÄuÔßÀecÄ;Ü@M<éŠYÏà”ÅïûÂFZ–cÜ“dêÅ'µÆ-¼Å¼¦¹ØxÜÃãÄm\į³±}2¿8ÜÇ‘\8UdÁ‡;Ê<ŠÁÑž%|ʵ«ÊC|¦›<Ç5Ü,ÃÊË]™o­ü™u,yµ9&éÍÑþeÖœ:]œÈ4‡L[ÎmGÃZ½õä=^ÈÖá=Ëi¶Xaž™|æWþÎú[õ4çu¾Ý¡Œ7©\ãyñ¿…Þ¦üÇižÖèÉté zçYu°°éa|꩞¤žçm+ëéý敾ëœ:ûÅÉëÅþ神ëÍž…“}âóã>êß¾ìã¾¢·ÜFËçÕ¾[ƒ{ï)¼ï¶çÿ×ážð3Ùâ]>ìïÞæ§µ¾_¡ó‚îýÄèY^ò¯J+¿ñÓˆÙ¾í»|ò=ÿó7vE_Ö›²àÝÞrNõ÷ñE.Ÿ½ôMŸòeß(i¿Mµ1_žG{÷sÑþîk_sŠ?ø/zv•ßÃ]}€[/*®‰ÿö!¿‚þÒæ°vð«ÿ¤Gû[ê¶_÷»ó_Ó ]ü©¿üEþú¡ŸÁÔýÙ?ò³_Ë£ÿ¹5{þé¿þ¡Ðb´:ÿ >¦.·?ŒrÒj/Îzóî?ŠPš'šª+Ûº/0Ê3]Û#œë;zû?0(FxÆ#2©\–ˆÎ'4*R«V3«M]»Þ/c+^Ëæsw¬^³‘è7<.ŸÓmí;¬®ßkð[>`` a!› b¢â"#‡ácS£$dÒä%¦På&g^æ'h¨hT§ßèéT©*k+„*¬ªë,mmmì¡­.nËîoh¯°!pþ±ññܰ2s…rOsôà3õ˜ô5vvMõ’¶÷÷·xw9Ó8zººùÑz6õ»°ýŽ>󳿀vø$#ð ÂOï%Ô5¬!D 'žˆhñ"%Š1ÎÆñãA’,IE$“¨z©l‰%A—2gÒ€Y‘&(\8UÚ¬·ó'P =M½«(È¡í2mÊN©SF°¢FTº”*Vš6³J-ŵ¡Õp_Ç–„I6‘¬³ÃÆSëÖ¢Ùo÷tšë­2»z¢ÜK—“_|x=.¼®¯ád¿Ì’1doˆ#£YL9ÝÑ0f/sn&²³™G Çy}õy4ê_S“+þÄZr%¡#_Ónµº¶b¸¥™’`áîà™n —âºø¿;¼ì!o¾ˆ¸s"½£k3ƒõ쀀ËÕ÷b¹d0oÎìó>”«whm ¹öò¿Ÿc¼}WjÖ—Ëï?ULÿÕôž€¶ñð” ¿ñ×V ~Wƒ8üvN„æ@JBsTwz„‚苈â1T4¦U"‹Ž<¦b‚-ŽH”Œ&’˜–V#¼øÒM= yPŒ¡u#`C*éaK: Q†­a¨£eOZ‰äTWj)\ ÝŶ¥“y9&kGb9]Wd%¦šm¾Ve#AºÉ›sÚé—\fêfTŽwrÄ Ÿþ2¶ç$r @‡*¡’¤¸hBÕ@:é\„äÔ'¥wIš)§_¡‰É£Î#–¨¥6õ)¨˜šŠ©«ººª|Fò*«€Òz«Kàc(®Ø´Ú+°eígfª¼›œ­Ç*‹‘úeHì²¶l-µÌº3++.T»OÛz‹hE,Ürã·ã6Y.º`õeGä¦k¡Wо;oU»¸KïJuá»ï• b˯(_<ðGò޲ÁÙ0Ã2ŠÛpÀB,+Ì]£ç´Øe‹0Æ¡šý{k»ýÜ×…ªý¶ÖÖ¹L7Þu£çÜy{qœß³7ß} Žbm¾8{+â8ãR¹Lä•ãx2Z[žŠ‚gf±9與½¿¡ÓG¹é©?1:«>Ŀ;>»twˬ9íôÈž;ïâhÛ»t“S<ñ¼ý^|&ÿ<ó6BÞü€y¢=õκ^ýuÂ+=÷ùÞ}MT>ùr__>Êwƒ>û¿ÐþÛÃ??"'ÒÿôîÜ¿ëÇóßAþô÷¿!ÙŽ6ö`Ƈ@±7ï[`º´>¶Èþp<C2Á ’g7P³Y9ø€ZB„&<¡Õ6ˆÂ²°ij! cx¹éɰ†6¬Ý o¨ÃJÈs ä!ƒè¢ý±ˆFtÆÖލÄ%.€ˆL|â%¸<(Ž­sTŒœ¯X¬i‘n9ìbk,F³MqŒa ¡£&E¦ñobl£ÔhÇpŽLûœóÈB<ê±\£ü(H²q†äŸü©Èÿ2‹|dê™ÀÒA²’x“äügÉM–-‘Žða9)Jšy€Ï%*y†ÉI~0•®¬Y)_)Ë×År–¶]-o©ËÅår—¾ô[ )LÁõr˜Æ[1©L5ºáþh\&4µÈV'qѼ¦¤J.J«•Øü&u—" òœæ”ÏFByÎun¬K:b'<ã)ÏyFô¼'>ó©Ï}ò³Ÿþü'@*д =(BªÐ…2´¡}(D#*щR´¢½(F3ªÑr´£ý(HC*Ò‘’´¤&=)JSªÒ•²´¥.})Lc*Ó™Ò´¦6½)NsªS–Ús§>ÅÊ3*Ô¨ps¨F- 措ÔS-µ©”y£S£ÊRªV qwÕ­b•Ûä*X¡Ô°’US,+Z[öô²Õx|I[㪷ʵ®°YÅP½iWViƒ4ÕªiÈéL½*u•5¼}Þ8k®žæÔ°eìŒÈF‚ Ž²¦$l^“ Á¾ ³äѾZË6±Ž”ml_©IHº& kš” àŠp¡æHµš fa³Š×Õâöl޽íΰÐ[ÙÒˆ³O+ãM¿¸ÙÝù·!Rnis93žB÷~C.ØS%qæ0-¼*ªC“hÝØ’–ŽÚ=o0*^ð)Iåzã›Þ‹Z§}iœ|󛬊֗{ç=nòô+àniTŽÀ0TY‰à_Å$;tkabber-plugins/georoster/msgs000075500000000000000000000000001500237002100164145ustar00nobodynobodytkabber-plugins/georoster/msgs/de.msg000064400000000000000000000030461500237002100175760ustar00nobodynobody# de.msg -- # # German messages for the Georoster Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 13.03.2009 ::msgcat::mcset de "Automatically look at vCard to find users coordinates." \ "Für die Koordinaten des Benutzers automatisch in seine Visitenkarte\ schauen." ::msgcat::mcset de "Automatically open Georoster window." \ "Das Georoster-Fenster automatisch öffnen." ::msgcat::mcset de "Connection: %s" "Verbindung: %s" ::msgcat::mcset de "Default country to use when looking at a vCard." \ "Voreingestelltes Land beim Schauen in die Visitenkarte." ::msgcat::mcset de "Display users who are no longer available." \ "Auch Benutzer, die nicht länger verfügbar sind, anzeigen." ::msgcat::mcset de "Don't show cities" "Keine Städte anzeigen" ::msgcat::mcset de "Georoster plugin options." \ "Optionen für das Georoster-Plugin." ::msgcat::mcset de "Georoster" "Georoster" ::msgcat::mcset de "Latitude: %.2f Longitude: %.2f" \ "Breitengrad: %.2f / Längengrad: %.2f" ::msgcat::mcset de "Plugins options." "Optionen für Plugins." ::msgcat::mcset de "Show city markers and names" \ "Markierungen und Namen anzeigen" ::msgcat::mcset de "Show only city markers" "Markierungen anzeigen" ::msgcat::mcset de "Specify how to show cities at the map." \ "Angeben, wie Städte auf der Karte angezeigt werden sollen." ::msgcat::mcset de "Store" "Speichern" ::msgcat::mcset de "Whether the Georoster plugin is loaded." \ "Georoster-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/georoster/msgs/es.msg000064400000000000000000000027511500237002100176170ustar00nobodynobody# es.msg -- # # Spanish messages for the Georoster Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "Automatically look at vCard to find users coordinates." \ "Mirar automáticamente las coordenadas del otro contacto en su vCard." ::msgcat::mcset es "Automatically open Georoster window." \ "Abrir automáticamente la ventana de Georoster." ::msgcat::mcset es "Connection: %s" "Conexión: %s" ::msgcat::mcset es "Default country to use when looking at a vCard." \ "País por defecto para usar cuando se busca un vCard." ::msgcat::mcset es "Display users who are no longer available." \ "Mostrar usuarios que no están disponibles." ::msgcat::mcset es "Don't show cities" "No mostrar ciudades" ::msgcat::mcset es "Georoster plugin options." "Opciones del plugin Georoster." ::msgcat::mcset es "Georoster" "Georoster" ::msgcat::mcset es "Latitude: %.2f Longitude: %.2f" \ "Latitud: %.2f Longitud: %.2f" ::msgcat::mcset es "Plugins options." "Opciones de plugins." ::msgcat::mcset es "Show city markers and names" \ "Mostrar marcadores y nombres de las ciudades" ::msgcat::mcset es "Show only city markers" \ "Mostrar solo los marcadores de ciudades" ::msgcat::mcset es "Specify how to show cities at the map." \ "Especificar como mostrar las ciudades en el mapa." ::msgcat::mcset es "Store" "Almacenar" ::msgcat::mcset es "Whether the Georoster plugin is loaded." \ "Cargar el plugin Georoster." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/georoster/msgs/nl.msg000064400000000000000000000026121500237002100176150ustar00nobodynobody# nl.msg -- # # Dutch messages for the Georoster Tkabber plugin. # # Author: Sander Devrieze ::msgcat::mcset nl "Georoster" "Georoster" ::msgcat::mcset nl "Store" "Opslaan" ::msgcat::mcset nl "Latitude: %.2f Longitude: %.2f" \ "Breedtegraad: %.2f Lengtegraad: %.2f" ::msgcat::mcset nl "Automatically open Georoster window." \ "Venster van Georoster automatisch openen." ::msgcat::mcset nl "Automatically look at vCard to find users coordinates." \ "Automatisch in vCard kijken om de coördinaten van gebruikers te\ vinden." ::msgcat::mcset nl "Display users who are no longer available." \ "Toon gebruikers die niet langer beschikbaar zijn." ::msgcat::mcset nl "Default country to use when looking at a vCard." \ "Standaard land dat gebruikt wordt tijdens het kijken naar een vCard." ::msgcat::mcset nl "Plugins options." "Pluginopties." ::msgcat::mcset nl "Georoster plugin options." "Pluginopties van Georoster." ::msgcat::mcset nl "Don't show cities" "Steden verbergen" ::msgcat::mcset nl "Show only city markers" \ "Enkel markeringen voor steden laten zien" ::msgcat::mcset nl "Show city markers and names" \ "Markeringen voor steden en stadsnamen laten zien" ::msgcat::mcset nl "Specify how to show cities at the map." \ "Geef op hoe steden op de map getoond moeten worden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/georoster/msgs/pl.msg000064400000000000000000000027471500237002100176300ustar00nobodynobody# pl.msg -- # # Polish messages for the Georoster Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "Automatically open Georoster window." \ "Pokazuj automatycznie okno Georostera po uruchomieniu." ::msgcat::mcset pl "Default country to use when looking at a vCard." \ "DomyÅ›lnie używany kod kraju przy wyszukiwaniu w wizytówkach." ::msgcat::mcset pl "Automatically look at vCard to find users coordinates." \ "Automatycznie wyszukuj koordynaty geograficzne w wizytówkach." ::msgcat::mcset pl "Display users who are no longer available." \ "Pokazuj użytkowników niedostÄ™pnych." ::msgcat::mcset pl "Georoster" "Georoster" ::msgcat::mcset pl "Latitude: %.2f Longitude: %.2f" \ "Szerokość: %.2f DÅ‚ugość: %.2f" ::msgcat::mcset pl "Georoster plugin options." "Ustawienia wtyczki Georoster." ::msgcat::mcset pl "Don't show cities" "Nie pokazuj miast" ::msgcat::mcset pl "Show only city markers" "Pokaż miasta jako punkty" ::msgcat::mcset pl "Show city markers and names" \ "Pokaż miasta jako punkty z nazwami" ::msgcat::mcset pl "Specify how to show cities at the map." \ "Wybierz sposób prezentacji miast na mapie." ::msgcat::mcset pl "Store" "Zapisz" ::msgcat::mcset pl "Connection: %s" "Połączenie: %s" ::msgcat::mcset pl "Whether the Georoster plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ Georoster." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/georoster/msgs/ro.msg000064400000000000000000000005331500237002100176240ustar00nobodynobody# ro.msg -- # # Romanian messages for the Georoster Tkabber plugin. ::msgcat::mcset ro "Georoster" "Listă geografică" ::msgcat::mcset ro "Store" "Salvare" ::msgcat::mcset ro "Show cities" "Arată oraÅŸe" ::msgcat::mcset ro "Latitude: %.2f Longitude: %.2f" \ "Latitudine: %.2f Longitudine: %.2f" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/georoster/msgs/ru.msg000064400000000000000000000035401500237002100176330ustar00nobodynobody# ru.msg -- # # Russian messages for the Georoster Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Plugins options." "Параметры раÑширений." ::msgcat::mcset ru "Georoster plugin options." \ "Параметры раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð“ÐµÐ¾ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ñ‹" ::msgcat::mcset ru "Don't show cities" "Ðе показывать города" ::msgcat::mcset ru "Show only city markers" "Показывать только метки городов" ::msgcat::mcset ru "Show city markers and names" \ "Показывать метки городов и названиÑ" ::msgcat::mcset ru "Specify how to show cities at the map." \ "Как показывать города на карте." ::msgcat::mcset ru "Georoster" "Геоконтакты" ::msgcat::mcset ru "Connection: %s" "Соединение: %s" ::msgcat::mcset ru "Store" "Сохранить" ::msgcat::mcset ru "Latitude: %.2f Longitude: %.2f" \ "Широта: %.2f Долгота: %.2f" ::msgcat::mcset ru "Automatically open Georoster window." \ "ÐвтоматичеÑки открывать окно Геоконтактов." ::msgcat::mcset ru "Automatically look at vCard to find users coordinates." \ "ÐвтоматичеÑки иÑкать координаты пользователей во vCard." ::msgcat::mcset ru "Display users who are no longer available." \ "Отображать недоÑтупных пользователей." ::msgcat::mcset ru "Default country to use when looking at a vCard." \ "Страна, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÐµÐ¼Ð°Ñ Ð¿Ð¾ умолчанию (еÑли не указана во vCard)." ::msgcat::mcset ru "Whether the Georoster plugin is loaded." \ "Загружено ли раÑширение Геоконтакты." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/georoster/msgs/uk.msg000064400000000000000000000035061500237002100176260ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Georoster Tkabber plugin. # # Author: Artem Bondarenko # Author: Sergei Golovan ::msgcat::mcset uk "Plugins options." "Параметри плагінів." ::msgcat::mcset uk "Georoster plugin options." "Параметри плагіна Геоконтакти" ::msgcat::mcset uk "Don't show cities" "Ðе показувати міÑта" ::msgcat::mcset uk "Show only city markers" "Показувати тільки мітки міÑÑ‚" ::msgcat::mcset uk "Show city markers and names" \ "Показувати мітки міÑÑ‚ Ñ– назви" ::msgcat::mcset uk "Specify how to show cities at the map." \ "Як показувати міÑта на карті." ::msgcat::mcset uk "Georoster" "Геоконтакти" ::msgcat::mcset uk "Connection: %s" "З'єднаннÑ: %s" ::msgcat::mcset uk "Store" "Зберегти" ::msgcat::mcset uk "Latitude: %.2f Longitude: %.2f" \ "Широта: %.2f Довгота: %.2f" ::msgcat::mcset uk "Automatically open Georoster window." \ "Ðвтоматично відкривати вікно Геоконтактів." ::msgcat::mcset uk "Automatically look at vCard to find users coordinates." \ "Ðвтоматично шукати координати кориÑтувачів у vCard." ::msgcat::mcset uk "Display users who are no longer available." \ "Відображати недоÑтупних кориÑтувачів." ::msgcat::mcset uk "Default country to use when looking at a vCard." \ "Країна, викориÑтовувана за замовчуваннÑм (Ñкщо не зазначена в vCard)." ::msgcat::mcset uk "Whether the Georoster plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð“ÐµÐ¾ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð¸." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/gmail000075500000000000000000000000001500237002100145235ustar00nobodynobodytkabber-plugins/gmail/gmail.tcl000064400000000000000000000462071500237002100164100ustar00nobodynobody# gmail.tcl -- # # Gmail notifications plugin for Tkabber XMPP client. package require msgcat namespace eval gmail { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered gmail]} { ::plugins::register gmail \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Gmail\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } custom::defgroup Plugins \ [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup {Gmail Notifications} \ [::msgcat::mc "Google Talk XMPP extensions."] \ -group Plugins custom::defvar options(gmail_notifications) 1 \ [::msgcat::mc "Request Gmail notifications."] \ -type boolean -group {Gmail Notifications} \ -command [namespace current]::request_all_notifications custom::defvar options(delete_old_notifications) 1 \ [::msgcat::mc "Delete Gmail notifications, which are\ older than 24 hours."] \ -type boolean -group {Gmail Notifications} \ -command [namespace current]::request_all_notifications custom::defvar options(timestamp_format) {[%m/%d %R] } \ [::msgcat::mc "Format of timestamp in Gmail tree view. Set to\ empty string if you don't want to see timestamps."] \ -group {Gmail Notifications} -type string custom::defvar last_mail_time {} \ [::msgcat::mc "Last Gmail message time."] \ -type string -group Hidden } package require md5 proc gmail::load {} { hook::add connected_hook [namespace current]::request_notifications hook::add finload_hook [namespace current]::create_menu hook::add save_session_hook [namespace current]::save_session create_menu request_all_notifications } proc gmail::unload {} { hook::remove connected_hook [namespace current]::request_notifications hook::remove finload_hook [namespace current]::create_menu hook::remove save_session_hook [namespace current]::save_session catch { set menu [.mainframe getmenu plugins] set idx [$menu index [::msgcat::mc "Open Gmail notifications"]] $menu delete $idx } destroy_win .gmail_messages } ############################################################################ proc gmail::request_all_notifications {args} { variable options if {$options(gmail_notifications)} { foreach xlib [connections] { request_notifications $xlib } } } ############################################################################ proc gmail::request_notifications {xlib} { variable options variable last_mail_time set jid [connection_bare_jid $xlib] catch {array set tmp $last_mail_time} if {[info exists tmp($jid)]} { set time $tmp($jid) } else { set time 0 } if {$options(gmail_notifications)} { ::xmpp::sendIQ $xlib get \ -query [::xmpp::xml::create query \ -xmlns google:mail:notify \ -attrs [list newer-than-time $time]] \ -command [list [namespace current]::receive_notifications $jid] } } ############################################################################ proc gmail::receive_notifications {jid status xml} { variable last_mail_time if {$status != "ok"} { return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[::xmpp::xml::isAttr $attrs result-time]} { catch {array set tmp $last_mail_time} set tmp($jid) [::xmpp::xml::getAttr $attrs result-time] set last_mail_time [array get tmp] } fill_tree $jid $subels } ############################################################################# proc gmail::create_menu {} { catch { set menu [.mainframe getmenu plugins] $menu add command \ -label [::msgcat::mc "Open Gmail notifications"] \ -command [list [namespace current]::open_window -raise 1] } } ############################################################################# proc gmail::open_window {args} { global tcl_platform set raise 0 foreach {key val} $args { switch -- $key { -raise { set raise $val } } } set w .gmail_messages if {[winfo exists $w]} { if {$raise} { raise_win $w } return } add_win $w -title [::msgcat::mc "Gmail notifications"] \ -tabtitle [::msgcat::mc "Gmail"] \ -raisecmd [list focus $w.tree] \ -class JDisco \ -raise $raise if {$tcl_platform(platform) eq "unix" && \ ![string equal [option get $w disabledForeground JDisco] ""]} { set config(seencolor) [option get $w disabledForeground JDisco] } else { set config(seencolor) [option get $w featurecolor JDisco] } set config(unseencolor) [option get $w fill JDisco] set sw [ScrolledWindow $w.sw] set tw [MyTree $w.tree] $sw setwidget $tw $tw tag configure seen -foreground $config(seencolor) $tw tag configure unseen -foreground $config(unseencolor) pack $sw -side top -expand yes -fill both $tw tag bind Text <> \ [list [namespace current]::message_popup [double% $tw] %x %y] $tw tag bind Text \ [list [namespace current]::message_browse [double% $tw]] # Override the default action which toggles the non-leaf nodes bind $tw break if {[winfo exists $tw.c]} { # HACK bind $tw.c \ [list [namespace current]::message_browse [double% $tw]] } else { $tw tag bind Text \ [list [namespace current]::message_browse [double% $tw]] # Override the default action which toggles the non-leaf nodes bind $tw break } messages_restore } ############################################################################# proc gmail::fill_tree {jid xmlList} { if {[llength $xmlList] == 0} { return } open_window foreach xml $xmlList { ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- $tag { mail-thread-info { set tid [::xmpp::xml::getAttr $attrs tid] set messages [::xmpp::xml::getAttr $attrs messages] set date [::xmpp::xml::getAttr $attrs date] set url [::xmpp::xml::getAttr $attrs url] add_thread $jid $tid $messages $date $url $subels 1 } } } } proc gmail::add_thread {jid tid messages date url xmlList unseen} { variable options set w .gmail_messages set tw $w.tree set fnode [str2node $jid] if {![$tw exists $fnode]} { $tw insert {} end \ -id $fnode \ -text $jid \ -open 1 \ -tags {Text unseen} \ -image browser/user \ -values [list type jid jid $jid unseen $unseen] } set senders [list] set subject "" foreach xml $xmlList { ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- $tag { senders { foreach subel $subels { ::xmpp::xml::split $subel stag sxmlns sattrs scdata ssubels if {$stag == "sender"} { lappend senders [::xmpp::xml::getAttr $sattrs name] } } } subject { set subject $cdata } } } set snode [str2node "$tid $jid"] if {[$tw exists $snode]} { $tw delete [list $snode] } set timestamp [clock format [string range $date 0 end-3] \ -format $options(timestamp_format)] set names [senders2names $senders] $tw insert $fnode end \ -id $snode \ -text "$timestamp$names ($messages) $subject" \ -open 1 \ -tags {Text unseen} \ -values [list type thread jid $jid tid $tid \ messages $messages date $date url $url \ xml $xmlList unseen $unseen] if {$options(delete_old_notifications)} { message_action deleteold $tw $fnode } else { messages_store $tw } message_update $tw $snode sort_nodes $tw $fnode -date tab_set_updated $w 1 message } proc gmail::senders2names {senders} { if {[llength $senders] <= 1} { return [lindex $senders 0] } else { set names {} foreach s $senders { lappend names [lindex [split [string trim $s]] 0] } if {[llength $names] <= 3} { return [join $names ", "] } else { return "[lindex $names 0] .. [join [lrange $names end-1 end] {, }]" } } } proc gmail::str2node {string} { set utf8str [encoding convertto utf-8 $string] if {[catch { ::md5::md5 -hex $utf8str } ret]} { return [::md5::md5 $utf8str] } else { return $ret } } proc gmail::message_popup {tw x y} { $tw selection set [list [$tw identify item $x $y]] set node [lindex [$tw selection] 0] if {[catch {array set props [$tw item $node -values]}]} { return } set m .gmail_popup_menu if {[winfo exists $m]} { destroy $m } menu $m -tearoff 0 switch -- $props(type) { jid { # $m add command -label [::msgcat::mc "Mark all seen"] \ # -command [list [namespace current]::message_action markseen \ # $tw $node] # $m add command -label [::msgcat::mc "Mark all unseen"] \ # -command [list [namespace current]::message_action markunseen \ # $tw $node] $m add command -label [::msgcat::mc "Delete messages older than\ 24 hours"] \ -command [list [namespace current]::message_action deleteold \ $tw $node] # $m add command -label [::msgcat::mc "Delete seen messages"] \ # -command [list [namespace current]::message_action deleteseen \ # $tw $node] $m add command -label [::msgcat::mc "Delete all messages"] \ -command [list [namespace current]::message_action delete \ $tw $node] } thread { $m add command -label [::msgcat::mc "Browse"] \ -command [list [namespace current]::message_action browse \ $tw $node] # $m add command -label [::msgcat::mc "Mark seen"] \ # -command [list [namespace current]::message_action markseen \ # $tw $node] # $m add command -label [::msgcat::mc "Mark unseen"] \ # -command [list [namespace current]::message_action markunseen \ # $tw $node] $m add command -label [::msgcat::mc "Delete"] \ -command [list [namespace current]::message_action delete \ $tw $node] } default { return } } tk_popup $m [winfo pointerx .] [winfo pointery .] } proc gmail::message_browse {tw} { set node [lindex [$tw selection] 0] if {$node != ""} { message_action browse $tw $node } } proc gmail::message_action {action tw node} { message_action_aux $action $tw $node messages_store $tw } proc gmail::message_action_aux {action tw node} { if {[catch {array set props [$tw item $node -values]}]} { return } switch -glob -- $props(type)/$action { jid/markseen { foreach child [$tw children $node] { message_action_aux markseen $tw $child } } jid/markunseen { foreach child [$tw children $node] { message_action_aux markunseen $tw $child } } jid/deleteold { foreach child [$tw children $node] { message_action_aux deleteold $tw $child } } jid/deleteseen { foreach child [$tw children $node] { message_action_aux deleteseen $tw $child } } jid/delete { foreach child [$tw children $node] { message_action_aux delete $tw $child } } thread/browse { if {$props(url) != ""} { browseurl $props(url) } } thread/markseen { set props(unseen) 0 } thread/markunseen { set props(unseen) 1 } thread/deleteold { set datediff \ [expr {[clock seconds] - [string range $props(date) 0 end-3]}] if {$datediff > 86400} { message_action_aux delete $tw $node } } thread/deleteseen { if {!$props(unseen)} { message_action_aux delete $tw $node } } thread/delete { set props(unseen) 0 $tw item $node -values [array get props] message_update $tw $node # Deduce the node to select after $node is deleted: # Next sibling is tried first, then previous, then parent node. set p [$tw parent $node] set end [expr {[llength [$tw children $p]] - 1}] set ix [$tw index $node] if {$ix < $end} { set next [lindex [$tw children $p] [incr ix]] } elseif {$ix > 0} { set next [lindex [$tw children $p] [incr ix -1]] } else { set next $p } $tw delete [list $node] if {![string equal $next {}]} { $tw selection set [list $next] } } default { return } } } proc gmail::sort_nodes {tw node type} { if {[string range $type 0 0] == "-"} { set order -decreasing set type [string range $type 1 end] } elseif {[string range $type 0 0] == "+"} { set order -increasing set type [string range $type 1 end] } else { set order -increasing } set children {} foreach child [$tw children $node] { catch {unset props} array set props [$tw item $child -values] lappend children [list $child $props($type)] } set neworder {} foreach child [lsort $order -index 1 $children] { lappend neworder [lindex $child 0] } $tw children $node $neworder } proc gmail::message_update {tw node} { for {set parent [$tw parent $node]} \ {$parent ne {}} \ {set parent [$tw parent $parent]} { set unseen 0 foreach child [$tw children $parent] { catch {unset props} array set props [$tw item $child -values] incr unseen $props(unseen) } catch {unset props} array set props [$tw item $parent -values] set props(unseen) $unseen set text $props(jid) set tag seen if {$unseen > 0} { append text " ($unseen)" set tag unseen } $tw item $parent -text $text -tags [list Text $tag] \ -values [array get props] } } ############################################################################# proc gmail::messages_store {tw} { set file [file join $::configdir gmail-notifications.tcl] set file0 [file join $::configdir gmail-notifications0.tcl] set file1 [file join $::configdir gmail-notifications1.tcl] if {[catch {open $file1 {WRONLY CREAT TRUNC}} fd]} { debugmsg plugins "unable to open $file1: $fd" return } fconfigure $fd -encoding utf-8 set code [catch {messages_store_aux $tw root $fd} result] catch {close $fd} if {$code} { debugmsg plugins $result catch {file delete $file1} return } set renameP 0 if {![file exists $file]} { } elseif {[file size $file] == 0} { catch {file delete -force $file} } else { set renameP 1 catch {file rename -force $file $file0} } if {![catch {file rename $file1 $file} result]} { return } debugmsg plugins "unable to rename $file1 to $file: $result" if {($renameP) && ([catch {file rename -force $file0 $file} result])} { debugmsg plugins "unable to rename $file0 back to $file: $result" } catch {file delete $file1} return } ############################################################################# proc gmail::messages_store_aux {tw node fd} { if {![winfo exists $tw]} { return } if {[llength [set children [$tw children $node]]] > 0} { foreach child $children { messages_store_aux $tw $child $fd } } elseif {![catch {array set props [$tw item $node -values]}]} { puts $fd [list [namespace current]::add_thread \ $props(jid) $props(tid) $props(messages) \ $props(date) $props(url) $props(xml) \ $props(unseen)] } } ############################################################################# proc gmail::messages_restore {} { set file [file join $::configdir gmail-notifications.tcl] if {[file exists $file]} { catch { set fd [open $file "r"] fconfigure $fd -encoding utf-8 uplevel #0 [read $fd] close $fd } } return "" } ############################################################################# proc gmail::notify_response {xlib from xml args} { if {$from != "" && \ $from != [connection_bare_jid $xlib] && \ $from != [connection_jid $xlib]} { return {error cancel not-allowed} } ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {$tag != "new-mail"} { return {error modify bad-request} } request_notifications $xlib return [list result ""] } ::xmpp::iq::register set * google:mail:notify \ [namespace current]::gmail::notify_response ############################################################################# proc gmail::restore_window {from xlib jid} { open_window -raise 1 } ############################################################################# proc gmail::save_session {vsession} { upvar 2 $vsession session global usetabbar # We don't need JID at all, so make it empty (special case) set user "" set server "" set resource "" # TODO if {!$usetabbar} return set prio 0 foreach page [.nb pages] { set path [ifacetk::nbpath $page] if {[string equal $path .gmail_messages]} { lappend session \ [list $prio $user $server $resource \ [list [namespace current]::restore_window ""]] } incr prio } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/gmail/msgs000075500000000000000000000000001500237002100154745ustar00nobodynobodytkabber-plugins/gmail/msgs/de.msg000064400000000000000000000034001500237002100166500ustar00nobodynobody# de.msg -- # # German messages for the Gmail notifications Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 26.03.2009 ::msgcat::mcset de "Browse" "Durchsuchen" ::msgcat::mcset de "Delete" "Löschen" ::msgcat::mcset de "Delete Gmail notifications, which are older than 24\ hours." "Gmail-Benachrichtigungen löschen, die älter als 24\ Stunden sind." ::msgcat::mcset de "Delete all messages" "Alle Nachrichten löschen" ::msgcat::mcset de "Delete messages older than 24 hours" \ "Nachrichten löschen, die älter als 24 Stunden sind" ::msgcat::mcset de "Delete seen messages" "Gelesene Nachrichten löschen" ::msgcat::mcset de "Format of timestamp in Gmail tree view. Set to empty\ string if you don't want to see timestamps." "Format des\ Zeitstempels in der Gmail-Baumansicht (frei lassen, wenn keine\ Zeitstempel angezeigt werden sollen)." ::msgcat::mcset de "Gmail" "Gmail" ::msgcat::mcset de "Gmail notifications" "Gmail-Benachrichtigungen" ::msgcat::mcset de "Google Talk XMPP extensions." \ "Google Talk XMPP-Erweiterungen." ::msgcat::mcset de "Last Gmail message time." \ "Zeit der letzten Gmail-Nachricht." ::msgcat::mcset de "Mark all seen" "Alle Gelesenen markieren" ::msgcat::mcset de "Mark all unseen" "Alle Ungelesenen markieren" ::msgcat::mcset de "Mark seen" "Gelesene markieren" ::msgcat::mcset de "Mark unseen" "Ungelesene markieren" ::msgcat::mcset de "Open Gmail notifications" "Gmail-Benachrichtigungen" ::msgcat::mcset de "Plugins options." "Optionen für Plugins." ::msgcat::mcset de "Request Gmail notifications." \ "Gmail-Benachrichtigungen abfragen." ::msgcat::mcset de "Whether the Gmail plugin is loaded." \ "Gmail-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/gmail/msgs/es.msg000064400000000000000000000032541500237002100166760ustar00nobodynobody# es.msg -- # # Spanish messages for the Gmail notifications Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "Browse" "Navegar" ::msgcat::mcset es "Delete Gmail notifications, which are older than 24\ hours." "Borrar notificaciones de Gmail que sean anteriores a 24\ horas." ::msgcat::mcset es "Delete all messages" "Borrar todos los mensajes" ::msgcat::mcset es "Delete messages older than 24 hours" \ "Borrar los mensajes anteriores a 24 horas" ::msgcat::mcset es "Delete seen messages" "Borrar mensajes ya leídos" ::msgcat::mcset es "Delete" "Borrar" ::msgcat::mcset es "Format of timestamp in Gmail tree view. Set to empty\ string if you don't want to see timestamps." "Formato de la fecha\ en el árbol de Gmail. Si no pones nada, no se verán las fechas." ::msgcat::mcset es "Gmail notifications" "Notificaciones de Gmail" ::msgcat::mcset es "Gmail" "Gmail" ::msgcat::mcset es "Google Talk XMPP extensions." \ "Extensiones XMPP de Google Talk." ::msgcat::mcset es "Last Gmail message time." \ "Hora del último mensaje de Gmail." ::msgcat::mcset es "Mark all seen" "Marcar todos como leídos" ::msgcat::mcset es "Mark all unseen" "Marcar todos como no leídos" ::msgcat::mcset es "Mark seen" "Marcar como leído" ::msgcat::mcset es "Mark unseen" "Marcar como no leído" ::msgcat::mcset es "Open Gmail notifications" "Abrir Notificaciones de Gmail" ::msgcat::mcset es "Plugins options." "Opciones de plugins." ::msgcat::mcset es "Request Gmail notifications." \ "Solicitar notificaciones de Gmail." ::msgcat::mcset es "Whether the Gmail plugin is loaded." \ "Cargar el plugin Gmail." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/gmail/msgs/pl.msg000064400000000000000000000033731500237002100167040ustar00nobodynobody# pl.msg -- # # Polish messages for the Gmail notifications Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Browse" "PrzeglÄ…daj" ::msgcat::mcset pl "Delete" "UsuÅ„" ::msgcat::mcset pl "Delete Gmail notifications, which are older than 24\ hours." "Usuwaj powiadomienia Gmail starsze niż 24 godziny." ::msgcat::mcset pl "Delete all messages" "UsuÅ„ wszystkie wiadomoÅ›ci" ::msgcat::mcset pl "Delete messages older than 24 hours" \ "UsuÅ„ wszystkie wiadomoÅ›ci starsze niż 24 godziny" ::msgcat::mcset pl "Delete seen messages" "UsuÅ„ przeczytane wiadomoÅ›ci" ::msgcat::mcset pl "Format of timestamp in Gmail tree view. Set to empty\ string if you don't want to see timestamps." "Format znacznika\ czasu w widoku wiadomoÅ›ci Gmail. Aby wyłączyć znaczniki czasu\ pozostaw to pole puste." ::msgcat::mcset pl "Gmail" "Gmail" ::msgcat::mcset pl "Gmail notifications" "Powiadomienia Gmail" ::msgcat::mcset pl "Google Talk XMPP extensions." \ "Rozszerzenia XMPP dla Google Talk." ::msgcat::mcset pl "Last Gmail message time." \ "Czas ostatniego powiadomienia Gmail." ::msgcat::mcset pl "Mark all seen" "Oznacz wszystkie jako przeczytane" ::msgcat::mcset pl "Mark all unseen" "Oznacz wszystkie jako nieprzeczytane" ::msgcat::mcset pl "Mark seen" "Oznacz jako przeczytane" ::msgcat::mcset pl "Mark unseen" "Oznacz jako nieprzeczytane" ::msgcat::mcset pl "Open Gmail notifications" "Pokaż okno powiadomieÅ„ Gmail" ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "Request Gmail notifications." \ "Odbieraj powiadomienia Gmail." ::msgcat::mcset pl "Whether the Gmail plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ Gmail." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/gmail/msgs/ru.msg000064400000000000000000000043101500237002100167070ustar00nobodynobody# ru.msg -- # # Russian messages for the Gmail notifications Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Browse" "ПроÑмотреть" ::msgcat::mcset ru "Delete" "Удалить" ::msgcat::mcset ru "Delete Gmail notifications, which are older than 24\ hours." "УдалÑть ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Gmail Ñтарше 24 чаÑов." ::msgcat::mcset ru "Delete all messages" "Удалить вÑе ÑообщениÑ" ::msgcat::mcset ru "Delete messages older than 24 hours" \ "Удалить ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñтарше 24 чаÑов" ::msgcat::mcset ru "Delete seen messages" "Удалить проÑмотренные ÑообщениÑ" ::msgcat::mcset ru "Format of timestamp in Gmail tree view. Set to empty\ string if you don't want to see timestamps." "Формат вывода\ даты/времени в окне уведомлений Gmail. Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы не показывать\ дату/Ð²Ñ€ÐµÐ¼Ñ ÑовÑем, уÑтановите Ñту опцию в пуÑтую Ñтроку." ::msgcat::mcset ru "Gmail" ::msgcat::mcset ru "Gmail notifications" "Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Gmail" ::msgcat::mcset ru "Google Talk XMPP extensions." \ "РаÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ XMPP Ð´Ð»Ñ Google Talk." ::msgcat::mcset ru "Last Gmail message time." \ "Ð’Ñ€ÐµÐ¼Ñ Ð¿Ð¾Ñледнего ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Gmail." ::msgcat::mcset ru "Mark all seen" "Пометить вÑе как проÑмотренные" ::msgcat::mcset ru "Mark all unseen" "Пометить вÑе как непроÑмотренные" ::msgcat::mcset ru "Mark seen" "Пометить как проÑмотренное" ::msgcat::mcset ru "Mark unseen" "Пометить как непроÑмотренное" ::msgcat::mcset ru "Open Gmail notifications" "Открыть окно уведомлений Gmail" ::msgcat::mcset ru "Plugins options." "ÐаÑтройки раÑширений." ::msgcat::mcset ru "Request Gmail notifications." \ "Запрашивать ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Gmail." ::msgcat::mcset ru "Whether the Gmail plugin is loaded."\ "Загружено ли раÑширение Gmail." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/gmail/msgs/uk.msg000064400000000000000000000043431500237002100167060ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Gmail notifications Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Browse" "ПереглÑнути" ::msgcat::mcset uk "Delete" "Видалити" ::msgcat::mcset uk "Delete Gmail notifications, which are older than 24\ hours." "ВидалÑти нотифікації Gmail, Ñтаріші ніж 24 години." ::msgcat::mcset uk "Delete all messages" "Видалити вÑÑ– повідомленнÑ" ::msgcat::mcset uk "Delete messages older than 24 hours" \ "Видалити Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñтаріші за 24 години" ::msgcat::mcset uk "Delete seen messages" "Видалити переглÑнуті повідомленнÑ" ::msgcat::mcset uk "Format of timestamp in Gmail tree view. Set to empty\ string if you don't want to see timestamps." "Формат виводу\ дати/чаÑу у вікні нотифікацій Gmail. Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб не показувать\ дату/Ñ‡Ð°Ñ Ð·Ð¾Ð²Ñім, вÑтановіть цю опцію пуÑтим Ñ€Ñдком." ::msgcat::mcset uk "Gmail" ::msgcat::mcset uk "Gmail notifications" "Ðотифікації Gmail" ::msgcat::mcset uk "Google Talk XMPP extensions." \ "Ð Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ XMPP Ð´Ð»Ñ Google Talk." ::msgcat::mcset uk "Last Gmail message time." \ "Ð§Ð°Ñ Ð¾Ñтаннього Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Gmail." ::msgcat::mcset uk "Mark all seen" "Помітити вÑÑ– Ñк переглÑнуті" ::msgcat::mcset uk "Mark all unseen" "Помітити вÑÑ– Ñк непереглÑнуті" ::msgcat::mcset uk "Mark seen" "Помітити Ñк переглÑнуте" ::msgcat::mcset uk "Mark unseen" "Помітити Ñк непереглÑнуте" ::msgcat::mcset uk "Open Gmail notifications" "Відчинити вікно нотифікацій Gmail" ::msgcat::mcset uk "Plugins options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½ÑŒ." ::msgcat::mcset uk "Request Gmail notifications." \ "Запитувати на нотифікації Gmail." ::msgcat::mcset uk "Whether the Gmail plugin is loaded."\ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Gmail." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/iconsets000075500000000000000000000000001500237002100152615ustar00nobodynobodytkabber-plugins/iconsets/amibulb000075500000000000000000000000001500237002100166745ustar00nobodynobodytkabber-plugins/iconsets/amibulb/docking000075500000000000000000000000001500237002100203125ustar00nobodynobodytkabber-plugins/iconsets/amibulb/docking/tkabber.ico000064400000000000000000000510261500237002100225030ustar00nobodynobody°h¶hh† hîhVh¾°&"hÖ"h>( ¨¦- èN6 ¨69hÞAhFGh®L( ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(  &,?2F5L<$R3+Y¤D-[<0\ ” #ŽE0`:3a+ƒ:pG9iJ>n D~T?q1²Nˆ]Hz>²N®(Y–OºVÀgªj®vºqÐ}Àu؂ƎВ֙à¡äî®î©ø²ü¼ú»ø ÁþÄþÅþ,Çü&Îþ3Ðý?ÎýJÍþ}Øý†Ýþ–ßþ¤áþ´æþÂìþ;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;; ;;;;;;;;&+%;;;;;;+-''(";;;;; //!*/)-';;;; ,////////- ;;;015861///.$;;;15:::7////# ;;;,7:::9////;;;;;5:::6//1/;;;;;;6852101;;;;;;;;0340/;;;;;;;;;; ;;;;;þ?üüüøðààÀÀÀÀàðøü( #./4A7fXU^e[ciBjfelsErsF€eKhIw{F€oX|rK‡jH‚xH‚zQpR”qR”zT˜tT˜~YŸx\¦c©p¬‰u±x´€¸–Œ¾ ’¦ªÎ¹°Ò¿ºØÇÀÚÌÈàÒÑåÚÝëã------------------------------ ----------- ---------- -------------- -----!!   ---- """""""!---##'*(#""" ---#&,,,)""" --- ),,,+""" -----',,,'""# ------'*'####--------#$%# ---------- -----þ?üüüøðààÀÀÀÀàðøü(  &,?2F5L<$R3+Y¤D-[<0\ ” #ŽE0`:3a+ƒ:pG9iJ>n*³ D~T?q1²]Hz>²N®J¸(Y–gªj®vº}À‚ÆŽÐ’Ö™à¡ä©ø²ü¼ú»øÀþÃþÅþÉþ Çþ,Çü&Îþ3Ðý?ÎýJÍþyÙý†Ýþ–ßþ¤áþ´æþÆìþ8888888888888888888 8888888888888888888888 8888888888 88888888#&***"888888&**88888**%)$**8888 '********( 888-.253.***)!888.274*) 888'476*)8888827773*,,)888888352/.-.88888888-01-+8888888888 88888þ?üüüøðààÀÀÀÀàðøü(  &,?2F¤D-[ ™<0\ ” #Ž+ƒ*³ D~1²]Hz>²(Y–Oºgªj®}ÀuØ¡äî¼ú»ø ÁþÅþÈþ,Çü&Îþ3Ðý?ÎýJÍþ}Øý†Ýþ“Þý¤åþ´æþÆìþ(((((((((((((((((( (((((((( ((((((( ((((((  '''' ((((( '''' (((( (((( ((((((("%# ((( "'''$((($'''&((((("'''#((((((#%"(((((((( !((((((((((  (((((þüüüøðààÀÀÀÀàðøü( JJJNTPEm_BjfEqsGyhKhIw{X|rK‡jH‚zR”qR|T˜tS—}\¤|dªƒp¬‰u±€¸–½§§Œ¾ ’¦ҵ·Ø½½Ò¾ªÎ¹°Ò¿ÛÉÇãÍ̺ØÇÀÚÌêÔÔÈàÒîÙØõÝÛÑåÚáààéâáóáàÝëãúæäüëéÿñïÿùöÿÿÿ....+-%+&.#-----"+,-. +-----'"----.--------,".---")*,+...-"-  ....- .... ... ! ... ((( ...((($..... ((( ...... !........  .......... .....€€€ÀÀÀÀÀàðøü( /.0546===DCEGFHLNPPRTX[\]bc`efekkhnnmsstzyz€‚ˆˆˆŽŽŒ’‘¡¡¡¥¥¥©©ª®®°´´¶ºº¼À¿                þ?üüüøðààÀÀÀÀàðøü( þ?üüüø÷÷ïûïûÏùßýÏùïûïû÷÷ûïü( *U*€U*>*ªUUU?*?UªU?U?UªU?U_UUÔU?ªª_UU_UUª_U_ªªUUU_Ôª………UªUÔªŸUŸª¤  UÿªŸªÿŸªU¿ªª¿ªÿŸÔªŸÿª¿Ôðʦÿ¿Ôª¿ÿÀÜÀªßÔUßÿªßÿÿÿªÿÔUÿÿªÿÿõüÿ! -! #!+  #5!#  -!))5! ( .54 ,,,( #4).&((((245!(("!%3  0! 531%55!%1/#4$'-+&&45)+# -!-! 5*!5+!#55-+ -þÀ€€€€€€€€€Àâöÿ( Uÿÿ*U>*ÿ*ÿUU?UUÿÿ?UU_Uªÿÿ?Uÿÿ_UUU?ÿU_ªÿ__ÿ………ÿU_ÿª_ÿÿÿªªÿŸÿÿŸªªŸÔUŸÿÿŸÔªŸÿU¿ÿª¿ÿÿßÔªßÿðûÿ         "" "" ##%"##%!& $ & üø?À€€€€€€„ÂÇçÏ( @9N>UAZIe!Li#Pn%Vx(]€*bˆ.k•.q3y§1}±<€­:…·;ŒÃDÃ=‘ÈD”Ê;™×CšÕJ¢Ü>¤êG¦åR¬çB«ñI°ïZ´îY¹ú`¿ÿÿÿÿ                                  ( @'¢É<´ÙA¹ÝhÔñÿÿÿUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUPUUUUUUUUUUU3330UUUUUUUUUUPUUUUUUUUUPUUUUUUUUUP14DCUUUUUUUUUPD3D1UUUUUUUUUP3@41UUUUUUUUUP1@DUUUUUUUUUUUUUUUUUUUUUUUUUP333UUUUUU0UUUUUPCUUUUUPD!3AUUUUUPDD4@0D0UUUUUP2@D@!0AUUUUUP@D@3D0UUUUUUDD4@#$0UUUUUUP##1P2UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU( @!)' 3:<2ADK3p);kF4oNAS5>e 0’AoV% %4ŽÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇ& 4ŠÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇ( 's§ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇj;+CGKPS! 0O#"-/258AFFLORT5P157<>BEHM! .I#"+-/2489?C%$(*;@'&((),-0369ððÀÀÀÀÀÀÀÀÀÀÀÀÀÀ( GGGIIIJJJKLKLLLMMMNNNOONOOOOOPPPPQQQQQRRRRRSRSSSTTTUUUVVVWWWXXXZYZZZZ\[\]\\]\]]]]^^__`_```bbbbbcedeeffghhihijjjkkkmmmŠÿŽÿÿ“ÿ”ÿ–ÿ—ÿšÿœÿŸÿ¡ÿ£ÿ¤ÿ¥ÿ§ÿ¨ÿªÿ«ÿ­ÿ®ÿ¯ÿ°ÿ²ÿ³ÿ´ÿµÿ¶ÿ¸ÿ¹ÿ»ÿ¼ÿ¾ÿÀÿÁÿÂÿÄÿÅÿÆÿÇÿÈÿÊÿËÿÍÿÎÿÐÿÒÿÔÿÖÿÙÿÚÿÛÿÞÿßÿàÿãÿäÿæÿçÿèÿìÿíÿñÿ  RUWZ\_bde MQTVX[^acI`EHKORUWZ]@YBE%$*,=A'&()+.0258;ððÀÀÀÀÀÀÀÀÀÀÀÀÀÀtkabber-plugins/iconsets/amibulb/icondef.xml000064400000000000000000000056031500237002100211100ustar00nobodynobody Amibulb 1.0 Tkabber's Amibulb Iconset. 2006-01-21 toolbar/add-user tkabber/toolbar-add-user.gif toolbar/disco tkabber/toolbar-disco.gif toolbar/join-conference tkabber/toolbar-join-conference.gif toolbar/show-offline tkabber/toolbar-show-offline.gif toolbar/show-online tkabber/toolbar-show-online.gif browser/client roster/available.gif browser/user roster/available.gif docking/tkabber docking/tkabber.ico roster/user/chat roster/available-chat.gif roster/user/available roster/available.gif roster/user/away roster/available-away.gif roster/user/xa roster/available-xa.gif roster/user/dnd roster/available-dnd.gif roster/user/invisible roster/invisible.gif roster/user/unavailable roster/unavailable.gif roster/user/unsubscribed roster/stalker.gif roster/user/error roster/unavailable.gif roster/group/closed roster/group-closed.gif roster/group/opened roster/group-opened.gif tkabber-plugins/iconsets/amibulb/roster000075500000000000000000000000001500237002100202125ustar00nobodynobodytkabber-plugins/iconsets/amibulb/roster/available-away.gif000064400000000000000000000011031500237002100236320ustar00nobodynobodyGIF89aÆKJJJ]G3RJB^G2ZI9bL6tZ>t\>u_?teNzjHtlNjEwmKupMrN”ƒPŸU¡„W¤…X¦‰ZŸŽU¦ŠZ¦ŒZ ‘V¡’W¦Z£”W£•W¦“Z¦•Z¤—X¦™Z¦›Z¦žZ¦ Z¦¢Z¦¤Z¦¥Z¥¦Z§§½©©À³´Ð·µÒ··Ë·¶Ò½½Ø¾ÂÒÇÉÛÉÉåËËâËÌäÌÍãÏÏæÔÔêרîרïØÙîÙÛïÛÜíÛÝõààááâéàáóäæúéëüìíÿîðüïñÿñòüòõÿöùÿ÷úÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù , €‚‚……ƒˆ„ ‰%(š&’ˆ$š›ž”¤¥(¨¢"™¥ ²  "&¯!¨5K #'¥ ž½K4:Ƚ‚KÝ68A½BHG½ÛÝèK3.JKH<æ7EéK@;Ýí,/=õrÈ’¿+`YâÃÈ*ZÄ0wðšE‹“2& ;tkabber-plugins/iconsets/amibulb/roster/available-chat.gif000064400000000000000000000010621500237002100236140ustar00nobodynobodyGIF89aÆE$$$%%%(((=(8,///000S0L>2S?-}DMNPDE–Jg[Dhhhk±[±e³h»gÃiÝvÙ|óúü”÷šÿ˜ÿšä©ÿžÿ ÿ¡ÿ¢ÿ¤ÿ¥ÿ§ÿ¨ÿ©ÿªÿ«ÿ°ÿµó¾õÂÿ¿ÿÁ÷ÈÿÄùÈÿÇùËüÎÿÒÿÖÿÚÿâÿäÿéÿðÿñÿõÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,€‚‚……ƒˆ„8461‰!/ADšB"’ˆ%&3?ššCž”,#5¤¥D0©)$2<@°9³ +'.;B°:³*()7=Î ˆ+-#>Ú>΃…/Ù Úä‰ ÙÛÚç‰ãåÜ“ì äõ‰ ìܽK„@€gÝ&)D;tkabber-plugins/iconsets/amibulb/roster/available-dnd.gif000064400000000000000000000010611500237002100234410ustar00nobodynobodyGIF89aÆD$$$%%%(((‡d///000‰L>2S?-ÿMNPDE–J“DEhhh¸T±[±e³h¸h»gÃiÝvÙ|óúü”÷šÿ˜ÿšä©ÿžÿ ÿ¡ÿ¢ÿ¤ÿ¥ÿ§ÿ¨ÿ©ÿªÿ«ÿ°ÿµó¾õÂÿ¿ÿÁ÷ÈÿÄùÈÿÇùËüÎÿÒÿÖÿÚÿâÿéÿðÿñÿõÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,Ž€‚‚……ƒˆ„8461‰!/@CšA"’ˆ%&3>ššBž”,#5¤¥C0©)$2t\>u_?xeJwmK€lB·hrN³dh”ƒPŸU¡„W¤…X¦‰ZŸŽU¦ŠZ¦ŒZ ‘V¡’W¦Z£”W£•W¦“Z¦•Z¤—X¦›Z˜˜˜¦ Z¦¢Z¦¤Z²¡N¥¦Z©ªVº­F³´Lµ¶J±±°³´Ð·µÒ½½Ø¾ÂÒËÌäÌÍãÏÏæÔÔêרîØÙîÛÝõààáççæäæúîðüïñÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,¡€‚‚……ƒˆ„   ‰'*š(’ˆ !&š› ž”"¤¥*¨¢$™¥#²$(+..-) ƒ5A,Ñ‚½A49Ì<@@ÑAä68=Ü@ÞêâäïAêëàâ7?ðò%ìâ12t¼ ðbž¿^0fø²cÁyTëE±i'iL;tkabber-plugins/iconsets/amibulb/roster/available.gif000064400000000000000000000010641500237002100227010ustar00nobodynobodyGIF89aÆU$$$%%%(((///000111L>2S?-\@&MNPDEF–J”T`abhhh±[±e³h»gÃi{{{ÃzÝvÙ|•••º§óúü”¤¤¥÷šÿ˜ÿšä©ÿžÿ ÿ¡ÿ¢ÿ¤ÿ¥ÿ§ÿ¨°°°ÿ©ÿªÿ«ÿ­ÿ°ÿµó¾ºººõÂÿ¿ÿÁ÷ÈÿÄùÈÿÇùËúÌÿÊüÎÿÒÿÖËËËÿÚÿÝÿâÓÓÓÿéÿëÿðÿñÿòÿõÿøÿûÿÿòòóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,‘€‚‚……ƒˆ„$@<>9‰&6NSšP'’ˆ*+;KššQž” 2(=¤¥S7©".):GM°C³%1,5EP°D³/-.?IR¥©!13(BHOSAÐ…64L‡“ ê “ˆFJ0îƒ8ö‚ FP™0ÀŸ  0ÈðO ;tkabber-plugins/iconsets/amibulb/roster/group-closed.gif000064400000000000000000000001301500237002100233550ustar00nobodynobodyGIF89a Âÿÿÿ†ËñY„Áÿÿÿÿÿÿÿÿÿÿÿÿ!ù , HºÜÀ1¢|AXG…–0lK8rÙ‰ªÜwAWL$;tkabber-plugins/iconsets/amibulb/roster/group-opened.gif000064400000000000000000000001271500237002100233640ustar00nobodynobodyGIF89a Âÿÿÿ…ÊðXƒÀÿÿÿÿÿÿÿÿÿÿÿÿ!ù , HºÜþ02@«U è­ÁBÞ$’0 %½P;tkabber-plugins/iconsets/amibulb/roster/icondef.xml000064400000000000000000000025111500237002100224210ustar00nobodynobody Amirose Bulb 1.0 Amirose Jabber Bulb Iconset 2003-09-05 Tomasz Sterna (conversion) amirose (icons) status/online online.png status/offline offline.png status/away away.png status/xa xa.png status/dnd dnd.png status/invisible invisible.png status/chat ffc.png tkabber-plugins/iconsets/amibulb/roster/invisible.gif000064400000000000000000000007321500237002100227460ustar00nobodynobodyGIF89aÆU$$$%%%(((///000111L>2S?-\@&MNPDEF–J”T`abhhh±[±e³h»gÃi{{{ÃzÝvÙ|•••º§óúü”¤¤¥÷šÿ˜ÿšä©ÿžÿ ÿ¡ÿ¢ÿ¤ÿ¥ÿ§ÿ¨°°°ÿ©ÿªÿ«ÿ­ÿ°ÿµó¾ºººõÂÿ¿ÿÁ÷ÈÿÄùÈÿÇùËúÌÿÊüÎÿÒÿÖËËËÿÚÿÝÿâÓÓÓÿéÿëÿðÿñÿòÿõÿøÿûÿÿòòóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,7€‚‚…†ƒˆ…‰ŠŒŒƒˆ’„•‘™˜–œ•””ž“˜‹‘ „¦¥†¤¡š¬—£¢›ª›´;tkabber-plugins/iconsets/amibulb/roster/stalker.gif000064400000000000000000000010711500237002100224240ustar00nobodynobodyGIF89aÆL<<æÞÔãßÛäßÙãàÛýð?ÿï?öô?ÿð<àááûó?ÿò?ÿó?ÿô?ýö=ÿõ>ýö?ÿõ?ÿö?ýø<ýø=ýø>ýù?ÿø?æææÿù?ÿú?ÿû?ÿü?ÿý?éééÿÿ?ìììðððóóóôôôöööøøøùùùüüýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,–€‚‚ ƒŠ‚ #7892‹,3@CA.‹ ,/6œCA¡‚ 00;§¨4¬$°;?A¨C:¶ *116>½¨=¶Ä5=@ÈC"¶)151=¼¿Õ!65@+ß–Ö'&(&&%ëƒBIJGó‚DEHìûc¡…‘%< ü#aA† ;tkabber-plugins/iconsets/amibulb/roster/unavailable.gif000064400000000000000000000005271500237002100232470ustar00nobodynobodyGIF89a¥$\Wg ih h lnu$$$%%%(((///š000111¬L>2S?-MNP`abhhh{{{•••¤¤¥°°°ºººËËËÓÓÓòòóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ?,tÀŸPh(‡HâàiF†äϰdL,Ø #Š\ W¬eŒoX áNÑßÈÚqŸÓ ¹˜n¤ãkeC pznST~ GR—RH!"›C £B#«B ³¹?A;tkabber-plugins/iconsets/amibulb/tkabber000075500000000000000000000000001500237002100203065ustar00nobodynobodytkabber-plugins/iconsets/amibulb/tkabber/toolbar-add-user.gif000064400000000000000000000002031500237002100242130ustar00nobodynobodyGIF89aÂY„ÁEuÿÿÿ†Ëñÿÿÿÿÿÿÿÿÿÿÿÿ!ù,HHºÜþ0ÊI«½è0B8 Žcy¨*mš€’\Þ3î6ìì“¶ßoÇè SÁc+h6e-'ñaœ¾ Hˆ‘:=à°xI;tkabber-plugins/iconsets/amibulb/tkabber/toolbar-disco.gif000064400000000000000000000002311500237002100236110ustar00nobodynobodyGIF89a€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,^xºÜþ0ÊI«½ ©#Áö|!‚蜩9tŒ ¼.@È·2«Ù+ä¶ßfW; ã8¢)“ ¡sõA­Lª 'ÊöN@$púUÍÞ˜ó5“Õªv4½ÐðV0Œ~ÏïC;tkabber-plugins/iconsets/amibulb/tkabber/toolbar-join-conference.gif000064400000000000000000000006061500237002100255620ustar00nobodynobodyGIF89a¥ÔßÿU_Uÿûð€€€*?UUU?Uª_UUUÿ¿ªÿߪÿŸªÿŸUÿªÿ_ªÿ¿UÔŸªªŸÿÔŸÿªÿ_ÿÿ_UÿUÿÔU*ÿÿªÿÿ?Uÿÿ?UÿŸÿ_U_ÿ?ÿÿUU?ÿ*ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ?,£ÀŸpH,ȤrÉl2€"Ô ¢BÀàÚ Q(ÀpÀ*ˆDx P˜“€£á€ÊÈû—G¼P y{R…Rˆ’DuŒž œ!K"#$%¥&^p¸¹''±&¿ÁÂH¸¬'(ÉOb±SNY(ਵÝÞåæçèéA;tkabber-plugins/iconsets/amibulb/tkabber/toolbar-show-offline.gif000064400000000000000000000002441500237002100251140ustar00nobodynobodyGIF89a¦¦¦sssÿÿÿûùûÛYYYÿÿÿ!ù ,ixºÜþ0ÊI‚ pf› b׎À@xÚuŽ*±jA-Þ]Ù{ü. %…†‡ˆ ;tkabber-plugins/iconsets/amibulb/tkabber/toolbar-show-online.gif000064400000000000000000000002101500237002100247470ustar00nobodynobodyGIF89aÂÿÿÿûùûÛÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,MHºÜþ0ÊI«½Ü@GxBb¤iiÚWšläîkÃÙÕö‹ç²Þ §{„‚_r3ƒÒZ—ÀT³¥h©#eFȉÎè´:;tkabber-plugins/iconsets/gabber000075500000000000000000000000001500237002100165035ustar00nobodynobodytkabber-plugins/iconsets/gabber/docking000075500000000000000000000000001500237002100201215ustar00nobodynobodytkabber-plugins/iconsets/gabber/docking/available-away.gif000064400000000000000000000005521500237002100235500ustar00nobodynobodyGIF89a¥±#°"z™w¶“'³’$ª‰’qlصI¸—(¡€‹i †d ¸•(ž{‹iƒa ’p¦„}[ …b yZ¯Œ!uTÌÌÌ```QQQ???ÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þCreated with The GIMP!ù ,n@pH,ȤrÉlP€s©³Z0 í’«X ‡8 $"Y#ƒƒ2¡TìG|€  ˆŠw ‰SB‘lQP—œŸ ¦—±²³FA;tkabber-plugins/iconsets/gabber/docking/available-chat.gif000064400000000000000000000004401500237002100235220ustar00nobodynobodyGIF89a„ˤ)Ê£(È¡&Ï©.Ö±7Ù´<É¢'Õ°6ܸ@çÆRΨ-ݹAóÙpøâ‚ëËZز9èÇTéÈVìÌ\ãÁLñÔhÞºBóØoÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þCreated with The GIMP!ù ,„à'Ždižhª®lk0àŠp ÜDa„ƒ!Sñ0°`Q€‚¢áh( ‚€áùÒ>Ç`ƒD¸$€@ÚXÕZ zЇ’00&s4Q?A9‚}68cF 1‹t  š;Š›'—3®¯°±,!;tkabber-plugins/iconsets/gabber/docking/available-dnd.gif000064400000000000000000000004351500237002100233540ustar00nobodynobodyGIF89a„þâÔþÒÄó¾«é²šÞ¦Öž„ÆŠo¾‚dÎ’t²wW¦jL¡eD‘Y<ªqQ€K.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þCreated with The GIMP!ù , $Ždižhª®l[pìÂ&Ú(Nsÿ@Ù+  ƒáp@8¼—¶(ŒÑˆî¦€v”ÃÝZx\ ›Ã;‚ lª€­µmm{m t"{smsqcZ5P] €ae5  c'A©‡.¬­®#!;tkabber-plugins/iconsets/gabber/docking/available-xa.gif000064400000000000000000000004451500237002100232200ustar00nobodynobodyGIF89a„öÿÿÍúÿ½òÿ¬âÿœÒÿ‹Æÿs¶öj®îÇäJ…Å9y´1m¬)aœ¬âü·Ú˜Ñün§ÐŠÂá«ãÿ1l¬b¥æL‡¼R•͈Äü Gabber 1.0 Tkabber's Gabber Iconset. 2006-01-21 toolbar/add-user tkabber/toolbar-add-user.gif toolbar/disco tkabber/toolbar-disco.gif toolbar/join-conference tkabber/toolbar-join-conference.gif toolbar/show-offline tkabber/toolbar-show-offline.gif toolbar/show-online tkabber/toolbar-show-online.gif browser/client roster/available.gif browser/user roster/available.gif browser/conference roster/conference-available.gif browser/headline services/rss_online.gif browser/directory services/jud.gif browser/jud services/jud.gif browser/sms services/sms.gif browser/aim services/aim_online.gif browser/icq services/icq_online.gif browser/msn services/msn_online.gif browser/yahoo services/yahoo_online.gif docking/chat docking/available-chat.gif docking/available docking/available.gif docking/away docking/available-away.gif docking/xa docking/available-xa.gif docking/dnd docking/available-dnd.gif docking/invisible docking/invisible.gif docking/unavailable docking/unavailable.gif docking/message docking/message.gif docking/message-personal docking/message-personal.gif docking/message-server docking/message-server.gif docking/tkabber docking/tkabber.ico roster/user/chat roster/available-chat.gif roster/user/available roster/available.gif roster/user/away roster/available-away.gif roster/user/xa roster/available-xa.gif roster/user/dnd roster/available-dnd.gif roster/user/invisible roster/invisible.gif roster/user/unavailable roster/unavailable.gif roster/user/unsubscribed roster/stalker.gif roster/user/error roster/unavailable.gif roster/conference/available roster/conference-available.gif roster/conference/unavailable roster/conference-unavailable.gif roster/group/closed roster/group-closed.gif roster/group/opened roster/group-opened.gif services/aim/away services/aim_away.gif services/aim/chat services/aim_chat.gif services/aim/dnd services/aim_dnd.gif services/aim/unavailable services/aim_offline.gif services/aim/available services/aim_online.gif services/aim/xa services/aim_xa.gif services/icq/away services/icq_away.gif services/icq/chat services/icq_chat.gif services/icq/dnd services/icq_dnd.gif services/icq/unavailable services/icq_offline.gif services/icq/available services/icq_online.gif services/icq/xa services/icq_xa.gif services/jud services/jud.gif services/msn/away services/msn_away.gif services/msn/chat services/msn_chat.gif services/msn/dnd services/msn_dnd.gif services/msn/unavailable services/msn_offline.gif services/msn/available services/msn_online.gif services/msn/xa services/msn_xa.gif services/rss/away services/rss_away.gif services/rss/chat services/rss_chat.gif services/rss/dnd services/rss_dnd.gif services/rss/unavailable services/rss_offline.gif services/rss/available services/rss_online.gif services/rss/xa services/rss_xa.gif services/sms services/sms.gif services/yahoo/away services/yahoo_away.gif services/yahoo/chat services/yahoo_chat.gif services/yahoo/dnd services/yahoo_dnd.gif services/yahoo/unavailable services/yahoo_offline.gif services/yahoo/available services/yahoo_online.gif services/yahoo/xa services/yahoo_xa.gif tkabber-plugins/iconsets/gabber/roster000075500000000000000000000000001500237002100200215ustar00nobodynobodytkabber-plugins/iconsets/gabber/roster/available-away.gif000064400000000000000000000005051500237002100234460ustar00nobodynobodyGIF89a¥±#°"z™w¶“'³’$ª‰’qlصI¸—(¡€‹i †d ¸•(ž{‹iƒa ’p¦„}[ …b yZ¯Œ!uTÌÌÌ```QQQ???ÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,b@pH,A€$àHÂ’é,ˆÄ´XU,Œ†c; Ї‘…€Áá ™P*o$Á©SyH  €‚p Le‰eJIH“H–—”GA;tkabber-plugins/iconsets/gabber/roster/available-chat.gif000064400000000000000000000003701500237002100234240ustar00nobodynobodyGIF89a„ˤ)Ê£(È¡&Ï©.Ö±7Ù´<É¢'Õ°6ܸ@çÆRΨ-ݹAóÙpøâ‚ëËZز9èÇTéÈVìÌ\ãÁLñÔhÞºBóØoÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,uà'Ždi~@ œcƒžQqÈJÖ‰”"X0|"@AÑp4AÀ€L€ãa@">€`Ù<ÅSIx@(CÂÀ˜„%N'£Tª0]1\? *„HI  Ž4&‹,¢%!;tkabber-plugins/iconsets/gabber/roster/available-dnd.gif000064400000000000000000000003551500237002100232550ustar00nobodynobodyGIF89a„þâÔþÒÄó¾«é²šÞ¦Öž„ÆŠo¾‚dÎ’t²wW¦jL¡eD‘Y<ªqQ€K.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,j $ŽdihjŠè íʾ¯\¦x®‚0ƒáp@(jP,£‘ Ô°½R­X@AË Ô™‡³O1À!w·›K´ü>g£HbT tWV[\‹‹  Y:—/!;tkabber-plugins/iconsets/gabber/roster/available-xa.gif000064400000000000000000000003711500237002100231160ustar00nobodynobodyGIF89a„öÿÿÍúÿ½òÿ¬âÿœÒÿ‹Æÿs¶öj®îÇäJ…Å9y´1m¬)aœ¬âü·Ú˜Ñün§ÐŠÂá«ãÿ1l¬b¥æL‡¼R•͈ÄüÏÄ@e.›RÐ!”Re/›•*”ÙPL©O9 k1¸JR WAÇp•JÏS¶};tkabber-plugins/iconsets/gabber/roster/conference-unavailable.gif000064400000000000000000000016451500237002100251650ustar00nobodynobodyGIF89aç  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~€€€‚‚‚ƒƒƒ„„„………†††‡‡‡ˆˆˆ‰‰‰ŠŠŠ‹‹‹ŒŒŒŽŽŽ‘‘‘’’’“““”””•••–––———˜˜˜™™™ššš›››œœœžžžŸŸŸ   ¡¡¡¢¢¢£££¤¤¤¥¥¥¦¦¦§§§¨¨¨©©©ªªª«««¬¬¬­­­®®®¯¯¯°°°±±±²²²³³³´´´µµµ¶¶¶···¸¸¸¹¹¹ººº»»»¼¼¼½½½¾¾¾¿¿¿ÀÀÀÁÁÁÂÂÂÃÃÃÄÄÄÅÅÅÆÆÆÇÇÇÈÈÈÉÉÉÊÊÊËËËÌÌÌÍÍÍÎÎÎÏÏÏÐÐÐÑÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖÖ×××ØØØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝÞÞÞßßßàààáááâââãããäääåååæææçççèèèéééêêêëëëìììíííîîîïïïðððñññòòòóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿ!ù ÿ,‚ÿý@P€Àƒ @ÄpÁ.%À’ŠöìaˆÈàÄŠ3‚zbTÇŒ$Ar¸ç H“>™ÉR#(KOfdT¥€™.dD”çΞB!ˆ˜QcÒƒ 7jŒ˜p!A‹VE¤²ëS„( æÔ V#Щ ¡%J6-Á¥mÿ;tkabber-plugins/iconsets/gabber/roster/group-closed.gif000064400000000000000000000001141500237002100231660ustar00nobodynobodyGIF89a¡îîîÿÿÿÿÿÿ!ù ,”©ËÝà€Ñ€@ãÅusç}Œ—ø O Vîk;tkabber-plugins/iconsets/gabber/roster/group-opened.gif000064400000000000000000000001141500237002100231670ustar00nobodynobodyGIF89a¡îîîÿÿÿÿÿÿ!ù ,”©Ë혴‚Þá®Ìy ØA™ø Ñʶ.S;tkabber-plugins/iconsets/gabber/roster/invisible.gif000064400000000000000000000003331500237002100225520ustar00nobodynobodyGIF89a„111999BBBJJJRRRZZZccckkksss{{{„„„µŒÆ”!Μ)Ö¥1çµBï½JÆÆÆÿÎZÿÖcÿÖkÿÞsÿç{ÿÿÖÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,Xà'Ždi~@ œ$PM†±²®e!1—5v%Â`7P*‹Â $Š eDœ(H#) ,êá˜,WÊÑ8¤Õ(Æ[­RÁ ÉBv†b- !lA#rG'~R0ppp²†Y5Ža<‘d?—iCª{Tÿ·ˆaÿÿÿ!ù,È $I’$I€$I’$I’$I’$ ’$’$I’$Nà I’$I’8Q´J’$IMôÇ€$IÀ²Œ³ÃHÀa ȱÅ CÄq A’$0 !H’$%€’$II’$I B ¤€$I’”@’’$I(%I’$€$I’$II’’$I $I’”$ ’$IR;tkabber-plugins/iconsets/gabber/roster/unavailable.gif000064400000000000000000000003341500237002100230520ustar00nobodynobodyGIF89a„|||www^^^XXX}}}oooRRRNNNµµµˆˆˆxxxdddGGGBBBƒƒƒ___III???OOOiii;;;777uuuÌÌÌ```QQQÀÀÀÿÿÿÿÿÿÿÿÿ!ù ,Yà'Ždi~@ œ$±²naH2—µ²0 Çc7 ˆ "™E€Á±¤T,Oá‰X!—,*1Á,ÀbècÒ³Š÷¥JÍ…LA“†6N}P‚Eb!;tkabber-plugins/iconsets/gabber/services000075500000000000000000000000001500237002100203265ustar00nobodynobodytkabber-plugins/iconsets/gabber/services/aim_away.gif000064400000000000000000000006111500237002100226610ustar00nobodynobodyGIF89aõ/ ?&1-22/%|O+l_+QQQfffppo|||.–Ê:õJï9eòEtêoƒ}ƒÌ“k2€‚K˜‚eÊ Gþ·GýÉfžžž‘¢‡‘°¥¡œª¦Ÿººº˜ø˜¦ý¦·õÞ݃úÓ·üóµÚÚÚÍÔþãàÌàààêèåêêêóóóùùùÿÿÿ!ù/,¦À—ðuZmHÅê4Q@S t–Ãâ(b(h4$„`„}­FG÷«CÈDTäñpKÀñˆ ž" !+ ŽŽ,š› &_–™ ¤ , ¡™›š Š—£¥§%UµŒ ¯°%»~'¾¥¦ p¾¿ ËX .ÚÚ *B )-CA;tkabber-plugins/iconsets/gabber/services/aim_chat.gif000064400000000000000000000006271500237002100226460ustar00nobodynobodyGIF89aõ* ('$*&)(?BR=xc-_bB)EJyN @@@UUUgggnnn€Œ·“  ©ÁÈñî/ÌÒ-èáKîènÚÛ’€7ÌœQù¦TúËgžžžŽ©§˜Ã½†÷öžóîÚÚÚÊõòàààêèåñòñÿÿÿ!ù*,´@•PUB@U ‹¦ €ÓáBÌa‘”I0>`‚”U¡¸—É A\ÈDSær±Õ€å’1Gt  #((t `  s‚`Ÿ|›t£Ž¨…Š™€´VtŒ%"À¾Á}%% ÉѾpwÔ ¾Y†« ƒ MD†%''ô)CA;tkabber-plugins/iconsets/gabber/services/aim_dnd.gif000064400000000000000000000006121500237002100224660ustar00nobodynobodyGIF89aõ0 ?&1-22/%|O+[*!l_+fffppo.–Ê:õJï9eòEtêoƒ}ƒÌ‚<0žI8“k2ÿw[€‚K˜‚eÊ Gÿ“lþ·GýÉfœ›žžž‘¢‡‘°¥¡œª¦Ÿ˜ø˜¦ý¦·õÞ݃úÓ·üóµÚÚÚÍÔþãàÌàààêèåóóóÿÿÿ!ù0,§@˜¦r}H…K5W€Ec „–â b(t:§„À„…¹LG÷Û?ÈÄÄáhL á€¬ž% "# $.ŽŽ#š›)_–™¤ ¡™›š Š—£¥§(UµŒ¯°(»~*¾¥¦ p¾¿ ËXÚÚ -BÉ,/CA;tkabber-plugins/iconsets/gabber/services/aim_offline.gif000064400000000000000000000003601500237002100233430ustar00nobodynobodyGIF89aô $$!%$"$$$$%'>;7999LLL]\Xƒ€|‹ŒŒ›•¤¡™ÿÿÿ!ù,mà$ŽSd:ÎãJ"R½(òH× žO€… õ ÀÀ'KÔb 8jØ1xH Ç"! "_ä6¥`DБ—LAxÄo9 p°?|o T"A"o+, e#F{I*Ž#!;tkabber-plugins/iconsets/gabber/services/aim_online.gif000064400000000000000000000006271500237002100232130ustar00nobodynobodyGIF89aõ* ()+'*))CBSXz.GcC+EK{Q @@@UUUgggnnnK ZªhÊ‹¸ò0‚Ó-˜éK«ïn§Ü“‚8Í Rú¨UûÏhžžžŽŸª™¶Ä†ÆøžÑôÚÚÚÊåöàààëéåòóòÿÿÿ!ù*,´@•PUB@U ‹¦ €ÓáBÌa‘”I0>`‚”U¡¸—É A\ÈDSær©Õ@å’1Gt  #((t `  s‚`Ÿ|›t£Ž¨…Š™€´VtŒ%"À¾Á}%% ÉѾpwÔ ¾Y†« ƒ MD†%''ô)CA;tkabber-plugins/iconsets/gabber/services/aim_xa.gif000064400000000000000000000006121500237002100223310ustar00nobodynobodyGIF89aõ0 ?&1-22/%|0^'O+_Jl_+fffppo.–Ê:õJï9eòEtê€oƒ}ƒÌ“k2¼¹€‚K˜‚eÊ Gþ·GþûýÉfœ›žžž‘¢‡‘°¥¡œª¦Ÿ˜ø˜¦ý¦·õÞ݃úÓ·üóµÚÚÚÍÔþãàÌàààêèåóóóÿÿÿ!ù0,§@˜¦r}È…K5W€Ec „–â)b(t:'…À„…¹LG÷ÛCÈÄUäñpLÀñˆ¬ž% "# $. ŽŽ#š› )_–™¤  ¡™›š Š—£¥§(UµŒ ¯°(»~*¾¥¦  p¾¿ ËX )ÚÚ -B É,/CA;tkabber-plugins/iconsets/gabber/services/icq_away.gif000064400000000000000000000002071500237002100226700ustar00nobodynobodyGIF89aòĦ€€€ÀÀÀàààøüøÿÿÿ!ù,Lhª@+ÆFŸö…7ÀfÎSÛà|F³#`†ØêtÇd€@ïÈñ<[êäARb0Cv ªäò˜¢Íj²JxHÔ…ë„I.bj;tkabber-plugins/iconsets/gabber/services/icq_chat.gif000064400000000000000000000002071500237002100226460ustar00nobodynobodyGIF89aò€Ä¦ëºGàààÿÿÿ!ù,LXºÀ"ž{Ë5ZÅSWêTÒ4¼°¦\Ä6>`› ÿ²†Kg{@žœn$ ùvª é²›ò&¨ ÄšY>žiDk!ƒÂE;tkabber-plugins/iconsets/gabber/services/icq_dnd.gif000064400000000000000000000002161500237002100224740ustar00nobodynobodyGIF89aòf(-ĦÆjLàààÿÿÿ!ù,SXºÀ"ž{Ë5ZÅÓÅyB¥LUê(Á0ijy:1!z€m,™N7Óœ(4âª$y²åe’Ûõ.Àà,jÜp+UÉÖ°|HäÌ×úeºåE;tkabber-plugins/iconsets/gabber/services/icq_offline.gif000064400000000000000000000001771500237002100233570ustar00nobodynobodyGIF89aòÆjLëºGàààÿÿÿ!ù,DHºÀž{Ë5ZÅÓÅyA¥LÝ8J_ˆbØ]Ú9N‚ðÂÓ7䨈†#Í‚DâFøje’Ñt²´W, ËÔª‹;tkabber-plugins/iconsets/gabber/services/icq_online.gif000064400000000000000000000001771500237002100232210ustar00nobodynobodyGIF89aòĦëºGøüøÿÿÿ!ù,DHºÀž{Ë5ZÅÓÅyA¥LÝ8J_ˆbØ]Ú9N‚ðÂÓ7䨈†#Í‚DâFøje’Ñt²´W, ËÔª‹;tkabber-plugins/iconsets/gabber/services/icq_xa.gif000064400000000000000000000002061500237002100223360ustar00nobodynobodyGIF89aòĦÆjLàààøüøÿÿÿ!ù,KXºÀž{Ë5ZÅÓÅyA¥hªª:¼pü¦Ä4Ø÷m£uø†„Ú€²=Ä_n9IæŒÊ”l:´VX”B3étMbCÖd0…;tkabber-plugins/iconsets/gabber/services/jud.gif000064400000000000000000000001421500237002100216530ustar00nobodynobodyGIF89a¡ÿÔeÿßtÿÿÿ!ù,3œ©ÝËœSRj#½=ŸÃ]¥gÜveªpµ.O PÊ.AC¡>)ÑÏÇ@* ;tkabber-plugins/iconsets/gabber/services/msn_away.gif000064400000000000000000000002451500237002100227130ustar00nobodynobodyGIF89aó9Æ\âLìÒnn×;tkabber-plugins/iconsets/gabber/services/rss_chat.gif000064400000000000000000000003341500237002100227020ustar00nobodynobodyGIF89aô”’”œšœ¤¢¤¬ª¬´²´¼¾¼ÄÆÄÌÎÌÔÖÔäâäìêìôöôüúüüþüÿÿÿ!ù,Y $ŽÁhžb %zA°n*…q lk³À.¡X0|XîÀ*_K1°h Ñh}é¤,F£KúndÒŽµ¨:×a‘õF¦ÎÆ^c|5w€v}…!;tkabber-plugins/iconsets/gabber/services/rss_dnd.gif000064400000000000000000000003341500237002100225300ustar00nobodynobodyGIF89aô”|jœ‚p¤‰v¬{´—¼¡‡Ä¨Ì®’Ôµ˜ä¿¤ìÆ©ôЯüÔµü×µÿÿÿ!ù,Y $ŽÁhžb %zA°n*…q lk³À.¡X0|XîÀ*_K1°h Ñh}é¤,F£KúndÒŽµ¨:×a‘õF¦ÎÆ^c|5w€v}…!;tkabber-plugins/iconsets/gabber/services/rss_offline.gif000064400000000000000000000002471500237002100234100ustar00nobodynobodyGIF89aóA@AHGHPNPXVX`^`hjhqsqz}z„†„–”–žœž§©§®¬®®°®ÿÿÿ!ù,TðÉ ¦½PñÂ0p^ Da\g#°"‰²¸˜\}»  `à`Ífü¨„œ£Iy.oTÊŠ£(6ÇYóÅe>Æ\âLìÒnn×;tkabber-plugins/iconsets/gabber/services/rss_online.gif000064400000000000000000000003341500237002100232470ustar00nobodynobodyGIF89aô”’”œšœ¤¢¤¬ª¬´²´¼¾¼ÄÆÄÌÎÌÔÖÔäâäìêìôöôüúüüþüÿÿÿ!ù,Y $ŽÁhžb %zA°n*…q lk³À.¡X0|XîÀ*_K1°h Ñh}é¤,F£KúndÒŽµ¨:×a‘õF¦ÎÆ^c|5w€v}…!;tkabber-plugins/iconsets/gabber/services/rss_xa.gif000064400000000000000000000002471500237002100223760ustar00nobodynobodyGIF89aóA@AHGHPNPXVX`^`hjhqsqz}z„†„–”–žœž§©§®¬®®°®ÿÿÿ!ù,TðÉ ¦½PñÂ0p^ Da\g#°"‰²¸˜\}»  `à`Ífü¨„œ£Iy.oTÊŠ£(6ÇYóÅe>Æ\âLìÒnn×;tkabber-plugins/iconsets/gabber/services/sms.gif000064400000000000000000000003361500237002100217000ustar00nobodynobodyGIF89aô***?.03*U*U*_UU?UUU?UU_EFEUQPdddpuwªŸªª¿ÔŸÔ¿ëºGŠŠœ¥œ¨ »¿¦¿©°ÂůÆÀÜÀÿÿÿ!ù,[à'Ž£@ž¨‰ž†(+ Ä"Ò¢ã€A‚0 €ž‹’r‹*Ê‹¥¹2X¢Lœk ÇR ¢gQ­Ð &b>0N§Q'n+](!;tkabber-plugins/iconsets/gabber/services/yahoo_away.gif000064400000000000000000000005241500237002100232350ustar00nobodynobodyGIF89aõ!^l))GGGŸD-·‰½Ž!Å–&Æ—'È™)Ê›*Ñ¡/Ó£1×§5Úª8Þ®;ä´Aê¹FëºGì»Hð¿MõÄSùÈWÿÏ_ÿÑaÿÔeÿ×iÿÛnÿßtÿáwÿä{¡ÒíÿÿÑÿÿÿ!ù!,qÀpH,H!0$CK &iÎfc±<Î"@Óy2 J#<s>&ðY(ØPÌÔ‘c$ xƒ ˆxP —F –˜J£—«DKVOµ¶DA;tkabber-plugins/iconsets/gabber/services/yahoo_chat.gif000064400000000000000000000005241500237002100232130ustar00nobodynobodyGIF89aõ!^l))GGGŸD-·‰½Ž!Å–&Æ—'È™)Ê›*Ñ¡/Ó£1×§5Úª8Þ®;ä´Aê¹FëºGì»Hð¿MõÄSùÈWÿÏ_ÿÑaÿÔeÿ×iÿÛnÿßtÿáwÿä{¡ÒíÿÿÑÿÿÿ!ù!,qÀpH,H!0$CK &iÎfc±<Î"@Óy2 J#<s>&ðY(ØPÌÔ‘c$ xƒ ˆxP —F –˜J£—«DKVOµ¶DA;tkabber-plugins/iconsets/gabber/services/yahoo_dnd.gif000064400000000000000000000005241500237002100230410ustar00nobodynobodyGIF89aõ!^l))GGGŸD-·‰½Ž!Å–&Æ—'È™)Ê›*Ñ¡/Ó£1×§5Úª8Þ®;ä´Aê¹FëºGì»Hð¿MõÄSùÈWÿÏ_ÿÑaÿÔeÿ×iÿÛnÿßtÿáwÿä{¡ÒíÿÿÑÿÿÿ!ù!,qÀpH,H!0$CK &iÎfc±<Î"@Óy2 J#<s>&ðY(ØPÌÔ‘c$ xƒ ˆxP —F –˜J£—«DKVOµ¶DA;tkabber-plugins/iconsets/gabber/services/yahoo_offline.gif000064400000000000000000000005221500237002100237140ustar00nobodynobodyGIF89aõ"GGGGRTlcc}trƒ~t†‚y‹‡~ŒˆŽŠŒ„”‘‰–“‹™–Žœ™‘ž›“¤¡™©¦žª§Ÿ«¨ ®«£´±©·´¬½º²¾»³À½µÂ¿·ÃÀ¸ÅüÇžÉÇÀÊÍÏëëèÿÿÿ!ù",o@‘pH,Ha $EËMFiž‡s¹@Îb`ó }4¡Š#<w@Ofb,ØÐ 'ä‘g& xƒ ‡‰xP•F ”–J¡•©DKVO³´DA;tkabber-plugins/iconsets/gabber/services/yahoo_online.gif000064400000000000000000000005241500237002100235600ustar00nobodynobodyGIF89aõ!^l))GGGŸD-·‰½Ž!Å–&Æ—'È™)Ê›*Ñ¡/Ó£1×§5Úª8Þ®;ä´Aê¹FëºGì»Hð¿MõÄSùÈWÿÏ_ÿÑaÿÔeÿ×iÿÛnÿßtÿáwÿä{¡ÒíÿÿÑÿÿÿ!ù!,qÀpH,H!0$CK &iÎfc±<Î"@Óy2 J#<s>&ðY(ØPÌÔ‘c$ xƒ ˆxP —F –˜J£—«DKVOµ¶DA;tkabber-plugins/iconsets/gabber/services/yahoo_xa.gif000064400000000000000000000005241500237002100227040ustar00nobodynobodyGIF89aõ!^l))GGGŸD-·‰½Ž!Å–&Æ—'È™)Ê›*Ñ¡/Ó£1×§5Úª8Þ®;ä´Aê¹FëºGì»Hð¿MõÄSùÈWÿÏ_ÿÑaÿÔeÿ×iÿÛnÿßtÿáwÿä{¡ÒíÿÿÑÿÿÿ!ù!,qÀpH,H!0$CK &iÎfc±<Î"@Óy2 J#<s>&ðY(ØPÌÔ‘c$ xƒ ˆxP —F –˜J£—«DKVOµ¶DA;tkabber-plugins/iconsets/gabber/tkabber000075500000000000000000000000001500237002100201155ustar00nobodynobodytkabber-plugins/iconsets/gabber/tkabber/toolbar-add-user.gif000064400000000000000000000004301500237002100240240ustar00nobodynobodyGIF89a„ʤ)ײ9ܸ@éÈVóÙpøâ‚òÖkãÁLŠÀðdžà–ÊôSÑ?{Á"^œU‘ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,• $Ždižhª®ì ¼@k¾A¼²Bo ±Önð"‡Á@@( ƵcÂŽ§Ur €ƒVÚUm„ô ”SçžÀ@’p¶í6¸ ç70nW2mrM18Thiw‹ xf0# ”…/™–9 ™ ›p ¥©p/§Ÿ9: ±·%¨»¼²À$!;tkabber-plugins/iconsets/gabber/tkabber/toolbar-disco.gif000064400000000000000000000004141500237002100234230ustar00nobodynobodyGIF89a„Òq5E+Í‘ŠÓ‰ze-ÂttÕ—ˆBV6ʉ„ÖœPgAÇ€}J`€®é@¸0w T,ßIdhŠ^º‚A´ôež€æ‘z¬«‹{*i äI-ü*Yj™–ŒSÚÓ×13ý©_Zm ^~fƒŠ‹ŒŽ‹ ;tkabber-plugins/iconsets/gabber/tkabber/toolbar-show-offline.gif000064400000000000000000000006261500237002100247270ustar00nobodynobodyGIF89a¥ÿ×iÿÑaê¹Fä´AÿßtÿÛnùÈWÞ®;×§5ÿÿÑÿä{ÿÔeð¿MÑ¡/Ê›*ÿáwëºGÓ£1Å–&Úª8õÄS½Ž!www^^^XXXÈ™)ì»H·‰}}}oooRRRNNNÆ—'ÿÏ_µµµˆˆˆxxxdddGGGBBBƒƒƒ___III???°‚OOOiii;;;777ÌÌÌ```uuuQQQÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ?,³ÀŸpH,ȤRh–I@ç‚É<¡E©¬ãù€®ØŸvD*™N(0péŒRÕŠåT#O)îzvF(**} „Y ,5$Œ ’D(,& Ÿ 01 ª®Lu·ºb2324 !" ÂÄb6tM Ãa72W-РÞuâ…ÆÈæYÒÔa…ÜêGMîôõö÷øDA;tkabber-plugins/iconsets/gabber/tkabber/toolbar-show-online.gif000064400000000000000000000005261500237002100245700ustar00nobodynobodyGIF89a¥ÿ×iÿÑaê¹Fä´AÿßtÿÛnùÈWÞ®;×§5ÿÿÑÿä{ÿÔeð¿MÑ¡/Ê›*ÿáwëºGÓ£1Å–&HHH666Úª8õÄS½Ž!£££’’’ŽŽŽRRRÈ™)ì»H·‰§§§ŠŠŠ~~~Æ—'ÿÏ_ÍÍÍ®®®–––‚‚‚«««yyy}}}°‚€€€™™™zzzwwwÌÌÌ```‡‡‡¡¡¡ŸŸŸQQQ???ÀÀÀªªªÜÜÜÿÿÿ!ù ?,sÀŸpH,ȤrÉl:ŸÐ¨@H…€€`@°F³Ã‘ð:ÁŠ£áx˜™AD$“÷080ìzS„I5 $% ‹{ ŒW?.–pUTW343¥9:¤¥<3¡M¯œ¶·¸¶A;tkabber-plugins/iconsets/gush000075500000000000000000000000001500237002100162275ustar00nobodynobodytkabber-plugins/iconsets/gush/docking000075500000000000000000000000001500237002100176455ustar00nobodynobodytkabber-plugins/iconsets/gush/docking/tkabber.ico000064400000000000000000000510261500237002100220360ustar00nobodynobody°h¶hh† hîhVh¾°&"hÖ"h>( ¨¦- èN6 ¨69hÞAhFGh®L( ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(  &,?2F5L<$R3+Y¤D-[<0\ ” #ŽE0`:3a+ƒ:pG9iJ>n D~T?q1²Nˆ]Hz>²N®(Y–OºVÀgªj®vºqÐ}Àu؂ƎВ֙à¡äî®î©ø²ü¼ú»ø ÁþÄþÅþ,Çü&Îþ3Ðý?ÎýJÍþ}Øý†Ýþ–ßþ¤áþ´æþÂìþ;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;; ;;;;;;;;&+%;;;;;;+-''(";;;;; //!*/)-';;;; ,////////- ;;;015861///.$;;;15:::7////# ;;;,7:::9////;;;;;5:::6//1/;;;;;;6852101;;;;;;;;0340/;;;;;;;;;; ;;;;;þ?üüüøðààÀÀÀÀàðøü( #./4A7fXU^e[ciBjfelsErsF€eKhIw{F€oX|rK‡jH‚xH‚zQpR”qR”zT˜tT˜~YŸx\¦c©p¬‰u±x´€¸–Œ¾ ’¦ªÎ¹°Ò¿ºØÇÀÚÌÈàÒÑåÚÝëã------------------------------ ----------- ---------- -------------- -----!!   ---- """""""!---##'*(#""" ---#&,,,)""" --- ),,,+""" -----',,,'""# ------'*'####--------#$%# ---------- -----þ?üüüøðààÀÀÀÀàðøü(  &,?2F5L<$R3+Y¤D-[<0\ ” #ŽE0`:3a+ƒ:pG9iJ>n*³ D~T?q1²]Hz>²N®J¸(Y–gªj®vº}À‚ÆŽÐ’Ö™à¡ä©ø²ü¼ú»øÀþÃþÅþÉþ Çþ,Çü&Îþ3Ðý?ÎýJÍþyÙý†Ýþ–ßþ¤áþ´æþÆìþ8888888888888888888 8888888888888888888888 8888888888 88888888#&***"888888&**88888**%)$**8888 '********( 888-.253.***)!888.274*) 888'476*)8888827773*,,)888888352/.-.88888888-01-+8888888888 88888þ?üüüøðààÀÀÀÀàðøü(  &,?2F¤D-[ ™<0\ ” #Ž+ƒ*³ D~1²]Hz>²(Y–Oºgªj®}ÀuØ¡äî¼ú»ø ÁþÅþÈþ,Çü&Îþ3Ðý?ÎýJÍþ}Øý†Ýþ“Þý¤åþ´æþÆìþ(((((((((((((((((( (((((((( ((((((( ((((((  '''' ((((( '''' (((( (((( ((((((("%# ((( "'''$((($'''&((((("'''#((((((#%"(((((((( !((((((((((  (((((þüüüøðààÀÀÀÀàðøü( JJJNTPEm_BjfEqsGyhKhIw{X|rK‡jH‚zR”qR|T˜tS—}\¤|dªƒp¬‰u±€¸–½§§Œ¾ ’¦ҵ·Ø½½Ò¾ªÎ¹°Ò¿ÛÉÇãÍ̺ØÇÀÚÌêÔÔÈàÒîÙØõÝÛÑåÚáààéâáóáàÝëãúæäüëéÿñïÿùöÿÿÿ....+-%+&.#-----"+,-. +-----'"----.--------,".---")*,+...-"-  ....- .... ... ! ... ((( ...((($..... ((( ...... !........  .......... .....€€€ÀÀÀÀÀàðøü( /.0546===DCEGFHLNPPRTX[\]bc`efekkhnnmsstzyz€‚ˆˆˆŽŽŒ’‘¡¡¡¥¥¥©©ª®®°´´¶ºº¼À¿                þ?üüüøðààÀÀÀÀàðøü( þ?üüüø÷÷ïûïûÏùßýÏùïûïû÷÷ûïü( *U*€U*>*ªUUU?*?UªU?U?UªU?U_UUÔU?ªª_UU_UUª_U_ªªUUU_Ôª………UªUÔªŸUŸª¤  UÿªŸªÿŸªU¿ªª¿ªÿŸÔªŸÿª¿Ôðʦÿ¿Ôª¿ÿÀÜÀªßÔUßÿªßÿÿÿªÿÔUÿÿªÿÿõüÿ! -! #!+  #5!#  -!))5! ( .54 ,,,( #4).&((((245!(("!%3  0! 531%55!%1/#4$'-+&&45)+# -!-! 5*!5+!#55-+ -þÀ€€€€€€€€€Àâöÿ( Uÿÿ*U>*ÿ*ÿUU?UUÿÿ?UU_Uªÿÿ?Uÿÿ_UUU?ÿU_ªÿ__ÿ………ÿU_ÿª_ÿÿÿªªÿŸÿÿŸªªŸÔUŸÿÿŸÔªŸÿU¿ÿª¿ÿÿßÔªßÿðûÿ         "" "" ##%"##%!& $ & üø?À€€€€€€„ÂÇçÏ( @9N>UAZIe!Li#Pn%Vx(]€*bˆ.k•.q3y§1}±<€­:…·;ŒÃDÃ=‘ÈD”Ê;™×CšÕJ¢Ü>¤êG¦åR¬çB«ñI°ïZ´îY¹ú`¿ÿÿÿÿ                                  ( @'¢É<´ÙA¹ÝhÔñÿÿÿUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUPUUUUUUUUUUU3330UUUUUUUUUUPUUUUUUUUUPUUUUUUUUUP14DCUUUUUUUUUPD3D1UUUUUUUUUP3@41UUUUUUUUUP1@DUUUUUUUUUUUUUUUUUUUUUUUUUP333UUUUUU0UUUUUPCUUUUUPD!3AUUUUUPDD4@0D0UUUUUP2@D@!0AUUUUUP@D@3D0UUUUUUDD4@#$0UUUUUUP##1P2UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU( @!)' 3:<2ADK3p);kF4oNAS5>e 0’AoV% %4ŽÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇ& 4ŠÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇ( 's§ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇj;+CGKPS! 0O#"-/258AFFLORT5P157<>BEHM! .I#"+-/2489?C%$(*;@'&((),-0369ððÀÀÀÀÀÀÀÀÀÀÀÀÀÀ( GGGIIIJJJKLKLLLMMMNNNOONOOOOOPPPPQQQQQRRRRRSRSSSTTTUUUVVVWWWXXXZYZZZZ\[\]\\]\]]]]^^__`_```bbbbbcedeeffghhihijjjkkkmmmŠÿŽÿÿ“ÿ”ÿ–ÿ—ÿšÿœÿŸÿ¡ÿ£ÿ¤ÿ¥ÿ§ÿ¨ÿªÿ«ÿ­ÿ®ÿ¯ÿ°ÿ²ÿ³ÿ´ÿµÿ¶ÿ¸ÿ¹ÿ»ÿ¼ÿ¾ÿÀÿÁÿÂÿÄÿÅÿÆÿÇÿÈÿÊÿËÿÍÿÎÿÐÿÒÿÔÿÖÿÙÿÚÿÛÿÞÿßÿàÿãÿäÿæÿçÿèÿìÿíÿñÿ  RUWZ\_bde MQTVX[^acI`EHKORUWZ]@YBE%$*,=A'&()+.0258;ððÀÀÀÀÀÀÀÀÀÀÀÀÀÀtkabber-plugins/iconsets/gush/icondef.xml000064400000000000000000000055751500237002100204530ustar00nobodynobody Gush 1.0 Tkabber's Gush Iconset. 2006-01-21 toolbar/add-user tkabber/toolbar-add-user.gif toolbar/disco tkabber/toolbar-disco.gif toolbar/join-conference tkabber/toolbar-join-conference.gif toolbar/show-offline tkabber/toolbar-show-offline.gif toolbar/show-online tkabber/toolbar-show-online.gif browser/client roster/available.gif browser/user roster/available.gif docking/tkabber docking/tkabber.ico roster/user/chat roster/available-chat.gif roster/user/available roster/available.gif roster/user/away roster/available-away.gif roster/user/xa roster/available-xa.gif roster/user/dnd roster/available-dnd.gif roster/user/invisible roster/invisible.gif roster/user/unavailable roster/unavailable.gif roster/user/unsubscribed roster/stalker.gif roster/user/error roster/unavailable.gif roster/group/closed roster/group-closed.gif roster/group/opened roster/group-opened.gif tkabber-plugins/iconsets/gush/roster000075500000000000000000000000001500237002100175455ustar00nobodynobodytkabber-plugins/iconsets/gush/roster/available-away.gif000064400000000000000000000011011500237002100231630ustar00nobodynobodyGIF89aÆZ#.A4/B62G<7MB;PGBXOJXSHZTL]SMV_?_ZOd[TXf>e^Uic[_mEfjBkd]npDslesrEusEe€FhK{wIo€Fp€Fr|Xj‡Kv‚Hx‚Hz‚Hw†J~ƒIw‡KnŽNpQxŠLq”Rz”Rt˜T}—S~˜TxWxŸY|¤\{¦\¦\¦\©cƒ¨bƒªd‚ªh†¬l‡­m‰¬p‡®p‰®pНq‰°rŒ°t±u޲v³w´x‘´z‘µ{“·}•·–¸€š¹ƒ˜º„ ¾Œ¦Â’¹Îª¼Ò®¿Ò°¿Ó±ÁÔ´ÄÖ¶ÇØºÊÚ¾ÌÚÀÒàÈÓàÈÚåÑâêÚãëÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,ž€‚ƒ ƒŠƒHJKH=‹ŒPUOIGGD”NYXXQ@AC;“„9T¢XW@¥<Š!GL­S°@;(ƒ FEMVRGº:*#ƒ9Bºº?6Š&?>,5<4+7/‹382""10%©Š.3')$-ì‹  ”Š 0xPàŸ¢&4`pÐ h8(€‰‹;tkabber-plugins/iconsets/gush/roster/available-chat.gif000064400000000000000000000011001500237002100231400ustar00nobodynobodyGIF89aÆ_ &?,A.F2L5R$J³*~D q?T²1²:ˆNzH]²>²?®J®N¸J–Y(ºOÀVªg®jºv¼wÐqÔsÀ}ØuƂЎ֒à™ä¡îî¢ì§î®ø©ü²ú¼ø»ø»þÀþÁþÁ þÂþÃþÃþÄþÅþÅþÈþÆþÆþÉþÇ üÇ,ýÆ1ýÊ-þÍ"þÎ&ýÐ3ýÎ?þÍJýØ}ýÙyþÛpýÞþ݆þÜŒþß‚ýÞ“þß–þá¤þå¤þæ´þéÂþìÂþìÆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,€‚ƒ ƒŠƒINOIF‹ŒVZSMJJK!”P^\]TBDG>“„9X][B­?$ŠJR­]W±=- ƒHLQYUJBÉC.ƒ 8EÉÒBA:' Š*AB6?5±B‹7±  Ü,©Š0æÉ/&í‹ %”ŠL(àOQ€ $ (8(0€ÄE;tkabber-plugins/iconsets/gush/roster/available-dnd.gif000064400000000000000000000010651500237002100230000ustar00nobodynobodyGIF89aÆ_ &?,A.F2L5R$J³*~D q?T²1²:ˆNzH]²>²?®J®N¸J–Y(ºOÀVªg®jºv¼wÐqÔsÀ}ØuƂЎ֒à™ä¡îî¢ì§î®ø©ü²ú¼ø»ø»þÀþÁþÁ þÂþÃþÃþÄþÅþÅþÈþÆþÆþÉþÇ üÇ,ýÆ1ýÊ-þÍ"þÎ&ýÐ3ýÎ?þÍJýØ}ýÙyþÛpýÞþ݆þÜŒþß‚ýÞ“þß–þá¤þå¤þæ´þéÂþìÂþìÆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,’€‚ƒ ƒŠƒINOIF‹ŒVZSMJJK!”P^\]TBDG>“„9X¢][B¥?$ŠJR]¸W°B=- ƒHLQYUJ»C.ƒ 8E°C% Ó ‹*A@+" ÞÓŠ7<1ÝßÞ¿â07Ý^ï^à” îðò”çèê‹ûÀõS”@já(  á¢@;tkabber-plugins/iconsets/gush/roster/available-xa.gif000064400000000000000000000011331500237002100226370ustar00nobodynobodyGIF89aÆcJJJKKJKMJLMKNOJMPKNPLPTN_mEfjBnpDsqEhyGusEhK{wIt}Fr|Xu€Hj‡Kv‚Hx‚HwƒJz‚H~ƒIq”R|Rt˜T}—S|¤\ƒ¨bƒªd‚ªh†¬l‰¬p‡®p‰®pНq‰°r±u޲v³w‘´z‘µ{“·}•·–¸€§§½š¹ƒ˜º„©©À ¾Œ¦Â’³´Ð·µÒ··Ë·¶Ò½½Ø¾ÂҹΪ¼Ò®¿Ò°¿Ó±ÇÉÛÁÔ´ÉÉåÄÖ¶ËËâËÌäÌÍãÇØºÏÏæÊÚ¾ÌÚÀÔÔêÒàÈÓàÈרîרïØÙîÙÛïÛÜíÛÝõÚåÑààááâéàáóâêÚãëÝäæúéëüìíÿîðüïñÿñòüòõÿöùÿ÷úÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,¸€‚ƒ  ƒŠƒ0340&‹Œ@K>1..+”=XWWB()*$“„"I¢WS(¥%Š.;­H°($ ƒ-,J³*~D q?T²1²:ˆNzH]²>²?®J®N¸J–Y(ºOÀVªg®jºv¼wÐqÔsÀ}ØuƂЎ֒à™ä¡îî¢ì§î®ø©ü²ú¼ø»ø»þÀþÁþÁ þÂþÃþÃþÄþÅþÅþÈþÆþÆþÉþÇ üÇ,ýÆ1ýÊ-þÍ"þÎ&ýÐ3ýÎ?þÍJýØ}ýÙyþÛpýÞþ݆þÜŒþß‚ýÞ“þß–þá¤þå¤þæ´þéÂþìÂþìÆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,Ÿ€‚ƒ ƒŠƒINOIF‹ŒVZSMJJK!”P^\]TBDG>“„9X¢][B¥?$ŠJR]¸W°B=- ƒHLQYUJ»C.ƒ 8E»»A:' Š*A@+6?5);3‹7<1  24,©Š07#("/&í‹ %”ŠPx0¡@E6\0àà àpP;tkabber-plugins/iconsets/gush/roster/available2.gif000064400000000000000000000011051500237002100223120ustar00nobodynobodyGIF89aÆh )))+++000644;;;DDDGF7JG:IG=IGGKKANL#‰ BE;&$&=?6 ŠJ³*~D q?T²1²:ˆNzH]²>²?®J®N¸J–Y(ºOÀVªg®jºv¼wÐqÔsÀ}ØuƂЎ֒à™ä¡îî¢ì§î®ø©ü²ú¼ø»ø»þÀþÁþÁ þÂþÃþÃþÄþÅþÅþÈþÆþÆþÉþÇ üÇ,ýÆ1ýÊ-þÍ"þÎ&ýÐ3ýÎ?þÍJýØ}ýÙyþÛpýÞþ݆þÜŒþß‚ýÞ“þß–þá¤þå¤þæ´þéÂþìÂþìÆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,`€‚ƒ ƒŠƒ‹‹‚‹!ŒŠ‰ƒœ$Š‚Ÿ¤ ƒ—Ч ¬‚' Š*±ޱ’˜»Š %±ÇÎ ÎÏÚ‹;tkabber-plugins/iconsets/gush/roster/unavailable.gif000064400000000000000000000010761500237002100226020ustar00nobodynobodyGIF89aÆQ0./1/0645:89===CCADCBECDFEDFFDHFGIHGJIHMKILLJNLMOMKOMMPNLRRRTRPUTQTTTUUQWVSXVTWWSYXUZYVZZVZZX\[X[[[_^Y__[cb]cc]ed_fe`ff`iickkennhooissmttnuvpxysyysyztz{u||v}}w}~x~~xy€z{‚‚|‚ƒ}„„~„…††€ˆˆ‚‰‰ƒŽŽˆ‘’Œ  œ££Ÿ¤¤ ¥¥¡§§£¨¨¤««§®®ª´´°ºº¶¿À¼ÁÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,›€‚ƒ ƒŠƒACDA6‹ŒIMHB@@= ”GPOOJ9:<4“„3L¢ON9¥5Š@E­L°94&Œ?>FMK@º4)ƒ3;ºº80Š$87(/5.'1,‹.2---#©´+.!%*ë‹ ”Š&è§(€ ”@ â¢@;tkabber-plugins/iconsets/gush/tkabber000075500000000000000000000000001500237002100176415ustar00nobodynobodytkabber-plugins/iconsets/gush/tkabber/toolbar-add-user.gif000064400000000000000000000002031500237002100235460ustar00nobodynobodyGIF89aÂY„ÁEuÿÿÿ†Ëñÿÿÿÿÿÿÿÿÿÿÿÿ!ù,HHºÜþ0ÊI«½è0B8 Žcy¨*mš€’\Þ3î6ìì“¶ßoÇè SÁc+h6e-'ñaœ¾ Hˆ‘:=à°xI;tkabber-plugins/iconsets/gush/tkabber/toolbar-disco.gif000064400000000000000000000002311500237002100231440ustar00nobodynobodyGIF89a€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,^xºÜþ0ÊI«½ ©#Áö|!‚蜩9tŒ ¼.@È·2«Ù+ä¶ßfW; ã8¢)“ ¡sõA­Lª 'ÊöN@$púUÍÞ˜ó5“Õªv4½ÐðV0Œ~ÏïC;tkabber-plugins/iconsets/gush/tkabber/toolbar-join-conference.gif000064400000000000000000000006061500237002100251150ustar00nobodynobodyGIF89a¥ÔßÿU_Uÿûð€€€*?UUU?Uª_UUUÿ¿ªÿߪÿŸªÿŸUÿªÿ_ªÿ¿UÔŸªªŸÿÔŸÿªÿ_ÿÿ_UÿUÿÔU*ÿÿªÿÿ?Uÿÿ?UÿŸÿ_U_ÿ?ÿÿUU?ÿ*ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ?,£ÀŸpH,ȤrÉl2€"Ô ¢BÀàÚ Q(ÀpÀ*ˆDx P˜“€£á€ÊÈû—G¼P y{R…Rˆ’DuŒž œ!K"#$%¥&^p¸¹''±&¿ÁÂH¸¬'(ÉOb±SNY(ਵÝÞåæçèéA;tkabber-plugins/iconsets/gush/tkabber/toolbar-show-offline.gif000064400000000000000000000007041500237002100244500ustar00nobodynobodyGIF89a¥8ÿ×iÿÑaê¹Fä´AÿßtÿÛnùÈWÞ®;×§5ÿÿÑÿä{ÿÔeð¿MÑ¡/Ê›*ÿáwëºGÓ£1Å–&Úª8õÄS½Ž!www^^^XXXÈ™)ì»H·‰}}}oooRRRNNNÆ—'ÿÏ_µµµˆˆˆxxxdddGGGBBBƒƒƒ___III???°‚OOOiii;;;777ÌÌÌ```uuuQQQÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ?,áÀŸpH,Ȥò÷9eVŸ%2Cª’:i13ê’R)YVûãÞΣNGV/?¥Ñù–V·µ™”­î”Z,€-Iyz])}-ƒG %}”- — Fj&%- § ªG- §§ª¬­/±4Š·©ªE''Š—¹ÆI1+,¹Û€Õ - ´êJ(1'-õêÇG1?-ÞêM¨GfŠzõX°(HÄÚ 1@#D‰ßÁè‡Q?ŽCJ ;tkabber-plugins/iconsets/gush/tkabber/toolbar-show-online.gif000064400000000000000000000005531500237002100243140ustar00nobodynobodyGIF89a¥8ÿ×iÿÑaê¹Fä´AÿßtÿÛnùÈWÞ®;×§5ÿÿÑÿä{ÿÔeð¿MÑ¡/Ê›*ÿáwëºGÓ£1Å–&Úª8õÄS½Ž!www^^^XXXÈ™)ì»H·‰}}}oooRRRNNNÆ—'ÿÏ_µµµˆˆˆxxxdddGGGBBBƒƒƒ___III???°‚OOOiii;;;777ÌÌÌ```uuuQQQÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ?,ˆÀŸpH,ȤrÉl:‹-V´õ$¶6•Æ@­¶àÆfé6[…z1hsψ…Zݼ™WÜÝFXÌIW`uL,uQg -˜N™- ˜€K-  U?(  ,,¬B1' 1³B4¸º­1'0À?ÈÆÊËÌÍÆA;tkabber-plugins/iconsets/iconsets.tcl000064400000000000000000000026301500237002100176740ustar00nobodynobody# iconsets.tcl -- # # Several iconsets, borrowed from other Jabber clients. package require msgcat namespace eval iconsets { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered iconsets]} { ::plugins::register iconsets \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Iconsets\ plugin is loaded."] \ -loadcommand \ [namespace code \ [list load [file dirname [info script]]]] \ -unloadcommand [namespace code unload] return } } proc iconsets::load {dirname} { set ::pixmaps::theme_dirs \ [concat $::pixmaps::theme_dirs \ [glob -nocomplain -directory $dirname *]] ::pixmaps::load_themes ::pixmaps::init_custom ::pixmaps::load_stored_theme } proc iconsets::unload {} { set ::pixmaps::theme_dirs \ [concat [glob -nocomplain -directory \ [file join $::configdir pixmaps] *] \ [glob -nocomplain -directory [fullpath pixmaps] *]] ::pixmaps::load_themes ::pixmaps::init_custom ::pixmaps::load_stored_theme } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/iconsets/icq000075500000000000000000000000001500237002100160355ustar00nobodynobodytkabber-plugins/iconsets/icq/docking000075500000000000000000000000001500237002100174535ustar00nobodynobodytkabber-plugins/iconsets/icq/docking/available-away.gif000064400000000000000000000002041500237002100230740ustar00nobodynobodyGIF89aÂøüøüÀÀÀ€€€ÿÿÿÿÿÿÿÿÿ!ù ,Ixª+ÆFŸö‰7ÀfÎÛà|G³©€bkÌ“Ĭ; ·ïµ”ë·ƒ¤D`føë@XDç)£iPÇ”U…JEÉÑh[$;tkabber-plugins/iconsets/icq/docking/available-chat.gif000064400000000000000000000001751500237002100230610ustar00nobodynobodyGIF89a€€ÿÿÿÿÿ€€€ÿÿÿÿÿÿÿÿÿ!ù ,BxºÜ 0Bƒ7OþÙÝ \Uè‚¡‘ʨk¥¨3Éó 88BŽGiaŽŽ¥Ð*r£­&;tkabber-plugins/iconsets/icq/docking/available-dnd.gif000064400000000000000000000002161500237002100227030ustar00nobodynobodyGIF89aÂøüøü€øÿÿÿÿÿÿÿÿÿ!ù ,SxºÀ ž{Ë5ZÅÓÅyB¥LÕ0ê(Aijy:q ú€m,™N7Óœ(4âª$y²åe’Ûõ.Àà,jÜp+UÉÖ°|HäÌ×úeºåE;tkabber-plugins/iconsets/icq/docking/available-xa.gif000064400000000000000000000002011500237002100225400ustar00nobodynobodyGIF89aÂøüøüøÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,FHºÀ ž{Ë5ZÅÓÅyB¥ hªª¼pü¦ÁTáízvøN»ZOè Þ†7£ï–tÉž¨ÖjmX>$$gF. !;tkabber-plugins/iconsets/icq/docking/available.gif000064400000000000000000000001771500237002100221460ustar00nobodynobodyGIF89aÂøüøüøüÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,DHºÀ ž{Ë5ZÅÓÅyB¥LÝ8J_ˆbØ]Ú9NÃðÂÓ䨈†#Í‚DâFøje’Ñt²´W, ËÔª‹;tkabber-plugins/iconsets/icq/docking/invisible.gif000064400000000000000000000001771500237002100222120ustar00nobodynobodyGIF89a”””ßßßúúúÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,DxºÀž{Ë5ZÅÓÅyA¥LÝ8J_ˆbØ]Ú9N‚ðÂÓ7䨈†#Í‚DâFøje’Ñt²´W, ËÔª‹;tkabber-plugins/iconsets/icq/docking/unavailable.gif000064400000000000000000000001771500237002100225110ustar00nobodynobodyGIF89aÂøüøøøüÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,DHºÀ ž{Ë5ZÅÓÅyB¥LÝ8J_ˆbØ]Ú9NÃðÂÓ䨈†#Í‚DâFøje’Ñt²´W, ËÔª‹;tkabber-plugins/iconsets/icq/icondef.xml000064400000000000000000000061441500237002100202520ustar00nobodynobody ICQ 1.0 Tkabber's ICQ Iconset. 2006-01-20 toolbar/add-user tkabber/toolbar-add-user.gif toolbar/disco tkabber/toolbar-disco.gif toolbar/join-conference tkabber/toolbar-join-conference.gif toolbar/show-offline tkabber/toolbar-show-offline.gif toolbar/show-online tkabber/toolbar-show-online.gif docking/chat docking/available-chat.gif docking/available docking/available.gif docking/away docking/available-away.gif docking/xa docking/available-xa.gif docking/dnd docking/available-dnd.gif docking/invisible docking/invisible.gif docking/unavailable docking/unavailable.gif roster/user/chat roster/available-chat.gif roster/user/available roster/available.gif roster/user/away roster/available-away.gif roster/user/xa roster/available-xa.gif roster/user/dnd roster/available-dnd.gif roster/user/invisible roster/invisible.gif roster/user/unavailable roster/unavailable.gif roster/user/unsubscribed roster/stalker.gif roster/user/error roster/unavailable.gif tkabber-plugins/iconsets/icq/roster000075500000000000000000000000001500237002100173535ustar00nobodynobodytkabber-plugins/iconsets/icq/roster/available-away.gif000064400000000000000000000002041500237002100227740ustar00nobodynobodyGIF89aÂøüøüÀÀÀ€€€ÿÿÿÿÿÿÿÿÿ!ù ,Ixª+ÆFŸö‰7ÀfÎÛà|G³©€bkÌ“Ĭ; ·ïµ”ë·ƒ¤D`føë@XDç)£iPÇ”U…JEÉÑh[$;tkabber-plugins/iconsets/icq/roster/available-chat.gif000064400000000000000000000001751500237002100227610ustar00nobodynobodyGIF89a€€ÿÿÿÿÿ€€€ÿÿÿÿÿÿÿÿÿ!ù ,BxºÜ 0Bƒ7OþÙÝ \Uè‚¡‘ʨk¥¨3Éó 88BŽGiaŽŽ¥Ð*r£­&;tkabber-plugins/iconsets/icq/roster/available-dnd.gif000064400000000000000000000002161500237002100226030ustar00nobodynobodyGIF89aÂøüøü€øÿÿÿÿÿÿÿÿÿ!ù ,SxºÀ ž{Ë5ZÅÓÅyB¥LÕ0ê(Aijy:q ú€m,™N7Óœ(4âª$y²åe’Ûõ.Àà,jÜp+UÉÖ°|HäÌ×úeºåE;tkabber-plugins/iconsets/icq/roster/available-xa.gif000064400000000000000000000002011500237002100224400ustar00nobodynobodyGIF89aÂøüøüøÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,FHºÀ ž{Ë5ZÅÓÅyB¥ hªª¼pü¦ÁTáízvøN»ZOè Þ†7£ï–tÉž¨ÖjmX>$$gF. !;tkabber-plugins/iconsets/icq/roster/available.gif000064400000000000000000000001771500237002100220460ustar00nobodynobodyGIF89aÂøüøüøüÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,DHºÀ ž{Ë5ZÅÓÅyB¥LÝ8J_ˆbØ]Ú9NÃðÂÓ䨈†#Í‚DâFøje’Ñt²´W, ËÔª‹;tkabber-plugins/iconsets/icq/roster/invisible.gif000064400000000000000000000001771500237002100221120ustar00nobodynobodyGIF89a”””ßßßúúúÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,DxºÀž{Ë5ZÅÓÅyA¥LÝ8J_ˆbØ]Ú9N‚ðÂÓ7䨈†#Í‚DâFøje’Ñt²´W, ËÔª‹;tkabber-plugins/iconsets/icq/roster/message.gif000064400000000000000000000002301500237002100215400ustar00nobodynobodyGIF89a üø€€€øüøüøø€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,Eɉ€¥xÚr¶B‡Y$É•ä@+@ËZkœ½ZªNÊ®˜n(ã•v¨` H,-ΟTÈdòª– ÍP`°gLG;tkabber-plugins/iconsets/icq/roster/send.gif000064400000000000000000000002301500237002100210450ustar00nobodynobodyGIF89a üø€€€øüøüøø€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,Eɉ€¥xÚr¶B‡Y$É•ä@+@ËZkœ½ZªNÊ®˜n(ã•v¨` H,-ΟTÈdòª– ÍP`°gLG;tkabber-plugins/iconsets/icq/roster/stalker.gif000064400000000000000000000001771500237002100215730ustar00nobodynobodyGIF89aÂøüø#píÑ%èÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,DHºÀ ž{Ë5ZÅÓÅyB¥LÝ8J_ˆbØ]Ú9NÃðÂÓ䨈†#Í‚DâFøje’Ñt²´W, ËÔª‹;tkabber-plugins/iconsets/icq/roster/unavailable.gif000064400000000000000000000001771500237002100224110ustar00nobodynobodyGIF89aÂøüøøøüÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,DHºÀ ž{Ë5ZÅÓÅyB¥LÝ8J_ˆbØ]Ú9NÃðÂÓ䨈†#Í‚DâFøje’Ñt²´W, ËÔª‹;tkabber-plugins/iconsets/icq/tkabber000075500000000000000000000000001500237002100174475ustar00nobodynobodytkabber-plugins/iconsets/icq/tkabber/toolbar-add-user.gif000064400000000000000000000011661500237002100233650ustar00nobodynobodyGIF89aÆœ ŠÄÅŒÎÎ’³´ƒ‡Šq¾Â§óó¥öö àà™¨©}Éɶùù½üü¡ì윭¯~ÅÆ²õõ·øø ç盪¬ª°šØÙ™ÝÞ˜ÇÉ’–š€Ž“‹²´—ÃĤ¦z…r ”››ÀÄÀììËöö°àà—­°‡†y¶»¹ëëÑúú´øøŸÞÞ—¢¤zÇÈÁööÔûû¯!*%ÇËÈi“¹U„¸$ÇËÆööÑ­®~x¥ÌV‹Â#É̽ùùÆéêš‘“ku¤ÍTŠÃ&9 Ãîðð¼ôôªôôžóóžÑÒŒg‘·~®Øz«Ö^˜ÔOŠÌ8o®1g¤O‚›¹¹†¾¿ˆº»‡¢£yMw¥Y‰¿O‚¹NˆÉ=xº#XMCr6i¥%[•%/b›S‹ HvIyÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,Ó€‚ƒ„…†‡ˆ‰Š‹Œ…†’„ 𛂠£¤¬›´µ¼½¤ƒ¿‹ !"#$%&'¤()* +,-ʉ./0 ©«‚12Œ3â䪚4567Ë89ã©:š;<=>Ë?€à "Ò"EŒù†$‰’%LšpòJ)S¨T±‚èÃ,Y²hÙ€K/_À„3†LG_0”1sæÃa‚ФQã§ 5lÚpôùs ÑE;tkabber-plugins/iconsets/icq/tkabber/toolbar-disco.gif000064400000000000000000000010401500237002100227510ustar00nobodynobodyGIF89a ¥ú¹YÕšCÊ”Dï°I•k.ˆb*eIU>·…:ý³GàŸ@­€<ñ«B–m0xV%ê¤>ÿÁcç¬R§y3iL!q.ÃDZAÜ¢JÃŒ;å¦GÈ‘=ÿ¿`nP#×™;øüøüšp2€](î´Z±}1øü¡r.N9ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù?, þÀŸpH,H#  ’Pc€P0É„":\¿†ãQ„D’‰ƒ"©$’Ëå PˆDA‚q8.ScH?? t~o GO‹ Œ?q!CGœŒ¥¡  ¡X?oG Œ¡~³"d?PÅ Œ¡ Ô#ˆ$#\ÓÕ†¿U`HÄä ¦º? IÓ¨+QBž Í~H8'í®nr@Á/iñVQH ˜‘¼„0P@¼dä>pˆ A‘ (#èB>…b62ºÐáÀ 5" hÐʇ'ˆ`J^TÐ`§‘$Ì!R¬jÙF\F¢b*­Û·pãÊ};tkabber-plugins/iconsets/icq/tkabber/toolbar-join-conference.gif000064400000000000000000000011751500237002100247250ustar00nobodynobodyGIF89aÆœ ŠÄÅŒÎÎ’³´ƒ‡Šq¾Â§óó¥öö àà™¨©}Éɶùù½üü¡ì윭¯~ÅÆ²õõ·øø ç盪¬ª°šØÙ™ÝÞ˜ÇÉ’–š€Ž“‹²´—ÃĤ¦z…r ”››ÀÄÀììËöö°àà—­°‡†y¶»¹ëëÑúú´øøŸÞÞ—¢¤zÇÈÁööÔûû¯ÇËÈÇËÆööÑ­®~É̽ùùÆéêš‘“k««¦÷÷Ïûû¹ÔÕ”ââÎêêžu•˜‡ÉÉ‘¼¾‹Š‹kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,Ú€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘‘„’“‰‚˜šœžˆ £¥§©£‡ «²´¶—«¼¾À—«ÆÈÊŠ•¯•‹Ð”Ó—«ÙÛ݈ !"#$%&'ãåçé'‡()* +,-òôöøÑƒ\¼€Ñ —> Æ‹1°`-} >Œ'c†Dú*^ü¯†„7pèóGCrèØQ°H=Xôñãd¡@‚ðØDH$!;y±I责Ј>ZÊ´)¢@;tkabber-plugins/iconsets/icq/tkabber/toolbar-show-offline.gif000064400000000000000000000003051500237002100242530ustar00nobodynobodyGIF89aÂøüøüøü#píøÿÿÿÿÿÿ!ù ,ŠxºÜþPëAÐIí™_¦MYaœH š…ªê…ðj>\:æwƒ¾°Áà¤R@Ü90HÞr5*˜x@l®`½‘*b Ãíag[ÐõI‰TŽû›C×'Ö4z”Ée^v}{`eW„{ZE>ƒ$xdO)vl$\m ”šœ?£3¤z=¦ ;tkabber-plugins/iconsets/icq/tkabber/toolbar-show-online.gif000064400000000000000000000003121500237002100241130ustar00nobodynobodyGIF89aÂøüøüøüøÀÀÀÿÿÿÿÿÿ!ù ,xºÜþPëAÐIí™_¦MYaœH š…ªê…ðjžéÈø ƒÏ"•@Ÿ®Ahv¤ oÒR4•Ê©Ù0ËVÂdoàÔ¹,Ò èpJ¨5Çík’Þ _¤±EFEX€~`„ˆˆWˆ}VN‡Xp7 tS„”'yƒ”c”23š{§¢•7« ;tkabber-plugins/iconsets/jajc000075500000000000000000000000001500237002100161705ustar00nobodynobodytkabber-plugins/iconsets/jajc/docking000075500000000000000000000000001500237002100176065ustar00nobodynobodytkabber-plugins/iconsets/jajc/docking/available-away.gif000064400000000000000000000006231500237002100232340ustar00nobodynobodyGIF89a¥»»»  ¤U_U*_UÀÜÀ*Uÿ€€€€Ô¿ªÿÿÿ*ÿÿÿÿªÔßÿßÿªU?U?UÔßUÿŸU€€ÿ¿ÿßÿÿªUÿ¿U*ªªÿŸÿ_€€Ô¿ÿU_ÔªÔŸÔ_ªŸª**?U*?ª_ÿ??_Uÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þCreated with The GIMP,Ÿ@€pH,ȤrÉl6‚¡`0œDB8,ƵÙ8…¢7#’É¡>´ÇJ¥b™C.v xItj L‘ M !¡™š"‘#$XC%‘&ªB%#§'±(#)*ª³§ +ÀNº§),ÁL-.§/ÆÉXP01¸áâãäFA;tkabber-plugins/iconsets/jajc/docking/available-chat.gif000064400000000000000000000006111500237002100232070ustar00nobodynobodyGIF89a¥»»»€€€U_U*?U*ÿÿ  ¤ÀÜÀÿþýªŸªÿÿ€€U?_UÿßUÔŸU?Ô¿ÿÿªÿŸÿßÿ¿ÿUÿ_*ªÔŸ_Ô?ª*ª¿ªÿ?*?U?U*_UÔ_U_*Uÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þCreated with The GIMP,•@€pH,ȤrÉl6‚€P(œÃ‘( ¾ˆkS@x«Õ…xÉh¼à…™éx@"g´š<& {tjkKŠŠ|‰XC‰B‹¤  !"#n N¶¸±$#M"%‹%²#¾X &'ª«×ØÙÚEA;tkabber-plugins/iconsets/jajc/docking/available-dnd.gif000064400000000000000000000005701500237002100230410ustar00nobodynobodyGIF89a¥»»»  ¤U_U*?Ô¿ªÿþý*ªUª€€€U?*?UÔßUÔŸU?ª?Ô?_ÿ¿ÿßUÿÿªÿŸÿßÿ¿Uÿÿÿÿ?ÔŸÿUU€€€U?Uª_Ô_Uÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þCreated with The GIMP,„@€pH,ȤrÉl6‚Ó †)ñ€($ÚáaÁ`€DÃñ€D$aÁ„R¡Lá„å2Ád4qSƒ‡‡S†Ž‘MžŸ M!Ÿž"šœ–Ž©«…®#N$%&‡ªS ' #"½hÆÇÈÉCA;tkabber-plugins/iconsets/jajc/docking/available-xa.gif000064400000000000000000000005671500237002100227120ustar00nobodynobodyGIF89a¥»»»  ¤U_UU?Uª¿ªÿþþŸª*ªU*U*_U€€€ÔßUÿŸU?ª?Ô__UÔ¿ÿßUÿߪÿÿªÿ¿ÿŸÿßÿÿÿÿ_ª_€*U?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þCreated with The GIMP,ƒ@€pH,ȤrÉl6‚Ó  ‡)¸&´CÄAq€ FÃñ€DÀ’ ¥b¹`À‚ŒærÙܵ |{„S |†N•Ž‘••K šœ—!M£ž§L©"œ#N$ š„ŸZ#!­gÅÆÇÈCA;tkabber-plugins/iconsets/jajc/docking/available.gif000064400000000000000000000005661500237002100223030ustar00nobodynobodyGIF89a¥»»»  ¤U?U*_U¦Êðÿÿÿ*Ôßÿ€€€*?UUU?U_U_UÿߪԟU?Ô?ª_ÿŸÿßUÿÿªÿ¿ÿßÿ_ÿÔ¿_ÔÔ€€*?ÔŸªÿ?ªŸªªÔ_ª¿ªÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þCreated with The GIMP,‚@€pH,ȤrÉl6‚Ó †)18 Ú¡b1H0€†ã‰HÎZÆ„R¡X a…eÁd xZ{~h‹ Žh‚ !Z… fNœ"Ÿ #M $…% &Z hÄÅÆÇFA;tkabber-plugins/iconsets/jajc/docking/tkabber.ico000064400000000000000000000562161500237002100220050ustar00nobodynobody°h¶hh† hîhVh¾h&"hŽ'hö, ¨^2 ¨; ¨®ChVLh¾Qh&W( ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ( *?*U?*?UU?U?U_*ÔU_U_?ÔU__ª?ÿ€€_ÔUª€€€_ÿÔÿ¤  ªŸªUŸÔŸÿªŸÔ¿Ôª¿ª¿ÿðʦßÿUßÿÿßÔªßÿªÿÿÿÿÿ&&&&&&  &&&&&&&&& &&&&&&&  &&&&&  &&&&&&  &&&&&&&& &&&&&&&&&&  &&&&&&&&& &&&&&&&&&  &&&&&&&&& &&&&&&&&& !$!&&&&&&&&& # &&&&&&&&&& &&&&&&&&&&&"&&&&&&&&&&&%&&&&&&&&&&&&&&&&&&&üøøøøøøðððððø?ø?ø?ü( €ÿ*ª*U*U?*€€U?*?UUªU?Uª?U_*ÔU_U_U__ª?ÿ€€_Ôª€€€ª_ÿÿŸÔÿߤ  ªŸªŸÿ¿ÔÿÿUŸÿ¿ÿÿÿ*ª¿ÔU¿ÿUßÔßÿÀÜÀÿßÔªÿÿÿÿÿ! '"#' "'"#"' ,''$'''#,,#'''* %%(',/%0000( +& %00 %000%!. 000%)0!(%%!-üøøøøøøðððððøøøü( ÿ*ª*U*?*ÿ*U?*?UªU?U?U_*_UU_U_?ÔU_?ÿ€€_ÔU€€€_ÿÿŸÔ¤  ªŸªUŸÔŸÿ¿Ôª¿ª¿ÿßÿÀÜÀUßÿÿÿªÿÿýþÿ    "   ! !!  ! $#%% &$$# &$&&&&$&&&$"&&&&&üøøøøøøðððððøøøüC( *€?*U?*?UÔUU?U?ÿ?ªU_U_ÿ?ÔU_Uÿ_ª?ÿ€€€€€ªUªÿŸÔ¤  UŸÔŸÿ¿ÿª¿ÔU¿ÿUßÔßÿUßÿªÿÿýþÿ       &&&&&&  &&&&&& #  # # #!$%$ " & &üøøøøøøðððððø?ø?ø?ü( **€U*?UU?U?ÿU_*?ªU_U_ÿ_ª_ÔU€€€_ÿUªªŸÿ¤  Ÿÿ¿ÔUŸÿª¿ª¿ÿUßÔßÿUßÿªßÿªÿÿþþÿ   ###  #####  #####  ##### #######   !"   ## üøøøøøøðððððø?ø?ø?ü( *U*?*U?*U?UU_*U_UU_ª_€€€¤  ªŸªªŸÔª¿ªÿŸÔª¿Ôÿ¿ÔÀÜÀªßÔÿÌÿªßÿõüÿ                            üøøøøøøðððððø?ø?ø?ü(  ES%`M3G†j\O*[m3\†m`mkrQ3o†IX¸qvq>t¡Ih¸4†‡v{‹>†¡I{¸v‹‹cyÂIЏc„”””c’ÂcÂI­¸c¨Â¨¼°¯¯c¶Â³°³¼Ã¼¾ºÍ—ÉÖàÒÅÉÝêÉéêôèãÿÿÿ&&&&&& &&&&&&&&& &&&&&&& &&&&&   &&&&&&   &&&&&&&& &&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&  # &&&&&&&&&" &&&&&&&&&& &&&&&&&&&&&$&&&&&&&&&&&!%&&&&&&&&&&&&&&&&&&&üøøøøøøðððððø?ø?ø?ü( *U*€U*?*ªUUU?*?UªU?U?UªU?U_UUÔU?ªª_UU_UUª_U_ªªUU€€€U_ÔªUªUÔªŸUŸª¤  UÿªŸªÿŸªU¿ªª¿ªÿŸÔªŸÿª¿Ôðʦÿ¿Ôª¿ÿÀÜÀªßÔUßÿÿßÔªßÿÿÿªÿÔÿßÿUÿÿªÿÿõüÿ! -! #!+  #7!#  -!))7! ( .76 ,,,( #6).&((((367!(("!%5  1! 752%77!%2/#6$'-0&&67)+# -!-! 4*!7+!#77-+ -þÀ€€€€€€€€€Àâöÿ( Uÿÿ*U?*ÿ*ÿUU?UUÔU?Uÿÿ?UU_Uªÿÿ?Uÿÿ_UUU?ÿU_ªÿ_€€€_ÿÿU_ÿª_ÿÿÿªªÿŸÿÿŸªªŸÔUŸÿÿŸÔªŸÿU¿ÿª¿ÿÿßÔªßÿðûÿ      ! !!$$ $$"%%'$%%'#!( & ( üø?À€€€€€€„ÂÇçÏ( @   $$$$(,L000(X(`<@ ##••••••••••••••••••••••GSS8••••••••••••••••••••••••vˆdS-•••••••••••••••••••••••-ˆ”ˆdG•••••••••••••••••••••••ˆ””d8•••••••••••••••••••••••••#vd?••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••ÿÿüÿÿ€ÿàóððàààÀ€€€€€€Ààøüþ8ÿx?ÿøÿþÿÿþÿÿþÿÿþÿÿÿÿÿÿƒÿÿÿÿÿ( @4  $@(L(X4 $8l((((H((0 P€P(((ˆ(0x4444”\000€P88h88<  @XP@@0€DDDP¨XHHPPHPhlLLP( @PPTP(°\\\h``Œ\\`8¸DÄL¸h@°hhhX¨hhLØxX LättthÀx¤xPÈ€`°\è¤xx\ô„„„hÈ´„„@ˆ¨løx¸xø lÜÄ””¤xÜœœœŒø¤Ü¬€ä˜ô¨ÈР ´¤¤¸€ð¨¨¨h¨À°ä¨øÀð´´´h¨è´øÀøÄøÄÄĨÈÐàÄÄLÌøÐÐÐhÐø@ØøÜÔÔàÜäèèèÀìøÐðøØðøôôôppppppppppppppppppppppppppppppppppppppppppp)=ppppppppppppppppppppppppQaPH$pppppppppppppppppppp"Q9aaPHC4pppppppppppppppQa9aaSHCC:pppppppppppp*FZaAaaPCHHW!pppppppp1UM Za9aa[CHCR& ppppppppMF1MM ZaAaaPCHCW! ppppppppMB1UMQa;aaPHHC R! pppppppp MF1MM ZaAaaPHCA W!! ppppppppUF1UM Z_AaaP;CCR! pppppppp MF1MM Za_aa_P;9W! ppppppppUB1UM ZaaaaaSC;@ ppppppppMF1MM[aaaaaPHH3ppppppppMMFUM>aaaaaa[CHH N&pppppppp UMUMM#>_aaaaaPHHCN!ppppppp MUMUU>aaaaaa[CHC N! pppppp8MUMUM#>_aaaaaPHCHN! ppppppBUMUMU>_aaaaheCHC N!!ppppppBMMUUM#>__ahlngSHHN! ppppppBUMUMU>`elng`aa_K R!!ppppppBMUUMU'Gmn^7,=HKS>jE! ppppppBMUUdo0%cY%-$ -T\WL.ppppppBUdodMF* D]OD%I5+22?LppppppVoi1 (bjb]D pppppppV*/( 6kojbO????AY+†4{6ˆIeIe8‹@KO8;’<•Yq___L¾gggDÝTÊh«Sæxxxyyy{¤Vîž|¤}¤~¤]椀¤S‰¤dádâ\öfäfåg僯aó`ödðaù………düeþeÿfÿgÿhÿiÿiÿŠ‹‹:ÂŒŒŒxÿ•••–––‹ÿ Œý¡¡¡“ÿ¥¥¥ ñ§§§¡ö¡÷¤ø+ü°°°-¡ÿ¬û²²²®ÿ¶ù·ùµÿ¸¸¸¹û¸ÿºü¹ÿ¹ÿºÿ»þ»ÿ»»»¼ÿ½ÿ¾ÿ¿ÿÀÿÁÿÆ÷Âÿ¿¿¿ÂÿÃÿÅýÄÿÅÿÆþÆÿÇþÇÿÈÿÃÃÃÉÿÊÿÊÿËÿÌÿÅÅÅ:Èÿ*Ëÿ:ÌÿÒÿ3Ñÿ‡ÉþÔÔÔØØØÝÝÝ‹èÿååå«ëÿ´êÿ«íÿïïïÀñÿðððôôôé÷úã÷ÿâøÿøøøãùÿ 6j: "^ŽvOL)*|@aŽvONN%>@`ŽtONN(<‹?`ŽtONN(;Š@`ŽtONN(;ˆBaŽtONN(9‡DaŽtONN(9…CaŽsKMN(8ƒCbŽi15A'7‚f†ŽmG.4}…ŠŽŽ…QI E}ƒˆŽ{PNFoz‚‡Ž{PNN,#ty€…‹Ž{PNN,#rx}ƒŠ{PNN,#pwz‚ˆ{PNN,#nvy€‡Œ‘RNN,#nrx”¤eQN,#nq’›¦™“ŽkV,$œ£•cZY\h„0&¢ŸT!H/=3U2 S~u]J‰š˜[+—¥ —g-d¡ž–_ XlW ÿÿÿÿÿþÿÿøÿÿàÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿ€ÿÿ€ÿÿ€ÿÿ€ÿÿ€ÿÿ€ÿÿ€ÿÿ€ÿÿ€ÿÿÀÿÿàÿÿàÿÿàÿÿðÿÿðÿÿø?ÿÿÿÿÿ( GGGIIIJJJKLKLLLMMMNNNOONOOOOOPPPPQQQQQRRRRRSRSSSTTTUUUVVVWWWXXXZYZZZZ\[\]\\]\]]]]^^__`_```bbbbbcedeeffghhihijjjkkkmmmtttvvvvwvxxxyxyyyyzzz||{||||}}}~}~€€€€€‚ƒ‚ƒƒ‚„ƒƒƒ„ƒ„„„„„…„……†…†…†…††††‡‡‡‡‡ˆ‡‡ˆˆ‡ˆˆˆ‰‰‰ŠŠ‰ŠŠŠ‹Š‹‹‹‹ŒŒ‹ŒŒŒŒŒŒŽŽŽŽ‘‘‘‘’‘‘’’’“““”””•”••••—–––—–——–———˜˜˜™˜˜™™™šš›››››œœœœœœžžžŸŸŸ  VZ\`cfikk RUY[_behjMgHLQTXZ]adB^;@FJNRUY[8W36:>CGKPS! 0O#"-/258AFFLORT5P157<>BEHM! .I#"+-/2489?C%$(*;@'&((),-0369ððÀÀÀÀÀÀÀÀÀÀÀÀÀÀ( GGGIIIJJJKLKLLLMMMNNNOONOOOOOPPPPQQQQQRRRRRSRSSSTTTUUUVVVWWWXXXZYZZZZ\[\]\\]\]]]]^^__`_```bbbbbcedeeffghhihijjjkkkmmmŠÿŽÿÿ“ÿ”ÿ–ÿ—ÿšÿœÿŸÿ¡ÿ£ÿ¤ÿ¥ÿ§ÿ¨ÿªÿ«ÿ­ÿ®ÿ¯ÿ°ÿ²ÿ³ÿ´ÿµÿ¶ÿ¸ÿ¹ÿ»ÿ¼ÿ¾ÿÀÿÁÿÂÿÄÿÅÿÆÿÇÿÈÿÊÿËÿÍÿÎÿÐÿÒÿÔÿÖÿÙÿÚÿÛÿÞÿßÿàÿãÿäÿæÿçÿèÿìÿíÿñÿ  RUWZ\_bde MQTVX[^acI`EHKORUWZ]@YBE%$*,=A'&()+.0258;ððÀÀÀÀÀÀÀÀÀÀÀÀÀÀtkabber-plugins/iconsets/jajc/docking/unavailable.gif000064400000000000000000000004071500237002100226400ustar00nobodynobodyGIF89a„»»»  ¤U_UÔ¿ªÿüõ*?UªŸª€€€*_UU?UÿÌÿÀÜÀÿߪÔߪԿÿª¿ª*_U*?_ªÔŸªÔŸÿ*Uÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þCreated with The GIMP,s Ždižhª®lÛ‚àšÁ@ÅLÇ裄¢P Cì`œ  ‚ã¡8B‹G ª<Æ!bed @fLšNw(žDÑ {vs1{- C|:‚ šjžŸ &!;tkabber-plugins/iconsets/jajc/icondef.xml000064400000000000000000000203451500237002100204040ustar00nobodynobody JAJC 1.0 Tkabber's JAJC Iconset. 2006-01-20 toolbar/add-user tkabber/toolbar-add-user.gif toolbar/disco tkabber/toolbar-disco.gif toolbar/join-conference tkabber/toolbar-join-conference.gif toolbar/show-offline tkabber/toolbar-show-offline.gif toolbar/show-online tkabber/toolbar-show-online.gif browser/client roster/available.gif browser/user roster/available.gif browser/conference roster/conference-available.gif browser/directory services/jud.gif browser/jud services/jud.gif browser/sms services/sms.gif browser/aim services/aim_online.gif browser/icq services/icq_online.gif browser/msn services/msn_online.gif browser/yahoo services/yahoo_online.gif docking/chat docking/available-chat.gif docking/available docking/available.gif docking/away docking/available-away.gif docking/xa docking/available-xa.gif docking/dnd docking/available-dnd.gif docking/unavailable docking/unavailable.gif docking/tkabber docking/tkabber.ico roster/user/chat roster/available-chat.gif roster/user/available roster/available.gif roster/user/away roster/available-away.gif roster/user/xa roster/available-xa.gif roster/user/dnd roster/available-dnd.gif roster/user/unavailable roster/unavailable.gif roster/user/error roster/unavailable.gif roster/conference/available roster/conference-available.gif roster/conference/unavailable roster/conference-unavailable.gif roster/group/closed roster/group-closed.gif roster/group/opened roster/group-opened.gif services/aim/away services/aim_away.gif services/aim/chat services/aim_chat.gif services/aim/dnd services/aim_dnd.gif services/aim/unavailable services/aim_offline.gif services/aim/available services/aim_online.gif services/aim/xa services/aim_xa.gif services/icq/away services/icq_away.gif services/icq/chat services/icq_chat.gif services/icq/dnd services/icq_dnd.gif services/icq/unavailable services/icq_offline.gif services/icq/available services/icq_online.gif services/icq/xa services/icq_xa.gif services/jud services/jud.gif services/msn/away services/msn_away.gif services/msn/chat services/msn_chat.gif services/msn/dnd services/msn_dnd.gif services/msn/unavailable services/msn_offline.gif services/msn/available services/msn_online.gif services/msn/xa services/msn_xa.gif services/sms services/sms.gif services/yahoo/away services/yahoo_away.gif services/yahoo/chat services/yahoo_chat.gif services/yahoo/dnd services/yahoo_dnd.gif services/yahoo/unavailable services/yahoo_offline.gif services/yahoo/available services/yahoo_online.gif services/yahoo/xa services/yahoo_xa.gif tkabber-plugins/iconsets/jajc/roster000075500000000000000000000000001500237002100175065ustar00nobodynobodytkabber-plugins/iconsets/jajc/roster/available-away.gif000064400000000000000000000007111500237002100231320ustar00nobodynobodyGIF89aõ0**?*U*?U*_UUU??U?UU_U_U_U€*ªÿªªßÿÿÿ*ÿÿªª_ªÔÿ?Ô_ÿ_ÿ€€€€ÔŸÔ¿ÿŸÿ¿ÿŸUÿ¿UÿßÔßU€€€ªŸª  ¤Ô¿ªÿÿªÀÜÀÔßÿÿÿÿÿÿÿ!ù1,æÀX,‹ÅV‚k‰œÃÃôx<Èét:2éq0y<Óét:14ÍÆòð@ §Óét:56›Í¦â€O§Óét:@˜NgãpœN§Óét:NŠÎf#aœN§Óét:N ËÆYœN§Óét:NKÆR£Óét:N'…Fc™†Eèt:N'…Fc©¡t:N'ec¡ˆÐét:N§S(T ‹Óét ;tkabber-plugins/iconsets/jajc/roster/available-dnd.gif000064400000000000000000000007111500237002100227360ustar00nobodynobodyGIF89aõ'**?*?UU??U?UU_U_U_Uª€ª?ª_ªUÔÔ?ÿÿÿ?ÿUÿ€€ÔŸÿŸÿ¿ÔŸUÿ¿UÿßÔßUÿßU€€€  ¤Ô¿ªÿÿªÿþýÿÿÿ!ù',æÀÓét:F Áét:N§Óét:H¦Qàt:N§Óét:E&àt:N§Óét:EƒÁât:€§Óét:‰@Ãc¢8N§Óét:-8¡Rˆs8N§Óét:‰6Žc8N§Óét:-8œÏ¦B¡-§Óét:"·B¡P*•Óét:NŠ¥B¡P(—Êét:NŠ Åd2™L&Jât:N ÅdšL&Åq:N'ņR¡P( Åq:N'ÅfS¡P(Ját:N'„ƒ©H(Çét:N§“ˆ< Çét ;tkabber-plugins/iconsets/jajc/roster/available-xa.gif000064400000000000000000000007111500237002100226010ustar00nobodynobodyGIF89aõ%***?*U*_UU??U?U_U_UUŸª€ª?ª_ªUÿÿÔ_ÿ_ÿÔ¿ÿŸÿ¿ÿŸUÿßÔßUÿßU€€€  ¤ª¿ªÿߪÿÿªÿþþÿÿÿ!ù%,æÀR©T*•@ E©T*•J¥R©T*B$‡ T*•J¥R©T*I@$¡T*•J¥R©T*I£T*•€¥R©T*}:›¤²(•J¥R©T*50ÑHƒ(•J¥R©T*12æ‚(•J¥R©T*}4Žf2™)¥R©T*•>†b!H”R©T*•J …D"H$J©T*•J‹Ì„D"H¤ ¢T*•J‘Ì„D’$ÒäQ*•J¥EfB"H$ÒäQ*•J¥EF3 H¤É¡T*•J%CD“™L&D©T*•J¥hL(G©T ;tkabber-plugins/iconsets/jajc/roster/available.gif000064400000000000000000000007111500237002100221730ustar00nobodynobodyGIF89aõ&**?*?U*_UU??U?U_U_U_UUª_ªÔÔ?ÿ?Ô_Ôÿ_ÿ€€Ô¿ÿŸÿ¿ÔŸUÿßÿßU€€€ªŸª  ¤ª¿ª¦ÊðÔŸªÿߪÿÿªÔßÿÿÿÿÿÿÿ!ù',æÀÓét:>Âét:N§Óét:}B¦Oàt:N§Óét:}>¥Îàt:N§Óét:1 „ât:€§Óét:-Fš¤¡8N§Óét:)0's8N§Óét:12™Ì†b8N§Óét:-0™ ¦r8O§Óét::—M&C1œN§Óét:N‰M&YœN§Óét:N Ìeò@œN§Óét:NL¦ ¢Óét:N'KS¡Åçt:N§&S‰Âs:N§‚S‘ Ðét:N§Ó'<Óét ;tkabber-plugins/iconsets/jajc/roster/conference-available.gif000064400000000000000000000007111500237002100243000ustar00nobodynobodyGIF89aõ**?UUU?U?UU_UUUÿ*ÿ*ÿUÿU?ÿ?ÿU_ÿ_ÿÿª_Uÿ?ÔUÿUÿUÿ_ÿÿ_Uªÿÿªÿÿÿ_ªÿªÿŸÿŸUÿ¿U€€€ªŸÿÔŸªÿŸªÿ¿ªÔŸÿÿߪÔßÿÿûð!ù*,æ@•J¨T*• P©T*• €2T* e¨T*•  Tà@¨T* 2¨)@P©€* t"}€ÐáT* T:! Sêp*`D¦Ì€ÁT*• 2"ä¨'•Jø|Ìã¡h*•Jø\$€ÇcL•Jð\,GC¨P!CH¸X,R(C(¤\,C‘P(ƒJ¥R€B*•J¥R©T*@"‘¨T*•J¥R©T*¨T*•J¥ ;tkabber-plugins/iconsets/jajc/roster/conference-unavailable.gif000064400000000000000000000004001500237002100246360ustar00nobodynobodyGIF89aó***JJJZZZjjjˆˆˆŸŸŸ¬¬¬¾¾¾ÏÏÏÔÔÔééé÷÷÷!ù,­ð½À{ï=Þƒï½ï=àï½÷À à`à½÷€à à½÷c+Ì*÷`lÁŠ­Þ ¦ÖR ¤tÀ{ð”€Zk%p €ï=P+¥ ï½’1 ¥c (€¼÷€1$8b0ƈÐÇbÌÆ@2À@Þ{À9ðÞ{ð½÷0Æ€÷Þƒï½÷Þ{€÷|ï½;tkabber-plugins/iconsets/jajc/roster/group-closed.gif000064400000000000000000000002721500237002100226600ustar00nobodynobodyGIF89aðÿÿÿ!ù,‘L˜0a„ &L˜0a„ &L˜0a„ &L˜0aÀ„ &L˜0a@„ &L˜0a@€ &L˜0a@€&L˜0a@€&L˜0a@€&L˜0a@€ &L˜0a@„ &L˜0aÀ„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &;tkabber-plugins/iconsets/jajc/roster/group-opened.gif000064400000000000000000000002721500237002100226610ustar00nobodynobodyGIF89aðÿÿÿ!ù,‘L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜ @€&L˜0 @€&L˜0!@€&L˜0a@€ &L˜0aB„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &;tkabber-plugins/iconsets/jajc/roster/group_closed.gif000064400000000000000000000002721500237002100227420ustar00nobodynobodyGIF89aðÿÿÿ!ù,‘L˜0a„ &L˜0a„ &L˜0a„ &L˜0aÀ„ &L˜0a@„ &L˜0a@€ &L˜0a@€&L˜0a@€&L˜0a@€&L˜0a@€ &L˜0a@„ &L˜0aÀ„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &;tkabber-plugins/iconsets/jajc/roster/group_opened.gif000064400000000000000000000002721500237002100227430ustar00nobodynobodyGIF89aðÿÿÿ!ù,‘L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜ @€&L˜0 @€&L˜0!@€&L˜0a@€ &L˜0aB„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &;tkabber-plugins/iconsets/jajc/roster/unavailable.gif000064400000000000000000000005131500237002100225360ustar00nobodynobodyGIF89aô**?*U*?U*_UU?UU_U_U_ª€€€ªŸª  ¤ª¿ªÔŸªÔ¿ªÔŸÿÔ¿ÿÔߪÿߪÀÜÀÿÌÿÿüõÿÿÿ!ù,Èàu]×u1Çq]×u]×u]×Å<C\×u×u]×u-ŠÅ×u]×u]×u!A×^×u]×u)ÕrÊq]×u]×uÔdIh\×u]×u]JóTc\×u]×u]GT= ¥×u]×u]—ÒPUÄ×u]×u]×u€ÕC%Çu]×u]×u ÅÇu]×u]×^Š-Šp4×u]×u]ÊÒ0Êps]x]—âP ‡p,×u]—¡<ÍaGs]àu]×u1ŠaÊu]W;tkabber-plugins/iconsets/jajc/services000075500000000000000000000000001500237002100200135ustar00nobodynobodytkabber-plugins/iconsets/jajc/services/aim_away.gif000064400000000000000000000002501500237002100223450ustar00nobodynobodyGIF89aó €Ÿÿÿ€ª€€ÿÿ€€€ÿÿÿÿÿÿ!ù ,UPI‚¥`jÆ@CpÙÖ% „‡°q¬¢ñv€1³¥v¢´LoÒñ„ Ò‹cžÊ%à ¨7„硺”LµÂ£¨›\™¼M·zBájM»›;tkabber-plugins/iconsets/jajc/services/aim_chat.gif000064400000000000000000000002241500237002100223240ustar00nobodynobodyGIF89aó€€ÿÿ€€€ª¿ª¦ÊðÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù ,A0ÉIk£`)@ hp݆[7œáÐ%æé–€d9ÙVž—fv ‚‰U­d ~?O3À{ÁŽØ¨›-Ù¾ßJ;tkabber-plugins/iconsets/jajc/services/aim_dnd.gif000064400000000000000000000002411500237002100221510ustar00nobodynobodyGIF89a󟀪ÿ€€ÿÿÿÿÿÿÿÿ!ù,NI$ª@ÌM‰'‚Qhœð}aÁQG릫ྐྵ™'¨Ùî ÁhE© HC€· 3¢$ôd6“H5“žo㬅E6€ [¥œ;tkabber-plugins/iconsets/jajc/services/aim_offline.gif000064400000000000000000000002311500237002100230250ustar00nobodynobodyGIF89aó ª€€ªŸªª¿ª¦ÊðÔ¿ªÔ¿ÿÀÜÀÿÿÿ!ù ,F0É9 ˜‚#nÖ‡Ÿ† YVâ­@w½PŒ‚à–[{4ÓÁbY ¢"OD8p‚ ÒCP1ÕÁNº3u*¯FY®(;tkabber-plugins/iconsets/jajc/services/aim_online.gif000064400000000000000000000001651500237002100226750ustar00nobodynobodyGIF89aòŸ€ª€€ÿÿÿÿÿ!ù,:hº À^”%“‹5ïÖ ŽF%'”fË¥NÉ °}½™Ðš/@ Ór@¢+¬Š:EôI;tkabber-plugins/iconsets/jajc/services/aim_xa.gif000064400000000000000000000002131500237002100220130ustar00nobodynobodyGIF89aò€ÿ€€ÿßÿÿÿÿÿÿÿÿ!ù,PxzÒr¬É E”!© †„6PU8fú©¤ÖMš–Ò¼á ƒÅpŽÝSˆDˆŠò e"Jˆ08*¹S­—‚*Â/u±†B;tkabber-plugins/iconsets/jajc/services/icq_away.gif000064400000000000000000000001751500237002100223610ustar00nobodynobodyGIF89aòÿ€€€ÿÿÿÿÿÿ!ù,BHª@Ð+®Æ»ažíŒåÝðAU—Væ=*kZ&Ì3*â<íô=” H»[”A)˜a E¤f©I*.ëºÕ,;tkabber-plugins/iconsets/jajc/services/icq_chat.gif000064400000000000000000000002101500237002100223250ustar00nobodynobodyGIF89aò€ÿÿÿÿÿÿÿÿÿ!ù,MXºÀ"ž{Ë5ZÅSWêTÒ4¼°¦\Ä6>`› ÿ²†Kg{@žœnÄòTjFÕ†tÙQyÔ„FbÍ,§W¢–!—Ö";tkabber-plugins/iconsets/jajc/services/icq_dnd.gif000064400000000000000000000002161500237002100221610ustar00nobodynobodyGIF89aòÿ€ÿÿÿÿÿÿÿ!ù,SXºÀž{Ë5ZÅÓÅyA¥L• ê(Â0ijy:1!º€m,™N7Óœ(4âª$y²åe’Ûõ.Àà,jÜp+UÉÖ°|HäÌ×úeºåE;tkabber-plugins/iconsets/jajc/services/icq_offline.gif000064400000000000000000000001321500237002100230330ustar00nobodynobodyGIF89aðÿÿÿ!ù,1Œȸ™”[/¾k48êJ[¥Œe zG¦d¡*´Å§¨uõÅ;9,ƒùD”ëU+;tkabber-plugins/iconsets/jajc/services/icq_online.gif000064400000000000000000000001771500237002100227060ustar00nobodynobodyGIF89aòÿÿÿÿÿÿÿÿÿ!ù,DHºÀž{Ë5ZÅÓÅyA¥LÝ8J_ˆbØ]Ú9N‚ðÂÓ7䨈†#™ŒDâFøje’Ñt²´‚°§ÆS“tc‹;tkabber-plugins/iconsets/jajc/services/icq_xa.gif000064400000000000000000000002011500237002100220160ustar00nobodynobodyGIF89aòÿÿÿÿÿÿÿÿ!ù,FHºÀž{Ë5ZÅÓÅyA¥hªª:¼pü¦ÃTáízvøN»ZOè Þ†7£ï–tÉž¨ÖjmX>$$gF. !;tkabber-plugins/iconsets/jajc/services/jud.gif000064400000000000000000000003001500237002100213340ustar00nobodynobodyGIF89añÿÿÿÿÿ!ù,‘ܸqãÆ7nܸqãF€1nܸqã@€nܸ @€nÜ8 @€1nÜ @€1nÜ DnÜ¢D€1nÜ D‰1nÜ8¢D7nܸ¢D7nܸ"@€7nÜ8¢À7n܈q À7nܸqãFŒ7nܸqãÆ7n;tkabber-plugins/iconsets/jajc/services/msn_away.gif000064400000000000000000000003661500237002100224040ustar00nobodynobodyGIF89aô*UU€*ªÿª€€Ÿªßÿÿÿ*ÿÿ€€€€€€€  ¤Ô¿ªÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù,s %RG ˆAQ £XN‡ ‹â(¬{ÀðLÀçŠì8æ^£ÐhNž’CÖX' Áè€8<BB¡XZ$€\Ĩ¿áø¼N6×C!1'x%F0€2ƒY<1hp%HGcZG0Fˆce”‚"!;tkabber-plugins/iconsets/jajc/services/msn_chat.gif000064400000000000000000000002621500237002100223550ustar00nobodynobodyGIF89aó ÿ€€Ÿªÿÿ€€€  ¤ª¿ªÔ¿ªÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù ,_I&*!‡)ÅX‚K¹l‚¤¨ ¨BšÄ™‚‰Ðj0Éà0@ ¾!8©—W†ÓX1(ªvªe ŽÖK—B3ÄÔŠdF7×4¤›,8”ŸîÊl%sœ€r;tkabber-plugins/iconsets/jajc/services/msn_dnd.gif000064400000000000000000000002541500237002100222040ustar00nobodynobodyGIF89aó €€Ÿª€ªÿ€€€ªŸª  ¤ª¿ªÔ¿ªÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù,YÐÉ)ƒ4Kš0˜Vu‚ŠN§.A¨YMˆ› -šr<›£@,TÈL±è[.wHW¡A­Ã'4­R¯tè$J»yIPå‚’%6{»x‹ÞŒ;tkabber-plugins/iconsets/jajc/services/msn_offline.gif000064400000000000000000000002321500237002100230550ustar00nobodynobodyGIF89a󀪀€€ª¿ªÔ¿ªÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù ,G0É*˜WÆÍTÀq(…ÁnѹY`¬@×U ›€H,V;tkabber-plugins/iconsets/jajc/services/yahoo_chat.gif000064400000000000000000000003461500237002100227020ustar00nobodynobodyGIF89aô*?UU?UU_U_U€ߪ€ªÿ€€ÿÿ€€€  ¤ª¿ªªßªÔ¿ÿÔߪÀÜÀÿÿÿÿÿÿ!ù,c %ŽdiR­ë0˜‚1ÍtKÏÌFµmH£‹ nÇ›3‘68Î “TcH<'ÂL\/r4Òqq`' Ei~H$êy&slHz‚Vy†'F?‹Œ$!;tkabber-plugins/iconsets/jajc/services/yahoo_dnd.gif000064400000000000000000000002411500237002100225220ustar00nobodynobodyGIF89aó €Ÿ€ªÿ€€ÿÿ€€€ÿÿÿÿÿÿ!ù ,NPÉI«½X`LVÛ!‚gb¢&GbRè:¯Ö&›‹uœ * 6 fCMaY8Ò’&$ƒÕÊI›dµ *­•69—òðÁŒŸ;tkabber-plugins/iconsets/jajc/services/yahoo_offline.gif000064400000000000000000000002331500237002100234000ustar00nobodynobodyGIF89aó Ÿª€€ª¿ª¦ÊðÔ¿ªÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù ,HPÉI«½XŽ0FVÝ‘ Iw ‰(’ˆW ¤‘&²;ÁcBг &‚N¢Ä)Q2Q!Gò¡’Lšï×Ħ ’HV»s†àÓ1}ÎhJ;tkabber-plugins/iconsets/jajc/services/yahoo_online.gif000064400000000000000000000002251500237002100232430ustar00nobodynobodyGIF89aó €€ÿ€€ÿÿ€€€ªŸª  ¤¦ÊðÀÜÀÿÿÿÿÿÿ!ù ,BÉI«½X@Hf[!݈Kº‹WêH¾ì¬·èjì( ƒBG9ÉŽ;H ‹ËÁ€9£Ÿ/ت”Ùp>àp%;tkabber-plugins/iconsets/jajc/services/yahoo_xa.gif000064400000000000000000000002451500237002100223710ustar00nobodynobodyGIF89aó €Ÿ€ªÿ€€€€ÿÿ€€€ÿÿÿÿÿÿ!ù ,RpÉI«½XpN^""݈Jª ŠWêˆ/«+.ºš¤¿¥@,ÈF„I!PwÂÅ’™*t¢RUÓ9Ñ$SŶÐ-)©ÕÁ·RØ* ƒO‘œ‰;tkabber-plugins/iconsets/jajc/tkabber000075500000000000000000000000001500237002100176025ustar00nobodynobodytkabber-plugins/iconsets/jajc/tkabber/toolbar-add-user.gif000064400000000000000000000005651500237002100235220ustar00nobodynobodyGIF89a¥€€€_U*?UªŸªÀÜÀÿý÷  ¤*UŸª*ªU?U?UU_UÿßUÔŸU?ª?Ô__Ô¿ÿÿUÿߪÿ¿ÿ*ÿÿßÿ_€€ÿÔÿŸª_ÿ?*?Ô¿ª*_Ô?U_UUÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ?,’ÀŸpH,ȤrÉl:€€àY †u‰­P±`â†ã‰H&[ÅQ±\0MÆÙ¸ø7{MyƒyLr~““…KŒz–J ‹O!! zN"!# $ N¨ª %M&³'gT() bÔÕÖ×DA;tkabber-plugins/iconsets/jajc/tkabber/toolbar-disco.gif000064400000000000000000000007111500237002100231100ustar00nobodynobodyGIF89aõ:***?*U*?UUU??UUU?U?UU_UUU_UUU_ªUª_ªªŸª€ªªªUª?Uª_UªUÔUÔ_UÔUÿUªŸUª¿UÿÿÿßUÿÿU€€€ªŸª  ¤ª¿ªªŸÿ¦ÊðÔ¿ªÿŸªÿ¿ªÔŸÿÔ¿ÿÔߪÔÿªÿߪÿÿªÀÜÀÌÌÿÔßÿÿßÿÿüõÿÿÿ!ù:,æ@N§Óét:ØcQÓét:N§;ét¹J®&Ðét:N·BQt¹ 5Ðét:.uÊ¡j(°0á€:.•¢åXì$©5N4"h…êUkn&©4r8D¹F…2!r(NT 5B3Ta³!9“N‘Ñ jÓj”NG9ÑX±§Õjµ:NWáÄr´„Ëåje!N‡b±r¨ƒçÓb ŠN§;åP§Ãó±,–BM§;¡`…F@“Ø\.“N§ÓÕP¦Fcáñ\ N§Óét:<0N§ ;tkabber-plugins/iconsets/jajc/tkabber/toolbar-join-conference.gif000064400000000000000000000006061500237002100250560ustar00nobodynobodyGIF89a¥ÔßÿU_Uÿûð€€€*?UUU?Uª_UUUÿ¿ªÿߪÿŸªÿŸUÿªÿ_ªÿ¿UÔŸªªŸÿÔŸÿªÿ_ÿÿ_UÿUÿÔU*ÿÿªÿÿ?Uÿÿ?UÿŸÿ_U_ÿ?ÿÿUU?ÿ*ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ?,£ÀŸpH,ȤrÉl2€"Ô ¢BÀàÚ Q(ÀpÀ*ˆDx P˜“€£á€ÊÈû—G¼P y{R…Rˆ’DuŒž œ!K"#$%¥&^p¸¹''±&¿ÁÂH¸¬'(ÉOb±SNY(ਵÝÞåæçèéA;tkabber-plugins/iconsets/jajc/tkabber/toolbar-show-offline.gif000064400000000000000000000006541500237002100244150ustar00nobodynobodyGIF89a¥€€€U_UU?U  ¤Ô¿ªÝÝÝ*Uÿûð*ª_U?*?UÿߪԟUª?_Uÿ¿ÿßUÿŸÿßÿ?ÀÜÀª¿ªÿ_*ßU¿UÔŸUŸU*¿U_Ô?UUÔUŸUU¿UßU*_U€€ªŸUŸU*_ŸÔ_*?ªŸª*ªª¦Êðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ?,ÉÀŸpH,Èdr(•Âa°x"_€)B8œ¬Â‡`±pdZköÕƒ ú \‡KAðPœÊjR  NJn O„¡V’™u/L¡¤j2X.· j/ º³(« .J(®eKìÊØ./` ®-`C|°  €*\ÈpH;tkabber-plugins/iconsets/jajc/tkabber/toolbar-show-online.gif000064400000000000000000000005441500237002100242550ustar00nobodynobodyGIF89a¥  ¤U?U*_U¦Êðÿÿÿ*Ôßÿ€€€*?UUU?U_U_UÿߪԟU?Ô?ª_ÿŸÿßUÿÿªÿ¿ÿßÿ_ÿÔ¿_ÔÔ€€*?ÔŸªÿ?ªŸªªÔ_ª¿ªÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ?,ÀŸpH,ȤrÉl:‡€€àY € 0[aB!@,ÂŒ†ã‰œ© É„2©<¶‰ŠÞrÁlwTz}aŠ a T„ fN›!ž"M #„$ %T aÃÄÅÆBA;tkabber-plugins/iconsets/jarl000075500000000000000000000000001500237002100162115ustar00nobodynobodytkabber-plugins/iconsets/jarl/icondef.xml000064400000000000000000000025101500237002100204170ustar00nobodynobody Jarl 1.0 Tkabber's Jarl Iconset. 2006-01-21 roster/user/chat roster/available-chat.gif roster/user/available roster/available.gif roster/user/away roster/available-away.gif roster/user/xa roster/available-xa.gif roster/user/dnd roster/available-dnd.gif roster/user/invisible roster/invisible.gif roster/user/unavailable roster/unavailable.gif roster/user/error roster/unavailable.gif tkabber-plugins/iconsets/jarl/roster000075500000000000000000000000001500237002100175275ustar00nobodynobodytkabber-plugins/iconsets/jarl/roster/available-away.gif000064400000000000000000000002771500237002100231620ustar00nobodynobodyGIF89aò333LLLÿÿÿÿÿÿÿÿÿ!ù,„hff†fffhff†fhff†ffHDa†fffhAD„ffhf3ƒ333hffƒUUUXUc†6UU…5fSPP€UPchSP€PXc6…PX5†fSUXUU…cff833ƒ3cfhff‚ fhff†fhff†fffhff†f–;tkabber-plugins/iconsets/jarl/roster/available-chat.gif000064400000000000000000000002771500237002100231400ustar00nobodynobodyGIF89aò333LLLfffÿÿÿÿÿ!ù,„XUU…UUUXUU…UXUU…UUHDQ…UUUXAD„UUXUA„CCXUU…ACC8U…U4HD€UUUXAC€DUXU„DDHPU…UDD€UUDD„DPUX%@„@@XUU‚D@HPU…UHDP…UUUXU€U•;tkabber-plugins/iconsets/jarl/roster/available-dnd.gif000064400000000000000000000003531500237002100227610ustar00nobodynobodyGIF89aó333LLLfffÿÿÿÿÿÿÿÿÿ!ù,˜!„B!„‚!„ ! „D!„P0Æ„ B!„‚1ƘB!Œ!†hB! 1Ä@bB! 1!B!„‚!ЈRŠ@!„‚DRÈ!„ ¢C)!„ ¢rH)!¢C)!ˆARÈA„B!ˆRŠ@"„B!!BE;tkabber-plugins/iconsets/jarl/roster/available-xa.gif000064400000000000000000000003531500237002100226240ustar00nobodynobodyGIF89aó333LLLfffÿÿÿ²²²ÿÿÿÿÿÿ!ù ,˜0¥”RJ)¥”R‚)¥”R !””L)¥”J0Æ„’`J)¥”Š1Ƙ…H)¥Š!FXH)¥ŠA„)%! B)%8 €)%‚ )%D€)¥$à!$„H)¥BB‘RJ)%˜„€‘RJ)Á”RJ!„”RJ ¦”RJ)¥”RJ0E;tkabber-plugins/iconsets/jarl/roster/available.gif000064400000000000000000000002771500237002100222230ustar00nobodynobodyGIF89aò333LLLfffÿÿÿÿÿ!ù,„XUU…UUUXUU…UXUU…UUHDQ…UUUXAD„UUXUA„CCXUU…ACC8U…U4HDCUUUXACƒUUXU„CCQXUU…UACUU…UUHCQ…UUUX%RUUXUU‚ UXUU…UXUU…UUUXUU…U•;tkabber-plugins/iconsets/jarl/roster/invisible.gif000064400000000000000000000002771500237002100222670ustar00nobodynobodyGIF89aò333LLLfffÿÿÿ!ù,„XUU…UUUXUU…UXUU…UUXUQ…UUUXSU…5UUXUQ…SSXUU…SSS85U…U5XUSUUUXSSƒ5UUXU…SSQXUU…USS8UU…UUXSQ…UUUX%ƒRUUXUU‚ UXUU…UXUU…UUUXUU…U•;tkabber-plugins/iconsets/jarl/roster/unavailable.gif000064400000000000000000000002771500237002100225660ustar00nobodynobodyGIF89aò333LLLfff‚ÿÿÿ!ù,„XUU…UUUXUU…UXUU…UUHDQ…UUUXAD„UUXUA„CCXUU…ACC8U…U4HDCUUUXACƒUUXU„CCQXUU…UACUU…UUHCQ…UUUX%RUUXUU‚ UXUU…UXUU…UUUXUU…U•;tkabber-plugins/iconsets/kroc000075500000000000000000000000001500237002100162175ustar00nobodynobodytkabber-plugins/iconsets/kroc/docking000075500000000000000000000000001500237002100176355ustar00nobodynobodytkabber-plugins/iconsets/kroc/docking/available-away.gif000064400000000000000000000002031500237002100232550ustar00nobodynobodyGIF89aÂÿ)%¿fffÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,HxºÜþ0ÊI«½qh̆ À``ÕFš,:yŠÀž¼Î+Ár@´—Þô/¦ana“‰ªÉ »P«L V¡i޾à°x|H;tkabber-plugins/iconsets/kroc/docking/available-chat.gif000064400000000000000000000002031500237002100232330ustar00nobodynobodyGIF89aÂÿfffÿ²ÿÿÿÿÿÿÿÿÿÿÿ!ù ,HxºÜþ0ÊI«½QhÌ„àÀ aÕFš,:yÊÀž¼Î„+Á2´—Þô/¦ana“‰ªÉ3 »¨&޾à°x¬H;tkabber-plugins/iconsets/kroc/docking/available-dnd.gif000064400000000000000000000002031500237002100230610ustar00nobodynobodyGIF89a¨ÿfffÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,HxºÜþ0ÊI«½qh̆ `À `ÕFš,:yJÀž¼Î‚+Á²@´—Þô/¦ana“‰ªÉ »P«L V¡i޾à°x|H;tkabber-plugins/iconsets/kroc/docking/available-xa.gif000064400000000000000000000002031500237002100227240ustar00nobodynobodyGIF89a®ÿ’%¿fffÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,HxºÜþ0ÊI«½qh̆ À``ÕFš,:yŠÀž¼Î+Ár@´—Þô/¦ana“‰ªÉ »P«L V¡i޾à°x|H;tkabber-plugins/iconsets/kroc/docking/available.gif000064400000000000000000000002031500237002100223160ustar00nobodynobodyGIF89a–fffÁÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,HxºÜþ0ÊI«½QhÌ„ `Àà`ÕFš,:yJÀž¼Îƒ+Áò@´—Þô/¦ana“‰ªÉ »P«L V¡i޾à°x|H;tkabber-plugins/iconsets/kroc/docking/invisible.gif000064400000000000000000000002041500237002100223630ustar00nobodynobodyGIF89aÂfffŒŒŒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,IHºÜþ0ÊI«½1hÌ‚ Àà`ÕFš,:yŠÀž¼Îƒ+ÁrÞ^=ÀIW‘ sãOa“ŽH‚jò̈–+–IÙJ§£°xL.+;tkabber-plugins/iconsets/kroc/docking/tkabber.ico000064400000000000000000000062761500237002100220350ustar00nobodynobody ¨ ( @HHÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿéééÌÌÌßßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøø רØÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþ€ƒƒ  ABB÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøø¨¨¨abbTVVKNNRSS[]]xxxÌÌÍÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ±±±acc`aa_aaWYY\__`bb\\\¢¢¢ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ±±±bccaaa]bbW[\^^^\]]YZZ   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ±²²bcccee_hiUce]gi_``]__£¥¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³³³Sw|=¥¶DÂØFÇÞHÒê?®Ã9…‘©°±ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáåæC½ÓHÒêDÃÚ@·Ì?±Æ9Ÿ±DÇÞŒ¯µÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÙÛEËâIÖïIÖïIÖïIÖï?³È?³È{®·ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿšÂÉIÖïIÖïIÖïIÖïIÖïHÑê<¨»M¡®ýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ`·ÇJÖïIÖïJÖïIÖïIÖïIÖï@·Ì>­ÁÓÖ×ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»ËÎFÌäIÖïIÖïIÖïIÖïJÖïIÖïHÒëA¼Ñ‹°µÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøH¥µHÑêA¹Ï>­Á@·ÌDÅÜJÖîJÖïIÖïDÃÚBšªïïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ”¹¿FËã=«¿CÀÖHÑêIÖïHÔìIÖîIÖïIÖïHÒêEÇÞŠ¤¨ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÔÝßGÀÕ?¶ÊGÐèIÖïIÖïIÖïIÖïIÖïIÖïIÖïIÖïIÔí?™©îïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøùùZ±¾GÍåHÐèIÖïJÖïMÖïKÑêJÏèO×ïP×ïMÖïIÖïIÖïJÔî«°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿš¼ÂHÑéJÖïLÖïO×ïG¿Ù;ž»=¢¿:›¸.|œF¸ÓQÖïKÖïKÖïußòF«»ëííÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòM´ÆdÛñQ×ïR×ïIÀÚ;ž»;ž»@ªÆ< ½0 =¢¿?§ÃP×ïJÖï|àòjÜðŽ«°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶ËÍHÑé²í÷M×ïR×ï=£ÀE¶ÑA­ÈA¬ÈD´ÏD³Ï7“°3‰¨NÍæQ×ïM×ï¦éõQ¡¯ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰¼ÄTØðçùüM×ïIÇáB®ÊA®ÉIÀÚPÓëR×ïMËä?§Ã=¢¿C±ÌR×ïN×ïžêö@µÉßââÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿl¬¸jÝñùýþ[ÚðEÂÝ?§Ã4‹ªA®É<Ÿ¼RÖîOÐéJÃÜ?¡¾D´ÏR×ïQ×ï‡äôGÆÜ¦¸¼ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿk§±nÞòÿÿÿ}áóIÑë=Ÿ¼/Ÿ3ЍA¬ÈDµÐPÒëB®É?¦ÂIÃÝR×ïR×ï_ÚðFÇݦ¹¼ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„­´XØïóüý·îøKÖï>§Ä:›¸JÃÝ>¥Á< ½NÎç9—µ:š·OÖîR×ïR×ïKÖïA¼Ñàäåÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²¾¿DÊáÈòùõýþTØïQÖî9—µLÉâA­ÉMËä<Ÿ¼/ŸH¾ÙQ×ïMÖïP×ïKÖïI¨º÷øøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòE™§lÝñ÷ýþ£éõUØïG»Õ:š·1…¤:›¹JÄÞJÄÝRÖîR×ïN×ïIÖïIÔí„«³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ£±³B¿Õ“æõìûýhÜðS×ïQÕíIÁÛOÏçR×ïR×ïR×ïVØïUØïIÖïFª¹íððÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúún’EÈà’æõ·ïøUØïR×ïR×ïR×ïR×ïR×ïR×ïWØïM×ï<°ÅÆÓÕÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûû†›ž=­ÀnÞòqÞñIÖïIÖïIÖïLÖïP×ïXØïLÓëH¡°´ÁÄÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÑÓÓk›£D¡±A½ÓFÍåGÐèEËâ?µÊHœª¬±îïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÃÇÈ¡¯±¡¯±¦²´ÔÕÖøøøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿtkabber-plugins/iconsets/kroc/docking/unavailable.gif000064400000000000000000000002031500237002100226610ustar00nobodynobodyGIF89aÂfffŒŒŒ···ÿÿÿÿÿÿÿÿÿÿÿÿ!ù,HxºÜþ0ÊI«½1hÌ‚ Àà`ÕFš,:yŠÀž¼Îƒ+Áò@´—Þô/¦ana“‰ªÉ »P«L V¡i޾à°x|H;tkabber-plugins/iconsets/kroc/icondef.xml000064400000000000000000000305221500237002100204310ustar00nobodynobody Kroc 1.0 Tkabber's Kroc Iconset. 2006-01-21 toolbar/add-user tkabber/toolbar-add-user.gif toolbar/disco tkabber/toolbar-disco.gif toolbar/join-conference tkabber/toolbar-join-conference.gif toolbar/show-offline tkabber/toolbar-show-offline.gif toolbar/show-online tkabber/toolbar-show-online.gif toolbar/gpg-signed tkabber/gpg-signed.gif toolbar/gpg-unsigned tkabber/gpg-unsigned.gif toolbar/gpg-encrypted tkabber/gpg-encrypted.gif toolbar/gpg-unencrypted tkabber/gpg-unencrypted.gif gpg/signed tkabber/gpg-signed.gif gpg/badsigned tkabber/gpg-badsigned.gif gpg/encrypted tkabber/gpg-encrypted.gif browser/client roster/available.gif browser/user roster/available.gif browser/conference roster/conference-available.gif browser/headline services/rss_online.gif browser/directory services/jud.gif browser/jud services/jud.gif browser/sms services/sms.gif browser/aim services/aim_online.gif browser/icq services/icq_online.gif browser/msn services/msn_online.gif browser/yahoo services/yahoo_online.gif browser/gadu-gadu services/gg_online.gif browser/x-weather services/weather_online.gif docking/chat docking/available-chat.gif docking/available docking/available.gif docking/away docking/available-away.gif docking/xa docking/available-xa.gif docking/dnd docking/available-dnd.gif docking/invisible docking/invisible.gif docking/unavailable docking/unavailable.gif roster/user/chat roster/available-chat.gif roster/user/available roster/available.gif roster/user/away roster/available-away.gif roster/user/xa roster/available-xa.gif roster/user/dnd roster/available-dnd.gif roster/user/invisible roster/invisible.gif roster/user/unavailable roster/unavailable.gif roster/user/unsubscribed roster/unsubscribed.gif roster/user/error roster/unavailable.gif roster/conference/available roster/conference-available.gif roster/conference/unavailable roster/conference-unavailable.gif roster/group/closed roster/group-closed.gif roster/group/opened roster/group-opened.gif services/aim/away services/aim_away.gif services/aim/chat services/aim_chat.gif services/aim/dnd services/aim_dnd.gif services/aim/unavailable services/aim_offline.gif services/aim/available services/aim_online.gif services/aim/xa services/aim_xa.gif services/gadu-gadu/away services/gg_away.gif services/gadu-gadu/chat services/gg_chat.gif services/gadu-gadu/dnd services/gg_dnd.gif services/gadu-gadu/unavailable services/gg_offline.gif services/gadu-gadu/available services/gg_online.gif services/gadu-gadu/xa services/gg_xa.gif services/icq/away services/icq_away.gif services/icq/chat services/icq_chat.gif services/icq/dnd services/icq_dnd.gif services/icq/unavailable services/icq_offline.gif services/icq/available services/icq_online.gif services/icq/xa services/icq_xa.gif services/jud services/jud.gif services/msn/away services/msn_away.gif services/msn/chat services/msn_chat.gif services/msn/dnd services/msn_dnd.gif services/msn/unavailable services/msn_offline.gif services/msn/available services/msn_online.gif services/msn/xa services/msn_xa.gif services/rss/away services/rss_away.gif services/rss/chat services/rss_chat.gif services/rss/dnd services/rss_dnd.gif services/rss/unavailable services/rss_offline.gif services/rss/available services/rss_online.gif services/rss/xa services/rss_xa.gif services/sms services/sms.gif services/x-weather/away services/weather_away.gif services/x-weather/chat services/weather_chat.gif services/x-weather/dnd services/weather_dnd.gif services/x-weather/unavailable services/weather_offline.gif services/x-weather/available services/weather_online.gif services/x-weather/xa services/weather_xa.gif services/yahoo/away services/yahoo_away.gif services/yahoo/chat services/yahoo_chat.gif services/yahoo/dnd services/yahoo_dnd.gif services/yahoo/unavailable services/yahoo_offline.gif services/yahoo/available services/yahoo_online.gif services/yahoo/xa services/yahoo_xa.gif tkabber-plugins/iconsets/kroc/roster000075500000000000000000000000001500237002100175355ustar00nobodynobodytkabber-plugins/iconsets/kroc/roster/available-away.gif000064400000000000000000000001651500237002100231640ustar00nobodynobodyGIF89aÂfff)%¿ÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,:xºÜÐ=j«Š=Z<Á&v ‰c*!*ÊÚ£4×¶@¿Ø±í¼XC‡û,ˆ/˜dÀ”¬Ê’±‡I;tkabber-plugins/iconsets/kroc/roster/available-chat.gif000064400000000000000000000001661500237002100231430ustar00nobodynobodyGIF89aÂfffÿ²ÿÿÿÿÿÿÿÿÿÿÿÿ!ù,;xºÜÐ=j«Š=Z<Á&v ‰c*!*ÊÚ£4×¶@¿Ø±í¼XC‡û,ˆ/˜¤0P– dÕë%;tkabber-plugins/iconsets/kroc/roster/available-dnd.gif000064400000000000000000000001651500237002100227700ustar00nobodynobodyGIF89aÂfff¨ÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,:xºÜÐ=j«Š=Z<Á&v ‰c*!*ÊÚ£4×¶@¿Ø±í¼XC‡û,ˆ/˜dÀ”¬Ê’±‡I;tkabber-plugins/iconsets/kroc/roster/available-xa.gif000064400000000000000000000001651500237002100226330ustar00nobodynobodyGIF89a®ÿ’%¿fffÿÿÿÿÿÿÿÿÿÿÿÿ!ù,:xºÜ>Ð='ª«† Z<Â&vˉc*!ÊÚ£4×v@¿Ø±í¼XC‡û,ˆ/˜À”¬Ê’±‡I;tkabber-plugins/iconsets/kroc/roster/available.gif000064400000000000000000000001651500237002100222250ustar00nobodynobodyGIF89aÂfff–Áÿÿÿÿÿÿÿÿÿÿÿÿ!ù,:xºÜÐ=j«Š=Z<Á&v ‰c*!*ÊÚ£4×¶@¿Ø±í¼XC‡û,ˆ/˜dÀ”¬Ê’±‡I;tkabber-plugins/iconsets/kroc/roster/conference-available.gif000064400000000000000000000007111500237002100243270ustar00nobodynobodyGIF89aõ**?UUU?U?UU_UUUÿ*ÿ*ÿUÿU?ÿ?ÿU_ÿ_ÿÿª_Uÿ?ÔUÿUÿUÿ_ÿÿ_Uªÿÿªÿÿÿ_ªÿªÿŸÿŸUÿ¿U€€€ªŸÿÔŸªÿŸªÿ¿ªÔŸÿÿߪÔßÿÿûð!ù*,æ@•J¨T*• P©T*• €2T* e¨T*•  Tà@¨T* 2¨)@P©€* t"}€ÐáT* T:! Sêp*`D¦Ì€ÁT*• 2"ä¨'•Jø|Ìã¡h*•Jø\$€ÇcL•Jð\,GC¨P!CH¸X,R(C(¤\,C‘P(ƒJ¥R€B*•J¥R©T*@"‘¨T*•J¥R©T*¨T*•J¥ ;tkabber-plugins/iconsets/kroc/roster/conference-unavailable.gif000064400000000000000000000004001500237002100246650ustar00nobodynobodyGIF89aó***JJJZZZjjjˆˆˆŸŸŸ¬¬¬¾¾¾ÏÏÏÔÔÔééé÷÷÷!ù,­ð½À{ï=Þƒï½ï=àï½÷À à`à½÷€à à½÷c+Ì*÷`lÁŠ­Þ ¦ÖR ¤tÀ{ð”€Zk%p €ï=P+¥ ï½’1 ¥c (€¼÷€1$8b0ƈÐÇbÌÆ@2À@Þ{À9ðÞ{ð½÷0Æ€÷Þƒï½÷Þ{€÷|ï½;tkabber-plugins/iconsets/kroc/roster/group-closed.gif000064400000000000000000000002721500237002100227070ustar00nobodynobodyGIF89aðÿÿÿ!ù,‘L˜0a„ &L˜0a„ &L˜0a„ &L˜0aÀ„ &L˜0a@„ &L˜0a@€ &L˜0a@€&L˜0a@€&L˜0a@€&L˜0a@€ &L˜0a@„ &L˜0aÀ„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &;tkabber-plugins/iconsets/kroc/roster/group-opened.gif000064400000000000000000000002721500237002100227100ustar00nobodynobodyGIF89aðÿÿÿ!ù,‘L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜ @€&L˜0 @€&L˜0!@€&L˜0a@€ &L˜0aB„ &L˜0a„ &L˜0a„ &L˜0a„ &L˜0a„ &;tkabber-plugins/iconsets/kroc/roster/invisible.gif000064400000000000000000000001661500237002100222720ustar00nobodynobodyGIF89aÂfffŒŒŒ···ÿÿÿÿÿÿÿÿÿÿÿÿ!ù,;xºÜÐ=j«’=Z<Á&v ‰c*!JÊÚ£4spÒ/¾µ˜Ž×;|2´ÒwPæJŒgìÈ”$;tkabber-plugins/iconsets/kroc/roster/stalker.gif000064400000000000000000000005131500237002100217470ustar00nobodynobodyGIF89aôK%R+\3c:h>!lA#rG'~R0ppp²†Y5Ža<‘d?—iCª{Tÿ·ˆaÿÿÿ!ù,È $I’$I€$I’$I’$I’$ ’$’$I’$Nà I’$I’8Q´J’$IMôÇ€$IÀ²Œ³ÃHÀa ȱÅ CÄq A’$0 !H’$%€’$II’$I B ¤€$I’”@’’$I(%I’$€$I’$II’’$I $I’”$ ’$IR;tkabber-plugins/iconsets/kroc/roster/unavailable.gif000064400000000000000000000001651500237002100225700ustar00nobodynobodyGIF89aÂfffŒŒŒ···ÿÿÿÿÿÿÿÿÿÿÿÿ!ù,:xºÜÐ=j«Š=Z<Á&v ‰c*!*ÊÚ£4×¶@¿Ø±í¼XC‡û,ˆ/˜dÀ”¬Ê’±‡I;tkabber-plugins/iconsets/kroc/roster/unsubscribed.gif000064400000000000000000000001661500237002100227760ustar00nobodynobodyGIF89aÂfffÿ²ÿÿÿÿÿÿÿÿÿÿÿÿ!ù,;xºÜÐ=j«’=Z<Á&v ‰c*!JÊÚ£4spÒ/¼^L$}2´Òw(,'‹‚²bb;tkabber-plugins/iconsets/kroc/services000075500000000000000000000000001500237002100200425ustar00nobodynobodytkabber-plugins/iconsets/kroc/services/aim_away.gif000064400000000000000000000002501500237002100223740ustar00nobodynobodyGIF89aó €Ÿÿÿ€ª€€ÿÿ€€€ÿÿÿÿÿÿ!ù ,UPI‚¥`jÆ@CpÙÖ% „‡°q¬¢ñv€1³¥v¢´LoÒñ„ Ò‹cžÊ%à ¨7„硺”LµÂ£¨›\™¼M·zBájM»›;tkabber-plugins/iconsets/kroc/services/aim_chat.gif000064400000000000000000000002241500237002100223530ustar00nobodynobodyGIF89aó€€ÿÿ€€€ª¿ª¦ÊðÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù ,A0ÉIk£`)@ hp݆[7œáÐ%æé–€d9ÙVž—fv ‚‰U­d ~?O3À{ÁŽØ¨›-Ù¾ßJ;tkabber-plugins/iconsets/kroc/services/aim_dnd.gif000064400000000000000000000002411500237002100222000ustar00nobodynobodyGIF89a󟀪ÿ€€ÿÿÿÿÿÿÿÿ!ù,NI$ª@ÌM‰'‚Qhœð}aÁQG릫ྐྵ™'¨Ùî ÁhE© HC€· 3¢$ôd6“H5“žo㬅E6€ [¥œ;tkabber-plugins/iconsets/kroc/services/aim_offline.gif000064400000000000000000000002311500237002100230540ustar00nobodynobodyGIF89aó ª€€ªŸªª¿ª¦ÊðÔ¿ªÔ¿ÿÀÜÀÿÿÿ!ù ,F0É9 ˜‚#nÖ‡Ÿ† YVâ­@w½PŒ‚à–[{4ÓÁbY ¢"OD8p‚ ÒCP1ÕÁNº3u*¯FY®(;tkabber-plugins/iconsets/kroc/services/aim_online.gif000064400000000000000000000001651500237002100227240ustar00nobodynobodyGIF89aòŸ€ª€€ÿÿÿÿÿ!ù,:hº À^”%“‹5ïÖ ŽF%'”fË¥NÉ °}½™Ðš/@ Ór@¢+¬Š:EôI;tkabber-plugins/iconsets/kroc/services/aim_xa.gif000064400000000000000000000002131500237002100220420ustar00nobodynobodyGIF89aò€ÿ€€ÿßÿÿÿÿÿÿÿÿ!ù,PxzÒr¬É E”!© †„6PU8fú©¤ÖMš–Ò¼á ƒÅpŽÝSˆDˆŠò e"Jˆ08*¹S­—‚*Â/u±†B;tkabber-plugins/iconsets/kroc/services/gg_away.gif000064400000000000000000000005721500237002100222320ustar00nobodynobodyGIF89aÕ™Œ„{fZRJB3)Rc˜±Îï¹Ò­ÆŒ {ŒÛ÷ÎçÆÞ§º„”m{ëÿ÷ÿÿÿffÿÿÿ÷ÿïÿçÞÆ”„ÿÞε½¥÷ÖïÎçÆµœ¥Œœ„ÿÖέÿ„„„ÿÿÿ!ù0,—@˜pkÈ– 946—B'ÑØjuªEè±ÅátD&%“Ëy}^§‘xëõ¬N,ÒºXí>% •RU¥z(/!.K‚/‡ 0Ž‘—0¡« • ¹  B¼Ʊ À0½ÑÉ DÑCÕ×DA;tkabber-plugins/iconsets/kroc/services/gg_chat.gif000064400000000000000000000005341500237002100222060ustar00nobodynobodyGIF89aÕÿÿÿ÷ÿïÿçÞÆœŒ”„ÿÞε½¥÷ÖïÎçÆµœ­”¥ŒÿÖέ”{÷óæÿÿÿÿÞÞÞÖÖÖÌÌ̵µµ­­­¥¥¥™™™„„„{{{ÿÿÿ!ù ,y@p¢HJ946—B'ÑH¡ª 6  ʧò9RºŸÁ‡Ð–§^„I;žb5 ( nf€ ZPQ n‹ySu•ŽEUUOOZZP J¦–L²’©LBx¿A;tkabber-plugins/iconsets/kroc/services/gg_dnd.gif000064400000000000000000000005721500237002100220360ustar00nobodynobodyGIF89aÕ™Œ„{fZRJB3)Rc˜±Îï¹Ò­ÆŒ {ŒÛ÷ÎçÆÞ§º„”m{ëÿ÷ÿÿÿffÿÿÿ÷ÿïÿçÞÆ”„ÿÞε½¥÷ÖïÎçÆµœ¥Œœ„ÿÖέÿ„„„ÿÿÿ!ù0,—@˜pkÈ– 946—B'ÑØjuªEè±ÅátD&%“Ëy}^§‘xëõ¬N,ÒºXí>% •RU¥z(/!.K‚/‡ 0Ž‘—0¡« • ¹  B¼Ʊ À0½ÑÉ DÑCÕ×DA;tkabber-plugins/iconsets/kroc/services/gg_offline.gif000064400000000000000000000005241500237002100227100ustar00nobodynobodyGIF89aÕ”|yÿ‡„ÿ’Žÿ¾ª§™Ž„|rf^ÓÄÞîØãÿ ö ÿÿÿÿ&%ÿ+)ÿ33ÿLJÿSQÿZWÿ|yÿ™™$€€€ÿÿÿ!ù%,qÀ’pXÈÁ946—B'Ñ(øt4—"ô: eKô|Žˆ!…›Ž§³±@†í`Ñh2{R%!$ #’z$— oB œZ¢ ZGJOP­Cd°L¬¥´¥A;tkabber-plugins/iconsets/kroc/services/gg_online.gif000064400000000000000000000003361500237002100225530ustar00nobodynobodyGIF89aÄÿÿÿ÷ÿïÿçÞÆœŒ”„ÿÞε½¥Œ{÷ÖïÎçÆµœ­”¥Œœ„ÿÖέ”{ÿ„„„ÿÿÿ!ù,[ &ŽXEžhe¡£Ù®¢KšUÔ%|V ‹¸ . „pçH“IJT  ÂĉÔd¥ÃEë¸T–t‹A¸¸ Šé,ú0Pä¯Z‡Ÿ¢c:x,€…,#!;tkabber-plugins/iconsets/kroc/services/gg_xa.gif000064400000000000000000000005721500237002100217010ustar00nobodynobodyGIF89aÕ™Œ„{fZRJB3)Rc˜±Îï¹Ò­ÆŒ {ŒÛ÷ÎçÆÞ§º„”m{ëÿ÷ÿÿÿffÿÿÿ÷ÿïÿçÞÆ”„ÿÞε½¥÷ÖïÎçÆµœ¥Œœ„ÿÖέÿ„„„ÿÿÿ!ù0,—@˜pkÈ– 946—B'ÑØjuªEè±ÅátD&%“Ëy}^§‘xëõ¬N,ÒºXí>% •RU¥z(/!.K‚/‡ 0Ž‘—0¡« • ¹  B¼Ʊ À0½ÑÉ DÑCÕ×DA;tkabber-plugins/iconsets/kroc/services/icq_away.gif000064400000000000000000000001751500237002100224100ustar00nobodynobodyGIF89aòÿ€€€ÿÿÿÿÿÿ!ù,BHª@Ð+®Æ»ažíŒåÝðAU—Væ=*kZ&Ì3*â<íô=” H»[”A)˜a E¤f©I*.ëºÕ,;tkabber-plugins/iconsets/kroc/services/icq_chat.gif000064400000000000000000000002101500237002100223540ustar00nobodynobodyGIF89aò€ÿÿÿÿÿÿÿÿÿ!ù,MXºÀ"ž{Ë5ZÅSWêTÒ4¼°¦\Ä6>`› ÿ²†Kg{@žœnÄòTjFÕ†tÙQyÔ„FbÍ,§W¢–!—Ö";tkabber-plugins/iconsets/kroc/services/icq_dnd.gif000064400000000000000000000002161500237002100222100ustar00nobodynobodyGIF89aòÿ€ÿÿÿÿÿÿÿ!ù,SXºÀž{Ë5ZÅÓÅyA¥L• ê(Â0ijy:1!º€m,™N7Óœ(4âª$y²åe’Ûõ.Àà,jÜp+UÉÖ°|HäÌ×úeºåE;tkabber-plugins/iconsets/kroc/services/icq_offline.gif000064400000000000000000000001321500237002100230620ustar00nobodynobodyGIF89aðÿÿÿ!ù,1Œȸ™”[/¾k48êJ[¥Œe zG¦d¡*´Å§¨uõÅ;9,ƒùD”ëU+;tkabber-plugins/iconsets/kroc/services/icq_online.gif000064400000000000000000000001771500237002100227350ustar00nobodynobodyGIF89aòÿÿÿÿÿÿÿÿÿ!ù,DHºÀž{Ë5ZÅÓÅyA¥LÝ8J_ˆbØ]Ú9N‚ðÂÓ7䨈†#™ŒDâFøje’Ñt²´‚°§ÆS“tc‹;tkabber-plugins/iconsets/kroc/services/icq_xa.gif000064400000000000000000000002011500237002100220450ustar00nobodynobodyGIF89aòÿÿÿÿÿÿÿÿ!ù,FHºÀž{Ë5ZÅÓÅyA¥hªª:¼pü¦ÃTáízvøN»ZOè Þ†7£ï–tÉž¨ÖjmX>$$gF. !;tkabber-plugins/iconsets/kroc/services/jud.gif000064400000000000000000000003001500237002100213630ustar00nobodynobodyGIF89añÿÿÿÿÿ!ù,‘ܸqãÆ7nܸqãF€1nܸqã@€nܸ @€nÜ8 @€1nÜ @€1nÜ DnÜ¢D€1nÜ D‰1nÜ8¢D7nܸ¢D7nܸ"@€7nÜ8¢À7n܈q À7nܸqãFŒ7nܸqãÆ7n;tkabber-plugins/iconsets/kroc/services/msn_away.gif000064400000000000000000000003661500237002100224330ustar00nobodynobodyGIF89aô*UU€*ªÿª€€Ÿªßÿÿÿ*ÿÿ€€€€€€€  ¤Ô¿ªÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù,s %RG ˆAQ £XN‡ ‹â(¬{ÀðLÀçŠì8æ^£ÐhNž’CÖX' Áè€8<BB¡XZ$€\Ĩ¿áø¼N6×C!1'x%F0€2ƒY<1hp%HGcZG0Fˆce”‚"!;tkabber-plugins/iconsets/kroc/services/msn_chat.gif000064400000000000000000000002621500237002100224040ustar00nobodynobodyGIF89aó ÿ€€Ÿªÿÿ€€€  ¤ª¿ªÔ¿ªÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù ,_I&*!‡)ÅX‚K¹l‚¤¨ ¨BšÄ™‚‰Ðj0Éà0@ ¾!8©—W†ÓX1(ªvªe ŽÖK—B3ÄÔŠdF7×4¤›,8”ŸîÊl%sœ€r;tkabber-plugins/iconsets/kroc/services/msn_dnd.gif000064400000000000000000000002541500237002100222330ustar00nobodynobodyGIF89aó €€Ÿª€ªÿ€€€ªŸª  ¤ª¿ªÔ¿ªÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù,YÐÉ)ƒ4Kš0˜Vu‚ŠN§.A¨YMˆ› -šr<›£@,TÈL±è[.wHW¡A­Ã'4­R¯tè$J»yIPå‚’%6{»x‹ÞŒ;tkabber-plugins/iconsets/kroc/services/msn_offline.gif000064400000000000000000000002321500237002100231040ustar00nobodynobodyGIF89a󀪀€€ª¿ªÔ¿ªÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù ,G0É*˜WÆÍTÀq(…ÁnѹY`¬@×U ›€H,V¿¤ß¹Óºy÷ݱÿùëÿÿÿ!ù,BxºÜ+0JÈ„¹8‹z§5ÛsdÙqY*Öà¾.ÈtMË"ñ.Ú»@!˜Ó3Ûp·:´ŒÄ_-¸D²R;Œå™(;tkabber-plugins/iconsets/kroc/services/rss_offline.gif000064400000000000000000000001671500237002100231250ustar00nobodynobodyGIF89aò¿¤ß¹Óºy÷ݱÿùëÿÿÿ!ù,²U*×kàš»’òÙL¯©|È©?";tkabber-plugins/iconsets/kroc/services/weather_xa.gif000064400000000000000000000001701500237002100227350ustar00nobodynobodyGIF89aÂnnn¶¶¶Ž«ÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,=xºÜþ° ¢AˆP™¶u¦q¢Ø™b˜®i¬^²¼º5·|ü· €$€Çb’DN’ÄÆà¢˜–,‘;tkabber-plugins/iconsets/kroc/services/yahoo_away.gif000064400000000000000000000002471500237002100227530ustar00nobodynobodyGIF89aó €ÿŸÿÿª€€ªª€€ÿÿ€€€ÿÿÿÿÿÿ!ù ,TÉI«½X€Pf["&݈Kº$‹WêH¾ì¬·èjµ’ú: @ ÈF»  uA†2X8;Q)!usÊ’Ààf[! ”©Š`à\”Kö‡a¨>;tkabber-plugins/iconsets/kroc/services/yahoo_chat.gif000064400000000000000000000003461500237002100227310ustar00nobodynobodyGIF89aô*?UU?UU_U_U€ߪ€ªÿ€€ÿÿ€€€  ¤ª¿ªªßªÔ¿ÿÔߪÀÜÀÿÿÿÿÿÿ!ù,c %ŽdiR­ë0˜‚1ÍtKÏÌFµmH£‹ nÇ›3‘68Î “TcH<'ÂL\/r4Òqq`' Ei~H$êy&slHz‚Vy†'F?‹Œ$!;tkabber-plugins/iconsets/kroc/services/yahoo_dnd.gif000064400000000000000000000002411500237002100225510ustar00nobodynobodyGIF89aó €Ÿ€ªÿ€€ÿÿ€€€ÿÿÿÿÿÿ!ù ,NPÉI«½X`LVÛ!‚gb¢&GbRè:¯Ö&›‹uœ * 6 fCMaY8Ò’&$ƒÕÊI›dµ *­•69—òðÁŒŸ;tkabber-plugins/iconsets/kroc/services/yahoo_offline.gif000064400000000000000000000002331500237002100234270ustar00nobodynobodyGIF89aó Ÿª€€ª¿ª¦ÊðÔ¿ªÔ¿ÿÀÜÀÿÿÿÿÿÿ!ù ,HPÉI«½XŽ0FVÝ‘ Iw ‰(’ˆW ¤‘&²;ÁcBг &‚N¢Ä)Q2Q!Gò¡’Lšï×Ħ ’HV»s†àÓ1}ÎhJ;tkabber-plugins/iconsets/kroc/services/yahoo_online.gif000064400000000000000000000002251500237002100232720ustar00nobodynobodyGIF89aó €€ÿ€€ÿÿ€€€ªŸª  ¤¦ÊðÀÜÀÿÿÿÿÿÿ!ù ,BÉI«½X@Hf[!݈Kº‹WêH¾ì¬·èjì( ƒBG9ÉŽ;H ‹ËÁ€9£Ÿ/ت”Ùp>àp%;tkabber-plugins/iconsets/kroc/services/yahoo_xa.gif000064400000000000000000000002451500237002100224200ustar00nobodynobodyGIF89aó €Ÿ€ªÿ€€€€ÿÿ€€€ÿÿÿÿÿÿ!ù ,RpÉI«½XpN^""݈Jª ŠWêˆ/«+.ºš¤¿¥@,ÈF„I!PwÂÅ’™*t¢RUÓ9Ñ$SŶÐ-)©ÕÁ·RØ* ƒO‘œ‰;tkabber-plugins/iconsets/kroc/tkabber000075500000000000000000000000001500237002100176315ustar00nobodynobodytkabber-plugins/iconsets/kroc/tkabber/gpg-badsigned.gif000064400000000000000000000003551500237002100230750ustar00nobodynobodyGIF89aòW”Y•×”””ÀÀÀÿÿÿ!ù,²XUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUUXUU…UUXUU…UU…UUUXUU…@@XUU…UUU(@4‚PUXUU…(PU…"""(…PUX%"‚RUUX;tkabber-plugins/iconsets/kroc/tkabber/gpg-encrypted.gif000064400000000000000000000005601500237002100231500ustar00nobodynobodyGIF89aônH}VHHHTTTfffxxx‡^›q´‰1ÈDÕ©Qáµ`÷Ê|†††˜˜˜¦¦¦···ÿç¨ÈÈÈÚÚÚæææÿÿÿ!ù,í eY–eY––eY–eY–eY€Ô€K‚€eY–eY–eR €eY–Z–e `Y–$€eY–eY–,€eY(€eY–eY–$À–eY–eY @EM€€eY–epQ=@€`Y–eÕDc<`€eY–PB@Ža€eY–P†AhY–Dd@FA–eYA DE1–eY=@TÃX–e–EQA `Y–eY–€e…;tkabber-plugins/iconsets/kroc/tkabber/gpg-signed.gif000064400000000000000000000004401500237002100224210ustar00nobodynobodyGIF89aó ===W”Y•בY<¾‚dÎ’t”””ŽÃñÖž„ó¾«ÀÀÀÿÿÿ!ù ,Í1ÆcŒ1Æ€€1ÆcŒ1Æd €DcŒ1Æ cŒ1H" 0cŒ1Æ$h`Œ1ÆcŒA@I*Æc 2Æ©ec1ÆcŒD’‚0ÆcŒ1ÆcŒ1Æ cŒÀcŒ1cŒ1Æ`Œ1ÈcŒ1Æc @Àc c 2ÆŒ1ÆÀZðÆcŒÆƒŒ1°cŒ1ÆdŒ1ÆX'Æ cŒ1Æ  Ç€1ÆcŒ1ÈX;tkabber-plugins/iconsets/kroc/tkabber/gpg-unencrypted.gif000064400000000000000000000005601500237002100235130ustar00nobodynobodyGIF89aônH}VFFFTTTfffxxx‡^›q´‰1ÈDÕ©Qáµ`÷Ê|†††˜˜˜¦¦¦···ÿç¨ÈÈÈÚÚÚæææÿÿÿ!ù,í e€eY–eY–eY 5K‚€e–eY–eY€Ô`Y–eY–e Z–e `Y–eY–e `Y–(€eYhY–e `Y–0– €eY @EMÑ €€eQ=0€`–eÕDc<Î`€eY–PB@Ža€eY–PFAhY–Dd@FA–eYA DE1–eY=@TÃX–e–EQA `Y–eY–€e…;tkabber-plugins/iconsets/kroc/tkabber/gpg-unsigned.gif000064400000000000000000000003551500237002100227710ustar00nobodynobodyGIF89aò===W”Y•×”””ŽÃñÀÀÀÿÿÿ!ù,²xww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡wwwxww‡www‡wwwxww€fwxww‡wwwx`p‡wwwxww‡Fxww‡wwwxP3ƒwwxww‡w—;tkabber-plugins/iconsets/kroc/tkabber/toolbar-add-user.gif000064400000000000000000000002071500237002100235420ustar00nobodynobodyGIF89aÂÿ)%¿ÿ*ÿÿÿÿÿÿÿÿÿÿ!ù ,LxºÜþ0ÊI«½oÛ#Œ‚¤}qŒA H ˃ÐÞo”Ûp»”íÈM6„Vw.ÍÀÓhQ21Òë%[¤Zf…7L.›ÏhI;tkabber-plugins/iconsets/kroc/tkabber/toolbar-disco.gif000064400000000000000000000002031500237002100231330ustar00nobodynobodyGIF89aÂÿ)%¿µ!ÿ²ÿÿÿÿÿÿÿÿÿ!ù ,HxºÜþ0ÊIkxX7ˆÏ™Õyäw¨p•å 0°²Ïô`Ë8«ßXy »ÍéH´ÀÍ 3J™xÊ+VyØr¿à°xÌM;tkabber-plugins/iconsets/kroc/tkabber/toolbar-join-conference.gif000064400000000000000000000003161500237002100251030ustar00nobodynobodyGIF89aã ÿ)%¿þÿüôÿ–Áàœÿ²ÿÿÿÿÿÿÿÿÿÿÿ!ù ,{ðÉI«½8ë*ºØWŒÈhiJJ®¬û®mРK¾€õ( †ð@!Û(("Peäc6 Ьt¢ X›†lb+é2Í‚xl¸Ï×DCÛžÑ ¬œžâó{l XsQƒx‚Dn dnd0™0œž0;tkabber-plugins/iconsets/kroc/tkabber/toolbar-show-offline.gif000064400000000000000000000002241500237002100244350ustar00nobodynobodyGIF89aÂÿ)%¿ŒŒŒ···ÿÿÿÿÿÿÿÿÿ!ù ,YxºÜþ0ÊI߸£¶K:ÐËÐ(ŽD©( ¼ÂtãܪÕÑpÿ9‡ˆçúá$»šñ!ð¾@ˆ$F§Ì`«ðaƒÜ O¤TÐ]6O¶nJ\M¯Ûïš;tkabber-plugins/iconsets/kroc/tkabber/toolbar-show-online.gif000064400000000000000000000001641500237002100243020ustar00nobodynobodyGIF89aÂÿ)%¿ÿ*ÿÿÿÿÿÿÿÿÿÿ!ù ,9xºÜþ0ÊI«½8ë*ºÐ] ™ žäežAj­¬K­ªŠõˆ™¹\á6L ×Ê G¾ `¹9$›Ð¨š;tkabber-plugins/iconsets/msgs000075500000000000000000000000001500237002100162325ustar00nobodynobodytkabber-plugins/iconsets/msgs/ru.msg000064400000000000000000000005201500237002100174440ustar00nobodynobody# ru.msg -- # # Russian messages for the Iconsets Tkabber plugin. # # Author: Sergei Golovan. ::msgcat::mcset ru "Whether the Iconsets plugin is loaded."\ "Загружено ли раÑширение, Ñодержащее дополнительные наборы пиктограмм." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/iconsets/msgs/uk.msg000064400000000000000000000005131500237002100174370ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Iconsets Tkabber plugin. # # Author: Sergei Golovan. ::msgcat::mcset uk "Whether the Iconsets plugin is loaded."\ "Чи завантажене розширеннÑ, Ñке міÑтить додаткові наборі піктограм." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/iconsets/psi000075500000000000000000000000001500237002100160545ustar00nobodynobodytkabber-plugins/iconsets/psi/icondef.xml000064400000000000000000000051331500237002100202660ustar00nobodynobody Psi 1.0 Tkabber's Psi Iconset. 2006-01-21 toolbar/add-user tkabber/toolbar-add-user.gif toolbar/disco tkabber/toolbar-disco.gif toolbar/join-conference tkabber/toolbar-join-conference.gif toolbar/show-offline tkabber/toolbar-show-offline.gif toolbar/show-online tkabber/toolbar-show-online.gif browser/client roster/available.gif browser/user roster/available.gif roster/user/chat roster/available-chat.gif roster/user/available roster/available.gif roster/user/away roster/available-away.gif roster/user/xa roster/available-xa.gif roster/user/dnd roster/available-dnd.gif roster/user/unavailable roster/unavailable.gif roster/user/unsubscribed roster/stalker.gif roster/user/error roster/unavailable.gif roster/group/closed roster/group-closed.gif roster/group/opened roster/group-opened.gif tkabber-plugins/iconsets/psi/roster000075500000000000000000000000001500237002100173725ustar00nobodynobodytkabber-plugins/iconsets/psi/roster/available-away.gif000064400000000000000000000002031500237002100230120ustar00nobodynobodyGIF89aÂÿÿÿÞÞÞ¿¿¿¡hþö¼ÿÿÿÿÿÿ!ù ,HxºÀ ^”TÔ»¦ÞãdŸøLù}Ã0®°Ðºaß¶6[DáÿYËR+àŒ;Fïç#$½£óYd"©Ñ›€µ%îvI;tkabber-plugins/iconsets/psi/roster/available-chat.gif000064400000000000000000000001751500237002100230000ustar00nobodynobodyGIF89aÂÿÿÿûùûÛ!ù ,BHºÀ ^”TÔ»¦ÞãdŸøLåh«0 c9°ó 7_®Ù®»¯žPùÀn¡™)˜´9™§C*á ­GVȹ$;tkabber-plugins/iconsets/psi/roster/available-dnd.gif000064400000000000000000000002061500237002100226210ustar00nobodynobodyGIF89aÂÿÿÿÞÞÞ¿¿¿ÿÿÿÿÿÿÿÿÿÿ!ù ,KxºÀ ^”TÔ»¦ÞãdŸøLA ~ß0Œ!¬û6“L¨šm¡] àSd©dhiè’:f©œ¹š@¡ªØ "ÜéÌ踈8‡;tkabber-plugins/iconsets/psi/roster/available-xa.gif000064400000000000000000000001711500237002100224650ustar00nobodynobodyGIF89aÂÿÿÿÞÞÞ¿¿¿ÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,>HºÀ ^”TÔ»¦ÞãdŸøLù}Ã0®°ÐºM̶VϹÀ¼` ™áBÆ$­ct4%ÁF´ãT9XB;tkabber-plugins/iconsets/psi/roster/available.gif000064400000000000000000000001711500237002100220570ustar00nobodynobodyGIF89aÂÿÿÿûùûÛÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,>HºÀ ^”TÔ»¦ÞãdŸøLù}Ã0®°ÐºM̶VϹÀ¼` ™áBÆ$­ct4%ÁF´ãT9XB;tkabber-plugins/iconsets/psi/roster/group-closed.gif000064400000000000000000000001301500237002100225350ustar00nobodynobodyGIF89a Âÿÿÿ†ËñY„Áÿÿÿÿÿÿÿÿÿÿÿÿ!ù , HºÜÀ1¢|AXG…–0lK8rÙ‰ªÜwAWL$;tkabber-plugins/iconsets/psi/roster/group-opened.gif000064400000000000000000000001271500237002100225440ustar00nobodynobodyGIF89a Âÿÿÿ…ÊðXƒÀÿÿÿÿÿÿÿÿÿÿÿÿ!ù , HºÜþ02@«U è­ÁBÞ$’0 %½P;tkabber-plugins/iconsets/psi/roster/stalker.gif000064400000000000000000000001611500237002100216030ustar00nobodynobodyGIF89aÂZZZ:::uuuRRR™™™™™™™™™!ù ,6xº7ýáT¡®{²uœB$¥ABx æy°ŠÊÀ‹‘ áŒ~3„íÀ-`Å¢‚48]§;tkabber-plugins/iconsets/psi/roster/unavailable.gif000064400000000000000000000001711500237002100224220ustar00nobodynobodyGIF89a¦¦¦sssYYYÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,>HºÀ ^”TÔ»¦ÞãdŸøLù}Ã0®°ÐºM̶VϹÀ¼` ™áBÆ$­ct4%ÁF´ãT9XB;tkabber-plugins/iconsets/psi/tkabber000075500000000000000000000000001500237002100174665ustar00nobodynobodytkabber-plugins/iconsets/psi/tkabber/toolbar-add-user.gif000064400000000000000000000002031500237002100233730ustar00nobodynobodyGIF89aÂY„ÁEuÿÿÿ†Ëñÿÿÿÿÿÿÿÿÿÿÿÿ!ù,HHºÜþ0ÊI«½è0B8 Žcy¨*mš€’\Þ3î6ìì“¶ßoÇè SÁc+h6e-'ñaœ¾ Hˆ‘:=à°xI;tkabber-plugins/iconsets/psi/tkabber/toolbar-disco.gif000064400000000000000000000002311500237002100227710ustar00nobodynobodyGIF89a€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,^xºÜþ0ÊI«½ ©#Áö|!‚蜩9tŒ ¼.@È·2«Ù+ä¶ßfW; ã8¢)“ ¡sõA­Lª 'ÊöN@$púUÍÞ˜ó5“Õªv4½ÐðV0Œ~ÏïC;tkabber-plugins/iconsets/psi/tkabber/toolbar-join-conference.gif000064400000000000000000000006061500237002100247420ustar00nobodynobodyGIF89a¥ÔßÿU_Uÿûð€€€*?UUU?Uª_UUUÿ¿ªÿߪÿŸªÿŸUÿªÿ_ªÿ¿UÔŸªªŸÿÔŸÿªÿ_ÿÿ_UÿUÿÔU*ÿÿªÿÿ?Uÿÿ?UÿŸÿ_U_ÿ?ÿÿUU?ÿ*ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ?,£ÀŸpH,ȤrÉl2€"Ô ¢BÀàÚ Q(ÀpÀ*ˆDx P˜“€£á€ÊÈû—G¼P y{R…Rˆ’DuŒž œ!K"#$%¥&^p¸¹''±&¿ÁÂH¸¬'(ÉOb±SNY(ਵÝÞåæçèéA;tkabber-plugins/iconsets/psi/tkabber/toolbar-show-offline.gif000064400000000000000000000002441500237002100242740ustar00nobodynobodyGIF89a¦¦¦sssÿÿÿûùûÛYYYÿÿÿ!ù ,ixºÜþ0ÊI‚ pf› b׎À@xÚuŽ*±jA-Þ]Ù{ü. %…†‡ˆ ;tkabber-plugins/iconsets/psi/tkabber/toolbar-show-online.gif000064400000000000000000000002101500237002100241270ustar00nobodynobodyGIF89aÂÿÿÿûùûÛÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,MHºÜþ0ÊI«½Ü@GxBb¤iiÚWšläîkÃÙÕö‹ç²Þ §{„‚_r3ƒÒZ—ÀT³¥h©#eFȉÎè´:;tkabber-plugins/jidlink000075500000000000000000000000001500237002100150565ustar00nobodynobodytkabber-plugins/jidlink/README000064400000000000000000000015401500237002100160150ustar00nobodynobodyJidlink is a simple negotiation protocol for setting up a bytestream between two JIDs. With it you can specify what transports you can use, and via negotiation choose more appropriate one. There are three transport implementations: dtcp-active: that allows you to connect to any node that supports "dtcp-passive"; dtcp-passive: that allows any node that supports "dtcp-active" to connect to you; and, inband-bytestream: that uses your "Jabber" connection to transmit the data (which may slowdown other traffic to you). If your machine is behind a firewall, then you can't use the "dtcp-passive" transport, so you should disable it in a config file: set jidlink::transport(allowed,dtcp-passive) 0 Jidlink is undocumented and obsolete, but it may be useful for file transfer to old Tkabber clients which don't support Stream Initiation protocol. tkabber-plugins/jidlink/jidlink.tcl000064400000000000000000000160051500237002100172670ustar00nobodynobody# jidlink.tcl -- # # This file is a part of the Jidlink plugin for the Tkabber XMPP client. package require msgcat namespace eval ::jidlink { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered jidlink]} { ::plugins::register jidlink \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Jidlink\ plugin is loaded."] \ -loadcommand \ [namespace code \ [list load [file dirname [info script]]]] \ -unloadcommand [namespace code unload] return } variable transport set transport(list) {} } proc ::jidlink::load {dir} { ::xmpp::negotiate::register jabber:iq:jidlink ::jidlink::negotiate_handler ::xmpp::iq::register set query jabber:iq:jidlink ::jidlink::set_handler # Loading jidlink plugins foreach file [lsort [glob -nocomplain [file join $dir plugins]/*.tcl]] { debugmsg jidlink "Loading plugin from $file" source $file } ::trans::load [file join $dir trans] foreach ns [namespace children] { ${ns}::load } setup_customize } proc ::jidlink::unload {} { foreach ns [namespace children] { ${ns}::unload } ::xmpp::negotiate::unregister jabber:iq:jidlink ::xmpp::iq::unregister set query jabber:iq:jidlink } package require xmpp::negotiate proc ::jidlink::connect {xlib jid {key {}}} { variable connection if {$key == ""} { set key [rand 1000000000] } #set connection(sf,$key) $send_func #set connection(rf,$key) $recv_func set connection(xlib,$key) $xlib set connection(jid,$key) $jid set_status [::msgcat::mc "Opening Jidlink connection"] ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create query \ -xmlns jabber:iq:jidlink \ -subelement [::xmpp::xml::create key -cdata $key]] \ -to $jid \ -command [list [namespace current]::connect_response $xlib $jid $key] vwait [namespace current]::connection(status,$key) return connection(status,$key) } proc ::jidlink::connect_response {xlib jid key status xml} { variable connection variable transport if {$status != "ok"} { # TODO set connection(status,$key) 0 return } set trans [lsort -unique -index 1 $transport(list)] set options {} foreach t $trans { set name [lindex $t 0] if {![info exists transport(allowed,$name)] || \ $transport(allowed,$name)} { lappend options $name } } if {[llength $options] == 0} { # TODO set connection(status,$key) 0 return } ::xmpp::negotiate::sendOptions $xlib $jid jabber:iq:jidlink $options \ -command [namespace code [list negotiate_recv_response \ $xlib $jid $key $options]] } proc ::jidlink::negotiate_recv_response {xlib jid key options status opts} { variable connection variable transport if {$status != "ok"} { set connection(status,$key) 0 return } foreach {tag field} $opts { if {$tag != "field"} continue lassign $field var type label values if {$var != "jabber:iq:jidlink"} continue set name [lindex $values 0] if {[lsearch -exact $options $name] >= 0} { set connection(transport,$key) $name eval $transport(connect,$name) [list $xlib $jid $key] set connection(status,$key) 1 return } } set connection(status,$key) 0 } proc ::jidlink::set_readable_handler {key handler} { variable connection set connection(readable_handler,$key) $handler } proc ::jidlink::set_closed_handler {key handler} { variable connection set connection(closed_handler,$key) $handler } proc ::jidlink::send_data {key data} { variable connection variable transport eval $transport(send,$connection(transport,$key)) [list $key $data] } proc ::jidlink::recv_data {key data} { variable connection debugmsg jidlink "RECV_DATA [list $key $data]" append connection(data,$key) $data if {[info exists connection(readable_handler,$key)]} { eval $connection(readable_handler,$key) [list $key] } } proc ::jidlink::read_data {key} { variable connection set data $connection(data,$key) set connection(data,$key) {} return $data } proc ::jidlink::close {key} { variable connection variable transport eval $transport(close,$connection(transport,$key)) [list $key] set_status [::msgcat::mc "Jidlink connection closed"] } proc ::jidlink::closed {key} { variable connection if {[info exists connection(closed_handler,$key)]} { eval $connection(closed_handler,$key) [list $key] } } proc ::jidlink::negotiate_handler {xlib from options args} { variable transport set trans [lsort -unique -index 1 $transport(list)] set myoptions {} foreach t $trans { set name [lindex $t 0] if {![info exists transport(allowed,$name)] || \ $transport(allowed,$name)} { lappend myoptions $transport(oppos,$name) } } if {$options == {}} { # Options request return $myoptions } else { foreach opt $options { if {[lsearch -exact $myoptions $opt] >= 0} { return [list $opt] } } } return {} } proc ::jidlink::set_handler {xlib from xml args} { debugmsg jidlink "set: [list $from $xml]" ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {$tag == "query"} { foreach item $subels { ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels if {$stag == "key"} { set key $scdata debugmsg jidlink "KEY: $key" } } if {[info exists key]} { return [list result $xml] } else { # TODO } } else { # TODO } } proc ::jidlink::register_transport \ {name oppos prio default connect send close} { variable transport lappend transport(list) [list $name $prio] set transport(oppos,$name) $oppos set transport(connect,$name) $connect set transport(send,$name) $send set transport(close,$name) $close if {$default == "enabled"} { set transport(default,$name) 1 } else { set transport(default,$name) 0 } } proc ::jidlink::setup_customize {} { variable transport foreach t [lsort -unique -index 1 $transport(list)] { lassign $t name prio custom::defvar transport(allowed,$name) $transport(default,$name) \ [::msgcat::mc "Enable Jidlink transport %s." $name] \ -type boolean -group Jidlink } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/jidlink/msgs000075500000000000000000000000001500237002100160275ustar00nobodynobodytkabber-plugins/jidlink/msgs/de.msg000064400000000000000000000033171500237002100172120ustar00nobodynobody# de.msg -- # # German messages for the Jidlink Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 01.04.2009 # .../jidlink.tcl ::msgcat::mcset de "Enable Jidlink transport %s." \ "'Jidlink'-Transport %s aktivieren." ::msgcat::mcset de "Jidlink connection closed" \ "'Jidlink'-Verbindung geschlossen" ::msgcat::mcset de "Opening Jidlink connection" "Öffne 'Jidlink'-Verbindung" ::msgcat::mcset de "Whether the Jidlink plugin is loaded." \ "'Jidlink'-Plugin laden." # .../plugins/ibb.tcl ::msgcat::mcset de "Opening IBB connection" "Öffne IBB-Verbindung" # .../plugins/filetransfer.tcl ::msgcat::mcset de "Browse..." "Durchsuchen..." ::msgcat::mcset de "Cancel" "Abbrechen" ::msgcat::mcset de "Connection closed" "Verbindung geschlossen" ::msgcat::mcset de "Description:" "Beschreibung:" ::msgcat::mcset de "Jidlink connection failed" \ "'Jidlink'-Verbindung misslungen" ::msgcat::mcset de "Jidlink options." "Optionen für 'Jidlink'." ::msgcat::mcset de "Jidlink transfer failed" "'Jidlink'-Übertragung misslungen" ::msgcat::mcset de "Name:" "Name:" ::msgcat::mcset de "Receive" "Empfangen" ::msgcat::mcset de "Receive file from %s" "Empfange Datei von %s" ::msgcat::mcset de "Receiving file failed: %s" "Datei-Empfang misslungen: %s" ::msgcat::mcset de "Request failed: %s" "Anfrage misslungen: %s" ::msgcat::mcset de "Save as:" "Speichern als:" ::msgcat::mcset de "Size:" "Größe:" ::msgcat::mcset de "Transferring..." "Übertrage . . ." # .../plugins/dtcp.tcl ::msgcat::mcset de "Opening DTCP active connection" \ "Öffne aktive DTCP-Verbindung" ::msgcat::mcset de "Opening DTCP passive connection" \ "Öffne passive DTCP-Verbindung" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/jidlink/msgs/es.msg000064400000000000000000000030501500237002100172230ustar00nobodynobody# es.msg -- # # Spanish messages for the Jidlink Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "Browse..." "Navegar..." ::msgcat::mcset es "Cancel" "Cancelar" ::msgcat::mcset es "Connection closed" "Conexión cerrada" ::msgcat::mcset es "Description:" "Descripción:" ::msgcat::mcset es "Enable Jidlink transport %s." \ "Actibar transporte Jidlink %s." ::msgcat::mcset es "Jidlink connection closed" "Conexión Jidlink cerrada" ::msgcat::mcset es "Jidlink connection failed" "Falló la conexión Jidlink" ::msgcat::mcset es "Jidlink options." "Opciones Jidlink." ::msgcat::mcset es "Jidlink transfer failed" "Falló la transferencia Jidlink" ::msgcat::mcset es "Name:" "Nombre:" ::msgcat::mcset es "Opening DTCP active connection" \ "Abriendo conexión activa DTCP" ::msgcat::mcset es "Opening DTCP passive connection" \ "Abriendo conexión pasiva DTCP" ::msgcat::mcset es "Opening IBB connection" "Abriendo conexión IBB" ::msgcat::mcset es "Opening Jidlink connection" "Abriendo conexión Jidlink" ::msgcat::mcset es "Receive file from %s" "Recibir fichero de %s" ::msgcat::mcset es "Receive" "Recibir" ::msgcat::mcset es "Receiving file failed: %s" \ "Falló la recepción del fichero: %s" ::msgcat::mcset es "Request failed: %s" "Falló la petición: %s" ::msgcat::mcset es "Save as:" "Guardar como:" ::msgcat::mcset es "Size:" "Tamaño:" ::msgcat::mcset es "Transferring..." "Transfiriendo..." ::msgcat::mcset es "Whether the Jidlink plugin is loaded." \ "Cargar el plugin Jidlink." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/jidlink/msgs/pl.msg000064400000000000000000000032531500237002100172340ustar00nobodynobody# pl.msg -- # # Polish messages for the Jidlink Tkabber plugin. # # Author: Irek Chmielowiec # jidlink.tcl ::msgcat::mcset pl "Enable Jidlink transport %s." "Włącz transport Jidlink %s." ::msgcat::mcset pl "Jidlink connection closed" "Otwieranie połączenia Jidlink" ::msgcat::mcset pl "Opening Jidlink connection" "Połączenie Jidlink zamkniÄ™te" # plugins/dtcp.tcl ::msgcat::mcset pl "Opening DTCP active connection" \ "Otwieranie aktywnego połączenia DTCP" ::msgcat::mcset pl "Opening DTCP passive connection" \ "Otwieranie pasywnego połączenia DTCP" # plugins/ibb.tcl ::msgcat::mcset pl "Opening IBB connection" "Otwieranie połącznia IBB" # plugins/filetransfer.tcl ::msgcat::mcset pl "Browse..." "PrzeglÄ…daj..." ::msgcat::mcset pl "Cancel" "Anuluj" ::msgcat::mcset pl "Connection closed" "Połączenie zamkniÄ™te" ::msgcat::mcset pl "Description:" "Opis:" ::msgcat::mcset pl "Jidlink connection failed" \ "Połączenie za pomocÄ… protokoÅ‚u Jidlink nie udaÅ‚o siÄ™" ::msgcat::mcset pl "Jidlink options." "Ustawienia protokoÅ‚u Jidlink." ::msgcat::mcset pl "Jidlink transfer failed" \ "PrzesÅ‚anie pliku za pomocÄ… protokoÅ‚u Jidlink nie udaÅ‚o siÄ™" ::msgcat::mcset pl "Name:" "Nazwa:" ::msgcat::mcset pl "Receive" "Odbierz" ::msgcat::mcset pl "Receive file from %s" "Odbierz plik od %s" ::msgcat::mcset pl "Receiving file failed: %s" \ "Nie udaÅ‚o siÄ™ odebrać pliku: %s" ::msgcat::mcset pl "Request failed: %s" "WywoÅ‚anie nie powiodÅ‚o siÄ™: %s" ::msgcat::mcset pl "Save as:" "Zapisz jako:" ::msgcat::mcset pl "Size:" "Rozmiar:" ::msgcat::mcset pl "Transferring..." "PrzesyÅ‚anie..." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/jidlink/msgs/ru.msg000064400000000000000000000037341500237002100172530ustar00nobodynobody# ru.msg -- # # Russian messages for the Jidlink Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Browse..." "Выбрать..." ::msgcat::mcset ru "Cancel" "Отменить" ::msgcat::mcset ru "Connection closed" "Соединение закрыто" ::msgcat::mcset ru "Description:" "ОпиÑание:" ::msgcat::mcset ru "Enable Jidlink transport %s." \ "Разрешить иÑпользование Jidlink-транÑпорта %s" ::msgcat::mcset ru "Jidlink connection closed" "Соединение Jidlink закрыто" ::msgcat::mcset ru "Jidlink connection failed" \ "СоединитьÑÑ Ð¿Ð¾ Jidlink не удалоÑÑŒ" ::msgcat::mcset ru "Jidlink options." "Параметры Jidlink-транÑпорта." ::msgcat::mcset ru "Jidlink transfer failed" \ "Передать файл по Jidlink не удалоÑÑŒ" ::msgcat::mcset ru "Name:" "ИмÑ:" ::msgcat::mcset ru "Opening DTCP active connection" "Открываем Ñоединение DTCP" ::msgcat::mcset ru "Opening DTCP passive connection" "Соединение DTCP закрыто" ::msgcat::mcset ru "Opening IBB connection" "Открываем Ñоединение IBB" ::msgcat::mcset ru "Opening Jidlink connection" "Открываем Ñоединение Jidlink" ::msgcat::mcset ru "Receive" "Получить" ::msgcat::mcset ru "Receive file from %s" "Получение файла от %s" ::msgcat::mcset ru "Receiving file failed: %s" "Получение файла не удалоÑÑŒ: %s" ::msgcat::mcset ru "Request failed: %s" "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ðµ удалÑÑ: %s" ::msgcat::mcset ru "Save as:" "Сохранить как:" ::msgcat::mcset ru "Size:" "Размер:" ::msgcat::mcset ru "Transferring..." "Передача файла..." ::msgcat::mcset ru "Whether the Jidlink plugin is loaded."\ "Загружено ли раÑширение передачи файлов по протоколу Jidlink." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/jidlink/msgs/uk.msg000064400000000000000000000037321500237002100172420ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Jidlink Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Browse..." "Вибрати..." ::msgcat::mcset uk "Cancel" "Відмінити" ::msgcat::mcset uk "Connection closed" "Ð—â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ðµ" ::msgcat::mcset uk "Description:" "ОпиÑ:" ::msgcat::mcset uk "Enable Jidlink transport %s." \ "Дозволити викориÑÑ‚Ð°Ð½Ð½Ñ Jidlink-транÑпорту %s" ::msgcat::mcset uk "Jidlink connection closed" "Ð—â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Jidlink закрите" ::msgcat::mcset uk "Jidlink connection failed" \ "З’єднатиÑÑ Ð¿Ð¾ Jidlink не вдалоÑÑ" ::msgcat::mcset uk "Jidlink options." "Параметри Jidlink-транÑпорту." ::msgcat::mcset uk "Jidlink transfer failed" \ "Передати файл по Jidlink не вдалоÑÑ" ::msgcat::mcset uk "Name:" "Им’Ñ:" ::msgcat::mcset uk "Opening DTCP active connection" "Відкриваємо Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ DTCP" ::msgcat::mcset uk "Opening DTCP passive connection" "Ð—â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ DTCP закрите" ::msgcat::mcset uk "Opening IBB connection" "Відкриваємо Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ IBB" ::msgcat::mcset uk "Opening Jidlink connection" "Відкриваємо Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Jidlink" ::msgcat::mcset uk "Receive" "Отримати" ::msgcat::mcset uk "Receive file from %s" "ÐžÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ð° від %s" ::msgcat::mcset uk "Receiving file failed: %s" "Отримати файл не вдалоÑÑ: %s" ::msgcat::mcset uk "Request failed: %s" "Запит не вдавÑÑ: %s" ::msgcat::mcset uk "Save as:" "Зберегти Ñк:" ::msgcat::mcset uk "Size:" "Розмір:" ::msgcat::mcset uk "Transferring..." "Передача файла..." ::msgcat::mcset uk "Whether the Jidlink plugin is loaded."\ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ñ– файлів по протоколу Jidlink." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/jidlink/plugins000075500000000000000000000000001500237002100165375ustar00nobodynobodytkabber-plugins/jidlink/plugins/dtcp.tcl000064400000000000000000000275731500237002100202720ustar00nobodynobody# dtcp.tcl -- # # This file is a part of Jidlink Tkabber plugin. It implements # Direct TCP connection protocol. namespace eval dtcp {} namespace eval dtcp::active {} namespace eval dtcp::passive {} proc dtcp::load {} { jidlink::register_transport dtcp-active dtcp-passive 25 disabled \ [namespace current]::active::connect \ [namespace current]::active::send_data \ [namespace current]::active::close ::xmpp::iq::register set query jabber:iq:dtcp \ [namespace current]::iq_set_handler jidlink::register_transport dtcp-passive dtcp-active 50 disabled \ [namespace current]::passive::connect \ [namespace current]::passive::send_data \ [namespace current]::passive::close } proc dtcp::unload {} { #jidlink::unregister_transport dtcp-active ::xmpp::iq::unregister set query jabber:iq:dtcp #jidlink::unregister_transport dtcp-passive namespace delete [namespace current] } proc dtcp::active::connect {xlib jid key} { variable connection set_status [::msgcat::mc "Opening DTCP active connection"] ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create query \ -xmlns jabber:iq:dtcp \ -subelement [::xmpp::xml::create key \ -cdata $key] \ -subelement [::xmpp::xml::create comment \ -subelement [::xmpp::xml::create key \ -cdata $key]]] \ -to $jid \ -command [list [namespace current]::recv_connect_response \ $xlib $jid $key] vwait [namespace current]::connection(status,$key) } proc dtcp::active::recv_connect_response {xlib jid key status xml} { variable connection if {$status != "ok"} { # TODO set connection(status,$key) 0 return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {$tag == "query"} { set hosts {} foreach item $subels { ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels switch -- $stag { verify { set verify $scdata debugmsg jidlink "VERIFY: $verify" } host { lappend hosts [list $scdata \ [::xmpp::xml::getAttr $sattrs port]] } } } if {[info exists verify]} { variable verify_key variable key_verify set verify_key($verify) $key set key_verify($key) $verify set connection(xlib,$key) $xlib set connection(jid,$key) $jid foreach host $hosts { lassign $host addr port debugmsg jidlink "CONNECTING TO $addr:$port..." if {[catch {set sock \ [::pconnect::socket $addr $port \ -proxyfilter ::proxy::proxyfilter]}]} { continue } debugmsg jidlink "CONNECTED" fconfigure $sock -translation binary set connection(sock,$key) $sock puts $sock "key:$key" flush $sock fileevent $sock readable \ [list [namespace current]::wait_for_verify $key $sock] return } debugmsg jidlink "FAILED" set connection(status,$key) 0 return } else { # TODO } } else { # TODO } set connection(status,$key) 0 } proc dtcp::active::sock_connect {key hosts} { variable connection variable verify_key variable key_verify foreach host $hosts { lassign $host addr port debugmsg jidlink "CONNECTING TO $addr:$port..." if {[catch {set sock [::pconnect::socket $addr $port \ -proxyfilter ::proxy::proxyfilter]}]} { continue } debugmsg jidlink "CONNECTED" fconfigure $sock -translation binary set connection(sock,$key) $sock puts $sock "key:$key" flush $sock fileevent $sock readable \ [list [namespace current]::wait_for_verify $key $sock] return } debugmsg jidlink "FAILED" set connection(status,$key) 0 } proc dtcp::active::send_data {key data} { variable connection variable key_stream puts -nonewline $connection(sock,$key) $data flush $connection(sock,$key) return 1 } proc dtcp::active::close {key} { variable connection variable key_stream ::close $connection(sock,$key) } proc dtcp::active::wait_for_verify {key chan} { variable connection variable key_verify set s [gets $chan] debugmsg jidlink "WFV: [list $s]" if {[string range $s 0 6] == "verify:"} { set verify [string range $s 7 end] if {$verify == $key_verify($key)} { fconfigure $chan -translation binary -blocking no fileevent $chan readable \ [list [namespace parent]::readable $key $chan] set connection(status,$key) 1 return } } ::close $chan jidlink::closed $key } proc dtcp::passive::connect {xlib jid key} { variable connection set_status [::msgcat::mc "Opening DTCP passive connection"] set servsock [socket -server [list [namespace current]::accept $key] 0] lassign [fconfigure $servsock -sockname] addr hostname port set ip [::xmpp::ip $xlib] ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create query \ -xmlns jabber:iq:dtcp \ -subelement [::xmpp::xml::create key \ -cdata $key] \ -subelement [::xmpp::xml::create host \ -attrs [list port $port] \ -cdata $ip] \ -subelement [::xmpp::xml::create comment \ -subelement [::xmpp::xml::create key \ -cdata $key]]] \ -to $jid \ -command [list [namespace current]::recv_connect_response \ $xlib $jid $key] vwait [namespace current]::connection(status,$key) } proc dtcp::passive::recv_connect_response {xlib jid key status xml} { variable connection if {$status != "ok"} { # TODO set connection(status,$key) 0 return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {$tag == "query"} { set hosts {} foreach item $subels { ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels switch -- $stag { verify { set verify $scdata debugmsg jidlink "VERIFY: $verify" } host { lappend hosts [list $scdata \ [::xmpp::xml::getAttr $attrs port]] } } } if {[info exists verify]} { variable verify_key variable key_verify set verify_key($verify) $key set key_verify($key) $verify set connection(xlib,$key) $xlib set connection(jid,$key) $jid #set connection(status,$key) 1 return } else { # TODO } } else { # TODO } set connection(status,$key) 0 } proc dtcp::passive::send_data {key data} { variable connection variable key_stream puts -nonewline $connection(sock,$key) $data flush $connection(sock,$key) return 1 } proc dtcp::passive::close {key} { variable connection variable key_stream ::close $connection(sock,$key) } proc dtcp::passive::accept {key chan addr port} { variable connection variable key_verify debugmsg jidlink "CONNECT FROM $addr:$port" set connection(sock,$key) $chan fileevent $chan readable \ [list [namespace current]::wait_for_key $key $chan] } proc dtcp::passive::wait_for_key {key chan} { variable connection variable key_verify set s [gets $chan] if {[string range $s 0 3] == "key:"} { set key2 [string range $s 4 end] if {$key == $key2} { debugmsg jidlink [array get key_verify] puts $chan "verify:$key_verify($key)" flush $chan fconfigure $chan -translation binary -blocking no fileevent $chan readable \ [list [namespace parent]::readable $key $chan] set connection(status,$key) 1 return } } puts $chan error flush $chan } proc dtcp::readable {key chan} { if {![eof $chan]} { set buf [read $chan 4096] jidlink::recv_data $key $buf } else { fileevent $chan readable {} jidlink::closed $key } } proc dtcp::iq_set_handler {xlib from xml args} { ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {$tag == "query"} { set hosts {} foreach item $subels { ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels switch -- $stag { comment { foreach sitem $ssubels { ::xmpp::xml::split $sitem \ sstag ssxmlns ssattrs sscdata sssubels if {$sstag == "key"} { set key $sscdata debugmsg jidlink "KEY: $key" } } } key { set key $scdata debugmsg jidlink "KEY: $key" } host { lappend hosts [list $scdata \ [::xmpp::xml::getAttr $sattrs port]] } } } if {[info exists key]} { set verify [rand 1000000000] if {$hosts == {}} { variable passive::verify_key variable passive::key_verify set passive::verify_key($verify) $key set passive::key_verify($key) $verify set servsock \ [socket -server \ [list [namespace current]::passive::accept $key] 0] lassign [fconfigure $servsock -sockname] addr hostname port set ip [::xmpp::ip $xlib] set res [::xmpp::xml::create query \ -xmlns jabber:iq:dtcp \ -subelement [::xmpp::xml::create verify \ -cdata $verify] \ -subelement [::xmpp::xml::create host \ -attrs [list port $port] \ -cdata $ip]] } else { variable active::verify_key variable active::key_verify set active::verify_key($verify) $key set active::key_verify($key) $verify debugmsg jidlink [list $hosts] after idle [list [namespace current]::active::sock_connect \ $key $hosts] set res [::xmpp::xml::create query \ -xmlns jabber:iq:dtcp \ -subelement [::xmpp::xml::create verify \ -cdata $verify]] } return [list result $res] } else { # TODO } } else { # TODO } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/jidlink/plugins/filetransfer.tcl000064400000000000000000000325021500237002100220100ustar00nobodynobody# filetransfer.tcl -- # # This file is a part of Jidlink Tkabber plugin. It implements # file transfer via Jidlink. namespace eval ftjl { variable winid 0 variable id 0 variable chunk_size 1024 variable options custom::defgroup Jidlink \ [::msgcat::mc "Jidlink options."] \ -group {File Transfer} } proc ftjl::load {} { ::xmpp::iq::register set query jabber:iq:filexfer \ [namespace current]::iq_set_handler ft::register_protocol jidlink \ -priority 20 \ -label "Jidlink" \ -send [namespace current]::send_file \ -close [namespace current]::send_file_close } proc ftjl::unload {} { ::xmpp::iq::unregister set query jabber:iq:filexfer ft::unregister_protocol jidlink namespace delete [namespace current] } ############################################################################### proc ftjl::send_file {token} { upvar #0 $token state variable id variable files if {![info exists state(fd)]} return incr id set state(id) $id set files(token,$id) $token ::xmpp::sendIQ $state(xlib) set \ -query [::xmpp::xml::create query \ -xmlns jabber:iq:filexfer \ -subelement [::xmpp::xml::create file \ -attrs [list id $id \ name $state(name) \ size $state(size)] \ -cdata $state(desc)]] \ -to $state(jid) \ -command [list [namespace current]::send_file_result $token] } ############################################################################### proc ftjl::send_file_result {token status xml} { upvar #0 $token state if {![info exists state(fd)]} return if {$status eq "ok"} return eval $state(command) \ [list error \ [::msgcat::mc "Request failed: %s" [error_to_string $xml]]] } ############################################################################### proc ftjl::send_file_request {xlib from lang id offset} { variable files if {![info exists files(token,$id)]} { return [list error cancel not-allowed \ -text [::trans::trans $lang "Invalid file ID"]] } set token $files(token,$id) upvar #0 $token state if {![info exists state(fd)]} { return [list error cancel not-allowed \ -text [::trans::trans $lang "Transfer is expired"]] } if {$state(xlib) != $xlib || $state(jid) != $from} { return [list error cancel not-allowed \ -text [::trans::trans $lang "Invalid file ID"]] } set state(key) [rand 1000000000] set state(offset) $offset set res \ [::xmpp::xml::create query \ -xmlns jabber:iq:filexfer \ -subelement [::xmpp::xml::create file \ -attrs [list id $id] \ -subelement [::xmpp::xml::create key \ -cdata $state(key)]]] after idle [list [namespace current]::send_file_setup_connection $token] return [list result $res] } ############################################################################### proc ftjl::send_file_setup_connection {token} { upvar #0 $token state variable chunk_size if {![info exists state(fd)]} return set res [jidlink::connect $state(xlib) $state(jid) $state(key)] if {$res == 0} { if {[info exists state(command)]} { eval $state(command) \ [list error [::msgcat::mc "Jidlink connection failed"]] } return } set_status [::msgcat::mc "Transferring..."] # Transfer window may be destroyed during jidlink::connect if {![info exists state(fd)]} return set chunk [read $state(fd) $chunk_size] if {[catch { while {$chunk != ""} { jidlink::send_data $state(key) $chunk update idletasks eval $state(command) [list progress [tell $state(fd)]] after 1000 set chunk [read $state(fd) $chunk_size] } }]} { if {[info exists state(command)]} { eval $state(command) \ [list error [::msgcat::mc "Jidlink transfer failed"]] } return } eval $state(command) ok } ############################################################################### proc ftjl::send_file_close {token} { upvar #0 $token state variable files if {![info exists state(fd)]} return catch {unset files(token,$state(id))} catch {jidlink::close $state(key)} } ############################################################################### ############################################################################### proc ftjl::recv_file_dialog {xlib from lang id name size date hash desc} { variable winid variable files variable result set w .rfd$winid while {[winfo exists $w]} { incr winid set w .rfd$winid } Dialog $w -title [::msgcat::mc "Receive file from %s" $from] \ -anchor e -transient 0 \ -modal none -default 0 -cancel 1 set f [$w getframe] Label $f.lname -text [::msgcat::mc "Name:"] Label $f.name -text $name Label $f.lsize -text [::msgcat::mc "Size:"] Label $f.size -text $size Label $f.ldesc -text [::msgcat::mc "Description:"] Message $f.desc -width 10c -text $desc set dir $::ft::options(download_dir) Label $f.lsaveas -text [::msgcat::mc "Save as:"] Entry $f.saveas -textvariable [namespace current]::saveas$winid variable saveas$winid [file join $dir $name] Button $f.browsefile -text [::msgcat::mc "Browse..."] \ -command [list [namespace current]::set_receive_file_name \ $w $winid $dir $name] set pbvar [namespace current]::progress$f.pb Progressbar $f.pb -variable $pbvar $f.pb configure -maximum $size set $pbvar 0 grid $f.lname -row 0 -column 0 -sticky e grid $f.name -row 0 -column 1 -sticky w grid $f.lsize -row 1 -column 0 -sticky e grid $f.size -row 1 -column 1 -sticky w grid $f.ldesc -row 2 -column 0 -sticky en grid $f.desc -row 2 -column 1 -sticky ewns -columnspan 2 -pady 1m grid $f.lsaveas -row 3 -column 0 -sticky e grid $f.saveas -row 3 -column 1 -sticky ew grid $f.browsefile -row 3 -column 2 -sticky ew grid $f.pb -row 4 -column 0 -sticky ew -columnspan 3 -pady 2m grid columnconfigure $f 1 -weight 1 -minsize 8c grid rowconfigure $f 2 -weight 1 $w add -text [::msgcat::mc "Receive"] -command \ [list [namespace current]::recv_file_start \ $winid $size $pbvar $xlib $from $lang $id] $w add -text [::msgcat::mc "Cancel"] -command \ [list [namespace current]::recv_file_cancel $winid $lang] bind .rfd$winid \ [list [namespace current]::recv_file_failed $winid $lang] $w draw vwait [namespace current]::result($winid) set res $result($winid) unset result($winid) incr winid return $res } ############################################################################### proc ftjl::set_receive_file_name {w winid dir fname} { variable saveas$winid set file [tk_getSaveFile -parent $w -initialdir $dir -initialfile $fname] if {$file != ""} { set saveas$winid $file } } ############################################################################### proc ftjl::recv_file_start {winid size pbvar xlib user lang id} { variable saveas$winid variable files set filename [set saveas$winid] .rfd$winid itemconfigure 0 -state disabled set $pbvar 0 #set files(filename,$key) $filename ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create query \ -xmlns jabber:iq:filexfer \ -subelement [::xmpp::xml::create file \ -attrs [list id $id]]] \ -to $user \ -command [list [namespace current]::recv_file_reply \ $winid $size $pbvar $user $lang $id $filename] } ############################################################################### proc ftjl::recv_file_reply \ {winid size pbvar user lang id filename status xml} { variable files if {$status != "ok"} { recv_file_failed $winid $lang after idle \ [list MessageDlg .auth_err -aspect 50000 -icon error \ -message [::msgcat::mc "Receiving file failed: %s" \ [error_to_string $xml]] -type user \ -buttons ok -default 0 -cancel 0] return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {$tag == "query"} { foreach item $subels { ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels if {$stag == "file"} { foreach sitem $ssubels { ::xmpp::xml::split $sitem \ sstag ssxmlns ssattrs sscdata sssubels if {$sstag == "key"} { set key $sscdata set files(filename,$key) $filename debugmsg filetransfer "RECV KEY: $key" set fd [open $filename w] fconfigure $fd -translation binary set files(fd,$key) $fd jidlink::set_readable_handler \ $key [list [namespace current]::recv_file_chunk \ $pbvar] jidlink::set_closed_handler \ $key [list [namespace current]::recv_file_finish \ $winid $size] } } } } } } ############################################################################### proc ftjl::recv_file_chunk {pbvar key} { variable files if {[info exists files(filename,$key)]} { set data [jidlink::read_data $key] debugmsg filetransfer \ "RECV into $files(filename,$key) data length [string length $data]" puts -nonewline $files(fd,$key) $data incr $pbvar [string length $data] debugmsg filetransfer [set $pbvar] } } ############################################################################### proc ftjl::recv_file_failed {winid lang} { variable result bind .rfd$winid {} set result($winid) \ [list error modify undefined-condition \ -text [::trans::trans $lang "File transfer is failed"]] } ############################################################################### proc ftjl::recv_file_finish {winid size key} { variable files variable result if {[info exists files(filename,$key)]} { debugmsg filetransfer CLOSE catch { close $files(fd,$key) } set fsize [file size $files(filename,$key)] unset files(filename,$key) set_status [::msgcat::mc "Connection closed"] } if {[winfo exists .rfd$winid]} { bind .rfd$winid {} destroy .rfd$winid if {$fsize != $size} { if {$fsize < $size} { set msg "Transfer interrupted (File size is too small)" } else { set msg "File size is too large" } after idle \ [list MessageDlg .auth_err -aspect 50000 -icon error \ -message [::msgcat::mc "Receiving file failed: %s" \ $msg] \ -type user \ -buttons ok -default 0 -cancel 0] } } set result($winid) {result {}} } ############################################################################### proc ftjl::recv_file_cancel {winid lang} { variable result catch { bind .rfd$winid {} destroy .rfd$winid } set result($winid) \ [list error cancel not-allowed \ -text [::trans::trans $lang "File transfer is refused"]] } ############################################################################### proc ftjl::iq_set_handler {xlib from xml args} { debugmsg filetransfer "FTJL set: [list $from $xml]" ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {$tag != "query"} { return {error modify bad-request} } set lang [::xmpp::xml::getAttr $args -lang en] foreach item $subels { ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels if {$stag == "file"} { if {[::xmpp::xml::getAttr $sattrs name] != ""} { return [recv_file_dialog $xlib $from $lang \ [::xmpp::xml::getAttr $sattrs id] \ [::xmpp::xml::getAttr $sattrs name] \ [::xmpp::xml::getAttr $sattrs size] \ [::xmpp::xml::getAttr $sattrs date] \ [::xmpp::xml::getAttr $sattrs hash] \ $scdata] } else { return [send_file_request $xlib $from $lang \ [::xmpp::xml::getAttr $sattrs id] \ [::xmpp::xml::getAttr $sattrs offset]] } } } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/jidlink/plugins/ibb.tcl000064400000000000000000000144111500237002100200570ustar00nobodynobody# ibb.tcl -- # # This file is a part of Jidlink Tkabber plugin. It implements # inband-bytestream protocol. package require base64 namespace eval ibb {} proc ibb::load {} { ::xmpp::iq::register set query jabber:iq:ibb \ [namespace current]::iq_set_handler ::xmpp::iq::register set query jabber:iq:inband \ [namespace current]::iq_inband_set_handler jidlink::register_transport inband-bytestream inband-bytestream \ 75 enabled \ [namespace current]::connect \ [namespace current]::send_data \ [namespace current]::close } proc ibb::unload {} { ::xmpp::iq::unregister set query jabber:iq:ibb ::xmpp::iq::unregister set query jabber:iq:inband #jidlink::unregister_transport inband-bytestream namespace delete [namespace current] } proc ibb::connect {xlib jid key} { variable connection set_status [::msgcat::mc "Opening IBB connection"] ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create query \ -xmlns jabber:iq:ibb \ -subelement [::xmpp::xml::create comment \ -subelement [::xmpp::xml::create key \ -cdata $key]]] \ -to $jid \ -command [list [namespace current]::recv_connect_response \ $xlib $jid $key] vwait [namespace current]::connection(status,$key) } proc ibb::recv_connect_response {xlib jid key status xml} { variable connection if {$status != "ok"} { # TODO set connection(status,$key) 0 return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {$tag == "query"} { foreach item $subels { ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels if {$stag == "streamid"} { set streamid $scdata debugmsg jidlink "STREAMID: $streamid" } } if {[info exists streamid]} { variable stream_key variable key_stream set stream_key($streamid) $key set key_stream($key) $streamid set connection(xlib,$key) $xlib set connection(jid,$key) $jid set connection(status,$key) 1 } else { # TODO } } else { # TODO } set connection(status,$key) 0 } proc ibb::send_data {key data} { variable connection variable key_stream debugmsg jidlink [array get stream_key] ::xmpp::sendIQ $connection(xlib,$key) set \ -query [::xmpp::xml::create query \ -xmlns jabber:iq:inband \ -subelement [::xmpp::xml::create streamid \ -cdata $key_stream($key)] \ -subelement [::xmpp::xml::create data \ -cdata [base64::encode $data]]] \ -to $connection(jid,$key) \ -command [list [namespace current]::send_data_ack $key] vwait [namespace current]::connection(ack,$key) return $connection(ack,$key) } proc ibb::send_data_ack {key status xml} { variable connection if {$status != "ok"} { # TODO set connection(ack,$key) 0 return } set connection(ack,$key) 1 } proc ibb::close {key} { variable connection variable key_stream ::xmpp::sendIQ $connection(xlib,$key) set \ -query [::xmpp::xml::create query \ -xmlns jabber:iq:inband \ -subelement [::xmpp::xml::create streamid \ -cdata $key_stream($key)] \ -subelement [::xmpp::xml::create close]] \ -to $connection(jid,$key) } proc ibb::iq_set_handler {xlib from xml args} { ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {$tag == "query"} { foreach item $subels { ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels if {$stag == "comment"} { foreach sitem $ssubels { ::xmpp::xml::split $sitem \ sstag ssxmlns ssattrs sscdata sssubels if {$sstag == "key"} { set key $sscdata debugmsg jidlink "KEY: $key" } } } } if {[info exists key]} { variable stream_key variable key_stream set streamid [rand 1000000000] set stream_key($streamid) $key set key_stream($key) $streamid set res [::xmpp::xml::create query \ -xmlns jabber:iq:ibb \ -subelement [::xmpp::xml::create streamid \ -cdata $streamid]] return [list result $res] } else { # TODO } } else { # TODO } } proc ibb::iq_inband_set_handler {xlib from xml args} { variable stream_key ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {$tag == "query"} { foreach item $subels { ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels switch -- $stag { streamid { set streamid $scdata } data { set data $scdata } close { set close 1 } } } if {[info exists streamid] && [info exists stream_key($streamid)]} { if {[info exists data]} { if {[catch {set decoded [base64::decode $data]}]} { # TODO debugmsg jidlink "IBB: WRONG DATA" } else { debugmsg jidlink "IBB: RECV DATA [list $data]" jidlink::recv_data $stream_key($streamid) $decoded } } if {[info exists close]} { jidlink::closed $stream_key($streamid) } return [list result ""] } else { # TODO } } else { # TODO } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/jidlink/trans000075500000000000000000000000001500237002100162055ustar00nobodynobodytkabber-plugins/jidlink/trans/ru.msg000064400000000000000000000006371500237002100174300ustar00nobodynobody# ru.msg -- # # Messages to send to Russian peers for the Tkabber Jidlink plugin. # # Author: Sergei Golovan ::trans::trset ru "File transfer is failed" "Передать файл не удалоÑÑŒ" ::trans::trset ru "Invalid file ID" "Ðеправильный ID файла" ::trans::trset ru "Transfer is expired" "Срок передачи иÑтёк" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/jidlink/trans/uk.msg000064400000000000000000000006571500237002100174230ustar00nobodynobody# uk.msg -- # # Messages to send to Ukrainian peers for the Tkabber Jidlink plugin. # # Author: Sergei Golovan ::trans::trset uk "File transfer is failed" "Передати файл не вдалоÑÑ" ::trans::trset uk "Invalid file ID" "Ðеправильний ID файлу" ::trans::trset uk "Transfer is expired" "Термін передачі закінчивÑÑ" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/latex000075500000000000000000000000001500237002100145475ustar00nobodynobodytkabber-plugins/latex/latex.tcl000064400000000000000000000157211500237002100164550ustar00nobodynobody# latex.tcl -- # # LaTeX plugin for the Tkabber XMPP client. It shows LaTeX formulae # as pictures (*NIX and Windows only) Requires working latex, dvips, # imagemagick and their binaries should be in the directory listed # in the PATH environment variable. package require msgcat namespace eval latex { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered latex]} { ::plugins::register latex \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the LaTeX\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } custom::defgroup Plugins [::msgcat::mc "Plugins options."] -group Tkabber custom::defgroup LaTeX [::msgcat::mc "LaTeX formulas plugin options."] \ -group Plugins custom::defvar options(resolution) [winfo pixels . 1i] \ [::msgcat::mc "Resolution of the LaTeX generated images in\ pixels per inch."] \ -group LaTeX -type integer } proc latex::load {} { variable tmpdir [pwd] variable null "" switch -- $::tcl_platform(platform) { windows { catch { set tmpdir $::env(TMP) } catch { set tmpdir $::env(TEMP) } set null "2>NUL" } unix { set tmpdir "/tmp" catch { set tmpdir $::env(TMPDIR) } set null "2>/dev/null" } macintosh { # In case when someone would like to implement it set tmpdir $::env(TRASH_FOLDER) return } } # Blacklist is taken from KopeTeX. Not all of them are dengerous though variable blacklist {\\def \\let \\futurelet \\newcommand \\renewcommand \\else \\fi \\write \\input \\include \\chardef \\catcode \\makeatletter \\noexpand \\toksdef \\every \\errhelp \\errorstopmode \\scrollmode \\nonstopmode \\batchmode \\read \\csname \\newhelp \\relax \\afterground \\afterassignment \\expandafter \\noexpand \\special \\command \\loop \\repeat \\toks \\output \\line \\mathcode \\name \\item \\section \\DeclareRobustCommand} hook::add draw_message_hook [namespace current]::find_formulas 10 } proc latex::unload {} { hook::remove draw_message_hook [namespace current]::find_formulas 10 variable tmpdir variable null variable blacklist unset tmpdir null blacklist } proc latex::find_formulas {chatid from type body x} { variable blacklist init_colors $chatid foreach {str formula} [regexp -all -inline {\$\$([^$]+)\$\$} $body] { debugmsg plugins "found formula: $str -> $formula" if {[lsearch -exact [image names] latex/$str] >= 0} { debugmsg plugins "formula $str already exists" continue } set bl 0 foreach csname $blacklist { if {[string first $csname $formula] >= 0} { set bl 1 break } } if {$bl} { debugmsg plugins "blacklisted word: $csname" continue } if {[catch {convert_formula latex/$str $formula} msg]} { debugmsg plugins "latex error: $msg" continue } debugmsg plugins "adding formula: $str" plugins::emoticons::add $str latex/$str } } proc latex::convert_formula {imgname formula} { variable tmpdir variable options variable bg variable fg variable null set res $options(resolution) set i 0 while {1} { set dirname [file join $tmpdir latex$i] if {![file exists $dirname]} break incr i } file mkdir $dirname set fname [file join $dirname out.tex] set fd [open $fname w] fconfigure $fd -encoding utf-8 puts $fd "\\documentclass\[12pt,letterpaper\]{article} \\usepackage{amsmath} \\usepackage{amssymb} \\usepackage{color} \\pagestyle{empty} \\pagecolor\[rgb\]{$bg} \\begin{document} \\color\[rgb\]{$fg} \\begin{gather*}$formula\\end{gather*} \\end{document}" close $fd if {[catch { exec latex -output-directory $dirname \ -interaction=batchmode out.tex $null if {[catch { exec dvigif -o [file join $dirname out.gif] \ -D $res \ -T tight \ [file join $dirname out.dvi] $null } msg1]} { debugmsg plugins "dvigif error: $msg1, trying dvips&convert" exec dvips -o [file join $dirname out.eps] \ -E \ [file join $dirname out.dvi] $null exec convert +adjoin \ -antialias \ -density ${res}x${res} \ [file join $dirname out.eps] \ [file join $dirname out.gif] $null } } msg]} { file delete -force $dirname return -code error $msg } create_image $imgname -file [file join $dirname out.gif] -scale 1 file delete -force $dirname # dvigif produces 1x1 image if the page is empty if {[image width $imgname] == 1 && [image height $imgname] == 1} { image delete $imgname return -code error "Image produced by dvigif is empty" } # If the page is empty, dvips doesn't crop it, so we # check image height and width. Letter paper dimensions are 8.5in x 11in if {abs([image width $imgname] - $res * 8.5) < 1 && \ abs([image height $imgname] - $res * 11) < 1} { # It's better to delete image and run latex every time when the same # formula appears. Otherwise large images will be stored # and waste space image delete $imgname return -code error "Image produced by dvips & convert is empty" } return $imgname } proc latex::init_colors {chatid} { variable fg variable bg if {[info exists fg] && [info exists bg]} return set chatw [chat::chat_win $chatid] set bgopt [$chatw cget -background] if {$bgopt == ""} { set bgopt white } set bg [get_rgb_color $chatw $bgopt] set fgopt [$chatw cget -foreground] if {$fgopt == ""} { set fgopt black } set fg [get_rgb_color $chatw $fgopt] } proc latex::get_rgb_color {w color} { lassign [winfo rgb $w $color] r g b set r [expr {$r/65535.}] set g [expr {$g/65535.}] set b [expr {$b/65535.}] return $r,$g,$b } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/latex/msgs000075500000000000000000000000001500237002100155205ustar00nobodynobodytkabber-plugins/latex/msgs/de.msg000064400000000000000000000010441500237002100166760ustar00nobodynobody# de.msg -- # # German messages for the LaTeX Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 13.11.2010 ::msgcat::mcset de "Plugins options." "Optionen für Plugins." ::msgcat::mcset de "LaTeX formulas plugin options." \ "Optionen für das LaTeX-Plugin." ::msgcat::mcset de "Resolution of the LaTeX generated images in pixels per\ inch." "Auflösung der von LaTeX erstellten Bilder in Pixel/Inch." ::msgcat::mcset de "Whether the LaTeX plugin is loaded." "LaTeX-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/latex/msgs/es.msg000064400000000000000000000007221500237002100167170ustar00nobodynobody# es.msg -- # # Spanish messages for the LaTeX Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "LaTeX formulas plugin options." \ "Opciones del plugin de fórmulas LaTeX." ::msgcat::mcset es "Plugins options." "Opciones de los plugins." ::msgcat::mcset es "Resolution of the LaTeX generated images in pixels per\ inch." "Resolución en pixeles por pulgada de las imágenes generadas\ por LaTeX." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/latex/msgs/ru.msg000064400000000000000000000012611500237002100167350ustar00nobodynobody# ru.msg -- # # Russian messages for the LaTeX Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Plugins options." "ÐаÑтройки раÑширений." ::msgcat::mcset ru "LaTeX formulas plugin options." \ "ÐаÑтройки раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ñ„Ð¾Ñ€Ð¼ÑƒÐ» LaTeX." ::msgcat::mcset ru "Resolution of the LaTeX generated images in pixels per\ inch." "Разрешение изображений, генерируемых LaTeX'ом, в точках на\ дюйм." ::msgcat::mcset ru "Whether the LaTeX plugin is loaded." \ "Загружено ли раÑширение LaTeX." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/latex/msgs/uk.msg000064400000000000000000000013251500237002100167270ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the LaTeX Tkabber plugin. # # Author: Artem Bondarenko # Author: Sergei Golovan ::msgcat::mcset uk "Plugins options." "Параметри плагінів." ::msgcat::mcset uk "LaTeX formulas plugin options." \ "Параметри плагіна формул LaTeX." ::msgcat::mcset uk "Resolution of the LaTeX generated images in pixels per\ inch." "Роздільна здатніÑть зображень, що будуть генеруватиÑÑ\ LaTeX'ом, у точках на дюйм." ::msgcat::mcset uk "Whether the LaTeX plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ LaTeX." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/mute000075500000000000000000000000001500237002100144045ustar00nobodynobodytkabber-plugins/mute/msgs000075500000000000000000000000001500237002100153555ustar00nobodynobodytkabber-plugins/mute/msgs/ru.msg000064400000000000000000000017041500237002100165740ustar00nobodynobody# ru.msg -- # # Russian messages for the MUTE Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Commit current version" "ЗапиÑать текущую верÑию" ::msgcat::mcset ru "Edit %s" "Редактировать %s" ::msgcat::mcset ru "Error getting list: %s" "Ошибка при получении ÑпиÑка: %s" ::msgcat::mcset ru "Error patching: %s" "Ошибка при внеÑении изменений: %s" ::msgcat::mcset ru "List of texts from %s" "СпиÑок текÑтов от %s" ::msgcat::mcset ru "MUTE" "МПТР" ::msgcat::mcset ru "Revert to master version" "ВернутьÑÑ Ðº оÑновной верÑии" ::msgcat::mcset ru "Whether the Multi-User Text Editor plugin is loaded."\ "Загружено ли раÑширение, реализующее многопользовательÑкий текÑтовый\ редактор." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/mute/msgs/uk.msg000064400000000000000000000017151500237002100165670ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the MUTE Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Commit current version" "ЗапиÑати наÑвну верÑÑ–ÑŽ" ::msgcat::mcset uk "Edit %s" "Редагувати %s" ::msgcat::mcset uk "Error getting list: %s" "Помилка при отриманні ÑпиÑку: %s" ::msgcat::mcset uk "Error patching: %s" "Помилка при внеÑенні змін: %s" ::msgcat::mcset uk "List of texts from %s" "СпиÑок текÑтів від %s" ::msgcat::mcset uk "MUTE" "БКТР" ::msgcat::mcset uk "Revert to master version" "ПовернутиÑÑ Ð´Ð¾ оÑновної верÑÑ–Ñ—" ::msgcat::mcset uk "Whether the Multi-User Text Editor plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ñ€ÐµÐ°Ð»Ñ–Ð·Ð°Ñ†Ñ–Ñ— багатокориÑтувацького\ текÑтового редактора." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/mute/mute.tcl000064400000000000000000000364631500237002100161550ustar00nobodynobody# mute.tcl -- # # This file implements MUTE plugin for the Tkabber XMPP client. # MUTE stands for the Multi-User Text Editor. # # Requirements: # The following text utilities have to be present on your system # and in the PATH environment variable: # diff: utility to compare two files (apt-get install diffutils # in Debian, but it has priority required, so it's always # present in the system) # patch: applies a diff output to an original file (apt-get install # patch in Debian) # merge: three-way file merger (apt-get install rcs in Debian) package require msgcat namespace eval mute { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered mute]} { ::plugins::register mute \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Multi-User\ Text Editor plugin is\ loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } } proc mute::load {} { set ::NS(mute_ancestor) "http://jabber.org/protocol/mute#ancestor" set ::NS(mute_editor) "http://jabber.org/protocol/mute#editor" hook::add roster_create_groupchat_user_menu_hook \ [namespace current]::editor::add_user_menu_item 49 hook::add chat_create_user_menu_hook \ [namespace current]::editor::add_user_menu_item 49 hook::add roster_jid_popup_menu_hook \ [namespace current]::editor::add_user_menu_item 49 ::xmpp::iq::register set * $::NS(mute_editor) \ [namespace current]::editor::recv_set_iq ::xmpp::iq::register get * $::NS(mute_ancestor) \ [namespace current]::ancestor::recv_get_iq ::xmpp::iq::register set * $::NS(mute_ancestor) \ [namespace current]::ancestor::recv_set_iq } proc mute::unload {} { hook::remove roster_create_groupchat_user_menu_hook \ [namespace current]::editor::add_user_menu_item 49 hook::remove chat_create_user_menu_hook \ [namespace current]::editor::add_user_menu_item 49 hook::remove roster_jid_popup_menu_hook \ [namespace current]::editor::add_user_menu_item 49 ::xmpp::iq::unregister set * $::NS(mute_editor) ::xmpp::iq::unregister get * $::NS(mute_ancestor) ::xmpp::iq::unregister set * $::NS(mute_ancestor) catch {unset ::NS(mute_ancestor)} catch {unset ::NS(mute_editor)} namespace delete [namespace current]::editor namespace delete [namespace current]::ancestor } namespace eval mute::editor {} proc mute::editor::get_winid {xlib jid id} { return [win_id mute [list $xlib $jid]//@mute@//$id] } proc mute::editor::add_user_menu_item {m xlib jid} { $m add command \ -label [::msgcat::mc "MUTE"] \ -command [list [namespace current]::list_request $xlib $jid] } proc mute::editor::list_request {xlib jid} { ::xmpp::sendIQ $xlib get \ -query [::xmpp::xml::create list \ -xmlns $::NS(mute_ancestor)] \ -to $jid \ -command [list [namespace current]::list_recv $xlib $jid] } proc mute::editor::list_recv {xlib jid status xml} { variable txts if {$status != "ok"} { after idle [list MessageDlg .mute_list_error -icon error \ -message [::msgcat::mc "Error getting list: %s" \ [error_to_string $xml]] \ -type ok] return "" } ::xmpp::xml::split $xml tag xmlns attrs cdata subels set ids {} foreach subel $subels { ::xmpp::xml::split $subel stag sxmlns sattrs scdata ssubels set id [::xmpp::xml::getAttr $sattrs id] lappend ids $id set desc($id) [::xmpp::xml::getAttr $sattrs desc] } set w .mute_invite if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "List of texts from %s" $jid] \ -anchor e -default 0 foreach id $ids { $w add -text "$id: $desc($id)" \ -command [list [namespace current]::subscribe_request \ $xlib $jid $id] } $w add -text Cancel -command [list destroy $w] $w draw } proc mute::editor::subscribe_request {xlib jid id} { ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create subscribe \ -xmlns $::NS(mute_ancestor) \ -subelement [::xmpp::xml::create item \ -attrs [list id $id]]] \ -to $jid \ -command [list [namespace current]::subscribe_recv $xlib $jid $id] } proc mute::editor::subscribe_recv {xlib jid id status xml} { variable txts if {$status != "ok"} { after idle [list MessageDlg .mute_list_error -icon error \ -message [::msgcat::mc "Error getting list: %s" \ [error_to_string $xml]] \ -type ok] return "" } } proc mute::editor::open_win {xlib jid id} { variable txts set w [get_winid $xlib $jid $id] if {[winfo exists $w]} { return } add_win $w -title [::msgcat::mc "Edit %s" $id] \ -tabtitle [::msgcat::mc "Edit %s" $id] \ -class Mute set bbox [ButtonBox $w.bbox -spacing 2m -padx 2m] pack $bbox -side bottom -anchor e $bbox add -text [::msgcat::mc "Commit current version"] \ -command [list [namespace current]::commit $xlib $jid $id] $bbox add -text [::msgcat::mc "Revert to master version"] \ -command [list [namespace current]::revert $xlib $jid $id] set sw [ScrolledWindow $w.sw] set text [Text $w.text] pack $sw -side top -anchor w -expand yes -fill both -pady 1m $sw setwidget $text } proc mute::editor::get_textw {xlib jid id} { return "[get_winid $xlib $jid $id].text" } proc mute::editor::set_text {xlib jid id text} { variable txts set txts(text,$xlib,$jid,$id) $text set t [get_textw $xlib $jid $id] $t delete 1.0 end $t insert 0.0 $text } proc mute::editor::revert {xlib jid id} { variable txts set text $txts(text,$xlib,$jid,$id) set tw [get_textw $xlib $jid $id] lassign [split [$tw index insert] .] line pos $tw delete 1.0 end $tw insert 0.0 $text $tw mark set insert "$line.$pos" } proc mute::editor::commit {xlib jid id} { variable txts set orig $txts(text,$xlib,$jid,$id) set tw [get_textw $xlib $jid $id] set edit [$tw get 1.0 "end -1 chars"] if {[string index $edit end] != "\n"} { set edit "$edit\n" } # TODO: check temp files set fn "/tmp/mute[rand 1000000]" set fd [open $fn.orig w] fconfigure $fd -encoding utf-8 puts -nonewline $fd $orig close $fd set fd [open $fn.edit w] fconfigure $fd -encoding utf-8 puts -nonewline $fd $edit close $fd catch { exec diff -u $fn.orig $fn.edit > $fn.diff } set fd [open $fn.diff r] fconfigure $fd -encoding utf-8 gets $fd gets $fd set diff [read $fd] close $fd file delete $fn.orig $fn.edit $fn.diff if {$diff != ""} { ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create patch \ -xmlns $::NS(mute_ancestor) \ -attrs [list id $id] \ -cdata $diff] \ -to $jid \ -command [list [namespace current]::patch_res $xlib $jid $id] } } proc mute::editor::patch_res {xlib jid id status xml} { variable txts if {$status != "ok"} { after idle [list MessageDlg .mute_list_error -icon error \ -message [::msgcat::mc "Error patching: %s" \ [error_to_string $xml]] \ -type ok] return "" } set text $txts(text,$xlib,$jid,$id) set tw [get_textw $xlib $jid $id] lassign [split [$tw index insert] .] line pos $tw delete 1.0 end $tw insert 0.0 $text $tw mark set insert "$line.$pos" } proc mute::editor::patch {xlib jid id patch} { variable txts set tw [get_textw $xlib $jid $id] if {![info exists txts(text,$xlib,$jid,$id)] || ![winfo exists $tw]} { return [list error cancel not-allowed] } set text $txts(text,$xlib,$jid,$id) set edit [$tw get 1.0 "end -1 chars"] lassign [split [$tw index insert] .] line pos # TODO: check temp files set fn "/tmp/mute[rand 1000000]" set fd [open $fn.old w] fconfigure $fd -encoding utf-8 puts -nonewline $fd $text close $fd set fd [open $fn.orig w] fconfigure $fd -encoding utf-8 puts -nonewline $fd $text close $fd set fd [open $fn.patch w] fconfigure $fd -encoding utf-8 puts -nonewline $fd $patch close $fd set fd [open $fn.edit w] fconfigure $fd -encoding utf-8 puts -nonewline $fd $edit close $fd if {[catch { exec patch $fn.orig $fn.patch }]} { puts "something wrong..." return } set fd [open $fn.orig r] fconfigure $fd -encoding utf-8 set new [read $fd] close $fd catch { exec merge $fn.edit $fn.old $fn.orig } set fd [open $fn.edit r] fconfigure $fd -encoding utf-8 set newedit [read $fd] close $fd file delete $fn.old $fn.orig $fn.patch $fn.edit set txts(text,$xlib,$jid,$id) $new $tw delete 1.0 end $tw insert 0.0 $newedit set lineregexp {@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@} set shift 0 foreach l [split $patch \n] { if {[regexp $lineregexp $l temp ol os nl ns]} { if {$ol >= $line} break set shift [expr {$nl + $ns - $ol - $os}] } } set line [expr {$line + $shift}] $tw mark set insert "$line.$pos" return [list result ""] } proc mute::editor::recv_set_iq {xlib from xml args} { ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- $tag { text { set id [::xmpp::xml::getAttr $attrs id] open_win $xlib $from $id set_text $xlib $from $id $cdata } patch { set id [::xmpp::xml::getAttr $attrs id] return [patch $xlib $from $id $cdata] } default { return [list error cancel feature-not-implemented] } } } ############################################################################### namespace eval mute::ancestor { variable txts set txts(ids) {id1 id2} set txts(desc,id1) "Useful text" set txts(desc,id2) "Useless text" set txts(text,id1) "... 8. Admin Use Cases 8.1. Banning a User 8.2. Modifying the Ban List 8.3. Granting Membership 8.4. Revoking Membership 8.5. Modifying the Member List 8.6. Granting Moderator Privileges 8.7. Revoking Moderator Privileges 8.8. Modifying the Moderator List ... " set txts(text,id2) "" } proc mute::ancestor::send_text {xlib jid id} { variable txts ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create text \ -xmlns $::NS(mute_editor) \ -attrs [list id $id] \ -cdata $txts(text,$xlib,$id)] \ -to $jid # -command [list [namespace current]::subscribe_recv $xlib $jid $id] } proc mute::ancestor::patch {xlib jid id patch} { variable txts set text $txts(text,$xlib,$id) # TODO: check temp files set fn "/tmp/mute[rand 1000000]" set fd [open $fn.orig w] fconfigure $fd -encoding utf-8 puts -nonewline $fd $text close $fd set fd [open $fn.patch w] fconfigure $fd -encoding utf-8 puts -nonewline $fd $patch close $fd if {[catch { exec patch $fn.orig $fn.patch }]} { return [list error cancel not-allowed] } set fd [open $fn.orig r] fconfigure $fd -encoding utf-8 set new [read $fd] close $fd file delete $fn.orig $fn.patch set txts(text,$xlib,$id) $new after idle [list [namespace current]::distribute_patch $xlib $id $patch] return [list result ""] } proc mute::ancestor::distribute_patch {xlib id patch} { variable txts foreach subscriber $txts(subscribed,$xlib,$id) { ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create patch \ -xmlns $::NS(mute_editor) \ -attrs [list id $id] \ -cdata $patch] \ -to $subscriber \ -command [list [namespace current]::unsubscribe_on_error \ $xlib $subscriber $id] } } proc mute::ancestor::unsubscribe_on_error {xlib jid id status xml} { variable txts if {$status != "ok"} { set idx [lsearch -exact $txts(subscribed,$xlib,$id) $jid] set txts(subscribed,$xlib,$id) \ [lreplace $txts(subscribed,$xlib,$id) $idx $idx] puts "REMOVE $xlib $jid" } } proc mute::ancestor::recv_get_iq {xlib from xml args} { ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- $tag { list { variable txts # TODO if {![info exists txts(ids,$xlib)]} { set txts(ids,$xlib) $txts(ids) foreach id $txts(ids) { set txts(desc,$xlib,$id) $txts(desc,$id) set txts(text,$xlib,$id) $txts(text,$id) } } set items {} foreach id $txts(ids,$xlib) { lappend items [::xmpp::xml::create item \ -attrs [list id $id \ desc $txts(desc,$xlib,$id)]] } return [list result [::xmpp::xml::create list \ -xmlns $::NS(mute_ancestor) \ -subelements $items]] } default { return [list error cancel feature-not-implemented] } } return "" } proc mute::ancestor::recv_set_iq {xlib from xml args} { ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- $tag { subscribe { variable txts foreach subel $subels { ::xmpp::xml::split $subel stag sxmlns sattrs scdata ssubels set id [::xmpp::xml::getAttr $sattrs id] if {[lsearch -exact $txts(ids,$xlib) $id] >= 0} { lappend txts(subscribed,$xlib,$id) $from set txts(subscribed,$xlib,$id) \ [lsort -unique $txts(subscribed,$xlib,$id)] after idle [list [namespace current]::send_text \ $xlib $from $id] return [list result ""] } else { return [list error modify bad-request] } } return [list error modify bad-request] } patch { set id [::xmpp::xml::getAttr $attrs id] return [patch $xlib $from $id $cdata] } default { return [list error cancel feature-not-implemented] } } return "" } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/openurl000075500000000000000000000000001500237002100151165ustar00nobodynobodytkabber-plugins/openurl/msgs000075500000000000000000000000001500237002100160675ustar00nobodynobodytkabber-plugins/openurl/msgs/de.msg000064400000000000000000000024071500237002100172510ustar00nobodynobody# de.msg -- # # German messages for the Open URL Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 13.03.2009 ::msgcat::mcset de "A binary name or a full path to user defined browser.\ Use its full path if can't be\ autodetected.\n\nExample:\n /home/user/bin/hv3/hv3-linux" "Binärer Name oder\ vollständiger Pfad zu einem benutzerdefinierten Browser. Den\ vollständigen Pfad benutzen, wenn der Browser nicht automatisch\ erkannt werden kann.\n\nBeispiele:\n \ /home/user/usr/bin/firefox\n c:/programme/firefox/firefox.exe" ::msgcat::mcset de "Open URL plugin options." \ "Optionen für das 'Open URL'-Plugin." ::msgcat::mcset de "Open URL with" "Öffne URL mit" ::msgcat::mcset de "Open URL with %s" "Öffne URL mit %s" ::msgcat::mcset de "Plugins options." "Optionen für Plugins." ::msgcat::mcset de "Whether the Open URL plugin is loaded." \ "'Open URL'-Plugin laden." ::msgcat::mcset de "Use submenu for browsers list." \ "Unter-Menü für Browser-Liste benutzen." ::msgcat::mcset de "User defined browser name.\n\nExamples:\n HV3\n Google\ Chrome" "Benutzerdefinierter Browser-Name.\n\nBeispiele:\n Google\ Chrome\n Mozilla Firefox" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/openurl/msgs/es.msg000064400000000000000000000021721500237002100172670ustar00nobodynobody# es.msg -- # # Spanish messages for the Open URL Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "A binary name or a full path to user defined browser. Use\ its full path if can't be autodetected.\n\nExample:\n \ /home/user/bin/hv3/hv3-linux" "Un nombre de programa o ruta completa al\ navegador definido por el usuario. Indica la ruta completa si no se\ detecta automáticamente.\n\nEjemplo:\n /home/user/bin/hv3/hv3-linux" ::msgcat::mcset es "Open URL plugin options." "Opciones del plugin Open URL." ::msgcat::mcset es "Open URL with %s" "Abrir URL con %s" ::msgcat::mcset es "Open URL with" "Abrir URL con" ::msgcat::mcset es "Plugins options." "Opciones del plugin." ::msgcat::mcset es "Use submenu for browsers list." \ "Usar submenu para la lista de navegadores." ::msgcat::mcset es "User defined browser name.\n\nExamples:\n HV3\n Google\ Chrome" "Nombre del navegador definido por el usuario.\n\nEjemplos:\n \ HV3\n Google Chrome" ::msgcat::mcset es "Whether the Open URL plugin is loaded." \ "Cargar el plugin Open URL." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/openurl/msgs/pl.msg000064400000000000000000000003261500237002100172720ustar00nobodynobody# pl.msg -- # # Polish messages for the Open URL Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Open URL with" "Otwórz URL za pomocÄ…" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/openurl/msgs/ru.msg000064400000000000000000000032161500237002100173060ustar00nobodynobody# ru.msg -- # # Russian messages for the Open URL Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Open URL with" "Открыть URL Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ" ::msgcat::mcset ru "Open URL with %s" "Открыть URL Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ %s" ::msgcat::mcset ru "Use submenu for browsers list." "ИÑпользовать\ подменю Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° браузера." ::msgcat::mcset ru "A binary name or a full path to user defined\ browser. Use its full path if can't be\ autodetected.\n\nExample:\n /home/user/bin/hv3/hv3-linux"\ "Ð˜Ð¼Ñ Ð·Ð°Ð¿ÑƒÑкаемого файла или полный путь к браузеру,\ определÑемому пользователем. ИÑпользуйте полный путь, еÑли\ его невозможно автоопределить.\n\nПример:\n /home/user/bin/hv3/hv3-linux" ::msgcat::mcset ru "Open URL plugin options." \ "ÐаÑтройки раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ð²Ð°Ð½Ð¸Ñ URL." ::msgcat::mcset ru "Plugins options." "ÐаÑтройки раÑширений." ::msgcat::mcset ru "User defined browser name.\n\nExamples:\n HV3\n Google\ Chrome" "Ðазвание браузера, определÑемого\ пользователем.\n\nПримеры:\n HV3\n Google Chrome" ::msgcat::mcset ru "Whether the Open URL plugin is loaded."\ "Загружено ли раÑширение, позволÑющее открывать URL произвольным\ уÑтановленным в ÑиÑтеме браузером." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/openurl/msgs/uk.msg000064400000000000000000000032441500237002100173000ustar00nobodynobody# uk.msg -- # # Russian messages for the Open URL Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Open URL with" "Відкрити URL за допомогою" ::msgcat::mcset uk "Open URL with %s" "Відкрити URL за допомогою %s" ::msgcat::mcset uk "Use submenu for browsers list." "ВикориÑтовувати\ підменю Ð´Ð»Ñ Ð²Ð¸Ð±Ð¾Ñ€Ñƒ браузера." ::msgcat::mcset uk "A binary name or a full path to user defined\ browser. Use its full path if can't be\ autodetected.\n\nExample:\n /home/user/bin/hv3/hv3-linux"\ "Ð†Ð¼â€™Ñ Ñ„Ð°Ð¹Ð»Ð°, чи повний шлÑÑ… до браузера, зазначеного\ кориÑтувачем. Вказуйте повний шлÑÑ…, Ñкщо він не може\ бути знайдений автоматично.\n\nÐаприклад:\n \ /home/user/bin/hv3/hv3-linux" ::msgcat::mcset uk "Open URL plugin options." \ "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ð²Ð°Ð½Ð½Ñ URL." ::msgcat::mcset uk "Plugins options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½ÑŒ." ::msgcat::mcset uk "User defined browser name.\n\nExamples:\n HV3\n Google\ Chrome" "Ðазва браузера, призначеного\ кориÑтувачем.\n\nПриклади:\n HV3\n Google Chrome" ::msgcat::mcset uk "Whether the Open URL plugin is loaded."\ "Чи завантажене розширеннÑ, Ñке дозволÑÑ” відкривати URL довільним\ вÑтановленим у ÑиÑтемі браузером." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/openurl/openurl.tcl000064400000000000000000000124331500237002100173700ustar00nobodynobody# openurl.tcl -- # # This file implements Open URL plugin for the Tkabber XMPP client. # It allows to choose in which browser you want to open an URL. package require msgcat namespace eval openurl { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered openurl]} { ::plugins::register openurl \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Open URL\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable options set options(browsers) [list \ iceweasel "Iceweasel" \ chromium "Chromium" \ firefox "Firefox" \ galeon "Galeon" \ konqueror "Konqueror" \ mozilla-firefox "Mozilla Firefox" \ mozilla-firebird "Mozilla Firebird" \ mozilla "Mozilla" \ netscape "Netscape" \ iexplore "Internet Explorer" \ opera "Opera" \ chrome "Google Chrome" \ lynx "Lynx" \ links "Links" \ elinks "Elinks" \ dillo "Dillo"] custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup {Open URL} [::msgcat::mc "Open URL plugin options."] \ -group Plugins custom::defvar options(submenu) 1 \ [::msgcat::mc "Use submenu for browsers list."] \ -group {Open URL} \ -type boolean custom::defvar options(custom_browser) "" \ [::msgcat::mc "User defined browser\ name.\n\nExamples:\n HV3\n Google Chrome"] \ -group {Open URL} \ -type string custom::defvar options(path_to_custom_browser) "" \ [::msgcat::mc "A binary name or a full path to user defined browser.\ Use its full path if can't be\ autodetected.\n\nExample:\n /home/user/bin/hv3/hv3-linux"] \ -group {Open URL} \ -type string } proc openurl::load {} { hook::add chat_win_popup_menu_hook \ [namespace current]::add_chat_win_popup_menu 5 } proc openurl::unload {} { variable options hook::remove chat_win_popup_menu_hook \ [namespace current]::add_chat_win_popup_menu 5 catch {unset options(browsers)} } proc openurl::open_url {brname brpath url} { switch -- $brname { iceweasel - firefox - mozilla-firefox - mozilla-firebird - mozilla - netscape { if {[catch { exec $brpath -remote openURL($url,new-tab) }]} { exec $brpath $url & } } galeon { exec $brpath --new-tab $url & } opera { exec $brpath -newpage $url & } links - elinks - lynx { exec xterm -e $brpath $url & } default { exec $brpath $url & } } } proc openurl::add_chat_win_popup_menu {m chatwin X Y x y} { variable options set tags [$chatwin tag names "@$x,$y"] if {[lsearch -glob $tags href_*] < 0} return set url \ [::plugins::urls::encode_url [::plugins::urls::get_url $chatwin $x $y]] if {$options(submenu)} { set mb [menu $m.openurl -tearoff 0] foreach {brname brdesc} $options(browsers) { if {[llength [set e [auto_execok $brname]]] > 0} { $mb add command \ -label $brdesc \ -command [list [namespace current]::open_url \ $brname [lindex $e 0] $url] } } if {$options(custom_browser) != "" && \ $options(path_to_custom_browser) != ""} { set brname $options(path_to_custom_browser) if {[llength [set e [auto_execok $brname]]] > 0} { $mb add command \ -label $options(custom_browser) \ -command [list [namespace current]::open_url \ $brname [lindex $e 0] $url] } } $m add cascade -label [::msgcat::mc "Open URL with"] -menu $mb } else { foreach {brname brdesc} $options(browsers) { if {[llength [set e [auto_execok $brname]]] > 0} { $m add command \ -label [::msgcat::mc "Open URL with %s" $brdesc] \ -command [list [namespace current]::open_url \ $brname [lindex $e 0] $url] } } if {$options(custom_browser) != "" && \ $options(path_to_custom_browser) != ""} { set brname $options(path_to_custom_browser) if {[llength [set e [auto_execok $brname]]] > 0} { $m add command \ -label [::msgcat::mc "Open URL with %s" \ $options(custom_browser)] \ -command [list [namespace current]::open_url \ $brname [lindex $e 0] $url] } } } } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/osd000075500000000000000000000000001500237002100142175ustar00nobodynobodytkabber-plugins/osd/ChangeLog000064400000000000000000000012601500237002100160470ustar00nobodynobody2004-12-22 Alexey Shchepin * osd.tcl: Updated to work with xosd 2.2.12 (thanks to Krzysztof Kotlenga) 2003-06-27 Alexey Shchepin * osd.tcl (::osd::presence_notify): Accept connid argument (thanks to Maciek Pasternacki) 2003-06-09 Alexey Shchepin * osd.tcl: Better presence displaying (thanks to Maciek Pasternacki) 2003-04-08 Alexey Shchepin * osd.tcl: Now possible to show messages notifications (thanks to Vincent Ricard) 2003-04-07 Alexey Shchepin * osd.tcl: Now it works again with recent versions of osd_cat, added osdfont variable (thanks to Jan Hudec) tkabber-plugins/osd/msgs000075500000000000000000000000001500237002100151705ustar00nobodynobodytkabber-plugins/osd/msgs/ru.msg000064400000000000000000000004071500237002100164060ustar00nobodynobody# ru.msg -- # # Russian messages for the OSD Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Whether the OSD plugin is loaded." \ "Загружено ли раÑширение OSD." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/osd/msgs/uk.msg000064400000000000000000000004151500237002100163760ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the OSD Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Whether the OSD plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ OSD." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/osd/osd.tcl000064400000000000000000000104671500237002100155770ustar00nobodynobody# osd.tcl -- # # Tkabber OSD Module. # # Requirements: # osd_cat: Utility to put messages on-screen. (apt-get install # xosd-bin in Debian) # # Author: Jan Hudec # Modifications: Sergei Golovan package require msgcat namespace eval ::osd { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered osd]} { ::plugins::register osd \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the OSD plugin\ is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable options "" variable delay 5 variable osdfont "" variable pipe "" variable statuses array set statuses {} } proc ::osd::load {} { if {![info exists ::osd] || $::osd == ""} return ::osd::open_osd_cat foreach event $::osd { switch -- $event { presence { hook::add client_presence_hook ::osd::presence_notify 100 } chat_message { hook::add draw_message_hook ::osd::chat_message_notify 20 } default { debugmsg osd "Unsupported notify type $event" } } } } proc ::osd::unload {} { if {![info exists ::osd] || $::osd == ""} return foreach event $::osd { switch -- $event { presence { hook::remove client_presence_hook ::osd::presence_notify 100 } chat_message { hook::remove draw_message_hook ::osd::chat_message_notify 20 } default { debugmsg osd "Unsupported notify type $event" } } } variable pipe close $pipe set pipe "" } proc ::osd::open_osd_cat {} { variable pipe variable options variable delay variable osdfont if {$pipe != ""} { close $pipe set pipe "" } set command "|osd_cat $options -d $delay -a$delay" if {$osdfont != ""} { append command " -f $osdfont" } debugmsg osd $command set pipe [open $command w] fconfigure $pipe -buffering line } proc ::osd::try_write {text} { variable pipe if {[catch {puts $pipe $text}]} { osd::open_osd_cat if {[catch {puts $pipe $text}]} { debugmsg osd "Can't write to OSD" } } } proc ::osd::presence_notify {xlib from type x args} { variable statuses if {[catch { set nick [get_nick $xlib $from chat] }]} { set nick "$from" } if {"$nick" != "$from"} { set thefrom "$nick ($from)" } else { set thefrom "$from" } if {"$type" == ""} { set type "available" } set status "" set show "" foreach {attr val} $args { switch -- $attr { -status { set status $val } -show { set show $val } } } if {"$status" != ""} { set status " ($status)" } if {"$show" != ""} { set type "$type/$show" } set newstatus "$thefrom: $type$status" if {[catch { set oldstatus $statuses($from) } ]} { set oldstatus "$newstatus" } if {"$newstatus" != "$oldstatus"} { osd::try_write "$newstatus" } set statuses($from) "$newstatus" } proc ::osd::chat_message_notify {chatid from type body extras} { if {[chat::is_our_jid $chatid $from] || $type ne "chat"} { return } foreach xelem $extras { ::xmpp::xml::split $xelem tag xmlns attrs cdata subels # Don't notify if this 'empty' tag is present. It indicates # messages history in chat window. if {[string equal $tag ""] && [string equal $xmlns tkabber:x:nolog]} { return } } set nick [get_nick [chat::get_xlib $chatid] $from $type] osd::try_write "New message from $nick" } proc ::osd::get_nick {xlib jid type} { if {[catch {chat::get_nick $xlib $jid $type} nick]} { return [chat::get_nick $jid $type] } else { return $nick } } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/otr000075500000000000000000000000001500237002100142365ustar00nobodynobodytkabber-plugins/otr/README000064400000000000000000000021301500237002100151710ustar00nobodynobodyAs usual, copy or link this directory to $HOME/.tkabber/plugins (on UNIX), to %APPDATA%\Tkabber\plugins (on Windows), or to $HOME/Library/Application Support/Tkabber (on MacOS X) directory. Restart Tkabber, then you'll find OTR submenu in Tkabber top menu, in users' roster menus and in chat tabs or message windows. On all systems this plugin requires Tcl 8.5 or newer because it uses an arbitrary precision integers. Also, the base64, sha1, sha256, aes, asn and math::bignum packages are required, they all are bundled with the Tcllib collection. For Windows this plugin also requires the Memchan package. Its [random] channel is used as a PRNG. To actually use OTR you'll need a 1024 bit DSA private key (OTR protocol supports only 1024 bit keys). There are two ways of making it work: 1) You can generate a new key directly in Tkabber (Main menu -> Tkabber -> OTR -> Manage private keys) 2) You can import an existing key stored in PEM format. To generate it outside Tkabber you can use OpenSSL: openssl dsaparam -out dsaparam.pem 1024 openssl gendsa -out otr.private.key dsaparam.pem Happy hacking! tkabber-plugins/otr/auth.tcl000064400000000000000000000251501500237002100157650ustar00nobodynobody# auth.tcl -- # # This file is a part of Off-the-record messaging plugin for # the Tkabebr XMPP client. It implements keeping track of # authenticated OTR buddies. namespace eval auth { variable ns http://tkabber.jabber.ru/otr variable otrdir [file join $::configdir otr] if {![file exists $otrdir]} { file mkdir $otrdir catch {file attributes $otrdir -permissions 0700} } # State variable with all auth data variable Auth [dict create] hook::add finload_hook [namespace current]::restore } proc auth::store {auth} { variable otrdir if {![catch { set fd [open [file join $otrdir auth.xml.new] w] fconfigure $fd -encoding utf-8 puts $fd {} puts $fd [serialize_auth $auth] close $fd } res]} { file rename -force -- [file join $otrdir auth.xml.new] \ [file join $otrdir auth.xml] } } proc auth::serialize_auth {auth} { variable ns set subtags {} dict for {jid val} $auth { set items [serialize_auth_items $jid $val] ::xmpp::xml::split $items tag xmlns attrs cdata subels if {[llength $subels] > 0} { lappend subtags $items } } ::xmpp::xml::toTabbedText [::xmpp::xml::create authentication \ -xmlns $ns \ -subelements $subtags] } proc auth::serialize_auth_items {jid items} { variable ns set subtags {} dict for {item val} $items { lappend subtags [serialize_auth_item $item $val] } ::xmpp::xml::create profile -xmlns $ns \ -attrs [list jid $jid] \ -subelements $subtags } proc auth::serialize_auth_item {item val} { variable ns lassign $item jid fingerprint ::xmpp::xml::create item -xmlns $ns \ -attrs [list jid $jid \ fingerprint $fingerprint \ auth $val] } proc auth::restore {} { variable otrdir variable Auth if {[catch {set fd [open [file join $otrdir auth.xml]]}]} { return [dict create] } set data [read $fd] close $fd set Auth [deserialize_auth [lindex [::xmpp::xml::parseData $data] 0]] } proc auth::deserialize_auth {xmlel} { variable ns ::xmpp::xml::split $xmlel tag xmlns attrs cdata subels if {$tag ne "authentication"} { return -code error "The root element must be 'authentication'" } if {$xmlns ne $ns} { return -code error "The namespace must be '$ns'" } set auth [dict create] foreach subel $subels { ::xmpp::xml::split $subel tag1 xmlns1 attrs1 cdata1 subels1 dict set auth [::xmpp::xml::getAttr $attrs1 jid] \ [deserialize_items $subels1] } set auth } proc auth::deserialize_items {xmlels} { set items [dict create] foreach xmlel $xmlels { ::xmpp::xml::split $xmlel tag xmlns attrs cdata subels dict set items [list [::xmpp::xml::getAttr $attrs jid] \ [::xmpp::xml::getAttr $attrs fingerprint]] \ [::xmpp::xml::getAttr $attrs auth] } set items } proc auth::set_auth {vauth myjid jid fingerprint value} { upvar $vauth auth set myjid [::xmpp::jid::normalize $myjid] set jid [::xmpp::jid::normalize $jid] if {![dict exists $auth $myjid]} { dict set auth $myjid [dict create] } dict set auth $myjid [list $jid $fingerprint] $value set auth } proc auth::del_auth {auth myjid jid fingerprint} { set myjid [::xmpp::jid::normalize $myjid] set jid [::xmpp::jid::normalize $jid] if {[dict exists $auth $myjid]} { dict unset auth $myjid [list $jid $fingerprint] } if {[llength [dict get $auth $myjid]] == 0} { dict unset auth $myjid } set auth } proc auth::get_auth {auth myjid jid fingerprint} { set myjid [::xmpp::jid::normalize $myjid] set jid [::xmpp::jid::normalize $jid] if {[catch {dict get $auth $myjid [list $jid $fingerprint]} res]} { return 0 } else { return $res } } proc auth::edit_auth_dialog {} { variable Auth variable authjid set w .otreditauth if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Edit OTR authentication"] \ -anchor e \ -default 0 \ -cancel 1 set f [$w getframe] $w add -text [::msgcat::mc "Apply"] \ -state disabled \ -command [namespace code [list apply_edit_auth_changes \ $w $f.items.listbox]] $w add -text [::msgcat::mc "Close"] \ -command [list destroy $w] set myjids [lsort [dict keys $Auth]] set authjid [lindex $myjids 0] set connections [connections] if {[llength $connections] > 0} { set myjid [::xmpp::jid::normalize \ [::xmpp::jid::removeResource [lindex $connections 0]]] if {[dict exists $Auth $myjid]} { set authjid $myjid } } trace add variable [namespace current]::authjid write \ [namespace code [list fill_mclistbox $w $f.items.listbox]] bind $w [list unset -nocomplain [namespace current]::authjid] if {[llength $myjids] == 0} { set myjids {""} } Label $f.lmyjid -text [::msgcat::mc "Your JID: "] tk_optionMenu $f.myjid [namespace current]::authjid {*}$myjids grid $f.lmyjid -row 0 -column 0 -sticky e grid $f.myjid -row 0 -column 1 -sticky ew set sw [ScrolledWindow $f.items] set l [::mclistbox::mclistbox $sw.listbox -width 100 -height 16] grid $sw -row 1 -column 0 -columnspan 2 -sticky nsew $sw setwidget $l bind $l <> \ [namespace code [list select_and_popup_menu \ [double% $w] [double% $l] %x %y]] bindscroll $sw $l set label(N) [::msgcat::mc #] set label(jid) [::msgcat::mc JID] set label(fingerprint) [::msgcat::mc Fingerprint] set label(auth) [::msgcat::mc Authenticated] set label(del) [::msgcat::mc Delete] $l column add N -label $label(N) foreach name {jid fingerprint auth del} { $l column add $name -label $label($name) \ -image search/sort/noArrow \ -command [list search::Sort $l $name] } $l column add filler -label "" -width 0 $l configure -fillcolumn filler fill_mclistbox $w $l $w draw } proc auth::fill_mclistbox {w l args} { variable Auth variable authjid if {![winfo exists $l]} return if {[dict exists $Auth $authjid]} { set items [dict get $Auth $authjid] } else { set items {} } $l delete 0 end foreach name {N jid fingerprint auth del} { set width($name) [string length [$l column cget $name -label]] incr width($name) 5 } set row 0 dict for {key val} $items { lassign $key jid fingerprint if {$val} { set data(auth) [::msgcat::mc Yes] } else { set data(auth) [::msgcat::mc No] } set data(N) [incr row] set data(jid) $jid set data(fingerprint) $fingerprint foreach name {N jid fingerprint auth} { if {$width($name) < [string length $data($name)] + 2} { set width($name) [string length $data($name)] incr width($name) 2 } } $l insert end [list $data(N) $data(jid) \ $data(fingerprint) $data(auth) ""] } foreach name {N jid fingerprint auth del} { $l column configure $name -width $width($name) } # The filled listbox is unchanged, so disable apply button $w itemconfigure 0 -state disabled } proc auth::select_and_popup_menu {w l x y} { set index [$l find $x $y] if {$index < 0} return $l sel clear 0 end $l sel set $index if {[winfo exists [set m .otrauthpopupmenu]]} { destroy $m } menu $m -tearoff 0 $m add command -label [::msgcat::mc "Set authenticated"] \ -command [namespace code [list set_authenticated \ $w $l $index 1]] $m add command -label [::msgcat::mc "Unset authenticated"] \ -command [namespace code [list set_authenticated \ $w $l $index 0]] $m add command -label [::msgcat::mc "Mark for deletion"] \ -command [namespace code [list set_delete $w $l $index 1]] $m add command -label [::msgcat::mc "Unmark for deletion"] \ -command [namespace code [list set_delete $w $l $index 0]] $m add command -label [::msgcat::mc "Copy to clipboard"] \ -command [namespace code [list copy_to_clipboard \ $w $l $index]] tk_popup $m [winfo pointerx .] [winfo pointery .] } proc auth::copy_to_clipboard {w l index} { set data [$l get $index] clipboard clear clipboard append [lindex $data 1] clipboard append " " clipboard append [lindex $data 2] } proc auth::set_authenticated {w l index val} { if {$val} { set auth [::msgcat::mc Yes] } else { set auth [::msgcat::mc No] } set data [lreplace [$l get $index] 3 3 $auth] $l delete $index $l insert $index $data $l sel set $index $w itemconfigure 0 -state normal $w itemconfigure 1 -text [::msgcat::mc "Cancel"] } proc auth::set_delete {w l index val} { if {$val} { set del [::msgcat::mc Yes] } else { set del "" } set data [lreplace [$l get $index] 4 4 $del] $l delete $index $l insert $index $data $l sel set $index $w itemconfigure 0 -state normal $w itemconfigure 1 -text [::msgcat::mc "Cancel"] } proc auth::apply_edit_auth_changes {w l} { variable Auth variable authjid $w itemconfigure 0 -state disabled $w itemconfigure 1 -text [::msgcat::mc "Close"] set data [$l get 0 end] set items [dict create] foreach item $data { lassign $item i jid fingerprint auth del if {$del eq [::msgcat::mc Yes]} continue if {$auth eq [::msgcat::mc Yes]} { set auth1 1 } else { set auth1 0 } dict set items [list $jid $fingerprint] $auth1 } dict set Auth $authjid $items store $Auth [namespace parent]::reset_auth $authjid fill_mclistbox $w $l } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/otr/key.tcl000064400000000000000000000357651500237002100156310ustar00nobodynobody# key.tcl -- # # This file is a part of Off-the-record messaging plugin for # the Tkabebr XMPP client. It implements interface for private # key management (storing, generating, exporting, importing). package require otr::crypto package require otr::key namespace eval key { variable ns http://tkabber.jabber.ru/otr variable otrdir [file join $::configdir otr] if {![file exists $otrdir]} { file mkdir $otrdir catch {file attributes $otrdir -permissions 0700} } # State variable with all key data variable Keys [dict create] hook::add finload_hook [namespace current]::restore } proc key::store {keys} { variable otrdir if {![catch { set fd [open [file join $otrdir keys.xml.new] w] fconfigure $fd -encoding utf-8 puts $fd {} puts $fd [serialize_keys $keys] close $fd } res]} { file rename -force -- [file join $otrdir keys.xml.new] \ [file join $otrdir keys.xml] } } proc key::serialize_keys {keys} { variable ns set subtags {} dict for {jid val} $keys { lappend subtags [serialize_key $jid $val] } ::xmpp::xml::toTabbedText [::xmpp::xml::create privkeys \ -xmlns $ns \ -subelements $subtags] } proc key::serialize_key {jid key} { variable ns set attrs [list jid $jid \ type DSA \ p [format %llx [lindex $key 0]] \ q [format %llx [lindex $key 1]] \ g [format %llx [lindex $key 2]] \ y [format %llx [lindex $key 3]] \ x [format %llx [lindex $key 4]]] ::xmpp::xml::create key -xmlns $ns \ -attrs $attrs } proc key::restore {} { variable otrdir variable Keys if {[catch {set fd [open [file join $otrdir keys.xml]]}]} { return [dict create] } set data [read $fd] close $fd set Keys [deserialize_keys [lindex [::xmpp::xml::parseData $data] 0]] } proc key::deserialize_keys {xmlel} { variable ns ::xmpp::xml::split $xmlel tag xmlns attrs cdata subels if {$tag ne "privkeys"} { return -code error "The root element must be 'privkeys'" } if {$xmlns ne $ns} { return -code error "The namespace must be '$ns'" } set keys [dict create] foreach subel $subels { ::xmpp::xml::split $subel tag1 xmlns1 attrs1 cdata1 subels1 if {[::xmpp::xml::getAttr $attrs1 type] eq "DSA"} { scan [::xmpp::xml::getAttr $attrs1 p] %llx p scan [::xmpp::xml::getAttr $attrs1 q] %llx q scan [::xmpp::xml::getAttr $attrs1 g] %llx g scan [::xmpp::xml::getAttr $attrs1 y] %llx y scan [::xmpp::xml::getAttr $attrs1 x] %llx x dict set keys [::xmpp::xml::getAttr $attrs1 jid] \ [list $p $q $g $y $x] } } set keys } proc key::set_key {vkeys jid key} { upvar $vkeys keys set jid [::xmpp::jid::normalize $jid] dict set keys $jid $key set keys } proc key::del_key {vkeys jid} { upvar $vkeys keys set jid [::xmpp::jid::normalize $jid] if {[dict exists $keys $jid]} { dict unset keys $myjid } set keys } proc key::get_key {keys jid} { set jid [::xmpp::jid::normalize $jid] if {[catch {dict get $keys $jid} res]} { return {} } else { return $res } } proc key::manage_keys_dialog {} { variable Keys variable keyjid variable progress variable help variable fingerprint set w .otreditkeys if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Manage OTR private keys"] \ -anchor e \ -default 0 \ -cancel 0 set f [$w getframe] $w add -text [::msgcat::mc "Close"] -command [list destroy $w] # Start with the existing keys set jids [lsort [dict keys $Keys]] # Next, the existing connections foreach xlib [connections] { lappend jids [::xmpp::jid::normalize \ [::xmpp::jid::removeResource [connection_jid $xlib]]] } # Next the existing profiles for {set i 1} {[info exists ::loginconf$i]} {incr i} { upvar #0 ::loginconf$i loginconf if {$loginconf(user) ne "" && $loginconf(server) ne ""} { lappend jids [::xmpp::jid::normalize \ [::xmpp::jid::jid $loginconf(user) $loginconf(server)]] } } # Finally, the ::loginconf if {$::loginconf(user) ne "" && $::loginconf(server) ne ""} { lappend jids [::xmpp::jid::normalize \ [::xmpp::jid::jid $::loginconf(user) \ $::loginconf(server)]] } set jids [lsort -unique -dictionary $jids] if {[llength [connections]] > 0} { set keyjid [::xmpp::jid::normalize \ [::xmpp::jid::removeResource \ [connection_jid [lindex [connections] 0]]]] } else { set keyjid [lindex $jids 0] } trace add variable [namespace current]::keyjid write \ [namespace code [list fill_dialog $w $f]] bind $w [list unset -nocomplain [namespace current]::keyjid] bind $w +[list unset -nocomplain [namespace current]::progress] bind $w +[list unset -nocomplain [namespace current]::help] bind $w +[list unset -nocomplain \ [namespace current]::fingerprint] bind $w <> [namespace code [list add_to_clipboard]] Message $f.header -text [::msgcat::mc "Manage OTR long term DSA private\ key for your JID"] \ -width 12c grid $f.header -row 0 -column 0 -columnspan 2 -sticky nsew tk_optionMenu $f.jid [namespace current]::keyjid {*}$jids grid $f.jid -row 1 -column 0 -columnspan 2 -sticky ew Message $f.help -textvariable [namespace current]::help -width 12c grid $f.help -row 2 -column 0 -columnspan 2 -sticky nsew Message $f.fingerprint \ -textvariable [namespace current]::fingerprint -width 12c grid $f.fingerprint -row 3 -column 0 -columnspan 2 -sticky nsew Button $f.import -text [::msgcat::mc "Import key..."] \ -command [namespace code [list import_key $w]] grid $f.import -row 4 -column 0 -sticky nsew Button $f.export -text [::msgcat::mc "Export key..."] \ -command [namespace code [list export_key $w]] grid $f.export -row 4 -column 1 -sticky nsew Button $f.gen -text [::msgcat::mc "Generate new key"] \ -command [namespace code [list generate_key $w]] grid $f.gen -row 5 -column 0 -sticky nsew Button $f.delete -text [::msgcat::mc "Delete key"] \ -command [namespace code [list delete_key $w]] grid $f.delete -row 5 -column 1 -sticky nsew set progress -1 Progressbar $f.pb -variable [namespace current]::progress \ -maximum 200 \ -mode indeterminate # HACK: The following configure works for Ttk only. There's no need to # switch mode back and forth in Tk. catch {$f.pb configure -mode determinate} grid $f.pb -row 6 -column 0 -columnspan 2 -sticky ew Frame $f.f -width 12c -height 0m grid $f.f -row 7 -column 0 -columnspan 2 -sticky ew fill_dialog $w $w draw } # key::add_to_clipboard -- # # Add the current fingerprint to clipboard. # # Arguments: # None # # Result: # Empty string. # # Side effects: # The current DSA key fingerprint is put to clipboard. proc key::add_to_clipboard {} { variable fingerprint clipboard clear clipboard append $fingerprint } # key::fill_dialog -- # # Private procedure which showa an appropriate help message and # enables or disables the dialog controls depending on whether a DSA # key for the selected JID exists. # # Arguments: # w Dialog window path. # args Ignored arguments from [trace] command. # # Result: # Empty string. # # Side effects: # The help message in the keys dialog is set, the buttons are enabled # or disabled. proc key::fill_dialog {w args} { variable Keys variable keyjid variable help variable fingerprint if {![winfo exists $w]} return set f [$w getframe] if {[dict exists $Keys $keyjid]} { set help [::msgcat::mc "The fingerprint of your long term OTR DSA\ private key for this JID is the following:"] set key [dict get $Keys $keyjid] binary scan [::otr::crypto::DSAFingerprint $key] Iu* nums set res {} foreach n $nums { lappend res [format %llX $n] } set fingerprint $res $f.import configure -state normal $f.export configure -state normal $f.gen configure -state normal $f.delete configure -state normal join $res } else { set help [::msgcat::mc "You don't have a private DSA key for this JID.\ Either import a 1024 bit DSA private key, or\ generate one."] set fingerprint "" $f.import configure -state normal $f.export configure -state disabled $f.gen configure -state normal $f.delete configure -state disabled } return } # key::import_key -- # # Private procedure which imports DSA key to a key file in PEM format # and either adds it or replaces the existing one. # # Arguments: # w Dialog window path. # # Result: # Empty string. # # Side effects: # The key for a given JID is read from an external file. The filename # where to get the key is asked in an addiyional dialog. JID for which # the key is to import is taken from the $keyjid variable. The key # itself is stored to the global $Keys dictionary and to the # ~/.tkabber/otr/keys.xml file. proc key::import_key {w} { variable Keys variable keyjid set filename [tk_getOpenFile \ -initialdir $::configdir \ -filetypes \ [list [list [::msgcat::mc "Key files"] *.key] \ [list [::msgcat::mc "All files"] *]]] if {$filename == ""} return if {![file readable $filename]} { MessageDlg .otrfileunreadable -aspect 50000 -icon error \ -message [::msgcat::mc "Can't open the key file \"%s\"" \ $filename] \ -type user -buttons ok -default 0 -cancel 0 return } if {[catch {::otr::key::readPEM $filename} key]} { MessageDlg .otrfileunreadable -aspect 50000 -icon error \ -message [::msgcat::mc "Can't import DSA key from the\ file \"%s\": %s" $filename $key] \ -type user -buttons ok -default 0 -cancel 0 return } if {![dict exists $Keys $keyjid] || [dict get $Keys $keyjid] ne $key} { dict set Keys $keyjid $key store $Keys [namespace parent]::clear_all_jid $keyjid } fill_dialog $w return } # key::export_key -- # # Private procedure which exports existing DSA key to a key file in PEM # format. # # Arguments: # w Dialog window path. # # Result: # Empty string. # # Side effects: # The key for a given JID is saved into an external file. The filename # where to save the key is asked in an addiyional dialog. JID for which # the key is to export is taken from the $keyjid variable. The key # itself is taken from the global $Keys dictionary. proc key::export_key {w} { variable Keys variable keyjid set filename [tk_getSaveFile \ -initialdir $::configdir \ -initialfile otr-$keyjid.key \ -filetypes \ [list [list [::msgcat::mc "Key files"] *.key] \ [list [::msgcat::mc "All files"] *]]] if {$filename == ""} return set key [dict get $Keys $keyjid] ::otr::key::writePEM $key $filename return } # key::delete_key -- # # Private procedure which deletes DSA key from the keys dictionary and # from the external storage. # # Arguments: # w Dialog window path. # # Result: # Empty string. # # Side effects: # The key for a given JID is deleted from the $Keys dictionary and # from ~/.tkabber/otr/keys.xml. JID for which the key is to delete # is taken from the $keyjid variable. proc key::delete_key {w} { variable Keys variable keyjid if {[dict exists $Keys $keyjid]} { dict unset Keys $keyjid store $Keys [namespace parent]::clear_all_jid $keyjid } fill_dialog $w return } # key::generate_key -- # # Private procedure which generates and store new DSA private key. # Before starting, the dialog controls are disabled, upon finishing, # they are enabled again. # # Arguments: # w Dialog window path. # # Result: # Empty string. # # Side effects: # New key is generated and stored into the $Keys dictionary and # ~/.tkabber/otr/keys.xml. JID for which to store the key is taken # from the $keyjid variable. Progress is tracking by increasing # the $progress variable upon each internal iteration. proc key::generate_key {w} { variable Keys variable keyjid variable progress set L 1024 set N 160 $w itemconfigure 0 -state disabled set f [$w getframe] catch {$f.pb configure -mode indeterminate} $f.jid configure -state disabled $f.import configure -state disabled $f.export configure -state disabled $f.gen configure -state disabled $f.delete configure -state disabled set newkey [::otr::key::generate $L $N] incr progress if {![dict exists $Keys $keyjid] || [dict get $Keys $keyjid] ne $newkey} { dict set Keys $keyjid $newkey store $Keys [namespace parent]::clear_all_jid $keyjid } set progress -1 catch {$f.pb configure -mode determinate} fill_dialog $w $w itemconfigure 0 -state normal $f.jid configure -state normal return } # ::otr::crypto::GenPrimesIteration -- # A dirty hack which overrides ::otr::crypto::genPrimesIteration and # adds a side effect which updates progressbar. This helps not freezing # the GUI during DSA private key generation. # [subst] substitutes [namespace current]. rename ::otr::crypto::GenPrimesIteration ::otr::crypto::GenPrimesIteration:old proc ::otr::crypto::GenPrimesIteration {L t q p0 pseed pgen_counter} \ [subst -novariables { incr [namespace current]::key::progress update ::otr::crypto::GenPrimesIteration:old $L $t $q $p0 $pseed $pgen_counter }] # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/otr/msgs000075500000000000000000000000001500237002100152075ustar00nobodynobodytkabber-plugins/otr/msgs/ru.msg000064400000000000000000000456501500237002100164360ustar00nobodynobody# ru.msg -- # # Russian messages for the Tkabber OTR plugin. # # Author: Sergei Golovan # ./auth.tcl ::msgcat::mcset ru "#" "â„–" ::msgcat::mcset ru "Apply" "Применить" ::msgcat::mcset ru "Authenticated" "Ðутентифицирован" ::msgcat::mcset ru "Cancel" "Отменить" ::msgcat::mcset ru "Copy to clipboard" "Скопировать в буфер обмена" ::msgcat::mcset ru "Delete" "Удалить" ::msgcat::mcset ru "Edit OTR authentication" "Изменить аутентификацию OTR" ::msgcat::mcset ru "Fingerprint" "Отпечаток" ::msgcat::mcset ru "JID" "JID" ::msgcat::mcset ru "Mark for deletion" "Отметить Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ" ::msgcat::mcset ru "No" "Ðет" ::msgcat::mcset ru "Set authenticated" "Отметить как аутентифицированного" ::msgcat::mcset ru "Unmark for deletion" "СнÑть отметку Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ" ::msgcat::mcset ru "Unset authenticated" "Отметить как не аутентифицированного" ::msgcat::mcset ru "Yes" "Да" ::msgcat::mcset ru "Your JID: " "Ваш JID:" # ./otr.tcl ::msgcat::mcset ru "%s has requested an Off-the-Record private conversation,\ but you can't maintain it because you don't have your OTR private key\ configured." "%s предложил вам воÑпользоватьÑÑ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ð¾Ð¼ OTR длÑ\ безопаÑного разговора, но вы не можете его поддержать, потому что\ у Ð²Ð°Ñ Ð½ÐµÑ‚ Ñконфигурированного закрытого ключа OTR." ::msgcat::mcset ru "%s have sent you an OTR encrypted message, but you can't\ decipher it because you don't have your OTR private key configured." \ "%s приÑлал вам Ñообщение, зашифрованное Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ OTR, но вы не\ можете раÑшифровать его, так как у Ð²Ð°Ñ Ð½ÐµÑ‚ Ñконфигурированного\ закрытого ключа OTR." ::msgcat::mcset ru "Advertise your support of OTR using the whitespace tag." \ "Показывать поддержку OTR, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð¼ÐµÑ‚ÐºÑƒ из пробельных Ñимволов." ::msgcat::mcset ru "Allow Tkabber to use Off-the-Record protocol (version 2 or\ 3)." "Разрешить Tkabber'у иÑпользовать протокол OTR (верÑию 2 или 3)." ::msgcat::mcset ru "Allow encryption" "Разрешить шифрование" ::msgcat::mcset ru "Attach whitespace tag" \ "ПрикреплÑть метку из пробельных Ñимволов" ::msgcat::mcset ru "Authenticate" "Ðутентифицировать" ::msgcat::mcset ru "Authenticate %s" "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ %s" ::msgcat::mcset ru "Authenticate %s\n\nAuthenticating a peer helps ensure\ that the person you are talking to is who he or she claims to be." \ "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ ÑобеÑедника помогает удоÑтоверитьÑÑ, что он (или она)\ тот, за кого ÑÐµÐ±Ñ Ð²Ñ‹Ð´Ð°ÐµÑ‚." ::msgcat::mcset ru "Authenticate %s\n\nAuthenticating a peer helps ensure\ that the person you are talking to is who he or she claims to\ be.\n\nHow would you like to authenticate your peer?" "ÐутентификациÑ\ %s\n\nÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ ÑобеÑедника помогает удоÑтоверитьÑÑ, что он (или\ она) тот, за кого ÑÐµÐ±Ñ Ð²Ñ‹Ð´Ð°ÐµÑ‚." ::msgcat::mcset ru "Authenticate peer..." "Ðутентифицировать ÑобеÑедника..." ::msgcat::mcset ru "Authentication aborted" "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð¿Ñ€ÐµÑ€Ð²Ð°Ð½Ð°" ::msgcat::mcset ru "Authentication failed" "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð½Ðµ удалаÑÑŒ" ::msgcat::mcset ru "Authentication from %s" "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð¾Ñ‚ %s" ::msgcat::mcset ru "Authentication succeeded" "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ ÑƒÑпешнаÑ" ::msgcat::mcset ru "Do not log OTR messages." "Ðе журналировать ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ OTR." ::msgcat::mcset ru "Don't log OTR messages" "Ðе журналировать ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ OTR" ::msgcat::mcset ru "Edit authentication" "Изменение аутентификации" ::msgcat::mcset ru "End OTR session" "Завершить ÑеÑÑию OTR" ::msgcat::mcset ru "Enter question here:" "Введите Ð²Ð¾Ð¿Ñ€Ð¾Ñ Ð·Ð´ÐµÑÑŒ:" ::msgcat::mcset ru "Enter secret answer here (case sensitive):" \ "Введите Ñекретный ответ здеÑÑŒ (чувÑтвителен к региÑтру):" ::msgcat::mcset ru "Enter secret here (case sensitive):" \ "Введите Ñекрет здеÑÑŒ (чувÑтвителен к региÑтру):" ::msgcat::mcset ru "Fingerprint for you, %s:\n%s" \ "Отпечаток вашего (%s) ключа:\n%s" ::msgcat::mcset ru "Fingerprint:" "Отпечаток:" ::msgcat::mcset ru "Finished" "Завершен" ::msgcat::mcset ru "I have not verified" "Я не удоÑтоверилÑÑ" ::msgcat::mcset ru "I have verified" "Я удоÑтоверилÑÑ" ::msgcat::mcset ru "If the interval between two consecutive incoming OTR\ messages exceeds the specified interval (in minutes, zero means\ no heartbeat at all) the heartbeat message will be sent to change\ the session keys." "ЕÑли интервал между Ð´Ð²ÑƒÐ¼Ñ Ð¿Ð¾Ñледовательными\ зашифрованными ÑообщениÑми превышает данный (в минутах, ноль\ означает отключение), то Ñпециальное пуÑтое Ñообщение будет\ отоÑлано, чтобы обновить ÑеÑÑионные ключи." ::msgcat::mcset ru "Manage private keys" "Управление закрытыми ключами" ::msgcat::mcset ru "Manual fingerprint verification" \ "Ð ÑƒÑ‡Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° отпечатка" ::msgcat::mcset ru "Not private" "Ðе шифрованное" ::msgcat::mcset ru "OK" "Продолжить" ::msgcat::mcset ru "OTR" "OTR" ::msgcat::mcset ru "OTR conversation is lost because you have changed your\ OTR key. The next private chat will use the new key." "Ð¡ÐµÐ°Ð½Ñ OTR\ завершен, так как вы Ñменили закрытый ключ. При Ñледующем шифрованном\ разговоре будет иÑпользоватьÑÑ Ð½Ð¾Ð²Ñ‹Ð¹ ключ." ::msgcat::mcset ru "OTR Error:" "Ошибка OTR:" ::msgcat::mcset ru "OTR Info:" "Сообщение OTR:" ::msgcat::mcset ru "OTR icons theme." "Тема пиктограмм OTR." ::msgcat::mcset ru "OTR is disabled because you have deleted your OTR key.\ Generate or import a new one if you want to enable it again." \ "Шифрование OTR отключено, так как вы удалили Ñвой закрытый ключ.\ Сгенерируйте или импротируйте новый, еÑли вы хотите включить его\ Ñнова." ::msgcat::mcset ru "Off-the-record messaging plugin options." \ "Параметры раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð·Ð°Ñ‰Ð¸Ñ‰ÐµÐ½Ð½Ð¾Ð¹ перепиÑки OTR." ::msgcat::mcset ru "Plugins options." "Параметры раÑширений." ::msgcat::mcset ru "Personal OTR preferences." \ "Личные наÑтройки раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ OTR" ::msgcat::mcset ru "Private" "Защищенный" ::msgcat::mcset ru "Problem loading TclOTR. The OTR functionality will be\ disabled.\nRefer to the README file of the OTR plugin." \ "Проблема при подключении TclOTR. РаÑширение OTR будет\ отключено.\nПрочитайте файл README, приложенный к Ñтому раÑширению." ::msgcat::mcset ru "Protocol error" "Ошибка протокола" ::msgcat::mcset ru "Purported fingerprint for %s:\n%s" \ "Предполагаемый отпечаток ключа %s:\n%s" ::msgcat::mcset ru "Question and answer" "Ð’Ð¾Ð¿Ñ€Ð¾Ñ Ð¸ ответ" ::msgcat::mcset ru "Refresh OTR session" "ПерезапуÑтить ÑеÑÑию OTR" ::msgcat::mcset ru "Refuse to send unencrypted messages. Note that if this\ option is enabled and the previous one is not then you will not be\ able to send any chat or normal messages at all" "ОтказыватьÑÑ\ поÑылать незашифрованные ÑообщениÑ. Заметьте, что еÑли Ñта опциÑ\ включена, а Ð¿Ñ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°, то вы не Ñможете поÑылать\ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ ÑовÑем (кроме групповых)." ::msgcat::mcset ru "Require encryption" "Требовать шифрование" ::msgcat::mcset ru "Reset to default policy" "Вернуть наÑтройки по умолчанию" ::msgcat::mcset ru "SMP verification is in progress. If you want to start\ new one, abort the current one first" "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñ Ð¸Ñпользованием\ протокола SMP уже идет. ЕÑли вы хотите начать заново, Ñначала отмените\ текущую." ::msgcat::mcset ru "Shared secret" "Общий Ñекрет" ::msgcat::mcset ru "Start AKE on whitespace tag or OTR error" "Ðачинать AKE\ при получении метки из пробельных Ñимволов или ошибки OTR" ::msgcat::mcset ru "Start OTR session" "Ðачать ÑеÑÑию OTR" ::msgcat::mcset ru "Start the OTR authenticated key exchange when you\ receive a whitespace tag or an OTR error message." "Ðачинать\ аутентифицированный обмен ключами OTR при получении ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñо\ Ñпециальной меткой из пробельных Ñимволов или при получении\ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ð± ошибке OTR." ::msgcat::mcset ru "SSID:" "Идентификатор ÑеÑÑии:" ::msgcat::mcset ru "State:" "СоÑтоÑние:" ::msgcat::mcset ru "This is the question asked by your peer:" \ "ВопроÑ, который задал ваш ÑобеÑедник:" ::msgcat::mcset ru "Tkabber is too old for the OTR plugin" \ "ВерÑÐ¸Ñ Tkabber'а Ñлишком ÑÑ‚Ð°Ñ€Ð°Ñ Ð´Ð»Ñ Ñ€Ð°ÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ OTR" ::msgcat::mcset ru "To authenticate using a question, pick a question\ whose answer is known only to you and your peer. Enter this\ question and this answer, then wait for your peer to enter\ the answer too. If the answers don't match then you may be\ talking to an imposter." "Чтобы аутентифицировать ÑобеÑедника\ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ вопроÑа и ответа, выберите вопроÑ, ответ на который\ извеÑтен только вам двоим, введите Ð²Ð¾Ð¿Ñ€Ð¾Ñ Ð¸ ответ, и подождите,\ пока ваш ÑобеÑедник не введет ответ тоже. ЕÑли ответы не Ñовпадут,\ возможно ваш ÑобеÑедник не тот, за кого ÑÐµÐ±Ñ Ð²Ñ‹Ð´Ð°ÐµÑ‚." ::msgcat::mcset ru "To authenticate, pick a secret known only to you\ and your peer. Enter this secret, then wait for your peer to\ enter it too. If the secrets don't match then you may be\ talking to an imposter." "Чтобы аутентифицировать ÑобеÑедника,\ выберите Ñекрет, извеÑтный только вам двоим. Введите Ñтот Ñекрет\ и подождите, пока ваш ÑобеÑедник не введет его тоже. ЕÑли Ñекреты\ не Ñовпадут, возможно ваш ÑобеÑедник не тот, за кого ÑÐµÐ±Ñ Ð²Ñ‹Ð´Ð°ÐµÑ‚." ::msgcat::mcset ru "To verify the fingerprint, contact your peer via\ some other authenticated channel, such as the phone or\ GPG-signed email. Each of you should tell your fingerprint to\ the other. if everything matches up, you should indicate in\ this dialog that you have verified the fingerprint." "Чтобы\ убедитьÑÑ, что Ñто дейÑтвительно отпечаток открытого ключа\ ÑобеÑедника, ÑвÑжитеÑÑŒ Ñ Ð½Ð¸Ð¼ по какому-нибудь другому защищенному\ каналу ÑвÑзи, например, по телефону или подпиÑанному Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ GPG\ Ñлектронному пиÑьму. Каждый из Ð²Ð°Ñ Ð´Ð¾Ð»Ð¶ÐµÐ½ назвать другому отпечаток\ Ñвоего ключа. ЕÑли вÑе Ñовпало, то вы можете указать, что вы\ удоÑтоверилиÑÑŒ в подлинноÑти ключа." ::msgcat::mcset ru "Unverified" "Ðепроверенное" ::msgcat::mcset ru "View" "Вид" ::msgcat::mcset ru "You cannot verify the peer's identity using SMP\nif\ an OTR session is not in progress" "ÐÐµÐ»ÑŒÐ·Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€Ð¸Ñ‚ÑŒ личноÑть\ ÑобеÑедника Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ протокола SMP, пока не начата ÑеÑÑÐ¸Ñ OTR" ::msgcat::mcset ru "Your peer is attempting to determine if he or she\ is really talking to you, or if it's someone pretending to be\ you. Your peer has asked a question, indicated below. To\ authenticate to your peer, enter the answer and click\ 'Authenticate'." "Ваш ÑобеÑедник пытаетÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€Ð¸Ñ‚ÑŒ, дейÑтвительно\ ли он разговаривает Ñ Ð²Ð°Ð¼Ð¸, или Ñто кто-то вами притворÑющийÑÑ.\ Он задал вопроÑ, приведенный ниже. Чтобы подтвердить Ñвою личноÑть,\ введите ответ и нажмите 'Ðутентифицировать'." ::msgcat::mcset ru "Your peer is attempting to determine if he or she\ is really talking to you, or if it's someone pretending to be\ you. Your peer has picked a secret known only to him or her and\ you. To authenticate to your peer, enter this secret and click\ 'Authenticate'." "Ваш ÑобеÑедник пытаетÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€Ð¸Ñ‚ÑŒ, дейÑтвительно\ ли он разговаривает Ñ Ð²Ð°Ð¼Ð¸, или Ñто кто-то вами притворÑющийÑÑ.\ Он выбрал Ñекрет, извеÑтный только вам двоим. Чтобы подтвердить\ Ñвою личноÑть, введите Ñтот Ñекрет и нажмите 'Ðутентифицировать'." ::msgcat::mcset ru "\n\tOTR:" "\n\tOTR:" ::msgcat::mcset ru "that this is in fact the correct fingerprint for %s" \ "что Ñто на Ñамом деле верный отпечаток ключа %s" # ./key.tcl ::msgcat::mcset ru "All files" "Ð’Ñе файлы" ::msgcat::mcset ru "Can't import DSA key from the file \"%s\": %s" \ "Ðе удалоÑÑŒ импортировать ключ DSA из файла \"%s\": %s" ::msgcat::mcset ru "Can't open the key file \"%s\"" "Ðе удалоÑÑŒ открыть\ файл Ñ ÐºÐ»ÑŽÑ‡Ð¾Ð¼ \"%s\"" ::msgcat::mcset ru "Close" "Закрыть" ::msgcat::mcset ru "Delete key" "Удалить ключ" ::msgcat::mcset ru "Export key..." "ЭкÑпортировать ключ..." ::msgcat::mcset ru "Generate new key" "Сгенегрировать новый ключ" ::msgcat::mcset ru "Import key..." "Импортировать ключ..." ::msgcat::mcset ru "Key files" "Файлы ключей" ::msgcat::mcset ru "Manage OTR long term DSA private key for your JID" \ "Управление долгоживущими закрытыми ключами DSA протокола OTR Ð´Ð»Ñ JID" ::msgcat::mcset ru "Manage OTR private keys" "Управление закрытыми ключами OTR" ::msgcat::mcset ru "The fingerprint of your long term OTR DSA private key\ for this JID is the following:" "Отпечаток вашего долгоживущего\ закрытого ключа OTR Ñледующий:" ::msgcat::mcset ru "You don't have a private DSA key for this JID. Either\ import a 1024 bit DSA private key, or generate one." "У Ð²Ð°Ñ Ð½ÐµÑ‚\ закрытого ключа DSA Ð´Ð»Ñ Ñтого JID. Или мпортируйте, или Ñгенерируйте\ Ñебе 1024-битный ключ." ::msgcat::mcset ru "Encrypted message can't be deciphered" "Зашифрованное\ Ñообщение не удалоÑÑŒ раÑшифровать" ::msgcat::mcset ru "Last message has been resent" "ПоÑледнее Ñообщение было\ отоÑлано повторно" ::msgcat::mcset ru "Last message should have been resent but has not because\ the peer's OTR key has been changed" "ПоÑледнее Ñообщение Ñледовало\ бы отоÑлать повторно, но оно не было отÑлано, так как ключ OTR\ ÑобеÑедника изменилÑÑ" ::msgcat::mcset ru "Message is not sent because encryption is required.\ Trying to start private conversation..." "Сообщение не отправлено,\ так как шифрование обÑзательно. Пробуем начать приватный разговор..." ::msgcat::mcset ru "Message is not sent. Either end your private\ conversation, or restart it" "Сообщение не отправлено. Или\ завершите защищенный разговор, или начните заново" ::msgcat::mcset ru "OTR request message is received but it uses an\ incompatible or disabled protocol version" "Получено Ñообщение Ñ\ запроÑом ÑеÑÑии OTR, но в нем иÑпользуетÑÑ Ð½ÐµÐ¿Ð¾Ð´Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°ÐµÐ¼Ð°Ñ Ð¸Ð»Ð¸\ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ð°" ::msgcat::mcset ru "OTR request message is received but you have disabled\ encryption" "Получено Ñообщение Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñом ÑеÑÑии OTR, но вы\ отключили шифрование" ::msgcat::mcset ru "Unmatched protocol versions" "ÐеÑовпадающие верÑии\ протокола" ::msgcat::mcset ru "Private conversation is refreshed" "Защищенный разговор\ начат заново" ::msgcat::mcset ru "Private conversation is started" "Защищенный разговор\ начат" ::msgcat::mcset ru "Private conversation is finished" "Защищенный разговор\ закончен" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/otr/msgs/uk.msg000064400000000000000000000457671500237002100164400ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Tkabber OTR plugin. # # Author: Sergei Golovan # ./auth.tcl ::msgcat::mcset uk "#" "â„–" ::msgcat::mcset uk "Apply" "ПриклаÑти" ::msgcat::mcset uk "Authenticated" "Ðутентифікований" ::msgcat::mcset uk "Cancel" "Відмінити" ::msgcat::mcset uk "Copy to clipboard" "Скопіювати в буфер обміну" ::msgcat::mcset uk "Delete" "Видалити" ::msgcat::mcset uk "Edit OTR authentication" "Змінити аутентифікацію OTR" ::msgcat::mcset uk "Fingerprint" "Відбиток" ::msgcat::mcset uk "JID" "JID" ::msgcat::mcset uk "Mark for deletion" "Відмітити Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ" ::msgcat::mcset uk "No" "ÐÑ–" ::msgcat::mcset uk "Set authenticated" "Відмітити Ñк аутентифікованного" ::msgcat::mcset uk "Unmark for deletion" "ЗнÑти відмітку Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ" ::msgcat::mcset uk "Unset authenticated" "Відмітити Ñк не аутентифікованного" ::msgcat::mcset uk "Yes" "Так" ::msgcat::mcset uk "Your JID: " "Ваш JID:" # ./otr.tcl ::msgcat::mcset ru "%s has requested an Off-the-Record private conversation,\ but you can't maintain it because you don't have your OTR private key\ configured." "%s запропонував вам ÑкориÑтатиÑÑ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ð¾Ð¼ OTR длÑ\ безпечної розмови, але ви не можете його підтримати, тому що\ у Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” Ñконфігурованого закритого ключа OTR." ::msgcat::mcset ru "%s have sent you an OTR encrypted message, but you can't\ decipher it because you don't have your OTR private key configured." \ "%s приÑлав вам повідомленнÑ, зашифроване за допомогою OTR, але ви не\ можете розшифрувати його, тому що у Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” Ñконфігурованого\ закритого ключа OTR." ::msgcat::mcset uk "Advertise your support of OTR using the whitespace tag." \ "Показувати підтримку OTR, викориÑтовуючи мітку з пропуÑкових Ñимволів." ::msgcat::mcset uk "Allow Tkabber to use Off-the-Record protocol (version 2 or\ 3)." "Дозволити Tkabber'у викориÑтовувати протокол OTR (верÑÑ–ÑŽ 2 чи 3)." ::msgcat::mcset uk "Allow encryption" "Дозволити шируваннÑ" ::msgcat::mcset uk "Attach whitespace tag" \ "Прикріплювати мітку з пропуÑкових Ñимволів" ::msgcat::mcset uk "Authenticate" "Ðутентифікувати" ::msgcat::mcset uk "Authenticate %s" "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ %s" ::msgcat::mcset uk "Authenticate %s\n\nAuthenticating a peer helps ensure\ that the person you are talking to is who he or she claims to be." \ "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ Ñпіврозмовника помагає впевнитиÑÑ, що він (чи вона)\ той, за кого Ñебе видає." ::msgcat::mcset uk "Authenticate %s\n\nAuthenticating a peer helps ensure\ that the person you are talking to is who he or she claims to\ be.\n\nHow would you like to authenticate your peer?" "ÐутентифікаціÑ\ %s\n\nÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ Ñпіврозмовника помагає впевнитиÑÑ, що він (чи вона)\ той, за кого Ñебе видає." ::msgcat::mcset uk "Authenticate peer..." "Ðутентіфікувати Ñпіврозмовника..." ::msgcat::mcset uk "Authentication aborted" "Ðутентіфікацію перервано" ::msgcat::mcset uk "Authentication failed" "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ Ð½Ðµ вдалаÑÑ" ::msgcat::mcset uk "Authentication from %s" "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ Ð²Ñ–Ð´ %s" ::msgcat::mcset uk "Authentication succeeded" "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ ÑƒÑпішна" ::msgcat::mcset uk "Do not log OTR messages." "Ðе зберігати Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ OTR в журнал." ::msgcat::mcset uk "Don't log OTR messages" "Ðе зберігати Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ OTR в журнал" ::msgcat::mcset uk "Edit authentication" "Зміна аутентифікації" ::msgcat::mcset uk "End OTR session" "Завершити ÑеÑÑ–ÑŽ OTR" ::msgcat::mcset uk "Enter question here:" "Введіть Ð¿Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ‚ÑƒÑ‚:" ::msgcat::mcset uk "Enter secret answer here (case sensitive):" \ "Введіть Ñекретну відповідь тут (чутливий до регіÑтру):" ::msgcat::mcset uk "Enter secret here (case sensitive):" \ "Введіть Ñекрет тут (чутливий до регіÑтру):" ::msgcat::mcset uk "Fingerprint for you, %s:\n%s" \ "Відбиток вашого (%s) ключа:\n%s" ::msgcat::mcset uk "Fingerprint:" "Відбиток:" ::msgcat::mcset uk "Finished" "Завершена" ::msgcat::mcset uk "I have not verified" "Я не впевнивÑÑ" ::msgcat::mcset uk "I have verified" "Я впевнивÑÑ" ::msgcat::mcset uk "If the interval between two consecutive incoming OTR\ messages exceeds the specified interval (in minutes, zero means\ no heartbeat at all) the heartbeat message will be sent to change\ the session keys." "Якщо інтервал між двома поÑлідовними\ зашифрованими повідомленнÑми перевищує даний (в хвилинах, нуль\ означає що Ñ†Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð°), то Ñпеціальне порожнє\ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð±ÑƒÐ´Ðµ відправлене, щоб обновити ÑеÑійнй ключі." ::msgcat::mcset uk "Manage private keys" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ð¸Ð¼Ð¸ ключами" ::msgcat::mcset uk "Manual fingerprint verification" \ "Ручна перевірка відбитка" ::msgcat::mcset uk "Not private" "Ðе шифроване" ::msgcat::mcset uk "OK" "Продовжити" ::msgcat::mcset uk "OTR" "OTR" ::msgcat::mcset uk "OTR conversation is lost because you have changed your\ OTR key. The next private chat will use the new key." "Ð¡ÐµÐ°Ð½Ñ OTR\ завершений, тому що ви змінили закритий ключ. У наÑтупній шифрованій\ розмові буде викориÑтаний новий ключ." ::msgcat::mcset uk "OTR Error:" "Помилка OTR:" ::msgcat::mcset uk "OTR Info:" "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ OTR:" ::msgcat::mcset uk "OTR icons theme." "Тема піктограм OTR." ::msgcat::mcset uk "OTR is disabled because you have deleted your OTR key.\ Generate or import a new one if you want to enable it again." \ "Ð¨Ð¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ OTR відключене, тому що ви видалили Ñвій закритий\ ключ. Згенеруйте або імпортуйте новий, Ñкщо ви хочете ввімкнути\ його знову." ::msgcat::mcset uk "Off-the-record messaging plugin options." \ "Параметри Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ñ…Ð¸Ñ‰ÐµÐ½Ð¾Ñ— перепиÑки OTR." ::msgcat::mcset uk "Plugins options." "Параметри розширень." ::msgcat::mcset uk "Personal OTR preferences." \ "ПерÑональні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ OTR" ::msgcat::mcset uk "Private" "Захищена" ::msgcat::mcset uk "Problem loading TclOTR. The OTR functionality will be\ disabled.\nRefer to the README file of the OTR plugin." \ "Проблема при підключенні TclOTR. Ð Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ OTR буде\ відключене.\nПрочитайте файл README, доданий до цього розширеннÑ." ::msgcat::mcset uk "Protocol error" "Помилка протоколу" ::msgcat::mcset uk "Purported fingerprint for %s:\n%s" \ "Можливий відбиток ключа %s:\n%s" ::msgcat::mcset uk "Question and answer" "Ð—Ð°Ð¿Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ– відповідь" ::msgcat::mcset uk "Refresh OTR session" "ПерезапуÑтити ÑеÑÑ–ÑŽ OTR" ::msgcat::mcset uk "Refuse to send unencrypted messages. Note that if this\ option is enabled and the previous one is not then you will not be\ able to send any chat or normal messages at all" "ВідмовлÑтиÑÑ\ поÑилати незашифровані повідомленнÑ. Занотуйте, що Ñкщо Ñ†Ñ Ð¾Ð¿Ñ†Ñ–Ñ\ ввімкнена, а Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð½Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð°, то ви не зможете поÑилати\ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð·Ð¾Ð²Ñім (окрім групових)." ::msgcat::mcset uk "Require encryption" "Вимагати шифруваннÑ" ::msgcat::mcset uk "Reset to default policy" "ПовернутиÑÑ Ð´Ð¾ налаштувань за замовчуваннÑм" ::msgcat::mcset uk "SMP verification is in progress. If you want to start\ new one, abort the current one first" "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ Ð· викориÑтаннÑм протоколу\ SMP уже запущена. Якщо ви хочете почати заново, Ñпочатку відмініть поточну." ::msgcat::mcset uk "Shared secret" "Спільний Ñекрет" ::msgcat::mcset uk "Start AKE on whitespace tag or OTR error" "Починати AKE\ при отриманні мітки Ñ Ð¿Ñ€Ð¾Ð¿ÑƒÑкових Ñимволів або помилки OTR" ::msgcat::mcset uk "Start OTR session" "Почати ÑеÑÑ–ÑŽ OTR" ::msgcat::mcset uk "Start the OTR authenticated key exchange when you\ receive a whitespace tag or an OTR error message." "Починати\ аутентифікований обмін ключами OTR при отриманні повідомленнÑ\ зі Ñпеціальною міткою з пропуÑкових Ñимволів або при отриманні\ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ помилку OTR." ::msgcat::mcset uk "SSID:" "Ідентифікатор ÑеÑÑ–Ñ—:" ::msgcat::mcset uk "State:" "Стан:" ::msgcat::mcset uk "This is the question asked by your peer:" \ "ЗапитаннÑ, Ñке задав ваш Ñпіврозмовник:" ::msgcat::mcset uk "Tkabber is too old for the OTR plugin" \ "ВерÑÑ–Ñ Tkabber'а надто Ñтара Ð´Ð»Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ OTR" ::msgcat::mcset uk "To authenticate using a question, pick a question\ whose answer is known only to you and your peer. Enter this\ question and this answer, then wait for your peer to enter\ the answer too. If the answers don't match then you may be\ talking to an imposter." "Щоб аутентифікувати Ñпіврозмовника з\ допомогою Ð·Ð°Ð¿Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ– відповіді, виберіть запитаннÑ, відповідь\ на Ñке відома тільки вам двом, введіть Ð·Ð°Ð¿Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ– відповідь,\ Ñ– зачекайте, доки ваш Ñпіврозмовник не введе відповідь також.\ Якщо відповіді не Ñпівпадуть, то можливо, що ваш Ñпіврозмовник\ не той, за кого Ñебе видає." ::msgcat::mcset uk "To authenticate, pick a secret known only to you\ and your peer. Enter this secret, then wait for your peer to\ enter it too. If the secrets don't match then you may be\ talking to an imposter." "Щоб аутентифікувати Ñпіврозмовника,\ виберіть Ñекрет, відомий тільки вам двом. Введіть цей Ñекрет\ Ñ– зачекайте, доки ваш Ñпіврозмовник не введе його також. Якщо\ Ñекрети не Ñпівпадуть, то можливо, що ваш Ñпіврозмовник\ не той, за кого Ñебе видає." ::msgcat::mcset uk "To verify the fingerprint, contact your peer via\ some other authenticated channel, such as the phone or\ GPG-signed email. Each of you should tell your fingerprint to\ the other. if everything matches up, you should indicate in\ this dialog that you have verified the fingerprint." "Щоб\ переконатиÑÑ, що це наÑправді відбиток відкритого ключа\ Ñпіврозмовника, зв’ÑжітьÑÑ Ð· ним за допомогою Ñкого-небудь\ іншого захищенного каналу зв’Ñзку, наприклад, по телефону\ або підпиÑаним з допомогою GPG електронним лиÑтом. Кожен з ваÑ\ має назвати іншому відбиток Ñвого ключа. Якщо вÑе Ñпівпало, то\ ви можете вказати, що ви впевнилиÑÑ Ð² ÑправжноÑті ключа." ::msgcat::mcset uk "Unverified" "Ðеперевірено" ::msgcat::mcset uk "View" "Вид" ::msgcat::mcset uk "You cannot verify the peer's identity using SMP\nif\ an OTR session is not in progress" "Ðе можна перевірити\ оÑобиÑтіÑть Ñпіврозмовника за допомогою протоколу SMP, доки\ не почалаÑÑ ÑеÑÑ–Ñ OTR" ::msgcat::mcset uk "Your peer is attempting to determine if he or she\ is really talking to you, or if it's someone pretending to be\ you. Your peer has asked a question, indicated below. To\ authenticate to your peer, enter the answer and click\ 'Authenticate'." "Ваш Ñпіврозмовник намагаєтьÑÑ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€Ð¸Ñ‚Ð¸, чи\ дійÑно він розмовлÑÑ” з вами, чи це хтоÑÑŒ, що прикидаєтьÑÑ Ð²Ð°Ð¼Ð¸.\ Він задав запитаннÑ, наведене нижче. Щоб підтвердити Ñвою\ оÑобиÑтіÑть, введіть відповідь Ñ– натиÑніть 'Ðутентифікувати'." ::msgcat::mcset uk "Your peer is attempting to determine if he or she\ is really talking to you, or if it's someone pretending to be\ you. Your peer has picked a secret known only to him or her and\ you. To authenticate to your peer, enter this secret and click\ 'Authenticate'." "Ваш Ñпіврозмовник намагаєтьÑÑ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€Ð¸Ñ‚Ð¸, чи\ дійÑно він розмовлÑÑ” з вами, чи це хтоÑÑŒ, що прикидаєтьÑÑ Ð²Ð°Ð¼Ð¸.\ Він вибрав Ñекрет, відомий тільки вам двом. Щоб підтвердити Ñвою\ оÑобиÑтіÑть, введіть цей Ñекрет Ñ– натиÑніть 'Ðутентифікувати'." ::msgcat::mcset uk "\n\tOTR:" "\n\tOTR:" ::msgcat::mcset uk "that this is in fact the correct fingerprint for %s" \ "що це наÑправді вірний відбиток ключа %s" # ./key.tcl ::msgcat::mcset uk "All files" "Ð’ÑÑ– файли" ::msgcat::mcset uk "Can't import DSA key from the file \"%s\": %s" \ "Ðе вдалоÑÑ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ñ‚Ð¸ ключ DSA з файлу \"%s\": %s" ::msgcat::mcset uk "Can't open the key file \"%s\"" "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸\ файл з ключем \"%s\"" ::msgcat::mcset uk "Close" "Закрити" ::msgcat::mcset uk "Delete key" "Видалити ключ" ::msgcat::mcset uk "Export key..." "ЕкÑпортувати ключ..." ::msgcat::mcset uk "Generate new key" "Генерувати новий ключ" ::msgcat::mcset uk "Import key..." "Імпортувати ключ..." ::msgcat::mcset uk "Key files" "Файли ключів" ::msgcat::mcset uk "Manage OTR long term DSA private key for your JID" \ "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð²Ð³Ð¾Ð¶Ð¸Ð²ÑƒÑ‡Ð¸Ð¼Ð¸ закритими ключами DSA протоколу OTR Ð´Ð»Ñ JID" ::msgcat::mcset uk "Manage OTR private keys" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ð¸Ð¼Ð¸ ключами OTR" ::msgcat::mcset uk "The fingerprint of your long term OTR DSA private key\ for this JID is the following:" "Відбиток вашого довгоживучого\ закритого ключа OTR Ñлідуючий:" ::msgcat::mcset uk "You don't have a private DSA key for this JID. Either\ import a 1024 bit DSA private key, or generate one." "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ”\ закритого ключа DSA Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ JID. Ðбо імпортуйте, або згенеруйте\ Ñобі 1024-бітний ключ." ::msgcat::mcset uk "Encrypted message can't be deciphered" "Зашифроване\ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ðµ вдалоÑÑ Ñ€Ð¾Ð·ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ñ‚Ð¸" ::msgcat::mcset ru "Last message has been resent" "ОÑтаннє Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð±ÑƒÐ»Ð¾\ відіÑлане повторно" ::msgcat::mcset ru "Last message should have been resent but has not because\ the peer's OTR key has been changed" "ОÑтаннє Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¼Ð°Ð»Ð¾ бути\ відіÑлане повторно, але воно не було відіÑлане, тому що ключ OTR\ Ñпіврозмовника змінивÑÑ" ::msgcat::mcset uk "Message is not sent because encryption is required.\ Trying to start private conversation..." "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ðµ відправлене,\ тому що ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð±Ð¾Ð²â€™Ñзкове. Спробуємо почати приватну беÑіду..." ::msgcat::mcset uk "Message is not sent. Either end your private\ conversation, or restart it" "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ðµ відправлене. Ðбо завершіть\ захищену розмову, або почніть Ñ—Ñ— заново." ::msgcat::mcset ru "OTR request message is received but it uses an\ incompatible or disabled protocol version" "Отримане Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð·\ запитом ÑеÑÑ–Ñ— OTR, але в ньому викориÑтовуєтьÑÑ Ð½ÐµÐ¿Ñ–Ð´Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð° або\ вимкнена верÑÑ–Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ñƒ" ::msgcat::mcset ru "OTR request message is received but you have disabled\ encryption" "Отримане Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· запитом ÑеÑÑ–Ñ— OTR, але ви\ вимкнули шифруваннÑ" ::msgcat::mcset uk "Unmatched protocol versions" "ÐеÑпівпадаючі верÑÑ–Ñ— протокола" ::msgcat::mcset uk "Private conversation is refreshed" "Захищена розмова почалаÑÑ Ð·Ð°Ð½Ð¾Ð²Ð¾" ::msgcat::mcset uk "Private conversation is started" "Захищена розмова почалаÑÑ" ::msgcat::mcset uk "Private conversation is finished" "Захищену розмову завершено" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/otr/otr.tcl000064400000000000000000001637611500237002100156430ustar00nobodynobody# otr.tcl -- # # This file is a part of Off-the-record messaging plugin for # the Tkabebr XMPP client. It implements the interface with # Tkabber. namespace eval otr { # Prepare to load the local TclOTR library variable scriptdir [file dirname [info script]] variable tclotr [file join $scriptdir tclotr] if {[file isdirectory $tclotr]} { lappend ::auto_path $scriptdir package forget otr } # Load message catalogs: package require msgcat ::msgcat::mcload [file join $scriptdir msgs] ::trans::load [file join $scriptdir trans] # Check if Tkabber is sufficiently new if {[hook::is_empty send_normal_message_hook]} { puts stderr [::msgcat::mc "Tkabber is too old for the OTR plugin"] # Clean up what's already here and bail out: namespace delete [namespace current] return } # Attempt to load TclOTR. Warn and quit loading plugin if we can't: variable err if {[catch { package require otr } err]} { puts stderr $err puts stderr [::msgcat::mc "Problem loading TclOTR. The OTR\ functionality will be disabled.\nRefer\ to the README file of the OTR plugin."] # Clean up what's already here and bail out: namespace delete [namespace current] return } # Load DSA keys and authenticaton infrastructure source [file join $scriptdir auth.tcl] source [file join $scriptdir key.tcl] # Auxiliary namespace. Rewrite_message_hook will use it to add some # supplemetary info. variable ns tkabber:otr # PLugin's options variable options variable themes variable dirs \ [glob -nocomplain -directory [file join [file dirname [info script]] \ pixmaps] *] variable dir foreach dir $dirs { pixmaps::load_theme_name [namespace current]::themes $dir } variable values {} variable theme foreach theme [lsort [array names themes]] { lappend values $theme $theme } variable options custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup OTR \ [::msgcat::mc "Off-the-record messaging plugin options."] \ -group Plugins custom::defvar options(theme) OTR \ [::msgcat::mc "OTR icons theme."] -group OTR \ -type options -values $values \ -command [namespace current]::load_stored_theme custom::defvar options(allow-encryption) 1 \ [::msgcat::mc "Allow Tkabber to use Off-the-Record protocol\ (version 2 or 3)."] \ -group OTR -type boolean \ -command [namespace current]::update_default_policy custom::defvar options(require-encryption) 0 \ [::msgcat::mc "Refuse to send unencrypted messages. Note that if this\ option is enabled and the previous one is not then you\ will not be able to send any chat or normal messages\ at all"] \ -group OTR -type boolean \ -command [namespace current]::update_default_policy custom::defvar options(send-whitespace-tag) 1 \ [::msgcat::mc "Advertise your support of OTR using the\ whitespace tag."] \ -group OTR -type boolean \ -command [namespace current]::update_default_policy custom::defvar options(whitespace-or-error-start-ake) 1 \ [::msgcat::mc "Start the OTR authenticated key exchange when you\ receive a whitespace tag or an OTR error message."] \ -group OTR -type boolean \ -command [namespace current]::update_default_policy custom::defvar options(heartbeat-interval) 60 \ [::msgcat::mc "If the interval between two consecutive incoming OTR\ messages exceeds the specified interval (in minutes,\ zero means no heartbeat at all) the heartbeat message\ will be sent to change the session keys."] \ -group OTR -type integer -command [namespace current]::update_heartbeat custom::defvar options(dont-log-otr-messages) 0 \ [::msgcat::mc "Do not log OTR messages."] \ -group OTR -type boolean # Hidden option for storing contacts' personal preferences # {myjid1 {jid1 {allow-encryption 0 ...} jid2 {...}} # myjid2 {jid1 {...} jid2 {...}}} custom::defvar options(personal-preferences) {} \ [::msgcat::mc "Personal OTR preferences."] \ -type string -group Hidden # Correspondence between GUI options and OTR policy flags variable PolicyFlags array set PolicyFlags {allow-encryption {ALLOW_V2 ALLOW_V3} require-encryption {REQUIRE_ENCRYPTION} send-whitespace-tag {SEND_WHITESPACE_TAG} whitespace-or-error-start-ake {WHITESPACE_START_AKE ERROR_START_AKE}} } ############################################################################# proc otr::load_stored_theme {args} { variable options variable themes pixmaps::load_dir $themes($options(theme)) } ############################################################################# proc otr::draw_encrypted {chatid from type body x} { variable ns variable ctx if {$type ne "chat"} return set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] set chatw [chat::chat_win $chatid] if {[::xmpp::jid::equal $jid $from]} { # Incoming message foreach xe $x { ::xmpp::xml::split $xe tag xmlns attrs cdata subels if {$tag eq "" && $xmlns eq $ns} { $chatw image create end -image [::xmpp::xml::getAttr $attrs icon] break } } } elseif {$from ne ""} { # Outgoing message set draw 1 foreach xe $x { ::xmpp::xml::split $xe tag xmlns attrs cdata subels # Don't draw the icon for the messages from the log # TODO: store the OTR attribute in the log and draw # the icon for these messages as well if {$tag eq "" && $xmlns eq "tkabber:x:nolog"} { set draw 0 break } } if {$draw && [msgstate:index $xlib $jid] > 0} { $chatw image create end -image [msgstate:icon $xlib $jid] } } } hook::add draw_message_hook [namespace current]::otr::draw_encrypted 5.4 ############################################################################# proc otr::process_x_encrypted {rowvar bodyvar f x xlib from id type replyP} { variable ns variable ctx upvar 2 $rowvar row upvar 2 $bodyvar body if {$type eq "error" || $type eq "groupchat" || $type eq "headline"} return if {$body eq ""} return foreach xe $x { ::xmpp::xml::split $xe tag xmlns attrs cdata subels if {$tag eq "" && $xmlns eq $ns} { set lb [join [lrange [split $f .] 0 end-1] .].title.otrmsgstate if {[winfo exists $lb]} { destroy $lb } Label $lb -image [::xmpp::xml::getAttr $attrs icon] grid $lb -row 1 -column 4 -sticky e break } } } hook::add message_process_x_hook \ [namespace current]::otr::process_x_encrypted 21 ############################################################################# proc otr::once_only {xlib jid} { variable options variable ctx if {[info exists ctx($xlib,$jid)]} { return 1 } debugmsg otr "ONCE_ONLY $xlib $jid" set myjid [::xmpp::jid::removeResource [connection_jid $xlib]] set privkey [key::get_key $key::Keys $myjid] if {[llength $privkey] == 0} { return 0 } set ctx(msgstate,$xlib,$jid) MSGSTATE_PLAINTEXT msgstate:trace {} $xlib $jid set ctx($xlib,$jid) \ [::otr::new $privkey \ -policy [get_policy $xlib $jid] \ -heartbeat $options(heartbeat-interval) \ -authstatecommand [namespace code [list on_authstate_change \ $xlib $jid]] \ -msgstatecommand [namespace code [list on_msgstate_change \ $xlib $jid]] \ -smpstatecommand [namespace code [list on_smpstate_change \ $xlib $jid]] \ -smpprogresscommand [namespace code [list progress_smp \ $xlib $jid]] \ -infocommand [namespace code [list show_info $xlib $jid]] \ -errorcommand [namespace code [list show_error $xlib $jid]] \ -sendcommand [namespace code [list send $xlib $jid]] \ -discardcommand [namespace code [list discard $xlib $jid]] \ -resendcommand [namespace code [list resend $xlib $jid]]] return 1 } proc otr::clear {xlib jid} { variable ctx if {[info exists ctx($xlib,$jid)]} { finish_session $xlib $jid "" ::otr::free $ctx($xlib,$jid) unset ctx(authstate,$xlib,$jid) unset ctx(msgstate,$xlib,$jid) unset ctx(smpstate,$xlib,$jid) unset ctx($xlib,$jid) set chatid [chat::chatid $xlib $jid] set chatw [chat::chat_win $chatid] if {![winfo exists $chatw]} return if {[key::get_key $key::Keys \ [::xmpp::jid::removeResource [connection_jid $xlib]]] eq ""} { chat::add_message $chatid $jid info \ "[::msgcat::mc {OTR Info:}]\ [::msgcat::mc {OTR is disabled because you have deleted\ your OTR key. Generate or import a new\ one if you want to enable it again.}]" {} } else { chat::add_message $chatid $jid info \ "[::msgcat::mc {OTR Info:}]\ [::msgcat::mc {OTR conversation is lost because you\ have changed your OTR key. The next\ private chat will use the new key.}]" {} } } } proc otr::clear_all {xlib} { variable ctx foreach idx [array names ctx $xlib,*] { regexp {[^,]*,(.*)} $idx -> jid clear $xlib $jid } } proc otr::clear_all_jid {myjid} { foreach xlib [connections] { if {[::xmpp::jid::equal $myjid \ [::xmpp::jid::removeResource [connection_jid $xlib]]]} { clear_all $xlib } } } proc otr::reset_auth {myjid} { variable ctx foreach xlib [connections] { if {![::xmpp::jid::equal $myjid \ [::xmpp::jid::removeResource [connection_jid $xlib]]]} continue foreach idx [array names ctx msgstate,$xlib,*] { regexp {msgstate,[^,]*,(.*)} $idx -> fjid on_msgstate_change $xlib $fjid $ctx($idx) } } } ############################################################################# proc otr::on_authstate_change {xlib jid authstate} { variable ctx set ctx(authstate,$xlib,$jid) $authstate } proc otr::on_msgstate_change {xlib jid msgstate} { variable ctx set ctx(msgstate,$xlib,$jid) $msgstate } proc otr::on_smpstate_change {xlib jid smpstate} { variable ctx set ctx(smpstate,$xlib,$jid) $smpstate } ############################################################################# proc otr::show_info {xlib jid info} { set chatid [::chat::chatid $xlib $jid] chat::add_message $chatid $jid info \ "[::msgcat::mc {OTR Info:}] [::msgcat::mc $info]" {} } proc otr::show_error {xlib jid error} { set chatid [::chat::chatid $xlib $jid] chat::add_message $chatid $jid error \ "[::msgcat::mc {OTR Error:}] $error" {} } proc otr::send {xlib jid message} { upvar 2 type type debugmsg otr "SEND: $xlib; $jid; $message;" # Dirty hack to recover message type for {set i 1} {$i < 12} {incr i} { if {[catch {upvar $i type type}]} break if {[info exists type] && $type eq "chat"} break } # Another dirty hack to translate OTR error messages if {![catch {::otr::data::findErrorMessage $message} error]} { set lang [get_jid_presence_info lang $xlib $jid] set message [::otr::data::errorMessage [::trans::trans $lang $error]] } if {[info exists type] && $type eq "chat"} { set targs [list -type $type] } else { set targs {} } ::xmpp::sendMessage $xlib $jid -body $message {*}$targs } ############################################################################# proc otr::store {xlib jid isid id istype type issubject subject isbody body iserr err isthread thread isx x} { variable ctx if {[info exists ctx($xlib,$jid)]} { # Store only the last message set ctx(stored,$xlib,$jid) \ [list $isid $id $istype $type $issubject $subject \ $isbody $body $iserr $err $isthread $thread $isx $x] } } proc otr::discard {xlib jid} { variable ctx if {[info exists ctx($xlib,$jid)]} { set ctx(stored,$xlib,$jid) {} } } proc otr::resend {xlib jid} { variable ctx if {[info exists ctx($xlib,$jid)] && [info exists ctx(stored,$xlib,$jid)]} { set opts {} foreach {isid id istype type issubject subject isbody body iserr err isthread thread isx x} $ctx(stored,$xlib,$jid) { if {$isid} { lappend opts -id $id } if {$istype} { lappend opts -type $type } if {$issubject} { lappend opts -subject $subject } if {$isbody} { lappend opts -body $body } if {$iserr} { lappend opts -error $err } if {$isthread} { lappend opts -thread $thread } if {$isx} { lappend opts -xlist $x } ::message::send_msg $xlib $jid {*}$opts } } } ############################################################################# proc otr::update_heartbeat {args} { variable options variable ctx foreach idx [array names ctx ::*] { ::otr::configure $ctx($idx) -heartbeat $options(heartbeat-interval) } } proc otr::get_policy {xlib jid} { variable options variable PolicyFlags set njid [::xmpp::jid::normalize $jid] set policy {} foreach key {allow-encryption require-encryption send-whitespace-tag whitespace-or-error-start-ake} { if {[info exists options($key,$xlib,$njid)]} { set flag $options($key,$xlib,$njid) } else { set flag $options($key) } if {$flag} { lappend policy {*}$PolicyFlags($key) } } debugmsg otr "GET_POLICY $xlib $jid $policy" set policy } proc otr::update_default_policy {args} { update_policy } proc otr::update_policy {{xlib ""} {jid ""}} { variable ctx if {$xlib eq ""} { set xlibs [connections] } else { set xlibs [list $xlib] } foreach xl $xlibs { if {$jid eq ""} { set jids {} foreach idx [array names ctx $xl,*] { regexp "$xl,(.*)" $idx -> j lappend jids $j } } else { if {[info exists ctx($xl,$jid)]} { set jids [list $jid] } else { set jids {} } } foreach j $jids { ::otr::configure $ctx($xl,$j) -policy [get_policy $xl $j] } } } proc otr::reset_policy {xlib jid} { variable options set njid [::xmpp::jid::normalize $jid] foreach key {allow-encryption require-encryption send-whitespace-tag whitespace-or-error-start-ake} { if {[info exists options($key,$xlib,$njid)]} { unset options($key,$xlib,$njid) } } update_policy $xlib $jid } ############################################################################# proc otr::get_personal_prefs {xlib} { variable options set connjid [::xmpp::jid::normalize [connection_bare_jid $xlib]] array set p $options(personal-preferences) if {[info exists p($connjid)]} { foreach {jid prefs} $p($connjid) { foreach {key val} $prefs { set options($key,$xlib,$jid) $val } } } } hook::add connected_hook [namespace current]::otr::get_personal_prefs 1 proc otr::set_personal_prefs {xlib} { variable options set connjid [::xmpp::jid::normalize [connection_bare_jid $xlib]] array set p $options(personal-preferences) set p($connjid) {} set jids {} foreach idx [array names options *,$xlib,*] { lappend jids [join [lrange [split $idx ,] 2 end] ,] } set jids [lsort -unique $jids] foreach j $jids { set prefs {} foreach key {allow-encryption require-encryption send-whitespace-tag whitespace-or-error-start-ake dont-log-otr-messages} { if {[info exists options($key,$xlib,$j)] && \ $options($key,$xlib,$j) != $options($key)} { lappend prefs $key $options($key,$xlib,$j) } } if {[llength $prefs] > 0} { lappend p($connjid) $j $prefs } } if {[llength $p($connjid)] == 0} { unset p($connjid) } set options(personal-preferences) [array get p] } hook::add disconnected_hook [namespace current]::otr::set_personal_prefs 40 ############################################################################# proc otr::request_session {xlib jid type} { variable ctx once_only $xlib $jid set lang [get_jid_presence_info lang $xlib $jid] ::otr::requestConversation $ctx($xlib,$jid) \ \n[::trans::trans $lang \ "I has requested an Off-the-Record private conversation.\ However, you do not have a plugin to support that (or\ the plugin is disabled, or you don't have an OTR private\ key to use it).\nSee http://otr.cypherpunks.ca/ for more\ information."] \ } proc otr::finish_session {xlib jid type} { variable ctx once_only $xlib $jid ::otr::finishConversation $ctx($xlib,$jid) } proc otr::toggle_session {xlib jid type} { if {[msgstate:index $xlib $jid] == 0} { request_session $xlib $jid $type } else { finish_session $xlib $jid $type } } ############################################################################# proc otr::peer_jid {xlib jid} { set bjid [::xmpp::jid::removeResource $jid] if {![chat::is_groupchat [chat::chatid $xlib $bjid]]} { return $bjid } else { return $jid } } proc otr::begin_smp_dialog {xlib jid} { variable ctx set w .otrstartauth[jid_to_tag $jid] Dialog $w -title [::msgcat::mc "Authenticate %s" [peer_jid $xlib $jid]] \ -anchor e -default 0 -cancel 1 wm resizable $w 0 0 $w add -text [::msgcat::mc "Authenticate"] \ -command [namespace code [list begin_smp $w $xlib $jid]] $w add -text [::msgcat::mc "Cancel"] \ -command [list destroy $w] bind $w \ [namespace code [clear_dialog [double% $xlib] [double% $jid]]] bind $w <> \ [namespace code [add_to_clipboard [double% $xlib] [double% $jid]]] set f [$w getframe] set m [Message $f.header \ -text [::msgcat::mc "Authenticate %s\n\nAuthenticating\ a peer helps ensure that\ the person you are talking to is who\ he or she claims to be.\n\nHow would\ you like to authenticate your peer?" \ $jid] \ -width 12c] grid $m -row 1 -column 0 -sticky nswe tk_optionMenu $f.choice [namespace current]::ctx(authmethod,$xlib,$jid) \ [::msgcat::mc "Question and answer"] \ [::msgcat::mc "Shared secret"] \ [::msgcat::mc "Manual fingerprint verification"] trace add variable [namespace current]::ctx(authmethod,$xlib,$jid) \ write [namespace code [list smp_dialog_switch_page $w $xlib $jid]] grid $f.choice -row 2 -column 0 -sticky nswe set pm [PagesManager $f.method] grid $pm -row 3 -column 0 -sticky nswe $pm add qa set pf1 [$pm getframe qa] set m1 [Message $pf1.instr \ -text [::msgcat::mc "To authenticate using a question,\ pick a question whose answer is known\ only to you and your peer. Enter this\ question and this answer, then wait\ for your peer to enter the answer\ too. If the answers don't match then\ you may be talking to an imposter."] \ -width 12c] grid $m1 -row 0 -column 0 -sticky nswe set l1 [Label $pf1.l1 -text [::msgcat::mc "Enter question here:"]] grid $l1 -row 1 -column 0 -sticky nsw set e1 [Entry $pf1.e1] grid $e1 -row 2 -column 0 -sticky nswe set l2 [Label $pf1.l2 -text [::msgcat::mc "Enter secret answer here\ (case sensitive):"]] grid $l2 -row 3 -column 0 -sticky nsw set e2 [Entry $pf1.e2] grid $e2 -row 4 -column 0 -sticky nswe Progressbar $pf1.pb \ -variable [namespace current]::ctx(progress,$xlib,$jid) -maximum 3 grid $pf1.pb -row 5 -column 0 -sticky ew set l4 [Label $pf1.l4 \ -textvariable [namespace current]::ctx(status,$xlib,$jid)] grid $l4 -row 6 -column 0 $pm add ss set pf2 [$pm getframe ss] set m2 [Message $pf2.instr \ -text [::msgcat::mc "To authenticate, pick a secret known\ only to you and your peer. Enter this\ secret, then wait for your peer to\ enter it too. If the secrets don't\ match then you may be talking to an\ imposter."] \ -width 12c] grid $m2 -row 0 -column 0 -sticky nswe set l3 [Label $pf2.l3 \ -text [::msgcat::mc "Enter secret here (case sensitive):"]] grid $l3 -row 1 -column 0 -sticky nsw set e3 [Entry $pf2.e3] grid $e3 -row 2 -column 0 -sticky nswe Progressbar $pf2.pb \ -variable [namespace current]::ctx(progress,$xlib,$jid) -maximum 3 grid $pf2.pb -row 3 -column 0 -sticky ew set l4 [Label $pf2.l4 \ -textvariable [namespace current]::ctx(status,$xlib,$jid)] grid $l4 -row 4 -column 0 set ctx(progress,$xlib,$jid) 0 set ctx(status,$xlib,$jid) "" set ctx(smpdialog,$xlib,$jid) $w $pm add mfv set pf3 [$pm getframe mfv] set m3 [Message $pf3.instr \ -text [::msgcat::mc "To verify the fingerprint, contact\ your peer via some other\ authenticated channel, such as the\ phone or GPG-signed email. Each of\ you should tell your fingerprint to\ the other. if everything matches up,\ you should indicate in this dialog\ that you have verified the\ fingerprint."] \ -width 12c] grid $m3 -row 0 -column 0 -columnspan 2 -sticky nswe set m4 [Message $pf3.mefp \ -text [::msgcat::mc "Fingerprint for you, %s:\n%s" \ [connection_jid $xlib] \ [::otr::fingerprint $ctx($xlib,$jid) 1]] \ -width 12c] grid $m4 -row 1 -column 0 -columnspan 2 -sticky nswe set m5 [Message $pf3.hefp \ -text [::msgcat::mc "Purported fingerprint for %s:\n%s" \ $jid \ [::otr::fingerprint $ctx($xlib,$jid) 0]] \ -width 12c] grid $m5 -row 2 -column 0 -columnspan 2 -sticky nswe set myjid [::xmpp::jid::removeResource [connection_jid $xlib]] set fingerprint [::otr::fingerprint $ctx($xlib,$jid)] set tjid [peer_jid $xlib $jid] if {![auth::get_auth $auth::Auth $myjid $tjid $fingerprint]} { set ctx(ihave,$xlib,$jid) [::msgcat::mc "I have not verified"] } else { set ctx(ihave,$xlib,$jid) [::msgcat::mc "I have verified"] } tk_optionMenu $pf3.ihave [namespace current]::ctx(ihave,$xlib,$jid) \ [::msgcat::mc "I have not verified"] \ [::msgcat::mc "I have verified"] grid $pf3.ihave -row 3 -column 0 -sticky nwe set m6 [Message $pf3.ver -text [::msgcat::mc "that this is in fact the\ correct fingerprint for %s" \ $jid] \ -width 8c] grid $pf3.ver -row 3 -column 1 -sticky nw grid columnconfigure $pf3 0 -minsize 4c $pm compute_size $pm raise qa $w draw } proc otr::clear_dialog {xlib jid} { variable ctx unset -nocomplain ctx(status,$xlib,$jid) unset -nocomplain ctx(progress,$xlib,$jid) unset -nocomplain ctx(authmethod,$xlib,$jid) unset -nocomplain ctx(ihave,$xlib,$jid) unset -nocomplain ctx(smpdialog,$xlib,$jid) } proc otr::add_to_clipboard {xlib jid} { variable ctx clipboard clear if {![once_only $xlib $jid]} return clipboard append [::otr::fingerprint $ctx($xlib,$jid) 1] clipboard append \n clipboard append [::otr::fingerprint $ctx($xlib,$jid) 0] } proc otr::smp_dialog_switch_page {w xlib jid name1 name2 op} { variable ctx set f [$w getframe] set pm $f.method if {$ctx(authmethod,$xlib,$jid) eq [::msgcat::mc "Question and answer"]} { $pm raise qa } elseif {$ctx(authmethod,$xlib,$jid) eq [::msgcat::mc "Shared secret"]} { $pm raise ss } else { $pm raise mfv } } proc otr::begin_smp {w xlib jid} { variable ctx if {$ctx(msgstate,$xlib,$jid) ne "MSGSTATE_ENCRYPTED"} { MessageDlg .beginsmperr -aspect 50000 -icon error \ -message [::msgcat::mc "You cannot verify the peer's identity\ using SMP\nif an OTR session is not in\ progress"] \ -type user -buttons ok -default 0 -cancel 0 return } if {$ctx(smpstate,$xlib,$jid) ne "SMPSTATE_EXPECT1"} { MessageDlg .beginsmperr -aspect 50000 -icon error \ -message [::msgcat::mc "SMP verification is in progress. If you\ want to start new one, abort the current\ one first"] \ -type user -buttons ok -default 0 -cancel 0 return } $w itemconfigure 0 -state disabled $w itemconfigure 1 -command [namespace code [list abort_smp $w $xlib $jid]] set f [$w getframe] set pm $f.method $f.choice configure -state disabled set page [$pm raise] set pf [$pm getframe $page] switch -- $page { qa { $pf.e1:cmd configure -state readonly $pf.e2:cmd configure -state readonly set secret [$pf.e2 get] set question [list -question [$pf.e1 get]] } ss { $pf.e3:cmd configure -state readonly set secret [$pf.e3 get] set question {} } mfv { if {$ctx(ihave,$xlib,$jid) eq [::msgcat::mc "I have verified"]} { set val 1 } else { set val 0 } set myjid [::xmpp::jid::removeResource [connection_jid $xlib]] set fingerprint [::otr::fingerprint $ctx($xlib,$jid)] set tjid [peer_jid $xlib $jid] auth::set_auth auth::Auth $myjid $tjid $fingerprint $val auth::store $auth::Auth foreach idx [array names ctx msgstate,$xlib,*] { regexp {msgstate,[^,]*,(.*)} $idx -> fjid if {[peer_jid $xlib $fjid] eq $tjid} { on_msgstate_change $xlib $fjid $ctx($idx) } } destroy $w return } } ::otr::startSMP $ctx($xlib,$jid) $secret {*}$question } ############################################################################# proc otr::reply_smp_dialog_qa {xlib jid question} { variable ctx set w .otrreplauth[jid_to_tag $jid] Dialog $w -title [::msgcat::mc "Authentication from %s" \ [peer_jid $xlib $jid]] \ -anchor e -default 0 -cancel 1 wm resizable $w 0 0 $w add -text [::msgcat::mc "Authenticate"] \ -command [namespace code [list reply_smp $w $xlib $jid]] $w add -text [::msgcat::mc "Cancel"] \ -command [list destroy $w] bind $w [namespace code [clear_dialog [double% $xlib] \ [double% $jid]]] set f [$w getframe] set m [Message $f.header \ -text [::msgcat::mc "Authenticate %s\n\nAuthenticating\ a peer helps ensure that\ the person you are talking to is who\ he or she claims to be." \ $jid] \ -width 12c] grid $m -row 1 -column 0 -sticky nswe set m1 [Message $f.instr \ -text [::msgcat::mc "Your peer is attempting to determine\ if he or she is really talking to\ you, or if it's someone pretending to\ be you. Your peer has asked a\ question, indicated below. To\ authenticate to your peer, enter the\ answer and click 'Authenticate'."] \ -width 12c] grid $m1 -row 2 -column 0 -sticky nswe set l1 [Label $f.l1 -text [::msgcat::mc "This is the question asked by\ your peer:"]] grid $l1 -row 3 -column 0 -sticky nsw set m2 [Message $f.m2 -text $question -width 12c] grid $m2 -row 4 -column 0 -sticky nsw set l2 [Label $f.l2 -text [::msgcat::mc "Enter secret answer here (case\ sensitive):"]] grid $l2 -row 5 -column 0 -sticky nsw set e1 [Entry $f.e1] grid $e1 -row 6 -column 0 -sticky nswe Progressbar $f.pb \ -variable [namespace current]::ctx(progress,$xlib,$jid) -maximum 2 grid $f.pb -row 7 -column 0 -sticky ew set l4 [Label $f.l4 \ -textvariable [namespace current]::ctx(status,$xlib,$jid)] grid $l4 -row 8 -column 0 set ctx(progress,$xlib,$jid) 0 set ctx(status,$xlib,$jid) "" set ctx(smpdialog,$xlib,$jid) $w $w draw } proc otr::reply_smp_dialog_ss {xlib jid} { variable ctx set w .otrreplauth[jid_to_tag $jid] Dialog $w -title [::msgcat::mc "Authentication from %s" \ [peer_jid $xlib $jid]] \ -anchor e -default 0 -cancel 1 wm resizable $w 0 0 $w add -text [::msgcat::mc "Authenticate"] \ -command [namespace code [list reply_smp $w $xlib $jid]] $w add -text [::msgcat::mc "Cancel"] \ -command [list destroy $w] bind $w [namespace code [clear_dialog [double% $xlib] \ [double% $jid]]] set f [$w getframe] set m [Message $f.header \ -text [::msgcat::mc "Authenticate %s\n\nAuthenticating\ a peer helps ensure that the person\ you are talking to is who he\ or she claims to be." \ $jid] \ -width 12c] grid $m -row 1 -column 0 -sticky nswe set m2 [Message $f.instr \ -text [::msgcat::mc "Your peer is attempting to determine\ if he or she is really talking to\ you, or if it's someone pretending to\ be you. Your peer has picked a secret\ known only to him or her and you. To\ authenticate to your peer, enter this\ secret and click 'Authenticate'."] \ -width 12c] grid $m2 -row 2 -column 0 -sticky nswe set l3 [Label $f.l3 -text [::msgcat::mc "Enter secret here (case\ sensitive):"]] grid $l3 -row 3 -column 0 -sticky nsw set e1 [Entry $f.e1] grid $e1 -row 4 -column 0 -sticky nswe Progressbar $f.pb \ -variable [namespace current]::ctx(progress,$xlib,$jid) -maximum 2 grid $f.pb -row 5 -column 0 -sticky ew set l4 [Label $f.l4 \ -textvariable [namespace current]::ctx(status,$xlib,$jid)] grid $l4 -row 6 -column 0 set ctx(status,$xlib,$jid) "" set ctx(progress,$xlib,$jid) 0 set ctx(smpdialog,$xlib,$jid) $w $w draw } proc otr::reply_smp {w xlib jid} { variable ctx if {$ctx(msgstate,$xlib,$jid) ne "MSGSTATE_ENCRYPTED"} { MessageDlg .beginsmperr -aspect 50000 -icon error \ -message [::msgcat::mc "You cannot verify the peer's identity\ using SMP\nif an OTR session is not in\ progress"] \ -type user -buttons ok -default 0 -cancel 0 return } if {$ctx(smpstate,$xlib,$jid) ne "SMPSTATE_EXPECT1"} { MessageDlg .beginsmperr -aspect 50000 -icon error \ -message [::msgcat::mc "SMP verification is in progress. If you\ want to start new one, abort the current\ one first"] \ -type user -buttons ok -default 0 -cancel 0 return } $w itemconfigure 0 -state disabled $w itemconfigure 1 -command [namespace code [list abort_smp $w $xlib $jid]] set f [$w getframe] $f.e1:cmd configure -state readonly set secret [$f.e1 get] ::otr::replySMP $ctx($xlib,$jid) $secret } proc otr::abort_smp {w xlib jid} { variable ctx ::otr::abortSMP $ctx($xlib,$jid) destroy $w } proc otr::result_smp {w xlib jid} { if {![winfo exists $w]} return $w itemconfigure 0 -state normal -text [::msgcat::mc "OK"] \ -command [list destroy $w] $w itemconfigure 1 -state disabled -command [list destroy $w] } proc otr::progress_smp {xlib jid progress} { variable ctx if {![info exists ctx(smpdialog,$xlib,$jid)]} return set w $ctx(smpdialog,$xlib,$jid) switch -- $progress { SMP_PROGRESS { incr ctx(progress,$xlib,$jid) } SMP_ABORT { set ctx(progress,$xlib,$jid) 3 set ctx(status,$xlib,$jid) [::msgcat::mc "Authentication aborted"] result_smp $w $xlib $jid } SMP_CHEATING { set ctx(progress,$xlib,$jid) 3 set ctx(status,$xlib,$jid) [::msgcat::mc "Protocol error"] result_smp $w $xlib $jid } SMP_SUCCESS { set ctx(progress,$xlib,$jid) 3 set ctx(status,$xlib,$jid) \ [::msgcat::mc "Authentication succeeded"] result_smp $w $xlib $jid set myjid [::xmpp::jid::removeResource [connection_jid $xlib]] set fingerprint [::otr::fingerprint $ctx($xlib,$jid)] set tjid [peer_jid $xlib $jid] auth::set_auth auth::Auth $myjid $tjid $fingerprint 1 auth::store $auth::Auth foreach idx [array names ctx msgstate,$xlib,*] { regexp {msgstate,[^,]*,(.*)} $idx -> fjid if {[peer_jid $xlib $fjid] eq $tjid} { on_msgstate_change $xlib $fjid $ctx($idx) } } } SMP_FAILURE { set ctx(progress,$xlib,$jid) 3 set ctx(status,$xlib,$jid) [::msgcat::mc "Authentication failed"] result_smp $w $xlib $jid set myjid [::xmpp::jid::removeResource [connection_jid $xlib]] set fingerprint [::otr::fingerprint $ctx($xlib,$jid)] set tjid [peer_jid $xlib $jid] auth::set_auth auth::Auth $myjid $tjid $fingerprint 0 auth::store $auth::Auth foreach idx [array names ctx msgstate,$xlib,*] { regexp {msgstate,[^,]*,(.*)} $idx -> fjid if {[peer_jid $xlib $fjid] eq $tjid} { on_msgstate_change $xlib $fjid $ctx($idx) } } } } } ############################################################################# proc otr::rewrite_message_body \ {vxlib vfrom vid vtype vis_subject vsubject vbody verr vthread vpriority vx} { upvar 2 $vxlib xlib upvar 2 $vfrom from upvar 2 $vtype type upvar 2 $vbody body upvar 2 $verr err upvar 2 $vx x variable ns variable ctx # Work only in chats and normal messages if {$type ne "" && $type ne "normal" && $type ne "chat"} return # We can't distinguish between bodyless message and message with empty # body, so be it if {$body eq ""} return if {![once_only $xlib $from]} { if {![catch {::otr::data::binaryMessageFragment $body}] || \ ![catch {::otr::data::binaryMessage $body}]} { show_info $xlib $from \ [::msgcat::mc "%s have sent you an OTR encrypted\ message, but you can't decipher it\ because you don't have your OTR private\ key configured." $from] set body "" } elseif {![catch {::otr::data::findQueryMessage $body}]} { show_info $xlib $from \ [::msgcat::mc "%s has requested an Off-the-Record\ private conversation, but you can't\ maintain it because you don't have\ your OTR private key configured." $from] set body "" } return } set result [::otr::incomingMessage $ctx($xlib,$from) $body] debugmsg otr "INCOMING MESSAGE: $xlib; $from; $result;" array set res $result if {[info exists res(message)]} { set body $res(message) if {[info exists res(warn)]} { lappend x [::xmpp::xml::create "" \ -xmlns $ns \ -attrs {icon otr/notprivate}] } elseif {[msgstate:index $xlib $from] != 0} { lappend x [::xmpp::xml::create "" \ -xmlns $ns \ -attrs [list icon [msgstate:icon $xlib $from]]] } } else { lappend x [::xmpp::xml::create "" -xmlns $ns -attrs {discard 1}] } if {[info exists res(question)]} { after idle [namespace code [list reply_smp_dialog_qa \ $xlib $from $res(question)]] } if {[info exists res(secret)]} { after idle [namespace code [list reply_smp_dialog_ss \ $xlib $from]] } return } hook::add rewrite_message_hook \ [namespace current]::otr::rewrite_message_body 80 ############################################################################### proc otr::discard_message {xlib from id type is_subject \ subject body err thread priority x} { variable ns foreach xel $x { ::xmpp::xml::split $xel tag xmlns attrs cdata subels if {$tag eq "" && $xmlns eq $ns && \ [::xmpp::xml::getAttr $attrs discard] == 1} { return -code break } } return } hook::add process_message_hook [namespace current]::otr::discard_message 0.1 ############################################################################### proc otr::store_original_message_body \ {vxlib vto vid vtype vsubject vbody verr vthread vx} { upvar 2 $vxlib xlib upvar 2 $vto to upvar 2 $vtype type upvar 2 $vbody body variable ctx if {![info exists body]} return if {![info exists ctx($xlib,$to)]} return set ctx(original_message_body,$xlib,$to) $body } hook::add rewrite_outgoing_message_hook \ [namespace current]::otr::store_original_message_body 1 proc otr::rewrite_outgoing_message_body \ {vxlib vto vid vtype vsubject vbody verr vthread vx} { variable ctx upvar 2 $vtype type # Only chat and normal messages are subject to OTR if {[info exists type] && $type ne "" && $type ne "normal" && $type ne "chat"} return # Only messages with body are subject to OTR upvar 2 $vbody body if {![info exists body]} return upvar 2 $vxlib xlib upvar 2 $vto to if {![once_only $xlib $to]} return # Disable sending the message in case of error in the OTR code hook::unset_flag rewrite_outgoing_message_hook send # Only the message body is encrypted if appropriate set result [::otr::outgoingMessage $ctx($xlib,$to) $body] debugmsg otr "OUTGOING MESSAGE: $xlib; $to; $result;" array set res $result if {[info exists res(store)] && $res(store)} { upvar 2 $vid id upvar 2 $vsubject subject upvar 2 $verr err upvar 2 $vthread thread upvar 2 $vx x foreach v {id type subject err thread x} { if {[info exists $v]} { set is$v 1 set n$v [set $v] } else { set is$v 0 set n$v "" } } store $xlib $to $isid $nid $istype $ntype $issubject $nsubject \ 1 $ctx(original_message_body,$xlib,$to) \ $iserr $nerr $isthread $nthread $isx $nx } if {[info exists res(message)]} { # Enable sending the message back hook::set_flag rewrite_outgoing_message_hook send set body $res(message) } else { # Don't show this message in the chat log window # This flag makes sense only for chat messages, but causes no harm for # normal ones hook::unset_flag chat_send_message_hook draw } return } hook::add rewrite_outgoing_message_hook \ [namespace current]::otr::rewrite_outgoing_message_body 10 ############################################################################### proc otr::disable_log {chatid from type body x} { set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] if {[log_is_disabled $xlib $jid]} { hook::unset_flag draw_message_hook log } return } hook::add draw_message_hook [namespace current]::otr::disable_log 10 proc otr::disable_archive_in \ {xlib from id type is_subject subject body err thread priority x} { if {[log_is_disabled $xlib $from]} { hook::unset_flag process_message_hook log } return } hook::add process_message_hook [namespace current]::otr::disable_archive_in 10 proc otr::disable_archive_out {xlib to subject body thread} { if {[log_is_disabled $xlib $to]} { hook::unset_flag send_normal_message_hook log } return } hook::add send_normal_message_hook \ [namespace current]::otr::disable_archive_out 10 proc otr::log_is_disabled {xlib jid} { variable options variable ctx if {![info exists ctx($xlib,$jid)]} { return 0 } set njid [::xmpp::jid::normalize $jid] switch -- $ctx(msgstate,$xlib,$jid) { MSGSTATE_ENCRYPTED { if {[info exists options(dont-log-otr-messages,$xlib,$njid)]} { return $options(dont-log-otr-messages,$xlib,$njid) } else { return $options(dont-log-otr-messages) } } } return 0 } ############################################################################# proc otr::msgstate:trace {script xlib jid} { variable trace if {![info exists trace(msgstate,$xlib,$jid)]} { set trace(msgstate,$xlib,$jid) {} } if {[list write [namespace current]::trace] ni [trace info variable \ [namespace current]::ctx(msgstate,$xlib,$jid)]} { trace add variable \ [namespace current]::ctx(msgstate,$xlib,$jid) write \ [namespace current]::tracevar } if {$script ne {} && ($script ni $trace(msgstate,$xlib,$jid))} { lappend trace(msgstate,$xlib,$jid) $script } } proc otr::tracevar {name1 name2 op} { variable trace set new {} foreach script $trace($name2) { if {[catch { {*}$script } result]} { debugmsg otr "$result -- $script" } else { lappend new $script } } set trace($name2) $new } ############################################################################# proc otr::message_button {mw xlib jid} { set bbox [ButtonBox $mw.bottom.otrbutton -spacing 0] set b [$bbox add \ -image [msgstate:icon $xlib $jid] \ -helptype balloon \ -helptext [msgstate:helptext $xlib $jid] \ -relief link \ -state [msgstate:enabled $xlib $jid] \ -command [namespace code [list toggle_session $xlib $jid ""]]] msgstate:trace \ [list [namespace current]::msgstate:button_conf $b $xlib $jid] \ $xlib $jid pack $bbox -side left -fill x -padx 2m -pady 2m } hook::add open_message_post_hook [namespace current]::otr::message_button 55 ############################################################################### proc otr::chat_window_button {chatid type} { if {$type ne "chat"} { return } set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] set cw [chat::winid $chatid] set b [Button $cw.status.otrmsgstate \ -relief link \ -image [msgstate:icon $xlib $jid] \ -helptype balloon \ -helptext [msgstate:helptext $xlib $jid] \ -state [msgstate:enabled $xlib $jid] \ -command [namespace code [list toggle_session \ $xlib $jid $type]]] msgstate:trace \ [list [namespace current]::msgstate:button_conf $b $xlib $jid] \ $xlib $jid pack $b -side left -before $cw.status.mb } hook::add open_chat_post_hook [namespace current]::otr::chat_window_button 55 ############################################################################# proc otr::msgstate:button_conf {b xlib jid} { $b configure -image [msgstate:icon $xlib $jid] \ -helptext [msgstate:helptext $xlib $jid] \ -state [msgstate:enabled $xlib $jid] } proc otr::msgstate:icon {xlib jid} { lindex [list otr/notprivate \ otr/unverified \ otr/private \ otr/finished] \ [msgstate:index $xlib $jid] } proc otr::msgstate:helptext {xlib jid} { variable ctx set text [::msgcat::mc "State:"] append text " " [msgstate:state $xlib $jid] switch -- [msgstate:index $xlib $jid] { 1 - 2 { append text \n [::msgcat::mc "Fingerprint:"] " " \ [::otr::fingerprint $ctx($xlib,$jid)] \ \n [::msgcat::mc "SSID:"] " " \ [::otr::ssid $ctx($xlib,$jid)] } } set text } proc otr::msgstate:state {xlib jid} { lindex [list [::msgcat::mc "Not private"] \ [::msgcat::mc "Unverified"] \ [::msgcat::mc "Private"] \ [::msgcat::mc "Finished"]] \ [msgstate:index $xlib $jid] } proc otr::msgstate:index {xlib jid} { variable ctx if {[info exists ctx($xlib,$jid)]} { switch -- $ctx(msgstate,$xlib,$jid) { MSGSTATE_PLAINTEXT { return 0 } MSGSTATE_ENCRYPTED { set myjid [::xmpp::jid::removeResource [connection_jid $xlib]] set fingerprint [::otr::fingerprint $ctx($xlib,$jid)] set tjid [peer_jid $xlib $jid] if {![auth::get_auth $auth::Auth $myjid $tjid $fingerprint]} { return 1 } else { return 2 } } MSGSTATE_FINISHED { return 3 } } } return 0 } proc otr::msgstate:enabled {xlib jid} { if {[lsearch -exact [connections] $xlib] < 0 || [::xmpp::jid::equal [my_jid $xlib $jid] $jid] || ![once_only $xlib $jid]} { return disabled } else { return normal } } ############################################################################### proc otr::enable_disable_buttons {xlib} { variable ctx foreach chatid [chat::opened $xlib] { set jid [chat::get_jid $chatid] if {[info exists ctx(msgstate,$xlib,$jid)]} { on_msgstate_change $xlib $jid $ctx(msgstate,$xlib,$jid) } else { on_msgstate_change $xlib $jid MSGSTATE_PLAINTEXT } } } hook::add connected_hook [namespace current]::otr::enable_disable_buttons hook::add disconnected_hook [namespace current]::otr::enable_disable_buttons ############################################################################### proc otr::user_popup_info {infovar xlib jid} { variable ctx upvar 0 $infovar info if {[info exists ctx($xlib,$jid)]} { append info [::msgcat::mc "\n\tOTR:"] append info \ [regsub -all {\n} \n[msgstate:helptext $xlib $jid] "\n\t "] } } hook::add roster_user_popup_info_hook \ [namespace current]::otr::user_popup_info 99 ############################################################################# proc otr::userinfo {tab xlib jid editable} { variable ctx if {$editable} return set bjid [::xmpp::jid::removeResource $jid] set chatid [chat::chatid $xlib $bjid] if {[chat::is_groupchat $chatid]} { if {[info exists ctx(authstate,$xlib,$jid)]} { set jids [list authstate,$xlib,$jid] } else { set jids [list] } } else { set bjpat [regsub -all {(.)} $bjid {\\\1}] set jids [array names ctx authstate,$xlib,$bjpat/*] } if {[llength $jids] > 0} { set otrinfo [$tab insert end otrinfo \ -text [::msgcat::mc "OTR"]] set sw [ScrolledWindow $otrinfo.sw -scrollbar vertical] pack $sw -fill both -expand yes set sf [ScrollableFrame $otrinfo.sf -constrainedwidth 1] $sw setwidget $sf set i 0 foreach j $jids { regexp {authstate,[^,]*,(.*)} $j -> fjid set x [userinfo::pack_frame [$sf getframe].otr_$i $fjid] userinfo::pack_entry $jid $x 1 otr_state_$i [::msgcat::mc "State:"] set ::userinfo::userinfo(otr_state_$i,$jid) \ [msgstate:state $xlib $fjid] userinfo::pack_entry $jid $x 2 otr_fingerprint_$i \ [::msgcat::mc "Fingerprint:"] set ::userinfo::userinfo(otr_fingerprint_$i,$jid) \ [::otr::fingerprint $ctx($xlib,$fjid)] userinfo::pack_entry $jid $x 3 otr_ssid_$i [::msgcat::mc "SSID:"] set ::userinfo::userinfo(otr_ssid_$i,$jid) \ [::otr::ssid $ctx($xlib,$fjid)] bindscrolldeep $sf $sf incr i } } } hook::add userinfo_hook [namespace current]::otr::userinfo 90 proc otr::bindscrolldeep {w f} { bindscroll $w $f foreach sw [winfo children $w] { bindscrolldeep $sw $f } } ############################################################################### proc otr::main_menu {} { variable options catch { set m [.mainframe getmenu tkabber] set ind [$m index [::msgcat::mc "View"]] incr ind -1 set mm .otr_menu menu $mm -tearoff $::ifacetk::options(show_tearoffs) $mm add command -label [::msgcat::mc "Manage private keys"] \ -command [namespace code key::manage_keys_dialog] $mm add command -label [::msgcat::mc "Edit authentication"] \ -command [namespace code auth::edit_auth_dialog] $mm add separator $mm add checkbutton -label [::msgcat::mc "Allow encryption"] \ -variable [namespace current]::options(allow-encryption) $mm add checkbutton -label [::msgcat::mc "Require encryption"] \ -variable [namespace current]::options(require-encryption) $mm add checkbutton -label [::msgcat::mc "Attach whitespace tag"] \ -variable [namespace current]::options(send-whitespace-tag) $mm add checkbutton -label [::msgcat::mc "Start AKE on whitespace tag\ or OTR error"] \ -variable \ [namespace current]::options(whitespace-or-error-start-ake) $mm add checkbutton -label [::msgcat::mc "Don't log OTR messages"] \ -variable [namespace current]::options(dont-log-otr-messages) $m insert $ind cascade -label [::msgcat::mc "OTR"] \ -menu $mm } } hook::add finload_hook [namespace current]::otr::main_menu 55 ############################################################################### proc otr::user_menu {type m xlib jid} { variable options variable ctx set njid [::xmpp::jid::normalize $jid] foreach key {allow-encryption require-encryption send-whitespace-tag whitespace-or-error-start-ake dont-log-otr-messages} { if {![info exists options($key,$xlib,$njid)]} { set options($key,$xlib,$njid) $options($key) } } if {[::xmpp::jid::equal [my_jid $xlib $jid] $jid] || ![once_only $xlib $jid]} { set state disabled set qstate disabled set rstate disabled set fstate disabled set astate disabled } else { switch -- $ctx(msgstate,$xlib,$jid) { MSGSTATE_PLAINTEXT { set qstate normal set rstate disabled set fstate disabled set astate disabled } MSGSTATE_ENCRYPTED { set qstate disabled set rstate normal set fstate normal set astate normal } MSGSTATE_FINISHED { set qstate disabled set rstate normal set fstate normal set astate disabled } } } if {![info exists state] && [lsearch -exact [connections] $xlib] >= 0} { set state normal } else { set state disabled } set mm $m.otr_menu menu $mm -tearoff 0 $mm add command -label [::msgcat::mc "Start OTR session"] \ -command [list [namespace current]::request_session $xlib $jid $type] \ -state $qstate $mm add command -label [::msgcat::mc "Refresh OTR session"] \ -command [list [namespace current]::request_session $xlib $jid $type] \ -state $rstate $mm add command -label [::msgcat::mc "End OTR session"] \ -command [list [namespace current]::finish_session $xlib $jid $type] \ -state $fstate $mm add separator $mm add command -label [::msgcat::mc "Authenticate peer..."] \ -command [list [namespace current]::begin_smp_dialog $xlib $jid] \ -state $astate $mm add separator $mm add command -label [::msgcat::mc "Reset to default policy"] \ -command [list [namespace current]::reset_policy $xlib $jid] $mm add checkbutton -label [::msgcat::mc "Allow encryption"] \ -variable [namespace current]::options(allow-encryption,$xlib,$njid) \ -command [list [namespace current]::update_policy $xlib $jid] $mm add checkbutton -label [::msgcat::mc "Require encryption"] \ -variable \ [namespace current]::options(require-encryption,$xlib,$njid) \ -command [list [namespace current]::update_policy $xlib $jid] $mm add checkbutton -label [::msgcat::mc "Attach whitespace tag"] \ -variable \ [namespace current]::options(send-whitespace-tag,$xlib,$njid) \ -command [list [namespace current]::update_policy $xlib $jid] $mm add checkbutton -label [::msgcat::mc "Start AKE on whitespace tag or\ OTR error"] \ -variable \ [namespace current]::options(whitespace-or-error-start-ake,$xlib,$njid) \ -command [list [namespace current]::update_policy $xlib $jid] $mm add checkbutton -label [::msgcat::mc "Don't log OTR messages"] \ -variable \ [namespace current]::options(dont-log-otr-messages,$xlib,$njid) \ -command [list [namespace current]::update_policy $xlib $jid] $m add cascade -label [::msgcat::mc "OTR"] -menu $mm -state $state } hook::add chat_create_user_menu_hook \ [list [namespace current]::otr::user_menu chat] 43.8 hook::add roster_jid_popup_menu_hook \ [list [namespace current]::otr::user_menu ""] 43.8 hook::add message_dialog_menu_hook \ [list [namespace current]::otr::user_menu ""] 43.8 hook::add roster_create_groupchat_user_menu_hook \ [list [namespace current]::otr::user_menu ""] 43.8 # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/otr/pixmaps000075500000000000000000000000001500237002100157175ustar00nobodynobodytkabber-plugins/otr/pixmaps/otr000075500000000000000000000000001500237002100165235ustar00nobodynobodytkabber-plugins/otr/pixmaps/otr/finished.gif000064400000000000000000000020231500237002100210570ustar00nobodynobodyGIF89aç€  £…© §Ñ’"¬¦Ó­«Ð Õ Ò ¯G44¯žž× AAABBBCCCFFFÓ!!Õ##™55MMMØ((`NNÊ55Ë55Ì66}OO_^]„VV```aa`p^^r``×EEÖHHâEE×HHÕKKåGGâIIæIIÞLLèKKçOOqpoÖUUéPPÛXXÛZZÝ[[äZZ{{z{{{Ýbbé``€€€ìdd€‚‚ìffƒƒ‚ˆˆˆ‹ŠŠŒ‹‹âttŒŒŒèttévvëxxíyyè{{•••–––˜˜˜šššœœ›œœœžž¡¡ £££§§¦§§§©§¥¨¨¨ª¨¦©©©«««¬¬¬­­­®®®¯¯¯°°°²²²³³³´´´¶¶¶¸¸¸¹¹¹ººº»»»¼¼¼½½½¾¾¾¿¿¿ÀÀÀÂÂÂÃÃÃÄÄÄÅÅÅÇÇÇÈÈÈÊÊÊËËËÌÌÌÎÎÎÏÏÏÑÑÑÒÒÒÔÔÔÖÖÖ×××ÙÙÙñìëñíìîîìïïíððîññïññðòòðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ÿ,ðÿ £äG1*üwÄ ?r¸Y˜°ÈB‚úèÉ£†E1^2(:XÀ,Lbç Að¼a“&ÉÂ{ðìᓇN›3m~¬tCg8mЬp€„b¶ÐYÃF™xD‰²cBBfÜœ £Â€#9liÒ@ !VȨA cH1\ôÀAá>]üð‘£GŽ=Z2àC™1u*0%Ñ#FŠ-2`Ã-Y®P©C†… tá!E•/Pœ0 Á€8°P ðƒ–5n‚ŸH@âE ¼šÐ€¡y MH;tkabber-plugins/otr/pixmaps/otr/icondef.xml000064400000000000000000000012751500237002100207400ustar00nobodynobody OTR 1.0 Theme from the OTR website. 2014-01-11 otr/notprivate notprivate.gif otr/unverified unverified.gif otr/private private.gif otr/finished finished.gif tkabber-plugins/otr/pixmaps/otr/notprivate.gif000064400000000000000000000011301500237002100214570ustar00nobodynobodyGIF89aÆMAAAFFFMMMUUU\\\bbbcccgggooorpowwwzyxzzz{{z|||}}}~~~€~‚‚‚‡‡‡‰‰‰‹ŠŠ‹‹‹Œ‹‹ŒŒŒ‘‘‘“““–––—–•˜˜—˜˜˜ššš››šœœœœ›žžžŸŸŸ   ¡¡¡¢¢¢¥£¢¥¥¥¦¦¦¨¨¨©©©ªªª­­­®®®°°°±±±²²²´´´µµµ···¸¸¸¹¹¹»»»¼¼¼¾¼¹½½½¾¾¾¿¿¿ÀÀÀÃÃÃÅÅÅÈÈÈÉÉÉÊÊÊËËËÎÎÎÐÐÐÒÒÒÖÖÖØØØÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,µ€‚‚=$ƒ‰‰+.GH7ŠŠ.LKFA<†ˆ‰DIJE;‘ƒ?@%”–A>ŒŽ(Ÿ¡<6)¯—> EBC@81*ž E¼'4:8603"ÅÇÉ*92.2/$ÒÔÖ &'!‚ßáã5:>?/,ìîà@c¼ 4 À§_…T”˜Ø‚A€‚þYPÀ€Ç$DœX¢¢¤A=yòO ;tkabber-plugins/otr/pixmaps/otr/private.gif000064400000000000000000000017541500237002100207520ustar00nobodynobodyGIF89açŠ\5f]7g^7h`:jgBpgCpoKw|QXtP{uR{wT}V^yW|Z‚…gгu³u³u²u²u¶y¶z·|¸}¸}•|˜¸~º‚*»ƒ*¼„+ ¢½…-½….½…/½†/­¨­€©®©®‚ª°„«°…¬±ˆ­«Œª³Š¯¬«Ì’6Ì“7Ì”6¶²¸‘²Î—>³”±¸“´Î™C´–²Åœ`¶˜´ÐœI¼™··›¶ÇŸb½›ºÒ¢UÒ¢W¿ž»â¡<̤d̤e̤fâ¢>Ü£IÌ¥fÀ »â£?½¢»Ý¥LݦNݦOÀ¤½ã¦Fä§HݨUã¨J¦¿ä¨Jå©MäªNß«Xå«Qå¬RÞ­`ã­Wæ­UÆ¬Âæ®Væ¯Xç°[ȯÅå±`ç±\ʱÆç³`á´mè´dèµfé¶hã¸vé¸lé¹mé¹nιËä¼~侂ë¾yå¿„ë¿zÓ¿ÏìÀ|ìÀ}ÕÂÄêÆíÃÖÄÅíÄ…íÆŠëÈîÈîÈŽïÊ’ÙËÕð͘ïΚðÏœñРñÑ¡ñÓ¤òÔ¨àÖÜÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ÿ,Éÿ <""ˆ!*ü§á‡œ>jr\X˜œCƒøØ©£ÅE"> B¨š62„, ñæ B~âœùr¥ÃÂxæäÙS‡ *b ,ü`¦Íš6iÆTyÒĦB!5Úpñ’J,/T.œ¥Œ”"I¬‘@ñß‚ .˜lY҂ŠTèáÁáÁ†w))AAACCCFFFMMMSSSZYYlVV```aa`t__qpoÄ[[ƒmm…pp{{z{{{€€€€‚‚ƒƒ‚ˆˆˆ‹ŠŠŒ‹‹Ï{{•••–––˜˜˜šššœœ›œœœžž¡¡ £££§§¦§§§©§¥¨¨¨ª¨¦©©©ªªª«««¬¬¬­­­®®®¯¯¯²²²³³³´´´ßªª¶¶¶¸¸¸¹¹¹ººº»»»¼¼¼½½½¾¾¾¿¿¿ÀÀÀÂÂÂÃÃÃå»»ÄÄÄÅÅÅÇÇÇÈÈÈÊÊÊËËËÌÌÌÎÎÎÏÏÏÑÑÑÒÒÒÔÔÔÖÖÖ×××ÙÙÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ,µ€‚++‚‰Š'BI<%‹‰APMHED3”+'OOQKD:>!)‹@JMNJB95‹FBFGD>71ÁŠ8>=>;72Á¶‰+$>4530*ÁS‰081*,µC@6΂ .3-ØÙÎ G& SSÎ/Xü`"Û%Sàý)c„ hHȯŸ­PpØ`0¡GaFÐÀѬdIA `òd ;tkabber-plugins/otr/tclotr000075500000000000000000000000001500237002100155455ustar00nobodynobodytkabber-plugins/otr/tclotr/ChangeLog000064400000000000000000000150741500237002100174050ustar00nobodynobody2023-03-30 Sergei Golovan * crypto.tcl: Use TWAPI to generate random numbers in Windows if available. 2017-03-27 Sergei Golovan * otr.tcl: Use zero padding when formatting an OTR fingerprint for display. 2016-01-04 Sergei Golovan * otr.tcl: Reset the keys counter after the AKE completion in case when the correspondent's keys have been changed. 2016-01-02 Sergei Golovan * otr.tcl: Fixed a small bug in returning "can't decrypt" message. Added -discardcommand and -resendcommand options to the otr::new procedure. They allow the caling application to replace built-in storing, discarding and resending routines. 2015-12-27 Sergei Golovan * otr.tcl: Don't switch to plaintext message state on an OTR error message retrieving. Display a bit more meaningful error messages to a user in case of receiving OTR request with nismatched protocol version. Do not resend pending message if the peer has changed her OTR key between sessions. 2015-05-10 Sergei Golovan * auth.tcl, message.tcl, otr.tcl: Removed trailing spaces. 2015-05-09 Sergei Golovan * crypto.tcl, key.tcl, otr.tcl, pkgIndex.tcl: Reformatted the TclOTR library code. 2015-03-29 Sergei Golovan * auth.tcl, crypto.tcl, data.tcl, key.tcl, message.tcl, otr.tcl, pkgIndex.tcl, smp.tcl: Removed no longer needed SVN keywords placeholders. * ChangeLog, README: Added separate ChangelLog and README for the TclOTR package. 2015-03-25 Sergei Golovan * otr.tcl: Returned [eval] instead of [uplevel #0] for calling back since [eval] allows to look up the call stack anf find something useful there (see [otr::send] procedure). Switch the OTR state to plaintext after an OTR error message is received. Otherwise, if the other side disables OTR in the middle of an encrypted conversation we cannot tell her anything at all - all messages will be encrypted, and she'll never read them. * license.terms: Fixed copyright year. 2014-11-12 Sergei Golovan * otr.tcl: Evaluate external callback procedures at the top stack level. 2014-05-06 Sergei Golovan * auth.tcl: Fixed recreating the reveal signature message. 2014-02-19 Sergei Golovan * smp.tcl: Added a debug print procedure instead of plain puts calls. 2014-02-15 Sergei Golovan * README: Fixed the requirements list. 2014-02-02 Sergei Golovan * key.tcl: Moved key generation procedure to the otr::key package. 2014-01-27 Sergei Golovan * key.tcl: Fixed typo. * key.tcl: Use unix line endings when exporting the DSA private key. Refuse to import keys which aren't 1024 bit long. * otr/README: Fixed info on how to use private keys. * message.tcl: Treat human readable message part as HTML (strip tags for incoming messages, escape HTML entities for outgoing ones). 2014-01-26 Sergei Golovan * otr.tcl: Fixed refreshing private connection if the peer has changed his instance tag. Clear messages subject to resend when the message state switches from encrypted. * auth.tcl: Fixed recreating D-H commit message. 2014-01-25 Sergei Golovan * key.tcl, crypto.tcl: Code cleanup, made DSA key generation more clear. * otr.tcl: Use the sender's instance tag included into the Diffie-Hellman commit message. Resend the last data message if it was replied by an OTR error message (resend it after a new successful AKE). * otr.tcl: Fixed processing message state changes. Show an info message when private conversation is started. * otr.tcl: Show an info message when private conversation is finished. * otr.tcl: Implemented functions which return SSID and fingerprint. 2014-01-24 Sergei Golovan * crypto.tcl: Implemented generating new DSA private key. 2014-01-23 Sergei Golovan * message.tcl, otr.tcl: Code cleanup. Moved most of the interaction with the calling program to callbacks. * otr.tcl: Fixed typos in callback invocations. 2014-01-21 Sergei Golovan * key.tcl, pkgIndex.tcl: Added a new subpackage which currently encodes and decodes DSA private keys in PEM format. * otr.tcl: Tell the OTR plugin about state changes and SMP progress using callbacks and only in case of actual change. * otr.tcl: Attach the OTR whitespace tag only if there weren't received plaintext messages from the peer before. 2014-01-20 Sergei Golovan * otr.tcl: Do not send the OTR query message after an OTR error if no ALLOW_V2 or ALLOW_V3 is in the policy flags. * data.tcl: Removed already done todo item. * otr.tcl, message.tcl: Implemented the old MAC keys revelation, checking for the peer's counter monotonicity, ignoring verification and decryption errors if IGNORE_UNREADABLE message flag is set. * data.tcl, otr.tcl: Implemented assembling incoming messages from fragments. * otr.tcl: Implemented sending heartbeat messages. * otr.tcl: Fixed typo in code which stores old MAC keys. * otr.tcl: Removed unnecessary field from OTR procedures' result. * otr.tcl: Fixed typo in ::otr::configure. * otr.tcl: Warn user if plaintext message is received while encryption is required. 2014-01-19 Sergei Golovan * otr.tcl: Fixed checking data message hash for protocol version 3. * message.tcl: Fixed typo in processing SMP message 4. Fixed error reporting. * smp.tcl: SMP protocol is now working, but its outcome isn't utilised anywhere. * message.tcl: Got rid of eval and uplevel calls. * otr.tcl: Don't attach the OTR whitespace tag if policy doesn't allow using any protocol version. * message.tcl, otr.tcl, smp.tcl: Roughly finished SMP implementation. No peer authentication status storing yet though. 2014-01-18 Sergei Golovan * *: Better error reporting. Continue implementing peer authentication. 2014-01-17 Sergei Golovan * *: Added pre-alpha of the new OTR package. No key management, peer authentication, SMP, proper error reporting, resending messages yet. Not for regular usage yet. * crypto.tcl: Added procedure which computes binary DSA public key fingerprint. * otr.tcl: Don't compute DSA key fingerprint directly, but convert the one computed in the otr::crypto package. * smp.tcl: Initially implemented parsing, creating and verifying OTR SMP messages. tkabber-plugins/otr/tclotr/README000064400000000000000000000016331500237002100165070ustar00nobodynobodyThe TclOTR package implements the Off-the-record messaging protocol (https://otr.cypherpunks.ca/). This package requires Tcl 8.5 or newer because it uses an arbitrary precision integers. Also, the base64, sha1, sha256, aes, asn and math::bignum packages are required, they all are bundled with the Tcllib collection. For Windows this package also requires the Memchan package. Its [random] channel is used as a PRNG. To actually use OTR you'll need a 1024 bit DSA private key (OTR protocol supports only 1024 bit keys). There are two ways of making it work: 1) You can generate a new key directly using [::otr::key::generate 1024 160] (only 1024 bit keys can be used with OTR). 2) You can import an existing key stored in PEM format via [::otr::key::readPEM otr.private.key]. To generate it you can use OpenSSL: openssl dsaparam -out dsaparam.pem 1024 openssl gendsa -out otr.private.key dsaparam.pem Happy hacking! tkabber-plugins/otr/tclotr/auth.tcl000064400000000000000000000633751500237002100173070ustar00nobodynobody# auth.tcl -- # # This file is a part of the Off-the-Record messaging protocol # implementation. It contains the OTR AKE packets serializing and # deserializing procedures. # # Copyright (c) 2014 Sergei Golovan # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAMER OF ALL WARRANTIES. package require sha256 package require otr::data package require otr::crypto package provide otr::auth 0.1 ############################################################################## namespace eval ::otr::auth {} # ::otr::auth::createDHCommitMessage -- # # Assemble the first OTR AKE message which Bob sends to Alice - the D-H # commit one. # # Arguments: # version Protocol version (2 or 3). # r Random binary to use as an AES key. # x D-H private key. # -sinstance num (only for version 3) The sender instance tag. # -rinstance num (only for version 3) The receiver instance tag. # # Result: # Tuple {authstate msgstate message} where authstate and msgstate are # the new FSM state, and message is a BASE64 encoded OTR packet with the # message inside. # # Side effects: # None. proc ::otr::auth::createDHCommitMessage {version authstate msgstate r x args} { set sinstance 0x100 set rinstance 0 foreach {key val} $args { switch -- $key { -sinstance { set sinstance $val } -rinstance { set rinstance $val } } } set message [createDHCommitPayload $version \ $r \ $x \ $sinstance \ $rinstance] set authstate AUTHSTATE_AWAITING_DHKEY list $authstate $msgstate $message } # ::otr::auth::createDHCommitPayload -- # # Assemble the first OTR AKE message which Bob sends to Alice - the D-H # commit one. # # Arguments: # version Protocol version (2 or 3). # r Random binary to use as an AES key. # x D-H private key. # sinstance (only for version 3) The sender instance tag. # rinstance (only for version 3) The receiver instance tag. # # Result: # BASE64 encoded binary OTR packet with the message inside. # # Side effects: # None. proc ::otr::auth::createDHCommitPayload {version r x sinstance rinstance} { set res "" append res [::otr::data::encode SHORT $version] append res [::otr::data::encode BYTE 0x02] if {$version > 2} { append res [::otr::data::encode INT $sinstance] append res [::otr::data::encode INT $rinstance] } set gx [::otr::crypto::DHGx $x] set gxmpi [::otr::data::encode MPI $gx] set egxmpi [::otr::crypto::aes $gxmpi $r 0] append res [::otr::data::encode DATA $egxmpi] append res [::otr::data::encode DATA [::sha2::sha256 -bin $gxmpi]] ::otr::data::encodeMessage $res } # ::otr::auth::processDHCommitMessage -- # # Pick the received D-H Commit message without the protocol version, # packet type and instance tags, as well as the D-H private key, and # create a suitable reply message. # # Arguments: # version OTR protocol version. # authstate AKE authentication state. # msgstate Message state. # data D-H commit packet to process. # x D-H private key which is to be used for creating the # answer. # -sinstance num (only for version 3) The sender instance tag. # -rinstance num (only for version 3) The receiver instance tag. # -r r One-time AES key to use only in auth state # AUTHSTATE_AWAITING_DHKEY to recreate D-H commit # message. # # Result: # Tuple {auhstate msgstate message} or {authstate msgstate message # egxmpi hgxmpi} with new FSM state, the message to reply, and encrypted # and hashed peer's D-H public key to store if the current FSM state is # appropriate. # # Side effects: # None. proc ::otr::auth::processDHCommitMessage {version authstate msgstate data \ x args} { set sinstance 0x100 set rinstance 0x100 foreach {key val} $args { switch -- $key { -sinstance { set sinstance $val } -rinstance { set rinstance $val } -r { set r $val } } } if {[catch {parseDHCommitMessage $version $data} res]} { return [list $authstate $msgstate ""] } lassign $res egxmpi hgxmpi switch -- $authstate { AUTHSTATE_NONE - AUTHSTATE_AWAITING_SIG { set authstate AUTHSTATE_AWAITING_REVEALSIG return [list $authstate $msgstate [createDHKeyMessage \ $version \ $x \ -sinstance $rinstance \ -rinstance $sinstance] \ $egxmpi $hgxmpi] } AUTHSTATE_AWAITING_DHKEY { set gx [::otr::crypto::DHGx $x] set gxmpi [::otr::data::encode MPI $gx] set myhgxmpi [::sha2::sha256 -bin $gxmpi] if {[::otr::data::Bin2Int $myhgxmpi] > [::otr::data::Bin2Int $hgxmpi]} { return [createDHCommitMessage $version \ $authstate \ $msgstate \ $r \ $x \ -sinstance $rinstance] } else { set authstate AUTHSTATE_AWAITING_REVEALSIG return [list $authstate $msgstate [createDHKeyMessage \ $version \ $x \ -sinstance $rinstance \ -rinstance $sinstance] \ $egxmpi $hgxmpi] } } AUTHSTATE_AWAITING_REVEALSIG { return [list $authstate $msgstate [createDHKeyMessage \ $version \ $x \ -sinstance $rinstance \ -rinstance $sinstance] \ $egxmpi $hgxmpi] } } } # ::otr::auth::parseDHCommitMessage -- # # Parse the D-H commit message (without version and packet type which # were extracted earlier). # # Arguments: # version Protocol version (2 or 3). # data Payload to parse. # # Result: # Tuple {egxmpi, H(gxmpi)}. # # Side effects: # Error is raised if decoding is failed for some reason. proc ::otr::auth::parseDHCommitMessage {version data} { lassign [::otr::data::decode DATA $data] egxmpi data lassign [::otr::data::decode DATA $data] hgxmpi data list $egxmpi $hgxmpi } # ::otr::auth::createDHKeyMessage -- # # Assemble the first OTR AKE message which Alice returns to Bob - the # D-H key one. # # Arguments: # version Protocol version (2 or 3). # y D-H private key. # -sinstance num (only for version 3) The sender instance tag. # -rinstance num (only for version 3) The receiver instance tag. # # Result: # BASE64 encoded OTR packet with the message inside. # # Side effects: # None. proc ::otr::auth::createDHKeyMessage {version y args} { set sinstance 0x100 set rinstance 0 foreach {key val} $args { switch -- $key { -sinstance { set sinstance $val } -rinstance { set rinstance $val } } } set res "" append res [::otr::data::encode SHORT $version] append res [::otr::data::encode BYTE 0x0a] if {$version > 2} { append res [::otr::data::encode INT $sinstance] append res [::otr::data::encode INT $rinstance] } set gy [::otr::crypto::DHGx $y] append res [::otr::data::encode MPI $gy] ::otr::data::encodeMessage $res } # ::otp::auth::processDHKeyMessage -- # # Pick the received D-H Key message without the protocol version, # packet type and instance tags, as well as the one-time AES key, D-H # private key with its keyid, and create a suitable reply message. # # Arguments: # version OTR protocol version. # authstate AKE authentication state. # msgstate Message state. # data D-H key packet to process. # r One time AES key to reveal to the peer. # x D-H private key which is to be used for creating the # answer. # keyid Serial number of the above D-H key. # -sinstance num (only for version 3) The sender instance tag. # -rinstance num (only for version 3) The receiver instance tag. # -gy gy The already obtained peer's D-H public key for the case # when it's a repeated D-H key message (used only in # auth state AUTHSTATE_AWAITING_SIG). # # Result: # Tuple {auhstate msgstate message} or {authstate msgstate message gy} # with new FSM state, the message to reply, and the peer's D-H public # key to store if the current FSM state is appropriate. # # Side effects: # None. proc ::otr::auth::processDHKeyMessage {version authstate msgstate data privkey r x keyid args} { set sinstance 0x100 set rinstance 0x100 foreach {key val} $args { switch -- $key { -sinstance { set sinstance $val } -rinstance { set rinstance $val } -gy { set oldgy $val } } } if {[catch {parseDHKeyMessage $version $data} res]} { return [list $authstate $msgstate ""] } lassign $res gy if {![::otr::crypto::DHCheck $gy]} { return [list $authstate $msgstate ""] } switch -- $authstate { AUTHSTATE_NONE - AUTHSTATE_AWAITING_REVEALSIG { return [list $authstate $msgstate ""] } AUTHSTATE_AWAITING_DHKEY { lassign [::otr::crypto::AKEKeys $gy $x] ssid c cp m1 m2 m1p m2p set authstate AUTHSTATE_AWAITING_SIG return [list $authstate $msgstate [createRevealSignatureMessage \ $version $r $c $m1 $m2 \ $x $gy $privkey $keyid \ -sinstance $rinstance \ -rinstance $sinstance] \ $gy] } AUTHSTATE_AWAITING_SIG { if {$gy != $oldgy} { return [list $authstate $msgstate ""] } else { lassign [::otr::crypto::AKEKeys $gy $x] ssid c cp m1 m2 m1p m2p return [list $authstate $msgstate \ [createRevealSignatureMessage \ $version $r $c $m1 $m2 \ $x $gy $privkey $keyid \ -sinstance $rinstance \ -rinstance $sinstance] \ $gy] } } } } # ::otr::auth::parseDHKeyMessage -- # # Parse the D-H key message (without version and packet type which # were extracted earlier). # # Arguments: # version The protocol version (2 or 3). # data The payload to parse. # # Result: # Tuple {gy}. # # Side effects: # Error is raised if decoding is failed for some reason. proc ::otr::auth::parseDHKeyMessage {version data} { lassign [::otr::data::decode MPI $data] gy data list $gy } # ::otr::auth::createRevealSignatureMessage -- # # Assemble the third OTR AKE message which Bob sends to Alice - the # reveal signature one. # # Arguments: # version The protocol version (2 or 3). # r The random value which was used as an AES key. # c AES key computed from the shared secret. # m1 MAC key computed from the shared secret. # m2 MAC key computed from the shared secret. # x The random value which is the part of shared secret. # gy The part of D-H shared secret. # keyB Long-term private key. # keyidB Serial number for the D-H key. # -sinstance num (only for version 3) The sender instance tag. # -rinstance num (only for version 3) The receiver instance tag. # # Result: # BASE64 encoded OTR packet with the message inside. # # Side effects: # None. proc ::otr::auth::createRevealSignatureMessage {version r c m1 m2 x \ gy keyB keyidB args} { set sinstance 0x100 set rinstance 0 foreach {key val} $args { switch -- $key { -sinstance { set sinstance $val } -rinstance { set rinstance $val } } } set res "" append res [::otr::data::encode SHORT $version] append res [::otr::data::encode BYTE 0x11] if {$version > 2} { append res [::otr::data::encode INT $sinstance] append res [::otr::data::encode INT $rinstance] } append res [::otr::data::encode DATA $r] set gx [::otr::crypto::DHGx $x] set gxmpi [::otr::data::encode MPI $gx] set gympi [::otr::data::encode MPI $gy] set pubB [::otr::data::encode PUBKEY $keyB] set ikeyidB [::otr::data::encode INT $keyidB] set MB [::sha2::hmac -bin -key $m1 $gxmpi$gympi$pubB$ikeyidB] set sigBMB [::otr::data::encode SIG [::otr::crypto::sign $MB $keyB]] set encr [::otr::crypto::aes $pubB$ikeyidB$sigBMB $c 0] set encrfield [::otr::data::encode DATA $encr] append res $encrfield append res \ [::otr::data::encode MAC [::sha2::hmac -bin -key $m2 $encrfield]] ::otr::data::encodeMessage $res } # ::otr::auth::processRevealSignatureMessage -- # # Pick the received Reveal signature message without the protocol # version, packet type and instance tags, as well as the got earlier # peer's encrypted and hashed D-H public key, D-H private key with its # keyid, and create a suitable reply message. # # Arguments: # version OTR protocol version. # authstate AKE authentication state. # msgstate Message state. # data Reveal signature packet to process. # egxmpi Encrypted peer's D-H public key. # hgxmpi Hashed peer's D-H public key. # keyA DSA private key. # y D-H private key which is to be used for decrypting, # verifying the hash and creating the answer. # keyidA Serial number of the above D-H key. # -sinstance num (only for version 3) The sender instance tag. # -rinstance num (only for version 3) The receiver instance tag. # # Result: # Tuple {auhstate msgstate message} or {authstate msgstate message key # gx keyid} with new FSM state, the message to reply, and the peer's # DSA public key, D-H public key and its serial to store if the current # FSM state is appropriate. # # Side effects: # None. proc ::otr::auth::processRevealSignatureMessage {version authstate msgstate \ data egxmpi hgxmpi keyA y \ keyidA args} { set sinstance 0x100 set rinstance 0x100 foreach {key val} $args { switch -- $key { -sinstance { set sinstance $val } -rinstance { set rinstance $val } } } if {[catch {parseRevealSignatureMessage $version $data} res]} { #puts "Reveal signature message is corrupt" return [list $authstate $msgstate ""] } lassign $res r encr hmac switch -- $authstate { AUTHSTATE_NONE - AUTHSTATE_AWAITING_DHKEY - AUTHSTATE_AWAITING_SIG { #puts "Wrong state for reveal signature message" return [list $authstate $msgstate ""] } AUTHSTATE_AWAITING_REVEALSIG { set gxmpi [::otr::crypto::aes $egxmpi $r 0] set vhgxmpi [::sha2::sha256 -bin $gxmpi] if {$hgxmpi ne $vhgxmpi} { #puts "H(Gx) and decrypted Gx from D-H commit differ" return [list $authstate $msgstate ""] } if {[catch {::otr::data::decode MPI $gxmpi} res]} { #puts "D-H public key can't be deciphered" return [list $authstate $msgstate ""] } lassign $res gx if {![::otr::crypto::DHCheck $gx]} { #puts "D-H public key is incorrect" return [list $authstate $msgstate ""] } lassign [::otr::crypto::AKEKeys $gx $y] ssid c cp m1 m2 m1p m2p set myhmac \ [::sha2::hmac -bin -key $m2 [::otr::data::encode DATA $encr]] if {[string range $myhmac 0 19] ne $hmac} { #puts "HMAC in Reveal signature message is invalid" return [list $authstate $msgstate ""] } set decr [::otr::crypto::aes $encr $c 0] if {[catch {parsePubkey $decr} res]} { #puts "DSA public key can't be deciphered" return [list $authstate $msgstate ""] } lassign $res keyB keyidB sigBMB set gxmpi [::otr::data::encode MPI $gx] set gympi [::otr::data::encode MPI [::otr::crypto::DHGx $y]] set pubB [::otr::data::encode PUBKEY $keyB] set ikeyidB [::otr::data::encode INT $keyidB] set MB [::sha2::hmac -bin -key $m1 $gxmpi$gympi$pubB$ikeyidB] if {![::otr::crypto::verify $MB $sigBMB $keyB]} { #puts "DSA signature in Reveal signature message is invalid" return [list $authstate $msgstate ""] } set authstate AUTHSTATE_NONE set msgstate MSGSTATE_ENCRYPTED set message [createSignatureMessage $version $cp $m1p $m2p \ $y $gx $keyA $keyidA \ -sinstance $rinstance \ -rinstance $sinstance] return [list $authstate $msgstate $message $keyB $gx $keyidB] } } } # ::otr::auth::parseRevealSignatureMessage -- # # Parse the reveal signature message (without version and packet type # which were extracted earlier). # # Arguments: # version The protocol version (2 or 3). # data The payload to parse. # # Result: # Tuple {r, eXB, hmac}. # # Side effects: # Error is raised if decoding is failed for some reason. proc ::otr::auth::parseRevealSignatureMessage {version data} { lassign [::otr::data::decode DATA $data] r data lassign [::otr::data::decode DATA $data] encr data lassign [::otr::data::decode MAC $data] hmac data list $r $encr $hmac } # ::otr::auth::createSignatureMessage -- # # Assemble the fourth OTR AKE message which Alice returns to Bob - the # signature one. # # Arguments: # version The protocol version (2 or 3). # cp AES key computed from the shared secret. # m1p MAC key computed from the shared secret. # m2p MAC key computed from the shared secret. # y The random value which is the part of shared secret. # gx The part of D-H shared secret. # keyA Long-term private key. # keyidA Serial number for the D-H key. # -sinstance num (only for version 3) The sender instance tag. # -rinstance num (only for version 3) The receiver instance tag. # # Result: # BASE64 encoded OTR packet with the message inside. # # Side effects: # None. proc ::otr::auth::createSignatureMessage {version cp m1p m2p y gx \ keyA keyidA args} { set sinstance 0x100 set rinstance 0 foreach {key val} $args { switch -- $key { -sinstance { set sinstance $val } -rinstance { set rinstance $val } } } set res "" append res [::otr::data::encode SHORT $version] append res [::otr::data::encode BYTE 0x12] if {$version > 2} { append res [::otr::data::encode INT $sinstance] append res [::otr::data::encode INT $rinstance] } set gy [::otr::crypto::DHGx $y] set gympi [::otr::data::encode MPI $gy] set gxmpi [::otr::data::encode MPI $gx] set pubA [::otr::data::encode PUBKEY $keyA] set ikeyidA [::otr::data::encode INT $keyidA] set MA [::sha2::hmac -bin -key $m1p $gympi$gxmpi$pubA$ikeyidA] set sigAMA [::otr::data::encode SIG [::otr::crypto::sign $MA $keyA]] set encr [::otr::crypto::aes $pubA$ikeyidA$sigAMA $cp 0] set encrfield [::otr::data::encode DATA $encr] append res $encrfield append res \ [::otr::data::encode MAC [::sha2::hmac -bin -key $m2p $encrfield]] ::otr::data::encodeMessage $res } # ::otr::auth::processSignatureMessage -- # # Pick the received Signature message without the protocol version, # packet type and instance tags, as well as the got earlier # peer's D-H public key, D-H private key, and create a suitable reply # message (which is always empty). # # Arguments: # version OTR protocol version. # authstate AKE authentication state. # msgstate Message state. # data Signature packet to process. # gy Peer's D-H public key. # x D-H private key which is to be used for decrypting, # verifying the hash and creating the answer. # -sinstance num (only for version 3) The sender instance tag. # -rinstance num (only for version 3) The receiver instance tag. # # Result: # Tuple {auhstate msgstate message} or {authstate msgstate message key # gy keyid} with new FSM state, the message to reply, and the peer's # DSA public key, and serial of the D-H public key to store if the # current FSM state is appropriate. # # Side effects: # None. proc ::otr::auth::processSignatureMessage {version authstate msgstate data gy x args} { set sinstance 0x100 set rinstance 0x100 foreach {key val} $args { switch -- $key { -sinstance { set sinstance $val } -rinstance { set rinstance $val } } } if {[catch {parseSignatureMessage $version $data} res]} { return [list $authstate $msgstate ""] } lassign $res encr hmac switch -- $authstate { AUTHSTATE_NONE - AUTHSTATE_AWAITING_DHKEY - AUTHSTATE_AWAITING_REVEALSIG { return [list $authstate $msgstate ""] } AUTHSTATE_AWAITING_SIG { lassign [::otr::crypto::AKEKeys $gy $x] ssid c cp m1 m2 m1p m2p set myhmac \ [::sha2::hmac -bin -key $m2p [::otr::data::encode DATA $encr]] if {[string range $myhmac 0 19] ne $hmac} { #puts "HMAC in Signature message is invalid" return [list $authstate $msgstate ""] } set decr [::otr::crypto::aes $encr $cp 0] if {[catch {parsePubkey $decr} res]} { # puts "DSA public key can't be deciphered" return [list $authstate $msgstate ""] } lassign $res keyA keyidA sigAMA set gympi [::otr::data::encode MPI $gy] set gxmpi [::otr::data::encode MPI [::otr::crypto::DHGx $x]] set pubA [::otr::data::encode PUBKEY $keyA] set ikeyidA [::otr::data::encode INT $keyidA] set MA [::sha2::hmac -bin -key $m1p $gympi$gxmpi$pubA$ikeyidA] if {![::otr::crypto::verify $MA $sigAMA $keyA]} { #puts "DSA signature in Signature message is invalid" return [list $authstate $msgstate ""] } set authstate AUTHSTATE_NONE set msgstate MSGSTATE_ENCRYPTED return [list $authstate $msgstate "" $keyA $keyidA] } } } # ::otr::auth::parseSignatureMessage -- # # Parse the signature message (without version and packet type # which were extracted earlier). # # Arguments: # version The protocol version (2 or 3). # data The payload to parse. # # Result: # Tuple {eXB, hmac}. # # Side effects: # Error is raised if decoding is failed for some reason. proc ::otr::auth::parseSignatureMessage {version data} { lassign [::otr::data::decode DATA $data] encr data lassign [::otr::data::decode MAC $data] hmac data list $encr $hmac } # ::otr::auth::parsePubkey -- # # Parse the pubkey, keyid, signature data block. # # Arguments: # data The data to parse. # # Result: # Tuple {pubkey, keyid, signature}. # # Side effects: # Error is raised if decoding is failed for some reason. proc ::otr::auth::parsePubkey {data} { lassign [::otr::data::decode PUBKEY $data] key data lassign [::otr::data::decode INT $data] keyid data lassign [::otr::data::decode SIG $data] sig list $key $keyid $sig } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/otr/tclotr/crypto.tcl000064400000000000000000000614651500237002100176640ustar00nobodynobody# crypto.tcl -- # # This file is a part of the Off-the-Record messaging protocol # implementation. It contains the OTR cryptography procedures. # # Copyright (c) 2014 Sergei Golovan # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAMER OF ALL WARRANTIES. package require Tcl 8.5- package require sha1 package require sha256 package require aes package require otr::data package provide otr::crypto 0.1 ############################################################################## namespace eval ::otr::crypto { # Useful constants variable Prime \ 0x[join {FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D 670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF} ""] variable G 2 variable RandomProvider if {![file readable /dev/urandom]} { if {[catch {package require twapi}]} { package require Memchan # Random channel from Memchan uses the ISAAC algorithm which is # supposedly cryptographically secure variable randomfd [::random] fconfigure $randomfd -translation binary -buffering none set RandomProvider memchan } else { set RandomProvider twapi } } else { set RandomProvider urandom } } ############################################################################## # # Diffie-Hellman key exchange auxiliary procedures # ::otr::crypto::DHGx -- # # Return the DIffie-Hellman public key. # # Arguments: # x Private key. # # Result: # D-H public key (G**x mod P). # # Side effects: # Modulus and generator are taken from global variables. proc ::otr::crypto::DHGx {x} { variable Prime variable G Power $Prime $G $x } # ::otr::crypto::DHCheck -- # # Check if the Diffie-Hellman public key is correct. # # Arguments: # gy Public key. # # Result: # 1 if gy is correct (1 < gy < P-1). # # Side effects: # Modulus is taken from a global variable. proc ::otr::crypto::DHCheck {gy} { variable Prime expr {$gy > 1 && $gy < $Prime-1} } # ::otr::crypto::DHSecret -- # # Return the common Diffie-Hellman secret. # # Arguments: # gy Public key. # x Private key. # # Result: # The D-H secret (gy**x mod P). # # Side effects: # Modulus is taken from a global variable. proc ::otr::crypto::DHSecret {gy x} { variable Prime Power $Prime $gy $x } # ::otr::crypto::AKEKeys -- # # Return the set of AKE keys. # # Arguments: # gy Public key. # x Private key. # # Result: # List of SSID and set of keys which are used in AKE. # # Side effects: # Modulus is taken from a global variable. proc ::otr::crypto::AKEKeys {gy x} { set s [DHSecret $gy $x] set secbytes [::otr::data::encode MPI $s] set ssid [string range [::sha2::sha256 -bin \x00$secbytes] 0 7] set ccp [::sha2::sha256 -bin \x01$secbytes] set c [string range $ccp 0 15] set cp [string range $ccp 16 31] set m1 [::sha2::sha256 -bin \x02$secbytes] set m2 [::sha2::sha256 -bin \x03$secbytes] set m1p [::sha2::sha256 -bin \x04$secbytes] set m2p [::sha2::sha256 -bin \x05$secbytes] set extrakey [::sha2::sha256 -bin \xff$secbytes] list $ssid $c $cp $m1 $m2 $m1p $m2p $extrakey } # ::otr::crypto::AESKeys -- # # Return the set of DES keys to encrypt/decrypt and hash/verify # data messages. # # Arguments: # gy Public key. # x Private key. # # Result: # List of keys which are used to exchange data messages. # # Side effects: # Modulus is taken from a global variable. proc ::otr::crypto::AESKeys {gy x} { set s [DHSecret $gy $x] set secbytes [::otr::data::encode MPI $s] set gx [DHGx $x] if {$gx > $gy} { # We're on the high end set sendbyte \x01 set recvbyte \x02 } else { # We're on the low end set sendbyte \x02 set recvbyte \x01 } set skey [string range [::sha1::sha1 -bin $sendbyte$secbytes] 0 15] set rkey [string range [::sha1::sha1 -bin $recvbyte$secbytes] 0 15] set smac [::sha1::sha1 -bin $skey] set rmac [::sha1::sha1 -bin $rkey] list $skey $smac $rkey $rmac } ############################################################################## # # AES128-CTR # ::otr::crypto::aes -- # # Encrypt or decrypt (these operations are the same) binary data using # AES128-CTR method. # # Arguments: # data Binary data to encrypt/decrypt. # key 128-bit binary key. # ctrtop 64-bit integer top counter. # ctrbot (optional, 0 by default) 64-bit integer bottom counter. # # Result: # Encrypted/decrypted binary data. # # Side effects: # None. proc ::otr::crypto::aes {data key ctrtop {ctrbot 0}} { set res "" set ctr [expr {$ctrtop*(2**64) + $ctrbot}] while {[string length $data] > 0} { # Make binary counter set binctr [Int2Octets $ctr 128] # Encrypt $binctr using $key set binectr [::aes::aes -mode ecb -dir encrypt -key $key $binctr] # XOR the data chunk with the encrypted counter set chunk [string range $data 0 15] set len [string length $chunk] set binectr [string range $binectr 0 [expr {$len-1}]] append res [Xor $binectr $chunk] set data [string range $data 16 end] incr ctr } return $res } # ::otr::crypto::Xor -- # # Return bitwize XOR between two binary strings of equal length. # # Arguments: # data1 Binary to XOR. # data2 Binary to XOR. # # Result: # Bitwise XOR of the supplied binaries or error if their lengths differ. # # Side effects: # None. proc ::otr::crypto::Xor {data1 data2} { set res "" binary scan $data1 cu* clist1 binary scan $data2 cu* clist2 foreach c1 $clist1 c2 $clist2 { append res [binary format cu [expr {$c1 ^ $c2}]] } return $res } ############################################################################## # # DSA signing and verifying # ::otr::crypto::DSAFingerprint -- # # Return the DSA public key fingerprint. # # Arguments: # key DSA public key {p q g y}. # # Result: # The binary SHA-1 hash of the binary representation of the key. # # Side effects: # None. proc ::otr::crypto::DSAFingerprint {key} { set bytes [::otr::data::encode PUBKEY $key] return [::sha1::sha1 -bin [string range $bytes 2 end]] } # ::otr::crypto::sign -- # # Sign binary data using the DSA algorithm. # # Arguments: # data Binary data to sign. # key DSA private key (list {p q g y x}). # -hash proc (optional, default is no hash) Hash function # (::sha1::sha1 or ::sha2::sha256 works) to apply to the # signed data. # -random num (optional, useful for testing only) Random number to # add to the signature. # # Result: # The DSA signature (list {r s}). # # Side effects: # The side effects of ::otr::crypto::random in case if there's no # -random or -hmac options. proc ::otr::crypto::sign {data key args} { lassign $key p q g y x set random 0 set h1 $data set hmac "" foreach {opt val} $args { switch -- $opt { -random { set random $val } -hash { set h1 [$val -bin $data] } -hmac { set hmac $val } } } set qlen [BitLength $q] set h [Bits2Int $h1] set r 0 set s 0 set k 0 while {$r == 0 || $s == 0} { if {$random == 0} { while {$k == 0} { set k [expr {[random [expr {$qlen+64}]] % ($q-1) + 1}] } } else { set k $random ; # For testing purposes only } set r [expr {[Power $p $g $k] % $q}] set s [Mult $q [Inverse $q $k] [expr {$h + $x*$r}]] } list $r $s } # ::otr::crypto::verify -- # # Verify binary data DSA signature. # # Arguments: # data Binary data. # sig DSA signature to verify. # key DSA public key (list {p q g y}). # -hash proc (optional, default is no hash) Hash function # (::sha1::sha1 or ::sha2::sha256 works) to apply to the # signed data. # # Result: # 1 if the signature is correct, 0 otherwise. # # Side effects: # None. proc ::otr::crypto::verify {data sig key args} { lassign $sig r s lassign $key p q g y if {$r <= 0 || $r >= $q || $s <= 0 || $s >= $q} { return 0 } set data1 $data foreach {opt val} $args { switch -- $opt { -hash { set data1 [$val -bin $data] } } } set hash [Bits2Int $data1] set w [Inverse $q $s] set u1 [Mult $q $hash $w] set u2 [Mult $q $r $w] set v0 [Mult $p [Power $p $g $u1] [Power $p $y $u2]] set v [expr {$v0 % $q}] expr {$v == $r} } # ::otr::crypto::BitLength -- # # Return the bit length of the given number x (minimum l such that # 2**l is greater than x). # # Arguments: # x Non-negative nteger. # # Result: # Bit length of x. # # Side effects: # None. proc ::otr::crypto::BitLength {x} { set len 0 while {$x >= 2**$len} { incr len } set len } # ::otr::crypto::Bits2Int -- # # Convert binary into an unsigned integer treating binary as a big # endian byte array. # # Arguments: # data Binary to convert. # len Number of leftmost bits to convert. If 0 then all bits # are to be converted. # # Result: # Arbitrary length integer which corresponds to the first $len bits of # the given binary. Bits are taken in big endian way. # # Side effects: # None. proc ::otr::crypto::Bits2Int {data {len 0}} { binary scan $data cu* clist set int [lindex $clist 0] set olen [expr {($len - 1) / 8}] foreach c [lrange $clist 1 end] { if {$olen == 0} break set int [expr {$int*256 + $c}] incr olen -1 } if {$len > 0} { set int [expr {$int & ((2**($len+1)) - 1)}] } set int } # ::otr::crypto::Int2Octests -- # # Convert integer to the sequence of octets of the given length (left # zero padded). # # Arguments: # int Non-negative integer. # len (optional, by default the hole x is converted into minimum # length binary) How many bits to convert (in fact the # number of bits would be 8*ceil(len/8). # # Result: # Binary which represents the given integer. # # Side effects: # None. proc ::otr::crypto::Int2Octets {int {len 0}} { if {$int == 0} { return \00 } set bin "" set olen [expr {($len - 1) / 8}] while {($len == 0 && $int > 0) || $olen >= 0} { set bin [binary format cu [expr {$int % 256}]]$bin set int [expr {$int / 256}] incr olen -1 } set bin } # ::otr::crypto::Bits2Octets -- # # Convert binary into another binary as described in RFC-6979 section # 2.3.4. # # Arguments: # data Binary to convert. # q Modulus. # # Result: # Binary. # # Side effects: # None. proc ::otr::crypto::Bits2Octets {data q} { set len [BitLength $q] set z1 [Bits2Int $data $len] set z2 [expr {$z1 % $q}] Int2Octets $z2 $len } ############################################################################## # # Generating random number # ::otr::crypto::random -- # # Return random number which is not shorter than the required number # of bits. # # Arguments: # bits Number of random bits to generate. # # Result: # The generated random number. # # Side effects: # Some entropy from /dev/urandom is used. proc ::otr::crypto::random {bits} { variable RandomProvider set bytes [expr {($bits + 7) / 8}] switch -- $RandomProvider { urandom { set fd [open /dev/urandom r] fconfigure $fd -translation binary -buffering none set rnd [read $fd $bytes] close $fd } memchan { variable randomfd set rnd [read $randomfd $bytes] } twapi { set rnd [twapi::random_bytes $bytes] } default { return -code error "Unknown random numbers provider" } } Bits2Int $rnd $bits } ############################################################################## # # Generating DSA private key (see FIPS 186-4) # ::otr::crypto::getFirstSeed -- # # Return the first seed for DSA parameters (p, q) generator (see # appendix A.1.2.1.1 in FIPS 186-4). # # Arguments: # N Length of q in bits. # seedlen Length of the returned first seed (seedlen >= N) # # Result: # Tuple {status, seedlen} where status is 0 in case of failure (in this # case the seedlen is undefined) and 1 in case of success. # # Side effects: # The random number of seeldlen bits is used. proc ::otr::crypto::getFirstSeed {N seedlen} { switch -- $N { 160 - 224 - 256 {} default { return {0} } } if {$seedlen < $N} { return {0} } set firstseed [random $seedlen] if {$firstseed < 2**($N-1)} { incr firstseed [expr {2**($N-1)}] } return [list 1 $firstseed] } # ::otr::crypto::genPrimes -- # # Return the DSA parameters (p, q) (see appendix A.1.2.1.2 in FIPS # 186-4). # # Arguments: # L Length of p in bits. # N Length of q in bits. # firstseed The first seed to be used (the length of firstseed is # to be not less then N). # # Result: # Tuple {status, p, q, pseed, qseed, pgen_counter, qgen_counter} where # status is 0 in case of failure (in this case all the other values # are unassigned) or 1 in case of success. p and q are the generated # DSA primes, pseed and qseed are the new seed values, pgen_counter and # qgen_counter show how many iterations were used. # # Side effects: # None. proc ::otr::crypto::genPrimes {L N firstseed} { switch -- $L/$N { 1024/160 - 2048/224 - 2048/256 - 3072/256 {} default { return {0} } } lassign [randomPrime $N $firstseed] \ qstatus q qseed qgen_counter if {!$qstatus} { return {0} } lassign [randomPrime [expr {[Ceil $L 2]+1}] $qseed] \ pstatus p0 pseed pgen_counter if {!$pstatus} { return {0} } set outlen 256 set iterations [expr {[Ceil $L $outlen]-1}] set old_counter $pgen_counter set x 0 set mult 1 for {set i 0} {$i <= $iterations} {incr i} { incr x [expr {[Bits2Int [::sha2::sha256 \ -bin [Int2Octets $pseed]]] * $mult}] incr pseed set mult [expr {$mult * 2**$outlen}] } set x [expr {2**($L-1) + ($x % (2**($L-1)))}] set t [Ceil $x [expr {2*$q*$p0}]] while {$pgen_counter <= 4*$L+$old_counter} { lassign [GenPrimesIteration $L $t $q $p0 $pseed $pgen_counter] \ status t p pseed pgen_counter if {$status} { return [list 1 $p $q $pseed $qseed $pgen_counter $qgen_counter] } } return {0} } # ::otr::crypto::genGenerator -- # # Return the DSA generator g (see appendix A.2.1 of FIPS 186-4). # # Arguments: # p DSA prime p. # q DSA prime q. # # Result: # The generator g of the DSA key. # # Side effects: # A random number of bitlength at least L is used. proc ::otr::crypto::genGenerator {p q} { set e [expr {($p-1)/$q}] set g 1 set l [BitLength $p] while {$g == 1} { set h [expr {2+([random $l] % ($p-3))}] set g [Power $p $h $e] } set g } # ::otr::crypto::genKeyPair -- # # Return the DSA private and public key pair for given parameters # p, q and g (see appendix B.1.1 of FIPS 186-4). # # Arguments: # p DSA prime p. # q DSA prime q. # g DSA generator g. # # Result: # Tuple {status, x, y} where status is 0 in case of failure (in this # case the x and y are unassigned), or 1 in case of success (in this # case x is a private key, y is a g^x mod p - public key. # # Side effects: # A random number of bitlength N+64 is used. proc ::otr::crypto::genKeyPair {p q g} { set L [BitLength $p] set N [BitLength $q] switch -- $L/$N { 1024/160 - 2048/224 - 2048/256 - 3072/256 {} default { return {0} } } set c [random [expr {$N+64}]] set x [expr {$c % ($q-1) + 1}] set y [Power $p $g $x] return [list 1 $x $y] } # ::otr::crypto::randomPrime -- # # Generate a prime number of a given bitlength using the Shawe-Taylor # algorithm (see Appendix C.6 from FIPS 186-4). # # Arguments: # length Bitlength of a number to generate. # input_seed The seed to be used for the generation. # # Result: # Tuple {status, prime, prime_seed, prime_gen_counter} where status is # 1 if the generation is successful and 0 otherwise. If status is 0 then # the other values aren't assigned. If status is 1 then prime is the # generated prime number, prime_seed is a new seed value, # prime_gen_counter shows hom many iterations were made. # # Side effects: # None. proc ::otr::crypto::randomPrime {length input_seed} { if {$length < 2} { return {0} } if {$length < 33} { set prime_seed $input_seed set prime_gen_counter 0 while {$prime_gen_counter <= 4*$length} { set c [Bits2Int \ [Xor [::sha2::sha256 -bin [Int2Octets $prime_seed]] \ [::sha2::sha256 \ -bin [Int2Octets [expr {$prime_seed+1}]]]]] set c [expr {2**($length-1) + ($c % (2**($length-1)))}] set c [expr {($c % 2 == 0)? $c+1 : $c}] incr prime_gen_counter incr prime_seed 2 if {[TestPrime $c]} { return [list 1 $c $prime_seed $prime_gen_counter] } } return {0} } else { lassign [randomPrime [Ceil $length 2] $input_seed] \ status c0 prime_seed prime_gen_counter if {!$status} { return {0} } set outlen 256 set iterations [expr {[Ceil $length $outlen]-1}] set old_counter $prime_gen_counter set x 0 set mult 1 for {set i 0} {$i <= $iterations} {incr i} { incr x [expr {[Bits2Int [::sha2::sha256 \ -bin [Int2Octets $prime_seed]]] * $mult}] incr prime_seed set mult [expr {$mult * 2**$outlen}] } set x [expr {2**($length-1) + ($x % (2**($length-1)))}] set t [Ceil $x [expr {2*$c0}]] while {$prime_gen_counter < 4*$length+$old_counter} { lassign [GenPrimesIteration \ $length $t 1 $c0 $prime_seed $prime_gen_counter] \ status t c prime_seed prime_gen_counter if {$status} { return [list 1 $c $prime_seed $prime_gen_counter] } } return {0} } } # ::otr::crypto::GenPrimesIteration -- # # Private procedure which implements a common iteration part for # [randomPrime] (steps 23-34 in appendix C.6) and [genPrimes] # (steps 11-22 in appendix A.1.2.1.2) routines (see FIPS 186-4). # # Arguments: # L Length of the generated prime p in bits. # t Candidate for a (p-1) factor. # q Number which p-1 is to be divisible by. # p0 Prime number which is to be a factor of (p-1). # pseed Seed. # pgen_counter Value of the global iteration counter. # # Result: # Tuple {status, t, p, pseed, pgen_counter} where status equals 0 # if iterations are to be continued (in this case p is not prime # and has to be ignored), or 1 in case if p is prime. t is the next # auxiliary factor of p-1, pseed is nes seed, pgen_counter is the # next counter value. # # Side effects: # None. proc ::otr::crypto::GenPrimesIteration {L t q p0 pseed pgen_counter} { if {2*$t*$q*$p0+1 > 2**$L} { set t [Ceil [expr {2**($L-1)}] [expr {2*$q*$p0}]] } set p [expr {2*$t*$q*$p0+1}] incr pgen_counter set outlen 256 set iterations [expr {[Ceil $L $outlen]-1}] set a 0 set mult 1 for {set i 0} {$i <= $iterations} {incr i} { incr a [expr {[Bits2Int [::sha2::sha256 \ -bin [Int2Octets $pseed]]] * $mult}] incr pseed set mult [expr {$mult * 2**$outlen}] } set a [expr {2+($a % ($p-3))}] set z [Power $p $a [expr {2*$t*$q}]] lassign [EGCD $p [expr {$z-1}]] xx yy set pow [Power $p $z $p0] if {$xx*$p + $yy*($z-1) == 1 && $pow == 1} { return [list 1 $t $p $pseed $pgen_counter] } incr t return [list 0 $t $p $pseed $pgen_counter] } # ::otr::crypto::TestPrime -- # Private procedure which tests the given positive integer number for # primality. It does that by division on 2 and all odd numbers up to # the square root of the tested number trials, so it's supposed to # work only with sufficiently short numbers (32 bit). # # Arguments: # n Positive integer to test. # # Result: # 1 if it is a prime number, 0 otherwise. # # Side effects: # None. proc ::otr::crypto::TestPrime {n} { if {$n < 2} { return 0 } if {$n > 2 && $n % 2 == 0} { return 0 } for {set k 3} {$k*$k <= $n} {incr k 2} { if {$n % $k == 0} { return 0 } } return 1 } # ::otr::crypto::Ceil -- # # Private procedure which computes ceiling of the ratio of two positive # integers. # # Arguments: # k Positive integer umerator. # n Positive integer denominator. # # Result: # ceil(k/n). # # Side effects: # None. proc ::otr::crypto::Ceil {k n} { expr {($k+$n-1)/$n} } ############################################################################## # # Useful procedures implementing arithmetics modulo some prime number. # ::otr::crypto::Mult -- # # Multiplication modulo some positive integer. # # Arguments: # prime Modulus (usually it's a prime number). # x The first multiplier. # y The second multiplier. # # Result: # x*y mod p. # # Side effects: # None. proc ::otr::crypto::Mult {prime x y} { expr {($x * $y) % $prime} } # ::otr::crypto::Inverse -- # # Inverse modulo some prime number. It's found using the Euclid GCD # algorithm. # # Arguments: # prime Modulus (must be a prime number, or result will not be # the inversion. # x Number to inverse. # # Result: # Number y such that x*y mod p = 1. # # Side effects: # None. proc ::otr::crypto::Inverse {prime x} { lassign [EGCD $prime $x] x1 y1 expr {$y1 % $prime} } # ::otr::crypto::Power -- # # Power modulo some integer. It's implemented using the exponentiation # by squaring algorithm. # # Arguments: # prime Modulus (usually it's a prime number). # x Exponentiation base. # n Exponentiation index. # # Result: # x**n mod p. # # Side effects: # None. proc ::otr::crypto::Power {prime x n} { set y 1 while {$n > 0} { if {$n % 2 == 0} { set n [expr {$n / 2}] set x [Mult $prime $x $x] } else { incr n -1 set y [Mult $prime $y $x] } } return $y } # ::otr::crypto::EGCD -- # # Perform the Euclid algorithm to find the Greatest Common Divisor. # # Arguments: # a Positive integer. # b Positive integer. # # Result: # Tuple {x y} where x*a+y*b = GCD(a,b). # # Side effects: # None. proc ::otr::crypto::EGCD {a b} { set r [expr {$a % $b}] if {$r == 0} { return {0 1} } else { lassign [EGCD $b $r] x y return [list $y [expr {$x - $y * ($a / $b)}]] } } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/otr/tclotr/data.tcl000064400000000000000000000364771500237002100172620ustar00nobodynobody# data.tcl -- # # This file is a part of the Off-the-Record messaging protocol # implementation. It contains the decoding/encoding procedures. # # Copyright (c) 2014 Sergei Golovan # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAMER OF ALL WARRANTIES. package require base64 package provide otr::data 0.1 ############################################################################## namespace eval ::otr::data { variable WSHeader " \t \t\t\t\t \t \t \t " variable WSv1 " \t \t \t " variable WSv2 " \t\t \t " variable WSv3 " \t\t \t\t" } # ::otr::data::Bin2Int -- # # Convert binary into an unsigned integer treating binary as a big # endian byte array. # # Arguments: # data Binary to convert. # # Result: # Arbitrary length integer which corresponds to the given binary. # # Side effects: # None. proc ::otr::data::Bin2Int {data} { binary scan $data cu* clist set int [lindex $clist 0] foreach c [lrange $clist 1 end] { set int [expr {$int*256 + $c}] } set int } # ::otr::data::encodeMessage -- # # Encode binary message using BASE64 and add ?OTR: prefix and . suffix. # # Arguments: # data Binary OTR message. # # Result: # BASE64 encoded message ready for transmission. # # Side effects: # None. proc ::otr::data::encodeMessage {data} { return ?OTR:[::base64::encode -maxlen 0 $data]. } # ::otr::data::binaryMessage -- # # Decode BASE64 message with ?OTR prefix and parse out the protocol # version, the packet type and for version 3 packets the sender and # receiver's instances. # # Arguments: # data Received or assembled from the fragments OTR BASE64 # encoded message. # # Result: # Tuple {version type binary ?sinstance rinstance?} where version is # the OTR version, type is the packet type, sinstance is a sender's # instance, rinstance is a receiver's instance, and binary is the # rest of the binary message. # # Side effects: # Error is raised if the message doesn't start with ?OTR: or if the # BASE64 decoded message is too short to contain the protocol version, # message type and sender and recipient instance tags (for version 3). proc ::otr::data::binaryMessage {data} { if {![scan $data {?OTR:%[^.].} message] == 1} { return -code error "Message doesn't contain OTR marker" } set binary [::base64::decode $message] lassign [decode SHORT $binary] version binary lassign [decode BYTE $binary] type binary if {$version >= 3} { lassign [decode INT $binary] sinstance binary lassign [decode INT $binary] rinstance binary return [list $version $type $binary $sinstance $rinstance] } else { return [list $version $type $binary] } } # ::otr::data::binaryMessageFragment -- # # Decode the OTR message fragment and return its piece number, the total # number of pieces, the message fragment and the sender and receiver's # instance tags for version 3 packages. # # Arguments: # data Received OTR message fragment. # # Result: # Tuple {version part numpatrs message ?sinstance rinstance?} where # version is the protocol version, part is a piece number, numparts is a # total number of parts, message is an OTR message fragment, sinstance # is a sender's sinstance tag, rinstance is a receiver's instance tag. # # Side effects: # Error is raised if this data is not an OTR message fragment. proc ::otr::data::binaryMessageFragment {data} { if {[scan $data {?OTR|%x|%x,%u,%u,%[^,],} \ sinstance rinstance part numparts message] == 5} { return [list 3 $part $numparts $message $sinstance $rinstance] } elseif {[scan $data {?OTR,%u,%u,%[^,],} part numparts message] == 3} { return [list 2 $part $numparts $message] } else { return -code error "Message doesn't contain OTR part marker" } } # ::otr::data::queryMessage -- # # Return the OTR query message. # # Arguments: # policy The correspondent policy list. # # Result: # The OTR query message which requests an OTR conversation with # protocol versions including 2 if ALLOW_V2 belongs to the policy # and 3 id ALLOW_V3 belongs to the policy. # # Side effects: # Error is raised if the policy contains ALLOW_V1. proc ::otr::data::queryMessage {policy} { set res ?OTR if {"ALLOW_V1" in $policy} { return -code error "OTR version 1 is not supported" } append res v if {"ALLOW_V2" in $policy} { append res 2 } if {"ALLOW_V3" in $policy} { append res 3 } return $res? } # ::otr::data::findQueryMessage -- # # Parse the OTR query message if it is given. # # Arguments: # message Message to parse. # # Result: # OTR versions list from the message if it is the OTR query message, # or error if it is not. # # Side effects: # Error is raised if the message is not an OTR query message. proc ::otr::data::findQueryMessage {message} { if {![regexp {^\?OTR(\??)(?:v([^?]*))?\?} $message -> v1 v2]} { # BUG: ?OTR? shows no support for version 1, though it doesn't # matter because we don't support OTR version 1 return -code error "Message is not an OTR query message" } set res {} if {$v1 eq "?"} { lappend res 1 } set res [concat $res [split $v2 ""]] return [lsort -unique $res] } # ::otr::data::whitespaceTag -- # # Return the OTR whitespace tag corresponding to a given policy. # # Arguments: # policy The correspondent policy list. # # Result: # The OTR whitespace tag which indicates the willing to start an OTR # conversation with protocol versions 2 if ALLOW_V2 belongs to the # policy and 3 if ALLOW_V3 belongs to the policy. # # Side effects: # Error is raised if ALLOW_V1 belongs to the policy. proc ::otr::data::whitespaceTag {policy} { variable WSHeader variable WSv2 variable WSv3 set res $WSHeader if {"ALLOW_V1" in $policy} { return -code error "OTR version 1 is not supported" } if {"ALLOW_V2" in $policy} { append res $WSv2 } if {"ALLOW_V3" in $policy} { append res $WSv3 } set res } # ::otr::data::findWhitespaceTag -- # # Find the OTR whitespace tag in a plaintext message. # # Arguments: # message Message to search. # # Result: # OTR versions list from the message if the whitespace tag is found, # or error if it is not. # # Side effects: # Error is raised if the message doesn't contain the whitespace tag. proc ::otr::data::findWhitespaceTag {message} { variable WSHeader variable WSv1 variable WSv2 variable WSv3 set idx [string first $WSHeader $message] if {$idx < 0} { return -code error "There's no whitespace tag in the message" } set res {} set str1 [string range $message [expr {$idx+16}] [expr {$idx+23}]] set str2 [string range $message [expr {$idx+24}] [expr {$idx+31}]] set str3 [string range $message [expr {$idx+32}] [expr {$idx+39}]] if {$str1 eq $WSv1 || $str2 eq $WSv1 || $str3 eq $WSv1} { lappend res 1 } if {$str1 eq $WSv2 || $str2 eq $WSv2 || $str3 eq $WSv2} { lappend res 2 } if {$str1 eq $WSv3 || $str2 eq $WSv3 || $str3 eq $WSv3} { lappend res 3 } return $res } # ::otr::data::removeWhitespaceTag -- # # Remove the OTR whitespace tag from a plaintext message. # # Arguments: # message Message to search. # # Result: # The given message without the OTR whitespace tag if was any. # # Side effects: # None. proc ::otr::data::removeWhitespaceTag {message} { variable WSHeader variable WSv1 variable WSv2 variable WSv3 string map [list $WSHeader "" $WSv1 "" $WSv2 "" $WSv3 ""] $message } # ::otr::data::errorMessage -- # # Create an OTR error message. # # Arguments: # error The error text. # # Result: # The OTR error message. # # Side effects: # None. proc ::otr::data::errorMessage {error} { return "?OTR Error: $error" } # ::otr::data::findErrorMessage -- # # Check if a given message is an OTR error message and return the error # text. # # Arguments: # message Message to check. # # Result: # The error text or error if the message is not an OTR error message. # # Side effects: # Error is raised if the message is not an OTR error message. proc ::otr::data::findErrorMessage {message} { if {[regexp {^\?OTR Error:\s*(.*)} $message -> error]} { return $error } else { return -code error "Message is not an OTR error message" } } # ::otr::data::encode -- # # Encode given data to the binary format suitable for inclusion into # an OTR binary message. # # Arguments: # type Data type (BYTE, SHORT, INT, MPI, DATA, CTR, MAC, PUBKEY, # SIG). # data Data to encode (for BYTE, SHORT, INT, MPI, CTR it's a # number, for DATA, MAC it's a binary string, for PUBKEY # it's a list of 4 numbers {p q g y}, for SIG it's a list # of 2 numbers {r s}). # # Result: # Binary string. # # Side effects: # None. proc ::otr::data::encode {type data} { switch -- $type { BYTE { return [binary format cu $data] } SHORT { return [binary format Su $data] } INT { return [binary format Iu $data] } MPI { if {$data == 0} { return [binary format Iucu 1 0] } set len 0 set res "" while {$data > 0} { incr len set res [binary format cu [expr {$data % 256}]]$res set data [expr {$data / 256}] } return [binary format Iu $len]$res } DATA { return [binary format Iu [string length $data]]$data } CTR { return [binary format Wu $data] } MAC { return [string range $data 0 19] } PUBKEY { lassign $data p q g y set res [encode SHORT 0] ; # DSA key only append res [encode MPI $p] append res [encode MPI $q] append res [encode MPI $g] append res [encode MPI $y] return $res } SIG { lassign $data r s set res [binary format IuIuIuIuIu \ [expr {$r / (256**16)}] \ [expr {($r / (256**12)) % (256**4)}] \ [expr {($r / (256**8)) % (256**4)}] \ [expr {($r / (256**4)) % (256**4)}] \ [expr {$r % (256**4)}]] append res [binary format IuIuIuIuIu \ [expr {$s / (256**16)}] \ [expr {($s / (256**12)) % (256**4)}] \ [expr {($s / (256**8)) % (256**4)}] \ [expr {($s / (256**4)) % (256**4)}] \ [expr {$s % (256**4)}]] return $res } } } # ::otr::data::decode -- # # Decode a portion of given binary string and return the decoded # value and the rest of the string. # # Arguments: # type Type of the decoded chunk. # data Binary string to decode. # # Result: # List of two items: the decoded data chunk (the same as is given to # ::otr::data::encode proc) and the rest of the input data. # # Side effects: # None. proc ::otr::data::decode {type data} { switch -- $type { BYTE { if {[binary scan $data cu num]} { set res $num set data [string range $data 1 end] } else { return -code error "Invalid BYTE" } } SHORT { if {[binary scan $data Su num]} { set res $num set data [string range $data 2 end] } else { return -code error "Invalid SHORT" } } INT { if {[binary scan $data Iu num]} { set res $num set data [string range $data 4 end] } else { return -code error "Invalid INT" } } MPI { if {[binary scan $data Iu len]} { set res [Bin2Int [string range $data 4 [expr {$len+3}]]] set data [string range $data [expr {$len+4}] end] } else { return -code error "Invalid MPI" } } DATA { if {[binary scan $data Iu len]} { set res [string range $data 4 [expr {$len+3}]] set data [string range $data [expr {$len+4}] end] } else { return -code error "Invalid DATA" } } CTR { if {[binary scan $data Wu num]} { set res $num set data [string range $data 8 end] } else { return -code error "Invalid CTR" } } MAC { set res [string range $data 0 19] set data [string range $data 20 end] } PUBKEY { lassign [decode SHORT $data] keytype data if {$keytype != 0} { return -code error "Only DSA keys are supported" } lassign [decode MPI $data] p data lassign [decode MPI $data] q data lassign [decode MPI $data] g data lassign [decode MPI $data] y data set res [list $p $q $g $y] } SIG { set r [Bin2Int [string range $data 0 19]] set s [Bin2Int [string range $data 20 39]] set res [list $r $s] set data [string range $data 40 end] } } list $res $data } # ::otr::data::encodeTLV -- # # Encode a TLV record for an OTR data message. # # Arguments: # type TLV type (non-negative integer). # data TLV payload (binary string). # # Result: # Binary string with encoded TLV. # # Side effects: # None. proc ::otr::data::encodeTLV {type data} { return [encode SHORT $type][encode SHORT [string length $data]]$data } # ::otr::data::decodeTLV -- # # Decode a TLV record from an OTR data message. # # Arguments: # data Binary string with encoded TLV in it. # # Result: # Tuple {type, payload, rest} where type is a TLV type, payload is a # TLV payload, and rest is the rest of the given data. # # Side effects: # Error is raised if decoding fails. proc ::otr::data::decodeTLV {data} { lassign [decode SHORT $data] type data lassign [decode SHORT $data] length data list $type [string range $data 0 [expr {$length-1}]] \ [string range $data $length end] } # ::otr::data::Bin2Hex -- # # Convert binary string to hex representation. Useful for debugging. # # Arguments: # data Binary data to print. # # Result: # Hexadecimal string. # # Side effects: # None. proc ::otr::data::Bin2Hex {data} { binary scan $data H* hex set hex } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/otr/tclotr/key.tcl000064400000000000000000000111401500237002100171150ustar00nobodynobody# key.tcl -- # # This file is a part of the Off-the-Record messaging protocol # implementation. It contains the private DSA key encoding/decoding # procedures. # # Copyright (c) 2014 Sergei Golovan # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAMER OF ALL WARRANTIES. package require base64 package require asn package require math::bignum package require otr::crypto package provide otr::key 0.1 ############################################################################## namespace eval ::otr::key {} # ::otr::key::encodePEM -- # # Encode the given DSA private key into PEM format. # # Arguments: # key DSA private key {p, q, g, y, x}. # # Result: # Key in PEM format. # # Side effects: # None. proc ::otr::key::encodePEM {key} { lassign $key p q g y x set ev [::asn::asnInteger 0] set ep [::asn::asnBigInteger [::math::bignum::fromstr $p]] set eq [::asn::asnBigInteger [::math::bignum::fromstr $q]] set eg [::asn::asnBigInteger [::math::bignum::fromstr $g]] set ey [::asn::asnBigInteger [::math::bignum::fromstr $y]] set ex [::asn::asnBigInteger [::math::bignum::fromstr $x]] set seq [::asn::asnSequence $ev $ep $eq $eg $ey $ex] format \ "-----BEGIN DSA PRIVATE KEY-----\n%s\n-----END DSA PRIVATE KEY-----" \ [::base64::encode -maxlen 64 $seq] } # ::otr::key::decodePEM -- # # Decode the diven DSA private key from PEM format. # # Arguments: # data PEM encoded DSA private key. # # Result: # DSA private key {p, q, g, y, x}. # # Side effects: # Error is raised if decoding is failed. proc ::otr::key::decodePEM {data} { if {![regexp -- \ {-----BEGIN DSA PRIVATE KEY-----\n(.*)\n-----END DSA PRIVATE KEY-----} \ $data -> base64]} { return -code error "Incorrect DSA private key PEM data" } set binary [::base64::decode $base64] ::asn::asnGetSequence binary sequence ::asn::asnGetInteger sequence version if {$version != 0} { return -code error "Unsupported DSA private key PEM version" } ::asn::asnGetBigInteger sequence bp set p [::math::bignum::tostr $bp] ::asn::asnGetBigInteger sequence bq set q [::math::bignum::tostr $bq] ::asn::asnGetBigInteger sequence bg set g [::math::bignum::tostr $bg] ::asn::asnGetBigInteger sequence by set y [::math::bignum::tostr $by] ::asn::asnGetBigInteger sequence bx set x [::math::bignum::tostr $bx] if {[::otr::crypto::BitLength $p] != 1024 && [::otr::crypto::BitLength $q] != 160} { return -code error \ "Unsupported DSA private key length, must be 1024 bit" } list $p $q $g $y $x } # ::otr::key::readPEM -- # # Read and decode DSA private key from a file in PEM format. # # Arguments: # filename Filename with the key to read. # # Result: # DSA private key {p, q, g, y, x}. # # Side effects: # Error is raised if file can't be read or decoding is failed. proc ::otr::key::readPEM {filename} { set fd [open $filename] set data [read $fd] close $fd decodePEM $data } # ::otr::key::writePEM -- # # Encode DSA private key to PEM format and write it to a file. # # Arguments: # key DSA private key {p, q, g, y, x}. # filename Filename to write. # Result: # Empty string. # # Side effects: # Error may be raised if the file can't be written. proc ::otr::key::writePEM {key filename} { set fd [open $filename wb] set data [encodePEM $key] puts $fd $data close $fd } # ::otr::key::generate -- # # Generate a new DSA private key. # # Arguments: # L Length of p in bits. # N Length of q in bits. # # Result: # DSA private key {p, q, g, y, x}. # # Side effects: # Several random numbers are generated, so some entropy is used # by PRNG. proc ::otr::key::generate {L N} { set status 0 while {!$status} { # Generate first seed set fstatus 0 while {!$fstatus} { lassign [::otr::crypto::getFirstSeed $N $N] \ fstatus firstseed } # Generate p and q lassign [::otr::crypto::genPrimes $L $N $firstseed] \ status p q pseed qseed pgen_counter qgen_counter } # Generate g set g [::otr::crypto::genGenerator $p $q] # Generate x y set kstatus 0 while {!$kstatus} { lassign [::otr::crypto::genKeyPair $p $q $g] kstatus x y } list $p $q $g $y $x } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/otr/tclotr/license.terms000064400000000000000000000024301500237002100203210ustar00nobodynobodyCopyright (c) 2014 Sergei Golovan All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. tkabber-plugins/otr/tclotr/message.tcl000064400000000000000000000435661500237002100177720ustar00nobodynobody# message.tcl -- # # This file is a part of the Off-the-Record messaging protocol # implementation. It contains the OTR Data packets serializing and # deserializing procedures. # # Copyright (c) 2014 Sergei Golovan # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAMER OF ALL WARRANTIES. package require sha1 package require otr::data package require otr::crypto package require otr::smp package provide otr::message 0.1 ############################################################################## namespace eval ::otr::message { variable Flags array set Flags {IGNORE_UNREADABLE 0x01} } # ::otr::message::createDataMessage -- # # Assemble the OTR data message, the only message type which is to be # sent after AKE succeedes. # # Arguments: # version Protocol version (2 or 3). # flags List of message flags (currently either {} or # {IGNORE_UNREADABLE}). # skeyid Sender D-H key serial ID (for x1). # rkeyid Recipient D-H key serial ID (for gy). # x1 Current D-H private key. # x2 Next D-H private key. # gy Peer's current D-H public key. # ctrtop Top 64 bit of the counter for AES128-CTR cipher. # humanreadable Human readable message. # tlvlist List of even number of items, integer TLV types and # their binary payloads. # -sinstance num (only for version 3) Sender instance tag. # -rinstance num (only for version 3) Receiver instance tag. # # Result: # BASE64 encoded OTR packet with the data message inside. # # Side effects: # None. proc ::otr::message::createDataMessage {version flags skeyid rkeyid skey smac x ctrtop humanreadable tlvlist oldmackeys args} { variable Flags set sinstance 0x100 set rinstance 0 foreach {key val} $args { switch -- $key { -sinstance { set sinstance $val } -rinstance { set rinstance $val } } } set res "" append res [::otr::data::encode SHORT $version] append res [::otr::data::encode BYTE 0x03] if {$version > 2} { append res [::otr::data::encode INT $sinstance] append res [::otr::data::encode INT $rinstance] } set binflags 0 foreach f $flags { if {[info exists Flags($f)]} { set binflags [expr {$binflags | $Flags($f)}] } } append res [::otr::data::encode BYTE $binflags] append res [::otr::data::encode INT $skeyid] append res [::otr::data::encode INT $rkeyid] set gx [::otr::crypto::DHGx $x] append res [::otr::data::encode MPI $gx] append res [::otr::data::encode CTR $ctrtop] set plaintext [createDataMessagePlaintext $humanreadable $tlvlist] set cryptotext [::otr::crypto::aes $plaintext $skey $ctrtop] append res [::otr::data::encode DATA $cryptotext] set hmac [::sha1::hmac -bin -key $smac $res] append res [::otr::data::encode MAC $hmac] append res [::otr::data::encode DATA [join $oldmackeys ""]] ::otr::data::encodeMessage $res } # ::otr::message::processDataMessage -- # # Process received OTR data message. Check its validity, decode and # process the TLVs if any. # # Arguments: # version Protocol version. # msgstate OTR message state. # smpstate OTR SMP state. # data Unparsed yet message data (encrypted text, HMAC and # old keys for revelation). # flags Message flags. # skeyid Sender's (peer's) key serial ID. # rkeyid Receiver's (your) key serial ID. # gy Next sender's public key. # ctrtop Top 8 bytes of AES counter. # rkey Receiver's key for decrypting. # rmac Receiver's key for verification. # -smpcommand cmd Callback to call when some SMP state data are to be # stored or retrieved. # -sinstance tag The sender's instance tag (for version 3) # -rinstance tag The receiver's instance tag (for version 3) # # Result: # Serialized array with the following fields (not all of them may be # present): info - info message to show to theh user, replyerr - # error message to reply, debug - debug message, message - the message # body, msgstate - new message state, smpstate - new smp state, # smpprogress - the progress of SMP procedure, secret - ask user the # SMP secret, question - show user the SMP question, reply - send # the given data message. # # Side effects: # SMP data may be stored or retrieved via callback. proc ::otr::message::processDataMessage {version msgstate smpstate data flags skeyid rkeyid gy ctrtop rkey rmac args} { variable Flags set sinstance 0x100 set rinstance 0x100 foreach {key val} $args { switch -- $key { -smpcommand { set smpcommand $val } -sinstance { set sinstance $val } -rinstance { set rinstance $val } } } if {![info exists smpcommand]} { return -code error "Option -smpcommand is mandatory" } if {"IGNORE_UNREADABLE" in $flags} { set err {} } else { set err [list info "Encrypted message can't be deciphered" \ replyerr [list [::otr::data::errorMessage \ "Encrypted message can't be deciphered"]]] } if {[catch {parseDataMessage $data} res]} { return [linsert $err 0 debug "Parsing data message failed: $res"] } lassign $res cryptotext hmac oldmackeys # Reassemble the message and verify its hash set msg "" append msg [::otr::data::encode SHORT $version] append msg [::otr::data::encode BYTE 0x03] if {$version > 2} { append msg [::otr::data::encode INT $sinstance] append msg [::otr::data::encode INT $rinstance] } set binflags 0 foreach f $flags { if {[info exists Flags($f)]} { set binflags [expr {$binflags | $Flags($f)}] } } append msg [::otr::data::encode BYTE $binflags] append msg [::otr::data::encode INT $skeyid] append msg [::otr::data::encode INT $rkeyid] append msg [::otr::data::encode MPI $gy] append msg [::otr::data::encode CTR $ctrtop] append msg [::otr::data::encode DATA $cryptotext] set myhmac [::sha1::hmac -bin -key $rmac $msg] if {$myhmac ne $hmac} { return [linsert $err 0 debug "Data message hash verification failed"] } # Decrypt the payload and parse it set plaintext [::otr::crypto::aes $cryptotext $rkey $ctrtop] if {[catch {parseDataMessagePlaintext $plaintext} res]} { return [linsert $err 0 debug \ "Data message plaintext decoding failed: $res"] } lassign $res message tlvlist if {$message eq ""} { set msg {} } else { set msg [list message $message] } # Store the extra symmetric key usage info if it's present foreach {type value} $tlvlist { switch -- $type { 8 { # Extra symmetric key # TODO } } } # Finish the OTR conversation if the peer asked to foreach {type value} $tlvlist { switch -- $type { 1 { # Disconnected # There's no point to continue SMP if any in progress set msgstate MSGSTATE_FINISHED set smpstate SMPSTATE_EXPECT1 {*}$smpcommand clear return [list msgstate $msgstate \ smpstate $smpstate \ smpprogress SMP_ABORT \ {*}$msg] } } } # Consider only the first SMP TLV, ignore the rest foreach {type value} $tlvlist { switch -- $type { 0 { # Padding } 2 { # SMP message 1 # Don't process it immediately, just store and go # after the user will supply the shared secret {*}$smpcommand set data1 $value return [list secret ""] } 3 { # SMP message 2 set x [{*}$smpcommand get x] set a2 [{*}$smpcommand get a2] set a3 [{*}$smpcommand get a3] lassign [::otr::smp::processSMPMessage2 \ $smpstate $value $x $a2 $a3] \ smpstate tlv payload g3b PaPb QaQb Ra if {$tlv == 6} { {*}$smpcommand clear set answer SMP_CHEATING } else { {*}$smpcommand set g3b $g3b {*}$smpcommand set PaPb $PaPb {*}$smpcommand set QaQb $QaQb {*}$smpcommand set Ra $Ra set answer SMP_PROGRESS } return [list msgstate $msgstate \ smpstate $smpstate \ smpprogress $answer \ reply [list "" [list $tlv $payload]] \ {*}$msg] } 4 { # SMP message 3 set g3a [{*}$smpcommand get g3a] set g2 [{*}$smpcommand get g2] set g3 [{*}$smpcommand get g3] set b3 [{*}$smpcommand get b3] set Pb [{*}$smpcommand get Pb] set Qb [{*}$smpcommand get Qb] lassign [::otr::smp::processSMPMessage3 \ $smpstate $value $g3a $g2 $g3 $b3 $Pb $Qb] \ smpstate tlv payload res if {$tlv == 6} { {*}$smpcommand clear set answer SMP_CHEATING } else { if {$res} { set answer SMP_SUCCESS } else { set answer SMP_FAILURE } } return [list msgstate $msgstate \ smpstate $smpstate \ smpprogress $answer \ reply [list "" [list $tlv $payload]] \ {*}$msg] } 5 { # SMP message 4 set a3 [{*}$smpcommand get a3] set g3b [{*}$smpcommand get g3b] set PaPb [{*}$smpcommand get PaPb] set QaQb [{*}$smpcommand get QaQb] set Ra [{*}$smpcommand get Ra] lassign [::otr::smp::processSMPMessage4 \ $smpstate $value $a3 $g3b $PaPb $QaQb $Ra] \ smpstate tlv payload res {*}$smpcommand clear if {$tlv == 6} { set answer SMP_CHEATING set tlvp [list $tlv $payload] } else { if {$res} { set answer SMP_SUCCESS } else { set answer SMP_FAILURE } set tlvp {} } return [list msgstate $msgstate \ smpstate $smpstate \ smpprogress $answer \ reply [list "" $tlvp] \ {*}$msg] } 6 { # SMP abort message set smpstate SMPSTATE_EXPECT1 {*}$smpcommand clear return [list msgstate $msgstate \ smpstate $smpstate \ smpprogress SMP_ABORT \ {*}$msg] } 7 { # SMP message 1Q # Don't process it immediately, just store and go # after the user will supply the shared secret set idx [string first \x00 $value] if {$idx < 0} { set smpstate SMPSTATE_EXPECT1 {*}$smpcommand clear return [list msgstate $msgstate \ smpstate $smpstate \ smpprogress SMP_CHEATING \ reply {"" {6 ""}} \ {*}$msg] } set question [encoding convertfrom utf-8 \ [string range $value 0 [expr {$idx-1}]]] set value [string range $value [expr {$idx+1}] end] {*}$smpcommand set data1 $value return [list question $question] } } } return [list msgstate $msgstate \ smpstate $smpstate \ {*}$msg] } # ::otr::message::parseDataMessage -- # # Parse the OTR data message (without version, packet type, sender # and receiver instance tags, flags and sender and receiver keyids # which were extracted earlier). # # Arguments: # data Payload to parse. # # Result: # Tuple {cryptotext, hmac, oldmackeys} where cryptotext is the # encrypted message body (possibly with TLV attached), hmac is # a message HMAC for verifiction, and oldmackeys is a set of old # receiver's MAC keys for revelation. # # Side effects: # Error is raised if decoding is failed for some reason. proc ::otr::message::parseDataMessage {data} { variable Flags lassign [::otr::data::decode DATA $data] cryptotext data lassign [::otr::data::decode MAC $data] hmac data lassign [::otr::data::decode DATA $data] oldmackeys list $cryptotext $hmac $oldmackeys } # ::otr::message::getDataMessageKeyids -- # # Return message flags, D-H key serial IDs, the peer's next public key, # counter, encoded in the data message (with stripped out protocol # version, message type, sender and receiver instance tags). # # Arguments: # data Payload to parse. # # Result: # Tuple {flags, skeyid, rkeyid, gy, ctrtop, data} with the message # flags, sender and recipient key serials, peer's public key, the top # 8 bytes of the AES counter, and rest of the message, or tuple # {{}, 0, 0, 0, 0, ""} if decoding fails. # # Side effects: # None. proc ::otr::message::getDataMessageKeyids {data} { variable Flags if {![catch { lassign [::otr::data::decode BYTE $data] binflags data set flags {} foreach f [array names Flags] { if {[expr {$binflags & $Flags($f)}]} { lappend flags $f } } lassign [::otr::data::decode INT $data] skeyid data lassign [::otr::data::decode INT $data] rkeyid data lassign [::otr::data::decode MPI $data] gy data lassign [::otr::data::decode CTR $data] ctrtop data list $flags $skeyid $rkeyid $gy $ctrtop $data } res]} { return $res } else { return {{} 0 0 0 0 ""} } } # ::otr::message::createDataMessagePlaintext -- # # Assemble the plaintext part of OTR data message. # # Arguments: # humanreadable Human readable part (message body). # tlvlist List with an even items number with TLV types # and payloads. # # Result: # Encoded plaintext part of OTR data message. # # Side effects: # None. proc ::otr::message::createDataMessagePlaintext {humanreadable tlvlist} { set res [encoding convertto utf-8 [escapeHTML $humanreadable]] if {[string first \x00 $res] >= 0} { return -code error "Zero byte in the human readable message part" } if {[llength $tlvlist] > 0} { append res \x00 } foreach {type data} $tlvlist { append res [::otr::data::encodeTLV $type $data] } set res } # ::otr::message::escapeHTML -- # # Return a text message with escaped HTML entities. # # Arguments: # message Text message. # # Result: # Text with HTML entities. # # Side effects: # None. proc ::otr::message::escapeHTML {message} { string map {& & < < > > \" " \n
} $message } # ::otr::message::parseDataMessagePlaintext -- # # Parse an OTR data message plaintest part. # # Arguments: # data Plaintext part of OTR data message. # # Result: # Tuple {body, tlvlist} where body is a human readable message, and # tlvlist is an even items number list of TLV types and payloads. proc ::otr::message::parseDataMessagePlaintext {data} { set tlvlist {} set idx [string first \x00 $data] if {$idx < 0} { set hrutf8 $data set data "" } else { set hrutf8 [string range $data 0 [expr {$idx-1}]] set data [string range $data [expr {$idx+1}] end] } while {[string length $data] > 0} { lassign [::otr::data::decodeTLV $data] type value data lappend tlvlist $type $value } list [stripHTML [encoding convertfrom utf-8 $hrutf8]] $tlvlist } # ::otr::message::stripHTML -- # # Remove HTML tags from a message. # # Arguments: # message Message to remove HTML tags from. # # Result: # The plain text message. # # Side effects: # None. # # Bugs: # The tag stripper is very basic. Should really use htmlparse or so. proc ::otr::message::stripHTML {message} { set message [regsub -all {]*>} $message "\n"] set message [regsub -all {<[^>]*>} $message ""] string map {< < > > " \" ' ' & &} $message } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/otr/tclotr/otr.tcl000064400000000000000000001455051500237002100171460ustar00nobodynobody# otr.tcl -- # # This file is a part of the Off-the-Record messaging protocol # implementation. It contains the OTR instance implementation. Only # versions 2 and 3 are implemented, any support for version 1 is # omitted. # # Copyright (c) 2014 Sergei Golovan # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAMER OF ALL WARRANTIES. package require otr::data package require otr::key package require otr::crypto package require otr::auth package require otr::smp package require otr::message package provide otr 0.1 namespace eval ::otr { # AuthState { # AUTHSTATE_NONE # AUTHSTATE_AWAITING_DHKEY # AUTHSTATE_AWAITING_REVEALSIG # AUTHSTATE_AWAITING_SIG # } # MsgState { # MSGSTATE_PLAINTEXT # MSGSTATE_ENCRYPTED # MSGSTATE_FINISHED # } # SMPState { # SMPSTATE_EXPECT1 # SMPSTATE_EXPECT2 # SMPSTATE_EXPECT3 # SMPSTATE_EXPECT4 # } # Policy { # ALLOW_V1 # ALLOW_V2 # ALLOW_V3 # REQUIRE_ENCRYPTION # SEND_WHITESPACE_TAG # WHITESPACE_START_AKE # ERROR_START_AKE # } variable debug 0 } ############################################################################## # ::otr::new -- # # Create new OTR instance. # # Arguments: # privkey Private key (tuple {p q g y x}). # -policy policy List of policy flags. # -heartbeat time (minutes) Interval before which a heartbeat # message will not be sent. # -maxsize size (ASCII chars) Max message size to send (not # implemented yet (TODO)). # -sendcommand cmd Callback which is called to send a message # to user's peer. # -authstatecommand cmd Callback which is called on every authstate # change. # -msgstatecommand cmd Callback which is called on every msgstate # change. # -smpstatecommand cmd Callback which is called on every smpstate # change. # -smpprogresscommand cmd Callback which is called to track progress of # SMP authentication. # -infocommand cmd Callback which is called to show some info # message to user. # -errorcommand cmd Callback which is called to show some error # message to user. # # Result: # An OTR token. # # Side effects: # The state variable is created. proc ::otr::new {privkey args} { variable id if {![info exists id]} { set id 0 } set policy {} set heartbeat 0 set maxsize 0 set authstatecommands {} set msgstatecommands {} set smpstatecommands {} set smpprogresscommands {} set infocommands {} set errorcommands {} set discardcommands {} set resendcommands {} foreach {key val} $args { switch -- $key { -policy { set policy $val } -heartbeat { set heartbeat $val } -maxsize { set maxsize $val } -sendcommand { set sendcommands [list $val] } -discardcommand { set discardcommands [list $val] } -resendcommand { set resendcommands [list $val] } -authstatecommand { set authstatecommands [list $val] } -msgstatecommand { set msgstatecommands [list $val] } -smpstatecommand { set smpstatecommands [list $val] } -smpprogresscommand { set smpprogresscommands [list $val] } -infocommand { set infocommands [list $val] } -errorcommand { set errorcommands [list $val] } default { return -code error "Invalid option '$key'" } } } if {"ALLOW_V1" in $policy} { return -code error "OTR version 1 is not supported" } if {![info exists sendcommands]} { return -code error "Option -sendcommand is mandatory" } set token [namespace current]::[incr id] variable $token upvar 0 $token state array unset state set state(privatekey) $privkey while {[set state(sinstance) [::otr::crypto::random 32]] < 0x100} {} set state(policy) $policy set state(heartbeat) $heartbeat set state(maxsize) $maxsize set state(sendcommands) $sendcommands set state(discardcommands) $discardcommands set state(resendcommands) $resendcommands set state(authstatecommands) $authstatecommands set state(msgstatecommands) $msgstatecommands set state(smpstatecommands) $smpstatecommands set state(smpprogresscommands) $smpprogresscommands set state(infocommands) $infocommands set state(errorcommands) $errorcommands set state(storedmessages) {} set state(receivedplaintext) 0 set state(lastmessage) [clock seconds] # Init vars for fragmented message set state(k) 0 set state(n) 0 set state(f) "" # Generate DH private keys (key management 1) InitDHKeys $token # Track state changes trace add variable ${token}(authstate) write \ [namespace code [list TrackAuthState $token]] trace add variable ${token}(msgstate) write \ [namespace code [list TrackMsgState $token]] trace add variable ${token}(smpstate) write \ [namespace code [list TrackSMPState $token]] trace add variable ${token}(smpprogress) write \ [namespace code [list TrackSMPProgress $token]] set state(storedauthstate) "" set state(storedmsgstate) "" set state(storedsmpstate) "" set state(authstate) AUTHSTATE_NONE set state(msgstate) MSGSTATE_PLAINTEXT set state(smpstate) SMPSTATE_EXPECT1 set state(smpprogress) SMP_NONE set token } # ::otr::configure -- # # Get or set OTR token option. # # Arguments: # token OTR token. # key Option to query or set (see ::otr::new for the # comprehensive list). # args If empty, then the current option value is # returned, if not then the first item is used to # set the specified option. # # Result: # The current value of the specified option if args are empty. # Otherwise, an empty string. # # Side effects: # Error is raised if invalid option is queried or set. proc ::otr::configure {token key args} { variable $token upvar 0 $token state if {![info exists state(privatekey)]} return if {[llength $args] == 0} { switch -- $key { -policy { return $state(policy) } -heartbeat { return $state(heartbeat) } -maxsize { return $state(maxsize) } -sendcommand { return [lindex $state(sendcommands) 0] } -discardcommand { return [lindex $state(discardcommands) 0] } -resendcommand { return [lindex $state(resendcommands) 0] } -authstatecommand { return [lindex $state(authstatecommands) 0] } -msgstatecommand { return [lindex $state(msgstatecommands) 0] } -smpstatecommand { return [lindex $state(smpstatecommands) 0] } -infocommand { return [lindex $state(infocommands) 0] } -errorcommand { return [lindex $state(errorcommands) 0] } -smpprogresscommand { return [lindex $state(smpprogresscommands) 0] } default { return -code error "Invalid option '$key'" } } } set val [lindex $args 0] switch -- $key { -policy { if {"ALLOW_V1" in $val} { return -code error "OTR version 1 is not supported" } set state(policy) $val } -heartbeat { set state(heartbeat) $val } -maxsize { set state(maxsize) $val } -sendcommand { set state(sendcommands) [list $val] } -discardcommand { set state(discardcommands) [list $val] } -resendcommand { set state(resendcommands) [list $val] } -authstatecommand { set state(authstatecommands) [list $val] } -msgstatecommand { set state(msgstatecommands) [list $val] } -smpstatecommand { set state(smpstatecommands) [list $val] } -smpprogresscommand { set state(smpprogresscommands) [list $val] } -infocommand { set state(infocommands) [list $val] } -errorcommand { set state(errorcommands) [list $val] } default { return -code error "Invalid option '$key'" } } return } # ::otr::free -- # # Destroys an OTR token and clears its state array. # # Arguments: # token OTR token. # # Result: # Empty string. # # Side effects: # The token associated array is unset. proc ::otr::free {token} { variable $token upvar 0 $token state unset -nocomplain state } # ::otr::fingerprint -- # # Return the nicely formatted DSA public key fingerprint. # # Arguments: # key DSA public key {p q g y}. # me (optional, 0 is default) If 1, then our fingerprint # is returned, if 0, then the peer's one. # # Result: # The hex SHA-1 hash of the binary representation of the key split # into five chunks. # # Side effects: # None. proc ::otr::fingerprint {token {me 0}} { variable $token upvar 0 $token state if {$me} { if {[info exists state(privatekey)]} { set key $state(privatekey) } else { return "" } } else { if {[info exists state(publickey)]} { set key $state(publickey) } else { return "" } } binary scan [::otr::crypto::DSAFingerprint $key] Iu* nums set res {} foreach n $nums { lappend res [format %08X $n] } join $res } # ::otr::ssid -- proc ::otr::ssid {token} { variable $token upvar 0 $token state switch -- $state(msgstate) { MSGSTATE_ENCRYPTED { return $state(displayssid) } default { return "" } } } # ::otr::requestConversation -- # # Send the OTR query message to the peer. # # Arguments: # token OTR token. # suffix (optional, default is "") A short clarification # message to be appended to the OTR query message. # # Result: # Empty string. # # Side effects: # The OTR query message is sent, it's formed using the stored # policy flags. proc ::otr::requestConversation {token {suffix ""}} { variable $token upvar $token state CallBack $token send [::otr::data::queryMessage $state(policy)]$suffix } # ::otr::finishConversation -- # # Send the finishing conversation OTR message. # # Arguments: # token OTR token. # # Result: # Empty string. # # Side effects: # The message is not sent if the current message state is 'plaintext' # or 'finished'. The message state is switched to 'plaintext' proc ::otr::finishConversation {token} { variable $token upvar $token state switch -- $state(msgstate) { MSGSTATE_ENCRYPTED { set message [CreateEncryptedMessage $token {} "" {1 ""}] CallBack $token send $message InitDHKeys $token } } set state(msgstate) MSGSTATE_PLAINTEXT return } # ::otr::startSMP -- # # Start the SMP authentication procedure. # # Arguments: # token OTR token. # secret The secret common to the user and his peer. # -question qu (optional, default to no question) Question to ask. # # Result: # Empty string. # # Side effects: # SMP message 1 or 1Q is sent to the peer if the message state is # 'encrypted'. Also, SMP state and progress callbacks are invoked. proc ::otr::startSMP {token secret args} { variable $token upvar $token state switch -- $state(msgstate) { MSGSTATE_ENCRYPTED { lassign [CreateSMP1 $token $secret {*}$args] \ smpstate smpprogress flags body tlvlist set message [CreateEncryptedMessage $token $flags $body $tlvlist] CallBack $token send $message set state(smpstate) $smpstate set state(smpprogress) $smpprogress } default { set state(smpprogress) SMP_ABORT } } return } # ::otr::replySMP -- # # Reply to the SMP authentication procedure. # # Arguments: # token OTR token. # secret The secret common to the user and his peer. # # Result: # Empty string. # # Side effects: # SMP message 2 is sent to the peer if the message state is 'encrypted'. # Also, SMP state and progress callbacks are invoked. proc ::otr::replySMP {token secret} { variable $token upvar $token state switch -- $state(msgstate) { MSGSTATE_ENCRYPTED { lassign [CreateSMP2 $token $secret] \ smpstate smpprogress flags body tlvlist set message [CreateEncryptedMessage $token $flags $body $tlvlist] CallBack $token send $message set state(smpstate) $smpstate set state(smpprogress) $smpprogress } default { set state(smpprogress) SMP_ABORT } } return } # ::otr::abortSMP -- # # Abort the SMP authentication procedure in progress. # # Arguments: # token OTR token. # # Result: # Empty string. # # Side effects: # SMP abort message is sent to the peer if the message state is # 'encrypted'. Also, SMP state and progress callbacks are invoked. proc ::otr::abortSMP {token} { variable $token upvar $token state switch -- $state(msgstate) { MSGSTATE_ENCRYPTED { set message [CreateEncryptedMessage $token {} "" {6 ""}] CallBack $token send $message set state(smpstate) SMPSTATE_EXPECT1 set state(smpprogress) SMP_ABORT } default { set state(smpprogress) SMP_ABORT } } return } # ::otr::outgoingMessage -- # # Take an outgoing user message and either encrypt it and return or # swallow and return -code break to signal that this message is not # to be sent. # # Arguments: # token OTR token. # message Message to process. # # Result: # Serialized array with one possible element 'message'. # # Side effects: # Query message may be sent. proc ::otr::outgoingMessage {token message} { variable $token upvar 0 $token state switch -- $state(msgstate) { MSGSTATE_PLAINTEXT { if {[QueryPolicy $token REQUIRE_ENCRYPTION]} { # TODO: Think about resending message after AKE #Store $token $message CallBack $token info "Message is not sent because encryption\ is required. Trying to start private\ conversation..." CallBack $token send [::otr::data::queryMessage $state(policy)] return {} } elseif {[QueryPolicy $token SEND_WHITESPACE_TAG] && ([QueryPolicy $token ALLOW_V2] || [QueryPolicy $token ALLOW_V3]) && !$state(receivedplaintext)} { return [list message \ $message[::otr::data::whitespaceTag \ $state(policy)]] } else { return [list message $message] } } MSGSTATE_ENCRYPTED { Store $token $message # Store the time of last message sent set state(lastmessage) [clock seconds] set message [CreateEncryptedMessage $token {} $message {}] return [list message $message store 1] } MSGSTATE_FINISHED { # TODO: Think about resending message after AKE #Store $token $message CallBack $token info "Message is not sent. Either end your private\ conversation, or restart it" return {} } } } # ::otr::incomingMessage -- # # Take an incoming message from the peer and decrypt it if appropriate. # # Arguments: # token OTR token. # message Message to process. # # Result: # Serialized array with optional 'message' item (message to show) and # 'warn' item (warn the user about publicly readable message). # # Side effects: # Change of the OTR states, error or info messages may be shown to the # uesr, etc. proc ::otr::incomingMessage {token message} { variable $token upvar 0 $token state if {![catch {::otr::data::binaryMessageFragment $message} data]} { # Binary OTR message fragment Debug $token 2 "OTR binary message fragment" return [AssembleBinaryMessage $token $data] } elseif {![catch {::otr::data::binaryMessage $message} data]} { # Binary OTR message Debug $token 2 "OTR binary message" # Delete stored message only if type==3 return [DispatchBinaryMessage $token $data] } elseif {![catch {::otr::data::findErrorMessage $message} error]} { # OTR error message Debug $token 2 "OTR error message" # Don't delete stored message CallBack $token error $error if {[QueryPolicy $token ERROR_START_AKE] && ([QueryPolicy $token ALLOW_V2] || [QueryPolicy $token ALLOW_V3])} { CallBack $token send [::otr::data::queryMessage $state(policy)] } return {} } elseif {![catch {::otr::data::findQueryMessage $message} versions]} { # OTR query message Debug $token 2 "OTR query message" Delete $token if {[set version [FindVersion $token $versions]]} { # Version is good lassign [NewSession $token $version] authstate msgstate message CallBack $token send $message set state(authstate) $authstate set state(msgstate) $msgstate } else { # Version is incompatible if {[QueryPolicy $token ALLOW_V3] || \ [QueryPolicy $token ALLOW_V2]} { # OTR isn't completely disabled CallBack $token info "OTR request message is received but\ it uses an incompatible or disabled\ protocol version" } else { # OTR is disabled CallBack $token info "OTR request message is received but\ you have disabled encryption" } } return {} } else { # Plaintext message Debug $token 2 "Plaintext message" Delete $token if {![catch {::otr::data::findWhitespaceTag $message} versions]} { # Plaintext with the whitespace tag Debug $token 2 "... with the whitespace tag" set message [::otr::data::removeWhitespaceTag $message] if {[QueryPolicy $token WHITESPACE_START_AKE] && \ [set version [FindVersion $token $versions]]} { lassign [NewSession $token $version] authstate msgstate reply CallBack $token send $reply set state(authstate) $authstate set state(msgstate) $msgstate } } set ret [list message $message] switch -- $state(msgstate) { MSGSTATE_PLAINTEXT { set state(receivedplaintext) 1 if {[QueryPolicy $token REQUIRE_ENCRYPTION]} { lappend ret warn 1 } } MSGSTATE_ENCRYPTED - MSGSTATE_FINISHED { lappend ret warn 1 } } return $ret } } # ::otr::AssembleBinaryMessage -- # # Auxiliary proc which appends received binary message part to the # already assembled parts. Process the message if it is whole. # # Arguments: # token OTR data. # data Message part. # # Result: # Either empty list (show the user that the message is to be ignored), # or the result of [incomingMessage] if all parts are received. # # Side effects: # Internal assemble message state is updated. If it is complete then # the side effects of [incomingMessage]. proc ::otr::AssembleBinaryMessage {token data} { variable $token upvar 0 $token state # Here sinstance is a remote instance tag, rinstance is ours, # because the message is incoming lassign $data version k n message sinstance rinstance Debug $token 2 "$version $k $n $message" if {$version >= 3} { if {$sinstance < 0x100 || ($rinstance > 0 && $rinstance != $state(sinstance))} { return {} } if {![info exists state(rinstance)]} { set state(rinstance) $sinstance } elseif {$sinstance != $state(rinstance)} { return {} } } else { # Fake rinstance for version 2 set state(rinstance) 0x100 } if {$k == 0 || $n == 0 || $k > $n} { # Do nothing } elseif {$k == 1} { set state(f) $message set state(k) $k set state(n) $n } elseif {$n == $state(n) && $k == $state(k)+1} { append state(f) $message incr state(k) } else { set state(f) "" set state(k) 0 set state(n) 0 } if {$state(n) > 0 && $state(k) == $state(n)} { set data $state(f) set state(f) "" set state(k) 0 set state(n) 0 return [incomingMessage $token $data] } else { return {} } } # ::otr::DispatchBinaryMessage -- # # Auxiliary proc which looks at the OTR binary message type and calls # appropriate handler. # # Arguments: # token OTR token # data List {version, type, binary, sinstance, rinstance} # # Result: # The result of handler for the given message type. # # Side effects: # The side effects of handler for the given message type. proc ::otr::DispatchBinaryMessage {token data} { variable $token upvar 0 $token state # Here sinstance is a remote instance tag, rinstance is ours, # because the message is incoming lassign $data version type binary sinstance rinstance Debug $token 2 "$version $type [::otr::data::Bin2Hex $binary]" if {$type == 2} { # If this is a D-H Commit message, it specifies the protocol version # and the peer's instance tag if {$version == 3 && [QueryPolicy $token ALLOW_V3]} { set state(version) 3 } elseif {$version == 2 && [QueryPolicy $token ALLOW_V2]} { set state(version) 2 } else { Debug $token 1 "Protocol version $version is disabled" return {} } set state(rinstance) $sinstance } if {![info exists state(version)]} { switch -- $type { 3 { Debug $token 1 "Var state(version) is not set" set error "Encrypted message can't be deciphered" CallBack $token info $error CallBack $token send [::otr::data::errorMessage $error] return {} } default { Debug $token 1 "Non-data message and state(version) is not set" return {} } } } if {$version != $state(version)} { set error "Unmatched protocol versions" Debug $token 1 $error CallBack $token info $error CallBack $token send [::otr::data::errorMessage $error] return {} } if {$version >= 3} { if {$sinstance < 0x100 || ($rinstance > 0 && $rinstance != $state(sinstance))} { Debug $token 1 "sinstance: $sinstance, rinstance: $rinstance,\ state(sinstance): $state(sinstance)" return {} } if {![info exists state(rinstance)]} { set state(rinstance) $sinstance } elseif {$sinstance != $state(rinstance)} { Debug $token 1 "sinstance: $sinstance,\ state(rinstance): $state(rinstance)" return {} } } else { # Fake rinstance for version 2 set state(rinstance) 0x100 } switch -- $type { 2 { # D-H commit message return [ProcessDHCommitMessage $token $binary] } 3 { # Data message Delete $token return [ProcessDataMessage $token $binary] } 10 { # D-H key message return [ProcessDHKeyMessage $token $binary] } 17 { # Reveal signature message return [ProcessRevealSignatureMessage $token $binary] } 18 { # Signature message return [ProcessSignatureMessage $token $binary] } default { return {} } } } # ::otr::ProcessDHCommitMessage -- # # Auxiliary procedure which takes the D-H commit message and replies # to it. proc ::otr::ProcessDHCommitMessage {token data} { variable $token upvar 0 $token state switch -- $state(authstate) { AUTHSTATE_AWAITING_DHKEY { set arg [list -r $state(r)] } default { set arg {} } } set keyid [expr {$state(keyid)-1}] lassign [::otr::auth::processDHCommitMessage \ $state(version) \ $state(authstate) \ $state(msgstate) \ $data \ $state(x,$keyid) \ -sinstance $state(rinstance) \ -rinstance $state(sinstance) \ {*}$arg] \ state(authstate) state(msgstate) message \ state(egxmpi) state(hgxmpi) if {$message ne ""} { CallBack $token send $message } return {} } # ::otr::ProcessDHKeyMessage -- proc ::otr::ProcessDHKeyMessage {token data} { variable $token upvar 0 $token state switch -- $state(authstate) { AUTHSTATE_AWAITING_SIG { set arg [list -gy $state(gy)] } default { set arg {} } } set keyid [expr {$state(keyid)-1}] lassign [::otr::auth::processDHKeyMessage \ $state(version) \ $state(authstate) \ $state(msgstate) \ $data \ $state(privatekey) \ $state(r) \ $state(x,$keyid) \ $keyid \ -sinstance $state(rinstance) \ -rinstance $state(sinstance) \ {*}$arg] \ state(authstate) state(msgstate) message state(gy) if {$message ne ""} { CallBack $token send $message } return {} } # ::otr::ProcessRevealSignatureMessage -- proc ::otr::ProcessRevealSignatureMessage {token data} { variable $token upvar 0 $token state set keyid [expr {$state(keyid)-1}] lassign [::otr::auth::processRevealSignatureMessage \ $state(version) \ $state(authstate) \ $state(msgstate) \ $data \ $state(egxmpi) \ $state(hgxmpi) \ $state(privatekey) \ $state(x,$keyid) \ $keyid \ -sinstance $state(rinstance) \ -rinstance $state(sinstance)] \ authstate msgstate message publickey gy keyidy if {[info exists state(publickey)] && $publickey ne $state(publickey)} { set oldkey $state(publickey) } else { set oldkey $publickey } set state(publickey) $publickey if {$message ne ""} { # Success UpdatePeerDHKeysAfterAKE $token $gy $keyidy StoreSSID $token 0 CallBack $token send $message switch -- $state(msgstate) { MSGSTATE_PLAINTEXT { CallBack $token info "Private conversation is started" } default { CallBack $token info "Private conversation is refreshed" } } set state(authstate) $authstate set state(msgstate) $msgstate Resend $token $oldkey } else { set state(authstate) $authstate set state(msgstate) $msgstate } return {} } # ::otr::ProcessSignatureMessage -- proc ::otr::ProcessSignatureMessage {token data} { variable $token upvar 0 $token state set keyid [expr {$state(keyid)-1}] lassign [::otr::auth::processSignatureMessage \ $state(version) \ $state(authstate) \ $state(msgstate) \ $data \ $state(gy) \ $state(x,$keyid) \ -sinstance $state(rinstance) \ -rinstance $state(sinstance)] \ authstate msgstate message publickey keyidy if {[info exists state(publickey)] && $publickey ne $state(publickey)} { set oldkey $state(publickey) } else { set oldkey $publickey } set state(publickey) $publickey if {$keyidy ne ""} { # Success UpdatePeerDHKeysAfterAKE $token $state(gy) $keyidy StoreSSID $token 1 switch -- $state(msgstate) { MSGSTATE_PLAINTEXT { CallBack $token info "Private conversation is started" } default { CallBack $token info "Private conversation is refreshed" } } set state(authstate) $authstate set state(msgstate) $msgstate Resend $token $oldkey } else { set state(authstate) $authstate set state(msgstate) $msgstate } return {} } # ::otr::UpdatePeerDHKeysAfterAKE -- proc ::otr::UpdatePeerDHKeysAfterAKE {token gy keyidy} { variable $token upvar 0 $token state # Store the peer's D-H public key (key management 2) if {$state(keyidy) == $keyidy && $state(gy,$keyidy) == $gy} { # Do nothing } elseif {$state(keyidy)-1 == $keyidy && $state(gy,$keyidy) == $gy} { # Do nothing } else { array unset state gy,* array unset state ctrtop,* set state(keyidy) $keyidy set state(gy,$keyidy) $gy incr keyidy -1 set state(gy,$keyidy) 0 } } # ::otr::StoreSSID -- proc ::otr::StoreSSID {token flag} { variable $token upvar 0 $token state set gy $state(gy,$state(keyidy)) set x $state(x,[expr {$state(keyid)-1}]) lassign [::otr::crypto::AKEKeys $gy $x] state(ssid) binary scan $state(ssid) H8H8 left right if {$flag} { set state(displayssid) "*$left* $right" } else { set state(displayssid) "$left *$right*" } } # ::otr::ShowCantDecipherError -- proc ::otr::ShowCantDecipherError {token flags} { variable $token upvar 0 $token state set info "Encrypted message can't be deciphered" set reply [::otr::data::errorMessage $info] if {"IGNORE_UNREADABLE" ni $flags} { CallBack $token info $info CallBack $token send $reply } } # ::otr::ProcessDataMessage -- proc ::otr::ProcessDataMessage {token data} { variable $token upvar 0 $token state switch -- $state(msgstate) { MSGSTATE_ENCRYPTED { lassign [::otr::message::getDataMessageKeyids $data] \ flags skeyid rkeyid nextkey ctrtop rest if {$skeyid <= 0 || $rkeyid <= 0} { Debug $token 1 \ "Data message doesn't contain key serial numbers" ShowCantDecipherError $token $flags return {} } if {$skeyid != $state(keyidy) && $skeyid != $state(keyidy)-1} { Debug $token 1 "The sender's key serial number is unknown" ShowCantDecipherError $token $flags return {} } if {$rkeyid != $state(keyid) && $rkeyid != $state(keyid)-1} { Debug $token 1 "The recipient's key serial number is unknown" ShowCantDecipherError $token $flags return {} } if {$state(gy,$skeyid) <= 0} { Debug $token 1 \ "The sender's key with this serial number doesn't exist" ShowCantDecipherError $token $flags return {} } if {[info exists state(ctrtop,$skeyid,$rkeyid)]} { if {$state(ctrtop,$skeyid,$rkeyid) >= $ctrtop} { Debug $token 1 \ "The sender's counter isn't monotonically increasing" ShowCantDecipherError $token $flags return {} } } else { array unset ctrtop,* } set state(ctrtop,$skeyid,$rkeyid) $ctrtop lassign [::otr::crypto::AESKeys $state(gy,$skeyid) \ $state(x,$rkeyid)] \ skey smac rkey rmac # Save the receiving MAC key to reveal it later set state(oldmackey,$skeyid,$rkeyid) $rmac set result [::otr::message::processDataMessage \ $state(version) \ $state(msgstate) \ $state(smpstate) \ $rest \ $flags \ $skeyid \ $rkeyid \ $nextkey \ $ctrtop \ $rkey \ $rmac \ -smpcommand [namespace code [list SMPCallback \ $token]] \ -sinstance $state(rinstance) \ -rinstance $state(sinstance)] array set res $result foreach field {msgstate smpstate smpprogress} { if {[info exists res($field)]} { set state($field) $res($field) } } if {[info exists res(debug)]} { Debug 2 $token $res(debug) } set ret {} foreach field {message secret question} { if {[info exists res($field)]} { lappend ret $field $res($field) } } if {[info exists res(info)]} { CallBack $token info $res(info) } if {[info exists res(error)]} { CallBack $token error $res(error) } if {[info exists res(replyerr)]} { CallBack $token send $res(replyerr) } if {[info exists res(info)] || [info exists res(error)] || [info exists res(replyerr)]} { return $ret } if {[info exists res(reply)]} { switch -- $state(msgstate) { MSGSTATE_ENCRYPTED { # Auto reply makes sense only in encrypted state # The only existing example so far is SMP set repl {} foreach {body tlvlist} $res(reply) { CallBack $token send \ [CreateEncryptedMessage $token {} $body \ $tlvlist] } # Store the time of last message sent set state(lastmessage) [clock seconds] } default { Debug 1 $token \ "Trying to autoreply in $state(msgstate) state" } } } if {![info exists res(message)]} { Debug 2 $token "Decrypted message is empty" } switch -- $state(msgstate) { MSGSTATE_ENCRYPTED { # Keys rotation (key management 4) if {$rkeyid == $state(keyid)} { incr rkeyid -1 unset state(x,$rkeyid) foreach id [array names state oldmackey,*,$rkeyid] { # Add the used receiving MAC keys to the # revealed keys list lappend state(oldmackeys) $state($id) unset state($id) } incr rkeyid 2 set state(x,$rkeyid) [::otr::crypto::random 320] incr state(keyid) set state(ctrtop) 0 } if {$skeyid == $state(keyidy)} { incr skeyid -1 unset state(gy,$skeyid) foreach id [array names state oldmackey,$skeyid,*] { # Add the used receiving MAC keys to the # revealed keys list lappend state(oldmackeys) $state($id) unset state($id) } incr skeyid 2 set state(gy,$skeyid) $nextkey incr state(keyidy) set state(ctrtop) 0 } # Heartbeat message if {([lsearch -exact $ret reply] % 2) != 0} { set curtime [clock seconds] if {$state(heartbeat) > 0 && $curtime > $state(lastmessage) + 60*$state(heartbeat)} { set state(lastmessage) [clock seconds] CallBack $token send \ [CreateEncryptedMessage $token \ {IGNORE_UNREADABLE} "" {}]] } } } default { InitDHKeys $token } } return $ret } MSGSTATE_PLAIN - MSGSTATE_FINISHED { ShowCantDecipherError $token {} return {} } } } # ::otr::InitDHKeys -- proc ::otr::InitDHKeys {token} { variable $token upvar 0 $token state # Forget the existing keys if any array unset state x,* array unset state gy,* array unset state ctrtop,* array unset state oldmackey,* # Generate DH private keys (key management 1) set state(keyid) 2 set state(x,1) [::otr::crypto::random 320] set state(x,2) [::otr::crypto::random 320] set state(keyidy) 0 set state(gy,0) 0 set state(gy,-1) 0 set state(oldmackeys) {} # Not exactly D-H related: set state(ctrtop) 0 unset -nocomplain state(version) } # ::otr::CreateSMP1 -- proc ::otr::CreateSMP1 {token secret args} { variable $token upvar $token state lassign [::otr::smp::createSMPMessage1 $state(smpstate) \ $state(privatekey) \ $state(publickey) \ $state(ssid) \ $secret \ {*}$args] \ smpstate type payload x a2 a3 if {$type == 6} { SMPCallback $token clear set progress SMP_ABORT } else { SMPCallback $token set x $x SMPCallback $token set a2 $a2 SMPCallback $token set a3 $a3 set progress SMP_PROGRESS } list $smpstate $progress {} "" [list $type $payload] } # ::otr::CreateSMP2 -- proc ::otr::CreateSMP2 {token secret} { variable $token upvar $token state set data1 [SMPCallback $token get data1] lassign [::otr::smp::processSMPMessage1 $state(smpstate) \ $data1 \ $state(privatekey) \ $state(publickey) \ $state(ssid) \ $secret] \ smpstate type payload g3a g2 g3 b3 Pb Qb if {$type == 6} { SMPCallback $token clear set progress SMP_ABORT } else { SMPCallback $token set g3a $g3a SMPCallback $token set g2 $g2 SMPCallback $token set g3 $g3 SMPCallback $token set b3 $b3 SMPCallback $token set Pb $Pb SMPCallback $token set Qb $Qb set progress SMP_PROGRESS } list $smpstate $progress {} "" [list $type $payload] } # ::otr::CreateEncryptedMessage -- proc ::otr::CreateEncryptedMessage {token flags body tlvlist} { variable $token upvar $token state # Key management 3 set keyid $state(keyid); # Next private key id set keyidx [expr {$state(keyid)-1}]; # Current private key id set keyidy $state(keyidy); # Current public key id lassign [::otr::crypto::AESKeys $state(gy,$keyidy) $state(x,$keyidx)] \ skey smac rkey rmac set oldmackeys $state(oldmackeys) set state(oldmackeys) {} ::otr::message::createDataMessage \ $state(version) $flags $keyidx $keyidy $skey $smac \ $state(x,$keyid) [incr state(ctrtop)] $body $tlvlist \ $oldmackeys \ -sinstance $state(sinstance) \ -rinstance $state(rinstance) } # ::otr::FindVersion -- # # Check if the given versions list contains one of the supported. # # Arguments: # token The OTR session token. # versions The OTR protocol versions list (from the received # OTR request or whitespace tag). # # Result: # Either the preferred version to choose or 0 if there's no supported # version in the list. # # Side effects: # None. proc ::otr::FindVersion {token versions} { variable $token upvar 0 $token state if {3 in $versions && [QueryPolicy $token ALLOW_V3]} { return 3 } elseif {2 in $versions && [QueryPolicy $token ALLOW_V2]} { return 2 } else { return 0 } } # ::otr::NewSession -- proc ::otr::NewSession {token version} { variable $token upvar 0 $token state set state(version) $version unset -nocomplain state(rinstance) set state(r) [::otr::crypto::Int2Octets [::otr::crypto::random 128] 128] set keyid [expr {$state(keyid)-1}] ::otr::auth::createDHCommitMessage $state(version) \ $state(authstate) \ $state(msgstate) \ $state(r) \ $state(x,$keyid) \ -sinstance $state(sinstance) } # ::otr::Store -- proc ::otr::Store {token message} { variable $token upvar 0 $token state # Store only the last message set state(storedmessages) [list $message] } # ::otr::Resend -- proc ::otr::Resend {token oldkey} { variable $token upvar 0 $token state switch -- $state(msgstate) { MSGSTATE_ENCRYPTED { if {$oldkey eq $state(publickey)} { if {[llength $state(resendcommands)] > 0} { CallBack $token resend } else { foreach message $state(storedmessages) { set message [CreateEncryptedMessage \ $token {} $message {}] CallBack $token send $message } } if {[llength $state(storedmessages)] > 0} { set state(lastmessage) [clock seconds] CallBack $token info "Last message has been resent" } } else { # Peer has changed his OTR key, so we can't trust him if {[llength $state(storedmessages)] > 0} { set state(storedmessages) {} CallBack $token info "Last message should have been\ resent but has not because the\ peer's OTR key has been changed" } } } } Delete $token } # ::otr::Delete -- proc ::otr::Delete {token} { variable $token upvar 0 $token state CallBack $token discard set state(storedmessages) {} } # ::otr::QueryPolicy -- proc ::otr::QueryPolicy {token item} { variable $token upvar 0 $token state expr {$item in $state(policy)} } # ::otr::SMPCallback -- proc ::otr::SMPCallback {token op {name ""} {val ""}} { variable $token upvar 0 $token state switch -- $op { clear { array unset state smp,* return "" } get { switch -- $name { privkey { # Our DSA key return $state(privatekey) } pubkey { # Peer's DSA key return $state(publickey) } default { if {[info exists state(smp,$name)]} { return $state(smp,$name) } else { return "" } } } } set { set state(smp,$name) $val return $val } } } # ::otr::fragmentMessage -- proc ::otr::fragmentMessage {token data size} { variable $token upvar 0 $token state set len [string length $data] switch -- $state(version) { 2 { if {$len <= $size} { return [list $data] } # Compute number of pieces set len [string length $data] set maxdig 1 while {1} { set psize [expr {$size - 8 - 2*$maxdig}] if {$psize <= 0} { return -code error "Too small chunk size" } set n [expr {($len+$psize-1)/$psize}] if {[string length $n] <= $maxdig} break incr maxdig } set res {} set k 1 set id1 0 set id2 [expr {$psize-1}] while {$k <= $n} { lappend res [format "?OTR,%hu,%hu,%s," \ $k $n [string range $data $id1 $id2]] incr k incr id1 $psize incr id2 $psize } return $res } 3 { if {$len <= $size} { return [list $data] } set sinstance $state(sinstance) set rinstance [expr {[info exists state(rinstance)]? \ $state(rinstance) : 0}] set fsinstance [format %llx $sinstance] set frinstance [format %llx $rinstance] set slen [string length $fsinstance] set rlen [string length $frinstance] # Compute number of pieces set len [string length $data] set maxdig 1 while {1} { set psize [expr {$size - 10 - $slen - $rlen - 2*$maxdig}] if {$psize <= 0} { return -code error "Too small chunk size" } set n [expr {($len+$psize-1)/$psize}] if {[string length $n] <= $maxdig} break incr maxdig } set res {} set k 1 set id1 0 set id2 [expr {$psize-1}] while {$k <= $n} { lappend res [format "?OTR|%s|%s,%hu,%hu,%s," \ $fsinstance $frinstance \ $k $n [string range $data $id1 $id2]] incr k incr id1 $psize incr id2 $psize } return $res } default { return -code error "Unsupported protocol version $state(version)" } } } # ::otr::TrackAuthState -- proc ::otr::TrackAuthState {token name1 name2 op} { variable $token upvar 0 $token state if {$state(storedauthstate) eq $state(authstate)} return set state(storedauthstate) $state(authstate) CallBack $token authstate $state(authstate) } # ::otr::TrackMsgState -- proc ::otr::TrackMsgState {token name1 name2 op} { variable $token upvar 0 $token state if {$state(storedmsgstate) eq $state(msgstate)} return switch -- $state(storedmsgstate) { MSGSTATE_ENCRYPTED { switch -- $state(msgstate) { MSGSTATE_FINISHED - MSGSTATE_PLAINTEXT { Delete $token CallBack $token info "Private conversation is finished" } } } } set state(storedmsgstate) $state(msgstate) switch -- $state(msgstate) { MSGSTATE_PLAINTEXT { set state(receivedplaintext) 0 } } CallBack $token msgstate $state(msgstate) set state(smpstate) SMPSTATE_EXPECT1 set state(smpprogress) SMP_NONE } # ::otr::TrackSMPState -- proc ::otr::TrackSMPState {token name1 name2 op} { variable $token upvar 0 $token state if {$state(storedsmpstate) eq $state(smpstate)} return set state(storedsmpstate) $state(smpstate) CallBack $token smpstate $state(smpstate) } # ::otr::TrackSMPProgress -- proc ::otr::TrackSMPProgress {token name1 name2 op} { variable $token upvar 0 $token state CallBack $token smpprogress $state(smpprogress) } # ::otr::CallBack -- proc ::otr::CallBack {token op args} { variable $token upvar 0 $token state foreach cmd $state(${op}commands) { eval $cmd $args } return } # ::otr::Debug -- # # Prints debug information. # # Arguments: # token OTR instance token. # level A debug level. # str A debug message. # # Result: # An empty string. # # Side effects: # A debug message is printed to the console if the value of # ::otr::debug variable is not less than num. proc ::otr::Debug {token level str} { variable debug if {$debug >= $level} { puts "[clock format [clock seconds] -format %T]\ [lindex [info level -1] 0] $token $str" } return } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/otr/tclotr/pkgIndex.tcl000064400000000000000000000015171500237002100201050ustar00nobodynobody# pkgIndex.tcl -- # # This file is a part of Off-the-Record messaging protocol # implementation. It loads the main package. # # Copyright (c) 2014 Sergei Golovan # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAMER OF ALL WARRANTIES. package ifneeded otr 0.1 [list source [file join $dir otr.tcl]] package ifneeded otr::key 0.1 [list source [file join $dir key.tcl]] package ifneeded otr::data 0.1 [list source [file join $dir data.tcl]] package ifneeded otr::crypto 0.1 [list source [file join $dir crypto.tcl]] package ifneeded otr::auth 0.1 [list source [file join $dir auth.tcl]] package ifneeded otr::smp 0.1 [list source [file join $dir smp.tcl]] package ifneeded otr::message 0.1 [list source [file join $dir message.tcl]] # vim:ts=8:sw=4:sts=4:et tkabber-plugins/otr/tclotr/smp.tcl000064400000000000000000000423341500237002100171350ustar00nobodynobody# smp.tcl -- # # This file is a part of the Off-the-Record messaging protocol # implementation. It contains the OTR SMP packets serializing and # deserializing procedures. # # Copyright (c) 2014 Sergei Golovan # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAMER OF ALL WARRANTIES. package require sha256 package require otr::data package require otr::crypto package provide otr::smp 0.1 ############################################################################## namespace eval ::otr::smp { variable q [expr {($::otr::crypto::Prime-1)/2}] variable g1 $::otr::crypto::G variable debug 0 } # ::otr::smp::createSMPMessage1 -- # # Return the SMP message 1 or 1Q binary packet. # # Arguments: # smpstate SMP state to check. # privkey Your DSA private key. # pubkey Peer's DSA public key. # ssid Secure session ID. # usersecret User part of the secret. # -question question If present, then the 1Q message is created. # # Result: # Tuple {smpstate, type, payload, x a2 a3} where smpstate is a new SMP # state, type and payload make a binary to encrypt and send, x, a2, a3 # are the values to save for the next SMP spteps if SMP state is # SMPSTATE_EXPECT1. Otherwise x, a2, a3 aren't returned. # # Side effects: # Four 128-bit random numbers are generated. # Modulus is taken from a global variable. proc ::otr::smp::createSMPMessage1 {smpstate privkey pubkey ssid \ usersecret args} { variable q variable g1 switch -- $smpstate { SMPSTATE_EXPECT1 { set a2 [::otr::crypto::random 128] set a3 [::otr::crypto::random 128] set r2 [::otr::crypto::random 128] set r3 [::otr::crypto::random 128] set prefix "" set type 2 foreach {key val} $args { switch -- $key { -question { set prefix [encoding convertto utf-8 $val]\x00 set type 7 } } } set x [Secret $privkey $pubkey $ssid $usersecret] set g2a [Exp $g1 $a2] set g3a [Exp $g1 $a3] set c2 [Hash 1 [Exp $g1 $r2]] set D2 [expr {($r2-$a2*$c2) % $q}] set c3 [Hash 2 [Exp $g1 $r3]] set D3 [expr {($r3-$a3*$c3) % $q}] return [list SMPSTATE_EXPECT2 $type \ $prefix[Payload $g2a $c2 $D2 $g3a $c3 $D3] \ $x $a2 $a3] } default { return {SMPSTATE_EXPECT1 6 ""} } } } # ::otr::smp::processSMPMessage1 -- # # Process SMP message 1 (or 1Q without the question) and create # SMP message 2 to reply. # # Arguments: # smpstate SMP state to check. # data Message to parse. # privkey Your DSA private key. # pubkey Peer's DSA public key. # ssid Secure session ID. # usersecret User part of the secret. # # Result: # Tuple {smpstate, type, payload, g3a, g2, g3, b3, Pb, Qb} where # smpstate is a new SMP state, payload is a binary to encrypt and # send, the rest are the values to save for the next SMP spteps if SMP # state is SMPSTATE_EXPECT1. Otherwise, g3a, g2, g3, b3, Pb, Qb aren't # returned. # # Side effects: # Seven 128-bit random numbers are generated. # Modulus is taken from a global variable. proc ::otr::smp::processSMPMessage1 {smpstate data privkey pubkey ssid usersecret} { variable q variable g1 switch -- $smpstate { SMPSTATE_EXPECT1 { set b2 [::otr::crypto::random 128] set b3 [::otr::crypto::random 128] set r2 [::otr::crypto::random 128] set r3 [::otr::crypto::random 128] set r4 [::otr::crypto::random 128] set r5 [::otr::crypto::random 128] set r6 [::otr::crypto::random 128] if {[catch {ParsePayload $data} res]} { Debug 1 "Parse of SMP message 1 failed" return [list $smpstate 6 ""] } lassign $res g2a c2 D2 g3a c3 D3 if {![Check $g2a] || ![Check $g3a]} { Debug 1 "Check 1 of SMP message 1 failed" return [list $smpstate 6 ""] } set myc2 [Hash 1 [Mult [Exp $g1 $D2] [Exp $g2a $c2]]] if {$myc2 != $c2} { Debug 1 "Check 2 of SMP message 1 failed" return [list $smpstate 6 ""] } set myc3 [Hash 2 [Mult [Exp $g1 $D3] [Exp $g3a $c3]]] if {$myc3 != $c3} { Debug 1 "Check 3 of SMP message 1 failed" return [list $smpstate 6 ""] } set y [Secret $pubkey $privkey $ssid $usersecret] set g2b [Exp $g1 $b2] set g3b [Exp $g1 $b3] set c2 [Hash 3 [Exp $g1 $r2]] set D2 [expr {($r2-$b2*$c2) % $q}] set c3 [Hash 4 [Exp $g1 $r3]] set D3 [expr {($r3-$b3*$c3) % $q}] set g2 [Exp $g2a $b2] set g3 [Exp $g3a $b3] set Pb [Exp $g3 $r4] set Qb [Mult [Exp $g1 $r4] [Exp $g2 $y]] set cP [Hash 5 [Exp $g3 $r5] [Mult [Exp $g1 $r5] [Exp $g2 $r6]]] set D5 [expr {($r5-$r4*$cP) % $q}] set D6 [expr {($r6-$y*$cP) % $q}] return \ [list SMPSTATE_EXPECT3 3 \ [Payload $g2b $c2 $D2 $g3b $c3 $D3 $Pb $Qb $cP $D5 $D6] \ $g3a $g2 $g3 $b3 $Pb $Qb] } default { # Abort SMP return [list SMPSTATE_EXPECT1 6 ""] } } } # ::otr::smp::processSMPMessage2 -- # # Process SMP message 2 and create SMP message 3 to reply. # # Arguments: # smpstate SMP state to check. # data Message to parse. # x a2 a3 SMP values returned by [createSMPMessage1]. # # Result: # Tuple {smpstate, type, payload, Pa, Qa, cP, D5, D6, Ra, cR, D7} where # smpstate is a new SMP state, type and payload make a binary to # encrypt and send, the rest are the values to save for the next SMP # steps if SMP state is SMPSTATE_EXPECT2. Otherwise, Pa, Qa, cP, D5, # D6, Ra, cR, D7 aren't returned. # # Side effects: # Four 128-bit random numbers are generated. # Modulus is taken from a global variable. proc ::otr::smp::processSMPMessage2 {smpstate data x a2 a3} { variable q variable g1 switch -- $smpstate { SMPSTATE_EXPECT2 { set r4 [::otr::crypto::random 128] set r5 [::otr::crypto::random 128] set r6 [::otr::crypto::random 128] set r7 [::otr::crypto::random 128] if {[catch {ParsePayload $data} res]} { Debug 1 "Parse of SMP message 2 failed" return [list $smpstate 6 ""] } lassign $res g2b c2 D2 g3b c3 D3 Pb Qb cP D5 D6 if {![Check $g2b] || ![Check $g3b] || ![Check $Pb] || ![Check $Qb]} { Debug 1 "Check 1 of SMP message 2 failed" return [list $smpstate 6 ""] } set myc2 [Hash 3 [Mult [Exp $g1 $D2] [Exp $g2b $c2]]] if {$myc2 != $c2} { Debug 1 "Check 2 of SMP message 2 failed" return [list $smpstate 6 ""] } set myc3 [Hash 4 [Mult [Exp $g1 $D3] [Exp $g3b $c3]]] if {$myc3 != $c3} { Debug 1 "Check 3 of SMP message 2 failed" return [list $smpstate 6 ""] } set g2 [Exp $g2b $a2] set g3 [Exp $g3b $a3] set mycP [Hash 5 [Mult [Exp $g3 $D5] [Exp $Pb $cP]] \ [Mult [Exp $g1 $D5] \ [Mult [Exp $g2 $D6] [Exp $Qb $cP]]]] if {$mycP != $cP} { Debug 1 "Check 4 of SMP message 2 failed" return [list $smpstate 6 ""] } set Pa [Exp $g3 $r4] set Qa [Mult [Exp $g1 $r4] [Exp $g2 $x]] set cP [Hash 6 [Exp $g3 $r5] [Mult [Exp $g1 $r5] [Exp $g2 $r6]]] set D5 [expr {($r5-$r4*$cP) % $q}] set D6 [expr {($r6-$x*$cP) % $q}] set PaPb [Mult $Pa [Inv $Pb]] set QaQb [Mult $Qa [Inv $Qb]] set Ra [Exp $QaQb $a3] set cR [Hash 7 [Exp $g1 $r7] [Exp $QaQb $r7]] set D7 [expr {($r7-$a3*$cR) % $q}] return [list SMPSTATE_EXPECT4 4 \ [Payload $Pa $Qa $cP $D5 $D6 $Ra $cR $D7] \ $g3b $PaPb $QaQb $Ra] } default { # Abort SMP return [list SMPSTATE_EXPECT1 6 ""] } } } # ::otr::smp::processSMPMessage3 -- # # Process SMP message 3 and create SMP message 4 to reply. # # Arguments: # smpstate SMP state to check. # data Message to parse. # g3a g2 g3 b3 Pb Qb SMP values returned by [processSMPMessage1]. # # Result: # Tuple {smpstate, type, payload, result} where smpstate is a new SMP # state, type and payload make a binary to encrypt and send, the result # equals 1 if authentication succeeded, or 0 if not, if SMP state is # SMPSTATE_EXPECT3. Otherwise, no result field is returned. # # Side effects: # One 128-bit random numbers are generated. # Modulus is taken from a global variable. proc ::otr::smp::processSMPMessage3 {smpstate data g3a g2 g3 b3 Pb Qb} { variable q variable g1 switch -- $smpstate { SMPSTATE_EXPECT3 { set r7 [::otr::crypto::random 128] if {[catch {ParsePayload $data} res]} { Debug 1 "Parse of SMP message 3 failed" return [list $smpstate 6 ""] } lassign $res Pa Qa cP D5 D6 Ra cR D7 set QaQb [Mult $Qa [Inv $Qb]] if {![Check $Pa] || ![Check $Qa] || ![Check $Ra]} { Debug 1 "Check 1 of SMP message 3 failed" return [list $smpstate 6 ""] } set mycP [Hash 6 [Mult [Exp $g3 $D5] [Exp $Pa $cP]] \ [Mult [Exp $g1 $D5] \ [Mult [Exp $g2 $D6] [Exp $Qa $cP]]]] if {$mycP != $cP} { Debug 1 "Check 2 of SMP message 3 failed" return [list $smpstate 6 ""] } set mycR [Hash 7 [Mult [Exp $g1 $D7] [Exp $g3a $cR]] \ [Mult [Exp $QaQb $D7] [Exp $Ra $cR]]] if {$mycR != $cR} { Debug 1 "Check 3 of SMP message 3 failed" return [list $smpstate 6 ""] } set Rb [Exp $QaQb $b3] set cR [Hash 8 [Exp $g1 $r7] [Exp $QaQb $r7]] set D7 [expr {($r7-$b3*$cR) % $q}] set PaPb [Mult $Pa [Inv $Pb]] set Rab [Exp $Ra $b3] set res [expr {$PaPb == $Rab}] Debug 1 "$smpstate $res" return [list SMPSTATE_EXPECT1 5 \ [Payload $Rb $cR $D7] \ $res] } default { # Abort SMP return [list SMPSTATE_EXPECT1 6 ""] } } } # ::otr::smp::processSMPMessage4 -- # # Process SMP message 4 and return the authentication result. # # Arguments: # smpstate SMP state to check. # data Message to parse. # a3 g3b PaPb QaQb Ra SMP values returned by [createMessage1] and # [processSMPMessage2]. # # Result: # Tuple {smpstate, type, payload, result} where smpstate is a new SMP # state, type and payload make a binary to encrypt and send, the result # equals 1 if authentication succeeded, or 0 if not, if SMP state is # SMPSTATE_EXPECT3. Otherwise, no result field is returned. # # Side effects: # Modulus is taken from a global variable. proc ::otr::smp::processSMPMessage4 {smpstate data a3 g3b PaPb QaQb Ra} { variable q variable g1 switch -- $smpstate { SMPSTATE_EXPECT4 { if {[catch {ParsePayload $data} res]} { Debug 1 "Parse of SMP message 4 failed" return [list $smpstate 6 ""] } lassign $res Rb cR D7 if {![Check $Rb]} { Debug 1 "Check 1 of SMP message 4 failed" return [list $smpstate 6 ""] } set mycR [Hash 8 [Mult [Exp $g1 $D7] [Exp $g3b $cR]] \ [Mult [Exp $QaQb $D7] [Exp $Rb $cR]]] if {$mycR != $cR} { Debug 1 "Check 2 of SMP message 3 failed" return [list $smpstate 6 ""] } set Rab [Exp $Rb $a3] set res [expr {$PaPb == $Rab}] Debug 1 "$smpstate $res" return [list SMPSTATE_EXPECT1 0 "" $res] } default { # Abort SMP return [list SMPSTATE_EXPECT1 6 ""] } } } # ::otr::smp::Check -- # # Wrapper to ::otr::crypto::DHCheck to make the call shorter. # # Arguments: # a Number to check. # # Result: # 1 if $a is greater than 1 and less than P-1 (where P is a # D-H prime). # # Side effects: # Modulus is taken from a global variable. proc ::otr::smp::Check {a} { ::otr::crypto::DHCheck $a } # ::otr::smp::Exp -- # # Exponent a**b mod P where P is a D-H prime. # # Arguments: # a Exponent base. # b Exponent index. # # Result: # a**b mod P. # # Side effects: # Modulus is taken from a global variable. proc ::otr::smp::Exp {a b} { ::otr::crypto::DHSecret $a $b } # ::otr::smp::Mult -- # # Multiplication modulo P. # # Arguments: # a First multiplier. # b Second multiplier. # # Result: # a*b mod P. # # Side effects: # Modulus is taken from a global variable. proc ::otr::smp::Mult {a b} { ::otr::crypto::Mult $::otr::crypto::Prime $a $b } # ::otr::smp::Inv -- # # Inverse modulo P. # # Arguments: # a Number. # # Result: # a**(-1) mod P, or b such that a*b = 1 mod P. # # Side effects: # Modulus is taken from a global variable. proc ::otr::smp::Inv {a} { ::otr::crypto::Inverse $::otr::crypto::Prime $a } # ::otr::smp::ParsePayload -- # # Decode SMP payload - a series of long integers. # # Arguments: # data Binary to parse. # # Result: # List of integers. # # Side effects: # Error is raised if parsing fails. proc ::otr::smp::ParsePayload {data} { set res {} lassign [::otr::data::decode INT $data] count data for {set i 0} {$i < $count} {incr i} { lassign [::otr::data::decode MPI $data] num data lappend res $num } set res } # ::otr::smp::Payload -- # # Create SMP payload from a series of integers. # # Arguments: # args List of integers. # # Result: # SMP binary. # # Side effects: # None. proc ::otr::smp::Payload {args} { set res "" append res [::otr::data::encode INT [llength $args]] foreach num $args { append res [::otr::data::encode MPI $num] } set res } # ::otr::smp::Hash -- # # SMP hash for its zero knowledge proofs. # # Arguments: # version Number. # arg1 The first number to hash. # arg2 (optional) The second number to hash. # # Result: # Integer representation of the SHA256 hash of the concatenated given # arguments. # # Side effects: # None. proc ::otr::smp::Hash {version arg1 {arg2 ""}} { set res "" append res [::otr::data::encode BYTE $version] append res [::otr::data::encode MPI $arg1] if {$arg2 ne ""} { append res [::otr::data::encode MPI $arg2] } ::otr::crypto::Bits2Int [::sha2::sha256 -bin $res] } # ::otr::smp::Secret -- # # Return the common secret to check for equality using the SMP. # # Arguments: # pubkey1 The first public key. # pubkey2 The second public key. # ssid The secure session ID. # secret The users' common secret. # # Result: # Secret to compare. # # Side effects: # None. proc ::otr::smp::Secret {pubkey1 pubkey2 ssid secret} { set res "" append res [::otr::data::encode BYTE 1] append res [::otr::crypto::DSAFingerprint $pubkey1] append res [::otr::crypto::DSAFingerprint $pubkey2] append res $ssid append res [encoding convertto utf-8 $secret] ::otr::crypto::Bits2Int [::sha2::sha256 -bin $res] } # ::otr::smp::Debug -- # # Prints debug information. # # Arguments: # level Debug level. # str Debug message. # # Result: # An empty string. # # Side effects: # A debug message is printed to the console if the value of # ::otr::smp::debug variable is not less than num. proc ::otr::smp::Debug {level str} { variable debug if {$debug >= $level} { puts "[clock format [clock seconds] -format %T]\ [lindex [info level -1] 0] $str" } return } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/otr/trans000075500000000000000000000000001500237002100153655ustar00nobodynobodytkabber-plugins/otr/trans/ru.msg000064400000000000000000000023471500237002100166100ustar00nobodynobody# ru.msg -- # # Messages to send to Russian peers for the Tkabber OTR plugin. # # Author: Sergei Golovan ::trans::trset ru "I has requested an Off-the-Record private conversation.\ However, you do not have a plugin to support that (or the plugin\ is disabled, or you don't have an OTR private key to use it).\nSee\ http://otr.cypherpunks.ca/ for more information." "Я хочу начать\ Ñ Ð²Ð°Ð¼Ð¸ непроÑлушиваемый разговор по протоколу OTR. Однако, у Ð²Ð°Ñ Ð½ÐµÑ‚\ раÑширениÑ, которое поддерживает Ñтот протокол (или Ñто раÑширение\ отключено, или у Ð²Ð°Ñ Ð½ÐµÑ‚ закрытого ключа Ð´Ð»Ñ Ñ€Ð°ÑширениÑ\ OTR).\nОпиÑание протокола можно найти по ÑÑылке\ http://otr.cypherpunks.ca/" ::trans::trset ru "Encrypted message can't be deciphered" "Зашифрованное\ Ñообщение не удалоÑÑŒ раÑшифровать" ::trans::trset ru "Unmatched protocol versions" "ÐеÑовпадающие верÑии\ протокола" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/otr/trans/uk.msg000064400000000000000000000023551500237002100166000ustar00nobodynobody# uk.msg -- # # Messages to send to Ukrainian peers for the Tkabber OTR plugin. # # Author: Sergei Golovan ::trans::trset uk "I has requested an Off-the-Record private conversation.\ However, you do not have a plugin to support that (or the plugin\ is disabled, or you don't have an OTR private key to use it).\nSee\ http://otr.cypherpunks.ca/ for more information." "Я хочу почати\ з вами розмову за протоколом OTR, Ñку неможливо проÑлухати. Проте,\ у Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” розширеннÑ, Ñке пітримує ций протокол (або це розширеннÑ\ вимкнене, або у Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” закритого ключа Ð´Ð»Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ\ OTR).\nÐžÐ¿Ð¸Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ñƒ можна знайти за поÑиланнÑм\ http://otr.cypherpunks.ca/" ::trans::trset uk "Encrypted message can't be deciphered" "Зашифроване\ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ðµ вдалоÑÑ Ñ€Ð¾Ð·ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ñ‚Ð¸" ::trans::trset uk "Unmatched protocol versions" "ВерÑÑ–Ñ— протокола не\ Ñпівпадають" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/poker000075500000000000000000000000001500237002100145525ustar00nobodynobodytkabber-plugins/poker/msgs000075500000000000000000000000001500237002100155235ustar00nobodynobodytkabber-plugins/poker/msgs/ru.msg000064400000000000000000000264071500237002100167510ustar00nobodynobody# ru.msg -- # # Russian messages for the Poker Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "%s (%s) has refused poker invitation: %s" \ "%s (%s) не принÑл приглашение Ñыграть в покер: %s" ::msgcat::mcset ru "%s wants to deal first." "%s хочет Ñдавать первым." ::msgcat::mcset ru "%s wants to deal second." "%s хочет Ñдавать вторым." ::msgcat::mcset ru "Ace" "Туз" ::msgcat::mcset ru "Agree to play" "СоглаÑитьÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ" ::msgcat::mcset ru "All-In" "Ð’Ñе фишки" ::msgcat::mcset ru "All-In " "ПоÑтавить вÑе оÑтавшиеÑÑ Ñ„Ð¸ÑˆÐºÐ¸" ::msgcat::mcset ru "Amount to bet: " "Размер Ñтавки: " ::msgcat::mcset ru "Bet" "ПоÑтавить" ::msgcat::mcset ru "Bet %s" "ПоÑтавить %s" ::msgcat::mcset ru "Bet:" "Ставка" ::msgcat::mcset ru "Big blind is %s" "Ð‘Ð¾Ð»ÑŒÑˆÐ°Ñ Ñтавка вÑлепую равна %s" ::msgcat::mcset ru "Big blind: " "Ð‘Ð¾Ð»ÑŒÑˆÐ°Ñ Ñтавка вÑлепую: " ::msgcat::mcset ru "Blinds are doubled every %s deals" \ "Ставки вÑлепую удваиваютÑÑ ÐºÐ°Ð¶Ð´Ñ‹Ðµ %s раздач" ::msgcat::mcset ru "Call" "Отвечаю" ::msgcat::mcset ru "Call " "Ответить" ::msgcat::mcset ru "Call %s" "Ответить %s" ::msgcat::mcset ru "Cancel invitation" "Отменить приглашение" ::msgcat::mcset ru "Check" "ПроверÑÑŽ" ::msgcat::mcset ru "Check " "Проверить" ::msgcat::mcset ru "Checking decks" "Проверка колоды карт" ::msgcat::mcset ru "Dealer: " "Сдающий: " ::msgcat::mcset ru "Eight" "ВоÑьмерка" ::msgcat::mcset ru "Flop is dealt: %s" "Флоп Ñдан: %s" ::msgcat::mcset ru "Flush" "ФлÑш" ::msgcat::mcset ru "Fold" "СбраÑываю" ::msgcat::mcset ru "Fold " "СброÑить" ::msgcat::mcset ru "Four of a kind" "Четверка" ::msgcat::mcset ru "Full house" "Полный дом" ::msgcat::mcset ru "Games" "Игры" ::msgcat::mcset ru "I want to deal first" "Я хочу Ñдавать первым" ::msgcat::mcset ru "I want to deal second" "Я хочу Ñдавать вторым" ::msgcat::mcset ru "Jack" "Валет" ::msgcat::mcset ru "King" "Король" ::msgcat::mcset ru "New state %s" "Ðовое ÑоÑтоÑние %s" ::msgcat::mcset ru "Nine" "ДевÑтка" ::msgcat::mcset ru "Opponent" "Оппонент" ::msgcat::mcset ru "Opponent bets %s equals to %s" \ "Оппонент Ñтавит %s, равную %s" ::msgcat::mcset ru "Opponent calls %s" "Оппонент отвечает %s" ::msgcat::mcset ru "Opponent checks" "Оппонент проверÑет" ::msgcat::mcset ru "Opponent deals first" "Оппонент Ñдает первым" ::msgcat::mcset ru "Opponent folds" "Оппонент ÑбраÑывает карты" ::msgcat::mcset ru "Opponent goes all-in" \ "Оппонент Ñтавит вÑе оÑтавшиеÑÑ Ñ„Ð¸ÑˆÐºÐ¸" ::msgcat::mcset ru "Opponent has to go all-in (stack equals %s)" \ "Оппонент вынужден поÑтавить вÑе оÑтавшиеÑÑ Ñ„Ð¸ÑˆÐºÐ¸ (вÑего фишек %s)" ::msgcat::mcset ru "Opponent lost all chips" "Оппонент проиграл вÑе фишки" ::msgcat::mcset ru "Opponent raises %s" "Оппонент поднимает %s" ::msgcat::mcset ru "Opponent revealed pocket cards: %s" \ "Оппонент открыл карманные карты: %s" ::msgcat::mcset ru "Opponent thinks that you cheat" \ "Оппонент Ñчитает, что вы играете нечеÑтно" ::msgcat::mcset ru "Opponent won pot %s" "Оппонент выиграл банк %s" ::msgcat::mcset ru "Opponent won side pot %s" \ "Оппонент выиграл побочный банк %s" ::msgcat::mcset ru "Opponent's best hand is %s (%s)" \ "Ð›ÑƒÑ‡ÑˆÐ°Ñ Ñ€ÑƒÐºÐ° оппонента \u2015 %s (%s)" ::msgcat::mcset ru "Opponent's stack is %s" \ "КоличеÑтво фишек у оппонента \u2015 %s" ::msgcat::mcset ru "Pair" "Пара" ::msgcat::mcset ru "Plugins options." "ÐаÑтройки раÑширений." ::msgcat::mcset ru "Poker (Texas hold'em) game invitation from %s (%s) is\ received." "Получено приглашение от %s (%s) Ñыграть в покер\ (ТехаÑÑкий холдем)" ::msgcat::mcset ru "Poker (Texas hold'em) plugin options." \ "ÐаÑтройки раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ 'Покер (ТехаÑÑкий холдем)'." ::msgcat::mcset ru "Poker Invitation" "Приглашение Ñыграть в покер" ::msgcat::mcset ru "Poker Invitation from %s" \ "Приглашение Ñыграть в покер от %s" ::msgcat::mcset ru "Poker playing cards theme." "Тема игральных карт." ::msgcat::mcset ru "Poker with %s" "Покер Ñ %s" ::msgcat::mcset ru "Poker..." "Покер..." ::msgcat::mcset ru "Queen" "Дама" ::msgcat::mcset ru "Raise" "Поднимаю" ::msgcat::mcset ru "Raise " "ПоднÑть" ::msgcat::mcset ru "Raise %s" "ПоднÑть на %s" ::msgcat::mcset ru "Received deck for checking" \ "Получена колода карт Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸" ::msgcat::mcset ru "Received doubly reencrypted deck" \ "Получена дважды Ð¿ÐµÑ€ÐµÐ·Ð°ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ ÐºÐ¾Ð»Ð¾Ð´Ð° карт" ::msgcat::mcset ru "Received reencrypted deck" \ "Получена Ð¿ÐµÑ€ÐµÐ·Ð°ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ ÐºÐ¾Ð»Ð¾Ð´Ð° карт" ::msgcat::mcset ru "Received reshuffled deck" \ "Получена дважды Ð¿ÐµÑ€ÐµÐ¼ÐµÑˆÐ°Ð½Ð½Ð°Ñ ÐºÐ¾Ð»Ð¾Ð´Ð° карт" ::msgcat::mcset ru "Received shuffled deck" "Получена Ð¿ÐµÑ€ÐµÐ¼ÐµÑˆÐ°Ð½Ð½Ð°Ñ ÐºÐ¾Ð»Ð¾Ð´Ð° карт" ::msgcat::mcset ru "Reencrypting deck" "Перезашифровываем колоду карт" ::msgcat::mcset ru "Refuse to play" "ОтказатьÑÑ Ð¾Ñ‚ игры" ::msgcat::mcset ru "Reshuffling deck" "Повторно перемешиваем колоду карт" ::msgcat::mcset ru "Returning doubly reencrypted deck" \ "Возвращаем дважды перезашифрованную колоду карт" ::msgcat::mcset ru "Returning reshuffled deck" \ "Возвращаем дважды перемешанную колоду карт" ::msgcat::mcset ru "River is dealt: %s" "Ривер Ñдан: %s" ::msgcat::mcset ru "Royal flush" "КоролевÑкий флÑш" ::msgcat::mcset ru "Sending Poker (Texas hold'em) game invitation to %s (%s)" \ "ПоÑылаем приглашение %s (%s) Ñыграть в покер (ТехаÑÑкий холдем)" ::msgcat::mcset ru "Sending reencrypted deck" \ "ПоÑылаем перезашифрованную колоду карт" ::msgcat::mcset ru "Sending shuffled deck" "ПоÑылаем перемешанную колоду карт" ::msgcat::mcset ru "Sending unencrypted deck for checking" \ "ПоÑылаем незашифрованную колоду карт Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸" ::msgcat::mcset ru "Seven" "Семерка" ::msgcat::mcset ru "Show tooltips with short instructions." \ "Показывать вÑплывающие подÑказки Ñ ÐºÑ€Ð°Ñ‚ÐºÐ¸Ð¼Ð¸ указаниÑми." ::msgcat::mcset ru "Shuffling deck" "Перемешиваем колоду" ::msgcat::mcset ru "Small blind is %s" "ÐœÐ°Ð»Ð°Ñ Ñтавка вÑлепую равна %s" ::msgcat::mcset ru "Small blind: " "ÐœÐ°Ð»Ð°Ñ Ñтавка вÑлепую: " ::msgcat::mcset ru "Sound to play after opponent's deal or bet" \ "Звук, который будет проигрыватьÑÑ Ð¿Ð¾Ñле того, как оппонент ÑдаÑÑ‚\ карты или Ñделает Ñтавку" ::msgcat::mcset ru "Split" "Дележ" ::msgcat::mcset ru "Stack: " "Фишки: " ::msgcat::mcset ru "Starting deal %s" "Ðачинаем раздачу %s" ::msgcat::mcset ru "Starting the game" "Ðачинаем игру" ::msgcat::mcset ru "Stop the game" "ОÑтановить игру" ::msgcat::mcset ru "Straight" "Стрит" ::msgcat::mcset ru "Straight flush" "Стрит флÑш" ::msgcat::mcset ru "Ten" "ДеÑÑтка" ::msgcat::mcset ru "The game is finished" "Игра окончена" ::msgcat::mcset ru "The game is terminated by opponent" \ "Игра прервана оппонентом" ::msgcat::mcset ru "The game is terminated by you" "Игра прервана вами" ::msgcat::mcset ru "The opponent is cheating" "Оппонент играет нечеÑтно" ::msgcat::mcset ru "The opponent's deck is checked successfully" \ "Колода карт оппонента проверена уÑпешно" ::msgcat::mcset ru "Three of a kind" "Тройка" ::msgcat::mcset ru "Turn is dealt: %s" "Терн Ñдан: %s" ::msgcat::mcset ru "Two pairs" "Две пары" ::msgcat::mcset ru "Waiting for checked deck" "Ждем проверку колоды карт" ::msgcat::mcset ru "Waiting for doubly reencrypted deck" \ "Ждем дважны перезашифрованную колоду карт" ::msgcat::mcset ru "Waiting for reshuffled deck" \ "Ждем дважды перемешанную колоду карт" ::msgcat::mcset ru "Waiting for shuffled deck" "Ждем перемешанную колоду карт" ::msgcat::mcset ru "Whether the Poker (Texas hold'em) plugin is loaded." \ "Загружено ли раÑширение 'Покер (ТехаÑÑкий холдем)'" ::msgcat::mcset ru "Winner" "Победитель" ::msgcat::mcset ru "You" "Ð’Ñ‹" ::msgcat::mcset ru "You and opponent split pot %s" \ "Ð’Ñ‹ и оппонент разделили банк" ::msgcat::mcset ru "You bet %s equals to %s" "Ð’Ñ‹ Ñтавите %s, равную %s" ::msgcat::mcset ru "You call %s" "Ð’Ñ‹ отвечаете %s" ::msgcat::mcset ru "You check" "Ð’Ñ‹ проверÑете" ::msgcat::mcset ru "You deal first" "Ð’Ñ‹ Ñдаете первым" ::msgcat::mcset ru "You fold" "Ð’Ñ‹ ÑбраÑываете карты" ::msgcat::mcset ru "You go all-in" "Ð’Ñ‹ Ñтавите вÑе оÑтавшиеÑÑ Ñ„Ð¸ÑˆÐºÐ¸" ::msgcat::mcset ru "You got pocket cards %s" "Ð’Ñ‹ получили карманные карты %s" ::msgcat::mcset ru "You got pocket cards: %s" "Ð’Ñ‹ получили карманные карты: %s" ::msgcat::mcset ru "You have to go all-in (stack equals %s)" \ "Ð’Ñ‹ вынуждены поÑтавить вÑе оÑтавшиеÑÑ Ñ„Ð¸ÑˆÐºÐ¸ (вÑего фишек %s)" ::msgcat::mcset ru "You lost all chips" "Ð’Ñ‹ проиграли вÑе фишки" ::msgcat::mcset ru "You opened pocket cards to opponent" \ "Ð’Ñ‹ открыли карманные карты оппоненту" ::msgcat::mcset ru "You raise %s" "Ð’Ñ‹ поднÑли на %s" ::msgcat::mcset ru "You won pot %s" "Ð’Ñ‹ выиграли банк %s" ::msgcat::mcset ru "You won side pot %s" "Ð’Ñ‹ выиграли побочный банк %s" ::msgcat::mcset ru "Your best hand is %s (%s)" \ "Ваша Ð»ÑƒÑ‡ÑˆÐ°Ñ Ñ€ÑƒÐºÐ° \u2015 %s (%s)" ::msgcat::mcset ru "Your stack is %s" "Ваше количеÑтво фишек \u2015 %s" ::msgcat::mcset ru "big blind" "большую Ñтавку вÑлепую" ::msgcat::mcset ru "small blind" "малую Ñтавку вÑлепую" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/poker/msgs/uk.msg000064400000000000000000000262431500237002100167400ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Poker Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "%s (%s) has refused poker invitation: %s" \ "%s (%s) відхилив Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в покер: %s" ::msgcat::mcset uk "%s wants to deal first." "%s хоче здавати першим." ::msgcat::mcset uk "%s wants to deal second." "%s хоче здавати другим." ::msgcat::mcset uk "Ace" "Туз" ::msgcat::mcset uk "Agree to play" "ЗгодитиÑÑ Ð³Ñ€Ð°Ñ‚Ð¸" ::msgcat::mcset uk "All-In" "Ð’ÑÑ– фішки" ::msgcat::mcset uk "All-In " "ПоÑтавити вÑÑ– фішки, Ñкі залишилиÑÑ" ::msgcat::mcset uk "Amount to bet: " "Розмір Ñтавки: " ::msgcat::mcset uk "Bet" "ПоÑтавити" ::msgcat::mcset uk "Bet %s" "ПоÑтавити %s" ::msgcat::mcset uk "Bet:" "Ставка" ::msgcat::mcset uk "Big blind is %s" "Велика Ñтавка наоÑліп дорівнює %s" ::msgcat::mcset uk "Big blind: " "Велика Ñтавка наоÑліп: " ::msgcat::mcset uk "Blinds are doubled every %s deals" \ "Ставки наоÑліп подвоюютьÑÑ ÐºÐ¾Ð¶Ð½Ñ– %s роздач" ::msgcat::mcset uk "Call" "Відповідаю" ::msgcat::mcset uk "Call " "ВідповіÑти" ::msgcat::mcset uk "Call %s" "ВідповіÑти %s" ::msgcat::mcset uk "Cancel invitation" "Відмінити запрошеннÑ" ::msgcat::mcset uk "Check" "ПеревірÑÑŽ" ::msgcat::mcset uk "Check " "Перевірити" ::msgcat::mcset uk "Checking decks" "Перевірка колоди карт" ::msgcat::mcset uk "Dealer: " "Здає: " ::msgcat::mcset uk "Eight" "Ð’Ñ–Ñімка" ::msgcat::mcset uk "Flop is dealt: %s" "Флоп зданий: %s" ::msgcat::mcset uk "Flush" "Флеш" ::msgcat::mcset uk "Fold" "Скидаю" ::msgcat::mcset uk "Fold " "Скинути" ::msgcat::mcset uk "Four of a kind" "Четвірка" ::msgcat::mcset uk "Full house" "Повний дім" ::msgcat::mcset uk "Games" "Ігри" ::msgcat::mcset uk "I want to deal first" "Я хочу здавати першим" ::msgcat::mcset uk "I want to deal second" "Я хочу здавати другим" ::msgcat::mcset uk "Jack" "Валет" ::msgcat::mcset uk "King" "Король" ::msgcat::mcset uk "New state %s" "Ðовий Ñтан %s" ::msgcat::mcset uk "Nine" "Дев’Ñтка" ::msgcat::mcset uk "Opponent" "Опонент" ::msgcat::mcset uk "Opponent bets %s equals to %s" \ "Опонент Ñтавить %s, Ñка дорівнює %s" ::msgcat::mcset uk "Opponent calls %s" "Опонент відповідає %s" ::msgcat::mcset uk "Opponent checks" "Опонент перевірÑÑ”" ::msgcat::mcset uk "Opponent deals first" "Опонент здає першим" ::msgcat::mcset uk "Opponent folds" "Опонент Ñкидає карти" ::msgcat::mcset uk "Opponent goes all-in" \ "Опонент Ñтавить вÑÑ– фішки, що залишилиÑÑ" ::msgcat::mcset uk "Opponent has to go all-in (stack equals %s)" \ "Опонент вимушений поÑтавити вÑÑ– фішки, що залишилиÑÑ (вÑього фішок %s)" ::msgcat::mcset uk "Opponent lost all chips" "Опонент програв вÑÑ– фішки" ::msgcat::mcset uk "Opponent raises %s" "Опонент піднімає %s" ::msgcat::mcset uk "Opponent revealed pocket cards: %s" \ "Опонент відкрив карти з кишені: %s" ::msgcat::mcset uk "Opponent thinks that you cheat" \ "Опонент вважає, що ви граєте нечеÑно" ::msgcat::mcset uk "Opponent won pot %s" "Опонент виграв банк %s" ::msgcat::mcset uk "Opponent won side pot %s" \ "Опонент виграв побічний банк %s" ::msgcat::mcset uk "Opponent's best hand is %s (%s)" \ "Краща рука опонента \u2015 %s (%s)" ::msgcat::mcset uk "Opponent's stack is %s" \ "КількіÑть фішок у опонента \u2015 %s" ::msgcat::mcset uk "Pair" "Пара" ::msgcat::mcset uk "Plugins options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½ÑŒ." ::msgcat::mcset uk "Poker (Texas hold'em) game invitation from %s (%s) is\ received." "Отримане Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð²Ñ–Ð´ %s (%s) зіграти в покер\ (ТехаÑький холдем)" ::msgcat::mcset uk "Poker (Texas hold'em) plugin options." \ "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ 'Покер (ТехаÑький холдем)'." ::msgcat::mcset uk "Poker Invitation" "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в покер" ::msgcat::mcset uk "Poker Invitation from %s" \ "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в покер від %s" ::msgcat::mcset uk "Poker playing cards theme." "Тема гральних карт." ::msgcat::mcset uk "Poker with %s" "Покер Ñ %s" ::msgcat::mcset uk "Poker..." "Покер..." ::msgcat::mcset uk "Queen" "Дама" ::msgcat::mcset uk "Raise" "Піднімаю" ::msgcat::mcset uk "Raise " "ПіднÑти" ::msgcat::mcset uk "Raise %s" "ПіднÑти на %s" ::msgcat::mcset uk "Received deck for checking" \ "Отримана колода карт Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸" ::msgcat::mcset uk "Received doubly reencrypted deck" \ "Отримана двічі перезашифрована колода карт" ::msgcat::mcset uk "Received reencrypted deck" \ "Отримана перезашифрована колода карт" ::msgcat::mcset uk "Received reshuffled deck" \ "Отримана двічі перемішана колода карт" ::msgcat::mcset uk "Received shuffled deck" "Отримана перемішана колода карт" ::msgcat::mcset uk "Reencrypting deck" "Перезашифровуємо колоду карт" ::msgcat::mcset uk "Refuse to play" "ВідмовитиÑÑ Ð²Ñ–Ð´ гри" ::msgcat::mcset uk "Reshuffling deck" "Повторно перемішуємо колоду карт" ::msgcat::mcset uk "Returning doubly reencrypted deck" \ "Вертаємо двічі перезашифровану колоду карт" ::msgcat::mcset uk "Returning reshuffled deck" \ "Вертаємо двічі перемішану колоду карт" ::msgcat::mcset uk "River is dealt: %s" "Рівер зданий: %s" ::msgcat::mcset uk "Royal flush" "КоролевÑький флеш" ::msgcat::mcset uk "Sending Poker (Texas hold'em) game invitation to %s (%s)" \ "ПоÑилаємо Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ %s (%s) зіграти в покер (ТехаÑький холдем)" ::msgcat::mcset uk "Sending reencrypted deck" \ "ПоÑилаемо перезашифровану колоду карт" ::msgcat::mcset uk "Sending shuffled deck" "ПоÑилаемо перемішану колоду карт" ::msgcat::mcset uk "Sending unencrypted deck for checking" \ "ПоÑилаемо незашифровану колоду карт Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸" ::msgcat::mcset uk "Seven" "Сімка" ::msgcat::mcset uk "Show tooltips with short instructions." \ "Показувати Ñпливаючі підказки з короткими вказівками." ::msgcat::mcset uk "Shuffling deck" "Перемішуємо колоду" ::msgcat::mcset uk "Small blind is %s" "Мала Ñтавка наоÑліп дорівнює %s" ::msgcat::mcset uk "Small blind: " "Мала Ñтавка наоÑліп: " ::msgcat::mcset uk "Sound to play after opponent's deal or bet" \ "Звук, Ñкий буде програватиÑÑ Ð¿Ñ–ÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк опонент здаÑть\ карти чи зробить Ñтавку" ::msgcat::mcset uk "Split" "Розділ" ::msgcat::mcset uk "Stack: " "Фішки: " ::msgcat::mcset uk "Starting deal %s" "Починаємо роздачу %s" ::msgcat::mcset uk "Starting the game" "Починаємо гру" ::msgcat::mcset uk "Stop the game" "Зупинити гру" ::msgcat::mcset uk "Straight" "Стріт" ::msgcat::mcset uk "Straight flush" "Стріт флеш" ::msgcat::mcset uk "Ten" "ДеÑÑтка" ::msgcat::mcset uk "The game is finished" "Гру закінчено" ::msgcat::mcset uk "The game is terminated by opponent" \ "Гру перервано опонентом" ::msgcat::mcset uk "The game is terminated by you" "Гру перервано вами" ::msgcat::mcset uk "The opponent is cheating" "Опонент грає нечеÑно" ::msgcat::mcset uk "The opponent's deck is checked successfully" \ "Колода карт опонента перевірена уÑпішно" ::msgcat::mcset uk "Three of a kind" "Трійка" ::msgcat::mcset uk "Turn is dealt: %s" "Терн зданий: %s" ::msgcat::mcset uk "Two pairs" "Дві пари" ::msgcat::mcset uk "Waiting for checked deck" "Ждемо перевірку колоди карт" ::msgcat::mcset uk "Waiting for doubly reencrypted deck" \ "Ждемо двічі перезашифровану колоду карт" ::msgcat::mcset uk "Waiting for reshuffled deck" \ "Ждемо двічі перемішану колоду карт" ::msgcat::mcset uk "Waiting for shuffled deck" "Ждемо перемішану колоду карт" ::msgcat::mcset uk "Whether the Poker (Texas hold'em) plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ 'Покер (ТехаÑький холдем)'" ::msgcat::mcset uk "Winner" "Переможець" ::msgcat::mcset uk "You" "Ви" ::msgcat::mcset uk "You and opponent split pot %s" \ "Ви Ñ– опонент розділили банк" ::msgcat::mcset uk "You bet %s equals to %s" "Ви Ñтавите %s, що дорівнює %s" ::msgcat::mcset uk "You call %s" "Ви відповідаєте %s" ::msgcat::mcset uk "You check" "Ви перевірÑете" ::msgcat::mcset uk "You deal first" "Ви здаєте першим" ::msgcat::mcset uk "You fold" "Ви Ñкидаєте карти" ::msgcat::mcset uk "You go all-in" "Ви Ñтавите вÑÑ– фішки, що залишилиÑÑ" ::msgcat::mcset uk "You got pocket cards %s" "Ви отримали карти в кишеню %s" ::msgcat::mcset uk "You got pocket cards: %s" "Ви отримали карти в кишеню: %s" ::msgcat::mcset uk "You have to go all-in (stack equals %s)" \ "Ви змушені поÑтавити вÑÑ– фішки, що залишилиÑÑ (вÑього фішок %s)" ::msgcat::mcset uk "You lost all chips" "Ви програли вÑÑ– фішки" ::msgcat::mcset uk "You opened pocket cards to opponent" \ "Ð’Ñ– відкрили карти з кишені опоненту" ::msgcat::mcset uk "You raise %s" "Ви піднÑли на %s" ::msgcat::mcset uk "You won pot %s" "Ви виграли банк %s" ::msgcat::mcset uk "You won side pot %s" "Ви виграли побічний банк %s" ::msgcat::mcset uk "Your best hand is %s (%s)" \ "Ваша краща рука \u2015 %s (%s)" ::msgcat::mcset uk "Your stack is %s" "Ваша кількіÑть фішок \u2015 %s" ::msgcat::mcset uk "big blind" "велику Ñтавку наоÑліп" ::msgcat::mcset uk "small blind" "малу Ñтавку наоÑліп" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/poker/pixmaps000075500000000000000000000000001500237002100162335ustar00nobodynobodytkabber-plugins/poker/pixmaps/classic000075500000000000000000000000001500237002100176545ustar00nobodynobodytkabber-plugins/poker/pixmaps/classic/00.gif000064400000000000000000000010631500237002100206410ustar00nobodynobodyGIF89aG`ó€€€€€ÿÿÿ!ù,G`þP€I«½8ëÍ©D(Ždižhªô¾p»rm×4ì|ïÿÀ påˆÈ¤2iˆv·h:tˬ¶H%X±WlˆJ—Çæ4z-_»ß­|Þö:×êöYŸßûûoavOs†Juql‹|Œ€x‰wn‡•D’„:›Ž‹p“P–¤\‚Šž©ŸM™¥±=˜‘ªœ¬·­§¢…²¥´”«Â¹ÄnÀ£¾±ÇoŸ¶ÏȯxÉ¿¡°ÎØÃŽ®U¼`Ô•ËšÐÚÙ›ÖÓàáèÁÍåï‘ìÈê‡âðäîç»×ô†öæøŽú׎WN=JŽêØg‘½»Š:ˆO~¼€;tkabber-plugins/poker/pixmaps/classic/01.gif000064400000000000000000000010321500237002100206360ustar00nobodynobodyGIF89aH`óÿÿÿ9B9ÎεssZ)11œ”sçç÷½½Î„!))Œ))1„9J¥!ù,G`þ„I«½8ëÍ©4@(ŽdižhªÆ´¾p»ä ߸JEîÿ¡]h°³©è!Ÿ:¥ˆ81B¯$!ÐÄzE;biýBwÛ Ó|–R-e6Ƽ¬ås©+Åçù;~‚Aƒ?{ˆWŠ‹OŽG{”‘‰}–9Bšœ7;£24 ¢«+4±/­°µ(;•J•ºQ5EÀ¶˜€Ä²ÆÈ0Ë)ÍÎ'ÐÑ%ÓÔ#Ö׆ÚÅÜÉÞÁà»Êâ`äOqŒçG®íï@ª_Ù8®¡fünàóÐyl¾H'„UÖÑ»t%ž‡‹¡&z2(cà}Èõ®øÓKÇ<´‰BC: O#Ž—0Õ±ã€áNwrÊÁ  Oj#ŠŒ)1§À ê’Z‹j,««°ŽÒÚ‰«%¯‘À4&ö ‘8eErò+í“‘ÿøx£%—Ü¢Ü>1… ¤Þ·›°)­…Ð\9J%ÿLMqRn…)q¼1Ð!ʳèaÜ©Ž'˜q¼©`$4Ž4\Ö˜¾!Ãà¶tííM™Õ§gÓ®=Lp9×Õ8Çj‡»ˆß#Z¤ìÀ¼¹ó;tkabber-plugins/poker/pixmaps/classic/02.gif000064400000000000000000000012151500237002100206420ustar00nobodynobodyGIF89aH`óÿÿÿçç÷ssZ)11ZRR”{„Îε½œ¥½½Î!)9B9œ”sZR!„!ù,G`þp„I«½8ëÍ©l@(ŽdižhªÍ´¾p»ä!߸JDîÿ¡]è°³‰è!Ÿ:¥ˆ81B¯$!ÐÄzE;biýBwÛ Ó|–R-e6Ƽ¬ås©+Åçù;~‚Aƒ?{ˆWŠ‹OŠŽG{‘’>B•—˜7;›ž04¡£¤Q†ª¥z®/4²+;·J»¸¹}CE¿³Á€ÄÀÈ9Ê«Í2ÌÏ'ÑOxÔGÖlØ?Ü_Þ9àãfæ7èê^ì1îðŒÆÙáöøßúøMòwà‰¶3Èá2…óvpø â zÞ‘Ëdq…þ/ H…Cž uBZ  à@ª´€`ÀÆŠ?0˜‰AKŽ?,àyaÁ- >jµpôaP™K'ÔL4eTMKvD¡3*ŸT_ Í€€ ¨ŒÞ„¶Åh¥H ÁG‘ âàr A³0 @A Y¶@½{³%Ø•€[¸!LP¹›C$èÖ¶R›ëJÏ»+w-“Ï`7“­Œ62ÛÄpÿÒíèÐÞ‹ˆÄîÇW¯¦Äå(­p49éV|¤ýŽ]zˆS¢ Y½“s9¡F}o)‹jY$ÇKRßûüz߀”°oèÐü6æµo·JÁÉý'oT<`ÄO¤ÁÅ"!d€áž'[táàvSPPF‚J8!… ÷ )wèÇ!zaH#–ÐÂr^µØâ;tkabber-plugins/poker/pixmaps/classic/03.gif000064400000000000000000000010321500237002100206400ustar00nobodynobodyGIF89aH`óÿÿÿÿÿ½½ÿJJÿs{ÿ11ssZœ”s„!))Œ))11)1„!ù,G`þð„I«½8ëÍ©D@(ŽdižhªÈ´¾p»ä ߸JBîÿ¡]h °³© ( Ÿ+!QP„ZMB& yíŠvD'Óèµî´!nÙ¬L©pòúHcÂáÎ9’F%õõtJw"ƒ€?.…[p†‡mŒ^Bl’Ž6—”94T˜Ÿœ7|w‰¥/ž¨ ªIC­U¯«–¨¤´µ"šp˜¹º»Ÿ¾¿QŽCÃÄ:ÆCÉÀͦËÏÎÒ0‘ÔÊ×°ÙÓÛ(ÖÝ%ßà#âãAÑæ_è@dîy“VvTbwóOå8oq­rY1ÐÊôžÈZ˜ Á…wBáw£D*ô „ï¡,wÈP¼â»+#IzŒrã•’,+•)à¤Ì™mÞœ9«LÊ-¦#·.ÝÏlG¯%¥¶TZÓgO›EM6•XÕ_Wse}r«!M½êá… €Ø5¼@‘9[FT/uàüÅ9Îí\l»@¤ÛMT(Wf‹6»”iß¡$òJRüˆ±ÂEi9F’hÐdÊ=xd¾|Ä žÃÙäR1¹sæ-óJ ` ÜqZÔ€ÞöFŽjÓo¯î9»Ûé׿º 7b-$tXμ9ó;tkabber-plugins/poker/pixmaps/classic/04.gif000064400000000000000000000010021500237002100206360ustar00nobodynobodyGIF89aH`óÿÿÿÿÿs{ÿ½½ÿJJÿœœssZœ”s„!))Œ))11)1„!ù,G`þð„I«½8ëÍ©D@(ŽdižhªÈ´¾p»$!߸JBîÿ¡]ˆ °³i  Ÿ+!QP„ZMB& yíŠvD'Óèµî´!nÙ¬L©pòúHcÂáÎ9’F%õõtJw"ƒ€?.…[p†‡mŒ^Bl%r’9‘[–@‘Lyš8BpŸ ŽoT•¥:Žw‹«0`®ª°'¡£µ±Ž!¹º%=¾/˜´Â%˜ÆÃ»É¿Ì2ÈÎ(ÐÑXËÔÒÖ×ÕÚQÙÜ#ÓßáßäGžeæ?è]ê9Å{ÞHóTkð7úpøA·ÎwOüÁ@5ëÁ œt%¢«‰P¾`xÇž°/ì¸Bx¯ŒEŒ½D™²‹nE&âJ¾HR®e„™'€Ã† J”ذaÿýwÑ =4ÂzJ!XÑsVM$ 0\„ (Th‚E0äÀCÓ5—×^R½wP|IÂ0¼fAXp¢ Pãre¨‡ RÔÞe‘8×^78Ñ04€Šþp! )RˆÂ…5æ Â(äø”d<àãD+°ÂE °hÁ…0°ÀkeФ4Nd£tVJÝtUÇœœV6 ÁÄež HĦ OZp<@ÐalY”Yœš-@h "9‘˜²i(E(ì@•ÊäœA•i”A¡iQzMšç&þýØ\£¶……gþ æcþ@㓃>y⫟.*×ZŸ­ºzГjþ Á0lšA…×z@hž‚êaD]~âGÚö)AX)Šø±Ù€HÀ¦D+ÀŠA•ßÊö”H•¦8 ,j«f›Þ ë²Æ›F+&Y¦ ðj‚‹ ˆiA¥(Œ¯Âîi”¢ò2éµ…Æôü6@  .xË1{  º&L<À,à3¯0 Ck+-CËÁ3œù*¥œ|‡À ´,Ax|àÂYFS@…}0€ `êÃ÷†ÚÍœš€€0@P€?þxYí5}l-öÎ9\ ÀÙ$|ìU¥ .%0A@0?<ÐÃG¹ÇÙ2 \àÃlª­¶DL B +¨pí 0Ááe Â "hع´é4 ½ƒî‡Çl,{¯ÿ€1Àßõ˜þÞdÞ Ÿ-&Bð¤¹`4'@Ѐêým¼øc00€ %x ‚ý*l ‚¡ ÀûhAÙ"‚ˆ†tcûÀú Î}лÊdÀxÀzüÉ€`J`;í) &¸Ñr€š ÀÍÆÆ@ rªSÀ ˜ « ­‚+Ȧ.@l ‡þ+øŽ|0¾´€æ-  @Èí…‡S€h¸ µÉ`òS H°ÅÝ ¬#G&p€Tà¬@áXSš³| X_è|ºÎ†b³à}à€ (²>°LЀ¡ ŸhEk Ø¢Siia]Г É °%0¢‘g éÊÅñ /þ*¨ôŒ½ßÔ8Z¥ç¯(ðÝ@‚¨Ò,¨ég&Ós’ åÔÀIG °. ØdÐÛ§,§Œ'“ÜÛTÀ5²­´"èÁq,н´æ5(XA9g˜ °N¼å¦ŽŽ€ t n@(˜@ px-ˆAb€ܨ€j((g €¸Z4k.è®THM´î€n°&$7$ï,¡Qd3/ ½üÀùãáþ4ƒ ¬[¡Öª¼’‚BÀ àé7^Q»¹D@fØ—#>ÌôÉEüIù,tÀ•ï 7Ë Ïß!Û†\@àAv}X ¬çÏøS$X/“é‚*ÀªÛ FGž³pà¿Æ+ ]U`‚ÊaÎw*HÍõøã)Ë­Ž¬`ìà,cAgÚrÖº P{@€™Õ¥¿Â(ÕQÓ@©jH -Ë¡žÑ4ƒÏhh¦›ÍŒ–ÃãmaØ< ÏÞ'—û@rØÑL#ƒ nÀkáy¿ðôÇðULP¯)mjÜU¬—½ƒP _Fßþ¶,€ù$מàv9ó×Dûš™Rª³PlÀ ˜Θf> æ:ºMÀäAÀ¶ttc©  f=ÀÏYr¾]¡ @hëžgx$Ѐ <ýŽÚÄt™‹6f<ˆ "@:ðp¦5éJÀÏ" 6ya*^¸8ÛøÍsc íYð›,@— U`ÏôؽR ‹ QhÎU«E0Ñ-°€wA‰SÓ{Çø>óÝñ@\?P´`Ô°KõK$ë™ NÔfî >"¡Ï@¼‚ ¯eÊ^5Œ@²žpñ²Ü£ìäq¯­+?É<;<»påѳ HÊšýUªþS‚ÛKÄI1j>î}ÕÜ×8‹I=‘A¥¶êàôQSŒ&Žó$Àú4Sˆ¨&¯x_"S¤Cÿ‚1¾b €NC+=²ý&;ðG÷$Á%€b(ÐuÓ=±pR'”±6Janþ·|#­"( @Âzà2a|ã¢~>B{²“$¨$Ò$Ë_èW}UF} ‚%¶¡}“‡b6X"ƒ %7Ã"©'(¡€ZR*zA" Øw}”„JX!"sƒ·beu%q˜t)Ðêu WP?û±°efV…ð†Ççö#† Trâ1”SÛÑÌðJŸÇtv²Ð ¸ ãgœáf½áÀAvåBPY²%‘Œƒ uÇAWÐFV¥OžÁ z¥8.!X[è4qLjµYêu…1MÆÓ¤($xXyÈnÁab‘dÓc`±q©˜LÑŒÇRâHàèI!爎BaŽ‘ÁŽHqë.ÑøŽôX§È ù¨’øýˆŽ“<1ACa㸠Y;tkabber-plugins/poker/pixmaps/classic/06.gif000064400000000000000000000067551500237002100206640ustar00nobodynobodyGIF89aH`÷?„!))Œ))11)1„9B99J¥BZRBc½R!RZœZ))ZR!ZRRc1sc{­ssZ{{s){”Æ”{!”{„”œ½œ))œ”s¥R!¥”)¥µÞ­­Rcµs„µ{!½1)½œZ½œ¥½½ÎÆœ!ÆÞ÷Æ÷ÿεcÎεÞRJÞµ!ç))ç{!çç÷÷Þ¥ÿÿÿÿ11ÿJJÿs{ÿœ1ÿœœÿ½!ÿ½½ÿÞÿÞcÿÿ)ÿÿ¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þ'H° Áƒ*\È À ?"JœH±¢Å‹3jü±aàÆ C†ô(²¤É’ þPy²åÉ”WÆtIs$€ˆ$ÖÜù‘¤Gx ÍèСH-5š´éÄ¢G%6œJ5¡Æ¢?¢®üè¡€ˆ`wt8¶‡=ÀŽ ÛCćo•›“éÖ‰. À"m…-Hì¸ðáÃ× €ïàP@‡Ò«tå® z7"y+zø@áF‡Ï*´ø@ƒ <¨°„ƒ‹’aßTI[âå™)6AáD‡ À'P(L!Â* @cl¥³cÖþq›`n‰040(Na;¾þ‹ïÞ=„E¸Ï㦧x³zÁëP(  þ€úøóã?`Åú§ÿI%BåWl°A ”°¼9åAyÅ6SE{v)¢ ,Jà#˜?v™hD0œÀÃnB6àAsjäAŽ&䨧Eþ&F$8Š:”¦*”jFBæ ƒ"Â*,Ft‚ ¨à¨@]’Ž0ÀÐç«‹ X`í0à- ŽZ¹U–»b´c´ø¸*™$`¢ )¤»m¨$¨®©ÕI#H\깪•&p·œ9ë¶Üzko¸Jº‘ té°}Ò*ÁÄI6p­¿j[k½÷Îu•FBn9+ÿ*‹Å®ˆðõ&Ë0lªfÛ@p0À Ì-¬ÐÎÛà*2QÅ›~2ØÐô¬µ$°ÀúÃÄBfàîFDB”z´s™°@èGA 4Ð C  pÁ JÀÇóþø°å“EÏü˜œ@î à@÷ Ðt 2ˆðÀ`÷ pA-t BÓôAðC}ðü$F;¥Œ`8|H«ôQ@ƒ 6ŒðÙ ¨WàÜ'È %`€­1Ø«,¾Î-¾C?d0ÀÙH `ÃìœpBPA´0B . ð9êðÀ±à»î±ÆB$pA `ÏÕ'ˆðMºÇ þQ)$À9€ |ÀðÔ yL^Pšút…k?ÀåvÀBùm`~йÊ0p è@ýÖ<@xh *ÐÖp€6 €@Ÿ`züÀx ª \æ“qIž7à f@Û-À PÀþpÀ ð¬`Å#ZpÂT19ØŸ².  ÈåZ€ A3@åð³³:&(@Àg^µü`Z¨TI4x ZƒL½ ÔG-Hhxиհ@ PLþÀ+€A RœìI¨xô@2`¦Ãùó™” `€h50vv|öîG=Àž<ÐÔ• €âxÁl¡ m×` ׃å0’0˜£*—VÈ=Ë[ÑÉŠ…4`~"ZŸV–3kÂ]> àçP 8$ž©TWµkíÙ´ÊÆŒ²àþ*#µz h•³âÓÁá‚è·xàˆ ÑbÇ›³I+M°] 4À/¼ÁЖ¸Äœ >•T¤P—.˜Š h¾=m‚–ƒ Dîr@A3ñƒlTibÍ‚E †,R ƒ t„±OÙÁNCÓGâO”À}¿c€öîÓÚÉn}p7ž@¬ÛtÚ T€œ<èÀý¾7°ú@@kcv@Í ¸Àitt¦ðRˆÅÒ"Á00€Óv2~iK~ »5°€¾¹A¼Ç‚à`>–<%Âè½Q ð1éNð|¦¢¬ƒÝQ €>²X¨\ÖAþ Pd×ê²6LÀK[ KÅ· æ|ãAâÕq&xã4OX>ŸQÐ$ $ ßœ€R¤ói{€ÄÀ7-À¯lI#ÊàKœ~?pÄDš“·å»°Þg€ÓöQz|†ùvœú°@¶ÀXÊçÆ>?ôYµ÷*À-p ÕvÆÉam8µ ‘]µA ܹT`r…;4¢»:šæÀhk²œì•ðà—+¸®¶Ò†ºUJr-Pjćf.љŀ°€¤)9`€N«<ØqH0êJÀ5”¢á€gDlЀÐü¦ÐÆ:Œv>¾• þ(Œ´ýà™ž~ææ ;j>`s D4~ž©ÞÃá.M>.š Ö »â%Àö¬£7Ö\\ÀÚ-AÛ²Ùsüð»XåÐUpØW0-mb;™¨¶è°xG”ù¾=€¢¸”£"çDþµ®ŠDKI?4 ÊydÄU ²`m5n ‰V× |DVÅoƒ kx×"Q¾u‚¾_M[ƒZj451Z!*OZËÀ¢4©H)F‹· o2 qÉ› Öª¸4±hU$±Ñ—篲” QÒú š›'P±]¯ïID²„%Ê|^)ßê@ßM¦j•­KÒêÔGÆ,ƒ\)J*è¬ËþþƒE?Vá:«À¿¡êøqUl? ©ù”Ò«TûSôΛDàø T2®±Ò%¯·V""-Óçy'¸°á°~á&°T…Â-DS—‚)‹†²‡–a™~챿ÔxágrÔâ +}}ZcÄ'.•Q¹!‚OÁSj7=³#Kõ4f>£y3•uQ}á,¶!'r;@êÅ-ØA…`B„ð~ìa²…Wa!Ày°5À ¢ @†ùrZ+Тt¨QEÄZ¸„u³‡4vB@âá1Ü1Ôܧ‡T²´!Q‚Ìq0e`O…Á À1чŠxƒ§Š8X%Á#°bàÓF"À4p?p—Ó70/ó×!uÖ„ ø¡ `¡G´nñ¬9,¦Q±!ÃgXÑy±†‘`¡ciѾÄXµÈ‹5r}ºh:UqŽT1@NÑÕWŽí8ëñˆGÁŽõXa|ô˜5ш0áÿèˆ)N1ŠI 9ûˆŽ‘U1;tkabber-plugins/poker/pixmaps/classic/07.gif000064400000000000000000000071101500237002100206470ustar00nobodynobodyGIF89aH`÷?„!))Œ))11)1„9B99J¥BZRBc½R!RZœZ))ZR!ZRRc1sc{­ssZ{{s){”Æ”{!”{„”œ½œ))œ”s¥R!¥”)¥µÞ­­Rcµs„µ{!½1)½œZ½œ¥½½ÎÆœ!ÆÞ÷Æ÷ÿεcÎεÞRJÞµ!ç))ç{!çç÷÷Þ¥ÿÿÿÿ11ÿJJÿs{ÿœ1ÿœœÿ½!ÿ½½ÿÞÿÞcÿÿ)ÿÿ¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þ'H° Áƒ*\È À ?"JœH±¢Å‹3jü±aàÆ C†ô(²¤É’e¨”ñc%Ë“0O¦\Ù’fÌ›#DTц 8ƒ~$ɳÆO¡H3•ahÒ§—…JUâÒ¦jÝšPãÒX#êĈáÂŽ³g+ä@Û‚C´Nœ]ÛãƱwÇò;ul:~èø‘¹9Ìžh±£ÅWØqCnãîzÕû¬SF™VYã zˆ8‘CÄ…bËàÀz­ˆ"d0¸E¼gòtùC§Ëã9|8q¢Ãƒ»ñC‹ *<ØñŠˆf/þüÞ\s8MÐÇIK4ì = `@?B  PøA"‰ Œ§pé¤Cz2‘òQ@_lûuG }(Àáâ)GžR…¶Riy› „B !lÂ}<¦¨@‚ >\pA dØ€ˆ–˜`„9i F4$F `‚X$L0À%t ¾e(Q¡'Zh¥á5Ú‘Á`Á”ßM)¾eA” @e €‡'`T@æoÆ!Èpƒ5Ñ”0˜o& `i¤d€lÁ(j  (š•™Ç¥I‘£þÍ™dÖ@ À a¦(d ©Á BD™e@d^‚!˜ªY@% À™diž¾Ò™Aˆ¦‰P ˜`BžÇçW«bidÁœù¬ð of¦up‚-¸VAºE"y¢‚ÌJ”AÄZ$¤)ÌKe›?”ðÀÚñ‹lDk6°DþÐÀ¸ûƒ½V¯±a€Ö°åÈ(›_´.ºf@'½?œ'•–.,Ñ<0À&¤\æ«^4¥ Lë®ß}|g¯QfŠiD(@\Á@t1Iš]$åœ ,`‘›U>­©žzF4ÁuuÃ)l½µE4p­³Ü.þ 2»I%ž½ºišZ¬&‚صÀGäë 8 ¬³wfšië.€tä¨ ‚°&À'ÈíU³šÒlg•H`€ Ôl¬X@@ëeOúø>l`¦“¸‚Zv³û•¼N  ‚oÜîMëZs9 €ZN Åßõß A›™¡ *} Ÿ‰UPeÐ5ošýhà¿Aù‚Ó‚ âs–i2fÇÐ@¤Î.p˜ Z¦!€ À`óûùœ `À·¢DµHIà8ØÁ·D0¥=ÊMøà<˜ƒPçþ.`ÂÂí  pV˜¨ô¼éÄð9¸A `C0À¨3€h@£‚€\ ;è@>`3'u*~2A np„ˆN²ô¼(ƒN  ô·íÀ x ¨µ>*Z@‚Ï¡£Û ¬ z0‰8?ˆ5 Œñ7¯A"#ÄŸ‹XØЗ¯8 ‘”zÀÞ£îApÛy>™•&R–±347®2„S_ÓP°€(g³Ìh` @†¼´Š ¤ôuG~ €æ¨$ÇõE2¸SÌ,pY `8Áh€ •ÙþËŠ&Ô/y,Cœ@bZPtÊÀøA•J \R'Ѐ ´ìrQPO°šQ‘i °Ž zÐJZ ¸€t‚ÐS?O>‹Ct`ŽÌ9GÅ/¾€¤MQJ¡)ô@4x<@‚Äõë.·9âvrp˜NÄãò€ð½ï% vßÉ'„\ó5pÀÕ~Ђ™ Š'¸ÁM_ðt uÕVÔÐÂ×¥I+;.€@÷¦<,¦%pëì÷œ <À(7Ÿ60=*fÒ¦˜=Á¨øƒ€oh Sìú€pµ£¿i ðЀÖqþÐ д`€ª«±W&4L`?ŸÊa1ÐN \à¢O N—~ð¥¡),€ ´ãWð-QS(#‹ ¼ peŽ[[S<6†€@w)à¥öiL]@’ö&xì*` ׂÅ’ P ÁZà m ½ÍZɰšÄ«¶TÌébG·Æ¿®Á ƒÎ3¶^ }¤J|¬@W;5\·b &0aO øÊÀPÁº~ À:Ö™ÀÁ4Ô¦ÜtŒÍܺƒ  ¡>A§¶ùœA¡ØÐ{ÀuâzÉ5@ Xã~8àÊoÀ­“y²þk?ÐCÏV§ X¦à€ÄLØ~”r¤’»£œøìÀ­ØNAkÀæ5ÂçøŽ»àÜ´`;†Íò%ר·¹€[iÇà/°Ÿ í”hÍ*³Ø(°fÕ¢€ fÙh”>À­aƒ(v8‚@~Ûðƒ¬&_­VI‘7½Ói¼@ôÜz8h ¤Ž¡JmkM‹¸ÌIvüœ¥èq)`-Îß™Q›•Y?†~¤§“)ªùÖ¦“±Ñtd KÙÛ[ÍÓRÜê½ïÉÇÓ2`ŽƒÁäH„Î,6Š  4pÊh9RìÝ:ÔŒ@˜uF§þòÔÈqYàj9°ÐUÁ }T"Àv.àÔ‰ÝÅ{fùøz8$íaï Aʱ0@øu¹ïm1¢¼¢^ â:¢ݵÝþ#%€05òF(È…7u$’y /¦!BóS!¢è‰àáDZ,šÇvp$ •F àà ñ1ñAí1!’ˆ ®Bı‡QAáA5±>Ws9 20kÐÑNö"OvQé!"ÂxÖ×&Qph”T¥RJÖ>‚[=@¾†hB$6€"5!ÛX*Â_q%C;Q±Á-pæ¸'à F‚‡I2>"{AŒ­GlsDgq“q=`h±x×u\Òwñ¸„æÂ¹q y1U>1’%I"ù ™’&I‰(é0’BáN“2yÙÈ-y“!‘“‹B’< ;”71ÝH”HÑñ‘LÙ”[1;tkabber-plugins/poker/pixmaps/classic/08.gif000064400000000000000000000067771500237002100206720ustar00nobodynobodyGIF89aH`÷?„!))Œ))11)1„9B99J¥BZRBc½R!RZœZ))ZR!ZRRc1sc{­ssZ{{s){”Æ”{!”{„”œ½œ))œ”s¥R!¥”)¥µÞ­­Rcµs„µ{!½1)½œZ½œ¥½½ÎÆœ!ÆÞ÷Æ÷ÿεcÎεÞRJÞµ!ç))ç{!çç÷÷Þ¥ÿÿÿÿ11ÿJJÿs{ÿœ1ÿœœÿ½!ÿ½½ÿÞÿÞcÿÿ)ÿÿ¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þ'H° Áƒ*\È À ?"JœH±¢Å‹3jü±aàÆ C†ô(²¤É’e¨”ñc%Ë“0O¦\Ù’fÌ›#DTц 8ƒ~$ɳÆO¡H3•ahÒ§—…JUâÒ¦jÝšPãÒX#êÜ‚B‡;ZœíqaG 2Îî8‘ãÚ`X‹ñ+Ø©|踘‚Á s[ä8q¢Å>ôhA¢GŽÊXôxïXžk8 üÒb¨%ÑD‹‘?´h¶G ôR„q¢sT.kòäëÓ©Eñ5|Ðð€AÔNt¨P¡…3dx!‡oŠ3yþ‹c%Ž‹(  @Ã*#;¨pAÁ‰ Pü€Ñû ;0ð]VZ%˜K2 V dàÁƒ(Àž À_d d§‚zyp‚ ŠÕ™‚"E&\„‚„:@rDD‚ *Hðƒ‡ zÕYib艥¸À Ø( (XÀ àÁ~*ðÀÃÚ}â$õ4U?”§ÒyI z%ðäx¦ Iz€^(ðpšHÐBŽJñå¥ `b)Qq逘gþÀ¦v&X€Â˜¤hÂ5j'•:F¤‚ ’–‘˜ÉaD‹ª™$ ЦùCœø°€›w^)Upþ~Jän)ê$‡,z( FÒCƒ&Pš§¥˜r¹‘‘™àà¢0<ø`zAJ‚´ð«zšgàG–°ŠI¢°( (+îFT-ž}è¶yP療šk¹0ŒYjŠ?LãÖbK±~ÔÀ‘5jƒ—;fv¨Ûj¥ͪ ð‹‘u@œ&Hð ÇÍ’û°Dþe0Æ}ýÀ¼&€Ñ“ŸF„$›pȨ®…J´®ÀJýг ‘(½`¾04H.®Ímñµ0_€Lã‹fv àêì³ÎJš·Úe€X ÁÄpêÅ홆º9hþ³ vÏnKФÕc³%žC=€{tÀ®Ö®~â pC0Œ C ”Ðä„ôpÂЦVj5Ö“´7€€Yï* PÐÞüðJäà⋇aÐCu³upÁ',ÁY°%L@tÌ00Ð…\  +™Ð+QÀC4VÁ¬ï€zêŽAƺ PÀõZO@aî³ïΡ #°@t>Àì€yŽAŸ0Ö1¦ Àï:€— {¡€î À¤ù°åG3Á Ђ´\`uÈ(›º¤.È:Àˆ ‚ŒŠý˜T€¢.þ=Pd†:Ç\@59` #£š,/¸!…l˜ä<ïÀÐÇ dPð¾ÆìàKTÎÃ<àÀ &SCÇ\1+`› p8Þ +ðœ ÈXÓá'6°ù€P'Ôí6r¬ wpG« Q ˆ!cDf€ø ÈA@!¸g=¦d ü:ðÅ| `Üd JŠEY{<]@€„íà)HÁIÙ,¬àø°œ°½låÜ“ƒÌÒ–~Ú#ò:ÐË  ˆÁRpR`=XæãpŸ¬/Õc ÀÓÑ®n}þÁ$ÐçÇt +£ Ü9!û¹§=$x€Ò7ppz=ÁpƒÇa cdHþQ0øÜD`¢•€Áã% ÀÇ„ /HËEp‚Éœ —é *Y`¤:µfG½)0ÊÀ¼jõz0 P´=œZD–N‡`Ÿø žÀ¬Ü°3) ˆöë(Ké2OÕ\ô„-YZ…j€x`À@ É8²¶à›ÁvðU€=è:¾‹ÂpA€7çš Ô©yØÜXy02¨< ÐK :èëMít(ä þN±ª ´€”ln€è H¥êa½ù͹ôàí@–ÍØšö*­v`!qàiìhÓúÏÆœÀÖ[-x ƒÖv€£MØ &ð“á¥à]©ý y×àᔃ|tÌëjÕh 2ØÁrëK8(†£kRT Æ ä ´ÞDÀêf÷‚QÎ+›ý/sÐK .s¹€~€€Šà?ÈÜ R‚ ÜCýçd @€ÏÕR¼Yï F`»$Œy®ÛÁ2'4äenÖL¨+{ÉÓÛà,žœg¼"ƒp¢6 "› (Qƒ`fÀ|N€‚ ts½¤Ïþ~Aƒ‰^´©E½—eÀN^`}ÍCäã۶à®Gõ#lsS­º'¼øÔš+0yªG:N<‹a–È$FÉ-(ó ›÷ÇÆ\ ÝßE+À¬Ç2°rë <à€ tÀùƒx ®_tâ2y8»‹v‡ñlt”ÇØ ‡êKÝ€ÀŠP†Ë[&ÐÁ‹ÆŽ®ü€5ç‚çfžÀ5î4"ˆ/°ÈøNª"{¨½žhæ¢Ð_ôX€ìÔaú>±7ë„÷;œ)X R¥íöhæI¾.€þЂºR‡>wV^ó:à üî0 ¨N V‚ ìà šù™þ.Š&Y™'A Ж ìót¤ÝN¨_,À`€$2=ì¢þŽØÅ%n6Þ]y§$Àt·Y h€83éIÚ±ð”•âï«o`os2°4mÀÈÀšÆ&±©[€J ÛO¹ÚtQÙXíFlšú²2ÐñÜV :šÒÚû¦\5@ÿsEÊu¯Q¹ l²©n„‘"¡€HZÿ •Op&ÿÜèAÌ’@¾J–«ýô’J °YFJ¦—ÇUv¾4ˆÝë[_ƒÁéC>”½žÊŠÿØk¨RAíaäÒOÞÔE(¸kKXr•¿Ï$< òÊÕ˜Âþ屆A‹a½Èžú”%­Mÿ  Dþ36R5«^ar>±~$¢Í'i1 ÑÒÆe.íw_g†x$Ÿa"õÇu- °<à< ¢R*mù²€½3x¾·-—BÑ·y=Ã5*°)"/ÌÒ(w£|72ûïR0ãgÒwbbv¸«2&d~Ð)P|(/ha-Ø\‡]À€}Öƒ&Ð$¢((Ø^~#zO(+Ų#¿W„)b2*@‘¡è$N“,QRZ§1Ò×OB*!ÈÑo¡=ìÑ c“S8+1Å;ð-°pB…¤Óá"¿ãæ`J’;ÄWA41®"JÞ@î¤dåô4ðR F­F=h-‰âAå·+V)E§ãqq²!Òq[œÁ#ca5  ‘ŠQqwFƒ' ¦CË!@Fj±,$ŠA€ZÒ‹5q€1S0PŒÃ—ѶAKÞ¸W¶Alñ³ÄÁÕH„íÂî¸áFñÀXHá¿x%öxò˜ûøò¸Žõøü8þH8’ˆ ‰¨¨ ‘81ëG‘HÑñŽÙ‘[1;tkabber-plugins/poker/pixmaps/classic/09.gif000064400000000000000000000067561500237002100206700ustar00nobodynobodyGIF89aH`÷?„!))Œ))11)1„9B99J¥BZRBc½R!RZœZ))ZR!ZRRc1sc{­ssZ{{s){”Æ”{!”{„”œ½œ))œ”s¥R!¥”)¥µÞ­­Rcµs„µ{!½1)½œZ½œ¥½½ÎÆœ!ÆÞ÷Æ÷ÿεcÎεÞRJÞµ!ç))ç{!çç÷÷Þ¥ÿÿÿÿ11ÿJJÿs{ÿœ1ÿœœÿ½!ÿ½½ÿÞÿÞcÿÿ)ÿÿ¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þ'H° Áƒ*\È À ?"JœH±¢Å‹3jü±aàÆ C†ô(²¤É’$8á¤Ë—?H®t³æHS¦´Éó"I8{ ­ø3hL£C“•¸3©Ð¥9ƒ6œJ5¡F¨GsºÔ`¡ëìXË–-R‹XND@w# ®`DÌ`ÁÂ#¸ñAÃD°=ñ–¨T£r#" ˆ@c (¢`á‹dø G lK4¦(Ó`˘'¬œD…=˜ø‚€(|`ðt ¶VOL9ó5l•0Âpn‘‰Pü°F†¯ @þPLœC‡ks Pδ±À×8e¤]ň $àÝUï Ð @hÄíà€ÜðFME$V ] ÀÙv4p€v XÂh ƒpà à ú„]ôÁ&_A-NôA™™àÁ^H4–. € 0àB œ"\FÉG_PuÅ£D%|PAfÚ]”€È0@Ã}p ‘ìEeLM´+dôÁ dvãEHxŒ0"=œàA˜YA'|Ë5(‘ 2œ @ŽÀàAŽÁ`ÂX øcq|PŸ½H&Ÿ}àBþÐE0tÖWlICqP€)Nþrª£ "0€Ž6°À›åxÀ&ZqŒ¾úƒ¦³©¦ $l)@e»%*Q_‹` 'nZeDR“ÇÒ&ëÙrð€ m;ê´aÙ@_ÐÀ€”é-Rg¦iïFÆ èc¨ÙØWX7f(V–P¥±í!%+2ŒÐÁ–¶ú8€®~YÀYWð._,€8@· bºQ 2ÈÐB9´Üò.ÇœÌ3ß@X¿ùØà nTî@×ð ôm4]C|«²¬™üƒ |åµ›D·0À ]G?4Ø@PÑcЀXÎ;ÙUV/ºÖ…ƒvPþÍv\Ð ~Âá-äÐB Ppð쓃=˜ÝB½%Üœÿ›ðç ‡þ9 ¤gË€äpi÷Àaï`¤D $œCÊ„]ð@'ÝAÓ-_¯ (œ…:Q àAá;lYDP0/Ð0âœÃÛ÷ÐBî=8 ƒõ´°_ ÈpjAÊ>¸ì@þ¬;Oî—²hL0€– ` …Z±€r„‚ljϸÕRF,î"¸]°ƒ³€ xÀÊÐÓT@hÉ¡ÛUˆ§<±@¬äÜ­hgžìµ;¸1 h¯"ÈÁ Žó€ŒŠ1Ñ~ ¢@4¸dÓì$ìU€è€ÿ@” T\×ì)Fp€êXÉ&[ò Hƒ=@‚-³Á‰» ˆà­ä`²ç*9zKy ª$P@JÐÉÞýϤñ€!w@¸VŠÐoÄ^«b‘â$ð;@  °xÀþО WÊ O'àà²7€ hØ)ÀBè˜ Ì“ƒ , \zdÀ [îÆh¨(t¡Îd;Ÿ×±kγƒÚëè¶Ô¦E"4Œc\feÀ‡ÆR •% 0Ñý .Ô‚€ 0@ X`hÙ÷dž ¡ À Xzì]€p‰Áµr™ÁSUЀ@ Üú¶,§Hb©Uk€2`ÁÖÁU@'€@0 LÀ°À2Í:¶Ð€0°–ÇPz¯«H€š•¬ZÖ©¶,¢˜À0° ˆ%þÁÂX¼7–$@3;ë­ŠOeÚöV©ÈX@tŸ³@y;¢^6oªÐFÀWÝ~€iŒk! ©ÆÜ¨pf \ D¶rž‹Z€C Pªê*Öe™z €«V•ƒ'èÁ&jØŠ*’.èØðhÉü ¹m¯{ÛsáL`boܨ\µçÝBUà›f«@Ly”²¨f€ d`=)õÉH°¶€š5pÍIGTQÖ@€# |0ËŽ¸†h âÈ[µr«,ölZ9¤¬ƒ=øš!×ÖшA a Áe €–¯ÌrO)†ËrP9/jOŽþ8©„ ÉW“S6 P€Ë¡Ñ€XfùÂX~ÜA†ø€lqñ›"0&—ƒ³ÈèJ¢hТ]™ 3±t*Ö Ä(àC´ûB{pÿÒ®´ãЪè>Øñˆ·`1y+ P…ðX@Ήm¶Ð2΢@Hp´ •ú:±dÀ$€È“vÖS#Hí?`KøÆîq(Ѐˆ`I„CÀ™ÂLâ&\NùÐÖ{{ŠœøÃtQ€QäÚ€ë.0ËŽ°›5#zá ¼´¤em­|Àׯv¸ýÅzc€%B7ÎE(.²OþðˆÒ¡¹(ݸ9·;P-€ŸI¦¢«ì1¯Àâwøœp³õ¤¹ˆæ¾}WرÀÝÞK˜…rò‹Ðl7ÐÛm×vdCZØ p»vyPÓ1ñÂîÀ„=^C3Ú¹. 4¥‘Mí¼“1°vJÀìÍ@n@3™ù=fC$ÌGØùƒ„}€ðz(XLÜ•]% ·ê±­èd >P³ ÌN°; K ßÚnš þòÉ×{½%‘+S€Œ€Ö(¤ ÒM B&UÆI¶îYDnÿ£’w&;‹’ˆ£®öƒDº”ɱò{«Y 8·¢°þÖçého»} °áH?V˜"ÑYÀê ÀTþ¡È¨nu|@$ñ¡~Ÿ´ªÚ’&û}q&QËww&zŽá01Áç1Ô@ö#pBq#`/p¡zû¢$ Æz'ÀÐ%ì'‚ÛQ[ßaàR B‚?pP¼@‚„ˆ ¯–è!G H-¦œ9ûµm‚¸#zè#Ç4 þŒ–ÑÒƒ[?˜pKýZì¸,™5€Ù8¯Ìî¡B‡ÔðÁh¬f$`ÂÉ%HA\?dÐÃ~EG”…*U¦ÐDaôîAô)ƒçþv÷x :Ä'€Äñy8o ,» ]Ÿ¶O;t(:zÀ« d 4À• B ·÷UÁ 7· {~€€ /]ñ?ç ëÍ3ïþ87÷x´| aæ¡À€ Ä€ Hf 60®ãxÀÈ_ Öd,hH@.Ah€¼À X^„ô‚’€tLæHðά\ÀÔô€ø=à=@€@ à9ÈÀn@¶8 ðÆ_ðA2{0 ì+0h–5U Kî)€/€ ~H¸ <þòÀP ü´$•. Ôu¥šs„ ƒÀ|¹¬׈ú,ðâ6%Ö JÀ|ñA¿´ÚVØKš…À$™¿¹]€ÿ(4@Ír¶³u€ Dð¬ '€l |pò¹õ„>Xþ­ZU|ñçÚÕhà¯À_¨YYò·ºUš¾€$ ÌMIòf JàL 4@eÙ¬fÛæoSäUĺ,n²«M¦غZiÔ€À LÀÐvVŸål§4PR ‘àiÊ¥'d¥™Ìi..©3s€Z0 ¼ˆ420AŽøq2øÀö:àƒ Ü+0V˼öF¬=ïÌž& 4ÀÁº¥Á<0€8j  PÊ+M§¶ÅD-ÞA'Q 1`q€ŒOÚø;°ÀèÁ² µ5õË>`Q¹$Õ$ó(fu¶g" /èAþD“‚hé&ˆPƒ§ayAÎ"×FçØ«Ägn) g3®jqq#AЂ¿N9©…¬éƒÁàH&ÐZ¦1€v@À Äø-q‹^ÜíZ\@Òtá—×€:jZt#ò© `@NSHÞAç`—%€@8K@€}"èÀ*Kxb¦í ˆäXÐB b€Ô=¸±•¦G´ ƒ‹ $!³@©Ú9áÀ ë<†`þ2ÈüG`OÅÌ<f¸°}q$aJ¤^Ë%-‚K Á ÐZì zÓ@¸ÇÈíé9àAþH€ Ÿ`HÌ—C¦~óáírði|Øðãÿz46OßX@Ì$L ¶àá#÷*0°§Q²~=íÎ)ÀïžÀ} $Ð25™*3|‡Gà>œ`Ðè±ß8/ÌÿH^rq}Ì?B†wL 1 (‡:¸Áø¸§=´@8Ð〶8ÒÌÝ(‘ äƒö|ùt¢ù@ lÐ@¬n"xBu€ÉRï z(¶ Pò½GZê}ú ñ>åœ x0vÓh/Û5¼Jà¿8‘ÊI Ҿȵ€äà¸ü*pdØ@*€‡ÎþÞ‚oê Gr ‚Á¤¬¥?@[ Ú® ]e§óÀ @úÔ,>þÙ Ínׂˆ1qR·)…67²MA4¶$$»U53þÁíF;›ç'#P#S)x€ÔEÁ3àzpv–ãCŸ7` £‚¨ñb'6›Áiá9ç"SÑ9 ¥à'  ñ.W’ƒrñÈ'ïaèW…,’~²)#qá„ÒÁ'p$#P3ï-WèT°±BP6r1,Áò%p1…RÌÓa `‡”3ˆóþD£Ø†D!" % $®§~!P(LW$S%²n6¡—kgȲ &ÐëQ°zã×2cƒZñ&‹ø‰>ZjÒïB…#‡ÅRJ£ S%c%²q*—‘xB°àBé!qŠñeX‡Ã@…‡Csí’#Ëx#1C!ËÐ"à p'b"Æ4˜4…ˆŽRQ!=0#=%@ÌÃu&’°5?ð>5x¤q³|´x«¡¶(¦33ï„í( ð+@h? [XWÔ#¨EƒX‹FAR›‘½™‡á‡#)(ˆhpUñ!‡pb2ÆÈÙˆ`‘eS. I Ažñþ6€S¢ŒŸˆr¦ñ‘Šq~2˜Ø{q!ŽWIWq% Ì¢~âÒ,.P#PÐ

|à1W„E¼¹òýQƒåßÎk'B°€‚"   Pcĸrsì¸py+^š5]ÊìZ³÷ÄQ6!€ñÚ2:ÌÝñ®m‰¸uïÝ;tD'NK°‹ÂCwþ¨AãÃ…'Ò«¨·âJOWg 8b $˜°ðF~»PÀ°•à ¤g—sí¹çgÕÕ0‘ ,@@üeÐ,`VqjÕ€À ž°ƒ™av^‚Õô×D-AÝE$AvÁ`A Ò0Â-´p 쥑_€ &ánµøâD"PÂa FtØ    Ðz$tPäŠ:ö™gL6ù¤D0D BDXäa xœd'\‰ÔsóÕ”f“­ð‘ Ñcj ™ üýPZ|íQ×›„*^¤‚ Í~`à®ÈÈÛ‚º›! `À€C¿”åþ)H€P– 9À€ T &+.¼Ì ?‰ jÛÁ Y‷|à| (K P@€¬¦5 Î x ‚ ˆic1Aïµ ,w] P€ xFä@`‚x Œ F0,¬‘D ÀX8GŠ`N‹àó¶ôqs=@Žè·Áx ` \ÐȰ@$ ’p€T)i‰–gHðà©”¿óÅpè€ØÈÃà|$¸Á Y=ÜR"°ãsPBø€¸ÀþPõ(FæÀ‰-°@îRÙ™F^à˜@ŒÒ’–k>ÅŒöþK‹ qà<` (Ž@‹sÎ ²ç²A;/@xsâ4@Z"»U „„ÃK|Ð È HÐÉö×ô+ÿ hà|€X:Å( ö” /:Œ€%/HSp€†0èâžI @A:A?`F›ö9À ðǘˆ8ÀâîF0|à]|©¹ IÀ/ ÀÐÓ‚ÈpóúË깦×M¬ ¨@æp J‘2ðÛ ‚¤78 s`€‰rÖ«éÏ–½ÌöÃ%ºîÜÛ0@8.(0ªdÀÛmàBzþÀLäˆàiªé@V; šßu€ý<Á ¤x´µ,¡€ P€Ààxl40Û ,Ñ_Œ)WVUó€ :Ð NÀ€”Ë$ˆj ^ð€°äM&HA(pT 'ˆ6pƒÁ©æÛýãÌZ€!¡'ôu€`ŒÍýÁKÉ: Ý€18AḪÛÌÞ¯ª!° 8ž ·K΄v2€Ju`™°d"ØÔ¬éaK~N5^%9`Vh`¥ØÀ,`ÈÌSiÔRdàF°D^Ó‹E”q¸@ fêP°­Å ‘þND´8P² |pT•›ÈÁvÓâ l œT¥ Èõƒ’›¯yÔ(Ãì<©„EÀ–zÚ´+¸AC¥$ÐÍM: P?bÆÐˆàÁ~#XAGN1À°K,£ Ànq$¶eNof3›rÆ&Î4 ñcöe`þàÈ«Ž%Xû3`xa£­Ôª@Úd8 *ûù×.ƒàl÷6«Ó®=p ©eúÑ)“pç£zðkÒ3•—1!Õ"p•&ðbÑ-Q‰A*ŒdÑ£€£u[±-€ Cï,uÒ)1± 'ÀH´=-âõ1Αfƒ.Á8*Æ-IJْ3]ä²Ír)c7&`6 +,TãÚB0…‡1@%¤„ò1´29Ã*À©²? #’fa’2_p"ñc).€ð÷~ H;¤bÉ4†‚V ð8þòÇó‡±C)ÐÄÔ´£#ö'ÑL"pˆj"2e‚ƒfˆ]S™&`ou20ˆ/ØÁâñ×kÒ/¢$M˜€ñ2zS#@;4+S/@/ŠgqˆÈ.9H|Ø$'é‘;ÐNû³|CDh- p!@‡„L"ÒÁ,8!ic4â…`qâ)£ˆ1³Â$8à”g‹nˆÃsmQ;d,Ôˆ¢Ž¤‘a‡h‚Ñ!‚öÈËq‘Q¬d*ˆ“"ò5}·Qº¡ƒÃW»3To÷6Eha&7ˆ)U 8~&q["‰¼Ø@*lB*¢R³8ÝÈ]Q‹¸-²!’#T’ S,aQ‘ѳV!9YQ•Xñ’Xé‘RRI”[ù]“_É•BÉ<3–!–Z‰–%6!–ly é•qykY—11Í—@Ña•€˜X1;tkabber-plugins/poker/pixmaps/classic/12.gif000064400000000000000000000070551500237002100206530ustar00nobodynobodyGIF89aH`÷?„!))Œ))11)1„9B99J¥BZRBc½R!RZœZ))ZR!ZRRc1sc{­ssZ{{s){”Æ”{!”{„”œ½œ))œ”s¥R!¥”)¥µÞ­­Rcµs„µ{!½1)½œZ½œ¥½½ÎÆœ!ÆÞ÷Æ÷ÿεcÎεÞRJÞµ!ç))ç{!çç÷÷Þ¥ÿÿÿÿ11ÿJJÿs{ÿœ1ÿœœÿ½!ÿ½½ÿÞÿÞcÿÿ)ÿÿ¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þ'H° Áƒ*\È À ?"JœH±¢Å‹3jü±aàÆ C†ô(²¤É’$ØÁÒÆÉ—0\ɲeÌ›#Dd)‘'ΟIúü1¨Ñ‰BeôTz´iĤK:…º“iëXj¤JÔêË 'P ðð…³,`°b‹<àîèaBgP»C}Ú¨¤‡PdCŠ,5 ˜ áAŽ;NähQw+^¦]ŸNĬñD *zðà€%LÎÑáF {/άiS¦Ä•.5fØaCF ,  @âįc[LISFnÛ?pÔÄѹƒ€Š&$ þ‘âË þ48±#Ç Ø–+®¤n[m}/î ´…Á0,˜ð ÿ‡ –.”wžr¥4ÑJš½WEœ@Ÿ0E! F$KÁ´‚)øC|éäm(Rô—PÁHðƒ `B0H¤ 4œ–%Üp‰H)ÇtұĞE´@Ÿ %Œfc~d(‘ÞÉ | ’)ƆR·9‡Q 9 @TF„‚D(ô8‘Ô4@xP@æS{5)Ó±-IÑ|üXBD&hd €oÊd׊5Å[‹5¥ !p×èXIÐ(,Qbz]½§ÙGþ)ÜðÀ§ªÊÙhEd0Ú]:ð*F$aÊ’¦ í6À ÐÀ (ÐvdÕK6Vš’ „»}ÀÉÀÀY¢p«D†e7€ Ìrƒµfª¹êGžà¤þÀœwnc“6Š˜ c²ÚS‰ ]`2  B+øv¨›¼]€@„0û£ ìRÄ)&†èV„ Ð÷À' Ã0ƒ›$§|o0@ÅÓf @öÀ£"ç0+ËHŒ²TPtÑÖI†@„xÂÏ?` 3° <°Cd@ òH,Âڼì¬ ÐAO 0³ZŸÝÀ£WË×äÐCþ‰e€àœpÁH9À%9@µ`?0wÝË‘Ðk@‘x€€ ÐGùø`=šù`€’ÙpP 5`I#`\ +Xœ¨‚L@$ðó ì/E°‘¨Ê€t0TkàÔdà ÀVÂ@ðÁ àúàþøàS2€‚üðF* Ð&‹Mb€RðÀ €4ø€6  øå“˜ ð L6ûÉÀì8²µ tt¬MPÀx`X l €|ƒ*™‚xÆåQ°À VFB L@J ðƒ ì`¸bcÀE ø€pÁøTp8² Ñ6° ¶¥€ @k`2(G ƒ4€M7ð@ h>U. ‡íóN °­cà”Ø" r´Ô=°=@@£¼D ¯¼€dzÀlà›*¤.9ð™0ŒÖZÐ’ .Ô+@Ñ$ÑnVþàd 0øÇÀ Þ ‰LÉ -0Ò¬vpƒlÑç žDéSèp&Ø€w>Ð,k$@¦äŽ™°nСâ–#‰àžÌÖ àƒ©@”TPLÆõ™û2Ïæ"cž Ä€]<@$ò¸À*€ À7A6‚m ´pÈœ€”ЃͬyPAþ*H…R @ <€H ð¢ûÈ׃p>@&.ÍÔ øÀƃ p(1©’Á¼?ôQ  Ò¶v0€í]™КjÞÉo`‹ øf@ðÀ®!þÁj¬€Ò€_§dn€>4Û Kl`FÅ“R10LX €L n‹{=ä:d®¬¬ÛjÀȇClÀq±5£v2îê-šÛó ·â"Ó¿ïT¯ÞW€-2Øí3o<°ÈÂÀiæ; Ζ_ˆ‰@•ЖµÈ¦ÛL«–¨`þþxH$ò_Î$ùÀ€¨¡9£• JpùXP€(ÀNâ02¨ pWÆý F‰V–  ¼ó‹;¹#d°‚fòúxÚÒÚ@1ˆPØ,š7„ØÀÖDðƒ>ª2wÙŠbçØÌÎ6­ðÁ°h9ø²tO£KÀ@a"À½2€Ì‘>p³®:˜z7SA 2P¸`…‰’JHÀ‘ËÈ\÷Y|Ø.N`‚Æ¢-Wpl H*¬Á(‚$à1'(ÁP±0ËÆZ>h€>-€ & ƒ‰5_}xp „¢QöޤþL°ä™gÂ'02óÙ€d‰>yí0ÜÐâ Ï8$‰%*ˆ à[s92wéƒÚý38ÂW³tàq’CÀ{]—ƒúPä›Ë[½ã½Ëàäa&â¤4aú´`lÚÜ“ÐÜ6¶:Qdf;˜Ùæi–ShØ:±½çMÄü¯ÍR§¼–Ud(›æïXe9OÍ"#À%íò!²¦Š&)Çàk"«ÖZ°®ý–h|)ÈÙ¬©wâüU+ÀÐáy2“Ýàó„Ùˆˆk‰lÌZ‰©“œþó Û™HuG3€I«oQR‰¬u1y“¬'Û@ÏåþÔ€ˆUTÇAÒ®çXj+gÎ’¥«‹‚íûG,̲@f‡+©„&úÁV™¶R5¥À,?@Dp/0P§ñN²—òšb-Qãs#«F9"óyÝ")e' X®r~A!óç5&p.2'Yò±•0àtÑ" È"€Â cn,Áq+%@ï”|Á2ûà@85B}Ãø²ƒ§¡¨îâpg2„À2æK²€µV!Ð#0;hv€úçpD1}[q/p €BÝ„¡°dQ#à P\8Âhø{k˜b‹A Ã&Fþ!r+YÒ(ôPá Jæg…²¡yà 55A%Ø1 —xRƒ(…Øv!•‚À¢Dp‚zÞg*¡67 g¸Íñ&’ & "g‡S`Ò|ÕP >xUÍQ¿X"âvyã:ð[è»ò9p< „U¬ˆF®vBƒ /,ÑíÇD$k}hŠh’á8ŽËa[#;À€ÿ&gq7"'qâI’‰õH )0‘VQ)Y9ƒ iY‘˜¡’ñŒî2‘&)½h‰+y*ù’01)“@Ññ:¹“X1;tkabber-plugins/poker/pixmaps/classic/13.gif000064400000000000000000000071631500237002100206540ustar00nobodynobodyGIF89aH`÷?„!))Œ))11)1„9B99J¥BZRBc½R!RZœZ))ZR!ZRRc1sc{­ssZ{{s){”Æ”{!”{„”œ½œ))œ”s¥R!¥”)¥µÞ­­Rcµs„µ{!½1)½œZ½œ¥½½ÎÆœ!ÆÞ÷Æ÷ÿεcÎεÞRJÞµ!ç))ç{!çç÷÷Þ¥ÿÿÿÿ11ÿJJÿs{ÿœ1ÿœœÿ½!ÿ½½ÿÞÿÞcÿÿ)ÿÿ¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þ'H° Áƒ*\È À ?"JœH±¢Å‹3jü±aàÆ C†ô(²¤É’$%<ɲeʈ+[Êù&€™8AÖü±3§Ï‰;{þüôæÐ£*UÚ°©S†‹ªüˆâÇ2hÈÈ*`D[i|0p5« *zPÕ(É”lȵhá,Y ø€×_èÕ+ãBŠØZ|ë–©DXD ƒ¯ °[3kÖºõÈ - FtðAqE’ B˜ò@Ét¦ð7¯€ÁnpÀ@ÄNDÄ`Õ4Å”®f=A,Â@½úm¹s[§þãÄ€Ã?þ×(tªkƒ°'ÂxpáD÷*2z ñCÂ… =\x`|)yž UdA{x ?ÀA0HdÂ(ˆæÁþ°_IM$Wz<ýp^AF¤À{vpÁ ‘fà¢%Øà\€¡MEÆÚ\7ÍUQ$x"Š $Рp€ÂUÄä)u^zl­@…=`à 'œˆäðƒd&Ð}iy#€5÷\t&Õ Á¹×B—ùI@DJA hRTãš}¨ãš Hb ïÍ8Q 3’ЂŽ&xa”"Ä“ŠY B¸—Ã{æ'‘‹?LpÁ}‚V@hþIÀ•^dß -¬š—ñE¤  ,&(B„µ^¦Êš,L«vZc{-TƒX&lƒçAµ?< «YYí¬øa”ˆð@ î×y`Á‚.²‡p‚v®œ@ÕXëŠ œ$¬ûÀ¨”ê`D¬ŠÁº¡ð°¾Èb{MÀ@DT€@{9 PAXЀ•¢ Àª_ 48ݾ{›(2ÀàÊT°ÃÞÐ Xp@ À  €£,Z€Ð»{êŒ %¨(ƒ P'Â\À¨;`Ã~-X°O‹€ÀH mõþbœ0uW?<ˆ_pÖmüŒ@´ ã9X÷>d°]6¸€’kU|µÙ ?4ðƒáh`ÔPÁ90:@$`°¬Ðº =x@  °÷i¡V$¨èA .¤þè2pPAè‰ÿ<=l0>`ë-ÄGÀ tžQy0u ‚ „ðšÂ^yÉÆÁP7½| Â¿óHÀ¶ÀìwÞqØ à;“ÔÞì%zÑrOþ ÷·m@•ޱªƒ @@1À D,à@~@œe+8Ðr°+ÚÀþ€b€ À*XA b02ª„] ˜ÀT0¶´àg€@ 2£Fq©=a€ÿ ¬`€Óó@ 0 &ºÊs‹ÁT0:Êåˆ+ÛA 0 •´`w^èèˆ °QØ€"·Å²9&ZrÁ-@öYàˆísÀH‚.æÊl-€ž N 6Ö1t,ÈÞT@‚AÁ‘x'6€Ä t€@ €.ŸÆD÷ÉèpÆEâ-t €"3ƒ è‘<9 Ä8xÀ$€€ 0LR§‘£Š]@¬øO‘ØË^n@ÉUÞš³:Á4@íþÃ@Mí €Kà“òb ÀØ‹)  x@«‚ç'› dÀˆA D `@¸¤B«³2[¹Á6@€|EŒ"Ø úÆóŠ]VIK ø¬ 5ÀG!°2FåÀ}Za@pW7î¥)<0͈qئŒÀ£°hº$½@1@îüâ1r *èÀ±lJv¹Pæ1$ãíÀc&H$uHË «ˆA= —ç%ó0 < ³«†”SÒÚ#‚kN  HWp‚iH¥ÄYÚ*ƒ@”bt=þŸ‰T ¬P@¨p“@‰v»uð€ܳƒÀhè 'ƒïØè•Ç1Qíú§N¬ªÀ–‰cáó¤IÀ"Ëñ (`ºh±*pà‰üOÏsp;Ä@xÛŠî´d`{@€&'`¼­ª€±Wik’Ý~]@&PAÿÜg2ÞNc™)À¨ZÀŽ}Ð&Rd¾asÝT;0Ó ˆ ¾y!€öD°•´a¹¢NHàtµ `jkÿi€É>ø¢¶êU6pMTf `@@¾iF+¨ãG‘XO†]‚gþG ÜÀªm•Üþ*?ÐV h¸á¼€0½™Nð’ОzOÏm rŠœ0u HÜPÃÏ2ÛþŠÉ( íS¬íº©â«dU$(Á"CPOÀp;AfðÇUÁY! Á"p b®p\áY¶¬@•ým lW7È€òµÓn ÓÀ{›-ÀŽÖ:’€€Rl-6²ÔÎ¥V @ V ]—ÜÃ%Õm¥û™{f{¦J̈Á¶ñ)€]a ±žGN\MY†¾¡°@!Ø xÌÙÒ0ÚG©S6ðeÀ Ø\ ÷k”Ãg)@êþžv:˜^à*=í¨$I­0°bH @%mÀɤNþ<òr œ„ ŠÚŠ<â<ñ@@€¨`wf»w™ÜËŸõàú ø\ ¯¤@p%hmþ)m‹ Æ“ \G²¬€–¶•ÐZp¡Å’™±ìJ÷Cwš"¨©ÙÉCµ, Aï1À.~42å@…ûý°˜ ˆ+!xЃX ö„H€6×ôúlàíõ}ߦ‚u…ÓN&¼GC'ºpmk1ûAÞú% j Ѐ@I“¢PÄ  ðÖëô­p–`ED]ð€Ìrþ¯*‘­jœòU˜Ï;ìŠdÓ‹Hà4‘&†>Ú¹ÉV•ESMĆ™2Éb ÀúêñNKÁèÃ&BÁõG/å Ñv ¢%…*áJ!.þq>÷Q)Ó×6 b&P)q5ewÂ2xÕÊâ# C0°( )°"×â \2efÓ%v£0ð\†òlr>#Cô÷AðÂ'¢"scs‚!<™rCX3å|Ð%à+ÿv¢>]…ã!±R…QÁ*‘i`7œ’Èw}¸B"Pƒ‹ñFá&8"[ð/$0 @&,ò'/¡Â%þ‚„¬A†B¸‡Vh'&ä/0P$KhäÖ0+R¢#x†åŽR75˜"cÂ'.bêC`:„ ,á#£¸ìÑ +ð¥"ƒƒ… ò+Ð%rP¨q2xçàA#`7*°„Wä¶t¨!eOV±1? }“Û!cw<-ÕiÛñ/©ây'l‘.˜!ç_ÀqÄáfè˜Ô‘`xµi1¢¸Œð8îH(É$-#Àfa±™Á2@2"­QLѹx)†Ñ\ƒl€A# ¤2 †òÈ[äAA™±daÍãXA‘•Å-Q!hvOQ”N!”H‰Da¨”'!N9P•>1•T91‘”WÉYÙ‘[¹”_é”#aé‘F™–jÙ;tkabber-plugins/poker/pixmaps/classic/14.gif000064400000000000000000000067611500237002100206600ustar00nobodynobodyGIF89aH`÷?„!))Œ))11)1„9B99J¥BZRBc½R!RZœZ))ZR!ZRRc1sc{­ssZ{{s){”Æ”{!”{„”œ½œ))œ”s¥R!¥”)¥µÞ­­Rcµs„µ{!½1)½œZ½œ¥½½ÎÆœ!ÆÞ÷Æ÷ÿεcÎεÞRJÞµ!ç))ç{!çç÷÷Þ¥ÿÿÿÿ11ÿJJÿs{ÿœ1ÿœœÿ½!ÿ½½ÿÞÿÞcÿÿ)ÿÿ¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þ'H° Áƒ*\È À ?"JœH±¢Å‹3jü±aàÆ C†ô(²¤É’$%<ɲeʈ+[Êù&€™8AÖü±3§Ï‰;{þüôæÐ£*UÚ°©Ó„‹ªÜ€4dÈ`P@ƒ  p1`Fˆu!ÃBD(`F5J2¥Òˆ,jûa€³24|ŒF\ €_Àý(`ÀÁ‡+œèQ¡…kŠ)! œM[sÁÛKP(ü/‚Âþ{ÈÁ‚P|Ð"rë¹QX7ˆ="*DÎÑ¡¢ ¤Eì€À<·T| UCíР'L”?d`ÂNdB;ô§`RÕwSƒ­ÐBüµpA )Lƒ4æ–Œ9ä8|i†ÝM±4AEäp…+ÞãD,цÉíÀžf<Êgm äupBŠ@¡Eq=99Lhˆ6Õv\­À ­@ᑞÐ!F7Jô@ðß|oÞEÐExùbd'ÀpQy?”Ñ;è·&| ²éá "°'Âj9dÐB}?À`†=°C¨ ©Gþ™‚ô j'è÷"ª-Ñ©(œ‘Êõ ê«@"¤åG° &…' ÐBˆàŸ º¢Ù<;é±Y媄 <àešz¹ƒdí)Ñì@eF/ÉI'mY£rGVPiž¢àh 089 &x@h›”¡¡p@ pÄyæÈbŽ'ç,˜ ©¿ô*(¼¯b„ Á}8Û‚ù5{Á9W@+0ÀB àuH€0x 0FÏÀ†4ЀRîPidÂ2÷€_;Là— ;HÐ,µ?£°#ÉñyÈp!{€B ‚N#hÎÜŠ?·ÃZ³œþ0À0ôEJ¥@ i?H ØÀ 68nC !G3:`}(t­Ü˜ýwexíöW_Qà:°3°ÝÀÀ -èvÀ—'0€VÒU 8 h`z ê|õÁº±E8p9l6=0 ^Vð×` ŒþZü0¸a~àV4ß— V À}ŠƒVnx~BYX¡€ø “€x ƒé‹<´SµNcù@b`œQü)Àþ#pyσqÁÒ>³}àc[ ñ2äàÀuϳÒ¦/íA`q8Í€€ø}`„þ*9€ LðT`rS p´î8±~¨›z?ôÐ:lÁ¿&@AaXð¢–qj=¨wpèpn4‘,0˜ŒÍòpŒ÷Ež„Ñ.ˆD¦ Æi8¡ÓZЃ|j1à@ @­ lÀÀð€ gp}€`‚T€“ç’àX`H | øI ¨ #@ó@<@‡9zD(¼Ê”'ÄÏ*5˜é†;€Þ+%ˆ‚S•Àp±À îðL5H,@( ¨­„Ë‘l,À8°W¾riéÁ€€@!þøúv€PP5èáÆ€°à/Ì:0 °R7¯<è4) {jÅ’†á› ˜x4Ç/Qnê=@uÓà ìRšÒÄhàÐÍR  ¡ìe.h1ǧ>É w©ÀŠ8p‚è…¢ƒ)ÀÌÀK€ ƒùADP1] ”@@°o/ÃO @Ö 0+0ð(àK©iœ€õª;…ÎÈzƒòI@7Z“¼tV@`h=, 0²æàÌ]`hš‚ŒÕ¡TN§:P>Ý”àž ¤ç.À€¦ˆ€=!´^¦Cœ@(ðþTʼÈY(ãÐr#Ó¼`/± no €Rt À (0£%& ”¾©•Ęè/:â3£b^)ÈÓ0;`XÂŶˆ@–R}n^‚DtàHrK b‚ÿ`À©(À€+{  ô€.øÀ8?}Q(5Z)Ä k¥~385² R`‚”¥•ç4ÐNÂå@¢úd;°Êñ ”.à¡{nd€   àNC&äéʜו×ÊÏL œx½*!œï.P· À@X rÖÄ€‰bd œvƒ¨Š‡TTˆF0 lð þpåÚ”ÀŒ’ED ´€;©q@»z°/§‰é;Fb \`äPꦪr`Œ‚ó1¹øAUŸèÄ `þô] ãB#&ÆczX œ@€p•À0°à ÆuNTc î} ¶83Ñ^E¸ ç”"À~À½Ø€XãŽì ?Äè’of3«,øÓ<¡ ú¢\qú ”, ƒh‡]qAR\¸\—/“{Ô ~@õ¢™hêü€ÜØÓíme Põj&ø´^Ùù$pø°yq(O A7zé†É¬²€Vw31°sÈþŸL¾lÔ/ÚÖ ¼¸WŶp`²d  /耬ä&¹ÇÙÀ+hLëÖPÃè*”}ƒ÷7…½¿ø`àÀq#ö<Ç6u@Õ ­ %zµ<*^3(ìZ ì@À¡”å*5±½iP@Êwò®ÛšÊÇ!°G¼(ÈwV,.7žÒe0À ™HI½ï‰CA(,‘!† ñ9ÌVÅ, Õ¬€C‡×R õ* `€vüзRá:OúJÔ‘h–_‰>NsZ¼6ÀFÉ")8Á¹¼Ô‚åq^·ïÖ–Ú/ЬV¡pŸ$r&•BVÕO6þR¬ƒhéUÎOã|0 H~ú’>ÁŒÄ*ZuÀQ9T„¢’gåÀ÷9?ü3Ó‚ ðg5<!ê"z™ò*E¢/\b&äq0@!iâ%žÓr C(WBrq\@èW$ÐyGÒÈ—"¹WôÁ|Dƒ"Ð 00ùg!ïõ%¡|?Ð-#c%qÈv¦*QÄ$‘˜7!’,%PARÇÒ#›¡{'˜#-°»’85B…)À~,’‚!hqƒx%Ã{'`wÂ!"kÑyŒ¢z<1xç²Ô!|#lÈ"GYuè„‘¡Ô‘‘1Ês*Ø2p†¿ñ„%R‚`(P‡;*ÀvÐ' 0O½AiÝ‘RÆ£@…nò„ÞB‰Á%—HïÅ3!££!=2@‹ÛÖ``>rwÌg`'0 ¤eÁ‚Afƒ¶aƒ! VŒ¼$ò†&8O`ŒëÆðr ½Q‹ …8acb8OÑŽNQPˆC!òxôXDá;ˆ(¡šÂ#q(ñ.!ðHH±É 9±„î8‘É;tkabber-plugins/poker/pixmaps/classic/15.gif000064400000000000000000000071061500237002100206530ustar00nobodynobodyGIF89aH`÷?„!))Œ))11)1„9B99J¥BZRBc½R!RZœZ))ZR!ZRRc1sc{­ssZ{{s){”Æ”{!”{„”œ½œ))œ”s¥R!¥”)¥µÞ­­Rcµs„µ{!½1)½œZ½œ¥½½ÎÆœ!ÆÞ÷Æ÷ÿεcÎεÞRJÞµ!ç))ç{!çç÷÷Þ¥ÿÿÿÿ11ÿJJÿs{ÿœ1ÿœœÿ½!ÿ½½ÿÞÿÞcÿÿ)ÿÿ¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þ'H° Áƒ*\È À ?"JœH±¢Å‹3jü±aàÆ C†ô(²¤É’$%ÊX)ã¤Ë—)#²lù²¦È˜2iÚܹç•<ƒfô T¨QŠDu=šTbçPjlÀF+q¬¤A#† 6lÔÐ!ƒ†Ö•de|HaÑêP·E‹þp[cìu'R@‹£¯ 6úâø Xp µ($"€át*\šr­–1vr‰f–ÝZ–†fÀ24Hôð€ñn1’<»ÒFãÏ,)fVû¶)|1›å‡‰.$FÑ"õÅ”„]7ž¬ù2EÐ$P€@PÀ6p 'JþüháÀx[ó­¦Õ¬£bbŠN´È!¿C<|ÇÃBŽè!àDt5W 04`Á¦yÐA äðà ê'‘X0ß è]váåœ[x±dE&üЀ(xÀX \ a $È×ÂÁAìÐC:öƒe%R6—D%žH‘~,€¡Dœp Îx‚i?XÐ@;tä[?ÁÖ’qxµgQ?d°À’öµ0¥|Z¨" ´Àå—ªIÛeæ™éžDïI´‚õÍ! f€AéaUêÁÖÞ£e #šÁð`TÎHBe`§)8*ä R-ê8Q þ"pê¦ 6âQ \Y*žÇ‘È܉”N” ‚I å¦UVœ§™ fDIúìD :iœ>x`ùƒ?ìJiLe(’œ×žPñm£”ŒÁ€hD0äPÞ©H"%RŠa„<ÐAïºë¦D¥R0î¸"I` &˜0ÁTpÅ`WÝ'(@9¶ 0¾ÇE´ÁèRtÀ2>C -<sëîƒÇ`W±€ÛìÈϪvšÅ\° I;Pq<€@RËœ1/· €LP@úµ0ÂÂSyÀ\¼í¼&Á@8AÖÛÊ'3Ì´PAþL`ÀבÀh =ƒ?  œ°Â·ô€ôpA¶î}2÷`W‡Ü<ìpoÐÇ% b (`™ €k¸@Àî @äpuÔîl0Á¢†«–ª§yš¿»`@¬0qÈàÂJôÆ€Œ(PÀìPA2  ‚ 4œ¨„ŠÀdöA`0yÃMvdÀ€ààÞLð? <Àr˜€6Ð’µåMŠH,ö@$ Pì {±Û ©ö9¿)@-'P_d0Óåi*?8€`0 ¤ þØd7°«¶Q¡ Ð8·ým]#àîC h@~m‰H:ð€ÄXà×€dà\‡„Ü“Av( ðmt[ òG@FQP LÏL0‚þÀÈ¡  Àn8ÀÍ>P€î À@ß `À¯jé‘ ,¦G’7È6€;Ú±¤Û"è²Ê 7BÀfi€ ð$è^!{@í†C‘AXp‚ ` FøƒÀìxpÎ:è87 @è;b € `Œ2x`ðˆº¶ TÃ@ *1@`*@€æyJI ¯€|þÛä0¼ø *VB´€œÀT ^ƒ˜ àƒ<ÀP´Îv€<À%„@À¸Ø¨ <,q£<‰”9fì&€@ ƒ Ä £N=@A`À+ àÀdöQ@^@—žy€òXJ ü jHÛH0\à@Mkú¾ ¨€‚ÄjÜ6à  øbžÊT§0+qµ@uT€²àFŸÊ }°ƒ°QCm I@A]þ†4m­Êð*P¿|Àš^åA rF° ̆cäÀV¢ œ€cÖñò  a5±s¹Øý+TÞŒþÛ.w‚Í: ÍAfÔe1—ùàð‹ÀP° à µ¸€"2›ZB`²wÝVŒzÀ4{q@¥H¤šNØhÕm‹çT€Ü@¢ 7<D+Ø (¬\ýêV ¾\@ 2°@ ¹0)K\ÀÏ øÀD%á¸Àž^ hAÀnºfn &xVPœ<"%šXY‰;7@3IÍoÖDGÕw@€$Ú?À iX»Ê›ƒìE €§|àÍ8ó•Õ?ìÌÓî€,#æP <ò0¢F5Î*`¢Þ<Û0 ÌL€ ô›þuöy¸ø?8&6p‚¹¾0¾ 3øA$‚9*ƒ!*1Ø.Vv÷ hÒF‹ˆ“€Ü;N ‚T£€ù$Ökz—zÐ %I€¬$üÅÔþ` –D+°ƒþ @ ^<#ƒ`E­ÁÀV0ðð]o‡YÒ¢L®e§ô@ÝÒŽ€h—Qpx¾Óîb€ˆ@½.&wô"b‚Ï]’%ܺS0êió×üu² `o}S€×®4ŽHL €Üè­%Ð'¨-3˜éÍM4{™ð"$KeZˆJ«€ w-HÓ Îg€ px>sYÕ<÷4÷ ÊtªDŽ–¹‹=®ï-`ËSЬJ9BÛmèÝ ?Ÿð@FoµHÛ«RôªP X2VC?K<ìù€ÃP°ø $È͸ìþ £Õv` ÎÚ:È%Ý„"~‚T¼‘/ÄKJ—kœr=›²ˆÔ()ׇ¦Â€Ø >õ!ŸR÷G'ç-‡¡$> l1_$‚,öq×' ÒÞ‚Cwñ+f²€Ò€‰s."Û!´Â-°}i€"×Á+1"ãÒ)ð) 'Ÿ!0ÓƒWRðE1ˆë1“rƒÂÓ?µ&A…pr3ïÖ’úBƒ&27Ø=pÕÒ£AnÒƒö‘2 €&Eˆ$Jr$b2&7Ø%>x…r(RR~Y=_tѲ5X$|rƒ¥3Eþ‚%'X#5!Ý¢A( %XXEB8ƒ!’^È9Љr&!2!7Â/ "‰ˆ*31"Å7‡f;€2 DmBµu ”()ïvS™Gg%§PÐÑjÕ  pÚ¡zÁ…5ønɱCá8‰swø?æ` ޾¤úCqèl„‘ê7¦%%\Áœ1¿!DbÎ4‚!Áw^”!É1ƒQ‚APј‰¬˜¹‰øW¬õ,žaA•x ƒI " *¡ë¸G!Öˆ’F¡’'É’Aá.’ “1i’3I“61‚“<¡“ É“0é@i‘4C)!#¹”L ;tkabber-plugins/poker/pixmaps/classic/16.gif000064400000000000000000000070171500237002100206550ustar00nobodynobodyGIF89aH`÷?„!))Œ))11)1„9B99J¥BZRBc½R!RZœZ))ZR!ZRRc1sc{­ssZ{{s){”Æ”{!”{„”œ½œ))œ”s¥R!¥”)¥µÞ­­Rcµs„µ{!½1)½œZ½œ¥½½ÎÆœ!ÆÞ÷Æ÷ÿεcÎεÞRJÞµ!ç))ç{!çç÷÷Þ¥ÿÿÿÿ11ÿJJÿs{ÿœ1ÿœœÿ½!ÿ½½ÿÞÿÞcÿÿ)ÿÿ¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þ'H° Áƒ*\È À ?"JœH±¢Å‹3jü±aàÆ C†ô(²¤É’$%ÊX)ã¤Ë—)#²lù²¦È˜2iÚܹç•<ƒfô T¨QŠDu=šTbçPjlÀÆ2hà`YÆ 4jˆÝƒ¬[=X¬`uhÛ¢E´¨ã"6tàØëµÆÞ½2\øÝ«C†‹ ̽H®ÎÅJ'¢˜I¹2å3<°Ø"É­,m8•èU´E 2>P`Àz€€ ½š‚ ,–0 xê\¯x'¶-ÇE¯‘+_ÎùE¼;Wô‰ôGá™u+šÁ Šnþ´8q£C….zˆî›böÑ–-zˆQ…ø7rÜñÜçöEfÕu,½7Ñô]„Bäƒ'|gE* Л[•&\DÄ—™„‘ X ø9x -¨ðà "@D×kÒ!5W‡£E¤áE˜¢0d°@@ÂÐÁƒãíç" <@è`° +eYF4 AüdßqÄ y-ˆàâ&œðè=ð@½UYUXÑ+˜`Z^òÉÑ å­(B ­pìð@p:Õ•_UfF0` B ™`Ñ7¬(( Á (RbÈ!KÊ•ÁF0 '£¦þ? 0ÑcB(¨¡°zVµØŽU=°ÂGàê À0iû`뙑ð@½ÊÕ™€\0©|)lÀA«z ÁªapBζPÁ°íV*F8Ù @@[ \pÂ{ZP"¬A`«³"(ð€½?”pÕR'\fbdº·vk¨ xpAPê{Á¤ ‘®"¼ËXÃè!lÂè5PA”ÇN8‘©Ù€œd «—+¬ÙpÃç‰B˜÷±jªà# 2à (¤ÃhP€€Ãm`HMØtÿ˜ ^ˆRÁ æÝEÿ#>ðôü 2(á PÁ ¯pÀŠƒ¸%N‡†xRC€Ѐ{É:(ð‚d²„ôšâ °è-.ÙÚèH¤ òÆëÁd@€+* ˆRS«…‘lç¹Á^£€¨í“v € ò‰Ó!š0Àäàý €¸—Üåšúe¶ p® àq˜‹A"e€P`˜h¥pV4 H’vþ  Ю`|M¾p}‘óeØ ø¨¨0@nòtŠã6@8@–´dpo6àoàÛÔeNPn˜njáz0¼Sñ”žg‰M    %l& Õ\¤|+á ÈI9œg¨i\¦XC¯²½‘1ˆMwà•ZâL‡r‚êä¨ëèÀ¢^“ÆäÀ ˜+e:˜ÖÓž- dÞ€7çyM`c¼ @Ør`þ‰Çï„eD«‚µØT?uÄ_¢ д@g®éêe€È€°™ JpÖMÆN‹• Ö&àRkž Ž€{þÀ ÐÊ!§b„¥øøYX(6`æ&ÕêFx¡,n¬ÀX ¶µ€‹–…PÔJ} ø€&@V€@¸¸@TS X>€5‰ l·Ër ²'¨@Zë.›ámÆôà MMeЍèíøXËÍD騗_£d]#Ý¥ƒC€ 4É(yaYj:(›1€ÀD t¨àr0cüv  @Àb#ƒœ•.pœ¦2H+rà^…|›Ð´iÆÊšÀ,5ƒ @.XuÖF§w*afvð,#`¤„þ ¦è9 GòŠcÌ•#ƒ° ÷dû˜k?K :slÛ0 ‘¥@ʪq‘IƒÚñÏ (™xÉKC6Ï €'Ð3äu·ô›ø¦­dü d°¯ ”ÌË€†]“_LÀ‹»›@ŸÝ’ ¡'æy€²&€¬0 (™QËVWÊv· Àò–BXÀMoNÕ`À©»)"ªnÀJ }ìlU¼&ÈÀ°ÉBR‡h}pónÉGÀ Œi„&@fÿ:æä™¼À²™Dõa€§úþ@˜¬6aFÈ{®Îñ&&7€»²£þ¦=Œ@Û*OÁ½[RŸÇÖcvòÇ”õfK ãŠ"€C;òºš…W!òÖÔÌCi_³àµ"¨©¸áWÂb‘ûŠä@´%¼ùî6ÙnÛ€á$ ¬yéQB€ÂÏ3€|€00Ъ-`þÚ©àæ·‘>T“€È~,˜@²•@¶d€ü ñ¸†"‘…U>$fg› " Äe1‰X`¨áN2?EDç!ïÒ7ð³?²,xÁ<¦‰°K$è„20øŠ¨À¤ª¿¦&‚xˆ``"€ÀDôT"yì[õ‰[gäE4àŠ"+¨@™Êþ™›ˆ$\-86Óßëc×2ðP>6| !¿<Q–PÀ§5$h¿ ÎÈa÷ÖW„ã  ™ö-!?#W;¶Öt€›B+% €€BVÒ0NFX¡Ã.?°}ç(2Rsa"&°)h"'”Ñ€ðâ&çq=°ò{)â 2üô[B"/XJÑØAƒÓ£/úá,<ð¿×)e‚lË–ñ³y{bC˜!ú' ˆ*û/®q&0ð{âã¡"â$þb1!²'äR ˜¦„žá3!¢" Ò)9ÐzYhÈ…¢~pdLö!ùq7€0æ—38}†UÐ~q5…7`~qgwS'ƒH^¼‰Ñ¨¨]uq¨…[è0NÁŽøµ1³ÁW-ÅÙ%GÀò3á!°ÈXAd³dÊ8~Xˆ9ò4QÅ(Qe¦{Q·ñ8Pxñ:àp1¨ÑHÓ8/òQga1PbQ4P6à+g=aŽÑäQñPÁ•¸B_HÖ‚GatÈ6á ‘<1I‘.a‘C†‘9 ˆY!y’( ;tkabber-plugins/poker/pixmaps/classic/17.gif000064400000000000000000000016301500237002100206510ustar00nobodynobodyGIF89aH`óÿÿÿssZ9B9Îεœ”sçç÷½½Î„!))Œ))11)1„9J¥!ù,G`þP„I«½8ëÍ©,@(ŽdižhªÅ´¾p»rm×4-Âíû¹`7éýް @‰l¦”L§”.­Óì5äŠj¥U.–D „_ùœ¶…·%€2h×ätûÌÚåEDE7›/k =l¥f§…ªh{0xEy*´<¶uI(„ž%ÁÃ'‰!Ë%£(ÎÐ*É¢–¨Ù"k±!—º”¾#×#¹¢mçí¢éë·/‰éžÝiBû€Û!üõ3ãži¼€2!ÚT@ü`8q€ÂšJTœpqÂþe”û’ˆ™fwZMJµjJ2艑‹‘^`þPÔa¡“—G>^ùèpþbÕ&»Ïâío…ÀÞ?ï**ãçf¿ÿ iÝöͪ‡±nŠþ{Ñþ÷B1XöMOR·žSÝ{µDYfæùõŠo‚YÈRzµé•P(RXß}té'K jidCœ7 ‰ÿ•Ú~V1v^y ¾æ"SÅ瞎XaH£ù™–Ó~¨ÔÂhN –¢Øc8Ý!Q2åʆž`(ÁñÅH6|4 v#p7š‰"¨©àDbÖðgþÞ[-Ɖ y\•e$züjÉ=êTR®M˜£¢ˆÒæ^Õ)HIz'™Õ% ^„´ŒC‘"xfÍ2¥„UÂwji© ¨%a€½ú—’e)™(†x™^ŒÈ¦¯®)H¯/¤˜k JBì 3H2ëähB¨h@b©ì!6à˜mŸÖn±¬u|y‹-¸]+ ¹åŠ{.º›ô±.»™ˆó-¼£ò:.½Kâ›ú"ÑB“=,ðÀED;tkabber-plugins/poker/pixmaps/classic/18.gif000064400000000000000000000015331500237002100206540ustar00nobodynobodyGIF89aH`óÿÿÿssZÎε!))ZRR½½Îçç÷”{„œ”s„)Œ)11)1„!ù,G`þP„I«½8ëÍ©\@(ŽdižhªË´¾p»rm×4-Âíû¹`7éýް @‰l¦”L§”.­Óì5äŠj¥U.Ö4p–ÖnzLŒ?7·ÞÚKÄy- ßGDE7<6JzC‰*„‚2L;‰Ž1”Il)no/œž™0g(¥¨*4# & Œ€¢+®! °m¦´"—ÁTc¼¾ÂÀ$¬ŠÅ#®Èʪ¬r#ØÎ(4ÔÖ  Ú•"åçéëíïßàk(´„êÃï àYTá…†¬PŠKE:Âzp±­PþGq;u£›}hŒiúôqÖ]H†U™k¥™òœÀ”áÌd†ž?vÂØÆÍ:uìÜÁóHSšÍF9ãÑF@@ü5³ªŒ‰{BzZ1CÈa4…žuצ–mCª-áÊy¦î ƒÛX}ãŠ\ÓZf/ærå­ðÀš¤òª¨{A¯ÓôŽÞSj9Df{IóÍ »éñMÓcodÝjc5Á/°O(Žý’4m¶o#™}0á×^­¢ÞTïyFAã[ºâ3Òåç¾&9e Ñÿ”†•{âéŽ#†ÌòVãÀþjruòåAÆ÷+wz´–,¦þ*6ÿ…¦Ç-þf˜À 8|ü È÷E5ÚM9·™hµ'Æ=½çYPö6^~òán6‚^ê}ÇFˆÍiˆI—MÁVzÅq´Äp°(¢YÂýwak¾¨`*¤]~uUQ0üø‚„¡1× aPB÷ ¾x]Ú¸µ%¬ˆÓ‹tCèLx$PcM€hnÇX ¼XsäZ'Rb-æ™ çœd¸H—Ÿ²Ù7#Š jg} öç!\áŎĄ壀Õ!©ƒe*¹×fÊ ¤´ø¡£0wZRª¨%rcÆutªFœZújJ±:9«WjØzë~¹ò¹kw‚¸ú뢎Ê:,nÇÖB²H ´à˜)ÐF ­;tkabber-plugins/poker/pixmaps/classic/19.gif000064400000000000000000000016441500237002100206600ustar00nobodynobodyGIF89aH`óÿÿÿÿÿ11ÿ½½ÿs{ÿJJssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×t„…^Ü@`n×Ó~Á$lÐ…œÊhŠ …J¯$ꮹÅzÚg÷{ sI…Á€ "¨‘¯ôºý–™­€¢/o<Æû?z~Kbg‡}:Š‹l)}‘F+w]‹Gš*™‹‚:/L‚pš¨x&©¨„†|ƒ!Ÿ¬¢ž´F£–…q³©p'i·¿®/n½‹j•'ǬÊÅÆÈ}s+nÎË*4lÜ%ÖœØÒÔÅ:ÝêáÈèr•Çpâ¸äÙ»¬&÷ò€°ö„ð—O_ˆv‹ÞõË„n#Mô4˜ÕDEˤ…:7£]þÛªÀv«‰‰ºÚ ìVÃ',Ú©cYC-be@¤Y£™/tQb roœ¡QŠâû‚4i<”eÌ£ƒsà, S­V%¥S…©€±Iñõ+´‘!v °Ì![µ\ah|Ù‘ÄÜdgS”4¢b¯*MM¸Ä›bð´¼(l:fB±/Æ€»¢ð‰êY¹Á–SÂP: ªÕk3$—«ì™i;¢GwîùGjÕçJÃ[êú†5 ¬cß\­»_W“"Ûo2dŽ#?*|9ÌæÎ¥(‡D<Ètf¾“·q}6n·‹èÞñªxӢ΃~²5x÷¡ßŸÞlîûöŸ}•æL;n4Ìö•þ lÝ9Vdhv‚Æá§`-…í• E+ø5Æ*~!vÂ]‡Õ5‡¸hØOZެÕ‰’ˆØ@f}†‹©ØXfõ”×_4ÖßJ˜yôÍ÷œü¥GT @ޤ†3>BÂSI¦` ' :éÎ2Q¢ð Gà­TI–C`áI* ´Ž`nˆ”݈pe^(RbZ€f¡P”‰PVŒbÝ(?ëå¶9VÕ#9í°sf¡1ð×d{BŠÀ7à@‰_ úEšŒ2 eœLŠ&~S&S%¢Ã¬:žƒÚRÒ„E Ewcê•!Ý +(ti©ÉF¹T±ƒ¯›ÕÉZŽTÀuˆÈÂð§®òJ-XÀ{Y‰µ•W‰2¦m´Ñ%1î`–;èТ»©ºB.¼6œ«)½@|5/¾R ´/¿A½ °. E t ð /|@;tkabber-plugins/poker/pixmaps/classic/20.gif000064400000000000000000000014601500237002100206440ustar00nobodynobodyGIF89aH`óÿÿÿÿÿJJÿs{ÿ½½ÿœœssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×t„„NÜ@`n×Ó~Á$lÐ…œÊhŠ …J¯$ꮹÅzÚgׄT–ma.Š08ߨî™@¬®— ƒÀ ÄëùhsjUc#y:A‡z7iV†Fˆ7‹’8‚NE>%™‘q*œFžS—[Eq‘©€/¨©F«/40”©‰³®F¶K‚·¸Œ½¸º±¼"°$­¸Æ)Ȯʣ%…$ šd'ÓG–ÒØ(´Â#p'Ý#F)‹ÞÅy{á¹¼ÌÎ!~í&é'öô*²¸)àðÕ²ÖFHQ¹*ሧû‚¨j¯x“êL×Õèoui³Òú¶oݰÅsÅÚDigû'\…[µ¿åDÍ];ÕmÇK(ÝÄm¶ô¼h¥…Fþ÷{ ÁÇR§ÿSØFbòá¿7ï¾{lî.½ÌÅ’]Æó>%ôßgVYAD#àpÞMçÆ»ùÒ› åèpv›É¥m2-ƒP ŠðžÛÉwÑ?Vh{7)7zYMD¡_ñÕ£$1Ša–^yÎBˆÁ5†KmB šØb2Ð9XU€JÒ(\kîÂsÞ·Âÿ5Ȥ6Û@Áà~œÉC'ut$•ZÒ1ÈàÚŽ`’f”wÌ蟞n:!&ž›ø(Çmá'œ€âgF vþ™Y"ú¨‘ê8i†îàè¥/¡¹)§oPó)¨ü%Jê0 œ*E tàê«°¾z@;tkabber-plugins/poker/pixmaps/classic/21.gif000064400000000000000000000015621500237002100206500ustar00nobodynobodyGIF89aH`óÿÿÿssZ9B9Îεçç÷œ”s½½Î”{„ZR!„!))Œ))11!ù,G`þP„I«½8ëÍ©4@(ŽdižhªÆ´¾p»rm×t(MÂíÿ¹çG”厢r…å–PR3ôŒZ§€ª¼ ‚€ð‹É¶§P" (tÍ —Ï’&6`èÙø~Fx$'o7‰piƒYC'€7”8 *‹>œ7z&f =g/£{},¨0¡$t<u*²}´q¯)|“¬/UÇ%(ÊÌ*OŸ#€¸Á&Õ–LÓ"·œv¢œâäµÅƒâØfcYóæ'÷õú¼!κ(J †(ø‘pÂÂGþ0@Û²$²$È(^éE >þJªP¹I.½NR4™/ =ü.Ù÷qMˆ5¶ÉÐÙ¯†³‰0~âÜi žì9ò´T& UO½´†+©5ó¤Ì×Hˆ])ny]Çíè°@1a0z‚eÄnø'±ç mEuä]uÍš¤²©Ð+÷v)¸t„“>uI&IÚ½öï“l7'1ÞJ*£a€‡mª®2å*„gЂ¢ˆÍlÅ­>Ô^`ëÃmÐa@À®TÔ/(¶Iœþ&X.9Ã9•'Ù1e›¦j¹´^樜[¶;VñÄ’ÛûN–»Ù¾HIà½V9Ý ¹G¼·¿„mÙ…u m¿ûˆÕ³þgKW¬¹fÞbXEÚTa‰Õv)'_S6dvÇùÅÞ2U!}ʽ°¡ #¢ aàÉ Wj3=×"„Š©Ò‰2²X##@ã±x$…<6³FÌìÈ#]ì(^ Kþˆ@ ߈—aVW$1裃-eW—{¼3N ¶6Xy%˜i\k@Bf÷õVâz`g”sáæn@3QœûùrÖ”:â  _¦I`€lº£M^c,‘.˜•VJ”ik+$#”²g™¨ú=A£‡‚xB!‡ôê_fXh[xþ—âSå8Ú¬;Æ4‡‹»þe$X {c±µ9+¨Ì"*k#Ξ'l²ÑòU¥±Õ:Am¶ZÀ­-à7̸ä–ËC;tkabber-plugins/poker/pixmaps/classic/22.gif000064400000000000000000000014551500237002100206520ustar00nobodynobodyGIF89aH`óÿÿÿssZÎε”{„!))ZRR½½Îçç÷œ”sZR!„)Œ)11!ù,G`þP„I«½8ëÍ©\@(ŽdižhªË´¾p»rm×t(MÂíÿ¹çG”厢r…å–PR3ôŒZ§€ª¼¨K°ï)ÔŽ„­¶™³É“°m›ßÌ…@An¡ÇÊ~/O‚:†)€<8qT |‰&‹C3Ž+hi/›0o%b(¥¨*Z{%Ÿœ”:¡L™y¯g¦³–¿N™y¼‡¿Á}¢ŽÆȪ¬&ÓÕ(4ÐÒ  ÙÖßáãåçé˜(Ã*öcq'  ?üMè&Ž¥{[Œ8Ð# Ä[ª”R±H #æÊqG.þcP¬1—6EPÞ ©éÒ ;ë4“Y(¦Œƒ5p*¼©!°ž;aĺpKQ-P>=ޏ¦¡$¦œzT‰jC1M¡T³š^‹~uÙŠ%,_^]Že4ÈìUSb©ŠAê#‘ìÄ‘3‡..¢òºãÏÙÉ@g'õ)Å- Ò²*²ä aàFéú§*ÒÍŽy*e-b7,‹ {•j›2ý§÷]_ùVâ¥=ÖÓ«ïõ-ïk ®ÿ­ÖÜV(ZEÏMzŠ.‰BÎÀ­bçï ‹žùç/æú`sÒ/®ŸíK²üåÜ´ž€Œ€5aÑÞGú0˜ÑjsÑ‚ž0QcžÔ0m@˜a23yÂk©)g?pVàbÒ“" ³µ3Üm+ÄXa¬pÍ]Æ‘g y:ò‚iËP§ËŽSM7tKް †ž¤WÁ€gH©ž!ÈðX£¤pyÂYMyO˜WØR|gÚW%‰ß~JÂé!‚èß|w:©Ç‰u‚¸âœ”¼!"-V9Ë~ƒ– {ù%Z!ŽFiŸNú!lX\ ŸK‘F“–šZDi¨%L©?´`š)¬¶Êª;tkabber-plugins/poker/pixmaps/classic/23.gif000064400000000000000000000015741500237002100206550ustar00nobodynobodyGIF89aH`óÿÿÿÿÿ11ÿ½½ÿs{ÿJJssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×tX|qÿÀÜŽ×e9žHylª’eÔI5A¥Õìèbj³B"±T "‚Ù+ŸÓk¤`4Óžz€­Òçñ3s&;#b<†‡h)‰bD‹+9w|‡{˜*—‡z<›/“={$˜§^'¨§0£E$« œ²D¡’‚+eµ•ƒ±¨½­¹*jÀ‡f‘'Æ«ÉÃ1jÍÊ(ÑÁÓ)9hÚ%ÕÈ×ÔÇ â(4<ÛéßÇo2àå8‚«&àñ5ùæØ‚ì‡ÜỤÏF´‚B<‚D-@?†úP]1''*¸í‹–IþÝÚeôXD·‘$å|Kù‘K“^~‰ÙÇ™Â8ml0æë‰Ë~Õh¨¨ŸË0-tXL©Òg/È} pë„TMPWÔ£b«\0ȪjB,Ö£9yõ$±K–0´/˜CøÎ,Uº'hŽ“×.Þ¼H÷jB¹Sì_Àûྮdb[ÊÜDâY(Öás‹Œ\ª‹EèË4SE…JÛ¦©dCoÉlÃkª#¬mØCÖHîm›­ýñ[ž™f—߸6¯±É ´©þ<øÛt•7¿s^ôâÛé™´Ìœüêèá!o§Û8Ú,N¼öh“2xáÅ—C,*‹!³?:[)²1H{,µ2ë)¶*¸-·Ðë› ˆkC t îºì®{@;tkabber-plugins/poker/pixmaps/classic/24.gif000064400000000000000000000014151500237002100206500ustar00nobodynobodyGIF89aH`óÿÿÿÿÿJJÿs{ÿ½½ÿœœssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×tHU6‡å#‡M'Ë@>kîöóD.I¶\Óù1S¡0fZœ–jꥸV~ ëJ]&6š éµFHgµkzâ ±%ȆÍXÖÆ³”aƒ`ÕM‹Ûœ7O*k =l/£¥,¨—[¢Œ™y±¶u¯0‚š’ƒ/¡Ä%Œ(ÇÉ*OŸ#V•*ғ°Ð"x¸œzdœÞà´ØÞ–kh`îâqfïIò{!˸(¬DþŽÀd8q€Â' ¸/@³/ErKR "”P̳ïK( þE¸9ܨ$”kYL.Yöð"¬((±¨\ÙÈãËfH :õ.ÊÌ"gá" êæ^|ùøi£á…–@Œú°FÍe‘Ê…ó)Õ¾{õˆµÐ SK$ °°DZ#]Ñnå8®˜1ð¢«Ár‘¨ÎâžÐû‚p`¿ü<ÕÄ!x„*V<Ån˹j§«½+‚ÞY‹Çæ\˜«Súh´®NÿªHèô ªbD‹™;t ¬ZÏÉ¥“{¨ëÌaá½Eìe&;ºœñµmm@k±º@ˆÓm’mž2yŒ¯ñ‚s½Jî[Ý’Þ W¢=Ä*Ö‹ÑÃ4í~‰fϾëÛ§ ù¸ü/Útæ÷…a{¼t–b­‘‘8RRÛ"ŠP”LƒtéÆPHBvn‰§–A'h%¤íÂÝ e˜xÃуŠq=¥C;ZÀ€›yŽÃŽù‰ …°µ×Ïzxýè|‰)LKÄ<$}CvPâÞÇh»áw¥d5ÚÈŸe1Þö¥)þ¥ !Šñ]˜¤ ™P™^iÊ`Jgê£ZSw–ÐG•Å™WUz2¢ Xq©c¿81Ÿá•ù‡&Xà¦uJÐù&¥‘ z¦Qu¹)§Ô}Ê(¨} 9*©mzJª~«¢B«J´€0´Öj«;tkabber-plugins/poker/pixmaps/classic/26.gif000064400000000000000000000014501500237002100206510ustar00nobodynobodyGIF89aH`óÿÿÿssZÎε)11”{„!))ZRR½½Îçç÷œ”s„)Œ)1„!ù,G`þP„I«½8ëÍ©d@(ŽdižhªÌ´¾p»rm×t(MÂíÿ¹çG”厢r…å–PR0 ô¢X'µZÉzÓÊ5X–}MnJPûØnã6mÆeöý9òn~V6aC%xw*Oy†‹'‡…0|km/l™‘&–'gd£¥•["u˜š—²L¬®$“ž:‚/O¹»"½¿Éb«­Ç¢£¨ª)ÔÖÕ¦ŒTÅÑ#    ßdæèêìîð3T(Ë+ýhôe8¡€‚‚'De’¿/ùõH"à!ÄgäÄû±  þKà\’R’EYÄq«¤//(ß@:Ù’§ µ–Ĭ±MC65ßÀêeg¢+mEif²ˆÑ=tãÖ1 –rçÒ­k÷®ªUˆ!> •"a€…d¿Úi3§@M c¹V\gtåâá0/Œd+¿ý;ô‚[I…-F16*†Ÿ¡®e€œbìM¢³bY´lSDJ7uVñy.8Q§bó"µTo_`¥·õk³µÚënÒ:¦×0‹Öq=A/zL^äø—±¾G2·‘»W|E§Ëp-™2èÿFCOZ<Ð¥‰ ÿ®¬ªäÇ·…‡LOa1özí.÷Ò÷þ-òé×Ç‘FRàWh€LÄÌòe_€/aàÎ¥EA'ì#¡LëñÜBW]m¼­0ânØ… N»4ÖÝkT©Àlа¨„xfžŠHÃRåIB.Òl¸ }<¨’õ-R¤‘&¾ww$86e|j†iL*Y`~{…—Á"ŽdÉ—"5ôçá^ªtW\fÒ!W‡À øeœöáå?JJàƒy’c†- ݨœnšyè}†B¹¨Zr>ÊP£ JZ'%•ZÊŒI™jša ž²B¨J´PZ0¨¦Šª;tkabber-plugins/poker/pixmaps/classic/27.gif000064400000000000000000000015261500237002100206560ustar00nobodynobodyGIF89aH`óÿÿÿÿÿ11ÿ½½ÿs{ÿJJssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×tX|qÿÀÜŽ×e9žHylª’eÔI5 §€€¯ÊåCmw ¸ŤÂ`@ÖÛ—ší†#Òü(,æÇS~`gOx!LYXg<Œm)g“D‘+Pz!Z*œ|< /fD«ˆ'¬«0_a„¢¯¥¡¶D¦˜†+j¹„%¿¶Á±½*oµŸt’k¯k—…1oÐÒ(լͧ½mÞ%ÙÛ+ägæ¼!<ßíãËêçôöÓ‰°óº×0äòéƒ×Hž‰j_ üÇ-D%KØ0”Áhâ:v“9±xqÁoþ7æ\R&ìÈ—pñ8¢¨Ê*O<”Ø)æ dÐóTÎ%N#¹Îø¬²sÕ®&/ƒVòGR Ê %´ñjÑR6ovAç¯KU#\§:ý¹±–رdq:‹6mÅ´eÈVÉÚ†È:ÆìFÃÛôÄ×aƒ¥’¸eC…5k&K 錤êáõÉñ‹ DT`n•â=S€NgÙ×èz}uœÎÛ1Ù3mb£ÂÎêy×t6ow-­°([‡¾éÆ­V¸ÚrÆk÷Ãz# ñá6Z­÷zt‰GÞÞP.óœ÷ºc´“á}mõÃ[Íž×Ç¥øòƒ{•ûC7ó¡Tdý¾ÉRm©áþ@Ÿ §ÝB|šm†ŸUvà€Ä1FÉ‚N°X}% hÚ6$AÒÂ…M;†¢ˆã|tɉ‹l¤AîxaDë9„L«D¢tõ™wŒD¤¡sÍ©gÂ+&ÎH‚{áó<ïÄh]oFÑ¥›=Þ€#N’ԀƖ}ÔiÕ›—±½¶mJ‚±Z€ÿ Œav” J¶Ç`p^¦` ›)BJÜ5 ‚’¦ "Üͤèb(v(äYˆ§ ’1"ˆ¦©‡vèÅ)k"ü™'ŠGÌ¢¦¤ž°Ã€¢šj ˜Bêê«—b‘)­?ˆÊ%®!M:%¯HÍ , €0ì-HÐÁ²Ì6Ëì;tkabber-plugins/poker/pixmaps/classic/28.gif000064400000000000000000000013431500237002100206540ustar00nobodynobodyGIF89aH`óÿÿÿÿÿJJÿs{ÿ½½ÿœœssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×tH}ýjÙõí×U|±±t‹µ×tðjÍTmíÒÂhV,Ú1[¾l#ë Ï„ßàb•ó›§Aü–aªšôèŸCAsaLv3ÉÖ•Á¦Ä-#òî.‰owÁ˜&⹟Í;†o*´·Q6r,ºtÝ?œ%Í(û͵íKÿ€ ÅæÿIS±•u¯E+\å}ˆî ·²‹äÞ>€Ì•’Gžyà]g›Ø‰ò]tϱ ÚѶ\*†±SmÈM¶Wh†àt®47á #6v ƒ:—¢‚ia]YµU ƒ¼`Œy‘@#ïá7—~'ìXßâÙP$‹œ I$jž$©¤Re`AÍ{Pê(%þU9‚çiYU$.fé¥Nv9frgîBšN´ ApÆ)gœD;tkabber-plugins/poker/pixmaps/classic/29.gif000064400000000000000000000014461500237002100206610ustar00nobodynobodyGIF89aH`óÿÿÿssZ9B9Îεœ”sçç÷½½Î)11ZRR„!))Œ))1„!ù,G`þP„I«½8ëÍ©,@(ŽdižhªÅ´¾p»rm×4€Ý<Ÿï½à, ¢¡r•%„¥ôÔ ‰©–T$Ñ­¸‹H¦‚ |C«Ù²ê1‹" (x̎׿ª~#7„6U_*w7ŽxŠD#•(ˆ†6šœq˜!]%’<¦7¤'n †o/­¯,²0«%|›}*¼Ÿ¾y¹¢)ž 'ÉË)UÒ¥§(’×*M©ƒ¯à*žá…Æ#Þ"Á¦‚#ëí￘íÏnk:üÅ#!`Ás²MböIˆ-U•4œ8@á@Š,R ¡˜-þ9¦™öqŠ0JŽ9FAȺAt!÷Qf…ÛL“BseÉt[lÖ e+Ö?S‚!BTLŠÐÍ.<‹¹ófµœT§fÎiUóÜÁCš4Í?"*—<åñ°æW`fãa  qW\ˆ6^¶‹ãm&q‡²3’¬Lü2ìZ£ç` {܃hC£0Õ¥qu׽ʒ–Ú«z˜µÌE‹ˆ*x1‡©TTs¼Úˆöç[»î¥šì€¦èñ%Gøhn¿ÞE{wEAæž³m8“:åsëÚÈŽ·¤÷Ôßï ï#9ùë烚O?„½O÷ ×ÃG>Ÿl}%ã朗_ÿ=ýÍÕ'RB×è^GÖìww<0X‚D:ÈB[ÓÁ6Û§Œ÷œrÑÕ±‡G­¦; ¬V=Ädvâp&nàp•21öÔZbX[XI“ÓZ¬1¶›>ø›R¦5E\/Lž†Ð,›ÕÒYˆgDYT‡¾I梖ˆÐE€½Á¦—fx)_a= f&$T­dÝ‹2è•‹$|á‡i ÕÜ e˜` {s*¡{O2hzW°ÉÅ¡é]F‹ž„‚ú%fA›™fÕi€ð© -YÍ©¨¦úI;tkabber-plugins/poker/pixmaps/classic/30.gif000064400000000000000000000014251500237002100206460ustar00nobodynobodyGIF89aH`óÿÿÿssZÎε)11ZRR”{„!))½½Îçç÷œ”s„)Œ)1„!ù,G`þP„I«½8ëÍ©d@(ŽdižhªÌ´¾p»rm×4€Ý<Ÿï½à, ¢ ¡r•ƒ¥ôÔ †©–TÑ­¸KH®ÂB´­z̪.¿U%j“dR¿í}2U_o1|kD#Œ'‰5‘Š‚!]"”’0›•0™q/p¤‡)¡%WP*­¯/]z£¥)§¹©T—¶$ž†…¾&MÂÄš€ÈÊ%9ÍϱŽŽ³(ÜHäày(4ØÚ    ç&íïñóõ÷ù~aÊ€BBµNÒì0ÒpB=N€¸(Ħƒb*Z”CDÆŒþ8€ hƒä’*–Щؔ?}¸TylÌÌ9b†ÜbLç-¼0è’²ªä7 ᔄ Õ”¥2ŒUðÉ䦟hTU@1Î[…¤B¶ruO={ø´ˆ½šÕR“PŎÖÕÑ šº,ãäÒ‹&›¶A§X©œ bMý¢k¹num½Œñˆ}eý¡­k…l¿³²ÅÙvà¸sm@̲úÚê2±[÷­½ÇõînÁÛ?ž¼Zîæ•§?‰~}U÷!}w?’K{÷uÈïþŠ‹ýÕÄ0ZCPKz%ÔƒAè¸pÇý“ÖÆ™%¡êd ,»Ý†Dnϼ6Û.'Š€6&®†¢‹#£ ‚£qPYc¤afÂŒ4žñg ºB܆x9õ_ŽÜØ`TøäXo&V“TƒD”R*Hel˸1Â|ûq™ØAG¤æ~JF•¦_œsæ6KW”þ€—_Þ·Þù¼ÙÝxæY§ Ž„Ñ„ŸÚAä öY (£ÔAj ’ÆÐlÑdªé¦D;tkabber-plugins/poker/pixmaps/classic/31.gif000064400000000000000000000014461500237002100206520ustar00nobodynobodyGIF89aH`óÿÿÿÿÿ½½ÿ11ÿs{ÿJJssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×4ì|pÿ¿\,Ê„>À P0:W¹Q!0xZOÑвy펲€iÕKïNa¬Ts_éµhà> H[Ó”×ÜïÞ)~La=€*Yb%KC‹=l'<‘;)Yg%CL›*šC‚;ž/—I$›©˜(ª©0¦& ­£Ÿ³<¤Pwp²ª†%i¶¾¯º+t¼Cj•Šj­ÊÄ1tÎË&Ò½ÔXÅUÛÌ©r0ÖÉØÙ!;Üéà=âÑÈñÐ:ªÕ²ôò·æ(4ìCÜá  O†´‚¥tM¢„bI¿ƒh ¨âá8 9¼ñàv#›cþ¿ŒDÑÈц >…ºdñf±Ú¦…-눙i“(‚WÀ±Õ#g1'Èzù¼lÖ0+:s†Pbrh&ô•Ÿ—¤Eª6-‚5k>©3~>Õ´U¤Ø§TȈèê,޳ži©Ããº2Wœ$ÄNʽySÀ|Yñ%á©/‚ÞÄuBq§À¬x®:!y²%¸±$3ÎÌs³?ÌÀ‚& )E4<Ò%ØÞ5M°lÖrsí»6MÕ3E»ÎN*nÞðÀjû8A·m¬¾½qùÜã7ŠãI›•º éxž8€]-FÐÞU‚t={Äﯚ}>ýõ÷‡æ/¿ŸyjûýÍÕQÒZHÒ#îŧ‘:l$¸ÝL*¤JYW¡9 Q—^s@ph‚„…Ð9» 4 5­ˆX`rÁÕ0\ ì¬3!wVuâlåÀÈ‘7шcTµMÖ8ÍôâÚRFÆô[QΠ“½8ù…}¬ÁSKg&Xö[e§PVY–]ú˜˜M¥àX2`’ðÛ`ŒÆÈa3 2e {¦B)c¡˜uÅ~â…J˜|hŒœsê×2 ¾—ÇŠêEÝ*²çŠŠ‘ªpi¡™â×é[ |C t`ꩨžz@;tkabber-plugins/poker/pixmaps/classic/32.gif000064400000000000000000000013061500237002100206460ustar00nobodynobodyGIF89aH`óÿÿÿÿÿJJÿs{ÿ½½ÿœœssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×4ì|pÿ¿\,Ê„>@!@0:W¹!PxZOÑвy펲€iUÅ5–màÝŠ08ßØî™€´UÁøvÏïsRT*x;@…y7Yj)‰†7Š8"'SCL5™Cq*ŒI&Kš;v¥¦€2’=‡0­<¯0`Ž©“/±r%§#¤¥¾(ÀšÂ(i)=ŸÉ¥ÌÇ•!SÏ’³¬C×´Ñ<¶»‘²‹•ă'}z@鯠•¥Émfòä"æíÒkúAÜÞNp^¾D ³É»€!9I¤í |°²!¬eÆY@ŠënAD3pá­†þF0þÐ…ËŠH>½œ|cQeÇ'Ö&¾„9N&B%xÔÙ¼ ðæÊ"ÔœüÄô$hŠ¡%zQJ‰OÎÞֳÁQͦ5bR•ˆ5†2FI|ÝV  s= jIÉ+I'Þ®rû‘n*¸Xf¢cû-µ õbjé•ð¶­®Ä%îŠ-â’mkü1™± ¦oèq\ZÒ›E>ƒæ7º´èÒ–Qw9­úpë‹‚_“–½:6íÔ·=ÛÎ=ªëÜ¢Dü¦=Äð×Ýv|¾›è?Ti™ÿÀlƒúxúY'uoôìñ®¨Š"y€åà_Uï8iAé— ¿ûÞDðô}ù®ð« ïæ!ÈuÑ]s XŠx$è ü“_*í\‚ß|ò­Qáu÷¦UV\¡ !¬‘§d½Ô"€¿t§N(ˆaŠRh6Œ'|x"gÏ¡Çq­¹ø"o1Ôñ0øx ¨aw#‘+(‰$Oò6LÞЂd©å–Z;tkabber-plugins/poker/pixmaps/classic/33.gif000064400000000000000000000013661500237002100206550ustar00nobodynobodyGIF89aH`óÿÿÿssZ9B9Îεœ”sçç÷½½Î”{„ZR!„!))Œ))11!ù,G`þP„I«½8ëÍ©,@(ŽdižhªÅ´¾p»rm×´˜Pwïç ÏG”åDqi ˆ€Ì(*gH¯$jËÕ>'‚` øÄd³Í‚ŠÊ@]ƒËé30€]zn~V8z|$q7ˆrkzƒ}[6’y#~—%ŒŠ=7n(h Vi/¤A‘,©0¢&v‚w*³‘µs°z*›“Â'PÈœž(ŒÍ*@ ™U¹ÅÕØ×/Ó#¸x²äæ¶Þä›he{ôèacõNø˜ÏÀ™0U„`(0N pÀÇ …¸‹Ë•Éœ$³( þù82Dd”X&;úJÙe%Ë‹._žŒ)s Êš?hâ̹fO•?gersÔ¾0üI¬sî†8¤)ФTÃÒR£ÅÈz5†ÕJTÿÕ ¶H`“«¢ª·"m«µPKH KS»QŒìîŠ;b.+b¿–e“«óÐ2­Ê: 6VX[­¯(,qÔ+©ºrMSˆ[—y…ß{Gí)½º_èÊ€Z1Ø5ÆÃo¼Ž}vèÈÆ¶=ãÎu7oÆ¿{|Þ×7ñâÇ %¯½Ü]sÔÏ¥·]²Íô¡Ñ ÿ™`³í;)2³.›¡Có&î¹.‚u÷†/xúìÏô+Ò©ì³m¯œ$¿›a¥vW—±³W|ã}ƒdÀ`X™å—xò©@¡ˆ!£•_À`0X^ð!rªä¥ 3|Õu"/Î%5F)oݧً¬œ"£teUô‰YèF^U.$ˆTÇ• G¦à24èÕë-%S¢ÕY…déÔi[ÞHâ”`>Œ”ÑABftR‚7J06_¾9AX¢‰£Sž%´â2€*¨;tkabber-plugins/poker/pixmaps/classic/34.gif000064400000000000000000000013431500237002100206510ustar00nobodynobodyGIF89aH`óÿÿÿssZÎε)11”{„!))ZRR½½Îçç÷œ”sZR!„)Œ!ù,G`þP„I«½8ëÍ©d@(ŽdižhªÌ´¾p»rm×´ØPwïç ÏG”å Cqi ˆ€Ì(*gH¯$jËÕ>©SÜó† $AÁJT³mfZ$ ¼mõû ,çσ[xMtƒ#uz+ˆ8|€Š’'Œ‰„0jk/›0%d(¥§©*hJ%Ÿœ•t¡+PH°‡v*—”¢H¼!Á´È¾Ë#GÇ«¦¦Ô­&ÓÕ¨Ã!ÅÑ#    Ø'äæèêìîðS`(΋¿7hì3¡€‚'„&˜?.™‚Xq"à!Ä=$Àw‘”!þ£Œ )òÉ.&O^©ÒcÊ–LX ør¦K›+k⤹³dϘ:Wp¬14WÐnŠ$å)(’ ˜#2*Ö°Ôy@n×h›!çä†Ç]"c•\™Ü”Gö´‹–ÃÙHåq4ÐÛ–R¢É$j–Ђ¾Ä)çœvD;tkabber-plugins/poker/pixmaps/classic/35.gif000064400000000000000000000014101500237002100206450ustar00nobodynobodyGIF89aH`óÿÿÿÿÿ11ÿ½½ÿs{ÿJJssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×´Xüíÿ9Ànøq] plÊrK§ôåñ˜Óì¨jjµUQT "‚û*ŸÓëg24ÔCÄ«°ËNå£}*atEi]<ˆh)Šˆ]+„v†!‹<*™ˆ›Ts{|#‹©w&ª©0Ay‚Ÿ­œž´V£”¥*e·‚%½´¿¯»Žf­f“'j³‹ÊÅ1jÉË(ÓªoÑ!hÜ%׈Ù/â]ä¤Û<Ýëá΢Õ+æñH…®ï¸òå³èÚí‹ 0ËäOÆ´‚éD’dÑEûhE #'%~«˜ñ‹ þ»ycì[Ç‘7‚„8‰Ò†Ê–_^ÂÌ"s¦”š6›àÌid'ÏÆ~ê *´'Ñ¢@‘Þ<ªÔ^ 7“šC±Lƒ Ôfë)mó-L¤b,#±`mz¦–[‰*nu‰+w Ÿ"àak;,­½ã¦Ž–Lp ¼+‘aC8¢Y2Ƈ³’ wŽ¥BÀœ,‡@ 'ä|Ï4o– Z_ zŸMpnÜO4kÓNOt=yvJÒ̘Ômf@p7$|øÝâÆU#ONb5óæËŸ–î2ºtçÔ`§¾ýºõçÝ‘Ê /Ô$ôì&B.#ŸsãºIä§WAÑÝô¼wëNŸªQ÷ƒò%·V õUtŸA­á—` ­j´AX@ìØçeòã™<ÜxŽƒea–á1Ô`õ bž¥æØbšqF6†á!"'1n!ÜŒ¸ð• VôÁY]v‘ä%¦ô(gz…’Ë I¾Uˆ—pfÖ”e‰…”X‚è‡WF®ÀW¨\R‡sU%vUИ Lc~ÇS(Gºù&"q¢·evš0žy²'Ÿ}v hŸ'°gÜ zB tàè£>z@;tkabber-plugins/poker/pixmaps/classic/36.gif000064400000000000000000000012601500237002100206510ustar00nobodynobodyGIF89aH`óÿÿÿÿÿJJÿs{ÿ½½ÿœœssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×´Hüíÿ9Ànøq]€plÊrK§ôåñ˜Óì¨j¦°G°­*ê¡ñ ­ž%Cf@¼T…_ýž¿åEp&v<?…w7d‚'‰†7ŠHJ]mB]V—_™W”•^$V}/£¤¦T/’]‡0¯V±0A+³²©“¶­!«¢¼Á)¨¤Ä)·rœ›g¤Î'·C)’µ2Ö~#VÕ´ˆàÚÀ™ÈÀvxzèæ*\]_iañ‹Æ<ì!Ñ1úÉ­Ü<Þ´œJ`eƒ üŸBÊd(QKÄŠS.bt¢q㑎þP ùq$I‘'¦Ìhrå§5Nø¡yfÞ6[¢Ø“ÎO‡Òt:‰è¡%²ÙPz´‘L2G<µôòÔ°öÊ5‘«.^×VÐÑ5ì·TfûÉÈÚ¨¶¥¶îƒæ”®\®™Ò~…5®F"½®Œº¹ñSz>pQÜ×FTKŒu))åv–/Ï̬ÙÄäΞ9ƒÞ"ztˆÏ¦E N `ujצa¯$&;eÂÓ¥WR#ÍÚÄ¿qߌ©"«)ÙŒÛ4AJuîÂ>×íÔ*|©`l×·uãí7oQ¾ÏÔ¬žª©n³·[s†{ëÕ´9—Å‹öî^R€“‚µ_ü½ÕTÈ<_%ÆxvÍu^ äáSØWBqÀöW8º07H„ÏIÝa'@8rË­" :7\ú÷an'‘gboϼ#‚¡ÔÒÙèQyÜ͈™•ä -HÐÁ‘H&‰ä;tkabber-plugins/poker/pixmaps/classic/37.gif000064400000000000000000000012661500237002100206600ustar00nobodynobodyGIF89aH`óÿÿÿssZ9B9Îεœ”sçç÷½½Î„!))Œ))11)1„9J¥!ù,G`þP„I«½8ëÍ©,@(ŽdižhªÅ´¾p»rm×4€Ý<Ÿï½à, Ê °É\)=Í(é •J#ìˆ =®lӆ̀2 ×Ôl÷°¸ÔÕI’Šà–¯Ê”t'k7ƒleu}{&‹5‘s"}”%‡…<š7h&b {c/¡£,¦Iw)pŒq*°²m­0˜%¼¾'XÅ™›(‡Ê*F#“¶z*Ó“º"Ñ"µšr šßá³/9ߘb_:i]ñ+ð`D÷•̈'ªAÿÉpâ…= N@(?\V¢ä0FÄXÄ&Xwñ þ%º iåI$&O I©²Ë–žFÂô(sf—6+åDYsgCŸ+{ ÑçqE…öÀVR)' Î0:åcA͋ۮLJU©zLŒÚ;t Ï&À.XÙä!†¨7·¾¸VUj“n憕{оy¬öv Øô¢Â  º˜qc—|O‰,9P埗ufζ™sg'”/‹Ý<Ú'È,¡sjWÚ&E‡ÊZÃt»©õáÄ6n#h‡aªkiäêWQZÅó—Æ\$œxÁéEý®qYqÒ­–b»ŸÙ·º½—Äx¨™,Z^‘¶nwdk'èUö:-²·’qÜM|€(H«€eõJÿ‘h†ô“ D(\‚š LIâÞ/–ÆOy+\ÈßpÊ¡‡Ê×aiÝì7–Y"–ÐÚq6°˜â‹Ÿñ²Þg!<2#vˆc޽íD8þ(›dC>6;žÐB{È4é䓌D;tkabber-plugins/poker/pixmaps/classic/38.gif000064400000000000000000000012601500237002100206530ustar00nobodynobodyGIF89aH`óÿÿÿssZÎε)11”{„!))ZRR½½Îçç÷œ”s„)Œ)1„!ù,G`þP„I«½8ëÍ©d@(ŽdižhªÌ´¾p»rm×4€Ý<Ÿï½à, Ê °É\)=Í(é •J#li€äú–%íHPÉæ›².I&éÛ;—­CbÀ.·Ô“`{t&‚|2…ƒvms!ˆ†/‰€1de‘—(y[^( ¢”$„š˜)–®œ&X«$’³"ºUNm¶¸½“'¾*9ÂÄ¥ ¦¨)ÑÓÒ£ËKÍÏ    ܤãåçéëíCx(¼0ú_÷@%PPÐCà‚6h Úg%a 3D0lˆ£ ´î(ÁBAcOþ™€ ¹Ñ"É&OŠL©²dK+#_:”‰’f“˜6S傳GÆšÑhìiƒE¢‡ü4DÊÃÄ™Q$=Uµ†W+›`Ó` SXV3`uÉ$Ù1ž,ût˜úâ+)j´eûéO+¹ðÞÁ…mà>¡Áv¶È΢BT9¼óö¾0//=nßœù^±5®õ¹*ªË­Ý±žf†W%s$câÑ—°õl2¿°WÅÿ0VD{÷Ëábèz¢ú~¾­½_·I&‚¦‚T•hÀ‰Qæ%xpz8EˆRÓ9øKR»ðÆ50¨–p rØa}E‘ˆš†>uÑ Š®EhAƒ® c‹ÓÍF“ˆŸd#I:¦†ÙŽ;M&´`–1H&‰¤;tkabber-plugins/poker/pixmaps/classic/39.gif000064400000000000000000000013241500237002100206550ustar00nobodynobodyGIF89aH`óÿÿÿÿÿ½½ÿ11ÿs{ÿJJssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×4ì|pÿ¿\,Ê„>£ò(í–Ð’WˆZISêu›#=Ia ˆ«°ð¸|fž¾¢B¯*×®ê;ú|Ö ÁáC‚Cd)…=‰<‡+HNI!ƒx<*“C•;—R}›h~ƒ¤‘o¥ƒ0]x¢’¨=(™¯±*])a´­&º¯¼ªŸ*f³ƒb'ŨÈÂ1fÌÉ(Ð¥kÎ!dÙ%ÔCÖ/ß°Ò·};ÚèÞÆµåÄïáר&ßôϳùžØ¤í÷&ñÓïEŒ¦2"(^?=N[âða uì*n 2Œ[ÆþWpqÓÒà°$KÚÀ¥’ËÉ–!_ÂŒÂr&”š6•àÌYd'OŽ?­ø ŠC&Q“G— µ¡¦Q±^:þ¨¤ÇÎM©6”’O”w6Õ¢‰µ­d¿ž{5Ê/fP,ÕÖÒ@ QÆëêÕŠ^N|ûúXð`K… ¾µdÃ’s$.š´qåže/›Ó,73ç‘?cñ,ztiʧ§N:uëÓ¯“–‹Mt¤éÕ#£ò(í–Ð’GˆZISªªªäÞr¤'Š0ðþÈfæIl* ƒÐ —ÛΤé½ùp_M!ll$€}7ˆ8ƒCi!C’[•–#”š%™;v/ ¡£RŽ/‹=~0«<­0`+¯‰®¡Œ²©!§$¥™½)¿•Á)³:)=—É™Ì(³Ï‹±2Õw©<)€Ö5ß‚"Ãżoqséç*YDceFhAŽåí“KÓîÚÜWÿ¢yh嘂QŽáC8Ž!Ãc îŠ(‘"Aˆ•`ÌXd#Çzþ+†„âq¤“'ZÙg¤dzU.¡£ ËâlÊ4‚íßÍÊ´\ù£\…Ù®ÔÊEr'N\àR^1Êé¦+Aw°Lú¯çP§Erú»®NL„0u2Ü „(Jhdßò“Û1.ÝnïŽÈ«7ß¾õ¾;˜na¹‡3Klñ _»r¥aŒrÛŽn"³Ý¢â^fʜ佽¦Òç4­žHÂócE°þÄFa9æ×á†DU¥»Yš¼YÂ>Íq@ÊTEÅÕn1奻O@?y+Tô=P©“b¾Ü”‰Nf€;:¾DP/|½^ëm¢ž¿bmÄ£‡Í_Ö?ð·7ŽÛFÚ3¤í5‡hœèƒÉ§õuBP *˜‚}¾¡ƒ%dÒ …„˜Ö†sq¸Â xˆB t`â‰(žx@;tkabber-plugins/poker/pixmaps/classic/41.gif000064400000000000000000000012421500237002100206450ustar00nobodynobodyGIF89aH`óÿÿÿ9B9ssZÎεœ”sçç÷½½Î„!))Œ))11)1„9J¥!ù,G`þp„I«½8ëÍ©,@(ŽdižhªÅ´¾p»rm×4ÙÞ|Ÿ‹­@oˆŽ‚F¢Rõk—PTÎ øE¯U#5‹ír³˜a zãòÙFÓ˜Š`]ƒËé³äÈ:’T7~lz"|"q7‰r„%'‚€6“•2|‘'‹<ž7‡bd €j/i¦˜,ª0£%v”w*´˜¶s±…(—™’®/VÉ%Ÿ(ÌÎLz¡}§×*—ؾ#Õ"¹žxožäæ·ÇIäÃifUõd÷+ögBýyB@ãÌXS<Úd8q€Â '<|``i^ˆäP&DYF(þV@÷Qc! %£ÈJ¹d%K“/3ºŒ™ðM%3oÑy%'Oo?[Ú J‘èŸF¥ M ”©¨¥N§E}:µhÕ¦WÝe ¸Uk×H³†½:¶jÙ©g£¦uº–iÛ¤oÆ%:7hÝŸwyæÕ¹÷f_š» ÜuªHt£p¬è,ñ‹ŸÎF 0ñÆäÊ$Ü|±dÂN"ðŸ>’oNãØ'^¹L>Å­;‡K]9Úßb›®n)|o#n³ ‹0.+¦<FŸÁ0Ð+ýÂô± Ô+E®ííÀòÁ ÂTûp•2ï =jìã‰ëf4Ò`œ×n‚þÐ(Q÷B€JõŸüí— |Ú Î{µ…GXÆÅÀÚ f¶P…[Ѱ…c ±‡b0"‰dMÂ_e±"‹_™Ø`‹)€X’Š4žÐBuÅôèãD;tkabber-plugins/poker/pixmaps/classic/42.gif000064400000000000000000000012161500237002100206470ustar00nobodynobodyGIF89aH`óÿÿÿssZÎε)11œ”s”{„!))ZRR½½Îçç÷„)Œ)1„!ù,G`þP„I«½8ëÍ©,@(ŽdižhªÅ´¾p»rm×4ÙÞ|Ÿ‹­@oˆŽ‚F¢Rõk—PTÎ øE¯U#5‹ír³˜Ô`9æÑ4(A@T³oÖP|$™¼oõÀ]6Ÿ‡òvx{0q&€5‰|I"‡$ŒŠ0“…*jk/›˜0e(¤¦¨L™ˆ¡i²´­$°’zš¿„R»½"–ƒÁÃ'9ÆȪ¥¥Ö¬&Õ×§¢¯Ó      Ú'åçéëíïñÄriÀCÎ^œágb…= N@hƒÆ¤€^à$ÀFňQ¬ £Lþ®J“h” F±%-‚t©%§=kB=7õ¤Ôª)šb%¡u«ˆ®^€õ:vkY¬g«¦ºj[§o—ÆM:×h]¢w…æý¹—gßœmž9fá,ôG!ÉõjÕ•;üR¬ã)Ç©˜Øîëå6­*ÎYƒ>P›àLѲ r¤2ãó¤ÏÕ–Ï#`Ó®¡;v vëZƒí½qß$´qóv;ÆñâцÉv-¯e˜™ #xB«¯ZÄP|OV(+nëáná"5Õ­ëeµŠÅ½gÖGé:‘¿ VX·ˆB£1äÈ€ÿ}Ñ ‚Ò !ƒŒQˆmÔ1ˆ]Bl¸qáåQ(Y¬tñ!™tQaX©ôÑÇ{¸-%a€(¶·"Œ1âQÞ‚5š—£% ìhB t äDy@;tkabber-plugins/poker/pixmaps/classic/44.gif000064400000000000000000000011551500237002100206530ustar00nobodynobodyGIF89aH`óÿÿÿÿÿJJÿs{ÿ½½ÿœœssZœ”s„!))Œ))11)1„!ù,G`þð„I«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×4Iwïç¢ÏG”Âaq©î„Ì(*÷”ÒlˆVµbOf¸G»šÏ(Â`ìS³qÐy~* ƒ‚ÏŽ×ÛŽr_$wW>„x7€^(ˆ…7މp%h%Igo/—f™+€•#sg~/¢£W¥/‹¨0‘g†3q1±f³/·¯0€ª$§¨¿)Á£Ã)Ÿ)›W*ËÍȵAÐ)‘¹2×ÓfÖ¸‡âÛ"ÅÇ!|y{wìåtikEndÓçéAb?ÜÞWà´<ÒE –drS—PaÇ[B<(q¢V—`ÌHd#Ç{þ)†Ìâq¤‘Š&¡L9‰e‘’.›¬Œ¹j&M™7Aæ„·ódÏ–?{Ù :&QF‰& ºôgÓžOwFÍ9õfUšWcfu¹•e×”_M†96dÙgKkP[-#ñO@@¹=¢ÕЫnN©©öˆ>JDÔuúV F‘ÏðPˆ°Õˆœ¢î]¤Í‘ k³²jE3SÅ×Ä3¾nE8G*k3úÖªÞ%I—«Ú5³ÝæÜÊï)ª_§r}{(Ç{Q•¶¤ÜÄq¼ºeAòLXæé¼lPFqÅÄaw‰U,vî ú^z‚Ñ“/|=/?Ý‘€~+¥{AúQ˜6” üL0S€KìÚ\ž¨æT xB t á„Nx@;tkabber-plugins/poker/pixmaps/classic/45.gif000064400000000000000000000011501500237002100206470ustar00nobodynobodyGIF89aH`óÿÿÿ9B9ssZÎεZRRœ”sçç÷)”{„½½Î„!))Œ)11!ù,G`þp„I«½8ëÍ©4@(ŽdižhªÆ´¾p»rm×4€Ý<Ÿï½à, ¢ ¡r•“Ëè© xJ¯¥æqRÀzuDbŒt{„`@ø‚§áA@´½ÔbÜ&© ¾?qy1t€q[g7}ˆ#ŠŒ<…‡Ri kwQƒE(á„yD;tkabber-plugins/poker/pixmaps/classic/47.gif000064400000000000000000000011621500237002100206540ustar00nobodynobodyGIF89aH`óÿÿÿÿÿ½½ÿ11ÿs{ÿJJssZœ”s„!))Œ))11)1„!ù,G`þðˆI«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×4ì|pÿ¿\,Ê„>@!P0:W9Ѳù¬ž¢J¦u[Š.wT.7: Ë Â@4H›ŸXÑÎögyoc<4— †CkUHrI1€u<V9ŒZ2€”}p#uy+Š•=Ž…˜Uhž;›A¢Om”i„—[mžj[9k¸7³€µ¶¢;¹Ã½­¦°¢ž?¾Àc”ÈЊÓÔ!‚ƒEÌÛ!Æ<×ßb#9»åáèzªë¹îÁ$»íôEqøù@{ýÍÒû'Ð Á‚úà! µP\C†!F4¨pb*‹¹ ™Æ •¿ŠþE5Y¯J7'wð»q°†20¿V)5Dæ“—•@Å…sÈ)›NXÑÒöNVÏe%­Dû´ò"—¥Òš:}ÚŠ¨DªQݵüh H¥ù¶bT!v,вfM MKb-[n߈û–.[»iñšÕ;–/F¿Ûx¯íW¹ò˜ ¦·Ž¬Å&¤¾ G îá ]¤TòˆYVcP.×ù²æª’O<›k:™ÏÔ%Œ«Ìë/Ø$péâUÚ(-Ü/ ÍzªR¥~^5rÔ'<éZÇ Ù£F¤0‹qF’VÃ’%á€6×Èð’$»—®ñ77"±—kBÓ|ú%¦˜ÇOBÿ~þ!ø!÷tQb€‡ÔÔ‚dÈß 0xB t`á…^x@;tkabber-plugins/poker/pixmaps/classic/48.gif000064400000000000000000000010661500237002100206600ustar00nobodynobodyGIF89aH`óÿÿÿÿÿs{ÿJJÿ½½ÿœœssZœ”s„!))Œ))11)1„!ù,G`þð„I«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×4 ì¼pÿ¿\,Ê„>À@00:W9Ѳù¬ž¢J¦u[Š.wTc˜ŠÇ·½ÅŠvÅA@(Ë8ßîHoI7}<d9_·J‚` tCMp‘0  ÌÝ`ô ygd¶~kWy|?wsq‚D~€Wb `dpPS?l›oQ˜v†KO¦}¢¤|‹ª1…[\JM®6š®–µ|»´0eIÈ¿À!‹DjŽÊ?gÕϯÛD9§I§à«$Íæá¬Õîì@ðñŸóôç÷‡ùúûW ý>þ´!p {q L8c!êˆ(ÅŠ&.btâpcÆŽÖ9†<8²aIG¦ ¹ÒcË/1Ƭ8Sb͇7æL¸Ó`Ï?í7t_Ñ|Gï%¥·Ôß“¦QÒ5ƒªd\+UTy£³ Ûm­qÛ6 Õ…FA™) ¶†0 ÅöDuµ«—›u+nÉ…«Ê,z¹B¦á Sß~Ê`¬Ý\N~;á ûhŒ¤9”’ÕÛøÆ ÁXbɳ° aÃ&AMÀ´£¹M–Q6i[i£@Ÿt[wɲ¥O‚ÊêX5H†¬Çîæ'øòÏSL½D‹Å¢²kß>+;tkabber-plugins/poker/pixmaps/classic/50.gif000064400000000000000000000010451500237002100206460ustar00nobodynobodyGIF89aH`óÿÿÿssZ”{„Îε)11!))ZRRœ”s½½Îçç÷„)Œ)1„!ù,G`þP„I«½8ëÍ©T@(ŽdižhªÊ´¾p»rm×t(MÂíÿ¹çG”厢r•#5—ÐÑSèE¯¢©ÄŠÅ>·PBWš—·¬†¦2áúŠÌ–oBÞiñå‡^wxsJp?ijtwJbPS~Œ•Ž—6†@ŽŸ¡qnœ"¨ª0‘‘“Q4°²/    ”®Dg{eÏ>  cÎe£­Ù‡w=IáÞÍ"ÌåßNˆë6îïìòÒôõöøùúºüDñþñ'ðFÀ‚/"T¡p!ІM@ŒØŽ¢A‚bÌøp#G‰Ó?V™0$É7&ONä¸2cK‹/)ÆŒ8ÓaÍ…7æ,¸S`Ï?ùÕ7_Q{Gé% Ôiétê´Ô!9”S¹YIjm6Ô–F»8Hj`ˆC¦,ê ^±°†¹5ÁV-·*àªúÉíB©¼qíDéká/`_|3mØd×Ù%´6ä2‡F1ÆK†6œ¢ìãÁ8w¾ ¸ËÑ£K¾"à¶nb1Cë¶ ^BsœB+÷$ïÞ$éž÷xx‘Óª}>dóÑ ž—hA˜•õëØyD;tkabber-plugins/poker/pixmaps/classic/51.gif000064400000000000000000000010761500237002100206530ustar00nobodynobodyGIF89aH`óÿÿÿÿÿ½½ÿ11ÿs{ÿJJssZœ”s„!))Œ))11)1„!ù,G`þð„I«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×tX|qÿÀÜŽ×e9žHylªr$¦sZ‚Šv>ªVd`·`€õû+Ñàœ¥BÉ·aQ.h;…õ6 û~iSIK†2u‹n‡5‹”{G…’‰•Ž„Sf›<v—ŸNkŠ•gƒw§¨ª”hZ9i¶7k²­ž!<·Á»±£¾¿›?¼Éa4ÄÆÎŠ³ÑŸ€Ê5}Ý"ÓÂMàá!¹D·a´¯éëìçjðñË#æõ?]ùíüñûþ\Ì6 À‚A^!lrp¡†‘(Œ¨o"Ň/JÔh"Çì?ž)²JÆ’ O¢©r¥I—3ZÂä"s¦˜š3IÂÔé’çJŸ(–*’èG£‘jTz‘)E§¡:”º*B«ñºa “KÙÖ-ï|}¥’NX«±ðÅWŒfVAF¶ùô•¶lÉÝäëî¤J!°>#âw­YbÕ¬öS†-\ºã䃌“ZŒdÏlb%¯I(Q¤:©¼êo¦½SD†AÉíÒtFý=äÕ"¹<.—`‡*¿ÀAMÅÌÝT¥d 'ns9s˜ÎŸ»´T{¦)hÄn“];;ÝÿMî„M-$tXϾ=û;tkabber-plugins/poker/pixmaps/classic/52.gif000064400000000000000000000010351500237002100206470ustar00nobodynobodyGIF89aH`óÿÿÿÿÿs{ÿJJÿ½½ÿœœssZœ”s„!))Œ))11)1„!ù,G`þð„I«½8ëÍ©D@(ŽdižhªÈ´¾p»rm×t8üpÿÀÜŽ×e9žHylªr$¦sZ‚Šv>ªVd`Ù-7@ú6„°j>BA ²ÒœG ’K?{D}kd!D‹?C‹wˆ‚7‹sZ]G…–‡TšFœžS]˜?•–<§¥‰#ƒ@Ž‹j­e¡£tPD›†~9©D¬6oqÅŸ®ªGh´™®Ã«g~u®¼<¾Õµ#mÜM]°àá×!Éä? éåìºæîNëñêðôFó÷8öú7ùý0þ\!p`Š‚O LX…C‚Œ(Q!ÅŠ 1"¹¨qLÇ€Ë?.Ä8²bI‰'¦d¸2aKƒ/Æ8³_M}7ï夷3^Ow?ÙM7”\Q-ÉŽRgí£-ZJ›d°­iµgÆêì3«bŽÉ1"MÀÖ6 ‘º1µê´2D­µñí­YD°Ê`j©ªi@’Â}!jÑÜ#; ƒ¶¥ì¥_ûjÁ[²%bä‘"%¨Z#LÚ‹Žî-°wÓ€9úîêgQÔm­1ψ؛au|oܱòÞæ’¸Ê œ¢h!¡ƒóçПˆ;tkabber-plugins/poker/pixmaps/classic/big.gif000064400000000000000000000032271500237002100211670ustar00nobodynobodyGIF89a22ç‹                   $ % ' ( ' ) ( ) + ++ . .!0! 2" 5$ 3%4%6% 8(<+>+=,>-?0E0F3J3aC^DfJhK$mLjM$sPpQpQ'uQsSsS(wSqV,zUwV!yX*w[/y\/~[+ƒ[!‚^-ƒ_-Š`#Œa#h1’j2“k3”k3sss™o5Ÿs7™u<§t*£v8x>«w+²1«‚C²>½ƒ0ÂŒ5ÄŽ6Ë”FÕ”6Í•GÏ–HјHÛŸLäŸ:å¦?æ¦?î¦<è¨@ëªAó©=êªQø­?ï®Sú®?ð¯Sñ¯Tô±Uÿ²Aú¶Wû·Wü·Wó¹`ÿºYö¼aÿÃeÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ÿ,22þÿ H° A=ƒ!Z¨HBƒ#J„˜B… V4±ãD/.D¤F…Š<ªØð¢B‘ aVt¸r"J/b´xÒ$É‹5 Žl©“gÅŸEC :P$QŒ0Š<êr!Ó’$AJ-Š´'Ï…(k¶ifÕ®&¡ê¼©2+˜GqÂ]»ugËŽ(õ¼Ek4nÔºC5Ú䋵/F­d÷fD&â[ÄHp`ŒdTUKöiã‚%åF¶€%‹‘|j!s¶ëMœCWœ‚4PøÌŒ°OÀx`Q´¡ÖÏe×3yò•Ýš5ƒÊ Äg>9Q×?þ€@£æLfòÄ DrdÏ(×»ò™Ìa jÈÀ…ëà‚B…È×vˆØ÷Ølùí§Gð`t,ð^öÝBÝýãV^Ë@šNÌ@"$7P!B†ôÕXV>‰ÆÜdLÀ„!êE÷Ç l0/Ø…`‚*xz%´áaqˆÀ ½UwnÍ•““F† øpLQÜ‘\6TcU.)ù–†Á!„t…6yT›yÉ“’rrõ”˜}r•`2 ¦\&ªÝT2ú\NAzäw7µè‚ÀP×~C¤tV”™V}Š"þ¦ÖÕP¨ a!†k©NÈ*IjÙ OA?C@@IBCKCDLDEMGEHEFNFGOHHQJKTKLTMNVOPXPQYUU^UV_VW`WXaXYbYZc[\e\]f]^f_`h`aiffohhqhirijsmnwopyqr{rtqyzƒ}~‡~ˆ€Š†‡‹Œ•ŒŸ“¢’–¥•– “—¦™™£›Ÿ®œ ¯¡°¥©¸¦ª¹®²Á°´Ã´¸Çµ¹É¶ºÊ¹½Í»ÀÏÃÇׯÊÚÃËàÇËÛÆÎãÊÎÝÇÏåÈÐæÏÎæÌÐàÐÏçÊÑçÍÑáÑÐèËÒèÎÒâÌÓéÏÓãÒÒéÍÔêÐÔäÓÓêÑÕåÔÔëÎÖëÒÖæÕÕìÏ×ìÓ×çÖ×áÖÖîÐØí××ïÑÙïÔÙ騨ðÒÚðÖÚêÓÛñÚÙñ×ÛëÔÜòÛÚòØÜìÜÛóÖÝóÙÝí×ÞôÚÞîÝÝôØßõÛßïÞÞõÜàðßß÷ÙáöÝáòààøÚâøááùÛãùÞãóââúÜäúàäôÝåûäãûáåõÞæüåäüâæöàçýãç÷áèþäèøâéÿåéùæêûãëÿçëüêóûòóýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ÿ,22þÿ H° ÁU‚츱cç$Ež JœHQb$W¦^ ЧOŸF—Böt©¢ÉŠ‘LYÂKU¥9v`®ÑsÉÕ¥>Š.%šãç¤O‘"Bäh•)Akõ©c§Ï%I# äÇMœŸé8ÚdÉ‘©T«0)² R#7N YgO¢8s.•ÂjÐÑŸ?– ýÁ´ÊRªK‚*ê£É%EŠôØ™šSn"ºƒò¡ShR«U£½bÕÇΞ9”TyÄÉŽ¢D¦CR¢ ÙQ­Ž&©Ê<ÉѨW}Æ ÉtNŸ=—(1dèñ#V:tˆþ‰¤j"Ø‘X‰j¬JÑáë—qt§˜v|þNM”'ÏŸI˜ 9"Ӧؚ0¡uRÑœ8x<6RZÜ$¤3{¬¥I*© ‰%AY2Ê(³Ô–J!#=¢VíÑGi§E%UE}ø!ˆ…šå&£L’ #´‚È*…HâIp¹µÁÑTq(B$‰X¨ÄD{45%•Dâˆz&:ÛVš™bŠ&Ù Òˆ…~,V• J=2Ö…;Ô‡ŒžUâ $|YÈPDY²É$°À‚ž$‰-–P‹ÙqI< •²¿;¾A‡%t*p±â{îæ•Š*ŽðI%U I!”%e‘”e¤#ØÉ$©ìˆ zD4@£‰ &F®"I€— â‘Ì08ɹF"Rž êÁ‚ ";&I ¼æÈ a"@ ð–àZ† ðÁ‘­rþ$> ÁA9€ & …#–ôZâØLÒ €I$CÐ 0ÑÔ ð D4"‰Þ… 1ÐÄ$¦tìB;ÒëÊ©Àü,y0Â&rhà€bP@‚­ep±ÐG"0ÿAG€ñ%d€É¢É+³3Û|$yŒÀ ˜äîñÇpf!)4À%šMÔù(p ɳ)½ª¢$Ì7ƒBˆ0¦ 0@ TXBü ˆ D`7Àj`f" 8  Sp‚„B6ý=«–˜DÐ’p a"‚à 4Xž„tLuè #>WƒÀðþ|"4‰^Y"ôØXÐ9ÐlØÁà30P (€ ^¸?ÈÏ.<˜â ÈÀ‡?mL+›L´ dª“©4Q*I B”¸“ <¡ IÆH’ÐD%–“ HËX†bU¯þBý!k{8ƒoQ <تÉAD˜L19d1IhD‡‚“ÇÕîqD¯vt IðLptÃ(Æ$‡ôaHZéË"Á¤;ÍÁIx„–‰»˜)«ü*7qª1Bx°±¤y˜ý ©xä$&q§â æB:Ñä qÌE äg¼ "üІ¸xbÉ.ÏT™QX¢,eþAÌZ¡ IŒ k J¦@ìùHóÜq*ÙqÊGž‚,LX¢‘BjÙStBQL¢L‘°§@ÿ‹D9wìV¥)Hl“ !c%§ Fš¨ ¡˜iμâ9@,DYD÷ HIgÊÃ(œó\ÙJ"Ì&øð†<$k£’#ÃÀ\R ¹+FQ&>l+VšŠ$ü8"/r°Í*75«Á1ˆ¨%`@â OhBHDÙæÎ4ª¬v(!v Q¡0U‚ s=‘h$¬ZŠR ËHyØ„ÒøJ/6Q¥’DªWØ‚8™êkpäâ A\T(± eÍRH‚9„íÉlA¨¬EB†9ëˆ\ã8œ="”öš%±•µú¤¦ÈɯÈRŸål%|˜„dñˆáâ$W¡ŠqR z Ɖ8Œ"´‚ÄÀ1+‹ %VóAl+¢\‹­~«bJWª5E!á?@â½tQNô’d…О)ÓiuB%?¬•­QB¨ƒ«!n"]ªˆÄ©»X$âÁ‘H¯T•‘諸Ú#C…1‡¸ k…Äχ`#=X¶/†ñw\Óÿ„Ç=ÆJ@;tkabber-plugins/poker/pixmaps/classic/icondef.xml000064400000000000000000000142701500237002100220700ustar00nobodynobody Classic 1.0 Chess Classic Theme. 2009-03-02 poker/button button.gif poker/bigblind big.gif poker/smallblind small.gif poker/back 00.gif poker/AC 01.gif poker/AS 02.gif poker/AH 03.gif poker/AD 04.gif poker/KC 05.gif poker/KS 06.gif poker/KH 07.gif poker/KD 08.gif poker/QC 09.gif poker/QS 10.gif poker/QH 11.gif poker/QD 12.gif poker/JC 13.gif poker/JS 14.gif poker/JH 15.gif poker/JD 16.gif poker/TC 17.gif poker/TS 18.gif poker/TH 19.gif poker/TD 20.gif poker/9C 21.gif poker/9S 22.gif poker/9H 23.gif poker/9D 24.gif poker/8C 25.gif poker/8S 26.gif poker/8H 27.gif poker/8D 28.gif poker/7C 29.gif poker/7S 30.gif poker/7H 31.gif poker/7D 32.gif poker/6C 33.gif poker/6S 34.gif poker/6H 35.gif poker/6D 36.gif poker/5C 37.gif poker/5S 38.gif poker/5H 39.gif poker/5D 40.gif poker/4C 41.gif poker/4S 42.gif poker/4H 43.gif poker/4D 44.gif poker/3C 45.gif poker/3S 46.gif poker/3H 47.gif poker/3D 48.gif poker/2C 49.gif poker/2S 50.gif poker/2H 51.gif poker/2D 52.gif tkabber-plugins/poker/pixmaps/classic/small.gif000064400000000000000000000054671500237002100215460ustar00nobodynobodyGIF89a22çÿ*æ-ß!è)ê "é!$â##ê%&ã6!äFç''åDß8"æ-ç4é:#ç*(æHé<$è,)çG"â;&à/è>%é.*è0á0é1+éK$ä!1â1-â?)ã3,êB*å%3ä9ç?êB-ß)4æ70å:è+5çF-è91çP+â-6è;é;3á<â/8âH1ã"=ä>5ãI2äCç$>å3:äIêDè'?æ5;åKæ*@çEéO6èFã,BáE;á.Bé Mè!Hå1Dä$IæNé3Eå?Bå&JçVè(KáPä*Ké7Há+LãWé:JãRæ.Nä;KÝXã Xê"SçIGì#Tá$SèYå3Pà_é'Uã`êZæMKè`Fê[ç+Wäbæ\è.Xæ]â.Yß!]é1Zádç#^êdKç#_ädè4\ã&`å(`æeé)aàfãmè*açnéF[íhå-dâ/eÝ!iæ0eäpä2få$ká%kèvê4gæqæ'lâ6iá)märç+nåsèzè-oæj]èuã\bð0qá |é"vå]eì$wæ}ê'xç~å*zã€ç:wèckìrtq0}æ2€âOzîauí{pïluïSç…rí0Œç~uíL†êI‘í`íU‘éˆòz‡îc’ìc•è]šë—Œòj›îr¥ñŒ¡ô•¡õ…§ð®›ñ©žòž¤ô€®ï˜§õ‹¯ò•°õœ®õ—µóŽºîŸµô§³õŸ¸ñ¯³÷©ºôžÃó¦Ãô´Àõþ÷¯Çó½ÄôªÊôÀÇ÷±ÍòÂÉùµÍù½Ìú·ÓøÅÐùÀÓúÁÙøÔÔùÛÓùØ×üÝÙøßÚùÙÜúÓÞúÍàúÛÞûâÝýÖáýÚâøáàøÛãùÖåùÜäú×çûØèüååýàçýàìúçëüïëýêîþäñÿôíùïïúéòúñòüóôþî÷ÿóøûúøüõúýýúÿ÷ýÿþÿüÿÿÿ!ù ÿ,22þÿ H° Á7‘`ÀP'S"u JœHQâ›3HR¤9 !E %4"%Á’äMÅ“Ó(üpbJ EHnÔ‰”¡F–6):€àÊŸ-$±ðãÌVôQùF„B“ødEäÇ4@+ÞÐÀã0"êøId… ’@i´°T”ÆO$XšD2™µ`„¤!‚ …7oNÔi»á„ŸBHÒH£Ç'Õxbˆ7ÎA$M‹4?Ò°HƒÁ™3ÀL¡AA#?¼i4YÍV´X!‚!M +BüÈ9“BŽÕ+l:¼Ñóršy! µI ?„Ô1K$‰•*UNþì$ÂæÌ.…°ôTtC€ú³yÒ=ù&ŠURPQ‰•B8q0$ u2Ä0‰V¼¡'1rˆp D|!ÂuÈqB%8ø¡g°QÅrð|xDÁB(R‡'œ`…é–„OÅàÂ"Bt0BüÑL’‰"¼@ üA мÑ2D±8´Á†1\ô‡¡LD„<,â Q$²Èr’D!oø@ô‰Å%‚@ZÄÀÀEò1¨!‡gh‘fAà G*Ûì³Ï6¦°ðÁ‘|€À$ ! (b ; @H þVü ‡?è,ð?Þ P ‘ aP%›ü!‹?ð s =þHÒ'P XႊœV vŠ"AG þœsÀ ¸vÀ†IÀ0é@| .þô(ÑÄ"ÄþDcL>Þ ÂÌ>ÞÄAÁ(ªX“?ã¸ÂA&þ¤ãþÓA!gÔñG(çúñm$¯ôã8Å”‚ƒPXøã6ÒøÓO6ÔøÓÌ~@ãO2¼ðL´b¡­rL’,Ppn%7üð³dÃÈíaþØÃsÓêú#Ž¢ÔP"” ;­œÜê '‚Àç¹øÁÄ |r†´8ãÏ3uÐëàŠ#@#R¿Q þ&Üäs=þp®kãŠÅ"8€DÿÓg"oq?´¤1 ŸÑÔ$Œ`8´"I<ñhqH<þ €?åø!‚?ß@þCHÈñFš0ñØÒô2ØãO-‰œ!µi$œ·é¸É<ý(ÓŒÈB@ëu(ÿA$jÒZš€)ÂDu¬¢>ú  ŠX"uçŠ@·bTrÊ;û ³Œ?¤ü€+ÀÕnðNBu›Žk8±‘ü M @B\s†C(2yÃt2A=Ôa6LD$"aÈ`ቨd2A„$2 ±ŠòšA†lD°£?@6þ¢À !£‰²Œ°Âîˆ:PŒ.pÀ\Ð9¨g…o°€ª`žL¤Á(ƒ4`´X@%¬ƒЈ:Œ “ChD …F   s€°0P :@(÷4ÂiB(0‰&LA°€A„4‚`h Á„6èä~ ’ ¼Á®êF‰¥`áЂêü †è­ñD°S‡@ˆ°?¨‚ê6iGÈèsR"~ ì4`ÐB,!›$ÔA#X$&Abw DÀ°*ÔA˜?|C(f j¾A¾œ:&á øaþ@X9,ÖÕAdÚÐ ÀopŸ8°ˆBþÀ`˜Dãøðƒ)L皬³DRÐ5@æzM†/ôP…$a °Ô‚ˆPP3t²ÉTB±4Q@°BW‡eäƒÄ@Âæwpâ¢Ù.òÑY$ÁD0>ê Ö¡R‘8D PÓ¤Æ&m„DÖSwøã(ðß9`²¹…¬Óp›;AaøcÃ`G·°éÈ4¢q™òI£ê#`…?²Ñµ¦¡ŸSsŸ=è€yô¨G>´ð†>ÐJ M@†ÚUèAU¤!üáÈ0mÐþÃÿdKŽ:àíS¸A9ü!€4¬+:0ùƒ6€«€ýÇ$ÞÀ‡$ˆaµû`¶ 2pkn„Þ¼‘BœÃ(;î¡ÂVÐêzÐCÔð×s „šÔ܄ɸñ á"ŒRûAvÏÙž‰èðGø „ãïà:4Q”– ƒÚàjÃôÀ´t¦aàl‰@0¡SÕÅ;¼QÈÕÔ½yC Þ°3Kàƒ%%D!c = Ñ5Çl'± ¦XÐÀðà‚ @ %œB Qé*$þIî n€u’€†‚e>¢ X¨Bþ“ ˆ Hënp’èáV±Ä!š’>4¢ Lï‡`Çv¾ø$I`þ4JB´ÆUhCInü†3²|²Ñ1%‡ @Q`‰bêáœèñð†6X@mЀ«`€?›ðÓ?Ñ!PÐFôÔYµ„D Û&Áš7¨B#’]•2yÍ(f…Lâ–hC´ÐšFŒÐ¶‡h!Qàº.¡˜M‡ªl¾'j0Ĉj"óÜ“I·êN‹["ÀiðõÞPü±|6´'óŠé@B$BdA †àÃÄ ‚'—áy±ª…,ÀA´J€ŒÇò‚¬üå,o9E`þñ¬;tkabber-plugins/poker/pixmaps/doods000075500000000000000000000000001500237002100173435ustar00nobodynobodytkabber-plugins/poker/pixmaps/doods/101.gif000064400000000000000000000027121500237002100204140ustar00nobodynobodyGIF89aG`ÆR´ ¼Ì ÜÜÜìä ä ääÔ"$ì&$ä*,ô.$ü*,ü.,ô6,ü.4ä64ì24ä6<ä:<ü64ü6<ü:<ÔTüdÜBDäFDôNDôJLìVDä~|üJŒüfœüz¬¼¦¬´ª¬¼ª¬¼¶´¼º´¼¾¼Ü†„ä‚„ü’”ü‚¬ü‚´Ä²´Ä¶´Ô²´ä²´ä¶´ä¾¼ô¶´ô¾´üº¼ü¼ü®ÌÄÂÄÜÂÄÜÆÄüÎÌüÂÜüÆÜäöÔüÞìÌúìÜòìÔþôÔúüäöìäòôäöôäúôäúüäþüìþüôöôüúôüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þ€‚‚…†‡ˆ‰Š‹Œ‰ƒ…Q”•–—˜™š›œ˜…‘¢£¤¥ƒ¡—<¥¬­¢§’–NP®¶·•§©–<+¸À­“–´µÁȯ»”½Q4PîZøLq5ÃÁ‹¶Kya[B 3´ÏÞtcB‰÷à1¿2$Èïæßc0 l;§¼'`|óÑDäáW bà\E¶äà‚–ð€ x  ùUX‚ƒ²ÒD xøÞ fD†A¸Àà‰j`Cv®øg 6°p‰ ¦Èâ.˜øÞ,ØÐG£0þуŽ/6ù PF)å”NRXB-øp„)ë‰ÐÁ/Àæ˜b¾ðh¦©&˜é¦˜p†éA \Žâåxæ©gž ¬©f{Šg"ÔIŠºç~ð€¢z^ ‚4Žb£%6´`¤x °€šp:‚-̈d+5dé   ÀÁ£Šf`Ö5®‡ €‚>ÀÁ¯® °Á¯€šiáäj ííÙÀ¯Ãr 믿Қç~Q¼¥¬-NÜAž¾R ,µÑ;Â5¤k&Ý~û,´Ð +î°FpƒF¶\º 1„m¼ÆˆKì Ú†L¬ÑK€G<¡25þ¼ÛðÂâ6PS#äÖD-1,![2FT0Ã59L®Ï!CÃ,‹ÌA4œ6M ´lL2D¶Í>oà€BO#C-‚W:oÓsM ÀÌÛ6*(O&ƒ/%ú²2u:Ë5Ô¬[Š ¤Ãu0$©€oجhmŒfßâ„Gñ\Bw)+°AýDõN:…ÿ] $€ô-Ew“ÏÈÞ·äó ÌáPE¡8Hþ<ã‰Ú ”vé'£Þ±êý‘NÑ,³È¢íç ©CŽ:2ÑžÐ;F±ä“î K8a 9ÀÄRO˜³ÎI˳»¾‘6´@•|ðÐhÓ¼ó›ôR½ß+Òƒ”ÎèÜ‹ò”'±”ÿ<ú髯I瞣â>)° >HŸDBˆ#ü÷ï#‘;tkabber-plugins/poker/pixmaps/doods/102.gif000064400000000000000000000011621500237002100204130ustar00nobodynobodyGIF89aG`ã œ~4ÔTüJŒ¼¦„ü’”ôÚ¬ÔÖÔüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS!dižhª®,Z…@+Ït Lq­ïü-–‚`G,’n9„pilêF¤aTà¬Ê (©uëJš„ܰ ÔŠÃd¥ùÌ%ƒÙgì{ oÊ©Óúö¾Äë|L€^ƒbi†m…J‰UioEn‚‘=I}t;Dz™4 ¡u“ž;§¨©l¥3®¯°‡‹~<µ¶·Š\¼½¾VˆEÂǨh‹FÁ½¢$$%–aͨÏÑÓ$Õ$6ËMÍÚÜÞàâãg¼çÒÔ%íîï¯ñÝóáÐö÷ùéÖµãF£Ø–Mýô}£—Ð_tûØ5tÈâB~ÛˆÜbQÃŒþÉYé(pâŽNH~$²¢¼‹AAYD%F–’DÖ|éñ&1z‰Š3pvŽu‘Fs]?nŒw4œif=£¤¥_kh4«±¤­„Gª²¬eµ¶¸¹º^·¾¿À«ždNœÆÇ»T—ŸÍ’5ÑÒHÔÕ,ÈØÙ×ÛPÝÞ#ÚáVà>˜æ4Ð_ìí¦ê-ñòó´Z÷øùZã3øõóW ½Ý s‚°¡¼…N&üWO…D| !>¹˜·QãÆ=~”RäÇ’&Ÿ {GnZK—/­Å”9“[M›7UôñŒe,µ¨Zæe§Œ`DSòìÕS©(¦Âèí•PÅHŸ¼óe¨ÖPFgu¢‰CØMØirÖÑÚm½5{Õíº9ϼŠ+i+ßp½þS–kÞ¹†sƉ3O(¸u =Æ{¸pcÇwç•ãá2f‘%/ašp% 7W²QºšÔ›;£hýçDrëÞ]!C;tkabber-plugins/poker/pixmaps/doods/104.gif000064400000000000000000000015731500237002100204230ustar00nobodynobodyGIF89aG`ãœ~4ÔTüJŒ¼¦„ÔÖÔüÞìüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þI ª½8ëÍ{ž Rdižhª®,Z…@+Ït Lñ)uï·7‘n÷+I·\iG<:{£%“÷¬Ê¢f–jí¦¢Ú­w|O§d²ùÜLw±¦¶û­ŒsçV8 Ï×÷a}Oz‚j…c„wˆGzN‚pgU‘}Xl‹%œž&–&žŸE˜l(*œ$¡¢›­'³>¨”¤-­¯±µ)«Pu¸²3­°¿+Ë@$º4µÍÌÂ(‹£ÓºÕ,Ú4„'Ú±5­Þ*¡àW‡ ¯ÛÆèé°ë,â%‘ô),Ò*ü(^€÷¥«^(´öoá8dõTÜx@ß …Y5Ìø0Á2þZ4±$°}%‚)1¤:)MÒ‚S%¾r+&F,QÓf4š5SìtárcLU@ uV$(Ò¤O…l‘R#ʨR`¹qÐTW+ 5ð‘„Ø€áŠ‚íÀ€Û²+FÁE2U.[·dÙâc×ÂxóþÝË7ÝZŠ}ãŠvíÜû ¨MqàÊeý>†ì²”gÏ“ƒõ¹4Æ&"×è‘,2ˆ^Tÿ}ýšum:ÌL—¢Í»wÝ¥˜>± Ñ÷æ´Vˆ·U»3ðÝôD÷zî u‰È–&«xqeÃŽ /EL>®e²›5 KXÆùãäcoÿw±ÞÃ9Õ–¯ÿÖ‡ö‚îþ±œ€ÈiÕ g![X>‘Â`‚?,xUƒ?Má5àYH¡?$)5^~æi¸•2PÉ´ÝzáÄSOOuèÔJéÄÒ=AÈ¡Y,®¤"€†Íø¢ƒ%&(PŒ.!t‘‰\AÕ‘(D~SÑŽ4RXáU)z$žPïì“Û$ Ý•XBÙO7\~Ãä ²YÇ ™þÁ'a™k3Í š¼ '-º £Ì¹¨„{‘òƒ tõ`(ž®ÀM3èdrÝWÀ˜£*Ÿ± i¢sÀצœáá駈†ÊˆRzê§D­jˆ«‰¨ «rp:+ ¥Úzë µêº+©<þªi&T:+±ÅÊúka+{+8{l©ÒškÂÊð'Ù[ÝBƒ²¿¾¤«îº„;tkabber-plugins/poker/pixmaps/doods/105.gif000064400000000000000000000015111500237002100204140ustar00nobodynobodyGIF89aG`ã œ~4ÔTüJŒüfœü’”ôÚ¬ÔÖÔüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS!dižhª®,Z…@+Ït Lq­ïü-òÀ ë–CŽHp©‘’H¦Tæ4*§Xjñ˜í®ªÐ«× ÉÅ÷œ­ªÅli¹´ŽË·âº}Y†îï&~Lnƒ]…†XˆpB…QKŽŽvn‚@”™g}I˜$$›htf;”¡¡šl‘5¨%ª£Ši—*Œ°&²j€z)b¹±¢t„iO-ÁÊÄÆÆ ÈÏÊBˆÎÐÜWªÅ%Ôª×ÐŒMÌÛÜë&Ô”âëëç4Ú+òì$î«à$øÜAìÝúwe²~åºL§.ŸÁïüÉ£WaCúžˆOa6‹þ+=ËÈ/Gs%{€4I‡ä¬$1jÜ!…´™!IŽÃY‘ÆÍ”-8î:£&Äj.OéÜ…NÆÏ—N—ò²’ß·‡<„2-ºòi‹A¥U!Ð+‹ „í7ê {fW v­¸­_ÆU1—n]Z§š@´7E_¿s²Åë‚Ya‡'Vx, 7OD–<™åbÁU2›àLš®Ýcc1#íç–ÄfÉj‹…ZHt‰×tc+¾+áÕX “ÖMy6UÏW{»†}ikßm/Ïݼ­ÅÉ-ßîlÓøuìá”#+û³ö·U¥Wg||möçÅÍÃ\õà{¥òiÖ·þ<Ìüú½øœxñæYûåORåQ#Ó*5k»I¤Ä|îPƒÿ9èÑBâÃaÍó‘ ¡D!‰Fb ÿ@Óß$:Åø`€5¤(ãŒ:u„Eßå8Ñ€b%$/èñpÍ…(Ò‡ÎübÔ@ÃiÝØÈ`Ë”·ü÷sHji tYÃ^Žcr)àNg¢y‰šk¶‰¢'%À¹&„3¸rY‚JaHÃ9vêà牉R([òyh)o*º¨¥Ôéè¢uÔ(¥]zè/’>:g£ž~ꊦ¡Z:i¨î‰jžižZhb±j@Ì „?Øj ®úBx ì°ÄvB;tkabber-plugins/poker/pixmaps/doods/106.gif000064400000000000000000000014411500237002100204170ustar00nobodynobodyGIF89aG`ã œ~4ÔT¤ŽTüfœür¤¼¦„ìÒ¤Üâäüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS%dižhª®,Z…@+Ït Lq­ïü-š‚ oH,Ýr¤ ²Èܒ¦ԆŒN¯­gB¹ÄzMZn÷ë JVòÕŒ>«±lè^uoíó¦YœŸjïc}L‚_„…t(xˆD„Œ=H€iD}{\L––s˜:– œjž”5¡ ¢¤†’|C–%«¥’€•ª$¹¬k¶[¸¢ »¼½­D'©ÄÅÆ´&ÊE‡3%–ºÎ»$Û¤ÖØÀ2Ö×Ù ²ÍÅ$²áèéCÔ,çòã£ëÜÆð%÷èò騧BžAtêØõÓGâ ¾H5Ì«„¿†,·BbÀeþû.þË(Á‚Shcx"#=Ž,ªÌ­¥ArCäÍv …Nœ9wê"Q3Ú ˜<˜¹ë™hŠRgDYúAŠj_;¨L¥œeµÛ;©Z©®f¢b»¯¾}™!H…hQˆ›&ÖçÍ·Á&¸W’ʉ}+Ši°ïŒ­6]âM›ÑíÆ?‚LëQ£ßˆ$QT¤œÙI]€5‡Ôâ_Ë ór–lút஼“˜ ”ÇZ±ÊV{ôŠY¯ûÒö–ò»ÛBáµ›<]Z4,–åQ‘ÓM&”Xô·=·Í®gsŒÜM~Žv¤¨ïjËk×Q$¸íCnì>Á{òŠåWsxŽ¢}Õ%ÐÄšxìTXjÖG@†e1Þl!¸”Hñ]V kÅMÈ_ÉaæŸBÆÅaƒ‡=hTY¹\õ Xáè[ŠÌé¥Ã" ÆÕ0+J7Ã#6Þ8‹Œ5¼BB>¢¤v风;"i„‰U1Ù¤Jî % BÖ%$m,R%—@¸°%˜*|If™cB’¥™j:9dšˆXa›ŒÈ™$œ…Øùä™G¶±'ŸSfò& XR‰'—sZg¢„Š‹RrD£ôP@i8\j Š òBx ꨤvB;tkabber-plugins/poker/pixmaps/doods/107.gif000064400000000000000000000016101500237002100204160ustar00nobodynobodyGIF89aG`ã œ~4ÔTüJŒüfœür¤¼¦„ìÒ¤Üâäüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS%dižhª®,Z…@+Ït Lq­ïü-’‚ PÀ+·\b(<:u# Qú¬Ê¢§ u»Âš´Ü°ÉK›‘Êø&/§l.yßÎáuë=/O¿ùv~€}ƒgnx…Ewˆ‰PiL:$$$’ – ” ˜OXLt+—“•%šœ˜¤N ¡2”¬˜œ–©¥ ¤œF®,º²¦™Á«%º=C-Ƹ·ºª$¬Å»~M¾%%À›ÛÐ×ÒÇ(Œ'ºÙÍ·ÑæèÁŽ;åóîÌÝë%æôà6‚Ö$úæK×@ûÞÍp³B‡ &xˆß)äQLh¯c@Šþõ–uÁ˜1߯äL‚´Ø‚aC•Q¢Ð“eK’*hÊ$1À„N›7yÈÛ™ À€zÜŠTHÃ¥²o 8êjRxE–“:•*K‘Mq>UصìÔªL±‰e‚«Y¯ÞÀö;ò«í[¸å.ûÒD´¢f‘þ½ªV‡C‚» ¶ª—…Ó¾Jëý5ºø ѰñTl¢'âͧx<&ÇÁÞ"¼”†CØR#>·2íHì`/í˜ôCÎ{kä¦ ú²Fß»Qßnz7Xš§ Ïîr@àswôF|ësòp<¢ÅîXÊ“ìñÊ/<Ø“yòð³‰ÖþÄ{úGH· UÅýøÒ…þgß ÿµÂW$-¼÷ɪ à‚O ö ‚éÉ7_|ïQ …Úq׆²'`žIx_<…àt‰¹câ ¬P¦"f6•‹û%vãŒêéc`<¦æ–Wª Zw +Iz&Ú G Ù$ŽÂØ3dYTÇœ@ÚS‹”oe©å–CR©I•?b$.0ˆ"—f£IšD²PM QÂØbj¶Ð"¥˜â$ƒ§›z’Èç;~ÚS¢¯' øUù 7szh/h8Áß)ÜH2 §›¶ ¦ÀŠ-'~Š& ˜fÚHw:Jè«_´Ik ·ê1k®¢”Ê+"¾ÞÚë®ÂKì«¢¸š+«Œ8‹l³Ç&’¬²ËŠ:޳…¬±¶ƒŒ:hµ2xëèàö@A¹æž‹nS0D›È !PàÁ¼ôÖÛA;tkabber-plugins/poker/pixmaps/doods/108.gif000064400000000000000000000017401500237002100204230ustar00nobodynobodyGIF89aG`ã œ~4ÔTüJŒüfœür¤¼¦„ìÒ¤Üâäüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS%dižhª®,Z…@+Ït Lq­ïü-–‚`G,’n¹„pilêF¤aTà¬Ê JêÔÊUa¥Ù®Ø„Í ÇèÄw 6Ò¥5PÛ<ÀIp›ø~Ãå[n%~hkl‚&„be‡E„v$Š\eV ’U”N–$˜šMœt;ž% ]”g¥§%­‘“If{-¦¯¯ŸƒV†L3·®°™›yl¤+À&¹—»¢Å4˜¹v˘NŒ¾2'Ó°Ë$ÜÎ'«2ÁÌ&Õ%çéF£4çèì$¸ºîõöEœóüêÁS—\züîø·-`@‚øö9¬G„! zÞ»†q¢Bþ/ÄxO_¸‘+Î’A(c¿.†ZòÄL?– "g«™)j– ìŠH{¾ÄDt†ÐaÖJˆCQéᄽJfe BQWTµz•…´f,j=kòÙ·*Ø2ãªÆk"oÛ’û©N¹Õšz±« Iƒ'ø’ÅJ°Ý°Á,üà5,ö-ã¼ërq­)Yï1wVsLWhçuJ|Þ[6…Õß §%lsêz«ðtÍ”f§´kS~07ïâyéÆ .ü¶Cã&ˆ?G{…ùñ‰°YHŸ²Ž×.fçÝxÖ£cç~}=î'éÕ»?On>ýê<¶O×î¾{Ðøõ±þ'ƒ~ïõàcΡã#Ñ¡\W5ÜÄ;¹í†‚þdC|‚aòZnU‰6SèýBj †¦g=hZcYfAÊ©…ZX(ôeU\0 æ L†#h:¶VÒ‰ÕlFÛir¥ ˜Š+„õÛ_åÕ$U2F‚ÿÙbå S%% af&•@~¹×Kb2f”>SÎfâ‰i”‚…‰Ù™p4œS Rö`]JµÞ‘׸G] OåižC QcBGHDF$Ùv"¦)Yzi¥Ê@TçHþè(›íL6*›Ú¹`jž©jæš—‘³G£+”9™cRÑ ¡V°%)’ß³\'Zu#̃ÆÐ+2Éb†Ê Í[08:E9À^-jÚÎq̳^ê5m~®Šaʹ¼¼Z.3ì¶‹†)áÚÊ-¹}6—Ÿ±xÀAH½¶Îam}8¡‡³îÖpMLpÕö{¿â;±kt€añÅÒ-Ç gŒ0ÈMDü1ÉûÞûÊ©PÀrË.¿Œ ¿üBx óÎÜt žzZìÆr…Ë—+Mš @ÚI’8Gj<:U€W«>ƒÎxkgW¯_•¸(’2¤hã&•J¢á·¡,dZ”lIŒ;ôã[MÀéžE;î0âo_26\ÂîX¼Ï|ñÜÛXeS¡DB¢<1W­è¬9£)Vq5ª=È6WŸ8©óµºŸ®GÏöÌu¶¢ªëÎÇKÖçd§æÖëxmn‡¡·¦äÚ|©QÛ#*®èü¸SÌ W(ä^×x"Éã9~á?öíï$GaYG}Ðѽ·`‹]ëõŒÿA¯ÇjJ'`2±Ù—  „Ìg4úY×[ ºŸsø\°Ì'a€©È¡%x(a„e„'%˜¸ŠD}æ‰.–WÅ}ƒ°Qã%–xá&@¸ð#^ I¤GêС‘“èc’3ôh!”2|Ò"“‹°x%•-̸%—+€ÆŽYš1&–ˆˆI#š…¨ù%˜jù$œ vøßP€gžzîÉ‚8°‰È !PàÁ¡ˆ&ÚA;tkabber-plugins/poker/pixmaps/doods/110.gif000064400000000000000000000014151500237002100204130ustar00nobodynobodyGIF89aG`ã ÔTüdüJŒür¤¼¦„ìÒ¤Üâäüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS!dižhª®,Z…@+Ït Lq­ïü-òÀ ë– HF£p©!”É$sÚrBO,u{²•Y®¸ä ›ÇÜ2ŒÞª±ìöôÔÊ™ôó}™ïƒoQxEpRƒ|9ˆhN‹c%vŽ@Y’AQ—<™{œ~(--¥‰‘¢,,§+®°B¡¬*®¯+²)º¼€Š–£%À»µ(¾'ÇÁ=Ö+»ÓÔ)Ÿ'ÔÙ”ÐO³ÙÔÉ­ßÓá4•2ÍÈ5éÎMÜèÙåðàÂ@Àò%ÞêõöíÌð‘ ¥*Hª_ Dp°Ÿ$ °Ð˜„3¶9·"F‰þ+:äÑÐXÆ)J> B…G”.ÿíà8O&‚—øîÙz×¢Y΀¿âœ1nW }¤ŠnÓÁŽ_Ï¢6«ðÜ'”;‘*hŠ£—b™ ŸC­’;q*SY^u†‹ï Yncb2U†J™ÌâÝKÊb·qåh-q pý#~«Ø« Å… ϼ0¨º¨¬í={ÍÄ]w,mÆ…tî ʹÆ>ÞÌú«ê¥;ÀvMÍu¥¨5pÛ[tnÓ¨tcÇ”ÙpØL«Ì©|&fÚ6quº[øOKr÷¤Æ¾Û©¼Œ˜Ñ4è‡Þ2zÎc¼úõB>ß„™Òo{à¶\[sañ˜Ô9¼w_m¼½&àmJÑ Û  æZoÊxœ ‡˜ààƒÍ•àØM¦ÀIìGàjÓx‚(v\("pd≸ ¢qu&W (Zb},ØŽ‚èx‡ATHÆŽ“ Ð ’IÊ0c“RAYCl<9 +U2y¥!gXéÈ_háå"`v©å—\f)å eª¹&u˜ù&œa¸9'…iŠy&™Úy§‡‡Tùß3Q@h¡†: {&ùBx 餔vB;tkabber-plugins/poker/pixmaps/doods/111.gif000064400000000000000000000034571500237002100204240ustar00nobodynobodyGIF89aG`„lR$DJTœ~4¼DÔTü2|Ħ\̾düJŒür¤$¦ü„‚„¼‚„ÜÆ”ÜÚœüþ„üÒ¼ÄÂÄüâÔÌÞäüÊäüÞìüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þà'Š@ižhª®l›ŽðW^tmßx®ï<^Æ€žpH,FÁ¢rÉ<ʘÐ(®©v9³1®Œ­xص]ÇèiÕšM»oe¶ÐE„·qÚYHèûû~‚by{s ~ ‘“}‡ˆkzmB Ÿ’ }—˜z—‹œž¦¥¡¥–;›D]{¬­¡¢ ¨8”J]_Xw4Ç:…ͳ9‘W FUÅÊÉju:ÑXÓd™9Ù×6&  ìíìâŠXòµ;‰8ä; ûêN0çmž¤9ðnàÛ1àƒ~ëd›-Ù€`"²°Æš†!00p_Éþ1Ê·±GÇ l xаÀ'àDÙí5ŽäÛS&Mˆì’d×o‡°Ÿ.+Þ¡ lfCÿ(J`jÎ —„6‚^ 0–ê «H- ´°AW)öæ@ÁŽtý ¸o@ÊT.\Hä÷:¤ÿJ0˜Ð@A?µÄ ;Ç –˜  hÒ3¹†Xq3ªëôˆ¤ZŠŽ CŽÚ’G¶Á–1?pàÀ´Ö$€¦òÀ䊵wœö!1€s *\¨Iú#ƒ-$HFhr·×trà`@¾>У_ø­Ù\ؾ&Èí¥‘ N  8™_@ž€îþßh—@˜DÞá–isuâ_’ç×EÎôqy Ê!€n‡M>r´ø_€ß8Àg%¦ˆâƒ²¨Pƒ5Ðà+3zøá’F(@ƒÚÍa *Þ7dTÉ0väIŠ$€€)f˜(öø`„^Pá•<4c lùI‡"`Ž8Â¥‰g¸âwã4àc l)c‡ Œ©(ŠìɧŠkÖs!2‰iA)—Êb€À§ ‚ cP:(Ÿ}BJÊ‘ TPÁ–ÿ‰Hª€ †ië””€&j¦ªC~LÁ ¯^êJ¦ÐÉ@#9Â7*ÛIˆ&ª€þÞÓÀ`®뇜Ivº(¹BˆB¯ÕÊ…[tG‚;³Òè)¨úAß™­RÛ¢K4´ê*¬ù2g€Þ’ùl´Úø*¹÷ÚVºÆÂ·’_º[`œòš`0nVªŠ/¶ûf ŸÇæ3%­S¢9­ÁGúë¤Áp£3B,&%8ƒ2ƾæìiÙ î¶Þ à'2þÒSØÄ÷™úª]éIÆVÆ:ú¸~‰“&HžÁÈHyËÚÞ“"3‰ëK6’ß>D;.ÑaÇ\:øÀ‚(D#òK=¶˜,PgÜà çÜG/È=œ"Ï‚üB»Ü!H쫌G`$¥ À=XÏt®#"  ‚ÊÀšÆl#sPÉOé™þâ#¤C8'Oûw.±84P@p²EÇG6‘ÉW·¨¶\Æ0¾!I@@§}f4p@!¥`Èq/x’aÒñ˜Œ5ŽnP•”Iˆ†X™xZt|‘”–X ±¤B©Dk\]_ž¯x²³ ‹=  Kkª]T7«’­Â²Åɶ;ÍRÏF—€8Ö“ ÞïïàÂ8ä]æCÑ=ÖØ ð ,¢·ìF¯ƒºÐñXg) ‡ @¸z4ît¦OáŽUþ°4Ѐ þF ºX°†F| ‹¬õž *8h ïA{ó Ù÷ñš+P"DàvSéΕô<Þ:ÔcŽ™"“*U*Àiž­6£ZuÈz)(¥@±Á» °Ü‘«#‘UZÒÞhó+ØŸpˆ~Ìû€€“(¦à@ñW¹QãÞªð„ &ß¾0Á±EŒa&ç¨\òòåPð\¦R1¬d«˜L™˜ÐÀ4æ¦Y#‹¶ P‹RUxñ´x"}ÁЀ&¾oUÄs€VPLhhÊBË$ î\eƒ j¥ý÷ôŠ$L¯Þx[ò—å±€|eœ"ýXÀÍ…þx ˆƒvñ Èþ1H€Ôa(œ(#uÉÐ^}4<ˆ@„t'ßvćÈ]àØ~ 0pâ~;°€Ç!¨áŒ®G]ó„XCê@.àc…Z´¸ˆ Fi‘OJ*¦X‡Oî@€qcþHS•rgŠ*%“ä{±õU˜:øèŒ™Œq‚ID2ˆ›I*Õ€n @gþhIXy¥Ix×S’–JÁ ‡âp§,J!í5RÑ‘¶ ¨$%XJ uþ(ˆ§ÞqˆŒ à@ª„X0ªƒZ«ª]|ÂÁ:@ÌB& ·b£+¯þújh¦7§Œ‹â*P²¸À¬®µF›';W*CyüYÙ-‡È.³ô\Cj%œ[Ñ × {çU§n§®®\ôÎm(pLžØaü‹Etü¶h‰wÄ‹+¨Í2{ÈWTpšZ, ÚÇa¬€ €Ã±\ÁÍ7;슼ֹ2ñÀÖ±šÃ…DǼoÌòÎìðÍ \-:ƒ›²¢Ü’sײ%ß&½4ÎØLóÎ@ð-†?ƒÉÃÊX¤iÝ«ûæ©y†„ *HsL0ÇU«¹¶Êƒ üm¾J3ü€EàЛ7/<°ºÂê‚òzGAlx§’ˆ‹°ÔßžëöÕþ£YLJË® z@§¾«âàBðªç?ƒÎ']Á§\æ¼ætxæš+o±àœŸÚ”Y lû–¾kEºCFë¾/)uÍ.„[j!¯< ß¦Î^è%Dn|ÆÉ.ê„^ª”+ožssʶçÅäº凑 qÓ Ù'éæ·Ô Êü%g˜`×”M¸T#q@74X øÐÿ”¯|Bë‘—®Å%.=p]p4Q!)©è€$B“P$‰5Û’`†´F1,ÈGERÊ V˜ Öˆ:XÒ t!­ƒùã‰D4òÔ ÒÚzD8CŠR"Ö„à¤æ0hANÄþ§ˆ¤¨@0b‘mŸà>o|N ZÁ©á|Ï=áÓCX¶F€GZ\^Ö8  8š²àáʶ4ÎÏ‚ÒCetT¨4ÚQÜ€-áŽèÑÓôJñRól @ ¬öÌá ‚b?t"¢P‚àª)åcp€ãC<kü‹¸M €þP(ö€Ø*ºôÝáèÑa‘‘o¨lÐÀ"„– €Æ€7o6oF (¨`„+´|05æ9†'’*•7‘àS¨ ‚J­Šgaº2™hcJCš„‚|xÀ„¬šÕ§NH%Áè1P)]ºR Ǽà Z_9hÉ<Å5!ƒ¼TÓ½•‹/Ú¿zRøª8ñáÅxóm'¬Ê”†éþ¼LÛ‡ê¬wHû˜+lÊÙˆó G}V«Ëöõ@ÕõàÌviot[Gî  ×ÞO^FT\œ axÞ^Õ{}ÖÎ9´D Ä‡uá'õg´ ¶}:`€¾°ž`€øX þ¨‚q«!GZýÉd€Hà…@”†“%Ç`ƒ(PBXa‚hᤈ †ÚYvŸ?ˆÄ P¡„ô©ààŒCˆ¨ÀCÞ¡L ä’L6©d’O~äjDY‚F–8€†H1¤OZ ^– úRVPb‰’ਣ>Æ)ç€c¢Y@éQãW‘j–x‚숢†-`iCDžýÈ!âš%8 ©¤žH蚘bZ‡&ZdfB:)P á¥d¦àŸTÀ)¢ (:%n¢JÊ顦ö§¦ VÒ¡¤­¾Êç‡>øùÀ¨k–¨HVYd¥LÊê Äþ‚¥†Ç:p«‰€ š©‘«’:À´ÒŠX­I2gk‰¥vÛl•A0í­¥b$­³Z'§ºÚ’š+¡à€{Á¶õpo¾½@ª‚ÙÞ[)’ø ó+ÁÓî{.û6ìo·òeÖÄìk°´ûpp¶ôº«aÄ7Êkk»ÇY2 k›¬»ú°üp´÷ƼðÌl3»;³‰‘<;0@»Yl¦_B§|AÇÎ"½.®1z± Qû[ô·;uÓ»nÍã ãŒ&¼Ë†{³È~š]ÂÊ\¶Ðê“æ®ü:4Ì}b)·«‰ÚMU·+ø)ðËí~]£«mZ¸¬™V^‚†a“츹OËÑáþ±êBºaŸ)š@§&¬j0çë˜`¼hº6ç B–‚\€ù ^šàMߘˆ$™Îâ¹_R. ¥“Ð?ùð‰U³µüqîõH-„³#Yc„œ#.+«Ha‹+b¨`¥è8ÀÜOE¶ ó1&øŒúæ«O¨GÆØ¡ü T ZèšO¥ö£ŸîÈM5ÚÐ@Ñ hè‡=‘ `qp@›»”Ç0³ Jsr¡ˆä§= pà¡áÀ$3ƒ K«Ò"i¸ÇgªÎeðr™‚P%®á £Ôãg‚±ÌR¢À8€¤ˆ,¤Ë[ó¸Àà0‹93£9\¨™×ăX‹®¨œ8Îd*SñM­xƒX¯s‘óƒÇ¬H©c4P!¤ prÈë­æ(eL,¤Â’N„')¹IªðF9t¤#c„,XòH•,à/8¡C%‰hJšh( K¬8@IJ$¥L$ðð1{0ÂŽ’œäR R…vÐp5}ñ˜#ŒÉ‚lä¤ÖøBøMb cˇ8ŒbÍYÂÜ,ãbTÎc¸³å°E™tžI“[ô"¾‰V°â ¯ˆ)Šp{Šá¡à„'šÐN” Î|&ö‰‡FTÔ •ID Š…?„W¤'Gõˆ8´!£NRù©ÔÙÄFJ_J„v83 4Í©@H Óž:á =}éOIàÒ F.HОR—ªÔ„;tkabber-plugins/poker/pixmaps/doods/114.gif000064400000000000000000000021301500237002100204120ustar00nobodynobodyGIF89aG`„,6<46TDFTDJTT^l\fdœ~4´z$¼šD̾dlvŒ$ŽülÎü„‚„œÞüÄÂÄüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þà'Š@ižhª®l›Ž£ñ•Qmßx®ï|Ÿ—ÉG,€àÈl:#É™Îñ¬V“K]ÖÊEnoµKöÑ~ç² CÇë8ô[GÜòxº†ç×{s(j{a)p„V{ŠNi‡p’‹['6˜•OŽ›€tžŸ:¡–9¥ª§œ ¤¯¬®ª¦±L{¥«¹L¾¿„i¯´ÄG¾ľi´ª´F¿  ¿yÃÎÉ«DÒ¾¾×Ëz_°¦¥Ñ×%%ãrÝëìî%÷ä… °öÚ8Ðà]¸qÁú•GÀµ÷‰"Sê¾ „g1a™NNPÐàÉ þ’šØÅ—Ew7 Б%q!N‹(Oa™äÉ*@…êëi³KÒœð˜ú< X§&$ꪊMV¯_ÊÈ=- XX^¨"KÆÖ*ЃUeËÚ" q@K3‚ž p0 @<»„‘ 8à°`i}ìE– AƒË—ÛM”ecθ+Þ£7ÀZ¾lòdƒvkd74ëÖ˜ãFîAùÁe•+#¸ [Üìq¶ ž@cÉâ»yôΘ-` \ζ˜0ÝæÏyöFJïâ¾ ‡Öh÷í_Ñ«/`ùÁç»=òÚ@fþulÕï•‚œ{Ùqe›}âþ¡_ ªTöW”MS)Öd÷ß/–U¶’ nEJsÄfá+Hx5k}ÖpâÇC‡ŠÙVÚ>†IsMV† TW”¨Ù0Yƒ=P„”H„Gf(Xt8 ìógƒ|gƒˆ…:K~‰~ŠnŽ‚„:uGˆš•4ˆ—cŒ3›hQ‰A§ŸZ©œ2¦ƒ²_z2𦔰dB›À[·-š‚»¤TÃÄ~º”¶¾Nž¨ÐH§ Ô«ÁÏÉØÜ‘ßvÞá+Êä"æç&ãA­×+ññ,ª*òó,Ã%²ê@€ß?ì ìã篫 ‚ƒ·pÀÁµ<ñêPûÂ÷.JÒx DÈE é+æ*%‡“ŠÍÚs†²xü,Š ÔlãËœó%¬ØÐ!­NDÊPäN–$’êüh•UåQU‡’+—^‹„­vl:³eÞmánÛ–€mÖ^…*,-@kn©Òˆ¬[•\3û:‘ût¥O@'Ñí¥¥R€K‡˜M0ax+¯Û‚uÇ(QLìâ1LêrÅœLŸÞeLìX™Í¼AYölØPD«SŽ÷7ßÓ²„¾]„ŽkâkÞèÆD xÞÍÄÍ<貜¹ðãÑmÏ®}{t"jªÇõ‚ãròRpGc}â™g€a¡¾ýû2$;tkabber-plugins/poker/pixmaps/doods/117.gif000064400000000000000000000016501500237002100204230ustar00nobodynobodyGIF89aG`ãDJTœ~4Ħ\$¦ülÎüÔòüüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þI ª½8ëÍ{ž Rdižhª®,Z…@+Ït Lñ9Ö|ÏÞ"ÝÎG,Þr¥KqI0̨ iy"¥XÕ®jÍzSÛÍwܵjÈ_gòŠÆªIï6ó­”»Ùf¼½©ß{ã~Yow'ˆ…QNˆŠKC„Ž„>;“Ž•<—ž”)¢£¢5¤¤–H”«*¥(¨­£¡œlš¡2´­¹S‡‰¸2'Ã3º2€À2ÂÄ$ÆÐ¼Ê}¯5ÏÆÓÔ?Ö&®&·ÑÚÄÎêåç%äZâ$ñ%Ÿ&éÃÙß÷^%3ïÀÀæ<Ó'¬€¿o ßÁ Ξ$D ñésöÏD¢FþOR1&…%œ©ôxòÝHË&²ü„2å0_4]RlqPáÅ_øPø4 ”ÞN#­%C)‰¢FWÄŒšBbÐV©,i1+?¯I-ÈM(ÍbÎÞœY3e‹©n±9œ«–Ç7y4î²È6€nÞ°U3õLoJˆðŒØp4c/]¥—¶ã+ÄȉÂü2ŸÚÈ$±õ³ /[惛½ôìͱäì’°ùåìÙúÚÑ€‹6­0tA÷­Ëmî×Ý“{ó3|ÅðÂË]ãµËüwñæ­Œ/ÜËn:Ù£h¶÷wé¡ó޾›º^ûչצ¡Ø!éqœ“¥ÎœÂ³0Ð0%þ××qýq¶f®ñó× ¼••Wf~†ÞUGµà˜ýùEÜ ö7Ÿ…f…õ˜qwå„zpE&">òá•LÓ!…Õ‹VE£V¯ñd†KÕ€Q&O1…czιd[Ñ„( QB˜¢‹&²XbN:UÒPm©d]1)R…»øB”I5tßGhŠc‘6¾ã_eSfådAõpYkühs&’ổÌKnžWœn]ÍòÖd£Î:ìL£•ôåµÍˆŽÄ`r–Ó"7Î ƒ\‰fÊ ›—úP§A²Är꩚z «³¼ÊÂ; n‚‘¶6õÔ®p`º •”ÔjkKÁúú똠›«ˆÊX. U³Ëæ˜ë"ÆN+­µáÐQí#uˆm©×~»æâŽuFåJv.´•„‘»ÜÆÀºéªë¼Št Gõª«ý†û¿öí‚4ìðÄ;tkabber-plugins/poker/pixmaps/doods/118.gif000064400000000000000000000013621500237002100204240ustar00nobodynobodyGIF89aG`ãDJTœ~4̾d$ŽülÎüÔòüüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þI ª½8ëÍ{ž Rdižhª®,Z…@+Ït Lq­ïü-–žpxË‘‚än4*Ÿ6'J•M™ªÖ%Ín¿×Sø 7ÉÛëÔŒ&vÏmªÚ†1u¹3Ofóõm‚‚mfPŠ…{O”'™’–—%‡š‡<¤¤ZS¡‘;¯Œ`F™´¬:®Œ¸}N¢À-+¹¼+ÃIcš-Ë*§'Í=ŽÒ)µB×B~Ç«Õ4µÈ;Û*Ñååßæ êâŽÌª´2ë ôî;µù3ùÙQø¡ödÈcg‹Æ8k‡¢‘(oá0†3®ðFc]²wûäñèwo£>þü´aäkFI;#IšD•R%‹“eZºìVfÌ!¼lêêI'®gþpê40 –N]@ƒVÌEÂ&u™Ì¡`Zj@¸ˆ2M À©Ä3Z 5zõZ€ÀU+YKl­dì?±¥N*{¶…Dµ\M=DPÔØ¦t—¤%AÔ”MVí RåU—ÅÝNÉA4AušÐ£<ýN­,MH_d|‚Þ‚³Ò-L[®¢šDk¥;†…{íú€l%M|®±»36°£Šòpò<š§ÿ-\Ø.ãòUf~ŽgÆêp±þ{«y"÷îh·×Ë.™o@ØéhG¨|øß’78]÷|ùñßÃg‘ôÓzý_¡CÛj¤å²K/²„öJS¢àMn4èÕTÖ§Ã$ý}óœfÖ0WWð}„……4$²ÈñØÒaEƒD·z&¬ø‡ÕÈ8#u\ܨ„{6ê¨B>æ¤`ˆAâHqäŒk¼1$}p(ù$”?.ù‡@æ‘äˆSÒwAŒVú8G—II¦txñÙU¦‰lö€Cœ6À&“>„ ‚|öég!D;tkabber-plugins/poker/pixmaps/doods/119.gif000064400000000000000000000012151500237002100204220ustar00nobodynobodyGIF89aG`ÂDJTœ~4Ħ\lÎü´æüüþüÿÿÿ!ù,G`þxªÐþ0ÊIk\ø4ûÿ`(Ž$Ød@©®l ,i+Ïô«ÑxN¾q÷èÀÙÆçYCCñÈ,%“ͨ)&‘Z•Ôêµ9„B·Án fŠ=ßrNÜK«kíÈ;<† ew“[ù`zF„WiF|x€R_’A„•VP’@‹QI‰ž‰:†–[C§ž$°!£²8­¹¨"º"´½k=¨Ä%Á x!Çpµ“±¦“ÎÆÐз~¶ ¹¯¯ØÙ®ÚB~+ºäÓäÝ*‚#ÚÔ»¼ßèNâãÅÜôÄî.ó-ñæ@êÌIc±,\Žs!’5+¸¯Ì/Rü˜<ä1ˆ*U*êåþèÆ•.eòx…£(’:Ð]T6ÙAp &2lø2žL˜.gDۉ̷j9ûÁké-ÚO}+²K¢WY|£"4xKS<½ÜI\‘ùÜa¼ry&A°ãª^¦.×àv-âFÖð°ñܶ¸íëÚŸÑ5J–˜/lÍ*ØÝJ•êœé‰åŠ«†<Ú4ig£ÅeRæ|3íØÒßÕ²ÞÏ€wÉׯ-›b«ËŸ·.Ë„€ªøV—mö9Š÷ñÚw;µ½ *¸þVW U—_yûõÕG'ÑöÍ'y u4@~ €… >Ö•…j¨!B&IÈ‚pwáŠÇuÈŸ]! 3@€,$¾(C>µ´¡ˆ+ 1ÜŽâU†,GÓ$v(*'J?M:C%•£¥sN”‘ùRex¢dVÙv`¬¶Ød-v8¿pÉftíìÖg¼%cB”ê|ç$i˜ü‡²‘‡3vÚsPB• XT`Πsºù󩾆'±>Ó*³cÏ­Evå!Òã ±F­F­Ü šm¿½œ¢öì>¦•äºâhÞ¡ôs ²…_»z¿Hêio¸ºv NÍHQòܾ£ò]¬ë²á̈çÆDëÔëF³` —f©Q±Ïh )cÑôǫ́–µÖ¦{;4!ÇoqöÎ:Tö°ØÁC—ŽP8ëÊŸt;2Ú5Ìé:P§þ«Ú¶é—ªI{7M»óæñ5¬-ŸœÜ®õžS&^Š-VÆõ­cÞA˜‘àÀýÀçBl<™“Ìê$Ö ó{çh“Î3Æ7àE_esÀ2Í„& ƒÈ¹ÔP/%³×y 5˜ &"öN@*ò° R£¢ÐXœc`¢ †s£N°,š0ä ˆ$¢cDKÒ…RÒ(_ˆUò–¥ [>fAX’D]¦E&eŽ•G˜~ÄÁcšt饘a(Éæn¢ çxkîɧsâ™’?ø‰Ù—@P`h8,j wÒTj饄;tkabber-plugins/poker/pixmaps/doods/122.gif000064400000000000000000000016201500237002100204140ustar00nobodynobodyGIF89aG`ÂDJTœ~4̾d$ŽülÎüüþüÿÿÿ!ù,G`þxªÐþ0ÊIk\ø4ûÿ`(Ž$Ød@©®l ,i+Ïô«u­ïÜžP¶éýŠÃ$ Éü)ŸŸ&Î ­JÕ,Ö˜ÓZïW„'ËSª™WîÒÁ`xÛŽ÷|4·CÑ:{,‚gj2„ |~B€ƒ"Š“Œˆ5Tš%—s ž•DNš§|* +¤,H¨ ~¨"«®"¸°*E´½·§µ!»!ǵ¿%ÁÌČ̩¼ÇÎ#²µÈ¾Ü³››¶ËááÅ¥Äè׿ÞÊíèÙ!hëÆÑëÖûãöQ ‘£'Žà»~³ ¢‹%Г‡qÝŽ€Îá @ÕËEþ‚ß·‹ á•ó¸päFñ´…üµ/B¬’rFLŒØxèâq³aÌ«@ÕlçÇ~!>…by2#Ÿ¯Yšd€,j.—´‡5„¢—$ìát&®l‹²ç’jͪ± ÔóÞZ|š”©?‰ î6-– £¨¸$Û&”‹­¯¡¡‡%~¸—"½j÷« Ùµ­*•Éàç±rfº/µ”gî1iÏ„ «å`q^a›sIÊ Ú’¡+ôâýt® C~`%NT·‹- ¼äïÏpçDoÚ‘¡·f왳Ibr¾pQY§î%v'D^²fõÑF^®2*·êšï›†þÜ)þ÷Áý§Xlãaf‹]þLw[ýùÇ€{™4 Lª­öAûMVZ„Gegáw#ˆ÷Z€bmÕÑf³Q2"‡Î5hÛ‰)UÀ_,¶d4,çš EA¥S+BôMC‰ãi’Ÿƒ.~ˆänÙ Wà3!uÈ ;’ô“Q"1¦_}ùΖU˜N¸ÑO2½òàhï%h#}ÕœyPMvÚÈ—¡•!v^Ò‚ÌU{ñ9—”Vþç )Ô)6Å!ouÜš‚ueè¡,î„”žÈ!s©o@çæ2zóé(a ÀŠ(…ÁØÔ©/&E•UGnꬼ• "py¸«œ°¹V‘Â;®‹dXÓ‡ÜXÅA+ìoyÜZæÀà„,¶ÎúÊ-³nlñ-¸án;n›â¢{î±G€qíºÝâ/»âpü ¹aûøÊTm0ôË ü ,S0X ð WA;tkabber-plugins/poker/pixmaps/doods/123.gif000064400000000000000000000013301500237002100204130ustar00nobodynobodyGIF89aG`ã DJTœ~4̾d$ŽülÎüüöŒŒÚüüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS!dižhª®,Z…@+Ït Lq­ïü-òÀ ë–!.¤Î8Ê(Ÿ-fL ­¦¨T«–„-æ¶Ö.÷ †Šä²òlT?Ùiw.{ÑÈz2›× Û~[€aq„v(‡{iŽ2ŽŠA‘Œ&‘+—’;š_Š”›‰—@s9¡”'¡¢-­±@F𤖩¶°¸«KŸ$’¯ªµ¹,ÃÄ4ƒ¼¬»˜º­ÂÍ6ÑË¿¿ÁÊ×Ö³†3Ù%¦£Á½¥Ç×àÐÔ圵·ÐÜáîÝZ¤ ékÞ“ÆëˆVöêÀ ª0lý¤™ÃÇðœBân¥‹¸c .xц½sE 3rþã@¬¨/¿„Ëøõ(RÕHZÞC¹Âb1`ÚN ³šËx$÷p hÏq• :$jÔ¤Cd,RD  GåM…ªE€W;€õ*0j ¦Èz-ÐT‹M;‹ €`‚¹r³úƒ‚VmÕ¶…º~ ;V¯³)ÏU½jXcÇvéúJ¥1Ò’¥&õ¸m]ØQAVÖP±Ì—iœ-ÑØJÒ¿Å £(ÇÚ8¾V:ÑáV®¼6Ä7ã­3Ð?×/nYö³§›¡¬.[o¶ÛæèˆÅº×zùìÙÉmýÍ\¨ŠßÞG×NŽaèÇÎEBoí:8ã!qßTy~þÄõ¥‡ÐLâufÂÕè&›m“‰ƒ`~ ¡ÄL &ÆZ&óÍôÓæu¸5."‘ à‰¸á%šxEŠ*ž¢ˆy´ñâ!NÈÈ¢g Ñ¢ 9ÎHH7ÖäŽê5ñ… IdMwظ$“:ùäŠHÈøÃ”$òA–KàÀeq0™¤!ˆàÁ™h¦ÙA;tkabber-plugins/poker/pixmaps/doods/124.gif000064400000000000000000000030671500237002100204250ustar00nobodynobodyGIF89aG`„DJTœ~4ÜnR¤Z´$¦ülÎü„‚„ÜÆ”üþ„üÒ¼´æüÄÂÄüÖÄüâÔÌÞäüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þà'Š@ižhª®l›ŽðWFtmßx®ï<^Æ€žpH,FÁ¢rÉ<ʘÐ(¤Øå̆(!²àáÖ6›seZúÌŽ¬×V—Ü~Ws…¼~Ïçô uwj„>zŠŠ‹ˆŽˆfv7‡š›š™‚“I¢i–7ˆž ­œ ¢£…µ6h¬‹¼‹²;©ZI]&_·„}{y¥:¨ÂFUÅÇÈÕËs%Õ·ÔàBp8â·ÌêëêËîã4âñS†9Üéìëïîæ,Q‹€ÊÚTúÂ} ðªÿàU(p {æò à!* #nœ7H¹‰ þolÇNäÄ‚ ^<¨Qáoât9QžÓxì•\&P%ì©=¢Ö(;éEŸe[¦v<ùræòªQ:ïH½®Hx„ÇÇtWàSŽ1“7¿Cº<¬\p²=¦Ü|— þ`_xÎí·[™!$ v €wÞu¡ &ÍYá PdD¸@€¯Q¨rÀ†àb@yêàY$H …–Ñ—ÀŽ,v8Þ‹üɘ™ø”Iv³uq;®¸`~ cP4øâ"â½Z@Nr˜Ÿ–#ˆqTYÂc/2€äcÌiØd ’õQTn€v ¥2‡xÉ㓚xúa>{"ÙUõ}â%˜tZQàc‰ª²h€0Ðé§Ãð‰&‚†Ù¢‡j—iˆjzꦫ²‰:j©•îYàS*ªægŸúé¦&ú¥©¤Tøž¬gj†£®~†¤¬³Î¹ ­}þÚ·jšz~új¨£ ;¨}{þ”U²älúMG8vè°,àÞ«Ÿ’¹Ÿ¼‰Y·´Žú,¼˜æª©šš¼K ¾Ò|(AÚrt­-ˤjü­»vÊk¿h2Ì\ÔjYE¤’²[¯±ÚÆ»°æ^š›ÄaRëf§}b¬ìÆŒçf¡G»c¤¶Ê3›ªþ²ªç99'1]0w+›{–pòŒ“7¦x ‹ôÕ=燥”£¬¦ÔPæ,éÕKº$N§7s0Œ‚³ø–€nƺéˆQåÉ4ï×/¢Ñ-Ò(Òw+–¯A°@×P·Ý·Oblj"ŠáK8iœ­=âIÝxŽ"göäþåueù=˜O]¦}+ ßeuŸMÞo‡ž‘•‹k7s©s÷ùëÕ‰^n•Ôl!L}œÇ—ÞG­“·ÞQDÊ^ɃeÈBz¿ÝÚ…mG­akñlZi‡­‡• }âÕ\ˆgFŽ—¹CY¤±Óèa=­~¹%ÆTü:†`õÓÛyêàÊ0„0%hÈ\Ì'û1$Ã3ß?Îâ?½áC€Û{`[¦ó¿ â$+WAšD4liÐ+MÇ”’Ò¤Òdr>txp'7 7X¢Ù‰()< K³‘Êý®‡|ŠH@ÒˆØn:<$‚7('‚ä#è‚b ó„D;‘ņM¡¹`CFHÂôAá+`t‡Kà íÉð„1´ÍÈHlÃy艡^œá 6ªâŽ7À† ˜ƒ ÀˆÜ…=YƒbÐÁkg0d&\1IX(2 ÿ‚䌈ЀVP²“tE# Ž-èEcXèd/ùG$b/”C `â–y¨åˆÊ(8Ò,È ÐÚ@ÌX³ Æ<æ’©L0’ Ohæ ¢Gi6Ó Ñ´&°I‚ûi³1@0ÇIN9Ä ;tkabber-plugins/poker/pixmaps/doods/125.gif000064400000000000000000000032271500237002100204240ustar00nobodynobodyGIF89aG`„DJTœ~4Ün‚\žlR¤üZ¬4Öœ$¦ülÎü„‚„¼‚„ÜÆ”üþ„üÒ¼´æüÄÂÄüâÔÌÞäÔòüüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þà'Š@ižhª®l›ŽðWVtmßx®ï<^Æ€žpH,FÁ¢rÉ<Êj Ó‚I­ÒŽÉJ±z•³k6ü-óÈè¬y}K×ÈìxÅ-–ÛésuÅÀïûù)KMc…5 ЋР% ‘ &E–Kxa‰ŒŒŽ 7QC–¤`†u4œ‹‘9z:¤—FY[']‡œ­ ©a±7—¥´BpQ%S¡œž®©ÑApÃųCÔ¨6ª¬¾©áᔲ³æƒÇÂ;›½ßâð¼ê؃ØéJª­ÏÊÊäí …ÎXm<˜à Ô»(á’ äQÊT%V&~-ð'aÀ[Ô¥²G¡v þ+x|î݃þ&â8‡.›Hfþ<½ºö’¥K˜Qݤbr˜Pg%¼ ‚RD[„Æ)zƒÒ_ïàÁó—Lêª>2ÒX°€¸ï˜òëа;¹šNí€lßÚ4õ,Ož¹uým RïAÃy\MJÒƒ¹,h<'Bá7ˆ1—ü”„qYÇŽÉ^Y @á‰ÛFoÆI*“A!+š²€ &E¶ZufÖ‰') ]Ú¯–64JK’Ì[õjL®))¸;yÀë¥sƒ"—çy5ï*{òâ8hä¶öÅžl)€ ~½ÇÆ“¯0ÝüíTàÀ Êm—S+|þGõ!p~éGž$Åýà€¸-—À$ž|W|÷ „gH¸…¥¥W{ÊåI Ö·àáåÇÞ#ä!É‹þH2‡lÈ¡' a‰($îðš޼ø PNÒ‡bðAðÈ0ð’aÀ)–À9Ë­ˆ è  V=Ìò‡–,çSJò%œ X9=qéš'ôÀ‹sNIA$d|ÜÝ“%8à€ | *%tÉNšç•¿¹ÖФ XB¥—)‡& ç¤02ZK6£f'€¤“ÂI¨ª™*–h§éÝhå4lžáIiúÝ: ª`Úk«@^¡ß¢üþ$©µ*®Èž¤¿^ªˆ¦e)i¶ÔÆçèAŽ|y 쥢«·€@ À¸ ÌqWºWžk¬#ÜĶËZÚ¬ªà&ÚY½Ü›nt´¦ÓŠó¬@H˜,î¤õ&¶°µ°à›o»×¼;ðª®LoÆsl¬oBÔ0-·ºRÌ«¦®á€&.Êp6)»ŸÄÞöŠèÅ7gÇ^;óŒm¤®*3Á4+z¡€°æ{=?ó>»B äÐFLi—ˆQ²4ªìõ×á*zê”ÃÒç5ŸþJ¦Ú«²]¦«~t— ©¾úØ90 ’œ#dҽĖAK¥ÚÏ€bùb^ÞMvIiÎQäÂþ›6«#T¾Ry8‚|5Ï4,hŸÎŠÍПŠ,¸‰ªÿ]„ˆ`_:—I¥…ˆÛ{ÁN7ôÉâ}±º2zq_­·+¿²Í;ˆåWMW]zëµWÜñ¹%Ï8"αZ!Ó§ÈvÉ%·]£Jfæ¾sÓDâ7ÈÅ ²³áàïZ¿ñÍsä±ñÝ&] hÄ šØm®¾¹BH,€Ò ‰,j ád8'ù‰oÉi°(<¦.k ˦?X¨ƒËÐ`$ –i$s)/nX‚»ÌÅ#u‰:œ¯¥)&0KLĦe`.Tlb@²¢•–ÐÀIŽàþC±„(”€%·P K¬=EÔDwSÊF–ò˜|qHú À2¶7s\K…gôI8ÖÈø,b|ìcEþˆt ˆø¢ °ˆ7®®±¡Æá‘A€q¼@d"gR‘()$ÉèZø3IPÀ’—¤ˆ5ü&ŸtQžŒÕ!a! àЄ–ò)V–¨ËJâ@"ˆôå,{Eƒ˜‹â„(o±ÍŒ¢Ä€%ròPCјÖ4Ž8¯ÉL%匫pc8ñ@ÎL^K”`¤d:õ¸ v’³¥+æ*6²ÎSà:zÓZÓO;È!54(Å …²Éžµ5ñò†'D´ Ȭ¨E/z$pô @HèG[$¸à¤(Mi b;tkabber-plugins/poker/pixmaps/doods/126.gif000064400000000000000000000032171500237002100204240ustar00nobodynobodyGIF89aG`„DJTœ~4ÜnĦ\̾dR¤Z´$¦ü„‚„¼‚„ÜÆ”üþ„üÒ¼´æüÄÂÄüâÔÌÞäüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þà'Š@ižhª®l›ŽðWJtmßx®ï<^Æ€žpH,FÁ¢rÉ<Ê$'¨‰I­“‰RB’l«`åŒ6‡ÏCóÌܼ%ko´z "îÀᎀ¢áotU y……R€lKŠ™z˜–quA“E ˜©¤¤r džD•©·ª¹»•:_i²³L¯ÄŤ¼9 Dc][Ï9<.¬¯8 Ë´9eSQ7â:^çèç%¤8ÐÓB¢<âöÒ ééëë¢ÓÊäõ ·ÃÞ8ë” a¡¸ë¬00"ãî¤èÅ\‚úFœH£"IþÃi”`ÐFBt aB !‹ó¸!4ÈsbÂê 4 `fÍp7OvÓ©2#Ë{ó} O(„¢#m¼8ä ¼¨æSVš'Mr-ÕÍ€|TÑ)„Ð-ŸI×vméF‹º»2û)x+PmN¶=ŽÝ§n&D_óFSî.Ä,f¯Ö}XÂ@ ÙŠ!üvæÙ‘40ÀÚ³äÐξ•8³Ÿ¿·Z$´²u2ª&JP0¼4qÜRXÓØýššè<³€"œÝ›Ö­#õ†]$úgÂßaN†;Žº™óÆÉ}H9>À;0žun÷W§÷ãg»s"Yô!`|á9P+YØþ`ÍjäõÇÞB%„Gß!¼’ ,À ü%àš;¤TCeÒw¡bhí¢k_°¶žR><Ç…%Lß}ºø ê§66Wâsòñ˜â*~Ö¢gÆ|èZz(‰“<öŸ Þ%€x6’B¤‡Ø("#7ê…ÒôH_ ð8å‹2‚¨\zlj¹Ô@ HPä À˜–I¤‘Wbצo[Ùc(~ôh'™/ZÉ›t'<¸dNvYi$,!z+E¦ÉE CUu—›9&E…J@xò@ežz‚ÈêPTec_¡­ É,)¤ºœ¯4 ëP ¼ )JCþ5- 6ÞêÜ’)vR¬ ÂڰБæ†Üv¸·òY.´ÕêHê’ôÖ˧g¸¶Û!¼óYék¾×šë¹ç쨆Ûv ^#6¢PmµÍÙ=°€[ø VÖQÆÔ "ÒHŒîW˜Ùl&€— \—~Ï'wL?R•q‰å<1Ö§Ø—!²C.âx¡BTR’’(‘XLDˆC(®¹8 †<»EÃO³VÑ"ÀbÂZ·€ È™Íݪ ô"èêÔï_¥Kß,·0»@©*H¬xñÇl!3u+x0µ1z"æ¬øÀÚ×IÁNž\zÂËb6ÞÜk×°'%@»ôm2P¯èÊ»7ðà‹—&pü],0g­÷@‚ïÐIŸ.¸ú›ëÊÍr×[õyôÙä)ãî’Zsoß P -<¾àqÍ×…öu†Wü‘&ÝfFaqVg4Pa~¾·àþT6;ExÅ÷]^†ýù7€R!b!ÊD…ÎågÀwàØpä `š/H×, #‰ÝPÕ(¦‹UI¤Z8”A‘VИdW ¬•€“Oàá\)ãPY‰åVhý¦äcýmH”!©Ñ™h^g§™V|õÜk:Æ©bƒTì¹æÉÙI¤It5 6^+ʵ§‘çuaä¦&Mð'œ`–¶"¡œbši&(Ù Îeh ¾åßœòBFQZÍht“N·"V¸¾ØEr…:TE¹‚Æë†¿ÊETÇš:,z!0°´%©xO®èb×jB œ áPþÁ’áïu QêâJ²Óra®ßªì*Hé»!ᛸôR¹ÁÂRÁI[ÉÚme!•‹Âõ¬Q 3B7Ü2˜SÄ^\1„àbü-3Éù+|EÉ&[ÒEÀV‹ïî¢ûrÍÌÅHœÕ@PE8‹ZiX°³Âàéµ.J`”ËE‹¨Ò?fÕôËW[ÕߺüáV òe²¼c;ò"ƒÆ,–ÛG­|¶ œœi”‘'ž¥¥((¦¦“J™*ž­´$©ª«%§¤ 6u•µ¾)´  ¬¶³ÌWš$Î+ž ÇÉ ÓÍ4„w&Ã-ÎÚÔ܇)=¶ã+èÏ2èÊë í*Æð,„'óôëÒ|SÆj?¬Ž$ @‰†ÄÀ1t8a2 ¿˜+ÙBþ †$@$Ä‘‘aÌXfã-k`fH2l6ÔY3¥5–&¾Œi‚'Íž-ŒÒÄéh ¡ÿ•Pz3çÑ¥ý¤ºp¹2…É£$g|¥¶ŸS$\Ï*¸J‘Ûj¡¶8úƒî%j'¶õ²EÜ´yg2Å·B0Þ¿xµ¢L¸pbÄpΘ¯•¼dñÁÌ» ¡5­QaË|Ž•Gþã|K¥>~H–‡‘Äç[µý^Ì+×kÜÌŠÍø¶ßÊ4>) ®„6Ûéóbœ W!·WdkÕ•sú|öÞÖáÒáúKþùí»àŸ?®¸tõë÷å{ÖÿºïËÑþ2*?ñæŸlD wŸ4œü6Ànû¦Ài´t[m¬=x@WÜ¥µY ©‘‡Ûp£äa‚2 £ZFZT_±0eõ¤¡R¥`˜z&â5Dp­Ð—aWKú•ZoÕå9A‰ÂX(‰ÅVYå˜KTíd[<¾ä¥g(*f™*¬É؃/¢•Ølj.…URvVÕÚOUâcÌ„õ•¥ _­ÕPYÊÆ_o$¤I¤¡¥ðè£m˜[’‡ñ s=g <È%gO‹8rÖÝJê8jï°vj@¢~Cê7å¨:Y0acÞ.¡y£À« ¶XÌ5ô˜ÇËÞË«0ˆå¢K°µ¨Œœ?¸rl³ÏÊj­´lÀ8Ç+FdÒ„²–"˯Е‹‚¸T[.|¸û.È«.¦÷Va¯$£P›ï ý¢ûo rx;° û{0·çî‹» /Ì­¹K¼.$m8ÜÈ´[¼B¿IxÌpˆœBÂAa20¤+ñ !PàÁÌ4×ÜA;tkabber-plugins/poker/pixmaps/doods/131.gif000064400000000000000000000015611500237002100204200ustar00nobodynobodyGIF89aG`ã ìüìfDü’”üž¤üêìüîìüöôüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS%dižhª®,Z…@+Ït Lq­ïü-òÀ ë–KŽHp©‘’H¦Tæ4*§Xjñ˜í®ªÐ«× ÉÅ÷œ­ªÅli¹´ŽË·âº}Y†îï&~Lnƒ]…†XsOp‰M9IVzŽ4NaQ”Œ—™š›‘6i‚¡•i’2«¬3ª­Bˆ(ª°°¸®+¹¾º¼=§%*°ÀÈÀ*ºËÑ@ˆ-ÈÉÚ±Í'ÀÙËܪÂ:ÚéÚ¹ß$¬ìÈóëÁ¢çõêöÞñÀúêÜÝ›am…€íÞ±Z !=]; ; n_7f­¼UT× VÄaþ½ní[ö¬d+ºF&»5°…D Sª3€’¦ªš5oAS·k•§WÀTiÛ¥³'Ê]C3Â#ÒÙ³†ö2öìÉ0UÞýLS×U]9Ÿú‚u®§KµÔ`V“¦X¢AMÆ„»õZܲg‹Ž% ¶¤Îº,0ÆòFtïÛXYÏ6øì¨c´,#+\r±³©,ƒ"ËM'ΠåðÑøE™YÅ:†{ËòÄ\8oÕ›õäç 3„ª’+¼Ïp×(l3–ènõ†=šYf·É¦šVíðÝïðª\8×dK—M îÕùlßxÏútísòc›uehNG«¸äÑñ›ÎºþpÖgåþtaòAäßu‘‰åÖ‚éMWMx,`6Þtµö ²W Qîx!†VIÈß3!~gJ¨½µ!.ÚTÇ æMHá>|@¸Âvy¨Ò,6¦2ñ‡Ë©ñR Ç T`’Ö$h…1yà ³DšXU¶Ód %@”SuÉ‘=¦€L g&p%K$¤éecžhª®lëªVX½tmß@Ü|ï39j@üŽÇÜîT$"Ÿ½’©­ò¤ §uKÃ6µH„Á€à–ٯñˆ ÚeóÉ»N#ݦ¶|Žƒ}dy{&tLu€(ƒ„†Sˆ>nz„@}jP“”CMHbŒh\ccbc¡{že {vO˜“Rœœq²KjTGd¬¨iº¼oo‹­•_l¤¤·fXÀ™PÎÀP 'Ö¸*+'Ý( ' Ì à&è>Ó' -ÝÞñyã×å'ðàó?ì/ñŒw@¶{evS(p¨  Lp…‚rpØ##Áƒþqâ\ô¸c} `S  ä=”é™ì!±[Eq'ʸ»XÓ[¿‡7$Vd€Ó3ž‘ø³ï ¶qØTDê3 Ð7\P4g YŸ,¥!nãWœáV{•,E,í™p'UÅ|V}\ÑRn¸­äÌáhÛbï ®~sº[7 á†ÛåL°Ý߈ 9q¸Ê)î ~16gÆ‹Açy‘¹ËãÉÖ††ó,y4ŠÖ.J׋®*:ÚªÕU5›…nÎ(Ïu“ICßF~k”š¡uÖ5Þ¶b¬Áê=K†NA²á\Å»·¥n™Ay³çã»ož;ѹ¯~—Ï&tû.øþ·\qÇ{-ô4ž}©a£ dÛ÷Ð~ü}“„‡Y†–ç ‚•-pß5ʧƒ(”x^j•áæ E'¶gBXf8£y1JÖÚX!¶ç|Æ7b"º·àŠ9jâ#†E‰¢ 9ž8$4¤Fä-S²äŠDiY$h1ú£j:ÕXmK®0 ˜Þ‡ÖxZJÖ"R&I%”³±É”çù%e…JÚµ'qZùçœ÷e™ß •½Y% èÙfå–…\¥h;8I$¤'˜5Ž¡fÞ9¨ŒeÕ7è¤óm”Š'ŠÙædÊ ‡j‚àà*i¯'ŽD-ô¨a­ÜåXªe<Èe…=Ùêä=þ  ÌɈ³4Öä¢.X‰À{BÊ÷ÞhIò¨Â¶ôiªV¹-Ù™‚nA&¤‘vBZ™ÝGÜ©ùXˆ8%Çϵ,è;`¤[.¶ »°*g¡= WUq»ˆš-zIÞ1 ”¥€ŒÃ.8*í‘#òi¥²Ï4Lð]Ç °ré¢Á.h笪ݗ²Ê•žÉ(§æHË.Ëùj¯›Žjq`ô܃º"­·º¼¬R¹FcÃÅ5K E0U[„u­õ \cü5ag=vez6Ù–˜½ö m«ý¶EG=7ØußÍvÃ@¡w µ2ÃßIè@ø:L@‚݄Ǡ¸ D.ùäÈð@;tkabber-plugins/poker/pixmaps/doods/133.gif000064400000000000000000000016651500237002100204270ustar00nobodynobodyGIF89aG`ãìüœ~4ìfDĦ\ôÊ\ü’”üþ„üþÜüêìüîìüöôüþüÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS5dižhª®,Z…@+Ït Lq­ïü-òÀ ë–IÀl ÐaÑÙŒZ]ÓçR{í*OÌ®8Y4…Ç×o錶ª·ít¾Ùuä›?îûP€~sƒ…†„k\x‰4JN ‘Ž69T“) š žŸ ¡Ÿš B—$ ¬š œ¢²œ­­¬œ@_©)žŸ¾³¢¾ÀÂ;jT* ¾ÇÏàÍÏ ÑžÉsU™ÏÞϰà á¾çà Ú(|' éßêÓðòßë:o% ÝöâÂf™û‡._%­œÙ#ÐjZ >B´Â˜¼€žHÅõ™>Šþ*8u’G.c­W¸6‘üĮƂ†×Šiìõ‹f'˜ÏDfû¨#ãKoønqRÍ—´7ÒÚyÐe(|ÔÒI- OTKô<Å»—õꌬ À(Ë«Œ¬6œf¶EV‹ßÈÎjËâ­ÊoTÙòtJ§ÌMôèVµ‰lRuB3%8$-W·äV åÊ,M±Ò4&yV1›L'î¨ X¢1H“8c‹°èîå¥,•kc^[ÅeÍ]ð6 ØöÆN.Ÿïiå1ìì)ù·ˆÇMÀµfµD¨Ž¡[ƒd6o¨wŸ•ŒnÝï/À' /•ý^͇ƒÂBQà÷OÄäÈ“•¥‰¨þ'Ý'ýù—ÙWz•pÀ‚ ¾3Œ~ ÖÀõ5p@P€€ ŠÆ×\ÖÇ`Táƒï!ˆ¢†Nh≠xV‡€€-î·¢‡šuX"%¸£v=IX†/Â#*XÝ‘:ù]Š3Æ·kIÆÂ€RBAø{ˆ‚O©éÄš ®Už/³IDØ+e‡ævcÒtÑ[vÆ%g iªà\4kÍò§QóQÙq÷0Ç oêxÉh³|ð·0,ìì !PàÁÅgÜA;tkabber-plugins/poker/pixmaps/doods/134.gif000064400000000000000000000014431500237002100204220ustar00nobodynobodyGIF89aG`ãìüœ~4ìfDôntĦ\ôÊ\ü’”üž¤ôâ„üþÜüöôüþüÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS5dižhª®,Z…@+Ït Lq­ïü-–‚`G,’n¹†pilêF¤aTà¬Ê JêÔÊUa¥Ù®Ø„Í ÇèÆw N[×@­û·çMø_]³ù}Ifw€De…b‡ˆ\za‹†9LL;Pl“”6‘—„™,~˜ž3e¢š'g*%«D®$°•‚Q+«¬¸;·®º=´% (¸Ÿ5È«ÌÇ³ËÆÒÊ4ÎÓÐÕÒÆÔ3ÖÛØ4½Ò»:âÆäOÁ-Ú¬<ìîÆ)²²&ÒEŠ3¸)â ¿(ûð©“QŒ[ g‰=XÄàAvÍR8gÅ[24ùth  sþÿ<&ب ‚=ÆÒV"e‰ÀŒ @Ð1€Ê•I$°™`¦“Œ5°y"§ÎЩ2À€RO4}Z’©'*HÚè§XU(hšh`+ÐŽñ:¯?·$¤kÏm½S5úý+A—ï ½«Ðáí¶í›‰¾}I 4<˜ Ä…%¶0ö!D˜ŸÌ*¼sºrì“ JµÈÀ1u¼31ùDëº÷R«–gbÀ‚j¸]ú­ÑÏñàê^põÄUÜEïß•5ñÞ ‡ Y6s z×^@,æ½jÿù]fuŒå‹ü^›>¸ò®ígÇF?ætÑŒâ7àÎÂbDö IÒôL˜ÑÀ– ÍQ— cx…~­¼Ø}m ·\ óÕa…ïáj;€x¡ öá×B‰Öµàßyý H‘Š.fã Ôp eÍ0ã‚­ ‡úMh" B² !Úeá ü½µ¡¡ÜhÊ GJ) 'RXé –Zh™‰$©xù¥`ˆ9å fž‰¤š-”r„cº™æ"vÈ1'"u®É¦ y¾¹'”rÂgwÒ§‚>rh¡€,š(—ØøÃŸ)ÈI¥6à€é0<úÈ !PàÁ¨¤–ÚA;tkabber-plugins/poker/pixmaps/doods/135.gif000064400000000000000000000014601500237002100204220ustar00nobodynobodyGIF89aG`ã Tjlìüœ~4ìfDĦ\ôÊ\ü’”üþÜüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS)dižhª®,Z…@+Ït Lq­ïü-–ƒ`G,’n9…pilêF¤atà¬Ê JêÔÊUa¥Ù®ØôÕ†ÇãòÒŒæb³Ìv÷mË«ô)ûÞ|¯ùnIp{€Fy…s‚ˆbe@„‹69Lq;Pk”•‘z˜š–I˜$%¤;§£¥=‚*¤¥±5°§³¬'B+±½±3À¤Ä¿Ÿ(¢$ƾÇ'(̾ÂOŠ2ÒÁ(ÑÍÓÈ;¶Í´ÏÐ'á¾ãÕDÝ«&ðð(íD‡3Í&Û  ÔæTÅ*bï^*¶ÅSpÞÁ\EzQ;°„¾ YÓ1þ ŒÖg£•„¶)Xྕ&¹¼„ÉÎÝC„*Þ¤ÁòÕ@\S„StÇiÞ®!Íf´¶bÃÚAmJ㩳…Ëäñ“êl¸vã& K]Q¯¨º-;Ñ‘Ÿ@_õb¶ÀçV•ÛƒÔèB¬éŽÚP ”Û"ãZcˆënmK•GDZ\Ǿ+Ù²TÉ*—»6³‘¶yÕ*î<øs×ÎtAŸþÆ—­)¼'Ç-¢·³á¶µÓ 7¹.nѬkqî=ZYRêÐVìZõåàQŸ»fË\wá¥S¯KªœÆ_äÂo‡¾Û¦»g9ÍϾ3MO'íÓnâòÎû"(UºŸÏ‚±E"ñßBYD«‘P qãOü¥wž É£ßkZgl $ØÏ?#åÖ]yÆ£• ¼‘'Ãq$‡`9( ¨â ÷½SNÔI§!1–`c#-3c2v(£Û1¥]1Üé’É›‰—bx²Œ¤+B6›z:èT!'®0©I(RxYÉ$»TéÉ`€!æ™)¬Éæ nŽYæV¾I¥™oÎ0'užd q"Ò  }z ¡yêi†š…~¹¨’&¤Ê颉¶pè?dÊ•>Tš¨zÊ ¢VòBxàê«°vB;tkabber-plugins/poker/pixmaps/doods/136.gif000064400000000000000000000015551500237002100204300ustar00nobodynobodyGIF89aG`ã ìüœ~4ìfDĦ\ôÊ\ü’”üº¼ôâ„üþÜüþüÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS-dižhª®,Z…@+Ït Lq­ïü-òÀ ë–HF£p©-”É$sÚrBO,u{²•Y®¸ä ›ÇÜ2ŒÞª±ìöôÔÊ™ôó}™ïƒoQxEpRƒ|9rŒrNmml~<‘ ”–…W™;£ŽŸQ¡¤$©*+««4^§™£ ¶+­)µ¤¹Mгv$¶ƶ¬)É£ÎÈ6ŠY‡'ÐÇÑ5×Ç˱ÓÔ*ÛÊ:âÏÒ(Ä'¾Øº;ëÇíÞ<ذ%¯·'ôøçóǽ¶¸FųçoÇ#QõŠqã†`oÚ²YÓgnb7ƒµ…£(ÑÄEŒþmÞsPŒ>4%M“RÆ=W Uí‹9$#‹u ôرΑò"*cجÙÂqAi”ëÙbéÇ*67R|Ú”#Õ-oêÛ9C¤À`ý°(@¶€Êò’)lØ„f(P°`.ÚµliÖ âpl¹tí&ÀËHVÆ®ø;·®‚¿„$6ÕÄ€JÖXml7mÑ—e.1ÉXÅrëB¦LTŒ(;cqàÁ2ÊPÐho‹Òûj3^Íú€kß-Bï°[‡rä<®úœ™rÉ,S/$¾¬š«Ï!yÌ··u«ã$ ³g xÎGÏ{ ¯:ǪUk?WèˆYþEŽ€IÍàÔ€S•gàQ¡p4*Ø@@YôÏ/_I8ÃKãÑÄ¡†\¬GReK¸7bH[±D" Òè +nô WUC•µ”€¼à„Ìm&qêÔyð%³h.…°ë÷ŽΛ—N8¸RÔ¨\Ëö/éÅ¥%|Xf¨)±í ]­XaÂZ„iR½ôW@çrÅ›×-ßQ5¬x‘«<{s^ìFâ¤w•<1²É~qº*kƒµ=+48m²»ª¹ÂŽV ˜ÁIÀèV‚ƒÖ’aÇæ!G@ÅçÖÍ\7ßÀõ–îxå k7 AB‰æÌK\¬€éD¡ž‹×È#ƒ÷î𻫌)BÐäÓÃÅæMOûñ {&è¤@Oyþ–ŸT¼0@{ìñ€Ò'Á”` Oo€e]ÍÐ !+LèÀ‰oHØp;¥JˆúçÞŒíÕˆá‰8¦à¡Ý ð¢'ò¡ÂyäˆÂŽI$}4Ô¤ÍäŽp¢õšƒöèÉ Í´¥'Ržh¥‘¡¦‚üIe‚’_æbPPêc‘†÷™‚[’gxAÀ)æT^¹œs@Àß~S¤§¨tà¥Ùäƒ1ž‰ç¡z’Ǩž%¡èwiªÐ‘˜…® é§k]Ó¨›Ÿ9w¢\9© TN鬱ÊùÙ¦éWÅrSža0ä:l y*¯œ1À䥙¡m´þ–` ×ÛÁJª©ªœ:«,6i^K­¡ØÔ²æ•Ô^{ê¢àöêl«˜Ëí­3pé#¹¶«+ ¤Z]‹¼%Jn½ÏÝ;lº_òÇ.·îŽ[³>øJï´Ü"k-¶oÛmS|h¢I,­°ÈfHž^Çvë-6"ï9o´Sâze­%x’Ê«±æù26ñ6+›É+€{:›ªÁØ ¬ƒz©Dj+žz  ¦Î•AЋk0¦)SɇÕÚp*NË­«UžÙvT £œúzW×#³™ïÁ¶šyeµT gÒu{Ù)›ü­9u­€^µÕW‡»$¬™gðF cC.]—þ•„B¡*P#4þёΉ€·Ì¤€NšIâ|î©>wÌ ~tà³Û¬éV(‡ª+iïzáSÀÓ { 8òzt1Õª¢pízч‚ñ5æ±ëë½4L]vÕP¨àQ¸`?ÁŒ~óF ó˜p©sµ© hãæµ)á_ÆÖžÚ¦6ã9_ÚÔðš`5áÉKƒ“âddÄ^ô§Í Ä,üÖ§ ¥´¤ƒ'` UØÂ¼`Ä7IŽvò„í…«0,Oƒ §*>TÛ€‘ ò膷Á‡;’D¡á+>àŠVs“#"1„ˆÃþÀSJh-ê0Š#™¢þî¶BÅ Ð[SæÒÅ~dc"¸ß‡ÐȨDâmÐX†ˆ„¦7¨G(²øƒ@q G4ÇHYC!,d Ù`’")¾ãz =ÆÅÖÁAUw¤L(=3Êf”²ßèv‘Æ/Æë  +]éÊ‘¹Æ8 #™ŠM øëÁ%W—ÉTÀâ°pÅ0¥³pQ£"d]G|i LxÓ´ìÁ"€Í0ª!ŠxE0€pî`"äA,çÙwæžæ¬XaŠ D™=‹Mrîìù“©¡‹.acD©¶_´YhjT9—T!õÔ¥? [»zM§ç&ޱthà³Z®×žÆ”)‡ê.“xÔ–Þ¼O) Ê6Œ_Œü4löðdµ^ù:v{#H’É’Ø…¡_±<¾ÆäÉ6@‡vùÂ^ÈÒ¦€ éd ¯‘ÁÄS¸Ÿppjç,¨“¸~ ›ÆôÀºO$ç—»”s#"„ÿ­¡Êtëå³€>Duy\¡¿÷€ôµÈ-æÙ–À†YA$  ZÕäÈdþ ^‚¿™`ƒ ðÈ€p™&€¨‰}C• (D€À‰RX€…ºaÈ¡$àbÎÀ“á?#’x_@F8Ù!,¦@CŒÒxÏ’xÓ• þdŠ€¶$ŠÆ¡’K:È„`é”Qä^¦ÁŠ`陫Íá–1’ˆI¢\?ò÷_‘k²‰%‰ß0ÐX—šTðß1ôDY?ö—¦n}¶ùäN X0¨#s6 ɘd0ŠÝ£A°Ù¦œZjiorh œ^cÝ Žò)êŸ$ò4“|Ž4i§g‹Šh jΪ(O@Šk¡…8©¨Åh —¯€êFÁŠ&þZ+°ÙÕ¨!ÑD³reá+ eY‹mnÆbºŠ¡”\fnXá>ø'f×(º#)Ù:‡7V¾+Ýg¤£V ÞÞ«$ÚúàÍ-ÞÚ€ ;Ɨ׃æF|ðœ™b—[ÃÖÅ+[×ÕË)ºÆ` ͽ¿{ܼ•°VÁº±kòggnY'Œè C´=P¯Î23¦ïäm +^c³ÎÆ]ãó®ñ”°>ë­¨Jg7nW/›«ëÔú0Pœæb]ž²˜ °+µ¾ê˜Ê6¢z4ÚUêöÛSâê¬éÐBTZ)Ëlf6ÚáÕ7°·ˆÊ ö[ƒÏköÝ€ ˆ€â]íú÷ã]/ÝþIŸ]âáEðƒ"rª* o«+„€ 8è& vSž·‰@ž~Ó›Ãì .¬¬8úíæ¾»Îäè<à:Ș¡ðÒÇ~7Þ•‡wb„(0 â}œ_#ãeÕ‹né&î<|} 6/ô;LV–€4–p<Þ²QzÐJø{J\$æCX‰æqXz2Ó¡JÝÙ säe59«»à5¢óÀe9$ØÊ.áf ²Ivï@,¶YÙ3øÂÙp!NšxŽJdsžP;?t• ÃÀáô°,Õ™KK(›Ý±ƒX("hŽø0%vDðÈnJ¡CqÉAŠ0,þË5À»p¥+§¸”ï¢8Ųñ,X`)Ôèº"E`ìá\zÒ‘Äñ]ô¢™á‹É±)>A œ˜ÃÅ&t±&=h#"›‚ÆFNE‡ãp„õø–’Žuô =æ)šXAe iÚÀô0HgXWÄl¤.¿à"(C©qÐãŽcÝ àèK:²(!0³À:H<àþ€Å5v™‘L’¾Ì¦>(á n´cÍrË9ÐWÖ–¸ …,do<“ÆFz /ì9Í1 )¹Io>S`BÀÄ=Áòv:©h@ýàsN%ºJÂʈêá‡ÐÔLDx ÐkŠyBGÖ’öB5©FêP•*¥t)ê)…j\ã 2UÃ8õC‚œÊÔ 8õ)AS¡êà *H—ÊÔ¦U!;tkabber-plugins/poker/pixmaps/doods/139.gif000064400000000000000000000033571500237002100204350ustar00nobodynobodyGIF89aG`„747×47ð47ú47ÿ47ÿlj¢ˆYúœzʳjð:‹z€‹™˜™¸¶¸á¶¸ÿ½¿æÓ“ëâ™üö¸ÿÿ¸ÿÄÅæåæÿàáÿîáëôöÿöðöúüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þà'Š@ižhª®l›ŽðWjtmßx®ï<^Æ€žpH,FÁ¢rÉ<Ê4‰h*eZ¯Ç$%JÑlÝ«X9£EÍÓ±šX¦ºÇÉ8M®IbíÒ4\S@ú~}4pxgj‹Œ…w5y‰‹œ ž—VmgˆW ž ­¥®¡±¦M‡hb½¿¾À½·K¨zª65Ë8ŠÑÓ¤¤½¬svlZ\^Þ6ËÌãϬèéì•sÛBešš5ãøã7-êqà™àVd_>~)0(\¨°Eý5ð…ä]yÛýTÐþ7äW@~A(ן|D  Þñ¦róAa‚ .À˜9ø`r(ApD xjÈ]‡uP!:W€jÀé·Ÿ„ð"†ß ¸¡⨠}ó¤Vx >¸HŠ?é'‘1–‡¤‡0P…9îÙ“ :¸_Š=–aFnxå‹Hðe}bòU—d‚磖 JWd›–Až©áÉäb;:Ifƒ&W‚ŸYiœ¬öå¡Îšoeî)aŒ2NZcœ©€Ù¥u6ùÇ—( œ )h3¨n„©CfµB9æ ]1Õ€}¯Z©#š*¢¹®æa¯œÁj©–ÖjkÅþιܲ½öj#xùÌ:ì©ÒNëêò)[G¶L™@·ÛÍjj¡áŠû¹­²Æ‚®Ož¤²ä–@€¼®U‹§ èI'Ï{Ê n¸ü‹©˜ÿŽˆÂªÒ¢7Ã8uH§ÅŸÐ0À5ðñ ×ú“Åuü”±Æ÷kÂÇß:ò%©b„Î%N©ZZ‡&1±JLXr•œä æpKDRbjiˆJ2B‘ƒø‘€®yG ’Ù43Ϭl2€°à 'RQ¦ƒ›uXG;Ô¡ü’Jæ7À0Ï0Б‰¬'8A jƒJÍ`† T¡Š{î@†/|ñÏ! ¢ KÌ+h ^Ä‚¢¶¸r9¶‰N|â%EC‰`sîbŠx„#ÈÓˆGPb å4é.ˆš¢0©AÅ4‡žâô§è ZÆ¢æà¡zØ©Q‰ð….4ÕŒK-c=Ê™…¨ZÕ$¸ªV瀄­ZÕ HªWƒ°Zî¬hM+XE;tkabber-plugins/poker/pixmaps/doods/140.gif000064400000000000000000000021211500237002100204110ustar00nobodynobodyGIF89aG`ã\>TJ$lb4œ~4̦LĪtüÖl„‚„¼²„üêŒôÞ´ÄÂÄüþüÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS5dižhª®,Z…@+Ït Lq­ïü-š9žpXº‚ÈŽŠÏ¦tM6”Ó,+еj¿§§÷º›Ÿó9–Ì”ÕÙQ”4‡7åXRûmgâƒ}Ru3†%‡ˆ$‹ Љ‡NG5‹˜†$ŽŒ›ŸŽ;„4 ¢Œ¨ ž† š±Du–,§©‘¨ š °šŽ´µGI—’‘ŠËŸ”~A"|3 ¨ ÕÕ°Ø­ÕZbÓ*™†æè犙w1  2äËõöîHá‚=lûýòéƒߎ‚æ$1¸ƒyv¢À«‘ ‚ §”’âPÀÈþ·¦ ð( £@0$=‚432¥Ib`: @²â—D.z,ࣜBZz<àr¡‘–T‡Ì¡¤ `sPÈ ) ØÊ“äKMi =°µ,Q¯Þ®ê@ªukƒ²]“ÆQ+6%ƒ²î–•ŠÖªEšàmõ¶ìÓ¯-®@ª×­£vxãú|6i‚ÁÂ<áMP&§˶j×É@cÐUÁÒUÁðNÑ«\Vx@\©i(6Z°Û­ÖdÃú½õlÍJNS ëxðÇΆ«?oóïm:R†ƒoP†‹F‚eI‹‘@Œa‘‡9—•Š’™—ŽXc 8Ÿ”^V¦4¥˜§T«£b~A‡‚¬­Y©¡²¶ºˆf»¿BÁÂ,{ÅÆÄÈHÊË#ÇÎ;ÍÑOXÙ]Ð3×áâ×¾Mãéá·FêêܱMïã‹éóÀGöâ—ùôŒ ó÷i»}  IÜA5ÓJ ,°(€E|ë™ʉ!ÆõD$Ñb¼&ÇéY/†5)YÀ"J•S¼µ˜¨.cΑ*ÀÉ[‰p 6må²è¤öa)S2O]eê4jÕ§W©N¥–•E®v®zmBˀآdW)ÝJâÕ¬^]ÛªU-¬¦IÐ`¹«£Ô½ggøÕ‹+mª¸r!N\7êŠÅÈ “ì&aÇJ,S~Ôƒ æ¿MÙæÁ³ySИ-_ùìAJiÎ?ñ̺ÈjÙ`ˆÜ`-†èÉ0x›@ñ{´ ,(_μB†;tkabber-plugins/poker/pixmaps/doods/143.gif000064400000000000000000000016741500237002100204300ustar00nobodynobodyGIF89aG`ãTJ$„^$œ~4ĪtôÞ´üöôüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þI ª½8ëÍ{ž Rdižhª®,Z…@+Ït Lñ9Ö|ÏÞ"ÝÎG$n¹Ò¥È$˜¦Ô–´@“Ó¬jg½j¿)îLö^5$C9ûTb×ì7© —Ò—õ¸«›·Ëû`t€_mƒZOЇSCŠY};•S“9•(žŸ ž&˜%¡¨¦<Ž–'¢,¯¤¥$¯+¶3…ª-¢¤´¸°¼?Xœµ¤Ä·˜À·¥Êa§²Ó*¶ÐÑÒ2‚§À´5¾ØÙ³ånËáÄîî»ÏÊïð£çÛ&ßÏì&ôþ®Âüѳ×,™×úÑ ðoÔ  žšeP_2…ï5¬…ÑF‰þµÄ­°Ø.c%Ï:nB)¯…Ň&W¾;Ubᦈõh[! ãÍtˆys¦‰ž#« …Yà§"£)I•´ŸK¥Ukzt UÕÔ“9¥^]‘UªÉ†žvÕº-Zœe—îT”íV¸eyAT µD]j·PìÅëÐnS¾a9ÎE8O Ë’Ž·\Ü©[ÇB ?¾HÙÕ,‘†Fe*YhÀÜN÷JiÐ3EoJ÷}n­ØígŸÑÁîõN5À¶ ÊrG[ŸµPŒ'¾FÆy®ØÙRyF,Õí=d<Í:@ñú*è=†×\|xYÜ-“1ÞÕôÓÖ?õ`?ªœ¶ÙÖ†}Ÿï7îà4ôþ'„ ÚÝf›bü©×Ù.äÈ×´ÆÞüŒ3Z€÷ì¶Nƒ˜&Øc÷T…äE×…f9Fn 䕉qA™‹cEóbL˜éea‰¨Ÿa@…¥#Ž›Õ˜Ji½Ò‡¹…˜+F¦P×W@ E%_'ü…Y>q•ÓNáôP”‚uùÓZ)†Ù—\I±PÖŽ`}i×™kž8 O¤Q•’A¢ åG^äž@"v¢ËÖTޏ@ÔádmÚ8¤@õA:ÔŒõù–ψø]4š†hjª" k§sP6áhZi3Xš‹&²)î4ø)¬˜œšq'l¢ÎŃÛrKÂOsl˜uöðŸ|*0»jv_Û,#R¨J·-Ø:,¸ˆ8Kîsç~w‡¹éâqkºT /º[Î[ ×Ú»¾ßÚ+FýÎ;ßú&Õ ß« GšÓì|1 tìñÇ„;tkabber-plugins/poker/pixmaps/doods/144.gif000064400000000000000000000010461500237002100204220ustar00nobodynobodyGIF89aG`ÂTJ$TjlĪtôÞ´ôîÔüþüÿÿÿ!ù,G`þxªÐþ0ÊIk\ø4ûÿ`(Ž$Ød@©®l ,i+Ïô«ÑxN¾±!é@Ù†ó KC_ïÈÜõ’Í¨é ‘Z•â• õt·À/q S³är.ÉN«kÔêÛì}̃â»1¯§}~„kK„‰†pƒ‰Š‹.=Ž+P“#€•X$”-šœ‚›…!¡˜¥¢¤8| ­“«*¶Ž© ®·¸™¾À:´ºÄ½¿ÉŒ+È·%ϯÍΧ€Á"Ò»³nʲ½×Ù×Åà™£Û¹Ãì3ÆRê먇xè÷–ùúHüý#â !pà‡‚ÑX1Uï B¡è•yØnÙ;.ÿ`Y‡ì‘I7Ž{2VÛèM Ea$AâkŠœ¶†MNFs3ŠLPêT¹Ù§>Ÿ÷€vZ‰($£‹Rˆi™‰æÑˆªÎÞTB¾LÉH”Õj‹BØ ‰b6 ±ðDªÖµ0¬h#m}Û–ÄÛuY<¼›W߸zÕ®uÔw[À¯rEì–0ã?Û Ѝ˜² ˜79i¡ùrIO =0s*e´`HÓ@‡ùt%Ì®’¾3Û¦…«ÑÈQ½º îÜ }çý;wžÚw#Oî øð1Ο ®eyHå7žd };÷îYPÄ^j#ƒ èÓ«¯!;tkabber-plugins/poker/pixmaps/doods/145.gif000064400000000000000000000012271500237002100204240ustar00nobodynobodyGIF89aG`ÂTJ$œ~4ĪtôÞ´üþüÿÿÿÿÿÿ!ù,G`þxªÐþ0ÊIk\ø´Â»ÿ`(Ž$Ød@©®l ,i+Ïô«ÑxN¾q÷èÀÙÆ÷ UÂãÈDö’Í¨é ‘Z•Ôêµ™ìö¶F/Ìs d›g‹mõW—ׯèû1h Èh‚L`P‚ˆF…x=ˆ@‹Œ[I‰4“•›R‡‘9Ÿ”Ÿ _}A¨§Qƒ,¬ Ÿ®µ9y2™·°¾8¼´¢¿¸ÂÇ5ª-˜³¿!Ϻ2Å%ÓÐÁØÔ,Ö$ݶ âÌ8åÛèÕÍÆÜÜÞ§Ò}ôñ+à*ÃÑ"úBíÎÙöͳ÷í!@l‹•P“@ íøqÕhSÄ] g0þ Gމe”±±#Dˆ FY”å€J\F’$`%̘A¼m¬XÓÁ‚@úQTПLãNæZfôÜ3Á¦at*U'Xë\È\ZU›<ŸØDR}jõØ®ìr ªu黢@­8¾kE‡’ƒ«ÕÊNm=q®¤Éóf™­+Xö,iØÍÊ–€;öÓò£ä wIR´ÒœŸ‡_“錱CC¦¹Ž¸Ø/­\‚¬ùÆ¥±^ˆ…µe—ȼ­Ò³d›ÎÈZ™ïٽ‚†wü^êUÁÓ dÚW-õß\uÿÀ›_‹Þæš’S0~Ɔu×x5hðõ-ôZGzæy R”ÌÎÏ_Å^­RíÍÇ}þx„7ýÅטJ`f‰íz0CG‚z¬áBG‡zFáˆ!t¡‡žX¢D$®¨.¾1:7#5îCŽB €bŠÀ`ÁDYA ;tkabber-plugins/poker/pixmaps/doods/146.gif000064400000000000000000000021211500237002100204170ustar00nobodynobodyGIF89aG`ã tBTJ$Tjl¼¦lĪtìÖ¤ôÞ´üòäüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS%dižhª®,Z…@+Ït Lq­ïü-’žp˜¸åŠ¢R7›Ë( j¢J¯'«ËÍKÚîUGÉ_ó8]V+­m÷ž–/évl|i°ï‰y€,guC‹+†‡'”5‹Ž™%žœ‘o_”¥+—˜š()™£%¥³›$‹%2}(®¯žBP³¦›}¹5¬'½™¾¢¶-TÂ&<»ÉË׿ È+Z‰'™Ü ß§â ÊØ×æ)VÃ$법'¨¬è”ê™ÕSu(®áG«^<,¦ŽÓŒ=ü„íã‡@\B‰é–‚õ .uþ'ªóG"dÆj»y„2$Es³Ìª˜¬#¤ˆ¥d–z‰"æ,s)ÛyTÖ²Až)*Å Äî\3/*ˆÜIqšŠRBR©¢*+ªÉ%×Ô©Š0®Xj<¡0ì¼U· Ma,6‹ ã¦uÉOÁÔyºv•Æ>µ–uÆ+0’€­šhû5'­Å%þž›+­îäròX†9æ [¤©(Ëͧ©{¥O?µâ¹Ö꞉–&jK³Åém‚k¢Ð, )Rx‡ÇâïnPf÷îókœbéISðsdÄi}6|-šŠj»“ÈÀóIKX]>~æ„ µý%-B÷¬ÜþãZ%‹µ5`q}Ù¢&ø§ >R2Z%4w‘„T—6 VÛ6õIøS%Y¦¡iêt¸Þ‡Ê! A¶¥€Ì‹o™Ê2*žÃ"v“55|ÙÙ˜¢z:’‡Í;¬ü(£ 'nÈ!‘N†_lÙ† j¶ YE¢ÈOr(@YUÉ6NâèBŽÝx×)·5–¦šDn6Ü—`.i;¿¸™ÍšÖȸ•«Y–ŸÖ‰%ˆ±c^…¥à§cZL! â ×bow^ãØcà4ãHiÛ€‡ŸWzz@ÍPFƒVˆ¾IÏ“«¶²ÉA¹É¦!r3)WEÒbeºÞZÕk»¸¹hj¼þ0zdn0 Š“Q”<‡­µÚêçF>+"’8~Êl· ™X#Bn}[#À’[.Fîfb’”Ë'©S-™'å ·Àª a\)•‹3å F0‰§À‰Ó‰· Á– nºrú !%CÅŒ•˜Ý +Vu؉Ú)  5 ÜÉ+è ªžhœrÉ@* r+¿Bê'õzlóJ3碙wⶬðËJð¬4šBhx³ ¤äÓ¾åQ§Që´Õ6°±5×y öbMfSÕiëvÛa£ 7 a°vÝ_ÏÍ,v?èÝ€.x8¾ƒ8ä}ø !PàÁä”WÞA;tkabber-plugins/poker/pixmaps/doods/147.gif000064400000000000000000000016111500237002100204230ustar00nobodynobodyGIF89aG`ã  $TJ$Tjlœ~4¼š\ĪtìÖœôÞ´üòÌüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS)dižhª®,Z…@+Ït Lq­ïü-òÀ ë–#a„ÈÝȘI:eKE4ú¬ž¦Eªu‹-i·UêLÆŽÉÖ.ÍͺÙé÷þ4_èõ¢ôŽw~ûq€l_‚~z ІHTŠŒAQ”H}“”‹A—tŽ•œ¤Ÿƒˆ‰–¤«¦eˆ-…(«¬)²¨3°%´ «¿ž'¼’º±¢ ´µË¦š¹;š‹ÊË̉ÑB+””ÔÞ¤ÛÈJÆ*çßÞæè›=ä·æÝêËáÄ:ÙÚ…ÖôëûÖ°Á›• A:êl…o   *¢'€¢¢ˆ iä;1bÄþßR+@Ç¡8LvÒ#Èzój‘l¹pœŒŽ4 ¾MfNŒ [àü™à¥½‰fEiÞÐ¥ Ùq›¨t)ÓYZÕyT@Õ¥)UdÕ öÀEü™}š3¬Ø•lO0K÷ݵ`mÎø*ã]³vÿâìëòÝ^JÎýËX°DÂEëeQÀ€e’šk¾«)òå ”-‹Ž&`³fÒ¢?k„W±å®¦ï"èzYµJ©_+:7µbìº»Û È-ù¶Š­GË ¼ðÝ”rXÝ"¹niKÿæ ðbêéÔ«‹&i­ïâíkqsY<¼øÄQ:ç®ýnG…ݾ¥×ïüÙܘþåœ'Véç\Övýµd  c5xR]}•VI˜ßlÁõ–ÔV@§‚†ñÝA¶åÞˆÖB)¿¤(WS7µÓ*šŒDÔƒ"HÓ."¥#M<öÈŸGpãM0! L]Ú ƒ)‰PHëÕdX  ÕÏ•8.H@1:tµä?'º3Ù.Š„T÷ÐXƒ™`vEf™×L£Î%¤ ă3$èIM3âl šÉì9 ¢,Ü3V9)* ¸ÐPéVèYd£â<ºƒ2›êèhtª¨ÈxÊ霣j$‹^ú*¬&\J*­yàš«®«Y`$¯*1+¬jÜ ìr{ì~˜9‰^¬ìÊ.{`´ØZˬ±Î2Rl·†@kÄÚ¦ ,åÚ€CºPÀ í´>„ ‚ôÖko!D;tkabber-plugins/poker/pixmaps/doods/148.gif000064400000000000000000000011761500237002100204320ustar00nobodynobodyGIF89aG`ãTJ$„j<Œr<œ‚D´–TĪtüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þI ª½8ëÍ{ž Rdižhª®,Z…@+Ït Lq­ïü-òÀ ë–#a„ÈÝȘI:eËC4ú¬ž¦Eªu‹-i·Õ.LÆÉÜ¢ôŒ«Mß¶0n‘»½l{’zÑßýmq€O_ƒNZЇHTŠŒAQ”‘=E”,†Hœsj™-š@£@…2¡<©¦o¥(™‹:°žJo¨³´¢¸¬;¸¹›»—½Á3¾¼Ã†±5‹Ê¿4‚·Ï4®µAÕÌËÇ–„¶Ü’ÞßÂâ{áÅIÓ6æºéÒë+ŠÚÙóí-ÑñöÃüþ¶QÛWÀ@?zÀø hMÖ~ú ¸g"ÀÈ)¦È—Âb¦‰þ;N¤rœ,C’=ö(%BhðV 0@…¼—fÖütí¥¼ƒ+qÂós¡ÐwD/F$P GU#5MÓ3è—A5®xªB§Lš_w‚S…ReGŸe‰yÂ#I­É¢*šª®—ÒŒÌî2… ‡mE‚Fá*p @µ¯2løñÙÅŒ‡ñmëx«ßʑӼ™g籟 g›ü—tߪB°ÕE挵YÑì`–mrà¬Ù«tp-M»1Ý—KÜ>™Û&½Ý”UÇÖú yòÔŽs;o‹Î÷ªé–†¯ ¬vn®¾ƒwœûóÀÑ«èƒG=yöÛÝãñ&þ úƒš´—Ï„ ~@bÄ-Ç_€ÿùA`y–È_ð±àuAÁƒëá@á0 ÈÍ !PàÁ‡ †ØA;tkabber-plugins/poker/pixmaps/doods/149.gif000064400000000000000000000015641500237002100204340ustar00nobodynobodyGIF89aG`ÂTJ$ĪtìÖ¤üòäüþüÿÿÿÿÿÿ!ù,G`þxªÐþ0ÊIk\ø´Â»ÿ`(Ž$Ød@©®l ,i+Ïô«ÑxN¾ñV<º Ì·‰%bJ‰l†˜L§”íŦÎ*õŠEjÜ®ðëÉas­>[Á@œ`Nt£ñ`@]îîÍ}Xbƒ9ƒ‰S3ut”s’^\œ+ƒ¡¢£¢v‡5Wœ­% ¦¥¦¨†k¬­¸"»²¢´§Š®8}¾#»¼À¤£¶Êª,…ÑÐËÁé֫ռ!Ö‡’Í™ÄÐÜ3಴¶·æ3…ž{ó‡ÀÂíôÆi-°¿Á²•Ó…¿öZ tG_Ž„»ŽqbÒˆ¡‰0þBGiA`lçc(pE€"¹#äY, ˜$e-%˜.\ªËöiT¾[ÎŒز3š=} ªMX¨˜" †`† ¡R§Ï!õfÆbV± Ôø4§Ñ“Û8ÌöѲ² Ï"UöïäØš >ÑY7]_¸Mßæ5Ë"¡! ¶Öõséà¸$ÏrüXq嫵Ô\7cf«¥Påô9ÖæŽM©mi¨ê×íô‚)!€SmpU=àÆ-»+ÂÔ¯m~˜|ao—’‹3­-Z9SÓ\‘'½¼YsÌÏG—ë9›åëh>^á{'ÚÓ³û×øáëÒº^_N°ìåûÊ·w—ìþ}ùÍ'ßZ¡4ž †5×A†Ò–[Ô˜_®…ç UÙE´UT*hÇATQ†$Àü×A‚8¥b^w %eâ-Œ¤’Rèa5㋳±`‘káEÀƒ/yš=’õc –P¤`Gj¢ƒ?i5ÞAðtˆ_¹7P.8´×Y„YÕ¸ ~)¨%„`½×|aÑXnÉP&€•©æšUaØ_šßx“#™`Vœ½˜`e7Iù´Ú–$ä–ä•ÀÙµ¨Š¯Ðã’\ÂÜ%äÈSÕ£è áè¡¡Šê'¨r: ªýðA*|—Üñjø9p)«´nD¹Ž9¯½V #°ÁVÄÅ <û+²É»³Í’÷±Ñnvì¥Õ"8-´ÙF·+·ÝrˆÇ áÃ@¹æž‹® (Ìšì 0`Á¼ôÖ[A ;tkabber-plugins/poker/pixmaps/doods/150.gif000064400000000000000000000032311500237002100204150ustar00nobodynobodyGIF89aG`„TJ$lR$DJTœ~4¼‚ÌŽ̦LĦ\ìº\ìÂt„‚„¼‚„ôâ„üþ„ôÞ´üÒ¼´æüÄÂÄüêÌüâÔÌÞäüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þà'Š@ižhª®l›ŽðWZtmßx®ï<^Æ€žpH,FÁ¢rÉ<ʘÐ(¤Øå̶(-²àáÖ6›seZÚçj{³ë5. ¨Ûïø¼]¯Zý7[v††‡„Š„|}l;_j‰˜‹…€V”ƒu–˜˜– ž6MIr¤V–ˆŠ‰†­9ÃZ²Æh·ºVzz³sÃÄFI]&¥d·¹×n%ÐÑÒbUÕ×åëë“î]]ßàá=rSå¦%íðï€óÅ)±µÌŠ> ­ôõ[ï@p‰Ì ‚Ž ;vþ ø÷0ZD‰£¶­ƒ£„'þOrìKˆ=I"G’,9i€Æ¿Y€åñ£˜s¥öéa¾”(sêè9ÍH¶‚ùJ `³ªÍP4æ ĪÃV¨ê.*´ªqÖ¦ qÄnãI­>0äk Ð@bQ2<‰ó­º[‹0\Fh[›oqÞløIÌL LY#  j«Ê ÿ ó2ƒ”KÝmceÓõVã ø’s˜]À@mZ4v ¡„lÙ¢G N[8$o=…¹•AHþ È ëÕM=ø[yˆÒ™L‚Ð-ü–L¼ýðãàÁhPsç$ˆžp–Á÷]x 4›u9þ§‰~ÃD§ždš ƒ^„v—œ|Â8ß} 2¨ Ò™Muè•8HƒÞa¨á|ôù´C Hx݃Àða‰†Ür<Η›1Þæ’‚22¨žtâ)0@…L8¡€ À” ÛC™Ÿ,Œ6`Z&bA|Ê…'¥L0A-ÖÓá çir@ ] ¤˜|’é'™P†ä UÆÙ\–t–xÀ(PÛ”_Šæ˜c‡\ L©›]2WßNú•¨£]0è—”¦ f T&0eb)ŒŠ2ê¨P©™n:ÁhwÊÚC„Œ@©„*€t0[G³ÍÚ±&• þØV¥§D>°h££µ©©²î¹WÛ<àæ¯U+g–Å’j-¡â'o £YP/iÔ¾Š@(+,0º‹k±TŠge°SÂ@Ç@zk*¿Äø¯$Æ" g¾âÙ;^môZ2¾ÔÚ¶o¿è]Ü•­¸–ë&¸á†+e玖·S»l3Îäk2¿ ”ØÒ¡.0Z®šêêœ L鿣—hñº. ñ ®*‹‚ªªF=åh'­I:û õ¹½–_xªJê§ØT/juuGKr_rœbx’ö)xÔd—€óÙ$æÝÕÞ¸Ip —Ê蟔P² ~¢âö‰á°Ïþ¹ým#“N°@µø…HëæœG’õçàÒÇ£|:¢ã ë]7áÕH»´b¡G{í:6xdˆ›£µï,yx¥W(!t" "­)/ï{Šà< —ß~iË)ûÛñŽ;®mÄáþ úq(Eð^'AuÜM„ÿŒÓý÷ô§z»PxbVã8h?DùßÓš³‚™`8BÚCHIÁ ­pKi6/¦‚$:p"·Àe#°¹ˆB™™¡&dÑ NÄRÈ Æ…J8‹FÈÕœ„†7hÅfpXª!­8ajرš, ð ‹H?İ bÑH!Å.…<©þ¢)S  #,~xâ-’áEy<$II‰:@#”1qüs ̤$íàÂ%C=’!Ž( ‹™ÆQàñi†´ÂUú‘Åk$q"SVG|0J¢ã €Pã#sNfêcÚøE¦b!î"Î1Ê%¸jÜhdÙX>€éà/@ÃC#»ÀKANâg°:ñ‹^ "ã€bùBša™¨H6¡ TD³˜È´&… U¬"›— ćœÈ•- qœ<(g3IÏgBS í <Ì~ÞA{øC5rɂޅ3™ ((ÊÐ8 ’¡™´&DÍ@Ž@Ή¯†DrêMkV Û¨Ÿ´< 9’Fªô(æÄé¡™ª0Ûm«IC`€Ð$LÀ Ó©C ¥ö£éU{:›òäVhÃF=p`B´8'ñ*çë›.[ÊÊu€—b^Z^s呹'‰Õ*,-7«Â€½<—ñ{C‡À-TÎfÙ²…KjUi®ñ õcýApu–è¥qÛFÀ ÷»Õ­+Thm‡± (ÁÂm³"DàÍ@L Ÿ0aøk· £ÈUîa„ ,¤w.:Ò È/ÝÃá$è^AlÃx+-p,€z¶þç›ðÍ's3ÜWwÃíñÖT¨œr$8Ý‚ðà ( À%G|ÄÙsd ¡ÈÞ‡Õ1øÀ|ô˜‰ HA \AA‹ŽuNnhž‚96(_”¨,ÁCÉ"‰.7Ç2FP âø^ˆHe•@Æ©À%'p&†PÃdËÀÛšS¾ '–X9Y4v&ùß”¹av™DÀ | ÝÎÁ)§‡"zg?c’©!&4dâ ÎeÊA‰…r ]å$†éh}Z@©t©ÊUZéj4嬄䬠à\ '©˜ _ÎþÉ'€¯hÈ]&XrlÆÅƒÀ²dRs™[ȇiµPÀµüêX–ÀA–äûé¢Ë.kAž—•€¯Î‰èîÀ+/¬šùÊ î6sŒk±³8™ªvŒm5«Ò2ÄûžO¿tÞ¡²½„Œ/®Ÿý®$äÍ8ç¬óôb‰Àªœ½8 p€ŸP@L‹%(= Ó,.m–òqŠšŒ‚·_* Á-†=À×aGMvÕ'…lLVÍuÓRÃýôÔKW]ôÑjOÓª/ciç΀@äß"ôþ¼jË+7n1ayËÜâ«Â t#¿zìà;9€³þ£fœ‹[rïå`A›×nЮ|©¶gÂçy>n8x‹äkÉÃ×Á¬ºµïÂÎÞƒdrY¹…Gþ‹T§Œ—ùëÜ("´‘NÓì¸AŒÞC.%>«0}ìlOÃZ2WûíYÿc'9°`"– ”¿±#P*ÊRs¨ÜɯSöÛÀ.€RðÀÐÀºÊóé•À+J ”|ØDÐiC5’¨2؆ ž›2Q{´«z 7à€ „¢$¼¡ ·$'¥0C,|óŽå%!iTªa çD0–§}2*þ`ü|€$¡h%&jDÇ’ˆC^¥§‰NR!üÖ&¹ûP¨BœÐÕ|ÀÆ%R+=é©`zÚ7G½õ?úáÏk¶ ¢öq`Ôr 3ÐÄ/` ÞÂvºCœõé .J„ä:œÓˆ ]²1@ÜAp¼sƒÀÔ 7&¼Mn,ùY\syàšï´rpñ“hrC ZZ`/¸ÌÎgd"4"$˜º¹ŒN$sµX'•^x&Rf¡rpå.tiJ2u9Æ/)èf±r2¹\—yQ3Áà”¤ EÕ$Ü¢øÆ€¥#àòJ=00 @#ŸH¹?»1„¶h°žü&fàI”€CrEˆÊþ?ÑŒcê„)úTh!—×PZeåèL•d¨DœP‰Ewé’— ôPi2¾‘‚Ì ¤0Ê$[lÚ†NTC5YfÞ±P õÀ¦7½$TqÏhÀtŸjðÇ‹ êX4‚ÏÀÉlà ’o˜B R,éBRšGjH ¬æHlp (¦™kíê':Ñ€^l‚â˜k?ËP!8ô †àk+’Q‘ ieèYüìïîÈ{Cïš{Êòy{ÃÏ Z$”ˆ'ÐGÁr*ìõÂÃì²@%Þ¼z¬þ2ÚØÈŒaÀ—ï¬Hå7•+{­jÙñ£Ç˜39¸h'>Ž:^ (áÁ‰M<J4¥’t㔲{ qÓ—mª3š“§KÙAðêt°5q"¤€€C?Gš€÷h ™ª7ÑÔxØp©ÌOz¡ ðXÁôëê€SË—!H^ìf¨Xd{,°y±O»!J½ K…[<Ë ­c/¤[wœ:^@ˆ½ ât•ÜNp€4i»¹Y“>|8²12±-\ùò L?Á¹ôÞW —R¢8¶" ò 0Ð}ùÄ“/Ï?@ú×Ö) `vE_ þ§`z$PPì·Ÿÿ­w îD P(\‚õÙç~+T €ØeØÇl ‚¨ €Þ5xߌ4Þ×!3b‡ágï±ÒaƒZ7·¹€wBâ€*¦b‚(há Ëä7 W–p¥‰J® = Ò7Ÿu  Hd~ú]I^ \^HÁ›ló˜@¾xHp¦•âõ9Þ‘Õ½–"†oÎVÎA*if•~6 ¨zà bœQZà“J©d8@¤|®¹%Ž " £6†‚‰`¢×)`ª1j‰%›8Š)é’®b÷%+ºH&§œžÉ’R‚x‚S¤ê£‡cžh*‘¼jê´°þV'å˜=КÀ×nìm 8gnµ«Ð %}–±•ì®ß0 / ¢¢’›ÛZ¤¡‹ €ÂeÛš²ß {™Ƨo¦hºhΠ`¶—Á«NkÈ )* /ÀïÃH¢DØÊËÁê ë•Æ¾Ö°°¹ ÷Òiº^Û"Êû`|ðµÃ‘‹+Š!‹ ˆ½âüFÆ&¼^‘%Ê,§ñl/…Fô³€ Ò÷)šYöù¨¹øš˜PV½â&%`ý"£jþ9ªÌxÖ¼ ‚fÿEéPq"iϠʪfŸÿ-92Ñ Ö]iœí]··°n7J¡ÌœÊý!Õƒ†w¡ro­¥Û>ú €þQÛûa‡†¯9Û³Êúß6Ó]9Cqâ:2ßËÌ#cO^øë-€xÚ³oÍ\5Þêz×–]ºï­Š½4Ó)Œ8¢ñÇ“\tr1|’U: ášV@}”ŘHö±;Ï7¨ô'á‘6ƤùF Åó žçÜ~ >ƒ ú‚ìw:œ 7’Mêb®/J\Â\  =îp-¾A Z8³z'‚§¥#…ÖH†ÉÚàiæ…Ü´Á~}ØhTs™Ë4dƒ£Ì½`© ¤Mù‡D Ã@æ_¬`ž ììe$+¬ m°W%Þ&îòØ[ÒU,ä|Uìþá`ÒjQ+ÜúR¨h+Ä#NJÑè—]¬‘I#˜ÒŽÃÀ/S±ãN>Æ6êч|„ÊL” –Ü10†¼F<¼ ®¼å4]ÔÈFð(BN¼Ä.2é+s–pòb‡„‰·X™Ï82]¼‹á!}è!‚2 ¥ÔÇ)÷a„ãºÌÚ’°Cƒ@DÑx†òL³pA Ïô‚“˜@Ø|FFœ9M]P³ƒˆ-`!‹kVAâsPÍ;ˆ"Ÿ…;=A—M¬ˆ àœ%ô O)T‚Þ` èi‚ÚaŠê B‡tsB( eBsˆ& G̨2“0ªQÁ$#Hì(E§€Ë+ˆô¤!JWê„'¬´£-%E_ š ÁH8Í©N_ƒ;tkabber-plugins/poker/pixmaps/doods/153.gif000064400000000000000000000030741500237002100204250ustar00nobodynobodyGIF89aG`„!!qe>_eqË!Ñ!ë!ø!¥]!ë#qÿQO»ŸOø„_äÅz€¥¢¥Ë¢Ø¢¥ÿ«­ÿ³µøÝ”ÿÿ¥ÿ‘ÄÿÖØÿéØÿëÞÿóëÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þà'Š@ižhª®l›ŽðWjtmßx®ï<^Æ€žpH,FÁ¢rÉ<Êp‚(sJÕ“¶¨¶Ê­ ^°mvÓJ»Õż^Œ±éö¬ ¸’µ!¿–ÔÈqstCkU|z}XfŽ„=†wS‰Š{Œ5fqƒEvki™n›œ ž9v¯v5†±°¯D¦7€Y7k°Xd°‡¸z>p4Ž;†ÀÃÒvÏ•–ÆbºÉ«®Îж┤Jy~È\¢ÏÕ”íÏá—:»Mîñ”_íðÉ]ö÷Ä œ†f.Px+hÅŸd˜Hq¢€ 0NPÀ0ˆ+R¼˜1#ÇŽ þ"%KHj<ÙàZFàR¦I”)Uެès#P›Eà´`q¢ Ei2D:âÒ¦O¡jü‰’*Žl@dð4CNY‹:ú5¬‡9À‚­¡”‘#·f4Wî["’(¤w¸eÑIÁe“¯ 0¤…>¢˜âŠ‹Š} Ù°F¬Œ7ºtå‰?ˆ‹Äá|Uç À‡!î­ˆ‰Óý ma_€Ýê Áe F(àt°÷Š{þGÎÎàá7žæ• ±4_жnHÖmvEãMs^ê{m¤€–¡ p_QV8ŠrKŒmô¢kQ|vRj¤óÐÛŒ”ðÙL—aÀ”K%ñý§cŠƒÉÆÚH-A`¾÷%ƒ?™_9fþlxMD¾R¼Áïþû<à´kY9 f,ÀÌexSèÌl²§¬…/TèÀí…ÇkaKì–”ÿ…§)öÓàQBAÚô&QX $X&†'¯ÃX(„ÖÏ,Œ 'èÂú9 ‡S !xr*Aˆ4ˆšñŠ lSÁ‡5ö~ !X”]Àw Ö€¾‡5hÁ,š±r7¨*Pg(ñcü× ÌHGƒ¤xdc!À êÀ"Ž: £ we5â1CøEi`_bq_eqø ¤] ê"q»ŸNøƒ_qv€€€Š‘¤¤¢¤Ë¢€×¢¤×¾¤ÿ²´ÿÿ¤ÿ‘ÃÃÁÃÿÖ×ÿé×ÿêÞÿòêÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,G`þà'Š@ižhª®l›ŽðWftmßx®ï<^Æ€žpH,FÁ¢rÉ<Êr¦”hÈ“·€vÊÕI +¶¦-wÏ´¯ìgÊpt"!U¯Ù¶ç.ætJwƒkyX|ˆS %Ev„xzoˆ}L‹Dwa5”–—: *4‹Ž4*›6Ÿ ‡¢[=€(ªX(€;v¯°6fQfB%µ.Å<_½¾8ÂFÇ¥.È=UbÍ£CÄsÚÑÓS”{ÎD&Ûs èæÑnKáh“Æ'gîhñò\ôó ü È`;%úºð×à@>{—‡á¿ ìa´gB¡Ä|5ȸ‘ÁGr'þ¥,ì×p Ã 'RT’…€)˜LÙ#&¸ ü °y3§IƒùxÚ(P€Ç‚‚€þ#Ê`ƒ ôÃTæ¦]­LàµìCaÛ4›Raï¸Ië§&bõë0`_w|¹¶߃W•.$£yëÀÕ»O¿~Ý1øU7}=PÁ}˜þÄ€~ѨÇ`{è k<0ßxÓ pßN,h¥xø_z & ¡I>úq1;tkabber-plugins/poker/pixmaps/doods/155.gif000064400000000000000000000027301500237002100204250ustar00nobodynobodyGIF89aG`ã 0.0nI¥{)±œ0ï®)\ü8´ü½À½üÓ½üÿ½½ìüüÿüÿÿÿÿÿÿÿÿÿ!ù,G`þðI ª½8ëÍ{žàS ƒ”E‰–'C–djÂë,·ï½ì|¿T!€k8cÈn4c ·Ts,Ÿ´˜_ÄVILYI$j’ò´Œªˆü:ÁÎv³ '#Ìèôz%³'órJoNLN>€iBNqƒ‰E2„au5‡;’‚”5*ƒŽ( :y…¥+>š~Y•ž™e—¢qp2»s¯·E™w<¶}¸*Ë œ¢ÇÄ;¡5‘%ÊÍ*®¾œhRƒÁy ÜçÉÎOßžF)âã”Ñæ Üø½ë…_CØ(ñ䱃Ũ{öÎìæÍ»/ÓÌ,àB0[7„ô1ôF⟦aþxxܨŽä¾$ÇÌ¢VmN=“0»Q¤çíT”–›i[ó"Â&^& ̤cLŠ—{^DëZ¨Yýø±ú©P©=t0BcmÄ'U+î8€Õ*Ö´n™‘Jh&(`ß•X0–lR¦$›ÝS†v"ÖLÌ ôo-]²%{žMû©¡Ži(GnY@5©ÒÊÔ‚ Ll 2k‘j¼Œwæ³(6¥:4—qtσè¸DjjQ‡[·jÏ6tªx¹ïÆ1 OCžÍhÀH†]Ÿ$’|`Y¹›?„ްWk†oTz›æóŸùdr²‡‰×H«¶kKû4û"8°ëôøübõìqþQû!C#|ýçØt¯œ`S'­ã‘.¼´#›}-ÔV „ñ¥ÐŠ€mÑ!Œ‚Q"€ªµÀ¡Pðp¢Š'.x›Nâu`ob#€€…׃Î8Ü5pp“"L>‚G*ö˜D( @!À˜”d Ã0Ù•ç(àe3/T‰ä7@F£UZ€å—$ìø—RIz"šé€é¥m¦Ó$š(rf2/ÃE@v¼BkQ›ZÒä€KdQ~øE,޶=•O`{ÅjÖ@MJŒxÈ"üpƒêMñQkäÎ'ÝÄN³£"ñ¨‡F …äã•D2É1Ö@ –„E}p¡ûl¦C²ûdÙI!Æ,,¹Q*•„PÀ¸Ì¥.;‚;tkabber-plugins/poker/pixmaps/doods/big.gif000064400000000000000000000032271500237002100206560ustar00nobodynobodyGIF89a22ç‹                   $ % ' ( ' ) ( ) + ++ . .!0! 2" 5$ 3%4%6% 8(<+>+=,>-?0E0F3J3aC^DfJhK$mLjM$sPpQpQ'uQsSsS(wSqV,zUwV!yX*w[/y\/~[+ƒ[!‚^-ƒ_-Š`#Œa#h1’j2“k3”k3sss™o5Ÿs7™u<§t*£v8x>«w+²1«‚C²>½ƒ0ÂŒ5ÄŽ6Ë”FÕ”6Í•GÏ–HјHÛŸLäŸ:å¦?æ¦?î¦<è¨@ëªAó©=êªQø­?ï®Sú®?ð¯Sñ¯Tô±Uÿ²Aú¶Wû·Wü·Wó¹`ÿºYö¼aÿÃeÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ÿ,22þÿ H° A=ƒ!Z¨HBƒ#J„˜B… V4±ãD/.D¤F…Š<ªØð¢B‘ aVt¸r"J/b´xÒ$É‹5 Žl©“gÅŸEC :P$QŒ0Š<êr!Ó’$AJ-Š´'Ï…(k¶ifÕ®&¡ê¼©2+˜GqÂ]»ugËŽ(õ¼Ek4nÔºC5Ú䋵/F­d÷fD&â[ÄHp`ŒdTUKöiã‚%åF¶€%‹‘|j!s¶ëMœCWœ‚4PøÌŒ°OÀx`Q´¡ÖÏe×3yò•Ýš5ƒÊ Äg>9Q×?þ€@£æLfòÄ DrdÏ(×»ò™Ìa jÈÀ…ëà‚B…È×vˆØ÷Ølùí§Gð`t,ð^öÝBÝýãV^Ë@šNÌ@"$7P!B†ôÕXV>‰ÆÜdLÀ„!êE÷Ç l0/Ø…`‚*xz%´áaqˆÀ ½UwnÍ•““F† øpLQÜ‘\6TcU.)ù–†Á!„t…6yT›yÉ“’rrõ”˜}r•`2 ¦\&ªÝT2ú\NAzäw7µè‚ÀP×~C¤tV”™V}Š"þ¦ÖÕP¨ a!†k©NÈ*IjÙ OA?C@@IBCKCDLDEMGEHEFNFGOHHQJKTKLTMNVOPXPQYUU^UV_VW`WXaXYbYZc[\e\]f]^f_`h`aiffohhqhirijsmnwopyqr{rtqyzƒ}~‡~ˆ€Š†‡‹Œ•ŒŸ“¢’–¥•– “—¦™™£›Ÿ®œ ¯¡°¥©¸¦ª¹®²Á°´Ã´¸Çµ¹É¶ºÊ¹½Í»ÀÏÃÇׯÊÚÃËàÇËÛÆÎãÊÎÝÇÏåÈÐæÏÎæÌÐàÐÏçÊÑçÍÑáÑÐèËÒèÎÒâÌÓéÏÓãÒÒéÍÔêÐÔäÓÓêÑÕåÔÔëÎÖëÒÖæÕÕìÏ×ìÓ×çÖ×áÖÖîÐØí××ïÑÙïÔÙ騨ðÒÚðÖÚêÓÛñÚÙñ×ÛëÔÜòÛÚòØÜìÜÛóÖÝóÙÝí×ÞôÚÞîÝÝôØßõÛßïÞÞõÜàðßß÷ÙáöÝáòààøÚâøááùÛãùÞãóââúÜäúàäôÝåûäãûáåõÞæüåäüâæöàçýãç÷áèþäèøâéÿåéùæêûãëÿçëüêóûòóýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ÿ,22þÿ H° ÁU‚츱cç$Ež JœHQb$W¦^ ЧOŸF—Böt©¢ÉŠ‘LYÂKU¥9v`®ÑsÉÕ¥>Š.%šãç¤O‘"Bäh•)Akõ©c§Ï%I# äÇMœŸé8ÚdÉ‘©T«0)² R#7N YgO¢8s.•ÂjÐÑŸ?– ýÁ´ÊRªK‚*ê£É%EŠôØ™šSn"ºƒò¡ShR«U£½bÕÇΞ9”TyÄÉŽ¢D¦CR¢ ÙQ­Ž&©Ê<ÉѨW}Æ ÉtNŸ=—(1dèñ#V:tˆþ‰¤j"Ø‘X‰j¬JÑáë—qt§˜v|þNM”'ÏŸI˜ 9"Ӧؚ0¡uRÑœ8x<6RZÜ$¤3{¬¥I*© ‰%AY2Ê(³Ô–J!#=¢VíÑGi§E%UE}ø!ˆ…šå&£L’ #´‚È*…HâIp¹µÁÑTq(B$‰X¨ÄD{45%•Dâˆz&:ÛVš™bŠ&Ù Òˆ…~,V• J=2Ö…;Ô‡ŒžUâ $|YÈPDY²É$°À‚ž$‰-–P‹ÙqI< •²¿;¾A‡%t*p±â{îæ•Š*ŽðI%U I!”%e‘”e¤#ØÉ$©ìˆ zD4@£‰ &F®"I€— â‘Ì08ɹF"Rž êÁ‚ ";&I ¼æÈ a"@ ð–àZ† ðÁ‘­rþ$> ÁA9€ & …#–ôZâØLÒ €I$CÐ 0ÑÔ ð D4"‰Þ… 1ÐÄ$¦tìB;ÒëÊ©Àü,y0Â&rhà€bP@‚­ep±ÐG"0ÿAG€ñ%d€É¢É+³3Û|$yŒÀ ˜äîñÇpf!)4À%šMÔù(p ɳ)½ª¢$Ì7ƒBˆ0¦ 0@ TXBü ˆ D`7Àj`f" 8  Sp‚„B6ý=«–˜DÐ’p a"‚à 4Xž„tLuè #>WƒÀðþ|"4‰^Y"ôØXÐ9ÐlØÁà30P (€ ^¸?ÈÏ.<˜â ÈÀ‡?mL+›L´ dª“©4Q*I B”¸“ <¡ IÆH’ÐD%–“ HËX†bU¯þBý!k{8ƒoQ <تÉAD˜L19d1IhD‡‚“ÇÕîqD¯vt IðLptÃ(Æ$‡ôaHZéË"Á¤;ÍÁIx„–‰»˜)«ü*7qª1Bx°±¤y˜ý ©xä$&q§â æB:Ñä qÌE äg¼ "üІ¸xbÉ.ÏT™QX¢,eþAÌZ¡ IŒ k J¦@ìùHóÜq*ÙqÊGž‚,LX¢‘BjÙStBQL¢L‘°§@ÿ‹D9wìV¥)Hl“ !c%§ Fš¨ ¡˜iμâ9@,DYD÷ HIgÊÃ(œó\ÙJ"Ì&øð†<$k£’#ÃÀ\R ¹+FQ&>l+VšŠ$ü8"/r°Í*75«Á1ˆ¨%`@â OhBHDÙæÎ4ª¬v(!v Q¡0U‚ s=‘h$¬ZŠR ËHyØ„ÒøJ/6Q¥’DªWØ‚8™êkpäâ A\T(± eÍRH‚9„íÉlA¨¬EB†9ëˆ\ã8œ="”öš%±•µú¤¦ÈɯÈRŸål%|˜„dñˆáâ$W¡ŠqR z Ɖ8Œ"´‚ÄÀ1+‹ %VóAl+¢\‹­~«bJWª5E!á?@â½tQNô’d…О)ÓiuB%?¬•­QB¨ƒ«!n"]ªˆÄ©»X$âÁ‘H¯T•‘諸Ú#C…1‡¸ k…Äχ`#=X¶/†ñw\Óÿ„Ç=ÆJ@;tkabber-plugins/poker/pixmaps/doods/icondef.xml000064400000000000000000000145211500237002100215560ustar00nobodynobody Doods 1.0 Poker Dood Theme. katzmiff katzmiff 2005 GNU GPL v2 2009-03-10 poker/button button.gif poker/bigblind big.gif poker/smallblind small.gif poker/back 155.gif poker/AD 101.gif poker/2D 102.gif poker/3D 103.gif poker/4D 104.gif poker/5D 105.gif poker/6D 106.gif poker/7D 107.gif poker/8D 108.gif poker/9D 109.gif poker/TD 110.gif poker/JD 111.gif poker/QD 112.gif poker/KD 113.gif poker/AC 114.gif poker/2C 115.gif poker/3C 116.gif poker/4C 117.gif poker/5C 118.gif poker/6C 119.gif poker/7C 120.gif poker/8C 121.gif poker/9C 122.gif poker/TC 123.gif poker/JC 124.gif poker/QC 125.gif poker/KC 126.gif poker/AH 127.gif poker/2H 128.gif poker/3H 129.gif poker/4H 130.gif poker/5H 131.gif poker/6H 132.gif poker/7H 133.gif poker/8H 134.gif poker/9H 135.gif poker/TH 136.gif poker/JH 137.gif poker/QH 138.gif poker/KH 139.gif poker/AS 140.gif poker/2S 141.gif poker/3S 142.gif poker/4S 143.gif poker/5S 144.gif poker/6S 145.gif poker/7S 146.gif poker/8S 147.gif poker/9S 148.gif poker/TS 149.gif poker/JS 150.gif poker/QS 151.gif poker/KS 152.gif tkabber-plugins/poker/pixmaps/doods/small.gif000064400000000000000000000054671500237002100212350ustar00nobodynobodyGIF89a22çÿ*æ-ß!è)ê "é!$â##ê%&ã6!äFç''åDß8"æ-ç4é:#ç*(æHé<$è,)çG"â;&à/è>%é.*è0á0é1+éK$ä!1â1-â?)ã3,êB*å%3ä9ç?êB-ß)4æ70å:è+5çF-è91çP+â-6è;é;3á<â/8âH1ã"=ä>5ãI2äCç$>å3:äIêDè'?æ5;åKæ*@çEéO6èFã,BáE;á.Bé Mè!Hå1Dä$IæNé3Eå?Bå&JçVè(KáPä*Ké7Há+LãWé:JãRæ.Nä;KÝXã Xê"SçIGì#Tá$SèYå3Pà_é'Uã`êZæMKè`Fê[ç+Wäbæ\è.Xæ]â.Yß!]é1Zádç#^êdKç#_ädè4\ã&`å(`æeé)aàfãmè*açnéF[íhå-dâ/eÝ!iæ0eäpä2få$ká%kèvê4gæqæ'lâ6iá)märç+nåsèzè-oæj]èuã\bð0qá |é"vå]eì$wæ}ê'xç~å*zã€ç:wèckìrtq0}æ2€âOzîauí{pïluïSç…rí0Œç~uíL†êI‘í`íU‘éˆòz‡îc’ìc•è]šë—Œòj›îr¥ñŒ¡ô•¡õ…§ð®›ñ©žòž¤ô€®ï˜§õ‹¯ò•°õœ®õ—µóŽºîŸµô§³õŸ¸ñ¯³÷©ºôžÃó¦Ãô´Àõþ÷¯Çó½ÄôªÊôÀÇ÷±ÍòÂÉùµÍù½Ìú·ÓøÅÐùÀÓúÁÙøÔÔùÛÓùØ×üÝÙøßÚùÙÜúÓÞúÍàúÛÞûâÝýÖáýÚâøáàøÛãùÖåùÜäú×çûØèüååýàçýàìúçëüïëýêîþäñÿôíùïïúéòúñòüóôþî÷ÿóøûúøüõúýýúÿ÷ýÿþÿüÿÿÿ!ù ÿ,22þÿ H° Á7‘`ÀP'S"u JœHQâ›3HR¤9 !E %4"%Á’äMÅ“Ó(üpbJ EHnÔ‰”¡F–6):€àÊŸ-$±ðãÌVôQùF„B“ødEäÇ4@+ÞÐÀã0"êøId… ’@i´°T”ÆO$XšD2™µ`„¤!‚ …7oNÔi»á„ŸBHÒH£Ç'Õxbˆ7ÎA$M‹4?Ò°HƒÁ™3ÀL¡AA#?¼i4YÍV´X!‚!M +BüÈ9“BŽÕ+l:¼Ñóršy! µI ?„Ô1K$‰•*UNþì$ÂæÌ.…°ôTtC€ú³yÒ=ù&ŠURPQ‰•B8q0$ u2Ä0‰V¼¡'1rˆp D|!ÂuÈqB%8ø¡g°QÅrð|xDÁB(R‡'œ`…é–„OÅàÂ"Bt0BüÑL’‰"¼@ üA мÑ2D±8´Á†1\ô‡¡LD„<,â Q$²Èr’D!oø@ô‰Å%‚@ZÄÀÀEò1¨!‡gh‘fAà G*Ûì³Ï6¦°ðÁ‘|€À$ ! (b ; @H þVü ‡?è,ð?Þ P ‘ aP%›ü!‹?ð s =þHÒ'P XႊœV vŠ"AG þœsÀ ¸vÀ†IÀ0é@| .þô(ÑÄ"ÄþDcL>Þ ÂÌ>ÞÄAÁ(ªX“?ã¸ÂA&þ¤ãþÓA!gÔñG(çúñm$¯ôã8Å”‚ƒPXøã6ÒøÓO6ÔøÓÌ~@ãO2¼ðL´b¡­rL’,Ppn%7üð³dÃÈíaþØÃsÓêú#Ž¢ÔP"” ;­œÜê '‚Àç¹øÁÄ |r†´8ãÏ3uÐëàŠ#@#R¿Q þ&Üäs=þp®kãŠÅ"8€DÿÓg"oq?´¤1 ŸÑÔ$Œ`8´"I<ñhqH<þ €?åø!‚?ß@þCHÈñFš0ñØÒô2ØãO-‰œ!µi$œ·é¸É<ý(ÓŒÈB@ëu(ÿA$jÒZš€)ÂDu¬¢>ú  ŠX"uçŠ@·bTrÊ;û ³Œ?¤ü€+ÀÕnðNBu›Žk8±‘ü M @B\s†C(2yÃt2A=Ôa6LD$"aÈ`ቨd2A„$2 ±ŠòšA†lD°£?@6þ¢À !£‰²Œ°Âîˆ:PŒ.pÀ\Ð9¨g…o°€ª`žL¤Á(ƒ4`´X@%¬ƒЈ:Œ “ChD …F   s€°0P :@(÷4ÂiB(0‰&LA°€A„4‚`h Á„6èä~ ’ ¼Á®êF‰¥`áЂêü †è­ñD°S‡@ˆ°?¨‚ê6iGÈèsR"~ ì4`ÐB,!›$ÔA#X$&Abw DÀ°*ÔA˜?|C(f j¾A¾œ:&á øaþ@X9,ÖÕAdÚÐ ÀopŸ8°ˆBþÀ`˜Dãøðƒ)L皬³DRÐ5@æzM†/ôP…$a °Ô‚ˆPP3t²ÉTB±4Q@°BW‡eäƒÄ@Âæwpâ¢Ù.òÑY$ÁD0>ê Ö¡R‘8D PÓ¤Æ&m„DÖSwøã(ðß9`²¹…¬Óp›;AaøcÃ`G·°éÈ4¢q™òI£ê#`…?²Ñµ¦¡ŸSsŸ=è€yô¨G>´ð†>ÐJ M@†ÚUèAU¤!üáÈ0mÐþÃÿdKŽ:àíS¸A9ü!€4¬+:0ùƒ6€«€ýÇ$ÞÀ‡$ˆaµû`¶ 2pkn„Þ¼‘BœÃ(;î¡ÂVÐêzÐCÔð×s „šÔ܄ɸñ á"ŒRûAvÏÙž‰èðGø „ãïà:4Q”– ƒÚàjÃôÀ´t¦aàl‰@0¡SÕÅ;¼QÈÕÔ½yC Þ°3Kàƒ%%D!c = Ñ5Çl'± ¦XÐÀðà‚ @ %œB Qé*$þIî n€u’€†‚e>¢ X¨Bþ“ ˆ Hënp’èáV±Ä!š’>4¢ Lï‡`Çv¾ø$I`þ4JB´ÆUhCInü†3²|²Ñ1%‡ @Q`‰bêáœèñð†6X@mЀ«`€?›ðÓ?Ñ!PÐFôÔYµ„D Û&Áš7¨B#’]•2yÍ(f…Lâ–hC´ÐšFŒÐ¶‡h!Qàº.¡˜M‡ªl¾'j0Ĉj"óÜ“I·êN‹["ÀiðõÞPü±|6´'óŠé@B$BdA †àÃÄ ‚'—áy±ª…,ÀA´J€ŒÇò‚¬üå,o9E`þñ¬;tkabber-plugins/poker/poker.tcl000064400000000000000000002656601500237002100164740ustar00nobodynobody# poker.tcl -- # # This file implements Poker game plugin for the Tkabber XMPP client. # This plugin uses long arithmetics and [lmap], so it requires Tcl 8.6 if {![package vsatisfies [package present Tcl] 8.6-]} return package require msgcat namespace eval poker { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered poker]} { ::plugins::register poker \ -namespace [namespace current] \ -source [info script] \ -description \ [::msgcat::mc "Whether the Poker (Texas\ hold'em) plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable themes variable dirs \ [glob -nocomplain -directory [file join [file dirname [info script]] \ pixmaps] *] variable dir foreach dir $dirs { pixmaps::load_theme_name [namespace current]::themes $dir } variable values {} variable theme foreach theme [lsort [array names themes]] { lappend values $theme $theme } variable options custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup Poker [::msgcat::mc "Poker (Texas hold'em) plugin\ options."] \ -group Plugins custom::defvar options(theme) Classic \ [::msgcat::mc "Poker playing cards theme."] -group Poker \ -type options -values $values \ -command [namespace code load_stored_theme] custom::defvar options(show_tooltips) 1 \ [::msgcat::mc "Show tooltips with short instructions."] \ -type boolean -group Poker \ -command [namespace code set_tooltips] custom::defvar options(sound) "" \ [::msgcat::mc "Sound to play after opponent's deal or bet"] \ -type file -group Poker variable prime1 \ 0x[join {FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF} \ ""] variable generator1 2 variable bytesp1 96 ; # Prime1 length variable bytes1 40 ; # Key length option add *Poker*tableBackground #8fbc8f widgetDefault option add *Poker*tableForeground #cdddcd widgetDefault variable card_width [expr {71*$::icons_scale}] variable card_height [expr {96*$::icons_scale}] variable line_width [expr {5*$::icons_scale}] variable line_pad [expr {5*$::icons_scale}] variable line_margin [expr {10*$::icons_scale}] variable text_height [expr {20*$::icons_scale}] } proc poker::load {} { hook::add roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.4 hook::add chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.4 hook::add roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.4 hook::add games_cards_create_hook [namespace current]::iq_create hook::add games_cards_turn_hook [namespace current]::iq_turn ::xmpp::iq::register set create games:cards \ [namespace parent]::iq_games_cards_create ::xmpp::iq::register set * games:cards \ [namespace parent]::iq_games_cards_turn load_stored_theme } proc poker::unload {} { hook::remove roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.4 hook::remove chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.4 hook::remove roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.4 hook::remove games_cards_create_hook [namespace current]::iq_create hook::remove games_cards_turn_hook [namespace current]::iq_turn if {[hook::is_empty games_cards_create_hook]} { ::xmpp::iq::unregister set create games:cards rename [namespace parent]::iq_games_cards_create "" } if {[hook::is_empty games_cards_turn_hook]} { ::xmpp::iq::unregister set * games:cards rename [namespace parent]::iq_games_cards_turn "" } foreach var [info vars [namespace current]::*] { upvar #0 $var flags if {[info exists flags(window)]} { destroy_win $flags(window) } } foreach var [info vars [namespace current]::*] { if {$var ne "[namespace current]::options"} { unset $var } } foreach img [image names] { if {[string first poker/ $img] == 0} { image delete $img } } } proc poker::load_stored_theme {args} { variable options variable themes pixmaps::load_dir $themes($options(theme)) } proc poker::make_gid {jid id} { jid_to_tag [concat $jid $id] } proc poker::invite_dialog {xlib jid} { set w .poker_invite if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Poker Invitation"] \ -modal none \ -anchor e \ -default 0 set wf [$w getframe] Message $wf.message -aspect 50000 \ -text [::msgcat::mc "Sending Poker (Texas hold'em)\ game invitation to %s (%s)" \ [chat::get_nick $xlib $jid chat] \ $jid] pack $wf.message -pady 2m $w add -text [::msgcat::mc "I want to deal first"] \ -command [namespace code [list invite $xlib $jid true]] $w add -text [::msgcat::mc "I want to deal second"] \ -command [namespace code [list invite $xlib $jid false]] $w add -text [::msgcat::mc "Cancel invitation"] \ -command [list destroy $w] $w draw } proc poker::invite {xlib jid deal} { destroy .poker_invite set id poker[rand 1000000000] # FIX #set rjid [get_jid_of_user $jid] set fields [concat [::xmpp::data::formField field \ -var FORM_TYPE \ -type hidden \ -value games:cards:dn] \ [::xmpp::data::formField field \ -var modp \ -type list-single \ -options {"" 1}]] set feature \ [::xmpp::xml::create feature \ -xmlns http://jabber.org/protocol/feature-neg \ -subelement [::xmpp::data::form $fields]] ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create create \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $id \ deal $deal] \ -subelement $feature] \ -to $jid \ -command [namespace code [list invite_res $xlib $jid $id $deal]] } proc poker::invite_res {xlib jid id deal status xml} { if {![string equal $status ok]} { after idle [list NonmodalMessageDlg .poker_invite_error \ -aspect 50000 \ -icon error \ -message [::msgcat::mc "%s (%s) has refused poker\ invitation: %s" \ [chat::get_nick $xlib $jid \ chat] \ $jid [error_to_string $xml]]] return } # TODO: Parse negotiation submit form start_play $xlib $jid $id $deal 1 } proc poker::invited_dialog {xlib jid iqid id deal modp} { set w .poker_invited if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Poker Invitation from %s" $jid] \ -modal none \ -anchor e \ -default 0 set wf [$w getframe] bind $wf [namespace code [list invited_res $w $xlib $jid $iqid \ $id $deal $modp 0]] set nick [chat::get_nick $xlib $jid chat] set message1 [::msgcat::mc "Poker (Texas hold'em) game invitation\ from %s (%s) is received." \ $nick $jid] switch -- $deal { true { set message2 [::msgcat::mc "%s wants to deal first." $nick] } false { set message2 [::msgcat::mc "%s wants to deal second." $nick] } default { return [list error modify bad-request] } } Message $wf.message1 -aspect 50000 -text $message1 Message $wf.message2 -aspect 50000 -text $message2 pack $wf.message1 -pady 1m pack $wf.message2 -pady 1m $w add -text [::msgcat::mc "Agree to play"] \ -command [namespace code [list invited_res $w $xlib $jid $iqid \ $id $deal $modp 1]] $w add -text [::msgcat::mc "Refuse to play"] \ -command [namespace code [list invited_res $w $xlib $jid $iqid \ $id $deal $modp 0]] $w draw return } proc poker::invited_res {w xlib jid iqid id deal modp res} { catch { set wf [$w getframe] bind $wf {} destroy $w } if {$res} { switch -- $deal { true { start_play $xlib $jid $id false $modp } false { start_play $xlib $jid $id true $modp } default { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify bad-request] \ -to $jid \ -id $iqid } } set feature \ [::xmpp::xml::create feature \ -xmlns http://jabber.org/protocol/feature-neg \ -subelement [::xmpp::data::submitForm \ [list FORM_TYPE games:cards:dn \ modp $modp]]] ::xmpp::sendIQ $xlib result \ -query [::xmpp::xml::create create \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $id] \ -subelement $feature] \ -to $jid \ -id $iqid } else { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify not-acceptable] \ -to $jid \ -id $iqid } return } proc poker::start_play {xlib jid id deal modp} { set gid [make_gid $jid $id] variable $gid variable options upvar 0 $gid flags set flags(window) [win_id poker $gid] set flags(xlib) $xlib set flags(opponent) $jid set flags(id) $id set flags(modp) $modp set flags(deal_first) $deal set flags(deals) 0 set flags(stop) 0 # TODO: Negotiate these values set flags(my_stack) 2000 set flags(opp_stack) 2000 set flags(small_blind) 10 set flags(big_blind) 20 set flags(double_blinds) 4 trace add variable [namespace current]::${gid}(state) write \ [namespace code [list on_state_change $gid]] open $gid } proc poker::close {gid} { variable $gid upvar 0 $gid flags array unset flags } proc poker::exists {gid} { variable $gid info exists $gid } proc poker::open {gid} { variable line_margin variable line_width variable line_pad variable card_width variable card_height variable text_height variable options variable $gid upvar 0 $gid flags set jid $flags(opponent) set w $flags(window) if {[winfo exists $w]} { raise_win $w return } set title [::msgcat::mc "Poker with %s" \ [chat::get_nick $flags(xlib) $jid chat]] add_win $w -title $title \ -tabtitle $title \ -class Poker \ -raise 1 variable board_width \ [expr {4*$line_margin + 6*$line_width + 8*$line_pad + 5*$card_width}] variable board_height \ [expr {8*$line_margin + 6*$line_width + 6*$line_pad + 3*$card_height + 2*$text_height}] set board [canvas $w.board \ -borderwidth 0 \ -highlightthickness 0 \ -width $board_width \ -height $board_height] set background [option get $board tableBackground Poker] $board configure -background $background pack $board -side left -anchor w -padx 2m set color [option get $board tableForeground Poker] set x1 \ [expr {($board_width - 2*$line_width - 3*$line_pad - 2*$card_width)/2}] set y1 [expr {$board_height - $line_margin}] set x2 [expr {$board_width - $x1}] set y2 [expr {$y1 - 2*$line_width - 2*$line_pad - $card_height}] $board create polygon $x1 $y1 $x1 $y2 $x2 $y2 $x2 $y1 \ -fill "" -outline $color -width $line_width -joinstyle round set y1 [expr {$board_height - $y1}] set y2 [expr {$board_height - $y2}] $board create polygon $x1 $y1 $x1 $y2 $x2 $y2 $x2 $y1 \ -fill "" -outline $color -width $line_width -joinstyle round set x1 [expr {$line_margin}] set x2 [expr {$x1 + 2*$line_width + 4*$line_pad + 3*$card_width}] set y1 \ [expr {($board_height - 2*$line_width - 2*$line_pad - $card_height)/2}] set y2 [expr {$board_height - $y1}] $board create polygon $x1 $y1 $x1 $y2 $x2 $y2 $x2 $y1 \ -fill "" -outline $color -width $line_width -joinstyle round set x1 [expr {$x2 + $line_margin}] set x2 [expr {$x1 + 2*$line_width + 2*$line_pad + $card_width}] $board create polygon $x1 $y1 $x1 $y2 $x2 $y2 $x2 $y1 \ -fill "" -outline $color -width $line_width -joinstyle round set x1 [expr {$x2 + $line_margin}] set x2 [expr {$x1 + 2*$line_width + 2*$line_pad + $card_width}] $board create polygon $x1 $y1 $x1 $y2 $x2 $y2 $x2 $y1 \ -fill "" -outline $color -width $line_width -joinstyle round frame $w.mystack -background $background label $w.mystack.label \ -text [::msgcat::mc "Stack: "] -background $background grid $w.mystack.label -row 1 -column 0 -sticky w label $w.mystack.stack -anchor w -background $background \ -textvariable [namespace current]::${gid}(my_stack) grid $w.mystack.stack -row 1 -column 1 -sticky w label $w.mystack.lbet -text [::msgcat::mc "Bet:"] -background $background grid $w.mystack.lbet -row 0 -column 0 -sticky w label $w.mystack.bet -anchor w -background $background \ -textvariable [namespace current]::${gid}(my_bet) grid $w.mystack.bet -row 0 -column 1 -sticky w set x [expr {($board_width - $line_pad)/2 - $card_width - $line_pad - $line_width - $line_margin}] set y [expr {$board_height - ($line_margin + 2*$line_width + 2*$line_pad + $card_height)}] $board create window $x $y -window $w.mystack -anchor ne frame $w.oppstack -background $background label $w.oppstack.label \ -text [::msgcat::mc "Stack: "] -background $background grid $w.oppstack.label -row 0 -column 0 -sticky w label $w.oppstack.stack -anchor w -background $background \ -textvariable [namespace current]::${gid}(opp_stack) grid $w.oppstack.stack -row 0 -column 1 -sticky w label $w.oppstack.lbet -text [::msgcat::mc "Bet:"] -background $background grid $w.oppstack.lbet -row 1 -column 0 -sticky w label $w.oppstack.bet -anchor w -background $background \ -textvariable [namespace current]::${gid}(opp_bet) grid $w.oppstack.bet -row 1 -column 1 -sticky w set x [expr {($board_width - $line_pad)/2 - $card_width - $line_pad - $line_width - $line_margin}] set y [expr {$line_margin + 2*$line_width + 2*$line_pad + $card_height}] $board create window $x $y -window $w.oppstack -anchor se set flags(board) $board Frame $w.info1 pack $w.info1 -side top -anchor w Label $w.info1.ldealer -text [::msgcat::mc "Dealer: "] grid $w.info1.ldealer -row 0 -column 0 -sticky w Label $w.info1.dealer -anchor w \ -textvariable [namespace current]::${gid}(dealer) grid $w.info1.dealer -row 0 -column 1 -sticky w Label $w.info1.lsblind -text [::msgcat::mc "Small blind: "] grid $w.info1.lsblind -row 1 -column 0 -sticky w Label $w.info1.sblind -anchor w \ -textvariable [namespace current]::${gid}(small_blind) grid $w.info1.sblind -row 1 -column 1 -sticky w Label $w.info1.lbblind -text [::msgcat::mc "Big blind: "] grid $w.info1.lbblind -row 2 -column 0 -sticky w Label $w.info1.bblind -anchor w \ -textvariable [namespace current]::${gid}(big_blind) grid $w.info1.bblind -row 2 -column 1 -sticky w set bbox [ButtonBox $w.bbox -orient vertical -spacing 0] $bbox add -text [::msgcat::mc "Bet"] \ -state disabled \ -command [namespace code [list bet $gid bet]] $bbox add -text [string trim [::msgcat::mc "Check "]] \ -state disabled \ -command [namespace code [list bet $gid check]] $bbox add -text [string trim [::msgcat::mc "Fold "]] \ -state disabled \ -command [namespace code [list bet $gid fold]] $bbox add -text [::msgcat::mc "Stop the game"] \ -command [namespace code [list stop_game $gid]] grid columnconfigure $bbox 0 -weight 1 pack $bbox -side bottom -anchor w -fill x set flags(bbox) $bbox #set_tooltips Frame $w.info5 pack $w.info5 -side bottom -anchor w -fill x set flags(scale) \ [Scale $w.info5.scale \ -orient horizontal \ -from $flags(big_blind) \ -to $flags(my_stack) \ -variable [namespace current]::${gid}(bet_or_raise_amount)] if {[catch {$flags(scale) state disabled}]} { $flags(scale) configure -state disabled -showvalue 0 } pack $w.info5.scale -side left -anchor w -expand yes -fill x Frame $w.info4 pack $w.info4 -side bottom -anchor w -fill x Label $w.info4.lamount -state disabled \ -text [::msgcat::mc "Amount to bet: "] pack $w.info4.lamount -side left Entry $w.info4.amount -state disabled \ -textvariable [namespace current]::${gid}(bet_or_raise_amount) pack $w.info4.amount -side left -anchor w -expand yes -fill x set flags(lentry) $w.info4.lamount set flags(entry) $w.info4.amount trace add variable [namespace current]::${gid}(bet_or_raise_amount) write \ [namespace code [list configure_raise_button $gid]] Button $w.allin -text [string trim [::msgcat::mc "All-In "]] \ -state disabled \ -command [namespace code [list bet $gid allin]] pack $w.allin -side bottom -anchor w -fill x set flags(button_allin) $w.allin set hsw [ScrolledWindow $w.hsw] pack $hsw -side top -fill x -expand yes set ht [Text $w.text -wrap word -height 60 -state disabled] $ht tag configure attention \ -foreground [option get $ht errorForeground Text] $hsw setwidget $ht set flags(hw) $ht bind $w [namespace code [list close $gid]] add_to_log $gid [::msgcat::mc "Starting the game"] add_to_log $gid [::msgcat::mc "Your stack is %s" $flags(my_stack)] add_to_log $gid [::msgcat::mc "Opponent's stack is %s" $flags(opp_stack)] add_to_log $gid [::msgcat::mc "Small blind is %s" $flags(small_blind)] add_to_log $gid [::msgcat::mc "Big blind is %s" $flags(big_blind)] add_to_log $gid [::msgcat::mc "Blinds are doubled every %s deals" \ $flags(double_blinds)] if {$flags(deal_first)} { add_to_log $gid [::msgcat::mc "You deal first"] set_state $gid new } else { add_to_log $gid [::msgcat::mc "Opponent deals first"] # Can't use set_state here because of sync problem if the opponent is # already sent us a deck set flags(state) new } } proc poker::add_to_log {gid message} { variable $gid upvar 0 $gid flags $flags(hw) configure -state normal $flags(hw) insert end \ "\[[clock format [clock seconds] -format %H:%M:%S]\] $message\n" $flags(hw) configure -state disabled $flags(hw) see end } proc poker::configure_raise_button {gid args} { variable $gid upvar 0 $gid flags if {$flags(state) eq "new"} return if {$flags(my_bet) == $flags(opp_bet)} { $flags(bbox) itemconfigure 0 \ -text [::msgcat::mc "Bet %s" $flags(bet_or_raise_amount)] \ -command [namespace code [list bet $gid bet \ $flags(bet_or_raise_amount)]] } else { $flags(bbox) itemconfigure 0 \ -text [::msgcat::mc "Raise %s" $flags(bet_or_raise_amount)] \ -command [namespace code [list bet $gid raise \ $flags(bet_or_raise_amount)]] } } proc poker::bet {gid tag {amount ""}} { variable $gid upvar 0 $gid flags if {$amount ne ""} { set attrs [list amount $amount] } else { set attrs {} } ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create bet \ -xmlns games:cards \ -attrs [list type poker:th:1 id $flags(id)] \ -subelement [::xmpp::xml::create $tag \ -attrs $attrs]] \ -to $flags(opponent) \ -command [namespace code [list bet_result $gid $tag $amount]] } proc poker::bet_result {gid tag amount status xml} { variable $gid upvar 0 $gid flags if {![string equal $status ok]} { # TODO return } set state $flags(state) switch -- $flags(state) { preflop { set newstate flop-deal } flop { set newstate turn-deal } turn { set newstate river-deal } river { set newstate finish } default { # TODO: Some error message return } } set flags(bet) [expr {!$flags(bet)}] incr flags(bets) switch -- $tag { call { set call [expr {$flags(opp_bet) - $flags(my_bet)}] incr flags(my_stack) -$call incr flags(my_bet) $call draw_bet $gid 1 [::msgcat::mc "Call"] add_to_log $gid [::msgcat::mc "You call %s" $call] } allin { incr flags(my_bet) $flags(my_stack) set flags(my_stack) 0 set flags(my_all_in) 1 draw_bet $gid 1 [::msgcat::mc "All-In"] add_to_log $gid [::msgcat::mc "You go all-in"] } bet - raise { incr flags(my_stack) -$amount incr flags(my_bet) $amount draw_bet $gid 1 [::msgcat::mc "Raise"] add_to_log $gid [::msgcat::mc "You raise %s" $amount] } check { draw_bet $gid 1 [::msgcat::mc "Check"] add_to_log $gid [::msgcat::mc "You check"] } fold { draw_bet $gid 1 [::msgcat::mc "Fold"] draw_bet $gid 0 [::msgcat::mc "Winner"] add_to_log $gid [::msgcat::mc "You fold"] set pot [expr {$flags(my_bet) + $flags(opp_bet)}] incr flags(opp_stack) $pot add_to_log $gid [::msgcat::mc "Opponent won pot %s" $pot] set flags(my_bet) 0 set flags(opp_bet) 0 set_state $gid check return } } # Non-dealer sending call, or calling all-in, or closing check # should switch to the next state without after idle. switch -- $tag { check { if {$flags(bets) % 2 == 0} { if {$newstate eq "finish"} { send_open_cards $gid } set flags(state) $newstate } } call { if {$flags(opp_all_in)} { set flags(showdown) 1 send_open_cards $gid } if {$flags(bets) != 1} { if {$newstate eq "finish"} { send_open_cards $gid } set flags(state) $newstate } } allin { # All-In is not always closing if {$flags(opp_all_in) || $flags(my_bet) <= $flags(opp_bet)} { set flags(showdown) 1 send_open_cards $gid set flags(state) $newstate } } } if {$flags(state) eq $state} { start_betting $gid } } proc poker::stop_game {gid} { variable $gid upvar 0 $gid flags set flags(stop) 1 disable_controls $gid add_to_log $gid [::msgcat::mc "The game is terminated by you"] ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create stop \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $flags(id)]] \ -to $flags(opponent) } proc poker::disable_controls {gid} { variable $gid upvar 0 $gid flags $flags(bbox) itemconfigure 0 -text [::msgcat::mc "Bet"] -state disabled $flags(bbox) itemconfigure 1 -text [string trim [::msgcat::mc "Check "]] \ -state disabled $flags(bbox) itemconfigure 2 -state disabled $flags(bbox) itemconfigure 3 -state disabled $flags(button_allin) configure -state disabled if {[catch {$flags(scale) state disabled}]} { $flags(scale) configure -state disabled } $flags(lentry) configure -state disabled $flags(entry) configure -state disabled } proc poker::send_deck {gid} { variable prime1 variable bytesp1 variable $gid upvar 0 $gid flags set deck {} for {set i 0} {$i < 52} {incr i} { set msg [expr {([gen_rnd $bytesp1] & ~0x3f) | $i}] lappend deck $msg } set subels {} set ekey [ekey $flags(key)] foreach msg [shuffle $deck] { lappend subels \ [::xmpp::xml::create card \ -attrs [list msg [dec2hex [encipher $ekey $msg]]]] update # During update many things may happen if {![exists $gid] || $flags(stop)} return } # We don't store the shuffled deck because there will be another # reshuffle at the other side, so this cards order will be useless. add_to_log $gid [::msgcat::mc "Sending shuffled deck"] ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create deck \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $flags(id)] \ -subelements $subels] \ -to $flags(opponent) \ -command [namespace code [list send_deck_result $gid]] add_to_log $gid [::msgcat::mc "Waiting for reshuffled deck"] } proc poker::send_deck_result {gid status xml} { variable $gid upvar 0 $gid flags if {![string equal $status ok]} { # TODO return } set flags(deck) {} ::xmpp::xml::split $xml tag xmlns attrs cdata subels foreach subel $subels { ::xmpp::xml::split $subel stag sxmlns sattrs scdata ssubels if {[string equal $stag card]} { lappend flags(deck) [hex2dec [::xmpp::xml::getAttr $sattrs msg]] } } if {[llength $flags(deck)] != 52} { # TODO return } add_to_log $gid [::msgcat::mc "Received reshuffled deck"] send_deck2 $gid } proc poker::send_deck2 {gid} { variable prime1 variable bytes1 variable $gid upvar 0 $gid flags set flags(keys) {} for {set i 0} {$i < 52} {incr i} { lappend flags(keys) [gen_rnd $bytes1] } set subels {} set dkey [dkey $flags(key)] foreach msg $flags(deck) key $flags(keys) { set ekey [ekey $key] lappend subels \ [::xmpp::xml::create card \ -attrs [list msg \ [dec2hex [encipher $ekey \ [decipher $dkey $msg]]]]] update # During update many things may happen if {![exists $gid] || $flags(stop)} return } # We don't store the shuffled deck because there will be another # reshuffle at the other side, so this cards order will be useless. add_to_log $gid [::msgcat::mc "Sending reencrypted deck"] ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create redeck \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $flags(id)] \ -subelements $subels] \ -to $flags(opponent) \ -command [namespace code [list send_deck2_result $gid]] add_to_log $gid [::msgcat::mc "Waiting for doubly reencrypted deck"] } proc poker::send_deck2_result {gid status xml} { variable $gid upvar 0 $gid flags if {![string equal $status ok]} { # TODO return } set flags(deck) {} ::xmpp::xml::split $xml tag xmlns attrs cdata subels foreach subel $subels { ::xmpp::xml::split $subel stag sxmlns sattrs scdata ssubels if {[string equal $stag card]} { lappend flags(deck) [hex2dec [::xmpp::xml::getAttr $sattrs msg]] } } if {[llength $flags(deck)] != 52} { # TODO return } add_to_log $gid [::msgcat::mc "Received doubly reencrypted deck"] set_state $gid preflop-deal } proc poker::send_open_cards {gid} { variable $gid upvar 0 $gid flags set subels {} foreach {seq card} $flags(mvisible_cards) { if {[lsearch -exact $flags(hole_cards) $card] >= 0} { lappend subels \ [::xmpp::xml::create card \ -attrs [list seq $seq \ msg [dec2hex $card]]] lappend flags(ovisible_cards) $seq } } ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create open \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $flags(id)] \ -subelements $subels] \ -to $flags(opponent) \ -command [namespace code [list send_open_cards_result $gid]] } proc poker::send_open_cards_result {gid status xml} { variable $gid upvar 0 $gid flags if {![string equal $status ok]} { # TODO return } add_to_log $gid [::msgcat::mc "You opened pocket cards to opponent"] switch -- $flags(state) { preflop { set_state $gid flop-deal } flop { set_state $gid turn-deal } turn { set_state $gid river-deal } river { set_state $gid finish } } } proc poker::send_hole_cards {gid} { variable $gid upvar 0 $gid flags set subels {} # Opponent's cards foreach seq {0 1} { set dkey [dkey [lindex $flags(keys) $seq]] lappend subels \ [::xmpp::xml::create card \ -attrs [list seq [expr {$seq + 1}] \ hold true \ msg \ [dec2hex \ [decipher $dkey \ [lindex $flags(deck) $seq]]]]] } lappend flags(ovisible_cards) 1 2 # Dealer's cards foreach seq {2 3} { lappend subels \ [::xmpp::xml::create card \ -attrs [list seq [expr {$seq + 1}] \ hold false \ msg [dec2hex [lindex $flags(deck) $seq]]]] } ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create deal \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $flags(id)] \ -subelements $subels] \ -to $flags(opponent) \ -command [namespace code [list send_hole_cards_result $gid {3 4}]] } proc poker::send_hole_cards_result {gid seqlist status xml} { variable $gid upvar 0 $gid flags if {![string equal $status ok]} { # TODO return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels foreach subel $subels { ::xmpp::xml::split $subel stag sxmlns sattrs scdata ssubels if {[string equal $stag card]} { set seq [::xmpp::xml::getAttr $sattrs seq] set dkey [dkey [lindex $flags(keys) [expr {$seq - 1}]]] if {[set idx [lsearch -exact $seqlist $seq]] < 0} { # TODO return } set seqlist [lreplace $seqlist $idx $idx] set card [expr {[decipher $dkey \ [hex2dec [::xmpp::xml::getAttr \ $sattrs msg]]] & 0x3f}] lappend flags(mvisible_cards) $seq $card lappend flags(hole_cards) $card } } if {[llength $flags(hole_cards)] != 2 || [llength $seqlist] != 0} { # TODO return } add_to_log $gid [::msgcat::mc "You got pocket cards %s" \ [join [lmap x $flags(hole_cards) \ {[namespace current]::num2card $x}] ", "]] # We're not using set_state here to ensure that immediate bet will # be processed if any. set flags(state) preflop } proc poker::draw_hole_cards {gid} { variable board_height variable board_width variable card_height variable card_width variable line_margin variable line_width variable line_pad variable $gid upvar 0 $gid flags set x [expr {$board_width/2 - $card_width - $line_pad/2}] set y1 [expr {$board_height - $line_margin - $line_width - $line_pad - $card_height}] set y2 [expr {$line_margin + $line_width + $line_pad}] foreach card $flags(hole_cards) { set c [num2card $card] $flags(board) create image $x $y1 -anchor nw -image poker/$c -tags card $flags(board) create image $x $y2 -anchor nw -image poker/back \ -tags card set x [expr {$x + $line_pad + $card_width}] } set x [expr {$board_width/2 - $card_width - $line_pad/2}] foreach card $flags(opp_hole_cards) { set c [num2card $card] $flags(board) create image $x $y2 -anchor nw -image poker/$c -tags card set x [expr {$x + $line_pad + $card_width}] } catch {$flags(board) lower card bet} } proc poker::draw_flop {gid} { variable board_height variable board_width variable card_height variable card_width variable line_margin variable line_width variable line_pad variable $gid upvar 0 $gid flags set x [expr {$line_margin + $line_width + $line_pad}] set y [expr {($board_height - $card_height)/2}] foreach card $flags(flop) { set c [num2card $card] $flags(board) create image $x $y -anchor nw -image poker/$c -tags card set x [expr {$x + $line_pad + $card_width}] } } proc poker::draw_turn {gid} { variable board_height variable board_width variable card_height variable card_width variable line_margin variable line_width variable line_pad variable $gid upvar 0 $gid flags set x [expr {2*$line_margin + 3*$line_width + 5*$line_pad + 3*$card_width}] set y [expr {($board_height - $card_height)/2}] foreach card $flags(turn) { set c [num2card $card] $flags(board) create image $x $y -anchor nw -image poker/$c -tags card set x [expr {$x + $line_pad + $card_width}] } } proc poker::draw_river {gid} { variable board_height variable board_width variable card_height variable card_width variable line_margin variable line_width variable line_pad variable $gid upvar 0 $gid flags set x [expr {3*$line_margin + 5*$line_width + 7*$line_pad + 4*$card_width}] set y [expr {($board_height - $card_height)/2}] foreach card $flags(river) { set c [num2card $card] $flags(board) create image $x $y -anchor nw -image poker/$c -tags card set x [expr {$x + $line_pad + $card_width}] } } proc poker::draw_best_hand {gid} { variable board_height variable board_width variable card_height variable card_width variable line_margin variable line_width variable line_pad variable text_height variable $gid upvar 0 $gid flags $flags(board) delete hand set color [option get $flags(board) tableForeground Poker] set x [expr {$board_width/2}] set msg [score2msg [select_best_hand [concat $flags(hole_cards) \ $flags(flop) \ $flags(turn) \ $flags(river)]]] set y [expr {($board_height + $card_height)/2 + $text_height + $line_width + $line_pad + $line_margin}] $flags(board) create text $x $y -anchor center -tags hand \ -text $msg -fill $color -font {Arial 20 bold} if {[llength $flags(opp_hole_cards)] == 2} { # Opponent reveared his cards, so we can evaluate his hand set msg [score2msg [select_best_hand [concat $flags(opp_hole_cards) \ $flags(flop) \ $flags(turn) \ $flags(river)]]] set y [expr {($board_height - $card_height)/2 - $text_height - $line_width - $line_pad - $line_margin}] $flags(board) create text $x $y -anchor center -tags hand \ -text $msg -fill $color -font {Arial 20 bold} } } proc poker::send_community_cards {gid seqlist} { variable $gid upvar 0 $gid flags # This proc is calld from after command, so checking the game existence if {![exists $gid]} return set flags(ovisible_cards) [concat $flags(ovisible_cards) $seqlist] set subels {} foreach seq $seqlist { set dkey [dkey [lindex $flags(keys) [expr {$seq - 1}]]] lappend subels \ [::xmpp::xml::create card \ -attrs [list seq $seq \ community true \ msg \ [dec2hex \ [decipher $dkey \ [lindex $flags(deck) \ [expr {$seq - 1}]]]]]] } ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create deal \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $flags(id)] \ -subelements $subels] \ -to $flags(opponent) \ -command [namespace code [list send_community_cards_result \ $gid $seqlist]] } proc poker::send_community_cards_result {gid seqlist status xml} { variable $gid upvar 0 $gid flags if {![string equal $status ok]} { # TODO return } ::xmpp::xml::split $xml tag xmlns attrs cdata subels foreach subel $subels { ::xmpp::xml::split $subel stag sxmlns sattrs scdata ssubels if {[string equal $stag card]} { set seq [::xmpp::xml::getAttr $sattrs seq] if {[set idx [lsearch -exact $seqlist $seq]] < 0} { # TODO return } set seqlist [lreplace $seqlist $idx $idx] set card \ [expr {[hex2dec [::xmpp::xml::getAttr $sattrs msg]] & 0x3f}] switch -- $flags(state) { flop-deal { lappend flags(flop) $card } turn-deal { lappend flags(turn) $card } river-deal { lappend flags(river) $card } } lappend flags(mvisible_cards) $seq $card } } if {[llength $seqlist] != 0} { # TODO return } # We're not using set_state here to ensure that immediate bet will # be processed if any. switch -- $flags(state) { flop-deal { set flags(state) flop } turn-deal { set flags(state) turn } river-deal { set flags(state) river } } } proc poker::start_betting {gid} { variable $gid upvar 0 $gid flags if {$flags(bet) && !$flags(my_all_in)} { if {$flags(my_bet) == $flags(opp_bet)} { if {$flags(my_stack) < $flags(big_blind)} { set flags(bet_or_raise_amount) $flags(big_blind) $flags(bbox) itemconfigure 0 -text [::msgcat::mc "Bet"] \ -state disabled $flags(lentry) configure -state disabled $flags(entry) configure -state disabled } else { $flags(bbox) itemconfigure 0 -text [::msgcat::mc "Bet"] \ -state normal set flags(bet_or_raise_amount) $flags(big_blind) $flags(lentry) configure -state normal $flags(entry) configure -state normal } $flags(bbox) itemconfigure 1 \ -text [string trim [::msgcat::mc "Check "]] \ -state normal \ -command [namespace code [list bet $gid check]] } elseif {$flags(my_bet) < $flags(opp_bet)} { set call [expr {$flags(opp_bet) - $flags(my_bet)}] set raise [expr {2*$call}] if {$flags(my_stack) < $call} { set flags(bet_or_raise_amount) $raise $flags(bbox) itemconfigure 0 \ -text [string trim [::msgcat::mc "Raise "]] \ -state disabled $flags(bbox) itemconfigure 1 \ -text [string trim [::msgcat::mc "Call "]] \ -state disabled $flags(lentry) configure -state disabled $flags(entry) configure -state disabled } elseif {$flags(my_stack) < $raise} { set flags(bet_or_raise_amount) $raise $flags(bbox) itemconfigure 0 \ -text [string trim [::msgcat::mc "Raise "]] \ -state disabled $flags(bbox) itemconfigure 1 \ -text [::msgcat::mc "Call %s" $call] \ -state normal \ -command [namespace code [list bet $gid call]] $flags(lentry) configure -state disabled $flags(entry) configure -state disabled } else { $flags(bbox) itemconfigure 0 \ -text [string trim [::msgcat::mc "Raise "]] \ -state normal set flags(bet_or_raise_amount) $raise $flags(bbox) itemconfigure 1 \ -text [::msgcat::mc "Call %s" $call] \ -state normal \ -command [namespace code [list bet $gid call]] $flags(lentry) configure -state normal $flags(entry) configure -state normal } } else { # Can't happen } $flags(button_allin) configure -state normal $flags(bbox) itemconfigure 2 -state normal } else { if {$flags(bets) == 0} { $flags(bbox) itemconfigure 0 \ -text [::msgcat::mc "Bet"] \ -state disabled $flags(bbox) itemconfigure 1 \ -text [string trim [::msgcat::mc "Check "]] \ -state disabled } else { $flags(bbox) itemconfigure 0 \ -text [string trim [::msgcat::mc "Raise "]] \ -state disabled $flags(bbox) itemconfigure 1 \ -text [string trim [::msgcat::mc "Call "]] \ -state disabled } $flags(lentry) configure -state disabled $flags(entry) configure -state disabled $flags(button_allin) configure -state disabled $flags(bbox) itemconfigure 2 -state disabled } } proc poker::turn_recv {gid tag xmllist} { variable bytes1 variable $gid upvar 0 $gid flags if {$flags(stop)} { # Return error if the game is terminated return [list error cancel not-acceptable] } switch -- $tag { deck { add_to_log $gid [::msgcat::mc "Received shuffled deck"] switch -- $flags(state) { new { # We are ready to reshuffle and return the deck if {$flags(button)} { return [list error cancel not-acceptable] } } default { # The deck has come not in time. return [list error cancel not-acceptable] } } set deck {} foreach xml $xmllist { ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[string equal $tag card]} { lappend deck [hex2dec [::xmpp::xml::getAttr $attrs msg]] } } add_to_log $gid [::msgcat::mc "Reshuffling deck"] # Saving flags(deck) for checking for cheaters # at the end of the deal set flags(deck) [shuffle $deck] if {[llength $flags(deck)] != 52} { return [list error modify bad-request] } set subelements {} set ekey [ekey $flags(key)] foreach message $flags(deck) { lappend subelements \ [::xmpp::xml::create card \ -attrs [list msg \ [dec2hex [encipher $ekey $message]]]] update # During update many things may happen if {![exists $gid] || $flags(stop)} return } set_state $gid renew add_to_log $gid [::msgcat::mc "Returning reshuffled deck"] return [list result [::xmpp::xml::create deck \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $flags(id)] \ -subelements $subelements]] } redeck { add_to_log $gid [::msgcat::mc "Received reencrypted deck"] switch -- $flags(state) { renew { # We are ready to reshuffle and return the deck if {$flags(button)} { return [list error cancel not-acceptable] } } default { # The deck has come not in time. return [list error cancel not-acceptable] } } set deck {} foreach xml $xmllist { ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[string equal $tag card]} { lappend deck [hex2dec [::xmpp::xml::getAttr $attrs msg]] } } add_to_log $gid [::msgcat::mc "Reencrypting deck"] if {[llength $deck] != 52} { return [list error modify bad-request] } set flags(keys) {} for {set i 0} {$i < 52} {incr i} { lappend flags(keys) [gen_rnd $bytes1] } set subelements {} set flags(deck) {} set dkey [dkey $flags(key)] foreach message $deck key $flags(keys) { set ekey [ekey $key] set message2 [decipher $dkey $message] # Saving flags(deck) for checking for cheaters # at the end of the deal lappend flags(deck) $message2 lappend subelements \ [::xmpp::xml::create card \ -attrs [list msg \ [dec2hex [encipher $ekey $message2]]]] update # During update many things may happen if {![exists $gid] || $flags(stop)} return } set_state $gid preflop-deal add_to_log $gid [::msgcat::mc "Returning doubly reencrypted deck"] return [list result [::xmpp::xml::create redeck \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $flags(id)] \ -subelements $subelements]] } deal { if {$flags(button)} { return [list error cancel not-acceptable] } switch -- $flags(state) { preflop-deal { if {[llength $flags(hole_cards)] > 0} { return [list error cancel not-acceptable] } } flop-deal { if {[llength $flags(flop)] > 0} { return [list error cancel not-acceptable] } } turn-deal { if {[llength $flags(turn)] > 0} { return [list error cancel not-acceptable] } } river-deal { if {[llength $flags(river)] > 0} { return [list error cancel not-acceptable] } } default { return [list error cancel not-acceptable] } } set subelements {} foreach xml $xmllist { ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[string equal $tag card]} { if {![::xmpp::xml::isAttr $attrs seq]} { return [list error cancel not-acceptable] } set seq [::xmpp::xml::getAttr $attrs seq] if {[::xmpp::xml::isAttr $attrs hold]} { set hold [::xmpp::xml::getAttr $attrs hold] } else { set hold false } if {[::xmpp::xml::isAttr $attrs community]} { set community [::xmpp::xml::getAttr $attrs community] } else { set community false } set dkey [dkey [lindex $flags(keys) [expr {$seq - 1}]]] set msg [decipher $dkey \ [hex2dec [::xmpp::xml::getAttr $attrs \ msg]]] if {$community} { lappend subelements \ [::xmpp::xml::create card \ -attrs [list seq $seq \ msg [dec2hex $msg]]] set card [expr {$msg & 0x3f}] lappend flags(ovisible_cards) $seq lappend flags(mvisible_cards) $seq $card switch -- $flags(state) { flop-deal { lappend flags(flop) $card } turn-deal { lappend flags(turn) $card } river-deal { lappend flags(river) $card } default { return [list error cancel not-acceptable] } } } elseif {$hold} { set card [expr {$msg & 0x3f}] lappend flags(mvisible_cards) $seq $card switch -- $flags(state) { preflop-deal { lappend flags(hole_cards) $card } default { return [list error cancel not-acceptable] } } } else { lappend flags(ovisible_cards) $seq lappend subelements \ [::xmpp::xml::create card \ -attrs [list seq $seq \ msg [dec2hex $msg]]] switch -- $flags(state) { preflop-deal {} default { return [list error cancel not-acceptable] } } } } } switch -- $flags(state) { preflop-deal { add_to_log $gid [::msgcat::mc "You got pocket cards: %s" \ [join [lmap x $flags(hole_cards) \ {[namespace current]::num2card $x}] ", "]] set_state $gid preflop } flop-deal { set_state $gid flop } turn-deal { set_state $gid turn } river-deal { set_state $gid river } } return [list result [::xmpp::xml::create deal \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $flags(id)] \ -subelements $subelements]] } bet { ::xmpp::xml::split [lindex $xmllist 0] tag xmlns attrs cdata subels switch -- $flags(state) { preflop - flop - turn - river { if {$flags(bet)} { return [list error cancel not-acceptable] } } default { return [list error cancel not-acceptable] } } set state $flags(state) switch -- $flags(state) { preflop { set newstate flop-deal } flop { set newstate turn-deal } turn { set newstate river-deal } river { set newstate finish } } set flags(bet) [expr {!$flags(bet)}] incr flags(bets) switch -- $tag { call { set call [expr {$flags(my_bet) - $flags(opp_bet)}] incr flags(opp_stack) -$call incr flags(opp_bet) $call draw_bet $gid 0 [::msgcat::mc "Call"] add_to_log $gid [::msgcat::mc "Opponent calls %s" $call] } allin { incr flags(opp_bet) $flags(opp_stack) set flags(opp_stack) 0 set flags(opp_all_in) 1 draw_bet $gid 0 [::msgcat::mc "All-In"] add_to_log $gid [::msgcat::mc "Opponent goes all-in"] } bet - raise { set amount [::xmpp::xml::getAttr $attrs amount] incr flags(opp_stack) -$amount incr flags(opp_bet) $amount draw_bet $gid 0 [::msgcat::mc "Raise"] add_to_log $gid [::msgcat::mc "Opponent raises %s" $amount] } check { draw_bet $gid 0 [::msgcat::mc "Check"] add_to_log $gid [::msgcat::mc "Opponent checks"] } fold { draw_bet $gid 0 [::msgcat::mc "Fold"] draw_bet $gid 1 [::msgcat::mc "Winner"] add_to_log $gid [::msgcat::mc "Opponent folds"] set pot [expr {$flags(my_bet) + $flags(opp_bet)}] incr flags(my_stack) $pot add_to_log $gid [::msgcat::mc "You won pot %s" $pot] set flags(my_bet) 0 set flags(opp_bet) 0 set_state $gid check return [list result {}] } } switch -- $tag { check { if {$flags(bets) % 2 == 0} { if {$newstate eq "finish"} { send_open_cards $gid } set flags(state) $newstate } } call { if {$flags(my_all_in)} { set flags(showdown) 1 send_open_cards $gid } if {$flags(bets) != 1} { if {$newstate eq "finish"} { send_open_cards $gid } set flags(state) $newstate } } allin { # All-In is not always closing if {$flags(my_all_in) || $flags(opp_bet) <= $flags(my_bet)} { set flags(showdown) 1 send_open_cards $gid set flags(state) $newstate } } } if {$flags(state) eq $state} { start_betting $gid } return [list result {}] } open { set flags(opp_hole_cards) {} foreach xml $xmllist { ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[string equal $tag card]} { if {![::xmpp::xml::isAttr $attrs seq]} { return [list error cancel not-acceptable] } set seq [::xmpp::xml::getAttr $attrs seq] set msg [hex2dec [::xmpp::xml::getAttr $attrs msg]] set card [expr {$msg & 0x3f}] lappend flags(mvisible_cards) $seq $card lappend flags(opp_hole_cards) $card } } if {[llength $flags(opp_hole_cards)] != 2} { return [list error cancel not-acceptable] } else { draw_hole_cards $gid add_to_log $gid \ [::msgcat::mc "Opponent revealed pocket cards: %s" \ [join [lmap x $flags(opp_hole_cards) \ {[namespace current]::num2card $x}] ", "]] return [list result {}] } } check { add_to_log $gid [::msgcat::mc "Received deck for checking"] switch -- $flags(state) { check {} default { # The deck has come not in time. return [list error cancel not-acceptable] } } set deck {} foreach {seq card} $flags(mvisible_cards) { lappend deck $card } foreach xml $xmllist { ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[string equal $tag card]} { set seq [::xmpp::xml::getAttr $attrs seq] set dkey [dkey [lindex $flags(keys) [expr {$seq - 1}]]] set msg [decipher $dkey \ [hex2dec [::xmpp::xml::getAttr $attrs \ msg]]] lappend deck [expr {$msg & 0x3f}] } update # During update many things may happen if {![exists $gid] || $flags(stop)} return } set sorted [lsort -integer $deck] if {[llength $deck] != 52 || [llength $sorted] != 52 || \ [lindex $sorted 0] != 0 || [lindex $sorted 51] != 51} { add_to_log $gid [::msgcat::mc "The opponent is cheating"] return [list error cancel not-acceptable] } add_to_log $gid \ [::msgcat::mc "The opponent's deck is checked successfully"] set flags(opp_deck_checked) 1 if {$flags(my_deck_checked)} { set_state $gid new } return [list result {}] } stop { set flags(stop) 1 disable_controls $gid add_to_log $gid [::msgcat::mc "The game is terminated by opponent"] } } } proc poker::draw_deck_and_buttons {gid} { variable board_width variable board_height variable card_width variable card_height variable line_width variable line_pad variable line_margin variable $gid upvar 0 $gid flags set x [expr {$board_width - $line_margin - 4*$line_width - $card_width}] set x1 [expr {$board_width/2 - $card_width - 3*$line_pad/2 - $line_width - $line_margin}] set x2 [expr {$x1 - [image width poker/smallblind] - $line_pad}] if {$flags(button)} { set y [expr {$board_height - $line_margin - $line_width - $line_pad - $card_height}] set y1 [expr {$board_height - $line_margin - $line_width - $line_pad}] set a1 se set a2 ne } else { set y [expr {$line_margin + $line_width + $line_pad}] set y1 [expr {$line_margin + $line_width + $line_pad}] set a1 ne set a2 se } set y2 [expr {$board_height - $y1}] #foreach i {1 2 3 4} { # $flags(board) create image $x $y -anchor nw -image poker/back \ # -tags card # incr x $line_width #} $flags(board) create image $x2 $y1 -anchor $a1 -image poker/button \ -tags button $flags(board) create image $x1 $y1 -anchor $a1 -image poker/smallblind \ -tags chip $flags(board) create image $x1 $y2 -anchor $a2 -image poker/bigblind \ -tags chip } proc poker::draw_bet {gid my {message ""}} { variable board_width variable board_height variable card_width variable card_height variable line_width variable line_pad variable line_margin variable $gid upvar 0 $gid flags if {$my} { set tag my_bet } else { set tag opp_bet } $flags(board) delete $tag if {$message eq ""} return set font {Arial 20 bold} set x [expr {$board_width/2}] set y [expr {$line_margin + $line_width + $line_pad + $card_height/2}] if {$my} { set y [expr {$board_height - $y}] } for {set i 0} {$i < 16} {incr i} { set x1 [expr {$x + 4*cos(3.141592*$i/8)}] set y1 [expr {$y + 4*sin(3.141592*$i/8)}] $flags(board) create text $x1 $y1 -text $message -font $font \ -tags [list bet $tag] -fill black } $flags(board) create text $x $y -text $message -font $font \ -tags [list bet $tag] -fill white } proc poker::set_state {gid state} { after idle [list [namespace current]::set_state_aux $gid $state] } proc poker::set_state_aux {gid state} { variable $gid upvar 0 $gid flags set flags(state) $state } proc poker::on_state_change {gid args} { variable bytes1 variable $gid upvar 0 $gid flags # This proc is called from after command, so checking the game existence if {![exists $gid]} return #add_to_log $gid [::msgcat::mc "New state %s" $flags(state)] switch -- $flags(state) { new { if {$flags(my_stack) <= 0} { add_to_log $gid [::msgcat::mc "You lost all chips"] add_to_log $gid [::msgcat::mc "The game is finished"] disable_controls $gid return } if {$flags(opp_stack) <= 0} { add_to_log $gid [::msgcat::mc "Opponent lost all chips"] add_to_log $gid [::msgcat::mc "The game is finished"] disable_controls $gid return } $flags(board) delete card||button||chip||hand||bet if {$flags(deals) == 0} { set flags(button) $flags(deal_first) } else { set flags(button) [expr {!$flags(button)}] } draw_deck_and_buttons $gid incr flags(deals) add_to_log $gid [::msgcat::mc "Starting deal %s" $flags(deals)] add_to_log $gid [::msgcat::mc "Your stack is %s" $flags(my_stack)] add_to_log $gid \ [::msgcat::mc "Opponent's stack is %s" $flags(opp_stack)] if {($flags(deals) % $flags(double_blinds)) == 0} { set flags(small_blind) [expr {2*$flags(small_blind)}] set flags(big_blind) [expr {2*$flags(big_blind)}] } add_to_log $gid \ [::msgcat::mc "Small blind is %s" $flags(small_blind)] add_to_log $gid [::msgcat::mc "Big blind is %s" $flags(big_blind)] set flags(my_deck_checked) 0 set flags(opp_deck_checked) 0 set flags(dealer) \ [expr {$flags(button) ? [::msgcat::mc "You"] : [::msgcat::mc "Opponent"]}] set flags(bet_or_raise_amount) $flags(big_blind) set flags(key) [gen_rnd $bytes1] set flags(deck) {} set flags(hole_cards) {} set flags(opp_hole_cards) {} set flags(flop) {} set flags(turn) {} set flags(river) {} # Cards visible by me in form 'seq' 'card' set flags(mvisible_cards) {} # Cards visible by the opponent (only sequence numbers) set flags(ovisible_cards) {} set flags(my_all_in) 0 set flags(opp_all_in) 0 set flags(showdown) 0 if {$flags(button)} { set my_bet $flags(small_blind) set my_bet_name [::msgcat::mc "small blind"] set opp_bet $flags(big_blind) set opp_bet_name [::msgcat::mc "big blind"] set flags(bet) 1 } else { set my_bet $flags(big_blind) set my_bet_name [::msgcat::mc "big blind"] set opp_bet $flags(small_blind) set opp_bet_name [::msgcat::mc "small blind"] set flags(bet) 0 } if {$flags(my_stack) <= $my_bet} { set flags(my_bet) $flags(my_stack) set flags(my_stack) 0 set flags(my_all_in) 1 draw_bet $gid 1 [::msgcat::mc "All-In"] set flags(bet) 0 add_to_log $gid \ [::msgcat::mc "You have to go all-in (stack equals %s)" \ $flags(my_bet)] } else { set flags(my_bet) $my_bet set flags(my_stack) [expr {$flags(my_stack) - $my_bet}] add_to_log $gid \ [::msgcat::mc "You bet %s equals to %s" \ $my_bet_name $my_bet] } if {$flags(opp_stack) <= $opp_bet} { set flags(opp_bet) $flags(opp_stack) set flags(opp_stack) 0 set flags(opp_all_in) 1 draw_bet $gid 0 [::msgcat::mc "All-In"] if {!$flags(my_all_in)} { set flags(bet) 1 } add_to_log $gid \ [::msgcat::mc "Opponent has to go all-in (stack\ equals %s)" $flags(opp_bet)] } else { set flags(opp_bet) $opp_bet set flags(opp_stack) [expr {$flags(opp_stack) - $opp_bet}] add_to_log $gid \ [::msgcat::mc "Opponent bets %s equals to %s" \ $opp_bet_name $opp_bet] } set flags(bets) 0 if {$flags(button)} { add_to_log $gid [::msgcat::mc "Shuffling deck"] send_deck $gid } else { add_to_log $gid [::msgcat::mc "Waiting for shuffled deck"] } } preflop-deal { if {$flags(button)} { send_hole_cards $gid } } preflop { draw_hole_cards $gid if {$flags(my_all_in) && ($flags(my_bet) <= $flags(opp_bet))} { # Opponent automagically calls set flags(showdown) 1 send_open_cards $gid } elseif {$flags(opp_all_in) && ($flags(opp_bet) <= $flags(my_bet))} { # Me automagically call set flags(showdown) 1 send_open_cards $gid } else { if {$flags(button)} { set flags(bet) 1 } else { set flags(bet) 0 } set flags(bets) 0 start_betting $gid } } flop-deal { if {$flags(button)} { if {$flags(showdown)} { set delay 4000 } else { set delay 0 } after $delay [namespace code [list send_community_cards \ $gid {5 6 7}]] } if {!$flags(showdown)} { # Erasing the previous bets draw_bet $gid 0 draw_bet $gid 1 } } flop { draw_flop $gid add_to_log $gid \ [::msgcat::mc "Flop is dealt: %s" \ [join [lmap x $flags(flop) \ {[namespace current]::num2card $x}] ", "]] draw_best_hand $gid if {$flags(showdown)} { set_state $gid turn-deal } else { if {$flags(button)} { set flags(bet) 0 } else { set flags(bet) 1 } set flags(bets) 0 start_betting $gid } } turn-deal { if {$flags(button)} { if {$flags(showdown)} { set delay 4000 } else { set delay 0 } after $delay [namespace code [list send_community_cards \ $gid {8}]] } if {!$flags(showdown)} { # Erasing the previous bets draw_bet $gid 0 draw_bet $gid 1 } } turn { draw_turn $gid add_to_log $gid [::msgcat::mc "Turn is dealt: %s" \ [join [lmap x $flags(turn) \ {[namespace current]::num2card $x}] ", "]] draw_best_hand $gid if {$flags(showdown)} { set_state $gid river-deal } else { if {$flags(button)} { set flags(bet) 0 } else { set flags(bet) 1 } set flags(bets) 0 start_betting $gid } } river-deal { if {$flags(button)} { if {$flags(showdown)} { set delay 4000 } else { set delay 0 } after $delay [namespace code [list send_community_cards \ $gid {9}]] } if {!$flags(showdown)} { # Erasing the previous bets draw_bet $gid 0 draw_bet $gid 1 } } river { draw_river $gid add_to_log $gid [::msgcat::mc "River is dealt: %s" \ [join [lmap x $flags(river) \ {[namespace current]::num2card $x}] ", "]] draw_best_hand $gid if {$flags(showdown)} { set_state $gid finish } else { if {$flags(button)} { set flags(bet) 0 } else { set flags(bet) 1 } set flags(bets) 0 start_betting $gid } } finish { disable_controls $gid $flags(bbox) itemconfigure 3 -state normal if {[llength $flags(opp_hole_cards)] != 2} { # Waiting for opponent's cards after 1000 [list [namespace current]::on_state_change $gid] } else { set my_hand [select_best_hand [concat $flags(hole_cards) \ $flags(flop) \ $flags(turn) \ $flags(river)]] set opp_hand [select_best_hand [concat $flags(opp_hole_cards) \ $flags(flop) \ $flags(turn) \ $flags(river)]] set my_score [score $my_hand] set opp_score [score $opp_hand] add_to_log $gid \ [::msgcat::mc "Your best hand is %s (%s)" \ [join [lmap x $my_hand \ {[namespace current]::num2card $x}] ", "] \ [score2msg $my_hand]] add_to_log $gid \ [::msgcat::mc "Opponent's best hand is %s (%s)" \ [join [lmap x $opp_hand \ {[namespace current]::num2card $x}] ", "] \ [score2msg $opp_hand]] if {$my_score > $opp_score} { draw_bet $gid 0 "" draw_bet $gid 1 [::msgcat::mc "Winner"] if {$flags(my_bet) >= $flags(opp_bet)} { add_to_log $gid \ [::msgcat::mc "You won pot %s" \ [expr {$flags(my_bet) + $flags(opp_bet)}]] set flags(my_stack) \ [expr {$flags(my_stack) + $flags(my_bet) + $flags(opp_bet)}] } else { add_to_log $gid [::msgcat::mc "You won pot %s" \ [expr {2*$flags(my_bet)}]] add_to_log $gid \ [::msgcat::mc "Opponent won side pot %s" \ [expr {$flags(opp_bet) - $flags(my_bet)}]] set flags(my_stack) \ [expr {$flags(my_stack) + 2*$flags(my_bet)}] set flags(opp_stack) \ [expr {$flags(opp_stack) + $flags(opp_bet) - $flags(my_bet)}] } } elseif {$my_score < $opp_score} { draw_bet $gid 1 "" draw_bet $gid 0 [::msgcat::mc "Winner"] if {$flags(opp_bet) >= $flags(my_bet)} { add_to_log $gid [::msgcat::mc "Opponent won pot %s" \ [expr {$flags(my_bet) + $flags(opp_bet)}]] set flags(opp_stack) \ [expr {$flags(opp_stack) + $flags(my_bet) + $flags(opp_bet)}] } else { add_to_log $gid [::msgcat::mc "Opponent won pot %s" \ [expr {2*$flags(opp_bet)}]] add_to_log $gid [::msgcat::mc "You won side pot %s" \ [expr {$flags(my_bet) - $flags(opp_bet)}]] set flags(opp_stack) \ [expr {$flags(opp_stack) + 2*$flags(opp_bet)}] set flags(my_stack) \ [expr {$flags(my_stack) + $flags(my_bet) - $flags(opp_bet)}] } } else { draw_bet $gid 0 [::msgcat::mc "Split"] draw_bet $gid 1 [::msgcat::mc "Split"] add_to_log $gid \ [::msgcat::mc "You and opponent split pot %s" \ [expr {$flags(my_bet) + $flags(opp_bet)}]] set flags(my_stack) \ [expr {$flags(my_stack) + $flags(my_bet)}] set flags(opp_stack) \ [expr {$flags(opp_stack) + $flags(opp_bet)}] } set flags(my_bet) 0 set flags(opp_bet) 0 set_state $gid check } } check { disable_controls $gid $flags(bbox) itemconfigure 3 -state normal add_to_log $gid [::msgcat::mc "Checking decks"] after 4000 [namespace code [list check_deck $gid]] } } } proc poker::check_deck {gid} { variable $gid upvar 0 $gid flags # This proc is called from after command, so checking the game existence if {![exists $gid]} return set subels {} set seq 1 foreach card $flags(deck) { if {[lsearch -exact $flags(ovisible_cards) $seq] < 0} { if {$flags(button)} { set dkey [dkey [lindex $flags(keys) [expr {$seq - 1}]]] set msg [dec2hex [decipher $dkey $card]] } else { set msg [dec2hex $card] } lappend subels [::xmpp::xml::create card \ -attrs [list seq $seq \ msg $msg]] update # During update many things may happen if {![exists $gid] || $flags(stop)} return } incr seq } add_to_log $gid [::msgcat::mc "Sending unencrypted deck for checking"] ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create check \ -xmlns games:cards \ -attrs [list type poker:th:1 \ id $flags(id)] \ -subelements $subels] \ -to $flags(opponent) \ -command [namespace code [list check_deck_result $gid]] add_to_log $gid [::msgcat::mc "Waiting for checked deck"] } proc poker::check_deck_result {gid status xml} { variable $gid upvar 0 $gid flags if {![string equal $status ok]} { # TODO add_to_log $gid [::msgcat::mc "Opponent thinks that you cheat"] return } set flags(my_deck_checked) 1 if {$flags(opp_deck_checked)} { set flags(state) new } } proc poker::gen_rnd {bytes} { variable prime1 # TODO: Support for other MODP groups set num 0 for {set i 0} {$i < $bytes} {incr i 8} { set num [expr {$num * (16**8) + int((16**8) * rand())}] } return [expr {$num % $prime1}] } proc poker::dec2hex {num} { return [format %llx $num] } proc poker::hex2dec {num} { return [expr 0x$num] } proc poker::shuffle {deck} { set deck1 {} foreach card $deck { lappend deck1 [list $card [expr {rand()}]] } set deck2 {} foreach card [lsort -real -index 1 $deck1] { lappend deck2 [lindex $card 0] } return $deck2 } proc poker::egcd {a b} { set r [expr {$a % $b}] if {$r == 0} { return {0 1} } else { lassign [egcd $b $r] x y return [list $y [expr {$x - $y * ($a / $b)}]] } } proc poker::exp {a n p} { # a**n (mod p) set b 1 while {$n > 0} { if {$n % 2 == 0} { set n [expr {$n / 2}] set a [expr {($a * $a) % $p}] } else { incr n -1 set b [expr {($b * $a) % $p}] } } return $b } proc poker::ekey {key} { variable prime1 variable generator1 exp $generator1 $key $prime1 } proc poker::encipher {ekey message} { variable prime1 expr {($message * $ekey) % $prime1} } proc poker::dkey {key} { variable prime1 variable generator1 variable generatorm1 if {![info exists generatorm1]} { lassign [egcd $prime1 $generator1] x y set generatorm1 [expr {$y % $prime1}] } exp $generatorm1 $key $prime1 } proc poker::decipher {dkey message} { variable prime1 expr {($message * $dkey) % $prime1} } proc poker::select_best_hand {cards} { switch -- [llength $cards] { 5 { return $cards } 6 { set score 0 set hand {} for {set i 0} {$i < 6} {incr i} { set h [lreplace $cards $i $i] set s [score $h] if {$s > $score} { set score $s set hand $h } } return $hand } 7 { set score 0 set hand {} for {set i 0} {$i < 7} {incr i} { for {set j [expr {$i + 1}]} {$j < 7} {incr j} { set h [lreplace [lreplace $cards $j $j] $i $i] set s [score $h] if {$s > $score} { set score $s set hand $h } } } return $hand } default { return -code error } } } proc poker::score2msg {hand} { set score [score $hand] if {$score >= 9*16**7} { return [::msgcat::mc "Royal flush"] } if {$score >= 8*16**7} { return [::msgcat::mc "Straight flush"] } if {$score >= 7*16**7} { return [::msgcat::mc "Four of a kind"] } if {$score >= 6*16**7} { return [::msgcat::mc "Full house"] } if {$score >= 5*16**7} { return [::msgcat::mc "Flush"] } if {$score >= 4*16**7} { return [::msgcat::mc "Straight"] } if {$score >= 3*16**7} { return [::msgcat::mc "Three of a kind"] } if {$score >= 2*16**7} { return [::msgcat::mc "Two pairs"] } if {$score >= 1*16**7} { return [::msgcat::mc "Pair"] } if {$score >= 14*16**4} { return [::msgcat::mc "Ace"] } if {$score >= 13*16**4} { return [::msgcat::mc "King"] } if {$score >= 12*16**4} { return [::msgcat::mc "Queen"] } if {$score >= 11*16**4} { return [::msgcat::mc "Jack"] } if {$score >= 10*16**4} { return [::msgcat::mc "Ten"] } if {$score >= 9*16**4} { return [::msgcat::mc "Nine"] } if {$score >= 8*16**4} { return [::msgcat::mc "Eight"] } if {$score >= 7*16**4} { return [::msgcat::mc "Seven"] } # Couldn't reach here return "" } proc poker::score {hand} { # hand is a list of numbers 0 <= num < 52 set pips {} set suits {} foreach num $hand { lappend pips [expr {$num / 4 + 2}] lappend suits [expr {$num % 4}] } set pips [lsort -integer $pips] lassign $pips c0 c1 c2 c3 c4 set straight \ [expr {($c0==$c1-1 && $c1==$c2-1 && $c2==$c3-1 && $c3==$c4-1) || ($c4==14 && $c0==2 && $c1==3 && $c2==4 && $c3==5)}] # score could be 0xeeeed max (4 Aces and King) set score [expr {(((($c4*16) + $c3)*16 + $c2)*16 + $c1)*16 + $c0}] if {$straight && $c4==14 && $c3==5} { set score [expr {(((($c3*16) + $c2)*16 + $c1)*16 + $c0)*16 + $c4}] } lassign [lsort $suits] s0 s1 s2 s3 s4 set flush [expr {$s0 eq $s4}] if {$straight == 1 && $flush && $c0 == 10} { # Royal flush return [expr {9*16**7}] } if {$straight == 1 && $flush} { # Straight flush return [expr {8*16**7 + $score}] } if {$c0 == $c3 || $c1 == $c4} { # Four of a kind return [expr {7*16**7 + $c3*16**6 + $score}] } if {$c0 == $c1 && $c2 == $c4} { # Full house return [expr {6*16**7 + $c4*16**6 + $score}] } if {$c0 == $c2 && $c3 == $c4} { # Full house return [expr {6*16**7 + $c2*16**6 + $score}] } if {$flush} { # Flush return [expr {5*16**7 + $score}] } if {$straight} { # Straight return [expr {4*16**7 + $score}] } if {$c0 == $c2 || $c1 == $c3 || $c2 == $c4} { # Three of a kind return [expr {3*16**7 + $c2*16**6 + $score}] } if {$c0 == $c1 && $c2 == $c3} { # Two pairs return [expr {2*16**7 + $c3*16**6 + $c1*16**5 + $score}] } if {$c0 == $c1 && $c3 == $c4} { # Two pairs return [expr {2*16**7 + $c4*16**6 + $c1*16**5 + $score}] } if {$c1 == $c2 && $c3 == $c4} { # Two pairs return [expr {2*16**7 + $c4*16**6 + $c1*16**5 + $score}] } if {$c0 == $c1} { # Pair return [expr {1*16**7 + $c1*16**6 + $score}] } if {$c1 == $c2} { # Pair return [expr {1*16**7 + $c2*16**6 + $score}] } if {$c2 == $c3} { # Pair return [expr {1*16**7 + $c3*16**6 + $score}] } if {$c3 == $c4} { # Pair return [expr {1*16**7 + $c4*16**6 + $score}] } return $score } proc poker::num2card {num} { # 0 <= num < 52 set pip [string map {10 T 11 J 12 Q 13 K 14 A} [expr {$num / 4 + 2}]] set suit [string map {0 C 1 D 2 H 3 S} [expr {$num % 4}]] return $pip$suit } proc poker::card2num {card} { lassign [split $card ""] pip suit set pip [string map {T 10 J 11 Q 12 K 13 A 14} $pip] set suit [string map {C 0 D 1 H 2 S 3} $suit] return [expr {($pip - 2) * 4 + $suit}] } proc poker::add_groupchat_user_menu_item {m xlib jid} { set mm $m.gamesmenu if {![winfo exists $mm]} { menu $mm -tearoff 0 $m add cascade -label [::msgcat::mc "Games"] -menu $mm } $mm add command -label [::msgcat::mc "Poker..."] \ -command [list [namespace current]::invite_dialog $xlib $jid] } proc poker::iq_create {varname xlib from iqid xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[::xmpp::xml::getAttr $attrs type] eq "poker:th:1"} { set modps {} foreach subel $subels { ::xmpp::xml::split $subel stag sxmlns sattrs scdata ssubels if {$sxmlns eq "http://jabber.org/protocol/feature-neg"} { lassign [::xmpp::data::findForm $ssubels] type form set fields [::xmpp::data::parseForm $form] foreach {tag field} $fields { switch -- $tag { field { lassign $field var type label desc required \ options values media if {[string equal $var modp]} { foreach {olabel ovalue} $options { lappend modps $ovalue } } } } } } } # TODO: Support of other MODP groups if {[lsearch -exact $modps 1] < 0} { set var [list error cancel not-acceptable] return } if {[::xmpp::xml::isAttr $attrs deal]} { set deal [::xmpp::xml::getAttr $attrs deal] switch -- $deal { true - false { } 1 { set deal true } 0 { set deal false } default { set var [list error modify bad-request] } } } else { set deal true } # TODO: Support of other MODP groups set var [invited_dialog $xlib $from $iqid \ [::xmpp::xml::getAttr $attrs id] \ $deal 1] } return } proc poker::iq_turn {varname xlib from xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[::xmpp::xml::getAttr $attrs type] == "poker:th:1"} { set gid [make_gid $from [::xmpp::xml::getAttr $attrs id]] if {[exists $gid]} { set var [turn_recv $gid $tag $subels] } else { set var [list error cancel item-not-found] } } return } # Common games:cards part proc iq_games_cards_create {xlib from xml args} { set res [list error cancel feature-not-implemented] set iqid [::xmpp::xml::getAttr $args -id] hook::run games_cards_create_hook res $xlib $from $iqid $xml return $res } proc iq_games_cards_turn {xlib from xml args} { set res [list error cancel feature-not-implemented] hook::run games_cards_turn_hook res $xlib $from $xml return $res } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/poker/proto000064400000000000000000000245671500237002100157350ustar00nobodynobodyTODO: describe betting. Request: games:cards:dn Here, the form contains the only field: the list of Modular Exponential (MODP) group numbers (as specified in RFC 2409 or RFC 352) which can be used for encrypting cards dealing. The only required group is 1 (it is the only group which is supported currently). Positive response: games:cards:dn 1 After the MODP group is chosen, both parties generate random keys (key1 and key2). After that the dealer must shuffle the deck, encode cards in the following way: 2C -> 0 2D -> 1 2H -> 2 2S -> 3 3C -> 4 3D -> 5 3H -> 6 3S -> 7 4C -> 8 ... KS -> 47 AC -> 48 AD -> 49 AH -> 50 AS -> 51 and encrypts the shuffled deck using the following 2 stage algorithm: Stage1 For every card C0--C51 a new random number R0--R51 is generated and forms the message to encrypt: Mi = ((Ri & ~0x3F) | Ci). Then the encrypted message MSGi = Mi * g^key1 (here * and ^ are operations in a chosen groups, and g is a group generator) is generated. Then the encrypted deck is sent to the other player encoded in hexadecimal notation to save a bit of bandwidth: ... ... The player who received the list encrypted messages (each of which corresponds to some card) shuffles them and encrypts again using its key key2: MSG2i = MSGi * g^key2 (here * and ^ are operations in a chosen groups, and g is a group generator). The doubly encrypted messages are returned in IQ result stanza: ... ... Stage2 For every shuffled and doubly encrypted card C0--C51 a new random key KA0--KA51 is generated and the encrypted message MSG3i = MSG2i * g^KAi *g^(-key1) (here * and ^ are operations in a chosen groups, and g is a group generator) is generated. Then the reencrypted deck is sent to the other player encoded in hexadecimal notation: ... ... The player who received the list encrypted messages (each of which corresponds to some card) generates a new set of keys KB0--KB51 and encrypts the messages again using individual keys and key2: MSG4i = MSG3i * g^KBi * g^(-key2) (here * and ^ are operations in a chosen groups, and g is a group generator). The messages, which are now doubly encrypted with individual keys, are returned in IQ result stanza: ... ... When dealing hole cards the dealer chooses 4 doubly encrypted card messages, decrypts two of them using his individual keys (MSG3i = MSG2i * g^(-KAi)) and sends all four cards to the other player: Then the player who received the cards deciphers all 4 cards using the corresponding keys KBi, keeps 6 least significant bits for cards with hold='true' and returns the other two to the dealer: The dealer decrypts them using keys KAi and keeps 6 lowest bits as card numbers. This way all parties have their cards and no party knows the other player's cards. The cipher commutativity was used to achieve the goal. If it's necessary to deal community cards then they are dealt with community='true', and the dealer decrypts the messages before sending a message. The other player decrypts and returns them, so, both parties know the cards: The following examples give possible bets. 1) Check: 2) Call: 3) Bet: 4) Raise: 5) All-in: If the bet is illegal (e.g. amount is insufficient) the opponent returns an error, otherwise he returns a simple IQ result stanza. If a player wants (or have to) show his pocket cards to the opponent he should use the following stanza: where msg attribute contains UNENCRYPTED card values. After the deal play is finished, the dealer takes all cards which weren't shown to him, also decrypts all cards which weren't shown to the other player and send both bunches to him to perform consistency check: ... The other player decrypts all of them and checks if the all cards are present and present only once. If the check is successful then the result is returned, including the decyphered cards (with hold='false'): ... and the next deal may be played. Otherwise the error is returned: and since dealer is considered to be a cheater the game is stopped. If the dealer finds cheating then it responds by error to the next deck, and the game is stopped. Both players are allowed to stop the game at any moment. To do that the following stanza is to be sent: After this stanza current game must be terminated and the usual deck checking procedure is to be performed. tkabber-plugins/presencecmd000075500000000000000000000000001500237002100157225ustar00nobodynobodytkabber-plugins/presencecmd/AUTHORS000064400000000000000000000000661500237002100170530ustar00nobodynobodyKonstantin Khomoutov tkabber-plugins/presencecmd/INSTALL000064400000000000000000000005021500237002100170270ustar00nobodynobodyAs usual, copy this directory under the ~/.tkabber/plugins directory so that you get a hierarchy like this: ~/.tkabber/plugins ~/.tkabber/plugins/presencecmd/ ~/.tkabber/plugins/presencecmdv/presencecmd.tcl Restart Tkabber, to get the plugin loaded. Consult the README file for the details about using this plugin. tkabber-plugins/presencecmd/README000064400000000000000000000074231500237002100166670ustar00nobodynobody"Presence command" chat plugin for Tkabber. I. The idea. This plugin provides additional set of what are called "IRC-style chat commands" in Tkabber -- specially formatted messages which are recognized as commands to Tkabber. They are parsed and executed, then their text is thrown away (widely known examples of standard chat commands are: /clear, /nick, /ban, /leave, etc). Provided commands are: * /presence allows to change "master" (i.e. basic, main, global) presence of the user [1]; * /chatpresence (or its alias /thispresence) allows to change the presence in this chat session (which may be a MUC room) only, in other words it sends what is called "directed presence" to the chat peer or room [2]. (See also "Notes" section below.) II. Usage. Both commands have identical syntax and they behave identically -- changes only the presence they operate on. The formal syntax is: /presence ?presence|clear[status]? ?status message? Fields surrounded by "?" represent optional parts, so does text in [...]. "|" specifies alteration (a set of mutually exclusive options). Note that while both presence and status message fields are marked optional at least one of them MUST appear. Otherwise the command has no sense and the usage info is shown in the chat log window. The presence field may have this (standard) values, literally: * available -- user is available; * avail -- shortcut for "available"; * away -- user is away; * xa -- user is extended away; * dnd -- user doesn't want to be disturbed; * chat -- user is free for chat. Note that there's currently no support for "unavailable" presence. The special value of the presence field is "clearstatus" ("clear" is a shortcut to it). When spceified, the status message is set to the empty string; the presence itself isn't changed. (See also section "Notes" below.) The status message field may be used to provide status message for the presence. Any text, on a new line after the command (and the presence value, if specified) is treated as the status message, so it can span multiple lines and have empty lines in between. The only transformation that is applied to the status message is removal of any leading and trailing whitespace. Any of this fields both) may be omitted. In this case the current value for the omitted field is kept intact. III. Examples: Set the "do not disturb" master presence: /presence dnd Set the "free to chat" presence with a fancy status message: /presence chat Hey girls! Just change the status message while keeping the presence intact: /presence To be, or not to be -- That is the question. Send directed presence to the chat peer (or to the room you're in): /chatpresence xa Gone shopping Just change the status message seen by the chat peer (or in the room): /thispresence Gone nuts emerging ebuilds IV. Notes. 1. You should understand that directed presence is somewhat odd in its behaviour to many (not to say most) users: any change in master presence invalidates any directed presences which were set before. In other words if you set, say, "dnd" presence in some MUC room and then change your master presence to "chat", this one will be broadcasted to that room also changing your presence there to "chat". 2. Oddly enough, but currently there's no easy way in Tkabber to sent *really* empty status message: if Tkabber is told to send one it replaces it with the "canonical" spelling of the presence being set in your locale. I.e. when you set the available presence with the empty status message and have an English locale, Tkabber will cook the "Available" status message for you. This is done so that presence stanzas can be PGP-signed, if PGP encryption is enabled. V. References: 1. http://www.xmpp.org/rfcs/rfc3921.html#presence 2. http://www.xmpp.org/rfcs/rfc3921.html#presence-resp-directed vim:et:ts=4:sw=4:tw=64 tkabber-plugins/presencecmd/TODO000064400000000000000000000001261500237002100164700ustar00nobodynobodyHIGH: LOW: * Write provide ChangeLog and VERSION files. * Russian message catalog. tkabber-plugins/presencecmd/VERSION000064400000000000000000000000221500237002100170430ustar00nobodynobody0.2, 14-July-2007 tkabber-plugins/presencecmd/license.terms000064400000000000000000000021121500237002100204730ustar00nobodynobodyCopyright (c) 2007 Konstantin Khomoutov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tkabber-plugins/presencecmd/msgs000075500000000000000000000000001500237002100166735ustar00nobodynobodytkabber-plugins/presencecmd/msgs/de.msg000064400000000000000000000024331500237002100200540ustar00nobodynobody# de.msg -- # # German messages for the Presence command Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 13.11.2010 ::msgcat::mcset de "Unknown presence \"%s\". Must be avail\[able\], away, xa,\ dnd, chat or clear\[status\]" "Unbekannte Präsenz \"%s\". Erlaubt sind\ avail\[able\], away, xa, dnd, chat oder clear\[status\]." ::msgcat::mcset de "Usage: \t/presence ?presence|clear\[status\]?\n \t?status\ message?\n or\n \t/chatpresence ?presence|clear\[status\]?\n \t?status\ message?\n Where presence is one of: avail\[able\], away, xa, dnd,\ chat.\n Special presence \"clear\[status\]\" just clears the current\ status.\n /thispresence is an alias for /chatpresence" \ "Benutzung:\t/presence ?presence|clear\[status\]?\n\ \t\t?Status-Nachricht?\n oder:\n \t\t/chatpresence\ ?presence|clear\[status\]?\n \t\t?Status-Nachricht?\n\n Wobei\ 'presence' eines der folgenden ist: avail\[able\], away, xa, dnd,\ chat.\n Die spezielle Präsenz 'clear\[status\]' setzt den derzeitigen\ Status zurück.\n ('/thispresence' ist ein Alias für '/chatpresence')" ::msgcat::mcset de "Whether the Presencecmd plugin is loaded." \ "Präsenz-Befehle-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/presencecmd/msgs/es.msg000064400000000000000000000021351500237002100200720ustar00nobodynobody# es.msg -- # # Spanish messages for the Presence command Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "Unknown presence \"%s\". Must be avail\[able\], away, xa,\ dnd, chat or clear\[status\]" "Presencia desconocida \"%s\". Debe ser:\ avail\[able\], away, xa, dnd, chat o clear\[status\]" ::msgcat::mcset es "Usage: \t/presence ?presence|clear\[status\]?\n \t?status\ message?\n or\n \t/chatpresence ?presence|clear\[status\]?\n \t?status\ message?\n Where presence is one of: avail\[able\], away, xa, dnd,\ chat.\n Special presence \"clear\[status\]\" just clears the current\ status.\n /thispresence is an alias for /chatpresence" "Modo de uso:\ \t/presence ?presence|clear\[status\]?\n \t?status message?\n or\n\ \t/chatpresence ?presence|clear\[status\]?\n \t?status message?\n\ Donde presence es uno de estos: avail\[able\], away, xa, dnd,\ chat.\n La presencia especial \"clear\[status\]\" simplemente limpia\ el estado actual.\n /thispresence es un alias de /chatpresence" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/presencecmd/msgs/pl.msg000064400000000000000000000026141500237002100201000ustar00nobodynobody# pl.msg -- # # Polish messages for the Presence command Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Unknown presence \"%s\". Must be avail\[able\], away, xa,\ dnd, chat or clear\[status\]" "Nieznany status \"%s\". PrawidÅ‚owe\ wartoÅ›ci to avail\[able\], away, xa, dnd, chat lub clear\[status\]" ::msgcat::mcset pl "Usage: \t/presence ?presence|clear\[status\]?\n\ \t?status message?\n\ or\n\ \t/chatpresence ?presence|clear\[status\]?\n\ \t?status message?\n\ Where presence is one of: avail\[able\], away, xa, dnd,\ chat.\n\ Special presence \"clear\[status\]\" just clears the\ current status.\n\ /thispresence is an alias for /chatpresence" \ "Użycie: \t/presence ?presence|clear\[status\]?\n\ \t?opis statusu?\n\ lub\n \t/chatpresence ?presence|clear\[status\]?\n\ \t?opis statusu?\n\ gdzie presence jest jednym z: avail\[able\], away, xa,\ dnd, chat.\n\ Status specjalny \"clear\[status\]\" tylko czyÅ›ci aktualny\ status.\n\ /thispresence jest aliasem dla /chatpresence" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/presencecmd/msgs/ru.msg000064400000000000000000000033211500237002100201070ustar00nobodynobody# ru.msg -- # # Russian messages for the Presence command Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Unknown presence \"%s\". Must be avail\[able\], away, xa,\ dnd, chat or clear\[status\]" "ÐеизвеÑтное приÑутÑтвие \"%s\". Должно\ быть avail\[able\], away, xa, dnd, chat или clear\[status\]" ::msgcat::mcset ru "Usage: \t/presence ?presence|clear\[status\]?\n\ \t?status message?\n\ or\n\ \t/chatpresence ?presence|clear\[status\]?\n\ \t?status message?\n\ Where presence is one of: avail\[able\], away, xa,\ dnd, chat.\n\ Special presence \"clear\[status\]\" just clears the\ current status.\n\ /thispresence is an alias for /chatpresence" \ "СинтакÑиÑ: \t/presence ?presence|clear\[status\]?\n\ \t?ÑтатуÑное Ñообщение?\n\ или\n\ \t/chatpresence ?presence|clear\[status\]?\n\ \t?ÑтатуÑное Ñообщение?\n\ Где presence - одно из: avail\[able\], away, xa, dnd,\ chat.\n\ ОÑобое приÑутÑтвие \"clear\[status\]\" очищает ÑтатуÑное\ Ñообщение.\n\ /thispresence ÑвлÑетÑÑ Ñинонимом /chatpresence" ::msgcat::mcset ru "Whether the Presencecmd plugin is loaded." \ "Загружено ли раÑширение Presencecmd." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/presencecmd/msgs/uk.msg000064400000000000000000000033071500237002100201040ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Presence command Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Unknown presence \"%s\". Must be avail\[able\], away, xa,\ dnd, chat or clear\[status\]" "Ðевідома приÑутніÑть \"%s\". Має бути\ avail\[able\], away, xa, dnd, chat або clear\[status\]" ::msgcat::mcset uk "Usage: \t/presence ?presence|clear\[status\]?\n\ \t?status message?\n\ or\n\ \t/chatpresence ?presence|clear\[status\]?\n\ \t?status message?\n\ Where presence is one of: avail\[able\], away, xa,\ dnd, chat.\n\ Special presence \"clear\[status\]\" just clears the\ current status.\n\ /thispresence is an alias for /chatpresence" \ "СинтакÑиÑ: \t/presence ?presence|clear\[status\]?\n\ \t?ÑтатуÑне повідомленнÑ?\n\ або\n\ \t/chatpresence ?presence|clear\[status\]?\n\ \t?ÑтатуÑне повідомленнÑ?\n\ Де presence - одне з: avail\[able\], away, xa, dnd,\ chat.\n\ ОÑоблива приÑутніÑть \"clear\[status\]\" очищає ÑтатуÑне\ повідомленнÑ.\n\ /thispresence Ñ” Ñинонімом /chatpresence" ::msgcat::mcset uk "Whether the Presencecmd plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Presencecmd." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/presencecmd/presencecmd.tcl000064400000000000000000000107051500237002100210000ustar00nobodynobody# presencecmd.tcl -- # # "Presence commands" -- Tkabber chat plugin. # Provides two IRC-style chat commands that provide # for manipulating user's presence and/or assotiated status message # as well as sending directed presence to the chat peer (or room). # # Author: Konstantin Khomoutov # # See license.terms for details on distribution. # See INSTALL and README for details on installation and usage. package require msgcat namespace eval presencecmd { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered presencecmd]} { ::plugins::register presencecmd \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Presencecmd plugin\ is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } } proc presencecmd::load {} { hook::add generate_completions_hook [namespace current]::command_comps hook::add chat_send_message_hook [namespace current]::handle_command 15 } proc presencecmd::unload {} { hook::remove generate_completions_hook [namespace current]::command_comps hook::remove chat_send_message_hook [namespace current]::handle_command 15 } proc presencecmd::command_comps {chatid compsvar wordstart line} { upvar 0 $compsvar comps if {!$wordstart} { lappend comps {/presence } {/chatpresence } {/thispresence } } } proc presencecmd::handle_command {chatid user body type} { global userstatus if {[string match {/presence*} $body]} { set cmd /presence } elseif {[string match {/chatpresence*} $body]} { set cmd /chatpresence } elseif {[string match {/thispresence*} $body]} { set cmd /thispresence } else return set fields [split $body \n] set pres [string trim [string range [lindex $fields 0] \ [string length $cmd] end]] set status [string trim [join [lrange $fields 1 end] \n]] set sendstatus [expr {$status != ""}] if {$pres == "" && !$sendstatus} { show_usage $chatid return stop } if {$pres != ""} { switch -- $pres { avail { set pres available } available - away - xa - dnd - chat { } clear - clearstatus { set sendstatus true set pres $userstatus set status "" } default { show error $chatid [::msgcat::mc "Unknown presence \"%s\".\ Must be avail\[able\], away, xa, dnd, chat\ or clear\[status\]" $pres] return stop } } } else { set pres $userstatus } switch -- $cmd { /presence { set_master_presence $pres $status $sendstatus } /chatpresence - /thispresence { send_directed_presence $chatid $pres $status $sendstatus } } return stop } proc presencecmd::set_master_presence {pres status sendstatus} { global userstatus textstatus if {$sendstatus} { set textstatus $status } # the following assignment triggers sending the presence set userstatus $pres } proc presencecmd::send_directed_presence {chatid pres status sendstatus} { global userpriority set cmd [list send_presence [chat::get_xlib $chatid] $pres \ -to [chat::get_jid $chatid] \ -priority $userpriority] if {$sendstatus} { lappend cmd -status $status } eval $cmd } proc presencecmd::show_usage chatid { show error $chatid [::msgcat::mc "Usage:\ \t/presence ?presence|clear\[status\]?\n\ \t?status message?\n\ or\n\ \t/chatpresence ?presence|clear\[status\]?\n\ \t?status message?\n\ Where presence is one of: avail\[able\], away, xa, dnd, chat.\n\ Special presence \"clear\[status\]\" just clears the current status.\n\ /thispresence is an alias for /chatpresence"] } # $type should be either "info" or "error" proc presencecmd::show {type chatid msg} { set jid [chat::get_jid $chatid] set cw [chat::chat_win $chatid] chat::add_message $chatid $jid $type $msg {} } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/quiz000075500000000000000000000000001500237002100144225ustar00nobodynobodytkabber-plugins/quiz/msgs000075500000000000000000000000001500237002100153735ustar00nobodynobodytkabber-plugins/quiz/msgs/ru.msg000064400000000000000000000006601500237002100166120ustar00nobodynobody# ru.msg -- # # Russian messages for the Quiz Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Whether the 'Quiz' plugin is loaded. The plugin\ implements a simple quiz in Russian." "Загружено ли раÑширение\ 'Викторина'. Оно реализует проÑтую викторину на руÑÑком Ñзыке." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/quiz/msgs/uk.msg000064400000000000000000000006731500237002100166070ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Quiz Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Whether the 'Quiz' plugin is loaded. The plugin\ implements a simple quiz in Russian." "Чи завантажене розширеннÑ\ 'Вікторина'. Воно імплементує проÑту вікторину роÑійÑькою мовою." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/quiz/quiz.tcl000064400000000000000000000330561500237002100162040ustar00nobodynobody# quiz.tcl -- # # This file implements Quiz game plugin for the Tkabber XMPP client. package require msgcat namespace eval quiz { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered quiz]} { ::plugins::register quiz \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the 'Quiz'\ plugin is loaded.\ The plugin implements\ a simple quiz in\ Russian."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable prefix {[QUIZ]: } } proc quiz::load_file {filename {enc utf-8}} { variable questions set fd [open $filename] fconfigure $fd -encoding $enc set questions(qa) {} set questions(qpos) {} set n 0 while {![eof $fd]} { set s [gets $fd] set s [string trim $s] lappend questions(qa) [split $s |] lappend questions(qpos) $n incr n } close $fd } namespace eval quiz { # A hack (reload the script in UTF-8 encoding) variable questions if {![info exists questions(qa)]} { variable file variable fd set file [file join [file dirname [info script]] quizdata.txt] if {[catch {load_file $file utf-8}]} { puts "Can't load file $file" return } set fd [open [info script]] fconfigure $fd -encoding utf-8 uplevel 1 [read $fd] close $fd return } } proc quiz::load {} { hook::add generate_completions_hook \ [namespace current]::commands_comps hook::add draw_message_hook [namespace current]::handle_messages 79 hook::add chat_send_message_hook \ [namespace current]::handle_commands 50 } proc quiz::unload {} { variable prefix variable questions variable game variable question variable answer variable points variable asktime variable hint variable top variable stats hook::remove generate_completions_hook \ [namespace current]::commands_comps hook::remove draw_message_hook [namespace current]::handle_messages 79 hook::remove chat_send_message_hook \ [namespace current]::handle_commands 50 foreach chatid [chat::opened] { if {[info exists game($chatid)]} { stop $chatid } } catch {unset prefix} catch {unset questions} catch {unset game} catch {unset question} catch {unset answer} catch {unset points} catch {unset asktime} catch {unset hint} catch {unset top} catch {unset stats} } proc quiz::get_question {} { variable questions if {![info exists questions(qa)]} return if {![llength $questions(qpos)]} { for {set i 0} "\$i < [llength $questions(qa)]" {incr i} { lappend questions(qpos) $i } } set idx [rand [llength $questions(qpos)]] set qidx [lindex $questions(qpos) $idx] set questions(qpos) [lreplace $questions(qpos) $idx $idx] return [lindex $questions(qa) $qidx] } proc quiz::commands_comps {chatid compsvar wordstart line} { upvar 0 $compsvar comps if {!$wordstart} { lappend comps "/quizstart " "/quizstop " "/quiznext " "/quiztop " } } proc quiz::handle_commands {chatid user body type} { variable game if {$type != "groupchat"} return if {[string index $body 0] != "/"} return set command [string trim $body] switch -- $command { /quizstart { start $chatid return stop } /quizstop { stop $chatid return stop } /quiznext { next $chatid return stop } /quiztop { top $chatid return stop } } return } proc quiz::handle_messages {chatid from type body x} { variable game variable question variable answer variable points variable asktime variable prefix set xlib [chat::get_xlib $chatid] set group [chat::get_jid $chatid] set s [string trim $body] switch -- $s { !topscores - !topscore { top $chatid return } } if {![info exists game($chatid)] || ![info exists answer($chatid)]} return switch -- $s { !хинт - !hint { after 5000 [list [namespace current]::hint $chatid] } default { if {[filter $body] == [filter $answer($chatid)]} { set time [expr [clock seconds] - $asktime($chatid)] if {[catch { chat::get_nick $xlib $from $type } nick]} { set nick [chat::get_nick $from $type] } set msg_time "" variable last if {[info exists last(nick,$chatid)] && \ $last(nick,$chatid) == $nick} { incr last(num,$chatid) if {$last(num,$chatid) > 2} { set msg_cont "$nick отвечает на\ $last(num,$chatid) [lindex {. Ð²Ð¾Ð¿Ñ€Ð¾Ñ Ð²Ð¾Ð¿Ñ€Ð¾Ñа вопроÑов} [numgrp \ $last(num,$chatid)]] подрÑд!" } } else { set last(nick,$chatid) $nick set last(num,$chatid) 1 } variable stats if {![info exists stats(quick,$chatid/$nick)]} { set stats(quick,$chatid/$nick) $time } elseif {$stats(quick,$chatid/$nick) > $time} { set msg_time ", и Ñто твой Ñамый быÑтрый ответ," set stats(quick,$chatid/$nick) $time } if {![info exists stats(quick,$chatid)]} { set stats(quick,$chatid) $time } elseif {$stats(quick,$chatid) > $time} { set msg_time ", и Ñто Ñамый быÑтрый ответ за игру," set stats(quick,$chatid) $time } message::send_msg $xlib $group -type groupchat \ -body "${prefix}Молодец, $nick! Правильный\ ответ \"$answer($chatid)\" был дан за $time [lindex {. Ñекунду Ñекунды \ Ñекунд} [numgrp $time]]$msg_time\ и Ð¿Ñ€Ð¸Ð½Ñ‘Ñ Ñ‚ÐµÐ±Ðµ $points($chatid) [lindex {. очко очка очков} [numgrp \ $points($chatid)]]." if {[info exists msg_cont]} { message::send_msg $xlib $group -type groupchat \ -body $msg_cont } add_score $chatid $nick $points($chatid) $time catch { unset question($chatid) } variable lost set lost($chatid) 0 next $chatid } } } } proc quiz::start {chatid} { variable game variable prefix set xlib [chat::get_xlib $chatid] set group [chat::get_jid $chatid] if {![info exists game($chatid)]} { set game($chatid) "" message::send_msg $xlib $group -type groupchat \ -body "${prefix}Добро пожаловать на нашу викторину! Ðачинаем игру." variable lost set lost($chatid) 0 next $chatid } else { chat::add_message $chatid $group error "Викторина уже запущена" {} } } proc quiz::stop {chatid} { variable game variable question variable prefix set xlib [chat::get_xlib $chatid] set group [chat::get_jid $chatid] if {[info exists game($chatid)]} { after cancel [list [namespace current]::ask $chatid] after cancel [list [namespace current]::next $chatid] after cancel [list [namespace current]::hint $chatid] after cancel [list [namespace current]::hint $chatid 1] catch { unset question($chatid) } catch { unset answer($chatid) } unset game($chatid) message::send_msg $xlib $group -type groupchat \ -body "${prefix}Викторина оÑтановлена." top $chatid } else { chat::add_message $chatid $group error "Викторина не запущена" {} } } proc quiz::next {chatid} { variable game variable question variable answer variable hint variable prefix set xlib [chat::get_xlib $chatid] set group [chat::get_jid $chatid] after cancel [list [namespace current]::ask $chatid] after cancel [list [namespace current]::next $chatid] after cancel [list [namespace current]::hint $chatid] after cancel [list [namespace current]::hint $chatid 1] if {[info exists game($chatid)]} { if {[info exists question($chatid)]} { variable lost incr lost($chatid) if {$lost($chatid) > 4} { message::send_msg $xlib $group -type groupchat \ -body "${prefix}Ðу не хотите правильно отвечать\ -- и не надо :-/" stop $chatid return } variable last catch { unset last(nick,$chatid) } catch { unset last(num,$chatid) } message::send_msg $xlib $group -type groupchat \ -body "${prefix}Ðикто не ответил на вопроÑ, Ñледующий через\ 5 Ñекунд. Правильный ответ \"$answer($chatid)\"." } catch { unset question($chatid) } catch { unset answer($chatid) } catch { unset hint($chatid) } after 5000 [list [namespace current]::ask $chatid] } else { chat::add_message $chatid $group error "Викторина не запущена" {} } } proc quiz::ask {chatid} { variable game variable question variable answer variable points variable asktime variable prefix set xlib [chat::get_xlib $chatid] set group [chat::get_jid $chatid] after cancel [list [namespace current]::ask $chatid] after cancel [list [namespace current]::next $chatid] lassign [get_question] question($chatid) answer($chatid) set points($chatid) 3 set asktime($chatid) [clock seconds] message::send_msg $xlib $group -type groupchat \ -body "${prefix}$question($chatid)" after 60000 [list [namespace current]::next $chatid] } proc quiz::hint {chatid {cont 0}} { variable game variable answer variable hint variable points variable prefix set xlib [chat::get_xlib $chatid] set group [chat::get_jid $chatid] if {![info exists game($chatid)] || \ ![info exists answer($chatid)] || \ ([info exists hint($chatid)] && !$cont)} return set hint($chatid) "" if {![incr points($chatid) -1]} { next $chatid return } message::send_msg $xlib $group -type groupchat \ -body "${prefix}ПодÑказка: [string range $answer($chatid) \ 0 [expr 3 - $points($chatid)]]...?" after 20000 [list [namespace current]::hint $chatid 1] } proc quiz::filter {text} { regsub -all {[;:()\[\]!?.,/\\{}]} [string tolower $text] "" text return [string trim $text] } proc quiz::numgrp {number} { switch -glob -- $number { *11 {return 3} *12 {return 3} *13 {return 3} *14 {return 3} *1 {return 1} *2 {return 2} *3 {return 2} *4 {return 2} default {return 3} } } proc quiz::top {chatid} { variable top variable prefix variable stats set xlib [chat::get_xlib $chatid] set group [chat::get_jid $chatid] if {[info exists top($chatid)]} { set t [lsort -integer -decreasing -index 1 $top($chatid)] set ts "" foreach item $t { lassign $item nick score set avgp [format "%.4f" \ [expr $score * 1.0 / $stats(answ,$chatid/$nick)]] set answ $stats(answ,$chatid/$nick) set quick $stats(quick,$chatid/$nick) set avgt [format "%.4f" [expr $stats(time,$chatid/$nick) * 1.0 / \ $stats(answ,$chatid/$nick)]] append ts "$score\t$avgp\t$answ\t$quick\t$avgt\t$nick\n" } message::send_msg $xlib $group -type groupchat \ -body "${prefix}Top scores: points\tavg p\tansw\tmin t\tavg t\tnick\n$ts" } else { chat::add_message $chatid $group error "Ðет данных о top scores" {} } } proc quiz::add_score {chatid nick points time} { variable top if {![info exists top($chatid)]} { set top($chatid) {} } set t {} set b 1 foreach item $top($chatid) { lassign $item n s if {$n == $nick} { incr s $points set b 0 } lappend t [list $n $s] } if {$b} { lappend t [list $nick $points] } set top($chatid) $t variable stats if {![info exists stats(answ,$chatid/$nick)]} { set stats(answ,$chatid/$nick) 1 } else { incr stats(answ,$chatid/$nick) } if {![info exists stats(time,$chatid/$nick)]} { set stats(time,$chatid/$nick) $time } else { incr stats(time,$chatid/$nick) $time } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/quiz/quizdata.txt000064400000000000000000000016501500237002100170660ustar00nobodynobodyПоÑледовательное изложение Ñамим говорÑщим или пишущим оÑновных Ñтапов его жизни.|Ð°Ð²Ñ‚Ð¾Ð±Ð¸Ð¾Ð³Ñ€Ð°Ñ„Ð¸Ñ ÐœÑƒÐ·Ñ‹ÐºÐ°Ð»ÑŒÐ½Ð¾Ðµ Ñопровождение Ñольной вокальной или инÑтрументальной партии, оÑновной темы или мелодии музыкального произведениÑ.|аккомпанемент СиÑтема взглÑдов на развитие органичеÑкого мира, Ð¾Ñ‚Ñ€Ð¸Ñ†Ð°ÑŽÑ‰Ð°Ñ Ð±Ð¸Ð¾Ð»Ð¾Ð³Ð¸Ñ‡ÐµÑкую Ñволюцию вообще или учение о еÑтеÑтвенном отборе.|антидарвинизм СтроительÑтво барж.|баржеÑтроение ÐедоÑтаток художеÑтвенной образноÑти (в произведении иÑкуÑÑтва, литературы).|безобразноÑть tkabber-plugins/quotelastmsg000075500000000000000000000000001500237002100161625ustar00nobodynobodytkabber-plugins/quotelastmsg/AUTHORS000064400000000000000000000000661500237002100173130ustar00nobodynobodyKonstantin Khomoutov tkabber-plugins/quotelastmsg/INSTALL000064400000000000000000000005051500237002100172720ustar00nobodynobodyAs usual, copy this directory under the ~/.tkabber/plugins directory so that you get a hierarchy like this: ~/.tkabber/plugins ~/.tkabber/plugins/quotelastmsg/ ~/.tkabber/plugins/quotelastmsg/quotelastmsg.tcl Restart Tkabber, to get the plugin loaded. Consult the README file for the details about using this plugin. tkabber-plugins/quotelastmsg/README000064400000000000000000000045741500237002100171330ustar00nobodynobody"Quote last message" -- chat plugin for Tkabber. I. The idea This plugin provides a way to "quote" the message located at the very bottom of the conversation log of a chat window -- that is, to copy such message into the input box of the same chat window with some decorations added (by default the ">> " string is prepeneded to the message). By default, quoting is done using the keyboard shortcut. The functionality provided by this plugin might come in handy when you want to refer to someone else's (or your own) message appeared in the course of the conversation. II. Configuration You can configure two parameters affecting the operation of this plugin: actions triggering the quotation of the last message and the format string used to decorate the message being quoted. Message quoting action is bound to a Tk virtual event named <>. By default, it's bound to (also to to accound for certain Unix systems). To change the binding you will have to add appropriate command(s) to the Tkabber configuration file. For instance, to unbind this action from and bind it to write this into your condig.tcl: event delete <> event delete <> event add <> Full details about the "event" command can be found in [1]. Note that you can use any event specifier, not just keyboard shortcuts. Refer to [2] for full details. The format string used to decorate the message being quoted can be changed using the Customize interface in the "Plugins -> Quote Last Message" group of settings (also reachable as "Chat -> Quote Last Message"). The actual setting is named ::plugins::quotelastmsg::options(format) and it defaults to the string ">> %m". In the format string the format specifier "%m" is substituted by the whole message as seen in the conversation log window, and the specifier "%%" is replaced by a single character "%". III. Bugs and limitations * There's currently no way to separately refer to the parts of the message being quoted (such as its timestamp, poster's nickname and the message body) in the format string. * It's impossible to embed "special chanracters" into the format string (such as \n or \t). IV. References 1. http://www.tcl.tk/man/tcl8.5/TkCmd/event.htm 2. http://www.tcl.tk/man/tcl8.5/TkCmd/bind.htm vim:et:ts=4:sw=4:tw=64 tkabber-plugins/quotelastmsg/license.terms000064400000000000000000000021121500237002100207330ustar00nobodynobodyCopyright (c) 2008 Konstantin Khomoutov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tkabber-plugins/quotelastmsg/msgs000075500000000000000000000000001500237002100171335ustar00nobodynobodytkabber-plugins/quotelastmsg/msgs/de.msg000064400000000000000000000022421500237002100203120ustar00nobodynobody# de.msg -- # # German messages for the Quote last message Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 18.11.2010 ::msgcat::mcset de "Format string used to quote the message. Format specifer\ \"%m\" is replaced by the whole message being quoted. Format\ specifier \"%%\" is replaced by a single character \"%\"." \ "Formatierungs-Zeichenfolge für das Zitieren der Nachricht.\nDie\ Format-Angabe '%m' wird ersetzt durch die zu zitierende Nachricht\ (die Format-Angabe '%%' wird ersetzt durch ein einzelnes '%')." ::msgcat::mcset de "Plugins options." "Optionen für Plugins." ::msgcat::mcset de "Quote Last Message plugin options." \ "Optionen für das 'Quote Last Message'-Plugin." ::msgcat::mcset de "This plugin provides a way to copy a message located at\ the bottom of a chat window conversation log to the input box of\ that chat window." "Die Nachricht am Ende eines Chat-Fensters in\ das Eingabefeld des Chat-Fensters kopieren." ::msgcat::mcset de "Whether the last message quoting plugin is loaded." \ "'Quote Last Message'-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/quotelastmsg/msgs/ru.msg000064400000000000000000000030531500237002100203510ustar00nobodynobody# ru.msg -- # # Russian messages for the Quote last message Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Format string used to quote the message.\ Format specifer \"%m\" is replaced by the whole message\ being quoted. Format specifier \"%%\" is replaced by\ a single character \"%\"."\ "Строка формата Ð´Ð»Ñ Ñ†Ð¸Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ ÑообщениÑ. Спецификатор\ формата \"%m\" заменÑетÑÑ Ð½Ð° вÑе цитируемое Ñообщение.\ Спецификатор формата \"%%\" заменÑетÑÑ Ð½Ð° один знак процента \"%\"." ::msgcat::mcset ru "Plugins options." "ÐаÑтройки раÑширений." ::msgcat::mcset ru "Whether the last message quoting plugin is loaded." \ "Загружено ли раÑширение Ñ†Ð¸Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾Ñледнего ÑообщениÑ." ::msgcat::mcset ru "Quote Last Message plugin options." \ "ÐаÑтройки раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ñ†Ð¸Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾Ñледнего ÑообщениÑ." ::msgcat::mcset ru "This plugin provides a way to copy a message located at\ the bottom of a chat window conversation log to the input\ box of that chat window." \ "Это раÑширение позволÑет копировать Ñообщение, находÑщееÑÑ Ð² Ñамом\ низу окна разговора, в окно ввода ÑообщениÑ." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/quotelastmsg/msgs/uk.msg000064400000000000000000000031141500237002100203400ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Quote last message Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Format string used to quote the message.\ Format specifer \"%m\" is replaced by the whole message\ being quoted. Format specifier \"%%\" is replaced by\ a single character \"%\"."\ "РÑдок формату Ð´Ð»Ñ Ñ†Ð¸Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ. Спеціфікатор\ формату \"%m\" замінюєтьÑÑ Ð½Ð° вÑе цитуєме поідомленнÑ.\ Спеціфікатор формату \"%%\" замінюєтьÑÑ Ð½Ð° один знак проценту \"%\"." ::msgcat::mcset uk "Plugins options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½ÑŒ." ::msgcat::mcset uk "Whether the last message quoting plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ñ†Ð¸Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ñтаннього повідомленнÑ." ::msgcat::mcset uk "Quote Last Message plugin options." \ "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ñ†Ð¸Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ñтаннього повідомленнÑ." ::msgcat::mcset uk "This plugin provides a way to copy a message located at\ the bottom of a chat window conversation log to the input\ box of that chat window." \ "Це Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÑÑ” копіювати повідомленнÑ, Ñке мітитьÑÑ Ð½Ð°Ð¹Ð½Ð¸Ð¶Ñ‡Ðµ\ у вікні розмови, у вікно вводу повідомленнÑ." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/quotelastmsg/quotelastmsg.tcl000064400000000000000000000076351500237002100215100ustar00nobodynobody# quotelastmsg.tcl -- # # "Quote last message" chat plugin for Tkabber. # Allows to copy message located at the bottom of the # conversation log in the chat window to the input box # of that chat window. # # Author: Konstantin Khomoutov # # See license.terms for the terms of distribution. # See README for usage details. package require msgcat namespace eval quotelastmsg { variable state variable options ::msgcat::mcload [file join [file dirname [info script]] msgs] variable desc [::msgcat::mc \ "This plugin provides a way to copy a message located\ at the bottom of a chat window conversation log\ to the input box of that chat window."] if {![::plugins::is_registered quotelastmsg]} { ::plugins::register quotelastmsg \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc \ "Whether the last message quoting plugin is loaded."]\n$desc \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } custom::defgroup Plugins [::msgcat::mc "Plugins options."] -group Tkabber custom::defgroup {Quote Last Message} \ [::msgcat::mc "Quote Last Message plugin options."]\ $desc \ -group Plugins \ -group Chat custom::defvar options(format) {>> %m} \ [::msgcat::mc "Format string used to quote the message.\ Format specifer \"%m\" is replaced by the whole message\ being quoted. Format specifier \"%%\" is replaced by\ a single character \"%\"."] \ -group {Quote Last Message} \ -type string } proc quotelastmsg::load {} { hook::add open_chat_post_hook [namespace current]::prepare_chat_window hook::add close_chat_post_hook [namespace current]::cleanup_state hook::add draw_message_post_hook [namespace current]::on_message_drawn event add <> event add <> foreach chatid [chat::opened] { prepare_chat_window $chatid ? } } proc quotelastmsg::unload {} { foreach chatid [chat::opened] { unprepare_chat_window $chatid } event delete <> event delete <> hook::remove open_chat_post_hook [namespace current]::prepare_chat_window hook::remove close_chat_post_hook [namespace current]::cleanup_state hook::remove draw_message_post_hook [namespace current]::on_message_drawn } proc quotelastmsg::prepare_chat_window {chatid type} { set iw [::chat::input_win $chatid] set cw [::chat::chat_win $chatid] bind $iw <> \ [list [namespace current]::quote [double% $chatid]] variable state set state($chatid,last) [$cw index {end - 1 char}] } proc quotelastmsg::unprepare_chat_window {chatid} { set iw [::chat::input_win $chatid] bind $iw <> {} set cw [::chat::chat_win $chatid] $cw tag delete lastmsg cleanup_state $chatid } proc quotelastmsg::cleanup_state {chatid} { variable state unset state($chatid,last) } proc quotelastmsg::on_message_drawn {chatid from type body x} { if {![chat::is_opened $chatid]} return variable state upvar 0 state($chatid,last) last set cw [::chat::chat_win $chatid] set now [$cw index {end - 1 char}] if {[$cw compare $last < $now]} { $cw tag delete lastmsg $cw tag add lastmsg $last $now } set last $now } proc quotelastmsg::quote {chatid} { variable options set cw [::chat::chat_win $chatid] set iw [::chat::input_win $chatid] set range [$cw tag prevrange lastmsg end] if {$range == ""} return lassign $range x y $iw insert end [string map \ [list %% % %m [$cw get $x $y]] $options(format)] $iw see end } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/receipts000075500000000000000000000000001500237002100152505ustar00nobodynobodytkabber-plugins/receipts/AUTHORS000064400000000000000000000001631500237002100163770ustar00nobodynobodyKonstantin Khomoutov Artwork by Artem Bannikov tkabber-plugins/receipts/INSTALL000064400000000000000000000004701500237002100163610ustar00nobodynobodyAs usual, copy this directory under the ~/.tkabber/plugins directory so that you get a hierarchy like this: ~/.tkabber/plugins ~/.tkabber/plugins/receipts/ ~/.tkabber/plugins/receipts/receipts.tcl Restart Tkabber, to get the plugin loaded. Consult the README file for the details about using this plugin. tkabber-plugins/receipts/README000064400000000000000000000035631500237002100162160ustar00nobodynobody"Message receipts" -- plugin for Tkabber. I. The Idea This plugin implements XEP-0184 "Message receipts": in one-to-one chat sessions it is able to request confirmations of reception of outgoing messages and reply to such requests coming from remote party. Reception status is tracked for each message placed in the chat log window of a chat session using special icon: when the message is sent, the icon depicts "unconfirmed" status, when the confirmation arrives for this message, the icon associated with this message is changed to depict "confirmed" status. Receipts are only sent when all these conditions hold: * Receipt is requested (attached to a message). * Replying receipt requests isn't explicitly prohibited using the "reply" Customize option (see below). * The receipt request is attached to a message which is either received in a MUC's private chat or is originated from a user which is subscribed to our presence. In all other cases receipt requests are silently ignored. This is done in order not to leak presence information. Note that unlike some other IM clients Tkabber doesn't wait for receipt to arrive -- it just changes the status icon associated with particular message when its receipt is received. II. Configuration This plugin can be configured using Tkabber's Customize mechanism. Two configuration options are available under the "Plugins -> Message Receipts" group of settings (also available under "Chat -> Message Receipts"): * ::plugins::options::receipts(request) -- Attach request for receipt to each outgoing chat message. Default is true. * ::plugins::options::receipts(reply) -- Issue message receipts for messages that request them. Default is true. Note that issuing of receipts is further restricted based on privacy considerations (see above). III. Limitations Some functionality is missing. See TODO for details. # vim:tw=64:et tkabber-plugins/receipts/TODO000064400000000000000000000025241500237002100160220ustar00nobodynobodyHIGH * Implement per-chat or per-JID enabling/disabling of message receipts. This presumably suggests implementing some general framework for "client-side privacy handling" on which this and other parts of Tkabber should be based (such as chat events and MUC ignoring). * Provide for sending receipts along with normal messages. And displaying of "reception confirmed" status. It appears to require a patch to Tkabber. Also it probably will fit more naturally to the "mailbox" concept which will probably be eventually implemented for handling "normal" messages. LOW * Honor peer's features, if available. * Think of implementing displaying of reception requests originating from chat peer: i.e. if peer reqtested a receipt for a given message, display an "empty" icon next to this message; if this request was satisfied, display "filled" icon, otherwise display "denied" icon. In fact this doesn't have much sense other than providing for better lineup of messages in a chat window which appears to be rather ragged now. * Receipts should probably be sent when a message is displayed, not when it's received. This also fits more cleanly with displaying of remote reception requests. * Try to decrease the size of icons (at least make them twice as this horizontally) -- may be they will look better. # vim:tw=64:et tkabber-plugins/receipts/images000075500000000000000000000000001500237002100165155ustar00nobodynobodytkabber-plugins/receipts/images/confirmed.gif000064400000000000000000000005421500237002100212320ustar00nobodynobodyGIF89aÕ0µµµŠŠŠqqqòòòçççéééåååøøøëëëàààñññâââïïïöööíííèèèìììúúú………€€€ùùùãããûûûôôôßßßîîîtttsss~~~ððð‰‰‰÷÷÷{{{õõõ‚‚‚üüü‡‡‡yyyêêêvvvwwwÞÞÞäääáááóóóæææýýýþþþ!ù0,@˜pH,’D4á€J'͆x¹FÊ¡b Ô‘%rø4hø8.‡.ñ(hô “q ê0y„&€g„ˆy†ˆq–ˆ „ž* ˆ ‹h ˆª+ ˆ-¬)ˆIKMO(RFÄEA;tkabber-plugins/receipts/images/unconfirmed.gif000064400000000000000000000005471500237002100216020ustar00nobodynobodyGIF89aÕ/ŠŠŠqqqíííòòòïïïëëëøøøåååçççéééìììóóóõõõñññöööãããôôôêêêîîîèèèððð÷÷÷àààâââæææúúú€€€yyyäää………‰‰‰ûûû‚‚‚~~~ssstttüüü{{{ßß߇‡‡ùùùÞÞÞáááwwwvvvþþþýýý!ù/,„À—pH,žS¤ •6¬‘ˆh¹H”ÁÁX TÒ'c¨8 ‹|—ZÀ´\/E"(Ô_oq| y{  ˆhj †ˆr—ˆs•žˆ}ˆ*&ˆŽ¬®°&)ˆIKMO+RFÉEA;tkabber-plugins/receipts/license.terms000064400000000000000000000021121500237002100200210ustar00nobodynobodyCopyright (c) 2008 Konstantin Khomoutov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tkabber-plugins/receipts/msgs000075500000000000000000000000001500237002100162215ustar00nobodynobodytkabber-plugins/receipts/msgs/de.msg000064400000000000000000000021251500237002100174000ustar00nobodynobody# de.msg -- # # German messages for the Receipts Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 27.03.2009 ::msgcat::mcset de "Plugins options." "Optionen für Plugins." ::msgcat::mcset de "Issue receipts for incoming messages." \ "Empfangsbestätigungen für eingehende Nachrichten ausstellen." ::msgcat::mcset de "Request receipts for outgoing messages and reply to such\ requests originating from chat peers. Message reception state is\ displayed next to each chat message using special icon." \ "Optionen für Empfangsbestätigungen.\nEmpfangsbestätigungen für\ ausgehende Nachrichten anfordern und derartige Anfragen von\ Chat-Partnern beantworten. Der Empfangs-Status wird durch ein\ spezielles Icon neben jeder Chat-Nachricht angezeigt." ::msgcat::mcset de "Request receipts for outgoing messages." \ "Empfangsbestätigungen für ausgehende Nachrichten anfordern." ::msgcat::mcset de "Whether the Message Receipts plugin is loaded." \ "Empfangsbestätigungs-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/receipts/msgs/es.msg000064400000000000000000000017301500237002100174200ustar00nobodynobody# es.msg -- # # Spanish messages for the Receipts Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "Issue receipts for incoming messages." \ "Proporcionar recetas para los mensajes recibidos." ::msgcat::mcset es "Plugins options." "Opciones del plugin." ::msgcat::mcset es "Request receipts for outgoing messages and reply to such\ requests originating from chat peers. Message reception state is\ displayed next to each chat message using special icon." "Solicitar\ recetas para los mensajes enviados y responder a dichas peticiones\ cuando alguien te las pide. El estado de la recepción del mensaje se\ muestra junto a cada mensaje usando un dibujito especial." ::msgcat::mcset es "Request receipts for outgoing messages." \ "Solicitar recetas para los mensajes enviados." ::msgcat::mcset es "Whether the Message Receipts plugin is loaded." \ "Cargar el plugin Receipts." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/receipts/msgs/pl.msg000064400000000000000000000021551500237002100174260ustar00nobodynobody# pl.msg -- # # Polish messages for the Receipts Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Error" "Błąd" ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "Issue receipts for incoming messages." \ "WysyÅ‚aj potwierdzenia odbioru dla przychodzÄ…cych wiadomoÅ›ci." ::msgcat::mcset pl "Request receipts for outgoing messages." \ "Żądaj potwierdzeÅ„ odbioru dla wysyÅ‚anych wiadomoÅ›ci." ::msgcat::mcset pl "Request receipts for outgoing messages and reply to such\ requests originating from chat peers. Message reception state is\ displayed next to each chat message using special icon." "Żądania\ potwierdzeÅ„ odbioru dla wychodzÄ…cych wiadomoÅ›ci i odpowiadaj na takie\ żądania pochodzÄ…ce od rozmówcy. Status potwierdzenia odbioru jest\ wyÅ›wietlany przy każdej wiadomoÅ›ci w rozmowie za pomocÄ…\ odpowiedniej ikony." ::msgcat::mcset pl "Whether the Message Receipts plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ statusu potwierdzenia odbioru." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/receipts/msgs/ru.msg000064400000000000000000000027521500237002100174440ustar00nobodynobody# ru.msg -- # # Russian messages for the Receipts Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Issue receipts for incoming messages." "Подтверждать\ приём входÑщих Ñообщений." ::msgcat::mcset ru "Plugins options." "ÐаÑтройки раÑширений." ::msgcat::mcset ru "Request receipts for outgoing messages and reply to such\ requests originating from chat peers. Message reception state is\ displayed next to each chat message using special icon." "Запрашивать\ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ñ‘Ð¼Ð° иÑходÑщих Ñообщений и удовлетворÑть подобные\ запроÑÑ‹ Ð´Ð»Ñ Ñообщений других пользователей. Факт Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ñ‘Ð¼Ð°\ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶Ð°ÐµÑ‚ÑÑ Ñ€Ñдом Ñ Ñообщением в окне разговора при помощи\ Ñпециальной картинки." ::msgcat::mcset ru "Request receipts for outgoing messages." "Запрашивать\ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ñ‘Ð¼Ð° иÑходÑщих Ñообщений." ::msgcat::mcset ru "Whether the Message Receipts plugin is loaded."\ "Загружено ли раÑширение, позволÑющее запрашивать и отÑылать\ подтверждение приема Ñообщений." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/receipts/msgs/uk.msg000064400000000000000000000030441500237002100174300ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Receipts Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Issue receipts for incoming messages." "Підтверджувати\ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð²Ñ…Ñ–Ð´Ð½Ð¸Ñ… повідомлень" ::msgcat::mcset uk "Plugins options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½ÑŒ." ::msgcat::mcset uk "Request receipts for outgoing messages and reply to such\ requests originating from chat peers. Message reception state is\ displayed next to each chat message using special icon." \ "Запитувати Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð²Ð¸Ñ…Ñ–Ð´Ð½Ð¸Ñ… повідомлень Ñ–\ задовольнÑти подібні запити Ð´Ð»Ñ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½ÑŒ інших кориÑтувачів.\ Факт Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶Ð°Ñ”Ñ‚ÑŒÑÑ Ð¿Ð¾Ñ€Ñд з\ повідомленнÑм у вікні розмови з допомогою Ñпеціальної іконки." ::msgcat::mcset uk "Request receipts for outgoing messages." "Запитувати\ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð²Ð¸Ñ…Ñ–Ð´Ð½Ð¸Ñ… повідомлень" ::msgcat::mcset uk "Whether the Message Receipts plugin is loaded."\ "Чи завантажене розширеннÑ, Ñке дозволÑÑ” запитувати Ñ– відÑилати\ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½ÑŒ." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/receipts/receipts.tcl000064400000000000000000000137701500237002100176610ustar00nobodynobody# receipts.tcl -- # # Support for XEP-0184 "Message Receipts" (v1.1 and 1.0). # # Author: Konstantin Khomoutov # Artwork by Artem Bannikov # # See license.terms for legal details on usage and distribution. # See README for usage guidelines. package require msgcat namespace eval receipts { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered receipts]} { ::plugins::register receipts \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc \ "Whether the Message Receipts\ plugin is loaded."] \ -loadcommand \ [namespace code \ [list load \ [file dirname \ [info script]]]] \ -unloadcommand [namespace code unload] return } variable options custom::defgroup Plugins [::msgcat::mc "Plugins options."] -group Tkabber custom::defgroup "Message Receipts" \ [::msgcat::mc "Request receipts for outgoing\ messages and reply to such requests originating from chat peers.\ Message reception state is displayed next to each chat message\ using special icon."] \ -group Plugins \ -group Chat custom::defvar options(request) 1 \ [::msgcat::mc "Request receipts for outgoing messages."] \ -group "Message Receipts" \ -type boolean custom::defvar options(reply) 1 \ [::msgcat::mc "Issue receipts for incoming messages."] \ -group "Message Receipts" \ -type boolean } proc receipts::load {dir} { set ::NS(receipts) urn:xmpp:receipts foreach item {confirmed unconfirmed} { create_image receipts/$item \ -file [file join $dir images $item.gif] } hook::add process_message_hook \ [namespace current]::process_message hook::add chat_send_message_xlist_hook \ [namespace current]::attach_confirmation_request hook::add draw_message_hook \ [namespace current]::add_receipt_icon 7 disco::register_feature $::NS(receipts) } proc receipts::unload {} { disco::register_feature $::NS(receipts) foreach item {confirmed unconfirmed} { image delete photo receipts/$item } hook::remove process_message_hook \ [namespace current]::process_message hook::remove chat_send_message_xlist_hook \ [namespace current]::attach_confirmation_request hook::remove draw_message_hook \ [namespace current]::add_receipt_icon 7 unset ::NS(receipts) } # Receipts are only sent when all these conditions hold: # * They aren't disabled via Customize options. # * Receipt request is attached to a groupchat private # message or to a message from a user who subscribed # to our presence. proc receipts::reply_allowed {xlib from type} { variable options if {!$options(reply)} { return 0 } if {[string equal $type chat]} { set chatid [chat::chatid $xlib [::xmpp::jid::stripResource $from]] if {[chat::is_groupchat $chatid]} { return 1 } } return [roster::is_trusted $xlib $from] } # When parsing the element, we prefer the value of its "id" # attribute, if present, over the value of the "id" attribute of the # enclosing element. This allows to support both v1.1 # and v1.0 versions of XEP-0184. proc receipts::process_message \ {xlib from id type is_subject subject body err thread priority x} { foreach element $x { ::xmpp::xml::split $element tag xmlns attrs cdata subels switch -- $tag { request { if {![string equal $xmlns $::NS(receipts)]} continue if {![reply_allowed $xlib $from $type]} continue process_receipt_request $xlib $from $id } received { if {![string equal $xmlns $::NS(receipts)]} continue set id [::xmpp::xml::getAttr $attrs id $id] process_receipt_response $xlib $from $id $type } } } } # XMPP-0184 v1.1 suggests mirroring the id attribute of the source # message only in the tag; mirroring of this attribute # in the tag is the requirement of v1.0 and below. # We maintain both of them for backwards compatibility. proc receipts::process_receipt_request {xlib from id} { ::xmpp::sendMessage $xlib $from -id $id \ -xlist [list [::xmpp::xml::create received \ -xmlns $::NS(receipts) \ -attrs [list id $id]]] } proc receipts::process_receipt_response {xlib from id type} { variable requests foreach chatid [chat::opened $xlib [::xmpp::jid::stripResource $from]] { set cw [chat::chat_win $chatid] set name msgid_$id if {[lsearch -exact [$cw image names] $name] >= 0} { $cw image configure $name -image receipts/confirmed return } } } proc receipts::add_receipt_icon {chatid from type body x} { if {![string equal $type chat]} return if {![richtext::property_exists msgid]} return set id [richtext::property_get msgid] set cw [chat::chat_win $chatid] $cw image create end -name msgid_$id -image receipts/unconfirmed } proc receipts::attach_confirmation_request \ {xlistVar chatid user id body type} { variable options if {!$options(request) || ![chat::is_chat $chatid]} return upvar 2 $xlistVar xlist lappend xlist [::xmpp::xml::create request \ -xmlns $::NS(receipts)] richtext::property_update msgid $id } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/renju000075500000000000000000000000001500237002100145555ustar00nobodynobodytkabber-plugins/renju/msgs000075500000000000000000000000001500237002100155265ustar00nobodynobodytkabber-plugins/renju/msgs/es.msg000064400000000000000000000106221500237002100167250ustar00nobodynobody# es.msg -- # # Spanish messages for the Renju/Gomoku Tkabber plugin. # # Author: Badlop ::msgcat::mcset es " (Opponent)" " (Oponente)" ::msgcat::mcset es " (You)" " (Tu)" ::msgcat::mcset es "%s (%s) has refused Gomoku/Renju invitation: %s" \ "%s (%s) ha rechazado la invitación a Gomoku/Renju: %s" ::msgcat::mcset es "%s wants play %s." "%s quiere jugar a %s." ::msgcat::mcset es "%s wants to move first." "%s quiere mover primero." ::msgcat::mcset es "%s wants to move second." "%s quiere que muevas primero." ::msgcat::mcset es "%s with %s" "%s con %s" ::msgcat::mcset es "Accept opponent illegal moves (useful for debugging)." \ "Aceptar movimientos ilegales del oponente (útil para depuración)." ::msgcat::mcset es "Accept the draw proposal" "Aceptar la propuesta de empate" ::msgcat::mcset es "Agree to play" "Aceptar a jugar" ::msgcat::mcset es "Allow illegal moves (useful for debugging)." \ "Permitir movimientos ilegales (últil para depuración)." ::msgcat::mcset es "Black" "Negras" ::msgcat::mcset es "Cancel invitation" "Cancelar invitación" ::msgcat::mcset es "Default game variant." "Variante de juego por defecto." ::msgcat::mcset es "Draw (Both players skipped move)" \ "Empate (ambos jugadores pasaron turno)" ::msgcat::mcset es "Draw (Opponent accepted)" "Empate (el oponente aceptó)" ::msgcat::mcset es "Draw (You accepted)" "Empate (aceptaste)" ::msgcat::mcset es "Draw" "Empate" ::msgcat::mcset es "Free-style Gomoku" "Gomoku de estilo libre" ::msgcat::mcset es "Games" "Juegos" ::msgcat::mcset es "Gomoku/Renju Invitation from %s" \ "Invitación a Gomoku/Renju de %s" ::msgcat::mcset es "Gomoku/Renju Invitation" "Invitación a Gomoku/Renju" ::msgcat::mcset es "Gomoku/Renju figures theme." \ "Tipo de fichas de Gomoku/Renju." ::msgcat::mcset es "Gomoku/Renju game invitation from %s (%s) is received." \ "Se ha recibido invitación a Gomoku/Renju de %s (%s)." ::msgcat::mcset es "Gomoku/Renju plugin options." \ "Opciones de plugin de Gomoku/Renju." ::msgcat::mcset es "Gomoku/Renju..." "Gomoku/Renju..." ::msgcat::mcset es "History" "Historial" ::msgcat::mcset es "I want to move first" "Quiero mover primero" ::msgcat::mcset es "I want to move second" \ "Quiero que el oponente mueva primero" ::msgcat::mcset es "Move: " "Mover: " ::msgcat::mcset es "Opponent wins (You resigned)" \ "El oponente gana (te has rendido)" ::msgcat::mcset es "Opponent wins" "El oponente gana" ::msgcat::mcset es "Plugins options." "Opciones de plugin." ::msgcat::mcset es "Press button and make move if you want propose draw" \ "Pulsa el botón y haz un movimiento para proponer un empate" ::msgcat::mcset es "Press button if you want accept the draw proposal" \ "Pulsa el botón para aceptar la propuesta de empate" ::msgcat::mcset es "Press button if you want resign" \ "Pulsa el botón para rendirte" ::msgcat::mcset es "Press button if you want skip current move" \ "Pulsa el botón si quieres pasar el turno" ::msgcat::mcset es "Propose a draw" "Proponer un empate" ::msgcat::mcset es "Refuse to play" "Rechazar la partida" ::msgcat::mcset es "Renju" "Renju" ::msgcat::mcset es "Resign the game" "Rendirte" ::msgcat::mcset es "Sending Gomoku/Renju game invitation to %s (%s)" \ "Enviando invitación de Gomoku/Renju a %s (%s)" ::msgcat::mcset es "Show last move by default." \ "Mostrar por defecto el último movimiento." ::msgcat::mcset es "Show last move" "Mostrar el último movimiento" ::msgcat::mcset es "Show tooltips with short instructions." \ "Mostrar ventanitas con pequeñas instrucciones." ::msgcat::mcset es "Skip the move" "Saltar el movimiento" ::msgcat::mcset es "Sound to play after opponent's turn" \ "Sonido a reproducir cuando el oponente mueva pieza" ::msgcat::mcset es "Standard Gomoku" "Gomoku convencional" ::msgcat::mcset es "Tournament Gomoku" "Gomoku de torneo" ::msgcat::mcset es "Whether the Gomoku/Renju plugin is loaded." \ "Cargar el plugin Gomoku/Renju." ::msgcat::mcset es "White" "Blancas" ::msgcat::mcset es "You win (Opponent resigned)" \ "Has ganado (el oponente se rinde)" ::msgcat::mcset es "You win" "Has ganado" ::msgcat::mcset es "\n\n Opponent proposes a draw\n\n" \ "\n\n El oponente propone un empate\n\n" ::msgcat::mcset es "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n El oponente rechazó el movimiento:\n %s\n\n" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/renju/msgs/ru.msg000064400000000000000000000130151500237002100167430ustar00nobodynobody# ru.msg -- # # Russian messages for the Renju/Gomoku Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Plugins options." "Параметры раÑширений." ::msgcat::mcset ru "Show last move by default." \ "По умолчанию показывать поÑледний ход." ::msgcat::mcset ru " (You)" " (Ð’Ñ‹)" ::msgcat::mcset ru " (Opponent)" " (Оппонент)" ::msgcat::mcset ru "Gomoku/Renju plugin options." \ "Параметры раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð“Ð¾Ð¼Ð¾ÐºÑƒ/РÑндзю." ::msgcat::mcset ru "Gomoku/Renju figures theme." "Тема фишек Гомоку/РÑндзю." ::msgcat::mcset ru "Free-style Gomoku" "Свободное Гомоку" ::msgcat::mcset ru "Standard Gomoku" "Стандартное Гомоку" ::msgcat::mcset ru "Tournament Gomoku" "Турнирное Гомоку" ::msgcat::mcset ru "Renju" "РÑндзю" ::msgcat::mcset ru "Show tooltips with short instructions." \ "Показывать вÑплывающие подÑказки к Ñлементам интерфейÑа." ::msgcat::mcset ru "Allow illegal moves (useful for debugging)." \ "Разрешать неправильные ходы (иÑпользуетÑÑ Ð¿Ñ€Ð¸ отладке)." ::msgcat::mcset ru "Accept opponent illegal moves (useful for debugging)." \ "Принимать неправильные ходы от оппонента (иÑпользуетÑÑ Ð¿Ñ€Ð¸ отладке)." ::msgcat::mcset ru "Default game variant." "Вариант игры по умолчанию." ::msgcat::mcset ru "Gomoku/Renju Invitation" \ "Приглашение Ñыграть в Гомоку/РÑндзю" ::msgcat::mcset ru "Sending Gomoku/Renju game invitation to %s (%s)" \ "ПоÑылаем приглашение Ñыграть в Гомоку/РÑндзю Ñ %s (%s)" ::msgcat::mcset ru "I want to move first" "Хочу ходить первым" ::msgcat::mcset ru "I want to move second" "Хочу ходить вторым" ::msgcat::mcset ru "Cancel invitation" "Отменить приглашение" ::msgcat::mcset ru "%s (%s) has refused Gomoku/Renju invitation: %s" \ "%s (%s) отказалÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ в Гомоку/РÑндзю: %s" ::msgcat::mcset ru "Gomoku/Renju Invitation from %s" \ "Приглашение Ñыграть в Гомоку/РÑндзю Ñ %s" ::msgcat::mcset ru "Gomoku/Renju game invitation from %s (%s) is received." \ "Получено приглашение Ñыграть в Гомоку/РÑндзю Ñ %s (%s)" ::msgcat::mcset ru "%s wants play %s." "%s хочет играть в %s" ::msgcat::mcset ru "%s wants to move first." "%s хочет ходить первым." ::msgcat::mcset ru "%s wants to move second." "%s хочет ходить вторым." ::msgcat::mcset ru "Agree to play" "СоглаÑитьÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ" ::msgcat::mcset ru "Refuse to play" "ОтказатьÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ" ::msgcat::mcset ru "%s with %s" "%s Ñ %s" ::msgcat::mcset ru "Show last move" "Показывать поÑледний ход" ::msgcat::mcset ru "Move: " "Ход: " ::msgcat::mcset ru "Propose a draw" "Предложить ничью" ::msgcat::mcset ru "Accept the draw proposal" "ПринÑть предложенную ничью" ::msgcat::mcset ru "Resign the game" "Сдать партию" ::msgcat::mcset ru "History" "ЗапиÑÑŒ партии" ::msgcat::mcset ru "Gomoku/Renju..." "Гомоку/РÑндзю..." ::msgcat::mcset ru "White" "Белые" ::msgcat::mcset ru "Black" "Чёрные" ::msgcat::mcset ru "Opponent wins" "Оппонент выиграл" ::msgcat::mcset ru "You win" "Ð’Ñ‹ выиграли" ::msgcat::mcset ru "Opponent wins (You resigned)" \ "Оппонент выиграл (Ð’Ñ‹ ÑдалиÑÑŒ)" ::msgcat::mcset ru "You win (Opponent resigned)" \ "Ð’Ñ‹ выиграли (Оппонент ÑдалÑÑ)" ::msgcat::mcset ru "Draw" "ÐичьÑ" ::msgcat::mcset ru "Draw (Both players skipped move)" \ "ÐÐ¸Ñ‡ÑŒÑ (Оба игрока пропуÑтили ход)" ::msgcat::mcset ru "Draw (You accepted)" "ÐÐ¸Ñ‡ÑŒÑ (Ð’Ñ‹ принÑли)" ::msgcat::mcset ru "Draw (Opponent accepted)" "ÐÐ¸Ñ‡ÑŒÑ (Оппонент принÑл)" ::msgcat::mcset ru "Press button and make move if you want propose draw" \ "Ðажмите кнопку и Ñделайте ход, еÑли хотите предложить ничью" ::msgcat::mcset ru "Press button if you want accept the draw proposal" \ "Ðажмите кнопку, еÑли хотите принÑть предложенную ничью" ::msgcat::mcset ru "Press button if you want resign" \ "Ðажмите кнопку, еÑли хотите ÑдатьÑÑ" ::msgcat::mcset ru "Press button if you want skip current move" \ "Ðажмите кнопку, еÑли хотите пропуÑтить ход" ::msgcat::mcset ru "Skip the move" "ПропуÑтить ход" ::msgcat::mcset ru "\n\n Opponent proposes a draw\n\n" \ "\n\n Оппонент предлагает ничью\n\n" ::msgcat::mcset ru "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Оппонент отверг ход:\n %s\n\n" ::msgcat::mcset ru "Games" "Игры" ::msgcat::mcset ru "Sound to play after opponent's turn" \ "Звук, который проигрываетÑÑ Ð¿Ð¾Ñле хода оппонента" ::msgcat::mcset ru "Whether the Gomoku/Renju plugin is loaded."\ "Загружено ли раÑширение Гомоку/РÑндзю." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/renju/msgs/uk.msg000064400000000000000000000130261500237002100167360ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Gomoku/Renju Tkabber plugin. # # Author: Artem Bondarenko # Author: Sergei Golovan ::msgcat::mcset uk "Plugins options." "Параметри плагінів." ::msgcat::mcset uk "Show last move by default." \ "Показувати оÑтанній хід за замовчуваннÑм." ::msgcat::mcset uk " (You)" " (Ви)" ::msgcat::mcset uk " (Opponent)" " (Опонент)" ::msgcat::mcset uk "Gomoku/Renju plugin options." "Параметри плагіна Гомоку/Рендзю." ::msgcat::mcset uk "Gomoku/Renju figures theme." "Тема фішок Гомоку/Рендзю." ::msgcat::mcset uk "Show tooltips with short instructions." \ "Показувати Ñпливаючі підказки до елементів інтерфейÑу." ::msgcat::mcset uk "Allow illegal moves (useful for debugging)." \ "ДозволÑти неправильні ходи (викориÑтовуєтьÑÑ Ð¿Ñ€Ð¸ налагодженні)." ::msgcat::mcset uk "Accept opponent illegal moves (useful for debugging)." \ "Приймати неправильні ходи від опонента (викориÑтовуєтьÑÑ Ð¿Ñ€Ð¸\ налагодженні)." ::msgcat::mcset uk "Gomoku/Renju Invitation" "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в Гомоку/Рендзю" ::msgcat::mcset uk "Sending Gomoku/Renju game invitation to %s (%s)" \ "Ð’Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в Гомоку/Рендзю з %s (%s)" ::msgcat::mcset uk "I want to move first" "Хочу ходити першим" ::msgcat::mcset uk "I want to move second" "Хочу ходити другим" ::msgcat::mcset uk "Cancel invitation" "СкаÑувати запрошеннÑ" ::msgcat::mcset uk "%s (%s) has refused Gomoku/Renju invitation: %s" \ "%s (%s) відмовивÑÑ Ð³Ñ€Ð°Ñ‚Ð¸ в Гомоку/Рендзю: %s" ::msgcat::mcset uk "Gomoku/Renju Invitation from %s" \ "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в Гомоку/Рендзю з %s" ::msgcat::mcset uk "Gomoku/Renju game invitation from %s (%s) is received." \ "Отримане Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в Гомоку/Рендзю з %s (%s)" ::msgcat::mcset uk "%s wants play %s." " %s хоче грати %s" ::msgcat::mcset uk "%s wants to move first." " %s хоче ходити першим." ::msgcat::mcset uk "%s wants to move second." " %s хоче ходити другим." ::msgcat::mcset uk "Agree to play" "ПогодитиÑÑ Ð³Ñ€Ð°Ñ‚Ð¸" ::msgcat::mcset uk "Refuse to play" "ВідмовитиÑÑ Ð³Ñ€Ð°Ñ‚Ð¸" ::msgcat::mcset uk "%s with %s" "%s з %s" ::msgcat::mcset uk "Show last move" "Показувати оÑтанній хід" ::msgcat::mcset uk "Move: " "Хід: " ::msgcat::mcset uk "Propose a draw" "Запропонувати нічию" ::msgcat::mcset uk "Accept the draw proposal" "ПрийнÑти запропоновану нічию" ::msgcat::mcset uk "Resign the game" "Здати партію" ::msgcat::mcset uk "History" "Ð—Ð°Ð¿Ð¸Ñ Ð¿Ð°Ñ€Ñ‚Ñ–Ñ—" ::msgcat::mcset uk "Gomoku/Renju..." "Гомоку/Рендзю..." ::msgcat::mcset uk "White" "Білі" ::msgcat::mcset uk "Black" "Чорні" ::msgcat::mcset uk "Opponent wins" "Опонент виграв" ::msgcat::mcset uk "You win" "Ви виграли" ::msgcat::mcset uk "Opponent wins (You resigned)" "Опонент виграв (Ви здалиÑÑ)" ::msgcat::mcset uk "You win (Opponent resigned)" "Ви виграли (Опонент здавÑÑ)" ::msgcat::mcset uk "Draw" "ÐічиÑ" ::msgcat::mcset uk "Draw (You accepted)" "ÐÑ–Ñ‡Ð¸Ñ (Ви прийнÑли)" ::msgcat::mcset uk "Draw (Opponent accepted)" "ÐÑ–Ñ‡Ð¸Ñ (Опонент прийнÑв)" ::msgcat::mcset uk "Press button and make move if you want propose draw" \ "ÐатиÑніть кнопку й зробіть хід, Ñкщо хочете запропонувати нічию" ::msgcat::mcset uk "Press button if you want accept the draw proposal" \ "ÐатиÑніть кнопку, Ñкщо хочете прийнÑти запропоновану нічию" ::msgcat::mcset uk "Press button if you want resign" \ "ÐатиÑніть кнопку, Ñкщо хочете здатиÑÑ" ::msgcat::mcset uk "\n\n Opponent proposes a draw\n\n" \ "\n\n Опонент пропонує нічию\n\n" ::msgcat::mcset uk "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Опонент відкинув хід:\n %s\n\n" ::msgcat::mcset uk "Games" "Ігри" ::msgcat::mcset uk "Sound to play after opponent's turn" \ "Звук, Ñкий буде програватиÑÑ Ð¿Ñ–ÑÐ»Ñ Ñ…Ð¾Ð´Ñƒ опонента" ::msgcat::mcset uk "Whether the Gomoku/Renju plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð“Ð¾Ð¼Ð¾ÐºÑƒ/Рендзю." ::msgcat::mcset uk "Press button if you want skip current move" \ "ÐатиÑніть кнопку, Ñкщо ви хочете пропуÑтити хід" ::msgcat::mcset uk "Renju" "Рендзю" ::msgcat::mcset uk "Skip the move" "ПропуÑтити хід" ::msgcat::mcset uk "Standard Gomoku" "Стандартне Гомоку" ::msgcat::mcset uk "Tournament Gomoku" "Турнірне Гомоку" ::msgcat::mcset uk "Default game variant." "Варіант гри за замовчуваннÑм." ::msgcat::mcset uk "Draw (Both players skipped move)" \ "ÐÑ–Ñ‡Ð¸Ñ (обидва Ð³Ñ€Ð°Ð²Ñ†Ñ Ð¿Ñ€Ð¾Ð¿ÑƒÑтили хід)" ::msgcat::mcset uk "Free-style Gomoku" "Вільне Гомоку" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/renju/pixmaps000075500000000000000000000000001500237002100162365ustar00nobodynobodytkabber-plugins/renju/pixmaps/black000075500000000000000000000000001500237002100173125ustar00nobodynobodytkabber-plugins/renju/pixmaps/black/b.gif000064400000000000000000000003301500237002100202750ustar00nobodynobodyGIF89aã  R b„•¦Çéêûÿ!ù ,…ÈIE9I©tŠ `(²œhŠf*«ƒ;s.¶¡ÿ(ƒ,ò(ƒ¢rQÅ–?D @€* ’§U‡¶J Øx1æ_&­Ó°s›÷Œ#—uê)õѾ»T{X~fRIrM7oG >fB.D[.0PŒ6„%@+S ;tkabber-plugins/renju/pixmaps/black/bot.gif000064400000000000000000000001331500237002100206410ustar00nobodynobodyGIF87a €ÿÿÿ, :„‘íœTÒÛ,Þ@óë}S(>d™1訮fë¦ñ;;ç|ÛËÎ÷þ ƒµ¢ñˆL*—̦ó J9;tkabber-plugins/renju/pixmaps/black/center.gif000064400000000000000000000001541500237002100213400ustar00nobodynobodyGIF87a €ÿÿÿ, K„‘íœTÒÛ,Þ@óë}S(>d™1訮f릱³œk]ÏŽƒü ‡D ï§ëð’»³ù<ØbSWõc^QÛRWôý„9ãM¸;tkabber-plugins/renju/pixmaps/black/icondef.xml000064400000000000000000000030611500237002100215220ustar00nobodynobody Black 1.0 Renju Black Theme. 2007-02-26 renju/b b.gif renju/w w.gif renju/bf bot.gif renju/tf top.gif renju/rf right.gif renju/lf left.gif renju/rbf right_bot.gif renju/rtf right_top.gif renju/lbf left_bot.gif renju/ltf left_top.gif renju/mf middle.gif renju/cf center.gif tkabber-plugins/renju/pixmaps/black/left.gif000064400000000000000000000001501500237002100210060ustar00nobodynobodyGIF87a €ÿÿÿ, G„‘íœTÒÛ,Þ@óë}S(>d™1訮fë¦ñ;;ç|ÇËÎ÷;ç ò€°š!çB®”(fÉ)‚~¤D£¢h¤n´.[“;tkabber-plugins/renju/pixmaps/black/left_bot.gif000064400000000000000000000001321500237002100216520ustar00nobodynobodyGIF87a €ÿÿÿ, 9„‘íœTÒÛ,Þ@óë}S(>d™1訮fë¦ñ;;ç|ÇËÎ÷;ç òjÄ¢ñˆL*—̦ó r ;tkabber-plugins/renju/pixmaps/black/left_top.gif000064400000000000000000000001251500237002100216720ustar00nobodynobodyGIF87a €ÿÿÿ, 4„©Ëí£œ´Ú‹³Þ¼û†¢”扖SÊžk@¡:Ë }Û¾ëÿóu€C!‡x4nŒ;tkabber-plugins/renju/pixmaps/black/middle.gif000064400000000000000000000001501500237002100213120ustar00nobodynobodyGIF87a €ÿÿÿ, G„‘íœTÒÛ,Þ@óë}S(>d™1訮fë¦ñ;;ç|ÛËÎ÷þ ƒœœË¸B¢”%¦Èùa5ƒtsÅdAÔê¶Ò­A ;tkabber-plugins/renju/pixmaps/black/right.gif000064400000000000000000000001501500237002100211710ustar00nobodynobodyGIF87a €ÿÿÿ, G„‘íœTÒÛ,Þ@óë}S(>d™1訮fë¦ñ;;ç|ÛËÎ÷yê þVCT±t%?KNsóÄDA°šaZ©Z±,«B[[;tkabber-plugins/renju/pixmaps/black/right_bot.gif000064400000000000000000000001321500237002100220350ustar00nobodynobodyGIF87a €ÿÿÿ, 9„‘íœTÒÛ,Þ@óë}S(>d™1訮fë¦ñ;;ç|ÛËÎ÷yê þjÄ¢ñˆL*—Ì¦ó ® ;tkabber-plugins/renju/pixmaps/black/right_top.gif000064400000000000000000000001241500237002100220540ustar00nobodynobodyGIF87a €ÿÿÿ, 3„©Ëí£œ´Ú‹³Þ¼û†â”扖dÊš¢ üÑžÝ᜾ñšŸb„¢ÅXAR”;tkabber-plugins/renju/pixmaps/black/top.gif000064400000000000000000000001261500237002100206610ustar00nobodynobodyGIF87a €ÿÿÿ, 5„©Ëí£œ´Ú‹³Þ¼û†â”扦êʶ,ˆ¥‡³]ƒ·ž»ßóü„ÁÎÐXä•IF;tkabber-plugins/renju/pixmaps/black/w.gif000064400000000000000000000003301500237002100203220ustar00nobodynobodyGIF89aã % /&icXwri”‰£Ÿ™²®©ÏÍÉìëêíìëûûûÿÿÿ!ù ,…ÈIE9I©tŠ `(²œhŠf*«ƒ;s.¶¡ÿ(ƒ,ò(ƒ¢rQÅ–?D @€* ’§U‡¶J Øx1æ_&­Ó°s›÷Œ#—uê)õѾ»T{X~fRIrM7oG >fB.D[.0PŒ6„%@+S ;tkabber-plugins/renju/pixmaps/stones000075500000000000000000000000001500237002100175515ustar00nobodynobodytkabber-plugins/renju/pixmaps/stones/b.gif000064400000000000000000000031341500237002100205410ustar00nobodynobodyGIF89açÿ               $!"! '%#$"%#$"2 0"3$&(&5%)+(0+:*7*"0,+-.,=,:,70=-01/=1C135375):5%954686D79;8C9*<>;S: ?A?<@MM@'LC#U@BDAZ??FHVC+MG1GHFPI.QG7HIQJKIUL,\K!PNAMOLMQSVOINSUcQ'cR.]QGdT*cS4_U5TVScU;`UEkW'hZ"XZXkY/hZ4k\%jZ;r\ h[EtZ,\^[h]Aq]-c^]r_4_a^{_$cebee]ifYd*hh`~h+gifwilnkqnaznR€pC‚nY‹o@rtqptwxtms=‡tNuwtuitt…wU‡yK†yQ”xH“xN}{{}z”|>™{E€w†|‚œ{R€€€Š…{‚„€…ˆ†„ˆ‡‰†‹ˆ˜‹Š‘†Œ§ŽUŽ˜’”©’R²N¬d²‘T‘–˜™’ž­•b—™•š—œ•šœ®—j­š_¹—Tšœ™šš¤²šf»™Už”¼™o¢¤ ¢Ÿ£¢šº g¶¡m¡¥•Ä ]¿£dÀ¡o¥§¤£¨«¨¦ª©¨ŸÃ§gÀªh¾ªnÇ©cȬ_Ƭr˪rƯgÕ­VÓ­\Û¬WߪWÜ­QϳXׯXÔ¯dÙ°RÔ²YÒ²_Ì´eвlØ´L×´Sà­`Ú²ZÙ²`ß°[Þ°aÔµhã³WÙ´pâ³]Ø·dܵdß¶^à·X׸qÝ·lÞ»aäºbÿÿÿ!ù ÿ,þÿ 8p7c¡$‰á²”3nûJœøÏ[³O}â¬9£… ”!7œ,j6¢Du"DˆÏ3`¢0Bƒ†OÞL \×+¤K•,YJ4èÏ0S’Ôˆ¡B„m&ëåši+«ªD }ÓˆŽ"`0Ó©SÔªTÖ©UÕªUשUÚ§XשVÕ«UÖ«UÖ«VÕ¬VÕ¬WÑ®XÖ¬VÖ¬XÖ­UÕ­XÙ«XÙ«YÖ­WÒ¯XÖ­XÒ¯Y×­WÙ¬WÙ¬XÒ­f×­YÒ­gØ­WÕ«jØ­XÚ¬X×®VÖ®YÚ¬YÓ­g×®XÙ­XÓ°YÓ°ZØ®XØ®YׯWׯXÙ®XØ®[Û­YدWÛ­ZدXÛ­[دYÔ²TÔ±ZدZÔ²UÔ±[Õ±YÙ¯YÜ­\Ù¯ZÛ®ZÛ®[Ú¯ZÜ®ZÙ°XÜ®[Õ³UÖ²XÕ³VÝ®\Ú°Zܯ[Ö³VÙ±YÚ°\زYÚ±Yݯ\Ö´VÖ´WÙ²ZݰZÞ¯]Û±[ݰ\߯]ܱ[Þ°[ݰ^ܱ\Þ°\Þ°]ß°]Þ±[ß°^ܲ\Þ±]ß±[ݲ\ܲ_Ú´[ß±^ܳ\ܳ]á°`à±^ݳ]á±_Þ³]à²_Ý´]ܵ\á²_Þ´^ݵ\â²_ܶZâ²aܶ]á³`ݶ[ä±cÞµ^ã²aݶ]ݶ^â³aßµ_á´`Ý·[â´^ßµaá´aàµ_ã³bÝ·]àµ`Ý·^ß¶^Þ·\áµ`ä³cÞ·^áµaÞ·_ã´bà¶`ã´cÞ¸\ß·_âµbß·`Þ¸^ß·a߸]߸^߸_߸`ã¶`äµcá·aä¶`ä¶aåµdß¹_â¸aä·aâ¸bâ¸dä·eã¸cå¸bã¹cæ¸bäºdå»e>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>, þW`ñ´#  s d´bŒ¥ ¬ÊpeEK+®ÔÉPçÊ ŒX>áØòBÂ…,B”HÑâŒ9z´ÔÃG'bþ,°óÆ!'gXuˆ¸ª!ÌT” z0hÌ R L:¦Gd(hâR£Uˆ„6|AT Ù(q6ìÁR‚ ›¦ŠdƒÒ˜Œº„p%$"¤f¡Ð2H- àhyÁȃLLâTrhÌKc2Àêñá†ÔóÀÍLÇ¡¦¤墑š˜WlîœásF†¤Ü”>m ”+§\èY“ ·lÎ<ƒ¶¸J·é¨oÌPÄÍk㳓×]çÁ*ÒÏ-þ9Τ£DžOÜ øžA–’ˆ?'íNŠt Ç#I¢½œõ­à|-Í—An á7Èxª]R~çF³¼€K)±‘q«(È •wôÑ E«€4 €Á§ÓP_!µK0md5FQ`¢‚AÒÄ×…=öEUÏ;tkabber-plugins/renju/pixmaps/stones/center.gif000064400000000000000000000030071500237002100215770ustar00nobodynobodyGIF89a ç>`0Ó©SÔªTÖ©UÕªUשUÚ§XשVÕ«UÖ«UÖ«VÕ¬VÕ¬WÑ®XÖ¬VÖ¬XÖ­UÕ­XÙ«XÙ«YÖ­WÒ¯XÖ­XÒ¯Y×­WÙ¬WÙ¬XÒ­f×­YÒ­gØ­WÕ«jØ­XÚ¬X×®VÖ®YÚ¬YÓ­g×®XÙ­XÓ°YÓ°ZØ®XØ®YׯWׯXÙ®XØ®[Û­YدWÛ­ZدXÛ­[دYÔ²TÔ±ZدZÔ²UÔ±[Õ±YÙ¯YÜ­\Ù¯ZÛ®ZÛ®[Ú¯ZÜ®ZÙ°XÜ®[Õ³UÖ²XÕ³VÝ®\Ú°Zܯ[Ö³VÙ±YÚ°\زYÚ±Yݯ\Ö´VÖ´WÙ²ZݰZÞ¯]Û±[ݰ\߯]ܱ[Þ°[ݰ^ܱ\Þ°\Þ°]ß°]Þ±[ß°^ܲ\Þ±]ß±[ݲ\ܲ_Ú´[ß±^ܳ\ܳ]á°`à±^ݳ]á±_Þ³]à²_Ý´]ܵ\á²_Þ´^ݵ\â²_ܶZâ²aܶ]á³`ݶ[ä±cÞµ^ã²aݶ]ݶ^â³aßµ_á´`Ý·[â´^ßµaá´aàµ_ã³bÝ·]àµ`Ý·^ß¶^Þ·\áµ`ä³cÞ·^áµaÞ·_ã´bà¶`ã´cÞ¸\ß·_âµbß·`Þ¸^ß·a߸]߸^߸_߸`ã¶`äµcá·aä¶`ä¶aåµdß¹_â¸aä·aâ¸bâ¸dä·eã¸cå¸bã¹cæ¸bäºdå»e>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>, þW`ñ´#  s d´bŒ¥ ¬ÊpeEK+®ÔÉPçÊ ŒX>áØòBÂ…,B”HÑâŒ9z´ÔÃG'bþ,°óÆ!'gXuˆ¸ª!ÌT” z0hÌ R L:¦Gd(hâR£Uˆ„6|AT Ù(q6ìÁR‚ ›¦ŠdƒÒ˜Œº„p%$"¤f¡Ð2H- àhyÁȃLLâTrhÌKc2Àêñá†ÔóÀÍLÇ¡¦¤墑š˜WlîœásF†¤Ü”>m ”+§\èY“ ·lÎ<ƒ¶¸J·é¨oÌPÄÍk㳓×]çÁ*ÒÏ-þ9Τ£DžOÜ øžA–’ˆ?'íNŠt Ç#I¢½œõ­à|-Í—An á7Èxª]R~çF³¼€K)±‘q«(È • Ô =ÐyÅBˆ g)hJ2BEÀR—mTÑ wж(CŽbé’´Àæ* Ó¦=t×TîÅÀ‡¨‘Žà†n¤`Qw«zV‡œc$º‚¬´’*CS¢¥¯š>4ȯc\Ñê @Ì*J$pf h´BDºõš%zäÔ|¨pf¶PÔîFà> .).ÙY"º;ÄÒ†¨1ˆK¿î*¯¦Ý*Ó=àû   "ÜÝ·k¦^¡Û 3­0D!)r »­E´­Êœ `<®Æ…XP9„¼‘Cm&qKœ’@G+/ñH UÐAÂ"DÀZ›%8²ÄãK7wôÑ >«4 €qçÑIO´4L9Q˜¨`Ѐ4qµCYWÌõÁ–;tkabber-plugins/renju/pixmaps/stones/icondef.xml000064400000000000000000000030631500237002100217630ustar00nobodynobody Stones 1.0 Renju Stones Theme. 2007-02-15 renju/b b.gif renju/w w.gif renju/bf bot.gif renju/tf top.gif renju/rf right.gif renju/lf left.gif renju/rbf right_bot.gif renju/rtf right_top.gif renju/lbf left_bot.gif renju/ltf left_top.gif renju/mf middle.gif renju/cf center.gif tkabber-plugins/renju/pixmaps/stones/left.gif000064400000000000000000000030451500237002100212530ustar00nobodynobodyGIF89a ç>`0Ó©SÖ¨TÔªTÖ©UÕªUשUÚ§XשVÕ«UÖ«UÖ«VتWÕ¬VÕ¬WÑ®XÖ¬VÖ¬XѬfÖ­UÕ­XÙ«XÙ«YÖ­WÒ¯XÖ­XÒ¯Y×­WÙ¬WÙ¬XÒ­f×­YÒ­gØ­WÕ«jØ­XÚ¬X×®VÖ®YÚ¬YÓ­g×®W×®XÙ­XÓ°YÓ°ZØ®XØ®YׯWׯXÙ®XØ®[Û­YدWÛ­ZدXÛ­[دYÔ²TÔ±ZدZÔ²UÔ±[Õ±YÙ¯YÜ­\Ù¯ZÛ®ZÛ®[Ú¯ZÜ®ZÙ°XÜ®[Õ³UÖ²XÕ³VÝ®\Ú°Zܯ[Ö³VÙ±YÚ°\زYÚ±Yݯ\Ö´VÖ´WÙ²ZݰZÞ¯]Û±[ݰ\߯]ܱ[Þ°[ݰ^ܱ\Þ°\Ù³ZÞ°]ß°]Þ±[ß°^ܲ\Þ±]ß±[ݲ\ܲ_Ú´[ß±^ܳ\ܳ]á°`à±^ݳ]ß²^á±_Þ³]à²_Ý´]ܵ\á²_Þ´^ݵ\â²_ܶZâ²aܶ]á³`ݶ[ä±cÞµ^ã²aݶ]ݶ^â³aßµ_á´`Ý·[Þ¶^â´^ßµaá´aàµ_ã³bÝ·]àµ`Ý·^ß¶^Þ·\áµ`ä³cÞ·^áµaÞ·_ã´bà¶`ã´cÞ¸\ß·_âµbß·`ä´cÞ¸^ß·a߸]߸^߸_߸`ã¶`äµcá·aä¶`ä¶aåµdß¹_â¸aä·aâ¸bâ¸dä·eã¸cå¸bã¹cæ¸bäºdå»e`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0, þ_p1õÃŒž y¨pHôM'Ìâ°%ÅN/¶ìá°gË Œ\NñøRGBÂ…0B”HÑâŒ9zìDH) g 1à3„†#)lhˆ8«!ÌXœ$ŠÍ V#hZgP‡Ji.„“£V‘ˆŠ} •-¯d‚£ ·lÎ<ƒ¶8K·é¨w܈ä Ík㳓×½'Â,ÒÏ;þ9åÅŸSæøÎA—“ˆ?'íΊôž Ç3i =õ½à|-ÍÇAn á—Èxªy‚„7G»¼€K9±‘q³(Èàœ<¸lsȶ˜[¸8‘ßcL$‰ é‘A''^X †:ÕáB°‰D‚Cz7ΡÀ.•¢†7föc" Àˆ Œ¢Â„DSœ æ˜d– tX,eh€Š )€Kw`çxæÉ‚¬Ù曟ÉIç…8¡›†/ì±ÔN¼`Ñ ~làJ›¤P ºèF ”J½Ä¢[,ÄA ‘¶Òf&p&"Àœ+¹´QEþ/8*Z¨ ‘º©dC ³0„â« Ñ]SA`Tƒ ·žjº±‚QDÝÅôRm{$ŠÆ§/›l®64%š¯DûêC‰T‹Æ¾@²ªtq)T`¦€F/D¤›´u’¡GN!ˆ l¾KÅ÷ndoøèR£%úûC.rT ‰¸Zo¸Ë³29„÷èñ,6(šÑ}ÐR¤ñº%2Ó G,ÒB#}œ@òæZD›´ %ª€Ë`sjèÑÃÍ9¤@g'·k"K†ŠÑ–´…'H‚D±µuQ¾ÔtG½@µ WŸ`Žvý5K)ŠÙUñ‰ i`H m;ôöDqôÝ;tkabber-plugins/renju/pixmaps/stones/left_bot.gif000064400000000000000000000030521500237002100221150ustar00nobodynobodyGIF89a ç>`0Ó©SÖ¨TÔªTÖ©UÕªUשUÚ§XשVÕ«UÖ«UÖ«VتWÕ¬VÕ¬WÑ®XÖ¬VÖ¬XѬfÖ­UÕ­XÙ«XÙ«YÖ­WÒ¯XÖ­XÒ¯Y×­WÙ¬WÙ¬XÒ­f×­YÒ­gØ­WÕ«jØ­XÚ¬X×®VÖ®YÚ¬YÓ­g×®W×®XÙ­XÓ°YÓ°ZØ®XØ®YׯWׯXÙ®XØ®[Û­YدWÛ­ZدXÛ­[دYÔ²TÔ±ZدZÔ²UÔ±[Õ±YÙ¯YÜ­\Ù¯ZÛ®ZÛ®[Ú¯ZÜ®ZÙ°XÜ®[Õ³UÖ²XÕ³VÝ®\Ú°Zܯ[Ö³VÙ±YÚ°\زYÚ±Yݯ\Ö´VÖ´WÙ²ZݰZÞ¯]Û±[ݰ\߯]ܱ[Þ°[ݰ^ܱ\Þ°\Ù³ZÞ°]ß°]Þ±[ß°^ܲ\Þ±]ß±[ݲ\ܲ_Ú´[ß±^ܳ\ܳ]á°`à±^ݳ]ß²^á±_Þ³]à²_Ý´]ܵ\á²_Þ´^ݵ\â²_ܶZâ²aܶ]á³`ݶ[ä±cÞµ^ã²aݶ]ݶ^â³aßµ_á´`Ý·[Þ¶^â´^ßµaá´aàµ_ã³bÝ·]àµ`Ý·^ß¶^Þ·\áµ`ä³cÞ·^áµaÞ·_ã´bà¶`ã´cÞ¸\ß·_âµbß·`ä´cÞ¸^ß·a߸]߸^߸_߸`ã¶`äµcá·aä¶`ä¶aåµdß¹_â¸aä·aâ¸bâ¸dä·eã¸cå¸bã¹cæ¸bäºdå»e>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>, þ_p1õÃŒž y¨pHôM'Ìâ°%ÅN/¶ìá°gË Œ\NñøRGBÂ…0B”HÑâŒ9zìDH) g 1à3„†#)lhˆ8«!ÌXœ$ŠÍ V#hZgP‡Ji.„“£V‘ˆŠ} •-¯d‚£ ·lÎ<ƒ¶8K·é¨w܈ä Ík㳓×½'Â,ÒÏ;þ9åÅŸSæøÎA—“ˆ?'íΊôž Ç3i =õ½à|-ÍÇAn á—Èxªy‚„7G»¼€K9±‘q³(Èàœ<¸lsȶ˜[¸8‘ßcL$‰ é‘A''^X †:ÕáB°‰D‚Cz7ΡÀ.•¢†7föc" Àˆ Œ¢Â„DSœ æ˜d– tX,eh€Š )€KwÔiçxÖÉ‚¬Ù曟ÉÙ]"¡9¡›†/ì±ÔN¼`Ñ ~làJ›¤P ºè†c†Ý)õB‹n±%DÚJ›™À™ˆsr°)EþUô‚£¢‰ÊP©œªA&1: C„º+CA ŠFÕ H®¨š0‡n¬`Dhw1½TÛ‰˲ÌîjCS¢1„#µ±>”¶hlQì D,«J'Bf hôѺUûP'zäÔ‚¸Àf¼Tì‘F ï.5Z"À?ä"G° ‘ˆ°Oi¤ð°<+“£A@|‹Àbƒ¢ÝÇJµãËÔL/±H ôq‚És kÑhUËP¢ êjÌ‹d †=༑C  áPÊ-͚Ȓ¢bô„%-d¡Ç ’ lmDîD)¾uG½pµ ZŸ`Ž‚-öd»ÓFhcTÅ'.¤!QÄíÐÜu_töL;tkabber-plugins/renju/pixmaps/stones/left_top.gif000064400000000000000000000030531500237002100221340ustar00nobodynobodyGIF89a ç>`0Ó©SÖ¨TÔªTÖ©UÕªUשUÚ§XשVÕ«UÖ«UÖ«VتWÕ¬VÕ¬WÑ®XÖ¬VÖ¬XѬf׬WÖ­UÕ­XÙ«XÙ«YÖ­WÒ¯XÖ­XÒ¯Y×­WÙ¬WÙ¬XÒ­f×­YÒ­gØ­WÕ«jØ­XÚ¬X×®VÖ®YÚ¬YÓ­g×®W×®XÙ­XÓ°YÓ°ZØ®XØ®YׯWׯXÙ®XØ®[Û­YدWÛ­ZدXÛ­[دYÔ²TÔ±ZدZÔ²UÔ±[Õ±YÙ¯YÜ­\Ù¯ZÛ®ZÛ®[Ú¯ZÜ®ZÙ°XÜ®[Õ³UÖ²XÕ³VÝ®\Ú°Zܯ[Ö³VÙ±YÚ°\زYÚ±Yݯ\Ö´VÖ´WÙ²ZݰZÞ¯]Û±[ݰ\߯]ܱ[Þ°[ݰ^ܱ\Þ°\Ù³ZÞ°]Þ°^ß°]Þ±[ß°^ܲ\Þ±]ß±[ݲ\ܲ_Ú´[ß±^ܳ\ܳ]á°`à±^ݳ]ß²^ݳ_á±_Þ³]à²_Ý´]ܵ\á²_Þ´^ݵ\â²_ܶZâ²aܶ]á³`ݶ[ä±cÞµ^ã²aݶ]ݶ^â³aßµ_á´`Ý·[Þ¶^â´^ßµaá´aàµ_ã³bÝ·]àµ`Ý·^ß¶^Þ·\áµ`ä³cÞ·^áµaÞ·_ã´bà¶`ã´cÞ¸\ß·_âµbß·`ä´cÞ¸^ß·a߸]߸^߸_߸`ã¶`äµcá·aä¶`ä¶aåµdß¹_â¸aä·aâ¸bâ¸dä·eã¸cå¸bã¹cæ¸bäºdå»e`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0, þatIM |ªt`C ¨u¸ØêÀ…EP0¸øéà‡ Œ]TõƒGBÂ…1B”HÑ"Œ9z%dª i1øC¤F¤)nn…¸#±!LZž0ŠÀH ŒW$tb2ÇLk0 £—3}(#)E—²Vô| Ô%E# JaY´i‡'5,‰)‘ëH šF´™Ôâ £_¾,Èó…†%FEÑói†"5@©é°KH‡Õ0¬Áš?Bf…Ž«—â(Ð £óçУ¾ªƒzæê+[dÍ$GÁîÚžAwÑ¢-Þ©A­æƒ’ƒ7²ÛVÎ\c[§£þCõ#… Têߡד'L—[|â'«Ó~<3ßÄ %ô{p îÁçÒ|í¶~ãµJYb\Bøò ñU”T‚uÀ` ƒ‘a‘Æ'ú1[‡»x”!‚ì&Ä.O,ÄŸ”ÌÞ‰€¢â¶èÔ‡ P€'K\@IéåX‡~`0Ó©SÔªTÖ©UÕªUשUÚ§XשVÕ«UÖ«UÖ«VÕ¬VÕ¬WÑ®XÖ¬VÖ¬XÖ­UÕ­XÙ«XÙ«YÖ­WÒ¯XÖ­XÒ¯Y×­WÙ¬WÙ¬XÒ­f×­YÒ­gØ­WÕ«jØ­XÚ¬X×®VÖ®YÚ¬YÓ­g×®XÙ­XÓ°YÓ°ZØ®XØ®YׯWׯXÙ®XØ®[Û­YدWÛ­ZدXÛ­[دYÔ²TÔ±ZدZÔ²UÔ±[Õ±YÙ¯YÜ­\Ù¯ZÛ®ZÛ®[Ú¯ZÜ®ZÙ°XÜ®[Õ³UÖ²XÕ³VÝ®\Ú°Zܯ[Ö³VÙ±YÚ°\زYÚ±Yݯ\Ö´VÖ´WÙ²ZݰZÞ¯]Û±[ݰ\߯]ܱ[Þ°[ݰ^ܱ\Þ°\Þ°]ß°]Þ±[ß°^ܲ\Þ±]ß±[ݲ\ܲ_Ú´[ß±^ܳ\ܳ]á°`à±^ݳ]á±_Þ³]à²_Ý´]ܵ\á²_Þ´^ݵ\â²_ܶZâ²aܶ]á³`ݶ[ä±cÞµ^ã²aݶ]ݶ^â³aßµ_á´`Ý·[â´^ßµaá´aàµ_ã³bÝ·]àµ`Ý·^ß¶^Þ·\áµ`ä³cÞ·^áµaÞ·_ã´bà¶`ã´cÞ¸\ß·_âµbß·`Þ¸^ß·a߸]߸^߸_߸`ã¶`äµcá·aä¶`ä¶aåµdß¹_â¸aä·aâ¸bâ¸dä·eã¸cå¸bã¹cæ¸bäºdå»e`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0, þW`ñ´#  s d´bŒ¥ ¬ÊpeEK+®ÔÉPçÊ ŒX>áØòBÂ…,B”HÑâŒ9z´ÔÃG'bþ,°óÆ!'gXuˆ¸ª!ÌT” z0hÌ R L:¦Gd(hâR£Uˆ„6|AT Ù(q6ìÁR‚ ›¦ŠdƒÒ˜Œº„p%$"¤f¡Ð2H- àhyÁȃLLâTrhÌKc2Àêñá†ÔóÀÍLÇ¡¦¤墑š˜WlîœásF†¤Ü”>m ”+§\èY“ ·lÎ<ƒ¶¸J·é¨oÌPÄÍk㳓×]çÁ*ÒÏ-þ9Τ£DžOÜ øžA–’ˆ?'íNŠt Ç#I¢½œõ­à|-Í—An á7Èxª]R~çF³¼€K)±‘q«(È •4Ȱc\ë @Ø*J$pf h´BDºû%zäÔ|¨f·PÔQîFä>`î.íY"»;ÄÒ†¨1§ã>k¯«è*Ÿ=ðû   "žÝç+E_¡Û 3­0D!)r »A­E´ËÐ pœF[P9”¼‘C tVqKŸ²ä£-ñH UÐAÂ"DÌZ›%UàK;wôÑ B«P4 €ÁçÒM³”"Ô1IQ˜¨`Ѐ4±µC]Oô5L‰;tkabber-plugins/renju/pixmaps/stones/right.gif000064400000000000000000000030261500237002100214350ustar00nobodynobodyGIF89a ç>`0Ó©SÔªTÖ©UÕªUשUÚ§XשVÕ«UÖ«UÖ«VÕ¬VÕ¬WÑ®XÖ¬VÖ¬XÖ­UÕ­XÙ«XÙ«YÖ­WÒ¯XÖ­XÒ¯Y×­WÙ¬WÙ¬XÒ­f×­YÒ­gØ­WÕ«jØ­XÚ¬X×®VÖ®YÚ¬YÓ­g×®XÙ­XÓ°YÓ°ZØ®XØ®YׯWׯXÙ®XØ®[Û­YدWÛ­ZدXÛ­[دYÔ²TÔ±ZدZÔ²UÔ±[Õ±YÙ¯YÜ­\Ù¯ZÛ®ZÛ®[Ú¯ZÜ®ZÙ°XÜ®[Õ³UÖ²XÕ³VÝ®\Ú°Zܯ[Ö³VÙ±YÚ°\زYÚ±Yݯ\Ö´VÖ´WÙ²ZݰZÞ¯]Û±[ݰ\߯]ܱ[Þ°[ݰ^ܱ\Þ°\Þ°]ß°]Þ±[ß°^ܲ\Þ±]ß±[ݲ\ܲ_Ú´[ß±^ܳ\ܳ]á°`à±^ݳ]á±_Þ³]à²_Ý´]ܵ\á²_Þ´^ݵ\â²_ܶZâ²aܶ]á³`ݶ[ä±cÞµ^ã²aݶ]ݶ^â³aßµ_á´`Ý·[â´^ßµaá´aàµ_ã³bÝ·]àµ`Ý·^ß¶^Þ·\áµ`ä³cÞ·^áµaÞ·_ã´bà¶`ã´cÞ¸\ß·_âµbß·`Þ¸^ß·a߸]߸^߸_߸`ã¶`äµcá·aä¶`ä¶aåµdß¹_â¸aä·aâ¸bâ¸dä·eã¸cå¸bã¹cæ¸bäºdå»e>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>, þW`ñ´#  s d´bŒ¥ ¬ÊpeEK+®ÔÉPçÊ ŒX>áØòBÂ…,B”HÑâŒ9z´ÔÃG'bþ,°óÆ!'gXuˆ¸ª!ÌT” z0hÌ R L:¦Gd(hâR£Uˆ„6|AT Ù(q6ìÁR‚ ›¦ŠdƒÒ˜Œº„p%$"¤f¡Ð2H- àhyÁȃLLâTrhÌKc2Àêñá†ÔóÀÍLÇ¡¦¤墑š˜WlîœásF†¤Ü”>m ”+§\èY“ ·lÎ<ƒ¶¸J·é¨oÌPÄÍk㳓×]çÁ*ÒÏ-þ9Τ£DžOÜ øžA–’ˆ?'íNŠt Ç#I¢½œõ­à|-Í—An á7Èxª]R~çF³¼€K)±‘q«(È •4Ȳc\ë @ø*J$pf h´BDº!û%zäÔ|¨@g¹PÔÑîFìn™í.¹Y"½;ÄÒ†¨1©ë^ëoÂÊôf¿BG¨ÈhF÷K‘­é6ÈL+ QH †ÜABÆnpkmÈ2Äl#g€‘É”AG,oäPqÜÒ©lvdó K<’Bt°»ÖfÉDø’Ð}„ô#*0M D¼)5Õ,¥xuLYc&*t MˆíÙ™ ÓFi;tkabber-plugins/renju/pixmaps/stones/right_bot.gif000064400000000000000000000030351500237002100223010ustar00nobodynobodyGIF89a ç>`0Ó©SÔªTÖ©UÕªUשUÚ§XשVÕ«UÖ«UÖ«VÕ¬VÕ¬WÑ®XÖ¬VÖ¬XÖ­UÕ­XÙ«XÙ«YÖ­WÒ¯XÖ­XÒ¯Y×­WÙ¬WÙ¬XÒ­f×­YÒ­gØ­WÕ«jØ­XÚ¬X×®VÖ®YÚ¬YÓ­g×®XÙ­XÓ°YÓ°ZØ®XØ®YׯWׯXÙ®XØ®[Û­YدWÛ­ZدXÛ­[دYÔ²TÔ±ZدZÔ²UÔ±[Õ±YÙ¯YÜ­\Ù¯ZÛ®ZÛ®[Ú¯ZÜ®ZÙ°XÜ®[Õ³UÖ²XÕ³VÝ®\Ú°Zܯ[Ö³VÙ±YÚ°\زYÚ±Yݯ\Ö´VÖ´WÙ²ZݰZÞ¯]Û±[ݰ\߯]ܱ[Þ°[ݰ^ܱ\Þ°\Þ°]ß°]Þ±[ß°^ܲ\Þ±]ß±[ݲ\ܲ_Ú´[ß±^ܳ\ܳ]á°`à±^ݳ]á±_Þ³]à²_Ý´]ܵ\á²_Þ´^ݵ\â²_ܶZâ²aܶ]á³`ݶ[ä±cÞµ^ã²aݶ]ݶ^â³aßµ_á´`Ý·[â´^ßµaá´aàµ_ã³bÝ·]àµ`Ý·^ß¶^Þ·\áµ`ä³cÞ·^áµaÞ·_ã´bà¶`ã´cÞ¸\ß·_âµbß·`Þ¸^ß·a߸]߸^߸_߸`ã¶`äµcá·aä¶`ä¶aåµdß¹_â¸aä·aâ¸bâ¸dä·eã¸cå¸bã¹cæ¸bäºdå»e`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0, þW`ñ´#  s d´bŒ¥ ¬ÊpeEK+®ÔÉPçÊ ŒX>áØòBÂ…,B”HÑâŒ9z´ÔÃG'bþ,°óÆ!'gXuˆ¸ª!ÌT” z0hÌ R L:¦Gd(hâR£Uˆ„6|AT Ù(q6ìÁR‚ ›¦ŠdƒÒ˜Œº„p%$"¤f¡Ð2H- àhyÁȃLLâTrhÌKc2Àêñá†ÔóÀÍLÇ¡¦¤墑š˜WlîœásF†¤Ü”>m ”+§\èY“ ·lÎ<ƒ¶¸J·é¨oÌPÄÍk㳓×]çÁ*ÒÏ-þ9Τ£DžOÜ øžA–’ˆ?'íNŠt Ç#I¢½œõ­à|-Í—An á7Èxª]R~çF³¼€K)±‘q«(È •4ȳc\Áë @+J$pf hôѺ1û%zäÔ|¨@gºPÔï†Ê{ Kn–ˆï±´!*D ’ëSm©kÆÊôf¿BG¨È hF÷‘ÂìÄð25Ó C’‚!wбàZ4ÚCÌ2m}–Šr!”AG/oäPc8rKª²Ù‘ÎK<’Bt°¿ÖfÉáN”âKGwôÑ M«5 €ñ¦ÕX_¡µK0mä5FQ`¢‚AÒÄÙ¥½öE]Ï;tkabber-plugins/renju/pixmaps/stones/right_top.gif000064400000000000000000000030361500237002100223200ustar00nobodynobodyGIF89a ç>`0Ó©SÔªTÖ©UÕªUשUÚ§XשVÕ«UÖ«UÖ«VÕ¬VÕ¬WÑ®XÖ¬VÖ¬X׬WÖ­UÕ­XÙ«XÙ«YÖ­WÒ¯XÖ­XÒ¯Y×­WÙ¬WÙ¬XÒ­f×­YÒ­gØ­WÕ«jØ­XÚ¬X×®VÖ®YÚ¬YÓ­g×®XÙ­XÓ°YÓ°ZØ®XØ®YׯWׯXÙ®XØ®[Û­YدWÛ­ZدXÛ­[دYÔ²TÔ±ZدZÔ²UÔ±[Õ±YÙ¯YÜ­\Ù¯ZÛ®ZÛ®[Ú¯ZÜ®ZÙ°XÜ®[Õ³UÖ²XÕ³VÝ®\Ú°Zܯ[Ö³VÙ±YÚ°\زYÚ±Yݯ\Ö´VÖ´WÙ²ZݰZÞ¯]Û±[ݰ\߯]ܱ[Þ°[ݰ^ܱ\Þ°\Þ°]Þ°^ß°]Þ±[ß°^ܲ\Þ±]ß±[ݲ\ܲ_Ú´[ß±^ܳ\ܳ]á°`à±^ݳ]ݳ_á±_Þ³]à²_Ý´]ܵ\á²_Þ´^ݵ\â²_ܶZâ²aܶ]á³`ݶ[ä±cÞµ^ã²aݶ]ݶ^â³aßµ_á´`Ý·[â´^ßµaá´aàµ_ã³bÝ·]àµ`Ý·^ß¶^Þ·\áµ`ä³cÞ·^áµaÞ·_ã´bà¶`ã´cÞ¸\ß·_âµbß·`Þ¸^ß·a߸]߸^߸_߸`ã¶`äµcá·aä¶`ä¶aåµdß¹_â¸aä·aâ¸bâ¸dä·eã¸cå¸bã¹cæ¸bäºdå»e>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>, þYd ÅcÌ v¢h0Ä¢L& p°¸Ò€ÅÅL,°àÑ€ ŒYDåà"BÂ…-B”HÑ"Œ9zÌäã¨d-È$†¢'i^yˆ#±!LV–z`¨ ‹S!XBâІHf*têb–0q³ÈD–²Rèpð“ÅÄ¡ز ñU”T‚p°à ƒ‘QA&â1[‡³x”!‚ìæÃ,K,ÄŸ¼Þ‰d¢â¶èÔ‡ u@À%GPÐH éåGx,áShH_Ž›iXf©å–X.%¥‰Mi`ed–iæ™d.µoô}d“ZôÅ´"£ Z³Ô@j²‰ x,GœаG©Üù‰J P o"ø€R,ø`( i0¢¨ÜY  Ч•R´QE,°°TGþ ±ði¡bP‰ {ºÂPª1±êC}Mù€‘ Ð** pðv FÖ×khƒš¦) Äkë M•¶kήú!ƒ–ů,Ql)Z”ðIš%  òö,hóyä¬`§ºQà!ïFñFém‹.]Ø!¾<ÐòÆ«aˆKƒ6+pKÁ!“«> ,Ë ¬2C¡å׬ªcÁ›!3±@"*$¢G îE>Ô+C„&€2h*#rÁwèóF%PsÈ-µú&¬1!‰ VÜQ‚#E»\&ü9‘†/!ÝÑG,8½BÔ% R„«WgÀÖ.Á´Ñ×I±É a0ˆh;¤6Ûy=S@;tkabber-plugins/renju/pixmaps/stones/top.gif000064400000000000000000000030251500237002100211210ustar00nobodynobodyGIF89a ç>`0Ó©SÔªTÖ©UÕªUשUÚ§XשVÕ«UÖ«UÖ«VÕ¬VÕ¬WÑ®XÖ¬VÖ¬X׬WÖ­UÕ­XÙ«XÙ«YÖ­WÒ¯XÖ­XÒ¯Y×­WÙ¬WÙ¬XÒ­f×­YÒ­gØ­WÕ«jØ­XÚ¬X×®VÖ®YÚ¬YÓ­g×®XÙ­XÓ°YÓ°ZØ®XØ®YׯWׯXÙ®XØ®[Û­YدWÛ­ZدXÛ­[دYÔ²TÔ±ZدZÔ²UÔ±[Õ±YÙ¯YÜ­\Ù¯ZÛ®ZÛ®[Ú¯ZÜ®ZÙ°XÜ®[Õ³UÖ²XÕ³VÝ®\Ú°Zܯ[Ö³VÙ±YÚ°\زYÚ±Yݯ\Ö´VÖ´WÙ²ZݰZÞ¯]Û±[ݰ\߯]ܱ[Þ°[ݰ^ܱ\Þ°\Þ°]Þ°^ß°]Þ±[ß°^ܲ\Þ±]ß±[ݲ\ܲ_Ú´[ß±^ܳ\ܳ]á°`à±^ݳ]ݳ_á±_Þ³]à²_Ý´]ܵ\á²_Þ´^ݵ\â²_ܶZâ²aܶ]á³`ݶ[ä±cÞµ^ã²aݶ]ݶ^â³aßµ_á´`Ý·[â´^ßµaá´aàµ_ã³bÝ·]àµ`Ý·^ß¶^Þ·\áµ`ä³cÞ·^áµaÞ·_ã´bà¶`ã´cÞ¸\ß·_âµbß·`Þ¸^ß·a߸]߸^߸_߸`ã¶`äµcá·aä¶`ä¶aåµdß¹_â¸aä·aâ¸bâ¸dä·eã¸cå¸bã¹cæ¸bäºdå»e`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0, þYd ÅcÌ v¢h0Ä¢L& p°¸Ò€ÅÅL,°àÑ€ ŒYDåà"BÂ…-B”HÑ"Œ9zÌäã¨d-È$†¢'i^yˆ#±!LV–z`¨ ‹S!XBâІHf*têb–0q³ÈD–²Rèpð“ÅÄ¡ز ñU”T‚p°à ƒ‘QA&â1[‡³x”!‚ìæÃ,K,ÄŸ¼Þ‰d¢â¶èÔ‡ u@À%GPÐH éåGx,áShH_Ž›iXf©å–\v©e`†)æ˜d–)¦_üá@+b`0 ¢%0K}°Ô¼ÑÇKÁq¡E4ì‘A*m~"RÔÂ[>  >ô‰ÅBŒ (*mVBBEÌ©£mT ,,ÕÑB,Xš¦TâBœü®0jL£úP_S>`$ëfJ¼‚QõÑ{–) »öÚê M•&kÅŠú!È–…­,Ák)Z”ðIš%  uòf,hóyä¬À¦¸Qà¡îFéFim‹.]Ø!¼<ÐòÆ«aˆKÈ«oKÁ!S©>,Ë ¬2ŸåGl¨ cÁ›!3±@"*$¢G Ñ­Eu>D+C{&2h"#rÁwèòF%ÐrÆ-‘j““bÄ„$*XqG Ž‘ër™Z,„#&GuÓÈiÓnصe¹šÛ„ •ÿô±ò³Ê@QâÞÅÓÇÏe×ìâ™Cæ-Wµj§J4‰VÿC§n^>~­+ó‹çn2Á® ßòµˆS©5'rü+Ô­¹yõüþ‰çׯŸ>sæ´å²Ö+Õ°I§N±I4êGˆ¡¾y#WoÞëòþè“5Üô‚ 4®øÂ‹!¨B…!cLC0àp£T<ÈíƒÜ<ñƒ 5Ö¸’ $©tÂ*fPA†%0“Þ9ÜÌÃŽ>øÔÃ9Þ¬Ã^5ºùRŠ*¥H‰$TaÊ4ƒc:à¸c=F¹ƒL3Ú¤’ 4±ŒâJ#±$²H €dC²4C 5àTÓŽ6èã5´@$¹øÒI*ªLRÉdd± ãM4Û,S/éübŽ5Ë4å 2´tòK)†X²Ç‹p!Ä*P 8ÇlÓLRõ¢ -ÈèÖK/ŸÜ¹H"þŒ1 B‘¡  1ÔÜrh5¨VX'»œbH)¥ÌÁ#Y°Á0PÈ3»43Í1Ë,s 5ª4s -½”òÉ.‹ìAés°!D<@A°ì‚5»°âK.®ÐB‹%´¤²jˆBtÑE. ­ÌÂK,¶“Š/¦„K ¥±t²È'‰4ðB p„°°Â‹*º Ë-¦¤J¤€XÂÆ ¨!W\á $`CArÌÂJ*³è"É-œ|‚q$Ò3j¡ƒ7T@À!!Ç%§”bI‰ ¢1 ’°ÈMpÁÅFÜ -}d²Èš$“ #†°a¦{\QxAø Ã8€BEnD’Òˆ!ˆ ² <_Q„E¡ƒ,ÀµEp AC~”{fHÁF!7  @ýsF/hðCŒDAA0`p ¬Ðû@z̰Á¤C,˜P°@5L_Ñ3„ €€ Hð @;tkabber-plugins/renju/proto000064400000000000000000000034531500237002100157270ustar00nobodynobodyRequest: 600 -- for all players 10 -- if on black side played Kasparov Positive response: or simply ? Turn: 'pos' attribute contains coordinates of piece. Coordinate is a comma-separated list of integers >= 0. Skipping the move: Proposing draw: Accepting draw proposal: Resigning: Also we need and tags for games where we must put or remove pieces. can have 'type' and 'color' attributes. move, put & destroy tags may have some game-specific subtags. Response: if move accepted, or error 'Not Acceptable' if other side thinks that this move illegal. tkabber-plugins/renju/renju.tcl000064400000000000000000001366641500237002100165030ustar00nobodynobody# renju.tcl -- # # This file implements Renju/Gomoku game plugin for the Tkabber XMPP # client. package require msgcat namespace eval renju { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered renju]} { ::plugins::register renju \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the\ Gomoku/Renju plugin\ is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable square_size [expr {31*$::icons_scale}] variable line_width $::icons_scale variable themes variable dirs \ [glob -nocomplain -directory [file join [file dirname [info script]] \ pixmaps] *] variable dir foreach dir $dirs { pixmaps::load_theme_name [namespace current]::themes $dir } variable values {} variable theme foreach theme [lsort [array names themes]] { lappend values $theme $theme } variable game_names_list \ [list \ renju [::msgcat::mc "Renju"] \ gomoku:freestyle [::msgcat::mc "Free-style Gomoku"] \ gomoku:standard [::msgcat::mc "Standard Gomoku"] \ gomoku:tournament [::msgcat::mc "Tournament Gomoku"] \ ] variable game_names array set game_names $game_names_list variable options custom::defgroup Plugins [::msgcat::mc "Plugins options."] -group Tkabber custom::defgroup Gomoku/Renju \ [::msgcat::mc "Gomoku/Renju plugin options."] -group Plugins custom::defvar options(theme) Stones \ [::msgcat::mc "Gomoku/Renju figures theme."] -group Gomoku/Renju \ -type options -values $values \ -command [namespace current]::load_stored_theme custom::defvar options(game) renju \ [::msgcat::mc "Default game variant."] -group Gomoku/Renju \ -type options \ -values $game_names_list custom::defvar options(show_last_move) 0 \ [::msgcat::mc "Show last move by default."] \ -type boolean -group Gomoku/Renju custom::defvar options(show_tooltips) 1 \ [::msgcat::mc "Show tooltips with short instructions."] \ -type boolean -group Gomoku/Renju \ -command [list [namespace current]::set_tooltips] custom::defvar options(sound) "" \ [::msgcat::mc "Sound to play after opponent's turn"] \ -type file -group Gomoku/Renju custom::defvar options(allow_illegal) 0 \ [::msgcat::mc "Allow illegal moves (useful for debugging)."] \ -type boolean -group Gomoku/Renju custom::defvar options(accept_illegal) 0 \ [::msgcat::mc "Accept opponent illegal moves (useful\ for debugging)."] \ -type boolean -group Gomoku/Renju } proc renju::load {} { hook::add roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.3 hook::add chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.3 hook::add roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.3 hook::add games_board_create_hook [namespace current]::iq_create hook::add games_board_turn_hook [namespace current]::iq_turn ::xmpp::iq::register set create games:board \ [namespace parent]::iq_games_board_create ::xmpp::iq::register set turn games:board \ [namespace parent]::iq_games_board_turn load_stored_theme calc_moves } proc renju::unload {} { hook::remove roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.3 hook::remove chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.3 hook::remove roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.3 hook::remove games_board_create_hook [namespace current]::iq_create hook::remove games_board_turn_hook [namespace current]::iq_turn if {[hook::is_empty games_board_create_hook]} { ::xmpp::iq::unregister set create games:board rename [namespace parent]::iq_games_board_create "" } if {[hook::is_empty games_board_turn_hook]} { ::xmpp::iq::unregister set turn games:board rename [namespace parent]::iq_games_board_turn "" } foreach var [info vars [namespace current]::*] { upvar #0 $var flags if {[info exists flags(window)]} { destroy_win $flags(window) } } foreach var [info vars [namespace current]::*] { if {$var ne "[namespace current]::options"} { unset $var } } foreach img [image names] { if {[string first renju/ $img] == 0} { image delete $img } } } proc renju::load_stored_theme {args} { variable options variable themes pixmaps::load_dir $themes($options(theme)) } proc renju::get_nick {xlib jid type} { if {[catch {chat::get_nick $xlib $jid $type} nick]} { return [chat::get_nick $jid $type] } else { return $nick } } proc renju::invite_dialog {xlib jid} { variable options set w .renju_invite if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Gomoku/Renju Invitation"] \ -modal none -anchor e -default 0 set wf [$w getframe] Message $wf.message -aspect 50000 \ -text [::msgcat::mc "Sending Gomoku/Renju game invitation to %s (%s)" \ [get_nick $xlib $jid chat] \ $jid] pack $wf.message -pady 2m variable game $options(game) Radiobutton $wf.renju -text [::msgcat::mc "Renju"] \ -value renju -variable [namespace current]::game pack $wf.renju -padx 15m -anchor w Radiobutton $wf.freestyle -text [::msgcat::mc "Free-style Gomoku"] \ -value gomoku:freestyle -variable [namespace current]::game pack $wf.freestyle -padx 15m -anchor w Radiobutton $wf.standard -text [::msgcat::mc "Standard Gomoku"] \ -value gomoku:standard -variable [namespace current]::game pack $wf.standard -padx 15m -anchor w Radiobutton $wf.tournament -text [::msgcat::mc "Tournament Gomoku"] \ -value gomoku:tournament -variable [namespace current]::game pack $wf.tournament -padx 15m -anchor w $w add -text [::msgcat::mc "I want to move first"] \ -command [list [namespace current]::invite $xlib $jid black] $w add -text [::msgcat::mc "I want to move second"] \ -command [list [namespace current]::invite $xlib $jid white] $w add -text [::msgcat::mc "Cancel invitation"] \ -command [list destroy $w] $w draw } proc renju::invite {xlib jid color} { variable game destroy .renju_invite set id renju[rand 1000000000] # FIX #set rjid [get_jid_of_user $jid] ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create create \ -xmlns games:board \ -attrs [list type $game \ id $id \ color $color]] \ -to $jid \ -command [list [namespace current]::invite_res \ $game $xlib $jid $id $color] } proc renju::invite_res {game xlib jid id color status xml} { if {![string equal $status ok]} { after idle [list NonmodalMessageDlg .renju_invite_error \ -aspect 50000 -icon error \ -message [::msgcat::mc "%s (%s) has refused Gomoku/Renju\ invitation: %s" \ [get_nick $xlib $jid chat] \ $jid [error_to_string $xml]]] return "" } start_play $game $xlib $jid $id $color } proc renju::invited_dialog {game xlib jid iqid id color} { variable game_names set w .renju_invited if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Gomoku/Renju Invitation from %s" $jid] \ -modal none -anchor e -default 0 set wf [$w getframe] bind $wf [namespace code [list invited_res $w $game $xlib $jid \ $iqid $id $color 0]] set nick [get_nick $xlib $jid chat] set message1 [::msgcat::mc "Gomoku/Renju game invitation from %s (%s)\ is received." \ $nick $jid] set message2 [::msgcat::mc "%s wants play %s." $nick $game_names($game)] switch -- $color { white { set message3 [::msgcat::mc "%s wants to move second." $nick] } black { set message3 [::msgcat::mc "%s wants to move first." $nick] } default { return [list error modify bad-request] } } Message $wf.message1 -aspect 50000 -text $message1 Message $wf.message2 -aspect 50000 -text $message2 Message $wf.message3 -aspect 50000 -text $message3 pack $wf.message1 -pady 1m pack $wf.message2 -pady 1m pack $wf.message3 -pady 1m $w add -text [::msgcat::mc "Agree to play"] \ -command [namespace code [list invited_res $w $game $xlib $jid \ $iqid $id $color 1]] $w add -text [::msgcat::mc "Refuse to play"] \ -command [namespace code [list invited_res $w $game $xlib $jid \ $iqid $id $color 0]] $w draw return } proc renju::invited_res {w game xlib jid iqid id color res} { catch { set wf [$w getframe] bind $wf {} destroy $w } if {$res} { switch -- $color { white { start_play $game $xlib $jid $id black } black { start_play $game $xlib $jid $id white } default { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify bad-request] \ -to $jid \ -id $iqid } } ::xmpp::sendIQ $xlib result \ -query [::xmpp::xml::create create \ -xmlns games:board \ -attrs [list type $game \ id $id]] \ -to $jid \ -id $iqid } else { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify not-acceptable] \ -to $jid \ -id $iqid } return } proc renju::start_play {game xlib jid id color} { set gid [make_gid $jid $id] variable $gid upvar 0 $gid flags set flags(window) [win_id renju $gid] set flags(xlib) $xlib set flags(opponent) $jid set flags(id) $id set flags(game) $game set flags(our_color) $color trace add variable [namespace current]::${gid}(position,turn) write \ [list [namespace current]::set_label_move $gid] make_default_position $gid open $gid } proc renju::set_label_move {gid args} { variable $gid upvar 0 $gid flags switch -- $flags(position,turn) { white { set flags(move_label) [::msgcat::mc "White"] set move 1 } black { set flags(move_label) [::msgcat::mc "Black"] set move 1 } default { set move 0 } } if {$move && [is_my_move $gid]} { append flags(move_label) [::msgcat::mc " (You)"] } else { append flags(move_label) [::msgcat::mc " (Opponent)"] } } proc renju::make_default_position {gid} { variable $gid upvar 0 $gid flags for {set c 0} {$c < 15} {incr c} { for {set r 0} {$r < 15} {incr r} { set flags(position,$c,$r) "" } } set flags(position,turn) black catch {unset flags(position,last_move)} set flags(position,draw) 0 set flags(position,halfmove) 0 set flags(position,history) {} } proc renju::save_position {gid} { variable $gid upvar 0 $gid flags set flags(saved_position) [array get flags position,*] } proc renju::restore_position {gid} { variable $gid upvar 0 $gid flags array set flags $flags(saved_position) draw_position $gid update_controls $gid find_legal_moves $gid $flags(position,turn) } proc renju::make_gid {jid id} { jid_to_tag [concat $jid $id] } proc renju::turn_recv {gid xmlList} { variable options variable $gid upvar 0 $gid flags set move 0 set skip 0 set draw 0 foreach xml $xmlList { ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- $tag { put { set pos [::xmpp::xml::getAttr $attrs pos] set poss [split $pos ","] if {[llength $poss] == 2} { set ct [lindex $poss 0] set rt [lindex $poss 1] set move 1 if {$options(sound) != "" && ![::sound::is_mute]} { ::sound::play $options(sound) } } } skip { set skip 1 add_move_to_history $gid if {[is_white $flags(position,turn)]} { set flags(position,turn) black } else { set flags(position,turn) white } find_legal_moves $gid $flags(position,turn) } resign { end_game $gid 1 [::msgcat::mc "You win (Opponent resigned)"] update_controls $gid draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type $flags(game) \ id $flags(id)]]] } accept { if {$flags(position,draw)} { end_game $gid 0.5 [::msgcat::mc "Draw (Opponent accepted)"] update_controls $gid draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type $flags(game) \ id $flags(id)]]] } else { return [list error modify not-acceptable] } } draw { set draw 1 } } } if {$skip || ($move && [do_move $gid $ct $rt $draw])} { if {[lindex $flags(position,history) end] == "skip" && \ [lindex $flags(position,history) end-1] == "skip"} { end_game $gid 0.5 [::msgcat::mc "Draw (Both players skipped move)"] } update_controls $gid $draw draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type $flags(game) \ id $flags(id)]]] } else { return [list error modify not-acceptable] } } ############################################################################### proc renju::calc_moves {} { variable moves for {set c 0} {$c < 15} {incr c} { for {set r 0} {$r < 15} {incr r} { for {set moves(d1,$c,$r) {}; \ set x [expr {$c+1}]; set y [expr {$r+1}]} \ {($x < 15) && ($y < 15)} {incr x; incr y} { lappend moves(d1,$c,$r) $x $y } for {set moves(d2,$c,$r) {}; \ set x [expr {$c-1}]; set y [expr {$r+1}]} \ {($x >= 0) && ($y < 15)} {incr x -1; incr y} { lappend moves(d2,$c,$r) $x $y } for {set moves(d3,$c,$r) {}; \ set x [expr {$c-1}]; set y [expr {$r-1}]} \ {($x >= 0) && ($y >= 0)} {incr x -1; incr y -1} { lappend moves(d3,$c,$r) $x $y } for {set moves(d4,$c,$r) {}; \ set x [expr {$c+1}]; set y [expr {$r-1}]} \ {($x < 15) && ($y >= 0)} {incr x; incr y -1} { lappend moves(d4,$c,$r) $x $y } for {set moves(h1,$c,$r) {}; set x [expr {$c+1}]} \ {$x < 15} {incr x} { lappend moves(h1,$c,$r) $x $r } for {set moves(h2,$c,$r) {}; set x [expr {$c-1}]} \ {$x >= 0} {incr x -1} { lappend moves(h2,$c,$r) $x $r } for {set moves(v1,$c,$r) {}; set y [expr {$r+1}]} \ {$y < 15} {incr y} { lappend moves(v1,$c,$r) $c $y } for {set moves(v2,$c,$r) {}; set y [expr {$r-1}]} \ {$y >= 0} {incr y -1} { lappend moves(v2,$c,$r) $c $y } } } } proc renju::center {c r} { variable square_size variable line_width set r [expr {14 - $r}] list [expr {$line_width + ($square_size * 0.5) + \ (($square_size + $line_width) * $c)}] \ [expr {$line_width + ($square_size * 0.5) + \ (($square_size + $line_width) * $r)}] } proc renju::close {gid} { variable $gid upvar 0 $gid flags array unset flags } proc renju::exists {gid} { variable $gid info exists $gid } proc renju::button_update_relief {b flag} { set rstate [expr {$flag? {pressed} : {!$pressed}}] if {[catch {$b state $rstate}]} { set relief [expr {$flag? "sunken" : "raised"}] $b configure -relief $relief } } proc renju::open {gid} { variable options variable game_names variable square_size variable line_width variable $gid upvar 0 $gid flags set jid $flags(opponent) set w $flags(window) if {[winfo exists $w]} { raise_win $w return } set title [::msgcat::mc "%s with %s" $game_names($flags(game)) \ [get_nick $flags(xlib) $jid chat]] add_win $w -title $title \ -tabtitle $title \ -class renju \ -raise 1 set board [canvas $w.board \ -borderwidth 0 \ -highlightthickness 0 \ -width [expr {15 * $square_size + 16 * $line_width}] \ -height [expr {15 * $square_size + 16 * $line_width}]] pack $board -side left -anchor w -padx 2m set flags(board) $board set flags(show_last_move) $options(show_last_move) set slm [Button $w.show_last_move -text [::msgcat::mc "Show last move"] \ -command [list [namespace current]::toggle_show_last_move \ $gid]] button_update_relief $slm $flags(show_last_move) pack $slm -side top -anchor w -fill x set flags(show_last_move_button) $slm Frame $w.move pack $w.move -side top -anchor w Label $w.move.title -text [::msgcat::mc "Move: "] pack $w.move.title -side left Label $w.move.on_move -anchor w \ -textvariable [namespace current]::${gid}(move_label) pack $w.move.on_move -side left -anchor w set bbox [ButtonBox $w.bbox -orient vertical -spacing 0] $bbox add -text [::msgcat::mc "Skip the move"] \ -command [list [namespace current]::send_skip $gid] set flags(propose_draw_button) \ [$bbox add -text [::msgcat::mc "Propose a draw"] \ -command [list [namespace current]::toggle_draw $gid]] $bbox add -text [::msgcat::mc "Accept the draw proposal"] \ -state disabled \ -command [list [namespace current]::accept_draw $gid] $bbox add -text [::msgcat::mc "Resign the game"] \ -command [list [namespace current]::send_resign $gid] grid columnconfigure $bbox 0 -weight 1 pack $bbox -side bottom -anchor w -fill x set flags(bbox) $bbox set_tooltips #label $w.history -text [::msgcat::mc "History"] #pack $w.history -side top -anchor w set hsw [ScrolledWindow $w.hsw] pack $hsw -side top -fill x -expand yes set ht [Text $w.text -wrap word -height 60 -state disabled] set font [$ht cget -font] set tabstop1 [font measure $font "99.."] set tabstop2 [font measure $font "99..Qa8-a8+= "] $ht configure -tabs "$tabstop1 $tabstop2" $ht tag configure attention \ -foreground [option get $ht errorForeground Text] $hsw setwidget $ht set flags(hw) $ht set dsq_color #77a26d set lsq_color #c8c365 for {set c 0} {$c < 15} {incr c} { for {set r 0} {$r < 15} {incr r} { set x1 [expr {$line_width + (($square_size + $line_width) * $c)}] set x2 [expr {($square_size + $line_width) * ($c + 1)}] set y1 [expr {$line_width + (($square_size + $line_width) * $r)}] set y2 [expr {($square_size + $line_width) * ($r + 1)}] set color [expr {($c+$r) % 2 ? $dsq_color : $lsq_color}] if {$c == 0 && $r == 0} { set img "ltf" } elseif {$c == 0 && $r == 14} { set img "lbf" } elseif {$c == 0} { set img "lf" } elseif {$c == 14 && $r == 0} { set img "rtf" } elseif {$c == 14 && $r == 14} { set img "rbf" } elseif {$c == 14} { set img "rf" } elseif {$r == 0} { set img "tf" } elseif {$r == 14} { set img "bf" } elseif {($c == 7 && $r == 7) || ($c == 3 && $r == 3) || \ ($c == 3 && $r == 11) || ($c == 11 && $r == 3) || \ ($c == 11 && $r == 11)} { set img "cf" } else { set img "mf" } $board create image $x1 $y1 -image renju/$img -anchor nw \ -tags [list background [list cr $c [expr {14-$r}]]] $board create rectangle $x1 $y1 $x2 $y2 \ -outline {} -width $line_width \ -tags [list last [list cr $c [expr {14-$r}]]] $board create rectangle $x1 $y1 $x2 $y2 \ -outline {} -width $line_width \ -tags [list square [list cr $c [expr {14-$r}]]] } } bind $board \ [list [namespace current]::motion $gid %x %y] bind $board \ [list [namespace current]::motion $gid %x %y] bind $board \ [list [namespace current]::leave $gid %x %y] bind $board \ [list [namespace current]::release $gid %x %y] bind $w [list [namespace current]::close $gid] make_default_position $gid draw_position $gid update_controls $gid find_legal_moves $gid $flags(position,turn) } proc renju::set_tooltips {args} { variable options if {$options(show_tooltips)} { set tooltip0 \ [::msgcat::mc "Press button if you want skip current move"] set tooltip1 \ [::msgcat::mc "Press button and make move if you\ want propose draw"] set tooltip2 \ [::msgcat::mc "Press button if you want accept the draw proposal"] set tooltip3 [::msgcat::mc "Press button if you want resign"] } else { set tooltip0 "" set tooltip1 "" set tooltip2 "" set tooltip3 "" } foreach var [info vars [namespace current]::*] { upvar 0 $var flags if {[info exists flags(bbox)]} { catch { $flags(bbox) itemconfigure 0 -helptext $tooltip0 $flags(bbox) itemconfigure 1 -helptext $tooltip1 $flags(bbox) itemconfigure 2 -helptext $tooltip2 $flags(bbox) itemconfigure 3 -helptext $tooltip3 } } } } proc renju::toggle_show_last_move {gid} { variable $gid upvar 0 $gid flags set flags(show_last_move) [expr {!$flags(show_last_move)}] button_update_relief $flags(show_last_move_button) $flags(show_last_move) highlight_last_move $gid } proc renju::toggle_draw {gid} { variable $gid upvar 0 $gid flags set flags(position,draw) [expr {!$flags(position,draw)}] button_update_relief $flags(propose_draw_button) $flags(position,draw) } proc renju::update_controls {gid {draw_proposed 0}} { variable $gid upvar 0 $gid flags button_update_relief $flags(propose_draw_button) 0 if {[is_my_move $gid]} { $flags(board) config -cursor "" set flags(position,draw) 0 if {$draw_proposed} { $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state normal $flags(bbox) itemconfigure 3 -state disabled } else { $flags(bbox) itemconfigure 0 -state normal $flags(bbox) itemconfigure 1 -state normal $flags(bbox) itemconfigure 2 -state disabled $flags(bbox) itemconfigure 3 -state normal } } elseif {![is_white $flags(position,turn)] && \ ![is_black $flags(position,turn)]} { $flags(board) config -cursor "" $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state disabled $flags(bbox) itemconfigure 3 -state disabled } else { $flags(board) config -cursor watch $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state disabled $flags(bbox) itemconfigure 3 -state disabled } } proc renju::end_game {gid my_score message} { variable $gid upvar 0 $gid flags set opponent_score [expr {1 - $my_score}] if {[is_black $flags(our_color)]} { set score "$my_score : $opponent_score" } else { set score "$opponent_score : $my_score" } set flags(position,turn) none set flags(move_label) $message set hw $flags(hw) $hw configure -state normal catch {$hw delete attention.first attention.last} $hw delete {end -1 char} end $hw insert end "\n\t\t$score\n" $hw see end $hw configure -state disabled } proc renju::draw_position {gid} { variable $gid upvar 0 $gid flags $flags(board) delete figure for {set c 0} {$c < 15} {incr c} { for {set r 0} {$r < 15} {incr r} { if {$flags(position,$c,$r) != ""} { $flags(board) create image [center $c $r] \ -image renju/$flags(position,$c,$r) \ -tags [list figure $flags(position,$c,$r) [list cr $c $r]] } } } } proc renju::motion {gid x y} { variable line_width variable $gid upvar 0 $gid flags set board $flags(board) set x [$board canvasx $x] set y [$board canvasy $y] $board itemconfigure dst_sq&&square -outline "" -width $line_width $board dtag dst_sq $board addtag dst_sq overlapping $x $y $x $y set tags [$board gettags dst_sq&&background] lassign [lindex $tags [lsearch $tags cr*]] cr c r $board addtag dst_sq withtag [list cr $c $r]&&square if {[info exists flags(position,$c,$r)] && $flags(position,$c,$r) == ""} { $board itemconfigure dst_sq&&square -outline red -width $line_width $board itemconfigure dst_sq&&legal&&square -outline blue -width $line_width } } proc renju::leave {gid x y} { variable line_width variable $gid upvar 0 $gid flags set board $flags(board) $board itemconfigure dst_sq&&square -outline "" -width $line_width $board dtag dst_sq highlight_last_move $gid } proc renju::release {gid x y} { variable options variable line_width variable $gid upvar 0 $gid flags set board $flags(board) set x [$board canvasx $x] set y [$board canvasy $y] $board itemconfigure dst_sq&&square -outline "" -width $line_width $board dtag dst_sq $board addtag dst_sq overlapping $x $y $x $y set tags [$board gettags dst_sq&&background] lassign [lindex $tags [lsearch $tags cr*]] cr c r $board dtag dst_sq if {$options(allow_illegal) || [is_my_move $gid]} { if {[do_move $gid $c $r $flags(position,draw)]} { $board itemconfigure [list cr $c $r]&&square -outline "" -width $line_width } } update_controls $gid draw_position $gid highlight_last_move $gid } proc renju::highlight_last_move {gid} { variable line_width variable $gid upvar 0 $gid flags $flags(board) itemconfigure last -outline "" -width $line_width if {[catch {lassign $flags(position,last_move) ct rt}]} { return } if {$flags(show_last_move)} { set color white } else { set color {} } $flags(board) itemconfigure [list cr $ct $rt]&&last -outline $color -width $line_width } proc renju::do_move {gid ct rt draw} { variable options variable moves variable $gid upvar 0 $gid flags if {$ct == "" || $rt == ""} { return 0 } set my_move [is_my_move $gid] if {![is_move_legal $gid $ct $rt]} { if {$my_move && !$options(allow_illegal)} { return 0 } if {!$my_move && !$options(accept_illegal)} { return 0 } } save_position $gid if {[is_white $flags(position,turn)]} { set mover w set opp b } else { set mover b set opp w } set flags(position,$ct,$rt) $mover set flags(position,last_move) [list $ct $rt] set checkmate [test_checkmate $gid $ct $rt] if {[is_white $flags(position,turn)]} { find_legal_moves $gid black } else { find_legal_moves $gid white } set skip [expr {[llength $flags(legal_moves)] == 0}] add_move_to_history $gid $ct $rt if {!$checkmate && $draw && !$my_move} { attention_message $gid \ [::msgcat::mc "\n\n Opponent proposes a draw\n\n"] } if {$my_move} { send_move $gid $ct $rt } if {!$skip} { if {[is_white $flags(position,turn)]} { set flags(position,turn) black } else { set flags(position,turn) white } } find_legal_moves $gid $flags(position,turn) set endgame 0 if {$skip && [llength $flags(legal_moves)] == 0} { # Can't find any move for both sides set endgame 1 } elseif {$skip} { add_move_to_history $gid } if {$checkmate} { if {$my_move} { # I win end_game $gid 1 [::msgcat::mc "You win"] } else { # Opponent wins end_game $gid 0 [::msgcat::mc "Opponent wins"] } } elseif {$endgame} { # Draw end_game $gid 0.5 [::msgcat::mc "Draw"] } tab_set_updated [winfo parent $flags(board)] 1 mesg_to_user return 1 } proc renju::accept_draw {gid} { variable $gid upvar 0 $gid flags ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type $flags(game) \ id $flags(id)] \ -subelement [::xmpp::xml::create accept]] \ -to $flags(opponent) end_game $gid 0.5 [::msgcat::mc "Draw (You accepted)"] update_controls $gid draw_position $gid highlight_last_move $gid } proc renju::send_skip {gid} { variable $gid upvar 0 $gid flags add_move_to_history $gid if {[is_white $flags(position,turn)]} { set flags(position,turn) black } else { set flags(position,turn) white } find_legal_moves $gid $flags(position,turn) ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type $flags(game) \ id $flags(id)] \ -subelement [::xmpp::xml::create skip]] \ -to $flags(opponent) \ -command [list [namespace current]::send_result $gid] if {[lindex $flags(position,history) end] == "skip" && \ [lindex $flags(position,history) end-1] == "skip"} { end_game $gid 0.5 [::msgcat::mc "Draw (Both players skipped move)"] } update_controls $gid draw_position $gid highlight_last_move $gid } proc renju::send_resign {gid} { variable $gid upvar 0 $gid flags ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type $flags(game) \ id $flags(id)] \ -subelement [::xmpp::xml::create resign]] \ -to $flags(opponent) end_game $gid 0 [::msgcat::mc "Opponent wins (You resigned)"] update_controls $gid draw_position $gid highlight_last_move $gid } proc renju::send_move {gid ct rt} { variable $gid upvar 0 $gid flags set put_tags [list [::xmpp::xml::create put \ -attrs [list pos "$ct,$rt"]]] if {$flags(position,draw)} { lappend put_tags [::xmpp::xml::create draw] } ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type $flags(game) \ id $flags(id)] \ -subelements $put_tags] \ -to $flags(opponent) \ -command [list [namespace current]::send_result $gid] } proc renju::send_result {gid status xml} { if {$status == "error"} { attention_message $gid \ [::msgcat::mc "\n\n Opponent rejected move:\n %s\n\n" \ [error_to_string $xml]] restore_position $gid } } proc renju::count_pieces {gid} { variable $gid upvar 0 $gid flags set b 0 set w 0 for {set ct 0} {$ct < 15} {incr ct} { for {set rt 0} {$rt < 15} {incr rt} { switch -- $flags(position,$ct,$rt) { b { incr b } w { incr w } } } } return [list $b $w] } proc renju::add_move_to_history {gid {ct ""} {rt ""}} { variable $gid upvar 0 $gid flags incr flags(position,halfmove) if {$ct != "" && $rt != ""} { lappend flags(position,history) [list $ct $rt] } else { lappend flags(position,history) skip } set hw $flags(hw) $hw configure -state normal $hw delete 0.0 end $hw insert end "\t[::msgcat::mc Black]\t[::msgcat::mc White]\n" set i 1 foreach {b w} $flags(position,history) { $hw insert end "${i}.\t" if {$b == "skip"} { $hw insert end "--\t" } elseif {$b != {}} { lassign $b ct rt incr rt set lt [format %c [expr {$ct+97}]] $hw insert end "$lt$rt\t" } if {$w == "skip"} { $hw insert end "--\n" } elseif {$w != {}} { lassign $w ct rt incr rt set lt [format %c [expr {$ct+97}]] $hw insert end "$lt$rt\n" } else { $hw insert end "\n" } incr i } $hw see end $hw configure -state disabled } proc renju::test_checkmate {gid ct rt} { variable $gid upvar 0 $gid flags variable moves if {$flags(position,$ct,$rt) == ""} { return 0 } set mover $flags(position,$ct,$rt) foreach dir {d1 d2 d3 d4 h1 h2 v1 v2} { set str($dir) 0 foreach {x y} $moves($dir,$ct,$rt) { if {$flags(position,$x,$y) == $mover} { incr str($dir) } else { break } } } set s1 [expr {1 + $str(d1) + $str(d3)}] set s2 [expr {1 + $str(d2) + $str(d4)}] set s3 [expr {1 + $str(h1) + $str(h2)}] set s4 [expr {1 + $str(v1) + $str(v2)}] switch -- $flags(game) { gomoku:freestyle - gomoku:tournament { return [expr {$s1 >= 5 || $s2 >= 5 || $s3 >= 5 || $s4 >= 5}] } gomoku:standard { return [expr {$s1 == 5 || $s2 == 5 || $s3 == 5 || $s4 == 5}] } renju { if {[is_black $mover]} { return [expr {$s1 == 5 || $s2 == 5 || $s3 == 5 || $s4 == 5}] } else { return [expr {$s1 >= 5 || $s2 >= 5 || $s3 >= 5 || $s4 >= 5}] } } } } proc renju::find_legal_moves {gid color} { variable $gid upvar 0 $gid flags set flags(legal_moves) {} for {set ct 0} {$ct < 15} {incr ct} { for {set rt 0} {$rt < 15} {incr rt} { if {$flags(position,$ct,$rt) != "" && \ [test_checkmate $gid $ct $rt]} { highlight_legal_moves $gid return } } } for {set ct 0} {$ct < 15} {incr ct} { for {set rt 0} {$rt < 15} {incr rt} { if {$flags(position,$ct,$rt) == "" && \ [check_legal $gid $ct $rt $color]} { lappend flags(legal_moves) [list $ct $rt] } } } highlight_legal_moves $gid } proc renju::is_overline {gid ct rt color} { variable moves variable $gid upvar 0 $gid flags # Assume that $ct $rt cell is empty set mover [expr {[is_black $color] ? "b" : "w"}] foreach dir {d1 d2 d3 d4 h1 h2 v1 v2} { set str($dir) 0 foreach {x y} $moves($dir,$ct,$rt) { if {$flags(position,$x,$y) == $mover} { incr str($dir) } else { break } } } set s1 [expr {1 + $str(d1) + $str(d3)}] set s2 [expr {1 + $str(d2) + $str(d4)}] set s3 [expr {1 + $str(h1) + $str(h2)}] set s4 [expr {1 + $str(v1) + $str(v2)}] return [expr {$s1 > 5 || $s2 > 5 || $s3 > 5 || $s4 > 5}] } proc renju::five {gid ct rt color dir} { variable moves variable $gid upvar 0 $gid flags # Assume that $ct $rt cell is empty set mover [expr {[is_black $color] ? "b" : "w"}] switch -- $dir { d1 { set dir2 d3 } d2 { set dir2 d4 } d3 { set dir2 d1 } d4 { set dir2 d2 } h1 { set dir2 h2 } h2 { set dir2 h1 } v1 { set dir2 v2 } v2 { set dir2 v1 } } set str {} foreach d [list $dir $dir2] { foreach {x y} $moves($d,$ct,$rt) { if {$flags(position,$x,$y) == $mover} { lappend str [list $x $y] } else { break } } } # Return a list of row cells (all except $ct $rt) if {[llength $str] == 4} { return [lsort $str] } else { return {} } } proc renju::straight_four {gid ct rt color dir} { variable moves variable $gid upvar 0 $gid flags # Assume that $ct $rt cell is empty set mover [expr {[is_black $color] ? "b" : "w"}] switch -- $dir { d1 { set dir2 d3 } d2 { set dir2 d4 } d3 { set dir2 d1 } d4 { set dir2 d2 } h1 { set dir2 h2 } h2 { set dir2 h1 } v1 { set dir2 v2 } v2 { set dir2 v1 } } set str {} foreach d [list $dir $dir2] { set open 0 foreach {x y} $moves($d,$ct,$rt) { if {!$open} { if {$flags(position,$x,$y) == $mover} { lappend str [list $x $y] } elseif {$flags(position,$x,$y) == ""} { # The row is open from $d side set open 1 } else { # The row is blocked return {} } } else { if {$flags(position,$x,$y) == $mover} { # The row is blocked by own stone return {} } else { break } } } if {!$open} { # The row is blocked by a border return {} } } # Return a list of row cells (all except $ct $rt) if {[llength $str] == 3} { return [lsort $str] } else { return {} } } proc renju::threes_and_fours {gid ct rt color dir} { variable moves variable $gid upvar 0 $gid flags # Assume that $ct $rt cell is empty set mover [expr {[is_black $color] ? "b" : "w"}] switch -- $dir { d1 { set dir2 d3 } d2 { set dir2 d4 } d3 { set dir2 d1 } d4 { set dir2 d2 } h1 { set dir2 h2 } h2 { set dir2 h1 } v1 { set dir2 v2 } v2 { set dir2 v1 } } foreach d [list $dir $dir2] { set str4($d) {} set str5($d) {} foreach {x y} $moves($d,$ct,$rt) { if {$flags(position,$x,$y) == ""} { # The row is open from $d side set flags(position,$ct,$rt) $mover set str4($d) [straight_four $gid $x $y $color $d] if {$str4($d) == {}} { set str5($d) [five $gid $x $y $color $d] } set flags(position,$ct,$rt) "" break } elseif {$flags(position,$x,$y) != $mover} { break } } } if {$str4($dir) == {} && $str4($dir2) == {}} { set th 0 } elseif {$str4($dir) == $str4($dir2)} { set th 1 } elseif {$str4($dir) == {} || $str4($dir2) == {}} { set th 1 } else { set th 2 } if {$str5($dir) == {} && $str5($dir2) == {}} { set fo 0 } elseif {$str5($dir) == $str5($dir2)} { set fo 1 } elseif {$str5($dir) == {} || $str5($dir2) == {}} { set fo 1 } else { set fo 2 } return [list $th $fo] } proc renju::check_legal {gid ct rt color} { variable moves variable $gid upvar 0 $gid flags set me [expr {[is_black $color] ? "b" : "w"}] set opp [expr {[is_black $color] ? "w" : "b"}] switch -- $flags(game) { gomoku:freestyle { return 1 } gomoku:standard { return 1 } gomoku:tournament { if {![is_black $color]} { return 1 } else { set hist [llength $flags(position,history)] if {$hist == 0} { if {$ct == 7 && $rt == 7} { return 1 } else { return 0 } } elseif {$hist == 2} { if {$ct >= 5 && $ct <= 9 && $rt >= 5 && $rt <= 9} { return 0 } else { return 1 } } else { return 1 } } } renju { if {![is_black $color]} { return 1 } else { set hist [llength $flags(position,history)] if {$hist == 0} { if {$ct == 7 && $rt == 7} { return 1 } else { return 0 } } foreach dir {d1 d2 h1 v1} { if {[llength [five $gid $ct $rt $color $dir]] == 4} { return 1 } } if {[is_overline $gid $ct $rt $color]} { return 0 } set threes 0 set fours 0 foreach dir {d1 d2 h1 v1} { lassign [threes_and_fours $gid $ct $rt $color $dir] th fo incr threes $th incr fours $fo } if {$fours > 1 || $threes > 1} { return 0 } else { return 1 } } } } } proc renju::is_move_legal {gid ct rt} { variable $gid upvar 0 $gid flags expr {[lsearch -regexp $flags(legal_moves) ^[list $ct $rt]] >= 0} } proc renju::highlight_legal_moves {gid} { variable $gid upvar 0 $gid flags set board $flags(board) $board dtag legal foreach move $flags(legal_moves) { lassign $move ct rt $board addtag legal withtag [list cr $ct $rt]&&square } } proc renju::attention_message {gid message} { variable $gid upvar 0 $gid flags set hw $flags(hw) $hw configure -state normal $hw delete {end -1 char} end $hw insert end $message attention $hw see end $hw configure -state disabled } proc renju::is_my_move {gid} { variable $gid upvar 0 $gid flags is_same_color $flags(position,turn) $flags(our_color) } proc renju::is_white {f} { string equal -length 1 $f w } proc renju::is_black {f} { string equal -length 1 $f b } proc renju::is_same_color {f1 f2} { string equal -length 1 $f1 $f2 } proc renju::add_groupchat_user_menu_item {m xlib jid} { set mm $m.gamesmenu if {![winfo exists $mm]} { menu $mm -tearoff 0 $m add cascade -label [::msgcat::mc "Games"] -menu $mm } $mm add command -label [::msgcat::mc "Gomoku/Renju..."] \ -command [list [namespace current]::invite_dialog $xlib $jid] } proc renju::iq_create {varname xlib from iqid xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels set game [::xmpp::xml::getAttr $attrs type] switch -- $game { gomoku:freestyle - gomoku:standard - gomoku:tournament - renju {} default { return } } if {[::xmpp::xml::isAttr $attrs color]} { set color [::xmpp::xml::getAttr $attrs color] switch -- $color { white - black { } default { set var [list error modify bad-request] } } } else { set color white } set var [[namespace current]::invited_dialog \ $game $xlib $from $iqid \ [::xmpp::xml::getAttr $attrs id] \ $color] } proc renju::iq_turn {varname xlib from xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- [::xmpp::xml::getAttr $attrs type] { gomoku:freestyle - gomoku:standard - gomoku:tournament - renju {} default { return } } set gid [make_gid $from [::xmpp::xml::getAttr $attrs id]] if {[exists $gid]} { set var [[namespace current]::turn_recv $gid $subels] } else { set var [list error cancel item-not-found] } } # Common games:board part proc iq_games_board_create {xlib from xml args} { set res [list error cancel feature-not-implemented] set iqid [::xmpp::xml::getAttr $args -id] hook::run games_board_create_hook res $xlib $from $iqid $xml return $res } proc iq_games_board_turn {xlib from xml args} { set res [list error cancel feature-not-implemented] hook::run games_board_turn_hook res $xlib $from $xml return $res } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/reversi000075500000000000000000000000001500237002100151115ustar00nobodynobodytkabber-plugins/reversi/msgs000075500000000000000000000000001500237002100160625ustar00nobodynobodytkabber-plugins/reversi/msgs/es.msg000064400000000000000000000076061500237002100172710ustar00nobodynobody# es.msg -- # # Spanish messages for the Reversi Tkabber plugin. # # Author: Badlop ::msgcat::mcset es " (Opponent)" " (Oponente)" ::msgcat::mcset es " (You)" " (Tu)" ::msgcat::mcset es "%s (%s) has refused reversi invitation: %s" \ "%s (%s) ha rechazado la invitación de jugar al reversi: %s" ::msgcat::mcset es "%s wants play black." "%s quiere jugar con las negras." ::msgcat::mcset es "%s wants play white." "%s quiere jugar con las blancas." ::msgcat::mcset es "Accept opponent illegal moves (useful for debugging)." \ "Aceptar movimientos ilegales del oponente (útil para depuración)." ::msgcat::mcset es "Accept the draw proposal" "Aceptar la propuesta de empate" ::msgcat::mcset es "Agree to play" "Aceptar la invitación" ::msgcat::mcset es "Allow illegal moves (useful for debugging)." \ "Permitir movimientos ilegales (útil para depuración)." ::msgcat::mcset es "Black" "Negra" ::msgcat::mcset es "Cancel invitation" "Cancelar la invitación" ::msgcat::mcset es "Draw (Opponent accepted)" "Empate (el oponente aceptó)" ::msgcat::mcset es "Draw (You accepted)" "Empate (aceptaste)" ::msgcat::mcset es "Draw" "Empate" ::msgcat::mcset es "Flip board view when playing white by default." \ "Rotar tablero por defecto cuando juegas con las blancas." ::msgcat::mcset es "Flip view" "Rotar tablero" ::msgcat::mcset es "Games" "Juegos" ::msgcat::mcset es "History" "Historia" ::msgcat::mcset es "I want play black" "Quiero jugar con las negras" ::msgcat::mcset es "I want play white" "Quiero jugar con las blancas" ::msgcat::mcset es "Move: " "Movimiento: " ::msgcat::mcset es "Opponent wins (You resigned)" \ "El oponente gana (te rendiste)" ::msgcat::mcset es "Opponent wins" "El oponente gana" ::msgcat::mcset es "Plugins options." "Opciones de plugins." ::msgcat::mcset es "Press button and make move if you want propose draw" \ "Pulsa el botón y haz un movimiento si quieres proponer un empate" ::msgcat::mcset es "Press button if you want accept the draw proposal" \ "Pulsa el botón si quieres aceptar la propuesta de empate" ::msgcat::mcset es "Press button if you want resign" \ "Pulsa el botón si quieres rendirte" ::msgcat::mcset es "Propose a draw" "Proponer un empate" ::msgcat::mcset es "Refuse to play" "Rechazar la invitación" ::msgcat::mcset es "Resign the game" "Rendirte" ::msgcat::mcset es "Reversi Invitation from %s" "Invitación al Reversi de %s" ::msgcat::mcset es "Reversi Invitation" "Invitación al Reversi" ::msgcat::mcset es "Reversi figures theme." "Tipo de fichas en Reversi." ::msgcat::mcset es "Reversi game invitation from %s (%s) is received." \ "Se ha recibido una invitación para jugar al reversi de %s (%s)." ::msgcat::mcset es "Reversi plugin options." "Opciones del plugin Reversi." ::msgcat::mcset es "Reversi with %s" "Reversi: %s" ::msgcat::mcset es "Reversi..." "Reversi..." ::msgcat::mcset es "Sending reversi game invitation to %s (%s)" \ "Enviando invitación para jugar al reversi a %s (%s)" ::msgcat::mcset es "Show last move by default." \ "Mostrar el último movimiento por defecto." ::msgcat::mcset es "Show last move" "Mostrar el último movimiento" ::msgcat::mcset es "Show tooltips with short instructions." \ "Mostrar pequeñas instrucciones de ayuda." ::msgcat::mcset es "Sound to play after opponent's turn" \ "Sonido a reproducir cuando el oponente haya movido" ::msgcat::mcset es "Whether the Reversi plugin is loaded." \ "Cargar el plugin Reversi." ::msgcat::mcset es "White" "Blanca" ::msgcat::mcset es "You win (Opponent resigned)" \ "Tu ganas (el oponente se rindió)" ::msgcat::mcset es "You win" "Tu ganas" ::msgcat::mcset es "\n\n Opponent proposes a draw\n\n" \ "\n\n El oponente propone un empate \n\n" ::msgcat::mcset es "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n El oponente rechazó el movimiento:\n %s\n\n" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/reversi/msgs/nl.msg000064400000000000000000000075641500237002100172760ustar00nobodynobody# nl.msg -- # # Dutch messages for the Reversi Tkabber plugin. # # Author: Sander Devrieze ::msgcat::mcset nl "Plugins options." "Pluginopties." ::msgcat::mcset nl "Reversi plugin options." "Pluginopties voor Reversi." ::msgcat::mcset nl "Reversi figures theme." \ "Thema voor afbeeldingen van stenen." ::msgcat::mcset nl "Flip board view when playing white by default." \ "Het speelbord standaard omkeren bij het spelen met wit." ::msgcat::mcset nl "Show last move by default." \ "Laatste zet standaard laten zien." ::msgcat::mcset nl "Show tooltips with short instructions." \ "Tekstballonnen met korte instructies laten zien." ::msgcat::mcset nl "Allow illegal moves (useful for debugging)." \ "Niet-toegelaten zetten toestaan (bruikbaar voor debuggen)." ::msgcat::mcset nl "Accept opponent illegal moves (useful for debugging)." \ "Niet-toegelaten zetten van tegenstander accepteren (bruikbaar voor\ debuggen)." ::msgcat::mcset nl "Reversi Invitation" \ "Uitnodiging voor een spelletje Reversi" ::msgcat::mcset nl "Sending reversi game invitation to %s (%s)" \ "Bezig met verzenden van uitnodiging voor een spelletje Reversi naar\ %s (%s)" ::msgcat::mcset nl "I want play black" "Ik wil met zwart spelen" ::msgcat::mcset nl "I want play white" "Ik wil met wit spelen" ::msgcat::mcset nl "Cancel invitation" "Uitnodiging annuleren" ::msgcat::mcset nl "%s (%s) has refused reversi invitation: %s" \ "%s (%s) ging niet in op de uitnodiging om met hem Reversi te\ spelen: %s" ::msgcat::mcset nl "Reversi Invitation from %s" \ "Uitnodiging voor een spelletje Reversi met %s" ::msgcat::mcset nl "Reversi game invitation from %s (%s) is received." \ "Uitnodiging voor een spelletje Reversi met %s (%s) werd ontvangen." ::msgcat::mcset nl "%s wants play %s." "%s wil spelen met %s." ::msgcat::mcset nl "Agree to play" "Spelen" ::msgcat::mcset nl "Refuse to play" "Niet spelen" ::msgcat::mcset nl "White" "Wit" ::msgcat::mcset nl "Black" "Zwart" ::msgcat::mcset nl " (You)" "(Jij)" ::msgcat::mcset nl " (Opponent)" "(Tegenstander)" ::msgcat::mcset nl "You win (Opponent resigned)" \ "Jij hebt gewonnen (de tegenstander gaf het op)" ::msgcat::mcset nl "Draw (Opponent accepted)" \ "Gelijkspel (de tegenstander accepteerde de uitslag)" ::msgcat::mcset nl "Reversi with %s" "Reversi met %s" ::msgcat::mcset nl "Show last move" "Laatste zet laten zien" ::msgcat::mcset nl "Flip view" "Beeld omkeren" ::msgcat::mcset nl "Move: " "Zet: " ::msgcat::mcset nl "Propose a draw" "Gelijkspel voorstellen" ::msgcat::mcset nl "Accept the draw proposal" \ "Het voorstel voor gelijkspel accepteren" ::msgcat::mcset nl "Resign the game" "Geef het op" ::msgcat::mcset nl "History" "Geschiedenis" ::msgcat::mcset nl "Press button and make move if you want propose draw" \ "Druk op de knop en doe een zet als je gelijkspel wilt voorstellen" ::msgcat::mcset nl "Press button if you want accept the draw proposal" \ "Druk op de knop als je het voorstel voor gelijkspel wilt accepteren" ::msgcat::mcset nl "Press button if you want resign" \ "Druk op de knop als je wilt opgeven" ::msgcat::mcset nl "\n\n Opponent proposes a draw\n\n" \ "\n\n De tegenstander stelt een gelijkspel voor\n\n" ::msgcat::mcset nl "Draw" "Gelijkspel" ::msgcat::mcset nl "You win" "Jij hebt gewonnen" ::msgcat::mcset nl "Opponent wins" "De tegenstander heeft gewonnen" ::msgcat::mcset nl "Draw (You accepted)" \ "Gelijkspel (jij accepteerde de uitslag)" ::msgcat::mcset nl "Opponent wins (You resigned)" \ "De tegenstander heeft gewonnen (jij gaf het op)" ::msgcat::mcset nl "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n De tegenstander weigerde de zet:\n %s\n\n" ::msgcat::mcset nl "Games" "Spelletjes" ::msgcat::mcset nl "Reversi..." "Reversi..." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/reversi/msgs/pl.msg000064400000000000000000000076171500237002100172770ustar00nobodynobody# pl.msg -- # # Polish messages for the Reversi Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Reversi plugin options." \ "Ustawienia wtyczki do gry w Reversi." ::msgcat::mcset pl "Reversi figures theme." "Motyw graficzny figur." ::msgcat::mcset pl "Flip board view when playing white by default." \ "Odwróć widok planszy podczas gry biaÅ‚ymi." ::msgcat::mcset pl "Reversi Invitation" "Zaproszenie do gry w Reversi" ::msgcat::mcset pl "Sending reversi game invitation to %s (%s)" \ "WysyÅ‚anie zaproszenia do gry w Reversi do %s (%s)" ::msgcat::mcset pl "%s (%s) has refused reversi invitation: %s" \ "%s (%s) odrzuca zaproszenie do gry w Reversi: %s" ::msgcat::mcset pl "Reversi Invitation from %s" \ "Zaproszenie do gry w Reversi od %s" ::msgcat::mcset pl "Reversi game invitation from %s (%s) is received." \ "Otrzymano zaproszenie do gry w Reversi od %s (%s)." ::msgcat::mcset pl "Reversi with %s" "Reversi: %s" ::msgcat::mcset pl "Draw" "Remis" ::msgcat::mcset pl "Reversi..." "Reversi..." ::msgcat::mcset pl "White" "BiaÅ‚e" ::msgcat::mcset pl "Move: " "Ruch: " ::msgcat::mcset pl "History" "Historia" ::msgcat::mcset pl "Black" "Czarne" ::msgcat::mcset pl "Show last move by default." "Pokazuj ostatni ruch." ::msgcat::mcset pl "Show tooltips with short instructions." \ "Pokazuj dymki podpowiedzi z krótkimi instrukcjami." ::msgcat::mcset pl "Allow illegal moves (useful for debugging)." \ "Pozwalaj na nieprawidÅ‚owe ruchy (użyteczne przy debugowaniu)." ::msgcat::mcset pl "Accept opponent illegal moves (useful for debugging)." \ "Pozwalaj na nieprawidÅ‚owe ruchy przeciwnika (użyteczne przy\ debugowaniu)." ::msgcat::mcset pl "I want play white" "ChcÄ™ grać biaÅ‚ymi" ::msgcat::mcset pl "I want play black" "ChcÄ™ grać czarnymi" ::msgcat::mcset pl "Cancel invitation" "Anuluj zaproszenie" ::msgcat::mcset pl "Agree to play" "Przyjmij zaproszenie" ::msgcat::mcset pl "Refuse to play" "Odrzuć zaproszenie" ::msgcat::mcset pl " (You)" " (Ty)" ::msgcat::mcset pl " (Opponent)" " (Przeciwnik)" ::msgcat::mcset pl "You win (Opponent resigned)" \ "WygaÅ‚eÅ› (przeciwnik zrezygnowaÅ‚)" ::msgcat::mcset pl "Draw (Opponent accepted)" "Remis (za zgodÄ… przeciwnika)" ::msgcat::mcset pl "Show last move" "Pokaż ostatni ruch" ::msgcat::mcset pl "Flip view" "Odwróć widok" ::msgcat::mcset pl "Propose a draw" "Zaproponuj remis" ::msgcat::mcset pl "Accept the draw proposal" "Zaakceptuj remis" ::msgcat::mcset pl "Resign the game" "Zrezygnuj z gry" ::msgcat::mcset pl "Press button and make move if you want propose draw" \ "NaciÅ›nij przycisk i wykonaj ruch jeżeli chcesz zaproponować remis" ::msgcat::mcset pl "Press button if you want accept the draw proposal" \ "NaciÅ›nij przycisk jeżeli chcesz zaakceptować propozycjÄ™ remisu" ::msgcat::mcset pl "Press button if you want resign" \ "NaciÅ›nij przycisk jeżeli chcesz zrezygnować z gry" ::msgcat::mcset pl "\n\n Opponent proposes a draw\n\n" \ "\n\n Przeciwnik proponuje remis\n\n" ::msgcat::mcset pl "Draw (You accepted)" "Remis (Za mojÄ… zgodÄ…)" ::msgcat::mcset pl "Opponent wins (You resigned)" \ "WygraÅ‚ przeciwnik (ZrezygnowaÅ‚eÅ› z gry)" ::msgcat::mcset pl "Games" "Gry planszowe" ::msgcat::mcset pl "Sound to play after opponent's turn" \ "Odtwórz dźwiÄ™k po ruchu przeciwnika" ::msgcat::mcset pl "%s wants play white." "%s chce grać biaÅ‚ymi." ::msgcat::mcset pl "%s wants play black." "%s chce grać czarnymi." ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Przeciwnik odrzuciÅ‚ ruch:\n %s\n\n" ::msgcat::mcset pl "You win" "WygraÅ‚eÅ›" ::msgcat::mcset pl "Opponent wins" "WygraÅ‚ przeciwnik" ::msgcat::mcset pl "Whether the Reversi plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ do gry w reversi." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/reversi/msgs/ru.msg000064400000000000000000000115151500237002100173020ustar00nobodynobody# ru.msg -- # # Russian messages for the Reversi Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Plugins options." "Параметры раÑширений." ::msgcat::mcset ru "Flip board view when playing white by default." \ "Разворачивать по умолчанию доÑку при игре белыми." ::msgcat::mcset ru "Show last move by default." \ "По умолчанию показывать поÑледний ход." ::msgcat::mcset ru " (You)" " (Ð’Ñ‹)" ::msgcat::mcset ru " (Opponent)" " (Оппонент)" ::msgcat::mcset ru "Flip view" "Развернуть доÑку" ::msgcat::mcset ru "Reversi plugin options." "Параметры раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð ÐµÐ²ÐµÑ€Ñи." ::msgcat::mcset ru "Reversi figures theme." "Тема фишек реверÑи." ::msgcat::mcset ru "Show tooltips with short instructions." \ "Показывать вÑплывающие подÑказки к Ñлементам интерфейÑа." ::msgcat::mcset ru "Allow illegal moves (useful for debugging)." \ "Разрешать неправильные ходы (иÑпользуетÑÑ Ð¿Ñ€Ð¸ отладке)." ::msgcat::mcset ru "Accept opponent illegal moves (useful for debugging)." \ "Принимать неправильные ходы от оппонента (иÑпользуетÑÑ Ð¿Ñ€Ð¸ отладке)." ::msgcat::mcset ru "Reversi Invitation" "Приглашение Ñыграть в реверÑи" ::msgcat::mcset ru "Sending reversi game invitation to %s (%s)" \ "ПоÑылаем приглашение Ñыграть в реверÑи Ñ %s (%s)" ::msgcat::mcset ru "I want play white" "Хочу играть белыми" ::msgcat::mcset ru "I want play black" "Хочу играть чёрными" ::msgcat::mcset ru "Cancel invitation" "Отменить приглашение" ::msgcat::mcset ru "%s (%s) has refused reversi invitation: %s" \ "%s (%s) отказалÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ в реверÑи: %s" ::msgcat::mcset ru "Reversi Invitation from %s" \ "Приглашение Ñыграть в реверÑи Ñ %s" ::msgcat::mcset ru "Reversi game invitation from %s (%s) is received." \ "Получено приглашение Ñыграть в реверÑи Ñ %s (%s)" ::msgcat::mcset ru "%s wants play white." "%s хочет играть белыми" ::msgcat::mcset ru "%s wants play black." "%s хочет играть чёрными" ::msgcat::mcset ru "Agree to play" "СоглаÑитьÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ" ::msgcat::mcset ru "Refuse to play" "ОтказатьÑÑ Ð¸Ð³Ñ€Ð°Ñ‚ÑŒ" ::msgcat::mcset ru "Reversi with %s" "РеверÑи Ñ %s" ::msgcat::mcset ru "Show last move" "Показывать поÑледний ход" ::msgcat::mcset ru "Move: " "Ход: " ::msgcat::mcset ru "Propose a draw" "Предложить ничью" ::msgcat::mcset ru "Accept the draw proposal" "ПринÑть предложенную ничью" ::msgcat::mcset ru "Resign the game" "Сдать партию" ::msgcat::mcset ru "History" "ЗапиÑÑŒ партии" ::msgcat::mcset ru "Reversi..." "РеверÑи..." ::msgcat::mcset ru "White" "Белые" ::msgcat::mcset ru "Black" "Чёрные" ::msgcat::mcset ru "Opponent wins" "Оппонент выиграл" ::msgcat::mcset ru "You win" "Ð’Ñ‹ выиграли" ::msgcat::mcset ru "Opponent wins (You resigned)" \ "Оппонент выиграл (Ð’Ñ‹ ÑдалиÑÑŒ)" ::msgcat::mcset ru "You win (Opponent resigned)" \ "Ð’Ñ‹ выиграли (Оппонент ÑдалÑÑ)" ::msgcat::mcset ru "Draw" "ÐичьÑ" ::msgcat::mcset ru "Draw (You accepted)" "ÐÐ¸Ñ‡ÑŒÑ (Ð’Ñ‹ принÑли)" ::msgcat::mcset ru "Draw (Opponent accepted)" "ÐÐ¸Ñ‡ÑŒÑ (Оппонент принÑл)" ::msgcat::mcset ru "Press button and make move if you want propose draw" \ "Ðажмите кнопку и Ñделайте ход, еÑли хотите предложить ничью" ::msgcat::mcset ru "Press button if you want accept the draw proposal" \ "Ðажмите кнопку, еÑли хотите принÑть предложенную ничью" ::msgcat::mcset ru "Press button if you want resign" \ "Ðажмите кнопку, еÑли хотите ÑдатьÑÑ" ::msgcat::mcset ru "\n\n Opponent proposes a draw\n\n" \ "\n\n Оппонент предлагает ничью\n\n" ::msgcat::mcset ru "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Оппонент отверг ход:\n %s\n\n" ::msgcat::mcset ru "Games" "Игры" ::msgcat::mcset ru "Sound to play after opponent's turn" \ "Звук, который проигрываетÑÑ Ð¿Ð¾Ñле хода оппонента" ::msgcat::mcset ru "Whether the Reversi plugin is loaded." \ "Загружено ли раÑширение РеверÑи." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/reversi/msgs/uk.msg000064400000000000000000000115321500237002100172720ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Reversi Tkabber plugin. # # Author: Artem Bondarenko # Author: Sergei Golovan ::msgcat::mcset uk "Plugins options." "Параметри плагінів." ::msgcat::mcset uk "Flip board view when playing white by default." "Розвертати дошку при грі білими за замовчуваннÑм." ::msgcat::mcset uk "Show last move by default." \ "Показувати оÑтанній хід за замовчуваннÑм." ::msgcat::mcset uk " (You)" " (Ви)" ::msgcat::mcset uk " (Opponent)" " (Опонент)" ::msgcat::mcset uk "Flip view" "Розгорнути дошку" ::msgcat::mcset uk "Reversi plugin options." "Параметри плагіна РеверÑÑ–." ::msgcat::mcset uk "Reversi figures theme." "Тема фішок реверÑÑ–." ::msgcat::mcset uk "Show tooltips with short instructions." \ "Показувати Ñпливаючі підказки до елементів інтерфейÑу." ::msgcat::mcset uk "Allow illegal moves (useful for debugging)." \ "ДозволÑти неправильні ходи (викориÑтовуєтьÑÑ Ð¿Ñ€Ð¸ налагодженні)." ::msgcat::mcset uk "Accept opponent illegal moves (useful for debugging)." \ "Приймати неправильні ходи від опонента (викориÑтовуєтьÑÑ Ð¿Ñ€Ð¸\ налагодженні)." ::msgcat::mcset uk "Reversi Invitation" "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в реверÑÑ–" ::msgcat::mcset uk "Sending reversi game invitation to %s (%s)" \ "Ð’Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в реверÑÑ– з %s (%s)" ::msgcat::mcset uk "I want play white" "Хочу грати білими" ::msgcat::mcset uk "I want play black" "Хочу грати чорними" ::msgcat::mcset uk "Cancel invitation" "СкаÑувати запрошеннÑ" ::msgcat::mcset uk "%s (%s) has refused reversi invitation: %s" \ "%s (%s) відмовивÑÑ Ð³Ñ€Ð°Ñ‚Ð¸ в реверÑÑ–: %s" ::msgcat::mcset uk "Reversi Invitation from %s" \ "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в реверÑÑ– з %s" ::msgcat::mcset uk "Reversi game invitation from %s (%s) is received." \ "Отримане Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ñ–Ð³Ñ€Ð°Ñ‚Ð¸ в реверÑÑ– з %s (%s)" ::msgcat::mcset uk "%s wants play white." " %s хоче грати білими" ::msgcat::mcset uk "%s wants play black." " %s хоче грати чорними" ::msgcat::mcset uk "Agree to play" "ПогодитиÑÑ Ð³Ñ€Ð°Ñ‚Ð¸" ::msgcat::mcset uk "Refuse to play" "ВідмовитиÑÑ Ð³Ñ€Ð°Ñ‚Ð¸" ::msgcat::mcset uk "Reversi with %s" "РеверÑÑ– з %s" ::msgcat::mcset uk "Show last move" "Показувати оÑтанній хід" ::msgcat::mcset uk "Move: " "Хід: " ::msgcat::mcset uk "Propose a draw" "Запропонувати нічию" ::msgcat::mcset uk "Accept the draw proposal" "ПрийнÑти запропоновану нічию" ::msgcat::mcset uk "Resign the game" "Здати партію" ::msgcat::mcset uk "History" "Ð—Ð°Ð¿Ð¸Ñ Ð¿Ð°Ñ€Ñ‚Ñ–Ñ—" ::msgcat::mcset uk "Reversi..." "РеверÑÑ–..." ::msgcat::mcset uk "White" "Білі" ::msgcat::mcset uk "Black" "Чорні" ::msgcat::mcset uk "Opponent wins" "Опонент виграв" ::msgcat::mcset uk "You win" "Ви виграли" ::msgcat::mcset uk "Opponent wins (You resigned)" "Опонент виграв (Ви здалиÑÑ)" ::msgcat::mcset uk "You win (Opponent resigned)" "Ви виграли (Опонент здавÑÑ)" ::msgcat::mcset uk "Draw" "ÐічиÑ" ::msgcat::mcset uk "Draw (You accepted)" "ÐÑ–Ñ‡Ð¸Ñ (Ви прийнÑли)" ::msgcat::mcset uk "Draw (Opponent accepted)" "ÐÑ–Ñ‡Ð¸Ñ (Опонент прийнÑв)" ::msgcat::mcset uk "Press button and make move if you want propose draw" \ "ÐатиÑніть кнопку й зробіть хід, Ñкщо хочете запропонувати нічию" ::msgcat::mcset uk "Press button if you want accept the draw proposal" \ "ÐатиÑніть кнопку, Ñкщо хочете прийнÑти запропоновану нічию" ::msgcat::mcset uk "Press button if you want resign" \ "ÐатиÑніть кнопку, Ñкщо хочете здатиÑÑ" ::msgcat::mcset uk "\n\n Opponent proposes a draw\n\n" \ "\n\n Опонент пропонує нічию\n\n" ::msgcat::mcset uk "\n\n Opponent rejected move:\n %s\n\n" \ "\n\n Опонент відкинув хід:\n %s\n\n" ::msgcat::mcset uk "Games" "Ігри" ::msgcat::mcset uk "Sound to play after opponent's turn" \ "Звук, Ñкий буде програватиÑÑ Ð¿Ñ–ÑÐ»Ñ Ñ…Ð¾Ð´Ñƒ опонента" ::msgcat::mcset uk "Whether the Reversi plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð ÐµÐ²ÐµÑ€ÑÑ–." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/reversi/pixmaps000075500000000000000000000000001500237002100165725ustar00nobodynobodytkabber-plugins/reversi/pixmaps/checkers000075500000000000000000000000001500237002100203615ustar00nobodynobodytkabber-plugins/reversi/pixmaps/checkers/b.gif000064400000000000000000000017011500237002100213470ustar00nobodynobodyGIF89a11õ!  '''/0/00/777??@?@??@@@??@?@@@?FFFOPOOPPPOOPOPPPOWWW__`_`_`__`_`gggoopopppoopopppovvvÿÿÿ!ù!,11þÀpH,ȤrÉl:ŸÐ¨tJ­Z™MgÃÕT*W§Dþ|6štÖ ÉpÐ9MÿÚ!îáΩ vnq ‚’ƒ… ŒVq“”„©œžSq¤’]…† °p£pi¾¿¿Q{ ¢pstÐ_Ò ÖÂOp²¢qhÏvš‹  ÁÖOd*H5wuZhîÀ'p&)ˆÃaž³DÊKÐ „ 4Ùó`”Š-$ŠaaƒÖ@˜Ð @H&p*xfþ›D $€©Žå©p‚¨@ꤟ,üTÄPÝ›¾\-°¤‚’¼™a†ð‹¢ æ¦,ðà˃T\“ŒÙp@Ò„žíy\ˆ€è´\¨aÀ€¸H¸l$@òRíTØ LZ¸. &`X šŒzQi­e‡p ¸ µ’ç4§òڛટU̪á”:±ëkÅpÁéÔ¹Ãô; k$S}ÐÀ¶Ã­T*œy’ 4PMA²&Õý"E~ÊÀ– ¾¿{á…`¶+ê~Q§pJÐ.H‚^H9ÜgvÆ_$¸€P€$Xh•J[÷ÁÔÏupàÈ$p‚“TèGH‡Ü—‡û=XŠc €5HLCÖ(dÙ_©pö`$<@F9Aiý²âZ rÊ$ˆ‚´<±—5 ,¤~Ù= %ˆ2uBT:­—]r‘ð€”IB@hÉ_¸yÀÀ9PS¤ó€–› ù‡n ° Œd„ÉMéÄ”‘d¢m ¥T>jÅiLð…ÐÁÅ#ʨéÖ¤+k¨ñÖ$Må!€íwI¥Ì(+[ñ÷c›ºîzÄUln'ì±È&«ì²Ì6[D;tkabber-plugins/reversi/pixmaps/checkers/bf.gif000064400000000000000000000015651500237002100215250ustar00nobodynobodyGIF89a11ó sQ1sY1{U1{Y1kUBsYJ{YB„YB„aBŒaJŒiBÿÿÿ!ù ,11þÐ"€ ¦˜m„AöQã¦!Hn ’x&HLÕ•qݲdj~©•ÎË  …C¨ˆÌiŒCbátŸ€†•B.… 3=õ®BN Á7B+A'(„7«ža ˆy@\V§7—6¶°!~°2 ™(Š©H¥ºRƒš«99 / ’j§¸ͺbi8*ŸÃ¤8n…¨Î$/b8ž´ãÂ,0{¤Ú‰Î#ÉŸT{VXkA„ Bl¬:iΖ"üP“òð¶.Àäã@-™¸"þC$€ PäÁ "Þh6ÅŠ WÜ©Ååž©¶pTðγ5;$ˆf ¥½&q ¸pS?Žs|4:RÌÍMPX´(‚ ¬¡ ò€8ÁXœLy@Ù–f µ<2] ëjBN@ãΉ¡i8¡-(”E‚„ÎA˜¦Ð’÷%X?B‡¶ô—jg Ÿ:ÖÎ ;t°±4¹‹BÈž ¼½"@ŽduÌØ¹:,‡m« K»šndS‘F€‚pULWó6óÂ7ÿ¹¼‚õÅ5j8›*œ«à;I0ŽÜ‰‹»vw¯ËK=¸ž¹ýµIô¯¿¢g ’i¤sú<þ÷ÝtiìÕš@¥UÚ.¿ ÷H(&¤´_8çÁCöôI0 Checkers 1.0 Reversi Checkers Theme. 2006-01-23 reversi/bf bf.gif reversi/b b.gif reversi/wf wf.gif reversi/w w.gif tkabber-plugins/reversi/pixmaps/checkers/w.gif000064400000000000000000000016601500237002100214000ustar00nobodynobodyGIF89a11õ ‰‰‰———ŸŸ  ŸŸ  Ÿ§§§°°¯···¿¿À¿À¿¿ÀÀÀ¿¿À¿ÀÇÇÇÏÐÏÏÐÐÐÏÏÐÏÐÐÐÏ×××ßßàßàßßàààßàçççïðïïðððïïððïööõÿÿÿ!ù ,11þ@pH,ȤrÉl:ŸÐ¨tJ­Z™šlg“­T®ÎÍçÃùl³K÷ >Žß­ñÚ!í¡æ=®$ vm| ”ƒƒ†ŠŒV| ‘’•–„§«U|’’ t…† »S|°cµ^ Ê» Q{cÀ’edÆk^Ë ÉËPo¯’ÃÄsuu^ ÎáÐa}° péëì‹ñ¼ròf>bgÔ±›0a•e :AHu I‡1 bñѦ!C†…8uzøðA„ S1y#*™bÇø‰„˜r–¢S—Ø 0`Ìþ†l×0ìçoY*¼àZRLÆø¶h«°ïäªo)`€ §’=šð Õ…D:3ªõT‚ `ʉäç†@4èûÈ.íƒß(ž"t. ºG4 4€Î¾ ŠVL‰Ó! 4XRÔ’Y ‰"ôKÀ€í)¨-gÖ<èkÏ ùù{PZ™à–-7~Ý: @΂>I´¶í¶§-@³9ÉY„Ù!ÎëáqœtB ·‚ J*|üC A¢ œþY?Ú–@)J6xx@ ñªrOÉthúà‚H¢—b ÀD µõ€_­G‘˜XBIÖx Á„LPà¹ÏˆTTV87È„yyàÁ•4ÁÎQ»<`Ýuƒ½'€9|°ÁŒ8ÁPCßLv[ŒxU#ÆÌh ŽœôØßaâ˜@D  v²@i r(Ê4IÀ!«p¤Þû™”…iœ'…ci¢*ë%“Ih¾D q RÇáÛ=9œ•–š(.‰DfÛ!}´Ø Ûf&4ó’ÅJJ Ño£¬w€]&_bYo1qz f(EG‹dk+oQy4 :-ŽŽ3_adl£^ŒhX¢mm4„‡KuXqh ›:¬ b©|:ž€v‘BД a«Ô> f’Ь Æ×JÁ|”R'd¥ÓÒeÔÖת,PH'ÝŽÀ°¹pãc°ñ!eBO @î:Ø G)9db²`‚ïÇ!( ßy:±Œ‹]þ{&ð›¶bä‘ƬÍA´¤â‰} áÙÙ8Ï4œFÐxö®§ ‡×nÅP§Ó Nh !­1Q`ŠZ5êÕ³ª¼šªŽåõ©IRƒJü7b*O«âP5ˆ®@»\§ÅÔ'2¡‘*í,5÷AKÅœC÷Ä ®hGmÃX "D%îeÉR@§lÙP\7âˆI]O)3FÙqàÒEzHÚÉ@„]̆ê=ùKegOU .Q°ŒR¥Ma «Dƒv‰N¯×Öʱmñ_êoBêaȽ{´c6e¶“u»»ºo`½\jIÂ.)¡3Ç:öÌÀP{9æ%øG'Ž™Þ}„mé°Àëpßúù–™_­„„ÑbŽÄVÝ cƒÝX°/ñ`±.N!xN…%ƒTA{Èd`/!wxä¤BI³d‘BÐC!‚ŒíÆ`3é•ÎjÕ Æã?’æ‰Ì©c–B«©G:4;ñÅ‘dÒèvY*£29ü…‡düT·"NíVMS¤‘ç#®œ·šx®(˜e–pDæÃèÄiÖ³ž`/ZÆ·°àVdÂ%äÝÕâIcƒÁ€@eâŽ%Ã|çæ›lÖ犵ݶ¦–Äe¦ˆêAï°I«ð2@;tkabber-plugins/reversi/pixmaps/xboard000075500000000000000000000000001500237002100200515ustar00nobodynobodytkabber-plugins/reversi/pixmaps/xboard/b.gif000064400000000000000000000003441500237002100210410ustar00nobodynobodyGIF89a11ðÿÿÿ!ù,11»Œ©Ëí£œ´Ú‹³† {¿IßH†ÌØ ¦ñ$È›ü–10wwmËÈ ê| P r†ÇcRWÄ5§ÏènÊ‹‰¤ØfuyíÖ´¦Ø u˜ÏÁoŠËFãÞÏ82½XÛÇx…~_Ò—ðØ"ˆ@XȤ§ˆrèÒèhÄX7IYy‰™©Éf©HV&Yè6f' 6iºDÊVWa”ª1{‹#v“3:ÖÒ‚šF¼¢’w¼éÅüöò,=M]m}Q;tkabber-plugins/reversi/pixmaps/xboard/bf.gif000064400000000000000000000001331500237002100212030ustar00nobodynobodyGIF89a11ðw¢mÿÿÿ!ù,112„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇòL×öçúÎ÷þ ‡Ä¢ñˆÜ;tkabber-plugins/reversi/pixmaps/xboard/icondef.xml000064400000000000000000000012601500237002100222600ustar00nobodynobody Xboard 1.0 Reversi Xboard Theme. 2006-01-23 reversi/bf bf.gif reversi/b b.gif reversi/wf wf.gif reversi/w w.gif tkabber-plugins/reversi/pixmaps/xboard/w.gif000064400000000000000000000003521500237002100210650ustar00nobodynobodyGIF89a11ñÿÿÌÿÿÿ!ù,11»”©Ëí£œ´Ú‹³†¡{¿IßH†ÌØ ¦ñ$È›ü–q0wwmËÈ ê| P( r†ÇcRWÄ5§ÏènÊ‹‰¤ØfuyíÖ´¦Ø u˜ÏÁoŠËFãÞÏ82½XÛÇx…~_Ò—ðØ"ˆ@XȤ§ˆrèÒèhÄX7IYy‰™©Éf©HV&Yè6f' 6iºDÊVWa”ª1{‹#v“3:ÖÒ‚šF¼¢’w¼éÅüöò,=M]m}Q;tkabber-plugins/reversi/pixmaps/xboard/wf.gif000064400000000000000000000001331500237002100212300ustar00nobodynobodyGIF89a11ðÈÃeÿÿÿ!ù,112„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇòL×öçúÎ÷þ ‡Ä¢ñˆÜ;tkabber-plugins/reversi/proto000064400000000000000000000032161500237002100162600ustar00nobodynobodyRequest: 600 -- for all players 10 -- if on black side playes Kasparov Positive response: or simply ? Turn: 'pos' attribute contains coordinates of piece. Coordinate is a comma-separated list of integers >= 0. Proposing draw: Accepting draw proposal: Resigning: Also we need and tags for games where we must put or remove pieces. can have 'type' and 'color' attributes. move, put & destroy tags can have some game-specific subtags Response: if move accepted, or error 'Not Acceptable' if other side think that this move illegal. tkabber-plugins/reversi/reversi.tcl000064400000000000000000001142611500237002100173600ustar00nobodynobody# reversi.tcl -- # # This file implements Reversi (Othello) game for the Tkabber XMPP # client. package require msgcat namespace eval reversi { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered reversi]} { ::plugins::register reversi \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Reversi\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable square_size [expr {48*$::icons_scale}] variable line_width $::icons_scale variable themes variable dirs \ [glob -nocomplain -directory [file join [file dirname [info script]] \ pixmaps] *] variable dir foreach dir $dirs { pixmaps::load_theme_name [namespace current]::themes $dir } variable values {} variable theme foreach theme [lsort [array names themes]] { lappend values $theme $theme } variable options custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup Reversi [::msgcat::mc "Reversi plugin options."] \ -group Plugins custom::defvar options(theme) Checkers \ [::msgcat::mc "Reversi figures theme."] -group Reversi \ -type options -values $values \ -command [namespace current]::load_stored_theme custom::defvar options(flip_white_view) 0 \ [::msgcat::mc "Flip board view when playing white by default."] \ -type boolean -group Reversi custom::defvar options(show_last_move) 0 \ [::msgcat::mc "Show last move by default."] \ -type boolean -group Reversi custom::defvar options(show_tooltips) 1 \ [::msgcat::mc "Show tooltips with short instructions."] \ -type boolean -group Reversi \ -command [list [namespace current]::set_tooltips] custom::defvar options(sound) "" \ [::msgcat::mc "Sound to play after opponent's turn"] \ -type file -group Reversi custom::defvar options(allow_illegal) 0 \ [::msgcat::mc "Allow illegal moves (useful for debugging)."] \ -type boolean -group Reversi custom::defvar options(accept_illegal) 0 \ [::msgcat::mc "Accept opponent illegal moves (useful for\ debugging)."] \ -type boolean -group Reversi } proc reversi::load {} { hook::add roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.2 hook::add chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.2 hook::add roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.2 hook::add games_board_create_hook [namespace current]::iq_create hook::add games_board_turn_hook [namespace current]::iq_turn ::xmpp::iq::register set create games:board \ [namespace parent]::iq_games_board_create ::xmpp::iq::register set turn games:board \ [namespace parent]::iq_games_board_turn load_stored_theme calc_moves } proc reversi::unload {} { hook::remove roster_create_groupchat_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.2 hook::remove chat_create_user_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.2 hook::remove roster_jid_popup_menu_hook \ [namespace current]::add_groupchat_user_menu_item 48.2 hook::remove games_board_create_hook [namespace current]::iq_create hook::remove games_board_turn_hook [namespace current]::iq_turn if {[hook::is_empty games_board_create_hook]} { ::xmpp::iq::unregister set create games:board rename [namespace parent]::iq_games_board_create "" } if {[hook::is_empty games_board_turn_hook]} { ::xmpp::iq::unregister set turn games:board rename [namespace parent]::iq_games_board_turn "" } foreach var [info vars [namespace current]::*] { upvar #0 $var flags if {[info exists flags(window)]} { destroy_win $flags(window) } } foreach var [info vars [namespace current]::*] { if {$var ne "[namespace current]::options"} { unset $var } } foreach img [image names] { if {[string first reversi/ $img] == 0} { image delete $img } } } proc reversi::load_stored_theme {args} { variable options variable themes pixmaps::load_dir $themes($options(theme)) } proc reversi::get_nick {xlib jid type} { if {[catch {chat::get_nick $xlib $jid $type} nick]} { return [chat::get_nick $jid $type] } else { return $nick } } proc reversi::invite_dialog {xlib jid} { set w .reversi_invite if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Reversi Invitation"] \ -modal none -anchor e -default 0 set wf [$w getframe] Message $wf.message -aspect 50000 \ -text [::msgcat::mc "Sending reversi game invitation to %s (%s)" \ [get_nick $xlib $jid chat] \ $jid] pack $wf.message -pady 2m $w add -text [::msgcat::mc "I want play black"] \ -command [list [namespace current]::invite $xlib $jid black] $w add -text [::msgcat::mc "I want play white"] \ -command [list [namespace current]::invite $xlib $jid white] $w add -text [::msgcat::mc "Cancel invitation"] \ -command [list destroy $w] $w draw } proc reversi::invite {xlib jid color} { destroy .reversi_invite set id reversi[rand 1000000000] # FIX #set rjid [get_jid_of_user $jid] ::xmpp::sendIQ $xlib set \ -query [::xmpp::xml::create create \ -xmlns games:board \ -attrs [list type reversi \ id $id \ color $color]] \ -to $jid \ -command [list [namespace current]::invite_res $xlib $jid $id $color] } proc reversi::invite_res {xlib jid id color status xml} { if {![string equal $status ok]} { after idle [list NonmodalMessageDlg .reversi_invite_error \ -aspect 50000 -icon error \ -message [::msgcat::mc "%s (%s) has refused reversi\ invitation: %s" \ [get_nick $xlib $jid chat] \ $jid [error_to_string $xml]]] return "" } start_play $xlib $jid $id $color } proc reversi::invited_dialog {xlib jid iqid id color} { set w .reversi_invited if {[winfo exists $w]} { destroy $w } Dialog $w -title [::msgcat::mc "Reversi Invitation from %s" $jid] \ -modal none -anchor e -default 0 set wf [$w getframe] bind $wf [namespace code [list invited_res $w $xlib $jid \ $iqid $id $color 0]] set nick [get_nick $xlib $jid chat] set message1 [::msgcat::mc "Reversi game invitation from %s (%s)\ is received." \ $nick $jid] switch -- $color { white { set message2 [::msgcat::mc "%s wants play white." $nick] } black { set message2 [::msgcat::mc "%s wants play black." $nick] } default { return [list error modify bad-request] } } Message $wf.message1 -aspect 50000 -text $message1 Message $wf.message2 -aspect 50000 -text $message2 pack $wf.message1 -pady 1m pack $wf.message2 -pady 1m $w add -text [::msgcat::mc "Agree to play"] \ -command [namespace code [list invited_res $w $xlib $jid \ $iqid $id $color 1]] $w add -text [::msgcat::mc "Refuse to play"] \ -command [namespace code [list invited_res $w $xlib $jid \ $iqid $id $color 0]] $w draw return } proc reversi::invited_res {w xlib jid iqid id color res} { catch { set wf [$w getframe] bind $wf {} destroy $w } if {$res} { switch -- $color { white { start_play $xlib $jid $id black } black { start_play $xlib $jid $id white } default { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify bad-request] \ -to $jid \ -id $iqid } } ::xmpp::sendIQ $xlib result \ -query [::xmpp::xml::create create \ -xmlns games:board \ -attrs [list type reversi \ id $id]] \ -to $jid \ -id $iqid } else { ::xmpp::sendIQ $xlib error \ -error [::xmpp::stanzaerror::error \ modify not-acceptable] \ -to $jid \ -id $iqid } } proc reversi::start_play {xlib jid id color} { set gid [make_gid $jid $id] variable $gid upvar 0 $gid flags set flags(window) [win_id reversi $gid] set flags(xlib) $xlib set flags(opponent) $jid set flags(id) $id set flags(flip) 0 set flags(our_color) $color trace add variable [namespace current]::${gid}(position,turn) write \ [list [namespace current]::set_label_move $gid] make_default_position $gid open $gid } proc reversi::set_label_move {gid args} { variable $gid upvar 0 $gid flags switch -- $flags(position,turn) { white { set flags(move_label) [::msgcat::mc "White"] set move 1 } black { set flags(move_label) [::msgcat::mc "Black"] set move 1 } default { set move 0 } } if {$move && [is_my_move $gid]} { append flags(move_label) [::msgcat::mc " (You)"] } else { append flags(move_label) [::msgcat::mc " (Opponent)"] } } proc reversi::make_default_position {gid} { variable $gid upvar 0 $gid flags for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { set flags(position,$c,$r) "" } } set flags(position,3,3) w set flags(position,4,4) w set flags(position,3,4) b set flags(position,4,3) b set flags(position,turn) black catch {unset flags(position,last_move)} set flags(position,draw) 0 set flags(position,halfmove) 0 set flags(position,history) {} } proc reversi::save_position {gid} { variable $gid upvar 0 $gid flags set flags(saved_position) [array get flags position,*] } proc reversi::restore_position {gid} { variable $gid upvar 0 $gid flags array set flags $flags(saved_position) draw_position $gid update_controls $gid find_legal_moves $gid $flags(position,turn) } proc reversi::make_gid {jid id} { jid_to_tag [concat $jid $id] } proc reversi::turn_recv {gid xmlList} { variable options variable $gid upvar 0 $gid flags set move 0 set draw 0 foreach xml $xmlList { ::xmpp::xml::split $xml tag xmlns attrs cdata subels switch -- $tag { put { set pos [::xmpp::xml::getAttr $attrs pos] set poss [split $pos ","] if {[llength $poss] == 2} { set ct [lindex $poss 0] set rt [lindex $poss 1] set move 1 if {$options(sound) != "" && ![::sound::is_mute]} { ::sound::play $options(sound) } } } resign { end_game $gid 1 [::msgcat::mc "You win (Opponent resigned)"] update_controls $gid draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type reversi \ id $flags(id)]]] } accept { if {$flags(position,draw)} { end_game $gid 0.5 [::msgcat::mc "Draw (Opponent accepted)"] update_controls $gid draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type reversi \ id $flags(id)]]] } else { return [list error modify not-acceptable] } } draw { set draw 1 } } } if {$move && [do_move $gid $ct $rt $draw]} { update_controls $gid $draw draw_position $gid highlight_last_move $gid return [list result [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type reversi \ id $flags(id)]]] } else { return [list error modify not-acceptable] } } ############################################################################### proc reversi::calc_moves {} { variable moves for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { for {set moves(d1,$c,$r) {}; \ set x [expr {$c+1}]; set y [expr {$r+1}]} \ {($x < 8) && ($y < 8)} {incr x; incr y} { lappend moves(d1,$c,$r) $x $y } for {set moves(d2,$c,$r) {}; \ set x [expr {$c-1}]; set y [expr {$r+1}]} \ {($x >= 0) && ($y < 8)} {incr x -1; incr y} { lappend moves(d2,$c,$r) $x $y } for {set moves(d3,$c,$r) {}; \ set x [expr {$c-1}]; set y [expr {$r-1}]} \ {($x >= 0) && ($y >= 0)} {incr x -1; incr y -1} { lappend moves(d3,$c,$r) $x $y } for {set moves(d4,$c,$r) {}; \ set x [expr {$c+1}]; set y [expr {$r-1}]} \ {($x < 8) && ($y >= 0)} {incr x; incr y -1} { lappend moves(d4,$c,$r) $x $y } for {set moves(h1,$c,$r) {}; set x [expr {$c+1}]} \ {$x < 8} {incr x} { lappend moves(h1,$c,$r) $x $r } for {set moves(h2,$c,$r) {}; set x [expr {$c-1}]} \ {$x >= 0} {incr x -1} { lappend moves(h2,$c,$r) $x $r } for {set moves(v1,$c,$r) {}; set y [expr {$r+1}]} \ {$y < 8} {incr y} { lappend moves(v1,$c,$r) $c $y } for {set moves(v2,$c,$r) {}; set y [expr {$r-1}]} \ {$y >= 0} {incr y -1} { lappend moves(v2,$c,$r) $c $y } } } } proc reversi::center {c r} { variable square_size variable line_width set r [expr {7 - $r}] list [expr {$line_width + ($square_size * 0.5) + \ (($square_size + $line_width) * $c)}] \ [expr {$line_width + ($square_size * 0.5) + \ (($square_size + $line_width) * $r)}] } proc reversi::close {gid} { variable $gid upvar 0 $gid flags array unset flags } proc reversi::exists {gid} { variable $gid info exists $gid } proc reversi::button_update_relief {b flag} { set rstate [expr {$flag? {pressed} : {!$pressed}}] if {[catch {$b state $rstate}]} { set relief [expr {$flag? "sunken" : "raised"}] $b configure -relief $relief } } proc reversi::open {gid} { variable options variable square_size variable line_width variable $gid upvar 0 $gid flags set jid $flags(opponent) set w $flags(window) if {[winfo exists $w]} { raise_win $w return } set title [::msgcat::mc "Reversi with %s" \ [get_nick $flags(xlib) $jid chat]] add_win $w -title $title \ -tabtitle $title \ -class Reversi \ -raise 1 set board [canvas $w.board \ -borderwidth 0 \ -highlightthickness 0 \ -width [expr {8 * $square_size + 9 * $line_width}] \ -height [expr {8 * $square_size + 9 * $line_width}]] pack $board -side left -anchor w -padx 2m set flags(board) $board set flags(show_last_move) $options(show_last_move) set slm [Button $w.show_last_move -text [::msgcat::mc "Show last move"] \ -command [list [namespace current]::toggle_show_last_move \ $gid]] button_update_relief $slm $flags(show_last_move) pack $slm -side top -anchor w -fill x set flags(show_last_move_button) $slm set flags(flip) 0 set slm [Button $w.flip -text [::msgcat::mc "Flip view"] \ -command [list [namespace current]::toggle_flip_view $gid]] pack $slm -side top -anchor w -fill x set flags(flip_button) $slm Frame $w.move pack $w.move -side top -anchor w Label $w.move.title -text [::msgcat::mc "Move: "] pack $w.move.title -side left Label $w.move.on_move -anchor w \ -textvariable [namespace current]::${gid}(move_label) pack $w.move.on_move -side left -anchor w set bbox [ButtonBox $w.bbox -orient vertical -spacing 0] set flags(propose_draw_button) \ [$bbox add -text [::msgcat::mc "Propose a draw"] \ -command [list [namespace current]::toggle_draw $gid]] $bbox add -text [::msgcat::mc "Accept the draw proposal"] \ -state disabled \ -command [list [namespace current]::accept_draw $gid] $bbox add -text [::msgcat::mc "Resign the game"] \ -command [list [namespace current]::send_resign $gid] grid columnconfigure $bbox 0 -weight 1 pack $bbox -side bottom -anchor w -fill x set flags(bbox) $bbox set_tooltips #label $w.history -text [::msgcat::mc "History"] #pack $w.history -side top -anchor w set hsw [ScrolledWindow $w.hsw] pack $hsw -side top -fill x -expand yes set ht [Text $w.text -wrap word -height 60 -state disabled] set font [$ht cget -font] set tabstop1 [font measure $font "99.."] set tabstop2 [font measure $font "99..Qa8-a8+= "] $ht configure -tabs "$tabstop1 $tabstop2" $ht tag configure attention \ -foreground [option get $ht errorForeground Text] $hsw setwidget $ht set flags(hw) $ht set dsq_color #77a26d set lsq_color #c8c365 for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { set x1 [expr {$line_width + (($square_size + $line_width) * $c)}] set x2 [expr {($square_size + $line_width) * ($c + 1)}] set y1 [expr {$line_width + (($square_size + $line_width) * $r)}] set y2 [expr {($square_size + $line_width) * ($r + 1)}] set color [expr {($c+$r) % 2 ? $dsq_color : $lsq_color}] set img [expr {($c+$r) % 2 ? "bf" : "wf"}] $board create image $x1 $y1 -image reversi/$img -anchor nw \ -tags [list background [list cr $c [expr {7-$r}]]] $board create rectangle $x1 $y1 $x2 $y2 \ -outline {} -width $line_width \ -tags [list last [list cr $c [expr {7-$r}]]] $board create rectangle $x1 $y1 $x2 $y2 \ -outline {} -width $line_width \ -tags [list square [list cr $c [expr {7-$r}]]] } } bind $board \ [list [namespace current]::motion $gid %x %y] bind $board \ [list [namespace current]::motion $gid %x %y] bind $board \ [list [namespace current]::leave $gid %x %y] bind $board \ [list [namespace current]::release $gid %x %y] bind $w [list [namespace current]::close $gid] make_default_position $gid if {[is_white $flags(our_color)] && $options(flip_white_view)} { toggle_flip_view $gid } draw_position $gid update_controls $gid find_legal_moves $gid $flags(position,turn) } proc reversi::toggle_flip_view {gid} { variable $gid upvar 0 $gid flags set flags(flip) [expr {!$flags(flip)}] set board $flags(board) for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { $board addtag [list temp [expr {7-$c}] [expr {7-$r}]] \ withtag [list cr $c $r] $board dtag [list cr $c $r] } } for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { $board addtag [list cr $c $r] withtag [list temp $c $r] $board dtag [list temp $c $r] } } button_update_relief $flags(flip_button) $flags(flip) draw_position $gid highlight_legal_moves $gid highlight_last_move $gid } proc reversi::set_tooltips {args} { variable options if {$options(show_tooltips)} { set tooltip0 [::msgcat::mc "Press button and make move\ if you want propose draw"] set tooltip1 [::msgcat::mc "Press button if you want\ accept the draw proposal"] set tooltip2 [::msgcat::mc "Press button if you want resign"] } else { set tooltip0 "" set tooltip1 "" set tooltip2 "" } foreach var [info vars [namespace current]::*] { upvar 0 $var flags if {[info exists flags(bbox)]} { catch { $flags(bbox) itemconfigure 0 -helptext $tooltip0 $flags(bbox) itemconfigure 1 -helptext $tooltip1 $flags(bbox) itemconfigure 2 -helptext $tooltip2 } } } } proc reversi::toggle_show_last_move {gid} { variable $gid upvar 0 $gid flags set flags(show_last_move) [expr {!$flags(show_last_move)}] button_update_relief $flags(show_last_move_button) $flags(show_last_move) highlight_last_move $gid } proc reversi::toggle_draw {gid} { variable $gid upvar 0 $gid flags set flags(position,draw) [expr {!$flags(position,draw)}] button_update_relief $flags(propose_draw_button) $flags(position,draw) } proc reversi::update_controls {gid {draw_proposed 0}} { variable $gid upvar 0 $gid flags button_update_relief $flags(propose_draw_button) 0 if {[is_my_move $gid]} { $flags(board) config -cursor "" set flags(position,draw) 0 if {$draw_proposed} { $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state normal $flags(bbox) itemconfigure 2 -state disabled } else { $flags(bbox) itemconfigure 0 -state normal $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state normal } } elseif {![is_white $flags(position,turn)] && \ ![is_black $flags(position,turn)]} { $flags(board) config -cursor "" $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state disabled } else { $flags(board) config -cursor watch $flags(bbox) itemconfigure 0 -state disabled $flags(bbox) itemconfigure 1 -state disabled $flags(bbox) itemconfigure 2 -state disabled } } proc reversi::end_game {gid my_score message} { variable $gid upvar 0 $gid flags set opponent_score [expr {1 - $my_score}] if {[is_black $flags(our_color)]} { set score "$my_score : $opponent_score" } else { set score "$opponent_score : $my_score" } set flags(position,turn) none set flags(move_label) $message set hw $flags(hw) $hw configure -state normal catch {$hw delete attention.first attention.last} $hw delete {end -1 char} end $hw insert end "\n\t\t$score\n" $hw see end $hw configure -state disabled } proc reversi::draw_position {gid} { variable $gid upvar 0 $gid flags $flags(board) delete figure for {set c 0} {$c < 8} {incr c} { for {set r 0} {$r < 8} {incr r} { if {$flags(position,$c,$r) != ""} { if {$flags(flip)} { set c1 [expr {7 - $c}] set r1 [expr {7 - $r}] } else { set c1 $c set r1 $r } $flags(board) create image [center $c1 $r1] \ -image reversi/$flags(position,$c,$r) \ -tags [list figure $flags(position,$c,$r) [list cr $c $r]] } } } } proc reversi::motion {gid x y} { variable line_width variable $gid upvar 0 $gid flags set board $flags(board) set x [$board canvasx $x] set y [$board canvasy $y] $board itemconfigure dst_sq&&square -outline "" -width $line_width $board dtag dst_sq $board addtag dst_sq overlapping $x $y $x $y set tags [$board gettags dst_sq&&background] lassign [lindex $tags [lsearch $tags cr*]] cr c r $board addtag dst_sq withtag [list cr $c $r]&&square if {[info exists flags(position,$c,$r)] && $flags(position,$c,$r) == ""} { $board itemconfigure dst_sq&&square -outline red -width $line_width $board itemconfigure dst_sq&&legal&&square -outline blue -width $line_width } } proc reversi::leave {gid x y} { variable line_width variable $gid upvar 0 $gid flags set board $flags(board) $board itemconfigure dst_sq&&square -outline "" -width $line_width $board dtag dst_sq highlight_last_move $gid } proc reversi::release {gid x y} { variable options variable line_width variable $gid upvar 0 $gid flags set board $flags(board) set x [$board canvasx $x] set y [$board canvasy $y] $board itemconfigure dst_sq&&square -outline "" -width $line_width $board dtag dst_sq $board addtag dst_sq overlapping $x $y $x $y set tags [$board gettags dst_sq&&background] lassign [lindex $tags [lsearch $tags cr*]] cr c r $board dtag dst_sq if {$options(allow_illegal) || [is_my_move $gid]} { if {[do_move $gid $c $r $flags(position,draw)]} { $board itemconfigure [list cr $c $r]&&square -outline "" -width $line_width } } update_controls $gid draw_position $gid highlight_last_move $gid } proc reversi::highlight_last_move {gid} { variable line_width variable $gid upvar 0 $gid flags $flags(board) itemconfigure last -outline "" -width $line_width if {[catch {lassign $flags(position,last_move) ct rt}]} { return } if {$flags(show_last_move)} { set color white } else { set color {} } $flags(board) itemconfigure [list cr $ct $rt]&&last -outline $color -width $line_width } proc reversi::do_move {gid ct rt draw} { variable options variable moves variable $gid upvar 0 $gid flags if {$ct == "" || $rt == ""} { return 0 } set my_move [is_my_move $gid] if {![is_move_legal $gid $ct $rt]} { if {$my_move && !$options(allow_illegal)} { return 0 } if {!$my_move && !$options(accept_illegal)} { return 0 } } save_position $gid if {[is_white $flags(position,turn)]} { set mover w set opp b } else { set mover b set opp w } set flags(position,$ct,$rt) $mover foreach dir {d1 d2 d3 d4 h1 h2 v1 v2} { set state opp foreach {x y} $moves($dir,$ct,$rt) { set pos $flags(position,$x,$y) switch -- $state { opp { if {$pos != $opp} { break } else { set state both } } both { if {$pos == ""} { break } elseif {$pos == $mover} { foreach {x y} $moves($dir,$ct,$rt) { set pos $flags(position,$x,$y) if {$pos == $mover} { break } else { set flags(position,$x,$y) $mover } } break } } } } } set flags(position,last_move) [list $ct $rt] add_move_to_history $gid $ct $rt if {$draw && !$my_move} { attention_message $gid \ [::msgcat::mc "\n\n Opponent proposes a draw\n\n"] } if {$my_move} { send_move $gid $ct $rt } if {[is_white $flags(position,turn)]} { find_legal_moves $gid black } else { find_legal_moves $gid white } set skip [expr {[llength $flags(legal_moves)] == 0}] if {!$skip} { if {[is_white $flags(position,turn)]} { set flags(position,turn) black } else { set flags(position,turn) white } } find_legal_moves $gid $flags(position,turn) set endgame 0 if {$skip && [llength $flags(legal_moves)] == 0} { set endgame 1 lassign [count_pieces $gid] bp wp } elseif {$skip} { add_move_to_history $gid } if {$endgame} { if {$bp == $wp} { # Draw end_game $gid 0.5 [::msgcat::mc "Draw"] } elseif {(($bp > $wp) && [is_black $flags(our_color)]) || \ (($bp < $wp) && [is_white $flags(our_color)])} { # I win end_game $gid 1 [::msgcat::mc "You win"] } else { # Opponent wins end_game $gid 0 [::msgcat::mc "Opponent wins"] } } tab_set_updated [winfo parent $flags(board)] 1 mesg_to_user return 1 } proc reversi::accept_draw {gid} { variable $gid upvar 0 $gid flags ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type reversi \ id $flags(id)] \ -subelement [::xmpp::xml::create accept]] \ -to $flags(opponent) end_game $gid 0.5 [::msgcat::mc "Draw (You accepted)"] update_controls $gid draw_position $gid highlight_last_move $gid } proc reversi::send_resign {gid} { variable $gid upvar 0 $gid flags ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type reversi \ id $flags(id)] \ -subelement [::xmpp::xml::create resign]] \ -to $flags(opponent) end_game $gid 0 [::msgcat::mc "Opponent wins (You resigned)"] update_controls $gid draw_position $gid highlight_last_move $gid } proc reversi::send_move {gid ct rt} { variable $gid upvar 0 $gid flags set put_tags [list [::xmpp::xml::create put -attrs [list pos "$ct,$rt"]]] if {$flags(position,draw)} { lappend put_tags [::xmpp::xml::create draw] } ::xmpp::sendIQ $flags(xlib) set \ -query [::xmpp::xml::create turn \ -xmlns games:board \ -attrs [list type reversi \ id $flags(id)] \ -subelements $put_tags] \ -to $flags(opponent) \ -command [list [namespace current]::send_result $gid] } proc reversi::send_result {gid status xml} { if {$status == "error"} { attention_message $gid \ [::msgcat::mc "\n\n Opponent rejected move:\n %s\n\n" \ [error_to_string $xml]] restore_position $gid } } proc reversi::count_pieces {gid} { variable $gid upvar 0 $gid flags set b 0 set w 0 for {set ct 0} {$ct < 8} {incr ct} { for {set rt 0} {$rt < 8} {incr rt} { switch -- $flags(position,$ct,$rt) { b { incr b } w { incr w } } } } return [list $b $w] } proc reversi::add_move_to_history {gid {ct ""} {rt ""}} { variable $gid upvar 0 $gid flags incr flags(position,halfmove) if {$ct != "" && $rt != ""} { lappend flags(position,history) [list $ct $rt] } else { lappend flags(position,history) skip } set hw $flags(hw) $hw configure -state normal $hw delete 0.0 end $hw insert end "\t[::msgcat::mc Black]\t[::msgcat::mc White]\n" set i 1 foreach {b w} $flags(position,history) { $hw insert end "${i}.\t" if {$b == "skip"} { $hw insert end "--\t" } elseif {$b != {}} { lassign $b ct rt incr rt set lt [format %c [expr {$ct+97}]] $hw insert end "$lt$rt\t" } if {$w == "skip"} { $hw insert end "--\n" } elseif {$w != {}} { lassign $w ct rt incr rt set lt [format %c [expr {$ct+97}]] $hw insert end "$lt$rt\n" } else { $hw insert end "\n" } incr i } lassign [count_pieces $gid] bp wp $hw insert end "\n\t$bp\t$wp\n" $hw see end $hw configure -state disabled } proc reversi::find_legal_moves {gid color} { variable $gid upvar 0 $gid flags set flags(legal_moves) {} for {set ct 0} {$ct < 8} {incr ct} { for {set rt 0} {$rt < 8} {incr rt} { if {$flags(position,$ct,$rt) == "" && \ [check_legal $gid $ct $rt $color]} { lappend flags(legal_moves) [list $ct $rt] } } } highlight_legal_moves $gid } proc reversi::check_legal {gid ct rt color} { variable moves variable $gid upvar 0 $gid flags set me [expr {[is_black $color] ? "b" : "w"}] set opp [expr {[is_black $color] ? "w" : "b"}] foreach dir {d1 d2 d3 d4 h1 h2 v1 v2} { set state opp foreach {x y} $moves($dir,$ct,$rt) { set pos $flags(position,$x,$y) switch -- $state { opp { if {$pos != $opp} { break } else { set state both } } both { if {$pos == ""} { break } elseif {$pos == $me} { return 1 } } } } } return 0 } proc reversi::is_move_legal {gid ct rt} { variable $gid upvar 0 $gid flags expr {[lsearch -regexp $flags(legal_moves) ^[list $ct $rt]] >= 0} } proc reversi::highlight_legal_moves {gid} { variable $gid upvar 0 $gid flags set board $flags(board) $board dtag legal foreach move $flags(legal_moves) { lassign $move ct rt $board addtag legal withtag [list cr $ct $rt]&&square } } proc reversi::attention_message {gid message} { variable $gid upvar 0 $gid flags set hw $flags(hw) $hw configure -state normal $hw delete {end -1 char} end $hw insert end $message attention $hw see end $hw configure -state disabled } proc reversi::is_my_move {gid} { variable $gid upvar 0 $gid flags is_same_color $flags(position,turn) $flags(our_color) } proc reversi::is_white {f} { string equal -length 1 $f w } proc reversi::is_black {f} { string equal -length 1 $f b } proc reversi::is_same_color {f1 f2} { string equal -length 1 $f1 $f2 } proc reversi::add_groupchat_user_menu_item {m xlib jid} { set mm $m.gamesmenu if {![winfo exists $mm]} { menu $mm -tearoff 0 $m add cascade -label [::msgcat::mc "Games"] -menu $mm } $mm add command -label [::msgcat::mc "Reversi..."] \ -command [list [namespace current]::invite_dialog $xlib $jid] } proc reversi::iq_create {varname xlib from iqid xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[::xmpp::xml::getAttr $attrs type] == "reversi"} { if {[::xmpp::xml::isAttr $attrs color]} { set color [::xmpp::xml::getAttr $attrs color] switch -- $color { white - black { } default { set var [list error modify bad-request] } } } else { set color white } set var [[namespace current]::invited_dialog \ $xlib $from $iqid \ [::xmpp::xml::getAttr $attrs id] \ $color] } return } proc reversi::iq_turn {varname xlib from xml} { upvar 2 $varname var ::xmpp::xml::split $xml tag xmlns attrs cdata subels if {[::xmpp::xml::getAttr $attrs type] == "reversi"} { set gid [make_gid $from [::xmpp::xml::getAttr $attrs id]] if {[exists $gid]} { set var [[namespace current]::turn_recv $gid $subels] } else { set var [list error cancel item-not-found] } } return } # Common games:board part proc iq_games_board_create {xlib from xml args} { set res [list error cancel feature-not-implemented] set iqid [::xmpp::xml::getAttr $args -id] hook::run games_board_create_hook res $xlib $from $iqid $xml return $res } proc iq_games_board_turn {xlib from xml args} { set res [list error cancel feature-not-implemented] hook::run games_board_turn_hook res $xlib $from $xml return $res } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/sensible-copy000075500000000000000000000000001500237002100162065ustar00nobodynobodytkabber-plugins/sensible-copy/AUTHORS000064400000000000000000000000661500237002100173370ustar00nobodynobodyKonstantin Khomoutov tkabber-plugins/sensible-copy/INSTALL000064400000000000000000000005101500237002100173120ustar00nobodynobodyAs usual, copy this directory under the ~/.tkabber/plugins directory so that you get a hierarchy like this: ~/.tkabber/plugins ~/.tkabber/plugins/sensible_copy/ ~/.tkabber/plugins/sensible_copy/sensible_copy.tcl Restart Tkabber, to get the plugin loaded. Consult the README file for the details about using this plugin. tkabber-plugins/sensible-copy/README000064400000000000000000000011741500237002100171500ustar00nobodynobody"Sensible Copy" -- chat plugin for Tkabber. I. The idea This plugin modifies the way text is copied in Tkabber chat windows. By default, when a text copying event is generated in the chat input window (via the Ctrl-C keyboard shortcut or the corresponding context menu entry), only the selection in the input window is considered. This plugin changes this behaviour by making Tkabber look for the selected text in the chat window as well, so it's now possible to select text in the chat window and hit Ctrl-C to make it copied to the clipboard. II. Configuration This plugins contains no configuration. vim:et:ts=4:sw=4:tw=64 tkabber-plugins/sensible-copy/license.terms000064400000000000000000000021121500237002100207570ustar00nobodynobodyCopyright (c) 2016 Konstantin Khomoutov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tkabber-plugins/sensible-copy/msgs000075500000000000000000000000001500237002100171575ustar00nobodynobodytkabber-plugins/sensible-copy/msgs/ru.msg000064400000000000000000000016311500237002100203750ustar00nobodynobody# ru.msg -- # # Russian messages for the Sensible Copy Tkabber plugin. # # Author: Konstantin Khomoutov ::msgcat::mcset ru "This plugin copies the selected text from the chat log\ window or the chat input window - depending on which one\ contains the selection."\ "Это раÑширение копирует выделенный текÑÑ‚ либо из окна разговора,\ либо из окна ввода текÑта - в завиÑимоÑти от того, которое из них\ Ñодержит выделение." ::msgcat::mcset ru "Plugins options." "ÐаÑтройки раÑширений." ::msgcat::mcset ru "Whether the sensible text copying plugin is loaded."\ "Загружено ли раÑширение разумного ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑта." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/sensible-copy/sensible-copy.tcl000064400000000000000000000043311500237002100215460ustar00nobodynobody# sensible_copy.tcl -- # # "Sensible Copy" chat plugin for Tkabber. # Copies selected text from the chat window (containing the # log of the conversation) or the input windows -- depending # on which one contains the selection. # # Author: Konstantin Khomoutov # # See license.terms for the terms of distribution. # See README for usage details. package require msgcat namespace eval sensible_copy { variable options ::msgcat::mcload [file join [file dirname [info script]] msgs] variable desc [::msgcat::mc \ "This plugin copies the selected text from the chat log\ window or the chat input window - depending on which one\ contains the selection."] if {![::plugins::is_registered sensible_copy]} { ::plugins::register sensible_copy \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc \ "Whether the sensible text copying plugin is loaded."]\n$desc \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } } proc sensible_copy::load {} { hook::add open_chat_post_hook [namespace current]::prepare_chat_window foreach chatid [chat::opened] { prepare_chat_window $chatid ? } } proc sensible_copy::unload {} { foreach chatid [chat::opened] { unprepare_chat_window $chatid } hook::remove open_chat_post_hook [namespace current]::prepare_chat_window } proc sensible_copy::prepare_chat_window {chatid type} { set iw [::chat::input_win $chatid] bind $iw <<_DefaultCopy>> [bind [winfo class $iw] <>] bind $iw <> \ [list [namespace current]::copy [double% $chatid]] } proc sensible_copy::unprepare_chat_window {chatid} { set iw [::chat::input_win $chatid] bind $iw <> {} bind $iw <<_DefaultCopy>> {} } proc sensible_copy::copy {chatid} { set cw [::chat::chat_win $chatid] set iw [::chat::input_win $chatid] set range [$cw tag ranges sel] if {$range == ""} { event generate $iw <<_DefaultCopy>> return } event generate $cw <> } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/singularity000075500000000000000000000000001500237002100160045ustar00nobodynobodytkabber-plugins/singularity/AUTHORS000064400000000000000000000000661500237002100171350ustar00nobodynobodyKonstantin Khomoutov tkabber-plugins/singularity/INSTALL000064400000000000000000000005021500237002100171110ustar00nobodynobodyAs usual, copy this directory under the ~/.tkabber/plugins directory so that you get a hierarchy like this: ~/.tkabber/plugins ~/.tkabber/plugins/singularity/ ~/.tkabber/plugins/singularity/singularity.tcl Restart Tkabber, to get the plugin loaded. Consult the README file for the details about using this plugin. tkabber-plugins/singularity/README000064400000000000000000000050161500237002100167450ustar00nobodynobody"Singularity" -- main interface plugin for Tkabber. I. The Idea When you chat with someone in Tkabber, the corresponding chat window is opened for the full JID of that person (it is a JID with the resource part: node@server/resource). Since your peers can normally log into their XMPP accounts several times at once (with a different resource each time) Tkabber maintains clear distinction between these full JIDs. On the other hand, most people seldom chat from several connections to their account at once -- quite more often they move between two or more XMPP clients located in places which are geographically quite apart, such as their home and office. In this case it may be convenient to maintain just one chat window open for each person you're chatting with -- for instance, you start chatting whith your peer when he/she is at home, then your peer moves to their office and sends a message from the new location; at this point it might be convenient not to have two chat windows -- old and new -- open, but just the new one. This plugin implements the described functionality: when the new window for a one-on-one chat is about to be opened the plugin checks whether there are any active chat sessions with the same bare JID (that is, without the "/resource" part) as that of the new chat. If there are, they are closed with their conversation log and input history preserved, the new chat window is opened and then the saved data is inserted into the new window. So effectively this plugin makes Tkabber keep just one chat window per bare JID open. The plugin does not touch MUC private chats because in them resource part of the room JID is used to designate participants' nicknames. II. Usage Just install this plugin as usually and restart Tkabber. Currently there's no UI to control the plugin's behaviour. III. Bugs and limitations * Tkabber is currently unable to actually "switch" a chat window from one JID to another, so this plugin works by closing the existing window(s) and opening the new one. While in tabbed mode this looks mostly OK, in windowed mode this may be annoying because the new window will most probably not appear at the same location and layer as the closed window. * For some unknown reason the first line of the input history is lost when the chat state is transferred to the newly opened window. * If there are several chat windows to be closed when the new one is about to be opened, the order in which their conversation logs and input history records are collected is undefined. # vim:tw=64:et tkabber-plugins/singularity/license.terms000064400000000000000000000021121500237002100205550ustar00nobodynobodyCopyright (c) 2008 Konstantin Khomoutov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tkabber-plugins/singularity/msgs000075500000000000000000000000001500237002100167555ustar00nobodynobodytkabber-plugins/singularity/msgs/pl.msg000064400000000000000000000017001500237002100201550ustar00nobodynobody# pl.msg -- # # Polish messages for the Singularity plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Allows closing obsolete chat windows for a contact when a\ new chat session window with that contact is about to be opened." \ "Pozwalaj na zamykanie niepotrzebnych okien rozmów kiedy otwierane\ jest nowe okno rozmowy z danym użytkownikiem." ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "Singularity plugin options. What this plugin makes is to\ do cleanup by closing obsolete chat windows opened for different\ resources of the same contact ensuring only one chat window for a\ contact is opened at any given time." "Opcje wtyczki singularity.\ Wtyczka ta pozwala na utrzymanie porzÄ…dku w oknach rozmów poprzez\ zamykanie wielu okien rozmów dla różnych zasobów tego samego kontaktu." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/singularity/msgs/ru.msg000064400000000000000000000014021500237002100201670ustar00nobodynobody# ru.msg -- # # Russian messages for the Singularity plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Whether the Singularity plugin is loaded." \ "Загружено ли раÑширение Signularity." ::msgcat::mcset ru "This plugin allows closing obsolete chat windows\ for a contact when a new chat session window\ with that contact is about to be opened." \ "Это раÑширение позволÑет закрывать ÑущеÑтвующие окна разговора Ñ\ контактом, еÑли открываетÑÑ Ð½Ð¾Ð²Ð°Ñ ÑеÑÑÐ¸Ñ Ñ€Ð°Ð·Ð³Ð¾Ð²Ð¾Ñ€Ð° Ñ Ñ‚ÐµÐ¼ же контактом\ (Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼ реÑурÑом)." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/singularity/msgs/uk.msg000064400000000000000000000013671500237002100201720ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Singularity plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Whether the Singularity plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Singularity." ::msgcat::mcset uk "This plugin allows closing obsolete chat windows\ for a contact when a new chat session window\ with that contact is about to be opened." \ "Це Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÑÑ” закривати вже Ñ–Ñнуючі вікна розмови з\ контактом, Ñкщо відчинÑєтьÑÑ Ð½Ð¾Ð²Ð° ÑеÑÑ–Ñ Ñ€Ð¾Ð·Ð¼Ð¾Ð²Ð¸ з тим же контактом\ (з іншим реÑурÑом)." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/singularity/singularity.tcl000064400000000000000000000062571500237002100211530ustar00nobodynobody# singularity.tcl -- # # When a new chat window is about to be opened this plugin # checks whether any chats with other resources of this chat peer # are currently opened and closes them all, if any. # In other words, it ensures that only one chat window per bare # JID is opened at any given time. # # Author: Konstantin Khomoutov # # See license.terms for the terms of distribution. # See README for usage details. namespace eval singularity { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered singularity]} { ::plugins::register singularity \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc \ "Whether the Singularity plugin is loaded."]\n[::msgcat::mc \ "This plugin allows closing obsolete chat windows\ for a contact when a new chat session window\ with that contact is about to be opened."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } } proc singularity::load {} { variable contexts; array set contexts {} hook::add open_chat_pre_hook \ [namespace current]::process_new_chat_opening hook::add open_chat_post_hook \ [namespace current]::restore_chat_context } proc singularity::unload {} { hook::remove open_chat_pre_hook \ [namespace current]::process_new_chat_opening hook::remove open_chat_post_hook \ [namespace current]::restore_chat_context variable contexts; unset contexts } proc singularity::process_new_chat_opening {chatid type} { if {![string equal $type chat]} return set from [chat::get_jid $chatid] set barejid [::xmpp::jid::stripResource $from] if {[chat::is_groupchat [chat::chatid \ [chat::get_xlib $chatid] $barejid]]} return variable contexts upvar 0 contexts(input,$chatid) savedinput upvar 0 contexts(history,$chatid) savedhistory variable [namespace parent]::history set savedinput "" set savedhistory [list {}] foreach cid [chat::opened] { set jid [chat::get_jid $cid] if {![::xmpp::jid::equal $from $jid] && [::xmpp::jid::equal $barejid [::xmpp::jid::stripResource $jid]]} { if {$savedinput != ""} { append savedinput \n } append savedinput [[chat::input_win $cid] get 1.0 end-1c] set savedhistory \ [concat $savedhistory [lrange $history(stack,$cid) 1 end]] chat::close $cid } } } proc singularity::restore_chat_context {chatid type} { if {![string equal $type chat]} return variable contexts upvar 0 contexts(input,$chatid) savedinput upvar 0 contexts(history,$chatid) savedhistory if {![info exists savedinput]} return variable [namespace parent]::history [chat::input_win $chatid] insert end $savedinput set history(stack,$chatid) $savedhistory set history(pos,$chatid) 0 unset savedinput savedhistory } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/socials000075500000000000000000000000001500237002100150675ustar00nobodynobodytkabber-plugins/socials/ChangeLog000064400000000000000000000004231500237002100167170ustar00nobodynobody2005-03-17 Alexey Shchepin * socials.tcl: Bugfix 2003-12-03 Alexey Shchepin * socials.tcl: Bugfix (thanks to Sergei Golovan) 2003-05-29 Alexey Shchepin * socials.tcl: Now socials work in private chats tkabber-plugins/socials/README000064400000000000000000000004301500237002100160230ustar00nobodynobodySocials Tkabber plugin -- add many "social" commands like "/dance" that used in Rom and Aladon MUDs. To install, copy socials/ directory to $HOME/.tkabber/plugins (on UNIX), to %APPDATA%\Tkabber\plugins (on Windows), or to $HOME/Library/Application Support/Tkabber (on MacOS X). tkabber-plugins/socials/msgs000075500000000000000000000000001500237002100160405ustar00nobodynobodytkabber-plugins/socials/msgs/de.msg000064400000000000000000000004001500237002100172110ustar00nobodynobody# de.msg -- # # German messages for the Socials Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 15.03.2009 ::msgcat::mcset de "Whether the Socials plugin is loaded." \ "'Socials'-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/socials/msgs/ru.msg000064400000000000000000000004741500237002100172620ustar00nobodynobody# ru.msg -- # # Russian messages for the Socials Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Whether the Socials plugin is loaded." \ "Загружено ли раÑширение Ñ Ñоциальными ÑообщениÑми." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/socials/msgs/uk.msg000064400000000000000000000005101500237002100172420ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Socials Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Whether the Socials plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ñ Ñоціальними повідомленнÑми." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/socials/socials.en000064400000000000000000001721651500237002100171430ustar00nobodynobody#SOCIALS gack Gaaack! $n gacks with dismay! Appalled, you gack at $N. $n gacks expressively, shooting $N a dismayed look. $n gacks, and looks your way, dismayed. That person isn't here. *GACK!* Appalled, $n gacks at $mself! kiss 0 0 Isn't there someone you want to kiss? $ You kiss $M. $n kisses $N. $n kisses you. Never around when required. All the lonely people :( # bounce 0 0 BOIINNNNNNGG! $n bounces around with a happy smile. You bounce onto $S lap and wiggle about. $n bounces onto $N's lap and wiggles about. $n bounces onto your lap and wiggles about. You don't see your plaything. You bounce your head like a basketball. $n plays basketball with $s head. smile 1 0 You smile happily. $n smiles happily. You smile at $M. $n beams a smile at $N. $n smiles at you. There's no one by that name around. You smile at yourself. $n smiles at $mself. dance 1 8 Feels silly, doesn't it? $n dances wildly before you! You lead $M to the dancefloor. $n sends $N across the dancefloor. $n sends you across the dancefloor. Eh, WHO? You skip and dance around by yourself. $n skips a light Fandango. cackle 0 0 You cackle gleefully. $n throws back $s head and cackles with insane glee! You cackle gleefully at $N $n cackles gleefully at $N. $n cackles gleefully at you. Better keep your distance from $m. You can't find a friend to cackle with. You cackle at yourself. Now, THAT'S strange! $n is really crazy now! $e cackles at $mself. laugh 0 0 You fall down laughing. $n falls down laughing. You laugh at $N mercilessly. $n laughs at $N mercilessly. $n laughs at you mercilessly. Hmmmmph. You can't find the butt of your joke. You laugh at yourself. I would, too. $n laughs at $mself. Let's all join in!!! giggle 0 0 You giggle. $n giggles. You giggle in $S presence. $n giggles at $N's actions. $n giggles at you. Hope it's not contagious! You giggle by yourself, since you can't find a partner to giggle with. You giggle at yourself, which makes you giggle at yourself, which makes you ... $n giggles at $mself. $e must be nervous or something. shake 0 5 You shake your head. $n shakes $s head. You shake $S hand. $n shakes $N's hand. $n shakes your hand. Sorry good buddy, but that person doesn't seem to be here. You are shaken by yourself. $n shakes and quivers like a bowl full of jelly. puke 0 0 You puke...chunks everywhere!!! YUK! $n pukes. You puke on $M. $n pukes on $N. $n spews vomit and pukes all over your clothing! Once again? You puke on yourself. $n pukes on $s clothes. growl 0 0 Grrrrrrrrrr... $n growls. Grrrrrrrrrr....take that, $N!!! $n growls at $N. Better leave the room before the fighting starts. $n growls at you. Hey, two can play it that way! No one can see you growl that far. You growl at yourself. Boy, do you feel bitter! $n growls at $mself. This could get interesting... scream 0 0 ARRRRRRRRRRGH!!!!! $n screams loudly! ARRRRRRRRRRGH!!!!! Yes, it MUST have been $S fault!!! $n screams loudly at $N. Better leave before $n blames you, too!!! $n screams at you! That's not nice! *sniff* Your lungs can't reach that far! You scream at yourself. Yes, that's ONE way of relieving tension! $n screams loudly at $mself! Is there a full moon up? comfort 0 5 Do you feel uncomfortable? $ You comfort $M. $n comforts $N. $n comforts you. Comfort who? You make a vain attempt to comfort yourself. $n has no one to comfort $m but $mself sigh 0 0 You sigh. $n sighs. You sigh as you think of $M. $n sighs at the sight of $N. $n sighs as $e thinks of you. Touching, huh? You really sigh, since you don't see your friend. You sigh at yourself. You MUST be lonely. $n sighs at $mself. What a sorry sight. sulk 1 0 You sulk. $n sulks in the corner. # hug 1 5 Hug who? $ You hug $M. $n hugs $N. $n hugs you. Sorry, friend, I can't see that person here. You hug yourself. $n hugs $mself in a vain attempt to get friendship. snuggle 1 5 Who? $ You snuggle $M. $n snuggles up to $N. $n snuggles up to you. They aren't here. You snuggle up, getting ready to sleep. $n snuggles up, getting ready to sleep. cuddle 1 5 Who do you feel like cuddling today? $ You cuddle $M. $n cuddles $N. $n cuddles you. They aren't here. You must feel very cuddly indeed ... :) $n cuddles up to $s shadow. What a sorry sight. nuzzle 1 5 Nuzzle who?? $ You nuzzle $S neck softly. $n softly nuzzles $N's neck. $n softly nuzzles your neck. No.. they aren't here.. I'm sorry, friend, but that's impossible. # cry 0 5 Waaaaah.. $n bursts into tears. You cry on $S shoulder. $n cries on $N's shoulder. $n cries on your shoulder. Who's that? You cry to yourself. $n sobs quietly to $mself. poke 0 0 Poke who?? $ You poke $M in the ribs. $n pokes $N in the ribs. $n pokes you in the ribs. You can't poke someone who's not here!. You poke yourself in the ribs, feeling very silly. $n pokes $mself in the ribs, looking very sheepish. accuse 0 5 Accuse who?? $n is in an accusing mood. You look accusingly at $M. $n looks accusingly at $N. $n looks accusingly at you. Accuse somebody who's not even there ?? You accuse yourself. $n seems to have a bad conscience. grin 0 0 You grin evilly. $n grins evilly. You grin evilly at $M. $n grins evilly at $N. $n grins evilly at you. Hmmm. Better keep your distance. You must be delirious. You grin at youself. You must be getting very bad thoughts. $n grins at $mself. You must wonder what's in $s mind. bow 0 5 You bow deeply. $n bows deeply. You bow before $M. $n bows before $N. $n bows before you. Who's that? You kiss your toes. $n folds up like a jacknife and kisses $s own toes. applaud 0 0 Clap, clap, clap. $n gives a round of applause. You clap at $N's actions. $n claps at $N's actions. $n gives you a round of applause. You MUST'VE done something good! You give your imaginary round of applause to your imaginary friend. You applaud at yourself. Boy, are we conceited! $n applauds at $mself. Boy, are we conceited! blush 0 0 Your cheeks are burning. $n blushes. You get all flustered up seeing $M. $n blushes as $e sees $N here. $n blushes as $e sees you here. Such an effect on people! You blush as you notice that person isn't here. You blush at your own folly. $n blushes as $e notices $s boo-boo. burp 0 0 You burp loudly. $n burps loudly. You burp loudly to $M in response. $n burps loudly in response to $N's remark. $n burps loudly in response to your remark. You can't find your victim. You burp at yourself. $n burps at $mself. What a sick sight. chuckle 0 0 You chuckle politely. $n chuckles politely. You chuckle at $S joke. $n chuckles at $N's joke. $n chuckles at your joke. You can't find a friend to chuckle with. You chuckle at your own joke, since no one else would. $n chuckles at $s own joke, since none of you would. clap 0 0 You clap your hands together. $n shows $s approval by clapping $s hands together. You clap at $S performance. $n claps at $N's performance. $n claps at your performance. You clap for nothing. You clap at your own performance. $n claps at $s own performance. cough 0 0 Yuck, try to cover your mouth next time! $n coughs loudly. # curtsey 0 0 You curtsey to your audience. $n curtseys gracefully. You curtsey to $M. $n curtseys gracefully to $N. $n curtseys gracefully for you. You curtsey to no one in particular. You curtsey to your audience (yourself). $n curtseys to $mself, since no one is paying attention to $m. fart 0 0 Where are your manners ? $n lets off a real rip-roarer ... a greenish cloud envelops $n! You fart at $M. Boy, you are sick. $n farts in the direction of $N. Better flee before $e turns to you! $n farts in your direction. You gasp for air. You can't hold it that long! You fart at yourself. You deserve it. $n farts at $mself. Better $m than you. flip 0 0 You flip head over heels. $n flips head over heels. You flip $M over your shoulder. $n flips $N over $s shoulder. $n flips you over $s shoulder. Hmmmm. You can't find the person. You tumble all over the room. $n does some nice tumbling and gymnastics. fondle 0 5 Who needs to be fondled ? $ You fondly fondle $M. $n fondly fondles $N. $n fondly fondles you. You fondly try to fondle someone not in the room, but who cares. You fondly fondle yourself, feels funny doesn't it? $n fondly fondles $mself - this is going too far!! frown 0 0 You frown disapprovingly. $n frowns. You frown at what $E did. $n frowns at what $N did. $n frowns at what you did. You don't see any reason to frown. You frown at yourself. Poor baby. $n frowns at $mself. What a sad puppy.... gasp 0 0 You gasp in astonishment. $n gasps in astonishment. You gasp as you realize what $E did. $n gasps as $e realizes what $N did. $n gasps as $e realizes what you did. You need to panic. You look at yourself and gasp! $n takes one look at $mself and gasps in astonisment! glare 0 5 You glare at nothing in particular. $n glares around $m. You glare icily at $M. $n glares at $N. $n glares icily at you, you feel cold to your bones. You try to glare at somebody who is not present. You glare icily at your feet, they are suddenly very cold. $n glares at $s feet, what is bothering $m? groan 0 0 You groan loudly. $n groans loudly. You groan at the sight of $M. $n groans at the sight of $N. $n groans at the sight of you. You see no reason to groan. You groan as you realize what you have done. $n groans as $e realizes what $e has done. grope 0 5 Whom do you wish to grope ?? $ Well, what sort of noise do you expect here? $n gropes $N. $n gropes you. Try someone who's here. You grope yourself - YUCK. $n gropes $mself - YUCK. hiccup 0 0 *HIC* $n hiccups. # lick 0 0 You lick your mouth and smile. $n licks $s mouth and smiles. You lick $N's jawline delicately. $n licks $N's jawline delicately. $n licks your jawline delicately. Lick away, nobody's here with that name. You lick your own eyebrows. $n licks $s own eyebrows. love 0 0 You love the whole world. $n loves everybody in the world. You tell your true feelings to $N. $n whispers softly to $N. $n whispers to you sweet words of love. Alas, your love is not present... Well, we already know you love yourself (lucky someone does !) $n loves $mself, can you believe it ? moan 0 0 You start to moan. $n starts moaning. You moan for the loss of $M. $n moans for the loss of $N. $n moans at the sight of you. Hmmmm. You see no cause to moan. You moan at yourself. $n makes $mself moan. nibble 0 0 Nibble on who ? $ You nibble on $N's ear. $n nibbles on $N's ear. $n nibbles on your ear. Sorry, not present. You nibble on your OWN ear ??????????????????? $n nibbles on $s OWN ear (I wonder how it is done !!). pout 0 0 Ah, don't take it so hard. $n pouts. # ruffle 0 0 You've got to ruffle SOMEONE. $ You ruffle $N's hair playfully. $n ruffles $N's hair playfully. $n ruffles your hair playfully. Might be a bit difficult. You ruffle your hair, wondering how far you can go before the rest think you're crazy. $n ruffles $s hair - weirdo! shiver 0 0 Brrrrrrrrr. $n shivers uncomfortably. You shiver at the thought of fighting $M. $n shivers at the thought of fighting $N. $n shivers at the suicidal thought of fighting you. You don't see any reason to shiver. You shiver to yourself? $n scares $mself to shivers. shrug 0 0 You shrug. $n shrugs helplessly. You shrug in response to $S question. $n shrugs in response to $N's question. $n shrugs in response to your question. You shrug to no one in particular. You shrug to yourself. $n shrugs to $mself. What a strange person. sing 0 0 You raise your clear (?) voice towards the sky. HEY CLERICS! I COULD USE A HEAL! $n has begun to sing. You sing a ballad to $M. $n sings a ballad to $N. $n sings a ballad to you! How sweet! You see no one to sing to. You sing a little ditty to yourself. $n sings a little ditty to $mself. slap 0 0 What is the sound of one hand slapping? $ *thwock!* You slap $N ringingly. *thwock!* $n slaps $N! $n slaps you stingingly. How about slapping someone in the same room as you ?? You slap yourself, silly you. $n slaps $mself, really strange ... smirk 0 0 You smirk. $n smirks. You smirk at $S saying. $n smirks at $N's saying. $n smirks at your saying. You want to smirk to whom? You smirk at yourself. Okay..... $n smirks at $s own 'wisdom'. snap 0 0 Eureka! You snap your fingers. $n snaps $s fingers. You snap back at $M. $n snaps back at $N. $n snaps back at you! You must be very agitated. You snap yourself to attention. $n snaps $mself to attention. sneeze 0 0 Gesundheit ! $n sneezes. # snicker 0 0 You snicker softly. $n snickers softly. You snicker with $M about your shared secret. $n snickers with $N about their shared secret. $n snickers with you about your shared secret. Huh? You snicker at your own evil thoughts. $n snickers at $s own evil thoughts. sniff 0 0 You sniff sadly. *SNIFF* $n sniffs sadly. You sniff sadly at the way $E is treating you. $n sniffs sadly at the way $N is treating $m. $n sniffs sadly at the way you are treating $m. You see no reason to sniff. You sniff sadly at your lost opportunities. $n sniffs sadly at $mself. Something MUST be bothering $m. snore 0 0 Zzzzzzzzzzzzzzzzz. $n snores loudly. # squeeze 0 0 Where, what, how, WHO ??? $ You squeeze $M fondly. $n squeezes $N fondly. $n squeezes you fondly. Where, what, how, WHO ??? You squeeze yourself - try to relax a little! $n squeezes $mself. stare 0 5 You stare at the sky. $n stares at the sky. You stare dreamily at $N, completely lost in $S eyes.. $n stares dreamily at $N. $n stares dreamily at you, completely lost in your eyes. You stare and stare but can't see that person anywhere... You stare dreamily at yourself - enough narcissism for now. $n stares dreamily at $mself - NARCISSIST! strut 0 0 Strut your stuff. $n struts proudly. You strut to get $S attention. $n struts, hoping to get $N's attention. $n struts, hoping to get your attention. You don't see an audience. You strut to yourself, lost in your own world. $n struts to $mself, lost in $s own world. thank 0 5 Thank you too. $ You thank $N heartily. $n thanks $N heartily. $n thanks you heartily. No one answers to that name here. You thank yourself since nobody else wants to ! $n thanks $mself since you won't. twiddle 0 0 You patiently twiddle your thumbs. $n patiently twiddles $s thumbs. You twiddle $S ears. $n twiddles $N's ears. $n twiddles your ears. You don't see the person here. You twiddle your ears like Dumbo. $n twiddles $s own ears like Dumbo. wave 0 0 You wave. $n waves happily. You wave goodbye to $N. $n waves goodbye to $N. $n waves goodbye to you. Have a good journey. They didn't wait for you to wave goodbye. Are you going on adventures as well?? $n waves goodbye to $mself. whistle 0 0 You whistle appreciatively. $n whistles appreciatively. You whistle at the sight of $M. $n whistles at the sight of $N. $n whistles at the sight of you. You don't see nothing special to whistle at. You whistle a little tune to yourself. $n whistles a little tune to $mself. wiggle 0 0 Your wiggle your bottom. $n wiggles $s bottom. You wiggle your bottom toward $M. $n wiggles $s bottom toward $N. $n wiggles $s bottom toward you. You must be alone. You wiggle about like a fish. $n wiggles about like a fish. wink 0 5 Have you got something in your eye? $n winks suggestively. You wink suggestively at $N. $n winks at $N. $n winks suggestively at you. No one with that name is present. You wink at yourself ?? - what are you up to? $n winks at $mself - something strange is going on... yawn 0 0 You must be tired. $n yawns. # snowball 0 0 Who do you want to throw a snowball at? $ You throw a snowball in $N's face. $n conjures a snowball from the thin air and throws it at $N. $n conjures a snowball from the thin air and throws it at you. You stand with the snowball in your hand because your victim is not here. You conjure a snowball from the thin air and throw it at yourself. $n conjures a snowball out of the thin air and throws it at $mself. french 0 0 Kiss whom? $ You give $N a long and passionate kiss, it seems to last forever... $n kisses $N passionately. $n gives you a long and passionate kiss, it seems to last forever... Your heart is filled with despair as that person is not here. You gather yourself in your arms and try to kiss yourself. $n makes an attempt at kissing $mself. comb 0 0 You comb your hair - perfect. $n combs $s hair, what a dashing specimen ! You patiently untangle $N's hair - what a mess ! $n tries patiently to untangle $N's hair. $n pulls your hair in an attempt to comb it. That person is not here. You pull your hair, but it will not be combed. $n tries to comb $s tangled hair. massage 0 0 Massage what? Thin air? $ You gently massage $N's shoulders. $n massages $N's shoulders. $n gently massages your shoulders - Ahhhhhhhhhh... You can only massage someone in the same room as you. You practice yoga as you try to massage yourself. $n gives a show on yoga-positions, trying to massage $mself. tickle 0 0 Whom do you want to tickle? $ You tickle $N. $n tickles $N. $n tickles you - ho ho ho. Who is that?? You tickle yourself, how funny! $n tickles $mself. pat 0 0 Pat who? $ You pat $N on $S head. $n pats $N on $S head. $n pats you on your head. Who, where, what? You pat yourself on your head, very reassuring. $n pats $mself on the head. curse 0 0 You swear loudly for a long time. $n swears : #@*"*&^*#%@*&! !!!!! You swear at $M. $n swears at $N. $n swears at you! Where are the manners? You can't find the victim of your frustrations. You swear at your own mistakes. $n starts swearing at $mself. Why don't you help? pray 0 0 You feel righteous, and maybe a little foolish. $n begs and grovels to the powers that be. You crawl in the dust before $M. $n falls down and grovels in the dirt before $N. $n kisses the dirt at your feet. No such person around; your prayers vanish into the endless voids. Talk about narcissism... $n performs some strange yoga-exercises and mumbles a prayer to $mself. beg 0 0 You beg the gods for mercy. The gods fall down laughing at $n's request for mercy. You desperately try to squeeze a few coins from $M. $n begs you for money. You graciously let $m peep at your fortune. $n begs $N for a dime or two - or twenty ! Your money-lender seems to be out for the moment. Begging yourself for money doesn't help. # cringe 1 0 You cringe in terror. $n cringes in terror! You cringe away from $M. $n cringes away from $N in mortal terror. $n cringes away from you. I don't see anyone by that name here.. what are you afraid of? I beg your pardon? # daydream 1 0 You dream of better times. $n looks absent-minded, his eyes staring into space. # fume 1 5 Take it easy now! count to ten, very slowly. $n grits $s teeth and fumes with rage. You stare at $M, fuming. $n stares at $N, fuming with rage. $n stares at you, fuming with rage! Fume away... they ain't here. That's right - hate yourself! $n clenches $s fists and stomps his feet, fuming with anger. grovel 1 0 You grovel in the dirt. $n grovels in the dirt. You grovel before $M $n grovels in the dirt before $N. $n grovels in the dirt before you. Who? That seems a little silly to me. # hop 0 0 You hop around like a little kid. $n hops around like a little kid. # nudge 0 0 Nudge whom? $ You nudge $M. $n nudges $N. $n nudges you. Who? You nudge yourself, for some strange reason. $n nudges $mself, to keep $mself awake. ponder 0 0 You ponder the question. $n sits down and thinks deeply. # punch 0 0 Punch whom? $ You punch $M playfully. $n punches $N playfully. $n punches you playfully. OUCH! You can't find your boxing partner. You punch yourself. You deserve it. $n punches $mself. Why don't you join in? snarl 0 0 You grizzle your teeth and look mean. $n snarls angrily. You snarl at $M. $n snarls at $N. $n snarls at you, for some reason. No need to snarl! You snarl at yourself. $n snarls at $mself. spank 0 0 Spank whom? $ You spank $M playfully. $n spanks $N playfully. $n spanks you playfully. OUCH! Your hand can't find your victim! You spank yourself....HMMMMMMM... $n spanks $mself....HMMMMMMM... hand 0 0 Kiss whose hand? $ You kiss $S hand. $n kisses $N's hand. How continental! $n kisses your hand. How continental! You can't find a lady in THIS group. You kiss your own hand. $n kisses $s own hand. yodel 1 0 You think of Julie Andrews and start to yodel. $n begins to yodel: HEY!! CLERICS!! I COULD USE A HEAL!!! $N covers $S ears as you begin to yodel. $n yodels to $N. $n yodels to you...you cringe and turn away. That person just escaped! Well, it's up to you if you want to damage your hearing. $n yodels to $mself. What a sado-masochist. faint 1 0 You faint. $n faints. You faint into $S arms. $n faints into $N's open arms. $n just fainted into YOUR arms. You fall on the floor and look stupid--really suave. # pinch 1 0 You say, 'A pinch of this, and a dab of that.' $n says, 'A pinch of this and a dab of that.' You squeeze $S bottom and grin. $n pinches $N's bottom and grins. $n pinches your bottom and grins. You'd like to, wouldn't you? You pinch yourself to see if you are dreaming! $n pinches $mself to see if $e is dreaming! stroke 1 0 You stroke the air vaguely. $n makes vague stroking motions. You gently stroke $S inner thigh. $N inhales sharply. $N exhales sharply and suddenly. $n gently strokes your inner thigh. You inhale sharply. Maybe you should practice on yourself first. You are about to do something you'd rather not be caught doing. # apologize 1 0 You apologize until you are blue in the face. $n apologizes profusely. You might as well apologize because $E sure as hell won't. $n apologizes to $N with a very sincere look on $s face. $n apologizes to you and begs for forgiveness. Who's that? # caress 1 0 Who do you wish to caress? $n looks for someone to caress. You tenderly caress $M. $n tenderly caresses $N. $n tenderly caresses your body. You're S.O.L., buddy. # stagger 1 8 You stagger blindly around the room. $n staggers blindly around the room. You stagger toward $N as the room begins to spin. $n staggers into $N. $n staggers blindly into you. Stagger into whom!?!? # snort 1 0 You snort derisively. $n snorts derisively. You snort derisively at $N. $n snorts derisively at $N. $n snorts at you. Snort at whom? You snort derisively at yourself. $n snorts derisively at $sself. slobber 1 0 You slobber down your front. $n slobbers all over $mself. You slobber on $N. $n slobbers on $N **Yuck** $n slobbers disgustingly on you. Slobber on WHOM? # blink 1 0 You bat your eyelashes. $n blinks innocently. You blink innocently at $N. $n blinks innocently at $N. $n blinks innocently at you. Feign innocence for whom? You try to convince yourself of your innocence. # tease 1 0 What a tease. SHEESH. $n looks around for someone to tease. You tease $N in a playful way. $n sticks $s tongue out at $N. $n sticks $s tongue out at you, what a DORK!! Tease whom? You tease yourself. NYAH NYAH NYAH. $n teases $mself. knee 1 8 You raise one knee, preparing to do justice... $n cocks one knee threateningly. You knee $M hard in the groin. $N doubles over in pain as $n knees $M in the groin! $n suddenly knees you in the groin! You fall to your knees in agony. Whom do you wish to render impotent? What ARE you thinking !?!??!?!?!?! # flirt 1 0 You flirt outrageously. $n is an outrageous flirt. You flirt with $N trying to get $S attention. $n flirts with $N, hmmm wonder what $e wants? *wink* $n flirts with you. Sorry no one here to flirt with. :( You flirt with yourself -- what ARE you trying to gain!?!?!? $n flirts with $mself, wonder what $e is trying to accomplish? tip 1 0 You tip your hat gallantly. $n gallantly tips $s hat. You tip your hat to $N. $n gallantly tips $s hat to $N. $n gallantly tips $s hat to you. But there is no one here to impress?!?! # lust 1 0 Your hormones begin to rage. $n has that look of lust in $s eyes --- Get away QUICK! You have lust after $N. $n looks lustily at $N. $n lusts after your delectable body. Whom are you trying to lust after? Oh, please! You aren't THAT great... $n lusts after $mself, lonely eh? flutter 1 0 You flutter your eyelashes seductively. $n flutters $s eyelashes seductively. You flutter your eyelashes at $N, trying to be seductive. $n flirts with $N, flutters $s eyelashes at $M. $n flutters $s eyelashes at you coyly. EH? Can't see them here. # bark 1 0 You bark loudly. $n barks like a dog. GO DAWGS SIC 'EM!!! WOOF! WOOF! WOOF! WOOF! You bark at $N scaring $M silly -- SHAME ON YOU!! $n barks at $N scaring $M senseless. $n barks loudly at you, you back away, because $e might bite too!! Bark at whom? You bark at yourself and jump back in fear. $n barks at $mself and cowers in fear. howl 1 0 You howl at the moon. $n howls at the moon. You howl soulfully at $N. $n howls at $N. $n howls soulfully at you. Who? What? Where? # babble 1 0 You babble endlessly. $n babbles endlessly, won't $e EVER shut up? You babble to $N for hours on end. $n babbles to $N for what seems an eternity, how can $N stand it? $n babbles at you. You nod mechanically, hoping $e will shut up soon. Whom do you wish to annoy with your babble? You babble on and on to yourself, FINALLY! someone who LISTENS!! $n babbles quietly to $mself. ramble 1 0 You ramble on and on. $n rambles on about a boring exploit. You ramble on to $N about your past adventures. $n blithers on and on to $N about something. $n tells you a rather boring tale, you feign interest. ??EH?? # hush 1 0 SHHHHHHHHHHHHHHHHHHHHHH $n requests everyone quiet down. Shhhhhhhhhhh... You nicely ask $N to be more quiet. $n nicely asks $N to be more quiet. $n kindly requests that you please quiet down. Who needs to be silenced? You realize you are loud and obnoxious and try to silence yourself. $n covers $s mouth in an attempt to silence $mself. threaten 1 8 You threaten everyone with your overwhelming presence. You feel threatened in the presence of the great $n. You stand tall as you threaten $N. $n threatens $N forcefully. $n threatens you...oooooooh scary *laugh* Whom do you wish to intimidate? # roll 1 0 You roll your eyes in disgust. $n rolls $s eyes, disgusted. You look at $N and roll your eyes in disgust. $n rolls $s eyes in disgust at $N. $n rolls $s eyes at you. You should be disgusted with yourself because you look so foolish. At whom do you wish to roll your eyes? # swoon 1 0 You swoon. $n swoons in absolute ecstasy. You look at $N and swoon in ecstasy. $n looks at $N and swoons in ecstasy. $n looks at you and swoons in ecstasy. Who? # bird 1 0 You flick a bird...How obscene! $n flicks a bird at no one in particular. You shoot a bird at $N. $n gives $N the bird. $n gives you the bird...What an ass! Don't you hate to waste a good obscene gesture like that? # eyebrow 1 0 You raise an eyebrow at the notion. $n raises an eyebrow. You raise your eyebrow at $N. $n raises an eyebrow at $N's weird actions. $n raises an eyebrow at you. Forget it. They aren't here. # serenade 1 0 You raise your voice in a loud serenade to your invisible love. $n raises $s voice to serenade the world. You raise your voice in a loving serenade to $N. $n raises $s voice in a loving serenade to $N. $n serenades you, you are swept away by $s voice. The one that you wish to serenade has left you to sing to yourself. You sing a loud serenade to yourself. What type of person are you?! $n serenades $mself. What an ego! grimace 1 0 You grimace painfully at the thought. $n grimaces painfully at the thought. You grimace at $N. $n grimaces at $n. $n grimaces at you. What could be wrong? You grimace at no one in particular. You grimace painfully at your thoughts. $n grimaces painfully to $mself. boggle 1 0 You boggle at the concept. $n boggles at the concept. You boggle at $N. $n boggles at $N. $n boggles at you. Boggle away. They've left. You boggle at yourself. Hmmm...intriguing. $n boggles quietly to $mself. beckon 1 0 You beckon for everyone to follow. $n beckons for everyone to follow. You beckon for $N to follow -- sure hope they do! $n beckons $N to follow...hmmm what's going on? $n beckons for you to follow. So sorry, that person has already left. You beckon to your shadow to follow. $n beckons to $s shadow to follow. wonder 1 0 You wonder about how things could have been. $n gets a blank stare on $s face. What could $e be wondering about? You look at $N and wonder what will happen. $n looks at $N and wonders.... $n looks at you quizzically. You wonder what would have happened had they been here. You wonder about yourself and your purpose here. A blank stare crosses $n's face. What could $e be wondering about? worry 1 0 You worry about what's going to happen. A troubled look suddenly crosses $n's face. Wonder what's wrong? You look at $N worriedly. $n looks at $N with a troubled gaze. $n looks at you worriedly. Well they obviously aren't worried -- they left! You worry about what's going to happen. A troubled look suddenly crosses $n's face. Wonder what's wrong? drool 1 0 You drool down the front of your shirt. $n drools all over $mself -- making a TERRIBLE mess! You drool messily on $N. $n drools upon $N. $n looks at you lustily and drools. Oh fine, make a pool of slobber -- they aren't even here! You drool down the front of your shirt. $n drools all over $mself -- making a TERRIBLE mess! nod 1 0 You nod. $n nods. You nod at $N. $n nods at $N. $n nods at you in agreement. Nod your head off -- they aren't here. You attempt to nod at yourself and get dizzy instead. $n nods quietly to $mself. What a wacko. purr 1 0 MMMMMMEEEEEEEEEOOOOOOOOOOOOOWWWWWWWWWWW!!!!!!!!!!! $n purrs contentedly. You rub up against $N and purr contentedly. $n rubs against $N and purrs contentedly. $n rubs up against you and purrs contentedly. You silly cat! They aren't here. You purr quietly to yourself. $n purrs contentedly to $mself. point 1 0 You point in every direction. $n points excitedly! You point at $N. $n points excitedly at $N! $n points at you. How rude! You point at no one in particular. You point at yourself, obviously very confused. $n points at $mself, obviously very confused. rub 1 0 You rub your hands together in greedy anticipation. $n rubs $s hands together in greedy anticipation. You give $N a nice, long, kinky rubdown. $n gives $N a nice long rubdown. $n gives you a rubdown, running $s hands over your tense shoulders...Mmmm... Shame to waste those talented hands, but they've already left. You rub yourself...lingering a little too long in some places. $n rubs $mself...what a creep! bleed 1 0 You bleed profusely -- making a horrible mess! $n weakly bleeds all over the floor. You bleed on $N -- ewww! $n bleeds on $N. Watch out, YOU might be next! $n bleeds on you -- ewww! Get away!! Bleed on whom? You bleed all over yourself. $n bleeds profusely all over $mself. highfive 1 0 You jump in the air and give a BIG high five to...umm...absolutely nothing. $n wildly high fives the air, looking very foolish -- very foolish indeed. You jump in the air and give a BIG high five to $N! $n enthusiastically high-five's $N! $n gives you a BIG high five! Way to go!! Sorry, they have already left. You try to give yourself a high five. What ARE you thinking? $n tries to high five $mself, but ends up looking foolish instead. propose 1 0 You propose to everyone in the room. $n proposes to everyone in the room. Very odd. You kneel and romantically propose to $N. $n gets on one knee and proposes to $N. $n gets down on one knee and romantically proposes to you. You must be lonely. They aren't here. You are SO full of yourself! $n proposes to $mself -- how narcissistic! peer 1 0 You peer around yourself intently. $n peers around $mself intently. You peer intently at $N. $n peers intently at $N. $n peers at you intently. They aren't here. You get a little cross-eyed with your attempts to stare yourself down. $n peers at $mself, crossing $s eyes in the process. worship 1 0 You prostrate yourself and worship the gods! $n prostrates $mself and worships the gods! You fall on your knees and worship $N. $n falls on $s knees and worships $N. $n falls to the ground and worships you. You can't worship someone who isn't here. You worship yourself. $n worships $mself. bearhug 1 0 Whom do you wish to bearhug? $ You overwhelm $N with a great, big, hulking bearhug. $n encompasses $N in an ENORMOUS bearhug! $n clutches you tightly in an overwhelming bearhug! Perhaps you should shower your affections on someone who is here? You vainly clutch yourself in a bearhug for consolation. $n hugs $mself as tightly as possible. Looks like $e could use a hand. innocent 1 0 You innocently whistle a tune. $n looks around and whistles innocently. You look at $N and bat your eyelashes -- the picture of innocence! $n bats $s eyelashes innocently at $N. $n looks at you and innocently bats $s eyelashes. Don't even TRY -- they've already left. # collapse 1 0 You collapse on the floor from exhaustion. $n dramatically collapses to the floor from exhaustion. You collapse right into $N's arms. $n collapses right into $N's arms. Suddenly, $n collapses into your arms from exhaustion. They've already left, just collapse on the floor. # stretch 1 0 You lean back and streeeeeettch your arms and legs. $n stretches luxuriously. Kinda makes you want to doesn't it? # spam 1 0 You mutter, 'spam' quietly to yourself again and again. $n rests in a corner and mutters 'spam' quietly to $mself. You SPAM $N mercilessly! $n spams $N! You've been SPAMMED by $n! Spam away -- they've left. # boast 1 0 You boast loudly of all your amazing accomplishments. $n boasts loudly in a pigheaded fashion. You boast to $N of all your great deeds. $n boasts to $N. Once again, $n boasts to you, what a bloated ego! Your ego takes a blow. They've already left. You boast to yourself of all your great feats! Your own biggest fan. $n boasts to $mself -- what an ego! squirm 1 0 You squirm uncontrollably in your consternation. $n squirms uncontrollably, suddenly looking very uncomfortable. You look at $N and squirm with delight. $n looks at $N and squirms with delight. $n looks at you and squirms with delight. # moo You chew your cud and moo plaintively. Muh-OOOOO! $n turns cowlike eyes on you, chews $s cud, and moos plaintively. You focus all your bovine Zen on $N, and speak your thoughts. Muh-OOOOO! Slowly, $n looks at $N, chews $s cud, and muh-OOOOs! $n moos at you. What could that possibly mean? You'd better find someone else to moo at. You settle down into the center of your bovine Zen; the foolish world thinks you're just mooing. $n is mooing at $mself again... You look for an exit... moon 1 0 You drop your drawers and moon everyone in the room! $n drops $s pants and gives you the vertical smile! You bend over and moon $N. $n drops $s pants and rudely moons $N! $n bends over and gives you the vertical smile! You stand, with your pants around your ankles, looking VERY silly! You try to moon yourself, but you can't see your A** that well. $n nearly goes into convulsions while trying to moon $mself. goose 1 0 Who would you like to goose? $ You tenderly goose $N on the tush. $n reaches around $N's backside and gooses $M tenderly. $n gooses you tenderly! You should go hunting for another victim, they left. You pinch yourself on the rear, you must be desperate. $n pinches $mself on the rear. wince 1 0 You wince in agony. $n winces in agony. You look at $N and wince at $S remark. $n winces at $N's remark. $n winces at your remark. # type 1 0 You can't type for crap tonight! You give up in frustration! $n throws $s hands up in disgust at $s lousy typing skills! # brb 1 0 Hope to see you soon! $n will be right back! # mutter 1 0 You mutter quietly to yourself. $n mutters something quietly to $mself. You mutter something to $N. $n looks at $N and mutters something nasty under $s breath. $n looks at you and mutters something nasty under $s breath. There's nothing left for you to say, they've left! You mutter quietly to yourself. $n mutters something quietly to $mself. rofl 1 0 You roll on the floor, laughing hysterically. $n falls to the ground and rolls around laughing hysterically. You fall to the floor laughing at $N's remark. $n rolls on the floor laughing at $N's antics! $n rolls on the floor laughing at your antics! # sob 1 0 You sob quietly to yourself. $n sobs in misery. You sob quietly to yourself because $N has hurt your feelings so badly. $n sobs quietly to $mself because $N was a jerk! You feel like a cad because you've made $n sob. # pant 1 0 You pant lustily. $n pants lustily. You pant lustily at $M. $n looks at $N and pants lustily. $n looks at you and pants lustily... # whine 1 0 You whine to anyone who will listen to you. $n whines pathetically to anyone who will listen. You whine to $M, hoping desperately that at least $E will give a damn. $n whines pathetically to $N. $n whines pathetically to you. What a loser! They really don't care. You whine to yourself, probably the only one who will listen. $n whines to $mself. At least $e isn't bitching to YOU. flex 1 0 You flex your muscles proudly! $n flexes $s muscles...what a stud!?! You show off to $N, flexing your muscles proudly. $n flexes $s muscles, in a vain attempt to impress $N. $n flexes $s muscles in a vain attempt to show off to you. # embrace 1 0 Who would you like to embrace? $ You wrap your arms around $N in a warm and loving embrace. $n wraps $s arms around $N in a warm and loving embrace. $n takes you in $s arms in a warm and loving embrace. Your heart breaks as you realize you are alone. You try to console yourself with a loving embrace. $n tries to console $mself by wrapping $s arms around $mself. duck 1 0 DUCK!!!! $n ducks defensively. You duck defensively, anticipating the oncoming swipe from $N. $n ducks, anticipating $N's reaction. $n ducks, please oh please don't hit $m! # bonk 1 0 ***BONK!!!*** $ You bonk $N on the head for being such a moron. $n bonks $N on the head for being such an UTTER moron. $n bonks you on the head for being so foolish. ***BONK*** they left... You bonk yourself, fool that you are. $n bonks $mself and grimaces in pain. squeal 1 0 You squeal with delight! $n lets out a sudden squeal of delight! You look at $N and squeal with delight! $n squeals with delight at $N. $n looks at you and squeals with delight! # tackle 1 0 You're going to tackle everyone in the room?! $ You tackle $N playfully. $n playfully tackles $N. $n brings you down in a playful tackle! # spit 1 0 You spit in utter disgust. $n spits in utter disgust! You spit on $N...you're gross! $n spits on $N. $n spits on you -- how gross! Your victim isn't here. You spit on yourself, pretty nasty eh? $n spits on $mself...what a sicko! life 0 0 You try to get a life, and fail. $n tries to get a life, and fails. $N needs to get a life! $N needs to get a life! You need to get a life! Who needs a life? But you have none to give! $n attempts to give $mself a life, but has none to spare. mosh 8 0 You mosh insanely around the room! $n moshes insanely around the room! You mosh sadistically against $N ... you WILL be punished. $n bounces off of $N in a vain attempt to mosh... what a LOSER. $n slams into you, moshing painfully against you. That REALLY hurts! Hmmm... your victim found a new dance partner. Masochist! $n throws $mself on the floor, grinding $mself into a bloody pulp flinch 0 0 EEEK... You flinch in obvious pain. $n flinches in obvious pain... you wonder what $e did THIS time. Don't you wish you could just crawl under a rock and die? $n sneaks a glance at $N and flinches. $n flinches in response to your cold rebuke. Relax, $E is gone. You can't belive what you've done... $n twitches violently, shocked at $s own behavior. air 0 0 You grab your air guitar and play for all you're worth. $n air-guitars like a mad man ... EXCELLENT!!! You hope $E appreciates your (total lack of) talent. $n is surrounded by air groupies. $n plays a most excellent tune for you on $s most excellent air guitar. Awww... you have no audience! You play softly to yourself. # tweak 0 0 Tweak who? $ You gently tweak $S cheek. Isn't $E so CUTE? $n tweaked $N's cheek... don't they look so adorable together? $n lovingly tweaks your cheek. It reminds you of Grandma... sniff... *Sniff* That cheek seems to be missing. You can't DO that. # peck 5 0 Wouldn't you like to do that to a person, or do you prefer air? $ Risking a slap to the face, you give $N a peck on the cheek. $n smiles and gives $N a chaste peck on the cheek. $n pecks you on the cheek, how sweet! I guess you scared them away... You must REALLY like yourself. $n tries in vain to wrap $s lips around $s cheeks. explode 0 0 You feel the blood boiling in your veins! $n turns a deep red, fighting to contain $s temper... You feel your rage explode deep in the pit of your stomach... $n burns holes through $N with his explosive anger! $n is ANGRY with you... I'd run if I were you!!! Temper Temper... they left. Your soul burns brightly then fades to nothing. $n implodes!!! Only a grease spot remains where $e once stood. raspberry 4 0 You stick your tongue out at ... well, no one. $n sticks $s tongue out, catching a few flies in the process. You give $N the raspberry... and spit all over yourself. $n gives $N the raspberry... PHBT! What a mess... Spit EVERYWHERE! You are splattered with saliva as $n gives you the raspberry... HOW RUDE! Hang your tongue out if you like, $e isn't here. You try to stick your tongue out at yourself... somehow, it isn't the same. # flash 0 0 You grin and strut as you open your coat and show what you've got! $n rips $s clothes off and parades naked around the room! Swiftly you jerk open your jacket, trying to get $M to notice you. Cover your eyes, $n is exposing $mself to $n! EWWWW! You gasp! $n has just revealed $s "equipment" to you! Exhibitionist, that person isn't here! That's sick. PERVERT PRESENT! $n is trying to flash $mself strip 0 0 You do a slow strip tease for the people... $n begins a slow, erotic strip-tease act... You start to undress $N ... one piece of clothing at a time... $n runs $s hands over $Ns body, slowly stripping away the clothing... $n has started to strip you... woah BABY! Your toy doesn't seem to be here... You can't DO that in public! # undress 0 0 You start to undress in the shadows, waiting for someone to notice. $n begins to undress... $e is VERY sexy... *Pant* You undress $M with your eyes... Kinky. You feel the temperature of the room rise as $n lusts on $N... Feeling exposed, you sense $n undressing you with $s eyes... They are not here... A mirror would work better... # tongue 0 0 You slowly give your tongue a nice workout. $ Mmmm... you give $N a good working over with your tongue... $n slides $s tongue over $N's body... $n wraps $s tongue around you, moving it across your young, nubile flesh... Never around when required... You slowly tongue yourself. $n slowly tongues $mself... ICK. view 0 0 You sit back and watch the world go by. $n kicks back and enjoys the view. # grumble 0 0 You grumble distractedly to yourself $n grumbles and growls. You wonder what's wrong... You grumble at $N, disgusted with their presence. $n seems to be a grumpy bear... $e is grumbling at poor $N. $n is grumbling at you... what'd you do? That person is presently AWOL. Why bother? # cheer 0 0 You cheer and dance as the joy within you bursts forth! $n cheers and sings... $e is just BURSTING with joy! You cheer $N on and wish $M good luck! *Yay!* Go $N!!! $n cheers $M on. You are cheered on by $n... you feel so loved! Who? Huh? Where? They're not here, that's for sure You cheer silently for yourself since nobody else will $n resorts to cheering for $mself... how sad. plead 0 0 You beg and plead to anyone who will listen. $n pleads $s case to anyone who will listen... You ALMOST feel sorry for $s. # charge 0 0 You charge into the fray! $n charges into the fray! All guts, no brains. With surprising dexterity, you head-butt $N! $n ducks down low, charges forward, and head-butts $N! OOF! $n rammed $s head into your stomach! That HURT. Nobody 'round with that name, Mister! You run your head into a brick wall. OUCH! # criticize 0 0 Yes, but who? $ You criticize $M with all the warmth of a snake. With a nasty grin, $n rips apart $Ns efforts. $n informs you that your attempts need some MAJOR adjustments. Where oh where has my victim gone, oh where oh where... You criticize yourself profusely. $n tears $mself apart, cursing $s own stupidity. run 0 0 You run away in terror and horror! $n runs away in utter terror! You run away from $N in complete terror! $n runs away from $N in utter terror and horror! $n runs from you, fearing for $s life! No reason to be afraid, they aren't here. Are you THAT ugly? $n looks in the mirror, sees $s face, and runs away terrified! judge 0 0 Yes, but who? $ You judge $m on a scale of 1 to 10. On a scale from 1 to 10, $n thinks $N is a complete ZERO!!! $n judges your actions on a scale of 1 to 10 and comes up with ZERO!!! They aren't here right now. You don't REALLY want to do that. # insane 0 0 You feel your sanity slipping away... Before your eyes, $n's sanity is slipping away... # cover 0 0 You cover your ears to protect them from the noise. $n covers $s ears to protect them from all the noise. You glare at $N and cover your ears. $n glares at $N and covers $s ears. $n covers $s ears because of you... you are TOO LOUD! They aren't here right now. No... I don't think so. # flare 0 0 You flare your nostrils disdainfully. $n flares $s nostrils disdainfully. You flare your nostrils disdainfully at $N... HOW RUDE! $n flares $s nostrils disdainfully at $N and turns up $s snobbish nose. $n flares $s nostrils disdainfully at you... what'd you DO??? Flare if you wish, but that person isn't here to see it. *Sniff* But you should LOVE yourself! # head 0 0 You toss your head haughtily. $n tosses $s head haughtily. You toss your head haughtily at $N. $n tosses her head haughtily at $N... what an ATTITUDE! $n tossed $s head haughtily at you... :( That person is AWOL. Why would you do that? # pie 0 0 You pick up a pie and toss it around for a bit. $n picks up a pie and tosses it around for a bit. You toss a pie at $N and hit $M right in the FACE! $n tosses a pie at $N and hits $m right in the FACE! $n tossed a pie in your face... and now you are all covered in GOO! That person isn't here... You bury your face in the pie... yummmmm!!! :) $n buries $s face in the pie, licking the pan clean. cower 0 0 You cower in a corner. $n cowers in a corner and whimpers softly. You cower away from $N and $S harsh words. $n cowers in a corner, terrified that $N will come after $m. You scared poor $n! Now $S is cowering in a corner, afraid for $s life. That person is AWOL at the moment. You are afraid of your own shadow! $n cowers in the corner afraid of $s own shadow noogie 5 0 You can't noogie the AIR! It has no head. $ You grab $N, get $M in a head lock and NOOGIE $M! $n grabs $N in a head lock and NOOGIES $M... ARGH!!! Oh NO, $n grabs you, throws you in a head lock and NOOGIES you! That person has gone off to other lands... You rub your head and create a static charge... $n rubs $s OWN head and creates a static charge... *ZAP* yeehaw 5 0 You mount your pony(?) and shout YEEEEEEEHAAAAAAAW! $n bounces up and down screaming *YEEEEEEHAAAAAAW!* # pissed 5 0 You are PISSED! $n is PISSED so watch out! You turn a stoney gaze toward $N... you are SOOO pissed at $N! $n glares at $n.... $n is SOOO PISSED at $m! $n is pissed at you now... What do you think $e'll DO? That person is not here... You are PISSED at yourself! $n is so pissed at $mself. How could $e be so stupid??? passout 5 0 You belch and pass out. $n is OBVIOUSLY intoxicated... $e burps loudly and passes out! # adjust 5 0 You look around, make sure nobody is watching, and you adjust your "Tool." $n looks around slyly, smiles, then reaches down and "adjusts" $mself... # scratch 5 0 You scratch yourself contentedly. $n reaches down and scratches $mself... Now $e looks VERY happy. # meditate 0 0 You assume a very comfortable position and begin to meditate. $n rests and begins to meditate... $e chants softly to $mself. # bkiss 0 0 You blow kisses to the air. $n blows kisses at no one in particular. You blow a kiss at $N and wonder if $E will catch it. $n blows a kiss at $N ... isn't $e so CUTE? $n blows a kiss at you and hopes you'll blow one back at $m. You kiss falls to the ground with no one to go to. You blow a kiss to yourself... isn't the world beautiful? $n blows a kiss to $mself, obviously very in love. beer 0 0 You pull out a six-pack. $n starts to juggle a six-pack of beer. You toss a bottle of beer at $N. $n tosses a bottle of beer at $N ... let's just hope $e'll catch it! $n tossed you a bottle of beer... I think $e wants something... The bottle crashes to the floor and shatters. You pop off the top and down a beer. $n pops the top off a bottle of beer and downs it in one gulp. bcatch 0 0 You reach out and rescue the bottle from its flight. $n reaches out and grabs the bottle of beer tossed to $m. # claw 0 0 You tighten your hands into a fist. $n clenches $s fists until blood drips from them... You claw $S eyes out... GROSS! $n buries $s nails in $N's eyes ... OH GOD, THE BLOOD! $n buries $s nails in your eyes and you are blinded by your own blood! They aren't here to claw. You claw yourself to shreds! $n rips $mself to shreds with $s fingernails! rose 0 0 Who would you like to give it to? $ You give $M a pretty rose. $n hands $N a beautiful rose. $n hands you a beautiful ---'---,--{@ They seem to have left. You give yourself a rose and feel a little sad... $n gives $mself a rose, dont you feel sorry for $m? laces Whose laces? $ With the greatest of stealth, you tie $S shoelaces together. $n sneaks up to $N and ties $S shoelaces together. You try to take a step, and you hit the world facedown! Someone must have tied your shoelaces together! Whose laces? You tie your own shoelaces together, try to walk, and promptly fall. $n cleverly ties $s own shoelaces together, tries to walk, and sprawls flat on the floor. tag Tag whom? $n casts about for someone to tag. >From nowhere, you pounce on $N and TAG $M remorselessly! BWAHAHA!!! $n dives from the shadows and TAGS $N. $N IS IT! $n pounces on you and >>> TAGS <<< you! You're IT! Who were you going to tag, then? Unable to catch anyone else, you do the intelligent thing and tag yourself. You're still IT! Unable to catch anyone else, $n tags $mself. Are you impressed? tank You boldly offer to tank for your everyone else. Are you sure you know what you're getting into? $n offers to tank! You offer to tank for $N. $n offers to tank for $N. $n offers to tank for you! Tank for whom? No one will tank for you, eh?!? WELL, YOU'LL SHOW THEM! (right?) In dazzling chivalry, $n offers to tank-- for $mself! starve You show your prominent ribs and hope that someone will take pity. $n is withering before your eyes! Starvation! You throw yourself upon $S mercy, begging for food. $n begs $N for food. One would think that magic would have cured hunger by now... $n is starving before your eyes! Could you spare some food, please? Sorry, but that person isn't around-- looks like you'll starve. # aargh AAAAAARRRRRRGGGGGGHHHHHH!!!!!! $n throws back $s head and howls in profound frustration! You scream your frustration and grab for $S throat with both hands! $n howls in frustration, and leaps for $N, trying to throttle $M! $n grabs for your throat with two hands, howling in frustration! You get even MORE frustrated when you can't find anyone to throttle! You scream in frustration at your own stupidity! $n screams in frustration at $s own stupidity! homework Your suddenly remember that you have to defend your thesis today... $n looks stricken. Could $e have blown off some important homework? # puff You mimic Puff at her most annoying. $n says, "Did you know that I'm written in C?" # yae You sigh, burdened with Yet Another Eeediot. $n sighs, burdened with Yet Another Eeediot. There's Yet Another Eeediot in the room, and you're looking right at $M. $n clearly believes that $N is an Eeediot! $n glares at you, obviously not impressed with your intelligence. There are plenty of Eeediots, but that one doesn't seem to be present. You bonk yourself for the Eeediot you are! $n bonks $mself, HARD, and curses $mself for the Eeediot $e is! lightbulb *Ding!* Inspiration! A light bulb appears above $n's head! # voodoo Bad juju like this has to be directed at a person. $n looks hostile for a moment. You stare daggers at $N, jabbing pins into $S effigy. $n glares balefully at $N while stabbing a pin into a voodoo doll. Your heart lurches in your chest, and fiery pain stabs through your skull! Your hatred finds no such target. You stab a pin into your own voodoo doll! Agony! $n jabs a pin into $s own voodoo doll, and twitches in agony! ogg Ogg who? $ Engage! $n oggs $N's head with photon torpedos! $N reels. $n oggs your head with photon torpedos! You are reeling. You can't find your target. If you do that, the universe will explode. $n almost oggs $mself, but wisely reconsiders. confused Your confusion is showing. $n blinks slowly... You blink slowly, trying to decipher $S comment. $n blinks slowly. Maybe $N left a word out of $S sentence... $n blinks slowly. Maybe you left a word out of your sentence? No wonder you're confused. # beam You beam delightedly at nothing in particular. $n beams broadly at nothing in particular. You dazzle $N with your smile. $n must like $N a great deal to beam at $M so broadly! $n must like you a great deal to beam at you so broadly! You look pretty silly beaming at imaginary friends... Well, aren't you special? $n beams at $mself, obviously pleased. bite You glare around, muttering "Bite me..." under your breath. $n glares around, muttering "Bite me..." under $s breath. You bite $N on the neck. $n bites $N on the neck! $n bites you on the neck. Hungry? No such luck. You bite your knuckle in anguish. $n bites $s knuckle in anguish...the tragedy! discodance Groovy! $n discos wildly! You grab $N and disco wildly! Groovy! $n grabs $N and does $m best Travolta! $n grabs you and does $m best Travolta! It's okay, you can disco solo too. # scuff You scuff your foot sheepishly. $n scuffs $s foot in the dirt, looking very sheepish. You scuff your foot, avoiding $N's gaze. $n scuffs $s foot and shyly avoids $N's gaze. $n scuffs $s foot and shyly avoids your gaze. They aren't here. # whap Whap who? $ You whap $N upside the head! With a resounding WHAP!, $n reprimands $N. HEY! $n whaps you upside the head! Whiff... Ow! You give yourself a resounding whap upside the head. Biff! $n whaps $mself upside the head! lag Yes, yes. $n is m o v i n g v e ry sl o w l y ... # chortle Heh. $n chortles mischievously. You chortle mischievously at $N. $n chortles mischievously at $N. $n chortles mischievously at you. Took you a while to get that....they aren't here. You chortle at your own joke. $n chortles at $s own joke. Don't bother. zerbert Gotta zerbert SOMEBODY. $ You lift $N's shirt and blow loudly into $S navel! $n lifts $N's shirt and blows loudly into $S navel! Yeek! $n lifts your shirt and blows loudly into your navel! You missed. Careful, people are staring... $n looks around furtively, and then bends over and blows loudly into $s own navel! twitch 0 0 You twitch nervously. $n twitches nervously. You twitch involuntarily at $N's presence. $N must really be getting to $n... $n notices you and twitches. Nervous? They aren't even here. # leer 0 0 You peer around the room, leering like the pervert you are! $n peers about, leering like a filthy pervert! You leer at $N like the pervert you are. $n eyes $N up and down, leering like a filthy pervert! $n eyes you up and down, leering like a filthy pervert! You'll have to settle for memories -- that person isn't here. Desperation has reached new heights, hasn't it? $n leers at $mself shamelessly. polite 0 0 You give a polite little chuckle. $n gives a polite little chuckle. You indicate your underappreciation of $S joke. $n gives a polite little chuckle to $N's joke. $n gives a politle but unappreciative chuckle to your joke. You can't find a friend to chuckle with. You chuckle at your own joke, since no one else would. $n chuckles at $s own joke, since none of you would. mischievous 0 0 You give a mischievous smile at the trouble you have in mind. $n grins mischievously at a nasty idea. You grin mischievously at $M, thinking an evil thought. $n grins mischievously at $N. $m must be thinking something evil. $n grins mischievously at you. You inch toward the door. You must be delirious. You grin mischievously to yourself. $n grins mischievously to $mself. accept 0 0 You accept the proferred apology graciously. $n graciously accepts the proferred apology. # anticipate 0 0 You murmur 'Sssssoonnn, my presssssciousssss...' $n murmurs 'Ssssssooonnnn, my pressssscioussss...' # shudder 0 0 You shudder at the horror and repress tears. $n shudders at the horror and represses tears. # powertrip 0 0 You scream 'The PPppppPOOOOoooWWWwwwErrRRR!' and writhe. $n writhes, screaming 'The PPppppPOOOOoooWWWwwwErrRRR!' # mull 0 0 You mull over the idea at hand, asking for patience. $n mulls over the idea at hand. Please be patient. # wait 0 0 You wait patiently. $n waits patiently. # bat 0 0 You bat your long, dark lashes and smile innocently. $n bats $s long, dark lashes and smiles innocently. # sage 0 0 You nod sagely. $n nods sagely. # contemplate 0 0 You bite your lip contemplatively. $n bites $s lip contemplatively. # agree 0 0 You agree absolutely. $n agrees absolutely. You nod in enthusiastic agreement with $N. $n nods in enthusiastic agreement with $N. $n nods in enthusiastic agreement with you. Sorry, your target is absent. You find yourself most agreeable. $n finds $mself the most agreeable being alive. toast 0 0 You raise a glass of champagne in a toast. $n raises $s glass of champagne in a toast. You raise your glass of champagne to $S. $n silently toasts $N. $n silently toasts you. Your object of praise is absent. You grin evilly and toast yourself. $n grins evilly and toasts $mself. conspire 0 0 You wink conspiratorily, waiting for the countersign. $n winks conspiratorily, waiting for the countersign. You induct $S into your private conspiracy with a wink. $n winks conspiratorily at $N. You wonder what this can mean. $n inducts you into $m private conspiracy with a wink. Even you conspire against yourself. $n is paranoid enough to distrust even $mself. # support 0 0 You fully support the plan. $n fully supports the plan. You hug $M supportively and smile. $n hugs $N supportively and smiles. $n hugs you supportively and smiles. Sorry, friend, I can't see that person here. You hug yourself sadly. $n hugs $mself sadly. Perhaps you could help? pound 0 0 You make vague pounding motions with your fist at the thought. $n makes vague pounding motions with $m fist at the thought. You pound $M into a bloody mass. $n pounds $N into a bloody mass. $n pounds you into a bloody mass. Sorry, friend, I can't see that person here. # wrist 0 0 You hold out out a wrist for a slap. $n holds out a wrist for a slap. You slaps $M wrist sharply. $n slaps $N's wrist sharply. $n slaps your wrist sharply. Sorry, friend, I can't see that person here. You slap your own wrist. $n slaps $m own wrist. romeo 0 0 You light up a Romeo y Julietta cigar and puff contentedly. $n lights up a Romeo y Julietta cigar and puffs contentedly. # camel 0 0 You pretend you are a camel. $n pretends to be a camel. You light a Camel cigarette for $M. $n lights a Camel cigarette for $N. $n lights a Camel cigarette for you. You don't see that personhere. You light a Camel cigarette and inhale sharply. $n lights a Camel cigarette and inhales sharply. whip 0 0 You crack your bullwhip menacingly. $n cracks a bullwhip menacingly. You flick your whip across $M bare back. $n flicks $s whip across $N's bare back. $n flicks a whip across your back... the pain.. the pleasure.. Sorry, friend, I can't see that person here. You whip yourself into a frenzy. $n whips $mself into a frenzy. cramp 0 0 You gasp and clutch your abdomen, wheezing with the pain. $n gasps and clutches $m abdomen in agony. You hammerlock $M, screaming, "AAAAARRRRRGH!! I HAVE A CRAMP!!!" $n hammerlocks $N, screaming, "AAAAARRRRRGH!! I HAVE A CRAMP!!!". $n hammerlocks you, screaming "AAAAARRRRRGH!! I HAVE A CRAMP!!!" Suffering as you are, you didn't see that person slip out. # make 0 0 You breathe heavily and wetly. $n breathes heavily and wetly. You steam up the windows with $M. $n and $N start steaming up the windows. $n starts steaming up the windows with you. Sorry, friend, I can't see that person here. # sweep 0 0 You look at your empty arms and sigh. $n looks at $s empty arms and sighs. You sweep $M into your arms and kiss $M long and deeply. $n sweeps $N into $s arms and kisses $M long and deeply. $n sweeps you into $s arms and kisses you long and deeply. The object of your kiss is absent. # buff 0 0 You buff your nails on your cloak. $n buffs $s nails on $s cloak. # liver 0 0 You look angrily for someone to disembowel. $n angrily for someone to disembowel. You rip out $S liver and eat it. $n rips out $N's liver and eats it. $n rips out your liver and eats it. The object of your wrath is absent. # wrestle 0 0 $ $ You wrestle $M to the floor and pin $M there. $n wrestles $N to the floor, pinning $M there. $n wrestles you to the floor and pins you. Sorry, friend, I can't see that person here. You wrestle with your conscience. $n wrestles with $m conscience. tie 0 0 You toy with a pair of handcuffs suggestively. $n toys suggestively with a pair of handcuffs. You grab $N and tie $M to the bedposts. $n grabs $N and ties $S to a four poster bed. $n grabs you and ties you securely to a four poster bed. Sorry, friend, I can't see that person here. # tight 0 0 $ $ You hold $M tightly in your arms. $n holds $N tightly in $m arms. $n holds you in $m arms. Sorry, friend, I can't see that person here. # fatality 0 0 $ $ You intone, '$N wins. Fatality.' $n intones, '$N wins. Fatality.' $n intones, '$N wins. Fatality.' # yowl 0 0 You yowl in frustration. $n yowls in frustration! # silly 0 0 You do the silly walk all around the room. $n does the silly walk all around the room. $e *is* silly. # #0 #$ tkabber-plugins/socials/socials.ru000064400000000000000000002766161500237002100171750ustar00nobodynobody#SOCIALS kiss целовать поцелуй Кого ты хочешь целовать ? $ Ты целуешь $N4. $n целует $N4. $n целует тебÑ. Hикого желаемого вокpуг. Как вÑе люди одиноки :( # bounce 0 0 BOIINNNNNNGG! $n Ñкачет вокруг, ÑчаÑтливо улыбаÑÑÑŒ. Ты прыгаешь к $E3 на колени. $n прыгает к $N3 на колени. $n прыгает к тебе на колени. Ты не видишь Ñ Ñ‡ÐµÐ¼ поиграть. Ты Ñрываешь Ñвою голову и начинаешь играть в баÑкетбол. $n играет в баÑкетбол Ñвоей головой. smile улыбатьÑÑ ÑƒÐ»Ñ‹Ð±Ð½ÑƒÑ‚ÑŒÑÑ 1 0 Ты ÑчаÑтливо улыбаешьÑÑ. $n ÑчаÑтливо улыбаетÑÑ. Ты улыбаешьÑÑ $N3. $n улыбаетÑÑ $N3. $n улыбаетÑÑ Ñ‚ÐµÐ±Ðµ. Ðикого Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем тут нет... Ты улыбаешьÑÑ Ñебе. $n улыбаетÑÑ Ñебе. dance танцевать танец 1 8 ЧувÑтвуешь ÑÐµÐ±Ñ Ð³Ð»ÑƒÐ¿Ð¾Ð²Ð°Ñ‚Ð¾, не правда ли ? $n плÑшет дикий танец! Ты ведешь $E2 танцевать. $n танцует Ñ $N5. $n танцует Ñ Ñ‚Ð¾Ð±Ð¾Ð¹. Эй, Ñ ÐºÐµÐ¼? Ты подпрыгиваешь и танцуешь Ñ Ñобой. $n подпрыгивает и пытаетÑÑ Ñ‚Ð°Ð½Ñ†ÐµÐ²Ð°Ñ‚ÑŒ Ñ Ñобой. tango танго 0 8 Ðеловко танцевать танго без партнера, правда ? $n зажимает розу меж зубов...но партнера Ð´Ð»Ñ Ñ‚Ð°Ð½Ð³Ð¾ не наблюдаетÑÑ. Ты берешь розу в зубы и Ñоблазнительно танцуешь танго Ñ $E5. $n берет розу в зубы и очень ÑекÑуально танцует танго Ñ $N5. $n берет розу в зубы и очень Ñротично танцует танго Ñ Ñ‚Ð¾Ð±Ð¾Ð¹. Таких тут нет. Лучше поÑиди Ñпокойно. ЧувÑтвуешь ÑÐµÐ±Ñ Ð³Ð»ÑƒÐ¿Ð¾, не правда ли ? $n берет розу в зубы и пытаетÑÑ Ñ‚Ð°Ð½Ñ†ÐµÐ²Ð°Ñ‚ÑŒ танго Ñ Ñобой. cackle гоготать 0 0 Ты гогочешь Ñ Ð»Ð¸ÐºÐ¾Ð²Ð°Ð½Ð¸ÐµÐ¼. $n запрокидывает голову и гогочет во вÑе горло! Ты гогочешь над $E5. $n гогочет над $N5. $n гогочет над тобой. Лучше держиÑÑŒ подальше от $E2. Ты не можешь найти, Ñ ÐºÐµÐ¼ погоготать. Ты гогочешь Ñам Ñебе. У Ñ‚ÐµÐ±Ñ Ñ‡Ñ‚Ð¾-то Ñ Ð³Ð¾Ð»Ð¾Ð²Ð¾Ð¹. $n немного того ÑегоднÑ. $e гогочет Ñебе. laugh ÑмеÑтьÑÑ Ñмех 0 0 Ты падаешь на землю от Ñмеха. $n падает на землю от Ñмеха. Ты немилоÑердно хохочешь над $N5. $n немилоÑердно хохочет над $N5. $n немилоÑердно хохочет над тобой. Хмммммм. Ты никого не находишь поÑмешищем Ð´Ð»Ñ Ñвоей шутки. Ты ÑмеешьÑÑ Ð½Ð°Ð´ Ñобой. И Ñ Ñ‚Ð¾Ð¶Ðµ. $n ÑмеетÑÑ Ð½Ð°Ð´ Ñобой. Давай поÑмеемÑÑ Ð²Ð¼ÐµÑте! giggle хихикать хихинанье 0 0 Ты хихикаешь. $n хихикает. Ты хихикаешь над дейÑтвиÑми $N2. $n хихикает над дейÑтвиÑми $N2. $n хихикает над тобой. ÐадеюÑÑŒ, Ñто не заразно. Ты хихикаешь Ñебе под ноÑ, потому что больше не над кем. Ты хихикаешь над Ñобой, который хихикает Ñам Ñебе, который... $n хихикает над Ñобой. $e должно быть немного не в Ñебе. shake трÑÑти пожать 0 5 Ты трÑÑешь головой. $n трÑÑет головой. Ты пожимаешь $E2 руку. $n пожимает руку $N2. $n пожимает твою руку. Извини, друг, но такой личноÑти тут нет. Ты трÑÑешь руку Ñам Ñебе. $n трÑÑетÑÑ Ð¸ дрожит как желе. puke блевать 0 0 Ты блюешь...везде блевотина !!! И-и-К ! $n блюет. Ты блюешь на $E2. $n блюет на $N2. $n2 рвет и $e блюет прÑмо тебе на одежду! Еще раз? Ты блюешь на ÑебÑ. $n блюет на Ñвою одежду. growl рычать рык 0 0 РРррррррр... $n рычит. Ррррррр....так что, $N!!! $n рычит на $N2. Лучше покинуть Ñто меÑто до драки. $n рычит на тебÑ. Это наезд! Ðикто Ñ‚ÐµÐ±Ñ Ð½Ðµ Ñлышит твой рык. Ты рычишь на ÑебÑ. Эй, тебе надо раÑÑлабитьÑÑ. $n рычит на ÑебÑ. Это интереÑно... scream кричать крик 0 0 Ð-Ð-Ð-Ð-а-а!!!!! $n громко кричит! Ð-Ð-Ð-Ð-а-а-а!!!!! Да - Ñто ДОЛЖÐО повредить $E3!!! $n громко орет на $N4. Лучше удалитьÑÑ, пока $n не обвинÑет тебÑ!!! $n громко орет на тебÑ! Это ÑовÑем нехорошо, *ФУ* Твои легкие не докричатÑÑ Ñ‚Ð°Ðº далеко! Ты орешь на ÑебÑ. Да, Ñто один из методов ÑброÑить ÑтреÑÑ. $n громко орет на ÑебÑ! Разве ÑÐµÐ³Ð¾Ð´Ð½Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð»ÑƒÐ½Ð¸Ðµ? comfort утешать утешение 0 5 Тебе неуютно? $ Ты утешаешь $E4. $n утешает $N4. $n утешает тебÑ. Утешить кого? Ты делаешь попытку утешить ÑебÑ. $n утешает ÑебÑ. sigh вздыхать вздох 0 0 Ты вздыхаешь. $n вздыхает. Ты вздыхаешь, когда думаешь о $E6. $n вздыхает по $N6. $n вздыхает, когда думает о тебе. Трогательно, да? Ты дейÑтвительно вздыхаешь, когда не видишь друга. Ты Ñ‚Ñжело вздыхаешь. Ты очень одинок. $n вздыхает Ñебе. Очень Ñ‚Ñжелый вздох. sulk 1 0 Ты не в духе. $n выглÑдит очень угрюмо. # hug обнÑть обьÑÑ‚Ð¸Ñ 1 5 ОбнÑть кого? $ Ты обнимаешь $E4. $n обнимает $N4. $n обнимает тебÑ. Извини, друг, таких тут нет. Ты обнимаешь ÑÐµÐ±Ñ Ð·Ð° плечи. $n обнимает ÑÐµÐ±Ñ Ð² тщетной надежде найти поддержку. snuggle прижатьÑÑ 1 5 Чего? $ Ты прижимаешьÑÑ Ðº $E3. $n лаÑково прижимаетÑÑ Ðº $N3. $n лаÑково прижимаетÑÑ Ðº тебе. Таких тут нет. Ты ÑворачиваешьÑÑ ÐºÐ»ÑƒÐ±Ð¾Ñ‡ÐºÐ¾Ð¼, готовÑÑÑŒ ко Ñну. $n ÑворачиваетÑÑ, готовÑÑÑŒ ко Ñну. cuddle прижать 1 5 Кого мы прижмем к Ñебе ÑегоднÑ? $ Ты прижимаешь $E4 к Ñебе. $n прижимает $N4 к Ñебе. $n прижимает Ñ‚ÐµÐ±Ñ Ðº Ñебе. Таких тут нет. Ты наверное внутри как выжатый лимон :) $n прижимает к Ñебе Ñвою тень. Что за жалкое зрелище. nuzzle ÑˆÐµÑ 1 5 Кого? $ Ты нежно лаÑкаешь $E2 шею. $n нежно лаÑкает шею $N2. $n нежно лаÑкает твою шею. Ðет... таких тут нет... Извини, друг, но Ñто невозможно. # cry плакать плач 0 5 Ва-а-а..Ва-а-а.. $n заливаетÑÑ Ñлезами. Ты плачешь на $E2 плече. $n плачет на плече $N2. $n плачет на твоем плече. Где ? Ты плачешь по Ñебе. $n тихо рыдает по Ñебе. poke тыкать тычок 0 0 Ткнуть кого?? $ Ты тычешь $E4 под ребро. $n тычет $N4 под ребро. $n тычет Ñ‚ÐµÐ±Ñ Ð¿Ð¾Ð´ ребро. Ты не можешь ткнуть того, кого здеÑÑŒ нет. Ты тычешь ÑÐµÐ±Ñ Ð¿Ð¾Ð´ ребра, чувÑÑ‚Ð²ÑƒÑ ÑÐµÐ±Ñ Ð¾Ñ‡ÐµÐ½ÑŒ глупо. $n тычет ÑÐµÐ±Ñ Ð¿Ð¾Ð´ ребра и выглÑдит глуповато. accuse обвинÑть обвинение 0 5 ОбвинÑть кого?? $n в Ñуровом наÑтроении. Ты обвинÑюще Ñмотришь на $E4. $n обвинÑюще Ñмотрит на $N4. $n обвинÑюще Ñмотрит на тебÑ. ОбвинÑть кого-то, кого тут нет? Ты обвинÑешь ÑебÑ. $n не в ладах Ñо Ñвоей ÑовеÑтью. grin уÑмехатьÑÑ ÑƒÑмешка 0 0 Ты недобро уÑмехаешьÑÑ. $n зло уÑмехаетÑÑ. Ты недобро уÑмехаешьÑÑ $N3. $n зло уÑмехаетÑÑ $N3. $n зло уÑмехаетÑÑ Ñ‚ÐµÐ±Ðµ. Хммм. Лучше держиÑÑŒ подальше. Ты должно быть, вне ÑебÑ. Ты зло уÑмехаешьÑÑ Ñебе. Должно быть, мыÑли у Ñ‚ÐµÐ±Ñ Ð¾Ñ‡ÐµÐ½ÑŒ плохие. $n зло уÑмехаетÑÑ Ñебе. Ты удивлÑешьÑÑ, что Ñ $e раÑÑудком. bow кланÑтьÑÑ Ð¿Ð¾ÐºÐ»Ð¾Ð½ 0 5 Ты глубоко кланÑешьÑÑ. $n глубоко кланÑетÑÑ.. Ты кланÑешьÑÑ $E3. $n кланÑетÑÑ $N3. $n кланÑетÑÑ Ñ‚ÐµÐ±Ðµ. Кому? Ты целуешь ноÑки Ñвоих ботинок. $n ÑкладываетÑÑ Ð½Ð°Ð¿Ð¾Ð´Ð¾Ð±Ð¸Ðµ Ñкладного ножа и целует ноÑки Ñвоих ботинок. applaud аплодировать аплодиÑменты 0 0 Хлоп, хлоп, хлоп. $n хлопает в ладоши. Ты аплодируешь $E3. $n аплодирует $N3. $n аплодирует тебе. Тебе ДОЛЖÐО быть хорошо! Ты аплодируешь Ñвоему воображаемогму другу. Ты аплодируешь Ñебе. Да, мы вÑе тщеÑлавны! $n аплодирует Ñебе. Да, мы вÑе тщеÑлавны! blush краÑнеть краÑка 0 0 Твои щеки горÑÑ‚. $n краÑнеет. Ты краÑнеешь и волнуешьÑÑ Ð¿ÐµÑ€ÐµÐ´ $E5. $n краÑнеет, глÑÐ´Ñ Ð½Ð° $N4. $n краÑнеет, глÑÐ´Ñ Ð½Ð° тебÑ. Как ты дейÑтвуешь на людей! Ты краÑнеешь, как вÑпомнишь, что Ñтой личноÑти тут нет. Ты краÑнеешь за Ñвою глупоÑть. $n краÑнеет за Ñвою глупоÑть. burp рыгнуть 0 0 Ты громко отрыгиваешь. $n громко отрыгивает. Ты громко отрыгиваешь в ответ на $E обращение. $n громко отрыгивает в ответ на обращение $N2. $n громко отрыгивает в ответ на твое обращение. Ты не можешь найти Ñвою жертву. Ты отрыгиваешь на ÑебÑ. $n отрыгивает на ÑебÑ. ÐеприÑтное зрелище. chuckle поÑмеиватьÑÑ Ñмешок 0 0 Ты вежливо поÑмеиваешьÑÑ. $n вежливо поÑмеиваетÑÑ. Ты поÑмеиваешьÑÑ Ð½Ð°Ð´ $E2 шуткой. $n поÑмеиваетÑÑ Ð½Ð°Ð´ шуткой $N2. $n поÑмеиваетÑÑ Ð½Ð°Ð´ твоей шуткой. Ты не находишь дpуга, Ñ ÐºÐµÐ¼ бы поÑмеÑлÑÑ. Ты поÑмеиваешьÑÑ Ð½Ð°Ð´ Ñвоей шуткой, пока никого нет. $n поÑмеиваетÑÑ Ð½Ð°Ð´ Ñвоей шуткой. clap хлопать хлопок 0 0 Ты хлопаешь в ладоши. $n показывает Ñвое одобpение, Ñ…Ð»Ð¾Ð¿Ð°Ñ Ð² ладоши. Ты хлопаешь в ладоши за $E2 выÑтупление. $n хлопает в ладоши за выÑтупление $N2. $n хлопает в ладоши за твое выÑтупление. Ты хлопаешь в пуÑтоту. Ты хлопаешь Ñебе за Ñвое выÑтупление. $n хлопает Ñебе за Ñвое выÑтупление. cough 0 0 Эк, пытайÑÑ Ð¿pикpывать pот! $n гpомко кашлÑет. # curtsey Ñ€ÐµÐ²ÐµÑ€Ð°Ð½Ñ 0 0 Ты приÑедаешь в реверанÑе перед Ñвоими ÑлушателÑми. $n делает гpациозный реверанÑ. Ты приÑедаешь в глубоком реверанÑе перед $E5. $n приÑедает в реверанÑе перед $N5. $n приÑедает в реверанÑе перед тобой. Ты делаешь Ñ€ÐµÐ²ÐµÑ€Ð°Ð½Ñ Ð² пуÑтоту. Ты делаешь Ñебе реверанÑ. $n делает Ñебе реверанÑ, поÑкольку никто не обpащает на $e4 вниманиÑ. fart пукнуть пукать 0 0 Где твои манеры ? $n издает оглушительный пук... и $e4 окружает зеленоватое облако ! Ты пукаешь на $N4. Эй, да тебе нездоровитÑÑ ! $n пукает в направлении $N2. Тебе пора бежать, пока $e не повернетÑÑ Ðº тебе ! $n пукает в твоем направлении. Ты задыхаешьÑÑ. Ты не можешь ÑдерживатьÑÑ Ñ‚Ð°Ðº долго! Ты пукаешь Ñебе под ноÑ! $n пукает Ñебе под ноÑ. Да, лучше $e3, чем тебе. flip кувыркатьÑÑ ÐºÑƒÐ²Ñ‹Ñ€Ð¾Ðº 0 0 Ты делаешь кувырок. $n делает кувырок. Ты перебраÑываешь $E4 через Ñвое плечо. $n перебраÑывает $N4 через Ñвое плечо. $n перебраÑывает Ñ‚ÐµÐ±Ñ Ñ‡ÐµÑ€ÐµÐ· плечо. Хммм. Ты не можешь найти Ñтого человека. Ты кувыркаешьÑÑ Ñ‡ÐµÑ€ÐµÐ· голову. $n делает неÑколько прыжков и кувырков. fondle прилаÑкать лаÑкать 0 5 Кого нужно прилаÑкать? $ Ты нежно лаÑкаешь $E4. $n нежно лаÑкает $N4. $n нежно лаÑкает тебÑ. Ты пытаешьÑÑ Ð¿Ñ€Ð¸Ð»Ð°Ñкать того, кого здеÑÑŒ нет. Ты нежно лаÑкаешь ÑебÑ, прекраÑные ощущениÑ, правда? $n лаÑкает ÑÐµÐ±Ñ - Ñто уже заходит Ñлишком далеко! frown хмуритьÑÑ 0 0 Ты неодобрительно хмуришьÑÑ. $n хмуритÑÑ. Ты хмуришьÑÑ Ð½Ð° $E4. $n хмуритÑÑ Ð½Ð° $N4. $n хмуритÑÑ Ð½Ð° тебÑ. Тебе не на кого хмуритьÑÑ. Ты хмуришьÑÑ Ð½Ð° ÑебÑ. Бедный ребенок... $n хмуритÑÑ Ð½Ð° ÑебÑ. Бедный ребенок... gasp задыхатьÑÑ 0 0 Ты задыхаешьÑÑ Ð¾Ñ‚ изумлениÑ. $n задыхаетÑÑ Ð¾Ñ‚ изумлениÑ. Ты задыхаешьÑÑ, когда видишь, что $E делает. $n задыхаетÑÑ, когда $e видит, что делает $N. $n задыхаетÑÑ, когда $e видит, что ты делаешь. You need to panic. Ты Ñмотришь на ÑÐµÐ±Ñ Ð¸ задыхаешьÑÑ Ð¾Ñ‚ изумлениÑ! $n Ñмотрит на ÑÐµÐ±Ñ Ð¸ задыхаетÑÑ Ð¾Ñ‚ изумлениÑ! glare приÑтально 0 5 Ты приÑтально Ñмотришь в проÑÑ‚pанÑтво. $n приÑтально Ñмотрит вокруг ÑебÑ. Ты приÑтально Ñмотришь на $E4. $n приÑтально Ñмотрит на $N4. $n приÑтально Ñмотрит на Ñ‚ÐµÐ±Ñ Ð»ÐµÐ´Ñным взглÑдом, ты чувÑтвуешь холод в Ñвоих коÑÑ‚ÑÑ…. Ты пытаешьÑÑ Ð¿Ñ€Ð¸Ñтально Ñмотреть на кого-то, кого здеÑÑŒ нет. Ты приÑтально Ñмотришь на Ñвои Ñтупни. $n приÑтально Ñмотрит на Ñвои Ñтупни. Что Ñто Ñ $e5 ? groan охать 0 0 Ты громко охаешь. $n громко охает. Ты охаешь, глÑÐ´Ñ Ð½Ð° $E4. $n охает, глÑÐ´Ñ Ð½Ð° $N4. $n охает, глÑÐ´Ñ Ð½Ð° тебÑ. Тебе незачем охать. Ты охаешь, глÑÐ´Ñ Ð½Ð° Ñвои дейÑтвиÑ. $n охает, глÑдÑ, что $e делает. grope ощупать 0 5 Кого ты хочешь ощупать? $ Ðу, что ты обнаруживаешь? $n ощупывает $N4. $n ощупывает тебÑ. ПопытайÑÑ Ñ‚Ð¾Ð³Ð¾, кто тут еÑть. Ты щупаешь ÑÐµÐ±Ñ - ОЙ. $n ощупывает ÑÐµÐ±Ñ - ОЙ. hiccup икать 0 0 *ИК* $n икает. # lick облизнутьÑÑ 0 0 Ты облизываешьÑÑ Ð¸ улыбаешьÑÑ. $n облизываетÑÑ Ð¸ улыбаетÑÑ. Ты нежно облизываешь $S щечку. $n нежно облизывает щечку $N. $n нежно облизывает твою щечку. Ðикого такого нет тут. Ты облизываешь Ñвою бровь. $n облизывает Ñвою бровь. love любить любовь 0 0 Ты любишь веÑÑŒ мир. $n любит каждого в Ñтом мире. Ты выÑказываешь $E3 Ñвои иÑтинные чувÑтва. $n нежно шепчет $N3. $n шепчет тебе нежные Ñлова любви. Ð’Ñе, твоей любви тут нет. Ðу, мы уже знаем, что ты очень любишь ÑебÑ. $n любит ÑебÑ, ты веришь? moan Ñтонать 0 0 Ты начинаешь Ñтонать. $n начинает Ñтонать. Ты Ñтонешь $E3 о Ñвоих потерÑÑ…. $n Ñтонет $N3 о Ñвоих потерÑÑ…. $n Ñтонет, глÑÐ´Ñ Ð½Ð° тебÑ. Хмммм. Ðекому Ñтонать. Ты Ñтонешь Ñебе. $n Ñтонет Ñебе. nibble куÑать ÑƒÐºÑƒÑ 0 0 Кого куÑнуть? $ Ты нежно покуÑываешь ухо $N2. $n нежно покуÑывает ухо $N2. $n нежно покуÑывает твое ухо. Извини, тут нет таких. Ты хочешь укуÑить ÑÐµÐ±Ñ Ð·Ð° ухо??????????????????? $n пытаетÑÑ ÑƒÐºÑƒÑить ÑÐµÐ±Ñ Ð·Ð° ухо (ИнтереÑно, как $e Ñто Ñделает?!!). pout надуть 0 0 ÐÑ…, не бери Ñто близко к Ñердцу. $n надувает губы. # ruffle взьерошить ерошить 0 0 Тебе нужно КОГО-ТО взьерошить. $ Ты игриво ерошишь $E2 волоÑÑ‹. $n игриво ерошит волоÑÑ‹ $N2. $n игриво ерошит твои волоÑÑ‹. Это трудно. Ты ерошишь Ñвои волоÑÑ‹, думаÑ, как долго ты Ñможешь Ñто делать, пока оÑтальные не подумали, что ты немного того. $n ерошит Ñвои волоÑÑ‹ - выглÑдит как клоун! shiver дрожать 0 0 Брррррррр. $n неуютно дрожит. Ты дрожишь при мыÑли о Ñхватке Ñ $E5. $n дрожит при мыÑли о Ñхватке Ñ $N5. $n дрожит от ÑамоубийÑтвенных мыÑлей дратьÑÑ Ñ Ñ‚Ð¾Ð±Ð¾Ð¹. Тебе незачем дрожать. Ты боишьÑÑ ÑебÑ? $n иÑпуганно дрожит. shrug пожимать плечами 0 0 Ты пожимаешь плечами. $n беÑпомощно пожимает плечами. Ты пожимаешь плечами в ответ на $E2 вопроÑ. $n пожимает плечами в ответ на Ð²Ð¾Ð¿Ñ€Ð¾Ñ $N2. $n пожимает плечами в ответ на твой вопроÑ. Ðет таких тут. Ты пожимаешь плечами Ñебе. $n пожимает Ñебе плечами. Что за ÑÑ‚Ñ€Ð°Ð½Ð½Ð°Ñ Ð»Ð¸Ñ‡Ð½Ð¾Ñть. sing петь пеÑÐ½Ñ 0 0 Ты обращаешь Ñвой чиÑтый (?) Ð³Ð¾Ð»Ð¾Ñ Ðº небу. Ты отказала мне два раза! Рмуж пошел за пивом! - $n начинает петь. Ты поешь $E3 балладу. $n поет $N3 балладу. $n поет Ð´Ð»Ñ Ñ‚ÐµÐ±Ñ Ð±Ð°Ð»Ð»Ð°Ð´Ñƒ! Как мило! Тебе некому тут петь. Ты негромко напеваешь Ñебе по ноÑ. $n негромко напевает Ñебе под ноÑ. slap шлепать шлепок 0 0 Рукой по воздуху плохо получаетÑÑ ÑˆÐ»ÐµÐ¿Ð°Ñ‚ÑŒ. $ *Бац!* Ты даешь $E3 звонкую пощечину. *Бац!* $n дает $N3 звонкую пощечину! $n отвешивает тебе пощечину. Как тебе Ñто удаÑÑ‚ÑÑ? Ты шлепаешь ÑебÑ, какой дурак! $n шлепает ÑебÑ, Ñтранно... smirk ухмылÑтьÑÑ ÑƒÑ…Ð¼Ñ‹Ð»ÐºÐ° 0 0 Ты ухмылÑешьÑÑ. $n ухмылÑетÑÑ. Ты ухмылÑешьÑÑ Ð½Ð° $E2 разговоры. $n ухылÑетÑÑ Ð½Ð° речи $N2. $n ухмылÑетÑÑ Ð½Ð° твои разговоры. Кому тебе ухмылÑтьÑÑ? Ты ухмылÑешьÑÑ Ñебе. Ðу-ну..... $n ухмылÑетÑÑ Ñвоей 'мудроÑти'. snap щелкать щелчок 0 0 Эврика! Ты щелкаешь пальцами. $n щелкает пальцами. Ты щелкаешь пальцами, пытаÑÑÑŒ привлечь $E2 внимание. $n щелкает пальцами перед $N5. $n щелкает пальцами перед тобой! Ты должно быть очень хороший агитатор. Ты щелкаешь пальцами перед Ñобой. $n щелкает пальцами перед Ñобой. sneeze чихать 0 0 Ðаапчхи ! $n чихает. # snicker ржать ржание 0 0 Ты тихо ржешь. $n тихо ржет. Ты тихо ржешь и хихикаешь Ñ $E5 о вашем общем Ñекрете. $n тихо ржет и хихикает вмеÑте Ñ $N5 о Ñвоем общем Ñекрете. $n тихо ржет и хихикает Ñ Ñ‚Ð¾Ð±Ð¾Ð¹ о вашем общем Ñекрете. Чего? Ты тихо ржешь Ñебе, Ð¾Ð±Ð´ÑƒÐ¼Ñ‹Ð²Ð°Ñ ÐºÐ¾Ð²Ð°Ñ€Ð½Ñ‹Ðµ планы. $n тихо ржет, Ð¾Ð±Ð´ÑƒÐ¼Ñ‹Ð²Ð°Ñ Ñвои коварные планы. sniff фыркать 0 0 Ты доÑадно фыркаешь. *ФУ* $n доÑадно фыркает. Ты доÑадно фыркаешь в ответ на $E2 обращение. $n доÑадно фыркает в ответ на обращение $N2. $n доÑадно фыркает в ответ на твое обращение. Ðекому фыркать. Ты доÑадно фыркаешь, Ð²Ð¿Ð¾Ð¼Ð¸Ð½Ð°Ñ Ð¾Ð± утраченных возможноÑÑ‚ÑÑ…. $n доÑадно фыркает Ñебе. $e что-то беÑпокоит. snore храпеть 0 0 Хррррррр. Хррррр. Zzzzzzzzzzzzzzzzz. $n громко храпит. # squeeze Ñжать 0 0 Где, как, КОГО ??? $ Ты Ñжимаешь $E4 в обьÑтьÑÑ…. $n Ñжимает $N4 в обьÑтьÑÑ…. $n Ñжимает Ñ‚ÐµÐ±Ñ Ð² обьÑтьÑÑ…. Где, как, КОГО ??? Ты ÑжимаешьÑÑ - попробуй немного раÑÑлабитьÑÑ! $n ÑжимаетÑÑ Ð² комок. stare таращитьÑÑ 0 5 Ты таращищьÑÑ Ð½Ð° небо. $n таращитÑÑ Ð½Ð° небо. Ты мечтательно таращищьÑÑ Ð½Ð° $N4, полноÑтью потерÑвшиÑÑŒ в $E2 глазах.. $n мечтательно таращитÑÑ Ð½Ð° $N4. $n мечтательно таращитÑÑ Ð½Ð° тебÑ, полноÑтью утонув в твоих глазах. Ты таращищьÑÑ Ð¸ таращищьÑÑ, но никого такого здеÑÑŒ нет. Ты мечтательно таращищьÑÑ Ð½Ð° ÑÐµÐ±Ñ - полный нарциÑÑизм. $n мечтательно таращитÑÑ Ð½Ð° ÑÐµÐ±Ñ - ÐÐРЦИССИЗМ! strut гоголем гоголь 0 0 Ты ходишь гоголем. $n важно ходит гоголем. Ты краÑуешьÑÑ Ð¿ÐµÑ€ÐµÐ´ $E5. $n краÑуетÑÑ Ð¿ÐµÑ€ÐµÐ´ $N5, надеÑÑÑŒ привлечь $E2 внимание. $n краÑуетÑÑ Ð¿ÐµÑ€ÐµÐ´ тобой, надеÑÑÑŒ привлечь твое внимание. Тебе не попадаетÑÑ Ð½Ð° глаза Ñта личноÑть. Ты краÑуешьÑÑ Ð¿ÐµÑ€ÐµÐ´ Ñобой. $n краÑуетÑÑ Ð¿ÐµÑ€ÐµÐ´ Ñобой. thank благодарить ÑпаÑибо 0 5 И тебе ÑпаÑибо. $ Ты Ñердечно благодаришь $N4. $n Ñердечно благодарит $N4. $n Ñердечно благодарит тебÑ. Ðикто не откликаетÑÑ Ð½Ð° Ñто имÑ. Кто же Ñ‚ÐµÐ±Ñ Ð¿Ð¾Ñ…Ð²Ð°Ð»Ð¸Ñ‚, еÑли не ты ! $n хвалит ÑебÑ, потому что никто не хочет $e благодарить. twiddle вертеть крутить 0 0 Ты терпеливо вертишь Ñвоими пальцами. $n терпеливо вертит Ñвои пальцы. Ты крутишь $E2 уши. $n крутит уши $N2. $n крутит твои уши. Да нет таких тут. Ты крутишь Ñвои уши наподобие Ñлоника Дамбо. $n крутит Ñвои уши как Ñлоник Дамбо. wave махать 0 0 Ты машешь рукой. $n ÑчаÑтливо машет рукой. Ты машешь $E3 рукой на прощание. $n машет $N3 рукой на прощание. $n машет тебе рукой на прощание. СчаÑтливого пути. Они не ждут твоего прощаниÑ. Ты ÑобираешьÑÑ Ñ€Ð°ÑÑтаватьÑÑ Ñ Ð¶Ð¸Ð·Ð½ÑŒÑŽ?? РприключениÑ?? $n машет Ñебе рукой. whistle ÑвиÑтеть приÑвиÑÑ‚ 0 0 Ты оценивающе приÑвиÑтываешь. $n оценивающе приÑвиÑтывает. Ты приÑвиÑтываешь, Ð²Ð¸Ð´Ñ $E4. $n приÑвиÑтывает, Ð²Ð¸Ð´Ñ $N4. $n приÑвиÑтывает, Ð²Ð¸Ð´Ñ Ñ‚ÐµÐ±Ñ. Ðикого... Ты приÑвиÑтываешь, наÑÑ‚Ñ€Ð°Ð¸Ð²Ð°Ñ ÑÐµÐ±Ñ Ð½Ð° подвиги. $n приÑвиÑтывает, немного наÑÑ‚Ñ€Ð°Ð¸Ð²Ð°Ñ ÑÐµÐ±Ñ Ð½Ð° подвиги. wiggle вилÑть 0 0 Ты вилÑет хвоÑтом. $n вилÑет хвоÑтом. Ты вилÑешь хвоÑтом перед ноÑом $N2. $n вилÑет хвоÑтом перед $N2. $n вилÑет хвоÑтом перед тобой. Ты похоже, одинок$z. Ты вилÑешь хвоÑтом как рыба. $n вилÑет хвоÑтом как рыба. wink мигать подмигивать 0 5 Что-то попало в глаз? $n двуÑмыÑленно подмигивает. Ты двуÑмыÑленно подмигиваешь $N3. $n подмигивает $N3. $n двуÑмыÑленно подмигивает тебе. Ðикого Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем тут. Ты подмигиваешь Ñебе ?? - Зачем? $n Ñебе подмигивает - что-то Ñ $e Ñтранное творитÑÑ... yawn зевать зевок 0 0 Должно быть ты чувÑтвуешь ÑÐµÐ±Ñ Ð¾Ñ‡ÐµÐ½ÑŒ уÑтало. $n зевает. # snowball Ñнежок 0 0 Ð’ кого тебе хочетÑÑ Ð±Ñ€Ð¾Ñить Ñнежок? $ Ты броÑаешь Ñнежок в $E2 лицо. $n делает Ñнежок из воздуха и броÑает его прÑмо в $N4. $n делает Ñнежок из воздуха и броÑает его тебе прÑмо в лицо. Ты Ñтоишь Ñо Ñнежком в руке и выиÑкиваешь Ñвою жертву. Ты делаешь Ñнежок из воздуха и броÑаешь его Ñебе прÑмо в лицо. $n делает Ñнежок из воздуха и броÑает его Ñебе прÑмо в лицо. french ÑтраÑтно 0 0 Кого поцеловать? $ Ты долго и ÑтраÑтно целуешь $E4. $n ÑтраÑтно целует $N4. $n долго и ÑтраÑтно целует тебÑ. Твое Ñердце наполнÑетÑÑ Ñ‚Ð¾Ñкой, потому что Ñтой личноÑти тут нет. Ты обнимаешь и пытаешьÑÑ Ð¿Ð¾Ñ†ÐµÐ»Ð¾Ð²Ð°Ñ‚ÑŒ...ÑебÑ. $n делает попытку поцеловать ÑебÑ. comb раÑчеÑать 0 0 Ты раÑчеÑываешь Ñвои волоÑÑ‹ - прекраÑно. $n раÑчеÑывает Ñвои волоÑÑ‹ - хорошо выглÑдит ! Ты терпеливо раÑпутываешь $E2 волоÑÑ‹ - что за беÑпорÑдок ! $n пытаетÑÑ Ð¿Ñ€Ð¸Ñ‡ÐµÑать волоÑÑ‹ $N2. $n дергает Ñ‚ÐµÐ±Ñ Ð·Ð° волоÑÑ‹ в попытке причеÑать их. Этих тут нет. Ты дергаешь ÑÐµÐ±Ñ Ð·Ð° волоÑÑ‹, но их очень трудно причеÑать. $n пытаетÑÑ Ð¿Ñ€Ð¸Ñ‡ÐµÑать Ñвои Ñпутанные волоÑÑ‹. massage маÑÑировать маÑÑаж 0 0 Что маÑÑировать? Воздух? $ Ты Ñлегка маÑÑируешь $E2 плечи. $n маÑÑирует плечи $N2. $n мÑгко маÑÑирует твои плечи - Ðаахххх... Ты можешь маÑÑировать только тут. Ты практикуешьÑÑ Ð² йоге и пытаешьÑÑ Ð¼Ð°ÑÑировать ÑÐµÐ±Ñ ÑамоÑтоÑтельно. $n показывает позу йоги, пытаÑÑÑŒ ÑÐµÐ±Ñ Ð¼Ð°ÑÑировать. tickle щекотать 0 0 Кого щекотать? $ Ты щекочешь $N4. $n щекочет $N4. $n щекочет Ñ‚ÐµÐ±Ñ - хи-хи-ХИ! Кого? Ты щекочешь ÑебÑ, как Ñмешно! $n щекочет ÑебÑ. pat похлопать 0 0 Похлопать кого ? $ Ты похлопываешь $N4 по $E2 голове. $n похлопывает $N4 по $E2 голове. $n похлопывает Ñ‚ÐµÐ±Ñ Ð¿Ð¾ голове. Кого, как, где? Ты хлопаешь ÑÐµÐ±Ñ Ð¿Ð¾ голове, очень уÑпокаивает. $n хлопает ÑÐµÐ±Ñ Ð¿Ð¾ голове. curse ругатьÑÑ Ñ€ÑƒÐ³Ð°Ð½ÑŒ 0 0 Ты громко и долго ругаешьÑÑ. $n ругаетÑÑ : #@*"*&^*#%@*&! !!!!! Ты ругаешьÑÑ Ð½Ð° $E4. $n ругаетÑÑ Ð½Ð° $N4. $n ругаетÑÑ Ð½Ð° тебÑ! Что за манеры? Ты не можешь найти жертву, чтобы Ñорвать Ñвою злоÑть. Ты ругаешь ÑÐµÐ±Ñ Ð·Ð° ошибки. $n ругает ÑебÑ. Почему бы тебе не помочь? pray молитьÑÑ Ð¼Ð¾Ð»Ð¸Ñ‚Ð²Ð° 0 0 Ты чувÑтвуешь ÑÐµÐ±Ñ Ð¿Ñ€Ð°Ð²ÐµÐ´Ð½Ð¸ÐºÐ¾Ð¼...и может быть немного глупым. $n молитÑÑ Ð¸ падает ниц. Ты ползаешь в пыли перед $N5. $n падает ниц перед $N5. $n целует пыль у твоих ног. Этой личноÑти тут нет, Ñ‚Ð²Ð¾Ñ Ð¼Ð¾Ð»Ð¸Ñ‚Ð²Ð° раÑтворÑетÑÑ Ð² пуÑтоте. ГоворÑÑ‚, так ÑтановÑÑ‚ÑÑ Ð½Ð°Ñ€Ñ†Ð¸ÑÑиÑтами... $n выполнÑет Ñтранные йогичеÑкие ÑƒÐ¿Ñ€Ð°Ð¶Ð½ÐµÐ½Ð¸Ñ Ð¸ бормочет молитвы Ñебе. beg умолÑть 0 0 Ты умолÑешь бога проÑтить тебÑ. Боги ÑмеютÑÑ Ð² ответ на молитвы $n2 о ÑоÑтрадании. Ты безнадежно пытаешьÑÑ Ð²Ñ‹Ð¼Ð¾Ð»Ð¸Ñ‚ÑŒ неÑколько монет у $E2. $n умолÑет $N4 дать $e3 монетку или две - или двадцать ! $n умолÑет Ñ‚ÐµÐ±Ñ Ð´Ð°Ñ‚ÑŒ немного денег. Бог подаÑÑ‚! Твой ÑпонÑор далеко. УмолÑть ÑÐµÐ±Ñ Ð´Ð°Ñ‚ÑŒ Ñебе же денег? Это ÑовÑем не помогает. # cringe ÑъеживатьÑÑ 1 0 Ты ÑъеживаешьÑÑ Ð¾Ñ‚ ужаÑа. $n ÑъеживаетÑÑ Ð¾Ñ‚ ужаÑа! Ты Ñ ÑƒÐ¶Ð°Ñом отходишь от $E2. $n Ñ ÑƒÐ¶Ð°Ñом отходит подальше от $N2. $n Ñ ÑƒÐ¶Ð°Ñом отходит от тебÑ. Ты никого Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем тут не видишь. Чего же ты боишьÑÑ? Прошу прощениÑ? # daydream мечтать мечта 1 0 Ты мечтаешь о лучших временах. $n выглÑдит отÑутÑвующе, $e2 глаза уÑтавилиÑÑŒ в проÑтранÑтво. # fume дымитьÑÑ 1 5 УÑпокойÑÑ ! доÑчитай до деÑÑти, очень медленно. $n Ñкpежещет зубами и дымитÑÑ Ð¾Ñ‚ ÑpоÑти. ДымÑÑÑŒ, ты пpиÑтально Ñмотpишь на $E4. $n пpиÑтально Ñмотpит на $N4, дымÑÑÑŒ от ÑpоÑти. $n пpиÑтально Ñмотpит на тебÑ, дымÑÑÑŒ от ÑpоÑти. ДымиÑÑŒ... их тут нет. Вот Ñто пpавильно - ненавидеть ÑÐµÐ±Ñ ! $n Ñжимает кулаки и качаетÑÑ Ð½Ð° ноÑках, дымÑÑÑŒ от злоÑти. grovel ползать 1 0 Ты позаешь в пыли. $n ползает в пыли. Ты преÑмыкаешьÑÑ Ð¿ÐµÑ€ÐµÐ´ $E5. $n ползает в гpÑзи перед $N5. $n ползает в гpÑзи пеpез тобой. Who? That seems a little silly to me. # hop прыгать прыжок 0 0 Ты прыгаешь как маленький ребенок. $n прыгает вокруг как маленький ребенок. # nudge толкнуть толчок 0 0 Толкнуть кого? $ Ты подталкиваешь $E4 локтем. $n подталкивает $N4 локтем. $n толкает Ñ‚ÐµÐ±Ñ Ð»Ð¾ÐºÑ‚ÐµÐ¼. Кого-кого? Ты толкаешь ÑÐµÐ±Ñ Ð»Ð¾ÐºÑ‚ÐµÐ¼. $n толкает ÑÐµÐ±Ñ Ð»Ð¾ÐºÑ‚ÐµÐ¼. ponder задуматьÑÑ 0 0 Ты обдумываешь вопроÑ. $n ÑадитÑÑ Ð¸ глубоко задумываетÑÑ. # punch ткнуть 0 0 Ткнуть кого? $ Ты шутливо тыкаешь $E4 кулаком. $n шутливо тыкает $N4 кулаком. $n шутливо тычет Ñ‚ÐµÐ±Ñ ÐºÑƒÐ»Ð°ÐºÐ¾Ð¼. Ох! Ты не находишь партнера. Ты тычешь ÑÐµÐ±Ñ Ð¿Ð¾Ð´ ребра. Ты Ñтого заÑлуживаешь. $n тычет ÑÐµÐ±Ñ Ð¿Ð¾Ð´ ребра. Почему бы тебе не помочь ему? snarl огрызатьÑÑ 0 0 Ты Ñкалишь зубы и зло огрызаешьÑÑ. $n зло огрызаетÑÑ. Ты огрызаешьÑÑ Ð½Ð° $E4. $n огрызаетÑÑ Ð½Ð° $N4. $n огрызаетÑÑ Ð½Ð° тебÑ, Ñ Ñ‡ÐµÐ³Ð¾ бы? Ðе на кого огрызатьÑÑ! Ты огрызаешьÑÑ Ð½Ð° ÑебÑ. $n огрызаетÑÑ Ð½Ð° ÑебÑ. spank шлепнуть шлепок 0 0 Шлепнуть кого? $ Ты игриво шлепаешь $E4. $n игриво шлепает $N4. $n игриво шлепает тебÑ. Ох! Ð¢Ð²Ð¾Ñ Ñ€ÑƒÐºÐ° не находит жертву! Ты шлепаешь ÑебÑ....ХММММмм... $n шлепает ÑебÑ....Хи-хи... hand руку 0 0 Чью руку целовать? $ Ты целуешь $E2 руку. $n целует руку $N2. Как целомудренно! $n целует твою руку. Как целомудренно! Ты не находишь леди в ЭТОЙ группе. Ты целуешь Ñвою руку. ПриÑтно? $n целует Ñвою руку. yodel йодль 1 0 Ты начинаешь петь йодль. $n начинает петь йодль. $N затыкает Ñвои уши, когда ты начинаешь петь йодль. $n поет йодль Ð´Ð»Ñ $N2. $n поет йодль тебе... ты ÑъеживаешьÑÑ Ð¸ отворачиваешьÑÑ. Это человек только что убежал! Ðу, еÑли тебе не жалко Ñвои уши - вперед! $n поет йодль Ñам$z Ñебе. Садо-мазохиÑÑ‚. faint обморок 1 0 Ты падаешь в обморок. $n падает в обморок. Ты падаешь в обморок прÑмо в $E2 руки. $n падает в обморок в раÑкрытые руки $N2. $n падает в обморок в твои руки. Ты падаешь на пол и выглÑдишь идиотом -- Ñто еще мÑгко Ñказано. # pinch щипать ущипнуть 1 0 Ты произноÑишь, 'Ущипни за Ñто и тронь за то.' $n произноÑит, 'Ущипни за Ñто и тронь за то.' Ты щипаешь $E4 за попку и уÑмехаешьÑÑ. $n щипает $N4 за попку и уÑмехаетÑÑ. $n щипает Ñ‚ÐµÐ±Ñ Ð·Ð° попку и уÑмехаетÑÑ. You'd like to, wouldn't you? Ты щипаешь ÑебÑ, чтобы убедитьÑÑ, что ты не Ñпишь. $n щипает ÑебÑ, чтобы убедитьÑÑ, что $e не Ñпит! stroke гладить 1 0 Ты неопределенно гладишь воздух. $n делает неопределенные гладÑщие движениÑ. Ты нежно гладишь $E2 бедро Ñ Ð²Ð½ÑƒÑ‚Ñ€ÐµÐ½Ð½ÐµÐ¹ Ñтороны. $N резко вздыхает. $N резко вздыхает. $n нежно гладит твое бедро Ñ Ð²Ð½ÑƒÑ‚Ñ€ÐµÐ½Ð½ÐµÐ¹ Ñтороны. Ты резко вздыхаешь. ПопрактикуйÑÑ Ñначала на Ñебе. You are about to do something you'd rather not be caught doing. # apologize извинÑтьÑÑ 1 0 Ты извинÑешьÑÑ. $n обильно извинÑетÑÑ. Ты извинÑешьÑÑ Ð¿ÐµÑ€ÐµÐ´ $E5 и проÑишь прощениÑ. $n извинÑетÑÑ Ð¿ÐµÑ€ÐµÐ´ $N5 Ñ Ð²Ð¸Ð½Ð¾Ð²Ð°Ñ‚Ñ‹Ð¼ видом. $n извинÑетÑÑ Ð¿ÐµÑ€ÐµÐ´ тобой и проÑит прощениÑ. Это как ? # caress погладить 1 0 Кого ты хочешь погладить? $ Ты нежно гладишь $E4. $n нежно гладит $N4. $n нежно гладит тебÑ. Да ты ÑекÑуально озабочен$z ! # stagger шататьÑÑ 1 8 Ты Ñлепо шатаешьÑÑ. $n Ñлепо шатаетÑÑ. Ты шатаешьÑÑ Ð¿Ð¾ напpавлению к $N6, а комната начинает вpащатьÑÑ. $n шатаетÑÑ Ðº $N6. $n Ñлепо шатаетÑÑ Ð¿Ð¾ напpавлению к тебе. Это как? # snort фыркать фыркнуть 1 0 Ты наÑмешливо фыркаешь. $n наÑмешливо фыркает. Ты наÑмешливо фыркаешь на $N4. $n наÑмешливо фыркает на $N4. $n наÑмешливо фыркает на тебÑ. Ðа кого фыркнуть? Ты фыркаешь Ñам$z на ÑебÑ. $n фыркает Ñам$z на ÑебÑ. slobber Ñлюнить обÑлюнÑвить 1 0 Ты пуÑкаешь Ñлюни изо рта. $n обÑлюнÑвливает Ñам$z ÑебÑ. Ты пуÑкаешь Ñлюни на $E4. $n пуÑкает Ñлюни на $N4. *Фу* $n обÑлюнÑвливает тебÑ. Кого обÑлюнÑвить? # blink моргать 1 0 Ты невинно хлопаешь глазами. $n невинно моргает. Ты невинно моргаешь, глÑÐ´Ñ Ð½Ð° $N4. $n невинно моргает, глÑÐ´Ñ Ð½Ð° $N4. $n невинно моргает, глÑÐ´Ñ Ð½Ð° тебÑ. Как? # tease дразнитьÑÑ 1 0 Что ты за дpазнилка ! $n оÑматpиваетÑÑ Ð²Ð¾Ðºpуг - кого бы подpазнить. Ты дpазнишь $N4 Ñ Ð¸Ð³pивой уÑмешкой. $n показывает $N3 Ñзык. $n показывает тебе Ñзык! Tease whom? Ты дpазнишь ÑебÑ. HЯ-HЯ-HЯ. $n дpазнит ÑебÑ. knee коленом 1 8 Ты поднимаешь колено, готовÑÑÑŒ к правоÑудию... $n угрожающе поднимает колено. Ты бьешь $E4 коленом в пах. $N ÑгибаетÑÑ Ð¾Ñ‚ боли, когда $n бьет $E4 коленом в пах! $n неожиданно бьет Ñ‚ÐµÐ±Ñ ÐºÐ¾Ð»ÐµÐ½Ð¾Ð¼ в пах! Ты падаешь на колени от боли. Кого ты хочешь Ñделать импотентом? О чем ты думаешь!?!??!?!?!?! # flirt флиртовать 1 0 Ты беÑÑовеÑÑ‚Ñно флиртуешь. $n беÑÑовеÑÑ‚Ñно флиртует. Ты флиртуешь Ñ $N5, пытаÑÑÑŒ завоевать $E2 внимание. $n флиртует Ñ $N5. Хммм, что $e хочет? $n флиртует Ñ Ñ‚Ð¾Ð±Ð¾Ð¹. Извини, тут не Ñ ÐºÐµÐ¼ пофлиртовать. :( Ты флиртуешь Ñам$z Ñ Ñобой -- чего ты хочешь добитьÑÑ!?!?!? $n флиртует Ñам$z Ñ Ñобой - чего $e пытаетÑÑ Ð´Ð¾Ð±Ð¸Ñ‚ÑŒÑÑ? tip шлÑпа приподнÑть 1 0 Ты вежливо приподымаешь шлÑпу. $n вежливо приподымает Ñвою шлÑпу. Ты приподымаешь Ñвою шлÑпу перед н$E5. $n вежливо приподымает Ñвою шлÑпу перед $N5. $n вежливо приподымает Ñвою шлÑпу перед тобой. Ðа кого ты хочешь произвеÑти впечатление? # lust 1 0 Твои гормоны начинают бушевать. Глаза $n начинают гореть желанием --- БыÑтро ÑматывайÑÑ! Ты ÑтраÑтно Ñмотришь на н$M. $n ÑтраÑтно Ñмотрит на $N. $n ÑтраÑтно желает твое тело. Кого ты хочешь? О, пожалуйÑта! ПереÑтань... $n ÑтраÑтно желает ÑÐµÐ±Ñ - как $e одинок$a... flutter 1 0 Ты ÑоблазнÑюще хлопаешь реÑницами. $n ÑоблазнÑюще хлопает реÑницами. Ты Ñмотришь на $N и хлопаешь реÑницами, пытаÑÑÑŒ Ñоблазнить. $n флиртует Ñ $N, ÑоблазнÑюще Ñ…Ð»Ð¾Ð¿Ð°Ñ Ñ€ÐµÑницами. $n Ñмотрит на Ñ‚ÐµÐ±Ñ Ð¸ ÑоблазнÑюще хлопает реÑницами. Эх, ты не видишь их тут. # bark гавкать лаÑть 1 0 Гав-гав !!! Воу-воу ! $n лает Ñловно Ñобака. Гав-гав !!! Воу-воу! воу! Ты гавкаешь на $N, глупо Ð¿ÑƒÐ³Ð°Ñ $E4 -- КÐК ÐЕ СТЫДÐО!! $n гавкает на $N, глупо Ð¿ÑƒÐ³Ð°Ñ $E4. $n громко лает на тебÑ, ты невольно отÑтупаешь!! ЛаÑть на кого? Ты лаешь на ÑÐµÐ±Ñ Ð¸ прыгаешь назад в иÑпуге. $n лает на ÑÐµÐ±Ñ Ð¸ отпрыгивает в иÑпуге. howl выть 1 0 Ты воешь на луну. $n воет на луну. Ты душераздирающе воешь на $E4. $n воет на $N4. $n душераздирающе воет на тебÑ. Who? What? Where? # babble 1 0 Ты болтаешь без перерыва. $n болтает без перерыва, $e когда-нибудь замолчит? Ты болтаешь Ñ $N уже неÑколько чаÑов. $n болтает Ñ $N уже целую вечноÑть - как $N может выноÑить Ñто? $n болтает Ñ Ñ‚Ð¾Ð±Ð¾Ð¹. Ты механичеÑки киваешь, надеÑÑÑŒ, что $e Ñкоро замолчит. Кому ты ÑобираешьÑÑ Ð½Ð°Ð´Ð¾ÐµÐ´Ð°Ñ‚ÑŒ Ñвоей болтовней? Ты болтаешь Ñам$a Ñ Ñобой. Ðаконец! Хоть кто-то, кто Ñ‚ÐµÐ±Ñ Ñлушает!! $n тихо болтает Ñам$a Ñ Ñобой. ramble 1 0 Ты беÑÑвÑзно болтаешь. $n беÑÑвÑзно раÑÑказывает что-то Ñкучное. Ты раÑÑказываешь $N о Ñвоих прошлых приключениÑÑ…. $n раÑÑказывает $N что-то Ñкучное. $n раÑÑказывает тебе ужаÑно Ñкучную иÑторию. Что? # hush 1 0 Шшшшшшшш... $n проÑит вÑех веÑти ÑÐµÐ±Ñ Ð¿Ð¾Ñ‚Ð¸ÑˆÐµ. Шшшшш... Ты мило проÑишь $N веÑти ÑÐµÐ±Ñ Ð¿Ð¾Ñ‚Ð¸ÑˆÐµ. $n мило проÑит $N веÑти ÑÐµÐ±Ñ Ð¿Ð¾Ñ‚Ð¸ÑˆÐµ. $n мило проÑит Ñ‚ÐµÐ±Ñ Ð²ÐµÑти ÑÐµÐ±Ñ Ð¿Ð¾Ñ‚Ð¸ÑˆÐµ. Кому Ñтоит веÑти ÑÐµÐ±Ñ Ð¿Ð¾Ñ‚Ð¸ÑˆÐµ? Ты понимашь, что ведешь ÑÐµÐ±Ñ Ñлишком шумно и пытаешьÑÑ ÑƒÑпокоитьÑÑ. $n закрывает рот рукой, пытаÑÑÑŒ веÑти ÑÐµÐ±Ñ Ð¿Ð¾Ñ‚Ð¸ÑˆÐµ. threaten 1 8 Ты пугаешь вÑех Ñвоим приÑутÑтвием. Ты чувÑтвуешь ÑÐµÐ±Ñ Ð¸Ñпуганно в приÑутÑтвии $n. Ты выпрÑмлÑешьÑÑ Ð²Ð¾ веÑÑŒ роÑÑ‚, пытаÑÑÑŒ иÑпугать $N. $n пытаетÑÑ Ð¸Ñпугать $N. $n пытаетÑÑ Ð¸Ñпугать тебÑ... ой, как Ñтрашно *laugh* Кого надо иÑпугать? # roll закатывать 1 0 Ты Ñ Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸ÐµÐ¼ закатываешь глаза. $n Ñ Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸ÐµÐ¼ закатывает глаза. Ты Ñмотришь на $N4 и Ñ Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸ÐµÐ¼ закатываешь глаза. $n Ñмотрит на $N4 и закатывает глаза. $n закатывает глаза, глÑÐ´Ñ Ð½Ð° тебÑ. Ðа кого ты хочешь закатить глаза? Ты закатываешь глаза и выглÑдишь очень глупо. # swoon обморок 1 0 Ты падаешь в обморок. $n в ÑкÑтазе падает в обморок. Ты Ñмотришь на $N4 и в ÑкÑтазе падаешь в обморок. $n Ñмотрит на $N4 и в Ñктазе падает в обморок. $n Ñмотрит на Ñ‚ÐµÐ±Ñ Ð¸ в Ñктазе падает в обморок. Кто? # bird 1 0 You flick a bird...How obscene! $n flicks a bird at no one in particular. You shoot a bird at $N. $n gives $N the bird. $n gives you the bird...What an ass! Don't you hate to waste a good obscene gesture like that? # eyebrow брови 1 0 Ты поднимаешь брови. $n поднимает брови. Ты поднимаешь брови над дейÑтвием $N2. $n поднимает брови над Ñтранным дейÑтвием $N2. $n поднимает брови над твоим дейÑтвием. Забудь. Таких тут нет. # serenade Ñеренада 1 0 Ты поешь Ñеренаду Ð´Ð»Ñ Ñвоей невидимой любви. $n поет вÑему миру Ñеренаду. Ты поешь прекраÑную Ñеренаду Ð´Ð»Ñ $N2. $n поет прекраÑную Ñеренаду Ð´Ð»Ñ $N2. $n поет Ñеренаду Ð´Ð»Ñ Ñ‚ÐµÐ±Ñ, ты балдеешь от $e2 голоÑа. Человек, которому ты хотел$z Ñпеть, ушел, оÑтавив Ñ‚ÐµÐ±Ñ Ð¿ÐµÑ‚ÑŒ Ð´Ð»Ñ ÑебÑ. Ты поешь Ñеренаду Ñебе. Что ты за человек?! $n поет Ñебе Ñеренаду. ЭгоиÑÑ‚! grimace гримаÑа гримаÑничать 1 0 Ты гримаÑничаешь. $n гримаÑничает. Ты Ñтроишь гримаÑу $N3. $n Ñтроит гримаÑу $N3. $n Ñтроит тебе гримаÑу. Ð’ чем дело? Тут некому ÑоÑтроить гримаÑу. Ты Ñтроишь гримаÑу Ñебе. $n Ñтроит гримаÑу Ñебе. boggle 1 0 You boggle at the concept. $n boggles at the concept. You boggle at $N. $n boggles at $N. $n boggles at you. Boggle away. They've left. You boggle at yourself. Hmmm...intriguing. $n boggles quietly to $mself. beckon 1 0 Ты приглашаешь вÑех Ñледовать за Ñобой. $n приглашает вÑех Ñледовать за Ñобой. Ты приглашаешь $N Ñледовать за Ñобой. $n приглашает $N Ñледовать за Ñобой... хммм, что проиÑходит? $n приглашает Ñ‚ÐµÐ±Ñ Ñледовать за Ñобой. Извини, но Ñтот человек уже ушел. Ты зовешь Ñвою тень Ñ Ñобой. $n зовет Ñвою тень Ñ Ñобой. wonder удивлÑтьÑÑ 1 0 Ты удивлÑешьÑÑ, как могло такое ÑлучитьÑÑ. $n удивлÑетÑÑ, как могло такое ÑлучитьÑÑ. Ты Ñмотришь на $N4 и ждешь, что произойдет. $n Ñмотрит на $N4 и удивлÑетÑÑ... $n вопроÑительно Ñмотрит на тебÑ. Ты думаешь, что могло бы ÑлучитьÑÑ, еÑли бы Ñтот человек тут был. Ты удивлÑешьÑÑ Ñебе и тому, что ты делаешь. ВопроÑительное выражение поÑвлÑетÑÑ Ð½Ð° лице $n. Чему $e удивлÑетÑÑ? worry беÑпокоитьÑÑ 1 0 Ты беÑпокоишьÑÑ, что может ÑлучитÑÑ. БеÑпокойÑтво поÑвлÑетÑÑ Ð½Ð° лице $n2. Ð’ чем дело? Ты Ñмотришь на $N4 Ñ Ð±ÐµÑпокойÑтвом. $n Ñмотрит на $N4 Ñ Ð±ÐµÑпокойÑтвом. $n Ñмотрит на Ñ‚ÐµÐ±Ñ Ñ Ð±ÐµÑпокойÑтвом. Они не беÑпокоÑÑ‚ÑÑ - они ушли! Ты беÑпокоишьÑÑ, что может ÑлучитÑÑ. БеÑпокойÑтво поÑвлÑетÑÑ Ð½Ð° лице $n. Ð’ чем дело? drool 1 0 You drool down the front of your shirt. $n drools all over $mself -- making a TERRIBLE mess! You drool messily on $N. $n drools upon $N. $n looks at you lustily and drools. Oh fine, make a pool of slobber -- they aren't even here! You drool down the front of your shirt. $n drools all over $mself -- making a TERRIBLE mess! nod кивать кивок 1 0 Ты киваешь. $n кивает. Ты киваешь $N3. $n кивает $N3. $n кивает тебе в знак ÑоглаÑиÑ. Ðе кивай - их нет. Ты пытаешьÑÑ ÐºÐ¸Ð²Ð½ÑƒÑ‚ÑŒ Ñебе, но у Ñ‚ÐµÐ±Ñ ÐºÑ€ÑƒÐ¶Ð¸Ñ‚ÑÑ Ð³Ð¾Ð»Ð¾Ð²Ð°. $n уÑпокаивающе кивает Ñебе. purr мурлыкать мурчать 1 0 ММММММЯЯЯЯЯЯУУУУУУ!!! $n довольно мурлыкает. Ты прижимаешьÑÑ Ðº $N3 и довольно мурлыкаешь. $n прижимаетÑÑ Ðº $N3 и довольно мурлыкает. $n прижимаетÑÑ Ðº тебе и довольно мурлыкает. Глупое животное! Тут нет таких. Ты тихо мурлыкаешь Ñебе. $n тихо мурлыкает Ñебе. point указывать 1 0 Ты указываешь во вÑех направлениÑÑ…. $n возбужденно показывает куда-то! Ты показываешь на $N4. $n показывает на $N4! $n показывает на тебÑ. Как грубо! Таких тут нет. Ты Ñмущенно показываешь на ÑебÑ. $n Ñмущенно показывает на ÑебÑ. rub потирать 1 0 Ты потираешь руки в жадном ожидании. $n потирает Ñвои руки в жадном ожидании. Ты долго и мÑгко маÑÑажируешь $N4. $n долго и мÑгко маÑÑажирует $N4. $n маÑÑажирует тебÑ, Ð¿Ñ€Ð¾Ð±ÐµÐ³Ð°Ñ Ñвоими руками по твоим плечам. Хм. Стыдно видеть Ñти одаренные руки в бездейÑтвии... Ты маÑÑажируешь ÑебÑ... задерживаÑÑÑŒ в некоторых меÑтах чуть дольше.. $n маÑÑажирует ÑебÑ... что за ÑÐºÑ†ÐµÐ½Ñ‚Ñ€Ð¸Ñ‡Ð½Ð°Ñ Ð»Ð¸Ñ‡Ð½Ð¾Ñть! bleed 1 0 You bleed profusely -- making a horrible mess! $n weakly bleeds all over the floor. You bleed on $N -- ewww! $n bleeds on $N. Watch out, YOU might be next! $n bleeds on you -- ewww! Get away!! Bleed on whom? You bleed all over yourself. $n bleeds profusely all over $mself. highfive 1 0 You jump in the air and give a BIG high five to...umm...absolutely nothing. $n wildly high fives the air, looking very foolish -- very foolish indeed. You jump in the air and give a BIG high five to $N! $n enthusiastically high-five's $N! $n gives you a BIG high five! Way to go!! Sorry, they have already left. You try to give yourself a high five. What ARE you thinking? $n tries to high five $mself, but ends up looking foolish instead. propose 1 0 You propose to everyone in the room. $n proposes to everyone in the room. Very odd. You kneel and romantically propose to $N. $n gets on one knee and proposes to $N. $n gets down on one knee and romantically proposes to you. You must be lonely. They aren't here. You are SO full of yourself! $n proposes to $mself -- how narcissistic! peer разглÑдывать 1 0 Ты внимательно оглÑдываешьÑÑ Ð²Ð¾ÐºÑ€ÑƒÐ³. $n внимательно оглÑдываетÑÑ Ð²Ð¾ÐºÑ€ÑƒÐ³. Ты приÑтально разглÑдываешь $N4. $n приÑтально разглÑдывает $N4. $n приÑтально разглÑдывает тебÑ. Тут нет таких. Ты раÑÑматриваешь ÑебÑ, ÑкоÑив глаза. $n раÑÑматривает ÑебÑ. worship 1 0 Ты молишьÑÑ Ð±Ð¾Ð³Ð°Ð¼! $n молитÑÑ Ð±Ð¾Ð³Ð°Ð¼! Ты падаешь на колени и боготворишь $E4. $n падает на колени и боготворит $N4. $n падает на колени и боготворит тебÑ. Ты не можешь поклонÑтьÑÑ Ñ‚Ð¾Ð¼Ñƒ, кого тут нет. Ты боготворишь ÑебÑ. $n боготворит ÑебÑ. bearhug 1 0 Whom do you wish to bearhug? $ You overwhelm $N with a great, big, hulking bearhug. $n encompasses $N in an ENORMOUS bearhug! $n clutches you tightly in an overwhelming bearhug! Perhaps you should shower your affections on someone who is here? You vainly clutch yourself in a bearhug for consolation. $n hugs $mself as tightly as possible. Looks like $e could use a hand. spam 1 0 You mutter, 'spam' quietly to yourself again and again. $n rests in a corner and mutters 'spam' quietly to $mself. You SPAM $N mercilessly! $n spams $N! You've been SPAMMED by $n! Spam away -- they've left. # innocent невинно 1 0 Ты невинно наÑвиÑтываешь мелодию. $n невинно наÑвиÑтывает мелодию. Ты Ñмотришь на $N4 и хлопаешь реÑницами -- невинный вид! $n Ñмотрит на $N4 и хлопает реÑницами. $n Ñмотрит на Ñ‚ÐµÐ±Ñ Ð¸ невинно хлопает реÑницами. Даже и не пытайÑÑ - они уже ушли. # collapse падать 1 0 Ты в изнеможении падаешь на пол. $n драматично падает на пол в изнеможении. Ты в изнеможении падаешь на руки $N2. $n в изнеможении падает на руки $N2. Ðеожиданно $n в изнеможении падает прÑмо тебе в руки. Они уже ушли, проÑто падай на пол. # stretch потÑнутьÑÑ 1 0 Ты откидываешьÑÑ Ð¸ потÑгиваешьÑÑ. $n грациозно потÑгиваетÑÑ. Ты хочешь $e4, не так ли? # boast хваÑтатьÑÑ 1 0 Ты громко хваÑтаешьÑÑ Ð¾ Ñвоих невероÑных похождениÑÑ…. $n громко хваÑтаетÑÑ. Ты хваÑтаешьÑÑ $N3 Ñвоими великими делами. $n хваÑтаетÑÑ $N3. Ð’ очередной раз $n хваÑтаетÑÑ Ñ‚ÐµÐ±Ðµ! УÑпокой Ñвой Ñгоизм. Они уже ушли. Ты хваÑтаешьÑÑ Ñебе Ñвоими подвигами. $n хваÑтаетÑÑ Ñам$a Ñебе - ÑгоиÑÑ‚! squirm 1 0 You squirm uncontrollably in your consternation. $n squirms uncontrollably, suddenly looking very uncomfortable. You look at $N and squirm with delight. $n looks at $N and squirms with delight. $n looks at you and squirms with delight. # moo You chew your cud and moo plaintively. Muh-OOOOO! $n turns cowlike eyes on you, chews $s cud, and moos plaintively. You focus all your bovine Zen on $N, and speak your thoughts. Muh-OOOOO! Медленно, Ð¶ÑƒÑ Ð¶Ð²Ð°Ñ‡ÐºÑƒ, $n Ñмотрит на $N, и мычит мууу-УУУУ! $n мычит на тебÑ. Чтобы Ñто могло значить ? You'd better find someone else to moo at. You settle down into the center of your bovine Zen; the foolish world thinks you're just mooing. $n is mooing at $mself again... You look for an exit... moon 1 0 You drop your drawers and moon everyone in the room! $n drops $s pants and gives you the vertical smile! You bend over and moon $N. $n drops $s pants and rudely moons $N! $n bends over and gives you the vertical smile! You stand, with your pants around your ankles, looking VERY silly! You try to moon yourself, but you can't see your A** that well. $n nearly goes into convulsions while trying to moon $mself. goose 1 0 Who would you like to goose? $ You tenderly goose $N on the tush. $n reaches around $N's backside and gooses $M tenderly. $n gooses you tenderly! You should go hunting for another victim, they left. You pinch yourself on the rear, you must be desperate. $n pinches $mself on the rear. wince вздрагивать вздрогнуть 1 0 Ты ÑодрогаешьÑÑ Ð² агонии. $n ÑодрогаетÑÑ Ð² агонии. Ты Ñмотришь на $N4 и вздрагиваешь от $E2 Ñлов. $n вздрагивает от Ñлов $N2. $n вздрагивает от твоих Ñлов. # type 1 0 Ты опуÑкаешь руки, потерÑв надежду научитьÑÑ Ð¿ÐµÑ‡Ð°Ñ‚Ð°Ñ‚ÑŒ без ашыпок! $n опуÑкает руки, потерÑв надежду научитьÑÑ Ð¿ÐµÑ‡Ð°Ñ‚Ð°Ñ‚ÑŒ без ашыпок! # brb 1 0 Заходи еще! $n Ñкоро вернетÑÑ! # mutter бормотать 1 0 Ты тихо бормочешь что-то. $n что-то бормочет. Ты что-то бормочешь $N3. $n Ñмотрит на $N4 и что-то тихо бормочет. $n Ñмотрит на Ñ‚ÐµÐ±Ñ Ð¸ что-то тихо бормочет. Тебе нечего Ñказать - они ушли! Ты тихо бормочешь Ñебе. $n что-то тихо бормочет Ñебе. rofl 1 0 Ты катаешьÑÑ Ð¿Ð¾ земле, иÑтеричеÑки ÑмеÑÑÑŒ. $n падает на землю и катаетÑÑ Ð¿Ð¾ ней, иÑтеричеÑки ÑмеÑÑÑŒ. Ты падаешь на землю, ÑмеÑÑÑŒ над Ñловами $N. $n катаетÑÑ Ð¿Ð¾ земле, ÑмеÑÑÑŒ над Ñловами $N! $n катаетÑÑ Ð¿Ð¾ земле, ÑмеÑÑÑŒ над твоими Ñловами! # sob рыдать 1 0 Ты одиноко рыдаешь Ñебе. $n тихо рыдает. Ты рыдаешь Ñебе, потому что $N наплевал$A на твои чувÑтва. $n тихо рыдает Ñебе, потому что $N наплевал$A на $e чувÑтва! Ты чувÑтвуешь ÑÐµÐ±Ñ Ð½ÐµÐ²ÐµÐ¶ÐµÐ¹, так как заÑтавил$a $N4 рыдать. # pant 1 0 Ты задыхаешьÑÑ Ð¾Ñ‚ желаниÑ. $n задыхаетÑÑ Ð¾Ñ‚ желаниÑ. Ты ÑтраÑтно желаешь $S. $n Ñмотрит на $N и задыхаетÑÑ Ð¾Ñ‚ желаниÑ. $n Ñмотрит на Ñ‚ÐµÐ±Ñ Ð¸ задыхаетÑÑ Ð¾Ñ‚ желаниÑ... # whine Ñкулить 1 0 Ты жалобно Ñкулишь в надежде, что Ñ‚ÐµÐ±Ñ ÑƒÑлышат. $n жалобно Ñкулит в надежде, что $e4 уÑлышат. Ты жалобно Ñкулишь, глÑда на $e4. $n жалобно Ñкулит, глÑÐ´Ñ Ð½Ð° $N4. $n жалобно Ñкулит, глÑÐ´Ñ Ð½Ð° тебÑ. Им вÑе равно. Ты жалобно Ñкулишь Ñебе, так как больше никто Ñ‚ÐµÐ±Ñ Ð½Ðµ Ñлушает. $n жалобно Ñкулит Ñебе. Главное, что $e не приÑтает к тебе. flex 1 0 You flex your muscles proudly! $n flexes $s muscles...what a stud!?! You show off to $N, flexing your muscles proudly. $n flexes $s muscles, in a vain attempt to impress $N. $n flexes $s muscles in a vain attempt to show off to you. # embrace 1 0 Кого ты хочешь заключить в объÑтиÑ? $ Ты Ñ Ð»ÑŽÐ±Ð¾Ð²ÑŒÑŽ заключаешь $N4 в Ñвои объÑтиÑ. $n Ñ Ð»ÑŽÐ±Ð¾Ð²ÑŒÑŽ заключает $N4 в Ñвои объÑтиÑ. $n Ñ Ð»ÑŽÐ±Ð¾Ð²ÑŒÑŽ заключает Ñ‚ÐµÐ±Ñ Ð² Ñвои объÑтиÑ. Твое Ñердце разбито - тут нет таких. Ты обнимаешь ÑебÑ, пытаÑÑÑŒ утешитьÑÑ. $n обнимает ÑебÑ, пытаÑÑÑŒ утешитьÑÑ. duck 1 0 DUCK!!!! $ Ты уворачиваешьÑÑ, предчувÑÑ‚Ð²ÑƒÑ Ð´ÐµÐ¹Ñтвие $N. $n уворачиваетÑÑ, предчувÑÑ‚Ð²ÑƒÑ Ñ€ÐµÐ°ÐºÑ†Ð¸ÑŽ $N. $n уворачиваетÑÑ, пожалуйÑта, не бей $s! # bonk 1 0 ***BONK!!!*** $ You bonk $N on the head for being such a moron. $n bonks $N on the head for being such an UTTER moron. $n bonks you on the head for being so foolish. ***BONK*** they left... You bonk yourself, fool that you are. $n bonks $mself and grimaces in pain. squeal визжать 1 0 Ты визжишь от воÑторга! $n визжит от воÑторга! Ты Ñмотришь на $N4 и взвизгиваешь от воÑторга! $n визжит от воÑторга, глÑÐ´Ñ Ð½Ð° $N4. $n Ñмотрит на Ñ‚ÐµÐ±Ñ Ð¸ взвизгивает от воÑторга! # tackle 1 0 You're going to tackle everyone in the room?! $ You tackle $N playfully. $n playfully tackles $N. $n brings you down in a playful tackle! # spit плевать 1 0 Ты Ñплевываешь Ñ Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸ÐµÐ¼. $n Ñплевывает Ñ Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸ÐµÐ¼! Ты плюещь на $N4... как вульгарно! $n плюет на $N4. $n плюет на Ñ‚ÐµÐ±Ñ - как вульгарно! Твоей жертвы тут нет. Ты плюешь на ÑÐµÐ±Ñ - противно, да? $n плюет на ÑебÑ... как глупо! life 0 0 You try to get a life, and fail. $n tries to get a life, and fails. $N needs to get a life! $N needs to get a life! You need to get a life! Who needs a life? But you have none to give! $n attempts to give $mself a life, but has none to spare. mosh 8 0 You mosh insanely around the room! $n moshes insanely around the room! You mosh sadistically against $N ... you WILL be punished. $n bounces off of $N in a vain attempt to mosh... what a LOSER. $n slams into you, moshing painfully against you. That REALLY hurts! Hmmm... your victim found a new dance partner. Masochist! $n throws $mself on the floor, grinding $mself into a bloody pulp flinch 0 0 Ð-а-а... Ты вздрагиваешь от боли. $n вздрагивает от боли... Что $e Ñделал$a на Ñтот раз? Тебе не кажетÑÑ, что ты можешь проÑто лечь и умереть? $n глÑдит на $N и вздрагивает. $n вздрагивает в ответ на твой холодный упрек. УÑпокойÑÑ, они ушли. Ты не можешь поверить, что ты Ñделал$a... $n вздрагивает, оÑознав Ñвое поведение. air 0 0 Ты берешь воздушную гитару и играешь Ð´Ð»Ñ Ð²Ñех, кого ценишь. $n безумно играет на воздушной гитаре... Великолепно!!! Ты надеешьÑÑ, что $E оценит твой талант. $n играет прекраÑную мелодию Ð´Ð»Ñ $N. $n играет Ñамую прекраÑную мелодию Ð´Ð»Ñ Ñ‚ÐµÐ±Ñ Ð½Ð° $s воздушной гитаре. Ðууу... у Ñ‚ÐµÐ±Ñ Ð½ÐµÑ‚ аудитории! Ты тихо играешь Ð´Ð»Ñ ÑебÑ. # tweak ущипнуть 0 0 Кого ущипнуть? $ Ты мÑгко щипаешь $e2 щеку... $E прелеÑть, не так ли? $n щипает $N4 за щеку... Они выглÑдÑÑ‚ воÑхитительно вмеÑте, правда? $n щипает Ñ‚ÐµÐ±Ñ Ð·Ð° щеку. Это напоминает про бабушку... фи... Этого человека похоже тут нет. Ты не можешь Ñтого Ñделать. # peck 5 0 Ðе хочешь ли ты Ñделать Ñто человеку или ты предпочитаешь воздух? $ РиÑÐºÑƒÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ пощечину, ты целуешь $N в щеку. $n улыбаетÑÑ Ð¸ целует $N в щеку. $n целует Ñ‚ÐµÐ±Ñ Ð² щеку, как Ñладко! Я думаю, они ушли... Ты похоже очень любишь ÑебÑ. # explode взрыватьÑÑ 0 0 Ты чувÑтвуешь, как кровь кипит в твоих венах! $n ÑтановитÑÑ Ð±Ð°Ð³Ñ€Ð¾Ð²Ñ‹Ð¼. Ты чувÑтвуешь, как Ñ‚Ð²Ð¾Ñ ÑроÑть разраÑтаетÑÑ... $n прожигает дырки на $N6 Ñвоей ÑроÑтью! $n злитÑÑ Ð½Ð° тебÑ... Я бы на твоем меÑте бежал!!! УÑпокойÑÑ... они ушли. Ð¢Ð²Ð¾Ñ Ð´ÑƒÑˆÐ° Ñрко разгораетÑ, но потом затухает. $n пропал$a!!! Только жирное пÑтно оÑталоÑÑŒ на том меÑте, где $e раньше ÑтоÑл$a. raspberry 4 0 You stick your tongue out at ... well, no one. $n sticks $s tongue out, catching a few flies in the process. You give $N the raspberry... and spit all over yourself. $n gives $N the raspberry... PHBT! What a mess... Spit EVERYWHERE! You are splattered with saliva as $n gives you the raspberry... HOW RUDE! Hang your tongue out if you like, $e isn't here. You try to stick your tongue out at yourself... somehow, it isn't the same. # flash 0 0 You grin and strut as you open your coat and show what you've got! $n rips $s clothes off and parades naked around the room! Swiftly you jerk open your jacket, trying to get $M to notice you. Cover your eyes, $n is exposing $mself to $n! EWWWW! You gasp! $n has just revealed $s "equipment" to you! Exhibitionist, that person isn't here! That's sick. PERVERT PRESENT! $n is trying to flash $mself strip Ñнимать 0 0 Ты начинаешь показывать медленный Ñтриптиз Ð´Ð»Ñ Ð¾ÐºÑ€ÑƒÐ¶Ð°ÑŽÑ‰Ð¸Ñ…... $n начинает показывать Ñтриптиз... Ты начинаешь раздевать $N4... вещь за вещью... $n начинает медленно Ñнимать Ñ $N2 одежду... $n начинает медленно раздевать тебÑ... Твоей игрушки похоже тут нет... Ðе при людÑÑ…! # undress раздеватьÑÑ 0 0 Ты начинаешь раздеватьÑÑ Ð² тени, выжидаÑ, пока Ñ‚ÐµÐ±Ñ Ð·Ð°Ð¼ÐµÑ‚ÑÑ‚. $n начинает раздеватьÑÑ... очень ÑекÑуально... *Pant* Ты раздеваешь глазами $N4... Прикольно. Температура раÑтет - $n ÑтраÑтно Ñмотрит на $N4... Ты чувÑтвуешь, как $n раздевает Ñ‚ÐµÐ±Ñ Ð³Ð»Ð°Ð·Ð°Ð¼Ð¸... Тут нет таких... Лучше перед зеркалом... # tongue 0 0 You slowly give your tongue a nice workout. $ Mmmm... you give $N a good working over with your tongue... $n slides $s tongue over $N's body... $n wraps $s tongue around you, moving it across your young, nubile flesh... Never around when required... You slowly tongue yourself. $n slowly tongues $mself... ICK. view 0 0 Ты удобно уÑтраиваешьÑÑ Ð¸ Ñмотришь, что проиÑходит в мире. $n удобно уÑтраиваетÑÑ Ð¸ наÑлаждаетÑÑ Ð²Ð¸Ð´Ð¾Ð¼. # grumble ворчать 0 0 Ты тихо ворчишь про ÑебÑ. $n ворчит и рычит. Ð’ чем дело... Ты ворчишь на $N4, Ñ‚ÐµÐ±Ñ Ñ€Ð°Ð·Ð´Ñ€Ð°Ð¶Ð°ÐµÑ‚ $e2 приÑутÑтвие. $n выглÑдит как медведь-ворчун... $e уже замучал$a $N4 Ñвоим ворчанием. $n ворчит на тебÑ... что ты Ñделал$A? Этого человека похоже тут нет. О чем ты беÑпокоишьÑÑ? # cheer удачи 0 0 Ты шутливо прыгаешь и пританцовываешь! $n радуетÑÑ Ð¸ припевает! Ты желаешь $N3 удачи! *Вау!* Вперед, $N!!! $n поддержит $e4. $n желает тебе удачи! Ðе подведи $e4. Кто? Что? Где? Их тут нет, Ñто точно. Ты тихо желаешь Ñебе удачи, так как больше никто Ñтого не Ñделал. $n желает удачи Ñам$a Ñебе... как печально. plead 0 0 Ты умолÑешь поÑлушать тебÑ. $n умолÑет поÑлушать $s... Тебе $s почти жалко. # charge 0 0 Ты затеваешь драку! $n затевает драку! Ðи капли мозгов. С неожиданной быÑтротой ты бьешь $N головой! $n разбегаетÑÑ Ð¸ бьет $N головой прÑмо в живот! Уф! $n бьет Ñ‚ÐµÐ±Ñ Ð³Ð¾Ð»Ð¾Ð²Ð¾Ð¹ прÑмо в живот! Это было больно. Ðикого вокруг Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем нет. Ты разбегаешьÑÑ Ð¸ бьешьÑÑ Ð³Ð¾Ð»Ð¾Ð²Ð¾Ð¹ в Ñтенку. Ой! # criticize критиковать критика 0 0 Да, но кого? $ Ты критикуешь $N4 Ñо вÑей горÑчноÑтью. Злобно ухмылÑÑÑÑŒ, $n уничтожает вÑе ÑÑ‚Ð°Ñ€Ð°Ð½Ð¸Ñ $N2. $n говорит, что тебе нужно Ñделать много важных улучшений. Эх, куда же делать Ñ‚Ð²Ð¾Ñ Ð¶ÐµÑ€Ñ‚Ð²Ð°... Ты критикуешь Ñам$a ÑебÑ. $n рвет и мечет, Ð¿Ñ€Ð¾ÐºÐ»Ð¸Ð½Ð°Ñ ÑобÑтвенную глупоÑть. run 0 0 Ты убегаешь в Ñтрахе и ужаÑе! $n убегает в Ñтахе и ужаÑе! Ты в ужаÑе убегаешь от $N! $n убегает от $N в Ñтрахе и ужаÑе! $n бежит от тебÑ, опаÑаÑÑÑŒ за Ñвою жизнь! Тебе нечего боÑтьÑÑ - тут таких нет. Ðеужели ты наÑтолько некраÑив$a? $n Ñмотрит в зеркало, видит Ñвое лицо и в Ñтрахе убегает! judge Ñудить 0 0 Да, но кого? $ Ты оцениваешь $e4 по шкале от 1 до 10. По шкале от 1 до 10, $n оценивает $N4 как полный ноль!!! $n оценивает твои дейÑÑ‚Ð²Ð¸Ñ Ð¿Ð¾ шкале от 1 до 10 и решает, что Ñто... Ðоль!!! Ð¡ÐµÐ¹Ñ‡Ð°Ñ Ñ‚Ð°ÐºÐ¸Ñ… тут нет. Ты ведь не хочешь Ñтого делать. # insane 0 0 Ты чувÑтвуешь, как твое здравомыÑлие иÑчезает... ПрÑмо на твоих глазах, здравомыÑлие $n иÑчезает... # cover затыкать заткнуть 0 0 Ты затыкаешь уши от шума. $n затыкает уши от шума. Ты Ñмотришь на $N4 и затыкаешь уши. $n Ñмотрит на $N4 и закрывает уши. $n затыкает Ñвои уши из-за тебÑ... ты Ñлишком громко кричишь! Их ÑÐµÐ¹Ñ‡Ð°Ñ Ñ‚ÑƒÑ‚ нет. Ðет... Я так не думаю. # flare 0 0 Ты пренебрежительно раздуваешь ноздри. $n пренебрежительно раздувает ноздри. Ты пренебрежительно раздуваешь ноздри, глÑÐ´Ñ Ð½Ð° $N... Как грубо! $n пренебрежительно раздувает ноздри, глÑÐ´Ñ Ð½Ð° $N, и отворачиваетÑÑ. $n пренебрежительно раздувает ноздри, глÑÐ´Ñ Ð½Ð° тебÑ... Что ты Ñделал$A??? ЗлиÑÑŒ, еÑли хочешь, но Ñтого человека тут нет. *Sniff* Ðо тебе бы Ñледовало любить ÑебÑ! # head 0 0 Ты надменно закидываешь голову. $n надменно закидывает голову. Ты надменно закидываешь голову, глÑÐ´Ñ Ð½Ð° $N. $n надменно закидывает голову, глÑÐ´Ñ Ð½Ð° $N... $n надменно закидывает голову, глÑÐ´Ñ Ð½Ð° тебÑ... :( Этот человек уже ушел. Зачем тебе Ñто? # pie 0 0 Ты берешь пирог и кидаешь его в Ñтенку. $n берет пирог и кидает его в Ñтенку. Ты берешь пирог и кидаешь его прÑмо в лицо $N! $n берет пирог и кидает его прÑмо в лицо $N! $n кидает пирог прÑмо тебе в лицо... и ÑÐµÐ¹Ñ‡Ð°Ñ Ñƒ Ñ‚ÐµÐ±Ñ Ð²Ñе лицо в креме! Этого человека тут нет... Ты падаешь лицом прÑмо в торт... уимммм!!! :) $n падает лицом прÑмо в торт, Ð¾Ð±Ð»Ð¸Ð·Ñ‹Ð²Ð°Ñ Ñ‚Ð°Ñ€ÐµÐ»ÐºÑƒ. cower 0 0 Ты приÑаживаешьÑÑ Ð² уголке. $n приÑаживаетÑÑ Ð² уголке и тихо вÑхлипывает. Ты приÑаживаешьÑÑ Ð² уголке, подальше от $N и $S грÑзных Ñлов. $n приÑаживаетÑÑ Ð² уголке, подальше от $N. Ты иÑпугал$a $n! Ð¡ÐµÐ¹Ñ‡Ð°Ñ $e Ñидит в уголке, опаÑаÑÑÑŒ за Ñвою жизнь. Этого человека ÑÐµÐ¹Ñ‡Ð°Ñ Ñ‚ÑƒÑ‚ нет. Ты боишьÑÑ ÑобÑтвенной тени! $n ÑадитÑÑ Ð² уголке, пугаÑÑÑŒ ÑобÑтвенной тени. noogie 5 0 You can't noogie the AIR! It has no head. $ You grab $N, get $M in a head lock and NOOGIE $M! $n grabs $N in a head lock and NOOGIES $M... ARGH!!! Oh NO, $n grabs you, throws you in a head lock and NOOGIES you! That person has gone off to other lands... You rub your head and create a static charge... $n rubs $s OWN head and creates a static charge... *ZAP* yeehaw 5 0 You mount your pony(?) and shout YEEEEEEEHAAAAAAAW! $n bounces up and down screaming *YEEEEEEHAAAAAAW!* # pissed 5 0 You are PISSED! $n is PISSED so watch out! You turn a stoney gaze toward $N... you are SOOO pissed at $N! $n glares at $n.... $n is SOOO PISSED at $m! $n is pissed at you now... What do you think $e'll DO? That person is not here... You are PISSED at yourself! $n is so pissed at $mself. How could $e be so stupid??? passout 5 0 You belch and pass out. $n is OBVIOUSLY intoxicated... $e burps loudly and passes out! # adjust 5 0 Ты Ñмотришь вокруг, убеждаешьÑÑ, что никто не Ñмотрит и поправлÑешь Ñвой "инÑтрумент". $n хитро оглÑдыаетÑÑ, улыбаетÑÑ, потом Ñ‚ÑнетÑÑ Ð²Ð½Ð¸Ð· и "поправлÑет" ÑебÑ... # scratch 5 0 Ты довольно почеÑываешь ÑебÑ. $n Ñ‚ÑнетÑÑ Ð²Ð½Ð¸Ð· и почеÑывает ÑÐµÐ±Ñ Ñ‚Ð°Ð¼... Ð¡ÐµÐ¹Ñ‡Ð°Ñ $e выглÑдит очень ÑчаÑтливо. # meditate 0 0 Ты ÑадишьÑÑ Ð¿Ð¾ÑƒÐ´Ð¾Ð±Ð½ÐµÐµ и начинаешь медитировать. $n ÑадитÑÑ Ð¸ начинает медитировать... $e что-то тихо напевает про ÑебÑ. # bkiss 0 0 Ты поÑылаешь Ñвой поцелуй в воздух. $n поÑылает Ñвой поцелуй в воздух. Ты поÑылаешь $N воздушный поцелуй и надеешьÑÑ, что $E поймает его. $n поÑылает $N воздушный поцелуй... Как мило! $n поÑылает тебе воздушный поцелуй и надеетÑÑ, что ты пошлешь его обратно. Твой поцелуй падает на землю, не находÑ, к кому лететь. Ты поÑылаешь Ñебе поцелуй... Мир прекраÑен, не нак ли? $n поÑылает Ñебе поцелуй, выглÑÐ´Ñ Ð¿Ñ€Ð¸ Ñтом влюбленно. beer пиво 0 0 Ты доÑтаешь 6 банок пива. $n начинает раÑпаковывать 6 банок пива. Ты броÑаешь бутылку пива $N3. $n броÑает бутылку пива $N3 ... надеÑÑÑŒ, что $E поймает ее! $n броÑает тебе бутылку пива... Похоже, $e чего-то хочет... Бутылка падает на пол и разбиваетÑÑ. Ты открываешь бутылку и пьешь пиво. $n открывает бутылку и начинает жадно глотать пиво. bcatch 0 0 Ты прыгаешь и ловишь бутылку, которую тебе кинули. $n подпрыгивает и в воздухе ловит бутылку, которую $e3 кинули. # claw царапать 0 0 Ты Ñжимаешь руки в кулаки. $n Ñжимает Ñвои кулаки, пока из них не начинает капать кровь... Ты впиваешьÑÑ Ð½Ð¾Ð³Ñ‚Ñми в $E2 глаза... Как грубо! $n впиваетÑÑ Ð½Ð¾Ð³Ñ‚Ñми в глаза $N2... О, Боже, кровь! $n впиваетÑÑ Ð½Ð¾Ð³Ñ‚Ñми в твои глаза и ты оÑлеплен$A Ñвой ÑобÑтвенной кровью! Тебе некого поцарапать. Ты разрываешь ÑÐµÐ±Ñ Ð½Ð° куÑочки! $n раздирает ÑÐµÐ±Ñ Ð½Ð° куÑочки! rose роза 0 0 Кому бы ты хотел$a подарить розу? $ Ты даришь $N3 прекраÑную розу. $n дарит $N3 прекраÑную розу. $n дарит тебе прекраÑную ---'---,--{{@ Они похоже ушли. Ты даешь Ñебе розу и чувÑтвуешь одиночеÑтво... $n дарит Ñам$a Ñебе розу, тебе не жалко $s? laces шнурки 0 0 Чьи шнурки? $ Ðезаметно Ð´Ð»Ñ Ð²Ñех, ты ÑвÑзываешь $E2 шнурки вмеÑте. $n подкрадываетÑÑ Ðº $N3 и ÑвÑзывает $E2 шнурки вмеÑте. Ты пытаешьÑÑ Ñделать шаг и падаешь лицом на пол! $n похоже ÑвÑзал$a твои шнурки! Чьи шнурки? Ты ÑвÑзываешь Ñвои шнурки, пытаешьÑÑ Ñделать шаг и падаешь. $n ÑвÑзывает Ñвои шнурки вмеÑте, пытаетÑÑ Ñделать шаг и падает лицом на пол. tag Tag whom? $n casts about for someone to tag. >From nowhere, you pounce on $N and TAG $M remorselessly! BWAHAHA!!! $n dives from the shadows and TAGS $N. $N IS IT! $n pounces on you and >>> TAGS <<< you! You're IT! Who were you going to tag, then? Unable to catch anyone else, you do the intelligent thing and tag yourself. You're still IT! Unable to catch anyone else, $n tags $mself. Are you impressed? tank танковать You boldly offer to tank for your everyone else. Are you sure you know what you're getting into? $n offers to tank! Ты предлагаешь пойти вперед грудью (танком) перед $N5. $n предлагает пойти вперед грудью (танком) перед $N5. $n предлагает пойти вперед грудью (танком) перед тобой! Танковать Ð´Ð»Ñ ÐºÐ¾Ð³Ð¾ ? No one will tank for you, eh?!? WELL, YOU'LL SHOW THEM! (right?) In dazzling chivalry, $n offers to tank-- for $mself! starve голодать Ты показываешь Ñвои выÑтупающие ребра и надеешьÑÑ, что Ñ‚ÐµÐ±Ñ Ð¿Ð¾Ð¶Ð°Ð»ÐµÑŽÑ‚. $n Ñохнет прÑмо на глазах - $e умирает от голода! Ты броÑаешьÑÑ Ð¿Ð¾Ð´ ноги $N3, умолÑÑ Ð´Ð°Ñ‚ÑŒ немного еды. $n проÑит у $N2 еды. $e думает, что Ð¼Ð°Ð³Ð¸Ñ Ð¼Ð¾Ð¶ÐµÑ‚ утолить голод... $n умирает от голода прÑмо на твоих глазах! ПоделишьÑÑ ÐµÐ´Ð¾Ð¹? Извини, но Ñтого человека тут нет -- похоже ты так и умрешь от голода. # aargh Ð-Ð-Ð-Ð-а-а-а-а-а!!! $n закидывает голову и раÑÑтроенно кричит! Ты раÑÑтроенно кричишь и хватаешь ÑÐµÐ±Ñ Ð·Ð° горло Ð´Ð²ÑƒÐ¼Ñ Ñ€ÑƒÐºÐ°Ð¼Ð¸! $n раÑÑтроенно кричит и прыгает вокруг $N2, пытаÑÑÑŒ задушить $E! $n хватает Ñ‚ÐµÐ±Ñ Ð·Ð° горло, раÑÑтроенно крича! Ты еще более раÑÑтраиваешьÑÑ, когда понимаешь, что некого придушить! Ты раÑÑтроенно кричишь на ÑÐµÐ±Ñ Ð·Ð° Ñвою глупоÑть! $n раÑÑтроенно кричит на ÑÐµÐ±Ñ Ð·Ð° Ñвою глупоÑть! homework Ты неожиданно вÑпоминаешь, что тебе еще надо доделать кое-что ÑегоднÑ... $n выглÑдит взволнованно. Может $e забыл$a Ñделать какое-то важное задание? # puff Ты подражаешь Ñамым глупым выходкам Пуфф. $n говорит, "Знаете ли вы, что Ñ Ð½Ð°Ð¿Ð¸Ñан$a на C?" # yae Ты вздыхаешь в приÑутÑтвии Еще Одного Идиота. $n вздыхает в приÑутÑтвии Еще Одного Идиота. Тут еÑть Еще Один Идиот в комнате, и ты Ñмотришь прÑмо на н$s. $n чеÑтно веришь, что $N - идиот! $n Ñмотрит на тебÑ, твой интеллект Ñвно не впечатлÑет $s. Тут полно идиотов, но того, который тебе нужен, тут ÑÐµÐ¹Ñ‡Ð°Ñ Ð½ÐµÑ‚Ñƒ. Ты бьещь ÑÐµÐ±Ñ Ð¿Ð¾ лбу за Ñвое идиотÑкое поведение! $n ругает ÑÐµÐ±Ñ Ð·Ð° Ñвое идиотÑкое поведеине! lightbulb *Динь!* Вдохновение! Лампочка зажигаетÑÑ Ð½Ð°Ð´ головой $n! # voodoo Bad juju like this has to be directed at a person. $n looks hostile for a moment. You stare daggers at $N, jabbing pins into $S effigy. $n glares balefully at $N while stabbing a pin into a voodoo doll. Your heart lurches in your chest, and fiery pain stabs through your skull! Your hatred finds no such target. You stab a pin into your own voodoo doll! Agony! $n jabs a pin into $s own voodoo doll, and twitches in agony! ogg Ogg who? $ Engage! $n oggs $N's head with photon torpedos! $N reels. $n oggs your head with photon torpedos! You are reeling. You can't find your target. If you do that, the universe will explode. $n almost oggs $mself, but wisely reconsiders. confused ÑмущатьÑÑ Ð¢Ð²Ð¾Ðµ Ñмущение заметно. $n Ñмущенно моргает... Ты Ñмущенно моргаешь, пытаÑÑÑŒ понÑть $E2 Ñлова. $n Ñмущенно моргает. Может $N пропуÑтил$A Ñлово в $S предложении... $n Ñмущенно моргает. Может ты пропуÑтил$A Ñлово в Ñвоем предложении? Ðе удивительно, что ты ÑмущаешьÑÑ. # beam You beam delightedly at nothing in particular. $n beams broadly at nothing in particular. You dazzle $N with your smile. $n must like $N a great deal to beam at $M so broadly! $n must like you a great deal to beam at you so broadly! You look pretty silly beaming at imaginary friends... Well, aren't you special? $n beams at $mself, obviously pleased. bite You glare around, muttering "Bite me..." under your breath. $n glares around, muttering "Bite me..." under $s breath. You bite $N on the neck. $n bites $N on the neck! $n bites you on the neck. Hungry? No such luck. You bite your knuckle in anguish. $n bites $s knuckle in anguish...the tragedy! discodance Groovy! $n discos wildly! You grab $N and disco wildly! Groovy! $n grabs $N and does $m best Travolta! $n grabs you and does $m best Travolta! It's okay, you can disco solo too. # scuff You scuff your foot sheepishly. $n scuffs $s foot in the dirt, looking very sheepish. You scuff your foot, avoiding $N's gaze. $n scuffs $s foot and shyly avoids $N's gaze. $n scuffs $s foot and shyly avoids your gaze. They aren't here. # whap Whap who? $ You whap $N upside the head! With a resounding WHAP!, $n reprimands $N. HEY! $n whaps you upside the head! Whiff... Ow! You give yourself a resounding whap upside the head. Biff! $n whaps $mself upside the head! lag Yes, yes. $n is m o v i n g v e ry sl o w l y ... # chortle Heh. $n chortles mischievously. You chortle mischievously at $N. $n chortles mischievously at $N. $n chortles mischievously at you. Took you a while to get that....they aren't here. You chortle at your own joke. $n chortles at $s own joke. Don't bother. zerbert Gotta zerbert SOMEBODY. $ You lift $N's shirt and blow loudly into $S navel! $n lifts $N's shirt and blows loudly into $S navel! Yeek! $n lifts your shirt and blows loudly into your navel! You missed. Careful, people are staring... $n looks around furtively, and then bends over and blows loudly into $s own navel! twitch нервно 0 0 Ты нервно дергаешьÑÑ. $n нервно дергаетÑÑ. Ты непроизвольно дергаешьÑÑ Ð² приÑутÑтвии $N. $N дергаетÑÑ Ð¿Ñ€Ð¸ виде $n... $n замечает Ñ‚ÐµÐ±Ñ Ð¸ начинает дергатьÑÑ. Ðервничаешь? Ðо их тут нет. # leer 0 0 You peer around the room, leering like the pervert you are! $n peers about, leering like a filthy pervert! You leer at $N like the pervert you are. $n eyes $N up and down, leering like a filthy pervert! $n eyes you up and down, leering like a filthy pervert! You'll have to settle for memories -- that person isn't here. Desperation has reached new heights, hasn't it? $n leers at $mself shamelessly. polite 0 0 Ты Ñлегка поÑмеиваешьÑÑ. $n Ñлегка поÑмеиваетÑÑ. Ты незаметно поÑмеиваешьÑÑ Ð½Ð°Ð´ $S шуткой. $n Ñлегка поÑмеиваетÑÑ Ð½Ð°Ð´ шуткой $N. $n незаметно поÑмеиваетÑÑ Ð½Ð°Ð´ твоей шуткой. Тебе не Ñ ÐºÐµÐ¼ поÑмеÑтьÑÑ. Ты поÑмеиваешьÑÑ Ð½Ð°Ð´ Ñвоей шуткой, так как больше никто не хочет. $n поÑмеиваетÑÑ Ð½Ð°Ð´ Ñвоей шуткой, так как больше никто не хочет. mischievous ехидно 0 0 Ты ехидно улыбаешьÑÑ Ñвоим мыÑлÑм. $n ехидно уÑмехаетÑÑ Ð½Ð°Ð´ гадкой идеей. Ты ехидно уÑмехаешьÑÑ Ð½Ð°Ð´ $N, задумав что-то гадкое. $n ехидно уÑмехаетÑÑ Ð½Ð°Ð´ $N. $e похоже задумал$a что-то гадкое. $n ехидно уÑмехаетÑÑ Ð½Ð°Ð´ тобой. Ты поглÑдываешь в Ñторону двери. Ты бредишь. Ты ехидно уÑмехаешьÑÑ Ð½Ð°Ð´ Ñобой. $n ехидно уÑмехаетÑÑ Ð½Ð°Ð´ Ñобой. accept 0 0 You accept the proferred apology graciously. $n graciously accepts the proferred apology. # anticipate 0 0 You murmur 'Sssssoonnn, my presssssciousssss...' $n murmurs 'Ssssssooonnnn, my pressssscioussss...' # powertrip 0 0 You scream 'The PPppppPOOOOoooWWWwwwErrRRR!' and writhe. $n writhes, screaming 'The PPppppPOOOOoooWWWwwwErrRRR!' # shudder 0 0 Ты дрожишь в ужаÑе, подавлÑÑ Ñлезы. $n дрожит в ужаÑе, подавлÑÑ Ñлезы. # sage 0 0 Ты киваешь Ñ ÑƒÐ¼Ð½Ñ‹Ð¼ видом. $n кивает Ñ ÑƒÐ¼Ð½Ñ‹Ð¼ видом. # contemplate 0 0 Ты задумчиво прикуÑываешь губу. $n задумчиво прикуÑывает губу. # agree ÑоглашатьÑÑ 0 0 Ты ÑоглашаешьÑÑ. $n ÑоглашаетÑÑ. Ты воÑторженно ÑоглашаешьÑÑ Ñ $N5. $n воÑторженно ÑоглашаетÑÑ Ñ $N5. $n воÑторженно ÑоглашаетÑÑ Ñ Ñ‚Ð¾Ð±Ð¾Ð¹. Извини, Ñтот человек отÑутÑтвует. Ты ÑоглашаешьÑÑ Ñам$a Ñ Ñобой. $n ÑоглашаетÑÑ Ñам$a Ñ Ñобой. toast тоÑÑ‚ 0 0 Ты поднимаешь бокал шампанÑкого, ÑобираÑÑÑŒ произнеÑти тоÑÑ‚. $n поднимает бокал шампанÑкого, ÑобираÑÑÑŒ произнеÑти тоÑÑ‚. Ты поднимаешь бокал шампанÑкого за н$e. $n молча пьет за $N4. $n молча пьет за тебÑ. Этот человек отÑутÑтвует. Ты ухмылÑешьÑÑ Ð¸ пьешь за ÑебÑ. $n ухмылÑетÑÑ Ð¸ пьет за ÑебÑ. conspire 0 0 Ты заговорщичеÑки подмигиваешь, Ð¾Ð¶Ð¸Ð´Ð°Ñ Ñигнала. $n заговорщичеÑки подмигивает, Ð¾Ð¶Ð¸Ð´Ð°Ñ Ñигнала. Ты заговорщичеÑки подмигиваешь $N. $n заговорщичеÑки подмигивает $N. Хм, что бы Ñто значило? $n заговорщичеÑки подмигивает тебе. Ты уÑтраиваешь заговор Ñам$a Ñ Ñобой. $n подозрительно Ñмотрит вокруг. # support поддерживать 0 0 Ты полноÑтью поддерживаешь план. $n полноÑтью поддерживает план. Ты поддерживающе обнимаешь $S и улыбаешьÑÑ. $n поддерживающе обнимает $N и улыбаетÑÑ. $n поддерживающе обнимает Ñ‚ÐµÐ±Ñ Ð¸ улыбаетÑÑ. Извини, друг, но Ñтого человека тут нет. Ты Ñ Ð³Ñ€ÑƒÑтью обнимаешь ÑебÑ. $n Ñ Ð³Ñ€ÑƒÑтью обнимает ÑебÑ. Может ты можешь помочь? pound 0 0 Ты делаешь неопределенные Ð´Ð²Ð¸Ð¶ÐµÐ½Ð¸Ñ ÐºÑƒÐ»Ð°ÐºÐ°Ð¼Ð¸. $n делает неопределенные Ð´Ð²Ð¸Ð¶ÐµÐ½Ð¸Ñ ÐºÑƒÐ»Ð°ÐºÐ°Ð¼Ð¸. Ты бьешь $N, Ð¿Ñ€ÐµÐ²Ñ€Ð°Ñ‰Ð°Ñ $S в кровавую маÑÑу. $n бьет $N, Ð¿Ñ€ÐµÐ²Ñ€Ð°Ñ‰Ð°Ñ $S в кровавую маÑÑу. $n бьет тебÑ, Ð¿Ñ€ÐµÐ²Ñ€Ð°Ñ‰Ð°Ñ Ð² кровавую маÑÑу. Извини, друг, но Ñ Ð½Ðµ вижу Ñтого человека тут. # wrist 0 0 Ты поднимаешь руку, чтобы ударить. $n поднимает руку, чтобы ударить. Ты резко бьешь $S по руке. $n резко бьет $N по руке. $n резко бьет Ñ‚ÐµÐ±Ñ Ð¿Ð¾ руке. Извини, друг, но Ñ Ð½Ðµ вижу Ñтого человека тут. Ты бьешь ÑÐµÐ±Ñ Ð¿Ð¾ руке. $n бьет ÑÐµÐ±Ñ Ð¿Ð¾ руке. romeo 0 0 Ты зажигаешь Ñигару 'Romeo & Julietta' и затÑгиваешьÑÑ Ñ ÑƒÐ´Ð¾Ð²Ð¾Ð»ÑŒÑтвием. $n зажигает Ñигару 'Romeo & Julietta' и затÑгиваетÑÑ Ñ ÑƒÐ´Ð¾Ð²Ð¾Ð»ÑŒÑтвием. # camel 0 0 You pretend you are a camel. $n pretends to be a camel. You light a Camel cigarette for $M. $n lights a Camel cigarette for $N. $n lights a Camel cigarette for you. You don't see that personhere. You light a Camel cigarette and inhale sharply. $n lights a Camel cigarette and inhales sharply. whip 0 0 You crack your bullwhip menacingly. $n cracks a bullwhip menacingly. You flick your whip across $M bare back. $n flicks $s whip across $N's bare back. $n flicks a whip across your back... the pain.. the pleasure.. Sorry, friend, I can't see that person here. You whip yourself into a frenzy. $n whips $mself into a frenzy. cramp 0 0 You gasp and clutch your abdomen, wheezing with the pain. $n gasps and clutches $m abdomen in agony. You hammerlock $M, screaming, "AAAAARRRRRGH!! I HAVE A CRAMP!!!" $n hammerlocks $N, screaming, "AAAAARRRRRGH!! I HAVE A CRAMP!!!". $n hammerlocks you, screaming "AAAAARRRRRGH!! I HAVE A CRAMP!!!" Suffering as you are, you didn't see that person slip out. # make 0 0 You breathe heavily and wetly. $n breathes heavily and wetly. You steam up the windows with $M. $n and $N start steaming up the windows. $n starts steaming up the windows with you. Sorry, friend, I can't see that person here. # sweep 0 0 Ты Ñмотришь на Ñвои пуÑтые руки и вздыхаешь. $n Ñмотрит на Ñвои пуÑтые руки и вздыхает. Ты берешь $N на руки и целуешь $S долго и ÑтраÑтно. $n берет $N на руки и целует $S долго и ÑтраÑтно. $n берет Ñ‚ÐµÐ±Ñ Ð½Ð° руки и целует долго и ÑтраÑтно. Человека, которого ты хотел$a поцеловать, тут нет. # buff ногти 0 0 Ты полируешь ногти. $n полирует ногти. # liver печень 0 0 Ты злобно оглÑдываешьÑÑ, Ð²Ñ‹Ð±Ð¸Ñ€Ð°Ñ Ñ†ÐµÐ»ÑŒ. $n злобно оглÑдываетÑÑ, Ð²Ñ‹Ð±Ð¸Ñ€Ð°Ñ Ñ†ÐµÐ»ÑŒ. Ты вырываешь $S печень и ешь ее. $n вырывает печень $N и еÑÑ‚ ее. $n вырывает твою печень и еÑÑ‚ ее. Объект твоей злоÑти отÑутÑтвует. # wrestle боротьÑÑ 0 0 $ $ Ты борешьÑÑ Ñ $N на полу. $n боретÑÑ Ñ $N на полу. $n боретÑÑ Ñ Ñ‚Ð¾Ð±Ð¾Ð¹ на полу. Извини, друг, но Ñ Ð½Ðµ вижу Ñтого человека тут. Ты борешьÑÑ Ñо Ñвоей ÑовеÑтью. $n боретÑÑ Ñо Ñвоей ÑовеÑтью. tie 0 0 Ты вертишь в руках пару наручников. $n вертит в руках пару наручников. Ты хватаешь $N и привÑзываешь $S к кровати. $n хватает $N и привÑзывает $S к кровати. $n хватает Ñ‚ÐµÐ±Ñ Ð¸ привÑзывает к кровати. Извини, друг, Ñ Ð½Ðµ вижу Ñтого человека тут. # tight 0 0 $ $ Ты крепко держишь $E в Ñвоих руках. $n крепко держит $N в Ñвоих руках. $n крепко держит Ñ‚ÐµÐ±Ñ Ð² Ñвоих руках. Извини, друг, Ñ Ð½Ðµ вижу Ñтого человека тут. # fatality 0 0 $ $ Ты замечаешь, '$N победил$A. Это конец.' $n замечает, '$N победил$A. Это конец.' $n замечает, '$N победил$A. Это конец.' # yowl выть 0 0 Ты разочарованно воешь. $n разочарованно воет! # silly глупо 0 0 Ты глупо прогуливаешьÑÑ Ð¿Ð¾ комнате. $n беÑцельно прогуливаетÑÑ Ð¿Ð¾ комнате. $e выглÑдит дейÑтвительно глупо. # dig копать ковырÑть 0 0 Ты ковырÑешь ноÑком ноги землю. $n ковырÑет ноÑком землю. # finger пальцы 0 0 Ты раÑтопыриваешь пальцы веером. $n раÑтопыривает пальцы веером. # #0 #$ tkabber-plugins/socials/socials.tcl000064400000000000000000000122721500237002100173130ustar00nobodynobody# socials.tcl -- # # This file implements Socials plugin for the Tkabber XMPP client. package require msgcat namespace eval socials { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered socials]} { ::plugins::register socials \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Socials\ plugin is loaded."] \ -loadcommand \ [namespace code \ [list load [file join \ [file dirname [info script]] \ socials.ru] \ utf-8]] \ -unloadcommand [namespace code unload] return } } proc socials::load {filename {enc utf-8}} { variable social_list {} variable social load_file $filename $enc #puts [array get social] #puts [socials::interp giggle asd ""] #puts [socials::interp ползать asd qwe] hook::add generate_completions_hook \ [namespace current]::commands_comps 51 #puts [llength $social_list] hook::add chat_send_message_hook \ [namespace current]::handle_commands 50 return } proc socials::unload {} { variable social_list variable social hook::remove chat_send_message_hook \ [namespace current]::handle_commands 50 hook::remove generate_completions_hook \ [namespace current]::commands_comps 51 catch {unset social_list} catch {unset social} return } proc socials::load_file {filename {enc utf-8}} { variable social set f [file join [file dirname [info script]] $filename] set fd [open $f] fconfigure $fd -encoding $enc while {1} { set s [gets $fd] if {$s == "" && [eof $fd]} break set s [string trim $s] if {$s == "#SOCIALS" || $s == ""} continue if {$s == "#0"} break set names [split $s] set names [lsearch -all -inline -regexp $names {[^\d]}] #puts $names add $names foreach kind {char_no_arg others_no_arg char_found others_found \ vict_found char_not_found char_auto others_auto} { set s [string trim [gets $fd]] if {$s == {$}} { continue } elseif {$s == "#"} { break } assign $names $kind $s } } close $fd } proc socials::add {names} { variable social variable social_list foreach name $names { lappend social_list $name } foreach kind {char_no_arg others_no_arg char_found others_found \ vict_found char_not_found char_auto others_auto} { assign $names $kind "" } } proc socials::assign {names kind val} { variable social foreach name $names { set social($kind,$name) $val } } proc socials::substitute {s from to} { regsub -all {\$n\d?} $s /me s regsub -all {\$e\d?} $s /me s #regsub -all {\$e\d?} $s $from s regsub -all {\$N\d?} $s $to s regsub -all {\$E\d?} $s $to s return $s } proc socials::interp {soc from to} { variable social if {$to == ""} { return [substitute $social(others_no_arg,$soc) $from $to] } else { return [substitute $social(others_found,$soc) $from $to] } } proc socials::commands_comps {chatid compsvar wordstart line} { variable social_list upvar 0 $compsvar comps if {!$wordstart} { foreach soc $social_list { lappend comps "/$soc " } } #debugmsg completion "SOC: $comps" } proc socials::handle_commands {chatid user body type} { variable social_list variable social #if {$type != "groupchat"} return if {[string index $body 0] != "/"} return set we [string wordend $body 1] set command [string trim [string range $body 1 $we]] set to [string trim [string range $body $we end]] if {[lsearch -exact $social_list $command] >= 0} { set our_jid [chat::our_jid $chatid] set xlib [chat::get_xlib $chatid] if {[catch {chat::get_nick $xlib $our_jid groupchat} from]} { set from [chat::get_nick $our_jid groupchat] } if {$to == $from} { set s [substitute $social(others_auto,$command) $from $to] } elseif {$to == ""} { set s [substitute $social(others_no_arg,$command) $from $to] if {$s == ""} { set se [substitute $social(char_no_arg,$command) $from $to] chat::add_message $chatid $chatid error $se {} } } else { set s [substitute $social(others_found,$command) $from $to] } if {$s != ""} { #hook::run chat_send_message_hook $chatid $user $s $type ::plugins::send_message $chatid $user $s $type ::plugins::draw_message $chatid $user $s $type } return stop } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/spy000075500000000000000000000000001500237002100142455ustar00nobodynobodytkabber-plugins/spy/msgs000075500000000000000000000000001500237002100152165ustar00nobodynobodytkabber-plugins/spy/msgs/de.msg000064400000000000000000000022751500237002100164030ustar00nobodynobody# de.msg -- # # German messages for the Spy Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 26.03.2009 ::msgcat::mcset de "Alert when available" "Benachrichtigen wenn verfügbar" ::msgcat::mcset de "Cancel" "Abbrechen" ::msgcat::mcset de "File to log Spy Presence messages." \ "Datei, in die Präsenz-Spion-Nachrichten geschrieben werden sollen." ::msgcat::mcset de "Format of timestamp in Spy Presence window." \ "Format des Zeitstempels im Präsenz-Spion-Fenster." ::msgcat::mcset de "Open chat" "Chat öffnen" ::msgcat::mcset de "Plugins options." "Optionen für Plugins." ::msgcat::mcset de "Presence Spy" "Präsenz-Spion" ::msgcat::mcset de "Remove" "Entfernen:" ::msgcat::mcset de "Set watch" "Überwachen:" ::msgcat::mcset de "Spy Alert: user %s (%s) is available!" \ "Spion-Benachrichtigung: Benutzer %s (%s) ist verfügbar!" ::msgcat::mcset de "Spy Presence plugin options." \ "Optionen für das Präsenz-Spion-Plugin." ::msgcat::mcset de "Spy presence" "Präsenz-Spion" ::msgcat::mcset de "Spy" "Präsenz-Spion" ::msgcat::mcset de "Whether the Spy Presence plugin is loaded." \ "Präsenz-Spion-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/spy/msgs/es.msg000064400000000000000000000021501500237002100164120ustar00nobodynobody# es.msg -- # # Spanish messages for the Spy Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "Alert when available" "Alertar cuando disponible" ::msgcat::mcset es "Cancel" "Cancelar" ::msgcat::mcset es "File to log Spy Presence messages." \ "Fichero donde guardar mensajes de Espia Presencia." ::msgcat::mcset es "Format of timestamp in Spy Presence window." \ "Formato del tiempo en la ventana de Espia Presencia." ::msgcat::mcset es "Open chat" "Abrir charla" ::msgcat::mcset es "Plugins options." "Opciones de plugins." ::msgcat::mcset es "Presence Spy" "Espia Presencia" ::msgcat::mcset es "Remove" "Borrar" ::msgcat::mcset es "Set watch" "Guardar" ::msgcat::mcset es "Spy Alert: user %s (%s) is available!" \ "Alerta Espia: el usuario %s (%s) está conectado" ::msgcat::mcset es "Spy Presence plugin options." \ "Opciones del plugin Espia Presencias." ::msgcat::mcset es "Spy presence" "Espiar presencia" ::msgcat::mcset es "Spy" "Espia" ::msgcat::mcset es "Whether the Spy Presence plugin is loaded." \ "Cargar el plugin Spy Presence." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/spy/msgs/pl.msg000064400000000000000000000023431500237002100164220ustar00nobodynobody# pl.msg -- # # Polish messages for Presence spy plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Presence Spy" "Åšledzenie statusów" ::msgcat::mcset pl "Spy" "Åšledzenie statusów" ::msgcat::mcset pl "Spy presence" "Åšledzenie statusów" ::msgcat::mcset pl "Set watch" "Ustaw czujkÄ™" ::msgcat::mcset pl "Spy Presence plugin options." \ "Ustawienia wtyczki Å›ledzenia statusów." ::msgcat::mcset pl "File to log Spy Presence messages." \ "Nazwa pliku do którego zapisywane bÄ™dÄ… Å›ledzone statusy." ::msgcat::mcset pl "Format of timestamp in Spy Presence window." \ "Format znacznika czasu w oknie Å›ledzenia statusów." ::msgcat::mcset pl "Alert when available" \ "Alarmuj kiedy kontakt staje siÄ™ dostÄ™pny" ::msgcat::mcset pl "Spy Alert: user %s (%s) is available!" \ "Alarm Å›ledzenia statusów: użytkownik %s (%s) jest dostÄ™pny!" ::msgcat::mcset pl "Open chat" "Rozpocznij rozmowÄ™" ::msgcat::mcset pl "Cancel" "Anuluj" ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "Remove" "UsuÅ„" ::msgcat::mcset pl "Whether the Spy Presence plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ Å›ledzenia statusów." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/spy/msgs/ru.msg000064400000000000000000000033361500237002100164400ustar00nobodynobody# ru.msg -- # # Russian messages for Presence spy plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Alert when available" "Предупреждать при поÑвлении" ::msgcat::mcset ru "Cancel" "Отменить" ::msgcat::mcset ru "File to log Spy Presence messages." \ "Файл, в который ÑохранÑетÑÑ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ приÑутÑтвии." ::msgcat::mcset ru "Format of timestamp in Spy Presence window." \ "Формат вывода даты/времени в шпионÑком окне." ::msgcat::mcset ru "Open chat" "Открытие окна разговора" ::msgcat::mcset ru "Plugins options." "Параметры раÑширений." ::msgcat::mcset ru "Play this sound file" "Проигрывать Ñтот звуковой файл" ::msgcat::mcset ru "Presence Spy" "Шпион за приÑутÑтвием" ::msgcat::mcset ru "Remove" "Удалить" ::msgcat::mcset ru "Set watch" "УÑтановить наблюдение" ::msgcat::mcset ru "Sound when available" "Проигрывать звук при поÑвлении" ::msgcat::mcset ru "Spy Alert: user %s (%s) is available!" \ "Тревога: пользователь %s (%s) доÑтупен!" ::msgcat::mcset ru "Spy Presence plugin options." \ "ÐаÑтройки раÑширениÑ, шпионÑщего за приÑутÑтвием." ::msgcat::mcset ru "Spy presence" "Шпионить за приÑутÑтвием" ::msgcat::mcset ru "Spy" "Шпион" ::msgcat::mcset ru "Whether the Spy Presence plugin is loaded."\ "Загружено ли раÑширение, шпионÑщее за приÑутÑтвием." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/spy/msgs/uk.msg000064400000000000000000000031701500237002100164250ustar00nobodynobody# uk.msg -- # # Ukrainian messages for Presence spy plugin. # # Author: Artem Bondarenko # Author: Sergei Golovan ::msgcat::mcset uk "Alert when available" "Сповіщати коли доÑтупний" ::msgcat::mcset uk "Cancel" "Відмінити" ::msgcat::mcset uk "File to log Spy Presence messages." \ "Файл протоколу Ð´Ð»Ñ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½ÑŒ шпигуна." ::msgcat::mcset uk "Format of timestamp in Spy Presence window." \ "Формат дати/чаÑу у вікні шпигуна." ::msgcat::mcset uk "Open chat" "Відкрити розмову" ::msgcat::mcset uk "Plugins options." "Параметри плагінів." ::msgcat::mcset uk "Presence Spy" "Шпигун" ::msgcat::mcset uk "Remove" "Видалити" ::msgcat::mcset uk "Set watch" "УÑтановити наглÑд" ::msgcat::mcset uk "Spy Alert: user %s (%s) is available!" \ "Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ шпигуна: кориÑтувач %s (%s) доÑтупний" ::msgcat::mcset uk "Spy Presence plugin options." \ "Параметри плагіна Spy Presence." ::msgcat::mcset uk "Spy presence" "Шпигувати за приÑутніÑтю" ::msgcat::mcset uk "Spy" "Шпигун" ::msgcat::mcset uk "Play this sound file" "Програвати цей звуковий файл" ::msgcat::mcset uk "Sound when available" "Програвати звук коли з’ÑвлÑєтьÑÑ" ::msgcat::mcset uk "Whether the Spy Presence plugin is loaded." \ "Чи завантажене розширеннÑ, Ñке шпигує за приÑутніÑтю. " # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/spy/spy.tcl000064400000000000000000000346571500237002100156620ustar00nobodynobody# spy.tcl -- # # Tkabber presence spy module, version 1.0. # Traces presence messages, logging them into tkabber window # and/or file. # # Copyright (C) 2003 Maciek Pasternacki # Modifications: Sergei Golovan package require msgcat namespace eval spy { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered spy]} { ::plugins::register spy \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Spy\ Presence plugin is\ loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable options custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup Spy [::msgcat::mc "Spy Presence plugin options."] \ -group Plugins custom::defvar options(log_file) "" \ [::msgcat::mc "File to log Spy Presence messages."] \ -type string -group Spy custom::defvar options(timestamp_format) {[%m/%d %R]} \ [::msgcat::mc "Format of timestamp in Spy Presence window."] \ -type string -group Spy custom::defvar options(plugin_spy_sound) \ [fullpath sounds default chat_their_message.wav] \ [::msgcat::mc "Play this sound file"] \ -command [list ::sound::load_sound_file plugin_spy] \ -type file -group Spy } proc spy::load {} { variable the_file variable watches set the_file "" set watches {} hook::add postload_hook [namespace current]::init_spy 100 hook::add client_presence_hook \ [namespace current]::client_presence_handler 100 hook::add quit_hook [namespace current]::deinit_spy 100 hook::add finload_hook [namespace current]::setup_menu hook::add save_session_hook [namespace current]::save_session init_spy setup_menu } proc spy::unload {} { variable the_file variable watches desetup_menu if {[winfo exists .spy]} { destroy_win .spy } deinit_spy hook::remove postload_hook [namespace current]::init_spy 100 hook::remove client_presence_hook \ [namespace current]::client_presence_handler 100 hook::remove quit_hook [namespace current]::deinit_spy 100 hook::remove finload_hook [namespace current]::setup_menu hook::remove save_session_hook [namespace current]::save_session set the_file "" set watches {} namespace delete [namespace current]::search } option add *Spy.timestampforeground $::defaultforeground widgetDefault if {$::darktheme} { option add *Spy.nickforeground cornflowerblue widgetDefault option add *Spy.jidforeground cornflowerblue widgetDefault option add *Spy.presenceforeground coral3 widgetDefault option add *Spy.reasonforeground mediumorchid3 widgetDefault } else { option add *Spy.nickforeground DarkBlue widgetDefault option add *Spy.jidforeground DarkBlue widgetDefault option add *Spy.presenceforeground DarkRed widgetDefault option add *Spy.reasonforeground DarkMagenta widgetDefault } proc spy::open_window {} { variable watches set w .spy if {[winfo exists $w]} { raise_win $w return } add_win $w -title [::msgcat::mc "Presence Spy"] \ -tabtitle [::msgcat::mc "Spy"] \ -class Spy \ -raisecmd [list [namespace current]::focus_log] \ -raise 1 Frame $w.controls Button $w.controls.add -text [::msgcat::mc "Set watch"] \ -command "[namespace current]::set_watch" set watch_entry [Entry $w.controls.watch_regex] bind $watch_entry "[namespace current]::set_watch" pack $w.controls.add -side left -anchor e pack $watch_entry -side left -anchor w -fill x pack $w.controls -side bottom -fill x Frame $w.watches foreach watch $watches { set watch_id [lindex $watch 0] set watch_regex [lindex $watch 1] add_watch_frame $watch_id $watch_regex } pack $w.watches -side bottom -fill x set sw [ScrolledWindow $w.isw -scrollbar vertical] pack $sw -side top -fill both -expand yes -in $w -pady 1m set log [Text $w.log -wrap word -state disabled -takefocus 1] $sw setwidget $log bind [Wrapped $log] <1> [list [namespace current]::focus_log] $log tag configure timestamp \ -foreground [option get $w timestampforeground Spy] $log tag configure nick \ -foreground [option get $w nickforeground Spy] $log tag configure jid \ -foreground [option get $w jidforeground Spy] $log tag configure presence \ -foreground [option get $w presenceforeground Spy] $log tag configure reason \ -foreground [option get $w reasonforeground Spy] search::setup_panel $w } proc spy::focus_log {} { set w .spy focus [Wrapped $w.log] } proc spy::set_watch {} { variable watches set w .spy if {![winfo exists $w]} return set entr $w.controls.watch_regex set regex [$entr get] if {$regex eq ""} return # Add new watch if there is no such already present foreach watch $watches { set r [lindex $watch 1] set idx [lindex $watch 0] if {$r == $regex} { #set b [$w.watches.$idx cget -background] #$w.watches.$idx configure -background red #after 1500 [list $w.watches.$idx configure -background $b] return } } if {[catch {regexp $regex ""}]} { if {[catch { $entr configure \ -foreground [option get $entr errorForeground Entry] }]} { # The invalid.TEntry style is defined in # tkabber/plugins/search/search.tcl $entr configure -style invalid.TEntry } return } else { if {[catch { $entr configure \ -foreground [option get $entr foreground Entry] }]} { $entr configure -style TEntry } } set next_watch 0 while {[winfo exists $w.watches.$next_watch]} { incr next_watch } lappend watches [list $next_watch $regex] add_watch_frame $next_watch $regex } proc spy::add_watch_frame {watch_id watch_regex} { variable spy_alerts set w .spy if {![winfo exists $w]} return Frame $w.watches.$watch_id Button $w.watches.$watch_id.remove -text [::msgcat::mc "Remove"] \ -command [list [namespace current]::remove_watch $watch_id $watch_regex] Label $w.watches.$watch_id.regex -text $watch_regex \ -foreground [option get $w nickforeground Spy] Label $w.watches.$watch_id.nick -text "" \ -foreground [option get $w nickforeground Spy] Label $w.watches.$watch_id.jid -text "" \ -foreground [option get $w nickforeground Spy] Label $w.watches.$watch_id.timestamp -text "" \ -foreground [option get $w timestampforeground Spy] Label $w.watches.$watch_id.presence -text "" \ -foreground [option get $w presenceforeground Spy] Label $w.watches.$watch_id.reason -text "" \ -foreground [option get $w reasonforeground Spy] Checkbutton $w.watches.$watch_id.alert \ -text [::msgcat::mc "Alert when available"] \ -variable [namespace current]::spy_alerts($watch_id) set [namespace current]::spy_alerts($watch_id) 0 Checkbutton $w.watches.$watch_id.sound \ -text [::msgcat::mc "Sound when available"] \ -variable [namespace current]::spy_alerts($watch_id.sound) set [namespace current]::spy_alerts($watch_id.sound) 0 pack $w.watches.$watch_id.remove \ $w.watches.$watch_id.regex \ $w.watches.$watch_id.timestamp \ $w.watches.$watch_id.nick \ $w.watches.$watch_id.jid \ $w.watches.$watch_id.presence -side left pack $w.watches.$watch_id.alert -side right pack $w.watches.$watch_id.sound -side right pack $w.watches.$watch_id.reason -side left -fill x pack $w.watches.$watch_id -side bottom -fill x } proc spy::remove_watch {watch_id watch_regex} { variable watches set w .spy.watches.$watch_id if {![winfo exists $w]} return set idx [lsearch -exact $watches [list $watch_id $watch_regex]] set watches [lreplace $watches $idx $idx] destroy $w } proc spy::update_watch {xlib watch_id nick jid type reason} { variable options variable spy_alerts set w .spy.watches.$watch_id if {![winfo exists $w]} return $w.timestamp configure -text \ [clock format [clock seconds] -format $options(timestamp_format)] $w.nick configure -text $nick $w.jid configure -text $jid $w.presence configure -text $type $w.reason configure -text $reason if {$spy_alerts($watch_id) && $type=="available"} { alert_dialog $xlib $watch_id $nick $jid } if {$spy_alerts($watch_id.sound) && $type=="available" } { ::sound::play $options(plugin_spy_sound) } } proc spy::alert_dialog {xlib watch_id nick jid} { set w .spy_alert_${watch_id} if {[winfo exists $w]} { destroy $w } set message [::msgcat::mc "Spy Alert: user %s (%s) is available!" \ $nick $jid] Dialog $w -title $message -modal none -anchor e -default 0 -cancel 1 set frame [$w getframe] Message $frame.msg -text $message -aspect 50000 pack $frame.msg -side left -fill x $w add -text [::msgcat::mc "Open chat"] \ -command [list [namespace current]::open_chat $w $xlib $jid ] $w add -text [::msgcat::mc "Cancel"] -command [list destroy $w] $w draw } proc spy::open_chat {w xlib jid} { destroy $w chat::open_to_user $xlib $jid } proc spy::display {xlib jid nick type reason} { variable options variable watches set w .spy if {![winfo exists $w]} return set log $w.log $log configure -state normal $log insert end \ [clock format [clock seconds] -format $options(timestamp_format)] \ timestamp " " {} if {$nick ne ""} { $log insert end $nick nick " (" {} $jid jid ") " {} } else { $log insert end $jid jid " " {} } $log insert end "$type" presence if {$reason ne ""} { $log insert end " (" {} $reason reason ")" {} } $log insert end "\n" $log see end $log configure -state disabled foreach watch $watches { set watch_id [lindex $watch 0] set watch_regex [lindex $watch 1] if {[regexp $watch_regex $nick] || [regexp $watch_regex $jid]} { update_watch $xlib $watch_id $nick $jid $type $reason } } } proc spy::client_presence_handler {xlib from type x args} { variable options variable the_file if {[catch { chat::get_nick $xlib $from chat } nick]} { if {[catch { chat::get_nick $from chat } nick]} { set nick $from } } if {$nick eq $from} { set nick "" } set reason "" set show "" foreach {attr val} $args { switch -- $attr { -status {set reason $val} -show {set show $val} } } if {$type eq ""} { set type available } if {$show ne ""} { set type $type/$show } display $xlib $from $nick $type $reason if {$options(log_file) ne "" && $the_file eq ""} { init_spy } if {$options(log_file) eq "" && $the_file ne ""} { deinit_spy } if {$the_file ne ""} { puts -nonewline $the_file "[clock format [clock seconds]] " if {$nick ne ""} { puts -nonewline $the_file "$nick ($from) " } else { puts -nonewline $the_file "$from " } puts -nonewline $the_file "$type" if {$reason ne ""} { puts -nonewline $the_file " ($reason)" } puts $the_file "" flush $the_file } } proc spy::init_spy {} { variable the_file variable options if {$options(log_file) ne ""} { if {$the_file ne ""} { catch {close $the_file} set the_file "" } set the_file [open $options(log_file) a] puts $the_file "[clock format [clock seconds]] Started spying." } } proc spy::deinit_spy {} { variable the_file if {$the_file ne ""} { puts $the_file "[clock format [clock seconds]] Spy goes away." catch {close $the_file} set the_file "" } } proc spy::setup_menu {} { catch { set m [.mainframe getmenu plugins] $m add command -label [::msgcat::mc "Spy presence"] \ -command [namespace current]::open_window } } proc spy::desetup_menu {} { catch { set m [.mainframe getmenu plugins] set idx [$m index [::msgcat::mc "Spy presence"]] $m delete $idx } } namespace eval spy::search {} proc spy::search::open_panel {w sf} { pack $sf -side bottom -anchor w -fill x -before $w.isw update idletasks $w.log see end } proc spy::search::close_panel {w sf} { $w.log tag remove search_highlight 0.0 end pack forget $sf [namespace parent]::focus_log } proc spy::search::setup_panel {w} { set log $w.log $log mark set sel_start end $log mark set sel_end 0.0 set sf [plugins::search::spanel [winfo parent $log].search \ -searchcommand [list ::plugins::search::do_text_search $log] \ -closecommand [list [namespace current]::close_panel $w]] bind $w.log <> \ [double% [list [namespace current]::open_panel $w $sf]] } ############################################################################## proc spy::restore_window {args} { open_window } proc spy::save_session {vsession} { upvar 2 $vsession session global usetabbar # We don't need JID at all, so make it empty (special case) set user "" set server "" set resource "" # TODO if {!$usetabbar} return set prio 0 foreach page [.nb pages] { set path [ifacetk::nbpath $page] if {[string equal $path .spy]} { lappend session [list $prio $user $server $resource \ [list [namespace current]::restore_window] \ ] } incr prio } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/stripes000075500000000000000000000000001500237002100151235ustar00nobodynobodytkabber-plugins/stripes/AUTHORS000064400000000000000000000000661500237002100162540ustar00nobodynobodyKonstantin Khomoutov tkabber-plugins/stripes/INSTALL000064400000000000000000000006751500237002100162430ustar00nobodynobodyAs usual, copy this directory under the ~/.tkabber/plugins directory so that you get a hierarchy like this: ~/.tkabber/plugins ~/.tkabber/plugins/stripes/ ~/.tkabber/plugins/stripes/stripes.tcl Restart Tkabber, to get the plugin loaded. Consult the README file for the details about using this plugin. Usually you'll want to set the stripes' color which can be done either via XRDB (on Unix) or using Tk option database (on any system). tkabber-plugins/stripes/README000064400000000000000000000030701500237002100160620ustar00nobodynobody"Stripes" -- chat plugin for Tkabber. I. The Idea This plugin allows to colorize backgrounds of the whole messages placed in the conversation logs of Tkabber chat windows. Backgrounds of even and odd messages can be configured separately from each other (or not configured at all). II. Usage The colors of even and odd messages can be manipulated using the Tk option database resources which are: * Chat.oddBackground for odd messages. * Chat.evenBackground for even messages. When the particular resource is not defined, it's not used thus not affecting the appearance of the corresponding messages. By default these resources are not defined. The color may be specified in any form accepted by Tk which mean any named color (from the X server's color database on systems using X Window or listed in [1] on other systems) or the color specification such as #RRGGBB. For the strict explanation or color specifications read [2]. III. Examples 1) To set up gray colors using the Tkabber configuration file add these lines to your config.tcl file: # Colors for the stripes plugin: option add *Chat.oddBackground gray77 option add *Chat.evenBackground gray84 2) To do the same using XRDB (systems based on X Window): ! Colors for the stripes plugin: Tkabber*Chat.oddBackground: AntiqueWhite Tkabber*Chat.evenBackground: bisque IV. Bugs and limitations * Changing any color resource at runtime won't affect already opened chat windows. V. References 1. http://www.tcl.tk/man/tcl8.5/TkCmd/colors.htm 2. http://www.tcl.tk/man/tcl8.5/TkLib/GetColor.htm # vim:tw=64:et tkabber-plugins/stripes/license.terms000064400000000000000000000021201500237002100176730ustar00nobodynobodyCopyright (c) 2007, 2008 Konstantin Khomoutov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tkabber-plugins/stripes/msgs000075500000000000000000000000001500237002100160745ustar00nobodynobodytkabber-plugins/stripes/msgs/de.msg000064400000000000000000000007451500237002100172610ustar00nobodynobody# de.msg -- # # German messages for the Stripes Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 18.11.2010 ::msgcat::mcset de "This plugin paints backgrounds of even and odd messages\ in chat windows with different colors." "Die Hintergründe gerader und\ ungerader Nachrichten mit unterschiedlichen Farben darstellen." ::msgcat::mcset de "Whether the Stripes plugin is loaded." \ "'Stripes'-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/stripes/msgs/ru.msg000064400000000000000000000011271500237002100173120ustar00nobodynobody# ru.msg -- # # Russian messages for the Stripes Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Whether the Stripes plugin is loaded." \ "Загружено ли раÑширение Stripes." ::msgcat::mcset ru "This plugin paints backgrounds of\ even and odd messages in chat windows with different colors." \ "Это раÑширение раÑкрашивает фон чётных и нечётных Ñообщений\ в окнах разговоров разными цветами." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/stripes/msgs/uk.msg000064400000000000000000000011141500237002100172770ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Stripes Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Whether the Stripes plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Stripes." ::msgcat::mcset uk "This plugin paints backgrounds of\ even and odd messages in chat windows with different colors." \ "Це Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ñ„Ð°Ñ€Ð±ÑƒÑ” фон парних Ñ– непарних повідомлень\ у вікнах розмов у різні кольори." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/stripes/stripes.tcl000064400000000000000000000061001500237002100173740ustar00nobodynobody# stripes.tcl -- # # "Stripes" chat plugin for Tkabber -- colorizes background of # whole messages in chat windows. # # Author: Konstantin Khomoutov # # See license.terms for the terms of distribution. # See README for usage details. # Color for odd and even messages can be tuned separately # using the Tk option database (or XRDB) like this: # option add *Chat.oddBackground gray77 # option add *Chat.evenBackground gray84 package require msgcat namespace eval stripes { variable state ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered stripes]} { ::plugins::register stripes \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc \ "Whether the Stripes plugin is loaded."]\n[::msgcat::mc \ "This plugin paints backgrounds of even and odd messages\ in chat windows with different colors."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } } proc stripes::load {} { hook::add open_chat_post_hook [namespace current]::setup_chat_window hook::add close_chat_post_hook [namespace current]::cleanup_state hook::add draw_message_post_hook [namespace current]::on_message_drawn foreach chatid [chat::opened] { setup_chat_window $chatid ? } } proc stripes::unload {} { foreach chatid [chat::opened] { cleanup_chat_window $chatid } hook::remove open_chat_post_hook [namespace current]::setup_chat_window hook::remove close_chat_post_hook [namespace current]::cleanup_state hook::remove draw_message_post_hook [namespace current]::on_message_drawn } proc stripes::setup_chat_window {chatid type} { set cw [::chat::chat_win $chatid] set mw [::chat::winid $chatid] set bgodd [option get $mw oddBackground Chat] if {$bgodd != ""} { $cw tag configure odd -background $bgodd $cw tag lower odd } set bgeven [option get $mw evenBackground Chat] if {$bgeven != ""} { $cw tag configure even -background $bgeven $cw tag lower even } variable state set state($chatid,last) [$cw index {end - 1 char}] set state($chatid,tag) odd } proc stripes::cleanup_state {chatid} { variable state unset state($chatid,last) unset state($chatid,tag) } proc stripes::cleanup_chat_window {chatid} { set cw [::chat::chat_win $chatid] $cw tag delete odd even cleanup_state $chatid } proc stripes::on_message_drawn {chatid from type body x} { if {![chat::is_opened $chatid]} return variable state upvar 0 state($chatid,last) last upvar 0 state($chatid,tag) tag set cw [::chat::chat_win $chatid] set now [$cw index {end - 1 char}] if {[$cw compare $last < $now]} { $cw tag add $tag $last $now if {[string equal $tag even]} { set tag odd } else { set tag even } } set last $now } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/tclchat000075500000000000000000000000001500237002100150545ustar00nobodynobodytkabber-plugins/tclchat/msgs000075500000000000000000000000001500237002100160255ustar00nobodynobodytkabber-plugins/tclchat/msgs/es.msg000064400000000000000000000047271500237002100172350ustar00nobodynobody# es.msg -- # # Spanish messages for the Tclchat Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "%s has changed nick to %s in the IRC channel, but %s is\ already in Jabber room" "%s se ha cambiado el apodo a %s en el canal\ de IRC, pero %s ya está en la sala de charla" ::msgcat::mcset es "%s has changed nick to %s in the IRC channel, but %s is\ still in Jabber room and %s is already in Jabber room" "%s se ha\ cambiado el apodo a %s en el canal de IRC, but %s is still in Jabber\ room and %s is already in Jabber room" ::msgcat::mcset es "%s has changed nick to %s in the IRC channel, but %s is\ still in Jabber room" "%s se ha cambiado el apodo a %s en el canal\ de IRC, but %s is still in Jabber room" ::msgcat::mcset es "%s has joined IRC channel, but %s is already in Jabber\ room" "%s ha entrado en el canal de IRC, pero %s ya está en la sala\ Jabber" ::msgcat::mcset es "%s has joined IRC channel, but he/she is already in\ Jabber room" "%s ha entrado en el canal de IRC, pero ya está en la\ sala de charla" ::msgcat::mcset es "%s has left IRC channel, but %s is still in Jabber\ room" "%s ha salido del canal de IRC, pero %s aún está en la\ sala Jabber " ::msgcat::mcset es "JID of Tclers' chat." "JID de la sala de Tclers." ::msgcat::mcset es "Nickname of Tclers' chat bridge to IRC channel. Groupchat\ messages from this participant are treated specially, replacing his\ nickname by corresponding IRC user nickname." "Apodo del puente de\ la sala Tclers al canal IRC. Los mensajes de charla de este\ participante se tratan de forma especial, reemplazando su apodo con\ el correspondiente del usuario de IRC." ::msgcat::mcset es "Plugins options." "Opciones de plugin." ::msgcat::mcset es "Real JID of Tclers' chat bridge to IRC channel. If set\ to nonempty string, the list of IRC users will be requested before\ entering the conference room." "JID real del puente entre la sala\ de Tclers y el canal de IRC. Si se pone la palabra vacía, se pedirá\ la lista de usuarios IRC antes de entrar en la sala de charla." ::msgcat::mcset es "Tclchat plugin options." "Opciones de plugin Tclchat." ::msgcat::mcset es "Use TkChat embedded colors." \ "Usar colores embebidos TkChat." ::msgcat::mcset es "Whether the Tclchat plugin is loaded." \ "Cargar el plugin Tclchat." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/tclchat/msgs/ru.msg000064400000000000000000000062431500237002100172470ustar00nobodynobody# ru.msg -- # # Russian messages for the Tclchat Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "%s has changed nick to %s in the IRC channel, but %s is\ already in Jabber room" "%s Ñменил пÑевдоним на %s в канале IRC, но\ %s уже приÑутÑтвует в конференции Jabber" ::msgcat::mcset ru "%s has changed nick to %s in the IRC channel, but %s is\ still in Jabber room" "%s Ñменил пÑевдоним на %s в канале IRC, но %s\ вÑе еще приÑутÑтвует в конференции Jabber" ::msgcat::mcset ru "%s has changed nick to %s in the IRC channel, but %s is\ still in Jabber room and %s is already in Jabber room" "%s Ñменил\ пÑевдоним на %s в канале IRC, но и %s вÑе еще приÑутÑтвует, и %s уже\ приÑутÑтвует в конференции Jabber" ::msgcat::mcset ru "%s has joined IRC channel, but %s is already in Jabber\ room" "%s приÑоединилÑÑ Ðº каналу IRC, но %s уже приÑутÑтвует в\ конференции Jabber" ::msgcat::mcset ru "%s has joined IRC channel, but he/she is already in Jabber\ room" "%s приÑоединилÑÑ Ðº каналу IRC, но он уже приÑутÑтвует в\ конференции Jabber" ::msgcat::mcset ru "%s has left IRC channel, but %s is still in Jabber room" \ "%s ушел Ñ ÐºÐ°Ð½Ð°Ð»Ð° IRC, но %s вÑе еще приÑутÑтвует в конференции Jabber" ::msgcat::mcset ru "JID of Tclers' chat." "Jabber ID чата Tcler'ов" ::msgcat::mcset ru "Nickname of Tclers' chat bridge to IRC channel. Groupchat\ messages from this participant are treated specially, replacing his\ nickname by corresponding IRC user nickname." "ПÑевдоним моÑта из чата\ Tcler'ов в канал IRC. Ð¡Ð¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð² конференцию от Ñтого учаÑтника\ обрабатываютÑÑ Ð¾Ñобым образом. Ð’ них подменÑетÑÑ Ð¿Ñевдоним на\ ÑоответÑтвующий пÑевдоним из канала IRC." ::msgcat::mcset ru "Real JID of Tclers' chat bridge to IRC channel. If set to\ nonempty string, the list of IRC users will be requested before\ entering the conference room." "Реальный Jabber ID моÑта из чата\ Tcler'ов в канал IRC. ЕÑли параметр непуÑÑ‚, то во Ð²Ñ€ÐµÐ¼Ñ Ð²Ñ…Ð¾Ð´Ð° в\ конференцию у него запрашиваетÑÑ ÑпиÑок поÑетителей канала IRC." ::msgcat::mcset ru "Plugins options." "ÐаÑтройки раÑширений." ::msgcat::mcset ru "Tclchat plugin options." "ÐаÑтройки раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Tclchat" ::msgcat::mcset ru "Use TkChat embedded colors." \ "ИÑпользовать вÑтроенные цвета TkChat." ::msgcat::mcset ru "Whether the Tclchat plugin is loaded." \ "Загружено ли раÑширение Tclchat." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/tclchat/msgs/uk.msg000064400000000000000000000062351500237002100172410ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Tclchat Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "%s has changed nick to %s in the IRC channel, but %s is\ already in Jabber room" "%s змінив пÑевдонім на %s у каналі IRC, але\ %s вже Ñ” наÑвний в конференції Jabber" ::msgcat::mcset uk "%s has changed nick to %s in the IRC channel, but %s is\ still in Jabber room" "%s змінив пÑевдонім у каналі IRC, але %s вÑе\ ще Ñ” наÑвний у конференції Jabber" ::msgcat::mcset uk "%s has changed nick to %s in the IRC channel, but %s is\ still in Jabber room and %s is already in Jabber room" "%s змінив\ пÑевдонім на %s у каналі IRC, але Ñ– %s вÑе ще Ñ” наÑвний, Ñ– %s вже\ Ñ” наÑвний у конференції Jabber" ::msgcat::mcset uk "%s has joined IRC channel, but %s is already in Jabber\ room" "%s приєднавÑÑ Ð´Ð¾ каналу IRC, але %s вже Ñ” наÑвний в\ конференції Jabber" ::msgcat::mcset uk "%s has joined IRC channel, but he/she is already in Jabber\ room" "%s приєднавÑÑ Ð´Ð¾ каналу IRC, але він уже Ñ” наÑвний у\ конференції Jabber" ::msgcat::mcset uk "%s has left IRC channel, but %s is still in Jabber room" \ "%s вийшов з каналу IRC, але %s вÑе ще Ñ” наÑвний в конференції Jabber" ::msgcat::mcset uk "JID of Tclers' chat." "Jabber ID чату Tcler'ів" ::msgcat::mcset uk "Nickname of Tclers' chat bridge to IRC channel. Groupchat\ messages from this participant are treated specially, replacing his\ nickname by corresponding IRC user nickname." "ПÑевдонім моÑту з чата\ Tcler'ів до канаду IRC. ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð² конференцію від цього учаÑтника\ оброблÑютьÑÑ Ñпеціальним чином. Ð’ них підмінÑетьÑÑ Ð¿Ñевдонім на\ відповідний пÑевдонім з каналу IRC." ::msgcat::mcset uk "Real JID of Tclers' chat bridge to IRC channel. If set to\ nonempty string, the list of IRC users will be requested before\ entering the conference room." "Реальний JID моÑту між чатом Tcler'ів\ та каналом IRC. Якщо цей параметр непуÑтий, то під Ñ‡Ð°Ñ Ð·Ð°Ñ…Ð¾Ð´Ñƒ в\ конференцію у нього запитуєтьÑÑ ÑпиÑок відвідувачів каналу IRC." ::msgcat::mcset uk "Plugins options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½ÑŒ." ::msgcat::mcset uk "Tclchat plugin options." "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Tclchat" ::msgcat::mcset uk "Use TkChat embedded colors." \ "ВикориÑтовувати вбудовані кольори TkChat." ::msgcat::mcset uk "Whether the Tclchat plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Tclchat." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/tclchat/tclchat.tcl000064400000000000000000000315241500237002100172660ustar00nobodynobody# tclchat.tcl -- # # This file is a part of implementation of Tkabber's interface to # the Tcler's chat. Inject the history from the tclers chat logs # into the current chat window. This hook only activates if you open # a groupchat to a site that we know is linked to the tclers chat. # ie: tach.tclers.tk or the irc channel. # # Copyright (C) 2004 Pat Thoyts # Copyright (C) 2007-2009 Sergei Golovan package require msgcat namespace eval tclchat { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered tclchat]} { ::plugins::register tclchat \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Tclchat\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } custom::defgroup Plugins [::msgcat::mc "Plugins options."] \ -group Tkabber custom::defgroup Tclchat [::msgcat::mc "Tclchat plugin options."] \ -group Plugins custom::defvar options(use_tkchat_colors) 1 \ [::msgcat::mc "Use TkChat embedded colors."] \ -group Chat -group Tclchat -type boolean } # Load in the additional files that are part of the tclchat plugin. # source [file join [file dirname [info script]] tclchat_messages.tcl] source [file join [file dirname [info script]] tclchat_commands.tcl] package require http 2 proc tclchat::load {} { load_commands load_messages hook::add finload_hook [namespace current]::on_init 30 hook::add open_chat_post_hook [namespace current]::on_open_chat hook::add chat_send_message_xlist_hook [namespace current]::add_color on_init } proc tclchat::unload {} { catch { set menu [.mainframe getmenu plugins] set idx [$menu index [msgcat::mc "Tkchat colors"]] $menu delete $idx } unload_commands unload_messages hook::remove finload_hook [namespace current]::on_init 30 hook::remove open_chat_post_hook [namespace current]::on_open_chat hook::remove chat_send_message_xlist_hook [namespace current]::add_color } proc tclchat::on_init {} { global tcl_platform global loginconf variable Options variable urlid 0 catch { set menu [.mainframe getmenu plugins] $menu add checkbutton -label [msgcat::mc "Tkchat colors"] \ -underline 0 \ -variable [namespace current]::options(use_tkchat_colors) } array set Options { HistoryLines 0 url "http://tclers.tk/conferences/tcl" sel "/?pattern=*.tcl" RE {.*\s([0-9]+) bytes} } } proc tclchat::on_open_chat {chatid type} { variable Options if {[string equal $type "groupchat"]} { switch -glob -- [set mucjid [chat::get_jid $chatid]] { *@tach.tclers.tk { set muc [lindex [split $mucjid @] 0] set Options(url) "http://tclers.tk/conferences/$muc" after 400 [LoadHistory $chatid] } } } set W [chat::chat_win $chatid] $W tag configure URL -underline 1 $W tag bind URL [list $W configure -cursor hand2] $W tag bind URL [list $W configure -cursor xterm] return } # ------------------------------------------------------------------------- # Check the HTTP response for redirecting URLs. - PT proc tclchat::checkForRedirection {tok} { set ncode [::http::ncode $tok] if {[expr {$ncode == 302 || $ncode == 301 || $ncode == 307}]} { upvar \#0 $tok state array set meta $state(meta) if {[info exists meta(Location)]} { return $meta(Location) } } return {} } proc tclchat::FetchHistoryIndex {url} { variable Options set loglist {} set tok [::http::geturl ${url}$Options(sel)] switch -- [::http::status $tok] { ok { if {[::http::ncode $tok] >= 500} { debugmsg tclchat "error [::http::code $tok]" } elseif {[http::ncode $tok] >= 400} { debugmsg tclchat "error [::http::code $tok]" } else { if {[set _url [checkForRedirection $tok]] != {}} { regsub {/\?M=D} $_url {} $_url set loglist [FetchHistoryIndex $_url] } else { foreach line [split [::http::data $tok] \n] { if { [regexp -- $Options(RE) $line -> logname size] } { set logname [string map {"%2d" -} $logname] set size [expr {$size / 1024}]k set loglist [linsert $loglist 0 $logname $size] } } } } } reset { debugmsg tclchat "reset" } timeout { debugmsg tclchat "timeout" } error { debugmsg tclchat "error [::http::error $tok]" } default { debugmsg tclchat "????? [::http::error $tok]" } } ::http::cleanup $tok return $loglist } proc tclchat::ParseHistLog {log {reverse 0}} { variable Options set retList {} set MsgRE \ {^\s*(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun).+?\[([^\]]+)\]\s+([^:]+):?\s*(.*)$} set ircRE {ircbridge: \*\*\* (.+) (.+)$} set TimeRE {^(.+?)\s+(.+?)\s+(\d{1,2})\s+(\d\d:\d\d:\d\d)\s+(\d{4})} set logtime 0 # fetch log set url "$Options(url)/$log" debugmsg tclchat "fetch log \"$url\"" set tok [::http::geturl $url] debugmsg tclchat "status [::http::status $tok] [::http::code $tok]" switch -- [::http::status $tok] { ok { # Tcl Jabber logs set I [interp create -safe] interp alias $I m {} [namespace current]::ParseLogMsg if { $reverse } { set histTmp [set [namespace current]::History] set Options(History) {} } $I eval [::http::data $tok] if { $reverse } { set Options(History) [concat $Options(History) $histTmp] } } reset { debugmsg tclchat "reset" } timeout { debugmsg tclchat "timeout" } error { debugmsg tclchat "error [::http::error $tok]" } default { debugmsg tclchat "????? [::http::error $tok]" } } ::http::cleanup $tok return $retList } # this called on first logon and after a purge # so not bothering to backgound it proc tclchat::LoadHistory {chatid} { variable Options set FinalList {} if {$Options(HistoryLines) == 0} { # don't even bother return } elseif {$Options(HistoryLines) < 0} { set loglist [FetchHistoryIndex $Options(url)] if {[set len [llength $loglist]] > 0} { if {$len > 18} { set loglist [lrange $loglist 0 17] } # ask user set t [Toplevel .histQ -class dialog] wm withdraw $t wm transient $t wm protocol $t WM_DELETE_WINDOW { } wm title $t "Load History From Logs" grid [Label $t.lbl \ -text "Please select how far back you want to load:"] \ -sticky ew -pady 1.25m set i 0 variable HistQueryNum [expr {[llength $loglist] / 2}] set loglist [lpairreverse $loglist] foreach {l s} $loglist { grid [Radiobutton $t.rb$i -text "$l $s" \ -val $i -var [namespace current]::HistQueryNum] \ -sticky w -padx 4m -pady 0 incr i } grid [Radiobutton $t.rb$i -text "None" \ -val $i -var [namespace current]::HistQueryNum] \ -sticky w -padx 4m -pady 0 grid [Button $t.ok -text Ok -width 8 \ -command [list destroy $t] -default active] \ -sticky e -padx 1.25m -pady 2m grid columnconfigure $t 0 -weight 1 bind $t [list $t.ok invoke] catch {::tk::PlaceWindow $t widget .} wm deiconify $t tkwait visibility $t focus $t.ok grab $t tkwait window $t foreach {l s} [lrange $loglist [expr {$HistQueryNum * 2}] end] { debugmsg tclchat "loading history \"$l\" (${s}k)" if {[catch {ParseHistLog $l} new]} { debugmsg tclchat "ERROR: $new" } } } } else { set loglist [FetchHistoryIndex $Options(url)] # go thru logs in reverse until N lines loaded foreach {log size} $loglist { # fetch log if {[catch {ParseHistLog $log} new]} { debugmsg tclchat "ERROR: $new" } if {[llength $Options(History)] >= $Options(HistoryLines)} { break } } } set w [chat::chat_win $chatid] # Set a mark for the history insertion point. if {[lsearch -exact [$w mark names] HISTORY] == -1} { $w config -state normal $w insert 0.0 \ "+++++++++++++++ Loading History +++++++++++++\n" $w mark set HISTORY 0.0 $w config -state disabled } LoadHistoryLines $chatid $w see end } proc tclchat::LoadHistoryLines {chatid} { variable Options set w [chat::chat_win $chatid] set state [$w cget -state] $w configure -state normal if {![info exists Options(History)]} {set Options(History) {}} set count 0 foreach {time nick msg} $Options(History) { #$w insert HISTORY "<$nick> $msg\n" [list they NICK-$nick] Insert $w $nick $msg $time incr count 3 if {$count > 100} { break } } $w see end set Options(History) [lrange $Options(History) $count end] if {$Options(History) == {}} { $w configure -state normal $w delete "HISTORY + 1 char" "HISTORY + 1 line" $w insert "HISTORY + 1 char" \ "+++++++++++++++ End Of History +++++++++++++\n" } else { after idle [list [namespace origin LoadHistoryLines] $chatid] } $w configure -state $state } proc tclchat::gotourl {url} { debugmsg tclchat "goto url \"$url\"" browseurl $url } proc tclchat::Insert {w nick msg time} { variable urlid if {[info exists ::plugins::options(delayed_timestamp_format)]} { set fmt $::plugins::options(delayed_timestamp_format) } else { set fmt "\[%m/%d %R\]" } if {[string equal $nick "ijchain"]} { set nick "" regexp {^<(\w+)> (.*)$} $msg -> nick msg } set nk "<$nick>" if {[string length $nick] < 1} {set nk "*"} $w insert HISTORY \ [clock format $time -format $fmt] {} \ "$nk " [list they NICK-$nick] while {[regexp -nocase -- {^(.*?)(.*?)(.*?)$} \ $msg -> pre url link post]} { if {[string length $pre]} { $w insert HISTORY $pre [list they NICK-$nick] } set id URL-[incr urlid] $w insert HISTORY $link [list they NICK-$nick URL $id] $w tag bind $id <1> [list [namespace origin gotourl] $link] set msg $post } $w insert HISTORY "$msg\n" [list they NICK-$nick] } proc tclchat::ParseLogMsg { when nick msg {opts ""} args } { variable Options set Options(HaveHistory) 1 set time [clock scan ${when} -gmt 1] lappend Options(History) $time $nick $msg if {[llength $args] > 0} { debugmsg tclchat "WARNING: Log incorrect log format." } #debugmsg tclchat "[clock format $time] $nick :: $msg $opts $args" } proc tclchat::lpairreverse {L} { set res {} set i [llength $L] while {$i} { lappend res [lindex $L [incr i -2]] [lindex $L [incr i]] incr i -1 } set res } proc tclchat::color_to_hex {color} { lassign [winfo rgb . $color] r g b return [format "%02x%02x%02x" \ [expr {$r % 256}] [expr {$g % 256}] [expr {$b % 256}]] } # tclchat::add_color -- # # In our tclers groupchat window, we want to add additional 'x' # elements to add our own color specification. proc tclchat::add_color {varname chatid user id body type} { variable options upvar 2 $varname var set jid [chat::get_jid $chatid] if {$options(use_tkchat_colors) && \ $type eq "groupchat" && \ [string match "*@tach.tclers.tk" $jid]} { set color [plugins::nickcolors::get_color $user] if {[string length $color] > 0} { lappend var [::xmpp::xml::create x \ -xmlns urn:tkchat:chat \ -attrs [list color [color_to_hex $color]]] } } } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/tclchat/tclchat_commands.tcl000064400000000000000000000055341500237002100211510ustar00nobodynobody# tclchat_commands.tcl -- # # This file is a part of implementation of Tkabber's interface to # the Tcler's chat. It adds a few IRC-like commands. # # Copyright (C) 2004 Pat Thoyts # Copyright (C) 2007-2009 Sergei Golovan namespace eval tclchat {} proc tclchat::load_commands {} { hook::add chat_send_message_hook \ [namespace current]::send_commands 50 hook::add generate_completions_hook \ [namespace current]::command_completion } proc tclchat::unload_commands {} { hook::remove chat_send_message_hook \ [namespace current]::send_commands 50 hook::remove generate_completions_hook \ [namespace current]::command_completion } proc tclchat::command_completion {chatid compsvar wordstart line} { upvar 0 $compsvar comps if {!$wordstart} { lappend comps {/google } lappend comps {/googlefight } lappend comps {/tip } lappend comps {/bug } } } proc tclchat::send_commands {chatid user body type} { if {$type == "groupchat"} { set body [string trim $body] if {[string match /* $body]} { switch -regexp -- $body { {^/google\s} { set body [string range $body 8 end] debugmsg tclchat "google \"$body\"" if {[string length $body] > 0} { set q {http://www.google.com/search?ie=UTF-8&oe=UTF-8&} append q [::http::formatQuery q $body] browseurl $q return stop } } {^/googlefight\s} { googlefight $body return stop } {^/(urn:)?tip[: ]\d+} { if {[regexp {(?:urn:)?tip[: ](\d+)} $body -> tip]} { browseurl http://tip.tcl.tk/$tip return stop } } {^/bug[: ]} { dobug [split $body ": "] return stop } } } } } proc tclchat::dobug {msg} { # msg should be of form: ^/bug[: ]id if {[llength $msg] != 2} { debugmsg tclchat "wrong # args: must be /bug id" return } set id [lindex $msg end] set url "http://sourceforge.net/support/tracker.php?aid=$id" browseurl $url } proc tclchat::googlefight {msg} { set q {http://www.googlefight.com/cgi-bin/compare.pl} set n 1 foreach word [lrange $msg 1 end] { append q [expr {($n == 1) ? "?" : "&"}] append q q$n=$word incr n } if {[string match fr_* [msgcat::mclocale]]} { append q &langue=fr } else { append q &langue=us } browseurl $q } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/tclchat/tclchat_messages.tcl000064400000000000000000000316251500237002100211570ustar00nobodynobody# tclchat_messages.tcl -- # # This file is a part of implementation of Tkabber's interface to # the Tcler's chat. It does the same job and draw_normal_message # but is capable of filtering the extra nicks generated by the # various bridges used in the tclers chats. Namely ircbridge and # ijbridge. # # This plugin processes messages from ijbridge in Tclers' chat only # (tcl@tach.tclers.tk) # # Includes support for nick_colors.tcl (now incorporated into tkabber # proper) and also supports the tclers chat embedded color. # # Originally by Steve Redler # Modified by Pat Thoyts # Rewritten by Sergei Golovan namespace eval tclchat { custom::defvar options(tclers_chat_jid) "tcl@tach.tclers.tk" \ [::msgcat::mc "JID of Tclers' chat."] \ -group Tclchat -type string custom::defvar options(bridge_jid) "ijchain@all.tclers.tk/ijbridge" \ [::msgcat::mc "Real JID of Tclers' chat bridge to IRC channel.\ If set to nonempty string, the list of IRC users\ will be requested before entering the conference\ room."] \ -group Tclchat -type string custom::defvar options(bridge_nickname) "ijchain" \ [::msgcat::mc "Nickname of Tclers' chat bridge to IRC channel.\ Groupchat messages from this participant\ are treated specially, replacing his nickname by\ corresponding IRC user nickname."] \ -group Tclchat -type string } proc tclchat::load_messages {} { hook::add presence_xlist_hook [namespace current]::request_users_list hook::add process_message_hook [namespace current]::fill_irc_users 30 hook::add process_message_hook \ [namespace current]::process_ijchain_message 30 hook::add draw_message_hook [namespace current]::check_color 62 hook::add join_group_hook [namespace current]::touch_connect } proc tclchat::unload_messages {} { hook::remove presence_xlist_hook [namespace current]::request_users_list hook::remove process_message_hook [namespace current]::fill_irc_users 30 hook::remove process_message_hook \ [namespace current]::process_ijchain_message 30 hook::remove draw_message_hook [namespace current]::check_color 62 hook::remove join_group_hook [namespace current]::touch_connect } # VERY DIRTY HACK. # Tkabber doesn't have appropriate hook, so using inappropriate proc tclchat::request_users_list {vxlist xlib stat} { upvar 3 group group variable irc_users variable options # HACK: Use the fact that joining groupchat calls presence_args # which in turn runs presence_xlist_hook if {![info exists group]} return # Don't request IRC users list if bridge JID is empty if {$options(bridge_jid) eq ""} return # If the presence doesn't go to Tclers' chat, do nothing if {$group ne $options(tclers_chat_jid)} return set chatid [chat::chatid $xlib $group] # If the chat is disconnected then we're trying to connect. Then it's # time to request IRC users list if {[chat::is_opened $chatid] && [chat::is_disconnected $chatid]} { # Setting the flag to show that the answer is to be processed # programmatically set irc_users($xlib) {} message::send_msg $xlib $options(bridge_jid) \ -type chat \ -body names } } proc tclchat::fill_irc_users \ {xlib from id type is_subject subject body err thread priority x} { variable irc_users variable options # Don't process message if we didn't ask the list or this message isn't # from bridge JID if {![info exists irc_users($xlib)]} return if {$from ne $options(bridge_jid)} return unset irc_users($xlib) after idle [list [namespace current]::inject_irc_users $xlib $body] return stop } proc tclchat::touch_connect {chatid nick} { variable connect set connect($chatid) {} } proc tclchat::update_presence {xlib jid type xmlElements} { client:presence $xlib $jid $type $xmlElements ::xmpp::presence::process $xlib $jid $type $xmlElements } proc tclchat::inject_irc_users {xlib users args} { variable irc_users variable connect variable options set group $options(tclers_chat_jid) set chatid [chat::chatid $xlib $group] trace remove variable [namespace current]::connect($chatid) write \ [list [namespace current]::inject_irc_users $xlib $users] if {![chat::is_opened $chatid]} { catch {unset connect($chatid)} return } # If we're still disconnected, schedule the IRC users injection after # a change in chat status if {![info exists connect($chatid)]} { trace add variable [namespace current]::connect($chatid) write \ [list [namespace current]::inject_irc_users $xlib $users] return } unset connect($chatid) set px [::xmpp::xml::create x \ -xmlns $::NS(muc#user) \ -subelement [::xmpp::xml::create item \ -attrs [list affiliation none]]] foreach nick $users { set nickid $group/$nick if {![jid_in_chat $chatid $nickid]} { update_presence $xlib $nickid available [list $px] } else { client:message $xlib $group groupchat {} \ -body [::msgcat::mc "%s has joined IRC channel,\ but he/she is already in\ Jabber room" $nick] } } } ############################################################################### proc tclchat::jid_in_chat {chatid jid} { set xlib [chat::get_xlib $chatid] set nick [::xmpp::jid::resource $jid] expr {[lsearch -exact [muc::roster $chatid] $nick] >= 0 && \ [muc::get_role $xlib $jid] ne ""} } proc tclchat::process_ijchain_message \ {xlib from id type is_subject subject body err thread priority x} { variable options # Filter groupchat messages only if {$type ne "groupchat"} return set group [::xmpp::jid::stripResource $from] set chatid [chat::chatid $xlib $group] # Filter messages from tcl@tach.tclers.tk only if {$group ne $options(tclers_chat_jid)} return set nick [chat::get_nick $xlib $from $type] # Filter messages from ijchain only if {$nick != $options(bridge_nickname)} return set lbody [split $body " "] # Update userlist on "*** nick leaves" and "*** nick joins" messages # Update userlist on "* nick left" and "* nick entered" messages if {[llength $lbody] == 3 && [lindex $lbody 0] eq "***"} { set nick [lindex $lbody 1] set nickid $group/$nick switch -- [lindex $lbody 2] { joins { debugmsg chat "Handle \"$nick\" joined message." set px [::xmpp::xml::create x \ -xmlns $::NS(muc#user) \ -subelement [::xmpp::xml::create item \ -attrs [list affiliation none]]] if {![jid_in_chat $chatid $nickid]} { update_presence $xlib $nickid available [list $px] } else { client:message $xlib $group $type {} \ -body [::msgcat::mc "%s has joined IRC\ channel, but %s is\ already in Jabber\ room" \ $nick $nick] } } leaves { debugmsg chat "Handle \"$nick\" left message." if {![jid_in_chat $chatid $nickid]} { update_presence $xlib $nickid unavailable {} } else { client:message $xlib $group $type {} \ -body [::msgcat::mc "%s has left IRC\ channel, but %s is\ still in Jabber room" \ $nick $nick] } } default { return } } return stop } if {[llength $lbody] == 7 && [lindex $lbody 0] eq "***"} { set from_nick [lindex $lbody 1] set to_nick [lindex $lbody 6] if {[join [lrange $lbody 2 5] " "] eq "is now known as"} { set ux [::xmpp::xml::create x \ -xmlns $::NS(muc#user) \ -subelement [::xmpp::xml::create item \ -attrs [list affiliation none \ nick $to_nick]] \ -subelement [::xmpp::xml::create status \ -attrs [list code 303]]] set px [::xmpp::xml::create x \ -xmlns $::NS(muc#user) \ -subelement [::xmpp::xml::create item \ -attrs [list affiliation none]]] set from_nickid $group/$from_nick set to_nickid $group/$to_nick if {![jid_in_chat $chatid $from_nickid]} { if {![jid_in_chat $chatid $to_nickid]} { update_presence $xlib $from_nickid unavailable [list $ux] update_presence $xlib $to_nickid available [list $px] } else { update_presence $xlib $from_nickid unavailable {} client:message $xlib $group $type {} \ -body [::msgcat::mc "%s has changed nick\ to %s in the IRC\ channel, but %s is\ already in Jabber\ room" \ $from_nick $to_nick $to_nick] } } else { if {![jid_in_chat $chatid $to_nickid]} { client:message $xlib $group $type {} \ -body [::msgcat::mc "%s has changed nick to\ %s in the IRC channel,\ but %s is still in\ Jabber room" \ $from_nick $to_nick $from_nick] update_presence $xlib $to_nickid available [list $px] } else { client:message $xlib $group $type {} \ -body [::msgcat::mc "%s has changed nick to\ %s in the IRC channel,\ but %s is still in\ Jabber room and %s is\ already in Jabber\ room" \ $from_nick $to_nick \ $from_nick $to_nick] } } return stop } return } # Filter out nicks if {[regexp {^<(\S+)>\s+(.*)} $body -> nick body]} { set nickid $group/$nick client:message $xlib $nickid $type {} -body $body return stop } elseif {[regexp {^\*\s+(\S+)\s+(.*)} $body -> nick body]} { set nickid $group/$nick client:message $xlib $nickid $type {} -body "/me $body" return stop } return } # TODO: Use of tkchat colors # tclchat::check_color -- # # The tclers chat client 'tkchat' likes to embed the users choice of # color into the 'x' elements of each jabber message. In this procedure # we check that our idea of their color agrees. If not we'll update # and refresh. proc tclchat::check_color {chatid from type body x} { set xlib [chat::get_xlib $chatid] set nick [chat::get_nick $xlib $from $type] foreach node $x { ::xmpp::xml::split $node tag xmlns attrs cdata subels if {$xmlns == "urn:tkchat:chat"} { set color [string trim [::xmpp::xml::getAttr $attrs "color"] "#"] if {[string length $color] > 0} { set orig [::plugins::nickcolors::get_color $nick] debugmsg chat "Checking color for $nick ('$orig' eq '#$color')" if {"$orig" != "#$color"} { ::plugins::nickcolors::set_color $chatid $nick "#$color" } } } } } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/tkabber-khim000075500000000000000000000000001500237002100157725ustar00nobodynobodytkabber-plugins/tkabber-khim/ChangeLog000064400000000000000000000025711500237002100176300ustar00nobodynobody2006-12-17 Sergei Golovan * Bumped khim version number to ensure its loading. 2006-12-15 Sergei Golovan * Changed colors of Unicode charmap. This change looks like a hack, so it's not for proposing uopstream. 2006-12-13 Sergei Golovan * Removed autoscroll package and reference to it from KHIM to make plugin slightly lighter. 2006-12-11 Konstantin Khomoutov * Fixed KHIM bug with attempting to re-create the Unicode map window on simultaneous Compose keypresses. * Added translateable title to the KHIM help window. * Several typos fixed ru.msg of KHIM (thanks to Serge Yudin). * Added KHIM help window title string to en.msg and ru.msg. * In tkabber-khim.tcl: * Fixed comment; * Added removal of one transient variable; * Added cleanup of the plugin namespace on failed khim loading attempt. * Misc indenting fix in INSTALL. * Misc fix in khim/ru.msg. 2006-12-10 Konstantin Khomoutov * Fixed issues with mclocale. * Added loading of message catalogs. * Added Russian translation of the plugin interface. * Written INSTALL file, added ChangeLog file. * Added tklib_license.terms file (for khim and autoscroll packages). 2006-12-09 Konstantin Khomoutov * Initial (preview) release. tkabber-plugins/tkabber-khim/INSTALL000064400000000000000000000033641500237002100171100ustar00nobodynobodyAs usually, copy this directory to $HOME/.tkabber/plugins (on UNIX), to %APPDATA%\Tkabber\plugins (on Windows), or to $HOME/Library/Application Support/Tkabber (on MacOS X) directory. Restart Tkabber, then navigate to the "Services" -> "Plugins" menu and activate the "KHIM Options..." menu entry -- the KHIM configuration dialog will appear. Hit the "Help..." button and read the help carefully. Normally, this plugin is bundled with the original "khim" and "autoscroll" Tcl packages, which are parts of the "tklib" library [1]. If these packages are missing, you most probably need to get tklib installed in your system. The khim package is not yet currently in the official "stable" flavor of the tklib [2], so you generally have two options: 1) Recent Active State's distros come with the "CVS HEAD state" tklib, so if you have such a distro, you most probably have khim, too. 2) Fetch and install tklib from CVS: * Log in as anonymous with the empty password (just hit Enter): cvs -d :pserver:anonymous@tcllib.cvs.sourceforge.net/cvsroot/tcllib/ login * Fetch the sources (the "tklib" directory under the current one will be created): cvs -z3 -d :pserver:anonymous@tcllib.cvs.sourceforge.net/cvsroot/tcllib/ \ co tklib * Log out: cvs -d :pserver:anonymous@tcllib.cvs.sourceforge.net/cvsroot/tcllib/ \ logout * Install: cd tklib ./configure --with-tcl=/usr/bin --prefix=/usr make test su make install (Leave out "su" if not on Unix. "make test" step is optional, of course). * Alternatively, you can just grab "khim" and "autoscroll" packages and place them into the root directory of this plugin. [1] http://tcllib.sourceforge.net/ [2] This is written on 09-Dec-2006. tkabber-plugins/tkabber-khim/VERSION000064400000000000000000000000371500237002100171210ustar00nobodynobodyVersion: 1.2 Date: 11-Dec-2006 tkabber-plugins/tkabber-khim/khim000075500000000000000000000000001500237002100167225ustar00nobodynobodytkabber-plugins/tkabber-khim/khim/ROOT.msg000064400000000000000000000055661500237002100203100ustar00nobodynobody# ROOT.msg -- # # Default English-language messages for KHIM # # Copyright (c) 2006 by Kevin B. Kenny. All rights reserved. # # Refer to the file "license.terms" for the terms and conditions of # use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES. # # $Id: ROOT.msg,v 1.2 2006/09/05 18:52:22 kennykb Exp $ # $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/ROOT.msg,v $ # #---------------------------------------------------------------------- # Make sure that help text is available in the root locale. namespace eval ::khim { # If you edit this file, also edit the corresponding text in en.msg, # which is provided for 8.4 compatibility. ::msgcat::mcset {} HELPTEXT { Kevin's Hacky Input Method (KHIM) KHIM allows you to input international characters from a keyboard that doesn't support them. It works independently of any input method that the operating system may supply; it is intended for when you don't have control over your keyboard mapping and still need to input text in other languages. To use KHIM, bring up the KHIM Controls (the way this is done depends on your application) and enable KHIM by checking "Use KHIM". You also need to choose a key on your keyboard that is seldom used, and designate it as the "Compose" key by pressing the button labelled, "Compose key:" then striking the key you wish to designate. Generally speaking, this key should not be the key designated as "Compose" on the keyboard; that key will continue to invoke whatever input method the local operating system supplies. Once KHIM is enabled, you can enter international characters in any widget that is configured to use KHIM by pressing the Compose key followed by a two-character sequence. The listbox in the KHIM controls shows the available sequences. In addition, if you strike the Compose key twice, you get a dialog that allows you to input arbitrary symbols from a Unicode character map. In the map, you can navigate among the characters using either the cursor keys or the mouse, and you can select the current character for insertion by double-clicking it, pressing the space bar, or pressing the Enter (or Return) key. To define a new sequence for use with the Compose key, bring up the KHIM controls, enter the two characters in the "Input key sequence" entry and the desired character to insert into the "Character" entry, and press "Change". (You may copy and paste the character from another application, or use the "Unicode..." button (or press the Compose key twice) to select the character from a map of all available Unicode code points.) To remove a sequence, select it in the listbox and press "Delete". } ::msgcat::mcset {} {SELECT COMPOSE KEY} [string map [list \n\t \n] { Please press the key that you want to use as the "Compose" key. }] } tkabber-plugins/tkabber-khim/khim/cs.msg000064400000000000000000000073171500237002100201260ustar00nobodynobody# cs.msg -- # # Czech-language messages for KHIM # # Copyright (c) 2005 by Kevin B. Kenny. All rights reserved. # Translation by Michal Mestan # # Refer to the file "license.terms" for the terms and conditions of # use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES. # # $Id: cs.msg,v 1.1 2006/12/06 17:28:12 kennykb Exp $ # $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/cs.msg,v $ # #---------------------------------------------------------------------- namespace eval ::khim { ::msgcat::mcset cs HELPTEXT { Kevin's Hacky Input Method (KHIM) KHIM vám umožňuje zadávat mezinárodní znaky vÄetnÄ› tÄ›ch, které na vaší klávesnici nejspou. Pracuje nezávisle na požité vstupní metodÄ› kterou váš operaÄní systém může poskytovat. Je hlavnÄ› urÄen pro případy, kdy nemáte možnost mÄ›nit mapování klávesnice a pÅ™esto potÅ™ebujete zapsat cizojazyÄný text. K nastavení KHIM slouží "Ovládací panel KHIM" (jeho vyvolání je závaislé na konkrétní aplikaci), zde povolte KHIM zaÅ¡krtnutím políÄka "Používat KHIM". Mužete si zde též vybrat klávesu na vaší klávesnici, kterou bude KHIM používat jako "mrtvá" stisknutím talÄítka "Mrtvá klávesa" a poté stisktnutím patÅ™iÄné klávesy. ObecnÄ› lze říci, nemůže to být jakákoliv "mrtvá" klávasa vaší klávesové mapy, jelikož pÅ™i stisknutí je volána vstupní metoda operaÄního systému. Když je KHIM povolen, můžete vkládat mezinárodní znaky v jakémkoliv přípravku, který je nastaven tak, aby používal KHIM stiknutním "mrtvé" klávesy následované posloupností dvou znaků. Seznam v "Ovládacím panelu KHIM" zobrazuje dostupné posloupnosti. Pokud stisknete "mrtvou" klávesu dvakrát, zobrazí se vám dialog, ve kterém můžete vybrat žádaný symbol z unokódové mapy. V mapÄ› se můžete pohybovat kursorovými klávesami, dvojklikem myší, mezerníkem Äi klávesou enter vybraný znak vložíte do textu. Chcete-li další znaky vkládat pomocí mrtvé klávesy, otevÅ™ete "Ovládací panel KHIM" vložte dva znaky do pole "Posloupnost kláves" a požadovaný znak, který chcete vložit do pole "Vkládaný znak" a stisknÄ›tÄ› talÄítko "ZmÄ›nit" (vkládaný znak můžete nakopírovat z jiné aplikace nebo pouÄít talÄítko "Unikód..." (nebo stisknout dvakrát "mrtvou" klávesu) a vybrat znak z unikódové mapy). K odstranÄ›ní klávesové posloupnosti slouží tlaÄítko "Smazat". } ::msgcat::mcset cs {SELECT COMPOSE KEY} [string map [list \n\t \n] { StisknÄ›te klávesu kterou chcete používat jako "mrtvou" klávesu. }] ::msgcat::mcset cs {Apply} "Použít" ::msgcat::mcset cs {Cancel} "ZruÅ¡it" ::msgcat::mcset cs {Change} "ZmÄ›nit" ::msgcat::mcset cs {Character} "Znak" ::msgcat::mcset cs {Compose Key} "Mrtvá klávesa" ::msgcat::mcset cs {Compose key:} "Mrtvá klávesa:" ::msgcat::mcset cs {Composed sequence must be two characters long} \ "Vkládaný znak je vždy Å¡ložen z posloupnosti zdvou nzaků" ::msgcat::mcset cs {Delete} "Smazat" ::msgcat::mcset cs {Help...} "NápovÄ›da..." ::msgcat::mcset cs {Input key sequence} "Zadajete posloupnost kláves" ::msgcat::mcset cs {Insert Character} "Vkládaný znak" ::msgcat::mcset cs {Invalid sequence} "Chybná posloupnost" ::msgcat::mcset cs {Key sequences} "Posloupnosti kláves" ::msgcat::mcset cs {KHIM Controls} "Ovládací panel KHIM" ::msgcat::mcset cs {OK} {OK} ::msgcat::mcset cs {Select code page:} "VýbÄ›r kódové stránky:" ::msgcat::mcset cs {Unicode...} "Unikód..." ::msgcat::mcset cs {Use KHIM} "Používat KHIM" } # Local Variables: # mode: tcl # End: tkabber-plugins/tkabber-khim/khim/da.msg000064400000000000000000000072721500237002100201050ustar00nobodynobody# da.msg -- # # Danish-language messages for KHIM # # Copyright (c) 2005 by Kevin B. Kenny. All rights reserved. # Translation by Torsten Berg # # Refer to the file "license.terms" for the terms and conditions of # use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES. # # $Id: da.msg,v 1.1 2006/09/05 13:48:49 kennykb Exp $ # $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/da.msg,v $ # #---------------------------------------------------------------------- namespace eval ::khim { ::msgcat::mcset da {Apply} {Anvend} ::msgcat::mcset da {Cancel} {Annuller} ::msgcat::mcset da {Change} {Ændre} ::msgcat::mcset da {Character} {Tegn} ::msgcat::mcset da {Compose Key} {Compose taste} ::msgcat::mcset da {Compose key:} {Compose taste:} ::msgcat::mcset da {Composed sequence must be two characters long} \ {Compose tegnfølgen skal bestÃ¥ af to tegn} ::msgcat::mcset da {Delete} {Slet} ::msgcat::mcset da {Help...} {Hjælp...} ::msgcat::mcset da HELPTEXT { Kevin's Hacky Input Method (KHIM) KHIM gør det muligt at indtaste internationale tegn med et tastatur som ikke understøtter disse. Dette fungerer uafhængigt af en bestÃ¥ende indtast metode som styresystemet mÃ¥tte understøtte. Det er tænkt til at hjælpe, hvis du ikke har kontrol over tilordningen pÃ¥ dit tastatur og dog har brug for at indtaste tekst i andre sprog. For at benytte KHIM, vis kontrolpanelet (hvordan det gøres, afhænger af dit program) og aktiver KHIM ved at afkrydse "Benyt KHIM". Du skal vælge en taste der kun sjældent benyttes pÃ¥ dit tastatur og fastlægge denne som "Compose" taste for at sætte tegn sammen med. Tryk dertil pÃ¥ knappen markeret med "Compose taste:" og tryk derefter pÃ¥ den taste du ønsker at fastlægge. Generellt skulle det ikke være den taste som normalt benyttes til at konstruere tegn med; denne taste vil fortsat oprÃ¥be din lokale systems indtast metode. NÃ¥r KHIM er aktiveret kan du indtaste internationale tegn i enhver kontrol der er konfigureret til at bruge KHIM ved at trykke pÃ¥ den valgte "Compose" taste fulgt af to bestemte tegn. Rullelisten til venstre pÃ¥ KHIM kontrolpanelet viser de tegnfølger der stÃ¥r til rÃ¥dighed. Hvis du trykker "Compose" tasten to gange kommer der et vindue frem hvor du kan vælge vilkÃ¥rlige symboler fra en unicode tabel. Du kan navigere rundt i selve tabellen ved enten at benytte markøren eller markørtasterne. Du kan udvælge det markerede tegn ved at doppelt-klikke pÃ¥ symbolet eller ved at trykke pÃ¥ mellemrums-, enter- eller returtasten. Ny tegnfølger kan defineres ved at indtaste en følge af to tegn i feltet markeret med "Indtast tegnfølge" og det ønskede symbol i feltet markeret med "Tegn" og derefter trykke pÃ¥ "Ændre". Du kan ogsÃ¥ kopiere og indsætte et symbol fra et andet program eller benytte "Unicode..." knappen (eller trykke "Compose" tasten to gange) for at hente et symbol fra tabellen med alle unicode koder. Tryk pÃ¥ "Slet" knappen for at fjerne en tegnfølge. } ::msgcat::mcset da {Input key sequence} {Indtast tegnfølge} ::msgcat::mcset da {Insert Character} {Indtast et tegn} ::msgcat::mcset da {Invalid sequence} {Ugyldig tegnfølge} ::msgcat::mcset da {Key sequences} {Tegnfølger} ::msgcat::mcset da {KHIM Controls} {KHIM kontrolpanel} ::msgcat::mcset da {OK} {O.k.} ::msgcat::mcset da {Select code page:} {Vælg kode side:} ::msgcat::mcset da {SELECT COMPOSE KEY} [string map [list \n\t \n] { Tryk pÃ¥ den taske du ønsker at bruge som "Compose" taste. }] ::msgcat::mcset da {Unicode...} {Unicode...} ::msgcat::mcset da {Use KHIM} {Benyt KHIM} } # Local Variables: # mode: tcl # End: tkabber-plugins/tkabber-khim/khim/de.msg000064400000000000000000000104711500237002100201040ustar00nobodynobody# de.msg -- # # German-language messages for KHIM # # Copyright (c) 2006 by Andreas Kupries. All rights reserved. # # Refer to the file "license.terms" for the terms and conditions of # use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES. # # $Id: de.msg,v 1.2 2006/09/07 13:18:13 kennykb Exp $ # $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/de.msg,v $ # #---------------------------------------------------------------------- namespace eval ::khim { ::msgcat::mcset de HELPTEXT { Kevin's Hacky Input Method (KHIM) KHIM ermöglicht die Eingabe von internationalen Zeichen mittels einer Tastatur, welches diese nicht direkt unterstützt. Es ist unabhängig von allen Eingabemethoden, welche vom Betriebssystem bereitgestellt werden (könnten), und für den Fall gedacht, wenn der Anwender keine Kontrolle über die Tastatur hat und dennoch Text in anderen Sprachen eingeben muß. Um KHIM zu benutzen, ist es notwendig, den KHIM Steuer-Dialog zu öffnen (dies ist abhängig von der Anwendung) und dann KHIM durch 'ticken' der 'Benutze KHIM'-Checkbox zu aktivieren. Es ist weiterhin notwendig, eine Taste als die Kombinier-Taste zu wählen. Die gewählte Taste sollte im Normalgebrauch selten genutzt werden. Die Auswahl selbst besteht aus zwei Schritten. Zuerst muß der Knopf "Kombinier-Taste:" gedrückt werden, dann die gewünschte Taste. Allgemein gesprochen, wenn die benutzte Tastatur eine Taste "Compose" besitzt, dann sollte diese _nicht_ als die Kombinier-Taste für KHIM gewählt werden. Dies stellt sicher, das diese Taste weiterhin vom Betriebssystem genutzt werden kann, um dessen eventuelle Eingabemethoden zu aktivieren. Sobald KHIM aktiviert wurde, können in jedem Widget, welches für die Benutzung von KHIM konfiguriert wurde, internationale Zeichen eingegeben werden. Dies geschieht durch Drücken der gewählten Kombinier-Taste, gefolgt von zwei weiteren Zeichen, welche das gewünschte Zeichen identifizieren. Der KHIM Steuer-Dialog stellt eine Liste der bekannten Zeichenfolgen zur Verfügung. Zusätzlich ist es möglich einen Dialog zu öffnen, welcher die Auswahl beliebiger Zeichen in einer Tabelle erlaubt. Dies geschieht durch zweimaliges Drücken der Kombinier-Taste. Navigation in der Tabelle geschieht mit der Maus oder den Kursor-Tasten. Das einzufügende Zeichen kann mit Doppel-Klick gewählt werden, durch Drücken der Leer-Taste, oder durch Drücken der Enter- (oder Return-)Taste. Es ist auch möglich, die Liste der direkt anwählbären Zeichen zu erweitern. Dies geschieht im KHIM Steuer-Dialog durch Eingabe der zwei Zeichen für den Kode im Eingabefeld "Eingabezeichenfolge", des gewünschten Zeichens im Feld "Zeichen", gefolgt vom Drücken des Knopfes "Ändern". (Bezüglich der Herkunft des gewünschten Zeichens: Es kann aus einer anderen Anwendung kopiert werden, oder man benutze den Knopf "Unicode..." (oder drücke die Kombinier-Taste zweimal), um es aus der Tabelle aller Zeichen auszuwählen.) Eine Zeichenfolge wird gelöscht durch Auswahl der Folge in der Liste aller Zeichenfolgen, gefolgt von der Lösch/Entferne-Taste. } ::msgcat::mcset de {SELECT COMPOSE KEY} [string map [list \n\t \n] { Bitte drücken Sie die Taste, welche Sie als Kombinier-Taste verwenden wollen. }] ::msgcat::mcset de {Apply} {Anwenden} ::msgcat::mcset de {Cancel} {Abbrechen} ::msgcat::mcset de {Change} {Ändern} ::msgcat::mcset de {Character} {Zeichen} ::msgcat::mcset de {Compose Key} {Kombinier-Taste} ::msgcat::mcset de {Compose key:} {Kombinier-Taste:} ::msgcat::mcset de {Composed sequence must be two characters long} \ {Die Eingabezeichenfolge muß aus zwei Zeichen bestehen} ::msgcat::mcset de {Delete} {Löschen} ::msgcat::mcset de {Help...} {Hilfe...} ::msgcat::mcset de {Input key sequence} {Eingabezeichenfolge} ::msgcat::mcset de {Insert Character} {Zeichen einfügen} ::msgcat::mcset de {Invalid sequence} {Ungültige Zeichenfolge} ::msgcat::mcset de {Key sequences} {Zeichenfolgen} ::msgcat::mcset de {KHIM Controls} {KHIM Steuerung} ::msgcat::mcset de {OK} {OK} ::msgcat::mcset de {Select code page:} {Wähle Code-Seite:} ::msgcat::mcset de {Unicode...} {Unicode...} ::msgcat::mcset de {Use KHIM} {Benutze KHIM} } # Local Variables: # mode: tcl # End: tkabber-plugins/tkabber-khim/khim/en.msg000064400000000000000000000075131500237002100201210ustar00nobodynobody# en.msg -- # # English-language messages for KHIM # # Copyright (c) 2005 by Kevin B. Kenny. All rights reserved. # # Refer to the file "license.terms" for the terms and conditions of # use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES. # # $Id: en.msg,v 1.3 2007/06/08 19:24:31 kennykb Exp $ # $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/en.msg,v $ # #---------------------------------------------------------------------- namespace eval ::khim { # If you edit HELPTEXT or {SELECT COMPOSE KEY}, also edit the corresponding # messages in ROOT.msg ::msgcat::mcset en HELPTEXT { Kevin's Hacky Input Method (KHIM) KHIM allows you to input international characters from a keyboard that doesn't support them. It works independently of any input method that the operating system may supply; it is intended for when you don't have control over your keyboard mapping and still need to input text in other languages. To use KHIM, bring up the KHIM Controls (the way this is done depends on your application) and enable KHIM by checking "Use KHIM". You also need to choose a key on your keyboard that is seldom used, and designate it as the "Compose" key by pressing the button labelled, "Compose key:" then striking the key you wish to designate. Generally speaking, this key should not be the key designated as "Compose" on the keyboard; that key will continue to invoke whatever input method the local operating system supplies. Once KHIM is enabled, you can enter international characters in any widget that is configured to use KHIM by pressing the Compose key followed by a two-character sequence. The listbox in the KHIM controls shows the available sequences. In addition, if you strike the Compose key twice, you get a dialog that allows you to input arbitrary symbols from a Unicode character map. In the map, you can navigate among the characters using either the cursor keys or the mouse, and you can select the current character for insertion by double-clicking it, pressing the space bar, or pressing the Enter (or Return) key. To define a new sequence for use with the Compose key, bring up the KHIM controls, enter the two characters in the "Input key sequence" entry and the desired character to insert into the "Character" entry, and press "Change". (You may copy and paste the character from another application, or use the "Unicode..." button (or press the Compose key twice) to select the character from a map of all available Unicode code points.) To remove a sequence, select it in the listbox and press "Delete". } ::msgcat::mcset en {SELECT COMPOSE KEY} [string map [list \n\t \n] { Please press the key that you want to use as the "Compose" key. }] ::msgcat::mcset en {Apply} {Apply} ::msgcat::mcset en {Cancel} {Cancel} ::msgcat::mcset en {Change} {Change} ::msgcat::mcset en {Character} {Character} ::msgcat::mcset en {Compose Key} {Compose Key} ::msgcat::mcset en {Compose key:} {Compose key:} ::msgcat::mcset en {Composed sequence must be two characters long} \ {Composed sequence must be two characters long} ::msgcat::mcset en {Delete} {Delete} ::msgcat::mcset en {KHIM Help} {KHIM Help} ::msgcat::mcset en {Help...} {Help...} ::msgcat::mcset en {Input key sequence} {Input key sequence} ::msgcat::mcset en {Insert Character} {Insert Character} ::msgcat::mcset en {Invalid sequence} {Invalid sequence} ::msgcat::mcset en {Key sequences} {Key sequences} ::msgcat::mcset en {KHIM Controls} {KHIM Controls} ::msgcat::mcset en {OK} {OK} ::msgcat::mcset en {Select code page:} {Select code page:} ::msgcat::mcset en {Unicode...} {Unicode...} ::msgcat::mcset en {Use KHIM} {Use KHIM} } # Local Variables: # mode: tcl # End: tkabber-plugins/tkabber-khim/khim/es.msg000064400000000000000000000076131500237002100201270ustar00nobodynobody# es.msg -- # # Spanish-language messages for KHIM # # Copyright (c) 2008 by Emiliano Gavilán. # Proofreading and corrections by Miguel Sofer. # # Refer to the file "license.terms" for the terms and conditions of # use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES. # # $Id: es.msg,v 1.3 2008/05/30 02:00:19 kennykb Exp $ # $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/es.msg,v $ # #---------------------------------------------------------------------- namespace eval ::khim { ::msgcat::mcset es HELPTEXT { Kevin's Hacky Input Method (KHIM) KHIM permite ingresar caracteres internacionales desde un teclado que no soporta esta funcionalidad. Funciona independientemente de cualquier método de entrada que su sistema operativo pueda proveer; su finalidad es permitirle ingresar caracteres en otros lenguajes, aun cuando no tenga control del mapeo de su teclado. Para usar KHIM, seleccione el diálogo de control de KHIM (la forma de lograr esto depende de su aplicación) y habilite el uso de KHIM seleccionando "Usar KHIM". También necesitará seleccionar una tecla que sea raramente usada y designarla como tecla "Componer" presionando el botón con la leyenda "Tecla Componer:" y luego la tecla que quiere asignar a esta función. Ésta tecla no debe ser la tecla designada como la tecla de composición de su teclado; dicha tecla seguirá invocando cualquier método de entrada que su sistema operativo provea. Una vez que KHIM esté habilitado, podrá ingresar caracteres internacionales en cualquier widget que este configurado para usar KHIM presionando la tecla designada como Componer seguida de una secuencia de dos teclas. La lista en el control de KHIM muestra todas las secuencias disponibles. Además, si presiona la tecla "Componer" dos veces, se mostrará un diálogo que le permitirá ingresar cualquier carácter arbitrario desde un mapa de caracteres Unicode. Dicho mapa puede navegarse utilizando el ratón o las teclas de dirección, y se puede seleccionar el carácter deseado con un doble click, la barra espaciadora o la tecla Return (Enter). Para definir una nueva secuencia para utilizar con la tecla "Componer", seleccione el control de KHIM, ingrese dos teclas en secuencia en la entrada "Secuencia de teclas", el carácter deseado en la entrada "Carácter", y luego presione la tecla "Cambiar". (Usted puede copiar y pegar dicho carácter desde otra aplicación, o presionar el botón "Unicode..." (o presione la tecla "Componer" dos veces) para seleccionar el carácter desde el mapa de los caracteres Unicode disponibles). Para borrar una secuencia, selecciónela de la lista y presione "Borrar". } ::msgcat::mcset es {SELECT COMPOSE KEY} [string map [list \n\t \n] { Por favor presione la tecla que desee usar como tecla "Componer". }] ::msgcat::mcset es {Apply} {Aplicar} ::msgcat::mcset es {Cancel} {Cancelar} ::msgcat::mcset es {Change} {Cambiar} ::msgcat::mcset es {Character} {Carácter} ::msgcat::mcset es {Compose Key} {Tecla Componer} ::msgcat::mcset es {Compose key:} {Tecla Componer:} ::msgcat::mcset es {Composed sequence must be two characters long} \ {La secuencia de composición debe ser de dos teclas} ::msgcat::mcset es {Delete} {Borrar} ::msgcat::mcset es {KHIM Help} {Ayuda de KHIM} ::msgcat::mcset es {Help...} {Ayuda...} ::msgcat::mcset es {Input key sequence} {Secuencia de teclas de entrada} ::msgcat::mcset es {Insert Character} {Insertar carácter} ::msgcat::mcset es {Invalid sequence} {Secuencia inválida} ::msgcat::mcset es {Key sequences} {Secuencias de teclas} ::msgcat::mcset es {KHIM Controls} {Controles de KHIM} ::msgcat::mcset es {OK} {Aceptar} ::msgcat::mcset es {Select code page:} {Seleccionar página de código:} ::msgcat::mcset es {Unicode...} {Unicode...} ::msgcat::mcset es {Use KHIM} {Usar KHIM} } tkabber-plugins/tkabber-khim/khim/khim.tcl000064400000000000000000001566541500237002100204560ustar00nobodynobody# khim.tcl -- # # Kevin's Hacky Input Method # # The 'khim' package defines a KHIM bindtag that can be applied to # entry or text widgets (after widget-specific bindings but before # Entry or Text bindings) to allow entry of international characters # from a US keyboard without any input method other than Tk. # # It works by defining a "Compose" key (default is ). When # the "Compose" key is pressed, followed by a two-character sequence, # those two characters are looked up in a user-configurable table and # replaced with a Unicode character, which is inserted into the widget. # # Copyright (c) 2006 by Kevin B. Kenny. All rights reserved. # # Refer to the file "license.terms" for the terms and conditions of # use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES. # # $Id: khim.tcl,v 1.10 2007/06/08 19:24:31 kennykb Exp $ # $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/khim.tcl,v $ # #---------------------------------------------------------------------- package require Tcl 8.4- package require Tk 8.4- package require msgcat 1.2 #package require autoscroll 1.0 package provide khim 1.0.1 namespace eval khim [list variable KHIMDir [file dirname [info script]]] namespace eval khim { namespace import ::msgcat::mc namespace export getOptions getConfig setConfig showHelp variable composeKey; # Keysym of the key used for the # Compose function variable map; # Dictionary whose keys are two- # character sequences and whose # values are the characters to # insert when those sequences # are composed variable UniOK; # Table of code-point ranges that # conform to printable chars variable use; # 1 if KHIM is enabled, 0 if not. #---------------------------------------------------------------------- variable CMapFont; # Font to use to display Unicode # characters in the character map variable CMapBadCharFont; # Font in which to display the hex # values of bad code points #---------------------------------------------------------------------- variable CMapCodePage; # Array whose keys are the # path names of KHIM character map # dialogs and whose values are # the code pages on display in # those dialogs variable CMapFocus; # Array whose keys are the path names # of KHIM character map dialogs and # whose values are the focus windows # where characters selected in the # dialogs will be inserted. variable CMapInputCodePage; # Array whose keys are the path names # of KHIM character map dialogs and # whose values are variables used # to hold the value of the spinbox # that selects the code page. variable CMapSelectedCharacter; # Array whose keys are the path names # of KHIM character map dialogs and # whose values are the characters # currently selected in the dialogs variable CMapXL; # Array whose keys are the path names # of KHIM character map dialogs and # whose values are the # X co-ordinates of the columns in # the character map variable CMapYL; # Array whose keys are the path names # of KHIM character map dialogs and # whose values are the # Y co-ordinates of the rows in the # character map. } # Load up message catalogs for the locale namespace eval khim [list ::msgcat::mcload [file dirname [info script]]] # Compressed table of which Unicode code points in the BMP are printable # characters. The table is read, "0x0000-0x001f are not printable, # 0x0020-0x007e are printable, 0x007f-0x009f are not printable, # 0x00a0-0x00ac are printable, 0x00ad is not, 0x00ae-0x0241 are, etc." set khim::UniOK { 0x0000 0x0020 0x007f 0x00a0 0x00ad 0x00ae 0x0242 0x0250 0x0370 0x0374 0x0376 0x037a 0x037b 0x037e 0x037f 0x0384 0x038b 0x038c 0x038d 0x038e 0x03a2 0x03a3 0x03cf 0x03d0 0x0487 0x0488 0x04cf 0x04d0 0x04fa 0x0500 0x0510 0x0531 0x0557 0x0559 0x0560 0x0561 0x0588 0x0589 0x058b 0x0591 0x05ba 0x05bb 0x05c8 0x05d0 0x05eb 0x05f0 0x0600 0x060b 0x0616 0x061b 0x061c 0x061e 0x0620 0x0621 0x063b 0x0640 0x065f 0x0660 0x06dd 0x06de 0x070f 0x0710 0x074b 0x074d 0x076e 0x0780 0x07b2 0x0901 0x093a 0x093c 0x094e 0x0950 0x0955 0x0958 0x0971 0x097d 0x097e 0x0981 0x0984 0x0985 0x098d 0x098f 0x0991 0x0993 0x09a9 0x09aa 0x09b1 0x09b2 0x09b3 0x09b6 0x09ba 0x09bc 0x09c5 0x09c7 0x09c9 0x09cb 0x09cf 0x09d7 0x09d8 0x09dc 0x09de 0x09df 0x09e4 0x09e6 0x09fb 0x0a01 0x0a04 0x0a05 0x0a0b 0x0a0f 0x0a11 0x0a13 0x0a29 0x0a2a 0x0a31 0x0a32 0x0a34 0x0a35 0x0a37 0x0a38 0x0a3a 0x0a3c 0x0a3d 0x0a3e 0x0a43 0x0a47 0x0a49 0x0a4b 0x0a4e 0x0a59 0x0a5d 0x0a5e 0x0a5f 0x0a66 0x0a75 0x0a81 0x0a84 0x0a85 0x0a8e 0x0a8f 0x0a92 0x0a93 0x0aa9 0x0aaa 0x0ab1 0x0ab2 0x0ab4 0x0ab5 0x0aba 0x0abc 0x0ac6 0x0ac7 0x0aca 0x0acb 0x0ace 0x0ad0 0x0ad1 0x0ae0 0x0ae4 0x0ae6 0x0af0 0x0af1 0x0af2 0x0b01 0x0b04 0x0b05 0x0b0d 0x0b0f 0x0b11 0x0b13 0x0b29 0x0b2a 0x0b31 0x0b32 0x0b34 0x0b35 0x0b3a 0x0b3c 0x0b44 0x0b47 0x0b49 0x0b4b 0x0b4e 0x0b56 0x0b58 0x0b5c 0x0b5e 0x0b5f 0x0b62 0x0b66 0x0b72 0x0b82 0x0b84 0x0b85 0x0b8b 0x0b8e 0x0b91 0x0b92 0x0b96 0x0b99 0x0b9b 0x0b9c 0x0b9d 0x0b9e 0x0ba0 0x0ba3 0x0ba5 0x0ba8 0x0bab 0x0bae 0x0bba 0x0bbe 0x0bc3 0x0bc6 0x0bc9 0x0bca 0x0bce 0x0bd7 0x0bd8 0x0be6 0x0bfb 0x0c01 0x0c04 0x0c05 0x0c0d 0x0c0e 0x0c11 0x0c12 0x0c29 0x0c2a 0x0c34 0x0c35 0x0c3a 0x0c3e 0x0c45 0x0c46 0x0c49 0x0c4a 0x0c4e 0x0c55 0x0c57 0x0c60 0x0c62 0x0c66 0x0c70 0x0c82 0x0c84 0x0c85 0x0c8d 0x0c8e 0x0c91 0x0c92 0x0ca9 0x0caa 0x0cb4 0x0cb5 0x0cba 0x0cbc 0x0cc5 0x0cc6 0x0cc9 0x0cca 0x0cce 0x0cd5 0x0cd7 0x0cde 0x0cdf 0x0ce0 0x0ce2 0x0ce6 0x0cf0 0x0d02 0x0d04 0x0d05 0x0d0d 0x0d0e 0x0d11 0x0d12 0x0d29 0x0d2a 0x0d3a 0x0d3e 0x0d44 0x0d46 0x0d49 0x0d4a 0x0d4e 0x0d57 0x0d58 0x0d60 0x0d62 0x0d66 0x0d70 0x0d82 0x0d84 0x0d85 0x0d97 0x0d9a 0x0db2 0x0db3 0x0dbc 0x0dbd 0x0dbe 0x0dc0 0x0dc7 0x0dca 0x0dcb 0x0dcf 0x0dd5 0x0dd6 0x0dd7 0x0dd8 0x0de0 0x0df2 0x0df5 0x0e01 0x0e3b 0x0e3f 0x0e5c 0x0e81 0x0e83 0x0e84 0x0e85 0x0e87 0x0e89 0x0e8a 0x0e8b 0x0e8d 0x0e8e 0x0e94 0x0e98 0x0e99 0x0ea0 0x0ea1 0x0ea4 0x0ea5 0x0ea6 0x0ea7 0x0ea8 0x0eaa 0x0eac 0x0ead 0x0eba 0x0ebb 0x0ebe 0x0ec0 0x0ec5 0x0ec6 0x0ec7 0x0ec8 0x0ece 0x0ed0 0x0eda 0x0edc 0x0ede 0x0f00 0x0f48 0x0f49 0x0f6b 0x0f71 0x0f8c 0x0f90 0x0f98 0x0f99 0x0fbd 0x0fbe 0x0fcd 0x0fcf 0x0fd2 0x1000 0x1022 0x1023 0x1028 0x1029 0x102b 0x102c 0x1033 0x1036 0x103a 0x1040 0x105a 0x10a0 0x10c6 0x10d0 0x10fd 0x1100 0x115a 0x115f 0x11a3 0x11a8 0x11fa 0x1200 0x1249 0x124a 0x124e 0x1250 0x1257 0x1258 0x1259 0x125a 0x125e 0x1260 0x1289 0x128a 0x128e 0x1290 0x12b1 0x12b2 0x12b6 0x12b8 0x12bf 0x12c0 0x12c1 0x12c2 0x12c6 0x12c8 0x12d7 0x12d8 0x1311 0x1312 0x1316 0x1318 0x135b 0x135f 0x137d 0x1380 0x139a 0x13a0 0x13f5 0x1401 0x1677 0x1680 0x169d 0x16a0 0x16f1 0x1700 0x170d 0x170e 0x1715 0x1720 0x1737 0x1740 0x1754 0x1760 0x176d 0x176e 0x1771 0x1772 0x1774 0x1780 0x17b4 0x17b6 0x17de 0x17e0 0x17ea 0x17f0 0x17fa 0x1800 0x180f 0x1810 0x181a 0x1820 0x1878 0x1880 0x18aa 0x1900 0x191d 0x1920 0x192c 0x1930 0x193c 0x1940 0x1941 0x1944 0x196e 0x1970 0x1975 0x1980 0x19aa 0x19b0 0x19ca 0x19d0 0x19da 0x19de 0x1a1c 0x1a1e 0x1a20 0x1d00 0x1dc4 0x1e00 0x1e9c 0x1ea0 0x1efa 0x1f00 0x1f16 0x1f18 0x1f1e 0x1f20 0x1f46 0x1f48 0x1f4e 0x1f50 0x1f58 0x1f59 0x1f5a 0x1f5b 0x1f5c 0x1f5d 0x1f5e 0x1f5f 0x1f7e 0x1f80 0x1fb5 0x1fb6 0x1fc5 0x1fc6 0x1fd4 0x1fd6 0x1fdc 0x1fdd 0x1ff0 0x1ff2 0x1ff5 0x1ff6 0x1fff 0x2000 0x200b 0x2010 0x202a 0x202f 0x2060 0x2070 0x2072 0x2074 0x208f 0x2090 0x2095 0x20a0 0x20b6 0x20d0 0x20ec 0x2100 0x214d 0x2153 0x2184 0x2190 0x23dc 0x2400 0x2427 0x2440 0x244b 0x2460 0x269d 0x26a0 0x26b2 0x2701 0x2705 0x2706 0x270a 0x270c 0x2728 0x2729 0x274c 0x274d 0x274e 0x274f 0x2753 0x2756 0x2757 0x2758 0x275f 0x2761 0x2795 0x2798 0x27b0 0x27b1 0x27bf 0x27c0 0x27c7 0x27d0 0x27ec 0x27f0 0x2b14 0x2c00 0x2c2f 0x2c30 0x2c5f 0x2c80 0x2ceb 0x2cf9 0x2d26 0x2d30 0x2d66 0x2d6f 0x2d70 0x2d80 0x2d97 0x2da0 0x2da7 0x2da8 0x2daf 0x2db0 0x2db7 0x2db8 0x2dbf 0x2dc0 0x2dc7 0x2dc8 0x2dcf 0x2dd0 0x2dd7 0x2dd8 0x2ddf 0x2e00 0x2e18 0x2e1c 0x2e1e 0x2e80 0x2e9a 0x2e9b 0x2ef4 0x2f00 0x2fd6 0x2ff0 0x2ffc 0x3000 0x3040 0x3041 0x3097 0x3099 0x3100 0x3105 0x312d 0x3131 0x318f 0x3190 0x31b8 0x31c0 0x31d0 0x31f0 0x321f 0x3220 0x3244 0x3250 0x32ff 0x3300 0x4db6 0x4dc0 0x9fbc 0xa000 0xa48d 0xa490 0xa4c7 0xa700 0xa717 0xa800 0xa82c 0xac00 0xd7a4 0xe000 0xfa2e 0xfa30 0xfa6b 0xfa70 0xfada 0xfb00 0xfb07 0xfb13 0xfb18 0xfb1d 0xfb37 0xfb38 0xfb3d 0xfb3e 0xfb3f 0xfb40 0xfb42 0xfb43 0xfb45 0xfb46 0xfbb2 0xfbd3 0xfd40 0xfd50 0xfd90 0xfd92 0xfdc8 0xfdf0 0xfdfe 0xfe00 0xfe1a 0xfe20 0xfe24 0xfe30 0xfe53 0xfe54 0xfe67 0xfe68 0xfe6c 0xfe70 0xfe75 0xfe76 0xfeff 0xff01 0xffbf 0xffc2 0xffc8 0xffca 0xffd0 0xffd2 0xffd8 0xffda 0xffdd 0xffe0 0xffe7 0xffe8 0xfff9 0xfffc 0xfffe } #---------------------------------------------------------------------- # # BSearch -- # # Service procedure that does binary search in several places. # # Parameters: # list - List of lists, sorted in ascending order by the # first elements # key - Value to search for # # Results: # Returns the index of the greatest element in $list that is less # than or equal to $key. # # Side effects: # None. # #---------------------------------------------------------------------- proc ::khim::BSearch { list key } { if { $key < [lindex $list 0 0] } { return -1 } set l 0 set u [expr { [llength $list] - 1 }] while { $l < $u } { # At this point, we know that # $k >= [lindex $list $l 0] # Either $u == [llength $list] or else $k < [lindex $list $u+1 0] # We find the midpoint of the interval {l,u} rounded UP, compare # against it, and set l or u to maintain the invariant. Note # that the interval shrinks at each step, guaranteeing convergence. set m [expr { ( $l + $u + 1 ) / 2 }] if { $key >= [lindex $list $m 0] } { set l $m } else { set u [expr { $m - 1 }] } } return $l } #---------------------------------------------------------------------- # # khim::ValidChar -- # # Test whether a number is the index of a valid character. # # Parameters: # c - Number of the character. # # Results: # Returns 1 if the character is a printable Unicode characte # in the BMP, and 0 otherwise. # #---------------------------------------------------------------------- proc ::khim::ValidChar { c } { variable UniOK return [expr {( [BSearch $UniOK $c] & 1 )}] } #---------------------------------------------------------------------- # # khim::getOptions -- # # Displays a dialog that allows the user to enable/disable KHIM, # change key mappings, and change the Compose key. # # Parameters: # w -- Window path name of the dialog box. # # Results: # None. # # Side effects: # Changes options to whatever the user selects. # #---------------------------------------------------------------------- proc khim::getOptions {w} { variable use variable composeKey variable map variable inputUse variable inputComposeKey variable inputMap # Set temporary options for the use of the dialog set inputUse $use set inputComposeKey $composeKey array set inputMap $map # Create a modal dialog toplevel $w -class dialog wm withdraw $w set p [winfo toplevel [winfo parent $w]] set g [wm transient $p] if { ![string compare {} $g] } { set g $p } wm transient $w $g catch {wm attributes $w -toolwindow 1} wm title $w [mc "KHIM Controls"] bind $w [list ::khim::HandleDestroy $w %W] # Create GUI and manage geometry checkbutton $w.v -variable ::khim::inputUse -text [mc "Use KHIM"] label $w.l1 -text [mc "Compose key:"] button $w.b1 -textvariable ::khim::inputComposeKey \ -command [list ::khim::GetComposeKey $w.b1] labelframe $w.lf1 -text [mc "Key sequences"] -padx 1.25m -pady 1.25m -width 12c listbox $w.lf1.lb -height 20 -yscroll [list $w.lf1.y set] \ -font {Courier 12} -width 8 -height 10 \ -exportselection 0 bind $w.lf1.lb <> [list ::khim::Select %W] scrollbar $w.lf1.y -orient vertical -command [list $w.lf1.lb yview] frame $w.lf1.f1 label $w.lf1.f1.l1 -text [mc "Input key sequence"] entry $w.lf1.f1.e1 -textvariable ::khim::inputSequence -width 2 \ -font {Courier 12} bind $w.lf1.f1.e1 { %W selection from 0 %W selection to end } grid $w.lf1.f1.l1 $w.lf1.f1.e1 grid columnconfigure $w.lf1.f1 2 -weight 1 frame $w.lf1.f2 label $w.lf1.f2.l1 -text [mc "Character"] entry $w.lf1.f2.e1 -textvariable ::khim::inputCharacter -width 2 \ -font {Courier 12} bind $w.lf1.f2.e1 { %W selection from 0 %W selection to end } button $w.lf1.f2.b1 -text [mc "Unicode..."] \ -command [list ::khim::FocusAndInsertSymbol $w.lf1.f2.e1] grid $w.lf1.f2.l1 $w.lf1.f2.e1 grid $w.lf1.f2.b1 -row 0 -column 2 -sticky w -padx {5m 0} grid columnconfigure $w.lf1.f2 3 -weight 1 grid $w.lf1.lb -row 0 -column 0 -sticky nsew -rowspan 5 grid $w.lf1.y -row 0 -column 1 -sticky ns -rowspan 5 frame $w.lf1.f3 button $w.lf1.f3.b1 -text [mc Change] \ -command [list ::khim::ChangeSequence $w] button $w.lf1.f3.b2 -text [mc Delete] \ -command [list ::khim::DeleteSequence $w] grid $w.lf1.f1 -row 0 -column 2 -sticky e -padx {5m 0} grid $w.lf1.f2 -row 1 -column 2 -sticky e -padx {5m 0} grid $w.lf1.f3.b1 $w.lf1.f3.b2 -padx 1.25m -sticky ew grid columnconfigure $w.lf1.f3 {0 1} -weight 1 -uniform A grid $w.lf1.f3 -row 3 -column 2 -sticky e -padx 5m grid rowconfigure $w.lf1 2 -weight 1 grid columnconfigure $w.lf1 3 -weight 1 #::autoscroll::autoscroll $w.lf1.y frame $w.bf button $w.bf.ok -text [mc OK] -command [list ::khim::OK $w] button $w.bf.apply -text [mc Apply] -command [list ::khim::Apply $w] button $w.bf.cancel -text [mc Cancel] -command [list destroy $w] button $w.bf.help -text [mc Help...] \ -command [list ::khim::showHelp $w.help] grid $w.bf.ok -row 0 -column 0 -padx 1.25m -sticky ew grid $w.bf.apply -row 0 -column 1 -padx 1.25m -sticky ew grid $w.bf.cancel -row 0 -column 2 -padx 1.25m -sticky ew grid $w.bf.help -row 0 -column 4 -padx 1.25m grid columnconfigure $w.bf 3 -weight 1 grid columnconfigure $w.bf {0 1 2 4} -uniform A grid $w.v -columnspan 2 -sticky w grid $w.l1 $w.b1 -sticky w grid $w.lf1 -columnspan 2 -sticky nsew -padx 1.25m -pady 1.25m grid $w.bf -pady 1.25m -sticky ew -columnspan 2 grid columnconfigure $w 1 -weight 1 # Initialize the listbox content ShowSequences $w # Pop up the dialog wm deiconify $w tkwait window $w return } #---------------------------------------------------------------------- # # khim::FocusAndInsertSymbol -- # # Shift focus to a given window and call the character map # interactor on it. # # Parameters: # w - Window to focus # # Results: # None. # # Side effects: # Whatever the user requests from the character map. # #---------------------------------------------------------------------- proc khim::FocusAndInsertSymbol {w} { focus $w CMapInteractor $w return } #---------------------------------------------------------------------- # # khim::showHelp -- # # Display a help dialog for KHIM # # Parameters: # w -- Path name of the dialog # # Results: # None. # # Side effects: # Pops up the dialog. # # The help text is in the HELPTEXT entry in the message catalog of the # current locale. # #---------------------------------------------------------------------- proc khim::showHelp {w} { variable KHIMDir # Create dialog to display help catch {destroy $w} toplevel $w wm withdraw $w set p [winfo toplevel [winfo parent $w]] set g [wm transient $p] if { ![string compare {} $g] } { set g $p } wm transient $w $g wm title $w [mc {KHIM Help}] catch {wm attributes $w -toolwindow 1} # Create and manage GUI components text $w.t -width 60 -yscrollcommand [list $w.y set] -wrap word set text [string trim [mc HELPTEXT]] if {$text eq "HELPTEXT"} { # This must be a version of Tcl that doesn't support the root # locale. Do The Right Thing anyway set locale [::msgcat::mclocale] ::msgcat::mclocale en set text [string trim [mc HELPTEXT]] if {$text eq "HELPTEXT"} { ::msgcat::mcload $KHIMDir set text [string trim [mc HELPTEXT]] } ::msgcat::mclocale $locale } regsub -all -line {^[ \t]+} $text {} text regsub -all -line {[ \t]+$} $text {} text regsub -all {\n\n} $text

text regsub -all {\n} $text { } text regsub -all

$text \n\n text $w.t insert insert $text $w.t see 1.0 $w.t configure -state disabled scrollbar $w.y -command [list $w.t yview] -orient vertical button $w.ok -text [mc OK] -command [list destroy $w] grid $w.t -row 0 -column 0 -sticky nsew grid $w.y -row 0 -column 1 -sticky ns grid $w.ok -pady 1.25m -row 1 -column 0 -columnspan 2 grid rowconfigure $w 0 -weight 1 grid columnconfigure $w 0 -weight 1 # Determine whether we have a grab in effect set gr [grab current $w] if {$gr ne {}} { bind $w "focus $w.ok; grab set $w" } else { bind $w [list focus $w.ok] } # Pop up the dialog wm deiconify $w # Restore the grab if there was one if {$gr ne {}} { tkwait window $w grab set $gr } return } #---------------------------------------------------------------------- # # khim::GetComposeKey -- # # Prompt the user for what key to use for the "Compose" function. # # Parameters: # parent -- Path name of the parent widget of the dialog # # Side effects: # Stores the user's selection in 'inputComposeKey' # #---------------------------------------------------------------------- proc khim::GetComposeKey {parent} { variable KHIMDir variable inputComposeKey set w [winfo parent $parent].composeKey toplevel $w -class dialog wm withdraw $w wm geometry $w +[winfo rootx $parent]+[winfo rooty $parent] set p [winfo toplevel [winfo parent $w]] set g [wm transient $p] if { ![string compare {} $g] } { set g $p } wm transient $w $g catch {wm attributes $w -toolwindow 1} wm title $w [mc "Compose Key"] set text [mc "SELECT COMPOSE KEY"] if {$text eq "SELECT COMPOSE KEY"} { # This must be a version of Tcl that doesn't support the root # locale. Do The Right Thing anyway set locale [::msgcat::mclocale] ::msgcat::mclocale en set text [string trim [mc "SELECT COMPOSE KEY"]] if {$text eq "SELECT COMPOSE KEY"} { ::msgcat::mcload $KHIMDir set text [string trim [mc "SELECT COMPOSE KEY"]] } ::msgcat::mclocale $locale } grid [label $w.l -text $text] bind $w.l [list set ::khim::inputComposeKey %K] bind $w.l [list focus %W] wm resizable $w 0 0 bind $w [list grab $w] wm deiconify $w bind $w {set ::khim::inputComposeKey DESTROYED} set holdInputComposeKey $inputComposeKey while {1} { vwait ::khim::inputComposeKey if { $inputComposeKey eq {DESTROYED} } { set inputComposeKey $holdInputComposeKey break } elseif {$inputComposeKey ne {}} { bind $w {} after idle [list destroy $w] break } } return } #---------------------------------------------------------------------- # # khim::Select -- # # Handles selection in the listbox containing KHIM input # character sequences. # # Parameters: # lb -- Path name of the listbox. # # Results: # None. # # Side effects: # Stores the currently selected sequence, and its mapping, # in "inputSequence" and "inputCharacter." # #---------------------------------------------------------------------- proc khim::Select {lb} { variable inputSequence variable inputCharacter foreach item [$lb curselection] { if { [regexp "^(..) \u2192 (.)" [$lb get $item] \ -> inputSequence inputCharacter] } { break } } return } #---------------------------------------------------------------------- # # khim::DeleteSequence -- # # Deletes the currently selected input sequence from the set. # # Parameters: # w - Path name of the active dialog box. # # Results: # None. # # Side effects: # Removes the currently selected sequence from 'inputMap' # and redisplays the sequences in the listbox # #---------------------------------------------------------------------- proc khim::DeleteSequence {w} { khim::SetSequence $w {} return } #---------------------------------------------------------------------- # # khim::ChangeSequence -- # # Changes the currently selected input sequence from the set. # # Parameters: # w - Path name of the active dialog box. # # Results: # None. # # Side effects: # Changes the currently selected sequence from 'inputMap' # to request the character stored in 'inputCharacter' # and redisplays the sequences in the listbox # #---------------------------------------------------------------------- proc khim::ChangeSequence {w} { variable inputCharacter khim::SetSequence $w $inputCharacter return } #---------------------------------------------------------------------- # # khim::SetSequence -- # # Deletes or changes a character sequence in the input map # # Parameters: # w - Path name of the active dialog box # inputCharacter - Character that the active sequence should # map to. An empty string deletes the sequence. # # Results: # None. # # Side effects: # Changes the currently selected sequence from 'inputMap' # to request the character stored in 'inputCharacter' # and redisplays the sequences in the listbox # #---------------------------------------------------------------------- proc khim::SetSequence {w inputCharacter} { variable inputSequence variable inputMap if { [string length $inputSequence] != 2 } { tk_messageBox \ -message [mc {Composed sequence must be two characters long}] \ -type ok \ -icon error \ -parent $w \ -title [mc {Invalid sequence}] } elseif { [string length $inputCharacter] == 0 } { catch { unset inputMap($inputSequence) } ShowSequences $w } else { set inputMap($inputSequence) $inputCharacter ShowSequences $w $inputSequence } return } #---------------------------------------------------------------------- # # khim::ShowSequences -- # # Updates the listbox in the KHIM configuration dialog with # the currently defined input sequences. # # Parameters: # w -- Path name of the active dialog # inputSequence -- Input sequence that has been changed, if any. # # Results: # None. # # Side effects: # Listbox is updated to reflect change, and the active sequence # is selected. # #---------------------------------------------------------------------- proc khim::ShowSequences {w {inputSequence {}}} { variable inputMap # Remember the scroll position foreach {top bottom} [$w.lf1.lb yview] break # Clear the listbox $w.lf1.lb delete 0 end # Put all the items back in the listbox, in order. # Remember the index of any item that matches the current sequence. foreach key [lsort -dictionary [array names inputMap]] { if { ![string compare $key $inputSequence] } { set idx [$w.lf1.lb index end] } $w.lf1.lb insert end "$key \u2192 $inputMap($key)" } # Select the just-changed item, if any. If there is nothing to select, # simply restore the scroll position. if { [info exists idx] } { $w.lf1.lb selection set $idx $w.lf1.lb see $idx } else { $w.lf1.lb yview moveto $top } return } #---------------------------------------------------------------------- # # khim::Apply -- # # Apply changes from the KHIM configuration dialog. # # Parameters: # w - Path name of the dialog # # Results: # None. # # Side effects: # Current configuration is stored, and bindings to the KHIM # bindtag are applied. # #---------------------------------------------------------------------- proc khim::Apply { w } { variable use variable composeKey variable map variable inputUse variable inputComposeKey variable inputMap set use $inputUse set composeKey $inputComposeKey set map [array get inputMap] RedoBindings return } #---------------------------------------------------------------------- # # khim::OK -- # # Apply changes and dismiss the KHIM configuration dialog. # # Parameters: # w - Path name of the dialog # # Results: # None. # # Side effects: # Current configuration is stored, and bindings to the KHIM # bindtag are applied. The dialog is dismissed. # #---------------------------------------------------------------------- proc khim::OK { w } { Apply $w destroy $w } #---------------------------------------------------------------------- # # khim::HandleDestroy -- # # Clean up from destruction of the KHIM input dialog. # # Parameters: # w - Path name of the destroyed window # t - Path name of the toplevel of the active dialog. # # Results: # None. # # Side effects: # Unsets variables that are used only when the dialog is active. # #---------------------------------------------------------------------- proc khim::HandleDestroy { w t } { if { [string compare $w $t] } return variable inputComposeKey variable inputMap variable inputUse unset inputUse unset inputComposeKey unset inputMap return } #---------------------------------------------------------------------- # # khim::RedoBindings -- # # Establish bindings on the KHIM bindtag according to the current # settings. # # Parameters: # None. # # Results: # None. # # Side effects: # Binds the Compose key to a {break}, the leading character # of each two-character sequence to a break as well, and # the second character of each two character sequence to # insert the mapped character. Arranges so that unrecognized # two-character sequences insert the two individual characters. # #---------------------------------------------------------------------- proc khim::RedoBindings {} { variable use variable composeKey variable map foreach b [bind KHIM] { bind KHIM $b {} } if { $use } { bind KHIM break bind KHIM { khim::CMapInteractor %W } foreach {seq char} $map { set c0 [string map {{ } < } [string index $seq 0]] set c1 [string map {{ } < } [string index $seq 1]] bind KHIM $c0 break bind KHIM $c0 \ [list khim::BadCompose %W [string index $seq 0] %A] bind KHIM $c0$c1 \ [list khim::Insert %W $char]\;break } } return } #---------------------------------------------------------------------- # # khim::BadCompose -- # # Handle an unrecognized key sequence # # Parameters: # w - Focus window # c0 - First character in the sequence # c1 - Second character in the sequence, or an empty string if # there is no second character # # Results: # None # # Side effects: # Inserts the two individual characters into the focus window. # #---------------------------------------------------------------------- proc khim::BadCompose {w c0 c1} { if {$c1 ne {}} { khim::Insert $w $c0 khim::Insert $w $c1 } return -code break } #---------------------------------------------------------------------- # # khim::Insert -- # # Inserts a character into a text or entry. # # Parameters: # w - Window in which to insert # c - Character to insert # # Results: # None. # # Side effects: # Character is inserted. # #---------------------------------------------------------------------- proc khim::Insert {w c} { $w insert insert $c switch -exact [winfo class $w] { Entry - TEntry { set c [$w index insert] if {($c < [$w index @0]) || ($c > [$w index @[winfo width $w]])} { $w xview $c } } Text { $w see insert } } } #---------------------------------------------------------------------- # # khim::getConfig -- # # Returns a script that will restore the current KHIM configuration. # # Results: # Returns the script. # #---------------------------------------------------------------------- proc khim::getConfig {} { variable use variable composeKey variable map array set x $map set retval [list khim::setConfig 1.0 $use $composeKey] append retval { } \{ foreach key [lsort -dictionary [array names x]] { append retval \n { } [list $key] { } [ReplaceU $x($key)] } append retval \n\} } #---------------------------------------------------------------------- # # khim::setConfig -- # # Restores the saved configuration from "khim::getConfig" # # Parameters: # version - Version of the configuration command # u - Flag for whether KHIM is enabled # c - Compose key selected # m - Map from compose sequences to characters. # # Results: # None # # Side effects: # Configuration is set. # #---------------------------------------------------------------------- proc khim::setConfig {v u c m args} { variable use variable composeKey variable map switch -exact $v { 1.0 { set use $u set composeKey $c set map $m } default { return -code error "Unknown KHIM version $v" } } RedoBindings return } #---------------------------------------------------------------------- # # khim::ReplaceU -- # # Replaces non-ASCII characters in a Unicode string with \u escapes. # # Parameters: # s - String to clean up # # Results: # Returns the cleaned string. # #---------------------------------------------------------------------- proc khim::ReplaceU {string} { set retval {} foreach char [split $string {}] { scan $char %c ccode if { $ccode >= 0x0020 && $ccode < 0x007f && $char ne "\{" && $char ne "\}" && $char ne "\[" && $char ne "\]" && $char ne "\\" && $char ne "\$" } { append retval $char } else { append retval \\u [format %04x $ccode] } } return $retval } #---------------------------------------------------------------------- # # khim::CMapUpdateSpinbox -- # # Variable trace callback that manages the state of the # code page selection spinbox when the code page changes. # # Parameters: # w - Window path name of the character map dialog # args - Extra args from the 'trace' mechanism are not used here. # # Results: # None. # # Side effects: # If the CMapInputCodePage variable contains an invalid code # page number, the background of the spinbox changes to red. # Otherwise, the background of the spinbox changes to white. # The values list of the spinbox is updated to be a list of # the decimal or hexadecimal code page numbers according to # whether the variable's string representation contains # '0x'. # #---------------------------------------------------------------------- proc khim::CMapUpdateSpinbox {w args} { variable CMapInputCodePage variable CMapCodePage variable CMapSavedColors set spin $w.spin # Test validity of the code page number if { ![string is integer -strict $CMapInputCodePage($w)] || $CMapInputCodePage($w) < 0 || $CMapInputCodePage($w) >= 0x100 } { #if {![info exists CMapSavedColors($w)]} { # set CMapSavedColors($w) \ # [list [$spin cget -background] [$spin cget -foreground]] #} #$spin configure -background \#ff6666 -foreground \#000000 } else { # Valid code page - generate the values list. Make sure that # the current value is in the list, even if it's formatted # eccentrically (e.g., 0x000012). #if {[info exists CMapSavedColors($w)]} { # foreach {bg fg} $CMapSavedColors($w) break # $spin configure -background $bg -foreground $fg # unset CMapSavedColors($w) #} if { [string match *0x* $CMapInputCodePage($w)] } { set format 0x%02X } else { set format %d } for { set i 0 } { $i < $CMapInputCodePage($w) } { incr i } { lappend values [format $format $i] } lappend values $CMapInputCodePage($w) for { incr i } { $i < 0x100 } { incr i } { lappend values [format $format $i] } # When we change the values list, the content of the spinbox # appears to be lost; deal with this by saving and restoring it. set cp $CMapInputCodePage($w) set i [$spin index insert] $spin configure -values $values $spin set $cp $spin icursor $i set CMapCodePage($w) $CMapInputCodePage($w) } return } #---------------------------------------------------------------------- # # khim::CMapDrawCanvas -- # # Puts a map of a single Unicode code page into a canvas. # # Parameters: # w -- Path name of the character map dialog # args -- Additional arguments resulting from a 'trace' callback # # Results: # None. # # Side effects: # The given canvas is redrawn with a 16x16 grid of characters. # #---------------------------------------------------------------------- proc khim::CMapDrawCanvas {w args} { variable CMapCodePage variable CMapInputCodePage variable CMapFont variable CMapBadCharFont variable CMapXL variable CMapYL variable CMapSelectedCharacter variable CMapAfter variable CMapBackground variable CMapForeground if {[info exists CMapAfter($w)]} { after cancel $CMapAfter($w) unset CMapAfter($w) } set c $w.c set pad 2 # Clear the canvas $c delete all set minsize [CMapCellSize $c] # Drop glyphs for all the characters onto the canvas, stacking them # all at (0,0). We'll be sliding them by rows and columns to make the # grid. set rem [expr { $CMapSelectedCharacter($w) % 0x0100 }] set srow [expr { $rem / 16 }] set scol [expr { $rem % 16 }] set tick [clock clicks -milliseconds] set ok 1 for { set row 0 } { $row < 16 } { incr row } { for { set col 0 } { $col < 16 } { incr col } { set point [expr { 256 * $CMapCodePage($w) + 16 * $row + $col }] if { ($ok || ($row == $srow && $col == $scol)) && [ValidChar $point] } { set t [format %c $point] set f $CMapFont } else { set t [format %02X\n%02X \ [expr { $point / 0x100 }] [expr { $point % 0x100 }]] set f $CMapBadCharFont } set tags [list text row$row col$col] $c create text 0 0 -text $t -font $f -fill $CMapForeground($w)\ -anchor center -justify center -tags $tags set tock [clock clicks -milliseconds] if {$ok && $tock-$tick > 1500} { set CMapAfter($w) [after 500 [list khim::CMapDrawCanvas $w]] set ok 0 } } } # Spread out the columns and generate a list of the X co-ordinates # of the spacer lines set xmin [expr {$pad + 1}] set x $xmin set CMapXL($w) [list $x] for { set col 0 } { $col < 16 } { incr col } { foreach { x0 - x1 - } [$c bbox col$col] break set cw [expr { $x1 - $x0 + 5 }] if { $cw < $minsize } { set cw $minsize } set xt [expr { $x + $cw/2 }] set dx [expr { $xt - ( $x0 + $x1 ) / 2 }] $c move col$col $dx 0 incr x $cw lappend CMapXL($w) $x } set xmax $x # Now do the same with the rows set ymin [expr {$pad + 1}] set y $ymin set CMapYL($w) [list $y] for { set row 0 } { $row < 16 } { incr row } { foreach { - y0 - y1 } [$c bbox row$row] break set rh [expr { $y1 - $y0 + 5 }] if { $rh < $minsize } { set rh $minsize } set yt [expr { $y + $rh/2 }] set dy [expr { $yt - ( $y0 + $y1 ) / 2 }] $c move row$row 0 $dy incr y $rh lappend CMapYL($w) $y } set ymax $y # Now that the characters on the grid are properly positioned, draw # the separator lines and configure the canvas size # We interpolate between foreground and background to draw the lines, # so that they appear "finer" visually than a 0-pixel line set linecolor \# foreach \ c1 [winfo rgb $c $CMapForeground($w)] \ c2 [winfo rgb $c $CMapBackground($w)] { set c3 [expr {(3 * $c2 + $c1) / 4}] append linecolor [format %04x $c3] } foreach x $CMapXL($w) { $c create line $x $ymin $x $ymax -width 0 -fill $linecolor } foreach y $CMapYL($w) { $c create line $xmin $y $xmax $y -width 0 -fill $linecolor } $c configure -width [expr { $xmax + $pad }] \ -height [expr { $ymax + $pad }] \ -scrollregion [list 0 0 [expr {$xmax + $pad}] [expr {$ymax + $pad}]] # Change the codepage in the spinbox if { $CMapCodePage($w) != $CMapInputCodePage($w) } { set CMapInputCodePage($w) $CMapCodePage($w) } # Display a selection box ShowSelectedCell $w } #---------------------------------------------------------------------- # # khim::CMapCellSize -- # # Computes the size of one cell in the character map # # Parameters: # c - canvas in which the map will be drawn. # # Results: # Returns the size in pixels of one square cell in the canvas. # #---------------------------------------------------------------------- proc khim::CMapCellSize {c} { variable CMapFont variable CMapBadCharFont # Compute the minimum linear dimension of one box in the grid. # It is at least 5 pxl greater than # - the linespace of the display font # - 2-line space in the "bad character" font # - one em in the display font # - two digit widths in the "bad character" font set minsize \ [expr { [font metrics $CMapFont -displayof $c -linespace] + 5 }] set minsize2 [expr { 2 * [font metrics $CMapBadCharFont \ -displayof $c -linespace] + 5 }] if { $minsize2 > $minsize } { set minsize $minsize2 } set minsize2 [expr { [font measure $CMapFont -displayof $c M] + 5 }] if { $minsize2 > $minsize } { set minsize $minsize2 } set minsize2 [expr { [font measure $CMapBadCharFont -displayof $c 00] + 5 }] if { $minsize2 > $minsize } { set minsize $minsize2 } return $minsize } #---------------------------------------------------------------------- # # khim::ShowSelectedCell -- # # Paints a border around the cell in the KHIM character map # corresponding to the selected character # # Parameters: # w - Path name of the character map # # Results: # None. # #---------------------------------------------------------------------- proc khim::ShowSelectedCell {w} { variable CMapCodePage variable CMapSelectedCharacter variable CMapXL variable CMapYL variable CMapBackground variable CMapForeground variable CMapSelectBackground variable CMapSelectForeground if { $CMapSelectedCharacter($w) < $CMapCodePage($w) * 0x0100 || $CMapSelectedCharacter($w) >= ($CMapCodePage($w) + 1) * 0x100 } { set CMapSelectedCharacter($w) \ [expr { ($CMapSelectedCharacter($w) % 0x100) + (0x100 * $CMapCodePage($w)) }] } set c $w.c set rem [expr { $CMapSelectedCharacter($w) % 0x0100 }] set row [expr { $rem / 16 }] set col [expr { $rem % 16 }] $c itemconfigure text -fill $CMapForeground($w) $c itemconfigure text&&row$row&&col$col -fill $CMapSelectForeground($w) set xmin [lindex $CMapXL($w) $col] incr col set xmax [lindex $CMapXL($w) $col] set ymin [lindex $CMapYL($w) $row] incr row set ymax [lindex $CMapYL($w) $row] catch { $c delete selectrect } $c create rectangle $xmin $ymin $xmax $ymax \ -width 2 -fill $CMapSelectBackground($w) \ -outline $CMapSelectForeground($w) -tags selectrect $c lower selectrect text return } #---------------------------------------------------------------------- # # khim::CMapSelectedCharacter -- # # Given X and Y co-ordinates in the character map, determines # what character is selected. # # Parameters: # c - The canvas displaying the map. # # Results: # Returns the character, or an empty string if the co-ordinates # do not designate a cell. # #---------------------------------------------------------------------- proc khim::CMapSelectedCharacter {w x y} { variable CMapCodePage variable CMapXL variable CMapYL set row [BSearch $CMapYL($w) $y] set col [BSearch $CMapXL($w) $x] if { $row >= 0 && $row <= 15 && $col >= 0 && $col <= 15 } { return [format %c [expr { 0x100 * $CMapCodePage($w) + 0x10 * $row + $col }]] } else { return {} } } #---------------------------------------------------------------------- # # khim::CMapSelect -- # # Handles mouse selection in the KHIM color map # # Parameters: # c - Path name of the canvas # x, y - Mouse coordinates relative to the canvas # # Results: # None # # Side effects: # Character in the cell containing the pointer is selected, and # the display of the selection is updated. # #---------------------------------------------------------------------- proc khim::CMapSelect {c x y} { variable CMapSelectedCharacter set w [khim::CMapCanvToDialog $c] set ch [khim::CMapSelectedCharacter $w $x $y] if { $ch ne {} } { scan $ch %c CMapSelectedCharacter($w) } ShowSelectedCell $w return } #---------------------------------------------------------------------- # # khim::CMapActivate -- # # Activates the KHIM character map after a mouse selection. # # Parameters: # c - Path name of the canvas # x, y - Mouse coordinates relative to the canvas # # Results: # None # # Side effects: # Directs focus to the canvas, and selects the character designated # by the pointer. # #---------------------------------------------------------------------- proc khim::CMapActivate {c x y} { focus $c khim::CMapSelect $c $x $y return } #---------------------------------------------------------------------- # # khim::CMapHomeEnd -- # # Handles the Home and End keys in the KHIM character map # # Parameters: # c - Path name of the canvas # unit - Unit being homed (word, page, file) # key - 1 for End, 0 for Home # # Results: # None. # # Side effects: # Moves the selection according to the key pressed. # #---------------------------------------------------------------------- proc khim::CMapHome {c unit key} { variable CMapSelectedCharacter set w [khim::CMapCanvToDialog $c] set sc [expr { $unit * ($CMapSelectedCharacter($w) / $unit) + $key * ($unit - 1) }] khim::CMapMoveTo $c $sc return } #---------------------------------------------------------------------- # # khim::CMapMove -- # # Handles several cursor keys (Left, Right, Up, Down, PgUp, # PgDn) in the KHIM character map. # # Parameters: # c - Path name of the canvas # delta - Number of code points to move # # Results: # None. # # Side effects; # Moves the selection by the designated number of codepoints. # #---------------------------------------------------------------------- proc khim::CMapMove {c delta} { variable CMapSelectedCharacter set w [khim::CMapCanvToDialog $c] set sc [expr { $CMapSelectedCharacter($w) + $delta }] if { $sc < 0 } { set sc 0 } elseif { $sc > 0xffff } { set sc 0xffff } khim::CMapMoveTo $c $sc return } #---------------------------------------------------------------------- # # khim:CMapMoveTo -- # # Changes the selection in the KHIM character map to a specified # codepoint. # # Parameters: # c - Path name of the canvas # sc - Code point to select, expressed as an integer # # Results: # None # # Side effects: # Moves the selection to the given character. # #---------------------------------------------------------------------- proc khim::CMapMoveTo { c sc } { variable CMapSelectedCharacter variable CMapCodePage set w [khim::CMapCanvToDialog $c] set cp [expr { $sc / 0x0100 }] set CMapSelectedCharacter($w) $sc if { $cp != $CMapCodePage($w) } { set CMapCodePage($w) $cp } else { ShowSelectedCell $w } return } #---------------------------------------------------------------------- # # CMapKey -- # # Handles non-cursor keypresses in the KHIM character map # # Parameters: # c - Path name of the canvas # char - Character sent by the key # # Results: # None. # # Side effects: # Selects the given character # #---------------------------------------------------------------------- proc khim::CMapKey {c char} { if {$char eq {}} return; # If the key doesn't generate a char, # ignore it. scan $char %c sc CMapMoveTo $c $sc return } #---------------------------------------------------------------------- # # khim::CMapWheel -- # # Handles the mousewheel in the KHIM character map # # Parameters: # c - Path name of the canvas # delta - Amount by which the canvas is to move. # # Return value: # None. # # Side effects: # Adjusts the selection by an appropriately scaled version of 'delta' # #---------------------------------------------------------------------- proc khim::CMapWheel { c delta shifted } { # the delta will vary for OS X and X11/Win32, but we only check # + or - and move accordingly if {$delta > 0} { khim::CMapMove $c [expr {$shifted ? -1 : -16}] } else { khim::CMapMove $c [expr {$shifted ? 1 : 16}] } return } #---------------------------------------------------------------------- # # khim::CMapCanvToDialog -- # # Locates the KHIM character map dialog given the widget path # name of the canvas. # # Parameters: # c - Path name of the canvas # # Results: # Returns the path name of the dialog. # #---------------------------------------------------------------------- proc khim::CMapCanvToDialog {c} { return [winfo parent $c] } #---------------------------------------------------------------------- # # khim::CMapInteractor -- # # Posts the KHIM character map for interacting with the user. # # Parameters: # w - Path name of the text or canvas widget to which the # interactor applies. # # Results: # None. # # Side effects: # Interactor is posted, and the event loop is entered recursively # to handle it. On return, any requested symbol insertion has # already been done. # #---------------------------------------------------------------------- proc khim::CMapInteractor {w} { variable CMapSelectedCharacter variable CMapInputCodePage variable CMapCodePage variable CMapFocus variable CMapBackground variable CMapForeground variable CMapSelectBackground variable CMapSelectForeground set t [winfo toplevel $w] if { $t eq "." } { set t {} } set map $t.khimcmap if {[winfo exists $map]} { wm deiconify $map return } toplevel $map wm withdraw $map wm title $map [mc {Insert Character}] if { ![info exists CMapInputCodePage($map)] } { set CMapInputCodePage($map) 0 set CMapCodePage($map) 0 } grid [label $map.l1 -text [mc {Select code page:}]] \ -row 0 -column 0 -sticky e grid [spinbox $map.spin -textvariable ::khim::CMapInputCodePage($map) \ -width 4] \ -row 0 -column 1 -sticky w # Get canvas background from the background that a text widget would # have had. text $map.text set CMapBackground($map) [$map.text cget -background] set CMapForeground($map) [$map.text cget -foreground] set CMapSelectBackground($map) [$map.text cget -selectbackground] set CMapSelectForeground($map) [$map.text cget -selectforeground] destroy $map.text # Create the dialog set c $map.c grid [canvas $c -width 12c -height 12c \ -bg $CMapBackground($map) -takefocus 1] \ -columnspan 2 -padx 0.75m -pady 0.75m grid [frame $map.f] -row 2 -column 0 -columnspan 2 -sticky ew -pady 0.75m button $map.f.b1 -text [mc OK] -command [list khim::CMapOK $map] button $map.f.b2 -text [mc Cancel] -command [list khim::CMapCancel $map] button $map.f.b3 -text [mc Help...] \ -command [list khim::showHelp $map.help] grid $map.f.b1 -row 0 -column 0 -sticky ew -padx 1.25m grid $map.f.b2 -row 0 -column 1 -sticky ew -padx 1.25m grid $map.f.b3 -row 0 -column 3 -sticky ew -padx 1.25m grid columnconfigure $map.f 2 -weight 1 grid columnconfigure $map.f {0 1 3} -uniform A grid columnconfigure $map 1 -weight 1 bindtags $c [list $c khim::cmap Canvas [winfo toplevel $c] all] trace add variable ::khim::CMapInputCodePage($map) write \ [list khim::CMapUpdateSpinbox $map] after idle [list khim::CMapUpdateSpinbox $map] trace add variable ::khim::CMapCodePage($map) write \ [list khim::CMapDrawCanvas $map] if { ![info exists CMapSelectedCharacter($map)] } { set CMapSelectedCharacter($map) 0x0000 } set CMapFocus($map) $w # Draw the character map in the canvas CMapDrawCanvas $map wm deiconify $map bind $map [list grab $map] bind $map.c [list focus %W] # eeew, tkwait... make this interaction modal tkwait window $map catch { destroy $map } focus $w return } #---------------------------------------------------------------------- # # khim::CMapCopypastedismiss -- # # Handles double-click in the KHIM character map. # # Parameters: # c - Path name of the canvas # x,y - Mouse co-ordinates of the double click # # Results: # None. # # Side effects: # Copies the designated character into the text or entry # that KHIM is using, and dismisses the widget. # #---------------------------------------------------------------------- proc khim::CMapCopypastedismiss {c x y} { CMapSelect $c $x $y CMapOK $c return } #---------------------------------------------------------------------- # # khim::CMapOK # # Handles the 'OK' button in the KHIM character map. # # Parameters: # w - Path name of the dialog # # Results: # None. # # Side effects: # Copies the selected character into the text or entry # that KHIM is using, and dismisses the widget. # #---------------------------------------------------------------------- proc khim::CMapOK {w} { CMapCopy $w CMapPasteToFocus $w CMapCancel $w return } #---------------------------------------------------------------------- # # khim::CMapCopy -- # # Copies a character from the KHIM character map onto the # clipboard. # # Parameters: # w - Path name of the dialog. # # Results: # None. # # Side efffects: # Copies the selected character to the clipboard. # #---------------------------------------------------------------------- proc khim::CMapCopy {w} { variable CMapSelectedCharacter clipboard clear -displayof $w upvar 0 CMapSelectedCharacter([winfo toplevel $w]) ch if { [info exists ch] && $ch ne {} } { clipboard append -displayof $w -- [format %c $ch] } return } #---------------------------------------------------------------------- # # khim::CMapPasteToFocus -- # # Sends a <> event into the window on whose behalf # the KHIM character map was invoked, to copy a character selection # into it. # # Parameters: # w - Path name of the character map dialog. # # Results: # None. # # Side effects: # <> is generated. # #---------------------------------------------------------------------- proc khim::CMapPasteToFocus {w} { variable CMapFocus event generate $CMapFocus([winfo toplevel $w]) <> return } #---------------------------------------------------------------------- # # khim::CMapCancel -- # # Handles the 'Cancel' button in the KHIM character map. # # Parameters: # w - Path name of the character map dialog. # # Results: # None. # # Side effects: # Destroys the dialog without taking further action. # #---------------------------------------------------------------------- proc khim::CMapCancel {w} { destroy [winfo toplevel $w] } #---------------------------------------------------------------------- # # khim::CMapDestroy -- # # Handles the notification in the KHIM character map # # Parameters: # c - Path name of the character map canvas # # Results: # None. # # Side effects: # Cleans up memory for the destroyed widget. # #---------------------------------------------------------------------- proc khim::CMapDestroy {c} { variable CMapFocus variable CMapAfter variable CMapXL variable CMapYL variable CMapSavedColors variable CMapForeground variable CMapBackground variable CMapSelectForeground variable CMapSelectBackground set w [winfo toplevel $c] if {[info exists CMapAfter($w)]} { after cancel $CMapAfter($w) unset CMapAfter($w) } catch {unset CMapFocus($w)} catch {unset CMapXL($w)} catch {unset CMapYL($w)} catch {unset CMapSavedColors($w)} catch {unset CMapForeground($w)} catch {unset CMapSelectForeground($w)} catch {unset CMapBackground($w)} catch {unset CMapSelectBackground($w)} return } # Bindings for the "khim::cmap" bindtag that is used in the character map # dialog bind khim::cmap <1> {khim::CMapSelect %W %x %y} bind khim::cmap {khim::CMapCopypastedismiss %W %x %y} bind khim::cmap {khim::CMapSelect %W %x %y} bind khim::cmap {khim::CMapActivate %W %x %y} bind khim::cmap {khim::CMapMove %W -16; break} bind khim::cmap {khim::CMapMove %W -1; break} bind khim::cmap {khim::CMapMove %W 1; break} bind khim::cmap {khim::CMapMove %W 16; break} bind khim::cmap {khim::CMapMove %W 0x100; break} bind khim::cmap {khim::CMapMove %W -0x100; break} bind khim::cmap {khim::CMapMoveTo %W 0x0000; break} bind khim::cmap {khim::CMapMoveTo %W 0xffff; break} bind khim::cmap {khim::CMapHome %W 0x0100 0; break} bind khim::cmap {khim::CMapHome %W 0x0100 1; break} bind khim::cmap {khim::CMapHome %W 0x010 0; break} bind khim::cmap {khim::CMapHome %W 0x010 1; break} bind khim::cmap {khim::CMapKey %W %A} bind khim::cmap <> {khim::CMapCopy %W} bind khim::cmap <> {khim::CMapCopy %W} bind khim::cmap {khim::CMapOK %W} bind khim::cmap {khim::CMapOK %W} bind khim::cmap {khim::CMapCancel %W} bind khim::cmap {khim::CMapWheel %W %D 0; break} bind khim::cmap {khim::CMapWheel %W %D 1; break} bind khim::cmap {tk::TabToWindow [tk_focusNext %W]; break} bind khim::cmap <> {tk::TabToWindow [tk_focusPrev %W]; break} if { [string equal "x11" [tk windowingsystem]] } { bind khim::cmap <4> {khim::CMapWheel %W 120 0; break} bind khim::cmap <5> {khim::CMapWheel %W -120 0; break} bind khim::cmap {khim::CMapWheel %W 120 1; break} bind khim::cmap {khim::CMapWheel %W -120 1; break} } bind khim::cmap {khim::CMapDestroy %W} # Set initial default configuration khim::setConfig 1.0 1 Pause { !! \u00a1 {"A} \u00c4 {"a} \u00e4 {"E} \u00cb {"e} \u00eb {"I} \u00cf {"i} \u00ef {"O} \u00d6 {"o} \u00f6 {"U} \u00dc {"u} \u00fc 'A \u00c1 'a \u00e1 'E \u00c9 'e \u00e9 'I \u00cd 'i \u00ed 'O \u00d3 'o \u00f3 'U \u00da 'u \u00fa 'Y \u00dd 'y \u00fd *A \u00c5 *a \u00e5 ,C \u00c7 ,c \u00e7 -> \u2192 -L \u0141 -l \u0142 /O \u00d8 /o \u00f8 12 \u00bd 13 \u2153 14 \u00bc 18 \u215b 23 \u2154 34 \u00be 38 \u215c 58 \u215d 78 \u215e :( \u2639 :) \u263a <- \u2190 << \u00ab >> \u00bb ?? \u00bf ^A \u00c2 ^a \u00e2 ^E \u00ca ^e \u00ea ^I \u00ce ^i \u00ee ^O \u00d4 ^o \u00f4 ^U \u00db ^u \u00fb `A \u00c0 `a \u00e0 `E \u00c8 `e \u00e8 `I \u00cc `i \u00ec `O \u00d2 `o \u00f2 `U \u00d9 `u \u00f9 AA \u00c5 aa \u00e5 AE \u00c6 ae \u00e6 bu \u2022 de \u00b0 eu \u20ac LP \u2615 mu \u00b5 OE \u0152 oe \u0153 OC \u00a9 OR \u00ae ss \u00df |c \u00a2 ~A \u00c3 ~a \u00e3 ~N \u00d1 ~n \u00f1 ~O \u00d5 ~o \u00f5 } # Set initial bindings on the KHIM bind tag. khim::RedoBindings set khim::CMapFont [font create -family helvetica -size 15] set khim::CMapBadCharFont [font create -family courier -size 8] # Test program if {[info exists ::argv0] && ![string compare $::argv0 [info script]]} { grid [entry .e -font {Courier 18}] -columnspan 5 -sticky ew .e insert end {Type here} bindtags .e {.e KHIM Entry . all} grid [button .test -text "Test" -command "khim::getOptions .khim"] \ [button .bload -text "Load config" -command "testLoadConfig"] \ [button .bsave -text "Save config" -command "testSaveConfig"] \ [button .bhelp -text "Help" -command "khim::showHelp .help"] \ [button .bquit -text "Quit" -command "exit"] \ -padx 1.25m -pady 1.25m proc testLoadConfig {} { source $::env(HOME)/.khimrc } proc testSaveConfig {} { set f [open $::env(HOME)/.khimrc w] puts $f [khim::getConfig] close $f } } tkabber-plugins/tkabber-khim/khim/pkgIndex.tcl000064400000000000000000000010261500237002100212550ustar00nobodynobody# Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. package ifneeded khim 1.0.1 [list source [file join $dir khim.tcl]] tkabber-plugins/tkabber-khim/khim/pl.msg000064400000000000000000000100311500237002100201170ustar00nobodynobody# pl.msg -- # # Polish-language messages for KHIM # Contributed by Irek Chmielowiec # Copyright (c) 2005 by Kevin B. Kenny. All rights reserved. # # Refer to the file "license.terms" for the terms and conditions of # use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES. # #---------------------------------------------------------------------- namespace eval ::khim { # If you edit HELPTEXT or {SELECT COMPOSE KEY}, also edit the corresponding # messages in ROOT.msg ::msgcat::mcset pl HELPTEXT { Kevin's Hacky Input Method (KHIM) KHIM pozwala na wprowadzanie znaków narodowych i symboli z klawiatury która tego nie obsÅ‚uguje. DziaÅ‚a niezależnie od metody wprowadzania znaków jakÄ… może oferować system operacyjny; jest przewidziany do sytuacji kiedy nie ma siÄ™ kontroli nad odwzorowaniem klawiszy a istnieje potrzeba wprowadzania tekstu w różnych jÄ™zykach. Aby móc używać KHIM, uruchom okno UstawieÅ„ KHIM (sposób jego uruchomienia zależy od używanej aplikacji) i włącz KHIM zaznaczajÄ…c opcjÄ™ "Włącz KHIM". Należy także wybrać klawisz który jest rzadko używany i przypisać mu funkcjÄ™ klawisza "sterujÄ…cego" naciskajÄ…c przycisk "Klawisz sterujÄ…cy:", a nastÄ™pnie naciskajÄ…c klawisz któremu chcemy tÄ™ funkcjÄ™ przypisać. MówiÄ…c ogólnie, nie powinien to być klawisz ustawiony jako sterujÄ…cy dla używanego ukÅ‚adu klawiatury (np. Alt); klawisz ten bÄ™dzie dziaÅ‚aÅ‚ niezależnie od metody wprowadzania znaków oferowanej przez lokalny system operacyjny. Kiedy KHIM jest już uruchomiony, można wprowadzać znaki narodowe i symbole w każdym elemencie interfejsu użytkownika, który zostaÅ‚ ustawiony do korzystania z KHIM, naciskajÄ…c klawisz sterujÄ…cy razem z sekwencjÄ… dwóch znaków. Lista wyboru w ustawieniach KHIM pokazuje dostÄ™pne kombinacje. Dodatkowo, po dwukrotnym naciÅ›niÄ™ciu klawisza sterujÄ…cego pojawi siÄ™ okno pozwalajÄ…ce na bezpoÅ›rednie wstawienie wybranego znaku z tablicy symboli Unicode. W oknie tablicy można nawigować pomiÄ™dzy znakami używajÄ…c klawiszy kursorów lub za pomocÄ… myszy a wybór znaku nastÄ™puje przez dwukrotne klikniÄ™cie, naciÅ›niÄ™cie spacji lub naciÅ›niÄ™cie klawisza Enter (Return). Aby zdefiniować nowÄ… sekwencjÄ™ do użycia z klawiszem sterujÄ…cym należy uruchomić ustawienia KHIM, wprowadzić dwa znaki w polu "Sekwencja znaków" i znak jaki chcemy uzyskać w polu "Wynik" oraz nacisnąć przycisk "ZmieÅ„". (Można także skopiować i wkleić znak z innej aplikacji lub użyć przycisku "Tablica Unicode..." (także przez dwukrotne naciÅ›niÄ™cie klawisza sterujÄ…cego) do wyboru znaku z tablicy wszystkich dostÄ™pnych kodów Unicode.) Aby usunąć sekwencjÄ™ znaków, należy wybrać jÄ… z listy i nacisnąć "UsuÅ„". } ::msgcat::mcset pl {SELECT COMPOSE KEY} [string map [list \n\t \n] { ProszÄ™ nacisnąć klawisz który ma być używany jako sterujÄ…cy. }] ::msgcat::mcset pl {Apply} {Zastosuj} ::msgcat::mcset pl {Cancel} {Anuluj} ::msgcat::mcset pl {Change} {ZmieÅ„} ::msgcat::mcset pl {Character} {Wynik} ::msgcat::mcset pl {Compose Key} {Klawisz sterujÄ…cy} ::msgcat::mcset pl {Compose key:} {Klawisz sterujÄ…cy:} ::msgcat::mcset pl {Composed sequence must be two characters long} \ {Sekwecja znaków musi być dwuelementowa} ::msgcat::mcset pl {Delete} {UsuÅ„} ::msgcat::mcset pl {KHIM Help} {Pomoc KHIM} ::msgcat::mcset pl {Help...} {Pomoc...} ::msgcat::mcset pl {Input key sequence} {Sekwencja znaków} ::msgcat::mcset pl {Insert Character} {Wstaw znak} ::msgcat::mcset pl {Invalid sequence} {NieprawidÅ‚owa sekwencja} ::msgcat::mcset pl {Key sequences} {Sekwencje znaków} ::msgcat::mcset pl {KHIM Controls} {Ustawienia KHIM} ::msgcat::mcset pl {OK} {OK} ::msgcat::mcset pl {Select code page:} {Wybierz kodowanie:} ::msgcat::mcset pl {Unicode...} {Tablica Unicode...} ::msgcat::mcset pl {Use KHIM} {Włącz KHIM} } # vim:ft=tcl:ts=8:sw=4:sts=4:noet # Local Variables: # mode: tcl # End: tkabber-plugins/tkabber-khim/khim/ru.msg000064400000000000000000000150271500237002100201440ustar00nobodynobody# ru.msg -- # # Russian-language messages for KHIM # # Contributed by Konstantin Khomoutov . # Proof-read and edited by Serge Yudin . # # Copyright (c) 2005 by Kevin B. Kenny. All rights reserved. # # Refer to the file "license.terms" for the terms and conditions of # use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES. # # $Id: ru.msg,v 1.1 2007/06/08 19:24:31 kennykb Exp $ # $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/ru.msg,v $ # #---------------------------------------------------------------------- namespace eval ::khim { # If you edit HELPTEXT or {SELECT COMPOSE KEY}, also edit the corresponding # messages in ROOT.msg ::msgcat::mcset ru HELPTEXT { Kevin's Hacky Input Method (KHIM) -- Ðетривиальный Метод Кевина Ð´Ð»Ñ Ð’Ð²Ð¾Ð´Ð° Символов KHIM делает возможным ввод Ñимволов национальных алфавитов Ñ ÐºÐ»Ð°Ð²Ð¸Ð°Ñ‚ÑƒÑ€Ñ‹, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð½Ðµ позволÑÑŽÑ‚ Ñтого делать. Он работает незавиÑимо от любых ÑпоÑобов ввода, которые поддерживает ОС; его задача -- позволить оÑущеÑтвлÑть ввод таких Ñимволов, которые невозможно ввеÑти Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ð¼Ð¸ наÑтройками ОС данного компьютера, а менÑть их нет возможноÑти или желаниÑ. Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы иÑпользовать KHIM, Ñледует вызвать диалог "ÐаÑтройки KHIM" (как Ñто Ñделать, завиÑит от приложениÑ, иÑпользующего KHIM) и разрешить работу KHIM, включив переключатель "ИÑпользовать KHIM". Также Вам понадобитÑÑ Ð²Ñ‹Ð±Ñ€Ð°Ñ‚ÑŒ редко иÑпользуемую клавишу на Вашей клавиатуре и назначить её "клавишей композиции". Ð”Ð»Ñ Ñтого нужно нажать кнопку, подпиÑанную "Клавиша композиции:", в диалоге наÑтроек KHIM и затем нажать выбранную клавишу на клавиатуре. Имейте в виду, что еÑли на Вашей клавиатуре еÑть клавиша, Ð½Ð°Ð·Ñ‹Ð²Ð°ÐµÐ¼Ð°Ñ "Compose", то её не Ñледует выбирать в качеÑтве клавиши композиции Ð´Ð»Ñ KHIM -- пуÑть она продолжает вызывать тот метод ввода, который назначен ей операционной ÑиÑтемой. ПоÑле того как KHIM активирован, Ð’Ñ‹ можете вÑтавлÑть Ñимволы национальных алфавитов в любое поле ввода, наÑтроенное на иÑпользование KHIM, таким образом: нажать и отпуÑтить клавишу композиции, затем ввеÑти два Ñимвола -- "входную поÑледовательноÑть". Ð’ диалоге наÑтроек KHIM еÑть окно Ñо ÑпиÑком доÑтупных поÑледовательноÑтей. Кроме того, двойное нажатие клавиши композиции вызывает окно диалога, позволÑющее выбрать произвольный Ñимвол Unicode. Выбор нужного Ñимвола в Ñтом диалоге оÑущеÑтвлÑетÑÑ Ð¼Ñ‹ÑˆÑŒÑŽ либо клавишами ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÑƒÑ€Ñором, а вÑтавка выбранного Ñимвола -- двойным щелчком левой кнопки мыши на нём, либо нажатием клавиши Пробел или Ввод. Чтобы Ñоздать новую входную поÑледовательноÑть Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÑовмеÑтно Ñ ÐºÐ»Ð°Ð²Ð¸ÑˆÐµÐ¹ композиции окройте диалог наÑтроек KHIM, введите два Ñимвола в поле "Ð’Ñ…Ð¾Ð´Ð½Ð°Ñ Ð¿Ð¾ÑледовательноÑть" и ÑоответÑтвующий ей Ñимвол в поле "Символ", затем нажмите кнопку "Изменить". (Ð’Ñ‹ можете копировать и вÑтавлÑть целевой Ñимвол из другого приложениÑ. Также можно воÑпользоватьÑÑ Ð²Ñтроенным в KHIM диалогом выбора Ñимволов Unicode, нажав кнопку "Unicode..." или дважды нажав клавишу композиции.) Ð”Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð²Ñ…Ð¾Ð´Ð½Ð¾Ð¹ поÑледовательноÑти выберите её в ÑпиÑке и дажмите "Удалить". } ::msgcat::mcset ru {SELECT COMPOSE KEY} [string map [list \n\t \n] { Ðажмите клавишу, которую вы хотите иÑпользовать в качеÑтве "Клавиши композиции" }] ::msgcat::mcset ru {Apply} {Применить} ::msgcat::mcset ru {Cancel} {Отменить} ::msgcat::mcset ru {Change} {Изменить} ::msgcat::mcset ru {Character} {Символ} ::msgcat::mcset ru {Compose Key} {Клавиша композиции} ::msgcat::mcset ru {Compose key:} {Клавиша композиции:} ::msgcat::mcset ru {Composed sequence must be two characters long} \ {Ð’Ñ…Ð¾Ð´Ð½Ð°Ñ Ð¿Ð¾ÑледовательноÑть должна ÑоÑтоÑть из двух Ñимволов} ::msgcat::mcset ru {Delete} {Удалить} ::msgcat::mcset ru {KHIM Help} {Справка по KHIM} ::msgcat::mcset ru {Help...} {Справка...} ::msgcat::mcset ru {Input key sequence} {Ð’Ñ…Ð¾Ð´Ð½Ð°Ñ Ð¿Ð¾ÑледовательноÑть} ::msgcat::mcset ru {Insert Character} {Выберите Ñимвол} ::msgcat::mcset ru {Invalid sequence} {ÐÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ð¼Ð±Ð¸Ð½Ð°Ñ†Ð¸Ñ} ::msgcat::mcset ru {Key sequences} {Комбинации клавиш} ::msgcat::mcset ru {KHIM Controls} {ÐаÑтройки KHIM} ::msgcat::mcset ru {OK} {OK} ::msgcat::mcset ru {Select code page:} {Выберите Ñтраницу кодов:} ::msgcat::mcset ru {Unicode...} {Unicode...} ::msgcat::mcset ru {Use KHIM} {ИÑпользовать KHIM} } # vim:ft=tcl:ts=8:sw=4:sts=4:noet # Local Variables: # mode: tcl # End: tkabber-plugins/tkabber-khim/khim/uk.msg000064400000000000000000000143311500237002100201320ustar00nobodynobody# uk.msg -- # # Ukrainian-language messages for KHIM # # Contributed by Fixer jabber:, email:. # # Copyright (c) 2005 by Kevin B. Kenny. All rights reserved. # #---------------------------------------------------------------------- namespace eval ::khim { # If you edit HELPTEXT or {SELECT COMPOSE KEY}, also edit the corresponding # messages in ROOT.msg ::msgcat::mcset uk HELPTEXT { Kevin's Hacky Input Method (KHIM) -- Ðетривіальний Метод Кевіна Ð´Ð»Ñ Ð’Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð¡Ð¸Ð¼Ð²Ð¾Ð»Ñ–Ð² KHIM дає можливіÑть вводити Ñимволи національних алфавітів з клавіатури, Ñка не дозволÑÑ” цього робити. Він працює незалежно від інших ÑпоÑобів вводу, котрі підтримує ОС; його Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ -- дати змогу здійÑнювати Ð²Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ñ‚Ð°ÐºÐ¸Ñ… Ñимволів, котрі неможливо ввеÑти з теперішніми налаштуваннÑми ОС даного компьютера, а помінÑти Ñ—Ñ… немає ні можливоÑті, ні бажаннÑ. Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб кориÑтуватиÑÑ KHIM, треба відкрити діалог "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ KHIM" (Ñк це зробити, залежить від програми, Ñка викориÑтовує KHIM) Ñ– дозволити роботу KHIM, увімкнувши перемикач "ВикориÑтовувати KHIM". Також Вам необхідно обрати рідко викориÑтовувану клавішу на Вашій клавіатурі Ñ– призначити Ñ—Ñ— "клавішою композиції". Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ потрібно натиÑнути кнопку, підпиÑану Ñк "Клавіша композиції:", у діалозі налаштувань KHIM, а потім натиÑнути обрану клавішу на клавіатурі. Майте на увазі, що Ñкшо на Вашій клавіатурі Ñ” клавіша, що зветьÑÑ "Compose", то Ñ—Ñ— не треба обирати в ÑкоÑті клавіши композиції Ð´Ð»Ñ KHIM -- хай вона продовжує викликати той метод вводу, котрий призначений їй операційною ÑиÑтемою. ПіÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾ Ñк KHIM активувавÑÑ, Ви можете вÑтавлÑти Ñимволи національних алфавітів в будь-Ñке поле Ð´Ð»Ñ Ð²Ð²Ð¾Ð´Ñƒ, налаштоване на викориÑÑ‚Ð°Ð½Ð½Ñ KHIM, таким чином: натиÑнути Ñ– відпуÑтити клавішу композиції, а потім ввеÑти два Ñимволи -- "вхідну поÑлідовніÑть". У діалозі налаштувань KHIM Ñ” вікно з переліком доÑтупних поÑлідовноÑтей. Крім того, подвійне натиÑÐºÐ°Ð½Ð½Ñ ÐºÐ»Ð°Ð²Ñ–ÑˆÑ– композиції викликає вікно діалогу, що дозволÑÑ” обрати довільний Ñимвол Unicode. Вибір потрібного Ñимволу в цьому діалозі здійÑнюєтьÑÑ Ð¼Ð¸ÑˆÐ¾ÑŽ чи клавішами ÑƒÐ¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ ÐºÑƒÑ€Ñором, а вÑтавлÑÐ½Ð½Ñ Ð¾Ð±Ñ€Ð°Ð½Ð¾Ð³Ð¾ Ñимолу -- подвійним клацаннÑм лівої кнопки миші на ньому, або натиÑканнÑм клавіши Пробіл чи Ввід. Щоб Ñтворити нову вхідну поÑлідовніÑть Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ ÑуміÑно з клавішою композиції відкрийте діалог налаштувань KHIM, введіть два Ñимволи в поле "Вхідна поÑлідовніÑть" Ñ– відповідний їй Ñимвол у полі "Символ", а потім натиÑніть клавішу "Змінити". (Ви можете копіювати Ñ– вÑтавлÑти цільовий Ñимвол з іншої програми. Також можна ÑкориÑтатиÑÑ Ð²Ð±ÑƒÐ´Ð¾Ð²Ð°Ð½Ð¸Ð¼ у KHIM діалогом вибору Ñимволів Unicode, натиÑнувши кнопку "Unicode...", або подвійно клацнувши клавішу композиції.) Ð”Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð²Ñ…Ñ–Ð´Ð½Ð¾Ñ— поÑлідовноÑті оберіть Ñ—Ñ— у переліку Ñ– натиÑніть "Видалити." } ::msgcat::mcset uk {SELECT COMPOSE KEY} [string map [list \n\t \n] { ÐатиÑніть клавішу, котру ви бажаєте викориÑтовувати в ÑкоÑті "Клавіші композиції" }] ::msgcat::mcset uk {Apply} {ПрийнÑти} ::msgcat::mcset uk {Cancel} {Відмінити} ::msgcat::mcset uk {Change} {Змінити} ::msgcat::mcset uk {Character} {Символ} ::msgcat::mcset uk {Compose Key} {Клавіша композиції} ::msgcat::mcset uk {Compose key:} {Клавіша композиції:} ::msgcat::mcset uk {Composed sequence must be two characters long} \ {Вхідна поÑлідовніÑть повинна ÑкладатиÑÑ Ð· двох Ñимволів} ::msgcat::mcset uk {Delete} {Видалити} ::msgcat::mcset uk {KHIM Help} {Допомога по KHIM} ::msgcat::mcset uk {Help...} {Допомога...} ::msgcat::mcset uk {Input key sequence} {Вхідна поÑлідовніÑть} ::msgcat::mcset uk {Insert Character} {Оберіть Ñимвол} ::msgcat::mcset uk {Invalid sequence} {Ðеправильна комбінаціÑ} ::msgcat::mcset uk {Key sequences} {Комбінації клавіш} ::msgcat::mcset uk {KHIM Controls} {ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ KHIM} ::msgcat::mcset uk {OK} {OK} ::msgcat::mcset uk {Select code page:} {Оберіть кодову Ñторінку:} ::msgcat::mcset uk {Unicode...} {Unicode...} ::msgcat::mcset uk {Use KHIM} {ВикориÑтовувати KHIM} } # vim:ft=tcl:ts=8:sw=4:sts=4:noet # Local Variables: # mode: tcl # End: tkabber-plugins/tkabber-khim/msgs000075500000000000000000000000001500237002100167435ustar00nobodynobodytkabber-plugins/tkabber-khim/msgs/es.msg000064400000000000000000000007611500237002100201450ustar00nobodynobody# es.msg -- # # Spanish messages for the Tkabber-khim plugin. # # Author: Badlop ::msgcat::mcset es "KHIM options" "Opciones de KHIM" ::msgcat::mcset es "Problem loading KHIM. Tkabber-khim functionality will be\ disabled.\nRefer to the INSTALL file of the tkabber-khim plugin." \ "Hubo un problema cargando KHIM.\nLa funcionalidad se ha desactivado\ en Tkabber.\nConsulta el fichero INSTALL del directorio de\ tkabber-khim." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/tkabber-khim/msgs/pl.msg000064400000000000000000000010531500237002100201440ustar00nobodynobody# pl.msg -- # # Polish messages for the Tkabber-khim plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "KHIM options" "Ustawienia wtyczki KHIM" ::msgcat::mcset pl "Problem loading KHIM. Tkabber-khim functionality will be\ disabled.\nRefer to the INSTALL file of the tkabber-khim plugin." \ "WystÄ…piÅ‚ problem podczas Å‚adowania wtyczki KHIM.\nFunkcje dostÄ™pne\ przez wtyczkÄ™ bÄ™dÄ… wyłączone.\nSprawdź instrukcje w pliku INSTALL w\ katalogu wtyczki." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/tkabber-khim/msgs/ru.msg000064400000000000000000000011501500237002100201550ustar00nobodynobody# ru.msg -- # # Russian messages for the Tkabber-khim plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "KHIM options" "ÐаÑтройки KHIM" ::msgcat::mcset ru "Problem loading KHIM. Tkabber-khim functionality will be\ disabled.\nRefer to the INSTALL file of the tkabber-khim plugin." \ "Ðе удалоÑÑŒ загрузить KHIM. РаÑширение Tkabber-khim не будет\ активизирован.\nОбратитеÑÑŒ к файлу INSTALL в каталоге Ñ Ñ€Ð°Ñширением\ tkabber-khim." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/tkabber-khim/msgs/uk.msg000064400000000000000000000011721500237002100201520ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Tkabber-khim plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "KHIM options" "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ KHIM" ::msgcat::mcset uk "Problem loading KHIM. Tkabber-khim functionality will be\ disabled.\nRefer to the INSTALL file of the tkabber-khim plugin." \ "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ KHIM. Ð Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Tkabber-khim не буде\ активований.\nЗвернітьÑÑ Ð´Ð¾ файлу INSTALL в деці, Ñка міÑтить\ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ tkabber-khim." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/tkabber-khim/tkabber-khim.tcl000064400000000000000000000064131500237002100211210ustar00nobodynobody# tkabber-khim.tcl -- # # Tkabber plugin adding KHIM functionality to Tkabber's Text and Entry # widgets. # # Author: Konstantin Khomoutov . # KHIM author: Kevin B Kenny . # # Read more about KHIM: http://wiki.tcl.tk/16343 # # To use this plugin you either need KHIM and autoscroll packegs themselves, # or the fresh tklib, which KHIM is now a part of. # Refer to INSTALL file for details. # TODO eval'ing of KHIM settings looks unsafe. # TODO it would be better not to subvert ::entry and ::text commands. namespace eval khim { # If the directory named "khim" is available locally, use it. # This makes possible to distribute KHIM and autoscroll bundled # with this plugin (and lift the dependency on tklib). variable scriptdir [file dirname [info script]] variable local_khim [file join $scriptdir khim] if {[file isdirectory $local_khim]} { lappend ::auto_path $scriptdir package forget khim } # Load message catalog: package require msgcat ::msgcat::mcload [file join $scriptdir msgs] # Attempt to load KHIM. Warn and quit loading plugin if we can't: variable err if {[catch { package require khim } err]} { # TODO why didn't tk_messageBox work here? puts stderr $err puts stderr [::msgcat::mc "Problem loading KHIM. Tkabber-khim\ functionality will be\ disabled.\nRefer to the INSTALL file\ of the tkabber-khim plugin."] # Clean up what's already here and bail out: namespace delete [namespace current] return } # Configuration section: variable settings custom::defvar settings {} \ "KHIM subsystem settings" \ -group Hidden \ -type string # Event handlers: # This handler should be called after Customize DB has been restored # which occurs in postload_hook at priority 60. ::hook::add postload_hook [namespace current]::restore_settings 70 ::hook::add finload_hook [namespace current]::on_init # The trickery (see http://wiki.tcl.tk/16343): auto_load Entry rename ::Entry ::khim::Entry rename ::text ::khim::text proc ::Entry {w args} { eval [linsert $args 0 ::khim::Entry $w] bindtags $w [linsert [bindtags $w] 1 KHIM] return $w } proc ::text {w args} { eval [linsert $args 0 ::khim::text $w] bindtags $w [linsert [bindtags $w] 1 KHIM] return $w } } # Passes the KHIM settings restored from the Customize DB # to the KHIM subsystem: proc khim::restore_settings {args} { variable settings catch {eval $settings} } # Invokes the KHIM's options dialog, # then saves current KHIM options. # Intended to be invoked via Tkabber menus, etc. proc khim::edit_options {} { variable settings ::khim::getOptions .tkabber_khim_options set settings [::khim::getConfig] } # Creates an entry for KHIM in the "Services->Plugins" Tkabber menu: proc khim::on_init {} { set menu [.mainframe getmenu plugins] $menu add command \ -label [::msgcat::mc "KHIM options"] \ -command [namespace current]::edit_options } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/tkabber-khim/tklib_licence.terms000064400000000000000000000041521500237002100217160ustar00nobodynobodyThis software is copyrighted by Ajuba Solutions and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. tkabber-plugins/traffic000075500000000000000000000000001500237002100150505ustar00nobodynobodytkabber-plugins/traffic/Changelog000064400000000000000000000001001500237002100167300ustar00nobodynobodyhttp://wiki.tkabber.jabe.ru/index.php/Plugins/Traffic/Changelog tkabber-plugins/traffic/msgs000075500000000000000000000000001500237002100160215ustar00nobodynobodytkabber-plugins/traffic/msgs/de.msg000064400000000000000000000030221500237002100171750ustar00nobodynobody# de.msg -- # # German messages for the Traffic accounting Tkabber plugin. # # Author: Roger Sondermann # Last-Modified: 26.03.2009 ::msgcat::mcset de "All IN" "Alle <-" ::msgcat::mcset de "All OUT" "Alle ->" ::msgcat::mcset de "Are you sure you want to reset counters?" \ "Wirklich alle Zähler zurücksetzen?" ::msgcat::mcset de "Iq IN" "IQ <-" ::msgcat::mcset de "Iq OUT" "IQ ->" ::msgcat::mcset de "JID" "JID" ::msgcat::mcset de "Msg IN" "Nachr. <-" ::msgcat::mcset de "Msg OUT" "Nachr. ->" ::msgcat::mcset de "Off" "Aus" ::msgcat::mcset de "On" "An" ::msgcat::mcset de "Plugins options." "Optionen für Plugins." ::msgcat::mcset de "Pres IN" "Präs. <-" ::msgcat::mcset de "Pres OUT" "Präs. ->" ::msgcat::mcset de "Refresh" "Abfragen" ::msgcat::mcset de "Reset" "Zurücksetzen" ::msgcat::mcset de "Save" "Speichern" ::msgcat::mcset de "Show XML" "XML" ::msgcat::mcset de "Show nick instead of JID." \ "Nicknamen an Stelle JID anzeigen." ::msgcat::mcset de "Timer:" "Intervall:" ::msgcat::mcset de "Total" "Datenverkehr insgesamt:" ::msgcat::mcset de "Traffic Counter plugin options." \ "Optionen für das Datenverkehr-Plugin." ::msgcat::mcset de "Traffic statistics" "Datenverkehr-Statistik" ::msgcat::mcset de "Traffic" "Datenverkehr-Statistik" ::msgcat::mcset de "Use human-readable counters with K, M, G." \ "Menschen-lesbare Zähler mit K, M, G benutzen." ::msgcat::mcset de "Whether the Traffic Counter plugin is loaded." \ "Datenverkehr-Statistik-Plugin laden." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/traffic/msgs/es.msg000064400000000000000000000027031500237002100172210ustar00nobodynobody# es.msg -- # # Spanish messages for the Traffic accounting Tkabber plugin. # # Author: Badlop ::msgcat::mcset es "All IN" "Todo IN" ::msgcat::mcset es "All OUT" "Todo OUT" ::msgcat::mcset es "Are you sure you want to reset counters?" \ "¿Estás seguro de que deseas reiniciar los contadores?" ::msgcat::mcset es "Iq IN" "Iq IN" ::msgcat::mcset es "Iq OUT" "Iq OUT" ::msgcat::mcset es "JID" "JID" ::msgcat::mcset es "Msg IN" "Msg IN" ::msgcat::mcset es "Msg OUT" "Msg OUT" ::msgcat::mcset es "Off" "No" ::msgcat::mcset es "On" "Sí" ::msgcat::mcset es "Plugins options." "Opciones de plugin." ::msgcat::mcset es "Pres IN" "Pres IN" ::msgcat::mcset es "Pres OUT" "Pres OUT" ::msgcat::mcset es "Refresh" "Actualizar" ::msgcat::mcset es "Reset" "Reiniciar" ::msgcat::mcset es "Save" "Guardar" ::msgcat::mcset es "Show XML" "Mostrar XML" ::msgcat::mcset es "Show nick instead of JID." "Mostrar apodo en vez del JID." ::msgcat::mcset es "Timer:" "Reloj:" ::msgcat::mcset es "Total" "Total" ::msgcat::mcset es "Traffic Counter plugin options." \ "Opciones del plugin Contador de Tráfico." ::msgcat::mcset es "Traffic statistics" "Estadísticas de tráfico" ::msgcat::mcset es "Traffic" "Tráfico" ::msgcat::mcset es "Use human-readable counters with K, M, G." \ "Usar contadores legibles con K, M, G." ::msgcat::mcset es "Whether the Traffic Counter plugin is loaded." \ "Cargar el plugin Traffic Counter." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/traffic/msgs/pl.msg000064400000000000000000000027751500237002100172360ustar00nobodynobody# pl.msg -- # # Polish messages for the Traffic accountind Tkabber plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "JID" "JID" ::msgcat::mcset pl "Plugins options." "Ustawienia wtyczek." ::msgcat::mcset pl "Pres IN" "Status WCH" ::msgcat::mcset pl "Pres OUT" "Status WYCH" ::msgcat::mcset pl "Iq IN" "Iq WCH" ::msgcat::mcset pl "Iq OUT" "Iq WYCH" ::msgcat::mcset pl "Msg IN" "Wiad WCH" ::msgcat::mcset pl "Msg OUT" "Wiad WYCH" ::msgcat::mcset pl "All IN" "Wsz WCH" ::msgcat::mcset pl "All OUT" "Wsz WYCH" ::msgcat::mcset pl "On" "Włącz" ::msgcat::mcset pl "Off" "Wyłącz" ::msgcat::mcset pl "Show nick instead of JID." \ "Pokaż nazwy kontaktów zamiast JID." ::msgcat::mcset pl "Use human-readable counters with K, M, G." \ "Użyj jednostek Å‚atwych do odczytania (Kilo, Mega, Giga)." ::msgcat::mcset pl "Traffic statistics" "Statystyka ruchu" ::msgcat::mcset pl "Traffic" "Statystyka ruchu" ::msgcat::mcset pl "Refresh" "OdÅ›wież" ::msgcat::mcset pl "Show XML" "Pokaż konsolÄ™ XML" ::msgcat::mcset pl "Reset" "Wyzeruj" ::msgcat::mcset pl "Save" "Zapisz" ::msgcat::mcset pl "Timer:" ::msgcat::mcset pl "Total" "Razem" ::msgcat::mcset pl "Are you sure you want to reset counters?" \ "Czy na pewno wyzerować liczniki?" ::msgcat::mcset pl "Traffic Counter plugin options." \ "Ustawienia wtyczki statystyki ruchu." ::msgcat::mcset pl "Whether the Traffic Counter plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ statystyki ruchu." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/traffic/msgs/ru.msg000064400000000000000000000031751500237002100172440ustar00nobodynobody# ru.msg -- # # Russian messages for the Traffic accountind Tkabber plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Pres IN" ::msgcat::mcset ru "Pres OUT" ::msgcat::mcset ru "Iq IN" ::msgcat::mcset ru "Iq OUT" ::msgcat::mcset ru "Msg IN" ::msgcat::mcset ru "Msg OUT" ::msgcat::mcset ru "All IN" ::msgcat::mcset ru "All OUT" ::msgcat::mcset ru "On" "Вкл" ::msgcat::mcset ru "Off" "Выкл" ::msgcat::mcset ru "Plugins options." "Параметры раÑширений." ::msgcat::mcset ru "Show nick instead of JID." "Показывать ник вмеÑто JID-а." ::msgcat::mcset ru "Use human-readable counters with K, M, G." \ "ИÑпользовать читабельные Ñчетчики Ñ K, M, G." ::msgcat::mcset ru "Traffic statistics" "СтатиÑтика по трафику" ::msgcat::mcset ru "Traffic" "Трафик" ::msgcat::mcset ru "Refresh" "Обновить" ::msgcat::mcset ru "Show XML" "XML" ::msgcat::mcset ru "Save" "Сохранить" ::msgcat::mcset ru "Reset" "СброÑить" ::msgcat::mcset ru "Timer:" "Таймер:" ::msgcat::mcset ru "JID" ::msgcat::mcset ru "Total" "Ð’Ñего" ::msgcat::mcset ru "Are you sure you want to reset counters?" \ "Ð’Ñ‹ уверены, что хотите ÑброÑить Ñчетчики?" ::msgcat::mcset ru "Traffic Counter plugin options." \ "ÐаÑтройки раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ ÑÐ»ÐµÐ¶ÐµÐ½Ð¸Ñ Ð·Ð° трафиком." ::msgcat::mcset ru "Whether the Traffic Counter plugin is loaded." \ "Загружено ли раÑширение ÑÐ»ÐµÐ¶ÐµÐ½Ð¸Ñ Ð·Ð° трафиком." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/traffic/msgs/uk.msg000064400000000000000000000032401500237002100172260ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Traffic accountind Tkabber plugin. # # Author: Artem Bondarenko # Author: Sergei Golovan ::msgcat::mcset uk "Pres IN" ::msgcat::mcset uk "Pres OUT" ::msgcat::mcset uk "Iq IN" ::msgcat::mcset uk "Iq OUT" ::msgcat::mcset uk "Msg IN" ::msgcat::mcset uk "Msg OUT" ::msgcat::mcset uk "All IN" ::msgcat::mcset uk "All OUT" ::msgcat::mcset uk "On" "Увімкнути" ::msgcat::mcset uk "Off" "Вимкнути" ::msgcat::mcset uk "Plugins options." "Параметри плагінів." ::msgcat::mcset uk "Show nick instead of JID." "Показувати нік заміÑть JID-а." ::msgcat::mcset uk "Use human-readable counters with K, M, G." \ "ВикориÑтовувати читабельні лічильники з K, M, G." ::msgcat::mcset uk "Traffic statistics" "СтатиÑтика по трафіку" ::msgcat::mcset uk "Traffic" "Трафік" ::msgcat::mcset uk "Refresh" "Оновити" ::msgcat::mcset uk "Show XML" "XML" ::msgcat::mcset uk "Save" "Зберегти" ::msgcat::mcset uk "Reset" "Скинути" ::msgcat::mcset uk "Timer:" "Таймер:" ::msgcat::mcset uk "JID" ::msgcat::mcset uk "Total" "Ð’Ñього" ::msgcat::mcset uk "Are you sure you want to reset counters?" \ "Ви впевнені, що хочете Ñкинути лічильники?" ::msgcat::mcset uk "Traffic Counter plugin options." \ "Параметри Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð¿Ð¾ підрахунку трафіка." ::msgcat::mcset uk "Whether the Traffic Counter plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ñке підраховує трафік." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/traffic/traffic.tcl000064400000000000000000000362471500237002100172650ustar00nobodynobody# traffic.tcl -- # # This plugin counts in and out bytes per JID. # # Bugs and feature request send to feez@jabber.ru package require msgcat namespace eval traffic { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered traffic]} { ::plugins::register traffic \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Traffic\ Counter plugin is\ loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } # Options custom::defgroup Plugins [::msgcat::mc "Plugins options."] -group Tkabber custom::defgroup Traffic [::msgcat::mc "Traffic Counter plugin options."] \ -group Plugins custom::defvar options(show_nick) 1 \ [::msgcat::mc "Show nick instead of JID."] \ -type boolean -group Traffic \ -command [namespace code clear_and_refresh] custom::defvar options(human_readable) 1 \ [::msgcat::mc "Use human-readable counters with K, M, G."] \ -type boolean -group Traffic } proc traffic::load {} { variable stats variable jids variable names variable columns variable sort_order variable current_xlib variable wished_xlib variable timer variable timer_state variable timer_id variable timer_names array set stats {} array set jids {} # for table array set names [list \ presence,in [::msgcat::mc "Pres IN"] \ presence,out [::msgcat::mc "Pres OUT"] \ iq,in [::msgcat::mc "Iq IN"] \ iq,out [::msgcat::mc "Iq OUT"] \ message,in [::msgcat::mc "Msg IN"] \ message,out [::msgcat::mc "Msg OUT"] \ total,in [::msgcat::mc "All IN"] \ total,out [::msgcat::mc "All OUT"]] set columns [list presence,in presence,out iq,in iq,out \ message,in message,out total,in total,out] set sort_order total,in set current_xlib {} set wished_xlib [list {} None] set timer 5 set timer_state 0 set timer_id {} array set timer_names [list 0 [::msgcat::mc "On"] 1 [::msgcat::mc "Off"]] hook::add log_hook [namespace current]::handle_inout hook::add finload_hook [namespace current]::setup_menu hook::add connected_hook [namespace code [list update_connections on]] hook::add disconnected_hook [namespace code [list update_connections off]] hook::add save_session_hook [namespace current]::save_session setup_menu } proc traffic::unload {} { variable stats variable jids variable names variable columns variable sort_order variable current_xlib variable wished_xlib variable timer variable timer_state variable timer_id variable timer_names setup_menu if {[winfo exists .traffic_stats]} { destroy_win .traffic_stats } hook::remove log_hook [namespace current]::handle_inout hook::remove finload_hook [namespace current]::setup_menu hook::remove connected_hook [namespace code [list update_connections on]] hook::remove disconnected_hook \ [namespace code [list update_connections off]] hook::remove save_session_hook [namespace current]::save_session catch {unset stats} catch {unset jids} catch {unset names} catch {unset columns} catch {unset sort_order} catch {unset current_xlib} catch {unset wished_xlib} catch {unset timer} catch {unset timer_state} catch {unset timer_id} catch {unset timer_names} } # ############################ # Handlers proc traffic::handle_inout {xlib dir type xmldata} { variable stat variable jids variable columns variable names switch -- $dir { output { set prefix out set attr to } default { set prefix in set attr from } } switch -- $type { xml { set size [string length [::xmpp::xml::toText $xmldata]] ::xmpp::xml::split $xmldata tag xmlns attrs cdata subels set jid [::xmpp::xml::getAttr $attrs $attr] if {$jid eq ""} { set jid SERVER } else { catch { set jid [::xmpp::jid::stripResource $jid] } } } default { set tag "" set size [string length $xmldata] set jid SERVER } } if {![info exists jids($xlib,$jid)]} { # create set jids($xlib,$jid) 1 lappend jids($xlib,jids) $jid # initialize counters foreach column $columns { set stat($xlib,$jid,$column) 0 } } # increment counters if {[info exists names($tag,$prefix)]} { incr stat($xlib,$jid,$tag,$prefix) $size } incr stat($xlib,$jid,total,$prefix) $size } # ############################ # GUI proc traffic::get_connections {} { set res [list [list {} None]] foreach con [connections] { lappend res [list $con [connection_jid $con]] } return $res } proc traffic::open_window {} { variable columns variable names variable current_xlib variable timer_state variable timer_names # create widgets set w .traffic_stats if {[winfo exists $w]} { raise_win $w return } # base widget add_win $w -title [::msgcat::mc "Traffic statistics"] \ -tabtitle [::msgcat::mc "Traffic"] \ -class Traffic \ -raise 1 # button box set tools [Frame $w.tools -borderwidth 1m] pack $tools -side top -anchor w -fill x Button $tools.refresh -text [::msgcat::mc "Refresh"] \ -command [list [namespace current]::refresh] pack $tools.refresh -side right -anchor w set connections [get_connections] Combobox $tools.connection -textvariable [namespace current]::wished_xlib \ -values $connections \ -height [expr [llength $connections] + 1] \ -editable 0 \ -modifycmd [list [namespace current]::refresh] pack $tools.connection -side right -anchor w -expand yes -fill x unset connections Button $tools.show_xml -text [::msgcat::mc "Show XML"] \ -command [list ::plugins::rawxml::open_window] pack $tools.show_xml -side left -anchor w Button $tools.save -text [::msgcat::mc "Save"] \ -command [list [namespace current]::save_stat] pack $tools.save -side left -anchor w Button $tools.reset -text [::msgcat::mc "Reset"] \ -command [list [namespace current]::reset] pack $tools.reset -side left -anchor w pack [Label $tools.timerlab -text [::msgcat::mc "Timer:"]] \ -side left -anchor w Spinbox $tools.timerspin 1 100000 1 [namespace current]::timer $tools.timerspin configure -width 4 pack $tools.timerspin -side left -anchor w Button $tools.timer -text $timer_names($timer_state) \ -command [list [namespace current]::turn_timer] pack $tools.timer -side left -anchor w # create grid set sw [ScrolledWindow $w.sw -relief sunken -bd 0.25m] pack $sw -side top -fill both -expand yes set sf [ScrollableFrame $w.sf] $sw setwidget $sf set f [$sf getframe] bindscroll $f $sf # fill grid header grid [Label $f.titlejid -text [::msgcat::mc "JID"] -width 20] \ -row 0 -column 0 -sticky w bindscroll $f.titlejid $sf set i 1 foreach col $columns { set b [Button $f.titlelabel$i -text $names($col) \ -command [list [namespace current]::sort $col]] grid $b -row 0 -column $i -sticky we bindscroll $f.titlelabel$i $sf incr i } refresh } proc traffic::refresh {} { variable stat variable jids variable columns variable wished_xlib variable current_xlib variable options set w .traffic_stats if {![winfo exists $w]} return set f [$w.sf getframe] # clear if connection was changed if {[lindex $wished_xlib 0] ne $current_xlib} { clear_table $f set current_xlib [lindex $wished_xlib 0] } if {$current_xlib == {}} return # init sum counters array set sum {} foreach col $columns { set sum($col) 0 } # fill the table set row 1 foreach jid \ [lsort -decreasing -command compare $jids($current_xlib,jids)] { set tag [jid_to_tag $jid] # set first column - jid if {![winfo exists $f.jid$tag]} { Label $f.jid$tag -text $jid if {$options(show_nick)} { set nick [roster::itemconfig $current_xlib \ [roster::find_jid $current_xlib $jid] -name] if {$nick != ""} { $f.jid$tag configure -text $nick } } } grid $f.jid$tag -row $row -column 0 -sticky w bindscroll $f.jid$tag $w.sf set i 1 # set other columns - counters foreach col $columns { if {![winfo exists $f.value$i$tag]} { Label $f.value$i$tag } set value $stat($current_xlib,$jid,$col) incr sum($col) $value $f.value$i$tag configure -text [convert_to_hr $value 10] grid $f.value$i$tag -row $row -column $i -sticky e bindscroll $f.value$i$tag $w.sf incr i } incr row } # add sum if {![winfo exists $f.sumname]} { Label $f.sumname -text [::msgcat::mc "Total"] } grid $f.sumname -row $row -column 0 -sticky w bindscroll $f.sumname $w.sf set i 1 foreach col $columns { if {![winfo exists $f.sumval$i]} { Label $f.sumval$i } $f.sumval$i configure -text [convert_to_hr $sum($col) 10] grid $f.sumval$i -row $row -column $i -sticky e bindscroll $f.sumval$i $w.sf incr i } } proc traffic::convert_to_hr {value limit} { variable options if {!$options(human_readable)} { return $value } set cur "" foreach c {K M G} { if {($value / 1024) > $limit} { set value [expr {$value / 1024}] set cur $c } else { break } } return $value$cur } proc traffic::clear_table {f} { set max [expr [string length $f.title] - 1] foreach slave [grid slaves $f] { if {[string range $slave 0 $max] ne "$f.title"} { grid remove $slave destroy $slave } } } proc traffic::clear_and_refresh {args} { set w .traffic_stats if {![winfo exists $w]} return set f [$w.sf getframe] clear_table $f refresh } proc traffic::update_connections {type xlib} { variable wished_xlib set w .traffic_stats if {![winfo exists $w]} return set connections [get_connections] if {$type eq "off" && [lsearch $connections $wished_xlib] < 0} { set wished_xlib [list {} None] } $w.tools.connection configure -values $connections \ -height [expr [llength $connections] + 1] if {$type eq "on" && [string equal $wished_xlib [list {} None]]} { set wished_xlib [list $xlib [connection_jid $xlib]] } refresh } proc traffic::tick {} { variable timer_id variable timer refresh set timer_id [after [expr $timer * 1000] [list [namespace current]::tick]] } proc traffic::turn_timer {args} { variable timer_state variable timer_names variable timer_id variable timer set timer_state [expr 1 - $timer_state] if {$timer_state} { set timer_id [after [expr $timer * 1000] \ [list [namespace current]::tick]] } else { after cancel $timer_id } set w .traffic_stats if {![winfo exists $w]} return $w.tools.timer configure -text $timer_names($timer_state) } # ############################ # Other functions proc traffic::compare {arg1 arg2} { variable stat variable sort_order variable current_xlib expr {$stat($current_xlib,$arg1,$sort_order) - $stat($current_xlib,$arg2,$sort_order)} } proc traffic::sort {tag} { variable sort_order set sort_order $tag refresh } proc traffic::save_stat {} { variable names variable columns variable stat variable current_xlib variable jids set filename [tk_getSaveFile -initialdir $::configdir] if {$filename ne ""} { set fd [open $filename w] # Header set str {} lappend str "JID" foreach col $columns { lappend str $names($col) } puts $fd [join $str "\t"] # Data foreach jid $jids($current_xlib,jids) { set str {} lappend str $jid foreach col $columns { lappend str $stat($current_xlib,$jid,$col) } puts $fd [join $str "\t"] } close $fd } } proc traffic::reset {} { variable current_xlib variable columns variable jids variable stat if {$current_xlib != {}} return if {[MessageDlg .request_reset_traffic \ -aspect 50000 \ -icon warning \ -type user \ -buttons {yes no} \ -default 1 \ -cancel 1 \ -message [::msgcat::mc "Are you sure you\ want to reset counters?"]]} { return } # clear stats foreach jid $jids($current_xlib,jids) { foreach col $columns { unset stat($current_xlib,$jid,$col) } unset jids($current_xlib,$jid) } set jids($current_xlib,jids) {} # clear table clear_and_refresh } # ############################ # Register in the main menu proc traffic::setup_menu {} { catch { set m [.mainframe getmenu plugins] set ind [$m index end] $m insert $ind command -label [::msgcat::mc "Traffic statistics"] \ -command [list [namespace current]::open_window] } } proc traffic::desetup_menu {} { catch { set m [.mainframe getmenu plugins] set ind [$m index [::msgcat::mc "Traffic statistics"]] $m delete $ind } } ############################################################################## proc traffic::restore_window {args} { open_window } proc traffic::save_session {vsession} { upvar 2 $vsession session global usetabbar # We don't need JID at all, so make it empty (special case) set user "" set server "" set resource "" # TODO if {!$usetabbar} return set prio 0 foreach page [.nb pages] { set path [ifacetk::nbpath $page] if {[string equal $path .traffic_stats]} { lappend session [list $prio $user $server $resource \ [list [namespace current]::restore_window] \ ] } incr prio } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/traffic/version.txt000064400000000000000000000000041500237002100173470ustar00nobodynobody0.3 tkabber-plugins/unixkeys000075500000000000000000000000001500237002100153115ustar00nobodynobodytkabber-plugins/unixkeys/AUTHORS000064400000000000000000000000661500237002100164420ustar00nobodynobodyKonstantin Khomoutov tkabber-plugins/unixkeys/INSTALL000064400000000000000000000004701500237002100164220ustar00nobodynobodyAs usual, copy this directory under the ~/.tkabber/plugins directory so that you get a hierarchy like this: ~/.tkabber/plugins ~/.tkabber/plugins/unixkeys/ ~/.tkabber/plugins/unixkeys/unixkeys.tcl Restart Tkabber, to get the plugin loaded. Consult the README file for the details about using this plugin. tkabber-plugins/unixkeys/README000064400000000000000000000074141500237002100162560ustar00nobodynobody"Unixkeys" -- plugin for Tkabber. I. The idea This plugins adds some Unix-style keybindings to various widgets used to enter text in Tkabber (namely, entry widgets, chat input windows, comboboxes etc). The text "Unix-style" is vague, so more precisely it stands for something like "resembles default keybindings of Emacs text editor and Readline library". That is, these keybindings should be familiar to those using bash and Emacs. See the next section for complete listing of keybindings. II. Usage After this plugin is loaded by Tkabber, the keybindings it provides are available in all controls used to input text in Tkabber. The keybindings added are: * M-a -- move cursor to the start of text. * M-e -- move cursor to the end of text (but see below). * M-f -- move cursor one word forward. * M-b -- move cursor one word backward. * C-u -- delete text from the cursor to the beginning of the current line. * M-BackSpace, C-w -- delete text from the cursor to the start of the current word. * M-BackSpace, M-d -- delete text from the cursor to the end of the current word. * C-x C-u -- Undo the last change (in multiline entry widgets). * C-x h -- Select all text. Also, on Windows, another keybinding is added to multiline entry widgets: * C-_ (Ctrl-Underscore) -- Undo the last change. And, finally, two convenience bindings are added to multiline entry widgets (they're borrowed from single-line entry and listbox Tk widgets): * C-/ (Ctrl-slash) -- Select all text. * C-\ (Ctrl-backslash) -- Clear selection. Since text-oriented Tk widgets already provide some Unix-style bindings, we can summarise the complete "Unix-style editing capabilities" which those widgets provide in concert with this plugin: * C-f, C-b -- move cursor one character forward/backward. * M-f, M-b -- move cursor one word forward/backward. * C-a, C-e -- move cursor to the start/end of the current line (in multiline entry widgets) or to the start/end of text (in single-line entry widgets). * M-a, M-e -- move cursor to the start/end of text. * C-h, C-d -- delete one character to the left/right from the cursor. * C-w, M-BackSpace -- delete text to the start of the current word. * M-d, M-Delete -- delete text to the end of the current word. * C-u, C-k -- delete text from the cursor to the start/end of the current line. * C-x C-u, C-_, C-z -- Undo the last change (only in multiline entry widgets). * C-/, C-x h -- Select all text. * C-\ -- Clear selection. III. Configuration. No configuration is needed except for one issue explained below. The built-in Tkabber plugin providing support for emoticons binds its action "show menu with available emoticons" to M-e ( and ) in chat input windows thus effectively cancelling the effect of pressing M-e which this plugin adds. If you prefer M-e to be used for cursor motion as provided by this plugin, add something like construct in the postload section of your config.tcl: foreach b [event info <>] { event delete <> $b } This will unbind *all* bindings from the Tk virtual event that shows the emoticons palette, effectivly disabling its usage. If you want to access this palette via some other gesture, add it like this, for instance: event add <> This will made the emoticons palette to pop up when you press on your keyboard. IV. Limitations. The bindings do not match *exactly* the behaviours of software they borrow from. For example, M-e in Emacs stands for "end of sentence", not "end of text in the buffer" as this plugin does for multiline entry widgets. The plugin requires special tweaking to get M-e working, as described above. # vim:tw=64:et tkabber-plugins/unixkeys/TODO000064400000000000000000000001051500237002100160540ustar00nobodynobody* M-a, M-e in text widgets should move by sentences. # vim:tw=64:et tkabber-plugins/unixkeys/license.terms000064400000000000000000000021121500237002100200620ustar00nobodynobodyCopyright (c) 2007 Konstantin Khomoutov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tkabber-plugins/unixkeys/msgs000075500000000000000000000000001500237002100162625ustar00nobodynobodytkabber-plugins/unixkeys/msgs/ru.msg000064400000000000000000000012601500237002100174760ustar00nobodynobody# ru.msg -- # # Russian messages for the Tkabber Unixkeys plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Whether the Unixkeys plugin is loaded." \ "Загружено ли раÑширение Unixkeys." ::msgcat::mcset ru "This plugin makes the widgets providing textual input\ support certain combinations of keystrokes\ familiar to the users of Readline and Emacs." \ "Это раÑширение добавлÑет в Ð¿Ð¾Ð»Ñ Ñ‚ÐµÐºÑтового ввода поддержку комбинаций\ клавиш, знакомых пользователÑм Readline и Emacs." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/unixkeys/msgs/uk.msg000064400000000000000000000012541500237002100174720ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Tkabber Unixkeys plugin. # # Author: Sergei Golovan ::msgcat::mcset uk "Whether the Unixkeys plugin is loaded." \ "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Unixkeys." ::msgcat::mcset uk "This plugin makes the widgets providing textual input\ support certain combinations of keystrokes\ familiar to the users of Readline and Emacs." \ "Це Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ” у Ð¿Ð¾Ð»Ñ Ñ‚ÐµÐºÑтового вводу підтримку комбінацій\ клавіш, знайомих кориÑтувачам Readline та Emacs." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/unixkeys/unixkeys.tcl000064400000000000000000000072031500237002100177550ustar00nobodynobody# unixkeys.tcl -- # # "Unixkeys" -- plugin for Tkabber. # Provides keybindings in Tk Text widgets which are familiar # to Unix users: they resemble "canonical" bindings found in # readline and Emacs. # # Author: Konstantin Khomoutov # # See license.terms for details on usage and distribution. # See INSTALL for installation procedure. # See README for usage guidelines. package require msgcat namespace eval unixkeys { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered unixkeys]} { ::plugins::register unixkeys \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc \ "Whether the Unixkeys plugin is loaded."]\n[::msgcat::mc \ "This plugin makes the widgets providing textual input\ support certain combinations of keystrokes\ familiar to the users of Readline and Emacs."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } } proc unixkeys::load {} { foreach mod {Alt Meta} { Bind Text <$mod-Key-a> [bind Text ] Bind Text <$mod-Key-e> [bind Text ] BindEntry <$mod-Key-a> [bind Entry ] BindEntry <$mod-Key-e> [bind Entry ] } foreach mod {Alt Meta} { Bind Text <$mod-Key-b> [bind Text ] Bind Text <$mod-Key-f> [bind Text ] } BindEntry [bind Entry ] BindEntry [bind Entry ] Bind Text {%W delete {insert linestart} insert} BindEntry {%W delete 0 insert} foreach {mod key} {Alt BackSpace Control w} { Bind Text <$mod-Key-$key> \ {%W delete [tk::TextPrevPos %W insert tcl_startOfPreviousWord] insert} BindEntry <$mod-Key-$key> \ {%W delete [tk::EntryPreviousWord %W insert] insert} } foreach key {d Delete} { foreach mod {Alt Meta} { Bind Text <$mod-Key-$key> \ {%W delete insert [::tk::TextNextPos %W insert tcl_endOfWord]} BindEntry <$mod-Key-$key> \ {%W delete insert [::tk::EntryNextWord %W insert]} } } if {[string equal $::tcl_platform(os) windows]} { AddEvent <> } AddEvent <> Bind Text {%W tag add sel 1.0 end} Bind Text {%W tag remove sel 1.0 end} Bind Text {%W tag add sel 1.0 end} BindEntry [bind Entry ] } proc unixkeys::Bind {target event script} { set existing [bind $target $event] bind $target $event $script variable bindtable lappend bindtable $target $event $script $existing } proc unixkeys::BindEntry {event script} { Bind Entry $event $script Bind TEntry $event $script Bind BwEntry $event $script } proc unixkeys::AddEvent {name event} { event add $name $event variable evtable lappend evtable $name $event } proc unixkeys::unload {} { variable bindtable foreach {target event installed original} $bindtable { set existing [bind $target $event] if {[string equal $existing $installed]} { bind $target $event $original } } unset bindtable variable evtable foreach {name event} $evtable { event delete $name $event } unset evtable } # vim:ts=8:sw=4:sts=4:et tkabber-plugins/whiteboard000075500000000000000000000000001500237002100155625ustar00nobodynobodytkabber-plugins/whiteboard/ChangeLog000064400000000000000000000025721500237002100174210ustar00nobodynobody2006-05-27 Alexey Shchepin * whiteboard.tcl: Updated interface, bugfix (thanks to Sergei Golovan) * msgs/ru.msg: Updated (thanks to Sergei Golovan) 2006-04-27 Alexey Shchepin * msgs/ru.msg: Updated (thanks to Sergei Golovan) 2006-01-20 Alexey Shchepin * whiteboard.tcl: Updated (thanks to Sergei Golovan) 2005-08-14 Alexey Shchepin * msgs/nl.msg: Updated (thanks to Sander Devrieze) 2004-07-17 Alexey Shchepin * msgs/nl.msg: Dutch translation (thanks to Sander Devrieze) 2004-03-22 Alexey Shchepin * svgrender.tcl: Extended the parsing of point-lists to match SVG spec, extended proc parse_text to use new proc text_opts (thanks to Jeff Silver) * whiteboard.tcl: Enhanced uniqueness of object ID, added "Text" tool with color and font configuration, bugfix in wb::send_clear, removed the code that put commas in x,y pairs in lists of points, changed line join style in freehand from 'miter' to 'round' (thanks to Jeff Silver) 2004-01-05 Alexey Shchepin * whiteboard.tcl (wb::add_roster_menu_item): Updated to latest tkabber cvs version 2003-09-01 Alexey Shchepin * whiteboard.tcl: Bugfixes 2003-05-29 Alexey Shchepin * whiteboard.tcl: Support for private whiteboard tkabber-plugins/whiteboard/msgs000075500000000000000000000000001500237002100165335ustar00nobodynobodytkabber-plugins/whiteboard/msgs/de.msg000064400000000000000000000051161500237002100177150ustar00nobodynobody# de.msg -- # # German messages file for the Tkabber Whiteboard plugin. # # Author: Roger Sondermann 15.03.2009 ::msgcat::mcset de "%s created: %s" "%s erstellt von %s" ::msgcat::mcset de "%s moved: %s" "%s verschoben von %s" ::msgcat::mcset de "%s transformed: %s" "%s transformiert: %s" ::msgcat::mcset de "%s whiteboard" "%s 'Whiteboard'" ::msgcat::mcset de "All files" "Alle Dateien" ::msgcat::mcset de "All images" "Alle Bilder" ::msgcat::mcset de "Cancel" "Abbrechen" ::msgcat::mcset de "Circle" "Kreis" ::msgcat::mcset de "Clear" "Leeren" ::msgcat::mcset de "Enter text" "Text eingeben" ::msgcat::mcset de "Fill color" "Füll-Farbe" ::msgcat::mcset de "Fill" "Füllen" ::msgcat::mcset de "Flip horizontally" "Spiegeln horizontal" ::msgcat::mcset de "Flip vertically" "Spiegeln vertikal" ::msgcat::mcset de "FreeHand" "Frei-Hand" ::msgcat::mcset de "GIF images" "GIF-Bilder" ::msgcat::mcset de "Image" "Bild" ::msgcat::mcset de "JPEG images" "JPEG-Bilder" ::msgcat::mcset de "Line color" "Linien-Farbe" ::msgcat::mcset de "Line width: " "Linien-Breite" ::msgcat::mcset de "Loading image failed: %s." \ "Laden der Bilder misslungen: %s." ::msgcat::mcset de "Move/Transform" "Bewegen" ::msgcat::mcset de "OK" "OK" ::msgcat::mcset de "PNG images" "PNG-Bilder" ::msgcat::mcset de "PolyLine" "Linie" ::msgcat::mcset de "Polygon" "Polygon" ::msgcat::mcset de "Rectangle" "Rechteck" ::msgcat::mcset de "Remove" "Entfernen" ::msgcat::mcset de "Rotate 135\u00b0" "Drehen 135\u00b0" ::msgcat::mcset de "Rotate 180\u00b0" "Drehen 180\u00b0" ::msgcat::mcset de "Rotate 45\u00b0" "Drehen 45\u00b0" ::msgcat::mcset de "Rotate 90\u00b0" "Drehen 90\u00b0" ::msgcat::mcset de "Save..." "Speichern..." ::msgcat::mcset de "Show balloons" "Tooltips" ::msgcat::mcset de "Text color" "Text-Farbe" ::msgcat::mcset de "Text font" "Schriftart" ::msgcat::mcset de "Text" "Text" ::msgcat::mcset de "Whether the Whiteboard plugin is loaded." \ "'Whiteboard'-Plugin laden." ::msgcat::mcset de "Whiteboard" "Whiteboard" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/whiteboard/msgs/es.msg000064400000000000000000000040531500237002100177330ustar00nobodynobody# es.msg -- # # Spanish messages for the Tkabber Whiteboard plugin. # # Author: Badlop ::msgcat::mcset es "%s created: %s" "%s creado: %s" ::msgcat::mcset es "%s moved: %s" "%s movido: %s" ::msgcat::mcset es "%s transformed: %s" "%s transforma: %s" ::msgcat::mcset es "%s whiteboard" "Pizarra: %s" ::msgcat::mcset es "All files" "Todos los ficheros" ::msgcat::mcset es "All images" "Todas las imágenes" ::msgcat::mcset es "Cancel" "Cancelar" ::msgcat::mcset es "Circle" "Círculo" ::msgcat::mcset es "Clear" "Limpiar" ::msgcat::mcset es "Enter text" "Introduce texto" ::msgcat::mcset es "Fill color" "Color de relleno" ::msgcat::mcset es "Fill" "Rellenar" ::msgcat::mcset es "Flip horizontally" "Girar horizontalmente" ::msgcat::mcset es "Flip vertically" "Girar verticalmente" ::msgcat::mcset es "FreeHand" "Mano alzada" ::msgcat::mcset es "GIF images" "Imágenes GIF" ::msgcat::mcset es "Image" "Imagen" ::msgcat::mcset es "JPEG images" "Imágenes JPEG" ::msgcat::mcset es "Line color" "Color de línea" ::msgcat::mcset es "Line width: " "Ancho de línea: " ::msgcat::mcset es "Loading image failed: %s." \ "La carga de la imagen ha fallado: %s." ::msgcat::mcset es "Move/Transform" "Mover/Transformar" ::msgcat::mcset es "OK" "Sí" ::msgcat::mcset es "PNG images" "Imágenes PNG" ::msgcat::mcset es "PolyLine" "Polilínea" ::msgcat::mcset es "Polygon" "Polígono" ::msgcat::mcset es "Rectangle" "Rectángulo" ::msgcat::mcset es "Remove" "Borrar" ::msgcat::mcset es "Rotate 135\u00b0" "Rotar 135\u00b0" ::msgcat::mcset es "Rotate 180\u00b0" "Rotar 180\u00b0" ::msgcat::mcset es "Rotate 45\u00b0" "Rotar 45\u00b0" ::msgcat::mcset es "Rotate 90\u00b0" "Rotar 90\u00b0" ::msgcat::mcset es "Save..." "Guardar..." ::msgcat::mcset es "Show balloons" "Mostrar globos" ::msgcat::mcset es "Text color" "Color del texto" ::msgcat::mcset es "Text font" "Fuente del texto" ::msgcat::mcset es "Text" "Texto" ::msgcat::mcset es "Whether the Whiteboard plugin is loaded." \ "Cargar el plugin Whiteboard." ::msgcat::mcset es "Whiteboard" "Pizarra" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/whiteboard/msgs/nl.msg000064400000000000000000000011711500237002100177330ustar00nobodynobody# nl.msg -- # # Dutch messages for the Tkabber Whiteboard plugin. # # Author: Sander Devrieze ::msgcat::mcset nl "Whiteboard" "Whiteboard" ::msgcat::mcset nl "%s whiteboard" "Whiteboard %s" ::msgcat::mcset nl "PolyLine" "Veelhoek" ::msgcat::mcset nl "FreeHand" "Potlood" ::msgcat::mcset nl "Move" "Verplaatsen" ::msgcat::mcset nl "Clear" "Wissen" ::msgcat::mcset nl "Color" "Kleur" ::msgcat::mcset nl "Text" "Tekst" ::msgcat::mcset nl "Text Color" "Tekstkleur" ::msgcat::mcset nl "Font" "Lettertype" ::msgcat::mcset nl "OK" "OK" ::msgcat::mcset nl "Cancel" "Annuleren" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/whiteboard/msgs/pl.msg000064400000000000000000000042661500237002100177450ustar00nobodynobody# pl.msg -- # # Polish messages for the Tkabber Whiteboard plugin. # # Author: Irek Chmielowiec ::msgcat::mcset pl "Whiteboard" "Tablica rysunkowa" ::msgcat::mcset pl "%s whiteboard" "Tablica: %s" ::msgcat::mcset pl "PolyLine" "Linia prosta" ::msgcat::mcset pl "FreeHand" "Linia odrÄ™czna" ::msgcat::mcset pl "Move" "PrzesuÅ„" ::msgcat::mcset pl "Text" "Tekst" ::msgcat::mcset pl "Text color" "Kolor tekstu" ::msgcat::mcset pl "Text font" "Czcionka tekstu" ::msgcat::mcset pl "Line width: " "Grubość linii: " ::msgcat::mcset pl "Line color" "Kolor linii" ::msgcat::mcset pl "Cancel" "Anuluj" ::msgcat::mcset pl "Clear" "Wyczyść" ::msgcat::mcset pl "OK" "OK" ::msgcat::mcset pl "Remove" "UsuÅ„" ::msgcat::mcset pl "Circle" "OkrÄ…g" ::msgcat::mcset pl "Fill" "WypeÅ‚nienie" ::msgcat::mcset pl "Fill color" "Kolor wypeÅ‚nienia" ::msgcat::mcset pl "Polygon" "WielokÄ…t" ::msgcat::mcset pl "Save..." "Zapisz..." ::msgcat::mcset pl "%s created: %s" "%s utworzyÅ‚: %s" ::msgcat::mcset pl "%s moved: %s" "%s przesunÄ…Å‚: %s" ::msgcat::mcset pl "Enter text" "Wprowadź tekst" ::msgcat::mcset pl "Show balloons" "Pokaż dymki podpowiedzi" ::msgcat::mcset pl "%s przeksztaÅ‚cono: %s" ::msgcat::mcset pl "Flip horizontally" "Odbij poziomo" ::msgcat::mcset pl "Flip vertically" "Odbij pionowo" ::msgcat::mcset pl "Move/Transform" "PrzesuÅ„/Przekształć" ::msgcat::mcset pl "Rectangle" "ProstokÄ…t" ::msgcat::mcset pl "Rotate 135\u00b0" "Obrót o 135\u00b0" ::msgcat::mcset pl "Rotate 180\u00b0" "Obrót o 180\u00b0" ::msgcat::mcset pl "Rotate 45\u00b0" "Obrót o 45\u00b0" ::msgcat::mcset pl "Rotate 90\u00b0" "Obrót o 90\u00b0" ::msgcat::mcset pl "%s transformed: %s" "PrzeksztaÅ‚cono %s: %s" ::msgcat::mcset pl "All files" "Wszystkie pliki" ::msgcat::mcset pl "All images" "Wszystkie obrazy" ::msgcat::mcset pl "GIF images" "Obrazy GIF" ::msgcat::mcset pl "Image" "Obraz" ::msgcat::mcset pl "JPEG images" "Obrazy JPEG" ::msgcat::mcset pl "Loading image failed: %s." \ "Otwarcie obrazu nie powiodÅ‚o siÄ™: %s." ::msgcat::mcset pl "PNG images" "Obrazy PNG" ::msgcat::mcset pl "Whether the Whiteboard plugin is loaded." \ "ZaÅ‚aduj wtyczkÄ™ tablicy rysunkowej." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/whiteboard/msgs/ro.msg000064400000000000000000000007101500237002100177400ustar00nobodynobody# ro.msg -- # # Romanian messages for the Tkabber Whiteboard plugin. # # Author: ::msgcat::mcset ro "Whiteboard" "Tablă" ::msgcat::mcset ro "%s whiteboard" "Table %s" ::msgcat::mcset ro "PolyLine" "Linie poligonală" ::msgcat::mcset ro "FreeHand" "Mână liberă" ::msgcat::mcset ro "Move" "Mută" #::msgcat::mcset ro "Remove" "Åžterge" ::msgcat::mcset ro "Clear" "Åžterge tot" ::msgcat::mcset ro "Color" "Culoare" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/whiteboard/msgs/ru.msg000064400000000000000000000060151500237002100177520ustar00nobodynobody# ru.msg -- # # Russian messages for the Tkabber Whiteboard plugin. # # Author: Sergei Golovan ::msgcat::mcset ru "Cancel" "Отменить" ::msgcat::mcset ru "Circle" "ОкружноÑть" ::msgcat::mcset ru "Clear" "ОчиÑтить" ::msgcat::mcset ru "Enter text" "Введите текÑÑ‚" ::msgcat::mcset ru "Fill color" "Цвет заливки" ::msgcat::mcset ru "Fill" "Заливать" ::msgcat::mcset ru "Flip horizontally" "Отразить горизонтально" ::msgcat::mcset ru "Flip vertically" "Отразить вертикально" ::msgcat::mcset ru "FreeHand" "КриваÑ" ::msgcat::mcset ru "Line color" "Цвет линии" ::msgcat::mcset ru "Line width: " "Ширина линии: " ::msgcat::mcset ru "Move/Transform" "ПеремеÑÑ‚./ТранÑформ." ::msgcat::mcset ru "OK" "Продолжить" ::msgcat::mcset ru "Polygon" "Многоугольник" ::msgcat::mcset ru "PolyLine" "ЛоманаÑ" ::msgcat::mcset ru "Rectangle" "ПрÑмоугольник" ::msgcat::mcset ru "Remove" "Удалить" ::msgcat::mcset ru "Rotate 135\u00b0" "Повернуть на 135\u00b0" ::msgcat::mcset ru "Rotate 180\u00b0" "Повернуть на 180\u00b0" ::msgcat::mcset ru "Rotate 45\u00b0" "Повернуть на 45\u00b0" ::msgcat::mcset ru "Rotate 90\u00b0" "Повернуть на 90\u00b0" ::msgcat::mcset ru "Save..." "Сохранить..." ::msgcat::mcset ru "Show balloons" "Показывать подÑк." ::msgcat::mcset ru "Skew horizontally 10\u00b0" \ "СкоÑить горизонтально на 10\u00b0" ::msgcat::mcset ru "Skew horizontally -10\u00b0" \ "СкоÑить горизонтально на -10\u00b0" ::msgcat::mcset ru "Skew vertically 10\u00b0" "СкоÑить вертикально на 10\u00b0" ::msgcat::mcset ru "Skew vertically -10\u00b0" \ "СкоÑить вертикально на -10\u00b0" ::msgcat::mcset ru "%s created: %s" "%s Ñоздано: %s" ::msgcat::mcset ru "%s moved: %s" "%s перемещено: %s" ::msgcat::mcset ru "%s transformed: %s" "%s транÑформировано: %s" ::msgcat::mcset ru "%s whiteboard" "%s доÑка" ::msgcat::mcset ru "Text color" "Цвет текÑта" ::msgcat::mcset ru "Text font" "Шрифт текÑта" ::msgcat::mcset ru "Text" "ТекÑÑ‚" ::msgcat::mcset ru "Whiteboard" "Ð“Ñ€Ð¸Ñ„ÐµÐ»ÑŒÐ½Ð°Ñ Ð´Ð¾Ñка" ::msgcat::mcset ru "All files" "Ð’Ñе файлы" ::msgcat::mcset ru "All images" "Ð’Ñе изображениÑ" ::msgcat::mcset ru "GIF images" "Ð˜Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ GIF" ::msgcat::mcset ru "Image" "Изображение" ::msgcat::mcset ru "JPEG images" "Ð˜Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ JPEG" ::msgcat::mcset ru "Loading image failed: %s." \ "Загрузить изображение не удалоÑÑŒ: %s" ::msgcat::mcset ru "PNG images" "Ð˜Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ PNG" ::msgcat::mcset ru "Whether the Whiteboard plugin is loaded." \ "Загружено ли раÑширение 'Ð“Ñ€Ð¸Ñ„ÐµÐ»ÑŒÐ½Ð°Ñ Ð´Ð¾Ñка'." # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/whiteboard/msgs/uk.msg000064400000000000000000000057371500237002100177550ustar00nobodynobody# uk.msg -- # # Ukrainian messages for the Tkabber Whiteboard plugin. # # Author: Mykola Dzham # Author: Sergei Golovan ::msgcat::mcset uk "Whiteboard" "Грифельна дошка" ::msgcat::mcset uk "%s whiteboard" "%s дошка" ::msgcat::mcset uk "PolyLine" "Ламана" ::msgcat::mcset uk "FreeHand" "Крива" ::msgcat::mcset uk "Remove" "Видалити" ::msgcat::mcset uk "Clear" "ОчиÑтити" ::msgcat::mcset uk "Line color" "Колір лінії" ::msgcat::mcset uk "Text" "ТекÑÑ‚" ::msgcat::mcset uk "Text color" "Колір текÑту" ::msgcat::mcset uk "Text font" "Шрифт текÑту" ::msgcat::mcset uk "Line width: " "Товщина лінії: " ::msgcat::mcset uk "OK" "Продовжити" ::msgcat::mcset uk "Cancel" "Відмінити" ::msgcat::mcset uk "%s created: %s" "%s Ñтворено: %s" ::msgcat::mcset uk "%s moved: %s" "%s переміщено: %s" ::msgcat::mcset uk "%s transformed: %s" "%s транÑформовано: %s" ::msgcat::mcset uk "All files" "Ð’ÑÑ– файли" ::msgcat::mcset uk "All images" "Ð’ÑÑ– зображеннÑ" ::msgcat::mcset uk "Circle" "Коло" ::msgcat::mcset uk "Enter text" "Уведіть текÑÑ‚" ::msgcat::mcset uk "Fill" "Заливати" ::msgcat::mcset uk "Fill color" "Колір заливки" ::msgcat::mcset uk "Flip horizontally" "Відбити горизонтально" ::msgcat::mcset uk "Flip vertically" "Відбити вертикально" ::msgcat::mcset uk "GIF images" "Ð—Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ GIF" ::msgcat::mcset uk "Image" "ЗображеннÑ" ::msgcat::mcset uk "JPEG images" "Ð—Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ JPEG" ::msgcat::mcset uk "Loading image failed: %s." "Завантажити Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð½Ðµ вдалоÑÑ: %s." ::msgcat::mcset uk "Move/Transform" "ПереміÑÑ‚./ТранÑформ." ::msgcat::mcset uk "PNG images" "Ð—Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ PNG" ::msgcat::mcset uk "Polygon" "Багатокутник" ::msgcat::mcset uk "Rectangle" "ПрÑмокутник" ::msgcat::mcset uk "Rotate 135\u00b0" "Повернути на 135\u00b0" ::msgcat::mcset uk "Rotate 180\u00b0" "Повернути на 180\u00b0" ::msgcat::mcset uk "Rotate 45\u00b0" "Повернути на 45\u00b0" ::msgcat::mcset uk "Rotate 90\u00b0" "Повернути на 90\u00b0" ::msgcat::mcset uk "Save..." "Зберегти..." ::msgcat::mcset uk "Show balloons" "Показувати підÑк." ::msgcat::mcset uk "Skew horizontally -10\u00b0" "СкоÑити горизонтально на -10\u00b0" ::msgcat::mcset uk "Skew horizontally 10\u00b0" "СкоÑити горизонтально на 10\u00b0" ::msgcat::mcset uk "Skew vertically -10\u00b0" "СкоÑити вертикально на -10\u00b0" ::msgcat::mcset uk "Skew vertically 10\u00b0" "СкоÑити вертикально на 10\u00b0" ::msgcat::mcset uk "Whether the Whiteboard plugin is loaded." "Чи завантажене Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ 'Грифельна дошка'" # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/whiteboard/svgrender.tcl000064400000000000000000000477741500237002100203670ustar00nobodynobody# svgrender.tcl -- # # This file is a part of the Whiteboard plugin for Tkabber # XMPP client. It renders a subset of SVG on a Tk canvas. package require Tk 8.5- catch {package require Img} namespace eval svg { variable Debug 0 } proc svg::loadFile {c filename} { set f [open $filename] set file [read $f] close $f ::xmpp::xml::parseData $file [namespace code [list parseSVGFile $c]] } proc svg::parseSVGFile {c xmldata} { Debug 2 $xmldata ::xmpp::xml::split $xmldata tag xmlns attrs cdata subels if {$tag != "svg"} { return -code error "Not a SVG file" } parseSVGItem $c {} {} $xmldata } proc svg::parseSVGItem {c transform curAttrs item} { ::xmpp::xml::split $item tag xmlns attrs cdata subels switch -- $tag { svg { ParseSVG $c $transform $curAttrs $item } rect { ParseRect $c $transform $curAttrs $item } line { ParseLine $c $transform $curAttrs $item } polyline { ParsePolyline $c $transform $curAttrs $item } polygon { ParsePolygon $c $transform $curAttrs $item } circle { ParseCircle $c $transform $curAttrs $item } ellipse { ParseEllipse $c $transform $curAttrs $item } text { ParseText $c $transform $curAttrs $item } image { ParseImage $c $transform $curAttrs $item } g { ParseG $c $transform $curAttrs $attrs $subels } default { Debug 1 Unknown SVG tag '$tag' return "" } } } proc svg::ParseSVG {c transform curAttrs item} { ::xmpp::xml::split $item tag xmlns attrs cdata subels foreach subel $subels { parseSVGItem $c $transform $curAttrs $subel } return "" } proc svg::ParseG {c transform curAttrs attrs items} { eval lappend transform \ [ParseTransform [::xmpp::xml::getAttr $attrs transform]] array set Attrs $curAttrs array set Attrs $attrs set curAttrs [array get Attrs] foreach item $items { parseSVGItem $c $transform $curAttrs $item } return "" } proc svg::ParsePolygon {c transform curAttrs item} { ::xmpp::xml::split $item tag xmlns attrs cdata subels eval lappend transform \ [ParseTransform [::xmpp::xml::getAttr $attrs transform]] set p [TransformPoints $transform [::xmpp::xml::getAttr $attrs points]] array set Attrs $curAttrs array set Attrs $attrs set styles [split [::xmpp::xml::getAttr $attrs style] \;] set drawitem line foreach s $styles { foreach {attr val} [split $s :] break set attr [string trim $attr] set val [string trim $val] switch -- $attr { "" {} fill - stroke - stroke-width - stroke-linejoin { set Attrs($attr) $val } default { Debug 1 Unknown style attr '$attr' } } } if {[info exists Attrs(fill)]} { set opts [PolygonOpts] set drawitem polygon } else { set opts [LineOpts] set drawitem line lappend p [lindex $p 0] [lindex $p 1] } Debug 2 $drawitem $p $opts eval [list $c create $drawitem] $p $opts } proc svg::ParseCircle {c transform curAttrs item} { variable Unitcircle ::xmpp::xml::split $item tag xmlns attrs cdata subels eval lappend transform \ [ParseTransform [::xmpp::xml::getAttr $attrs transform]] array set Attrs $curAttrs array set Attrs {cx 0 cy 0 r 0} array set Attrs $attrs set styles [split [::xmpp::xml::getAttr $attrs style] \;] set drawitem circle foreach s $styles { foreach {attr val} [split $s :] break set attr [string trim $attr] set val [string trim $val] switch -- $attr { "" {} cx - cy - r - fill - stroke - stroke-width { set Attrs($attr) $val } default { Debug 1 Unknown style attr '$attr' } } } set opts [CircleOpts] set points {} for {set i 0} {$i < 30} {incr i} { set a [expr {3.1415926 * $i / 15}] lappend points [expr {$Attrs(cx) + $Attrs(r)*cos($a)}] \ [expr {$Attrs(cy) + $Attrs(r)*sin($a)}] } set points [TransformPoints $transform $points] Debug 2 polygon $points $opts eval [list $c create polygon $points] $opts } proc svg::ParseEllipse {c transform curAttrs item} { variable Unitcircle ::xmpp::xml::split $item tag xmlns attrs cdata subels eval lappend transform \ [ParseTransform [::xmpp::xml::getAttr $attrs transform]] array set Attrs $curAttrs array set Attrs {cx 0 cy 0 rx 0 ry 0} array set Attrs $attrs set styles [split [::xmpp::xml::getAttr $attrs style] \;] set drawitem circle foreach s $styles { foreach {attr val} [split $s :] break set attr [string trim $attr] set val [string trim $val] switch -- $attr { "" {} cx - cy - rx - ry - fill - stroke - stroke-width { set Attrs($attr) $val } default { Debug 1 Unknown style attr '$attr' } } } set opts [CircleOpts] set points {} for {set i 0} {$i < 30} {incr i} { set a [expr {3.1415926 * $i / 15}] lappend points [expr {$Attrs(cx) + $Attrs(rx)*cos($a)}] \ [expr {$Attrs(cy) + $Attrs(ry)*sin($a)}] } set points [TransformPoints $transform $points] Debug 2 polygon $points $opts eval [list $c create polygon $points] $opts } proc svg::ParseLine {c transform curAttrs item} { ::xmpp::xml::split $item tag xmlns attrs cdata subels eval lappend transform \ [ParseTransform [::xmpp::xml::getAttr $attrs transform]] set x1 [::xmpp::xml::getAttr $attrs x1] set y1 [::xmpp::xml::getAttr $attrs y1] set x2 [::xmpp::xml::getAttr $attrs x2] set y2 [::xmpp::xml::getAttr $attrs y2] foreach {x1 y1} [TransformCoord $transform $x1 $y1] break foreach {x2 y2} [TransformCoord $transform $x2 $y2] break array set Attrs $curAttrs array set Attrs $attrs set styles [split [::xmpp::xml::getAttr $attrs style] \;] set drawitem line foreach s $styles { foreach {attr val} [split $s :] break set attr [string trim $attr] set val [string trim $val] switch -- $attr { "" {} stroke - stroke-width - stroke-linecap - stroke-linejoin { set Attrs($attr) $val } default { Debug 1 Unknown style attr '$attr' } } } set opts [LineOpts] Debug 2 line $x1 $y1 $x2 $y2 $opts eval [list $c create line $x1 $y1 $x2 $y2] $opts } proc svg::ParseRect {c transform curAttrs item} { ::xmpp::xml::split $item tag xmlns attrs cdata subels eval lappend transform \ [ParseTransform [::xmpp::xml::getAttr $attrs transform]] set x [::xmpp::xml::getAttr $attrs x] set y [::xmpp::xml::getAttr $attrs y] set width [::xmpp::xml::getAttr $attrs width] set height [::xmpp::xml::getAttr $attrs height] set rx [::xmpp::xml::getAttr $attrs rx] set ry [::xmpp::xml::getAttr $attrs ry] if {$rx != ""} { Debug 1 Round corners are ignored } set x2 [expr {$x + $width}] set y2 [expr {$y + $height}] foreach {xx yy} [TransformCoord $transform $x $y] break foreach {xx1 yy1} [TransformCoord $transform $x2 $y] break foreach {xx2 yy2} [TransformCoord $transform $x2 $y2] break foreach {xx3 yy3} [TransformCoord $transform $x $y2] break array set Attrs $curAttrs array set Attrs $attrs set styles [split [::xmpp::xml::getAttr $attrs style] \;] set drawitem line foreach s $styles { foreach {attr val} [split $s :] break set attr [string trim $attr] set val [string trim $val] switch -- $attr { "" {} stroke - stroke-width - stroke-linejoin { set Attrs($attr) $val } default { Debug 1 Unknown style attr '$attr' } } } set opts [PolygonOpts] Debug 2 polygon $xx $yy $xx1 $yy1 $xx2 $yy2 $xx3 $yy3] $opts eval [list $c create polygon $xx $yy $xx1 $yy1 $xx2 $yy2 $xx3 $yy3] $opts } proc svg::ParsePolyline {c transform curAttrs item} { ::xmpp::xml::split $item tag xmlns attrs cdata subels set p [TransformPoints $transform [::xmpp::xml::getAttr $attrs points]] array set Attrs $curAttrs array set Attrs $attrs set styles [split [::xmpp::xml::getAttr $attrs style] \;] set drawitem line foreach s $styles { foreach {attr val} [split $s :] break set attr [string trim $attr] set val [string trim $val] switch -- $attr { "" {} fill - stroke - stroke-width - stroke-linecap - stroke-linejoin { set Attrs($attr) $val } default { Debug 1 Unknown style attr '$attr' } } } set opts [LineOpts] Debug 2 line $p $opts eval [list $c create line] $p $opts } proc svg::ParseImage {c transform curAttrs item} { ::xmpp::xml::split $item tag xmlns attrs cdata subels eval lappend transform \ [ParseTransform [::xmpp::xml::getAttr $attrs transform]] set x [::xmpp::xml::getAttr $attrs x] set y [::xmpp::xml::getAttr $attrs y] if {$x == ""} {set x 0} if {$y == ""} {set y 0} foreach {x y} [TransformCoord $transform $x $y] break array set Attrs $curAttrs array set Attrs $attrs # Works only with BOB data included in the same XMPP stanza set cid [::xmpp::xml::getAttr $attrs http://www.w3.org/1999/xlink:href] if {[string first cid: $cid] != 0} { return } lassign [::xmpp::bob::get [string range $cid 4 end]] type data if {![info exists data] || $data == ""} { return "" } if {[catch {image create photo -data $data} image]} { return "" } bind $c +[list image delete $image] set opts [ImageOpts] Debug 2 image $x $y -image $image $opts eval [list $c create image $x $y -image $image] $opts } proc svg::ParseText {c transform curAttrs item} { ::xmpp::xml::split $item tag xmlns attrs cdata subels eval lappend transform \ [ParseTransform [::xmpp::xml::getAttr $attrs transform]] set x [::xmpp::xml::getAttr $attrs x] set y [::xmpp::xml::getAttr $attrs y] if {$x == ""} {set x 0} if {$y == ""} {set y 0} foreach {x y} [TransformCoord $transform $x $y] break array set Attrs $curAttrs array set Attrs $attrs set styles [split [::xmpp::xml::getAttr $attrs style] \;] foreach s $styles { foreach {attr val} [split $s :] break set attr [string trim $attr] set val [string trim $val] set Attrs($attr) $val } set allopts [TextOpts] set opts [lindex $allopts 0] set fontopts [lindex $allopts 1] if {$fontopts != ""} { variable app_font set fontname [list font $fontopts] if {![info exists app_font($fontname)]} { # create a font to match the settings set app_font($fontname) \ [eval [list font create $fontname] $fontopts] } lappend opts -font $app_font($fontname) } Debug 2 text $x $y -text $cdata $opts eval [list $c create text $x $y -text $cdata] $opts } proc svg::LineOpts {} { upvar Attrs Attrs upvar c c set opts {-joinstyle miter -capstyle butt} foreach {attr val} [array get Attrs] { switch -- $attr { "" {} stroke {lappend opts -fill [color $c $val]} stroke-width {lappend opts -width $val} stroke-linecap { switch -- $val { round {lappend opts -capstyle round} square {lappend opts -capstyle projecting} } } stroke-linejoin { switch -- $val { round {lappend opts -joinstyle round} bevel {lappend opts -joinstyle bevel} } } id {lappend opts -tags [list [list id $val]]} } } return $opts } proc svg::PolygonOpts {} { upvar Attrs Attrs upvar c c set opts {-joinstyle miter -fill "" -outline ""} foreach {attr val} [array get Attrs] { switch -- $attr { "" {} fill { if {$val != "" && $val != "none"} { lappend opts -fill [color $c $val] } } stroke { if {$val != "" && $val != "none"} { lappend opts -outline [color $c $val] } } stroke-width {lappend opts -width $val} stroke-linejoin { switch -- $val { round {lappend opts -joinstyle round} bevel {lappend opts -joinstyle bevel} } } id {lappend opts -tags [list [list id $val]]} } } return $opts } proc svg::CircleOpts {} { upvar Attrs Attrs upvar c c set opts {-smooth bezier -joinstyle round -fill "" -outline ""} foreach {attr val} [array get Attrs] { switch -- $attr { "" {} fill { if {$val != "" && $val != "none"} { lappend opts -fill [color $c $val] } } stroke { if {$val != "" && $val != "none"} { lappend opts -outline [color $c $val] } } stroke-width {lappend opts -width $val} id {lappend opts -tags [list [list id $val]]} } } return $opts } proc svg::ImageOpts {} { upvar Attrs Attrs upvar c c set opts {-anchor nw} foreach {attr val} [array get Attrs] { switch -- $attr { id {lappend opts -tags [list [list id $val]]} } } return $opts } proc svg::TextOpts {} { upvar Attrs Attrs upvar c c set opts {-anchor w} set fontopts {} foreach {attr val} [array get Attrs] { switch -- $attr { "" {} fill {lappend opts -fill [color $c $val]} font-family {lappend fontopts -family $val} font-size {lappend fontopts -size $val} font-size-adjust { # How to do this in Tk? } font-stretch { # How to do this in Tk? } font-style { if {[string equal $val italic] || [string equal $val oblique]} { lappend fontopts -slant italic } } font-variant { # How to do this in Tk? } font-weight { if {[string match bold* $val]} { lappend fontopts -weight bold } } text-decoration { foreach subval $val { switch -- $subval { underline { lappend fontopts -underline on } line-through { lappend fontopts -overstrike on } } } } dx { # How to do this in Tk? } dy { # How to do this in Tk? } id {lappend opts -tags [list [list id $val]]} } } return [list $opts $fontopts] } proc svg::TransformPoints {transform raw_points} { # SVG spec says coordinate points can be separated by comma or # white space or comma-with-white-space # string map... convert , to space # regsub... condense multiple whitespaces to single space regsub -all {\s\s*} [string map {, { }} [string trim $raw_points]] \ { } points_str set p {} foreach {x y} [split $points_str] { eval lappend p [TransformCoord $transform $x $y] } return $p } proc svg::ParseTransform {s} { Debug 2 $s set t {} while {[regexp {(\w+)\s*\(([^\)]*)\)(.*)} $s temp transform param s]} { lappend t [list $transform [split $param ", "]] } Debug 1 $s $t return $t } proc svg::TransformCoord {transform x y} { Debug 2 $transform $x $y set matrix [list 1 0 0 1 0 0] foreach t $transform { foreach {op param} $t break switch -- $op/[llength $param] { matrix/6 { set matrix [Tcompose $matrix $param] } translate/1 { foreach tx $param break set matrix [Tcompose $matrix [list 1 0 0 1 $tx 0]] } translate/2 { foreach {tx ty} $param break set matrix [Tcompose $matrix [list 1 0 0 1 $tx $ty]] } scale/1 { foreach sx $param break set matrix [Tcompose $matrix [list $sx 0 0 $sx 0 0]] } scale/2 { foreach {sx sy} $param break set matrix [Tcompose $matrix [list $sx 0 0 $sy 0 0]] } rotate/1 { foreach a $param break set a [expr {3.1415926 * $a / 180}] set matrix [Tcompose $matrix \ [list [expr {cos($a)}] [expr {sin($a)}] \ [expr {-sin($a)}] [expr {cos($a)}] 0 0]] } rotate/3 { foreach {a cx cy} $param break set a [expr {3.1415926 * $a / 180}] set matrix [Tcompose $matrix [list 1 0 0 1 $cx $cy]] set matrix [Tcompose $matrix \ [list [expr {cos($a)}] [expr {sin($a)}] \ [expr {-sin($a)}] [expr {cos($a)}] 0 0]] set matrix [Tcompose $matrix \ [list 1 0 0 1 [expr {-$cx}] [expr {-$cy}]]] } skewX/1 { foreach a $param break set a [expr {3.1415926 * $a / 180}] set matrix [Tcompose $matrix [list 1 0 [expr {tan($a)}] 1 0 0]] } skewY/1 { foreach a $param break set a [expr {3.1415926 * $a / 180}] set matrix [Tcompose $matrix [list 1 [expr {tan($a)}] 0 1 0 0]] } } } return [Tapply $matrix $x $y] } proc svg::Tcompose {matrix1 matrix2} { Debug 2 [list $matrix1] [list $matrix2] foreach {a1 b1 c1 d1 e1 f1} $matrix1 break foreach {a2 b2 c2 d2 e2 f2} $matrix2 break set a [expr {$a1*$a2 + $c1*$b2}] set b [expr {$b1*$a2 + $d1*$b2}] set c [expr {$a1*$c2 + $c1*$d2}] set d [expr {$b1*$c2 + $d1*$d2}] set e [expr {$a1*$e2 + $c1*$f2 + $e1}] set f [expr {$b1*$e2 + $d1*$f2 + $f1}] return [list $a $b $c $d $e $f] } proc svg::Tapply {matrix x y} { Debug 2 [list $matrix] $x $y foreach {a b c d e f} $matrix break set x1 [expr {$a*$x + $c*$y + $e}] set y1 [expr {$b*$x + $d*$y + $f}] Debug 1 $x1 $y1 return [list $x1 $y1] } proc svg::color {c color} { Debug 2 $color if {[catch {$c create line 0 0 0 0 -fill $color -width 0} id]} { return black } else { $c delete $id return $color } } proc svg::Debug {level args} { variable Debug if {$Debug >= $level} { puts "[lindex [info level -1] 0]: [join $args]" } } # vim:ft=tcl:ts=8:sw=4:sts=4:et tkabber-plugins/whiteboard/whiteboard.tcl000064400000000000000000001334111500237002100205000ustar00nobodynobody# whiteboard.tcl -- # # This file is a part of the Whiteboard plugin for Tkabber # XMPP client. It provides a user interface and communication # means. package require msgcat namespace eval wb { ::msgcat::mcload [file join [file dirname [info script]] msgs] if {![::plugins::is_registered whiteboard]} { ::plugins::register whiteboard \ -namespace [namespace current] \ -source [info script] \ -description [::msgcat::mc "Whether the Whiteboard\ plugin is loaded."] \ -loadcommand [namespace code load] \ -unloadcommand [namespace code unload] return } variable id_base [pid] ;# used in proc create_id } proc wb::load {} { hook::add chat_create_user_menu_hook \ [namespace current]::add_whiteboard_menu_item 47 hook::add chat_create_conference_menu_hook \ [namespace current]::add_whiteboard_menu_item 47 hook::add roster_jid_popup_menu_hook \ [namespace current]::add_whiteboard_menu_item 47 hook::add draw_message_hook [namespace current]::handle_wb 1 variable chats {} } proc wb::unload {} { hook::remove chat_create_user_menu_hook \ [namespace current]::add_whiteboard_menu_item 47 hook::remove chat_create_conference_menu_hook \ [namespace current]::add_whiteboard_menu_item 47 hook::remove roster_jid_popup_menu_hook \ [namespace current]::add_whiteboard_menu_item 47 hook::remove draw_message_hook [namespace current]::handle_wb 1 variable chats foreach chatid $chats { destroy_win [win_id whiteboard $chatid] } namespace delete ::svg foreach var [info vars [namespace current]::*] { catch {unset $var} } } package require base64 catch {package require Img} uplevel #0 [list source [file join [file dirname [info script]] svgrender.tcl]] proc wb::add_whiteboard_menu_item {m xlib jid} { $m add command -label [::msgcat::mc "Whiteboard"] \ -command [list [namespace current]::open_wb $xlib $jid -raise 1] } proc wb::open_wb {xlib jid args} { variable width variable dofill set raise 0 foreach {key val} $args { switch -- $key { -raise { set raise $val } } } set chatid [chat::chatid $xlib $jid] set w [win_id whiteboard $chatid] if {[winfo exists $w]} { if {$raise} { raise_win $w } return } set jid [chat::get_jid $chatid] set title [::msgcat::mc "%s whiteboard" $jid] add_win $w -title $title \ -tabtitle $title \ -class Whiteboard \ -raise $raise set sw [ScrolledWindow $w.sw] pack $sw -side right -fill both -expand yes set c [Canvas $w.c -background white] $sw setwidget $c bind $c [namespace code [list clean_wb $chatid]] bindscroll $c set tb [Frame $w.tb] pack $tb -side left -fill y set filler [Frame $w.filler -width 2m] pack $filler -side left -fill y set tbfreehand \ [Radiobutton $w.tb.freehand -text [::msgcat::mc "FreeHand"] \ -variable [namespace current]::tool($chatid) \ -value freehand \ -command [list [namespace current]::freehand_bind \ $c $chatid]] set tbpolyline [Radiobutton $w.tb.line -text [::msgcat::mc "PolyLine"] \ -variable [namespace current]::tool($chatid) \ -value polyline \ -command [list [namespace current]::line_bind \ $c $chatid]] set tbrectangle \ [Radiobutton $w.tb.rectangle -text [::msgcat::mc "Rectangle"] \ -variable [namespace current]::tool($chatid) \ -value rectangle \ -command [list [namespace current]::rectangle_bind \ $c $chatid]] set tbpolygon [Radiobutton $w.tb.polygon -text [::msgcat::mc "Polygon"] \ -variable [namespace current]::tool($chatid) \ -value polygon \ -command [list [namespace current]::polygon_bind \ $c $chatid]] set tbcircle [Radiobutton $w.tb.circle -text [::msgcat::mc "Circle"] \ -variable [namespace current]::tool($chatid) \ -value circle \ -command [list [namespace current]::circle_bind \ $c $chatid]] set tbimage [Radiobutton $w.tb.image -text [::msgcat::mc "Image"] \ -variable [namespace current]::tool($chatid) \ -value image \ -command [list [namespace current]::image_bind \ $c $chatid]] set tbtext [Radiobutton $w.tb.text -text [::msgcat::mc "Text"] \ -variable [namespace current]::tool($chatid) \ -value text \ -command [list [namespace current]::text_bind \ $c $chatid]] set tbmove [Radiobutton $w.tb.move -text [::msgcat::mc "Move/Transform"] \ -variable [namespace current]::tool($chatid) \ -value move \ -command [list [namespace current]::move_bind \ $c $chatid]] pack $tbfreehand -anchor w pack $tbpolyline -anchor w pack $tbrectangle -anchor w pack $tbpolygon -anchor w pack $tbcircle -anchor w pack $tbimage -anchor w pack $tbtext -anchor w pack $tbmove -anchor w Button $w.tb.clear -text [::msgcat::mc "Clear"] \ -command [list [namespace current]::send_clear $chatid] pack $w.tb.clear -side bottom -anchor w -fill x Button $w.tb.save -text [::msgcat::mc "Save..."] \ -command [list [namespace current]::save_wb $chatid] pack $w.tb.save -side bottom -anchor w -fill x #frame $w.tb.spacer1 -relief sunken -bd 1 -height 2 -highlightthickness 0 #pack $w.tb.spacer1 -side bottom -anchor w -fill x -pady 1m variable text_set_fr set text_set_fr($chatid) $w.tb Label $w.tb.example_char -text Aa pack $w.tb.example_char -side bottom -fill x Button $w.tb.seltextcol -text [::msgcat::mc "Text color"] \ -command [list [namespace current]::select_text_color \ $w.tb.seltextcol $w.tb.example_char] pack $w.tb.seltextcol -side bottom -anchor w -fill x Button $w.tb.selfont -text [::msgcat::mc "Text font"] \ -command [list [namespace current]::select_font \ $w.tb.selfont $w.tb.example_char] pack $w.tb.selfont -side bottom -anchor w -fill x #frame $w.tb.spacer2 -relief sunken -bd 1 -height 2 -highlightthickness 0 #pack $w.tb.spacer2 -side bottom -anchor w -fill x -pady 1m Frame $w.tb.fill Checkbutton $w.tb.dofill -text [::msgcat::mc "Fill"] \ -variable [namespace current]::dofill($chatid) pack $w.tb.dofill -side left -in $w.tb.fill canvas $w.tb.fillcolor -background \#FFFFFF -height 5m -width 5m \ -borderwidth 0 -highlightthickness 0 pack $w.tb.fillcolor -side left -padx 3m -in $w.tb.fill pack $w.tb.fill -side bottom -anchor w -fill x Button $w.tb.selfillcol -text [::msgcat::mc "Fill color"] \ -command [list [namespace current]::select_color \ $w.tb.selfillcol $w.tb.fillcolor] pack $w.tb.selfillcol -side bottom -anchor w -fill x #frame $w.tb.spacer3 -relief sunken -bd 1 -height 2 -highlightthickness 0 #pack $w.tb.spacer3 -side bottom -anchor w -fill x -pady 1m canvas $w.tb.color -background \#000000 -height 5m -width 1 \ -borderwidth 0 -highlightthickness 0 pack $w.tb.color -side bottom Frame $w.tb.linewidth Label $w.tb.lwidth -text [::msgcat::mc "Line width: "] pack $w.tb.lwidth -side left -in $w.tb.linewidth Spinbox $w.tb.width 1 100 1 [namespace current]::width($chatid) -width 3 pack $w.tb.width -side left -in $w.tb.linewidth pack $w.tb.linewidth -side bottom -anchor w -fill x Button $w.tb.selcol -text [::msgcat::mc "Line color"] \ -command [list [namespace current]::select_color \ $w.tb.selcol $w.tb.color] pack $w.tb.selcol -side bottom -anchor w -fill x variable balloon set balloon($chatid) 1 Checkbutton $w.tb.balloon -text [::msgcat::mc "Show balloons"] \ -variable [namespace current]::balloon($chatid) pack $w.tb.balloon -side bottom -anchor w -fill x $c bind all \ [list [namespace current]::balloon $chatid $c enter %X %Y] $c bind all \ [list [namespace current]::balloon $chatid $c motion %X %Y] $c bind all \ [list [namespace current]::balloon $chatid $c leave %X %Y] set width($chatid) 1 set dofill($chatid) 0 trace add variable [namespace current]::width($chatid) write \ [list [namespace current]::change_width \ $w.tb.color [namespace current]::width($chatid)] variable chats lappend chats $chatid variable tool set tool($chatid) move move_bind $c $chatid } proc wb::clean_wb {chatid} { variable width variable dofill variable tool variable balloon variable text_set_fr variable chats variable text_entered if {[set idx [lsearch -exact $chats $chatid]] >= 0} { set chats [lreplace $chats $idx $idx] } catch {unset width($chatid)} catch {unset dofill($chatid)} catch {unset tool($chatid)} catch {unset balloon($chatid)} catch {unset text_set_fr($chatid)} catch {unset text_entered($chatid)} } proc wb::balloon {chatid c action X Y} { variable balloon if {!$balloon($chatid)} return set id [$c find withtag current] set tags {} foreach t [$c gettags $id] { if {[lindex $t 0] == "time"} { lappend tags $t } } set msgs {} foreach t [lsort -index 1 -integer $tags] { lappend msgs [lindex $t 2] } balloon::default_balloon $c:$id $action $X $Y -text [join $msgs "\n"] } proc wb::select_color {but col} { set color [SelectColor::menu $col.color [list below $but] \ -color [$col cget -background]] if {[string length $color]} { $col configure -background $color } } proc wb::select_font {chatid col} { variable app_font set font_desc [SelectFont .s -type dialog] if {[string length $font_desc] == 0} return if {![info exists app_font($font_desc)]} { set app_font($font_desc) \ [eval font create [list $font_desc] [font actual $font_desc]] } $col configure -font $app_font($font_desc) } proc wb::select_text_color {but col} { set color [SelectColor::menu $col.color [list below $but] \ -color [$col cget -foreground]] if {[string length $color]} { $col configure -foreground $color } } proc wb::get_text_color {chatid} { variable text_set_fr $text_set_fr($chatid).example_char cget -foreground } proc wb::get_text_font {chatid} { variable text_set_fr $text_set_fr($chatid).example_char cget -font } proc wb::get_fill_color {chatid} { set w [win_id whiteboard $chatid] $w.tb.fillcolor cget -background } proc wb::get_color {chatid} { set w [win_id whiteboard $chatid] $w.tb.color cget -background } proc wb::change_width {col widthvar args} { set width [set $widthvar] $col configure -width $width } proc wb::get_width {chatid} { set w [win_id whiteboard $chatid] $w.tb.color cget -width } proc wb::save_wb {chatid} { set w [win_id whiteboard $chatid] set filepath [tk_getSaveFile -defaultextension .eps \ -filetypes \ {{{Encapsulated PostScript files} *.eps} {{All files} *}}] if {$filepath == ""} return $w.c postscript -file $filepath } ############################################################################### proc wb::create_id {} { # Unseeded random number is not good enough, because remote clients # are likely to produce the same numbers. return [rand 10000][clock seconds][set [namespace current]::id_base] } proc wb::send_svg {chatid tag {tag2 ""}} { if {[chat::is_groupchat $chatid]} { set type groupchat } else { set type chat } set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] set xlist [list [::xmpp::xml::create x \ -xmlns tkabber:whiteboard \ -subelement [::xmpp::xml::create svg \ -xmlns http://www.w3.org/2000/svg \ -subelement $tag]]] if {$tag2 != ""} { lappend xlist $tag2 } ::xmpp::sendMessage $xlib $jid -type $type -xlist $xlist } proc wb::send_clear {chatid} { if {[chat::is_groupchat $chatid]} { set type groupchat } else { set type chat set w [win_id whiteboard $chatid] $w.c delete all $w.c configure -scrollregion [$w.c bbox all] } set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] ::xmpp::sendMessage $xlib $jid -type $type \ -xlist [list [::xmpp::xml::create x \ -xmlns tkabber:whiteboard \ -subelement [::xmpp::xml::create clear]]] } proc wb::handle_wb {chatid from type body x} { set seconds [::xmpp::xml::getAttr [::xmpp::delay::parse $x] seconds] foreach xelem $x { ::xmpp::xml::split $xelem tag xmlns attrs cdata subels if {[string equal $xmlns tkabber:whiteboard]} { open_wb [chat::get_xlib $chatid] [chat::get_jid $chatid] set w [win_id whiteboard $chatid] foreach subel $subels { parse_item $chatid $from $seconds $subel } tab_set_updated $w 1 message $w.c configure -scrollregion [$w.c bbox all] } } } proc wb::parse_item {chatid from seconds item} { set w [win_id whiteboard $chatid] ::xmpp::xml::split $item tag xmlns attrs cdata subels switch -- $tag { svg { foreach subel $subels { set id [svg::parseSVGItem $w.c {} {} $subel] if {$id != ""} { $w.c addtag [list tag $subel] withtag $id $w.c addtag [time_tag created $from $seconds] withtag $id } } } transform { set id [::xmpp::xml::getAttr $attrs id] set transform [::xmpp::xml::getAttr $attrs transform] set transform1 $transform set tags [$w.c gettags [list id $id]] set child {} foreach t $tags { if {[lindex $t 0] == "tag"} { set child [lindex $t 1] break } } foreach t $tags { if {[lindex $t 0] == "transform"} { set transform "$transform [lindex $t 1]" break } } if {$child != {}} { $w.c delete [list id $id] set id1 [svg::parseSVGItem $w.c \ [svg::ParseTransform $transform] {} $child] if {$id1 != ""} { foreach t $tags { $w.c addtag $t withtag $id1 } add_transform_tag $w.c $id $transform1 $w.c addtag [time_tag transformed $from $seconds] \ withtag $id1 } } } move { set id [::xmpp::xml::getAttr $attrs id] set dx [::xmpp::xml::getAttr $attrs dx] set dy [::xmpp::xml::getAttr $attrs dy] if {![string is double $dx] || $dx == ""} {set dx 0} if {![string is double $dy] || $dy == ""} {set dy 0} add_transform_tag $w.c $id translate($dx,$dy) $w.c addtag [time_tag moved $from $seconds] withtag [list id $id] $w.c move [list id $id] $dx $dy } remove { $w.c delete [list id [::xmpp::xml::getAttr $attrs id]] } clear { $w.c delete all } } } ############################################################################### proc wb::add_transform_tag {c id transform} { set tags [$c gettags [list id $id]] foreach t $tags { if {[lindex $t 0] == "transform"} { set transform "$transform [lindex $t 1]" $c dtag [list id $id] $t break } } $c addtag [list transform $transform] withtag [list id $id] } proc wb::time_tag {type jid {seconds ""}} { set seconds_now [clock seconds] set format $::plugins::options(timestamp_format) set seconds_day_before \ [clock scan "-23 hours 59 minutes" -base $seconds_now] if {$seconds == ""} { set seconds $seconds_now } if {$seconds <= $seconds_day_before} { set format $::plugins::options(delayed_timestamp_format) } set time [clock format $seconds -format $format] switch -- $type { created { return [list time $seconds \ [::msgcat::mc "%s created: %s" $time $jid]] } moved { return [list time $seconds \ [::msgcat::mc "%s moved: %s" $time $jid]] } transformed { return [list time $seconds \ [::msgcat::mc "%s transformed: %s" $time $jid]] } default { return "" } } } ############################################################################### proc wb::popup_menu {c chatid x y} { set m .whiteboard_popup_menu if {[winfo exists $m]} { destroy $m } set tags [$c gettags current] set id "" set tag "" foreach t $tags { switch -- [lindex $t 0] { id { set id [lindex $t 1] } tag { ::xmpp::xml::split [lindex $t 1] tag xmlns attrs cdata subels } } } menu $m -tearoff 0 if {![string equal $id ""]} { set state normal switch -- $tag { image - text - "" { set state1 disabled } default { set state1 normal } } } else { set state disabled set state1 disabled } $m add command -label [::msgcat::mc "Flip horizontally"] \ -command [list [namespace current]::flip_h $c $chatid $id] \ -state $state1 $m add command -label [::msgcat::mc "Flip vertically"] \ -command [list [namespace current]::flip_v $c $chatid $id] \ -state $state1 $m add command -label [::msgcat::mc "Rotate 45\u00b0"] \ -command [list [namespace current]::rotate $c \ $chatid $id -45] \ -state $state1 $m add command -label [::msgcat::mc "Rotate 90\u00b0"] \ -command [list [namespace current]::rotate $c \ $chatid $id -90] \ -state $state1 $m add command -label [::msgcat::mc "Rotate 135\u00b0"] \ -command [list [namespace current]::rotate $c \ $chatid $id -135] \ -state $state1 $m add command -label [::msgcat::mc "Rotate 180\u00b0"] \ -command [list [namespace current]::rotate $c \ $chatid $id -180] \ -state $state1 $m add command -label [::msgcat::mc "Skew horizontally 10\u00b0"] \ -command [list [namespace current]::skew $c \ $chatid $id X -10] \ -state $state1 $m add command -label [::msgcat::mc "Skew horizontally -10\u00b0"] \ -command [list [namespace current]::skew $c \ $chatid $id X 10] \ -state $state1 $m add command -label [::msgcat::mc "Skew vertically 10\u00b0"] \ -command [list [namespace current]::skew $c \ $chatid $id Y 10] \ -state $state1 $m add command -label [::msgcat::mc "Skew vertically -10\u00b0"] \ -command [list [namespace current]::skew $c \ $chatid $id Y -10] \ -state $state1 $m add separator $m add command -label [::msgcat::mc "Remove"] \ -command [list [namespace current]::remove_b1p $c \ $chatid $id] \ -state $state tk_popup $m $x $y } ############################################################################### proc wb::flip_h {c chatid id} { lassign [$c bbox [list id $id]] x1 y1 x2 y2 set x02 [expr {$x1+$x2}] transform $c $chatid $id "translate($x02,0) scale(-1,1)" } proc wb::flip_v {c chatid id} { lassign [$c bbox [list id $id]] x1 y1 x2 y2 set y02 [expr {$y1+$y2}] transform $c $chatid $id "translate(0,$y02) scale(1,-1)" } proc wb::rotate {c chatid id angle} { lassign [$c bbox [list id $id]] x1 y1 x2 y2 set x0 [expr {($x1+$x2)/2}] set y0 [expr {($y1+$y2)/2}] transform $c $chatid $id "rotate($angle,$x0,$y0)" } proc wb::skew {c chatid id xy angle} { lassign [$c bbox [list id $id]] x1 y1 x2 y2 set x0 [expr {($x1+$x2)/2}] set y0 [expr {($y1+$y2)/2}] transform $c $chatid $id "translate($x0,$y0) skew${xy}($angle)\ translate([expr {-$x0}],[expr {-$y0}])" } proc wb::transform {c chatid id transform} { set elem [::xmpp::xml::create transform \ -attrs [list id $id transform $transform]] if {[chat::is_groupchat $chatid]} { set type groupchat } else { set type chat set jid [connection_jid [chat::get_xlib $chatid]] parse_item $chatid $jid [clock seconds] $elem $c configure -scrollregion [$c bbox all] } set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] ::xmpp::sendMessage $xlib $jid \ -type $type \ -xlist [list [::xmpp::xml::create x \ -xmlns tkabber:whiteboard \ -subelement $elem]] } ############################################################################### ############################################################################### # Line proc wb::line_bind {c chatid} { bind $c \ [list [namespace current]::line_b1 [double% $c] \ [double% $chatid] %x %y] bind $c {} bind $c [list [namespace current]::line_b1m [double% $c] %x %y] bind $c {} bind $c <> [list [namespace current]::line_b3 \ [double% $c] [double% $chatid]] $c configure -cursor crosshair } proc wb::line_b1 {c chatid x y} { variable line set x [$c canvasx $x] set y [$c canvasy $y] if {[info exists line(drawed)]} { lappend line(coords) $x $y catch {$c delete $line(temp)} set tag [line_tag ""] set line(temp) [svg::parseSVGItem $c {} {} $tag] } else { set line(drawed) 1 set line(coords) [list $x $y] set line(options) \ [list stroke-linejoin miter stroke [get_color $chatid]] if {[set width [get_width $chatid]] != 1} { lappend line(options) stroke-width $width } } } proc wb::line_b1m {c x y} { variable line set x [$c canvasx $x] set y [$c canvasy $y] if {[info exists line(drawed)]} { set coords $line(coords) lappend line(coords) $x $y catch {$c delete $line(temp)} set tag [line_tag ""] set line(temp) [svg::parseSVGItem $c {} {} $tag] set line(coords) $coords } } proc wb::line_b3 {c chatid} { variable line catch { unset line(drawed) set id [create_id] catch {$c delete $line(temp)} set tag [line_tag $id] set line(temp) [svg::parseSVGItem $c {} {} $tag] if {[chat::is_groupchat $chatid]} { $c delete $line(temp) } else { set jid [connection_jid [chat::get_xlib $chatid]] $c addtag [list tag $tag] withtag $line(temp) $c addtag [time_tag created $jid] withtag $line(temp) $c configure -scrollregion [$c bbox all] } send_svg $chatid $tag set line(coords) {} set line(temp) {} } } proc wb::line_tag {id} { variable line set attrs $line(options) lappend attrs points $line(coords) if {$id != ""} { lappend attrs id $id } return [::xmpp::xml::create polyline -attrs $attrs] } ############################################################################### ############################################################################### # Polygon proc wb::polygon_bind {c chatid} { bind $c \ [list [namespace current]::polygon_b1 [double% $c] \ [double% $chatid] %x %y] bind $c {} bind $c [list [namespace current]::polygon_m [double% $c] %x %y] bind $c {} bind $c <> [list [namespace current]::polygon_b3 \ [double% $c] [double% $chatid]] $c configure -cursor crosshair } proc wb::polygon_b1 {c chatid x y} { variable polygon variable line1 variable line2 variable dofill set x [$c canvasx $x] set y [$c canvasy $y] if {[info exists polygon(drawed)]} { lappend polygon(coords) $x $y catch {$c delete $line1(temp)} catch {$c delete $line2(temp)} catch {$c delete $polygon(temp)} set tag [polygon_tag ""] set polygon(temp) [svg::parseSVGItem $c {} {} $tag] } else { set polygon(drawed) 1 set polygon(coords) [list $x $y] set polygon(line_options) [list -fill [get_color $chatid] \ -width [get_width $chatid] \ -joinstyle miter] set polygon(options) \ [list stroke-linejoin miter stroke [get_color $chatid]] if {[set width [get_width $chatid]] != 1} { lappend polygon(options) stroke-width $width } if {$dofill($chatid) == 1} { lappend polygon(options) fill [get_fill_color $chatid] } } } proc wb::polygon_m {c x y} { variable polygon variable line1 variable line2 set x [$c canvasx $x] set y [$c canvasy $y] if {[info exists polygon(drawed)]} { set x1 [lindex $polygon(coords) 0] set y1 [lindex $polygon(coords) 1] set xn [lindex $polygon(coords) end-1] set yn [lindex $polygon(coords) end] catch {$c delete $line1(temp)} catch {$c delete $line2(temp)} set line1(temp) \ [eval $c create line $x1 $y1 $x $y $polygon(line_options)] set line2(temp) \ [eval $c create line $xn $yn $x $y $polygon(line_options)] } } proc wb::polygon_b3 {c chatid} { variable polygon variable line1 variable line2 catch { unset polygon(drawed) set id [create_id] catch {$c delete $line1(temp)} catch {$c delete $line2(temp)} catch {$c delete $polygon(temp)} set tag [polygon_tag $id] if {[llength $polygon(coords)] > 4} { set polygon(temp) [svg::parseSVGItem $c {} {} $tag] if {[chat::is_groupchat $chatid]} { $c delete $polygon(temp) } else { set jid [connection_jid [chat::get_xlib $chatid]] $c addtag [list tag $tag] withtag $polygon(temp) $c addtag [time_tag created $jid] withtag $polygon(temp) $c configure -scrollregion [$c bbox all] } send_svg $chatid $tag } set polygon(coords) {} set polygon(temp) {} } } proc wb::polygon_tag {id} { variable polygon set attrs $polygon(options) lappend attrs points $polygon(coords) if {$id != ""} { lappend attrs id $id } return [::xmpp::xml::create polygon -attrs $attrs] } ############################################################################### ############################################################################### # Rectangle proc wb::rectangle_bind {c chatid} { bind $c \ [list [namespace current]::rectangle_b1 [double% $c] \ [double% $chatid] %x %y] bind $c \ [list [namespace current]::rectangle_b1m [double% $c] %x %y] bind $c {} bind $c \ [list [namespace current]::rectangle_b1r [double% $c] \ [double% $chatid] %x %y] bind $c <> {} $c configure -cursor crosshair } proc wb::rectangle_b1 {c chatid x y} { variable rectangle variable dofill set x [$c canvasx $x] set y [$c canvasy $y] set rectangle(drawed) 1 set rectangle(x1) $x set rectangle(y1) $y set rectangle(options) [list stroke [get_color $chatid]] if {$dofill($chatid) == 1} { lappend rectangle(options) fill [get_fill_color $chatid] } if {[set width [get_width $chatid]] != 1} { lappend rectangle(options) stroke-width $width } } proc wb::rectangle_b1r {c chatid x y} { variable rectangle if {[info exists rectangle(drawed)]} { unset rectangle(drawed) set rectangle(x2) [$c canvasx $x] set rectangle(y2) [$c canvasy $y] set id [create_id] set tag [rectangle_tag $id] catch {$c delete $rectangle(temp)} set rectangle(temp) [svg::parseSVGItem $c {} {} $tag] if {[chat::is_groupchat $chatid]} { $c delete $rectangle(temp) } else { set jid [connection_jid [chat::get_xlib $chatid]] $c addtag [list tag $tag] withtag $rectangle(temp) $c addtag [time_tag created $jid] withtag $rectangle(temp) $c configure -scrollregion [$c bbox all] } send_svg $chatid $tag unset rectangle(x1) unset rectangle(x2) unset rectangle(y1) unset rectangle(y2) set rectangle(temp) {} } } proc wb::rectangle_b1m {c x y} { variable rectangle if {[info exists rectangle(drawed)]} { set rectangle(x2) [$c canvasx $x] set rectangle(y2) [$c canvasy $y] set tag [rectangle_tag ""] catch {$c delete $rectangle(temp)} set rectangle(temp) [svg::parseSVGItem $c {} {} $tag] } } proc wb::rectangle_tag {id} { variable rectangle set attrs $rectangle(options) if {$rectangle(x2) > $rectangle(x1)} { lappend attrs x $rectangle(x1) \ width [expr {$rectangle(x2) - $rectangle(x1)}] } else { lappend attrs x $rectangle(x2) \ width [expr {$rectangle(x1) - $rectangle(x2)}] } if {$rectangle(y2) > $rectangle(y1)} { lappend attrs y $rectangle(y1) \ height [expr {$rectangle(y2) - $rectangle(y1)}] } else { lappend attrs y $rectangle(y2) \ height [expr {$rectangle(y1) - $rectangle(y2)}] } if {$id != ""} { lappend attrs id $id } return [::xmpp::xml::create rect -attrs $attrs] } ############################################################################### ############################################################################### # Circle proc wb::circle_bind {c chatid} { bind $c \ [list [namespace current]::circle_b1 [double% $c] \ [double% $chatid] %x %y] bind $c \ [list [namespace current]::circle_b1m [double% $c] %x %y] bind $c {} bind $c \ [list [namespace current]::circle_b1r [double% $c] \ [double% $chatid] %x %y] bind $c <> {} $c configure -cursor crosshair } proc wb::circle_b1 {c chatid x y} { variable circle variable dofill set cx [$c canvasx $x] set cy [$c canvasy $y] set circle(drawed) 1 set circle(cx) $cx set circle(cy) $cy set circle(options) [list cx $cx cy $cy stroke [get_color $chatid]] if {$dofill($chatid) == 1} { lappend circle(options) fill [get_fill_color $chatid] } if {[set width [get_width $chatid]] != 1} { lappend circle(options) stroke-width $width } } proc wb::circle_b1r {c chatid x y} { variable circle if {[info exists circle(drawed)]} { unset circle(drawed) set cx $circle(cx) set cy $circle(cy) set x [$c canvasx $x] set y [$c canvasy $y] set r [expr {hypot($cx - $x, $cy - $y)}] set id [create_id] set tag [circle_tag $id $r] catch {$c delete $circle(temp)} set circle(temp) [svg::parseSVGItem $c {} {} $tag] if {[chat::is_groupchat $chatid]} { $c delete $circle(temp) } else { set jid [connection_jid [chat::get_xlib $chatid]] $c addtag [list tag $tag] withtag $circle(temp) $c addtag [time_tag created $jid] withtag $circle(temp) $c configure -scrollregion [$c bbox all] } send_svg $chatid $tag unset circle(cx) unset circle(cy) set circle(temp) {} } } proc wb::circle_b1m {c x y} { variable circle if {[info exists circle(drawed)]} { set cx $circle(cx) set cy $circle(cy) set x [$c canvasx $x] set y [$c canvasy $y] set r [expr hypot($cx - $x, $cy - $y)] set tag [circle_tag "" $r] catch {$c delete $circle(temp)} set circle(temp) [svg::parseSVGItem $c {} {} $tag] } } proc wb::circle_tag {id r} { variable circle set attrs $circle(options) lappend attrs r $r if {$id != ""} { lappend attrs id $id } return [::xmpp::xml::create circle -attrs $attrs] } ############################################################################### ############################################################################### # Freehand proc wb::freehand_bind {c chatid} { bind $c \ [list [namespace current]::freehand_b1p \ [double% $c] [double% $chatid] %x %y] bind $c [list [namespace current]::freehand_b1m \ [double% $c] %x %y] bind $c \ [list [namespace current]::freehand_b1r [double% $c] [double% $chatid]] bind $c <> {} $c configure -cursor crosshair } proc wb::freehand_b1p {c chatid x y} { variable line set x [$c canvasx $x] set y [$c canvasy $y] set line(drawed) 1 set line(coords) [list $x $y] set line(options) [list stroke-linejoin round stroke [get_color $chatid]] if {[set width [get_width $chatid]] != 1} { lappend line(options) stroke-width $width } } proc wb::freehand_b1m {c x y} { variable line set x [$c canvasx $x] set y [$c canvasy $y] if {[info exists line(drawed)]} { lappend line(coords) $x $y catch {$c delete $line(temp)} set tag [freehand_tag ""] set line(temp) [svg::parseSVGItem $c {} {} $tag] } } proc wb::freehand_b1r {c chatid} { variable line catch { unset line(drawed) set id [create_id] set tag [freehand_tag $id] catch {$c delete $line(temp)} set line(temp) [svg::parseSVGItem $c {} {} $tag] if {[chat::is_groupchat $chatid]} { $c delete $line(temp) } else { set jid [connection_jid [chat::get_xlib $chatid]] $c addtag [list tag $tag] withtag $line(temp) $c addtag [time_tag created $jid] withtag $line(temp) $c configure -scrollregion [$c bbox all] } send_svg $chatid $tag set line(coords) {} set line(temp) {} } } proc wb::freehand_tag {id} { variable line set attrs $line(options) lappend attrs points $line(coords) if {$id != ""} { lappend attrs id $id } return [::xmpp::xml::create polyline -attrs $attrs] } ############################################################################### ############################################################################### # Remove proc wb::remove_b1p {c chatid id} { set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] if {[chat::is_groupchat $chatid]} { set type groupchat } else { set type chat $c delete [list id $id] $c configure -scrollregion [$c bbox all] } if {$id != ""} { ::xmpp::sendMessage $xlib $jid \ -type $type \ -xlist [list [::xmpp::xml::create x \ -xmlns tkabber:whiteboard \ -subelement [::xmpp::xml::create remove \ -attrs [list id $id]]]] } } ############################################################################### ############################################################################### # Move proc wb::move_bind {c chatid} { bind $c \ [list [namespace current]::move_b1p [double% $c] \ [double% $chatid] %x %y] bind $c \ [list [namespace current]::move_b1m [double% $c] %x %y] bind $c \ [list [namespace current]::move_b1r [double% $c] [double% $chatid]] bind $c <> \ [list [namespace current]::popup_menu [double% $c] \ [double% $chatid] %X %Y] bind $c {} $c configure -cursor "" } proc wb::move_b1p {c chatid x y} { variable move set tags [$c gettags current] set id "" foreach t $tags { if {[lindex $t 0] == "id"} { set id [lindex $t 1] break } } if {$id != ""} { set x [$c canvasx $x] set y [$c canvasy $y] set move(startx) $x set move(starty) $y set move(lastx) $x set move(lasty) $y set move(id) $id $c configure -cursor hand2 } else { catch {unset move(id)} } } proc wb::move_b1m {c x y} { variable move if {[info exists move(id)]} { set id $move(id) set x [$c canvasx $x] set y [$c canvasy $y] $c move [list id $id] [expr {$x - $move(lastx)}] \ [expr {$y - $move(lasty)}] set move(lastx) $x set move(lasty) $y } } proc wb::move_b1r {c chatid} { variable move if {[info exists move(id)]} { set id $move(id) set x $move(lastx) set y $move(lasty) set dx [expr {$x - $move(startx)}] set dy [expr {$y - $move(starty)}] if {$dx == 0 && $dy == 0} { $c configure -cursor "" return } if {[chat::is_groupchat $chatid]} { set type groupchat $c move [list id $id] [expr {-$dx}] [expr {-$dy}] } else { set type chat set jid [connection_jid [chat::get_xlib $chatid]] add_transform_tag $c $id translate($dx,$dy) $c addtag [time_tag moved $jid] withtag [list id $id] $c configure -scrollregion [$c bbox all] } set attrs [list id $id dx $dx dy $dy] set xlib [chat::get_xlib $chatid] set jid [chat::get_jid $chatid] ::xmpp::sendMessage $xlib $jid \ -type $type \ -xlist [list [::xmpp::xml::create x \ -xmlns tkabber:whiteboard \ -subelement [::xmpp::xml::create move \ -attrs $attrs]]] $c configure -cursor "" } } ############################################################################### # Image proc wb::image_bind {c chatid} { bind $c {} bind $c {} bind $c \ [list [namespace current]::image_b1 [double% $c] \ [double% $chatid] %x %y] bind $c <> {} $c configure -cursor crosshair } proc wb::image_b1 {c chatid x y} { variable image_info set image_info(x) [$c canvasx $x] set image_info(y) [$c canvasy $y] set w [win_id whiteboard $chatid] if {[catch { package require Img }]} { set types [list [list [::msgcat::mc "GIF images"] {.gif}] \ [list [::msgcat::mc "All files"] {*}]] } else { set types \ [list [list [::msgcat::mc "All images"] {.jpg .jpeg .gif .png}] \ [list [::msgcat::mc "JPEG images"] {.jpg .jpeg}] \ [list [::msgcat::mc "GIF images"] {.gif}] \ [list [::msgcat::mc "PNG images"] {.png}] \ [list [::msgcat::mc "All files"] {*}]] } set filename [tk_getOpenFile -filetypes $types] if {$filename == ""} return if {[catch {image create photo -file $filename} res]} { if {[winfo exists .load_image_error]} { destroy .load_image_error } NonmodalMessageDlg .load_image_error -aspect 50000 -icon error \ -message [::msgcat::mc "Loading image failed: %s." \ $res] return } image delete $res set f [open $filename] fconfigure $f -translation binary set binval [read $f] close $f binary scan $binval H4 binsig switch -- $binsig { ffd8 { set type "image/jpeg" } 4749 { set type "image/gif" } 8950 { set type "image/png" } default { set type "image" } } set cid [::xmpp::bob::cid $binval] set data [::xmpp::bob::data $type $binval -maxage 0] set id [create_id] set attrs [list id $id x $image_info(x) y $image_info(y) \ type $type http://www.w3.org/1999/xlink:href cid:$cid] set tag [::xmpp::xml::create image -attrs $attrs] if {![chat::is_groupchat $chatid]} { ::xmpp::bob::cache [list $data] set imageid [svg::parseSVGItem $c {} {} $tag] set jid [connection_jid [chat::get_xlib $chatid]] $c addtag [list tag $tag] withtag $imageid $c addtag [time_tag created $jid] withtag $imageid $c configure -scrollregion [$c bbox all] } send_svg $chatid $tag $data } ############################################################################### # Text proc wb::text_bind {c chatid} { bind $c {} bind $c {} bind $c \ [list [namespace current]::text_b1 [double% $c] \ [double% $chatid] %x %y] bind $c <> {} $c configure -cursor crosshair } proc wb::text_b1 {c chatid x y} { variable text_info set text_info(x) [$c canvasx $x] set text_info(y) [$c canvasy $y] set w [win_id whiteboard $chatid] set wt $w.text_dialog if {[winfo exists $wt]} { wm deiconify $wt } else { Dialog $wt -anchor e \ -title [::msgcat::mc "Enter text"] \ -side bottom \ -modal none \ -default 0 \ -cancel 1 $wt add -text [::msgcat::mc "OK"] \ -command [list [namespace current]::text_ok $wt $c $chatid] $wt add -text [::msgcat::mc "Cancel"] \ -command [list [namespace current]::text_cancel $wt $c $chatid] set en [Entry $wt.text -width 80 \ -textvariable [namespace current]::text_entered($chatid)] pack $en -side top -in [$wt getframe] $wt draw $en } } proc wb::text_ok {wt c chatid} { variable app_font variable text_info variable text_entered set id [create_id] set text $text_entered($chatid) set attrs [list id $id x $text_info(x) y $text_info(y) \ fill [get_text_color $chatid]] set font [get_text_font $chatid] if {[info exists app_font($font)]} { array set font_opt [font configure $font] lappend attrs font-size $font_opt(-size) \ font-family $font_opt(-family) if {$font_opt(-underline) || $font_opt(-overstrike)} { set dec {} if {$font_opt(-underline)} { lappend dec underline } if {$font_opt(-overstrike)} { lappend dec line-through } lappend attrs text-decoration $dec } if {[string equal $font_opt(-slant) italic]} { lappend attrs font-style italic } if {[string equal $font_opt(-weight) bold]} { lappend attrs font-weight bold } unset font_opt } set tag [::xmpp::xml::create text -attrs $attrs -cdata $text] if {![chat::is_groupchat $chatid]} { set textid [svg::parseSVGItem $c {} {} $tag] set jid [connection_jid [chat::get_xlib $chatid]] $c addtag [list tag $tag] withtag $textid $c addtag [time_tag created $jid] withtag $textid $c configure -scrollregion [$c bbox all] } send_svg $chatid $tag wm withdraw $wt } proc wb::text_cancel {wt c chatid} { wm withdraw $wt } # vim:ft=tcl:ts=8:sw=4:sts=4:et