pax_global_header00006660000000000000000000000064150573377030014524gustar00rootroot0000000000000052 comment=e53d0be589374e39121cd9d5c92fb424956dbde5 tenace-0.18/000077500000000000000000000000001505733770300127135ustar00rootroot00000000000000tenace-0.18/.gitignore000066400000000000000000000012131505733770300147000ustar00rootroot00000000000000# autotools ABOUT-NLS aclocal.m4 autom4te.cache/ config/ configure configure~ config.* lib/ libtool m4/ Makefile.in Makefile po/POTFILES po/*.gmo po/stamp-it po/Makefile.in.in po/Makefile.in.in~ po/Makevars.template po/Rules-quot po/boldquot.sed po/en@boldquot.header po/en@quot.header po/insert-header.sin po/quot.sed po/remove-potcdate.sin po/tenace.pot src/.deps stamp-h1 intltool-* stamp-h.in NEWS # built *.o handdisplay/int_int_marshal.h src/tenace dds/dds.[ch] dds/libdds.a # debian build-stamp configure-stamp debian/files debian/tenace debian/tenace.substvars debian/*.debhelper debian/tenace.debhelper.log # stuff *.bak *.swp src/tags tenace-0.18/.travis.yml000066400000000000000000000012411505733770300150220ustar00rootroot00000000000000dist: xenial sudo: required language: C arch: - amd64 - ppc64le compiler: - gcc #- clang before_install: - sudo apt-get update -qq - sudo apt-get install -y libboost-thread-dev - sudo apt-get install -y libgtk2.0-dev libdds-dev intltool gnulib script: - test -d dds/.git || git clone https://github.com/dds-bridge/dds.git - ( cd dds && git pull ) - make -C dds/src -f Makefiles/Makefile_linux_shared - sed -i -e 's/bool/int/' dds/include/dll.h # missing - sudo install -m644 dds/src/libdds.so /usr/lib/libdds.so - sudo install -m644 -D dds/include/dll.h /usr/include/dds/dll.h - ./autogen.sh - make - make distcheck # vim:sw=2: tenace-0.18/AUTHORS000066400000000000000000000000351505733770300137610ustar00rootroot00000000000000Christoph Berg tenace-0.18/COPYING000066400000000000000000000431031505733770300137470ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 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 Lesser 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General Public License instead of this License. tenace-0.18/ChangeLog000066400000000000000000000114321505733770300144660ustar00rootroot00000000000000tenace (0.16) upstream; urgency=medium * Update to dds 2.9.0, remove our dds copy, remove gnulib physmem module. * Fix handling of board numbers in menu callback. -- Christoph Berg Sun, 23 Sep 2018 15:04:09 +0200 tenace (0.15) upstream; urgency=medium * Adapt glib-genmarshal call to new syntax. -- Christoph Berg Mon, 21 Aug 2017 20:04:11 +0200 tenace (0.14) upstream; urgency=medium * Correctly read lin files starting with qx||. * Various minor build system and gtk compatibility tweaks. * Add desktop menu and icon. -- Christoph Berg Sun, 12 Jun 2016 15:40:13 +0200 tenace (0.13) upstream; urgency=low * Support reading compressed svg files (.svgz). * Explicitely link with -lm. * On startup, show a random deal if no file is loaded. * Set dealer and vulnerability correctly on new boards. -- Christoph Berg Fri, 04 Oct 2013 22:02:06 +0200 tenace (0.12) upstream; urgency=low * Build system updates; fix building with --as-needed. * Add /usr/share/aisleriot/cards/{bonded,paris}.svg and /usr/share/gnome-games-common/cards/gnomangelo_bitmap.svg to list of default svg files. * Initialize win->svg correctly. * handdisplay: include glib.h directly. -- Christoph Berg Tue, 03 Apr 2012 22:34:27 +0200 tenace (0.11) upstream; urgency=low * "Open in web" shows the current deal on http://www.bridgebase.com/tools/handviewer.html. Suggested by Christos Trochalakis. * Import dds 2.0.1. * Show dds version number in about dialog. * Port to CalcDDtable (using openmp in libdds). -- Christoph Berg Thu, 10 Feb 2011 00:24:10 +0100 tenace (0.10) upstream; urgency=low * Yet another GUI change, now using GtkBuilder. * Port to dds 2.0: + Use gnulib to import "nproc". + Use threads to parallelize parscore computation. -- Christoph Berg Sun, 25 Apr 2010 01:04:24 +0200 tenace (0.9) upstream; urgency=low * Code ported to Windows for compiling with mingw32. -- Christoph Berg Sun, 09 Aug 2009 21:46:31 +0200 tenace (0.8) upstream; urgency=low * Implement printing, including "magic card" labels. * Some lin parser improvements to rudimentarily parse BM2000 data. * Include dds copy in our source to facilitate compilation on systems not providing libdds.a. * New example: triple-coup.lin. * GUI uses libglade. -- Christoph Berg Sat, 24 Jan 2009 20:51:51 +0100 tenace (0.7) upstream; urgency=low * Use the currently loaded file for greying out already played cards, this looks nicer, and fixes the fact that grey.svg was not looked for in --prefix. Thanks to Mark Voorhies for spotting. * Add contrib/bonded.svg for convenience. * Board list can be reordered via the options menu. -- Christoph Berg Mon, 24 Mar 2008 23:50:38 +0100 tenace (0.6) upstream; urgency=low * Solver: + Always use dealt cards for parscore computation. + Parscore computation was broken when S makes more tricks than N. * UI: + Move fast forward/rewind to menu, make to buttons go one trick forward/backward, and generally reorder menu. + Support dragging to/from card window. + Implement options window and read/write ~/.config/tenacerc as keyfile. + Card filename and rendering size are now configurable. + Sort recently used files by time. * Hand widget: Start dragging manually to prevent dragging 'x' and empty cards. * Examples: Add squeeze.lin. -- Christoph Berg Sun, 16 Mar 2008 00:11:54 +0100 tenace (0.5) upstream; urgency=low * Use GTK_CHECK_VERSION to disable parts that require Gtk 2.10 (recently used menu) and 2.12 (tooltips for alert explanations). -- Christoph Berg Sat, 09 Feb 2008 00:50:11 +0100 tenace (0.4) upstream; urgency=low * File handling: + EW vuln was parsed incorrectly; 0 is also none. + Fix parsing of tournament records. + Store number of claimed tricks. + Implement saving of multiple boards. + Add recently-used handling and filters. * Hand display: + Nicely shaped cards in table display. * Bidding: + Fix "make bids for current contract". * Add README and require gtk+ 2.12. * Translations: de. -- Christoph Berg Thu, 07 Feb 2008 00:12:15 +0100 tenace (0.3) upstream; urgency=low * Initial public release. -- Christoph Berg Sun, 06 Jan 2008 22:28:27 +0100 tenace (0.2) upstream; urgency=low * New snapshot. -- Christoph Berg Wed, 28 Nov 2007 20:25:04 +0100 tenace (0.1) upstream; urgency=low * Initial release. * Some bits of Bridge math in bridge.c were already written in 2005. -- Christoph Berg Sat, 16 Jun 2007 14:54:27 +0200 tenace-0.18/Makefile.am000066400000000000000000000016061505733770300147520ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in ACLOCAL_AMFLAGS = -I m4 SUBDIRS = contrib doc examples handdisplay lib src po dist_pkgdata_DATA = tenace.desktop tenace.png tenace.ui tenace.glade magic.ui \ screenshots/board_cards.png \ screenshots/board_editor.png \ screenshots/board_text.png EXTRA_DIST = \ README.md \ autogen.sh \ .travis.yml install-data-local: @$(NORMAL_INSTALL) if test -d $(srcdir)/pixmaps; then \ $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/pixmaps; \ for pixmap in $(srcdir)/pixmaps/*; do \ if test -f $$pixmap; then \ $(INSTALL_DATA) $$pixmap $(DESTDIR)$(pkgdatadir)/pixmaps; \ fi \ done \ fi dist-hook: if test -d pixmaps; then \ mkdir $(distdir)/pixmaps; \ for pixmap in pixmaps/*; do \ if test -f $$pixmap; then \ cp -p $$pixmap $(distdir)/pixmaps; \ fi \ done \ fi tenace-0.18/README.md000066400000000000000000000050731505733770300141770ustar00rootroot00000000000000tenace ====== Tenace is a Bridge hand viewer and editor. * https://www.df7cb.de/bridge/tenace/ Screen Shots ------------ Main window ![Tenace main window](screenshots/board_cards.png) Main window with textual cards ![Main window with textual cards](screenshots/board_text.png) Board editor ![Board editor](screenshots/board_editor.png) Requirements ------------ Tenace was written on Debian GNU/Linux, but should run on any platform that features GTK+. Recommended minimum version is 2.12 due to the usage of GtkTooltip. Tenace will still compile with older versions, but some features will be disabled, notably the recently-used boards menu and tooltip popups for alert explanations. To render images of cards, librsvg is used (other image formats to display cards work as well). The GUI is rendered using libglade. * http://www.gtk.org/ * http://library.gnome.org/devel/rsvg/ http://ftp.gnome.org/pub/GNOME/sources/librsvg/ Tenace uses Bo Haglund's excellent DDS double dummy solver library for discovering optimal leads and computing parscores. * http://privat.bahnhof.se/wb758135/bridge/index.html Installation ------------ Get and unpack the tarball. $ ./configure --help $ ./configure $ make # make install If you are running Debian, get packages from the next Debian mirror. The contrib sub-directory contains some useful supplementary files: * mailcap, mime.types: sample MIME configs to launch Tenace from web browsers and mail clients. On Debian systems, mailcap will automatically be installed. mime.types can be appended to your ~/.mime.types. * bonded.svg: SVG data to render cards. Most probably already installed in /usr/share/gnome-games-common/cards/ or the like by your Gnome installation. Translations ------------ * German (de) * Norwegian Nynorsk (nn) by Yngve Spjeld Landro More translations welcome! (For technical reason, there's also an English translation that only contains four strings, though real `en_US`/`en_GB` translations would be welcome as well.) Development ----------- The Tenace source code is maintained on GitHub: * https://github.com/df7cb/tenace Feedback and Bugs ----------------- I'd be happy to hear back from you, either by mail, or using the Debian bug tracking system. I'm Myon on BBO, feel free to say hello there. Credits ------- * Mark Voorhies spotted a problem with greying out already-played cards. * Christos Trochalakis suggested the "Open in web" feature. I probably forgot to list others here. Please tell me when this is the case. -- Christoph Berg Thu, 10 Feb 2011 00:21:34 +0100 tenace-0.18/configure.ac000066400000000000000000000017741505733770300152120ustar00rootroot00000000000000dnl Process this file with autoconf to produce a configure script. AC_INIT(tenace, 0.18, [cb@df7cb.de]) AC_CONFIG_AUX_DIR([config]) AM_INIT_AUTOMAKE([-Wall foreign]) AM_CONFIG_HEADER(config.h) AM_MAINTAINER_MODE AC_CONFIG_MACRO_DIR([m4]) AC_ISC_POSIX AC_PROG_CC gl_EARLY AM_PROG_LIBTOOL AM_PROG_CC_STDC AC_HEADER_STDC AC_SEARCH_LIBS([SolveBoard], [dds], [], [AC_MSG_ERROR([Unable to find dds library])]) pkg_modules="gtk+-2.0 >= 2.0.0" PKG_CHECK_MODULES(PACKAGE, [$pkg_modules]) AC_SUBST(PACKAGE_CFLAGS) AC_SUBST(PACKAGE_LIBS) IT_PROG_INTLTOOL([0.35.0]) GETTEXT_PACKAGE=tenace AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [The domain to use with gettext]) AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION([0.17]) PROGRAMNAME_LOCALEDIR=[${datadir}/locale] AC_SUBST(PROGRAMNAME_LOCALEDIR) gl_INIT AC_CONFIG_FILES([ Makefile contrib/Makefile doc/Makefile examples/Makefile handdisplay/Makefile lib/Makefile src/Makefile po/Makefile.in ]) AC_OUTPUT tenace-0.18/contrib/000077500000000000000000000000001505733770300143535ustar00rootroot00000000000000tenace-0.18/contrib/Makefile.am000066400000000000000000000000531505733770300164050ustar00rootroot00000000000000EXTRA_DIST = bonded.svg mailcap mime.types tenace-0.18/contrib/bonded.svg000066400000000000000000002477121505733770300163440ustar00rootroot00000000000000 GNOME tenace-0.18/contrib/mailcap000066400000000000000000000000671505733770300157070ustar00rootroot00000000000000application/bbolin; tenace %s; test=test -n "$DISPLAY" tenace-0.18/contrib/mime.types000066400000000000000000000000321505733770300163630ustar00rootroot00000000000000application/bbolin lin tenace-0.18/debian/000077500000000000000000000000001505733770300141355ustar00rootroot00000000000000tenace-0.18/debian/changelog000066400000000000000000000102721505733770300160110ustar00rootroot00000000000000tenace (0.18-1) unstable; urgency=medium * Fix board_window_init prototype. (Closes: #1097982) * Remove quotes from mailcap file. (Closes: #987416) * Run gnulib-tool and autoreconf at build time. * Pull tarball from github tags. -- Christoph Berg Sun, 07 Sep 2025 17:06:43 +0000 tenace (0.17-1) unstable; urgency=medium [ Debian Janitor ] * Wrap long lines in changelog entries: 0.16-2. * Bump debhelper from old 11 to 12. * Set debhelper-compat version in Build-Depends. * Update standards version to 4.5.0, no changes needed. [ Christoph Berg ] * Update package URLs. -- Christoph Berg Tue, 31 Aug 2021 17:00:32 +0200 tenace (0.16-2) unstable; urgency=medium [ Helmut Grohne ] * Fix FTCBFS: Let dh_auto_configure pass --host to ./configure. (Closes: #923147) [ Christoph Berg ] * Simplify debian/rules. (Don't run dh_autoreconf, doesn't work yet.) -- Christoph Berg Mon, 25 Feb 2019 11:18:48 +0100 tenace (0.16-1) unstable; urgency=medium * New upstream version. + Update to dds 2.9.0, remove our dds copy, remove gnulib physmem module. + Fix handling of board numbers in menu callback. Closes: #879455. -- Christoph Berg Sun, 23 Sep 2018 15:04:05 +0200 tenace (0.15-1) unstable; urgency=medium * New upstream version. + Adapt glib-genmarshal call to new syntax. Closes: #871082. -- Christoph Berg Mon, 21 Aug 2017 20:04:07 +0200 tenace (0.14-1) unstable; urgency=medium * New upstream version. + Font handling improved. Closes: #515572. + Support lin files starting with qx||. Closes: #680912. * Install desktop file and icon. Closes: #738041. -- Christoph Berg Sun, 12 Jun 2016 15:39:54 +0200 tenace (0.13-1) unstable; urgency=low * New upstream version. + Links with -lm. Closes: #704794. + Set dealer and vulnerability correctly on new boards. Closes: #668003. * Drop Suggests: gnome-games-extra-data, doesn't exist anymore. Thanks to Jeremy Bicha for spotting. -- Christoph Berg Fri, 04 Oct 2013 22:01:11 +0200 tenace (0.12-1) unstable; urgency=low * New upstream version. + Fixes building with --as-needed. Closes: #632104. + Updates for two yet another new locations of gnome-card-data svg files. + handdisplay: include glib.h directly. Closes: #665618. -- Christoph Berg Wed, 06 Jul 2011 16:42:37 +0200 tenace (0.11-1) unstable; urgency=low * New upstream version. + "Open in web" shows the current deal on http://www.bridgebase.com/tools/handviewer.html. Closes: #522047. -- Christoph Berg Thu, 10 Feb 2011 00:24:33 +0100 tenace (0.10-1) unstable; urgency=low * New upstream version, needs libdds-dev >= 2.0.0. * Upgrade to DH 7. -- Christoph Berg Sun, 25 Apr 2010 01:03:55 +0200 tenace (0.8-3) unstable; urgency=low * Move EINVAL tweak into file.h so main.c sees it. -- Christoph Berg Sat, 10 Apr 2010 21:35:32 +0200 tenace (0.8-2) unstable; urgency=low * Use EINVAL on platforms where EMEDIUMTYPE is undefined. -- Christoph Berg Sat, 10 Apr 2010 15:14:02 +0200 tenace (0.8-1) unstable; urgency=low * New upstream version. * Adding Build-Dependency on libglade2-dev. -- Christoph Berg Sat, 24 Jan 2009 20:52:09 +0100 tenace (0.7-1) unstable; urgency=low * New upstream version. -- Christoph Berg Mon, 24 Mar 2008 23:57:32 +0100 tenace (0.6-1) unstable; urgency=low * New upstream version. * Relax gtk+ Build-Depends, we check features at compile time (cf 0.5-1). * Suggest gnome-games-extra-data for more svg files. -- Christoph Berg Sun, 16 Mar 2008 02:06:32 +0100 tenace (0.5-1) unstable; urgency=low * New upstream version, will now also compile on Etch. -- Christoph Berg Sat, 09 Feb 2008 00:57:40 +0100 tenace (0.4-1) unstable; urgency=low * New upstream version. -- Christoph Berg Thu, 07 Feb 2008 00:12:56 +0100 tenace (0.3-1) unstable; urgency=low * Initial release. -- Christoph Berg Sun, 06 Jan 2008 22:28:27 +0100 tenace-0.18/debian/control000066400000000000000000000014731505733770300155450ustar00rootroot00000000000000Source: tenace Section: games Priority: optional Maintainer: Christoph Berg Build-Depends: debhelper-compat (= 13), libgtk2.0-dev, libdds-dev (>= 2.9), intltool Standards-Version: 4.6.0 Vcs-Browser: https://github.com/df7cb/tenace Vcs-Git: https://github.com/df7cb/tenace.git Homepage: https://www.df7cb.de/bridge/tenace/ Package: tenace Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-cards-data, librsvg2-common Description: Bridge hand viewer and editor Tenace is a Bridge hand viewer and editor. Hand records are read using BBO's .lin format. The board editor allows one to easily move cards around to simulate different distributions. The double dummy solver computes optimal lines of play and par scores. . Bridge is an intellectually challenging card game for four players. tenace-0.18/debian/copyright000066400000000000000000000021051505733770300160660ustar00rootroot00000000000000This is the tenace package, a bridge hand viewer and editor written and maintained by Christoph Berg . Upstream website: http://www.df7cb.de/bridge/tenace/ License and copyright: /* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2018 Christoph Berg * * 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. */ On Debian systems, the complete text of the GNU General Public License can be found in the file /usr/share/common-licenses/GPL. The shipped bonded.svg file has been copied from gnome-cards-data and has been around for at least 10 years, author unknown. It is also GPL-licensed. tenace-0.18/debian/rules000077500000000000000000000004231505733770300152140ustar00rootroot00000000000000#!/usr/bin/make -f execute_before_dh_autoreconf: gnulib-tool --update override_dh_auto_configure: dh_auto_configure -- --bindir=/usr/games override_dh_auto_install: dh_auto_install install -m644 -D contrib/mailcap debian/tenace/usr/lib/mime/packages/tenace %: dh $@ tenace-0.18/debian/source/000077500000000000000000000000001505733770300154355ustar00rootroot00000000000000tenace-0.18/debian/source/format000066400000000000000000000000141505733770300166430ustar00rootroot000000000000003.0 (quilt) tenace-0.18/debian/source/options000066400000000000000000000005671505733770300170630ustar00rootroot00000000000000extend-diff-ignore = tenace.glade extend-diff-ignore = m4/* extend-diff-ignore = po/Makevars.template extend-diff-ignore = po/Rules-quot extend-diff-ignore = po/boldquot.sed extend-diff-ignore = po/en@boldquot.header extend-diff-ignore = po/en@quot.header extend-diff-ignore = po/insert-header.sin extend-diff-ignore = po/quot.sed extend-diff-ignore = po/remove-potcdate.sin tenace-0.18/debian/tenace.install000066400000000000000000000001241505733770300167610ustar00rootroot00000000000000tenace.png usr/share/icons/hicolor/64x64/apps tenace.desktop usr/share/applications tenace-0.18/debian/tenace.manpages000066400000000000000000000000151505733770300171050ustar00rootroot00000000000000doc/tenace.6 tenace-0.18/debian/watch000066400000000000000000000001161505733770300151640ustar00rootroot00000000000000version=4 https://github.com/df7cb/tenace/tags .*/v@ANY_VERSION@@ARCHIVE_EXT@ tenace-0.18/doc/000077500000000000000000000000001505733770300134605ustar00rootroot00000000000000tenace-0.18/doc/Makefile.am000066400000000000000000000000311505733770300155060ustar00rootroot00000000000000dist_man_MANS = tenace.6 tenace-0.18/doc/tenace.6000066400000000000000000000015121505733770300150050ustar00rootroot00000000000000.TH TENACE 6 2008-01 .SH NAME tenace \- Bridge hand viewer and editor .SH SYNOPSIS .B tenace [\fIfilename\fP] .SH "DESCRIPTION" .B Tenace is a bridge hand viewer and editor. .SH OPTIONS .TP .I filename Load hand records from \fIfilename\fP. .SH COPYRIGHT Copyright (C) 2005-2008 Christoph Berg 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. .SH BUGS Probably lots. .SH "SEE ALSO" dealer(6), dds(6). tenace-0.18/examples/000077500000000000000000000000001505733770300145315ustar00rootroot00000000000000tenace-0.18/examples/01-26-08-3.lin000066400000000000000000000116371505733770300162770ustar00rootroot00000000000000vg|Bridge Base Online,IMPs,P,1,21,,,,| rs|3SE=,,4SN=,,3NS=,,2NE+3,,3NW-1,,4SW=,,4SW=,,4SS+3,,3NN+1,,6NS=,,4HE=,,2DW=,,3CS-1,,3NW-2,,6CE=,,4SS+2,,3DW-1,,3HS+1,,4SEx-1,,6HS=,,3NW+2,| pw|Frederic,Advena,hennibaer,Codo,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Myon,wendelin,zuse,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,| mp|,2.1,4.3,,2.3,,5.7,,2.7,,,6.1,,3.8,2.5,,3.5,,4.2,,,1.5,0.3,,4.0,,3.3,,,8.9,1.1,,1.2,,3.0,,1.1,,--,--,,2.7| bn|23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43| pg|| qx|o11|pn|Frederic,Myon,wendelin,zuse|st||md|3S2349JH56D2KC25QK,S5TQKH78AD46JAC49,S67AHKD5789TQC678,|rh||ah|Board 33|sv|o|mb|p|mb|3H|mb|p|mb|4H|mb|p|mb|p|mb|p|pg||pc|DK|pc|DA|pc|D5|pc|D3|pg||pc|C9|pc|C8|pc|C3|pc|CQ|pg||pc|D2|pc|DJ|pc|DQ|pc|H2|pg||pc|HT|pc|H5|pc|H7|pc|HK|pg||pc|DT|pc|HQ|pc|S9|pc|D4|pg||pc|S8|pc|S2|pc|SQ|pc|SA|pg||pc|C6|pc|CA|pc|C2|pc|C4|pg||pc|H3|pc|H6|pc|H8|pc|D7|pg||mc|10|pg|| qx|o12|pn|Frederic,Myon,wendelin,zuse|st||md|4S59TJH38D29JC45TK,S34H5TAD358TQAC3A,S28KAH9JQKD46C28J,|rh||ah|Board 34|sv|n|mb|p|mb|p|mb|1D|mb|d|mb|p|mb|1S|mb|2D|mb|p|mb|p|mb|p|pg||pc|HK|pc|h2|pc|H8|pc|hA|pg||pc|c3|pc|C2|pc|cQ|pc|CK|pg||pc|H3|pc|h5|pc|H9|pc|h4|pg||pc|HQ|pc|h6|pc|SJ|pc|hT|pg||pc|HJ|pc|h7|pc|S5|pc|d3|pg||pc|d5|pc|D4|pc|dK|pc|D2|pg||pc|d7|pc|D9|pc|dA|pc|D6|pg||mc|8|pg|| qx|o13|pn|Frederic,Myon,wendelin,zuse|st||md|1S68KAH7QD38C2459A,S59JH2TJKAD256ACJ,S34TH346DTQC68TQK,|rh||ah|Board 35|sv|e|mb|1C|mb|1H|mb|2C|mb|p|mb|3C|mb|p|mb|p|mb|p|pg||pc|hA|pc|H3|pc|H8|pc|H7|pg||pc|hK|pc|H4|pc|H5|pc|HQ|pg||pc|d2|pc|DT|pc|DJ|pc|D3|pg||pc|S2|pc|SA|pc|s5|pc|S3|pg||pc|C2|pc|cJ|pc|CQ|pc|C3|pg||pc|H6|pc|H9|pc|C5|pc|h2|pg||pc|CA|pc|hT|pc|C6|pc|C7|pg||pc|D8|pc|dA|pc|DQ|pc|D4|pg||pc|s9|pc|ST|pc|SQ|pc|SK|pg||pc|S6|pc|sJ|pc|S4|pc|S7|pg||mc|8|pg|| qx|o14|pn|Frederic,Myon,wendelin,zuse|st||md|2S3456H26D24TKC257,S89H79TKD35JQC3QK,S2TJQH348QAD6AC89,|rh||ah|Board 36|sv|b|mb|p|mb|1H|mb|p|mb|p|mb|1N|mb|p|mb|3N|mb|p|mb|p|mb|p|pg||pc|SQ|pc|sA|pc|S6|pc|s8|pg||pc|hJ|pc|H2|pc|h7|pc|HQ|pg||pc|SJ|pc|sK|pc|S5|pc|s9|pg||pc|h5|pc|H6|pc|hK|pc|HA|pg||pc|ST|pc|s7|pc|S3|pc|d3|pg||pc|DA|pc|d7|pc|D2|pc|d5|pg||pc|S2|pc|d8|pc|S4|pc|c3|pg||pc|DK|pc|dJ|pc|D6|pc|d9|pg||pc|D4|mc|7|pg|| qx|o15|pn|Frederic,Myon,wendelin,zuse|st||md|3S256H367QKD289C78,S8QAH5TJADTKAC49K,S379KH248D457JC6J,|rh||ah|Board 37|sv|n|mb|p|mb|p|mb|p|mb|2N|mb|p|mb|6C|mb|p|mb|p|mb|p|pg||pc|HK|pc|HA|pc|H8|pc|H9|pg||pc|C4|pc|C6|pc|CA|pc|C7|pg||pc|C2|pc|C8|pc|CK|pc|CJ|pg||pc|DA|pc|D4|pc|D3|pc|D2|pg||pc|DK|pc|D5|pc|D6|pc|D8|pg||pc|DT|pc|D7|pc|DQ|pc|D9|pg||pc|ST|pc|S2|pc|S8|pc|SK|pg||pc|H2|mc|12|pg|| qx|o16|pn|Frederic,Myon,wendelin,zuse|st||md|4S368JQHD2457QKC4A,S24TH4JQD8AC567QK,S7KAH3569TAD39C29,|rh||ah|Board 38|sv|e|mb|p|mb|1S|mb|2C|mb|2H|mb|3C|mb|3D|mb|p|mb|4S|mb|p|mb|p|mb|p|pg||pc|cK|pc|C2|pc|C3|pc|CA|pg||pc|S3|pc|s2|pc|SA|pc|S5|pg||pc|HA|pc|H2|pc|C4|pc|h4|pg||pc|D3|pc|D6|pc|DK|pc|dA|pg||pc|cQ|pc|C9|pc|CJ|pc|S6|pg||pc|DQ|pc|d8|pc|D9|pc|DT|pg||pc|D2|pc|sT|pc|SK|pc|DJ|pg||pc|S7|pc|S9|pc|SQ|pc|s4|pg||mc|12|pg|| qx|o17|pn|Frederic,Myon,wendelin,zuse|st||md|1S56TKH68JD26TC78Q,S37H5KD4578QAC34K,S248AH479TAD39JCA,|rh||ah|Board 39|sv|b|mb|p|mb|1D|mb|1H|mb|1N|mb|2H|mb|3D|mb|p|mb|p|mb|p|pg||pc|CA|pc|c2|pc|C8|pc|c3|pg||pc|HA|pc|h2|pc|H8|pc|h5|pg||pc|H7|pc|h3|pc|H6|pc|hK|pg||pc|d4|pc|D3|pc|dK|pc|D6|pg||pc|hQ|pc|HJ|pc|s3|pc|H4|pg||pc|cJ|pc|C7|pc|c4|pc|D9|pg||pc|S2|pc|s9|pc|ST|pc|s7|pg||pc|CQ|pc|cK|pc|DJ|pc|c5|pg||pc|S4|mc|8|pg|| qx|o18|pn|Frederic,Myon,wendelin,zuse|st||md|2S6TH58TJQAD5C247T,S4QAH6D468TJKC8KA,S89KH7KD239AC359Q,|rh||ah|Board 40|sv|o|mb|1D|mb|p|mb|p|mb|2H|mb|3D|mb|3H|mb|p|mb|p|mb|p|pg||pc|cA|pc|C3|pc|CJ|pc|C2|pg||pc|s4|pc|SK|pc|S7|pc|S6|pg||pc|HK|pc|H2|pc|H5|pc|h6|pg||pc|H7|pc|H3|pc|HQ|pc|d4|pg||pc|HA|pc|d6|pc|S8|pc|H4|pg||pc|HJ|pc|d8|pc|S9|pc|H9|pg||pc|C4|pc|cK|pc|C5|pc|C6|pg||pc|sA|pc|D2|pc|S2|pc|ST|pg||pc|sQ|mc|10|pg|| qx|o19|pn|Frederic,Myon,wendelin,zuse|st||md|3S8H7TKD567KAC2479,S26QH238QAD2C56TA,S3TJKH56JD349JQCJ,|rh||ah|Board 41|sv|e|mb|p|mb|p|mb|1D|mb|1H|mb|d|mb|1S|mb|p|mb|2S|mb|3D|mb|3S|mb|p|mb|4S|mb|d|mb|p|mb|p|mb|p|pg||pc|DA|pc|D2|pc|D9|pc|DT|pg||pc|C4|pc|C5|pc|CJ|pc|CK|pg||pc|D8|pc|D5|pc|S2|pc|D3|pg||pc|S6|pc|S3|pc|S4|pc|S8|pg||pc|C2|pc|CA|pc|ST|pc|C3|pg||pc|SK|pc|SA|pc|C7|pc|SQ|pg||pc|H9|pc|HT|pc|HQ|pc|H5|pg||mc|9|pg|| qx|o20|pn|Frederic,Myon,wendelin,zuse|st||md|4S36JH59JQKDC2347K,S57KH68D267C59TJQ,S4AH347TAD5TQKAC8,|rh||ah|Board 42|sv|b|mb|p|mb|1H|mb|p|mb|2D|mb|p|mb|2H|mb|p|mb|2S!|mb|p|mb|4S|mb|p|mb|4N|mb|p|mb|5C|mb|p|mb|6H|mb|p|mb|p|mb|p|pg||pc|cQ|pc|C8|pc|CA|pc|C2|pg||pc|D3|pc|S3|pc|d2|pc|D5|pg||pc|H3|pc|H2|pc|HK|pc|h6|pg||pc|H5|pc|h8|pc|HT|pc|S9|pg||mc|12|pg|| qx|o21|pn|Frederic,Myon,wendelin,zuse|st||md|1S579TH67D9AC2345T,S46QH389AD6TKC9JQ,S8KH245JQD278C68K,|rh||ah|Board 43|sv|o|mb|p|mb|1D|mb|1H|mb|d|mb|p|mb|1N|mb|p|mb|3N|mb|p|mb|p|mb|p|pg||pc|H4|pc|hT|pc|H6|pc|h3|pg||pc|d3|pc|DA|pc|d6|pc|D8|pg||pc|H7|pc|h8|pc|H2|pc|hK|pg||pc|cA|pc|C4|pc|c9|pc|C6|pg||pc|c7|pc|C2|pc|cQ|pc|CK|pg||pc|HQ|pc|s2|pc|D9|pc|hA|pg||pc|cJ|pc|C8|pc|s3|pc|C3|pg||pc|dK|pc|D2|pc|d4|pc|C5|pg||pc|dT|pc|D7|pc|d5|mc|11|pg|| tenace-0.18/examples/2007_Spingold_Final.First_Quarter.lin000066400000000000000000002016021505733770300233670ustar00rootroot00000000000000vg|2007 SPINGOLD FINAL,First Quarter,I,1,16,NICKELL,0,GROMOV,0| rs|2HN=,3HN=,4SS=,5CN+1,3NN=,3NN+1,3NW+2,4SE+1,2SN-1,3CW=,6HS+1,1SWx-4,1NS+1,1NS+1,6CN=,6CN=,4SW-1,4SW-1,3NE+1,3NE+1,4SE+1,4SE=,3SS-2,3NNx-1,3NW-2,2NW=,4SN-1,4SN-1,4DW=,4CE-1,3NN+1,3NN=| pn|Meckstroth,Zmudzinski,Rodwell,Balicki,Dubinin,Nickell,Gromov,Lall|pg|| qx|o1|st||md|3SA2HT7DK75432C974,S84HQ986DQTCAK852,SKQT3HAKJ54DCJT63,SJ9765H32DAJ986CQ|sv|o|nt|Walddk2: Hello everyone and welcome back to Nashville, Tennessee, for the Spingold Knockout Teams. Finals, 4 segments of 16 boards; this is the first|pg|| mb|1H|mb|p|nt|brolucius: Hi to the kibitzers!|pg|| nt|Walddk2: Your commentators are David Bird, England, and Karen Allison, USA. I am Roland Wald from Denmark|pg|| mb|1N|an|f1|mb|p|mb|2C|nt|Walddk2: Our operator is Jan Martel from USA. Good morning to you|pg|| nt|kareno: Good morning from Nashville. Roland :) David :) Jan :)|pg|| nt|brolucius: Both pairs are top-of-the-range and we should be in for a great session.|pg|| mb|d|nt|kareno: They have met before at World Championships. And the level of the Spingold is certainly up to World Championship quality.|pg|| nt|brolucius: Now meckstroth will be worried about bidding diamonds because East has shown them.|pg|| mb|2D|nt|brolucius: Still, no reason to think that clubs would be better.|pg|| nt|Vugraph7: I think that N & S alerted 2@c as could be as few as 2|pg|| nt|kareno: He would never have bid them - In my opinion he was always going back to hearts.|pg|| nt|kareno: hm.. wrong again!|pg|| nt|brolucius: West has a misfit but he may be worried that East is stronger and that N-S are attempting to steal the board with a light opening and a light response.|pg|| mb|d|mb|2H|mb|p|nt|brolucius: Terence Reese once described meckstroth as 'having the appearance of an all-in wrestler'. A fearsome opponent indeed.|pg|| nt|Vugraph7: Adam writing about his dbl I think (I'm going to call him Adam because Zmudzinski is just too much for me to type fast|pg|| mb|p|nt|brolucius: In their youth, Rodwell and Meckstroth were long-haired 'angry young men'. Now they have some of the best temperaments in world bridge. Often impossible to tell from their manner ...|pg|| nt|brolucius: whether they have just had a bad board or an excellent one.|pg|| nt|brolucius: They never seem to get ruffled. Mind you, that is easier when you win most of the time...|pg|| nt|Vugraph7: Lots of writing went on, which I can't begin to see. Now Adam has his head in his hand and is thinking|pg|| mb|p|nt|Vugraph7: Rod asks about honor leads and Zmud says "standard"|pg|| nt|kareno: A good decision. 2@h will make or go down one I think.|pg|| pc|cQ|pc|c4|pc|c5|pc|c6|pg|| nt|Walddk2: http://www.acbl.org/nabc/Nashville2007/ is the link to the official website with schedule, results and daily bulletins|pg|| nt|brolucius: West has wisely decided not to double 2@H, which might punish partner for his initiative in competing for the partscore.|pg|| nt|Vugraph7: Now Zmud says - sorry - honor leads standard except J denies and 10, 9 from interior sequences (probably didn't think about that because of the lead being Q but wanted to be sure ...|pg|| nt|Vugraph7: he didn't mislead for a future hand|pg|| pc|h2|pc|h7|pc|h8|pc|hJ|pg|| nt|brolucius: Great that Jan can find time for extra 'table info'. More than i would be able to do, with all the cards to tap in. (Not that anyone would ever persuade me to do such a tiring ...|pg|| nt|brolucius: job). |pg|| pc|s3|pc|s7|pc|sA|pc|s4|pg|| pc|hT|pc|hQ|pc|hA|pc|h3|pg|| nt|Walddk2: http://www.worldbridge.org/people/person.asp?qryid=3776 Jeff Meckstroth|pg|| pc|hK|pc|d6|nt|Walddk2: http://www.worldbridge.org/people/person.asp?qryid=3777 Eric Rodwell|pg|| pc|d2|pc|h6|pg|| pc|c3|nt|Walddk2: http://www.worldbridge.org/people/person.asp?qryid=4861 Cezary Balicki|pg|| pc|d8|pc|c9|nt|Walddk2: http://www.worldbridge.org/people/person.asp?qryid=4862 Adam Zmudzinski|pg|| pc|cK|pg|| pc|s8|pc|sK|pc|s5|pc|s2|pg|| pc|cJ|nt|kareno: Just making two.|pg|| nt|brolucius: Rodwell might have tried to ruff the @S10, hoping to absorb West's trump trick. But it seems that West could have crossed to the East hand with a club ruff to score a second ...|pg|| nt|brolucius: overruff in spades.|pg|| mc|8|pg|| qx|c1|st||md|3SA2HT7DK75432C974,S84HQ986DQTCAK852,SKQT3HAKJ54DCJT63,SJ9765H32DAJ986CQ|sv|o|mb|1H|mb|p|nt|jtr: X at MPs i guess|pg|| mb|1N|nt|jtr: Passed partner too|pg|| nt|hedyg: alerted 1@c, maybe strong?|pg|| nt|xenya: maybe strong club?|pg|| nt|jtr: ah maybe|pg|| nt|jtr: So double for reds or blacks:)|pg|| nt|hedyg: LOL|pg|| mb|p|mb|2C|mb|p|mb|2H|mb|p|mb|p|nt|xenya: yeah, double anyway :)|pg|| nt|jtr: Not a strong @c|pg|| nt|vugraph814: seems to be natural, no alert on 1@d|pg|| mb|2S|mb|3D|nt|jtr: 3@d could turn out to be lucky|pg|| mb|p|mb|3H|mb|p|mb|p|mb|p|nt|voldenuit: 3@d can be made 2@d and 2@h to lose |pg|| nt|jtr: first bit of luck has appeared|pg|| nt|hedyg: friendly lead|pg|| pc|s5|pc|s2|pc|s8|pc|sT|pg|| pc|c3|pc|cQ|nt|hedyg: 2nd good news|pg|| nt|jtr: No lead was likely to do any damage but this helped the timing|pg|| pc|c4|nt|jtr: Well, he may be able to play for H10 doubleton|pg|| pc|c2|pg|| pc|s6|pc|sA|nt|jtr: By ruffing in hand|pg|| pc|s4|pc|s3|pg|| pc|c7|pc|cA|pc|c6|pc|d9|pg|| pc|dQ|pc|h4|nt|hedyg: had to play another @s first|pg|| pc|d6|pc|d2|pg|| pc|cJ|pc|sJ|pc|c9|nt|jtr: nice recovery|pg|| nt|jtr: except the @s gets ruffed now|pg|| nt|xenya: indeed|pg|| pc|cK|pg|| pc|c8|pc|cT|pc|h2|nt|jtr: Nice little hand Kokish would love it|pg|| pc|h7|pg|| pc|hT|pc|hQ|nt|voldenuit: deep finesse says 1 down but I don't know how he can down 1 now |pg|| pc|hA|pc|h3|pg|| nt|hedyg: with a @s ruff|pg|| pc|hK|pc|d8|pc|d3|nt|voldenuit: ah yes sry |pg|| pc|h6|pg|| pc|sK|pc|s7|pc|d4|nt|jtr: @hK better|pg|| nt|hedyg: clearer yes|pg|| nt|jtr: Help partner to avoid a mistake|pg|| nt|xenya: good principle|pg|| pc|h8|pg|| mc|9|pg|| qx|o2|st||md|4ST87654H74DACAJ97,SK932H52DJT7542C3,SAQHKQJ8DQCQT8654,SJHAT963DK9863CK2|sv|n|nt|Walddk2: Long time partnerships as you can see by looking at their WBF numbers, just next to each other|pg|| nt|Vugraph7: Polish discussion E-W and ROd asks what does "yocki crupa" mean - something about cards :)|pg|| mb|1H|mb|1S|mb|p|mb|2H|mb|p|nt|brolucius: A friend of mine, what I was chatting to him on Friday morning, talked about 'Meckstroth and Rodwell, when they were in their prime'. Who says they are not now, when they reach the ...|pg|| nt|brolucius: Spingold final yet again?|pg|| mb|3S|mb|p|mb|4S|mb|p|mb|p|nt|Walddk2: And yet another Bermuda Bowl appearance in a couple of months|pg|| nt|brolucius: The same applied to Hamman and Soloway. Amazing to play with such intensity after so many years of hard work at the table.|pg|| nt|Vugraph7: Zmud asks about 3@h - I think Meck said game try in spades|pg|| mb|p|pc|c3|pc|cQ|pc|cK|pc|cA|pg|| pc|s4|pc|s2|pc|sA|pc|sJ|pg|| pc|sQ|pc|h6|pc|s5|nt|Walddk2: Balicki - Zmudzinski not in contention for the Polish Bermuda Bowl team. Rumour has it they will be representing Russis at the next European Championships. They would be eligible|pg|| pc|sK|pg|| nt|Walddk2: Russia that is|pg|| pc|h2|nt|brolucius: Interesting that Meckstroth should think that he has sufficient by way of extras (for a vulnerable overcall) to jump a level. It was the sixth spade that tipped it.|pg|| pc|hK|pc|hA|pc|h4|pg|| nt|Walddk2: And their team-mates in this event are indeed from Russia|pg|| nt|kareno: Great play, ace of spades. Caters to either singleton.|pg|| mc|10|pg|| qx|c2|st||md|4ST87654H74DACAJ97,SK932H52DJT7542C3,SAQHKQJ8DQCQT8654,SJHAT963DK9863CK2|sv|n|nt|jtr: Both majors opening?|pg|| nt|hedyg: pass!|pg|| mb|1H|mb|1S|mb|p|mb|2C|mb|p|mb|2D!|mb|p|mb|3C|nt|Walddk2: Many can now bid a weak 2@H|pg|| nt|hedyg: nice to play 2@h as weak|pg|| nt|Walddk2: pass or correct|pg|| mb|p|mb|4C|nt|voldenuit: 2@s or 2@h is the same number of trick |pg|| nt|hedyg: use checkback for better hands|pg|| mb|p|nt|voldenuit: hard lead for east |pg|| mb|5C|mb|p|mb|p|mb|p|nt|Walddk2: But it will be difficult for Holmen to know the club position with his holding. Not so attractive to lead from|pg|| pc|d3|pc|dA|pc|d2|nt|jtr: well @hs will make 9|pg|| nt|hedyg: small @H?|pg|| pc|dQ|pg|| pc|s4|nt|Walddk2: Welcome back to Anders Kristensen|pg|| pc|s3|pc|sA|nt|andersk: ty|pg|| nt|xenya: @H lead was just fine imo|pg|| nt|hedyg: hi Anders!|pg|| nt|andersk: great dinner here:)|pg|| nt|xenya: re Anders|pg|| nt|hedyg: lol|pg|| nt|andersk: Hi Hedy, long time now:)|pg|| nt|hedyg: :)|pg|| pc|sJ|pg|| nt|andersk: Hi vladimir:)|pg|| pc|cQ|pc|c2|pc|c7|nt|voldenuit: well done |pg|| pc|c3|pg|| pc|c4|pc|cK|pc|cA|nt|jtr: Nice|pg|| nt|Walddk2: well done indeed|pg|| pc|d4|pg|| nt|voldenuit: hi anders|pg|| pc|s5|pc|s2|nt|andersk: Hi:)|pg|| pc|sQ|pc|d6|pg|| mc|12|pg|| qx|o3|st||md|1S95HK93DKT874CK73,SAT2H742DQ6CAT865,SQJ63HAJ8DAJ5CQJ4,SK874HQT65D932C92|sv|e|mb|p|mb|p|nt|kareno: Interesting that they can switch so easily to playing for Russia.|pg|| mb|1N|mb|p|mb|2N|mb|p|mb|3C|mb|p|mb|3N|mb|p|mb|p|mb|p|nt|brolucius: A couple of days ago I made some general comment about the standard of the bulletins in these events and that they did not seem to contain many deals (rather than appeals and long ...|pg|| nt|brolucius: lists of contestants). I see that my comment is inappropriate here. The bulletins look good and contain several interesting hands. So, I must apologize for that.|pg|| pc|h5|pc|h3|pc|h7|pc|hJ|pg|| nt|kareno: Our bulletins always have a great deal of interest, including hands, appeal committee reports, human interest and so on, David.|pg|| pc|cJ|pc|c9|pc|c3|nt|brolucius: Not always.... (I have often looked for column deals in previous bulletins and found few match reports). |pg|| nt|kareno: There is a requirement to wait before you can switch playing for countries (I did that when I moved to Canada and again when I returned to the US).|pg|| nt|kareno: Apparently this pair has fulfilled that requirement already.|pg|| pc|cA|pg|| nt|brolucius: Although one never knows with M & R (who have a complicated system), this auction seems to be a transfer to diamonds, broken by the opener, and then 3NT to offer a choice of games ...|pg|| nt|brolucius: if partner has good diamond support and a low doubleton in some suit.|pg|| pc|sT|pc|sQ|pc|sK|pc|s5|pg|| nt|kareno: The daily bulletins can be found at www.acbl.org|pg|| nt|brolucius: I am told that 2NT is puppet Stayman with 3@C denying a five-card major. |pg|| nt|Vugraph7: Balicki pulled out spade 4, put it back, now thinking|pg|| pc|s8|pc|s9|pc|sA|pc|s3|pg|| pc|s2|nt|brolucius: If Rodwell knew where the 13th spade was, he could finesse diamonds into the 'safe hand'.|pg|| nt|Vugraph7: Rod's in "thinking" posture, sitting up, arms crossed, cards on table|pg|| nt|brolucius: Kibitzers are commending the @S8 play, which may give declarer an awkward guess.|pg|| nt|Walddk2: They don't seem to care who is North and South. Yesterday Meck was North all day and night|pg|| nt|Vugraph7: Rod asks "do you have any understanding about breaking suits like this?" Bal: "no, normally we lead 2nd/4th but nothing special here"|pg|| nt|kareno: The deuce tells a story too, David.|pg|| nt|brolucius: Declarer has no count on the heart suit, really, so he is some way from obtaining a count to assist him in the diamond guess. Anyway, the queen lies with the doubleton.|pg|| pc|s6|pc|s7|nt|kareno: If he decides to play west for three spades, he may play the diamond into the safe hand.|pg|| pc|d4|pg|| nt|kareno: Apparently he hasn't done so. |pg|| nt|kareno: Now Balicki must exit safely.|pg|| nt|Vugraph7: Bal now has head in hands to think|pg|| nt|brolucius: Now he must guess the diamonds. If he has risen with the @SJ, he would have a double chance: diamond finesse wins, or a losing finesse into the hand with no spade. But of course ...|pg|| nt|brolucius: finessing the spade here was also a possible chance. So that was two chances too.|pg|| nt|kareno: Then Rodwell can cash the spade before playing on diamonds to confirm suit lengths.|pg|| nt|Walddk2: Those guys guess better than most people so it would not surprise me one bit if Rod gets diamonds right|pg|| nt|Vugraph7: Bal fingering the heart Q|pg|| pc|hQ|pc|h9|pc|h2|pc|hA|pg|| pc|sJ|pc|s4|pc|d7|pc|c6|pg|| pc|c4|pc|c2|pc|cK|pc|c5|pg|| nt|kareno: This is all about the diamond queen. |pg|| pc|c7|pc|c8|pc|cQ|nt|Walddk2: Specs suggest that he will go wrong because he knows Bal has three diamonds to Zmud's two. We shall see|pg|| nt|brolucius: Perhaps he will place East with @H4 and think that West has three hearts, causing him to finesse the right way.|pg|| nt|kareno: He has a good nose, you know. |pg|| nt|Vugraph7: Bal pulled out a diamond, then teh heart 6, now head in hands again|pg|| nt|kareno: I can't answer all the spec comments.. we all know what is going on here :)|pg|| nt|Walddk2: Exciting board no matter what|pg|| nt|brolucius: Yes|pg|| pc|d3|pg|| pc|h8|pc|h6|pc|hK|pc|h4|pg|| nt|kareno: He cannot get a complete count.|pg|| nt|kareno: The diamond pitch was unexpected!!|pg|| nt|Vugraph7: Rod: "I'm going to play for diamonds 2-2 now"|pg|| mc|9|pg|| qx|c3|st||md|1S95HK93DKT874CK73,SAT2H742DQ6CAT865,SQJ63HAJ8DAJ5CQJ4,SK874HQT65D932C92|sv|e|nt|Walddk2: I agree with you, Ivar. You must bid 2@H with that hand|pg|| mb|p|nt|andersk: better stop in max 3@S here|pg|| nt|Walddk2: No guarantee of a fit of course, but it's with the odds to assume that 2 of a major plays better|pg|| mb|p|mb|1N|nt|xenya: well EW have some partial on the previous hand -- might pay more than 100|pg|| nt|hedyg: no reason to get higher|pg|| mb|p|mb|3N|nt|Walddk2: http://bridgefestival.no/results.htm for results and ranking|pg|| nt|Walddk2: http://bridgefestival.no/webcam.htm for live pictures with autorefresh every 30 seconds|pg|| mb|p|mb|p|nt|jtr: 2@h|pg|| nt|hedyg: wow great to be able to pass 1@s|pg|| mb|p|nt|jtr: Yes, that is why East must not pass though|pg|| nt|hedyg: first time i see this|pg|| pc|h5|pc|h9|pc|h2|pc|h8|pg|| pc|d4|pc|d6|pc|dJ|pc|d2|pg|| pc|dA|nt|andersk: strange pass|pg|| nt|hedyg: 6-10 HCPs 5 @ss|pg|| nt|voldenuit: maybe 1@s isn't forcing for them |pg|| pc|d9|pc|d7|nt|hedyg: that isnt forcing|pg|| nt|voldenuit: and they use double to show better hand with @s |pg|| nt|hedyg: maybe|pg|| nt|xenya: very awkward for E -- on the one hand he hates to let them 1@S, on the other no bid looks safe enough at this vulnerability|pg|| nt|jtr: You must take risks when the opponents do something that looks good for them|pg|| pc|dQ|pg|| pc|cJ|nt|andersk: wd|pg|| nt|andersk: 9 safe now|pg|| pc|c2|pc|c3|pc|cA|pg|| pc|sT|pc|sJ|pc|sK|pc|s5|pg|| nt|hedyg: claim|pg|| mc|10|pg|| qx|o4|st||md|2ST54HQT9542D74C72,S82HKJ6DAKJ93C863,SA93HA3D865CQJT95,SKQJ76H87DQT2CAK4|sv|b|nt|brolucius: Well, that all finished at the speed of light, after so much thought on the way.|pg|| mb|1D|mb|p|mb|1S|mb|p|mb|1N|mb|p|mb|2D!|mb|p|mb|2N|mb|p|nt|brolucius: Nearly everyone uses either 2@C (or 2@D or both) to ask for extra information on shape.|pg|| nt|Vugraph7: Zmud thought about 2NT, now writing, so maybe had a choice to show the 5 card @d suit, but usually they have 5 when they open 1@d instead of a Polish club with a weak NT|pg|| nt|brolucius: Yes, 1@C shows the 12-14 hands, so 1@D nearly always shows five.|pg|| mb|3D|mb|p|mb|3H!|mb|p|nt|Vugraph7: When he bid 3@h, Zmud indicated it was values|pg|| mb|3N|nt|brolucius: This is a lot of bidding in what seemed at first to be rather simple hands.|pg|| mb|p|mb|p|mb|p|pc|cJ|pc|cA|nt|brolucius: But I suppose that is the only way to detect @H8-7 opposite @HQ-4 and then play in diamonds instead.|pg|| pc|c2|pc|c3|pg|| pc|sK|pc|s5|pc|s2|pc|sA|pg|| pc|c9|nt|Vugraph7: Bal went for a cigarette break, then the hand was very fast and now Zmud has gone to get him|pg|| nt|Vugraph7: Now Meck & Rod leaving also, back shortly I'm sure|pg|| nt|brolucius: Cigarette break. Is that $250 or 10 IMPs in this tournament? I forget.|pg|| nt|brolucius: Does Meckstroth still smoke? I remember (a few years ago) that Rodwell detested smoke. |pg|| nt|brolucius: A kibitzer tells me that the penalty is the 'higher of the two', namely 10 IMPs.|pg|| nt|kareno: I believe he still does.|pg|| nt|brolucius: Anyway, taking a cigarette break when you are keeping 1991 people waiting is quite something. |pg|| nt|kareno: They're playing fast enough not to incur time penalties I'm sure.|pg|| nt|kareno: And that is only in THIS room!!|pg|| nt|brolucius: Yes. "Marlboro tastes so great, folks, that people who smoke them are happy to keep 1991 people waiting."|pg|| nt|kareno: There is only one smoking area in the Convention Center and that is quite a distance from the playing space. |pg|| nt|brolucius: The further the better. The TD should supply nicotine patches.|pg|| nt|Vugraph7: We're back now|pg|| mc|11|pg|| qx|c4|st||md|2ST54HQT9542D74C72,S82HKJ6DAKJ93C863,SA93HA3D865CQJT95,SKQJ76H87DQT2CAK4|sv|b|mb|1D|mb|p|mb|1S|mb|p|mb|1N|mb|p|mb|2D!|mb|p|mb|3D|mb|p|nt|voldenuit: they will play probably 4@h = |pg|| mb|3S|nt|jtr: A very flat noard here|pg|| nt|hedyg: can claim already|pg|| mb|p|nt|andersk: yes|pg|| mb|4S|mb|p|mb|p|mb|p|pc|c7|pc|c8|pc|c9|pc|cA|pg|| pc|sK|pc|s4|pc|s2|pc|s3|pg|| pc|sQ|pc|s5|pc|s8|pc|sA|pg|| nt|voldenuit: y few pairs might played 5@h if west make an effort with this hand |pg|| nt|andersk: agree|pg|| pc|cQ|pc|cK|pc|c2|pc|c3|pg|| pc|sJ|pc|sT|pc|c6|pc|s9|pg|| mc|11|pg|| qx|o5|st||md|3SJ87HJ2DAJ973C753,SH9864DKQ6CKQT864,SA9643HA753D52CAJ,SKQT52HKQTDT84C92|sv|n|nt|Vugraph7: Meck, who just gave up smoking, says "I can smell you guys, it smells wonderful"|pg|| mb|1S|nt|brolucius: A friend of mine, Marc Smith, asked me to joing his pub quiz team. I said I would after July, when smoking was banned in English pubs. He replied that he would not be going to any ...|pg|| nt|brolucius: pubs then. (He is a two-pack-a-day man).|pg|| mb|p|mb|1N!|mb|p|mb|2H|mb|p|mb|2S|mb|p|mb|p|mb|p|nt|kareno: e/w wisely staying out of this misfit auction.|pg|| nt|Vugraph7: Meck, as he puts down dummy; "we play 1-2 as constructive"|pg|| pc|d8|nt|Vugraph7: Rod: "just so I understand, with 3 small you lead middle?" Zmud yes|pg|| pc|dA|pc|d6|pc|d2|pg|| pc|h2|pc|h4|pc|h7|pc|hQ|pg|| pc|c2|pc|c3|pc|cQ|pc|cA|pg|| pc|hA|pc|hK|pc|hJ|pc|h6|pg|| pc|h3|pc|hT|pc|s7|pc|h8|pg|| pc|c5|pc|cK|pc|cJ|pc|c9|pg|| nt|brolucius: Yes, when you play a forcing 1NT response there are two ways of raising to 2@S: direct and via 1NT. Since you have to take the indirect route on some hands with only two spades, it ...|pg|| nt|brolucius: is sensible that this is the weaker route.|pg|| pc|dK|pc|d5|pc|d4|pc|d3|pg|| pc|c8|pc|s6|nt|kareno: East's spades may become an encumbrance.|pg|| pc|sT|pc|c7|pg|| pc|sK|pc|s8|pc|c4|pc|sA|pg|| pc|h5|pc|dT|pc|sJ|pc|h9|pg|| mc|7|pg|| qx|c5|st||md|3SJ87HJ2DAJ973C753,SH9864DKQ6CKQT864,SA9643HA753D52CAJ,SKQT52HKQTDT84C92|sv|n|nt|xenya: but i don't like E's break -- his hand is under 17 hcp i think|pg|| nt|andersk: just tell them to claim 11 here|pg|| mb|1S|nt|jtr: and another.....|pg|| mb|p|mb|2S!|mb|3C|mb|p|mb|p|nt|xenya: sort of twin hand|pg|| mb|p|pc|d5|pc|d8|pc|dA|pc|d6|pg|| nt|andersk: maybe we can get a smoke break|pg|| pc|hJ|pc|h4|pc|hA|nt|voldenuit: they have avoid the contract of 3Nt which is 10 tricks |pg|| nt|jtr: However, you will find that E/W will probably score around 55% on each of these|pg|| pc|hT|pg|| pc|h3|pc|hQ|pc|h2|pc|h6|pg|| pc|c2|pc|c5|pc|cK|pc|cA|pg|| pc|h5|pc|hK|pc|c3|nt|andersk: Karlberg - Fagerdal, just past +800|pg|| pc|h8|pg|| pc|d3|pc|dQ|pc|d2|pc|d4|pg|| pc|cQ|pc|cJ|pc|c9|pc|c7|pg|| mc|9|pg|| qx|o6|st||md|4S72HAKQT43DAQCKQ6,SKT8643HJ7DKT93C5,SAQJ5H985D64CA942,S9H62DJ8752CJT873|sv|e|nt|kareno: The five will stand up for a trick but east will be endplayed for down only one.|pg|| mb|p|nt|Vugraph7: Meck: Good you didn't take a long time to play that one. Rod "well, I might have done better double dummy..."|pg|| nt|brolucius: Nickells' 3@C overcall at the other table may seem risky, but when the opponents find a fit at a low level (1@S - 2@S) it is reasonably safe to enter the bidding with a long suit. ...|pg|| nt|brolucius: They will not want to double at a low level.|pg|| mb|1C!|an|str|nt|kareno: A good heart slam here.|pg|| mb|1H|an|!|nt|Vugraph7: Both sides writing but of course I can't read them|pg|| nt|brolucius: Wow! 1100 at the one level at the other table.|pg|| mb|d!|nt|kareno: Could be a duplicated result here.|pg|| mb|2N|nt|brolucius: Nice double from South (there) rather than bidding the hearts.|pg|| nt|kareno: With that EXCELLENT dummy :)|pg|| nt|kareno: Finding a better home .. diamonds|pg|| nt|brolucius: 1@H must show two suits, so East is confident of a fit in one of the minors.|pg|| nt|kareno: And safe for sure at the three-level.|pg|| nt|Vugraph7: Zmud writing a lot - I might be able to see if it was in pen, but it's pencil, sorry|pg|| mb|3H|mb|p|nt|brolucius: I am told: 1@H is 54 with @S and @D or with @H and @C|pg|| nt|Vugraph7: I'm told that 2NT was pick a minor|pg|| nt|kareno: 7 is excellent on the auction. |pg|| nt|kareno: They will surely reach 6@h.|pg|| nt|brolucius: Now it is more difficult for North to express his hand because the opponents have not clearly bid a suit.|pg|| nt|kareno: They have bid spades clearly, David, and north has those locked up.|pg|| nt|brolucius: To reach 7@H would be an immense triumph. To reach 6@H would be great.|pg|| nt|kareno: Actually with the explanation, west has shown spades and diamonds.|pg|| nt|brolucius: North might bid 3@S, on the assumption that West must hold that suit, but it is a bit murky.|pg|| nt|Vugraph7: Rod studying his hand and the bidding|pg|| mb|5H|mb|p|nt|brolucius: Now South may worry about two spade losers.|pg|| nt|brolucius: Amazing what difficulties the intervention caused. You can imagine M/R soaring into a slam in a few seconds without intervention.|pg|| nt|Vugraph7: Silent conversation between Meck & Zmud|pg|| nt|kareno: It is absolutely clear now that west holds spades and diamonds. South has bid hearts naturally.|pg|| nt|brolucius: But Meckstroth's trumps are so great he can guess that North must hold some controls.|pg|| mb|6H|mb|p|mb|p|mb|p|nt|brolucius: He cannot be missing controls AND trumps. Yes, well bid!|pg|| nt|kareno: So they will pick up eight IMPs on the board.|pg|| nt|kareno: Welcome Doug Simpson, a great player and expert on Meckwell|pg|| nt|Vugraph7: Meck & Rod discuss what they should do vs EW's interference|pg|| pc|c5|pc|c2|pc|cT|pc|cK|pg|| nt|kareno: Oh.. wrong vulnerability.. sorry, they lose IMPs here.|pg|| pc|hA|pc|h7|pc|h5|pc|h2|pg|| pc|hK|pc|hJ|pc|h8|pc|h6|pg|| nt|kareno: Lose three IMPs.|pg|| nt|dougs: Rod's x is usually 6-7, but here he was hoping for a penalty|pg|| pc|hQ|pc|s6|pc|h9|pc|c3|pg|| pc|s7|pc|s3|pc|sQ|pc|s9|pg|| pc|c4|pc|c7|pc|cQ|pc|s4|pg|| pc|s2|pc|s8|pc|sJ|mc|13|pg|| qx|c6|st||md|4S72HAKQT43DAQCKQ6,SKT8643HJ7DKT93C5,SAQJ5H985D64CA942,S9H62DJ8752CJT873|sv|e|mb|p|mb|1C!|mb|1S|nt|andersk: hehe another @h Game|pg|| mb|p!|nt|jtr: method testing for E/W|pg|| nt|hedyg: why not bid 1@s?|pg|| nt|hedyg: as t/o of @s|pg|| nt|jtr: Transfers are not unusual nowadays so they should know what to do|pg|| mb|p|mb|d|nt|voldenuit: 4@s downs of 3 in NS with a good defense |pg|| nt|jtr: X then X to show more maybe?|pg|| mb|p|mb|p|nt|jtr: Nice 3@s|pg|| mb|p|nt|hedyg: 1@s and then X for me|pg|| nt|jtr: South may save now|pg|| nt|hedyg: now if i could only get pd to lead @d......|pg|| pc|h8|pc|h2|pc|hQ|nt|xenya: why not lead it yourself Hedy?|pg|| pc|h7|pg|| nt|hedyg: ah true!|pg|| nt|hedyg: :))|pg|| pc|s2|pc|s3|pc|sJ|pc|s9|pg|| pc|h9|pc|h6|pc|hK|pc|hJ|pg|| pc|hT|pc|s4|pc|h5|nt|xenya: played by S 4@S is likely to go 3 down -- too expensive|pg|| pc|d2|pg|| pc|dK|pc|d4|pc|d5|pc|dA|pg|| pc|h3|pc|s6|pc|d6|pc|d7|pg|| nt|jtr: If East takes the @dA|pg|| pc|d9|nt|xenya: yes|pg|| pc|s5|pc|d8|pc|dQ|pg|| pc|c4|pc|c3|pc|cQ|pc|c5|pg|| pc|h4|pc|sT|pc|sQ|pc|dJ|pg|| pc|c2|pc|c7|nt|andersk: now short break:)|pg|| nt|jtr: Yes i am|pg|| nt|vugraph814: they played fast, so a short break till next round|pg|| nt|andersk: I think The leaders will scoore 70% this round|pg|| nt|hedyg: webcam: http://bridgefestival.no/modules.php?name=NukeWrap&page=http://bridgefestival.no/refresh.htm|pg|| nt|andersk: I think we get Geo-Furunes vs karlber- Fagerdal next round|pg|| nt|hedyg: wishful thinking?|pg|| nt|andersk: top 3 vil jeg si|pg|| nt|hedyg: webcam seems to be stuck|pg|| nt|Walddk2: webcam is fine here, but updates on result page. they are having a look at it now|pg|| nt|Walddk2: no updates currently|pg|| nt|hedyg: i have had the same picture for 10 minutes|pg|| nt|Walddk2: Definitely working|pg|| nt|Walddk2: http://bridgefestival.no/webcam.htm for live pictures with autorefresh every 30 seconds|pg|| nt|andersk: my webcam is ok|pg|| nt|hedyg: i feel at a disadvantage! story of my life|pg|| nt|andersk: hehe|pg|| nt|andersk: 2 strong pairs now|pg|| nt|vugraph814: Waiting for Geo|pg|| nt|Walddk2: 170 pairs in the Swiss here, and 60 teams in the mixed simultaneously. Very impressive. We had 260 pairs in the mixed|pg|| nt|andersk: thats normal:)|pg|| nt|andersk: been around 160-180 in swiss pairs last 3 years, we had 220 3 years ago|pg|| nt|vugraph814: including the side tournament, there are 185 tables at play now. New record!|pg|| nt|andersk: no|pg|| nt|andersk: thats not recor Ivar|pg|| nt|vugraph814: wanna bet? :)|pg|| nt|andersk: 2 years ago therewere 198 teams in open teas, and 2 sideturnament beside withover 30 tables|pg|| pc|cK|pc|s8|pg|| pc|d3|pc|c9|pc|c8|pc|s7|pg|| pc|hA|mc|3|pg|| qx|o7|st||md|1SK9H743DAQJ2CQ954,ST7HAJ65D873CA872,SAQJ4HT982D965CT3,S86532HKQDKT4CKJ6|sv|b|nt|brolucius: North-South can be happy to have reached 6@H, as I see it. They faced a very awkward situation, which they got right. |pg|| nt|Vugraph7: R-M agree that DBL is a little better vs these methods. |pg|| nt|kareno: Doug :)|pg|| mb|1D|an|can be short|mb|p|mb|1H|mb|p|nt|Walddk2: Welcome to Doug Simson, one of our two Meckwell experts|pg|| nt|Vugraph7: Meck said: "great bid, partner" after the discussion about new methods|pg|| mb|1N|mb|p|mb|p|mb|p|nt|Vugraph7: No lead, Meck says "thank you, play small"|pg|| nt|dougs: Meckwell have great judgement in these ackward hands.|pg|| pc|c2|pc|c3|pc|cK|pc|c4|pg|| pc|cJ|pc|cQ|nt|brolucius: Yes, and that is so important. That sort of hand is where all the points exchange hands.|pg|| pc|cA|pc|cT|pg|| nt|Walddk2: 4 segments of 16 boards, two of which will be played before a break for dinner|pg|| pc|c8|pc|d5|pc|c6|pc|c9|pg|| pc|s9|pc|s7|pc|sJ|pc|s6|pg|| pc|d6|nt|Walddk2: I am asked if the players know the running scores. The answer is know. They will not know until they score up after each segment of 16 boards|pg|| pc|d4|pc|dQ|pc|d3|pg|| pc|sK|pc|sT|pc|sA|pc|s2|pg|| nt|Walddk2: The answer is no, I meant to say|pg|| pc|sQ|nt|brolucius: With players of this quality at the table, we might easily be watching a Bermuda Bowl final (as another commentator mentioned at the start). Even a 1NT contract may become ...|pg|| nt|brolucius: interesting. No, I shouldn't exaggerate.|pg|| pc|s3|pc|d2|pc|h5|pg|| pc|d9|nt|kareno: Actually, David, while some points change hands on these deals, I am still of the opinion that the team that gets the partscore battles right will win in the long run.|pg|| pc|dT|pc|dJ|pc|d7|pg|| pc|dA|pc|d8|pc|s4|pc|dK|pg|| nt|Walddk2: I must agree with that|pg|| mc|8|pg|| qx|c7|st||md|1SK9H743DAQJ2CQ954,ST7HAJ65D873CA872,SAQJ4HT982D965CT3,S86532HKQDKT4CKJ6|sv|b|nt|hedyg: we trust Ivar! he told us to:)|pg|| nt|andersk: I take the bet|pg|| nt|andersk: I was there:)|pg|| mb|1N|mb|p|mb|p|mb|p|pc|h5|pc|h2|pc|hQ|pc|h4|pg|| pc|hK|pc|h7|pc|h6|pc|h8|pg|| pc|d4|pc|dQ|nt|jtr: 3@c shows a good raise but a little optimistic|pg|| pc|d3|pc|d5|pg|| pc|sK|pc|sT|pc|s4|pc|s3|pg|| pc|s9|pc|s7|pc|sJ|pc|s2|pg|| pc|sA|pc|s5|pc|c4|pc|c2|pg|| nt|voldenuit: very funny board if 4@s is played king of @c ruff @d ruff @c overruff |pg|| nt|andersk: 4@S is makeable|pg|| nt|jtr: I guess 4@s might have made|pg|| pc|sQ|pc|s6|pc|h3|pc|d8|pg|| pc|d6|nt|jtr: But could be defeated|pg|| pc|dT|pc|dJ|pc|d7|pg|| pc|dA|pc|c7|pc|d9|pc|dK|pg|| pc|d2|pc|c8|nt|jtr: ?|pg|| nt|jtr: Did he miss the @c9?|pg|| nt|hedyg: seems so|pg|| nt|Walddk2: Good afternoon to Frances Hinden from England|pg|| pc|c3|pc|s8|pg|| mc|11|pg|| qx|o8|st||md|2SAHA8432DAQT2CK94,SQJ98HKDJ98765C75,SKT65HT7D4CAQJT82,S7432HQJ965DK3C63|sv|o|nt|Walddk2: The partscore swings often decide matches between two very good teams|pg|| mb|p|mb|2C!|an|6+ clubs, 11-15|nt|kareno: Note how south gave up a spade trick for the extra entry to finesse diamonds twice. |pg|| mb|p|mb|2D|an|asking description|nt|brolucius: Seven hands in an hour, despite the break. That is better. The first session of one of the QFs took 3 hours for 16 boards. I never heard if any penalty was applied. Probably not.|pg|| nt|Walddk2: 2@C 11-15 5+ clubs|pg|| mb|p|mb|2H!|mb|p|mb|2S|an|!|mb|p|nt|dougs: 2@H shows a major|pg|| mb|3C!|mb|p|mb|3D!|nt|Walddk2: Can be 10 with a good shape like this one|pg|| nt|dougs: 3@C shows spades|pg|| mb|p|nt|dougs: 3@D is a slam try on @C|pg|| mb|3S!|mb|p|nt|brolucius: Another bidding test for them. But with no opposition the odds are good that they can hit the target.|pg|| nt|dougs: 2C promises 6|pg|| mb|4D!|an|RKCB !cs|mb|p|nt|kareno: This has the feel of a relay auction.. Doug?|pg|| mb|4S|nt|brolucius: It will be disappointing when someone makes a natural bid.|pg|| mb|p|nt|dougs: 3@S shows a spade control and denies a @H control|pg|| mb|4N|nt|Walddk2: http://usbf.org/docs/2006usbc/SSF/06meckstrothrodwell.htm for a system summary|pg|| nt|dougs: 4@D is RKC|pg|| nt|Vugraph7: I think 4@d was RKCB clubs and 4@s showed 1|pg|| nt|dougs: 4@S is 1|pg|| mb|p|mb|5H|nt|dougs: 4nt ask for Q|pg|| mb|p|nt|dougs: 5@H is q with 1 king|pg|| nt|Walddk2: Nice to have Doug here to give us accurate info on all this artificial stuff|pg|| nt|kareno: I'll say!!|pg|| nt|brolucius: I hope Bal and Zmud are enjoying this. I guess not. |pg|| nt|dougs: Thanks|pg|| mb|6C|mb|p|mb|p|mb|p|nt|kareno: They are having a nice nap until the full auction is over.|pg|| pc|hQ|pc|hA|pc|hK|pc|h7|pg|| nt|dougs: Rod is known to be 6+@C with 4@S and 2 @H without A K|pg|| nt|brolucius: It was like watching an expert cellist. You don't know quite how he/she does it but the end effect is very pleasant.|pg|| pc|sA|pc|s8|pc|s5|pc|s2|pg|| pc|c4|pc|c5|nt|Walddk2: They are thinking about 7 in the closed room at the moment|pg|| nt|kareno: A trump lead would have been useful here. But the diamond comes on the second round so all is well. (and is in the pocket for that possible play).|pg|| pc|cQ|pc|c3|pg|| pc|s6|pc|s3|nt|Walddk2: 6@C bid so far, but Dubinin is in the tank|pg|| pc|c9|pc|s9|pg|| pc|dA|pc|d5|pc|d4|pc|d3|pg|| nt|kareno: It's not good but it will make if it is bid.|pg|| nt|Vugraph7: Meck: "sorry, should have bid it" Rod: "did he have the K of diamonds? I dont' want to bid grands on a finesse"|pg|| nt|Walddk2: 6@C passed eventually in the closed room|pg|| mc|12|pg|| qx|c8|st||md|2SAHA8432DAQT2CK94,SQJ98HKDJ98765C75,SKT65HT7D4CAQJT82,S7432HQJ965DK3C63|sv|o|nt|hedyg: welcome Frances|pg|| nt|finch: Good afternoon|pg|| nt|andersk: Welc:)|pg|| mb|p|nt|voldenuit: hi frances |pg|| nt|xenya: hello Frances|pg|| mb|2C!|mb|p|mb|2D|nt|vugraph814: sry, misclick|pg|| mb|p|nt|voldenuit: conservative pass by north |pg|| nt|hedyg: very|pg|| mb|2S|nt|hedyg: lollllll|pg|| mb|p|mb|2N!|mb|p|mb|3S!|nt|xenya: but not unreasinable -- holding as many as 3 hearts|pg|| mb|p|mb|4C!|mb|p|mb|4D|nt|finch: I was about to say I might bid 1NT in 4th seat (as a passed hand)|pg|| nt|finch: ...which would not have been a great success|pg|| nt|hedyg: how many @ss did W need to pass?|pg|| mb|p|nt|voldenuit: I don't like to bid 1Nt without stopper @h |pg|| mb|4H!|mb|p|mb|5H!|mb|p|mb|5N!|mb|p|mb|6C|mb|p|nt|finch: This is the one auction in which I think it's OK|pg|| nt|Walddk2: A cunning low heart now perhaps|pg|| mb|p|mb|p|pc|hJ|pc|hA|pc|hK|pc|h7|pg|| pc|sA|pc|s9|pc|s5|pc|s4|pg|| pc|dA|pc|d5|pc|d4|pc|d3|pg|| pc|d2|pc|d6|nt|hedyg: nice|pg|| pc|c2|pc|dK|pg|| pc|cA|pc|c3|pc|c4|pc|c5|pg|| pc|sK|pc|s2|pc|h2|mc|12|pg|| qx|o9|st||md|3SQJ4HT42DQ76CQJT8,SKT9632HKJDAK2C52,S87HAQ8DJ953C9643,SA5H97653DT84CAK7|sv|e|mb|p|nt|dougs: Meck knew they had a heat loser from Eric failre to cue 3@H|pg|| mb|1H|nt|dougs: heart|pg|| mb|p|mb|1S|nt|Vugraph7: M-R still mumbling about whether they should have tried harder for 7 :)|pg|| nt|brolucius: Great to get actual dialogue. Much appreciated, Jan!|pg|| mb|p|mb|1N|nt|brolucius: Like many of the kibitzers, I would have been well pleased to get to six. Typical that at this level they have to mumble about missing seven.|pg|| mb|p|mb|4S|mb|p|mb|p|mb|p|pc|c4|nt|kareno: I've been asked about prizes for this tournament. Of course there are master points (but these folks don't need them!).|pg|| pc|cK|nt|kareno: In addition there is (for an all-US team) the benefit of better placement in the Team Trials |pg|| pc|cQ|pc|c2|pg|| nt|dougs: Can i buy some master points on E-bay?|pg|| nt|brolucius: They will get a Mercedes each from their sponsors. No problem.|pg|| nt|kareno: However, there are no money prizes - with a professional team, there are, of course, fees from the sponsor and possible bonuses but we are not privy to that information.|pg|| nt|Vugraph7: Mostly it's glory - name on the Spingold trophy :)|pg|| nt|brolucius: Neither is the taxman privy to that information, I dare say...|pg|| nt|Walddk2: Fame but no fortune?|pg|| nt|kareno: Nickell most likely gets his extra qualification by being the last US team in the event.|pg|| nt|kareno: This could mean a bye to the semi-finals.. Jan is that correct?|pg|| pc|sA|pc|s4|pc|s2|pc|s7|pg|| pc|s5|pc|sQ|pc|sK|pc|s8|pg|| pc|sT|nt|kareno: The event I'm referring to is the US Team Trials for World Championship play.|pg|| nt|Vugraph7: No, this one event won't earn them a semi-final bye - need more Positioning Points than that, but it's a good start|pg|| pc|c3|pc|h3|pc|sJ|pg|| pc|h2|nt|Vugraph7: I don't have the PP scale or bye requirements memorized, but I think a semi bye requires at least one win plus something more|pg|| pc|hJ|pc|hQ|pc|h5|pg|| pc|c6|pc|cA|pc|c8|pc|c5|pg|| pc|h6|pc|h4|pc|hK|pc|hA|pg|| nt|kareno: And this is what, the beginning of a cycle?|pg|| mc|9|pg|| qx|c9|st||md|3SQJ4HT42DQ76CQJT8,SKT9632HKJDAK2C52,S87HAQ8DJ953C9643,SA5H97653DT84CAK7|sv|e|mb|p|nt|Walddk2: This would have been a passout 57 years ago|pg|| mb|p|nt|Walddk2: Not so any more|pg|| nt|hedyg: now they all open:)|pg|| nt|jtr: Now it is maybe a game hand:)|pg|| mb|p|mb|1S|nt|hedyg: E. S and W|pg|| mb|p|mb|2H|nt|finch: Good hand for the methods: 1@S denying spades|pg|| mb|p|mb|2S|nt|hedyg: maybe showing @ds|pg|| nt|finch: (double shows spades) - gets NT the right way up|pg|| nt|jtr: Maybe play a 14-16NT|pg|| nt|Walddk2: No, just denying four spades|pg|| mb|p|nt|hedyg: ok ty|pg|| mb|3S|nt|hedyg: wow lead|pg|| mb|p|mb|4H|nt|jtr: Unusual|pg|| mb|p|mb|4S|mb|p|mb|p|nt|hedyg: especially since W tends to have minors|pg|| nt|finch: Horrible lead problem. I might have gone for a low spade lead - but depends what double of 1@S would have meant|pg|| nt|Walddk2: I'm old-fashioned. I would have led 4th best from my longest and strongest|pg|| mb|p|nt|hedyg: leading through dummies strength?|pg|| pc|c6|pc|cA|pc|cQ|nt|Walddk2: And @H3 would have been a fine lead|pg|| pc|c2|pg|| pc|h3|pc|h4|pc|hJ|nt|jtr: the @h2 even:)|pg|| pc|hQ|pg|| pc|c3|pc|cK|pc|c8|pc|c5|pg|| pc|h5|pc|h2|pc|hK|pc|hA|pg|| nt|hedyg: didnt expect K@D in N|pg|| pc|c4|pc|c7|pc|cJ|pc|s2|pg|| pc|s3|pc|s7|pc|sA|nt|hedyg: sry J@d|pg|| nt|vugraph814: Geo not looking happy, the diamond position was a nasty surprise|pg|| pc|s4|pg|| pc|s5|pc|sJ|pc|sK|pc|s8|pg|| pc|s9|pc|c9|pc|h6|nt|Walddk2: http://bridgefestival.no/webcam.htm for live pictures with autorefresh every 30 seconds|pg|| pc|sQ|pg|| nt|voldenuit: 1Nt is a good mark for EW|pg|| nt|hedyg: @ds were supposed to be 3 3 with QJ10 in S|pg|| nt|xenya: yes nice score|pg|| nt|finch: +120 would have been even better|pg|| nt|voldenuit: 90 is probably 70% for EW|pg|| nt|jtr: Most wll open i would think Suitable distribution|pg|| nt|finch: 3 10s|pg|| nt|finch: More of an opening bid that many 4333 12-counts|pg|| nt|xenya: true but where 1@H opening would get them is another question|pg|| nt|finch: I think East has more of an opening than South, even though South has a 5-card suit|pg|| nt|xenya: ah yes|pg|| nt|Walddk2: Good afternoon and welcome back to Liz McGowan|pg|| nt|cuttysark: Good afternoon|pg|| nt|finch: Hi Liz|pg|| nt|xenya: re Liz|pg|| nt|voldenuit: hi liz |pg|| pc|hT|pc|s6|pc|h8|pc|h7|pg|| pc|sT|pc|d3|pc|h9|pc|cT|pg|| pc|dA|mc|9|pg|| qx|o10|st||md|4SAK43HQT764DJ632C,SJ5H52DAQ5CAJT964,S76H983DT874CK832,SQT982HAKJDK9CQ75|sv|b|nt|Walddk2: Please understand that the commentators may not have time to respond to private chat messages. No offence intended. Useful information much appreciated though|pg|| nt|kareno: Positioning points for the Open Team Trials come from the three major team games - the Vanderbilt, the Spingold and the Reisinger.|pg|| nt|Walddk2: sagolun çok teþekkürler siz nereye karar verdiniz. is not considered useful info as far as I am concerned :)|pg|| nt|Vugraph7: Yes, the Open cycle is always Summer-Spring, so this is the first event of the cycle. PPs are awarded based on finish in the event (iow, if Nickell loses today, they get the PPs ...|pg|| nt|Vugraph7: for second even though the winners would not get any PPs because they're not US players)|pg|| mb|1N|an|15-17|nt|brolucius: Incredible that the scoreline is just 5-0. A measure of the standard, I suppose. |pg|| mb|d!|an|1 minor or both majors|nt|dougs: d is 1 minor or both majors|pg|| mb|3N|nt|dougs: x|pg|| mb|p|nt|Walddk2: We will try to respond to as many private messages as possible and even relay questions if we find them appropriate, but please understand that we can't respond to all of them. ...|pg|| nt|Walddk2: Thank you|pg|| mb|p|mb|p|pc|h6|nt|kareno: I think we can sit back and have a cup of tea (_)? and a few cookies (except Roland who prefers smaller ones) OOO|pg|| nt|Vugraph7: Zmud: "don't go too many down" |pg|| pc|h2|nt|Walddk2: Yes, the holes are too big|pg|| pc|h3|pc|hJ|pg|| pc|cQ|pc|h4|pc|c4|nt|brolucius: On the last deal declarer would have had to set up the hearts to dispose of his diamond loser. Not an obvious line, perhaps.|pg|| pc|cK|pg|| nt|kareno: We used to say, "Don't come home lame, partner!" with such a dummy.|pg|| pc|s7|mc|10|pg|| qx|c10|st||md|4SAK43HQT764DJ632C,SJ5H52DAQ5CAJT964,S76H983DT874CK832,SQT982HAKJDK9CQ75|sv|b|mb|1N|mb|2H!|mb|2N!|mb|p|nt|vugraph814: sys on or not after X? :)|pg|| nt|hedyg: xfer to @c|pg|| mb|3C|mb|d|nt|finch: 2@S either a transfer to clubs or a well-timed psyche|pg|| nt|hedyg: ooooops|pg|| mb|3N|mb|p|nt|Walddk2: Well, it was natural to one player|pg|| mb|p|mb|p|nt|voldenuit: missunderstand here |pg|| nt|hedyg: he got me!|pg|| nt|cuttysark: I was wondering what the double meant :) Some play it as showing spades....|pg|| nt|Walddk2: Unfortunately the wrong one|pg|| nt|jtr: Where is DB99 on the rare occasion we need him?:)|pg|| pc|h6|nt|finch: Do we know what the double meant?|pg|| pc|h2|nt|voldenuit: y and west hasn't double |pg|| pc|h8|nt|hedyg: see? even when he isnt here he is here!|pg|| nt|vugraph814: double showed a strong hand|pg|| pc|hJ|pg|| pc|cQ|pc|hQ|nt|cuttysark: I suppose he fancies his chances with a spade lead. Probably fancies them even more now|pg|| pc|c4|pc|c2|pg|| nt|finch: It can be a wildly effective psyche when partner has 12-14, less so opposite a strong NT|pg|| nt|Walddk2: Holmen left in the dark|pg|| nt|Walddk2: Maybe he knows now|pg|| nt|hedyg: now why doesnt pd give a ruff?|pg|| nt|Walddk2: The problem is that he endplayed his partner|pg|| nt|finch: As it seems that 2@S was marginal for 7 or 8 tricks, going for -150 won't be good|pg|| nt|finch: -100 might not be great either, but that will be his target|pg|| pc|c5|pc|dJ|pc|cJ|pc|cK|pg|| pc|s7|pc|s2|pc|sK|pc|s5|pg|| pc|sA|pc|sJ|pc|s6|pc|s8|pg|| mc|10|pg|| qx|o11|st||md|1SJTHJ95DT52CKT853,SA8764HQ4DK6CJ742,S9HAT763DAQJ9CQ96,SKQ532HK82D8743CA|sv|o|mb|p|mb|p|mb|1H|mb|1S|nt|Vugraph7: We've had a time monitor in the room, so the pace of play has picked up :)|pg|| mb|2H|nt|Vugraph7: Now that we're back on time, he's left :)|pg|| mb|3H|nt|kareno: That would help!|pg|| nt|brolucius: I had so many messages, I was not following the last deal. General opinion seems to be that the club lead prevented declarer from making the contract. |pg|| mb|p|mb|4S|mb|p|mb|p|mb|p|nt|Vugraph7: M & R agreed they couldn't beat it|pg|| pc|h5|pc|h4|pc|hA|pc|h2|pg|| pc|h3|nt|kareno: North has a problem on the low heart lead. If south has the king, he needs to cash two hearts and get a diamond shift.|pg|| nt|brolucius: Declarer now has a discard for one of the diamond losers.|pg|| mc|11|pg|| qx|c11|st||md|1SJTHJ95DT52CKT853,SA8764HQ4DK6CJ742,S9HAT763DAQJ9CQ96,SKQ532HK82D8743CA|sv|o|nt|Walddk3: http://bridgefestival.no/webcam.htm for live pictures with autorefresh every 30 seconds|pg|| mb|p|mb|p|nt|jtr: This 11 i would not think of opening|pg|| nt|hedyg: 2 10s......|pg|| nt|finch: Nor I|pg|| nt|vugraph814: Nymoen commenting it was bad luck this happened at the vugraph table :)|pg|| mb|1H|nt|jtr: yes, and three ruffing values i suppose....|pg|| mb|1S|nt|hedyg: and opps still in shock.....|pg|| nt|xenya: obviously W and N went to different schools|pg|| nt|hedyg: hopefully!|pg|| mb|2D!|mb|2H!|nt|Walddk3: No defence against 3NT|pg|| mb|3D|mb|3H|nt|hedyg: 2NT is a bit high for me|pg|| nt|finch: 3NT is a little awkward once North has held up in diamonds twice|pg|| mb|p|nt|finch: Though I agree it's still likely to make a lot of tricks|pg|| nt|Walddk3: Then you can turn your attention to hearts|pg|| mb|4S|mb|p|mb|p|nt|jtr: Odd not to raise Maybe they open all 11's too|pg|| mb|p|pc|sJ|pc|s4|pc|s9|nt|jtr: But the KJ@c is worth 5 points|pg|| nt|voldenuit: north has to duck 1 time more |pg|| nt|finch: Covering the @D10 gives North count in the suit|pg|| nt|hedyg: you can overtake @c to get to hand|pg|| nt|finch: That's only 8 tricks, however|pg|| pc|sK|pg|| mc|10|pg|| qx|o12|st||md|2SQ98742HJ4DQ6CAK3,SKJT3HQT7DT9832C8,SA5HK632DKJ5CT642,S6HA985DA74CQJ975|sv|n|nt|kareno: In this case, the ace loses a trick but it is not an important trick.|pg|| mb|p|mb|1D|an|can be short|nt|kareno: The three of hearts was, I suspect, upside down suit preference, showing diamonds. Doug?|pg|| nt|dougs: i can answer questions on meckwell if anyone likes|pg|| nt|brolucius: I am impressed by all five participants here (including Jan.... nice job!)|pg|| mb|p|mb|1S|mb|p|nt|dougs: they play ud suit pref|pg|| mb|1N|mb|p|nt|dougs: doesn't everyone?|pg|| nt|Vugraph7: Thank you for all of us :)|pg|| nt|Walddk2: They are playing very fast in this room. On board 9 in the closed room|pg|| nt|kareno: Yes, so a low heart back would ask for the high suit, in this case diamonds.|pg|| mb|3S|mb|p|nt|brolucius: If anyone wants to know why it is good idea to open that North hand, vulnerable, please ask Doug and not me...|pg|| mb|p|mb|p|pc|d3|pc|d5|nt|kareno: Ahh and I thought the Brits were the specialists in paper-thin opening bids :)|pg|| nt|brolucius: 3@S is normally played as forcing. Not by them, though, so it is a good stop.|pg|| nt|Walddk2: Not balanced 11 counts, unless you play some kind of mini-NT|pg|| pc|dA|pc|d6|pg|| pc|c5|pc|cA|pc|c8|pc|c2|pg|| pc|s2|pc|s3|pc|sA|pc|s6|pg|| pc|s5|pc|c7|pc|s9|nt|Walddk2: 1@S was the limit it seems|pg|| pc|sT|pg|| nt|Walddk2: Very nasty trump break|pg|| nt|brolucius: It is easier to get away with light openings when you play a strong 1@C system. Otherwise you run the risk of widening the range too much for one-of-a-suit. |pg|| pc|d8|nt|kareno: I imagine they are glad they play it invitational only.|pg|| pc|dK|pc|d7|pc|dQ|pg|| pc|dJ|pc|d4|pc|c3|pc|d2|pg|| pc|c4|nt|dougs: controls are underrated...an A and 2 K's qualify for a Meckwell opening|pg|| pc|c9|pc|cK|pc|sJ|pg|| pc|sK|pc|h2|pc|h5|pc|s4|pg|| pc|dT|pc|c6|pc|cQ|pc|s7|pg|| mc|7|pg|| qx|c12|st||md|2SQ98742HJ4DQ6CAK3,SKJT3HQT7DT9832C8,SA5HK632DKJ5CT642,S6HA985DA74CQJ975|sv|n|mb|p|mb|p|mb|1C|mb|1S|mb|p|mb|1N|nt|hedyg: heavy 1NT|pg|| mb|p|mb|2S|nt|cuttysark: Gosh, the16-18 1NT - you don't see many of these|pg|| nt|hedyg: AND both majors!|pg|| nt|voldenuit: pessimistic bid from the 2 sides |pg|| mb|p|nt|finch: Is it really 16-18? If so why didn't East move?|pg|| mb|3S|mb|p|nt|vugraph814: they play 15-17|pg|| mb|3N|mb|d|nt|jtr: What is East doing?|pg|| nt|cuttysark: Maybe if he cannot count his cards he cannot count his points either. Nerves will do that to you|pg|| nt|hedyg: 3@s?|pg|| nt|hedyg: must do something now|pg|| nt|voldenuit: pass is very pessimistic by east u have 2 aces and 5@c and 4@s |pg|| mb|p|mb|p|mb|p|pc|s6|nt|hedyg: 2@s could be 0!|pg|| nt|hedyg: 3@s better|pg|| nt|jtr: Playing a near slam in a part-score?|pg|| nt|finch: It's consistent to bid 2@S now having passed 1NT; you've already made the decision|pg|| nt|hedyg: not once pd shows a good NT opening|pg|| pc|s9|nt|cuttysark: Another unique contract, I suspect|pg|| nt|hedyg: yes and the majors|pg|| nt|finch: The double of 2@D doesn't show extras, it just shows diamond shortage - you can't pass out 2@D|pg|| nt|voldenuit: in imp east hand is game forcing after 1Nt opening of his partner|pg|| pc|sT|pc|sA|pg|| pc|s5|pc|h5|pc|sQ|nt|hedyg: it surely shows a good hand once pd has passed|pg|| pc|sK|pg|| pc|d9|nt|hedyg: he wouldnt X with 15|pg|| pc|d5|pc|d4|pc|dQ|pg|| nt|jtr: Well, it is closer to a 2NT opening than a 1NT anyway|pg|| pc|s8|nt|cuttysark: Well, he would with xx in diamonds - nothing to say partner doesn't have a major or two and a few points|pg|| nt|finch: Oh yes, the same hand without the @DK is an easy double |pg|| nt|hedyg: for sure|pg|| pc|sJ|pc|h3|nt|finch: At matchpoints I'd expect a double on the same hand without one of the major suit kings as well|pg|| pc|c7|pg|| pc|d8|nt|hedyg: i wouldnt|pg|| pc|dK|pc|dA|pc|d6|pg|| pc|cQ|nt|cuttysark: He may as well go for 11 tricks - only vompeting with the other pairs in pastscore now - if there are any|pg|| nt|voldenuit: it's a great score for NS 90% I think |pg|| pc|cA|pc|c8|pc|c4|pg|| pc|s7|pc|s3|pc|h2|pc|c5|pg|| pc|s4|pc|h7|nt|hedyg: even like this still makes 11|pg|| nt|vugraph814: he claimed 10 of course, still a @c loser|pg|| nt|cuttysark: That should cheer up some of our spectators - it doesn't just happen at your table :)|pg|| pc|c2|pc|d7|pg|| pc|h4|pc|hT|pc|hK|pc|hA|pg|| pc|h8|pc|hJ|pc|hQ|pc|h6|pg|| pc|d2|pc|dJ|mc|8|pg|| qx|o13|st||md|3SAQJ2HA875DQ96C62,S95HQ43DAK3CAQJ84,ST73HT6D8742CKT93,SK864HKJ92DJT5C75|sv|b|nt|dougs: 3@S is invitational and shows a balanced hand as well inviting 3nt|pg|| nt|brolucius: It was easy for North to reject the game-try. Rather more difficult, it seemed, for South to only make a game try on that hand. Well done.|pg|| nt|kareno: As we used to say in the bad old days of 'Animal Acol,' an opening bid opposite an opening bid makes a partscore when the suits break well!!|pg|| mb|p|mb|p|nt|Walddk2: http://www.worldbridge.org/people/person.asp?qryid=3776 Jeff Meckstroth|pg|| nt|Walddk2: http://www.worldbridge.org/people/person.asp?qryid=3777 Eric Rodwell|pg|| nt|Vugraph7: R-M discussing the decision to pass 3@s - Meck :"you had a lot of primes" Rod: Kings aren't aces|pg|| nt|Walddk2: http://www.worldbridge.org/people/person.asp?qryid=4861 Cezary Balicki|pg|| mb|1D|mb|1N|nt|Walddk2: http://www.worldbridge.org/people/person.asp?qryid=4862 Adam Zmudzinski|pg|| mb|p|mb|2C|mb|p|nt|dougs: karen do yo think meckwell will play all 4 quarter in this final?|pg|| mb|2D|mb|p|mb|2N|mb|p|mb|3N|mb|p|mb|p|mb|p|pc|d8|nt|dougs: 1@D in 3rd set vul is 11-14 since 1nt would be 15-17|pg|| nt|kareno: My guess is yes, Doug. Paul Soloway's health isn't the best and I think they'll rest him when they can.|pg|| nt|brolucius: This is a borderline game and it seems that the lie of the cards is not favourable enough for a make. Perhaps he can work a miracle.|pg|| nt|dougs: They finished very last last night|pg|| nt|Vugraph7: Zmud asks about lead in "your suit" Meck: 1@d isn't really a suit, so this is just a normal lead, either 4th or high or 2nd high|pg|| pc|dJ|pc|d6|pc|d3|pg|| pc|c5|pc|c6|pc|cJ|pc|cK|pg|| nt|brolucius: South declines to cover in case declarer has @DA-K bare, but that was unlikely after North's choice of spotcard for the lead.|pg|| pc|d2|pc|d5|pc|d9|pc|dA|pg|| nt|ritong: he also wanted to encourage a @s shift|pg|| nt|ritong: disclosing @d AK with declarer|pg|| nt|Vugraph7: Z studying dummy|pg|| nt|kareno: South needs a shoehorn to force an entry into north's hand!|pg|| nt|brolucius: The spade game on board 9 has again gone one down on a club lead, in the Closed Room.|pg|| nt|Vugraph7: Yesterday, each time they finished, R-M asked me if the other room was done and I had to laugh, I can see it will be the same today :)|pg|| pc|cA|pc|c3|pc|c7|pc|c2|pg|| pc|cQ|pc|c9|pc|s4|nt|brolucius: Very good.|pg|| nt|kareno: I imagine the time monitor has gone away?|pg|| nt|Vugraph7: yes, probably to the other room|pg|| pc|h8|pg|| nt|Vugraph7: :)|pg|| pc|h3|pc|h6|pc|hJ|nt|dougs: Jeff plays very quickly...Eric is more studious, especially in the card play.|pg|| nt|Vugraph7: Meck had the low heart out, then stopped and now is studying things|pg|| nt|brolucius: West denies four hearts in the bidding, so South knows his partner has at least two.|pg|| pc|h5|pg|| nt|kareno: If he ducks two hearts, Jeff will be stripped of his diamond exit before being tucked in with the third heart.|pg|| pc|h2|pc|hA|pc|h4|pc|hT|pg|| nt|brolucius: Now he must take the ace and exit in diamonds. Yes, well defended.|pg|| nt|Vugraph7: He actually played the A instantly, but hid it from me|pg|| pc|dQ|pc|dK|nt|kareno: Now the diamond and then he'll have to pitch a quack of spades on the last heart, allowing his partner to win the ten.|pg|| pc|d4|pc|dT|pg|| nt|brolucius: Now Meckstroth must discard a middle spade to avoid having to give dummy the @SK.|pg|| nt|Vugraph7: Z shaking his head as he looks at the dummy|pg|| nt|Walddk2: He will do that I am sure. This is great bridge|pg|| nt|kareno: If declarer leads a spade now, Rodwell can play the ten.|pg|| nt|brolucius: Yes, it is brilliant to watch.|pg|| nt|Walddk2: More than 3,100 watching at this table|pg|| pc|hQ|nt|kareno: You are really privileged to watch these two great pairs compete, spectators.|pg|| pc|d7|nt|brolucius: Declarer has to calculate whether to overtake.|pg|| pc|h9|pc|h7|pg|| nt|kareno: Here is the node point. Duck and play for the spade onside or win and play for the ending.|pg|| nt|Vugraph7: Before he ducked, Z said "is it down 2 or down 1" - presumably if he guessed wrong|pg|| nt|ritong: if the endplay works, it works with a @s from hand as well|pg|| pc|s9|pc|sT|nt|kareno: Ten!|pg|| nt|Vugraph7: Meck claimed|pg|| mc|7|pg|| qx|c13|st||md|3SAQJ2HA875DQ96C62,S95HQ43DAK3CAQJ84,ST73HT6D8742CKT93,SK864HKJ92DJT5C75|sv|b|mb|p|mb|p|mb|1D!|mb|1N|nt|hedyg: @c lead will save a trick for NS|pg|| mb|p|mb|2C|mb|p|mb|2D|mb|p|nt|hedyg: oh! not in @s:)|pg|| nt|cuttysark: Hearts better - get the ruff|pg|| mb|2N|mb|p|mb|p|mb|p|pc|sT|nt|finch: NS bidding has rather propelled EW into a making game|pg|| pc|sK|nt|hedyg: making?|pg|| nt|hedyg: not anymore:)|pg|| pc|sA|nt|voldenuit: to beat 4@s south had to play ace and king of @h for the jack of @h of his part and @d for his ace |pg|| pc|s5|pg|| nt|finch: ...or a 500 save. Still I doubt there were many matchpoints available for -420|pg|| pc|c6|nt|cuttysark: I guess the defence is not trivial - some will make 4@S|pg|| nt|finch: Yes, we can see 4@S is beatable, but I bet it makes most of the time|pg|| pc|cQ|pc|cK|pc|c5|pg|| pc|s7|pc|s4|nt|jtr: I cant see many bidding it though|pg|| pc|sJ|nt|finch: Yes, left to their own devices EW will play a major suit partial|pg|| pc|s9|pg|| pc|c2|nt|voldenuit: a lot of pairs will play 2@h +2 I think |pg|| pc|cJ|pc|c3|pc|c7|pg|| pc|hQ|pc|h6|pc|h2|pc|h5|pg|| pc|h3|nt|xenya: i don't agree with S's 5@C |pg|| pc|hT|pc|hK|pc|h7|pg|| pc|h9|nt|hedyg: once W found the doublefit and with a stiff @c he loved his hand|pg|| pc|hA|pc|h4|nt|jtr: 4@c was the error i think-although tempting|pg|| pc|d7|pg|| pc|h8|pc|c4|pc|s3|pc|hJ|pg|| pc|dJ|nt|cuttysark: I think the club overcall is normal, and the negative dbl will get them to spades, surely?|pg|| nt|voldenuit: me too his hand is too balanced 6322 |pg|| pc|d9|pc|d3|pc|d2|pg|| pc|d5|pc|d6|pc|dK|pc|d4|pg|| pc|dA|pc|d8|pc|dT|pc|dQ|pg|| pc|cA|pc|c9|pc|s6|pc|s2|pg|| pc|c8|pc|cT|pc|s8|pc|sQ|pg|| pg|| qx|o14|st||md|4SA852HQ72DAKJ63C3,SQ63HK54DT74CT854,SJT974HA86D852CK7,SKHJT93DQ9CAQJ962|sv|o|nt|Vugraph7: Rod: "nice defense partner"|pg|| nt|brolucius: Well, it was more interesting than most '3NT-2's. If that is the correct plural.|pg|| mb|2C!|an|6+ clubs|mb|d|mb|3C|nt|brolucius: The most important move in the defence, which many would have got wrong, was to rise with the @HA on the second round.|pg|| nt|Walddk2: sure, one sec|pg|| mb|3S|mb|4C|mb|4S|mb|p|mb|p|mb|p|nt|Walddk2: Welcome to Barnet Shenkin from USA|pg|| nt|kareno: The nine of spades did not change anything. On the low one, Eric would surely have played the ten.|pg|| nt|barnets: afternoon all from wet florida|pg|| nt|kareno: Barnet :)|pg|| nt|ritong: hi barnet|pg|| nt|barnets: stormy weather|pg|| nt|kareno: Likely @h jack lead.|pg|| nt|Walddk2: That's a song|pg|| nt|ritong: hurricane?|pg|| nt|kareno: I love that song, Roland :)|pg|| nt|Vugraph7: Rod just told Bal it was his lead, apparently he thought his partner was on lead :)|pg|| pc|hJ|nt|Walddk2: But to say that we know it well is also the same as revealing our age I'm afraid|pg|| nt|brolucius: Most unlikely to be from K-J-10, but what can declarer do about it?|pg|| nt|kareno: I'm not afraid to reveal my age. I think it's still in the Encyclopedia anyway ;)|pg|| nt|Vugraph7: Actually, they play that J denies a higher, as Z told R|pg|| nt|Vugraph7: Both of these pairs are very good about disclosing everything to their opponents|pg|| nt|barnets: so we have a strong 4 handed team in strong contention int he spingold ----|pg|| nt|brolucius: Declarer can lose a trump trick to the 'safe hand' who cannot play a second heart but, of course, East still has the @CA.|pg|| nt|Walddk2: Not much Rod can do about this|pg|| nt|Vugraph7: Rod leaning back studying the dummy|pg|| nt|kareno: Yes, the non-club lead is fatal to the contract.|pg|| nt|barnets: anyone know when was the last time a four handed team actually won the spingold?|pg|| nt|Walddk2: B-Z are not known to present gifts|pg|| nt|barnets: my guess avery long time ago|pg|| nt|barnets: the specs say b_Z won 4 handed in 2001 |pg|| nt|Walddk2: I am getting lots of interesting lines that suggest that it makes. I do not believe any of them|pg|| nt|brolucius: Unlucky for North-South that East had an 'easy' heart lead to make. Somehow, they needed South to play the contract.|pg|| pc|h2|pc|h5|nt|brolucius: If anyone does tell you how to make it, Roland, copy me on their message... |pg|| nt|Vugraph7: Rod had a card out then put it back and now thinking again|pg|| pc|hA|pg|| pc|sJ|pc|sK|pc|sA|nt|Walddk2: I think they got cold feet. There really is no way he can make it|pg|| pc|s3|pg|| nt|brolucius: Usually Barnet can spot a winning line but he is as quiet as the grave at the moment.|pg|| pc|s2|pc|sQ|pc|s7|pc|c2|pg|| pc|c8|nt|Walddk2: Now comes the club switch and a heart through|pg|| nt|barnets: cant see it 4 diamonds west makes 2 trump tricks|pg|| nt|Vugraph7: Bathroom break|pg|| nt|barnets: even thought the heart goes|pg|| nt|barnets: declarer could not stop east getting in to play the HJ thru|pg|| nt|kareno: The heart opening lead was natural from east and will probably be duplicated in the closed room.|pg|| nt|brolucius: West would ruff the fourth round of diamonds low.|pg|| nt|kareno: And east would not cover the jack of spades from a doubleton holding.|pg|| nt|barnets: if west had clubsingleton -- could make with 4 diamonds pitching a club the only lose 2 trumps and heart|pg|| nt|brolucius: I told my wife I would watch only one session of this and be by her side thereafter.... but it sure it tempting to watch more.|pg|| nt|Walddk2: Notice how in high level bridge how quickly the resolution/claim happens, and how the experts treat each other in that regard|pg|| nt|barnets: if north had club sing that shud rread|pg|| nt|kareno: That's what happens when you have a wife, David :)|pg|| nt|Walddk2: Rod conceded 1 down very quickly after the C switch I am sure|pg|| nt|barnets: so now i am told a 4 handed team won 20 years ago in 1987|pg|| nt|brolucius: Married for 32 years.... he said proudly.|pg|| nt|dougs: The quality of shortsmanship is very high in top level bridge.|pg|| nt|dougs: sportmanship|pg|| nt|kareno: And luckily - you've obviously found a keeper :)|pg|| nt|Walddk2: Yes, a housekeeper. Hope she doesn't leave and keep the house|pg|| nt|barnets: who knows who won in 2001 was it this same 4?|pg|| nt|kareno: That was a Zsa Zsa Gabor line, Roland :)|pg|| nt|Walddk2: I am not THAT old|pg|| nt|brolucius: Housekeepers can be found on Ebay. A good wife is much more difficult to find... but I was lucky.|pg|| nt|kareno: She said she was a good housekeeper - married X times and kept the house each time.|pg|| nt|ritong: :)|pg|| nt|kareno: And Roland - as I've said - I AM that old!! And hope to be doing commentary for another twenty years or so :)|pg|| nt|Walddk2: Also, the "cards speak"; therefore, when it is "obvious", the opponents will just concede, and just tell declarer what they made: no one looks at the cards, however, they might ...|pg|| nt|Walddk2: ask the shapes, as everyone knows the position of the high cards|pg|| mc|9|pg|| qx|c14|st||md|4SA852HQ72DAKJ63C3,SQ63HK54DT74CT854,SJT974HA86D852CK7,SKHJT93DQ9CAQJ962|sv|o|nt|hedyg: most might bid 2@H|pg|| nt|cuttysark: Without the overcall, maybe|pg|| mb|1C|mb|1D|mb|p|mb|1S|mb|2C|mb|3S|mb|p|mb|4S|mb|p|mb|p|mb|p|nt|voldenuit: 11 tricks in 4@h north may have tried the contract of 3Nt |pg|| pc|hJ|pc|h2|pc|h5|pc|h6|pg|| pc|hT|pc|hQ|pc|hK|pc|hA|pg|| pc|sJ|pc|sK|pc|sA|pc|s3|pg|| pc|s2|pc|sQ|nt|cuttysark: That is a mtach point bid that deseerves its fate on a diamond lead|pg|| pc|s4|pc|c6|pg|| pc|c5|pc|cK|pc|cA|nt|voldenuit: south could play @s 4/2 now when he sees @h 4/1 |pg|| pc|c3|pg|| pc|h9|pc|h7|pc|h4|pc|h8|pg|| pc|h3|mc|9|pg|| qx|o15|st||md|1SQ976HJT85DATCT75,SKJ5HAK7D865432CJ,SAT842HQ32DJ9CA42,S3H964DKQ7CKQ9863|sv|n|nt|barnets: Apparently the won either the spingold or the vandrebilt 4 handed in 2001 -- B -Z Gromov and Petrunin|pg|| nt|brolucius: Anyone logging on to BBO now will say.... "Oh, no, the score had gone wrong again. Typical!" Who would believe 6-0 after so many boards?|pg|| nt|Walddk2: Walddk6 would|pg|| mb|p|mb|1D|nt|barnets: the vanderbit is confirmed|pg|| mb|1S|nt|brolucius: Or perhaps that just represents the number of cigarettes smoked by each team.|pg|| mb|2C|nt|kareno: Of course, quite a few boards are yet to be played in the closed room.|pg|| mb|3H!|nt|dougs: close between 3@S preemptive and 3@H 8-9 raise|pg|| mb|p|mb|3S|mb|3N!|mb|p|mb|4D|mb|p|mb|p|mb|p|nt|barnets: A spec has menioned curiously that in all the vugraph matches he has watched he has never ever seen Meckwell not score 1 imp in a quarter|pg|| nt|brolucius: Not at all easy for E-W after that barrage. If 3NT meant 'you choose the minor' that was a great piece of system.|pg|| nt|kareno: I have a report that on board 12 (where Meckwell stayed out of the poor spade game) the Russians are in 3NT doubled.|pg|| pc|h2|nt|Walddk2: And will go for 500 most likely|pg|| nt|kareno: 3NT would have been expensive.|pg|| nt|kareno: So a pickup for Nickell.|pg|| nt|Walddk2: That would be 7 IMPs to Nickell, and we have a new lerader|pg|| pc|h4|pc|h8|pc|hK|pg|| nt|barnets: so that fixes the specs problem :)|pg|| pc|d5|pc|d9|pc|dK|pc|dA|pg|| nt|kareno: The heart lead deprives west of an opportunity to set up a spade trick.|pg|| nt|Walddk2: It's quite normal for Meckwell to play all 4 sets in a final|pg|| nt|brolucius: South must persist with partner's chosen defence.|pg|| nt|barnets: declare has a achance fro down 1 in 3N x now would be flat board|pg|| nt|barnets: the score is morelike baseball than bridge|pg|| nt|brolucius: Tennis!|pg|| nt|Walddk2: Football (soccer)|pg|| pc|sQ|nt|Walddk2: I believe Russia could beat USA 6-0 :)|pg|| nt|brolucius: "First set to Gromov!"|pg|| pc|sK|pc|sA|pc|s3|pg|| nt|barnets: thats only if man u are playing|pg|| nt|kareno: I said it to Roland privately but I'll repeat it: Meckwell aren't kids any more but they still have plenty of energy for long matches.|pg|| nt|brolucius: Well, who would believe it? Meckstroth is human.|pg|| nt|Walddk2: It could also be the Ashes scoreline if they played 6 tests |pg|| nt|brolucius: With a vulnerable overcall opposite, it was unlikely that a spade switch would cost. But it has done.|pg|| pc|h3|pc|h6|pc|hT|pc|hA|pg|| pc|sJ|pc|s4|pc|h9|pc|s6|pg|| pc|cJ|nt|kareno: Yes.. undone the fine opening lead by Rodwell.. the deuce, not a higher one.|pg|| nt|Walddk2: 3NTX on 12 only 1 down, so a flat board it is|pg|| nt|Walddk2: Still 0-6|pg|| pc|cA|pc|c3|pc|c5|pg|| mc|10|pg|| qx|c15|st||md|1SQ976HJT85DATCT75,SKJ5HAK7D865432CJ,SAT842HQ32DJ9CA42,S3H964DKQ7CKQ9863|sv|n|mb|p|mb|1D|mb|1S|mb|2C|mb|2S|mb|p|mb|p|mb|2N|mb|3S|mb|3N|nt|hedyg: nice pass by S over 2@h|pg|| mb|p|nt|finch: 2NT was a little optimistic - unless 2@H showed a 2-suiter|pg|| nt|vugraph814: all natural|pg|| nt|jtr: trump lead mandatory here|pg|| mb|4C|mb|p|mb|p|mb|p|pc|hJ|pc|hA|nt|jtr: low @s better|pg|| pc|h2|nt|finch: I agree this would usually be a trump lead - but in fact forcing it feels like good defence|pg|| pc|h4|pg|| pc|d2|pc|d9|pc|dK|pc|dA|pg|| pc|h5|pc|hK|pc|h3|pc|h6|pg|| pc|cJ|pc|c4|pc|c3|pc|c5|pg|| pc|d3|pc|dJ|pc|dQ|pc|dT|pg|| pc|cK|pc|c7|nt|hedyg: needs to try K@h|pg|| pc|d4|nt|hedyg: now @ds|pg|| nt|finch: North might have done better to duck the heart off|pg|| pc|cA|pg|| pc|sA|pc|s3|pc|s6|pc|s5|pg|| nt|hedyg: ty all! see you later:)|pg|| nt|cuttysark: Sometimes when you sacrifice a trick it comes back - East would probably rise with @HK but that might not be enough|pg|| nt|andersk: Board 46, might be same board as a board in Mixed Pairs, they are workeing on it now to find out if it is same board!|pg|| nt|andersk: Ivar, maybe you can give us an update when they have investigated:)|pg|| nt|vugraph814: I wasn't aware there was anything wrong, Mixed teams is in the other end of the venue|pg|| nt|xenya: thanks everyone -- bye for now |pg|| pc|hQ|pc|h9|pc|h8|pc|h7|pg|| pc|c2|mc|9|pg|| qx|o16|st||md|2SJTHQJ5DAKT954CT6,S8HKT832D862CKJ42,SA542HA9DQJ7CQ985,SKQ9763H764D3CA73|sv|e|nt|brolucius: It was great bidding by the Poles, to get to 4@D. And almost a great defence from M/R.|pg|| nt|Walddk2: This is the last board of the first quarter. Many thanks to Jan Martel, our brilliant operator in Nashville. Flawless operating, and much useful information from the table|pg|| nt|Vugraph7: Thank you.|pg|| nt|brolucius: Yes, top class, Jan.|pg|| nt|Walddk2: Also thanks to my excellent fellow commentators: Karen Allison, David Bird, Doug Simson, Barnet Shenkin and Henri Schweitzer|pg|| mb|p|mb|1D|mb|2S|mb|3C|mb|p|mb|3N|mb|p|mb|p|mb|p|nt|kareno: And to you, Roland, for organizing these vugraphs and for your excellent participation as well!|pg|| nt|dougs: 3@C shows invite + in @D..transfer in effect|pg|| nt|Walddk2: Finally thanks to the ACBL, Rick Beye and Kevin Perkins for bringing this prestigious event to BBO vugraph. Much appreciated by all our dedicated fans|pg|| pc|s7|pc|sT|pc|s8|nt|dougs: Eric has an easy 3nt with 2 Aces and a @D fit|pg|| pc|s2|pg|| pc|hQ|nt|barnets: The sK lead would have given declarer more problems|pg|| pc|h2|pc|h9|pc|h7|pg|| nt|brolucius: It has been an intriguing 'warm-up' set to get the final going. Who knows what will happen in the next three sets. There's only one way to find out!|pg|| nt|barnets: with only 8 top tricks|pg|| nt|barnets: and would have gone much slower|pg|| nt|kareno: But with the heart in the pocket, all would be well.|pg|| nt|Walddk2: Thanks everyone. We will be back about 15 minutes after play finishes at the other table|pg|| nt|barnets: yes finally|pg|| nt|kareno: Yes, specs, don't give up your seats!!|pg|| nt|brolucius: Thanks for watching!|pg|| nt|Walddk2: See you then, bye for now|pg|| nt|kareno: Bye for now.|pg|| nt|barnets: later|pg|| nt|dougs: If there are any more questions, I will do my best.|pg|| nt|bigtrain: morning/afternoon/evening all|pg|| mc|10|pg|| qx|c16|st||md|2SJTHQJ5DAKT954CT6,S8HKT832D862CKJ42,SA542HA9DQJ7CQ985,SKQ9763H764D3CA73|sv|e|mb|p|mb|1N|mb|p|mb|3N|mb|p|mb|p|mb|p|pc|sQ|nt|voldenuit: which range is nt ? 14/16|pg|| pc|sT|pc|s8|pc|s2|pg|| nt|vugraph814: I'm not sure, no one has asked|pg|| nt|finch: EW are on the same wavelength - many people play 4NT as quantitative here|pg|| nt|finch: (how would you bid with invitational slam values and 4 spades?)|pg|| pc|sK|pc|sJ|pc|d2|pc|sA|pg|| pc|dQ|nt|cuttysark: Agree - I have to make some kind of fit-showing cuebid before using Blackwood|pg|| pc|d3|pc|d4|pc|d6|pg|| pc|dJ|pc|c7|pc|d5|pc|d8|pg|| pc|d7|pc|s3|pc|dA|pc|c2|pg|| pc|dK|pc|h3|pc|s5|pc|h4|pg|| pc|dT|pc|c4|pc|c5|pc|c3|pg|| pc|d9|nt|finch: As it is, at pairs 6NT is better (and making)|pg|| mc|9|pg|| tenace-0.18/examples/7nt-south.lin000066400000000000000000000005411505733770300171050ustar00rootroot00000000000000pn|Süd,West,Nord,Ost|st||md|3STJKAH2JKDTQC29QK,S89QH9TQD789JC45J,S2H345AD2345KAC3A,|rh||ah|Board 1|sv|o|mb|p|mb|p|mb|7N|mb|p|mb|p|mb|p|pg||pc|CT|pc|C3|pc|C6|pc|C9|pg||pc|C2|pc|C5|pc|CA|pc|C7|pg||pc|HA|pc|H6|pc|H2|pc|H9|pg||pc|H3|pc|H7|pc|HK|pc|HT|pg||pc|SA|pc|S8|pc|S2|pc|S3|pg||pc|SK|pc|S9|pc|H4|pc|S4|pg||pc|CK|pc|CJ|pc|H5|pc|CT|pg||pc|CQ|pc|SQ|pg|| tenace-0.18/examples/Makefile.am000066400000000000000000000004371505733770300165710ustar00rootroot00000000000000examplesdir = $(docdir)/examples examples_DATA = README.examples \ 01-26-08-3.lin \ 2007_Spingold_Final.First_Quarter.lin \ 7nt-south.lin \ everybody-makes-3nt.lin \ everybody-makes-3s.lin \ everybody-makes-7nt.lin \ squeeze.lin \ triple-coup.lin EXTRA_DIST = $(examples_DATA) tenace-0.18/examples/README.examples000066400000000000000000000010521505733770300172240ustar00rootroot00000000000000Notes on the tenace examples ============================ Notes on the "Everybody makes" deals can be found at Thomas Andrew's site and in an article by Richard Pavlicek: * http://bridge.thomasoandrews.com/deals/everybody/ * http://www.rpbridge.net/7a59.htm#10 triple-coup.lin is an interesting deal where South can make 7H on a Spade lead. * http://james.fabpedigree.com/gslamsol.htm 7nt-south.lin is a hand where South makes 7NT, but North does not, and no hand has a void. (Otherwise, the example is trivial to contruct.) By Christian Löwenstein. tenace-0.18/examples/everybody-makes-3nt.lin000066400000000000000000000002211505733770300210400ustar00rootroot00000000000000pn|Süd,West,Nord,Ost|st||md|3S2345678AH9TQDCJK,SHJKD9TQC2345678A,S9TQH2345678ADJKC,|rh||ah|Board 1|sv|o|mb|p|mb|p|mb|3N|mb|p|mb|p|mb|p|pg||pg|| tenace-0.18/examples/everybody-makes-3s.lin000066400000000000000000000002211505733770300206610ustar00rootroot00000000000000pn|Süd,West,Nord,Ost|st||md|3S234567TJH23456DC,SHD56789TJC345678,S9H9TJD234QAC2QKA,|rh||ah|Board 1|sv|o|mb|p|mb|p|mb|3S|mb|p|mb|p|mb|p|pg||pg|| tenace-0.18/examples/everybody-makes-7nt.lin000066400000000000000000000002071505733770300210500ustar00rootroot00000000000000pn|Süd,West,Nord,Ost|st||md|3SHD234567C2345678,SHD89TJQKAC9TJQKA,S89TJQKAH9TJQKADC,|rh||ah|Board 1|sv|o|mb|7N|mb|p|mb|p|mb|p|pg||pg|| tenace-0.18/examples/squeeze.lin000066400000000000000000000002251505733770300167150ustar00rootroot00000000000000pn|South,West,North,East|st||md|3S37QH3JD45JC78QKA,S8JKH68QKD236TC69,S26AH457TAD7QC35J,|rh||ah|Board 1|sv|o|mb|1H|mb|p|mb|3N|mb|p|mb|p|mb|p|pg||pg|| tenace-0.18/examples/triple-coup.lin000066400000000000000000000006701505733770300175030ustar00rootroot00000000000000pn|Süd,West,Nord,Ost|st||md|3SH569JKAD345C9JQA,S89TJQH4D9TJQC2TK,S34567KAH23D2KAC3,|rh||ah|Board 1|sv|o|pg||pc|SQ|pc|SA|pc|S2|pc|D3|pg||pc|SK|pc|C4|pc|H5|pc|S8|pg||pc|CA|pc|C2|pc|C3|pc|C5|pg||pc|CQ|pc|CT|pc|S3|pc|C6|pg||pc|CJ|pc|CK|pc|H2|pc|C7|pg||pc|H3|pc|H7|pc|H9|pc|H4|pg||pc|C9|pc|D9|pc|S4|pc|C8|pg||pc|D4|pc|DT|pc|DA|pc|D6|pg||pc|S5|pc|D7|pc|H6|pc|S9|pg||pc|D5|pc|DJ|pc|DK|pc|D8|pg||pc|D2|pc|C6|pc|CJ|pc|CT|pg||pc|C3|pc|C7|pc|CA|pg|| tenace-0.18/handdisplay/000077500000000000000000000000001505733770300152135ustar00rootroot00000000000000tenace-0.18/handdisplay/Makefile.am000066400000000000000000000006351505733770300172530ustar00rootroot00000000000000CC = @CC@ CFLAGS += @PACKAGE_CFLAGS@ LDFLAGS += @PACKAGE_LIBS@ EXTRA_DIST = hand_display.c hand_display.h int_int_marshal.def all: hand_display.o hand_display.o: hand_display.c hand_display.h int_int_marshal.h $(CC) $(CPPFLAGS) $(CFLAGS) -I. -c -o $@ $< int_int_marshal.h: int_int_marshal.def glib-genmarshal --header $< > $@ glib-genmarshal --body $< >> $@ clean-local: rm -f *.o tags int_int_marshal.h tenace-0.18/handdisplay/hand_display.c000066400000000000000000000761521505733770300200310ustar00rootroot00000000000000/* * hand display - bridge hand widget for GTK+ * Copyright (C) 2007-2013 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include "hand_display.h" #include "int_int_marshal.h" /* static data */ static int render_init = 0, card_width = 100, card_height = 0; static gchar *svg_filename = NULL; static GdkPixbuf *card_pixbuf[52]; static cairo_surface_t *grey_surface = NULL; static GtkWidget *drag_win = NULL; /* current drag icon */ static GtkTargetEntry target_entry[1] = { { "card", 0, 0 } }; static GtkTargetList *target_list = NULL; static char *suit_str[] = {"♣", "♦", "♥", "â™ "}; static char *rank_str[] = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}; static double suit_color[4][3] = { { HAND_DISPLAY_CLUBS_FONT }, { HAND_DISPLAY_DIAMONDS_FONT }, { HAND_DISPLAY_HEARTS_FONT }, { HAND_DISPLAY_SPADES_FONT }, }; /* internal functions */ static int which_card (HandDisplay *handdisp, int x, int y) { /* find rightmost (= topmost) card at cursor position */ int c; int max_x = -1; int max = -1; for (c = 0; c < (handdisp->mode == HAND_DISPLAY_MODE_HAND_X ? 56 : 52); c++) { if ((c >= 52 /* HAND_X */ || handdisp->cards[c] & ~HAND_DISPLAY_INVISIBLE_CARD /* card visible */) && x >= handdisp->l[c] && x <= handdisp->r[c] && y >= handdisp->t[c] && y <= handdisp->b[c]) { if (handdisp->r[c] > max_x) { max = c; max_x = handdisp->r[c]; } } } return max; } static char * overtricks (int i) { static char buf[4]; if (i == 0) snprintf(buf, 3, "="); else snprintf(buf, 3, "%+d", i); return buf; } static void render_card_init (char *card_fname) { int i; if (render_init) { for (i = 0; i < 52; i++) g_object_unref (card_pixbuf[i]); cairo_surface_destroy (grey_surface); render_init = 0; } /* gdk_pixbuf_new_from_file doesn't seem to support .svgz (while * librsvg does), so decompress it here. Code from aisleriot * src/lib/ar-svg.c */ GFile *cf = g_file_new_for_path (card_fname); GFileInfo *info; GError *error = NULL; if (!(info = g_file_query_info (cf, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error))) { printf ("%s: %s\n", card_fname, error->message); g_object_unref (cf); g_error_free (error); return; } const char *type = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE); char *gz_type = g_content_type_from_mime_type ("application/x-gzip"); gboolean is_gzip = (type != NULL && g_content_type_is_a (type, gz_type)); g_free (gz_type); g_object_unref (info); GInputStream *stream; if (!(stream = G_INPUT_STREAM (g_file_read (cf, NULL, &error)))) { printf ("%s: %s\n", card_fname, error->message); g_object_unref (cf); g_error_free (error); return; } g_object_unref (cf); if (is_gzip) { GZlibDecompressor *decompressor; GInputStream *converter_stream; decompressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP); converter_stream = g_converter_input_stream_new (stream, G_CONVERTER (decompressor)); g_object_unref (stream); stream = converter_stream; } /* file contains cards in 13 columns (A/2..10/J/Q/K) and 5 rows (C/D/H/S/Jokers) */ /* actual card height is computed from resulting actual size */ GdkPixbuf *pb = gdk_pixbuf_new_from_stream_at_scale (stream, card_width * 13, -1, TRUE, NULL, &error); g_object_unref (stream); if (!pb) { printf ("%s: %s.\n", card_fname, error->message); g_error_free (error); return; } int buf_width = gdk_pixbuf_get_width (pb); int buf_height = gdk_pixbuf_get_height (pb); card_width = ceil (gdk_pixbuf_get_width (pb) / 13.0); card_height = ceil (gdk_pixbuf_get_height (pb) / 5.0); for (i = 0; i < 52; i++) { card_pixbuf[i] = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, card_width, card_height); if (!card_pixbuf[i]) { printf ("%s: rendering card_pixbuf failed\n", card_fname); return; } int col = (i + 1) % 13; int row = i / 13; gdk_pixbuf_copy_area (pb, buf_width * col / 13.0, buf_height * row / 5.0, //gdk_pixbuf_copy_area (pb, card_width * col, card_height * row, card_width, card_height, card_pixbuf[i], 0, 0); } g_object_unref (pb); /* construct a alpha channel in card shape for greying out cards */ grey_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, card_width, card_height); cairo_t *ct = cairo_create (grey_surface); gdk_cairo_set_source_pixbuf (ct, card_pixbuf[0], 0, 0); cairo_paint_with_alpha (ct, 0.3); cairo_destroy (ct); render_init = 1; } static void render_card (cairo_t *cr, int x, int y, int c, int color) { if (!render_init) return; assert (0 <= c && c < 52); gdk_cairo_set_source_pixbuf (cr, card_pixbuf[c], x, y); cairo_paint (cr); if (color == HAND_DISPLAY_OLD_CARD) { /* grey out old card */ cairo_set_source_rgb (cr, HAND_DISPLAY_GREY_FONT); cairo_mask_surface (cr, grey_surface, x, y); } return; } static void draw (GtkWidget *hand, cairo_t *cr) { int x, y; HandDisplay *handdisp = HAND_DISPLAY(hand); cairo_text_extents_t extents; cairo_font_extents_t fextents; GtkAllocation allocation; gtk_widget_get_allocation (hand, &allocation); cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); /* "card" mode for drap&drop icon */ if (handdisp->mode == HAND_DISPLAY_MODE_CARD) { if (handdisp->style == HAND_DISPLAY_STYLE_CARDS) { if (card_width != handdisp->want_width) { /* adjust window */ handdisp->want_width = card_width; gdk_window_resize (gtk_widget_get_parent_window (hand), card_width, card_height); /* shaped drag icon * credits to Mirco "MacSlow" Mueller * http://macslow.thepimp.net/?p=26 */ GdkBitmap *pShapeBitmap = (GdkBitmap*) gdk_pixmap_new (NULL, card_width, card_height, 1); assert (pShapeBitmap); cairo_t *pCairoContext = gdk_cairo_create (pShapeBitmap); assert (cairo_status (pCairoContext) == CAIRO_STATUS_SUCCESS); render_card (pCairoContext, 0, 0, handdisp->table_card[0], HAND_DISPLAY_CARD); cairo_destroy (pCairoContext); gdk_window_shape_combine_mask (gtk_widget_get_parent_window (hand), pShapeBitmap, 0, 0); g_object_unref ((gpointer) pShapeBitmap); } render_card (cr, 0, 0, handdisp->table_card[0], HAND_DISPLAY_CARD); return; } char cs[6]; int c = handdisp->table_card[0]; int suit = c / 13; int rank = c % 13; snprintf (cs, 6, "%s%s", suit_str[suit], rank_str[rank]); cairo_set_font_size (cr, 20); cairo_text_extents (cr, cs, &extents); #define XPAD 4 #define YPAD 2 int w = extents.width + 2 * XPAD + 5; int h = extents.height + 2 * YPAD; cairo_set_source_rgb (cr, HAND_DISPLAY_FOCUS_BG); cairo_rectangle (cr, 1, 1, w, h); cairo_fill (cr); cairo_set_source_rgb (cr, HAND_DISPLAY_FONT); cairo_rectangle (cr, 1, 1, w, h); cairo_stroke (cr); cairo_move_to (cr, XPAD - extents.x_bearing + 1, YPAD - extents.y_bearing + 2); cairo_set_source_rgb (cr, suit_color[suit][0], suit_color[suit][1], suit_color[suit][2]); cairo_show_text (cr, suit_str[suit]); cairo_set_source_rgb (cr, HAND_DISPLAY_FONT); cairo_show_text (cr, rank_str[rank]); if (w + 2 != handdisp->want_width) { /* adjust window */ handdisp->want_width = w + 2; gdk_window_resize (gtk_widget_get_parent_window (hand), w + 2, h + 2); } return; } cairo_set_source_rgb (cr, HAND_DISPLAY_TABLE_BG); cairo_rectangle (cr, 0, 0, allocation.width, allocation.height); cairo_fill (cr); /* "table" mode for displaying the already played cards in the middle of the screen */ if (handdisp->mode == HAND_DISPLAY_MODE_TABLE && handdisp->style == HAND_DISPLAY_STYLE_CARDS) { int i; for (i = 0; i < 4; i++) { switch (handdisp->table_seat[i]) { case 1: x = allocation.width / 2 - card_width + 5; /*W*/ y = (allocation.height - card_height) / 2 + 5; break; case 2: x = (allocation.width - card_width) / 2 - 2; /*N*/ y = MAX (allocation.height / 2 - card_height + 10, 0); break; case 3: x = allocation.width / 2 - 5; /*E*/ y = (allocation.height - card_height) / 2 - 5; break; case 4: x = (allocation.width - card_width) / 2 + 2; /*S*/ y = MIN (allocation.height / 2 - 10, allocation.height - card_height); break; default: return; /* stop here */ } render_card (cr, x, y, handdisp->table_card[i], HAND_DISPLAY_CARD); } return; } if (handdisp->mode == HAND_DISPLAY_MODE_TABLE) { /* text */ cairo_set_font_size (cr, 20); int i; for (i = 0; i < 4; i++) { char cs[6]; if (!handdisp->table_seat[i]) return; int c = handdisp->table_card[i]; int suit = c / 13; int rank = c % 13; snprintf (cs, 6, "%s%s", suit_str[suit], rank_str[rank]); cairo_text_extents (cr, cs, &extents); #define XOFF 38 #define YOFF 23 #define WIDTH 52 #define HEIGHT 28 #define RAD 5 switch (handdisp->table_seat[i]) { /* middle point */ case 1: x = allocation.width / 2 - XOFF; /*W*/ y = allocation.height / 2; break; case 2: x = allocation.width / 2; /*N*/ y = allocation.height / 2 - YOFF; break; case 3: x = allocation.width / 2 + XOFF; /*E*/ y = allocation.height / 2; break; case 4: x = allocation.width / 2; /*S*/ y = allocation.height / 2 + YOFF; break; default: return; /* stop here */ } cairo_new_path (cr); cairo_arc_negative (cr, x-WIDTH/2+RAD, y+HEIGHT/2 - RAD, RAD, M_PI, M_PI_2); cairo_arc_negative (cr, x+WIDTH/2-RAD, y+HEIGHT/2 - RAD, RAD, M_PI_2, 0.0); cairo_arc_negative (cr, x+WIDTH/2-RAD, y-HEIGHT/2 + RAD, RAD, 0.0, -M_PI_2); cairo_arc_negative (cr, x-WIDTH/2+RAD, y-HEIGHT/2 + RAD, RAD, -M_PI_2, M_PI); cairo_close_path (cr); cairo_set_source_rgb (cr, HAND_DISPLAY_FOCUS_BG); cairo_fill_preserve (cr); cairo_set_source_rgb (cr, HAND_DISPLAY_FONT); cairo_stroke (cr); cairo_move_to (cr, x - extents.width / 2 - 3, y + extents.height / 2 - 3); cairo_set_source_rgb (cr, suit_color[suit][0], suit_color[suit][1], suit_color[suit][2]); cairo_show_text (cr, suit_str[suit]); cairo_set_source_rgb (cr, HAND_DISPLAY_FONT); cairo_show_text (cr, rank_str[rank]); } return; } /* normal hands display */ /* compute cached best card score for this hand */ if (handdisp->best_card_score == HAND_DISPLAY_NO_SCORE) { int c; handdisp->best_card_score = handdisp->card_score_neg ? 14 : -14; for (c = 0; c < 52; c++) { if (handdisp->card_score_neg ? (handdisp->card_score[c] < handdisp->best_card_score) : (handdisp->card_score[c] > handdisp->best_card_score)) handdisp->best_card_score = handdisp->card_score[c]; } } /* "cards" style */ if (handdisp->style == HAND_DISPLAY_STYLE_CARDS && handdisp->mode != HAND_DISPLAY_MODE_HAND_X) { /* we do not support MODE_X here, yet we still allow setting * STYLE_CARDS there to have the right drag icon */ y = MAX (allocation.height - card_height - 5, 15); int n = 0; int suit; for (suit = 0; suit < 4; suit++) { int c; for (c = 13 * (handdisp->suits[suit] + 1) - 1; c >= 13 * handdisp->suits[suit]; c--) { if (handdisp->cards[c]) { x = floor (n++ * (allocation.width - card_width) / 12.0); int sc = handdisp->card_score[c]; int yy = c == handdisp->cur_focus ? y - 15 : (sc != HAND_DISPLAY_NO_SCORE && handdisp->best_card_score == sc ? y - 5 : y); yy = MAX (yy, 0); handdisp->l[c] = x; handdisp->r[c] = x + card_width; handdisp->t[c] = y - 15; handdisp->b[c] = y + card_height; if (handdisp->cards[c] & HAND_DISPLAY_INVISIBLE_CARD) continue; render_card (cr, x, yy, c, handdisp->cards[c]); if (handdisp->cards[c] == HAND_DISPLAY_HILIGHT_CARD) { /* draw triangular arrow */ cairo_set_source_rgb (cr, HAND_DISPLAY_HILIGHT_FONT); cairo_move_to (cr, x + 3 + (allocation.width - card_width - 10) / 24.0, yy); cairo_rel_line_to (cr, -5, -5); cairo_rel_line_to (cr, 10, 0); cairo_fill (cr); } /* show card score */ if (handdisp->card_score[c] == HAND_DISPLAY_NO_SCORE) continue; char *buf = overtricks (handdisp->card_score[c]); static int text_h = 0; if (!text_h) { cairo_font_extents (cr, &fextents); text_h = fextents.ascent; } cairo_text_extents (cr, buf, &extents); cairo_move_to (cr, x + 1 + text_h, yy + 30 + extents.width); cairo_set_source_rgb (cr, HAND_DISPLAY_DD_FONT); cairo_save (cr); cairo_rotate (cr, -G_PI_2); cairo_show_text (cr, buf); cairo_restore (cr); } } } return; } /* "text" style */ /* draw suit symbols */ cairo_set_font_size (cr, 20); int suit_width = 0; int suit; for (suit = 0; suit < 4; suit++) { x = 0; y = floor ((double) allocation.height * (3.8 - suit) / 4.0); cairo_move_to (cr, x, y); cairo_text_extents (cr, suit_str[suit], &extents); if (extents.x_advance > suit_width) suit_width = extents.x_advance; cairo_set_source_rgb (cr, suit_color[suit][0], suit_color[suit][1], suit_color[suit][2]); cairo_show_text (cr, suit_str[suit]); } /* draw cards */ for (suit = 0; suit < 4; suit++) { x = 4 + suit_width; y = floor ((double) allocation.height * (3.8 - suit) / 4.0); cairo_move_to (cr, x, y); int c; for (c = 13 * suit + 12; c >= 13 * suit; c--) { if (handdisp->cards[c]) { cairo_text_extents (cr, rank_str[c % 13], &extents); handdisp->l[c] = x + extents.x_bearing; handdisp->r[c] = x + extents.x_bearing + extents.width; handdisp->t[c] = y + extents.y_bearing; handdisp->b[c] = y + extents.y_bearing + extents.height; if (!(handdisp->cards[c] & HAND_DISPLAY_INVISIBLE_CARD)) { if (c == handdisp->cur_focus) { cairo_set_source_rgb (cr, HAND_DISPLAY_FOCUS_BG); cairo_rectangle (cr, handdisp->l[c] - 1, handdisp->t[c] - 1, extents.width + 2, extents.height + 2); cairo_fill (cr); } if (handdisp->card_score[c] == HAND_DISPLAY_NO_SCORE) { if (handdisp->cards[c] == HAND_DISPLAY_CARD) cairo_set_source_rgb (cr, HAND_DISPLAY_FONT); else if (handdisp->cards[c] == HAND_DISPLAY_GREY_CARD) cairo_set_source_rgb (cr, HAND_DISPLAY_GREY_FONT); else if (handdisp->cards[c] == HAND_DISPLAY_OLD_CARD) cairo_set_source_rgb (cr, HAND_DISPLAY_OLD_FONT); else if (handdisp->cards[c] == HAND_DISPLAY_HILIGHT_CARD) cairo_set_source_rgb (cr, HAND_DISPLAY_HILIGHT_FONT); } else { /* invert colors if the score is for the opps */ if (handdisp->card_score_neg ^ (handdisp->card_score[c] >= 0)) if (handdisp->best_card_score == handdisp->card_score[c]) cairo_set_source_rgb (cr, HAND_DISPLAY_BEST_POS_FONT); else cairo_set_source_rgb (cr, HAND_DISPLAY_POS_FONT); else if (handdisp->best_card_score == handdisp->card_score[c]) cairo_set_source_rgb (cr, HAND_DISPLAY_BEST_NEG_FONT); else cairo_set_source_rgb (cr, HAND_DISPLAY_NEG_FONT); } cairo_move_to (cr, x, y); cairo_show_text (cr, rank_str[c % 13]); } x += extents.x_advance; y += extents.y_advance; } else { handdisp->l[c] = handdisp->r[c] = handdisp->t[c] = handdisp->b[c] = 0; } } /* MODE_X */ if (handdisp->mode == HAND_DISPLAY_MODE_HAND_X) { c = 52 + suit; x += 3; cairo_text_extents (cr, "x", &extents); handdisp->l[c] = x + extents.x_bearing; handdisp->r[c] = x + extents.x_bearing + extents.width; handdisp->t[c] = y + extents.y_bearing; handdisp->b[c] = y + extents.y_bearing + extents.height; if (c == handdisp->cur_focus) { cairo_set_source_rgb (cr, HAND_DISPLAY_FOCUS_BG); cairo_rectangle (cr, handdisp->l[c] - 1, handdisp->t[c] - 1, extents.width + 2, extents.height + 2); cairo_fill (cr); } cairo_set_source_rgb (cr, HAND_DISPLAY_FONT); cairo_move_to (cr, x, y); cairo_show_text (cr, "x"); x += extents.x_advance + 4; } if (x > handdisp->want_width) { /* grow window */ handdisp->want_width = x; gtk_widget_queue_resize (hand); } } /* show card scores */ cairo_set_font_size (cr, 10); int c; for (c = 51; c >= 0; c--) { char *buf; if (handdisp->card_score[c] != HAND_DISPLAY_NO_SCORE) { buf = overtricks (handdisp->card_score[c]); cairo_text_extents (cr, buf, &extents); cairo_move_to (cr, handdisp->r[c] - extents.x_advance, handdisp->b[c]); cairo_set_source_rgb (cr, HAND_DISPLAY_DD_FONT); cairo_show_text (cr, buf); } } } static void redraw_card (GtkWidget *hand, int card) { HandDisplay *handdisp = HAND_DISPLAY(hand); GdkRectangle rect; rect.x = handdisp->l[card] - 2; rect.y = handdisp->t[card] - 7; rect.width = handdisp->r[card] - handdisp->l[card] + 4; rect.height = handdisp->b[card] - handdisp->t[card] + 8; gdk_window_invalidate_rect (gtk_widget_get_window (hand), &rect, FALSE); } /* private callbacks */ static gboolean hand_display_motion (GtkWidget *hand, GdkEventMotion *event) { HandDisplay *handdisp = HAND_DISPLAY(hand); int card = which_card(handdisp, event->x, event->y); if (handdisp->drag && handdisp->cur_click >= 0 && handdisp->cur_click < 52 && gtk_drag_check_threshold (hand, handdisp->drag_x, handdisp->drag_y, event->x, event->y)) { if (! target_list) target_list = gtk_target_list_new (target_entry, 1); handdisp->cur_drag = handdisp->cur_click; gtk_drag_begin (hand, target_list, GDK_ACTION_COPY, 1, (GdkEvent *) event); } if (handdisp->cur_focus != card) { if (handdisp->cur_focus != -1) { redraw_card (hand, handdisp->cur_focus); g_signal_emit_by_name (handdisp, "card-leave", handdisp->cur_focus); } handdisp->cur_focus = card; if (card != -1) { redraw_card (hand, card); g_signal_emit_by_name (handdisp, "card-enter", card); } } gdk_window_get_pointer(gtk_widget_get_window (hand), NULL, NULL, NULL); /* request more pointer hints */ return FALSE; } static gboolean hand_display_leave (GtkWidget *hand, GdkEventCrossing *event) { HandDisplay *handdisp = HAND_DISPLAY(hand); if (handdisp->cur_focus != -1) { redraw_card (hand, handdisp->cur_focus); g_signal_emit_by_name (handdisp, "card-leave", handdisp->cur_focus); handdisp->cur_focus = -1; } return FALSE; } static gboolean hand_display_button_press (GtkWidget *hand, GdkEventButton *event) { HandDisplay *handdisp = HAND_DISPLAY(hand); int card = which_card(handdisp, event->x, event->y); if (event->type != GDK_BUTTON_RELEASE) /* don't trigger after dnd */ handdisp->cur_focus = card; if (event->type == GDK_BUTTON_PRESS) { handdisp->cur_click = card; if (handdisp->drag) { handdisp->drag_x = event->x; handdisp->drag_y = event->y; } } if (handdisp->cur_focus == -1) return FALSE; redraw_card (hand, card); if (event->type == GDK_BUTTON_RELEASE) { if (handdisp->cur_click == card) g_signal_emit_by_name (handdisp, "card-clicked", card); handdisp->cur_click = -1; } return FALSE; } static void hand_display_realize (GtkWidget *widget) { GdkWindowAttr attributes; gint attributes_mask; g_return_if_fail (widget != NULL); g_return_if_fail (IS_HAND_DISPLAY (widget)); gtk_widget_set_realized (widget, TRUE); GtkAllocation allocation; gtk_widget_get_allocation (widget, &allocation); attributes.x = allocation.x; attributes.y = allocation.y; attributes.width = allocation.width; attributes.height = allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; GdkWindow *window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gtk_widget_set_window (widget, window); gtk_widget_style_attach (widget); gdk_window_set_user_data (window, widget); gtk_style_set_background (gtk_widget_get_style (widget), window, GTK_STATE_ACTIVE); } static gboolean hand_display_expose (GtkWidget *hand, GdkEventExpose *event) { cairo_t *cr; /* get a cairo_t */ cr = gdk_cairo_create (gtk_widget_get_window (hand)); /* set a clip region for the expose event */ cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height); cairo_clip (cr); draw (hand, cr); cairo_destroy (cr); return FALSE; } static void hand_display_size_request (GtkWidget *hand, GtkRequisition *requisition) { HandDisplay *handdisp = HAND_DISPLAY(hand); requisition->width = handdisp->want_width; requisition->height = handdisp->mode != HAND_DISPLAY_MODE_CARD ? 90 : 10; } static void hand_display_size_allocate (GtkWidget *hand, GtkAllocation *allocation) { g_return_if_fail (hand != NULL); g_return_if_fail (IS_HAND_DISPLAY (hand)); g_return_if_fail (allocation != NULL); gtk_widget_set_allocation (hand, allocation); if (gtk_widget_get_realized (hand)) { gdk_window_move_resize (gtk_widget_get_window (hand), allocation->x, allocation->y, allocation->width, allocation->height); } } /* drag-and-drop interface */ /* http://live.gnome.org/GnomeLove/DragNDropTutorial */ static void hand_display_drag_begin (GtkWidget *hand, GdkDragContext *dc, gpointer data /* unused */) { HandDisplay *handdisp = HAND_DISPLAY (hand); assert (handdisp->cur_drag >= 0 && handdisp->cur_drag < 52); handdisp->cards[handdisp->cur_drag] |= HAND_DISPLAY_INVISIBLE_CARD; handdisp->cur_click = -1; redraw_card (hand, handdisp->cur_drag); /* create drag widget */ if (drag_win) { /* should be NULL, but happens sometimes */ gtk_widget_destroy (drag_win); drag_win = NULL; } drag_win = gtk_window_new (GTK_WINDOW_POPUP); GtkWidget *card = hand_display_new (HAND_DISPLAY_MODE_CARD); hand_display_set_style (HAND_DISPLAY (card), handdisp->style); hand_display_card_set_card (HAND_DISPLAY (card), handdisp->cur_drag); gtk_container_add (GTK_CONTAINER (drag_win), card); gtk_drag_set_icon_widget (dc, drag_win, 0, 0); gtk_widget_show_all (drag_win); } static gboolean hand_display_drag_motion (GtkWidget *hand, GdkDragContext *dc, gint x, gint y, guint t, gpointer data) { HandDisplay *handdisp = HAND_DISPLAY(hand); int card = which_card(handdisp, x, y); if (handdisp->cur_focus != card) { if (handdisp->cur_focus != -1) { redraw_card (hand, handdisp->cur_focus); g_signal_emit_by_name (handdisp, "card-drag-leave", handdisp->cur_focus); } handdisp->cur_focus = card; if (card != -1) { redraw_card (hand, card); g_signal_emit_by_name (handdisp, "card-drag-enter", card); } } return FALSE; } static void hand_display_drag_leave (GtkWidget *hand, GdkDragContext *dc, gpointer data) { HandDisplay *handdisp = HAND_DISPLAY(hand); if (handdisp->cur_focus != -1) { redraw_card (hand, handdisp->cur_focus); g_signal_emit_by_name (handdisp, "card-drag-leave", handdisp->cur_focus); handdisp->cur_focus = -1; } } static gboolean hand_display_drag_drop (GtkWidget *hand, GdkDragContext *dc, gpointer data) { gtk_drag_get_data (hand, dc, 0, 0); return TRUE; } static void hand_display_drag_data_get (GtkWidget *hand, GdkDragContext *dc, GtkSelectionData *selection_data, guint targettype, guint t, gpointer data) { HandDisplay *handdisp = HAND_DISPLAY (hand); if (handdisp->cur_drag < 0) return; assert (targettype == 0); gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 32, (guchar *) &(handdisp->cur_drag), sizeof (int)); } static void hand_display_drag_data_received (GtkWidget *hand, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint targettype, guint t, gpointer data) { HandDisplay *handdisp = HAND_DISPLAY (hand); int *card = (int *) gtk_selection_data_get_data (selection_data); int on_card = which_card(handdisp, x, y); /* if (*card == on_card) { gtk_drag_finish (dc, FALSE, FALSE, t); return; } */ g_signal_emit_by_name (handdisp, "card-drag-drop", *card, on_card); gtk_drag_finish (dc, TRUE, FALSE, t); } /* static void hand_display_drag_data_delete (GtkWidget *hand, GdkDragContext *dc, gpointer data) { printf ("drag_data_delete %x %x %x\n", hand, dc, data); } */ static void hand_display_drag_end (GtkWidget *hand, GdkDragContext *dc, gpointer data) { HandDisplay *handdisp = HAND_DISPLAY (hand); if (handdisp->cur_drag >= 0) { handdisp->cards[handdisp->cur_drag] &= ~HAND_DISPLAY_INVISIBLE_CARD; redraw_card (hand, handdisp->cur_drag); } handdisp->cur_drag = -1; gtk_widget_destroy (drag_win); drag_win = NULL; } static void setup_dnd (HandDisplay *handdisp) { GtkWidget *hand = GTK_WIDGET (handdisp); /* start manually gtk_drag_source_set( hand, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, target_entry, 1, GDK_ACTION_COPY ); */ gtk_drag_dest_set( hand, GTK_DEST_DEFAULT_MOTION | // GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, target_entry, 1, GDK_ACTION_COPY ); g_signal_connect (GTK_OBJECT(hand), "drag-begin", GTK_SIGNAL_FUNC(hand_display_drag_begin), NULL); g_signal_connect (GTK_OBJECT(hand), "drag-leave", GTK_SIGNAL_FUNC(hand_display_drag_leave), NULL); g_signal_connect (GTK_OBJECT(hand), "drag-motion", GTK_SIGNAL_FUNC(hand_display_drag_motion), NULL); g_signal_connect (GTK_OBJECT(hand), "drag-drop", GTK_SIGNAL_FUNC(hand_display_drag_drop), NULL); g_signal_connect (GTK_OBJECT(hand), "drag-data-get", GTK_SIGNAL_FUNC(hand_display_drag_data_get), NULL); g_signal_connect (GTK_OBJECT(hand), "drag-data-received", GTK_SIGNAL_FUNC(hand_display_drag_data_received), NULL); //g_signal_connect (GTK_OBJECT(hand), "drag_data_delete", //GTK_SIGNAL_FUNC(hand_display_drag_data_delete), NULL); g_signal_connect (GTK_OBJECT(hand), "drag-end", GTK_SIGNAL_FUNC(hand_display_drag_end), NULL); } /* initializers */ static void hand_display_class_init (HandDisplayClass *class) { //GtkObjectClass *object_class; GtkWidgetClass *widget_class; //object_class = GTK_OBJECT_CLASS (class); widget_class = GTK_WIDGET_CLASS (class); //parent_class = gtk_type_class (gtk_widget_get_type ()); //object_class->destroy = hand_display_destroy; widget_class->realize = hand_display_realize; widget_class->expose_event = hand_display_expose; widget_class->size_request = hand_display_size_request; widget_class->size_allocate = hand_display_size_allocate; widget_class->motion_notify_event = hand_display_motion; widget_class->leave_notify_event = hand_display_leave; widget_class->button_press_event = hand_display_button_press; widget_class->button_release_event = hand_display_button_press; g_signal_new ("card-clicked", TYPE_HAND_DISPLAY, G_SIGNAL_RUN_LAST, 0 /* guint class_offset */, NULL /* GSignalAccumulator accumulator */, NULL /* gpointer accu_data */, g_cclosure_marshal_VOID__INT /* GSignalCMarshaller c_marshaller */, G_TYPE_NONE /* GType return_type */, 1 /* guint n_params */, G_TYPE_INT); g_signal_new ("card-enter", TYPE_HAND_DISPLAY, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); g_signal_new ("card-leave", TYPE_HAND_DISPLAY, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); g_signal_new ("card-drag-enter", TYPE_HAND_DISPLAY, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); g_signal_new ("card-drag-leave", TYPE_HAND_DISPLAY, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); g_signal_new ("card-drag-drop", TYPE_HAND_DISPLAY, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); } static void hand_display_init (HandDisplay *handdisp) { int i; handdisp->style = HAND_DISPLAY_STYLE_TEXT; if (handdisp->mode == HAND_DISPLAY_MODE_TABLE) { for (i = 0; i < 4; i++) { handdisp->table_seat[i] = handdisp->table_card[i] = 0; } return; } int suitlist[] = { 3, 2, 0, 1 }; /* S H C D */ for (i = 0; i < 4; i++) handdisp->suits[i] = suitlist[i]; for (i = 0; i < 52; i++) { handdisp->cards[i] = 0; handdisp->card_score[i] = -1; handdisp->l[i] = handdisp->r[i] = handdisp->t[i] = handdisp->b[i] = -1; } handdisp->card_score_neg = 0; handdisp->best_card_score = HAND_DISPLAY_NO_SCORE; handdisp->cur_focus = handdisp->cur_click = handdisp->cur_drag = -1; } /* public interface */ GType hand_display_get_type () { static GType hand_display_type = 0; if (!hand_display_type) { static const GTypeInfo hand_display_info = { sizeof (HandDisplayClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) hand_display_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (HandDisplay), 0, /* n_preallocs */ (GInstanceInitFunc) hand_display_init, }; hand_display_type = g_type_register_static (GTK_TYPE_WIDGET, "HandDisplay", &hand_display_info, 0); } return hand_display_type; } GtkWidget * hand_display_new (int mode) { HandDisplay *handdisp = g_object_new (TYPE_HAND_DISPLAY, NULL); handdisp->mode = mode; handdisp->want_width = mode != HAND_DISPLAY_MODE_CARD ? 100 : 10; return GTK_WIDGET(handdisp); } void hand_display_draw (GtkWidget *hand) { GtkAllocation allocation; gtk_widget_get_allocation (hand, &allocation); gtk_widget_queue_draw_area (hand, 0, 0, allocation.width, allocation.height); } void hand_display_set_style (HandDisplay *handdisp, int style) { handdisp->style = style; } void hand_display_set_svg (char *fname, int width) { assert (fname); assert (width > 0); if (svg_filename && ! strcmp (fname, svg_filename) && width == card_width) return; /* no change */ if (svg_filename) g_free (svg_filename); svg_filename = strdup (fname); card_width = width; render_card_init (svg_filename); } void hand_display_set_drag (HandDisplay *handdisp, int drag) { handdisp->drag = drag; if (drag) { setup_dnd (handdisp); } } /* hand interface */ void hand_display_set_card (HandDisplay *handdisp, int card, int val) { assert (card >= 0 && card < 52); handdisp->cards[card] = val; handdisp->card_score[card] = HAND_DISPLAY_NO_SCORE; } void hand_display_set_card_score (HandDisplay *handdisp, int card, int score) { assert (card >= 0 && card < 52); handdisp->card_score[card] = score; } void hand_display_set_card_score_neg (HandDisplay *handdisp, int neg) { handdisp->card_score_neg = neg; handdisp->best_card_score = HAND_DISPLAY_NO_SCORE; } /* table interface */ void hand_display_table_reset_cards (HandDisplay *handdisp) { int i; for (i = 0; i < 4; i++) { handdisp->table_seat[i] = handdisp->table_card[i] = 0; } } void hand_display_table_set_card (HandDisplay *handdisp, int n, int seat, int card) { assert (card >= 0 && card < 52); handdisp->table_seat[n] = seat; handdisp->table_card[n] = card; } /* card interface */ void hand_display_card_set_card (HandDisplay *handdisp, int card) { assert (card >= 0 && card < 52); handdisp->table_card[0] = card; } tenace-0.18/handdisplay/hand_display.h000066400000000000000000000102461505733770300200260ustar00rootroot00000000000000/* * hand display - bridge hand widget for GTK+ * Copyright (C) 2007-2013 Christoph Berg * * 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. */ #ifndef HAND_DISPLAY_H #define HAND_DISPLAY_H #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define TYPE_HAND_DISPLAY (hand_display_get_type ()) #define HAND_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_HAND_DISPLAY, HandDisplay)) //#define HAND_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_HAND_DISPLAY, HandDisplayClass)) #define IS_HAND_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_HAND_DISPLAY)) /* display modes */ #define HAND_DISPLAY_MODE_HAND 0 #define HAND_DISPLAY_MODE_HAND_X 1 #define HAND_DISPLAY_MODE_TABLE 2 #define HAND_DISPLAY_MODE_CARD 3 /* display styles */ #define HAND_DISPLAY_STYLE_TEXT 0 #define HAND_DISPLAY_STYLE_CARDS 1 #define HAND_DISPLAY_NO_CARD 0 #define HAND_DISPLAY_CARD 1 /* show */ #define HAND_DISPLAY_GREY_CARD 2 /* used in MODE_X for not-in-this-hand cards */ #define HAND_DISPLAY_OLD_CARD 4 /* played card (grey) */ #define HAND_DISPLAY_HILIGHT_CARD 8 /* hilight card (orange in text mode, orange marker card mode) */ #define HAND_DISPLAY_INVISIBLE_CARD 16 /* don't render card, leave space (for drag and drop) */ #define HAND_DISPLAY_NO_SCORE (0x1000) /* score undefined */ /* internally used colors */ #define HAND_DISPLAY_TABLE_BG 0.0, 0.6, 0.0 #define HAND_DISPLAY_TABLE_GDK_BG 0.0*65535, 0.6*65535, 0.0*65535 #define HAND_DISPLAY_FOCUS_BG 1.0, 0.8, 0.0 #define HAND_DISPLAY_FONT 0.0, 0.0, 0.0 #define HAND_DISPLAY_GREY_FONT 0.3, 0.3, 0.3 #define HAND_DISPLAY_OLD_FONT 0.5, 0.5, 0.5 #define HAND_DISPLAY_HILIGHT_FONT 1.0, 0.3, 0.0 #define HAND_DISPLAY_BEST_POS_FONT 0.0, 0.9, 0.0 #define HAND_DISPLAY_POS_FONT 0.0, 0.7, 0.0 #define HAND_DISPLAY_BEST_NEG_FONT 0.9, 0.0, 0.0 #define HAND_DISPLAY_NEG_FONT 0.7, 0.0, 0.0 #define HAND_DISPLAY_DD_FONT 0.0, 0.0, 1.0 #define HAND_DISPLAY_SPADES_FONT 0.0, 0.0, 0.8 #define HAND_DISPLAY_HEARTS_FONT 0.9, 0.0, 0.0 #define HAND_DISPLAY_DIAMONDS_FONT 1.0, 0.5, 0.0 #define HAND_DISPLAY_CLUBS_FONT 0.0, 0.4, 0.0 typedef struct _HandDisplay HandDisplay; typedef struct _HandDisplayClass HandDisplayClass; struct _HandDisplay { GtkDrawingArea parent; int mode; int style; int want_width; int drag, drag_x, drag_y; /* hand */ int cur_focus; int cur_click; int cur_drag; int cards[52]; int card_score[52]; int card_score_neg; int best_card_score; double l[56], r[56], t[56], b[56]; /* 52..55 are MODE_X */ int suits[4]; /* order in which to show suits */ /* table */ // FIXME: this should use a union or something int table_seat[4]; int table_card[4]; }; struct _HandDisplayClass { GtkDrawingAreaClass parent_class; }; GType hand_display_get_type (void); GtkWidget *hand_display_new (int mode); void hand_display_draw (GtkWidget *hand); void hand_display_set_style (HandDisplay *handdisp, int style); void hand_display_set_svg (char *fname, int width); void hand_display_set_drag (HandDisplay *handdisp, int drag); /* hand interface */ void hand_display_set_card (HandDisplay *handdisp, int card, int val); void hand_display_set_card_score (HandDisplay *handdisp, int card, int score); void hand_display_set_card_score_neg (HandDisplay *handdisp, int neg); /* table interface */ void hand_display_table_reset_cards (HandDisplay *handdisp); void hand_display_table_set_card (HandDisplay *handdisp, int n, int seat, int card); /* card interface */ void hand_display_card_set_card (HandDisplay *handdisp, int card); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* HAND_DISPLAY_H */ tenace-0.18/handdisplay/int_int_marshal.def000066400000000000000000000000151505733770300210420ustar00rootroot00000000000000VOID:INT,INT tenace-0.18/m4/000077500000000000000000000000001505733770300132335ustar00rootroot00000000000000tenace-0.18/m4/gnulib-cache.m4000066400000000000000000000035041505733770300160200ustar00rootroot00000000000000# Copyright (C) 2002-2025 Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This file is distributed in the hope that 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 file. If not, see . # # As a special exception to the GNU General Public License, # this file may be distributed as part of a program that # contains a configuration script generated by Autoconf, under # the same distribution terms as the rest of that program. # # Generated by gnulib-tool. # # This file represents the specification of how gnulib-tool is used. # It acts as a cache: It is written and read by gnulib-tool. # In projects that use version control, this file is meant to be put under # version control, like the configure.ac and various Makefile.am files. # Specification in the form of a command-line invocation: # gnulib-tool --import \ # --lib=libgnu \ # --source-base=lib \ # --m4-base=m4 \ # --doc-base=doc \ # --tests-base=tests \ # --aux-dir=config \ # --no-conditional-dependencies \ # --libtool \ # --macro-prefix=gl \ # nproc # Specification in the form of a few gnulib-tool.m4 macro invocations: gl_LOCAL_DIR([]) gl_MODULES([ nproc ]) gl_AVOID([]) gl_SOURCE_BASE([lib]) gl_M4_BASE([m4]) gl_PO_BASE([]) gl_DOC_BASE([doc]) gl_TESTS_BASE([tests]) gl_LIB([libgnu]) gl_MAKEFILE_NAME([]) gl_LIBTOOL gl_MACRO_PREFIX([gl]) gl_PO_DOMAIN([]) gl_WITNESS_C_MACRO([]) tenace-0.18/magic.ui000066400000000000000000000477701505733770300143510ustar00rootroot00000000000000 True 5 10 2 True True True adj_vert_sep 1 False 0 True mm False False 1 1 2 9 10 GTK_FILL True True True adj_horiz_sep 1 False 0 True mm False False 1 1 2 8 9 GTK_FILL True 0 Vertical separation: 9 10 GTK_FILL True 0 Horizontal separation: 8 9 GTK_FILL True True True adj_vert_margin 1 False 0 True mm False False 1 1 2 7 8 GTK_FILL True True True adj_horiz_margin 1 False 0 True mm False False 1 1 2 6 7 GTK_FILL True 0 Vertical margin: 7 8 GTK_FILL True 0 Horizontal margin: 6 7 GTK_FILL True 0 Headers: 2 3 GTK_FILL GTK_FILL True 0 Rows: word-char 1 2 GTK_FILL GTK_FILL True 0 Columns: GTK_FILL True True adj_rows True 1 2 1 2 GTK_FILL GTK_FILL True True adj_columns True 1 2 GTK_FILL True 0 Mark cards: 3 4 GTK_FILL True True False 0 True 1 2 3 4 GTK_FILL True 5 none True True False True magic_page_header 0 per page True True False True True 1 per suit True True False True magic_page_header 2 1 2 2 3 GTK_FILL True 0 Boards: 4 5 GTK_FILL True True True adj_from False 0 True to False 1 True True adj_to False 2 1 2 4 5 GTK_FILL GTK_FILL True 0 Internal border: 5 6 GTK_FILL True True True adj_border 1 False 0 True mm False 1 1 2 5 6 GTK_FILL 3 1 100 1 10 10 7 1 100 1 10 10 100 1 10 10 100 1 10 10 3 999 1 10 10 3 999 1 10 10 3 999 1 10 10 3 999 1 10 10 3 999 1 10 10 tenace-0.18/po/000077500000000000000000000000001505733770300133315ustar00rootroot00000000000000tenace-0.18/po/ChangeLog000066400000000000000000000000001505733770300150710ustar00rootroot00000000000000tenace-0.18/po/LINGUAS000066400000000000000000000001141505733770300143520ustar00rootroot00000000000000# keep this file sorted alphabetically, one language code per line de en nn tenace-0.18/po/POTFILES.in000066400000000000000000000012271505733770300151100ustar00rootroot00000000000000# List of source files containing translatable strings. # the file is actually called tenace.ui, but I haven't yet figured out how to # make gettext/intltool-update actually extract strings from it. tenace.glade # is a symlink and makes things mostly work (though there seems to be a problem # with menu items containing _underscores.) tenace.glade tenace.ui magic.ui lib/c-ctype.c src/bridge.c src/callbacks.c src/file.c src/functions.c src/main.c src/options.c src/print.c src/solve.c src/window_bids.c src/window_board.c src/window_card.c src/window_line_entry.c src/window_misc.c src/window_play.c # File for strings needed, but not in source src/unused.c tenace-0.18/po/de.po000066400000000000000000000374511505733770300142730ustar00rootroot00000000000000# tenace # Copyright (C) Christoph Berg # This file is distributed under the same license as the tenace package. # msgid "" msgstr "" "Project-Id-Version: tenace 0.4\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-06-12 15:03+0200\n" "PO-Revision-Date: 2013-10-07 20:14+0200\n" "Last-Translator: Christoph Berg \n" "Language-Team: Christoph Berg \n" "Language: German\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../tenace.glade.h:1 msgid "Tenace" msgstr "" #: ../tenace.glade.h:2 msgid "_File" msgstr "_Datei" #: ../tenace.glade.h:3 msgid "Append file to board list" msgstr "Datei an Boardliste anhängen" #: ../tenace.glade.h:4 msgid "_Boards" msgstr "_Boardliste" #: ../tenace.glade.h:5 msgid "_Edit" msgstr "_Bearbeiten" #: ../tenace.glade.h:6 msgid "E-W" msgstr "O-W" #: ../tenace.glade.h:7 msgid "N-S" msgstr "" #: ../tenace.glade.h:8 msgid "N-W" msgstr "" #: ../tenace.glade.h:9 msgid "N-E" msgstr "N-O" #: ../tenace.glade.h:10 msgid "S-W" msgstr "" #: ../tenace.glade.h:11 msgid "S-E" msgstr "S-O" #: ../tenace.glade.h:12 msgid "_Board editor..." msgstr "_Boardeditor..." #: ../tenace.glade.h:13 msgid "Text _input..." msgstr "Text_eingabe..." #: ../tenace.glade.h:14 msgid "Undo all cards" msgstr "Alle Karten zurücknehmen" #: ../tenace.glade.h:15 msgid "Play all cards" msgstr "Alle Karten spielen" #: ../tenace.glade.h:16 msgid "Show pla_y..." msgstr "Spiel _zeigen..." #: ../tenace.glade.h:17 msgid "_Contract" msgstr "_Kontrakt" #: ../tenace.glade.h:18 msgid "_West" msgstr "_West" #: ../tenace.glade.h:19 msgid "_North" msgstr "_Nord" #: ../tenace.glade.h:20 msgid "_East" msgstr "_Ost" #: ../tenace.glade.h:21 msgid "_South" msgstr "_Süd" #: ../tenace.glade.h:22 msgid "N_one" msgstr "_Keiner" #: ../tenace.glade.h:23 msgid "_North-South" msgstr "_Nord-Süd" #: ../tenace.glade.h:24 msgid "_East-West" msgstr "_Ost-West" #: ../tenace.glade.h:25 msgid "_All" msgstr "_Alle" #: ../tenace.glade.h:26 msgid "_1" msgstr "" #: ../tenace.glade.h:27 msgid "_2" msgstr "" #: ../tenace.glade.h:28 msgid "_3" msgstr "" #: ../tenace.glade.h:29 msgid "_4" msgstr "" #: ../tenace.glade.h:30 msgid "_5" msgstr "" #: ../tenace.glade.h:31 msgid "_6" msgstr "" #: ../tenace.glade.h:32 msgid "_7" msgstr "" #: ../tenace.glade.h:33 msgid "No _Trump" msgstr "_Sans Atout" #: ../tenace.glade.h:34 msgid "♠ S_pades" msgstr "♠ _Pik" #: ../tenace.glade.h:35 msgid "♥ _Hearts" msgstr "♥ _Coeur" #: ../tenace.glade.h:36 msgid "♦ _Diamonds" msgstr "♦ _Karo" #: ../tenace.glade.h:37 msgid "♣ _Clubs" msgstr "♣ _Treff" #: ../tenace.glade.h:38 msgid "_No double" msgstr "Kei_n Kontra" #: ../tenace.glade.h:39 msgid "X _Doubled" msgstr "X _Kontra" #: ../tenace.glade.h:40 msgid "XX _Redoubled" msgstr "XX _Rekontra" #: ../tenace.glade.h:41 msgid "_Bidding editor..." msgstr "_Reizeditor..." #: ../tenace.glade.h:42 msgid "_Analysis" msgstr "_Analyse" #: ../tenace.glade.h:43 msgid "Double dummy analysis" msgstr "Double-Dummy-Analyse" #: ../tenace.glade.h:44 msgid "Automatically run DD analysis" msgstr "DD-Analyse automatisch starten" #: ../tenace.glade.h:45 msgid "Always run DD" msgstr "Immer DD" #: ../tenace.glade.h:46 msgid "Compute par score and contract" msgstr "Berechne Parscore und -kontrakt" #: ../tenace.glade.h:47 msgid "Set contract to computed par contract" msgstr "Setze Kontrakt auf berechneten Par" #: ../tenace.glade.h:48 msgid "Open board" msgstr "Öffne Board" #: ../tenace.glade.h:49 msgid "Save board" msgstr "Speichere Board" #: ../tenace.glade.h:50 msgid "Previous board" msgstr "Vorheriges Board" #: ../tenace.glade.h:51 msgid "Next board" msgstr "Nächstes Board" #: ../tenace.glade.h:52 msgid "Rewind trick" msgstr "Stich zurück" #: ../tenace.glade.h:53 msgid "Rewind card" msgstr "Karte zurück" #: ../tenace.glade.h:54 msgid "Play next card" msgstr "Nächste Karte spielen" #: ../tenace.glade.h:55 msgid "Play next trick" msgstr "Nächsten Stich spielen" #: ../tenace.glade.h:56 msgid "Par score" msgstr "Parscore" #: ../tenace.glade.h:58 ../src/window_board.c:267 #, no-c-format msgid "" "NS: %d\n" "EW: %d" msgstr "" "NS: %d\n" "OW: %d" #: ../tenace.glade.h:60 msgid "East" msgstr "Ost" #: ../tenace.glade.h:61 msgid "North" msgstr "Nord" #: ../tenace.glade.h:62 msgid "South" msgstr "Süd" #: ../tenace.glade.h:63 msgid "West" msgstr "West" #: ../tenace.glade.h:64 msgid "Board editor" msgstr "Boardeditor" #: ../tenace.glade.h:65 msgid "Clear board" msgstr "Board leeren" #: ../tenace.glade.h:66 msgid "Deal randomly" msgstr "Zufällig teilen" #: ../tenace.glade.h:67 msgid "Bidding editor" msgstr "Reizeditor" #: ../tenace.glade.h:68 msgid "Remove all bids" msgstr "Alle Ansagen entfernen" #: ../tenace.glade.h:69 msgid "Remove last bid" msgstr "Letzte Ansage entfernen" #: ../tenace.glade.h:70 msgid "Make bids for the current contract" msgstr "Ansagen für aktuellen Kontrakt machen" #: ../tenace.glade.h:71 msgid "Alert" msgstr "" #: ../tenace.glade.h:72 msgid "IMP Table" msgstr "IMP-Tabelle" #: ../tenace.glade.h:73 msgid "Play" msgstr "Spiel" #: ../tenace.glade.h:74 msgid "Options" msgstr "Optionen" #: ../tenace.glade.h:75 msgid "Played cards " msgstr "Gespielte Karten " #: ../tenace.glade.h:76 msgid "Select File" msgstr "Datei auswählen" #: ../tenace.glade.h:77 msgid "Show" msgstr "Anzeigen" #: ../tenace.glade.h:78 msgid "Text" msgstr "" #: ../tenace.glade.h:79 msgid "Cards" msgstr "Karten" #: ../tenace.glade.h:80 msgid "Show as " msgstr "Anzeigen als" #: ../tenace.glade.h:81 msgid "Filename" msgstr "Dateiname" #: ../tenace.glade.h:82 msgid "Card width " msgstr "Kartenbreite " #: ../tenace.glade.h:83 msgid "Card display" msgstr "Kartenanzeige" #: ../tenace.glade.h:84 msgid "All" msgstr "Alle" #: ../tenace.glade.h:85 msgid "North-South" msgstr "Nord-Süd" #: ../tenace.glade.h:86 msgid "East-West" msgstr "Ost-West" #: ../tenace.glade.h:87 msgid "None" msgstr "Keinen" #: ../tenace.glade.h:88 msgid "Show DD scores " msgstr "Zeige DD für " #: ../tenace.glade.h:89 msgid "Show hands " msgstr "Hände zeigen " #: ../tenace.glade.h:90 msgid "Hands" msgstr "Hände" #: ../tenace.glade.h:91 msgid "Players " msgstr "Spieler " #: ../tenace.glade.h:92 msgid "Title " msgstr "Titel " #: ../tenace.glade.h:93 msgid "Current board" msgstr "Aktuelles Board" #: ../tenace.glade.h:94 msgid "Board list" msgstr "Boardliste" #: ../tenace.glade.h:95 msgid "deals" msgstr "Austeilungen" #: ../tenace.glade.h:96 msgid "Generate" msgstr "Erzeugen" #: ../tenace.glade.h:97 msgid "(C) 2005-2016 Christoph Berg" msgstr "" #: ../tenace.glade.h:98 msgid "Bridge Hand Viewer and Editor" msgstr "Bridgehand-Betrachter und -Editor" #: ../tenace.glade.h:99 msgid "Homepage" msgstr "" #: ../tenace.glade.h:100 msgid "" "tenace - bridge hand viewer and editor\n" "Copyright (C) Christoph Berg \n" "\n" "This program is free software; you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 2 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details." msgstr "" #. TRANSLATORS: Replace this string with your names, one name per line. #: ../tenace.glade.h:113 msgid "de: Christoph Berg " msgstr "" #: ../tenace.glade.h:114 msgid "Text input" msgstr "Texteingabe" #: ../tenace.glade.h:115 msgid "Hand as string" msgstr "Hand als Text" #: ../tenace.glade.h:116 msgid "Set hand" msgstr "Hand setzen" #. newly created board #: ../src/bridge.c:141 ../src/callbacks.c:501 ../src/window_board.c:674 #, c-format msgid "Board %d" msgstr "" #: ../src/bridge.c:341 msgid "Card is not in your hand" msgstr "Karte ist nicht in Ihrer Hand" #: ../src/bridge.c:346 msgid "Not your turn" msgstr "Nicht Ihr Zug" #: ../src/bridge.c:356 msgid "Please follow suit" msgstr "Bitte Farbe bekennen" #: ../src/bridge.c:410 msgid "Nothing to undo" msgstr "Nichts zurück zu nehmen" #: ../src/bridge.c:456 msgid "No cards left to play" msgstr "Keine weiteren Karten zu spielen" #: ../src/bridge.c:460 msgid "Which card should I play?" msgstr "Welche Karte soll ich spielen?" #: ../src/bridge.c:466 #, c-format msgid "Declarer claims %d tricks" msgstr "Alleinspieler claimt %d Stiche" #: ../src/bridge.c:471 msgid "Card was already played" msgstr "Karte wurde schon gespielt" #: ../src/bridge.c:475 msgid "Card belongs to wrong player" msgstr "Karte gehört falschem Spieler" #: ../src/bridge.c:512 msgid "Bidding is over" msgstr "Reizung ist zu Ende" #: ../src/bridge.c:518 msgid "Invalid double" msgstr "Ungültiges Kontra" #: ../src/bridge.c:524 msgid "Invalid redouble" msgstr "Ungültiges Rekontra" #: ../src/bridge.c:529 msgid "Insufficient bid" msgstr "Ungenügendes Gebot" #: ../src/callbacks.c:452 ../src/callbacks.c:479 msgid "No board" msgstr "Kein Board" #: ../src/callbacks.c:495 msgid "Cut buffer is empty" msgstr "Zwischenablage ist leer" #: ../src/callbacks.c:644 msgid "No previous board" msgstr "Kein vorheriges Board" #: ../src/callbacks.c:660 msgid "No next board" msgstr "Kein nächstes Board" #: ../src/file.c:35 msgid "Bridge files" msgstr "Bridge-Dateien" #: ../src/file.c:40 msgid "LIN files" msgstr "LIN-Dateien" #: ../src/file.c:44 msgid "PBN files" msgstr "PBN-Dateien" #: ../src/file.c:48 msgid "All files" msgstr "Alle Dateien" #: ../src/file.c:172 msgid "Closed" msgstr "" #: ../src/file.c:173 msgid "Open" msgstr "" #: ../src/file.c:173 msgid "Board" msgstr "" #: ../src/file.c:436 #, c-format msgid "Error loading file '%s': %s" msgstr "Kann Datei '%s' nicht laden: %s" #: ../src/file.c:457 msgid "Open File" msgstr "Datei öffnen" #: ../src/file.c:717 ../src/file.c:757 #, c-format msgid "Error saving file '%s': %s" msgstr "Kann Datei '%s' nicht speichern: %s" #: ../src/file.c:725 msgid "Save File" msgstr "Datei speichern" #: ../src/file.c:735 msgid "hand.lin" msgstr "" #: ../src/functions.c:145 ../src/functions.c:202 ../src/functions.c:213 #: ../src/window_bids.c:75 #, c-format msgid "X" msgstr "" #: ../src/functions.c:147 ../src/functions.c:202 ../src/functions.c:213 #: ../src/window_bids.c:78 #, c-format msgid "XX" msgstr "" #: ../src/functions.c:199 ../src/functions.c:210 ../src/window_bids.c:72 msgid "PASS" msgstr "" #. none vulnerable #: ../src/functions.c:223 msgid "none" msgstr "keiner" #. EW vulnerable #. parscore for EW #: ../src/functions.c:226 ../src/solve.c:484 msgid "EW" msgstr "OW" #. EW #. NS vulnerable #. parscore for NS #: ../src/functions.c:230 ../src/solve.c:477 msgid "NS" msgstr "" #. all vulnerable #: ../src/functions.c:233 msgid "all" msgstr "alle" #: ../src/main.c:74 ../src/print.c:405 #, c-format msgid "Could not find interface definition file: %s\n" msgstr "Konnte Interface-Definitionsdatei nicht finden: %s\n" #: ../src/main.c:81 ../src/print.c:413 #, c-format msgid "Could not load builder file: %s" msgstr "Konnte Builder-Datei nicht finden: %s" #: ../src/main.c:102 msgid "Hint: tenace can only read files in .lin format" msgstr "Hinweis: tenace kann nur .lin-Dateien lesen" #: ../src/options.c:378 msgid "#" msgstr "" #: ../src/options.c:383 msgid "Title" msgstr "Titel" #: ../src/print.c:512 msgid "Labels" msgstr "Etiketten" #. FIXME: do not call this every time #: ../src/solve.c:136 msgid "Error: hands have different numbers of cards" msgstr "Fehler: Hände haben unterschiedlich viele Karten" #. struct timeval tv1, tv2; #: ../src/solve.c:177 ../src/solve.c:329 msgid "Thinking..." msgstr "Denke..." #: ../src/solve.c:415 msgid "Error: board must be fully dealt" msgstr "Fehler: Board muss vollständig geteilt sein" #. parscore is pass #: ../src/solve.c:464 msgid "Par: PASS (0)\n" msgstr "" #: ../src/solve.c:466 #, c-format msgid "Par: %s %s (%+d)\n" msgstr "" #. North; translation should be a single letter #: ../src/solve.c:481 ../src/unused.c:8 msgid "N" msgstr "" #. South; translation should be a single letter #: ../src/solve.c:481 ../src/unused.c:12 msgid "S" msgstr "" #. East; translation should be a single letter #: ../src/solve.c:488 ../src/unused.c:10 msgid "E" msgstr "O" #. West; translation should be a single letter #: ../src/solve.c:488 ../src/unused.c:6 msgid "W" msgstr "" #: ../src/window_bids.c:50 #, c-format msgid "Contract set to %s" msgstr "Kontrakt auf %s gesetzt" #: ../src/window_bids.c:140 msgid "Suit was already bid from wrong side" msgstr "Farbe wurde schon von der falschen Seite geboten" #: ../src/window_board.c:145 ../src/window_board.c:209 msgid "Dealer" msgstr "Teiler" #: ../src/window_board.c:156 msgid "*" msgstr "" #: ../src/window_board.c:156 msgid "!" msgstr "" #: ../src/window_board.c:193 #, c-format msgid " - %s vs. %s" msgstr " - %s gegen %s" #: ../src/window_board.c:210 msgid "Vulnerable" msgstr "Gefahr" #: ../src/window_board.c:430 msgid "Card is in play and cannot be moved" msgstr "Karte ist im Spiel und kann nicht bewegt werden" #: ../src/window_board.c:437 msgid "Card is in play and cannot be exchanged" msgstr "Karte ist im Spiel und kann nicht ausgetauscht werden" #: ../src/window_board.c:449 ../src/window_card.c:72 ../src/window_card.c:103 msgid "Hand has already 13 cards" msgstr "Hand hat schon 13 Karten" #: ../src/window_board.c:505 msgid "(no explanation)" msgstr "(keine Erklärung)" #: ../src/window_board.c:775 msgid "Cannot change declarer while cards are in play" msgstr "Kann Alleinspieler nicht ändern wenn Karten im Spiel sind" #: ../src/window_board.c:808 msgid "Cannot change trumps while cards are in play" msgstr "Kann Trumpf nicht ändern wenn Karten im Spiel sind" #: ../src/window_card.c:90 msgid "All cards of that suit dealt" msgstr "Alle Karten dieser Farbe wurden geteilt" #: ../src/window_card.c:95 ../src/window_card.c:128 msgid "Card is in play and cannot be removed" msgstr "Karte ist im Spiel und kann nicht entfernt werden" #: ../src/window_line_entry.c:33 msgid "Parse error" msgstr "Parsefehler" #: ../src/window_misc.c:57 #, c-format msgid "" "\n" "DDS version: %d.%d.%d" msgstr "" #: ../src/window_play.c:46 msgid "CL" msgstr "" #: ../src/unused.c:14 msgid "NT" msgstr "SA" #. Spades; translation should be a single letter #: ../src/unused.c:16 msgid "Sp" msgstr "P" #. Hearts; translation should be a single letter #: ../src/unused.c:18 msgid "He" msgstr "C" #. Diamonds; translation should be a single letter #: ../src/unused.c:20 msgid "Di" msgstr "K" #. Clubs; translation should be a single letter #: ../src/unused.c:22 msgid "Cl" msgstr "T" #~ msgid " to " #~ msgstr " bis " #~ msgid "C_lear" #~ msgstr "_Leeren" #~ msgid "Columns: " #~ msgstr "Spalten: " #~ msgid "Complete play" #~ msgstr "Alle Karten spielen" #~ msgid "Double" #~ msgstr "Kontra" #~ msgid "Double dummy" #~ msgstr "Double Dummy" #~ msgid "Headers: " #~ msgstr "Header:" #~ msgid "Horizontal margin: " #~ msgstr "Horizontaler Rand: " #~ msgid "Horizontal separation: " #~ msgstr "Horizontaler Abstand: " #~ msgid "IMP _table..." #~ msgstr "IMP-_Tabelle..." #~ msgid "Internal border: " #~ msgstr "Abstand zum Rand: " #~ msgid "Mark cards: " #~ msgstr "Karten kennzeichnen: " #~ msgid "O_ptions..." #~ msgstr "O_ptionen..." #~ msgid "Play par contract" #~ msgstr "Spiele Parkontrakt" #~ msgid "Rewind play" #~ msgstr "Zurückspulen" #~ msgid "Rows: " #~ msgstr "Zeilen: " #~ msgid "Vertical margin: " #~ msgstr "Vertikaler Rand: " #~ msgid "Vertical separation: " #~ msgstr "Vertikaler Abstand: " #~ msgid "_Append" #~ msgstr "_Anhängen" #~ msgid "_Dealer" #~ msgstr "_Teiler" #~ msgid "_Flip hands" #~ msgstr "Hände _tauschen" #~ msgid "_Level" #~ msgstr "Stu_fe" #~ msgid "_Magic cards" #~ msgstr "_Magische Karten" #~ msgid "_New board" #~ msgstr "_Neues Board" #~ msgid "_Random" #~ msgstr "_Zufällig" #~ msgid "per suit" #~ msgstr "pro Farbe" tenace-0.18/po/en.po000066400000000000000000000304131505733770300142740ustar00rootroot00000000000000# tenace # Copyright (C) Christoph Berg # This file is distributed under the same license as the tenace package. # msgid "" msgstr "" "Project-Id-Version: tenace 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-06-12 15:03+0200\n" "PO-Revision-Date: 2013-10-07 13:19+0200\n" "Last-Translator: Christoph Berg \n" "Language-Team: Christoph Berg \n" "Language: English\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../tenace.glade.h:1 msgid "Tenace" msgstr "" #: ../tenace.glade.h:2 msgid "_File" msgstr "" #: ../tenace.glade.h:3 msgid "Append file to board list" msgstr "" #: ../tenace.glade.h:4 msgid "_Boards" msgstr "" #: ../tenace.glade.h:5 msgid "_Edit" msgstr "" #: ../tenace.glade.h:6 msgid "E-W" msgstr "" #: ../tenace.glade.h:7 msgid "N-S" msgstr "" #: ../tenace.glade.h:8 msgid "N-W" msgstr "" #: ../tenace.glade.h:9 msgid "N-E" msgstr "" #: ../tenace.glade.h:10 msgid "S-W" msgstr "" #: ../tenace.glade.h:11 msgid "S-E" msgstr "" #: ../tenace.glade.h:12 msgid "_Board editor..." msgstr "" #: ../tenace.glade.h:13 msgid "Text _input..." msgstr "" #: ../tenace.glade.h:14 msgid "Undo all cards" msgstr "" #: ../tenace.glade.h:15 msgid "Play all cards" msgstr "" #: ../tenace.glade.h:16 msgid "Show pla_y..." msgstr "" #: ../tenace.glade.h:17 msgid "_Contract" msgstr "" #: ../tenace.glade.h:18 msgid "_West" msgstr "" #: ../tenace.glade.h:19 msgid "_North" msgstr "" #: ../tenace.glade.h:20 msgid "_East" msgstr "" #: ../tenace.glade.h:21 msgid "_South" msgstr "" #: ../tenace.glade.h:22 msgid "N_one" msgstr "" #: ../tenace.glade.h:23 msgid "_North-South" msgstr "" #: ../tenace.glade.h:24 msgid "_East-West" msgstr "" #: ../tenace.glade.h:25 msgid "_All" msgstr "" #: ../tenace.glade.h:26 msgid "_1" msgstr "" #: ../tenace.glade.h:27 msgid "_2" msgstr "" #: ../tenace.glade.h:28 msgid "_3" msgstr "" #: ../tenace.glade.h:29 msgid "_4" msgstr "" #: ../tenace.glade.h:30 msgid "_5" msgstr "" #: ../tenace.glade.h:31 msgid "_6" msgstr "" #: ../tenace.glade.h:32 msgid "_7" msgstr "" #: ../tenace.glade.h:33 msgid "No _Trump" msgstr "" #: ../tenace.glade.h:34 msgid "♠ S_pades" msgstr "" #: ../tenace.glade.h:35 msgid "♥ _Hearts" msgstr "" #: ../tenace.glade.h:36 msgid "♦ _Diamonds" msgstr "" #: ../tenace.glade.h:37 msgid "♣ _Clubs" msgstr "" #: ../tenace.glade.h:38 msgid "_No double" msgstr "" #: ../tenace.glade.h:39 msgid "X _Doubled" msgstr "" #: ../tenace.glade.h:40 msgid "XX _Redoubled" msgstr "" #: ../tenace.glade.h:41 msgid "_Bidding editor..." msgstr "" #: ../tenace.glade.h:42 msgid "_Analysis" msgstr "" #: ../tenace.glade.h:43 msgid "Double dummy analysis" msgstr "" #: ../tenace.glade.h:44 msgid "Automatically run DD analysis" msgstr "" #: ../tenace.glade.h:45 msgid "Always run DD" msgstr "" #: ../tenace.glade.h:46 msgid "Compute par score and contract" msgstr "" #: ../tenace.glade.h:47 msgid "Set contract to computed par contract" msgstr "" #: ../tenace.glade.h:48 msgid "Open board" msgstr "" #: ../tenace.glade.h:49 msgid "Save board" msgstr "" #: ../tenace.glade.h:50 msgid "Previous board" msgstr "" #: ../tenace.glade.h:51 msgid "Next board" msgstr "" #: ../tenace.glade.h:52 msgid "Rewind trick" msgstr "" #: ../tenace.glade.h:53 msgid "Rewind card" msgstr "" #: ../tenace.glade.h:54 msgid "Play next card" msgstr "" #: ../tenace.glade.h:55 msgid "Play next trick" msgstr "" #: ../tenace.glade.h:56 msgid "Par score" msgstr "" #: ../tenace.glade.h:58 ../src/window_board.c:267 #, no-c-format msgid "" "NS: %d\n" "EW: %d" msgstr "" #: ../tenace.glade.h:60 msgid "East" msgstr "" #: ../tenace.glade.h:61 msgid "North" msgstr "" #: ../tenace.glade.h:62 msgid "South" msgstr "" #: ../tenace.glade.h:63 msgid "West" msgstr "" #: ../tenace.glade.h:64 msgid "Board editor" msgstr "" #: ../tenace.glade.h:65 msgid "Clear board" msgstr "" #: ../tenace.glade.h:66 msgid "Deal randomly" msgstr "" #: ../tenace.glade.h:67 msgid "Bidding editor" msgstr "" #: ../tenace.glade.h:68 msgid "Remove all bids" msgstr "" #: ../tenace.glade.h:69 msgid "Remove last bid" msgstr "" #: ../tenace.glade.h:70 msgid "Make bids for the current contract" msgstr "" #: ../tenace.glade.h:71 msgid "Alert" msgstr "" #: ../tenace.glade.h:72 msgid "IMP Table" msgstr "" #: ../tenace.glade.h:73 msgid "Play" msgstr "" #: ../tenace.glade.h:74 msgid "Options" msgstr "" #: ../tenace.glade.h:75 msgid "Played cards " msgstr "" #: ../tenace.glade.h:76 msgid "Select File" msgstr "" #: ../tenace.glade.h:77 msgid "Show" msgstr "" #: ../tenace.glade.h:78 msgid "Text" msgstr "" #: ../tenace.glade.h:79 msgid "Cards" msgstr "" #: ../tenace.glade.h:80 msgid "Show as " msgstr "" #: ../tenace.glade.h:81 msgid "Filename" msgstr "" #: ../tenace.glade.h:82 msgid "Card width " msgstr "" #: ../tenace.glade.h:83 msgid "Card display" msgstr "" #: ../tenace.glade.h:84 msgid "All" msgstr "" #: ../tenace.glade.h:85 msgid "North-South" msgstr "" #: ../tenace.glade.h:86 msgid "East-West" msgstr "" #: ../tenace.glade.h:87 msgid "None" msgstr "" #: ../tenace.glade.h:88 msgid "Show DD scores " msgstr "" #: ../tenace.glade.h:89 msgid "Show hands " msgstr "" #: ../tenace.glade.h:90 msgid "Hands" msgstr "" #: ../tenace.glade.h:91 msgid "Players " msgstr "" #: ../tenace.glade.h:92 msgid "Title " msgstr "" #: ../tenace.glade.h:93 msgid "Current board" msgstr "" #: ../tenace.glade.h:94 msgid "Board list" msgstr "" #: ../tenace.glade.h:95 msgid "deals" msgstr "" #: ../tenace.glade.h:96 msgid "Generate" msgstr "" #: ../tenace.glade.h:97 msgid "(C) 2005-2016 Christoph Berg" msgstr "" #: ../tenace.glade.h:98 msgid "Bridge Hand Viewer and Editor" msgstr "" #: ../tenace.glade.h:99 msgid "Homepage" msgstr "" #: ../tenace.glade.h:100 msgid "" "tenace - bridge hand viewer and editor\n" "Copyright (C) Christoph Berg \n" "\n" "This program is free software; you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 2 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details." msgstr "" #. TRANSLATORS: Replace this string with your names, one name per line. #: ../tenace.glade.h:113 msgid "de: Christoph Berg " msgstr "" #: ../tenace.glade.h:114 msgid "Text input" msgstr "" #: ../tenace.glade.h:115 msgid "Hand as string" msgstr "" #: ../tenace.glade.h:116 msgid "Set hand" msgstr "" #. newly created board #: ../src/bridge.c:141 ../src/callbacks.c:501 ../src/window_board.c:674 #, c-format msgid "Board %d" msgstr "" #: ../src/bridge.c:341 msgid "Card is not in your hand" msgstr "" #: ../src/bridge.c:346 msgid "Not your turn" msgstr "" #: ../src/bridge.c:356 msgid "Please follow suit" msgstr "" #: ../src/bridge.c:410 msgid "Nothing to undo" msgstr "" #: ../src/bridge.c:456 msgid "No cards left to play" msgstr "" #: ../src/bridge.c:460 msgid "Which card should I play?" msgstr "" #: ../src/bridge.c:466 #, c-format msgid "Declarer claims %d tricks" msgstr "" #: ../src/bridge.c:471 msgid "Card was already played" msgstr "" #: ../src/bridge.c:475 msgid "Card belongs to wrong player" msgstr "" #: ../src/bridge.c:512 msgid "Bidding is over" msgstr "" #: ../src/bridge.c:518 msgid "Invalid double" msgstr "" #: ../src/bridge.c:524 msgid "Invalid redouble" msgstr "" #: ../src/bridge.c:529 msgid "Insufficient bid" msgstr "" #: ../src/callbacks.c:452 ../src/callbacks.c:479 msgid "No board" msgstr "" #: ../src/callbacks.c:495 msgid "Cut buffer is empty" msgstr "" #: ../src/callbacks.c:644 msgid "No previous board" msgstr "" #: ../src/callbacks.c:660 msgid "No next board" msgstr "" #: ../src/file.c:35 msgid "Bridge files" msgstr "" #: ../src/file.c:40 msgid "LIN files" msgstr "" #: ../src/file.c:44 msgid "PBN files" msgstr "" #: ../src/file.c:48 msgid "All files" msgstr "" #: ../src/file.c:172 msgid "Closed" msgstr "" #: ../src/file.c:173 msgid "Open" msgstr "" #: ../src/file.c:173 msgid "Board" msgstr "" #: ../src/file.c:436 #, c-format msgid "Error loading file '%s': %s" msgstr "" #: ../src/file.c:457 msgid "Open File" msgstr "" #: ../src/file.c:717 ../src/file.c:757 #, c-format msgid "Error saving file '%s': %s" msgstr "" #: ../src/file.c:725 msgid "Save File" msgstr "" #: ../src/file.c:735 msgid "hand.lin" msgstr "" #: ../src/functions.c:145 ../src/functions.c:202 ../src/functions.c:213 #: ../src/window_bids.c:75 #, c-format msgid "X" msgstr "" #: ../src/functions.c:147 ../src/functions.c:202 ../src/functions.c:213 #: ../src/window_bids.c:78 #, c-format msgid "XX" msgstr "" #: ../src/functions.c:199 ../src/functions.c:210 ../src/window_bids.c:72 msgid "PASS" msgstr "" #. none vulnerable #: ../src/functions.c:223 msgid "none" msgstr "" #. EW vulnerable #. parscore for EW #: ../src/functions.c:226 ../src/solve.c:484 msgid "EW" msgstr "" #. EW #. NS vulnerable #. parscore for NS #: ../src/functions.c:230 ../src/solve.c:477 msgid "NS" msgstr "" #. all vulnerable #: ../src/functions.c:233 msgid "all" msgstr "" #: ../src/main.c:74 ../src/print.c:405 #, c-format msgid "Could not find interface definition file: %s\n" msgstr "" #: ../src/main.c:81 ../src/print.c:413 #, c-format msgid "Could not load builder file: %s" msgstr "" #: ../src/main.c:102 msgid "Hint: tenace can only read files in .lin format" msgstr "" #: ../src/options.c:378 msgid "#" msgstr "" #: ../src/options.c:383 msgid "Title" msgstr "" #: ../src/print.c:512 msgid "Labels" msgstr "" #. FIXME: do not call this every time #: ../src/solve.c:136 msgid "Error: hands have different numbers of cards" msgstr "" #. struct timeval tv1, tv2; #: ../src/solve.c:177 ../src/solve.c:329 msgid "Thinking..." msgstr "" #: ../src/solve.c:415 msgid "Error: board must be fully dealt" msgstr "" #. parscore is pass #: ../src/solve.c:464 msgid "Par: PASS (0)\n" msgstr "" #: ../src/solve.c:466 #, c-format msgid "Par: %s %s (%+d)\n" msgstr "" #. North; translation should be a single letter #: ../src/solve.c:481 ../src/unused.c:8 msgid "N" msgstr "" #. South; translation should be a single letter #: ../src/solve.c:481 ../src/unused.c:12 msgid "S" msgstr "" #. East; translation should be a single letter #: ../src/solve.c:488 ../src/unused.c:10 msgid "E" msgstr "" #. West; translation should be a single letter #: ../src/solve.c:488 ../src/unused.c:6 msgid "W" msgstr "" #: ../src/window_bids.c:50 #, c-format msgid "Contract set to %s" msgstr "" #: ../src/window_bids.c:140 msgid "Suit was already bid from wrong side" msgstr "" #: ../src/window_board.c:145 ../src/window_board.c:209 msgid "Dealer" msgstr "" #: ../src/window_board.c:156 msgid "*" msgstr "" #: ../src/window_board.c:156 msgid "!" msgstr "" #: ../src/window_board.c:193 #, c-format msgid " - %s vs. %s" msgstr "" #: ../src/window_board.c:210 msgid "Vulnerable" msgstr "" #: ../src/window_board.c:430 msgid "Card is in play and cannot be moved" msgstr "" #: ../src/window_board.c:437 msgid "Card is in play and cannot be exchanged" msgstr "" #: ../src/window_board.c:449 ../src/window_card.c:72 ../src/window_card.c:103 msgid "Hand has already 13 cards" msgstr "" #: ../src/window_board.c:505 msgid "(no explanation)" msgstr "" #: ../src/window_board.c:775 msgid "Cannot change declarer while cards are in play" msgstr "" #: ../src/window_board.c:808 msgid "Cannot change trumps while cards are in play" msgstr "" #: ../src/window_card.c:90 msgid "All cards of that suit dealt" msgstr "" #: ../src/window_card.c:95 ../src/window_card.c:128 msgid "Card is in play and cannot be removed" msgstr "" #: ../src/window_line_entry.c:33 msgid "Parse error" msgstr "" #: ../src/window_misc.c:57 #, c-format msgid "" "\n" "DDS version: %d.%d.%d" msgstr "" #: ../src/window_play.c:46 msgid "CL" msgstr "" #: ../src/unused.c:14 msgid "NT" msgstr "" #. Spades; translation should be a single letter #: ../src/unused.c:16 msgid "Sp" msgstr "S" #. Hearts; translation should be a single letter #: ../src/unused.c:18 msgid "He" msgstr "H" #. Diamonds; translation should be a single letter #: ../src/unused.c:20 msgid "Di" msgstr "D" #. Clubs; translation should be a single letter #: ../src/unused.c:22 msgid "Cl" msgstr "C" tenace-0.18/po/nn.po000066400000000000000000000364221505733770300143130ustar00rootroot00000000000000# tenace # Copyright (C) Christoph Berg # This file is distributed under the same license as the tenace package. # # Yngve Spjeld Landro , 2016. msgid "" msgstr "" "Project-Id-Version: tenace 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-06-12 15:03+0200\n" "PO-Revision-Date: 2016-06-02 16:29+0200\n" "Last-Translator: Yngve Spjeld Landro \n" "Language-Team: NorwegianNynorsk \n" "Language: en\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 1.8.7.1\n" #: ../tenace.glade.h:1 msgid "Tenace" msgstr "Tenace" #: ../tenace.glade.h:2 msgid "_File" msgstr "_Fil" #: ../tenace.glade.h:3 msgid "Append file to board list" msgstr "Legg fila til i bordlista" #: ../tenace.glade.h:4 msgid "_Boards" msgstr "_Bord" #: ../tenace.glade.h:5 msgid "_Edit" msgstr "_Endra" #: ../tenace.glade.h:6 msgid "E-W" msgstr "A-V" #: ../tenace.glade.h:7 msgid "N-S" msgstr "N-S" #: ../tenace.glade.h:8 msgid "N-W" msgstr "N-V" #: ../tenace.glade.h:9 msgid "N-E" msgstr "N-A" #: ../tenace.glade.h:10 msgid "S-W" msgstr "S-V" #: ../tenace.glade.h:11 msgid "S-E" msgstr "S-A" #: ../tenace.glade.h:12 msgid "_Board editor..." msgstr "_Bordstyrar …" #: ../tenace.glade.h:13 msgid "Text _input..." msgstr "_Tekstinndata …" #: ../tenace.glade.h:14 msgid "Undo all cards" msgstr "Gjer om alle korta" #: ../tenace.glade.h:15 msgid "Play all cards" msgstr "Spel alle korta" #: ../tenace.glade.h:16 msgid "Show pla_y..." msgstr "Syn _spelet …" #: ../tenace.glade.h:17 msgid "_Contract" msgstr "_Kontrakt" #: ../tenace.glade.h:18 msgid "_West" msgstr "_Vest" #: ../tenace.glade.h:19 msgid "_North" msgstr "_Nord" #: ../tenace.glade.h:20 msgid "_East" msgstr "_Aust" #: ../tenace.glade.h:21 msgid "_South" msgstr "_Sør" #: ../tenace.glade.h:22 msgid "N_one" msgstr "_Ingen" #: ../tenace.glade.h:23 msgid "_North-South" msgstr "_Nord-Sør" #: ../tenace.glade.h:24 msgid "_East-West" msgstr "_Aust-Vest" #: ../tenace.glade.h:25 msgid "_All" msgstr "A_lle" #: ../tenace.glade.h:26 msgid "_1" msgstr "_1" #: ../tenace.glade.h:27 msgid "_2" msgstr "_2" #: ../tenace.glade.h:28 msgid "_3" msgstr "_3" #: ../tenace.glade.h:29 msgid "_4" msgstr "_4" #: ../tenace.glade.h:30 msgid "_5" msgstr "_5" #: ../tenace.glade.h:31 msgid "_6" msgstr "_6" #: ../tenace.glade.h:32 msgid "_7" msgstr "_7" #: ../tenace.glade.h:33 msgid "No _Trump" msgstr "_Grand" #: ../tenace.glade.h:34 msgid "♠ S_pades" msgstr "♠ S_par" #: ../tenace.glade.h:35 msgid "♥ _Hearts" msgstr "♥ _Hjarter" #: ../tenace.glade.h:36 msgid "♦ _Diamonds" msgstr "♦ _Ruter" #: ../tenace.glade.h:37 msgid "♣ _Clubs" msgstr "♣ _Kløver" #: ../tenace.glade.h:38 msgid "_No double" msgstr "_Inga dobling" #: ../tenace.glade.h:39 msgid "X _Doubled" msgstr "X _Dobla" #: ../tenace.glade.h:40 msgid "XX _Redoubled" msgstr "XX _Redobla" #: ../tenace.glade.h:41 msgid "_Bidding editor..." msgstr "_Meldingsstyrar …" #: ../tenace.glade.h:42 msgid "_Analysis" msgstr "_Analyse" #: ../tenace.glade.h:43 msgid "Double dummy analysis" msgstr "Dobbel blindemann-analyse" #: ../tenace.glade.h:44 msgid "Automatically run DD analysis" msgstr "Køyr automatisk DB-analyse" #: ../tenace.glade.h:45 msgid "Always run DD" msgstr "Køyr alltid DB" #: ../tenace.glade.h:46 msgid "Compute par score and contract" msgstr "Rekn ut snittresultat og -kontrakt" #: ../tenace.glade.h:47 msgid "Set contract to computed par contract" msgstr "Set kontrakten til Ã¥ vera likt den utrekna" #: ../tenace.glade.h:48 msgid "Open board" msgstr "Opna bordet" #: ../tenace.glade.h:49 msgid "Save board" msgstr "Lagra bordet" #: ../tenace.glade.h:50 msgid "Previous board" msgstr "Førre bordet" #: ../tenace.glade.h:51 msgid "Next board" msgstr "Neste bordet" #: ../tenace.glade.h:52 msgid "Rewind trick" msgstr "Eitt stikk attende" #: ../tenace.glade.h:53 msgid "Rewind card" msgstr "Eitt kort attende" #: ../tenace.glade.h:54 msgid "Play next card" msgstr "Spel det neste kortet" #: ../tenace.glade.h:55 msgid "Play next trick" msgstr "Spel det neste stikket" #: ../tenace.glade.h:56 msgid "Par score" msgstr "Snittresultat" #: ../tenace.glade.h:58 ../src/window_board.c:267 #, no-c-format msgid "" "NS: %d\n" "EW: %d" msgstr "" "NS: %d\n" "AV: %d" #: ../tenace.glade.h:60 msgid "East" msgstr "Aust" #: ../tenace.glade.h:61 msgid "North" msgstr "Nord" #: ../tenace.glade.h:62 msgid "South" msgstr "Sør" #: ../tenace.glade.h:63 msgid "West" msgstr "Vest" #: ../tenace.glade.h:64 msgid "Board editor" msgstr "Bordstyrar" #: ../tenace.glade.h:65 msgid "Clear board" msgstr "Tøm bordet" #: ../tenace.glade.h:66 msgid "Deal randomly" msgstr "Tilfeldig deling" #: ../tenace.glade.h:67 msgid "Bidding editor" msgstr "Meldingsstyrar" #: ../tenace.glade.h:68 msgid "Remove all bids" msgstr "Fjerna alle meldingane" #: ../tenace.glade.h:69 msgid "Remove last bid" msgstr "Fjern den siste meldinga" #: ../tenace.glade.h:70 msgid "Make bids for the current contract" msgstr "Lag meldingar for den gjeldande kontrakten" #: ../tenace.glade.h:71 msgid "Alert" msgstr "Varsel" #: ../tenace.glade.h:72 msgid "IMP Table" msgstr "IMP-tabell" #: ../tenace.glade.h:73 msgid "Play" msgstr "Spel" #: ../tenace.glade.h:74 msgid "Options" msgstr "Val" #: ../tenace.glade.h:75 msgid "Played cards " msgstr "Spelte kort" #: ../tenace.glade.h:76 msgid "Select File" msgstr "Vel fil" #: ../tenace.glade.h:77 msgid "Show" msgstr "Syn" #: ../tenace.glade.h:78 msgid "Text" msgstr "Tekst" #: ../tenace.glade.h:79 msgid "Cards" msgstr "Kort" #: ../tenace.glade.h:80 msgid "Show as " msgstr "Syn som" #: ../tenace.glade.h:81 msgid "Filename" msgstr "Filnamn" #: ../tenace.glade.h:82 msgid "Card width " msgstr "Kortbreidde" #: ../tenace.glade.h:83 msgid "Card display" msgstr "Kortsyning" #: ../tenace.glade.h:84 msgid "All" msgstr "Alle" #: ../tenace.glade.h:85 msgid "North-South" msgstr "Nord-Sør" #: ../tenace.glade.h:86 msgid "East-West" msgstr "Aust-Vest" #: ../tenace.glade.h:87 msgid "None" msgstr "Ingen" #: ../tenace.glade.h:88 msgid "Show DD scores " msgstr "Syn DB-resultata" #: ../tenace.glade.h:89 msgid "Show hands " msgstr "Syn hendene" #: ../tenace.glade.h:90 msgid "Hands" msgstr "Hender" #: ../tenace.glade.h:91 msgid "Players " msgstr "Spelarar" #: ../tenace.glade.h:92 msgid "Title " msgstr "Tittel" #: ../tenace.glade.h:93 msgid "Current board" msgstr "Gjeldande bord" #: ../tenace.glade.h:94 msgid "Board list" msgstr "Bordliste" #: ../tenace.glade.h:95 msgid "deals" msgstr "spel" #: ../tenace.glade.h:96 msgid "Generate" msgstr "Lag" #: ../tenace.glade.h:97 msgid "(C) 2005-2016 Christoph Berg" msgstr "(C) 2005-2016 Christoph Berg" #: ../tenace.glade.h:98 msgid "Bridge Hand Viewer and Editor" msgstr "Bridgehandsynar og -styrar" #: ../tenace.glade.h:99 msgid "Homepage" msgstr "Heimesida" #: ../tenace.glade.h:100 msgid "" "tenace - bridge hand viewer and editor\n" "Copyright (C) Christoph Berg \n" "\n" "This program is free software; you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 2 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details." msgstr "" "tenace - bridge hand viewer and editor\n" "Copyright (C) Christoph Berg \n" "\n" "This program is free software; you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 2 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details." #. TRANSLATORS: Replace this string with your names, one name per line. #: ../tenace.glade.h:113 msgid "de: Christoph Berg " msgstr "nn: Yngve Spjeld Landro " #: ../tenace.glade.h:114 msgid "Text input" msgstr "Tekstinndata" #: ../tenace.glade.h:115 msgid "Hand as string" msgstr "Handa som tekst" #: ../tenace.glade.h:116 msgid "Set hand" msgstr "Lag handa" #. newly created board #: ../src/bridge.c:141 ../src/callbacks.c:501 ../src/window_board.c:674 #, c-format msgid "Board %d" msgstr "Bord %d" #: ../src/bridge.c:341 msgid "Card is not in your hand" msgstr "Kortet er ikkje pÃ¥ handa di" #: ../src/bridge.c:346 msgid "Not your turn" msgstr "Det er ikkje din tur" #: ../src/bridge.c:356 msgid "Please follow suit" msgstr "Følg farge" #: ../src/bridge.c:410 msgid "Nothing to undo" msgstr "Ingenting Ã¥ gjera om" #: ../src/bridge.c:456 msgid "No cards left to play" msgstr "Ingen fleire kort Ã¥ spela" #: ../src/bridge.c:460 msgid "Which card should I play?" msgstr "Kva kort skal eg spela?" #: ../src/bridge.c:466 #, c-format msgid "Declarer claims %d tricks" msgstr "Speleføraren krev %d stikk" #: ../src/bridge.c:471 msgid "Card was already played" msgstr "Kortet var alleiereie spelt" #: ../src/bridge.c:475 msgid "Card belongs to wrong player" msgstr "Kortet tilhøyrer feil spelar" #: ../src/bridge.c:512 msgid "Bidding is over" msgstr "Meldingane er ferdige" #: ../src/bridge.c:518 msgid "Invalid double" msgstr "Ugyldig dobling" #: ../src/bridge.c:524 msgid "Invalid redouble" msgstr "Ugyldig redobling" #: ../src/bridge.c:529 msgid "Insufficient bid" msgstr "For lÃ¥g melding" #: ../src/callbacks.c:452 ../src/callbacks.c:479 msgid "No board" msgstr "Ikkje noko bord" #: ../src/callbacks.c:495 msgid "Cut buffer is empty" msgstr "Mellomlageret er tomt" #: ../src/callbacks.c:644 msgid "No previous board" msgstr "Ikkje noko tidlegare bord" #: ../src/callbacks.c:660 msgid "No next board" msgstr "Ingen fleire bord" #: ../src/file.c:35 msgid "Bridge files" msgstr "Bridgefiler" #: ../src/file.c:40 msgid "LIN files" msgstr "LIN-filer" #: ../src/file.c:44 msgid "PBN files" msgstr "PBN-filer" #: ../src/file.c:48 msgid "All files" msgstr "Alle filer" #: ../src/file.c:172 msgid "Closed" msgstr "Lukka" #: ../src/file.c:173 msgid "Open" msgstr "Open" #: ../src/file.c:173 msgid "Board" msgstr "Bord" #: ../src/file.c:436 #, c-format msgid "Error loading file '%s': %s" msgstr "Klarte ikkje Ã¥ lasta fila '%s': %s" #: ../src/file.c:457 msgid "Open File" msgstr "Opna fil" #: ../src/file.c:717 ../src/file.c:757 #, c-format msgid "Error saving file '%s': %s" msgstr "Klarte ikkje Ã¥ lagra '%s': %s" #: ../src/file.c:725 msgid "Save File" msgstr "Lagra fila" #: ../src/file.c:735 msgid "hand.lin" msgstr "hand.lin" #: ../src/functions.c:145 ../src/functions.c:202 ../src/functions.c:213 #: ../src/window_bids.c:75 #, c-format msgid "X" msgstr "X" #: ../src/functions.c:147 ../src/functions.c:202 ../src/functions.c:213 #: ../src/window_bids.c:78 #, c-format msgid "XX" msgstr "XX" #: ../src/functions.c:199 ../src/functions.c:210 ../src/window_bids.c:72 msgid "PASS" msgstr "PASS" #. none vulnerable #: ../src/functions.c:223 msgid "none" msgstr "ingen" #. EW vulnerable #. parscore for EW #: ../src/functions.c:226 ../src/solve.c:484 msgid "EW" msgstr "AV" #. EW #. NS vulnerable #. parscore for NS #: ../src/functions.c:230 ../src/solve.c:477 msgid "NS" msgstr "NS" #. all vulnerable #: ../src/functions.c:233 msgid "all" msgstr "alle" #: ../src/main.c:74 ../src/print.c:405 #, c-format msgid "Could not find interface definition file: %s\n" msgstr "Fann ikkje grensesnittdefinisjonsfila: %s\n" #: ../src/main.c:81 ../src/print.c:413 #, c-format msgid "Could not load builder file: %s" msgstr "Klarte ikkje Ã¥ lasta byggfila: %s" #: ../src/main.c:102 msgid "Hint: tenace can only read files in .lin format" msgstr "Hint: tenace kan berre lesa filer i .lin-formatet" #: ../src/options.c:378 msgid "#" msgstr "#" #: ../src/options.c:383 msgid "Title" msgstr "Tittel" #: ../src/print.c:512 msgid "Labels" msgstr "Merke" #. FIXME: do not call this every time #: ../src/solve.c:136 msgid "Error: hands have different numbers of cards" msgstr "Feil: hendene har ulike tal kort" #. struct timeval tv1, tv2; #: ../src/solve.c:177 ../src/solve.c:329 msgid "Thinking..." msgstr "Tenkjer …" #: ../src/solve.c:415 msgid "Error: board must be fully dealt" msgstr "Feil: utdelinga mÃ¥ vera heilt ferdig" #. parscore is pass #: ../src/solve.c:464 msgid "Par: PASS (0)\n" msgstr "Par: PASS (0)\n" #: ../src/solve.c:466 #, c-format msgid "Par: %s %s (%+d)\n" msgstr "Par: %s %s (%+d)\n" #. North; translation should be a single letter #: ../src/solve.c:481 ../src/unused.c:8 msgid "N" msgstr "N" #. South; translation should be a single letter #: ../src/solve.c:481 ../src/unused.c:12 msgid "S" msgstr "S" #. East; translation should be a single letter #: ../src/solve.c:488 ../src/unused.c:10 msgid "E" msgstr "A" #. West; translation should be a single letter #: ../src/solve.c:488 ../src/unused.c:6 msgid "W" msgstr "V" #: ../src/window_bids.c:50 #, c-format msgid "Contract set to %s" msgstr "Kontrakten er %s" #: ../src/window_bids.c:140 msgid "Suit was already bid from wrong side" msgstr "Fargen er allereie meld frÃ¥ feil side" #: ../src/window_board.c:145 ../src/window_board.c:209 msgid "Dealer" msgstr "Gjevar" #: ../src/window_board.c:156 msgid "*" msgstr "*" #: ../src/window_board.c:156 msgid "!" msgstr "!" #: ../src/window_board.c:193 #, c-format msgid " - %s vs. %s" msgstr " - %s vs. %s" #: ../src/window_board.c:210 msgid "Vulnerable" msgstr "I sonen" #: ../src/window_board.c:430 msgid "Card is in play and cannot be moved" msgstr "Kortet er spelt og kan ikkje flyttast" #: ../src/window_board.c:437 msgid "Card is in play and cannot be exchanged" msgstr "Kortet er spelt og kan ikkje endrast" #: ../src/window_board.c:449 ../src/window_card.c:72 ../src/window_card.c:103 msgid "Hand has already 13 cards" msgstr "Handa har allereie 13 kort" #: ../src/window_board.c:505 msgid "(no explanation)" msgstr "(inga forklaring)" #: ../src/window_board.c:775 msgid "Cannot change declarer while cards are in play" msgstr "Kan ikkje endra speleføraren nÃ¥r korta vert spelte" #: ../src/window_board.c:808 msgid "Cannot change trumps while cards are in play" msgstr "Kan ikkje endra trumffargen nÃ¥r korta vert spelte" #: ../src/window_card.c:90 msgid "All cards of that suit dealt" msgstr "Alle korta i fargen er delte ut" #: ../src/window_card.c:95 ../src/window_card.c:128 msgid "Card is in play and cannot be removed" msgstr "Kortet er spelt og kan ikkje fjernast" #: ../src/window_line_entry.c:33 msgid "Parse error" msgstr "Lesefeil" #: ../src/window_misc.c:57 #, c-format msgid "" "\n" "DDS version: %d.%d.%d" msgstr "" "\n" "DDS-utgÃ¥ve: %d.%d.%d" #: ../src/window_play.c:46 msgid "CL" msgstr "CL" #: ../src/unused.c:14 msgid "NT" msgstr "NT" #. Spades; translation should be a single letter #: ../src/unused.c:16 msgid "Sp" msgstr "S" #. Hearts; translation should be a single letter #: ../src/unused.c:18 msgid "He" msgstr "H" #. Diamonds; translation should be a single letter #: ../src/unused.c:20 msgid "Di" msgstr "D" #. Clubs; translation should be a single letter #: ../src/unused.c:22 msgid "Cl" msgstr "C" tenace-0.18/screenshots/000077500000000000000000000000001505733770300152535ustar00rootroot00000000000000tenace-0.18/screenshots/board_cards.png000066400000000000000000002072601505733770300202330ustar00rootroot00000000000000‰PNG  IHDRZ†7Æ pHYsˆˆÈ¥†tIMEâ  ;ŸLòXtEXtCommentCreated with GIMPW IDATxÚìw\GÇ»wÇz,`¡)XA±!6£"–ØbÔØ&¦j|Õ$&Æ-š¨ÑX[4Æ+‚½€Ø^®oyÿ8vu¾bîöÙ™›ß>S)žçA Â[ EQBïß"yA „·“3§Ž IF@ä@ "‡@ 9$È!@ //‡\ò†w[Þ™õzÍÕàR¶ k9fÛ3þŒîíåõ,ᵕCRéúš<ðÖÉ!Ÿ½óƒVîž>EÞã.†o¿´a Uåi1ˆË£q‹íÃÇ.:þXûμR™ãÞ¸Ó¬s姘®7z‡>ëØÄu[Û›W©*˜ËŽÙõݤw;ú7ññ è>âãG**ÒK¥¡jƒâ¬ÔØ+pÜÞÌW I†Ï…@ ¼­Mª-Þßr|¦¯°&Ò£‹S§ÇlûbÂŒηŒ¨÷îá¬ÉÌ)á¬Óß ™vªîè/~ú_[OG3Eʨì‰lûYwË×µjcvý•Û-¼Ù¥]ÿ$÷}Ï…ôh„ÿœwXÆ{|¹-K|^ÜöÿêÖÆ¯IóöÝG-ø'Qýé;¶èÖœK|ø„Õ¹iç~š2 ]«VÞ¾]Â?ZÎò÷Nðu÷ôñðjÞ,¨ïØ%§S ÏŽ_Óßø÷ë?Ô­US¿)UÌ“ç¿ßÓ¯™¯oç³öÜW¦8çÒ/Ÿ„wjãÓ¢}×w¿üõrWEÙZvtϳNsäÓ‹n(N|ÑÖÃÓ§É»¿%™±6fýw{¨¡KVMíÞ´¶¥™PlãÒ¢×ÄïuZXv.ércþ†/ßíÖªi«V!£¾ÿ7-m‰LK/;o>7fë¬ÑÝÛú5mÝcÈì½wêÊß@½ç°åÀi³>è‘¶oÏ]}4e'»ü‡nPFSwŒõí·æyH×÷o5|Ã#®ì'nX¤«­H„7NË•É'»>™°6³ó÷{ÏÆ\Ø9»Åͯ§¬¹¡©´ ¤ÎˆÝw覬•¿»¿qÚôˆXûïù«G÷.Ø:ù“X–ák¯>¸wÿÎå3›Æ;ž˜õÕ®T}ý¥½t4®Õÿvœ¹²²Ç“_?žyÌaüÖÈèÈß':FŠe€½»õ›5i—î¿|éЦ/Ú¤ž:ŸQ%MuìÃ2£3À¬Çâ]Ÿµ…,ˆ¾/îöŽ‘¦ûClBTdŠk÷°fÒ2lååíåwýgÿqþêÉÍC{æ¬>§*3 ™Ö˱ì¼å’·¸í¢Ç¸ÙÃ[×–‰¤µÛOœØ=÷èÁ8¦Â¾§../ß6—?l=í£nöÀ>8¼ï¶×胛ى%Ž­Þÿrˆëý‡ }ÊÌÖ3tÚPë§/6þñ»ÍìÅ4؇Ük>þ‹¾­Å²ºA“§÷­£»o‘ØL`&1—ŠÍ,ëµê÷Õ§½jU¸ûÈ s<}Ü›ŽÙöŒ/7ºª€ÏÎ̆­cYý\FsIäûÞÇý½íÄf6M#z6/xp/­L·çy¦•—·ìÃ;®4øàëqê[J,ëúž5µ“ä¥Þ£žÞ}¿ãˆöh÷CÜÏì=›_d4šì2ºÞbÝáÝžüÁç (¢ÿø;·Ó€îŽ” O¼ Š@x-©xß!—¼áײ*µ´§iê s:6›ó¼N²è[á¦&}\<+O¹úÛŒéïÏ´úkqwëŒôL³º®Ž…•´ ®K]d¥gph ¹ÿײù¿»–˜Q ey"ÿà<V@;Ô²èÒ–‘‘i^§®MaÅ&¬]×™~@à6|ñwÚ5 'DäÒvî­{Ù¯©5U¹6gÞ/;º*²µ·Å¥ô,µK=‚òrÉeem©3PB3†-ûvŠ2 P•™·Òô´ 3×ÎU¥ðÜÃ}{.$Ü:×b{Q±aetéï@¡¼d«ÊèEHüõ³¾ëHzpçèÝÇÝ–w´¤LxâUQ$Â뚃“ƒ¬ãço>¸Wøw÷Â’.f•­õæuü‡¼ã“}êÄ -h;ÍÓ¤ÂþB°O’žÀÎÑžæ’þœýõ¥†Ó=~éêÝ»±gg·r†VQú´9ØËŸ>É)´°)Oõk’†Ý&.ܰuï峂ž.óõÁ\¾*²¢¼èŠÝ!E¡»k µ¯ýøØ¡›ª²â-3—ŒärYi(Ì´òò–vtrÔ:÷ý…O¼šŠ@x‹ät½ÁK×N°?=gpH‹€°‘ßa{ ho^aÔuÅyxµð ûì ´ÿâ%ï¹ û˜å‹û3;Æ·nÑuú~é»?-Ú@A£A3&8ž˜Ö³eËàó®ztl!*[ <Æ,›×9uõàvACJmÚL"ÿˆÖÑ‹ÇöökÙyèÚ¬nß}ÙǪ\‚õS[ۛǗ]qoʦë˜Nǧz7­àPLÊ.xÖŽMêÇ­›Ô»cÓfm»^rJØsp{Ëòr©üŒ¥¡Ü¼¥]†.[=±vôœÁ~G/‰óéî'®äíðYÇwžàÛ´ó6Ì©ÇV)í¼¢*ïmÃćʦóÀžâ¥_ÿ¾ Ëù ŸxU ðZBñ%Ž<¸WM *W DZ ®ÖÔ¾v¹ôÊn‡WÞÿsó1qت.D ‹yÖd ûÚÕæ¯$Á¯£æ½‚ÛÑœú4hêaqÓ!ßO”’Ÿ9@xi9$^KÌ‚_ŽYLò@ ˜ Y’@ "‡@ 9$º¾Ã3§Ž“Œ @ „·ª2ëLð&i!E UiðÖ¢ë1$Ci@ rH ‘C@ Ê–CݪÊUû/@ ÿeJnðäîéó†-M ‚ÊÞà©Êµð…úʰÇU&d€ÐdëÂÛÇ(Óâ·ågœU$©äEˬ\j{}hW·ÉáåVT½*ŠñÐVí¹y0úhê{?«P°ßô]Èó|¿Æ÷õ~ùD>οéjÙ´Z3ºJ¢ÐîÜ•Ü×ñõóež]zâ‹zú¸· ’Z8Š%§É˺}íÜR2ÅÙý=’ÃBËa {‡‡/=9(ÄÌLvgC…‚ÍÙS©ToüóÄËËáÜ+ëo~øCû¨jÍè_b§½ë5×Û¾ÃK†3jìT2Oô5¥ÒÏ.ãñþ'qßwë?^fÈó,EÑŒ*–Qœ±ÕîÐ룣;çÛÕía&uªDÈZFû0>!33++'€½½[£†"¡ˆvôPß°Uâò<84EùUp­8zÑ™—_].6ãäþÄÅ{Î_ºïÃÈëI¡?l;½XË©ýœÂjæéRµsïÞ¢¯ÃÃK¯ÉŸ˜xëΕJUU‘¦¦=»tõ Ã0­¶„æ1½@°SS322•*¥»››é¦J¾” EQ»÷í+êëîß§MW×T¥|¹jä—¿NÑ¥gǦB‘4.V[§Io÷V®¾UÆ£˜oÄÒ+u\F0ŠóöuzÞÛU -|”ôdØ‘ñ ñ¿nÚú$#O"‘º»ÖîÓ«ëàCŽ?€("á­‚.­^EŸ3³2쟦ÝLN¹¡û{šçèàœž™nz/l}åyžªø€ŠzÙÕV¯=;¼?qÑǽVÖ·jQ3yíjÕ죞+>]{>uoÉ!€aÆ8 è«!·îÜz””ôNïwª*ÆGÇܼ٫W/™TF2Ñd ½{÷~’šW!Så(/@]†÷6lMÓU#¹~Ùyvp¿u;£ŽGÝvr{¿qÇ-µ=FZØ5§…R‰…‹k³™ã.D 8í#‰¬žFñ¬Bkí•k×{të¹ã?æ-[Ç[ÖíÑwà{ï®ïí¿åï³._ëÖµû•k×µŒ–T‘âꄊ£(šãØ¢#ÇB¡P¸þ·Åe'ýZµh`¢w€ãyè«•c'½0ÅÝBz (p/¡†Sÿ:öd݇=—ŠDf ¯ª™¼fx•@(ø°ÇÒG>Ѳªu‡Ô€ ê*qº0‡)÷+×®³<߯o¸ÎQ{É7 Š¢nݹ›’–Þ_*•š‰E¦˜Lu{{‡>}úœü÷ø…ËWZûùêîȈée^ ʰ0RŠ¢KägÕ’ø$ãܵÄ5?}”έþ#rڰΚxÏÝ»ðIVòQb™=hkp ¡H¢VæžßåÀ®^wÏÀ% ^à³Þ»ÿ0,´wRÒãQ×úö‹x÷ÎÇ«µÚFuj9ÜŒ»Õ877$8äaüƒÆž^¤–$¼¥røBõÊ/x6uÊgåU,Ëþ´r‘¡¾Ð;äøçaé¤ÎD*]wG>Ùùì÷‰=æSB>‹yd+t0ýT«ÒgŠE²ž &w¬;ÔÄ/¤íÝÿ`©R[Pö+9¯ÊgS¥ë‰Ý¿ÿåøWZ^RoT5{‡@ë«ï¢ZeÙó/ÚØÚ¶oß)¿ ÇÚÊöåÝÐ+ׯkµL¿~á*•RĈ8½X1Užçó òBºvŽŽŠŒŠj _hªåHéïˆz.ÆÕ²!Ì¿1r†áo'f6m°bëY¡PÐÎ×í°à®:ÅÕ­~cߡσ¡hñ€‰[ï_ß/Á½õ/ÔBYÙ™2sË5ë7¶mÛ»kPž\©Ö09ùòœ¥B¥nÔ°AÜýÄÖ-šdff‘*’@¼Ãr%'7?%7?¥¼àê:7g9¦BúÊq•”5¦Rîá‰ä3÷Œî6‡¨³˜§Åƒû~h­—Ø„¼+¿þ±}wiʤ.¢ý—î:ÁÝ6†°LÍP3ùJ.GFÛê2{ÿ_kEhƒÉÕ­‡EÕ·î“J­Ž<åîáéëë››­R+­,m^Æ;ä8îü¥‹–VÖ]»öÈ+ÈU*åR‰<(PFLõØxðJ¥‚帠  Ø˜˜“g";I¥’òL‰¸·c$.‰D¬ËOš¢ ýÅêQÃsWÀÌ’6·WjØŒ9—Àû´ô[¶ù´H(hÞ¦Í<ƒ~¹}z°ÔüŸz ½(JÆj¦>¾{÷æ5ŸàÝ´@lJÙ9¹2™4+'?,¼¹B©*P¨Ò2sXž¥@™Ñ XڈŒ¬ìlREˆwø\+4z³tôBïåxè¯2½±”çÁU\'®ŠÉ;:²Ë*OÎdê>R]Ô¥\— žçÁƒçy-u”4`9-ËkiʤZF©)p”5|ª¸­áäE‚Þx^ÏPqù2Úî½.3¶\¤MP¾ÓðÓêRÃÂÆ½Â^.š¢óäygÏkèéé•““¥Õj(C·±ââ¡ÑjÎDE»5ró÷õÏÍÏÑhT…òKQ ÃD_¾Ø¨aISåš)PM3ZMvNVóæ-,-,Oœ>Ý©C‡òLíÛYYXTNàË ÐÎÆ¶˜wНj=dXî§ßÿ5~\jF—ö¬\ÅíxÞ«™ï¢'gŽ´òvˆ,¼ÚoŽ95@"µ©UoYVêå+gÿñî¼Khfeúƒãy^&•H%’윜\¹R@ó"žâ)ÐÀÃÜRÆóEÖ4&ïÐ@ÞÔ*æeäð…Þ!Ër<|…ÖR&2±±4_©åy¾¢r¸?~ñEÔÎÓäü³mV¡èñàyþWx˜çåL–ƒ8¿¢š&˜©I4ÚQúª_÷^$@QE)‘g.´ü᮳kvÝŸáñU QTqï0++ëLTd÷n¡Îεóòr8Ž¥) ECB*(ŠEÉʳçδôôôÊÍÏf†¢(š¢AQàù‹W®ú¶òóôô,a¢+ÚXª¿ -xžãró²6jdaiyòÔÉòL‡nÛºµƒƒ}Å=*?®ÃG·oÛ†}‡UåÞះ.µïÔ¡€ÈUª¢lÊÎWÞML÷òi9ÿ׳ÇwkêYW$±oÒaË…ßmÖ:9æâ‰Æ~Ëj›‹µB^àR×)##ÃÆÖÆL@Q<Š×• ¼™€R«¶¶Ö¤Š$¼=Yª“7š1ý¯rÞ!ÏóœŠÏS˜4Œ-_¡ýótÏóŒÉn+þÏûß>TïØ'¡à|R~l¾*3_™•§ÌÊWfæ+3ò•™yª¬|eV¾"3W‘žšÿð^VÔìËjµº¢"¡Õ2ñYWîfžKÉ«HÏWdæ+³òT)³ò•YùªÌäü›ñò¨ÎaOÙØ÷fóþläÙÎÁÿ:X¦)¸C{K ‹Š.o$®àíííìuVº¨±´ªñkÚ`é>[´qè°–‡:ŽVukY‰¡¸}vÒÐΡ —½UgeÝ]¶"=*Zþ4żNmÇ ¶^OÛÙ™ú³ ýZµJìØ¾Kóæ­ÕêÓ~ib†áݸ¢…O€T"3¥ïãøô¬ÜúLlhp`SŸ¦4MóXÈd]‚CÎFžUÈå-[ùÉr–ÕR¥f%š|»¼P(ìܱcÔÅ ùy;†¨T -£¡(/;uèuá|)Så¼CZ@ hm.³¼qãúÍ[±];ËÌÍË3‰Åf•Ú*…2 N¿Ÿçjõü&ÖsX÷͈Ïî”ðj/W«k—¯øûÔݺx¬¥Þ)Ì8ñêÇŸºµhѰKܤ¤g±q'z„µþi¹C›SÛKíj÷Þ!Á!>ÞM$ Ïójµ&//çà¡SR©ÌýñäéŸ×«[wPD_ŸÆdö!á­÷N¥RÕwõP(rÊ\SB”J­-­Ñ(¥Lè;Ô2Ëq,ËC•Ù¢y µZ½iË–¼¼»/>ýT&“™››Ëd²ììlï&Þœb£ÀŠ(Žå4LÅ*;š¼ç½èϻߞ‹=ÔÚ³ ¯¥ŸæÝåy´®Ý ž×y›ú5ÇÝvâhÓµJ,ÝO½Úľ“@@ë< ]{%ESºZôâÓ½gK÷ÚfM¢nq‘4êý Umã÷¨âºHÇ™‰D!ÁÏEGåÈ;vè¤V+KÌJ¬¨"RÕ!(èòÕ«‡èÑ£—@ ¤)šž§€2MTÅoƒ¢(33±D,=™’ò¤kpgš¢u/+eš*¹mXùqq§w£éb¾d5`gm¾zÎð9?íKNÍž3¹g3ÏzE&uVÖå§µébmi©‰OÐfdH•J—Zµl|š^úpZÈ‘L÷ìí»têô0áAffVnn.kkk{{»N´ZfÜ”éãÆ²¶¶^²bÕ'“'úxE$¼ÝÞa¼ÀÂÜR$)UZƤÕ[d”MZÚS[k‡rôµ$ [8F”¢(@ ;ëí=:óÖKKs™ÌB(fdddgg+•J4MËq•X¿›5ØköøåÑ·ÿiÕ°/$d_çêhì–Ò^ ÏsB¡¤·ÛTÚd¹zÇíã¿.{˜W¦Âuo>B£ÒºÚ4sºDÇifÒÏýóê}¼Ï½ÃçcGyž£(ªcû._>|ä`h÷žte½Ã"EäX¶µŸß͸[»÷î ïÛŸôÑ1Uà©énA"–=vX£QwêÐç8žç(Ë3Uö‚2`ñ.C Õ¸H›ØL8zÇqA±²twÙŠúuëÙȤìR¥B¤Pª ò,ëÔ­wwÙŠæßÎ5=@àéæ·2Ž7rk•]¿^ÝÙ3>ÿfþÂO¦LðiÒ˜Ô˜„·×;”ˆemi­TçšøºMS¢”Ô$[‡2õµ,9dYŽ+lS¤i‰D€ˆèÖGÖiavv¶îõœ¢i,ÇiY¶r÷Ü»Ñ4™Èúäýßš¹¶k`éÇ0,Ëi—_{ùÜl['¢mˆ2MŸi£Õhê[úš l.Ýÿ7¨ÎàîõÇV÷Ó-ª¯õcG©çƱmbnÆîÞ»³WhØK¶ýñ<ÏhµM}¼e ìØþÎ;}4í MòØòòr?jmeé؆a´…ýŽFL/áP— eønQ}­¥/3%´@FTtËFnÌ©Z%Q(Y…‚’Ë5€êþ}‡fÍîDEWUìC„3ÉùóÑ=C»}>}Ú‚%Ë?›:É»±'©4 ow(—Ëu®X½ºõ4¹F£0%8‘P±ü£GñušâòðÇë”ÏÜܼD]V¤…ÙÙÙæææEÃæY–Ój+?3!Äå} ‘õ_–z9ùk55´N±VËМÙG§z¸Nl_ïÝšˆ’€õ¿®+]}ó<Ï0ÚæM›ÝøpÇŸÛ«Ä×a´ÚF J¥Ò»w²,c “‰¢¾cçŸÆ½<<‹ëS¹¦—y(7@ŠðÛæM(¡‹5ˆüiŠ´y í¥Kb‘ˆâyZ.§X–¸‚‰……üiJ¥Cæž/ÅpoÔpæ§Ó¾_¼üð‘ãÁÚO7jÑŠÕ_|4¥±§;©7 o—w˜››'  £‹¥4-¶±ªoššk´ê´g) ê5y¡wÈqœƒ•$ùé3''Ǭ\èä¢(kk»ÜØ5ææVÒÓÓuZ¨Ñh¬­­ «,žgÙBïe¹ÒoЦà.Zí¸=ËÕ®YÍäuj^â£Ì›=gù:õ¬™)ŠzoØp#.V«ñps“J$â«$FF«­$”+ IDATíäÜ¡ÃØ±Xd¨%FL/p=:ε뻺ºº¸hµM•tsH>¤Ø¶uMÿbeujH$EV P€`ÊÂBUP`^§vÅî—ç9ŽçyŽ+ü_á´&µQÃúŸ}4yÑ«p:²c‡ ð>=×mܼtþ7¤Þ$¼]Þ!FÍ6ü¶V"›E]¿ž›µ•Ý ½CµZýa˜ó»±,+Ëxž× ]»zB¡x–eiš‹ÅNNNºŸ(Ïó6æf  PJ…š¢!—Ë­¬,+wó-ºH›Zü÷QÍäuBÆ‘M{Ûµ¯±§«¿x0°V«©[§Ž‹K=†aª$R†ÑÚÚX‡wf†eMF`¦c‡öÇ•Ö'#¦Êa<@…¢à•ÿbƒÚ¦ÆÆÕ÷ð(¸pA P¨‘‡GZzºcPÛ ºƒžz¢G˜µOS‹À@Åýû\Aea!òðÈž>IÙðs… }tŽã†Ñ2 £e8ŽÕ2 Çr,ËÚZ[ñîŸ{œŽI®Ð¼Ã2}DVÇq,˰,˰ÇéV癉Äfb©T" ¼³¯#gN=nZI9|Ἀ*}ç4J­f¶¢# (Š¢iJ,‹ÅÒtCxÛxÉUiÊ£¨K¢èW†W4bˆ@¨y9|ᚥÕèê¦UèfVÓÛÙUh~¡éo™Dÿo-eïhQ…ÿÖ˜¯I Bå_«»ï@ „ÿ2ºÆRÒëF ˆ¡ÎO$A @ o5~&™@ „·ÒwH ‘C@ ˆ@ä@  ôOB5â÷r—_!9H¨ü8¾æ#-±s‰·æÓS¹!¢D ›̕+5úuöìYï+¤(=•€4–@ä@È&‡/ ÌÆŠ&ÿyÊi,}üÄ PêÛmp –’Ü· Ü„À/@SÀ×Àß@0°Ø„Ë(@8!@Pu–Uðy‡±À À ˜,z»€ª3ï?“I-ö¶Â+®²—k€ÑÀSàwàÉPðòÞ!ì:=ôGüØÀ€;ðx8ƒ&°¸¨w`à¤÷€G€ 0hA²Pê­ì*p ©lÐÀ=}™Ìö±@>` ´ú性ÀV °:„sØ4> €™|X‹€x`0ÐÈö1@>`¡¤Uƒ@xüÃ4 h]ü`SÀ ¸§ÿz  ü´Ö™ü ä_K€†ÀZ€ÑŸ –€m€–d;¡8!€X¨_.Ý`o3€XDe€?pX °€X <B™@ ÀêCðh Pê; X PÉ xZ`ph ,€úØ Â"‡r€eñƒÀÈ×í¸" pn©À}à]À½ðØ ²s„@ ²I¶Šã D‰Àî—ÂX@ ˜ëg7Þ’3½Ö† xÜ2!Ð Zékö€Hî€pH4€-àÜ’3  :¥ÿí„דRí;2@>`kp䀅þ«ƒ˜Ú¹@ ¾4¸„2O™¬â%ºˆ¯†“ 7®_1ÓÊ>FM@ãŠGsA?zS j²"ýp@. Ò›t~¤@ë‹¥ðžwû€à`ð€' Ї¬>2HdR“Ò»Z>jìTR<*ÄÆõ+FóÓª'l.eÇ„»š¯ûcŠ·—úÇ„ð%z¯øû«6fPpô‹w›û÷ìöâêùäìŸÖë›óvý~ÜñU€{¼yôÐS]wü2¼^õŽþ×E¥1p‘ìûÿt`f ¨&®*þðš›]KÌ¡í4ëÐÔ¨¾­E5^ÆJÉ¡3` \\ Þ4€—þkFQ)²/ÀóJ¹•DùH-¶~…îà ê2[à}`p¾âqï'€=À&À ðl PZ@<@ë˪Τћ jàpÈÚpP”^ªí ?èÕðÅÑFóÓ°ž PÍot-?ן¢¯<å¼]hð×/'Ôm`yãÒ}¶ÐÄ]ŽášOmnVi Ì­”GWmØzœWMë]gè/{¦·|e}ßšk«§Ï‹ö±dwˆ›¬ )öìží»®5Pãz(,ãÀàWÀhˆ€›À6 +PK_kœ| HZv€° ˆ¬'Àq`x©Ê‚ðVbêK}°H¬lAîÜâ€mÀLÀ¨ <N] 4ܰ2nÀ)€7h/u„@@n ð@: <õzYH=%pˆÆTCžtrˆêu¦ ý}í~¿t-g¸‹¥¹y)®Q¿=öì¼ò„óq¥Ù—¯æ{ leQ­ßi§ž£ZEnXu ÏáÎoÕ|pîÙ­›éõº¾ÚÄAHÝûøjRRV¶·>î3éÀ! ?ðŽÁ þÀà#àð`PÀ€°˜ü´$&§â0X¨€ÉÀd ‡Ôob`âK¬ AýœDÀT 8 L.€É€@Q#à0ð-PKߌ¯Ã ¨ °ê΀ ` Ó€NÀy`:°¸„‘5-^g„MZ·2‹»£˜{—cl|:4M½|5‡—rõJªkk¿ZÕý|e~cÆûßÙ°>:ÿí”E×òiæ”|dãö3·žäj^e‹b9þ±`äåµ0¸ô³†CJ©íLƒ¯R`EY¶Ú‘_äÛ l)~¤ p±"—Ï,~¤°Òà«5ð^9×Ö>7øÚ£x°3ŠŸ¼ Ôå–e•v`¾Á×ùä¿.HZ´n¦]w鎶£ý•«ê–Sš»ù{οp]Ù§ÕÕKìü>lPýo;”}·‰Ãÿ½jÛÀÖce5éž=ÝöA›múof3ö­Šp¬Á9àf-'¯\äøÛ¿ÌØøðcëØcØ„1=Éj¼©R@YùµöÈþûrB†ãÕ”¦ý¼E”¤•_í_.Å.lj[F4®‘ªRÐpà”Þ}ºê@ïOjòµô÷fuÚŸÑv8À)Rb­úæë)¹–»fÕ´ ’ö@íäç_'ér䱋w=ý[HºŽoKÉõèç¯iš4—ÔP2¤­Fo}oÃÏ‘yoå4VZV»e¿Ý]rnÆ&³5{…OŸ ’ß@x³4jío·cËg__[ €ÀÿYö?›ÿÍôô÷µª±¶CʮۤN§7þ•ô¶ŒËçRö}ûùŠýï§æių¸¶M²ôjRGPã)!¥„„ìßKøï"òöo)ÞyLÖ˯p®Ÿ¨©Såþ³.ýüœj²®?`Jß=¶+jLŠõ¬ÃÜÃK{×Ü íÜmdŸ=[6Í\“”ËIí4ëô鲉,j¾9$…|wâÒwŽšUÏÅgzÖ„GhÓgÅÙ>Ï¿KZMßsazÍ8£6}VDõyµùNÉ\Ûÿªýð¯^u }‡@ TT“€“ÀÜÎ,ÆF ÂëIY¥·€#ÀC@ ´"ô{â\~@ |\Ž+3søˆ%Ž_»vmÍš5,˦¦¦~òÉ'¶oß¾zõê„„„«W¯vîÜY äççOž<ÀéÓ§gÍšåêêZtù“'O\]]_9qbú‰·üWü˜Ÿ >€ÚC C(«ÛAùÇPÇ®$ÀÇCþ$S߈ÛXÙbÇW˜Ô­ •Íû”…ÿˆ)6H^_¨|É¿a`<~x².cΌ؂ö’ªL-YJ¨ix–÷öö0hР~ýú5kÖìØ±cŽŽŽK—.åùB€ÜÜ܈ˆˆÀÀÀtëÖ-==ÝÍÍ @ffæƒ|ûí·GݰaÃôéÓ³²²tVÎÎÎÇôlÙ²…a˜–-[&@uîUTFÓºukf-Z˜5i"pt´7޶°00@Ëó:S1qmÙÒbøðÇ*UQ˜L|¼¤];ËqãŠþÉå%b ½w/ç›ox V­Z¥¦cÇŽ%%%iµZ[[[CÓüùó[µj•ššÊ0L‘ÉÅÅ塞ï¾ûŽa˜áÇ¿FÀÎÎŽ‘“]ßLø¥\€öÍÝü Þ0 ÏÇÌߌ™+vþ{˜×³&âÂ?·ï­¬b-,Ë;ÔmÛ{ ` 4B€F¯¼hý„ßtÝiõë×wqqÉÌÌìÚµkvvöòåË‹LN:UPP°víZ++«®]»nذA ræÌ™áÇ6 Àÿþ÷?µE‹£GîÚµ«N8ƒƒƒ9Ž33+Ö²¢ŽŽ ŽŠÒ}Õu ŠÌüüpýºõ_ð £:s¦Èdˆ80¶·×|óa˜²ðpYxxÑWÍ—_–ˆ@ÖäÉ"oo\»V¡ŒJLLìÒ¥‹ahï½÷^Ïž=uŸ÷ïßÿÞ{ï}üñdzgÏ&…êM€†8 Ô¹²Ö–CÜõÍj%²ÄW_Ã&D/KS.E¡p@ªZ²¿LºkåÀTÀX \ýod!ÙOø eôèÑ,˹sçNýúõ­¬¬”bZ¨:MéãÝ»wÿî»ïäåå…††æå啾P-òöV_¼Èk˜䜙35±±J?“œ¬¦?iú“Wã ÀgÀ_åL+óZøøXL.G€¹å„@ö~Y½zõþýûûí7Ã¥ÛMD.—÷êÕëÖ­[Û·o/aÒ>xÀ¦¥Yú)¯PhnÜ(}­òèÑÜ%KìW®4=ºœyó’]]ÓBCSÚ´IiÓ¦„•ËËËúôSËqãÄm«lW—³gÏöíÛ—¦i—eÝáuÅ–@\¼àÓ=`û=ªcÓˆü­ê½®¢?ë&éSUˆ?&}ÅJlzôâsëÄ®oÐHö­±nWÕ7–šÖwèäÏøÈ¾– µz™œ ü ¬>nçJbäZ×€ÁÀJÀßhJÈ~Âo …âã?E½†…þÈD¢Ê…ùÃ?œ;wN¡P´kWr—:*Š‹Í‡ 88µ—>/¤ZmúС´¹¹ù@“W¤iíÍ›µvîtÍϯs㛑QR,¿úŠW«m¾ý¶ 3íÞ½{B¡ÐÛÛ{ÇŽþþþºvf‚'l¶@¨oø ¼aó;„fÕ•å0(yðÅÿr·@\S÷jÞsCðý\d›6•nˆ=Õ3¬Ôd9´(@¤÷w[@ ôÀãbN=ê€ÒMMƯí 4Ðï›Ø˜[~Òü²ø˲wîÜñ÷÷wtt\¶lYÑñÇŸ9s&---77·ÁNŸ>}Ë–-W¯^ÕM`(!‡âÖ­)‰Ä,0P׉XLƒïÝ£-,Àóù?ÿlRLËãÇŽÛ¶É""h ³æÍmæÎ5´k®\É[³ÆnéRƒCæÛ˜1c233/]ºtçÎ |úé§·oß~É0³²²öìÙ³wïÞ¬¬,R2_-twØ.MŽ°Ú ±ý›{«̓Ë>ürÿÕ§Å´‰:r ðeqýÓí|8 ¤,À¥VÒ2r-ÓÙ û ¿AèÔnûöí;wîœ3gŽ¡Ë˜’’’––V·nÝåË—3¦BÁÚÚÚ–7ØR%íÙ€¤mÛüuÅvEcŸ=ãrsRìÜ™»h‘‰q êÖ•ED}•véòÜÆq™S¦H‚‚,JM®¨‚Ÿ®~ÌÑ'Ÿ|²xñâ'N4iRùÎ¥U«V}þùç …€L&[²dÉ„ Hù¬>Ò…Ë…m’ý%€kâ1¡ŽÁóý6÷¡îYã7î6kÿyaþ„üøºÈáÀÐ5g‹y@‰@Àv` àˆ“À¥RX—s-WñT“ý„ßììì|}}]]]'L˜°`Á¹\®;Þ¿ÿØØØ;v 0`ìØ±U——§‰‹£ÌÍŸõïϦ§3ûYÖªeÖºµ8 @X¿~^¥†½  V oß®>ÞbÔ¨ÜR£]bbbââ↠R‰( J¬EÀqMW~ÒTBBÂÔ©SuËÔéÞE¦L™Ú ARD« Ç1PyÛ$þ©æ-kø6GÄhƒ¯–B»´ä9ƒvbP ;åF[²€4`pˆ„@mÀ ØdZ øPZ€Ä€x”9Ŷ¼kKcd(M‘[Iö~³077Ÿ6mZ±w„„„9sæ,\¸P79½d) ¨¢¼ˆû÷ï5ª¼&Vut48NP»6%‘k×Fñ™(‘€ÀÉÉÒÀ•oÝšfð»(6–MMe’“‹¾j®\y®R …°Q#ÕéÓùëÖéþŠLׯ_;v¬Î˜˜Xær©æææùùù†G®^½jooâÄóߨ–-[233;uêTéÌ¿}ûv‰œdYöå[_ „׋r¼ÃõóÝ€éúy‡ð°X¨€z@( œP` êMGeiX™×r•J8ÙOø ‚çyŠ¢¦L™2kÖ¬¢ƒAAA ìZµjÒ¤Iû÷ï?{öl‰«¼½½9òÑGÅÇÇtvv>räHXXØÒ¥K}||®Ÿç§ŽŽ¹»×Ú³G÷Uëïõ2ÄêóÏ¡\J;9)RGG놆Êÿü³XsРA¼RYëï¿ÎÎljjÖ§Ÿ™,ÇŽµ;¶„†ëþ&‘Hºví:`À€‚‚‚uëÖuéÒåøñã%’6wî\ƒ~G__߆…… :ÔÇÇçúõë[·nýüóÏK DªÍš5£iÚPA³fÍHÉ$¼ÝrXzÛÞÈ€!ÀRWõz•uþç/º–f?Òè'Œì'üš³hÑ¢Ÿ~ú MÓºEÚ ­ 4øöÛo§OŸþÑG•é9Í;7$$¤N:†---O:5bĈ+€(ؼ9Íže³gͲ7/wÁ&)ÉÐ*ß±ƒW*Ÿúú:>ü¬oß"“4$DÖ§OJûö"OO.?Ÿ}úÔ0X‡M›ÒzôH®__Ø “ ôð([ò&%  è«½½ýéÓ§gÏž½bÅ ©TÚ¿ÿo¿ý¶h#wwwÝJÓ§O—Ëå%¦‹lÞ¼¹sçοýöÛñãÇ7nüûï¿W®Ñµ—‘#Gnܸ±èÈûï¿_¯^=RD Ä;$j‚~ýú ¹\îíííàà°k×®ž0cÆŒÁƒß¹sÇÃÃÃS¿4è¤I“FŽ©Ó˸¸¸ .X[[ûúú]åééyáÂ…[·n=zô¨qãÆ®¨$lØÐbÌfÍ›y{[Žƒùó‹¬âà`¾ À¬eKJ,–††>_A†¦kíÙ£íââ2fÌGG²ŸÈ!P=xxxLŸ>]÷ùرcã3‹hԨѭ[·< \.ssssssÝçÈÈÈnÝÊ^£ÏÛÛûÉ“' 6,:"éÐAÒ¡Ãó¦ŠwÞ‘½óN‘–°Ú~ÿ}‘I'AÒ=¤=z”%‘ÈÊJ|1‚’aÐO5ñôô,s’e‘Õˆ©³3cbbºvíšžž`õêÕ¡¡¡[¶lY¿~ý;ï¼CQÔúõë†éիב#Gtç/]ºôßÿ%ͧ„7²„7áÕ£Ûp~)©ðã?öéÓgÞ¼yF®*s[ùÒa2ññ郧æ-] žÏ_³Æp™ÒÖÊ™L ³ˆ¦M›”yEÖŠ^hœQ£Fé´PÇáÇÜÜÜÂÂÂz÷îݰaÀ€€"-žž>jÔ(RP Ä;$ª †a&Mš´~ýz3gëCÖh4&LÐuhýïÿ3rUlñõEË 3süxåñãÔ/ª/_–ï3b­œé…V>PbÉÖVã–ØØ8J¥òZ©•ÄìììÍx)âêÕ«J¥R*•’BK Þ!PõZ8`Àn•@£Ñ„‡‡î0r•áH#aN‡(­LF¬•3·*•Ê¥K—îܹsîܹfÏžýÏ?ÿ±¿páÂ…%æcA*•êd¯vvvÖÖÖ666eZíí퉈…–µBi¢[ãû«ˆšPlÙ²eß¾}eš6oÞ|ðHI4 IDATàÁŠ^eÜ*1\/¦"ÖÊ™Œ[gÏžýÉ'Ÿ 4èèѣ͛7¿qãF¿~ýŒX_øÅ_”95³]ÆõJ¿÷/<~좉ї€ €+pX|¾£óåD!¬`RÀ:À ˜pÀfà࣊ßiX2ÈÈÈ•+W:99oݺµ„•ã¸;v´mÛöàáS%L<ÏoÚ´IwUÇŽXË(ônnµÏŸ/áä©ÕjWW×>øàî½{Ò#GDó÷_øB“qkHHˆ‘ü1b5~aEyðàÁŸúµX·oß>cÆ ///R> oeu¿é€n¦S,À­*dà @ dWdã_eî!ÜpD@àÜ(©‘(Œl&\:©O$` ` X€ ½²·F0ÊÇ÷nFÍjR碭5}òäÉÒ³#hš^¾|yTTTpÛ’BBQÔòåËuW•Ebh-»Ü—R¦ääd©TÚ«W¯ wî”ûƒ)GðŒ›^h}å¨Õê«W¯* ¹\~íÚ5†aHù|µð ü}ë®#“{+ï?`_¹wÀhœç?@Z‘”Éôt›çpÙø×È n ”ØÀÇx¦'5$IWƒåŽ•º5‚QNúvB¿ë*5OaUD‡?¯{ª´ÐcnGìí‚s?özÝZ†Žkðûy„Ú½º{ ¶n@è+—CÝ€š @;àÐ_6Å uX˜¸ñ¯ñ=„3 ®Ê¼L‹¢¢X زV¿5‹X4oäæ-Ûo]jþIª¦GWÿm.²FFFÞ¼y³eË–4Má×̸S­é‹Å$‰îPh°~=Ú~‰9­!yŒ9#Ñgâ¶ÃAßH¦}‚Ý)àðˆ»Œ«}Ð^P ÉbƯ8Œ¯ºãÇ(/ãýy³¯zµð…÷øÈ2z@Óš{,åÌUj ˜€ú@=½:ç쯈¿hâÆ¿Æ÷>ÄZà4®ÆbJ/ÜLØ:@=`PäýŸ½óŽËqãøç~f{iª(dVVÙ[edʈ‡Ä#Ç^Ç&ó óØ{FÙEV¡%Š$ÚóÙãþýñèñ4TÒ÷ýêåõ¸¯ï}ïñ½¯ë¾¾ãº€€U¾kX–K#Á}ìœ]j9Ú1]ÙÖ ÷ßZ´pPJsss›4i2yòdWWW[»fz&å>³™Éd`±X\.—Ãá”RòÁùóäñÊËÃà º0´Ã_ûÑ*ýÓ,#Ø«å¢×DÝr[εÇî84—â0o ˜3°¸C%_;‚óg2ÒÀE•±ªÊñ‘?¡æÐ7T{@  óÕ•|eâßÒs;G€÷€!0¨¡ÒZJßñy08’Ÿ‚± 0 `”lMT½ÕSóFž>çÚ´njS›úJM™±]¹²-66öï¿ÿÖÕÕ533Û¼ysƒ ´µµwïÞ]®ç£-c0§”‘³Ìää‡ÞÞäñ~4‚oCÍ6ùÊX”…€X´lŒK!b¢gÜxŽ.P“].õ7ü˯ÂÝŒ¸7»bµW‘kGpC¥€8xÒeSò È¢é|M ’õÊÿ1[Å–Ì-à‰cSþï¯Iü[RaªH~`åö/æF É„K9U}Àë[Ê—T/áK4hh{v›nR²èŸÿÔ44>ŽDDDܸqãùóç³fÍŠ ë^j,´‚"‚6EQl6["‘ßÍ#ÿ;dÈ øø©äá~[15ËoÁ„Ñ;t[`¾ò3 GÎà`з½Ñ¤<ºLYè=³Ðn(lØ•yíY¤ß1 øXUÄù m„ÊDCMjfD5ªÇ ?w1ÇÄÄìÙ³çÉ“',ëêÕ«Å&ü+sÈ`0X,VQs(—Ëããã—º»÷¹s‡¼3¿0¹‡ N*ø§ëQùT÷l z.ÇŒ ˜”?"â BùŔ̈ʼnåÓ/ò æ¡óhD,Àþ·w«‹^;8œjWA¶d}¡¡å"š¦…b¨se|>_‘H!%%¥S§N§Žïe°49ާ§g:u¢¢¢*Ì;,jýü<~Lñx™¢à.G·‡8›<»_푌¬˜Ö«1ðüuSì?o¶¬ ] é4@¡]ch p=4ÀPG½r8 ÖEÜ`„lÆ=OŒ›€QU9×jù£rŠ:*aˆ9$üˆE¹ZTV­¥!ãó?}§¥¥ïód™={ö4lØPù߬¬¬~ýúUŒ9”Ëå ƒ¢ Œêq÷Y›EnY Þ¿;ûîcYkõ²T”––¿sçÎÿý÷_VVVVVÖáÇ»té¢ ›G sH ”b±¸^½zVµ Âï­ ¥‚¼÷>Óÿ(vq¡––VyŸL^^ž0ëîx·–JsH«ëhiPX¸'‘Db:/é>šW»&GMËÂÁÁ¡Œ¶gÙ²e™™™L&³M›6çÏ?ÿ|ñâ…¹¹ye=Ž»wï&&&ªnIHH¸{÷.i¨b „ò…Ãᤧ§‡=8¨.¶«›©«£>rX·bsÐóx¼ò>™Ëޏõú‘É Ïvô\T«Áyj™$Ýy$=±Y#7Ü“-°¤l{{û²TW·nÝæÍ›÷èÑãæÍ›³gÏ~üø±@ HHHÐÑÑ©¬Ç¡««[t£žži¨b „r'..βþ°f=nöz ^ãžwÞ¨«^À •J·lÙ¢š¸<°µá÷Ç;y!‚¦é˜˜'“}Z”o ›üT&—cH/vè3[ÝrÔ¨QwîÜ)Ku1117näp83gÎ|þü¹ŸŸŸ\.oÔ¨Qe=‹V­Z5iÒ¤À=±µ-£L T9ÈÌRBå`hh¨££sôèÑÌÌL‰DróæÍðððBe^¾|Ù²eKEЖò#²ûô5‰‡¥®i¤©©9dÈ2½r FŸ>}rrrz÷îÝ©S§Ö--£_ÜŒ_¼xq…Ý|oooÅïÔÔÔáÇ{{{/]º´nݺõêÕ[²dÉ´iÓFŒ‘––€¦é={öx{{ÿúR€EŽh:Êìš‘`XWÊ!à›x:ÁHFè2ò«ŸDZdOEf[ä†@<i}=ém L&jƒ˜C¯ˆžžžïœÍÌ!K—Iyééé§OŸ.TFSóSš§ëGޔߙ„…¿¨mÓ£u‡a]\&89÷Ù²yÃû÷ï}ç­@QòýgÄ^‹‘¯å¹Býöí;šššº¹¹•¥:>Ÿßºuë¡C‡fee-]ºôáý+,ŽVjjê¿ÿþ[1w^,ÿ‘IS‡å¾_ݸqãåË—…Ê55µôÀÀò;++«FÍŸ?¿[·n#G ®iÌÐÑù£†¡™Âî\ªnRƒÁd =WKSSS"‘$%%•¥º¨¨¨œœœ7oÞ,\¸¢¨ žc|f­>¼où™#´îÉd»¦åÊ•+l6ùÓk‹îUÞƒ¸?\{ì^€à€À1`ÎÀâåP Ëçÿ¶Ã_°w¢¥èP°‹„~ ÑÄ;$üòp8œØ7’‡Ïe¯ä) ÈW­ZU¨L\\Üï¿ÿ>g΃GÊïLž>}zþüy±cÇ6hÔ24,c÷¿[¶™9©r6‹ÊÈf±Ùl‘HdddT–ꬭ­W¬XaggÇb±hšÎê …6’48Ùf‹&“222:uêÔÔ©S½½½OžŠBaq= ¿¢¯±lä‚:ªàŸ®;DxÆsÈÿ"*åœÅªßÈñô©þþ«·äˆ¸s|ç999­[·NµŒÝ¾}ûÒýüÊõLŒŒŒÁ½{÷ââ^Y™ ’ÓÙ“&MÊO8¬v.0;+—îÚšÅbÀŸþY´S÷[yvã}ø8‹©‹6K ¼O–Ÿ’Ö«Íü*­°û¯®®Þ»woÕ- ÑÑÑE½{÷ÎÒÒ€……E§ÑV=DX?qƒ²÷<1n:\D½òP“4¬ÆÀð×L)æ¨>ô ý7HE@5†ÞA°ÊgÜV{$#+ù–ÿ ç@¼CB%›C;v26­»dñBww÷ôôôBe7nìêꪕ“S®gbii¹páBïiüo¬Ô¦–ä]’PWWW±ÆP ‹–åòh±„æ°!—ËE"ѵk×ÊRŸÏ|sîë¸d- *%ƒnÓ”õúºö‚)Üzµ+ùeÜ·oMÓr¹üÀÕ¶YÞ_Š•¹Ø³Lô]‡Áñ¿ â^ [óñÛN,¿VÄ*ô² ôWƒÁŒ sÜDasHøuQLbl×iàþc=ú¸3Œ¢±@Åb±T*¥‹˜ÉË™3g’’’úôýíôuö­‡2ƒáêêªZ“ɹNmYÎíX"1´µØ,K[[ûðáÃe©îíë; j¾05büwA¼c‰zG¦¹ ãÐyID¬¬‡@ P®ôعsgõ\tŸuc·b–?Úk¥•»º kÂ~´5ÌÄêµH‰ƒGÃO}ƒ =œ/Ø9Èš ½ÉÐ<†D[TÔ7:¹„JA™Ô—Éd …°G—ß¿:U¨Œ¦¦fJJJŒŒò>™Ë—/7®¦yíÇ©ššê³gÏVÄ—ʸ«ÿ™›0\]ØÛYèèè<þ¼OÙ< èœnl@E½¦ëÎéó7¤÷ÃdÎíYsÖV¦ºyóæ°aÃ#¦oß¾½qãF¯^½ª[›ÔsBTÁ¶¦ÓåÐú(\üâÓ¦ÀÝ .ÑÄ~m¤RéÁƒ_„ßâPI/]35ÈõÁê*Æáp>ÄÇ”sR >Ÿß·o_µ- gW;hPŠÈp\®Î„aAœ5»E2f‡Ã¡iÚÀ L«²_'†‹øúàZGÄzÚÔãY =ÊÚ‚Ÿ(¯¬'Ò«W¯jhÿb •LFJl·f†: ãå—$â“—™wŸZ°¹†@‚j1##£K/6-ç“a³Ù999&&&Žv‡Ü766©_¿þíÛ·äò™wËDbqÜ;¹sWNË–-)ŠÒ××/Kuwøo%WvkfdÓ‘¯e¹<8Ú1›7fÆÄËIà ˆ9$T/tkXÜý ‚!æ½>ˆé>3d2™••Uppˆj1“×>è2òr4#GŽT¬">fu StòòòØ,ùž½o?¦<²X3x|ÚÂDvùòåß~û­ŒÕutTk`-oeϽÍÿYgߜԬYS¹0\•ù«V%8:–ëÉ(c­^½zϾÓÎÎεjÕðÓ¼MÊ}&‹z-º/eÉãëÕ1+{d–Ç/ĵÌR¤RzËA‘Ç`ÎÖCb¹•>³”@ æ@¨$(–šŽ¥QÚû¬¬¬sM‹Nn‡?ÿÌdTDCåp8ZZZ £U«VÃ6оC›ô\ƒ·IòÍóÕ?¤ˆS. +ÓDC}]†ƒóô5ɱ˒ç1ò'²–¶ÌÙk„)é4i1‡„jŠK/7‘˜ÎHO£(J&+¾«ÐaàÀ·íÚUÀÉXXXÈd2Š¢èjd°´4³kÚáyŒ¼Eæá bAÆM7.K-±o$VæŒþ¢?'p]:°´5©Ô z×1ñ»dì@ æPmÑt2Уlh<}ú4!!¡¤R63gVÀ¹äååeee)~Ë%Ÿ¢¤þ9—HÊùç¸O¶Œÿ,.öI½ÃêÙ¹tºϾ.µqŸH]âràZLš@Ì!¡ºÂ®U³¦©&77$øv±¥ š PŽïƒ‘”””––6zôhEž?@–òN!US×[·ñp=+­>Y±oÄîîjÕªUYªKI—Þ},]2{~»Æ•;ÒëÁÒK·$b æy‘5f1‡„jL÷î=-ͨû÷Cʘ)â»áñxS§N]¸p¡D"177°zõêŒôŸqó߸f3WìÞ{"Ód”5ÕÔë·™O"eÏbdzrÿY¨nRƒÑÊž©§C‘Æ@ T"d¡¡’Ñ1éniºwøo¦.\¨” iºQ£F<OFÀ»wo5jdª–üû}]ö«Ç‹ÅyQÑ/n–¥: SÖ뉱ƒAQ~ûE׃¥éYò\¥§MÌ!@¼CB5¦†EŸÚæ\H“Î;_YæËå~øð‘?õUldJzáy=Ý{Ï|ð²õÖÃâ̤se©N_—ikÃLN—¿O–?‰qØ5€Ãdb¬¯€4x‡„j ¥îèè@Ó![ V|ýšššnnnªY =GµÞúO1¢»ü¯L›è|ãúé²T+vÿu2@ÂåPÏT{ ÏãÓ¹<šÅ„”¬Â'ˆwH¨ÎØ; ÌåÑÖ–j•R;‡Ãa³Ù¦¦¦Þ½{@ÊiaZÌ«Ád27ï¼ÎT/ÓB »ÜÐgÒ?Fr4Ô/ “=|.«oÅhÛœ|›Äª9šN6Õ»£¨²êWŒîر£I“&·nÝ ¼ùè÷¾ÅOse0³•iŒ3;W–”B»õçÔЧžDÈúueýÖÝÑÕ»31‡BeBÞ@ÂO§¡¶ŽAsÌʪßÔÔ4##cÈ!y9ss²7ø—8±E±Nÿ»±±æ°Ò)òº–ŒþÝ™£ÿä0~ïË}FºJ âª=­Ûv•Wj2‰DÂb±ÌÍ͆œ£jñ´MM IDATîcÿ,§Š† ¨ƒç$¿÷å\¾-íÐ’'c± ‘’V@ sH¨ö4°Ì¬ÔÆhbb “ÉÎ]z0ã¯Ãncç–SEÖìô,úu‚\(¢­-ƒ\Ø#ûq¶‡>#ö@¨LHg)áç@³‹£=àWâ) ÿkƒ$PÕ­[7 ‹Ý»wؾ}{ýúõÉBF1‡á'BMM­G…6:;;‡„„PÅ`0îß¿ïääT¨@¯^½455¿Íëe³‡ ¦®®îææFn;˜CðÓ±gÏžÖ­?­òd2™óæÍ»|ùò¾}û>|ºÿþ+W®Ì;W¬®M›6þþþßQÑþýûù|þÆÉ='üü¨4BµÃØØøÞ½{7nÜx÷î]çÎëÔ©;wåsçÎíÓ§ÏòåË=<;;[œ˜F1‡¡Ê ˆJSö㘛›=zôÊ•+5jÔÐÐÐhܸñªU«Èí%sH ª=zôxùòåÁƒÙlv­ZµÜÝÝÉ=!sH ª#gçÎZZZW¯^­]»6¹!b BµC,4èùó犼Nÿý÷™\J æ@ |B.——$¢(ª¤$J¥ˆ~N<<}ZÒŽ\.744ô[E¥³i­Zµ®^½ZR¬²îÝ»8p X÷±Ñω¿¿ÿµ" :T&“íÙ·GÖ@F^1‡„êÝ’ŽÝ¼ysQÑСCKMœ8ñàÁƒ·oß.ö˜¥HG޹k×®’|²Ž;>zôèîÝ»ß$*ý˜¥Hýüüø|¾]^^^Qé¼yó"""¼¼¼Š:—¥ˆ~NÚµkçTSSÓI^“¢¢£ä½ääE üt_êØAn¡Ü,ßzï®M´wÁ­ æRtݱcÇ &¨.t£izøðáÉÉÉÅŠ–.]=00ðÿû_!©@ >|xvvöæÍ›ûôéÃb HKK«]»¶X,ž5kÖ‚ ÔÔÔ¾FÄçó;v옖–¶iÓ¦¢Ç,]:þüeË–±X,›¢233ãââ ûõëWè_½zuáÂ…5jôíÛ·¨J™™yöâÙ´Œ4™‡ ö?¢!}ÝŽä5¬Ž†mç÷ŒNsH¨ps@lžO€e6›]Jˆ“’¤L&S&“1™LuuõÂç"— …BE?d±iùsXŠŠ FIǤiZ*•ŠD¢’j‰D4M—4;†¦i‹¥Ì¾«º].—3Œ¢¢ þŠþôWœˆfÓP/¦ãI®.—Ö—¢3 ÷ãðã Si•˜ò»–>£$© 2Å¿yÈ+Mí–lŸ‹Š¾æ˜_¬±$¤–rLÒ‚„òPK@ ï@(OÆzN‹iä>b Õ—½»6‘›@ ª_šJÓ²l‡Lî0¡ÊÖuâ åK«Þw® u u’¢Ñ¯û€¾Q;Ñ/~bE,"ïñ „ŸS=]¦è³´sogWo×¢Ë!~~²²²N9uÅï 5€¢{’ÅBõ4‡™ÀB`É÷Ìç. 9°è´&ÍæW'ôYzû¶í'N¬ºáéé¹}ûv¯É^¨_ÙG¬0h¬_kq©ÓW„\•cÅ„öÀ™¶äÆUÕ°Mc5pï'> ¡Ò?¯³zõ…B¡ðÔ©S›6m:{ö¬HT•zµ&MšäÒÃ…ut•ƒi\Ž^·¿}ÝìwïHø¹¼Ã#À à(ÀÖ›€6€< °èPÂîQ€_‘e× à/À¢¯˜fÿÜ$T:ñè=Pñ366ÖÉÉéãÇFFFÉÉÉuêÔ ¨BÙû 4#¨Z|æzÁuËæ’ûrhìÙ€qÏ€¢ ¥‹Níà犺¬¯}ëgü…ߥ.¾sGÂÏå¶>Iùï`<Ì—Fr”{©°Ø‘ÿçXMšä)~.¤|©2 Úÿþ÷?ccãÄÄÄÄÄÄ„„‡³dÉ’*t-Rž´º<¹À£ü¿Ð/kX¹@ìù¼œ ÙŒ¿ J•x‡_‡5`<,1LŽr€<Z_w(9°0`äËÕâ€w€1àÄ×àŒX€ XŒÌI–Ëm 8¼t€ö*z³Š?JÞ@C` ÐhŸ_¯ ¼ô€¡@S€®A°6Ï_ìdÀ8€«r@Â/G``à¦M›ŒŒŒ˜™™;w® ¥• |¥ÇfZÃê`^¤Ø¿£Ã@QP×F×NØ6–ÌÂÎ¥ê8"ÍöcØô 28¶Â–a°ã¨”bÛ.¬“áØD´Tû–HÂÏkY@sà!ððÐ:›,@x ´ý:o“Noÿj*ÛŸcà8° h,ò€ ÀãR?ôäÀ¿€° {ð)ˆU`{~™KÀ3Àª¸ÝŸ3 8 4’KÀ€„õTÊgÛK`Àø…‘Éd<O5^¶µµ5¹-¿4’ãq<mÛ‚ 5£ÐH{ßm˜`ˆ‹]JÖm4vlÃRþ¡“?À©—°³ÍïiÈ‚ïf\¯ ‘¨MÔůc8; ðhhõ0 9ð ˜úu¹ ܼƒ‚Û»å":¡Ào€: ؉¥šÃ$à=àhšÀÀ¯``à>0P/®9v‰Ú€L€ 05€Ôêä[qE]€€ È×]5A,ïÙ³'""¢Aƒ¿ÿþ»¶¶6¹'?)‡Ãù¿9ÀYÀ¨´âoÀ øä ÖqÀù–ßi †XÔ ¶Ïӥĉê²$ì|‰ÿ-CcèÐßè/#Î »‚zCŸ¨‹*gUó¡ìݵÉCÈ·2xà 0 €–ÀC€ p†_Qap[œ£¦‘ÿƒ °ñé; ùݤ¥ ¨©ì®_ÐIÎÞ%¯»P­WÑŽÍwà$ÀÌ€®@m˪tþ²-ÜCùõ¬ÖÁÉ~™3gÎÌÉɱµµÝ½{÷Ê•+ƒ‚‚¬¬¬ˆî¨/®tí`¾išŠ• ^Ž›Fn6íFÝx4&"‚ñ¿KùˆhœúÈ¢K6‡YøÈ†A1¢°»àë  Û—m!Q?ƒ‚b[Hñ£]fÔî1@S@ àÀ®`ÏgInÜn /Ðü»NŸ*¦QÿC|@‰ÏâoÀ8Àìëj4h Ø,Yz1À&`  YÚw@GÅãd#“À`jþgáW„ÉdšššÖ«WOÕW+61ïÅ‹ýü>Y§¦¦º¹¹%&&²Ùìï®]"‘(m!™L¶aÃ''§Þ½{“GS<ªc‡}K+®;¤(pÔФŒBc`†µ}1y+Ö `a…‰öà¼ù‚^šäéQLY‚÷4ZµÂæÖ\ˆ£¡y£Vcë ¸‡ôû á]8ë4 áMø.ªvúò‰8~üøàÁƒLž<ùܹs7~õêUÏž=Û´isðàÁB{¬ZµjΜ9…6&&&š››÷Y$&&ZZZ­höìoˆûpâĉ!C†”‡æ 4)Ú…FÊkT$„7á‡*(½‰@(•+WFDDØÚÚš™™}üøÑÁÁaãÆE‹5mÚ´ÐSSÓ²Tmfffllœ’’¢º±Y³fßq(Ÿ{[ÒÒÒ®\½’z*•zIÑSÉê¯1‡BièèèܸqãÆŠ…Ý»w/4j¨ÀÅÅ¥U«V¡¡¡Ê-¾¾¾L&³,U3™L___UKÖ¦M''§ï8T98Ž1â¿ÿþÃUT¤H sH T £{÷îÝ»w/´=&&æÐ¡CÙÙÙ®®®;wÞ½{wË–-Åb1€¶mÛN:U ìß¿?<<¼I“&êêê_¬K ìÞ½;22²Y³fîîîS§N=räȃp¹Üÿý—Á`ܸqãÌ™3ºººnnnõëׯÄ;søðákׯ¥¤Ó=ˆƒHøåÍ!ü#™L]¿~}åÔ˜³gÏ>\(Ø´i“——×úõë/^ìëë«¡¡áïï;xðà/> XýóÏ?·oß644,¥–ÔÔÔN:EGG+w9vìØ¾}ûZ´hÁçó/^\·nÝI“&íØñiÀíÚµGŽùí·ß*ñÎôìÑóࡃ•S÷7j§*°> ¸ÖKCPõr ÉÕåÒúRtþÑ™õˆwH üTtëÖíöíÛÍš5{òä EQ`Ô¨Q [¨`Û¶maaa§NÚµk×ï¿ÿþæÍ›!C†äää( DEEÍš5kïÞ½¥Ô2kÖ,¥-ðìÙ³Ö­[?~ÜÛÛûرc£GîÚµëýû÷U]ÉQ£F}øðáküÎrÂÄÄ„ûAöxö=¶$[RE¯€Æ–¨Ià\U3sH |™×¯_ˆ—Éd,ëÅ‹ª¦NAHHH³fÍ$ɱcÇV®\©X€¨Ê½{_ÈŠY´@vvvïÞ½ëÔ©“™™Ù¬Y³äää¢^¼xáèèXú‘—/_îêêÚ¨Éü³Bƒ¹›ÉŠ`Í™=§ÿþºººUî ²²²Îž=»rõJÙ;™lœ¬*ư$æ@(@°mÛ6KKËE‹yzz.X°àâÅ‹111 (¶|Íš5“““MLLRRR²³³ I-,¾ØÓÂÂâÕ«W…6jjjóxK;÷vvõvý!s†ª|±§L™àÅ‹7oÞ éÓ§O);ž8qÀ;w>~üXÆ4J’““öõäÉ“üñÇ÷¤E‹ÁÁÁL&óÉ“'ÉÉÉÏŸ=³³·'-çgFÂ43†„€¦A‘d‰Ä_$ôYzû¶í'N,¿JRRRüýýAéÅüýýH¥ÒC‡Íœ9ó‡T½ÿ~©T `ïÞ½ßm•Ë%‡ æ;gÎõíÛƒÊ^œP¾Îbr²4.NŊ̹s%11ì† É=!æ@øR ¾Îrîí}:HZPÓ.—@·àw¡ÎPaHÇÎŽQ£×ÑQ¬åáAî1‡Âò¥úúŸsNnÛ¶m`%©xåZx.—û}y'ŠR»víÚµk+~«¦]üVöîÝ{çÎ---##£ ƒiox<æÂ…µ[´¨•|BŬޭ‹±ˆ¼Ãà`n»v¸íÚñÏœ!7­b -„_ŸsçÎY[[×®]›¢(këû€+ôüù9ŸÜÜ\r*Å"f—àŒÐ"‘øÑ#yJJöòå²ÄDIt´<#ƒÜ4b „o#44´oß¾VVVÍš5Ûµk¹! fÍšµ{÷îþùÇ×××ÐÔ´‹†F<`œ9³eìX‘ˆ$Ÿ­L‹¬_@$~ôˆ–HDçíß/ FÕ\nAÌ!PÉ(‚…N›6­cÇŽ^^^Û·o'÷€\.×ÒÒÒÐÐÈËË377702 ºq4Ýöôé¿G’Ëåä.UŠE¼l„Þ­ l3ML,ââÌcbÌ_½b7h $æ°Bø–±CpxmN9(ö—°]u÷{U,ÅôôBPEÓôwìXŠHyäâ/ަY,–2¾I¥A•Ú ´Ši U+c ƒÁX¼xñÇÏ;§xjjj+W®ôôô,cÞ_ÃiV,½—H$ ƒÑ¨‘ÍÛ·Ï€ÀF¹¼ÿÉ“k<<þô÷¯ÂW(Ñ@±Ù ¤€¼d=C—‹ú*‹ô°çóA@@Þö픺zÞîÝZãÆñ†\Îó÷ç:8DYZNŸ>=<<\‘S³’‘Éd £X=SŠ´ô¿.—‹iߨš¨tšMC½ßí‡+¨¯6‡I`ïdËRdvÍìô TÎãñb¢bx<ž½½½žn‘@ Ê„%Y ƒ¡H ¦¦Vè!I¥R‘HTTTºT"‘ˆD"gggW×Â+²—-[öìÙ3ccã=zÔ¨Q£¨¾¸wïž‹‹ËÀ íxêÔ©£GöèÑcÀ€EWyK¥Ò5kÖ„……•deÙl¶Dòsgl¼â%U(c EQ ,PÝ2zôèµk×FFFÚÙÙ-Ÿ¢££Óµk×¢mì£{÷î4Mçåå)BŸh5oîxåÊnÀl”É<ÞQ£ÆÄuëªäå…ÚEÑRZCSƒ«Î-ð /“‰„"‰Lbgg§§WXkòx¼˜˜|Ý¥WX­EGGóù|{{û¢o})R‰DòêÕ«ääd6›]¬îRè¨Bº+//ÏÉaÖ­ ‰D––@ž™É47‹%LK›¿sç½{÷¾OÏ”"­ @VE(¨¯3‡Ù`û±[ÙµúïÁ–––ª’>´hÑ¢Eó($JII±²²’J¥ ,ðõõ-Ô2x<^‡²²²6oÞܳgO…ïõEQéÒ€€€ž={nß^ÌŠì¿ÿþûÙ³g#GŽ,XK±ãÆ‹Ý1 àèÑ£Û¶m+v•·T*µ¶¶NLLìܹóĉkÖ¬©Úî—,YrÿþýÙ³g“Œ-•‚••€÷ïß2‡4MûøølÙ²E‘ƒÉÈÈèСCÎÎο°9444¤(*44T±€R×Ä$pοã€ÿ$÷;þårÇ-_NU­(ï€íÐÑÕ¹zåjëÖ­‹j§æÍšÕNŸuW‹btW)¢Ò¥ í¤®®~þüùoÒ]Ê{®9x°¦J`?í)S´§Lùn=#—˽½½oÞ¼9kÖ¬BÒRDÕVA}•9¤.SÆ:ÆW.]ÑÒÒR<€+W®DFFÖ¯_ÿêÕ«jjj.\PˆT?‘†* ïÞ½Û®]1©>6lØðæÍ›°°°ÚEæyÉ>~”DG³ml˜ææ¥ì¸víÚ>}ú¨Ú­ÄÄÄ¥K—Μ9sݺu&&&|øðá®]»òòòš5k6yòä­[·fgg;v¬wïÞÊ_¼x1þüÈÈH›ôôtÕcfeeݹs'>>^__¿mÛ¶Ë–-KLLܲe‹"”—*»wï¾{÷n`` ÉØRY|üø@Ñ`i/^ôóóSþ755ÕÍÍ-11ñŽÒbddDÓ´H$ ß¾aã£G×õ»ÀÀø 8Íã ]·nÉ«Wb??¿¿þúkìØ±?*Ô\9²L&3&:ÆÄÄäs‡H$.\X¬vR°bÅ …”ÅbZÐYìŽB¡PñM¯ÜQKK«ÐŽk×®-I;•®ôŠéá Ó½¼ 6ofhi?þûôÌîÝ»¯]»VH*ÏÍehk+ªæ ê«Ì!û9{²ÏdEË‹Å}ûö ²°°xÿþ=—Ë;wnÑÖ6nܸ۷o;::*m¡äÕ«,__qTÛÆFÙ²C‡yzzª6 Qh¨$:š]¯^!Qæœ9ÙkÖ@.Ei{y R•òOŸÎݾ]š˜È²²z¼6?„‡‚ÀÀÀ;w6iÒ$##ÃÍÍ @XXØÑ£GÅbñýû÷GµmÛ¶>Èd²Ù³g+vyùòeëÖ­ÆŒtƒ IDATsãÆGmݺU!:}ú´§§gff¦™™YVV–P(d2™666Ê6*ÏÍÍýçITËÆfç™3îîî;v?~,W,¤Þ¼É;r„¡««=y2«Š¬÷Rdl9|÷°¤ÝÏÞ£2aÂ33³Å‹+þ»uëVSSÓ¢9o#"" mIIIIII177ÿUÍaíÚµOž<éáá1k̜֬œù2Ùy` 0 ØÌêlà‚XÜâĉ•mÛZ[[Ï;wÑ¢Eýû÷Ÿ0a‚““ÓO{iÔGª[·nª¶Pax|}}9ÎÂ… •Ú‰Çãíß¿?::º^½z£F:{öì¤I“´´´Ö¬Y£|ý¨î(“É-Z´}ûö´´4“©S§*w”Éd…vôöö®]»vî®]Ù+W:Õýééž&|Ò]ryÞÞ½ü3g$ññŒ"½¸ étOϼƒeÉÉÆçÎ8qBUÏ|R}gÏòÚzë–»››ªI£…Béë×,kkJCcçÎ -ôé=š9k–ôÝ;¦™ÙvMMU‘$&&oß>Yb"ËÊJkÌV:U¥mÿ@õU®’ Iݺu¿7nÜúäÉ“7oÞDDDðù|¥HÉ­[·œârsx<ÕÙBBBÓ4mll ÀÓÓsôèÑŽŽŽqqq¦¦¦#FŒ (J*ý¼”{íÚµ 4 òõõ½zõªRôöí[ww÷¡C‡fgg'&&æææîÙ³G,wíÚUÙ‚SúôÉY¿^ž••»uë³ððÎ;e-]ªh¾»u“DEñÏœùàà KJª* ®ªdliÛ¶íÒ¥K‡ ²nݺÁƒûùù­Y³†Ëå*Ö´iÓB[LLLª€Túõë7sæÌáÇ{zzÚ¶hñ¼A; `ÃSk 30¦===§L™Âf³gΜyêÔ©ž={öèÑcÆ ±±±?á¥Ñ2ºqãÆ…6þþûïGŽ‘H>+®¤¤¤¦M›Î;÷éÓ§‹/¶³³KJJRJMMM¯© •J•¢Å‹oذaöìÙ.\˜:uê²eËÞ¿¯ªô-Z¤Ü‘¦i…v’geɳ²´'LPüi-ûøñm^žRw¥ž>e COOsØ0n¾žTöc¦ÿñGÞÁƒ—/§Ëãñ>ëÕk—J#32:wé¢Ü1káÂ]Ý÷¶¶ouu3gÍzþü¹B )¾ÅSGŒÐ8ÐäêU­Ñ£_ÄÇ«Š’š7çŸ<)ÏÉÉ;x0©ysуU¨yÿ(õUÞ!-§•só‚‚‚† boo ~ýú4Mš¶'‹'OžÜ³gÏË—/+Ç …7oJãã-ïÜaš›ëLúÎÔT,+™fΛ'~øÐìþ}nëÖâ°0qóæJÿÔ)ÍÁƒµÜݽêÂÀ@ñöíJiΆ Ú“'ר²EÙ_èÌCBB´´´‚ƒƒ‹½®[·n­ZµjÛ¶mªq¼âââZ·n­¸(ÕA”Ç[[[oÞ¼Y)5jÔèÑ£µµµ?y·!!Â;wj†…qš6•¾~-¬W¯PÆ–Ü;4‡5:r„­­yÇëIåósRU2¶Œ;ÖÄÄÄÏÏoË–-7¾xñbÏž=‹sqqiÕªUhh¨r‹¯¯ï¯=ûT__?$$$**J&“8qÂÞÐÐ Ø8ÀGà иEQ2šÞºu«P(¼råŠÝºuë}LMMǯÚZìíí•ûJ$…vbššªµo¯ûçŸh‰$uð`ŠËóù ©ðÖ-Þ‰fwïr•I7*}»´Ñ£yÇŽ)¯°‹J=óù­ìߟݤ‰ðôi¥žÉÙ´){õjƒ ÔºvÞ»—éã#”ÒÜ]»Ôœ üü¨»¸W®TŠ2çÍSwq1>u -•¦ôꕳ~½ÑÑ£U¥yÿ(õÍAÚ K)°nݺøøø .ÔQq·%‘‘Ìš5™ææúú¬:uýÙë?qBgÖ,nëÖ8…¢[Ñ4Tg«þ–ËÅ/^èœL¨JNNNDDÄü¡:P¤$--mĈ ðôôT5‡Íš5;uêTNNŽŽŽŸÏWnwuuuuu-åÂÅÏž1 8M›`ñ˜ÈSSRJ]Y³¦,5„MïÞ½{÷î]t{LLÌ¡C‡²³³]]];wî¼{÷î–-[*&¬·mÛvêÔ©`ÿþýáááMš4ùõnËÅ‹·oßîååµoß¾ÐÐЈ§O;9õãñ®΀ì®·hÑ–Ã éß¿·nÝ233¯]»Ö©S§LŸ>ÝÀÀ@9²Ê¸bÅ CCCzzz>>>#GŽT~¹¸¸(K.[¶LEÇÈß¾}«:kܸqãÇW=²L&;wî\DD„êÜT-wwÅGŸ¿sçÎBÛçÌ™sôèQ+++“ÔR-Ö•+WTÿ+}û–eeE R¥#“É¢££ëׯ¯œsöìÙáÇ …B›6mòòòZ¿~ýâÅ‹}}}544üýýcccüâÅ‹_ø¶Lš4éôéÓèׯ_‹6mš4iJÉ€ Ð X«®îíéÉápBBB\\\._¾looß©S'…ÛݨQ£#GŽ 8¦iª ¦ßãr¹<ÞçåDOŸ>-Þ¢äæîUQ2ÊU ‰$..ÎÊʪhßûĉsssëÔ©“œœ\ÔÒ¤{yñÏœ1¹tI­CåfNóæœæÍ‹÷ã×®•çååíÞý=-?)I5÷C%–=µ.]²W­Òñña7n,‹Sõ+ •RêêÊ ÕÓâ;ktìØ±oß¾7ntwwÿûï¿ I§NjnnîããS¸UH¥P½Å§ð©uë–»e‹<+ €¼`E­Ñ£Õ{ôHýý÷·ZZ)p N¤ ~òäC›6 ::IEÍa½zõêÔ©St¬èýû÷YYYÏž=+ê52 >ŸŸ’’¢úþläôÎ; 9‹´XLýêËתݺu³µµmÕª•B— ‚Q£F)l¡‚mÛ¶uëÖm̘1uêÔñññyóæM«V­~m[¨`РA </**ªFçÎRÀ8 ð{êêQ¢Ÿ¹G . ÿþýÇCCCÍÌÌòòòóûÓÓÓ«âµ»ºº®Y³&<<@TTT± ®üûï¿Eö?~\GG§aÆ:::sUü-Š¢,,,¤RidddtttÑn³ì•+swí¢…ÂT7·Œ©SK:7Z%¸ÅbîÚ¥;gŽr‹¶—×W^#§E Þ±cPœ?Mó ÆþÖññaׯŸdg÷VSó½MaSšœœ>eÊÇ®]Ó'N”¨ø*Ä–ƼyónݺõÏ?ÿܾ}{wÁO˜³gÏž;wnÛ¶m…> ÄOŸJ¢£¡’:µKg°aƒ<+ë½MrÏž…žSî®]üK—4† ÓññÑtsÞ¹Sè|²–/gÛØlÚÄ)b󂃃۷o ÐJôôô7oÞ,^¼¸[·nË—//´×èÑ£-,,>|øžžž’’R¬ÓÙ®]»É“'«æw•%%ÉÓÓ)’´ú'àõë×âããË _¼x‘““Sô!6kÖ,++K±Æ¦h_>Ÿ˜šš:ðÿ»]£7`>°¾~}gg稨(KKËqãÆiiiq¹Ü:üý÷߯_¿Ž‰‰ñññqttTWñ!ª+V¬hÒ¤I³fÍŒ7n¬è5-Ê‘#G~ÿý÷BOœ8¡X¸ìçç§:òÂ`0Þ¾}ªH6¢YР1x°Îôé5vìÐ1ƒwêT±5ŠŸ>ý¨â8*̬þß+ú<5‡ ù<7âKè¯]+ üо}æ¼y»tÔ–¢»wÅÏž1­¬¸öö¬"ÙQ2}|DwîplmE%µh!ºŸ˜Ã/Àçó7lذvíZ//¯Ž;z¨dáâóù>>>îîîE¥Šî߈ž{öìÙ³gë!¢©© ðͨQ£Ü%ƒ*++Å‹èú òù|;;»ÏŸ??xð ~F=…Õ«ù))ìnDD™™zhh«‡D˜ŸOŸ9“0nÕÇ´×vEK—/çDDh¾}‹HPZô$ìÛ·ïøñã±çóû÷ïÅÛ÷ôôt;;»Çÿ_jàñ;vìØ³gÏÌ™3,X0räÈeË–½¨'­z*ž?îææ–`³tiîþâEðçÏ_NœÐÔÔ477‡ H·PSS0nܸ‹/îܹÓìûY‘H,))©ïèØýAИ1cħ¡aaaR IÊ7†ñx¼¸Š­ö´ª“ÑžÎpp€äå©>>$GÇú:Â`T¾»›¶à.&&Ôïv`ŽDù‚ìlš¯ï·I ‚DnÆ Hì  Ãò‹ÓQ.ªwPÚ³TËv‡zzz0 '$$Ô/ÒÒÒrpp¨Ïúmôõ…EEj“æÏg8:òRSx¾%%ÂüüúµMüôk¿H^ÃX##Av¶Ô;FGG“É䊊ŠêêêF³»vízúôiíGCCC …â)í;<<<***,,LjvYX^?d`±4Þ¾ÅèéKsnlÖ©ººxÆ aqqÍíÛßÃÉÛŽ 7·š;w„EEÅ“'‹*+{¦¡ã»@)(( R©ùß§ Ã^^^...ŠŠŠÊÊÊ...IIIÀb±Ÿ?þüùsïÞ½CBBîÝ»gee…ÇãõžäÖ‡ÃM™2EYYyüĉ[ÏžU<ØÞÞ>;;;&&fÙ²e¹¹¹qqqEEE½{÷Ǻݽ{—B¡H&4Æb±Ý0'ÔéÓ§544$­’¥111/_¾”´ÕoáÍ›7ƒ–4'@daaZ{ x÷G·ÏçÏŸ¿yóFŠÎ`0ªÿý•ðàûF|+-*¢ÏœI°µí•œLrrj¾Ra—K^6¡b$ÎËŪ•š†]] ¬"ÈÊB”•¥êž- Z¶;$“É®®®7nTPP=zôk‰½­„²GïÝ»÷ÿ7pèPQu5;4TõÒ%^b"ïý{Éf+`‡„¨GD 4*1‰`cS¶e íéSŒ––°¸¸Îq´â®] ˆ@ ŒÏ•˜ëïß¿¿víš––V||üøñã_þX”œœ\XXxáÂ…… æääôîÝ;û»NEÄÃÃÃÙÙ9##£Nß¿¯¤¤Uïüò›Œ0@¬×i~~Ò’¡ÃªªÂ¼<Êã ‹‹‘zK”Ïg88ð¾û¼U8€¨©5ÿ ½!0==+¾ÛuyIIô9sÔzžó˜›››ŽŽŽ¦¦æÌ™3ÇúìÙ³ŒŒŒÅ‹“Éäú®ùùù_¿~­5•ÛÛÛÛçŠlÝpllìþýû£¢¢Èd²££ãêsF·ååånnn÷îÝ«ªª3fÌ,,,ÚØ¦«‹-ŒVÝ~˜è²`QvvöÀ•••ß¼y3}úôU«VMœ8qæÌ™ÊÊÊéééòòòzzzx<¾Î‘¡¢¢b^^ž––V·š£GÞ¸qã¹sç\]]«««=*YtþüùÛ·o><--­¾ Ø`PÏÇäèÑ£cÇŽ;v¬Í«W¯ÂÃÃ%K¯\¹uåÊ++«‰4L(—[¶m÷Ý;•“'aQee‰«ëÿµZ` € ÊõëP yÑêêªãÇÉk׊ƒÖx?ZË6là}ø ,V~,‰ÓJŒ®.¶ÿʃ©÷îAx|½¨°lYÅ_a ˆãÇs^¾¬8tHaÕ*)wïéªÅ§OŸæñxÓ¦MkäWÇ›7p iÞ<ú´i˜>}YYˆš8`#oÛÆ ÊëÝ£¯/üÑ;‹âåE·³Ë××Çèé ¾~Åü¿Aš7åó+öï¯:uJ’óìåË—©©©b•<~üø'OžHÅÆÆ …Â={öØÙÙíÙ³§N †“““ººúÑ£GÏ;ghh(ia‰D;%<¾ê€0r$~ذ≠ÖÖR—{òK–0æÏUTòòК¹¹sëš V®dÕ™ß]]b½ÃŒæƒPòãÌæ„†–®ZEñô=ËñGNNNÌb•œœÓø,½ÿ> **ª¨¨¨í”4ééé666â ‹Å:sæLrrrÛ °sæÌ©•¿‘‘‘>|è#-ªµù¤óÊÄ! PìëÇ^^^T*ÕÈÈèèÑ£½{÷^¶lÙÓ§O׬Ychh8zôè¹sçVTTœ>}ÚÍÍí›äb2ÅG­$I’I£;ÀÜÜ|ÿþý6lOƒ:U[·n}÷î]­gƒ™´8‡²²²Áõ²Ã‡‹‹;|øðýû÷ûõë÷êÕ+I¢ð‹/.Z´H2lñ›`ÕÒ¢=|Èpv®¹u ££#ÈÌÛºj÷Ž(‡SheÕÒ>§LÁ˜›lmQ&³Ž¸_´¨ÈƦ`Àü°aü´4îÛVÊÕ«Å“'çã--yoßþ°ÏÙ¶MH§—¸º~ãÂ\±Biÿ~)öÌž. ZìYª  pãÆœœœ   ¬¬,éû$,V,k$A½y“zëiþ|ÊÕ«Z?ê<ŒŽŽfb"ÅË‹4ožò)f0½{k¼yC½{W~ñbê­[šõ¢…ä.ÔÊÈèÍfk}ýZûåÚµkËËË+**ÄÙ_9"YÄb±¸\nII‰¦¦fIIIe½½ùرcýýý333%# ÿý÷²z¨csP $-Z$b2å%œÓ#G’7nœœh~~‚~øpØØBb…ÂÒß~û!ªòûrŒ>{6ëÑ£VN5úܹ ž…„yåJÉ¢EhùjÐéô«W¯Ö±•ÕÇÕ«WàæÍ›m¿©ŸŸ_;†††·Í©ª¨¨¨Î^„Åbùùùµñ§n^‚?q…{j7±¤³páBƒÁf³---ÍÌÌ,--_½zåääêææ&æñÛoß¾]ëM­  Ðäî Annn@@@xxx°yyy??¿ÔÔÔ§OŸ¾}ûöíú@Œ}ûö-[¶LÊbР;wî$''?xð ÎîœL&ûúúfeeåääü º&OÖúúUõÂù ¨>>š‘–›3G®bHNŽT«BV¬ø¡‡“›5 ÌšÕØ,i à¯6"»‘"©y ZWVQQ®Üøî‹1¢–~BnÆ ¹3êN)6»dÑ¢šz ˆZ« ÃÉIÕÓóÉEóMׯ—._Ž6ÉŒyãÊãQ®]ëy±’õ}›¥j¯ÄÄÄïulÅŠd2¹-7­ï¿ŠÁ`ê{Þ·$ ƒÁÔÉ8Ýv,ŠƒÞð®S8—‹h4ÚÇÇŒ“ŸŸ/f0otquu½téÒÎ;k½flmmkU ƒa2™Ý0+ººúäÉ“ƒƒƒëø“‹ahh˜mnn.µîøñッƒj988¸¡,`ºººiiiõSAÁd²Ô×–0f AÂ=$–ìMì`”•%/þa+bh¨\Ïý¾H¯^J~ûpøp}ñ…9RÊ„ùeT+s&ŠóuIµ¿×/df2œœ --«Nœ(Z}þ|áðá”¶½¢¤dGd7R$5f«+¢NÉ’%R½¥ Ь­šjµK°W×òÝ»°y¼|Baù”¸º¢fõ¬¹{·hÜ8aa!øõ ©©™––ÆápÊËËë¤éiU³Žnppphc‡‚‚Be¥’’’TO®áêCžÛ:™«¥çÏŸöìYBBN/,,LLL|÷îxV›˜˜¨©©íÝ»W]]}ø÷—®¤¤dÖ¬Yß]B©Ÿ–½; 9ÒIêËÛŽÛ.»šXÓ´PÎÈT‡ìÁš5kþûï?À?ú85TTºr%;$À‹ãÆÇ×ܺ%Y«‘ÒVW¬EmDv#EBiCØÊŠiY)¢=~,>ëæÆÆÒgÎJ ö¯_½òðaîë×j~~P£{´¦¦xæLNóN­¸±±ff4__¼Ä»ú+ 6× ,Íï©™ÈÊʪ¬¬8p ŠŠÊÑ£Gkób*))‰£>*++SSSÅ„&ÍlS²Ê‰'kíùÇŽSVV …IIIJJJº­"¼úˆŸf¸xñÐ7n|ùòÅÙÙyÔ¨QcÆŒY·nÝĉÃÂÂjjjôôôLMMQ-**óõ‹·Voß¾­}têêêõSeu-š/’’’:´bÛeWãÒ ™rF& :pw(ìííÅcß‚" #~ýo¤´ÕëGd7RäïïßöŠÔMËÒHQé’%b³8ÖÔ”Ðì$윜ü‚PSö7ˆD’_°’f)’ â„ XSS C QXXhkk«¯¯offÖ¿ÿèèè+VÔÓN:¥®®~øðaMMMKKK*•*IÚаHAþ\‘ÝHÑ,‰SÉVWD9ÆüùÕß×1AÔ)bÞ¸AŸ9­©åå©7n¨œ:šÊ.„hjªGDÈÿxNÐä/Öˆ‰‘Î^ÿC£ˆ²»;ÅÛþÅhYÚEçÎ[ë8š––fmm}îÜ9///99¹©S§Îž={ÆŒ»wï'EáñxûöíóhŠmËÃÃÃÍÍM¬{jjjvíÚ5cÆ {{ûÉ“'“H$///kkëôôtñõÁÁÁsçΉZ–é-<Ž÷îÝ   ¼¼<ñ¾ÓÜÜ|þüùVVVþþþÚÚÚ999“&MÚ°aCdd$÷ððpqq‘šÇ¦[%Lntê Š­–]MÚH[$gdªÕáW ïÍæ)¹¹5’[¹‘ÒVWl("»ñ¢¶Tl$-‹Ô"ö³g¥ßs[“7l Ý»'5èõÛrÞÄD3>_£¼àÔˆ‰Á6Ì áñ´ÄùØdh)>þ,dàóùëÖ­;xð`ïÞ½i4Ú¨Q£ž={V§Ö¿’¤YÒàååUçÿQ£F©©©õîÝÛÍÍmýúõuMñ_KmöÇ>>>©©©Wê¹¹›<Ͷ;‰addäääÔGII$-^¼øôéÓL&3""âÅ‹UUU¦¦¦0 ß¿Ÿ@ ˜™™q8œÈÈH…ÒÒÒ”ïD—{÷îŸòùüîCOÓ:éÔA[-»GKåL— ¨&6”ÝL@µL80;;ûÇIII¹¹¹’ìD°ýú©GFb´µ°ŠŠÚ±œuJÛ^Q‘={öìOŸ>‰#²)’ ÖnuÅúiY)RX½šêãSgµEœ8‘vïø1¯7F_¿‘×FH§3œœNN u#ŠZP¶N¸‚PoÜ Ö –¡ùèÛ·o}7CCؘ›K—.8q‚PÏA|BSÇ0¶õâÏÂÉ“'/\¸`kk]?òGOO¯o½ì#00°(*jž†ÆŽ;V­Z5~üx›þù——÷ñãǤ¤$>Ÿïçç÷îÝ»qãÆ%''ß¹sç·ß~óññ¿×vvv¦¦¦âŸ×}è¼[$$×+Q±-B¯±S åL× ¨¦5b7P-´PVV0`@rrr\\œd.ˆÆ‹X##õ°0¬FTTý´…’¥íU4‘Ýx°vk*þ˜–¥‘"U©,õÄiÓ$Iè E- QS“ú Q6›>k– 'G“CŸ6 m 5ã·F$1TNž”k³³þ/,ëééYËÐ+''·ÿþÄÄD ‹ŠŠŠªªªM›6}øðArÁ4tèÐ]»v5Þì®]»FO˜˜>}ú‡6nÜXUUUQQaii™˜˜èææV»¤P(^^^LËüÃc_½rKOgp¹S¦Lqvv^³fÍ Aƒ ]\\Ö¯_ïëëK$Ož<¹víÚ?ÿüSCC##í]ú§€¯é±/_\\¹tBAî'CCȈˆZ…Ý}Æ¥ùÒÉôG¨ØFÙÕˆ ¡r¦ëT 4b·P­ ÃGQôêÕ«ÖÖÖõé<)`úôш…UT²¥ñn×–¶¨¨ñÒ†"²¯x]°aÝH¼vëŠ*§OCX¬²»; l­[ÔpÆ…ß~¤§W;‰´'O°Òx@(d8;s¿o^¹ññt''š¯/$M2bôõi~~E66(›­¸c¹á4¤24666_¾|‰ˆˆç@GdzÙì÷ïß÷éÓgýúõOŸ>MIIILLTWW=z4Ò”?‚²²rXXXdddqq±™™Ymæ ˜˜˜wïÞq8"‘¸ÿþ7†‡‡£(:vìX•fo,já®­­ôå S ˆŒŒçjމ‰qrr:sæLllìž={&MšdjjšPVV:b°Ðr;*^0a$#@Ÿ"íûõ=5ÄÒZÜšTë.D3¥Ó˜:QðS±-²«q´ZÎt’€j‘ê6ª5ê‚ Úla—/_nfQEE…’’RLPPþ•+Ø)¼ÿ¿WmxZ4>cZ4ŸD"Žyþô?Aî7)¡ZüpNËÒÌŒ-Êî$’“Sƒ¡6(Zºv-ëÇT×lÿ²uëTÏŸ—Jô‡>œrùrµ——r½tÇ2´***u‚âÃÂÂx<^hh(ŸÏ“õïß¿ÿ™}šX,#ˆ8D-ø|¾¸ÙðððÉ“'”””f5JÒÔ8¦}ù"âoÞ¼©®®ÖÕÕ511rwîÜ©¥¥emmíààPTTÈ,Oüœ—oDÀ P@¤àÁY9y¹‚7™øfËÂ7ìaÑ%h¦t꜊í.»Ú.g:C@µÝD@a:ç6Q»wÓÏËUV6f³õ‹Šw]‡ÓÒR ¾†;Úf“ð¥AA8ÞÖvB·zŸ ÓÊ+÷¿yófKydøéѸ€j-ºƒ€ê u¸eÖ,y??.®ÁРvQoù|þšÓ._õÿô‰Æ)Œ1lÁ¼ ÿu·ùÖÐTCY,ÆÂ…’y[ê€yㆈͦ^¿.µH&¹:ÙÙÙµI†Ïœ9Ó^ê°6µ¯¯oNNŽN“ÑZÍ|D¢ dddüù矂üöÛoB¡PMMMYY¹¸¸ØÚÚš€ãSU ‰£0Î[XéÙ"Àù[¼€ËrE%¨&UXRr…?|ìØ±î–æI†.PݳÙî¥ÌšõE$šüôéy•`]•w‹A·-©ypu£®¬¢cÑÁ#Í»U(q#ääÐçÌáIcâ—ëÁƒ¢ìlꃘv’›24ÁÁÁ[·nÕÖÖf³Ù™™™?~luæôZˆ±³³#¹¹¹ÁÁÁËv¦oØBáÍ+W>~üøâÅ ·aà …âä䤣£#öŽÉÍg  ¢ MÏýµ‰ð,‚ÿ*A¸ãçèv‚:ÉI'AS¦L èžÃAo[:~At¬:d±ª‹/滸6LïýûÞ¼ ¦ËV58Ñw#ÞÌcU—Ð騿šûÉ[?ÅòV™Y`a!*-mÎÅÜøøss͸8LOOìÞ­°|ùòvoÓÄÄäÌ™3í?ˆ.* š6mš‰‰ ŸÏ700¸yóæÇ/^¼˜ŸŸ_PP@/e£<ôs¨€H€¨*Ðõ„ð8×}~ÂG¡‘>®)=uêÔÈ0ßn81UÖËØÐóàS/©µ mÜ¡­Sû/‚¼X,v¾‡‡2fÀ;6v]‡uûŽÞs$!¯˜øµPáèÙð¾†f?DzE__õßáï©všTÕÿ•éBBºdrNNNDDD~~>‘Hœ4iÒÿý·yóæE‹‘H¤3gΤ¤UêÁŸ3„Û—ã4¨ð8K  ÑKE9¢ä4¡®&'-5qôèѺ½ÐîÖ;ßÍ› ..ýãã{ö >ÈûÎg+ÃO ó ˜A6Æ¿‰ÕëÂ…¿iDh©kCö䶃HR[»Hcé<=‘ý‰†Šää¤þꦩ$--õðp’““lrËÐ*ÐQPسgÏ©S§RSScccÓÓÓñx¼H$Ú²eKii©Ï‡Ïê‚@!8 Ã`ïü«ðÙhÕ ÂeŒ/|>”v«®ÝØ»·×Ù³ÊÝ/5qû¢ª¼<`Û6Ç„ÙdþiÔaj–¨¬œy×çÛfÂìÙS~ï7Æn’O=:ÇÎÖˆ¸ê~½9¥¥¥?×há ЈŽn„èkb¢ñæ ®ì¦2ÈÈ@ €°°°OŸ> ‰æNU[5' —¢ã­0E%¢ß±s Eo„)™B‚a âÓãcî@(³ût-ÈÛ[ÏÃ*”D¥öàA¼þÇ®Ý,»–L6 £0ÊŠP^v¢8gfQ~J@XÑ–mº¶Ï(*ðª¹l†T’þn±xwwç5š‰hh¨‡‡ã¤¥èà ¬ލ«K­È{ÿ¾²Ù·eèÁx€½øðááC‡nß¾}Ó¦MS¦Lùü!èúÕ#Ù­wL:™f  äñ€¼¤Aƒ5i›(Ê€Å,(Ͻ.þ»; #9>t¨WEÅcs÷‘»£&¾éÁƒˆ§Ó•dSùçR‡ýõ’r”ˆ)~þü9À÷Öv²ª™ŠŠ “Ù•+ÊʲìÒ A½:7'½ ëéÓòÝ»öö 9Î ŠÚóçØ™*1ººj ‘ŠJKööåüÁ®“£Q†_0å\.ŸÏ7119tèÐðáý½½§M4k\õ‹ÇÛ àÓ×|ÑÄ‘˜­îœÁÊ7€÷ðo3¾ XC€/@Åq­gÏÝc•½6Ô푬(½zµAZÚu½~Ñ}ôÖ@¶"¶° Àý^2ïñŸG–V £‡"wžV•—d¼xvâ ¿ÇAV˜­[Ü» ûL/J«aƒ² ”YYÐÝÆƒ÷ömÉüù@$â§§OвXÒ%•J{ü¸–ÏVQQ hh_ˆr8Å3gòÓÓHDwtl(† ¿F‰ç ˆ“T 2dˆ£ðÓSD…,ä Чa‚+÷øK JÑ tì Þùý¬„B<‰€PXlÔD¯TQ`»‡Ò‰ 2xùò¤†N’É 9Å={322þIKß6Ú>Úâ”l>ÿ4ê0ê½¶ót‘îù¿pöÌ\^vnYUEnT\E—ªÃ,Š€€_ÖA·ˆ‰oE-AVVñôé¢ï[gn\cÞ< J_Ñ|}!<Âãi¾¾Ø†˜ÀD"Æ‚ÜïäÂ(‹E·³ã§§Ë¦þ/ m™••·oß®©©yÿþ}hh¨ë;‡UÄYB>¤ŠöCÈ×¹Vo¿Í=5.ú[¸àë¿Ü„$!}ͽˆ÷…­-0Ï_ ºC§r³²žªkeí#( îÁc'‰|||Nœ¸:Ú!@±÷iÉR6ŸÛw(OíZ8Â,XC9?0Jðô"ÉÌ¡*C ~•]Õg.»†A_8¹ ªƒ¦¬ßý-­%,,,ž2EXT$ù%ëÉ“ÒõëU=<¤2‘FVùçA‰4?n ÑÒßg=xðà úôéœ2ÊгQ E<^SSsõêÕT*UU•öÎíwùœBå ¸¢\ôá*÷xu]¿ëYŸ…FJÐyèò=Þ¨!5U¨´Bôêm÷P‡eUa³õ5§ôä+-ݾý‰äXUe-›Æ?Ÿ:TRRZ¸æ<£xÐÃçÂ%‹‡'dfÜ|–UÀÀôïo@PWõexaŽ¿Ü¾í_¾x4$ôUËö…99Ŷ¶ü´´úEÕçΡUU 1‘*|ÏX-MÁ6ÈnÊOM-1B=$D›ø b9çèG¡lÙ²ÅÖÖöõë×ÇŽPW·¸î—5Р"ú€Ëƒµ`ðIŠY‚'š0ÐÓ€Yl´€Â^ —:©¹ÐõÚoR8zÆÛ~\ zÒ¨‰D¢%KÜäå7ñxDÙþ)Õ¡H$ºåýOdg銚ššd2yöª±±1àüå.sHÃc˜TV0˜Lf|ü—vl¼¼¼üÔÉS³ÆaÞ&7÷mä½}[}šl“ŸžÎ°·o(Tãÿ1/¯pôhÊåˤyódoÂ/…ý¨¦¥¥¥¥eee=xð¥òòOŠŠ†738áwŽZ0»3O$‚‘>¢Jƒ¬!,(‘¡I£0… 4$ZÀáûÁqéF]®?|(41&¹3,)Zsbó§[zÎåçWªªɦîO¬I$Ò_RVV&‘H%%¥3f…ÂÇ»0Å(È/¸úP£V?~|úôÙÁÁí¤þ?Ä]ñr×ÓÆŽ4‡"âš¾žÂX° Í"Çá%&MœØëÇÆ÷ˆhMMñ¤I‚ÌÌæ´‰ÖÔ0œa …hk+{l6{Íš5¿BOKÙìÁƒ$ÒÅ㕈D*—‹D—ùÛ—ã«jÐ/Y"ð¨™1bj€ŠKQ"Z¹µjƒAúÛŸÕ FMUòcqáñé#b/ÜîQÄ4¢ìõìht¬giAAÁž={nݺµtéR‘èÛ& AR³~¬ìB3cÄ~2VQžÃår¦M›Ø.Í¢(ºnµƒÍpX]U8vX³4ÑÖ–öèL&7çb¼¥¥zxx“öRˆDR Ã[6Ëå VT¤ùúÊta-6lØ ÎY؃±é{†5‹¥¬<A0Œ()©¨ Àá”ÒóGãqˆãF–·/š5vÞ4,M–#@Õ5¨•ó€çQ0?$Zp·g2xòàa3»CÈdãÚ¿KÏ]¦¨«²ÎÄõ¤Q#d[ß\0@__A“'OÞ _OLLìª?xð ð%!=IÉ„²ŠuÒÒÒ+*Ú'êãº×‘²’5 z´-?LåØ1ƒÁ¼~ýÿ7ÒÔ¤=}Š´G¯{NŸ>=cÆŒ/_¾ü UŠú÷_’•õJª«;›N:ô‚à"W\ª—Wø™ˆIï£óº&¦†CKû õ4ÙÌlK÷ì$<³ÜÔ°áç/e•£ íYÃU·;ÚÏ#Yÿ;Êwïfp""°ÆÆøaÃÚ¥Mn\\Éòå(‹U¾w¯ò_õLuØ_W F#‰×Ý£F())7‡ë‚Sn6›M D"ѱcLjD"“É Ù¾}{»4¾uÛnš¹ë·G›ÿæ¼xõÉAíEkv'ššjÏžŽ%ª¨¬­)W¯Jå£iÑQõòeaa!;8“ÉjÏžatdÌ¿Òahh˜˜˜ØºÝ¯¯/—ËÕÖÖf³ÙYYY£Fêßs^³‘’’òòåK==="‘˜››‹ÇãgÍšÕÆ6+ð…&+o„û|~ A}û:‹/(-M²=WÌ}ß[£x¨)“(a†|HÍÊ(f·pc·;;þü-^oMØq ö˜'7ík²{‹D\¡'^¬x¼Š~Úï²;[åWÿ÷_¥»;Ó=Nª50hëÀefÒíìÄÁf•‡#äuëz :ÔÔP€¤ø-((Àãñ]ÒU6›ýõë×Ý»w‡……Ñh4AˆDâçÏŸÛ.³x<~ï{—KmŒºÀÛÔºv°&&Ô{÷ЧLÁŠ)IÛaÕŒÅRïÝ+´²â§¥Ñ>Ä $S{€Hle¤³ŽŽÎ°aÃħƒ Z²dIÛŒ££cRR†áøöÈð^@ƒ”rQ–ÇCQQuõW †¤®>€¢Â‚ìÓÆ¼·4Ípy¸@Q<)ˆý¨¶fçIé¦rNÁ¸a fü›îÊ^u[‡Ús쥹¹¡VWwö7»þ1»:+:AØ©"Ôß¿T" IXRRUUU•””Ìž=ûÞ½{nnnŠŠŠ0 Ïž=»½ÚÇáp.kõ‡z8Ï5ž4ª¦õâØÖVåøqÚýû°b»EÁŠŠ´û÷Uþù‡0~¼LáuÌÍÍmllÄoÞ¼¹]4‚ ›¾ûCM˜0Á¬Q ¡;wî¬_¿þÑ£&‚Ϲòßì —C¡ îÕËV¬ ‚FÞâK/š‘×[~÷IXYN‡=£©¡b;ë…ªÑm¾’ü3ç)Õ!Êd¡‰)Š*”ÉêQÆR‹.IIc å÷B@Ué­‘²ÊçÆÇY[×É=Ð ‹¬­¹Ò hMMñôé¬'Oz”:b1QEõ›Ê©®®611éÛ·oWͦ>}ú|ùò%###88øéÓ§$jtìÇŽ¸‘HœétÈÐÓ¢hZZZFFFí7S§N…aØÆÆF^^þÛššÍNNN.))i~³%%%ÉÉÉlö7R‰4vìX†§L™R{ߌŒŒôôtqäÒ—/_.\¸ÿ~ 9sæ`±Ø]»v-Y²$77Wºª%rà²aø[ôNVúÎ ûÞ¿ùÀõöåɼdéÀ\åÆvÞÂÞû/eɪ£Ýy D"Áá“åˆÐ_›iÙ¢À(¾ :±‹Ð“&›¼¼§$þ[Sõ6”a1@_»3|«/]¢ÛÛ£\nCð’’ †åµ$b—”TheÅKNnðåâpè³gW9ÒsÔ!$áâïï¿hÑ"l×e Å`0 &L8èö;©jc¸g¾Ë è÷ß_½zµL²ËÐR$''öíÛ·ÿþ>())1Àd2wîÜ©¦¦6`À55µ… òx¼& ...4M\e×®]L&0bÄSSS2™ xðàAÿþýûöík```nnþåË—½{÷Þ¸qãÀ¦¦¦III¦¦¦îîîW¯^=|ø°ô·òûîP$ˆÓ>T–=˜c<ÐË€ÑC1‚ø#ç1§`÷®!ü¾P~„ùä®roîºDôyî$XQ — ¶#05,à÷¢GZP(ÿ/ˆû , w¬»ZSSâêZºre©”5V~~áØ±Ìæ±X0½½ ­¬ÙÙMí…å;w–,^Ü$¥óÏ¡XðxJJJ(ŠÞ¿ßÃã 'ÖÀ~Ȉù,6È/âzxxxyyµû-ÊËËe £C$¹ºº¦~?óHMM;wîôéÓ‹ŠŠ´µµµµµŸ?nddtäÈ‘êêjñõ7nÜ8{ölãÍž={ÖÇÇG¼ç«®®vww722 ·YXX8uêT{{ûÚ8ÄÄD±/‡[¿~=ƒY³føØ²A±ZuˆŠD"¾@ÀB¹gfØpž„ñµ5à‰KkÒ²E·OÊÑT!ª WÒt™Ý]¯Èá^ÿµ ËŸ+`²Ð¡¦ˆ@ˆvÎΩӠ ð-p A€Š|VØkÁÔ±Xf« Þ‡쀀æëN¦——Tƒj+.«ûÙ³&³üdê033ÓÀÀ SRRºdJÅÄÄâÒ•LôK6‡Ã-]º´ÝoôäâE™ÎèÁÈÊÊJHH¨ó¥¿¿¿±±ñË—/wìØ1yòä¼¼¼:Ü¿¿ñfë_——7qâÄ]»vEFFÔ“Mñññ®®®/^¼HIIÉÊÊJJJâñxŸ>}ŠŒŒÜ°aƒô5·ü7 "¯0ïøîßTƒr DúÚðÞ5x,wÀõíM4¢Sjjºùp ‚¢ØDŠ‚‚b´´ýòUÄæã>HÏštß<ƒHr‰ùÂéã°ÈvDdžà­¬4ðC‡6çbÅ;Ôƒƒ›Eª¢Ø¼7¼……æ»wx+«G/i¼ IDAT¥oݺõþý{‹… HKK«ógSIIɾ}ûž…¤D ÜÎpbjh4Z¯^½Úæv­ €ªª*©ß›˜˜¨¨¨Iåv`0­h–J¥©¨¨˜˜˜H­Å`0lll´´´<==.\044=ztƒ¦ e••CúõÕï].ıQý'¡#}øà¿œ£Û(c†aPx]PXÈTœ6­›GIYMHŒ`Õ<\i*u l  [:0{Ò”ƒ oêPQ.òs†às†p¨)RÈèðØJŒ––zD„\£®aK¹zUÙÝ4Ó›A”¡\¹0©s’½½zx8Òò¹+Õ!Š¢OŸ>]µj•øã!C¬­­;>©ªªº¸¸hkkWVó7ÿÍÆa¡"›B¡pÚ›(ïcB‚Qtt[Z৤ M3µxx¼ºÍ2´bnú:_®\¹ÒÏϯ¦¦FGG'66¶¾­rîܹ7;sfÝFFF±±±½zõb±XOž&Qhmì<Î×ö/8pÔüùÝ|8Ô¨"zýAˆÁ€ùÓ±7àw¬À/žƒïISŽÏÿ¶G×¢~ {-`”¡0²;…¦’“£Ý½+߀ Âá¨wîÈ·œêR~ñbÚ£G Q1“\\(·nAÄNMwÜê0**jÖ¬Y‚«V­jÒ¼# ‰6mÚ”žö 0iÖÚQ$Ë©¨¨´ïrïÝ£UV¶þw–—O›V¾¥©°Ê6o.ž6MÔNé;~q`0˜Gé}ÏCB"‘¼¼¼.\¸°mÛ¶’’//¯¯_¿ÆÅÅÍ—P$‡j¼ÙØÛÛ×~tqq‰‹‹ËÈȸvíƒÁضmÛ¥K—._¾\K𣝝ÿèÑ£Zާëׯ³X¬S§N5~—wßl?~ˆ……x©J¿vm>¯¬ê¯¯¥÷y‡O‹¶&N˜^»Æ9]O<{¶›ûÑT•qýôà¿Îså`æxìâl6Íd èISŽÃ) ¨€ª˜Íæ ]ñ}{ÃÂN#ÞAÊåËò Ö¨ȵ6z[nútê½{õ÷ˆò R½½! ¦³ßëN¸GeeåÊ•+ïÞ½;zôhíæ¥(ê˜E._¾¼w×Rž÷yLªªŒùôéc^î×ö½Q±Ÿ_«ynP>Ÿáè(È̬òðÀ’ÿ½]~Rõ¥KÕÿþ  Ïš¥á{Ô¹K0pàÀ¤¤¤/^TUUMž<™B¡ˆÝ²P]ºtirr²ÏÖ­[MLL,›‘‡ÃÝ»wïõë×?~433333«®®^¾|¹Ø¹ÆÓÓÓÞÞ~Ù²evvvAAAd2yüøñ­H*ö÷f±X«W¯c`Ð7*Ê€­xÃäœÀòZࡾþä›7 ºbåÚâh3úÐÄaq@}ø}Šl^}õê*páu™o"Q1 ªêƒ"1ËÌ”V XLç…áRõô³Ÿ?ÿÿBäÔ)¹éÓÛÒªÜôéªçÏ—J˜=ãÆ©þ÷_[É)»§:‰Dd2™Çã%$$XXXt©µÿ9ñž¾zžgˆÂÇ4Q`Ÿ¦¿NâÎÈZ²³ýtA+%¥•_(Zºl;$äÛ~NLVÔfÞ¶¿éÚµßÖ˜%‹SoÞpò»ëH$»ïÙ"Ùlvíq ;;{ß¾}'Nœ077777oQ³–––µºsß¾}Ùþè«V­JII¡R©õ-¢ÅÅÅÿý÷_ZZš±±ño¿ý¦¬¬Ü䋉Çã¿\»+n€À  ຉɢ;wú4pZÙÝPZμó*A˜W$b²Ð"zhÿú²òêž4Ù€ªü–ΨŽIN‹).A‰$*Ùö ,–zÿ~ј1¼ÄD€ÒÞ½ ßK[ °|¹àë×Ê¿þàLMivÕz½Ãeâ›7oLLL”••oÞ¼Ékïó°¡ '^õ?¶°pûYƒ|žò¢ÞTVTµ§9‘B!õïÛªºå»v1½½%%cÁîë6­p¹¯_Ó%Æjnß.ß½[¦ÌÚ~~~9©H—.]â6¹Ü<ûçÒ¥K’ßdggûùùÕ¿òãǦ¦¦—.]*//?uêÔ€²ê …€wïÞñét$=}",N°<¼,,Vü,º0ÈHáå[á×|Q^1´h·úÉ“Ç ¨¤Ù¹€@¢¨¨Ÿ^QÌ;A}‚@u ZÆ2èäŸ+(Оtˆäà€Ðhj°’RW=äW‡¥¥¥ †áÇ«««wá|R%$ºÎ‚/ßãßOÈ/Fé¥è¾µ„ˆ¤¬¼ö4Àãp8‘•UV+¶•GŽÔ§`@Y¬âÉ“¹­uÌá¾ySÞ®²µÂ¨*A_³Ïž=[±bÅ… zØSSSCÑQjJ¦¨¤…! @‚"bŠºäÇà­¬à&I[ö_Ø5êÃáÔáõ÷î]QQQýæÎX^©CÊd(§u˜‚õöãa¨Š‰–W¡êÔv>³e–•B›Ë¦/ªª*ž9³ªQš“Y ß|ŠÚÛY9çÕ«fnøyII…C‡²ýý›¾T (]»¶dáB´©G‡²X% –®[×$Í €õäIáС¼¤$Ù›Ðv,X° +++##ƒN§¿xñ¢]Øê BCCétzFFFff¦³³³4;äààpðàÁׯ_"""|}}iÓÖÖÖÂÂâSDÄ6[ Þƒ ¼ukþ¾}R¯o)Exçƒ(§  £Q©€@ ¸|ùrÏ#J\¹Ä4¯Hh? ()GËYê!/"dï];¢c=K··÷‰:‘HÃ0«³(Y%QÃB•ÉL‡¹îË#¡Ï¢¢’vÖ‡"‰QWÇèëóÓÒšw5‚éÓ§IŸ+ˆHÄ  ݹƒò›å"„ôê…H£P‘¡@¤~x~ÛA¥R©Tj#?~<77wøðá8ŽÇãYYY‰ù¥¿óLzz:¹¤ä £•”ÚÙmôðPhØöµwïÞ»wï<==LMM‹‹‹áüùóÝá±ëè ûX8ÊÍÍcx{{çå幺º*uGFaì„Å»ÿظe 2|0ò5­ôš8qâ­[·dïÝϱ;TUUe³Ù4‰\É0 ?{öLÌ_ÚÉïß$ +ªPÀ§tÑ->“…¶; .¯™ê „JUó÷'oÞÜô8)+«*íßßt€‘7l ùû7ÇAKqëVõ¤g9ü‚PTT ˆ¿zõêû÷ï·mÛÖÈŃ ²°°À}ý¦¨NžüãÚ5…FÏZLÞé襥#'¯V@G ‹J&Ož¼k×.MMMoI'íž!¬ÜœYÞ§)Ê0@AÙÀµå\02t™: ’¥‰‰ï.\3hP?ˆOó®!^}Ä»óŒ¯N…sßJX5×¾7â´(74‚¨üóê¹sè9Œ¶¶Ft4ÑÖ¶æ£ 4¢£1pÃÂ°ê… ÊÇŽÉ{ 2dÈüùóØø•JJJO?榥-[¿~ÎâÅM¶¼ÿþQ„w þ<|šHÄàñ.—»}ûv.!Fîh,Yu’/ýÀ#@]«.S‡­‡ó÷÷û×EDD˜›533 ¢PÆt•:”#@$"äyŸg5“[(ºÀ>¸=K…LK-V¯¦\»&•ÐÓ§zd$¶•8ÿÓ'þ§OR‹°FFêQQ©¶; †zýºÂÊ•² gàÙ³gáááµsrr¨T*ÒŸ2Š¢·.\`ÔÔŒ™8±™Š¶Eá]Û‰³úô—”œâéé¹yóæyóæU¶(±ÛB•¦OV56ŠP,ž*›ù?“:TQQa¸¤¤ÄÁÁiÆ û””T*u¨²²©‚‚^çw•ˆ‡>¥‹¶cõ«kPÊŠÛNÛòB+òWÉ/X@©çŽP©j]]©UDÕÕtºƒCCÞ¡]]õ/zឪ§O“\\d³¿€¢èOôƒÃÂÂæÏŸPXXøâÅ‹cÇŽÍþNf„¢hý==3ó ©öîÝü[4Ÿ"¼«°ßÝoçÎêêê/_¾üøñãünÏ<Þ:lÜí{í‰:xœìUm_t¬+ Ãñob¦OŸ¥@6ÓÕuápJa[S“ÅÊw~WqX`¨«(•Õ`–-võ~öß[òr`öÚv>ï}}}¹\®¶¶6›ÍÎÊÊ5j”äI…Biwb÷…››[VVÖ´iÓÄZ|Ú´iG¾S:äååIÞ‹•ý¡ð9£ÚBªëׯ_¿~½ûÊ2 æ@ûñ¤t[å”g¸xÇ?wÂ1Ê eì'Ú²ÙìiSm×.€ô{«S(CTTàpŠB€á.X×°8ƒ€}kñ¯ß Bc^‡‰³ÖÔl;Ê™:¶×ÁååCZ[WéÀù%KA¨·náâ}FÑÒ•+ÙAAâOœÐÐ’¥KAÜ!Ô»wÅ–X’‹‹’››lÞëèè8;;9ÒÖÖÖÃãŽo×øñã½½½E"ÑÏÒyyùû÷ïçää¼|ù2;;ûéÓ§b¿J¡Pèíí=~üxÉ‹óÒÒòóòì¨Tb ³ç…B:þ=–ž ƒþ¶s}Þ¾Ïù¹l¿º:|úøö[A~AùÂ©Š¤0MÍq$R/99 ‘ˆÛù]åò°¡py`õ|œªÔGÞ°¯¬ØÎÇÑš½zµÞ¨Aª/âGŽT9rDî;=t}TìßϼrEò›š›7+^§LQþûo¼…ÅË ÈŽß077·±±ÿ½yóæ:Çl{öìùøñãêÕ«»–e·¥ÐÒÒ9r¤ŽŽÎ· Ïå®^½:%%eÏž=’—Åz{÷ )**ÍlöäÉ““&MÚ¶m…BQSSÓÐÐxüø±l u-¨½¬Öoþ»¡4Ô2´ÒÀС­«« Ní&fäˆl\é'wûÄŠtu÷––&–—êü®–T‘`nqgôFfÙb{rGšcjبªR;«‡µOžräHÙ“A¶;l.ÔÔµœ~óŸd;ÌÜY¿¯¢Š í2 d5ùß7Ùséeø#Û'v.ÿELð•ÿ  ‚È›6©‡…!Ô&¼Vaµ  òÆ2R1ò¾311QQQ122¢H;Re0­h–J¥©¨¨˜4JžÁ`t9à [sÛŸÿÏUÌÂóJÅ‹/|òäIãU$— Æ ëÛ·ïœ9sd„™2ÈÔa+4¢Žý2_}£){OstÇU÷ÑÏí'vY‡ÒðÉžÚ3"Õ!«X7)gȇ\›Ÿe´ð#GªGEaÎTŽÑÖÖˆ‰!Œ“eAû? P?ËÄÊ•+ýüüjjjtttbccëÛ*çÎÛx³3gάó‘‘Qlll¯^½X,Ö“'OV¬XQç‚>}ú˜™™®fx™>÷èa¨¹‰û±óƒÒ¿Ì˜1£ ŠÁ$ò…ñx<œÌEY™:l(êüå×[8ï\)§­…Dw±}RGˆÉh/ã ïؾ1£Ûe÷fzy 23¥aûõSŒ”ÊDŠÑ×WŠÂJ§ªdfÖ UüE€Á`=z¤§÷D"yyy]¸paÛ¶m%%%^^^_¿~‹‹“äôrpp8ô¨!8pÀÞÞ¾ö£‹‹K\\\FFƵk× ƶmÛ.]ºtùòe999ñúúú=ªÕ"ׯ_g±X§Nêüb:öZlB™¦¶é…ã3š©ÕÈd²¤í·²²R¡½“¡Ëð¡Õjt…é´;‘Éäå¿ÿ÷ÀGÇsaû‘RÙ”jÜèèÒÕ«±¦¦‘‘‰$eÌtuÕƒƒ GŒ×~‰P(j˜X(Ñšº½=ÿÓ'lÿþx+«Æ/17xpOz¤LJJzñâEUUÕäÉ“)J@@€——EÑ¥K—&''ûøølݺ511ÑÄÄÄÒÒ²É6q8ܽ{÷^¿~ýñãG33333³êêêåË—‹íŠžžžöööË–-³³³ "“ÉãÇ'ý8𥥥ª G—vRÞ?Ñ×ï¿u×ÙØ˜¨fVéׯߵk×Äô§</++ËÐPF&PÒT+ÐMT§&÷Á`0N‹ð”ÿ^ç*K°×À)#ƒ>{6ÊãñèNNhí1úú´'Ojç"D$ÒüüÚ¡±`ïÝ;”Ë-ž1ƒß¨‹|ÍÝ»…Ítaý‰@"‘ììì,X@¡PØlöªU«j‹²³³÷íÛ077_ºtista-,--—.]*6îÛ·/;;»¶hÕªU‡J¥.X°ÀÎήVŠD¢¿þú‹F£Q( …òçŸ …ÂÎ|Á!¡} ŒðxüXëæ¦ ;vlyyù™3g ÜÝÝQ5jTmwd¯­L@µ ÝF@uA®» S–™à#›XRfÅÿÚ»ï𨊶 à÷¶TÒ;`¨ M)‘®D@éE”÷£«À y•¦X( Š¥D Š4%€¡Bh"Øh¡KKLéÙl=ßK–Í6’ ÉÞ¿‹‹ksž“ììÙyvΙ3“™™®IO×ý(ÿå—»–çÚ¶o×Îçûï!C,öټپcGKϼ;mZÑÎ÷¯¬¬´—^2ìV*>z4sÌÝäàJ“ј5Fttô;w ·¬[·N¡x¨‰‹‹‹×­[g¸åöíÛÑÑѦϜ?þ‚ f̘qøðለˆE‹é’ñcÓé¹f–Ö~²¤iÓ¦ ,˜9sf:u.\¸|ùò:uêèB7nÜÇl±zU§’>‘jmÆcˈ6//½OÕµk†ó##%îóæ™-âÔ¿¿û¼y‰œL†uèå|ôQÞªU¥¾ßݸ‘þòË~±±bWWÃíòØØŒW_Š‹hóóS{ôðŽvxþùšWÕF¹@aaaff¦¾‰¯€¬¬¬¢¢¢þ¢ÜÜÜ¥K—~úé§o¾ù&€®]»%%%•åW\¾|ùøñã 4pttLLL´··0`@þÔ·ßÝVR³fÍzýõ×oÞ¼ìS2¼Y©Tî?°_ä%À¹¤Ù@UD•j ¤|›«Ä¡–®8}ÚÌáòÞ{Ba¡¥™HÝ­v,r?ù$ÇܧO§vïî·oŸ~Ú¶ü/¿Ìš6 §>´99i/¾èµn]­Ñ£kXmwëÖM,žåkÑ¢…édfåЬY³K—.Ý?ñ"w3â› —Ë ‡­ZÖ))‚ƒƒ‡ rþüyÝÎÿøãŠý©..n~÷/säååµoß¾X^ŒÿðÌjqv[Õ(¦Ã'OýÏ?iýú© ZRÓƒF›“ã¹j•™™HÅæOw *ÕÝ7ßÌ/}úÎòÏ?S»tñÛ³GÚ iÆbggméÄÅ..Òò¬[]´k×îÛo¿={vbb"€îÝ»¯]»Vôp·iŠÅâèèè &>|@½zõ-ZôÌ3ϘvC臛–‹D"™>}úرcôêÕKwÁÒ’-[¶œ8q¢[·n¦3‹vxÐP…25d¹¹W¯]Õh4è „òCÌÊBeAÕl ˜Ÿ°â¸¸Œ¡C5™™ÖŸ–¿v­êúuŸÍ›x>MzzÆðáÅqqÖŸ¦ºx1¥}{Ÿ-[ºus ÷?~<=<\]râNä·oŸ¬I“Yí£F>|øíÛ·]\\|||*eŸÁÁÁqqqùùùõë×7{}.((ÀÅ‹õ9©\÷ð 2dêÔ©ùùùoèÅ´¬U«V£Fš5k–ièÔŸ§*áÕJ  òC\Õ)‘<æUl ˜«ùÁƒi½{£lƒâC‡R;v¬}æŒõÁÍBaaj§Nªë×˲OMFFj¯^~ûö9öìiâ›Ò¹³6+KR»¶ÿ‘#Ò’•ójjÔÐÜí›ÉÇÇÇJ~ nݺõŠ+ž{î9‘HTPPТE‹V­ZíܹSl®£Ÿ™™™ššÚ¨Q#ÝR½ÎÎÎ]ºt‰‰‰ ¿÷v Â7AhÔ¨‘H$ºzõêG}Ô¨Q£éÓ§8P&“Íš5+55õÃ? ,™½AXÅë|UN:u®—í3ËêÑ5PbˆOcÏž^+W–q BYãÆ>?ýôÀ}DÎÎ>;vÈÊv[˜ÈÞÞkÕ*Çž÷ÜËš6õ‹Ž{yùÅÄÔì\ø-Z´hÇŽ;v1bD³fÍ’’’vïÞm:iªB¡9r¤¯¯\Í×M IDATohh¨ŸŸß¬Y³ tìØ1$$ÄÕÕÀŽ;š6múÔSO·mÛöêÕ«óæÍÛ´iÓ|rþüùÅ‹oܸqáÂ…¬ùª¬ÿþ‘‘‘ºIäÙ@=©Šéð s™4Éÿða‰¯ïË€ß~³ -ÓU»–-~ûÍ¡G¼÷^^~û÷»ÜÀ¾S§:.صjÅ·æéÝ»÷‰'BBBT*Õ¸qãÖ¬YcöiÕwÅ ª€Ù³g+•ʾ}ûÞºÊê17P`€ü—_H4ð‹“¥´oï2y²[DD•®;LÏ4Ve¹¹¹†÷xèÆš–|!ô\­¬˜qõêÕºuëš]nP·b†J¥Ò¯˜ññÇsBµj¡yóæ–V~=éÕižx¥£øí·ÜO>Q]»f×¼¹Ûœ9•ÞGäÉÒªBä·w¯ØÓ³Ô)ˆðp¯õë+p¨•|’xoØàôòË¥ÞrOO¿}ûŒµ¢­[‹ãâNž LN»¸äÌŸ_m¾I¸Ê’““«W×ÐÓÀhƒ»¦’’’|KÎJUß3ˆ T¥7Pä¤tî,9¬IMMyöYÅ©S•û™«RËÞ¬™ïÎ"ÝvmÛúlÝZö[y,p›6Ùµm{ƒot´ÌäJ’êÒ%YãÆöÏ=' pìÝ[eá[j¤i¢Yÿíúj4sæÆcMˆÅbFÕ£ä‚Jõ]1ƒØ@Uz {ÆŒZÇûíßïþþûþGŽ8ôê•ý¿ÿUrÊç{\¥8„…yoܘ1|¸40ÐoÏq­JXšXìââ·gOJûöê¤$ïï¾s(™|Ù ÷ïè‹Q}N?jõ ‹&Nš¸jåªj±_Gs³Ë*Š·ÞzëòåËßÿý½¶¦B+fääää–ܪ\¿&N¡@6Ú@)Ê‹Ý?þøÞÏ"‘cÏžÙ³fA*qs¦Ã*ÇyèPåÙ³NýûK*mÝI@€ÏÖ­E»w;\Óê«64ã4ë¿Y¿û—Ý/÷yÙÃãڽ‚ììì½{÷æäälݺµY³f†¡öíÛëWØ0]1ãòå˺3ô—,Y¢¿§B¡Pp‘^ª ”ÈÞ^âë«JH@ÉE„âøx¡¸ZmÅOÕ2V à.1ûçžÓ­iZBó&õHêú¸õbyeŸÿÏ€ŸŸ_­ò| .((H+=%¿X, ²4 ÂÝÝýµ×^›ûŒéª5‘Tê±p¡ûüùê›7¥ Ê÷ì©ôtÈ‘¥D•L·b†~ŽÐîÝ»ïܹ³RVÌÐç¿zõêEEE™®˜1cÆŒ?üÐÓÓóŸcÆŒquu-û2RDU:)ÚÙÉš4Éd÷†ûUê™5ªw(‰¬Ü‘me,¾•‚Ö÷Y“2¡d9xA¡€½=?xãI­˜aäÚµkK—.]²dÉܧ%ª òV¬;;×úϽÕ5•çÎI4°´ÂÝ#L‡{‰éu '''K!ÅÅÅ–BvvvJ¥²¼!ëQoooKwd‹D¢[·nYÚ§•‚VB:jµùëUUvųž>gþüœ?–Ö¯_UküxèF£‰¹âyù<‘3ŒLš4©I“&“&MªÙUmiækë­“•h… V¸íz Šµ3V¢Õ«Ò5CYo¾©NI±oÓF™»d‰[É}‡•Õ@•)µJêJÇ6 ‰7²··?mnõdFýý÷ßå YöèÑ#**Êl/°^½zû÷ï·tHY)h%@*•&$$˜ UÍ[,¦Ã®]=?û,oÙ²¬qãÃÃÝçÌ {ê)‰—€«W¯Ê¼9L±šùá‡>¼fÍ©´&Ù‹tK.—«u²­pÁ ·]èµT´±­^ ×iÓÜß{/ÿË/ÓúöÍ[ºÔmæL÷¹su¡Êj Ê”•”QQQG5 M˜0aÓ¦MfCaaaüñÇñãÇÍîsäÈ‘‘‘‘f{lVBÖ£sçÎMHH˜4i’éW°åË—…††êVÉ){A+!Í›7OII1 UÍ[¬mÓ§×Ëʪ—ŸïýÝw"''~±±µÆŽÍÏÏÿjíWÊP%¨YÊË‹ˆˆ?~¼~ášJxZ¸víÚÊ•+ËÕ:YV¸`…Û.ë*ÜÎX‰V» "‘Û¬Y))õåòÀôt÷>ÐÝqX‰ ”kK[ã… ‘+Æ SKo…ä‰ä¼äˆwú÷ïox§³ Ó¦M;tèÐÌ™3BÙÙÙaaa*•*""â½÷Þs(™ÚG§¨¨(,,,33sÅŠ}úô1ük%ôÀèîÝ»GŒááántGö±cÇ~ýõW‰DÒ¸qc777£ŠÈÎξqㆷ·w¿~ýŒ ^¿~}Ïž=^^^}ûö5 eddlذÁÅÅeïÞ½F³¤¦¦¶mÛ688ø»ï¾«¾óƒÜºukĨ\úC5[—ò4Rf¤êh¶mÛV®-ž¬Õ«W¿ÿþûC† Ù²eËåË—½¼¼ô¡íÛ·<Øè#_2Ÿ…ÖI4[$ÜÂÂÂÆ¯Á¤k>úè£_ý5""¨u²ÞvY YÊåòaÃ†åææ®\¹²¼m—çÎkÓ¦‹‹KLLL¹Ú+Q6P¦ÇRÙÒ!ˆ…ìL•£2»w™L¦R©Ìeô{CQÌŽ¬ÓMÕ(‘Ht‹}pjµZ¡P˜†ÊÕý%¦Ë‹kµZµZmehŒ R©Ô´  Z­V,[Ù§£££QÊ×h4 …B¥RµhѳôÔ·•ýµ©2fU¥ß¢»ÙwÎ%Hü%ªq*TFËUMÄÖ-[WŸÙ|V¯^=uêT­V»~ýú×^{Í0´mÛ¶!C‡`MÍJ‡´Àjà<,]<²Ô:=0Z±‚ºËrh»¬Ð•ª@;STTtåÊ•‚‚‚ÐÐP£¼^XXh)TµÞwA€ÈÌ©ÌJo Ê|QA¼Õ  ̇ô—7Í^çÔ@£û¿f‹[ =0Z1VnåÖýµ–È!—Cn6tç«o:ÐB VíVÌ R©ºtéb¸V†NRR’ÌMfé£Z‰)V+ÄêK¶­XÁ6kÓvU¸9‹³ÙTÅû‰¬©v+fôë×/66vóæÍFçc4Íúo×kšhøž1•ÿ»g¸6!!a⤉"ÿ˜Õ­[·gÏž¥§WV('M¼tù’6\Ë÷”È,3×Y)T)jȵCç ùFâãåS}Ẅþ%:ón¦f¬-«ñûÀÖ‰ieœ׋–³š¨²Ôt 8éUi寘ñ:¸ŽZuc5ºîÕûM`ëD´UßQ×Tý<]ÎçÿÉ*#¢Ç„׉ˆˆ˜É6i…À©ý‰ˆéˆˆˆéª‰À4  Ð x°>¹±¬&†“à&“€ÿÂòÜ •Ô±[ œ|,¥ˆˆél‹ø/à ì~F›ñàùRjÇqŠã@mã¹åˆˆ*@Ê* '#ȆÞ€ö@û2”jœn Bà ðS-~ÎÅÀSÀpÀ¯ôv ð 00\ Fl4À{ ˆ @à XÜnFÀ àà)à&pxx ø¸†®æJ¸nîÀ "¦C²q¾€° <Ø•ù€íA%Ù€|H9€°XÌ$@$ ÿ\€?€k@ó’R¹À  H€$ xîg€§€±@&ÐЭ•¤ë›þ Lê°p>´ÀwÀ×À4 ¥Îã øh^:1ѓÓ¥ô„Ø«W`Ðx Ø_¶‚€‹@p38Sš \†€=ðPÜR€ëÀHÀp€’"ÉÀR 50$€p¤@C` å3±Ý€ @$‰À`Àp7 ¥º€èÈlDì’ 0œUkC䊱(=IMm` Ø |¸´S7 1ð# šK¶çJà]ƒgŠ€|@H³s«ý ¸] r^0Ø@7 ¾å?C'ü¨[`'ð1WÊ©äÄ ËXb½hùãÞæacVÍ™ó˜Éf[1Ýkm™0Ø œ/C:aÀ2à•Òǯ`| ãU@“5m.? ®+€)€sÉÆ6@@N+€G@dq-=¸j Э³{àZò§–g–ͱÂTDò1ƒßˆéjó‰0X šRà 4+Û«M6€€W7à_à 0ªdû÷ÀHÀøð(¹v(^~–o®À%à ÐðD€Ð"À HsçNkuíÀH@ l‚Ÿ•*W]1‚阩¦ò^6ç-ÌÂb‡"àÿ€hà ¨ ôtˆv‹Oí J‰‘À`ð $+»€/0º¤Ÿ× Ø–Œ5ÜÃxàG`6 ðZÉEy+¥ˆ¨ŠáÞô ã…R—|8…7UÊDôpd)Ó!Ó!8”†+^ $"ö‰ˆˆ˜‰ˆˆ˜‰ˆˆ˜‰ˆˆ˜‰ˆˆ˜‰ˆˆ˜‰ˆˆ˜‰ˆˆ˜‰ˆˆ˜‰ˆˆ˜‰ˆˆ˜‰ˆˆ˜‰ˆˆ˜‰ˆˆª.ðDOˆ8œä&!È ­¹‚j@ v+üot¬K¥ÔjµùO‚Õ¨H$2ÿÛA*•ŠÅb³!­V+‹M£‚ h4³!ëQëQÉÿ"óQA&ÀÑÌ7m­£VÝX.€;~b:$ÒI†lL“® mêî]ªu,,,¼réJaaaË–-ÝÝJ…T*Õõë×ÓÒÒd2™ƒƒƒiªP©T …B*•EuÛ{õê5pà@777£‚?ýôÓ–-[^|ñÅEÕjõ’%KΜ9#æÓ¯L&S©T–^¥•è#*XUäXx]™2•ƒ ½xZŠ˜‰äB¶\ölè³›Om 4Œ¤¤¤´mÛ¶m›¶QQQF¡ÂÂÂÎ;;::îÞ½»wï޺ΜQ4''gåÊ•FÑôîÝ{Íš5&L0ý[8°eË–Õ«W›FÕjuƒ ’’’ºté2a„ڵk¦Þ?üð·ß~ûßÿþ׿£$ªÕj§Naµz˜‚ÕBNNNttôâOk5šÿhÌw.‰˜ÉvˆöŠ|]}÷Åì«U«–n‹B¡¸páB³fÍ.\èàà°gÏ}@qq±ƒƒÃ²eËnݺuæÌ™úõë›îÓJtéÒ¥}úô1› £§OŸ>|ø°ahÛ¶mIII«V­š2eŠQ©o¾ùæøñ㇠3Ýç7ß|k6j%ô0«‹¶mÛöèÑ£{î8 täG˜ɶÉÎË&OŸl˜ðâãã{÷îýã?FGGOœ8QÊÊÊš7o^tttrr²ƒƒƒ½½ýøñãëׯ/‰‘<èùùçÐjó¾ø¢póf‘›Û¦ë×ÇW¿~ýüÈÈÜÅ‹ Ýo‰‰Ÿ}ù¥þÇ]»vÍŸ?ÿÒ¥KÁÁÁ³gÏ>uêÔÒ¥K9rdîܹõêÕÓ?óÖ­[ÁÁÁS¦L)Ú½;÷£„ÂBY‹^kÖdMœøe\ÜèQ£ÂŠví*Ü´Éè®ùûïÑ£G‡……A«Í6Ì0ôÕ‘#º‚FE ·o/ÚºuÍ… º‚¦»5*¨ü믢]»Ô7nˆ=<ìÜ„¸zœ|þùçGõÃñTUü,P•ÂSøô¸©îª5jd¸å×_pòäÉääd]H©T¾øâ‹111{ö쉌Œ,((hݺ5eBBÑÏ?È[µ*{ölû°0±«ëÍÄD]T›“£ÍÉq?^ÿ/_¥òððÐç´iÓ&22²sçÎ#GŽÌËËÓGÿ1 Õj»uë¦ i³³5ééºÇ‚Ju)'§K×®TW®ÅľMJÊ…›7»té‚P¸m›úßõÑKÙÙº‚¥ŠdffMœX¸m[º‚¦»½˜•¥/˜»`Ar»v…Û¶ióò”ÿ9bDj¯^Ðj«Ëн[wm¢–bïl $‰á–“'O8qâ„F£Ñ…öïßöìÙëׯëO~Ž=ÚÎÎΰTÑεÞxÃóóÏ!J±X•øû;têäöÎ;÷~—R‰wßÕ™?þ믿þÍ7ß5j”ÝòåËu¡×^{-<<\ÿÌ#GŽpqqàÔ¯_ql¬òÌŸ­[ˆ‹5'''Ý3%¾¾ºí:iáá†Qn3g:½òŠî±\$2 éd¿óŽÈÁAìê*ÏË3»Ûì9sôûTž;—ýÞ{^«W»Œ¯§xölrÛ¶òC‡{õª€“““F¡áØ;$*Ý7ÒhN:Õ­[·3gÎè7¶nÝ:..ÎìeÂûi5?_ìîwAÔ=Úw×.ýy_|aXäÊ•+ú€ÐÐPýc??¿ý}ô‘Ù_šY¸eËýTQ÷Æ ý…ß/5ÿ233¹é=%Pœ8Q°aƒç_ˆìíÍî6wÁ‚ÜE‹ô!mff­Ñ£õ¹€]«VÒÚµU/òX"b:¤jìüùóyyy3fÌ0¼ç/00ðáÇŒ*UþÊ•†[‚ƒƒ;¦ÿñÀ–þ¤¸¸8Óíª‹ïN›æfÐÝ,ýû„ÜO>©5j”ÑæÂÍ›}|î˜ Ôê¬)S{õr4Èì.óV­Êž7Ï뫯ô[ºw÷Þ¸Ñäs,Š‹y,1R5ö믿ºººöîÝÛèÎ Cé%×íÊ¥pËMZšá–¹sç~ýõ×S¦Lùù矧OŸ¾}ûv³W®\iØS,é—iÓ9:ºÏ›g¶”<6Vyþ¼ëô鯯öíµÞxÃ?>ÞkÝ:ãl÷Ū˗=Kçl½‚o¿½ûöÛ"GGùÞ½V^fÞ²eêädÇ>}x,1R5vòäÉ:H$’ŽÍ ½×jµëׯ7<«YŽtøí·Nn4hÐæÍ›ãââ ôË/¿Ìœ9ÓlÁ½{÷>ܸkxó¦&9Y›“£Èc&{EF:tïnתÕýM‰ßž=îóæy,\èÐ¥K­×_7|¾:))÷ƒÜæÌ‘5nlv‡Òzõ:w®5z´È`n©ÊÉÎΚ0áK—Ú™æo"b:¤êÕ;ìСÝÿF™òé§Ÿž0a°ҷ+”… —Ÿ8áØ¯ŸÑö¡C‡^ºtI¡P\½zµwïÞ¦/\¸””ô /nÔ¤¥i’“½¾þÚyذœ?6óû4ù¡CÎmvìÓÇýƒÌþ…w§N•øû»EDXz ݺù=êµfÏ÷ß¿:µ:ÿË/ÿmÒ¤(:ÚwÇשS+å½Pß¼©¾y“Ç$Ù&Ž,¥')--íÆ_}õÕúõë•J¥ahíÚµS¦LéÕ«×æÍ››6mºbÅŠrí¹øÈ¡¸Ø±gOóǽT @£13¾ñСCÞÞÞmÚ´1Ü(ñó³kÕÊyÈ»ÐÐÍõçNi³³J'Q+äýô“ÛìÙÅÇßËp¥_¾õ¤•1dˆòÂ×·Þr›3G\I3Ôryú A‰Ž™ÌGÄtHô8qB,¿ýöÛæ’$®^½:yòä ¼kiÜʽ&ÜÒLÞPœ8!kÖL`¸qñâÅYYYK–,ÑÿvÓ‚ ­[·6#[ìê @Ö¬™Ó+¯`ÇÓì+­WOlú …ivQž= wáÂÜ… Íö5¿ÿnÿÜs¦m~~jÏžbÚgÏZ:ËZZmÆèÑÊ¿þ1t¨ïO?¡ôÍ0DL‡DÐÉ“'CCCçÌ™£ûQŸu]4ë¹P¨üë/h4š¬,Ó¨êÚ5YÓ¦F[´h1`À€¤¤¤çž{îÚµkëLƶ¸sçNPP•ßë>w®i:T]º$3wS—º|~üQ$• So»¾õ–ËÿýŸá3ÿmÜ™™÷’å… ):y._îúæ›FY¿øÀMJJíß{zÞÿ-]»:ôìé>wn…߈»3f•¼¨¢]»²ÞzËp8+Ó!Ñ#´dÉÝi#GŽüþûï §-((HOO·´¬’Ž[DDjI hssÍô¯ÒÒd-ZmìׯßÎ;—-[¶téÒ€€€+VLš4É´¬ŸŸŸáòŠãâ4YYYãÆy,Y’o0回:9ÙL×pÿý´ððäæÍížyFùçŸúí"‡û]F&kâDmA>jת•ÇâÅwß~»àë¯e!!Jƒ;2U7nˆ¤ÒìY³J%ã„ûÎ+üFä-[ftƒfþêÕ²à`ÓQ²DL‡D•oÀ€ 6 ›)tܸq_•ôH^~ùe£.Ú!Ctœ´oÛ€}‡uΟ/Ú¹S俆qãŒvîÿ‚¿zuŠÁÓ¨é>»wïòì³Ïš]ÔW5“ Š‹3ßxÃð¬fYBO¤àƒSaaaÆÐ¡sa‰œ?Î6L(,äQJì=BjµzòäÉ‘‘‘fÏž]–PÖ„ òƒ(NŸVüñGáæÍ†¥¬Guþùç7oÞ4{£…>jÚ[Ê7®`Ó&£™nŒB†3¦>¶‚"iù>ÈêÛ·Ó^z©ŒÓœnݪ¼pÁ/&Fju Y"ö‰*ž  ¤Kxå%%Ýo©M²•¨\.ÿüóÏ·mÛ6þ|ï½÷Þ/¿üb%Zj¿ZmÖ›olÚÀxÊ´Ò¡¬7Þxüƒé^Ëô-¸n]çW_-ë‰b±ó AÒºuyÄ{‡DDTTTtttyC=z¨._¶´O+Ñ÷Þ{O7uðàÁ-[¶<{öì ƒq"¦Ñû=±ââÌ1c Vq²*0X¶÷±Ôܽë»u«ÈÙ¹¬U/‘¸ø¡}‡Æióò¬¥ÂZµ¼£¢Œæº#bï¨2ݺu«!÷÷ß—6lX¨þÎúäädŸ VåµÍ~÷]³™Ézèq”ÇÄdY:d‰cx¸|¼ÄÇÇbÒôõõ?vŒ¹˜‰­W_}U·¾n“&M^}õÕV“_[ I||übb$ÞÞ÷bƒYÊL£zï¿ÿþªU«~úé§£Gj4𨨨={öX‰êCK—ÖúÏ̾+¡ÇYÐyèP¯µk+ðصiã䈤vm3¹°vmÿøx»Ö­y Ó!Ñ£Õ²eËÛ·oŸ;wîüù󉉉¿ÿþ{YBdMšø=*  öô¼w—‚…¨~»““Ó”)S^yå•‹/ÆÇÇŸÛ·—Z©ŠÈp( =a‚ lܸ±k׮ߛ.cd9@Ú¨QÀo¿öÿÊíÞ½»•¿ÇJÔsùr‘Læ±x1¶m³2—™ÁòrèÚÕ+22sÌ^ë×;Ì{@ÄtHô8ˆD¢åË—ëýõ×e Ý;¹a!–%Z‘?U*õ,=·gYBO¤`Ô=Zyæ D¢Z£Fñ°$¦C"z­V[S_šÇâÅ|ÉfñÚ!Q9dgçôï?©ÆöÔe2‘¹y\‰˜‰è¾¬¬¬ÇÛÛObUÕ<í§»áR ÆÃÛÁ©«…ˆéȶ¸ùø<5yrŽX  7 †HÄO Ó!‘í>{v|XOÀÍ'È`1Ù©TÚხԩ“%•j]C Ö&"¦C"[Ò¾K— }ûþQ¿½s{@Æ !b:$²Qo._þ½³½½¯TêÎÚ b:$²Qööö{ŽÄªT?hµ<[JÄtHdü½½×®§T®bU1Ù´úõëùeDM}uÅqqÅqq|—‰éˆÌ××·F¾.ubbƈ#F¨+q·Ê3gxÌÓ!UÚ¼¼ô¾}5iiš´´´Þ½µÙÙ•²Û­[Sž}V¾?k˜ÊGV“€ úcX Ä–ü˜¬¦Ó•ÀµíPüÌÞÖyL‡DdÚò¨T¯¾ª…Û¶YzBÑ®]éýúisrÊ»giÆbggã¶ÆÅEZ¿>«ÊçÀ8Tz£ ˜8‘À4`ð{IèE`¾IfS”$W`3 ºt)¥C£s¤¦ä±±);ª._.×ÎÃÃý—Ö­{?Aù;æðüó¬y*108 Ü-½Ý  ,>:ß º1ÛËÔ'E ˜‰lžúÆ”öí˘äT—.¥´o¯¾q£\¿Â.$Ä/6Vìå@R»¶ÿ‘#²&MXóTÁ@`·™Á/÷R]gÀ¸iyµW@Q j3Ù[·êrÕƒ¿{yùlÙ"mذ¼¿EÖ´©_t´ØËË/&FZ¯«*H Îéùl p(*k“è1³Ci$@' H ŸF@€Éç‚UMdƒ{÷®}útZ¿~ª‹­¥´à`ßÝ»+ܱ³ïÔ©Î… V8=? ³ÁDO °¸€0hiu/ÅÀ@ ´Æ"¦C"*é#œ8‘®øí7³O°{úiÿýûËØ‰4¤¼pAué’™¶lÉS¦TÖá[¥· DCP iïEsÛ%À@` ÕO«Èf‰ÝÝýöïO{é%ʼn¦;¿½{Å..Ømá?æ.X`ºÝãÓOÝ""XíTE?¬"›n\]ý~ùÅ.´Ô7mY³f~»vU,Þë¶i$†ÿ$";;V81QUmÜÜ|wíÒ_á“øÅĈ==+¼CçaÃ<>ùäþÏ‚óñÇšôt‡®]YÛTeñd)Aä·gOÊóÏC$òÛ³Gô0{³ AHˆî±òÂ…»Ó¦9âµf]«V¬jb:$¢*Íîé§½V¯`×¶m¥ìP›=gNþºuömÚüú«}»v¬db:$¢j Ök¯UÖ®T iýú …÷† µF‚HÄê%¦C"²-ÚÜÜ´—_–Ö«ç³}»ÄÛ›BL‡Dd‹ ·nÕfdøþþûÃŒÇ!%«JO@*¦)Ààý’ ‡-ÀÛ@s€˜ Œµp3"€Ã{àsó©éˆ*»w˜ž.©]Û(;& ’²~èÁzCJoq~2_@®Àå’tx ÐVf ÎßX| o´ N$ ‚P±(UŒ´Aõ;ºµuÔ7o¦vë¦:wŽ•C¸×tÇp è \/™žô Pp²0gi[V2=f{IQQ‘Ù“““¥R©´´O+QooïäädK­GÕjµù— ‘h,¯o%úˆ V5={Šd²´¾}k#ñôT]½š÷ÅömÛ:ôê@£ÑˆÄ"üBåj8€§€+@' ¨´~ à ÐÂÌ4¤åÂÞ!=ö£º®äpüa³¡øøx³¡Fýý÷ß–öi%Ú£G¨¨(­V[Þ¨T*MHH0[ªN:ׯ_·ôÇX‰>¢‚Uî-öõõ;tH$‘dM˜Ö·oîgŸ9öëç·oŸnVš«W¯Ê¼eü 5‡€ %ÿ¦º%¨›×5ph8Àu øÐ͆kvù_¦Cªš””QQQG5 M˜0aÓ¦MfC#GŽŒŒŒ¼uë–Ù}Z‰Î;7!!aÒ¤If»V¢Í›7OII1-Õ¿ÿÈÈÈüü|³Œ•è#*XÙ?óŒßþýõ‹ŠêËåII^«Vé.%æççµö+e¨’²¦°¶äß—€; 1¤W&€h \nv% <=Ö²âéQÆ "WŒ¦–Þ É7ÉyÉ;ïôïßßÃÃã~D¦M›vèС™3g…ärù°aÃrssW®\Ù§O©´Ôyþ¢¢¢°°°ÌÌÌ+V˜FwïÞ=bÄððpÃ}ê\¿~}Ïž=^^^}ûö5ŒfddlذÁÅÅeïÞ½;v4,’ššÚ¶mÛàààï¾û®~ýúF;´}D«‹[·n5âK¨f«àòÐÕÌVXø™ ¥ >Ú‡y€+p ˆžî“Ëp²T7”æ3ó× ™é±§CÝ Ù!™*Ge¶ L&S©Ì„t—Ð$‰£££ñ.A­V+ KQÝÅb3gDAÐh4b±XTúnq­V«V«Aptttpp0 i4…B¡R©Z´háir;AQQÑ•+W BCCpaa¡¥õ¨õ‚UèMˆÌœxº›}7á\‚Ä_¢§2]y•éœlþÏG»;ÛRKá8éòöŽ×S8?„™z©lɲEÿ;%)9£8.[²ìdëq‹ûwJRrFíŠY`74ì~æ…—õz¼ ¥T*.*¨¯[}ñÆõjµj¦ß›)IÉ™ÃñT؅Ñ {_ß¾£«§wiyÙ{¯Ùœ–ffÖëóu÷ôþã©gþô·–•]rᆠëÖNôì îõµã?y(8ìžtý÷Ü5éÊ·.ûݤ+j]zAõ—Òr.Ÿ½…±¸ÌE—\qš=5>‘­^šìñ¨Àä:-=¾c†ê$=œRI ü¤‹,Q0„y'õqëÉöŸþòwK—9ΚU+kV¬®]››Ðm­*¥"';ó?Ûßݻߓÿ~îË÷ܵ¤¬tžú˜RûÉC—Ü|Kº^?Añ-ÊšI7_´ÉlÍž¸>8}{ßøÙœ8pÛ÷œfŒ¼7xô_ýßübùÓIŒWº×:ºç®åpŒ2yoùãÑÏhéU– ýÉ ƒÿ~¶óg¢!„!„ •fSá'¯(øä;£5µ<üÈ£m\£T(²³³ý>ßsÏ>ÿ›_ÿÖ ×kµÚ̬,«Å’‘i[¿®îÙç_6mÈûù¯ùÌŸ¨®ª˜>¦TЏGÒõzÏ /$^ñl©ºpuUâEwß÷Ыí=áàÈX³:ž·?ȋ᤾å;¿6º_0ÒoþÒíU¿Lž‹H¿´Ü{˒אּ]±¸OÞÖó››.»3[¿tÐ߉†^䣼À‹í®c¯tÿñ²üO$¯QÌ,úøŸO=»fõr£Á`4­ii,Ãè´ZƒÁ08hïìì:xð`Þ=ÁPP„Ë.ޠѨU*åkWýë™ç§F?¶6-à6’l·ùv¿îþõg®þaRß²kàÿv:þwÓúë×V_dœ;ñ Š$æ |fË_ìýåÇÖÅ}lˆ÷—š×úÇH´ç°{k£ë¹Žç;^)4W‚Jâ{ã éãæ­u«ªµZJ¥R*éééË—-÷xG÷îÙ/ˆ¼^oH³¤1 aY6-Í$ÏóµúXSËüíãé%NÝÉGÕ ,Pvû´@&$¹8nñnÛóç/]óƒÊš¼·ìw<ÿÆÀo¾ò ƒácþ¶5U—î8øÒ¿Û|ù7’ôÆãò/\õðCÛîæit]Öõ‹ødOCZΤá Qâ&„D¤aûŽÙÇ’$¹Ý#–t‹Z¥R)UjµZ¥VçåååçDy^¥TFùh àçy>‰„æyž°Œ$I§¯HÔBª“Ü|û/¶=úùiqLŠ$zG½¯ìõþï=W?¤P(š,£âˆëµ­=¿¼õÊ{%6ÄKá€àî‰4^PuÅ[‡_z±óá«‹?›Œ— 4Ìrìç6ÿì—/™ÃæÞ¼ˆ'„!fU–78“w4^A®]Q£Pª(•@!QI§Ó©>Êó„0µF¥Vë´:Ï3<ì6›Í“¾ú”‚nñ'ˆ¼Ú`ƒÈÏ„xÂ$«‡Gž;zöÓ[~H8êºÓ¸|?n¹jêJNs¡åã«Ó®;…·4»ßþwǃ·où&§€3ÚÅBÅAí‰8ijfée»šŸÑqæ‹ó?r OÞãxú¹“? ñþiÿ—§aŸh×°¦OoúÁ_»§áËòn[L ƒh8ð„ð„€$ßü›MkµQ¤£££M-ÍåeKlV«ÉdR©Ô,Ë ‚ IR õŒvww?Þär¦[ÒÁA¯[>ú'”`)¿×Ù°7 ÀÙð'5û¾ ·™VBÕŵ‹ß){Fžlмrû¦$6âB!ýà–i‚ÄNï'^zhUÚµd‹CÛè¾'ÛøÔæïhT:'ßJ)¥QQŠ¡p·Ä1«J.yµõ÷ΰ6{Á“ä¹öŸÝtÅ]eiõÌt©„ˆà I£Z&ý¶Ë¿ùØëߎ Á-Ew/ŒA!ŒŠÓF˜a˜wT_³ùŠ {‹Š Y–õù½‘h¸°ŸaAÂáðˆ{dÔ3ê÷û}>ŸßïW«Õ½áБãWmº|þú¸¡òº«7^§ÊX›xñµîÿ,­X ;*¨ò=vŒR‘ˆåVk…%]6Å Ié‘·‡ÿÒ.¼}ë_o@Ž]ìï@©œ­M)¥TÁhlê"AD*pdÁ².Ï¡'NÜû™-?2jÒœüIùá Eì-¾Vªfª 6>sòG…a¹õ²…¹\Q¿M[<lŽJS‰„È‹>!b~dXòi™ô]þ_ãøÎеÅ_Y»‚€¨YŒ’Øë“,³Å+Þ{õ–A»óÍ·v‹"5è *•šã8†a$I ‡Ã•X–U*•F£133S£ÕíØµ·£«ûÚ«6Ÿf¼Ûÿ »÷k$>à껟ñ¡+?ýÄñÁÁç[N´ ¹“Ôo =Ò-í¾å²/¨s(Ú €J£¥}ð[oüãÛÖôÅí úŠã—Ã\ëõ×uúDÊsDMiLõÆ4¦6%*Q)(xSóûãòù¿ˆç…÷%«5©²tœ™! admLâk d#t€eØK×^óæþÿÑúÍ•›Ì#Ð;hûõ¡ÛC¼o:»‚BXÂÉ &„!Ì×w\06Iœæîšß/â¶âûy„%e%×_àt¹Žkjniõú|^¯/*• –e5j5Ë@¥`³lÙfsZ{gÏ,c¨ycþjR4P½îj)»òñl]Ù|[Âáh„ðþ—¢b5*…Žc”ñ„“ Š„iT@D¤Q-gÖé³ôZ³}¨—ÂJV;çóståw®øíïÞùÉÍß)K[+Haž†)$ðˆM–ec“…RéÒe7‰‚ÄG»·³}¨ñöê_,îÞøÜù„a(hZš©jiyYyÙèÈH[[[~~Ao_o_oŸ-#cpp àˆ’¨T) ÃÌ>1`dQZµêBUÆŠ¢„Õf®Ø¤´,Í+YŽä Œê¦¼==ð­†Ã¯¯®¼¤+²ßqPê¡ŠŽ©dJ©”ð3¥QžÇ¼·©ÌªŒ¯¯}6ñÊ WÊ6…D)¥"d+œ""„î«ßÊ1ŠñÑ"Šy÷ò‘0Óˆ„(áýŒo쟲0 „•Ú5{í !îîÚG•Œf¾qhòO,ûå_^¿÷ W?¬SÝBOXòJc*_‚HBrÀþ|$Ìè–³TÓîjüHÕƒåæ5gÎ>–ï`†a4J¥T* …‚RPI’D‘RJ…B¡V«ŒF£‚›Æ5>5û˜€•D>i}¨g僡޷) vï°ä.¡TL–E”ïÏùž"hÝyøåÅ =²#a>ŽFÂ|üO4’ކ£Ñ0Ï*1*R*Íw¶°j gHü“6§‚Ÿ4€šÓ%Þ¬`Õó^Ñh4aMÂÇó‘Дæ„y2òT+w{M6ݹüwóqLJL«>TþÝ_¼x'äÒ³ÖDÛB¤üØlÉ7WTÖûÞ,ýFµõ’3j‹¢€ad»ã8µFcSpV‡Åb³‚Ïóé–t Éép2 SK¢(2 3fÛÏ©[Û»î>šx%úÞüMÀÝÃ)õRÄ6B@(• ñ ’ Q09y×eée¿ð޾¸¸Óš°ïÍùÆËö_¾}äŵK¯ <3à=A)Öd_0ˆi͸OPI’Úœ‡ˆDØÓKR‹kwD„@¢5~Ê¢bµmöÆJËÅ,ËrÌ€ÈwBö]—ymRtÐLúXE¯× `<·#¾"1 ñð„0L‚;C¼Û=’–fæâºyvû¸ä²¬u×®Zvé¸Í'QéG^TÔ—ÝùDýU_¼=‚PyP UFUËÛBîæ‹W¬[šgLF-YŸÓõØ®¦m«J.¡j¶sä$WŽþuªÞ¥TbYÕÅ™·fŒ4îOJa1(;—ÒiµâÚÒ/>ßþPûàñi¡¹iÅG£a¾À¼ÜÊåï>þòrËeï+ûÚé¼n™å"^úò#/ß÷ÉÍßÒ³¶°à!‚4un¶²rWÓ+r>xqÞ-g4^A) …B==½1»bþÐÕÕ¥P–›ŒÆ¾j˱ÆúrW÷îÿ÷`í…0ånˆ™Ýt¸«ñÐö¿ù×=–ì8ÎŶO¨Ý†=­O­(ÜXdX-¢(ñ_«x)Y!Ñ+‰"•b;§§¥/Èyÿ9Ó³µ¿ºcVéXó¾¶××çÜ´©ðŽÓoA­msD ?öêw>vå×õ ÛHÄ.аAiÍWÖ¾uìåå–‹·}úØÏ ‡#§€(‰ó9«E¡P¤§§p8yyy½eÉ)Ç+@ }ð‚§¾¯Áö¿y]±œ Â0æìŠ'£ŸºL—äK}úZÖøFç–f­á£|²_G%xÂöDŸ2yÂó#)woß\ðéyZ´˺ŽCO¼þã[.û"Ë(4 c¾vMÃÑW Ô+®/û¯w&~Ì0„ãÖô´öŽî Öe(Šxf4­ˆ˜(Uª¬Ì¬žA›ÅÂq –eÆ"ª§¨4aÃÃ_þ‘B¡Œí„Çä;÷mÅ™’å¦ÍJV÷ÒÀO -+’÷ eHôo Â,Q’æÑÚ½]ÝÃÇn\rÿªÌ«÷És?•BÿØþð¦uוê, Gß0"çÕßKö–Þôú˜¢Ñhrs³×¯­{ùõíœBñž«· FÂ0Œ^¯—¨ÀœfR(•ÙYÙÙÙ9--­'Ú:®¼ô¼ÜN7f4/X'´×d.»÷¹IÿoЪpe©~£:WÿÔÀIz¾šÓöŽYUE>n¤:m3^ énN×}œI:‡¼ú'Ué“ñðËòo ÁW÷<—fLGHuÛŠ‡’MjšM«Tª¼Ü\åFevVæÖW_ûö÷´zÕÊÚË­Kee¥$Q½V§VkNç‰Öö¶öÎ4“ác7 ¬´Äf³©ÕšùÄ+at:ÃîÈÌÊL¼¾¦àê<µ À_!v±q[ÅÒŠ’ÄÛìÖ4Àr¡®öæ¼>Ùw2~yÞ'þ¼í§*N  J ò!|aÞÍÉHÛ5(Ì©z°Ä´2y=vuñÝ|{°Ã}ðîšGÙyǼ“bÇbÆ9ÙÙf“©biyoÿÁÃÇž}îyŸß …x^Tp¬Z­Òët%Ew}â#ù¹¹ƒ^«Õ*•ÊD×p}Lê×Ô=ûì3>ß„½Í£†iܸ“;&³»¬i†;nX=g o»ãžÓï¦lMŇ ~šŒ¸(ï#ë²?“õ4«™Ï¦Ú)È+~“©+I6°®+ýjT -4”ø1Ã0*•J¡P «ÕRUY!ð‚$‰’D)¥„†! Ãr«T* ˲S³Bf7*JŠŠJŠŠ¦boš[o<Å.Ö)ŒVUa’Æ@ɪ•óßà8m9 –Ûu¦@Œùœ_ÛÏã8N£9•ÏJ_‘’3 Óœ'´¸§@œ’wÇ©C±Rr>à8%)9åÝ{n,ÏGSÃ^á8vÚ»JÒÓL}ü·©áOIJRr Á#©NHIÊÏKIJÎj?oxÍ0.4[‘»ÿò•v…¼§G<'.|«Õ8!‘øÊ/ÜQa¢h¸°áõåCñwpæ¶µõ',J ‚©c_}ÓP™lКד—åJ7Ô PŽë¼#V{_a¯K+ÎçLÔîÌÈtdf ¥éøXÂ^ }ÃMiÓdIÞ˜ÓQZ`·ƒJBDïqewµ;“Sˆj$¿¤3/ÓmÔFªˆLÃö‚öŽlŸ0éFŠÚA|¶=È‹BEàQ¢ÅŒ§óñH&â'ÿ0Ù›Wp3§‡‰«·Èž0.\ £ ³ {(ÍT2L4¬ x¬½ý.=/7LJ«|sCY`Ú§J#oî,óO›(zÅ1¼Ô%£DRáÊËñŸqÕÇ(½Ö윬!“.¤QGX°|DëµÚ{‹zœº„ÖKJ½Û–áÌÈ6ëƒj•ÀP.Ôºrº: ‡BLòpLsð÷ŸC÷ nûÏÂî"Y9®„1 †œc›Ñ3dZÎ|rÍ8ˆû×6'€˜3wÖ®jÉÒ‰ _#¨t›ÎcËí,uT8T2:GŽ0U¸hù𼺠ä×6¬È %§²ZOF¡Ç–ÛßÕXÜ¡k—v²®î„UMã7Fµ&—ÖäÊÉÍ;´gÅ@ñM‡ð—~(`m cƒìøX1.]†S:•ƒ5ôÖÔÍÑKñÔ:¯Zçµdêv]zÜ}(1 á7Ý3«:>§æí•Y‰JTi}*­Ï’ݓ߹f×q«< ŠÚ‹eN˜þ¼Æ0¢1Œdå÷µï¯OèÅÄ1‡7ïÃñ4¯`ÅÔ ÍßÚVÛsm‰P£Ì5/ñŒ0s¸}M}‹u Äê›\ª1¬0†Îºúã6%H![Û±Ên—^àü¶‚–ê%N #i³šêë°kO‰OšÕT>W®Ë™éŠ7Éž1—L2—XžbhÄÖ¼¯¦ËGÓËW—(8_Ñʃþ·ÖuÅT›ÂYµªÅª"ÎÊ}‡Š¼d´tÕþ%žÕ÷Õ®Òùw•{cŸ¤Æã îÈÅûªqRÂgáÇ.0Àò.|¦ß3W½ôªI3дtÇÆ%>HЯW JGõÚ#9ZJ( —4µ:=jªéMîÌ\§8Mo‘¦Kv¶ëæV,„Ç÷¢l–‰6÷·æ÷:Ò|mTŠê3:—¯hOWD45vo<éÇ‚Èèî¾ ÿ^ HøÇýpÍ;uª³ûÓcO¤Œ[éI ;ws¦öºµÍ2ˆEC×ú&ç8ˆA…Õqˆ‹¦¶}u­vcDdĈÑÞV·¯Í$RPZN,/ ̾v„{VíhXÙÜ‘3ìWÌ6ªòb/KogULjZ4®ÖŠÞÅpYéP¬OTY]¹’¾§¥d$ŠaËÉy! ¬¹³,3¾FdùŸN—á¨!~U {ìEof•;\ï“ûU°tõŒÙi¢¥üx¾–@ò•îÛ[Ù?¢å%FˆèFù'®>9zÊøò¸3t©g XqƒG×7žÈwêÃ<#‰jï`Åñn}lî0ŒOÎÓ½êÍ7×6÷X}V4c½òšFÔöœtétõñ”†ú6àŸ@„Œÿó±Û0¿Ìɉ-Ä’·°Ý)cE“Õo™q*PÎØQWßlSÅ`ªï>P<Ä1õ¦Ë:^p–vzŸÅx:K¼¬Ò {M‹Á:PØ­±uŠªÜîøhHf÷ûY9˜Î æÜª÷Å'‘ä×äÁŒÚ²‡åÏ£ïÅ Í‹ÿàšqmUfvçÄÓá"ƒÅ}¡øïpCyA€2Ã]EžEd˜ãÅ@.~`9•'Pu(ÿN>ëÄñœÀ„ÏãFG 2x‰ QO²û€ÏwwO%ôÚãÀÀÀWáYì ¡zNÅ„~îü$þÞÏi(ý@Ž9f&¿#¯Ë*β+ˆÚžk­r9¦3aŽêúµ¬kõ=ëŽ%˜ž±¯×Z†tòlcF]é“m`Þâe²3$0º!‹–ŽNË’Á4†Î„Á ‡Ô@QzLZêòƒaı>ž–PÇ#/qAgy«]ÖÊÌ~›üdôdÝþã%ưÀPQéw–5, Ò¸é’ïâ@Ä·¢”‚2øÙ2Ÿ‡›H m;®yþùk¶n»ì­e®¡£-ª=P>ýÞCÔR±·®ØÇ€’@_Mc‡a/OÜ ( „ãWn³øyR6ìÚ9<¾òÏÓsµò:¡qÚÍRlµsfÈhÍqL¥îШ­gPÃ:£qT¯kÌ×I“Ç€†Æv­fjˆ˜×jù1[:<}G„ê1SBÁC…SÄJUay½f|]kÞjXÖé0£¬$1|ÈàìZÚåf¨¼4邲ûß…:1ÞÅ7*qB°¯ÂV6¶Aƒ/÷L ‚RMN·¼ŽQÖÝU8) χURüŠÐÅ×q6à“{Œ0A­zÆÕ]± Ç!«÷kbŸ±"œ(ÄÍ ê4‰×ŽT8–i.Ö“›ë™<$j­Ü³¦lTAÊúkgÏf~ H$a-‹kèãÇ$ˆÄ( #«D‡Áì8v)‘™C¹Yq‡ˆ„Š×¿X<õK–&¿+4±i’¶ÿPµ»¦aEvˆ!`4öëÒ†•}f<ê6l RžLV7×3ÑÎV¸­fy‘‚–¡Àéã˜ñyŒ" q afÌà–4šH|ú™<ㆠ.>6Þy£—´ÊþîpÌL¤( È:CT£›Œ™èV!(€c‡ÇžãÏ+Žyœ4’ÝÙ§™4âÔgòÑþôÙZÌH³G´Èt!ðuNyX¯¿0¸q þ5½ª|Æ íYíjMdÂ'$b«Ü[Wâá@ïʆ#Ù¡9âØ;ÄSÒ÷k€³ècbdžÝñfQäþïÝŽ~k¼cÉ0Öíš!dÁÙú3ç:T‚0#¹ÓÚL’®÷`ý»ZÖÊÚÁšúùÚñî§£ùÝñ€—"«£pÂ*$‹Ú³âk´»À³§ðð®ì!Aîú´ôx(Ÿñ¤›e{4ìÈvÏŒUVgžŽ bZoŸA.ó7ª‡” £€Ží$ 0®=ŠI`bÒ{òñøOo‘sŠ›LC™ƒ£²âçtµü¡¢Î k 1yB3œMsZâK´à7#^Ç¼Úø #aÕWí±¯g> îþ/VÎÈ FfÛ“i5 ÑIDATÏ“pÁà?}KaÚƒljÀ>ŽÏ~Ï܈À(6þuÃ3Œ{F®SSÑœ¯¯¦óg‰dÎÔu–MSAHÒ÷6®cV7Tg†F×_³ŽÐÝ5±1 ú®£K²Ö7[ ìÈÒ58¶´wX'rkAKõ’јÆâGÊvéç0©HN[W»­ÌÇj,j.qÕvù¤ô²–°3Å݈ÿǯ÷V‹šWp×+³¿QéȵɆ£0”54ImP½Ó©[bò3cìÏ1”¶N»o%é»ëÉê†êŒ!`u}µëmX1"$oé¾=¨]u"S+±:{U½}BÉ^Šˆ»¼ñ@©w®]¡iSpt¥;ßS 4P²óª €m­;ªkX‘bT®ª¯V• ÝWv%X/Œf¸°Ô5éHJ£+÷·™ÇÝΞ||Õ‰_: ê;Ð:1†y"÷gLÜá,Ì’#¬Q{ÂÞÇ$â¬Ú߬¯R‘PníŽÜÚ±/`˶ïüiÒûs­ýåS炨±_u½ðó^˜¨!c -³kšù%©M«ÚÆvUƒ¥…^¹Û‰h(Üå„þ"ÞÖ wœHL&£À¿€>€ø( >üˆ-À6L ²Ó×íâkñä-q`ýá¹¶?T¹Í˲ƒ (ëj¯îõ²“m{1˜›?¢$áU|F÷0“^Øm9}‚¹¯3Söš©jÔnãÍv›V$ŒÒ›i‹øì~Âé=¹îKˆÈr"ËJr JüÝkßn,ô ‰‘…ˆ­¨Ç3uø´ÞŽŒ‹,ËñÍXsOëí²…ãqz¯=ß`8ETÁ‰,>l,n>XÓ1¢œà†ºm¾(XNd‘eÖ8 N­=Þcâ'™¢ûs°M…ƒ†À«Â!+~S;Ëà"fÑѪŒ!€¤ï ÄfŸ`€í@ù„­s6žjól¨±« hÄvlך.‚ç¡è¯»ü`¶¤‘Êí;K)9ŸåœÍ£'ÁÞšƒz‘‚¨\UuM6e< )\~"SN`Fãú>%ç±°¸öÜýöàpºhé·i%F5šaR8•ù^]_Ý“iä ( »ª›2#)Ÿ÷rnóþ%cÇ®-ã d”2BDð¦;û‹ºúÍ)¿+$Å3MIÊ>NIJR8NIJRöñ‚…®^ä’)üœ}8f‚¸lÖÃQŒÕBÎU’P{›{±á…µ89÷iÓIäýk‚øhnp¡6‹C¿ Vü¹¯NÌÕ›éBÐpìdÆþÖÌ}íiƒám3pÝmoÜž?7HÃÆ»K_m±tŽ(ÃDH³xj«ºn¨wäLÉÌÁ;ñ7Š"h7áßøy¶œ1›ðÄùðþ‘ÝxÕByÿú>Õ‰÷aYj½Z´âñ¼¢'Ÿ"»°¾KO€îj¸üèÐÙÌûWà׿·ìûݾ7ÞŠ~·ÿ4!–‹rÏ«øâðììl­dñþQ׉ÿmAYB~1' ÔƒRnéÄs¸µ£s(dõ+ÿºèwóê6ÞÿÐ_W¼=NÔdƒ¯ ÚÞ<Öõµ_coк“xú²Æ.DQãB ÎÖèL:ïU½xæ(ÊÇ€-¡Ì‹2/nÄÅ—bçi „ªXÞ­›ñgï_Â]ÇA €¢p/¾³ ?ôâ¿â  râ‡Oàà=è™y‡19¼Tuâ¥ãˆ/îµážJ¼ª‡Á;ZðßN($\ׄ§€«K0k²>Z_Í W]¹³&Zü•ç³g¤Ï æ>¹üíQ ¦²æo\×U$¦ÿßS«ŸêUDE?}Úÿ³vå0;ñ™½­·ÅßöãbKúð.,—³æÍûÇ‚xÿ6^8‚b J°½÷¢Q´jÜø°ÓðóæÍûo­8Z¨£3/ gïŸu`Kÿäðò×ðµ·0iãÝØŠ‹½³)¼dðþ™n‘A6áú:>º{N]+¬'–‚pP-ž¼ÁÔaUôâ*çT¤Âžy~&…÷U½¸0nNl-EãÞ?~Y*›DÄ]½‹â·*6YcÙ¸Dï®´Ê£Èq—ÇZDÕ{›eÞvWN£ôhëžzY2QÜÏuMï_?„cZ¿-B`ñÜ&ÅÐÒåÝ:4œÛÔf9”aÞ?@´¡S1 dÉÔi¨BçŒt—ɼÿAKŒšFÔö\ë ˆÂQ]ßdƒxZÞ?.Š£“Áké“™  öƵNÙ¬œNK$C›Cž+Œ!d¶éå–zMN 1ñK§‘ùãc¼ÿ7ä¶“XÆCÁçN‹÷Ú!ÄØíTŠNìØïV„¶¡y¾ÛÓôø2–íÚtÕÖk®yióÛׯn*´„§(mÞVq¤PG U:Z*í‘ùo¸°)§eQyÿ$ÎûQBæäýS-ž­Âç>Émh9vΤ6’ÅûÇ’8SAâÐ9åíTÎ8ïŸ ¢„¢í4©M¢z8; *A›ÀûשdÞ?õ«ÝÚµ€8?–P$°Ä?¾,dFä}xÿ( ÈÙäLŸçý£ÂûݸÞ+«1¸`Þ¿ÂÖ²¼ Èð®%ÇûÔ4cvüžE¼‚Þ‹s–»Uã7Wc¦I–4Þ?ôqGYLÇ)Fs< ;ý5Udù1熡 °¡ctm*°±ƒ,ŸÊ‘?‰óã{È=Œo÷“8i\;,2ï0$¬¢·_õ\U*‡ð–uã§öøÛçÍûW¸*–÷hP!íäñ‚SH|Gyÿ|î¹ Cd6gÿå›ðhÖŒ,i¼`:müZ›ôE`™±¢bÌ¢’HTˆ •[é[Šñ5›l _ÝÇ‹ØK¬=?ùœÂEçý ç `o1þdD„ör<_µ®í‡lΗ÷oYr´@K e¼Ë:|çïè^Ï^Š(™ÄÇ7á `ÆàHyÿ8/?É(œÂû'<ŠãEí8[á4p¶Äµ:(B ¼ÿ`üp¢Ë4e¯Á˰Մaƒ~~»tÐŽôƒ(‹Uád2yÿ¢ßÏÃs=`µ¸ÕŠ¿épi®Ê‘G e}åœÍ£'øK Vùñ9?2\øw.ªÆʪFó–MÇûOÁî<–s›gªöbÛ.\,ÀkËðÞŒÒÕÛ«ÒÆ/»ªöì/öŠ©qNéã³YÂF\²%aRâý§ôqJRr®JŠ/’ŽS’’³Ü>V ¨#صàðøYÍ—VFq‘×8pÍÊxy#ðgðå´é¦8uàv;j‚Ðv=^ÍÆÿ£íÔë¤+ŒƒEÅ}™é:Ê1D”!¿yh0¿³'3¿ù¬ª“~®ñ¥' Å·Gði¥ãÈYQ'}QøÒøäüzx^íPðç|04žISäÁÜÒÕã…ñÔ½ù×I×äZ¿²_;>j”Q† évCº=?¿xÿ®e®SJIbôs/=E®÷à+8àï>l4Î…Ít–ó¥#*¼–‹3ñº€†#ÐÌt§„ûÈ vÚp} ŽRüW#î·'bÍ:™u2ÿ:éÌpi• b){d_uP2ZSåRp†®Ê¢‚¡6={ꤟ{|éI²$€ß‡d€Wð›Ð¼è³/GWáÊ•x('fe§d às1)Á¯ª°K Ÿß®@7À4Œ¯ ÉZ{ÞuÒ‰ÊgTÅžÞ²>ŸBU#]¥ƒ±‰G¨Þ8sÖú;Q'ýäK'Š>Š¿ûdÐ ÀM|n~“å|áKcÓ b 6’ ;ã9t3öÆ_}í TXPt*(£Ò´kD\ûE•3éÈw Nú9Ç—ž0îDÂ/F±jR,Ń#ØoÅÎw¦Nú¼øÒ›% Η>]ž©4ÎæÕè癢G®“«E'R'ÏèîÓfB ù'síÕÉTÔž¥’Úҙ¯“žÀ—¶·TÚ£ÍËç£ÄΞ:éøÔ(n§aMküÕƒ ÌpÌ6Ͼ4EndüÞ{â½ÅDMqb!uÒ¡p_·/Ò\Ql7êúW^Ò¿2>Š!wn{se—çl©“~îò¥åAü$2£)\¯B³ pþð¥¥6+™P(|¬$‰Ý³°:é„‹è4a%;És’ªV™Áò:ãuÒÏm¾4€.Õl–ƒÀâŸJÌܪóˆ/Í$äãÓ †—b,I¾guÒOÙÚ†e#Âhñ¾76oݺéÍÆ|ŸN7T²r÷ÊüéRåÏxôsŸ/Ís¸Í,»äSVZ—NbD–8V$„H‚*èµvU>R6=K뤧øÒI•…ó¥Sr˹['©ÁÃzPÈ|ik<†œª“þ.”_:%烤øÒ)Ié㔤$e§$%)§$%)§ä]áç…€€fÌÌÆœ^nÞ¿— ·.ÄwŒn`}Ø·+) ¢hùxòF}¶žÃÛ>®¯Çë ›lКד—åJ7Ô PŽë¼#V{_a¯K;!&1Ò™ŽÌŒ¡4£`Ú7¼Ñ”67HxcNGiÝb *Y½Ç•ÝÕ^ìœ:ï>uÒ“ÄûÇßÄWgà/î­Àú2LÕY,Þ?*ܸƉMÃX„M€À¡[WrðPáì¥NÇn ò¾–(Ìóv#¸Ù•°aFqÓ~`Ä|~kNŽƒØoÄÖ&‚˜3wÖ®jÉÒ%’±•ÎcÓyl¹¥ŽŠ‡JFçH¢ê‚-žW·1üÚ†9!&þ>VëÉ(ôØrû»ë'¯æÏûORôs€÷Ÿ6€C‡¸a§äQ9‚ÊÜÚ‡÷OÔV‹„cèŠÇ£0Î×ɱãò‰ózé Ö,Áî¹~½®/¶È qc=^o7c謫?nS€²µ«ìvéÎo+h©^âÔ0’6«©¾»ö”ø¤Yc3’ÊçÊu93CBñÆ#Ù3æHæòËsB Øš÷ÕtùhzYãê²ç+ZyÐÿÖº®Àyÿó®“žlÞ?¾z ~2Ÿ„ªEæý£=?,ÁóiDqk~:%`òà±T¯€o‘íã&/0<0¿Ò¬ ¸¡_6Ch¼RÀÍ#süÞêv¼Ø,oÈ ¸©Û&/ VǶMmûêZíÆˆÈˆ£½­n_›)ÆJWZN,/ Ìž}îYµ£aesGΰ_1[XY5P^#BogULjZ4®ÖŠÞÅpYéPl ÌŸ÷Ÿ¤:éçïŸrøí*,_‹?Zá`á×àáü%žäžgÇÆEçýC1…üDæ»[ÂqóˆüÛG ±5žÜ:îi¡¿²/5#V„$¤Ç‡ê±uB.31õŽ-¥ž ¼Og©ƒ—µCZa¯éôÓè…mÐ*ok«ÜîøhHf÷ˆL7Tg¦3Xï?)uÒÏÞÿh¾˜3‘[É¡!^ÉŠ·(uÒ'ãx’5œ>=#jª,@œ+Žçòð”E°l;.ŸÁ@69°µiÄ·¬Ãó“¸(TkŠ›h̨+}² Ì[\ñ\rF7dÑ.FtÓ:$’¿(=&-æÉûáxñë¤Oáýo¿òª­×\½íÊKw­ZÚoàfP÷î‚+"/¡w;žlÂÅS³]ÏDtdħ5e0¼(uÒ'˜aÀ ø 3+”€ ðš¹´2ÅM2àž3¢+ ;ôÅÍ.¼=Í/i#ˆ0Öá#õxf ŸN?–)ȃS•–"ŒóþIP§¥œ.ï_­ŽŒ-ˆ‚P']àä:é$¢VQøÂûOBôSãýÑ¡î.°!lqš{.îG~þärǼ·UClÀ! ߎ—âÊ•89Îû [ƒÔ£'$“ÕÍõL<_Ká¶šå-)h ,FtQ¤!Ž$¬ÑŒÜ’F#/)4jòÆûOFôsŒ÷ÏDð?{ñE@üi%>•=×Ù‚yÿ–‰e1ñ"ÁLFî•ýȘ ª|`ºÓ~":|¬O«å âåÃ(ï~:šßx)²: 'œ>#‹Ú³âk´»À³ÙƼ+[fË’HZz<”ÏxÒͲ=vd»gÆÇ´¼ÿdÔI?MÞ?.pbìþ&##l7#à§{ÆAüè|@|*¼3 " òà€B ÈŒÓÍi·8å áÎAñª F ëÃþ¨¥ nÄ/ʦƒ²^‡4à½a ¤/\Q#ë-ªï:º$k}³EÂŽ,]ÓˆcK{‡u"°´T/i,~¤üh—nq’æ#9m]í¶2K¨±¨¹ÄUÛå“ÒËZò4@yK{»u¬NúoÞ?Š»ñ¨OgáM3Nª ¸´¿í–MA^G¬1C&)¼&‚ŸïÁg½ ±cFVâ¦Í©óþ3[¾±X´ÈÒ`g4*¬lŽ[¨ÿÉš¼Á(ê±U‡Z?ÔöcY)ŽO»Õ¦ÇÍõx²×D@€²>¼BpÅ ô’·tßÔ®:‘©•X½ªÞ^5Ѹ˔zç2è¦MÁÑ•î|O)Ð@ÉÎ7ªF(f´µî¨®aEvˆQ¹ª6¾:^']0t\ÙX0ï?IuÒçËûgDlèÇ¥ÓEœÂ|qv&‘÷œAÜ?Š—ˆ¸s?îœhÜ|çB|Ë81¨pZ¼74(Ððq{ƒÁ,GmÞÒŒå©ö£jžÌûG0ˆÛFÀ Ñ ¼ÁàS݈E“ýfüГ뱄ˆ,'²¬DJüÝkßn,ô sóþ‰a°,ÇÇÌÔ>­·Ë&›ùTéµç; §ˆ*8‘Ç ÃÅÍk:FN‘÷Ÿ¤:éóâýšð‚ ¥PKˆ(pÒ„'‹ñÉl›-¥ñôyÿ0ŽâóN°3éobû»•÷¯Í?°¡Æ®& Û±]kºü)Þÿ»XÎ]Þ°·æ`§^¤ *WU]“M¤xÿïB™þ<¡säÛƒÃ颥ߦ•Õh†IáTæoxu}uO¦‘'Dæý76e¦(Ó翜ۼÉØ±k˸ÇD)Þÿ»SR¼ÿ”œòÿSÛ¼ðàèT£IEND®B`‚tenace-0.18/screenshots/board_text.png000066400000000000000000001064441505733770300201250ustar00rootroot00000000000000‰PNG  IHDRî®ÐÉ pHYsˆˆÈ¥†tIMEâ  01ÐÒÓtEXtCommentCreated with GIMPW IDATxÚìw|EÇ¿»w—KOH¡…Iè5ôÞ«HPQAA¦ØÑ×öÚAì¨ `yE”&VšôÞ[è½—ôzu÷ýã²ñB.É]H‚À|?ïnvgfggç7Ï3³3’ªª@P’$é“lj²A>¬_» EAÀM„f@h†@ „f@h†@ îlÍP.ÌÚtä‚„Ûkº®ryÞ wM½#“»{¹=k£@p§k†x2E£&î‹@ 4Ã5jâ‚ÇÕˆª“ýW{ôöþ?î˜38D*ò¼8¥Y³Aƒ6ýGM]uÎú/.¼\…S£fû—7åc¹ÂÈùZÑÙÏÌÜtô’”BµSJâþ…o=1´có˜Zuš4ë6ü©OVœÌð<¦›ÊCÑF¥œøò¾šÑÍG/‰¿ ·ó}ù¢wë‘zäûUSëKæñu¤¥˜¯ïŸ÷ü˜_,[óûáþÅ£.%Y8YJ•°î­a“ÖFŒ|þÓÿ´Œ ÷ʸ|dóï?-ÞØòÙn·k5´î_øKr×þõv,üã½U£lÁíjgxbÈ«)±?þgD×MjÕoÓmÄ{œ1ßD¾Œá ô®¯œ9yÑîèÈ^ÝôéøA­5ªÝ¸sÿ'gm¹®ºdLãQu"£ë×kuï¨Ö]Î:úÔb|{Ö3÷umT·Éø?M¶‹¿óHÏ&õ7î8üåÅÇMY9NÚñõÓýÛ·¨Ó M—¡/ÌÞ™ Q±ºN³,fÐÔ}«ŸoU§ÖÐoÏ»Ÿ°uÿ¬·K÷ðùÄnuËxéÁôû¶C0\—’£4Þ™óÂЮê6jÔiÄÛ_µç΃õ†B»îºlAMÞÿÃË#»µlR·i÷a¯,9ša.üå±eñ²€Á“^~¬ûÕ¥‹jɸÎvÞ7Ý©Ž^™?ªq¿/þ‰é䬜sVq}Ç«t±U ànÕŒ<µäâ§Ç|ßñí%öo[ðJƒƒ¯ÿbŸ¥ÐisÜ¥ômSCØOÍ4y¿ü{ëîåÓú¤ý0îéùgí@@ÿ/wŸ8{üÈÎõß<¾úå—^Ñr뎱þ3ëþ]Ÿu¿8û©)+Ãÿaã–ÿ¾ñ¯6ûÑÞøâjÇé¿îÜñ×7Ï·¸²vk\‘xFì']&ç„W÷i ŸmàÛé½-ÇÅžÿ°û=kûéÍ/WêÖ»ž‹°¼J °î\}4敟¶î^óÝýºÅ¯ÎØdr™§Bëîºl• ?>5ö³‹Íþ3íÎÕsž®»|‡ZèËq¸øV-ØZëþÕý›=8Ððû¢ÝN}ÜÙÎÿ¦gÕê2=ïkm邬˜¬-=Ó¿O%¹À;^\UB ¸›4C¹ðÍðš}t³É[òhËþœ·=rô+6-çkð)×fìØnÉ+þŒµylÅ8ÒŠnÜbðÇ'›Nz²k¨öË–Žùâz!FïðF¼0¬Ò¾_—9÷f%¯RQ=&ݹwÝÎ4ÍíVïÁ§†Ö 5ÊØO,ûýXýÇŸ¿·fÑ7¢Õ¸É÷–w\·Áè¥óòöó1zThÔï¥gz•öØ¥íT8QujÔ}tÞ55ÏäŠÄ3•ŸH©pW¾÷|KÉÐø¡§Ô1z×س~Ú‰cW]v ÿ)´¼ÊÖ~ò÷ù»ª<öúè¶•¼"b†¼<±½÷Mu6.-[t¼Ýðî¡rAÃj¬_²!5;0ßl»¸éZHPÛ¡=Õ?lJ2¶üô[rûAÝÂ%7îxT àNÆóñ åœٮžü«—®š·½Ú®Þ«ÿ<¸þ÷zlÙki©öôË»¿}qò#S™Ö-(îz¼WD¥ð¬–LQ1‚„ëq U,Çùð¯Wî9—fµ«*†˜) rXéP#oqqñ~å#‚³ž~}¹ˆ²ò @WýÁioY¿xÌÀd9¤FÓ>ÃîW7H*\†½GÇ]'W$H¥BK±ãz‚J¹\· ¯RªHAŽIïeÀf³»¾œìB“˲õ¹~5ΫR•²E%ƒÊÉ¥‹·>´©ÁÙÕÆ¾2®ó€0‰¼²mÊû¦gãs_¿Ð.¿Þ¡ã–E+u]?n ¹qÇ‹¢JÂ7åNDaeÂ|Û½»õà‰c±YG·}ÐÙ«°M£Î¯|̰{ê$®]½ÏŠb¹t>k ûÅó ••ó?¿òúŽª“g¯Ú±ûèÑ^iªWœ×v—´¼……¦_º˜”b¿|IóexWí:öý9?,YðåË­.}üèë&«EQy%—ã %‰B,D¯«ÚªM¹s+ÿ:hr•®ËRʧ”]å!«Ðò*[9¼L¸åÜ™/©—ƒeß‚_Õ'~ÝŸ]mbçö:¶èÏ|FD ºéZAEöZ{ÏÏK·.ýysè=ý›û¸yÇ‹¥JB3r=¢5úÜßøàç¯ý°ýBªÕœ|áÀÊÏ'°2½ðÝÏÌ+{~þã TµFeºÝï‰><ç½…±‰sÜÞoÞûñlý>Ý+ɪÅdRôF___ƒ-þà’ißíµ¹Î[·Þ5öÏšúÛñdkæåm3>ZzI°nþìÉ~Ûu6ÉlWTYÂ’‘a-’¢p\΂,$?v"ÍSKÌPÔ”þÊOOølÕ¡«é6»%ùÂþ¿¾œ2uej^¥”÷ÍÏ/y•­®zïûŸþúՙϥšÓ.íúùÍO×› }9é›ý©´h[]—ý‹±a›&§–ü3îvÆr]]ÙÞCZžýÂûªõï_ÇaxÇ‹©JB3\8i†LÿrLèºW‡tjЬ÷Ãÿ]nï5¨ŸÇRሌnФ÷³ú ˜öÁC5t «ñèÇÓØæêдA—É¿ú ýtúýUtèªÝ÷â˜ðÕ“z6lØað›»#Û50¸nÅ#ýðÍŽWf iݬÕýŸ^iÙ£žÀ3pPЖi£ú4iØñþ/º¾õBß0©pÖ^Ñh4zIŠšGr9ûåÁ]^fÕøæµëz8ÑH éðòüoÆTŽùDŸvuëµì:òƒµúžCÚäUJyÇ”_ò,[¹âýÎ[nË«ƒ:4é8òƒØ:Ýš y9jª«Õ­k;—OL»F—Y°Ë”—$»yÓ‘‚;îiLÊl2àÞ*Yõ¼À;^UB ¸“‘TU{. îLÒ×½ÐýÅ´þü´O°hø‚›dýÚU#GO*` ¼FT~9q,¶˜2”;­H´82\¬¹½íJé–]ŽšyüçïV{ÞY†@Pd %Ù ÝvMÞ-Éðí( ·àr,kŸi5q™±î°·Ç4÷¹@PRš!Ü–xu˜¶sÿ4QAQ#VöÐ @ ÍÁ­B¬_»J„@ @ (2¤Â¬$‚»P0$Iˆ÷À@?ŽQ 1.wš!¡@ š!¡@ ø·së×(´ÙE)̉:¤“Å*ׂ»Å–yõÔ¼Ô¸ ¦´ó¦ô8I’}+–‹žÑUŽànÑŒÏüsËYdé?KžõèÄ7î}_UÕ~m«=~oí›Ïƹԃ•êë•I޹ní:t÷¶ã&ïÝõ3‹ÎœZ5ªN­|üÃÞaŠbII8¼gÓtKæå²5%,¸+4cÙŽsß×ÉËËÐûÈNŒ{¸gf¦yîÏ«o^3N&íšup»m6ë•~}`ÒÐè×j‡¶½ÉxFŒš(Þ§¹M)ô½‹;÷ëÅØ·»xÜ7¸¹ªÚ%I¶™Ø2Öûû–kÛëÉ Þ ‰èîåS¦1[mÖ“§NÇÇ'$$%!ÁÁ¡¡!Õ«U5è â~ <ÖŒËWίYÿ{zfºóþþZ÷*W¶b™Ûª^§Û}<¾Ãáøëx|ã¡v»r“8š°å»#ÏYl™Å]Ðf%ý»#ÏßõFýð•pùò•SgδnÙ¢¨"LLJŠ=|¸yLŒÁ`p?(¶lß^)¢BDDy‚ G‘GXh®Å§– õÔ®ÿÔoh;¶oejêʸ+§¼}JU¯Ó²FÝa™×^ô «Û¤å¹CWmò¶ÇñÇ]ßµgo¯½ý‚ü|}TUMOËHNMZ±rY“F K‡…‹öQà™flݹfà ûÃÃrô_®\½°rÅ_÷ö^$É«*ŠŠ,IM<\ÂDžºþæ=9·æ×3ÓÆö|gúÒ %PÖOôxwÞºiVÅܤLï’¹»’$-X²$ûëàþýs/sêÌ™CGŽ˜L¦¢JôÊÕk;vï²Ùl«õaÈ'¨U»r%..>Ó”Y£zu÷ƒ © yG(IÒ¢¥K³Çßôí+ËÅ5‹$5Ýôð ³'ïܳ]]½Á'ö€µ|­>a5Uji1ÅÝÿ†ÑgWùŠÃm[CË÷<»°‚qöüņ=|êô©Ùßüp1.ÅÛÛ§F¥r}{u2xØŠUË!mo>añ qa¡á—®¼pyŸãïÒÕØð°²×ã¯aTU•<É–¤›])kϵe¿ž™úT¯Ï*6(™²®XïÉžŸ­¸ôåÖ+KJL3€xpÐàAÙ_9täÐÙóçïésOQ¥xöܹýöêÕË×ÇWBr3ÈúôésñÊÕ±±޼"t`ÿýxàY–%©§`|½`Ã~f.ؼjóá2Õ©Ùîûr‘û‡Ô—õ>Þþ+Õ›r2v›ÎPE±žõö­`ɸæ©Kjמ½Ý»öœÿÓOo~8S ˆè~ïà‡Y¹vÌ÷¿mضsO×.ÝvíÙkµYE)ðÀÎPUE’dE±ÿãJRl:^¯×ÏúÖõ¾™:¾IƒV ê5óÀ=¥ªhÏÞÊÕx|×N=IB¹ ÉØ~å—•gNè9Ý`𲩦’)k›jÒéuºOÿdùÓV»©mİP GK'g•°ä,Õ»ö쵫j¿{û;ºü7)Ã’$:rôòÕ«ýûðñññ2Ü r_ùBCÃúöí»æïUÛvîjÚ¤±ãŠò º•Í;¬D%I¾¡<‹–3ã6í9óÅG÷Ÿ½®Ìøiã¤:¶¯  *Ƕ=pa`ô EBÉм͙É[ÖB*t‹jþRÖϱã'{÷èsþü¹Õ›÷ÜÛoàÐ{:*Šj¶Z«E„—)v0öPÍääN:5-)(°ÔÍ4»öîµZmýúõ7™2 6ƒ¢µ¨ùyj¦¦¥têÒmË–Í7oiÕ¢™^§/0¨Ð¶¯Ë%튤«X–…þèÛUþÏbSŸ‰¯Û¨Ù'?lÐëu­×@’k4{ï¨ùr¥ê•k6¾T›$ýáøÞN;]£é» ïëðŬ9Í[¶ìÓ¥UJz¦ÙbKJMOJËÌ0™«U­{üLÓµâãD)ðL3r·ËÉ©—“S/çu|DÙúvÅæQ¥m¿­P†Æê s·Ç/ÙõUEgN°]IEyû~Î"ûé”]ÿ[öQ›òCeÉ-·õ¯'§é2¦F©æ²«‚•$ÉlKÍT’|å_™ó÷ë[F*ãŠ[4²Û8Ç'“Ù¼qÓæ‘Q7NLN4™3‚oÆÎPeëŽíA]ºtOIKÎÌL÷ñöAEBÊ'ÈÓ¾¿Šš™™aW”V­ZØ¿ÍúíZµòññÎ+ÈÛÛXˆËÉ'-oo££W€ìši±Ç%¥+§Õ: ›|øÝ:ƒ^׬~UYöŠjõõáuC|üþ¨P5Z’|í–“WÎ=zpO‹dÑ$“’}}}’R{÷¯Ÿ‘iJË0]O²«v ÉKFÒ¡ 6½E)ðX3<š›Tˆ§Ô®¨hg¹ï›RUÏ5cÙ™Ï÷§¬x¸óó)%Ýïøñ¬i»#çŽ\¨ªŠŠªªÙ'Ü»Š]±ÚU«,¹õ(fZÒÂ}«^Ê8lQÒ%IBBëþÓ&%ÕWy¨ó‹óÖLµžÎ¼§ê3Åæ™r¤žåy—%9%=eæMM›5ŠŠNJJ°Z-’³ây k±ZÖoÞR½Zõ˜Æ1É©I‹)K£$Éf³mÙ¹½ZÕƒ çÑ‘$Y¶Y-‰I õë7ðX½n]û¶mó jÓºU ¿áT0¯C‚Kå°3Ô¢ ›]ùôx|ô•4‹#ï ɇO©ÑõO»fÊ(]£Ú•tÿè6ßí_;ÈÛ'¸t…®ìܵáÚê½Ý¿qªªúúxûx{'&%%§gêdÕ Jª„,Š_€¯ª‚$Ö‰x®f“vCa4î¨*©Ö_ƒ›¾©ÔL«ªªžjƯ§¦ÈØ<¬ã¤tõZš5!KTTÕ¡Yÿeý¬ªé¶„0cª§—s5ýd¼åŒŸ>DÒÚGÇ?ZKŠ$$e’â§¹¯Ã„…¾XxüÍ‘/IÅà—rÚ ë7oìÖµGÙ²åRR’Å.KÙc¹*‡$Ié™6mjÖ´yTTtrj¢Íf“$I–d$ UݾkwãFM¢¢¢n’=õMiW¡“u ªŠ’œ’XµZ5ÿ€€5k×ä´lù²–M›†……z¶Ì@Þi-[¾¬MË–8gHR‘Û?ÿµ£Mû¶i6]ºÉ”]L‰©™GÏ\®ÓðÙ«_y¼kݨƒwh­¶ßoû{h½¦öo_]³í·Fßrî§”‘žV1¢L\\\p©`/$©’ê¨1ª—N2›3J• M¤àä5Àb¶¹ÿW8;CUÕŸÖžJÉpk’Fj†õçu§UUµ¹m©¨?ÿïIÓÖÎÍûžNÛz>õ@ª)>53!%3!53>53.53>Å”š™šŸœqýJêÉc ›O&ì4›Íž¶¤V«íT®£ñ›.§žHθžšŸš™brJ(3!53!Õ!õà©ôÍ›õ¾d?0ÿØ+ªªýíýÇ#%ÛvîhÙ¢UÅ ÓÒSUU•dY–e¬ËOö´êÈòþØ‘5"kÕ®ž‘ª(Š,K²¤Óɲ,IŠ¢V®T©VíZ¹ƒv—‡$É:N'ëdYVURÓRÊ•+ߢEKUU]µnÝfûî]ÿøån:­Ö­ÛlݱÝÙn+r‘·Ù•ïÙR52RQTÉ…kŽŽznÚ´t`ô«ÝföÞm««7ûÈ7ȳ‘ê°ÐÔô´ݺ^8sÂKAƠà“ 2ƒ^ ðKJJ M¤À3;“Å£ñ >EQU]·ÿòÆØ«:Y–u’£e‘ä¬Ç]u8ŽUQU»¢(vÕ®(Š¢ÚÝî?Zíæ+éÇýƒƒ­6ÛÕô3éֽ䭓¼tªAFgWm6ÅfS,fk†Åž¡¨YX-VOÛ›Åf2YÌ’5-3E’$£ÎÇhðÓË^zY¯“ô v»dµ«f»jñÕûù—õ÷ ¾wÒª˜¼t¾Åá›Êö¿·hÖ|ýÆõAåÊ–KIKÁnSeIE-Ü, EQÔ­¿~ãÆÐ¨¨¨”´»Í†¬¨H’$˲|þÂ…£GŽDFFÞT8ésôýUT I–åÀ€à«W®ìرݡ ¹ƒ6mÚØ²Y35ÛçxÓimÚ´±m«V«Ö¬Î9^¤O£N~óÉ~o~1{ô˜º`Gô^]¥²Áá~Ï´ªæ/_îïçí8Þ7(ºQU:ƒ¿§ EV¯¾rå²A‡”/võÂ…Š+!©h–†—^ïåeX·~mçD)ðL3…„¸Ä‹—.€êÎrüØq_?Ÿ¥~_¦LÅæÛxŠŠjµÛEIMÏL¹v¦¬õ€jŠËë`ƒÙ‹ºÚª±th)o/›ÝÝÑs/÷Øú³æÄNܶouãZíϘw&›¯ªjšª þC–2ýóYU-V«G.]I’-«ÙdÕÜP’E²¦É©Ù_³‘$)Ыt%ߦÛ®W3õãÎö’}ŠÁÎÈá› íоê¿W´hÞ2*2:5-Ån·«Úõ´TUÅ×Ç»KÇë7mNMOmÒ8&--Õf·ªª*Ë’$IÍcšìص;%-冠lÛÇÍÖ<{ö—N§SUU'ë‚NŸ:µaã†N;üñן.ƒ:´màïïéú—ù¤Õ¡m›ÐPG¨œí›*jšÔ­2ýùAÏN{ÿƒ¼ÃʇF”4’±cˆ'îïØ£mÖ’eæ„„£~r}ó–ôK—ýÊ— oÕ2ú©‰Æw{½¾I£†kÖþݱCçëqq/^ )åï竨ª¿ŸŸÑèõ×òeþ6›]¯×‹VRàf¨ªzæì™vm:ׯßÔlNs¯:m6uöÜOÔiæã]pÇÙnWE½ž\Ùv G‡æuëÔ•eYUUI’|}}}||ÿz{{¯\µòû…¿_ö’áåeðhpÞ GÕñýáç7ï_ÝÁn>g:«*ÿȃªªÙâç0êüì»g.#UµX̲ÍÇdOÍ-Rö†,…úT¨`l´åથ܈zè¤bYÞ'[³½{ü}};wè´aㆌôô†š¤g¤ÛíV)×Ûn_®ª×ë;¶k·yû¶´Ô”ví:™LV›E’d$U§Ó·oÛvó¶­¹‚ ggÈ:Y'ëd?߀}ûöþÚØÕÝ{7ýôã°îNs iÑ’:tªS»–···ªªf³%%%éÏ¿ÖúøøFÖ¨9nòs""îxošâ- û¾)“©r¥ÈŒŒ¤ŒÌdwbôñ ´Ye‹%ÓÁ¬6Å®(v»Š)¾Aýf³ù›ï¿OII yþ™g|}}ýüü|}}kת­dÌÕÊ )vÅbó¬E%ÝCµ§þ|ô¿›üÕ4ª³j•/¥UUš–»dPU‡Ý¢ …+ŠrüÚ^I‘ÝoÐ:ßãWv× m¯ÓÉŽ¾´Ã=$É’£©Ù~i‰$Q6 F9¯Z›.¯è]ÿþÚoHÅ6;EÊ)(Šâe0têÐqÓ–Í)iéíÚ¶7›3ox{ÃSÙ$©m«V;wï^¶ì÷îÝ{étzY’%$TU—A’ç—!I’——ÑÛè³ióÆË—/véÐQ–d‡¢» *ä ûy§¥(ŠfÉ9¬’b $ÈoÆ«¾úéÒ W_׳^T…ì sBÂÎ “Ztì`9uÚç“™Y±téà:uwL˜Ôiùî[a¡¡Û·?yúD||Brr2Ò©}{«Õ6züäÑ£G}ðÉçO[§¶ š‘–žæï`02MqV›[ïKûJÁW¯^*äîè™Íž5J’$N$&\“kŒ?4' ÀÏ××_¯×ÇÅÅ%&&fff²,dW”B,P(! ‰~å÷So9üG£ªíUoÝ鼊MZqàûÜö„ª*z½wŸêe·Ûô{ª?õÛÉO^Žu)Ýê·˜¬•‚ë…é+n‰]^/´S¿ÏïíýÇÎøgf”ª*’$µkÓvÛÎË–ÿÙ£[O¹°vF¶l(v{Ó&MÆZ´daÿ{È:–\>AÜ5Ç%x}V¬\f±˜Û·m«*Šª*ú¼‚ «²R~æÆ(ƵCŒ^úw&TE§ËQ—Ž~øIåˆ Á¾>ö}û|23 ™æ´´ÔÓ§š7/Qá臟Ôÿïkî§¢Ó颪נº‹ß«U¯’˜X¹BÄ+/>÷Æ;ï?=~LZ5E‹)(@3¼¾Íšµ”ur¦9ÙÍŽ›,._9_*Ø}ͰÛ%Ë…#ËÞÞÞ€¤3Žà‚‘˜˜èèèI² ØÅj·îšûT›äkZsüÛz•ZW hb³ÙíŠuz‡=7_š-ËlY~ Ë g×·°Z,•ûé‚wÿ»Uù!Ý**ݨi3£¤ZyÅÞ²Y³ý,Z² WÞ7éjQUÕfµÖ­SÛ÷ôéŸæÿxÏ=}-kAõýSR’W®ZÓ¼…ÍfÍ É'è&L³¼"”rzü(æ¿$‰ˆÛ¼¥aµê¶}û}Ì&ïŒL{F†”žnÓñãaõêÙ¼¥¨R6¨ÿï|°uë–ž=º>7yÒ{|üìÄ'j׌¦Ð פ§§;:õ"*X,éK†;ÑôÞŠ]={öTDÙªnµ5`³ÙEuȃŸŸß |¶`$&&úùùeÏœ´Û«µð“S;U|ÄßôˉéÑeb¬–ZˆÍjµÉŠ×¾³k»WÛ¦ÂÐ’HR˜5{fî6NUU›ÍZ¿n½ã'OÎÿùÇ"é5Û¬ÖjU«úøø,X´Àn·9G˜O›Ê7Áü:5kFGFålÄó º•Í3BI¾ýîn$ýÒeŸú ¬;v IUåôtÉn—AIKóö÷O¿t¹Ð1+ÿ,É 5ªUò̤·§}¼lùªíÛ<1zÄÔOf<ÿäøšQ5D»)4ÃÉÉ):Yg³YŒFY6VvO3ü,VóÕk—«T¨åN ô¾péZ™2á É84C’¤  ä_øùׯ_w†Åb Êz®UÕnϲ3ìv%w_Ìš•íoÔÎ?ür¥z%SÖWRΜ?ÍžÓ IDAT88êåÆez–LŠ’$=ôÀƒùV«%²zuoï“§OIŠ6«µ\™²Ú¶Ýw`¿Ñhpnpó *°cQ¾l¹Ê•*UªXÑjµ¸THƒ)ß%¤‡åX|Ìb.é'Ö·|¹´´4oo;H`;Hþþ¦´4¿òå<»^UUUU%ëY3Û¡ÕªV~öÉqS?úœuÛµmÕ¿oÏ™s¿›þ΢ݚášÈjõæ|û¥·ÑèI#’\¹Bõ À‚âÌfó„Þeß]xÖn·¾ªª:æG}9㋌Œ Pív»,ËF£±L™2Žz¬ªj°Ÿz”™a–dÒÓÓ wñ Â:ûÔõŸûdÉ”õé¸}×V;¤M‰ÝÝŒô‚§ºY­–ˆòå+V¬`³ÙŠ$Q›ÍZ*8¨S‡Žv›Ín·¹”v›­]Û6Š¢änÄó *ùG˜‘‘vËŸØðV-¯ˆ­™¶m›$° ‘‘W¯_oÕÒCÃBUnDU»c°P’¤Šå'Ž}ìã3­¶õQ‘5ÒÒ2 ÝKÜášX½jªUj"RY’ƒ‚Ýh­l6sj¨Ô?Û-6)<Ð8zÌcùlb£(ŠM5ìÛµÏÑ!T e ƒÙl†€B_T©æãêÏüjÿ¸â.èCðƒµß©Ôè_X l6+¶¢ÐF ”OPÞ÷Ýn1Û= *¬¦ˆ#,r¢Ÿš¸º{ï :uý›7Ï8~\IK“üý ‘‘©:Ý¥‹:ÍùÊ#3ÔÙÚSÅf³Ym6›Õ¦(v«Í¦Ø»Ý^*(pÄð¡?/þ}ÝÆ­Ã‡Þg6›|||n‰_Nðo@RUõVí/m2™.\¸xþÂ…”´ ›ÍC7´$y{*V([­jÿ›ÌÉ•ô“eýªëÅ^M?UƯÚMFR=²6 ö¿)Â{·uûŽ “ÊGT ÷ö÷ÏLKK¼~ýÒÅ ½ŸáÒÚ°;PÅn·Ùív›]QÇûð/ƒÑËèãã­×ë‹owBÁ¿™õkW=éVj†¢(‹Åd6ÛmvO‡.%I’eÉh4ÞÂRÜmÜä{ày‘íÎ~ʸECý‚­fÜÊ…3k“kûCBh Šýêr솵Щ°1HP|! Žiu)–ÂH…h}Á€KðœPhëÏ:øªÂ³S@…· ¦Â)!~…ý ÁÐ z»V ¸;ã*$@Óœ?Ö/8¦}ÝCà#h³ T˜ ©ð|UáK°iÇï‡að1´‡y`Å~§Ð Œð˜o.ÇÜB/¬ð1l„vð!ÄÀ:˜v0à 8 =` \»CÈp25ŸªNA\¢Á ŸÀh Ó &ü ´ÔAa4#€€œ?êÀRµ¯í : „Á>¸Ça(”#ô‚ 8çÔ²T=´‚LHÅ~§P ÂXtjq2ÁO{ ä0\/M:NÁI8 q ‡Îà œ™¥!¬pŽƒ?øÃQ8(eà0œ/è¾Ð$جÕy@à¹Ìr_Í9PÊéG;¤ƒ¿ö5ÌIqJA2$^ÈésHͧC{¸ ÷· ¤p~{kî¬OF2)OÏÒÃð'|5=Of›67É@i@#´î‹ $ƒI rX$þ kÕIQp ŽÂqˆàx Q Ób6ÓNy°A"ø¸•ß9ÒÇ#FM¼KêÀÜYŸŒT'y~žryþ˜Á ëÏüi|m \ùiLÿÎöùä·—Zx¤­xþži~ÿýí•6Æâ©»I¿NêõÆÖ~Í©•¿(ç¾yÿÚ.ó¿~°BñÎu$½ÙâÔ'ðéïSšJòÆ™N-ûâ“ïVî9“$‡V©×vÀˆ÷6 /ÂäÒŒ²P v@%§‚¢µ¯qÙÕ!‚Àoæ2P„<ÜÎM†ãC G)x>„­ž§Ñ‚Õ°¾@ˆ„R ¬ ‡4PAÖê˜#È¢9W°Z° öA<´ ö$MÏB@_xWSç^‘ŒT'1뮸û7!ré&1•>ݲë’R»¢Œš¶wçéˆ*ûv··¨£KìÎýJý‰õ½Š3û’_`æŠÏç n::ÚPÂ%'—¿ÿëœ޲12Ëž“ßÜÒøÅuªî›vþÀ†Å?.ÜSwl³¢+½‹Álð‡6`€ƒ0º@ií]u "l„ëÐB :̃a<˜ëÉÜV¸ÛÍ‹áLa+`W8±0¦@mˆ€‹°ºÀj°CU¨6…xøºÂZPÜS5@WA†ê ƒ ×AQš¨T€ ð'ô„L8 ûáÑb(“Û]3(¼9¥«Ó8ä;ö$=X1D²Ü[­ß„ÈÅ v]TêT’í'vîNÜÈ¿X§HÊezŽh´qÎç¿÷ý¨Ù»ê4åÚ¡ƒ×+tÚ£V˜|ª7ðló¢.\¿5€ p¦Àdø À=NÄÀ|xÖÂc <ðL†Ÿ )x»‹Mð8|&ã I´Ø·F{¯‡J0 pÖ€&B+X“`;´…q ÓªËà¿PZóv:„ÍUÊB å!Hó€M‚ö°&ÃT8½Å‹­E¾VÓF^±;ög‚íØÎýÁ›µmV÷ÊÎÝI*ÊåÝ»®TjÚ¤tq—¹o“G92gÖ–Ô»k†ƒ\ºN½2–Ïýqý¡‹É–bñóäaBEB>Ý©*0$÷M‚a0,—$MqúêŸ¸Š°5´ÚmT1áûœ¿t†ížœ>%ç/à3§¯AðPçV€çœ¾vÏí‹9~/×é®j) ƒwœ¾¾#îñÍàÝ i=ëÌG¬íBwí67_Õ¯zLÔ;Ûöföm´{lj&ª¿LK¡]Ç>øóÈÏç n:Ê·$;ú—æ=ÖbžöًͫK?^‚ïy5÷ÙÔðoúúŹ'¯ÙJE6ïþÀ˜G»W+Â"SÓA·×MšF&þ¶ót\øîËuûÕ6HÞš”ûzGlšng¬±áÀš%Òìèªßç—g>ÿ½ÏÓ%ÙŸºÅãàU¾åƒ/¶|”ŒËûÿúü×Ç',|¹U‘©†0ËAQ7œešÄ”?¿sãÊíG£bø€\¾qCï½[~ߺÇR¯Y}ïʆO£7=6ç«)wå+8²o¹†ý†w«˜tðÀ{FëñáS ¹x(A>}üjMc‚bç¿«lãÆ¥$@S/ñïþŽŠiXb®)¤ëÃˬ›ûËù»e§ryéŸûä×íǯ¤Xl×bÿøaÅù€èZåuE—„ðM Ü@lš$ð C혆Æ+}{5Éz'ÂP7¦næ¯*ökR¦$råAãï]<æÇŒk´sŒgàÕöµeÓû”œJÊe»>Üwñ÷ßLùlÿùdÅ'´J½öÏ|8¶­&!4C =¾ÞZ½ã-§.`Ïië{–„mÜ÷“ }ÿùîÝhòâm“KƬ îûÉæ¾·¶Ü%ßJm|©Íƒ/Ÿ,‰Ê-‚âÑŒó°. ÂAØà´Fˆ@ îh\ù¦Ár8 Fhµe¨wÃl°ž„½°TXÏkïOe£ÂgpÆi{ò(ð>4®¢Øàΰ3l°zÀT˜ ç`¨ ÂßÚòæføÖh‹HÇÁÎ<¢÷…_œEÁ¥zxjD@;8íj©ÁÓ`q#úæ`†-¢œàN ßyS*ƒ ƒõफ jôÚöj¹1Â=ð 4ñdù)ÁíE| ‡ to ü%xS[G¶<àTÙ–ÁR­‚U†‰NËïñ°ÁU°€”†ZÐÎiqþlR!À!ÈÐzGÏ@uWYÊ€U°â@‚ÒÐ:åZaó"ì„#iàa Œ¨¡À:8 ÏhK‡v„p>ç1t„²yGkáoè-JûND-ϼð{‡« ¿» Ë£"Lp ÖÂ✦­ ÎÁ9X ý ³Ó·*|íöîâ×àc§åýÑ¢Ý Xû1ÞɹŤ .ÀØcóî6ÝYlذA¤{§{sš±þ‚ñN}(#Œ‚©9'JÕ†~ä×XÈо„–¢}½ûë^"¶Ò3ÔßOL\!cü¢ F˜˜s#–µð“¶ìyèeá üÁ A‚ÎN§øC ¨ &ø!ïÝ[­ð•&uàa°Ál8 `.LÒÜ·T–PB!þÖæ€˜áˆ¾ó'®K’$Ò½ƒÓu9ÏNßr˜•s•‘NBSuã½ÀHˆ†ßÄÆËwgG°¸*(¥™ÿ2× µBÁJX¢Õ˜”sÞu§ÐJ0*€*ÀãZýTa)\w²}GÁhªMùË‹]ÚÄq ‚ …þÚcqÌÉXñ†g 5”A?§îÔµ»b{1Uwã_Aš¡Â¯°ž‚ ®*NmÀ˜‚žÉìg¸ì…k¢•½ƒHmÍ×#1Kÿ|3­™ά‚Åš$”‡‰¹&mo³V‹ºj¾:0@WÍÆ5Ã&Ïí›ÝZÒNPIÉP`·{Q‰·cwoá2`Øà혖óÀŽp ä;ŒA.¥ ü- üNÁV‰o^ãš!G×àôcÌ;ÅÃnl쇭Õ.“œÆÐZíÃÚg¶Ýž3Ñ Ó&sÅ“¶[ Úç`'ÿªÁÀyWqª«áªÖïê!4Cp×j†|î†Ý0Ôc&äüe0 ~g8)X2•ØR¹~׳õe*ž¡ó)·âIrêRä G³ïÔwÉmÔ:~LÖ¼Xi†Rœ\O’SÕ͞㗜ӡê<éËAYxÀ•˜ w(¢w$ðœ£X]Íõè”ÈÒÿpÉÃðœÓj1k¼\Mµœ¼UžºÅlNz çñXØ „» ‹rN»„f9LÑu}Pòv?™ë°©®gQÆÂ¬œ3Yq’ŠlIÈÝ|«NgyyncKNÍ öMîc€ò0¾€·¡È Âø*§ñ!Í´ö´W| ¨T"Ýš#W[{O…ý0'×232„jŸ3µ·óœÉ„tís¨‡ÕYç4Þžé$Hª6˜¹2n¹ê Mµ_.ÀYQ3B3‚ÜHA2Qîå/;µ­*³[Q…Á$MTØssʆ ÑÚg;œÌÃ1§¾§oHÈN3“œl ›6@TÌ;NÉétÕihDð¯êáì!ã3L²n“í/Ògb½. Fh† ä4ã ­·h ¡1¾kð.aZc/ÅÓb³»S§JÃ$(¥µ¼»àÛœ~ž6šÓI…•9Ū½UxAO/kfDª6 8«ù»dh”o ¢ 5ã–±vz IB`‰Swžˆ¸$M ±%©[°¼@\o’'®¦«wÊeªÌé…¤gÔ_š©lçý´ú%™{}¤ÿ²OWN3à Ç‹Y3Txßó‰ó‚w×–¯1l‘û‰ùš'¾ÆT e'ã_¡Ñ¢Ö0b1ñÄçüG ì¿Ãv-´,Tã–ÑáSl*¦ß–rÔSÓGØ,j:éO‘òŠ  ž"ý§;å2,Åü—Ø{CóÄÒ̬÷ò~Døc˜UT%•¦óü*§M ;y|0MîfCìí*(„©‘Bû÷h¯U¡óµˆ Á Ƭ(d„Ž—3>†$PaÈ0\ëÒ86\ù¬°öäêöô„î9üvܨt¼¯}î0Àhøâ!žu:¾<ŒtêS¥ÁXë*ó¥r.Ž øwöt¶yÜ¡¾¨ðíþ`Ê·ü1Ê-; ÂC¼¹„—Dzí4£áùÏhíö²z–Ágp$ÐATƒNPíV—ŠØÄé߉µ>"ðoKS7eµ:^ÿH{Ëo èà~mMånÐ6Àa¸ fÍ%¥ƒ'´úP8ÊÀ˰ÒÕº¶F§Ã†A-Ø W ìàå¡´Qþ}È{#mr±ú…dÄØåÎêÅðÒëÄLaÙ`z¸sB–Ÿ*ë³'iåÑ;ê ÷ â`L‡‘Ðø_P6ŽMœjŠnÝ¿ÃnÞlæ™6ÌÈ#(¦æ}bô‡þZwa&ì;¬qUƒÇ<©T÷½ùã­¡µ¸ß·úñøÿDÚÞœ“ø$ôãñ»ãÖ!.{OÎKÒù•‚¾ð-SNòî žû”ÏáÕq(ÿ£{¦†¾€À²0XõA°ö‚ jÀ0m¡žÏa¿¶Ukèëj¬Äå¹ ¼ 5à4œƒ[àW14‡°ÚŠ'â®îBò\Ë `(H¢\9ñÇÿ'¬m19­t§ëN©·)Ž¥cS ôƒÜ0.ø ×¾Ïa²›BòÄÛ|=€o.øØ ³”Ó¡M™¹Ð³‡Ï š@\fC*¼@UøR›Ê2¾‚/àIØçjÜ;Ÿs=0>ƒ˜|sâØÄé/WSõw¾0 |A…u°Z”ˆÀ•&Šàï1hm¶T›àÿ¡÷*–´ 3×¢°É%#c¸¯uâí×Htoq¹*‹gxü.¬{šá¤Ã8C¡¡dÀ¹vÐäŠ$ÿs;B­«Ø^Ë;k1,–;@|_Á—97Ϝ۸n”zYF 'pÆÐ;X!¹ïM*.åëãÅjϸCšCÅ ,ðBN‘plÁ´VÀU°ƒ ‘¹VzÈç\ È™›8 볩øXÖÊd¼ÁȧSÞ©™›@ðq,}ñ«yÇ]f¹Çè¢yçQ:}tË5cióßðfÎmÔ€8ø…h0š\3ªàòÜBlV#6qábz´€¸÷§xß¡—9òOF:}m;ëô¹o÷•Ý–_ ®ÂbXAå :̃8°ÂøL`Œ ‡³y8—ó:77Ëáµ|µDlâ$·‚<쌿áoíýŒê0Y{?C‚Ç`)¼&¨=ÀÊB˜ &¨ u]-Ù–×¹…ÛSlâ$·^3rï•t¾0 †å:«ôruüs+Ôœ¿tÏõZ/b'@ ¸õˆ5 @ 4C B3@ 4C ÿvÄRÏ;tÚA³x®VeaC’oï+4ÜE÷s˜Ãù½' œ ¯ÂLØ­}ÕÁKÚnÙ\‚7µ-˜ÚÁNç.ƒ¥Ú :•a"øçq¼^Ë{ZöW.İuZÁð–x\‚›T˜ZÌK~:1ì ÍKI䳃Sî¬^‚ó0 Ái¸^ØK»SüÞ—]n<æÍŒ^¤äÕÏ8—µÏõA†Ú`ÐZííÍV ÷p–”åa0¼ ŸÃ4è:Òa®ÓâÊÙ^©ªbóà;«¯“Áo˜¹—ø»s^CbQvd]5¥!P 6 › ‰ænv_íƒNëTfï¶ô8<ã!9Ý–¶Â0ÆÀáÔ|„9e¹$çê„æ“„ûYM½S–BH)ì¥Ý‰XË3qqR~môò!Ì.›÷Û5‹AÖü{P] =¤íñ•±0 ¬žÔñ±Ðʃ ´×B4ËÆ¬y¥ô0T»Å‚Û3+Õ…p_|ÃéðÛr›yq÷þÇ¿¤ÓÒbÛ:“ךÒà…*ï¡ ‹bYÂ-½v´I€«Šlâ¸ìº_ÖöÂ)8¡~K k>hG>ÜDZÛÒ4øJûûRk,r¸3àGèÓáKšs²cœ“g#1×¾~n&Q `s$Ç ¼éK»³8ÛŠñ±H®#¶O¶Ì»[cuz¯TÑjWÍÖ4Ã^W'ÖÖú *ì‡97×uª£%§Â2 $è•E;|û`aÖ,Z¾ÀžËœ[MÝô}‚8§öÑz‘E—Q•Øì¶O6|xq6þ3yi5*dìä‘7yt=Bnåµ£ÀoÛá`ñiPü`T† ÚS]¶‚ ’àW'ý(7w[Êã¦õp ¬°®çj—óI¢Àœœ)`!¤A ,„*~Ó—vÇy¨6 äÍš.:.×ë3ª_Þ^)à($iŸãaœf¢Í×úA*ìpÕ' ƒIª³æÃБ «´,=Ûœ Ùq0þN¬º]ñâ­ŒìB… ÂêñÒhR·qÄé6é鯭JPžêŶ^’±>³_á‡ÑüyŠ—A7™×ÛÜâkg³6G…?‹f“º<ÊÏ1ï4ú-Á@ˆƒÉðTóÄxwì¶ïÁdø šâb£Åì›&ÂOP7gh ̇'a-<¦µž&áNyŒ¦ÀËàå»(WQ¥{Û¡gΣü˜óý¸ÌŠŒ}„³ù?“Ûݰ‘O:™•Δ†IÚд »à[Oú.ÎÔ²!¹÷ò¹à¶@eóz¼ë©M5'ñûšÔÆ[BÒÓ£kpÉZ\é×Ï[‘ oÊwåøæ¹’m r];§`­Ó&XT=Z‰¯DEäª~£Õ¹³>©NÊÿ0ïóÌ›Nó 5gžc~x¾'dÀKdy”›Âc9C³W‹’à^è™ÇúQ—á#ÍX‘ 9<¬éºËã×à hU 2a,Õ+ /A^S¼æh¦Æ]¶Þ”Ë  Žþ·g;ösºü—WÖ16À|žNÓÙœk#$šõ“¨SRο á7.STìÿŒo1ùwÆhfìn¶»òN8ÎÂËÅ’Û F¿Lû‡‰}…ïΖ\Qç¾v€.¹üê­< ·}S{\mÌã}øeïDäsržGk„š®*c='›ã|ÞQ9¿®ÂmÊ“ÝÉñ•]µ;À8h!tàÕa üG8¦Š‘€ÈTQsþ%±ÈSRÙö=Þç…e<óϼýŠå Ò\ë­êеZVìCtp1\°™é#85ˆog1£'ÏæD Œ~åqíÞ0Ðé ÙjСk n–=½ç–‰  :f ÌùËŒ<ŽŒ€©¹~¼ì¤Ù#^¨õ um#a¤¸ÃÿnTÖý‡û~äÝ•ŒˆÎÃÏñ¼˜r5ãÇ᪴[Åš4z÷à>ÿ¢ÏÈÖÿòn*¿½OˆŽ>0¨9}ŠÉÅiÇæ}íY”^ð B¿¢™A.ì ÁÒpp~Õ4ÃPX‘Üvw>‘÷§qí#kf¹¿ä`~3guS:õ`ÙSÌíÁùãlLâåü=É‘Eßð%­bÄ žý†ÖþR)ÞÅõ7™º÷]{6õ %ôw{ùgagî|®ÁkN¨deE¹ÜH!üQà\ ‰A2¨8³Ü…Ã9ß§ lOl¿âÚéZ”‰ ÍÜ)è!Š IDATj@û"èB3w(¥óöEŠÏÐ @ ÍÐ @ ÍÐ @ Í@h†@ „f@h†àöÀËF+»(@h†@P *¯'ògõUQÐ _ú'óŒ óR Å!Íò"*™™Yë\ÖNgF¦¨O‚Ê2>Ãt Ë&¶ýEúL¬×EÁÍ”8þ楦}•`H2l¢`dòZS¼@šöá ‹bY1l)qf£ºî‹o8c›–„}q-Hš@bKR·`y¸Þ$?N\ LWÅš!(A$…“hœs CVy'‘Öb`CøðâlügòÒjTÈØÉ#oòèz„uBfÍ¢å ì¹Ì¹ÕÔÙMß'ˆSAÁô6 €šNúS¤|†¢¨§HÿIÜ¡B"öÏxŽÊè$±çܰÞÑPØø>™–ÁˆnœÀXŸÙ¯Ðf4ÝVð÷#è&óz›bHÆ‹·hŸëñÒhæ¾Çmrî}­lÃ"n‰°3·„È ¦™ó¬:U3ù4Ó…œîBjŽç­H†7å»r|óÞÅߛټïúDêAÆØÉUE”Œ»ˆ›#4CPRœ1²)oM°éøÉ á èéÕ[1÷i(öÔbg0a5o½O @?ÿ¹º/úñøÕ÷Fh† ¤°êÌY×ý<> f±N’Àv‚Ñ/Óþab_ỳśÖþÏèñ“gL´ö“?þ?a,ã0]wJ½íÚþ¸IRÀGBÊù4s x äAh† 0\öf¸¦\¿¯ äead˜™>‚Sƒøv3zòÜhNÓ´:•mïÑã}^XƳ19 )Šàï1µ¯µ þz¯bÉEÀdª¨9ÿ’¿ÇX‚E^yš!($˜â…âôËoò#‚,¶þ—wS™ó>!:ú|À Ó<öI1T•uÿ¡ïLÞZɸú®Ú¸n”zYF 'pÆPqg„fn ³@β*Ìz â‚(I«1ƒg¿¡µ?€TŠwgqýM¦î-jÉHäýi\;ÅÈšY®9˜ßrúbô~¿ð«)îÌÍ"æÚ ¢cL0u¨%ñŸ`Öˆˆ@#¸ ‡s¾¾ØžØbx¡O áSÁýïO‹Ö–°3‚‚»“F†2'ˆéQ°3‚‚8èÇ(Q °3@ š!¡@ š!¡@ š!¡@ š!Ð @ ÍÐ @ ÍÁíX£PpsdB"H >n Þ;íàí÷Tˆ…p2´þÌ3PÝU$° öÂÿÙ»ï8»ªêÿÿÏ;%3™té^B/PB/""é@ ˆüüTô#"* ‚€¢4ƒ¢€Räk¡„f ` ô„ôÞfîïÉ™œ›;5e2IÖë1œ9wŸsî={ŸõÞkí}öšE†À1¬•m #øY,¢íÙ…£è5¡A#3‡Ï¬ÎÕ7íi»NçÉò Ö¯ðLîbVjÏD&2œkS_`)?ceªØ2&3™Á\ÅîQAš4åL²&¹k“h½®ñΖž,ãÏjL)¾’ûÁèÍ…¬â!Æ3™\—| ½èËŽlË^æ²,çvÐl„fÆò$Ä”6èËë¡Z‹Œ5)8Þ©µäÛL…œEp:wPÁX>dPÊ ©Ûpï1=qV*B3‚ ÁÄC¬+ÅdòLÿFí„dy'qAZ§Æ$z$#uINZB¢íAhFШš±ÖèÅ6lÔ ¯LN¶Û¦«ˆÖÉv:\–›¹<ÍŒ¤ÕŸm?Ö…ˆMëÄJ–Ñ–…É8s3Ú°æ­Y•³ Ù.MiF†Òd{~îXHzšV%8]¢ 7: ÿ¬Ã×-ËÝÙúëf>¢$îNhF°µe³ò†©W0>±àéº.½*uÑ‚æU5ŸW2ƒ§¸œöQ——VçYz^܆Ќ`+g&Ÿ×%*ÓiÎ6¡µVùk *ª+ƒ.ÜKsùÿ¢‚O¹ïPÕ #bºAYP¿bó7Â¥ SãKSþDÖšH›¼‘ùÊf¾-§rP²g2ŸE]AhFÐøM¦¸:5³q.Ý-Ùž—ò-V¥$ª{Í:“:<[oñ ‚ 4#Xw¶ÍÕƒ¶£CîÎÌFLUžvÿäB “IPø,‡/`¿ZÏ0%uªÖQ—AšllÚÒ- hÆö4£Œž‰·QDf‘HF×ËyŠÌáéÄçØ9µ"Èã<Ƈ̡œy<ϰäÓNôˆº ‚càAÃéÀv”'Íg2ÍèÀ6”S¸N©ž»§‚_$Û'p&(¦?w1›Q|;U¾ —¤zA‹ΫÕ]«—DÛ‚ÐŒ Ñ¨zå;Ë|Š“ðT ª¼æù²õ¤#ßçÅêÖµMOûÿ*»3’éÌ¥œ–ta/[§N‚ Í6€xônHùi)ÍØ6µÿ2.«÷IÊø2_®µL ã°¨¡ Í6G²|Ês‰f³wÜ” Í‚|frSj ΠSÜ— Í‚ZšÛ6ìÄ‘ôŠÛ±™‘¹?îAš4¸7îBlöÄûAAøÁúqñå.6 îC¡A |àî¸ Aä“q_­Ÿ°~§;îpl)4ÐdÿÛ„ ßò¨Îu$Æ3‚ ‚­Y3æ2€yú´ü”¡Ñf‚ QȺã'¾ðzy«ÏŸÞä´·â®…fl„†è nÂ' ‚`}ôcƒÔ@CÆÀçIþ’¬ƒý~ÉÝñ%~Ìá5>†»òr5pc*N#á›ö ƒ`³è{]Ç›¹Ïò=\cùßßéÒ÷!“Ѳ~‡ºë ;Õ÷)ûÖ¾µNç:lÍ8€{˜Jw²Œ ÃÍEE­+íÎïRÿ.ãNÚÑ%j!6O¾¦Aö¸× Æ~MqÖôO\ü+—mãåãbLu ÖŒíÙ†wéÎ Fq-OPA#Ø•–õ;UQ@·²Ÿ0‰| ¼Äbä<Š(燜—äÕ™ÅÍü„VÌæÆÑ:µ”é(îIy6®c7nKV<­¼îÎLà3ÚrûåE±˜îœÎιß9)çRJR' ‚ }ÿN;8wߟjÍøã¯\8R&£y+G÷óÛÓu/\ÛM¹ã§^<Â?úÉ]ì·u÷»&–;¨_Ÿk¯f©²Ëüö¿,÷×+Pšs`иšQÄ~ çTÆÒ–#¸‡y´åmúÖo|$ËÓ|Æ ”¦öÀtà îæP~È"îäíš}ÞJzíø9Ëø}²^ï”góÞ¯a£÷éOgñ({0ƒp ½˜ÈHvJ•ŸÏïèιŠ@i4Œ¬<1Aß¾ŠÁßt²fMñÝßêßÞÿ;ªf[’ußoý8ëáõkíí¡þ6Ö^{®þpÕ<ß½ÇK= :OÏx<7±fà îg%o³/-Ø…‘ìÇ8®­ßIþø./eô1ÉÀÆA ãTšÓœ™\«fLe WÑ‚œÆ]¹Þdߢyum躃Cyž¹R@)EìÀ‰ÔU^ëyçÑo ¶våÑd»ϲ]mÅ?}A³V»;èïä>Cí»¹é{¾oÁQÚÖp’ò©îë†[œØ?ÊáV'÷]<Ùמ1¿ŸA'kgãhF¶ÿ›:ð»/q]ÎÇ0— ¼Ãid8€áRÂnõ¸àžàâêºüeÉF!ÅV÷@$Q©ZXHiêðv¹îÎ(žã:5¶Áôu+_gÎç)–Й£é™’ŸÖY·`ü>s×Å—o–ko |àîK²×ųÔa ¬ûxÆÂ9î~ȉq…Ž£ÞtÃ?¼5Ý‚rÙ¬f»˜—­Y3æ™^lçmªùhä,ií…cêŒÍ÷ñÜäÖ ¨ÚB•ÕŽŽtá?|Ä>`þöÊ 4Õä<Ä)ì·N_?CAJ?–&­XÆZƒ¹«;ðp)x­ýØ,ø››“l §ñws5-j;Á%Ùë<°ù5‘x‚úZƒu&£Õ¶®èë–G -wÊ\WýÑ~WúÃîÚ—˜ò’݇®y‚ó)l«óJÏ¡ÃÚv–³F;ë¹N¿–[àãÙ¬AQ7´úêâ@§3íÀÎÌåe.ª«ë½€ß±/ǯ{SÓ‰!ìÄ2žKô£ yŠsYγIi÷svÞv}œ¡8”mȰ*%TE\Ä£ÜÅ5‰JÕÒ.7»Vë¿/žã¡!2íT »ÒÒ¬Ò-‹Ìœà{/ZYëcUØÅe;»ùöºP¿VÞæåvþoÏÕç×/ÓâçÜîáëÔfK{<›‚5hø…ò''ñŸböäz¬Eó3˜Á¹2П}ë­g2o±-‡ò(àráÛ´áP&‚÷Ù¨:üºúÐvf÷PÙ—9ŸÖ)ߥ€óxŠ;¹6ÑÎ Ø Igà&N©­xåxF&£Y©Þ»{ä{ÐÙí§øÆ½îXª[/Wì­Ù§uØ+¯²ê/®¾Ù”¬>}ÜspN¿öô µø‹ ~áÞo9c›¨¤ ÌÚkfûgsX±FáVÆÚ ˆÆ°®Ö Ö(Ü"­A¼OAÔ—ÐŒ ‚ 4#‚ ØÐÔ5A¬“5ˆ—êÂÏ‚ B3‚ ‚ 4#‚ Í‚ B3‚ ‚ÐŒ ‚`  h½ŽžÝ[ñ­+ê[>ËÛ a‹@+zq({Õ05/Ëã¼–,;Ø–Ÿ¬ï·‚`ÃÓ k0•[’¥?ûq^ê£ñ b‹(¥‡³®}xá5Ÿ¼r»ýswÎdc˜MíÙ•#è”(ç&fÖpÎ381êx=5#ÛÅ£¿Òâg.T¯™ØY2,7ëÑ\æ2’c9«:Ùø×#ÙV4mj j2/ðLj=ÐEŒf sA’áfÌc¬Lþ]É$&1’›×ã´¡ ;ðµj'sƒ½ßw଺Ëp²d8ˆ¯PÎÃŒ"Ë+F—ÜC–ò(QMAдÍHC­AµŒN#ÃÍ~ˆґ““’—qYî±ü˜©‰ŸÑ>õÑ{ü‰ 8Ž#iËlÆóAu_£›ªIÎT²®ãŸ]ìo}d©èàñïû¼J=%±þ|´æøÄ·¨Hê;Ýéx†Ï)ˆõƃ  ³Ö Z'cPb":sÅìÂ!ɧ/³¤æÃ?bz²½K’­¹Ò¥x"Ñ¡8“öÑ‘C¹"œŒÆñ3æÁK,Ϭù÷÷»þAÍj=ª%™Z£LkåÕªŠJ†Eeu±Š×Ê46íb×%t¡ý¶ôá·u³ù”39Ùî˜êÍVÅóQ )>³¼‘èM†cRQîÑÌJLÝÑñ„lÍXÕÃÃ7™YœÚ•1á2~âÂZC™{Ҟϩà_IlêÅDEz°Sªð’$*Õ’3x:j*¨‹yÜ“²;›–åL`orM͹è7{‘^WkP-+ërD&Õ sRQ¦Nì™ëTZ˜2^æ}fQDwŽäÀêÆP+¸Å²-½96Bë¬ÙVž¾Í¨¼û—-2äûºêØOj<¶Œëy’÷ÊÐd1}8=õ]²<ËçdøRÔVP?ãn¦hYæÞï8µŸ6-7©~-ôÌ«®¿Ã¼Ê„ßݽõ±ù°-‹ÁŒdøÓReæ×pì[‰Þd8*7ÜôyêØR­åcÆ1–¯åÉF6¹Ð*¦2•7¹ªá)¢·P8ž1îrƒv¨>¾”míÙ˜ZXGOp^Þ˜v9sX˜ÚS•Úž#¢Ž‚zðS´kmü3Î?y Ú¶rÑ—ŒyRó&çæ3ÞbXOkoŠJÌ÷4±’’Û3¨Ö;y3q&Zqp®õ_–úw[~ÀÝœÄÉßàÝ5’.œÍù ·sz"?‹˜{ªÐŒúÑÂk§¨¨Ùá\ÞÛà=küt"wQÙó8Ž;ù%‡‘e w0;qê+£RE|%F¨‚ú1 îü–M)ÿs§mýî{k¾Þ–ÅúYƒj9šÞ‰5‚k’QÍ«;êæ$Û‡å•)Ì=7J8…‰¨TÍþ/à*Ž£ E´â$ŽLŽÃèx̪M/«ãl“w®q”û•dX² §QFK΢,d0XœÄÇìÔiðå#>šãî¾óŽgçÖ={ÑDwüÂagi{¨Ò£ìü5çÜ韟®~)­N퇼9[ëi ª¥˜op.=hFÝø2UÃ%ùó_³©÷·JòÂZ§¶;¥.T5wV­sz'®O65/kë¦!AÖÌ%©»›Y¦Ód™¦uNnzVq ³U²Éì´K‰ -§ofnù—x)ÿAçjŠùU¼ ¤{µ«#BõdÂ8Ç¿f|9dÞuɱîïUcjôsNû¹«šö ãÆ7Öß^ñÚßVTGŠ-1¬±>Ö  9:w‚Ó§ü=éßî\]_al²½ù^fÔÐéZ©J?‚ågd¦;ì­d¼(«ë£N}Õ·jŸD3³òf“%JSv¿<õ¨/J¶Ë¢:‚Æ »Âo® dË=ü¦k˜´óùëNù‰—Ë:úƒŸ³ôMSÿæŸÿç«»oÅý–õ´õ­*^NF@w¤k^ÿ$Ƥ wŠm{'Ë´£°2‰„£[­V𿉺dª»zøuº£úÞdåU†ïªÍPg ôÑM ºæÿöP>Hdã…Ô¼·JÁ¨\¦06>…eºÄÈèQ›»h¨?O…L±«ÎY-Á°51–Qy;˸´ºÑÍ·“(E¦'£ò£³™Í‡ÌæÇ©ŠùZêñå¹ï¤iO ~K14cmVî탮Zá¤Oêâ*â*†1,w]Ûžôe¿H94–­+Ó¿——Æ­ú3«›“3r„¹iíÃÇõ{ÝÈ)V6Ókg冴‰F»nÖ <5¢P2ßæ Æ1‡ :°GW÷Rdo$'éDUʵ fSYIvåXº¥ŠEGÞã3泘R:±/ýR¡õÐŒu?´ø·ôiØ!’, Ó .á’¨¬`°x±‘óµí帩^\"KI+×ö4bª®íì–«ŸLZ-¯˜å®?VÙG¾ë–‘ž~Ç‹ÿŸÎ‘ƒf¬Á´”f¤C‚=ë=[²€ïÕßµ¤_* UýO`oöŽºÜxš›žxË7Ƙ•;µvùBßþ7d ±·¿öÑ1)¿0µ(^a÷ÿÒy]½ò ³±(kÔÓþ§?rCÈò)Ï%šQfz3#úHÁÖÂÇ£\4jmÁȱf^Ï5ã“pFqªOÕçí¬¤ÌI—9½ÍjQùû¿Ì‹ä.õg&Wsk²¤Gg¤^›ÂÏ‚¦Ãk“j[K»ªüâD+vT‚ŒNÛ&k1gìZõG©=º0–O1%«]8 µ:Û°GÒ+nGhF4IÊŠÖ^Œ¿usm²&/ËÙY”ò½÷ÚMñ?¬¨FYJV¯cÔ‹Üwaó&bSÁÖ »èšr2E®ííœ=í˜z2ÎÙq ô8ÜÍV«ÄGŸ&ó¬–“¬Òa=â B3‚`Ë£}/O÷µG3š·ô?Ǻº…Eí=ÛÏ¥2•¸ð·¥æ_vwãÉ 30ì¯þØò¥þõ §çC¦™+Î ?#غˆØT°qàžFõ6g¹¥J<ć+ì¶—á;›»\I‰²µF&2¾ð-·Nóaʧºô«.­ú¤™s¾ãw‰›„Ÿ[0Û”*A¹§?3üSŸfÉhWš'•ÅËÜp—×¾ë¬}tj©¸Ø¶ð%ýÁ£§†“„Ÿ[ …n?×íõ{J;ÃagÄ- ‚ð3‚ ‚ÐŒ ‚`ƒ±©`£±Š×Ê´dÅû­™+6òùKèBúÅc„f›ó¸‡ÉzÍ‹µnbë•ÏžßXWZÎ&ð&×T·l4¾f,qÌp}f›±½'÷5¿ržI…}ßvâDË·ó|ãê\4x6o0𬠨~©$½iÆ3ˆq,¢”Îþyk§gy›!¹ ­÷J2säO‰™É Æ0›"Ú³+GÄê7Èø›)Z–¹÷;Ní§MË{Á¾òg^uÁ›Öxþ 8d/o ÜȽÐ3¯ºþó&qßÝèÂõµSÁ‡ÌbÍhÏ.ÉšäUTØmŽ/ÎtÂl½—Øn•UE>ké….îìé³®7eÍ(ê7÷8iȸ´³/2¥Ü¥¿uÓhYð¢ë¿éÙmk8E–Wù›œÕ–1‘‰ â4ŽMÙ÷ÊìLÏX“è`£ÃÁ\Ê+že Ãr—†˜Ë\Fr,gåÊÆ`£*çJ&1‰‘Üœ:m°n¼ÆíZûðI¶iŒ ~õDC>pÕÏœØWÇmšÊm˜1Ç€Ûàë_Øè×jÛÊE_rÒ¡v8ÕÒɼ‘›U{C³¾Ö`)?K=€•v`2“ÌUk’âµ›jäÈœ9ÍÍVÚ}®Ýçºh²3ör¤Bj\ê-Ó®˜4dõææáv~Õw“&‚’™ný“5­ôù*aE’Éõü†$~ÀJždPªüèD02œÉ¯ùÊÈ2”§JŽe8Y2ôánKÒ°Tætœ–*üb%œÀOø 7sa é!ƒ†2 îüV# ®8Ã>»X²Ì®gxøïæ,ØÄ7`îüCÏS,XlÿÝ\~z#]·Ó¶~÷½5U°±Xk¡ð#~Í/81éÕ-Ïí&VÆ:¸ü¾ Õ±®í¼ºÏÙf¾ß¨UÇó Y–3˜Ó(O vLyD]’Å|Ä~ ¥µ×,]‹–)ßeVòÓŽ°qX¾:ZRO&ŒsükÆ—Cæ]—ëþ^ žÞ¬¥Wÿà§<öo£Æç¤Kj|Z–Ùk'_;IÿÓ5+®Ÿ"V…m¦zäibäD³—*j®kw‡ôqᙎïZ¯ ÕêPÏFcXƒÚi³æyŸ×ÉõyFkH«ÕšQ°J·•âuü¦¨åÛ™Pl§åk7ˆjV[(1¡Úä½cªz)ä¯Ò³+…¬%NÃÊZ¿S–I‰fìI{>§‚ñÊy1åÖì”õQ²³Œ—yŸYÑ#90Ò’76Ùn|sµ` [îá7ÝՉŵ5ÛÛžpC÷j>ð¾R«½;Ü·þá0ÈŽØ Š˜5⯾zq)‹¿j±ñÿ¡Gwê5þª¶›º‰®¯5Èç1ˆI¨à¤Z£æY’ÑlÙ1÷³q©og.[æÙ=Ô'#Ù¬½ nVfÌN¶›'±£4éŸ'žiÕèÙŒT|3=2Q5‘±ŒëÙŸ†r=70ŠbãÚ”8~ž:ö¦³Še|ÌCå¢Q«Ã÷ÕWu…×ßsÍø”I*ôÛÝù5Gî M3ÍÛ9ù"8ku'¡|ºC6[EÌZ”¨H¦DóêüÊ’hUv©ÅMÄ¥ZgkP-SRúÑ:G0~9Ôõ‰`<´Ÿþ7}t.4£d[ùAC+œmíûWx«ÎAËŽ|)Óþ„™Æ*¦râŠføb*âT¹lÑf³Šé<Âðć8;ùú™ÔŠRóx.‰t=™z#dÏäœÛqHRø&³œç“ÈX1ý¢U4¯MR·WõâD+j-Ò÷PÛ¬.<öSåMã×5X3Z$ýžìr˪ð[’Ì"ÉÔRp“°ŽÖàqãCæPÎ<žO½»ÞiM< `¹_ uݲ…îßß•!›¸Ÿ°N,ëîªóýý] Ýw¹¿lW¿ÃŽϱ’wóf(U¾Â}b^ÌjTÞyʸ”ž©=‡ò$KT½ëóV.SXõïÙÌæCfóãTÉb¾F÷hAYÑÚoa¶n®MÖäe9;‹êѫɦêvóSÄ• ÐN]˜‹|¶ÜeW² MHÂ5…]lß”&˜®‹5XÄp^­î£v\²Æ2u™æŠ«k6S‹ÊgÜ|„¶Žç©ÉkfìïŠS\ÖÖÏv©÷Øcårûóc˜Áòä‰/ä)o êÛ}›7Ç*èÀ^·ÔsW1Œa¹ëÚö¤/ûåš“R®e0C˜ÊJÚ°+Ǧ"ªÁFæ„]týÌä¤édŠ\ÛÛ2ž}Ǹ¤{ž)pÎŽu¼äûÖ`s“ecöØ©©,/Ù`E,pô G+Ç*¯Œtù19'œÿŽaIïz‡ìÐħ ¶_ewF2¹”Ó’.ìÅa©ùÁ–¤x÷‹®^‡ÃÚsz²ÐS÷ó.å¼Ânyߨg®?Q{˜í:ÞZC!ý" µ)ißËÓ}]8˜J[ºú0W/ó£æžíçÂ!Þ^¦°Ä×q[JÅ'<åÒ‘N?Ò‘½í´‚E^yÖUO­ŽG÷pEŸÍXú²Cþjð2*<ûg£°Gê¥ßñÌ«.øbÓú^Ï¿‡ìå­÷BózæU×ßaäX_ü¦ah¼”à•¿qM ä Ø ÄxF°8®ú™sšÐ—š1Ç€Ûàë_Øè×jÛÊE_2æIÍK¼7ÖýO7öotp´Â 4#Ø\èG7K–Ùõ ÿÝœM¨uîüCÏS,XlÿÝ\~z#]·Ó¶~÷=øó?õ7êQëâÐA°Dl*Ø8ÍêZ~mþ$7¥—)ößÍßï\&š7Ç?1µ@ßí}©]=zOY/Ýæ OX•…‚í¼øœcêŠ8Ú†|Pãhù†§WÇ“„f›mù¯3œ©¹iØ–eöÚÉ×NÒÿôÕ‚1aœã_3¾2ïºäX÷÷ªC6æ÷§V FnC£%-¡+}8"ë ©jF³UÌx³¡K‰Îæ F3ƒ4£»Ó/•`µŠ…ŒâF'a ¸«;ó^b$³ÈÐ8&•`Ï Æ±ˆÒ$(·ÞšuYÞfHî¢×½’, ù/ZÎdc˜MíÙ•#RÙ C3Ö…¬ÍuU~Ûx?Sïöñ*““Fg™È NãØTfyëwò™Ü•Jò*9íp®Í[;=ØŠ)_à½ÜDNåK¼µÀ‰ÛÖØn_¾×}“d ôÚÎg3"aü†°•,btº&ž§5“xÆšœà•§ÃÁ\Êñœe ÃrצŸË\Fr,gåÊÆ`³&sìJ&1‰‘ÜLáÖ^Õë®§ÏwÃ*E<ºÐá­+³ÅÔÅ«ü…,zs:˜Î3ü—•^NÖ˜âT.gpƒýbï$-¯5“ý=’‘ŒŠTÀ4غY¼Øà©Úör\ÙêWÒʵ=˜êÃ¥Õ4­—îuÿdÙŒ£ûûz‡¸ÈTõ#«äá¨$=_Ãë:°œÉÉvÇ”«róQ*VQ{¸¬eÊw™•ØÑQ·(6•©p×<ûçÆˆ ²~6׈ö×T7Œ© °K^])´:7üG‰oXO*R ¨mª}Ñ:™±3©ç ¶<*<ñ–oŒ1«"g÷ò…¾ýïÕª#öö×>kzó†ùÆß¬Êj±·»Îˆ^æ²UŒHF¶ 8˜Ù¼›¬ÎRGRß•uõ#'±Ø“ö|NÿJbS/¦b;%G}”ì,ãeÞgEtçHŒtpëàgdõŸç¢òjn]óU™¿æa«Æ¬Ï®*Z] )½óóÔ¸V}(§ê­±ÒT½fR«îÌ—[9rѨµ#§uWxý=׌OZÊR?¼Õør™f¾uƒÞ1uCYƒ*›0"y*;Ð}“‡waîÀxµv«jÂÂŒ”¹˜–*Sµ¶X׳? åzn`ÅƵ©žóç©c_`:«XÆÇ<Ä£aC®;/qûòÙ~©{–Ö¬ÄU#]ͪ“ëL*Zµ¢?bUª. jø}«¢¾·v^›´&Ä]‹|qâêX±ÀûÓe3v=Ëÿî÷oƒZLL™ø½)`Ädó¦9åÛ­ƒ32A¬äc†äš…*æ1/¯'ZΦ\“ô[DÛòîæ2dy#qƒB3êϧ%µù›« ý¥YÍÝ,% Ùê|É•y%ëIQJ„*òú2ùe‚­’²¢µ›@ëæº—®½³¨`í–ùá£Z(s Ì¾üÕ·âsÇö•9Ô“+¶Òû¹^ÖÃRCÓû€V©÷®F'/RÔÄÑôN¬ù\Ãí,Î ]T‰Ó]ÉÀÉqÜÉ/9Œ,c¸#)Ì=7J8% Ô©d¡ù¬,rq[ŸUß?sg[+¬‡/¹T5ý½¥©ú޶߫֩ód«ë8´ ÍØÚ9a]Sm SäÚÞÎÙÓŽ©Æ–)pÎŽuÒƒõµX™š–ÒŽ^I°aŸÔ\˜‘µ^¾˜opn2Õ¥ræ—Sኪ ¯$AŽ6œF-Sã% “I7™”ɤ^ß+N½k<+4£áƒÂÓJߢš• ^míûµt+ Ø5åŽÏ+06 î ü^tK9¡)ç´*¦Ù=À·vÚ÷òt_{4“¡yKÿs¬«[XÔÞ³ýX*CQ‰ p[Ò– :zå-Ù9Ïž¼Ú¦lçå·dßtÖV¼ÊÀ:Z|dÍK³¹š+¸‚Ç£œM^ª¨½³x47r¿áì‘Tß99Ϭ”8UÉXIjºÔÌd£G ʦôc«g]ÆõÞhå{+ݾbž\ê‚u CΫI`êEöJ]|%/$Ó¬áKrfØŸ÷ɲÉ{¤Ÿ%ñ®‚dE°usàžFõ6g¹¥J<ć+ì¶—á;›»\I‰²pFÇÔ'È3žYlWï¯RùZFe—qÇÔË䥩eyÒw\žŠ}U½Î¹7O'cŸÓÙ+±NUÁ«nÑõ\·qW[O¬®ôåE.h³f²ktäK‰ãù 2ULå~«]Ü _L9•õ瀤‰”ó ˜ÃÓIÚ™ÝãéV·±mJ• ÜÓŸþ©O³d´+ ÁÐHÖ`Iêꃸ/÷7PN- ˆ­ânF0›ULç‘äÅŽÎNl[&µ¢Ô<žKÂàO¦^Û39çv’~…É,çù$l^L¿¨ïu];¤¢Ð•mí9Çî?hë•zJÏñà9VònÞ$„Ê·4OÌÝù`Þ >ü"Ù®|W³²:ûs³Å·Så»pIô‚j"·ŸëötêÍ*nŽ{·~Öà}–&özß¼O;Ñid‘gÒŒeTÞÎ2.MÖ•¨äP>àƒd‰ªrC‡&þDå¿g3›™ÍS%‹ùÝ£¶×c½©y%¾ÒÚu¯òüýyƒ1Ì`yâ¢ò”à¯ù>/V·®mŒiÁƤÖ =û¨„ݪ‹}ì•LÃÊ$ ª›L_Ä·yƒqÌ¡‚ìÅÑy ’qÖ»®mOú²_îì˜R®e0C˜ÊJÚ°+ǦMC3Ö™ÿ¶pù:ÖžÓ9=qîç]Êy…Ýò¾Ñe\Vï3—ñe¾ÕM}­A†u•93‰T’üH¯=Ü3ן¨…IV£ª‡ª_„¡j»—›úúЌ≘ÊAÊ)™Às‰Y(fï¸)[¹fT:—SF–ו4œX°¸É}¯Ù•³½K£†ÎL®æÖdIΈ¬G›ž¦±†NWÖ¯ }â™W]ðŦõ½ž©õVƒu0QÛ°G&¯þ¡A°¾Ä'®ú™ûê¸MSùR3æp88j¨átàÞ¸ MŽ˜‚lô£›%Ëìz†‡ÿn΂Müuæ.ðÈ?ô<Å‚ÅI’ê ?#šPC¾–_›?ÉÅ?jJ_¬WÇs„fAS£-ßáu†3U5« 5&%t¥GÄC„fA“mÎÇpL܈ ØXÄxFAšA„fA¡AAhFA°¥°ó¦–2— mSéÚëC–ûSÙ€ ¹1•T«’©Ü’¤iìÇy©cÿųɚe=ähÌò6Cr—;_µÜq9ãø/c™É2JéÌA1-2Ý[‹fÌá³$ Þt¶Ï[³¾1:õo9Ãó4£&±ùwJ0ºsmJ0æ%ŒœË\Fr,g%²1Œ‡sO»„ñŒgh­"Ë›ë›*gRÒDP‘ûoŒL²*Vñ6«ê!/ðL¢ Ý@«äÓ±IÆù }¸ƒÛèøJ’Â¥’ÊlŽ×s7·r@"'ŸòL4‰ hDklš±<‰U±2Oj1ýUÞ@Qb¬gñI]¾ÈÓÉ]¹ŽÖ©O§$Í´2Al Zs|rþ ¦&%›s)ײ%´ãBÚ$Ÿ¾[õ ‚`ƒXƒ`kÑŒâÜlˆ•=÷zF¹>OÉÃQIè³"/é÷Z¼ÄßÁè€\Á@˼¯$¯@%ûrPîGÍR‘±¥I¦â 6¶5¶"ÍX+^¹ õÌ >"é•p0»&ûGÖÜ7yŸ§ÁèÌuÕEK÷¤}"?ÿb y19ª;Õêú,Jý´Hc ‚͆÷V²Œ¶,deÒOoÃBš×u¾ F$v¼ÝØ—‘dYÈhö«î¨yÉFÇe\Ï“¼ÇP†¦tN¯õ‹Mdr²½[4÷ hklùš‘e³òRv¯`|â“v¬uÔÄÔXôÞ°ŬHÆ9ö­5Ä´]*ÄT­´ÌË|+g S£åk±˜?&®O)§Öã ‚`ƒXƒ`ó¤!±©™|ž×DÖjFÓ™Ssa©‘ê}@+vL>ŠUË(Hº3ùjtW2RrwòK#Ëî`v ‚q7Sõ¼(rpAcYƒ`Ë׌zæ>›_³[õ_»$µo†}’®ýrFVwàÉXE–÷ù}uS›^I†CÚpe´ä¬dpb!ƒóYÈ]|šÆ…5DÆ‚ ØàÖ ØliHl*__ŠÉæYðšb;¥F&fsuu“ážw†ö|•_1›,ï2‹Sß=ˬ”&Û%´LrïÌÌŒ»™˜üŠ‹9 C4–5¶ ?cÛÜPÀvtÈÝ™a›V«'[Éø”õOÓëh—(ÄÛü!wVxi²1/µy*ØU–ÛEº+%—†`AYOkl~F[º1•ršÑrŠèÉdVQD×¼7'*YÂÉöA\–ûiÕêRåŒà Õ¡rÒÔ¯˜—x$\Höâ²Ìã9N¦‚§’€Uå‹ßiÁ¨œ(Ռ˒‘• Ç[‹fTö÷·K&ÓŒlC9…5»¢ï'ïÊeØ7ïÓNt`YFpb '©|9ã®D6†RÀùp($²ñ/ävv*—)¬äÔÌÚÜ›çwÝH·hA°Ñ¬A°9Óðwúª^òÌ2?¢È¤É'½^H »U÷-öJù“j¾zú%ð,oñ(qÑ›ÖP@ö¦?çGó ‚À:Xƒ`ëò3Öj.½ë]r@]eÎäÌÜ=÷ÖP²+·Õ ‡pH]:Š£¢Þƒ`C‹Gï¸ ágAAhFAšA„fA¡AÁfD5ó¦.¾|ÀÅuÏs ‚`Ë'¬AP‡f |àî¸)A„5ª%㾸 A]4t=®·ã–Á–IŒgA¡ÁI?MåîÝ"¯¡AAhF°Uò ßäHŽfïÖZ8Ë=\ÉR;'qߪ.åâ†unå­F9*B3‚ Vð-¶á)þçñX IÚÓtá?I6xü‡.±ôil~Å-ÆL>ç+I’öƒ9¸Gõæ=>e3’øGòéþÆH–±_¥cîþrä,ŠSç\Î@ʹ”^d‹éÎéìÌï™ÀfGþ‡Ÿ³˜ÈÅìÄãŒ{r.­«; yÏhË9‘§+Í‚zÒŽ ä|v¢Y½Z_Þ`Þ¦W"9ÈòEÜHÿâwÜH!åiÅ>fä¨ùüŽîœK!“ù×Ћ‰Œd'.aGÒ‰—ó.WГ,·Óš[¨à<È7k8ê}úÓ™A<ʹê[ › H3~Mk¾Ë‘\À¿ëw`_F3ÿpD*05ù í(ád–0‘iŒã<:М#R z§r;ûòU A!”RÄœQsàëhz‘I²{M+Úpø¼†£Ž¡;EÊRæF;ÂÏ‚ª®ÿlÕöÀî¾Äu9wá»` ÿäG´âкNÚ†]xœìÆèdÿâP¶!Ã*ÊÉPÆT²Õ…ªºÐ'9 ž¤ÛÕuTƒîÕæ«±.ašl:q*ó>ôâŽXf¸Œgù9ËèÆI”‚ËyŠŸ8(uTçñwr-;3‰{˜CÎO<†ãù/±C2*}†þ<Î÷@o.Høj9*¶nb ²ý³9áìX£p+oAêkAAhFAšAlb <¨1>AøAAhFAšA„fA¡AAhFA°UsmƒõfvoÅc´®hØQYîçäßBn¤kn™rÆñ_Æ2“e”Ò™ƒ8"o„Ÿlvd»xôWž<ªA‹‡Ã¢T JyžWfw🲄 –0žÇ¹Åq÷ƒ 4#ؼüÔ×n4ªá7x»}ÃÉòÜ=o³*¯X†=¹ž»¹•’õÉ?噸ÿAšlF|v±¿õ‘¥¢ƒÇ¿ïóÂz{' Kò%20‹Or‹5çR®e7JhÇ…©ÌzïV§1A„fM‘…‡yðË3kþýýÅVÔïØÏSòpÍAE^xjßÜœh–óXÊÒ¨† Íš>«zxø&3‹S»2&\æÑcê5°1‚ò¤Ì®Éþü€U¾ƒ²(Ù.¦$j"B3‚&N¶•§o3ª]Þþ"C¾oÐu^Áˆ$0Õn웄§æŒç3‘ÉÉönGeAhFÐÄw¹A;TïOd[{ö¦Öa÷§%Û{SÀ‰õOs䳘?&J)§6 _w¡Á&¡…×NQQ³µ^ÞÛà=k;Á0*’Ö·hŎɧ£Sѧµãn¦€".¢KÔE„fMœŠÎ¦—ÕѨ&ï\£¯°2õ_;z û$NÃrFæµ»ø4Œ Ù/j"6ñ*mÐ@2K”¤!³L§É2-LëœèDVqÍÙ1/ÙžÍÕy² çðTÜi!w3s1D5AøÁæ¡ÓöVbгº>êÔWq«öÉ»™Ùy³Æ‘†Z†+ªϬd{w¥ãÒŒ ?#Øœ¨Ð÷&+¯2|Wm†:c nR8Ð5ÿ癳-žçðß9pvõ‡.áƒdû .Ëýt*·PN9#øB"•¥šqY2þAhF°ù¸ ùsG&MhÒîZuµÏ ®|¡ŽßOÞÂ˰oÞ§èÀ4²ŒàDÞIͬ]Á½yNòt‹ú‚Æ#bSÁú±rotõþê\Ö6=¶„ݪkŒ{¥|ŽIqsƒ üŒ` £ø·ô©Ÿw€ºÊœÉ™©{rTÜâ ?#‚ Í‚ B3‚ ‚ 4#‚ Í‚ B3‚ ‚ÐŒ ‚ 4#‚ Í‚ B3‚ ‚ 4#‚ Í‚ B3‚ ‚&F¬k4¼£±Ä1Ãõ™mÆöžÜ×üÊ”|ö}Û‰-ßÎó}Œ+­ùø…ŒâF³$éºÜÀŽÕ^ÂKŒd:pÇÐ,UæA†×|¹ ýÙ?ê-B3‚F§tªßÜã¤9«Íñ¥}œ}‘)å.ý­›F+È€]ÿMÏn[ÝñYäÃú]l&w¥ò¼b"ε´Ú‚ÐŒ )Sáʉ` «ç07÷vëßM%3Ýú'ï0±Ú¬à-9„=YÆŸkN¾’ûÁèÍ…¬â!Æ3™\—ÄV/ËK[Á™šøí£æ‚ 4#ht g8iÊÚ~ñ/©X®y®éo=Ö‘ <Ò&ï.O¶ß©õboSy­B΢òT§sŒåCö¨áؘžlïB÷¨º Ø0ÄxÐ2yÚ€âI¾03¯hV«eëq¥,ï$.Hk:&û{$#5KN–7¬Î5›á2QuAš4:åÛ™P\ÎäÇ—JLXŸñ† &'ÛmSF¿ˆÖÉö$Õ'!ŸÃÉv'öŒz ‚ÐŒ`S-óì5@¤™µ—ÁÍÖGXl—¦4#CÕŒ¬ù5Œ…¼ÅʤðQF½AhF°IÈxþTo—ÔU¬Ô½'[°>¡U)=(¨¡Í®ªN3Vòf²¿GAhF°éXÙÅ€sÍÊÔ¦+ÿ>×CÖï2E)ßb­TEueªø€ªi]‡Ñ)¶Aš4²­ü ¿¡eÉ¿­}ÿ o•m¸ @WPÎS,`O'>ÇÎìž[~ Ã’í]èU£»ëʲî®:ßßеÐ}—ûËvõ;,IÁ ~‘lŸÀ™ ˜þÜÅlFñíTù.\’×áy›E‰NF„Tˆk× nIDATfMû»â—µõ³]êõÞFÃèÈ÷y±ºumKòTçdô»½£f‚ 4#h’¼ûEW7è€ü%k¡Œ/ó床𽨊 ØèÄxFAšA„fA¡AAhFAšA„fAAhFAšA„fA¡AAhFA°ekëK³UÌx³°~¥§rK’©ç%û³ü‹g“µi{2€–Õ-œž&CöåÜÄÌJžÁ‰ÕíÏò8¯%×mËOr‹)ŒàCf±ˆf´gŽ¢cªX9ãø/c™É2JéÌAÏYš‰ÍýÑ\Wè·÷3ë~ÿN Fw®¥e£|ÿS)ÄóYÊÏ’Ì€•,c2“ÌU©¼OÃx8÷Ø%ŒgRBånç·å‘­R xψvÁó|‡[?à¾Qbf<:‚6´ˆdFÕ6ªõéP·o÷´¼ÚÜÜ:xHkSëÙ^–—2¡áX¾šs™Ç¦p>ï+[·³ì/­Rc¸¤E¥òó¸…/ñ9>@W õ•ÁÅG50nâÙRÉ_μ5‘̈ÑêàWôzºÙ¦:ÿÔëÎ6¯ï;­Œ”­ó· 9¸¨^¹b\ÛõÁâò¿^F[íe{iÚ:©ÃÏÊ >Téë~F“½°›Õl.qgæ‰dFŒn[ÇûĤW{üxª¿n¿È˜É*f”súϹ½ullåɲ|&Óì?PçGüiù·®¬ßÁ5üyë·QãÄÊ‹ìjŒ›JŒe”ƒ%’¬™âúžA×Ã=3Þ¥“èèUf±ªôB×y”¯·hðy ¬ïêdˆíã¥4©UF¾¡g+ùQ¼‹ÕüºÆ•¼#‡Ik2n*Fªfu¯%/úhŸûǸtÚ«…:Ð?hê‹ì ÎÃtqÙàï3{ùiY^Äüf¯s?›x@/ûxû+¿¥ÿ>ÇqsÃso+¥Ækî7õ-êœÉ,¦±›*ïdNåôFÿÿ¿‡«x[‘HfDTôuûT¯·nwjÍßôºoÄUkÿÅ«Kl¬£‹OTbãÑr­Ã×ñíg]¥•©j&+ééüíáa~ÜlÓq¬¨|€~VY{€[êù¿ª4jE$3btÚ1Î%S­êò…#¼þ ÿ"ð/–«üÖÒÍÇè¢5¥‰i‹[¼Â2fó_<ÍN^aþ‘wð~°•ïðKºx3ç7%åa¾ÏCà4>ÖdÞÌÔG³‰|¯Ù]5r3Sø;nà\în^ú»ùÁ àko8šÌˆˆ8š-a?kÖï`ç0ñœÊ§JÓÒÝ|Ö ;Œöò~æ0‰ð[“Ç’q|»Ø;x}/Çq›Û˜Ð {ØÅ›Ê3˜ÀsÉŒˆˆcÌ;éåžÁ+Çòi&r+Ÿæ.›Îã³ §ÿý%úÕ§q’œôGD庸€/óîÁëgðñ’ëø:JoyÓze 9Pg“›{¦Îˆˆ8ú-äùæÓdŽãlŽçW­_a2SÙR~|‰}M¦²OGf/S£·“{ƒ?Žlbã™ÏÙœ5xbŒ­”Òj¬ä¬ü"Ê'â>W)^â–1Ÿná…2KØÝ¬åoW Ý,å?XȾËÉÌMfÄëh;O—ÑÛX@ïpO©óï|¯2fcøo–p)ÝÙ­#2›³+½ÓYÊ]ü/ufsñp“œÇoù<XÌŠ&ó›%3b¤³¥rêïc S‡kïÜP£Æ…,çW|‰½¬c6(¼Š«?·¿/9jÌÌß F}mqíà5qQeëéœÞ"Îk¶¾› ¹p¨ß™þŒ©ý¼æ`¥­U‘qo‰™¹œËXñÇeë= ã«6²­,/ª Œˆß—dFŒÔ؆ºµ6\áz¸2iöìÊÑ7ÐÏö [çÍš’7CÌ ÉŒxƒfÆkz/¦3ì¬à‡+D¶´Ø´õeyNëñ‚‘̈7œƒì¦·=Lc÷7´ébFY~¾ÒR½?ÁÎÏ][ò¦Æ²t•GüÿHxt¨¿x±aøž*çôÙœÐ"3ÞÅêlå^ÞÇfþ³ò˜C-"ê¡ò§°$†ˆdF^à7Ã…Ê6&0½ÙÖålä êÜÁ hz‘Çz¶—å¥\¯«´ME‡vµ÷°VMLcù3.f>=ŒáD>\iãšÕ,„î/EÆ8Þ“¿ADêŒ8z¿fŒ¥ÞЦ4Ä ¦n–³¼²f3?(/Þ8'ÌVž,Ëg¶(_"F•þÙ–ü‰[ÅV~ÂgÊçô>¾Íuœöq=+Z\´oq_ùrö…æù̈Í`g¥3£‹ãË™½^9|§wrôßSúÃOnÖò@¹¤+Cl#*Îᣃ×LáN^du62—ÿ)™±™>ÞÜú/áãk|iŒR/'–aK=, ‡‰œT¾Œa~“)!ç7ñ/qˆm|³ÜWj5’{ùiY^Tî–MÍe*¿,ŸµÍœÏ¦òl#ó™ØbÎ¥ö¤ÎˆÎÍâx—Ãçz˜ÅtÓ=\)ð$O4¬œÈ•œÔ°þQö”Ú%EFÄкy YÊ&sw²‡)ldñ‘~ˆ’1"—|×ÙÉXfµqxÿ÷—¬aÛéc§³¼Ùý ûXS𼿰8û=¢âžÊ Çðôr ?äOr2ãy›Xȳå^R­î7•̈ßGxtz*?©Y=ÑT×gG´ÐØŸEì.#GΦÆ"6ÒMÏëк›þŒˆˆcÈtf²ž-¼¥¤È&6”ÞÇdFDD¼zR_Ä}Lg28ÝüŒSJgFúÀ#"Fj./óŸÂOXRŠ‚1,à1 ÷‚ò²|M¥$™qkœm©êL¾<øÁW~@«>ð¥,¾Œ‰ˆˆhKêŒhîŠO^w…ë²""™øýÖ›²"¢QÍW²""¢-éψˆˆdFDD$3"""™otcn«­Î^ˆˆmVÔW$3°båªì¾ˆˆÑ£^¯¯øêH3q1JlZþĈŸ›þŒˆˆh£4YYOfDDD[Ñ{ˆdFDD´ÉŒˆˆh+0úÇY%3""b˜Àxï²sSgDDD»‘>ðˆˆh+0N^xZúÀ#"¢ƒÀHfDDD[‘>ðˆˆh+0ÒFúÀ#"¢­ÀHxDDtÉŒˆˆF[‘>ðˆˆF[‘>ðˆˆFga`Î¥#™‚#""ŽÞÀXQ_å¾a~”õz=»/"bT©}µÖþþLQ } ‘pÈIEND®B`‚tenace-0.18/src/000077500000000000000000000000001505733770300135025ustar00rootroot00000000000000tenace-0.18/src/Makefile.am000066400000000000000000000013711505733770300155400ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in AM_CPPFLAGS = \ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ @PACKAGE_CFLAGS@ bin_PROGRAMS = tenace tenace_SOURCES = \ main.c \ callbacks.c callbacks.h \ bridge.c bridge.h \ file.c file.h \ functions.c functions.h \ options.c options.h \ print.c print.h \ solve.c solve.h \ window_bids.c window_bids.h \ window_board.c window_board.h \ window_card.c window_card.h \ window_line_entry.c window_line_entry.h \ window_misc.c window_misc.h \ window_play.c window_play.h tenace_LDADD = @PACKAGE_LIBS@ $(INTLLIBS) ../handdisplay/hand_display.o ../lib/libgnu.la -ldds -lgomp -lm tenace_LDFLAGS = -export-dynamic EXTRA_DIST = unused.c tenace-0.18/src/bridge.c000066400000000000000000000305621505733770300151100ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2013 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include "bridge.h" #include "functions.h" #include "solve.h" #include "window_board.h" /* bridge math */ void calculate_target(board *b) { int side = b->declarer % 2; b->target[side] = b->level + 6; b->target[1 - side] = 14 - b->target[side]; /* 1 more to beat contract */ } int card_overtricks (board *b, card c) { assert (b->current_dd && b->current_dd->card_score[c] >= 0); return b->current_dd->card_score[c] - 6 - b->level; } int card_is_good (board *b, card c) { assert (b->current_dd && b->current_dd->card_score[c] >= 0); int side = b->current_turn % 2; if (side == (b->declarer % 2)) return b->current_dd->card_score[c] >= b->target[side]; else return 13 - b->current_dd->card_score[c] >= b->target[side]; /* NOT REACHED */ } static int ns_is_vulnerable (int board_number) { switch (board_number % 16) { case 2: case 4: case 5: case 7: case 10: case 12: case 13: case 15: return 1; break; } return 0; } static int ew_is_vulnerable (int board_number) { switch (board_number % 16) { case 0: /* actually 16 */ case 3: case 4: case 6: case 7: case 9: case 10: case 13: return 1; break; } return 0; } /* dealing with boards */ void board_clear(board *b) { b->n_dealt_cards = b->n_played_cards = 0; int i; for (i = 0; i < 52; i++) { b->cards[i] = 0; b->dealt_cards[i] = 0; if (b->next_dd[i]) { free (b->next_dd[i]); b->next_dd[i] = NULL; } b->played_cards[i] = -1; } for (i = 0; i < 4; i++) b->hand_cards[i] = 0; b->current_turn = seat_mod(b->declarer + 1); b->tricks[0] = b->tricks[1] = 0; b->declarer_tricks = -1; if (b->current_dd) { free (b->current_dd); b->current_dd = NULL; } b->par_score = -1; b->par_dec = b->par_suit = b->par_level = b->par_tricks = 0; } void board_set_contract(board *b, int level, suit trumps, seat declarer, int doubled) { b->level = level; b->trumps = trumps; b->declarer = declarer; b->current_turn = seat_mod(declarer + 1); b->doubled = doubled; calculate_target(b); } board *board_new (int board_number) /* user-visible board number 1.. */ { int i; char *names[] = {"West", "North", "East", "South"}; board *b = calloc (1, sizeof(board)); assert(b); b->name = g_string_new(NULL); /* newly created board */ g_string_printf (b->name, _("Board %d"), board_number); for (i = 0; i < 4; i++) { b->hand_name[i] = g_string_new (_(names[i])); } b->dealer = DEALER (board_number); board_set_contract(b, 1, NT, south, 0); /* default contract is 1NT by south */ b->current_dd = NULL; for (i = 0; i < 52; i++) { b->next_dd[i] = NULL; } board_clear(b); b->vuln[0] = ns_is_vulnerable (board_number); b->vuln[1] = ew_is_vulnerable (board_number); b->bidding = calloc(4, sizeof(card)); assert(b->bidding); b->alerts = calloc(4, sizeof(char *)); assert(b->alerts); b->n_bids = 0; b->n_bid_alloc = 4; return b; } board * board_dup (board *b0) { int i; board *b = malloc(sizeof(board)); assert(b); *b = *b0; /* copy "real" struct members */ b->name = g_string_new(b0->name->str); for (i = 0; i < 4; i++) { b->hand_name[i] = g_string_new (b0->hand_name[i]->str); } b->current_dd = NULL; for (i = 0; i < 52; i++) { b->next_dd[i] = NULL; } b->n_bids = 0; b->bidding = calloc(b0->n_bid_alloc, sizeof(card)); assert(b->bidding); b->alerts = calloc(b0->n_bid_alloc, sizeof(char *)); assert(b->alerts); for (i = 0; i < b0->n_bids; i++) { board_append_bid (b, b0->bidding[i], 0); board_set_alert (b, b0->alerts[i]); } return b; } void board_free(board *b) { int i; assert(b); g_string_free(b->name, TRUE); for (i = 0; i < 4; i++) { g_string_free(b->hand_name[i], TRUE); } free(b->bidding); for (i = 0; i < b->n_bid_alloc; i++) if (b->alerts[i]) free (b->alerts[i]); free (b->alerts); } /* dealing with cards */ int assert_board(board *b) /* check proper number of cards in hands */ { int i; for (i = 1; i < 4; i++) if (b->hand_cards[0] != b->hand_cards[i]) return 0; return 1; } int add_card(board *b, seat s, card c) /* return: 1 = card added */ { if (b->dealt_cards[c] != 0) return 0; if (b->hand_cards[s-1] == 13) return 0; b->cards[c] = s; b->dealt_cards[c] = s; b->n_dealt_cards++; b->hand_cards[s-1]++; invalidate_dd_scores (b); b->par_score = -1; return 1; } int remove_card(board *b, seat s, card c) /* return: 1 = card removed */ { assert (b->dealt_cards[c] == s); b->cards[c] = 0; b->dealt_cards[c] = 0; b->n_dealt_cards--; b->hand_cards[s-1]--; invalidate_dd_scores (b); b->par_score = -1; return 1; } int flip_hands (board *b, seat h1, seat h2) { int cards[13]; int n_cards = 0; int c, i; for (c = 0; c < 52; c++) { if (b->cards[c] == h1) { cards[n_cards++] = c; remove_card (b, h1, c); } } for (c = 0; c < 52; c++) { if (b->cards[c] == h2) { remove_card (b, h2, c); if (!add_card (b, h1, c)) { add_card (b, h2, c); break; } } } for (i = 0; i < n_cards; i++) { if (!add_card (b, h2, cards[i])) break; cards[i] = -1; } for (i = 0; i < n_cards; i++) { if (cards[i] >= 0) { c = add_card (b, h1, cards[i]); assert (c); } } invalidate_dd_scores (b); b->par_score = -1; /* invalidate par score */ return 1; } void deal_random(board *b) { seat s; for (s = west; s <= south; s++) { while (b->hand_cards[s-1] < 13) { int c = rand() % 52; if (b->dealt_cards[c] == 0) { int ret = add_card(b, s, c); assert(ret); } } } } /* playing */ static int has_suit(seat *cards, seat h, suit s) { int i; for (i = 0; i < 52; i++) if (SUIT(i) == s && cards[i] == h) return 1; return 0; } static void play_card_0(board *b, seat s, card c) { assert (s); assert (b->dealt_cards[c] == s); assert (b->cards[c] == s); b->cards[c] = 0; b->played_cards[b->n_played_cards] = c; b->n_played_cards++; } int play_card(board *b, seat s, card c) { board_statusbar(NULL); if (b->cards[c] == 0) { board_statusbar(_("Card is not in your hand")); return 0; } if (b->cards[c] != b->current_turn) { board_statusbar(_("Not your turn")); return 0; } int firstcard = 0; card lead = 0; if (b->n_played_cards % 4 != 0) { /* must follow suit */ firstcard = b->n_played_cards - (b->n_played_cards % 4); lead = b->played_cards[firstcard]; if (SUIT(c) != SUIT(lead) && has_suit(b->cards, s, SUIT(lead))) { board_statusbar(_("Please follow suit")); return 0; } } int old_next_card = b->played_cards[b->n_played_cards]; play_card_0(b, s, c); if (b->n_played_cards % 4 == 0) { /* trick complete */ seat leader = b->dealt_cards[lead]; card wincard = lead; b->current_turn = leader; int i; for (i = 1; i <= 3; i++) { card thiscard = b->played_cards[firstcard + i]; if ((SUIT(thiscard) == b->trumps && SUIT(wincard) != b->trumps) || (SUIT(thiscard) == SUIT(wincard) && RANK(thiscard) > RANK(wincard))) { wincard = thiscard; b->current_turn = seat_mod(leader + i); } } b->tricks[b->current_turn % 2]++; } else { b->current_turn = seat_mod(b->current_turn + 1); } /* update DD scores */ dd_t *dd = b->next_dd[c]; int i; for (i = 0; i < 52; i++) { /* remove the other DD previews */ if (b->next_dd[i] && b->cards[i] && (b->cards[i] == s || c != old_next_card)) { /* invalidate "what-if" previews and old scores from other cards */ free (b->next_dd[i]); b->next_dd[i] = NULL; } } b->next_dd[c] = b->current_dd; /* remember scores for rewind */ b->current_dd = dd; /* printf ("previews for: "); for (i = 0; i < 52; i++) if (b->next_dd[i]) printf ("%s ", card_string(i)->str); printf ("\n"); */ return 1; } int rewind_card(board *b) { if (b->n_played_cards == 0) { board_statusbar(_("Nothing to undo")); return 0; } if (b->n_played_cards % 4 == 0) b->tricks[b->current_turn % 2]--; b->n_played_cards--; card c = b->played_cards[b->n_played_cards]; assert (b->cards[c] == 0); seat s = b->dealt_cards[c]; /* remove DD previews */ dd_t *dd = b->next_dd[c]; int i; for (i = 0; i < 52; i++) { if (b->next_dd[i] && b->cards[i] == s) { free (b->next_dd[i]); b->next_dd[i] = NULL; } } b->next_dd[c] = b->current_dd; b->current_dd = dd; /* return card */ b->current_turn = b->cards[c] = s; /* printf ("previews for: "); for (i = 0; i < 52; i++) if (b->next_dd[i]) printf ("%s ", card_string(i)->str); printf ("\n"); */ return 1; } void board_rewind(board *b) { while (b->n_played_cards) rewind_card(b); } int next_card(board *b) { if (b->n_played_cards >= b->n_dealt_cards) { board_statusbar(_("No cards left to play")); return 0; } if (b->played_cards[b->n_played_cards] == -1) { board_statusbar(_("Which card should I play?")); return 0; } if (b->played_cards[b->n_played_cards] == claim_rest) { char buf[50]; snprintf (buf, sizeof (buf), _("Declarer claims %d tricks"), b->declarer_tricks); board_statusbar(buf); return 0; } if (b->cards[b->played_cards[b->n_played_cards]] == 0) { board_statusbar(_("Card was already played")); return 0; } if (b->cards[b->played_cards[b->n_played_cards]] != b->current_turn) { board_statusbar(_("Card belongs to wrong player")); return 0; } return play_card(b, b->current_turn, b->played_cards[b->n_played_cards]); } void board_fast_forward(board *b) { while (b->n_played_cards < b->n_dealt_cards && b->played_cards[b->n_played_cards] != -1) { if (! next_card (b)) return; } } /* bidding */ int board_append_bid(board *b, card bid, int set_contract) { int cur_bid = 0, cur_bid_i = 0, n_pass = 0, doubl = 0, redoubl = 0; int i; for (i = b->n_bids - 1; i >= 0; i--) { if (b->bidding[i] == bid_pass && !doubl && !redoubl) n_pass++; /* number of trailing passes */ if (b->bidding[i] == bid_x) doubl = 1; if (b->bidding[i] == bid_xx) redoubl = 1; if (b->bidding[i] > bid_xx) { cur_bid = b->bidding[i]; cur_bid_i = i; break; } } if (n_pass == 4 || (n_pass == 3 && cur_bid)) { board_statusbar(_("Bidding is over")); return 0; } if (bid == bid_x) if (doubl || redoubl || cur_bid == 0 || n_pass % 2 != 0) { board_statusbar(_("Invalid double")); return 0; } if (bid == bid_xx) if (!doubl || redoubl || cur_bid == 0 || n_pass % 2 != 0) { board_statusbar(_("Invalid redouble")); return 0; } if (bid > bid_xx && bid <= cur_bid) { board_statusbar(_("Insufficient bid")); return 0; } if (b->n_bids >= b->n_bid_alloc) { b->n_bid_alloc <<= 2; b->bidding = realloc(b->bidding, b->n_bid_alloc * sizeof (card)); b->alerts = realloc(b->alerts, b->n_bid_alloc * sizeof (char *)); assert(b->bidding && b->alerts); int i; /* I wished there was recalloc() */ for (i = b->n_bid_alloc >> 2; i < b->n_bid_alloc; i++) b->alerts[i] = NULL; } b->bidding[b->n_bids] = bid; b->alerts[b->n_bids] = NULL; b->n_bids++; if (bid == bid_pass && (n_pass == 3 || (n_pass == 2 && cur_bid))) { if (set_contract) { int trumps = DENOM (cur_bid); int declarer = 0; if (cur_bid) { /* find declarer */ for (i = cur_bid_i % 2; i < b->n_bids; i += 2) if (DENOM (b->bidding[i]) == trumps) { declarer = seat_mod (b->dealer + i); break; } assert (declarer); /* someone must actually bid the contract */ } else { declarer = b->dealer; /* default for passed boards */ } board_set_contract (b, LEVEL (cur_bid), trumps, declarer, doubl + redoubl); } return 2; /* signal end of bidding */ } return 1; } void board_remove_bid (board *b) { assert (b->n_bids > 0); b->n_bids--; if (b->alerts[b->n_bids]) { free (b->alerts[b->n_bids]); b->alerts[b->n_bids] = NULL; } } void board_clear_bidding (board *b) { while (b->n_bids > 0) board_remove_bid (b); } void board_set_alert (board *b, const char *alert) { assert (b->n_bids > 0); if (b->alerts[b->n_bids - 1]) free (b->alerts[b->n_bids - 1]); if (alert) b->alerts[b->n_bids - 1] = strdup (alert); else b->alerts[b->n_bids - 1] = NULL; } tenace-0.18/src/bridge.h000066400000000000000000000053741505733770300151200ustar00rootroot00000000000000#ifndef BRIDGE_H #define BRIDGE_H #include #include // FIXME typedef enum seat_e { seat_none = 0, west = 1, north, east, south, east_west, north_south, seat_all, } seat; #define DEALER(x) ((x) % 4 + 1) /* who is dealer in board x (starting from 1) */ #define VULN_N(x) (x) /* cards: SA = 51, C2 = 0, bids: 1C = 5, 7NT = 39 */ typedef enum suit_e { NT = 4, spade = 3, heart = 2, diamond = 1, club = 0, } suit; typedef enum rank_e { card2 = 0, card3, card4, card5, card6, card7, card8, card9, card10, cardJ, cardQ, cardK, cardA, cardX = 0x80, claim_rest = 0x81, bid_pass = 0, bid_x = 1, bid_xx = 2, bid_alert = 0x40, } rank; typedef int card; #define SUIT(c) ((int)((int)(c) / 13)) #define RANK(c) ((c) % 13) #define LEVEL(c) ((int)((int)(c) / 5)) #define DENOM(c) ((c) % 5) typedef struct _dd_t { int card_score[52]; int best_score; } dd_t; typedef struct board_t { GString *name; /* int number; FIXME: store "real" board number here */ int vuln[2]; /* 0 = NS, 1 = EW */ seat dealer; seat cards[52]; /* cards (still) in hand, 0 = not dealt */ int n_dealt_cards; seat dealt_cards[52]; /* cards dealt, differs from cards[] when cards was played */ int hand_cards[4]; /* number of cards in hand */ GString *hand_name[4]; seat declarer; suit trumps; int level; /* 0 = PASS */ int doubled; /* 1 = X, 2 = XX */ int declarer_tricks; /* final result */ int mp[2]; /* IMPs, Matchpoints * 100 */ /* play */ int n_played_cards; card played_cards[52]; /* -1 = none */ seat current_turn; int tricks[2]; /* 0 = NS, 1 = EW (running) */ /* bidding */ card *bidding; char **alerts; int n_bids; int n_bid_alloc; /* DD */ dd_t *current_dd; dd_t *next_dd[52]; int target[2]; /* sum might be less than 13 for partial deals */ int par_score; /* -1 = other par_ fields invalid */ int par_dec, par_suit, par_level, par_tricks; int par_arr[4][5]; } board; /* * prototypes */ void calculate_target(board *b); int card_overtricks (board *b, card c); int card_is_good (board *b, card c); void board_clear(board *b); void board_set_contract(board *b, int level, suit trumps, seat declarer, int doubled); board *board_new (int board_number); board *board_dup (board *b0); void board_free(board *b); int assert_board(board *b); int add_card(board *b, seat s, card c); int remove_card(board *b, seat s, card c); int flip_hands (board *b, seat h1, seat h2); void deal_random(board *b); int play_card(board *b, seat s, card c); int rewind_card(board *b); void board_rewind(board *b); int next_card(board *b); void board_fast_forward(board *b); int board_append_bid(board *b, card bid, int set_contract); void board_remove_bid (board *b); void board_clear_bidding (board *b); void board_set_alert (board *b, const char *alert); #endif tenace-0.18/src/callbacks.c000066400000000000000000000413261505733770300155730ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2013 Christoph Berg * * 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. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include "callbacks.h" #include "file.h" /* _() */ #include "functions.h" /* _() */ #include "solve.h" /* run_dd */ #include "window_board.h" #include "window_card.h" /* menu */ G_MODULE_EXPORT void on_neu1_activate (GtkMenuItem *menuitem, gpointer user_data) { int i; for (i = 0; i < win->n_boards; i++) { board_free (win->boards[i]); } win->n_boards = 0; win->cur = board_window_append_board (win, NULL); card_window_update(win->boards[0]->dealt_cards); show_board(win->boards[0], REDRAW_FULL); } G_MODULE_EXPORT void on_open1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_load_dialog (win, 0); } G_MODULE_EXPORT void on_append1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_load_dialog (win, 1); } G_MODULE_EXPORT void on_speichern1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_save_dialog (win, 0); } G_MODULE_EXPORT void on_speichern_unter1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_save_dialog (win, 1); } G_MODULE_EXPORT void on_beenden1_activate (GtkMenuItem *menuitem, gpointer user_data) { gtk_main_quit (); } G_MODULE_EXPORT void on_button_hand_open_clicked (GtkToolButton *toolbutton, gpointer user_data) { board_load_dialog (win, 0); } G_MODULE_EXPORT void on_button_hand_save_clicked (GtkToolButton *toolbutton, gpointer user_data) { board_save_dialog(win, 0); } G_MODULE_EXPORT void on_declarer_west1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_declarer (west); } G_MODULE_EXPORT void on_declarer_north1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_declarer (north); } G_MODULE_EXPORT void on_declarer_east1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_declarer (east); } G_MODULE_EXPORT void on_declarer_south1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_declarer (south); } G_MODULE_EXPORT void on_contract_no_trump1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_trumps(NT); } G_MODULE_EXPORT void on_contract_spades1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_trumps(spade); } G_MODULE_EXPORT void on_contract_hearts1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_trumps(heart); } G_MODULE_EXPORT void on_contract_diamonds1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_trumps(diamond); } G_MODULE_EXPORT void on_contract_clubs1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_trumps(club); } G_MODULE_EXPORT void on_level1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_level (1); } G_MODULE_EXPORT void on_level2_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_level (2); } G_MODULE_EXPORT void on_level3_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_level (3); } G_MODULE_EXPORT void on_level4_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_level (4); } G_MODULE_EXPORT void on_level5_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_level (5); } G_MODULE_EXPORT void on_level6_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_level (6); } G_MODULE_EXPORT void on_level7_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_level (7); } G_MODULE_EXPORT void on_level_doubled0_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_doubled (0); } G_MODULE_EXPORT void on_level_doubled1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_doubled (1); } G_MODULE_EXPORT void on_level_redoubled1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_doubled (2); } G_MODULE_EXPORT void on_double_dummy1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; compute_dd_scores (b, 1); show_board(b, REDRAW_HANDS); } G_MODULE_EXPORT void on_dd_always1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; run_dd = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)); compute_dd_scores (b, run_dd); show_board (b, REDRAW_HANDS); } G_MODULE_EXPORT void on_parscore1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; parscore(b); show_board (b, REDRAW_PAR); } G_MODULE_EXPORT void on_handbutton_par_clicked (GtkToolButton *toolbutton, gpointer user_data) { board *b = CUR_BOARD; parscore(b); show_board (b, REDRAW_PAR); } G_MODULE_EXPORT void on_vuln_none_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_vuln (0, 0); } G_MODULE_EXPORT void on_vuln_ns_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_vuln (1, 0); } G_MODULE_EXPORT void on_vuln_ew_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_vuln (0, 1); } G_MODULE_EXPORT void on_vuln_all_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_vuln (1, 1); } G_MODULE_EXPORT void on_set_par1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; parscore (b); if (b->trumps != b->par_suit || b->declarer != b->par_dec) { board_rewind (b); /* incompatible change */ b->trumps = b->par_suit; b->declarer = b->par_dec; b->current_turn = seat_mod (b->declarer + 1); } b->level = b->par_level; b->doubled = b->par_tricks < b->par_level + 6; show_board (b, REDRAW_FULL); } G_MODULE_EXPORT void on_rewind_play1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; if (!rewind_card (b)) /* extra call to show warning if there's nothing to do */ return; board_rewind (b); compute_dd_scores (b, run_dd); show_board(b, REDRAW_HANDS | REDRAW_NAMES | REDRAW_TRICKS | REDRAW_PLAY); } G_MODULE_EXPORT void on_complete_play1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; if (!next_card (b)) /* extra call to show warning if there's nothing to do */ return; board_fast_forward (b); compute_dd_scores (b, run_dd); show_board(b, REDRAW_HANDS | REDRAW_NAMES | REDRAW_TRICKS | REDRAW_PLAY); } G_MODULE_EXPORT void on_deal_clear_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; board_clear(b); card_window_update(b->dealt_cards); show_board(b, REDRAW_HANDS | REDRAW_PLAY | REDRAW_PAR); } G_MODULE_EXPORT void on_deal_random_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; deal_random(b); card_window_update(b->dealt_cards); compute_dd_scores (b, run_dd); show_board(b, REDRAW_HANDS | REDRAW_PAR); } G_MODULE_EXPORT void on_dealer_west1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_dealer (west); } G_MODULE_EXPORT void on_dealer_north1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_dealer (north); } G_MODULE_EXPORT void on_dealer_east1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_dealer (east); } G_MODULE_EXPORT void on_dealer_south1_activate (GtkMenuItem *menuitem, gpointer user_data) { board_set_dealer (south); } G_MODULE_EXPORT void on_played_cards1_activate (GtkMenuItem *menuitem, gpointer user_data) { win->show_played_cards = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)); show_board (win->boards[win->cur], REDRAW_HANDS); } G_MODULE_EXPORT void on_deal_new_activate (GtkMenuItem *menuitem, gpointer user_data) { win->cur = board_window_append_board (win, NULL); card_window_update(win->boards[win->cur]->dealt_cards); show_board(win->boards[win->cur], REDRAW_FULL); } G_MODULE_EXPORT void on_deal_cut_activate (GtkMenuItem *menuitem, gpointer user_data) { if (! win->n_boards) { board_statusbar (_("No board")); return; } if (win->cutbuf) board_free (win->cutbuf); board *b = CUR_BOARD; win->cutbuf = b; int i; for (i = win->cur; i < win->n_boards - 1; i++) win->boards[i] = win->boards[i + 1]; win->n_boards--; win->boards[win->n_boards] = NULL; if (! win->n_boards) { /* last board was cut */ board_window_append_board (win, NULL); } if (win->cur == win->n_boards) win->cur--; show_board (win->boards[win->cur], REDRAW_FULL); } G_MODULE_EXPORT void on_deal_copy_activate (GtkMenuItem *menuitem, gpointer user_data) { if (! win->n_boards) { board_statusbar (_("No board")); return; } if (win->cutbuf) board_free (win->cutbuf); board *b = CUR_BOARD; win->cutbuf = board_dup (b); assert (b); } G_MODULE_EXPORT void on_deal_paste_activate (GtkMenuItem *menuitem, gpointer user_data) { if (! win->cutbuf) { board_statusbar (_("Cut buffer is empty")); return; } board *b = board_dup (win->cutbuf); win->cur = board_window_append_board (win, b); g_string_printf (b->name, _("Board %d"), win->cur + 1); show_board (win->boards[win->cur], REDRAW_FULL); } G_MODULE_EXPORT void on_ew1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; flip_hands (b, east, west); card_window_update(b->dealt_cards); show_board(b, REDRAW_HANDS | REDRAW_PAR); /* flip invalidates parscore */ } G_MODULE_EXPORT void on_ns1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; flip_hands (b, north, south); card_window_update(b->dealt_cards); show_board(b, REDRAW_HANDS | REDRAW_PAR); } G_MODULE_EXPORT void on_nw1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; flip_hands (b, north, west); card_window_update(b->dealt_cards); show_board(b, REDRAW_HANDS | REDRAW_PAR); } G_MODULE_EXPORT void on_ne1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; flip_hands (b, north, east); card_window_update(b->dealt_cards); show_board(b, REDRAW_HANDS | REDRAW_PAR); } G_MODULE_EXPORT void on_sw1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; flip_hands (b, south, west); card_window_update(b->dealt_cards); show_board(b, REDRAW_HANDS | REDRAW_PAR); } G_MODULE_EXPORT void on_se1_activate (GtkMenuItem *menuitem, gpointer user_data) { board *b = CUR_BOARD; flip_hands (b, south, east); card_window_update(b->dealt_cards); show_board(b, REDRAW_HANDS | REDRAW_PAR); } /* toolbar */ G_MODULE_EXPORT void on_rewind_button_clicked (GtkToolButton *toolbutton, gpointer user_data) { board *b = CUR_BOARD; if (!rewind_card(b)) /* extra call to show warning if there's nothing to do */ return; while (b->n_played_cards % 4 != 0) rewind_card (b); compute_dd_scores (b, run_dd); show_board(b, REDRAW_HANDS | REDRAW_NAMES | REDRAW_TRICKS | REDRAW_PLAY); } G_MODULE_EXPORT void on_button_back_clicked (GtkToolButton *toolbutton, gpointer user_data) { board *b = CUR_BOARD; if (!rewind_card(b)) return; compute_dd_scores (b, run_dd); show_board(b, REDRAW_HANDS | REDRAW_NAMES | REDRAW_TRICKS | REDRAW_PLAY); } G_MODULE_EXPORT void on_button_next_clicked (GtkToolButton *toolbutton, gpointer user_data) { board *b = CUR_BOARD; if (!next_card(b)) return; compute_dd_scores (b, run_dd); show_board(b, REDRAW_HANDS | REDRAW_NAMES | REDRAW_TRICKS | REDRAW_PLAY); } G_MODULE_EXPORT void on_button_fast_forward_clicked (GtkToolButton *toolbutton, gpointer user_data) { board *b = CUR_BOARD; if (!next_card (b)) /* extra call to show warning if there's nothing to do */ return; while (b->n_played_cards % 4 != 0) { if (! next_card (b)) break; } compute_dd_scores (b, run_dd); show_board(b, REDRAW_HANDS | REDRAW_NAMES | REDRAW_TRICKS | REDRAW_PLAY); } G_MODULE_EXPORT void on_button_dd_clicked (GtkToolButton *toolbutton, gpointer user_data) { board *b = CUR_BOARD; compute_dd_scores (b, 1); show_board(b, REDRAW_HANDS); } G_MODULE_EXPORT void on_button_prev_board_clicked (GtkToolButton *toolbutton, gpointer user_data) { if (win->cur == 0) { board_statusbar (_("No previous board")); return; } PROTECT_BEGIN; board_statusbar (NULL); win->cur--; show_board (win->boards[win->cur], REDRAW_FULL); PROTECT_END; } G_MODULE_EXPORT void on_button_next_board_clicked (GtkToolButton *toolbutton, gpointer user_data) { if (win->cur == win->n_boards - 1) { board_statusbar (_("No next board")); return; } PROTECT_BEGIN; board_statusbar (NULL); win->cur++; assert (0 <= win->cur && win->cur < win->n_boards); show_board (win->boards[win->cur], REDRAW_FULL); PROTECT_END; } tenace-0.18/src/callbacks.h000066400000000000000000000307361505733770300156030ustar00rootroot00000000000000#include void on_neu1_activate (GtkMenuItem *menuitem, gpointer user_data); void on___ffnen1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_speichern1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_speichern_unter1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_beenden1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_button_hand_save_clicked (GtkToolButton *toolbutton, gpointer user_data); gboolean on_label12_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data); void on_button_hand_save_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_open1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_dealer_west1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_north1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_east1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_item3_activate (GtkMenuItem *menuitem, gpointer user_data); void on_declarer_west1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_declarer_north1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_declarer_east1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_declarer_south1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_contract_no_trump1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_contract_spades1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_contract_hearts1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_contract_diamonds1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_contract_clubs1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_level1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_level2_activate (GtkMenuItem *menuitem, gpointer user_data); void on_level3_activate (GtkMenuItem *menuitem, gpointer user_data); void on_level4_activate (GtkMenuItem *menuitem, gpointer user_data); void on_level5_activate (GtkMenuItem *menuitem, gpointer user_data); void on_level6_activate (GtkMenuItem *menuitem, gpointer user_data); void on_level7_activate (GtkMenuItem *menuitem, gpointer user_data); void on_level_doubled1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_level_redoubled1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_double_dummy1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_parscore1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_vuln_none_activate (GtkMenuItem *menuitem, gpointer user_data); void on_vuln_ns_activate (GtkMenuItem *menuitem, gpointer user_data); void on_vuln_ew_activate (GtkMenuItem *menuitem, gpointer user_data); void on_vuln_all_activate (GtkMenuItem *menuitem, gpointer user_data); void on_set_par1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_rewind_button_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_handbutton_par_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_button_back_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_button_next_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_button_fast_forward_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_button_dd_toggled (GtkToggleToolButton *toggletoolbutton, gpointer user_data); void on_pos_north_south_activate (GtkMenuItem *menuitem, gpointer user_data); void on_pos_declarer_activate (GtkMenuItem *menuitem, gpointer user_data); void on_pos_current_lead_activate (GtkMenuItem *menuitem, gpointer user_data); void on_deal_random_activate (GtkMenuItem *menuitem, gpointer user_data); void on_deal_line_activate (GtkMenuItem *menuitem, gpointer user_data); void on_deal_clear_activate (GtkMenuItem *menuitem, gpointer user_data); void on_level_doubled0_activate (GtkMenuItem *menuitem, gpointer user_data); void on_dealer_west1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_dealer_north1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_dealer_east1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_dealer_south1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_bidding1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_play1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_bids1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_played_cards1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_deal_new_activate (GtkMenuItem *menuitem, gpointer user_data); void on_ddno_one1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_ddeastwest1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_ddnorthsouth1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_ddall1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_handseastwest1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_handsnorthsouth1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_handsall1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_autonone1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_autoeastwest1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_autonorthsouth1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_autoall1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_ew1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_ns1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_nw1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_ne1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_sw1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_se1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_button_hand_open_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_append1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_button_prev_board_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_button_next_board_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_deal_cut_activate (GtkMenuItem *menuitem, gpointer user_data); void on_deal_copy_activate (GtkMenuItem *menuitem, gpointer user_data); void on_deal_paste_activate (GtkMenuItem *menuitem, gpointer user_data); void on_jump_to1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_dd_always1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_button_dd_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_rewind_play1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_complete_play1_activate (GtkMenuItem *menuitem, gpointer user_data); tenace-0.18/src/file.c000066400000000000000000000561751505733770300146030ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2013 Christoph Berg * * 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "bridge.h" #include "functions.h" #include "window_card.h" #include "file.h" static void add_filters (GtkFileChooser *dialog) { GtkFileFilter *filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("Bridge files")); gtk_file_filter_add_pattern (filter, "*.lin"); gtk_file_filter_add_pattern (filter, "*.pbn"); gtk_file_chooser_add_filter (dialog, filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("LIN files")); gtk_file_filter_add_pattern (filter, "*.lin"); gtk_file_chooser_add_filter (dialog, filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("PBN files")); gtk_file_filter_add_pattern (filter, "*.pbn"); gtk_file_chooser_add_filter (dialog, filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("All files")); gtk_file_filter_add_pattern (filter, "*"); gtk_file_chooser_add_filter (dialog, filter); } /* * loading */ static char *sane_strtok_r (char *const str, const char *delim, char **saveptr) { char *this = str ? str : *saveptr; if (!this) return NULL; char *next = strpbrk (this, delim); if (next) { *next = '\0'; *saveptr = next + 1; } else { *saveptr = NULL; } return this; } // pn|Frederic,gm,Myon,mecky|st||md|4S27KAHKD49C3589TJ,S36H48AD358KC27QK,STJH259TJQD26TJQC,|rh||ah|Board 14|sv|o|mb|p|mb|p|mb|1D|mb|2H|mb|2S|mb|p|mb|p|mb|p|pg||pc|HK|pc|H4|pc|H2|pc|H6|pg||pc|CJ|pc|CK|pc|ST|pc|C4|pg||pc|H9|pc|H3|pc|S2|pc|H8|pg||pc|CT|pc|C2|pc|SJ|pc|C6|pg||pc|HQ|pc|H7|pc|S7|pc|HA|pg||pc|D9|pc|D3|pc|DT|pc|DA|pg||pc|S4|pc|SK|pc|S3|pc|H5|pg||pc|SA|pc|S6|pc|HT|pc|S5|pg||pc|D4|pc|DK|pc|D2|pc|D7|pg||pc|C7|pc|D6|pc|CA|pc|C3|pg||mc|6| #define STRTOK sane_strtok_r(NULL, "|\n\r", &saveptr) static int board_parse_lin (window_board_t *win, char *line, FILE *f) { char *saveptr; char *tok; int card_nr = 0; setlocale (LC_NUMERIC, "C"); board *b = board_new (win->n_boards + 1); int board_filled = 0; board_window_append_board (win, b); /* global list of names for vugraph files */ char *name_arr[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; int name_n = 0; /* IMP/MP list */ char *mp_str = NULL; char *mp_ptr = NULL; do { for (tok = sane_strtok_r(line, "|", &saveptr); tok; tok = STRTOK) { /* single hand */ if (!strcmp(tok, "pn")) { /* SWNE */ tok = STRTOK; char *nameptr; char *name = sane_strtok_r(tok, ",", &nameptr); int i = 0; do { if (i < 4) g_string_printf(b->hand_name[seat_mod (i++) - 1], "%s", name); if (name_n < 8) name_arr[name_n++] = strdup(name); } while ((name = sane_strtok_r(NULL, ",", &nameptr))); } else if (!strcmp(tok, "md")) { /* make deal */ tok = STRTOK; if (*tok == '0') { printf ("md|0| (keep deal) mode not supported\n"); continue; } if (board_filled) { /* start new board */ card_nr = 0; board_filled = 0; b = board_new (win->n_boards + 1); board_window_append_board (win, b); /* initialize player names, required for vugraph files */ int i; for (i = 0; i < 4; i++) { g_string_printf(b->hand_name[seat_mod (i) - 1], "%s", name_arr[i + (tok[0] == 'c' ? 4 : 0)]); } } char *c; seat se = south; suit su = spade; b->dealer = seat_mod(*tok - '0' - 1); for (c = tok + 1; *c; c++) { int i; if ((i = parse_suit(*c)) != -1) { su = i; } else if ((i = parse_rank_char(*c)) != -1) { if (add_card(b, se, (su * 13) + i) != 1) goto error; } else if (*c == ',') { se = seat_mod(se + 1); } else { printf("Parse error: %s", tok); goto error; } } // TODO: end positions deal_random(b); /* compute east hand */ board_filled = 1; /* consider this board finished on next qx token */ } else if (!strcmp(tok, "ah")) { /* board name */ g_string_printf(b->name, "%s", STRTOK); } else if (!strcmp(tok, "qx")) { /* board number, o1, c1, o2, ... */ tok = STRTOK; if (board_filled) { /* first token in new vugraph board */ card_nr = 0; board_filled = 0; b = board_new (win->n_boards + 1); board_window_append_board (win, b); /* initialize player names, required for vugraph files */ int i; for (i = 0; i < 4; i++) { g_string_printf(b->hand_name[seat_mod (i) - 1], "%s", name_arr[i + (tok[0] == 'c' ? 4 : 0)]); } } if (strlen (tok) >= 1) g_string_printf(b->name, "%s %s", tok[0] == 'c' ? _("Closed") : (tok[0] == 'o' ? _("Open") : _("Board")), tok + 1); /* for now assume qx|| is present in all lin files with mp|| */ if (mp_str) { // FIXME: skip leading boards that were kibitzed but not played // (01-26-08-3.lin) char *score = mp_ptr ? sane_strtok_r (NULL, ",", &mp_ptr) : sane_strtok_r (mp_str, ",", &mp_ptr); b->mp[0] = score ? round (strtod (score, NULL) * 100.0) : 0; score = sane_strtok_r (NULL, ",", &mp_ptr); b->mp[1] = score ? round (strtod (score, NULL) * 100.0) : 0; } } else if (!strcmp(tok, "sv")) { tok = STRTOK; switch (*tok) { case '0': case 'o': b->vuln[0] = 0; b->vuln[1] = 0; break; case 'n': b->vuln[0] = 1; b->vuln[1] = 0; break; case 'e': b->vuln[0] = 0; b->vuln[1] = 1; break; case 'b': b->vuln[0] = 1; b->vuln[1] = 1; break; default: printf("Unknown vulnerability: sv|%s|\n", tok); } } else if (!strcmp(tok, "mb")) { /* mb|-ppp1Cp1Hp3Np4Dp4Hppp| */ tok = STRTOK; char *bidp = tok; char *al = strchr (bidp, '!'); if (al) { *al++ = '\0'; } do { int bid = parse_bid(&bidp); if (bid == -1) { printf("Invalid bid %s/%s\n", tok, bidp); break; } board_append_bid(b, bid, 1); if (al) { board_set_alert (b, al); al = NULL; } } while (*bidp); } else if (!strcmp(tok, "an")) { tok = STRTOK; board_set_alert (b, !strcmp (tok, "!") ? "" : tok); /* filter uninteresting ! */ } else if (!strcmp(tok, "pc")) { int c = parse_card(tok = STRTOK); if (c == -1) { printf("Invalid card %s\n", tok); continue; } if (card_nr < 52) b->played_cards[card_nr++] = c; } else if (!strcmp(tok, "mc")) { tok = STRTOK; // TODO: store number of (total) claimed tricks b->played_cards[card_nr] = claim_rest; // no card_nr increment here b->declarer_tricks = atoi (tok); /* vugraph file */ } else if (!strcmp(tok, "vg")) { /* match title */ tok = STRTOK; //printf ("Match title: %s\n", tok); if (win->title) free (win->title); if (win->subtitle) free (win->subtitle); if (win->team1) free (win->team1); if (win->team2) free (win->team2); char *t_ptr; char *title = sane_strtok_r (tok, ",", &t_ptr); if (title) win->title = strdup (title); char *subtitle = sane_strtok_r (NULL, ",", &t_ptr); if (subtitle) win->subtitle = strdup (subtitle); sane_strtok_r (NULL, ",", &t_ptr); /* scoring I IMPs P MPs B board-a-match */ sane_strtok_r (NULL, ",", &t_ptr); /* first board nr */ sane_strtok_r (NULL, ",", &t_ptr); /* last board nr */ char *team1 = sane_strtok_r (NULL, ",", &t_ptr); if (team1) win->team1 = strdup (team1); sane_strtok_r (NULL, ",", &t_ptr); /* carry-over score team 1 */ char *team2 = sane_strtok_r (NULL, ",", &t_ptr); if (team2) win->team2 = strdup (team2); /* carry-over score team 2 */ } else if (!strcmp(tok, "pw")) { /* more player names */ tok = STRTOK; //printf ("Players: %s\n", tok); } else if (!strcmp(tok, "bn")) { /* board numbers */ tok = STRTOK; //printf ("Board numbers: %s\n", tok); } else if (!strcmp(tok, "rs")) { /* results */ tok = STRTOK; //printf ("Results: %s\n", tok); } else if (!strcmp(tok, "mp")) { /* MP result */ tok = STRTOK; //printf ("Scores: %s\n", tok); mp_str = strdup (tok); } else if (!strcmp(tok, "nt")) { /* comment (new text) */ tok = STRTOK; //printf ("Comment: %s\n", tok); } else if (!strcmp(tok, "at")) { /* add text */ STRTOK; } else if (!strcmp(tok, "cr") || !strcmp(tok, "cg") || !strcmp(tok, "cb")) { /* color */ STRTOK; } else if (!strcmp(tok, "hc") || !strcmp(tok, "lc") || !strcmp(tok, "hs") || !strcmp(tok, "ls")) { STRTOK; /* hilight card, suit */ } else if (!strcmp(tok, "pg")) { STRTOK; /* page break, e.g. after trick or comment */ } else if (!strcmp(tok, "rh")) { /* reset heading */ STRTOK; } else if (!strcmp(tok, "sk")) { /* set kibitzed */ STRTOK; } else if (!strcmp(tok, "st")) { /* small text */ STRTOK; } else if (!strcmp(tok, "up")) { /* undo play */ tok = STRTOK; } else if (!*tok || *tok == '\n' || *tok == '\r') { /* empty token, hopefully end of line */ } else { printf("Unknown token '%s|%s|'\n", tok, STRTOK); } } } while (fgets(line, 1023, f)); int ret = 1; int i; goto ok; error: ret = 0; ok: for (i = 0; i < name_n; i++) free (name_arr[i]); if (mp_str) free (mp_str); setlocale (LC_NUMERIC, ""); return ret; } #undef STRTOK int board_parse_line(const char *line, board *b, char handsep, char suitsep) { const char *c = line; seat se = west; int su = spade; while (*c && *c != '\n') { int ra; if (*c == suitsep) { su--; if (su < 0) return 0; } else if (*c == handsep) { se++; su = spade; if (se > south) return 0; } else if ((ra = parse_rank_char(*c)) >= 0) { if (add_card(b, se, (su * 13) + ra) != 1) return 0; } else { printf ("parse error at char %ld: %s\n", c - line + 1, line); return 0; } c++; } return 1; } int board_load (window_board_t *win, char *fname) { FILE *f; char buf[1024]; if (! (f = fopen (fname, "r"))) return 0; if (fgets (buf, 1023, f) == NULL) return 0; int ret; if (!strncmp(buf, "pn|", 3) || !strncmp(buf, "vg|", 3) || !strncmp(buf, "st|", 3) || !strncmp(buf, "qx|", 3)) { ret = board_parse_lin (win, buf, f); } else { board *b = board_new (win->n_boards + 1); ret = board_parse_line(buf, b, ' ', '.'); if (ret) board_window_append_board (win, b); else { errno = EMEDIUMTYPE; board_free (b); } } int e = errno; fclose(f); if (ret) { if (win->filename) free (win->filename); win->filename = strdup (fname); } errno = e; return ret; } #define TRY_FREE(p) if (p) free (p) #define MOVE_PTR(dst, src) TRY_FREE (dst); dst = src; src = NULL /* tries opening a file in a temporary win structure, and displays errors if unable */ int board_load_popup (window_board_t *win, int append, char *filename) { int i; int ret = 0; window_board_t *win1 = calloc (1, sizeof (window_board_t)); if (board_load (win1, filename)) { if (append) { int n = win->n_boards; for (i = 0; i < win1->n_boards; i++) board_window_append_board (win, win1->boards[i]); if (win->n_boards > n) /* set to first new board */ win->cur = n; } else { MOVE_PTR (win->filename, win1->filename); MOVE_PTR (win->title, win1->title); MOVE_PTR (win->subtitle, win1->subtitle); MOVE_PTR (win->team1, win1->team1); MOVE_PTR (win->team2, win1->team2); for (i = 0; i < win->n_boards; i++) if (win->boards[i]) board_free (win->boards[i]); win->boards = win1->boards; win->n_boards = win1->n_boards; win->n_boards_alloc = win1->n_boards_alloc; win->cur = 0; } card_window_update(win->boards[win->cur]->dealt_cards); show_board(win->boards[win->cur], REDRAW_FULL); recently_used_add (filename); ret = 1; } else { GtkWidget *error = gtk_message_dialog_new (GTK_WINDOW (win->window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Error loading file '%s': %s"), filename, g_strerror (errno)); gtk_dialog_run (GTK_DIALOG (error)); gtk_widget_destroy (error); } TRY_FREE (win1->filename); TRY_FREE (win1->title); TRY_FREE (win1->subtitle); TRY_FREE (win1->team1); TRY_FREE (win1->team2); free (win1); return ret; } int board_load_dialog (window_board_t *win, int append) { GtkWidget *dialog; dialog = gtk_file_chooser_dialog_new (_("Open File"), GTK_WINDOW (win->window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); add_filters (GTK_FILE_CHOOSER (dialog)); if (win->filename) { char *cwd = g_path_get_dirname (win->filename); gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), cwd); g_free (cwd); gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), win->filename); } int ret = 0; while (ret == 0) { if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT) break; char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); ret = board_load_popup (win, append, filename); g_free (filename); } gtk_widget_destroy (dialog); return ret; } /* * saving */ GString *board_format_line(board *b, char handsep, char suitsep) { GString *out = g_string_new(NULL); int h; for (h = 1; h < 5; h++) { int c; for (c = 51; c >= 39; c--) if (b->dealt_cards[c] == h) g_string_append_printf(out, "%c", rank_char(RANK(c))); g_string_append_printf(out, "%c", suitsep); for (c = 38; c >= 26; c--) if (b->dealt_cards[c] == h) g_string_append_printf(out, "%c", rank_char(RANK(c))); g_string_append_printf(out, "%c", suitsep); for (c = 25; c >= 13; c--) if (b->dealt_cards[c] == h) g_string_append_printf(out, "%c", rank_char(RANK(c))); g_string_append_printf(out, "%c", suitsep); for (c = 12; c >= 0; c--) if (b->dealt_cards[c] == h) g_string_append_printf(out, "%c", rank_char(RANK(c))); if (h < 4) g_string_append_printf(out, "%c", handsep); } return out; } static char *lin_card_string(board *b) { static char out[39+16+4+1]; int i = 0, h; for (h = 4; h != 3; h = (h == 4 ? 1 : h + 1)) { int c; out[i++] = 'S'; for (c = 39; c < 52; c++) if (b->dealt_cards[c] == h) out[i++] = rank_char(RANK(c)); out[i++] = 'H'; for (c = 26; c < 39; c++) if (b->dealt_cards[c] == h) out[i++] = rank_char(RANK(c)); out[i++] = 'D'; for (c = 13; c < 26; c++) if (b->dealt_cards[c] == h) out[i++] = rank_char(RANK(c)); out[i++] = 'C'; for (c = 0; c < 13; c++) if (b->dealt_cards[c] == h) out[i++] = rank_char(RANK(c)); out[i++] = ','; } return out; } static char *lin_bid(card bid) { static char buf[3]; if (bid == bid_pass) return "p"; else if (bid == bid_x) return "d"; else if (bid == bid_xx) return "r"; snprintf(buf, sizeof (buf), "%d%c", LEVEL(bid), "CDHSN"[DENOM(bid)]); return buf; } static char * lin_contract (board *b) { static char buf[10]; if (b->level == 0) { snprintf (buf, sizeof (buf), "P"); } else { snprintf (buf, sizeof (buf), "%d%s%s%s%s", b->level, trump_str_char[b->trumps], seat_str[b->declarer], double_str[b->doubled], overtricks (b->declarer_tricks - b->level - 6)); } return buf; } static int board_save_lin(window_board_t *win, char *filename) { int cur; FILE *f; if ((f = fopen (filename, "w")) == NULL) return 0; setlocale (LC_NUMERIC, "C"); if (win->title) { fprintf (f, "vg|%s,%s,%s,%d,%d,%s,,%s,|\n", win->title, win->subtitle ? win->subtitle : "", "P", // FIXME 1, win->n_boards, win->team1 ? win->team1 : "", win->team2 ? win->team2 : ""); fprintf (f, "rs|"); for (cur = 0; cur < win->n_boards; cur++) { board *b = win->boards[cur]; fprintf (f, "%s,", lin_contract (b)); if (cur != win->n_boards - 1) fprintf (f, ","); } fprintf (f, "|\n"); fprintf (f, "pw|"); for (cur = 0; cur < win->n_boards; cur++) { board *b = win->boards[cur]; fprintf (f, "%s,%s,%s,%s", b->hand_name[south-1]->str, b->hand_name[west-1]->str, b->hand_name[north-1]->str, b->hand_name[east-1]->str); if (cur != win->n_boards - 1) fprintf (f, ","); } fprintf (f, "|\n"); fprintf (f, "mp|"); for (cur = 0; cur < win->n_boards; cur++) { board *b = win->boards[cur]; if (b->mp[0] == 0 && b->mp[1] == 0) fprintf (f, "--,--"); else { if (b->mp[0]) fprintf (f, "%.2f", b->mp[0] / 100.0); fprintf (f, ","); if (b->mp[1]) fprintf (f, "%.2f", b->mp[1] / 100.0); } if (cur != win->n_boards - 1) fprintf (f, ","); } fprintf (f, "|\n"); fprintf (f, "bn|"); for (cur = 0; cur < win->n_boards; cur++) { //board *b = win->boards[cur]; fprintf (f, "%d", cur + 1); // TODO: original number? if (cur != win->n_boards - 1) fprintf (f, ","); } fprintf (f, "|\n"); fprintf (f, "pg||\n"); } for (cur = 0; cur < win->n_boards; cur++) { board *b = win->boards[cur]; int i; if (win->n_boards > 1) fprintf (f, "qx|o%d|", cur + 1); // TODO: open/closed, real board number fprintf (f, "pn|%s,%s,%s,%s|", b->hand_name[south-1]->str, b->hand_name[west-1]->str, b->hand_name[north-1]->str, b->hand_name[east-1]->str); fprintf (f, "st||"); fprintf (f, "md|%d%s|", seat_mod(b->dealer + 1), lin_card_string(b)); // TODO: end positions fprintf (f, "rh||"); fprintf (f, "ah|%s|", b->name->str); fprintf (f, "sv|%c|", b->vuln[0] ? (b->vuln[1] ? 'b' : 'n') : (b->vuln[1] ? 'e' : 'o')); for (i = 0; i < b->n_bids; i++) { fprintf (f, "mb|%s|", lin_bid(b->bidding[i])); if (b->alerts[i]) fprintf (f, "an|%s|", *b->alerts[i] ? b->alerts[i] : "!"); } for (i = 0; i < 52; i++) { if (i % 4 == 0) fprintf (f, "pg||"); card c = b->played_cards[i]; if (c < 0) break; if (c == claim_rest) { fprintf (f, "mc|%d|", b->declarer_tricks >= 0 ? b->declarer_tricks : 0); break; } fprintf (f, "pc|%c%c|", "CDHS"[SUIT(c)], rank_char(RANK(c))); } fprintf (f, "pg||\n"); } int ret = 1, e = 0; if (ferror (f)) { ret = 0; e = errno; } fclose(f); errno = e; setlocale (LC_NUMERIC, ""); return ret; } int board_save(window_board_t *win, char *filename) { int len = strlen(filename); char *suffix = len > 4 ? filename + len - 4 : filename; int ret = 0; if (!strcmp(suffix, ".lin")) { ret = board_save_lin (win, filename); } else if (!strcmp(suffix, ".pbn")) { printf("pbn not yet implemented\n"); errno = EMEDIUMTYPE; } else { printf("unrecognized suffix %s\n", suffix); errno = EMEDIUMTYPE; } return ret; } int board_save_dialog (window_board_t *win, int save_as) { GtkWidget *dialog; if (!save_as && win->filename) { int ret = board_save(win, win->filename); if (! ret) { GtkWidget *error = gtk_message_dialog_new (GTK_WINDOW (win->window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Error saving file '%s': %s"), win->filename, g_strerror (errno)); gtk_dialog_run (GTK_DIALOG (error)); gtk_widget_destroy (error); } return ret; } dialog = gtk_file_chooser_dialog_new (_("Save File"), GTK_WINDOW (win->window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); add_filters (GTK_FILE_CHOOSER (dialog)); if (!win->filename) gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), _("hand.lin")); else gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), win->filename); retry_save: if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { char *filename; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); int ret = board_save (win, filename); if (ret) { if (win->filename) free (win->filename); win->filename = filename; show_board (CUR_BOARD, REDRAW_TITLE); recently_used_add (filename); } else { GtkWidget *error = gtk_message_dialog_new (GTK_WINDOW (win->window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Error saving file '%s': %s"), filename, g_strerror (errno)); g_free (filename); gtk_dialog_run (GTK_DIALOG (error)); gtk_widget_destroy (error); goto retry_save; } } gtk_widget_destroy (dialog); return 1; } /* open on bridgebase.com */ /* non-lin interface static char seat_lc[] = { 0, 'w', 'n', 'e', 's' }; static char vuln_lc[] = { 'o', 'n', 'e', 'b' }; */ void on_menu_file_web_activate () { board *b = CUR_BOARD; GString *url = g_string_new ("http://www.bridgebase.com/tools/handviewer.html?"); /* non-lin interface int h; g_string_append_printf (url, "d=%c", seat_lc[b->dealer]); g_string_append_printf (url, "&v=%c", vuln_lc[b->vuln[0] + 2 * b->vuln[1]]); g_string_append_printf (url, "&n=%d", b->n + 1); // TODO: real board number for (h = west; h <= south; h++) { if (*b->hand_name[h - 1]->str) g_string_append_printf (url, "&%cn=%s", seat_lc[h], b->hand_name[h - 1]->str); g_string_append_printf (url, "&%c=", seat_lc[h]); int s; for (s = club; s <= spade; s++) { g_string_append_printf (url, "%s", trump_str_char[s]); int c; for (c = s * 13 + 12; c >= (int)s * 13; c--) if (b->dealt_cards[c] == h) g_string_append_printf(url, "%c", rank_char(RANK(c))); } } if (b->n_bids) { g_string_append_printf (url, "&a="); int i; for (i = 0; i < b->n_bids; i++) g_string_append_printf (url, "%s", lin_bid (b->bidding[i])); } if (b->n_played_cards) { g_string_append_printf (url, "&p="); int i; for (i = 0; i < b->n_played_cards; i++) g_string_append_printf (url, "%s%c", trump_str_char[SUIT(b->played_cards[i])], rank_char(RANK(b->played_cards[i]))); if (b->played_cards[b->n_played_cards] = claim_rest) g_string_append_printf (url, "&c=%d", b->declarer_tricks); } */ int i; // TODO: merge with code from board_save_lin g_string_append_printf (url, "lin=pn|%s,%s,%s,%s|", b->hand_name[south-1]->str, b->hand_name[west-1]->str, b->hand_name[north-1]->str, b->hand_name[east-1]->str); g_string_append_printf (url, "st||"); g_string_append_printf (url, "md|%d%s|", seat_mod(b->dealer + 1), lin_card_string(b)); // TODO: end positions g_string_append_printf (url, "rh||"); g_string_append_printf (url, "ah|%s|", b->name->str); g_string_append_printf (url, "sv|%c|", b->vuln[0] ? (b->vuln[1] ? 'b' : 'n') : (b->vuln[1] ? 'e' : 'o')); for (i = 0; i < b->n_bids; i++) { g_string_append_printf (url, "mb|%s|", lin_bid(b->bidding[i])); if (b->alerts[i]) g_string_append_printf (url, "an|%s|", *b->alerts[i] ? b->alerts[i] : "!"); } for (i = 0; i < 52; i++) { if (i % 4 == 0) g_string_append_printf (url, "pg||"); card c = b->played_cards[i]; if (c < 0) break; if (c == claim_rest) { g_string_append_printf (url, "mc|%d|", b->declarer_tricks >= 0 ? b->declarer_tricks : 0); break; } g_string_append_printf (url, "pc|%c%c|", "CDHS"[SUIT(c)], rank_char(RANK(c))); } g_string_append_printf (url, "pg||\n"); printf ("%s\n", url->str); GError *error = NULL; gtk_show_uri (gdk_screen_get_default (), url->str, GDK_CURRENT_TIME, &error); if (error) { printf ("%s\n", error->message); g_error_free (error); } g_string_free (url, TRUE); } tenace-0.18/src/file.h000066400000000000000000000011211505733770300145650ustar00rootroot00000000000000#include "window_board.h" /* kfreebsd tweak */ #ifndef EMEDIUMTYPE #define EMEDIUMTYPE EINVAL #endif int board_parse_line(const char *line, board *b, char handsep, char suitsep); int board_load (window_board_t *win1, char *fname); int board_load_popup (window_board_t *win, int append, char *filename); int board_load_dialog (window_board_t *win, int append); GString *board_format_line(board *b, char handsep, char suitsep); int board_save (window_board_t *win, char *filename); int board_save_dialog (window_board_t *win, int save_as); #ifndef EMEDIUMTYPE #define EMEDIUMTYPE 124 #endif tenace-0.18/src/functions.c000066400000000000000000000173311505733770300156630ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2013 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include "bridge.h" #include "functions.h" const char *seat_str[] = {0, "W", "N", "E", "S"}; const char *trump_str[] = {"♣", "♦", "♥", "â™ ", "NT"}; /* 2 characters so Spade and South can be translated separately */ const char *trump_str_asc[] = {"Cl", "Di", "He", "Sp", "NT"}; const char *trump_str_char[] = {"C", "D", "H", "S", "N"}; const char *trump_color[] = {"#006600", "#ff8000", "#e60000", "#0000cc", "black"}; const char *double_str[] = {"", "X", "XX"}; int pos_score_for = 0; /* 0 = NS, 1 = declarer, 2 = current lead */ // TODO: implement char *rank_string (rank r) { static char *label[] = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}; return label[r]; } char rank_char (rank r) { static char label[] = {'2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A'}; return label[r]; } rank parse_rank_char (char c) { switch (tolower(c)) { case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return tolower(c) - '2'; case 't': case 'z': case '1': return card10; case 'j': case 'b': return cardJ; case 'q': case 'd': return cardQ; case 'k': return cardK; case 'a': return cardA; } return -1; } int parse_suit(char c) { switch (tolower(c)) { case 'n': return NT; break; case 's': return spade; break; case 'h': return heart; break; case 'd': return diamond; break; case 'c': return club; break; } return -1; } int parse_card(char *tok) { if (strlen(tok) != 2) return -1; int su = parse_suit(tok[0]); int ra = parse_rank_char(tok[1]); if (su == -1 || ra == -1) return -1; return 13 * su + ra; } int parse_bid(char **tok) { if (!strncasecmp (*tok, "p", 1) || !strncasecmp (*tok, "-", 1)) { *tok += 1; return bid_pass; } if (!strncasecmp (*tok, "xx", 2)) { *tok += 2; return bid_xx; } if (!strncasecmp (*tok, "r", 1)) { *tok += 1; return bid_xx; } if (!strncasecmp (*tok, "x", 1) || !strncasecmp (*tok, "d", 1)) { *tok += 1; return bid_x; } if (strlen (*tok) < 2) return -1; int alert = 0; if (strlen (*tok) >= 3 && *tok[2] == '!') // FIXME: can probably go alert = bid_alert; int le = *tok[0] - '0'; int su = parse_suit ((*tok)[1]); if (le < 1 || le > 7 || su == -1) return -1; *tok += alert ? strlen (*tok) : 2; return (5 * le + su) | alert; } char * card_string (card c) { static char s[8]; snprintf(s, sizeof (s), "%s%s", trump_str[SUIT(c)], rank_string(RANK(c))); return s; } char * card_string_color (card c) { static char s[60]; snprintf(s, sizeof (s), "%s%s", trump_color[SUIT(c)], trump_str[SUIT(c)], rank_string(RANK(c))); return s; } GString *bid_string (card c, int alert) { static GString *s = NULL; if (!s) s = g_string_new(NULL); if (c == bid_pass) { g_string_printf(s, "‒"); /* FIGURE DASH */ } else if (c == bid_x) { g_string_printf(s, _("X")); } else if (c == bid_xx) { g_string_printf(s, _("XX")); } else { g_string_printf(s, "%d%s", LEVEL(c), trump_color[DENOM(c)], _(trump_str[DENOM(c)])); } return s; } GString *hand_string (board *b, seat h) { static GString *s = NULL; if (!s) s = g_string_new(NULL); int c; g_string_printf(s, "â™ "); for (c = 51; c >= 39; c--) if (b->dealt_cards[c] == h) g_string_append_printf(s, "%s", rank_string(RANK(c))); g_string_append_printf(s, "\n♥"); for (c = 38; c >= 26; c--) if (b->dealt_cards[c] == h) g_string_append_printf(s, "%s", rank_string(RANK(c))); g_string_append_printf(s, "\n♦"); for (c = 25; c >= 13; c--) if (b->dealt_cards[c] == h) g_string_append_printf(s, "%s", rank_string(RANK(c))); g_string_append_printf(s, "\n♣"); for (c = 12; c >= 0; c--) if (b->dealt_cards[c] == h) g_string_append_printf(s, "%s", rank_string(RANK(c))); return s; } char * hand_suit_string (board *b, seat h, suit s) { static GString *str = NULL; if (!str) str = g_string_new(NULL); g_string_assign(str, ""); int c; for (c = s * 13 + 12; c >= (int)s * 13; c--) if (b->dealt_cards[c] == h) g_string_append_printf(str, "%s", rank_string(RANK(c))); return str->str; } char *contract_string(int level, suit trumps, seat declarer, int doubled) { if (level == 0) return _("PASS"); static char buf[20]; snprintf(buf, 20, "%d%s%s %s", level, _(trump_str[trumps]), doubled == 2 ? _("XX") : doubled == 1 ? _("X") : "", _(seat_str[declarer])); return buf; } char *contract_string_asc (int level, suit trumps, seat declarer, int doubled) { if (level == 0) return _("PASS"); static char buf[20]; snprintf(buf, 20, "%d%s%s %s", level, _(trump_str_asc[trumps]), doubled == 2 ? _("XX") : doubled == 1 ? _("X") : "", _(seat_str[declarer])); return buf; } char *vuln_string (board *b) { if (b->vuln[0] == 0) { if (b->vuln[1] == 0) /* none vulnerable */ return _("none"); else /* EW vulnerable */ return _("EW"); } else { if (b->vuln[1] == 0) /* EW */ /* NS vulnerable */ return _("NS"); else /* all vulnerable */ return _("all"); } } seat seat_mod(seat s) { return ((s + 3) % 4) + 1; } int seat_mask (seat s, seat filter) { switch (filter) { case seat_none: return 0; case seat_all: return 1; case north_south: return s == north || s == south; case east_west: return s == east || s == west; default: return s == filter; } } char *overtricks (int i) { static char buf[4]; if (i == 0) snprintf(buf, 3, "="); else snprintf(buf, 3, "%+d", i); return buf; } int score (int level, suit s, int doubled, int vuln, int tricks) { /* doubled: 0 / 1 (double) / 2 (redouble) / -1 (auto-double down contracts) */ int nv_double[] = { 100, 300, 500, 800, 1100, 1400, 1700, 2000, 2300, 2600, 2900, 3200, 3500 }; int v_double[] = { 200, 500, 800, 1100, 1400, 1700, 2000, 2300, 2600, 2900, 3200, 3500, 3800 }; if (tricks < level + 6) { if (doubled < 0) doubled = 1; if (doubled) { if (vuln) { return -v_double[level + 5 - tricks] * doubled; } else { return -nv_double[level + 5 - tricks] * doubled; } } return (tricks - level - 6) * 50 * (vuln + 1); } else { if (doubled < 0) doubled = 0; int trick_score = (s >= heart) ? 30 : 20; int base_score = (level * trick_score + (s == NT ? 10 : 0)) * (1 << doubled); int per_overtrick = doubled ? 100 * (vuln + 1) * doubled : trick_score; int overtrick_score = (tricks - level - 6) * per_overtrick; int game_bonus = vuln ? 450 : 250; return base_score + overtrick_score + 50 * (1 + doubled) + (base_score >= 100 ? game_bonus : 0) + (level >= 6 ? (vuln ? 750 : 500) : 0) + (level == 7 ? (vuln ? 750 : 500) : 0); } } char *score_string(int level, suit trumps, seat declarer, int doubled, int vuln, int tricks, seat lead) { static char buf[25]; int flip = 0; switch (pos_score_for) { case 0: /* NS */ flip = (declarer % 2) == 1 ? -1 : 1; break; case 1: /* declarer */ flip = 1; break; case 2: /* current lead */ flip = (declarer % 2) == (lead % 2) ? 1 : -1; break; } snprintf(buf, 24, "%s %s (%+d)", contract_string(level, trumps, declarer, doubled), overtricks(tricks - 6 - level), flip * score(level, trumps, doubled, vuln, tricks)); return buf; } tenace-0.18/src/functions.h000066400000000000000000000034341505733770300156670ustar00rootroot00000000000000#ifndef FUNCTIONS_H #define FUNCTIONS_H #ifdef HAVE_CONFIG_H # include #endif /* * Standard gettext macros. */ #ifdef ENABLE_NLS # include # undef _ # define _(String) dgettext (PACKAGE, String) # define Q_(String) g_strip_context ((String), gettext (String)) # ifdef gettext_noop # define N_(String) gettext_noop (String) # else # define N_(String) (String) # endif #else # define textdomain(String) (String) # define gettext(String) (String) # define dgettext(Domain,Message) (Message) # define dcgettext(Domain,Message,Type) (Message) # define bindtextdomain(Domain,Directory) (Domain) # define _(String) (String) # define Q_(String) g_strip_context ((String), (String)) # define N_(String) (String) #endif #include "bridge.h" extern const char *seat_str[]; extern const char *trump_str[]; extern const char *trump_str_asc[]; extern const char *trump_str_char[]; extern const char *trump_color[]; extern const char *double_str[]; char *rank_string (rank r); char rank_char (rank r); int parse_suit(char c); int parse_card(char *tok); int parse_bid(char **tok); rank parse_rank_char (char c); char *card_string (card c); char *card_string_color (card c); GString *bid_string (card c, int alert); GString *hand_string (board *b, seat h); char *hand_suit_string (board *b, seat h, suit s); char *contract_string(int level, suit trumps, seat declarer, int doubled); char *contract_string_asc (int level, suit trumps, seat declarer, int doubled); char *vuln_string (board *b); seat seat_mod(seat s); int seat_mask (seat s, seat filter); char *overtricks (int i); int score (int level, suit s, int doubled, int vuln, int tricks); char *score_string(int level, suit trumps, seat declarer, int doubled, int vuln, int tricks, seat lead); extern int pos_score_for; #endif tenace-0.18/src/main.c000066400000000000000000000055751505733770300146060ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2013 Christoph Berg * * 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. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include "bridge.h" #include "file.h" #include "functions.h" #include "options.h" #include "solve.h" #include "window_board.h" #include "window_card.h" #include "window_play.h" static char *xml_files[] = { PACKAGE ".ui", #ifndef _WIN32 PACKAGE_DATA_DIR "/" PACKAGE "/" PACKAGE ".ui", #endif }; int main (int argc, char *argv[]) { #ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); #endif gtk_set_locale (); gtk_init (&argc, &argv); init_solve(); srand(time(NULL)); win = malloc(sizeof(window_board_t)); char *xml_file = NULL; int i; for (i = 0; i < sizeof (xml_files); i++) { struct stat buf; if (stat (xml_files[i], &buf) != -1) { xml_file = xml_files[i]; g_debug ("Using interface file %s\n", xml_file); break; } } if (! xml_file) { fprintf (stderr, _("Could not find interface definition file: %s\n"), "tenace.ui"); exit (1); } GError *error = NULL; win->builder = gtk_builder_new (); if (! gtk_builder_add_from_file (win->builder, xml_file, &error)) { g_warning (_("Could not load builder file: %s"), error->message); g_error_free (error); exit (1); } gtk_builder_connect_signals (win->builder, NULL); board_window_init (win); read_config (win); board_window_apply_style (win); if (argc > 1) { char *fname = argv[1]; if (! g_path_is_absolute (argv[1])) { char *cwd = g_get_current_dir (); fname = g_build_filename (cwd, argv[1], NULL); g_free (cwd); } if (! board_load (win, fname)) { if (errno == EMEDIUMTYPE) { perror (fname); puts (_("Hint: tenace can only read files in .lin format")); } else perror (fname); exit (1); } recently_used_add (fname); if (! g_path_is_absolute (argv[1])) g_free (fname); } else { board_window_append_board (win, NULL); deal_random (win->boards[0]); /* show a random deal on startup */ } show_board(win->boards[0], REDRAW_FULL); card_window_update(win->boards[0]->dealt_cards); gtk_main (); write_config (win); return 0; } tenace-0.18/src/options.c000066400000000000000000000325531505733770300153510ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2012 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include "functions.h" #include "options.h" #include "window_board.h" #include "window_card.h" static char *entry_name[] = { "entry_west", "entry_north", "entry_east", "entry_south" }; static GtkWidget *window_options = NULL; static GtkListStore *board_store = NULL; /* set options window contents from program data */ void window_options_board_populate (void) /* no parameter as it is called from window_board.c */ { if (! window_options) return; board *b = CUR_BOARD; GtkWidget *w = get_widget ("entry_title"); if (b->name) gtk_entry_set_text (GTK_ENTRY (w), b->name->str); int i; for (i = 0; i < 4; i++) { w = get_widget (entry_name[i]); if (b->hand_name[i]) gtk_entry_set_text (GTK_ENTRY (w), b->hand_name[i]->str); } } void window_options_board_list_populate (void) /* no parameter as it is called from window_board.c */ { if (! window_options) return; assert (board_store); PROTECT_BEGIN; GtkWidget *w = get_widget ("board_list"); gtk_tree_view_set_model (GTK_TREE_VIEW (w), GTK_TREE_MODEL (board_store)); gtk_list_store_clear (board_store); GtkTreeIter iter; int i; GString *name = g_string_new (NULL); for (i = 0; i < win->n_boards; i++) { board *b = win->boards[i]; gtk_list_store_append (board_store, &iter); g_string_printf (name, "%s (%s)", b->name->str, contract_string (b->level, b->trumps, b->declarer, b->doubled)); gtk_list_store_set (board_store, &iter, 0, i + 1, 1, name->str, -1); } g_string_free (name, TRUE); PROTECT_END; } /* set program data from options window */ static void apply_options (GtkWidget *window_options) { /* Card display */ GtkWidget *w = get_widget ("show_played_cards"); win->show_played_cards = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)); w = get_widget ("show_as_cards"); int style = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)) ? HAND_DISPLAY_STYLE_CARDS : HAND_DISPLAY_STYLE_TEXT; window_card_set_style (style); w = get_widget ("svg_file"); gchar *fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w)); if (fname && strcmp (win->svg, fname)) { /* svg file changed */ if (win->svg) g_free (win->svg); win->svg = fname; } w = get_widget ("spinbutton_card_width"); int card_width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (w)); board_window_set_style (win, style, card_width); board_window_apply_style (win); /* Hands */ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (get_widget ("show_dd_all")))) { win->show_dd_scores = seat_all; } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (get_widget ("show_dd_ns")))) { win->show_dd_scores = north_south; } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (get_widget ("show_dd_ew")))) { win->show_dd_scores = east_west; } else { win->show_dd_scores = seat_none; } if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (get_widget ("show_hand_all")))) { win->show_hands = seat_all; } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (get_widget ("show_hand_ns")))) { win->show_hands = north_south; } else { win->show_hands = east_west; } /* Current board */ board *b = CUR_BOARD; w = get_widget ("entry_title"); g_string_printf (b->name, "%s", gtk_entry_get_text (GTK_ENTRY (w))); int i; for (i = 0; i < 4; i++) { w = get_widget (entry_name[i]); g_string_printf (b->hand_name[i], "%s", gtk_entry_get_text (GTK_ENTRY (w))); } /* Board list */ board **new_boards = malloc (win->n_boards_alloc * sizeof (board *)); //int new_cur = 0; i = 0; GtkTreeIter iter; gtk_tree_model_get_iter_first (GTK_TREE_MODEL (board_store), &iter); do { GValue val = { 0 }; gtk_tree_model_get_value (GTK_TREE_MODEL (board_store), &iter, 0, &val); int n = g_value_get_int (&val) - 1; assert (0 <= n && n < win->n_boards); new_boards[i] = win->boards[n]; /*if (n == win->cur) new_cur = i;*/ i++; } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (board_store), &iter)); free (win->boards); win->boards = new_boards; show_board(CUR_BOARD, REDRAW_HANDS | REDRAW_NAMES | REDRAW_CONTRACT | REDRAW_BOARD_LIST); } /* read config from disk */ int read_config (window_board_t *win) { char rcfile[1024]; snprintf (rcfile, sizeof (rcfile), "%s/%s", g_get_user_config_dir (), "tenacerc"); if (! g_key_file_load_from_file (win->keyfile, rcfile, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, NULL) && ! g_key_file_load_from_data_dirs (win->keyfile, "tenacerc", NULL, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, NULL) ) { return 0; } /* Card display */ char *p; if ((p = g_key_file_get_string (win->keyfile, "tenace", "show_as", NULL))) { win->hand_display_style = !strcmp (p, "cards") ? HAND_DISPLAY_STYLE_CARDS : HAND_DISPLAY_STYLE_TEXT; } else { win->hand_display_style = HAND_DISPLAY_STYLE_CARDS; } if (win->svg) g_free (win->svg); if ((p = g_key_file_get_string (win->keyfile, "tenace", "svg", NULL))) { win->svg = p; } else { win->svg = NULL; } int i; if ((i = g_key_file_get_integer (win->keyfile, "tenace", "card_width", NULL))) { win->card_width = i; } if ((i = g_key_file_get_boolean (win->keyfile, "tenace", "show_played_cards", NULL))) { win->show_played_cards = i; } /* Hands */ if ((p = g_key_file_get_string (win->keyfile, "tenace", "show_hands", NULL))) { if (! strcmp (p, "none")) win->show_hands = seat_none; else if (! strcmp (p, "ns")) win->show_hands = north_south; else if (! strcmp (p, "ew")) win->show_hands = east_west; else win->show_hands = seat_all; } if ((p = g_key_file_get_string (win->keyfile, "tenace", "show_dd", NULL))) { if (! strcmp (p, "none")) win->show_dd_scores = seat_none; else if (! strcmp (p, "ns")) win->show_dd_scores = north_south; else if (! strcmp (p, "ew")) win->show_dd_scores = east_west; else win->show_dd_scores = seat_all; } return 1; } /* write config to disk */ int write_config (window_board_t *win) { /* Card display */ g_key_file_set_string (win->keyfile, "tenace", "show_as", win->hand_display_style == HAND_DISPLAY_STYLE_CARDS ? "cards" : "text"); if (win->svg) g_key_file_set_string (win->keyfile, "tenace", "svg", win->svg); g_key_file_set_integer (win->keyfile, "tenace", "card_width", win->card_width); g_key_file_set_boolean (win->keyfile, "tenace", "show_played_cards", win->show_played_cards); /* Hands */ switch (win->show_hands) { case seat_all: g_key_file_set_string (win->keyfile, "tenace", "show_hands", "all"); break; case north_south: g_key_file_set_string (win->keyfile, "tenace", "show_hands", "ns"); break; case east_west: g_key_file_set_string (win->keyfile, "tenace", "show_hands", "ew"); break; default: g_key_file_set_string (win->keyfile, "tenace", "show_hands", "none"); }; switch (win->show_dd_scores) { case seat_all: g_key_file_set_string (win->keyfile, "tenace", "show_dd", "all"); break; case north_south: g_key_file_set_string (win->keyfile, "tenace", "show_dd", "ns"); break; case east_west: g_key_file_set_string (win->keyfile, "tenace", "show_dd", "ew"); break; default: g_key_file_set_string (win->keyfile, "tenace", "show_dd", "none"); }; struct stat buf; if (stat (g_get_user_config_dir (), &buf) == -1) mkdir (g_get_user_config_dir () #ifndef _WIN32 , 0777 #endif ); char rcfile[1024]; snprintf (rcfile, sizeof (rcfile), "%s/%s", g_get_user_config_dir (), "/tenacerc"); FILE *f; if (!(f = fopen(rcfile, "w"))) { perror (rcfile); return 0; } char *data = g_key_file_to_data (win->keyfile, NULL, NULL); fputs (data, f); fclose (f); g_free (data); return 1; } /* callbacks */ /* create options window and fill it */ G_MODULE_EXPORT void on_options1_activate (GtkMenuItem *menuitem, gpointer user_data) { if (window_options) return; window_options = get_widget ("window_options"); gtk_widget_show (window_options); /* Tab 1: Card display */ GtkWidget *w = get_widget ("show_played_cards"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), win->show_played_cards); w = get_widget (win->hand_display_style == HAND_DISPLAY_STYLE_CARDS ? "show_as_cards" : "show_as_text"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TRUE); w = get_widget ("svg_file"); if (win->svg) gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (w), win->svg); w = get_widget ("spinbutton_card_width"); GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (w)); gtk_adjustment_configure (adj, win->card_width, 10, 10000, 10, 100, 0); /* Tab 2: Hands */ switch (win->show_hands) { case seat_none: /* not yet implemented - is this useful? */ w = get_widget ("show_hand_none"); break; case east_west: w = get_widget ("show_hand_ew"); break; case north_south: w = get_widget ("show_hand_ns"); break; default: w = get_widget ("show_hand_all"); } gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TRUE); switch (win->show_dd_scores) { case seat_none: w = get_widget ("show_dd_none"); break; case east_west: w = get_widget ("show_dd_ew"); break; case north_south: w = get_widget ("show_dd_ns"); break; default: w = get_widget ("show_dd_all"); } gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TRUE); /* Tab 3: Current board */ window_options_board_populate (); /* Tab 4: Board list */ if (! board_store) { board_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING); } w = get_widget ("board_list"); gtk_tree_view_set_model (GTK_TREE_VIEW (w), GTK_TREE_MODEL (board_store)); GtkCellRenderer *renderer; GtkTreeViewColumn *column; renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ( _("#"), renderer, "markup", 0, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (w), column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ( _("Title"), renderer, "markup", 1, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (w), column); /* Tab 5: Generate */ w = get_widget ("options_generate_number"); adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (w)); gtk_adjustment_configure (adj, 1, 1, 10000, 1, 10, 0); window_options_board_list_populate (); } G_MODULE_EXPORT gboolean on_window_options_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { window_options = NULL; return FALSE; } G_MODULE_EXPORT void on_options_cancel_clicked (GtkButton *button, gpointer user_data) { gtk_widget_hide (GTK_WIDGET (window_options)); window_options = NULL; } G_MODULE_EXPORT void on_options_generate_go_clicked (GtkButton *button, gpointer user_data) { #ifndef _WIN32 GtkWidget *number = get_widget ("options_generate_number"); int n = gtk_spin_button_get_value (GTK_SPIN_BUTTON (number)); char nn[10]; snprintf (nn, sizeof(nn), "%d", n); GtkWidget *view = get_widget ("options_generate_entry"); GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); GtkTextIter start, end; gtk_text_buffer_get_iter_at_offset (buffer, &start, 0); gtk_text_buffer_get_iter_at_offset (buffer, &end, -1); char *text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); int wfd[2], rfd[2]; pid_t cpid; if (pipe(wfd) == -1 || pipe(rfd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } cpid = fork(); if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (cpid == 0) { /* Child reads from pipe */ close (wfd[1]); /* Close unused write end */ close (rfd[0]); dup2 (0, wfd[0]); dup2 (1, rfd[1]); execlp ("dealer", "dealer", "-v", "-p", nn, NULL); perror ("execlp"); _exit(EXIT_FAILURE); } else { close (wfd[0]); /* Close unused read end */ close (rfd[1]); if (write (wfd[1], text, strlen (text)) == -1) { perror ("write"); return; } close (wfd[1]); /* Reader will see EOF */ } int i; do { char buf[100]; i = read (rfd[0], buf, sizeof (buf)); buf[i == sizeof (buf) ? sizeof (buf) - 1 : i] = '\0'; puts (buf); } while (i > 0); close (rfd[0]); g_free (text); #endif } G_MODULE_EXPORT void on_options_apply_clicked (GtkButton *button, gpointer user_data) { apply_options (window_options); } G_MODULE_EXPORT void on_options_ok_clicked (GtkButton *button, gpointer user_data) { on_options_apply_clicked (button, user_data); gtk_widget_hide (GTK_WIDGET (window_options)); window_options = NULL; } tenace-0.18/src/options.h000066400000000000000000000020121505733770300153410ustar00rootroot00000000000000#include "window_board.h" /* hooks into options window */ void window_options_board_populate (void); void window_options_board_list_populate (void); /* rcfile handling */ int read_config (window_board_t *win); int write_config (window_board_t *win); /* callbacks */ void on_options1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_options_cancel_clicked (GtkButton *button, gpointer user_data); void on_options_apply_clicked (GtkButton *button, gpointer user_data); void on_options_ok_clicked (GtkButton *button, gpointer user_data); gboolean on_window_options_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data); tenace-0.18/src/print.c000066400000000000000000000400071505733770300150030ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2013 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include "functions.h" #include "window_board.h" static GtkPrintSettings *settings = NULL; /* standard printing */ #define STRIDE 0.25 * 72 #define L 1.0 * 72 #define C 2.0 * 72 #define R 3.0 * 72 #define T 1.0 * 72 #define M 2.0 * 72 #define B 3.0 * 72 static void draw_page (GtkPrintOperation *operation, GtkPrintContext *context, gint page_nr, gpointer user_data) { cairo_t *cr; cr = gtk_print_context_get_cairo_context (context); board *b = CUR_BOARD; cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size (cr, 12); cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); cairo_move_to (cr, 0.1 * 72, 0.2 * 72); cairo_show_text (cr, b->name->str); cairo_stroke (cr); cairo_move_to (cr, 0.1 * 72, 0.5 * 72); cairo_show_text (cr, contract_string(b->level, b->trumps, b->declarer, b->doubled)); cairo_stroke (cr); cairo_move_to (cr, C, T+1*STRIDE); cairo_show_text (cr, hand_suit_string (b, north, spade)); cairo_move_to (cr, C, T+2*STRIDE); cairo_show_text (cr, hand_suit_string (b, north, heart)); cairo_move_to (cr, C, T+3*STRIDE); cairo_show_text (cr, hand_suit_string (b, north, diamond)); cairo_move_to (cr, C, T+4*STRIDE); cairo_show_text (cr, hand_suit_string (b, north, club)); cairo_move_to (cr, L, M+1*STRIDE); cairo_show_text (cr, hand_suit_string (b, west, spade)); cairo_move_to (cr, L, M+2*STRIDE); cairo_show_text (cr, hand_suit_string (b, west, heart)); cairo_move_to (cr, L, M+3*STRIDE); cairo_show_text (cr, hand_suit_string (b, west, diamond)); cairo_move_to (cr, L, M+4*STRIDE); cairo_show_text (cr, hand_suit_string (b, west, club)); cairo_move_to (cr, R, M+1*STRIDE); cairo_show_text (cr, hand_suit_string (b, east, spade)); cairo_move_to (cr, R, M+2*STRIDE); cairo_show_text (cr, hand_suit_string (b, east, heart)); cairo_move_to (cr, R, M+3*STRIDE); cairo_show_text (cr, hand_suit_string (b, east, diamond)); cairo_move_to (cr, R, M+4*STRIDE); cairo_show_text (cr, hand_suit_string (b, east, club)); cairo_move_to (cr, C, B+1*STRIDE); cairo_show_text (cr, hand_suit_string (b, south, spade)); cairo_move_to (cr, C, B+2*STRIDE); cairo_show_text (cr, hand_suit_string (b, south, heart)); cairo_move_to (cr, C, B+3*STRIDE); cairo_show_text (cr, hand_suit_string (b, south, diamond)); cairo_move_to (cr, C, B+4*STRIDE); cairo_show_text (cr, hand_suit_string (b, south, club)); cairo_stroke (cr); cairo_move_to (cr, C, M); cairo_line_to (cr, C, R); cairo_line_to (cr, B, R); cairo_line_to (cr, B, C); cairo_close_path (cr); cairo_stroke (cr); } static void begin_print (GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data) { gtk_print_operation_set_n_pages (operation, 1); } G_MODULE_EXPORT void on_menu_print_activate (void) { GtkPrintOperation *print; GtkPrintOperationResult res; print = gtk_print_operation_new (); if (settings != NULL) gtk_print_operation_set_print_settings (print, settings); g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), NULL); g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), NULL); res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, GTK_WINDOW (win->window), NULL); if (res == GTK_PRINT_OPERATION_RESULT_APPLY) { if (settings != NULL) g_object_unref (settings); settings = g_object_ref (gtk_print_operation_get_print_settings (print)); } g_object_unref (print); } /* magic cards */ static void arrow (cairo_t *cr, int n, int background, seat dir, double size) { #define ARHEAD 0.0 #define ARWIDTH 0.2 cairo_save (cr); cairo_translate (cr, 0.5*size, 0.5*size); /* background box */ if (background) { cairo_set_source_rgb (cr, 0.7, 0.7, 0.7); cairo_move_to (cr, -0.5*size, -0.5*size); cairo_line_to (cr, 0.5*size, -0.5*size); cairo_line_to (cr, 0.5*size, 0.5*size); cairo_line_to (cr, -0.5*size, 0.5*size); cairo_close_path (cr); cairo_fill (cr); } /* arrow */ cairo_save (cr); cairo_rotate (cr, ((int)dir - 2) * M_PI_2); if (n % 2) cairo_set_source_rgb (cr, 0.7, 0.4, 0.4); /* red */ else cairo_set_source_rgb (cr, 0.4, 0.4, 0.7); /* blue */ cairo_move_to (cr, 0.0, -0.5*size); cairo_line_to (cr, 0.5*size, -ARHEAD*size); cairo_line_to (cr, ARWIDTH*size, -ARHEAD*size); cairo_line_to (cr, ARWIDTH*size, 0.5*size); cairo_line_to (cr, -ARWIDTH*size, 0.5*size); cairo_line_to (cr, -ARWIDTH*size, -ARHEAD*size); cairo_line_to (cr, -0.5*size, -ARHEAD*size); cairo_close_path (cr); cairo_fill (cr); cairo_restore (cr); /* board number */ char buf[8]; cairo_text_extents_t ext; snprintf (buf, sizeof (buf), "%d", n); cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cr, size / 2.0); cairo_text_extents (cr, buf, &ext); cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); cairo_move_to (cr, -ext.width / 2 - ext.x_bearing, ext.height/2); cairo_show_text (cr, buf); cairo_restore (cr); } static void cairo_clip_rectangle (cairo_t *cr, double x0, double y0, double x1, double y1) { cairo_move_to (cr, x0, y0); cairo_line_to (cr, x1, y0); cairo_line_to (cr, x1, y1); cairo_line_to (cr, x0, y1); cairo_close_path (cr); cairo_clip (cr); } /* row_height 0**************** border *xxx xxx xxx* arrow_size *xxx xxx xxx* * xxx xxx * * xxx xxx * col_width * arrow_columns * * TEXTSEP * * * * * * * * * *****************/ #define TEXTSEP 20.0 static struct magic_config_t { /* custom print settings */ /* widgets */ GtkSpinButton* magic_columns, * magic_rows; GtkToggleButton* magic_no_header, * magic_page_header, * magic_suit_header; GtkToggleButton* magic_mark_cards; GtkSpinButton* magic_from, * magic_to; GtkSpinButton* magic_border; GtkSpinButton* magic_horiz_margin, * magic_vert_margin; GtkSpinButton* magic_horiz_sep, * magic_vert_sep; /* data */ int columns, rows; int header; int mark_cards; int from, to; double border; double horiz_margin, vert_margin; double horiz_sep, vert_sep; /* metrics */ double col_width, row_height; int arrow_columns; double arrow_size; } mc; static void magic_card_half (cairo_t *cr, window_board_t *win, card c) { int n_boards = mc.to - mc.from + 1; int n; for (n = 0; n < n_boards; n++) { cairo_save (cr); int col = n % mc.arrow_columns; int row = n / mc.arrow_columns; cairo_translate (cr, col * mc.arrow_size + mc.border, row * mc.arrow_size + mc.border); board *b = win->boards[n + mc.from - 1]; arrow (cr, n + mc.from, (col + row) % 2, b->dealt_cards[c], mc.arrow_size); cairo_restore (cr); /* draw title */ cairo_text_extents_t ext; cairo_save (cr); cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size (cr, 8.0); cairo_clip_rectangle (cr, mc.border, mc.border, mc.row_height - mc.border, mc.col_width - mc.border); cairo_move_to (cr, mc.border, 0.5 * mc.col_width - 2.0); cairo_show_text (cr, win->title); cairo_text_extents (cr, win->title, &ext); /* clip subtitle to card width - title width */ cairo_clip_rectangle (cr, mc.border, mc.border, mc.row_height - ext.x_advance - mc.border - 4.0, mc.col_width - mc.border); cairo_move_to (cr, mc.border, 0.5 * mc.col_width + 8.0); cairo_show_text (cr, win->subtitle); cairo_stroke (cr); cairo_restore (cr); } } static void magic_card (cairo_t *cr, window_board_t *win, card c) { /* upper part */ magic_card_half (cr, win, c); /* lower part */ cairo_save (cr); cairo_translate (cr, mc.row_height, mc.col_width); cairo_rotate (cr, M_PI); magic_card_half (cr, win, c); cairo_restore (cr); } static void magic_draw_page (GtkPrintOperation *operation, GtkPrintContext *context, gint page_nr, gpointer user_data) { cairo_t *cr; cr = gtk_print_context_get_cairo_context (context); static int cc, print_head; if (page_nr == 0) { /* restart printing */ cc = 51; print_head = (mc.header > 0); } if (mc.header == 1) /* new page */ print_head = 1; cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); int r, c; for (c = 0; c < mc.columns; c++) { for (r = 0; r < mc.rows && cc >= 0; r++) { if (print_head && mc.header == 1) { /* page heading */ cairo_set_font_size (cr, 10.0); int r1, c1; int cc1 = cc; for (c1 = 0; c1 < mc.columns; c1++) { for (r1 = 0; r1 < mc.rows; r1++) { if ((c1 == 0 && r1 == 0) || cc1 < 0) continue; cairo_move_to (cr, c1 * (mc.col_width - 2.0*mc.border) / mc.columns + mc.border + mc.horiz_margin, r1 * (mc.row_height - 2.0*mc.border) / mc.rows + mc.border + mc.vert_margin + 10.0); cairo_show_text (cr, trump_str[SUIT(cc1)]); cairo_show_text (cr, rank_string (RANK(cc1))); cc1--; } } print_head = 0; continue; } if (print_head && mc.header == 2) { /* suit heading */ cairo_move_to (cr, (c + 0.5) * mc.col_width + c * mc.horiz_sep + mc.horiz_margin - 15.0, (r + 0.5) * mc.row_height + r * mc.vert_sep + mc.vert_margin + 30.0); cairo_set_font_size (cr, 40.0); cairo_show_text (cr, trump_str[SUIT(cc)]); print_head = 0; continue; } cairo_save (cr); cairo_translate (cr, /* lower left point */ c * mc.col_width + c * mc.horiz_sep + mc.horiz_margin, (r + 1) * mc.row_height + r * mc.vert_sep + mc.vert_margin); cairo_rotate (cr, -M_PI_2); /* rotate left */ magic_card (cr, win, cc); if (mc.mark_cards) { cairo_move_to (cr, 6, -2); cairo_set_font_size (cr, 10); cairo_show_text (cr, trump_str[SUIT(cc)]); cairo_show_text (cr, _(rank_string (RANK(cc)))); } cairo_restore (cr); cc--; /* next card */ if (RANK(cc) == cardA && mc.header == 2) print_head = 1; } } } static char *magic_xml_files[] = { "magic.ui", #ifndef _WIN32 PACKAGE_DATA_DIR "/" PACKAGE "/magic.ui", #endif }; #define get_magic_widget(x) (GTK_WIDGET (gtk_builder_get_object (builder, (x)))) static GObject * magic_custom_create (GtkPrintOperation *operation, gpointer user_data) { char *xml_file = NULL; int i; for (i = 0; i < sizeof (magic_xml_files); i++) { struct stat buf; if (stat (magic_xml_files[i], &buf) != -1) { xml_file = magic_xml_files[i]; break; } } if (! xml_file) { fprintf (stderr, _("Could not find interface definition file: %s\n"), "magic.ui"); exit (1); } GtkBuilder *builder; GError *error = NULL; builder = gtk_builder_new (); if (! gtk_builder_add_from_file (builder, xml_file, &error)) { g_warning (_("Could not load builder file: %s"), error->message); g_error_free (error); exit (1); } gtk_builder_connect_signals (builder, NULL); GtkWidget *table = get_magic_widget ("magic_options_table"); assert (table); mc.magic_rows = GTK_SPIN_BUTTON (get_magic_widget ("magic_rows")); mc.magic_columns = GTK_SPIN_BUTTON (get_magic_widget ("magic_columns")); mc.magic_no_header = GTK_TOGGLE_BUTTON (get_magic_widget ("magic_no_header")); mc.magic_page_header = GTK_TOGGLE_BUTTON (get_magic_widget ("magic_page_header")); mc.magic_suit_header = GTK_TOGGLE_BUTTON (get_magic_widget ("magic_suit_header")); mc.magic_mark_cards = GTK_TOGGLE_BUTTON (get_magic_widget ("magic_mark_cards")); mc.magic_from = GTK_SPIN_BUTTON (get_magic_widget ("magic_from")); gtk_spin_button_set_range (mc.magic_from, 1, win->n_boards); mc.magic_to = GTK_SPIN_BUTTON (get_magic_widget ("magic_to")); gtk_spin_button_set_range (mc.magic_to, 1, win->n_boards); gtk_spin_button_set_value (mc.magic_to, win->n_boards); mc.magic_border = GTK_SPIN_BUTTON (get_magic_widget ("magic_border")); mc.magic_horiz_margin = GTK_SPIN_BUTTON (get_magic_widget ("magic_horiz_margin")); mc.magic_vert_margin = GTK_SPIN_BUTTON (get_magic_widget ("magic_vert_margin")); mc.magic_horiz_sep = GTK_SPIN_BUTTON (get_magic_widget ("magic_horiz_sep")); mc.magic_vert_sep = GTK_SPIN_BUTTON (get_magic_widget ("magic_vert_sep")); g_object_ref (table); g_object_unref (builder); return (GObject *) table; } #define PTMM (72.0 / 25.4) static void magic_custom_apply (GtkPrintOperation *operation, GtkWidget *table, gpointer user_data) { mc.columns = gtk_spin_button_get_value_as_int (mc.magic_columns); mc.rows = gtk_spin_button_get_value_as_int (mc.magic_rows); mc.header = gtk_toggle_button_get_active (mc.magic_no_header) ? 0 : gtk_toggle_button_get_active (mc.magic_page_header) ? 1 : 2; mc.mark_cards = gtk_toggle_button_get_active (mc.magic_mark_cards); mc.from = gtk_spin_button_get_value_as_int (mc.magic_from); mc.to = gtk_spin_button_get_value_as_int (mc.magic_to); if (mc.to < mc.from) mc.to = mc.from; mc.border = PTMM * gtk_spin_button_get_value_as_float (mc.magic_border); mc.horiz_margin = PTMM * gtk_spin_button_get_value_as_float (mc.magic_horiz_margin); mc.vert_margin = PTMM * gtk_spin_button_get_value_as_float (mc.magic_vert_margin); mc.horiz_sep = PTMM * gtk_spin_button_get_value_as_float (mc.magic_horiz_sep); mc.vert_sep = PTMM * gtk_spin_button_get_value_as_float (mc.magic_vert_sep); } static void magic_begin_print (GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data) { if (mc.header == 0) { gtk_print_operation_set_n_pages (operation, ceil (52.0 / (mc.columns * mc.rows))); } else if (mc.header == 1) { gtk_print_operation_set_n_pages (operation, ceil (52.0 / (mc.columns * mc.rows - (mc.columns == 1 && mc.columns == 1 ? 0 : 1)))); } else { gtk_print_operation_set_n_pages (operation, ceil (56.0 / (mc.columns * mc.rows))); } gtk_print_operation_set_use_full_page (operation, TRUE); gtk_print_operation_set_show_progress (operation, TRUE); //gtk_print_operation_set_export_filename (operation, "foo"); mc.col_width = (gtk_print_context_get_width (context) - 2 * mc.horiz_margin - (mc.columns - 1) * mc.horiz_sep) / mc.columns; mc.row_height = (gtk_print_context_get_height (context) - 2 * mc.vert_margin - (mc.rows - 1) * mc.vert_sep) / mc.rows; /* find fitting number of arrow columns and corresponding arrow size */ int n_boards = mc.to - mc.from + 1; mc.arrow_columns = 0; do { mc.arrow_columns++; mc.arrow_size = (mc.row_height - 2*mc.border) / mc.arrow_columns; int arrow_rows = ceil ((double) n_boards / mc.arrow_columns); if (mc.arrow_size * arrow_rows <= mc.col_width/2.0 - mc.border - TEXTSEP/2.0) break; } while (mc.arrow_columns <= n_boards); } G_MODULE_EXPORT void on_menu_file_magic_activate (void) { GtkPrintOperation *print; GtkPrintOperationResult res; print = gtk_print_operation_new (); if (settings != NULL) gtk_print_operation_set_print_settings (print, settings); gtk_print_operation_set_custom_tab_label (print, _("Labels")); g_signal_connect (print, "begin_print", G_CALLBACK (magic_begin_print), NULL); g_signal_connect (print, "draw_page", G_CALLBACK (magic_draw_page), NULL); g_signal_connect (print, "create-custom-widget", G_CALLBACK (magic_custom_create), NULL); g_signal_connect (print, "custom-widget-apply", G_CALLBACK (magic_custom_apply), NULL); res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, GTK_WINDOW (win->window), NULL); if (res == GTK_PRINT_OPERATION_RESULT_APPLY) { if (settings != NULL) g_object_unref (settings); settings = g_object_ref (gtk_print_operation_get_print_settings (print)); } g_object_unref (print); } tenace-0.18/src/print.h000066400000000000000000000000761505733770300150120ustar00rootroot00000000000000int pdf_board (board *b); void on_menu_print_activate (void); tenace-0.18/src/solve.c000066400000000000000000000311211505733770300147740ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2018 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include /* system */ #include /* gettimeofday */ /* gnulib */ #include "../lib/nproc.h" #include "bridge.h" #include "file.h" /* board_format_line */ #include "functions.h" #include "window_board.h" /* statusbar */ void init_solve() { #if DDS_VERSION < 20101 #error "DDS minimum version required is 2.1.1" #endif /* cores to use */ int nproc = num_processors (NPROC_CURRENT_OVERRIDABLE); g_debug ("Using %d cores\n", nproc); SetMaxThreads(nproc); } static const char *dds_error[] = { NULL, /* -1 */ "Unknown fault", /* -2 */ "No of cards = 0", /* -3 */ "target > Number of tricks left", /* -4 */ "Duplicated cards", /* -5 */ "target < -1", NULL, /* -7 */ "target >13", /* -8 */ "solutions < 1", /* -9 */ "solutions > 3", /* -10 */ "No of cards > 52", /* -11 */ "For mode=2: target =-1 or solutions != 2", /* -12 */ "Suit or rank value out of range for deal.currentTrickSuit or deal.currentTrickRank", NULL, }; static const int card_bits[] = {0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000}; int run_dd = 0; void solve_statusbar(char *text) { static guint id = 0; if (!id) id = gtk_statusbar_get_context_id(win->statusbar, "solve_c"); gtk_statusbar_pop(win->statusbar, id); if (text) gtk_statusbar_push(win->statusbar, id, text); } static int dds_suit_conv(int s) /* works both ways */ { return s == NT ? NT : 3 - s; } /* void board_dds(board *b) { FILE *f; int i; char tr[] = { 'c', 'd', 'h', 's', 'n'}; char le[] = { 0, 'w', 'n', 'e', 's' }; if (!(f = fopen("dd", "w"))) { perror("dd"); return; } card lead = b->played_cards[b->n_played_cards - (b->n_played_cards % 4)]; seat leader = b->n_played_cards % 4 == 0 ? b->current_turn : b->dealt_cards[lead]; fprintf(f, "{ name=dd trumps=%c leader=%c ", tr[b->trumps], le[leader]); if (b->n_played_cards) fprintf(f, "played="); for (i = 0; i < b->n_played_cards; i++) { fprintf(f, "%c%c", tr[SUIT(b->played_cards[i])], tolower(rank_char(RANK(b->played_cards[i])))); if (i % 4 == 3) fprintf(f, "-"); else fprintf(f, "."); } fprintf(f, "}\n"); GString *out = board_format_line(b, ' ', '.'); fprintf(f, "%s\n", out->str); fclose(f); g_string_free(out, TRUE); system("dds dd&"); } */ static int score_to_tricks(board *b, int score) /* result: tricks for declarer */ { score += b->tricks[b->current_turn % 2]; if ((b->current_turn % 2) != (b->declarer % 2)) score = 13 - score; return score; } static int compute_dd_scores0 (board *b, dd_t *dd, card next) { int i, j, c; card old_next; struct deal d; struct futureTricks fut; char str[100]; if (!assert_board(b)) { /* FIXME: do not call this every time */ board_statusbar(_("Error: hands have different numbers of cards")); return 0; } if (next >= 0) { /* what-if mode: temporarily play this card */ old_next = b->played_cards[b->n_played_cards]; b->played_cards[b->n_played_cards] = c; b->n_played_cards++; } /* 0-3, 0=North, 1=East, 2=South, 3=West , Leading hand for the trick.*/ card lead = b->played_cards[b->n_played_cards - (b->n_played_cards % 4)]; seat leader = b->n_played_cards % 4 == 0 ? b->current_turn : b->dealt_cards[lead]; d.first = (leader + 2) % 4; d.trump = dds_suit_conv(b->trumps); for (i = 0; i < 3; i++) { d.currentTrickSuit[i] = 0; d.currentTrickRank[i] = 0; } for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) d.remainCards[i][j] = 0; } for (c = 0; c < 52; c++) { if (b->cards[c]) { d.remainCards[(b->cards[c] + 2) % 4][3 - SUIT(c)] |= card_bits[RANK(c)]; } dd->card_score[c] = -1; } for (i = 0; i < b->n_played_cards % 4; i++) { card c = b->played_cards[b->n_played_cards - (b->n_played_cards % 4) + i]; d.currentTrickSuit[i] = 3 - SUIT(c); d.currentTrickRank[i] = RANK(c) + 2; } if (next >= 0) { /* undo what-if change */ b->n_played_cards--; b->played_cards[b->n_played_cards] = old_next; } solve_statusbar(_("Thinking...")); while (gtk_events_pending ()) gtk_main_iteration(); i = SolveBoard(d, -1, 3, 1, &fut, 0); solve_statusbar(NULL); if (i <= 0) { snprintf(str, 99, "DD Error: %s", dds_error[-i]); board_statusbar(str); return 0; } //printf("solve nodes: %d cards: %d\n", fut.nodes, fut.cards); for (i = 0; i < fut.cards; i++) { c = 13 * (3 - fut.suit[i]) + fut.rank[i] - 2; //printf("card: %s = %d\n", card_string(c)->str, fut.score[i]); dd->card_score[c] = score_to_tricks(b, fut.score[i]); for (j = fut.rank[i] - 2; j >= 0; j--) { /* equals */ if (fut.equals[i] & card_bits[j]) { c = 13 * (3 - fut.suit[i]) + j; //printf(" %s = %d\n", card_string(c)->str, fut.score[i]); dd->card_score[c] = score_to_tricks(b, fut.score[i]); } } } dd->best_score = score_to_tricks(b, fut.score[0]); return 1; } /* (optionally!) compute DD scores per card and display optimal DD score in statusbar */ void compute_dd_scores (board *b, int compute) { if (b->n_played_cards == 52) return; if (compute && !b->current_dd) { b->current_dd = malloc (sizeof (dd_t)); assert (b->current_dd); if (!compute_dd_scores0(b, b->current_dd, -1)) return; } /* next card not defined (i.e. no prior undo), set it to the highest * optimal card */ // FIXME: 1st and 2nd hand low if (b->current_dd && seat_mask (b->current_turn, win->show_dd_scores) && b->played_cards[b->n_played_cards] == -1) { // FIXME: update when different card is played? int c; for (c = 51; c >= 0; c--) { if (b->current_dd->card_score[c] == b->current_dd->best_score) { b->played_cards[b->n_played_cards] = c; break; } } } if (b->current_dd) board_statusbar (score_string(b->level, b->trumps, b->declarer, b->doubled, b->vuln[b->declarer % 2], b->current_dd->best_score, b->current_turn)); } void invalidate_dd_scores (board *b) { if (b->current_dd) { free (b->current_dd); b->current_dd = NULL; } } /* // FIXME: reanimate void compute_next_dd_scores(board *b, card c) { if (!b->next_dd[c]) { b->next_dd[c] = malloc (sizeof (dd_t)); assert (b->next_dd[c]); compute_dd_scores0(b, b->next_dd[c], c); } } */ /**************************************************************************************** * Parscore computation * ****************************************************************************************/ #if 0 // pthreads version struct par_arr_chunk_t { int thread; board *b; int start; int end; }; static int compute_par_arr_chunk (struct par_arr_chunk_t *chunk) { int i, j, c; struct deal d; struct futureTricks fut; for (i = 0; i < 4; i++) { d.currentTrickSuit[i] = 0; d.currentTrickRank[i] = 0; for (j = 0; j < 4; j++) d.remainCards[i][j] = 0; } for (c = 0; c < 52; c++) { if (chunk->b->dealt_cards[c]) { d.remainCards[(chunk->b->dealt_cards[c] + 2) % 4][3 - SUIT(c)] |= card_bits[RANK(c)]; } } for (i = chunk->start; i < chunk->end; i++) { int t = 4 - (i / 4); /* NT .. Clubs */ int h = i % 4; //printf("thread %d: t %d; h %d ...\n", chunk->thread, t, h); //g_string_append_printf(str, " %s ", _(trump_str[t])); // for (h = 0; h < 4; h++) { //g_string_append_printf(str, "%s", _(seat_str[h + 1])); //solve_statusbar(str->str); //while (gtk_events_pending ()) //gtk_main_iteration(); d.trump = dds_suit_conv(t); d.first = h; j = SolveBoard(d, -1 /* target */, 1 /* solutions */, 1 /* legacy: h == 0 ? 1 : 2 */ /* mode */, &fut, chunk->thread); if (j <= 0) { //g_string_printf(str, "DD Error: %s", dds_error[-j]); //solve_statusbar(NULL); //board_statusbar(str->str); //g_string_free(str, TRUE); return 0; } chunk->b->par_arr[h][t] = 13 - fut.score[0]; /* we could store (one) optimum lead here */ //printf("thread %d: t %d; h %d = %d\n", chunk->thread, t, h, 13 - fut.score[0]); // } } } #endif static int compute_par_arr(board *b) { //struct timeval tv1, tv2; board_statusbar (_("Thinking...")); while (gtk_events_pending ()) gtk_main_iteration (); /* pthreads version int nproc = num_processors (NPROC_CURRENT_OVERRIDABLE); //printf ("nproc: %d\n", nproc); gettimeofday (&tv1, NULL); struct par_arr_chunk_t *chunk = malloc (sizeof (struct par_arr_chunk_t) * nproc); pthread_t *thread = malloc (sizeof (pthread_t) * nproc); int i; for (i = 0; i < nproc; i++) { chunk[i].thread = i; chunk[i].b = b; chunk[i].start = i * 20 / nproc; chunk[i].end = (i + 1) * (20 / nproc); //printf ("chunk %d: %d..%d\n", i, chunk[i].start, chunk[i].end); //compute_par_arr_chunk (&chunk[i]); int rc = pthread_create(&thread[i], NULL, compute_par_arr_chunk, (void *)&chunk[i]); if (rc) { printf ("ERROR; return code from pthread_create() is %d\n", rc); exit (-1); } } for (i = 0; i < nproc; i++) { //printf ("joining thread %d\n", i); int rc = pthread_join (thread[i], NULL); if (rc) { printf("ERROR; return code from pthread_join() is %d\n", rc); exit(-1); } } free (chunk); free (thread); */ int i, j, c; struct ddTableDeal d; struct ddTableResults ddresults; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) d.cards[i][j] = 0; } for (c = 0; c < 52; c++) { if (b->dealt_cards[c]) { d.cards[(b->dealt_cards[c] + 2) % 4][3 - SUIT(c)] |= card_bits[RANK(c)]; } } int result = CalcDDtable (d, &ddresults); if (result != 1) { char str[100]; snprintf(str, 99, "DD Error: %s", dds_error[-result]); solve_statusbar(str); return 0; } int h, t; for (h = 0; h < 4; h++) { for (t = club; t <= NT; t++) { b->par_arr[(h+1) % 4][dds_suit_conv(t)] = ddresults.resTable[t][h]; } } solve_statusbar(NULL); while (gtk_events_pending ()) gtk_main_iteration(); /*gettimeofday (&tv2, NULL); printf ("compute_par_arr: %dms\n", 1000 * (tv2.tv_sec - tv1.tv_sec) + (tv2.tv_usec - tv1.tv_usec) / 1000);*/ return 1; } void parscore(board *b) { int l, t; if (b->par_score == -1) { if (b->n_dealt_cards != 52) { board_statusbar (_("Error: board must be fully dealt")); return; } if (!compute_par_arr(b)) return; } b->par_score = 0; for (l = 1; l <= 7; l++) { for (t = club; t <= NT; t++) { int ha = north, tr = b->par_arr[1][t]; if (b->par_arr[3][t] > b->par_arr[1][t]) { ha = south; tr = b->par_arr[3][t]; } int sc = score(l, t, -1, b->vuln[0], tr); //printf("%s %d\n", contract_string(l, t, north, 0), sc); if (sc > b->par_score) { b->par_score = sc; b->par_level = l; b->par_suit = t; b->par_dec = ha; b->par_tricks = tr; //printf(" new par\n"); } ha = east, tr = b->par_arr[2][t]; if (b->par_arr[0][t] > b->par_arr[2][t]) { ha = west; tr = b->par_arr[0][t]; } sc = -score(l, t, -1, b->vuln[1], tr); //printf("%s %d\n", contract_string(l, t, east, 0), sc); if (sc < b->par_score) { b->par_score = sc; b->par_level = l; b->par_suit = t; b->par_dec = ha; b->par_tricks = tr; //printf(" new par\n"); } } } } char * par_label (board *b) { /* parscore is pass */ GString *par = g_string_new(_("Par: PASS (0)\n")); if (b->par_score != 0) g_string_printf(par, _("Par: %s %s (%+d)\n"), contract_string(b->par_level, b->par_suit, b->par_dec, b->par_tricks < b->par_level + 6), overtricks(b->par_tricks - b->par_level - 6), b->par_score); int t; for (t = 4; t >= 0; t--) { g_string_append_printf(par, "%s: ", _(trump_str[t])); if (b->par_arr[1][t] == b->par_arr[3][t]) /* parscore for NS */ g_string_append_printf(par, "%s%d ", _("NS"), b->par_arr[1][t]); else /* separate parscore for N and S */ g_string_append_printf(par, "%s%d%s%d ", _("N"), b->par_arr[1][t], _("S"), b->par_arr[3][t]); if (b->par_arr[0][t] == b->par_arr[2][t]) /* parscore for EW */ g_string_append_printf(par, "%s%d", _("EW"), b->par_arr[2][t]); else /* separate parscore for E and W */ g_string_append_printf(par, "%s%d%s%d", _("E"), b->par_arr[2][t], _("W"), b->par_arr[0][t]); if (t > 0) g_string_append_printf(par, "\n"); } char *ret = strdup (par->str); g_string_free(par, TRUE); return ret; } tenace-0.18/src/solve.h000066400000000000000000000004061505733770300150030ustar00rootroot00000000000000#include "bridge.h" void init_solve(); void solve_statusbar(char *text); //void board_dds(board *b); void compute_dd_scores (board *b, int compute); void invalidate_dd_scores (board *b); void parscore(board *b); char *par_label (board *b); extern int run_dd; tenace-0.18/src/unused.c000066400000000000000000000011061505733770300151470ustar00rootroot00000000000000/* some strings not translated elsewhere */ static void translate_me () { /* West; translation should be a single letter */ _("W"); /* North; translation should be a single letter */ _("N"); /* East; translation should be a single letter */ _("E"); /* South; translation should be a single letter */ _("S"); _("NT"); /* Spades; translation should be a single letter */ _("Sp"); /* Hearts; translation should be a single letter */ _("He"); /* Diamonds; translation should be a single letter */ _("Di"); /* Clubs; translation should be a single letter */ _("Cl"); } tenace-0.18/src/window_bids.c000066400000000000000000000121141505733770300161550ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2009 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include "bridge.h" #include "functions.h" #include "window_board.h" static GtkWidget *window_bids = 0; static void bid_clicked (GtkWidget *lab, int *bid) { static GtkWidget *alert_entry = NULL; if (! alert_entry) alert_entry = get_widget ("alert_entry"); board *b = CUR_BOARD; int ret = board_append_bid (b, *bid, 1); if (!ret) return; PROTECT_BEGIN; const char *alert = gtk_entry_get_text (GTK_ENTRY (alert_entry)); if (*alert) { board_set_alert (b, !strcmp (alert, "!") ? "" : alert); gtk_entry_set_text (GTK_ENTRY (alert_entry), ""); } show_board (b, (ret == 2 ? REDRAW_FULL : REDRAW_BIDDING) | REDRAW_BIDDING_SCROLL); if (ret == 2) { char buf[50]; snprintf (buf, sizeof (buf), _("Contract set to %s"), contract_string (b->level, b->trumps, b->declarer, b->doubled)); board_statusbar (buf); } PROTECT_END; } void window_bids_init () { if (window_bids) return; static int pass = bid_pass, x = bid_x, xx = bid_xx; static int bid[35]; window_bids = get_widget ("window_bids"); gtk_widget_show (window_bids); GtkTable *bids_table = GTK_TABLE(get_widget ("bids_table")); assert (bids_table); GtkWidget *lab; lab = gtk_button_new_with_label (_("PASS")); gtk_table_attach (bids_table, lab, 0, 3, 0, 1, GTK_FILL, 0, 0, 0); g_signal_connect (lab, "clicked", G_CALLBACK (bid_clicked), &pass); lab = gtk_button_new_with_label (_("X")); gtk_table_attach (bids_table, lab, 3, 4, 0, 1, GTK_FILL, 0, 0, 0); g_signal_connect (lab, "clicked", G_CALLBACK (bid_clicked), &x); lab = gtk_button_new_with_label (_("XX")); gtk_table_attach (bids_table, lab, 4, 5, 0, 1, GTK_FILL, 0, 0, 0); g_signal_connect (lab, "clicked", G_CALLBACK (bid_clicked), &xx); int d, l; for (l = 1; l <= 7; l++) { for (d = 0; d <= 4; d++) { GString *b = bid_string (5 * l + d, 0); lab = gtk_button_new_with_label (_(b->str)); gtk_label_set_use_markup (GTK_LABEL (gtk_bin_get_child (GTK_BIN (lab))), TRUE); gtk_table_attach(bids_table, lab, d, d+1, l, l+1, GTK_FILL, 0, 0, 0); bid[5 * (l - 1) + d] = 5 * l + d; g_signal_connect (lab, "clicked", G_CALLBACK (bid_clicked), bid + (5 * (l - 1) + d)); } } gtk_widget_show_all (window_bids); } void window_bids_delete (void) { if (!window_bids) return; gtk_widget_hide (window_bids); window_bids = 0; } G_MODULE_EXPORT void on_bid_clear_clicked (GtkToolButton *toolbutton, gpointer user_data) { board *b = CUR_BOARD; board_clear_bidding (b); show_board(b, REDRAW_BIDDING); } G_MODULE_EXPORT void on_bid_undo_clicked (GtkToolButton *toolbutton, gpointer user_data) { board *b = CUR_BOARD; if (b->n_bids) { board_remove_bid (b); } show_board(b, REDRAW_BIDDING | REDRAW_BIDDING_SCROLL); } #define TRY(x) { if (!(x)) goto end; } G_MODULE_EXPORT void on_bid_set_contract_clicked (GtkToolButton *toolbutton, gpointer user_data) { int i; board *b = CUR_BOARD; seat cur_seat = seat_mod (b->dealer + b->n_bids); int passes = (b->declarer - cur_seat) % 4; for (i = (b->n_bids + passes - 2) % 4; i < b->n_bids; i += 4) if (b->bidding[i] >= 5 && DENOM (b->bidding[i]) == b->trumps) { board_statusbar (_("Suit was already bid from wrong side")); goto end; } for (i = 0; i < passes; i++) TRY (board_append_bid (b, bid_pass, 0)); TRY (board_append_bid (b, 5 * b->level + b->trumps, 0)); if (b->doubled) TRY (board_append_bid (b, bid_x, 0)); if (b->doubled == bid_xx) TRY (board_append_bid (b, bid_xx, 0)); TRY (board_append_bid (b, bid_pass, 0)); TRY (board_append_bid (b, bid_pass, 0)); TRY (board_append_bid (b, bid_pass, 0)); end: show_board(b, REDRAW_BIDDING | REDRAW_BIDDING_SCROLL); } G_MODULE_EXPORT gboolean on_window_bids_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { PROTECT_BEGIN_BOOL; GtkCheckMenuItem *menuitem = GTK_CHECK_MENU_ITEM (get_widget ("bids1")); gtk_check_menu_item_set_active (menuitem, FALSE); window_bids_delete (); PROTECT_END; return FALSE; } G_MODULE_EXPORT void on_bids1_activate (GtkMenuItem *menuitem, gpointer user_data) { if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) window_bids_init (); else window_bids_delete (); } tenace-0.18/src/window_bids.h000066400000000000000000000016111505733770300161620ustar00rootroot00000000000000void window_bids_init (void); void window_bids_delete (void); void on_bid_clear_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_bid_undo_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_bid_set_contract_clicked (GtkToolButton *toolbutton, gpointer user_data); gboolean on_window_bidding_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data); gboolean on_window_bids_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data); tenace-0.18/src/window_board.c000066400000000000000000000606511505733770300163340ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2013 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include #include "../handdisplay/hand_display.h" #include "window_board.h" #include "file.h" #include "functions.h" #include "options.h" #include "solve.h" #include "window_card.h" #include "window_line_entry.h" #include "window_play.h" /* default paths */ static char *svg_files[] = { "bonded.svg", "paris.svg", "/usr/share/aisleriot/cards/bonded.svgz", /* jessie: aisleriot package */ "/usr/share/aisleriot/cards/bonded.svg", /* wheezy: aislerot package */ "/usr/share/gnome-games-common/cards/bonded.svg", /* lenny */ "/usr/share/pixmaps/gnome-games-common/cards/bonded.svg", /* etch */ "/usr/share/aisleriot/cards/paris.svgz", /* jessie: gnome-cards-data package */ "/usr/share/aisleriot/cards/paris.svg", /* wheezy: gnome-cards-data package */ "/usr/share/gnome-games-common/cards/paris.svg", /* lenny */ "/usr/share/pixmaps/gnome-games-common/cards/paris.svg", /* etch */ "/usr/share/gnome-games-common/cards/gnomangelo_bitmap.svg", /* only file in gnome-cards-data in squeeze */ NULL }; window_board_t *win; // FIXME static? int protect = 0; static GdkColor bidding_non_vuln = { 0, 0.8*65535, 0.8*65535, 0.8*65535 }; static GdkColor bidding_vuln = { 0, 0.8*65535, 0, 0 }; static void board_menu_select (GtkWidget *menuitem, int *n) { PROTECT_BEGIN; if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) PROTECT_RETURN; if (*n == win->cur) PROTECT_RETURN; win->cur = *n; //printf ("jump to %d\n", *n); assert (0 <= *n && *n < win->n_boards); show_board (win->boards[*n], REDRAW_BOARD); PROTECT_END; } static void board_window_rebuild_board_menu (window_board_t *win) { if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (win->board_menu))) gtk_menu_item_remove_submenu (GTK_MENU_ITEM (win->board_menu)); GtkWidget *submenu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (win->board_menu), submenu); /* build array of board numbers for use in menu callback */ if (win->board_numbers) free(win->board_numbers); win->board_numbers = malloc (win->n_boards_alloc * sizeof (int)); assert(win->board_numbers); int i; GSList *group = NULL; for (i = 0; i < win->n_boards; i++) { board *b = win->boards[i]; GString *label = g_string_new (b->name->str); g_string_append_printf (label, " (%s)", contract_string (b->level, b->trumps, b->declarer, b->doubled)); GtkWidget *menuitem = gtk_radio_menu_item_new_with_label (group, label->str); g_string_free (label, TRUE); group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem)); if (i == win->cur) gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), TRUE); win->board_numbers[i] = i; g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (board_menu_select), &(win->board_numbers[i])); /* pointer to array index */ gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem); gtk_widget_show (menuitem); } } static void board_set_player_name (GtkWidget *w, seat s, int dealer, int vuln, int declarer, int current, char *name) { GString *str = g_string_new (NULL); g_string_printf(str, " %s %s ", vuln ? "#cc0000" : "#00cc00", dealer ? " weight=\"bold\"" : "", _(seat_str[s]), declarer ? " weight=\"bold\"" : "", current ? " background=\"#ffa000\"" : "", name); gtk_label_set_markup((GtkLabel*) w, str->str); g_string_free (str, TRUE); } static void bidding_update (window_board_t *win, board *b, int scroll) { gtk_list_store_clear (win->bidding_store); int i; for (i = 0; i < 2; i++) { GdkColor *color = b->vuln[!i] ? &bidding_vuln : &bidding_non_vuln; gtk_widget_modify_bg (win->bidding_header[i], GTK_STATE_NORMAL, color); gtk_widget_modify_bg (win->bidding_header[i+2], GTK_STATE_NORMAL, color); } /* for (i = 0; i < 4; i++) { if (b->hand_name[i]) gtk_label_set_text (GTK_LABEL (win->bidding_label[i]), b->hand_name[i]->str); } */ int col = b->dealer - 1; GtkTreeIter iter; if (!b->n_bids) { gtk_list_store_append (win->bidding_store, &iter); gtk_list_store_set (win->bidding_store, &iter, 2 * col, "•", 2 * col + 1, _("Dealer"), -1); return; } int last_col = 5; for (i = 0; i < b->n_bids; i++) { char buf[100]; if (last_col > col) gtk_list_store_append (win->bidding_store, &iter); snprintf (buf, sizeof (buf), "%s%s", bid_string(b->bidding[i], b->alerts[i] != NULL)->str, b->alerts[i] ? (*b->alerts[i] ? _("*") : _("!")) : ""); gtk_list_store_set (win->bidding_store, &iter, 2 * col, buf, 2 * col + 1, b->alerts[i], -1); last_col = col; col = (col + 1) % 4; } if (scroll) { GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (win->bidding_store), &iter); gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (win->bidding), path, NULL, FALSE, 0.0, 0.0); gtk_tree_path_free (path); } } void show_board (board *b, redraw_t redraw) { GtkWidget *w; GString *str = g_string_new(NULL); assert (b); if (redraw & REDRAW_BOARD_LIST) { board_window_rebuild_board_menu (win); window_options_board_list_populate (); } if (redraw & (REDRAW_TITLE | REDRAW_CONTRACT)) { g_string_printf(str, "Tenace - %s (%s)", b->name->str, contract_string_asc (b->level, b->trumps, b->declarer, b->doubled)); if (win->title) { g_string_append_printf (str, " - %s", win->title); if (win->subtitle) g_string_append_printf (str, " - %s", win->subtitle); if (win->team1 && win->team2) g_string_append_printf (str, _(" - %s vs. %s"), win->team1, win->team2); } else if (win->filename) { char *fname = win->filename; if (strrchr(fname, '/')) fname = strrchr(fname, '/') + 1; g_string_append_printf (str, " - %s", fname); } gtk_window_set_title(GTK_WINDOW(win->window), str->str); } if (redraw & REDRAW_CONTRACT) { w = get_widget ("label_board"); g_string_printf(str, "%s\n%s\n%s: %s\n%s: %s", b->name->str, contract_string(b->level, b->trumps, b->declarer, b->doubled), _("Dealer"), _(seat_str[b->dealer]), _("Vulnerable"), vuln_string(b)); gtk_label_set_text((GtkLabel*) w, str->str); char *dealermenu[] = { 0, "dealer_west1", "dealer_north1", "dealer_east1", "dealer_south1"}; w = get_widget (dealermenu[b->dealer]); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE); char *declarermenu[] = { 0, "declarer_west1", "declarer_north1", "declarer_east1", "declarer_south1"}; w = get_widget (declarermenu[b->declarer]); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE); char *levelmenu[] = { "level1" /* PASS */, "level1", "level2", "level3", "level4", "level5", "level6", "level7" }; w = get_widget (levelmenu[b->level]); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE); char *suitmenu[] = { "contract_clubs1", "contract_diamonds1", "contract_hearts1", "contract_spades1", "contract_no_trump1" }; w = get_widget (suitmenu[b->trumps]); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE); char *doublemenu[] = { "level_doubled0", "level_doubled1", "level_redoubled1" }; w = get_widget (doublemenu[b->doubled]); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE); char *vulnmenu[] = { "vuln_none", "vuln_ns", "vuln_ew", "vuln_all" }; w = get_widget (vulnmenu[2 * b->vuln[1] + b->vuln[0]]); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE); window_options_board_populate (); } if (redraw & REDRAW_NAMES) { w = get_widget ("label_west"); board_set_player_name (w, west, b->dealer == west, b->vuln[1], b->declarer == west, b->current_turn == west, b->hand_name[0]->str); w = get_widget ("label_north"); board_set_player_name (w, north, b->dealer == north, b->vuln[0], b->declarer == north, b->current_turn == north, b->hand_name[1]->str); w = get_widget ("label_east"); board_set_player_name (w, east, b->dealer == east, b->vuln[1], b->declarer == east, b->current_turn == east, b->hand_name[2]->str); w = get_widget ("label_south"); board_set_player_name (w, south, b->dealer == south, b->vuln[0], b->declarer == south, b->current_turn == south, b->hand_name[3]->str); window_options_board_populate (); } if (redraw & REDRAW_TRICKS) { w = get_widget ("label_tricks"); g_string_printf(str, _("NS: %d\nEW: %d"), b->tricks[0], b->tricks[1]); gtk_label_set_markup((GtkLabel*) w, str->str); } if (redraw & REDRAW_PAR) { w = get_widget ("par_label"); if (b->par_score == -1) { gtk_label_set_text (GTK_LABEL (w), ""); } else { char *par = par_label (b); gtk_label_set_markup(GTK_LABEL (w), par); free (par); } } if (redraw & REDRAW_HANDS) { int i, c; /* hands */ int next_card = b->played_cards[b->n_played_cards]; for (i = west; i <= south; i++) { for (c = 51; c >= 0; c--) { int has = i == b->cards[c]; int had = i == b->dealt_cards[c]; int color; if (seat_mask (i, win->show_hands)) color = has ? (c == next_card ? HAND_DISPLAY_HILIGHT_CARD : HAND_DISPLAY_CARD) : (had && win->show_played_cards ? HAND_DISPLAY_OLD_CARD : HAND_DISPLAY_NO_CARD); else color = HAND_DISPLAY_NO_CARD; hand_display_set_card (win->handdisp[i - 1], c, color); if (has && b->current_dd && b->current_dd->card_score[c] >= 0 && seat_mask (i, win->show_dd_scores)) hand_display_set_card_score (win->handdisp[i - 1], c, card_overtricks(b, c)); else hand_display_set_card_score (win->handdisp[i - 1], c, HAND_DISPLAY_NO_SCORE); } hand_display_set_card_score_neg (win->handdisp[i - 1], i % 2 != b->declarer % 2); hand_display_draw(GTK_WIDGET (win->handdisp[i - 1])); } /* table */ hand_display_table_reset_cards (win->table); if (b->n_played_cards) { int trick_start = b->n_played_cards - seat_mod(b->n_played_cards); for (i = trick_start; i < b->n_played_cards; i++) { card c = b->played_cards[i]; seat s = b->dealt_cards[c]; hand_display_table_set_card (win->table, i - trick_start, s, c); } } hand_display_draw(GTK_WIDGET (win->table)); line_entry_set_from_board(b); } g_string_free(str, TRUE); if (redraw & REDRAW_PLAY) window_play_update(b); if (redraw & REDRAW_BIDDING) { bidding_update (win, b, redraw & REDRAW_BIDDING_SCROLL); } } void recently_used_add (char *filename) { #if GTK_CHECK_VERSION (2,10,0) static GtkRecentManager *recent = NULL; if (! recent) recent = gtk_recent_manager_get_default (); char buf[1024]; snprintf (buf, sizeof (buf), "file://%s", filename); gtk_recent_manager_add_item (recent, buf); #endif } /* callbacks */ static void card_clicked (HandDisplay *handdisp, int card, int *seatp) { if (card == -1) return; PROTECT_BEGIN; board *b = CUR_BOARD; assert (card >= 0 && card < 52); //printf("Clicked: %s for %c.\n", card_string(card), "WNES"[*seatp - 1]); int redraw = 0; if (*seatp != b->current_turn && b->n_played_cards > 0 && b->dealt_cards[b->played_cards[b->n_played_cards - 1]] == *seatp) { /* quick undo */ rewind_card (b); redraw = 1; } if (play_card(b, *seatp, card)) { redraw = 1; } if (redraw) { compute_dd_scores (b, run_dd); show_board(b, REDRAW_HANDS | REDRAW_NAMES | REDRAW_TRICKS | REDRAW_PLAY); } PROTECT_END; } static void card_enter (HandDisplay *handdisp, int card, int *seatp) { PROTECT_BEGIN; char buf[100]; board_statusbar(NULL); board *b = CUR_BOARD; if (!b->current_dd || b->current_dd->card_score[card] < 0 || !seat_mask (*seatp, win->show_dd_scores)) PROTECT_RETURN; snprintf(buf, 99, "%s: %s", card_string(card), score_string(b->level, b->trumps, b->declarer, b->doubled, b->vuln[b->declarer % 2], b->current_dd->card_score[card], b->current_turn)); board_statusbar(buf); /* what-if */ //hilight_next_dd_scores (b, card); //show_board (b, REDRAW_DD); PROTECT_END; } static void card_leave (HandDisplay *handdisp, int card, int *seatp) { PROTECT_BEGIN; //board *b = CUR_BOARD; board_statusbar(NULL); //show_board (b, REDRAW_DD); PROTECT_END; } /* gets called for target widget */ static void card_drag_drop (HandDisplay *handdisp, int card, int on_card, int *to_seat) { PROTECT_BEGIN; board *b = CUR_BOARD; printf("Dropped: %s on seat %c.\n", card_string(card), "WNES"[*to_seat - 1]); if (on_card >= 0) printf("Dropped on: %s.\n", card_string(on_card)); if (b->dealt_cards[card] && b->dealt_cards[card] == *to_seat) /* card didn't move */ PROTECT_RETURN; if (b->dealt_cards[card] && !b->cards[card]) { board_statusbar(_("Card is in play and cannot be moved")); PROTECT_RETURN; } seat from_seat = b->dealt_cards[card]; if (on_card >= 0) { /* exchange 2 cards */ if (b->dealt_cards[on_card] && !b->cards[on_card]) { board_statusbar(_("Card is in play and cannot be exchanged")); PROTECT_RETURN; } remove_card(b, *to_seat, on_card); if (from_seat) { remove_card(b, from_seat, card); add_card(b, from_seat, on_card); } add_card(b, *to_seat, card); } else { /* move single card */ if (b->hand_cards[*to_seat-1] == 13) { board_statusbar(_("Hand has already 13 cards")); PROTECT_RETURN; } if (from_seat) remove_card(b, from_seat, card); add_card(b, *to_seat, card); } b->par_score = -1; invalidate_dd_scores (b); board_statusbar(NULL); card_window_update(b->dealt_cards); show_board(b, REDRAW_HANDS | REDRAW_PAR); PROTECT_END; } /* static void bidding_clicked (GtkTreeViewColumn *column, void *data) { printf ("clicked bidd\n"); } */ #if GTK_CHECK_VERSION (2,12,0) static gboolean bidding_query_tooltip (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, window_board_t *bidding_store) { if (keyboard_mode) { printf ("FIXME: keyboard usage\n"); return FALSE; } GtkTreeIter iter; gboolean ret = gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget), &x, &y, keyboard_mode, NULL, NULL, &iter); if (!ret) { gtk_tooltip_set_text (tooltip, NULL); // TODO: don't show anything at all, or something interesting // y<0 -> headings return TRUE; } int i; int width = 0; for (i = 0; i < 4; i++) { width += gtk_tree_view_column_get_width (win->bidding_column[i]); // TODO: cache this, or use gtk_tree_view_get_path_at_pos if (x < width) break; } assert (i < 4); gchar *alert; gtk_tree_model_get (GTK_TREE_MODEL (win->bidding_store), &iter, 2 * i + 1, &alert, -1); gtk_tooltip_set_markup (tooltip, !alert || *alert ? alert : _("(no explanation)")); return TRUE; } #endif #if GTK_CHECK_VERSION (2,10,0) static void jump_menu_select (GtkWidget *recentchooser, char *unused) { char *filename = gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (recentchooser)); if (strncmp (filename, "file://", sizeof ("file://") - 1)) return; board_load_popup (win, 0, filename + sizeof ("file://") - 1); } #endif /* infrastructure */ static void create_hand_widgets (window_board_t *win) { static const char *alignment_a[] = {"alignment_w", "alignment_n", "alignment_e", "alignment_s"}; static int dir[] = { 1, 2, 3, 4 }; int h; GtkSizeGroup *sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_BOTH); for (h = 0; h < 4; h++) { GtkWidget *alignment = get_widget (alignment_a[h]); GtkWidget *hand = hand_display_new(HAND_DISPLAY_MODE_HAND); gtk_container_add(GTK_CONTAINER(alignment), hand); gtk_widget_show(hand); g_signal_connect (hand, "card-clicked", G_CALLBACK (card_clicked), dir + h); g_signal_connect (hand, "card-enter", G_CALLBACK (card_enter), dir + h); g_signal_connect (hand, "card-leave", G_CALLBACK (card_leave), dir + h); g_signal_connect (hand, "card-drag-drop", G_CALLBACK (card_drag_drop), dir + h); win->handdisp[h] = HAND_DISPLAY(hand); hand_display_set_drag (HAND_DISPLAY (hand), 1); gtk_size_group_add_widget (sizegroup, hand); } g_object_unref (sizegroup); /* trick display */ GtkWidget *grid = get_widget ("table1"); GtkWidget *table = hand_display_new (HAND_DISPLAY_MODE_TABLE); gtk_table_attach_defaults (GTK_TABLE (grid), table, 1, 2, 1, 2); gtk_widget_show (table); win->table = HAND_DISPLAY (table); } static void create_bidding_widget_cb (GtkWidget *w, window_board_t *win) { static int i = 0; win->bidding_header[i++] = w; assert (i <= 4); } static void create_bidding_widget (window_board_t *win) { /* GtkScrolledWindow *scroll = GTK_SCROLLED_WINDOW (get_widget ("scrolledwindow2")); GdkColor bg = { 0, 0.8*65535, 0.0, 0.0 }; gdk_colormap_alloc_color (gdk_colormap_get_system (), &bg, FALSE, TRUE); gtk_widget_modify_bg (GTK_WIDGET (scroll), GTK_STATE_NORMAL, &bg); */ win->bidding = GTK_TREE_VIEW (get_widget ("treeview_bidding")); //gtk_widget_modify_bg (GTK_WIDGET (bidding), GTK_STATE_NORMAL, &bg); //gdk_window_set_background (gtk_tree_view_get_bin_window (bidding), &bidding_vuln); win->bidding_store = gtk_list_store_new (8, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model (win->bidding, GTK_TREE_MODEL (win->bidding_store)); #if GTK_CHECK_VERSION (2,12,0) g_signal_connect (G_OBJECT (win->bidding), "query-tooltip", G_CALLBACK (bidding_query_tooltip), win); #endif GtkCellRenderer *renderer; renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "xalign", 0.5, "cell-background", "yellow", "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); char *dir[] = {"W", "N", "E", "S"}; int i; for (i = 0; i < 4; i++) { GtkTreeViewColumn *column; column = gtk_tree_view_column_new_with_attributes (_(dir[i]), renderer, "markup", 2 * i, NULL); gtk_tree_view_column_set_expand (column, TRUE); gtk_tree_view_column_set_min_width (column, 36); gtk_tree_view_column_set_alignment (column, 0.5); //g_signal_connect_swapped (column, "clicked", G_CALLBACK (bidding_clicked), 0); /* win->bidding_label[i] = gtk_label_new (dir[i]); //gtk_label_set_width_chars (win->bidding_label[i], 4); gtk_label_set_ellipsize (win->bidding_label[i], PANGO_ELLIPSIZE_END); gtk_tree_view_column_set_widget (column, win->bidding_label[i]); gtk_widget_show (win->bidding_label[i]); */ gtk_tree_view_append_column (win->bidding, column); win->bidding_column[i] = column; } gtk_container_forall (GTK_CONTAINER (win->bidding), (GtkCallback) create_bidding_widget_cb, win); GdkColormap *cmap = gdk_colormap_get_system (); gdk_colormap_alloc_color (cmap, &bidding_non_vuln, FALSE, TRUE); gdk_colormap_alloc_color (cmap, &bidding_vuln, FALSE, TRUE); } void board_window_set_style (window_board_t *win, int style, int card_width) { win->hand_display_style = style; win->card_width = card_width; } void board_window_apply_style (window_board_t *win) { /* check if the svg file is there */ if (win->svg) { struct stat buf; if (stat (win->svg, &buf) == -1) { g_free (win->svg); win->svg = NULL; } } /* otherwise set a default */ if (! win->svg) { int i; for (i = 0; svg_files[i] != NULL; i++) { struct stat buf; if (stat (svg_files[i], &buf) != -1) { win->svg = strdup (svg_files[i]); break; } } } if (! win->svg && win->hand_display_style == HAND_DISPLAY_STYLE_CARDS) /* still nothing... */ win->hand_display_style = HAND_DISPLAY_STYLE_TEXT; int h; for (h = 0; h < 4; h++) { hand_display_set_style(win->handdisp[h], win->hand_display_style); } hand_display_set_style(win->table, win->hand_display_style); window_card_set_style (win->hand_display_style); if (win->hand_display_style == HAND_DISPLAY_STYLE_CARDS && win->svg) { hand_display_set_svg (win->svg, win->card_width); } if (win->n_boards) show_board(CUR_BOARD, REDRAW_HANDS); } int board_window_append_board (window_board_t *win, board *b) { if (!b) { b = board_new (win->n_boards + 1); g_string_printf (b->name, _("Board %d"), win->n_boards + 1); } if (! win->n_boards_alloc) { win->n_boards_alloc = 4; /* start with 4 entries */ win->boards = malloc (win->n_boards_alloc * sizeof (board *)); assert(win->boards); } else if (win->n_boards >= win->n_boards_alloc) { win->n_boards_alloc <<= 2; win->boards = realloc(win->boards, win->n_boards_alloc * sizeof (board*)); assert(win->boards); } win->boards[win->n_boards] = b; return win->n_boards++; } void board_window_init (window_board_t *win) { //win->window = create_window_hand (); win->window = get_widget ("window_hand"); win->statusbar = GTK_STATUSBAR (get_widget ("statusbar1")); win->board_menu = get_widget ("board_menu1"); create_hand_widgets(win); create_bidding_widget (win); /* set up "recently used" menu */ GtkWidget *jump_menu = get_widget ("jump_to1"); #if GTK_CHECK_VERSION (2,10,0) GtkWidget *recentchooser = gtk_recent_chooser_menu_new (); gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (recentchooser), GTK_RECENT_SORT_MRU); gtk_menu_item_set_submenu (GTK_MENU_ITEM (jump_menu), recentchooser); g_signal_connect (G_OBJECT (recentchooser), "item-activated", G_CALLBACK (jump_menu_select), NULL); GtkRecentFilter *filter = gtk_recent_filter_new (); gtk_recent_filter_add_pattern (filter, "*.lin"); gtk_recent_filter_add_pattern (filter, "*.pbn"); gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (recentchooser), filter); #else gtk_widget_set_sensitive (jump_menu, FALSE); #endif win->keyfile = g_key_file_new (); win->show_played_cards = 0; win->show_hands = seat_all; win->show_dd_scores = seat_all; win->svg = NULL; win->card_width = 70; win->filename = NULL; win->title = win->subtitle = win->team1 = win->team2 = NULL; win->boards = NULL; win->board_numbers = NULL; win->n_boards_alloc = 0; win->n_boards = 0; win->cutbuf = NULL; win->cur = 0; GdkColor bg = { 0, HAND_DISPLAY_TABLE_GDK_BG }; gdk_colormap_alloc_color (gdk_colormap_get_system (), &bg, FALSE, TRUE); gtk_widget_modify_bg (win->window, GTK_STATE_NORMAL, &bg); gtk_widget_show (win->window); } G_MODULE_EXPORT gboolean on_window_hand_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { gtk_main_quit (); return FALSE; } void board_statusbar (char *text) { static guint id = 0; if (!id) id = gtk_statusbar_get_context_id(win->statusbar, "window_board_c"); gtk_statusbar_pop(win->statusbar, id); if (text) gtk_statusbar_push(win->statusbar, id, text); } void board_set_declarer (seat declarer) { board *b = CUR_BOARD; if (declarer == b->declarer) return; if (b->n_played_cards > 0) { board_statusbar (_("Cannot change declarer while cards are in play")); PROTECT_BEGIN; show_board(b, REDRAW_CONTRACT); PROTECT_END; return; } PROTECT_BEGIN; b->declarer = declarer; b->current_turn = seat_mod(declarer + 1); invalidate_dd_scores (b); show_board(b, REDRAW_CONTRACT | REDRAW_TRICKS | REDRAW_HANDS | REDRAW_NAMES | REDRAW_BOARD_LIST); PROTECT_END; } void board_set_dealer (seat dealer) { PROTECT_BEGIN; board *b = CUR_BOARD; b->dealer = dealer; show_board(b, REDRAW_CONTRACT | REDRAW_HANDS | REDRAW_NAMES | REDRAW_BIDDING); PROTECT_END; } void board_set_trumps (suit trumps) { board *b = CUR_BOARD; if (trumps == b->trumps) return; if (b->n_played_cards > 0) { board_statusbar (_("Cannot change trumps while cards are in play")); PROTECT_BEGIN; show_board(b, REDRAW_CONTRACT); PROTECT_END; return; } PROTECT_BEGIN; board_rewind (b); b->trumps = trumps; invalidate_dd_scores (b); show_board(b, REDRAW_CONTRACT | REDRAW_BOARD_LIST); PROTECT_END; } void board_set_level (int level) { board *b = CUR_BOARD; if (level == b->level) return; PROTECT_BEGIN; b->level = level; invalidate_dd_scores (b); calculate_target(b); show_board(b, REDRAW_CONTRACT | REDRAW_BOARD_LIST); PROTECT_END; } void board_set_vuln (int ns, int ew) { PROTECT_BEGIN; board *b = CUR_BOARD; if (ns == b->vuln[0] && ew == b->vuln[1]) PROTECT_RETURN; b->vuln[0] = ns; b->vuln[1] = ew; b->par_score = -1; show_board(b, REDRAW_CONTRACT | REDRAW_NAMES | REDRAW_BIDDING | REDRAW_PAR); PROTECT_END; } void board_set_doubled (int doubled) { PROTECT_BEGIN; board *b = CUR_BOARD; b->doubled = doubled; show_board(b, REDRAW_CONTRACT | REDRAW_BOARD_LIST); PROTECT_END; } tenace-0.18/src/window_board.h000066400000000000000000000052751505733770300163420ustar00rootroot00000000000000#ifndef WINDOW_CARD_H #define WINDOW_CARD_H #include "../handdisplay/hand_display.h" #include "bridge.h" /* defines */ #define CUR_BOARD (win->boards[win->cur]) /* make sure some code is not called twice */ #define PROTECT_BEGIN do { if (protect++) return; } while (0) #define PROTECT_BEGIN_BOOL do { if (protect++) return FALSE; } while (0) #define PROTECT_END do { protect = 0; } while (0) #define PROTECT_RETURN do { protect = 0; return; } while (0) /* convenience macros */ #define get_widget(x) (GTK_WIDGET (gtk_builder_get_object (win->builder, (x)))) /* types */ typedef struct _window_board_t { /* GTK */ GtkBuilder *builder; GtkWidget *window; GtkStatusbar *statusbar; GtkWidget *board_menu; HandDisplay *handdisp[4]; HandDisplay *table; /* bidding display */ GtkTreeView *bidding; GtkListStore *bidding_store; GtkTreeViewColumn *bidding_column[4]; GtkWidget *bidding_header[4]; /* config */ GKeyFile *keyfile; int show_played_cards; seat show_hands; seat show_dd_scores; int hand_display_style; char *svg; int card_width; /* boards */ char *filename; char *title, *subtitle, *team1, *team2; int n_boards; int n_boards_alloc; int cur; board **boards; int *board_numbers; /* array of indices for board menu callback */ board *cutbuf; } window_board_t; typedef enum _redraw_t { REDRAW_TITLE = 1 << 0, REDRAW_NAMES = 1 << 1, REDRAW_CONTRACT = 1 << 2, REDRAW_TRICKS = 1 << 3, REDRAW_HANDS = 1 << 4, REDRAW_PAR = 1 << 5, REDRAW_PLAY = 1 << 6, REDRAW_BIDDING = 1 << 7, REDRAW_BOARD = 0xff, /* everything above */ REDRAW_BOARD_LIST = 1 << 8, /* menu */ REDRAW_FULL = 0x1ff, /* everything above */ REDRAW_BIDDING_SCROLL = 1 << 9, } redraw_t; /* global variable */ extern window_board_t *win; extern int protect; /* inhibit infinite loops in handlers */ /* interface */ void show_board (board *b, redraw_t redraw); void recently_used_add (char *filename); int board_window_append_board (window_board_t *win, board *b); /* returns number of appended board */ void board_window_init (window_board_t *win); void board_window_set_style (window_board_t *win, int style, int card_width); void board_window_apply_style (window_board_t *win); void board_statusbar(char *text); /* stubs for calls from gui */ void board_set_declarer (seat declarer); void board_set_dealer (seat dealer); void board_set_trumps (suit trumps); void board_set_level (int level); void board_set_vuln (int ns, int ew); void board_set_doubled (int doubled); /* callbacks */ gboolean on_window_hand_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data); #endif /* WINDOW_CARD_H */ tenace-0.18/src/window_card.c000066400000000000000000000150471505733770300161550ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2009 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include "bridge.h" #include "functions.h" #include "solve.h" /* run_dd */ #include "window_board.h" /* board b */ #include "window_card.h" /* board b */ static GtkWidget *window_card = NULL; static HandDisplay *hand_display = NULL; static int seat_null = 0; static seat new_card_seat = west; void card_window_update (seat *cards) { if (!window_card) return; static seat *cards_ptr = NULL; if (cards) cards_ptr = cards; if (!cards_ptr) return; int c; for (c = 0; c < 52; c++) hand_display_set_card (hand_display, c, cards_ptr[c] ? ( cards_ptr[c] == new_card_seat ? HAND_DISPLAY_HILIGHT_CARD : HAND_DISPLAY_GREY_CARD ) : HAND_DISPLAY_CARD); hand_display_draw (GTK_WIDGET (hand_display)); } static void set_new_card_seat (seat s) { new_card_seat = s; card_window_update (NULL); } static void card_clicked (HandDisplay *handdisp, int c, int *seatp) { if (c == -1) return; assert (c >= 0 && c < 56); assert (new_card_seat >= 1 && new_card_seat <= 4); board *b = win->boards[win->cur]; /* x clicked */ if (c >= 52) { if (b->hand_cards[new_card_seat-1] == 13) { board_statusbar(_("Hand has already 13 cards")); return; } int i; for (i = 0; i < 13; i++) { int new = (c - 52) * 13 + i; if (b->dealt_cards[new] == 0) { add_card(b, new_card_seat, new); b->par_score = -1; board_statusbar(NULL); card_window_update(b->dealt_cards); hand_display_draw(GTK_WIDGET (hand_display)); /* force redraw */ show_board(b, REDRAW_HANDS | REDRAW_PAR); return; } } board_statusbar(_("All cards of that suit dealt")); return; } if (b->dealt_cards[c] && !b->cards[c]) { board_statusbar(_("Card is in play and cannot be removed")); return; } if (b->dealt_cards[c] == new_card_seat) remove_card(b, new_card_seat, c); else { if (b->hand_cards[new_card_seat-1] == 13) { board_statusbar(_("Hand has already 13 cards")); return; } if (b->dealt_cards[c]) remove_card(b, b->dealt_cards[c], c); add_card(b, new_card_seat, c); } b->par_score = -1; board_statusbar(NULL); card_window_update(b->dealt_cards); show_board(b, REDRAW_HANDS | REDRAW_PAR); } static void window_card_drag_drop (HandDisplay *handdisp, int c, int on_card, int *seatp /* unused, always 0 here */) { printf ("dropped %d on %d on card window\n", c, on_card); if (c == -1) return; board *b = win->boards[win->cur]; if (b->dealt_cards[c] && !b->cards[c]) { board_statusbar(_("Card is in play and cannot be removed")); return; } seat from_seat = b->dealt_cards[c]; if (! from_seat) return; remove_card(b, from_seat, c); if (on_card >= 0 && b->dealt_cards[on_card] == 0) add_card (b, from_seat, on_card); b->par_score = -1; board_statusbar (NULL); card_window_update (b->dealt_cards); show_board (b, REDRAW_HANDS | REDRAW_PAR); } void window_card_set_style (int style) { /* doesn't actually set the style, but makes the right drag icon appear */ if (window_card) hand_display_set_style(hand_display, style); } void window_card_init (int style) { if (window_card) { gtk_widget_show (window_card); return; } GtkWidget *w = hand_display_new (HAND_DISPLAY_MODE_HAND_X); hand_display = HAND_DISPLAY (w); int c; for (c = 0; c < 52; c++) { hand_display_set_card (hand_display, c, HAND_DISPLAY_CARD); } g_signal_connect (hand_display, "card-clicked", G_CALLBACK (card_clicked), NULL); g_signal_connect (hand_display, "card-drag-drop", G_CALLBACK (window_card_drag_drop), &seat_null); hand_display_set_drag (hand_display, 1); window_card = get_widget ("window_card"); GtkWidget *vbox = get_widget ("vbox2"); gtk_widget_show (w); gtk_box_pack_start_defaults (GTK_BOX (vbox), w); gtk_widget_show (window_card); card_window_update(CUR_BOARD->dealt_cards); window_card_set_style (style); } G_MODULE_EXPORT gboolean on_window_card_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { printf ("delete... \n"); PROTECT_BEGIN_BOOL; printf ("... delete\n"); GtkCheckMenuItem *menuitem = GTK_CHECK_MENU_ITEM (get_widget ("cards1")); gtk_check_menu_item_set_active (menuitem, FALSE); gtk_widget_hide (window_card); PROTECT_END; return FALSE; } G_MODULE_EXPORT void on_cards1_activate (GtkMenuItem *menuitem, gpointer user_data) { PROTECT_BEGIN; if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) { window_card_init (win->hand_display_style); } else gtk_widget_hide (window_card); PROTECT_END; } G_MODULE_EXPORT void on_radiotoolbutton_west_clicked (GtkToolButton *toolbutton, gpointer user_data) { set_new_card_seat (west); } G_MODULE_EXPORT void on_radiotoolbutton_north_clicked (GtkToolButton *toolbutton, gpointer user_data) { set_new_card_seat (north); } G_MODULE_EXPORT void on_radiotoolbutton_east_clicked (GtkToolButton *toolbutton, gpointer user_data) { set_new_card_seat (east); } G_MODULE_EXPORT void on_radiotoolbutton_south_clicked (GtkToolButton *toolbutton, gpointer user_data) { set_new_card_seat (south); } G_MODULE_EXPORT void on_toolbutton_card_wipe_clicked (GtkToolButton *toolbutton, gpointer user_data) { board *b = CUR_BOARD; board_clear(b); card_window_update(b->dealt_cards); show_board(b, REDRAW_HANDS | REDRAW_TRICKS | REDRAW_PAR); } G_MODULE_EXPORT void on_toolbutton_card_random_clicked (GtkToolButton *toolbutton, gpointer user_data) { board *b = CUR_BOARD; deal_random(b); card_window_update(b->dealt_cards); compute_dd_scores (b, run_dd); show_board(b, REDRAW_HANDS | REDRAW_PAR); } tenace-0.18/src/window_card.h000066400000000000000000000024501505733770300161540ustar00rootroot00000000000000void card_window_update (seat *cards); void window_card_set_style (int style); void window_card_init (int style); gboolean on_window_card_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data); void on_cards1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_radiotoolbutton_west_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_radiotoolbutton_north_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_radiotoolbutton_east_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_radiotoolbutton_south_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_toolbutton_card_wipe_clicked (GtkToolButton *toolbutton, gpointer user_data); void on_toolbutton_card_random_clicked (GtkToolButton *toolbutton, gpointer user_data); tenace-0.18/src/window_line_entry.c000066400000000000000000000056301505733770300174110ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2009 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include "bridge.h" #include "file.h" #include "functions.h" #include "window_board.h" #include "window_card.h" static GtkWidget *window_line_entry = NULL; static GtkEntry *line_entry = NULL; void board_set_from_line_entry(board *b) { assert (window_line_entry); const char *line = gtk_entry_get_text(line_entry); board_clear(b); if (!board_parse_line(line, b, ' ', '.')) { board_statusbar(_("Parse error")); } card_window_update(b->dealt_cards); show_board(b, REDRAW_FULL); } void line_entry_set_from_board(board *b) { if (!window_line_entry) return; GString *line = board_format_line(b, ' ', '.'); gtk_entry_set_text(line_entry, line->str); g_string_free(line, TRUE); } void window_line_entry_init(board *b) { if (!window_line_entry) { window_line_entry = get_widget ("window_line_entry"); line_entry = GTK_ENTRY(get_widget ("line_entry")); gtk_widget_show (window_line_entry); } if (b) line_entry_set_from_board(b); } static void window_line_entry_delete () { if (window_line_entry) { gtk_widget_hide (window_line_entry); window_line_entry = NULL; line_entry = NULL; } } G_MODULE_EXPORT void on_deal_line_activate (GtkMenuItem *menuitem, gpointer user_data) { PROTECT_BEGIN; if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) { board *b = CUR_BOARD; window_line_entry_init (b); } else window_line_entry_delete (); PROTECT_END; } G_MODULE_EXPORT void on_line_entry_activate (GtkEntry *entry, gpointer user_data) { board *b = CUR_BOARD; board_set_from_line_entry(b); } G_MODULE_EXPORT void on_line_entry_ok_clicked (GtkButton *button, gpointer user_data) { board *b = CUR_BOARD; board_set_from_line_entry(b); } G_MODULE_EXPORT gboolean on_window_line_entry_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { PROTECT_BEGIN_BOOL; GtkWidget *menuitem = get_widget ("deal_line"); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), FALSE); window_line_entry_delete (); PROTECT_END; return FALSE; } tenace-0.18/src/window_line_entry.h000066400000000000000000000011321505733770300174070ustar00rootroot00000000000000void board_set_from_line_entry(board *b); void line_entry_set_from_board(board *b); void window_line_entry_init(); void on_line_entry_ok_clicked (GtkButton *button, gpointer user_data); gboolean on_window_line_entry_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data); void on_line_entry_activate (GtkEntry *entry, gpointer user_data); tenace-0.18/src/window_misc.c000066400000000000000000000045341505733770300161760ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2018 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include "config.h" #include "functions.h" #include "window_board.h" /* IMP table */ static GtkWidget *window_imps = NULL; G_MODULE_EXPORT void on_imp_table1_activate (GtkMenuItem *menuitem, gpointer user_data) { window_imps = get_widget ("window_imps"); gtk_widget_show (window_imps); } G_MODULE_EXPORT void on_imps_ok_clicked (GtkButton *button, gpointer user_data) { gtk_widget_hide (GTK_WIDGET(window_imps)); } /* about dialog */ static GtkWidget *window_info = NULL; G_MODULE_EXPORT void on_info1_activate (GtkMenuItem *menuitem, gpointer user_data) { window_info = get_widget ("aboutdialog1"); #ifdef DDS_VERSION GString *comment = g_string_new (gtk_about_dialog_get_comments (GTK_ABOUT_DIALOG (window_info))); g_string_append_printf (comment, _("\nDDS version: %d.%d.%d"), DDS_VERSION / 10000, (DDS_VERSION / 100) % 100, DDS_VERSION % 100); gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (window_info), comment->str); g_string_free (comment, TRUE); #endif gtk_widget_show (window_info); } G_MODULE_EXPORT void on_aboutdialog1_close (GtkDialog *dialog, gpointer user_data) { gtk_widget_hide (GTK_WIDGET(window_info)); } G_MODULE_EXPORT void on_aboutdialog1_response (GtkDialog *dialog, gint response_id, gpointer user_data) { gtk_widget_hide (GTK_WIDGET(window_info)); } tenace-0.18/src/window_misc.h000066400000000000000000000026261505733770300162030ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2008 Christoph Berg * * 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. */ /* IMP table */ void on_imp_table1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_imps_ok_clicked (GtkButton *button, gpointer user_data); /* about dialog */ void on_info1_activate (GtkMenuItem *menuitem, gpointer user_data); void on_aboutdialog1_close (GtkDialog *dialog, gpointer user_data); void on_aboutdialog1_response (GtkDialog *dialog, gint response_id, gpointer user_data); tenace-0.18/src/window_play.c000066400000000000000000000062601505733770300162060ustar00rootroot00000000000000/* * tenace - bridge hand viewer and editor * Copyright (C) 2005-2009 Christoph Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include "bridge.h" #include "functions.h" #include "window_board.h" static GtkWidget *window_play = 0; static GtkTable *play_table; static GtkLabel *play_label[7 * 13]; void window_play_update (board *b) { if (!window_play) return; int t, i; for (t = 0; t < 13; t++) { /* trick */ for (i = 0; i < 7; i++) { GtkLabel *l = play_label[7*t + i]; gtk_label_set_markup(l, ""); } int col = -1; /* current column */ for (i = 0; i < 4; i++) { /* card in trick */ card c = b->played_cards[4*t + i]; if (c == -1) continue; if (col < 0) col = c == claim_rest ? 0 : b->dealt_cards[c] - 1; GtkLabel *l = play_label[7*t + col++]; if (c == claim_rest) gtk_label_set_markup(l, _("CL")); else { gtk_label_set_markup(l, card_string_color (c)); } gtk_widget_set_sensitive(GTK_WIDGET(l), 4*t + i < b->n_played_cards); } } } void window_play_init (window_board_t *win, board *b) { if (window_play) return; window_play = get_widget ("window_play"); play_table = GTK_TABLE(get_widget ("play_table")); assert (play_table); int cr, cc; char str[20]; for (cc = 1; cc < 8; cc++) { GtkWidget *lab = gtk_label_new (NULL); snprintf (str, sizeof (str), "%s", _(seat_str[seat_mod (cc)])); gtk_label_set_markup (GTK_LABEL (lab), str); gtk_table_attach(play_table, lab, cc, cc+1, 0, 1, 0, 0, 0, 0); } for (cr = 0; cr < 13; cr++) { snprintf(str, sizeof (str), " %d ", cr+1); GtkWidget *lab = gtk_label_new(str); gtk_table_attach(play_table, lab, 0, 1, cr+1, cr+2, 0, 0, 0, 0); for (cc = 0; cc < 7; cc++) { GtkWidget *lab = gtk_label_new(NULL); gtk_table_attach(play_table, lab, cc+1, cc+2, cr+1, cr+2, 0, 0, 0, 0); play_label[7 * cr + cc] = GTK_LABEL(lab); } } gtk_widget_show_all(window_play); window_play_update (b); } void window_play_delete (void) { if (!window_play) return; gtk_widget_hide (window_play); window_play = 0; } G_MODULE_EXPORT gboolean on_window_play_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { GtkCheckMenuItem *menuitem = GTK_CHECK_MENU_ITEM (get_widget ("play1")); gtk_check_menu_item_set_active (menuitem, FALSE); window_play_delete (); return FALSE; } G_MODULE_EXPORT void on_play1_activate (GtkMenuItem *menuitem, gpointer user_data) { if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) window_play_init (win, CUR_BOARD); else window_play_delete (); } tenace-0.18/src/window_play.h000066400000000000000000000005131505733770300162060ustar00rootroot00000000000000void window_play_init (window_board_t *win, board *b); void window_play_update (board *b); void window_play_delete (void); gboolean on_window_play_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data); tenace-0.18/tenace.desktop000066400000000000000000000004031505733770300155420ustar00rootroot00000000000000[Desktop Entry] Version=1.0 Type=Application Name=Tenace Comment=Bridge hand viewer and editor Comment[de]=Betrachter und Editor für das Kartenspiel Bridge Exec=tenace Icon=tenace Terminal=false Categories=Game;CardGame; Keywords=bridge;cards;viewer;editor; tenace-0.18/tenace.glade000077700000000000000000000000001505733770300167412tenace.uiustar00rootroot00000000000000tenace-0.18/tenace.png000066400000000000000000000174651505733770300146750ustar00rootroot00000000000000‰PNG  IHDR@@% æ‰ pHYsÄÄ•+tIMEà  È#+iTXtCommentCreated with GIMPd.e«IDAThÞÕzg@TÇösΞ­ì²ËKgiJ“¢(( F±a%Æk»‰ÆM¼11FS®ÆÄÄDkŒ‰£kl±D©" EštXXvÙ¾ç|?V‘‹&7æûîo~íÌì™yŸ33ïûÌó?ŒÀ 0áÿ¯B@>ˆ}cf6.Ÿû?ÏdÔ3ŒÅB“\.Çb6$‡Ç·›‘¦a21ªnRÕÍÁ!?ˆ%âÌÌLæ_"Â=oìúÌÕÞŽ&,((8{rÛƒË"¡€Ø´Š÷J<_ÑR÷B’8‹UVZÕÊ`0ü/^GG‡ª³³âíç®’IÚ¢[ùöLµÎö_ßÈ´zÆQJü¸ÑýNzÎ IÍÄèQ£œœ¬õääd___çééùÛo¿ý?±»¥¥%!!aÿþýñÒ„šVï£-&3–Íåˆy¾þâ­Y£gOv©VÍ<ž6/À›yeƘÀX˜   kE¥RÍœ93**êâÅ‹cÇŽ3gNssóÿé Ã;vìÒ¥KÑÑÑÍÍÍz½¾½Ã0døòºŽArOÏ”lxº óg»ô×n)- ý¼y/Ïz+zø¤¿> @llì¸qã$%%9r$---$$d„ [¶lñ÷÷ÿÛÖøá‡¿üò‹¯¯oAAP(”H$K—.%Â`4û +©èjnnòt!J«hGâVFµ—]Oè±e둜´„Ú»ó32sͰspt#IòO½Ð“RZZ*—Ëmmmp¹Üþýû—••ýí×ÿË/¿¼÷Þ{)))ÉÉÉsçÎõõõ5>>>nnnß}óž±K=e$»¤†¶—ß%¸Üòógž?µ¥öQ…‡KÅÑcg”Ù9÷ ‚øïÚÚÚd2YOÕÁÁ¡½½ýïY_^^>`ÀWW×3gΜ>}šÇã=|ø$ÉsçÎ………utt$%%éõze'ór0+ºØÜ"!½‚ÈÒ*ZÀ£çÌ],às"BdžQ￾~@HøY߀Ùlf³Ù=U6›m2ýÍÀVSScÝ–+W®ììì\¼xqkkëÈ‘#ÛÚÚÄb±\.¯ªªbsx”‹^“ƒáÍ–V‚E{’™…tÿ~Þ)·îÚÙÙý¥CÜóëÊ•+·nÝjiiQ©TûH’¦é¿a½Ñhì³kW­Ze4+**.\¸°uëV??¿ºººÒÒÒŽNm‡y®äcŠ-TÅÇÕ)-=ÿ/Zÿ´ZmSSSee¥››Û˜L¦Þ ò×˃hšÞ¶mÛ¡C‡òòòÌŸ?_£Ñ(Š‚‚‚ººº={ö455yzz:99>¤„„h¨™Ž"‘è©`ÆŒ………ÇŸ5kÖ’%K4MWW—P(üJKK½½½ÝÝÝE"QWW×?ü°|ùò:;;óù|³Ù|îÜ9óæÍ«¨¨prä÷ ò K+C¼âú®®.«#y±Я_¿êêêõë×oÞ¼yÕªUÅÅÅýû÷ÿ{[(**ê›o¾¹yó¦N§[¶l‰D2gÎN'‘H(Šrss8p`YY™ÔNâãAjƒ¨@Ð Êß_ õ®DGG›ÍæÝ»w/_¾<::º«««´´´¢¢âE8;;P«ÕçÏŸ_ºtéš5kœ?þêÕ«r¹œÇãÙÚÚ>üƒ>Xµj•Î@8;fG῭:'çÅYtt´ÕcH$6›½fÍš/¿ü²®®nĈ7oÞd±X£G~!uuu^^^$I.X° 88xîܹ‰$ `æÌ™ÙÙÙ¯¿þºÁ`hhh¨¯¯7™L mš8ÜÀ§Q†ù>ÀŠøÆâ:û–U«Võæw•••—.]*//·Võzý ÑÃÊÊÊšššçv>|8$$¤­­­  Àplmmí¥Â„¯øU—…'Iü$ûx¼ÌÛ·ÿ2}¦øøøÐ4ݯ_?k•Ëå¾hËåÏíš1cFhhèÎ;¿üòËÁƒs8@`+¤Ì4«QoGÄ%@·^_{íÚß9Ö²}ûö©S§nܸñïæææ¬¬¬µk×&%%õé²±±ILLܰaCuu5Ã0'N>|¸½„°XàíN2ޤ-Ð<:ú©±²ò…ÆE‹½÷Þ{ Ãüûßÿ¶:?bÈ55ÕÏíŠ×jµAŒ5ê–hþüùõõõ£Frss³—˜x\HÅ„À Ü;--g—.}1F£qúôéìi9uêT||¼Z­îóLYYÙÚ÷§]ºp´7ñìùmgg7jԨ Æg§ìîîÖëõÆ +//÷ôp¦HƒNÅk GÀp@t‚7NnØð>|ùòå>Ý©©©ûöîíÝ¢V«ܾôó7Híì­-7Ožœ6xpŸ7lØÂápž2 àäÉ“7oÞäóùçÏ¢iføêÛ5|3 å@ PÃ0]»vUß¿ÿWÔÕÕ=ÅÕ<½’›L›ÖÍpe}L;F¥R}½`Aã¢E#‚>Oö¸¾ž›ÅZ¶l™N§ËÍÍM½ë`GøN‹|l  €(íí ‹)Š¿`Ò¤I|>€\.Ÿ9s¦¿{üø±=ÿÙ¹å 1•Æã \ú-n¨mü|äÈ)‰‰^z}•\ž–––››Û³—x<žV«íîî¶n°ÂÂBFÓ3A±±±C‡åó¨Á¨ŠGt~‰ÅüÄeD Š‹MMr¹|áÂ…Ä‹ŸˆŒŒ¬ªªÊÌÌ,//¯««»‘|éâÙ}™)ûýüž²‰ääë·r,EõCGž‘úî»S v?X,¾gÏ'Mº5aÂ={z˜ìüùó“““×®]kccÓ›VUVVZ,–ß~ûmÂ(g£‰ ð!ÃYÝÁG5@9À¶·‰‹Û¸qã™3gz8òŸy!gg稨¨ÜÜÜìì쬬¬Ú‚•'Oò÷x2kÅÕÔ†¤4stì¬ÖuëfççÿP€0P«5vuuúûÿsÉ’Þ׉ñãÇ÷ë×oΜ9>>>½'*,,ÌÎÎ...vsPõóbýsÎ`DKcÕBì€. ØÑÕegg'‹ßyç‡ÿ~¡@ÓôñãLJ vùJÊ”á£C}Þ×ëõ©)×’.Tw”Úð u7³zùòÍzýÀ 0:`3 2äDZZï¡Þxã ’$ïÝ»7þüÞܸq[¶l é÷pøœñùœG팰FM[à¢@`ÔjwîÜéææVùÇ1¡o #IrÇŽééé/ “nØöàÖµ쥢‰“¦edd{úDmúzëO?ýôÅæÍwbb<Äâf@Ð@$`WRòÅŠ­­­Öq,Ë+¯¼"“ɶmÛ¦×ë{Ï9}úô¨b‘ á''ÃX¾ždn Ýãt 'zâÄï¿ÿ^$%$$ü  žÛZT˜Ÿº;n°™kjÑêÌ#b‚ÇŽy)l`ì䩯Z9ÖÒ+R®^í8rjµÐbÑ)•|•Jqùò[ee§¯^pòäÉððð   [·n¥¤¤¤¥¥Éår{{{“É”˜˜(sàŒÐõ÷b BM‹c+;‰€à«Ø ì7›ØØ°X,?¹àÑÃdz̘?&“¹Û·oïÙ³'###++ËKî>sr@jÒÖ†ºŠ•ËÆ}ýoí›Ü£Û—¼>µ²²òx•Á`¸{÷®õ÷þýû•Jå'Ÿ|’››ÛÞÞ>{öì>ø $$dâĉƒ ²µµµq¿zŸg(/Ã1‰÷mä/E=Vò'ï› 0-Ž]ÛqËWËL&Ó!sjµ:88xùòå3fÌ.qŠ òš«»ï¶’üÌžø’€"»G¥$ü¸:##ã¹/‚ÃáDDD˜ÍæÅ‹¯Y³F&“%''§§§Oš4iÒ¤I/¿ü²³³óÏ?ÿloookk;{"Å‚NÏl]Ëã°ñ ‚–Ù•@1бcüñG—mŸˆ6ñœRÏyúç½ÿÙ}ÀÛÛ{õêÕ¹¹¹B¡pç΋/ž>}ú¹sçš››}}}ƒÂ§·ký[õ]Ý, ¯nû—¢†Å9::>wÄk×®q8œyóæTUU¥§§ûûû=z”Çã8p`РA7oÞ˜;™ñv#ã—tk´=”ºxÓdè`ªèL’ðôõõU+ïo_£ð‰A¬_¯èB½ŠYâ™"[iŸéëŠ2eJaaáêÕ«çÍ›×ÝÝ™™i±Xbbbz?ÓÔÔÄb±z+H=åÂ…K6}y÷Þ=B, ìCÙØ˜Íf‹Åbooo±XT*Uff¦U<&²ýn‘åÀ¯Æþ^ä±­‚¬û–Ëg)÷-š'¬jZÛדtv b"(•šº§ødÜ”ŸˆËÊÊZ[[Y,EQIII+W®´Þ†‡úõ×_GFFö–'\\\ž5=77w÷î#ʬÌ%²$@‘BqY¡HJMe±ÙÓ¥R!‹Õd±<Ôé µZ³f5ËÇt¿ß2¯~ƒ{å¶9Ȭmg ±páÂo¿ý–KÔL#D6Dn‘eü¢n¡_¬äy–>ß )Š#Fœ9u¤l8Î’%K|||JJJ‚ƒƒÕjuQQÑœ9s&Ožl6›iš–ËåƒÏç744lýâ‹Ø¸¸o·oOJJ>}º€é(®øñÀÀ@ì7™¤--=ó~às„KÜ0¶Ù‚˜A”£”x“N*&ª•L¸7c±Xƒ¥ý³^£Es+Y`±Ð8ô ¢–æ“%ÏÐÖÖ–˜˜Hs\†$œ?oí°nqN7f̘ªªªÐÐÐüüüâââ7ß|“ ³ÙüÞôéÿª©9ø«Ë‰Ë..1ááË_2îl ˜ÌúìÙI@q´­V§b±ðõ^Ã'˸¿\0…°6|oPk™Û·ogf¤—%‰¼ÝYK×é„¢¡…ŽAÙ 6…Š*e„ÁÐ'&V~=4LîÔÞ©&{s&†ad2™¿¿¿•çíØ±ÃÛÛ› š¦7¬X1ãúõã²0ï)iîî“BC?-/XWWQ8VÖfÿŒõÖ3çá΋ˆ’Jú“e\¥Š¹[h!8º„'$$DGGüާ·;àý×¹?7Ú ‘ ÁãÀ£fÑöˆMmmß I2jSjgÞŠÏÒÒÒÌfshh¨F£Q©T2™¬±±qúôé±±±áááï¾û.€ }4úÒ¥Ã7ɰ}f†¦(aGG‰ÚÌò±3]*6 ´@2ÀV…€U¦’l ®”þh{ßIãGß™=\ˆÍ«yãëõz½Á`°’k)­–UÕÑ{¿à‹lPZE›- `Õ]¢çŽŠZVYIEAÙQYÐ\Cø÷ha€?Ðh.ðª5c˜Ix…Ü\ý÷­9E;½5ÑsÿþýÓ¦M°vK‡¢é³ëº4ŒÈ†8vEVÖè@hŽ5iµÿ £­¶´Ò؇–*•Ê’’’Þ«]o½µ ++Al×­¶©£ã“Ó0æi¾ÀbA*&>²´’¤ ø)ÀÀà&€¬± Tù{“¿]7ÍÇ^±ÑÒÚ®6 [?âåœÊìûêY¿\0Ťò+'kXƒ¬ÙŠÐÖÖ›ŸþvÒ%þ½ûý÷ßÿýwooo«¸ ÕjÃCB¢®_×7mCÇŒ=]T´³¦æœLÊÎf’€È†Ð]o9 øÀ Àlò @ üè¢Yßì3¾>ƒc0bËÙ$mCCÃÛo¿]R”>a8›óŒ~)Å<4ŒµqŸ›Ró–X>+•/´Ò}b¢V­~ €/lúzsŸËû¶mÛ¬22€K—. º»w8úÖ[@’T@À’êê3Á¢i#IPCBX¿Åmn¥Ó”šo€ÛÀFà >öÉÀ—€mq[F}.E:&šÚsÒîÀ¯½öÚøQÞu©6¾}ùæùë&“™©ªç•>Éf‹¸\©’ïjí ih¸ºqãÓCœÐ[‹ìììœ2eŠM?Ý·kצòò.¯J6Á_6´¥%ÝÉ)ÚÁaÃX8[É/µ4µÒãb©c;â®''@;Д iK?® S¦µµeÿUŸw¯Õ1{ޱôz÷o6éœ#WX ©¢ìzÜqubbÉÂ…dÏÁíý¼B¡°Z_RRÒÖÖÖÐÐ0J§³7¿sîOÛú¹¹îì, —OÕj›RÀ— cùÉÉÌ<Î_×ðT*Õ»ï¾;"´ÂÝÉòT5Ò1?Ÿ1î=iœ5SžçÅ~¯ÚÆ.Þ`è(.Þ]X¸£ÁüTh klÜõå—Ï¿Ððx<999ï¼óÎâÅ‹›îߟ}ï^7pSû©9åë;["é¯Ó)d²¨¶¶{4mpõü¨¡e“ƒ¹ŸA4ÝS€C€*,,§ € ˆÞ²—µˆD¢]»våçç_¾pô½ù Šv&=Ï\]O;;CÃ9 '„³æ¨[Š/ù„Ö™¸¼†o’$›Ó˜ò4 Ìœ1ã9Ìf3E=¦*•j̘1wíâÓô^WÚ¨lo½ÛÙY&“E64Üpw×Ý]çãóJié;‡%ÍÕgcÚ*ßø@›OèÖ­ùùùyyyZ­–Ïç{zz>üùçwššÚØ´---ÕÕÕnŽ]ß'‚bR 1<‚-–øœ8ÜuõkÅ«­ ØÕiìç;ÂÉi“IcÇÓ}Îb¹>çžöðáCWWWYYY&L8±eËÄ¢"ªPÒÍYØÔ”B”ÅbÐÖ–O,_ßWóò¯Pw ø€¨ôð (ŠÍf¿ù曓&Mb±X/á¥T– … z½Á`X³fMiqƲ×òĵÊ?ý"žl(Xxÿ¤Êõ­ê`½/©TªÓé†i¿~|AÝÜ WagKŒ‹¡Œf§ç”ÆÆ‡Á^ÍwÀ`Wàe ˆË4z´Z­ [°`A}}}zz:€û÷ïçåå999…‡‡‡……•””ddd´µµ]OL<Ì0 1 8@2‹§÷}µ££H* ®«û]dcpw&;»gÂ…%~ÌA¿É“Ÿ/îVUUýãÿX»v­ôî]k‹Ø}¾öÔï&?9Ù®²“J‡ŠDr®ESqt‰ºú&0 °À ˜9lX^^Ç;tèPzz:I’×®]ãóùûöí³jÔÁÁÁÅÅÅF£Ñ×××PZ:p¸ÀY ø†+µ÷y…$¹Ñ­¾%“Ò×3Ìa¬3WM–ÖÇ pwȸI“dddô`04ÍýÛ·#ž|-×Ds"CY4ûådxøšÖÖ»"‘—WãuÃXÉa!pø°<˜Çã%$$ddd¤§§_¾|yݺu;wî°pÁ‚Ë—/ …¶¶¶ððp¹\.àñNݲºi€NÚ¸PÎÑ$IYÝtWW“NϬYÂmë`âG°·>þ–ÒaÕ©®^½ÚÀÑ£G³²²â¥Òž¤—¨¬3µ*Ñ&0h­­B‘iiË_¦*»Ä4à<öDÔøñ­­­b±X&“]½zµ££#333??ß–Çóë×/&&&!!áèÑ£Z­6555åĉ·hÚgÎ2ÍuŒ»G<‚ Ìf…Fe-½y¿aôP– _ÝR ÀÑqäk¯Yn}}}_!!!‡â÷J­¶€P´Ó*­«|Ÿ—×´ÒÒýñ~ŠÛB‹™°/ñÁÁ>tss‹ŽŽ¶º2±X|úôéc‡ð𨬬 éìì,((¨©©‰‹‹³«¯ ˆ´ìvìúžUíŠâ›Í„«¹`›$‰~B!ËštŒˆ ±ú›åË—÷4cÆ aWWOK;[0ujê¸ñ©ÎÎ1ee?»¹m©>ó/eaù$ôt'€‘Ó¦‰D"†aZ[[·nݺ|ùòÍ›7Seêî–zxdgg“$9xðàÔÖÖJ%’¢‚ëç€û› óèÑoZm‚ B(ôðp!|Â͉äi<¢(—_î}£ žýÔÇl63½¾õSS6B¡—B‘ÙÞ^(—O!Ò»#[dÔu6 d›N`ÙœrâXkksIéC•J}çΠ  2¯±qü+¯äWUY,–©S§r¹\Š¢ÒNŸ¶×ëOøBøÒ¨Ã]¨«»â￈ HŽÑ…eµÕu¦e¯8Å=lp}È¥“'WVVúúúðòò¢ž …Â^©|š?&ÙŹ¼¼^ \Â0tZê¢]Š€@ œ%ˆÞŽ3ƒÅQÑ–ß½s¢M5õôû[lxýôS¶ZÀ0©Ëí¯¾2 7nܰ··wrrš?ožÍƒJ6Š}VÿH.p¹v­­9‰?ÃÐ\®Ä`Pº»ÍÏ[§hÇK%€‹‘‘ÃÃëëëׯ_oÕÃÃÂÂþu–w ×CPIEND®B`‚tenace-0.18/tenace.ui000066400000000000000000004521041505733770300145170ustar00rootroot00000000000000 True Tenace True vertical True True _File True gtk-new True True True gtk-open True True True gtk-jump-to True True True _Append True Append file to board list True True gtk-save True True True gtk-save-as True True True gtk-print True True True _Magic cards True True image1 False Open in _web True True image2 False True IMP _table... True True True O_ptions... True True True _Info... True True True gtk-quit True True True True _Boards True True _Edit True True _New board True True True gtk-cut True True True gtk-copy True True True gtk-paste True True True True C_lear True True True _Random True True True _Flip hands True True True True E-W True True N-S True True N-W True True N-E True True S-W True True S-E True True True True _Board editor... True True Text _input... True True Rewind play True Undo all cards True True Complete play True Play all cards True True True Show pla_y... True True _Contract True _Dealer True True True True _West True True _North True dealer_west1 True _East True dealer_west1 True _South True True dealer_west1 _Vulnerable True True True True N_one True True _North-South True vuln_none True _East-West True vuln_none True _All True True vuln_none _Level True True True True _1 True True _2 True level1 True _3 True level1 True _4 True level1 True _5 True level1 True _6 True level1 True _7 True level1 True True No _Trump True True ♠ S_pades True contract_no_trump1 True ♥ _Hearts True contract_no_trump1 True ♦ _Diamonds True contract_no_trump1 True ♣ _Clubs True True contract_no_trump1 True Double True True True True _No double True True X _Doubled True level_doubled0 True XX _Redoubled True True level_doubled0 True True _West True True _North True declarer_west1 True _East True declarer_west1 True _South True True declarer_west1 True True _Bidding editor... True True _Analysis True Double dummy True Double dummy analysis True True True Automatically run DD analysis Always run DD True True Parscore True Compute par score and contract True True Play par contract True Set contract to computed par contract True True False False 0 True both-horiz True Open board gtk-open False True True Save board gtk-save False True True Previous board gtk-go-back False True True Next board gtk-go-forward False True True False True Rewind trick True gtk-media-previous False True True Rewind card True gtk-media-rewind False True True Play next card True gtk-media-forward False True True Play next trick True gtk-media-next False True True False True Double dummy analysis gtk-convert False True True Par score gtk-find False True False False 1 True 5 3 3 True True 1 0.25999999046325684 5 5 True True never automatic True True 2 3 GTK_SHRINK GTK_EXPAND | GTK_SHRINK | GTK_FILL True True 1 1 NS: %d EW: %d right True 2 3 2 3 GTK_FILL GTK_FILL True True 0 1 True 2 3 GTK_FILL GTK_FILL True True 0 0 Open 1 4♥ N True GTK_FILL GTK_FILL True 0 etched-out True 5 5 True East True 2 3 1 2 GTK_FILL True 0 etched-out True 5 5 True North True 1 2 GTK_EXPAND | GTK_SHRINK | GTK_FILL True 0 etched-out True 5 5 True South True 1 2 2 3 GTK_EXPAND | GTK_SHRINK | GTK_FILL True 0 etched-out True 5 5 True West True 1 2 2 True False False 3 Board editor True vertical True icons True Clear board True gtk-delete False True True Deal randomly True gtk-select-color False True True False True West True gtk-go-back False True True North True gtk-go-up radiotoolbutton_west False True True East True gtk-go-forward radiotoolbutton_west False True True South True gtk-go-down radiotoolbutton_west False True False False 0 Bidding editor False True vertical True icons True Remove all bids gtk-delete False True True Remove last bid gtk-undo False True True Make bids for the current contract gtk-index False True False False 0 True True Alert False False 1 True 8 5 2 IMP Table False True 5 True 12 5 True 1 5 3500-3990 3 4 11 12 GTK_FILL True 1 5 3000-3490 3 4 10 11 GTK_FILL True 1 5 2500-2990 3 4 9 10 GTK_FILL True 1 5 2250-2490 3 4 8 9 GTK_FILL True 1 5 2000-2240 3 4 7 8 GTK_FILL True 1 5 1750-1990 3 4 6 7 GTK_FILL True 1 5 1500-1740 3 4 5 6 GTK_FILL True 1 5 1300-1490 3 4 4 5 GTK_FILL True 2 3 12 GTK_FILL GTK_FILL True 1 5 1100-1290 3 4 3 4 GTK_FILL True 1 5 900-1090 3 4 2 3 GTK_FILL True 1 5 750-890 3 4 1 2 GTK_FILL True 1 5 600-740 3 4 GTK_FILL True 23 4 5 11 12 GTK_FILL True 22 4 5 10 11 GTK_FILL True 21 4 5 9 10 GTK_FILL True 20 4 5 8 9 GTK_FILL True 18 4 5 6 7 GTK_FILL True 19 4 5 7 8 GTK_FILL True 17 4 5 5 6 GTK_FILL True 16 4 5 4 5 GTK_FILL True 15 4 5 3 4 GTK_FILL True 14 4 5 2 3 GTK_FILL True 13 4 5 1 2 GTK_FILL True 12 4 5 GTK_FILL True 5 11 1 2 11 12 GTK_FILL True 1 500-590 11 12 GTK_FILL True 1 430-490 10 11 GTK_FILL True 1 370-420 9 10 GTK_FILL True 1 320-360 8 9 GTK_FILL True 1 270-310 7 8 GTK_FILL True 1 220-260 6 7 GTK_FILL True 1 170-210 5 6 GTK_FILL True 1 130-160 4 5 GTK_FILL True 1 90-120 3 4 GTK_FILL True 1 50-80 2 3 GTK_FILL True 1 5 10 1 2 10 11 GTK_FILL True 0.80000001192092896 5 9 1 2 9 10 GTK_FILL True 0.80000001192092896 5 8 1 2 8 9 GTK_FILL True 0.80000001192092896 5 7 1 2 7 8 GTK_FILL True 0.80000001192092896 5 6 1 2 6 7 GTK_FILL True 0.80000001192092896 5 5 1 2 5 6 GTK_FILL True 0.80000001192092896 5 4 1 2 4 5 GTK_FILL True 0.80000001192092896 5 3 1 2 3 4 GTK_FILL True 0.80000001192092896 5 2 1 2 2 3 GTK_FILL True 0.80000001192092896 5 1 1 2 1 2 GTK_FILL True 1 20-40 1 2 GTK_FILL True 0.80000001192092896 5 0 1 2 GTK_FILL True 1 0-10 GTK_FILL False False 0 True False False 5 1 True gtk-ok True True True False True False False 0 False False 2 Play 150 True True 5 14 8 True 0 Options True vertical True True True 5 4 2 True 0 5 Played cards GTK_FILL True Select File 1 2 2 3 GTK_FILL GTK_FILL Show True True False True True 1 2 GTK_FILL True Text True True False True True True False False 0 Cards True True False True True show_as_text False False 5 1 1 2 1 2 GTK_FILL GTK_FILL True 0 5 Show as 1 2 GTK_FILL True 0 5 Filename 2 3 GTK_FILL True 0 5 Card width 3 4 GTK_FILL True True True 1 2 3 4 True Card display False True 5 2 2 True All True True False True True False False 0 North-South True True False True True show_dd_all False False 5 1 East-West True True False True True show_dd_all False False 2 None True True False True True show_dd_all False False 5 3 1 2 1 2 GTK_FILL GTK_FILL True 0 5 Show DD scores 1 2 GTK_FILL True All True True False True True False False 0 North-South True True False True True show_hand_all False False 5 1 East-West True True False True True show_hand_all False False 2 1 2 GTK_FILL True 0 5 Show hands GTK_FILL 1 True Hands 1 False True 5 4 3 True True 1 2 True 0.5 True True 1 3 3 4 GTK_FILL True 0.5 5 True True 1 3 1 2 GTK_FILL True True 2 3 2 3 True True 1 2 2 3 True 0 Players 2 3 GTK_FILL True 0 5 Title GTK_FILL 2 True Current board 2 False True True 5 automatic automatic in True True True 3 True Board list 3 False True 5 0 True True automatic automatic True True 0 True True True True False 0 True 0 5 deals 1 Generate True True True True 5 False 2 False 1 4 True Generate 4 False 0 True 5 5 end gtk-cancel True True True False True False False 0 gtk-apply True True True False True False False 1 gtk-ok True True True False True False False 2 False end 1 True normal (C) 2005-2016 Christoph Berg Bridge Hand Viewer and Editor http://www.df7cb.de/bridge/tenace/ Homepage tenace - bridge hand viewer and editor Copyright (C) Christoph Berg <cb@df7cb.de> 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. Christoph Berg <cb@df7cb.de> de: Christoph Berg <cb@df7cb.de> vertical False end 0 Text input 580 True True True Hand as string 63.A84.K853.KQ72 JT.QJT952.QJT62. Q9854.763.A7.A64 AK72.K.94.JT9853 0 gtk-ok True True False Set hand True False False 1 True gtk-print True gtk-jump-to