pax_global_header00006660000000000000000000000064107752332040014515gustar00rootroot0000000000000052 comment=0a477aaea125aa1ce0c57a65c6d0817e1dd7c5ff tagua-1.0-alpha2/000077500000000000000000000000001077523320400136235ustar00rootroot00000000000000tagua-1.0-alpha2/.gitignore000066400000000000000000000002101077523320400156040ustar00rootroot00000000000000*~ build patches CMakeCache.txt CMakeFiles CMakeTmp cmake_uninstall.cmake Makefile cmake_install.cmake DartTestfile.txt lib build.stamp tagua-1.0-alpha2/.kateconfig000066400000000000000000000000731077523320400157360ustar00rootroot00000000000000// kate: space-indent on; indent-width 2; mixedindent off; tagua-1.0-alpha2/AUTHORS000066400000000000000000000001661077523320400146760ustar00rootroot00000000000000Paolo Capriotti Maurizio Monge Yann Dirson tagua-1.0-alpha2/CHANGELOG000066400000000000000000000016721077523320400150430ustar00rootroot00000000000000Version 1.0 alpha 2 - "Raigor" ============================== 01-Mar-2008 * Ported to kdelibs 4.0. * Improved loading and saving of PGNs, now supporting more than just Chess. * New variants: Tori Shogi and Sho Shogi. * More consistent debug output. * Created a translation subsystem. * Added French and Czech translations. * Debian packaging. * Many bugs fixed. Version 1.0 alpha - "Clinkz" ============================ 01-Sep-2007 * Internal variant structure completely redesigned. * Chessboard and pool layout improved and made customizable. * More shogi themes. * New variants: Minichess, Minishogi. NOTE: Some features and variants that were in the 0.9 release got lost in refactoring. In particular, loading PGN's does not work anymore, and there are no more position editing facilities. Some of these features will be restored for the final 1.0 release, as well as the missing variants. Version 0.9 =========== 25-Sep-2006 * First release. tagua-1.0-alpha2/CMakeLists.txt000066400000000000000000000026431077523320400163700ustar00rootroot00000000000000PROJECT(tagua) CMAKE_MINIMUM_REQUIRED(VERSION 2.4.0) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) include(Tagua) if (NOT CMAKE_BUILD_TYPE) set(DEBUG_BUILD 0) else (NOT CMAKE_BUILD_TYPE) string(REGEX MATCH "debug" DEBUG_BUILD ${CMAKE_BUILD_TYPE}) endif (NOT CMAKE_BUILD_TYPE) # boost FIND_PACKAGE(Boost) # lua IF(SYSTEM_LUA) # use lua installed in the system INCLUDE(UsePkgConfig) IF(LUA_PKG) PKGCONFIG(${LUA_PKG} LUA_INCLUDE_DIRS LUA_LIBRARY_DIRS LUA_LINK_FLAGS LUA_CFLAGS) ELSE(LUA_PKG) PKGCONFIG(lua5.1 LUA_INCLUDE_DIRS LUA_LIBRARY_DIRS LUA_LINK_FLAGS LUA_CFLAGS) IF(NOT LUA_LINK_FLAGS) PKGCONFIG(lua LUA_INCLUDE_DIRS LUA_LIBRARY_DIRS LUA_LINK_FLAGS LUA_CFLAGS) ENDIF(NOT LUA_LINK_FLAGS) ENDIF(LUA_PKG) ADD_CUSTOM_TARGET(lua_library) ELSE(SYSTEM_LUA) # use the embedded lua source SET(LUA_BIN_DIR "${CMAKE_CURRENT_BINARY_DIR}/lua") SET(LUA_INCLUDE_DIRS "${LUA_BIN_DIR}/include") SET(LUA_LIBRARY_DIRS "${LUA_BIN_DIR}") SET(LUA_LINK_FLAGS lua) ADD_SUBDIRECTORY(lua) ENDIF(SYSTEM_LUA) ADD_DEFINITIONS(-fexceptions) find_package(KDE4 REQUIRED) include(KDE4Defaults) # blitz FIND_PACKAGE(Blitz REQUIRED) set(CMAKE_CXX_FLAGS_DEBUGFULL "${CMAKE_C_FLAGS_DEBUGFULL} -DTAGUA_DEBUG") add_definitions(-DQT_NO_KEYWORDS ${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) add_subdirectory(src) add_subdirectory(data) add_subdirectory(translations) enable_testing() add_subdirectory(tests EXCLUDE_FROM_ALL) tagua-1.0-alpha2/COPYING000066400000000000000000000431311077523320400146600ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. tagua-1.0-alpha2/INSTALL000066400000000000000000000020261077523320400146540ustar00rootroot00000000000000What you need ================== * A KDE4 development environment with kdelibs and libkdegames (>= KDE 3.92) * boost 1.34 (headers will suffice) Further you will need GNU make, a working C++ compiler (e.g. gcc 3.4.x or later) and CMake 2.4.7 or later. The following packages are optional: * lua (5.1.1, if it is not available you can use the internal copy) Preparations ================== Setting up a KDE4 development environment: Follow the tutorial at http://techbase.kde.org/Getting_Started/Build/KDE4 Alternatively, you can install KDE beta packages if your system supports them (e.g. debian, kubuntu, openSUSE). Compiling Tagua ================== Unpack the Tagua package, change to the package root directory, and type: mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=$KDEDIR -DCMAKE_BUILD_TYPE=release .. make -j2 make install If you want tagua to be linked to system lua instead that the internall one, add -DSYSTEM_LUA=1 to the command line, and optionally add -DLUA_PKG=xyz to specify the pkg-config lua package. tagua-1.0-alpha2/README000066400000000000000000000002211077523320400144760ustar00rootroot00000000000000Tagua - A generic board game application =========================================== For more information, visit http://www.tagua-project.org tagua-1.0-alpha2/RELEASE000066400000000000000000000031511077523320400146260ustar00rootroot00000000000000Introduction =============== Tagua is a generic board game application and framewok for KDE. It can be used as a replacement for chess applications like XBoard and Winboard, both for playing in internet servers and for local editing of games. However, Tagua is much more: it has an extensible board game infrastructure which makes developing new board games extremely easy. So far, a number of games have been developed, including Chess, Shogi and Xiangqi. Feature list =============== * Local editing of games: Games of chess and a number of variants (see below) can be edited and played locally. A user friendly and graphically appealing move list control provides a mean to visualize complicated subvariant nesting. * FICS / ICC compatible server support: Tagua can manage a connection to a FICS-like server, with which the user can interact using a detachable console. Games of any chess variant can be played, examined and observed. * Generic game support: Many board games can be easily implemented using the extensible Tagua infrastructure. So far, the following board games are implemented: - Chess - Chess 5x5 - Crazyhouse - Shogi - Minishogi * Graphics: Tagua features an advanced animation engine which can be easily extended on a per-variant basis. It includes a powerful theme loader based on lua scripts that allows to dynamically create effects like drop down shadows. Themes can customize the appearance of pieces, board squares and borders, clocks, backgrounds and the layout of all these elements. For more information, screenshots and design notes, visit http://www.tagua-project.org tagua-1.0-alpha2/TODO000066400000000000000000000055211077523320400143160ustar00rootroot00000000000000FEATURES: [DONE] * Play from any position. [PARTIALLY DONE] * Implement a real SDI interface. * Configuration dialog. * General: language choice, automatically connect on startup, default variant, etc... * Connection: manage ics connections and options. * [DONE] Highlighting: manage highlighting patterns for the ics console. * [DONE] Animations: animation speed, graphical effects, etc... * [DONE] Theme: manage themes and theme options; choose default theme; associate themes with variants. * [DONE] Movelist: colors, fonts, animations and graphical effects preferences. * [PARTIALLY DONE] Clock: colors and fonts. * [BROKEN] Engine: List of engines, with type, command line options, working path, etc... * GUI Tuning. Many things still have to be done to make the gui really user friendly (think about the Panda): * Message boxes to notify the user of error, for instance while connecting. * Restore a functional status bar. [SKETCHED] * Add some game info between the pools (like "FICS, rated crazyhouse") * Notify the user of Server/Engine events. I don't like the Babaschess-like popup when i get a match request, i'd prefer an amarok-like notification. CURRENT RELEASE: [DONE] * Set up a decent installation system, maybe with a cool one-click windows (linux?) installer. [MOSTLY DONE] * Improve default highlighting script. [DONE] * Add support for multiple ICS interactions. [MOSTLY DONE] * More robust ICS support: do not crash when testing invalid moves. [DONE] * About dialog. [DOME] * Choose an icon for the application. FUTURE RELEASES: * Better support for variants in pgn games * Pgn game list * Fix examination variant upgrade * Game print support, through khtml? * Ability to define a variant in some script language (ruby or lua or ...) * Complete support for chess engines or variant specific AI. * An advanced Edit Position mode, with the ability to edit a position for an arbitrary variant, as well as the various flags such as the en passant square, etc... * Improve Examine Mode and Observe Mode: Movelist support for examination is not as extensive as it could, and I don't know if it will ever be. Problems: * [FIXED] Crash when going back to the starting position * [FIXED] Moves are sometimes not correctly displayed even where there's enough information available. Future possible features: * Execute move immediately instead waiting the server response, when possible. Note: this may prove hard to implement correctly, because one needs to filter out server responses (after a suitable consistency check) so that they do not cause wrong updates if they come out when they are already obsolete. * Display variations correctly in the movelist, instead of always replacing mainline entries. Note: hard to do, because the protocol sends very few information about the reason of a style12 update. tagua-1.0-alpha2/TODO_Maurizio000066400000000000000000000033231077523320400161730ustar00rootroot00000000000000[DONE] - make the board support generic square tags, instead of select, premove, etc. [DONE] - make the board load squares and tags from a theme. [FORFAITED] - implement edit position. [DONE] - improve piece shadow (just a couple more configurable settings). [DONE] - the table should not dispatch mouse events based on the group, because group size is "virtual". [DONE] - document the pixmap loader, or soon it will be impossible to use (even for me). [PARTLY DONE] - fix examination mode. - reimplement piecesprite thumbnails. [DONE] - remove all "../icons" in the code [DONE] - improve the movelist to handle mixed turns [WONTFIX :)]- rewrite the piece pool. Now the conceptual bug of the PieceSprite's having type/color information is fixed, but i think that a std::map is ok for the pool because identical things should not be threated as different, if for two pieces ->equals returns true they should really be identical, for sake of god. [DONE] - manage in some way the with piece pool. - better pgn load/save for variants with irregular moves (like progressive) - add support for editing pgn game tags [DONE by Paolo :)] - add support for one click move preview in the board [DONE for reversi] - add support for games where you can or must pass the move (go, reversi, etc) [HALF DONE] - move in the variant the square numbering string and the SAN move figurines - support fonts for move figurines - investigate pcre as a possible replacement for QRegExp. - remove all code that assumes that there are 2 players :) - allow to customize fg and bg of svg files too, in some way (a CSS file? but Paolo will get angry because this will require Qt-4.2, or maybe 4.3. They are not even supported in the snapshot anyway) tagua-1.0-alpha2/TODO_Riccardo000066400000000000000000000000451077523320400161200ustar00rootroot00000000000000[IN PROGRESS] * Do the analog clock tagua-1.0-alpha2/TODO_shogi000066400000000000000000000017001077523320400155020ustar00rootroot00000000000000tagua core: - gnushogi engine gets confused when moving through history => generic pb ? - tooltips for figurines, for people who can't read kanji - allow for more complex moves (eg. Lion in Chu Shogi) -> maybe by splitting target square, so the piece gets all different moves in one click, depending on which part of the square is hit ? - allow to setup and play problems (tsume shogi) engines/core: - engine options (eg. select difficulty level) - do not allow selection of more than 1 engine for the same side - allow to declare engines system-wide shogi variant: - decorated move could show captured piece gnushogi engine: - gnushogi engine should catch "Illegal move: " notices from gnushogi - engine should detect endgame conditions from gnushogi: "Drawn game!" "Black mates!" (gnushogi only reports a draw on one side !?) - support for time fetching games from the net for learning: - http://play.chessvariants.org/ - http://brainking.com/ tagua-1.0-alpha2/add_variant.rb000077500000000000000000000006211077523320400164260ustar00rootroot00000000000000#!/usr/bin/ruby require 'erb' TEMPLATE = 'templates/variant_template' VARIANT_DIR = 'src/variants' variant = ARGV.shift or exit %w(h cpp).each do |ext| File.open(TEMPLATE + ".#{ext}.erb") do |f| template = ERB.new(f.read) out = File.join(VARIANT_DIR, variant + ".#{ext}") File.open(out, 'w') do |outfile| outfile.write(template.result(binding)) end puts "generated #{out}" end end tagua-1.0-alpha2/cmake/000077500000000000000000000000001077523320400147035ustar00rootroot00000000000000tagua-1.0-alpha2/cmake/FindCPPUNIT.cmake000066400000000000000000000020321077523320400176250ustar00rootroot00000000000000# - Try to find the libcppunit libraries # Once done this will define # # CPPUNIT_FOUND - system has libcppunit # CPPUNIT_INCLUDE_DIR - the libcppunit include directory # CPPUNIT_LIBRARIES - libcppunit library FIND_PATH(CPPUNIT_INCLUDE_DIR Test.h PATHS /usr/include/cppunit /usr/local/include/cppunit ) FIND_LIBRARY(CPPUNIT_LIBRARIES NAMES cppunit PATHS /usr/lib /usr/local/lib ) # IF(CPPUNIT_INCLUDE_DIR) # message (STATUS "found cppunit include dir: ${CPPUNIT_INCLUDE_DIR}") # ENDIF (CPPUNIT_INCLUDE_DIR) # # IF(CPPUNIT_LIBRARIES) # message (STATUS "found cppunit libraries: ${CPPUNIT_LIBRARIES}") # ENDIF (CPPUNIT_LIBRARIES) IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) SET(CPPUNIT_FOUND 1 ) if(NOT CPPUNIT_FIND_QUIETLY) message(STATUS "Found cppunit: ${CPPUNIT_LIBRARIES}") endif(NOT CPPUNIT_FIND_QUIETLY) ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) SET(CPPUNIT_FOUND 0 CACHE BOOL "Not found cppunit library") ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) MARK_AS_ADVANCED(CPPUNIT_INCLUDE_DIR CPPUNIT_LIBRARIES) tagua-1.0-alpha2/cmake/Tagua.cmake000066400000000000000000000011231077523320400167430ustar00rootroot00000000000000macro(install_local_dir local_dir install_dir) file(GLOB_RECURSE inst_files ${local_dir}/*) foreach(inst_file ${inst_files}) # message("file1 = ${CMAKE_CURRENT_SOURCE_DIR}") # message("file2 = ${inst_file}") file(RELATIVE_PATH rel_file ${CMAKE_CURRENT_SOURCE_DIR} ${inst_file}) # message("rel file = ${rel_file}") get_filename_component(rel_dir ${rel_file} PATH) # message("rel dir = ${rel_dir}") install(FILES ${inst_file} DESTINATION ${DATA_INSTALL_DIR}/${install_dir}/${rel_dir}) endforeach(inst_file) endmacro(install_local_dir local_dir install_dir) tagua-1.0-alpha2/data/000077500000000000000000000000001077523320400145345ustar00rootroot00000000000000tagua-1.0-alpha2/data/.gitignore000066400000000000000000000000561077523320400165250ustar00rootroot00000000000000DartTestfile.txt Makefile cmake_install.cmake tagua-1.0-alpha2/data/CMakeLists.txt000066400000000000000000000002071077523320400172730ustar00rootroot00000000000000add_subdirectory(highlighting) add_subdirectory(pics) add_subdirectory(piece_icons) add_subdirectory(scripts) add_subdirectory(themes) tagua-1.0-alpha2/data/highlighting/000077500000000000000000000000001077523320400172015ustar00rootroot00000000000000tagua-1.0-alpha2/data/highlighting/.gitignore000066400000000000000000000000561077523320400211720ustar00rootroot00000000000000DartTestfile.txt Makefile cmake_install.cmake tagua-1.0-alpha2/data/highlighting/CMakeLists.txt000066400000000000000000000001231077523320400217350ustar00rootroot00000000000000install(FILES highlighting.lua DESTINATION ${DATA_INSTALL_DIR}/tagua/highlighting) tagua-1.0-alpha2/data/highlighting/highlighting.lua000066400000000000000000000017641077523320400223610ustar00rootroot00000000000000on["^(%S+) tells you: "] = function() sentence = line(match.to, line.to) sentence.bold = true nick = Text("<" .. ref[1].text .. "> ") nick.color = "#104050" return nick + sentence end on["^%S+ rating adjustment:|^No rating adjustment done."] = function() -- send_text("Thank you") return line end filter("^<12>") filter("^") nick = "" -- Notification highlight["^(?:Present company includes|Notification|Challenge|You|:).*$"] = { color = Color(158,29,180) } -- Seek on["(^%S+%s%((%d|%+)+%))( seeking .*) %(\"play (%d+)\" to respond%)"] = function() ref[4].bold = true return ref[1] + ref[3] + Text(" ==> ") + ref[4] end -- Channel tell highlight["^%S+%((%d|%+)+%):.*$"] = { color = Color(177,130,0) } -- Shouts highlight["^(?:%-%->|%S+%s+(?:(?:c%-)?shouts:)).*$"] = { color = Color(0,145,65) } -- Game highlight["^(?:%{|Game|Creating).*$"] = { bold = true, color = Color(214,0,3) } -- Tells -- highlight["^%S+%s+tells you.*$"] = { -- color = Color(0,40,221) -- } tagua-1.0-alpha2/data/pics/000077500000000000000000000000001077523320400154725ustar00rootroot00000000000000tagua-1.0-alpha2/data/pics/.gitignore000066400000000000000000000000561077523320400174630ustar00rootroot00000000000000DartTestfile.txt Makefile cmake_install.cmake tagua-1.0-alpha2/data/pics/CMakeLists.txt000066400000000000000000000002331077523320400202300ustar00rootroot00000000000000install(FILES promoteBishop.png promoteKing.png promoteKnight.png promoteQueen.png promoteRook.png DESTINATION ${DATA_INSTALL_DIR}/tagua/pics) tagua-1.0-alpha2/data/pics/promoteBishop.png000066400000000000000000000061201077523320400210310ustar00rootroot00000000000000PNG  IHDR00%bKGD pHYsHHFk> vpAg00W IDATxy|T'$d–@P1j,.aEHk)JXlU("` aKHH&:!3ᅡ_r=ݳLt}ODM,#|=!=z*OpR} f :=c-?Sp^ ,9#z7].lX|gzZ5UpS_0[+@ v:[pۻޞ_iˏZ> .NP/ӭ3p{䑂 :^V]+`H }-LV ZSotK_Wi7NC Z*{>k X}-ZG*­C~\T"=A# 91# 5DpX_K(bf%n'z_:%8|J_Ud=kLcys+u F_łTis zVpS:bh_K z!V]ha`߮w?.Kl+Wp!i Sa}+;75/昺9cICW7Rl2 N®rv;6ALw"~`AuGخ=B9[ Z:@g|"ح>W9q J>$rn1Ƨ>ܑ.$㙞q=?""X-SgRY]y\܏s>(~w~C.~|c"Ӄoh.8aFBf5v?~ߧ>xAKWR^9&OԻu1/ >G|~%X4@m߃K^!؁dy`:Ru\qB/i5O`o}-*Ȃ >:SK:a:xg$==yvCwDMԉй|XmD/O^0=M ^`~C߭==ZUP'Kf_]ǴDFprFKxjZ['ɂ̍T/a vq30Zrܱ/ ^7-؋Dsa,h'P:L(7^\5ơ:Q m#ڂwB9y=^~0F^c'6S,BWn"!+!D0_Jђ3XC{ &~ Ɠ7WݵP0`*y۩-~edÝ,ӹA .'phyѼߩ*`.'4wPGbmI-7(%4qE0zg|vV8fd&rD7F~Y~*:LX ΍1VNFA}K2kmg"I do Z>[y6ʘγ ig7w ˡ*L'VrDV6$F ‰ gҥ[\eWGw[2(:&"R BGS1g"zNZ)&St g!:7`MjSⶭi&TM?MmNynKNF[XBcJR EnqG[NNq`I (F;'Ԅ*YSj-RTCs팢%TMw=Mw#-U |b_C"x.70nKOnav+)qO?@g;fҎpjYӏ`Ć41sa~)/wuϒ?Ʋ*b95/oLJj_Z;S.G$#/D4橂TΆT~u'͜WDr]ͯӟ"ܻlKrtl2 -Ἡ5ia5cYγq\^*y^L58|ڎsU[D395\T\<9s=/Qs2n-r[m1ƫN9_e븂= qEm0*ƛ^TBWT!*]d5Wx2ޟ=e>cKZC2l?OU?3/*ՄIV| 2{Nv{jT¦17}sv?J9f 'nUj>/b3B`|3֘!"UwqlX2A0U6TwWκ "|H7~&c)k6:Xx9Fw#j2/ȩe9:j2PYށ_+$VNhg~"g Ш1o,>8OkGUtf"ޔ^9M9rYQC9![3rlԜT\S%RZ̧-ND^TCڝu F2ʲV&DVVI"hAPA#"r>(dAHKՕU%,q?CΧ o1H^3~HІ\*t2oc7r2^umtuH/w'IENDB`tagua-1.0-alpha2/data/pics/promoteKing.png000066400000000000000000000061641077523320400205050ustar00rootroot00000000000000PNG  IHDR00%bKGD pHYsHHFk> vpAg00W IDATxyxUߒ$HX 1*)&֥ DQZ nV)EPDB(  T !FBmnon_e{~?93̙sLLO)ˆυ}CMދ ?oГ3w}s*'?byZvzWKBw{ Y(V:.{cϩ Co@KP;>S+^`*;W0D.&|04 ka®W"; {N^(5b..RȊ9B{"-w"ɣWne7! 1#K~Z=4B -υ_ ͘[gx (ja@amfvkv‹Jīr ^C.NC.+!.*/|k ]=m:Jqw{Q)I/%,,t.Z lg_!,M؇x:[m.?z[ma0f:)& Mлcz O}!,>,~n"K8Χ0ʊamaykOeQ q$tcR*wWn958'cmFNҀ4}¾(?=sSBc.x3?SO^Iv@k@N7lz"^bHQh=j3^B6mb"X!1Ko{"H.V+Pk)ܲ1‘~ D(ךH *l a]47Mf1N @=|,bLOWaݤ} oӄ0sڶ.WTʸ ̔]MtMaaDj}FAVLIM*k$s I`"mMs^tT9}r8|4%͂c7`$]4Ox/NA&ʹ2k3B ?hOܯ3 #YHGv3>s /9^={{?Em,P1qj08JU 7X P_2XGB>`Pdf=;_>'mO;3?Wɧi,H#Sj#_4&vn7Լ$P SqQ_轝Dr3&@V W;yo':P֯Aə6Mv!-Qk<3?Sg3 W{oNJ)];(9¸gpNP?od5{{ڽe@;U9#-RB-ظe<\ .';ȕw\x!QcD*.Ee]IԿ;P+2!) Lgkt)諚p]FFi ࿏7& lc.m1 h^Ǧ s,1YAN5NdƗL]r]VbxjG1&/=VlbN ;;Ӷ%|+7%q쑋09-M}_$#WI m Jҁ@0=!`z \.JWq9Ar/'u[ ɨڝ۹cT8zܩ 4na2 YIP]EDc> L+G)%\γd>lj(jfxYf,D֗ VkzMw3F vpAg00WIDATxyTUgPNz,(ͭ,c*Z rm̊r̬<j.(n!6*$*3 3ska''?3{y?ܐ!3_;֬y&h3XffAWspK`$-sfA;7~RoKx(;$< ݅ѪeUD"=#,X[|lޖU1rG'fQrn#`ri+X}_^:X>sgA{yj .|2";ޖˢ6ecT~ <e`GzI*;#h^}MŁ@eĖRjT6=tvQx s[L<|w5F"ׁ N0~ ۀTz pߙ[pq_J;q&YK=a$1|7^4X=m,ɺD"ħAc.m&gnd cpRքenNdh,Hԯ}9ip c}t`O`.Ǭyg~3~D=sb>[B6ׅ2V0P".LF_ XEhmt8 Jb򬨾wCxPK |6z7y/s.zDE< W=H#Ot:z/*E*x>$*~_<Ѯgh7P/&F\*_pq4>zU( }·)_`78J%xv+gao?Y)frQz>&ΐS(tͲ+M }} ѢU]Nn }` 7MJ#_^+8ʵӳ[sf"ӸVmb|NKaʵ :Zl3+! {GByX!IZ~ f@ pG;&=I52,zx@TR#$$ꇽ;lv&3dXUPS15vDC8Zwkq4FkƂ}_3빅7K_baMUlkpc6{-> L:dI-_KaUd}w6$K(2`׈ 6duĂqWvdɑk??M v;)ʆ21 c M9cyɓgޅWt.zpf屽2i7"' ko_]qY%\Mu3<Pnb%[]R^v l5`P_Sp?c$i#bv*wؚU'K3rd_3[NVR8[(I>R?nVmvLTv$!>Uq/,s$Uey#|!M\tW2ԸC8#pաq8Mԫ3;z|:fM` P+b.$ɶn<& 9R\`2G!gVXwx.P罙: RŘ++tpf>JH 1}|F7bes!#?*vn_QfW܎ZZ5&e<^k π VC$&a'L_G%"S|`;fH>r&,Fn6$vzUW5J55R򮀗1ְrҊNRV[8X YcgC{_I<:OL+2&\ayDn|lb>NbU*RUz Lhzh{32y 9M,'1E2d_96(W\ |+L7ݻ@5\,*cfYpCt煌3IENDB`tagua-1.0-alpha2/data/pics/promoteQueen.png000066400000000000000000000063311077523320400206660ustar00rootroot00000000000000PNG  IHDR00%bKGD pHYsHHFk> vpAg00W dIDATxyxT'L,\ڪUnآU" VP)biȢR?@HQCLdf2{~KHe}wy{wrZNi9-唒 a5Naxav*~jMϤ͹¹ =9B| I˜ޡħo=$m #. dv,S l:۰vN_Z>@so.<&,tf~j[~7Lxlpog|aߜkp埅A.^; r~=1;^S(l-m E~:d_n/0|д/.G>6}7f M $iQZa0Emz~0Z!}/Naaٯ /?fkm;6  H)|&at9EO_GD׿\XJ/c@;0]=&v+f g~pgPXGrCZ)OO'e*g0sP {.qѐ2 K ',4Fn F|C^˯gĠI^Gӱ_sPgdNn>ӄsCf%l(*Q]}0b.1kcFK*^xUzUEFTmI{tW%mׯwBY7'RɅL6W쫝?N5^Ѻ–ڷ.ܹY߷OwDUZ=q1--Sua&ۉK4M|;Ew&Q*\k؋l&ק,ab}O9;;ۋb ǷWV WfNةX8O,8o CӤˊ{s>|kbB{ƾo)t ^<muDU+&c#:4N83#v;H %Lo[…o|#l+iw6hM^/+a:cwSvn+ Z =t;O;,$twӫVt')|^#\7M+6l+sԁ"N$Y|@ߟ :5FX1)}su aC|3y PZx9 w7aᱮRx3ݺgOWzO#h.?KaJ"_nla/zG1]tCƜmaMGK~9AnFңoLK.ǰ]_ Ki>]$}.oCSɋu2|yz R GϹR[B.fmͳgWga$`bݨE-tc">8dl}<+$VuzIԕ}njg~lսz4&{L]Ok/#9,4?0DZNå^-Go6>@ >~d,NI~ЈzVO&ǯIKAK51{ޓ> %jEߒ;~tnl^`N{(>jB0 yلiۦ;. j4^9C{jfUzGxNB r9/끹'.J_/L]-|5G$|LA܆a(DJµu(=k+ pi&k=c2.qlcog a>]#7omD6@?!!)Ǥ>h6DߗNJ]/N}3& K(ʏ 囊Org'F4jCLAFz'+vݖ(l[ ldq^QeVOzzC pt32A®u#uр;`b _A#>iY~T WǞЫ^#J AYztaA6)#ՋB+艩tz]o1ђAgIa1[_]sõ^UwqȖJsцj 03uB|b4.k> %a²Dy.:`}$]o AGc}(6Z|K`|۸a9tVhΞI.zQ0H ?Hk|l'ZC $z]ܙsD+l3;Ԋ2xZ+"=>,96N3!vuJO{iXt~mB\[~rR5YƷyReZZz#MkdK'!\O Ҋm%=h, '0Y Zc@ZDr+z>R-52|<$Ϫ7pq6n+E ¶>^H)o.K|Aå2 C_c+4o H\Y8QH8QJI4U0@? NVqM.b_qrWɖc\#o./fŞ kKlC: (f笌lDp1_ǩR% 0@,=@Xz0vk6I&q kru&>$,d#uJ3.x]ǵ~@Cm&uZ~CCVǗhnZ{ f:{"9@J☑AdҎetyƷ8 5QJl\Lo:[*J٨ <┃?hIpJZYOe,û.Hc80PQP CƹSV8%: uh$#V\PyrK+![YK^S]w vpAg00W IDATxktg̓A0@P%u)P./|S'i _ ߿]cpjaӧiq) /-޹Jpº։?%7¢L_" |Kؼ(vc;@8jθ[WzCp7R狞?'<ɝ߁6tw_ _g E $K;_3^ch'8O>.O@NpcF&]K >-|t01;F'\Ui֫0_R_ _*I\^X/4Y͆ 0Uf Piλ/r\3#\>[b9k[w:&`/zT8D8gf)Oɥ  =n6|ba~^7Ϣ^A*ѯo/|]_;}=۹xf?֠ +?-]U# iWV7,IpZ$Mѯ ia@0WZjY:O> l+)O/1b|UFVߓazXn)7; ; [!b.»}>B+U[mQ8H@Wk~weS7n^ӑr)*cI,5Y [qֲ}/;x2 8r1;sOlLJ̝yCh"FC^MLr6e,'dJZPIG!L 3{=#{߮MqK OZǻa?kwy<,v wwz(B?uʧsG=+N/;Ҿҋ=IÓ Ǚ`9og滤fd  7%jǧPJĜ8PxE]w7Vt%ځ545;eHb3^6/_:q,m/|tLu𬛳)(oc}$:9[cB"ZA<ϐ_P(6֞Na vpAg00W IDATxy|T'$d–@P1j,.aEHk)JXlU("` aKHH&:!3ᅡ_r=ݳLt}ODM,#|=!=z*OpR} f :=c-?Sp^ ,9#z7].lX|gzZ5UpS_0[+@ v:[pۻޞ_iˏZ> .NP/ӭ3p{䑂 :^V]+`H }-LV ZSotK_Wi7NC Z*{>k X}-ZG*­C~\T"=A# 91# 5DpX_K(bf%n'z_:%8|J_Ud=kLcys+u F_łTis zVpS:bh_K z!V]ha`߮w?.Kl+Wp!i Sa}+;75/昺9cICW7Rl2 N®rv;6ALw"~`AuGخ=B9[ Z:@g|"ح>W9q J>$rn1Ƨ>ܑ.$㙞q=?""X-SgRY]y\܏s>(~w~C.~|c"Ӄoh.8aFBf5v?~ߧ>xAKWR^9&OԻu1/ >G|~%X4@m߃K^!؁dy`:Ru\qB/i5O`o}-*Ȃ >:SK:a:xg$==yvCwDMԉй|XmD/O^0=M ^`~C߭==ZUP'Kf_]ǴDFprFKxjZ['ɂ̍T/a vq30Zrܱ/ ^7-؋Dsa,h'P:L(7^\5ơ:Q m#ڂwB9y=^~0F^c'6S,BWn"!+!D0_Jђ3XC{ &~ Ɠ7WݵP0`*y۩-~edÝ,ӹA .'phyѼߩ*`.'4wPGbmI-7(%4qE0zg|vV8fd&rD7F~Y~*:LX ΍1VNFA}K2kmg"I do Z>[y6ʘγ ig7w ˡ*L'VrDV6$F ‰ gҥ[\eWGw[2(:&"R BGS1g"zNZ)&St g!:7`MjSⶭi&TM?MmNynKNF[XBcJR EnqG[NNq`I (F;'Ԅ*YSj-RTCs팢%TMw=Mw#-U |b_C"x.70nKOnav+)qO?@g;fҎpjYӏ`Ć41sa~)/wuϒ?Ʋ*b95/oLJj_Z;S.G$#/D4橂TΆT~u'͜WDr]ͯӟ"ܻlKrtl2 -Ἡ5ia5cYγq\^*y^L58|ڎsU[D395\T\<9s=/Qs2n-r[m1ƫN9_e븂= qEm0*ƛ^TBWT!*]d5Wx2ޟ=e>cKZC2l?OU?3/*ՄIV| 2{Nv{jT¦17}sv?J9f 'nUj>/b3B`|3֘!"UwqlX2A0U6TwWκ "|H7~&c)k6:Xx9Fw#j2/ȩe9:j2PYށ_+$VNhg~"g Ш1o,>8OkGUtf"ޔ^9M9rYQC9![3rlԜT\S%RZ̧-ND^TCڝu F2ʲV&DVVI"hAPA#"r>(dAHKՕU%,q?CΧ o1H^3~HІ\*t2oc7r2^umtuH/w'IENDB`tagua-1.0-alpha2/data/piece_icons/k.png000066400000000000000000000061641077523320400177630ustar00rootroot00000000000000PNG  IHDR00%bKGD pHYsHHFk> vpAg00W IDATxyxUߒ$HX 1*)&֥ DQZ nV)EPDB(  T !FBmnon_e{~?93̙sLLO)ˆυ}CMދ ?oГ3w}s*'?byZvzWKBw{ Y(V:.{cϩ Co@KP;>S+^`*;W0D.&|04 ka®W"; {N^(5b..RȊ9B{"-w"ɣWne7! 1#K~Z=4B -υ_ ͘[gx (ja@amfvkv‹Jīr ^C.NC.+!.*/|k ]=m:Jqw{Q)I/%,,t.Z lg_!,M؇x:[m.?z[ma0f:)& Mлcz O}!,>,~n"K8Χ0ʊamaykOeQ q$tcR*wWn958'cmFNҀ4}¾(?=sSBc.x3?SO^Iv@k@N7lz"^bHQh=j3^B6mb"X!1Ko{"H.V+Pk)ܲ1‘~ D(ךH *l a]47Mf1N @=|,bLOWaݤ} oӄ0sڶ.WTʸ ̔]MtMaaDj}FAVLIM*k$s I`"mMs^tT9}r8|4%͂c7`$]4Ox/NA&ʹ2k3B ?hOܯ3 #YHGv3>s /9^={{?Em,P1qj08JU 7X P_2XGB>`Pdf=;_>'mO;3?Wɧi,H#Sj#_4&vn7Լ$P SqQ_轝Dr3&@V W;yo':P֯Aə6Mv!-Qk<3?Sg3 W{oNJ)];(9¸gpNP?od5{{ڽe@;U9#-RB-ظe<\ .';ȕw\x!QcD*.Ee]IԿ;P+2!) Lgkt)諚p]FFi ࿏7& lc.m1 h^Ǧ s,1YAN5NdƗL]r]VbxjG1&/=VlbN ;;Ӷ%|+7%q쑋09-M}_$#WI m Jҁ@0=!`z \.JWq9Ar/'u[ ɨڝ۹cT8zܩ 4na2 YIP]EDc> L+G)%\γd>lj(jfxYf,D֗ VkzMw3F vpAg00WIDATxyTUgPNz,(ͭ,c*Z rm̊r̬<j.(n!6*$*3 3ska''?3{y?ܐ!3_;֬y&h3XffAWspK`$-sfA;7~RoKx(;$< ݅ѪeUD"=#,X[|lޖU1rG'fQrn#`ri+X}_^:X>sgA{yj .|2";ޖˢ6ecT~ <e`GzI*;#h^}MŁ@eĖRjT6=tvQx s[L<|w5F"ׁ N0~ ۀTz pߙ[pq_J;q&YK=a$1|7^4X=m,ɺD"ħAc.m&gnd cpRքenNdh,Hԯ}9ip c}t`O`.Ǭyg~3~D=sb>[B6ׅ2V0P".LF_ XEhmt8 Jb򬨾wCxPK |6z7y/s.zDE< W=H#Ot:z/*E*x>$*~_<Ѯgh7P/&F\*_pq4>zU( }·)_`78J%xv+gao?Y)frQz>&ΐS(tͲ+M }} ѢU]Nn }` 7MJ#_^+8ʵӳ[sf"ӸVmb|NKaʵ :Zl3+! {GByX!IZ~ f@ pG;&=I52,zx@TR#$$ꇽ;lv&3dXUPS15vDC8Zwkq4FkƂ}_3빅7K_baMUlkpc6{-> L:dI-_KaUd}w6$K(2`׈ 6duĂqWvdɑk??M v;)ʆ21 c M9cyɓgޅWt.zpf屽2i7"' ko_]qY%\Mu3<Pnb%[]R^v l5`P_Sp?c$i#bv*wؚU'K3rd_3[NVR8[(I>R?nVmvLTv$!>Uq/,s$Uey#|!M\tW2ԸC8#pաq8Mԫ3;z|:fM` P+b.$ɶn<& 9R\`2G!gVXwx.P罙: RŘ++tpf>JH 1}|F7bes!#?*vn_QfW܎ZZ5&e<^k π VC$&a'L_G%"S|`;fH>r&,Fn6$vzUW5J55R򮀗1ְrҊNRV[8X YcgC{_I<:OL+2&\ayDn|lb>NbU*RUz Lhzh{32y 9M,'1E2d_96(W\ |+L7ݻ@5\,*cfYpCt煌3IENDB`tagua-1.0-alpha2/data/piece_icons/p.png000066400000000000000000000040441077523320400177630ustar00rootroot00000000000000PNG  IHDR00%bKGD pHYsHHFk> vpAg00WIDATxyPUU}="`X.DKai8CICTdhSIjY.5ibN6k6E0 x8s߰ʻ={} ^׼5yk^o#uE@`R0b sr?~Pvk3_ Z]ǔ#NEu?9i`Ʒ`C;͘ >yTבj\~Zv^7_. L,z~2!{ĬS`VP8b914uo,׵I[`ݲ{.ٔ^7%pa!hɻ[$jwMN$[`  L=8=gsTٞdQ\.޸ I yj [ FYz>)%\vL=&N־PI|D6hizZ1~[V?WM-AYf2CÍ` L;:26 ɖۓ[rn1(Ֆ[7k =/dIpx1س;؛l$p$Z[;hPv%[[0u*k+RA{R-ŀkI<.dʲj= e%^pfM84NԽ`@ut@6'K[z^z9 [ vwj*ޗ/:h7QlIz-t$2lˡ&/z>vBDS('r1Z.SL{!Ac"ϒb#ўUc>P'WGO1sL^cN#g1NCPdp#`\՜gG]\(yM\XXO#+*aPZ|Rfc5;Z8L:? 8&VF\3`_NCNi\fF,vPQ*#`ݽBA#kt 圠 :v_ZѺ`qS}+4XjmAp4(sY׹rNrTHП҈bFvP8*wGFOݓ f GgV}_y;dVvM] V'Y{WC=IoHk5&no=;n+i@=mj`e=PFʴ8y`m(c9D\NÊ)S|ΊKJ[ f3r@#q8` vpAg00W dIDATxyxT'L,\ڪUnآU" VP)biȢR?@HQCLdf2{~KHe}wy{wrZNi9-唒 a5Naxav*~jMϤ͹¹ =9B| I˜ޡħo=$m #. dv,S l:۰vN_Z>@so.<&,tf~j[~7Lxlpog|aߜkp埅A.^; r~=1;^S(l-m E~:d_n/0|д/.G>6}7f M $iQZa0Emz~0Z!}/Naaٯ /?fkm;6  H)|&at9EO_GD׿\XJ/c@;0]=&v+f g~pgPXGrCZ)OO'e*g0sP {.qѐ2 K ',4Fn F|C^˯gĠI^Gӱ_sPgdNn>ӄsCf%l(*Q]}0b.1kcFK*^xUzUEFTmI{tW%mׯwBY7'RɅL6W쫝?N5^Ѻ–ڷ.ܹY߷OwDUZ=q1--Sua&ۉK4M|;Ew&Q*\k؋l&ק,ab}O9;;ۋb ǷWV WfNةX8O,8o CӤˊ{s>|kbB{ƾo)t ^<muDU+&c#:4N83#v;H %Lo[…o|#l+iw6hM^/+a:cwSvn+ Z =t;O;,$twӫVt')|^#\7M+6l+sԁ"N$Y|@ߟ :5FX1)}su aC|3y PZx9 w7aᱮRx3ݺgOWzO#h.?KaJ"_nla/zG1]tCƜmaMGK~9AnFңoLK.ǰ]_ Ki>]$}.oCSɋu2|yz R GϹR[B.fmͳgWga$`bݨE-tc">8dl}<+$VuzIԕ}njg~lսz4&{L]Ok/#9,4?0DZNå^-Go6>@ >~d,NI~ЈzVO&ǯIKAK51{ޓ> %jEߒ;~tnl^`N{(>jB0 yلiۦ;. j4^9C{jfUzGxNB r9/끹'.J_/L]-|5G$|LA܆a(DJµu(=k+ pi&k=c2.qlcog a>]#7omD6@?!!)Ǥ>h6DߗNJ]/N}3& K(ʏ 囊Org'F4jCLAFz'+vݖ(l[ ldq^QeVOzzC pt32A®u#uр;`b _A#>iY~T WǞЫ^#J AYztaA6)#ՋB+艩tz]o1ђAgIa1[_]sõ^UwqȖJsцj 03uB|b4.k> %a²Dy.:`}$]o AGc}(6Z|K`|۸a9tVhΞI.zQ0H ?Hk|l'ZC $z]ܙsD+l3;Ԋ2xZ+"=>,96N3!vuJO{iXt~mB\[~rR5YƷyReZZz#MkdK'!\O Ҋm%=h, '0Y Zc@ZDr+z>R-52|<$Ϫ7pq6n+E ¶>^H)o.K|Aå2 C_c+4o H\Y8QH8QJI4U0@? NVqM.b_qrWɖc\#o./fŞ kKlC: (f笌lDp1_ǩR% 0@,=@Xz0vk6I&q kru&>$,d#uJ3.x]ǵ~@Cm&uZ~CCVǗhnZ{ f:{"9@J☑AdҎetyƷ8 5QJl\Lo:[*J٨ <┃?hIpJZYOe,û.Hc80PQP CƹSV8%: uh$#V\PyrK+![YK^S]w vpAg00W IDATxktg̓A0@P%u)P./|S'i _ ߿]cpjaӧiq) /-޹Jpº։?%7¢L_" |Kؼ(vc;@8jθ[WzCp7R狞?'<ɝ߁6tw_ _g E $K;_3^ch'8O>.O@NpcF&]K >-|t01;F'\Ui֫0_R_ _*I\^X/4Y͆ 0Uf Piλ/r\3#\>[b9k[w:&`/zT8D8gf)Oɥ  =n6|ba~^7Ϣ^A*ѯo/|]_;}=۹xf?֠ +?-]U# iWV7,IpZ$Mѯ ia@0WZjY:O> l+)O/1b|UFVߓazXn)7; ; [!b.»}>B+U[mQ8H@Wk~weS7n^ӑr)*cI,5Y [qֲ}/;x2 8r1;sOlLJ̝yCh"FC^MLr6e,'dJZPIG!L 3{=#{߮MqK OZǻa?kwy<,v wwz(B?uʧsG=+N/;Ҿҋ=IÓ Ǚ`9og滤fd  7%jǧPJĜ8PxE]w7Vt%ځ545;eHb3^6/_:q,m/|tLu𬛳)(oc}$:9[cB"ZA<ϐ_P(6֞Na -- (c) 2006 Maurizio Monge -- -- 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. ------------------------------------------------------------------------------- Text = { create_from_hline = function(hline, from, to) local o = { line = hline, from = from, to = to } setmetatable(o, Text[".object_meta_table"]) return o end, [".getter_table"] = { text = function(self) return self.line:mid(self.from, self.to) end }, [".method_table"] = { dump = function(self) self.line:dump() end, clone = function(self) local hline = self.line:extract(self.from, self.to) return Text.create_from_hline(hline, 0, hline.length) end }, [".meta_table"] = { __call = function(prototype, str) local hline = HLine(str) return prototype.create_from_hline(hline, 0, hline.length) end }, [".object_meta_table"] = { __index = function(self, property) local h = Text[".getter_table"][property] if h ~= nil then return h(self) else h = Text[".method_table"][property] if h ~= nil then return h else return nil end end end, __newindex = function(self, property, value) self.line["set_" .. property](self.line, self.from, self.to, value) end, __call = function(self, from, to) if (to > self.to) then error("Index " .. to .. " is too large") end return Text.create_from_hline(self.line, from + self.from, to + self.from) end, __add = function(self, other) local hline = self:clone().line:append(other.line, other.from, other.to) return Text.create_from_hline(hline, 0, hline.length) end } } setmetatable(Text, Text[".meta_table"]) __patterns__ = { } on = {} highlight = {} setmetatable(on, { __newindex = function(self, re, h) local event = { pattern = re, handler = h } table.insert(__patterns__, event) end, __call = function(self, re, h) self[re] = h end }) setmetatable(highlight, { __newindex = function(self, re, fmt) local function handler() local function set_property(prop) if fmt[prop] ~= nil then match[prop] = fmt[prop] end end set_property("bold") set_property("italic") set_property("color") return line end table.insert(__patterns__, { pattern = re, handler = handler}) end, __call = function(self, re, fmt) self[re] = fmt end }) function filter(re) table.insert(__patterns__, { pattern = re, handler = function() end}) end function __run_event__(event, str, match, ref, state) env = getfenv(event.handler) env.line = Text(str) env.match = env.line(match.from, match.to) env.ref = {} for i, r in ipairs(ref) do env.ref[i] = env.line(ref[i].from, ref[i].to) end for k, v in pairs(state) do env[k] = v end setfenv(event.handler, env) local result = event.handler() if result ~= nil then return result end end tagua-1.0-alpha2/data/scripts/movelist_textual.html000066400000000000000000000014571077523320400225300ustar00rootroot00000000000000 tagua-1.0-alpha2/data/scripts/piece_theme.lua000066400000000000000000000037131077523320400212010ustar00rootroot00000000000000 function addShadow(func) return function(size, args) local isz = math.floor( size*100/(100+shadow_grow) + 0.5) local offx = shadow_offset_x*isz/200 local offy = shadow_offset_y*isz/200 local i = func(isz, args) local s = i:create_shadow( shadow*isz/100, shadow_color, Point(size-isz, size-isz), Point(offx, offy) ) s:draw_image(Rect((size-isz)/2-offx, (size-isz)/2-offy,isz,isz), i, Rect(0,0,isz,isz)) return s end end function fromSVG_Direct(file) return function(size, args) local i = Image(size,size) i:clear() i:draw_svg(Rect(0,0,size,size), file) return i end end function fromSVG(file) if shadow then return addShadow(fromSVG_Direct(file)) else return fromSVG_Direct(file) end end function fromFontGlyph_Direct(...) local t = (function(...) return ... end):partial(...) return function(size, args) local i = Image(size,size) i:clear() i:draw_glyph(Rect(0,0,size,size), t()) return i end end -- function fromFontGlyph_Direct(file, glyph, fg, bg, border, draw_inner_bg) -- return function(size) -- local i = Image(size,size) -- i:clear() -- i:draw_glyph(Rect(0,0,size,size), file, glyph, fg, bg, border, draw_inner_bg) -- return i -- end -- end function fromFontGlyph(...) if shadow then return addShadow(fromFontGlyph_Direct(...)) else return fromFontGlyph_Direct(...) end end function fromPixmap(file) return function(size, args) local i = Image(size,size) i:set_paint_over(false) i:draw_image(Rect(0,0,size,size), file) return i end end function fromColor(color) return function(size, args) local i = Image(size,size) i:clear(color) return i end end function overlay(func1,func2,...) if func2 then return overlay(function(size, args) return func2(func1(size, args), size, args) end, ...) else return func1 end end tagua-1.0-alpha2/data/scripts/shogi_themelib.lua000066400000000000000000000122351077523320400217130ustar00rootroot00000000000000-- generic functions for shogi themes -- FIXME: still depends on Shogi.ttf for the tile function tile(white, ratio) return function(size, args) local i = Image(size,size) i:clear() local g = RadialGradient(Point(size*0.5,size*0.5), size*0.5, Point(size*0.3,size*0.3)) g[0] = "#ffeda2" g[1] = "#c0a870" local b = Brush(g) local flip = (white or args.flipped) and not (white and args.flipped) if flip then i:translate(-size, -size) i:rotate(180) b:translate(-size, -size) b:rotate(180) end if ratio then i:scale(ratio, ratio) i:translate(size*(1-ratio)*0.5, size*(1-ratio)*0.5) b:scale(ratio, ratio) b:translate(size*(1-ratio)*0.5, size*(1-ratio)*0.5) end i:draw_glyph(Rect(0,0,size,size), "../ShogiSVG-TTF/Shogi.ttf", "0x2c", "black", b) --i:draw_svg(Rect(0,0,size,size), "../ShogiSVG/tile.svg") return i end end function draw_arrowhead(i, p, vx,vy, length, rwidth, linecolor,linewidth) -- normalize to 1 the direction vector local vl = (vx*vx + vy*vy)^0.5 vx,vy = vx/vl, vy/vl -- the component vector along the arrow direction local vxdirect, vydirect = -vx*length, -vy*length -- an orthogonal vector of requested relative width local vxortho,vyortho = vydirect*rwidth, -vxdirect*rwidth i:draw_line(p,Point(p.x+vxdirect+vxortho,p.y-vydirect-vyortho), linecolor,linewidth) i:draw_line(p,Point(p.x+vxdirect-vxortho,p.y-vydirect+vyortho), linecolor,linewidth) end function shogi_moves(moves) return function(i,size) if not theme.options.moves_overlay.value then return i end local index, move --local xcenter, ycenter, width = size/2, size/2, size/4 local xcenter, ycenter, width = 0.8*size, 0.82*size, 0.08*size local tilesize,shortsize = 0.8*width, 0.3*width local arrowlen,arrowrwidth = 0.2*width, 0.5 local centerpoint = Point(xcenter,ycenter) local b = Brush("red") for index,move in ipairs(moves) do local x,y,long = move[1],move[2],move[3] if long then local p2 = Point(xcenter+1.5*x*width, ycenter-1.5*y*width) i:draw_line(centerpoint,p2, "purple",1) draw_arrowhead(i, p2, x,y, arrowlen,arrowrwidth, "purple",1) else i:draw_line(centerpoint, Point(xcenter+x*width,ycenter-y*width),"red",1) i:fill_rect(Rect(xcenter+x*width-shortsize/2, ycenter-y*width-shortsize/2, shortsize, shortsize), b) end end -- the tile i:fill_rect(Rect(xcenter-tilesize/2,ycenter-tilesize/2, tilesize,tilesize), b) return i end end shogichars = {} -- standard Shogi shogichars["king"] = {"0x7389", {"0x7389", "0x5c06"}} shogichars["jade general"] = {"0x738b", {"0x738b", "0x5c06"}} shogichars["flying chariot"] = {"0x98db", {"0x98db", "0x8eca"}} shogichars["bishop"] = {"0x89d2", {"0x89d2", "0x884c"}} shogichars["gold general"] = {"0x91d1", {"0x91d1", "0x5c06"}} shogichars["silver general"] = {"0x9280", {"0x9280", "0x5c06"}} shogichars["knight"] = {"0x6842", {"0x6842", "0x99ac"}} shogichars["incense chariot"] = {"0x9999", {"0x9999", "0x8eca"}} shogichars["pawn"] = {"0x6b69", {"0x6b69", "0x5175"}} shogichars["dragon king"] = {"0x9f8d", {"0x9f8d", "0x738b"}} shogichars["dragon horse"] = {"0x99ac", {"0x9f8d", "0x99ac"}} shogichars["narigin"] = {"0x5168", {"0x6210", "0x9280"}} shogichars["narikei"] = {"0x572d", {"0x6210", "0x6842"}} shogichars["narikyo"] = {"0x674f", {"0x6210", "0x9999"}} shogichars["tokin"] = {"0x3068", {"0x3068", "0x91d1"}} -- Sho Shogi shogichars["drunken elephant"] = {"0x9154", {"0x9154", "0x8c61"}} shogichars["crown prince"] = {"0x592a", {"0x592a", "0x5b50"}} -- Tori Shogi shogichars["tori phoenix"] = { "0x9d6c" } shogichars["tori falcon"] = { "0x9df9" } shogichars["tori eagle"] = { "0x9d70" } shogichars["tori crane"] = { "0x9db4" } shogichars["tori quail"] = { "0x9d89" } shogichars["tori pheasant"] = { "0x96c9" } shogichars["tori swallow"] = { "0x71d5" } shogichars["tori goose"] = { "0x9d08" } -- Chess compatibility (part of Dai Shogi) shogichars["free king"] = {"0x5954", {"0x5954", "0x738b"}} shogimoves_king = { {-1,1},{0,1},{1,1}, {-1,0},{1,0}, {-1,-1},{0,-1},{1,-1}} shogimoves_rook = {{-1,0,1},{1,0,1},{0,-1,1},{0,1,1}} shogimoves_dragon = { {-1,0,1},{1,0,1},{0,-1,1},{0,1,1}, {-1,-1},{1,-1},{-1,1},{1,1}} shogimoves_bishop = {{-1,-1,1},{1,-1,1},{-1,1,1},{1,1,1}} shogimoves_horse = { {-1,-1,1},{1,-1,1},{-1,1,1},{1,1,1}, {-1,0},{1,0},{0,-1},{0,1}} shogimoves_gold = { {-1,1},{0,1},{1,1}, {-1,0},{1,0},{0,-1}} shogimoves_silver = { {-1,1},{0,1},{1,1}, {-1,-1},{1,-1}} shogimoves_knight = {{-1,2},{1,2}} shogimoves_lance = {{0,1,1}} shogimoves_pawn = {{0,1}} shogimoves_drunken_elephant = { {-1,1},{0,1},{1,1}, {-1,0},{1,0}, {-1,-1},{1,-1}} shogimoves_freeking = { {-1,1,1},{0,1,1},{1,1,1}, {-1,0,1},{1,0,1}, {-1,-1,1},{0,-1,1},{1,-1,1}} shogimoves_eagle = { {-1,1,1},{0,1},{1,1,1}, {-1,0},{1,0}, {-1,-1},{-2,-2},{0,-1,1},{1,-1},{2,-2}} shogimoves_crane = { {-1,1},{0,1},{1,1}, {-1,-1},{0,-1},{1,-1}} shogimoves_right_quail = {{0,1,1},{-1,-1,1},{1,-1}} shogimoves_left_quail = {{0,1,1},{1,-1,1},{-1,-1}} shogimoves_pheasant = {{0,2},{-1,-1},{1,-1}} shogimoves_goose = {{-2,2},{2,2},{0,-2}} tagua-1.0-alpha2/data/themes/000077500000000000000000000000001077523320400160215ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/.gitignore000066400000000000000000000000561077523320400200120ustar00rootroot00000000000000DartTestfile.txt Makefile cmake_install.cmake tagua-1.0-alpha2/data/themes/CMakeLists.txt000066400000000000000000000026761077523320400205740ustar00rootroot00000000000000install_local_dir(squares/Jose tagua/themes) install_local_dir(squares/Default tagua/themes) install_local_dir(controls/Cool tagua/themes) install_local_dir(controls/Cool tagua/themes) install_local_dir(controls/Google tagua/themes) install_local_dir(controls/XBoard tagua/themes) install_local_dir(figurines/AsciiShogiTTF tagua/themes) install_local_dir(figurines/FantasyTTF tagua/themes) install_local_dir(figurines/XiangQi tagua/themes) install_local_dir(figurines/AlphaTTF tagua/themes) install_local_dir(figurines/ShogiTTF tagua/themes) install_local_dir(pieces/EnquilTTF tagua/themes) install_local_dir(pieces/LucenaTTF tagua/themes) install_local_dir(pieces/FantasySVG tagua/themes) install_local_dir(pieces/MayanTTF tagua/themes) install_local_dir(pieces/SpatialSVG tagua/themes) install_local_dir(pieces/YahooTTF tagua/themes) install_local_dir(pieces/PrmiSVG tagua/themes) install_local_dir(pieces/StonesSVG tagua/themes) install_local_dir(pieces/XiangQiSVG tagua/themes) install_local_dir(pieces/XiangQiTTF tagua/themes) install_local_dir(pieces/AlphaTTF tagua/themes) install_local_dir(pieces/SkullsSVG tagua/themes) install_local_dir(pieces/ShogiSVG tagua/themes) install_local_dir(pieces/ShogiTTF tagua/themes) install_local_dir(pieces/ShogiSVG-TTF tagua/themes) install_local_dir(pieces/ToriShogiTTF tagua/themes) install_local_dir(pieces/XBoardTTF tagua/themes) install_local_dir(pieces/BerlinTTF tagua/themes) install_local_dir(wallpapers tagua/themes) tagua-1.0-alpha2/data/themes/controls/000077500000000000000000000000001077523320400176645ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/controls/Cool/000077500000000000000000000000001077523320400205605ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/controls/Cool/active_clock.svg000066400000000000000000000160461077523320400237360ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/controls/Cool/border_corner.svg000066400000000000000000000055371077523320400241400ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/controls/Cool/border_top.svg000066400000000000000000000043771077523320400234530ustar00rootroot00000000000000 tagua-1.0-alpha2/data/themes/controls/Cool/inactive_clock.svg000066400000000000000000000160501077523320400242600ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/controls/Cool/theme.desktop000066400000000000000000000002431077523320400232540ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Cool Type=Application Comment=Cool controls X-Tagua-ThemeType=Figurines X-Tagua-Variants=any[default] X-Tagua-Script=theme.lua tagua-1.0-alpha2/data/themes/controls/Cool/theme.lua000066400000000000000000000131121077523320400223630ustar00rootroot00000000000000import("piece_theme.lua") theme.options = OptList { BoolOpt("wallpaper", "Draw wallpaper", true, OptList { BoolOpt("blur", "Enable blur", false), UrlOpt("file", "File:", "../../wallpapers/Dark_Sunset.jpg") }), FontOpt("clock_font1", "Clock text font", Font("Sans", true, true)), FontOpt("clock_font2", "Clock time font", Font("Sans", true, false)), FontOpt("border_font", "Border font", Font("Sans", false, false)) } local border_ratio = 0.67 local clock_ratio = 2.6 local clock_height_ratio = 0.4 local clock_border_ratio = 0.33 local pool_width = 3 local pool_piece_ratio = clock_ratio/pool_width local border_text_near = 0.0 local border_text_far = 0.5 theme.layout = function(args) retv = {} retv.square_size = math.floor(math.min( args.width/(args.grid_size.x+2*border_ratio+clock_ratio+2*clock_border_ratio), args.height/(args.grid_size.y+2*border_ratio) ) ) retv.border_size = math.floor(retv.square_size*border_ratio) retv.border_text_near = math.floor(retv.border_size*border_text_near) retv.border_text_far = math.floor(retv.border_size*border_text_far) retv.clock_size = math.floor(retv.square_size*clock_ratio) retv.pool_width = pool_width; retv.pool_piece_size = math.floor(retv.square_size*pool_piece_ratio) local d = Point(math.floor((args.width-retv.square_size*(args.grid_size.x+ 2*border_ratio+clock_ratio+2*clock_border_ratio))/2), math.floor((args.height-retv.square_size*(args.grid_size.y+2*border_ratio))/2)); local clock_border = math.floor(retv.square_size*clock_border_ratio) local clock_height = math.floor(retv.clock_size*clock_height_ratio) local panel_x = retv.square_size*args.grid_size.x + 2*retv.border_size + clock_border; retv.board_position = d + Point(retv.border_size, retv.border_size) retv.clock0_position = d + Point(panel_x, clock_border_ratio*retv.square_size) retv.clock1_position = d + Point(panel_x, retv.square_size*args.grid_size.y + 2*retv.border_size - clock_height - clock_border) retv.pool0_position = Point(d.x + panel_x, retv.clock0_position.y+clock_height+clock_border); retv.pool1_position = Point(d.x + panel_x, retv.clock1_position.y-clock_border); return retv end function addShadow(i, size) local s = i:create_shadow( size, "#ffffff", Point(0, 0), Point(0, 0) ) s:draw_image(Rect(0, 0, i.width, i.height), i) return s end theme.border = function(b, args) local rb = math.floor(b*2/3); local w = args.width; local h = args.height; local tr = Image(b, b); tr:clear(); tr:draw_svg(Rect(0,b-rb,rb,rb), "border_corner.svg"); tr = addShadow(tr, b/5) local tl = Image(b, b); tl:set_paint_over(false); tl:rotate(270); tl:translate(0,b); tl:draw_image(Rect(0,0,b,b), tr) local bl = Image(b, b); bl:set_paint_over(false); bl:rotate(180); bl:translate(b,b); bl:draw_image(Rect(0,0,b,b), tr) local br = Image(b, b); br:set_paint_over(false); br:rotate(90); br:translate(b,0); br:draw_image(Rect(0,0,b,b), tr) local t = Image(w, b); t:clear(); t:draw_svg(Rect(0,b-rb,w,rb), "border_top.svg"); t = addShadow(t, b/5) local bt = Image(w, b); bt:set_paint_over(false); bt:rotate(180); bt:translate(w,b); bt:draw_image(Rect(0,0,w,b), t) local l = Image(b, h); l:set_paint_over(false); l:rotate(270); l:translate(0,h); l:draw_image(Rect(0,0,h,b), t) local r = Image(b, h); r:set_paint_over(false); r:rotate(90); r:translate(b,0); r:draw_image(Rect(0,0,h,b), t) return { [Rect(-b,-b,b,b)] = tl, [Rect(w,-b,b,b)] = tr, [Rect(-b,h,b,b)] = bl, [Rect(w,h,b,b)] = br, [Rect(0,-b,w,b)] = t, [Rect(0,h,w,b)] = bt, [Rect(-b,0,b,h)] = l, [Rect(w,0,b,h)] = r } end theme.border_color = function() return "black"; end theme.border_font = function() return theme.options.border_font.value; end theme.wallpaper = function() if(theme.options.wallpaper.value) then local i = Image(theme.options.wallpaper.sub_options.file.value, false) if(theme.options.wallpaper.sub_options.blur.value) then i:exp_blur(5); end return i else return nil end end function create_clock(file, col) return function(w) local h = math.floor(w*clock_height_ratio) local i = Image(w,h) i:clear() i:draw_svg(Rect(0,0,w,h), file) local s = i:create_shadow( w/16, col, Point(math.floor(w/7), math.floor(w/7)), Point(0, 0) ) s:draw_image(Rect(math.floor(w/14), math.floor(w/14), i.width, i.height), i) return s end end theme.clock_active_background = create_clock("active_clock.svg", "#ff8080") theme.clock_inactive_background = create_clock("inactive_clock.svg", "#e0e0e0") theme.clock_active_text = function(size) return Brush("#000000") end theme.clock_inactive_text = function(size) return Brush("#808080") end theme.clock_background_offset = function(w) local d = math.floor(w/14) return Point(-d, -d) end theme.clock_height = function(w) return math.floor(w*clock_height_ratio) end theme.clock_caption_rect = function(w) local h = math.floor(w*clock_height_ratio) return Rect(w*0.02, h*0.22, w*0.4, h*0.38) end theme.clock_time_rect = function(w) local h = math.floor(w*clock_height_ratio) return Rect(w*0.4, h*0.1, w*0.6, h*0.62) end theme.clock_player_rect = function(w) local h = math.floor(w*clock_height_ratio) return Rect(w*0.14, h*0.68, w*0.69, h*0.28) end theme.clock_caption_font = function() return theme.options.clock_font1.value; end theme.clock_time_font = function() return theme.options.clock_font2.value; end theme.clock_player_font = function() return theme.options.clock_font1.value; end tagua-1.0-alpha2/data/themes/controls/Google/000077500000000000000000000000001077523320400211005ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/controls/Google/active_clock.svg000066400000000000000000000050661077523320400242560ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/controls/Google/border_corner.svg000066400000000000000000000042351077523320400244520ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/controls/Google/border_top.svg000066400000000000000000000034351077523320400237650ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/controls/Google/inactive_clock.svg000066400000000000000000000050701077523320400246000ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/controls/Google/theme_google.desktop000066400000000000000000000002511077523320400251270ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Google Type=Application Comment=Google-like controls X-Tagua-ThemeType=Controls X-Tagua-Variants=any X-Tagua-Script=theme_google.lua tagua-1.0-alpha2/data/themes/controls/Google/theme_google.lua000066400000000000000000000121511077523320400242410ustar00rootroot00000000000000import("piece_theme.lua") theme.options = OptList { BoolOpt("wallpaper", "Draw wallpaper", false, OptList { BoolOpt("blur", "Enable blur", false), UrlOpt("file", "File:", "../../wallpapers") }), FontOpt("clock_font1", "Clock text font", Font("Sans", false, true)), FontOpt("clock_font2", "Clock time font", Font("Sans", false, false)), FontOpt("border_font", "Border font", Font("Sans", false, false)) } local border_ratio = 0.67 local clock_ratio = 2.8 local clock_height_ratio = 0.6 local clock_border_ratio = 0.16 local pool_width = 3 local pool_piece_ratio = clock_ratio/pool_width local border_text_near = 0.05 local border_text_far = 0.6 theme.layout = function(args) retv = {} retv.square_size = math.floor(math.min( args.width/(args.grid_size.x+2*border_ratio+clock_ratio+2*clock_border_ratio), args.height/(args.grid_size.y+2*border_ratio) ) ) retv.border_size = math.floor(retv.square_size*border_ratio) retv.border_text_near = math.floor(retv.border_size*border_text_near) retv.border_text_far = math.floor(retv.border_size*border_text_far) retv.clock_size = math.floor(retv.square_size*clock_ratio) retv.pool_width = pool_width; retv.pool_piece_size = math.floor(retv.square_size*pool_piece_ratio) local d = Point(math.floor((args.width-retv.square_size*(args.grid_size.x+ 2*border_ratio+clock_ratio+2*clock_border_ratio))/2), math.floor((args.height-retv.square_size*(args.grid_size.y+2*border_ratio))/2)); local clock_border = math.floor(retv.square_size*clock_border_ratio) local clock_height = math.floor(retv.clock_size*clock_height_ratio) local panel_x = retv.square_size*args.grid_size.x + 2*retv.border_size + clock_border; retv.board_position = d + Point(retv.border_size, retv.border_size) retv.clock0_position = d + Point(panel_x, clock_border_ratio*retv.square_size) retv.clock1_position = d + Point(panel_x, retv.square_size*args.grid_size.y + 2*retv.border_size - clock_height - clock_border) retv.pool0_position = Point(d.x + panel_x, retv.clock0_position.y+clock_height+clock_border); retv.pool1_position = Point(d.x + panel_x, retv.clock1_position.y-clock_border); return retv end theme.border = function(b, args) b = math.floor(b*0.7) local w = args.width; local h = args.height; local tr = Image(b, b); tr:clear(); tr:draw_svg(Rect(0,0,b,b), "border_corner.svg"); local tl = Image(b, b); tl:set_paint_over(false); tl:rotate(270); tl:translate(0,b); tl:draw_image(Rect(0,0,b,b), tr) local bl = Image(b, b); bl:set_paint_over(false); bl:rotate(180); bl:translate(b,b); bl:draw_image(Rect(0,0,b,b), tr) local br = Image(b, b); br:set_paint_over(false); br:rotate(90); br:translate(b,0); br:draw_image(Rect(0,0,b,b), tr) local t = Image(w, b); t:clear(); t:draw_svg(Rect(0,0,w,b), "border_top.svg"); local bt = Image(w, b); bt:set_paint_over(false); bt:rotate(180); bt:translate(w,b); bt:draw_image(Rect(0,0,w,b), t) local l = Image(b, h); l:set_paint_over(false); l:rotate(270); l:translate(0,h); l:draw_image(Rect(0,0,h,b), t) local r = Image(b, h); r:set_paint_over(false); r:rotate(90); r:translate(b,0); r:draw_image(Rect(0,0,h,b), t) return { [Rect(-b,-b,b,b)] = tl, [Rect(w,-b,b,b)] = tr, [Rect(-b,h,b,b)] = bl, [Rect(w,h,b,b)] = br, [Rect(0,-b,w,b)] = t, [Rect(0,h,w,b)] = bt, [Rect(-b,0,b,h)] = l, [Rect(w,0,b,h)] = r } end theme.border_color = function() return "#108060"; end theme.border_font = function() return theme.options.border_font.value; end theme.wallpaper = function() if(theme.options.wallpaper.value) then local i = Image(theme.options.wallpaper.sub_options.file.value, false) if(theme.options.wallpaper.sub_options.blur.value) then i:exp_blur(5); end return i else return {} end end function create_clock(file, col) return function(w) local h = math.floor(w*clock_height_ratio) local i = Image(w,h) i:clear() i:draw_svg(Rect(0,0,w,h), file) return i end end theme.clock_active_background = create_clock("active_clock.svg", "#ff8080") theme.clock_inactive_background = create_clock("inactive_clock.svg", "#e0e0e0") theme.clock_active_text = function(size) return Brush("#000000") end theme.clock_inactive_text = function(size) return Brush("#a0a0a0") end theme.clock_background_offset = function(w) return Point() end theme.clock_height = function(w) return math.floor(w*clock_height_ratio) end theme.clock_caption_rect = function(w) local h = math.floor(w*clock_height_ratio) return Rect(0, h*0.04, w, h*0.2) end theme.clock_time_rect = function(w) local h = math.floor(w*clock_height_ratio) return Rect(0, h*0.23, w, h*0.6) end theme.clock_player_rect = function(w) local h = math.floor(w*clock_height_ratio) return Rect(0, h*0.78, w, h*0.21) end theme.clock_caption_font = function() return theme.options.clock_font1.value; end theme.clock_time_font = function() return theme.options.clock_font2.value; end theme.clock_player_font = function() return theme.options.clock_font1.value; end tagua-1.0-alpha2/data/themes/controls/XBoard/000077500000000000000000000000001077523320400210435ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/controls/XBoard/theme_xboard.desktop000066400000000000000000000002011077523320400250700ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=XBoard Type=Application Comment=XBoard style X-Tagua-ThemeType=Controls X-Tagua-Variants=any tagua-1.0-alpha2/data/themes/controls/XBoard/theme_xboard.lua000066400000000000000000000051041077523320400242070ustar00rootroot00000000000000import("piece_theme.lua") local border_ratio = 0 local clock_height_ratio = 0.23 local clock_border_ratio = 0 local clock_ratio = 4 local pool_width = 3 local pool_piece_ratio = clock_ratio/pool_width theme.layout = function(args) retv = {} retv.square_size = math.floor(math.min( args.width/(args.grid_size.x+2*border_ratio), args.height/(args.grid_size.y+2*border_ratio+clock_ratio*clock_height_ratio+2*clock_border_ratio) ) ) retv.border_size = math.floor(retv.square_size*border_ratio) retv.clock_size = math.floor(retv.square_size*clock_ratio) retv.pool_width = pool_width; retv.pool_piece_size = math.floor(retv.square_size*pool_piece_ratio) local clock_border = math.floor(retv.square_size*clock_border_ratio) local clock_height = math.floor(retv.clock_size*clock_height_ratio) local x = math.floor(args.width/2 - retv.border_size-args.grid_size.y*retv.square_size/2) retv.board_position = Point(x + retv.border_size, retv.border_size+clock_height+2*clock_border) retv.clock0_position = Point(x + args.grid_size.x*retv.square_size+2*retv.border_size -retv.clock_size-clock_border, clock_border) retv.clock1_position = Point(x + clock_border, clock_border) retv.pool0_position = Point(); retv.pool1_position = Point(); return retv end theme.border = function(b, args) return {} end theme.wallpaper = function() return Image() end function create_clock(col) return function(w) print("clock ",w) local h = math.floor(w*clock_height_ratio) local i = Image(w,h) i:clear(col) i:draw_line(Point(0,0),Point(w,0), "black", 2); i:draw_line(Point(0,0),Point(0,h), "black", 2); i:draw_line(Point(w,h),Point(w,0), "black", 2); i:draw_line(Point(w,h),Point(0,h), "black", 2); return i end end theme.clock_active_background = create_clock("black") theme.clock_inactive_background = create_clock("white") theme.clock_active_text = function(size) return Brush("white") end theme.clock_inactive_text = function(size) return Brush("black") end theme.clock_background_offset = function(w) return Point() end theme.clock_height = function(w) return math.floor(w*clock_height_ratio) end theme.clock_caption_rect = function(w) local h = math.floor(w*clock_height_ratio) return Rect(0, h*0.1, w*0.5, h*0.7) end theme.clock_time_rect = function(w) local h = math.floor(w*clock_height_ratio) return Rect(w*0.4, h*0.05, w*0.7, h*0.8) end theme.clock_player_rect = function(w) local h = math.floor(w*clock_height_ratio) return Rect(0, h*0.68, w, h*0.28) end tagua-1.0-alpha2/data/themes/figurines/000077500000000000000000000000001077523320400200145ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/figurines/AlphaTTF/000077500000000000000000000000001077523320400214175ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/figurines/AlphaTTF/theme.desktop000066400000000000000000000002661077523320400241200ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Alpha Type=Application Comment=Alpha TTF figurines.| by Eric Bentzen X-Tagua-ThemeType=Figurines X-Tagua-Variants=Chess X-Tagua-Script=theme.lua tagua-1.0-alpha2/data/themes/figurines/AlphaTTF/theme.lua000066400000000000000000000004351077523320400232260ustar00rootroot00000000000000import("piece_theme.lua") function Fig(char) return Glyph("../../Pieces/AlphaTTF/Alpha.ttf", char, 2) end theme.bishop = Fig("0xF085") theme.king = Fig("0xF082") theme.knight = Fig("0xF086") theme.pawn = Fig("0xF087") theme.queen = Fig("0xF083") theme.rook = Fig("0xF084") tagua-1.0-alpha2/data/themes/figurines/AsciiShogiTTF/000077500000000000000000000000001077523320400224145ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/figurines/AsciiShogiTTF/theme.desktop000066400000000000000000000002551077523320400251130ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Shogi Type=Application Comment=Shogi figurines X-Tagua-ThemeType=Figurines X-Tagua-Variants=Shogi,LargeShogi[default],ToriShogi[default] tagua-1.0-alpha2/data/themes/figurines/AsciiShogiTTF/theme.lua000066400000000000000000000016031077523320400242210ustar00rootroot00000000000000import("piece_theme.lua") import("shogi_themelib.lua") function Fig(char) return Glyph("../ShogiTTF/mikachan.ttf", char, 2) end function Plain(str) return Glyph(nil, str, 2) end theme.num_9 = Plain("i") theme.num_8 = Plain("h") theme.num_7 = Plain("g") theme.num_6 = Plain("f") theme.num_5 = Plain("e") theme.num_4 = Plain("d") theme.num_3 = Plain("c") theme.num_2 = Plain("b") theme.num_1 = Plain("a") theme.phoenix = Plain("Ph") theme.crane = Plain("Cr") theme.pheasant = Plain("Pt") theme.right_quail = Plain("RQ") theme.left_quail = Plain("LQ") theme.falcon = Plain("Fa") theme.swallow = Plain("Sw") theme.king1 = Plain("K") theme.king2 = Plain("K") theme.rook = Plain("R") theme.bishop = Plain("B") theme.gold = Plain("G") theme.silver = Plain("S") theme.knight = Plain("N") theme.lance = Plain("L") theme.pawn = Plain("P") theme.drunken_elephant = Plain("DE") tagua-1.0-alpha2/data/themes/figurines/FantasyTTF/000077500000000000000000000000001077523320400217775ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/figurines/FantasyTTF/Fantasy.sfd000066400000000000000000000625031077523320400241100ustar00rootroot00000000000000SplineFontDB: 1.0 FontName: Fantasy FullName: Fantasy FamilyName: Fantasy Weight: Medium Copyright: Created by Monge Maurizio with FontForge 1.0 (http://fontforge.sf.net) Comments: 2006-10-15: Created. Version: 001.000 ItalicAngle: 0 UnderlinePosition: -100 UnderlineWidth: 50 Ascent: 800 Descent: 200 NeedsXUIDChange: 1 XUID: [1021 645 1811818106 7095199] FSType: 0 OS2Version: 0 OS2_WeightWidthSlopeOnly: 0 OS2_UseTypoMetrics: 0 CreationTime: 1160940435 ModificationTime: 1160942325 OS2TypoAscent: 0 OS2TypoAOffset: 1 OS2TypoDescent: 0 OS2TypoDOffset: 1 OS2TypoLinegap: 90 OS2WinAscent: 0 OS2WinAOffset: 1 OS2WinDescent: 0 OS2WinDOffset: 1 HheadAscent: 0 HheadAOffset: 1 HheadDescent: 0 HheadDOffset: 1 TtfTable: cvt 4 !$MDh EndTtf Encoding: ISO8859-1 UnicodeInterp: none NameList: Adobe Glyph List DisplaySize: -36 AntiAlias: 1 FitToEm: 1 WinInfo: 56 28 7 BeginChars: 256 6 StartChar: b Encoding: 98 98 0 Width: 1000 VWidth: 1050 Flags: H TeX: 0 0 0 0 HStem: -8.5625 40<218.008 384.809 471.262 687.496> 46.5817 36.3245<140.961 227.356> 49.1929 39.8071<643.986 719.243> 71.3438 64.5<341.854 507.645> 95.8438 15.5<338.774 509.714> 159.938 40<317.437 525.223> 441.76 40.928<429.74 456.022> VStem: 175.844 39.937<302.476 412.297> 264.75 39.969<128.658 157.683> 541.219 39.937<127.562 160.272> 623.718 39.8131<342.105 481.557> Fore 576.375 47.875 m 0 565.317 50.9414 534.45 73.8389 414.875 71.2812 c 0 372.666 70.1074 331.72 68.6787 296.656 54.3438 c 1 252.798 24.0811 191.436 58.0225 149.188 45.375 c 1 149.178 44.8076 148.574 45.3555 147.531 44.3125 c 1 148.566 45.3477 149.569 43.498 150.531 42.9688 c 0 174.341 29.8682 292.742 26.1514 349.156 34.2188 c 0 393.085 45.0811 408.373 80.1035 464.375 48.5312 c 0 509.018 23.3633 555.314 32.7598 612.469 31.4375 c 0 649.476 32.168 685.578 33.5977 717.438 44 c 1 717.498 44.1338 717.559 44.3184 717.781 44.6562 c 1 701.376 60.3877 629.589 33.1201 576.375 47.875 c 0 381.906 496.219 m 1 360.732 491.412 377.284 461.89 367.559 449.711 c 0 353.561 432.185 323.711 452.908 308 445.031 c 1 308 445.031 305.977 441.247 310.156 436.125 c 0 318.301 425.899 362.897 436.405 368.125 410.438 c 0 378.39 359.451 373.834 302.77 394.119 278.141 c 1 395.832 277.962 398.241 279.676 398.406 279.656 c 1 398.406 280.713 398.494 281.768 398.656 282.812 c 0 406.5 333.346 364.175 421.947 405.094 425.5 c 0 436.735 428.247 455.249 432.008 453.656 441.531 c 0 453.523 442.323 453.546 442.491 453.594 442.562 c 1 432.899 448.518 390.797 428.101 384.812 457.438 c 0 379.559 483.192 389.352 484.804 381.906 496.219 c 1 330.219 486.344 m 1 339.836 545.827 415.31 555.271 423.875 496.375 c 0 424.947 491.104 425.264 486.668 425.312 482.688 c 1 449.712 486.274 486.838 485.491 493.094 448.125 c 0 496.731 426.395 482.842 409.954 480.844 408.844 c 1 465.041 392.308 445.1 388.37 428.094 386.938 c 1 432.916 344.526 443.375 313.999 438.312 278.281 c 0 437.522 252.806 414.792 236.56 391.625 238.344 c 1 391.625 238.219 l 1 334.832 240.26 335.04 358.478 330.938 389.844 c 1 304.847 392.782 291.418 395.44 279.375 410.562 c 0 261.766 430.928 264.103 466.926 289.438 480.438 c 0 303.958 487.717 318.029 487.892 330.219 486.344 c 1 281.219 187 m 1 345.416 205.812 479.708 202.001 561.219 190.312 c 1 581.207 278.339 557.71 348.99 543.25 393.781 c 0 516.092 472.248 481.029 548.495 429.597 611.387 c 2 415.938 627.281 l 2 400.074 644.537 383.198 660.573 365.156 674.438 c 1 301.601 612.755 220.069 462.872 215.781 364.188 c 2 215.781 364 l 2 210.78 269.22 243.053 233.94 264.938 203 c 0 270.679 195.471 276.316 189.861 281.219 187 c 1 364.5 719.875 m 0 379.281 719.875 419.698 680.864 430.63 669.858 c 1 451.122 694.965 486.237 724.805 501.031 725.844 c 0 511.118 726.553 519.089 721.595 522.344 718.469 c 0 602.036 641.933 740.501 381.979 612.938 204.938 c 0 610.607 200.945 607.55 196.837 602.681 193.101 c 1 601.102 184.759 599.193 176.45 596.844 168.219 c 1 594.83 160.556 589.16 153.284 583.458 150.643 c 1 576.94 119.082 588.002 102.822 572.964 92.1699 c 1 587.781 86.25 l 2 613.727 79.292 663.701 89.3623 682.156 89 c 0 704.35 89.0488 734.334 89.5254 746.969 72.0312 c 1 770.938 48.5918 752.146 13.4727 733 6.96875 c 0 668.323 -15 509.575 -12.2266 476.156 -0.125 c 0 455.557 4.72754 442.366 17.8652 426.938 21.6875 c 1 378.21 10.6992 401.271 -16.9131 219.688 -8.40625 c 0 161.423 -4.78223 159.365 -4.65723 131.156 7.96875 c 0 98.4746 22.6074 102.601 70.9287 131.5 81.7812 c 0 188.639 103.239 241.317 66.6006 276.982 89.21 c 1 267.453 93.8242 265.855 102.91 265.719 106.438 c 2 263.979 150.613 l 1 237.575 163.593 202.265 223.066 196.844 234.938 c 0 108.795 430.657 321.654 719.875 364.5 719.875 c 0 393.995 278.153 m 1 393.978 278.164 393.969 278.156 393.969 278.156 c 2 393.995 278.153 l 1 304.844 129.562 m 1 374.982 137.23 447.402 138.557 541.219 130.438 c 1 541.378 137.378 541.639 144.842 542.878 152.464 c 1 464.841 162.359 354.342 163.141 303.966 151.702 c 1 304.719 132.906 l 2 304.785 131.234 304.779 131.204 304.844 129.562 c 1 607.938 279.5 m 1 661.873 418.16 571.25 609.487 502.062 682.125 c 1 485.429 670.79 470.646 656.264 457.938 639.844 c 1 515.251 571.07 552.508 489.28 580.969 407.125 c 1 595.68 366.56 605.516 323.297 607.938 279.5 c 1 EndSplineSet EndChar StartChar: k Encoding: 107 107 1 Width: 1000 VWidth: 1050 Flags: H TeX: 0 0 0 0 Fore 483.125 761.844 m 1 468.862 765.948 453.15 765.812 445.656 765.812 c 0 439.344 765.812 419.415 764.378 414.094 761.625 c 1 412.661 732.961 438.275 684.119 420.453 668.75 c 0 405.175 655.574 351.876 683.04 305.5 672.281 c 1 302.491 669.165 301.612 661.915 301.281 646.25 c 0 301.47 634.042 303.75 622.746 308.531 615.031 c 1 347.581 609.231 420.423 649.468 422.406 611.625 c 0 423.532 590.146 419.194 570.889 414.718 553.07 c 1 419.561 553.551 424.282 553.81 428.781 553.938 c 2 429.031 553.938 l 2 434.711 554.025 440.301 553.949 446.173 553.51 c 1 441.772 572.787 429.074 628.699 458.594 630.156 c 0 498.794 632.139 532.185 619.32 560.312 624.531 c 1 567.778 631.726 571.53 664.904 562.969 680.062 c 1 524.688 683.501 444.517 643.26 465.281 701.156 c 2 472.594 721.781 l 2 477.091 735.016 481.423 750.648 483.125 761.844 c 1 445.469 801.562 m 0 537.137 801.562 524.904 764.375 506.281 709.719 c 1 551.253 719.925 576.984 717.597 585.094 709.719 c 0 618.906 676.79 603.192 597.638 571.5 590.156 c 0 535.46 581.646 503.402 591.331 475.969 593.875 c 1 476.882 570.475 485.228 546.39 485.698 544.762 c 1 495.802 540.45 505.326 534.23 512.912 525.42 c 1 598.413 559.422 743.518 537.442 799.062 455.75 c 0 824.473 421.421 826.775 376.365 812.406 338.688 c 0 778.33 250.768 710.828 210.229 670.812 140.875 c 0 658.8 120.056 654.895 97.7393 636.247 91.8066 c 1 620.077 23.8467 627.825 -2.79297 602.781 -3.53125 c 0 512.726 -6.1875 371.207 -7.06445 274.719 -3.03125 c 0 249.16 -1.95117 258.43 26.5059 242.86 89.2256 c 1 232.008 91.5312 221.57 97.9336 218.375 107.438 c 0 207.96 138.416 197.853 141.945 162.438 187.719 c 0 130.559 232.865 89.2324 278.182 70.2188 338.656 c 0 45.7598 406.424 78.7549 468.3 108.688 491.094 c 0 127.101 506.084 175.025 541.094 274.531 541.094 c 0 301.033 541.443 328.12 537.545 353.565 527.523 c 1 360.115 534.088 367.492 539.048 375.26 542.79 c 1 378.897 559.539 383.215 574.859 385.375 589.281 c 1 369.947 585.665 303.176 567.326 285.219 586.75 c 0 268.94 604.375 265.845 627.087 265.531 645.688 c 2 265.531 646.344 l 2 265.647 651.833 265.016 698.671 293.406 706.25 c 0 327.001 715.218 358.962 709.449 387.906 704.062 c 1 377.194 752.29 356.144 801.562 445.469 801.562 c 0 335.331 491.595 m 1 315.711 498.688 294.874 501.58 272.719 501.031 c 2 272.375 501.031 l 2 181.065 500.449 75.5928 461.4 108.344 350.719 c 0 124.094 300.926 161.169 258.826 194.875 211.094 c 0 215.694 182.807 238.332 165.814 253.188 128.156 c 1 326.853 128.949 474.298 126.203 621.531 130.656 c 1 624.938 136.523 628.43 150.519 636.406 161.25 c 0 682.201 240.385 746.252 278.696 775.062 353.031 c 0 801.1 421.279 740.844 476.582 663.031 493.5 c 0 617.838 503.573 569.757 504.413 528.56 488.341 c 1 530.976 469.945 527.425 452.27 522.7 436.562 c 1 524.373 436.672 587.869 444.339 616.156 426.062 c 0 652.549 402.465 661.97 356.093 649.219 318.625 c 0 628.606 258.054 566.659 236.066 551.55 236.561 c 0 536.462 236.204 478.241 272.003 473.688 337.25 c 0 455.596 434.975 501.496 447.63 486.32 493.448 c 0 474.323 519.447 400.447 521.589 379.781 496.844 c 1 363.219 466.955 381.57 434.173 386.452 419.79 c 0 417.565 328.116 360.239 256.024 339.526 241.812 c 0 314.128 224.386 236.216 292.894 228.219 334.438 c 0 217.361 371.723 236.206 412.675 276.781 427.844 c 0 277.091 427.943 277.376 428.092 277.688 428.125 c 1 299.843 436.26 320.362 435.288 338.316 434.158 c 1 332.938 452.38 331.028 472.285 335.331 491.595 c 1 510.153 395.816 m 1 506.479 369.176 512.84 352.054 513.5 340.844 c 0 515.01 315.196 531.266 290.866 553.896 277.685 c 1 614.361 296.185 631.49 366.121 595.438 391.625 c 1 573.332 401.147 543.841 396.214 510.153 395.816 c 1 324.205 282.732 m 1 349.946 311.448 360.16 354.6 352.306 392.97 c 1 314.567 392.41 312.709 397.179 289.438 389.938 c 0 273.396 384.946 261.748 362.312 266.562 345.781 c 0 274.613 318.993 297.191 297.676 324.205 282.732 c 1 594.717 89.8779 m 1 491.03 87.418 387.492 88.2793 284.144 88.5605 c 1 288.664 68.417 291.529 49.5176 293.281 36.375 c 1 381.749 33.332 500.989 33.9717 585 36.125 c 1 586.999 49.2988 590.17 69.126 594.717 89.8779 c 1 EndSplineSet EndChar StartChar: n Encoding: 110 110 2 Width: 1000 VWidth: 1040 Flags: H TeX: 0 0 0 0 Fore 151.469 333.469 m 0 155.799 333.877 160.352 333.456 164.656 331.969 c 0 173.005 329.195 178.561 321.292 178.346 312.497 c 0 178.13 303.701 172.193 296.08 163.719 293.719 c 1 163.345 288.26 160.751 283.191 156.541 279.696 c 0 152.331 276.2 146.872 274.582 141.438 275.219 c 0 141.336 275.229 141.234 275.241 141.131 275.253 c 1 153.652 263.961 163.606 264.513 174.375 268.344 c 0 181.552 270.897 188.25 276.376 193.312 282 c 1 195.373 285.921 197.42 289.515 199.188 292.312 c 0 200.638 294.607 201.627 296.177 203.438 298.375 c 0 203.891 298.925 204.387 299.524 205.438 300.531 c 0 206.488 301.538 205.419 304.122 216.094 305.969 c 0 218.763 306.431 222.804 306.521 227.125 304.75 c 0 231.446 302.979 235.161 299.244 236.969 296.031 c 0 240.585 289.605 239.649 286.333 239.469 284.344 c 0 239.106 280.364 238.514 279.639 238.156 278.688 c 0 235.661 272.055 232.086 265.799 227.75 259.969 c 1 239.896 267.127 255.235 277.74 270.625 288.906 c 0 287.182 300.919 303.711 313.377 317.469 322.875 c 0 324.348 327.624 330.446 331.617 336.219 334.719 c 0 339.105 336.27 341.865 337.626 345.375 338.75 c 0 348.885 339.874 353.463 342.062 362.219 338.719 c 0 434.666 311.051 506.009 367.375 505.844 426.375 c 0 505.585 437.421 514.329 446.585 525.375 446.844 c 0 536.421 447.103 545.585 438.358 545.844 427.312 c 0 545.856 427.036 545.832 426.776 545.844 426.5 c 0 547.061 397.716 545.097 371.343 534.125 346.625 c 0 523.048 321.67 503.157 299.879 473.031 279.625 c 0 418.236 242.786 312.323 169.768 288.562 74.5 c 0 287.335 69.5781 288.375 58.1074 292.344 50.375 c 0 296.312 42.6426 300.172 39.5615 305.969 39.4688 c 0 424.381 37.582 565.449 37.0996 683.031 39.2812 c 0 685.438 39.3262 690.168 41.2314 696.906 53.3125 c 0 703.645 65.3936 710.031 85.4707 713.969 110.531 c 0 721.844 160.653 720.672 230.701 706.062 303.594 c 0 676.843 449.379 595.579 604.517 433.969 654.25 c 0 431.537 654.998 429.266 656.189 427.281 657.781 c 0 409.005 672.532 396.66 692.898 386.031 709.125 c 0 384.161 711.98 382.464 714.472 380.75 717 c 1 379.326 700.725 379.759 681.503 371.969 663.469 c 0 369.401 657.527 364.117 653.196 357.788 651.843 c 0 351.459 650.49 344.865 652.283 340.094 656.656 c 0 327.966 667.784 320.94 680.703 312.25 690.875 c 0 310.379 693.064 308.532 695.042 306.656 696.906 c 1 307.43 692.214 308.333 687.384 309.469 682.5 c 0 311.413 674.145 313.543 665.913 314.656 657.531 c 0 315.77 649.149 317.721 638.943 308.719 627.656 c 0 283.543 596.088 274.868 581.807 268.594 566.594 c 0 262.319 551.381 257.951 532.617 244.25 496.312 c 0 229.625 457.561 195.308 396.661 159.219 354.344 c 0 153.053 347.113 148.087 339.501 144.235 331.984 c 1 146.499 332.716 148.947 333.231 151.469 333.469 c 0 338.094 552.5 m 0 342.301 552.246 346.559 551.722 350.812 550.938 c 0 361.677 548.934 368.861 538.505 366.859 527.641 c 0 364.857 516.776 354.427 509.592 343.562 511.594 c 0 342.947 511.707 342.337 511.812 341.731 511.912 c 1 344.078 508.032 345.055 503.435 344.438 498.875 c 0 343.706 492.836 341.959 486.771 337.875 481.219 c 0 333.791 475.666 326.848 471.243 319.969 470.094 c 0 306.21 467.795 296.568 474.454 289.5 481.656 c 0 286.866 484.257 285.084 487.444 284.2 490.839 c 1 279.527 487.799 273.725 486.809 268.202 488.262 c 0 261.198 490.104 255.738 495.59 253.926 502.602 c 0 252.114 509.613 254.234 517.058 259.469 522.062 c 0 280.737 543.23 308.647 554.277 338.094 552.5 c 0 371.281 771.531 m 0 373.35 771.747 375.395 771.719 377.312 771.406 c 0 390.752 769.213 397.098 761.37 403 754.312 c 0 408.902 747.255 414.107 739.295 419.5 731.062 c 0 429.577 715.678 440.533 699.756 450.312 690.938 c 1 627.471 633.981 714.58 464.648 745.281 311.469 c 0 760.765 234.216 762.307 160.588 753.469 104.344 c 0 749.05 76.2217 742.212 52.4326 731.844 33.8438 c 0 721.476 15.2549 705.23 -0.320312 683.75 -0.71875 c 0 565.464 -2.91309 424.149 -2.42285 305.344 -0.53125 c 0 282.402 -0.166016 265.232 15.5977 256.75 32.125 c 0 248.268 48.6523 245.436 66.8906 249.75 84.1875 c 0 274.365 182.881 361.806 251.63 421.281 292.781 c 1 399.838 289.834 377.165 291.562 354.531 299.062 c 1 351.254 297.26 346.258 294.138 340.219 289.969 c 0 327.609 281.264 311.019 268.81 294.094 256.531 c 0 277.169 244.252 259.965 232.135 244.625 223.438 c 0 236.955 219.089 229.89 215.527 222.281 213.25 c 0 214.673 210.973 203.976 208.323 192.969 216.844 c 0 188.307 220.453 185.401 224.89 183.625 229.5 c 1 159.831 222.733 129.83 228.257 107.281 252.562 c 0 92.5352 268.457 91.417 289.854 95.4375 312.094 c 0 99.458 334.334 110.216 358.511 128.781 380.281 c 0 160.388 417.345 194.83 478.688 206.812 510.438 c 0 219.869 545.036 223.64 562.48 231.625 581.844 c 0 239.329 600.523 250.813 618.832 275.031 649.469 c 1 275.119 650.062 275.18 650.924 275 652.281 c 0 274.367 657.046 272.557 664.732 270.531 673.438 c 0 266.48 690.848 260.581 712.629 267.438 735.469 c 0 270.361 745.204 280.118 751.195 290.125 749.406 c 0 313.004 745.315 329.197 731.893 340.688 718.969 c 1 340.829 720.367 340.988 721.656 341.125 723.031 c 0 342.049 732.302 342.939 741.087 346.094 750.094 c 0 347.671 754.597 349.732 759.521 354.844 764.406 c 0 358.677 768.069 365.076 770.884 371.281 771.531 c 0 EndSplineSet EndChar StartChar: q Encoding: 113 113 3 Width: 1000 VWidth: 1040 Flags: H TeX: 0 0 0 0 Fore 115.125 474.719 m 0 99.7812 474.719 87.4443 455.043 93.1562 441.062 c 0 98.4014 428.224 121.023 421.274 133.515 432.582 c 0 149.388 446.95 138.55 475.837 115.125 474.719 c 0 56.125 425.938 m 1 56.1562 425.969 l 1 37.6289 466.669 69.1982 513.902 113.219 514.625 c 1 113.219 514.656 l 1 113.625 514.656 l 2 113.795 514.658 113.955 514.688 114.125 514.656 c 1 143.925 515.666 161.199 497.272 164.562 493.625 c 1 164.531 493.594 l 1 185.954 472.207 186.8 439.896 171.762 416.359 c 1 191.233 392.181 210.862 368.746 231.906 347.312 c 1 222.834 411.217 216.43 476.043 217.013 541.339 c 1 201.923 547.531 188.982 559.244 182 575.312 c 1 181.969 575.281 l 1 181.922 575.379 181.615 576.08 181.531 576.281 c 1 181.562 576.281 l 1 163.265 616.246 193.118 667.031 243.969 665.281 c 0 260.842 664.697 276.899 657.585 288.75 645.25 c 1 288.781 645.281 l 1 288.98 645.093 289.658 644.413 289.75 644.312 c 1 289.719 644.281 l 1 315.129 619.177 311.907 578.594 287.487 555.231 c 1 287.683 554.524 315.245 437.864 357.031 375.125 c 1 367.561 452.847 383.829 530.352 408.895 605.317 c 1 402.273 611.266 396.786 618.669 393.031 627.344 c 1 392.969 627.312 l 1 392.921 627.413 392.616 628.136 392.531 628.344 c 1 392.562 628.344 l 1 363.46 691.921 450.876 749.154 500.25 696.812 c 1 500.281 696.844 l 1 526.363 671.668 523.628 626.754 494.062 603.406 c 1 494.094 603.375 l 1 493.997 603.291 493.299 602.718 493.094 602.562 c 1 493.062 602.594 l 1 489.417 599.57 485.549 597.05 481.53 595.013 c 1 480.367 491.137 486.014 427.452 493.812 386.844 c 1 525.616 452.681 572.493 529.854 601.203 566.851 c 1 601 567.312 l 1 600.969 567.281 l 1 600.922 567.379 600.615 568.08 600.531 568.281 c 1 600.562 568.281 l 1 582.265 608.246 612.118 659.031 662.969 657.281 c 0 679.842 656.697 695.899 649.585 707.75 637.25 c 1 707.781 637.281 l 1 707.98 637.093 708.658 636.413 708.75 636.312 c 1 708.719 636.281 l 1 735.542 609.781 730.46 566.033 702.219 543.5 c 1 702.25 543.469 l 1 702.156 543.387 701.479 542.839 701.281 542.688 c 1 701.25 542.719 l 1 689.535 532.929 675.506 528.372 661.554 528.319 c 1 644.643 486.175 631.903 442.367 623.781 397.688 c 1 623.781 397.625 l 1 619.435 374.081 616.274 350.712 617.219 328.656 c 1 644.406 357.782 686.581 416.552 720.248 450.207 c 1 708.467 488.745 738.507 530.559 779.75 531.438 c 1 779.75 531.469 l 1 779.956 531.48 780.678 531.5 780.781 531.5 c 1 780.781 531.469 l 1 800.157 532.273 818.938 524.166 831.625 510.344 c 1 831.594 510.312 l 1 858.193 483.574 852.942 439.881 824.562 417.531 c 1 824.594 417.5 l 1 824.503 417.422 823.847 416.895 823.656 416.75 c 1 823.625 416.781 l 1 808.222 404.072 788.892 400.307 771 403.881 c 1 715.619 322.125 669.789 188.215 668.844 133.875 c 0 668.524 115.465 650.369 114.214 646.735 113.733 c 1 637.768 63.3037 638.882 20.4844 622.875 9.28125 c 1 599.686 -13.2461 311.864 -5.35156 267.844 8.625 c 0 249.778 14.3613 248.798 17.4971 236.906 84.2812 c 0 233.959 100.838 232.794 110.921 232.336 117.62 c 1 219.878 120.409 215.005 129.479 214.969 137.438 c 0 214.751 185.638 122.017 357.464 107.665 386.422 c 1 86.0176 389.516 65.9248 403.272 56.625 424.906 c 1 56.543 424.98 56.2129 425.723 56.125 425.938 c 1 239.656 625.25 m 0 226.849 625.25 211.767 607.076 218.5 591.594 c 0 222.11 582.884 242.543 570.62 257.969 582.438 c 0 262.568 585.961 273.319 603.284 260.312 617.219 c 0 255.212 622.683 247.223 625.848 239.656 625.25 c 0 782.031 491.531 m 0 768.335 491.531 753.513 473.652 760.312 457.469 c 0 764.095 448.764 783.917 436.832 799.5 448.625 c 0 803.175 451.407 815.012 469.363 802.219 483.219 c 0 797.245 488.607 789.116 491.939 782.031 491.531 c 0 658.656 617.25 m 0 645.849 617.25 630.767 599.079 637.5 583.594 c 0 641.11 574.884 661.543 562.62 676.969 574.438 c 0 681.568 577.961 692.319 595.283 679.312 609.219 c 0 674.212 614.684 666.223 617.848 658.656 617.25 c 0 450.625 677.25 m 0 436.164 677.25 423.491 657.874 429.5 643.594 c 0 433.182 634.843 453.419 622.639 468.938 634.438 c 0 485.986 647.4 475.794 679.202 450.625 677.25 c 0 279.562 301.094 m 0 280.768 292.753 278.044 276.641 259.75 275.625 c 0 259.7 275.625 259.651 275.616 259.641 275.62 c 2 249.302 275.179 243.871 282.099 242.25 283.438 c 0 213.372 307.297 188.359 334.129 164.969 361.844 c 1 216.462 261.086 247.155 197.644 253.531 154.5 c 1 324.67 144.145 531.624 142.048 630.125 152.094 c 1 637.498 218.552 675.808 315.064 706.844 374 c 1 698.562 364.156 l 2 674.3 334.251 649.885 299.337 615.906 272.844 c 0 604.105 263.647 588.364 270.21 584.5 282.719 c 0 564.271 348.203 591.549 452.666 614.531 516.969 c 1 595.669 489.249 541.335 402.162 507.5 319.5 c 0 500.317 301.95 475.906 303.788 470.094 320.5 c 0 443.57 396.782 443.084 476.584 441.281 552.062 c 2 441.281 552.344 l 2 441.209 560.361 441.365 568.089 441.438 576 c 1 426.127 527.438 399.382 425.993 392.344 324.531 c 0 391.191 307.911 371.495 299.604 358.875 311.156 c 0 327.574 339.809 293.128 385.459 257.25 514.375 c 1 259.136 418.209 273.411 343.627 279.562 301.094 c 0 259.601 275.616 m 1 259.263 275.595 l 1 259.406 275.594 l 2 259.471 275.6 259.536 275.609 259.601 275.616 c 1 259.263 275.595 m 1 259.25 275.594 l 2 259.245 275.594 259.251 275.595 259.263 275.595 c 1 605.47 109.806 m 1 542.544 105.411 463.487 105.288 447.703 105.288 c 0 343.004 105.288 290.516 109.848 273.205 111.602 c 1 275.808 90.4492 281.647 63.5137 285.625 45.5 c 1 345.234 33 558.176 34.0234 595.531 40.875 c 1 599.128 55.3643 601.526 83.8633 605.47 109.806 c 1 EndSplineSet EndChar StartChar: r Encoding: 114 114 4 Width: 1000 VWidth: 1040 Flags: H TeX: 0 0 0 0 Fore 544.438 529.344 m 0 592.861 527.902 641.225 523.675 665.375 521.688 c 1 674.098 556.74 713.491 573.99 724.25 581.281 c 1 724.883 593.125 732.899 631.462 733.438 653.062 c 1 707.387 659.666 665.192 674.268 638.406 677.531 c 1 637.002 653.691 646.57 607.23 618 605.75 c 0 584.486 604.014 550.146 606.203 516.75 614.812 c 0 494.802 620.47 503.216 642.743 502.5 694.25 c 1 462.874 697.486 412.455 695.792 402.781 694.344 c 1 401.564 680.234 403.852 662.729 402.5 642.125 c 1 404.877 628.618 395.146 614.376 380.344 613.375 c 1 349.426 606.654 319.709 608.114 292.875 606.812 c 0 263.269 605.375 272.088 650.49 273.656 674.75 c 1 259.603 672.111 225.836 669.717 174.875 655.656 c 1 176.435 648.14 182.536 594.577 185.875 579.625 c 1 203.079 568.255 228.481 552.426 234.969 521.188 c 1 252.167 523.306 304.373 530.44 408.531 530.844 c 2 410.781 530.844 l 2 455.667 530.98 500.004 529.98 544.156 529.344 c 0 544.25 529.345 544.344 529.345 544.438 529.344 c 0 362.688 650.781 m 1 361.89 726.611 355.454 736.312 438.469 736.312 c 0 552.857 736.312 543.673 735.39 541.781 650.25 c 1 560.192 646.723 579.176 645.251 598.312 645.312 c 1 598.43 665.075 597.395 671.828 598.438 678.25 c 1 598.438 678.25 598.507 707.335 615.5 716.25 c 0 635.252 726.59 719.566 698.636 719.594 698.625 c 0 725.68 696.207 771.24 692.609 773.125 667.469 c 0 775.609 634.201 767.295 604.338 764.094 577.812 c 0 763.729 565.128 756.048 554.067 746.75 548.188 c 0 702.53 518.167 714.467 528.285 703.844 511.094 c 1 705.583 513.896 704.552 512.029 703.406 506.188 c 0 701.073 494.302 691.068 479.481 675.938 480.719 c 2 646.224 483.134 l 1 646.95 373.977 646.42 268.827 647.951 159.457 c 1 662.752 147.172 679.995 126.037 752.281 112.844 c 0 791.677 105.653 780.242 1.76172 742.5 1.625 c 0 580.679 1.08984 418.8 0.318359 256.875 0.53125 c 0 161.555 -0.864258 142.425 1.01758 135.469 8 c 0 110.129 33.5029 116.7 101.589 143.938 109.188 c 0 215.728 129.215 239.509 155.576 244.581 158.813 c 1 244.014 267.977 244.216 373.031 246.912 482.481 c 1 219.802 479.376 221.611 478.944 216.312 480.875 c 0 195.469 488.472 195.781 513.452 195.312 514.875 c 0 189.33 535.558 153.459 545.971 149 561.938 c 0 140.979 590.774 140.646 618.429 136.125 642.281 c 0 132.811 659.765 129.012 683.776 149.656 690.125 c 0 204.546 707.006 257.815 713.521 273.719 715.281 c 0 319.471 720.343 316.312 683.798 312.438 647.469 c 1 330.01 647.935 347.142 648.402 362.688 650.781 c 1 600.688 125.125 m 0 589.812 125.125 578.368 124.851 566.469 125.062 c 0 467.086 124.699 367.893 125.488 268.906 124.719 c 1 251.742 109.62 213.122 87.0703 162.969 72.0938 c 1 159.418 54.9023 160.33 47.8477 161.906 42.4375 c 1 190.205 40.9102 731.393 42.623 732.062 42.625 c 1 732.881 46.1396 733.382 52.0967 735.5 59.7188 c 1 736.479 68.3359 736.519 71.3486 736.188 74.1875 c 1 697.688 81.8711 657.095 95.082 625.781 123.938 c 1 617.803 124.752 609.496 125.125 600.688 125.125 c 0 284.591 165.909 m 1 316.202 166.102 537.493 166.312 600.719 166.312 c 0 603.08 166.312 605.462 166.294 607.865 166.252 c 1 606.142 274.514 606.834 378.753 606.125 486.094 c 1 518.801 492 367.903 492.644 287.094 486.25 c 1 284.36 378.05 284.062 273.913 284.591 165.909 c 1 EndSplineSet EndChar StartChar: p Encoding: 112 112 5 Width: 800 VWidth: 1035 Flags: HW TeX: 0 0 0 0 HStem: -2.1562 40<141.649 512.429> -1.1875 39.9062<165.43 262.793> 89.5938 40<222.924 439.496> 309.188 40<182.406 499.938> 391.375 42.789<284.745 392.096> 394.119 36.756<279.775 398.357> 619.727 40.044<260.275 414.492> VStem: 192.332 39.962<461.645 592.247> 442.474 39.963<461.645 592.247> Fore 236.812 129.594 m 2 428.812 129.594 l 2 444.23 129.811 454.142 112.826 446.37 99.5117 c 0 442.733 93.2812 436.025 89.4922 428.812 89.5938 c 2 236.812 89.5938 l 2 221.395 89.377 211.483 106.361 219.255 119.676 c 0 222.892 125.906 229.6 129.695 236.812 129.594 c 2 499.938 349.188 m 1 412.297 409.343 250.04 399.293 182.406 349.188 c 1 499.938 349.188 l 1 337.384 619.727 m 0 278.069 619.727 232.294 577.177 232.294 526.945 c 0 232.294 476.714 278.069 434.164 337.384 434.164 c 0 396.698 434.164 442.474 476.714 442.474 526.945 c 0 442.474 577.177 396.698 619.727 337.384 619.727 c 0 337.384 659.771 m 0 416.156 659.771 482.438 601.249 482.438 526.945 c 0 482.438 483.394 459.666 445.264 424.956 421.162 c 1 532.073 400.061 563.75 343.174 568.875 342.031 c 1 579.847 328.663 570.411 309.188 553.531 309.188 c 2 400.365 309.188 l 1 415.294 190.678 471.331 161.622 528.938 125.812 c 0 582.077 92.7803 567.705 7.16992 500.469 -0.25 c 0 469.363 -3.68164 216.203 -3.25195 184.656 -1.1875 c 0 121.68 2.93457 102.395 85.7266 154.062 122.25 c 0 193.172 149.896 259.381 185.425 273.712 309.188 c 1 135.781 309.188 l 2 120.011 309.199 111.092 325.796 118.281 338.844 c 0 131.664 362.468 166.085 401.021 250.957 420.375 c 1 215.604 444.429 192.332 482.917 192.332 526.945 c 0 192.332 601.249 258.611 659.771 337.384 659.771 c 0 360.312 309.188 m 1 313.844 309.188 l 1 298.334 168.232 213.108 115.01 177.156 89.5938 c 0 158.824 76.6338 157.959 40.6387 187.281 38.7188 c 0 217.137 36.7646 469.681 36.5869 496.094 39.5 c 0 533.419 43.6191 522.42 82.7832 507.844 91.8438 c 0 449.701 127.987 376.982 165.747 360.312 309.188 c 1 EndSplineSet EndChar EndChars EndSplineFont tagua-1.0-alpha2/data/themes/figurines/FantasyTTF/Fantasy.ttf000066400000000000000000000120141077523320400241210ustar00rootroot00000000000000 PFFTMD_ OS/2UbEXVcmap Zcvt !y0gaspglyf3"H head6hhea$hmtx4"loca z4maxpU8 name@)v4post*42仍_< JdJd!Q""ZQ @.1PfEdbr 8Z" !Ml=] s2wT8 bknrbknp!y,,,j!n./<2<2/<2<23!%!!!M f!Xl!Gi%".."47>76725&&2741476&47>'05&.6>6'.5.'&67662>.'&/&'2>76632'.''.'&6767&5'.'&>667&"%6.'@"8!S#;-* !R%G"b 15 "8*+= #  7C /B3_  Z2+ 6.$ W5 -  N?-g + JN/Ym<'/A&I20        >) K/ ,3+!0 - <:Q1G!7! 2# Rqu2 )   6   -<IaF E'WA=6"+&#"&>6323&767>'&&?6'26&'>'".'&'.'.'&>763667>7'&5676.>&#"667467>76&'&6'&'&>'.&'&67216&>&'&>'"&"'76S   D -$!@0  RPH 5;    ; =i+$ T"=!O"$A7 5/aB gE>M9 F B:   R  W% ! 1   =R   $K & 9 7- )A&DA-  *  V'!>- 2 '5 # $9) N #u(1N?(+:+4,*  $:1 J6 E" -/ r< &]k6'7676767676766?67676654620727676'.'&'&/'.'&'672'"#'&''.7672'&'&767''&''&767>7>76745&'&7><5>76  .  5[  -*?*Щ   +@`:  0     "N   @hF-  "  .   ,!.    M    "=. 0% 8@" &Vk9iaI &*  ',P     ! Qip=q^," md !   $'%N, ))s> Fa732'#&6%&"264&23+ '.67>7#"&767&54# 7>&'. D5X==X=wU9%;    !!!  "c;.   ,'7L77L_N7B( ):1.: $:# ;(C74'#  ( %3 2Q"76&&6736&7&'41&6067&'41&>0#67141&600##>7&634361'$'.'&'&54.'&'07"7>'&"7>'&'"7>'&'"76&#01'&'7>7&'&7&'.'45'.'#8#"'7>s  L&! # (%$"#  "156(%  J &(=% %          $),(6K.. 7B) (  1Z@]p? )  !2:,+nT <43~h (9HnF<7@B* \47;+) 2 6C6;!     }   ;   #0U\.1 7 Pad  $[09z ZW=.+ 5w 8>7465.'#'.7&#&676732'6&>323<5746766/#'&'&67>3&7'&'41.'.'&76766*#*#%0676'&'&%2323.5&" ,M   (#  7.@# ( !)  KcH O   O    .! oF." ):B#''$FH& BC>  8   &&" A  x" (  %   @74L  9*     #)@F#J~     F n   Created by Monge Maurizio with FontForge 1.0 (http://fontforge.sf.net)Created by Monge Maurizio with FontForge 1.0 (http://fontforge.sf.net)FantasyFantasyMediumMediumFontForge 1.0 : Fantasy : 19-7-2007FontForge 1.0 : Fantasy : 19-7-2007FantasyFantasyVersion 001.000 Version 001.000 FantasyFantasy2 ENQSTU?X<XCutagua-1.0-alpha2/data/themes/figurines/FantasyTTF/theme.desktop000066400000000000000000000002571077523320400245000ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Fantasy Type=Application Comment=Google-like controls X-Tagua-ThemeType=Figurines X-Tagua-Variants=Chess[default] X-Tagua-Script=theme.lua tagua-1.0-alpha2/data/themes/figurines/FantasyTTF/theme.lua000066400000000000000000000004111077523320400236000ustar00rootroot00000000000000import("piece_theme.lua") function Fig(char) return Glyph("Fantasy.ttf", char, 3) end theme.bishop = Fig("0x0062") theme.king = Fig("0x006b") theme.knight = Fig("0x006e") theme.pawn = Fig("0x0070") theme.queen = Fig("0x0071") theme.rook = Fig("0x0072") tagua-1.0-alpha2/data/themes/figurines/ShogiTTF/000077500000000000000000000000001077523320400214435ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/figurines/ShogiTTF/mikachan.ttf000066400000000000000000000214041077523320400237360ustar00rootroot00000000000000pFFTM?"GDEF'!"OS/2~ :xVcmap^lcvt HDfpgmR glyfOa head6hheaN4$hmtx>loca2.7t H8maxp7 X name:DlpostҴF!prep%> /_<KK^Xp4 Take@0hppXy"lH%w8$('C8LZaM"**;"2 0hNNN N]NNQhQkQmVW-gOhBkissґђۙ0hNNN N]NNQhQkQmVW-gOhBkissґђۙϛ|u2ΔvBnDmgED?ED@EDAEDBEDCEDDEDEEDFEDGEDHEDIEDJEDKEDLEDMEDNEDOEDPEDQEDREDSEDTEDUEDVEDWEDXEDYEDZED[ED\ED]ED^ED_ED`EDaEDbEDcEDdEDeEDfEDgEDhEDiEDjEDkEDlEDmEDnEDoEDpEDqEDrEDsEDtEDuEDvEDwEDxEDyEDzED{ED|ED}ED~EDED  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~,,,2~V(r4z* b"w./<2<2/<2<23!%!!"UV"fl@?01&'&'&/&76?6/&76767676'767hD0 *$%; K ,&80,6)#)/6xd (B& 6<_s=:$ )>>\")34eN:&>#/"3j)B"#D"*C;0Z/9  & %H1 0176$&Hc34&37777%77+?)S?)?S?S))*}}S*}S*isv/]F/F0F/.G/GG/]w 01'?3%;''6 ;'#'%+77p=K88- T%]&V? ]J079$T'89g8L80.015>7'7"&577'737635'7/7'7#8TC3"3v!""DC32"3T3"!23T!UT08^q&8qq&&KKK88KKpq]$! 017'6$7%'7>7&5~!81:;VU u~2t!7?#'9, .4#A%(/#* R+01'67#56?#/6 7&237%>7'U-DG <.u' fL*-NQ QN+..7Y +#A(T 7( 784  *0 gVR T1601&?67''&7'7#57>7/'%#%hm\ +pdI 2Pk[RHVB_a\Fn -`p7#=s#jB6!fh5_- >q Fo}sD2] A 2&;@@3'01'>73/&/5623<=F.'9bO?!./757%5.'7&#'O 7K !1 WAc,!/`AX B 19+X"n+O2.oA~ 2[C#.[~[CB2D&!9e< /('$ 8%,)L+ O%+01'67%& #%57''.57''>7#%'P %e | L%~ K2K ?K WY  e2H[b** M)O4P j['Oi = kMLH?%@ 7%Y 7%f++@65M0$NN +++01'6235#'5635'7''7%5#'57<337&#637&#37"#7#'gEA4 DBE)=Bq?' OFBDVX>or ,X[-K2f?';' NN 8! > _F5 =* {# ;7 6g.  ; ZU5< /P6+01'6&?&'?#'6?'?37'./%%5!!. !l' : CP "" Љ$RQ :]Q  $P lmMB 0pX2!6.y, M!B, 9! @M!!!YB! Wa , dTg ;?*+@VQ\TS^N; F++++01'647''7>'#'>346737"?#'675#'6?637&373727+"/>37'##'  -  $> 5$ $#QH# #?> u,,HY& P7#c-G:1YZ- 6}'+}?6-@tk-5 ,l5 b ci:F :/R/; /i ;]#/ #F$: ./#^J# // /% :##  .; . u/uQ\aZ AJ01/>?37'77'#'7''75#57'?3?'62337'377#'%./?a sLt9ujj0 'DM}Ck   10j  & D'k9}Ck(Wf0k: 0p  lf(o2 2(*= 2)(G e \(((3 )z ( y)2  eM%501/?7'/775#56$7'3%'37/>37'''r r  dr3<re~4 3YL X &e22eAM 3qx8()7S6*S87 *)86 )5 o*)S7**"$- +f+01#'>3''6?#'7$%&#7&"#$#%;(O] B3 ^ K2B]]?wC'j wB)VBI,,+<;H\ ,-+*V$*:A01'?'?''%676 76%7'&7'7%?& SH >t]S[Ag7.KG&3e16H8+^ xIh` h +!K4xog D I#">G9D AKp 9C]dC0DAC ++01.#57'7#'775#'''737.'777#''37'%'{S*D4[)s{.pD2L";:+XmdXDmFd T}(2" +0").4/Mn#'38U<0$ 7"6y 8GRhmufeMH+G?h9+015'7.'?'#/7377/>7'37'6&'#37#'7'=7'7'3757'77'/'7375'?35'3?75#37%'%/&r  9/8 & LU& :%%%:% / 9 ' _&h9 & V g8C 0 U& & C_ 8K L9r & UL`'4N\] P&Bp]wNA 653A P4B5(CA5((5P 53CvvAv(4 ONP(5 i 4( vA((4 ( A N] 'B([ ]*LBNTaej :EX+01/7'?'''##'#/737'7'7%7#7'5'7/757'1%'.57'%7'%57'=8 6 K#00<-S3(,;! 21 c3cq ,@+ts7~$[k e0r $#z ~ }]WJm  a`} %6DE$ W9* 6Eg9d"jTN+V9gkh'` (F,d7o+h:3 n m  ;^)/6=D-P>+@ 2?=+?5(J.+++01'5#'757''>?37.'7"%5!3757!3757'5/ i LM 3Qm MdT .'.f*݊gg(}=>R[:Kq@ck,2. y w!' ;z 3 "nH #9SeY( D  C"WYeqz=b+WJ8S3++01/?7/.?37'#'>5'736$7#'"#3>3#'1337">3#%5&45>?/?7/?57&#57'75#3'75'#1~=1 @%  7Z %7D62f6" $E@r#M+= %   -H $   'K <u%$-8j,--P-x>& U"  3 )8OR  5  5 )h "<I@ @ $M)$ Hg 1!  kN P "  K5J'N;OV\z~5b*=++XFH"/++01.'&4'?#'737&6"37"7#37&?'73%535"'>35#'3?"3'5'6275#'75'77"#37'%7'"Q " Qj$ -  6= >,X Z=?+=H- =?.} $*$F;-?O--?-G G$,j6$O#? - 6"4Zt.LPl .FS#$ $ j /; :!1/ # :###0y5#0C3"  J# .j] ; F;#0 $/ u;#R$ j #$i ;# St i 9Xr   H ` {      $ 0<D VbtmikachanmikachanTagua_mikachanTagua_mikachanRegularRegularmikachanmikachanTagua_mikachanTagua_mikachan9.09.0Tagua_mikachanTagua_mikachanmikachanmikachan00K0a0000K0a00Regular00K0a0000K0a009.0mikachan00K0a00mikachanmikachanRegularmikachanmikachan9.0mikachanmikachan0     uni3068uni4E00uni4E03uni4E09uni4E5Duni4E8Cuni4E94uni5168uni516Buni516Duni56DBuni572Duni674Funi6842uni6B69uni7389uni738Buni89D2uni91D1uni9280uni98DBuni9999uni99ACuni9F8D ?tagua-1.0-alpha2/data/themes/figurines/ShogiTTF/theme.desktop000066400000000000000000000002171077523320400241400ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Shogi Type=Application Comment=Shogi figurines X-Tagua-ThemeType=Figurines X-Tagua-Variants=Shogi[default] tagua-1.0-alpha2/data/themes/figurines/ShogiTTF/theme.lua000066400000000000000000000021241077523320400232470ustar00rootroot00000000000000import("piece_theme.lua") import("shogi_themelib.lua") function Fig(char) return Glyph("mikachan.ttf", char, 2) end theme.num_9 = Fig("0x4e5d") theme.num_8 = Fig("0x516b") theme.num_7 = Fig("0x4e03") theme.num_6 = Fig("0x516d") theme.num_5 = Fig("0x4e94") theme.num_4 = Fig("0x56db") theme.num_3 = Fig("0x4e09") theme.num_2 = Fig("0x4e8c") theme.num_1 = Fig("0x4e00") theme.king1 = Fig(shogichars["jade general"][1]) theme.king2 = Fig(shogichars["king"][1]) theme.rook = Fig(shogichars["flying chariot"][1]) theme.p_rook = Fig(shogichars["dragon king"][1]) theme.bishop = Fig(shogichars["bishop"][1]) theme.p_bishop = Fig(shogichars["dragon horse"][1]) theme.gold = Fig(shogichars["gold general"][1]) theme.silver = Fig(shogichars["silver general"][1]) theme.p_silver = Fig(shogichars["narigin"][1]) theme.knight = Fig(shogichars["knight"][1]) theme.p_knight = Fig(shogichars["narikei"][1]) theme.lance = Fig(shogichars["incense chariot"][1]) theme.p_lance = Fig(shogichars["narikyo"][1]) theme.pawn = Fig(shogichars["pawn"][1]) theme.p_pawn = Fig(shogichars["tokin"][1]) tagua-1.0-alpha2/data/themes/figurines/XiangQi/000077500000000000000000000000001077523320400213545ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/figurines/XiangQi/theme.desktop000066400000000000000000000002251077523320400240500ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Xiangqi Type=Application Comment=Xiangqi figurines X-Tagua-ThemeType=Figurines X-Tagua-Variants=Xiangqi[default] tagua-1.0-alpha2/data/themes/figurines/XiangQi/theme.lua000066400000000000000000000023661077523320400231700ustar00rootroot00000000000000import("piece_theme.lua") function Fig(char) return Glyph("ukai.ttf", char, 4) end theme.rn_1 = Fig("0x4e00") theme.rn_2 = Fig("0x4e8c") theme.rn_3 = Fig("0x4e09") theme.rn_4 = Fig("0x56db") theme.rn_5 = Fig("0x4e94") theme.rn_6 = Fig("0x516d") theme.rn_7 = Fig("0x4e03") theme.rn_8 = Fig("0x516b") theme.rn_9 = Fig("0x4e5d") theme.bn_1 = Fig("0x0031") theme.bn_2 = Fig("0x0032") theme.bn_3 = Fig("0x0033") theme.bn_4 = Fig("0x0034") theme.bn_5 = Fig("0x0035") theme.bn_6 = Fig("0x0036") theme.bn_7 = Fig("0x0037") theme.bn_8 = Fig("0x0038") theme.bn_9 = Fig("0x0039") theme.black_general = Fig("0x5c07") theme.red_general = Fig("0x5e25") theme.black_advisor = Fig("0x58eb") theme.red_advisor = Fig("0x4ed5") theme.black_elephant = Fig("0x8c61") theme.red_elephant = Fig("0x76f8") theme.black_horse = Fig("0x99ac") theme.red_horse = Fig("0x508c") theme.black_chariot = Fig("0x8eca") theme.red_chariot = Fig("0x4fe5") theme.black_cannon = Fig("0x7832") theme.red_cannon = Fig("0x70ae") theme.black_soldier = Fig("0x5352") theme.red_soldier = Fig("0x5175") theme.advances = Fig("0x9032") theme.retreats = Fig("0x9000") theme.traverses = Fig("0x5E73") theme.front = Fig("0x524d") theme.rear = Fig("0x540e") tagua-1.0-alpha2/data/themes/figurines/XiangQi/ukai.ttf000066400000000000000000000457301077523320400230350ustar00rootroot00000000000000FFTM=`K8GDEF'.KOS/2bvVVORGgKTcmapN~\"cvt DgaspKglyfayB0head(6hheaT$hmtx>0jloca:lRmaxpqpx namej|GpostU±IRvhea K\$vmtxHJKX_<?KAKADW ((WZ1  (?@.33f PfEd@1ff(vDM\7H`Xv[t1cRLnuw;sZP/< 9NNN N]NNNOPQkQmQuRMSRTVX\^%^spvx2aʐ21NNN N]NNNOPQkQmQuRMSRTVX\^%^spvx2aʐ2Ҳ }=.ˬǬ @1r)sqZp%of{ D,,,F:(B p( P @ & \>J!DU./<2<2/<2<23!%!!D"UD #2#!5"'RX-bq99q3$74'"#"32767&'&74567672!7'!676Swp s%!3%"J@lbJ_VXX#jBUٲne^h~4" 7... E_€jhHoU4'&'7674'&'5#"32767&'&767672&'&#"27632&'&767674'&#"676'+9oW fv!!'-  =qP@ETD($9;_ILJXVoKO#. !o|ţt}XH \fQX^1"!! 3("$>=DR@  79@I=D/7%4!1q[_SeH#!#!5"'535)C }5E!Hu^99^u95!672&'&'47674'&'"67654'&'&!e|jLh^QYuC?  )( mqjkV*&+_IdZF 42 ( 1QE^YkuX!v1@67674'&'5'""767327674'&'5"#"5672&'& y|t|we  c_=,"!$& e[i ˄hrC@JJxqNKLh{fY-"$',\D? 5KRQIlu[!676733276576's/cZimh+'T_s-4K!IH5#5E!67674'&'67654'"#"&'&'4767&547672&N{j@Dز11d ctI4t.?{3Y]g[M1}7EJdkEJ74|r^SO[dbFCHTJT^_Y@CYM\R[bA<{HFVEuLP8S UhCL\D@9C[SJE@K,>%6'&'5"#"567&'&747&'&#6672&'&'4Vqv njpbgz@&%",$c]Eu~QK1-dzVCE):qwr퍉 ,G 4C>>|_vm3%DRW!"7676%676'&'&'&'"! \S >   Kq%[q嶎 B G W( ' F5  5!-?d6%276'&'&'&67676'&'&'&76767677676765&'&"#/&'&'&564   KfNt  J-)  c,#R B>t+$YYoY2,NL +5+~V9M`( 2 $7:8&4  52W VAe"3"2*Q0   )' )0:n*,I767%676'&'&727$%6'&'&'&767$727676'&'&Ld{w N9zn$<F!?P2K',B, N[ "[_%  g`{  >R" 7(1  9 N    j K767676'&'&'&&'&'&'&767676'&'&767676'&'&'&"767676767676767676P 'TQc_/.mG$& 58'v[N'$_"-\(> d* + .&.( -R_9-4!CsX"=1 $T|A!<o- ){Y,#a2,  .%' P1'   BOi4B K0 |Ync    P\%fn.! >(zƥ)&%Y?B3 AR:767%676'&'&'&"767$%67676'&'&'&'"wKPwI-s:KD$ Xf0(   Nn%[~ʘ  4 N!  > CP+ ( F5  3'c]`p76'&'&'&676'&'&'$76'&'&7676376767'"#&767$%67676'&'&6&7P  0|!};C/c4BU:F%  '-)2+@(ז rh9  Z & !3CVJVXPVv $:2f"-M  ? *2 KBP3    )  ,; -&  ,  $=  9R[U776576'&'&'&'676'&'&'&676767$!276'&'&6%7676/&76'&'&'&7236%4 ' % X}+!".$ !e3UK  RΦ! &   &  afxB["$ 7 UB   I qms4L5PnKYnqCA"!!9Vcv& #' N {h}j  ' C J+(  &  35 , dJ ;0Ll( 767645637676'&'&&56776767676'&'&'&6767676'&'&'&47676'&'&'&'&76763&'&767276776?6362676'&'&'&5$&'72767&'&'6727676'457676'&'&'67676'&'&'&76   9؁!  Z %sCg]z! <*U!  'uD%1mby{k=+*\P(  8^ ?7 ?l:7`00  C3V Jo$KQ K"yMI&6'0=)Y+7t5o!'#,3~`*e./   Vg|89 A;+% O|  VK7$M  kf< $ &wA 'B  YB  I@ +   7O-=  '   P2  >h8 G 9, . 9    k7 05 bS>B"# Ma4I#$ \h81*&1, nAX8L#27676'4576'&'&'67676'&'&'&'76767676'&54'&'67676'4'&'&76'&'&'67676'&'&'&&'&7676%$'&'&7676767676'&'&'&6767676'4'&'&723'&'776763767767674'&'&77676'&'&'&7676'4'&'&*<   MU_8/87("  Qd6   T1 --& {pL 7!b0A%7 %   b'0FH%5&q#*"$ #O#c[(C+_*  /!1F1"-OZo! ,<= 9<-  2D !/ #1>) (: h  8DB">B"# Mat# U aY(5&$ =2  vz)+ X@+IB+    5 "  >%   F4;  D*-4c   uP% IKB ** + |<    -     x1s X  )-+I    ,& 9   )**N  676767676'&'&7656/$&&'&Px%o  5LUU b749Y_(g{#(-~2c3   go o4vh [k4  ec  w+*BX723676'&'&767$!27676'&776767676'&'&#"7676'&'&%&%- Q-  ' LP ] B"  (~r T '|SC SA!%  !i {$(-T3!7  !G { #aP H WT; ky> [    nTb{767$%276'&'&676'&/$76'&'&'&&76'&'$767276'&'&'&&'&'7672%676'4'&'&%76'&'&%&" !&% c"D-  oPD  ',D%m%g`'  .f#?9F;[IzW+@ I c!x1* K" ך&$^  " !  V + .  = !4' D;# '- R- _hdlh  %Li蟧 \ &#G 3 ?  #>Nv"767$%67676'&'&'&'"767676'&'&'&276'&'&/&'&767676'&'&'&7676'&5&7676'&'&'&367654'&'&675676/&767677676'&'&'&&"#7276?6'&'&'&6'OA ]g!   <_[ٙ9Y  ci'3# $>3 ^%3s+ %1n> Y!W  /   ) (   i[ 364   2= W0 K &DZ/:A %2" J(5F2< a>   8- ?.DHT+ $wB!6 0 ]  rL) +8ge@J.):Qr=7    * ,/_N,  WA&duT  0"/r~>(*A  `W(L7676'&'&767$%676'&'&'&276'&'&/#476'&76767676'45&7676%7676'&'&47676'&'&'677276'&'&'#676'&"&#&767$j@ $9 P]V: <.]/;z "((  hL3 M&=- )eb % yp"  ]pf  ! Jv OY;FN1 G#7 ? &&  EX Pc  #V 2 01   XM.4! 4: @sy=>- EN1 nu;Kd  {->C> w=R OB[WB[{=ER B~ V E VuFp}767$!3676/&'&"6765$767676'&'&'&&'&7676276%676/#676'&'&'&&'&7676''6%6>@  + iIx +od*   2o(   e$! - ED"  6_.9! "*KU  $3 C!,->'4 E EpID J\, '-\< ^tt C!3&! 4C- Z1J!+|O!MY3  C  ER~*JK8? Oq  &7CF('  $ :t  ;F}K%767$!2276'&'&$7676'&'&'&76'&'&'&#"7676%& ,  D! C  m~G!!5 J$wt(>36476'&'&'677676767&#7676'&'&'&'&7676'&'&76767'767637674'&'&777676'&'&#&7767626767676'4'&'&67676'&'&'&32'&'&'&76767&67276/&676'&'&'&72767676'&'&'&{   -!5      % p @  .& 2 e.P%= 1i- 'y  $R C"m$, + sjt-Gm ,ALh)!,'! 6,=V -[  n/ ?tq \`NT  9= 2$" ǹ20    - 7Q  'DtM#$ +# CC  _b[+ j5M" Oq^1) 0@yf ) n "3  u   +  #    Wv0,: %(2')S=IQ H }G C > ' .  PZP  >8?   +CB ;^5^o76767674'676'&'&4776767674'676'&'&67676'&'&'&"&'&76764776764767676"%767645476'&'&'&767676'4576'&'&'&67676'&'&'&&7676767276  m629 v\^p50: lV=W0d0 ';%D"8- '    # i@[  X  R  &4  # 8   gA + -HG ( 3\  ?=";5!  9 C'!3 Y .zK  # X4dD(  +Uu *fTKD" ",  "]O/.  % KS>ªp; Y " V wXQ" NK =ZrW  !pE> '   3LA #j9@:=,A+~7676'&5&'&#%?676'&'&'&72767645&7656!276'&'&76'&'$76'&'&'&7677676%6D(0$ " H4n $4# !=4 X    )D0  uz")pD%u_BRg7/& ",% 8Q  =E_Ej'! 'l &aid Z#1~* I'0  . pFR" > N 767$'&'&767676676'&'&'&6767676'&'&#76&'&%6767676'&'&'4'&'&'&'&76776767674'676'&'&'&5676676'&'&'&#7676'&'&'&67676'&'&'&676'&'&'&72776767>2Y 72-J ! @'.&k vBR ?4'**6U  7  $ ?\R\ nr D/*uQMX.  W/') (1.-T6  lX[ # !B  =;  9 {[4,"&!1 /J!  U DH9X - k,F {8 WA 7]l>o;(  ('WC"( -E[q  D?\r?6% M' E E2". '6[#%~$  " R H-A Szx-)%WA* BF ! -'JHI "4!'{ & qqOW  ws`3676'&'&'&6767676'4'&'&476'&'&'&7676776767767676677676'4'&7676'&'&'&&'&7654%&2%6'4'&'&7%6'4'&'&67656%6&o  5>dD710$:#  C}ADk#'HT uZ+3!&4J8 7 a8(]q   # % ghcI  %  h4Pu9N'+& $twJL&INY-$+2N  Z]pP^MB" / E ! ' @" 326=4!Z[n 76767674'676'&'&'&6?&'$76'&'&'&763&'&6477676'&7&'67676"767$'"'&7676676'&'&'&67676'&'&'&76&'&%6?676'&'&'&'&'&'&'&76776767654'676'&'&'&65676"6 O4'- "6,U\?@&D?)'dHet73[(#  o$  XJ BZ  ! (\7/ 8: u',i 'MW(?6* .GEc  3i    ;c37Tlg" ' >"&lJER) S+'+  '- /68  kG,  % N$ [     &  EGX &Vt?*! 3!=  dA ]= J5  V-5,  '' ^I.$# }{  b  EAG'?2H' + -.) '3U&+ +  ] $-P TPm767676/$'&/&'676'&'&'&&'67676'&'6767676'&'&676'&'&'&4'&'&7676776#&767652776777676743767$6'65'&'&72767676'&'&&7&'$&&'673V(i y ^$W,Cp*%  I,O, !b"-|@/1O 6</FQ>?P+ $c~W 92   i xE\M_2O$E  "[79!,F  C''& (&l6 V -qݍ-+ [ Rp#%-,   a1A}--  "We9$'@  3 , 1& "E#,;: P(>   =% P+ o K  d2M67 E>a`8AL   cI# @QyT.$   /   QLz& gw 7676456%7676'&'&&56776767676'&'&'&6767676'&'&'&47676'&'&'&'&76763&'&7672767767$362676'&'&'&5$&'72767&'&'67   "!  Z ]z! <*U!  'uD%1mby{k=+*\P(  8^  ?7 ?l:7`00 C3V Jo$KQ Z"yLJ&6'0>)Y+7t5o!'#,3~`*eK7$M   k",f< $ &wA 'B  YB  I@ +   7O-=  '   P2  >hT G \, . 9    k7 05 bgBgx&'&767676##'&747677676776767676'&'&'&"4376'&'&'&67656%62&63276'&'&%&%367676'&'&'&#&37676'&'&'&"&7676727676'&#%&'&'43676'&'&76767&'&'&'"'"76765,"  83!M*  Y "G  %h7&I %3.D#)  !"g0A,$ 6I s&  cC & *%0(&  <' vSF'#G> U"J098 q #w^. .%&0/J*@ =Tj#7h3@ %%H, kVUc@&'F'OY( .k? !/  y-  q;9 > J  fyh&hq '}9%%%  42!  && ;    - Jao $ L&<45:R*/1N(0O '" ++  # :BMvX#276'&'&'&7676'&/67676'4'&'&'76743767767$!3676'&'&67676'&'&'&67676'4'&'&6'&'&'$76'&'&'&76776776?237276'&'&'&&"76767276%6'&#%&'&'676'&'&767676'&'&'&7676m;"  9 >y  !4=$!  75#,KEc  C(   !51 V$   __M2WU&5.Cc"6(+ 696QRej) ;M"  >)IW Xl4=$  J?#!L;Q#:xyVXLt $@ti  1%!,,+H./ 2X,6 ) 4D="#$0%0E"%(!G]?!)! "zs [wfaC<3=JO 7w;  LG = P       f53   t-=!&J'2  < "&{  E#92(,(!7%J%.?&'  [ 0+BA!!Y,2/Ow67676'&'&'&476'&/$76'4'&'&"&'&'$%'"#&'&7676776'6/&"767676'4'&'&7673'&'&7676767767637676767676'&'&'&#767676'&'&'&'&7767676'&'&&%7674/&" /):!    6o K*!  n$$,-24?  $| (F.(W< FC[C .!A+  +Ze2  U2E BX+  4E^-  '  $ #%1!>)9< uTX6   %7I !2 2 :(sw1 #B,  2FY!  !7 -  6dB &D_% `wr3-  -G=2F1ry- 5: c4 -!,$ 83"V`L (r       P    (c) Copyright 1994-1999, Arphic Technology Co., Ltd. Modified by Arne Goetje(c) Copyright 1994-1999, Arphic Technology Co., Ltd. Modified by Arne GoetjeTagua_ukaiTagua_ukaiRegularRegularFontForge : AR PL ZenKai Uni : 5-11-2004FontForge : AR PL ZenKai Uni : 5-11-2004Tagua_ukaiTagua_ukaiVersion 1.0 Version 1.0 Tagua_ukaiTagua_ukai2(     uni4E00uni4E03uni4E09uni4E5Duni4E8Cuni4E94uni4ED5uni4FE5uni508Cuni516Buni516Duni5175uni524Duni5352uni540Euni56DBuni58EBuni5C07uni5E25uni5E73uni70AEuni76F8uni7832uni8C61uni8ECAuni9000uni9032uni99AC '?22fZW(ffu`KuxKfKK'oG?;f} ]tagua-1.0-alpha2/data/themes/pieces/000077500000000000000000000000001077523320400172715ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/AlphaTTF/000077500000000000000000000000001077523320400206745ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/AlphaTTF/Alpha.ttf000066400000000000000000001174301077523320400224460ustar00rootroot00000000000000LTSH]TsT`OS/2T\$VVDMX^q8cmapK\^\cvt *fpgm2Ds]bglyfX8Thdmx.head> 6hhea]D$hmtxF_W plocaurTsmaxph namegaezpost&Hprep+qY_<Op]}\\&  SWAP@      ( 2= D Z h ~   Chess AlphaRegularChess AlphaChess AlphaChessAlphaChess AlphaRegularChess AlphaRegularChess AlphaChess AlphaChessAlphaChess AlphaRegular,  )+9BHLRTWbhlqtw !+1BHJNTWbhjntwdl\""&  XZ[\L&&!&!&&&L+,KPXYD_^-, EiD`-,*!-, F%FRX#Y Id F had%F hadRX#eY/ SXi TX!@Yi TX!@eYY:-, F%FRX#Y F jad%F jadRX#Y/-,K &PXQXD@DY!! EPXD!YY-, EiD` E}iD`-,*-,K &SX@Y &SX#!#Y &SX#!#Y &SX#!@#Y &SX%EPX#!#!%E#!#!Y!YD- ,KSXED!!Y-*00ffRfR\\R\R*''{:^:^`                                                         !  ! !  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%%%%%%%%%%%%%%%%$%%%%%%%%%%%%%%%%%%%$%%%%%$%$%%%$%%%%%%%%%%$$%%%%%%%%%%%%%!# !# %%$%*+**************+*********************************************************&(%!&(%!**+*..........................................................................*+ (%*+ (%....22222222222222221222222222222222222222222222222222222222222222222222222222-/",(-/",(22126666666666666666666666666666666666666666666666666666666666666666666666666613%/+"13%/+"6666::::::::::::::::9:::::::::::::::::::::::::::::::::::::::::::::::::::::::::47(3.$47(3.$::9:CC""CC"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=?.;5*=?.;5*CCCCKL&&KK&KKKKKKKKKKKKLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKDG4B7.54632!3!4&+"&''3&;2!"&5!&'&&66'&%6533##5#5BABCzM3J" L-R4DBCr`*!:R;:S;"*`rDBE3S-L !J4L{xw~/<;0}q^__^_B77BLru|5i'P xtqww` 26:LL:62 `wwqtx P'i5|uTF))FT ++hhhYY0N?OTY?/3 +3Q%+Q%Q9G%Q9%IиI/016?!&67>7&'7'6767676#!&>&'./67>7''76'7/nos`V+-#& `NJps3z (@N/MF6oL> 8Fu\l#(3;1c"Ne70 td%.9!$EK٬Rrn*yR2V)'c})AZ & ?!O~ב~PE> [C d78E )67/8/7и/4A4444444]A 44&464F4V4qAe4u4qи/8ܸ.Aj.z.qA.......]A ..).9.I.Y.q и /,969/ ++"++"и"и )01!6'&'#!5&67>7!%&54632!!'654&#"[PumVhgVnuO[iHIhaUeeUJPr3[JrggrJ[3rPJeLeeL #'+/37;?CGKOSW[g //tиt/и/zܸ'и'/'9'9t4и4/zJиJ/L'9tPиP/tA]A &6FVqAeuqrиr/zAjzqA]A )9IYq|и|/'9'9:/B/J/L/P/T/X/j +j~+ j9 к j9 к j9 к"~9% j9 &и ,и 0к1 j96 j9j\и~bи\iܸ~pиi01%#'3#3'7'3#'3#'3#' 375'375'3  3!5#5#5#57!6'&'#!5&67>7!%&54632!!'654&#"q::::\ '?::c::?:: ~,fuuE:o;d:VDh= :,u[PumVhgVnuO[iHIh::/],':T :y:K/:A:f:uO: 2:dE:h ::,::uaUeeUJPr3[JrggrJ[3rPJeLeeL #'+/37;?CGKOSW[i:/B/J/L/P/T/X/ +g+ к g9g9g9 9 кg9 9 к% 9 &к- 9 .и 0к1 96 9Dg9Mg9Qg9eg9g901 3 '3#''73#?3#'73#%'73#!75'35'35'73!5#5#5#5767>7'>?!&67>7&'7''%.'76!.7%'2&'7:&::9@ ?::[c::'::A::%uy&":&&:e:,uwNe70c1;3(#l\uF8P6FM/N@n  t z3spJN` #-+`soR"dt%.9!d&:/(?:2:y=:7:(:怯:u::(&8:f::,::u [C3>EP~˅~O!?SZA)}V2Ry*nrRـfٚK'Zd78 #'+/37;?CGKOSW[_ckp+A]A &6FVqAeuq99#9l9z9|99/и/99ܸи/99и/иии//F/N/V/X/\/`/ +t+ty+++ 9 к 9 к! 9 "иy$и$/) 9 *к1 9 2к4 9 8к9 9> 9yAиA/Jt9P9oܸyиyииииyиtиoиии01 #1 3#'3#53#'3#3#'3#'7757'35'35'73!5#5#572'6#"#!46;267637+"!267!67.7>7.54632!3!4&+"&''3&;2!"&5!&'&&66'&%6533##5#5F:F::::?:: jc::G@:: ::I ueB%:N :aJ:,uBABCzM3J" L-R4DBCr`*!:R;:S;"*`rDBE3S-L !J4L{xw~/<;0}q^__^_FF:ƀH# :/b::T/i:y::.:f:uOQ:,(:KK:X:,::uB77BLru|5i'P xtqww` 26:LL:62 `wwqtx P'i5|uTF))FT ++hhhYY 6DGS`dhlptx|F@p+@3 +3Aj z qA ]A  ) 9 I Y q ܺp9p9p9p9p9@!ܺ*p9Ep9Fp9Gp9Xp9Zp9ap@9pbкep9pfкip9pjкrp9tp9up@9pwк|p9pкp9p9pкp9 9 9кp9кp9p9p9кp9p9 39p9p9 9кp9p9кp9p@9p9и3a/e/i/s/{///++0 +0+и0$и7и =кw99к99к9к9к9к9017>54&#"'!&#"!'&632>7>32.'.#"67"&'632&#36535#5#%57!5!5 535'73553537!'3#'3#?3#'73#'7 37'u'sfS,.G22=N>=K J>=N=G--RgҭtԵH/Y]]\^Z]kk.0kk^ޯu_,_fD@:y:4:%WI::uf::wc::U5?:: y::}:'(TVT?X`mXBT*TTJm^HJ<s9[BкM[9[NкRnt9U[9[Vи[`и[dкe[9siкs9кs9ии[01'7'75 37'3#'7573#%3#73#' 375'35'7'735'73'735 5#57!&7.#"2>7 '>!6'#"&54632&'&676&7>7&'&54632#"'"3254"32546"3254"3254&%7'7'73R 'Dt:_ =::+FF?::::i ::f ,fu#M n:"':9-::,u5 dmnc 4olW>{{=Wlorq 6MM66M d@D66T56T66C ?d M66MM6 pr>>?>>>w??>>>>ZwȋT :7RL/E't:^1=:/::E:y0B:,-:A:f:u]5M:1n>):'2"$:# :,::u'99'5)iiY+ii)5M66MM6H,^D6D.d.D6D^,H6MM66M=I>>>>>>>>qHVVM>>>>>>>>qHVVSVT1!C + / / //++и01%!7'!35;35!!')!')2!!2MM}vkUkmvXXyWW0N -7Q// 99#9)9,9.939017%&'>?&67>7>74&''&'7'&%4E."dt~os`V+-#& `2A}>\ps3z af"xA @7ma'K٬Rr 98"y*yR2V)_epOlE// 9901%!5&67>7!%&54632![PumVhgVnuO[JPr3[JrggrJ[3rPJ3bGSQH+Q;HQ9HKиQM/47+4IJ+I4-ܸиܸܸܸ ܸ.к;4-97>и4Bи3Cи KܸNиJOиIP01!&/7&&66#67.7>7.54632#&;2!"&5#!46;2676#33535#5#4..vyxCr`*!:R;:S;"*`rD !J4L{zM3J" __^__^'+$.II11I(tqww` 26:LL:62 `wwqt5|urru|5YYh I5 *=Weh{/BиB/AqA]AqnAnqAn]Anqn9B9B9B9B9ܺKn9nTܺfn9gn9hn9|B9~n9ܸииT/>+++++E6+E+9+9+9Qкf+9g+9h+9+iи6qк|+9~+9и01!')&'67.546327"&'632&&'.'&'.#"6!'&632>7>32467>32&654&#"7'533#&5#5 ## % &y{KC#ZH/Y]]\^Z.R+ 3AgƖ=N>=K J>=N=!Z"DJ{w'ʖfB2 ,R/^kk0.kII<3003 /l`Y}D6ƜTy$$y~U +?Tx}J:m^HJ<7&'&54632#"'267.#">!&')%&%7'N;rq 6MM66M d@D66T56T66C ?d M66MM6 prmd lookcn :: wȋHVVM66MM6H,^D6D.d.D6D^,H6MM66M=9')0*44*0)'9"''"HVVWTV #'+/37/// ///// /$/(/,/0/4/99 9 99999!9%9)9-9195901333333375#5#5#5#5#5#57ufAAfuuQ,,u:f:A:::A:f:uu:Q:,:::,::u #'+/37;?CGKOSW[y]/// ///"/(/,/6/>/F/R/Z/(9(9 (9 (9(9(9(9(9(9 (9$(9&(9)(9-(90(92(95(9:(9=(9B(9E(9J(9M(9N(9Q(9V(9X(9e(9q(90157!5!5!53  '375'357!'3#'3#'3#'3'3#'#%!5&67>7!%&54632!u_,_^A= :{D+d:;E:uQuf' ~::c::?::: '=:\ ::q:[PumVhgVnuO[:u,::: E:d:2O::u:fK/:: :y%':x], ::JPr3[JrggrJ[3rPJ5:?CGKOSW[_cgkosw{A/J/V/^/f/n/p//z//////A9A9 A9A9A9+A91A94A9:A9@A9FA9IA9LA9NA9PA9RA9UA9XA9ZA9]A9`A9bA9eA9hA9jA9mA9qA9uA9vA9}A9~A9A9A9A9A9A9A901 1# &%>?&67>7>74&''&'7'%&73 '3#''73#?3#'73#%'73#!75'35'35'73!5#5#57FF:f"xA os`V+-#& `2A}>\ps3z "dt4E.B:&::9@ ?::[c::'::A::%uy&":&&:e:,uF:F:epOl0'K٬Rr 98"y*yR2V)m@7&:/(?:2:y=:7:(:怯:u::(&8:f:,::uGSW[_cgkosw{^/f/n/v/~///U///////47+4++K +K^U9%^U9-к;^U97>и4BиKNкZ K9]^U9b^U9e^U9h K9j^U9m^U9p^U9r^U9u^U9xиx/z K9}^U99^U9749^U9^U9749^U9и/^U9 K9749^U99^U9^U9^U901!&/7&&66#67.7>7.54632#&;2!"&5#!46;2676#33535#5##1 3#'3#53#'3#3#'3#'7757'35'35'73!5#5#574..vyxCr`*!:R;:S;"*`rD !J4L{zM3J" __^__^F:F::::?:: jc::G@:: ::I ueB%:N :aJ:,u'+$.II11I(tqww` 26:LL:62 `wwqt5|urru|5YYhFF:ƀH# :/b::T/i:y::.:f:uOQ:,(:KK:X:,::u# #'+/37;?CGKOSW[aiwz<F+<+AjzqA]A )9IYqܺF9кF9F<9 к F9F99кF9F99F9F9 F9"к%F9'F9(F9)к,9-к1F939F6к8F9;F9F>кCF9DF<9IF9KF9LF<9FNкPF9FQкTF9FUкXF<9FYкbF9xF9yF9zF9<и<ܺF9F9F9F9F9F9F9F92/:/B/J/P/T/X/a+a\+\_++a9кa9кa9к%a9&и(к)_9,к-a96a9>_9a]кx_9y_9z_9к_9_9_9ик_9_901' 37'73#'73#?3#'3#!3735535'73535 5#5#57!')&'67.546327"&'632&&'.'&'.#"6!'&632>7>32467>32&654&#"7'#36535#5#(}::: y?::y5c::::%fu$I:W4::UD@:Qf,u ## % &y{KC#ZH/Y]]\^Z.R+ 3AgƖ=N>=K J>=N=!Z"DJ{w'ʖfB2 ,R/kk.0kk^::T2x:yo:=1::f:u$:W::4!:t):.Bf::,::uII<3003 /l`Y}D6ƜTy$$y~U +?Tx}J:m^HJ<9F9h9j9k9m9999к9999901'7'75 37'3#'7573#%3#73#' 375'35'7'735'3'73!5#5#577!6'#"&54632&'&676&7>7&'&54632#"'267.#">!&')%&%7'R 'Dt:_ =::+FF?::::i ::f ,fu#M n:"': ^:-:,u;rq 6MM66M d@D66T56T66C ?d M66MM6 prmd lookcn :: wȋ7RL/E't:^1=:/::E:y0B:,-:A:f:u]5M:1n>):'2"$:w1_ :,::uHVVM66MM6H,^D6D.d.D6D^,H6MM66M=9')0*44*0)'9"''"HVVWTVf K / /ܸܸ и/ܸ + + 01!#53##!!RRRRR++01=!%5!RRR O / / и/ܸ  ܸܸ+ + 0135#533!5!RRmRRff+++////01!#3#3RRR+++////01!#3#3RRff K / / и/ܸ  ܸи  + +01!!!3#5fHRRRf++015!%5!fRRf G / /ܸܸ  и /и ++013!5!3#53fRRfRR2(Vf++9g+9)иgv////=+={_+{9999Sܺ){S9Q{S9016?6767#"327.'&'&/&'3276=4'&/&54?676=#"'&%276'&'&#"5476?654/&'&=4763 #"'&#3#3 SGE  FGSg8xqqxDC+  ,CBkE[D?h=&\]&=i?FZAogPOp]^UX{~WU^\@j3>j6ZYe6j=2j=[\\[=RR"1*%# *' $%*14FKK JI01 51IFM9IaL CpA!!@:5224:A BpC#KaE!9MFo=M/*Eq4@m51-TBC##BS./7m?3qB-+Q=K%&&%'\ //01!#53#RRRR+01=!RRR //0135#53RRRR\+//013#\RRR+//013#RRR\\ //013#5RRR\+015!\RR\ //013#53RRRRR+Yi+<j+<,иjy//@+@~b+~ 999#9Vܺ,~V9T~V9013#36?6767#"327&'&'&/&'3276=4'&/&54?676=#"'&%276'&'&#"5476?654/&'&=4763 #"'&RR TGE  FGSf8xqrx?C+  ,CBkB[D?h>&\]&=i>EZAofQOp]^UW|~WU_\@j3>j6Z[e6j=2j<[\\["1*%$ ** $%*14FKK'CI0171IFM9!EaL CpB A:5225:A BpD"KaE!9MFo=M/*Eq4@m7/-TBC##BS./7m?3qA.,P=K%&&% K+ + + //// 9 901#567673#3#3Z94*I;::RR<"V#35-/?+ܸܸ1//// +01!#3#3!47676767654'&#"'67632RR *)Lw**&);?('\ >?gh?=*,_MV#111=b9934&%''E f76;9W,*)02O@*A?++C////96901!#3#37327654'&#"72327654'&#"'67632#"'&RR|X%$5<-+('># 8--!55!$X9:U8400?$#DEi^?>\ L !+,?<(( M>0 "?W21+-0/&'-0D_@B97_+++ и//// +и 01!#3#35!533#RRROJcc[R$RK,M+ܸܸ.////+901!#3#37327654'&#"'!!632#"'&RRm_ &'5A--+,E+$"TGl(BI_BB:Gyd?@]E"#10RJ/, xV-BBheGY89',>5++////901!#3#3&'&#"67632#"'&547632327654'&#"RRW %3++/1/X>>45>oEELCrT75#"'7)(((;;+)2&9:l0ACeB;9 QQ^R/0x/(*-,NJ+++-7++//// + 01!#3#35!#676767RRqIDG$^! ?;HXGOz[rY{zvoS''7I?++////9901!#3#3&'&547632#"'&54767327654'&#"327654'&#"RR687_^9:5C!#ABjk@A##1!!44!"!24 !$#)@))+*@>))#&$5P4676O2%&//D\???>_E1-2! 00!! !'"#))>?**)+FJNK@+@и/%и(/D/HG+HLK+L013276765#"'&54767676767<54'&#"'6767632#&5!5!{/b5 33('.002V.."!-c;!C@V 53CD)+\z #(9(*)C&    66 7#!%8v#WRR,-/./- и / ܸи/.ܺ 9 и/%Aj%z%qA%%%%%%%]A %%)%9%I%Y%q//++015!%5!#3632#"/327654'&#"oRY7X/-+BC]^4*H:**(*9:*+fRRG"%00:HJM^*E31eg1133+v$+$A$$$$$$$]A $$&$6$F$V$qAe$u$q /++015!5!#"'&54767632&'&#"3276W;;Ul@A:7EV66V ,C*)((A5""\RRC Y43FEU?? +,N401gk-0 .Q+и/ 9'и'// /++015!%5!5#"'&'&547676323327654'&#"2`?3566>/%$X*):;()*(=;('fRRBN"">(*\RR, Q,,GGIIGH W,.B!3(*!S!+! и!/++ + и 015!%5!#5354767632&#"3#OO !=$/(fffRRF76# N/0F8-=>/?/>и/.A.......]A ..&.6.F.V.qAe.u.q и /?$ܸ6ܸи/6и/6!и!/*/++015!5!3276765#"'&5476763253#"'&327654'&#"+V!:<#! ;Vl<;62G]b=*-[5'$$fRRI((PSD $$?{?//ܸܸи///9 901!#3#567673RRY 52-K989< V#320'+'()+(-*/(/+01!&7676767654'&#"'67632#3 '*Lz&*&'<@('\ >=ig?=**`R RRV4.2++('># 9--! 55 # X::T:202@##DEh`=@RR\ K!!++@='( M>0 "?V31+-0/&&-.F`?B97O//ܸܸи/и ܸ//+ и01!#35!533#RROIddKR$R()+//+901!#37327654'&#"'!!632#"'&RR^ '&6A,-++F+#%TGk'BH`BA9Gyd?@]E"#10RL-, xV-BCgdHY89:+//!901!#3327654'&#"%&'&#"67632#"'&547632RRf#"'8'('(<:+*hX %3+)/00V@=44?nEFMCqT76,+*-,NI,++,2&:=i0ABfE89 QP`R/1+//+01!#35!#676767RRJBH$^ !>9IXGQxal[ypnT#3E'+//9901!#3&'&547632#"'&54767327654'&#"327654'&#"RR897^^:94B#"AAjjBA$!2!!44 !!33 "#!+@()**@>))#&%4O5676O1&&/0C]>???^F0-2! 10!! !'"%)'@?**)+f7J?0+0и/и8/5/+015!#"'&54767676767<54'&#"'6767632#&'32767651-/3U/.#8l2!C@V 33CC*+\ 4]7 34'&\RRW++)B(    57 8!#$9v#  $);f$()/*/)и/ܸи/*ܸAjzqA]A )9IYqи/$9/"/&%+&01327654'&#"#3632#"'5!n*H:**(+8:*+RY7X/-*BD\^4|^*E33df1131G"&00:IJNRRf#'j +A]A &6FVqAeuq/%$+%01#"'&54767632&'&#"32765!W;;SO?@!" /f$(/+&%+&+01!&'&#"#"'&547632!32765!p#*D=)*\8;[sCCDCmiBC{-,@0$"B!3)( R*-GGKHGH W-.zRRfG+и/++и01#5354767632&#"3#5!OO !$"K@;|24**lRRfQ//и/ܸи ܺ 9 ܸи// /+013632#4'&#"5!&[>b=*-[6(#$fI((PSD$$?RR  +FNQ_c d/1и1/ܸܸи к191919и/1'ܺ:9WܸCܺOW9PW9QW9RиR/`19bW9Ce/G,+G+4$+4K+и и4@иRи$Z01533#&5#5"&'632.7&'.#"6!&5&$32>7>32%!&#"65.#"7!6'#"&54632&'&676&7>7&'&54632#"'"3254"32546"3254"3254'%77 irsh 6sq!"puvv9OO98Q iDF88X78W97GCi P98PP8vwAAAAA@|AAAAA@]&M(<<(7+rB+7O98PP8!K-cH8I-S-I8Hc-K!8PP89O)wA@@AA@@AALX[nA@@AA@@AANVXWYW8 !70+.+.++)+)" +"(+*++ + ииии(,и(.и*/и(101!7)!7)!7'!35;35!%!/?#!5+!5#rsUTd3-,4dD9 HH׏ 9dMMMM{pdpR{M|rr|\fr~)x}+x}x9}x9s}x9s/$и$/-}x9}0и0/x6и6/9}x9svܸBиB/M}x9O}x9vyиs{3/! +!+f+fgb+gwx+w$иAи!EиIиOиUи Yиf^иwsиx|012'6#"#!463!267>737+"!267!67.7>7.54632!3!4&+"&''33!2!"&5!&5&&66'&%6533##5#5UEDFGQ6M#P/U6FEFxd-"7''>?!&7>7&'7'767>!&>4'./'76'7##Qi;30sxde-.% dQN{Kx5   BQ1PI8S:Iz`p'$*6=3fyh'0;! _E>)NVvq 0JE~V4Y5+E^WB"SʄSI@Ti 9: )78/9/8и/5A5555555]A 55&565F5V5qAe5u5qи/9ܸ/Aj/z/qA///////]A //)/9/I/Y/q и /,979/)++"++"и) и"017!6'&'#!5&6767!%&54632!!'>54&#"R_Szs(ZlkY'r{R_.7>32467>32&265.#"7'533#&5#5m  $"$%NF$!]V#B)aab`*B"U- 5CkΜ@QA?N N@@R@ ]!$HM|қjE4 -V1boo20oMMMC1131 2qe]G9VG77G؃'Y )BWŽ}P%|{bLL??LLb4e9G]eq2LV+P}WB (&YYWZbbcc%]CS[_cT+TDX+DXD9XD9XD9GXD9QXD9\XD9]XD9^XD9`XD9bXD9017!6'#"&54632&'&676&7>7&'&54632#"'267.#">!&')&%7'Hvv9OO98Q iDF88X78W97GCi P98PP8vwri psuohs (' {RI[XO98PP8!K-cH8I-S-I8Hc-K!8PP89O)<()4+77+4)(и4Bи3Cи LܸOиKPиJQ01!&/7&&66#67.7>7.54632#3!2!"&5#!463!267>#33535#5#KK/0yFxd-"?&7>74>74&''&'7'&%6I0$iysxde-.% d4DB_{Kx5 j#}D"B:qe)NUw <:#~/JE~V3Y68t]q// 9901)5&6767!%&54632!`_Szs(ZlkY'r{R_MTv6^NwkkxM^6vTM #'+/37;?CGKOSW[_ek) +v+y+y{+v9tܺt9 9 9# 9= 9E 9G{9Mt9O 9W 9 +l+?4+?|+|c`+cz+zif+i 9 кz94?9|9 9 к 9 к! 9 "и (и ,к- 92 9?6и4=и4Dи?Fи4Lи?Nи4Tи?Vи?Xи?\к]4?9|rиztи|vи|xиииии01%3773#'3#'3#'3#' 37  #35#35#35#3 7#3!5#57!7)!7)!7'!35;35!%!/?#!5+!5#2:L::U?::Dc::w"::K,fui A5::Q::",9:Fv::Zzi::,uxxGG2!!2-6 EE 6L>:/6:T 6:y=:z3L:A:f:u :A5?::7v::{i,::u#JJJJvkUkmvJwm攔m!w #'+/37;?CGKOSW[_u{1mi+mim9im9Gim9Mim90/4/>/F/N/V/]/|`+|+nx+nк9 кxn9икxn9ии и"к&`|9(и*к5`|98`|9Jxn9Xxn9Z9nhиxz0157!5#3 %#35#35#35#3  7!'3#'3#'3#'3#737%!7'!35;35!!')!')u_,I::~z::jv,9:"Q::v::i AufUK::S"c:: ?::0::2:2!!2MM}:u,::{i7v::?: :AJ:u:fz3L:=: 6:y6:T>:lMvkUkmvXXyWW I5 =DT[cftxy/-и-/AqA]Aqܸи к -9-9-9и/-ܸlAlqAlqAl]%ܺBl9El9OиO/Q9SиS/U-9X-9dl9el9fl9gиg/u-9wl9%z/](+]+0+0`+и и0"и(*и]cиgиo01533#&5#57.'.#"667632)'&6327&'63216767&#"&'676'&'!&#"%'>54&#"7^kk0.k#G--Rgҭt2=QN==NP<1]]\^"Z./Y9#& %$22sfS,.G____;TBXm`X{1$/m/#1%yyGVZ<7 '>!6'#"&54632&'&676&7>7&'&54632#"'"3254"32546"3254"3254&%75 dmnc 4olW>{{=Wlorq 6MM66M d@D66T56T66C ?d M66MM6 pr>>?>>>w??>>>>Zwȋ'99'5)iiY+ii)5M66MM6H,^D6D.d.D6D^,H6MM66M=I>>>>>>>>qHVVM>>>>>>>>qHVVSVTs $ s`pbX} : Z !&!F!""""## #4#H#\$x$%0%& &w&'9'(b)))*Y*+o+,,o,-,--../&/0-001C12Q3}45\67T899:;;@rAC*\.nulluni0020uni0020   !!""##$$%%&&''(())**++,,--..//00112233445566778899::;;<<==>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~tagua-1.0-alpha2/data/themes/pieces/AlphaTTF/gradient darkgrey.bmp000066400000000000000000000300661077523320400247670ustar00rootroot00000000000000BM606(@@0# # EEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ[[[\\\^^^```bbbccceeefffhhhjjjlllnnnoooqqqsssuuuwwwyyyzzz|||~~~CCCEEEGGGHHHJJJLLLNNNNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjlllnnnoooqqqsssuuuwwwyyyyyy{{{}}}AAABBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjlllmmmoooppprrrtttvvvxxxyyy{{{}}}???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^___aaacccdddeeegggiiikkkmmmoooppprrrtttvvvxxxyyy{{{}}}===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRSSSUUUVVVXXXZZZ\\\]]]___aaacccdddeeegggiiikkkmmmoooppprrrtttvvvxxxyyy{{{}}}~~~;;;===???@@@BBBDDDFFFGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccdddeeegggiiikkkmmmooopppqqqsssuuuwwwyyyzzz|||~~~999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccccceeefffhhhjjjlllnnnoooqqqsssuuuwwwyyyzzz|||~~~777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjlllnnnoooqqqsssuuuwwwyyyzzz|||~~~555777999:::<<<>>>@@@AAACCCEEEGGGHHHIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjlllnnnoooqqqsssuuuvvvxxxyyy{{{}}}333555777999:::<<<===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffgggiiikkkmmmoooppprrrtttvvvxxxyyy{{{}}}111222444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\]]]___aaacccdddeeegggiiikkkmmmoooppprrrtttvvvxxxyyy{{{}}}///111222444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccdddeeegggiiikkkmmmoooppprrrtttvvvxxxyyyzzz|||~~~---///111222444666888999;;;===???@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccdddeeegggiiikkklllnnnoooqqqsssuuuwwwyyyzzz|||~~~+++---///111222444555777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___```bbbccceeefffhhhjjjlllnnnoooqqqsssuuuwwwyyyzzz|||~~~)))+++,,,...000222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjlllnnnoooqqqsssuuuwwwyyyzzz|||}}}''')))+++,,,...000222333555777999:::<<<>>>@@@AAACCCEEEFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjlllnnnoooppprrrtttvvvxxxyyy{{{}}}%%%''')))+++,,,...000222333555777999999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbcccdddeeegggiiikkkmmmoooppprrrtttvvvxxxyyy{{{}}}$$$%%%''')))++++++---///111222444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUVVVXXXZZZ\\\]]]___aaacccdddeeegggiiikkkmmmoooppprrrtttvvvxxxyyy{{{}}}!!!###$$$&&&(((***+++---///111222444666888999;;;===???@@@BBBDDDFFFGGGIIIJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccdddeeegggiiikkkmmmoooppprrrtttuuuwwwyyyzzz|||~~~!!!###$$$&&&(((***+++---///111222444666888999;;;<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccdddeeefffhhhjjjlllnnnoooqqqsssuuuwwwyyyzzz|||~~~!!!###$$$&&&(((***+++---///000222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ[[[\\\^^^```bbbccceeefffhhhjjjlllnnnoooqqqsssuuuwwwyyyzzz|||~~~!!!###$$$%%%''')))+++,,,...000222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjlllnnnoooqqqsssuuuwwwyyyyyy{{{}}} """$$$%%%''')))+++,,,...000222333555777999:::<<<>>>@@@@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjkkkmmmoooppprrrtttvvvxxxyyy{{{}}} """$$$%%%''')))+++,,,...000222333444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^___aaacccdddeeegggiiikkkmmmoooppprrrtttvvvxxxyyy{{{}}} """$$$%%%'''(((***+++---///111222444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRSSSUUUVVVXXXZZZ\\\]]]___aaacccdddeeegggiiikkkmmmoooppprrrtttvvvxxxyyy{{{}}}~~~!!!###$$$&&&(((***+++---///111222444666888999;;;===???@@@BBBDDDEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccdddeeegggiiikkkmmmooooooqqqsssuuuwwwyyyzzz|||~~~!!!###$$$&&&(((***+++---///111222444666888999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccccceeefffhhhjjjlllnnnoooqqqsssuuuwwwyyyzzz|||~~~!!!###$$$&&&(((***+++,,,...000222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUUUUWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjlllnnnoooqqqsssuuuwwwyyyzzz||| """$$$%%%''')))+++,,,...000222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjlllnnnoooqqqssstttvvvxxxyyy """$$$%%%''')))+++,,,...000222333555777999:::<<<===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffgggiiikkkmmmoooppprrrtttvvvxxx """$$$%%%''')))+++,,,...///111222444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYYZZZ\\\]]]___aaacccdddeeegggiiikkkmmmoooppprrrtttvvv!!! """###$$$&&&(((***+++---///111222444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccdddeeegggiiikkkmmmoooppprrrttt###!!!!!!###$$$&&&(((***+++---///111222444666888999;;;===???@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccdddeeegggiiikkklllnnnoooqqq%%%###!!! !!!###$$$&&&(((***+++---///111222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]^^^```bbbccceeefffhhhjjjlllnnnooo(((&&&$$$""" !!!###$$$&&&''')))+++,,,...000222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjlllnnn***(((&&&$$$"""  """$$$%%%''')))+++,,,...000222333555777999:::<<<>>>@@@AAACCCEEEFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbccceeefffhhhjjjlll---***(((&&&$$$"""  """$$$%%%''')))+++,,,...000222333555777888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```bbbcccdddeeegggiii///---***)))'''%%%###!!! """$$$%%%''')))++++++---///111222444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUVVVXXXZZZ\\\]]]___aaacccdddeeeggg222000...+++)))'''%%%###!!!!!!###$$$&&&(((***+++---///111222444666888999;;;===???@@@BBBDDDFFFGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccdddeee444222000...+++)))'''%%%###!!!!!!###$$$&&&(((***+++---///111222444666888999;;;<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ\\\]]]___aaacccddd666444222000...+++)))'''%%%$$$""" !!!###$$$&&&(((***+++---///000222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXZZZ[[[\\\^^^```bbb888666555333111///---***(((&&&$$$""" !!!"""$$$%%%''')))+++,,,...000222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^```;;;999777555333111///---***(((&&&$$$"""  """$$$%%%''')))+++,,,...000222333555777999:::<<<>>>@@@@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\^^^===;;;999777555333111///---***(((&&&$$$"""  """$$$%%%''')))+++,,,...000222333444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPRRRTTTUUUWWWYYY[[[\\\???===;;;999777555333111000...+++)))'''%%%###!!! """$$$%%%&&&(((***+++---///111222444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPQQQSSSUUUVVVXXXZZZAAA???>>><<<:::888666444222000...+++)))'''%%%###!!!!!!###$$$&&&(((***+++---///111222444666888999;;;===???@@@BBBDDDEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVXXXEEEBBB@@@>>><<<:::888666444222000...+++)))'''%%%###!!!!!!###$$$&&&(((***+++---///111222444666777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUVVVGGGEEEBBB@@@>>><<<:::888666444222000...+++***(((&&&$$$""" !!!###$$$&&&(((***+++,,,...000222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHJJJLLLNNNOOOQQQSSSUUUIIIGGGEEEBBB@@@>>><<<:::999777555333111///---***(((&&&$$$"""  """$$$%%%''')))+++,,,...000222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHIIIKKKMMMNNNPPPRRRKKKJJJHHHFFFCCCAAA???===;;;999777555333111///---***(((&&&$$$"""  """$$$%%%''')))+++,,,...000222333555777999:::;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPNNNLLLJJJHHHFFFCCCAAA???===;;;999777555333111///---***(((&&&%%%###!!! """$$$%%%''')))+++,,,...///111222444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMNNNPPPNNNLLLJJJHHHFFFCCCAAA???===;;;999777555444222000...+++)))'''%%%###!!! """###$$$&&&(((***+++---///111222444666888999;;;===???@@@BBBDDDFFFGGGIIIKKKMMMRRRPPPNNNLLLJJJHHHFFFEEEBBB@@@>>><<<:::888666444222000...+++)))'''%%%###!!!!!!###$$$&&&(((***+++---///111222444666888999;;;===???@@@AAACCCEEEGGGHHHJJJUUUTTTQQQOOOMMMKKKIIIGGGEEEBBB@@@>>><<<:::888666444222000...+++)))'''%%%###!!! !!!###$$$&&&(((***+++---///111222333555777999:::<<<>>>@@@AAACCCEEEGGGHHHXXXVVVTTTQQQOOOMMMKKKIIIGGGEEEBBB@@@>>><<<:::888666444222111///---***(((&&&$$$""" !!!###$$$%%%''')))+++,,,...000222333555777999:::<<<>>>@@@AAACCCEEEGGGZZZXXXVVVTTTQQQOOOMMMKKKIIIGGGEEEBBB@@@???===;;;999777555333111///---***(((&&&$$$"""  """$$$%%%''')))+++,,,...000222333555777999:::<<<>>>@@@AAACCCDDD\\\ZZZXXXVVVTTTQQQOOONNNLLLJJJHHHFFFCCCAAA???===;;;999777555333111///---***(((&&&$$$"""  """$$$%%%''')))+++,,,...000222333555777888999;;;===???@@@BBB___]]][[[YYYWWWUUURRRPPPNNNLLLJJJHHHFFFCCCAAA???===;;;999777555333111///---+++)))'''%%%###!!! """$$$%%%''')))***+++---///111222444666888999;;;===???@@@aaa___]]][[[YYYWWWUUURRRPPPNNNLLLJJJHHHFFFCCCAAA???===;;;:::888666444222000...+++)))'''%%%###!!!!!!###$$$&&&(((***+++---///111222444666888999;;;===???dddaaa___]]][[[YYYWWWUUURRRPPPNNNLLLJJJIIIGGGEEEBBB@@@>>><<<:::888666444222000...+++)))'''%%%###!!!!!!###$$$&&&(((***+++---///111222444666888999;;;<<>><<<:::888666444222000...+++)))'''&&&$$$""" !!!###$$$&&&(((***+++---...000222333555777999:::iiigggeeebbb```^^^\\\ZZZXXXVVVTTTQQQOOOMMMKKKIIIGGGEEEBBB@@@>>><<<:::888666555333111///---***(((&&&$$$""" !!!"""$$$%%%''')))+++,,,...000222333555777999kkkiiigggeeebbb```^^^\\\ZZZXXXVVVTTTQQQOOOMMMKKKIIIGGGEEECCCAAA???===;;;999777555333111///---***(((&&&$$$"""  """$$$%%%''')))+++,,,...000222333555777mmmkkkiiigggeeebbb```^^^\\\ZZZXXXVVVUUURRRPPPNNNLLLJJJHHHFFFCCCAAA???===;;;999777555333111///---***(((&&&$$$"""!!! """$$$%%%''')))+++,,,...000222222444tagua-1.0-alpha2/data/themes/pieces/AlphaTTF/gradient lightgrey.bmp000066400000000000000000000300661077523320400251550ustar00rootroot00000000000000BM606(@@0  }}}|||zzzxxxvvvtttsssqqqooommmkkkiiihhhfffdddbbb``````}}}|||zzzxxxvvvtttsssqqqooommmllljjjiiigggeeecccaaa}}}|||zzzyyywwwuuusssrrrpppnnnllljjjiiigggeeeccc~~~|||{{{yyywwwuuusssrrrpppnnnllljjjiiigggeee~~~|||{{{yyywwwuuusssrrrpppnnnllljjjiiihhh~~~|||{{{yyywwwuuutttsssqqqooommmkkkiii}}}|||zzzxxxvvvtttsssqqqooommmkkk}}}|||zzzxxxvvvtttsssqqqooommm}}}|||zzzxxxvvvtttsssqqqppp~~~|||{{{yyywwwuuusssrrr~~~|||{{{yyywwwuuusss~~~|||{{{yyywwwuuu~~~|||{{{zzzxxx}}}|||zzz}}}|||}}}Ƚʺ˸ζгұӮ֬ة٧ۥtagua-1.0-alpha2/data/themes/pieces/AlphaTTF/theme_babaschess.desktop000066400000000000000000000003021077523320400255420ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Alpha (BabasChess style) Type=Application Comment=Alpha TTF theme,|as BabasChess's default.| by Eric Bentzen X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/AlphaTTF/theme_babaschess.lua000066400000000000000000000020211077523320400246520ustar00rootroot00000000000000import("piece_theme.lua") shadow = 7 shadow_color = "#404040" shadow_offset_x = 3 shadow_offset_y = 3 shadow_grow = 6 function fromGlyphBG(fg, background) return function(glyph) return function(size) local i = Image(background) local b = Brush(i) b:scale(size/i.width, size/i.height) return fromFontGlyph("Alpha.ttf", glyph, fg, b)(size) end end end fromGlyphW = fromGlyphBG( "#1f1f1f", "gradient lightgrey.bmp") fromGlyphB = fromGlyphBG( "#b1b1b1", "gradient darkgrey.bmp") theme.white_bishop = fromGlyphW("0xF062") theme.white_king = fromGlyphW("0xF06B") theme.white_knight = fromGlyphW("0xF068") theme.white_pawn = fromGlyphW("0xF070") theme.white_queen = fromGlyphW("0xF071") theme.white_rook = fromGlyphW("0x00A0") theme.black_bishop = fromGlyphB("0xF062") theme.black_king = fromGlyphB("0xF06B") theme.black_knight = fromGlyphB("0xF068") theme.black_pawn = fromGlyphB("0xF070") theme.black_queen = fromGlyphB("0xF071") theme.black_rook = fromGlyphB("0x00A0") tagua-1.0-alpha2/data/themes/pieces/AlphaTTF/theme_eboard.desktop000066400000000000000000000002451077523320400247060ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Alpha (Eboard style) Type=Application Comment=Alpha TTF theme.| by Eric Bentzen X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/AlphaTTF/theme_eboard.lua000066400000000000000000000021271077523320400240170ustar00rootroot00000000000000import("piece_theme.lua") shadow = 7 shadow_color = "#404040" shadow_offset_x = 3 shadow_offset_y = 3 shadow_grow = 6 function fromGlyphGrad(fg, grad1, grad2) return function(glyph) return function(size) --local g = LinearGradient(Point(0.3*size,0), Point(0.7*size,0)) local g = RadialGradient(Point(size*0.8,size*0.8), size*0.99) g[1] = grad1 g[0] = grad2 return fromFontGlyph("Alpha.ttf", glyph, fg, g)(size) end end end fromGlyphW = fromGlyphGrad("black", "#627183", "#DEEAEE") fromGlyphB = fromGlyphGrad("black", "#292052", "#73697B") theme.white_bishop = fromGlyphW("0xF062") theme.white_king = fromGlyphW("0xF06B") theme.white_knight = fromGlyphW("0xF068") theme.white_pawn = fromGlyphW("0xF070") theme.white_queen = fromGlyphW("0xF071") theme.white_rook = fromGlyphW("0x00A0") theme.black_bishop = fromGlyphB("0xF062") theme.black_king = fromGlyphB("0xF06B") theme.black_knight = fromGlyphB("0xF068") theme.black_pawn = fromGlyphB("0xF070") theme.black_queen = fromGlyphB("0xF071") theme.black_rook = fromGlyphB("0x00A0") tagua-1.0-alpha2/data/themes/pieces/AlphaTTF/theme_jose.desktop000066400000000000000000000002431077523320400244100ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Alpha (Jose style) Type=Application Comment=Alpha TTF theme.| by Eric Bentzen X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/AlphaTTF/theme_jose.lua000066400000000000000000000013331077523320400235210ustar00rootroot00000000000000import("piece_theme.lua") shadow = 7 shadow_color = "#404040" shadow_offset_x = 3 shadow_offset_y = 3 shadow_grow = 6 function fromGlyph(glyph) return fromFontGlyph("Alpha.ttf", glyph, "black", "white", 6.0) end theme.white_bishop = fromGlyph("0xF062") theme.white_king = fromGlyph("0xF06B") theme.white_knight = fromGlyph("0xF068") theme.white_pawn = fromGlyph("0xF070") theme.white_queen = fromGlyph("0xF071") theme.white_rook = fromGlyph("0x00A0") theme.black_bishop = fromGlyph("0xF06E") theme.black_king = fromGlyph("0xF06C") theme.black_knight = fromGlyph("0xF06A") theme.black_pawn = fromGlyph("0xF06F") theme.black_queen = fromGlyph("0xF077") theme.black_rook = fromGlyph("0xF074") tagua-1.0-alpha2/data/themes/pieces/BerlinTTF/000077500000000000000000000000001077523320400210625ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/BerlinTTF/Berlin.ttf000066400000000000000000002326601077523320400230250ustar00rootroot00000000000000LTSH{OS/2TLVVDMX^q/cmaplcvt *fpgm2Lsebglyf3`khdmx˒. ,head 6hheaxD$hmtx Hlocasf-maxpuh nameVpostٶ!~.Eprep+ _<N.mww"  SWAP@      + 6B I a o    Chess BerlinRegularChess BerlinChess BerlinChessBerlinChess BerlinRegularChess BerlinRegularChess BerlinChess BerlinChessBerlinChess BerlinRegular    !("'  DEIM#8+-*94.5,G:170>=)32@?C/;BOAFKJLNH$&%6<*  +59BHLRTWbhlrtw +17BHJNTWbhjntw 0&..226:Nd   ('  RX\SZVUY]T[W^`dbfh_acegi)+-/1j*,.023k468:ml579;<n>@opq=?ABCDEGIKMOFHJLNr#%$&wLDD/LDDLL++LLLL/DLLL"LDDLLDDLDLD"+,KPXYD_^-, EiD`-,*!-, F%FRX#Y Id F had%F hadRX#eY/ SXi TX!@Yi TX!@eYY:-, F%FRX#Y F jad%F jadRX#Y/-,K &PXQXD@DY!! EPXD!YY-, EiD` E}iD`-,*-,K &SX@Y &SX#!#Y &SX#!#Y &SX#!@#Y &SX%EPX#!#!%E#!#!Y!YD- ,KSXED!!Y-*,,$$CCCC$DDDD" bb" UU??,,$|                                                            ! ! !  ! ! !! ! ! !! ! !!  ! !  !"!!!!!"!!!!!!!!"!!!!!!!!!!!"!!!"!!!!!!!!!!!!!""!!"!!!!"!!!!!"" !"!!!!!!!!""!!!!!!!!!!!!!!!!"!!!! !!!!!%&%%%%%&%%%%$$%%&%%%%%%%%%%%&%%%&%%%%%%%%%%%%%&&%%&%%%%&%%%%%&&%%&%%$%$%%%&&%%%%!!!!%%%%%%%%%%%%&%%%%%%%%%%*+*****+****++**+*********+*+***+***********++++**+****+*****++**+**+*+***++****%""%%%"!************+***+******./...../....///./.........../.../.............//../.././.....//../.././...//....)%%)))%$............/..........23222223222222223222222222223222322222222222223322322223222223322322222222332222-((-,,'(!!22222222222232222222222676666676666666676666666665676667666666666666677667666676666677667666666667766660++0 !00*+##66666666666676665666666:;:::::;::::::::;:::::::::::;:::;:::::::::::::;;::;::::;:::::;;::;::::::::;;::::4..4##44..&&::::::::::::;::::::::::CD""CCCCCDCCCCBBCCDCCCBCCCCCDCDCCCDCCCCCCCCCCCCCDDCCDBCCDDCCCCCDDCCDCCBCBCCCDDCCCC";55<)(<<55,,CCCCDCCCCCCCDCCCDCCCCCC"KL&&KKKKKLKKKKKKKKLKKKKKKKKKKKLKKKLKKKKKKKKKKKKKLLKKLLKKKLKKKKKLLKKLKKKKKKKKLLKKKK&C<9D9J9013#73=!3=!3=!3=!3=!3=#!#!#!#!#!#!53!!!!! )!Mr!qM!) !!E j!!!j E!!!!!!!) !N !qq!!M! ) !!!F !j !!!j! E ! !!+E 2>F'+</+<6+# +#A&6FVfv ]A]к '#9'#9'#9#и/#!и'*и*/-'#9A66]A6)696I6Y6i6y6666666 ]A<&<6<F<V<f<v<<<<<<< ]A<<]#H/ #+ 3+339-3901"%5&$&54632!"45<7>7&54762654&#""32549X?>Y9Xs研76b{xbc~{_NNNͳ' e1.H?XX?I-]O'ގ5w1&Q]JGExYXXYxNNNN $).38=BGMSY^chmps z+z++}+99&9)9+9.9A&6FVfv ]A]5989Az&z6zFzVzfzvzzzzzzz ]Azz]Bz9C9O9U9[9^9_9d9i9zwк999и/ии/9A]A)9IYiy ]///H/N/T/\/^/k/m/q/}+}t+t9 иик&}9'и)к+}9,и.к5}96и8и?иAкB}9f}9nкp}9t9}ܺt901 +# #5'3#!#'3+'3+'3+';753=!3=!3=#; =';#73"%5&$&54632!"45<7>7&54762654&#""3254! CLz! ! E!j A!!A !A! J'! s% E!)E!qMB! vM ; !!!!!9X?>Y9Xs研76b{xbc~{_NNN"CL! Hz !!!E !j! 8!!R{$ !.  ! rA!!F !! )q!!MZ! L6;!!v-!!(ͳ' e1.H?XX?I-]O'ގ5w1&Q]JGExYXXYxNNNN5.6X`+H++2D+2>+>B4+B7H>9OH>9>bT/4B+4Y]+Y: +: %и42к7]Y9BDи:MкO]Y901267>54&'.+#"'#;5267>5#"%$)533).5>353&54632'"32544%Q)> ϗD?*I2 llI353&54632#"'#;57$7<5$''Dv,+vD `GFa+?*I2 ll^CEN&Wʭl5lʈW!DggD!K$6QfQZ}}Z5C _`ql)1BO`cfkpuz?+?-+-V+/+9Vܸ?ܺ 9aкb?9dкeV9iиkкpV9q?9sиuкw9}к9ик9ик9ик9?9ик99ик99V9ик99V9к999ик9ик9к9к99a/n/p/w/y////////+/P+PF+9+ и/ܸ/-иP2и2/9\иdкf/9i/9/9ик/9икF9/9ик/9иик/9кP9P9иFи/9901"325433).5>353&54632$)5%267>5#"#"'#;5267>54&'.+3#7=';= + =3=!3=!3=3+'3+'73+'73+?3+7'# #5'3 ?1+___;Dv,+vD `GFa ϗ@!!!! ! !F !On!qM!) A !'A! A !#A!! GB !x E{!<a! U! ]^^]Wʭl5lʈW!DggD!}ZZv eIv$6QfQ(IG#39Q !!!- !! : !OGuS !qq!!M! ) !B!!' !; !Az`!!e@x! E !A ya! +MRW]bglqv{U/X/e/g/o/q/y/{////// / /P/////////U 9U 9U 9U 9U 9,U 9DU 9OU 9SU 9ZU 9^U 9`U 9dU 9hU 9jU 9nU 9rU 9tU 9xU 9~U 9U 9U 9U 9U 9U 9U 9U 9U 9U 9U 9U 901= ?1+ 7$7<5$''#"'#;5733).5>353&54632'3#5#/3+?3+'73+'73+'3+3=!3=!3= =';=#73 + U! CEN0?*I2 llDv,+vD `GFa<a!w! EsxGB ! #A!!A !A! ^'A !! E!)E!qM]! ! !!!!F !KS ! 5Z||Z5C~ ^`qk$$6QfQ0Wʭl5lʈW!DggD!a!A E !@x! z`!!e; !A' !B!! !! )q!!M: ! N !!!!G,@ &@FJK/L/K:и:/ܸL2ܸܺ:29'//D/ + A +A5+Aи и/  9  и / 9'9E01!7!7!%!5'!6754''76&'27!5.5>7'!'!7']Wjh˄+J=n 뺻kEetxSFh2P(s]stt6^ _KHl5'!77'7^4txSFh1P(r]istt6_^t"CS6o(1_~<!s^ _-ttt  #(-27<AFLRX]bglorw{+++9ܺ9к99ии3и3/399 39!и#к%9(9)9+и-к/9295и7к99<9?иAкF9N9T9Z9d9g9mкn9t9y99/G/M/S/Z/\/e/g/p/t/v/B<+B+|++< и<к99<B9<и<к |9B$и<&и<(иB.и<0и<2иB9и<:и<Dкa|9<mкo<B9}и}/9<B9ик<B9|и/901='3#5#5+'3+53+53+';73=!3=!3= +  ';=#73 +17 !5'%!'!!7!7!7'527!5.5>7'!6754''76&'B}.D!! E`3 !*.nfC!!DB !ArD! :! E!)E!qM^, !|l7 !%!!!!/ !hg]l]Wj yyytxSGh2P(su+J=n 뺻kEeS} !E!CB E !'A!  o!!B !$Ar !a$!!= !! )q!!M-! |G  '$!!!!0Ps?lFL^_ _ ^KGl<zzydt"BS6o'0_~<!r-fa[E":빻9 #(-27<AFLRX]bglorw{/G/M/S/Z/\/e/g/p/t/v/B<+B+< и<к99<B9<и<к 9B$и<&и<(иB.и<0и<2иB9и<:и<Dкa9<mкo<B9ик<B9<B901='3#5#5+'3+53+53+';73=!3=!3= +  ';=#73 +177'567!5.5>5'!7)'!B}.D!! E`3 !*.nfC!!DB !ArD! :! E!)E!qM^, !|l7 !%!!!!/ !yyytySGh2P(s]]S} !E!CB E !'A!  o!!B !$Ar !a$!!= !! )q!!M-! |G  '$!!!!0Pszzydt"CS6o'0_~<!r_ ^^_;)9;!/*+*,+и,/и,5и,801 &'!2673! !>7>7%!5*#.'#*#R6y5J.**/JjfIR`> 0\6^&LKU!54LK3CfZ{{W33WC@:'B`ˌ\2WLMnO(B7n;);/+ܸиии!и'01!"&'#!5>7>7)5:3267:|`/**.``> 0\6^KL45!UKW33W%'B`ˌ\2WLه6B(O !&+/5;AFKPUY^chmrx} + к 9 9 и  к 9 к" 9 #и %и 2и 4и 8и :к= 9 >и @кF 9y 9 |к 9/////)/+/0/6/7>7%!5*#.'#*#!!!!O[R- Z !{ g! B%E !!B!qM!) A ! A! ȷAA)A!!rMB !p Eu! 9 !R6y5J.**/JjfIR`> 0\6^&LKU!54LK!!!s!![SS,-5Z#S,:5h! % ! +Q!Eq!!M! ) !6!!! OQ !GAr!!kBp! E !A ^6z7!3CfZ{{W33WC@:'B`ˌ\2WLMnO(B7n !&+/5;AFKPUY^chmrx}/////)/+/0/6/7>7)5:3267:!!!!O lR- Z !{ g! B  !!B!qM!) A ! A! ȷAA#;A!!rMB !p Eu! 9 !|`/**.``> 0\6^KL45!UK!!!s5!!lS,-5Z#S,:5h5 !! +Q!Eq!!M! ) !6!!! O"! Ar!!kBp! E !A ^6z7!W33W%'B`ˌ\2WLه6B(O$">#8+@/8+8017!5>75#&'#'55#5>7>#73%3%./] Ɵ_Pf0`G$+`-Z3[J'P(X*w|TļdDtQNU'o]SUQ7$3.Y3( 7`IDž1wě0,j>aTGs ///+иܸи  ܸ иܸܸии/ и и 01!5;!3#!35!35!#)5!bXbskc\\hgghu` $).38=BGMSX]bgjmsw+ ии к9ܸиии и /"и#и$и*и,и-и.к496и7и8и@иAиBкb9hкi9jи//H/N/U/W/`/b/k/n/E+E иEкE9EиEк&E9E'иE)к0E9E1иE3иE:иE<к=E9EGиEhкjE9013= '3 3 #'3+'3+53+';7'3+3=!3= + =';=#73%3=33%3!./#!Mr& !! EGB !T#A!!xA !'ڱ !t!C !! E!)`N !!A- !!P!!!!n!qMY%qG˅Z-`+$` 0fP_Ƴ1 ]УN !q !Z E !A! 7B!!e\@ !A}4& !!!! !! )O" ! P!!!!!q!!Mq3Y-3$QUS]n'VNQguDz$"/ / 9 90137!5>75#&'#'55#5>7>1 ] Ɵ_Pf0`G$+`-ZDuQNV'n]SUQ7$3-Y3 '*-27<AFKPU[afkpuzE(/5/7/?/A/I/K/R/T/V/\// + +%&+%и&#ܸи% и+к- 9B&%9X&%9c 9dиfкm 9nиpкs&%9w 9xиzк 9ик 9ик 9к9013!3!!!#5!#5!!3353353!3#7  #;=#;  #; 3+3=!3=3+53+'3+'3+'3+7'# #553,FsFsck"Q!!!!"NC !3">B! +EC !$)!!q!) A !'A!  4A !  #A!!xGB !x E{!+!'''duhgghUiiii!!!F!!N" !d+! D)!!v! ) !D!!n63 !t6 !AAx!!e@x! E !A F!UG#'׸(/)/(и/) ܸܸ ܸ"и"/ &и&////&+&+$+ +ии/ и и иܸиии  и!01!35!35!#7!3#!##5##5!!5kcbXcr@{sX"Ghgghu'Fiiii' #(-27<AGMRW\adg+и ик9ܸи иии/и ии$и&и 'и(к.90и 1и2и:и ;и<к\9bкc9 dи/B/H/O/Q/Z/\/e///?+?и? к?9?и?к ?9?!и?#к*?9?+и?-и?4и?6к7?9?Aи?bкd?901'3 3 #'3+'3+53+';7'3+3=!3= + =';=#7333%3!./3755>75#.''5#67>3=!3=& !! EGB !T#A!!xA !'ڱ !t!C !! E!)`N !!A- !!P!!!!ޅZ-`+$` 0fP_Ƴ1 ]УbdTw*X(D'J[3ͽ!qME!Mr%qG !Z E !A! 7B!!e\@ !A}4& !!!! !! )O" ! P!!!!3Y.3$QUS]o'UNQgtD|ja>j,0w19I`7 (q!!MN !qq 369>CHMRX^dinsx~4//F/H/O/Q/S/Y/_//+!"+!0+09 9 и к9ик90(и'ܸи!и"ܸ!$и/ܸ*и0,и,/(-и-/'2и7к99I09[09e('9l09o"!9u9vиxиyк{9099ик9к"!901=%'3+%3+%'!5!!5;!3#!35!35!#3#7#;=#;= +3=!3=!3= 5''3+!#533+%3+#5'!;! _A !A !<xrbXbskc!!!!cC !3">B! +! e!qM!) ' 4xGB !E E!#A!!iA! !  `!!!!N@x! `\\hgghuD!!!F" !dA+ !gq!!M! ) !D!!63 !@Ax!!eE !F!ӲA T6 !J4:@FL$+$8/J//@6+@GA+G%+%898989089G5иA;и;/>6@9@BиB/D6@96K01##%#!>?#'5!'73>7757&'.!7!7!%!5'%!'!Z-`,$F`.gQ]УcdTR{H`*U(P&KZ4]Wjgg]3Y-3$PRVFtD|ja>j!zSn19I`7(^ _KHl?]]Z-`,$F`.gQ]6_^ ^ _3Y-3$PRVFtD" "',28=BGLQV[`ejpuzs+// /"/*/,/-/3/x///Xd+X+++dкdX999%9X9иd;иd=иXCиdEиdGиXMиdOиdQиdZкbdX9fdX9dkкm9rdX9dsикdX9и/9и/9dX9013= '=3#7=%7';='7;!3=!3=3+'3+'73+'3+'3+%5#%3#5'3##%#!>?#'5!'73>7757&'.!7!7!%!5'%!'!'7;n!qMj*!w{!!!!/h'B !{! r!) @ !!'A! !LA !,ZpA!!0(6B ! _ E@!; !Z-`,$F`.gQ]УcdTR{H`*U(P&KZ4]Wjgg]d Y ! g[q!!M"-B| !q!!!A!!'BCB{ !+! ) !K!!!E! !iDZ !!!S@a! E ! !!@3Y-3$PRVFtD|ja>j!zSn19I`7(^ _KHl?3!7)'!'7;*!w{n!qM!!!!/h'B !{! r!) @ !!'A! !LA !,ZpA!!0(6B ! _ E@!; !Z-`,$F`.gQ]У"]$]d Y ! g["-B| !qq!!M!!!A!!'BCB{ !+! ) !K!!!E! !iDZ !!!S@a! E ! !!@3Y-3$PRVFtD^ __^[!YY!g+E%3//9 99 901&54632!"45<7>7&54769X?>Y9Xs研768.H?XX?I-]O'ގ5w1&Q]JG %+05:?DINSY_dins/2/4/=/?/G/I/L/N/T/Z/g/// //// /&/b/p/r/999 9 99999"9(9,9.95989<9B9F9K9O9Q9V9\9e9m9t9~999013#7';= 7#;!3=!3=!3= 5;7'3+'3+%3+'#!# '3#5 1+&54632!"45<7>7&5476!!!! ! ;MMB! !qM!) S! 'A! A !A!! !j E !z!L! C9X?>Y9Xs研76!!!-6;!!p! Lq!!M! ) !A!!域j ! {$ !.8!!j! E !!!Hz #L! C.H?XX?I-]O'ގ5w1&Q]JGTG #'׸(/)/(и/)ܸ ܸܸи/%и%////"&+"+$+$+иии/ и ܸи и иии 01%!!5#!5#'3533533!73!3!%!5!ckЊDsFseF:"uhgghEiiiiF''GTGk/ //+ܸии ܸ и/ ܸ ܸ и и/и01!5!3!5#!5#!3#!!5】cksb-1\\'uhggh'`` #(-27<BHMRW\afkotwz+|+~+~9и/99%9(9)~9/92|999D9J9M9NиN/T9W9Y9^9a~9|cиc/k9nиn/~и// ////&/(/0/2/:/A!  1! #@` h!!!!kcFsFFFX@FN!B !! mCp!!cz! N! 3)!!E !j! ײkA!!et> !AZM0 !caO'A!!F!!!iiiiEhggh'τ "',17=BGLQV[`ejpuz~/@/B/J/L/T/V/]/_/f/k/s//////%/'///1/2/8/x/+}+9999 9 999}999 9$9(9*9.949:9?9C9F9I9M9P9S9Z9[9`9a}9c9h}9m9r9v9ܸ{иии/ܸܸии/и01!#73537;773+#3+53+!#!# #;  #; #; +=3=3= #3#5!5!3!5#!5#!3#!!5!!!!o@` !  1A! @>@ !#A!!F!j EeC !+e@! R4A !z)!!d o(A% A!L!】cksb-!!KA!![aOM0 !t> !AkA!!ej! E !c)!!! 3z! NcCp!!M! ) !c FN!\\'uhggh'``CT #'Ӻ + + + $+$#%+#и/ии ии и и ии и#)!/ / +  + и/ &и&/0135#35#!%!!3#3#55%!'3#ChgghiiiiF'τkc@{FFsFFFX@"CT ++иܸи  ܸܸ и/и и и и//013#=!!5%!35#35#!#\\'uhggh`bXbskc #(-39>CHMRW\aflqvz~-/+-+++y+~+~E:+E/к/-9Eк:E9/E9 :E9- и/ и/к/E9/E9y9-и/и/к/E99/E9-и/ и/"к#/E9$9'/E9/*к2/E9/3и/4к89E<к?/E9B/-9EGи:HкI/E9L/E9:NиEOиEQкR/E9S/E9V/E9:XиEYиE[к\/E9]/E9`/E9Ebиb/e/E9Egкk~9m/E9Eoкr/E9/tиwиy{ииyии/иииииE// /////%/'/0/2/6/8/p//@/B/J/L/T/V/^/`/c/e/i/k/s/++999 99и/999 9#9$9*9-93999;9>9?и?/E9H9I9O9R9SиS/Y9\9]9f9l9m9r9zиz/и/013#7 ; = ; = ; =;=5;5; +  +  +%+%++ 35# #5 5%!'3#535#35#!%!!3#3#!!!!!!4"Y! "s! $L"O!!$") !! !!!K!! "! ! !ߠt!! !j! EU@k $!τhgghiiii!!!4! "@Y !"$K! "t$!!" )E!!! Kl !$n!! r!!!tj!E0j!#!OFFX@"sFsFkc@{ #(-27<BHMRW\afkpsvz'g^+g+~+~+9^к~9и к~9~9^9к^9"^9$и%и'к(^9)^9,9.и/и1к2^93^96^g98и9и;к<^9^=кA9^CкG9gIи^Jи^LкM^9N9Q^9gSи^Tи^VкW^9ܺX9[^9^`иgaкb^9e~9^iкl^9o9qкr9^tкu^g9wи~xܸ{ии/ܸии/ии/?/A/E/G/O/Q/Y/[/c/e/m/o/t// ////// /"/*/,/4/6/q/99999999%9(9)9/9293999<9B9H9J9M9N9T9W9X9^9a9b9h9k9l9s9v901 #5 35#+'++7+  +  +  5;5;=7;= ; = ; = ; #733#=!!5%!35#35#!#$!@k ! E !j?t!!! ! !! "!!!K!!! ) !""O!!$"s! $L"Y! "}!!!!!!\\'uhggh`#!j!%!Ejt!!!: !! $ !K!! A! )!!"O$K! "t$' !"Ys! "~!!0bXbskcCT #'˺&"+&$+++ +ии/и и и ииии !/ / + +и/ &и&/01#3#3!!!5#535#53%%55!#3hgghuFiiii''τkc@FFsFFFX@CT}+ + ܸик 9/ܸи и/ и и и/ //01#3!!5!#3#3!53Y\\hgghujbbskc #(-27=BGLQV\aflqvz)Vq+Vy}+y+/$+/}y9q/99q/9 q/9 $/99и/к$/9qкqV9q/9qV9q/9}|ܺ"}|9/&к)9,q/9/1и$2и$3и/4и/6к7q/9/8к<9V>иq?иqAкBq/9VCиqDиqFкGq/9Hq/9K9VMиqNиqPкQq/9qSиqWк[}y9]}y9q_и$bи/cи/eкfq/9/gкk9rq/9uq/9|wи|ии/9/ܸии/ии/////// /"/*/,/:/6+>6_ܺ_9#_9&_9IBܺCI9M(9T_9_UкV6_9XкYI9_]кa_9dI96eиe/7fиf/_gи_iкk_9p_9_qи_sкv_9_wи_yк|6>9_}и_к_96_9ик_9_9Iи/Jи/ик_9_9_9ик_9_9икI9I9_9I9икI96_9_к_9к(9_и_и>R/T/U/b/d/k/m/o/u/{//+<8+<F@+FM+M,+кM9Mи/M и /F4и4/@:к=9C9<Dи8GиG/I8<9XкZ9g@F9wM9иииииииик@F99ик8<9к8<9кM9017''7'.'5675!''%76/76=.!!75!!7)'!5!' 1+!#73'+' ; #!#!##7;=#7;=#7;=#7; '7;=3= ?3#57xyyys(PhGSܫxtheEk nJ,KL]Ku!! !!!!>7 !|U ! !!j EA !FD! B !:C!!n23 !% !7.!;Byyzr!<~`0'o5SC"t997%E\bf-Gl< _^^ _s?lFvP!!!'!!Z ?| ! !!j! E ! $F!!A !|B !z!!oVA! ) !B x! ! #(-27<AFLRX]bglorw{/G/M/S/Z/\/e/g/p/u/w/%+|+ ик|9|9%9к#|9'и%.и0и2и%8и:и<и%BиDиFк`|9mкo%9%9|ик%9017#5?3%3=='7;  #7;=#7;=#7;=#7;#!#!# ; '+'3#7+ !'!!7'7'.'5675!''%7';B7.!!% 3 !n,C!!^B !D! FA !! E!j! ! |7 !:!!!!!! Pu]l's(PhGSܫxtyyy !!B !A! _!!o)|B !zA !$F!!E !j! !!- ?| !~ '!!F!!!!vP^ _ _^r!<~`0'o5SC"tyyz9: &@FJ%*+%6+6 A+  +Aи и/  и / 9%к*9EиLC//:+2+2 C9C9C901!!'3'37#367&'#"'&%77&67'>33##.'7!7' _^KGl33##.#%!!'7'^ ^s#DS5n'0`;!s, ^^ttuD]3txSGh1P's^httt!.28>DJNRWZ]bglqw}q+$+$93+9GC+G+к 969G7иC:и:/<CG99?и?/3EкL9[к\9a9h9k399v9|9иик9иик999иик99399ик9CG99кCG99к999B+B`<+`(+ + <6ܸBHܺL 9`XкZ<`9[к]B9dB9<hиh/`iи`kи`tи`vи`zи`|и`и`к<`9<`9ииBи/ииииикB9B9B9икB9<`9`ик 9`и`01367&'#"'&%77&67'>33##.''7'%7!'37#3''!!' 7=73#7 ; = ; = 5;5;5;7 + 7 + 7 +%7 +%7+%+ 3 #5;-fb\E#9빻9{t"CS5o'0`~<!rttt^ _s?lFGl< _^>vPȧ!gg!!!!!!$ z!  M!!q) !!  d!!K! rns! !!oVʺm !h! E 8!Eh! }+J=n 뺻kEetxSGh2P(shuss4]KgjL]u! !g!!!%!  7z ! !MqF )E!! c) !rJ! s!!n2! l$!E!8!D} #(-27<AFLRX]bglorw{//и/ܸ и /ܸ ии(ܸи/к9и/и/к(9#9%и(.и/и1к29(8и9и;к<9(BиCиEкF9aиa/jи(kиk/mкn(9(9к(9///// /"/*/,/4/6/>/@/m/// /I/K/O/Q/U/W/_/a/i/k/p/9 9 99999#9%9(9)9/9293999<9C9F9L9R9X9Z9^9d9g9o9r9t9}99901 ;#5 3++?+ 7+ 7 + 7 + 75;5;5; = ; = ; #73=7377!!'7!7''77&67'>33##.'! }!E ! E !ʺ!!o)s! ! rnd!!K! ) !M!!q- z!  !!$!!!!g!vP _^^ _tttit"CS5o'0`~<!r;}!D!&!ED! -n,!!j! rq !cK! ! )!Mq ! z!  %!! !g!u]]usstxSGh2P(s9: 'AGK+B +B 3+ +++Bи и/9и/к+9+9=+9+?иCE//#/+#8+8 E9E9E9E9=E901!7#37'#7'6&'7&+3>%'#&'#367377!'!7'/^_wCHMRW\aflqv{//_и_/ и_Wܺ _W9ܸܸиWи/и/W5и_6и_8к9_9W?и_@и_BкC_9WIи_Jи_LкM_9_Tк\9a_W9bиb/cиc/_gиWiиi/jкk9mиm/_oк_W9ик_W9 /;/=/F/H/O/Q/Y/[/c/e/i/k/s/ /////%/'/+/-/1/3/n/x/z/ 9 9 9 9 9 9 9 9( 9. 94 96 99 9@ 9C 9D 9J 9M 9N 9T 9W 9\ 9^ 9a 9b 9l 9m 9v 9w 9 9 9 901'  #73 +  +  +++%=7 ; =73+=7 ;=7 ;=?;5; #57 3+ 7'!'#&'#367377!7%!'!!PU0!!!!?!! ! |.- !! !j! E'!!F-Ar !a! 1@!!ʺm !! " 7!h ! |/, !! j!E! 'F !-rD! !!@2! l$!G!7!*;zyys(PhGSܫyt^m$"/"/"9"9017#5&'.'5355736735'.'5!1Z-`+$` 0fP_Ƴ1 ]I3Y/3$7QST]o'UOQuC #(-27<AGMRW\adgmrw{~Ǻ+a+aкAa9C9aDиaFиaJиaLиSиaUиaWи^иa_иaeкfa9ajиalкsa9tиt/auиawиa/B/H/P/R/Z/\/e/h/p/r/ + и к 9 9 и к 9 !и #к* 9 +и -к4 9 5и 7к> 9 ?и Aк_ 9 bкd 9ܸ01#5573%3==#7;=#7;=#7;  #7;=#7;#!# +5+53#7#7+7%'7535&'.'5355736735'.'5!7>%#%?!!% ]B !$7A!!iA !sA! !D@ !! E!j! *? !!!!!! jg !*=hZ-`+$` 0fP_Ƴ1 ]LdTw*X(D'MX3<8B`!!A !@! pX7!!A !! s/!!!E !j! A@ !D>A!!F!!!!!!p)gMP ! 4Y.3$7QTT]n'VOQuC ja=k-0w0Ic4 '  "',17=BGLQV[`ejouze,+, и /, и, и,и,и,к,9, и)и,*и,4и,6и,:и,<кB,9vи,yи,/@/B/J/L/T/V/^/`/h/j/p/x/////%/'///1/2/8/}/99999 999999 9$9(9*9-949:9?9E9I9P9S9W9Y9]9c9g9k9m9r9v999901'777+!#!#735+5+!#!##7;=#7;  #7;=#7;=#7;=3= 573#57#5&'.'5355736735'.'5!g8B*=7jg !E!M!!!!*? !! !j E@ !! A! {sA !EA!!$7B !% !?!1Z-`+$` 0fP_Ƴ1 ] KP !)g!!!!A!! >@ !Aj! E !G/!!!! sA !X7!!@! ) !A !!(3Y/3$7QST]o'UOQuCB("?/+*иA /*+*01367>733337>73!./%3#!##5.''#53Y/3$7QRU]o'VOQuCka=k-1w0Ic4!&"[-_,$G`0fP_Ƴ]УbdT| w*W)P'NW4B(") // 9 9" 9015367>733337>73!./S3Y/3$7QRU]o'VOQuCϢ[-_,$G`0fP_Ƴ] #(-27<AGMRW\adgmswzɺ+и иик9 и"к#9*и,к-94и6к79>9?иAиbкc9/D/F/J/L/T/V/^/`/e/j/l/p/r/ + и %ии и%.ܸи и%и и.и и%и к$ 9 'и.(и /и%0и 1и 9и%:и ;кY 9 bи%cкd 901 #5 3 ++?+ 7 + 7 + 7 + 7=5;5; = ; = ; #735;5; 7%3!##5&'5'##5#-!+ $! E !)!!(u! (˿R! 0迿!!! ) !W6W ! ?k!!=!!!!M!!qq! NSCuhQOV'o]URQ$3/Y3 !*!j!E)! A)!!)˿! v0 !B !!! ) !5W >! m>!!!Mq rMH ]1ƞ_Pf0 `$,_-[B(") // 9 9 901#!33567573353DtQNV'o]TSQ7$3.Y3Ϣ ]1ƞ_Pf0 `$,_-[ "',16;AFKPUZ_bejotx} />/@/H/J/R/T/\/^/c/l/n/z/|/5+5и5и5и5и5и5и5и5и5!и(и5)и5+и2и53кW595`кb5901'7 #57 3 +5+5+ +  +  +  5;=?;=7 ; =7 ; #73=?; =7'?;#!33567573353E!F E! E !j!!! W(! 9!!8! ` !_X! L"!!!!!!!!/ ! DtQNV'o]TSQ7$3.Y3/!!/ʬ! ˬ3Ţ ]1ƞ_Pf0 `$,_-[+E 2>F+6+6&<+&+A&6FVfv ]A]и к 99и/и!и!/$9)9A6&666F6V6f6v6666666 ]A66]A<<]A<)<9<I<Y<i<y<<<<<<< ]H./+3+39$39012$75%&'&547.'&45<3!#"&54"32654&254#"GAM4Z67T埔sX9Y>?Xc{~cbx{fNNN Ѯe'HI^P%ݔ1x6'P].H?XX?GzWYYWzdNNNN+E%3/!/!9!9!9!901&'&547.'&45<3!#"&54Z67T埔sX9Y>?XHI^P%ݔ1x6'P].H?XX?G$,8EHKPUZ_ekqv{B+B0 +0!6+!<+и/9 99и/к9A0&060F0V0f0v0000000 ]A00]A66]A6)696I6Y6i6y6666666 ]A<<]A<)<9<I<Y<i<y<<<<<<< ]<?кV9[9_9a9g9s 09x999 099999999F/N/P/]/_/`/f/l////I/y/{//////////B+9-+9FI9 FI9-99-99HFI9KFI9QFI9SFI9VFI9XFI9[FI9bFI9hFI9nFI9s-99tFI9xFI9~FI9FI9FI9FI9FI9FI9FI9FI9FI9FI9FI9B9FI9FI9FI901#"&547.547.'&5'7!254#""32654&'2$7<5<#73+75+!#!#!# =#;=#;=#; +=3=!3= 3 5373+^9Y>?X9YrT蟔77NNNJczwcb|`MAG!!!! ! !,JL! i!!j E)$iB !C@! >A !G!!m PI!) O!!A@ !/G?XX?H.]P'ݏ6x1%P^IHNNNNzWYYWzYͳ'e!!* Z!!&B !+!!j! E !#!!%~# !E6? !kk @O!!M! ) !O!A JH@ !; $).38=BGMSY^chmps ///&/(/,/./6/8/@/B/n////H/N/T/\/^/k/m/q/ 9 9 9  9 9 9 9  9" 9) 9+ 9/ 91 95 9; 9? 9D 9E 9J 9P 9V 9Z 9_ 9a 9d 9f 9p 9s 9t 9z 9 9 901%3+753 3 3=!3== +!#;=#;=#;=#!#!# +57+3#7&'&547.'&45<3!#"&54@ !kAQ!O!n E!)yP!!meA ! >C@! =iB !)$ E!j!! !0 ! !!!!!Z67T埔sX9Y>?X*H@ !A O!i !! )b@O!!kE6? !~# !#!!E !j! !!$+B !Z!!O !!!HI^P%ݔ1x6'P].H?XX?GD+ 2>FոG/H/G3и3/A&6FVfv ]A]H#ܸ ܺ39-39/"/'+# +#</+<6+и#!и'*и*/013:3:##"&54632>32>7637"#*'.'#"'&%4&#"326%3254#"̴'e/G?XX?H.]P'ݏ5x1%P^IHyXXXXyeNNNN9X?>Y9Xs研76b{xbc~{_NNND+%?/////9 99 901#"&54632>32>7637"#*'.'#"'&Q/G?XX?H.]P'ݏ5x1%P^IH9X?>Y9Xs研76  EHKPUZ_ekqv{_ +0+0w+A ]A ) 9 I Y i y ]' 97 9IкJw9Tw9Y 9r 9yииwк 9wиик 9wиик 909 9к 9к09 9к 9F/R/T/W/Y/b/d/h/j/n/p////I/s/u/}///////////1+* +*9+%+% и к!IF9'IF9*-и-/14и4/7IF9<IF9HIF9KIF9LIF9MIF9Q%9V%9\IF9eIF9kIF9qIF9r99xIF9{IF9IF9IF919IF9IF9IF9IF9IF9IF9IF9IF9IF9IF9013"#*#4&#"326%3254#"767632>72632'"'.'#"&'#"&546323#7 = ;!; =%5;5;5; +  +  + +%++ #5 35# ;71'Ѯe'ZyXXXXyeNNNNHI^P%ݔ1x5'P].H?XX?G!!!!S!! ! H:<M!!q) !! N!!'! x8''! ''nH!! !j! E3!fA ! ,!!b|bcwzgNNNY77堔rY9X?>Yi!!!6!  H8 !:!MqF )E!N&! y9% !j&&! '!!oH j!E3!e!L+ ! $).38=BGMSY^chmps3%+ иии'и%*и+и-и%4и5и7и%>и?иAкg%9nкo%9/////!/#/0/2/:/72632'"'.'#"&'#"&54632!C! ,JA 3!>! E !jkH!!'''! '! x8'u!!"! ) !M!!qY<g! H!! K!!!!QHI^P%ݔ1x5'P].H?XX?G+ C !+!3!B!E jH'!!f&! &% !y]&! t! )!Mq !:hH& K! !!Y77堔rY9X?>YD+ 2>FٸG/H/3ܸA]A)9IYiy ]Gи/ܺ39$39/!/++6+6&<+&и ии/014'#23:32%#"'"#*572632632#"%32654&#"4#"32~Ѯe '1GJ]O&ݓ1w5'O]-I>YY>HxYWWYxNNNNGAM4Z67T埔sX9Y>?Xc{~cbx{fNNND+%?// / // 9 9 9 901#"'"#*572632632#"GJ]O&ݓ1w5'O]-I>YY>HZ67T埔sX9Y>?X $).38=BGMSY^chmpsg>5+>++A&6FVfv ]A]59 595 и5к95к59 9#9>%и5&и5(к)59>*и5+и5-к.59/5957и>8и5@кC9b59g5>95nкo5>9z99// /J/L/P/R/V/X/`/b/e/g/q//////!/#/0/2/:/! ) !!!H''q! b'T! '!!&! E !j!!Y ! #!!S!!!!GJ]O&ݓ1w5'O]-I?XX?HNNNNexYWWYxZѮe '! CLH!{!>! )H!!&! &r< !&U! & '!E j!W ! &"S! W!!!Z67T埔sX9Y>?XNNNRc{~cbx{dGAM c.6X`+H++2D+2$+>+>B4+B7H>9OH>9>bT/4B+4Y]+Y: +:]ܸ %и42к7]Y9BDи:MкO]Y901267>54&'.+#"'#;5267>5#"%$)533).5>353&54632'"3254'U*A!؝GB,M4 qq7>g%$*f}p%55CG{-zy,{HdJIebbc$*LJ$6:T"&:UUU~L{Œ]]ʼn[ԳqBqԍ["FllF%baab &@FJK/L/K:и:/ܸL2ܸܺ:29/D/'/ + A +A5+Aи и/  9  и / 9'9E01!%!7!%!5'!6754''76&'27!5.5>7'!%!7'Ldƥxv-M`s oHiy~VJm S*wLyyyxbbNKp>{xApI.kd_H%;;y#EW8s)2cƒ> "wbbpyyy #)'/'/ /+$и(017'!%67!5.5>5'!%!}yyy "wbb c!.?7/ / / 9 97 9= 90133).5>353&54632#"'#;57$7<5$' 'G{-zy,{HdJIe,B,M4 qqAQSQ/r[ԳqBqԍ["FllF%K&:UUU]]7F bduq# 2>F*+</+<6+" +"A&6FVfv ]A]и/ *"9*"9*"9"и/*'к-*"9A66]A6)696I6Y6i6y6666666 ]A<&<6<F<V<f<v<<<<<<< ]A<<]"H/ #+ 3+339-3901"%5&$&54632!"654&7>7&54762654&#""3254E<\AA\;\x~:8f|fgbQQRRֺ*iI/L@]]@L/`S)8}2'UaLK1}]\\]}RQQR%3//9 99 901&54632!"654&7>7&5476<\AA\;\x~:8/L@]]@L/`S)8}2'UaLK)9;!/*+*,+и,/и,5и,801 &'!2673! !>7>7%!5*#.'*#^U88X0-+0WohOUic@!3a8bj7>7)5:3267:O0+-0Nc@!3a8bjiNO67#XN [66['HEdՑI[O9E*R">#8+@/7+7017!5>75#&'#'55#5>7>#7%3%./` ϥdTk1cT&-d0^6^M(^)[-|!WixGyuTQY)t`XWTD%50]5)!:cL3{͡2.!n@f"/0137!5>75#&'#'55#5>7># ` ϥdTk1cT&-d0^GyuTQY)t`XWTD%50]5 #'׸(/)/(и/) ܸ ܸ ܸи/ &и&////&"+&+$++ии/ и и ܸи ииии 01!35!37!!!#!5##5 3!3!!7!5Unf"BIxIx~I'CMmllmdT nnnn   ؊S ///+иܸи иܸܸии/01!513!3#!35!3'!#)5!g f'fxnl""``"mllmdd;)9?/*+8+8 и8,и8/и8501!.'!67!.' .'!:3>7:35RIfj/**.5x7R|^6\0 >`|KL45!UKL\~DW33W|{YfD2٦MW3\͋ʹ`C':Nn6A'On;)?/)+)ܸии#и&и)'01.' .'5!2>3%*#.'*#5)|^6\0 >`.**/LKU!54LK|| %٦MW3\͋ʹ`C'%X33XbO'A6 #9>BGMRW\afjoty~-7:35%!.' .'!.'!67#5753%3==#7;=#7;=#73=#7;  #7;#!# +'7? ; '7%' ;?;?''3#7KLT"45KL|`=!0\7]|R6y5/**.jeJR !^ 9P!% ^@ !A!!BAA! ,(A !! E!jXi!!!!  %f !d~Ws! XE! [!!!!nO'A6nN١C`͋3\WM':=fY{|W33WD~D26!]4yuAQ !@! b$A!!Q !2S !H!!'E !j! 'i%!!R 5 ! 5% !fe}T,DsWF-!5[!!F!!! !&+/49?EJOTY]bglqv|/////(/*/7/9/:/@//H+HкH9H9HJкQH9HRиHTк[H9H\кdH9HeиHgкnH9HoиHqкrH9HwкyH9}H9Hииииܸ01!#73'7' ;? ; ''7 ;?'7+!#!##7;=#7;=#73=#7;=#7;=3= 537#5.' .'5!2>3%*#.'*#5)!!!! [E!s! Xf !d % ! <!i!!F!j EA ! A! BApA!!@ !% P!^9 !|^6\0 >`.**/LKU!54LK||!!5[!!F-!sWuT,fe5% !5 !;R %!!'ij! E !9H6!!2S !Q !$A!!@! ) !nAQ y6!%٦MW3\͋ʹ`C'%X33XbO'A6  "',05:?DJPUY]bglquz~ɺ+9,ܸк9,и,к,9,и,к,9,9, и,"иܺ'9,*к1,9,3и,5к;,9,=и,?кz,9,к,9ииииܸи ////$/&///7/9/B/D///E/K/S/U/`/b/o/q/x/z// 9 9 9 9 9 9 9 9 9 9' 9( 9* 9. 91 93 9: 9; 9= 9A 9G 9M 9R 9W 9X 9[ 9_ 9f 9g 9k 9l 9n 9s 9u 9w 9| 9~ 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 901#37 3 #573+57 ; 577#57;757+3=!3='7;5?'7;  ';?';?  #73#3!>7.'-.'! >74&'>5% Af!y5!5 E?A !!!vnQA !6 !! E!)6!!+=GOh5 !]>5! Q5I !ERk!!!!oO'A6oM٢B`͊2\XL':=d[{{X33XBD3g!7 5E !dA! B!!*w6A !B !1!A!!S  !! ) =B#g !  1]6_Q6y4K-**.KifIQ);)+иܸии!и'и+ // 9 9 9 9 9 9 901#>7.'-.';#<5.'>7<X22X%٢B`͊2\XL'6A'O|`/**.``> 0\6^KL45!UK);)9:/;/:и/и;ܸ*ܸ8ܸ,и8/и85/'/'9'9'9'9'9'9'9'9'9'9'9 '9!'9"'9#'9$'901 >74&'>5% !>7.'-.'!#3ffY{{X33XBD3٢B`͊2\XL':MoO'A6oR7x5J.**/JjfIR`> 0\6^&LKU!54LK),/48=AFKPUY]bhnsx}W+ܸиии ииxܸ-к.x9=x9xvк~x9xиxкx9xиxк9x9xиxкx9x9xиxкx9xиxкx9x-/q/s/z/|////////*/;/=/D/F/S/U/`/b/c/i//-*9-*9 -*9!-*9"-*9#-*9$-*9%-*9(-*9,-*9/-*91-*92-*96-*98-*9:-*9?-*9A-*9C-*9J-*9K-*9O-*9P-*9R-*9Y-*9[-*9\-*9_-*9e-*9k-*9p-*9t-*9v-*9}-*9~-*9-*9-*9-*9-*9-*9-*9-*9-*9-*9-*9-*9-*9-*9-*9-*9013#<5.'>7<'#>7.'-.'3#7=';';  '7;5'7;!3=!3= +57;757 3 573+573+57# 377#3v6A'ObX22X%٢B`͊2\XL'!!!!`5k+RG5I !+Q5! m>5 !OL+=6!!!)  6 !7 !nA1|A!!A ! E%!5y53Af!KL45"UKL`/**.a`> 0]6^z!!! k!! ID ! ! < #q=B ! ) ! A!! B !1|A !B!!dA! E !A 57 3g!);)9:/;/ܸи:и/*ܸ,ܸ/и,5и,8/'/'9'9'9'9'9'9'9'9'9'9'9'9'9 '9!'9$'901-67&'-!% %!3<5467.'<5#3D~CX33X{{Ze@:'LW\2̴`BMo6B(OoRIfj/**.5x7R|^6\0 >`|KL45!UKL);)&'+&ܸи&и&и&#и')//9999 9 9 9013% %#467.5#%'LW\2̴`B%W33WbO(B6|^6\0 >`.**/LKU!54LK|| !&+/4:@EJOTX]bglqw|q++qкq9q9Fq9qHиqJкPq9qRиqTкYq9q[иq]к_9cq9qeиqgкiq9qoкsq9qtиqvкq9qииܸиии/C/E/M/O/W/`/b/j/l/r/z/+к9ик9к9(и*к+91и3и5и;к=9H99к901!#73''? ; '? ; '';?'? + #!# ';=7;=3=#;=#;=3= '37'3#5-67&'-!% %!3<5>7.5<5#!!!!5[+R! I+Q4 !5.>2! ROL!!!j E6 !O! Q1AAv!!6Ad ![% 55!y5A!3Dc\{{X33XC~@:'B`̋\2WLMoO(B6o!!| !!\Isu  !< !uQ#'qj! E !  A!!/B !u1SA !wxB!!dA! ) ! 5 <7 !իR3|5/**.jeJR{`=!0]6]|KLT#45KL "',05:?DJPUY^chmqvz5?+?9?к?9?и?к?9?и?к?9?9? и?"к(?9?*и?,к1?9?3и?5и?=кs?9?к?9ܸиии ////%/'///8/:/B/D///E/K/R/T/\/^/k/m/s/u// 9 9 9  9 9 9 9 9 9  9$ 9( 9* 9. 91 93 97 9; 9= 9A 9G 9M 9U 9Y 9[ 9` 9a 9e 9f 9j 9o 9q 9v 9x 9z 9| 9} 9 9 9 9 9 9 9 9 9 9 9 9013#5?'3%3==%#;=#;=3=7;=';#!# + '?+''+'? ; '?'3#7467.53% %+3FA!5k55!% ?Ad ![Av!!6Q1AO! 6 !! E!j)!!O~5 !.>5E5! +QH! I+R5!!!!W33W%'B`̋\2WLه6B(Og! l 5 !A! dxB!!wSA !P1/B ! A!! E !j! M# b< !I  ! I !!F!!!Y.**/`=!0]6]|{KK54#TL $(,05:@EJOTY^cioty~A+A'++'$%+$ .+ + +op+oo9  и ииии/и.и.!и$)и$/к1o9o3к6o98и;к?+'9CкFo9Io9AKиLиNкOo9Po9So9AUиVиXкYo9Zo9]po9A_и`иbкco9odкh 9okиorкu 9xo9pzиo{иo}к~o9. 9o9pиoиoкo9o9%$9pиoиoкo9o9A9кA9oкpo9o9o9o7/f/h/l/n/v/x//////////2/=/?/G/I/Q/S/[/]//// +  +79'и'/ 0и0/179679@79B79E 9FиF/L79O79P 9V 9Y79 ZиZ/`79c79i79o79q79t 9u79{79~7979 979 и/7979 9797979017;1'%!!5#535#537#3#3!%5'#3!5 3 #5 5; =%; = ; = ; = ++%+ +  ;  + 3#7 ;4 ! xiiiiEhgghu'GG'!Dgu k! !!\! j!Z! l!UD!!p!! E !j"O$!!ܑ"$! "O !t"!!!!!!!!t A-kcFsF"bXFF!Dhu!jP!!! :j! !6m ! 3Cp! !!E j"!!O$"! $" ! "! !!!St,@ 'AGKL/M/L/и//M8ܺ/89/89ܸ/#ܺ=/89/E/(/+ B+ ++3 +3Bи и/ 99и/к(9(9=+9+?иC01!'!5!'%!75!76/76=.!'7'.'5675!''!77']LNNheEk nJ+is(PhFSܫxtstt^ ^x/@/m/U+~+++Uк U9U кCU9UIиUKкLU9UOиUQиUWи^и^/U_иUaиbиb/UiиUkиUpкrU9{9U901 +3 #575;%;=7%; =7%; =73+=7 ; =7+++  +  + 3#7 1'!7#37'#7'6&'7&+3>%'#&'#367377!'!7'S%!!!^/ !!^LNNheEk nJ,is'PhGSܫytttt$"?+*+A/+*01%5&'.'5355736735'.'5!537>%#%ޅZ-`+$` 0fP_Ƴ1 ]УbdTw*X(D'MX34Y.3$7QTT]n'VOQuCja=k-0w0Ic4 ' #(-27<AGMRW\adg+?ܸи? к9?и?к?9? и?"к#?9?*и?,к-?9?4и?6к7?9?Aк`9?bкc?9и/D/F/J/L/T/V/^/`/e/////.%+.+%и% и%к9.и%и%к9.и%и%и%'и.(и%0и%9и%;кY%.9%bкd%.901 #5 3 ++?+ 7 + 7 + 7 + 7=5;5; = ; = ; #73367>733337>73!./#!##5.''#573%5;'7;%7-!+ $! E !)!!(u! (˿R! 0迿!!! ) !W6W ! ?k!!=!!!!3Y/3$7QRU]o'VOQuC!ka=k-1w0Ic4!&cM!!q!! $} !*!j!E)! A)!!)˿! v0 !B !!! ) !5W >! m>!!C[-_,$G`0fP_Ƴ]LdT| w*W)P'NW4[!MqN !#,HB(">7+7/8+801!33567573353'5&'&'##'.'#!>?DtQNV'o]TSQ7$3.Y3' 5bIƄ0xŚ1,j>a"]1ƞ_Pf0 `$,_-[4WN'D)W*w TĽd">CGLQVY\afkpuz7y+7 ܸyIиyKкLy79ySиyUкVy79yWкXy79ycиyeкfy79ymиyoкpy79qy79ywиy{кy79y@/B/N/P/W/^/`/h/j/r/t/}///+8 +8Zк\9c9иииииииииик 89и015!33567573353&'&'##'.'#!>?7;'7=7; =73#7 ; =7 ; =7;=7'5;  +  +  + +++ 3 #57'7DtQNV'o]TSQ7$3.Y3>' 5bIƄ0xŚ1,j>a ! !!/!!!!!!X! L` !_!  8$!!]! =WZ! !! !j! EF {!č]1ƞ_Pf0 `$,_-[M4WN'D)W*w TĽd53! /!!!!!! XL !`_! X!b! 8": !! W[7j!EvE!z!< $).38=BGMSY^chmps'>5+>5 и5и5и>%и5&и5(и>*и5+и5-и57и>8и5@кg5>95nкo5>9/////!/#/0/2/:/! ) !!!H''q! b'T! '!!&! E !j!!Y ! #!!S!!!!GJ]O&ݓ1w5'O]-I?XX?H! CLH!{!>! )H!!&! &r< !&U! & '!E j!W ! &"S! W!!!Z67T埔sX9Y>?X+01!!m&7Gauo  ( S#U5Nh G!!#%c%'(0(+--.814559<}>5??pBEHF7FIJIKNNNPQ#RST5WJY'YZP]G_z`L`cccde]ef6g`gh6hiiJijQjk8m.nr9rsvw`wz<}X;OOOOwS3NO./EQ%1TZ4:KW-M5U+7fR2bcde.nulluni0020uni00AFuni00B5periodcentereduni00AD   !!""##$$%%&&''(())**++,,--..//00112233445566778899::;;<<==>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~tagua-1.0-alpha2/data/themes/pieces/BerlinTTF/theme_jose.desktop000066400000000000000000000002701077523320400245760ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Berlin (Jose style) Type=Application Comment=Berlin TTF theme,|as Jose's default.| by Eric Bentzen X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/BerlinTTF/theme_jose.lua000066400000000000000000000015021077523320400237050ustar00rootroot00000000000000-- this theme copies perfectly the default theme of jose, -- except for the shadow that is better :) import("piece_theme.lua") shadow = 7 shadow_color = "#404040" shadow_offset_x = 3 shadow_offset_y = 3 shadow_grow = 6 function fromGlyph(glyph) return fromFontGlyph("Berlin.ttf", glyph, "black", "white", 6.0) end theme.black_bishop = fromGlyph("0x006E") theme.black_king = fromGlyph("0x006C") theme.black_knight = fromGlyph("0x006A") theme.black_pawn = fromGlyph("0x006F") theme.black_queen = fromGlyph("0x0077") theme.black_rook = fromGlyph("0x0074") theme.white_bishop = fromGlyph("0x0062") theme.white_king = fromGlyph("0x006B") theme.white_knight = fromGlyph("0x0068") theme.white_pawn = fromGlyph("0x0070") theme.white_queen = fromGlyph("0x0071") theme.white_rook = fromGlyph("0x0072") tagua-1.0-alpha2/data/themes/pieces/EnquilTTF/000077500000000000000000000000001077523320400211045ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/EnquilTTF/Enquil.sfd000066400000000000000000000413331077523320400230430ustar00rootroot00000000000000SplineFontDB: 1.0 FontName: Enquil FullName: Enquil FamilyName: Enquil Weight: Medium Copyright: Created by Io with FontForge 1.0 (http://fontforge.sf.net) Version: 001.000 ItalicAngle: 0 UnderlinePosition: -100 UnderlineWidth: 50 Ascent: 819 Descent: 205 Order2: 1 XUID: [1021 645 1811818106 134493] FSType: 0 OS2Version: 0 OS2_WeightWidthSlopeOnly: 0 OS2_UseTypoMetrics: 0 CreationTime: 1156081627 ModificationTime: 1160235956 PfmFamily: 17 TTFWeight: 500 TTFWidth: 5 LineGap: 92 VLineGap: 0 Panose: 2 0 6 9 0 0 0 0 0 0 OS2TypoAscent: 0 OS2TypoAOffset: 1 OS2TypoDescent: 0 OS2TypoDOffset: 1 OS2TypoLinegap: 0 OS2WinAscent: 0 OS2WinAOffset: 1 OS2WinDescent: 0 OS2WinDOffset: 1 HheadAscent: 0 HheadAOffset: 1 HheadDescent: 0 HheadDOffset: 1 OS2SubXSize: 665 OS2SubYSize: 716 OS2SubXOff: 0 OS2SubYOff: 491 OS2SupXSize: 665 OS2SupYSize: 716 OS2SupXOff: 0 OS2SupYOff: 0 OS2StrikeYSize: 51 OS2StrikeYPos: 265 OS2Vendor: 'PfEd' TtfTable: cvt 4 !$VK# EndTtf TtfTable: maxp 32 !!*'"!"&^^!!<3$!!!!#!!!!"!!*'"!'gN:z EndTtf LangName: 1033 Encoding: UnicodeBmp UnicodeInterp: none NameList: Adobe Glyph List DisplaySize: -36 AntiAlias: 1 FitToEm: 1 WinInfo: 63 21 11 BeginChars: 65539 10 StartChar: .notdef Encoding: 65536 -1 0 Width: 1024 Flags: W TtfInstrs: 46 YlOhX4L,1p!:;PH"pNdEZ3(..m4n[H!rsu:Z3:@2m4tsP"p+WaZ2k",m4nYA EndTtf Fore 34 0 m 1,0,-1 34 682 l 1,1,-1 375 682 l 1,2,-1 375 0 l 1,3,-1 34 0 l 1,0,-1 68 34 m 1,4,-1 341 34 l 1,5,-1 341 648 l 1,6,-1 68 648 l 1,7,-1 68 34 l 1,4,-1 EndSplineSet EndChar StartChar: .null Encoding: 65537 0 1 Width: 0 Flags: W EndChar StartChar: nonmarkingreturn Encoding: 65538 12 2 Width: 1024 Flags: W EndChar StartChar: plus Encoding: 43 43 3 Width: 1024 Flags: W Fore 0 820 m 1,0,-1 1024 820 l 1,1,-1 1024 -209 l 1,2,-1 0 -209 l 1,3,-1 0 820 l 1,0,-1 EndSplineSet EndChar StartChar: b Encoding: 98 98 4 Width: 1024 Flags: W Fore 413 729 m 0,0,1 465 770 465 770 506.5 769.5 c 128,-1,2 548 769 548 769 600 728 c 0,3,4 666 675 666 675 696 619.5 c 128,-1,5 726 564 726 564 739 471 c 0,6,7 748 411 748 411 742 311.5 c 128,-1,8 736 212 736 212 721 157 c 0,9,10 717 141 717 141 722 137 c 128,-1,11 727 133 727 133 756 133 c 0,12,13 820 133 820 133 862 71.5 c 128,-1,14 904 10 904 10 899 -77 c 2,15,-1 896 -138 l 1,16,-1 858 -141 l 2,17,18 820 -144 820 -144 769 -118 c 0,19,20 718 -93 718 -93 612.5 -71.5 c 128,-1,21 507 -50 507 -50 461 -56 c 0,22,23 324 -76 324 -76 254 -119 c 0,24,25 215 -144 215 -144 171 -141 c 2,26,-1 128 -138 l 1,27,-1 125 -62 l 2,28,29 123 5 123 5 134 38 c 128,-1,30 145 71 145 71 181 102 c 0,31,32 203 121 203 121 219 127 c 128,-1,33 235 133 235 133 267 133 c 2,34,-1 319 133 l 1,35,-1 314 167 l 2,36,37 275 387 275 387 298.5 522 c 128,-1,38 322 657 322 657 413 729 c 0,0,1 545 726 m 0,39,40 525 737 525 737 500 737 c 0,41,42 477 737 477 737 429 693 c 128,-1,43 381 649 381 649 360 608 c 0,44,45 324 536 324 536 321 421 c 128,-1,46 318 306 318 306 349 180 c 0,47,48 355 154 355 154 362 126 c 2,49,-1 369 98 l 1,50,51 369 96 369 96 305 100 c 0,52,53 264 102 264 102 247 99 c 128,-1,54 230 96 230 96 212 82 c 0,55,56 183 59 183 59 169.5 29 c 128,-1,57 156 -1 156 -1 151 -53 c 0,58,59 147 -96 147 -96 149 -104.5 c 128,-1,60 151 -113 151 -113 168 -113 c 0,61,62 190 -113 190 -113 256 -78 c 0,63,64 402 -2 402 -2 570 -30 c 0,65,66 636 -40 636 -40 680 -46 c 0,67,68 711 -52 711 -52 775 -82 c 0,69,70 847 -113 847 -113 862 -113 c 0,71,72 876 -113 876 -113 878 -105 c 128,-1,73 880 -97 880 -97 874 -63 c 0,74,75 861 32 861 32 806 78 c 0,76,77 785 95 785 95 770 99 c 128,-1,78 755 103 755 103 720 100 c 128,-1,79 685 97 685 97 676 99 c 128,-1,80 667 101 667 101 671 112 c 0,81,82 682 140 682 140 695 206.5 c 128,-1,83 708 273 708 273 713 328 c 0,84,85 718 394 718 394 708 463 c 128,-1,86 698 532 698 532 675 583 c 0,87,88 660 617 660 617 617.5 664 c 128,-1,89 575 711 575 711 545 726 c 0,39,40 492 609 m 128,-1,91 492 615 492 615 496.5 620 c 128,-1,92 501 625 501 625 507 625 c 128,-1,93 513 625 513 625 517.5 620 c 128,-1,94 522 615 522 615 522 609 c 0,95,96 522 594 522 594 543 594 c 0,97,98 551 594 551 594 557 589.5 c 128,-1,99 563 585 563 585 563 579 c 0,100,101 563 572 563 572 557 567.5 c 128,-1,102 551 563 551 563 543 563 c 0,103,104 522 563 522 563 522 538 c 0,105,106 522 512 522 512 507 512 c 128,-1,107 492 512 492 512 492 537 c 0,108,109 492 561 492 561 471 566 c 0,110,111 463 568 463 568 457 573 c 128,-1,112 451 578 451 578 451 583 c 0,113,114 451 594 451 594 471 594 c 0,115,116 479 594 479 594 485.5 598.5 c 128,-1,90 492 603 492 603 492 609 c 128,-1,91 EndSplineSet EndChar StartChar: k Encoding: 107 107 5 Width: 1024 Flags: W Fore 413 717 m 0,0,1 417 731 417 731 435 734 c 128,-1,2 453 737 453 737 527 737 c 0,3,4 602 737 602 737 620 734 c 128,-1,5 638 731 638 731 642 718 c 0,6,7 645 705 645 705 656 700 c 128,-1,8 667 695 667 695 695 694 c 0,9,10 727 692 727 692 735 687 c 128,-1,11 743 682 743 682 745 663 c 0,12,13 749 638 749 638 739 605 c 2,14,-1 730 578 l 1,15,-1 794 582 l 2,16,17 863 586 863 586 891.5 568.5 c 128,-1,18 920 551 920 551 933 496 c 0,19,20 947 431 947 431 927.5 326 c 128,-1,21 908 221 908 221 870 159 c 0,22,23 852 127 852 127 845 49 c 0,24,25 838 -22 838 -22 818 -45 c 128,-1,26 798 -68 798 -68 722 -93 c 0,27,28 675 -108 675 -108 635.5 -112.5 c 128,-1,29 596 -117 596 -117 502 -117 c 0,30,31 366 -118 366 -118 304 -103 c 128,-1,32 242 -88 242 -88 205 -45 c 0,33,34 184 -20 184 -20 179 -5.5 c 128,-1,35 174 9 174 9 176 40 c 0,36,37 179 87 179 87 158 123 c 0,38,39 94 231 94 231 76.5 274 c 128,-1,40 59 317 59 317 55 386 c 0,41,42 51 451 51 451 53.5 467.5 c 128,-1,43 56 484 56 484 75 504 c 0,44,45 132 566 132 566 254 545 c 0,46,47 322 534 322 534 326 538 c 128,-1,48 330 542 330 542 318 581 c 0,49,50 307 620 307 620 307 658 c 2,51,-1 307 696 l 1,52,-1 357 696 l 2,53,54 388 696 388 696 399 700 c 128,-1,55 410 704 410 704 413 717 c 0,0,1 614 687 m 0,56,57 614 701 614 701 600 704 c 128,-1,58 586 707 586 707 526 707 c 0,59,60 463 707 463 707 451 704 c 128,-1,61 439 701 439 701 440 684 c 0,62,63 442 656 442 656 436 653 c 128,-1,64 430 650 430 650 393 663 c 0,65,66 346 678 346 678 341 672 c 0,67,68 337 668 337 668 345.5 613.5 c 128,-1,69 354 559 354 559 366 518 c 0,70,71 370 504 370 504 384.5 504 c 128,-1,72 399 504 399 504 449 518 c 0,73,74 465 522 465 522 468 515.5 c 128,-1,75 471 509 471 509 471 472 c 0,76,77 471 429 471 429 464 423.5 c 128,-1,78 457 418 457 418 429 439 c 128,-1,79 401 460 401 460 350 481 c 128,-1,80 299 502 299 502 251 512 c 0,81,82 213 519 213 519 194.5 518.5 c 128,-1,83 176 518 176 518 147 507 c 0,84,85 120 497 120 497 109.5 486.5 c 128,-1,86 99 476 99 476 92 453 c 0,87,88 80 408 80 408 90 352.5 c 128,-1,89 100 297 100 297 129 249 c 0,90,91 164 192 164 192 164 184 c 0,92,93 164 178 164 178 195 134 c 0,94,95 217 104 217 104 219.5 92 c 128,-1,96 222 80 222 80 214 56 c 0,97,98 206 35 206 35 206.5 24 c 128,-1,99 207 13 207 13 218 -4 c 0,100,101 238 -34 238 -34 267.5 -49 c 128,-1,102 297 -64 297 -64 359 -78 c 0,103,104 463 -100 463 -100 605.5 -81.5 c 128,-1,105 748 -63 748 -63 791 -22 c 0,106,107 804 -9 804 -9 809.5 32.5 c 128,-1,108 815 74 815 74 807 88 c 0,109,110 801 98 801 98 830 160 c 0,111,112 896 288 896 288 906 403 c 128,-1,113 916 518 916 518 864 542 c 0,114,115 775 582 775 582 634 472 c 0,116,117 581 430 581 430 573 430 c 128,-1,118 565 430 565 430 567 484 c 0,119,120 568 516 568 516 571 526 c 128,-1,121 574 536 574 536 584 535 c 0,122,123 641 521 641 521 654 526.5 c 128,-1,124 667 532 667 532 689 582 c 0,125,126 717 640 717 640 717 659 c 0,127,128 717 676 717 676 692.5 675 c 128,-1,129 668 674 668 674 638 655 c 0,130,131 604 636 604 636 599 645 c 0,132,133 594 653 594 653 604 660 c 0,134,135 614 668 614 668 614 687 c 0,56,57 EndSplineSet EndChar StartChar: n Encoding: 110 110 6 Width: 1024 Flags: W Fore 560 761 m 1,0,1 565 768 565 768 607 768 c 0,2,3 633 768 633 768 647.5 760.5 c 128,-1,4 662 753 662 753 685 728 c 0,5,6 715 695 715 695 734.5 644 c 128,-1,7 754 593 754 593 773 497 c 0,8,9 789 413 789 413 786 152 c 0,10,11 783 -112 783 -112 772 -123 c 0,12,13 762 -133 762 -133 516 -131 c 2,14,-1 271 -128 l 1,15,-1 268 -95 l 2,16,17 266 -74 266 -74 279 -55 c 128,-1,18 292 -36 292 -36 347 16 c 0,19,20 412 77 412 77 435.5 111 c 128,-1,21 459 145 459 145 481 212 c 0,22,23 493 244 493 244 494.5 262.5 c 128,-1,24 496 281 496 281 489 307 c 2,25,-1 478 350 l 1,26,-1 421 344 l 2,27,28 366 339 366 339 333 333 c 0,29,30 314 329 314 329 300 334 c 128,-1,31 286 339 286 339 263 358 c 0,32,33 237 381 237 381 231 394 c 128,-1,34 225 407 225 407 225 445 c 0,35,36 225 502 225 502 237 524 c 0,37,38 248 550 248 550 283 571.5 c 128,-1,39 318 593 318 593 358 598 c 0,40,41 478 615 478 615 525 649 c 0,42,43 542 662 542 662 547.5 674 c 128,-1,44 553 686 553 686 553 712 c 0,45,46 553 756 553 756 560 761 c 1,0,1 638 726 m 0,47,48 604 741 604 741 594 735 c 128,-1,49 584 729 584 729 584 692 c 0,50,51 584 663 584 663 578.5 651 c 128,-1,52 573 639 573 639 551 623 c 0,53,54 498 584 498 584 382 568 c 0,55,56 346 563 346 563 313 546 c 128,-1,57 280 529 280 529 264 507 c 0,58,59 256 497 256 497 256 449 c 0,60,61 256 418 256 418 261.5 405.5 c 128,-1,62 267 393 267 393 286 380 c 0,63,64 304 367 304 367 315.5 364.5 c 128,-1,65 327 362 327 362 343 369 c 0,66,67 371 379 371 379 439 379 c 2,68,-1 509 379 l 1,69,-1 522 318 l 2,70,71 531 278 531 278 530 259 c 128,-1,72 529 240 529 240 517 204 c 0,73,74 502 158 502 158 474 104 c 0,75,76 454 71 454 71 402.5 16 c 128,-1,77 351 -39 351 -39 321 -59 c 0,78,79 297 -74 297 -74 297 -88 c 0,80,81 297 -97 297 -97 339.5 -99.5 c 128,-1,82 382 -102 382 -102 522 -102 c 0,83,84 749 -102 749 -102 749 -94 c 1,85,86 750 -89 750 -89 754 164 c 0,87,88 756 329 756 329 752.5 387 c 128,-1,89 749 445 749 445 736 502 c 0,90,91 692 702 692 702 638 726 c 0,47,48 515 566 m 0,92,93 532 573 532 573 547.5 572.5 c 128,-1,94 563 572 563 572 568 564 c 128,-1,95 573 556 573 556 554.5 544 c 128,-1,96 536 532 536 532 518 532 c 0,97,98 504 532 504 532 502.5 546.5 c 128,-1,99 501 561 501 561 515 566 c 0,92,93 EndSplineSet EndChar StartChar: p Encoding: 112 112 7 Width: 1024 Flags: W Fore 435 669 m 0,0,1 459 676 459 676 540 672 c 0,2,3 594 670 594 670 615 665 c 128,-1,4 636 660 636 660 658 642 c 0,5,6 707 605 707 605 726 535.5 c 128,-1,7 745 466 745 466 728.5 397.5 c 128,-1,8 712 329 712 329 664 294 c 0,9,10 638 274 638 274 639.5 251.5 c 128,-1,11 641 229 641 229 672 182 c 0,12,13 696 143 696 143 696 132 c 0,14,15 696 120 696 120 757 58 c 128,-1,16 818 -4 818 -4 838 -11 c 0,17,18 851 -16 851 -16 855.5 -26 c 128,-1,19 860 -36 860 -36 860 -61 c 2,20,-1 860 -102 l 1,21,-1 517 -102 l 1,22,-1 174 -102 l 1,23,-1 174 -61 l 2,24,25 174 -38 174 -38 179 -27 c 128,-1,26 184 -16 184 -16 198 -9 c 0,27,28 235 11 235 11 284.5 62.5 c 128,-1,29 334 114 334 114 365 167 c 0,30,31 410 242 410 242 410 257 c 128,-1,32 410 272 410 272 378 296 c 0,33,34 329 333 329 333 313 417.5 c 128,-1,35 297 502 297 502 327 569 c 0,36,37 341 601 341 601 373.5 631 c 128,-1,38 406 661 406 661 435 669 c 0,0,1 628 621 m 0,39,40 607 634 607 634 546 640 c 128,-1,41 485 646 485 646 456 638 c 0,42,43 390 620 390 620 362 548 c 128,-1,44 334 476 334 476 358 387 c 0,45,46 367 357 367 357 399 327 c 128,-1,47 431 297 431 297 454 297 c 0,48,49 465 297 465 297 468.5 293.5 c 128,-1,50 472 290 472 290 468.5 281.5 c 128,-1,51 465 273 465 273 454 256 c 0,52,53 434 231 434 231 438 225 c 1,54,55 440 220 440 220 402 159 c 0,56,57 369 105 369 105 316 47 c 128,-1,58 263 -11 263 -11 233 -27 c 0,59,60 205 -41 205 -41 205 -56 c 0,61,62 205 -66 205 -66 260 -69 c 128,-1,63 315 -72 315 -72 517 -72 c 0,64,65 589 -72 589 -72 629 -72 c 128,-1,66 669 -72 669 -72 711.5 -71 c 128,-1,67 754 -70 754 -70 772 -69 c 128,-1,68 790 -68 790 -68 807 -65 c 128,-1,69 824 -62 824 -62 826.5 -59 c 128,-1,70 829 -56 829 -56 826.5 -50 c 128,-1,71 824 -44 824 -44 816 -38 c 128,-1,72 808 -32 808 -32 793 -22 c 0,73,74 762 0 762 0 708 57.5 c 128,-1,75 654 115 654 115 659 121 c 1,76,77 665 124 665 124 646 153 c 0,78,79 628 178 628 178 611 216 c 0,80,81 596 254 596 254 585 260 c 0,82,83 576 266 576 266 574 275 c 128,-1,84 572 284 572 284 577.5 290.5 c 128,-1,85 583 297 583 297 594 297 c 0,86,87 621 297 621 297 653.5 336 c 128,-1,88 686 375 686 375 692 415 c 0,89,90 714 563 714 563 628 621 c 0,39,40 EndSplineSet EndChar StartChar: q Encoding: 113 113 8 Width: 1024 Flags: W Fore 464 633 m 0,0,1 474 646 474 646 518 644.5 c 128,-1,2 562 643 562 643 573 630 c 0,3,4 587 616 587 616 594 510 c 0,5,6 601 423 601 423 617 335.5 c 128,-1,7 633 248 633 248 644 227 c 0,8,9 653 212 653 212 654 220 c 1,10,11 655 222 655 222 655 225 c 0,12,13 656 277 656 277 678 439.5 c 128,-1,14 700 602 700 602 708 610 c 1,15,16 719 625 719 625 758 625 c 0,17,18 801 625 801 625 834 577.5 c 128,-1,19 867 530 867 530 914 402 c 0,20,21 937 339 937 339 942 306.5 c 128,-1,22 947 274 947 274 947 184 c 2,23,-1 947 56 l 1,24,-1 905 0 l 2,25,26 852 -72 852 -72 760.5 -102.5 c 128,-1,27 669 -133 669 -133 507 -133 c 0,28,29 303 -133 303 -133 200 -83 c 0,30,31 165 -66 165 -66 119 -20 c 128,-1,32 73 26 73 26 61 57 c 0,33,34 50 85 50 85 51.5 177 c 128,-1,35 53 269 53 269 66 308 c 0,36,37 82 361 82 361 121 438.5 c 128,-1,38 160 516 160 516 193 558 c 0,39,40 218 593 218 593 232 601.5 c 128,-1,41 246 610 246 610 278 612 c 0,42,43 307 614 307 614 320 612 c 128,-1,44 333 610 333 610 340.5 593 c 128,-1,45 348 576 348 576 347 550 c 128,-1,46 346 524 346 524 340 467 c 0,47,48 330 369 330 369 329 276 c 128,-1,49 328 183 328 183 337 159 c 0,50,51 342 146 342 146 348 154 c 128,-1,52 354 162 354 162 368 200 c 0,53,54 412 319 412 319 441 532 c 0,55,56 452 619 452 619 464 633 c 0,0,1 552 596 m 0,57,58 544 611 544 611 518 613.5 c 128,-1,59 492 616 492 616 487 602 c 0,60,61 480 577 480 577 471.5 522 c 128,-1,62 463 467 463 467 465 462 c 1,63,64 475 445 475 445 433 297 c 128,-1,65 391 149 391 149 368 119 c 0,66,67 353 100 353 100 344.5 96 c 128,-1,68 336 92 336 92 328 99.5 c 128,-1,69 320 107 320 107 310 131 c 0,70,71 298 160 298 160 298 213 c 128,-1,72 298 266 298 266 310 538 c 0,73,74 312 566 312 566 308 573 c 128,-1,75 304 580 304 580 285 582 c 0,76,77 268 584 268 584 256 575.5 c 128,-1,78 244 567 244 567 221 536 c 0,79,80 189 492 189 492 147.5 409 c 128,-1,81 106 326 106 326 93 282 c 0,82,83 83 243 83 243 82.5 174 c 128,-1,84 82 105 82 105 92 78 c 0,85,86 103 49 103 49 143 7 c 128,-1,87 183 -35 183 -35 215 -51 c 0,88,89 268 -78 268 -78 357 -91 c 128,-1,90 446 -104 446 -104 547 -99 c 0,91,92 672 -94 672 -94 742.5 -72.5 c 128,-1,93 813 -51 813 -51 857 -4 c 0,94,95 898 38 898 38 911 84 c 128,-1,96 924 130 924 130 920 215 c 0,97,98 915 287 915 287 893.5 354.5 c 128,-1,99 872 422 872 422 822 520 c 0,100,101 801 564 801 564 788.5 579 c 128,-1,102 776 594 776 594 762 594 c 0,103,104 737 594 737 594 732 584 c 0,105,106 726 574 726 574 706 402 c 0,107,108 700 351 700 351 690.5 270.5 c 128,-1,109 681 190 681 190 679 177 c 0,110,111 674 130 674 130 661 123.5 c 128,-1,112 648 117 648 117 632 151 c 128,-1,113 616 185 616 185 601 251 c 0,114,115 562 419 562 419 562 515 c 0,116,117 560 580 560 580 552 596 c 0,57,58 EndSplineSet EndChar StartChar: r Encoding: 114 114 9 Width: 1024 Flags: W Fore 144 774 m 128,-1,1 156 788 156 788 239 789 c 128,-1,2 322 790 322 790 336 776 c 0,3,4 348 764 348 764 348 735 c 0,5,6 348 719 348 719 352.5 713 c 128,-1,7 357 707 357 707 368 707 c 0,8,9 380 707 380 707 384.5 714.5 c 128,-1,10 389 722 389 722 391 745 c 2,11,-1 394 783 l 1,12,-1 497 783 l 1,13,-1 599 783 l 1,14,-1 602 745 l 2,15,16 604 720 604 720 609 713.5 c 128,-1,17 614 707 614 707 631 707 c 0,18,19 646 707 646 707 650.5 712.5 c 128,-1,20 655 718 655 718 655 735 c 0,21,22 655 765 655 765 668 776 c 0,23,24 678 787 678 787 755 788.5 c 128,-1,25 832 790 832 790 848 780 c 0,26,27 861 770 861 770 858 639 c 2,28,-1 855 507 l 1,29,-1 802 504 l 1,30,-1 748 501 l 1,31,-1 745 181 l 1,32,-1 742 -138 l 1,33,-1 498 -141 l 2,34,35 254 -144 254 -144 244 -131 c 0,36,37 236 -117 236 -117 236 191 c 2,38,-1 236 501 l 1,39,-1 187 504 l 1,40,-1 138 507 l 1,41,-1 135 634 l 2,42,0 132 760 132 760 144 774 c 128,-1,1 317 717 m 1,43,-1 317 758 l 1,44,-1 248 758 l 2,45,46 176 758 176 758 171 751 c 1,47,48 164 746 164 746 164 638 c 2,49,-1 164 532 l 1,50,-1 218 532 l 1,51,-1 271 532 l 1,52,-1 268 210 l 1,53,-1 265 -113 l 1,54,-1 492 -113 l 1,55,-1 717 -113 l 1,56,-1 717 210 l 1,57,-1 717 532 l 1,58,-1 773 532 l 1,59,-1 829 532 l 1,60,-1 829 645 l 1,61,-1 829 758 l 1,62,-1 758 758 l 1,63,-1 686 758 l 1,64,-1 686 717 l 1,65,-1 686 676 l 1,66,-1 630 676 l 1,67,-1 573 676 l 1,68,-1 573 717 l 1,69,-1 573 758 l 1,70,-1 497 758 l 1,71,-1 420 758 l 1,72,-1 420 717 l 1,73,-1 420 676 l 1,74,-1 369 676 l 1,75,-1 317 676 l 1,76,-1 317 717 l 1,43,-1 EndSplineSet EndChar EndChars EndSplineFont tagua-1.0-alpha2/data/themes/pieces/EnquilTTF/Enquil.ttf000066400000000000000000000070201077523320400230570ustar00rootroot00000000000000`FFTMD  GDEF' OS/2VbhVcmapbcvt "@gasp glyfs\head6hhea4$$hmtx locaDmaxpOH name} DOpost 6_<JJJJ/44/\ @.3  PfEd+r334"|43\@ +bknr+bknp ",,,:J"w./<2<2/<2<23!%!!"UV"f/4!!4|r&Yt632'./&67>;'&7&#"'&3276326'&'.&7>76&'.46232#""54'.54324S4B<  @T&&33.F',+$ 4'/`$@)"BB,@H 7F US   ))5o]<7{W=++LCB "E X)H~<4+#L "_. 7B3"^l     47>3276#&'.76'.'&6766'&=3264&#"'&276.'&$7>'&7>'&"7>67654'&76$JK$  @E9 '&(L/O^|% @#9zD 2h+ B4Y5 91"   !#7A> NG. +/$lVEA!> ''&& m) %+ **  -o09,%) S >(n*6  2: |.[c632/&67>7>/&'.547>767>54&76;325676&'&6#"&0*' 7A/  97! F(x/ U" 5t$B DF  gU , %!f`T !&4=DC %+ &9+" , %'" 0  =(&$.6!n t9Ȉ\&Z6)5467>764'.7>.323:>.'.76'&'&'.632676Q6*1&!0z %c- 1 AzB8 @  &!jnHPU$"l  A %#-/' |))g5K%C <( Y<=6t  s&& N(3{8u676567632#"'.'&67>7>7667676.&'&46&'&7>7>'.'.#"&'&5& X  , '+B/ *5g#\  N!    , d4 T  S  P 5e},)+2 'y  jW4E_?AZ8H=2\'5*#"49b &wWnj,,'T+/*\UHb, 3 / DB`Ar[*L>326?;326547> '&/75#"; ;;=++=++ gf   56 11EH6588GH89LM34  &&    46S)ljCBqq)))))):v"!R{ t     D  D  Y  Created by Io with FontForge 1.0 (http://fontforge.sf.net)Created by Io with FontForge 1.0 (http://fontforge.sf.net)EnquilEnquilMediumMediumFontForge 1.0 : Enquil : 19-7-2007FontForge 1.0 : Enquil : 19-7-2007EnquilEnquilVersion 001.000 Version 001.000 EnquilEnquil2 ENQSTU  ?[M|4tagua-1.0-alpha2/data/themes/pieces/EnquilTTF/theme_eboard.desktop000066400000000000000000000002751077523320400251210ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Enquil Type=Application Comment=Eboard's Enquil theme,|converted to TTF|with potrace.| (unknown author) X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/EnquilTTF/theme_eboard.lua000066400000000000000000000020301077523320400242200ustar00rootroot00000000000000import("piece_theme.lua") shadow = 7 shadow_color = "#404040" shadow_offset_x = 3 shadow_offset_y = 3 shadow_grow = 6 function fromGlyphGrad(fg, grad1, grad2) return function(glyph) return function(size) local g = LinearGradient(Point(0.1*size,0), Point(1*size,0.2*size)) g[0] = grad1 g[1] = grad2 return fromFontGlyph("Enquil.ttf", glyph, fg, g)(size) end end end fromGlyphW = fromGlyphGrad("black", "#ffffff", "#b0b0c0") fromGlyphB = fromGlyphGrad("white", "#404060", "#000000") theme.black_bishop = fromGlyphB("0x0062") theme.black_king = fromGlyphB("0x006B") theme.black_knight = fromGlyphB("0x006E") theme.black_pawn = fromGlyphB("0x0070") theme.black_queen = fromGlyphB("0x0071") theme.black_rook = fromGlyphB("0x0072") theme.white_bishop = fromGlyphW("0x0062") theme.white_king = fromGlyphW("0x006B") theme.white_knight = fromGlyphW("0x006E") theme.white_pawn = fromGlyphW("0x0070") theme.white_queen = fromGlyphW("0x0071") theme.white_rook = fromGlyphW("0x0072") tagua-1.0-alpha2/data/themes/pieces/FantasySVG/000077500000000000000000000000001077523320400212565ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/FantasySVG/bb.svg000066400000000000000000000274571077523320400224010ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/bd.svg000066400000000000000000000273411077523320400223730ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/bg.svg000066400000000000000000000370631077523320400224000ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/bh.svg000066400000000000000000000257651077523320400224070ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/bk.svg000066400000000000000000000331311077523320400223740ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/bl.svg000066400000000000000000000175071077523320400224060ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/bn.svg000066400000000000000000000251411077523320400224010ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/bp.svg000066400000000000000000000134311077523320400224020ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/bq.svg000066400000000000000000000364041077523320400224100ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/br.svg000066400000000000000000000270461077523320400224130ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/bs.svg000066400000000000000000000303301077523320400224020ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/theme.desktop000066400000000000000000000003101077523320400237450ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=FantasySVG Type=Application Comment=Fantasy SVG theme,| by Maurizio Monge X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess[default], Shogi X-Tagua-Script=theme.lua tagua-1.0-alpha2/data/themes/pieces/FantasySVG/theme.lua000066400000000000000000000026201077523320400230630ustar00rootroot00000000000000import("piece_theme.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 theme.black_gold = fromSVG("bg.svg") theme.black_horse = fromSVG("bn.svg") theme.black_lance = fromSVG("bl.svg") theme.black_silver = fromSVG("bs.svg") theme.black_p_bishop = fromSVG("bh.svg") theme.black_p_knight = fromSVG("bg.svg") theme.black_p_lance = fromSVG("bg.svg") theme.black_p_pawn = fromSVG("bg.svg") theme.black_p_rook = fromSVG("bd.svg") theme.black_p_silver = fromSVG("bg.svg") theme.white_gold = fromSVG("wg.svg") theme.white_horse = fromSVG("wn.svg") theme.white_lance = fromSVG("wl.svg") theme.white_silver = fromSVG("ws.svg") theme.white_p_bishop = fromSVG("wh.svg") theme.white_p_knight = fromSVG("wg.svg") theme.white_p_lance = fromSVG("wg.svg") theme.white_p_pawn = fromSVG("wg.svg") theme.white_p_rook = fromSVG("wd.svg") theme.white_p_silver = fromSVG("wg.svg") theme.black_bishop = fromSVG("bb.svg") theme.black_king = fromSVG("bk.svg") theme.black_knight = fromSVG("bn.svg") theme.black_pawn = fromSVG("bp.svg") theme.black_queen = fromSVG("bq.svg") theme.black_rook = fromSVG("br.svg") theme.white_bishop = fromSVG("wb.svg") theme.white_king = fromSVG("wk.svg") theme.white_knight = fromSVG("wn.svg") theme.white_pawn = fromSVG("wp.svg") theme.white_queen = fromSVG("wq.svg") theme.white_rook = fromSVG("wr.svg") tagua-1.0-alpha2/data/themes/pieces/FantasySVG/wb.svg000066400000000000000000000274611077523320400224210ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/wd.svg000066400000000000000000000273151077523320400224210ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/wg.svg000066400000000000000000000370631077523320400224250ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/wh.svg000066400000000000000000000257651077523320400224340ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/wk.svg000066400000000000000000000313471077523320400224300ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/wl.svg000066400000000000000000000175071077523320400224330ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/wn.svg000066400000000000000000000251421077523320400224270ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/wp.svg000066400000000000000000000134001077523320400224230ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/wq.svg000066400000000000000000000346661077523320400224450ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/wr.svg000066400000000000000000000270631077523320400224370ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/FantasySVG/ws.svg000066400000000000000000000303271077523320400224350ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/LucenaTTF/000077500000000000000000000000001077523320400210565ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/LucenaTTF/Lucena.ttf000066400000000000000000001517241077523320400230160ustar00rootroot00000000000000LTSHDlpOS/2Q\~VPCLTmVMͼ6VDMX^qcmapg6o<.cvt  Dfpgm2Gs`bglyfu<hdmxբ head6hheamT$hmtxv@{ HlocauJmaxpx nameq66Jpost[̼prep+K-v_<[zll= Vx2MACR@ 2::RP`H& CO(V ~$   :   P, | H    Generated by Fontographer 4.1Chess LucenaRegularMacromedia Fontographer 4.1 Chess LucenaChess LucenaMacromedia Fontographer 4.1 19/11/99ChessLucenaGenerated by Fontographer 4.1Chess LucenaRegularMacromedia Fontographer 4.1 Chess LucenaChess LucenaMacromedia Fontographer 4.1 19/11/99ChessLucenaChess LucenaRegularGenerated by Fontographer 4.1Chess LucenaRegularMacromedia Fontographer 4.1 Chess LucenaChess LucenaMacromedia Fontographer 4.1 19/11/99ChessLucenaChess LucenaRegular  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghi. %+/5:<?BDFTXbdftx  (.17<>ADFKV[dfkv cB 2VW`ZjX\ca]CDYEeFbdifghHGIKJL[MONPQSRTUl+,KPXYD_^-, EiD`-,*!-, F%FRX#Y Id F had%F hadRX#eY/ SXi TX!@Yi TX!@eYY:-, F%FRX#Y F jad%F jadRX#Y/-,K &PXQXD@DY!! EPXD!YY-, EiD` E}iD`-,*-,K &SX@Y &SX#!#Y &SX#!#Y &SX#!@#Y &SX%EPX#!#!%E#!#!Y!YD- ,KSXED!!Y-?ABMAAAcbbccccBcccBTgQQJOHX~p                                                           ?G/ /и/ ܸܸ++013!%3#?w?kA ?+ܸи +и01%#533#T!!!SSS2!++015!!5!!!!S 3+ܸ+ܸ017#53#'#5TTS2"SS!!!B/++ ////01!3#3!S+++////01#3#!!SA++015!5!!!SSA 7+ܸ+ܸ0153#57#53TS"""TS3!////0172#"54  $(,048<@DHLPTX\`a// /////!/%/)/-/1// /6/:/>/B/F/J/N/R/V/Z/^/999 999999"9&9*9.92989<9@9D9H9L9P9T9X9\9`901!#7753 3333333337%353535353535353573573573h_w:O9;n<V:9f;_: ;]9UALIQihP$ $wOnWf_ ^^j8jjVj@jiMkHikjQhMM //01"&54632FaaFFaaMaFFaaFFaAA /+ܸ+ܸ013#5353ST2!S!!!2 //01%3#22222+015!!2222 //0153#2222+//01!323+//01133 //013#223+01!!32 //013#223! #'+/37;?CGJMQV[`ejoty~,/0/4/8/$%9@$+9A+'9B$%9C$+9D$%9E+'9F$%9I+'9y+'9%{и'|и|/}$%9+'9%и/$и/' и ///////// //// / +  ++*+и ܸи и#и&и+и*/и2кU 9Y 9[ 9\ 9]кa9c 9d 9eкl 9mкp 9qкt9y 9zк} 9~к 9к 9к 9к 9ик 9к 9*9*901%254#!"35!6723!53&546353333&'37'#75'7#3/75254#"577#?#?#7##7%&'7#7##7##7##7##7##7'#577+75337?75??%'775735573"'5737&'7?3'75#73'&'5#73&'3=3573573573 "܅~"JI"!!"ii}****K::C_`hCCbCC?!!VCC""vu]!"v0)).}Jb)v 0NIQidCC Q{# #Q <3B22!!)*``;;7BC*CD>!!DE!!v^!!!!!!!!!!!!!!!!7 BNh| &"7i_##Lu"K ,#9lQ>v)W)/}Ia)0MTHikjQh6/9=AEIMRVZ_cgkosw{;/?/C/G/Q/U/f/v//////5+5+9+ и9!и&и,и0к9959к59к59к5959к59к59к59к59к59к9959к59к9999959к959595901254#"77'#75'6723!53&54635333"3!254#7373733757&'3#735&'7'7#735?'?3?&'%735"'%5735573'7??75?7353#77%#57#73#73#73#73#73#7%&'7#73#?#?#?%57d****}܅~"JI"!!" QiIHN| 0))Vb4}))v4Q>z 8څ#, = H] ii^ 7&{ h[6 C=!!k!!j!!k!!k! k!"Y!!l!"u]v""CC?!!VCCCC!!)* Q{# #Q E#9 ,"uJ#?#i_X"7<&| hP77 B-!!!!!!!!!!!!!!!!v^!!DE!!VCD)BC2?GS]lvz~  "&*.26:>x/|////////////r,+r+v+иv ииmкv9,r9,к,r9,к,r9,к,r9,r9,к,r9,к ,r9, к,r9,к,r9,к,r9,кv9,r9, к#,r9,$к'v90v9293,r9,4к89:,r9<,r9>,r9013!53&546;676767#"'&''&'&'&76767&76767&?'&76'327654#"674'&'4#"63276"3!254#7373733 5&'73&'73?6%&'735&'735&'735&'7335&'737#657574'7&'7&'7&'7'7353#77%#57#73#73#73#73#73#7%&'7#73#?#?#?%571HI"CS$# 6),$* ( >4"MR?!`   I.      QiI?r 80  <A X K{ h q [&Y h[6 C=!!k!!j!!k!!k! k!"Y!!l!"u]v""CC?!!VCCCC3 #o6#" "2#  &.-!r`,$  HGrdmm ) GF Qh;<:H Z 8#4"MR?!E3QiI?r 80  <A X K{ h q [&Y h[6 C=!!k!!j!!k!!k! k!"Y!!l!"u]v""CC?!!VCCCC7a]\l<2   !OXG&Y; )90 2!$3n   "3 #o6#" "2#  &.-!r`,$  HGrdmm CCQh;<:H Z 8#BFJQV[aglquz}4+Afv ]A&qA5EqE9I9O9W999999994/8/иdPкRd9dTиdXиd\иd`кkd9dlиdvкd9d9dкd9dиdиdкd9dик9к99к9к9к9к9к9к/99к9к9к/9599к599901%5!%254#!"32654&#"#"'!&'&23!53&54636767&5467&5432%737373333 &#"735&'3'&'7'&'&'&'''3535 &5&'73&'73&'73#77%#57#73#73#73#73#7&#7#7%&'7#73#?#?#?%57c#((('3  lML76 ,.1?_"JI"_?0., QiIL ^ KD?^xw Qs|!f ph[6 C=!!k!!j!!k!!k!  5!"Y!!l!"u]v""CC?!!VCCCCdCCd""!"kKJli00adP# #Pbc1 /@Qh;<:H<M;]@ Dj ? ^y   {#f wqhP77 B-!!!!!!!!!!4!!!!!!v^!!DE!!VCD)BC6HS]amquy}  "&*.26:>V#+#k)+k/e+/DV+Dи/#ܸ и /#9A:VJVqAiVyVVVVVVVVV ]A VV)VqVܺ9#ܸV5иV;ܺA9FVD9JVD9R#9#[A:eJeqAieyeeeeeeeee ]A ee)eqAfkvkkkkkkkkk ]Akk&kqA5kEkqnV9oV9rкt#9vкx#9zк|9~к9#9к#9к99#9к9V9VD9к9к9к9ик#99V99999999V9кV9к9#999к#9кV9кV9ии/к#9#9#99#9 9 9999)k999V9к9!9#9%9'V9(к+9-9;/и//0к2V93V95VD9;7и7/8к:V9;и;/<к>#9D@^+^a+a,h+,G_+GAX+A8+8+и иGиAи8 и>иAIиGTиhܸsиwи{иик899к99h,9кh9ииикh9к8989к^9к^9^9к^9к ^9 к^9к^9к^9кXA9^9 к#^9$к+^9,к0XA92_G93^94к8_G9:^9<^901254#"!254#"53&5463'#"&54632&546327&54632#"'23'7#"''254#!"35!2654&#"7273737333575'5'3?%'''3536?3&'73&'73&'7373654'7'75'&'7%&'7&'7?575#77%#57#73#73#73#73#73#7%&'7#73#?#?#?%57d!!"C!!"I"L ''' .:**;. ''' L!IG F#n''''QiILcESg+u?Wd Q vE 'v+"11;( o ƫ K#(h[6 C=!!k!!j!!k!!k! k!"Y!!l!"u]v""CC?!!VCCCC !""!!""!9 #'((J/7*::*7J(('" RSRTdCC''''Qh;<:H<MaCc)E+J&?Xd È vRF.'#+4 "!1;o t Ku &hP77 B-!!!!!!!!!!!!!!!!v^!!DE!!VCD)BC6 #'+/37;?CGKOSW\_cgjosw{ + +++++++к9Kܺ K9 K9к9K9 иии иикK9K9  и /!и#к%K9'K9)K9*к-K9.к1K93K94K96к9K9;K9<K9>и@и@/CK9DK9KFиLиL/KNиPиP/KRиTиT/KVиXиX/K[и]к_ 9`K9c9e9KfкhK9Kiиmкo 9p 9r 9tK9vK9xK9zK9|K9~9K9K9K9KкK9K9K9KкK999K99KкK9K9KкK999KкK9к 9ии и ܺ9ик9K99K99K9K9K9K9K9K9+++++++:ܸи:к :9: к:9:к:9:к%:9:&к1:9:2к@:9:BкL9N9V9:Zк]:9:^иdиhкi9lкo9p9qкt9uкx9yк|9}к9к9к99к9к9к99999ииииииииииик9:к:9:0173737#73?#73575#737#733575#735#735573'7'757575757353'73#77%#57#73#73#73#73#7&#7#7%&'7#73#?#?#?%57##5##5#254#!"35!53&5463#3353353#23'!5735735#75Qi!!ۆ""6!0!c'ⅅy )^h[6 C=!!k!!j!!k!!k!  5!"Y!!l!"u]v""CC?!!VCCCC\d\?$#I!8r\\r8"J88b6*Qh;!qh!1{!_!Or!!'3343z *hP77 B-!!!!!!!!!!4!!!!!!v^!!DE!!VCD)BC OdCC! "<M# <~6B+o/d ///013#5244"""21#Fa!!#0SaE5 '159=AEIMQUY]aeimquy}/#и#/&Ap&]A&qA_&qA&]A &q ܸ& Ap ]A qA_ qA ]A qܸк 9#и/#и#%ܸ#7и7/8#&9;#&9=#&9%CиC/E#&9J#&9&MиM/S& 9U& 9 ZиZ/[& 9]& 9#_кb& 9e& 9g#&9 kиk/m 9n#&9s 9v#&9~ 9 9& 9& 9& 9& 9#&9#&9#&9#&9 9 9#&9#&9#&9#&9#&9& 9#&9&и/ 9& 9& 9& 9 и/ и/& 9 9 9и/ 93/7//B/F/J/_/g///////(}+(+#иܸи и#!и'ܸ-к[#9c}(9j}(9l}(9q9s}(9t}(9}uкy#9{9#9}(9}к}(9}к#9}(9}к}(9}к}(9}к}(9}к}(9}к}(9}и}к}(9}к}(9}к}(901753&546;&7%&54632323%"3!254#'35#5##3737373337757575'735'735?#7#?#?#7##7%&'7#7&#7#7?#775#7?#7&'7#7'7#57'73537+7?67&754'73&'73&'7373cI"/c0##0c."Jlee>hh)QiIL {CCCC?!!VCC""vu]!"!!DE!!v^!!!!!!4!!= !!2!!!=!! !!7 B hIR  ! [M4-*@1 $(,048<ADHMRZ`fkpw|{/////////////+++99999 к99к9к%9&к)9*к-9.к192к596к99:и>кA9BкC9EкG9I9X9l9q9v99999999иܸии 017577#?#?#7##7%&'7#7##7##7##7##7##7'#577+755?'&'7&'&'775654'773&'73&'73&'736?353'3''?%'35'57=353573573573"3!254#53&5463'#"&54632&546327&54632#"'2372CCCbCC?!!VCC""vu]!"!!DE!!v^!!!!!!!!!!!!!!!!7 BNh &K? : o1;M "+.'RF vd \Xu?&+s)EhMkHikjQhH #'((J/7*::*7J(('" ) !%)-159=AEIMQUY]aeimquy}// ///(/0/8/@/H/N/R/V///`/h/p/x////////999 9 999999$9,949<9D9G9J9L9O9S9W9Z9\9_9d9l9t9|99999999901!#77533#55#733#57 37'#'#'#'7#'73#%57 3377#735'35'35'3?'7357#?#73 35735735737/73#'#h A `v lG  Cp   r J  _: ;bU  a  8  :w c >fLIQiGGFGhP ( ˧`v m  C5  ^ [  1 f_ U)  bR  8{ y u &ȼ9fHikjQhHII,A-/./ܸ-и/ܸܺ9/+01!!654#""#!5#654&#&'&'654&  ,.0?_"I#J"_?1.,T/ 1cbP# #Pda00=Ac6A+6@8+@A@9A@9Aܺ+A@9:A@9@C>/8@+8016'&'&'&'&'76327676767#"#!5#654!! |RM"4> " *#-MVSC"I!H*nH  $,`r!-.+ #1#5%I6o# 3&u'/(/ܸ'и/ܺ9 9999%++01!!%5#654&+6'%654&#"#"#J".c0##0c/"IC "s g%#00#%g # !++ ++ܸиܺ9и#++и01!!#5#3"#!5#654&#3##5r8!I$J"9s" #<M<e/+/+9 9ܺ59;ܸ>+ +01!!%5#65432654&#"654&#"'654&#"327"#I!L ''' .;**:. ''' L"IC "'((J/7*::*7J(('# '͸(/)/ܸ(и/99 9 9 9 9 9999ܸи/9ܺ9$9%+ +01!!3'57#'73&'"#!5#654&#&****ۅ"I$J"~X!!*) Q{# #Q 2 //01!43222cC"&.Q]-\+\R+и)ииRܺ=\9=/-ܸи-к;\9CܺEC9RVиSWи\X&/+&@++@P$+PJ+JU+T+TUܸJиJиииPиP0иJ6иJRиUYиVZиT[013#36'%'35#535254#!"35!254#"53&546;&7%&54632323%35#5##3'dd_ _ddF#n332I"/c0##0c."J~ee!ddddbjjdddCC1221" #s g%#00#%g " "dd" //013"2222 //01#52222 bC ).3?BEHKST/U/+ܸиT$и$/%ܸ+'ܸ$/к5+'98+'9;$%9>$%9@$+9A+'9B$%9C$+9D$%9E+'9F$%9I+'94/ +  ++*+ии и#и&и+и*/и201%254#!"35!6723!53&546353333&'37'#75'7#3/75254#" "܅~"JI"!!"ii}****K::C_`dCC Q{# #Q <3B22!!)*``;;7bC/9O/+9+ и9!и&и,и0и501254#"77'#75'6723!53&54635333"3!254#d****}܅~"JI"!!"!!)* Q{# #Q 4"MR?!`   I.     3 #o6#" "2#  &.-!r`,$  HGrdmm ) GF cCK[e+A:JqAiy ]A )q/l+n+nt\+tиn`иtfиnj01654'&'&'#"'&'&''&'&'&'6322676767632''&#"5&5476"3!254#73!53&546;676767#"'&''&'&'&76767&76767&?632#"547&676!5 0(;  -,2/ 5#"/K- ,S&W   & 1HI"CS$# 6),$* ( >4"MR?!E37a]\l<2   !OXG&Y; )90 2!$3n   "3 #o6#" "2#  &.-!r`,$  HGrdmm CCcCt(2~+Afv ]A&qA5Eq%/+и)и.0123!53&54636767&5467&5432"3!254# ,.1?_"JI"_?0., T00adP# #Pbc1 /qcCt %NO/P/)ܸA:JqAiy ]A )qODиD/Afv ]A&qA5Eq)$и$/K/6++ܸ5ܸиܸ/ܸ!и4и58и9и/>01%5!%254#!"32654&#"#"'!&'&23!53&54636767&5467&5432c#((('3  lML76 ,.1?_"JI"_?0., dCCd""!"kKJli00adP# #Pbc1 /BCHS]amW#+#k)+k/e+/DV+Dи/Af#v######### ]A##&#qA5#E#q#ܸ и /#9A:VJVqAiVyVVVVVVVVV ]A VV)VqV;ܺ;9V5кA;9FVD9JVD9R#9#[A:eJeqAieyeeeeeeeee ]A ee)eqAfkvkkkkkkkkk ]Akk&kqA5kEkqDoa+a,h+,G_+GAX+A8+8+и иGиAи8 и>иAIиGT01254#"!254#"53&5463'#"&54632&546327&54632#"'23'7#"''254#!"35!2654&#"d!!"C!!"I"L ''' .:**;. ''' L!IG F#n'''' !""!!""!9 #'((J/7*::*7J(('" RSRTdCC''''cC 7;z+&+&'+*+*++.+.Afv ]A&qA5Eq ик9#и.3к5.9.=+-+-6+60+0+++ #+ ии и6 и6и0!и-$и+&и-(и#.и08и#901##5##5#254#!"35!53&5463#3353353#23'! \d\?$#I!8r\\r8"J88y OdCC! "<M# <22 //013#522222cC '12/#и#/&A &qA&qA_&qAp&]A&] ܸ& A ]A_ qA qAp ]A qܸк 9#и/#и#%ܸ3 / /#/+%(+%иܸ% и017"3!254#353#23!53&5463#335"3!254#s9"JI!8rdNݦ# "<McC",8+Afv ]A&qA5Eq 99/+#иܸи и#!и'ܸ-01753&546;&7%&54632323%"3!254#'35#5##3cI"/c0##0c."Jlee>hhC #s g%#00#%g " TBddBBC8BC/+ +(и .и6и9и=01753&5463'#"&54632&546327&54632#"'23%"3!254#cI"L ''' .:**;. ''' L!ImC #'((J/7*::*7J(('"  // //017/73#'#GGFGHII8 6+ +6и/6 916 91/ܸ://&+& +и/ 9 и/9/и//301!3653#"'632#"'&546323254#"#652 B8w*JI$5,C&#,C64h 34?!$  cr?7-$4+ 3+ +Af v ]A  & qA5 E q+и-и-/31и1/6//+9"и"/01!33632#"'&547632#"&547654#"&#&3276542--:L4A&"O#)X/ #48  +6-3=50Ck.91OA, 3!$,<'1 +++/++и/99Afv ]A&qA5Eq/и/Af+v+++++++++ ]A++&+qA5+E+q3//9901!3#"'&'475&7676654'&#"3276'2`ShL,HE,&23,"L!J6$aM5GD$3C0"/* 4b/C3%o#*u+/,/+и/)ܸи,ܸ)и/и/9)и/$ܸи//+01!!7&'52=4'73676;"4#"J4.-> 8* *3/W  .1/ 7m" z$TF{(+++>и>/H//// + :4+:  и /"и"/01!3336323276=3#"'&'&#"#"'67654&'&&'&7632BS2!(9  W!BQ$/ !2(!08$*4)3   24@='& $4-6:  g;+++////01!3#34+53273;#5325!S*>" /),HQBK50+5#=+#++= и /Af#v######### ]A##&#qA5#E#q&=#9=(Af5v555555555 ]A55&5qA55E5qD//// ,+ AиA/ܸи/ %и%/A&и&/,3ܸ,;и;/01!333327656#"#"&5&7632#"'&546323254'&+BS2!1.5) 8"C$Sb5)9+ )2 /< &,O 1 ;E3' /# W+Q:Ѻ9+++9и/992992/ܸ97и7/<////' +' + 9 и /9и/9 0и0/ 401!333653#"'632#"'&546323254#"#654BS2! B7v*KH$P#0&# -B64 h534M $  cr?7-9Jq+++ ии ////+иܸк901!333#5733#;#532=#BS2!煨888)%n = QO(8Ժ+ 7+ ++Af v ]A  & qA5 E q/и1и1/75и5/:////+9&и&/01!333632#"'&547632#"&747654#"&#&327654BS2!.,; "@@&"N"*W 0 #47  +7,)"%6/Ck.91OA,0$("?H +4.+.++и/99Af.v......... ]A..&.qA5.E.q6////9901!333#"'&'475&7676654'&#"3276'BS2!(T j.)5GD+&24,"L"K7%!_N6FD(3D0"0* 4b=C3%3'+/}0/1/ ܸܸ0и/ܸии/и/ 9!и!/#и#//)(+)-,+-014#"'7&'52=4&'73676;"5!5! **J4.- > 8 " z$0W .2 .7n!!SS3&*.K//0/ܸ#ܸи//и///('+(,++,01"3267&'&'&=4766?5&'5!5! *  #,-> 4= f$'#u  !!SS3++ /++01767&/&=4?'5!5!#D !i$=%"o*) 2:? $I O!!SS3,045/6/5(и(/ܸ6ܸܸ(и/ и /и/и/и/#/.-+.21+20154'&54632"'#"&'56=65!5!3F""/$% 20 "!|$ 2! ><"   - !!SS048g'.+'.и/.и/.ܸи/и/' )/21+265+601#5254&54323653#"&#";#"&'#+532=45!5!)#(  D a") (F"! = 3")B2!!SS3++ /++01#?327&=47675!5!/ 7o1"=] 0qrUD63"M&4 !!SS 59=s>/?/ܸܸ>1и1/ܸ и /1и/$и$/-и-//$/76+7;:+;01&'&'32?"#"'&32327654/&5&=4765!5! *6)!0T&*B+,)2 )  -."!% & "}!!SS .267/8/7и/ܸи8ܸ ܸ и /9'к(9 ,и,//0/+06*+6/4ܸ3017'676=4#"67&'52=4'&'7363#"5!5!P"'H:  !   x ,B8*"nG,""<&A82!!SS   !7;E+9 9 /8,+8+9++&@+&7+7и&ии&и6ܸ#и+.и&3и+<015'3'7#77'#75'&'373'6723!53&54355!%254#!"3VVx55^%xx%&xx&5{^^zxr4B-B4rxxkCu44VVxwxx%&x/"/) G5 ww 5]G ><+15 ww 5HtXY+?DE9?+9+?9F//9 901!3"'&'&#"#654&54'632632254'&'&32#"'&5676762. 1  :#&   $>F/4SI$ 4  V1  1$#92L82 !%-N'O/;и;/A?qA`p]ܸи/и/ии(A?(qA`(p(];,ܸ9и9/(Aܸ(CиC/AP%.+%>*+>M#+MH+H&+&HиH иܸииMиM/иH4к9&9C&901%36/&'3#53533#254#!"35!254#"53&54;&?&54632323zV  Vcc ddBlJ---B5*Z, +Y)5B>`` cc [<<w-,,-lx 5N]"+* "]5 xXEY;@+;++ @9G//// 9!901!333#.#"#654&54'63267632654'&'432#"&767676BS2!Z0A2   )#&   %=F)$RI$ 4   &1 1%":0L'91 '++//014+53273;#53253)>#/*2,H ~] + + ии// + иܸ к901!3#5733#;#532=#2888*&n = Q++015!!5!!!!S++015!!5!!!!SFQ]+A:JqAiy ]A )qZиZ//d+f+fkR+kиfWиk^иfb01%654'&'&'&''&''&'&'&'627676767632''&'&6"3!2=4#73!53&54;676767'"&''&/&'&76767&76767&547632#"547&676!5D , ,  (8Z 5  ,B+ GJ#O  -A-B5<K! )0+ 8-!FI9o. 5TTSb6  )  h 'Z 6%4+ % J;/b  ! . xx 5c2 0$  **(gT*"   B@g[abx    ==B#3.+3&=+&+= и /Af&v&&&&&&&&& ]A&&&&qA5&E&q$=&9Af3v333333333 ]A33&3qA53E3qD//*+AиA/ܸ и /$и$/*1ܸ*9и9/01!3327676#"#"&'&7632#"'&'&632327654'&+22$ 6*8!C%(c4)9+ '2 /% ', &O 1 # E4' /# *-o+ /+01!!67'&=4?'"E+#i$=%3o'*/:@ #H O?s#++8и8/A// + 4.+4 и/ и/и/01!36323676=3#"'&#"#"'67654&'&3&'676322(   W 0AR$/ "0/$!08%*40+.  3 15B;'&#,4.5; o*0o1/2/1&и&/и/&,ܸ и /, и /,и/2ܸи//!/+01!!&54632#&#"&'56=6754F" ".$' 20 " 32  ?<"   - |%o&*O+/,/+ и /ܸ,ܸܸи/%и%///()+(016?5&'7"3227&'&=47676!! 2 ) "(,-#  ) f#'$u ~3 6s-4+-4и/4 и /5 и /4 и /4ܸи/"и"/-&//+01!!#5254'5&54323653#"&#";#"&'#+532=4)#(  D a"3 ( F"! = 3")B2.8_9/:/ ܸ/ܸи/9*и*/и/*4ܸи//&и&///+01!!"#"'&32327654'&5&=476&'&'367)7)!0T&*B .,)0 3*  -."!% 3#"}3  2k3/4/3#и#/ܸи4ܸܸи/#9#+к,#90и0/ /+01!!7'676=4#"67&'52=4'&'7363#"P"'H:  !   x ,38*"nG,""<&A8o+ /+01!!327&=467#77o1"=]# /3TD63"M&&%q 59z+%+%&+)+)*+-+-Afv ]A&qA5Eq ик9"и-1к3-9-;+,+,4+4/+/*+* "+ ии и4 и4и/ и,#и*%и,'и"-и/6и"7015##5##5#254#!"35!53&543#3353353#23'!wSZSBlB52gRRg25B22񗗗zZ<<w 5,5 w7777j *Yr*<Pa{  a8R$)*-03|5667"78"889::;(;e?dA&B9BJCCD)DPDEFvFGGHIJJKwKLoLMJMNNO:OQRS(T,TTUKUkUVWXXY6YZ$Z[&[`\o\o{l !"$%')./012345679:;>?@ABCDEGINOPQRSTUVWYZ[bcdeijklmnopqrstuvw.null `uChess Lucena 7CHER00   !!""##$$%%&&''(())**++,,--..//00112233445566778899::;;<<==>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~tagua-1.0-alpha2/data/themes/pieces/LucenaTTF/theme_jose.desktop000066400000000000000000000002551077523320400245750ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Lucena (Jose style) Type=Application Comment=Lucena TTF theme.| by Armando H. Marroquin X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/LucenaTTF/theme_jose.lua000066400000000000000000000013351077523320400237050ustar00rootroot00000000000000import("piece_theme.lua") shadow = 7 shadow_color = "#404040" shadow_offset_x = 3 shadow_offset_y = 3 shadow_grow = 6 function fromGlyph(glyph) return fromFontGlyph("Lucena.ttf", glyph, "black", "white", 6.0) end theme.black_bishop = fromGlyph("0x0076") theme.black_king = fromGlyph("0x006C") theme.black_knight = fromGlyph("0x006D") theme.black_pawn = fromGlyph("0x006F") theme.black_queen = fromGlyph("0x0077") theme.black_rook = fromGlyph("0x0074") theme.white_bishop = fromGlyph("0x0062") theme.white_king = fromGlyph("0x006B") theme.white_knight = fromGlyph("0x006E") theme.white_pawn = fromGlyph("0x0070") theme.white_queen = fromGlyph("0x0071") theme.white_rook = fromGlyph("0x0072") tagua-1.0-alpha2/data/themes/pieces/MayanTTF/000077500000000000000000000000001077523320400207145ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/MayanTTF/Mayan.ttf000066400000000000000000001313101077523320400224770ustar00rootroot00000000000000LTSH¦f`@OS/2Pd!VVDMXcmapELcvt fpgm2Lsebglyf-W; hdmxJ',headh; 6hhea 2D$hmtx* locah8zmaxprUh nameOkposttvHprep+5_<!L .<<+  SWAP@      % .8 ? S a u   Chess MayaRegularChess MayaChess MayaChessMayaChess MayaRegularChess MayaRegularChess MayaChess MayaChessMayaChess MayaRegular#$%&')*( !"+689017-2 45./  3 ,*  %)+/59:?BDFTXbdftx !(+.17:?ADFKVadfkv*$.20B(6017-2 ./  3 ,<3333;3333DLLL77+,KPXYD_^-, EiD`-,*!-, F%FRX#Y Id F had%F hadRX#eY/ SXi TX!@Yi TX!@eYY:-, F%FRX#Y F jad%F jadRX#Y/-,K &PXQXD@DY!! EPXD!YY-, EiD` E}iD`-,*-,K &SX@Y &SX#!#Y &SX#!#Y &SX#!@#Y &SX%EPX#!#!%E#!#!Y!YD- ,KSXED!!Y-\nn$23233@            !   ! !"!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!"!!!!!!!!!!!!!!!!!!!!!%&%%%%%%%%%%%%%%%%%%%%%%%%%%%%$%%%%%%%&%%%%%%%%%%%%%%%%%%%%%*+************************************+*********************./............./.................../.././............././...232222232223233323222323322222222222223222222222222222222222676666666666666666666666666666666665667656666666666666565666:;:::::::::::::;::::::::::::::::::::::;:::::::::::::::::::::CDCCCCCCCCCCCCCCCCCCCCCCCCCCCCBCCCCCCCDCCCCCCCCCCCCCCCCCCCCCKLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKLKKLKLKKKKKKKKKKKKKKKKKKK\Z / /012#".54>"<,,<""<,,<-;""<--<"";- )7ES\enw%762"'.#762"'&4'62"'&462"'&4'62"'&4'62&'&4'> "'&47%64'&""'&47%64'&""'&4762"'&4762"'&4762"'&4762"'&4?62"'&4?62"'&42#".54>z.FG,0)9EPgiR:2C,GF. "<,,<""<,,<  .FH, :Gff<2&,GF.-;""<--<"";- )7ESao}%762"'.#762"'&4'62"'&462"'&4'62"'&4'62&'&4%62"'&462"'&4762"'&462"'&4762"'&4762"'&4762"'&4?62"'&4?62"'&4z.FG,S $S,GF.   .FH,S|%S,GF.Ey!7R+r+8+8G+GA&6FVfv ]A]A]A)9IYiy ]A&6FVfv ]A]ar9a/ܺRG9RG9mRG989/A]A)9IYiy ]|ܺRG9G L+ w+w+l"+l-+-иAиA/WиW/aиlиl017"3!2>54.##!.%"3!2>54.#;2#!".54>;2>7#".54>;.54>3232#"32>54.  C   #    C    G l *9 8+ k +!!++!!+   W5_P=>O_    d!<71*!  !*17=  " 9**9 "  w!++!!++!Eyhv_S/(+Ii+Ii ܸiи/3иi=и=/>иI]и(~01"32>54.;2#!".54>;2>7#".54>;.54>3232#%";2654&#"3!2654&#####x    G l *9 8+ k     !<71*!  !*17=  " 9**9 "       Ew5G?H/I/Hи/Iܺp9A&6FVfv ]A]A]A)9IYiy ]999*/++QܸTиܸиܸииииQи/01>&'&>.>7>7262"&#:3.'.5>746.'.'>.'67>7>72"3!2>54.#!#"3!2>54.#'32#!".54>;.54>7.>7>7*&".'..'.>7>7>5          VU    * "(/2       B  C  O     #     " #      1  Q"&   "! L   #(),,(        j    h       /.-+       '#" #'# Ew!5CQA/Ke+KDܸ<ܸ6ܸDZиZ/Dpиp/qKD901267.>7>74."67>7>'."3!2654&#"3!2654&#'32#!".54>;.54>7.>7>7*&".'..'.>7>7>5:27>'4.'"       R W g       #     " #          "#  (#   0   z   ]    /.-+       '#" #'#    Dy)?5/i+/++J+J^:+^A]A)9IYiy ]A&6FVfv ]A]A/&/6/F/V/f/v/////// ]A//]A::]A:):9:I:Y:i:y::::::: ]Oi^9Xi^9oi^9xi^99A]A)9IYiy ]i^95c+5 +n*+n+nиOиO/nXиwиw/012>54.#""3!2>54.#"3!2>54.#7232#!".54>;.54>;.5>7>7.54>32>"&'.6?6.'.'#"&'32>'.'            F    a   &Z  X&     j  _    %8 #"""  5        h  kn   51*       (07,)%!     v  p  /i9"! !!  Dym{bX+bAb&b6bFbVbfbvbbbbbbb ]Abb]UXb9oXb9]/%/+%C+Cи/%:иܸ/0126?232#!".54>;.54>;.5>7>7.54>32/#"&'326";2654&#"3!2654&# b  &Z  X&     D   z    V n    51*       (07,)%!     A#!c   q   EyGKOSW[_cgkosw{Q'+4+O2+OiI+iyM+ymj+m;+;[n+[+?+?A&6FVfv ]A]A]A)9IYiy ]OHиH/7ܺ8My98/<n[9+><+<,+,3+qV+qK+LS+LiN+i,и>5и<7и>9и3?иiHиqPи,TиiXиKYиL\иN]иq`иSaи,dиVeиKhиKlиimиSpиStиquиNxиLyиV|и,}ииии017"3!2>54.#'2#!".54>37>75#53353353#35#35#35#35'#'#'#'#3533535335'3535!535##5##5#3  C  )+- FEFF de_*#wqw"_o$3qe$ee$ehhhUDDDCC   4:lhg5Ddddd"8hfjMNLL MMtNNrLLrLLMMMMLLLLtNNLL~ThhhhEy159=AEIn!+!?>+?;:+;('+(!9/">?9"/%ܺj:;9j/-ܸ*к2>?92/3ܸ26и37и:Bи;Cи>Fи?GиNܸSܸNWиS[иjaи-cиc/-nܸeи(p +34+3 + &K+&;<+;CD+C78+7и&!и #и 'и)и;>и<@иCFиDHиCJиCMиDOи7Qи7Sи8Tи;Vи<Xи3Zи4\и _ܸ4`и3bи<dи;fи8hи7jиDl012#!".54>37>75#53353353#%3#3#3#'3#3#'3#%5!3#;#3#3#!5#53'#53'#535#5,. FEFF hhhhFeeeeeeee#Dd#*os+$e^:lhg5Ddddd"8hfjP-M"LLL+MMMM!!M#M"L"P''P"L"M#M nE'/VиV/zA?z]Az]Az]A@z]A]A?]A@]A]#z9(z9-z92z9=z9Ez9Kܺ\Vz9dVz9oVz9rVz9wz9zܺVz9z9z9z9zи/и/zи/и/Vܺz9z9z9Vz9Vz9KP+[+[+d+d7+7и/7и/(9d=и[Eи7jкw9dк79к79[01"32>54..#">7'>732>732#!".54>;.54>732>7&>7.54>327?7'7"3!2>54.#'.''.'#".'&'"3!2>54.#    j((  "%"        % "  CFFDEEDEEDDEE  C  w"''  ! !    i    &&  !'       w   '!    """"""""""t"""                 nE#'+~+A&6FVfv ]A] ~9~9~9 ~9$~9*~9,~9{~9/JT+Jи/hܸAиJ_и`и`/ܸT0132>727'.'7'7'77'7'7>732>732#!".54>;.54>732>7&>7.54>32'#"&'326"3!2654&#"3!2654&#    &# !'!JLLJJLLIJLLJLL"        % "     h _  &   (y'''''''''''''!'       w   '!     }   z   '09BKT]ky3IWenw9+9++D+и/A&6FVfv ]A]9fиf/ f9f9f9f9'f90f9;f9Kf9Uf99/ܺf9f99/A]A)9IYiy ]f9#ܺ(f9A9&969F9V9f9v9999999 ]A99]ADD]AD)D9DIDYDiDyDDDDDDD ]pf9xf99f9f9+4>+4++3+93и4ܸиܸии3и(и?ܺn>49oиxиии/01 "'&47'"'&4?'"'&4?#7 62'62762'#627>'762'762 62"'&4762"'&4?62"'&4?62"'&4'762/762%#!.%"3!2>54.#"32>54.;2#!".54>;2>7#".54>;.54>3232#"3!2>54.#762"'.#762"'&4%"'&4?3"'&4?"'&4?3"'&4?"'&4?%"'&47ahGށ)2Pt5B_R3A7`_{5$F. rl #    +!!++!!+p    G l *9 8+ k   C  Tdt0,.1&*0h ;M)PA߇B9B__D5$zF.q7g4`O>=P_     ,,  ,,  =71)!   !)18<  " 8**8 "    Sdtb,./' / (,5>GPYbkyk,+,+lv+l,ܸv ܸܺ 9 9(vl9l*и*/lHиH/,9ииии/,!ܸ6иlKиK/ Lܸl`и`/La01%"3!2654&#%"'&47'"'&4?'"'&4?#7 62'62762'#627>'762'762 62"'&4762"'&4?62"'&4?62"'&4'762/762762"'.#762"'&4%"'&4?3"'&4?"'&4?3"'&4?"'&4?%"'&47";2654&#;2#!".54>;2>7#".54>;.54>3232#'"32>54.#  hGށ)2Pt5B_R3A7`_{5$F. r2Tdt0,.1&*0   #    G l *9 8+ k ####   h ;M)PA߇B9B__D5$zF.q7eSdtb,./' /    =71)!   !)18<  " 8**8 "  4FOXajs| &/8A B/C/Bи/tиt/Cܺot9A&6FVfv ]A]A]A)9IYiy ]t9t9t9GиG/IиI/LиL/OиO/Pt9Yt9bt9lt9и/t9t9t9t9t9/t98t9;и;/H+++иииHPиP/HYиHbиHkк|901>&'&>.>7>7262.:3.'.5>746.'.'>.'267>27>7"3!2>54.#!#"3!2>54.#'32#!".54>;.54>7.>7>7"&".'.".'.>7>7>5"'&47%"'&4?#"'&4?#"'&4?#3"'&47'"'&4?%'762'762/762762"'&4?62"'.762"'&4762"'&462"'&47"'&4?"'&4?"'&47"'&47'7627627>62'62762/762          VU    * "(/2       B  C  O     #     " #      *0g&T1U.0,dtwrīK.ɬHgG~$~60>,!-%0  P"'  "  M  #')-,(        j    g         /.-+     '$!$'#  /' /.,Ldtzq7` . nh4~60`,ͧ"d =Q %.7@IWesY++ܸZиpк9иии01%"3!2654&#%"3!2654&#'267.>7>74."67>7>'.32#!".54>;.54>7.>7>7*&".'..'.>7>7>5:27>'4.'"7'7626262> 762762'762"'&47 "'&47"'&4?'"'&4?62"'&4?62"'&4?62"'&4762"'.#762"'&47#'762'762/762"'&4?3"'&4?"'&4?3"'&4?3"'&4?%"'&47%   )        ,     #     " #         +! ,><60H$~3gf. qrdt0,.1&*0   v   2 "#  (#       /.-+       '#" #'#    #G, 60D3g 5).Dp etb-.0' / '09BKT^lz5KT]fox)%+%+ + +0+:и:/ :9:9:9:9(:92:9A]A)9IYiy ]:9:9:9:9:9A&6FVfv ]A]9A%&%6%F%V%f%v%%%%%%% ]A%%]A00]A0)090I0Y0i0y0000000 ]T:9xиx/ox9A]A)9IYiy ]:9:9:9++ *+ KA+Kи/и(и1кB* 9Kܸи/и/ ܸиAиAи+ܸ@иܺT9901 "&'.467"'&47%"'&4?#"'&4?#"'&4?#3"'&47'"'&4?%'762'762/762762"'&4?62"'."&'.6?6.'.'#"&'32>'.'7232#!".54>;.54>;.5>7>7.54>32>"3!2>54.#%"3!2>54.#762'7>'62 6262%62"'&4762"'&4?62"'&4?62"'&42>54.#"?62'2?"'&47'"t*0g&T1U.0,dtwrī _    %8 #"""  aa   &Z  X&     j    F        kuF "F.     #1)f$u /' /.,Ldtzq7`  p  /i9"! !!  >n   51*       (07,)%!     v   h    Sut G}K߂F.    1)$fh '09BKT^lz$ú +( 9 9 9z 9 }иU+U+и/и(и1иUܺBU9ܸhܸ@и@/UJܸ_к`901 "&'.467"'&47%"'&4?#"'&4?#"'&4?#3"'&47'"'&4?%'762'762/762762"'&4?62"'.762'7>'62 6262%62"'&4762"'&4?62"'&4?62"'&4762'2?"'&47"3!2654&#%";2654&#'#"&'32626?232#!".54>;.54>;.5>7>7.54>32'"t*0g&T1U.0,dtwrīuF "F. 1)f    (    b  &Z  X&     $u /' /.,Ldtzq7` kut G}K߂F.1)$fh   q   #! n    51*       (07,)%!     +#,5@IR[dmv $(,048<@DHzZ+g+De+D>+:++n+n0+0O+Or+ro09o/ܺo9Znиn/ nO9кr9$nO95nO97и7/BnO9Jr9SnO9\nO9DEиE/jܺfEj9g9nO9nO9и/nO9nO9nO9 иикk:9k/ ܸe ܸкn9/ии!и#и%и'иvܸ)и,ܸ3и5и5/6и6/07иe9и<иFи HиvsA&6FVfv ]A]A]A)9IYiy ]O{B+{j++<9+< + +!"+!+к$ 95j9BJиBSиB\иBeкvB{9ик 99j9 и и ии<и/9иии!%и"&и9)и<*и*/-и.и1и2и"5и!6и=и?иAиCи"Eи!Gи9Jи9_иjnи{01#762'62'>'762'5762762727"'&47%"'&4?#"'&4?#"'&4?#3"'&47'"'&4?%'762#'762762"'.#762"'&4#762#762762'27 "'&47'"'&4?'"'&4?762"'&4?62"'&4!535##5##5#335'3535#35735#35'#7'#7'#7'#35735#735#735#2#!".54>37>75#53353353#"3!2>54.#21  ڽ.G *0g&T1U.0,dt r22*{2)A1AΫPUDDDCCwhhh"ee$eeqo$"_\wq*#e_+- FEFF   C  1_.m-s)3/G@M /' 0.-Met1p6e*)2C2UHThhhh.LLNNtLLLLMMMM[LLrLLrNNtMML'L&N&Mk:lhg5Ddddd"8hfjn   "159=AEInw&/8AJSaoߺ!+!?>+?;:+;('+(!9/">?9"/%ܺj:;9j/-ܸ*к2>?92/3ܸ26и37и:Bи;Cи>Fи?GиNܸSܸNWиS[иjaи-cиc/-nܸeкpj-9x'(9'(9'(9!9'(9:;9>?9!9!9>?9'"%91!9A!9(q!+]^+]@2+@KJ+K8:+8H6+H]`иܸи!%и]4и`5и@<и:>иJBиHDиJFиJMиHOи6Qи6Sи8Tи:Vи@Xи2Zи2bи@dи:fи8hи6jиHlиoкx6H9!9]и/`и/и'к16H9S!9012#!".54>37>75#53353353#%3#3#3#'3#3#'3#%5!3#;#3#3#!5#53'#53'#535#5#762'62'>'762'5762762727"'&47%"'&4?#"'&4?#"'&4?#3"'&47'"'&4?%'762#'762762"'.#762"'&4#762#762762'27 "'&47'"'&4?'"'&4?762"'&4?62"'&4,. FEFF hhhhFeeeeeeee#Dd#*os+$e^>21  ڽ.G *0g&T1U.0,dt r22*{2)A1AΫ:lhg5Ddddd"8hfjP-M"LLL+MMMM!!M#M"L"P''P"L"M#M)1_.m-s)3/G@M /' 0.-Met1p6e*)2C2UH$?CGKOcw"+4=HLU^gpyZ+Z+P+A&6FVfv ]A]@9B9D9F9H9N9APP]AP)P9PIPYPiPyPPPPPPP ]AZ&Z6ZFZVZfZvZZZZZZZ ]AZZ]_99959?9J9_9h9N+*+U+ ܸ иܸ>ܸи/ и 5и 6иUܸPиP/ZиZ/_U9>xиx/|ܺz|9U9и|кU9|9>и/U9кU9U9U9U9U9U9U9U95U9JU9KU9NVиN_иNhиNqк{U9U9N901"3!2>54.#'232#!".54>;.54>;?7?%77.#">7'"32>54.#".''.'#.'&'#32>7&>7.54>32>732>7762"'&4762"'&462"'&4"'&4?'"'&4?/2?'2?'62'762'762#7>2'3"'&47%"'&4?#"'&4?#"'&4?#3"'&47#62762"'&4??>2'7>2'762/762762"'&4?62"'.%!2>54.#!"4    VW  X1DEEDDEEBDEECFF((  "_    $"''  ! %   % "  "   x. ej - 1_w.*0g&T1U.0,3.et5awr ī"?     5    "    """0"""G"""""""&&             w '!      '   .4> !k.&Fa+v^ /' 0.-ethazp6 _ M     # )2;DMV_hqu~*?}+A&6FVfv ]A]j}9}9+}9z}9}9}9}9}9}9}9+S+wииик9ܸܸgܸ@иHиH/SIܸ^и^/I_01762"'&4762"'&462"'&4"'&4?/27'2?'2?'62'762'762'762'3"'&47%"'&4?#"'&4?#"'&4?#3"'&47#62762"'&4??>2'762'762#'762762"'&4?62"'.%"3!2654&#%"3!2654&#'#"&'3267>732>732#!".54>;.54>732>7&>7.54>327'7'7/7/32>727'.' . ej - 2dw.*0g&T1U.0,3.dt5awrīT  _ h |   "        % "  JLLJLLJLLJJLL    &# !'.4!! !k.&Ke+v^ /' 0.-etha{zp6_    z    !'       w   '!    '''''''R'''7'''V&   (e //01!53#g$eC""e+015!!eCge //013#5#53gC$g"C+//01!3D$g+//0133$C //0133#C$g"D+01!!Dg //01#535gg$fD"2 ' +  //+01%3+53#$$g""he++015!!!!hC" #+//+017#5#5#53$$gg""""eh3/++ ////01!3333gD"+++////013#3#3gg""21 '+ //+0153'33#$gg"""fh1++015!%5!1hh""1 # +//+01#5;#535$$$g"hfM%(3]h#'3`l)FR^bAD%+D.;+.++`_+`и/ %9'%D9@%9^и^/и/A&6FVfv ]A]и/_и/hиh/jиj/Dи/A&6FVfv ]A]+%9;2и2/;8и8/D?и?/%FиF/S9U9W%9Y%9[9]9j/l///  + +x+x9x9*x90x9 iиi/ и/*и*/+x9,и,/x.и./<x9x=и=/?x9xDиD/GиG/xPܸxQиQ/SиS/Ux9VиV/Wx9xYиY/[x9x\и\/]x9_и_/xaиa/Poиo/иxиPи/01'7.'.#.'./'#'?'?'77676'&'&'7>323.'.5&'&#"776765&'&#'763&'4&5.'&'&#72#&'&'&56767676"27674&'&7>56454&'&'&237''.'&'&7676767:76?"'.'.'.'&767'?'7'6'&'&'&7"&'&'&'&7476767>3276767'7'7727676''&'&'4767676#"&'&7"3276'4'&'&7767654''&'&'&767676#'&77676'.'&'&?.'.7>7%"32>54.'2#".54>'73#<5<5<5<?#'#5;#3#3#7373#'#?3#74'&'&#"3273#"'&'&'&54767676372#"'&'&546767>7>"327654'&'B4_ 6 C  _{X h70  !   52 # "      j        b   G * a )           ^Q    9   "I /v ,  ,,!!,2)U2**4W`&&##&&$T##w      A     Q(&&* '? 5 :   " t  #s       9 Q       6 64  I3 3      e;&   J2     N$    J#!+,!!,+!ZZ ^^ !###$$EL))LEZ  (  <     $   NK/7'.67>27>2"&/"&'.46      (    /:EPYbo| !/=26?267>4&/7>4&'."'."'7>2&'&6?/27"'&47/2?"&'.>?'267'267'67'27>/62764'&"'62'>'7>7>4&'."762"'.#762"'&4'62"'&4'762%62"'&4?62"'&4?62"'&4      +5)*=>DwrL8ʪz.[ . (     +56)62k<Dv's:-9}.Ey7KWmѸ//и/ܺ9999"A""]A")"9"I"Y"i"y""""""" ]-A-&-6-F-V-f-v------- ]A--]N9Q9sи"~к99999иO/y+yn+V8+VX+'+7 +7BиB/bии/иVии/01'7'7>77%>7>7>54.#!"7"32>54.'5'37'#5"3!2>54.#"3!2>54.#%.54>3.'.54>;.54>;232232#!".54>3PNPPEP J NDZ;        b;D;;4      C        j      '''I"'  '"          UE == E >>    f   $  &          %   Ey '5A9/+f(+f.+.и/Jܸ и /ܺ 9 9 9 9ܸ!ܸf?иBи(]и]/(oиo/]pиJии/01''7'7'"3!2654&#"3!2654&#";2654&#'5'37'#5.54>3.'.54>;.54>;232232#!".54>3"3!2654&#PNPPFNP V f    ;D;;4      j      F  '''#'CA 'F   e      wE == E >>  &          %     "a*3<ENR[dmv;//6и6/и/SܺS9#S9MS9lAll]Al)l9lIlYlilylllllll ]6wAw&w6wFwVwfwvwwwwwww ]Aww]S9S9S9и/wи/6и/6и/S9S9S9S9w4иwFиF/PS9]S9eS9loиo/vS9wS9S9S9wиlкS9Sи6кS9S9S9+++Nq+N<ܸ и /ܸиܸܸи/ܺ9#9'и'/N;иDи<Mиܺ999ииик9F<9P<9]<9e<9v<9ܸии01"32>54.>7'7>77#.'.54>;.54>;2327>7>54.#!"'7"&'.467"'&47%"'&4?#"'&4?#"'&4?#3"'&47'"'&4?%'762'762#'762762"'&4?62"'.762"'&4762"'&462"'&4"'&4?'"'&4?'"'&4?627#7762/76262'762'57627#762"3!2>54.#"3!2>54.#'232#!".54>;.54>373557#'  EP J ND!     j     "      >NPPY*0g&T1U.0,dtwrīK.-[m24mc& p/      C  R   y;4;;D;f  "'  '"  %          $       e'''? /' 0.-Metzp6_ .,6[o1nct |!0q3p+0O    f        >> E == % &/8AJS\enx )AO]o}uh(+hI5+Ip+h]ܸ^и^/ܸܸ]~иܺ^9^9^9^9&^9(0и(9и(Bи(Kк\(h9p9p9p9p9 p9 иh*иIAܸ+и+/h@и@/hBиB/*OиO/]PиP/h_ܸи/VܸhWܸ_]иpvܸpи/pи/01"3!2654&#7'7'''"&'.467"'&47%"'&4?#"'&4?#"'&4?#3"'&47'"'&4?%'762'762#'762762"'&4?62"'.762"'&4762"'&462"'&4"'&4?'"'&4?'"'&4?627#7762/76262'762'57627#76273557#'2#!".54>37"3!2654&#%"3!2654&#)6!.54>";2654&#!.'.54>;.54>;232#  PFN NPPY*0g&T1U.0,dtwrīK.-[m24mc& p/;4;;D;`      _ W     e     j        A '##'''' /' 0.-Metzp6_ .,6[o1nct |!0q3p+0 >> E == g       c       {   %          $f //01!#4>3"E% &D gf //0134.#52" & D& //013".5 % D&g //013#52>"E& &D 3+ + +ܸ 01!4>35"#4>3 %f !%( !f%($!7+и+ܸ013#52'52#4."" "(%!e&! _f!$(%34/++ܸ013".".53" "(%! f%! _f!$(%4; + и  +ܸ 01#52>53#" &e!%( !f%($!ZH / /012#".54>"<,,<""<,,<-;""<--<"";-& [ 2g>"(&u)*-1H588899969J9^9r999::0:X:x:@;@BDEJAM|MMMMN"N`NNNO<TSRQFZVXU[4321&:685;  #\<OP/0EWHJ%7(*.null   !!""##$$%%&&''(())**++,,--..//00112233445566778899::;;<<==>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~tagua-1.0-alpha2/data/themes/pieces/MayanTTF/theme_eboard.desktop000066400000000000000000000002531077523320400247250ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Maya (Eboard style) Type=Application Comment=Maya TTF theme.| by Armando H. Marroquin X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/MayanTTF/theme_eboard.lua000066400000000000000000000020211077523320400240300ustar00rootroot00000000000000import("piece_theme.lua") shadow = 7 shadow_color = "#404040" shadow_offset_x = 3 shadow_offset_y = 3 shadow_grow = 6 function fromGlyphGrad(fg, grad1, grad2) return function(glyph) return function(size) local g = LinearGradient(Point(0.3*size,0), Point(0.7*size,0)) g[0] = grad1 g[1] = grad2 return fromFontGlyph("Mayan.ttf", glyph, fg, g)(size) end end end fromGlyphW = fromGlyphGrad("black", "#737152", "#DEDEAC") fromGlyphB = fromGlyphGrad("black", "#5A3010", "#BD4820") theme.black_bishop = fromGlyphB("0x0062") theme.black_king = fromGlyphB("0x006B") theme.black_knight = fromGlyphB("0x006E") theme.black_pawn = fromGlyphB("0x0070") theme.black_queen = fromGlyphB("0x0071") theme.black_rook = fromGlyphB("0x0072") theme.white_bishop = fromGlyphW("0x0062") theme.white_king = fromGlyphW("0x006B") theme.white_knight = fromGlyphW("0x006E") theme.white_pawn = fromGlyphW("0x0070") theme.white_queen = fromGlyphW("0x0071") theme.white_rook = fromGlyphW("0x0072") tagua-1.0-alpha2/data/themes/pieces/MayanTTF/theme_jose.desktop000066400000000000000000000002511077523320400244270ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Maya (Jose style) Type=Application Comment=Maya TTF theme.| by Armando H. Marroquin X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/MayanTTF/theme_jose.lua000066400000000000000000000013331077523320400235410ustar00rootroot00000000000000import("piece_theme.lua") shadow = 7 shadow_color = "#404040" shadow_offset_x = 3 shadow_offset_y = 3 shadow_grow = 6 function fromGlyph(glyph) return fromFontGlyph("Mayan.ttf", glyph, "black", "white", 6.0) end theme.black_bishop = fromGlyph("0x0076") theme.black_king = fromGlyph("0x006C") theme.black_knight = fromGlyph("0x006D") theme.black_pawn = fromGlyph("0x006F") theme.black_queen = fromGlyph("0x0077") theme.black_rook = fromGlyph("0x0074") theme.white_bishop = fromGlyph("0x0062") theme.white_king = fromGlyph("0x006B") theme.white_knight = fromGlyph("0x006E") theme.white_pawn = fromGlyph("0x0070") theme.white_queen = fromGlyph("0x0071") theme.white_rook = fromGlyph("0x0072") tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/000077500000000000000000000000001077523320400205605ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/bb.svg000066400000000000000000000723461077523320400217000ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/bk.svg000066400000000000000000000721261077523320400217050ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/bn.svg000066400000000000000000001173351077523320400217120ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/bp.svg000066400000000000000000000604711077523320400217120ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/bq.svg000066400000000000000000000725131077523320400217130ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/br.svg000066400000000000000000000221051077523320400217040ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/theme.desktop000066400000000000000000000002351077523320400232550ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Prmi Type=Application Comment=Prmi (cats) SVG theme,| by Maurizio Monge X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/theme.lua000066400000000000000000000011041077523320400223610ustar00rootroot00000000000000import("piece_theme.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 theme.black_bishop = fromSVG("bb.svg") theme.black_king = fromSVG("bk.svg") theme.black_knight = fromSVG("bn.svg") theme.black_pawn = fromSVG("bp.svg") theme.black_queen = fromSVG("bq.svg") theme.black_rook = fromSVG("br.svg") theme.white_bishop = fromSVG("wb.svg") theme.white_king = fromSVG("wk.svg") theme.white_knight = fromSVG("wn.svg") theme.white_pawn = fromSVG("wp.svg") theme.white_queen = fromSVG("wq.svg") theme.white_rook = fromSVG("wr.svg") tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/wb.svg000066400000000000000000000716121077523320400217200ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/wk.svg000066400000000000000000000724571077523320400217410ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/wn.svg000066400000000000000000001217441077523320400217360ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/wp.svg000066400000000000000000000604661077523320400217430ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/wq.svg000066400000000000000000000720051077523320400217340ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/PrmiSVG/wr.svg000066400000000000000000000221071077523320400217330ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/ShogiSVG-TTF/000077500000000000000000000000001077523320400213555ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/ShogiSVG-TTF/Shogi.sfd000066400000000000000000000731031077523320400231300ustar00rootroot00000000000000SplineFontDB: 1.0 FontName: Shogi FullName: Shogi FamilyName: Shogi Weight: Medium Copyright: Created by Io with FontForge 1.0 (http://fontforge.sf.net) Comments: 2006-10-6: Created. Version: 001.000 ItalicAngle: 0 UnderlinePosition: -100 UnderlineWidth: 50 Ascent: 816 Descent: 208 NeedsXUIDChange: 1 XUID: [1021 306 260876167 15891889] FSType: 8 OS2Version: 0 OS2_WeightWidthSlopeOnly: 0 OS2_UseTypoMetrics: 0 CreationTime: 1160099864 ModificationTime: 1160353221 PfmFamily: 17 TTFWeight: 500 TTFWidth: 5 LineGap: 92 VLineGap: 0 OS2TypoAscent: 0 OS2TypoAOffset: 1 OS2TypoDescent: 0 OS2TypoDOffset: 1 OS2TypoLinegap: 92 OS2WinAscent: 0 OS2WinAOffset: 1 OS2WinDescent: 0 OS2WinDOffset: 1 HheadAscent: 0 HheadAOffset: 1 HheadDescent: 0 HheadDOffset: 1 OS2Vendor: 'PfEd' TtfTable: cvt 4 !$VK# EndTtf LangName: 1033 Encoding: UnicodeBmp UnicodeInterp: none NameList: Adobe Glyph List DisplaySize: -48 AntiAlias: 1 FitToEm: 1 WinInfo: 34 17 10 TeXData: 1 0 0 346030 173015 115343 0 1048576 115343 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144 BeginChars: 65536 16 StartChar: p Encoding: 112 112 0 Width: 1024 Flags: W TeX: 112 0 0 0 Fore 496 656 m 0 496 656 528 656 528 640 c 0 528 640 528 624 528 608 c 0 528 592 528 576 560 576 c 0 576 576 592 592 592 592 c 0 608 608 640 592 640 576 c 0 640 560 624 560 576 560 c 0 544 544 528 544 528 544 c 0 544 512 608 512 640 528 c 0 688 528 l 0 704 496 688 480 656 480 c 2 624 480 l 1 656 448 l 2 688 432 688 416 672 400 c 0 656 400 640 400 640 416 c 0 624 448 624 448 624 432 c 0 624 384 480 304 400 304 c 0 368 304 384 320 432 336 c 0 480 352 480 352 464 368 c 0 448 368 448 400 480 400 c 0 496 400 496 400 496 448 c 0 480 480 480 480 464 496 c 0 432 496 432 496 448 480 c 0 464 464 464 464 448 448 c 0 416 416 352 368 352 368 c 0 336 368 336 400 352 416 c 0 368 416 384 448 400 464 c 2 416 496 l 1 400 496 l 2 352 480 336 496 336 512 c 0 352 512 368 528 368 528 c 0 400 528 400 528 400 576 c 0 400 624 400 624 432 624 c 0 448 608 448 608 448 560 c 0 432 528 432 528 464 528 c 0 496 528 496 528 496 576 c 0 496 608 496 640 496 656 c 0 592 464 m 0 592 480 576 480 560 480 c 0 544 480 528 480 528 432 c 2 528 384 l 1 560 416 l 2 576 432 592 448 592 448 c 0 608 448 592 448 592 464 c 0 448 224 m 0 448 256 480 256 496 224 c 0 496 224 496 208 496 192 c 0 480 176 480 176 480 160 c 0 496 160 544 176 592 192 c 0 608 192 624 192 624 176 c 0 656 160 656 160 624 160 c 0 576 144 576 144 592 96 c 0 608 80 608 64 656 64 c 0 720 64 752 48 736 32 c 0 720 16 704 16 656 32 c 0 592 48 576 48 496 48 c 0 336 16 336 16 320 48 c 0 288 64 288 80 320 64 c 0 336 64 368 64 384 64 c 0 416 64 432 64 432 112 c 2 432 160 l 1 400 144 l 2 352 144 352 160 400 176 c 0 448 224 l 0 544 128 m 0 496 160 448 144 464 96 c 0 464 64 528 64 544 96 c 0 560 112 560 112 544 128 c 0 416 0 m 0 416 16 448 16 448 0 c 0 448 0 448 0 464 -16 c 0 464 -32 448 -32 416 -48 c 0 368 -80 320 -80 320 -64 c 0 320 -64 336 -48 368 -32 c 0 384 -32 400 -16 416 0 c 0 560 0 m 0 560 16 608 16 624 0 c 0 656 -16 672 -64 640 -64 c 0 624 -64 560 -16 560 0 c 0 EndSplineSet EndChar StartChar: g Encoding: 103 103 1 Width: 1024 Flags: W TeX: 103 0 0 0 Fore 448 624 m 0 480 656 496 672 496 672 c 0 512 672 528 656 544 624 c 0 576 592 608 576 624 560 c 0 688 544 704 528 688 512 c 0 672 496 640 496 608 528 c 0 592 544 576 544 576 528 c 0 560 528 544 528 544 528 c 0 528 528 528 512 528 512 c 0 528 496 560 480 576 496 c 0 592 512 608 512 608 512 c 0 624 496 624 464 608 464 c 0 608 448 l 0 608 432 592 400 576 384 c 2 544 352 l 1 576 352 l 2 592 352 608 368 608 368 c 0 624 384 656 368 656 336 c 0 656 336 624 320 512 320 c 0 384 320 352 336 352 336 c 0 352 352 368 352 400 352 c 2 432 352 l 1 416 400 l 2 416 416 416 448 416 448 c 0 432 464 464 400 464 384 c 0 448 368 464 352 480 352 c 0 496 352 496 368 496 416 c 2 496 464 l 1 448 464 l 2 416 464 400 464 384 464 c 0 368 480 400 496 448 496 c 0 480 496 496 496 496 512 c 0 496 512 480 528 464 528 c 0 448 528 432 528 432 528 c 0 432 544 416 528 400 512 c 0 384 512 368 496 352 496 c 0 320 480 320 496 368 544 c 0 400 560 432 608 448 624 c 0 544 560 m 0 560 576 544 592 528 592 c 2 512 624 l 1 464 592 l 1 432 544 l 1 496 560 l 2 512 560 544 560 544 560 c 0 560 416 m 2 576 464 l 1 544 464 l 2 528 464 528 464 528 416 c 0 528 384 528 352 528 352 c 0 528 352 544 384 560 416 c 2 544 288 m 0 624 304 656 304 656 288 c 0 672 272 640 256 592 256 c 0 560 256 528 240 528 224 c 0 528 224 544 208 560 208 c 0 576 192 592 192 624 208 c 0 656 224 656 224 672 208 c 0 704 192 704 160 688 144 c 0 656 144 672 128 720 112 c 0 784 96 800 64 752 64 c 0 736 64 720 48 720 16 c 0 720 -16 720 -32 704 -48 c 2 688 -80 l 1 656 -64 l 2 608 -32 608 -16 640 -16 c 0 672 -16 672 -16 672 32 c 2 672 80 l 1 640 80 l 2 624 80 576 80 544 64 c 0 480 48 464 48 448 64 c 0 448 64 432 80 448 80 c 0 448 80 592 112 624 112 c 0 624 112 640 112 640 128 c 0 640 128 640 128 608 128 c 0 560 128 560 128 576 144 c 0 592 160 576 176 528 176 c 0 496 160 480 176 512 224 c 0 512 272 l 0 512 288 528 288 544 288 c 0 368 272 m 0 384 288 400 272 416 256 c 0 432 240 432 240 416 160 c 0 416 112 400 64 400 32 c 0 400 0 384 -48 368 -48 c 0 352 -48 336 -32 336 -16 c 0 320 0 304 0 288 0 c 0 272 0 272 16 272 48 c 0 288 64 288 80 272 96 c 0 240 112 256 128 288 112 c 0 320 112 384 128 384 144 c 0 384 160 368 160 352 160 c 0 304 144 304 144 288 160 c 0 256 160 256 192 288 192 c 0 304 192 304 192 304 224 c 0 304 256 304 272 320 272 c 0 336 272 352 240 336 224 c 0 336 192 336 192 368 192 c 0 384 192 384 192 384 224 c 0 384 240 384 240 384 256 c 0 368 256 368 256 368 272 c 0 368 64 m 0 368 80 368 96 352 96 c 0 320 96 320 80 320 48 c 0 320 16 320 16 336 16 c 0 352 0 368 32 368 64 c 0 544 48 m 0 544 64 592 32 592 16 c 0 592 0 512 -32 496 -32 c 0 496 -16 496 -16 512 0 c 0 528 16 544 32 544 48 c 0 EndSplineSet EndChar StartChar: k Encoding: 107 107 2 Width: 1024 Flags: W TeX: 107 0 0 0 Fore 592 640 m 0 608 656 624 640 640 624 c 0 672 608 656 592 576 592 c 2 528 592 l 1 528 544 l 1 528 512 l 1 576 512 l 2 624 528 640 512 640 496 c 0 640 480 624 480 576 480 c 2 528 480 l 1 528 432 l 1 528 368 l 1 576 368 l 2 608 368 640 368 640 384 c 0 672 384 688 368 688 336 c 0 672 336 656 320 528 320 c 0 368 320 320 336 336 352 c 0 336 368 368 368 416 368 c 2 496 368 l 1 496 432 l 1 496 480 l 1 448 480 l 2 400 480 368 480 368 496 c 0 384 512 400 512 432 512 c 2 496 512 l 1 496 544 l 1 480 592 l 1 432 592 l 2 368 608 352 608 368 624 c 0 368 640 400 640 480 624 c 0 544 624 592 624 592 640 c 0 560 464 m 0 560 480 576 480 608 448 c 0 640 416 640 400 608 400 c 0 592 400 560 448 560 464 c 0 608 304 m 0 624 304 624 304 624 304 c 1 640 304 672 288 672 288 c 0 672 272 656 272 624 272 c 0 592 272 560 256 560 224 c 0 560 224 560 208 592 224 c 0 640 224 688 208 672 192 c 0 656 176 544 128 544 144 c 0 544 144 l 0 560 160 576 160 592 176 c 0 608 192 608 192 560 192 c 0 544 192 528 192 512 176 c 0 496 176 480 176 480 192 c 0 480 192 496 208 512 224 c 0 528 240 528 256 528 272 c 0 528 288 528 288 560 288 c 0 576 288 592 288 608 304 c 0 400 256 m 0 400 304 400 304 416 288 c 0 432 272 448 256 448 256 c 0 448 256 432 208 432 176 c 0 400 16 400 0 384 0 c 0 368 -16 368 -16 352 0 c 0 320 32 320 48 352 32 c 0 368 32 368 32 384 64 c 0 384 96 384 128 384 144 c 2 400 192 l 1 352 192 l 2 320 192 304 192 304 192 c 0 288 208 288 208 320 208 c 0 336 208 336 224 336 240 c 0 336 256 336 272 336 272 c 0 368 288 368 272 368 240 c 0 368 192 400 208 400 256 c 0 272 144 m 0 272 160 352 160 368 144 c 0 368 144 368 128 352 128 c 0 352 128 336 112 336 96 c 0 336 80 304 32 288 48 c 0 272 64 272 64 288 80 c 0 304 112 304 112 288 128 c 0 272 128 272 144 272 144 c 0 640 144 m 0 656 144 l 0 672 144 688 144 704 128 c 0 736 128 752 128 752 112 c 0 752 96 752 96 720 96 c 2 688 96 l 1 704 32 l 2 704 -32 688 -48 624 -32 c 0 592 0 576 16 624 0 c 2 656 0 l 1 656 48 l 2 656 96 656 96 640 96 c 0 624 96 592 96 592 96 c 0 576 96 560 80 576 64 c 0 576 64 576 48 544 32 c 0 496 -16 464 0 512 48 c 2 544 80 l 1 512 80 l 2 480 80 464 80 448 96 c 0 432 112 432 112 528 112 c 0 592 128 624 128 640 144 c 0 EndSplineSet EndChar StartChar: l Encoding: 108 108 3 Width: 1024 Flags: W TeX: 108 0 0 0 Fore 512 624 m 0 528 624 560 640 560 640 c 0 576 640 608 592 592 592 c 0 592 592 576 576 544 576 c 0 528 576 512 576 512 560 c 0 512 544 528 544 624 576 c 0 656 576 656 576 656 560 c 0 672 528 656 528 592 528 c 0 544 528 544 512 608 496 c 0 640 480 672 480 672 464 c 0 672 464 640 432 624 432 c 0 608 432 608 432 608 432 c 0 608 416 608 384 592 352 c 0 592 320 576 288 576 288 c 0 560 288 l 0 560 304 432 304 432 304 c 0 416 288 416 288 400 288 c 0 400 288 384 304 384 368 c 2 384 448 l 1 432 448 l 1 480 432 l 1 480 464 l 2 464 480 464 496 464 496 c 0 464 496 432 480 400 464 c 0 368 448 336 432 336 432 c 0 320 448 336 464 368 480 c 0 384 496 416 512 432 512 c 0 448 528 448 528 384 528 c 0 352 528 336 528 336 544 c 0 336 560 352 560 400 560 c 0 448 560 464 560 464 560 c 0 464 576 448 576 416 576 c 0 368 576 352 576 352 592 c 0 352 608 368 608 400 608 c 0 432 608 480 608 512 624 c 0 576 448 m 0 576 448 560 464 544 480 c 0 512 512 512 512 512 496 c 0 512 480 512 464 512 464 c 0 496 448 512 448 528 448 c 0 560 448 576 448 576 448 c 0 560 400 m 0 560 400 528 416 496 416 c 0 464 416 432 400 432 400 c 0 432 400 464 384 496 384 c 0 544 384 560 400 560 400 c 0 560 352 m 0 560 352 528 352 496 352 c 0 464 352 432 352 432 352 c 0 432 336 464 336 496 336 c 0 528 336 560 336 560 352 c 0 480 256 m 0 464 288 496 288 528 256 c 0 544 240 560 240 576 240 c 0 592 240 592 224 592 224 c 0 592 208 576 208 560 208 c 0 528 208 512 208 512 192 c 0 512 192 528 192 560 192 c 0 576 192 608 176 624 176 c 2 640 160 l 1 624 112 l 2 592 48 592 48 640 48 c 0 688 48 736 16 704 0 c 0 704 -16 688 0 640 0 c 0 544 32 512 32 496 -16 c 0 480 -48 464 -48 464 0 c 0 464 32 448 32 384 0 c 0 336 -16 320 -16 304 16 c 0 272 32 272 32 288 48 c 0 304 48 320 48 320 48 c 0 336 32 352 32 352 32 c 0 368 48 368 112 352 144 c 0 352 176 352 176 368 176 c 0 416 160 464 176 464 192 c 0 464 208 464 208 448 208 c 0 416 208 384 208 384 224 c 0 384 224 416 224 432 224 c 0 480 224 480 240 480 256 c 0 592 144 m 0 576 160 512 176 512 160 c 0 512 144 528 144 528 144 c 0 560 144 560 112 528 112 c 0 496 112 496 96 528 96 c 0 528 96 544 96 544 80 c 0 528 64 l 0 480 48 496 32 544 48 c 0 576 48 576 48 592 80 c 0 592 112 592 128 592 144 c 0 464 144 m 0 464 160 432 160 432 144 c 0 416 144 416 128 416 128 c 0 432 112 464 128 464 144 c 0 464 96 m 0 448 112 416 112 400 96 c 0 384 64 400 48 432 48 c 0 464 48 480 64 448 64 c 2 432 80 l 1 448 80 l 2 464 96 464 96 464 96 c 0 EndSplineSet EndChar StartChar: h Encoding: 104 104 4 Width: 1024 Flags: W TeX: 104 0 0 0 Fore 400 640 m 0 432 656 432 640 432 608 c 0 432 576 432 560 464 576 c 0 512 576 l 0 544 576 544 576 544 592 c 0 528 608 544 624 544 624 c 0 560 656 576 624 576 592 c 0 576 576 576 576 608 576 c 0 656 576 656 576 656 560 c 0 656 560 640 544 624 544 c 0 576 544 576 544 576 512 c 0 576 496 608 480 640 496 c 0 656 512 656 512 672 496 c 0 688 480 688 480 672 464 c 0 672 464 640 464 624 464 c 0 576 464 576 464 576 448 c 0 576 416 608 416 624 432 c 0 624 432 640 432 656 432 c 0 672 400 656 384 608 384 c 0 576 384 576 384 576 368 c 0 576 336 608 336 640 352 c 0 688 352 l 0 720 320 672 304 544 304 c 0 448 304 432 304 448 320 c 0 448 336 448 336 496 336 c 0 544 336 544 336 544 368 c 0 544 384 544 384 496 384 c 0 464 384 464 400 464 400 c 0 464 416 480 416 512 416 c 0 544 416 544 416 544 448 c 0 544 464 528 464 512 464 c 0 496 464 480 448 480 448 c 0 464 432 464 432 448 448 c 0 432 464 432 464 432 400 c 0 432 320 416 288 400 320 c 0 400 320 400 352 400 384 c 2 400 448 l 1 384 416 l 2 368 400 352 384 336 384 c 0 320 384 320 400 352 448 c 0 368 480 384 512 384 512 c 0 384 512 384 528 368 528 c 0 336 528 336 560 368 560 c 0 384 560 400 560 384 592 c 0 384 608 400 624 400 640 c 0 544 512 m 0 544 528 544 544 512 544 c 0 496 544 480 544 480 544 c 0 480 544 464 528 448 528 c 0 432 528 416 512 448 496 c 0 448 480 464 480 464 496 c 0 464 496 480 496 512 496 c 0 528 496 544 496 544 512 c 0 608 272 m 0 624 288 640 288 656 272 c 0 656 240 640 240 576 240 c 0 560 240 528 224 528 224 c 0 528 224 544 208 576 224 c 0 624 224 624 224 624 208 c 0 624 192 624 192 576 192 c 0 544 192 528 176 528 160 c 0 528 160 544 160 592 160 c 0 624 160 640 160 640 144 c 0 624 128 624 128 576 128 c 0 512 112 528 96 592 96 c 0 672 112 688 96 672 32 c 0 640 -48 608 -80 576 -48 c 0 544 -16 544 0 576 -16 c 0 608 -16 624 -16 624 0 c 0 624 0 l 0 608 -16 560 32 560 48 c 0 560 64 592 64 608 32 c 2 640 16 l 1 640 48 l 1 640 64 l 1 544 64 l 2 480 64 448 64 432 64 c 0 432 64 448 48 464 32 c 0 480 16 496 -32 464 -32 c 0 464 -32 448 -16 432 16 c 0 416 32 416 48 400 48 c 0 400 48 400 96 400 160 c 2 400 272 l 1 496 272 l 2 576 272 608 272 608 272 c 0 496 224 m 0 496 224 480 240 464 240 c 0 448 240 432 224 432 224 c 0 432 224 448 208 464 208 c 0 496 208 496 224 496 224 c 0 496 176 m 0 496 176 496 192 464 192 c 0 448 192 432 176 432 176 c 0 432 160 448 160 464 160 c 0 496 160 496 160 496 176 c 0 496 128 m 0 496 144 448 144 432 128 c 0 432 112 432 112 448 96 c 0 480 96 512 112 496 128 c 0 368 32 m 0 384 64 384 64 384 48 c 0 400 16 384 -32 368 -32 c 0 352 -48 352 -16 368 32 c 0 496 48 m 0 496 64 528 64 544 32 c 0 560 16 560 -16 528 -16 c 0 528 -16 496 32 496 48 c 0 EndSplineSet EndChar StartChar: B Encoding: 66 66 5 Width: 1024 Flags: W TeX: 66 0 0 0 Fore 528 624 m 0 512 624 512 640 544 640 c 0 576 640 592 624 576 592 c 0 560 560 576 560 608 560 c 0 640 576 640 544 592 528 c 0 560 512 560 496 576 480 c 0 576 480 576 464 576 448 c 0 576 432 592 416 608 400 c 2 640 384 l 1 608 336 l 2 576 288 544 272 528 304 c 0 512 320 512 336 528 320 c 0 560 320 576 352 576 368 c 0 576 400 576 400 560 400 c 0 512 400 512 416 528 432 c 0 544 464 544 464 528 464 c 0 512 464 448 416 448 384 c 0 448 368 416 320 416 320 c 0 400 320 400 336 384 336 c 0 384 352 384 352 384 368 c 0 400 384 400 400 384 400 c 0 368 416 352 400 336 352 c 0 336 320 320 304 320 304 c 0 288 304 288 352 320 384 c 0 336 416 336 432 320 448 c 0 288 448 304 464 320 464 c 0 336 464 352 480 368 496 c 0 384 512 384 512 352 544 c 0 304 576 304 576 336 576 c 0 352 576 368 592 384 608 c 0 400 624 432 624 448 608 c 0 464 592 464 592 432 576 c 0 416 560 416 560 416 544 c 0 416 528 432 512 432 512 c 0 464 512 448 496 432 480 c 0 400 464 384 448 400 432 c 0 400 416 416 416 480 480 c 0 528 512 528 528 528 560 c 0 528 592 528 608 528 624 c 0 656 544 m 2 656 592 672 592 704 576 c 0 736 560 736 544 688 528 c 2 656 512 l 1 656 544 l 2 448 240 m 0 512 240 608 240 624 240 c 0 624 224 608 224 576 208 c 0 544 192 544 192 544 192 c 0 544 224 512 224 448 192 c 2 400 176 l 1 368 208 l 1 336 240 l 1 384 240 l 2 400 224 432 224 448 240 c 0 448 160 m 0 448 160 544 160 560 160 c 0 560 144 544 144 528 128 c 0 480 112 480 96 544 112 c 0 608 112 640 80 640 48 c 0 640 16 576 -64 544 -64 c 0 448 -96 320 -48 352 16 c 0 368 32 400 48 416 48 c 0 464 32 480 0 480 -16 c 0 464 -32 512 -32 560 -16 c 0 608 16 608 32 576 64 c 0 560 80 544 80 496 80 c 0 432 64 416 80 448 112 c 0 464 128 464 128 448 144 c 0 448 144 448 144 448 160 c 0 432 0 m 0 416 16 384 16 384 0 c 0 384 -16 400 -48 416 -48 c 0 448 -48 448 -16 432 0 c 0 EndSplineSet EndChar StartChar: s Encoding: 115 115 6 Width: 1024 Flags: W TeX: 115 0 0 0 Fore 384 576 m 0 400 608 432 640 432 640 c 0 432 640 448 624 464 608 c 0 496 576 496 576 496 560 c 0 480 544 480 560 464 560 c 0 432 592 432 592 416 560 c 2 400 528 l 1 448 528 l 2 480 544 480 528 480 528 c 0 480 512 480 512 464 496 c 0 448 496 448 496 448 496 c 0 448 480 464 480 480 496 c 0 480 496 480 496 496 496 c 0 512 480 512 496 512 544 c 2 512 624 l 1 576 624 l 1 656 624 l 1 640 544 l 2 640 480 640 464 656 448 c 0 672 448 672 432 656 416 c 2 624 384 l 1 656 368 l 2 688 352 688 336 688 336 c 0 672 320 656 320 624 336 c 2 608 352 l 1 544 336 l 2 480 304 464 304 464 320 c 0 464 352 464 352 432 336 c 0 368 320 352 320 352 336 c 0 336 352 352 352 384 352 c 0 416 352 416 368 416 400 c 0 416 448 400 448 400 448 c 0 384 448 384 448 384 432 c 0 400 416 400 384 384 384 c 0 368 384 352 416 352 448 c 0 352 464 352 480 352 480 c 0 336 496 336 496 352 512 c 0 352 512 368 544 384 576 c 0 608 576 m 0 608 576 592 576 576 576 c 0 560 576 544 576 544 576 c 0 544 576 560 560 576 560 c 0 592 560 608 576 608 576 c 0 608 512 m 0 608 528 608 528 576 528 c 0 560 528 544 528 544 512 c 0 544 512 560 496 576 496 c 0 608 496 608 512 608 512 c 0 416 496 m 0 416 496 400 512 384 512 c 0 368 496 368 480 384 480 c 0 400 480 416 480 416 496 c 0 576 448 m 0 560 496 544 480 544 416 c 0 544 368 544 368 560 368 c 0 592 368 592 384 592 400 c 0 576 416 576 432 576 448 c 0 624 464 m 0 592 480 592 480 592 448 c 0 592 416 608 416 624 448 c 0 624 464 l 0 496 352 m 0 512 368 512 384 512 416 c 0 512 448 512 464 496 448 c 0 496 432 496 416 480 400 c 0 480 384 480 384 480 368 c 0 496 368 496 368 496 352 c 0 496 352 l 0 464 432 m 0 464 448 464 448 448 448 c 0 448 448 448 448 448 432 c 0 448 416 448 416 448 416 c 0 448 416 448 416 464 432 c 0 400 272 m 0 400 272 416 272 416 256 c 0 432 240 448 240 464 256 c 0 496 256 624 256 656 256 c 0 672 240 688 240 688 224 c 0 704 208 656 176 640 176 c 0 608 176 544 160 544 144 c 0 544 128 624 128 656 144 c 0 672 160 672 160 688 160 c 0 688 144 720 144 736 144 c 0 768 144 768 144 768 128 c 0 768 112 752 112 736 112 c 0 704 96 704 96 704 48 c 0 704 0 688 -48 656 -48 c 0 656 -32 640 -32 624 -16 c 2 592 16 l 1 624 16 l 2 656 16 656 16 656 32 c 0 672 48 672 64 656 80 c 0 656 96 656 112 624 112 c 0 592 112 576 112 560 96 c 0 544 96 544 96 560 80 c 0 592 48 592 32 544 16 c 0 496 0 496 16 528 32 c 0 544 64 544 96 528 96 c 0 512 80 464 96 464 112 c 0 464 112 480 128 496 128 c 0 512 128 544 176 528 192 c 0 512 208 512 224 528 224 c 0 528 256 528 256 496 240 c 0 448 208 432 176 432 128 c 0 432 32 416 -16 384 -16 c 0 368 -16 352 0 336 16 c 0 320 32 320 32 304 16 c 0 288 0 256 0 256 32 c 0 256 32 256 48 272 48 c 0 272 64 288 80 288 96 c 0 288 144 304 160 336 144 c 0 352 144 368 144 384 160 c 0 416 192 416 192 400 224 c 0 400 256 400 272 400 272 c 0 624 224 m 0 624 240 576 240 560 224 c 0 544 224 560 192 576 192 c 0 592 176 640 208 624 224 c 0 384 80 m 0 384 112 384 128 352 96 c 0 336 64 336 32 368 32 c 0 384 32 384 48 384 80 c 0 EndSplineSet EndChar StartChar: r Encoding: 114 114 7 Width: 1024 Flags: W TeX: 114 0 0 0 Fore 544 672 m 0 560 688 592 656 576 624 c 0 576 608 576 608 592 640 c 0 608 656 624 672 624 672 c 0 640 672 656 640 640 624 c 0 624 624 624 608 656 592 c 0 688 560 704 512 672 512 c 0 656 496 640 496 640 480 c 0 624 464 624 464 656 432 c 0 672 416 688 400 688 368 c 0 688 336 688 336 656 336 c 0 608 336 576 384 544 448 c 0 528 512 512 512 512 416 c 0 512 336 496 320 496 320 c 0 480 320 480 336 480 416 c 0 480 480 480 496 464 496 c 0 448 496 448 496 432 464 c 0 432 400 368 336 352 336 c 0 336 352 352 368 368 400 c 0 384 416 400 448 400 464 c 2 416 496 l 1 368 496 l 2 320 496 320 528 368 528 c 0 400 528 416 544 416 544 c 0 416 544 400 544 368 544 c 0 352 544 336 544 336 544 c 0 336 560 432 608 464 624 c 0 464 624 448 624 432 624 c 0 384 624 368 640 368 640 c 0 368 656 384 656 464 656 c 0 496 656 544 672 544 672 c 0 544 592 m 0 528 640 512 640 512 576 c 0 512 528 512 528 544 528 c 0 576 544 592 528 576 496 c 2 576 464 l 1 592 480 l 1 624 512 l 1 592 544 l 2 576 544 560 576 544 592 c 0 640 544 m 0 640 544 624 560 608 576 c 2 576 592 l 1 608 560 l 2 624 544 640 544 640 544 c 0 464 544 m 0 464 560 464 576 448 576 c 0 448 576 448 560 448 544 c 0 448 528 448 528 448 528 c 0 464 528 464 528 464 544 c 0 624 416 m 0 608 432 592 448 592 448 c 0 576 448 608 400 624 384 c 0 656 368 656 384 624 416 c 0 480 272 m 0 496 288 544 272 544 240 c 0 544 224 560 224 576 224 c 0 608 240 640 224 640 192 c 0 640 192 640 192 592 192 c 0 544 192 544 192 544 176 c 0 544 160 560 160 608 160 c 0 656 160 672 160 688 144 c 2 704 112 l 1 688 64 l 2 672 32 656 16 656 0 c 0 704 0 l 0 736 0 768 -32 752 -48 c 0 736 -48 720 -48 688 -48 c 0 656 -32 608 -32 576 -32 c 2 528 -16 l 1 528 -64 l 2 512 -112 496 -112 480 -64 c 0 480 -32 464 -16 368 -48 c 0 320 -64 320 -64 288 -32 c 0 272 -32 272 -16 272 -16 c 0 272 -16 304 0 320 -16 c 0 400 -16 400 0 368 80 c 0 352 96 352 128 352 144 c 0 352 144 368 144 416 144 c 0 480 144 512 160 496 176 c 0 496 192 480 192 448 176 c 0 416 176 416 176 400 192 c 2 368 208 l 1 432 208 l 2 496 208 512 224 496 256 c 0 480 272 480 272 480 272 c 0 496 112 m 0 496 128 480 128 448 128 c 0 400 112 400 96 448 96 c 0 480 96 496 96 496 112 c 0 640 80 m 2 656 128 l 1 592 128 l 2 576 128 544 128 544 128 c 0 528 112 528 96 560 96 c 0 608 96 608 64 576 64 c 0 544 64 528 64 528 64 c 0 528 64 544 48 576 48 c 0 592 48 608 48 608 32 c 0 608 32 592 16 576 16 c 0 560 32 544 16 528 16 c 0 528 0 624 0 624 16 c 0 640 16 640 48 640 80 c 2 496 64 m 0 496 64 480 64 448 64 c 0 416 64 416 64 416 48 c 0 416 48 416 48 432 48 c 0 464 48 512 64 496 64 c 0 496 16 m 0 496 16 416 32 416 16 c 0 400 16 416 0 448 0 c 0 480 0 496 0 496 16 c 0 EndSplineSet EndChar StartChar: b Encoding: 98 98 8 Width: 1024 Flags: W TeX: 98 0 0 0 Fore 448 640 m 0 464 672 512 688 512 656 c 0 496 640 528 624 576 640 c 0 576 656 592 640 592 640 c 0 608 624 608 608 576 592 c 2 560 576 l 1 608 576 l 1 672 576 l 1 672 464 l 2 672 352 656 336 640 320 c 0 624 304 624 304 592 320 c 0 560 336 560 352 592 352 c 0 624 352 624 368 624 384 c 0 624 400 624 416 592 416 c 0 480 416 464 416 416 368 c 0 368 320 352 304 352 320 c 0 352 336 368 352 384 368 c 0 400 400 416 416 416 480 c 0 416 528 400 544 384 528 c 0 368 512 368 512 368 528 c 0 368 528 368 544 400 576 c 0 416 592 432 624 448 640 c 0 528 592 m 0 544 608 544 608 512 608 c 0 464 608 448 592 448 576 c 0 448 560 512 576 528 592 c 0 528 528 m 0 512 560 448 560 448 528 c 0 448 512 464 512 480 512 c 0 512 512 528 512 528 528 c 0 624 528 m 0 624 544 608 544 592 544 c 0 560 544 560 544 560 528 c 0 560 512 560 512 592 512 c 0 608 512 624 512 624 528 c 0 528 464 m 0 528 480 512 480 496 480 c 0 464 480 448 480 448 448 c 0 448 432 512 448 528 464 c 0 624 464 m 0 624 464 608 480 592 480 c 0 560 480 544 480 560 464 c 0 560 448 576 448 592 448 c 0 624 432 624 448 624 464 c 0 368 256 m 0 368 288 384 288 400 256 c 0 416 240 416 240 384 224 c 0 368 192 368 192 384 144 c 0 400 144 400 128 368 96 c 0 336 64 336 64 352 32 c 0 368 16 368 -32 352 -64 c 0 336 -96 320 -80 320 -16 c 0 320 32 320 32 288 16 c 0 272 16 256 16 256 16 c 0 240 32 240 32 336 112 c 0 368 144 368 160 320 160 c 0 288 160 288 176 320 208 c 0 368 256 l 0 576 240 m 0 640 256 688 256 688 240 c 0 688 208 560 176 512 208 c 0 496 224 496 240 512 224 c 0 528 224 544 224 576 240 c 0 624 160 m 0 736 176 720 176 752 160 c 0 768 160 784 144 784 144 c 0 784 128 752 128 704 112 c 0 656 112 592 112 560 112 c 0 496 96 480 96 464 128 c 2 448 144 l 1 496 144 l 2 528 128 576 144 624 160 c 0 688 32 m 2 672 96 672 96 688 96 c 0 704 96 736 32 736 -16 c 0 736 -32 736 -64 720 -64 c 2 704 -96 l 1 640 -64 l 2 592 -48 592 -32 640 -32 c 2 688 -32 l 1 688 32 l 2 EndSplineSet EndChar StartChar: R Encoding: 82 82 9 Width: 1024 Flags: W TeX: 82 0 0 0 Fore 528 640 m 0 528 656 528 656 560 640 c 0 576 624 592 608 576 592 c 0 576 560 576 560 608 560 c 0 656 544 656 512 624 496 c 0 560 480 528 432 576 400 c 0 576 384 576 384 576 368 c 0 560 352 560 320 560 304 c 0 576 256 592 240 640 272 c 0 656 272 672 288 656 304 c 0 656 336 672 336 704 304 c 0 720 272 720 256 720 256 c 0 704 240 640 224 608 224 c 0 544 224 528 256 528 320 c 0 528 352 528 384 528 400 c 0 512 416 464 368 464 320 c 0 464 288 448 272 448 256 c 0 432 240 416 240 400 256 c 0 384 256 384 272 400 288 c 0 416 304 416 320 416 320 c 0 400 352 384 336 352 304 c 0 336 288 320 272 320 272 c 0 304 272 288 288 320 320 c 0 336 352 336 368 320 384 c 0 288 400 304 416 336 416 c 0 352 416 368 416 368 432 c 0 384 448 384 448 368 464 c 0 352 464 352 480 368 496 c 0 384 512 384 512 368 528 c 0 352 528 352 544 416 544 c 0 464 560 464 544 464 544 c 0 464 528 464 528 448 512 c 0 448 512 448 512 448 496 c 0 448 480 448 464 432 464 c 0 400 448 400 432 432 432 c 0 480 448 480 432 432 400 c 0 400 384 384 368 416 368 c 0 432 352 448 368 480 416 c 0 528 448 528 480 544 512 c 0 544 544 544 592 528 608 c 0 528 624 528 640 528 640 c 0 576 528 m 0 576 544 576 544 576 528 c 0 560 528 560 528 576 512 c 0 576 512 576 512 576 528 c 0 400 608 m 0 400 624 400 640 432 640 c 0 480 640 480 608 432 592 c 0 416 576 400 576 400 576 c 0 400 576 400 592 400 608 c 0 624 448 m 0 608 480 608 480 640 480 c 0 656 480 656 464 656 416 c 0 656 368 656 368 640 352 c 0 608 320 592 336 608 368 c 0 624 384 624 416 624 448 c 0 448 176 m 0 480 176 512 176 512 176 c 0 544 192 560 176 560 96 c 0 560 48 560 48 528 16 c 2 496 -16 l 1 528 0 l 2 560 0 592 -16 576 -48 c 0 576 -64 496 -80 448 -64 c 0 432 -48 416 -32 448 -16 c 0 464 0 464 16 448 16 c 0 400 48 432 128 496 128 c 0 512 128 528 128 528 144 c 0 528 144 512 160 496 144 c 0 448 128 416 144 416 160 c 0 416 176 416 176 448 176 c 0 512 80 m 0 512 96 464 96 464 80 c 0 448 80 448 48 464 32 c 0 480 16 480 32 496 48 c 0 512 64 512 80 512 80 c 0 EndSplineSet EndChar StartChar: S Encoding: 83 83 10 Width: 1024 Flags: W TeX: 83 0 0 0 Fore 480 448 m 0 480 480 480 496 528 464 c 0 544 448 544 448 544 416 c 0 528 400 544 384 608 336 c 0 704 288 720 256 688 240 c 0 688 224 672 240 608 288 c 0 496 384 512 384 432 304 c 0 400 272 368 240 352 240 c 0 304 208 320 240 400 320 c 0 480 400 480 416 480 448 c 0 480 288 m 0 512 288 544 288 544 288 c 0 576 304 576 272 544 256 c 0 512 240 528 224 560 224 c 0 576 224 576 208 544 192 c 0 512 192 512 160 544 160 c 0 576 160 576 128 544 128 c 0 512 112 528 80 560 80 c 0 608 80 608 80 608 64 c 0 608 48 576 48 480 48 c 0 384 48 368 48 400 96 c 0 416 112 416 112 416 128 c 0 416 144 416 160 416 160 c 0 448 176 448 192 416 208 c 0 384 224 400 224 448 224 c 0 480 224 496 240 464 256 c 0 432 272 432 288 480 288 c 0 480 96 m 0 480 112 464 112 448 96 c 0 432 80 432 80 448 80 c 0 464 64 480 80 480 96 c 0 EndSplineSet EndChar StartChar: H Encoding: 72 72 11 Width: 1024 Flags: W TeX: 72 0 0 0 Fore 448 480 m 0 448 496 448 512 464 512 c 0 464 512 512 464 512 448 c 0 512 432 352 304 336 304 c 0 320 320 352 352 384 384 c 0 432 432 448 464 448 480 c 0 608 336 m 0 560 384 544 400 560 400 c 0 592 400 688 336 688 304 c 0 704 256 672 256 608 336 c 0 464 352 m 0 464 368 480 368 496 352 c 0 560 320 560 304 496 288 c 0 480 288 464 288 480 304 c 0 480 320 480 336 480 336 c 0 464 352 464 352 464 352 c 0 432 256 m 2 512 272 528 272 544 256 c 0 560 224 544 160 528 128 c 0 512 112 512 96 528 96 c 0 544 96 560 80 544 64 c 0 544 48 544 48 496 48 c 0 432 32 400 64 432 80 c 0 448 96 448 112 432 128 c 0 416 160 416 176 480 208 c 2 512 224 l 1 464 224 l 2 448 224 416 224 416 240 c 2 384 256 l 1 432 256 l 2 512 176 m 0 496 192 480 192 464 176 c 0 448 176 448 128 464 128 c 0 496 128 512 160 512 176 c 0 EndSplineSet EndChar StartChar: L Encoding: 76 76 12 Width: 1024 Flags: W TeX: 76 0 0 0 Fore 480 528 m 0 480 560 512 560 528 544 c 0 544 528 544 512 528 496 c 0 512 480 512 464 544 464 c 0 576 464 576 448 560 432 c 0 544 416 544 416 560 400 c 0 624 384 624 368 576 336 c 0 560 336 544 320 544 304 c 0 528 272 528 224 544 224 c 0 560 224 544 176 528 144 c 2 480 112 l 1 528 112 l 2 560 128 576 128 576 112 c 0 592 80 560 64 512 64 c 0 464 64 432 80 448 112 c 0 464 112 464 128 448 160 c 0 432 224 432 272 448 304 c 0 464 304 464 304 480 288 c 0 496 272 512 288 512 320 c 0 512 368 512 368 464 336 c 0 400 304 384 320 448 384 c 0 480 416 480 432 480 528 c 0 560 368 m 0 560 384 l 0 544 384 544 368 544 368 c 0 544 368 544 352 560 352 c 0 560 368 l 0 496 208 m 0 496 208 496 224 480 240 c 0 464 240 464 240 480 224 c 0 480 192 496 176 496 208 c 0 EndSplineSet EndChar StartChar: P Encoding: 80 80 13 Width: 1024 Flags: W TeX: 80 0 0 0 Fore 480 448 m 0 512 496 512 512 528 496 c 0 544 480 544 416 544 384 c 0 528 368 528 352 560 352 c 0 576 352 576 336 576 320 c 0 576 304 576 304 528 288 c 0 512 288 496 272 480 240 c 0 464 176 464 160 512 128 c 0 560 96 576 80 544 64 c 0 496 32 416 112 416 176 c 0 416 192 432 224 448 256 c 0 480 304 480 320 464 352 c 0 464 368 464 384 480 448 c 0 EndSplineSet EndChar StartChar: plus Encoding: 43 43 14 Width: 1024 Flags: W TeX: 112 0 0 0 Fore 0 848 m 1 1088 848 l 1 1088 -208 l 1 0 -208 l 1 0 848 l 1 EndSplineSet EndChar StartChar: comma Encoding: 44 44 15 Width: 1024 VWidth: 16000 Flags: H TeX: 99 0 0 0 Fore 324.894 722.652 m 0 418.447 762.901 502.209 795.536 509.824 796.624 c 1 525.054 796.624 859.016 657.383 874.246 644.329 c 0 880.772 638.89 968.887 -118.236 968.887 -173.716 c 0 968.887 -192.209 948.218 -193.297 512 -193.297 c 0 75.7822 -193.297 55.1133 -192.209 55.1133 -173.716 c 0 55.1133 -130.202 142.14 636.714 147.578 642.153 c 0 150.842 645.417 230.253 681.314 324.894 722.652 c 0 696.93 695.457 m 2 609.904 733.53 531.581 766.165 522.878 769.429 c 0 514.176 771.604 430.413 741.146 337.948 699.808 c 2 169.335 626.924 l 1 160.633 561.654 l 2 156.281 526.844 136.7 349.528 117.119 168.949 c 2 81.2207 -160.662 l 1 512 -160.662 l 1 942.778 -160.662 l 1 906.881 168.949 l 2 887.3 349.528 867.719 526.844 863.367 561.654 c 2 854.665 626.924 l 1 696.93 695.457 l 2 EndSplineSet EndChar EndChars EndSplineFont tagua-1.0-alpha2/data/themes/pieces/ShogiSVG-TTF/Shogi.ttf000066400000000000000000000211341077523320400231460ustar00rootroot00000000000000 PFFTMDIb"@OS/2VwbXVcmap,RKcvt "tgasp"8glyf/ head6hhea$hmtxp.loca+2Jx(maxp`H8 nameXCpost}!Hy>_< JJJJ0@PP0\@ @.3  PfEd+s00\P"7(K-EE(p,BHLPSbhlps+BHLPRbgkpr ",,,:\$* 8 @ "w./<2<2/<2<23!%!!"UV"f0@P!!@P7>0672*#*.5476%&'& )/E V Z ;7b]Iiut4/ X #oC%$$%G )! /= )IA8JQ8A(ip"&63236'&42654&#"&764#""ȴ#&"4764'"747276&'&'&323276227>54634/32372#.7>367>'.#&764'&"326   + *  ! B   %   (  5P!3C а `0 0 ( p-3I3a; ( ,# (/  $ p   0%  ! :  H8       P"  00 D &W 3  &     #$K+ !@H43#&67.32&'42".756232#.676'&6?#"5'&"326  ( f - 00  0<(   $# - 00  @ % 0(I!6   P H   "P0!@c+4<F462"3236"&72'&72654&&7>5"3'&'"6$  . /%   000 &L&   $2 . P@     8$ 0`0$/-T  8@>32"&547>'4   $ ##]  & `   0/*U2@#& -pt423726'4#"&=&'"476?."&764'&632564'"464'"&>362#36367>74'"'4>32&632&763672'.6764#.6325'&&5464"">767#2 " %  0  K." 3       $$  0 $$    @  \$ ) $,X0      ( < 0& 00 -3P ;"(            & PP ` $ ($  ":$     7*  ` $  E0#T\46&'&'.#&>3632"2#32#*.67>=6'.62326'&64"36  2.1 0   @(N#@ 0$ 0P  00  # (   %' %  @1N0w   $        5=FNWe>74;"&432>4.#"547>54&"5767>6&#"6&"32>4#"34#"67'&#"3>422&54&#&676&#"7%62'&42622#&/3>&432#'&4; 4 *#+0@ 0X5#(   X @B D  ` @  Bm        H#000@FN PT 00$ 0 &X #@$$0  p4?   #(  6)# 0(  3 0     $  </$ <0   @   x0N"0  Yah72&'&"#"76?#32?6#"&/46;'56326=+&632>5'&+4"#&67>6&#'77#"6#"3262"#"'.6326=#""/&376325#"&76&#&754>"&5&#"&56'&62654#"'"432654>32326="&4#"3674#467608Z .  $  $ H29P   %  0@ ($    d  0 @@ p ($( 0  !      @ 0$  NN $ #    E $       0R p00(     $ (   00 < (0   %<  00 $@@    *   $0   #0 <X7      $    " %  Er>673265&?632#"762#"73#"73#*.7462654&#"&/4632654#""&'=#"?4#"432>'464.+#"25326#"72#"32#36'&42>5&546=+#'&'.#=3'&"32674#"3264"26636#4746#'&  0  $ $ (  0$ $ H(00#  H $   +    0 @4  $ $@ $ ;! 2. 5  `p    `   4  #            0  0     0;.@@ @@  x       1~.  -    pp0,$  T 8 (4 $AJo>+36+3252"#".746;=#".5>;5'#.6742>46#"&32#"725>76&#""5765463246#"'&426757+&632=>642#'&4764'"&'%322+'.6354&+"&?#"&'&63>P "900$(00@0H8L_$,P0 @0  p)%" 00 %0 &%7 s  $         00  T % p   !/   0  $ $  H- 0  0@0  @0  0 03   .     $ NN  P0    Y  -    @1  0$  $$   T_kp2?2##"672#"+#4/#'.=35&/&7>36&#".546;4&".54632'&3'&"3267+2&232#"32332.#&&54"&'.7364'463654&#"532>.32"32767267'4""6&"326&#'3   00 4%/   @@  00 @@5 ( 0 (@8P`   ( @@P $   00$%3 H<  0$   $< @0p B0&  $ ( p0      0   (P        0,P00$ #     L   e     @  # (]j232?6#73+"5&#&#"&67>'"&>3265&'""472>?#&52?264632654#"?'&42272#32"'.#&.'&432>="47&276442&57672642#"  $( N0  + Nk'$   && $   0` $ ` $  /- $.2@*$/@  $$$8 D  .4        =,   $  $   H $ $p0     $     0 0$ t     4 Qbhov62?2"#"&'."&54&#"#&67>57#"432?+47#"&/46327&36?'"./4#26'"4636#"232#&#''4&&'"&'57626'&5326'4"&/326'4&#32>7+32+32#&"#252'#"32>'&"32>        !4    @  0$$0   @   [    4 (0$ P 0$ @ P0(H$ :@/- 0 @/ $$ @0  0 `0&((    &  $ 6   97 %.$0 @4+U  ( @ H%/$   +   t 1 x    0 $ 0HH   $<0    0  0 0   U\hp} 6?"&#&"36#2736=;2"/&54&"5.>2>54&/""&=&47%+274&#"3267'&#32.32>5&7&27>54.2'4&#273#"27>332##4./32656'4.#""&6764#&576326'&434&#"'&"&543465427>'34""364.326    0   @P  @$ 0           0    0  -EX  0   #  4  #0  $0  4  0  @     (PP4!       $(  @8     $ 0 0`    D   %   $'9       (  5  3%  H   (:v!Jr t     B  >  P  Created by Io with FontForge 1.0 (http://fontforge.sf.net)Created by Io with FontForge 1.0 (http://fontforge.sf.net)ShogiShogiMediumMediumFontForge 1.0 : Shogi : 19-7-2007FontForge 1.0 : Shogi : 19-7-2007ShogiShogiVersion 001.000 Version 001.000 ShogiShogi2%+/356EJKNOSUV?KhOFEtagua-1.0-alpha2/data/themes/pieces/ShogiSVG-TTF/theme.desktop000066400000000000000000000002511077523320400240500ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Shogi SVG/TTF Type=Application Comment=Shogi TTF theme from SVG files X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess,Shogi[default] tagua-1.0-alpha2/data/themes/pieces/ShogiSVG-TTF/theme.lua000066400000000000000000000076101077523320400231660ustar00rootroot00000000000000import("piece_theme.lua") import("shogi_themelib.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 fontnames = {"Potraced from ???"} --, "Potraced from shogi.net"} fontlist = {"Shogi.ttf"} -- , "Shogi2.ttf"} theme.options = OptList { BoolOpt("moves_overlay", "Moves overlay", true), SelectOpt("symbols", "Symbol set", BoolOptList { BoolOpt("use_predefined", "Predefined", true, OptList { ComboOpt("font", "Symbol set", fontnames) }), BoolOpt("use_custom", "Custom font", false, OptList { UrlOpt("file", "SVG glyph directory", "Shogi.ttf") }), -- BoolOpt("use_system", "System font", false, OptList { -- FontOpt("font", "System font", Font("Arial", true, true)) -- }), }) } function addChar(char, promoted) return function(i, size) i:draw_glyph(Rect(0,0,size,size), theme.options.symbols.options.use_predefined.value and fontlist[theme.options.symbols.options.use_predefined.sub_options.font.selected+1] or theme.options.symbols.options.use_custom.value and theme.options.symbols.options.use_custom.sub_options.file.value or theme.options.symbols.options.use_system.sub_options.font.selected, char, promoted and "#d00000" or "#004000", "#fff3c8", 4, false) return i end end function shogi_piece(char, white, promoted, ratio, moves) return addShadow(overlay(tile(white, ratio), shogi_moves(moves), addChar(char, promoted))) end theme.black_king = shogi_piece("0x6B", false, false, 1, shogimoves_king) theme.black_rook = shogi_piece("0x72", false, false, 0.96, shogimoves_rook) theme.black_p_rook = shogi_piece("0x52", false, true, 0.96, shogimoves_dragon) theme.black_bishop = shogi_piece("0x62", false, false, 0.93, shogimoves_bishop) theme.black_p_bishop = shogi_piece("0x42", false, true, 0.93, shogimoves_horse) theme.black_gold = shogi_piece("0x67", false, false, 0.9, shogimoves_gold) theme.black_silver = shogi_piece("0x73", false, false, 0.9, shogimoves_silver) theme.black_p_silver = shogi_piece("0x53", false, true, 0.9, shogimoves_gold) theme.black_knight = shogi_piece("0x68", false, false, 0.86, shogimoves_knight) theme.black_p_knight = shogi_piece("0x48", false, true, 0.86, shogimoves_gold) theme.black_lance = shogi_piece("0x6C", false, false, 0.83, shogimoves_lance) theme.black_p_lance = shogi_piece("0x4C", false, true, 0.83, shogimoves_gold) theme.black_pawn = shogi_piece("0x70", false, false, 0.8, shogimoves_pawn) theme.black_p_pawn = shogi_piece("0x50", false, true, 0.8, shogimoves_gold) theme.white_king = shogi_piece("0x6B", true, false, 1, shogimoves_king) theme.white_rook = shogi_piece("0x72", true, false, 0.96, shogimoves_rook) theme.white_p_rook = shogi_piece("0x52", true, true, 0.96, shogimoves_dragon) theme.white_bishop = shogi_piece("0x62", true, false, 0.93, shogimoves_bishop) theme.white_p_bishop = shogi_piece("0x42", true, true, 0.93, shogimoves_horse) theme.white_gold = shogi_piece("0x67", true, false, 0.9, shogimoves_gold) theme.white_silver = shogi_piece("0x73", true, false, 0.9, shogimoves_silver) theme.white_p_silver = shogi_piece("0x53", true, true, 0.9, shogimoves_gold) theme.white_knight = shogi_piece("0x68", true, false, 0.86, shogimoves_knight) theme.white_p_knight = shogi_piece("0x48", true, true, 0.86, shogimoves_gold) theme.white_lance = shogi_piece("0x6C", true, false, 0.83, shogimoves_lance) theme.white_p_lance = shogi_piece("0x4C", true, true, 0.83, shogimoves_gold) theme.white_pawn = shogi_piece("0x70", true, false, 0.8, shogimoves_pawn) theme.white_p_pawn = shogi_piece("0x50", true, true, 0.8, shogimoves_gold) -- To be able to adapt this theme to chess too -- FIXME: should find a FreeKing kanji instead theme.black_queen = shogi_piece("0x67", false, false, 1, shogimoves_freeking) theme.white_queen = shogi_piece("0x67", true, false, 1, shogimoves_freeking) tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/000077500000000000000000000000001077523320400207225ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/000077500000000000000000000000001077523320400223465ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/bishop.svg000066400000000000000000000061631077523320400243610ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/example.svg000066400000000000000000000066411077523320400245310ustar00rootroot00000000000000 image/svg+xml 切り tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/gold.svg000066400000000000000000000070631077523320400240220ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/horse.svg000066400000000000000000000070551077523320400242160ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/king.svg000066400000000000000000000065121077523320400240230ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/lance.svg000066400000000000000000000064511077523320400241570ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/nude_tile.svg000066400000000000000000000050231077523320400250370ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/pawn.svg000066400000000000000000000061161077523320400240400ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/pbishop.svg000066400000000000000000000057501077523320400245420ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/phorse.svg000066400000000000000000000044401077523320400243710ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/plance.svg000066400000000000000000000041631077523320400243350ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/ppawn.svg000066400000000000000000000035231077523320400242170ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/prook.svg000066400000000000000000000061161077523320400242250ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/psilver.svg000066400000000000000000000043141077523320400245550ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/rook.svg000066400000000000000000000067331077523320400240520ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/silver.svg000066400000000000000000000072531077523320400244020ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/default/tile.svg000066400000000000000000000043151077523320400240270ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/theme.desktop000066400000000000000000000002551077523320400234210ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=ShogiSVG Type=Application Comment=Shogi SVG theme,| created with potrace from ??? X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess,Shogi tagua-1.0-alpha2/data/themes/pieces/ShogiSVG/theme.lua000066400000000000000000000070131077523320400225300ustar00rootroot00000000000000import("piece_theme.lua") import("shogi_themelib.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 fontnames = {"Potraced from ???"} -- , "Potraced from shogi.net", "Potraced from daemonshogi"} fontlist = {"default"} -- , "shogi.net", "daemonshogi"} theme.options = OptList { BoolOpt("moves_overlay", "Moves overlay", true), SelectOpt("symbols", "Symbol set", BoolOptList { BoolOpt("use_predefined", "Predefined", true, OptList { ComboOpt("font", "Symbol set", fontnames) }), BoolOpt("use_custom", "Custom", false, OptList { UrlOpt("dir", "SVG glyph directory", "default/") }), }) } function addGlyph(file) return function(i, size) local dir if theme.options.symbols.options.use_predefined.value then dir = fontlist[theme.options.symbols.options.use_predefined.sub_options.font.selected+1] else dir = theme.options.symbols.options.use_custom.sub_options.dir.value end i:draw_svg(Rect(0,0,size,size), dir .. '/' .. file) return i end end function shogi_piece(file, white, ratio, moves) return addShadow(overlay(tile(white, ratio), shogi_moves(moves), addGlyph(file))) end theme.black_king = shogi_piece("king.svg", false, 1, shogimoves_king) theme.black_rook = shogi_piece("rook.svg", false, 0.96, shogimoves_rook) theme.black_p_rook = shogi_piece("prook.svg", false, 0.96, shogimoves_dragon) theme.black_bishop = shogi_piece("bishop.svg", false, 0.93, shogimoves_bishop) theme.black_p_bishop = shogi_piece("pbishop.svg", false, 0.93, shogimoves_horse) theme.black_gold = shogi_piece("gold.svg", false, 0.9, shogimoves_gold) theme.black_silver = shogi_piece("silver.svg", false, 0.9, shogimoves_silver) theme.black_p_silver = shogi_piece("psilver.svg", false, 0.9, shogimoves_gold) theme.black_knight = shogi_piece("horse.svg", false, 0.86, shogimoves_knight) theme.black_p_knight = shogi_piece("phorse.svg", false, 0.86, shogimoves_gold) theme.black_lance = shogi_piece("lance.svg", false, 0.83, shogimoves_lance) theme.black_p_lance = shogi_piece("plance.svg", false, 0.83, shogimoves_gold) theme.black_pawn = shogi_piece("pawn.svg", false, 0.8, shogimoves_pawn) theme.black_p_pawn = shogi_piece("ppawn.svg", false, 0.8, shogimoves_gold) theme.white_king = shogi_piece("king.svg", true, 1, shogimoves_king) theme.white_rook = shogi_piece("rook.svg", true, 0.96, shogimoves_rook) theme.white_p_rook = shogi_piece("prook.svg", true, 0.96, shogimoves_dragon) theme.white_bishop = shogi_piece("bishop.svg", true, 0.93, shogimoves_bishop) theme.white_p_bishop = shogi_piece("pbishop.svg", true, 0.93, shogimoves_horse) theme.white_gold = shogi_piece("gold.svg", true, 0.9, shogimoves_gold) theme.white_silver = shogi_piece("silver.svg", true, 0.9, shogimoves_silver) theme.white_p_silver = shogi_piece("psilver.svg", true, 0.9, shogimoves_gold) theme.white_knight = shogi_piece("horse.svg", true, 0.86, shogimoves_knight) theme.white_p_knight = shogi_piece("phorse.svg", true, 0.86, shogimoves_gold) theme.white_lance = shogi_piece("lance.svg", true, 0.83, shogimoves_lance) theme.white_p_lance = shogi_piece("plance.svg", true, 0.83, shogimoves_gold) theme.white_pawn = shogi_piece("pawn.svg", true, 0.8, shogimoves_pawn) theme.white_p_pawn = shogi_piece("ppawn.svg", true, 0.8, shogimoves_gold) -- To be able to adapt this theme to chess too theme.black_queen = shogi_piece("gold.svg", false, 0.9, shogimoves_freeking) theme.white_queen = shogi_piece("gold.svg", true, 0.9, shogimoves_freeking) tagua-1.0-alpha2/data/themes/pieces/ShogiTTF/000077500000000000000000000000001077523320400207205ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/ShogiTTF/theme.desktop000066400000000000000000000002511077523320400234130ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=ShogiTTF Type=Application Comment=Shogi TTF theme X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess,Shogi[default],LargeShogi[default] tagua-1.0-alpha2/data/themes/pieces/ShogiTTF/theme.lua000066400000000000000000000150521077523320400225300ustar00rootroot00000000000000import("piece_theme.lua") import("shogi_themelib.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 theme.options = OptList { BoolOpt("moves_overlay", "Moves overlay", true), BoolOpt("single_kanji", "Single kanji on tiles", false), SelectOpt("symbols", "Symbol set", BoolOptList { -- BoolOpt("use_predefined", "Predefined", true, OptList { -- ComboOpt("font", "Symbol set", fontnames) -- }), BoolOpt("use_custom", "Custom font", false, OptList { UrlOpt("file", "SVG glyph directory", "../../figurines/ShogiTTF/mikachan.ttf") }), -- BoolOpt("use_system", "System font", false, OptList { -- FontOpt("font", "System font", Font("Arial", true, true)) -- }), }) } function addChar(complete, single, promoted) return function(i, size) font = theme.options.symbols.options.use_custom.sub_options.file.value if theme.options.single_kanji.value then i:draw_glyph(Rect(size*0.2,size*0.25,size*0.6,size*0.6), font, single, promoted and "#d00000" or "#004000", "#fff3c8", 4, false) else --local charsize, margin1, margin2 = 0.45, 0.09, -0.02 -- epgyobld local charsize, margin1, margin2 = 0.4, 0.12, 0 i:draw_glyph(Rect(size*(0.5-charsize/2),size*margin1,size*charsize,size*charsize), font, complete[1], promoted and "#d00000" or "#004000", "#fff3c8", 4, false) i:draw_glyph(Rect(size*(0.5-charsize/2),size*(0.5+margin2),size*charsize,size*charsize), font, complete[2], promoted and "#d00000" or "#004000", "#fff3c8", 4, false) end return i end end function shogi_piece(first, char, white, promoted, ratio, moves) return addShadow(overlay(tile(white, ratio), shogi_moves(moves), addChar(first, char, promoted))) end theme.black_king = shogi_piece(shogichars["jade general"][2], shogichars["jade general"][1], false, false, 1, shogimoves_king) theme.black_rook = shogi_piece(shogichars["flying chariot"][2], shogichars["flying chariot"][1], false, false, 0.96, shogimoves_rook) theme.black_p_rook = shogi_piece(shogichars["dragon king"][2], shogichars["dragon king"][1], false, true, 0.96, shogimoves_dragon) theme.black_bishop = shogi_piece(shogichars["bishop"][2], shogichars["bishop"][1], false, false, 0.93, shogimoves_bishop) theme.black_p_bishop = shogi_piece(shogichars["dragon horse"][2], shogichars["dragon horse"][1], false, true, 0.93, shogimoves_horse) theme.black_gold = shogi_piece(shogichars["gold general"][2], shogichars["gold general"][1], false, false, 0.9, shogimoves_gold) theme.black_silver = shogi_piece(shogichars["silver general"][2], shogichars["silver general"][1], false, false, 0.9, shogimoves_silver) theme.black_p_silver = shogi_piece(shogichars["narikei"][2], shogichars["narikei"][1], false, true, 0.9, shogimoves_gold) theme.black_knight = shogi_piece(shogichars["knight"][2], shogichars["knight"][1], false, false, 0.86, shogimoves_knight) theme.black_p_knight = shogi_piece(shogichars["narikei"][2], shogichars["narikei"][1], false, true, 0.86, shogimoves_gold) theme.black_lance = shogi_piece(shogichars["incense chariot"][2], shogichars["incense chariot"][1], false, false, 0.83, shogimoves_lance) theme.black_p_lance = shogi_piece(shogichars["narikyo"][2], shogichars["narikyo"][1], false, true, 0.83, shogimoves_gold) theme.black_pawn = shogi_piece(shogichars["pawn"][2], shogichars["pawn"][1], false, false, 0.8, shogimoves_pawn) theme.black_p_pawn = shogi_piece(shogichars["tokin"][2], shogichars["tokin"][1], false, true, 0.8, shogimoves_gold) theme.white_king = shogi_piece(shogichars["king"][2], shogichars["king"][1], true, false, 1, shogimoves_king) theme.white_rook = shogi_piece(shogichars["flying chariot"][2], shogichars["flying chariot"][1], true, false, 0.96, shogimoves_rook) theme.white_p_rook = shogi_piece(shogichars["dragon king"][2], shogichars["dragon king"][1], true, true, 0.96, shogimoves_dragon) theme.white_bishop = shogi_piece(shogichars["bishop"][2], shogichars["bishop"][1], true, false, 0.93, shogimoves_bishop) theme.white_p_bishop = shogi_piece(shogichars["dragon horse"][2], shogichars["dragon horse"][1], true, true, 0.93, shogimoves_horse) theme.white_gold = shogi_piece(shogichars["gold general"][2], shogichars["gold general"][1], true, false, 0.9, shogimoves_gold) theme.white_silver = shogi_piece(shogichars["silver general"][2], shogichars["silver general"][1], true, false, 0.9, shogimoves_silver) theme.white_p_silver = shogi_piece(shogichars["narikei"][2], shogichars["narikei"][1], true, true, 0.9, shogimoves_gold) theme.white_knight = shogi_piece(shogichars["knight"][2], shogichars["knight"][1], true, false, 0.86, shogimoves_knight) theme.white_p_knight = shogi_piece(shogichars["narikei"][2], shogichars["narikei"][1], true, true, 0.86, shogimoves_gold) theme.white_lance = shogi_piece(shogichars["incense chariot"][2], shogichars["incense chariot"][1], true, false, 0.83, shogimoves_lance) theme.white_p_lance = shogi_piece(shogichars["narikyo"][2], shogichars["narikyo"][1], true, true, 0.83, shogimoves_gold) theme.white_pawn = shogi_piece(shogichars["pawn"][2], shogichars["pawn"][1], true, false, 0.8, shogimoves_pawn) theme.white_p_pawn = shogi_piece(shogichars["tokin"][2],shogichars["tokin"][1], true, true, 0.8, shogimoves_gold) -- Sho Shogi theme.black_drunken_elephant = shogi_piece(shogichars["drunken elephant"][2], shogichars["drunken elephant"][1], false, false, 1, shogimoves_drunken_elephant) theme.black_p_drunken_elephant = shogi_piece(shogichars["crown prince"][2], shogichars["crown prince"][1], false, true, 1, shogimoves_king) theme.white_drunken_elephant = shogi_piece(shogichars["drunken elephant"][2], shogichars["drunken elephant"][1], true, false, 1, shogimoves_drunken_elephant) theme.white_p_drunken_elephant = shogi_piece(shogichars["crown prince"][2], shogichars["crown prince"][1], true, true, 1, shogimoves_king) -- This is part of Dai Shohi theme.black_freeking = shogi_piece(shogichars["free king"][2], shogichars["free king"][1], false, false, 1, shogimoves_freeking) theme.white_freeking = shogi_piece(shogichars["free king"][2], shogichars["free king"][1], true, false, 1, shogimoves_freeking) -- To be able to adapt this theme to chess too theme.black_queen = theme.black_freeking theme.white_queen = theme.white_freeking tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/000077500000000000000000000000001077523320400211265ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/bb.svg000066400000000000000000000667611077523320400222520ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/bk.svg000066400000000000000000000662631077523320400222600ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/bn.svg000066400000000000000000000635641077523320400222640ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/bp.svg000066400000000000000000000534021077523320400222540ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/bq.svg000066400000000000000000001056241077523320400222610ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/br.svg000066400000000000000000000425151077523320400222610ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/theme.desktop000066400000000000000000000002321077523320400236200ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Skulls Type=Application Comment=Skulls SVG theme,| by Maurizio Monge X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/theme.lua000066400000000000000000000011041077523320400227270ustar00rootroot00000000000000import("piece_theme.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 theme.black_bishop = fromSVG("bb.svg") theme.black_king = fromSVG("bk.svg") theme.black_knight = fromSVG("bn.svg") theme.black_pawn = fromSVG("bp.svg") theme.black_queen = fromSVG("bq.svg") theme.black_rook = fromSVG("br.svg") theme.white_bishop = fromSVG("wb.svg") theme.white_king = fromSVG("wk.svg") theme.white_knight = fromSVG("wn.svg") theme.white_pawn = fromSVG("wp.svg") theme.white_queen = fromSVG("wq.svg") theme.white_rook = fromSVG("wr.svg") tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/wb.svg000066400000000000000000000667641077523320400223020ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/wk.svg000066400000000000000000000662521077523320400223030ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/wn.svg000066400000000000000000000635651077523320400223120ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/wp.svg000066400000000000000000000534031077523320400223020ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/wq.svg000066400000000000000000001056241077523320400223060ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SkullsSVG/wr.svg000066400000000000000000000425141077523320400223050ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/000077500000000000000000000000001077523320400212465ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/bb.svg000066400000000000000000000150761077523320400223630ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/bk.svg000066400000000000000000000136121077523320400223660ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/bn.svg000066400000000000000000000105541077523320400223730ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/bp.svg000066400000000000000000000073411077523320400223750ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/bq.svg000066400000000000000000000120711077523320400223720ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/br.svg000066400000000000000000000177171077523320400224070ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/theme.desktop000066400000000000000000000002341077523320400237420ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Spatial Type=Application Comment=Spatial SVG theme,| by Maurizio Monge X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/theme.lua000066400000000000000000000011041077523320400230470ustar00rootroot00000000000000import("piece_theme.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 theme.black_bishop = fromSVG("bb.svg") theme.black_king = fromSVG("bk.svg") theme.black_knight = fromSVG("bn.svg") theme.black_pawn = fromSVG("bp.svg") theme.black_queen = fromSVG("bq.svg") theme.black_rook = fromSVG("br.svg") theme.white_bishop = fromSVG("wb.svg") theme.white_king = fromSVG("wk.svg") theme.white_knight = fromSVG("wn.svg") theme.white_pawn = fromSVG("wp.svg") theme.white_queen = fromSVG("wq.svg") theme.white_rook = fromSVG("wr.svg") tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/wb.svg000066400000000000000000000150771077523320400224110ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/wk.svg000066400000000000000000000136141077523320400224150ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/wn.svg000066400000000000000000000105631077523320400224200ustar00rootroot00000000000000 image/svg+xml Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/wp.svg000066400000000000000000000073421077523320400224230ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/wq.svg000066400000000000000000000120731077523320400224210ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/SpatialSVG/wr.svg000066400000000000000000000127721077523320400224300ustar00rootroot00000000000000 image/svg+xml Maurizio Monge Maurizio Monge tagua-1.0-alpha2/data/themes/pieces/StonesSVG/000077500000000000000000000000001077523320400211245ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/StonesSVG/black.svg000066400000000000000000000131021077523320400227160ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/StonesSVG/blue.svg000066400000000000000000000131111077523320400225710ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/StonesSVG/blue_add.svg000066400000000000000000000101721077523320400234050ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/StonesSVG/green.svg000066400000000000000000000131161077523320400227470ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/StonesSVG/grey.svg000066400000000000000000000131171077523320400226160ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/StonesSVG/orange.svg000066400000000000000000000131151077523320400231210ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/StonesSVG/red.svg000066400000000000000000000131041077523320400224160ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/StonesSVG/red_add.svg000066400000000000000000000101701077523320400232260ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/StonesSVG/theme_chainreaction.desktop000066400000000000000000000002571077523320400265140ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Red/Blue Type=Application Comment=Red/Blue SVG stones| by Maurizio Monge X-Tagua-ThemeType=Pieces X-Tagua-Variants=ChainReaction[Default] tagua-1.0-alpha2/data/themes/pieces/StonesSVG/theme_chainreaction.lua000066400000000000000000000067331077523320400256310ustar00rootroot00000000000000import("piece_theme.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 function fromSVG1(file) return function(size) local i = Image(size,size) i:clear() i:draw_svg(Rect(size*0.25,size*0.25,size*0.5,size*0.5), file) print("create from "..file) return i end end function fromSVG2(file) return function(size) local i = Image(size,size) i:clear() i:draw_svg(Rect(size*0.45,size*0.05,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.05,size*0.45,size*0.5,size*0.5), file) return i end end function fromSVG3(file) return function(size) local i = Image(size,size) i:clear() i:draw_svg(Rect(size*0.25,size*0.0334936490538904,size*0.5,size*0.5), file) i:draw_svg(Rect(0,size*0.46650635094611,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.5,size*0.46650635094611,size*0.5,size*0.5), file) return i end end function fromSVG4(file) return function(size) local i = Image(size,size) i:clear() i:draw_svg(Rect(0,0,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.5,0,size*0.5,size*0.5), file) i:draw_svg(Rect(0,size*0.5,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.5,size*0.5,size*0.5,size*0.5), file) return i end end function fromSVG5(file) return function(size) local i = Image(size,size) i:clear() i:draw_svg(Rect(0,0,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.5,0,size*0.5,size*0.5), file) i:draw_svg(Rect(0,size*0.5,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.5,size*0.5,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.25,size*0.25,size*0.5,size*0.5), file) return i end end function fromSVG6(file) return function(size) local i = Image(size,size) i:clear() i:draw_svg(Rect(0,0,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.5,0,size*0.5,size*0.5), file) i:draw_svg(Rect(0,size*0.25,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.5,size*0.25,size*0.5,size*0.5), file) i:draw_svg(Rect(0,size*0.5,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.5,size*0.5,size*0.5,size*0.5), file) return i end end function fromSVG7(file) return function(size) local i = Image(size,size) i:clear() i:draw_svg(Rect(size*0.08,0,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.42,0,size*0.5,size*0.5), file) i:draw_svg(Rect(0,size*0.25,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.5,size*0.25,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.08,size*0.5,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.42,size*0.5,size*0.5,size*0.5), file) i:draw_svg(Rect(size*0.25,size*0.25,size*0.5,size*0.5), file) return i end end theme.white_add = addShadow(fromSVG_Direct("red_add.svg")) theme.black_add = addShadow(fromSVG_Direct("blue_add.svg")) theme.white_1 = addShadow(fromSVG1("red.svg")) theme.black_1 = addShadow(fromSVG1("blue.svg")) theme.neutral_1 = addShadow(fromSVG1("grey.svg")) theme.white_2 = addShadow(fromSVG2("red.svg")) theme.black_2 = addShadow(fromSVG2("blue.svg")) theme.white_3 = addShadow(fromSVG3("red.svg")) theme.black_3 = addShadow(fromSVG3("blue.svg")) theme.white_4 = addShadow(fromSVG4("red.svg")) theme.black_4 = addShadow(fromSVG4("blue.svg")) theme.white_5 = addShadow(fromSVG5("red.svg")) theme.black_5 = addShadow(fromSVG5("blue.svg")) theme.white_6 = addShadow(fromSVG6("red.svg")) theme.black_6 = addShadow(fromSVG6("blue.svg")) theme.white_7 = addShadow(fromSVG7("red.svg")) theme.black_7 = addShadow(fromSVG7("blue.svg")) tagua-1.0-alpha2/data/themes/pieces/StonesSVG/theme_rs.desktop000066400000000000000000000002411077523320400243220ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Red/Blue Type=Application Comment=Red/Blue SVG stones| by Maurizio Monge X-Tagua-ThemeType=Pieces X-Tagua-Variants=Reversi tagua-1.0-alpha2/data/themes/pieces/StonesSVG/theme_rs.lua000066400000000000000000000003011077523320400234270ustar00rootroot00000000000000import("piece_theme.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 theme.white_stone = fromSVG("red.svg") theme.black_stone = fromSVG("blue.svg") tagua-1.0-alpha2/data/themes/pieces/StonesSVG/theme_ry.desktop000066400000000000000000000002671077523320400243400ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Red/Yellow Type=Application Comment=Red/Yellow SVG stones| by Maurizio Monge X-Tagua-ThemeType=Pieces X-Tagua-Variants=Reversi,Connect4[default] tagua-1.0-alpha2/data/themes/pieces/StonesSVG/theme_ry.lua000066400000000000000000000003031077523320400234370ustar00rootroot00000000000000import("piece_theme.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 theme.white_stone = fromSVG("red.svg") theme.black_stone = fromSVG("yellow.svg") tagua-1.0-alpha2/data/themes/pieces/StonesSVG/theme_wb.desktop000066400000000000000000000002541077523320400243120ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=White/Black Type=Application Comment=Shogi TTF theme,| created with potrace X-Tagua-ThemeType=Pieces X-Tagua-Variants=Reversi[default] tagua-1.0-alpha2/data/themes/pieces/StonesSVG/theme_wb.lua000066400000000000000000000003041077523320400234160ustar00rootroot00000000000000import("piece_theme.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 theme.white_stone = fromSVG("white.svg") theme.black_stone = fromSVG("black.svg") tagua-1.0-alpha2/data/themes/pieces/StonesSVG/violet.svg000066400000000000000000000131141077523320400231470ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/StonesSVG/white.svg000066400000000000000000000131021077523320400227620ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/StonesSVG/yellow.svg000066400000000000000000000131231077523320400231600ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/ToriShogiTTF/000077500000000000000000000000001077523320400215565ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/ToriShogiTTF/theme.desktop000066400000000000000000000002341077523320400242520ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=ToriShogiTTF Type=Application Comment=Tori Shogi TTF theme X-Tagua-ThemeType=Pieces X-Tagua-Variants=ToriShogi[default] tagua-1.0-alpha2/data/themes/pieces/ToriShogiTTF/theme.lua000066400000000000000000000062651077523320400233740ustar00rootroot00000000000000import("piece_theme.lua") import("shogi_themelib.lua") shadow=7.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 theme.options = OptList { BoolOpt("moves_overlay", "Moves overlay", true), BoolOpt("single_kanji", "Single kanji on tiles", false), SelectOpt("symbols", "Symbol set", BoolOptList { -- BoolOpt("use_predefined", "Predefined", true, OptList { -- ComboOpt("font", "Symbol set", fontnames) -- }), BoolOpt("use_custom", "Custom font", false, OptList { UrlOpt("file", "SVG glyph directory", "../../figurines/ShogiTTF/mikachan.ttf") }), -- BoolOpt("use_system", "System font", false, OptList { -- FontOpt("font", "System font", Font("Arial", true, true)) -- }), }) } function addChar(single, promoted) return function(i, size) font = theme.options.symbols.options.use_custom.sub_options.file.value i:draw_glyph(Rect(size*0.2,size*0.25,size*0.6,size*0.6), font, single, promoted and "#d00000" or "#004000", "#fff3c8", 4, false) return i end end function shogi_piece(char, white, promoted, ratio, moves) return addShadow(overlay(tile(white, ratio), shogi_moves(moves), addChar(char, promoted))) end -- Tori Shogi theme.black_phoenix = shogi_piece(shogichars["tori phoenix"][1], false, false, 1, shogimoves_king) theme.black_falcon = shogi_piece(shogichars["tori falcon"][1], false, false, 1, shogimoves_drunken_elephant) theme.black_p_falcon = shogi_piece(shogichars["tori eagle"][1], false, true, 1, shogimoves_eagle) theme.black_crane = shogi_piece(shogichars["tori crane"][1], false, false, 1, shogimoves_crane) theme.black_right_quail = shogi_piece(shogichars["tori quail"][1], false, false, 1, shogimoves_right_quail) theme.black_left_quail = shogi_piece(shogichars["tori quail"][1], false, false, 1, shogimoves_left_quail) theme.black_pheasant = shogi_piece(shogichars["tori pheasant"][1], false, false, 1, shogimoves_pheasant) theme.black_swallow = shogi_piece(shogichars["tori swallow"][1], false, false, 1, shogimoves_pawn) theme.black_p_swallow = shogi_piece(shogichars["tori goose"][1], false, true, 1, shogimoves_goose) theme.white_phoenix = shogi_piece(shogichars["tori phoenix"][1], true, false, 1, shogimoves_king) theme.white_falcon = shogi_piece(shogichars["tori falcon"][1], true, false, 1, shogimoves_drunken_elephant) theme.white_p_falcon = shogi_piece(shogichars["tori eagle"][1], true, true, 1, shogimoves_eagle) theme.white_crane = shogi_piece(shogichars["tori crane"][1], true, false, 1, shogimoves_crane) theme.white_right_quail = shogi_piece(shogichars["tori quail"][1], true, false, 1, shogimoves_right_quail) theme.white_left_quail = shogi_piece(shogichars["tori quail"][1], true, false, 1, shogimoves_left_quail) theme.white_pheasant = shogi_piece(shogichars["tori pheasant"][1], true, false, 1, shogimoves_pheasant) theme.white_swallow = shogi_piece(shogichars["tori swallow"][1], true, false, 1, shogimoves_pawn) theme.white_p_swallow = shogi_piece(shogichars["tori goose"][1], true, true, 1, shogimoves_goose) tagua-1.0-alpha2/data/themes/pieces/XBoardTTF/000077500000000000000000000000001077523320400210265ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/XBoardTTF/XBoard.sfd000066400000000000000000001224271077523320400227130ustar00rootroot00000000000000SplineFontDB: 1.0 FontName: XBoard FullName: XBoard FamilyName: XBoard Weight: Medium Copyright: Created by Io with FontForge 1.0 (http://fontforge.sf.net) Version: 001.000 ItalicAngle: 0 UnderlinePosition: -100 UnderlineWidth: 50 Ascent: 819 Descent: 205 Order2: 1 XUID: [1021 645 1811818106 3714181] FSType: 0 OS2Version: 0 OS2_WeightWidthSlopeOnly: 0 OS2_UseTypoMetrics: 0 CreationTime: 1156037136 ModificationTime: 1160235844 PfmFamily: 17 TTFWeight: 500 TTFWidth: 5 LineGap: 92 VLineGap: 0 Panose: 2 0 6 3 0 0 0 0 0 0 OS2TypoAscent: 0 OS2TypoAOffset: 1 OS2TypoDescent: 0 OS2TypoDOffset: 1 OS2TypoLinegap: 0 OS2WinAscent: 0 OS2WinAOffset: 1 OS2WinDescent: 0 OS2WinDOffset: 1 HheadAscent: 0 HheadAOffset: 1 HheadDescent: 0 HheadDOffset: 1 OS2SubXSize: 665 OS2SubYSize: 716 OS2SubXOff: 0 OS2SubYOff: 143 OS2SupXSize: 665 OS2SupYSize: 716 OS2SupXOff: 0 OS2SupYOff: 491 OS2StrikeYSize: 51 OS2StrikeYPos: 265 OS2Vendor: 'PfEd' TtfTable: cvt 4 !$VK# EndTtf TtfTable: maxp 32 !!*'"!"]0I!"T&0!!!!#!!!!"!!*'"!'gN:z EndTtf LangName: 1033 Encoding: UnicodeBmp UnicodeInterp: none NameList: Adobe Glyph List DisplaySize: -36 AntiAlias: 1 FitToEm: 1 WinInfo: 46 23 12 BeginChars: 65538 16 StartChar: .notdef Encoding: 65536 -1 0 Width: 443 Flags: W TtfInstrs: 46 YlOhX4L,1p!:;PH"pNdEZ3(..m4n[H!rsu:Z3:@2m4tsP"p+WaZ2k",m4nYA EndTtf Fore 34 0 m 1,0,-1 34 682 l 1,1,-1 375 682 l 1,2,-1 375 0 l 1,3,-1 34 0 l 1,0,-1 68 34 m 1,4,-1 341 34 l 1,5,-1 341 648 l 1,6,-1 68 648 l 1,7,-1 68 34 l 1,4,-1 EndSplineSet EndChar StartChar: .null Encoding: 65537 0 1 Width: 0 Flags: W EndChar StartChar: nonmarkingreturn Encoding: 13 13 2 Width: 341 Flags: W EndChar StartChar: plus Encoding: 43 43 3 Width: 1024 Flags: W Fore 0 818 m 1,0,-1 1024 818 l 1,1,-1 1024 -204 l 1,2,-1 0 -204 l 1,3,-1 0 818 l 1,0,-1 EndSplineSet EndChar StartChar: B Encoding: 66 66 4 Width: 1023 Flags: W Fore 461 732 m 0,0,1 481 756 481 756 507 756 c 0,2,3 540 756 540 756 565 722 c 0,4,5 579 704 579 704 579 686 c 0,6,7 579 662 579 662 564 643 c 2,8,-1 548 622 l 1,9,-1 593 593 l 2,10,11 754 483 754 483 754 374 c 0,12,13 754 294 754 294 711 236 c 0,14,15 709 233 709 233 707 231 c 0,16,17 683 200 683 200 683 189 c 256,18,19 683 178 683 178 705 117 c 2,20,-1 729 56 l 1,21,-1 712 46 l 2,22,23 694 34 694 34 623 25 c 2,24,-1 554 16 l 1,25,-1 580 -2 l 2,26,27 602 -16 602 -16 645 -17 c 0,28,29 666 -18 666 -18 738 -18 c 0,30,31 858 -18 858 -18 887 -28 c 0,32,33 895 -30 895 -30 907 -36 c 0,34,35 943 -52 943 -52 945 -62 c 1,36,37 945 -75 945 -75 906 -123 c 0,38,39 892 -141 892 -141 889 -141 c 0,40,41 881 -141 881 -141 855 -129 c 0,42,43 823 -117 823 -117 709 -120 c 0,44,45 604 -121 604 -121 583 -114 c 0,46,47 572 -110 572 -110 550 -98 c 2,48,-1 507 -79 l 1,49,-1 468 -98 l 2,50,51 432 -117 432 -117 402 -119 c 0,52,53 382 -121 382 -121 307 -120 c 0,54,55 193 -117 193 -117 161 -129 c 0,56,57 135 -141 135 -141 127 -141 c 256,58,59 119 -141 119 -141 86 -91 c 0,60,61 71 -68 71 -68 71 -62 c 0,62,63 71 -53 71 -53 110 -36 c 0,64,65 142 -21 142 -21 199 -19 c 0,66,67 225 -18 225 -18 278 -18 c 0,68,69 398 -18 398 -18 418 -11 c 0,70,71 426 -8 426 -8 436 -2 c 2,72,-1 462 16 l 1,73,-1 393 25 l 2,74,75 325 34 325 34 304 46 c 2,76,-1 287 56 l 1,77,-1 311 117 l 2,78,79 333 178 333 178 333 189 c 256,80,81 333 200 333 200 309 231 c 0,82,83 264 293 264 293 262 374 c 0,84,85 262 483 262 483 423 593 c 2,86,-1 468 622 l 1,87,-1 452 643 l 2,88,89 419 683 419 683 453 724 c 0,90,91 461 732 l 0,0,1 521 444 m 2,92,93 520 486 520 486 506 485 c 0,94,95 502 484 502 484 498 480 c 1,96,97 492 476 492 476 492 441 c 2,98,-1 492 407 l 1,99,-1 455 405 l 2,100,101 417 402 417 402 417 391 c 256,102,103 417 380 417 380 450 376 c 0,104,105 454 376 l 2,106,-1 491 374 l 1,107,-1 495 338 l 2,108,109 495 299 495 299 507 299 c 0,110,111 521 299 521 299 521 338 c 2,112,-1 525 374 l 1,113,-1 562 376 l 2,114,115 598 380 598 380 599 391 c 0,116,117 599 402 599 402 562 405 c 2,118,-1 525 407 l 1,119,-1 521 444 l 2,92,93 630 205 m 0,120,121 630 214 630 214 618 217 c 0,122,123 602 220 602 220 510 221 c 0,124,125 394 224 394 224 384 212 c 1,126,127 379 201 379 201 383 195 c 1,128,129 387 191 387 191 510 191 c 0,130,131 619 191 619 191 627 197 c 0,132,133 630 199 630 199 630 205 c 0,120,121 647 129 m 0,134,135 621 135 621 135 507 135 c 0,136,137 362 135 362 135 348 120 c 0,138,139 345 117 345 117 345 112 c 0,140,141 345 103 345 103 405 102 c 0,142,143 434 101 434 101 507 101 c 0,144,145 660 101 660 101 669 108 c 0,146,147 671 110 671 110 671 112 c 0,148,149 671 125 671 125 647 129 c 0,134,135 EndSplineSet EndChar StartChar: K Encoding: 75 75 5 Width: 1023 Flags: W Fore 498 735 m 0,0,1 508 746 508 746 516 732 c 0,2,3 520 725 520 725 521 714 c 0,4,5 525 696 525 696 538 693 c 0,6,7 542 692 542 692 550 691 c 0,8,9 577 688 577 688 576 675 c 0,10,11 575 663 575 663 550 662 c 0,12,13 529 660 529 660 526 653 c 0,14,15 524 646 524 646 524 622 c 0,16,17 525 589 525 589 536 579 c 0,18,19 540 575 540 575 550 570 c 1,20,21 596 538 596 538 603 479 c 0,22,23 604 471 604 471 604 464 c 2,24,-1 604 430 l 1,25,-1 647 455 l 2,26,27 736 504 736 504 826 472 c 0,28,29 899 446 899 446 930 379 c 0,30,31 977 273 977 273 853 161 c 2,32,-1 802 114 l 1,33,-1 796 22 l 2,34,35 794 -61 794 -61 783 -77 c 1,36,37 774 -84 774 -84 703 -105 c 0,38,39 556 -148 556 -148 384 -123 c 0,40,41 320 -113 320 -113 268 -94 c 0,42,43 232 -81 232 -81 224 -66 c 0,44,45 214 -49 214 -49 214 36 c 2,46,-1 214 114 l 1,47,-1 164 161 l 2,48,49 40 276 40 276 85 377 c 0,50,51 99 408 99 408 129 435 c 0,52,53 205 504 205 504 305 480 c 0,54,55 338 473 338 473 369 455 c 2,56,-1 412 430 l 1,57,-1 412 464 l 2,58,59 412 525 412 525 457 563 c 0,60,61 461 567 461 567 466 570 c 0,62,63 487 581 487 581 490 597 c 0,64,65 491 604 491 604 492 622 c 0,66,67 492 655 492 655 485 659 c 0,68,69 481 661 481 661 468 662 c 0,70,71 441 665 441 665 441 676 c 0,72,73 441 688 441 688 468 691 c 1,74,75 490 699 490 699 492 711 c 1,76,77 492 729 492 729 498 735 c 0,0,1 548 529 m 0,78,79 531 548 531 548 507 548 c 0,80,81 469 548 469 548 453 501 c 0,82,83 448 487 448 487 446 471 c 0,84,85 443 437 443 437 462 391 c 0,86,87 466 381 466 381 473 364 c 0,88,89 505 296 505 296 507 296 c 0,90,91 511 296 511 296 543 364 c 0,92,93 571 429 571 429 571 456 c 0,94,95 571 463 571 463 570 471 c 0,96,97 565 512 565 512 548 529 c 0,78,79 347 432 m 0,98,99 263 475 263 475 184 437 c 0,100,101 120 406 120 406 106 344 c 0,102,103 96 297 96 297 123 251 c 0,104,105 142 219 142 219 203 168 c 2,106,-1 262 120 l 1,107,-1 332 132 l 2,108,109 443 156 443 156 599 144 c 0,110,111 648 140 648 140 684 132 c 2,112,-1 754 120 l 1,113,-1 813 168 l 2,114,115 942 274 942 274 905 360 c 0,116,117 899 375 899 375 888 390 c 0,118,119 841 456 841 456 753 454 c 0,120,121 663 452 663 452 599 381 c 0,122,123 551 329 551 329 531 252 c 0,124,125 526 235 526 235 525 221 c 0,126,127 520 188 520 188 512 185 c 0,128,129 510 184 510 184 507 184 c 0,130,131 497 184 497 184 493 205 c 0,132,133 492 211 492 211 491 221 c 0,134,135 483 308 483 308 416 380 c 0,136,137 384 415 384 415 347 432 c 0,98,99 698 62 m 0,138,139 645 77 645 77 474 78 c 0,140,141 401 79 401 79 373 74 c 0,142,143 264 52 264 52 263 33 c 0,144,145 263 28 263 28 268 23 c 0,146,147 277 16 277 16 338 30 c 0,148,149 438 51 438 51 592 41 c 0,150,151 644 37 644 37 679 30 c 0,152,153 741 17 741 17 749 25 c 0,154,155 763 40 763 40 720 55 c 0,156,157 711 58 711 58 698 62 c 0,138,139 687 -11 m 0,158,159 634 4 634 4 478 7 c 0,160,161 418 9 418 9 401 5 c 1,162,163 391 1 391 1 332 -11 c 0,164,165 260 -27 260 -27 264 -48 c 0,166,167 265 -52 265 -52 268 -55 c 0,168,169 274 -63 274 -63 338 -45 c 0,170,171 438 -18 438 -18 584 -30 c 0,172,173 640 -35 640 -35 679 -45 c 0,174,175 743 -62 743 -62 749 -54 c 1,176,177 765 -38 765 -38 716 -20 c 0,178,179 703 -15 703 -15 687 -11 c 0,158,159 484 497 m 0,180,181 492 518 492 518 507 518 c 0,182,183 527 518 527 518 536 486 c 0,184,185 540 473 540 473 540 458 c 0,186,187 540 430 540 430 519 390 c 0,188,189 511 375 511 375 507 375 c 0,190,191 498 375 498 375 483 424 c 0,192,193 476 447 476 447 476 458 c 0,194,195 476 479 476 479 484 497 c 0,180,181 211 410 m 0,196,197 274 434 274 434 344 397 c 0,198,199 371 383 371 383 391 361 c 0,200,201 424 327 424 327 447 254 c 0,202,203 454 234 454 234 456 219 c 2,204,-1 461 186 l 1,205,-1 405 180 l 2,206,207 339 173 339 173 308 165 c 2,208,-1 266 156 l 1,209,-1 213 202 l 2,210,211 125 279 125 279 140 339 c 0,212,213 142 345 l 0,214,215 156 384 156 384 190 401 c 0,216,217 199 406 199 406 211 410 c 0,196,197 714 415 m 0,218,219 767 432 767 432 823 400 c 0,220,221 855 382 855 382 868 356 c 0,222,223 891 308 891 308 857 261 c 0,224,225 841 238 841 238 807 207 c 2,226,-1 754 155 l 1,227,-1 710 164 l 2,228,229 670 174 670 174 611 180 c 2,230,-1 555 186 l 1,231,-1 560 219 l 2,232,233 569 278 569 278 607 337 c 0,234,235 617 352 617 352 626 361 c 0,236,237 658 397 658 397 714 415 c 0,218,219 EndSplineSet EndChar StartChar: N Encoding: 78 78 6 Width: 1023 Flags: W Fore 273 712 m 0,0,1 277 723 277 723 285 720 c 0,2,3 294 717 294 717 340 682 c 0,4,5 383 649 383 649 387 640 c 0,6,7 393 623 393 623 406 638 c 0,8,9 415 648 415 648 432 677 c 0,10,11 460 721 460 721 473 722 c 1,12,13 484 721 484 721 514 668 c 0,14,15 525 650 525 650 529 638 c 1,16,17 577 628 l 2,18,19 741 598 741 598 834 409 c 0,20,21 921 232 921 232 923 -38 c 2,22,-1 925 -129 l 1,23,-1 623 -129 l 1,24,-1 321 -129 l 1,25,-1 323 -91 l 2,26,27 325 -43 325 -43 375 24 c 0,28,29 394 49 394 49 425 86 c 0,30,31 503 177 503 177 517 237 c 0,32,33 520 247 520 247 521 258 c 0,34,35 525 285 525 285 522 286 c 1,36,37 519 286 519 286 511 279 c 0,38,39 496 264 496 264 452 244 c 0,40,41 371 202 371 202 323 150 c 0,42,43 311 137 311 137 298 121 c 0,44,45 250 60 250 60 229 66 c 0,46,47 221 68 221 68 214 77 c 0,48,49 204 89 204 89 180 89 c 0,50,51 128 89 128 89 101 131 c 0,52,53 87 152 87 152 87 176 c 0,54,55 87 227 87 227 124 292 c 0,56,57 135 310 135 310 151 335 c 0,58,59 195 403 195 403 203 437 c 0,60,61 216 512 216 512 241 549 c 0,62,63 244 554 244 554 248 559 c 0,64,65 272 588 272 588 274 605 c 0,66,67 275 616 275 616 272 646 c 0,68,69 268 701 268 701 273 712 c 0,0,1 626 577 m 0,70,71 549 612 549 612 525 598 c 0,72,73 512 590 512 590 536 575 c 0,74,75 551 566 551 566 572 562 c 0,76,77 602 556 602 556 641 529 c 0,78,79 764 448 764 448 810 181 c 0,80,81 821 118 821 118 826 48 c 0,82,83 837 -73 837 -73 852 -92 c 0,84,85 860 -102 860 -102 875 -102 c 0,86,87 888 -102 888 -102 894 -90 c 0,88,89 902 -68 902 -68 882 103 c 0,90,91 873 173 873 173 865 209 c 0,92,93 837 340 837 340 785 427 c 0,94,95 779 437 l 0,96,97 738 501 738 501 667 552 c 0,98,99 645 568 645 568 626 577 c 0,70,71 425 589 m 1,100,101 415 605 415 605 366 589 c 0,102,103 325 576 325 576 325 561 c 0,104,105 325 538 325 538 381 560 c 0,106,107 425 574 425 574 425 589 c 1,100,101 364 510 m 0,108,109 364 527 364 527 333 515 c 0,110,111 312 507 312 507 296 491 c 0,112,113 270 462 270 462 269 435 c 0,114,115 269 422 269 422 278 422 c 0,116,117 285 422 285 422 286 434 c 0,118,119 286 446 286 446 300 446 c 0,120,121 320 446 320 446 335 470 c 0,122,123 341 480 341 480 341 488 c 0,124,125 341 499 341 499 353 502 c 1,126,127 364 502 364 502 364 510 c 0,108,109 552 340 m 0,128,129 565 369 565 369 555 377 c 1,130,131 549 385 549 385 542 369 c 0,132,133 539 359 539 359 529 329 c 1,134,135 525 321 525 321 533 315 c 0,136,137 539 311 539 311 550 336 c 0,138,139 552 340 l 0,128,129 183 229 m 0,140,141 169 244 169 244 158 235 c 0,142,143 155 233 155 233 151 229 c 0,144,145 137 212 137 212 147 190 c 0,146,147 152 179 152 179 161 178 c 1,148,149 176 174 176 174 185 197 c 0,150,151 193 217 193 217 183 229 c 0,140,141 246 161 m 0,152,153 246 176 246 176 243 176 c 0,154,155 233 176 233 176 217 140 c 0,156,157 209 122 209 122 212 118 c 1,158,159 217 108 217 108 234 132 c 0,160,161 246 149 246 149 246 161 c 0,152,153 EndSplineSet EndChar StartChar: P Encoding: 80 80 7 Width: 1023 Flags: W Fore 444 642 m 0,0,1 469 660 469 660 507 660 c 0,2,3 572 660 572 660 604 611 c 0,4,5 635 565 635 565 608 514 c 0,6,7 597 497 597 497 603 491 c 0,8,9 606 488 606 488 619 482 c 0,10,11 644 469 644 469 664 441 c 0,12,13 684 414 684 414 686 387 c 0,14,15 687 375 687 375 687 350 c 0,16,17 687 296 687 296 678 280 c 0,18,19 673 272 673 272 661 257 c 2,20,-1 636 226 l 1,21,-1 655 218 l 2,22,23 694 200 694 200 742 140 c 0,24,25 753 127 753 127 761 114 c 0,26,27 810 38 810 38 813 -64 c 2,28,-1 814 -121 l 1,29,-1 507 -121 l 1,30,-1 202 -121 l 1,31,-1 203 -64 l 2,32,33 206 38 206 38 255 114 c 0,34,35 290 169 290 169 340 205 c 0,36,37 352 214 352 214 361 218 c 2,38,-1 380 226 l 1,39,-1 362 248 l 2,40,41 315 303 315 303 329 381 c 0,42,43 342 453 342 453 397 482 c 0,44,45 416 491 416 491 416 498 c 0,46,47 416 502 416 502 408 514 c 0,48,49 379 571 379 571 418 619 c 0,50,51 429 632 429 632 444 642 c 0,0,1 EndSplineSet EndChar StartChar: Q Encoding: 81 81 8 Width: 1023 Flags: W Fore 468 732 m 0,0,1 488 754 488 754 507 756 c 0,2,3 531 756 531 756 557 723 c 0,4,5 572 704 572 704 572 690 c 0,6,7 572 672 572 672 552 646 c 2,8,-1 532 622 l 1,9,-1 564 472 l 2,10,11 596 321 596 321 598 315 c 0,12,13 600 307 600 307 649 454 c 2,14,-1 698 599 l 1,15,-1 683 619 l 2,16,17 668 636 668 636 667 657 c 0,18,19 667 682 667 682 699 709 c 0,20,21 718 724 718 724 732 724 c 0,22,23 755 724 755 724 781 691 c 0,24,25 795 672 795 672 795 657 c 0,26,27 795 634 795 634 770 608 c 0,28,29 758 596 758 596 751 596 c 0,30,31 740 596 740 596 745 492 c 0,32,33 747 386 747 386 754 343 c 2,34,-1 758 299 l 1,35,-1 823 414 l 2,36,37 880 515 880 515 881 531 c 0,38,39 882 538 882 538 877 545 c 0,40,41 849 583 849 583 888 622 c 0,42,43 934 666 934 666 971 620 c 0,44,45 1012 573 1012 573 971 533 c 0,46,47 961 522 961 522 945 514 c 0,48,49 931 508 931 508 923 480 c 0,50,51 916 454 916 454 900 357 c 0,52,53 877 222 877 222 869 202 c 0,54,55 862 186 862 186 836 154 c 0,56,57 807 119 807 119 796 71 c 0,58,59 787 31 787 31 793 16 c 0,60,61 796 7 796 7 811 -21 c 0,62,63 840 -73 840 -73 824 -92 c 0,64,65 806 -114 806 -114 692 -128 c 2,66,67 690 -129 690 -129 687 -129 c 0,68,69 511 -149 511 -149 338 -130 c 0,70,71 333 -130 333 -130 329 -129 c 0,72,73 212 -114 212 -114 193 -93 c 0,74,75 176 -74 176 -74 205 -21 c 0,76,77 227 19 227 19 226 34 c 0,78,79 226 43 226 43 220 71 c 0,80,81 209 119 209 119 180 154 c 0,82,83 151 191 151 191 144 213 c 0,84,85 137 236 137 236 116 357 c 0,86,87 94 490 94 490 83 505 c 0,88,89 79 511 79 511 71 514 c 0,90,91 12 545 12 545 28 592 c 0,92,93 33 606 33 606 45 620 c 0,94,95 82 666 82 666 128 622 c 0,96,97 167 583 167 583 139 545 c 0,98,99 130 531 130 531 144 503 c 0,100,101 154 481 154 481 193 414 c 2,102,-1 258 299 l 1,103,-1 262 343 l 2,104,105 269 386 269 386 271 492 c 0,106,107 276 596 276 596 265 596 c 0,108,109 251 596 251 596 232 627 c 0,110,111 221 645 221 645 221 657 c 0,112,113 221 682 221 682 253 710 c 0,114,115 270 724 270 724 282 724 c 0,116,117 308 724 308 724 334 691 c 0,118,119 349 672 349 672 349 657 c 0,120,121 349 638 349 638 333 619 c 2,122,-1 318 599 l 1,123,-1 367 454 l 2,124,125 416 307 416 307 418 315 c 0,126,127 420 321 420 321 452 472 c 2,128,-1 484 622 l 1,129,-1 464 646 l 2,130,131 426 691 426 691 468 732 c 0,0,1 679 152 m 0,132,133 561 166 561 166 390 155 c 0,134,135 349 153 349 153 323 149 c 0,136,137 237 138 237 138 248 117 c 0,138,139 250 114 250 114 252 112 c 0,140,141 261 102 261 102 322 114 c 0,142,143 419 130 419 130 600 122 c 0,144,145 661 119 661 119 694 114 c 0,146,147 755 102 755 102 764 112 c 0,148,149 780 129 780 129 735 142 c 0,150,151 713 147 713 147 679 152 c 0,132,133 671 56 m 0,152,153 582 70 582 70 407 62 c 0,154,155 359 60 359 60 333 56 c 0,156,157 263 45 263 45 263 26 c 0,158,159 263 22 263 22 267 18 c 0,160,161 274 10 274 10 325 19 c 0,162,163 390 28 390 28 507 28 c 0,164,165 626 28 626 28 691 19 c 0,166,167 742 10 742 10 749 18 c 0,168,169 765 34 765 34 721 46 c 0,170,171 701 52 701 52 671 56 c 0,152,153 EndSplineSet EndChar StartChar: R Encoding: 82 82 9 Width: 1023 Flags: W Fore 196 671 m 1,0,1 200 677 200 677 270 675 c 2,2,-1 338 671 l 1,3,-1 340 643 l 1,4,-1 342 613 l 1,5,-1 389 613 l 1,6,-1 436 613 l 1,7,-1 438 643 l 1,8,-1 441 671 l 1,9,-1 512 671 l 1,10,-1 582 671 l 1,11,-1 586 643 l 1,12,-1 588 613 l 1,13,-1 630 613 l 1,14,-1 674 613 l 1,15,-1 676 643 l 1,16,-1 679 671 l 1,17,-1 750 671 l 1,18,-1 821 671 l 1,19,-1 824 600 l 1,20,-1 826 527 l 1,21,-1 782 490 l 1,22,-1 738 452 l 1,23,-1 738 284 l 1,24,-1 738 116 l 1,25,-1 770 86 l 2,26,27 797 58 797 58 800 40 c 0,28,29 802 32 802 32 802 13 c 2,30,-1 802 -29 l 1,31,-1 836 -32 l 1,32,-1 870 -34 l 1,33,-1 870 -79 l 1,34,-1 870 -121 l 1,35,-1 507 -121 l 1,36,-1 146 -121 l 1,37,-1 146 -79 l 1,38,-1 146 -34 l 1,39,-1 180 -32 l 1,40,-1 214 -29 l 1,41,-1 214 13 l 2,42,43 214 48 214 48 226 64 c 0,44,45 232 71 232 71 246 86 c 2,46,-1 278 116 l 1,47,-1 278 284 l 1,48,-1 278 452 l 1,49,-1 234 490 l 1,50,-1 191 527 l 1,51,-1 191 596 l 2,52,53 191 666 191 666 196 671 c 1,0,1 773 533 m 0,54,55 773 542 773 542 697 545 c 0,56,57 653 546 653 546 510 548 c 0,58,59 264 548 264 548 244 540 c 0,60,61 233 536 233 536 244 525 c 0,62,63 252 517 252 517 513 519 c 0,64,65 757 521 757 521 770 529 c 0,66,67 773 531 773 531 773 533 c 0,54,55 703 462 m 0,68,69 703 471 703 471 636 473 c 0,70,71 603 474 603 474 510 476 c 0,72,73 324 478 324 478 311 468 c 0,74,75 306 463 306 463 315 454 c 0,76,77 323 445 323 445 513 448 c 0,78,79 692 450 692 450 701 458 c 0,80,81 703 460 703 460 703 462 c 0,68,69 703 121 m 0,82,83 703 130 703 130 636 132 c 0,84,85 603 133 603 133 510 135 c 0,86,87 319 137 319 137 310 124 c 0,88,89 307 120 307 120 315 112 c 0,90,91 322 105 322 105 513 105 c 0,92,93 688 109 688 109 700 116 c 0,94,95 703 118 703 118 703 121 c 0,82,83 750 57 m 0,96,97 750 66 750 66 663 69 c 0,98,99 617 70 617 70 510 71 c 0,100,101 285 73 285 73 266 64 c 0,102,103 257 59 257 59 268 48 c 0,104,105 275 41 275 41 513 43 c 0,106,107 736 45 736 45 748 53 c 0,108,109 750 55 750 55 750 57 c 0,96,97 766 -46 m 0,110,111 766 -37 766 -37 671 -34 c 0,112,113 622 -33 622 -33 510 -32 c 0,114,115 268 -30 268 -30 250 -40 c 0,116,117 241 -45 241 -45 252 -55 c 1,118,119 257 -62 257 -62 513 -60 c 0,120,121 749 -57 749 -57 763 -50 c 0,122,123 766 -49 766 -49 766 -46 c 0,110,111 EndSplineSet EndChar StartChar: b Encoding: 98 98 10 Width: 1023 Flags: W Fore 461 732 m 0,0,1 481 756 481 756 507 756 c 0,2,3 538 756 538 756 565 723 c 0,4,5 579 705 579 705 579 690 c 0,6,7 579 669 579 669 564 652 c 2,8,-1 548 630 l 1,9,-1 594 601 l 2,10,11 739 504 739 504 753 401 c 0,12,13 755 382 755 382 754 363 c 0,14,15 746 293 746 293 709 240 c 0,16,17 701 228 701 228 693 221 c 2,18,-1 676 206 l 1,19,-1 698 139 l 2,20,21 724 72 724 72 720 61 c 0,22,23 713 46 713 46 596 29 c 2,24,-1 560 23 l 1,25,-1 584 11 l 2,26,27 606 -1 606 -1 703 -2 c 0,28,29 719 -2 719 -2 742 -2 c 0,30,31 865 -2 865 -2 891 -11 c 0,32,33 899 -14 899 -14 911 -20 c 0,34,35 940 -36 940 -36 949 -45 c 1,36,37 953 -54 953 -54 914 -112 c 0,38,39 895 -141 895 -141 889 -141 c 0,40,41 882 -141 882 -141 853 -129 c 0,42,43 827 -117 827 -117 750 -120 c 0,44,45 736 -120 736 -120 718 -121 c 0,46,47 626 -127 626 -127 601 -120 c 0,48,49 588 -116 588 -116 561 -105 c 2,50,-1 507 -86 l 1,51,-1 455 -105 l 2,52,53 410 -124 410 -124 378 -124 c 0,54,55 359 -125 359 -125 298 -121 c 0,56,57 197 -116 197 -116 171 -126 c 0,58,59 168 -127 168 -127 164 -129 c 0,60,61 133 -141 133 -141 127 -141 c 0,62,63 117 -141 117 -141 83 -82 c 0,64,65 65 -50 65 -50 67 -45 c 1,66,67 76 -36 76 -36 105 -20 c 0,68,69 135 -5 135 -5 182 -3 c 0,70,71 209 -2 209 -2 274 -2 c 0,72,73 402 -2 402 -2 426 8 c 0,74,75 429 10 429 10 432 11 c 2,76,-1 456 23 l 1,77,-1 420 29 l 2,78,79 303 46 303 46 296 61 c 0,80,81 292 72 292 72 318 139 c 2,82,-1 341 206 l 1,83,-1 323 221 l 2,84,85 288 253 288 253 270 326 c 0,86,87 265 346 265 346 264 363 c 0,88,89 255 471 255 471 375 567 c 0,90,91 396 584 396 584 422 601 c 2,92,-1 468 630 l 1,93,-1 452 652 l 2,94,95 419 693 419 693 461 732 c 0,0,1 536 711 m 0,96,97 523 724 523 724 507 724 c 0,98,99 488 724 488 724 474 703 c 0,100,101 468 695 468 695 468 688 c 0,102,103 468 670 468 670 491 658 c 0,104,105 500 653 500 653 507 653 c 0,106,107 529 653 529 653 543 673 c 0,108,109 548 681 548 681 548 688 c 0,110,111 548 701 548 701 536 711 c 0,96,97 570 580 m 0,112,113 507 621 507 621 506 621 c 0,114,115 494 618 494 618 401 548 c 0,116,117 361 517 361 517 352 507 c 0,118,119 304 463 304 463 296 393 c 0,120,121 295 377 295 377 296 362 c 0,122,123 301 314 301 314 332 259 c 0,124,125 343 240 343 240 350 236 c 0,126,127 364 228 364 228 574 231 c 0,128,129 660 232 660 232 666 236 c 0,130,131 685 247 685 247 708 312 c 0,132,133 718 342 718 342 720 362 c 0,134,135 724 403 724 403 705 445 c 0,136,137 687 492 687 492 627 538 c 0,138,139 605 555 605 555 570 580 c 0,112,113 620 195 m 0,140,141 574 202 574 202 430 198 c 0,142,143 399 197 399 197 388 195 c 0,144,145 365 190 365 190 360 166 c 2,146,-1 352 141 l 1,147,-1 507 141 l 1,148,-1 664 141 l 1,149,-1 656 165 l 2,150,151 650 186 650 186 637 191 c 0,152,153 631 193 631 193 620 195 c 0,140,141 664 100 m 0,154,155 633 107 633 107 459 109 c 0,156,157 415 110 415 110 405 108 c 0,158,159 396 106 396 106 360 100 c 0,160,161 336 97 336 97 333 86 c 1,162,163 333 70 333 70 435 60 c 0,164,165 472 57 472 57 507 57 c 0,166,167 624 57 624 57 671 79 c 0,168,169 696 91 696 91 664 100 c 0,154,155 555 -8 m 2,170,171 514 18 514 18 506 18 c 0,172,173 499 18 499 18 457 -9 c 2,174,-1 418 -34 l 1,175,-1 282 -34 l 2,176,177 150 -34 150 -34 125 -45 c 0,178,179 108 -54 108 -54 108 -59 c 0,180,181 108 -63 108 -63 117 -79 c 0,182,183 130 -99 130 -99 141 -99 c 1,184,185 145 -98 145 -98 151 -96 c 0,186,187 173 -90 173 -90 294 -90 c 0,188,189 404 -90 404 -90 431 -81 c 0,190,191 443 -78 443 -78 463 -68 c 2,192,-1 507 -47 l 1,193,-1 554 -68 l 2,194,195 591 -86 591 -86 631 -89 c 0,196,197 654 -90 654 -90 722 -90 c 0,198,199 843 -90 843 -90 865 -96 c 0,200,201 882 -102 882 -102 892 -89 c 0,202,203 895 -85 895 -85 899 -79 c 0,204,205 910 -59 910 -59 906 -54 c 0,206,207 903 -51 903 -51 891 -45 c 0,208,209 866 -34 866 -34 732 -34 c 2,210,-1 598 -34 l 1,211,-1 555 -8 l 2,170,171 498 489 m 0,212,213 513 505 513 505 519 474 c 0,214,215 521 465 521 465 521 452 c 2,216,-1 525 415 l 1,217,-1 562 412 l 2,218,219 599 411 599 411 599 398 c 0,220,221 599 387 599 387 562 384 c 2,222,-1 525 382 l 1,223,-1 521 348 l 2,224,225 521 315 521 315 507 315 c 0,226,227 495 315 495 315 495 348 c 2,228,-1 491 382 l 1,229,-1 454 384 l 2,230,231 417 387 417 387 417 398 c 0,232,233 417 411 417 411 455 412 c 2,234,-1 492 415 l 1,235,-1 492 449 l 2,236,237 492 483 492 483 498 489 c 0,212,213 EndSplineSet EndChar StartChar: k Encoding: 107 107 11 Width: 1023 Flags: W Fore 498 735 m 0,0,1 508 746 508 746 516 732 c 0,2,3 520 725 520 725 521 714 c 0,4,5 525 696 525 696 538 693 c 0,6,7 542 692 542 692 550 691 c 0,8,9 577 688 577 688 576 675 c 0,10,11 575 663 575 663 550 662 c 0,12,13 529 660 529 660 526 653 c 0,14,15 524 646 524 646 524 622 c 0,16,17 525 589 525 589 536 579 c 0,18,19 540 575 540 575 550 570 c 1,20,21 596 538 596 538 603 479 c 0,22,23 604 471 604 471 604 464 c 2,24,-1 604 430 l 1,25,-1 647 455 l 2,26,27 736 504 736 504 826 472 c 0,28,29 899 446 899 446 930 379 c 0,30,31 977 273 977 273 853 162 c 2,32,-1 802 115 l 1,33,-1 797 25 l 2,34,35 794 -63 794 -63 783 -75 c 0,36,37 773 -85 773 -85 703 -105 c 0,38,39 556 -148 556 -148 384 -123 c 0,40,41 320 -113 320 -113 268 -94 c 0,42,43 232 -81 232 -81 224 -66 c 0,44,45 214 -49 214 -49 214 36 c 2,46,-1 214 114 l 1,47,-1 164 161 l 2,48,49 40 276 40 276 85 377 c 0,50,51 99 408 99 408 129 435 c 0,52,53 205 504 205 504 305 480 c 0,54,55 338 473 338 473 369 455 c 2,56,-1 412 430 l 1,57,-1 412 464 l 2,58,59 412 525 412 525 457 563 c 0,60,61 461 567 461 567 466 570 c 0,62,63 487 581 487 581 490 597 c 0,64,65 491 604 491 604 492 622 c 0,66,67 492 655 492 655 485 659 c 0,68,69 481 661 481 661 468 662 c 0,70,71 441 665 441 665 441 676 c 0,72,73 441 688 441 688 468 691 c 1,74,75 490 699 490 699 492 711 c 1,76,77 492 729 492 729 498 735 c 0,0,1 540 541 m 0,78,79 496 565 496 565 466 528 c 0,80,81 436 493 436 493 448 432 c 0,82,83 456 395 456 395 493 325 c 0,84,85 504 304 504 304 507 304 c 0,86,87 518 304 518 304 550 384 c 0,88,89 566 424 566 424 568 442 c 0,90,91 575 493 575 493 553 528 c 0,92,93 547 537 547 537 540 541 c 0,78,79 360 424 m 0,94,95 269 475 269 475 185 435 c 0,96,97 98 394 98 394 107 314 c 0,98,99 113 253 113 253 176 189 c 0,100,101 216 149 216 149 231 147 c 0,102,103 236 146 236 146 244 148 c 0,104,105 339 173 339 173 431 180 c 0,106,107 481 186 481 186 488 195 c 0,108,109 496 205 496 205 481 257 c 0,110,111 479 262 479 262 476 272 c 0,112,113 448 365 448 365 375 415 c 0,114,115 368 420 368 420 360 424 c 0,94,95 834 432 m 0,116,117 762 468 762 468 696 443 c 0,118,119 579 400 579 400 538 270 c 0,120,121 521 214 521 214 525 202 c 0,122,123 530 188 530 188 577 182 c 0,124,125 586 181 586 181 611 178 c 0,126,127 707 165 707 165 741 156 c 2,128,-1 788 144 l 1,129,-1 825 175 l 2,130,131 915 251 915 251 909 330 c 0,132,133 905 396 905 396 834 432 c 0,116,117 623 144 m 0,134,135 494 163 494 163 364 139 c 0,136,137 272 124 272 124 259 115 c 0,138,139 249 108 249 108 248 79 c 0,140,141 245 43 245 43 253 43 c 0,142,143 256 43 256 43 260 45 c 0,144,145 351 73 351 73 451 75 c 0,146,147 476 76 476 76 512 76 c 0,148,149 636 75 636 75 700 60 c 2,150,-1 762 45 l 1,151,-1 768 70 l 1,152,153 770 102 770 102 768 107 c 0,154,155 761 125 761 125 623 144 c 0,134,135 635 38 m 0,156,157 555 53 555 53 445 48 c 0,158,159 425 47 425 47 412 45 c 1,160,161 396 40 396 40 320 25 c 0,162,163 256 11 256 11 249 2 c 0,164,165 246 -2 246 -2 246 -14 c 2,166,-1 246 -38 l 1,167,-1 295 -21 l 2,168,169 446 24 446 24 614 2 c 0,170,171 655 -4 655 -4 691 -13 c 0,172,173 754 -31 754 -31 759 -27 c 0,174,175 762 -25 762 -25 762 -11 c 0,176,177 762 6 762 6 735 16 c 0,178,179 712 24 712 24 635 38 c 0,156,157 671 -42 m 0,180,181 604 -26 604 -26 479 -24 c 0,182,183 438 -24 438 -24 421 -27 c 0,184,185 300 -49 300 -49 286 -63 c 1,186,187 286 -79 286 -79 400 -92 c 0,188,189 457 -98 457 -98 507 -98 c 0,190,191 624 -98 624 -98 701 -75 c 0,192,193 723 -68 723 -68 727 -62 c 1,194,195 729 -56 729 -56 671 -42 c 0,180,181 EndSplineSet EndChar StartChar: n Encoding: 110 110 12 Width: 1023 Flags: W Fore 265 712 m 0,0,1 269 724 269 724 279 720 c 1,2,3 326 692 326 692 369 652 c 0,4,5 377 644 377 644 379 641 c 0,6,7 387 625 387 625 406 650 c 0,8,9 415 661 415 661 428 683 c 0,10,11 452 721 452 721 464 724 c 1,12,13 475 724 475 724 501 679 c 0,14,15 516 652 516 652 516 642 c 0,16,17 516 630 516 630 541 630 c 0,18,19 655 627 655 627 756 522 c 0,20,21 820 457 820 457 858 367 c 0,22,23 908 249 908 249 930 54 c 0,24,25 938 -17 938 -17 938 -75 c 2,26,-1 938 -125 l 1,27,-1 911 -129 l 2,28,29 896 -132 896 -132 599 -132 c 2,30,-1 314 -129 l 1,31,-1 311 -103 l 2,32,33 305 -43 305 -43 412 81 c 0,34,35 495 180 495 180 510 233 c 0,36,37 514 251 l 2,38,-1 518 279 l 1,39,-1 437 237 l 2,40,41 357 194 357 194 338 177 c 0,42,43 323 164 323 164 288 120 c 0,44,45 241 59 241 59 219 67 c 0,46,47 212 70 212 70 206 77 c 0,48,49 198 88 198 88 173 89 c 0,50,51 120 89 120 89 92 131 c 0,52,53 79 152 79 152 79 176 c 0,54,55 79 227 79 227 116 292 c 0,56,57 127 310 127 310 143 335 c 0,58,59 187 403 187 403 195 437 c 0,60,61 208 512 208 512 231 545 c 0,62,63 235 552 235 552 241 559 c 0,64,65 264 587 264 587 266 606 c 0,66,67 266 616 266 616 264 646 c 0,68,69 260 701 260 701 265 712 c 0,0,1 489 611 m 0,70,71 487 645 487 645 473 664 c 0,72,73 464 677 464 677 459 673 c 0,74,75 457 671 457 671 450 660 c 0,76,77 438 641 438 641 432 618 c 0,78,79 425 585 425 585 418 585 c 0,80,81 414 585 414 585 405 591 c 0,82,83 392 599 392 599 378 588 c 0,84,85 372 583 372 583 361 573 c 0,86,87 333 545 333 545 323 555 c 1,88,89 315 566 315 566 338 588 c 0,90,91 365 618 365 618 339 640 c 0,92,93 331 647 331 647 318 655 c 0,94,95 296 668 296 668 295 663 c 1,96,97 294 661 294 661 294 654 c 0,98,99 294 642 294 642 302 614 c 0,100,101 310 593 310 593 302 581 c 0,102,103 298 575 298 575 287 564 c 0,104,105 249 528 249 528 237 477 c 0,106,107 234 465 234 465 231 450 c 0,108,109 223 406 223 406 197 363 c 0,110,111 126 250 126 250 117 216 c 0,112,113 115 211 115 211 114 204 c 0,114,115 107 152 107 152 130 136 c 0,116,117 136 132 136 132 143 129 c 0,118,119 187 110 187 110 214 157 c 0,120,121 233 189 233 189 243 178 c 0,122,123 253 165 253 165 233 128 c 0,124,125 218 96 218 96 229 98 c 0,126,127 236 99 236 99 248 117 c 0,128,129 308 201 308 201 403 254 c 0,130,131 412 259 412 259 422 264 c 0,132,133 492 300 492 300 509 323 c 0,134,135 523 343 523 343 530 393 c 0,136,137 536 434 536 434 548 434 c 0,138,139 562 434 562 434 556 357 c 0,140,141 554 331 554 331 550 291 c 0,142,143 542 211 542 211 513 164 c 0,144,145 494 132 494 132 444 74 c 0,146,147 356 -29 356 -29 343 -81 c 0,148,149 341 -87 341 -87 341 -91 c 0,150,151 341 -102 341 -102 608 -102 c 2,152,-1 877 -102 l 1,153,-1 870 -11 l 2,154,155 847 372 847 372 695 521 c 0,156,157 648 570 648 570 607 582 c 0,158,159 536 606 536 606 526 598 c 0,160,161 523 596 523 596 521 589 c 0,162,163 515 564 515 564 503 575 c 0,164,165 493 584 493 584 489 611 c 0,70,71 289 491 m 0,166,167 316 518 316 518 344 519 c 0,168,169 357 520 357 520 357 510 c 0,170,171 357 502 357 502 345 502 c 0,172,173 336 502 336 502 333 488 c 1,174,175 333 467 333 467 310 452 c 0,176,177 301 446 301 446 292 446 c 0,178,179 278 446 278 446 278 434 c 128,-1,180 278 422 278 422 270 422 c 0,181,182 254 422 254 422 264 452 c 0,183,184 272 474 272 474 289 491 c 0,166,167 143 229 m 0,185,186 157 244 157 244 168 235 c 0,187,188 171 233 171 233 175 229 c 0,189,190 188 212 188 212 173 189 c 0,191,192 164 175 164 175 152 178 c 0,193,194 137 180 137 180 136 204 c 0,195,196 135 219 135 219 143 229 c 0,185,186 EndSplineSet EndChar StartChar: p Encoding: 112 112 13 Width: 1023 Flags: W Fore 444 642 m 0,0,1 469 660 469 660 507 660 c 0,2,3 572 660 572 660 604 611 c 0,4,5 635 565 635 565 608 514 c 0,6,7 597 497 597 497 603 491 c 0,8,9 606 488 606 488 619 482 c 0,10,11 644 469 644 469 664 441 c 0,12,13 684 414 684 414 686 387 c 0,14,15 687 375 687 375 687 350 c 0,16,17 687 296 687 296 678 280 c 0,18,19 673 272 673 272 661 257 c 2,20,-1 636 226 l 1,21,-1 655 218 l 2,22,23 694 200 694 200 742 140 c 0,24,25 753 127 753 127 761 114 c 0,26,27 810 38 810 38 813 -64 c 2,28,-1 814 -121 l 1,29,-1 507 -121 l 1,30,-1 202 -121 l 1,31,-1 203 -64 l 2,32,33 206 38 206 38 255 114 c 0,34,35 290 169 290 169 340 205 c 0,36,37 352 214 352 214 361 218 c 2,38,-1 380 226 l 1,39,-1 362 248 l 2,40,41 315 303 315 303 329 381 c 0,42,43 342 453 342 453 397 482 c 0,44,45 416 491 416 491 416 498 c 0,46,47 416 502 416 502 408 514 c 0,48,49 379 571 379 571 418 619 c 0,50,51 429 632 429 632 444 642 c 0,0,1 555 618 m 0,52,53 509 641 509 641 467 620 c 0,54,55 445 608 445 608 437 588 c 0,56,57 418 544 418 544 452 510 c 0,58,59 455 507 455 507 459 504 c 0,60,61 480 487 480 487 469 478 c 0,62,63 461 471 461 471 427 459 c 0,64,65 381 442 381 442 367 404 c 0,66,67 363 390 363 390 360 371 c 0,68,69 351 308 351 308 390 264 c 0,70,71 399 254 399 254 410 247 c 0,72,73 438 228 438 228 435 223 c 0,74,75 427 212 427 212 381 190 c 0,76,77 256 127 256 127 233 -52 c 2,78,-1 229 -94 l 1,79,-1 507 -94 l 1,80,-1 788 -94 l 1,81,-1 783 -52 l 2,82,83 760 127 760 127 635 190 c 0,84,85 583 215 583 215 581 223 c 1,86,87 578 228 578 228 606 247 c 0,88,89 650 275 650 275 656 336 c 0,90,91 658 354 658 354 656 371 c 0,92,93 648 427 648 427 612 448 c 0,94,95 602 454 602 454 589 459 c 0,96,97 542 476 542 476 542 486 c 0,98,99 542 492 542 492 552 502 c 0,100,101 591 533 591 533 584 576 c 0,102,103 580 604 580 604 555 618 c 0,52,53 EndSplineSet EndChar StartChar: q Encoding: 113 113 14 Width: 1023 Flags: W Fore 464 736 m 0,0,1 482 756 482 756 507 756 c 0,2,3 540 756 540 756 562 725 c 0,4,5 572 710 572 710 572 696 c 0,6,7 572 678 572 678 550 654 c 2,8,-1 529 633 l 1,9,-1 562 473 l 2,10,11 595 314 595 314 598 311 c 1,12,13 599 304 599 304 650 454 c 2,14,-1 702 602 l 1,15,-1 684 625 l 2,16,17 649 668 649 668 687 704 c 0,18,19 727 745 727 745 771 701 c 0,20,21 805 667 805 667 784 638 c 0,22,23 778 629 778 629 766 618 c 2,24,-1 739 591 l 1,25,-1 743 465 l 2,26,27 748 332 748 332 754 320 c 0,28,29 761 306 761 306 784 343 c 0,30,31 791 353 791 353 824 410 c 0,32,33 882 511 882 511 883 527 c 0,34,35 884 534 884 534 878 543 c 0,36,37 850 583 850 583 885 618 c 0,38,39 914 647 914 647 954 631 c 0,40,41 992 616 992 616 993 577 c 0,42,43 993 549 993 549 965 528 c 0,44,45 952 518 952 518 940 518 c 0,46,47 931 518 931 518 928 506 c 0,48,49 922 489 922 489 896 345 c 0,50,51 874 208 874 208 868 198 c 2,52,-1 833 150 l 2,53,54 802 112 802 112 795 70 c 0,55,56 786 31 786 31 794 11 c 0,57,58 797 5 797 5 802 -6 c 0,59,60 816 -36 816 -36 826 -42 c 0,61,62 839 -51 839 -51 831 -82 c 0,63,64 827 -97 827 -97 820 -103 c 0,65,66 801 -121 801 -121 631 -135 c 0,67,68 560 -141 560 -141 507 -141 c 0,69,70 372 -141 372 -141 247 -118 c 0,71,72 204 -110 204 -110 196 -103 c 0,73,74 181 -89 181 -89 183 -59 c 0,75,76 185 -46 185 -46 191 -42 c 0,77,78 200 -35 200 -35 214 -6 c 0,79,80 229 23 229 23 226 44 c 0,81,82 225 53 225 53 221 70 c 0,83,84 214 112 214 112 183 150 c 2,85,-1 148 198 l 2,86,87 142 208 142 208 120 345 c 0,88,89 91 507 91 507 84 515 c 0,90,91 82 518 82 518 76 518 c 0,92,93 51 518 51 518 32 548 c 0,94,95 23 563 23 563 23 577 c 0,96,97 23 615 23 615 60 631 c 0,98,99 100 647 100 647 131 618 c 0,100,101 166 583 166 583 138 543 c 0,102,103 129 529 129 529 139 508 c 0,104,105 147 489 147 489 192 411 c 0,106,107 259 296 259 296 261 300 c 0,108,109 266 310 266 310 271 446 c 2,110,-1 277 591 l 1,111,-1 250 618 l 2,112,113 212 652 212 652 229 681 c 0,114,115 234 690 234 690 245 701 c 0,116,117 289 745 289 745 329 704 c 0,118,119 367 668 367 668 332 625 c 2,120,-1 314 602 l 1,121,-1 366 454 l 2,122,123 418 300 418 300 418 311 c 1,124,125 421 314 421 314 454 473 c 2,126,-1 488 633 l 1,127,-1 468 654 l 2,128,129 424 694 424 694 464 736 c 0,0,1 532 712 m 0,130,131 520 724 520 724 507 724 c 0,132,133 485 724 485 724 480 700 c 0,134,135 474 673 474 673 496 664 c 0,136,137 520 657 520 657 533 679 c 0,138,139 544 697 544 697 532 712 c 0,130,131 308 683 m 0,140,141 296 693 296 693 289 693 c 0,142,143 276 693 276 693 260 673 c 0,144,145 254 665 254 665 254 660 c 0,146,147 254 650 254 650 275 635 c 0,148,149 282 629 282 629 286 629 c 0,150,151 298 629 298 629 313 651 c 0,152,153 318 659 318 659 318 664 c 0,154,155 318 673 318 673 308 683 c 0,140,141 749 679 m 0,156,157 728 701 728 701 708 683 c 1,158,159 698 671 698 671 698 664 c 0,160,161 698 651 698 651 718 635 c 0,162,163 725 629 725 629 730 629 c 0,164,165 739 629 739 629 749 641 c 0,166,167 762 654 762 654 762 660 c 0,168,169 762 668 762 668 749 679 c 0,156,157 111 593 m 0,170,171 95 612 95 612 72 602 c 0,172,173 56 594 56 594 56 577 c 0,174,175 56 548 56 548 95 548 c 0,176,177 111 548 111 548 116 568 c 0,178,179 120 583 120 583 111 593 c 0,170,171 948 600 m 1,180,181 919 612 919 612 904 592 c 0,182,183 896 581 896 581 901 565 c 0,184,185 909 544 909 544 935 549 c 0,186,187 959 555 959 555 960 577 c 0,188,189 960 597 960 597 948 600 c 1,180,181 543 409 m 0,190,191 511 548 511 548 507 548 c 0,192,193 501 548 501 548 460 337 c 0,194,195 446 267 446 267 448 265 c 0,196,197 453 260 453 260 480 271 c 0,198,199 508 281 508 281 536 271 c 0,200,201 563 260 563 260 568 265 c 1,202,203 570 269 570 269 543 409 c 0,190,191 357 376 m 0,204,205 324 485 324 485 312 506 c 1,206,207 308 511 308 511 306 494 c 0,208,209 302 469 302 469 299 390 c 0,210,211 294 262 294 262 298 255 c 1,212,213 306 255 306 255 325 264 c 0,214,215 351 273 351 273 371 264 c 0,216,217 393 256 393 256 394 258 c 0,218,219 396 263 396 263 357 376 c 0,204,205 718 255 m 1,220,221 720 258 720 258 716 387 c 0,222,223 709 513 709 513 704 503 c 0,224,225 691 483 691 483 636 310 c 0,226,227 620 259 620 259 622 258 c 1,228,229 623 256 623 256 645 264 c 0,230,231 665 273 665 273 691 264 c 0,232,233 710 255 710 255 718 255 c 1,220,221 202 333 m 0,234,235 143 428 143 428 144 427 c 1,236,237 134 438 134 438 134 437 c 0,238,239 134 435 134 435 137 423 c 2,240,-1 156 320 l 2,241,242 169 235 169 235 171 233 c 0,243,244 174 230 174 230 193 243 c 1,245,246 215 253 215 253 229 250 c 0,247,248 246 246 246 246 246 251 c 256,249,250 246 256 246 256 202 333 c 0,234,235 864 335 m 0,251,252 879 436 879 436 878 436 c 1,253,254 876 440 876 440 794 295 c 0,255,256 770 254 770 254 770 251 c 0,257,258 770 246 770 246 788 250 c 0,259,260 801 253 801 253 823 243 c 1,261,262 842 230 842 230 845 233 c 1,263,264 845 230 845 230 864 335 c 0,251,252 536 236 m 0,265,266 505 247 505 247 504 247 c 1,267,268 504 245 504 245 476 236 c 0,269,270 435 219 435 219 385 226 c 0,271,272 373 228 373 228 366 231 c 1,273,274 352 240 352 240 321 229 c 0,275,276 298 218 298 218 248 216 c 0,277,278 210 216 210 216 196 206 c 0,279,280 186 198 186 198 193 186 c 0,281,282 197 180 197 180 209 166 c 2,283,-1 236 136 l 1,284,-1 328 148 l 2,285,286 423 161 423 161 507 161 c 0,287,288 595 161 595 161 688 148 c 2,289,-1 780 136 l 1,290,-1 807 166 l 2,291,292 830 193 830 193 826 200 c 1,293,294 824 202 824 202 820 206 c 1,295,296 806 216 806 216 769 216 c 0,297,298 730 216 730 216 698 229 c 0,299,300 665 239 665 239 652 232 c 0,301,302 620 217 620 217 563 228 c 0,303,304 548 231 548 231 536 236 c 0,265,266 679 117 m 2,305,306 510 139 510 139 346 118 c 0,307,308 339 117 339 117 333 116 c 0,309,310 258 105 258 105 253 105 c 0,311,312 247 105 247 105 257 64 c 0,313,314 261 48 261 48 264 45 c 1,315,316 306 52 l 2,317,318 350 60 350 60 507 60 c 0,319,320 666 60 666 60 710 52 c 0,321,322 741 45 741 45 754 45 c 1,323,-1 768 105 l 1,324,325 679 117 l 2,305,306 712 18 m 0,326,327 641 29 641 29 455 30 c 0,328,329 407 31 407 31 389 29 c 0,330,331 257 13 257 13 251 -4 c 0,332,333 245 -18 245 -18 248 -18 c 2,334,335 333 -11 l 2,336,337 502 13 502 13 674 -10 c 0,338,339 678 -10 678 -10 683 -11 c 0,340,341 767 -18 767 -18 768 -18 c 0,342,343 770 -18 770 -18 766 -4 c 0,344,345 762 6 762 6 712 18 c 0,326,327 687 -43 m 0,346,347 497 -20 497 -20 318 -45 c 0,348,349 226 -55 226 -55 216 -71 c 0,350,351 214 -74 214 -74 214 -79 c 0,352,353 214 -87 214 -87 401 -104 c 0,354,355 474 -110 474 -110 507 -110 c 0,356,357 598 -110 598 -110 756 -88 c 0,358,359 802 -82 802 -82 802 -79 c 0,360,361 802 -62 802 -62 758 -53 c 0,362,363 735 -49 735 -49 687 -43 c 0,346,347 EndSplineSet EndChar StartChar: r Encoding: 114 114 15 Width: 1023 Flags: W Fore 196 671 m 1,0,1 200 677 200 677 270 675 c 2,2,-1 338 671 l 1,3,-1 340 643 l 1,4,-1 342 613 l 1,5,-1 389 613 l 1,6,-1 436 613 l 1,7,-1 438 643 l 1,8,-1 441 671 l 1,9,-1 512 671 l 1,10,-1 582 671 l 1,11,-1 586 643 l 1,12,-1 588 613 l 1,13,-1 630 613 l 1,14,-1 674 613 l 1,15,-1 676 643 l 1,16,-1 679 671 l 1,17,-1 750 671 l 1,18,-1 821 671 l 1,19,-1 824 600 l 1,20,-1 826 527 l 1,21,-1 782 490 l 1,22,-1 738 452 l 1,23,-1 738 282 l 1,24,-1 738 114 l 1,25,-1 770 87 l 2,26,27 796 64 796 64 800 49 c 0,28,29 802 40 802 40 802 15 c 2,30,-1 802 -29 l 1,31,-1 836 -32 l 1,32,-1 870 -34 l 1,33,-1 870 -79 l 1,34,-1 870 -121 l 1,35,-1 507 -121 l 1,36,-1 146 -121 l 1,37,-1 146 -79 l 1,38,-1 146 -34 l 1,39,-1 180 -32 l 1,40,-1 214 -29 l 1,41,-1 214 15 l 2,42,43 214 53 214 53 224 66 c 0,44,45 230 73 230 73 246 87 c 2,46,-1 278 114 l 1,47,-1 278 282 l 1,48,-1 278 452 l 1,49,-1 234 490 l 1,50,-1 191 527 l 1,51,-1 191 596 l 2,52,53 191 666 191 666 196 671 c 1,0,1 311 615 m 1,54,-1 309 645 l 1,55,-1 265 645 l 1,56,-1 221 645 l 1,57,-1 221 596 l 1,58,-1 221 548 l 1,59,-1 507 548 l 1,60,-1 795 548 l 1,61,-1 795 596 l 1,62,-1 795 645 l 1,63,-1 751 645 l 1,64,-1 707 645 l 1,65,-1 705 615 l 1,66,-1 703 585 l 1,67,-1 630 585 l 1,68,-1 560 585 l 1,69,-1 557 615 l 1,70,-1 555 645 l 1,71,-1 512 645 l 1,72,-1 469 645 l 1,73,-1 468 615 l 1,74,-1 464 585 l 1,75,-1 389 585 l 1,76,-1 314 585 l 1,77,-1 311 615 l 1,54,-1 744 498 m 1,78,-1 766 517 l 1,79,-1 507 517 l 1,80,-1 250 517 l 1,81,-1 272 498 l 1,82,-1 294 478 l 1,83,-1 507 478 l 1,84,-1 722 478 l 1,85,-1 744 498 l 1,78,-1 705 291 m 1,86,-1 705 446 l 1,87,-1 507 446 l 1,88,-1 311 446 l 1,89,-1 311 291 l 1,90,-1 311 137 l 1,91,-1 507 137 l 1,92,-1 705 137 l 1,93,-1 705 291 l 1,86,-1 727 89 m 0,94,95 715 101 715 101 677 103 c 0,96,97 643 105 643 105 507 105 c 0,98,99 322 105 322 105 302 98 c 0,100,101 295 95 295 95 289 89 c 0,102,103 281 80 281 80 290 77 c 0,104,105 306 73 306 73 507 73 c 0,106,107 719 73 719 73 730 78 c 1,108,109 734 81 734 81 727 89 c 0,94,95 770 6 m 1,110,-1 770 41 l 1,111,-1 507 41 l 1,112,-1 246 41 l 1,113,-1 246 6 l 1,114,-1 246 -30 l 1,115,-1 507 -30 l 1,116,-1 770 -30 l 1,117,-1 770 6 l 1,110,-1 841 -79 m 0,118,119 841 -70 841 -70 830 -67 c 0,120,121 806 -62 806 -62 507 -62 c 0,122,123 207 -62 207 -62 185 -68 c 0,124,125 175 -70 175 -70 175 -79 c 0,126,127 175 -87 175 -87 185 -89 c 0,128,129 207 -94 207 -94 507 -94 c 0,130,131 813 -94 813 -94 833 -88 c 0,132,133 841 -86 841 -86 841 -79 c 0,118,119 EndSplineSet EndChar EndChars EndSplineFont tagua-1.0-alpha2/data/themes/pieces/XBoardTTF/XBoard.ttf000066400000000000000000000176401077523320400227340ustar00rootroot00000000000000`FFTMD %GDEF'dOS/2VbxhVcmap:4cvt "xgasp\glyf(head6hhea:$$hmtxY*loca*d%X|"maxpaH name>IOpostIB3_<JJJJ4224\i@.3 PfEd+r332"UGIWBIOh +BKNRbknr +BKNPbknp ",,,:vjx "w./<2<2/<2<23!%!!"UV"f42!!2GsZu63232#"'&'&/'&#"'&5476763276?'&/7654'&'4?'&7&3325?674/4'&'&3276&#"327654!-+GE+Hx $' ri +'$Kr !' 95x ED--!"D%&!% %$%%i \t {mr<I "nmP: ==   0   2  == >Qmn()*#" $''$   F  I{Ma676'&'&'&='&76765476767674'&'&547674&#"327654'&&7676'&'&#"'&'&'&&'&7676'&&'&7676'&632#"'&546'&?676%6'&/767676    .+YZI/|3 G@4$ 2|-Ld!+- 8&  TO@ =;Fo1$F;% /XZ@0 C :5Im =d4#>+ 5< ;H@d8'@1   ?F!8B*5X" 58 ""5,(;8 &    !  ;"1 Cjp/\S+  UN/seE"=& !  /". DDA)P+&>/. 30   0jVBG4M! WH#  E    (1 E%"I! .M<'  0/4 !;; $WDai}676767)7676767676'"'&'&#"'&54767676767676'&&3276'&'&/&'&'&7643274327654726'&7&764#"76 .+   0]W2N,Q0 0 4% , fM '{.    4)G 1)8,=        5   #!  ,5 [&0C%[< *4 = *3AD"K% 7|# Q?Fy F$W @3 @     k  8$ .3632)767676?'&767654'&76&A     '0 11#2 / 7' 1.3  6< Lf99fL7$ 7NH  90 t672?'&'47632#"7676'&76#'"'&'&76'4'&'&'&'&'&'&76767676#"'&54763276?'&&7676'&&763276'& 11   A9'.%))  ru  ; %.'  'A   11 &v)V  =a=!= -*Y0F3AuwA3,!! hj+,se&',./( a #0( 45( 0#%y/.,'&Cs,+jh !-     [   f5CQ_m{6;?;;?;)=?5476?=/544'&'"%6764'&'&76764'&'&36764'&'&76764'&'&%676FD//GF*,GG,, """"  ,+FL,  FC!]   C!]  /W.k  _1p GI%&*-**-*#&%EF  E     =   e   Bs_o632232#"'&"'&/#'&#"'&7676763276?'&'&?'&'&'&76?'&7&#"327654&#76767676'&'&&;'&'&&'&3276&#"#"36763276?327676'&'&+6#"5/&54?54.%u$a{  'M\ 64- =e " /A$u# x.!u  ? ]( 0 V <.  !, $f%#u/)*' yn ,/%(Dy   d%%%% %%&%!agF5 CC    :    ;     CC Il`)   y)F ,F07 A)*/.]   c       % "!!" ""I{M]s676'&'&'&='&76765476767674'&'&547674&327676'&&767676'&'&'&%&76'&&327676376'&&767654'&&'"327676    .+YZI/|3 F@4$ 2|-Ld!+- 0, %  [TW ?(_\2IHBu)/ `"/%Z恂\ [d$|@>~Pn L@1)$?)C})yr92uM   !  ;"1 Cjo/ZX +  UN/seE"=& !  %#=%FP(3# q3()P=@( 4 ]2 $+8  LOB $ W  -  B O|D67676723!%'&76?'&'&'"'&54767676767674'&&'&#"'&'&76'&'&7676767676767632)''&'&'&676#"#"#"766'&'&  /+  re@&2kSQP#/5 % ,        & G ,   <_ F 2X   /)G         ( &- iAZvG:2<|c5*+ ,= *3AD"K! 7Z"  !       $3 ,+q"4/ % T5$2)M(P/ :g4 [1  ]  .3g632)767676?'&767654'&76&)'&'&'&7676'&'&'&5476'&&A     '0 11#2 / 7' ~.*" ". ' .}}4,$ / '1.3  6< Lf99fL7$ 7NH  90  ,"  &?,  ?**?=8  +s0CVh632?'&76767676'&76#"#"'&'&767676'&'&/&'&'&#"'&547676?'&767656?'&7&#"76&#"327654%&327654&3276%&7674&#"7676'&'&276766'&76%&&7654%6#&767%&#'&'&"763276'&'&#"'&'&&#"763237&'&376232'&&327654'&! !!34#&(," !:#(& #  G5}+ # %(# -C& ,(&#44!",l      u'<_ )! B 7;  jR )2 2&  \_TX]\%' ! 9K *,, 8G0UTK\ I![.,+$)," ~ % 9e (#'  0&*'    *&0 &#(Ns " ,)$+ (        K   F kmO ~ 3 N_  gU Oe)         r ) Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/black_cannon.svg000066400000000000000000000047141077523320400243500ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/black_chariot.svg000066400000000000000000000046531077523320400245270ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/black_elephant.svg000066400000000000000000000047411077523320400246740ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/black_general.svg000066400000000000000000000051041077523320400245030ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/black_horse.svg000066400000000000000000000051541077523320400242130ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/black_soldier.svg000066400000000000000000000043271077523320400245350ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/circle.svg000066400000000000000000000045661077523320400232060ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/inner_circle.svg000066400000000000000000000045701077523320400243740ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/red_advisor.svg000066400000000000000000000041571077523320400242420ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/red_cannon.svg000066400000000000000000000050241077523320400240410ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/red_chariot.svg000066400000000000000000000050211077523320400242130ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/red_elephant.svg000066400000000000000000000046131077523320400243700ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/red_general.svg000066400000000000000000000045311077523320400242040ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/red_horse.svg000066400000000000000000000055361077523320400237150ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiSVG/red_soldier.svg000066400000000000000000000044161077523320400242320ustar00rootroot00000000000000 Created by potrace 1.7, written by Peter Selinger 2001-2005 image/svg+xml tagua-1.0-alpha2/data/themes/pieces/XiangQiTTF/000077500000000000000000000000001077523320400212075ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/XiangQiTTF/XiangQi.sfd000066400000000000000000000551431077523320400232550ustar00rootroot00000000000000SplineFontDB: 1.0 FontName: XiangQi FullName: XiangQi FamilyName: XiangQi Weight: Medium Copyright: Created by Monge Maurizio with FontForge 1.0 (http://fontforge.sf.net) Version: 001.000 ItalicAngle: 0 UnderlinePosition: -100 UnderlineWidth: 50 Ascent: 51 Descent: 13 Order2: 1 XUID: [1021 645 1811818106 11622961] FSType: 0 OS2Version: 0 OS2_WeightWidthSlopeOnly: 0 OS2_UseTypoMetrics: 0 CreationTime: 1160082499 ModificationTime: 1160236156 PfmFamily: 17 TTFWeight: 500 TTFWidth: 5 LineGap: 6 VLineGap: 0 Panose: 2 0 6 3 0 0 0 0 0 0 OS2TypoAscent: 0 OS2TypoAOffset: 1 OS2TypoDescent: 0 OS2TypoDOffset: 1 OS2TypoLinegap: 0 OS2WinAscent: 0 OS2WinAOffset: 1 OS2WinDescent: 0 OS2WinDOffset: 1 HheadAscent: 0 HheadAOffset: 1 HheadDescent: 0 HheadDOffset: 1 OS2SubXSize: 41 OS2SubYSize: 44 OS2SubXOff: 0 OS2SubYOff: 30 OS2SupXSize: 41 OS2SupYSize: 44 OS2SupXOff: 0 OS2SupYOff: 0 OS2StrikeYSize: 3 OS2StrikeYPos: 16 OS2Vendor: 'PfEd' TtfTable: cvt 4 !!3-K EndTtf TtfTable: maxp 32 !!*'"!#,EO!!rW*!!!!#!!!!"!!*'"!'gN:z EndTtf LangName: 1033 Encoding: UnicodeBmp UnicodeInterp: none NameList: Adobe Glyph List DisplaySize: -36 AntiAlias: 1 FitToEm: 1 BeginChars: 65539 20 StartChar: .notdef Encoding: 65536 -1 0 Width: 27 Flags: W TtfInstrs: 46 YlOhX4L,1p!:;PH"pNdEZ3(..m4n[H!rsu:Z3:@2m4tsP"p+WaZ2k",m4nYA EndTtf Fore 2 0 m 1,0,-1 2 42 l 1,1,-1 23 42 l 1,2,-1 23 0 l 1,3,-1 2 0 l 1,0,-1 4 2 m 1,4,-1 21 2 l 1,5,-1 21 40 l 1,6,-1 4 40 l 1,7,-1 4 2 l 1,4,-1 EndSplineSet EndChar StartChar: .null Encoding: 65537 0 1 Width: 0 Flags: W EndChar StartChar: nonmarkingreturn Encoding: 65538 12 2 Width: 21 Flags: W EndChar StartChar: plus Encoding: 43 43 3 Width: 65 Flags: W Fore 0 52 m 1,0,-1 66 52 l 1,1,-1 66 -13 l 1,2,-1 0 -13 l 1,3,-1 0 52 l 1,0,-1 EndSplineSet EndChar StartChar: comma Encoding: 44 44 4 Width: 64 Flags: W Fore 32 49 m 0,0,1 39 49 39 49 45 46 c 0,2,3 64 38 64 38 63 18 c 0,4,5 62 -3 62 -3 42 -10 c 0,6,7 24 -17 24 -17 10 -2 c 0,8,9 -4 12 -4 12 4 31 c 256,10,11 12 50 12 50 32 49 c 0,0,1 32 46 m 256,12,13 23 46 23 46 15.5 40.5 c 128,-1,14 8 35 8 35 6 27 c 0,15,16 0 8 0 8 16 -3 c 0,17,18 32 -16 32 -16 49 -3 c 0,19,20 64 8 64 8 58 27 c 0,21,22 56 35 56 35 48.5 40.5 c 128,-1,23 41 46 41 46 32 46 c 256,12,13 EndSplineSet EndChar StartChar: period Encoding: 46 46 5 Width: 64 Flags: W Fore 32 45 m 0,0,1 38 45 38 45 44 42 c 0,2,3 59 35 59 35 58 18 c 0,4,5 58 0 58 0 41 -6 c 0,6,7 25 -12 25 -12 13 1 c 0,8,9 1 13 1 13 8 29 c 256,10,11 15 45 15 45 32 45 c 0,0,1 32 42 m 0,12,13 17 42 17 42 11 28 c 0,14,15 4 13 4 13 17 1 c 0,16,17 30 -10 30 -10 45 0 c 0,18,19 59 9 59 9 54 25 c 0,20,21 52 32 52 32 46 37 c 128,-1,22 40 42 40 42 32 42 c 0,12,13 EndSplineSet EndChar StartChar: A Encoding: 65 65 6 Width: 64 Flags: W Fore 24 33 m 1,0,1 25 37 25 37 28 34 c 1,2,3 28 32 28 32 26 29 c 0,4,5 24 27 24 27 24 16 c 0,6,7 25 4 25 4 22 4 c 1,8,9 21 5 21 5 21 14 c 2,10,-1 22 22 l 1,11,-1 19 19 l 1,12,13 15 16 15 16 15 17 c 128,-1,14 15 18 15 18 19 23 c 1,15,-1 24 33 l 1,0,1 34 34 m 1,16,17 36 36 36 36 38 33 c 0,18,19 39 32 39 32 39 27 c 1,20,-1 38 22 l 1,21,-1 43 23 l 1,22,-1 49 23 l 1,23,24 51 22 51 22 49.5 21 c 128,-1,25 48 20 48 20 44 20 c 2,26,-1 38 20 l 1,27,-1 38 15 l 1,28,-1 38 11 l 1,29,-1 42 11 l 1,30,31 44 12 44 12 46 11 c 128,-1,32 48 10 48 10 47 9 c 1,33,-1 44 9 l 1,34,35 31 7 31 7 29 8 c 256,36,37 27 9 27 9 31 10 c 1,38,39 35 10 35 10 35 15 c 1,40,-1 36 19 l 1,41,-1 32 18 l 1,42,43 29 18 29 18 27 18.5 c 128,-1,44 25 19 25 19 27 20 c 2,45,46 27 21 27 21 32 21 c 1,47,48 35 22 35 22 35 24 c 2,49,-1 35 30 l 1,50,-1 34 34 l 1,16,17 EndSplineSet EndChar StartChar: C Encoding: 67 67 7 Width: 64 Flags: W Fore 34 36 m 1,0,1 34 38 34 38 37 36 c 0,2,3 38 35 38 35 37 32 c 1,4,5 34 29 34 29 36 29 c 1,6,-1 40 30 l 2,7,8 44 31 44 31 45.5 30 c 128,-1,9 47 29 47 29 46 25 c 0,10,11 44 14 44 14 39 15 c 1,12,13 38 17 38 17 39 17 c 0,14,15 42 17 42 17 43 24 c 1,16,-1 43 28 l 1,17,-1 40 27 l 1,18,19 39 27 39 27 37 26 c 1,20,-1 35 26 l 2,21,22 34 26 34 26 32 24.5 c 128,-1,23 30 23 30 23 31 22 c 1,24,-1 34 23 l 2,25,26 37 24 37 24 38 23 c 128,-1,27 39 22 39 22 38 19 c 2,28,-1 37 16 l 1,29,30 37 15 37 15 35 15 c 1,31,32 32 14 32 14 31.5 11.5 c 128,-1,33 31 9 31 9 33 8 c 0,34,35 36 6 36 6 41.5 7.5 c 128,-1,36 47 9 47 9 47 12 c 0,37,38 47 13 47 13 50 12 c 1,39,40 50 9 50 9 51 9 c 1,41,42 52 7 52 7 48.5 5.5 c 128,-1,43 45 4 45 4 40 4 c 0,44,45 31 4 31 4 29 9 c 128,-1,46 27 14 27 14 32 29 c 2,47,-1 34 36 l 1,0,1 34 19 m 0,48,49 34 22 34 22 32 20 c 0,50,51 31 19 31 19 31.5 18 c 128,-1,52 32 17 32 17 33 17 c 128,-1,53 34 17 34 17 34 19 c 0,48,49 21 30 m 1,54,55 21 36 21 36 23 36 c 128,-1,56 25 36 25 36 25 31 c 0,57,58 25 28 25 28 25 27.5 c 128,-1,59 25 27 25 27 26 28 c 1,60,61 27 32 27 32 29 29 c 0,62,63 31 27 31 27 28 26 c 1,64,65 25 24 25 24 25 23 c 1,66,-1 24 22 l 1,67,68 24 20 24 20 24 19 c 0,69,70 24 16 24 16 26 15 c 1,71,72 28 15 28 15 28 13 c 0,73,74 28 9 28 9 24 12 c 1,75,76 23 14 23 14 22 12 c 1,77,78 22 11 22 11 19.5 8.5 c 128,-1,79 17 6 17 6 16 6 c 1,80,-1 17 9 l 1,81,82 23 16 23 16 21 30 c 1,54,55 16 24 m 0,83,84 16 27 16 27 19 24 c 0,85,86 23 20 23 20 19 20 c 0,87,88 16 20 16 20 16 24 c 0,83,84 EndSplineSet EndChar StartChar: E Encoding: 69 69 8 Width: 64 Flags: W Fore 23 31 m 2,0,1 23 35 23 35 24 35 c 0,2,3 26 35 26 35 26 31 c 1,4,5 27 27 27 27 29 27 c 0,6,7 30 27 30 27 29 24 c 1,8,9 22 22 22 22 28 20 c 0,10,11 30 19 30 19 30 17 c 0,12,13 30 14 30 14 27 16 c 1,14,15 26 12 26 12 26 10 c 0,16,17 26 2 26 2 24 2 c 1,18,-1 24 4 l 1,19,20 23 7 23 7 23 10 c 2,21,-1 24 18 l 1,22,-1 22 15 l 1,23,24 14 10 14 10 14 11 c 1,25,-1 17 14 l 2,26,27 18 15 18 15 19 17 c 128,-1,28 20 19 20 19 21 20 c 0,29,30 23 23 23 23 20 23 c 0,31,32 10 23 10 23 20 25 c 2,33,-1 24 26 l 1,34,-1 23 31 l 2,0,1 36 29 m 1,35,-1 43 29 l 1,36,-1 46 30 l 1,37,-1 46 20 l 2,38,39 46 17 46 17 46 13 c 1,40,-1 47 9 l 1,41,42 47 6 47 6 46 5 c 1,43,44 44 4 44 4 43 5 c 1,45,46 42 7 42 7 39 7 c 128,-1,47 36 7 36 7 35 6 c 1,48,49 34 4 34 4 33.5 6 c 128,-1,50 33 8 33 8 33 18 c 2,51,-1 33 28 l 1,52,-1 36 29 l 1,35,-1 43 25 m 0,53,54 43 28 43 28 39 27.5 c 128,-1,55 35 27 35 27 35 24 c 0,56,57 35 22 35 22 38 22 c 2,58,-1 40 22 l 1,59,-1 42 23 l 1,60,61 43 23 43 23 43 25 c 0,53,54 43 19 m 2,62,-1 43 20 l 1,63,-1 39 20 l 2,64,65 35 20 35 20 35 18 c 0,66,67 35 14 35 14 41 16 c 1,68,69 43 18 43 18 43 19 c 2,62,-1 43 12 m 128,-1,71 43 14 43 14 39 14 c 128,-1,72 35 14 35 14 35 11 c 0,73,74 35 9 35 9 37 9 c 1,75,76 38 10 38 10 41 10 c 0,77,70 43 10 43 10 43 12 c 128,-1,71 EndSplineSet EndChar StartChar: G Encoding: 71 71 9 Width: 64 Flags: W Fore 36 32 m 0,0,1 36 37 36 37 38 37 c 128,-1,2 40 37 40 37 40 32 c 128,-1,3 40 27 40 27 43 27 c 2,4,-1 47 27 l 1,5,6 48 26 48 26 47.5 20 c 128,-1,7 47 14 47 14 46 13 c 1,8,9 44 12 44 12 42 14 c 128,-1,10 40 16 40 16 42 16 c 128,-1,11 44 16 44 16 44 22 c 0,12,13 44 25 44 25 42 25 c 2,14,-1 39 25 l 1,15,-1 39 14 l 2,16,17 39 1 39 1 37 1 c 0,18,19 36 1 36 1 36 12 c 2,20,-1 35 23 l 1,21,22 34 23 34 23 34 20 c 0,23,24 34 16 34 16 33 14 c 1,25,26 31 12 31 12 31 15 c 0,27,28 31 17 31 17 31 20 c 0,29,30 31 26 31 26 34 26 c 0,31,32 36 26 36 26 36 32 c 0,0,1 22 35 m 0,33,34 22 37 22 37 25 35 c 0,35,36 26 34 26 34 24 31 c 0,37,38 22 29 22 29 24 29 c 1,39,40 27 30 27 30 28 28.5 c 128,-1,41 29 27 29 27 28 24 c 128,-1,42 27 21 27 21 23 20 c 2,43,-1 20 19 l 1,44,45 20 18 20 18 24 18 c 0,46,47 29 18 29 18 29 16 c 1,48,-1 28 14 l 1,49,-1 28 12 l 2,50,51 28 10 28 10 24 9 c 2,52,-1 20 8 l 1,53,54 20 6 20 6 18 8 c 0,55,56 17 9 17 9 17 19 c 128,-1,57 17 29 17 29 18 29 c 0,58,59 22 29 22 29 22 35 c 0,33,34 25 26 m 0,60,61 24 27 24 27 22.5 26.5 c 128,-1,62 21 26 21 26 21 24 c 128,-1,63 21 22 21 22 22 22 c 1,64,65 27 24 27 24 25 26 c 0,60,61 25 14 m 1,66,67 27 16 27 16 23 16 c 0,68,69 20 16 20 16 20 13 c 0,70,71 20 12 20 12 22.5 12 c 128,-1,72 25 12 25 12 25 14 c 1,66,67 EndSplineSet EndChar StartChar: H Encoding: 72 72 10 Width: 64 Flags: W Fore 23 32 m 128,-1,1 23 34 23 34 24 34.5 c 128,-1,2 25 35 25 35 26 33 c 1,3,4 28 32 28 32 25 29 c 1,5,6 23 25 23 25 23 23 c 2,7,-1 23 12 l 2,8,9 23 4 23 4 21 4 c 0,10,11 20 4 20 4 20 13 c 2,12,-1 21 22 l 1,13,-1 18 20 l 2,14,15 15 17 15 17 14.5 17 c 128,-1,16 14 17 14 17 17 20 c 1,17,0 23 30 23 30 23 32 c 128,-1,1 33 33 m 2,18,19 37 34 37 34 40.5 34.5 c 128,-1,20 44 35 44 35 44 34 c 0,21,22 44 32 44 32 41 32 c 1,23,-1 39 30 l 1,24,25 39 29 39 29 41 29 c 1,26,-1 43 28 l 1,27,28 43 27 43 27 41 27 c 0,29,30 38 27 38 27 38 25 c 0,31,32 38 24 38 24 41 24 c 1,33,-1 43 23 l 1,34,35 43 22 43 22 41 22 c 0,36,37 38 22 38 22 38 20 c 0,38,39 38 19 38 19 43 19 c 0,40,41 44 19 44 19 46 18 c 1,42,-1 48 18 l 1,43,44 49 16 49 16 47.5 10 c 128,-1,45 46 4 46 4 44 2 c 1,46,47 42 1 42 1 40 3 c 1,48,49 37 8 37 8 40 6 c 0,50,51 42 5 42 5 43 7 c 128,-1,52 44 9 44 9 44 13 c 0,53,54 44 18 44 18 34 16 c 2,55,-1 29 15 l 2,56,57 28 15 28 15 28 24 c 2,58,-1 28 32 l 1,59,-1 33 33 l 2,18,19 35 29 m 0,60,61 35 33 35 33 33 31 c 0,62,63 32 30 32 30 32 29 c 256,64,65 32 28 32 28 34 28 c 0,66,67 35 28 35 28 35 29 c 0,60,61 35 24 m 0,68,69 35 26 35 26 34 26 c 0,70,71 32 26 32 26 32 24 c 0,72,73 32 23 32 23 33.5 23 c 128,-1,74 35 23 35 23 35 24 c 0,68,69 35 19 m 0,75,76 35 21 35 21 33 21 c 0,77,78 30 21 30 21 30 19 c 0,79,80 30 18 30 18 33 18 c 0,81,82 35 18 35 18 35 19 c 0,75,76 37 15 m 0,83,84 37 16 37 16 38.5 15.5 c 128,-1,85 40 15 40 15 41 14 c 1,86,87 43 13 43 13 41 11 c 1,88,89 37 11 37 11 37 15 c 0,83,84 26 11 m 0,90,91 27 14 27 14 28 10 c 1,92,93 28 4 28 4 25 7 c 1,94,95 25 9 25 9 26 11 c 0,90,91 34 13 m 0,96,97 34 14 34 14 35 14 c 1,98,99 37 13 37 13 37 11 c 128,-1,100 37 9 37 9 36 9 c 0,101,102 34 9 34 9 34 13 c 0,96,97 30 11 m 2,103,104 30 13 30 13 31 13 c 0,105,106 34 13 34 13 34 9 c 0,107,108 34 8 34 8 32 8 c 128,-1,109 30 8 30 8 30 9 c 2,110,-1 30 11 l 2,103,104 EndSplineSet EndChar StartChar: R Encoding: 82 82 11 Width: 64 Flags: W Fore 34 37 m 1,0,1 34 40 34 40 35 40 c 0,2,3 38 40 38 40 38 36 c 1,4,5 37 35 37 35 37.5 35 c 128,-1,6 38 35 38 35 41 34 c 1,7,8 44 34 44 34 44 33 c 128,-1,9 44 32 44 32 41 32 c 1,10,-1 38 31 l 1,11,12 38 30 38 30 42 30 c 0,13,14 43 30 43 30 45 30 c 1,15,-1 47 29 l 1,16,-1 46 26 l 1,17,18 46 22 l 1,19,20 44 17 44 17 41 17 c 0,21,22 37 17 37 17 37 15 c 0,23,24 37 14 37 14 44 14 c 1,25,26 50 15 50 15 51 13 c 1,27,28 52 12 52 12 50 12 c 0,29,30 44 12 44 12 42 11 c 1,31,-1 37 11 l 1,32,-1 37 6 l 1,33,-1 35 -1 l 1,34,35 34 0 34 0 34 4 c 2,36,-1 34 10 l 1,37,-1 28 10 l 2,38,39 23 10 23 10 22 9.5 c 128,-1,40 21 9 21 9 21 5 c 0,41,42 21 3 21 3 20 3 c 128,-1,43 19 3 19 3 18 4 c 1,44,-1 18 14 l 1,45,-1 19 23 l 1,46,-1 16 20 l 2,47,48 13 17 13 17 12.5 17.5 c 128,-1,49 12 18 12 18 15 22 c 0,50,51 18 25 18 25 20 31 c 0,52,53 22 35 22 35 24 35 c 1,54,55 26 34 26 34 23 30 c 0,56,57 21 27 21 27 21 20 c 1,58,-1 22 13 l 1,59,-1 26 13 l 1,60,-1 34 15 l 1,61,62 34 16 34 16 31 16 c 0,63,64 29 16 29 16 28 20 c 1,65,66 28 26 28 26 26 26 c 1,67,68 26 28 26 28 28 28 c 2,69,-1 33 28 l 1,70,71 37 30 37 30 32 30 c 1,72,-1 28 31 l 1,73,74 28 34 28 34 33 34 c 0,75,76 35 34 35 34 34 37 c 1,0,1 43 26 m 1,77,78 43 28 43 28 40 28 c 128,-1,79 37 28 37 28 37 26 c 0,80,81 37 25 37 25 40 25 c 1,82,-1 43 26 l 1,77,78 34 25 m 0,83,84 34 28 34 28 31 26 c 0,85,86 27 24 27 24 32 24 c 0,87,88 34 24 34 24 34 25 c 0,83,84 34 21 m 1,89,90 34 22 34 22 32 22 c 128,-1,91 30 22 30 22 30 21 c 128,-1,92 30 20 30 20 32 20 c 1,93,-1 34 21 l 1,89,90 42 22 m 128,-1,95 42 23 42 23 40 23 c 1,96,-1 38 22 l 1,97,98 38 21 38 21 40 21 c 128,-1,94 42 21 42 21 42 22 c 128,-1,95 EndSplineSet EndChar StartChar: S Encoding: 83 83 12 Width: 64 Flags: W Fore 31 35 m 0,0,1 37 38 37 38 39 37 c 0,2,3 44 35 44 35 34 32 c 1,4,5 25 31 25 31 28 28 c 1,6,7 28 26 28 26 35 28 c 0,8,9 44 30 44 30 44 28 c 0,10,11 44 27 44 27 42 27 c 128,-1,12 40 27 40 27 40 25 c 0,13,14 40 24 40 24 39.5 23 c 128,-1,15 39 22 39 22 39 21 c 2,16,17 38 19 38 19 39 18.5 c 128,-1,18 40 18 40 18 44 18 c 0,19,20 50 18 50 18 50 17 c 128,-1,21 50 16 50 16 40 16 c 0,22,23 37 16 37 16 30.5 15.5 c 128,-1,24 24 15 24 15 23 15 c 0,25,26 17 14 17 14 16 15 c 0,27,28 14 17 14 17 20 17 c 128,-1,29 26 17 26 17 26 18 c 0,30,31 26 26 26 26 23 32 c 1,32,33 23 34 23 34 25 33 c 1,34,35 27 33 27 33 31 35 c 0,0,1 35 22 m 2,36,-1 35 24 l 1,37,-1 35 25 l 1,38,-1 31 25 l 1,39,40 27 24 27 24 28 20 c 1,41,42 29 18 29 18 32 18 c 128,-1,43 35 18 35 18 35 22 c 2,36,-1 23 9 m 0,44,45 29 15 29 15 30 12 c 1,46,47 31 11 31 11 29.5 9.5 c 128,-1,48 28 8 28 8 23 6 c 0,49,50 16 2 16 2 23 9 c 0,44,45 38 8 m 1,51,52 32 16 32 16 41 11 c 0,53,54 45 8 45 8 45 6 c 0,55,56 45 2 45 2 38 8 c 1,51,52 EndSplineSet EndChar StartChar: a Encoding: 97 97 13 Width: 64 Flags: W Fore 29 28 m 1,0,1 29 35 29 35 31 35 c 0,2,3 35 35 35 35 34 30 c 1,4,-1 34 24 l 2,5,6 34 21 34 21 40 22 c 1,7,-1 49 22 l 1,8,9 51 20 51 20 49.5 19.5 c 128,-1,10 48 19 48 19 42 19 c 2,11,-1 34 19 l 1,12,-1 34 14 l 1,13,-1 34 9 l 1,14,-1 37 9 l 1,15,16 40 10 40 10 43 9 c 128,-1,17 46 8 46 8 45 7 c 128,-1,18 44 6 44 6 33 6 c 0,19,20 21 6 21 6 21 7 c 128,-1,21 21 8 21 8 25 8 c 2,22,-1 30 8 l 1,23,-1 30 13 l 1,24,-1 30 18 l 1,25,-1 26 17 l 1,26,27 21 17 21 17 20 16 c 1,28,29 18 16 18 16 16 17 c 128,-1,30 14 18 14 18 15 19 c 1,31,32 15 20 15 20 23 20 c 1,33,-1 30 21 l 1,34,-1 29 28 l 1,0,1 EndSplineSet EndChar StartChar: c Encoding: 99 99 14 Width: 64 Flags: W Fore 33 36 m 2,0,1 34 38 34 38 35 36 c 1,2,3 36 35 36 35 36 32 c 1,4,-1 34 29 l 1,5,-1 39 30 l 2,6,7 44 31 44 31 45 29.5 c 128,-1,8 46 28 46 28 45 22 c 128,-1,9 44 16 44 16 42 14 c 128,-1,10 40 12 40 12 39 16 c 1,11,12 38 18 38 18 38 17 c 1,13,14 37 15 37 15 35 15 c 0,15,16 32 15 32 15 33 12 c 1,17,-1 33 8 l 1,18,-1 39 8 l 2,19,20 44 8 44 8 47 13 c 1,21,22 47 15 47 15 48 14 c 128,-1,23 49 13 49 13 50 10 c 1,24,25 50 7 50 7 47 6 c 1,26,27 38 0 38 0 32 6 c 0,28,29 30 8 30 8 30 14 c 0,30,31 30 22 30 22 27 22 c 1,32,33 25 20 25 20 30 29 c 1,34,35 30 30 30 30 32 33 c 1,36,-1 33 36 l 2,0,1 42 25 m 2,37,38 42 28 42 28 40 28 c 0,39,40 33 27 33 27 31 25 c 0,41,42 30 24 30 24 30.5 23.5 c 128,-1,43 31 23 31 23 34 23 c 0,44,45 39 23 39 23 39 21 c 128,-1,46 39 19 39 19 40 18 c 1,47,-1 42 24 l 1,48,-1 42 25 l 2,37,38 34 19 m 1,49,-1 34 21 l 1,50,51 32 21 32 21 32 19 c 0,52,53 32 18 32 18 34 18 c 1,54,-1 34 19 l 1,49,-1 21 29 m 0,55,56 29 31 29 31 29 29 c 128,-1,57 29 27 29 27 26 27 c 0,58,59 24 27 24 27 22 23 c 2,60,-1 21 20 l 1,61,-1 24 20 l 1,62,63 27 21 27 21 27.5 20 c 128,-1,64 28 19 28 19 27 15 c 128,-1,65 26 11 26 11 24 11 c 0,66,67 21 11 21 11 20 10 c 1,68,-1 18 13 l 1,69,70 18 16 18 16 15 14 c 0,71,72 13 12 13 12 12.5 13 c 128,-1,73 12 14 12 14 14 17 c 0,74,75 20 24 20 24 18 26 c 128,-1,76 16 28 16 28 21 29 c 0,55,56 24 16 m 1,77,78 24 18 24 18 23 18 c 0,79,80 21 18 21 18 21 15 c 128,-1,81 21 12 21 12 24 16 c 1,77,78 EndSplineSet EndChar StartChar: e Encoding: 101 101 15 Width: 64 Flags: W Fore 27 34 m 1,0,1 30 40 30 40 32 36 c 1,2,3 32 35 32 35 35 35 c 1,4,5 37 36 37 36 37.5 34.5 c 128,-1,6 38 33 38 33 36 32 c 1,7,-1 34 30 l 1,8,-1 36 30 l 1,9,-1 41 30 l 1,10,-1 43 29 l 1,11,-1 41 25 l 2,12,13 40 22 40 22 36 22 c 0,14,15 30 22 30 22 33 19 c 1,16,17 35 15 35 15 38 20 c 1,18,19 41 22 41 22 42 21 c 0,20,21 45 19 45 19 40 18 c 1,22,23 38 16 38 16 38 15 c 128,-1,24 38 14 38 14 43 11 c 128,-1,25 48 8 48 8 50 8 c 1,26,27 51 7 51 7 50 6.5 c 128,-1,28 49 6 49 6 47 6 c 1,29,30 46 5 46 5 40 8 c 1,31,-1 36 12 l 1,32,-1 36 10 l 2,33,34 36 2 36 2 33 1 c 1,35,36 32 1 32 1 30 3 c 128,-1,37 28 5 28 5 30 6 c 1,38,39 32 6 32 6 32 8 c 1,40,41 33 10 33 10 31 9 c 1,42,43 30 9 30 9 27 8 c 1,44,45 22 5 22 5 20 5 c 128,-1,46 18 5 18 5 23 8 c 1,47,48 24 8 24 8 26.5 10 c 128,-1,49 29 12 29 12 30 13 c 2,50,-1 32 16 l 1,51,-1 28 14 l 1,52,-1 19 10 l 1,53,-1 20 11 l 2,54,55 21 12 21 12 23 13 c 0,56,57 27 16 27 16 28.5 17 c 128,-1,58 30 18 30 18 29 18 c 1,59,60 29 19 29 19 25 17 c 2,61,-1 20 15 l 1,62,-1 20 16 l 1,63,64 21 17 21 17 25 19 c 1,65,66 28 22 28 22 26 21 c 1,67,68 24 21 24 21 23 24 c 0,69,70 21 32 21 32 24 32 c 0,71,72 25 32 25 32 27 34 c 1,0,1 30 30 m 2,73,74 34 32 34 32 30 32 c 0,75,76 28 32 28 32 26 30 c 1,77,78 24 29 24 29 27 29 c 128,-1,79 30 29 30 29 30 30 c 2,73,74 37 26 m 128,-1,81 37 27 37 27 35.5 27.5 c 128,-1,82 34 28 34 28 33 27 c 0,83,84 31 25 31 25 35 25 c 0,85,80 37 25 37 25 37 26 c 128,-1,81 30 25 m 0,86,87 30 27 30 27 28 27 c 128,-1,88 26 27 26 27 26 25 c 0,89,90 26 24 26 24 28 24 c 128,-1,91 30 24 30 24 30 25 c 0,86,87 EndSplineSet EndChar StartChar: g Encoding: 103 103 16 Width: 64 Flags: W Fore 24 31 m 2,0,1 24 35 24 35 25 35 c 0,2,3 28 35 28 35 28 25 c 1,4,-1 27 18 l 1,5,-1 32 21 l 2,6,7 37 24 37 24 37 25 c 1,8,-1 35 24 l 1,9,10 31 20 31 20 29 23 c 1,11,12 29 25 29 25 30 25 c 0,13,14 35 25 35 25 35 27 c 1,15,-1 32 27 l 1,16,-1 29 26 l 1,17,-1 33 31 l 1,18,-1 36 35 l 1,19,-1 38 35 l 2,20,21 40 35 40 35 40 33 c 1,22,-1 42 33 l 1,23,24 44 34 44 34 46 32 c 1,25,26 48 32 48 32 44 27 c 2,27,-1 41 23 l 1,28,29 42 23 42 23 42 21 c 0,30,31 42 20 42 20 46 20 c 1,32,33 49 19 49 19 49 18 c 128,-1,34 49 17 49 17 46 17 c 2,35,-1 42 17 l 1,36,-1 42 10 l 2,37,38 42 4 42 4 41 2.5 c 128,-1,39 40 1 40 1 37 4 c 2,40,-1 34 6 l 1,41,-1 37 7 l 1,42,43 39 7 39 7 39 12 c 1,44,-1 40 16 l 1,45,-1 34 16 l 1,46,-1 28 16 l 1,47,-1 28 10 l 2,48,49 28 6 28 6 27 4 c 128,-1,50 26 2 26 2 24 4 c 1,51,-1 24 11 l 1,52,53 25 15 25 15 24 16 c 1,54,-1 22 13 l 1,55,56 22 11 22 11 19 8 c 128,-1,57 16 5 16 5 15 5 c 0,58,59 13 5 13 5 16 8 c 1,60,61 19 14 19 14 17 15 c 128,-1,62 15 16 15 16 16 17 c 128,-1,63 17 18 17 18 20 18 c 0,64,65 24 18 24 18 24 21 c 1,66,67 25 22 25 22 24.5 22.5 c 128,-1,68 24 23 24 23 23 22 c 1,69,70 19 21 19 21 18.5 21.5 c 128,-1,71 18 22 18 22 18 26 c 2,72,-1 19 31 l 1,73,74 21 31 21 31 21 28 c 0,75,76 21 24 21 24 24 26 c 1,77,-1 24 31 l 2,0,1 40 28 m 1,78,79 42 30 42 30 39 30 c 1,80,81 37 29 37 29 38 28 c 0,82,83 40 26 40 26 40 28 c 1,78,79 38 20 m 0,84,85 38 22 38 22 36 20 c 1,86,87 34 19 34 19 36 19 c 128,-1,88 38 19 38 19 38 20 c 0,84,85 30 14 m 0,89,90 30 16 30 16 35 14 c 1,91,92 36 12 36 12 35.5 10.5 c 128,-1,93 35 9 35 9 34 9 c 1,94,-1 32 11 l 2,95,96 30 13 30 13 30 14 c 0,89,90 EndSplineSet EndChar StartChar: h Encoding: 104 104 17 Width: 64 Flags: W Fore 32 34 m 1,0,1 41 36 41 36 42 34 c 1,2,-1 37 32 l 2,3,4 31 30 31 30 37 30 c 0,5,6 41 30 41 30 41 28.5 c 128,-1,7 41 27 41 27 36 26 c 1,8,-1 37 26 l 1,9,-1 41 24 l 1,10,11 40 23 40 23 38 23 c 1,12,-1 34 22 l 1,13,14 34 21 34 21 40 21 c 128,-1,15 46 21 46 21 47 19.5 c 128,-1,16 48 18 48 18 47 13 c 0,17,18 45 3 45 3 42 1 c 1,19,20 41 1 41 1 38 4 c 2,21,-1 36 7 l 1,22,-1 38 7 l 1,23,24 40 6 40 6 41.5 8 c 128,-1,25 43 10 43 10 43 14 c 2,26,-1 43 18 l 1,27,-1 35 17 l 2,28,29 26 17 26 17 25 16 c 1,30,31 23 16 23 16 23 25 c 2,32,-1 23 34 l 1,33,-1 26 34 l 1,34,-1 32 34 l 1,0,1 30 30 m 0,35,36 30 32 30 32 29 32 c 0,37,38 27 32 27 32 27 30 c 0,39,40 27 29 27 29 29 29 c 0,41,42 30 29 30 29 30 30 c 0,35,36 30 25 m 1,43,-1 29 25 l 1,44,-1 27 25 l 1,45,-1 30 25 l 1,43,-1 30 21 m 128,-1,47 30 22 30 22 28 22 c 1,48,-1 26 21 l 1,49,50 26 20 26 20 28 20 c 128,-1,46 30 20 30 20 30 21 c 128,-1,47 18 12 m 1,51,52 19 17 19 17 21 11 c 1,53,54 21 9 21 9 19.5 7.5 c 128,-1,55 18 6 18 6 17 7 c 1,56,57 17 10 17 10 18 12 c 1,51,52 35 15 m 1,58,-1 37 15 l 1,59,-1 40 14 l 1,60,61 42 10 42 10 39 10 c 1,62,-1 35 15 l 1,58,-1 30 13 m 1,63,64 28 15 28 15 31 15 c 1,65,66 36 12 36 12 34 10 c 0,67,68 33 9 33 9 31.5 10.5 c 128,-1,69 30 12 30 12 30 13 c 1,63,64 24 12 m 0,70,71 23 14 23 14 25 14 c 128,-1,72 27 14 27 14 28 12.5 c 128,-1,73 29 11 29 11 28 10 c 1,74,75 26 6 26 6 24 12 c 0,70,71 EndSplineSet EndChar StartChar: r Encoding: 114 114 18 Width: 64 Flags: W Fore 30 36 m 1,0,1 29 38 29 38 32 38 c 0,2,3 34 38 34 38 34 36 c 128,-1,4 34 34 34 34 37 34 c 0,5,6 39 34 39 34 38 31 c 1,7,8 34 31 34 31 34 29 c 1,9,-1 37 29 l 1,10,11 41 30 41 30 42.5 28 c 128,-1,12 44 26 44 26 42 21 c 128,-1,13 40 16 40 16 37 16 c 128,-1,14 34 16 34 16 34 15 c 128,-1,15 34 14 34 14 41 15 c 1,16,17 49 15 49 15 50 14 c 128,-1,18 51 13 51 13 49.5 12.5 c 128,-1,19 48 12 48 12 42 11 c 1,20,-1 34 11 l 1,21,-1 34 7 l 2,22,23 34 0 34 0 31 0 c 0,24,25 30 0 30 0 30 5 c 128,-1,26 30 10 30 10 29.5 10.5 c 128,-1,27 29 11 29 11 23 10 c 128,-1,28 17 9 17 9 16 10 c 0,29,30 13 13 13 13 18 13 c 0,31,32 30 13 30 13 30 15 c 0,33,34 30 16 30 16 27 16 c 1,35,36 25 15 25 15 24.5 15.5 c 128,-1,37 24 16 24 16 24 19 c 0,38,39 24 20 24 20 23 22 c 128,-1,40 22 24 22 24 22 25 c 2,41,42 21 27 21 27 21.5 27.5 c 128,-1,43 22 28 22 28 26 28 c 128,-1,44 30 28 30 28 30 29 c 128,-1,45 30 30 30 30 27 30 c 0,46,47 25 30 25 30 26 33 c 1,48,49 30 33 30 33 30 36 c 1,0,1 38 26 m 2,50,51 38 27 38 27 36 27 c 128,-1,52 34 27 34 27 34 25 c 0,53,54 34 24 34 24 35 24 c 2,55,-1 36 24 l 1,56,-1 38 25 l 1,57,-1 38 26 l 2,50,51 30 25 m 0,58,59 30 26 30 26 29 26 c 128,-1,60 28 26 28 26 27 25 c 128,-1,61 26 24 26 24 26 23 c 1,62,63 30 21 30 21 30 25 c 0,58,59 38 20 m 128,-1,65 38 22 38 22 36 22 c 128,-1,66 34 22 34 22 34 20 c 128,-1,67 34 18 34 18 36 18 c 128,-1,64 38 18 38 18 38 20 c 128,-1,65 30 20 m 2,68,69 30 21 30 21 29 21 c 0,70,71 27 21 27 21 27 19 c 0,72,73 27 18 27 18 28 18 c 1,74,-1 30 19 l 1,75,-1 30 20 l 2,68,69 EndSplineSet EndChar StartChar: s Encoding: 115 115 19 Width: 64 Flags: W Fore 30 36 m 1,0,1 29 38 29 38 30 38 c 1,2,3 32 39 32 39 35 36 c 0,4,5 37 34 37 34 40 35 c 128,-1,6 43 36 43 36 44.5 34.5 c 128,-1,7 46 33 46 33 44 32 c 1,8,-1 41 32 l 2,9,10 39 32 39 32 41 30 c 1,11,12 42 30 42 30 41 27 c 1,13,14 41 26 41 26 42 26 c 0,15,16 44 26 44 26 44.5 24 c 128,-1,17 45 22 45 22 44 21 c 1,18,-1 41 22 l 1,19,20 40 24 40 24 38 23 c 128,-1,21 36 22 36 22 36 20 c 2,22,23 35 19 35 19 36 18.5 c 128,-1,24 37 18 37 18 41 19 c 1,25,26 50 19 50 19 50 17 c 0,27,28 50 16 50 16 43 16 c 0,29,30 37 16 37 16 35.5 14.5 c 128,-1,31 34 13 34 13 34 7 c 2,32,-1 34 2 l 1,33,34 33 -1 33 -1 32.5 1 c 128,-1,35 32 3 32 3 32 8 c 2,36,-1 32 15 l 1,37,-1 25 15 l 1,38,39 21 14 21 14 17 14 c 1,40,41 15 15 15 15 16 16 c 128,-1,42 17 17 17 17 19 17 c 0,43,44 32 17 32 17 32 19 c 128,-1,45 32 21 32 21 30 21 c 128,-1,46 28 21 28 21 28 22 c 1,47,48 27 23 27 23 24 22 c 1,49,50 22 19 22 19 21.5 20 c 128,-1,51 21 21 21 21 23 24 c 0,52,53 27 30 27 30 24 30 c 2,54,-1 23 30 l 1,55,56 22 31 22 31 21 31 c 1,57,58 21 34 21 34 28 34 c 0,59,60 32 34 32 34 30 36 c 1,0,1 37 29 m 2,61,-1 37 31 l 1,62,63 34 31 34 31 32 30 c 1,64,-1 28 30 l 1,65,66 31 30 31 30 29 28 c 1,67,68 29 23 29 23 33 23 c 128,-1,69 37 23 37 23 37 29 c 2,61,-1 EndSplineSet EndChar EndChars EndSplineFont tagua-1.0-alpha2/data/themes/pieces/XiangQiTTF/XiangQi.ttf000066400000000000000000000116541077523320400232750ustar00rootroot00000000000000`FFTMDGDGDEF'pOS/2JMWhVcmap$'cvt (gasphglyfy head6hhea9$$hmtx$e2loca*maxp_H name1postJ[5 _<@JKJKB44ABo @.=),),PfEd+s34 A@  x ,.ACEHSacehs+.ACEGRacegr ((((4`T 40:n*./<2<2/<2<2353'35#**&B453#BB4A@2 72'&76"76'.  1   ;- 72'&76"76'.    -   3$276#&574?673+36#'&7257"&7436= !   4%/5RX74376'&3275"#"76#6543#"&742'42762'&#76'4#""   $    /#"4=EM743232'#5&5757>76#"?37'&"&=4;725#"764"363     0% ;AH742;&254+#"5'"545432'43632'&432&366#"2$       1#;CJRY_fn646#"57"?>#3#"3#"323'&654"=4324#"24#"324"#6'4743#"'432"5         4(KQW\a743222#323#"36#"#&=#""'57&76763374#"'4#4;6#'4324"3#4324"364#" % 2&#+287676"32#"#'&254'42=#267&       #  3#"743273+36#"4;=""&7437   2%$06LQ7676'&#"3274'&54#7474#3275"3'6#"36#"'4&76&4#"!   $    3&HOU[7636;#"763#/"&7256""726?767>#45676"'&326#"24&3#4"2  "1#MSX`7432765'4325#?3236223+/7257+'56'#"76&63256&&572?6#424#'& 0#"*-29>EK76323#2"/36=""=34#"32+4#6'473#'&3&#&2    "  3&19?CK7&3232"36"72##"4&'&3254#&54&5&624#"724";7#4"4"'4#"37  $  2'<E7&366#"232'&72#"&=##&6324"5&&76+ư5"#22  $F#J~     F n   Created by Monge Maurizio with FontForge 1.0 (http://fontforge.sf.net)Created by Monge Maurizio with FontForge 1.0 (http://fontforge.sf.net)XiangQiXiangQiMediumMediumFontForge 1.0 : XiangQi : 19-7-2007FontForge 1.0 : XiangQi : 19-7-2007XiangQiXiangQiVersion 001.000 Version 001.000 XiangQiXiangQi2$&(*+56DFHJKUV ?K$M|tagua-1.0-alpha2/data/themes/pieces/XiangQiTTF/theme.desktop000066400000000000000000000002611077523320400237030ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=XiangQi Type=Application Comment=XiangQi TTF theme,| created with potrace X-Tagua-ThemeType=Pieces X-Tagua-Variants=XiangQi[default],Chess tagua-1.0-alpha2/data/themes/pieces/XiangQiTTF/theme.lua000066400000000000000000000043211077523320400230140ustar00rootroot00000000000000import("piece_theme.lua") shadow=5.0 shadow_color="#404050" shadow_offset_x=6 shadow_offset_y=4 shadow_grow=5 white_col = "#d00000" black_col = "#000070" white_col2 = "#a00000" black_col2 = "#000000" function fromChar(char, white) return function(size) local i = Image(size,size) i:clear() local g = RadialGradient(Point(size*0.5,size*0.5), size*0.5, Point(size*0.3,size*0.3)) g[0] = "#ffeda2" g[1] = "#c0a870" i:draw_glyph(Rect(0,0,size,size), "XiangQi.ttf", "0x2c", "black", g, 0, true) i:draw_glyph(Rect(0,0,size,size), "XiangQi.ttf", "0x2e", white and white_col2 or black_col2, "#fff3c8", 5, false) i:draw_glyph(Rect(0,0,size,size), "XiangQi.ttf", char, white and white_col or black_col, "#fff3c8", 4, false) return i end end theme.black_advisor = addShadow(fromChar("0x61", false)) theme.black_cannon = addShadow(fromChar("0x63", false)) theme.black_elephant = addShadow(fromChar("0x65", false)) theme.black_general = addShadow(fromChar("0x67", false)) theme.black_horse = addShadow(fromChar("0x68", false)) theme.black_chariot = addShadow(fromChar("0x72", false)) theme.black_soldier = addShadow(fromChar("0x73", false)) theme.red_advisor = addShadow(fromChar("0x41", true)) theme.red_cannon = addShadow(fromChar("0x43", true)) theme.red_elephant = addShadow(fromChar("0x45", true)) theme.red_general = addShadow(fromChar("0x47", true)) theme.red_horse = addShadow(fromChar("0x48", true)) theme.red_chariot = addShadow(fromChar("0x52", true)) theme.red_soldier = addShadow(fromChar("0x53", true)) -- To be able to adapt this theme to chess too theme.black_bishop = theme.black_advisor theme.black_king = theme.black_general theme.black_knight = theme.black_horse theme.black_pawn = theme.black_soldier theme.black_queen = theme.black_elephant theme.black_rook = theme.black_chariot theme.white_bishop = theme.red_advisor theme.white_king = theme.red_general theme.white_knight = theme.red_horse theme.white_pawn = theme.red_soldier theme.white_queen = theme.red_elephant theme.white_rook = theme.red_chariot tagua-1.0-alpha2/data/themes/pieces/YahooTTF/000077500000000000000000000000001077523320400207265ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/pieces/YahooTTF/Yahoo.sfd000066400000000000000000001454001077523320400225070ustar00rootroot00000000000000SplineFontDB: 1.0 FontName: Yahoo FullName: Yahoo FamilyName: Yahoo Weight: Medium Copyright: Created by Io with FontForge 1.0 (http://fontforge.sf.net) Version: 001.000 ItalicAngle: 0 UnderlinePosition: -100 UnderlineWidth: 50 Ascent: 819 Descent: 205 Order2: 1 XUID: [1021 645 1811818106 9845185] FSType: 0 OS2Version: 0 OS2_WeightWidthSlopeOnly: 0 OS2_UseTypoMetrics: 0 CreationTime: 1156082481 ModificationTime: 1160236016 PfmFamily: 17 TTFWeight: 500 TTFWidth: 5 LineGap: 92 VLineGap: 0 Panose: 2 0 6 9 0 0 0 0 0 0 OS2TypoAscent: 0 OS2TypoAOffset: 1 OS2TypoDescent: 0 OS2TypoDOffset: 1 OS2TypoLinegap: 0 OS2WinAscent: 0 OS2WinAOffset: 1 OS2WinDescent: 0 OS2WinDOffset: 1 HheadAscent: 0 HheadAOffset: 1 HheadDescent: 0 HheadDOffset: 1 OS2SubXSize: 665 OS2SubYSize: 716 OS2SubXOff: 0 OS2SubYOff: 491 OS2SupXSize: 665 OS2SupYSize: 716 OS2SupXOff: 0 OS2SupYOff: 0 OS2StrikeYSize: 51 OS2StrikeYPos: 265 OS2Vendor: 'PfEd' TtfTable: cvt 4 !$VK# EndTtf TtfTable: maxp 32 !!*'"!"&ar!#>P7!!!!#!!!!"!!*'"!'gN:z EndTtf LangName: 1033 Encoding: UnicodeBmp UnicodeInterp: none NameList: Adobe Glyph List DisplaySize: -36 AntiAlias: 1 FitToEm: 1 WinInfo: 63 21 11 BeginChars: 65539 10 StartChar: .notdef Encoding: 65536 -1 0 Width: 1024 Flags: W TtfInstrs: 46 YlOhX4L,1p!:;PH"pNdEZ3(..m4n[H!rsu:Z3:@2m4tsP"p+WaZ2k",m4nYA EndTtf Fore 34 0 m 1,0,-1 34 682 l 1,1,-1 375 682 l 1,2,-1 375 0 l 1,3,-1 34 0 l 1,0,-1 68 34 m 1,4,-1 341 34 l 1,5,-1 341 648 l 1,6,-1 68 648 l 1,7,-1 68 34 l 1,4,-1 EndSplineSet EndChar StartChar: .null Encoding: 65537 0 1 Width: 0 Flags: W EndChar StartChar: nonmarkingreturn Encoding: 65538 12 2 Width: 1024 Flags: W EndChar StartChar: plus Encoding: 43 43 3 Width: 1024 Flags: W Fore 0 817 m 1,0,-1 1024 817 l 1,1,-1 1024 -203 l 1,2,-1 0 -203 l 1,3,-1 0 817 l 1,0,-1 EndSplineSet EndChar StartChar: b Encoding: 98 98 4 Width: 1024 Flags: W Fore 500 785 m 0,0,1 523 804 523 804 532 802 c 128,-1,2 541 800 541 800 570 772 c 0,3,4 641 703 641 703 581 703 c 0,5,6 570 703 570 703 562 698 c 128,-1,7 554 693 554 693 554 686 c 0,8,9 554 666 554 666 568.5 646.5 c 128,-1,10 583 627 583 627 598 627 c 0,11,12 618 625 618 625 683.5 560.5 c 128,-1,13 749 496 749 496 742 484 c 0,14,15 736 472 736 472 754 462 c 1,16,17 771 456 771 456 773 422 c 128,-1,18 775 388 775 388 765.5 348 c 128,-1,19 756 308 756 308 736 268 c 128,-1,20 716 228 716 228 693 210 c 0,21,22 679 200 679 200 679.5 193 c 128,-1,23 680 186 680 186 696 172 c 1,24,25 720 144 720 144 720 123 c 0,26,27 720 99 720 99 735 84 c 0,28,29 752 67 752 67 739 52.5 c 128,-1,30 726 38 726 38 699 44 c 0,31,32 669 53 669 53 643 25 c 0,33,34 625 6 625 6 628.5 -0.5 c 128,-1,35 632 -7 632 -7 664 -8 c 1,36,37 685 -12 685 -12 685 -37 c 0,38,39 685 -54 685 -54 693 -58.5 c 128,-1,40 701 -63 701 -63 726 -61 c 0,41,42 768 -56 768 -56 796 -54 c 0,43,44 813 -52 813 -52 818 -60.5 c 128,-1,45 823 -69 823 -69 823 -100 c 2,46,-1 823 -147 l 1,47,-1 516 -148 l 2,48,49 374 -148 374 -148 304 -145.5 c 128,-1,50 234 -143 234 -143 214 -136.5 c 128,-1,51 194 -130 194 -130 228 -119 c 0,52,53 250 -109 250 -109 235 -93 c 0,54,55 216 -71 216 -71 243.5 -63.5 c 128,-1,56 271 -56 271 -56 356 -59 c 0,57,58 460 -66 460 -66 466 -47 c 0,59,60 469 -39 469 -39 462.5 -34.5 c 128,-1,61 456 -30 456 -30 443 -30 c 0,62,63 423 -30 423 -30 421 -27 c 128,-1,64 419 -24 419 -24 429 -10 c 0,65,66 447 10 447 10 435 14 c 1,67,68 399 19 399 19 374 29 c 0,69,70 353 37 353 37 311 42 c 0,71,72 295 43 295 43 284.5 49 c 128,-1,73 274 55 274 55 277 60 c 0,74,75 283 71 283 71 390.5 73 c 128,-1,76 498 75 498 75 498 64 c 128,-1,77 498 53 498 53 536 71 c 0,78,79 558 80 558 80 566 80 c 128,-1,80 574 80 574 80 577 71 c 0,81,82 580 64 580 64 583 61.5 c 128,-1,83 586 59 586 59 590 61 c 128,-1,84 594 63 594 63 601 69 c 0,85,86 617 87 617 87 603 102 c 0,87,88 588 120 588 120 578 102 c 0,89,90 570 86 570 86 552 104 c 0,91,92 536 120 536 120 558 141 c 0,93,94 578 161 578 161 593.5 162.5 c 128,-1,95 609 164 609 164 609 147 c 0,96,97 609 129 609 129 623 149 c 0,98,99 631 162 631 162 620.5 167.5 c 128,-1,100 610 173 610 173 570 177 c 0,101,102 513 183 513 183 494 173 c 128,-1,103 475 163 475 163 504 143 c 0,104,105 528 122 528 122 522 112 c 0,106,107 518 106 518 106 418 104 c 128,-1,108 318 102 318 102 292 107 c 1,109,110 287 109 287 109 304 129 c 128,-1,111 321 149 321 149 397 149 c 0,112,113 423 149 423 149 439.5 151 c 128,-1,114 456 153 456 153 462.5 156.5 c 128,-1,115 469 160 469 160 468 166 c 1,116,117 461 184 461 184 428 184 c 0,118,119 356 187 356 187 336.5 191 c 128,-1,120 317 195 317 195 325 203 c 0,121,122 341 218 341 218 384 223 c 128,-1,123 427 228 427 228 439 217 c 0,124,125 448 208 448 208 542.5 294.5 c 128,-1,126 637 381 637 381 637 400 c 0,127,128 637 405 637 405 613.5 384 c 128,-1,129 590 363 590 363 558 329 c 0,130,131 475 246 475 246 465 246 c 0,132,133 452 246 452 246 418 278 c 2,134,-1 385 309 l 1,135,-1 396 267 l 2,136,137 403 239 403 239 401 235.5 c 128,-1,138 399 232 399 232 383 245 c 0,139,140 360 263 360 263 360 248 c 0,141,142 360 232 360 232 340 233 c 128,-1,143 320 234 320 234 307 250 c 0,144,145 294 265 294 265 284 309 c 0,146,147 280 324 280 324 279.5 331 c 128,-1,148 279 338 279 338 281 338 c 128,-1,149 283 338 283 338 288 331 c 0,150,151 299 312 299 312 327 321 c 0,152,153 340 326 340 326 343 329 c 128,-1,154 346 332 346 332 343.5 335 c 128,-1,155 341 338 341 338 328 345 c 0,156,157 303 359 303 359 318 378 c 128,-1,158 333 397 333 397 318 405 c 0,159,160 302 415 302 415 327 441 c 0,161,162 348 470 348 470 343 475 c 0,163,164 336 483 336 483 313.5 473.5 c 128,-1,165 291 464 291 464 291 453 c 0,166,167 291 448 291 448 285.5 444 c 128,-1,168 280 440 280 440 274 440 c 0,169,170 257 442 257 442 291 471 c 0,171,172 324 500 324 500 309 505 c 0,173,174 292 511 292 511 290.5 531 c 128,-1,175 289 551 289 551 304 551 c 0,176,177 317 551 317 551 351.5 514.5 c 128,-1,178 386 478 386 478 387 464 c 0,179,180 387 452 387 452 433 399 c 0,181,182 479 343 479 343 516 343 c 0,183,184 538 343 538 343 546 349.5 c 128,-1,185 554 356 554 356 554 375 c 0,186,187 554 407 554 407 520 426 c 0,188,189 485 448 485 448 415.5 514.5 c 128,-1,190 346 581 346 581 346 592 c 0,191,192 346 601 346 601 352 604 c 128,-1,193 358 607 358 607 366.5 603.5 c 128,-1,194 375 600 375 600 381 591 c 0,195,196 390 577 390 577 410 584 c 0,197,198 429 591 429 591 429 572 c 0,199,200 429 559 429 559 434.5 554 c 128,-1,201 440 549 440 549 449.5 554 c 128,-1,202 459 559 459 559 470 572 c 0,203,204 477 580 477 580 479 585 c 128,-1,205 481 590 481 590 478 593 c 128,-1,206 475 596 475 596 466 599 c 0,207,208 453 605 453 605 454 616 c 128,-1,209 455 627 455 627 473 663 c 0,210,211 489 696 489 696 491 711.5 c 128,-1,212 493 727 493 727 483 739 c 0,213,214 473 750 473 750 476.5 759.5 c 128,-1,215 480 769 480 769 500 785 c 0,0,1 530 -51 m 0,216,217 540 -33 540 -33 529 -26 c 0,218,219 516 -19 516 -19 500 -28.5 c 128,-1,220 484 -38 484 -38 484 -53 c 0,221,222 484 -72 484 -72 503 -71.5 c 128,-1,223 522 -71 522 -71 530 -51 c 0,216,217 606 -55 m 0,224,225 600 -36 600 -36 583.5 -34 c 128,-1,226 567 -32 567 -32 567 -50 c 0,227,228 567 -59 567 -59 573.5 -65.5 c 128,-1,229 580 -72 580 -72 589 -72 c 0,230,231 611 -72 611 -72 606 -55 c 0,224,225 664 -59 m 128,-1,233 664 -46 664 -46 651.5 -39 c 128,-1,234 639 -32 639 -32 631 -40 c 0,235,236 620 -51 620 -51 624 -61.5 c 128,-1,237 628 -72 628 -72 643 -72 c 0,238,232 664 -72 664 -72 664 -59 c 128,-1,233 408 732 m 0,239,240 416 745 416 745 436.5 745 c 128,-1,241 457 745 457 745 457 732 c 0,242,243 457 718 457 718 442.5 710 c 128,-1,244 428 702 428 702 415 710 c 0,245,246 401 719 401 719 408 732 c 0,239,240 360 -32 m 0,247,248 360 -26 360 -26 364.5 -21.5 c 128,-1,249 369 -17 369 -17 374 -17 c 0,250,251 387 -17 387 -17 387 -22 c 0,252,253 387 -30 387 -30 374 -37 c 0,254,255 369 -40 369 -40 364.5 -38.5 c 128,-1,256 360 -37 360 -37 360 -32 c 0,247,248 EndSplineSet EndChar StartChar: k Encoding: 107 107 5 Width: 1024 Flags: W Fore 473 743 m 0,0,1 489 768 489 768 507.5 771.5 c 128,-1,2 526 775 526 775 526 753 c 0,3,4 526 744 526 744 534 735.5 c 128,-1,5 542 727 542 727 554 724 c 0,6,7 571 719 571 719 578 703.5 c 128,-1,8 585 688 585 688 578.5 674.5 c 128,-1,9 572 661 572 661 554 661 c 0,10,11 537 661 537 661 531.5 646.5 c 128,-1,12 526 632 526 632 523 576 c 128,-1,13 520 520 520 520 525 497.5 c 128,-1,14 530 475 530 475 552 451 c 0,15,16 573 427 573 427 583.5 423.5 c 128,-1,17 594 420 594 420 614 430 c 0,18,19 646 450 646 450 655 465 c 0,20,21 668 485 668 485 689 479.5 c 128,-1,22 710 474 710 474 729 445 c 0,23,24 745 422 745 422 751 419.5 c 128,-1,25 757 417 757 417 768 432 c 0,26,27 786 454 786 454 801 454 c 128,-1,28 816 454 816 454 816 468 c 0,29,30 816 481 816 481 837 481 c 0,31,32 855 481 855 481 858 455.5 c 128,-1,33 861 430 861 430 844 419 c 0,34,35 830 411 830 411 830 362 c 0,36,37 830 315 830 315 816 315 c 0,38,39 811 315 811 315 807 295 c 128,-1,40 803 275 803 275 803 248 c 0,41,42 803 180 803 180 782 163 c 0,43,44 767 151 767 151 767 143.5 c 128,-1,45 767 136 767 136 783 120 c 0,46,47 802 100 802 100 797.5 76 c 128,-1,48 793 52 793 52 769 52 c 0,49,50 762 52 762 52 753.5 42 c 128,-1,51 745 32 745 32 742 19 c 128,-1,52 739 6 739 6 727.5 -6 c 128,-1,53 716 -18 716 -18 703 -21 c 0,54,55 683 -26 683 -26 678.5 -32.5 c 128,-1,56 674 -39 674 -39 684.5 -43 c 128,-1,57 695 -47 695 -47 712.5 -48.5 c 128,-1,58 730 -50 730 -50 754 -44 c 0,59,60 800 -34 800 -34 815 -45.5 c 128,-1,61 830 -57 830 -57 830 -101 c 2,62,-1 830 -137 l 1,63,-1 505 -137 l 2,64,65 356 -137 356 -137 282 -134 c 128,-1,66 208 -131 208 -131 187 -124 c 128,-1,67 166 -117 166 -117 201 -105 c 0,68,69 223 -95 223 -95 206 -78 c 0,70,71 199 -69 199 -69 198.5 -66 c 128,-1,72 198 -63 198 -63 198.5 -59.5 c 128,-1,73 199 -56 199 -56 217.5 -55 c 128,-1,74 236 -54 236 -54 253.5 -53.5 c 128,-1,75 271 -53 271 -53 318 -53 c 0,76,77 422 -50 422 -50 422 -38 c 128,-1,78 422 -26 422 -26 394 -22 c 1,79,80 388 -22 388 -22 358 -20.5 c 128,-1,81 328 -19 328 -19 311 -18 c 0,82,83 279 -17 279 -17 272.5 -13.5 c 128,-1,84 266 -10 266 -10 280 -3 c 0,85,86 302 12 302 12 333 8 c 0,87,88 346 6 346 6 356.5 10 c 128,-1,89 367 14 367 14 369 22 c 1,90,91 374 33 374 33 360.5 35 c 128,-1,92 347 37 347 37 306 32 c 0,93,94 262 27 262 27 248.5 30 c 128,-1,95 235 33 235 33 235 46 c 0,96,97 235 54 235 54 229 60 c 128,-1,98 223 66 223 66 213 66 c 0,99,100 199 66 199 66 198.5 70 c 128,-1,101 198 74 198 74 208 87 c 0,102,103 219 100 219 100 225.5 100 c 128,-1,104 232 100 232 100 245 87 c 0,105,106 278 51 278 51 299 83 c 0,107,108 308 98 308 98 327 75 c 1,109,110 333 64 333 64 340.5 61 c 128,-1,111 348 58 348 58 351 65 c 1,112,113 361 78 361 78 316 123 c 0,114,115 309 130 309 130 303 136.5 c 128,-1,116 297 143 297 143 293.5 147.5 c 128,-1,117 290 152 290 152 288 155 c 128,-1,118 286 158 286 158 287 159 c 128,-1,119 288 160 288 160 291 159 c 0,120,121 301 156 301 156 306 162 c 128,-1,122 311 168 311 168 311 184 c 0,123,124 311 197 311 197 308.5 204.5 c 128,-1,125 306 212 306 212 302 210 c 0,126,127 291 203 291 203 263 218 c 0,128,129 251 225 251 225 247 227.5 c 128,-1,130 243 230 243 230 244 236 c 128,-1,131 245 242 245 242 250.5 247.5 c 128,-1,132 256 253 256 253 273 267 c 0,133,134 288 280 288 280 294 287 c 128,-1,135 300 294 300 294 299 297.5 c 128,-1,136 298 301 298 301 289 302 c 0,137,138 268 302 268 302 249 281 c 0,139,140 233 261 233 261 205 275 c 0,141,142 179 289 179 289 192 307 c 0,143,144 207 325 207 325 177 355 c 2,145,-1 148 387 l 1,146,-1 180 378 l 2,147,148 200 373 200 373 203.5 377.5 c 128,-1,149 207 382 207 382 193 393 c 128,-1,150 179 404 179 404 158 412 c 0,151,152 135 422 135 422 132.5 428.5 c 128,-1,153 130 435 130 435 141 454 c 0,154,155 172 505 172 505 205 452 c 2,156,-1 223 423 l 1,157,-1 255 452 l 2,158,159 285 480 285 480 302 479 c 128,-1,160 319 478 319 478 339 448 c 0,161,162 355 425 355 425 363.5 423 c 128,-1,163 372 421 372 421 396 433 c 0,164,165 423 446 423 446 453.5 475.5 c 128,-1,166 484 505 484 505 484 517 c 0,167,168 484 526 484 526 465 510 c 0,169,170 443 495 443 495 437 508 c 0,171,172 430 519 430 519 439 545 c 128,-1,173 448 571 448 571 462 581 c 0,174,175 478 592 478 592 461.5 617 c 128,-1,176 445 642 445 642 410 660 c 0,177,178 370 677 370 677 386 693 c 0,179,180 400 707 400 707 443 685 c 0,181,182 473 666 473 666 482.5 671 c 128,-1,183 492 676 492 676 469 699 c 0,184,185 454 714 454 714 473 743 c 0,0,1 511 407 m 0,186,187 477 447 477 447 443 405 c 0,188,189 428 388 428 388 431.5 363 c 128,-1,190 435 338 435 338 452 333 c 0,191,192 471 329 471 329 498 357 c 0,193,194 516 374 516 374 518.5 384 c 128,-1,195 521 394 521 394 511 407 c 0,186,187 298 386 m 0,196,197 289 399 289 399 278 397.5 c 128,-1,198 267 396 267 396 246 379 c 0,199,200 231 368 231 368 225 356.5 c 128,-1,201 219 345 219 345 223.5 337 c 128,-1,202 228 329 228 329 241 329 c 0,203,204 260 329 260 329 282.5 351 c 128,-1,205 305 373 305 373 298 386 c 0,196,197 738 390 m 0,206,207 729 398 729 398 712.5 398 c 128,-1,208 696 398 696 398 688 389 c 0,209,210 675 376 675 376 679 352.5 c 128,-1,211 683 329 683 329 699 329 c 128,-1,212 715 329 715 329 731.5 354 c 128,-1,213 748 379 748 379 738 390 c 0,206,207 360 293 m 0,214,215 360 303 360 303 353.5 309 c 128,-1,216 347 315 347 315 338 315 c 0,217,218 320 315 320 315 322 299 c 128,-1,219 324 283 324 283 343 277 c 0,220,221 350 275 350 275 355 279.5 c 128,-1,222 360 284 360 284 360 293 c 0,214,215 415 295 m 128,-1,224 415 303 415 303 408.5 309 c 128,-1,225 402 315 402 315 394 315 c 128,-1,226 386 315 386 315 380 309 c 128,-1,227 374 303 374 303 374 295 c 128,-1,228 374 287 374 287 380 280.5 c 128,-1,229 386 274 386 274 394 274 c 128,-1,230 402 274 402 274 408.5 280.5 c 128,-1,223 415 287 415 287 415 295 c 128,-1,224 498 286 m 0,231,232 498 299 498 299 485.5 306.5 c 128,-1,233 473 314 473 314 465 306 c 0,234,235 454 294 454 294 458 284 c 128,-1,236 462 274 462 274 477 274 c 0,237,238 498 274 498 274 498 286 c 0,231,232 581 295 m 128,-1,240 581 303 581 303 575 309 c 128,-1,241 569 315 569 315 560 315 c 0,242,243 552 315 552 315 546 309 c 128,-1,244 540 303 540 303 540 295 c 128,-1,245 540 287 540 287 546 280.5 c 128,-1,246 552 274 552 274 560 274 c 0,247,248 569 274 569 274 575 280.5 c 128,-1,239 581 287 581 287 581 295 c 128,-1,240 664 295 m 128,-1,250 664 303 664 303 658 309 c 128,-1,251 652 315 652 315 643 315 c 0,252,253 635 315 635 315 629 309 c 128,-1,254 623 303 623 303 623 295 c 128,-1,255 623 287 623 287 629 280.5 c 128,-1,256 635 274 635 274 643 274 c 0,257,258 652 274 652 274 658 280.5 c 128,-1,249 664 287 664 287 664 295 c 128,-1,250 671 232 m 1,259,260 668 238 668 238 664.5 242 c 128,-1,261 661 246 661 246 660 245 c 1,262,263 659 243 659 243 623 232 c 0,264,265 598 224 598 224 599.5 222.5 c 128,-1,266 601 221 601 221 634 220 c 0,267,268 654 219 654 219 665 222.5 c 128,-1,269 676 226 676 226 671 232 c 1,259,260 577 174 m 0,270,271 584 191 584 191 576 201 c 0,272,273 573 205 573 205 570.5 199.5 c 128,-1,274 568 194 568 194 569 183 c 0,275,276 569 170 569 170 572 168 c 0,277,278 574 167 574 167 577 174 c 0,270,271 720 120 m 0,279,280 720 139 720 139 693 149 c 128,-1,281 666 159 666 159 634.5 154 c 128,-1,282 603 149 603 149 592 131 c 0,283,284 581 112 581 112 597.5 96.5 c 128,-1,285 614 81 614 81 631 95 c 0,286,287 652 112 652 112 643 122 c 1,288,289 637 133 637 133 649 142 c 0,290,291 655 146 655 146 663.5 140 c 128,-1,292 672 134 672 134 678 122 c 0,293,294 687 105 687 105 697 98.5 c 128,-1,295 707 92 707 92 713.5 97.5 c 128,-1,296 720 103 720 103 720 120 c 0,279,280 387 133 m 0,297,298 387 139 387 139 379 144 c 128,-1,299 371 149 371 149 360 149 c 0,300,301 341 149 341 149 336.5 144 c 128,-1,302 332 139 332 139 339 126 c 128,-1,303 346 113 346 113 368 87 c 0,304,305 395 57 395 57 398.5 56 c 128,-1,306 402 55 402 55 396 80 c 0,307,308 387 123 387 123 387 133 c 0,297,298 470 122 m 0,309,310 470 133 470 133 464 141 c 128,-1,311 458 149 458 149 450 149 c 128,-1,312 442 149 442 149 435.5 142 c 128,-1,313 429 135 429 135 429 126 c 0,314,315 429 108 429 108 440 89.5 c 128,-1,316 451 71 451 71 464 61 c 128,-1,317 477 51 477 51 487.5 53 c 128,-1,318 498 55 498 55 498 73 c 0,319,320 498 94 498 94 484 94 c 0,321,322 479 94 479 94 474.5 102 c 128,-1,323 470 110 470 110 470 122 c 0,309,310 554 122 m 0,324,325 554 133 554 133 547.5 141 c 128,-1,326 541 149 541 149 533 149 c 128,-1,327 525 149 525 149 518.5 141 c 128,-1,328 512 133 512 133 512 122 c 0,329,330 512 110 512 110 518.5 102 c 128,-1,331 525 94 525 94 533 94 c 128,-1,332 541 94 541 94 547.5 102 c 128,-1,333 554 110 554 110 554 122 c 0,324,325 443 28 m 0,334,335 443 32 443 32 439 35.5 c 128,-1,336 435 39 435 39 430 39 c 0,337,338 416 39 416 39 409 25.5 c 128,-1,339 402 12 402 12 412 5 c 0,340,341 422 -1 422 -1 432.5 6.5 c 128,-1,342 443 14 443 14 443 28 c 0,334,335 498 18 m 0,343,344 498 39 498 39 486 39 c 0,345,346 473 39 473 39 465.5 26 c 128,-1,347 458 13 458 13 466 5 c 0,348,349 478 -6 478 -6 488 -2 c 128,-1,350 498 2 498 2 498 18 c 0,343,344 540 18 m 128,-1,352 540 39 540 39 526 39 c 0,353,354 521 39 521 39 516.5 32.5 c 128,-1,355 512 26 512 26 512 18 c 128,-1,356 512 10 512 10 516.5 3.5 c 128,-1,357 521 -3 521 -3 526 -3 c 0,358,351 540 -3 540 -3 540 18 c 128,-1,352 609 11 m 0,359,360 609 25 609 25 595 25 c 0,361,362 590 25 590 25 585.5 21 c 128,-1,363 581 17 581 17 581 11 c 0,364,365 581 6 581 6 585.5 1.5 c 128,-1,366 590 -3 590 -3 595 -3 c 0,367,368 601 -3 601 -3 605 1.5 c 128,-1,369 609 6 609 6 609 11 c 0,359,360 498 -28 m 0,370,371 498 -17 498 -17 486 -17 c 0,372,373 471 -17 471 -17 464 -30.5 c 128,-1,374 457 -44 457 -44 468 -50 c 0,375,376 478 -56 478 -56 488 -49 c 128,-1,377 498 -42 498 -42 498 -28 c 0,370,371 606 -33 m 0,378,379 608 -26 608 -26 603.5 -21.5 c 128,-1,380 599 -17 599 -17 589 -17 c 0,381,382 580 -17 580 -17 573.5 -23 c 128,-1,383 567 -29 567 -29 567 -39 c 0,384,385 567 -56 567 -56 583.5 -54 c 128,-1,386 600 -52 600 -52 606 -33 c 0,378,379 661 -33 m 0,387,388 663 -27 663 -27 658 -22 c 128,-1,389 653 -17 653 -17 643 -17 c 0,390,391 634 -17 634 -17 629 -22 c 128,-1,392 624 -27 624 -27 627 -33 c 1,393,394 632 -51 632 -51 643 -51 c 128,-1,395 654 -51 654 -51 661 -33 c 0,387,388 EndSplineSet EndChar StartChar: n Encoding: 110 110 6 Width: 1024 Flags: W Fore 421 757 m 0,0,1 420 771 420 771 423.5 773.5 c 128,-1,2 427 776 427 776 441 768 c 0,3,4 467 755 467 755 483 734 c 128,-1,5 499 713 499 713 495 697 c 1,6,7 494 687 494 687 503 683 c 128,-1,8 512 679 512 679 536 681 c 0,9,10 554 682 554 682 581 675 c 128,-1,11 608 668 608 668 628 657 c 0,12,13 672 633 672 633 751.5 552.5 c 128,-1,14 831 472 831 472 826 456 c 1,15,16 821 446 821 446 854 376 c 0,17,18 887 311 887 311 879 297 c 0,19,20 869 283 869 283 893 248 c 0,21,22 916 209 916 209 912 140 c 0,23,24 907 36 907 36 913 1.5 c 128,-1,25 919 -33 919 -33 942 -39 c 0,26,27 960 -44 960 -44 964.5 -55.5 c 128,-1,28 969 -67 969 -67 966 -100 c 2,29,-1 962 -152 l 1,30,-1 627 -155 l 2,31,32 550 -155 550 -155 491.5 -155 c 128,-1,33 433 -155 433 -155 393 -153.5 c 128,-1,34 353 -152 353 -152 328 -150 c 128,-1,35 303 -148 303 -148 294 -144 c 128,-1,36 285 -140 285 -140 289.5 -135 c 128,-1,37 294 -130 294 -130 311 -123 c 0,38,39 333 -113 333 -113 318 -97 c 0,40,41 299 -75 299 -75 325 -68 c 128,-1,42 351 -61 351 -61 433 -65 c 0,43,44 533 -70 533 -70 533 -56 c 128,-1,45 533 -42 533 -42 505 -42 c 0,46,47 479 -42 479 -42 461 -31 c 128,-1,48 443 -20 443 -20 443 -33 c 0,49,50 443 -52 443 -52 422 -47.5 c 128,-1,51 401 -43 401 -43 381 -21 c 0,52,53 363 -2 363 -2 363 3.5 c 128,-1,54 363 9 363 9 382 16 c 0,55,56 405 26 405 26 412 10 c 0,57,58 416 0 416 0 423 0 c 128,-1,59 430 0 430 0 446 8 c 0,60,61 477 24 477 24 519 16 c 0,62,63 565 9 565 9 580 25 c 0,64,65 595 40 595 40 595 25 c 128,-1,66 595 10 595 10 683.5 -0.5 c 128,-1,67 772 -11 772 -11 811 -2 c 0,68,69 839 7 839 7 840 17 c 128,-1,70 841 27 841 27 813.5 34 c 128,-1,71 786 41 786 41 747 39 c 0,72,73 706 35 706 35 692 38.5 c 128,-1,74 678 42 678 42 678 55 c 0,75,76 678 75 678 75 710 77 c 0,77,78 722 77 722 77 726 79.5 c 128,-1,79 730 82 730 82 724 86 c 1,80,81 705 93 705 93 706.5 112 c 128,-1,82 708 131 708 131 726 131 c 0,83,84 735 131 735 131 741 126.5 c 128,-1,85 747 122 747 122 747 117 c 0,86,87 747 104 747 104 767 120 c 0,88,89 775 127 775 127 777 134.5 c 128,-1,90 779 142 779 142 774 142 c 1,91,92 760 147 760 147 762 162 c 128,-1,93 764 177 764 177 782 195 c 0,94,95 801 214 801 214 793 238 c 0,96,97 784 261 784 261 778 245 c 0,98,99 773 229 773 229 753 228.5 c 128,-1,100 733 228 733 228 733 243 c 0,101,102 733 256 733 256 754 279 c 0,103,104 769 293 769 293 767.5 302 c 128,-1,105 766 311 766 311 747 335 c 0,106,107 731 354 731 354 724 369 c 128,-1,108 717 384 717 384 721 388 c 128,-1,109 725 392 725 392 738 386 c 1,110,111 740 384 740 384 739.5 385.5 c 128,-1,112 739 387 739 387 737 389.5 c 128,-1,113 735 392 735 392 731 397.5 c 128,-1,114 727 403 727 403 721.5 409 c 128,-1,115 716 415 716 415 708.5 423.5 c 128,-1,116 701 432 701 432 693 440 c 0,117,118 668 465 668 465 645.5 481.5 c 128,-1,119 623 498 623 498 617 495 c 0,120,121 600 484 600 484 565.5 485.5 c 128,-1,122 531 487 531 487 523 498 c 0,123,124 519 504 519 504 515.5 501 c 128,-1,125 512 498 512 498 512 488 c 128,-1,126 512 478 512 478 505.5 470.5 c 128,-1,127 499 463 499 463 491 463 c 0,128,129 480 463 480 463 478.5 456.5 c 128,-1,130 477 450 477 450 484 430 c 0,131,132 495 397 495 397 482 383 c 0,133,134 462 363 462 363 481.5 362 c 128,-1,135 501 361 501 361 523 380 c 0,136,137 548 404 548 404 565 407 c 128,-1,138 582 410 582 410 583 391 c 0,139,140 583 374 583 374 591 391 c 0,141,142 597 407 597 407 617 408 c 128,-1,143 637 409 637 409 637 394 c 0,144,145 637 378 637 378 598 341.5 c 128,-1,146 559 305 559 305 545 308 c 0,147,148 527 312 527 312 519 297 c 0,149,150 512 284 512 284 486 284 c 0,151,152 459 284 459 284 416 260.5 c 128,-1,153 373 237 373 237 346 207 c 0,154,155 314 173 314 173 296 173 c 0,156,157 290 173 290 173 270 156 c 128,-1,158 250 139 250 139 230 117 c 0,159,160 188 72 188 72 156.5 64 c 128,-1,161 125 56 125 56 125 91 c 0,162,163 125 119 125 119 102 112 c 0,164,165 88 108 88 108 88 113 c 0,166,167 88 115 88 115 90 119 c 0,168,169 99 132 99 132 86 149 c 0,170,171 72 167 72 167 65.5 197 c 128,-1,172 59 227 59 227 71 221 c 0,173,174 83 213 83 213 112 230 c 0,175,176 128 238 128 238 131.5 241.5 c 128,-1,177 135 245 135 245 133 248.5 c 128,-1,178 131 252 131 252 118 259 c 0,179,180 101 268 101 268 107 279.5 c 128,-1,181 113 291 113 291 154 328 c 0,182,183 190 361 190 361 198 374.5 c 128,-1,184 206 388 206 388 194 396 c 0,185,186 181 404 181 404 181.5 409 c 128,-1,187 182 414 182 414 199 425 c 0,188,189 219 436 219 436 219.5 440.5 c 128,-1,190 220 445 220 445 201 459 c 0,191,192 191 466 191 466 187.5 470.5 c 128,-1,193 184 475 184 475 189.5 485 c 128,-1,194 195 495 195 495 206 506 c 128,-1,195 217 517 217 517 245 544 c 2,196,-1 317 609 l 1,197,-1 284 647 l 2,198,199 251 685 251 685 230 685 c 0,200,201 217 685 217 685 216.5 691 c 128,-1,202 216 697 216 697 226 719 c 0,203,204 238 745 238 745 257.5 753 c 128,-1,205 277 761 277 761 277 740 c 0,206,207 277 726 277 726 299 736 c 0,208,209 319 745 319 745 328 714 c 0,210,211 333 693 333 693 346.5 685.5 c 128,-1,212 360 678 360 678 360 696 c 0,213,214 360 700 360 700 369.5 707 c 128,-1,215 379 714 379 714 392 719 c 0,216,217 421 735 421 735 421 757 c 0,0,1 325 657 m 0,218,219 332 671 332 671 320 671 c 0,220,221 305 671 305 671 298 657 c 1,222,223 294 652 294 652 295.5 647.5 c 128,-1,224 297 643 297 643 303 643 c 0,225,226 317 643 317 643 325 657 c 0,218,219 381 602 m 0,227,228 408 632 408 632 400 634 c 128,-1,229 392 636 392 636 363 607 c 0,230,231 332 574 332 574 343 574 c 0,232,233 355 574 355 574 381 602 c 0,227,228 595 629 m 0,234,235 595 643 595 643 560 643 c 0,236,237 526 643 526 643 526 629 c 0,238,239 526 624 526 624 536 620 c 128,-1,240 546 616 546 616 560 616 c 128,-1,241 574 616 574 616 584.5 620 c 128,-1,242 595 624 595 624 595 629 c 0,234,235 443 498 m 0,243,244 443 511 443 511 435 515.5 c 128,-1,245 427 520 427 520 415 515.5 c 128,-1,246 403 511 403 511 392 498 c 0,247,248 370 474 370 474 374 448 c 128,-1,249 378 422 378 422 403 422 c 0,250,251 419 422 419 422 424 428 c 128,-1,252 429 434 429 434 425 450 c 0,253,254 418 477 418 477 430 477 c 0,255,256 443 477 443 477 443 498 c 0,243,244 304 470 m 0,257,258 336 505 336 505 324 505 c 0,259,260 308 505 308 505 280 470 c 0,261,262 250 436 250 436 260 436 c 0,263,264 272 436 272 436 304 470 c 0,257,258 131 173 m 1,265,266 124 187 124 187 116 187 c 0,267,268 111 187 111 187 111 173 c 0,269,270 111 168 111 168 115.5 163.5 c 128,-1,271 120 159 120 159 126 159 c 0,272,273 131 159 131 159 133 163.5 c 128,-1,274 135 168 135 168 131 173 c 1,265,266 798 -54 m 0,275,276 745 -57 745 -57 735 -38 c 0,277,278 730 -29 730 -29 727 -27 c 128,-1,279 724 -25 724 -25 721 -28 c 128,-1,280 718 -31 718 -31 714 -42 c 0,281,282 706 -66 706 -66 706 -71 c 0,283,284 706 -79 706 -79 760.5 -75.5 c 128,-1,285 815 -72 815 -72 830 -62 c 0,286,287 841 -55 841 -55 833.5 -53 c 128,-1,288 826 -51 826 -51 798 -54 c 0,275,276 609 -62 m 0,289,290 609 -49 609 -49 587 -49 c 0,291,292 568 -49 568 -49 574 -62 c 0,293,294 582 -76 582 -76 596 -76 c 0,295,296 601 -76 601 -76 605 -71.5 c 128,-1,297 609 -67 609 -67 609 -62 c 0,289,290 540 443 m 128,-1,299 540 451 540 451 546 457 c 128,-1,300 552 463 552 463 560 463 c 0,301,302 569 463 569 463 575 457 c 128,-1,303 581 451 581 451 581 443 c 128,-1,304 581 435 581 435 575 428.5 c 128,-1,305 569 422 569 422 560 422 c 0,306,307 552 422 552 422 546 428.5 c 128,-1,298 540 435 540 435 540 443 c 128,-1,299 623 443 m 128,-1,309 623 451 623 451 629 457 c 128,-1,310 635 463 635 463 643 463 c 0,311,312 652 463 652 463 658 457 c 128,-1,313 664 451 664 451 664 443 c 128,-1,314 664 435 664 435 658 428.5 c 128,-1,315 652 422 652 422 643 422 c 0,316,317 635 422 635 422 629 428.5 c 128,-1,308 623 435 623 435 623 443 c 128,-1,309 605 296 m 0,318,319 617 311 617 311 622 313.5 c 128,-1,320 627 316 627 316 631.5 311.5 c 128,-1,321 636 307 636 307 646 288 c 0,322,323 664 254 664 254 664.5 179 c 128,-1,324 665 104 665 104 648 104 c 0,325,326 630 104 630 104 648 87 c 0,327,328 662 73 662 73 663.5 47 c 128,-1,329 665 21 665 21 652 21 c 0,330,331 636 21 636 21 617 51 c 0,332,333 596 82 596 82 580 66 c 0,334,335 570 57 570 57 560 58 c 128,-1,336 550 59 550 59 531 70 c 0,337,338 509 86 509 86 506 84 c 128,-1,339 503 82 503 82 508 59 c 256,340,341 513 36 513 36 511.5 35.5 c 128,-1,342 510 35 510 35 498 49 c 1,343,344 497 51 497 51 494 55 c 0,345,346 475 79 475 79 486 100 c 128,-1,347 497 121 497 121 523 111 c 0,348,349 545 102 545 102 563 118.5 c 128,-1,350 581 135 581 135 567 152 c 0,351,352 552 170 552 170 567 180 c 128,-1,353 582 190 582 190 566 209 c 0,354,355 551 228 551 228 566 228 c 0,356,357 572 228 572 228 576.5 234.5 c 128,-1,358 581 241 581 241 581 249 c 0,359,360 581 270 581 270 605 296 c 0,318,319 515 180 m 0,361,362 541 209 541 209 540 194 c 0,363,364 539 190 539 190 536 181 c 1,365,366 527 163 527 163 542 148 c 0,367,368 557 134 557 134 541 126 c 0,369,370 535 122 535 122 530.5 125.5 c 128,-1,371 526 129 526 129 526 137 c 0,372,373 526 146 526 146 521.5 152.5 c 128,-1,374 517 159 517 159 512 159 c 0,375,376 499 159 499 159 515 180 c 0,361,362 706 166 m 128,-1,378 706 174 706 174 712 180.5 c 128,-1,379 718 187 718 187 726 187 c 0,380,381 735 187 735 187 741 180.5 c 128,-1,382 747 174 747 174 747 166 c 128,-1,383 747 158 747 158 741 151.5 c 128,-1,384 735 145 735 145 726 145 c 0,385,386 718 145 718 145 712 151.5 c 128,-1,377 706 158 706 158 706 166 c 128,-1,378 21 159 m 0,387,388 14 173 14 173 26 173 c 0,389,390 42 173 42 173 42 159 c 128,-1,391 42 145 42 145 36 145 c 0,392,393 29 145 29 145 21 159 c 0,387,388 448 124 m 0,394,395 485 153 485 153 482 142 c 0,396,397 481 137 481 137 470 124 c 0,398,399 454 104 454 104 437 104 c 0,400,401 424 104 424 104 448 124 c 0,394,395 415 48 m 0,402,403 415 62 415 62 437 62 c 0,404,405 456 62 456 62 450 48 c 0,406,407 442 34 442 34 428 34 c 0,408,409 423 34 423 34 419 38.5 c 128,-1,410 415 43 415 43 415 48 c 0,402,403 EndSplineSet EndChar StartChar: p Encoding: 112 112 7 Width: 1024 Flags: W Fore 491 696 m 0,0,1 555 705 555 705 579 702 c 128,-1,2 603 699 603 699 617 682 c 0,3,4 634 659 634 659 635.5 614.5 c 128,-1,5 637 570 637 570 621 559 c 0,6,7 605 551 605 551 621 535 c 0,8,9 631 525 631 525 634.5 516.5 c 128,-1,10 638 508 638 508 633 503 c 128,-1,11 628 498 628 498 616 498 c 0,12,13 595 498 595 498 595 484 c 0,14,15 595 453 595 453 639 494 c 0,16,17 657 510 657 510 665 509.5 c 128,-1,18 673 509 673 509 692 491 c 0,19,20 720 467 720 467 720 400 c 0,21,22 720 357 720 357 711.5 336.5 c 128,-1,23 703 316 703 316 673 288 c 0,24,25 627 242 627 242 637 216 c 0,26,27 643 197 643 197 645.5 196.5 c 128,-1,28 648 196 648 196 655 213 c 0,29,30 662 229 662 229 669 226.5 c 128,-1,31 676 224 676 224 703 198 c 0,32,33 746 155 746 155 774.5 111 c 128,-1,34 803 67 803 67 803 45 c 0,35,36 803 19 803 19 818 4 c 0,37,38 832 -10 832 -10 828 -71 c 2,39,-1 823 -132 l 1,40,-1 516 -134 l 2,41,42 336 -135 336 -135 272 -132 c 128,-1,43 208 -129 208 -129 208 -118 c 0,44,45 208 -101 208 -101 228 -83 c 0,46,47 250 -65 250 -65 234 -47 c 0,48,49 218 -27 218 -27 242 -21 c 128,-1,50 266 -15 266 -15 353 -18 c 0,51,52 394 -19 394 -19 423.5 -16 c 128,-1,53 453 -13 453 -13 455 -7 c 0,54,55 459 2 459 2 434.5 9.5 c 128,-1,56 410 17 410 17 384 16.5 c 128,-1,57 358 16 358 16 345 8 c 1,58,59 329 -7 329 -7 322 11 c 0,60,61 314 29 314 29 299 14 c 0,62,63 281 0 281 0 256 27 c 0,64,65 231 55 231 55 240.5 62.5 c 128,-1,66 250 70 250 70 296 58 c 0,67,68 344 44 344 44 353 55 c 0,69,70 360 66 360 66 432 59 c 0,71,72 474 54 474 54 487 56.5 c 128,-1,73 500 59 500 59 495 70 c 0,74,75 491 82 491 82 468 84.5 c 128,-1,76 445 87 445 87 385 84 c 0,77,78 282 79 282 79 271 94 c 0,79,80 261 111 261 111 288.5 122 c 128,-1,81 316 133 316 133 351 126 c 0,82,83 397 116 397 116 437 117.5 c 128,-1,84 477 119 477 119 477 131 c 0,85,86 477 145 477 145 447 145 c 0,87,88 424 145 424 145 414 150 c 128,-1,89 404 155 404 155 410 163.5 c 128,-1,90 416 172 416 172 436 180 c 0,91,92 475 192 475 192 493 178 c 0,93,94 510 164 510 164 533 184 c 0,95,96 546 197 546 197 550.5 209 c 128,-1,97 555 221 555 221 550.5 228 c 128,-1,98 546 235 546 235 533 235 c 0,99,100 525 235 525 235 518.5 230 c 128,-1,101 512 225 512 225 512 218 c 0,102,103 512 202 512 202 495 218 c 0,104,105 480 235 480 235 439 235 c 0,106,107 413 235 413 235 389 243.5 c 128,-1,108 365 252 365 252 354 262 c 128,-1,109 343 272 343 272 348 281.5 c 128,-1,110 353 291 353 291 378 292 c 0,111,112 401 293 401 293 373 300 c 0,113,114 367 302 367 302 360 303 c 0,115,116 334 308 334 308 321 316 c 128,-1,117 308 324 308 324 313.5 332 c 128,-1,118 319 340 319 340 342 343 c 0,119,120 374 348 374 348 388.5 367.5 c 128,-1,121 403 387 403 387 381 396 c 0,122,123 367 402 367 402 372 411 c 128,-1,124 377 420 377 420 407 445 c 2,125,-1 457 487 l 1,126,-1 422 528 l 2,127,128 387 572 387 572 400 585 c 0,129,130 415 600 415 600 415 631 c 0,131,132 415 685 415 685 491 696 c 0,0,1 549 448 m 128,-1,134 558 457 558 457 544 472 c 0,135,136 529 485 529 485 520 473 c 1,137,138 513 460 513 460 526.5 449.5 c 128,-1,133 540 439 540 439 549 448 c 128,-1,134 498 465 m 0,139,140 498 470 498 470 484 470 c 0,141,142 479 470 479 470 474.5 465.5 c 128,-1,143 470 461 470 461 470 455 c 0,144,145 470 450 470 450 474.5 448 c 128,-1,146 479 446 479 446 484 449 c 0,147,148 498 457 498 457 498 465 c 0,139,140 443 354 m 0,149,150 443 360 443 360 429 360 c 0,151,152 424 360 424 360 419.5 355.5 c 128,-1,153 415 351 415 351 415 344 c 0,154,155 415 339 415 339 419.5 337.5 c 128,-1,156 424 336 424 336 429 339 c 0,157,158 443 346 443 346 443 354 c 0,149,150 452 288 m 1,159,160 461 304 461 304 451 314 c 1,161,162 448 318 448 318 445.5 312.5 c 128,-1,163 443 307 443 307 444 296 c 0,164,165 444 281 444 281 448 282 c 1,166,167 450 282 450 282 452 288 c 1,159,160 595 228 m 0,168,169 595 255 595 255 591.5 259.5 c 128,-1,170 588 264 588 264 577 253 c 128,-1,171 566 242 566 242 568 217.5 c 128,-1,172 570 193 570 193 581 193 c 0,173,174 595 193 595 193 595 228 c 0,168,169 554 131 m 128,-1,176 554 139 554 139 547.5 145.5 c 128,-1,177 541 152 541 152 533 152 c 128,-1,178 525 152 525 152 518.5 145.5 c 128,-1,179 512 139 512 139 512 131 c 128,-1,180 512 123 512 123 518.5 116.5 c 128,-1,181 525 110 525 110 533 110 c 128,-1,182 541 110 541 110 547.5 116.5 c 128,-1,175 554 123 554 123 554 131 c 128,-1,176 609 131 m 128,-1,184 609 139 609 139 602.5 145.5 c 128,-1,185 596 152 596 152 588 152 c 128,-1,186 580 152 580 152 573.5 145.5 c 128,-1,187 567 139 567 139 567 131 c 128,-1,188 567 123 567 123 573.5 116.5 c 128,-1,189 580 110 580 110 588 110 c 128,-1,190 596 110 596 110 602.5 116.5 c 128,-1,183 609 123 609 123 609 131 c 128,-1,184 650 124 m 128,-1,192 650 138 650 138 637 138 c 0,193,194 623 138 623 138 623 124 c 0,195,196 623 119 623 119 627.5 114.5 c 128,-1,197 632 110 632 110 637 110 c 0,198,191 650 110 650 110 650 124 c 128,-1,192 554 76 m 128,-1,200 554 84 554 84 547.5 90.5 c 128,-1,201 541 97 541 97 533 97 c 128,-1,202 525 97 525 97 518.5 90.5 c 128,-1,203 512 84 512 84 512 76 c 128,-1,204 512 68 512 68 518.5 61.5 c 128,-1,205 525 55 525 55 533 55 c 128,-1,206 541 55 541 55 547.5 61.5 c 128,-1,199 554 68 554 68 554 76 c 128,-1,200 649 63 m 0,207,208 635 80 635 80 630 81.5 c 128,-1,209 625 83 625 83 617 70 c 0,210,211 614 65 614 65 619.5 59.5 c 128,-1,212 625 54 625 54 638 51 c 0,213,214 655 46 655 46 657 48.5 c 128,-1,215 659 51 659 51 649 63 c 0,207,208 720 -15 m 128,-1,217 720 -2 720 -2 707 5 c 128,-1,218 694 12 694 12 686 4 c 0,219,220 675 -7 675 -7 679 -17.5 c 128,-1,221 683 -28 683 -28 699 -28 c 0,222,216 720 -28 720 -28 720 -15 c 128,-1,217 526 -14 m 0,223,224 526 0 526 0 505 0 c 128,-1,225 484 0 484 0 484 -14 c 0,226,227 484 -19 484 -19 490.5 -23.5 c 128,-1,228 497 -28 497 -28 505 -28 c 128,-1,229 513 -28 513 -28 519.5 -23.5 c 128,-1,230 526 -19 526 -19 526 -14 c 0,223,224 664 -14 m 0,231,232 664 0 664 0 643 0 c 0,233,234 623 0 623 0 623 -14 c 0,235,236 623 -19 623 -19 629 -23.5 c 128,-1,237 635 -28 635 -28 643 -28 c 0,238,239 652 -28 652 -28 658 -23.5 c 128,-1,240 664 -19 664 -19 664 -14 c 0,231,232 761 -14 m 128,-1,242 761 0 761 0 747 0 c 0,243,244 742 0 742 0 737.5 -4 c 128,-1,245 733 -8 733 -8 733 -14 c 0,246,247 733 -19 733 -19 737.5 -23.5 c 128,-1,248 742 -28 742 -28 747 -28 c 0,249,241 761 -28 761 -28 761 -14 c 128,-1,242 EndSplineSet EndChar StartChar: q Encoding: 113 113 8 Width: 1024 Flags: W Fore 462 632 m 0,0,1 470 654 470 654 508 649 c 128,-1,2 546 644 546 644 551 621 c 0,3,4 555 598 555 598 533 576 c 128,-1,5 511 554 511 554 488 558 c 0,6,7 469 562 469 562 461 584.5 c 128,-1,8 453 607 453 607 462 632 c 0,0,1 241 605 m 0,9,10 249 627 249 627 287 622 c 128,-1,11 325 617 325 617 329 594 c 0,12,13 333 570 333 570 311.5 548 c 128,-1,14 290 526 290 526 267 530 c 0,15,16 247 535 247 535 239 557.5 c 128,-1,17 231 580 231 580 241 605 c 0,9,10 684 605 m 0,18,19 692 627 692 627 730 622 c 128,-1,20 768 617 768 617 772 594 c 0,21,22 776 570 776 570 754.5 548 c 128,-1,23 733 526 733 526 710 530 c 0,24,25 690 535 690 535 682 557.5 c 128,-1,26 674 580 674 580 684 605 c 0,18,19 47 549 m 0,27,28 55 571 55 571 93 566 c 128,-1,29 131 561 131 561 136 538 c 0,30,31 140 515 140 515 118 493 c 128,-1,32 96 471 96 471 73 475 c 0,33,34 54 479 54 479 46 501.5 c 128,-1,35 38 524 38 524 47 549 c 0,27,28 877 549 m 0,36,37 885 571 885 571 923 566 c 128,-1,38 961 561 961 561 966 538 c 0,39,40 970 515 970 515 948 493 c 128,-1,41 926 471 926 471 904 475 c 0,42,43 884 479 884 479 876 501.5 c 128,-1,44 868 524 868 524 877 549 c 0,36,37 493 443 m 0,45,46 502 472 502 472 513.5 445.5 c 128,-1,47 525 419 525 419 527 364 c 0,48,49 531 292 531 292 544 292 c 0,50,51 556 292 556 292 551 251 c 0,52,53 546 215 546 215 555.5 211 c 128,-1,54 565 207 565 207 584 237 c 0,55,56 597 259 597 259 617 263.5 c 128,-1,57 637 268 637 268 637 251 c 0,58,59 637 239 637 239 609 220 c 0,60,61 593 210 593 210 586 197.5 c 128,-1,62 579 185 579 185 583.5 176 c 128,-1,63 588 167 588 167 602 167 c 0,64,65 629 167 629 167 659 219 c 128,-1,66 689 271 689 271 699 338 c 0,67,68 707 387 707 387 716.5 408.5 c 128,-1,69 726 430 726 430 734.5 417.5 c 128,-1,70 743 405 743 405 747 361 c 0,71,72 755 294 755 294 767 279 c 128,-1,73 779 264 779 264 810 284 c 0,74,75 839 304 839 304 850 296 c 1,76,77 860 286 860 286 857.5 220 c 128,-1,78 855 154 855 154 844 147 c 0,79,80 830 139 830 139 830 94 c 0,81,82 829 46 829 46 801.5 17 c 128,-1,83 774 -12 774 -12 728 -12 c 0,84,85 678 -12 678 -12 678 -32 c 128,-1,86 678 -52 678 -52 754 -44 c 2,87,-1 830 -39 l 1,88,-1 830 -86 l 1,89,-1 830 -134 l 1,90,-1 505 -134 l 2,91,92 282 -134 282 -134 216 -127 c 128,-1,93 150 -120 150 -120 201 -101 c 0,94,95 223 -91 223 -91 206 -73 c 0,96,97 202 -68 202 -68 199.5 -65.5 c 128,-1,98 197 -63 197 -63 198 -60 c 128,-1,99 199 -57 199 -57 199.5 -55.5 c 128,-1,100 200 -54 200 -54 208.5 -52.5 c 128,-1,101 217 -51 217 -51 222.5 -50.5 c 128,-1,102 228 -50 228 -50 247.5 -49.5 c 128,-1,103 267 -49 267 -49 280 -48.5 c 128,-1,104 293 -48 293 -48 325 -48 c 0,105,106 420 -46 420 -46 426 -33 c 0,107,108 428 -27 428 -27 415 -20.5 c 128,-1,109 402 -14 402 -14 384.5 -10.5 c 128,-1,110 367 -7 367 -7 349 -7.5 c 128,-1,111 331 -8 331 -8 324 -14 c 0,112,113 309 -27 309 -27 299 -17 c 1,114,115 292 -7 292 -7 238 -7 c 0,116,117 187 -4 187 -4 187 15 c 0,118,119 187 27 187 27 201 31.5 c 128,-1,120 215 36 215 36 252 36 c 0,121,122 317 36 317 36 327 46 c 0,123,124 331 50 331 50 339 49 c 128,-1,125 347 48 347 48 354 42 c 0,126,127 370 27 370 27 381 44 c 0,128,129 391 59 391 59 371.5 71 c 128,-1,130 352 83 352 83 329 76 c 0,131,132 307 70 307 70 298 84 c 0,133,134 289 100 289 100 264 79 c 0,135,136 248 63 248 63 236.5 63 c 128,-1,137 225 63 225 63 194 79 c 0,138,139 162 96 162 96 158.5 102 c 128,-1,140 155 108 155 108 173 120 c 0,141,142 195 139 195 139 234 133 c 0,143,144 254 129 254 129 254 131 c 0,145,146 254 132 254 132 249 134 c 0,147,148 220 148 220 148 194.5 181.5 c 128,-1,149 169 215 169 215 176 231 c 0,150,151 181 244 181 244 176 247 c 128,-1,152 171 250 171 250 151 245 c 0,153,154 138 242 138 242 133 242 c 128,-1,155 128 242 128 242 136 245 c 1,156,157 150 253 150 253 151.5 272.5 c 128,-1,158 153 292 153 292 138 292 c 0,159,160 125 292 125 292 125 334 c 0,161,162 125 355 125 355 135 367.5 c 128,-1,163 145 380 145 380 155.5 376 c 128,-1,164 166 372 166 372 167 352 c 0,165,166 167 330 167 330 195 285 c 0,167,168 227 234 227 234 244 184 c 1,169,170 245 177 245 177 251 173.5 c 128,-1,171 257 170 257 170 262 173 c 0,172,173 273 181 273 181 279.5 216 c 128,-1,174 286 251 286 251 277 257 c 1,175,176 269 260 269 260 270 281 c 128,-1,177 271 302 271 302 284 379 c 0,178,179 288 409 288 409 300 423.5 c 128,-1,180 312 438 312 438 322 428.5 c 128,-1,181 332 419 332 419 332 390 c 0,182,183 332 350 332 350 346 340 c 0,184,185 359 332 359 332 354 285 c 0,186,187 352 237 352 237 363 237 c 0,188,189 368 237 368 237 375.5 226 c 128,-1,190 383 215 383 215 387 201 c 1,191,192 394 186 394 186 403 177 c 128,-1,193 412 168 412 168 419 170 c 0,194,195 436 177 436 177 455 234 c 128,-1,196 474 291 474 291 479 354 c 0,197,198 487 429 487 429 493 443 c 0,45,46 789 210 m 0,199,200 789 226 789 226 775.5 222 c 128,-1,201 762 218 762 218 756 201 c 0,202,203 746 176 746 176 749 171.5 c 128,-1,204 752 167 752 167 768 181 c 0,205,206 789 200 789 200 789 210 c 0,199,200 354 165 m 0,207,208 345 181 345 181 324 181 c 0,209,210 305 181 305 181 296 159.5 c 128,-1,211 287 138 287 138 300 125 c 128,-1,212 313 112 313 112 338.5 130.5 c 128,-1,213 364 149 364 149 354 165 c 0,207,208 551 152 m 0,214,215 548 169 548 169 514 177.5 c 128,-1,216 480 186 480 186 466 173 c 0,217,218 457 162 457 162 457 123 c 0,219,220 457 101 457 101 463 92.5 c 128,-1,221 469 84 469 84 483 84 c 0,222,223 509 84 509 84 532 107 c 128,-1,224 555 130 555 130 551 152 c 0,214,215 713 167 m 0,225,226 703 181 703 181 677 181 c 0,227,228 662 181 662 181 656 173.5 c 128,-1,229 650 166 650 166 650 147 c 0,230,231 650 132 650 132 656 122 c 128,-1,232 662 112 662 112 670 112 c 0,233,234 689 112 689 112 705 133 c 128,-1,235 721 154 721 154 713 167 c 0,225,226 423 33 m 0,236,237 431 40 431 40 426 58 c 0,238,239 421 74 421 74 415 66 c 0,240,241 413 64 413 64 410 58 c 1,242,243 400 45 400 45 406.5 33.5 c 128,-1,244 413 22 413 22 423 33 c 0,236,237 495 -29 m 0,245,246 497 -23 497 -23 491.5 -17.5 c 128,-1,247 486 -12 486 -12 477 -12 c 128,-1,248 468 -12 468 -12 463 -17.5 c 128,-1,249 458 -23 458 -23 461 -29 c 1,250,251 466 -47 466 -47 477 -47 c 128,-1,252 488 -47 488 -47 495 -29 c 0,245,246 609 -33 m 128,-1,254 609 -25 609 -25 602.5 -18.5 c 128,-1,255 596 -12 596 -12 588 -12 c 128,-1,256 580 -12 580 -12 573.5 -18.5 c 128,-1,257 567 -25 567 -25 567 -33 c 128,-1,258 567 -41 567 -41 573.5 -47.5 c 128,-1,259 580 -54 580 -54 588 -54 c 128,-1,260 596 -54 596 -54 602.5 -47.5 c 128,-1,253 609 -41 609 -41 609 -33 c 128,-1,254 664 -33 m 128,-1,262 664 -25 664 -25 658 -18.5 c 128,-1,263 652 -12 652 -12 643 -12 c 0,264,265 635 -12 635 -12 629 -18.5 c 128,-1,266 623 -25 623 -25 623 -33 c 128,-1,267 623 -41 623 -41 629 -47.5 c 128,-1,268 635 -54 635 -54 643 -54 c 0,269,270 652 -54 652 -54 658 -47.5 c 128,-1,261 664 -41 664 -41 664 -33 c 128,-1,262 852 365 m 0,271,272 862 375 862 375 874 366 c 128,-1,273 886 357 886 357 886 339 c 0,274,275 886 331 886 331 879.5 325.5 c 128,-1,276 873 320 873 320 865 320 c 0,277,278 849 320 849 320 844.5 336.5 c 128,-1,279 840 353 840 353 852 365 c 0,271,272 581 320 m 0,280,281 581 334 581 334 617 334 c 0,282,283 651 334 651 334 648 317 c 1,284,285 639 299 639 299 632 303 c 1,286,287 617 306 617 306 602 306 c 0,288,289 594 306 594 306 587.5 310.5 c 128,-1,290 581 315 581 315 581 320 c 0,280,281 127 179 m 0,291,292 124 190 124 190 129.5 193.5 c 128,-1,293 135 197 135 197 145.5 191.5 c 128,-1,294 156 186 156 186 167 173 c 0,295,296 180 159 180 159 179 155.5 c 128,-1,297 178 152 178 152 161 155 c 0,298,299 135 160 135 160 127 179 c 0,291,292 EndSplineSet EndChar StartChar: r Encoding: 114 114 9 Width: 1024 Flags: W Fore 298 750 m 0,0,1 309 769 309 769 320.5 753.5 c 128,-1,2 332 738 332 738 332 702 c 0,3,4 332 665 332 665 349 652 c 128,-1,5 366 639 366 639 414 639 c 0,6,7 451 639 451 639 466 624 c 0,8,9 482 608 482 608 490 624 c 0,10,11 499 639 499 639 486 639 c 0,12,13 472 639 472 639 475 681 c 0,14,15 476 722 476 722 512 733 c 0,16,17 521 736 521 736 539 743 c 128,-1,18 557 750 557 750 560 751 c 0,19,20 567 753 567 753 572.5 739 c 128,-1,21 578 725 578 725 581 702 c 0,22,23 586 660 586 660 595 653 c 128,-1,24 604 646 604 646 650 646 c 0,25,26 694 646 694 646 704.5 652.5 c 128,-1,27 715 659 715 659 720 688 c 0,28,29 726 730 726 730 754 733 c 0,30,31 779 738 779 738 796 751 c 0,32,33 816 771 816 771 823 755 c 128,-1,34 830 739 830 739 830 673 c 0,35,36 830 608 830 608 826 595.5 c 128,-1,37 822 583 822 583 803 588 c 0,38,39 775 595 775 595 775 580 c 0,40,41 775 564 775 564 747 529 c 0,42,43 730 506 730 506 725 470.5 c 128,-1,44 720 435 720 435 721 328 c 0,45,46 721 233 721 233 725.5 195 c 128,-1,47 730 157 730 157 743.5 138 c 128,-1,48 757 119 757 119 793 104 c 0,49,50 815 94 815 94 822.5 81 c 128,-1,51 830 68 830 68 830 39 c 0,52,53 830 13 830 13 836 1 c 128,-1,54 842 -11 842 -11 858 -15 c 128,-1,55 874 -19 874 -19 880 -32 c 128,-1,56 886 -45 886 -45 886 -76 c 2,57,-1 886 -130 l 1,58,-1 519 -131 l 2,59,60 288 -132 288 -132 220 -129 c 128,-1,61 152 -126 152 -126 152 -113 c 0,62,63 152 -105 152 -105 159 -99.5 c 128,-1,64 166 -94 166 -94 176 -94 c 0,65,66 189 -94 189 -94 190.5 -90.5 c 128,-1,67 192 -87 192 -87 183 -77 c 0,68,69 144 -39 144 -39 205 -39 c 0,70,71 244 -39 244 -39 252.5 -28.5 c 128,-1,72 261 -18 261 -18 239 6 c 0,73,74 232 14 232 14 230 17 c 128,-1,75 228 20 228 20 225 24.5 c 128,-1,76 222 29 222 29 228 30 c 128,-1,77 234 31 234 31 237 33 c 128,-1,78 240 35 240 35 257.5 35 c 128,-1,79 275 35 275 35 287.5 35.5 c 128,-1,80 300 36 300 36 332 36 c 0,81,82 422 38 422 38 422 51 c 0,83,84 422 66 422 66 364 61 c 0,85,86 307 56 307 56 277 65 c 0,87,88 239 78 239 78 261.5 89 c 128,-1,89 284 100 284 100 346 100 c 0,90,91 401 100 401 100 413.5 103.5 c 128,-1,92 426 107 426 107 419 123 c 0,93,94 415 132 415 132 416.5 134.5 c 128,-1,95 418 137 418 137 424 132.5 c 128,-1,96 430 128 430 128 443 116 c 0,97,98 462 99 462 99 472.5 96 c 128,-1,99 483 93 483 93 494 101 c 0,100,101 512 118 512 118 512 101 c 0,102,103 512 95 512 95 516.5 90.5 c 128,-1,104 521 86 521 86 526 86 c 0,105,106 544 86 544 86 536.5 103.5 c 128,-1,107 529 121 529 121 491 165 c 0,108,109 443 223 443 223 457 231 c 0,110,111 470 239 470 239 456.5 259.5 c 128,-1,112 443 280 443 280 425 280 c 0,113,114 409 280 409 280 426 263 c 0,115,116 457 232 457 232 421 219 c 0,117,118 399 210 399 210 372 230 c 0,119,120 359 238 359 238 355 242.5 c 128,-1,121 351 247 351 247 354 250 c 128,-1,122 357 253 357 253 368 257 c 0,123,124 379 262 379 262 381.5 265.5 c 128,-1,125 384 269 384 269 380.5 275.5 c 128,-1,126 377 282 377 282 363 295 c 0,127,128 347 309 347 309 338.5 332 c 128,-1,129 330 355 330 355 333 371.5 c 128,-1,130 336 388 336 388 350 385 c 0,131,132 356 383 356 383 358.5 383.5 c 128,-1,133 361 384 361 384 357 386 c 0,134,135 345 394 345 394 347 413 c 128,-1,136 349 432 349 432 361 432 c 0,137,138 376 432 376 432 357 450 c 128,-1,139 338 468 338 468 314 477 c 0,140,141 292 485 292 485 297.5 499.5 c 128,-1,142 303 514 303 514 329 516 c 0,143,144 339 517 339 517 329.5 520.5 c 128,-1,145 320 524 320 524 298 527 c 0,146,147 266 532 266 532 252.5 540 c 128,-1,148 239 548 239 548 247.5 557 c 128,-1,149 256 566 256 566 284 572 c 256,150,151 312 578 312 578 313 580 c 1,152,-1 300 583 l 1,153,154 297 583 297 583 291 584 c 0,155,156 242 586 242 586 232 585 c 0,157,158 212 583 212 583 202 596 c 128,-1,159 192 609 192 609 206 619 c 1,160,161 220 626 220 626 213 645 c 0,162,163 204 669 204 669 222 702.5 c 128,-1,164 240 736 240 736 262 736 c 0,165,166 288 736 288 736 298 750 c 0,0,1 408 530 m 0,167,168 399 544 399 544 393 541.5 c 128,-1,169 387 539 387 539 387 520 c 0,170,171 387 512 387 512 391.5 508.5 c 128,-1,172 396 505 396 505 401 508 c 0,173,174 416 516 416 516 408 530 c 0,167,168 616 487 m 0,175,176 609 501 609 501 602 501 c 128,-1,177 595 501 595 501 588 487 c 0,178,179 585 482 585 482 589 477.5 c 128,-1,180 593 473 593 473 602 473 c 128,-1,181 611 473 611 473 615 477.5 c 128,-1,182 619 482 619 482 616 487 c 0,175,176 408 473 m 0,183,184 402 487 402 487 393 487 c 0,185,186 387 487 387 487 387 473 c 0,187,188 387 468 387 468 391.5 463.5 c 128,-1,189 396 459 396 459 403 459 c 0,190,191 408 459 408 459 409.5 463.5 c 128,-1,192 411 468 411 468 408 473 c 0,183,184 470 383 m 0,193,194 470 404 470 404 458 404 c 0,195,196 445 404 445 404 438 391.5 c 128,-1,197 431 379 431 379 439 371 c 0,198,199 450 360 450 360 460 364 c 128,-1,200 470 368 470 368 470 383 c 0,193,194 436 335 m 0,201,202 429 349 429 349 421 349 c 0,203,204 415 349 415 349 415 335 c 0,205,206 415 330 415 330 419.5 325.5 c 128,-1,207 424 321 424 321 430 321 c 0,208,209 435 321 435 321 437 325.5 c 128,-1,210 439 330 439 330 436 335 c 0,201,202 498 300 m 0,211,212 498 321 498 321 486 321 c 0,213,214 473 321 473 321 465.5 308.5 c 128,-1,215 458 296 458 296 466 288 c 0,216,217 478 277 478 277 488 281 c 128,-1,218 498 285 498 285 498 300 c 0,211,212 526 217 m 0,219,220 526 238 526 238 513 238 c 128,-1,221 500 238 500 238 493 225.5 c 128,-1,222 486 213 486 213 494 205 c 0,223,224 505 194 505 194 515.5 197.5 c 128,-1,225 526 201 526 201 526 217 c 0,219,220 581 149 m 0,226,227 581 155 581 155 567 155 c 0,228,229 554 155 554 155 554 140 c 0,230,231 554 127 554 127 567 134 c 0,232,233 581 140 581 140 581 149 c 0,226,227 623 107 m 0,234,235 623 127 623 127 609 127 c 0,236,237 604 127 604 127 599.5 121 c 128,-1,238 595 115 595 115 595 107 c 0,239,240 595 98 595 98 599.5 92 c 128,-1,241 604 86 604 86 609 86 c 0,242,243 623 86 623 86 623 107 c 0,234,235 498 51 m 0,244,245 498 68 498 68 488 71.5 c 128,-1,246 478 75 478 75 466 62 c 0,247,248 454 51 454 51 457.5 40.5 c 128,-1,249 461 30 461 30 477 30 c 0,250,251 485 30 485 30 491.5 36.5 c 128,-1,252 498 43 498 43 498 51 c 0,244,245 609 51 m 128,-1,254 609 59 609 59 602.5 65.5 c 128,-1,255 596 72 596 72 588 72 c 128,-1,256 580 72 580 72 573.5 65.5 c 128,-1,257 567 59 567 59 567 51 c 128,-1,258 567 43 567 43 573.5 36.5 c 128,-1,259 580 30 580 30 588 30 c 128,-1,260 596 30 596 30 602.5 36.5 c 128,-1,253 609 43 609 43 609 51 c 128,-1,254 668 53 m 0,261,262 661 71 661 71 642 71 c 128,-1,263 623 71 623 71 623 53 c 0,264,265 623 38 623 38 641 27 c 128,-1,266 659 16 659 16 668 26 c 1,267,268 677 33 677 33 668 53 c 0,261,262 706 58 m 0,269,270 706 72 706 72 692 72 c 0,271,272 687 72 687 72 682.5 68 c 128,-1,273 678 64 678 64 678 58 c 0,274,275 678 53 678 53 682.5 48.5 c 128,-1,276 687 44 687 44 692 44 c 0,277,278 698 44 698 44 702 48.5 c 128,-1,279 706 53 706 53 706 58 c 0,269,270 374 -18 m 0,280,281 347 -27 347 -27 328 -14 c 1,282,283 313 0 313 0 293 -19 c 0,284,285 282 -32 282 -32 286.5 -35.5 c 128,-1,286 291 -39 291 -39 317 -39 c 0,287,288 355 -39 355 -39 379 -47 c 0,289,290 401 -56 401 -56 401 -32 c 0,291,292 401 -19 401 -19 395 -16 c 128,-1,293 389 -13 389 -13 374 -18 c 0,280,281 462 -40 m 1,294,295 472 -29 472 -29 458 -19 c 0,296,297 445 -10 445 -10 437 -24 c 1,298,299 428 -35 428 -35 441 -44 c 0,300,301 446 -48 446 -48 452.5 -46.5 c 128,-1,302 459 -45 459 -45 462 -40 c 1,294,295 637 -40 m 128,-1,304 637 -27 637 -27 624 -20 c 128,-1,305 611 -13 611 -13 603 -21 c 0,306,307 592 -32 592 -32 596 -42.5 c 128,-1,308 600 -53 600 -53 616 -53 c 0,309,303 637 -53 637 -53 637 -40 c 128,-1,304 692 -39 m 0,310,311 692 -25 692 -25 671 -25 c 128,-1,312 650 -25 650 -25 650 -39 c 0,313,314 650 -44 650 -44 656.5 -48.5 c 128,-1,315 663 -53 663 -53 671 -53 c 128,-1,316 679 -53 679 -53 685.5 -48.5 c 128,-1,317 692 -44 692 -44 692 -39 c 0,310,311 740 -39 m 0,318,319 746 -25 746 -25 728 -25 c 0,320,321 706 -25 706 -25 706 -39 c 128,-1,322 706 -53 706 -53 718 -53 c 0,323,324 732 -53 732 -53 740 -39 c 0,318,319 803 -30 m 0,325,326 803 -25 803 -25 780 -25 c 0,327,328 772 -25 772 -25 768.5 -29.5 c 128,-1,329 765 -34 765 -34 768 -39 c 0,330,331 774 -48 774 -48 788.5 -45 c 128,-1,332 803 -42 803 -42 803 -30 c 0,325,326 415 202 m 128,-1,334 415 210 415 210 429 210 c 128,-1,335 443 210 443 210 443 205 c 0,336,337 443 198 443 198 452 173 c 0,338,339 458 156 458 156 457 155 c 128,-1,340 456 154 456 154 439 172 c 0,341,333 415 194 415 194 415 202 c 128,-1,334 353 127 m 0,342,343 347 141 347 141 358 141 c 0,344,345 374 141 374 141 374 127 c 128,-1,346 374 113 374 113 368 113 c 0,347,348 361 113 361 113 353 127 c 0,342,343 EndSplineSet EndChar EndChars EndSplineFont tagua-1.0-alpha2/data/themes/pieces/YahooTTF/Yahoo.ttf000066400000000000000000000162341077523320400225320ustar00rootroot00000000000000`FFTMD צGDEF'`OS/2VbhVcmapbcvt "@gaspXglyf&s\head6hhea:$$hmtx loca&DmaxpbH name+dCpost 6762676'&'&7>76&'&'&632>'&#.7>654#"/'&&'&'.27>&'&6'&76'&#&76'.3232654'.5467667>&'&67>'&66'&67.3:4&362'&4632&G< ( * ͎("7Uh   $*& (9&"L! !H'V / S "! (    - "! E..%"#      2 &T! 5 ) )   E ' DPP    /        ( *"S * , &  (I 58      $!   $   w[ (4CMV^fqy>#"76767625432#"#"76!".76'.>364'"&'.76676&&54&#"&7627676'.6654&'.>7>&'"'&76/6&'.76767>54'&676&'&766'&&7>&326%&"264&#">4&"274&3264&#"3264&#"32.66'&4&76'&766%4&#"'&4&"654#"&74&"264&#"674#"64#"374#"3264#"676&#"676&#"2%     *    #.*#%#/h<  ),  !  -          ! "=!#(+9""  - !  !|  7  ` S   _   $!c6? !       S   T   o 7  * S o  l !=  p-   3 1/(D 0  ,$      $   -        35 ;  4 2 (*2  , /2V          * 4  /     +  %  R *   "    e )3=hx&676*.676'&64#"&&'&476276767>&&54726'&6327>#&676'&5476&'.6.'.&'&#"7>7>'&#"#"545476'.7>&'&67>'&67>'.>?'&#"&7>76546766#"326&3274#"264&326'&326#"32&#"326'.676&4#"3264632#"64632#">#"#"'&&'&'&'&66'&6'&326546&54&#"4632#"%&32#"6#"432#"& 6,!!   MuP2 4Rd$**.'7')   (  -E   '"(NV (*?    )$   H!!  '  ` @ #"     5 m E  G      $ B    G %   *   FA#'EhE!4         &    !   !I /""-# < %!  A&&  N )!7~ 4 ##"          ~ "4  * ! Z      8 y=6#"7676&5476'&6676&'&'&6766'.'&6654#"&6767>&#"'&#".676'&'.67>'&6?'&76546'&'4#"764#"766'&724&324&"264&":4#"34&"27.64&3'4"2674#"3264#"3@0  ,. +9ʹ0W);14 .0 H*.3267>76#"?!"&76'.>3676.'&#&546327676&'&"'.7654'.76&"7>#"5467>'&67>327>76476&#"67.3267&#"3266'&6&"264&"264&#"326#"&432'&#"&&6'&L,L+L+L,GL,   ( <   7.2LL߄3 ' _#$ 63%A  '  '3         &. M 3D .    R  y  D     $"  :  x ,- ,- ,- ,- ,-Q57H)$   hC1+,C -0:(/0      C '*-32F*M( /0r?K #+% '.%*y 3       !!  |v %.5=DLU\63276#"767>76326767676'&&546326'&326'.>263654'&6326'&67632&'&76&#"'.67>&'.66'&632&'&676&'.6767'"'&&76'&632&76&"26&#"3264#"6&#"3264#"64"64#"764#"324&32624&"27&"7674#"326'&3254&6'&64&374"2676#"3274#"6$42'&32#"* "0% $ $ .,  $   '=' # Z:9&->7   &0 $    &    1  $x   ;  " ;   7 * }  o  H&$   & I     L*  0 G| V $%*) * *  BA#Gk_L& 6   &      #,:)   .!&$  C  U !  D 4 !  #      G          -:v!Jr t     B  >  P  Created by Io with FontForge 1.0 (http://fontforge.sf.net)Created by Io with FontForge 1.0 (http://fontforge.sf.net)YahooYahooMediumMediumFontForge 1.0 : Yahoo : 19-7-2007FontForge 1.0 : Yahoo : 19-7-2007YahooYahooVersion 001.000 Version 001.000 YahooYahoo2 ENQSTU  ?M|ptagua-1.0-alpha2/data/themes/pieces/YahooTTF/theme.desktop000066400000000000000000000002631077523320400234240ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Yahoo Type=Application Comment=Yahoo pieces, converted|to TTF with potrace.| (unknown author) X-Tagua-ThemeType=Pieces X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/pieces/YahooTTF/theme.lua000066400000000000000000000021631077523320400225350ustar00rootroot00000000000000import("piece_theme.lua") shadow = 7 shadow_color = "#404040" shadow_offset_x = 3 shadow_offset_y = 3 shadow_grow = 6 function fromGlyphW(glyph) return function(size) local g = LinearGradient(Point(0.2*size,0), Point(0.8*size,0)) g[0] = "#bcbabc" g[1] = "#939593" return fromFontGlyph("Yahoo.ttf", glyph, g, "#e0e0e0", 2, false)(size) end end function fromGlyphB(glyph) return function(size) local g = LinearGradient(Point(0.2*size,0), Point(0.8*size,0)) g[0] = "#cecfce" g[1] = "#636563" return fromFontGlyph("Yahoo.ttf", glyph, "#000000", g, 2, false)(size) end end theme.white_bishop = fromGlyphW("0x0062") theme.white_king = fromGlyphW("0x006B") theme.white_knight = fromGlyphW("0x006E") theme.white_pawn = fromGlyphW("0x0070") theme.white_queen = fromGlyphW("0x0071") theme.white_rook = fromGlyphW("0x0072") theme.black_bishop = fromGlyphB("0x0062") theme.black_king = fromGlyphB("0x006B") theme.black_knight = fromGlyphB("0x006E") theme.black_pawn = fromGlyphB("0x0070") theme.black_queen = fromGlyphB("0x0071") theme.black_rook = fromGlyphB("0x0072") tagua-1.0-alpha2/data/themes/squares/000077500000000000000000000000001077523320400175045ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/squares/Default/000077500000000000000000000000001077523320400210705ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/squares/Default/arrow_grey.svg000066400000000000000000000054501077523320400237750ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/squares/Default/arrow_yellow.svg000066400000000000000000000054551077523320400243470ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/squares/Default/selection.lua000066400000000000000000000013701077523320400235610ustar00rootroot00000000000000import("piece_theme.lua") function alone(color) return function(size) local i = Image(size,size) i:clear() i:draw_line(Point(size*0.1,size*0.1), Point(size*0.9,size*0.1), color, size*0.1); i:draw_line(Point(size*0.1,size*0.9), Point(size*0.9,size*0.9), color, size*0.1); i:draw_line(Point(size*0.1,size*0.1), Point(size*0.1,size*0.9), color, size*0.1); i:draw_line(Point(size*0.9,size*0.1), Point(size*0.9,size*0.9), color, size*0.1); local a = Color(color) a.a = 64 i:fill_rect(Rect(size*0.1,size*0.1,size*0.8,size*0.8), a); i:exp_blur(size*0.1); return i end end theme.validmove = fromColor("#cd9eee") theme.highlighting = alone("#80ff80") theme.premove = alone("#4040ff") theme.selection = alone("#ff4040") tagua-1.0-alpha2/data/themes/squares/Default/spiral.svg000066400000000000000000000101541077523320400231040ustar00rootroot00000000000000 image/svg+xml tagua-1.0-alpha2/data/themes/squares/Default/theme.desktop000066400000000000000000000002701077523320400235640ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Default Type=Application Comment=Default squares X-Tagua-ThemeType=Squares X-Tagua-Variants=Chess[default], Shogi, XiangQi X-Tagua-Script=theme.lua tagua-1.0-alpha2/data/themes/squares/Default/theme.lua000066400000000000000000000007551077523320400227040ustar00rootroot00000000000000import("piece_theme.lua") import("selection.lua") theme.background = function (size) local dark_square = Color("#6b829c") local light_square = Color("#b8c0c0") dark_square.a = 224 light_square.a = 224 local i = Image(size*2,size*2) i:set_paint_over(false); i:fill_rect(Rect(0,0,size,size), light_square) i:fill_rect(Rect(size,0,size,size), dark_square) i:fill_rect(Rect(0,size,size,size), dark_square) i:fill_rect(Rect(size,size,size,size), light_square) return i end tagua-1.0-alpha2/data/themes/squares/Default/theme_babaschess.desktop000066400000000000000000000002241077523320400257410ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=BabasChess Type=Application Comment=BabasChess default squares X-Tagua-ThemeType=Squares X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/squares/Default/theme_babaschess.lua000066400000000000000000000006751077523320400250630ustar00rootroot00000000000000import("piece_theme.lua") import("selection.lua") theme.background = function(size) local dark_square = "#008284" local light_square = "#c6dfc6" local i = Image(size*2,size*2) i:fill_rect(Rect(0,0,size,size), light_square) i:fill_rect(Rect(size,0,size,size), dark_square) i:fill_rect(Rect(0,size,size,size), dark_square) i:fill_rect(Rect(size,size,size,size), light_square) return i end theme.validmove = fromColor("#ffff8c") tagua-1.0-alpha2/data/themes/squares/Default/theme_chainreaction.desktop000066400000000000000000000002301077523320400264470ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Default Type=Application Comment=Default squares X-Tagua-ThemeType=Controls X-Tagua-Variants=ChainReaction[default] tagua-1.0-alpha2/data/themes/squares/Default/theme_chainreaction.lua000066400000000000000000000006411077523320400255650ustar00rootroot00000000000000import("piece_theme.lua") import("selection.lua") theme.background = function(size) local i = Image(size,size) i:clear("#a0a0a0"); i:draw_line(Point(0,0),Point(size,0), "black", 2); i:draw_line(Point(0,size),Point(size,size), "black", 2); i:draw_line(Point(0,0),Point(0,size), "black", 2); i:draw_line(Point(size,0),Point(size,size), "black", 2); return i end theme.validmove = fromColor("#bdaede") tagua-1.0-alpha2/data/themes/squares/Default/theme_connect4.desktop000066400000000000000000000002221077523320400253560ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Default Type=Application Comment=Default squares X-Tagua-ThemeType=Squares X-Tagua-Variants=Connect4[default] tagua-1.0-alpha2/data/themes/squares/Default/theme_connect4.lua000066400000000000000000000010301077523320400244640ustar00rootroot00000000000000import("piece_theme.lua") import("selection.lua") theme.background = function(size) local upper = Image(size,size) local lower = Image(size,size) upper:fill_rect(Rect(0,0,size,size), "#8090a0") upper:draw_svg(Rect(0,0,size,size), "arrow_grey.svg") lower:fill_rect(Rect(0,0,size,size), "#2030d0") lower:draw_svg(Rect(0,0,size,size), "spiral.svg") return { [Rect(0,0,size*7,size)] = upper, [Rect(0,size,size*7,size*6)] = lower } end theme.highlighting = fromSVG("arrow_yellow.svg") theme.validmove = fromColor("#bdaede") tagua-1.0-alpha2/data/themes/squares/Default/theme_reversi.desktop000066400000000000000000000002211077523320400253170ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Default Type=Application Comment=Default squares X-Tagua-ThemeType=Squares X-Tagua-Variants=Reversi[default] tagua-1.0-alpha2/data/themes/squares/Default/theme_reversi.lua000066400000000000000000000006401077523320400244340ustar00rootroot00000000000000import("piece_theme.lua") import("selection.lua") theme.background = function(size) local i = Image(size,size) i:clear("#008040"); i:draw_line(Point(0,0),Point(size,0), "black", 2); i:draw_line(Point(0,size),Point(size,size), "black", 2); i:draw_line(Point(0,0),Point(0,size), "black", 2); i:draw_line(Point(size,0),Point(size,size), "black", 2); return i end theme.validmove = fromColor("#bdaede") tagua-1.0-alpha2/data/themes/squares/Default/theme_shogi.desktop000066400000000000000000000002751077523320400247620ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Shogi Type=Application Comment=Shogi-like squares X-Tagua-ThemeType=Squares X-Tagua-Variants=Shogi[default],LargeShogi[default],ToriShogi[default],Chess tagua-1.0-alpha2/data/themes/squares/Default/theme_shogi.lua000066400000000000000000000020071077523320400240650ustar00rootroot00000000000000import("piece_theme.lua") import("selection.lua") theme.options = OptList { ColorOpt("square", "Square color", "#EBD6A0"), IntOpt("alpha", "Alpha", 192, 0, 255, "slider"), BoolOpt("useborder", "Use border", true, OptList { ColorOpt("border", "Border color", "#9C8755"), IntOpt("bwidth", "Border width", 3, 1, 10) }) } theme.background = function(size) local i = Image(size,size) local square = theme.options.square.value local useborder = theme.options.useborder.value local border = theme.options.useborder.sub_options.border.value local bwidth = theme.options.useborder.sub_options.bwidth.value square.a = theme.options.alpha.value i:clear(square); if(useborder) then i:draw_line(Point(0,0),Point(size,0), border, bwidth); i:draw_line(Point(0,size),Point(size,size), border, bwidth); i:draw_line(Point(0,0),Point(0,size), border, bwidth); i:draw_line(Point(size,0),Point(size,size), border, bwidth); end return i end theme.validmove = fromColor("#bdaede") tagua-1.0-alpha2/data/themes/squares/Default/theme_solid.desktop000066400000000000000000000002551077523320400247610ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Custom Color Type=Application Comment=Squares with a solid custom color X-Tagua-ThemeType=Squares X-Tagua-Variants=Chess, Shogi, XiangQi tagua-1.0-alpha2/data/themes/squares/Default/theme_solid.lua000066400000000000000000000013271077523320400240720ustar00rootroot00000000000000import("piece_theme.lua") import("selection.lua") theme.options = OptList { ColorOpt("light", "Light square", "white"), ColorOpt("dark", "Dark square", "black"), IntOpt("alpha", "Alpha", 192, 0, 255, "slider"), } theme.background = function(size) local dark_square = theme.options.dark.value local light_square = theme.options.light.value dark_square.a = theme.options.alpha.value light_square.a = theme.options.alpha.value local i = Image(size*2,size*2) i:set_paint_over(false) i:fill_rect(Rect(0,0,size,size), light_square) i:fill_rect(Rect(size,0,size,size), dark_square) i:fill_rect(Rect(0,size,size,size), dark_square) i:fill_rect(Rect(size,size,size,size), light_square) return i end tagua-1.0-alpha2/data/themes/squares/Default/theme_xboard.desktop000066400000000000000000000002141077523320400251210ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=XBoard Type=Application Comment=XBoard default squares X-Tagua-ThemeType=Squares X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/squares/Default/theme_xboard.lua000066400000000000000000000014471077523320400242420ustar00rootroot00000000000000import("piece_theme.lua") import("selection.lua") theme.background = function(size) local dark_square = "#73a26b" local light_square = "#c6c363" local i = Image(size*2,size*2) i:fill_rect(Rect(0,0,size,size), light_square) i:fill_rect(Rect(size,0,size,size), dark_square) i:fill_rect(Rect(0,size,size,size), dark_square) i:fill_rect(Rect(size,size,size,size), light_square) i:draw_line(Point(0,0),Point(2*size,0), "black", 2); i:draw_line(Point(0,size),Point(2*size,size), "black", 2); i:draw_line(Point(0,2*size),Point(2*size,2*size), "black", 2); i:draw_line(Point(0,0),Point(0,2*size), "black", 2); i:draw_line(Point(size,0),Point(size,2*size), "black", 2); i:draw_line(Point(2*size,0),Point(2*size,2*size), "black", 2); return i end theme.validmove = fromColor("#bdaede") tagua-1.0-alpha2/data/themes/squares/Default/theme_xiangqi.desktop000066400000000000000000000002211077523320400253000ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Xiangqi Type=Application Comment=Xiangqi squares X-Tagua-ThemeType=Squares X-Tagua-Variants=Xiangqi[default] tagua-1.0-alpha2/data/themes/squares/Default/theme_xiangqi.lua000066400000000000000000000175411077523320400244250ustar00rootroot00000000000000import("piece_theme.lua") theme.options = OptList { ColorOpt("square", "Square color", "#D9C48F"), ColorOpt("table", "Table color", "#B9A46F"), BoolOpt("useborder", "Use border", true, OptList { ColorOpt("border", "Border color", "#724D18"), IntOpt("bwidth", "Border width", 2, 1, 10) }) } function Pt(x, y) return Point(math.floor(x), math.floor(y)) end theme.background = function(size) local square = theme.options.square.value local table = theme.options.table.value local border = theme.options.useborder.sub_options.border.value local bwidth = theme.options.useborder.sub_options.bwidth.value local rb = Image(size,size) local rt = Image(size,size) local lb = Image(size,size) local lt = Image(size,size) local rlb = Image(size,size) local rlt = Image(size,size) local i_rlb = Image(size,size) local i_rlt = Image(size,size) local ltb = Image(size,size) local rtb = Image(size,size) local i_ltb1 = Image(size,size) local i_rtb1 = Image(size,size) local i_ltb2 = Image(size,size) local i_rtb2 = Image(size,size) local rltb = Image(size,size) local castle1 = Image(3*size,3*size) local castle2 = Image(3*size,3*size) rb:clear(table) rb:fill_rect(Rect(size*0.5,size*0.5,size*0.5, size*0.5), square) rb:draw_line(Pt(size,size*0.5),Pt(size*0.5,size*0.5), border, bwidth) rb:draw_line(Pt(size*0.5,size),Pt(size*0.5,size*0.5), border, bwidth) rt:clear(table) rt:fill_rect(Rect(size*0.5,0,size*0.5, size*0.5), square) rt:draw_line(Pt(size,size*0.5),Pt(size*0.5,size*0.5), border, bwidth) rt:draw_line(Pt(size*0.5,0),Pt(size*0.5,size*0.5), border, bwidth) lb:clear(table) lb:fill_rect(Rect(0,size*0.5,size*0.5, size*0.5), square) lb:draw_line(Pt(0,size*0.5),Pt(size*0.5,size*0.5), border, bwidth) lb:draw_line(Pt(size*0.5,size),Pt(size*0.5,size*0.5), border, bwidth) lt:clear(table) lt:fill_rect(Rect(0,0,size*0.5, size*0.5), square) lt:draw_line(Pt(0,size*0.5),Pt(size*0.5,size*0.5), border, bwidth) lt:draw_line(Pt(size*0.5,0),Pt(size*0.5,size*0.5), border, bwidth) rlb:clear(table) rlb:fill_rect(Rect(0,size*0.5,size, size*0.5), square) rlb:draw_line(Pt(size,size*0.5),Pt(0,size*0.5), border, bwidth) rlb:draw_line(Pt(size*0.5,size),Pt(size*0.5,size*0.5), border, bwidth) rlt:clear(table) rlt:fill_rect(Rect(0,0,size, size*0.5), square) rlt:draw_line(Pt(size,size*0.5),Pt(0,size*0.5), border, bwidth) rlt:draw_line(Pt(size*0.5,0),Pt(size*0.5,size*0.5), border, bwidth) i_rlb:clear(square) i_rlb:fill_rect(Rect(0,0,size, size*0.5), Color(0,255,255,32)) i_rlb:draw_line(Pt(size,size*0.5),Pt(0,size*0.5), border, bwidth) i_rlb:draw_line(Pt(size*0.5,size),Pt(size*0.5,size*0.5), border, bwidth) i_rlt:clear(square) i_rlt:fill_rect(Rect(0,size*0.5,size, size*0.5), Color(0,255,255,32)) i_rlt:draw_line(Pt(size,size*0.5),Pt(0,size*0.5), border, bwidth) i_rlt:draw_line(Pt(size*0.5,0),Pt(size*0.5,size*0.5), border, bwidth) ltb:clear(table) ltb:fill_rect(Rect(0,0,size*0.5, size), square) ltb:draw_line(Pt(0,size*0.5),Pt(size*0.5,size*0.5), border, bwidth) ltb:draw_line(Pt(size*0.5,size),Pt(size*0.5,0), border, bwidth) rtb:clear(table) rtb:fill_rect(Rect(size*0.5,0,size*0.5, size), square) rtb:draw_line(Pt(size,size*0.5),Pt(size*0.5,size*0.5), border, bwidth) rtb:draw_line(Pt(size*0.5,size),Pt(size*0.5,0), border, bwidth) i_ltb1:clear(table) i_ltb1:fill_rect(Rect(0,0,size*0.5, size), square) i_ltb1:fill_rect(Rect(0,size*0.5,size*0.5, size*0.5), Color(0,255,255,32)) i_ltb1:draw_line(Pt(0,size*0.5),Pt(size*0.5,size*0.5), border, bwidth) i_ltb1:draw_line(Pt(size*0.5,size),Pt(size*0.5,0), border, bwidth) i_rtb1:clear(table) i_rtb1:fill_rect(Rect(size*0.5,0,size*0.5, size), square) i_rtb1:fill_rect(Rect(size*0.5,size*0.5,size*0.5, size*0.5), Color(0,255,255,32)) i_rtb1:draw_line(Pt(size,size*0.5),Pt(size*0.5,size*0.5), border, bwidth) i_rtb1:draw_line(Pt(size*0.5,size),Pt(size*0.5,0), border, bwidth) i_ltb2:clear(table) i_ltb2:fill_rect(Rect(0,0,size*0.5, size), square) i_ltb2:fill_rect(Rect(0,0,size*0.5, size*0.5), Color(0,255,255,32)) i_ltb2:draw_line(Pt(0,size*0.5),Pt(size*0.5,size*0.5), border, bwidth) i_ltb2:draw_line(Pt(size*0.5,size),Pt(size*0.5,0), border, bwidth) i_rtb2:clear(table) i_rtb2:fill_rect(Rect(size*0.5,0,size*0.5, size), square) i_rtb2:fill_rect(Rect(size*0.5,0,size*0.5, size*0.5), Color(0,255,255,32)) i_rtb2:draw_line(Pt(size,size*0.5),Pt(size*0.5,size*0.5), border, bwidth) i_rtb2:draw_line(Pt(size*0.5,size),Pt(size*0.5,0), border, bwidth) rltb:clear(square) rltb:draw_line(Pt(size,size*0.5),Pt(0,size*0.5), border, bwidth) rltb:draw_line(Pt(size*0.5,size),Pt(size*0.5,0), border, bwidth) castle1:clear(square) castle1:fill_rect(Rect(0,0,size*3, size*0.5), table) castle1:fill_rect(Rect(size*0.5,size*0.5,size*2, size*2), Color(0,0,128,32)) castle1:draw_line(Pt(size*0.5,size*0.5),Pt(size*2.5,size*2.5), border, bwidth) castle1:draw_line(Pt(size*2.5,size*0.5),Pt(size*0.5,size*2.5), border, bwidth) castle1:draw_line(Pt(0,size*0.5),Pt(3*size,size*0.5), border, bwidth) castle1:draw_line(Pt(0,size*1.5),Pt(3*size,size*1.5), border, bwidth) castle1:draw_line(Pt(0,size*2.5),Pt(3*size,size*2.5), border, bwidth) castle1:draw_line(Pt(size*0.5, 0.5*size),Pt(size*0.5, 3*size), border, bwidth) castle1:draw_line(Pt(size*1.5, 0.5*size),Pt(size*1.5, 3*size), border, bwidth) castle1:draw_line(Pt(size*2.5, 0.5*size),Pt(size*2.5, 3*size), border, bwidth) castle2:clear(square) castle2:fill_rect(Rect(0,size*2.5,size*3, size*0.5), table) castle2:fill_rect(Rect(size*0.5,size*0.5,size*2, size*2), Color(255,0,0,32)) castle2:draw_line(Pt(size*0.5,size*0.5),Pt(size*2.5,size*2.5), border, bwidth) castle2:draw_line(Pt(size*2.5,size*0.5),Pt(size*0.5,size*2.5), border, bwidth) castle2:draw_line(Pt(0,size*0.5),Pt(3*size,size*0.5), border, bwidth) castle2:draw_line(Pt(0,size*1.5),Pt(3*size,size*1.5), border, bwidth) castle2:draw_line(Pt(0,size*2.5),Pt(3*size,size*2.5), border, bwidth) castle2:draw_line(Pt(size*0.5, 2.5*size),Pt(size*0.5, 0), border, bwidth) castle2:draw_line(Pt(size*1.5, 2.5*size),Pt(size*1.5, 0), border, bwidth) castle2:draw_line(Pt(size*2.5, 2.5*size),Pt(size*2.5, 0), border, bwidth) local retv = { [Rect(0,0,size,size)] = rb, [Rect(8*size,0,size,size)] = lb, [Rect(0,9*size,size,size)] = rt, [Rect(8*size,9*size,size,size)] = lt, [Rect(size,0,2*size,size)] = rlb, [Rect(6*size,0,2*size,size)] = rlb, [Rect(size,5*size,7*size,size)] = i_rlb, [Rect(size,4*size,7*size,size)] = i_rlt, [Rect(size,9*size,2*size,size)] = rlt, [Rect(6*size,9*size,2*size,size)] = rlt, [Rect(0,size,size,3*size)] = rtb, [Rect(0,4*size,size,size)] = i_rtb1, [Rect(0,5*size,size,size)] = i_rtb2, [Rect(0,6*size,size,3*size)] = rtb, [Rect(8*size,size,size,3*size)] = ltb, [Rect(8*size,4*size,size,size)] = i_ltb1, [Rect(8*size,5*size,size,size)] = i_ltb2, [Rect(8*size,6*size,size,3*size)] = ltb, [Rect(size,size,2*size,3*size)] = rltb, [Rect(6*size,size,2*size,3*size)] = rltb, [Rect(size,6*size,2*size,3*size)] = rltb, [Rect(6*size,6*size,2*size,3*size)] = rltb, [Rect(3*size,3*size,3*size,size)] = rltb, [Rect(3*size,6*size,3*size,size)] = rltb, [Rect(3*size,0,3*size,3*size)] = castle1, [Rect(3*size,7*size,3*size,3*size)] = castle2 } return retv end function alone(color) return function(size) local i = Image(size,size) local g = RadialGradient(Point(size*0.485,size*0.485), size*0.54) g[0] = Color(0,0,0,0) g[0.2] = Color(0,0,0,0) g[0.78] = color g[0.85] = color g[1] = Color(0,0,0,0) i:clear() i:fill_rect(Rect(0,0,size,size), g) return i end end theme.validmove = alone(Color(255,0,255,192)) theme.highlighting = alone(Color(255,255,128,192)) theme.premove = alone(Color(0,0,255,192)) theme.selection = alone(Color(255,0,0,192)) tagua-1.0-alpha2/data/themes/squares/Default/theme_yahoo.desktop000066400000000000000000000002101077523320400247550ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Yahoo Type=Application Comment=Yahoo games squares X-Tagua-ThemeType=Squares X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/squares/Default/theme_yahoo.lua000066400000000000000000000006751077523320400241040ustar00rootroot00000000000000import("piece_theme.lua") import("selection.lua") theme.background = function(size) local dark_square = "#319231" local light_square = "#cecf9c" local i = Image(size*2,size*2) i:fill_rect(Rect(0,0,size,size), light_square) i:fill_rect(Rect(size,0,size,size), dark_square) i:fill_rect(Rect(0,size,size,size), dark_square) i:fill_rect(Rect(size,size,size,size), light_square) return i end theme.validmove = fromColor("#bdaede") tagua-1.0-alpha2/data/themes/squares/Jose/000077500000000000000000000000001077523320400204045ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/squares/Jose/marble04.jpg000066400000000000000000000404021077523320400225140ustar00rootroot00000000000000JFIFHH Photoshop 3.08BIMHH8BIM 8BIM8BIM 8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM8BIM8BIM@@8BIM8BIMgBR58BIM8BIM8BIM ippP MJFIFHHAdobed            pp"?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?۔+pLVw5w"[[,C^cs41~kR:lwV|v#iЍAAXj/uIL\>(cI}y6<5IJn 7B)t^ƻt䒑x\eTVXvXƚ$7#̶ZLH8U20X!hH~J[ Ⲽl lzա]!ߜ1/e5IN_S7=~RR, l~}$¬ݶa2ZGlE8hgaYn;q<?$X"Ȓqu:v*& ]:;@hN|Q7~uyAUz.kA)xl6nyuqUH4X&;L]ڄE74ΕtFoqKu}1άx#w~rf?KCR_0:*#4\GÇqr]X*9%IA$j#;dDkwr<[RZ['1? Vfoƈje[GC3cx#A?%0e3(B,p㐒^Z}Ov+[ ȐalKI#ڒ%Hm#픔t਷n$xj j67mRJJ8BIM!UAdobe PhotoshopAdobe Photoshop 6.08BIMAdobed@          s!1AQa"q2B#R3b$r%C4Scs5D'6Tdt& EFVU(eufv7GWgw8HXhx)9IYiy*:JZjzm!1AQa"q2#BRbr3$4CS%cs5DT &6E'dtU7()󄔤euFVfvGWgw8HXhx9IYiy*:JZjz ?:\I'jH4qT*+"*i.-;U*/q $W P͸4#ďlU |XeE*G_ 2rnԞEcR1TR;X P)n6P$eb{qEzmR:UjI?*ۧQˮ*8Z=T3KڛuVWFv*jqU TqƔ۵qT(dQ@w*ĥQMICuo1TgPPnOLUQTf: UM 튶Us)(Aí1Td҄ -DXW~U>!=6gQbNH\tJU aGL,cjzq޽8m" Fu]WMmlE *-- :4g)*lVȨHv^*G|*ѲU5{w1UI(=(1TMyWr+D"ҸHh(}UMzUxަִۖتuHb{'Gsצ*HZcָ]R4PS1;j튫 :uqUUd|U }A[וANbFQdAv*|UpR>wڞ8USO*F=C[Tq4b)U犥rLZF5THw=ilU;vU_N |N*y˫蛋uXD^==TERFvhp Nx΍GV~{tjƄӦ*\[Rb7犡ctqG*WFjb8XHCZ?]Uuz&@:w*Q4`?}ت:ϸdo`_ U¿6jgR!~b VF䢂JSz\U\kp䲹կ;~1k&?eB `HQ6boTZdy J;*=oRk~=Sd:x努 SH6튪-9ȼx֔Xn=Jqq\UU% ڽت[ӯʃ@"iZ*uNl'\H*Dj[ :Whi'EdP#=ko WB@4`kXUw^[HVj.̽ jtYE΂X۔n\URF {VdjoqTQJ"+I `tMuF>qT|1 hHO*+,wPDVq:bun$}*?*m9aM oЃ>U .q"T7/Pc:/pm$$,N(zQ0e5oGzkPA\@k)%K h#i"UO^O4#cco:jw1WhV"w5W! Q {20@_lUH* h;Zeٹ\ֻg|U09t늡.bC jא}qU_R1Uź bcqU_ ]=U)/97*%>G|Us!5:МUƷ mNثWs( ֵ}*;FWc[ܒvPQѵK{s[8"enj9nqWQԍSA->#AN2;E P M>XiA+޸ӊ"تK6Ej~oY}g4dݭ)B5 iU;үP pU4Y,2#C1Tm Q Gzb bTz߷LUa*0jX TįA]U'JARzSjP5:;t1T%BԎRaɊ\75z_^N{o*CZvfS}UqiĖAFUb$PALUOMتgR7ݏzX9 Kˉ.7)^H*cHZܗ'x 2lj״>%"/;Jo.C!IgUHmKKf7[őO1GdzR=jGM!8qAb}%!*"Z U/@*i*_QkX P.=UUQ*B<تb/=ԩFå{Kd*Vq^OъUP}WI}vVUkRHCq}Yb+@6P Ā^Ԋbf{fHvh6hN*YEOm+#q6'UqQQ{w*75 1T&zLQК}ت_zW}TVa~E,RY~be٣,RS*u{Gאָ$Nszhm N<.c9c`c`XoJvY{bxG#)}1T} $#NλMzCj׶R4wY ˰o ŭ l8<4hIۯlUkhIGh(& NثD+$Zq$5{WnI0Cln 犿]ӊ"ѫD^\ru>⫊qP^05z<)!k)d,J#F1T&HkQMbGcSG"k"|<1TVnd|tOFa-:uo_L^LY)PU5$⩥&FcRi|U>V1Jt0M#R㷎*u$֕&w銱-rUՕh{b[pJTփҮ$X?GRƻuqVyrmYI#SAZҽN*XB v*Rֽ>U ?*TlUYtVK7xuW=⭛ZUj*S)|*EkƄ-zu=)튿kJv8LH;W[dr~bdٺSjW!wGCTڴ(>Ur QQqU0~& sZUI%o"?TVԐBxIrekߦ*Tri^)Pi}8HuQAժk㊮7&2A QuJ;64*'z)WE@ClU,t2O#MLU^% Gst*ۺڧQT-̐7F'o8*VY` >8/F"ҿ,UE#F [~}TTP~xb3̒oH}ؚ.X^oXYQM÷b_/XcuwSG`UGD^^8( jMzz⬆MT6J(M_*=x&SQŔmO㊤;-AbĈ;Cn%dиi4R‡bG 1U ,(=qV)yO-e&@Z8c4ڠ.OLUm䲆ڹ n';T{8;&:f4#%*;b%g:*t@TzyANLhkbaOݼ6=TDh6WT*wk튡=}8Vх5*3TqTZؑQk&|U Qx5Wo*xmFF!CJbU _,UJ6 TA{WQ{^Y污Q҇[_>#~Q{YVRx lQpYGM`TZ[NTTnC~'V wl U(.E#s|Tn?~*핣rr\IWmaC 7TC2<i1V)B$F!wu#.T6SG;v*`jbCSbֆv~Xq ½*+:Qwmb)N\U]~!^nG*~׊`Гa8Nتp>!Ԟj_#^uUɥH[=2 _. Ub3FJ;ӭ1Uxփ[EU S]F*Ԏ=oTPHݚ ;1W&AFS~6$Jp lUi6ruHW9m$0%SzVثt"DKqA[3iǓ$8c̮HN*br֢|iU#-liTkqCSbھ~*u\<֯Fv5F*4J+Djo|*["u1TzEEO[/|UA~Xߑw늱:z]] O݀}U+7MBNk-M=f8G7H oZ{uɧ.<)гQ]ˋab{,fUTҸ6 x~UoXp}8E|dRPR/ZlUYܤrGiPW⩬5u,>?E8 =X(#Mb NէLU HY##Ԕ\U`cZu*Q1V1W}zZLU*N`YeI8kxK!%N*]54]*TE#~UKylLK)9U^`ԁLUFG@h @I)oX[{pO.,U. ;b4{i*ѵZ_^7G잁b9%+w튪qF`+O**qW>XejqWz>LU q:MRˍF8QhX\U ?r>܌Uto#IW~ oqTC\H9m֠,cUD^E(X&Gwrm$qS>φ*-4{a($]PG*zaS޽i1T%a|" vXHmgqFث% I3(N؃LUD (ڛu*+ "ZF)\UJIkSMǏ|Ucʟ'IKeREIPA?-7R[-F?DRᙁ+H}!OnSUܖjP'C{bkiv$wXޱxcGJVaJյ0,HRPWk: \ecኯmZwx\U ++D:U-)QMzU/yHѐUR+;VWP?銤Bn_mA]:׮*a7+yfVemM=*Yy)>4?MUv +߾*O 8ivف@5Xpxy]fMt#xЕ>˜`B%((*kn4P+m݊FR鱭>x:UFݫ㊫04T狟_ xq$}<# qUJHW,M_T ScNUeȁMV^dU/*]OʝV)pki?zWju:uR \M,6G @8<\USqU"ZP[mj7*U<銥],a!FbUơi7AOBqT%-呄m2׾*>ҁ5jPO6R )jw1uXýw=TMqE@$yBӞhREԌt6(T|qUm3@0h̤$oCSC 6Tq]s!@lGFB*)^`!;Q*:WT|T|,̫SW1UerTwVݱT $k@1=wUnFh7۶*а;}*Tj|>b2 UWZ*t=@]?%I*5Is Mk '+|{"7PS`=VGszDH@hkQWbH}k*A֤cԄޚ2P]r,#fwZW|Ua:Is+\|@TקMktOIc)֔=VͼJ${tتIuTE] _銩c Tv޸]EO8a2R(EjEjE+61 j ؐqTO\UIFߎ*Op)b Ӧ*҇{b0B)_>UR)zVxȘ UW_UBHZE~lU.˹%*ksMoP{⨘ P+6_ OmVROr| vR F#F1U&HkQ7zXu;;MRiMX/&b+mj#4iLqw'zvSkShV0YđU+ Vy>OQz*M. :\Uhꪔ=7)܄zU0&V5jnI(hqV( P :[>-I,zWB˹jPOߚƦ݊6Ƞ|+R-}RAڠ`҄b{r튩5mʽϦ*{G]8R7qTL7ŤPv#zU9 mX52w8ƥۊ%WBCt~1U pw=N* (jj|TW"A(}TO2d[V3؈Wqzb"ږu=!1VΒm~ă&ZS1mk]P+(q*Q (jxmZbM;GJbM7j-6w;⩥? @|T"UhuS%,: L(mb(*>-+Z튡*@#ت׉PPb.v4=V=+y(.q(0 n1T,ŭJ񴂇*LU-3ݲvs)Uj,v#Bbe5[ķ7vHW #G P R]Jqw$&xbڜtx+@뷆*[\ȻIT+bzb8*uuNP- %<HS?*֣0 r,AI?#n >mH)ŎWbOZB#BcXAolU4jxت!tcJרm~U.9FSp`GC73q(U +V_L)۾*iA6UN*[ SU:JiSi+Ē>6=qW4( TUv ?^*1`_읷* T=qUA%C#rOlU!-U劜@NhSlUO1HX$~UljoLUuQZZ~q[MGn:4j:1UPhuqT<ֱZ>ӊqJ*%ɊobY[u",;0'LU"`HP ~]VL60j8mhUrqT_i e}w*FcE/zրbq! ִ80d _*Q;4Xj[~Яo*2̬ER@تkiR⨷TT&@H4=銡%)RB\j W犣-9)o]lUs(:vTVּ}UG_ت 1V/rHH3;?vm @lULۈ;oZÐ` @LU\i߿NتPMcr=U`|UQYN7|U'O|U/F8$$4H*[oTm4S^>!DuoM__~lEjkMb* S>GD@8PƵ44S\*hToMP:NQjJ nSoU3TE+)DF+Fj;ت@"&LU qTbBj;1U!5QJ8*IВcoci%ON[.w}[yE1TQS(bӊkoJ}P=?Mu Uh)*O8h0㊪"*v;uU(Q늡R$mXUuj< b݆*kU^F;^)")Vv8ad6MM>UUY6?wPRҝzUFsTڵ*eVNcaӶ*O;Uo]Hڕ*ڛ& ?G1T,BК'Jnkf$V(`nW,'mPd@et;UnRN4::UD* zS*{{bz,Ic~`ت_wR sJEBxʧ|UT5d^O@bž${ b^WB<{by#n q?GD~}UcR1Ȱ{KcFrkwSM80k#S|Uq4* .VK V^Dh0|qT jSPDf=(v*mց@wCY{һW*ցy1bXP VoE=>U)vWB:PzeDٚ)(Fq,E?dUt;⨵M6*5qЅتk흇Oъzۮb9'RI銠v TR1TT@q*ӦҴhtagua-1.0-alpha2/data/themes/squares/Jose/marble13.jpg000066400000000000000000000765351077523320400225340ustar00rootroot00000000000000JFIFxxPhotoshop 3.08BIMxx8BIM 8BIM8BIM 8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM@@8BIM8BIMqmarble138BIM8BIM8BIM wppP[JFIFHHAdobed            pp"?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?XpY@k̶+yֲh:sݾlY|5C5n2R`qu`nvvQ7Ea77F~w*דtZv|{Эs"IyMt"A M:1smPn;*.ypihsṻ]@{:#c-n{k;K^漣~]`\wY7_kmn6ukvpky |G*mCᣞGoe` ~Z0^{?ձ5}ߝѷ4I׵<7@ Nt )%5?_AZHs^_n;wNiُ! )+ ,qX'1D۸uSΠu:+7=:c}5Dm'wvGz4'P :ha?Պ wHwϻl@ j5s#B},nkLԺ?3Xos\ m7܊TZmh/ H7cڇXpykѨ$v%Jl - o(z  `~[+eˌ\$5}Mm9k$ZqkrJf1[K=A$zh5'k-ٴhT׃nc.=fS8E5#V:7sS+EՍae;enݵs??Cv4}^.*ZY@uqfc=ON*|{ǁk&[a#O N$O]ietQnC,pkE[KIp>ѥJwkם[\w3ƾȥgP?uioQt qԩVі=`GtxSߣZDI0]45N>櫹8<<Am6j]-cQmlk奷H-Hl'ٵBnS\?IGT9Շ1ċK@+ϧ>*ÝĐAd?XYwؠE$Qap#KnSmShsv6Dӥv&fHv9sC@%5iuxյ xuv /h۾ߦle,"\(bb۞kq ;K6~ uT}'0$G7{7#]PfXt 7^nw-v= 7ݴ9Վ]ʭc g'ߛZc6ףv!IN0}S$9$TCa-O':{5[u֒@ |= (텭~5;YVݮ#ɜ;w򖅹7 5XCqtYY9h#Dҝ[@oc'].wR_U&vȖV*6Oi=\[ݴs$ ׹j) ƯY8;G9ĔϝIi7u} "dznS鱟άLJGO#Y<{U߿ wV3e=εw )riI-yNٷoA~VZ"@ˣn{Ad_49wzLcX#pǑyފMc !:@t;}# kjH')ALC8s?SUpm ]#R9ۚ +&[LZtoa`%Lo? ;7n5>p-nZ'n͢=)/{u<5hs)ɭkmY KFp~o"mԋCZ̳iiUvkY􋁍-e؈QIf cXY^7|(v֑ d?P/nug@1X>Mw7gs?%1Y[!$OO;ڦr`ҧHs?CnެV߷cV7ZhߙW wK4-5hk{RRFXllkjO]a61kc]FA SolG "Hߡg}PZs1̝r74sK" mcmD2\!:KmRs"sMΞӹoPԖxcK h aOm C6kI O?Z-m4cW]o5oo۽ʫ 5+P Ɨ>]Xiݻ[ogfl=KU%X[j;}?7SUe0%Fv3o =pܫ?c#h-hn_띍5{'kwD:|~NV#MkX7h[v6+g:@܏ВaͲ:ij>feClXkf5.Q ,d9vy0!7Q6K,a:=iwD4O,9{]vz=݊}f85-#۹@׍V_sZ ݨ$R1kn{;;;j-emcǸ5]5c9.kDgow`d9ncv ݺMMĐ;Hkskl E=^CXFm m-.$뺟d zς-6Vwwv{Iյ}Mee664:sX>y#?ƾ {$vV>Ҏ_a|1emcLݾ C6x߹ߢ:׏Leе2L5fk{%Q7hyw`V}UG/msF^eQm{\eX";QaR Xu{=; \ԪTk>sktڏEuGmZKZk< VG"u쎧_`L9hL>{rߋh  ugen!}F́>Q 6k7;wD"SQWK:v½elp\Dw53sN~~JMmEOa!wOBɬѾK ?6}OAƽmkn?S\=~?e``.KA6(ww=TϪ5.nHkC}:{zJ8BIM!UAdobe PhotoshopAdobe Photoshop 6.08BIMAdobed@          s!1AQa"q2B#R3b$r%C4Scs5D'6Tdt& EFVU(eufv7GWgw8HXhx)9IYiy*:JZjzm!1AQa"q2#BRbr3$4CS%cs5DT &6E'dtU7()󄔤euFVfvGWgw8HXhx9IYiy*:JZjz ?;m_RT7#*ZLӢKʡ?#c_|"Y]IqĖ+OFz" %$n\ 墲H?aXͺ%5u!LqUԐx{ᘑX9*}ame5⸏`7,h -f 0*MhpLI 'P6X*Vz$\J@, 7A#.bW[]6f6qYiTDIb*r&86WPE$w r+;r@<$lxºd4Fר~P#w:dxi##?˷p2RiDeRUh+V=Oll]VczߦAXtɴTz|{&]=Sըe1#,ZS!$$s%ޜo i.M)!*F KZˋ^?Rd{OVY2 0?dzMtZO)bapTjiHnf3qioqޏn{%iT2ҁO,O0\Ϧ*ZKReq'p=LUaAK!(T̷-"$ z~4r,i]On&7x%Z~ĒyƗ+eԆj?$InGqBi ť2-jKkiJH4.K~ҤҀqӧs&E4W98TqM}Ғ-0!h CKUv=ʈB[)n R1JGSO$[vV1Z#L;LTvoJbL(ؕPvpj.,m-(vR\1n[ew>4ԝHgͥ_$S@&Ala1w2!mfXr~=,GJ\1`U񖛞Bk&β֫,gEYW~Dz.cNpC!/p+i&UK [rUjю@% L2cZSp[Ҿ )65 "{/R4O RZi`m+MYC(PXG Xӿl-eӭ(JzzO:T#*oOD򷗬N+ƕ^&rŶd?3u[hl"h׷;qذrO4>=+F.-i"~{)pA+ f2@DƨwR#Qefz"M2F.G5&z|LwSE Y"6^[l)mtV+;C#>=+SQU%MEz|LAn5SOА~[[i7`¥9u>'o U#JPױS(ȃ5OJJ|PM&4qކ#lҡ0!$ mƂxhA_Gt5qۋ'iyV}Di!zPPdI<2ڝ>( z ²q&JGGc2 |(!oR_BF? 2=*T%HYqB$)) J@J_HDrCL9sPB5cM!oİȨQӊk8JM!lr$um(ZE7RȪ_etDŽQg")!,RiN~ixQ` $;=*[8xa()pH~~xV+k2PkAMq1,RVCjVw4km&ҝ]!Ȑ xNL&mvdb) , ZS0$_ӗՒLdjw8HGKo +c٨5ڿvb ͳu ZFhxj ce&]{7JHLRŊx+8%Ov8?BiAHx䁶)E^HgVSnF-'j jNcosBX^).d- ve ߣK߁>(>"mQ=1sYejt6j s%@Qؖa~;O &v1J%*Jt R#:+VMBAԋPq (T֤ }\(=r"FPEH*2Hf,Z,A\w*%#ž 3@Z̢Qh*DS8] x5B GNS(@Ϫ[\[^Rm{w(3Ed?b01V8GbYX|(I: P}V;ȦiL0|qHT# +L4τucN>-$59 x6KĽ,KFFZT6].{&qm nnc|%3+1Fa i #Sg \FbX>d &c T#( ʋnE\5cHOA`Txe6M`%%'@ijYUMh/"Mў_[J}"#wj/3?,<&0K۸ۙ##w%b*M O,IH ֕KR&#=( -qq!8 yNƽH\xUuO-FI+-ʹӎZ?=qu\ͼiۄ*(>ѧf9Xҕ5"m>SNH#lKN-@S%q-QxEH=$ZdKs0VW+^NV xۢZ UTEbH G{}AD]1ў.|aT m4(ႝnĉES*O} iR۽MhVR=2)EMqH԰ւ!zZH˓zצ|*rC" IA6G;D+@T֙-4<vzNkTZj@6G.}:;'FidT`S}ɃH&mm#uwoצ@J.-e+Vf')9dX^=DB iq9g-0RA)JR%ḵM@2P)Hb (;l@x cč}Jɴ='JYK.Y} T`$1۫tѣfRO:; "[j\[Dg݈,% jh+"ɽJ%pb7 ;A~ \[_/# "yR8>ݷH ڌcHLIN5&Cy KVR(PӒ'8^z AŔU{G𝺪{aD(yV.{k{`ȢPEH'sInj̘gF.bpf@-ݲ$eXͶuku[U@Q{Њ|0rfEfr~]@, ݞz} Nd @&(a)01Ɨs;rDN2 |L˒͜BVD*#<{ (QuNeqZW+&3iGRURZNJװʁAWpr8RhXcEĒhVre|}Ϗc`ya#I²sQTP6VNҩ2TTlPM#IP̑$,`R۶--TeEzR2-[vFªopq U ޘVGjY#HĚ*S\UR uH~ SҴO_֒Z]sq=8f%?`GڴCtqUynbEuj})H!U|B`Z'ͦB;1,(7jE)QAn$MGUbtAlM$K9^ՙڕ,GNcѱ/זOsZD=65XF _$I])[W֋因'dj&*Hxӥ0\SѤZZaA o\ !XiR*ewfI팫)kܖd4&qlזڻF-XCp bXj\9¬!n;S)lQru RvG$ G]j6 e_.hE~ vYldG$Y}8v6ѐ"C^%[p⢡Mr)FijZJ-i(xU@E}[=jM!ŽJz%A,R-lPaPܤȃlXzߢ%\Z@WfgOc@pFjS~%^D&YZ߭V 'F )xKG4b ; G;K~`eԢ9UۃQޛ{S,"&wi[Fmo[URPSr22X"[I{E ְe[K.H"w ۦ1ǫՖ(<٨Yg/!i "/~ t:Եk$C;rqdE*ijʷg M[`:˓\X%7?  r,Z]fxr!Oޙ")buېk{E^0lZiyTQkV0dTvPNgQ[-ԑXx+NJQXW1-$6CWR6W"36֩v:G3!"Sx>Ԝˉs$-gp'6]}(Q\d`y v*~xHL;-bi]Ȣ(~ozIbrz#++" 0/IkNS%%QIbg*OՊ!WdpMNLQlBCɸZn@\$̂X %cR#] 痴k#t%d^3F~CA\(frWm-~ *TWa@K|a r%J~maRiHͿ:E֡\y!SBăҧX&cBm"ᡞ=U(PC05tMOKF$ZtIj[ٹ<*L `E$֡[eTd,X:&/\6he5]/M6MEp95a[WE Ri%JԆXڠqJ2tyRMAKDtOQ(w6@Y'G 9'6n/)?k>2ɋ[D$TGbcoӢqk%GTRAŒ 6>`ǚqo}%, %ӈeR 6Gi$Z 㻺yJą5'eޝ2tLlHID,{W'.Lj) d]KV3~YJ0J*+QSZܚlP95HroMKNۮ<)Dɫ)Z+e&0)@v4 jd[/B=OR?H/q % :}L/^s",tɁnaJvޣœ uFVOmB?V@sIS=..(`c-PR+Q P df/Xƥ' ;iʏ!:@sK1т] 1]2-AE"L vyxMM]DfD!rdڻ"ȊH5 K F#^VŊ#0BܽM޴.GZSh<6TO¡tɔf+! .DBNj$Gý+ƞ9z A_D!OS/C#6 ~ĕky}[Jef!`JM'bV+mX]B2U઄PqؚiHPi!hk%UfdXtfS&$~\mH4\4SJK0><*kkC2?]S+Hާ bwIT4h <ڄϲR+㕁LQ\-Q:J­ g* F$H/4*XLIG ]H]A+ j97y~ɌV hOt#:RÁ?8lL:IE=iVtRc#p[MZCI%@zo^USr#B}2|"eCyTW"i%ݮ3fp$فt=n%vꄩ̄a-<cxH݌< 6z9A41P-KtkEoMðʁ)=mY?7 N)LkIΧ%ƕOszޓ,{K57CAM1iN\$$>%,]鷸9Or‘m!!:PߦH `{+ Iy#04UH-j BZX<.3s۞B2VvNH TNg HP(i l+z9%owo%O95Ȁ@;dSLfHufX[5)eHR@ i`w}HeHjoZJ@*b.GHkԐzsh"ՓG+Tժݏpr@)֮m )4FWf~&E!]#IO')4T WHK`Bͤv\-M QwYGHj)֜w9Li{@ZB#j!@ =)IK/p_߉"{ԶN $2]_7ȃn(> Jw?VH `JMm8Ik{.fY ,jrّIد`1U((>#XE(Ԛ6b"2(w(߳+XHy}2z$9aBƸwY3 []L d!#ԑzo *!lKWu^cKXRDm}C)Y~狚f~De¥KN'Ժf+G3 t^R^d5G~PY7F$" ՆpHѤl|3)x*B1CڸLjVUX3 O/fG[WNuálbTRiRV?(;FxT4$n<艍-ZPȠпT/E\P J$~1)A}õ z7y @RBiJm\y5eYZO^ V!0j8VEA" $%ķQ"G>@"#S1Io sĖbK,AuY(mjIv91QJWv4"*ECgƩtm`h`ewe!RI,`Ҟs8-k(KV8֤sD2K)NVD-Ghiִ$Yh["']tD^J@5 z Eq(pMW NM2C612GoE4Π?!@c@Iؑ A4,@;uŽѤ[ &ST62ƵCSiZۘ=Gs V?n*0iRًMg37Y'[kP6Ji.Ck7 #ROzv%#͗ 0lHGBlI- #ߵ^B@7*d,aʵG|{#ƣY,2 f#jzm$nj`Bq2 vwI".TVO".嚿 X':HbW4.2Ss0hsȈ}" 1RkCm)VP|KNi4&k;_gX6Dnm$!/ rS#zW Vܼ#$CF{ ~X^5 .@ޛPIn#KB vb:-ҕiUh2{ aObzt6i-ֳqiQHfVPb 7;&-2t)'4_lfv =Z3fGum@ _ eS=dnKs!ք]ZdS+K;fծ?Ԣ0OM! ꀓj kb WHR빥8NAx.j=:|,V|-nO˷vzI4  @Ddew6mo4( 4 (%\ip:VnU#?h0!h4Fie:],5eZ9 |>#TM"wOq2 cZ1Ƽޙ )< oGjAXBǙb8#{ZC GD!Q@RoSQE0=XCmqsKO$ !n,bavYw6%-j/ZӾ9$t\Vlyo(6r⾂'9Y#7&Ё0){Q`ÚsDiƨobSP7' C ޏ&%7ynJRk w61βq0Z;T5N RON rQ]ڃin-$S5;hmJ((  14,Oz׶[[[GZbzuWIncI;nEjPuӘ]m$[K20|go# vA5sP%,SThd+%nfv@QqM"m?O4mM,͹H.vՠf1a~/5}z2\LG}B Eo\lRze6iM;m/NֆQhF4a['ou@'L')&[EB覵`EwDfZfH})-QNC}O&IY\,D4$) 9ZVl-5q Mtۋ:ksy ӋT"ˤG"6,줃J1VrDc2LPMHLxigeb'(jG'ՉVj\Aw'zHEy %ԪoX!grN&%{ɮL<5$vIbM I^& MuxTZZ\/5=NQ Pe{q $cRNڙ)7& s/Ď xZPoT6&GM"vz]34O Q_O1|,RJr^'N`25cGFoW+ZSmP1* \8d&j1CZZvDMu{W>Ñ~%ʂT!lJ4ZCƤ Rxr$[0m;^+cͩE8UP0i,KIIV  '.ilTł:Kj\z%!)G *?g&fz10[/nTk*B@f 83!]5$[I'YF>9m1Y_I_%▿*>#d5Wb-$r:sf$ǐޢ}J+YRKhrf;A0-xTҖBc-LE8r \f!#@%r5Cbs'XZ2rCMVSZ+xr65j -6$hn-U^g<˩GRzЊɴUV[i]xEaRY@\ FkvAwvAOJ(HkR)O$R E~x/\T ԑjJ.HdX\0دaeP|5 Ơ@ oi MŊ%9|,v$AqIQ OUSPNbk.%ćޕH`QnEh+)&6eI #唙PG2ݬ-/,TiÅFY.V"!H|&EQBG_|[H vDP r`2d8SNIw/^cȀ#*XՏ)X P(=d"-PK\+"%FۖHKկn\̜ $q*sҟN 66d\VqeH~rw,uhs1yBFV-\SIV9Y?v\KdR;0k$U@}}>)o!E"I]~?`בSn$jOF *Bia&t4˧\S*s|RK_ԚZY"c:lFxu!dFV? zz'iiqβDiPպ6丕eź5)*yn-_%J 2ĭA+ٻWԐ"nb.%$BA]Q&/ KMi  Q 5ؕ"sPV6|,/K{ *bzW*E_Y 32|G B&*M51C5$zԃߦDH]h!qj On)Xz1c@Ev)x[RB/*#m,ɴ$MK1O1RV%;w`z B3%KnThq*}~|$Naѫc P?NIEȺ#1`,aҋyRV2$ئU Y?y," $rh}{]BOҬKA$֦](M:dZ}jq8GkRy8 jx`$C*${Dh/QB*q4E l };>vw5+5 x26 * gꚴJ¤ ]\PE!.&u]S b=Ɵ,+7ī{ 2|1\>y"5`Z)& (;$`WeŜ4Ĵ%KBMw |@[)$6:Fi(( "PJqRQUj܇-ȃlȵ^.ujyOfux1%)1 PDRiE{|󙢑+nTv'16`А495n\$:z]0keH~}S4*BjcH];8xo-Y=f Ө A݅, /5TNia&;O%m&15<>t#@xI&`P@3 7rQƦ2GP(Jn(+~IUU ]tfTSh8p[ie)N >M",SނoߣY6ִ9-##F +k;{ᑙ(elڅ{bXVP(;$"ؓƑ8ʲY$xׅӯӖmh2!e+FQy@Wҵ8ZO"}p *ƅx~;*Ebceq%ɕQD`Sv5IdO }{m%#*OH_.5ش0K9LR/⾫EwZcf.ahn2zr3u )5RˉxxaIa"p qZbm;h]PGQ#[O<Kx"1U^jM?K1IZ[4"BQǦ<[Z@d.$dS"BD!AdvmG4$DJ^CA mȟmTlw,m{O^F/@0\G-l;RnVYC8TTt;96Qv9Li5 ::1<;ۉ0XҒ"x(n:׶)(./c,$Ņ^EA`öWŵ/ unb; )r A< 3%cf;? SyCH5OP `|M Mw42xi9@)L\dz'.h N$}#+1=#INw SWB1yI]s5ᣃD-`AޙkΒb %68cOAԘzOZ 1Yy Ŷnc( v$RdyX<[ܙ'ٝ;0R J&gzfN\ QZoP<2ȨmqwUA*K+uߵrJ%7$1n'B:םrG$T:7Vkq XK mF7lQ5Kio'x nχ"h}ݓZ_tJzvQ!@:%Y$S()Ҋ۽vk“ib*LKI-@\-so|Tzbҟ-h#i̗Q}Uі+4(dfAȭEk9g6@慺Юc fBn\Cĵ oQKH]6DиASdM!5 ]oDѠm$\Bj9Tvq#Ny?EC}{t>-ǠJѾnį 鑔wq6-V}3DQ\2@^!$ZYjQOɾ@Ix;&adh{9N7ri2'¤|AR% I&V٫Nʉ]!`>70xjڇ HTѭ֣+E-JՋ7~ b8T?ker8cvat"YՌGBy*WoPM2-[Ga(U Ă :S,؁Ive Ys<%Y d o,.kiդn Fj< L,[<#\Kt[2@lhVv|nIZrYWe>6Q}sP;Y[i*E@Q(0!o+z}/f۸hAހݖǒ,| ܼ4.ŋ!; ibYDkk$RLdsTQu5 Y XŽ ı)IfU e62k> !93YkBrb 他v%Uai=Ju)V}Mň$܎b3 V%'#ňKa:\Y2mum>^AG*mצK4:?DF^d*iԊ qdhEPpԔč9mu%ڟSG"S*K*rr JQ\bm:CoauU})9K#=d8xR'&?]tP1^чkZԢm$yͪF!Y{ǿ\S̈́!@^RAI%xX`lc[($rz+L6)Ixe uFjM>bM٭Im{;}> m0tKw拨ld+*Qu|6A[j IF=NqxT}9 sU3p!bJZMdх2xO eSRz4WsLwB9 eKv r-fFTΘW7Yqe[xVv!#w<{efn*^U؆1J5 @= :QӦ{.JkĂjt里0o//-XE5@^B)(,j{䈱Iϧ\~X7!Ձ7Om$[E8mو!jtjM'ktWW]J4 PP}71 Os<,ο@oJYO֋f?$F۳U# =;L& băDm4ޝjullɞRYU@$Ěbumŀ+'OBO~\R"k <>z*3 Nu&#|A(e*hŘ4aY ;aԊe2op`Ԓq^iBfͨ ,`iVh8ytb[~߳6!I'9 -E'`?Y҄&XigcR fECSji|RcܤdJ{ ̔h5y&()Ljı 9[ m]J׀!›w `E%UZY$g~]N Xa! 6N$L~ Б؞`6rfXqR>#"E/ > .+ %eՈqtrRΤ!ve&FER:ըe$:dyEfFOK.k$zlqí ;=f5a$FXիr>Y 0ij֊ Rw0'c{e`Bx\ O!%\%PP;dS,|fI-D|&WJIU:PPWo㓓-9д+xly [kU"\H$v?fUc:mG X!+]-6Ga_?2)i}^M5 =PF٩^@IlNԤ"ϒ4ⴹ#bep\nJ =\f mOuHv(ZjIIhW/sq SXBTڛUWrޣk+ȪO߼7X^HQFZ^J4zT\\,2|hUЀX׶BIsh+$7$@CPv!"kOlӛIHF팥n ~Xwڮ:|[} sqmjVJ $ّO0LКM:C">R|͏&Y ]6r};DxהakRO}2<4Mt=+d’giY6^ߎBIM\ͦ\K%Mym^!Մj\#h-ʜ?f`4%hWnU^U 4~-lQHfJQHߠz ]Y' WL ZGq&"[KF *5JAV)bMGBGŒ,im&oyn]EjZli>d~DTfߎUS&`Zah-MMsA"zj6DҞ4A,S V,x `I_1U1V*Jm&ڈlwҗLIaxUbt,I Le:dsoy4e1VG融n|U%c$jy2r=iCһSݣKnzN%A]SϒWE+iQVMQ9`6r,hyJE(}_ ]Y)2.~ U_ 0 ]h2'9mH|*M2}KB((YXyU@ }9Β2ܬ3,ahh$~-Z[Bfm!mux5ۻ;ks cv$ztÒ4U؛U>04R^]ibXc &k׮*FJcȈHwvvFLc,CnV '{LZG( RFj 2evVߓ1_stQ$z17Zc-KLR&@XI!dPUI 4i8H2)e єSLy5 ewX'v֑ 5|qDg%k&>H|%5ߐ)eDiwo:q9T, w/jhJm_Gkk4bE]!#FZzͧ\ hJ{Ido5hVԍ\Ԕ>=W"bnM1!q*[hPT"؂m:K-eM4Ji*:I'F쀤Vy5GŷH j&[6,ĉCOp0-2\*j('fnah+SԑZ|"*:c`P {cBȀRlA=-䎸I# UR~ Pf1n`/Lh,Miʽw''ÎN2Ɋ\iwn f*@؟AK5E' W'1ފkM'se Iy"<0!n;,է]2L[{i\OGqޟv$׀e*Nb[)ȦF*j>D9'InU`*­**2@imgEg%iY(F~&רm)E`noXJB+R;ˣʚ$?2u QռphUx dJmΓI):La[&ҽ+bmEg#LzE*>H 4cm7PnMoQ }`E8\*W𴞼V$JҬ74IIeu{<ӨHKJՈ"ɈyyP9 D쪌5!v JdO( !&@Rwg{hݸ#Nn6.MH-/Y#7e$%aҾ$TI*vTb|2 GקepO^Hibz@2`# [2! :9?${ڹ\X(IÈI\Y*y>G:q¦(V 7VكjbcPJjĄ ڇ,k!\Ÿ'A! ۤlBj6}pjμ)n]"H~ 7Ў\ڍj74hl6H!K`!d#c>XUϬ뗋oiaW"b:.䍇SE SO%$p)PEiS6)/E"D~+PTx4otagua-1.0-alpha2/data/themes/squares/Jose/square_last.png000066400000000000000000000015501077523320400234360ustar00rootroot00000000000000PNG  IHDRFbKGD pHYs  ~tIME /(0VIDATxٽnw33klo022\@(R L" @AAR&ÉDz;CA뱂^-FJ̎O~kU5/֝Sb]CjZuՇjy̦KMLM4q:=ߡ/MMԴU>|U[G4;ꏧoͪJMܟկ֓LJu]yzy?ljHnw] OTU572[hD@WM-nʯ^LԶM}pKMtj'zp#UvfSfWvMSU]U Wui@MSn5Wj庖gMnqkkXnb4KDDD@Dfo:y|Y"}?AWrby2mWp0sIENDB`tagua-1.0-alpha2/data/themes/squares/Jose/square_premove.png000066400000000000000000000015401077523320400241470ustar00rootroot00000000000000PNG  IHDRFbKGD pHYs  d_tIME ;u\sIDATxMNQE8Z+pTW("9i|W;8rc?idH{"M3G[_.Ryڡ[gޤ--N$-Ж3 !Ap;tǍ}d]Pɐz1O?wJ8MM;KRv.h}~}>,%Ft>(I2!/߼{ISKϯ~Ml;xd? ſ]3Ўwgb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@B H 1 !$Āb@BF*dg&jRj?=(ҮVg?mL4}ߥ-YԔ4vkbIENDB`tagua-1.0-alpha2/data/themes/squares/Jose/square_select.png000066400000000000000000000014201077523320400237460ustar00rootroot00000000000000PNG  IHDRFbKGD pHYs  ~tIME 222XIDATx͎LA:=!l,=H,N7"[˂DA^cxM']'3o{m~s< m9egsHG>W:;O@TqܶKIJn|:g$cJc}o:ɽ&7ÀFO99+lsC7 l݁y!y }Jri>|;,︐b/; IoֹlIENDB`tagua-1.0-alpha2/data/themes/squares/Jose/theme_jose.desktop000066400000000000000000000002101077523320400241120ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Jose Type=Application Comment=Jose default squares X-Tagua-ThemeType=Squares X-Tagua-Variants=Chess tagua-1.0-alpha2/data/themes/squares/Jose/theme_jose.lua000066400000000000000000000011471077523320400232340ustar00rootroot00000000000000import("piece_theme.lua") theme.background = function(size) local light = Brush(Image("marble04.jpg")) local dark = Brush(Image("marble13.jpg")) local img = Image(size*8,size*8) for x = 0,7 do for y = 0,7 do if ((x+y) % 2) > 0.5 then img:fill_rect(Rect(x*size,y*size,size,size), dark) else img:fill_rect(Rect(x*size,y*size,size,size), light) end end end return img end theme.validmove = fromColor("#bdaede") theme.highlighting = fromPixmap("square_last.png") theme.premove = fromPixmap("square_premove.png") theme.selection = fromPixmap("square_select.png") tagua-1.0-alpha2/data/themes/wallpapers/000077500000000000000000000000001077523320400201735ustar00rootroot00000000000000tagua-1.0-alpha2/data/themes/wallpapers/Dark_Sunset.jpg000066400000000000000000026701021077523320400231270ustar00rootroot00000000000000JFIFHH ExifMM*n!(i zEASTMAN KODAK COMPANYKODAK DX7630 ZOOM DIGITAL CAMERA%x"'d0221  Ȓ  В|tؠ0100  \ L Tu   0 2007:04:13 19:36:402007:04:13 19:36:40Z - - KDK0102IDX7630   $(*6666(RZ{{(~v{mC+3@ fhn\`aZ^p{xq]]8<->DTK9$$PUjp\8"""RYWP)6& J#+!KdUNQ^[z|x_f1qy~ͧs\G0%S[h[F-#@$QKCKDC44402203hRrrRDW|_-IP_&@I J>+; H5R(n7&(k~^{aJV<,5%2='(3#EU9ijDkkY_`;]Z2W]7\g?RdA T^Z\IJCfi9kn;7-PDv7}<>ɍĦWx9xf._U):2IA 89[_7dfZb>Wb<-5 DP-07 FNT   ,0 I0,6W|6((+Y}VK~?C >u, La m tL1B]Yu" cgQ" 5jk A5. x%vSpddR980100  ( $HHJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?畽JP.*Uz1:5 aP.=Aj@N CUqOKXԝ}H0а# wHqTc(Q*c+@Q\+Wi ֫M ije,،gOe8hn~tV-gl%w!ٔa1s̲ |+9dU-p*uM^eE&&u#J~mc0inRzZ v!@SL`3,s9ެie[McljH@fI$&>oRڽ $F Oʌ1?׽dחM50,*~;.O^HJ=N(41=?H0(y9H@ w9 -;^(R5.^D.fynQvB>~{d+yQ$׮?:4}9kX~StΥlƚ2 ''XVܓVi};g Š5z_ީ$>"RVU {ԡ'Rv 8؄jUbn0ޭ ,).?=:ir$ՒV - sϦjXˑ4lW0Fop#Ȍc}*{e>TקWl.nnH3 sw+2!#E~3U}:0feq1+Gq!\_' HQq;I,Btc[x8-Ȏ%Xvb T 31Uo`2Q d@sS۟L]P7JbFT\tFYQcT`6xqT$b?Ձ±3{T|-hR8ק{.Z<<ʪs:ZYُ^<&9'OjeEskt >]٢=g$MŐƤV5TJ=jA-XJMJjR ܪFRxqΣYzSRjzԘɭ4Xnn 'Hul\.HzVtNR|I>#e;#A$Onj[s{*X$8ldr5t6Љa O2HZla*_-R>0>zKk8=h@Ŗ8Q^C =O~-2G\;1l̟֓ct(1p;@!cAE Vb1DnKI?Ry yu&Y*=-wK숆?-y+޽hX{M I\SM*ϬjQ9R(WpA< < Яwf]An$S,iڟr}h!h^$miyT'tQ ǼHI!O8}7P 3֢*~rX+-' ӡ֬I$w+Q~g$o~8eubێA=nh1"wɩ[oE$HHθ< U B\gj)Cf ~֗t ̘!V%=8*š7J@h%Ɵ8M_(;w}D&R=38O?ʕvX ((z,G *$p* ,N~ :th`6r8?Z*g޹i9C*gCd +>bL&?ݧyʺ,d ?:p$( NgٲOdOB2Ąoz~ܓp9?΅ ќnF0zT}t9~Uytƕ7u\ETGMZ["?+ <(:Tgpu$ӓK>7j9~B+ "`{2[TIyv:u[WgSGe? Fڂ{S.;̧oq+5@}.x@8q[΋#@8{~M]bRw2>TLVuy<{&tA=&4C)iGBJЏMzdOc3O9 u#J].WvYv㚔i/*yюbe#q zC"d }jtg$zWbFyprX91D8n5&5I!X%Cy⊙1 nG<~TRΑ RU!P`0>j1Wi<Lᇡ1Xj@ r>>( _=(2f+`Ż1G1'YǦ*D$iXb[E%d]ǒFy`n2 A1^c.IGJDITle#eW*;_0?09+6:ƋhP) 9y 2 :o3Y'c֐EI?x2Q\@\֤8Agq=0PDF2O2zU9%gR}M'&`'|zb. ʮAV!o w<$旨TĮ`g8;rr(& ڎpQK"a`׬![O1m~sE1o [ bN3ZGGʙirqNk~T/xXC SqE,8QQLL/GߊuG'dϙ VtI5{I{w9qqIuSM +5:p d\y99;X|\)@֥[ tˉʉR2r]Qܭt\mXz)Zf 5|A6/AB6#>Ry %t!W6f'*4,0zkQ%ڊˢ+(((((((((Ȭ":'l=VȚSE0{PEKw. eON1E3{zUt#CC"  M!1"AQ2a#q BR$3b%Cr4 &S6DTK!1AQ"aq2#BR3b$Cr4S%s5DcTUd ?zIylU1Nz4\oI l~BR#1OP]$n%׌a\~pz8U_r(0>J>~~ _Ӟ8><ߚ<|6onܞne_i{ 2F9?=woUm$x',8ɒLar 99_$yQ1Dj9۵`pv~HӤ>~u.dSXc <^%JDž8*F>9RG?tԡ 'xpPn.3~283t;_ .aI*QA Uܹd7DovrrJ<$RD ŸňNps゜XG  'z0a ]#%<럐UW,lX7@9r#(X]]@p#|: ``g Z9pv<FXg9\0F w '#p8<KrOot# J d'$G# ?#\6QI|xrG9I#W;O>G8?z8Ȍ4-CFTJ7)-8OG(YasUxRp䁞O88f |.F DG"-VN0' qx߿n ||0aׅ c1@uAhH W~̧n6U@rs<Pq@Xo(p!rs8?/|Ϸ8a呏UNr 8 G7u-,#krH:{j:TrMB"#>26'Ot%}5Is(e`= 6r|磍 @nNw nj `9,wFi!q'q9㣅TOZBB<^#wfeupsIG4y'v6܍KXᙙ"rLmNve ĈNݭ2v2@?קSJd8wHq9ԩ$ ǀv: 04tr *deA#>>:Ԭ+;O#8#)q~0HV 2s H p[<`rsA|y?9@ or+ R$ 9>N@$3ږ64~0FT<ۣ֗E*nrppǃҖ%b-S$ '#ϟ<z\&@1c+mr@r8?]OɍT%B89XCG$q&*H%,=vUXbK1UUY0Nq0 2ܤlFQn0|=T$k\Ǵg'tt0VCOSBTWzft&1LIH 6HBov=іs%\t&* JaDlEWi#~cu~o[ߛ GF% +.]H) y&3?rz4>vçj,PP\Uf֒X#Vz-A#А#8KsRmR tWQUcj.x FP}0GQx#cFFegG^pȒUFWh`wXK)$6 #Q{{oT:I7(o֛¥M-e:o)PL0x榨挫)Cz{YEd8 $<> *wިQOQvQ44lV370I-A$DlC}zozMEjT(/diRoTn G - @RɀT?m*,Q `Mw}+G(acv@ |`4@+ͧ$1@(] / F' 2FJ`5jGR)-a*}EN;4'Fޞ޷aFvR)҂P)m#K,IK;dSTѰ3WYfO":?oKAy}JJZjtFe *+JGHK =>u4~ =6]iEEmJ3Vj*RIg"oTjK }+{.OFp &=K{GcwS@~}G/ mM,N*8$T.馎Fj$+,qHeբb@C#r<)Quت]B2uHڏBPl M 0nGo{J5U#UTI=Z$S9^@?ϧ-ELv‚AOO;o0njkUT,j nEuZbV:tnVM=}uW UYi)x\Y J0D$#u"_:89t*yq(@!+p#f%uƬIDfSvK\VJZ:8XV!EhZp̔t*&4Ř;_p'2n%wa@22 g$|dJw#L~[r.m-ͦcVEly* Y,m,EjUPly<")$ (sq{t65Gz4%[ [U\z]i:cBi[ƭ`h+[搢[LIN;tZg+u Qv5<8s{]. ?##+nX!A#iϜ i~.J z(DSY4f8vi]#,ABKY֛Vz*SM-ZRjVzE4L!U VǯEVh -ISuZzܽAA,fHYgi -Qoȯ EfpѨDi $Yys (QwҠՖ'e`GB럨5E].ZMVCTQIOP=149MYR_O{+|eE_]xVVz+-5MF+=KF0S$F,r!-=VVZ[ܭO4e+4VPĤ ڒ#1FcAHm#껟v]6Қ)kH૸YpAMIrQzo쫕A f,_/r<2yice/F6zR# 'M+GãFd2@oKu ;􀠝^P-i5V}5] B45I5txk%uZ]*ݩVF@J_n`K'$y OItq4YVfb[y1ۚhcreTm\ F8zrhrpŗˠHP ;lĒIbI$IWie%OCmU@ qb1H@$!?<~O3(c$HH,< 9S9R${## 㑐$ @ORH' 7s]"_k0YUD`ާpT5]kU*jk^/S#fRSrP #E_I# F:LX* wwsx㧃׭py#adrw5Ml pv(}\`;m砵Rh-@wS]OT7M=uՒɷ b̄wʲ jF%Kr岯RyTi{ڈpi+6r8MF$jg-U:-@6TvKsiK]õֵc}'-(TPiDWz1t2&,bO*e@wc"hP)TG[=N :r(uU;1[@'r8 :jpm~nCs7!Fpq'-<A9 9##~}Ǝ|$+eb@e/NKk7 GkԗkOWEG_MY%MuS"W,fV`G$( 'ŮJǪ;cIUS5*Mҏl7{QS"E7fru`F"4e%XkBW[D&B-Ka}Dcf ;<ݮ]vU^/wu%MuW1y%ؼ<$-{YsIWvbﴏW{wrej!ext̓MY*K*mPbo{<5vLwL%AzơhxcVo =uD"Hqr;&~Mj]]qqIZ[R"HvU 1z<eA3I3@XwV\)7)[)ҬrDN@+@">Jh?vnUV+ŮBm̥Z,P% M=< D۠̑ 3ך3MWgHhaG%Nij]EvJZkAZ`SI$;, 6۶.Ri|SE-EJ]WKlBI!6FS{cVn@?f6wGz4:,W0ߥ4MҢXGWqJ FHuH$l@ߛ-1I\Y|Nq39=\pSsK xPN31 bͱ <$s:vvVZy"ڪa,%&\+)Whe1o (䎭$Q)D_;%۸ryhKCHG6z-oPJE4҆R0ݸmk^m-z=uLU˒B32H#UҖRv4wwGǚN Y[@_Z'@1$.A>ܫυ#?N _ZtuErI'9'r|j}3ZuIJNy->U%X,Vɲz; 082T"bv|~MY䪹nV#R-UlJrN=~UBk[vXk+yOFQU(ix䊢wiu]`(R6_>|K5r2+Bڕ&۫ޱⳲDxBD{1w؍CM)}&EGlSq+ NΪLĸ FIS7PRTvdqڨ%m|edJc1ɬuv7W=q/s/Rvp>dkdgй޾֭M2^3=|6#Fܦ]5\/%^kEd LD։ 7 !` qg$7fNfg@cWWKIq W YV4A#HOR*FNIS©-g|{.^tHkv}-+ŢaH EqdiR0;ى#D㌟g-#31f,ŋ,1?9aG^>᮫sZt hJԟĪgd-<83 9⹜aRiLZ_"  Nj\u"e?* Қ4,3 ߜ5=R)/5MCH8@dF $jXߠn[NvZ(h흾)/rGFk-v‰IZ%,:/srݚ s]ܺv/;fUUA=]uBUSTSIN:4) cU,}70ܨ3'˖l0ܠ&㎽ ;'>C&ٳY3Y7t+b33iRy/9A`^TF EkҰJ'I>ւ=4us$H((2+ckܤ;6mz|5Rj6 J5JPU7Q7着JvӟX u⪆jj;^3׊+RIRy7dAyCƨRIRO_Pk'*Hc0Hy72Y~\Y/Rlĵޣ$nY\1꺚>eHװݫjŁ7JmM5Gu6}7)-/pIJk!hfݥ9]RM_iDFت,K)=2U*;GiEymmٝAL O5mZ|S+ S*BR A*ƪp G^f}x P7Y덪OjuVVئZ]L%ltYfUO0ss#RHL->b :tcQLB!=TYUm/E)bpKY6+ܾ^=]ږUyKE*Sc2) YF1 #OY5&^i;NXZ='.¶h^]iɇmn;KZͤ46ws,GlTprHkJUju_L/G=lZ z ,4vr**!MW6ڲ5x $40 -'^h==kzWVUVY u P=$Ig0;d>[/c\54*.Zn2 hiICi.t].:{PZ&Қ;~ucPz57d]2í"++) 7V]Q-,kAwpvX"UKKH0$*j(;f;}TDd8ҦrIr6d`C3ǜ $1@YExln- 80rSw,U*k#h/uUtudpU &+tES#TN[=L2T`ؾ+)T>UeGDukY^jpET@M JoKW_ ]# M^R]6b{:A/$0RKd6zw`ud!+BTWCpiu*A'e&bP[Sl]=I%QצfKʢc;~^K=tKm–8*)ܤ Ve"Dd;S1;_ޘ4ղ=5ejzZwh㩡֭5mHƣ{eJ_Ob Tl.`M~Kf@M%$p[ܑONlL V3#*пOοwM :L6EPn]}A%d֊٪*zCG(Yۉ5j;ݯ^$vn .W k\Z ؞窫jRVVJY¶o ȗtIYLʡLac$^nzsRuEmm%NxowX*ĉAO}iA$x@Y7_pnZ٫u=ƆW?OnKA*6SH:\sרomx^{Xs zZoQRUlGhTeyc$X|\ĒI!-$zFEQ@"QCQRǖ,Yט IRqLZM/47t5]djLi*xlOMQ4 JU>rjG!zrUAyԔ4՗:FdHλ Si_wt֝Ġ;SܤOCYIvdZD IfEܫ}?Y掼j ]Ĭ+,ښW)$i)dp&g|#-3f5/xpH,j8Hw(!tgQ0R$@$ڀB+t jըDvS>t.v1~UI qEzvUK]{3f:aLJ3q=J*-UDZ= 5B'-l}]W E J"7`I$FXppq֬Xj R QFx.L,WhS@2r=Fdy1U{"jees@BvXl> 27|$uUQw1@G@zt_^k,BOv9]HW“Cy$g0ODd*sʮ>I7w>pyx=-HQ!G9 nzoA:*ʡʸ9H烟'eޯ%9.F dg$30Ã#+6H8 ?''FO q>??:gjB4PRq98q~1(SH\n$\R~Tc#si=\ 9"AA@~GĎzH0f8<@?s*H <{p$ 8}*IQcQr2$;s|:%$O8$p=2F|g9:9EP@92<G0P"/` p y㯑 ]Mm`*A>:nFHʰ\O8<mHd =?Ӧ=:{o:zH(FdaF gz5萂ʥ<̜#㏎q;yQ ohq r~%bXcRw8)i瞤v;}] 3gr_G' #H2I dF\>P# %@*2`:5$1q?ط?|玘n|oۥ>y;#EB#P0XHI8NsdȀ4a2rD gx'*%ݜ`19A#v+n~Bu(A!,28>8'$FNIq:aVʞ9@sN #oC$00|y󎫮Qw v-=vNzi3sN>/2˜ufr.)(#@g_? Rvx|y`c0A+w@{4y;c>4V;_w hk`zF;1kQmimwZhjdϯN (crrVL6kvKWUSSWY_[1S$SRf'B@FF?J;gޯerIUK\XZ&ux#c BY7ku}GN^Vqmkg{}эȔQK+zǝ[K=-UucKEHI%8]PA4@{? <+zw/w*ŷU_"] Z( _jyfR÷Q*K#EcT ( Xh 3G~ ܒIݮ>>;]EA~߶oEC=+i;G.m;%OUKPU0ҁ3 FW{?l^{vVZ`Qni%u$XQgh_;j_Z%I]URGٖI2 EPW2'_黝&gS&-UwYt5 5eg"! ,gs/!5"!̰\ySYDMkDgU2Bea ,| InҩVf;p@$+c?>4EHe)um5d2g$JRQN~mv;ޏ}_k{ł+UFHN1?wHa;lVYӚj{v^o^(@wҝL9v ^Ь},_'{ƉK4֙MulCmX•!udϧٚ5#/CӖmMD Ep߶7~*)KQ= H,(Àme$*ke-0!J.ANpBڟѺz[c%F˃^,%)`> "GLG{V]ѥ Uov˅Q0QSKM$u#㩆*Hfb 1`658QFFyF[v m.[ROJ*W*JYdRFj60lm;-%gރ񡬷 Rijsi誠ݩ5:PޡRjJ390V~wrC"UU_KWY-SK-$ OK^ &GI*x>{S͇QotJƟޖymW}UnZxCU<2s vgԯ˦ZIe!hd&F`be*HSMI%j)QQ̡֔¬ G4FfoV뽂AKGgMW=9}:UT[䩷Ӱa LnfV)pYZ %zʩ]7fO}#_-M km˭4RDՂRzs4TJ# b5/u~momҝVZmM?[\Hy&悮.wEjtBƪ_ھsl{ 4Go ZꩥN4qȴVa{w)Z ~i 'tHli&Qnzֿ_w#m˾IuMZYkGZ 1FV7=ym:*IZz1h;U8t "1*ZC70"g2?& H*JhP=d YE J,ǪxeIFe ϩg[QFRHE϶꧊D߽S-I\HbL+EeLTR`7sDrzT-Q~XZb=VԔRx["patGaTWè4E_~ł4L5 E=toqrP @Wh;i=e^_g4_i1j %$RbVlbNew觶7-# IkԷ;}Tt=G]vZdjnwM kP-vQqsjOUNQXuR]/~Re~K4t]P?iEg5DAC;S-]T^L S?W/rq~{ŭNjtOc;[".\5zx^6Yfƪ&aZVsViGq쎯Uj)禦RWIJ!UR$r,k.^*N 4%X )¡tlnRGؕm *g::ӽ>-w6F\.K{MEՉ@(X ,4ϯ?UvյOOhJi14p = S2"zҗm'ys.zvXw ^mڗue/qҚ*{QeoUTU2ivV-=AW_(P\*b,^Q$q Gϙ %Ki,ܫ=r ̙5;6ʈT۹V+bF8uEJYm~']Г̎(mk^9 ku+A'cKVcy.?GZ[KP=GV?F#I3(,̨I%ى$q_L\rնk[>k#OO함r(.rҴ% +1^V~T8Lw1=v\qZ `S /A%wԽt, 06IEN\YW!ϫITy+) 8&DVkęxF2 >9z4r++ȱp9*= d03I9UV<JŒ I?8D-!9ʓ7גwب {v׾V,Nй'$c'1y<㤗KOnUhƒRIq;)mtqfmwO3X्dWhw+flKqi=ZUj[Zb[LIFSł_?}MZIƊOBZ^E1]P[A9TY>+_ Td˯&,vwrHo+4ԢH%@]w=^US4e Yn vSTs +*ARQ$aiAWGЯs/pWDv–Fkν2Rz0e ?ՒR0IT` \hH,Os]Cr5~ mEhG8Y ՊDdF״w m;-+j ZKm[(Jz}IQ߅)O2|O}VrEQխQ!gyjF.z<oSLMZ?ۗ@ /&[ozWV -zZS ImT(掆NgokAnvWj-O^ܵ& C3S1-Pf2$j} J>v);=*(cCkQ4B@Ρv2 )N$ x?;gkkh(W@+p 6 HF1Tڋ;3u$ rw5+]?oW(pVuVk mE0DM+W1c h:&:G{E7>vu5Z_KMi=zzkDS\⢨樖H)"Jk""dܬX8#du֚B߮tvз:Ymq4 jꤊypFފv0pFb(4{gpI$6pKhM 6.4*IT(n y)*i.4UWYPٮT-PZj07Yd>ãtqv` &9w<:nZN6hgpϥZc^[E}5M**vWǭ3SکJSC7Z[Vw#v= ܽUE\l+նƖSl}@;RTB>hC%:m*} K$A+l7k:M4NI?q;}6g%0?201FI="{7-"•o?_r[o~n7J{}]^+s_yʍMAΩ!Aȝ[T7 *lT IZZdPۣIНDeYHH]Wj4{]: ̛"qUǭX]`]"cNlc=b9\WA9i5{--Ť*m'Ҷh:+EN{=,C:=MڮX%Xo? `sy^( jq{JH5tW9=3Z5T:djPѰt`H4U`ˆ`0U䃥0{6(v+e܊z\0?vr|rJȃԌ>`#?HKW;ݞwNf\hۅ"u7)娊x+%,f8Q:kOMEuLF0ً;B*V;;|#*#ԡZPbƒ+^tX?)@Y:h*W~s%qv ypQ a-#UdMr2I!=R5`eWD%C@ )$-]=î;I\-u-А\.EWl4<j+9$8Uo6|K|3OKqnW= AҧJ]msi("SK]Y}I?oP+-V[j FѴzJiS]jj}̓:5:\w5>=Ƙɩ1ATMg)Ͷ^R ǖHOL$nx)#xlʆ#,l6f2< +yP˙BLjHb?i: 8Ocm"ٮZXwj)Xj.Tpg TZ@ ȴ (SkᶮO9c񎳮<Li-;tޞӽҎS[-9XRƈwJ`ZQޗ7>ܽ*Z녶बDx#g۴ 6gqynM X dXb{Nk-fU$sE)MD xL+l*hg!>9yV]|i߬DlaPi[X%ΚtҶZK\:FW^lS3 ɗ6bcjWv3,K1'I9'=[tq :Wޮ4QW'$qB%Q SWvzNeKK[^dJ+FZרDej%"I4bfcKVI>mB r&#cE y|;/ *-I6Ž;YJ}Aݫ}cƓ2=Ҫ t:zC$5ؑC4ΠSZ]럻tvKX.ۢT5> ];eLD}8XUrYON鹻plt]ӷ%EMLzf4Ә)*gȝ,1fOo<'rl]ڬ6Y5oLi#DI3BBn9  𜧅xq.zp3$3c.D @g1ffFg5.k0) ZB (Is{GJo}-O=:zQxԗMAr|++ #@ѵ${T$p"*cp8I)8Aby8Yk趶Jni, tDh$ Q>G$jZd^Wo#+ 'yH'1uQcjx +]FY 2j4g@1Q|n-cƵ=2DxakgYX 䞿;\}Gvc=ֺ諦W\f#<_TBљIv'Ǩo?#+b }OhJMlvw9kkow9 Q}*=x%R;UWqTSݧM Bw"˯zn Jꚝ4 VGO[c`n`erB6ऀ 9 G8:PA >` 㵖8LdZzf]TS4p$r:H=l[YvD#[mOKI4l+r,tY($|2Tx\SG%BooF PlY,ם65={P٭zzrW̒T="YiK[w>E{jvj[cz]Kj:{TPOg{AiM@"s=%<4c1;Ac;}bͧ5Ƶ9gR Sw9Q(̐"ʂc!J($m( @P4]-%lI6Aj7bu}7{Z%k-֊{n\hm1-B yR6XJŁv55n~Mf;UWe K0\[)X#TD8ܼ\[/^Kni0Mm7GpcL@?c۽z_]uEpz#Q]Q+Sj(ᧆM4"#T7Lf ,E# Db 7GK$+H֐y1LB#:|-guʛd;۾ѵZPdTiej:U`~E]wbP$^wZ oQoO&1ޣVz\0$P < xrv>җR[&V L~h[m 2Xhu%'FXa :oodk\KYoޝba^Ir))G6Q5쏁%|sA +;HLfiAad@ghŬG3g|d+'G'F"ӳZ֪U+V-gݛU#_pK1Hjj2TW\+XD _W_stuVc7+%έݣd6I5RFȴcdAy9\=E'd{{m{⎚î.'UG @bx i`N2v>hMY]0vocuvZl54 ,"I" O8U ϗ : 5G Q]EQR 2254 ) Ҁ` 6ME,ND{0T`ӐA>+$5fy#]ǒ9TW hRkJkhe~5Gmi%Pc&XuZCژܾ#zSwY4=Ѽ]UbحWdЄhCoeRR::FE`He#IwdXlnaJA~Hȯ5ڲOI4w%5ʺ-EFYUlRQtLm)ǻX2ByhI;8:J!"g ٟp;`UCyK, /p8D#u*r13 1>|G)CpPO ;\#$r |y$\ュ1.禨ޣ3d.Xo 9|Ndn,շL*~}_7~ ?!ێI 9A3Pl^ zZ\ R28'ǐHX* ˁ+2;W1АJn#OxM+U}p7ۋۯ϶p!.a<xF, UaYTR31<:kpV;KG#2tlcn0|7 ՌavF9HnNqs$$,)Bkec䝪H#Q禤:1S'dQѫ' A8Tl0#G019kH}r2}gzP%P 6w>I,dYKm28=,`'݃ ?N3q# p&fp;(> 9 t|ẸA*F0A9x:D6ā@8 <[+ @[;1sNz0a\s!ӸGJ7|Iۻ\FqCrڸ|9q'BKN67.Q񁻏Fpr]}ooPU "+$vB$,H*pfG1lBFp1Ymbybc?ۦt51*3[p,I$q<)DUdR9o?ۃD #crŌ+kc`FzjY=3g8JP1b89M+N}чYV0J 62-uf> 9FF:gdE=N@| 㣽GV%dl8!r+$U0gqq2z%[j,B>̧k A ,N] r@8y:::9'('vOrqzLJ`9Gs?M$K)p8nQ2rTh7?﹋$}Ł;A@C}}&HrBvb@$dsϕq)qೠ &{]F*d$г + ~K6vc'玌)iw B#o G#/*ِ. X 6񑃕,@(lF|~: +DIXmmy:?Ty<qq=x|wÃ;o{䯧%Y#*XK?>pb䓴pH2zR1xPFH<`ѿxBȪ˶@.e<  9~{|/wt_ӧyalH9㌓'8'H˄ a{yC㯎=I#{3u^Kam[}AKn ܺy"f776*G(9}'I .LTjMg;WT]$4+Nk^3-cg]e`YbG{ʱMM%ʊi#zZXم:*I#! ^9Ƴ$H1hѪJX2=e⣺ ڐ  "-`Zbɧy'Y$@䌜~:RzOpId~9&H#FH8G cڢo HőEB7zU9V+۟L6G s%)Z3|I{Q}=^v$KebZ(4?qn4uOpw]eIxO MR:hn,^)*27z; ltm֓Mݬ/L[T DcjhoE%y*}Ijb_}9IY]\435t#B,T /rHsv(L}ivyqi[MSc[UQzW:ƜyE2i 1}h}dAQjڍ!VzuCqw}?mpI"LQO)EHd>;߿~G~]m]h,ZcMEsh)[BS;CTT-:G>v/*|ٯ.ӵ=к㹟P;MSibҶ[tjg$x8)CO 1:3鿍yD>nc8Ŀ ,^vc 8we|3y>b :P>@=lʀ[F1랦Z@[n7jۥ5+Y:Y7馞DX#H(ᦇ~tLQ;}1G۽ -P3M듍)dI9uvnw[U@\P$ՔQj;{-tRni'u.݌c^ػl~Yt=jYg ,L蕶ɠKI…8o+'9$EHB/GD) -E$;ٌgx&XRA+R1*`hJz5&jtF[֬$5j6{-jx&Y Axdg4`rb>3>IMTTU^QE=Z(*]Z_H9(p1bV\o% }\i!*B $G(F’۰O=Q_WzϧaH?îzifj(HIQ딊]@zIXCֺ. Q#IÓ :4]$n `Ix;;|9/==mhu|ZZ^iJ/Օ)ȧ6#/diP=z{yj]bpj[E6ԕZr;\W5uzv5ZdZH`(elmJڏYD۴]55mlS[Ҟ}Βy'VӼQ)DQ>m]c~p)oLigqmѶ}3 dk fk桶HiXz eJeq"@fsFXPǦ1# ;fgTTki^[!jmZZ%Gk.IfWi qSCG}ЛaJnNkNJdز1{oCoX\;_Oj{k,env]uc,jiЊI'X"rlƎDW}'Q 5ewݩ(a UMt͡+IMK +:5QQ[R+vmkuҺj-IUV5mmU\4oGcīQQ3ec$v sBz-ܾ+jzZS}-5WN+n%ӵqʆ4$,{~Tu]VSi Uʥuu`6 EIGo:E3L*jdI)b0il{N'E꟩={ȡ2WUYo:RQSڠ@#)+-Rγx3$5 Θ: .Q2D BIw&vֵgB!R]u&9&c58? EK+خ[TM.&sXJX5DMOOԵm=t-]Aa}Ow#BNOtVWKAUjij#nYz9)t*bPMzܞٻZ+*n"G+SDSH=ZAYR7!Ok(;+eXkԢJSnTtmQM4u8= iL1"fr^7I.ZX E&TkY@uV0-qhU%VFXS}! ?~vzNӖ!K+vV[يu7Eh+i#Z瞞}I40,UƄҝ1.k>w]pZjJVn}7 zd^7r4J䤦{eGϥZ}-OrjrtGv4֦RMd%:vסnyJjxA= (h p6ח NTֽRݵeu"{)juW2awrݤW:]SH MRMVG2IpM$duܾڷtھhԗNjP}b/MSO3KKFw?ᓺ+w/dWw&}|dBvMS< ڸ.Y䢎%C<4:Jz<:>^O.#caJنS1!+ui39s-| RJjUasjH#cvnk׿_x5ɦVk$z ۫=1Tk[g"XzyRFKU-&29hcۇPU-m\fKnVZk]i[(#DUZ?Vyr15*Āf3!!TR)5Cw(>W$EKVL@=Ww}ꧻձEg VM-J+=9"*$ZzO3&Gl\(;t'gz-t7;eHMGU$RjJWBOOS RV*. n?umAZotTiQ'x<@+_D`uFbTg"QoN qb$xgف*\HPBA i~RΡ|p !MIKI'vU)#3\S],;-U0ƑFqU@T?}MWa8*?R@mB뽬_c0dڬă3aH0<{Iq>6<8$YF =8c{E+ܚ)cz}=jlK#RV,O3z~bPr1ӤI bFRHݔs2rv@-nv  cdoQ1 B\d1 aC8un֘*NJtuKI]U)'1$u՟`fY/:Mz4m~^mrG O$)'B9(k (W_HPpO>Tt{s]|C6I 0`}Ԗec]!B^7VsNˑ2% P"mtEҷmv5lnI`®=Z7x5=K~};I]LZQꪺWEd]*JĊ9g܆ u֝u;IlRi &ӕNnOc4֮VlA=,Ұa$RͿwUgC;SRY56YL&I Z$0(G'vٹϧ^Y{jX=VYΞWM45Mw:jjMVNVPSYH#IH$Hƙ  J,ntQMM7iOh\AuIqY*h=T}u]=L[ޮ5WltouƫEt,VTit^(&I*`N42lgF+{ӽ6PwcA8;AjN1`ߥh\QG=]5ZE$m?tsNOtKz =qWTHAOMOEM;um~PձިiUPi5omMtի+GE[o: zwzGSt>;􉨩 ]Ģk O47 ,;s|ډdj1ҜO[0v5Js 0Vg^9d=PDQhtֲep@).G.$zM(Ue%Hdx϶6\) FFsG`o vFs8!Wqד݋+sOjݾ[ϡrZn4oxry ^Igg>ŷg{~>~wˢZ2oQ#`ljEYeySˬf\y?+5 zN u,o~Bch,tDNsP}>JïWOk+zv}UEmթMyZajYoQ,s$Qו?V?WQ[Ŧ4nNhTKEDj5dMB/[媮(mVƖ =%WJd@K=5EueUCy%B" ؿO;:/菿ھMq{T?bQnlIEK]LO=]ʢze(KKxf{=d-,%$) uC:l1E)Vl]WnPUiAOc't٤uKAOk8U5V]<)zR1d~ڷ}쯼ΓSvRUjȨy"$ r nJ 1`' /kwv5o{ֺ*):uUDWuֹH3RC.4R"h˗)=zLvFiLT5FpGWs%#OsצL5]#8=%9A5+TA=B$4U2/NZ6<M,Dsv} )TPG3@# ªyDukZCrhqnX,]/f;lYҊmE@j&zI ?=\4v 0 nY,z?X^5i>[WTwmM-$MU]Z|7/Ⰵj/< m+2M]Kq>UCM#RH'mJGQP$t}Gm٫ozh6oUSCD+ڭtSHg1􍙔K/Ghm@kU*I2\⭇GXeE F:~] ff1tՑFIR̬=e 0Nq5{^~.o%4լO3ԥ$idA2u u%?ƾ|)ykcNY'eL VF`}}.niƳKnk lZf:EySG[WADQ+ acw^5p1s)> ef.GdWfpH{fe>c%#/JVu[y$bw_Mu5ՑOۋ].iS+SkP#]9+JկziuU%[okwSתW[4Q`#FO骶X7HH#^?l|YقS.ʸ 9R d|@HFtX` a@ iUZ@yc]l:mW}Iٲo !ۓuD6SڨzkL@T5!reXnR'.!UrzAS2ȑ_R)cJGw#dNF /OrMʸʅ$ <bPmJSXL.zHb0Q[+ d[zhj/o P"zxbPjA"4 Gkm'8ZX;W3SQ!=ܧԖXoҵSZ*tRPDs(1&zW>dUTeRlҺz䰼r-EmWS"La8ꄻv^=Zoj{@R5n Q'Rzhʄ'p(LeMB0JM/$Fh5b 6TUYkU XlXe6UYh b&E޴xi L@B}M}Iͨ飡]w>.ʪe㮼WG2S@" )PNGtڒA-t[QjV:c#2}¨ _{䜏@L^uh*%N_*;Ve8i#N׮˿;'?s)\LjxJ\E00^RlCrUcI +j"U Hfh$?M=5ΑxjH)MnkJ L49bMA28N ~o}6Wh4jKF5liKl&Xz) BQNre57j=5L޵zUoOk8*-K(c p݈7$O:{¤ԟQznltpW'2$:㧥+S?%]9yWe@&Z]`FWTIeFaZ:xՑʗQzYG*H$i` 99b knzvI"9X#IjENh& A <^WqQʎUWJΘ"hE.7 W+û2 (|r>箏b=ڽfٻ{n|g~EYnz0Zec<."RKmå?z Vi_X,Z|2WaIbiW9 <TmemA!܎n M6zjȚzI^]UЉz+(0,IXK4M5R"FHgCjQaG#f*MB؀A-Pv֭,Tq5Sık:dugFLFy+۞4V}:>m%*+m0U,]KWI WЗք)Y{X26=PZ5 bO]-Ua=*rL,LgvӐ#6Ҡe$GU} e L<8WU%u)Ӥe`SaCQ`H$^”LC'/dy>brz۹zqI`g0rOE %C@,'<`8'::fxTvbXsWی$'$nč]{_c$QXIl ,Y8$VWp_C2mPŁܣ'mX ^<Ō6Ng;90^[~LHϵ?d䏃8X`($݁x8A7Fzedwn*@@Prq~cKN#ef`SnXCrF8<@u wZ$eFdnB 0ry']&VAe` O &B`PT rG2dvŽ} 0*d'@z0;I-*Y8Q!0a\+S.Aݤ|i_S@L60Ē<iw1 1EW} 7~iu۝OOiY$VWN t:] 9ee`p<Hx9й(`$ 2F98x篦OrFYF 3#zinjj=(uEa{m},2=DK+*$10`6>$<ێSTKOW+XpAT88TY !q7 JFQH!oQFHs:0a l cF~8J#,Z@EBH#NK<<-ʜ rs6#!I8`u;TpǓrO2gh@V##Qf]1$xrNcԨx `H& 9Vv!O*7$g`ps 5[J2 )睹gOߎh*Y22 ~ncls;͂]Sd0| |;%C+a0|G ֚P}<9 ϓ ڸ*6w G$]l}vpt؄ ܼؖʪjH<ҳXxny㞑F$PƛWܩ #-`KN^vX Fs`<AzBv$\}Aȣ|T<¯v1*?Wю*,vQyӡigʂ'ьXza <2ǃ@#zmZm]*.xљPHxy|u2 HNf{I$I݀1 gi?ߌ=!#ߊnm\X)T) <7pO_uһduU'88'Da&29898RA'i@8$f8l2`x$g226>AeefO'`ȑm2daF23=& 'x@sO'=-?(?I881 pF<:0cYv$ʪxO8NN9?=+(V*3pA8$|y|u@ A<_Gkǵwm#A:0`!Gp9#c2l .U g\(198C9?MZRX4KV9kdQKTu& ;b HDr2pxuQEEEU% $U+' u_]43I#aخ2|ٺY_]ǻAO/Z_GwUS=6څyNȵt-T['tHu=^+ja:u_v&ig9VP;cinL|=AzMLRKE]x^xA*=`=UݤP.B#zK؝ ڰn=Gj"C]ϽWZ6QՀv+ q90r:,{xaiͧQ D+F7եu5rF M3oL?DhU;&i5fiBƱ!KP3U:'VicJU%Utck-@*ԕ̑4J$9r BX'M&}oH C獱{oڍ0h?G=MMOM\R̳OMYIaYbNȻ<oCBuR.h+agH$,T`ƎiKN۱2@'Xzjg f m#!WjnڋPU۴:UUd̶'jM0#}5kRL:Si'Y.zC޵2jid]::6,R<Ύio>kcMhN&՗=opjz 4I H$d<[Dclyd0IH4Zcdʺf3P@Pcma!ej孃J\Muꢶk/p;5{yT~uUQjZPEFZZjF"gg#JCT$0-K_Y]W+WnUQ(Ŏ[MLPĩQAcaqM$;b3=CR@BA})vE5:*xj}EU_{֦X_UTjTJ:lejjc6p$5O, y;ߧ EWl5}[~NMOLdhZʖFv+E9h?fg4U,H_0ꕀ6AB#UHN@^4v$C+%E ,+@h+VSx+nJ~]{UXnۘZCc2TzZ檚i" AuSw{n;y _=Iu[v])TO_Rf 4,wog.1l?P-꯺n]fXo~("S gMI'8$iUatHgJ;IZZ;n,})Vym (# K? ,pd5blNDlh̤i cO)2sE6.Β^\ŕRU,6b,Wj5 ۅfkwVjOut-ktZg<uGPxuƟH]vI.Nimv[65{i+]Mݪi+VshOPQr;ٛey\iXQjD_Io]S$кvhʸպS/g(Z-,cԔHu.mY,7(#᧥5vW.T" ψ14orap[.5UCVY//l 6%Y]`I{*ډV Oꏰz̷r)+S\ZRVTH}–D!HІMQpҕ?˻6oYoN9յ-^޽nP⒞"L4aai 3 ;m7N.s\^Yu=ũmKgM^djXc4 C kR%Ć 8 ۏ^./K۝kܭL.UZ f1&Im@Ӭc+9Ϛ ʰ_LQʕhC4a# ΤUʪˇT- AU݊pH_Zsa7u뮌;Xj'quZyM.JZl,hf}QF'$j@.vLQ dj+{UMX#-0;x) Ѭl,"enOw۴iNO]w\Y-O]UJ^ZqJU QS58j:8ATl/-bVwOSVOUUdVzYj)iަ{}5J(dyjI#'7,dxw."d}qC敌0 Hqj`'ʼFhdVϠAh)5hJ L;ޝxuw7V?l'xmt/ҶLM@4zZ$K g`X;Cj8;niHGtmƐTAuC6SѶOQҬөgquott<=:gw;(ޜO0jSIWsKR➞d-#k=ϰrn^HkL8.wOu/CSO<LfTybUeY9Y\cdxdBs1I*@:QV\X.l\ԱǔXhѬ<gQ`l1XnƒMGcoD=GӾO%CTr;{\jvTLjx3$e l 3 /:&{hnZ:xttz.ԗ7u SQެz]d[jA2*D&lyGuOZ}5uS (hy*eWvCK7*.ggZO_DԇmSNEW4VwZUYzKt}{Zno[Wf!KSR}3!C,**2"e*泣F4"*ӭn]<Ӻzݭ[G V7K٪zQ@ URYR;ZP6WtVfO4V[YEjT*:Y`3Ж#@1Gk{kǩu|[Ej$ەG : "5yU>!?dyS01,d,V2ufycDfR<4̪+CPAU~JM]O>/CUqwW.IP5 ZcQJINRf;V?ߥkUn{Upך`5)nV>j:CI%*v}O}A}8itӏk*lO}9j`C_r4vLb!4S@qKGw&ӭOq4JExz{5J*ʇV\)M;KL)L݄mCug6{;Y2&Z2e)(<]@:@ZSZW džUH!c#ƢT~kH񥾎MAWM 4_/=7jbGTѤQi=IWm۴c/#J5I-4YсJ]$K2;K]eVUf}tw3FOKs4TgMMt5Zyl.)"Z&Y44N*'fQDqw3xk x"*'ϸ+ *c ːPcVtGML]ƚS)ǖ6KF&[uGO\*k'Q-]TQY*<M_IE=Tu51jܨcYQGL%4٫Ws4L*(Υ) 7?ڦڏl[;$otGT[壒H9%W ďxe|DŽG<(, .A,YN ӿ|.(\Όbw)' \Yi y3+?g) .nhkU5AlP([sTc@&^M1iereGI eXg 1]*D e}Խ UMCsm5XGkxPAmc$2(* +BE5K%øq ךZ8u9ךRĘj:k}E3KO vXezdħ$2I~YYl1 ʊ" ,A]+V ph[ ؉ol} UˣWK[u+خ3ӳ"VONA!/-:/ z3T[&zJ +jG\%ė?/z(%5O,._*~7oUV-2kڪR~X*⥧GMqM^?,C Y#WnaߢΥ׽bmOmST?q޶;GOI,R ZX&vBBd/+-$D3`*jm16kXd`}R1@E# ,O`YDUHm'Wu]%VeUn-f8TE%CRX72#ot?ΥnWx5?zi Yv:S2INVKAYM(nHt*vg]}Y ;Tz/֖㣦_SHM QoXXufWLX#uoTX! $@If)Z^4ġ:VAh$ilbʒz4<6HM/u@iڍaa)>&jj}-5)+)5uyc?Ei]~l]0ijZ`T%_D\Z-ճMF'ӒOSw`־=ӺOojeh䧂MK%쪺M*F'G8h%y;,V+PXq)mtE[rHwb:(#q?#H2o:gf5HteR)D3JС[.D6ffdk }M]eM1* rO6c[Nkar&k'Elj4%Mm^Նj0Ѯ۝#OkOe}PsM]\0AC!O5"LN3FN5./q rFx\{ՙYT ) v$*7KUsxy$d'w=jS[ڀR,WjJi=jd$(h%Tg1jگut0Eb[*XBձo X;>AA)pH Ԛ_M v}6jNͬzw tZmY ]vUS+smAQS:hʖUZۭ*uҟ@j|nh;LڂN(PƒT^fsòͨ;cL[ꉴoi5T?o%#$Dlbs{9c*qtT{YH*-7zZkh*ʛ`X4TY_[ ]Hs@u, ]{ EhQaT+}x;;,vK7nU(l;UXY­K+Ո!%C +nϹX{sQ\j,vwn%Y=;U՜~#ݠg{٧aVV!Qd~v{M5BY4wOKʤ#"Ckd}=.Zbǥnm+= [(W\noOÉd@BlG)ⳙ3G)@3 2*;lDb=b)7eB *P4Z׫?V מsC]Qۻ_\e[OҴqxV~5:Zk/l4lr4wWMHzډYqfZx 5WVi-'aIY-GKE]DL$kU5U2I#G:G-wvuFIsCh6jOZ%ZъzvǙS?׌&o+Px~]$|y@c _1Ҫ5yYF\(HUb.BG%kJ $ZsarG~C-Kz;Y}ZErXµ]聂,'-F?^mSٍmxQ|ITT/7+jUvhm4sMWPX$FnJk=-SU;9;֕{1q?h$ݒ@+cVZgV{(6M|Ե;N}Co0 -yy2Կ^k[peXjꋕP\j.7 Y^ZZ@G( 4M!RRIJZ:`U%@';[~C%F{e`i樊:UIյSTgh23b}Ek*k%/4껰wzJZ[6M21`7'c'.Oh7wO(tҺV]OKC }U"0QȟŌT6LǪ.՘_-h~3E%I_aJ: |x/hC$v5lڎny8$ųkfU۲zܪm9$)$|N?VPT '$q,u*Nsϖ B <''?ӭQ)DN m#=PrjӖ[D-"]b2:7JhB,##~2d6y$ YvV--ݵq ]],K#I-ԉeFCOW0ư#ʱ2bl REl o@}ۯa~SJ2&_>9 ْs~E_vLjd s0|B *: H&UeVTw6$BupF,D^ q 97xx90oyK#DNC `0O@~zI,rvy+Ge# J1PKjkmnӻZPd!_2JXulj`W$ȻJ7B_$sjy-2QQTUOHS$;2۴sK{.Ӻnq.p\G J$WS |p5dlk궺Kja%N Q{s9+g|aç}j#`R:xbX8QPTTsibHrڬmf{W{}mRڬk} :,T4%wy$fby8㪆3kM&*k:6I\LHEwNI2./>%S*E Ht*b00HVzsOFCob KiN/i@)-+O"&^r\R5dRdu ^H;D{Ѡ}4hszNå&[tF;yS,rӻ*>-S,3,ҫHŷn D-K:ESYoi\Y%`]#?mehJxxp:!1D{ ͂89D5S\+hR_ը5N7;FqBRJ PziBT 8ksO4w}A%euNiВK4?äݠfZǩ"x,+$a|G'q_h*LDzBQH5t)OCpUwzY>ܰ454q). y7,Q̲;(;w@9e𣾚D\v+7h(ꄴWPq5qNdbw.vG>!)yRGpi@ͼH@0+3*5+ ,imO"O$BʁMlVKjnj*(hZJZ5=Nj+D }C5LkG#YIvy&Fi%|br3$ pG^tvնM5‚Ije5.UigӚڋ,9oaǹ| H m<>9_)$&bB#2׹P'J^vj`ʅQ@] ZSj߾0OnZE>\/5C-V1J7˅~A΍@/iZ;e;Om(52%54zX+0*;ׅCSv Z)M]mJQS+RCNE1}HLi9h+ -5"vHfps"xvdPr5wi͖ɽ0D91~$3@Dƶ7΅ԔQTW^Ki Va2)K eItZ#Tjy䨢.2ܧR\) IO*GX Km`Al/` ޚx 412HWXO_F=F+5E*`w=ƽffR"(k QݨZ}v?#a~h[(wX 5;m;qj[s]E l",/#2$^v8 V -^VW\=G!娥uiB+STlݭiۧ/v=KWV%u )&01x$kv*2{^bsSK4xXv08Ly"]21N䳆5Z7s`5ʠUX$W}l 3 VueӺ=wzֹutKIVC_Yh$M/WF:S[ X.t:\ET Q9 |0lHTN썻x<##ld\{x'>O<8D< 6I[$pJO88",jʅ=J.qF`Õ=IRq&,ö9c1 i[6ƞ5m*}\.xAK 8%>1)AE `N $H?98 ~VR=, 78gzW[De [FWoL 5Ll$R:qz6$TTO>0<=%|+ʫnVI*c;X}XxA.W*ە]Xdv2y<|tҧҸYއ|bGFnKxl|ayl>@q1IMUXcܭ,3e;"2n;p0YĮUv 11Ǽsr>z]5c#uab0$q~?=vX$?ߢsf23@ @9OώnY*9ڸ ';T`Յ1fVex'P|y$N s#''ѷ~|aYÝ*rxV OퟫWAy'x `6ヒ Œ8_Z$b|lH*FmAՎ*F@w8~Z 4mV8ܶ/WIOlPSSD6] iqQ$j0^\zkQj^ni%KՖH Ȓ)`O88Mcwm}HrZդ 4RUwP9٘uYvni (| Gm[bD"W|#w$ NI[kځ;n$UB: WSq>T. 'ě-A_H dfʪP 28l.r90ˍN 1dpIqY(.kTo[knuM3T4H#*$y6DV`:k>T=ol4gr$ij*}rzfUi emښmiIet5^ji3[=ZicXІ-Z>/g4vu3MQSpj+1*+o2M:Q]*{u-!kiM/>єtRE]teOpʕFh6O-;$E  4R9RX/$΀*1Sv(Ы $rF݆4zԵz* x wWX᪬)>jɍ*gCپwi IYiWƗ*"6Y 6+ %'!2k}k G:qW$@OZm:KxMRXyV@Lbl`;d5昙PF'ü1H"!`_1Ƣe!BaʫK 1wJmMh>u* cH Լ)^㠷,ge5Fog4][T:'x! TMd]z=C}h55[R-JB(hV➍gU?f7et̚gCڒQs^kn⦶-}CTF*+%3У)a,DHI$mǐIu恗0uCyq4$1|ƚR1 *XfjOQ@ДTLveSZ;^ב [jebͱiJOXuhUk޾4:l ݍumIQ3D M>*$rR,wF6us\k Q p,^2FjȣWPI&:yj,:aGvVkܨMApmsKUSAn;S[U1 21SnzG:Ygح6K4#5m*$\+0Epe,瓓9Q3rd㑆f,EY$҂2+>fUt` ¼xcF:YY)֫cYV Tԩ>1utqrnϫ?Q}LOIfooHPסMH.ڇ]-)-(WX/Oj(ahڋm*%R$C%g˶m#߽bK =YXw u5BO%e,_qYMbX/o66ص 5zj=Q׻GvTRN @`RT((|Fg7x3FgC".Y#Ty}4ռC!#b OxS m)ʄaES_^?LWЗgQyO]/vM=S/]Yݘ?Ӿ'҆ޜ{5QҗQQȓ,4T,-L[ Uk-󳽜U4:eN_4oگ&pԨF&fgͅ~.eWuV^鉒cBޝIAf vک$F/^=SgdK$Bd!HbJXR`#G_.BOQ'n̪(N¹.P0 Y[fًmFZ>p+YE]MD("H1#64Wꩬ+?:X^=jde+M5JF}*U_%nkBvsQ}NtƍMU6-C:>Tޥ<]l5&hP6ooP^-BwjWZmZ+#C[ Bȁdʲ2zG; J vx]VP`+&bukлjX.c#ƀ4/pZ?'ս֫ҽGsh[Ք46cW]bn # Z=mݶjD]h쑖-MS3WS/nԚwEvYϨgR٬vM3QPXVTWf>KL$5NBW,d >twԶqQ{ɧ)fIw^h*KJ[m]]] |Tf- L 2Ns#(G̱n$vD]U 3S@4 XPÊvR|niZ^h)Y5=LSS$-[bsb j*%9H'%9i_'P[WMS X]Q;U}l 89%G *=?M 5=čZ4EU$ufQ(-3ȕLϹ$^#trnSpZڡMuƭhmH5aH^i =<'U1ƫ6s54f4RF ^Q,bF4ͦ1;T]ZC1oHUn4֝w{_BvLW]ESj:HTz^hY H2Θ_n.EG*swP\ӗJU^-(YwVzeo&+0 e{s.;/)i4=ьQT9x Q&b-85ہ)mM|5M=rkecfRW)$)Mq5EK ,&FWئlw5% gdJ 2R" C"+ɜfgjHR 4If1)8>{!E[m>^en5Wuz&6SmzokmVzHm}4OUP\* u#4h7M!dvZW/G{H/ګ^EtszB#}xbYj]S$8O}vC:- mvigeߜi&6rbMRq$ ځjok[گsWSXkO5K3CpAc+ѻuTyd~qa.F_j />?zY C}%CQ5o$'HoUga;9A>kF}U?D%MdP0Gl ctT:o-%CEŰ)LŋXMc)y:UW xQ?BY4 mih&,4k$(J_Q_Pݭ-D׻Lr:-:#)k u*HrJ( =x5dw_|\Ghn:]Xhd6Hm1rQKNѐ̈<۪XN $cH20st[ĘG*SUX5@vډmϘhήIKOJ@NsBIYvHGILh^Fp3'nY# 6Ϸ) 9y=j9e7W<{I?N@pc_y8sH@ $ϹE~|q-KkLnj=A5(tT[bZb4s'*22r&iOW ?r偐݆;78(F"z>B |Ou@G+09sN,HPx^M͛{_`\;w/t]^LH+ wX8_##]6%EeOk*ƴj;U4&*-ܖ>oFyRxbr'8dui~uf]vMECydJiK-J9* Pf(lcH^6q2s*ħs'Wj 7eXLmB ؠNg<=v4_ow[UG~GGdQh#TGU,q0++6K},vzMX)/_Ғh+/,jƾx U Clï~M>;_tjMQC5Uf ) >e}Kzڃv=Golgdj;I5\g^Rin_ʒQO{^)t]%vmURB5]\a5TFp񼈰~o^K^5_>zG%[U)$TS%oPGO*\=,[l)[BACACkJJ1S,1 %<#JDd;oGw{4dX]A?hwǩ/ٯީ*JK)S&݅C1 %l% P'9;j$l \[ Qт W1||TqG'2A=*EgˁwC67  r?c#%ǦH X $|Fx $pq9(|~GJDvgJ(Dː2IFa5nU5uk<Ijh+sKSK"a'碴NZi JI/6*k(zjZMm3C9% 5*\quѝkmOj2ॺnUPԶZZ]wڰ!xk']X*+Phk]M5,oY8h6n:]@-5ZeE{ +~oogw]থt;W'}!p\#^j+3TZm*ՔWVƒ er1fx[xZ$Eiڕs% EJ,U#&5fXHĀH筫gTUh{UQi:n 3OWu '@r8>{;%~ZB-KjK_5e+6QK( ,"YcJ#19|7.E՝lXj~#y(#L@ΐw%śX$nw^}=q{}SEK(#5Ƃ yijPD,4NIIxȬ2um{w!՚KPYo洧XuՔJId %e fJmNKz׻=/L;f).MD+ME !PiYY^e\\<+2ٶ;(-%*x>:E^|_%" >$vd,5gb8,K7 OF" ,|移phlI㠠$b Q88?hQAfbI'IY$UdGuY4Uf MuMGqGEA!H UG4kX޽=4Y~8mqfHg%`<6=7>OwNinimjtnnv4pS]C*q7&0pXGu7QXiدNi~_KtZ)hMBjhbsW(;U5UKsGiBDƄVM%cPRl5lI'׿<|?*3f($qE}bsWdFolK,SVk]vm09hh5Y˗uȻB@f;?=;r߮7k5m~[nQ5uci!EwD1փӶՉh/ʺVӢ w_MrބQ;!Ktm_ i EđLika" '2C"h'(>A(H#]Qlf\m($Hj"n?m>FD ^}'u6me7;qKOI2{o9ʒ,ԱTGhv ֒Sz:;j7* 8}ZՋn*349nӀQ ~@8_-1ϹNN s6A=E,1eZ( /۵U$+}N؁[@ +ܽ4W* Im2,7V_mCW UGHNLh$!R$Bp8S0yAT잋TR}eP[.j%459.&Z#vepag՟fu hK/U5 snxAgT%\ Sa)'ȀȪJ   rpK*U`h+j̾jh}Qxѵ:E-T+ᣬ0˲H K̀szBw>}ꤾEojKuM@C54+G2[JjkyHBnSazɺ}ɶh[l?G^%$O.O[RVQ> iZF 3NkZkq-Atm4-̑ 2ȱƛT4S.$+4XaB -52IBef!M,4&r( hnE݋ yf~4.k}jQTjKfe9U]i8ĥOh= K맵WDXu5SqHf + $A}Y^6*H^KnmTȾqiEvO< 5UKЗ[YY#ϬQ5Gs+4'>Y'Z.㶑WSigy*{O$QEHFF3|g<|+pl._*eUZ΢X.T,P'̡ PЄV&On-vu;oU.uTbѥUuN g$i9^7KҲzs+k*\9ybslN}:Z{/uhfWTc*/Rkiiં*LIuX՟=Gn!&_Q^lWaݒZg ̆zf bHt2xx#9X|?/ I,s^L`h HB1e2WG *(-lH$tS\2(31,=Ր== 3N ̒<%(!^L ' ʝ>Á|e 2{vi+RXe]"=ƞQSIPLff*ΌLUw6OT ITZ]de'DTwXr]+A glbz /er4q@HY$lc`A7jUݘ `1Cf9V<hebiHrb}pq1ZR"&F3Iۯ#NsFZ\kYI=9U!7ZxXCHQ-'koh]jIkbTA9 A@(C mP+yWd3˜/;߂x!{ozݚB_"Ri)2%NnG$|e:SvEW\dΏ7hTkn/F4$.79e}I}C{=>/zZuۯ^jښ+h0kM41YF6{Cwٝͥ mT;UM3VRq-uDi(LP16heIm@fLt2@bn,U\ee+xن[ _k^vtXi^Rkv(4p,єRB&/OOʛHLzyn\]e:[R W479y@lյrXi۱G~1hڵԭ9AU]Ay^-(ՒS6ɥVj,3Hƻb׽贇tZF*yw{n]mumI;QJ*ib'etjJPdMB2RX[PZH*c՚~pi(TS,RYy=}Y;_p=IY+:E'ҘJwf+J9=UOyg[EdrQw\,I&٘.%lP Z &c P,H;iPDq?RZsDZj[ͽ*5&,;h,eXdejl7$_\ݏ 0:J֕h( #۟{l3v6OG~Y5ȃLZ5l*C S)ĭLޠ,*'ԿCeY隍]}Ӵw\SaD樞% 3d GO2|>V433H 2J*tB4C(,`07!hoj].^NE5%:(.5[LCҦ1C46Dxq}Z4ZSTEX:/LmG@T1CO^.U-sՔi-RS)F]V Az-M(CrwRۼU:3зIjnZR[lֵm!(dz5]$USj'wp4`fw+/jdTIi&س>gm.M\&Ϙub( Q@`c /aU5˝D*uUUMkku"( YH΀?KquiEږYr 4oYU4,*7*́:RIl41X4,]x}!j+ KTJ]Y-`Z^iɦn z^ySI e\E؝CW2!;Q\bvW}M!G{*#N[G.~RTˠ+ *,Ө-` ŝ5 Mdaa I ,pPsn Ks0ѩE1Bp>GZd"؃+n7?M aZJ8-{LkCGm`R83TJeFN`q|d㎏w-A9+7=peF\ pq3QU[S -%2jj'PBdWay $s4w:45֪%t4󣰔0d)n祯~6j%HX1LY@?n@ǎ:j=ƺi[}+lXiD@_VR#0 _RtF֚_Gj/T?i QS)#.2Fy5zk~mӺ.JUbE-te:ңI!,( Ufؕ( #k7kQq}a Z\6˭44ˍz-Q>j$8U{R:MsD,7V>CQ!fTT,w D#$[t5uYAA>jiv껵W]G]@URG-#%9E<-?OWsu)$IcӪBH*NvaeV 2; ^.PG F_@.t$H"7Y{ma@AJwGk-#{JITQV#$}Y(89^GΥH>slov}L'lI%%jO`ĤI #]]ޛSXmrY횺"]uCJzfvO dhA{ooArԽG|=m%v5 1Cn(;zJ9c 0Ef9I.V8b^y]gIE @(G]&Э5Q*dfpeF5d7 =4>*9pFq_igݟJ6 in|~}H\%?}*X@<:v>a\U$.DAhb l`9oJXixPrCx$HXл)W9l6`br$?VzYO0mF(ڬn>r>_ ^j!/g!r ߣ=gE͏h\s|x-<`s6;sf %q}㞕D%_b`.Km'#'<ߎvs~m^zqW]sqc)S9#pN~x)I#' B@$0s㮣Ԗ+.2r[ 9yrcBr[v[ Ip:n~?߷1evRr@Ü||zNJm%>B9?9=6"F\iPvFy::3 a m6KLFPq3уQÕ+F6I'3~<.2*< # 8ȥf@Y1syg=@$JO29C烸'碮޾0ૅVH2n$[$]SCHrIH_s>E @_oppAld`q1 dIF9x'#~W$쐠`3@NI+ϞSk ݕ pqD0%JI9}=)K wqʁpG |8VUVKnB7pAڹ9G$09*1`¢!1@0cv=<3eCٝ8;H>rKm'( _}4TpARN*TEWADol_ܞP J;l4ڞۥmlTTU/ O#B'f$7g~(|RC"{ag7fuzb$cXk{͈)';EԔ6n-5q>>(:ܴrZ-ɧ\k棕-T9VUA ˵:Zsצn{mIWREJjUrV$`Yu 2@uHnhK$Z{z~x.TQVgꥴm1Q:V,!rd- :`PB,WlC2 %Bhhpz8bJ wY["~wGN-6v2?/UjU Rq-Q9o\5:9{wܛz5^h+쳹Iced;rզ"ƊLiJY*IR *f\eMZڜHJb,UċgӆZ* .ơֽ =lUV5PKxkɸlj#9rAMڮ}mX[ڣ=VY(Ycp>FO$<^OVVu.dV#IY %5&ja ̲ ;ަ[KeUo~ڷVRf4uq53:ΗQ };jRfYj@ ȉ 4йj@P:qG<_V57^t Rj:ScI5CQ/3T#eA5VSQk{UBqu%RJYm)):M .e^')EyS4x|YƇ/Yma:B A]e-sB٤ӥR촜SAٯw7FͯG?kUUq]fyYpR8JR kG[駵r5NԵdI-7XZ4H5KVԈ)db,E#mQK{?O;-ǧt%Z_llhΡ$UֲH%JQ U=eZkHw7F][.]kf԰S RRT^Q;J%)B4YXxIdIb's |3"Pг)A(YaRQURګM0pbK5s͎ݢ.=AѺvե=5(JbjA쩬iM/#:9 1i 'a8;먯#Aھ1Rz=/GuݸҩC, V 2kDkֳ\*uE%ʊ HN k)Zj4,aH7T]KMF_]6j 5h+{? tl^i禭*zeSnG8dd&Xf6ܴkڳߩ4ަ$+վΒޓDv*4*2PY4Mh>{ӪU+uZ%뤸Qz M$0;}Q,7Y DzEvVZZH*V[U}3|=^Y}!WnՆz mFM24D}̲_l%*IwdybןT]7j{a5ZP%h}O,{#CS^ &$ [}`k NUT軥%F\}+T^)vI$UdyYTRגX]>ɢ;qiKDi R.Ԗ|45چ<+ܬ(e,(WrF?_.yQ GBJfyNPTiOE˚Bh$^ZCWP~~5Vںghۧ4IG,ҙkgCUS<#@P=u n4iu|'DuѶ6C߽ {&9$RTכJisUv{vԗkh."$ZHVt s)o$ C@XvV]dQm4;kfy5DKuJ:Hj*%ūGzfS sx΋l8 HpUL̬trd0W+14%̣V7-` $XꮯV껝5Ij L0Q@Z4ƪTu&[5]ʲS[p.B-cdtTAob7 /LoMj$OYM喊 u.ibbf՝^Rw+x[ƚ^Jc#V\)ӷ Zt5H%LTJ %= tOo]@V+EQm ¯MkpS=t@̐P0|eΑb\at,GUDVV@%C]t/˾Y#:62QA-Qt]ǀ09uV3O;U 09#d\xS?8#ǟu868|ߥc?u8O<1c csl襍P**rN[>@?9>z1q0>~xNX#x'|# X,nrϿA`灟< cw;G|6Pಲ~:*e_Q\܃dys|`|H7s~x#G4- HPWh ~1ұ/p7̻Ws 0fqx"SOo4DJ=TJDZteK$׉qt79uqrt }&nTUS[FHl` O^ uc#*;BauRwc=ﮚnh}¦rϬR+%m eb\ij袨 %F[uW 7e#x-u'b#[bHb91ұSGqBōKǕ-t^ZN}7u{Q[44G4'dPY6 aZG͢E<4Ʀ2rG<0^ʦ]Gl; Z}2]+Ǻ66RۦHV4e窷+2/k+_Yw5WSj-oں }6M%nQs~:iij|;=29cPO]Dө$:̓ZDf$uxbVFrFt6,uuzkɤԳU^nQJaPW *f=yub6*`NPsӯ|[4%@_4M{ͺya*i9%0,ά\ ^Mn㵽utӴ4]m TgZҡ_HΊ"VH5 :aBtm Uһo޽Mxպ5Ytu;zd_9$c:%J$qbi\V ӥ4&Nikj>֝pnj*^Fb<; ;_NYT_&z~z2uWb,;5ݩ(6Hn:[çac[keb"\rzs$mv dZ$haWf(| $qj,ZG@[jʛMM:fSjx=ezmG uۀ- WytێwC]^mԋUI#L1잺#D,@rU:- NWCܝdCIAt,h*67hbd1TPz?P{}H۴zoMd-ʕՕ{?LtlxUGY&S]@7eL$D0fQYT#6$ѨH#=dRҚAh߯ttzbSO5}@5m̋(i.u+ϻ75UMMV64_*r+.jć*D)}1_g~fRlW*4+\5TWYkLl%U8#wZV\wKZ fhCOJgzڛOD( L GrN:&yKd|62̣DVZ'HX6m} mNtnEvLjo owoW]or澒Zm IX᎖c Ltg }pj}#b&] J-LW*<8F0*6_N}_wNQ货톘E4zMPݪ)jZz:j*7buRa: ٻ,QJAkGYJںI , \|+u1$.P)Ib:1XwZ1ub| !pe64Vp!F {iat,,@6$a#2 ^Bur1[45-hgZ 0C@./o2Ɣm db%BKho6d;[]TVFԴ5jc,l&B9GdvƂ=:S[nU7-?dOoSW^o_eγD&2m7C2&i|Pd*JSyļ?2J GR1 *oፕ4x]j6vO}+,!P.YbNQ T7")$;H3<ۜ%1I$|*JuMI_馢۵uKQ45)W²HHup:G [b(Uȉ}F} "1pFvbs'=zQ?=uS~L.[D\ENOMom #:i9&y$2I+a~evG ): 7d51E-myYv)\2 +FQYlZWK,Zb n[i e9Zi%T#<~)[95e#;e F/@*'sXlGRUaƙ<"$n]VJi*ZP'Sk-!:RM=mB9Q"1@ ChS[VMS";oٛM'$;4+M%f3E% uAvSCQe}voU5Nײ]*rM9+-SG!cQ}lș,&lUH =p2z5_r sFZ$?o`l1ڷs$r}8AoFh-pEmP@ Ơ urk~JK5m&ɐH0bw'KW$ ?9 'h~2GtjR==5cq0۲8EHE9>O ~0V?0[;0 '<qZW&jn6դ 91V۪B1$]V-4@Usʪzo/GL]¯DD8Iy9/ZKo$yAi upSHb8 )-IwzsolRV>nS=R]S]W}zh{GbꀯXQ}Λ`k LRT]WY0S*'j`IB"$mv +pe** fSK5GQM!g$Ƀꝼi=]>!`PX-چ %>7ph[X*jiJ=䘚P{YVe] ܝ:UtvƱM뫶]2vHWXqQ\X)ph`*DJ`،9UבJ}QHj7JFĵR\#R\13}LRo؞bH!J5}P=J[\sj˖XV1 Ƣ 릞k=暲j-UE$gd5HY/iTAmLjm-iʳAU5$qգI'̙Xo|VW͙W%G嬪̂pE=I*ARŕ*77]WB3&ػ (,$,i +;FՍqݴU]ӒOvVJ !jDu!VDogP=D\p=u-kmImۢ0ū.d j٩utxm;Nx;_[:!۵% E[jIK/B)>)3Hm!jm:ptvGsN)^nU=u--CYB0E*]OEzԗmQjUj:NkJKuTv{bRh⾆ȬPC*t[Zm<)`ew6k}jcj(chy q@%2yܠ("9+dic|1S6)sVp0BeYgFABw`Q dnnΰLVUji {wD8T6*}/xZSuο{[1mbZCu[mB}O,v%>)P,H. @ұ AXROTǻ ړIح{*gVMh"T[i %ṩh W6[RH QxN"@Y @k8JjI?PvˢtRBCJ+&^dQ2,X"2TģufZZطJ$Ycc(15[jwr/ϡ4!YܮQY6^u${ Hf j˧bnoV{lF*fxi2fyȖ~FgCt*bK M6v#`,i  'm7¹iY 4h"WeȈ*0;6BoQZ[jI&+T2ȒI#$l#PC0v 1bYC }-=Lc,_TC e53*'uܠd)exaX=4îE> \l/[ $HWfcQ'ҺɪfMFTސU"iY.)=%EU<6{ʊ:եs{trHdS}< tZ8[m#!/S.KGIQU(Q!` =V:I[\f j_X4g0[g9xԁ=\ԭ%u(G3ӸuG>1H+?N4i=O(w8&Ă)w餫j ΀rnwۑ[5W$HAYKOlXht56PHuc3B1$:b*nYmRmIKc7HVhi"V#IR檫+t(|zԶuq+VS_+ݾ=*=D(kd0K3F7}Q$zRRmTa@%(E-u+%D[hQȕY$lc1Ywb%;*](]b? yhYA\Y؝,F{,Iٟ@}%J|34o"U@т!MܫrShXp[@JA{æXlǪm4Vh=4 G^וY]08}m7t;_B%HTFƘGv]Y,'yKܚ6H/3@G~{;o 4ߺX5uk^Oi-c#9[byMĐv$mN ǜ-Kdޚj:M׹ՐP 345L`+$SѶ2w{p9 <8 1Yux~]XY 4@?FkfăoHN ngI#D`<x<Ǟs#cg*=|Hp<,YcE Ko^I9όNq֎+`ѱnU$9't$b$<*@|`0sIáFb <|33!F$A8~?F 6t7m]Oe)))fSJ JIQA7P[M,w u/k"Vkڠ(\2nRlgp:HIy_q< 嶾WST"4TN$e'4. > 0܄.ΐƯ*˨0Gt 0zGqcT51˯'kZ96jVsӱ\z 8'Bh>i!SEݞ/t$45։ef5fY O9;ߚ}#GfCsm-i\.卒qdXZP rvg32Nr00f=.LQf >j-)VPHu,GPL5RCrT,Zo]?w5,ƭk553S\Ԕe]4f(UEhj}]Wtj,w t6&\䠨⎢>/$:S+FGsjXu]?n@mBV5jdd13SY# $g`uޥғh]$\M^ {,$}Md dH$+ LdGBA𼬑3)̹i&IgrBf 3/d3*QE WUCeT,4Эmp+(Qa aI`ppp6HVPIݸ$OQsa}L+)6wXP$z1IĀ7 =r1 }ۮ1+2L| ,s?=)z#SRFN8$8N@'bBoPSATZ='q689nhs=A뎜C^oĠ: ꈮYpW, ?>>zP.,r3A9y8QU-' #$?*5%i.y Jc>zJ?[ҿHF8-<c*NH`~pxRN9y*Y}EMEbrFXd3뿹! @B8TcҠRsקaCWAMp8} 6 %G'@`~w>W] x~q=D ?O=r1 ?͕'ঃ}s5Xax'Hi8`J.988qqT*YHR8 8Z@ J򠲐#j#|?wtH貳d^<̮$'+&x(H*qceTHnm ^-W BII`!`rIO8#яQ@pۘr[6vs5IP.y\yx ::؎Gr~3=0ʼnS rKgpFAc8 !A9o>:iZYY{fq g:=jT*wx, Ao< y9d;@ 'yЏ{} ryᩓ;8Y 6122z=jo4ryRH'@NILXXF2py#~Ap2z2a.2C`7Pg# <O zT>!TbF~ F, d?nsq,̆?j)$pNGpLJ)L1Hf~s+%r@nx$?q1&W n ?8$ ~8P|+^ǧϱl\FNr `Xl;@뵜Gフ#~zDǩ#2$ #?fKyU'; 98GA[Ú>ǎ0c2$rz, ߮ZUux Nrt R)s.@wm8qB|2 $?hvF0adJ39f` ?RF88¯.w9oI:!;PYm|xA\9v9Pv$+$1Mݚm{Tom ,9f dq dc?9G\ّ9n r<߱ .V5ϴfLKǁe20['gW>Nf|g9sc箖m[*}98tPvH́sNf\7.Al*^s0]2ʿ'|xXy^Ui7( Acפ ㌐ 뒠 ۤD #d2Urx1wJ$#=#T h!pH8# Hᱞ<O$>xу "yYK[ _9lsQmH#p B>2y" e`sLLHJ % F )X 0dsF5R"8aT%nj㢕N3]8lsO7o n\NpO#?'EFdr='FqI?=pTg,䬁 9C 6&ݻۑ@+9 +! C1G\Z͐ڥv3sтFMVܹPNcRdFfL8u Fsϻ?tEI;]sB@PFGT uXPMaGovR-6Kl0O:f&mIo^٩i憺6ގđSd^B ,23)d$ iO~[{ڪfi[h*%I'oJz'Bҕ\,+֌:{ 7© O< \}:oQPloMd:tj6ݮd-v; %=O㦎`QFTʊʍ$Ϩ:ajl^C^2y7kmXc(Kb[tUuwt݊r-ʴHO%L$FnHm3a&qeS(O5 ]}42MUp3+!V؝d,y?30F,iMEJ蚪kI}SK4Y2+We _ ٥D ,-[JoC+ERXmJ>RIb[4QJOpU*UȰƶzRL޲+4f?:Sn~;؍-M#\ZƲ LhbKL8i;`{ZcN}[},Tצ\GQUN5JyXٙ?.C"zQQcUI$JZU:^]пUP=vb7p((h"(U7%8c)-)1FZ)YK YJZ4ehtv:J[e,PRBE"HYzs30efiqa]'MCzjIi[}Gn_J:Y\tߤ?{UA-wSSU]VK4VZ#dy*unaF"zxX| NaCy+%2岊x,aI:E]"1iZ KnrJ૊ er]ZVV{C*je` EY&Q0WOTsvXoF=m!BJn6&fb7SVFHm^}>2 g~@~Rd]E+RyojERHUXOF#@Fd$夑q#9pd{OoWij5inTFz4TU,tWܤa܈43˰bmUWSUGgbTrȊβ"j6$iUFhr~@@4z#_^^zh+Cf:G2U8c3Q}ݒE/ѺȲ<{Puݾv]fAk+oѓE =nBXvREp S Ȏwu3N6=/orj 5p*]xZ*Zi`K:FfST%f:$U8Ǹ܎>|WJK$lj(8dHURYT;BtYEB" 7f{5m?>ݽ~z7M.[ovN֊xf PsVʏ HH{Hag*W'#oڝ]>ֽj=oeAVv֚֚:}CURLq#L}'e_T6Tv߻v7LUiiQSk3cX! %) &%CԱ3D )XlzX6IXVV5G*@Mc4D`g$eGBaTc8 - dy5P A ' m箝vPd$rG8鞭_ y6[ib0p=#pOdzU'cJ ~sG|y=|wgOMW gx9I9z>2Bρ||~:$ Ϗ?ћLAVP7$< FIn <' y>z0`F1yc B7T Ox??O}#@0K `.ܶߐ?#玈SQ 򓀹V#~W7dbY|s;4 ׍hQj(4 H("&)$>"<ܣ%!bPzʢحl F W[]ۭ-eض`|GO=K²20-x;WWhnhh̎H)NNv8 ͕I˜# Ukպrɣh/")QnU$3tdD@F|fG*]1&]$Cf C0>bvI Af0H]^+ƒ^֑@)饍E] EQMSd@DI`:HR.]jzŧVj${`ԺLӉQ`zZam6)tΖPg+.멯3MXƠ+W,=  &~v8OzsuPɱ41%qi$h0ess7K)J-bX$SX ؊0DMJwfY r ٯj{MWj`,V(3C%$N+JƱ6}/ [e-E]\J TPY+c}]wwn %)bdXܕe F&YUYTuXϊI;̣zPd#; ɰ;)Xera:Z[/v o˶vnYEOY/5i&UQfjZb(P}wӫ iO }1$ p8뀍%8Lu#K,XgG'V(9T`ܥBAQv4kW9 V,A܀9 q8"8UDD♙ػĖ'O$~$,ȤM9luk+<45a*>5IJRD Ӗ@ ~|8!u}Qk CBu V2',ь`E,(gb9a y?$qԭwVA]F8hqnNC CIqpb?"uCcpGۯFe pi NN1O-:\95V.6{%!5c2ᯭSn( Y$h9꼐R8'Z,PnaK DX,e@NcbLY=9h)$[ՏCoH~u*Nv[).ީEd7 ?PtdVgBRw6m?ܔJIe2E kb4 )0`(=DcXioi:z(!,QRCĨj e-շSr-M4'LQ63πٝ7uˌ'Sk^bb9UY!T.QE#}oe:ж$t jjWC(R| _\.>Jvm V/mJ-yDrGF3HSqqIqC=T|f1#_ͭ{_ۈ.TǡuMN\aX(*#x9=]:exiVVU`Zckɍ#n{V+u iږZHd5Օ5Qw8Y{zR\-V5e@j2UU[w iOV.. IۺfFxʦ]YKS hP=FTmۮԗZHn6kM$<3FI 6FX ы0 P0vz;ofb m ڇc_  -_dvuKesPYgx'q=$ITӤHceϚ /;*-^Q$z,mB}@+ 4q05ZUGf>}8귷wQ-T[E֢ ew kEEVT> ݞ +ކJBwe0rZE&W*06HLaY8#`'qcES#X[y8\ȇi`>K=9\sD2)$ n>:0`vRG?V(28# s-Lpޛ F23i$sу@dF$ꮲlB6Z1`)RSۍUJNGXVATN w4W`5тAFe@q9?gݛ= Q  bx޺I(s P+ʫqъ` ߨ'Z$"z#~*1JkKՕSٴ~ZJI-5ErTqD"Y],iWw{5? ib֒e:YB8 I r ڑ)i+{lIZ-tQiL}YRgϓR]%dSӻKuzUT,kuZ] =jt` <0 usg'$\z T @jPE 8*ٸ_Ro)#BO}j= u]ǚZ+^*vzJaDOX«#j&СHns?9WG;[ƑR٥Ӓ r&PK*/ט sG|#_/(2:QȢC+#3;wf6:`K#&i??U 9V;c 2*A$eH>THtzEښ;0VYZ5OKI% @WQ[+n54Vi*+j"/VI&4X3pY_ߟ~vZ[~ԺTZΘ[>ѥ*ډc4$Q,>;̤2ǩy2K,",q0AgH'S $7#E:)bΫuPxɡgC\B}ڮ1JC5%<uFUq.J{YN r E'v8A0c̬=G\[N`*O?>?=)ʋ w## ՘ qcvI8*01w ՐpIp?~l :` 8 !9q3Tm!i>TzB@j&I+LJ\11[p{٬k5ZV*xi)cf8!]Iv Kw;}V{"ީ"X4ΔMq?+<Ң$,dHa$4"(JdUMJXPDC;hlMHԚ>[_O6x5ٛ5%xn&)oj*5 ],lNgI) l֩{UH*+h-vJ%U->GeǑҕ1wC_]4"]/V]ۨWbSQ H+x0SQ<,ێڝҔ2m, $™inX"/`Vs!]RPX7:caӪOp-Ǭ`8:nիlr \Ҟ1},E7ʥGaMʹS;oj B_=FJiM7mI]jZ)i*Q$TjT2ʀNКrZmwWߡ h"RamR~7)U'~ʏJ㪵mҮtQ bI?K@OJQB<g C!fC Jr4(#Ef6b,L XDFvKn rkaYЮ!\# yH|}$<\rā=c>J$BNX|ow8cs':ѯ;PHc&' A@??~YFR7` 'W9 X$q9=+P#$c#p 碇{m`ÂTFW 2w`'9\*9d XL\>A`Dr}<8F9HܻFrNр(tlOʇ{0aav( Adۗ*-bF83QA}<s1~Rz(7m8pP2q%21ϼny8>:eU|6尻X77rU;V`TnnA$gzoɑ7p/0a9ѢvAT*tJ9zLt%p "Y;r c;I y>:oW8;Y|8=vLX`KT pA\88-q4чWedzԀ@J䝬|n ' {^lںUl;RsRcp bp1<ѦffpI1$ze$E79@<0 @`p˸|dO4;"~IF1qt nVX뿷~[LleB1ys=)8?y>> ۦd;H#vIYj$&0[P?pCzV2Y0`c9#?|wT}8 ?|yLQzb[Ǔ<|c$wUs s g!`~s z~=?Kg|^wg98]чnI'1L$a`3JU7U\qrOkk'!N}ʼnX89=t(d xx17=KInWEe8<|*Q$ qC!\ 㓻'n'2:XZI8RH$gǞt#pbn 1@*1<|,[E ;aۆ`9܃H0ca,G#)0eA% 11zjrV5#YlUVe{X' y վ|XsRC a{`,fom( N2\zE]UkN\]¢BBgn9,LB,9?aUܒSQk-;-|*:rmβҺZK,;R;\zJ14|Kg*ÐEnlCQ79ȐFO[I#7 P!}8>s388vpRd==1ejS@ F?|@9nzOSIhdoAdFT},K9Zr7 MltiPM,*]`t͡$uO_sDD՞:aZՕD.ʆª&ޚهubbcERL*Ȏ{k8xA&G MlĞ  'Fj]ά՗ Qp:xMbicѺzZ%hs l]%)Hwl]nпQ^i=Ml:1E.TUw >JK}%Q\qYjN#}Y^}0Qލ)!ѕIzKQXt5Qej{Xw7)"biYնkm ih+ffDX!2#+G+eY\dig͚?<`H+p,O.4:AY #*唍֊$wD$hPHUm$vKZ/-GpWY uP$9@(Fpe  Ԇ)jm8028xHMlvEe,44y}iR=8Ye r}>:|U`ۗ!+`)P9PFK3p>I5y5]r7:¨괁\<qGNz".Ut}^㢦i nQD'a d$j2rcW'q3:v%hUQKM3[ᩪ\Uhݣn& .X-JX/St0gR 4桸 FH,~7w_Q{!xW;6/r;h5}(劏Ujep%,6[m7KNHi TZ\i_OW^Jl9`W"3wggWTVSjItx++-%X-a%f2HU:9bw2r1?:5 cV  ,$NǢ$|DgJآl'>Y9ڍ?4ӳ^{u4RM$6郳;`$308vad{{`XڴoךM2^/U6(.zDnUH*evQbUoDQd`sOdۑ؆H QPEAX,TtbĘ@,F XO<%ŐԀyI%]oO۬m۶3doIT.v[_KuL՚OKQ5m6R}Y%ELHbHXu72TUX/+Idjċ,Q8ܡ ! MF|>mʮI?%N$ǜ.vF:_Q!E Q\FNI$Zȵdh `(о~u;Ivh_OU{kNx}Bh}owNwaMc뎙RXhn6MEjxcubK.֩x1$˶%\f#R&4Q G$bC>qj,ymF<2Z G&@˰6i8 d@oZfȔcPRG TdR57/Qe '(VST=X= v>QjZJ5v޺x YOQ,e_c{#Z>Kuf7{*%PZTITUpG!Kh]RJ`":fH!bxph{GL1Ijdq;_:{vx䩡Z;LA;(I+1l~t~{mI5\vsT_a;]'QXI=LHw Q%]|tVe/hiDB5QfTSK#g?v.}5h1}5-eQάNj*Y}JGpŀWyW*WmJw |ʐ1h쩱Y]娣95RXT/w:fizk&Ԛ UKjіU%Kmu2fp=}ZVi-2׻iqE%Ji8dahXVVNA<ddw P*P8O9ArI([@]ٜH#KPi 9B>$6y-_EX*-.0[hۆmyW+PAv+uV/E"MLT-PIvLВ X~}/pg;w;jL2zJJʑ*I>j?}kkƆҷWWWzx)R%oO#,~jIP\#%SҺmJF,eAiK\bݎ粩D[7z;dRSiǦ;.K 74 kJ&e &xovM ?M;v-G-> -¬ {[ OԪ6-GwGlY5ޫi/6#tZO"Poq믭֊Ժ*ʔ !oPMa򠢆W#5MLfd|j)u32Nb!s TODML4;-XI+洽+)'Fx,pA&Ww]톖-(i箤٩,pn4aI/O̰FW!bt.88<bzߡK޷E/h>:jb>d xWR?ӂ#nD,S{*y}8 OA||kG"k$+FqN>A#=Ȍs|zkPu}vli4pn6ioT2O mlSV_Xf$""N}6Vjߞn^Ŧ~ /GGm=ET+7̔bQN0-F@'{:b5{Qߋ\D{Mk=ʶf-c[g_uV+U)dy̖DL ,`I'Jv xvl/^TM%KiuXv^oik~~zbj5\m5~{;mڪǸuvUu-tpO`7@#=?~1_A_5 Dwvj딡 BɎJ)D*Z]Tv_TPt@ٵS^K,tuU\j)I=FqaӿJ?[*Tk;}T:ӧT(ԇOy׏UK'Q33;s­(lk-/]ǟ4,I)Ӳ iq2|RbuTh rj`G%@ջe*eqA h+nW[uj%DT)M%#D=JjMu׶  6: ϩ (`1˨} d՟-n(EVV:NkZZM= )ްK, E |,A,(`C'$zx efg@K;3$$ rtߥb(4z ՛:fO.X ?mqpUa=\\'id Ajav".U@TQy#ECsON^U8D q¨ b3븒?ntb*+XuB/#OG2Aϵ{n0:59!7hԝWǃs'XSo^3`g?}7q;}?c KG,3c|uEF]}QiՕ9ko5TՊ;e+##ml1Ǽ/Q$9p21uP<' q () )1?+*HlFSD6A M0 l@= n{s{{.ɣVs7ߚ j=Sv zP;ኜ@#q#n>2@kTA~; Lzz+&e2l[mHM$9Y?Ӯ3Jw,/JjFį>Ň|bI:M?Aڔ2X"Dx4n7N)?j8UVPwWRw-%dTm͢hnǵ݂^C0IMc9% pڠ8e;1x? \Eb y&BcB u;Fqq#d'p|sxTe8<2<9& w"0"c8?8#9HA$m?#19R ~pGC8P%P@ ʞ 6$q,MGǻk ]O7mE_oY]( P5umyXd8Ts69iZLχffXC$tdT P2I.۫2A"3 vYF`X NFzUYY5S]4& [TV"U}e֡֒& f)h?VZ[.:[Rij/g&Zӳ@bE+`}ʗt;y*˪i'lknҭO֢b-K|3G STϽD"K7@i;}O} L;6j;+$QUn0B^EcI40>'i2 pAe]*h `իQav`d\sͥrOq~AVIo,-.9r=@pDB18 te{QR3O>ۜgt$,h[],>^7LJ 6p8SZ4mץEe"L_j5lrH#1bͿ$BaʈE ѠsHc@3\e@ϩ sz\$*CAou%M̬]\6:Q}W$[>2HPXCO$3Y,]1+HT 3YUm|FTP2SA9<93/!1PP1qI瞑HR2q.B*v86qnZix,AG;c 0/#UD b8-Q~}#.NNHdd|g'p3KkMfӒKSsw-՟ïO:5nQU7QdX(p9 Ox ‘u7ӆE.k;SīaӖLIi-C\8 G %?; rpBK#G~`4 {s 9Ϗ9:JA\WrlrrG':~ cOIdٜ6 xϜy4Umbp@,@F2~2zk|.$ d9pz8J9 #8FXg8( T$がWۻj91\Fd-bAp9T wFwYFpg$Dc 0$T 19tm?~ _&ՐvUI `3J?H#q'q3?zmʡكF]U$. GqF3G+2C$=p9$+NYr70&0pv=!~z{lOl7#YsP7#?JmCJ{I-`| I()6m9PB'A 3hA! ˌ  ( Nq#UGpBvxώ 䜮Fy~@GFC{)x?8`ÚLmlx0?oG D{Nrp1y#B[;cJ8drf2{1G ci # 9''3r2c0s g0ʨ68lx '81I،T,|30~1q,΀ @#'ݸrh3'>8PټCF$$g|* #,$*J6O IǓ䞄|Ypd˶p}ŹmnW( yxa!bR  HۂCA$mߦ{ڻVMloCWr8PpG H8>8c<,x,}\>9dڄ)Q̸,rь `d&dY>[u?=9^~qG?g7;-VDe0EC*33o6˂ n^i'H>] x㛸ZݦX`Km+2 D/UCgE@ Y {xKTQU05TJĭt:+0<}V[>&qD )۫-Qӵo)XeF wPcrMGtFd,Hh? /SxrH"IBP(/=ɶtm;14m5=5-GhX. -5lSyeʌ "zNԦ8ղ 6H;# W6zТ@6Y$7 .[lZSӫ]-u6kM}9 mOE MU}Mu/EP1M<Pl=Cbi5WkmCfmq=47=},/$r.JK+]˒Yܞ]p݆wqPwĈ4=iZ"B1Ij|sCrH PP QvKl֋Rv^rvdYfޮqJ*9I<88 &BNF\ʠTs?"Qcp;% 0?I*A d ?rG8=) (@8~q>zapvo_$dmߠâ *^@(w A$Fv<<~ N1Ѱ-'!FЧ9S>N0i=9QB*js5D QN0Tn A` Xd<H "8PRW}{vKK[khHaI[kZڪƞ[=2RFB)F$T!2I  "ǵH$Ac_>S{;GQAqT3btKlM,Ēei4/%eպRj NVj#vY* ׉}eIy's<-ZWz,,y0vܒ`cGx`X˩k muYKFmu%#y93zZ9eXU^Z\a p!HZn?yە]L4^+U D@d44 T8YC?J=u5sl֋޽KsקiTIr5;ZI!VUI?1O㹃>T唫gsmIRzJA^I42)f3@7a]k=mSQMf6 ;|O k 5dH,p ~%/ eiKWmFj]UNkďlT^4 GiVXu֝z/nP]WvBPPEIC ũvkM!YۺySM.-'QJ7G_]kj֚ȽxD~B,shЬ" ZFEc$fMugZ1+`8&cmfE]n?S@]EY%-nIQ<4jIu,w1rpMmfӭ=7w;q 7}:fwGTHHc#0u*hlr^-6 kj>QX^EKySfdh'**0(4ok~%}3`:P:EijC=Z~TPo>$XɆ[O0<v v2H UW{YG32"KPMkMtc+Gw.!EAIqJłߪm[ ZLӥ ҕ (N?-5%1 pmmqkVV?3-&m]I[eеNu:힘QkGjW_D}2p)m.eZ/־WI-tpQHjkͮHk-IJT\&H q+/,ªsnO8Xkk2@jhp[ȋ/&I.zҗߕnC v^~n7+ Z7m{n04%krZ SȒ5-h҉ZRPuGі;w-Z郹7;tAw{MF0u*GoIM:JݻAcԉ*4Mf!FR-*zHJv?=3FRi'yydyX 7Q}".,2u yjжb7`BHIaM&(_ֵE_ހ lo]Mp5w+}fz:= p<2G5|."E n@ד5:1߽jXiuyA|tkkz7ZCTUcqI)Bmgoҝm0Hl)hk6٤3!p*]Pz\IN'4n)֚CJ7 )"jmM4BY'Ҿi) rUiy"uL%\0dVY#3V` |6, AgmM Oe]tҽ7KfT4pIW[AOKnyȒj)cۭn&1 2ӽN-FGBEVKܗJxbW8!B8v]C=VخB(/W:HZTrMEK\&<ލ4QEeH9RA8A)X#20FKR"/&$jRDNƒlYB('[Ǘ`$(cztH)0AO=NU6@碥yǖa@ 9r7I8?ɖ0 GVR r:2<,X1F`0G~:oӝ6{x2>'>Ft)7:K]KQ]y\j#[hYfvU'3:q#.m s½æmTkU0 mr]Qz'KG_u|Wn&C\ ?g傎hUS%|L̉JUiid\&Th3u7W/GՐ7/vaZfXhnvϪÒ MWGEUytCO =ZR[mU>1Ucپo5Ew%5ϷmqvY[^[P;(Y0/>ζ =M O4v9jbO"ro/fCoSPT1tҺ'OhK66ŷYinG \ IY2T9;vTeIZewvU#%X mz9wB( R,v 4zU *E#}3 ĸ—rI 9U sLD!#D9Vr1y$,TFTs,@2z:w-W;3{-SөNw_wk]HdPXgEt,(V6Y/djTkwP@ݰ 0"@rA8I6@d`AWklvF9 O d1o .6# |qnq_wecs9ۜs7Hرܡ,j},Q ^o#>'%+#sgqF*d9>NqcEa3(ENsF31:x'ߏ j.o)6=l YOHc>e;p1:^]Qa}{~I  Q4C8cliܻe \} X-ꋅuMN+#:ueh'qSw{k]j57O.sVYIxTeq_Aq9Tp@'f7[Vׂy="6]Thh'd㟏uWHDvhji/KZ5ܪ)x㑙qUQz’a*!VχIQ┡sc?љY\taj7< ܠ,_#W$om_z#VCK7mms?p0'kp3'gg+"`c烌 T1y`Xcu䰝|m,'p'^xYimrx>?nMR8' x[$:)ۃ#Rr|Nу XrIp< ~|dmB?S<>sʀKi gzXH.99,@8f|9?zr! '9vBH2m$݂ #8<1!љXp2#|;s {Ry91/3JW G/#|9 #À9@osntܥ-#.yXr]9'('@v65D ;qvOb|5ח:7b;x#cдҬJ,wnPGT/vtRkie]ꑤe/$sT(ʶykzwZv~ɨvwsITTӲfJͩ.QH/z1d7L"Y%21uwVw{ 4 ܸ`G-tEqovi-s,Q9Q1(ʦV̰$TW_LW/!y GL""0jXQ MJ vTWTi?5T*顢G%/!i1Opd}{Ni+5e\w#L}[ i;i掝`_=Mՠ}V+ lXzK3z¯+QK25 ܋$xEC<yuiJsl4P[Uި* Ĵ5챣*"f<*d98,@Qe)ig5Gz>4vv9iK%ylKQJ_溻02^ 5w]cʲtkܔ3}kwwPdFE;F:ndѕzzNIUMkL+Wv5:))1>iQr B 6$[ sM]`F$F̾QϒEdB^A\>ҊAA]\ (N-ҎoFz_5[s-ICE6g3`c=KmhP.WKRQ"+[{_9S1\ Rݾ`nU+Ob5$p>brZF$`dXW﬊,wM ao(Sw>0R˾'04tg" s"X`yXr>C"EƤj ?(*Hv|u}4vFo>RAj[>.X.UҗI$Ic$rڿ~inNv hݽRj c75S˶Z:xN4>EO4ՊץŲǧm4 e8``3Ѣ5E\VJKOS'G¢\E|@Ɇ1 g ClbyN1dҀg`Fl (##R;ve dҪ2]ӱMfqZuֻZ=TF* :))h`gRpQk.>dV[앱0uesPf1rX3r-i{uUVf1jkzp5TTAU[]Ji{eNYiVHzxbDҖp0n@X1utjI/װ"].vwm*@+}PMn:9T!*-zSGFFzjmqzSQfΏh`vQ ]ꠘ2l Ǫ+^Ki(dKjS֫MqOEWKHOucEسK,f(="t{53I4.ׄ("H 2+cY8gBeO## 108 Oόm<~:I&UEݴrpsJ؋{k>f`# ^Icq2Nj$RR2VJUѴC ~35IBQWAX(e]G1ACHc*U~=\4QXkowQW\nU).Pj&KbM(81M@FӻڊI٬ԩ֨TPSF5Suu ,rIN$RB8U\eM3o$AYEmq3մPSW"aCqL_>ډ(̒QHB'KդiEкIBErYVISCq{f@eH&dRWg(Q8>N* cKiVK_-BT5RA*tu0ejL1ZBPF csÕh`p9-–**G &f)# avۑ.x8,U!›5LF 0:G %IF (jcp rG*2hXI (t\pAr㎒ۆ dIp3~sP4K\*F԰$ili83*/b aQrQʲ TѺ>@VNX+x}keJ7 Z:I8#GG:9/ǝrqq2[vp$m˸d@x[ 8B<ۧ0&^U <91Fp9xgǷ'xd"B`?qwlrxQcYy H st9 Ԁr|pN|T2*KH'g<`ӂ5dR]pH0B>N:0a*N's? Ǐrؠ'ʌ'c<2 ,3RǼd d+ʂI6A䓴>8ppgV#Hgr'3,y`'>`B?JRQ_atu%d($c%YH(.VbRMH\A!<'!?۟=2?x(RzVH=ȥppq89$r:{A'0y(r|9 ώ~>.Z"cf'9:aZ~U8bQH`IHl~<0?ЈLl1!TsY$<>=d}]P8-r'G iCncv*LlH%YǕ?x(VlGwŊhۑ]a (H'?tz2 h CY71B8= āB?ۦiֹ煾zC]]aXc#1'x F991zY$̅9$sϞI?9 Al8\ ##UfR[nHxV'8^st*^p~=>[m;} YN7y8#v26˂' HĢ0**T6W֬-*-fH[hUvIu1 ۭ%XfL%Etd\oԷfInOM&eO , 3w>&%$3yGrHlw1 v]0IB8ǃ.$*ܫr GHGcw۷S cmCb$y>rrsye' A<{[*`tfBvS<<%yTrA'<'dؠC+k{0`"1HasnF"F`[!rp1!O#<,l6B<$q砳  ӌcdE}ՏnyU7hB T<'HFnV\PIadۯV;n#"V1V$i$)C#쨉.wǓNO-JMuX,gb%[#@>w,u5r姚T}8W{lT[*I؊(EÃ׸Zj+}-x7hnT]$0V@;U9$x̱H's@\qMpA 41S" ƱCh0h2N8/S ;rʻApwQ5;\- "IN`b TquxSa9*A%N0|ddrA˘6Œ2ē|c?[B;% 30$Id`˒2?#cA]Y[ddqirFt aA"9K>}<zV%% ~ br<`±)%`q8xF(Q08#rYsUiGw@LT2ԭJ\7Np) ;q~Pmm4(oSOL.tgRҪ2T%}jB%бgmyoC\-ܚEs]*X2h9#199|E}EJS.w ƒيZJ>Hih2X H<9#'טvNJU>\)5NJkMovTE$Z*A8g3C0<ق5Sj̒1 k@FXm|1c.4 Y޶ңvc{R,wںb-:SMN_rCl^kn|&hcH e,CGrs{}F54)G(J"t$VdJquQ{%Aw*wW[tԐI:-HLTq΢>KV]trR M^<9B]Do*_?UEZi1ԪT+9'z[&fo6Y[E#* E ;z 7Lk7`MގZMj3F,r,kގtՖګ@)9wa)c۬jF*}2 ڃIۢ#U7h|6.ڡ:F\ls\$TRU/(Fwj;iӷ֔:Rګr}ۨ*mۅNq&Y lԹ\vc]w{^>H?*PK$O[i AH6RR"5UVEE-xvu$kKoӪOIGM(! ,FTm*QXN2 f@cy8ty ~^("@LgYw;)eN6A4!ETT&}XXm^*ZY0Y(84P MhJƫJQ{=L"Kz]׭mK^lSpx8٘HQ,H8ǜ}nܲKqj;RSi}L%7IH6I>RwvQH$ A4:Jp,E8¨C]a[# [@VI_䕙i׃%ejQz6TR/8]B/CtOc4mr7ikY=2tpMkVk[UQ7 ֚i01KX/Liv\[rMtJh.H}HOص*5`d´%^M㬣?QjۭZ-EdBQW2U]{Sw]q|A7mV<~Ǥ(oe%A+&ȍ'X\y4[Es`juմ837{5L1w.ﵗ $H4%Vi!Jmz[NZwL$O*HwO!ؙO2{Yuùzۭu`/UnY(UMj[4g*KQ0AdU@M9-`Gh:n&7#M=VBp;5DtQkvzZ*kzx- @YU*U% g~ѹH$u [ƴD`R^jjbKpܒjjcƒ٢h+G!`Vj *p/%l6ک}utOHjpc V}cV\5O+i6zU4Բ5E*}9CVmK][I{Ƃ]=UjX [Gѹ%9FI ls4%M,B^,*w`z;Y+aBzWP_Yl;  ZN ` @Qw2 Ѯk4\(]q֘HBz.":ԧ; D)\¿Qw> m] VNڗIϨ̕uxWEl4jZ !b.G(4΅Z#T/o:,UV;$nQ\ZCI,3UHLB#fExu vOkmEEKq./JY{Q@n̺]m )ue$ލr4B:)U5FMܶ0[VëAlx-1_q̿a**. Q2B$VKu 2۷4RYl7I @[VՆҧ=@ʛ '`Us{.PKQ5=5v[~]azURV*%KEޣ>4^ja &vOK2nGMq2MGKKd˼6?jcA }Mo }luH*=DVa-b.OV&(\̎jj܀MFitɳi7,!QƧdQ*cӍF8`?;x~۽1N0w~yǁWWwV 9#I2I gä1P,8Ϝ3/ ߜ8|~Cˆ`[;?Ww$| 8PnA? G3JWiJ$Y - > UY` O,8bL$$Q¯,j(%CGpΈx92|9oV(BUs;MUT0V52'* +ߵ|wN4@81IZ٧u{u֓Gدf}-Ҟ#Wu2,ʅfX0ˇC>rg88?tA)4SSXtmELF@j7M3ou;;c=eU]=ʨ :\{~β T*SpX6Kɶ4m@K6{󵞻 ,'Fn,avrx<=`/ΨXt}ú}УFG[h*M5O/0OtLeK1&{hy;߮-L=S-M뼚ւIh5us=r+x`դ"v5T!6d׷]$ݹ\jWU7[I;QY9/788"EPGY)(jLpQ"jM5u EOT5Y"O*79֚_hd%Z jKYS;yK36 Wk,úzޢ%\[mƦa3ibTSح"7S՜O R93"b=c33 '.jV1dYcWy| F9<H;H#lpcpH;91FRvd|qNc?O1`eRUq?q{D]%q䑎> :OP@DeUF2 G1FNߟۑ>:\b@,Y`J+d'"BSrB1iUPNr|~@j$~n:XiQT:ss֍xE+3,H׏?#π9Ϟ2Y`+g!p[|id<Pm31>z-D`9i3FG<(F<ש㨲qB  rGכvl!VܭuT4 ynT ?3("@ [vN!=ͬ)\jYb#8JxD8THQTaT u7 1mKIb@-5b9PK?o^-Og.՗Qw!t$î+c<`hC<ž÷8@|[tGb#˨珏 w;e1I.Ajj*gE4sJAi` Z i%a t2H.]U 83*88wB?m%dյ6m#o2zs_#7HºI%Ŕo ;H̪?!'3H" d CcKݝ@賮Xo8r' r>2O?uaNH )Br IGF&.\8I9# Hdr#3pHHI>o JV\#i8<9*[wepH*Gs V@ }N?s>:.5,`;ǕXx: ;''糀wcٶ9 +' %?3?ߤRegFYJbmʓF rY_o =-{1ed(9'Fvy薍5@Ĩ |88A$+n(,A*0v< I6gwcq#M#*#oSsWkK;M·-Go-x ;m*Sb ⯠︵=ͷh.Uuv}?]AGoW++FkZiiՑd43 ݓ,<Єq;:LTmƛ7ٿQ$ нu{P4q9M7o4ٯ +YD1jzz],QCQ0LVJz o!8gߢ9 OZڦG*:$jǵr(%X,w_wѾ~k;o,K`yxԷ;mbBk.2=R;yVX9#Ǟdx?GiQY@f'+zIPjUl~fbnŰYwqArn"knw'3RoJiʍc[ 5}tTK'$%Ԏ̆F[;}O_Hv-fתu]eލ-==}©87z_TBԑ*7"{I ݎAi{q%Gڊ1<+<&x0TzSY#,Y[o i}]5uUOm5udeS$"RiQ#f3)1^9\jHAWfŚI"|ť*LnmieYW@4 jbK$TJi=D) jzQ/'ÅRI}]ѷuE`MGr+ Eexc>+ygٯ-oڭMS?Y5=Q%-=nՔ.i䧪gxIԓ଀r-} ޗt?U\g)᭣IB̴SQۆ"2L0e6Uf bm7HX̎+(䉋Ma?U!tm$`i4>vڻf4?o7ozZZHӃԞ(j+w1ҁ;Ǧl:^,bATKSOh`Ya٘hHٙ~7[W+,HC8"<8OjE#Ɗqm.ܮ' G'> ֞[*r<2l$ |"g?*/E'B;L&2 R3n!=y%Cv} q|?#y?>vV܂gN02zSjYjnT,=zDtաFBā A]nzkT~!ԃ|s釦Vv lA*r`) 8Np@躅1v BA#j(c|B|h,P#S |]e,%v, m>?#o_<[|~W:KSc m *LY53zl9e`dV8#o;_)-=Vw"y)^lzbBvC $1{IS:%$# u@@-.!SD_5hUwAkaojjs?;I+rJbiei$q*3 :R5gPF|A\ I X pHܱgMXPl]%.7y;%;ֵ_{mPgm6 :dhQUPD]U"){ua[,S٭vŵi}ֲt~DaazzW>4K. zPÖ> $ ß9#/:︷EIz3YϤD5TJ=r$j),X\kpJH)Egڳm獂Tw*Cnլ1PΡw`DC`,yb0 /}ӬΨeZ-EUroI#)R0}0 ׮EIY[t;M#&GBِ$[]vKh*iVOqԵs5f3T/(wKOlbQ` 8B XgF=\?lf ћ2nC9'5;Zsf^@NK?Ҋ|wb:33?~;Qm=>ͬT}L:H=$MN'j#&4+2CHX{ 5{5]Ԕ#5ja Z t;ĩ0@$EP[C,<3F0# 89 xV9^|>2w Nگ:z]@iAkyLbWYVyvTdW2#\VWH#1 pSB&I, J|lFa:|_9 @Ej oX Je˱bp\< $OD$8co 6=#R,гD(JgHgFh^9*N8cYqc?c`/`x?~{>ѼEʅvA<>rHQs>M6ܮw8#}*%f#1 ;`zqڽce(;C`|+ED;7ʌx$0>OA!C|sI N9|y9z>^ k}]hQg  p=AjuͺuI+PO $Jk'1##ܼr vC4az(Rf(ay 0B*T=I IAI4*hCKHNѠ nwtw~ێ}جZy<<(EVy,ϳ~ݪ/t,-LKuJ2W ԋՃ@fAIʍ脭I|;T_NnK6v!03qzX4Q[_(u] s4&U5V0Ul UM&D! !jRXB#; }A7UJD@mE c{Q$,ƃ΁VP1}7M'јe`*x)bF SFx8$`r ?O#stt`],*02O|F/ۚP~6H>Ckn'Gg)񃃁'b +H݋ c+ѐXwc20$w$Cz@n}q# 0#u2 CϩKdaʨ'a8ϒ DIrH g#''qtvJʅnr`O?'`8R$ivHpF9 w D8(1`pQY eJ$dc#]#K#d?_.SRs9!Xc@I؁W r#yCT ڌNnxyO=3Hv( B%nsIRGǙW v‚N[J8txqǏrv̀rA8瑀c8W )`X `.Gtt3Y|G%9%A<(='@ 䑑qѬ9QX?ly|P@< ?Tȹ&$b ''ʧ1#(A0>@9@||JUH!K #ڻ;݌sP}o . cIT)ʡݖm8msҭG?rm $n9 r@h}%!I6O$9\#'G2vq? ?zF݊߃5`NF?ʤsLqC+P37' ,Hvؓ290?>GGwcI7VIߓ{Pw80z {Gǟ=w`1x:O0,_>x8㣲>N^zpG/5 *$VckF9'|#}̣O ?@nj|dyAAq~t'd<<=7 #sKdqxs{tUM;h]%_4Ts30U)jrTXTc3T.jP W\*v 1IPuz ]wMYLfԷqj{ޑ7WWTۣd2s>x}KY]pUwz )o{kA"GJGA$1gi}~}H՗ʎPUmL[[iWn騪.zYI;e[YM?k-?aմ-=lUkzJqRkTqt#K1\y1`x^W=ܭLIkdIb_,@4Xq!ejQjMrH*PVy .Ov3]'%8l JJF]@bT(2Crc_~5ץ{/]k*i-њ.C uPӫ}hPM}Aw FZ/JWݸYDV=j\+d!jDҼߌz&f3ZbfdUDˇidf}IˌPiSl6aU E5՟Sy䤡ך[EWOFD44e%og'"y~i-)5%Tk6SK =I D+-M*H}G$[U^ pV4x%eE0$uURCW52XU|7;-A5/{eO}dJ{E*tm0$Tz)3!T:@'fl@]Lަ %c0"`ˠS2g=ƴ8 LT&;0*s;mI=ԯ=O}YrXm7JZWAE##P(Ff2W'fhuMuZTPٴ )+2PH&M $1^.?X^Msmk=V٭l2CFTU[RCCSQ4YٯLl(sYSӕD%MVy*Í ! bhZwa*lt^rG8:i=s!R4/k;A4w* qoӰպ* 9,1SI7Y*ae;ih`C%K-)B4EH0OYW跲rzRH4qeUG J*-tU΋Ph $ijw:9A0 qϞӦnVL_^`fs@)"bE_HTTjkYY$"] ىܓOAF2tF+H($qRΏR[Y)R罨iQQtS;oihO(DM)hTHBK $F2H89QCCAo).X)ig1@C,uWYFH c"߀`6x4>o8nQG,zo:9b\,zlZSqS DJ*̓Ȥu5欻i*EYlwֺΚcCMMrFQ~fH%-Q\zXBtsn%,vH 'hr@t:%FNAKH}^Adh4 ^:H)٣wAjI$Q +۱>Gc@a!?ۅc EK I (7 q<|y~>c1ϥX=+p=c0~I+R8,Ȁq$Ʋll6gG%5$FAp\{ssFdol~f};OfݢS5^Ҵָ"(h3vm)Nw}- ߹J껅\5ZĴVf  55"e"ux5JTKETgrF 3ל_`z˽%=Dx;sbeF"jJ! IA1)M;5kD[4ՇGJꈺ|:kadx>ۯk9tt c=E׷׊ @O &6ׯߧg]rުc&nkWw}ȓ5 ^_q.u3K2Y-%}7ooXw4s(: }2EY85SAv# g ,xj#c3IN=Y|iGD4Ҥ9U Ge;I+ f܁`;6v}T2f9"]qfFlc )f퐵kEZN4ڪ-WbTȹ;v1ֆn) rX!8|@1;E*j/&f/Fz{ݴxeUIQM9-217J%$_C@lR;=73UcQ{+ie**̌!`J19Lic5 5Fڶ)5K;ZގD UM" p0ۆ;ԍ>&8ާc2+(#(.["Zt%TUGo]7mxtZ&{$O[9R8X3(@`Qqz/c%EESdl.}c d,6dH~0A ёT$K )PI ~C 2GtcSm۫W TUGQd,zW$Lz(,I 1ep@2GM;Efԝ%ZBk}[pc苝G)xHYbjU{cxD"ۮT X A rGFnYZ% >OdMS8y +QI!;\ dߎF C}0=!H.XpI=#y]rPm߿q U;rdyzDf/Lfr H<ע,X`c'8:&g;H$ab}U}1]֎zO){ol}E;)+Mz=6A*˂FX sK'99>yso)ү~.Q4r5wۥ*&@i) 'i OflHrr?:V,,W9a~?P~YeTkH@FQ' 1'u }Ԧ6PJAe0 . c定zZJXzh yc(v=~{-:+ӷYo]NnQ_n?k'Z)!,; ?OV\o\):R=~zNvfIc<{8uI׆lrHǂxfpʁPC9 FII8\cԂ_i>X 12G>8^ ʹ0!2ܧGeW(`>H#Һ !8~y#@;ܜqax'Ǐ㥭~sKui(Sj* 7RidHRVԴ[=QV-dzm*b,Q&a"0p$.CR3Hn1QTpG 2>FT|gI^jN @;|<ͷ;%n6{V>iuʪ56(#SvX S攲1IZV/F Tb!CpFC8]QvvC2N˞98-TgRlC_OC\aM#KMYTy] , `q*0<6y8:!PDl̄nB r S!xb&*Z9cY!"†d:) yz留cݥhĦ:6rR$Ng6TwO2Y4iӺ{ۦsTS*ޚ`EvDމ#R~;'WκiUXE q\`EX6ڈMW|Nw<]4 |6}Gi<$uRé]H9|o%h+#5`UQ:c% DMy%t A)_=+#+ʠh.I,Nn'c?wmpp5L2W==wܵ̌;*=D#K2[OkVi)=T{-8[6ʺYLE*O9*$F3"J>5͂joOtVҥ D0`VJ֞5˿]gg`FQB,}xnWlםb댖[j*m: ,㚜Ԕy JG!fCfknj eMEpa[W傲 %ED}8d~[fl[d2,PBI(⬟Pƻ@ﯯ=jtvVt^SAiw+S< h!0V-eO[u-]LJ4@b6Le 6yNwvǨiR, GUOP`Y~UԮf0̸foj1kX(冪]TT 䖲hpIHU bG>SQs@2"@Ajڎb3 Wd,)gɖbI FA@qQ`, DxM+D֝W,4QL׹)髖XeYIڣ_g: n;ŵ![ŮJ9j>ը7>L1^:'4TuGAn]^oMY0MD|(bC~-Ah$5-,u4L(e2W'w {=mE۰R;ֺG]w}IcT?yi"_$6)Q-TTV\+*ؽ#ACMSW\t_~y :B@@"SAI6R}\wGPv=%.UuV{-ʪ٧m.Zh" pGGd:W}-bJG ;aB[%c眉38JO?3f,QK7<ҪFAƭmaˉ=l0zt]t.%Z(6GXcvC_w:SgPU%jadҶ:zBjL[4Ur,iٛחɦ_αz+O H7m{^~W xlL3!SKFcʜ2#!͙r8f*#Kˑ .%VٵI2 H}LK}) [(5 08"$#f*cdc4hݼ9scqVRYI$+ Ӄ䞺6966߾܍7ʆ2ƻTs0p9<`=dt:NDK<1.RҕĕkGMDs0jȬ3 >p8 ܆ 0xs]Ӡw' - =Q0R4rCk&0XXD`+vcls V]&12eHz"8PWWJ*~%G :ZvMvqTnvM-raWAog(@t1tZҵ{֊bkuG,*9"` ޿6UԺbC5o7q# HeF9 9ykEU%3Փl<8QI%1Q9Mm?w0_㆛_puOszjH*)OdO $HtMםEiZȡJh^Zu>$)aSn~xu]SYh5uk){Ѭ41\&(S )N@InӖˬ:ޅ 'Mli&x &ER,,tQby5/)[Q]@.ajh j:P'VphXM1l v PRLPPXźͫ4=tUV35uD\5vRWҙc5VYDC OEMvo}ޢD)a Ihx^36vm)e-lP F J-]T'ϗ_,X]zuc;:T,<HZ @`BjKmd^?MYiz)QTh#=lQ`A\<NC6@'dC3h8\ۜs5fQOtԷ}J[O'Jd"#}:HPYUI9$I$NIqGi@rKeتC]/54t0 V; \VM!Am껇t&{(j  - ,HH۔=SWxâW, ѯu/ _^<ž q, b/\:.iZൺjqyj߫F9dh%* YA6,%d'|R;+epet[Š5=U:@P -q<Π yq r+4 ?Rn??'!2qZeIl(P?c'2@`sуB2 #|rDbsI,9lpg'%*Td̬NJn+rprz[,A F0q8'9=B̅Xr=''46;sNr8J7 9q:MLR#sdd?'2]۲`½ŐmŒ8ܻvNqЉYZ2NG |8Hp?v H$@!r@>#Ãq!Nd,7 blWǂ<9HeqDd +6 r33J)?NH#?Ө Y>77l mw `=1J<AGz,w 'HEHd`g#>ヂ1}6T`yPI^rNlP1Rq8cF7 ;@,DnC @?9*|wFI,JXa!K9~ab1;$NH_i899X,*0>PA$cnjmy38#0<ǂ>zQ.$q9b\1݌:0~p[MˆR8/ DSFHOFFr?'ז"p`$=twvN9a@@YsR?@%c/O$RvBT'q$F9~:=}RAHq ÀA$A94ZSvٽ|kp 'F$ NFy09$gی( 0x gD}MÁI_''=󂍁pS@$|.wrG<`_//6 wYuyu{ F7By $J`T6v C%qR:xbiAqjz+"VC3B՝! WM@䃃Ww{i&6+Z`5U&!zTyJ$n*|V=?uVҵfEW juv}귚:j ځ*%TY C.p] ▖M*_E AxSz/Ktz7Zdx\%]ecWi= VкX.M8[E%%<,A#RHJES~`8@U@^o#z*Ҥ;w5&OrIvZM*[XjzjzEId.;ǹI\#}wO,ƚkBEaj;E*ZKt#PbUN/{{ 45WMo@%[z} SAE[$;wkth?mv {V:@մ -Lige@Ȏ);nԺF\lUR1=_sJ}fDe9 fdP]5챫[~TA bL l a@ٹ;pYtGԎ_[UOݫ;;Q ڮDZS'PTRS<>EL(\s꛵gi;EjQ^+3TZ $ jb%'ܼ=ܦd]Qy# gmC}(ק_3"d!jirv zwU%_gWnݹ4hăQh>Rmz*r}4$$SW,_0]{MYpM}xWKҖf]T}9 DT`bEQR~j~w7Go5e5@tm};uU$qBEEHQ ՟S=j^Q] I(uƛ)@AsFKF +6=I,Ҍ;mXXԥGklʵmlXh4@F4n[vDZ|Tuh!0۠|mŽ(V/Q0.W;:Gmؘ봗hk-7gJhVC}֚_Mvv *>{yFZ$ZoH{lIo̵_UEeBH}!LڒUWiA]6V_i.lƥG5[G gij? f cV9p[~b D*3hǗ5s @?εYQU +7}D5ާ7w.lgӶh,V8LCmn]H"?KpHjnQiRZ CMSOӴ՚f]\ .>{_oe5~- Q(dIjF[-jzٕ%"J첾(]G2@Q~GlƄmB p D]`=rg?|*cD`BnZg}]1dVF9 NN됬K6c'u׫pP A>:U >.gݓ噙#G.;_zgn6U`WkY V IAov OXJ@|'XKQ` ۰JA#rrMI4£aBBםDf awd' \EH_{` NyK!f-)j`{m]%қF F[3icI$s8KZ9$ٔRTWn,4 jnܯP-ʧo%-KRLk02zwP4Q8#**b $H,ޚB'[hZ`ZzڎxIC,jI>ǹ]r1ItY.6oRwO|oqm{׏ì/سhƎKo鋍 QC2M.H 5, PuiMC]o꫆Кã䩵ݩc*ZOXSceQWQcW\iPhaWӾ"ۚ',>ScI!HvTUpbk\z0힐Pʌ@^a'ZH"٩c`[ Qh[ͰDu(Gzw Y-?Hq<NyD\PĂco7*qc磕, >z>0a TrOSO>3?ĎyTv7ކuUO~Qn5UFjh>ԺJ$J1+yzcE !1ƂU'Jja$q<vUI ;b9o}2j.}>Cܺ=C[IimX}Cė=@ U\t}U_-_R?T]nϩl]@Q-GimU3h1*3 ;}R O{\^fҵU+uMQ#3\#J!>wNKkk&zLɳ,FТ5 ,k5"F 9oI22T\+$l#vfYT Y~Yt04Ue#')wjvU"H]SV(!@8 9<KڋܓXcNrz!nc{IۑI@#<pϑ9?`+1SȒJFerH'?o߬WE{ `j:eI4kEMrsTh))ⱐ򺪕2e g onFFkM٪Rթm[*墛`W Q4jJP\TSņw c# ~1)@}Mq ,e`J#(1%D'MSGqX'U[~ĒN٩k,;e=]ʡ+c"Y\y0KTUj(c[x<{ #rn8qù(?j[Ed-Ev\MX5%*eLbXLc2F2Z_No'wބ)`s~?e{ R=̧qm$H#03N"opc3vI#-3c$E ׍~o{مػZFۄQrPqD9<HA<0?LNp2F߰}}38CD $cU(եLGQePT$dceA}iM=_5}פͼ9^Eq+2)f|~ mmF6S ";tIuњMj:x*|]O=*~cv+HE^intjYr avIL0 n Ur?0Ƣ>n璗w_,Wx# Xˁ*62:quiFiSFrꖦzg;UZ6vL?pQ ͍9 ȶP 2`$1@ iaASށ[{$.2 n9_tQUsCXz.ujVHٿ40f]fz?xTM+1$hBSY/*7G'#H"'zi)P-go~m4,z;u/$W@OoJPIҒ(qibe(HrC;'I) i%EZHR.ꂋr&H;?G,uzr[-u3iic M,"ӲEM< Czk d{>q@885KKƐZF< 1'$>rx=#!sX) Z2 1@b!K eD`  r|s!d`i*[a]@v?`O??Iů'kji56֭{i?qH +O^}"PGjl%8A[SC_|O3=$9! ?SuIoH+,N?F:ϫ{ ($Sqєk1ii*u \WKP$dRZ߳w\H*L] h(e:iw4/~q1'2fZc\K“ #zbBI$oq$``dR7"T%@3gǞ3_e2~xճ!ec#ZF!B,f>n2B,Gπ|Gq=ߥ,ZSZkRj:0j笂4o߅1ͳe߻cZWOPyʃ'~?Dv;]tuRߨ'QiAM1Pw uE9V'~h.$- }Tdr,dE&<!Vן1> wҗ}kqnMjl`ig51.eqFͨn_k;aCMTIrN*id'dYjo[qRWg1V%aelfbh*LeIv_1.Fr2c$B '["Kn[sGthV45M]z}7Q^rZV*iU)+\AJ$l6պӼ:N^g 5== %LYך#g2n:ֳHPڡh5=ƢiKe}DؠH)[D6GDu1KW+ƣhk*,5;Pqh▆I] %jx(& óTdIflutTi nn"FbZH[8}/rKU-`۪WIe'IQ!ʡ 3_<1F>\&1P_.1v#>Tf@P3/. Ǫ2j$ت>\*_aVǷ'$y\CUv@O@LN9!@dg;@$as0C,AMIQQ2AMn(%YQ"8bvdg]7]1J%iw$2d,Ih؎Ae_(_Fr_tuu¶KZ9%\V %,FQHW 1PJĭeuuM/NȍMO;PJLR-HwI虭a:Rc|V_cԗʷbCYNMC,X[vr&zv ʨJO`>fWrԻx*Hp0@WR3O%v#f)$OIT>DjpYؕU6+=onQiV@饫` oFo7t܁?(ǡzFR%E}uJd+LL$""%sSK W!DpEHY㤣fZa"];D:գe=LOU{E*VWT.YW*a8ǡO@BRRjMku=ZۅXШPv+YclQfizBmVJv;*5[H{m*cZBY Cd$8#29$!|e ?dt$|=B5 dj/Ҧj }C_  ``epF:r]SUݮJK]'yW8b d( Xf*KgoEumN4Z4E%ªMMkjjjZiPƒ3$*qyq280%zdl GێCnp y䌞8h:S W۝g9d]6A<99##H]`'I'|sF $I ٽVyx!qG3qF *1t * ^pXx9:Z*J$OP@$`8jVY _L)0Idy9`|ro pL{]$݅2I0}/EPHr ǎGMBE.x##gnx]or' #<Vdl>pHSy<# Ҩr vYT䑌|dgOM(rǓ0G xǓѢ9$ۙ2v 9S9lH<uUY>@#8;8|tfn38$n?(w Vd8 0!HPA'p 玔zH<`m8qw`ad;#`'>1>=6Hlg#{,W#MaBK&*ڬx‚pG'I,9Aڔ˒?"̂9P =[ilg?[vڰaqWH$|㯱,s `94uE®K`?шSccHlbv0rH#¹]WnI0TJ&( Rv]Xqnr8bݓ?G:XHHʳGA9t`ÀpQ o>#@ };'Čq,wX8q|5)QNƢUe&Xm f8=7V|5@ܤ>>89qn<O?'UF7,FӁ@Oxʜ@rsNq$x#""RCqj*Ue $z20,hP m0p>?-*k&mݸv<|c#Jbf<)@+c@hdn|`|8z<$i96zn (2+ka]>rpH۝鞮*%ižv OpAVAae#Jv@F eV*5UL'x*mJu %n*#*KDh 1{hw?^g:lڂҖk>K%Jj:u'2Hh0P׉ҚSXk}PwZU5Xe椪OGK \h58'2CMœע׽=Һ@oG X4j <4sl֖W/E JAMݵ;ᦴ6;OKp+2 hRҔx  U}Nܻ>f$LbxSh88X4sh#p5.m aH#rc,SƯdӪ$q;] :z(ܮ֪̱Qk)⦬ѭUEpḡ|?ddWӵ5WI:r%ME1fx_6sJJttq2Rk*%)msGIY:IO$6%jT Ԩy#Vcg^.'֋auzzIw&-9SU%MTF& PXOdDpOU5zv$AVPeu4M]-MW7c(=i~ݩҽ7J1EYn˸jg_.iNOxurC4mqbtx\8IcZC{]N}>k]vG7﫭 + }mR9 W9@j䆢b(Co>k/2tʧ9u`<`>PvJCBbΦq:ƮW܅C8XĎP1 q4`;){:mKI]G+{SH(WUOJPi5mW-];{.'xuPTSR UO%IFO$c*;[0n3sJݳT-"tE`;W^'ᧇۨou(#pWpv360@D֟?,}}WntI5vT4.0Sӕ5CI;+FԝzSj馩zhЇz(# y8O,@^X~k4FvWHUO.Tf ZV !-۳JA#QE!232'ymTY-Is4x#G.d,"+pE!Gbb8}^/m;bDIf:i/-\T;CN9H11ߕî^:GLYuYjK媶~̌&42K0!Ɏ ֑Ӗ:WEX6 hV15S T3TNM4;` Wvے w;ı kK UM#HD (UE㞤xt(߉gtОBi5Ra1.d;z;(+z,fԪK(X;fV%\f[9$(W{gcy>qDž$2bxǰ[  H A<1GGa8OyĊHے`i@FUS~?sa}?F )$FBANFImI e߶bI`,`'g!ٕSd!gܘi:~ǸXC[WEANX5FQKn $R<,hSAƒGAzƤi/`bMWEVn w%dRDfJHGVeZaLUKRSxkt UVS\`뫫 gR%"W0Ҙ4@X99cG9HkyS}M1x%GArJKp#E BIl'yjfWnPR55o)Tj+~`8k>jij{Up;mDczJuW]&H%,SGFff9˿MA,FYMZpH-RGJc/AU WF%X$B$Bڪ7hDQ;DeޫU~ EY(⫌S®*'8iI'gXHdΊío6vJV,dWT]ޟ)UE,TSN[䷘heOGS[!H(V!m T8'i-ݵM Ak+#S˕LȮ,^˺*)V,zpˢS_#HNET[6}Yk pv 4_))o/45h$s$%Hf՗vۛE "XVzp娱.&(O[RI D`2;qvךwEY-ږz[ ]ʿ2NO [Fjgus&z:΋O EVݙ Mk$2$SMR0dXL>$ɗ_K*YiGaA˨,Tw!bɖ'Lu*|Y NN~kjçWk%IIqNST}ܵ8i%)C1H$7FnkFԴڮypڌ@ *i^ifxQaUfXwJte>ژ+UV& uW6Տ0:l57j_*eQvOLkX}gKF!6X/ ̍021"EF.0)5ef[ H;(qeQtcjcB4Ғ'N)?mlO޻ [IIUOlM%R5H =$HIHlKh;{5V}1K5Қ*D2L]Fd;E65I()-_N-E%DtMWGH8z 1v3Meu u*5+և+SYGWOKs2$m" J+BR$Y79Cl5$DHєd:4\c% wLTM7ʊ6bw\e^Mh/X]H^lZjgJ:4쑘g]Ŵov3J EWE=Ҍ,xEhI*vSjc\4#LX-zF򶶽Ǿ%HE{#H[nN%="RjZ\ Dw"I$V[I7L hlDSYcHbhҮVLmb'V I!CH؃[NNj"I\')q;aɄS!8 y5Dzޕb hki)./- ƍȀ9w'# GRX2Ay#zav}d $33zJda61N@\<I%DdrÓAq8yTc~Cbv!xOF &g1VUTjqCʃ g8V;O~N6c1rr3A>GH*a#n&<6qc$uQW,VVvP`zrGj{zzyO5tTO--56Q3H=1hgiLO4WO%m5TӲ"rQ#;Ѣ]Fk]{:UVCqPi'KƑDNdcIAVL==)E M`*X' 9e Y47uub !i5EU_&`0` w>#po{F56*{5+LGFGn3Us‚D`A(:6k3kΦZdQUt,RdPͱcHa bd-NꛮvޢuMdj[jlO+ZH"L3ef,{gRv<IU=:_$\i4cܛ Rhy2fG*DZʝԱQ#l xA @>}hl\Z4%J憦TEvCEN |̪V5ݾ}SZ=ùԩS$7[--%CII$E,f;Nsk_k&Qi 5QMCqS4Q9i ,!=+&uU75wNdXo1DXWehlG/#6t`LH Uy/XHв(r0i8E;ΐzv* %PP"kN߭^ãji*jY Eog2KL5fgĽ+vWXj-mFUw \TAnouhMTcq6]Ƿ/Q[&t^lh34rD(|hH# >EMoxk!-f=%ch<ӔUT9ɯ$Kq/>% ]j%Иh,&R zы3)RFJ,k̑O‚(iXzQb6Dm A>N~vft 'sHyUJHcr#?cQ(L]I `1|xPh(ުoh7a׷>|52sr0|ImGzwi,.1@1E'w%v*9(S<HNb@Y99;HBc? \"] 09$ OxcS#A&8 >YTp(*:1c;29SqC6pXFW7>z6G\,\BH#OF؂XspaJn9 's[+ p[paH88.K1-r}' t=q^W?1?ӑU4v2[ʂr߾s1tr0 0. $פ 1(q-'??|3ђs qyﰐ#ා;j9Iާ;c~$`x$ aJF0ǒO, .NybFG yv0y-!\zL*vpsp3[6) A0adlA0a'd|spLrUy?8<AtkHH>-Ǵ'#' 'RHs`6o-|$sz"!ACd |ϟ'}nT0ߨ)8WbB1*<18r傒>AyBN3C$`=x :Bp~-sWyfVO'r0I g2M$ݖy< zWUF2x8vEQ !Vą<ςF L$](rA qT9m'|`nq)*IR>>vFoe&^iRY/1_E-:R+4ufkATKalKVVzGDM5uZgz>TKCSmZ ^NP#u)D5TѢ,@˗l'vKXC^ˤkkV-IkJ{ ;]*#cUHŒr,̨ͩ3C>Q2˘ˮ]V=E[f*4&Jurj%0axY5fJ 9y&7c5BfFȂ%_ 9իu={UdRޯ}- TVX aǷt&6bJ-I# z @d pYy~ EMux@EN]sc ZH[Q)e\ 09pB@VXX`g9 c0éYeӲP[m:Ԫ %֖vh*Ч[u/=c={^ b=X?%DxТG7+଑7(˸؞D+] y8#>OYu=/Y-av=[_Q560ۮ-sLZ1eKWm5W)x c6 -WVAr+7(=:֨ xlV>x%l \r@'݁㦱SWDVdop<+B6 Bۜھ m8 y' 8QI*ǜ> ף̍*Nw=2Cwʁ1ϸ\JbN+~N T{@ ? ip,$_'B0$R~Fg8[ &6@ NqG=)2A=!\x +x S{o bTeH#ʜ>zoIQPwHʌ`gx8dS rNl]qt޶4:VԘq!d'F?|s8 r89?@%BczGadl|s#>yuKga hP>q ʎNGsǀzQK;\! ;Oaxck(3\+(M%Dw hV&噑DP#.B{CEۯxiit=\zn92]&u@rwcrHy*Yf "3Qg{+_o~.k:OIV[jTHs*SۭE5[S $O*{6K[> c=HtZ2 7g**J4+nUP8jxc0QCT CkM[Z-GנE\tʊY> =PC+"PY|ֽmi=KwKtpS[(lhRK)(5L^d@f;s$1XDhђ!GW +J2 .!I[CYSYv0!(7Vvu*M3(+mܨ,DƚBFYĬf޵ J}8z]A榖^+~POwVU"qZc4A9oE,x'z⿳J{>}^LGZ*⨿Z-2Q  gc$}qYkKn֊ݦ.T\ԝ竨ĉ,uEDKC5N[9yX2<7fZͯ]e:MheXI,$ԠlW:n=aњwN[ ZS@i^YԉT[$W< Vy*\X~7[^uu "zJ|ŊK,SB!mOvt?i'x/ƺoGM+vGUWC$T)H>B">zQ_}^uMXU.57J@E$K#e " :O E-6rD_,БX 7r0DiÆ/+EꣃgAEp-U-+0[mq<z =,R(F2(9W7q> jpy{ZvWGOI_tx%>=5u7!y6 = G.]lֽOw.ϡtEL~oomH8$_^lE9=uqtΕ<)AjMLJu.ݪञ_`H6U\clGsxK/^#*'2$>y]x!YE_%uyh4czIRǴ5Xn&הTb\mpTLn1Z++bCPIYw{;Em3Aٞ\4f>ZwQ{Cr} ՐD1 J)=MѪϡ;[sg4ΰ71)tNj=MhЊ ڶTxHadegZ_~wCVҾUlbQ\Q4mEbK$$3+԰f.j ȸLӬqWh# cDYC^RS&͙#!F+EH[iZ[pE _N64a)UE U@NK6lDO[x]etQN7VG[KCK"V%ui6wiU^6/Ks,SUwmSRK4[q+S{/u?Mz{lZ&tΏD2mƒ֡=Y*)3!'+,Ql6 EI# v%vbq4#rY)$:Y ң44TnPF &`NJzT-@3#Ob-#5=8稘B 42v~rĒ, o\'c~:Sַ{_XQIp m 9p<?28;T F*ddeI11VfU*BJ; KK /C[!ʏ$q|qeډۂH]CBP .ˎ7cc<IlrP>BvXȤA#}ZfozJ+$zY$*-ڰGS9~ddCӵXTE6M-:QwS۞5Q(7;DԬR8A) fpMGKGb YmQ6u,+,VǽWj:>w=jݭt=g0m}{i%[;RErdi 󴋹"ґQ#"D AB"S p(*yOh )lչV6SR,RJ,s# xL5VC1@ X@,|q0:dTҤ`jS -Bڨ;a/n'%yȻdڻI#xG4QF̍)|g?=zAa\/ gXpc(w[!U $s!drMP6K`]ǂG%k$hcgkc[ >IK. 7DTv].f_BYb`#>UӶ==m8<Ӟk=G[8t *4JOpTE]}ʌ, xL0B\%I*ܬ9)$gskm26_#=Y Զ`"0ٽH/Nfl6A_4XY#$l8b_%3F x<':a˘Sy#89ώ2 VU`H >xtRȮ$(*0K ! OвFtXðϷ K41$1IԞd/$In*dr('S'NzL°`cz\'O}|ymqd[4^Y/Z [Rj(B i( WzxdUe)HQOji4a?xN_kmbI㚢-eh<-6{0i-+99.GsHp[jn'$?=85#ۦ:x@3'vz$D! d`sG Jǻvs8_n@##ysϞsa$ I'#yʨYw$e sn?8bzp}Dd'ݜryz-PF=>@ $g<0\16ХY x?lVȥ*4D|~s=0RB.P`#<>1=W~Xy{{M-40l \ӚYšiq>GV_( $gCi}S }my}Eޕ,PKnQ;5HY*1Mql}};{rhn6Yjk $[E;CFՌK^s79`_S֦,#pif01̻y`1:hiZTBrj/UwS]iI'oWudtWTStqh$Ŷ˖nAGMKEm[4_ehıR[!@ı&#t+HpbPPXl41YthZi5ѧQ =g!d2\T PNN $B3p~1pȿWQ߼Xڧ_R IG?- MGEf KLX#~>- tvh $]܌WGH[;Q`n}}qV>4i`z}:٨SV7Gj긦&0 3u^БiJE,6%- k$E*~`]U@u3SS+QUI23>pCyC-*JUtHv@ЎH!Wb,j[mNJg:#!Wڈu(qW\2ıl񃸯 `1WK;cI}D5Z3^iX**)+A1EWO6"GPT]7ǹEh9)[=jn7+=dl fiE,*ٙ#YVlj?;pa) sY7K5E*nUIJK&b\L%*,E*$ \ ^iʰtRc1 M7~p=qzɡIgޛ1)aU@mѐ O0(%&ʗYI%e<=`.ߺZWܭ֡׻v:zE*Lrة.2Y%OLdιx˕gbU#5-$ͥU{fbݕg"m If *$IܭMS]~W {+v;NZKV*e ׹^9 MNc+%^ii恡z+}dWʹC߮TEI*&/3BGhrotN.z.еm\'%THj/7_ZZ(Ȇ/MT ZC2>x:HbmFia[nˊ5`krJP3 oMD+d(I$Ƙ#9ڭۂI9s PRX08#$>O=&g1)_A{qA$E11,Lh+drf g?p87C$ }x98avf~r?m`&WfHC'VEۻqmp>I0F/QnO`Aj MQ#׻,TESg,^`pYԖ}m>R0jXE ˖cuo.Pti*-REmyO2W=<52.0j&YWhf:fкl[%-$&`v8hci]MDeY` ǖ˼ZQ$+iqĬ SJUv,7 vPU@@VRXtg}m&OEэAM\h僉լ{VTeUh{~{Z5%L\UnW~jVDZf{b$J~dKo146( 2+GT$iY!*-Y,8IXlAfbvwe__}-iMuWznګֲz*t gfΨ?CrM-7v;D+gnMEUɵ,y ƦX!VD*V>+]ySn;OI.էmUECYoH"y5ybӒ7Fc 1tպ}ݴ͹)Z"[bJi|#tIc,]fpw<$9|,k8H㐜!&HK+"ƴX%&-224F#t)tUuWjsrU{eRy h,-zz|j~,1GTBۢwػ>/ @v3uUvN{ud*nBcJsepwˆR67"T=%BQO5dJRemM$Jc2wx u+ZGݙgcQwg6ǀl:1YKX& jag1߭<[HTJĞ ]@w@A c Nxyp䜑Qk/-){ґoT& S"tMs%1o'y꾴+NQtzTmk[EN!LH Oi9w$XdtE߿@ `gتEc8+4[H4Uhj IT*9v4s}ã(\,լ)*9;028#loNWOp4Fby:P`ZB6mP<0xq"q*P4KZUI (dX»vbIII=(I~b©fW,}Ā 㮌Yor{?K"YXh{b Lm H% HwLU{&hM94<0$'p6 MQ, Etjbm UKiZA5{{ގx<SҔT @ !E  d x0sH7>ʑ7?gr)w p7c?bʊ(*ܓlq8󞞭|۞6X#fYm2`tbJf1`͵s n' rFI$ FϞ !TeHStGvǶ^Mukww겞X(P('$?z\0e >p9M UP)Act<FL`$HWsCumtڇ^þAIK{nx >3`cwe,q'FH|t]f#b) c!`Gq]wߤ{NsHPB ܀Id$O$g>svr3 8O`ˣd>Ag?t|]pQO&Hv@F<`l6x'#1#& 8 0Ѹ T ~|uUVw( <|r: r's#WF~OK6"B͸0`r|`59!>b0I?>?n3$ >禘jk#+TNI OsN as89$~0=nǂ^@ #Ch龘:$ 3dg y$8uCn ;+'㑞qg6Wۆ8@|r8d #KR>ID 礣';F_%|)<?= Pyc1nH9~۞H D5Fmiœ FBѱMfeʀ*T?<$x Q$d|g9'uڟa`06W<1q}t^'liZRǯV +[Grb]%).3KgL#>>S]twUEOGqܨOO'V (pC$nY^'4ڗZȂ)M `2+R;Y7=xjִu5֚%ҕ(J;")fhg Njr]0YUW}?XlU=55ch *ikK; )oxҊ9dxxNX{Q.iۃܬbNhwj jݭ4KhFs#rP(InVRJ!G*7 20*ʧ#J*W֩UKUIg-SBbIC㖭 sL7O։7#moRkPjcIS8§a[2HP@#iaI( K#8ɑ=2OKd6*T,5LM!]Dhc+2X7Hm=Ƙ%M%J 빢n8Bݻo%᧦it$S<$:J0*T@bd?3wG\)ߠ*FB{Osۡ5E|71G&V.1 XX ˜p 8'9c>'u{jIf[}5-EA:}ي`]d#Uq i.kގԷu$4RijIhdʝϽTg3/PEf!&6z0SkNAg`IcWbF^ظ#\*x89tt;u;$uo=܎P}tDTTS5qq$Z`5 H%U)Hr2Ժ_LF4rm[S,{ j:Z X;=(%NZL KiWu VttkmXQ)eZ4ZALRHPNtVg}}vMӽ0[Ө'mƦ;!Tzod,!*4J(۵eUeYmB[i`LI +k&r1H+그֊tzvU[ZyAKLIH/+L荄u$r{`i;΋ZI=?p[զ ނPlt6*+ 8ɏkF5}%UOjz%TUm(f)i= \/:EJ]tr!yYoz^Y=em$fI _iʲH̙d;!}+4f&v4ȦZaH6@4鲑h;&WVܮ=Ʊګ~F7z 5FF)]<$UoRR#uT_[ݭж9}/_PJjt\T ֣DOM$sv6/7N-gF(t~b[Fj:vK-.$Gz^z?^WBدakKM ߵ]ŭVZgm<⑤=pL=6 $ f#3ćAKK$Xc,r1jv z1Fه8BB-tGwuloDj=KWxӺ i)u5nkk mܵ2J8 SߣW]_ͨԗCMcrVQWQT8joX$٘M~;]=FIhjZ[ZuBmL2!.rM4B*4K:72JiIim/ik\"op"8P쐀iY|f^$_i$\fY|R$P X莍~~.XQWMK]5-nOO|dw殺S)GrCHX)U Gvz^z-W]u%6Zm|_-uSpe1w I,}H%®$ gπ2ͯgݚurUK,6ra]S>)-K;zsJE\;/BΙdC4$E*]*!BJͥH|9@DVPtƻ!`N]@'k7A^lw}IuծYAlkKqjZ_C].,)Ob;3oӅ~͋MG_(lZHa1Yq`3|uJ_b ʼnq~?LZOuOIGIEo*jX@V8ICLl1+1T]WoKWYF^, 7=0Ǯ(i}C[k6]-j8/U\nZRAH+tgi;ciNhmDqw]V.W{.KSc=AW5KE)X£ԊY!YJ,qR c 'uҢws09# 8) s|2ήہeRI3xã&29'?? ץnW=q\ߐTq=' _N6>CGʲ8n08‚8~xM u{~j{5*Bj mM-]urG,QJ $!6i9 r7181M[[PčrJmYK02eX=y XO{D 0 .ӧ7&^ go7Iǃ瞕+` $ny?:- m/ `0ǝ|A]"2ď8||tA;Uu›;ہU}|>ypwnF'9 <_mʭuݽakNtnwS'E2uus:8 BiHPjWvSj Wsj-/Ry ^YQj7v~zo3A;[޽]~۾ZgM[~ID T"y\ISJbL̑X"JvKUPUت3*(vRbs`,@BMv ISUtoƫF\HbӺB/)Lb a!9aDdTT8R b͞I9*O>6 =#iN :xh-%]Y ^n&#Yq9Y*%z3&)K lVO8#>3NFaBHt5B"-XYYE* d(sB~btbhVdS2T8|cg|tM0~ynsX s$]莹$ y9#na+zhw*I‘9PG6Fm~rx?q0Gӳ!e3ǜ vw09zQ]G>pa/28eO>GH#.y Üga] `  to$ϞQ2:MIcݏ2y8?. &3LT\`|?qMeMxVe3;Or:U+9;?S?8:jTzw`*29yҀ U{{;ꊀA lme I>:A, F c*HĹ2scn0p 9s] (edɤuPsNG ?8H lq+.K`r0 ^RVE{]۪hfSt ڙ4i)骏VOi=z+t(ϸʍ98x)U%k{chGTJBO+iǎ[5.W)!DF d\+yZk0~F*~r7XVrDw^w#`@'~c餈h5zVLdᒌ*q_˕ejt$QG0@i>\bB|ZPjdYZ*6D"y׫EZ^I"BK}57klh~ jed\*Ӽ2TK$8?0>9 v'?E4=אN)ZU4M EeS: 70IjD)⨌IO4*Rdf;Տ@fr؄Yh6eni,Q2F1ITtjpFn(GČ@+=0 Go2 ˟6 qσ󓌎i 3#ޠFNO{x碚&$#$^|9ɨ3G+sDF6#Jj{.C{#QgtJh7,M"y %EL:#`rKP-ַ[#ˊ1V5V5{S?Ӹ O*mq1R[o6GJY}/K Vx2S#P 6=ݭk{}d[f9+})$HR1t q @;x{{("Ѥ:'pckiv;3?ny [5LUUoӿMsUiRimGvۭ[rVAf@ճ uA#o6XfңzYKjj>_O(hQ53OM$&fu, ǹ{Ś|QQRY$x6z`80Tn~X{QjӗnjkţP5mTUTC[PZVյT ʐӫI2>#͗X|?!6maK7e gDawKr_!˰G->a"g*2YK^ҵ7nW Z:yk++`\IJvI8,T%;T#>u.iR5NcjKV9OOrKp2.C7+tkK%%ƪWŰ 炖B"DomΌWۑ@OێӶ5׽O-Rh"VmI%5jJ\lLD"6~?w_25'(`ZIH 9pwBF!r7<9Hic=dbAǬ@7^wi쵺r{{}CVAaD61O44#,ɕU5A7mNMXUJ[u 7ݬa$ DKZ)*Ro`f]וԷ]}-qX/T0iPT1ttXRoOycmwwHZ4y @"I$ ;7&fؑaxxЙӘP%31VJ)-SB~A)&HX,\=tVcu %AmvdJx*S1B奍Hf89g.T'OPmfy$h"jGyR%*͵?Qw+X # `?9bw}8mWv:aC3;FO|?׎5nv8(̮啃m88cq?Ť/9q~H M.*Uw_ g~Zu\o/WGڦ0s|c'Ǟ.-nr8bFr1(26nqsIޠ8;c]Hc=%{vh^ðIfq62IX|`nq% O+Tb0\ڧ$7c#n!cn8pIqzm_QKR~@`3`|l t[M,&YdoF~Td`t^v7`qO95S"p Ќ0X;OIkn:sӯ_o*p?xǎ|*~[EIJ>8sڌq9$Qapk. rF=?p#t=&PLA{W,FHb6z#q'hc9Ce9*x뵋#ܨ c(ߠu$m]o}82E_ 8drW#Upg'IڪI`~dl*1=uG lgq:p;[+}8[Íx<.@0[=qH0A$=H n|P6A6@ %$g>qЈwS9>m$8=&zm s}WXP\cs| d W<p]>@c1s4Gy w09~F$sT p?o8P@x=}ABa8#FzL8vS3g9>p@ǁ҈JpxQDÝR%+kq, Q]nNϻo>3 $ 0sO?~_ӌMH`TO+`N> #u* `y< |qKT ʬ#<7?:0c0RУe 3NҐD™P2Id@-8d327O1o TR2qI>p2sJ˴yϞ_z0cm{.a`@<W<0Y`ҤIAOEEϨWp(̅pyy#UGf(N[b,dOp1p8:y\w^0tꑂp[* nsRC}8g AeejIuWmlVhL,+~O8zjh=+ 2_ PVھhܶ UJAC BVQo]N{gߜO+ IW de|gRT|\iHi5&^7 u8R%40UG"GgY3:3)?U@c7ZMQWh K Z>vV.Skble Vz-C4t^BeDDTCNtI#yJ>s*A@uEehݑ>PM(lG u0YgX6Dj2uJQ d@/SRK{~{ nQWpzZMZ22-$?8.T3~>]Z ASVVRnUk#&24jzA-tzgA˵݀ԩGnyh5/pQTdh539jDݦCjvJH{d> 1)ǩ#nI< ;W%'ɐLO,,1eH'hN}S lN1R@+YK4a CU{hБS^5pi&$C4`ilcAPJ)2AAqvMo@TZ5x:ftךh [lhE.TK6l詒ZT!3vxa$pt 勶LvgSZ_{n.4B^C =E*Vv4&&`fH"ghMVɿqY6V*v٠h.N)<񷨱YAܟpt2]fhmnT#4$"\F9F48e\66vJmUmOg5zStbfhfF3<;ZS[NO=/[)cd6UI<()e(K2D1݂OXViDzcOmjI|xTy@$Q/ #7xAc3W3K˜^PHfFŀ3- 9$O*8R G'c,nF=_V:4Y;ڞA[dnQCqߩ,ގ*ʊC5s_rS߭%QYhlg--HTQ\Z)#wwm$c#TVtqrm%u&"8v+8(-G#3F8jҽצv6Ku 4UVF~"F5l ~ee$˒żA0Ua4iҗ p׆QнƲP\/yeH%0K(TXں G黄5+2)J`)ˮU%Eb]Uk>F֚TVN\O-Ϛ*ki`T :8%t I7GKB(*hG*MRyUr4lΨ9e8,L=#V٨0Hb%F[F; u4Q=\fz iyeMCLOU_W -vU$`n~?Nx:I\8mI'i'FTy+I]B 0|cO ~yjl"=p;Lެ6\eAJ|=-"m@ Ws|όI { n06 :XJF0~0G< 9&FKcsd 2pʀy#IQ 6X Y ш6a0,2G<ƻ^ONq JTz^'e020GGJ#,#ry tXmC9pNOg?K|arrr%i]e@>N 1?\8Eo d ώ2>yQۦEmNSBb4%Kx]aJy'v~2H]Tzj#$ r@p?땂RApNSO#A) H@9QyIb[gWӚu>v1CA'9:Y,JѬ`aK@V16w{@'>>O]x]g8 ݂H':FUC~cov#S<㝿PLpq<~,I*o(̉@a <<`qJvIEnjۭڨ ME}Y ^IO@79y a]'|o;|PVT'35:RԖlQA4U^CO5ھSz !i؁2ŗҾ֚_[K_ã V}n2O==;XXf uCiBN`1L `ď FsDҤKnm  @H(i86`<(?~"I" (gvrq)1  oMI2).T&8'2N$h'9c8`~`g#?ϞYANpI x,IAc* TIώ9. TH.I+>1pQD9P<|p?snQT{ycI+*g8uʤj3$ grQ AP/MS:CM$flQr;DE.b/Xi~{qUM'%_jgfV==gUSxr;N~)t`olSQE;m V*ç*T c/-=]zzrUή}V| uMߋǻz펗)X:TmBKL Dȅ|0<˚4e$,[IHnfU ~32 W}Ƌ ;?Grh-TuT- $]\",V%F$~Z9pi]+iv}j:jG祫أћuBt:=C܃$LHԎC IIIO  (PIGIK &Ԇ*I(eP$`$ J#||χxfW`X`@ $nzR@,f\˖vΕAoz@]Q#nA1wr8rpaCAvpG|ZH0<~0o!/d PNp1_?#@#>i{ttknts}kn٢ADYQ&cՔx F90?P}^Tkf3QH2H̙[0Hv!/dA1u!]@#P)Ouq34BD(E6'z{3 :CGv}3__o-t7 mU$Ȧ2Xp_cCI_OysVQOhuR4̵9#,%YZGR HjaJv;VuUfEVCz277$sꙌ괋eQ{quZM:W8̽_";PT ><|c554h2!HAʰv|q2|c$~=10$qK -p4%.~JҖ_pq=W.ov(^R @$F=Is?'6lzCOn` %Ns9p-m>b9ZVB*!<~FG$OݷsѦ*`+hZFi_M\@;J7吹 TrXv,q:yS ,tCgIDV,ʼn䎉a,',TxgGcAAVUUO1MO'sETM.$8#'2NW;NT1ぞB 8*g_>r:*PHP#;s`Ug\k]ʲ܎- "`Y]rO '>wwܞi34}֪_>CHmGA"E:4&Iy&nOS m].(+uQSY| :&G #I-5`\_FXԒ)h<27WrOK6/$L)y!$$SHŒbi HuRN-eC"U*+#dYpKihր_Ku ֲn5)'AE:EUpZ *6%VeR>GSv;҈.KWF Z'yZ"LS,2E np4j{Q;wQ =~Z0vSS$0@J햪m]OWF饫PK,rp䤪PX4AR)ce?Lf%d.|=dM ѰA4r8s0I1iQޔ!Y 4 Ǝ,Ԡ MHg>Aw?\AOZv뭺5[q}4cbH 5(+v NӞnjJ CqV 5Mܬ:H엪nY_XMS4U"9ke3)ВdMw]cd4m~E4wj-q(١E̍DXK [sPs4ٴ]ђYꚖT:bE45>%;&Hܪ22Hsl*$"LV}ZX܆,R2 GT:RZM@V #rhc}_h]/::UvojƤ_.sEMUci$݀>:C ;h-ȵ-MSI!Cou[m]@4޴tn/R*7{/]Rj:!XQIUAtVA\UF[˯юnT[+1[U,tS-+QkC7i8x ?|OFȝO);®(y8fxRfF\1DW+M@@QagjMmsӴil%/5m2"%0"8ϴ_Uk Z .:R*('U)MS8O ҆/$jDCC(Ve!tf&hg`Tn H8X˾NMcLߴݺk]5,Km٨2E)f>"vaٌdžK<->,"ɩJHT=hy!2Xk qfi&VX+#i(WJvR\VztzިW0;39s@9瑜 uh;7=EECN^8JL떥w0|u4otw?izzIu7jkђԍ;ʛDDhCUȓ<6x3.\o1,)O=,4y+KhF(79ᙈش`KhY/`T.OCn .k]Y~W8,Tf{}P!SlT+#:ZnkZƲzzh =.LGe$;8]6՞i4ylV 0N)&Gq-UdKů357g(tRAtv>OB(}㤊27w9Xf3%ᙼ/W*BtP j8>`գfbE\UWP j $Qlk+0]Gе5Mlލ'ܩꂽΆ,E D.UzPįSik{[,Vhif`$jYU$w4d8PNNO_mTP%rZUR7]?mu&j1+"s<ł0~y ABa0yǃy>zN.oX5A;e 2I%G:S {L`7,qOIIRNv8 m q8O:Rl_EX{lzN)g 2Gx9xِG8?HL?7**@Nビ s5w w W sz:5,J?σ1IVH ~rYϸ$daǂzi+L<3>O$yEgc'o89?=}߀F>I/.8< 9nl?ǞqB&؊$s“U8>1z5ٍH?90bᘙ2JT*OI=t#UW-- ry9뗑 œ/33Obm q3уo#  8d~<҄džsG~1у.rK`nC<%y'$0p?O #I>c]9#?8t`F}G? 9#ny8+$aԪ('$68p ~z(ݏ9n@ $#ǟ=0IF~I'tr~0A>3?㦣37#@N78 I;1矞96BI8'.Oddt`۷(qy||tz"HPBprOiRc*d 4@0JJY&2h+c˻Qa>uN--Wv^vSM%ԿsfTuԺzjZh,MҪU_F*zsf1zv&/tmp&ҵ=MLXJ{fT;K4iI0[˼ר.7keR yۄ/M.4n1LǑ_d I#'11qՄ$ GiT(؛&Β"g~K37$,_8DTmPB(ETPTPg#nf  8E }Dhj)$UӔIH$`PHq*Z%$:\ ɡN\[ 2QW")*=&e#!Fk>jϖօC: 2g&8cwU$d0F*vP:wjO$TvN٩}ŷ\+( ޚK~ܛ*juh!T,#Ԟz^uXXָRPucF?Wf)Ғ7oVܠ}C.Bet֍Vv}ѫA\Ri }4WMU%YCi (窏׹1jmAs?nNhh+|8(cXjm[aZTzcyN\,se %U,2#G#c2Rѐn}qA%LԐ|r-7X{{wohҶSVPs:F[)jXSxc-xw۲]ӴPӮik¬kqs*a\U34bBkF+ݞ_5VkZC@CnRCP^IR`#`]#MYcYC4gS%eҕbR$u䧙DdaLf*2г))<(Vǔܳ1ζP]JLBt*?N吱P $Ǩi$I_kEN;tV-w d EL)FF=BWl~M5x#շ*=i_OKX^**ݑ %fDe#Ca(n"|We?y4v׋uQ6Q,UVmk = U'US*L{oyF5?p5wJj54)E*TRS:Zj!<  Q0N#|eog`ܹDXfY#`1uٸ5;yXޅzIvnni6Eq^._ hNNZ9*cR[D1iZ4wY-].&oGX%i q>v{r5BՕ3R# Y0OՕ/іUdGU߿Nik ,M_XK^+e;QI3rt>jZ;mZ6 CuFW 5u5MEM}CI5J¯ۿ?2LEbq媴* EFBW%U]ʠAz΢t)6IVARAtžzMAMmfEt[t]f"K|IQP]A oMT{xaQWK=C˔LQ:z2oF<Go[V[MEE_]KQ >YʽtT$4EB^vw=ս4ƓZjuWp.\zvH%e= ^%pM_edt%ZK g 0cDUW#iG5.4Ҁfbu Jjù}){ YdUzRSv{AhCn7X \aJ4epVv [ Y}DOW"\-2MAY %|W Ɗ7 $%ެc S]C;SN:[k]aҔvj*,3CWp֘i䫖F5uu<ʦ1Uִmڬ[Kml 4J˕TJO'H$5@XE-2]q!Z[*DBP՘J%PʔH`VJ&M.P]&pw=m;_鷱ƷURRzW[#TlVjBRZ}=Q7-LOQӻTSm5vQO_rmJ+CwhZE+ƅ{EM]InJXxyj,J˖m_Rhl+_iӚV;ZzMOJ}QWWFAPpr";$4bPKeFG*hUC/b^78Htl kM66e"Řrp1wx qcQ1&+2p8T=E&m]Pǩ%diKJm$ : nI%v1c"9H>RiՔЃv CpEAAm]GJ#Xcp.qdFA:1T݀3s矏XVls8y#,fTu# W>?fZMsE,eIV#N@O?"l17wOnjy>~GPo(|q2I?hQg?cK~c,8#TA޸|rq|>XA]`pT~9#|tzsb/l'u,4uVIOsN88†AIx 2U}y?K_`8>92xN6WoR=y8#q2 's g*͕ NǑG9#NHé>U 5:@|89 2F<㤂 x*G~sOvݮXjj-vH]T[⮊V,)!YW >Eԝд']EҴ8A@$'mO )F}G'JZBŵ,Heq\W I98TvVHYe"@|x=yﭿOM%MA [m155 j!ʶVݼ O߭kۙ;tCKbz嶖Wn*и" ރo%DrUŭ60QS( Զ_Σ߾vgp[X\hmDUP̦*xm31 )F:2qZ})zNeD>67mAYjJ5Q@Y5b'NXqw7Rw[-eeMn\lW7DƪLM-Zlt-fR.ivKm- tthd"\Kzu 3T@4Z2 Gb uh0n.vOt^8h(cDs(&kD 5Rbvڣ"sVUG>G鞤SQ ܕIlqp1Z,;g9 $ 6@Cu߾@0 {omsሑ>>U7OMFu![iOc |d i 9O??J5DlNpc 2!p0`2>Ilup(!6Ksh<Ӽ7,Bt #ϹqGϜ at6=v°P^ĞOצAFzC=+)u# s񁃟A'q1a:&Tǜul {X| & {3 s?`pzC*߰ʲ @Ĉ``A*b8<㞛X8o9> 8穁Dw*8| G8sǞ2I%e$`g#>zgzLhZ*Si.UZꮵkV0I G)'89pWVA%%E_sK] D#׫41Ǩq)NW=NsCs;|vc߶ jiIyDP+<Pᘎs_'pٛvGZJ+)y'!sS<@$XTN olnv. ]^(ԝG-NPU.~xgm`6r0Wх-^UP-lUE)*%Pջ.d\L)#yf3S'x[ՙ3IHX[tSU@K^D+fJ<vw:kJl5b+Uo]-meYWI&wE?lJO]P@ZuQS0O=:glR5¢Or*[@ij*#,(6$%[M1CNi+mMME "9*ʙZI瓟Ri#jd"*yUb,퓌r@'ַV_!^vI + i61,O52I+Bt jگr- H,I?F,2|{I\|ctU+wdX|g>G7G?9\td|10?~GI$rg?_'tٷK`px!y#&sӫ _ /'AK~x/UҾx0t"s TSN8U}RGAx7A<ƅVPv{Bbɲm#* $xPxA`BvGL,iRK|?l/b,WмuGa5h44VTQ5.uvkRR)-mZ#Յi]3ra6^2[NnU٠k]-:v2Dj`czژG$JM1ݴ>O*`F8Ik=;hPGbf%PMRUm-$2vFpNHI\1E,*UWѦ]rE+BT-,#P$wC# }A}7jʍ1IuU%,)U%:PPFq`Ju9B@kn}VŞqQSWVEK"SK?W&1I @k}`w~ŎEK+=MZdWI$0QڞiY,S]qjIE= 2 %T 8c+\3א7tYR]dڢ0e&FĂNRXfC[F,*5Zt6f'h~mLD\=ެIK*+<ՔմSdXhwhr5>K麪Hj F䎍hj$7$$G)1rzuw*ŧSKokͩdkjYD[G|+۟{Am=X[0t^=9dGFJhE*J!]G+9ee|o1IB4€h>I#J钖iQRlƪM$ݻ]^2Syg3z,L$)ʰp~3'gISH|3g*.Lm$0?'n>xI'm|MƆ=S16;HFqlG'iVs siڹ#-NlFb(R$mwݺw=kjjZ {T%eR]*š:yjn#H  7ڛq[shMCcy֚u-oT%KM8jkeBGpNH./; 1(!¦F G) .c2˰ m$h5VM { Wp4͚c7+=KE߻5s aQqjCʱ` Q`V(cd1\Wr+hhɣҗx|LGm|Gge#2(ۃ,t/~{Aæarr]G~?6vJI` (EEH's!wbBMBj#H [Nd p3Ygq,bBĉ^8b4ȑcXTZ㻚Ң 'Ͷ\Ϫ2ɻi-vx4;|rL;*AًuYI{M 2Cȱ[i]ۂјi/p$6u3Bkf˜poJ1bc57m)m5aqӗ[^֩nvɫ+CN(cIg3V  *@qlwi}ISۙ.wjKbTKSIEacZg,bv:nΥEMLMAƮj]qMQ0Z[]1Z`X͢ɧ #i-PCoiO̅fLb0CdI3ŗe%d#N3E6LPY&2)UViT(C)w`5CNچѥ=Oڊe()4]7؈M@RDA J"ơ957s䒡XXgRչ(2z3`6U0zл<}i=IvG+ϷE=4t5%U } (b1ʱz-vO _JA9&,yU%dxdJ"̞ͨzh01I| /XJwS;uG柢۬{g+iME营ZoD9Af#aVP݀OOUk;u,QSiJuL'-2UHP:;ފHdIV:eѬtn+x|Z㼫OfPҊ{ҙիb,b̕xC!,G3ҒL>Fo1V^ S1 44:T:O-4ȍ 6lÓ#Fĭ&#&s?IGdZOIZoSRVޕt5Pz $w VXu=mFj6&)VyVlXdՅKGuet=;$pO 老 h-Zʇ*js} NO<1 pUxD$fG˰V#߁G<{b1d|Lp'&{P|ᴄtKxJ^A*\]1˸is2Q*'џQ [}VAŭg:OVCpU{WABGYoYq$APaeVSH  UH'Ig)<&ya<`E0KMHFDXUu3pʄBQ48[+nUKjzOZ*OBCHX@|ܮ h* ѝ¬{E,%iZ VxL̆$庿hkm2pV5D D0vr(†F ]UAG4MEYg}mwJzePѢh;_;ihXϗk,$[M%ZZʤՆEVea9)$] NH x6=(it/p(z~U*斾H==A-Xj暞[ӍmqYt0 Ѻ,*9ޱfV.KNoUQCvZJ۵ZzihI MMRޢ)㊢A+W[x%+ :e -;16JYY Os"mZI!9XޠƖ]b h ap @p乜(l!3); 'lDJE#UT$_bzͲnϵG+U'rx ࢒eH_Q=I#_iam!UB>њ/HR61ZIh!Iw,z~+%eO^jԦ1Ueyy0[(2 03|PAYl̞^QO4B@?1eQO{$JAS=<$`c#laYw,@c^IP=@̪ێ=qAY-S[हie; E| yczCYpJ(yciX!ؾv-T Y;8_g~o`94=>}$[6eEY)d&L"r95Ed} mMm,ԔP-J$Y)~N t7D6ƯPӊ[M%$ 6UաTK;1]H*z)h{g$4W[|hiW^IS+[7,Tm8ed.mcAVk6$@Tn$,Y42WRgPadk} *Ũr/0|y?>?JWh8cF311-us0922Oɻ7ܧdp|~|t5s}|>7u،F8$'ASx㎺YYIG$9V*I3K g`̤BERqrqqPI8ǟTEsn=Bb[ pNNxtn!#- pR<6|`$qBL|xaϞ|H#鱿׶?^3>q ?ߥ޳I%wnFy@ 䌓#5& #BUT ͖.A[zPN>m {l eI9t9Br ][?s18KCxܠx<yẔ猯$3g]Gԧom:~܏v,F0F2^tzOH8c0frF)) #;?VN2y8:$YҸ]˅φ#< uj4(oB{_ r\dGFIp22=|*|HvrG3FE 7'8Wp88?qXv;|s#0PNἀœ#??0z08e q|T9l6\IUX.q:1łN@#$||ۤۯS®c ]FԤPq<w $> Yʤc0`2yy9:C  32II(p7.|;`e)< y$hЌp89]f"6OH4ЧTprO=0 x\p<a׫ N>8=30ؒ,`s-ہJS V;+1ǼHg'i8 gH+G 0`.х\c88, N1 `|ck79?Ihy?% (} mPW$>I$qуRO*@#'ݞyaL | fbX*1:hjb@v,Ķ@ @㨏p5К2i袯1Zj%xcRRPGI$ "6$rcgwV>1y'dX0<|Lѿ66۩{R8y ]* s'9MmhXݩ=5d66K઎I:'ݏIsFcC.$( A xHczGhҬG+$nlnp#KdQ:ZV1X2k,kJs=kT5 cFipq3+:^=w=ªէ)$Z;57ԓ]ۢ&)̘TG]8}ƢMYVj+hVuBLIcEkGW;Qd%a;=IZ/MXf۠҉/Z;YDŒ!>\#AҪ-*(Enɡ@Q;;qn#кFgԼڦFDqW׳:PC*0y3Rpʑ=W-=hTrOi5}uxcO]ndPNƊꞟŹ*$!# DH[jM$ "]""pT*D~Q:E E}v߸lPq[vKnh4Μʋ޾G:J25GX˖gfF*F+SEY];O^S*PUG<uvJJc@* R50Cdp`ýSiKf%_j.`ލWާzGh"*FUQTm@څa٘$ܗK ?~ueՂ};]&WE [mTuuQP53!+FijE#!nj}Fhw.AIKw>O5ڞD&9JJG**UiVUVv= X+`a5QWPe,UH#eP|zb;oŪo::NZv*ip%` `e`1̹ɗd1&kjTy"5H}R5.%#m1!W`حDh,84|zm.Nڒ+l}tԊeXc2FU䢴9TZC#l_uhjZ;v5UsSURwI*#Jge Y4|{U{Fk<ʻE5ɧTSӧ2HV,yZ; $W-{̤Q\'IʚƛʦŠlw+N_lZ~15\-k1ݍEL}8T ;O˵$d DY-3>kWUT66 +}?l>tk:Z_GJL 4 ZkG=#lT`z힚}]˯lv5ڎriG$EgYSG@Qvdy"g#̸ idr#WЁ@It; kyYLD3쨥\ZJڪcszǫĺN}|OdQQ%T](H+H' kyѝɹ4cL/2*dJ{izD$%&'DƮ_{k"Ogg|ΰ;Ր+ߥtJݨn"Z]-Ɩi"Lj`5 Tnh2Vh,v4v EG͟T૥'{J [^xMY2 =)GOZ槝G b7Ey"H2Ԡ ,CceXFVӿTR.7KMLdwRf 8IEO3?%)rg[ˮ;}5S=^j*M9c>2H#UGZ)ffC%;%;Tp𫍡®T*92PTpAFN?ۃ0>ЛWF99㞜֖XԖ7)*0l2 Frz;p>xpP8%?togU!FҰUFG]h*;mZʡ(iw3K I#/JvCއWiO.z[ezRQ% *꫈$e"!r9 !KEɡ@N@$ _mcP:$ȤdOMǴ)a)Gz#]-G]hvҒ#ڭzʙcx%pz&>-Uu嶢:ca EO ͔ڥ$;ݑ3WmQj ֨/3oӪĔ43G(I Wyq-4q&Wb{zKhebAT3IDj=jw^!v_C]A_$^ѵHFejhOvK<]_=H긝o#FGZB8YYU59'dlt?jtտGh /k~MUG jQ5\m 4~XFʪOA1O>GnbK Hɹ2#*AȰ)|ۻO ^ {Ǘ:C*~6];䙖zoeiX0 ,)ub'z74DPv+LEqF}\8D2[ 2IO碞2QC< ~~8PԤa@vՉ<(==VvwwHv[ݿ=m?LoqբU*Q>4VfM#ZV:y#j&4fHGU@g UXi yn2yL3$3bZ能0W tk=:671lJ#mK2B1><r0}e>08|u=6W AcMuT;K wm$q=89o퀁s}sJXM36G9 ?y鶮`Hd<Qٟ53Sp|g>F:hPC ~ry;U{;7w v?_ޱ ĸ mdϏi . sy~z54"6 u'w6$Ge s@#?:[IgmȱG!U40 !ry~ wژ\p=\`8\s98F; IpI8 sLq,AhSJ{N}r[$|LubL0nF~mI yfK0>?'֍ @rrKQTBơ/9ély8 #fߴ)T'~ :@XʬܗPAnQ 9k譒@p[$g#qǏ HXs||jV-㜞?8p9ԊOl1<sMQ>-]%ŠGSVOQ+o S+/pki; {[o4Vek,~*b ~Zdu֪vHjg2 #gFJ`yם_Gߪnv2JzJ-S[]A tІ@Hnӥ<@/ܙ uKa8`%8H# HфfI*H M* !kg-d@ f[Tqڡ5mA~? p*Z%;INv$cgCЀx)9_釼sNg ~y=$q2sH#\y{1et9%|$xLXA +HXnv'MR}80aPb1#* NGI'bWox ~3;0r3F9$bi\0k`69ǎ8Ihun0$I8b ʾ}GIg}a$ ON,%nSs&Ox'9:bd(>Эy p[#` (?@ %S 0O8\y.:vaUz~q* xh))īQQOLޕ+EA$6]+j\*Z  3$$_'v~i{+z{c![DP[b"o*#`( g$x|9B1G,@D8k̿qCN,@߫">;1qseiv ! O4mX& ,}f* _{i}9hzNѦ^!ZĔbST(ĵRVS3K;I#K { 51zSmPe;J&ڪaEA+dj Pi*α56=2FG@l.V!<+ÇYITחt$i%HG8٩Q 蝉~I:H[< ~\~^ӵ Ɗ9aT`uGFaUUAڻGdmIl'ku--T&QS>ϦfJQ!U%T\ Cw)edKp3iX33rؕT @׼.!_cI/ ~5+ 2@_PG!i3^'7P1P8Axe8XYus)I<(0P8s\(K /;r08/AU.y$?=sP0 e'!뱑q 1b0[ g#'dtO `7 *IxƘF0Iw`?ˏϟ?I$`AK9?tR=0d%YFۂfʰ0N'#s)CPϸ#>:)6@ہ%Tp[ ~ >?'@߾ (29$d<|@,3pWoBdǞW}.PPЄf:J@a4̪Uvmq/e}GIWJ۝ʄJԊ:4@hl嘒 cd Õ('M8']6q#>zA*0;T Mf#h 0qQQ>˶4WV/1L1hZ:X%da!X ]~u&集r.ĔOVYGD)K1S|^S;21PBICx!T$p'T]b$tHX:͡OWPEf8X㑋Bu5:?'u^5E"]d[ ]@mdġURCRN\H#(ζnQ^w&+ƙRRRjvwnpH'z(4ŲT\(骯 ]e}ǫ'hGų=2wc2 +R2HϤȪʌlR (J C P,EIpGOu7 ]_`Zk1]w+4G+kөO h O4N$FS*F`ud/nfHHU0SGMFHܤgTV=ǹ a+Rcj{ulVڪu=Viy#ZWZopJH0ue @9ٙ"‘t."8U#FC!X(-j$m6wbNY.eUbJJx4K4yo&e0,=UӑZ[]5fIt5jV{":(ةSoPA{Ι%I-]2j==;[ t1jc_XH M}6&]پJ{eGlSOh'BV.k6G 5fef;.J?Ύ"'Hы+$řFD*>X ($](F{ɴnfXhX\5 [wފ&DE0kRA;ݮH#H`>NT7FjmywdmJUTʢOFxq$v yS2 F(۟8 y,9\4g IX6ME4+r vl{wo yUqq'AA[1xshiSYTZJR8щ~ʲQKl#v#U =c,rS'-|؊$ x+ݻ* q:7+ƒjҚ~Lgs)f<Ef( |üA1'eiAIZٖ<38懘z4&=d-kA)@J\` -HUWE8 ,O}ʁ:>0L )p0H9N[NQdN%Z*YBD&ZQR9O" 0QpɅ0H9Q0_-01 $=tVb4A|Fc8pyKߨqCi˜UO Ő65L RAngXg*Q n=zJ۶x%xfY/UDȡX3Sp8Os HrIʕm'0x#`56]o'Q(q[~@Wv =QmCSa7KTR%cv)1/1=Y@\+ΤVz:I@aQ:oORۊ8G; AQO%M(LT꣝NCأ,R-?]U_dBimU0G('nݼ(P Yp2qʬr#/,͘\jZXTdZ5f]'QbH&&0G-2HBe$d%EUV6P3P4%GfV\Շ&0 Ǝb :E%5"HR^@ !| bXjrݟ ?O9 ddD"p1RS/c-{ *{*I; µjH#S](>`UnǫjJBMux`GGǎL s뗪`XhrfgK: q3GFq29\X+9<P; \,U[ ;+9BFفkr@0O4@`}e`gw=D܆&FGRnFZu.KzCv#z<85Da Xm;Aь8ildM=%$ȒSjj2(̊8#_TڛulYiR! W=D85dVsaX)) A8?`qzh5B=KHP`gx89g0s1Y7!W<}zWUQ=~]0[|G_U[1# H$edrq]"PaJnÍA`1EA9#,23ex`'? gB~p2ʨQ.ANHS=7Nq{|GN: VOqإT+ϴ*p0Fx+2`_y> ~%@q<0gu )gf #qcSjPd'5c:߭޶Т(PTVx'8 c 8dy8>~qte3䅑"gr$q19 ] F쌅SxF7շ6}paդR/>J#` (eI1I}DdR%ɐÐ20@ÿ*7d($NOIx1߃އAԑsWbxtLG}7 (N`3Gσ_rJ"rxF@:hܕ {rNH#GsPF6\c(#p9گ؎o\u' m\ހUFFv8  >1u$ qdW IЋ$@>31yt%)q8OytA܊]bo߮o{nGro='oPǑF23r<)琻H$!0T.e9;m$G@PW gw#GxFE)v rPՁ砅=n㏨ƒ{:r&\mQlo9'#T HÃϐU-̄ r@8cV(YjBQYm im Uܪԅ 0 abh]}`M=ұh{\ UC)`#p}4K6fX--M cca(ʲ R`ɧ&@#V-bF"[3ojJVC௔;{^Ieffʺnza}rp =ʒl?q=Gh- ``t9be:HS>@r8Wq$czǏyA#O>zV<+ 6rxr]v `< clH~Oy1uE[.\7Ju6 n$Q-CMQ ?XmYA$BQK1 MrphId-uF\pFώy=jlI6rr2x'qࡽ%|+ke{=੒av\܅#. mJȒ+xBvXdd`:ZEEa#GlM=E`v$~:Iq[(U,T0MDޞi`(8ڰGJI'-pA`Ϟ]N\D.w˕*EgBҲ_"Q4C $m]1HPX$ʰf2G DMSC"*hR >))$0σpy9Q#<x1H%VCwfK5P5LL0fsW:~p60K1FsO@w{`bU DnA >Hz:=Wm6cl|AC|:L3>* NW IUdml帱9lmRIr r3<zhPTWctTG#~s(ZbNbl,i-1*G嶝08'p:VB}=+m\3g03tN@RrV劌0$~>BRD;u[k`]2Fhm{sj;Kl4쉊ֶ<{$ */d 7u6Z~5xVM6,ָ9-8@ <_zF[64>+UOzS5E\TUK]V"xUHUyS^`ԋaTzt7?bUVXKPP7< x umЛ54]w(}mUɶ cXeC<1ʳ1U*)/y4Wcz\TtlZ~GFd &q2Cqv~W #Pz^U_i]% $4^SYkPV6#յmwuuIjzmCy5q>-~c9>ps_0NSmaUU-Zi.3'Jb::)FGD'P 4 ?_jzkΪ4f@"IJfWl*WWQ>:"h5EO;{&9DOsvh"Zj+T~&0і$Y#p/:U"z c/nUW[m_ y]MenK]n*5UTM4hޙc[)R%ZP:e^)g3:ul4VdEQnVuDvm1 3Ce]xT"53l@j*f;׺oV3NOsʽ!vSx{H_YVWg}!x~t=vYi#tԮ'q hi^m *ձAPჩcxG٪IQar+it枪Qo )5(3F _|1XkX}0`ߝe<4wFZES_l k)Q$T#+/D቟s iD|LCEw3uaHʮY.et\KK #A6H@ EmZk\[:75 ZCȒF` vBzݾ1U?]ciu]Y%-MƞRR#}u @(åJ:gYZIXtԢmVi7+EdiMT[}u5jyZԘO$vKUD{I{INm\"c-?G4rlZvY3;YXT2RĦFVUM$-솽^%Ib `U,&y[G7 U^AkRRGnvi^(R ;q%PEj:"($PŁPTS--M#"%U#J9 bc0M1:HBsLhE_,zORպr(ctW;ihoQT!Y7ʰ:iERgq3$q J`R'VI,I&T#}(ӊeZ=i+j=zUA--nkwJyi-JxHHco4O[GYO_IY uuSQCW E=,і] 0kO_rnj=TS%AKqtHѡ#xs.Yf=J>5]GʮnU=wM/!JӮͻV=A j  wۮܚCUmAqROTY9c`Cp2ܤ0V:*-mu_o[;rľi]sUQJR]+]Dhd4S0<ef,%aE$ln0d~Eu; IH$lpys ҥho7@Q؎6A!ڂ,:aBT$y~_w)+89[@QNJ8dH rN"HTW }Y`FA k#w{n;WcЩi a;y@sj8Q\ <sl3( A6Ar:w L,6,@3]ێ/ް-Oio*eD ,FHḪ F''leK޵ҵ֪[v5SEGmPmzZ#fS,qi8>}E}GO03;-=47 0M= ,$c;*Ā䐛Uϩ;ԮʐY dHy*Mdg @ |¶$Cz P[uj`Ȳz Et 8-YziEKO9jњztjPzxhco7+zNm;sc@}.놘Mu¶<Wt\5麉!U*G'1' "g 3@X6\/`A?9yIvRJVP8!, 6ޱ*ƀOjJMu[32,NW$I w»rvs`:>a9 oՃ?t%Rde2ā|`c^x ц2W G`(I9pAX%1B1 ?힥S`Ta8If-Pw0?F=I8gώua198hZ@TFr b'#9S#t?.8pv;%VUG#81p\8$)$&He@mvzƀ<LI08'XqccO䄢Ȧ5/8LqF;yXR$n03y?VTp;~B}Ij},+MnrI`|d0o2԰IXDea8n zuL#H9#88z. SS2UTLA HG5fYF%Q#`ϭk aݮV-5c_!j%,n!ՕLT夓< Dk{_b׺n{.Y_"Z׷Z`g )`_SZ\TNvɦZ_K*4yӖ 1=Utb ؾ}6۰6-Ck=3^}H6]AWksLʧ22X3QLJ`ڊQ1!E2(Nw^ .݌Dg(oʉh~w^ڃՠjd&\q4 Ǹ,q.#@6 WVgb O8@>ªŧVnEF[-,jU ,z}EʰhL,V%E;")KrRbH)VF y-T`:--)c-%nK>ӔEdǽEjjEy vuxNo~$eRy0]KYVzX0&K.Hw{j#~6&F˕}QCg[u+OAo+aa39U$$|ͧMnQKDC8o⚮jF?kߴG!2ENQ;DC;_sZWV],|o,֩+u _Z(zz)c YXGVӷўZur!պڢI y:n4PB-}'H]BHZ!o1! #f HT2%\ `IhTj$Hmά`Hc`pGKGmap<֛ՇGIZ*]k!TRA4ؙCSO+1cu1֩âf A;CeI]uM_׮5E*԰{ıpDjHvy^?$ w` %rT d, u?LE+fYte-t5zKY24Ӭ@NTt(p ܫ)̊caTG)1Iٳb2rۈ~@srdQF@>O3-9K<8n;pl``!ʟO#ϞPVhf:UZK|\ƗtbOks:^fU*GF3禨*uRT%5.PP f. Fzs w6HStl bzkOHv'L.ƶ-֪-UŎYDts @)>?IF"u<谭-=$t1CPGM F4 JȡY?'!FBܧd=&iJ2 ءDj,lbI$1,ĒI$gg6Ě:P@1e2c(N *PIOyJ m8$[U*rX=#6 C8q |sF(vuT$Kʖ PO\7^R:}ivAzGɦ9,YG8'M`Ey$ G[bo>UVqkUMMmBGOI TVI4ѠXTe <Svʶեuyi#TQLG2[ԙ (vEŎ$9d(dY 5;E8br\𻰣VI@hkWشXwiI^,3ʙ%E O;]~4}*tSUPT굫_y@HIņ$-1#mJ)lgyig VȀMY]4I\"$CqM)ܽ5%WRͼAKAQ,}" {H#aM/9 Z2 [BAeV`5) [fIӡ8<5 ]@P6id.YV\7q IG,W*I"1)BX#RbribIkoFAg#dQ(gYYd tkDkzה%lSPS%5% TCU=IS#6ebMv{}\U0X^) xJd 8ݜs܎V 3f= ˳֡YNw V!GPcH1=X`KUE;дצƢիk5M--=n)i3m|EKt8j Ci{jZZBfj:KE$ϕWď6%A6f`lqI|cUAyqE)-%5dQUmXdr7yIK]<\nDEP ȗz 00L$7>lol=mu-cQ+KLK {f;#H)ZNӯ^kKi{VK )em3[$>nf w6ۛIHQ[>ݦu%LnC44Vr"0 +&:֡}ilfJ ֮acN1@*1pFs94Yr1gaGO)gH/&IĎb %i@vKA&G,*[~奠uӗZk!/(x*A':Yq./wC$Vƶ9 UvEi´bM" cvM%O)!½X)%UDbiLs,[%\:%٪=S?pmo3W C!5Lvc$*Xw`9س9o>\-|VH$B<"²0hi\0ERj#U^«Ys* j4NrH1螝v}[mKZ{H 妖|c)rn#'Re~G#b:[j=ӥ,iO5"x% Uc2~#`a \'c.#4XZ5/!nms>PG 3mTƅaL}~8VCvS%\Bp@1tY0G\‘Qq|;rV?#8HSa5ƶP[keMKWK3-ڕ}Wh G $ZZ~g{%ZdM AN@8tܴ&(I3KLc.U9r~ͤ_F[ED 1Zx̠+gi822FwSYQ$Ӱ)G kL4֚Q؉dr 봚E3Mf  ,d8$ .5ڭ7tiZHJDォT﨧rQHm X6{ARJ$phn[OHĔe ?9UIɍYz:XBT?3{4ju[:K ejUkهqчU&HêW;FwT7c9pd;8$x,0yQ%]heQҍoܡo.L@ q^C $r$Նǂ؂e4Ta VG AOx aC5UyG~D%=bJ!;V<\33Ԧ*y4{P2F2[<|(m:2"ceeo+" 8HPqQ+E[n3$J* 4UwU|@Ic+2*`4R|"P6@{&{%δ: w .qQI =jcF$FBޤNUC+Gk%jִWʎ) R]ESH[R0YCw,Ri6Q7p#NYB{2<=TwfԂp|ȳ9sC2F%7Zؔ%V0P7 nJ`[`ЦlJ8diwyqn31@3RCT58H+TBc2na'8SOs;_$]=L 7C7h6U +iRVQ dZvlR -(NB\OwƳiE&,Ғb=%5K!N&g[F̹cK[)t7@@k Y+QS: br P1㭳&t*+b{da%QЖbBCgc&n6٠(㚚DcU[;JFveq$bՖ Jx^k``8a6*0p[8S#๹W4|/iVQ HGך2 ؓ% CXO05ma5^`u0yY+N}0t˕P'@tM[=5\23sMt((8bHNE+ Yc<+g%psgی8]1jAP+qFsFyHUD|{'nJ<Z|hr<;<10rF1|-S8Y$d3уZc,pJ  OU`l%?OX?~G,)gtqs>A$* c?׃*\3ϏwRlH}I8F =&2;g#F>0ņy9$cFPJ2# K|sv%C0x븤@M>vW;v?IViArV \1պ0꣐r?pq:_sӾXk?|)' uorOU6F“`F2ēyG=jbc-g|?F}XG;kmą$A,6<q rNCNq$c9RU$qs8㮞8P0Kp$ds:@8;aMU;;uoұ#9hϥrWO!;T`.1F7r~y ~Nsmjj0;ʹ.I ҨMe9*q*Y|>?/WCۏx~Trl$$9OQ rC ,rHQ-<*Ӑ<ݗ '>Ask;Y8%A;3pF8H$!:H<(8;N9%H\ʂ@!p<[99?xokoߪ $s??bNSa CH, Cn RYNJV7c\n'F㞺YVDwpFp180tKVD4RASpIDPbI5,#*=2H e֢B;tڂY-&DqTMR0Jtw9& R)iOkO3Ƭ#M؏ݜ\H#.j;Uj K XezK=][L5 r:dĔGeWD&=fx? ~0%ȰH@)gT @TR#J݈u)o+p}%`Z"Y7֏͛TYnt5npw%E e)"w3&!HXw\-outQ4qe nUIUNjFR88 "#QOmUavk΁Ju塊%ivnΛ#rFH. /Ig^ }cԋbYJMS (VR#vJeB"LLm,3b%d"BaBd&_tQhuعT8#r%6З?tA&sn(ahdYzyv2zgPnӺ-V)* i㌱534B€g+OfEI:sPY5%],ğq@U6i>u B c $-gpn{-"Of*pID2q8 6k|DP!Q"7a{XaȒo70˝\ d*@Oj]; ]vj-U|DЮY9 DMu:]ӗ+4F^pzFo4mY#YS:hHHaWi;k+ܝ[dR[UR=Z13Ff2Fx> acTiX.4IThedM$`c6 9d 8yKf,yW,ImN%&/^Y 1$SiMNKBٓŖFж+ijRR]vޢ#MsYYUQ$5Q1olȡW[/Gg<+BEeYWXFT%&ՆB잠U;zΚ 4Wp-T-)K\ʔ3DO-fgGYX%X.7Woࡅ@Ey/wsk;b`Ǣ¶ =5Wm$wh%S\he" 2e2=)TLb-f26KպSznM5oT* )"&9_LԒxK̃!E2mKereBI+T8Vrnī_1"k tIF*f I]KWcukV7j-*tk }Ǘ4eҼ$QT*פOtRESQriEfPJ@r叨;#luMIloVOjTYhmCJPH,~KT{Mj{)햲LcXmai3g:B ?#99>"b >E1%ZE/<4T4S.p-dP1X{db}'`+㭧LQ gi Mw{IەeׂGN+-i)'Zq*hH6ԅ. \_1k[u%꧵ܵ: GNܮU-mҢ4) lS[-ջQX*53PRKYGZK)䍡M#ȫHWi (9肪ٽ-|+r 6$hXogz[b{[{cPU.TIAU*K])7ER&2I3z86Aq&q$::l L]1`lQ<{KY׸z<ԖԆQQv`q\(bf9eHY@fhkhֶĸpzMuVk^i4^>ڋLCM__*VU-'zR m1ƭשQ; 9];mTıS€)EO(D H 9ѣݏwI~0 ϏTmU*P/*)@QaJݚ^_߹b\ e`A'A<`p|#=3Om(@PYN9?!|p# ;:~_ @uTG'|xߎI7~T~~G @ 8 ?n&, `?D檉NJ0'<ܜx)ci ]Hؐ,dW'jlKq+d6܆$<#u؅@T(sGk}!MVb:ѕeu@8Zn,kNe}-p JE,V\~l+1FEG~= IkD{ncY\m`gbqtQƒ\gTi>G䃞:\6B>#;I#$2sbhQdlg^MzGkWԨvl#08Ɍ"]D /@(sHQ9d?LPUA89 Hx/J>П*FR!*=0?ihq,ϬnTi{l+$`Ls0w}ȃyYjo46mcDf\:abT<R$,pʃ7җl$w#ZdOWAaiYnt"c54TQCqHY#"mf ]csK/ML5$AA28Azn>5Uwܮp J{֨mSOEO@\,gbWT%=wI +R@0%pB呪e5 " IarFzO< /|%<{OW!"@HQV=>$o;,S,wܟtNPewN9~fE/>tkJUrIO$*!l1ݻv?h ɳx.IHE|8`㟍N'K-%3O8<)嗐۹ܸ#<ϓ2H˟9݃Ok oa1ܲIrk`dNrOs+0gPcm̡\~ Hʀ9V܌kAWqYۯݜWW. w!XP]8IսǢ͢]Ji!AdLѾ^5}prznZ{OMn4S[&An[d đC*}v1`+. Izܪ&]+*%fyeiegc1i0 o~'B6nmJ B t I&$o #A*wǰ?xtm/øR5mrs+LF˝s=3Ԓ ɠtZ )-zvi؉ko9&jqMzvNUGm4-p"jvq Vk-^[}Jw N.FbuA2b FY30>R]ypen@lÍ@YZ!F:b $e%n9 TVN qUu~^U]D2hV[ $g ) @*qdZRd+] H%CggSFvoKmV]vq~b5g`CNѰH̆7;v2ܒC`UI c08n=^? !љu|bi3yQ̳f~hP;Y0V8cѮr@ެqt&.QmP:}.J9YTC)H)`Fc`Q#?kGW.F}\J*@l'iv8 xF|3֞S'R2C!f6敥ڶP܋5啦s#P$*UE .H$y$qǟߤX{UH g'|xMR"ndKiv!qS!PJH@ǀ1|na#áLdH$r8~Gx=!TVx1I zlie|!O߮^ f_Pc(8/#>:0acT}WώG's#'z%*a GMV!b xpGK$eN.8G& #P)p$c8I6F}˸G JenNU ?1# $,P)#h 00'c!ݐǒ0yASuҕWjXTwUvI cuC8'! H@'ǀxՃLUM *BNbxZL)èp2ι\c4/HZrjC,9wTy]QKslISYs*ijYc2S4ʼnun;uFCjRcQQ%j+[T 2QD*H:N=Q,7kCOd=I墊; H#=Mʦx#D@{QB-UjZJYB6+%XHzZטfiZIY8\1BbK33>f\׈>k,шEu:jG*"ؐ*.M`ubː 2 `@*C){m]ʪUͮVc}&?h!/d8-.7/.Ǟɩi媹*iZ-ƺiG-CFݑ-85I':Ѩm|{U]ECzzUULNʄұRUBN9ȗr~Utf(4LfƖ;VS<,57%}[ʛ eL̴/tAm_[&s9[5]w!½lt"ԘWlZxf_$ȳɟHF6H1_1e]Wuvalw U6 VWH1COR52}!  m4yjuT6}Ji'%VѦ2mGBvs6кCvUTV{EGI4-n (e5RM#I Dҽ 6L^dG(CV ;ڪyji UpW|vYL;1;Y8YdwM#d+O !2Fdp5nژ@m0 |C{}=-ۛE[IQ OZ-hۃNHW ;;+q6U9VYju$!Ii LR6"P$  8߫_Okbjkcm+J{ +tX]`[ަ,BeZj]Fb;gU_ (dxq#+f^6F3Q|QLU]+Bf̲5N䪈®@j?H<*Z_;5U Mnij$4%1fXRHvԅK!&MpAܻkfѷ) Xr_]'uB֤2#ci/5oZ KX[F#$0zE d@B@@ K|iC >8MȅX9/&g̴f%4eq ՞hE%gY|:iJ\c*X"*]Pes$zمlp]R,Zqj{ݜI-,K8FJ4k*tYQQSST@TBBn\{Y R0$au -ng7T,X98'-2NJ_nN.WKAlz)ihbcZ(*o]˰1cfy<ߋ 騔y^ $(`وuzSM:yPеKS(YU iK] uauv\?Z]=Q%4LdI&a 1Znut;a3ƷG]&n%@V#r|'oulk,Z`:#U-й6RC"Xq" X9Coqli-3<5ȭ]k U2Hd~:|2s8g7ryo"9b5˦g4aIleB{сȄxB:l/ z@bŁ1R+WN__#&Y:%'b.7Fr2spRLH2E dݞGPwM Kk`5n1U&@j)75Szq +>]ٍ+Vݯb{uҡf2㑰gw-*%Èm$E!ZIe!lׅ|c*5iRfF|*$84dWk<X۟s*&}!ǜКl#ev.7cpN 9(L(B>$F?ס3Č*0w>O]v21ZZ ;]i⬠WCH\x M4^դ,FrۅEvJĆt)F\nNGm,s998gV}j*z;a[3gH<2#GUfYuU^A-$fY^ RX1,xP85dRMQCĮf$ s2棔r0¦!`YwP:9`MN+䂍+]G51'E;1N}=PV+dw9Z~G"Ijj*"_֩U,FJ禋;_OCSUo1IPՑݍe%YC`^EٝP3ӼUnMw):H)U̫m:?h" Au'< -$ pI"Byp%ChtEYrѸܴHYt}vEK %!KjE;EX$xwrd-ٸ s'wF۪$TuqioP7 y0خ/m^ku4k%/pfT001JKv*׭g+RuWzx(KJ+;y=4Y-U^9xXG^$0B Lj6frK.kB#HUbPw(ĩfh y؍Ҥ@QG9>:#o H, Vy`7c3rO-D,H 6?cH{ﰮhn:z'HҽR3*r >rFN3$a P R Gs8C!9 vH %$c p(_pjm='퇡XHIP܎8A>H%c"4Rv FG |2!;I~&z`$@9 xN{W^)v>H|~G+#>׮eI<I?OQeF d?#>ѭQQcn7aqcO:P~W߷zwیHxfT݌Tpysa#Fᑍ~ q1ը}U@,CrNX) x#Rn 0s)xpkDU;TʡXvGϐ8LS c(79~x'0>zO$l$FrH?= x-Ǩoycǟu$߿Ա7՛r7>0q99+yQRTyx?-R[ ˇc,O?IN >H*pW,rčA%w9V\=L?2/wq+0c䝀3c=GQ9]n9 +0spN<c)0UgRNK$8qρ Hl(~ĩ'_Pe$#|zXjySAFGGBLngp1d߾xF#%p[ܸ#F Mm{msסڮPykJRDXcA'€@%qg$rUPA|G|99Qx F2H@GF dF #:/( vrs|m@m(v^/ҾX4usZiKm-%5e"C%s\jqhFP@fGX)dkХ]5ln* "?MK9i 22XPNzAIb4[$y2O!IWyݷ#qFI:mOZ.?aYU9RPU4(b21&$AM]Kj-" dQ]xS?lV .yw[mOq5]ů2SATiEWYv.Y1SStWhqoLWT\2+T0llIi dc辠j 햛_ MY%º$lUš zhAS ⪛Z*ybV֛9(uZe:"Ę;<~#x4^|캆J<ʪs.Dq Ҡ%6/+ā@3,$6VIX#:&vC-W:xK]\4WK|D@3H@VpфF^2ۇ'tw+m7Z\>ؚͧ*eoNFV"IB6#oEi۬$vJzፕl(B ؕ8⻼ku*+4]eH,*V\*y! G4-IrAii|Â!`șh\a+dvA==Oe1F@(er-u_*A;h9\c )ZdBdpc=o +G%p xCJ#jt8/xWݒ\0ZA[Yw&W뻌CPseV U<ȱS FD6.wuqY; ) >q smʪ&c.hsffvyT #ơ#ݤsUP`rp RX><.ۻ?u[Kg;QN}Q5P}TDD1.]N$>tWok.ٚ-= j8dҦAd [ DѦ*2 X\|8|cUw{O+)ueu!KڶcAP 2U?UV$gA|Bx1Y"I=MQN=H!b\E݂qYUv @tTKW GZGKUӽ\j<ҳR#r14m 6sXwJhژtVj-:+H’pM55lg!YAZ|썗B}de^=t]5EYf6EC 5; FΧ,8X@i١R-֦V+|U4WJZx)F* 6@75r/V89NOEMR*ͭ?23X#pԏB- NʭQM^wsO~-)]-jQnl#@G 1ڠkV}4T@$q[JLj@rI!۴ !ˡ p)$1nm, ɬtΪm MQM*Jbjem"VEe1%TZƎ@`v {~H<|gz0.M\uUV^D.Z7b;GOI ::qOI$6cH~6v%#ĐrH:̜UTtz0}R)T8Z{<"$RmƊOE_k祑jdݳxhKB0<3J]9IkZztQЫSʪ$YFŕpYET jal/d]XJ,YޯB@y{v#h-Te09rHK$( Dv$竢FMI1S42C$BHS!nv :+i۝% rLB4lMXJ#3%ZZ-=M-("2କ1ñ^Ok3)pXI1`CQ&7xU}>ROt{r9U/mm{%mWJ:3SRMYWS* )*Vr̪#me<7PmڷH l|7'E`,DTH8<u @&H aQu< =HGOr{9P5$e6my(]K$ؘwzjͳg]TS9r9IDs"Tl6HeOG䜖<$zoV)Ҧ̓R.j;Ec6)9l)S7kڊ6g7 aQY+yShKDc xagq>{?}=4ߤ߻+ԔmoZC,(ΰ܌b=-# m.AHWjk_XƫIikޤh6Ai @qRaEDso~mW.'{L;sJ\$ɥ#$X('f daU$%UA a^\=}4@$ ڨ  #Ƚ6*=5'aіk|JjeTUc*lyFvV- m$rf.wϐ?c1nܱ[Pq B8MΪgf+m#py^Hw'rz$w??j꫽s=Wq|J*q>?R%]{$~Q{nn93ԾCF_?>376bq߶?ϸ!EVߜ'@;CԞe+6 c38''FO=6RS*,-9$~~|u/I8 8 c?)vOl=EaRȻsZ 7r8,UG* A-Xp8u5YT H9$ǚ2IQNOw p**eo9Ǒ1Oa 8>?$A_Him@&!(:AMjϧxcn6W]_12jc=xC8hQ\|q_e9FT*?ųώ6zR,${vDfex(J%3F>G'#pGx?ӟZT`veb:ت v+ ;8 ?^G%O4s/imO3} i^Wid9] 8J6rUJjaQ fytb V4P;7SXH2Sr%rKs98'N:\@;H?so0ݝXrUV" Gl{v/R7m;}Ƨ]LKM6kƗԐvKN O8ϏnnM[:Zv]NU#5]%4QavVoxSNpV)!Fivvӭ~=L-PZh}fI",BK@tGU55 577@ Q hb1VjvRhԒ}$ JCchmU.} Hl1U}omUjkk&ݡ)Yh'Mzz⒞VIK *JثvtԾݯkDh˜*.PvF-LһL:{x.?1ig˲ Y)]u` Gv nKVEuDtN3=em1_5:ѩeazQKjʹjyԨۘ=Oke_;[iTڪs^5<񬗛Kɫg(Q7~~uvNj ^nm1h aW d4iIRDE\U@dc9ywK6$|A-f|˭4+ xP +srȶiTь`M݈6Y6m\TnP }.1G`$.r|98mL +sp@rHMdN'sGq'~ vnM8K46G'+~ @ -B$lL|9݄dm QOtSW <`>2l78=L<`I *bǎqsuu.**)B'&ZgC1b#$c,rwpO'T6ߛyMR $Td~g+&I8PK9SqHz>9[rĺ8*}hY|r+BW7F$s >rp.~z`10A<\tS;"fUr{xHGMZ <$g;ݫq\7}ޱu=}]*aoz}?maoI%U]A4P,AUKnS٬KNa53T eo 9# |~#6ڬ3[ZJU_S>ˤF0IHŘtZw6*4\Rר&3J3APzc+ J+ ×0 вy`SJ # OI:E%UQt) ]YƮw-5}Vr%%oxh#ĂiUTDcaZvSj]m^#Ԛf$PKEN] uzln|TZ-GCOVMhv)ov|)e*d/! g|Խjj:ƖDQoL2ܣjdt>xGpBd𬑚<" dgҮɥX@!VBhfXe2'.50GxB)*%d^Uc8l'$p97'Ƿ ώ<%rIܤ2d:0aHA r2AtIUs %|r A<,vny9qA=o%Pa V'' <0~0I=(o!r[;N8%N~NW#D V<[??>O.Oۧ=}fHe#~w2n'c: !N€b2## Dyr1RO؟Iw,O 2x~9A Un.a߿_a CbgfU@ _W]&YT6q4}!]>cQ(bESsnQiMwO. Z୧/?fvoAֲ_LUU"7 gיk]ֽ {SUњUB=cWۃg/[?:儤0U1Lu|Ǟ΄CQRD"v1i.-Im q:S. nX*+C#{qI=Ԫr٭S;Ϛ˓.o"d*|Lduڍ)UT庱aX)T{bCG$:RziJҘH.H!Ij,Zj*;]<5%暒*JfKX3KA. `d% Pѥ*"ƑF53 v.(4U\vv ےIn km 'oOn6w^= iڶR5DSXnR?WXKHQd&D9`L6Njkn+柞_.UU᭔Ѵ&՝CI6!(w[N[Vb X>U BAz>QK]8ΊZmAuپєea HEck9*Vݧ.U+4B+vT'ܪ#+ƈHRGK#m/m9Z"C鲔%H6.śIW.,W#,nEEBA! @j@R*kHڜ4[jңRJjln/(n2՚QȢGUUj2v48en\]U"%B&č#QUEPq `όr2zʦX5$FYQ\؊:EUćJ(Swf03HFTn Zrl DZG"6 cvG8 瑎2GQiXhny媩mXj@xh!2GQzA}6j-QEQsuP vh\-- L!B NWr՚骵,a5\~c,Igq,0/*]I)o2 1 %R0I5QzlAժ.jzXKSd [|pmY)E_L! 6{A^,hmQdA'=!/F$&9 9G<׮9ʁAO|e,8Id2 ",9lb5oé)lN⑫,I (e2sՋ{+hJ)j*>=f }=2@O}nj3 m#ܾyFxry'2>=V$6˒p%ldrO{HF"^Y pz/s|R:mhOȀ}o~H^o_,~Glb5}=tݢkQTA q 5E+1bD2FIaM#XrA  xh IC-=em4Ulc \p1s_9sYFIǘU:3q #:,RB ,Qf&@9uwzб` #xfݖN)KmPgDHeF*#Fg7*%-ڎOSdHJTY/K_2MEna&2PF:"oZȵ Xzv`*RU XC9Bیdh V: mWMSiT/)-UXge̎1q%Te8S)rFuGd%1x1ܧfʵU 26Y1'YVD y0e=cm[&7Sn/C.ZJjk T 8@؏ov5IYe]Rj&XdXIR7.T4֔vNH֨Jn ]Ջ7hE]$"jOU̒(10r0zI["5V?*8p bŦ\^(_4$Pd,9rT,>8&젨ZO2+QYdeDyS܁gw`aZFh*` ر~Vjb, AU ޾Z̺ZTTLTCgrR.PA㞡Ut\u6#]sVJ1M%;0rTQ};Aя52]O2f"egM.qDdtb ٮb3\PBnRBb}d]e mu,V^Vʋ]]2o#]`2v.$qpzߥZB/w}1_QXQGشUJ(23iI%-m%GUR,OԓhaT_M$H<-j=%yZhoqͦ A-+Ta 6gT)`ch?'rlc#$fIr KMQ**Qm(?3^f Ɖ28P|v@@9 ]obLʶz9>x#>>O_=W~@GG^%wCzobGξ?D$>32Xc=v9\#I2ȓ ## 2k:oۥu÷L{ 0~y9C 0yq3:g@$>>'?۠jW$fcA~]wW'6 xFܩ8<A p1oYPpρsc$#ˌpq8\t5M(E{uۓuÚ0g 8' p 21G?x=& >XPF9ݐH9?*=/|% ㏧0N >\1`pN}紨NLvs  8!0s7=e`K\|I? CtCpNPo[#sU`qyZKa$'ϟ=1` A|qӥ "ߒMax}O7/ްҟw>釐~2XI Q#ϑ N3Fg4dTqFˈTNI>Oy~?ҥA#<c 0 C"maHd{G T8&"8$7|uNKa1π<nN:>) XFs dx$Gy?s1 9g29#spLУ:z1`Ѡo{?מ:Vs)lK_ty룢*5%OJ֬$bVHQiG/$#TX:5KP}..Z~NX+5tUb`ϻhsU >"v~{zxE]P,* ĒC!XcGm;f&0M4m"$pl*G#e TfD8eiYAlT=~_NTHZ5%^:RUHFg!掽5sfMhDZu$I]4( ƅj'W[wIwa4f[Mu-;KSm QH&edu`]]ăv: J@)}QULsVFٶTndeGʅ`flS.Z4hDjC(HQi24_,3PE)LљFJKbonihnvKug{+K<9ULuOT3H,Gūn׺ ( <ӊsyh$ݔRS=a/-cm>WfTQ)v4?=ȦCIsI+$,IQkֺf|MQtH~ڡ*L*cGظ͟ ?7YO$9xKLC*+b;æU$ŘhUYQ8w5"=H}@;cm_hTTU<30pt8V p`A|Sgbi%:h!F=I$FprHHPH:Xw/HdMʊi^.z%k Rj I% kLvӜn.֗ +WMASyi!jN鴵 (ho2I!cF"#j!>HTg2O@*7t0Ul=D,OujV ;GJMs9$D9jXGm" >|q08\Q t;H"J!@vLGI:517'by'ڹƖ4Y13FG#I xtlng<e3Ƿ'ϟOT2>?>\\]|88byoF ʖ.qD8<Gs: rYl:+`ml7m㜁ԆwAɘUls -Q7Y%Ķ1eߜς>?R:IPH b09qgcP^ba (YJ$d)݌erADEl b{ET=nlr9FdQ,P¬KQ];P#3CNVCzoIچQ[–bFH*P9Kw]6jvky64 q ѠQ1ĞA#M& mdbġlϰOo}Iz~Nj~V_?q- ݗA+EꖩinUHj)mS\*d ʉ%OU-MH'xގksE+B6${=ŝ'zIlhkk\sD Xt)u)$PC65}퍘VW\>EX\.sʯVO?%A3Gy05F U%cgc(e[4,] . K{IcD[#Kx?3{BHqǜ ~c* as8'#xhP n00NYRG,[AD{mS#%ܨ q?9=Lm*8>x'3'nڨXC"$<u?̘->H9\uFFoî{|KK sof؀?@Ty#GM:RH.<~?'z,v `<99 qY=X|ر~X~[Do (8ǎ>'X0q 8\<;dY hP3~0ppPg-+] Q'<R"y~C#aSA?9ǎt5&1 8p|өв |c<R؀Ǹ8l~<?'*L7Fc,,lq  px8J( gqi"8FI-c8'99JG? 75CmYĞIQLP!l W<7 #?FAܠ$az5vv#('?<㌟ߎvD $l'?J(걵YCaxÄPed|k륜3~@'3 髭]+F@<ih;(] 2N bn %CgQI9Rdc88V yIx'''<֋۽%%X1sǷ< P^(4a xϞqڱMӧEW|T }A>Xc$*"D` M# dg*Obq$?ۃ+FL@c9d^ $VV ?|s5aSvT[ƁZwt5;52mKQӅi ہ樸3]K}Ezơ @@o%S!JT~}|uVcOny)ieYeJT)'Y:cIX7PgJH u7CmI}U}Pvú BT^.rT1Kb.CnzDun<^Owlu:~M="R_eI Lu5TVZc0,Pn}/U({߯w<^h;CLkYFe* +Q*p8MOZ>(QE=-O e!j6oWܝλw:뗕YgQuHΚФoRT*ijd4iٍ?6pZzJK٭]mttcHa$NqmzkjRY[*eg%zBMx1̌!b~>q8L2=8v~6'Ilcu2"Cr(9ݜ H݀s>N>:`girlg矌_usLQYwO߹<|jzq( "j0l:F+텒Tki1 Zv5W]аX&d̛epwfUڧݞ8A8#'u;kۮM&^4}ʲ"R~fYuVr@U-m\&-Vs?wzI%R#.rqcxyz{Z-Jꏷea P1$aJL< \s^Vn97>(N-c9(֨+z<?( rH=(צוF]Fr`l7nBJCN1qG8DK!v 0rq! @n)矃2W9S` #iL"N r_g .9utUQՌ*f OR͞\ <9?Cg 5C_gj{IjXP͸Ʋ ?Ty2+mu(Ccw%B22J|c6+,ɡ]N롔`V†CW F΢fd}LR{ =owj"6[r:EZC >rAXpUX?P5^ Y k);!l9PX IO驢X`R8T"@oq$ 6|q1 QÂj)B3F-Iu4dvcaX+*f̤|·daլ4ޱwhĒ5=[hoU|P7{; ;;UpyV)nGcڿ^+ӐR"1Tz Pvv.ޭiSO]*u RS<7Y$LsC"g5F!e.FDey$|FGb`Zh`}&\R0.4$ԠQEh(r6qAG]Q躖Y+ ¥ԚZjRªG 4GuY$Aۛe$QJ&ER/ }'70bX挦 F+:E\.0)9feoK%Whf q=@On5D):h XF\irf X΃)MmǾ#UO%O-5=RTDUeUTmB{v(sIViK Zma[ю7,BW,0ăԽUDDucjj~(ʸ%n'U^Y."TkVʸZ%R6K.I-3[?+8@(9@'I!aͰ[iǠG$#INL-PUu2͘Q< d?4~qY,dF$%M2B,#H0J1d#x@9QㆪIYX 1 Fɇʾzh^uGh2 %(q>Ъ c!:ǡF(e(ɒ8bâ0%1 6WId8@4")TPkO6Ѓi$]=lwĪA-BR\|k=,vG&Hm:ZYG)yr@] l]]G6֫4mNtf3# '~=:KSpLRMR1heiY?/,i$a&bi> !d˶rI2Y yE Q($!hU@p'NYu_czWEhU4uSB6J!UY ϟ&5Y[*ǵYf] S43`e(y Uꦜjlty#> Ý9iW\Cu27i)F8x:%:4rlL2["eV7dL (PVM*ͱ"lr$?^LWeO-,bR.G<ݍWUIKN41<%6)h12ziR5Է%|SIMbՌɽc$gӮmO,)ƝWґuE``Cd6y<dlLى1fvES_1! ƠQ-(TY[HQ by'k MiTmCSSF:ú!RBqJU]fڠպҞIN١y)?⭸zL,һ${I1G<oW TX-*q iabbp6F>xC6i禣K%=SĔچAG"I X6GMSE4&L>[*2eVTHW8ũ L HC=#D5ȲKO.ìޗJZKed% $E ]3;(!f-) 3UQ{=EUQ d ts#TwVct[y%<<~Yd_Qܲ\3gN:k%rd&ܕt^,0gʑ#i-箲Se1e_0ŸF!|cQ,ե 8A)Y :ݭȰ\)cewεشSKWQ%2}ˆ3l(۸ESmbSPj%٢\/53ԕV:,IUbT Ut{W qQs0R|z?{кmv@GOxbp @ 9$F9'F,#h M>N<0G>y'd|dyګu (=}o0rŽq㣖@%pdxǎR6<9'sz ANqq秉{mĐAjm 8?8`[`rr|OʀsA$-O9붛w0G<#??7bzoXqx%DesLªA[DBϴ#y>XcpI/KeS|bAݝ}s|?$onvX8O/kp:9 ,xHρA Uر$Ix秬t oUwa wޅ׶QSy c9s$q'IOGt9?$c>2G9>xP8R~wAqώ3z_<{Hߞ;{4c|c[b@ FIJ32BC ?V$9g#t|i=*F Q\qlm(q㰶G.\?YTd#c<@M$T=1-C,T< deoXm#;@c=9\&g|7}|:zqH'<|88,NN QK}]5UQ4CK #'!3 ;L'4|753% }9*GJPM24!ti2Ya&?2I5j0Drhz?>4VBYJ 8)<9|uNS #B<OzKUKQ9 D '\pT>x뺋E$C YʒFܯ8f,lq2[_dq 1~i` Lfub2yflPgh,i䢽w:cD V A5҈<:hVWI$x8GDGi(E$,RdTJaUZ z@]Ɍ&mӪe/+d<9T)4G37ܤzC!`EA/@( (ŵ"J6v1bupE$w9-K3ҖI*luūKZ3mf++(IOqz6U;M8!1*8 TЉKx(YN7z4L+vܼ.M2:ME)CGʩ.4 f1 j5\TeHi%:k ]ƅ`zj**>h-TTtCQOIt"&B_ lL֓&bS̥DJJ?L;$c%G `cSToDiYucN!ehdzi**6S%7)8qBʥ7^h? BD ! "b0F )!I]u5Bd25P;O8u52C@(jz20+$6ld(g4[K=ɖ;b8B;2NēJ9+$Leia1!a'8ZU{YnERʾ # md7N}(8zjh ҭN8ul' m, zPb͢ZҰLTed `O'-px%cRmJj.oJĭ(`p\ܿĹ+7{.zpdgKI%)!;;tG0os i)ҲI`8i!q׾zަI՗OEMY_]&HHӼmJ8Wl;xSSih"#"e_y%YUi8ŷm 'RK*BbH';3)s^sk]Ҋ+ۚXmn2MR.}ESn]KPR_ &mIrfU#%I_IU##z5F4i6ҚP (ae4%ĒYC\6pC6o9ᨆeD)c9 Bıma@U0ߔPI_U;Zɳ zlZ!cĐG23R8$eL ~=_wShVGby.Dҥ$Ԣȡꁹw>SA}-jS8" z;mDqBF*ybyc~~bjJ mCGQWA%¦0OQ30 9v%*:6)¥ SjIV鍭fmWKR{umlԺƢ wԥ5cE ]G-b1ltI" $(V,NUHg*CSu'{̶߱WB*ڥw.pЏ%X$ig&4-ᐧXXdtصz⹚B#L;i؊>Z0ңKJWLv_ikR^^V]IWjNI%d+UW> .k^Wue,/G,ʏRSġ95VPM9WZlvç ҉ޢG4`^c,Xaf}j U>52*!xbntR2( jJ!,3!ـ1Ijiv$Y’懘m )((0TTPN'_OU}\_ot+m%VfuLRXǦebqMSAs:z**5B\0r0\g uP\jl:Sӊs"9*Q-wkQJ*XĒ9e@Q=_9+-2MPDS Mb K41Qua*M}W5v7`2dZ~xblm*hFUQ#־tŽto7 5=cp!VL54AR&4ٔ>N:macw[Zk Ja=jZlJV75|ȂJw1bZmY/0M5X!&I;^(. DBayb ;:U}a zD7W5&t&)t5SIhm8k>RiYnj -}CSCe_lJȱ#E' +3z{]w_%IU\5wbZ6;4jڢD7 >޽Nj*jY ՚eWW: Z4Woi)d deF;L4x4OVlO+RWTUNF(22Y[<(fgcsx)%uj iIW$ Y<ϔB+t h젰@q-u[m jhewp2F|UdKTT>||3Vn M5Lt5SIS:GQ.exPRN `4j6O;~$㮍;zh 1]<j}pxq!DU,#3*"`۰$Np|< A3;de%A] Œ㨏)6cI1GL<029sr|zMBA:䱐K ' x={߶0481l6F28ꧻ zk)n$g#=o o⩂zx6RAxO8jmdYbt *[9cs'<,hJ(wVU6DWZ|{󌧨F]T 8#QgG_hٔ2W@$Oq֭Ԗ=O8Tk}!F v[D324%c,W&rVϴM4ֆht53HDeh )cWRN XETzmf G到Md "Apr3G]%bʹvAs~ s=/EyH<>OMUpyqN3wsx5 S9.XqWASUD`Kmʌ79zpQ!fDx,r9?`?,anx?RpE @{]\|~H??%zXcSpd3M"&"#H[e]AC!0yFFq}X]4F誛uU55-EA[k.핁ފxV|@)<^U ̴YGKig$*zI,@25ꤐ ]ETnZl}dIS\wv+tU(4֮ ې9CNim45¸8ԙ#8l"D$bF K?jrD5*_atP$R,˜j(8_-CE%jPi,2 eBkX5D&Au|mtmONIsoD& $}ɘQj:*륲)PXGWdݢbCdHHfwF%<33RO-4`DȧC- A(!#R60Vܡ7LWE"ӿqcb/nčUXكӴj*E"@€۔H 䃞z]eO99+u5y =;*J79G#:b*SKL54<$3E( #/#,1qC0MhYbj eXVդj++*{0,%t" +HSdsnHz!`ʒ`3+B8,LVݾKm'A$3$F ҨIccӌo`s`@>O*BXVR`w8 #bVՏBA+0$?iϦAVlrA< ~qs*q#z Fq$یrqŸy}G'1ϠT,nTT$,Fic bF #P_L,2j”k!ef/Pѹ $#r3%y+k k\ CrH*M=9(d*2A6voZEk CsjVT-pcfEp f$|K-3J_L!fV`h&%Xyi$lЍ}rhzv6aC4 8  JUF"e\8tI `8`I$N<1>93nR(Z!)Y)IV*91F*˂H^` %,PTrq} 0#* HeqCK*c`kIH|lF8<89OO&8o8]\SJZH]IeVQ>`kZ:jtlWc3Ă=*z7Pj*rӆ]a+Y)`1T1͓/gM-:TMeg$\K! E7$a1%^X+ )Rodq[«,,.Ab嗱čQ $4cf- Usǻ8>Lsv r3r2y<~~4@ A;F a%x<ې2-k#4G=~*Ws.ۻ]JxGOse>,|nrwaB?>?n3\v|c8Ӧ^ݸ:ҷÂ{Wۋ0)r yϜB'e" d[cӤ-̓S 6ꪊMk)of_YW_IQTE,z,YJ:D˸s֛"p :# n$4.,芊ʚ [WQUwߩ3#҅yP:Ku{Ŏ[eEMT& aÍA &fs>1Y$!c;^1c DA3b0҇.4/Jd $>Xt!A،Z'񹈒]IM, D6RM2HFhlRM*&4TOEQrzJZ^1 HqF9V\5֋D m$ed  F>b3UUt憟n3xH@!U'$|g3Yrلy1+&Z1Yc]r )$#H,yb+kqv6hMF-i=5 "$cIXe Vr̫#pI,A'zBkM=4R5M:Jڢy*썪AeU0r:{=5;C8ohT#lA=}i u=km["V± 1 I\gb2V1L1?˄flD )6ە;&sMi1y#P`Ag1H|^TrND餒{UՔTPfe1GR1JwX9 y?ͮRaZ-ԏJ/TJѪxd$Xo&o7$0,VF_bASz-&lc+:4LЊR*) ' 4ϠH8Q\OQlp7 *'zWWYY^7fGYH9=SCC+i*zbȜ4eHM2w2䜸8'RAoP-S=1/ClҖrNdloQKVwKO$V!xlRW9<`:<[\!5'äCWى5VB#u2f5IBk0>HAVi.uRiK|qiYvҚvݛתD,U}P?~/i?g⎪Us]#$K2 Td3hFNi$[n2 j-U1)ޱDJR'KMJZVܿylt<*_ޙE,>x ɜ31*1 ]/S4H 0 lG- 4$vj0;n $ ڹZYVn gA$8>z:jV30Pp9;䐤<xTU7U^Miz*uTdag .7"){e.iЉ($[Tq a2ڼu,#$16D_#,$%;f1@(HRV@Nܵu۬Co;BԉJ@nHJ8<rIըCh%B%gSpH3-:f]R*S%TJ!\Hbwc8`K.bJXSSNdHwR#N9ɂ s\}GLYDhB"+ɑE€k4H2X" @2I;Xu%5('H)a.9 YX;AQ W뺭3 5] t-d NbVXr0QA=5 jS)2(cHǜ4!iZ2H=IgwnF2#%,#,I ۤpi5~qu ,J ][UrwfĞeFUY$j2Fg<Fx%EZ8i #0 m+{@8zmܩR&`:\V)`jzKMLRAQT`7AgZ,!h2$rgYvNOs3f< 9UYfIv՚1eBEHR2*"14Ăv;Q]x.u0"-0t~B@r PcQPCZ&8ߟU9eJ8@[JK ;@X<oKq` cq>EQbid p S~9'gs$Kec&/#r3˩5kx!kf6 2RT2ԀI^v|$.2NO??ӣ_h'/$FNu +?ǃ?=;*I028=zp1~n:àp>s1|`tcJT)\mNsO1ոGd $1|Fxcccq?g (s/Yk u6?dp@0xd og>?T 9ilm`s|o9ϷDaIqrOy8?]# ?f;H$ psI8+q|LxB\mk߹ӌ:,yINF1#| gjɒxǁn ybH~!܏Gԑ1Oa%!H,81x88qn2ܮ4 E i:jIҏM;q&Bʔ52sVO<WŠ+:'-&hhJa|Su Fjn]g<ސ.'8mߩ8ad089߿FA8@<':6M,>XF2o2I#J_/C2lW;*!@n;Pyk]Q!*.$䏞 q/+-rP$rL4˕W\f'$vM[Rk.SIP0G\q`)`#ȑ:&DPˆ)w ~ #3)GcaMserjTGcFmVY)؍!|dzЖck!WSAQNZE5M zQu$1Tks͞UtK2Z'I6| Fy^`)# jB< JJq!S; Ynӥ5 QY'l4ӻ4K$>`xo3$yrrhܽ/LDLѪj 1-ƨYdвG1;C@@ƇGkv-c}Z;,pSIiDL je4\3`OV Җ[h U.ȃ-' պOAzHV>]"');LQ1$,h8{Kd&.7zJpKM# m9W ~8->vzΚGfzP;"ۅ#EyJ +LdjxAB*1 ΐXŋ*E#(15tIu WhJe92{k+^V+JjX„Ԁ͹J^o5NUP/h"Pтұ.Shp$$*g.w[U.g.z"bb I N:7NA&icE%J'͑K1FTB' 2٤PXAԅ.ҤtD{M=⒯Ni%.8ʺThpVUH-=U,q_lEpYiSԮ$V^HI "MiJWYI *֩X9g#($u4F21+ m#W'f>!$3:_@ҪeTP0D䱙+K/eTi>V[d$.ı~Mt[-қm $϶PQV7b0 MrvŦ+]|nފZpDGV!S*$;Mr3ۡS_ kv# ݴcX ~/ Fi$M:"g#dAv3Tk$[ %XX!orA'n4 pĺMhڶVV@7,&95pIs+BQCƱDCĩ`cz<Ĝ\鶎z qU|1{!;9upU&Pp9=Xh !ppy9NhdDUֺ$M@A'ى)'I UoeRTW)̈)`3'$d1?~\* >px'%8MK(LJb۰H =T,gz@%s$py:phaM+W 큒.[(U18 29TeBRR[{Ѳ^XH , Snlܩ~٪'yc,RG28X-e`ʼjPIҪ-eJljkHG1 ĕbI, |;-q*eB\* ORG,p]8I ŷdh$Ns:`UT$ds8?8 !T#?z[(vb<i/"[']M]ei_p$ qՙѨē*g A*F8c_9z-v=waR꣕'(޽gJ Mq=O,j++b4cVFnTQe;@<9d0 GPÖzMuU"Sj |E="EXjd*c@ ΨSwM%QpO0sTu-^l6dƬhb<6$@Ӷ'OHрB/ eOtܬ6^)$]*Uȣ\0 *ʦIu?5#Xd$+TP2r[$ F}?>HF$W C)g ?=4j = W+0IHČ&b0sWrZ57kʎmWqWʱAMOK`F%R81ڀ-F`*QӤ$AH#3t잮T#vxfhJZ3jK}Ee¡yUs>M1+qJcXvEQơ!$H Ԧ@. %$ǓMj$FBɫ$9zEn+_ U0}; }X,'žXٽ(8,\̇MD3Q#[jsCIInze6*j]jđE^cIrP #Fp0F>1`1$r61+PH@cD W7=+ un߹VVv 6 @'-$zg@@'?W@Q9sKpĴ? 4l@r @0G=PV򪯏n̵~(w|Xt "r[BCHo08"8 @$Gx$|%1m8<ݏ{e]̬crQ_a8չ`TH*?` 鏟TGi8RӞ$vUrY{PlNbdg c g^j!RdpH8$G#X7D1@E#$g mЈm~_tFbVvT;9?tr,; |p8#rO9FҤ ys䓀~2?m}:AK`U\oJT*$zc[,WWӊ( >2qw篊sb|s]a1?a^C\Cу dd|e[<~ua&) FrA矂x~*?+ڻjoA"C NiE%Cm]GgOԪ啗jPP$HXǢ/U_.U:;TS)6bQUMR\˔a ﭩM峆QXrX`0y8c[&um*ն^)cS$uvȝZ'!`s.So҉>֢ t6>=#MP\/W[%uJEDM<4U4TH"R!c@bx >5Mפ[ʲ[(~[(!X¬4F̞,p]e\릃ֺQ6VPII3S-Z Jd1HBׄqk-Pk'A,L du\nl`q)em,bL!D+ zY6 ,SW2YGV"+{$ [eIZgr-u M Eh tRTTzb_8K4mz{ s\樹I_gFSViRFfhDzUfF7h;m,Y+2O,*e,D!X+"6O:YdXaa$r $X`2PńX@#2Nb*hJ1!i`I Wڑ[Out:2RPii*`au,*eHQ;U=vs,ԴvJծK2O rL#20:yf ),]2LI'PME-/$ ᒺ2r=y SBQby=KȚ3y:dL]PU]X jU!,qeO0QR|HZ _Bq^UH^>xL7uP:YBec̊#BNIlF"U:$[95uQ.#TQ)%E1;r)UbPtŭ%=:wMT9JU5Wg 뀰Ya2eJhjx4͂e1k/[vbDibkf22H[3&[2R% % AI:Ȗ+6J:SjFRRG`,bngL U`ݗA" #'oUhuMOu;}Jv@Xdd5M$1ҝ=cJHmTPNg]t]kzOOn8ҁbP@;c*)'s'V~:|υ9f?Eql(|؛#o)vҶrJCpTEҔuQAR%MžԎWAq \)j!jI(jYJ#2pr }WDzdH,HFv>v \1&;aa3Go 0!i)76sz)# Kg ߇|AY@)OdٞBЂcg@ŵ QP/@'P 3?'0 (4uj*U$*(RTۖB%–d=]=][V%3Te<̲̅RVg-8ҬI '?cGGLgrCxi 4jr8#P Ӱ ]ba.ʹ( F*L+Hįc`LP7jRnݴO[H=yTә΅I!4/uR]_O߭+,hW*jb"7Bj\euX8GV%A#89y?ӟ>znmkhY-ڢ?Z 赓&1A_ˆ 1y|/5l3>$$2oMYij\8fJweP|m#&f,򳪅LZd*qdܪ\)s'@9Gw.csrA$`~9`8{iU/~yq#=.{ 0IA 9=C82(7M Z5)H6 }Xtf{X=Fǂ.Itx8(ຸ# A p8UnF.IP @$q0KݦhEEMHRAS yCcd72;~%cqu99HF&I?) `Te$ Zj ~m٩i댴5ZR(.2,O41ѳ@*v-[eꢓՈT##y y,:Sy~5X9 AdJ'q ]XEP9 zPAo"\q5.vMaC",ᬣbh@J jIXXՠEuWebzy#pq+4BM[%·2+2wb ܓ܁ROWK+~K$sWp%NBUlU!\,U%Pjg⟡)#n9њ&h5<[ݧiI%Н ;C,[F@ rsDqeid$RZEFb"OAgpqR(3JP&EHj@.E }u@ꊧ8 )b$ic$` ڻC}:iuHdK8`b<2#o'xr 2b/Ϙ"g7^:d&%I%28umu#եdٜXP-wGKTDKesdj:egD+riΩB0vIJiMky%*gePK@XBq\dsYꁤ9lbh@ =,c1O=T) br@((թZɰ) ;imZm[LS wܳ$$p}1a\+ꟷMiԔ8X*R۷:R U R|^)-5ƶᆞzSG$Ը;U!HH1?vzқ޵抦iPJKLUBP~O;de*b\S3\8fhYi!WDi qkSQ$LZI,mqg*6Fj@N$ qʏw koF rF99vMYSGT\*LS#"! $p:h֖hㆂOU)cXRk)B 2ʼn,sԲf)`pxdBhRq]],"+IKπ'2:R) ˡ*JF}Վ*Ê18<.$#GmI-\K1 TD? kڨz`)+7op$b?:vNy387I$nO|:v`a>p}oS߾M2q~9o'̍ [H'H q=]xApNzőC=8ߎ>\%Nv G8 s'=|zVv+j]RN7e)H^`ee`QʐPʒ1ӵZobI"~ ށGsӃtb2⊢WYt[fx$ u<A5/EpUDѨUT7ZPcpUnpRj:JZ(=4TNń`z~9'$#Yvn7 ':y Ӳ\u!u1+75 R/ʈ)4u86@٨tPSPA)OI p0'8N "`nQG 矜~>#3:i-)YS+vF봯n!T' tCajJ h$ I]27u]Ms#CWj ,vz$i]L@*u35ЪbSfʞnOI mutR8`0pKwMn)޵XU)QZ  .3ý u&L1tQDA9^Q˄]dr 3},R+j2rGQr0= bB(QiJo)%l%R F( nĂ ]lHJk] `EI :k\*<3݈31-mwLI脒Dp >Kf%U⣊" gܹs64+o:j=>hOQu9Jze}HW?d 1J8@3ȉ^% (XY ̙o!`ܒI޴ TćS_ dVGkyj A%?ShOFwl1HJ֢VJL҉YW%rK:EI_YPɦKGy$!H3+ؠT2F$ejVm$ ?K$!'+>:ts>aMyprFc|i&UQr[SF4F¤g{%cU Cj 0 M(i GL~I#neyh!ˡc^(Uj+*t$ U -#H@ ullw~nJ_g 6 #|9x\#' c<|cwq珂8#ώ6|gMmwq!Ŋ9p a+&H$#<V# PNO힘 8$d3?$?8봕C9rNs>|~0$,;IE䝄:IF$923x#sҤc<I<|.$V/&oCs@%0Rz#qca#Ma=[}co;cVCdxۻZB@a=LVy W2c>O Q-ە 8? 1yiS{t#zYbw vm:MMM,5]#/hfRjpd4eAZmPj[NlUw;{%j&uKHF12+r@Xl6: +CFڭ2b.*;;Gn=w\o3H#*jV8HRIӽwq !YFhGWUDH~}@&UbLZ$ DP4(꡻npgvVi-]"&{Xw JUYJ*/Z 2˱qIE ed#ܹimeuM̛m5QHp1$oCB4|0}}՝ĠzjtL-eڪh⨦-*{6>PFrٓLѰ:^2ʥ @,ȰK5`FUb4p\b6 cevD]?V '&WHܜ3`Q&psF~1d3NLee#yǎ0GGP2 vĪlY*2G9# H]1(z[R4u_?G|8x4lbU*>A>~AgnA.d`Xy?sYl4JmS`<p 3x8=S9n\B<*`9=XjԌ'kckFX||8zΉ 1!  8~O"6 c0dc?|Wr]q_]b6Ip cdc߫oOtą>09>GSi$ cձbn $pGYs|>bƏ3bĔBjƑ#!VEGϸp .2I rFESTy?zZ>=T$~?x$Gsٴ;n><ٚ >pݟq qܦ`2E c:G}9ceϱל$yۥ,TT*2H 8\/֌ؐ~&{ lU{M`#}:F CуgTw693yi3<aaׯۣ8`}$W>6l6QEW}sW_:\gypwy'r2%79>1g8? u۫utvMOSq&J;} 4JdyfOb)I;Q>v]~LBUo#U*\laݒIxn_t5&k&.-FU"XJ"=KX=RIţX_PfZyH䞑 ,[tm;7Wm:UuX [ԘYvrίx꾁Zk%e5{9*LŇXc"bG`;Ϙ|0Qfd@X_dVD%>k(Ȅ_75nXѫzw_ά lx?˰vn떴޲TZ@ՑU m89Zgx)!uuu-!Cy$PZ:ɡPեz$^-G}ب%]g "bT2. ~]8k6 pIG95\1ʈ$u Nx69"n۹XƁ!T(zDa $ĐXmw#Aߡ J;k))`YHv䍬Hcշ+},յ)0.ǒgDdrB(nf8";S(uE_qղi)!SZC@+8Dꨵ<Eak*}CUKijiXŻd6$  Q5oRFXWl@ 5`qF:Un5[}.ڏQ0q-U#7IUk|ܒȧ#o' 9bWQW=k&iiVgئI#X*I+:~jMYRj+b yU3Nڬ 񞋆R%]=T gF>2Ylcf_Qly#ˠS0j]`neSƽL|"j1w@b4V4 .yR WmPs$ ?ҐSa%p d d >rs=_l%DXFr=x''왥U'8$`stab}90O~ RwSR[4I=]eI#\3-zYR&GҊVE740Fs@&ݕEgv qĆv*&Yv [$r| g=1]tZW:V"z9T~M-'jhG"PAf8 #7εmt=MQPAsjwaTpO'@sL#ቤG44Fy'8zP@oQH@$eX!6ᗀrz'r:YwU{ OٯEuS 3]" 82ItDdp9?Nw 'ՋSٯѭM©h%h 僣6=>OUe 0,$n GϜK$nmV c)4lN فP{uꌡABxr`g Zo2/jxGdav@[kpGO7;VWSBwPHA;!$ G~&Ֆ Y0OC Dx$gU@C76KCeP%]0V[(1k/B9YHđnPckFT\-2ͧqD Q 'mA,8.sS޵ Kij C) t$цYT+2H''i:72¢~6]Wb,2Qm!`~y-4tg")zU}C3xψro$tfse3G#ELr$YxRbVYw=XG0Wv6+(mJ<++HA'JT`5GLXqcj-RJc+ F8ʃEE ̯y4Am3TX#@e[#ԛ,#E]Tš21mQиrU=[V{,uqJ (+-Zi*!9`=id=([h&+ONINX3-$(54q喒0Pލ:n`9`mi3˘rU%>cEҡ%yHK9!jG dƴ6rBC6u"T ؈iۜfI+&B֒I Ffqx$ k=޺h+ TqF};ZV;@bq]{MnӒz6W|jb]DFvn*?Q=+[1RdJoW#U_/K\1(1c1^6fcRgwm-Bq vP H8FIݔ~nh.pnRPm6O\XժkPxI;R7cbԵJZ}hOGEc $sR^Y"yETOpIq>1pFz21&OV̙ R HM~((^}sWj"[x# V/c%UUpa0T닎*m?nX>|1;dz7)Xzj=H.M%mN <pGYYtڕUEKݲ s~x!3>K1ɳ"!.g"Cd՘g5TkPG#~:WdUbkk HPI<=JѪeE":xT@UxZnť(!E5Af3U#9`RPlq}-\i LWBb*$ln(`ujS p^5hPO92˴^AG4ee6u_cH! 0q.$,x Q5*F!bpEBSd/j)+#1VA Dl 2zgCtM[b1%y) *~Yp9=JjQ[4tڭHX;rFDqtҵu]um%g1+#$O W3XօӆGX+POcliDdFjDkwGWM.[m` P#q5qjɪS薉I_oHZ(-Gܔ+1#nJ#+qӐ[-@i&2$q8ra۶ psʼӌ^\sy4jsyuJmѪ+1,dmKXJ:ի0j(-zrR*mueF.cm\3zh7SoH$}$XU!9#2**:6Zf,_Ly*'m/۪dLcXdz~#k'drR(>]YZU2)pWAeK(ܫJaDפHM]0WnTC H)!6 7 qV{T6$qASXfhDTb ʩ8 y$S]%J[fn.@>H,v`qt\lڬ0o8?֒.^YFd(i$* #C)]]U&E_,TFǁfJ$IMO"nP@sGmN!xIN#MШ9(0I¨9<<~yAN[L#^hbn$C>^9Y *0ycS I䭜:) 5%MoY[] WZ-$`[|HA߫xE'?xPkBUTNʻ52ȑ%۹!8}X% {ORWM*Ēy_I$H?Zp9T$yP@=q)e J:(J[Z5+Z` m,̕B`QJ UgH$ q򖢮hp6ǀyw +̖ D1*#sAd7_ĹIA,XXphFpvJ_<|q>Cy$@'?9 e11du ~ ~c^{ppJGi^y9|cW@9?lCdm\$#:rsO>1rIdۣ@d(aG?I![-isI$r0:&O2ssqOu]M_ {ѽ}_ NIUSPFTȱnq 7T㦿u!B~ʚzhRXe}i@O=MFk`38j:u28EGTUH y# tA"< x'<4L@T,TTRص@UB55YB+ nzވ;-=Ko쮫vX #*,Y?"*X aTm`?V8瞓! $ycJGr8'xb8ҁYSϩdb9btq(};Զj)j j*$Y\Vѩ@F,\㨽9($YXie8$9F1 x6ʧrr>yH4xH$wO>I.Jp8uq"B$WUb3lE` C,rQXQ6j`v"b)e-+:4! FNGN c"y(R[9Fi% WԙsP,S`20tV *q~]PYk#Q%bQs>GPcz2n $PP/U (Bަ}F5{h):e IP®CM*g,N[s=Jcfߓ\zxb[gT`0V8=P_Jwn[<9?A 0 (5PiQ{Nw7w6v;bM{aJg'1|yr%39'<ۢ0|ds$8'y$p$m452HPēg<{ 㛭Ɍ9qnzU|81mUEmQ"pzVLa,0zh;6*7f_ifFH;xܶ@OMBwc\ZJƎtr*UKmPy㫶7ܤ]=Ln@ 18b_^Y†Ĉ G&frVϞ(,~ڐY.ZYK;ijt+ ~-G0?==Iz藦nÁ_^J89)H#s=r12gd!T)$9?/OG;Æ??JۡYI=4D0-I8 J:0ax`G#y88 3*8P )'9 kW**ዮ>0sӎ1}xG9щn~+b*Jˍc?+iaS-l(g׆ "Y_fBDnWeyk(zHX%WaD % ߵupF zcP\4 U>NjyQKBƴ(cCT!Y]pv=-U['\imW4"ڳ:!WNc*Y^:d:@d$ 68_P=@׽_'n6ŅG::)ᣒ5x3+ Hxe V(I#q=H(rI<uݲrVzdiV8$ꖐ''@um b'I&#PK=De9 y\pA1$o;ƅbqWoS9AU#|K˰X'B( 'eg r~O|wϴ#cnq=6$6J7ԒOzF8V8GPj)S(*qUyOg8mWFR@(r?:}q&,f19 x}m2d0Tl`^>kDy )%8^N>8Sebm%U>xU$:_|N-{r2ʀi 2N39Y҃ m7bhaceF# udا!e(2J9> 8?952P@ ?=XVdd, 8A86Uڏ~+[\h=7T\h 991wiZ*8㑏lw2G&s@>:t՗vX pAϑ;O>yX;]u=MUL܌Li-*WgbZ˷:7wHPdn7g=y8];J8 A`<{)X7ۃ[Ɣ2 wolzMIS DK$NT<^G笡QG9i"—,h :m^A H|<O=ry1ذ@?] Nz\h\Xx=t*4^|#$g*;SwNB k.;~Ȱ;znVIFpOu\e&RNx2p߷T?{EK=kQ3SO$n4:uϾyY9`Z0jOm4{L451OCjmHaA\]M##i&1^կwu m,FnZ-2i>;I+qIljGCRJiTQC xw}7=b,¢"dV0B#liƪj!ڪnd\j G$Ǐ=C]=G%sn#>pg߆$ơ UP@ y&ɳ fg:'M'e`MF cFd#xea2*1PQJ#ܠB˝U)#A'<'v,3!@vc<Nt{_Ci{g{$:߹FΒX4:Uke /,O$pSr{p'gHS\P7 3tU$2+{nO ,MPׯn{tol7etA~S/s %s-D"`BIfTP}B}TjԾҔZ[A,bWUQudJtL`N㻭O*I+?ZWO-dvMmEQN Sd[5*iXvQQ'ϫ,P]afi ZQJ㪒+ɴ7X)8yS~WBq{Cr"0KblyX1M^#kQ~{dCC'+gsyNjFmFv2xb 0I'z;2S+]{D,RXBҸ8e%cb7)ΧUհ# $ߘ brdQG<π0Td t,g, ݽXǎE[E:*x7e] .H`}hMx*+;?*%XL(Xfe8;-Y j#cGtZ|L yu_$`'<0)ݵHm`c > 9 09隆AzXt\HeQ2q RL6# ;)eonF?a20e e6; Ƕ#f V؆폗 j PRW*"V;D+0 ˎBpj;]"-k'-Co[PU!L͐Tǔe G o4e cSq$ }5Zo$DdRX"JVJ`(*{m)&uzGdK/mذF,v pdTYۃk_ګs.r1ct M}s)nwj+Ƒ lvAwʌ"5HCahU%@U .F9[z81ʞt$5F[IW5L"m?p1~2-}\ HDl a<zKun:_Qi#!l$` uWnEe Ws21i0^$gi-[tu|Mn"52IOPnIcfBJI+8=|5уK*:VQ.`0)BEi Ƭ%C ǘU4@XϤ8#m Lm!7d2F~OڻF윁i9szjcuWY"upb26[#OL CIO4NL ԬD,0p±gKc&X†i5Ҩ n(8ܚ (h-tI{AFڽ;u洳n G.)(`и+mi7v껜(h+]+&xYD/!C{[urW{NҢ*[,񊩌 9dP U\DBVMKRjM^2WJZ:dV `K\GdMPGPե&DNf=HQUFW YJNXzV+ĶU_XJIU#UFU9d;1܊ 5 J22$eE}\8R@<:i]&g-#M;#bs*\en)`0oK-=2=Y$QG/2 s#XdLNuiTd%I"@th4+Z: puk4P+b mwXv]t4* @%w䞣:+MWO4^٫)*1;$(e\-Zjojd }X'oSeoλM+0k31-:#|ɥm1>w3V@_2(Xvㅽd_H ppXgrr>1unFi+^7dRPs*1>b`Xbn@X)gy3=W7{u\NE.۽0s#ϓQlȯy$Y4Qg,hM002R r.UcN^rmV\\VCvWw"Z3$s١D {W $&"iƤ!Kҫ ak2U8>@OL4V=U֊#Jgffgu5fX MCdc՗r8Qy=Qr>t*3yPeJL+iKePHz@ "oeyR "Ch/(@+ c :jn$FCURGRʋg:}l&*8@eS'iscb vgCbD 4C\IMh+e?V6,7r1r~SrXs̱I T`FmtmaZOP WӦR؞dPcA#3HH@vC11znԗDӤqnԶqPA#ZfFZJF;x8nJc3dMP1瞍cJR0i-f,ըl2śR$ ^\%;+a@aIAaPT}CEVZpʡ9d펪Ñf=o0\ O7XI tW%-Vؖ'uxcДjwe 5CPpI"Ĉ63>0ƉJ-4C,dHN7у']oA#pHTc@<`tw jD*IOL$H. ˀ#NBLaL9YTBI,nD UN+E%6m*e򚚂[UTIX-Lx&c6 c}g]sg:ZT[zցwH(9\$ps]D].T\OCLKZZ0#8 Hg[9c3A*`vLtUXSpŘ8F8<xaϏ?'yu #8!}>OP G 9X`IݐHFy x<~#?OFSWr?<~V`V9#|x9Єvr8q8<HuV>rN>:x,I]U޷ߝ_PF0a rs=vO  q#I(F asF1*JG<|2|x4̴zŅQ`qv&ٹcdSKTAPA{5^` p'v r@?8p'?<O'r.''yҷb"(^ T>{0pv *@P8#$*p7| \tJÓq=ߍ p1ON 7GposQ+çjyqrOF v6F#0$F '%x>N~>{1Hpm;s:PcU93qu `9x##> ''889N᮫ܷ&t y`xdi163J6>>:D0qϏ8^%O=qfqh>N(  l=KJ(op H7n+y'#<``g'Z/R+eƚ0A8XC;+3y\~Rgdq'1ډo+YU[jg.Xd5?)U$8Ȑ,I$q@*ΪNh A4EW;#;!>$~hrA'sF`!T*'xssùT–<)8>, VA]O </$y#FGbEr$ڐ8#N'8zܰQSFAu4(6}1'Tom%19 ?Hq+$٪;K%VƬgz0ݵ0I x᭭vf+LԒHF1# ,A,sd\ڝYsQS3R$U>Py^[ppzLyeg#5q 4d1/_wQ1T_K$[e=yc\:KqD ҶV* *CO|(H|$Os;H#>|[9>z5%qG>'Qb(RƵ@hEUm}~8YXcd텊HUS`2>1r|㣖Mdn\ Il82H<t]Y4 ac})1&=ל:EU,*5w Eߴ:wtIdML8IW 2TO`e&へnܵb:ĸV)sQ,c@|͹0ќS VV\C6磠nam(ύĜ:0bI Lj rT3d>tD]`On|c9dG2ϓ>>p9#ϿptaTѺ#I@d}Tdc8P* C >=ry>3yR3  KzDB9w3Mac P߶$Ho(~[T aA>uU2WPT*ޭ Hb,Bm V<Sܹ!H>|g?U_!F9A\>3x飳 ,vtVN|} "QI$QV8` ڎpAXf8o9ܧI dqJJ2nP9 <3+`1|xĝ. h$hya%8grdeU$3U&E-섰bp8꬈~5{VǽXF勶WHj OW*x8y,I"zJ gꉡ"G9Q8 <'y,<)J?8 cz,v=9;_n7h\]捀H#*Ųx=N3+C0-#ꓶa¨N byOmlATpF' G~y##=s?Qb=4yoA[+rFD(\7 'dxV"@rWr-a#7<f@\I 2$N|u4Ӛ8{)Y? c 9=gM@ہ]?n.{i)<|>z3bSw 02?#8 c+V ]*B>< #V}UҩVJ79]NF#89|64÷nk.kcd[u41_#9QjcU"MwS琾r@䏏ju*lg( x ݓҟYҪ(;Y 8~:ȗ$O hm=;Yx}[*+#kόy%kk5y'A眖<~xǓo<1 pŇuP~s;{v8jW{_öWN\/'ϖXduR2pq$9'TN+Tx>'9zTοuo8,9$m3ǑaCMPBz}pƔX|n1  FG g|u>KP>wvUIVQLcD79qdf]W$ʫI9 듹t SjG5BC՘#d.P0Ǵpd2!1 5JM +Ya3E݌=rDi=#l**̄m$.A\"ҝf{UiֶHtDrii}#劮ҺlZnT5iG$QSFUJC%4EfԚWwTuVشݦymTDe!cI0gҖ>cLF5BˀۨR qUɫ4 ƶY7|FKx;NI8'F9ρ[2zC|`G#y?:W >nIQ($0n~H}zRSuU$f'[<--#bM<{n~k:-rwm@{'ךPlKcyS9g~w@v]x4BHm/tF﷠Qci0;!2ԳNiʋޅJ@U@^B2UZ i`gb6:fZk= lm"Ls~څcf 1%v@n tU2|ت ;CU ?S|rD~(2,ca^0u}5]V4r[+RJZi^ΩW]tUWP,6d1=QՈw8Π)R%\>ikgKzI]M]PY[]*343n}I%&ܲĖE }Z2@B%R'XH`B=95oQ8-6 ?B5ʸN Xrg$Oc9#z*ڬ͑ yA#<',ͩh!,p@| Fsq~"Fg O_ K6RToV-Ozb",/b¹Wl1+$0SuUw ^Sh}/tֻ"H6:w 5G o EUۆe}Bvޕ?9˹MNB`@c{U5"e$j7ؔG)*֍PUX.1@T5K X X;jH;ux]lR[;Zju1[VCN2^P!ES#(帴kۛ/hm2zT֨kI^AS#%ilH]1 Lh7|5+*ކHDQ 䤍3̙l>x8%W5 { ' $Ews>9r8bDI3+,0%.AQJ%@>\itj#UTT51nvcHʍCaʜU09?rpjʁC $2c/af4jrWHs8!/圏M!fv3k9aCr#*=Qwiy*繘ni ae8YX ƽ\G-uyx2h1GF E|{J.]uVvʪIAo{}Y(ĎGM$̟pFHFreqQRⒽglJ9;99'~Xp1笘r4Lω3<倕t岡UE}LGZ,ifETI$'bM^Zw>$3rp$('j_i Y{ dI$gǞ8P(U^2OS3 (RrFOU?P!x-t< [-r6-6ؕGE / iqy*F [$0-X){qP NO,5pI%Ԃh^Y sFɽ88JO}3-]+]=7{]4VKLѣUeߍ>$O-9pcq5r<ɠ,p@;DUAIq5`3^@3[[mBZ6EД$OTdle󑌀F wkTIFXj1%m*JG9EDህ@qԪ].C.Tr)ڠJmܜdS+G M,1X٣j µKHR4/f 0` ץ sD{wk]Vdhd*n,J==e)\2l-WdDͨiC(FxYlX,#PK6jdR(2<`繶=*:x Y $8ž1gیxǂki#I J5@B l J;5 ֖Dt)sP#m.nwޒL[2h*Q\b U\j1{Y#(LZ㲖f[5u-š8*#JYHI8f##=Pםsm㧭Ʊch$5]<:2q( S 7dW!S9\N4hy3f2G M88,^C"FNkVRSz>HƯԶ[URꢶ@(:!RI$Ǖg,r*Dԗi %8LO( ]S0n-1wuԺnw*W*e@-T8֊bYvҪWU7HP~yfʑ5|Bp4qT궠u5Q8,G܋j/ F _uJ{omq-Z$p,.UfǴ `݁ե$N Ag8k}/ SR [3+)&&:' rs,7ŽIɫ (# 忈+,V$X@+"F\0m ,N͹XƬ9Rap@;n;kfR<gabTaH@nqo6@|9+?=PixjQ%(;.HHb3Um$ qC;|/f `,Y\$;061 pG[>\PH21vrU@\0Ij0z gܹIFp`qEsC qp\N0yeȔXpI%pA''8hܲpZ6矏F?r!t0HdQ Ub s??=78Dq>Q;6j3$#3pC $Gs)` PNYO''k۷)$Qp71cώCCZ@ *نo-ERGE^ME`騺DPlj{;sxqЗy*jj,.pR :#@9ϒko֛$NF:z‹iJrCxyp;f9x c fTZܧ>J$9p*{ nc<>grن&猨 }Jm]a79ȋ0$`HZQ.@? f^)jnwV gb" %YLm*{ 3IݶxaU`AS$QPX5;X$ex.?SBXPfwg>sІPF-wI)jg¹$`A``ق HbAZ\-o,RԈ!I)*URLJw9<kTUN# rd`1 (s D`Te2rH$㜌HJ$k<$(E!΅%n^x'Z.:[vzfNe;!<ݲXnfq̬9UL ~TM$!PcsQœ ^Ou4SX=5wFF1ZSxN@YU=>tp7sw0?Zxc  n> \ŸoD/pgD8# |cD i#'R.78@5%>@~qߞ~:GSsh !Q,]O99<ӟKBvfn6u2IMCT[MUlITq`#/TTzX}mv ,g 9-`pUSIGI1-#F=3r|r]*e+* H{Gg<TljD&/I"3;A,lX^%32*,MJnPuߒ@rcV.ƒOL'ٵFP {E⪪J'5R\8z6[;GCqGUMdj!}w#8vՙ}6saAW#wq πK+52@ ש赒/:L 4uPʐ-K 6yh5%3L%L[\vp@?P?tgC0[sR:tW_~g!s\;Hc<Ϝ<vGؓe<ŌeϏuJ9Pr@<pUU$0ߟ?zkz$`y<UWs_/_ Ybӂ?luJFsN_?gŮpg|39:$j$p9ϒN3xO8Gr~~ /_Kӿb97x':a9|cnY(3珁ϟ#nsc?PW^F?K{F<X.qy0׮DK'T\+sYqFO\ `d@8tʋ"vm`!X۰>ߧ.1m T dG#!ǜA$'#TWT7?\*r6I͟8'くpA@Q7GqwPYJ{f#<|~AݜIs2: ܏$zxvw}/NUt77rpG??9 IuBQΥj"enG޸2F3#T%ǒ'a1o}IjsA:SYbݯTo7v8篶doU|]ۮ܁XŶ=E*?YXıb cCh,贕uJv}wy8$duօ`j%oQvpI<2I|1A~a"02r ;y8bW.P"(V A2(7)*.ƍ745Eq ǂv8_>03'J:]I` (o HH# !ʆ *iB aJE$ Y޷V+/SƶM$YC/Spe cb[joM%Bzr d_tcWQ#:- 2$DWz1Rc*< x4-41"$ q?;-4)$0bHw]rn1"B+D|KbL|vT.9i@41.fiQDY9<I~q/HNDAA-݀G- ~F2\c~~U#GOm޵ڨp,ݟ?pl(m}_g,-Z2O-I$?Ꮬ~F?u֥rϓd| 8W*\k×^L)Cz:@jLiQv ; G||~DɩtVEpNUw$8cޕ?>?QQC}g=..|i쑙Ն"7L۴gr|u X+M*;+s|<38~=}Wb1>?dIVd]+mߩFdY]qȱ}߸|X d{*+(m=ºEyjc)#h${y58r3|鞦u72Ϟs! S I"&֤CPH%mlYx|1tխAlz^ S s4eTQ )ZJLT Df TFWܥ)(dFBh`rFNx_'1X  ~Cgo~3"IUQJ[;Z5F'QR Ő+k;Y4@ 2q(G?nz2NS^R0Jqp!H <9ϓc (Sۥ?Ğ,y0;l0M-~D|ag~zcE H ޤ:IYNW,3@ﶠPIr`IpwVy??R#bXd$NN09O^*69<L]+q>C^/̷\0 byňcr@tM r TlvK4k(U㬬$l'9 ||qҔA~R'5f.ԑ67l42]W^zm^PӍζQ=9@FA`xQ:Fc=Q!EU s!lpIbO$2Ǖ#9#Ǐ$tp$Lu7QVT Lq6ÐˍۖbxhR#l$̍W$`t7XHPȑ4Jp܀@9ee???U&VyǑ`8Unf4*ƈ7#iB]MՈ81HkRS$1f=8G=9A18ҴXENFِ7 ds?G+T1ܧ>xnjcX_--(iE{iѽ'&~;1h5~EM^c<+D9l.0 5uũ)m͆z!+3֭/^[XŁc|s}q'u4K5R}Jh`K_j%1RUJƮ†Wq.^6*hbYzmFO{C",Bmwf' Q& do8IGVQ2!sb7/$Io8yىt`H+H 2-`בR h =׳ E 7w .79brrp%V-q$0с`?S;6 y^vIq9.Hum'a68I?>y,P:؍7.b6dH&;;o[vǣ֟p9d 8mu:HW+9$!U)85=M®o Bc:{fC&wHe`f/@ Jr.HbFIǜ8< O-wD,,nO`pN0x?gȍ#|?\rޖuYH;2sZVO (?21` 'nr?SFG^vP(pۆP@8$r>0 oo!v>1ϐ?Aꤙ(F W,[1+S}HjxF71UʀJTS:2yg_'n|'H>}[naL`HC˸#'Hof-ݐqGx~\GZ [UEH9fvqm>FGTnpA`rHݑ08p:?}b;dlT%??:${ 8!$W+_$.sr3_~hUWO`~}{_,jʾڀ}K|>~P*Hw+; 7jAzˌ2$1=fƿ!<`S]wG Ì6I|''όN!C@Ja߾bxl\jYsM2FHqGR&o}F^>\uU[łn$av 굹_Rf*d. $ ܚm@ĽBėI*0]͂$a49rO<}6_Hתw™kf@sH= ӌ 'N>~:kĹ 䁃sUVSb/y4IobUU=_)aX 9OOEk@Uṟ z؎~%6|m 8px>z@_ 9oӖx0?RԧqEH`np7[= 9N?1Tnj !?WAʎ[x`s$Ѐ $8V۞4(އN{`ӹ{ttT#h!#ss=MᤐS[b8r `=G.2)Ң箨pݕ]g-1=PfG OJ@(7k4Kв_4.( |2?'?'2rG<`~q~xxR6*s ԟGp3"SSHe\eI*y08 y$gԁ6!~ }$p@ :W5U߫⧎vBmgۃѸ8?>럞xtO<~0OI<(C尮von?0}__~qώ?s}ϏNk]z}8|z :)c~HHC;oѮ{p0#<uT.qg c:]8'p81:)KWr7yy=4PkE'8:O~HCS4c'迹*~rq,ҠA?o:T6P6 s3A}E4`V;_]t8wMbphl᰸IGf*D9ے?$(m'aG%Ʃ G `>-?8a]rF:SH\ȏ6*Ð28''G<_*b8ڣ9%ώK*FP"RЪ~p,@NIm~6pOV*ɪ'XTA̒H9I1:{\DIbTO9 ?N*/sӅ )\g'9X㤥iQ#̞6?N~%L2 f.mz #`b²&&ǿd8e$D~fS??=**#ӧ"0( *"BdS gxĬ@"BǍ'#Z&-JЀC tH*Xܩة?1x>:VOad8ϐ>~:z#Ď\sy:MnD[Ԃ|d`|S+1tv6:W;_0G@N;D Q?@g88soic!r lH+F]UOGXHC`8?k0\#Hb@ GC>XՋ"O'FI801Hs F&Yg%?)A^p@ӕ-f)TUG2I;zSOnO;FG򈉈(  ݒmyS3{qI < n% [?R [%|hISbTy9I:[*i(v?0 Nq`E$RֿI[m;o:3%c X$S*A %(*BO~s s)I4o(oD"U9*q疊z|لf_'b8G*>@3SV㑆)bXr6?>}q1 gQ2H?xa2,Tj޹!NSi8?Ny>VQH$FdjHA,p3:OIH,SUN°Dl'x@xeՓ5vFTVHfV-[q89%K~) %rȪNPM*+2V(R+A;!RnHbr:_7 O2ܶ@?>ADU3Gos '? 7}㯮 bwFI$%kH HK;O:3.DrA,r*İX bP&:=2zՕymU ol-Trw;'e'Ǐё,*7 H7qN?ߥSZ*^B7uc N#'99SeY;.3܄XC)vAiP.=j#y[NY4j6@ߨ?:ofrv0?'Ϟ~y$'|cG`5WjM)`I*sO<Ԟ*Fi9dh K"6`8ݏcn ϛ~rtYBF*ZCӱ$zu rvFeFNMkq'ۮ_xs:GЌ?+8n8Wӏ[o}b|G3?ti`J?~9J9ds_NQGǟA?Cx0OH9z8?ynH\pxs`b03ۢ\H 9$|9貎}ǎp?9`^?~Ԍ#q۠ѮgO'ߏ{?9<>$8?#8G8o=0si א9$x`Ao}'9>A K޻=m^rNIqߞoчk/c<^ 89>?|y/ cgzA#߹8=tWjc0qt`\ʬ817{~al!l N1@8<N:4++{9cN4$O㌌qOFPUI*PG1QmwÃUt\_&;_jtGw}bn ?@2|)QҜ3?Qc /O !;1IH#ЋQ`:w8Ǿlڀz7G?<Ǐ8zMN&Ud 'Fy9ϟFcB>7pA޾} O?9ϓ@#BxUBI d8ǂ1 x@(C ;^85> '3O$т6<`G+xFGjO|G[$U\U7^׷Zc{xG#J689ێ|cӥy#=G$wIRH8#:QoWSShfDl2O'I:"ǡr8 kpw լ7# W!(Y0!“<H+xƞEl`\G9d ԒA2dc n^NٌoÌ='!uJ*łz . R QGccnk~0 #K)k*2IS*+b3maW# `~-T#ŊG`j?:E5`w,]|ɰ9 vN3>?|tKh*pA!.ߜA㌟nk[CLzzIR0Fe@NTT 8,N`8|4Wj A8<ԫOb?շ^1M ]Wۂwn!U'~: 猀>rqq:E[%X*H zW3[y0bIR##h$g?~zx~u~0I&jfý߫6D I|O+>?qiкIcp?>GG+ jh gEF7nGAS08$wxiB@ԷoM×(A OzŠdt+MDAy8?!巌V!sܣ8Ϟ_ FRp8B(;fz6#G;LG/ tN[oyߟ#1Np*-6}ZG! 2JFL \wRgj:7q$0Gx=ZO meh[cfwI=٩ bVm Đ NlWnπ #mLp '|| Tr,n+pAAlNg]u%@S+mguLdGXʑ 2[53v"۠'3i1(w @#9L[5AᤏR0 :KkvJjju! #v> ʃd(rլUʴY)54#2zlI8pT*=EMN@& [*/>J/cDV(sD_*Fp0NFNHxzkӺFHSge $mCulhY/,JB7H/I$~[α :㝻_&׆T;Fn 03,@$r|ʁ6K6H69!<Ϟ(R u3I.2@'6*wW::J)U`Ups-Geb>ۡ7[^%p>?x暬;Xd7~<8K(.RNqB 2gAѾP0\ΟTNsgbiʮլr]%*#d><`o8곿?sۑQu׿Oin drcp8d: ,X睼1nj?K$IsZ]I<;*YB 1* iN^8;YTe,A 4lĄ2Lm2hbȌ̱:d?۷ 껔dRB9,~I2I p08&SVVx$H;w6T1:~K'Ѥp7ٍ֢@gyy`g$|?4xõ5!CKa#Y^U.yx>Ggr!a $}>XEijf2j-;3',!RH:_O֪Id4b!# OY\]r8˙ { h)c _ooE@J=$'/Ae$ؒ8Zkm}edquOu>JBJ=t=C}?bG1"FUCe BD$NVe+7TXF${t$'@dR@ M-jH4H; [Ip }WvU]Φ=A~k&TBSޮn<:zi!" ۷q9€|unAm6)ict5PP@~s6ZW;H 7d .:\u4 KgdFPC77 nõ30X Vհv~;bڌ2$vJX ynN==]ujaJ&eڼl#PKPeTvČ?q:]_n5ʱH1U[?98U޳#IPMLvf$WlDbƆ v'8l$I]{|ItM M& 6y^#g'#ո\VGi1s#(ۃznVk;O>bF7gp9'*g؊utK#NŅI!Œl@ӳQ$TU IE;0B+@U''WNd!c23Ta;FFsq\wJ0;9;on\#="{tV 3Xql^2@mFXu'dJw>I&P.2%#q< uZ۶)גCs@ kYCSbA'B8:_Cl۽eR&3H9PpVE]WUZrGԅ1\QP G'?F!s5V=B-Ż!>G92% 2yFȐ9 ]y['!QŐl`y)ur?JNO` uIN2/(C  *Ocz4|$ ` aG4%3j ]!׽A d$ToQ Q:.K~4W*VKQ$>")JNTFXUH HrY:AVJ"Qv|_24&A2(7@Bt6i92 b$C*2$d禸4$X)Y\Z5%l(pA8fhƢBJe7,2 %br9,3_}}anQGH*(]/@c8 d 3:alB AqQ%KEi7>YUڙu3mq^j}PAP]M;H}!X|OKXve\x`tM5)Y4Up*-3%M3x`N7ti<#m<8^'n$Y\ӤLgWpȽB!Ax+y# c} mBp1n]-$U1ҫ#ӸҴe/<cߞ5gRc"@,x 2OOIXTgc1~KS*,P‘+jOF3ƀev>q|K2ds+`nEHhb5j=zUf;(2lnN8a2-wW|vQ-$RS<-u0Z&gIE*DfXisUyU$p)NFۥ-VTlk)UY.N 9rOE􎋫|QGKriJN,~>k(hP TV4OX'R4[ 2Wm>RXbUWœ 9:fW-fٓ$bXcHyVS0(hA#Pg'1*.Ѩh㺠gQ8c]B#y }J9^2<聡(XmCmE$vN<hw 9=/6@ߨ1:|RপH]V_B @\TA4rEu2>˥AYCF:n؆G@IQq lIqXt SLAHc>1$cJS!7)!2K6i HևVa5m a]3 NTLԤF~8Ttޕg}YNiIN0<, #@C&aB;F*}b!fWy] teNJ;EFH4b̭Ԕq\j9]RB#r9$Q"cHP65٘)*5>bhIRl-@ҍ"FyU`aYlT!vUO5ή-7mݲk hR[_Pi(! !q< ۥϦ1- 03qx,ǂMUSe`H 9S,9Ӿ(caN8Djn[oj⊂ijZ4J*)"L`~pV!q>`@(P %2!# Ya@ غǻHl7PzP&=%XmtRQVF[,2@ rGMnAL` c%DN`lrH9CU kue8))%E<f1$bF=O5Ovs<Բ#+IQ J!#(PA #{/xp3 ieUD ubVמ8(U$e%ԺPj*[S]`C SE6d rp$p]Zh,>gRn #'>$UW'E"RѼ[Z)ڠ/&Щ2v6GMfQݩT]ЬX 5 X0j:X1$,$V2Q3\rB+KDh6LCI9 '덾m }۳7+2 ƒ<8N`ن̬hc#K *M2Y"0 #(*U2e;Wk73#7Yf( @0XK3y@uInoJ_B lHeq*N8 Q_UB6?]ZX$#28\gTyMmJ)t` QayfW;mC"kJ:CT-T,,#0pZu& 5b._rSӤ\7$G<WO $uFѥs*9 |OLmVܒҤdDeܠiy44ʮ0';8`s弞d2RM ه0C49KYAJՔ oL̪5F} ս[p7LU5AM shTG[ =I`GKKUl)İ FNrsɗikhSMSURӮi(b`-TX# #¦t;1 _' q7QsJv"@c, 禨kVUD Lpgxx#K])tikY-3!o`8]e4$H F@TY⍴7{Չ4I)@-,yƊd$xĬG+ DҒ3%4AB޺%@iҽaj-tq]7Pz'pHsM:}SpȊ4VzQO1hGl2zbFd%]68Uwڼ:H;=){N;"悉; $a~y㞩?N^SBY=@Һ`7fٌe@jIP*RċVqK*um<~-Q_O8;v G'+EC$h5g&dzep7"cz{[aN'( xH9ql֟vەCOOS)|W;C2d60#ol';i&åUi0fBC1g hobSC6UcKZmEjJtYlʍOBng8wG #Lۛtkl @Ki]Gl&6Un=}?IaNѓݗ KlGDpD2X.o 23hK)y|ZBA Lq+mr2+'(VD5BSV/DzUXmdCk5Z@㍙䐪1czy&Th (HG99#z:vd2Ѥ HrcKUH/2IM#H#iTdm-zŠ'<1#@PjG.l9M%0 mפ7fΕDu=Bj'g>)?%I,ڠʪmCH=>Y5n]5Eҥ+fYaf%0iِ)ZvW*UkYclq322!2\@$ɚ̧[L*Q$Zm( QWC<@F?)K;66,0mpZ) zIIFNF #<P}<QK ,TnfҚGOQ5S\'(e0V]&jHܱDJ1@ $vz,TrREh -4--%H૩lYZ@YImIhbw(DEF%BR N ݝWW+!;%P CVN4mj,ۘ9220y9DÁ 3BG]6s`ݿ Lut,U i_$LaYv~3҈&=Y(ڰk<kp> vx>/Tcڮ`NX(F0sKiCj<2 r{ P @,͟F|gpA|uȠ򌿤Osm;yF./V苓2M7ۿ‰ĻrBG #4ލ׿ո1)FB[]I4ZVVÝ29#xz!(!QMn& Kk̕AIJIDFAG i <[ڪTT3^,BpI(#9*8$nV_J 2ϼ d`Jy9x醪zW. G}d96"9]Q، 3G@9bpeWKI$j%~L*4$3X$е 4meCFFhx`F(=J8S & )%IsyzEG]sPkQ[,kM+Hy 0>JNPGS8DY@(S(tP˱!X J,nh9fvrstI)Faij5k.f O qXpI1h _$qӘn' <`?Gσ.H#@9#<s9#?KeX (_~lvzh~}Uv~B9l9G9#jnmg- \X <  G,g g+k;]oGO5@;z~b=PsAg<@< =Tw$=7```KWsg$JU\n Ix|sɕrycV 26y]Wc}kGR <Ǔ{O%8oIQIV 9xML )>j'JijH ,@'l HܓCIt4ȩē4PUHꄬU/jSG8=L!LIQ I ,0cD܄9c{QAqb+ = f.Q"I۫BdR0U1c 4NȮ0mw=je h+CTjFJ: G" E0kRkMM~S$s$kG&Xʋ ,z((ar&F\8#{qup㆒ w O]osT4ݘ\e e99 _ pt*E$u%Mm\Jn fi%e&Y*+P$o,PԤ֥fk,E}{W{F}= r>Uc<u:5uڨF )Rd8A;d::7 [x4e hՆ6qՉIx*pNв, g> JC ;# Dlv=v1uąؒ[i#$'vxhhŇ c 9px꒤I)FT)#9% y\󁁐l+-42P^exk%*5H7 EKuW;WMEdEE]53tf!$B] ;p, 1Hv3Mw$rEX}午?-K9v^nYh79BnX,82O"(JRBc38I{wEm2]bMMj @IX$SG9di檜ޗU+q䑜9\pzAUE o_Ul\mdP;v3|>mt0e 6J('90R9UrӷQBTHUA{I~qD.M\%TO!d qC8NvPa5@b7v#/$FPv0d IPJ#+4ȡX-CGHmW},@.Aw`@ʅ|cu aF}fWZS 2A9^@ лk *M  >%ʕ6ݻv'gy{] uWXഅ(|sYqc_wGv:5" 3BTs,l$?YIcIQ1Sq@+g܆FI}@uVodCsPkڰRid`Jmy9P =[RQȶ顪6"$[; _F:V x$.0#!sʣdKƕ)+ē }#Xʷv#')V*FC *CIlv #n)w9ZYph/4잘dlmy >P\ۨM Db3J~X/+9w20:sYjzƼҤTI/v@;YB9`~9M5,f*dL ʩTUFʹ Y),H+QBP}W,@m%W땙I4d **+ZЪlu}%EPʎQe@6'I`n!<0.ݦl'K)(1 M$K Hzϥ5fw ֙\JSHmS m=^NbAthzwYWgxȒ);;Q,պb[gzQOZհGV2DaдIG'{2rҝ@4@L(,iku[Xܧ:]G*}Qn,@qRubûMk.G|֓ ZK=cOF$edP5`^jEK]_uy -N- SQP؇)%%AIw Xh %]K.^nqI#\iapV1>*ŧE]SSvCQj GPf#zPMAd1+㗩3*hD8X:9ıK8CE,* `2}4Y؊5f7uP :âHb.f>`FB͌3lzVu5vDW._OH}P1n͹eg+O}^κ XAlc&]XĨ,d.rqԋCFش7T\n77G#7g"'әξWB1f^}yZy ,Đۉ zYTU-̬P M Ƞ"G+JP4,1-$+^C*6(ƈM&TZCIr.vK5RTTfQp3HA T } 4ʘЬ4FrIK:ncΞ]?Gh$wm?]RIS:@7z[-O݊X>j]Pm #ȡ391D|ie)xzԕ5$yH邫L jSKE@|hĀb IwqҦਤ[5DC"OHK*d* qM5ƢkkX%#ʛ0moSV Y*0`Iç^ ,Wu1Z:1%fOĕ#{wu6n)m[.pA-fW|JVB\EncU沱6Z<2C<.f H%la9XfH╈I'ZH,o`'ofSUbIpӷ+IYa:R4DjRU2Q Q m *pmI~I+"ӫN*me $Jq"Sq5tg4OuydG8`] PUF?Q\]>dz2%"R̛(R2̌͜oCҹY<1 ]D3e]YXղlV6%hd`{@+W@ "{rAaCQiũ(d i-C$3љ$@*»b<6:>8Rr#EN#G,g1R3NDk vj+p+,48de0QOQ]Y|UB6 +8GG9fqJlc77)q"(.(LdA&`!XYc4 ncEvʣfj )tA O٪?[H[Q94ff0I #.ĦLPR[*j'X) id5z݌˂ U.HB& &ތ7dyUpuc7cq#yYE%8"CĪb[H5Vr L1vv$.A Es d.pF1sT%k]tpܪi-4+sMWP%Ev<݀< SjKfcO)Xet@0% `g OU'm=CGYDK2zW5EpXV%-U8sUp:iW3O=loRALļڊv88D6KjWXJ(ho}m, sƭCuA?9fRCMh4"0F*dvHDQBDRv*RAaCbB^ f-t&zt'\jIr[jxWry(Eg&'Lr2Ǿ))W' ]mV^jon]GH$+r raA33"$¨Ak:OG."WlLYIIu ͒p1<+;\3e.p$T}[cThg85 T "fZV>suO<^JhV*"*BġT*t=Bzo51SI,A>;YH G]AqzdS1q(S!VߒNܶ%O3jPP#’zn+ SsH㮢,(eTXE9Li vQk-) d|f$>Tve6T[Ҽqdx5nՖk.ҷ=UQ]-u=RԜ"oO,C_$kY- 5AU}m+@E GG;I$X[k0Jյ_ů11zVijLI3dGpps)-uQDSTi&BTa0 ǭe6zJ*hMN+S+j*wwuh{42MxWPSCV:@˞c~3|cEkmJa]EQqQ#I/R\UM!'E'i<(Y[U]T%]M,l>؞EI}$3ed!XYLyu-HHF2%&HrYM2)`IW5zuݑ.(kvCkZ**dp"h{[ zaHu^;vKB*{4Rԏ{б3AonKUm]pTrJyZ<eTEdJC;US0IDq" ꖋS1Pn5*ek&Y}Rw$eT#lcک۴cV:4+nGbUa8$*$3krJWO&I_.13/|5򲒧Z;f LI4x ؼV]MX)?Qici'mޖvTF~GUƿj4M=C/Tm͑V0X9<ԃ9ZS7G[=bN*ܒ2Ve+#ub@ok$wnjꘫfG[M(cE 9] # =S6&74XGGvR:F JZhXx'Zt[veuS5JomԶ *HZ~Ǐ0en>ÂGO3UL}^~MlFA:{oc EAF$xP9󟟌pqԍkmD(d'v8giH$JpCcsNs灟cxJhp7YOmFn:i-h1q  ?8LG#ǜǟԛ@-iDzg?8|7[?Ym3$Lnjr3vJ P99,[r<&o ?K އBCG 8AdvȎ$62C> @c$~0ݬ D  9 5H-ςVB/ ᔌy>yE.j'|m醗sy3ۛn?_nGfv]Q' 0qvx㢞Hx3e`~G>:\n%lI*('*p0bF0zoHf$rܑє5싱*no t#:(8' P8`I89rĤw'b1X?O%%HXa!H\;@9ϓ,/Jm&N&_ A#2yzSYM~?<ˡM<26S(cv{P a%rzv"a]^ߩ߃8@d+tZѫctrF@ l|9= Q nNӲ_#N Ǘ2Y#0O>$m"b[9lPg.o0h7C]jϠ%~~1! m#q'?6\ 'OOrG?Aeh )т |G1a&0PxNzrŔ5y_v;o{xk_+o}>ݭCsO90709iPnt x 2@${C`]$UNZc#1eRxic3#9(A|l5#CEtJޭ4΄İɡ6ف {I;Qg-%B<)$PaivY f v %z`mzyf*T.NI`@P7Rߴm`Clvh;_v\?JRX,:Z-KU Z4꒱&Iv SOSːJsiwtem+&ɭXՈy2y2eD- jj#E6 ` |<9US SNdFBZ82`+ FBeFˎCͧ1#I\# _2 7cQnOl|uَ r8>A3ӽ9Z[P`[t89Eb1<|YqeT,XԼps, +=Ѥo c[[a IT8x="2vQ3rs#-CGH眓5J$B9 q$< ,+ {c]'J`(mמfHܻ` 6䁆я*D7cq4lP@v,ďb$Gx0'G<8l`UI6,q؞g= OF_+%-ASǏ|*$$ Xg<<|u`Ch^8r`#A`O'>p!D Qm}˵:NxQcd=7k ?ʐs7VV( Xn)1^p2<ݑnjxF )Av;w3ըw9e؛a+9 $"m \<“vFFpnM߷m {tj}Oj p_ha 6pI0|uٜa@n992 ˢ-WP[ISݟ㦥Tk}Y\w8=!8s9vʭ|,~A(5W5[oBY$.|~gf9Q,Fpq?zw%1<1@9~|gD1p9<|g=T18j'j؋ZGƏ;W>V;1'Xg9tz ɰc$''8sDTLi19>3G}U@'szzD('kK!a}<ׯN0 KnbA |~p2?spr<䑕a`O!(XZ1 ;G'''灓 @_r1gp>~?өDoո]lo{}aoaO̸2(oG$|s*c]H`Ϟ&N2y${UA'x1c~R ]|RP~q@O9qخϩx2*j@y)xpK`zz΋_A5̉r~;ɿ.hWη>Z (Rtp2 WC8pѸl$a&dRWUFOۨ*+ceAP9C. v%ʂx7dxkTۭUxUTV~FXb+-HYA/#4Ǫ82s*J JR")`( p5z71=?82H>Iqllچ|hYeR"( P x`H m:Rqcjc?!ap6`|4NOd4HVHhVU`̌o%J'cڻOA,[u>J^hnv,YB]6@@qϒ@瞃[c5 zdg m}[έABm=X&4NJDΙ!q–ρ2kZ[6ӮTgL\"9"Gpr=CzL4In W 1xS?͂6L@ĺoI<9ŬOwApi0%gDWrRgVKh#z >]_1%@.AZ@(bH}"谰5W:y㠻sMeH"SV"W ٔGP4ttv5ǎ٤lvߧm%5)i"XJO;TsB psq~Tn'9g9gMqc(w/zm/OearAwYR(K͓?`^wVVIbx‚@ x㌌t9je0I*|Sٍm}?Tu7{˼!AA-Eֹ;WNʞqNuQ(`y00'S󷞘+b (y$3 kZbVY%cv$dpu%WQCR7w~Q) U1s$|'&&Pn T3F[etEٸ8%H#v<8il!ANA`~r9& >U٫~fG^~d5;>H#?Ia8Nj RS~MҙziVX)dIQ9H"gb@os@`{bEu7u@^~@nFoCY!J=T/U VfqFr .d*x '03T0zg hSU eg>8Q3,]mgo4,HF+?'<JD%Qd`lF""b-9[mGIczo|GoMvCEfeVIWڡd!]pѽe}i1\#Hd2pvOd{Uz=Re!g@؝#ʘY(,-x--IsI)A EMan2£yγ̙p`m%H`(9βkҽtޝgY ;UG TMmiu6j:JNyNJIU1//ruƢE0$OEB44(J N:_nӵvIȺU#UO]KR^6|9l*FIxi3*l2YK$q9ya=$I-7()Vfr `1f6@Um%,uD 567F36i9qEu$+%EEVէ5l$$+ʶ2?XYS1̲F%s9AUL1,d-WT妗<£RE⺣KXtk hY^:oZh'ڧ颫Kj V5[I4L@&K0@?wE"01XmaeZ4ʇrA4klx NeBTl:3Y6zb ID5MU"V-LHbe]03RdDPƐVF䓵xc6&IbI(6~QvXnpkҠ ؝,TުTPTTC+2$*"B?FH>́Oi> e i6 3l0pqHl UX=x"hL,cAPN2A ci dU@p[-N0c9 XYA]Kѷ*) xÞ[bڛzbA(-єxhiW"Epdnc91p Dg ;8@x4!Xm`rO 2|ZW`fWgUb”ᒬ  V,},Y$wR%DU[uu%-&F07n$0#Z~NʑY*%yP'dcVѦ\WH";BįIb[Em1=m&92GͶ`tdwar8Œ;}P( )KU'dTf$z̶Z8Z<$ #d(##QؑUj4ȆBKJXP -l,V^mlG4Q&^pY2 f'?&Wy_O#Dd2m  C=E$QZB;*&Y$іԹ8j4Ւ[h.Mj. $RƱOqU%8=]MoIx<[3qy~0wj;mXoE{1?ά$`v@~-O(YN=(䝤@I9֓[,RJ-*p2Eی=;LF*^o[sb:{ z'l%FVRIsrI{D_ #s֘m;Hwi瀠'`ݰ篟!@x#j3a2~q>3ȴ픒18> }%8Z6@GåMq2i?`I 95;c-j!8b c @ LtM$#h I'NI''ۡq(!S$l >?H:nS5P??kNJ-5Ʌr6`㞾-l8 .0G S.e,9RO9zտa?niS"K yAV軡B[{+V ,Bǀs9Ϗ_c9hh 䌞y֠M5FԱ6ܤǏ qfAO;C} +qϾ8ʭf#{F Fuv9ڮY'N1-GӅuH$:zon@06_% z%}Eu\NCd@ǎ]#oƪmPAqANOp."Zس:[T(=FA'^ =[: haD o@bWqT =Huɤ`Xǟh$ uIV7aP8,q8HH4,Dt.⋌` I?F~/`Q<Mowwlfm3+x* 9I x.6! ``0#H֤M+N RLj%Ae%`c;GN[6B<sCs$X (JH?Q{+?#*FH9ǀxrlrB>}~s= ̶﷧pwU|uN*4zzQ)#/I|G 15_eSpQ/(IqǦ(zaAe$$?uQi&TQPUkl "Rl5g u, ̹GIв2Bj$='1)YmETsR7ۦ)AaXFn q'MzSGY6psc3ַM[j#))! tIYO 9, ʠ6'#h񑞭2]n+4hM-Ʈ?2eA9~= 00>Ӓr#>Nr kf(ln!|Bizh@P~?n]']t/}wJ/{x_Z#p9F>q8\?VUëRA<$y'lX"RPpq 'ePN"?AHbxdd瑎0c>dMmf%5]OqՌrtldB;aRpr9Ջ`ml)8 89#aG`FD%RfI2H cq`$q? %*06>|i>FTL`c /$2"6*\?wOR,Uz)h-[=`F t;H9Jဵ$7gY$~sut.׎jXKKPm`T|tziA #pSW,WsA#9Q6}jSϵ^n[6hcdkD{B40I$9=mc<ާ?C!%Oe Ipq֨M@G?1xfV+ 4e~ OF9/˂F?چ5UնƦܞ7͉nBGjpJ;Hf1.M ?|k [%V@20 ET r\m' s#Ӕ+c{0ᴥ*H"F2`P c'C$Ni54jR>6Ğwۡ4l Gni}_YdĔQP#|8a~qcVS5IQU$ͻ,eB~X5}#C}01# )6q๮h + F9'qc#߁Hdr/" ^Kc~q'pZq5ӶM--On*;bIIjFWgHB$w1fBuX!Ni8"ii"rȊ֑c~ ;pl".iы! - ԍ5 )~H$n:)Idʈh1ĩmʣ4TXjkk+W@۹$quBi=Eb٣P VWi## &u d礚k: %Z_zC4D詽<Ѣl u߷5wkޏcͧW :Id LISی-ֽ)aS=G-t%iWV$7\E3se2N͗|b.I ]E4er*$35wiP/műO=TV[oo6dkk7$b1EDlFS,#U€OV(tWUe jm*H5Ϩ=j=,0j*Z*xI'TV0F۱m꾂IBYr?y[[զ* ]ھj;琙aeaHră%fr39 &Ȯr΃E4ʍSF9/q΅bl& >P2ٶX,VHQu Ʌ]=Xf0!zr[%SK`kQA#3k{U&kj)j$rU"VA$J{ CguKWho<{)` S h>±2,ܬl!f8p<č;Loi^u`5r.ZyffuD܍9 ?A:^-1d\})\TLI+|rE*?ehwI(lIS2eCYaS`5z]Oe՛4Ɗkzk5Q-DC!+Dyq员eV:d3>ֲ@]⩧yB:,ݸ;0UEAI^G$woE@m!Zq ];,I -jJ"R4zrHiꤙ]V$̬hIܖ$[6I,IHy%ZQڨpPT=j4qeE5GK4a!M`ǽ8eiOhmEU*sbuz)aPw,!D{†7;Z\'ZK*!jIM4uD,9".NʟXZFhF\r-VvBujF-40m+NJH9]*/4 yiXJͰݛ6U47$ =[FUEoWfӟP}ӏdoUUGT޹Td:DR$$`ؠ;yOv;o\e$SiE4mL v`$C+ߎZ&ikP*dTi}8#CG^J\K {έ}#z{ in%9IذU'O*btLUTb $ir?I$JoN`l NrOt`nFUa ^߶(,o7H}Tdr,UpzA5T02)`2PxOkGݷ,n`zOB2 c9(<qv9ߥnW?>h^ߩ|QbBz. C@ 7nR۹p$H-<8OHWۻiiV%;  H;qx # 6 b$ dSۧ_Xn۟})lTM)' rK?Psg QP@''c0:Ok+$* 0HgJK2IG'ne% .@ ,{CJFrrFKy_Ǐ醕jtiwie@QC> qv9VCO+9۲98bvp߃۷0F 21pP0OIdg$3h,!?#k *qKm0iZTh}<^cB$hr9$_Ri!VP\ltZESQ!aj%|ث[=VUVv4ͮ5,M 8i=LTG(vq![3.]WVٔpBK- 2Dp đ$SOQfU G괽 Wݫk?%!J`[%tp*p[qGlꍑ&/oA,Ơj?c\)z`{aAU>)by}q?`ڤ[iLUc47Z v=(t-ESYIeLqDB9Ʃm/LrT2f.30԰`]g4f%Tmi#TlCqEr$4Z7`$̹48БLlzm]@C ũu&]:[hORSt*e4i$a೫: i2Xc܌:_l>жboP-O5P:j8瀂΁D H4] uHza|זk*ECO!h婫ڞje](-TBSIIW!YQ"T%$ƣmrOgam9 pn'%\ϖQ## 8=1ٴevRF! K I U26K11L *@ )`E,~Aw7%nS)ZUvy㧅KN9U\nHtGjzږF˦:]ooJQQvF2(Y$m E%IY(K޴K-GtVVU3e $eY3Y}Go++씗iK۸_jJP3%TDLEwX3Pzqx09&is9tYS#djyf>pŚWr4dۄUcH*Suuur٨`\qDRJR(b8 ", T}T\\W je:*XBnTdpzKIU-HiCBU4kKȯ1 E;Ivz~e155$x̏U9U]eT+m%N<]L#Yys'dr.\͢9&HV%y!>i$`ftJ":G0y]`Hk!]/FH'頀.oO$_@岧PNI[l,X N&RuIM¥l m8;hs X,qQ_$5Ms\&`敽}BV8prF z2a w9 ?nFyBʕ "6P% $ipvY9'-~$7j㤷<5ue%Ep]hBrYGOQjrď Ş+GPI]Y8fe((FH0!YVFh{aHcgSE)BTVvPGQۅ6#ɧZ7xgHeڑIwFv ]A#D` TEdX٫cDTgYUK  ,WEJ9;|"r}&c pgc%1):Mj7+g@U.¬(f˲9OM +7b4}R OE. VAC2hGa@.gn=0h(kj]ڤмz~# &Uv/n>*]ޚ:imv*׉_FTj ۽&l*uC_E|zo]Ve"e7F75*Q#*J*ň/9wKfy +1יc|ʅf `"M>c:K̚m1K,1v. Z- Хe\ɤEm.Rye Af{Ulfz4L&3+!;#;䎥] <-䀘e #A x##sۭml8ڿQ]6x#fヷEE *g p6מh=1hV ƾY"*, g`I=[GO\+N졆Wk<f-YIy]j宆*Zx><26 r Ag!<QC6b XuԤ iԹc%1w{!( i \8dzh,18'' 9Bn6n08 3|㞦OUD= k` rzN9bT$ G%&ˢl 3]ҫ}wEiP s|w, i x'?SL 1ibA9d3}܃·mǶ={cۥ^!Mpǜ `| v(˝m1 ʁH98_%PK8*W(X 9=p-S>rOoNRۯC*9߶׶!^piG gi=,Ğ>3Q'ըo'ڽm$A+K>fesUz,QS Sr0V4B)1frD$$g෈ -5%=$K i)c2a(B[=5ŧ$%Vz8) Z@wjcS#H\DJ'9+$>j(XcG71>TPθ`-"ĩ*dfbjG`? EXix"in gId%& F6*[,4QĀ*~<՝uZdnhcLu 2r ƈH#@q :d\)k5$tuM*t $bk>;XHogQ2(eƀ%L8Th|睲L"oύH!T"$쇯>aTD$\wRĄlIi_ ܬ-AzXV k D`<=FKi* Z+lץwMB8۔uYjc|tRY l9iEs|!/wsyɑ6bbLaiG)"B`2A1 P¥L*RYhz9CT8jۥ 9\p)BTڮrx8W|פڿOZ_RRRPr mէ݂EAݽeA1iSZ"A#OJrie1wb2n^4+]ƤGO$ ,T$URv$g9 E?\+;1+o LG܁u}yY#4<2 V%Eʄr܀ m^Tpj夥Y)ҕ*VV!NPтF~~ h(,zFAh0WIVu@"YJD*2Fu֣ -C"?H4 \8iDLhqw9h=jֶڟcWhu5Eڿ [y_-RYssx{a*Bn]#I/D 2>}&&achu"$*"ސ}h<b"6A<}eM ))g'0:k=ofQҊ9a| Ynec"@TTW( ,Vٕbqӵ2TJUpۘO]^_;-q`bu$b9BK_IrFVBj{ԡTbV[Hbx^[b;]"#ńi)G #qG9>#N(U!%#lyR1ӡ N_ A6wqWRj V0URGV-#YѲ䜩8er,I e !$[P+3I%f'ƠQۓJ]aJ mA' K>1咾k2TVc#uEMB $˻zl$X4Ɯߧ>3QҀY;sPO֚OlZa+MPW#)`IJx=dG'Jl&y2.UbB(y,$OIMyZUB 9Ld`4ߨ($b Ԛ:;#Q}QsxHSy9ZzQq]E 78xHR6TԛJݤ w9<2Aq=LU[(eAM쉙 2‡ )VLq3(E-Z R AFp,9FV`$-!_KX$ڂOj̥,r&6$<D|)JG##O$_oG}o(ؕKͷ%A] ybqkM-M} sAC-`LEb҈EH/ERYn}KuA%8knԐ+bU4::IK:79,[9إtnu1Mt3՗,i!@P= =Jޱ+5LijcNj8[sPĘ<}bs1N"!2R=yI-Vƨ]&$ye,,gIԨ$>XxfP)e2̐RqWj9goj$$Z޵^Ke[1*㨄'3v#8myZW@\AO]G0"W#+C-1b@8FBnuY Zkf6w0Ҥ}]`rArBN3ՏĞ%;32o EjRن,(U,}"Kre).fg:H2ʼnSor+dܮVE546ِ85@Y8*r=NLơdYT8'@ pp>[$t%!5#,$G;@UBIX,8 gIӯh#bZ6Q*8$`jZ[U@-> ]dd<19v>vNxttTLw! i<Cd9?ȡ]H,{G"lsc|c<0Q ㍱e#8'#yS蟷Q1#lj$‚3> $x< O8Vcg>s?l12Z=ANpORJGFAG#c>p?=?p26Fќ 1>>s)"veUaǴIɃȨrFX?0>`yTf|(P -3IpC5 M qGa",v*B @{Otd 9|3tt4LMĺh#OSznh,.I ,ʍT 䁐y8n:|K*> a &|"/vx9yMƤv89!&J06H**| \x 4O׏0R&!oLS'<9|q꩘!2Ywn@\|cONebPCx 8g`d4@$d#6x6 Fǽ$yQ}#:S)pVi qs1%)q`|<E3aRJB3Ѩ{===vEH* ~mߑ;tz@'hpsA8`K7nC27~3sӄ{(`+898隉&}?3X { U}2@IY2xcy2 oޛp@>|d#vG4 #gۻ.0y't?LFPG?={MI~a2V;gĜp01q|a(~÷z9lO$NF"wHH?VHx0H}8ڪT˨<)i'7b=U@_Hۛ.[rhsHF2Jx898o;H$~vV +NR%W)UbƊ΋1ಖAp !N7;Tm8,s ^}KvW+`+Qj_ދSG <;TBdT*HvB 2+DX(d5Dӱ78m#$ `AJ)m Ȑxxaw? R,QTx9/<ґHHfn<3E$3#Kv@9sӰe|~s|Opv=X=ka?M/~y|2F}/ 3'?]Ӹv\z9d|O;]vmf+)P1<9pLs)@h#n|#i~7Cmw@t]4ۄ }`aI,*x+U]omzSEvh?5cG0evTHTn ]F#0rFx0G:8@bF0 p1`v"KsϞ:UMQŷd\+0+3njRB~ߧ٬I3lld~s[ޚg*B劒=w4Q2f@ G@oz6fx(9$H~nj z0`j862ϵ>KrۯI6F y~XI=9oQ3$&Gy=)jO+}8/ڈ2N9ywe$0 cVhe=ʙ3ys# 0DpU@jHV6*YX ,R U٣- btݫL`];cpTiVcd@p Ji&e"'!qiKƙԢtpd&޵0hX-CEW`ۊG`r:ɵ_MEM%VvۨZ:}5=sHGM,%*h[XmCkK; ǩ- #fKžf 43*3<;N't?UdFPZ2."`PD;zX1%Dܚ ]uKClѻ-a Ȋt"%bѨw@ ͎E(i=|-#Sg)SA$:MI]LMQO$oYR0!9zT7.[hzuek9 =!6BHwdNBe^9N\lWiz4~[@P *Nj`<DPTB ljňe`VʰbZ b+b4~A؍Em"%Da.I e8~jXc >}ϻP-+.cN_TBk|su կjy?iz yh&74AN(Fy 2Vvv}`QQ[-vZXҍid4穪(e(p =I@&Q]M5}Z4OpFZ#fT8:c08UQ: ܚ_v*m?.ih*֚x)˔U*ă3ľWi*=e#WWZYv(U̐W.Qnb[h)Q3/bJ/.0A=A_3@%X\}[So1qcӯqtjԇu^FPQ銋56mVHИBCa_Mkpnwx= }n-UUq5U v[-d쎢rnm\l^?Y }5$uNBwk~aOmʀn➯OhKgT%MWT K"J}NgDQE5@&1"'` yLAHF a%,Ж$l@#X`|餜¾,YUQ]MZT De'kA5lLVVf,EKd>ᢷ)-wx'W*I0TS3$2* ehUM%pj&j~RWFC07ya5;TuZʍX)i ZfzT6]EvmCI,44v H䑶,' ^N|cUwe Up9~z.Yy # ##. K 5c4j \J82>RIlrQ o|%/EZ"_$瓜d> 7=DPweN<)R0|UՑ]ap+`(%DJm\*1I,8)PR8 r>cтSSw,`VqqG=7V)ڻ^P岪' c<-A&sO~CKW[j{rgB}Y]# $ IU@l`gy$0NOFW9f&pv 2A@pH`@dOʫS+Nqitn>]AޫzYC[M ʒH# d 0A"7=zٙb R|ECOim}! ė 몙1B`r6m$iV8g@Ȯ4_^/\ox)mi_4Qi1EVJ6K%_VY@PINNgMEovP;WQ]MnFn֤wRݪSMxM%2kQ,a<Ȍ_׋UPWM -Cph e$;%}\59M#eG8WKd $sjQToKsM PCU<^ j[)EWCeeRʌ?:gD](^Vw7Uj!IiΖYN։h9MOK"<[q,O9[Pw;]j+nOi]]Sg7[icyEHUR=$tJUԹw>{[hljud{9VM!}@Y= )`zfllHq1Y&GQԹEs'v65f 3Fvp BT)hG@L_Ɣ>w3WYu_wzcmKEA(8iRRiy=C&M`_;_c=1=slIYQ?\*H#HNlrP%<O]jZ74⊖Ref L=Π/JӔ X9,G+(6b](ٖ-6`0kI*(QB-K`FDb0l ,w,Wf^REꔐ,&T1lFJ7LWEoZJ[&ZxEQ%BIgHl+!$6;IʳMm^њ[a꺪E^-P 5U;o,dr0U$vOVJj:{V-,tݯOsTʳOQ=T%&8TIH rBJ225\QF@ZЩ!JJhE$=& AM0nv ]Eֿz2*:T)\"ޞ mS[38'Zw-Rn%\ڻuCfYi$#Ȋ&B=ubh/-3Q%U IcHlѭJXՕR.58e؁T**¨P2N\ad3$kj2EyH%F 0dp рbwc*9nƑNG^F ?{t1DX,nBA]JP<ĴrcFŒ2INyvڴ穮e%MSح%=9*&edAAq%_7fiQ^-v8󗺲2 ;1Zl_/"E,J]#TYTJJ@bljDGRʾK e-)̂#)[kgtEbμ#5 Kokkjm{tfBOvvکWsXAoM"RD6=E.ߩ l]9fGG,Ԍr$'ʒSH*mJz6WzeKhY%Zj/TNeھf3YKF;TZ]C,eyGqSyyl #6X$:HN[1m+3AI]Dֹu];A-RGdHKUqLjic,"#t_h,T} ݯ^RJIS=$@ƫN0,eqzQlj !q4Kh3W1#B[oݭzuTԔ,]–q*SǴӴP8KJNAWuyB pAHX==Di$ULꚋ1ڦSVEOZI #_OC(8*AcWc=\j2XJ 8;~P {X@b;*],Pn v`NNpA8>:j4r9%2{@8'8=%H`XqߥJq?㊅G1TT#|8< g$gY֯ck w8e "44aW!~H?hKgʅ(> oϟINGUIeN Q9as 1~||eF׹8ڇ}om?|~dK<6+`88?sy% -($( xm)2sqE,nщHυ<`12:UU${Gy rʃ}k_1l}1l.%T XFNwdap9z;}0 E8'`PXʞ9Ԡ+w|B.6vx8[Mߎ^Ոܶ)3RBYI(N}8| |>ܬ1I“Ix"mA*#y9G9C`ЋP酡ÎskZ6ih"i$!%pU<6 [55ZԚLE2ʐ>UD,`+FAΖ8Q vfbI3$꒪ͬ4Uz OSҫE[WD'V $1O( M,*Ƹa+bd( Eݨ-.ZP%lJ4Q X iIU0˖#xN_'L#1s-"Gq3,mhcU !SrM#FW.L9Ufr0Y$5@ǘބZS]]u((΍R*ʓ"zȎf:&=“&\wG]mi%ʊyzd 2{Pb2Rkv7meUkk5w_Xk#JҒWF#tF zq-|SLt::ӧl"y)s)ObU zч*ܶg5s>{3ƥ9fY|Ɖ= * i$&d5=,@B74$2F}؛lg=-_b5h>v+f/<0G[DFsVc#~zK:_Lw?C]!7Sbg"PZT4L elg#S'M/+QZh碤ܭrJR$&Z*I+qG)2W\#˗^m_(O6jII@W:=O.D񫝡(pzfI?$yrj{f-hEc#c]=3kexDL G&BZ#8G9mRqʣbX'^AovƊw ePSIMO^WKf2xK,]pN7mtѐ,TU^i.UEa80 ,51Έ됰9kUk_:^'44’iKAHDmrAE\;%꾾h"S.&jĊZtVP6y'x4\ ` <0e yL4×He(k濓a cQԯdD4623[PH &+?c[N12%J veH%en7xb١R19@ȕڸcfIA **uORjje)H`hd f Zb&@0.p`UcWs>,EgEc%EUM$hܜ$(~XЖ 6[ݧO-t.]&jIV1RD(dc3Z׸;ΙJuLV fnS 5H]TA#võ}TN Gsof펌mK<Zzs@b+ =]4SFKKB!aH=()Tcb[zTZ(UcEhк*TuTk/2 4<(l›GLmBIFb$u|C $:A gsIS,aTH $c"v 9V5H󪨭#a[/,K<9n3mGQ.^kL'Դq$zUx̂{.ےs![$aH (*ƅYfsbZf=ܴ]E7*Uc=IyW4ڡ|RrɍjvNX-֙5ߩ PIuJAS9QU$ olT+g{`m걱ZlW;GpTa^ mE?j*(@,A[9o,yNY? t2 f[Ȍ 1I eA,i" ym`qn{N톘w9;wl>rpOvjh.8#dd\mT#r>o#h(iS m*tMUcx#"6XP GS rH8eH¬L؟1'nGAW%c#>OFI}vԎ?PlrXar09KY|pt1ra#D <g߃x5 ;|k㏒TE\ܲ7<A1<sﱱcCڷ8{秶8ccbp<^zA? P@Ǵ/E VI$mH2T0cI#~7aCl!_~wڻ㟝n$eg^H'< :F|VmMvYQۭUuUul҇Wc"@9̲9`1,^J(I=PKLvIgtt)Ab}8 WIOE#v8-aA1 g#9Vz*v>JrH8?9dtT:_Y!rH!A8tbݲE(?lOapQ>&GPTbI?#9b FNpry-yObC=|ywdفH$s$ez ;pa;D:pÃ:*|N2Nx/98<`gF~w@e8#i||.beA`?YnTH_v0yʚh3< `p @y:r2˒1 㥘hAFm{s1E[Wwߦ (1@*8'8$c<=6$ڠ@-rydO+IdS0YHOIc&&"RwD(GUB99/ѨuL+.B)rN1OH@w(+*Uy<qϞu~oMm>O# BI 3I' dc(uh B[p nA#u($a@Ѿ@ Cce`㎕UMH=l26@ \y04wڥX2H`g #pF& rJ?<N0UDS<H*8\H`Qv bJݰ cLDƱB0UXXr *8E;噷70H`Qc *.w36Xe$='*:@Ō=E$r3 lX"ExQXUŒygqV5!Ɛ%7{|r m䳐 A<@dGM*p?y#23iYNx?F "m?tnyizədZ6娅I60^vuѳ.;Z+P`]( zSᒊiP$ndGP4];IHm^ tvۜNjZnzИ(VlcyUQ u[7 S%N"1 bS$m,74#A b[KE4m{Һ4 jJTԺ[t[*$cY'So)((4q ԻU}i-}G5 Q/=l7髣vY$)z9osR&^qzhnj{UozZuy[|0`Z@Hfԍբ{?kۉd Gz5[II סoJaڧ+.3+p, T%B&I-"]?)rFlHGBD(|N.C}>PVPYkQ]T 㣒i"'S&2 ;ӕ^uԽ;%]YSQc1 5"Hdi"2:2[_m=}4׿څH҉햙kbd*e22$(' "ڻ[ӚDU)h$RӚhU&X6UzzЩ_ rD9|fSVP-ǨKV|[rfF*Ħj 5T-\ph4o?wcPuMGI^P܍\tI^Wq7:rz߽mjK- Wd+* hn/I6Xl5VWE_iE4Ծ?[.ښx$Q1?hJzz^CKM hcaY (@2ÈԒ#[/3N3fӴ-9@b AAE<Ha'BC9ٜGHS;Z2Gv03T;M*s[dF}i'瑒?4Q)%y `NCֵUSH4Prݐ61x׽+z~:5*U$N'1.ߪKES9II`7P$. m<(e+vvsWfdjOOm$e0b:cH.`VOCy|@XzDDrOL VOM 4K$ ̼GqqF]iXd@гoNOmF1qsHaACA>wI|jw}!5O@$hm#98 c8=w$5IbSBDy&oep76x^qXɴ#p\.ZW\YK--+k*1v' Ox3ܕV!.r8d0SO ,"L2aQC9L$E-Q Brpۧ-mXkX"*)&U  Mq"u+Uq"\rx#v3=.q2'X㑁ẅn gE_QF2߫ g1vְXvW\Bڬv+1ǿ-#$ |SjjW1VX8`s}HaNW9ř="N8{qp0q>_c A;Vy g#<$ RqGK$;cbyCmeKi匒BQ&좟):_H/;u xP7n$?@ 玾MP"L)pI>q7<]w#CvNֺ DjJF43GnZ;.TFpĜuAN }?n{C<Q. IS*jXlvji7 YQ5NJ.GT!ʳ\+E4$b3$keH"GUi"NUz{p}_jx),V\/qNLnhh%IRFVl*1 M{ LPw[/otd*Gn|ѽ~'+N=`=ZiA-]l=|;jF.[& ڝE"WG"1HfH^Rf;rI.A%;ϼ X"Y=fʀ+"${` "TjoL@a9&QCH{[(OkQͥmqa)5Vgc-TB\"{*`zêjh=\ӛzv档ֵ$ (+vш=Nwuk;$@ h]E˴b^wvgy@&=Y"6[$N^$SjG:"U!& ZHu1$I [45ujfq$$JIH ~Ÿ碩o+$8N8; K<xeg$XL qµD VyL[HH>2՝Ox榖MxS=}-E$RI8*Hȃ`O2 (T`{9? t}pbW. f!8p<jn.щF#v11h24*d##?~Ȓ)w#ܾG=0LzoB$clg8ܲJw':JܺJTՈ)ۜ`pGGΐpU;%T~s䎌oZtgynćJ[,u0#S*hfv *g=TW't4-G;>җ:Zu[;4䫧 yoUنb9`XR#'꺖@EC+1* '|>x)A 怬R$RZ]YHH MW] eI"G 7lX5w~m ۉ$xnwHJJA C.}񎣺Q}Iۨi~ܮ"T\fgoX#4)UTңĸ4AT>Wvv 8gAG'e2a6#9䩦R7ϒ,00 >GO[*_Mp9f xeK$+A:a(h&O`bH!|1@=rj׍L.$eDqۂ\sصoi9 C$3@O ҅t? |wM}^@VH,v.|y#|nJ;I7"lp<9=}d@@H:mB~I9r<'),RD$lqm?>|zPڬH*߯CU4f5l w1o~G]O4nΠ7ox$x_B"1pm+`N[ㆪz&8 lI2I`'Xz+{7cr,'o{*` cp>p?',@z]<\|^2NJI8V]&?JA89gҝw1x9 ܎Uj'NC}{֫|:C,m mFPX[#Oώ\x$ 9`t' A U2? $/'9K߷y6:_ߎ8mxKW4{c Br2n3&+ب+cy8qzAKQVݩ=0I-,D&#Υ9ccYCb?02? ~O?,FۋMnC~q8ɑB)>q~:$@;$g8O-,J7^LĂ ђdp DF[$~8< |qmcu$`oo=㋅)jZH'^=9Zy(sVWw3Ji筦5š j]Ql1щa"CDing1#%CVV'Λ| x Mm0(NS,|eH >"#"$9VEx#h.U[\+A!XSz+{u"6[t4IUx%HQi=ʬ# m Zn`QSO \ sUiʘ-Ž)-7un9V밡xcoFS+ "V;>bHmuiŒk,qCfƠju$uWBIbx!3=a`̣Z\-ȢnT(7pސYwR,l=fǧLMQ{o܊eW[KhjK}z<,2e83BF]ڲ3ZP)N7Y檴-쎒 5I,˒7>k}[*[%eEQST@* 92L:i&G2"j{&Zcڨj!HgXCY\n%[9`k|+)_eW3,Fau^5.#c!#N"#ȯI.RƑ@K hI I`]quotkN6{mŹ)XIT6,jNTuvYA{4j-M==mmmk|kU$r{A^F:$ւR]fU2U: X"K2"TNK˱oE W)ρDdy?9XdC,0IUZ0C)>U$ǝ4Kuu k4AXsmCbM^)cS^Võ}j jNf=Ѡ{#UW޵7 !A ՚jԎj&im4JO\{G"o|]+VhCJYIç=#ܝ-Tqt0\h@}܍VSW(LcuP$Vjtږ+4!C0$s%8ph9DȬ>xzf#KmH[szP%id1#T΂6]Gh~R٨`MH {Bygj#gNVأ5u2ƕWT\%_Y.YO Mq-6ݓZO֑`P*Wri 7DF=u_)H&ؓ4xf/ʋO4 Emy$Җ/ AZb:t,pBSzFkEOSJ($u,󫌾I5v]CYrV43MSTjX"Яpy"s{D5eUN yL3j.U3i{,1Cd*P2$3vk\]^(tPPM,S(̲ pyLωLV'B*IZ?:,y/#ef",#fS>Z,'%kP N]b4$4c]@NiviIk55LXA{K3.Hm[HHTs; uk(i#mLSE\m!$3\`p0ri7k"w50/4$$^6󏍿{5{_Exs{SSh$ '8>nTdO y20dYxf&ȲA YtsiS;W_;ygyq Ȳ$+,IAvi7zK}oCO===/sO6QLÇq<ԷJjI~j4Vn+e@Z2\s]B_^*Lpj`QKE)7!g`XI-z[h(ᠠVU,,s<0`iIL#Lc\.  GVg}99$Wt55$nCSP`ѥAKȇkwcrcVTbC ^AUO㥴X X~r Ja2  rA<|l0(YBo9¯ ݑ<1(9;~1q$:1sp%L(ǀr@|?v }o[_;Uv0V H22Nr[8NA 3'ʆj8J2rFI>8dpp rN0rJp힊#?R=okHbVBpA<APl%I.poD2ą8h%)9?9H}cA9ۓT0#}r2U U f9G r՛З䑄\#t0~9m<p01$y6{_n=[aX< TsSIwl?㦥hU*ǃgL(ڲ;[q y:(v>F@$Y0}A$[b 1>8>:m3B&-m Pd >>2|Mh,]Tn'<|}|q &!T+ R||~ovӤ2 \>y=qG2g2S 9$r8#zCU u$v %8s3c 9N0#UnW #Iz6Y%}(PQ+ǻ9Yfe# Tx8x`ۍNIӕ>p F|># )“~M$#cFO'/"nm>TFqzpb"8ʓ*#z0`؜ȎC&wdH##z8,1UJcsgn2% g$=A8= ٘~ T/>@G#8s@RMs|xl'' 2)`d. n< HȡuXUCR~<0ī& `Oq뭱4@PX1aJg$ `cDJ#G– 0`G' _hkGhצKjCUSrӀcdFUKd$%,yQA& '`/sUf4XJ 494,4Gohi6`Xze]}ݨ;zW6ՙIlFB.VtcG)P%14Iw98!l*TK)YcG1("3sؒB,uFY ՅU⻧׽Go}CLu[dВp$F`NC]SnLԶQ*[dZRAxJvM4K\*eC9x'ElwǬZ5-ETu2ҫF%e;}˴s]}/:bv2kU6ٮӥ=B"#!a819q3YI Ih*^mЗ#jhEkZj`H,AXwzEA>IߡgM504ƖOiRJebTġr[{>VŢ &zĖ]k|QJ%1Uđ`pwCF}Z+)/ZWʸUU5.)eX ͙3k4p̱-UI!b <"E [Y vSjsEC|r/Mymsjjcj톢&<$˭ow\dmen}~;cݢGv0jSuDMVEQStz q#31`)̝|obVۍ4w"+.WU$*]K$ԔBQ4H E=Pz':;欳Dw%xC5[=$I:-6[R+!D^xr3?ieOpgoqzQvۧJPOlU\^]+ܯ^'I{oR+cL 6e3͜$r3(G*o#KxbF;C!&2\`HP*l@"5%]j,,t5aJMi說Y(7/(fG ךԦWY*IR{5ﲲ|zU0K$;TS#i * bi$\)P@(S[7d2 TpTYFN_IIʽeӉa 3Ǵ00qz2ZT UX 2.ݍ \{ 9]zD֧ DG0R0bO{KQ%e\7SrLQE['ӕ`IDoDz1YcBqddʮn TIݏzL,ȃIP(-O !<)Q}˕p:Qa+cD ,6=2GϜcuմ4Q4QV^-*%VHRGLj3Wˑ`_?J%L񐬪Il@z#-2γƻ܃ɓyܜ:x ۍFokڥ3؂j-%-R&UziWpd)dI z׆95(bxPHYN3 |19tZU,Ē:5]Tq'SHI&hsra q$,`(be|t RڈΛt H&{6@MTL땗#h$B y'㞐5eIV8QDZr,wxA#EAhR)"9(@F[diV1y\($| SS 8<#|cͰ!iSphC0m9#bʸGH3A~yxt{m0 ĉTm+$f$bIu-# gq!q8a7eM 2 Ð_Av''$< ,pۛ`.pq<祽U6hNZmOK@ p0)xIΝEBC%r_  ˌqѓb3 1 $c$y'y>(*WKl/$g~?<4o@s/EdK(ڨ3a|\ςz⢞,, M U $Ʀ(m"R2,8-3H?"2oaĀ U^s1N$n6Y _z_> )TǼ8܄<,G҉Øʢ<8{Ty?ޕ%boy*)Gy (>!HBcAҎGc\`\aA} 7 nf9bRJH pFH8#~r-{T`񐬄H!hCTΛ +1?Qly;,m d|Ϝ9ҎIڶnG@0_qV_n,JL4q#DZUR{Y A*Y]^8ed$sF ȼH  A<7z+d=5u$9v< xɱ R=A{| )KIX=33Yo.ʕ4e+UJŸ@qUU^nt;}/Q_q Ĭܾ;c@ĭBSA@n'qZ񽟯n9XTBn6q gEp Noh>H rLڪSie6^ zek,gj%IcdRSEɪ4LzJ!Jh[|ۮu &U B@xHXr$htd9imM^dE}8)ž.ƺӧikbT,+ 0Q#Tq X =}oDZI/Q|qL:j5Mib#H[4N[,[gZ\ivP;ԷE`}U (i"Ams]jk6?HXki.R]aYvS¢THAN#X[܅و3x#2y"n]farF'#DX)tnBugЍ`yH Fb[+.,Xٌ67 tDi+ 3Y*fv , '5 X_%P~[,j+5hy#e9gy'3HHuAEOڦzxt) QϾ4]ĉH#?[cXPQ@gr(Q$$q( zҁv$P2,I.ŜUܛ$ +mvնK}ڊ(^dj9G]IR8Vs*dc !RU"yKw]YnUҖz䭷P,=*zUwo#3ioa]GQzC[3Lʛc%,TyjKc{=}9禺JZ+ 4aOI[V%Nq[2".Ђe\'h+epoB,9De_MY$F@l;-T .WV4U.t P_+Gi A=ƪ'bޘTZrg$Z,Tu2UTIMP#rT$&0Xwr`:SSvLQ֭NXvzMBU2 -;<3< 6 .Z /m2 CoQ&4UZ)vn P ۖQk0)\,vX@8R)Zi5FK*µ:܎@5U<e{]˺P"h$M?gm]/{D.ly +ͮse((i꡹_ou0 TΔ h,Y RPs6/n*պjiҬ7xcD;+p3v zj=mZ:}GoۋS-ȮXӎ-F9%xx@%^\ y /VӪ% LO@* O.)(W27` Le6oj=I{MKTtO];ZUS=kC$f2% [8@LW65_ݿcP Y&ic+JXH$:ZZOIRu+k7z JdPެIQ&ިY $ A<%|Zlkr9<@9%D0|K%wH;yt$qk8CNya%g0CLŒtJTΛ]`oviAuM_~h=(l*fEn9iAhպP_:JCPY㥚;"57^7nuLDwmIʲi*5PuLA-k vV;+F]}lZ駯:k^j& Mv_O>GOe#3neϦ{12_Pg%pJa'8a#E˘cB sibWM ͭͦ\_mZ{=scFV\+ćm" "Nw)]=hnx-: {"KUVI%Zz @vu[QG5Gp+]ETK[=7^VZ¤A8{cjv=1'Md1KIjԓ3(Dܞ4T[o51YKsw),x""|<\՝ "*^T(E#BʷDZyZ9f1@m@6Tl;k,UT*XҴT{imt)O49>P?aʛ[ꑩOgDPH*.fsL1b0z=iӝzQMO[G %u¨j8$ +$v4cJw *RZƑYQY=J1"zr59>S%\ܱJ6h3͔7AQ0U5 PDpbnwgRAbۤ*K:;wT4q?RS&C ;MTTŶ0pu2F 璬뼂9p<~uGw`׆k[kphhWV ЉBGPi\OiS>QbG2`#@d ~פrO3K$De:jj{AoRj,:p%YВ  6z:[Yި0hizX^;m B$LT*"B86tʍ*ZeY6%;;)_kS[ce4 IWhEmh_ eQ%8dkO':x,Y̋șfY%ffN t#F_1 \ixѶuTŢU@$)Qtk"c="H$̜Hl|bf \\!F r?1w$HET9U]lW_icp-Yw>3wn!0dF Έ+S3E*XU,v P,IPrjù#qdS<2F۾RSIHT6[I-N1H YxQx8<0z_5um1,7*)kZIQ$k.}Eeg2'{a"0Y 8#vBREvVɍ-1DQ MmI AURv$zkI1Z4IT4MUS1ܨ'r)nǂ1KdMB'$ e<;~N=%8 A8K󏐭D_*Tߐ '>z[7-AߏҿGV7p8\rOr9_$ce@ʑ eoDNOp/op.X:Y  T@ @8,@Y";x8 0nڱds 7BDp#$~9GN '$Qss ÏE$޽~E ($'pT '۴XKTfWH^wIQfp 2|ZF$=823dǂ:ꝛP3:˓Q\' =$x:FWpAoڒF *1spX G>rRÔT,AFrBG;brPG/A>rx'Xx@egGTndOJ~@sç[ 5uD|l H :2Eb 㢪adiDr*;U2pdd'.$P$yNx8j$FdâT'hl {حێM_l-oY̸P9d`pߨ@GDRWǵ0G$,JC$oņ(%X y:X:Uq @U<Kd~:Cc tozTA#mx 8qpqqfV\.qD>s!X ڸ(ry?xx9C|H#Ub4pz;'r+#D]\ J8x'# ]6HP@r3 bJ2PO<Hϐ# S2K&bp ])n Ҵ2.]??'!9(dC8ۏ9#i vc*T9~;n0aed,q 1Rp81zӬ0!pGϷ $R\q0}g$rz>)In]z@qs"3 >1>2OKbTp A# r0p:L}G6SX:2DžR >2# < % 8H\ #?ۮ)) g`ȣaBĀr3)࣓-KC(G 1rr} >KX̱8 vFr ghjc6j&Fގi1*du,3;|_$zYTU%ޙ,a /Ogx0_ܕ,20HC3 %v*d&Fe>b~85bg3Z$˘ɠ~/f&i@,G hM)HJ~ *%E ou[r){-U_-g:^FH)U4 w"ԝwt)#z&mt6*kYGEsz3Imǽ96,QC,ʐEEM=\)Pc+. ᗃO Uvh{M]r(ޚhq1B*7/Ր&G+zs fG(C2.e噵,{3<PP!B o)kds¬h@T%ybRBUe.[p' (#ާvqإZE5=|Oٸ'm0TS5d(3#V'`$9&-MPCVѐ mrH;p 2p2zI,]Yb1(SE%ji+agޕT㘤0WQh(6"6AzEa˰m}pk1!E@KAbUDe_{A.AN8kJAӂze+T{Nq~ZN<@K.dVh]';tN4;sduQBJ@q黎w/;v&L4; 1-q [n pv}I6 RTtgRHb ʘX6V;2 ؍ϱn* A'm_bV5uW-IWUCWz *7]8cN梊3r}3}6Itz]nV%SsZ %lRj2sLMMeViMumJwO^PE-L4Q%(e2s w/}iү|4p7yd*.TUǸ8N0soWmyM4 ΢LJ+57DZDP%i҂RRx7HW%tBnƕlJpeXsL`c{$c}_Snm;i=;حe_Yn?vx#g8"rH=gZeCԒE8)`N@sZz SMq\)STzⅲ`Yզ V=Rs =w gҠ'vXN(0@Y&߹5JH{%݉=@<Ǔnx\R!CdUS0R%Uqw'R\irTy ?sR]88oˊ}؉Kӣz4iNN2#lfp?<]ME\9A+8% $gSʈ$9#wP)'cHh*"R'^6@r7~a݁zp>nl6=7]l6Wc]>KK}hȑX*` q?=Մ) A$FF1*n8)oącyN9G^&H$F@ ;5_[+۞=6?ok}aIgi&܇- Vx\mR==Vt2lֺV\ҧVl=kd"j@"ˆ_v.ZimrT2N؀op]O9YHi?ܥ"VXnqr}Ш,I*\ *M*rĭT:OJBzpI:TX>Xct4zӸV^[lah^&!9dV?S:|*'/Sj.&C}>9n6RiO&PF hn{Sunk˵FOO+5†#Z--D*.\votvH:kZutUa3 ƒei}5Mx qʲn<2 P`H_ zBIu6&וcAKMC+ őǘ nJaZ6q e'EWnԖ6 ۺ;E -HSI5M IOTW%( NOoIi*X&Yelh9f.1T–uW۫)`]#UQT c}pʥONiF)ib*M7PWP-VtثavmXdNzttb{~ZnU_qhOQ3T ^@F0]B Z˵UY{ a  QjO^RIEX]5|I V+uCүH=]sTTG1 Q= JPi +36%Y';36$(,M**`kl;,u>K}LwJ[`x-ޖijgGvXNP U#lފdVeL A,FvA2|pRԧ,FumQ>\QK,J䓌9s`C˧Ȏ.hG wg'v0qUN$Uu*z|#8Ҥ$0T2Rs $F}nVy䆲}-UqhU>dqMIT D3u$OL~|qtUq]_?9%Mʎ0c“~( DGH,AT3>sF}DCd{NW#\#)/bHF%3W p/r 1]7F![g< +}ۋn#8'tU,hcӜH7nj8y:r)3 wyO?T*ѷ9;GpNqуbY P#PhʆŸ# #VQ{HܑGT $>#! 8<`cDѠ/݇S F2'Wcd##<)6g""m 8 *3xQ񢑴I0{A0cc*I0V ),8"FdCͣU0<ĥLaAF,; c's2Wi*Nkcpx?:vz*xU$ N@8ϟ|s'ٖns$|*y9_ I^h9'n jed"]'23yK\,HBH\1Nrxt ,Z'Y Fp#'# F쒠H] {~JFOf%WoXPHc1#Uacx8ˆ0Jb}ł8݌|czfQPe*3Ry|<:PlQڇ#=]~NZ pUZVg˹h~ÌL[q~A篵FIT@FBs~:O%lDH1+00r` =`}+_a>;4I$c( I!|uԚϧp5ijJY'w7 j 9$᷾BSisȑeP%4])75$2ʊωP5m=!)z#8h֜(/]Nj ehrk9r!uBC_.Y_RCMA:$z(zI|I2G2Z##lRE=}ֺ;Nr5ʺf `kI ( .^Pjg2Zm6ʱI9 v곹[;-d i){ߍoe1BzJx~!@Q$V|/w_e:jPǦEELZަut*j!u2,bu!eZ=Kb?mo.Қ(}Or\*2 S $4F{13O#bRimItD }YJeG UL[Ō[Nz'-kŭ)Fj3ByyrTSIh-2c2.2lԱe223cRQ*MkIm:D 03\u{&_ ʈcs=!%͸ВZ4eYŲ7X3 sr" zKSkN(_#ST[5gm۝W,J"##E0#-JE$A&pz;ue$4TUFm0ӈ"Xlnr0t}h"s=<Mb7,2̀ Dp5n7dw7#4K. "DI%IP܂y$^faԡQFfs"$rYd(bxM$J A$8-C*8 xLՇwRCLqN",͋FҴi![tww#f$Y]"(0,HZ $:t\zQ@#6"c'pk:^ KUERȖU@ȨqS#)q `(w9l Y>|J$qTj芇j+aLZ3F<;;lӓ@P5F]k4Zg'#qՔV[R5Tq ݶ*@^$x H &$rv]t6}3֦c[tVHޕoFCe@-LYҫ+h=ĐG8l ˓oKV'2M@%xv$G:V}Zb j} Py H}**԰ ͻ0SEEt RڎGpєA[5W]$Q BƌMjSCn6{o{FWS=;QHKLl8!gh $*Q_Z-3W/VCWmI B7މ\r8A|kMS_nԶgďXG8PcG+egU?2lEelу-] nR+_&%es w2gpIZijֺ?(RvT4j7X]CqV*w ʌCgh]+E;mm-N6$Ik(~ު' 3#r{e\lĪMJ*)PE O%)@޾1">U]AWU[Mrҗӵ'<4,r!.cpSz! 'hY(,!u35YeMKS%i`cͦu. ڊTH@'`z^Y軞(޵^t 5zx]L "RgHILʜE/F JM"UwH GE\ RIv eHն=LQS3P6֨*Z8c``OglA}MM+pe֖}S%VhfWe\k^ 3[rq&Y2G. !6Qi[yC3!˘\R+QJeF];{5F[dK|^WY/3%HBj"WX\e ,_3,k]36-$Gi (X'}yrWQVA$l$Qi QjBϽְvygOKSxJO!HYrAP,)ܠk{ol7ɮ3-=kAD>i92=S%;P3,hrdFo;ulԐ[kVMEzŽYQ SȥDܢ@F꽴v.۫4d\Nzdyf/.GErT=_'<'²Yi(*_hݖId\NĠE婫3es3SGP$@ a$aV-/QӺmZf\.떵ܭKQtcZjf;EA%=IO>{kݯQ;zj \gPWJ PR2wOIZQwRǯMQ3*-r.deku4}Jv7UY^OVGE5 J9 -{mҵOaQiȚZhe-[=jDEc +öFr% f ,GXȬ?3fgMý9&^g˾-EFGå䴪@:ǣˍ Wq[dLNd#Ch <44olv?rv|r?p}c,C1N;Qi/~\GuU556qU IXnҤ ]ٸ,ׁo{u ud!3㭏񌌾y$8\e.aFRJ@\ V`p}$uj68};Xj墶C3R` DL($@J%#hΡXo$P6JB9ڼxP6I>޹{}o:zF&uwGaQ$'"`p2:'ܓL~>A=Y_ tIGR=#Sng` )ZIR fҔ,sZE$q<)]yBl2Z~9 jR%<Pu+[,}E= Tgq$iw*R fP]5$_LO KTzԖiIB-q[n7K35=GUIAOO^#CXGvY9|:ОQg0h!DD\[L`ċ'I42Wi9+(aZ:m4G"Njhk䨵4󒆘dy6HyYANI V4Ұ9E2>y9MhUK_OM OIt` (GGj{IM#QE2 HÝ x6Ь0y!wsA[NY;Uml(%@$3@ذdMJ\NݹPI d.l>:JwJ\{U亅! 9?8hx7+pXLy N6Fr[8l`vzSD]Pdȸ8*qdjTQvӌ18RH۞9C@o[׽ۧ*$O=#s76;s ~I_;] 6!3rcIP$e@Jĕ ~Isr3҅&G@ž>3Np@c ⽽v&H&*d8zQϪdbPX#,$'=4VDѻ)e* $ U '$g秨TU e9c1'??FzJPC@b0[@rau]0 ~}}[D V*r?|+ ztJ)es3dca, ~Ǟ8cE2DWݹe q< Sòq ynO[9J"(2? үqGˌ.qWS+c9Os|$me9p aI <ăWy2|tM{Aߧ~K-:i#H ::XaW s玸hvڥI^@ l '䧐\;d1q3pM*I&2 l b@2 w')dܒ`,܁Ƿr@?bX%W NIvp gF$}P3 /g,`[uB ,l1G+$ƥǕc RA0*b Ķ܉ R1Ǝ(R@'$8t`S$\!ms>2$D_A cc>xcD@$̅rh;8?q4fOOp` 9U2I$FN@ 8նQg$dnx~s82v1Prx@`F|yW(T,NdH\,Q4m+G#%2F 0@L6V9Q`O9[I#S)J{t;ry{GRt?ncYot쀴I8@ٵDgj5p5VwʺiYUTdϑ- RӴiWWJdJG+쑗 %lb,TTRPTSSFDqA9Ymzk@r32xP@Vv崈I%Y$\qor4t˝5Tq5 -bץT#̣vRά(VEw''hWXiF)41 $h(P1duDB1+lyR~rG"RUPǎ9d'GVb(1( #; NŏRq; vQ4GoH  q㎄[ U ʬA B19->zpn؍8#>6109a%,UҞ*^BL3 $ԖHGvpD ־k_-$K]Q&FβKK$2)$giBXNkKOCbAKTjp1g,EwrH[WWCeU=+$̠W"(i) 8$%4,K` 9z}Jݎ@{{n~u]%c( BY g!x8<38 B4!س3EEH$`<1$ u˓z[1=F.ܠ:( @ǃ RCKIr6BB,Ns瀁Q~߮ =,q,qꍲr03k[IHӰhTL}2O'(1!]8tdSE0ِ X)'s3qyeg^V;ƛҖFzA-(iWlEBKQ-HVX@ I4gzTKv$E7~aꤐ4{+|4wڛ[\-:jmYv@iQMKJŦXqKjZU{1MT/#TKN UWGe\]ѱWM`ҖԹWk*nq_qxh@8=)P]}>iȴ՚fߪmh4RUIG&U=fdȹp+,Rhxo];E(ɢcd5SpFD 􍫩,qzjlw. PlE[^֋M0I#>fi @@ ! KpIkOSCp6_U(EEZ|grH10%7)7ϣ~ͣJWZ[wDc I},JcyU\th;C+->ѕ!)nVUMxcMMN أ;TU\ pzgoj_D4P: ը1"{~1axtvxGLKܘriVj@q´S5g Sf)I'ni>wbS_PU_mi i13Z1Cxgvv֦ =)beV $4+cWcbGzP&Q5\#z2aDUݎ+S'6-;"-GO-Vвڮvg=[ED_j!"|N`: ,B2>Y/Vs[Kui'rt-9\H4 HjBT NjkEdik})h;idIò~=Ulz+uDu)pkvG9 cVV8 n.Z]Ojzج eTѬWjgIYRƑo 7'B*V8gBT)'**79 x_GK$ O0];-g~u@X8e] R?]HI W¶ q${ZT1VyXN<v3ު[e7Ku:X1ԘĔTV27+X=ѽНݣӐ+{Em[B MxKNRHE"b֋ NPY%[Pf,Ibw´h (#3Tv梯2ӫ454veQmA\$C=¦pBLA|d֪ʍ3Xu0@HcvBbT0># FS,6(fY6DS*4*ƀ*d`8RH!@DIt q!9Y`X7@=$oD%EKWHw6F~QG$xWqwhZUB*&qh>FED0|c# |~еv1P$y$ :x *<7~pY_ίB)i=%^zJ2[bii=jRIm@P %l)U \e^䁏0n/FJ$^KzӒeTZh RS:-& mwT&[?ܩI!0Րd ,)@n _DX;; `+5nWnkd3Dx1aBI) 0bI=q*E"AXUy8'$3"V#jɒバ 8sxi*̰őEaNrx d[(wPm yN|N2sKJ }"xF2 GI閨' vr<8j#;g<NF0Ag%%ƕ{a]c/vm3'z&ߵv@c?#$#9#'#kKj~K)'9,HSx$sjj&0ۓ>$ q}2{S )$<+s81麆XQˇڪswr?ף-\7`dx-yNy]ʙI>@h+R?#<ߟF6B7rG#3Gb,8c̬HI8z[]tϦUTUVMYoRԬ*HQ:Bdlp%MI!I, Qn!G3HU[X(8ߗr*K $&;.7InzzI;4dkj%JC,SWF0"1"1=ZԽT^uzkmz=EdӤjkAoYʈ"IYw+gX"Fe}vS (E&4TP3wpY{_nt%=UTC<ə 刂(FMKȑ %e~ l k/̰d73Y`1GY5T[Qj'75F+#R$HͰU[HԙWo"}Ƨ}ɢ4 I)oHEʩ$@ik䒪Geib;8P0yz]]ݩY+5]-%dsZΰ2ps"9؂ B 8`S2|wX >O1Z> Iǝ1u zu*"D@hlLGhbkH$33SPJ6 B Hs `Bw p=ELiY[kzk+af467#h%),O8zH8'V6RGskNMe;W>Um4KU4Okt4T9C9&_y20"iո9lGp vDG${leJG>dUU GZ\-*{%NI6^n4Zgb3Ĥݩ49GZʁkxehđn9c#pd<ʐAN:4]ڭ⦎]O%F R5Nc,^3.H;uE;ՓoӵZkmdZ,dZZԤ;|=PIY)f#+IJv(%iY+L剗Ϩ$ z׋$KXJ.2 #9$#i*hȐ.Xp$T>0NQvP6cl><|ssLϼK zD(e!s zmG]bswG߸8R7#+nxs'<_SVXQt7xI5 Q]A$m9U%e` 8@*csXx'@ O8ddd~GC+2ҳ) * $tmu-QVdW j(9%Q'?S's:$ga˚|D>g@s3)`ec?Ѳg12* ):n9UsUfDY+Qbibaj5U=檆$QO$L WC~ {ޛZכEAu2z"ztR(Hi̺TYi'lnxi䒩饓`["Ԁ W*XGY#ZĵGC(d5+Y[=Hh7k@r{Wif2 122Hd9sȌRI},#"YL;t%upHڎw T@"&ӳh=ZAyd=sOCgIGU7yFꈅ,ƒ ݐ;bMktrd̵j'E0C UಜmAi8Y Uc. !G9?#; "{jAhhˤ"8*A(~qliaz$֖Q7a؅5 !P$Qą BEQlוMC ˃H y. 9$J 9!Gsk HX'-fI=Z aI<Y߻h1#me*XmBB9(U@ z& R# i3nK`Nx'8>z1IU%ǐ>8$j MadY]bs N9lgS|t\,"G)9#>8n~322y8`UE4RH/v3C|p#lrh(Wsܜ)_ΰSeQK9)G!?AS(hHdw6+p$AH~A$~?e+RРsπ?P]"*AsN3|#۸r[1q$Gg+#yf*Āp㓟9yލ D/<}Yܮ̫\`x#g>qt))L#jcX>F:iU6Wyq `I8@@!C<AxEnxzl0sv?q >, +Ԓp1~ WSn}m4,G䭞EpHcGN>kx9RYx;w`ye$E^p{%'(5;`,$r#  ~N]}pi6Fh\O 8P K18~$c'od4j~ xdsA<D03XjRqIx"d}Iq8 p܌tY#~780Zx$ L98%HA°֑2FMN}pL˴6@%G 2C#&o3 J7+ U|q'9zCBrK8Ä%|- $}|u@ޠV'v >zC"28#ҙ*cп *3/98|qF }3K,oUy$*9-x9LkU_u lVWQL(Cm3THDPF F25wrvM/nz[\fkLAC:Ɗ"Zx3ނE^Pv+;wuԟrgZ"QDU<$L!*G;I$xPH C/W+i!Dx+]*H>#PqԚ.iYjr*>kMgImo!hˇrрZ vkjYq[w^'^udSjӑ$y)yf Z4J*h ZzJ("6%2~h I eBvC(.7( ;0I>q:iRHUGIUޛ]7,T&w0rF1bȻ!ɿq~(Unz5ä|Fa%Ub}9FqԎ45IK3M،.$TvR0ώR1'Ҭ>TP\h, F>G Im BѐN#cݐܕ{t?ҼK ް`gd&PrpS;r2>ݸ<2;r$N&ޤQ̑[zpJcq^8=DeG}>#|9UPB6b2#G+㦐:On{}{wްHkN⬊2zj4r4[ryS tWIĊ[ln$`; 3kR\A1 Hq$ѶLfBl !2J 7cR,/COWBn9JEEG$UqQQQA5EtG$-;Oms6ujz]-.:^g1y %kOl}ʦYCg_n*MK˼ +m/[=T^T6yXza1$.THεvКzϫ+S;m+Q|Է*׎i$Kd+R/jl$uV@Kfxfw nI=V ˑ6beC]T'tJuH^P^ g= ЛjzE-!ށ^+PZjꣵܭOMl?,MALpG[Ny=SKFR[URMA_h \m[munb(-J9pN<]IP'sU=ʼn*1|uӏv4 mOmm#IvCk_aRTU.V њXџTX[^/l,%N]ʲӅfR\( )]62H@ "ؓ؁G{:Ik%owMU(U+u?WcGT,.K4* WOMuH%eaiOK"uxQY Va6zOGJ*8n rh(֢FE4qFFF2,l=/}Gv#Yo7b,rE뗎dbҖWUu \߀4<>AtsDPѰ`HըÞ : vPNG4n5XU]ZdTUd0䆚*Z8㉉i;Fб9 }`^M=EKe4K$dDz»M)}Ԗ #%kMAw RBJ7#MS;H%2nsv6,] vc[^S$J֥I5~0cs9|#!G0@f!Kj]Dbu77MBihu󍥪./mj:iV)"RlWhp!2B PNG͒PQEo+%Hf$m^ӆr[nFuϨ*[T1ERVVdIG>HKKw܋mnݨjL-_KQkZR42YDqvYT׋+3 NZ bCPB@b{M H:v&lFHX6k$noӑثIKMe4U}5BˆmRJ58$g+N>V^4֩{Q۪I=})QL4,ܟB*hn(HZwJVRQ$R[-RIO!}}K 9ti[ :u2M#mdNHL)3) Fd#6FQ:5bi}&wt(jU\sgV@<@麮CLYX5F6} ?P9jȦJP߹IUHsg|tU0.B C?9 Gbh7IJnEbn,*9RO\ZFUYgr2Gg'.)^(2*c$`񞖯`8`$qtOD5QG(i`̬P`| CK}ϡt+cYJGGYdG5KI=9ZD7I;M4ԩ)kHV8]y#¦)/KR"Aq9 w[9 rzu m=wß'koQIm FG2e(A$eYC2| SEB,$[o20x!q$M=JK= NX( bl`1]md±{ 80ݒ_g$($w_x9+| ɒB 1\c Otp,Я 24,2N21۫^I׀H6aT?&AYyHֱ0"DhI 8 #9R("+_ ?vơLP2%!<3l(*?~r2q3=: B}IP39Zbvpr@@#'<10b#+O8 7NI]DؠO$II#(Y0@[Vw|1 8]3UȥB00s' pA? yO r8gzH^< JG9' >ݕ%ۅ8>Am<N 8U(#9` 92ǟ蔑fYc#@q)}A G;)K '-j)Z d^bt2GmHa0pI8:yG16LlO眿*P24L8PZÀFòkSְ٨4՛X.z^G E9 /hT7Xim23$TPK , $oD$@3g/Xd˘F9Y!o4d4e$U9XVB(\"ca棩_TzYIVP-EGunQ)apDUe$5Cbၘ wzWL]T IXJ! +,k]iTp) ut~Һo:^Z9#X$`rTqlA>C:eMxH:'ZagQqwk*bWhE<ê+X1yMMdvA1''#c$MM  i<$b`(bPRrFF'.h`wykoq?g~8 UB8%r6wxE"A5ƴ #[\ 8=52v%ʕ㑜[o =5VK5 TxdFT}/e姺W^mv_Okz[mC*-eYaKZ9!ڒ zoZ 32c\$ BlE5P 02餓7ddTb6Qfz$!mDkƸJh%DEyNTJY -4PԲG]K.$@9RӺQSätNڧok * DYfE_ ű\wm\6nO?[vRZJg3ԨYxM&B(K;bש笽h(])Xջ3 Wo;Wl)V[)krbSSVv "1}@Ŕu5mObK6ܪh,6+j۪4RzuMQ&ɪ4TI"ڀɢٜQA2T3/NTa0vHQ K¨B+#3Ä`C![SQ `8=7c}NzcPT q4QAdةBHwmt5٧6!ܮW7Y (=Z(Y N($gbh>Ǡs%mQVԛCMEMHgDѱA%uZ\vkPP%LFWo0TH Nexϓh'!b2ܴ*CiΣ()1,ɇ㠆XL_*/0( Cw@4d*7=#N  GF]Ho쮘Wcc@~%AbئE$eY$T 8DJ&C2H? yfʂ9=Ck U<Z/S$qƵGօҰ$'29Ln.}hћuV4g!h,(|HquVc yӷivLPi`Teɒ#Q=&nyͷWh;k(gvqDj[KWHʵ.C9l*GC^#Ma*˲Dh%WOkerpdNRu:&*k!qYRҺ֭ʥ*Gd,2:3^2#˚ 7{S)2JAU{tmZ LXQibF  *Z*꘭<e$9d*Y6,/\EWdPT黕%qI'ASDzb}uxTkmxZhښkZnUR膦mᣮY)%G'=6`i{Itz!QvYI55K5nOeRRo%:ӷ ʬ_ɼs6c3(ٹH'yb6 #ɤ ץƚy^SyC*l,`U9L[KwKfTΕK3ۣy%LlƲn q6Y{ƒe4o}$b Xy(I- QU,BX*U2$}D,S;$y=<Z(նT, Dz{,00__.-҆I,Rj*TVwCI!66հv @60~R+ 4MjU#d PYq'ځ('+8q18ɋX`yuu򊚅!Kcؒ2E8eC0M,s34e[2 AqǛ)HA;֐TiQ&Z@a UкnzonZl;!IdWwꅀbX ,#[G=LuR?HPvN~1u{dSK9VFUYǞIQ98$,c{Q$]=%TbIcZ\P3Djm`9p孧.5IR?D13.RcI+ U>/lzM獪*9Dd}誀n;w pm*T,mH@݂Iǟi019=S'tܴTkߺ/PӔ\AVPe>7-Е;Ⴈ*yH; c'9òsq,iX^ȧ%O<OPUHߥ_U{70 @XdR}G9#rVR*n?;@qOJ"pXNr Fc34d$Tv#T d <j{^{@ln('Gi b]2Ϊ ~3蓬Z$i+!him fy'󌑎󑞤/e+M$ <뎢iˤEub~1Nۍm| :. <6AQq|y { %}b'A# 9m/TڞgE$nČw`)x碶ovߥ{qo-{}%Z _8*<<n9tէci2iqPl3?D,IRVUۊ  FH2OK,1ݍ`2S 3szJQ7N@4/oy‚{Ƞ>W:t5]ܰ >#s k4r.`%C kǜ|r617 dcFxh0 hF0rHUs98.z~=tt=?c(".QS+9sC`yr?ae\;u#g# ۞j"C$v#gh,\rU, rݡe˽<v&\ 60>9>{Qؓڋk=HCEGy%'yۀ>1*=bDsU m`PKn%q9-.։Ep6cztVY؍#Yr@p8v+IYBHGAmWl%F 'ߤLdŲ/R'V2zA y fvK,Fs?8#x0SQ477IDP9XѤFtQ8v<Q!x­ ,BNH㣙d) ;p69< R)U#sYۑ>ьfzaDM#[0`27m+ .dz2N^FV>Os)IC s2}$7Fؘw m>+~X1BO# I\ c? ^"BUm`ƫAܒu԰D6mQ 9$`IEc$ U˓ gs䞓TӔCtޓ{)AU@999IZpvpDa gB nOSA͛IW(p l 3 )4tJZX96J':0bz }=v:ƷX^n %٬ͺ=,R z1g8!H+ W8ay_%cEv`@ 瓜t[]4 $r ;898WBS1,Yܻgff%;C(3b 6 P o7n5UYU4DhDI Zd`1xs :GKhu!6? `$tMlCa$xǁ"L&Pc/O  1 ihJk3%I ps yew' #Gx砶 %+Hg#9 t}1Hu@ q<`E|Tޔ!U,v#*<>I;Tٔe= <񞺪@b$d}0ad.TFœ; I8=& ZU,p`|r>:h"Q`'?>:=2;0,(<_v2|r9SQ*V5 +cd!Œ|?|adZbzޠr y>OPZe Rq$A:ᬶUFbGgJ t7+|,'5I k}1c8㎃j`OZg(u`< | *JV9T2Bd# )_%9=5Nd%c3< g MH| |) /d!ՆlFAOGO%:%cS)b:897 L(ٔG^U9lT`#glHA`")3\F*}ӎpak 54|6qsq &u4 +WqtnJOadl<$;}9#gUzŠ༃ڍA#$dl` |68Q=={W=2@ F=0HLCW] ʲH !r3@cuTV>x; W61ʚ_H*oP 7{2q3t7a vO8ENH|Y[ J9pKK^9cYLdP7de`H't"^JWjCj${Almq'v(`,%l0QI9$2,;_+ۋq3&bҒhмlJR`;Cc@#>s`-U}=GW\5MSZ@%Z--gCq[,lDSᨠ̬}8(D D*"۟L*WOX4B{Q/ Iv|$čmy01ExC1HC?dfLcq1#rCU[#vՑe+ LNSU%G[Bk߼ݷ}=w5GHhkn2+ Mjs1m_IOYszޞUu%MtϷ!X=)AO_!{=EPk<rjO,u]恒g2ȊNGʣϗLJi,,t4zX7ZE$.T)<@*K#cuX_MW`hlXu&ibZWJ!H`ZmMvϰ}6S@ 4~]U4}KA$wYF   M4\uøtZI%QVZ\*):Eì{]]ygpj 7_㖿J\k-( jf/aTvO^#r,G,sfd@CˠyaO펣.veTX˪! -uMvYeM*-`۪im5 (hϴ'$ǰٓjZ4-QEln:{x 81Q#ᵾhST5Du'S!(Uyjdy7E۳n2%4:_=lSY-J߸5 wCE ګB,Hgwk ],SOR}!̫2->QH9J$RhY$PpɈI_c,E|\՚*5_FEqU7aXY=,)b!"dz=٢IUӼOrTANXjV[i a%d0b][kRvӶtɴoRۅcKk+$Jjp-xy.$`g@  I,NbĖ;;#Fymv1%Pj2m!;T*p33Luu)eS̲C \8o>9pyu J%JX@`}ʒ@z.ƫC褧|_s*#*y3ΘI>+>ߧ㨨ScpN2$A<|kTU.&p&pߩH08>FMu)fJ*'dQK $7%A OQj*i2[A*ꭗ8Y'@ͲHʜ3 |gQOTLtR%U[T4E,Nʹ>NI,ۘGVQ7:IQ`_B$feUbs6Wv~ `c؛ONN*- ڞ}ejgw +-T]c,UkOiM+0 Sߴu9Ic^*/rWKuuO5PTz4U 55LDvG;[VY3O[&%* %Mk*I] gMc2mx$8#?"ơ0z5Λ߶S[JbeY`p<y!J$P `+l/&';R;hH mrIZJaX`#|de[*G;'PM,+2rUx !mXrA? \pSb QfuWW>veۏo KwhI1U|6838IYo y6IVaI;+Rs%9όj!;ԩbE!Bx,#![9ފ(v 0Ib?Wc? 2]Q`vnXNr0Fq8E%JY^j2 + d1 WGs䓏<:IK3 "PȭN??m_ch@$F9 F qZD7zyXHx~__0+) P(#0%?9맂 ZʱuT9R@%@9ylzӰp2vÂ<~ãnS,aEeoN#>T@P11#U(ڂ8ʌ HI3%&FWg@IpJHPI$yW1uevb9Rg%q?lKru^]xl,UVwnPSnY;hl)'wMΰ BS[k'je7JSl$CTԅ :uHtZ]#~k(RE[8$ĿVRɧn-һJc?PzEKFRXp |tnS@i zS-W|C%K5cgLTUƩ4Zzu4oFk= UfHjY꫙F&0"eo_"՗U5kSZGO).4Œ&hBV% P6QKPʼnfk4To6M.Wd*nIӵ\ۢ6랺ϨM{ݧd7GJiD vJ.bSh~Zt*xgcQSwHS|efK46Jmybץ7Tjb$f%YK#n ,}: E=뤮U5 ˶_,kW{g*%R*ǟxKTh)"C2:O-3Te d%" 7ЦْmZ(D dd֜kK͖GEQGMq-rUngpQXȎm`ncfJ+V AGjm/`:Zhd mGb?VO5C1NB$8ɪs]rGqO"I$CG*Fum$%@5 $*IRVNO*hTGcӝn  7HB'_<`t\ՌKQECnJRRA)JefH2BUP㨽A-AENqVVO*E 3(?iU 勏MQ h[pm=nh:tzlRH5idlSICzbf/3Y) \ME:(TQ3I Rh[ c$H|=5fIdMY]K+!Ihf @qv: T')̒Fwр|a<e[,hi)iII@E9rlF=PB˵; `ijkGY֖g{u (PQՑ^6+"zXYK`VtzLWJU)#*$kuȓ7}H|i@1%Gld1:@Ȅ٪4Ů[J *5 DodU6h{]M+:n5U7DO$*BDw(ݍ9PYj]dtXe'JiqQG;ƦaKQ]U\q>@E(v p1Y>qz"jᒯa"؏j)'~OR]lD1F(-FӐFHv6S;BY#d|rmb*KyŤ̜:E&x:yJ+zB)vj%5u*ij#\hOPZ9xAQמ=ٮ]I8m(bkSV\c6XO MW9jHUH퀣,UKpշTh*k,H-43)i@e2 'k [wWVzvKl*xxX*O,wFM9̌ us72rF}"і"݋K TĞ3Sͪ*Җ7VV5Kk}KsK+/*͉ U14%Tu I(&UYIM>eYL {QY_W-W(F%- t:zw!CK*C#z2c_7zhUCWGyԛϸ"ϥYdL7ird+0XN %H (Tl^A\kUdT43UUT ZHdnRY@]T.rh _Rz @VyᘳZΔ펝',4~J7$d,yR'Nh>I318-S6#ҩyP,qtf4/ *fqtwb (G 먇2dl,p^pfiه.抙vg4[NuEmp*?J@d֍!$x(I E7Sv\ g4TQmUdIWhJrcFJ;[\/كW%xd%PFQ9, 2hOe?;v51 mihZM4ѱvR<g-!,D5jDOɛ@<uaUZ(#Q`E @QN(~I8'Lfr4{ URʕ|DgTR#q3濚.b2y(E =DK]lsJD4I!5ͯSI\"pIboy%k*{n\][Rͨw\zR0f;2I]dҴxZޢjh`ITK vb@.@x95-/;-֑åR, LXG1T*v !9a$IMS20 #:TFˇ: GjVi47Tt:g|XPWҦZ pI8,P)e9f1nlh:lj ƀP]#Z KLpjISPԼocNSq*_TW=EC*j54R@5SDH@+/'Fbki^(yedVFӍDd*eF8CLZhB2vG:">Bg8ݖ#93ל@{gUDTYAp@{#@=Q^ ;5}AB dpdf >H8#BLM~v2vry$ƍ= w.T@rFr|c=䝸_M_~z ޷_^}ٺ7R)]i~W<3![a8IO8@ x+8Xc@xrtlw)VaI ޣ+*T>Ut`݇cgncǽ~*nyg(+EIv 9 s'8qѐ HyܬRa8$qέ oyUMՓ)%vGIJbGq!,XgwaAgzdH`HS_'l!C$$Nr%UVBB;bw˲bԓl.hgr\FQqc7Qp\ADmRN&!}`yCe u gMrN8 =OFI A"e `F3G;c ێw==W0 {]JR |` `6z/G@OrՍI[=bzm+Y!=86!`U\AREoϜ|[`Eej + 3 Uq6zY[s%22B"!z4|P.e@WcP=4-}{:VhLJiE%vHBn!`dv| 2G8Ϟ Li{89F1ԨPL9TdA;tbYqPLK#M{}N26wgI-[n%e+HA#%ov|n>09 u{V eeT!Fpxǻ :p;(bqpN930H0|~<-!A ~?bÏA6tRX`(pXp$ҥё;2G{lp89Q" (g$u6D)~3:n^eE(wxӂG\+;K*xvN#1JJ@U l ?)H%([8P$`O0r$r3 ; 9L0WMP "J( d%rW#pc gA0AɃ  q0۷:wg3.p^%PA\r2.2gg-0xϸŶX=pI9'ǎ4p<͜Xc1 #H*Lf}HczS36,#m#`XUoF.s`(201_S Y#rN? /Jt #~x!xzzdޅI$FXpIs Fba6"m0j?ik2NӰq_`ϴf0QEųbnM-(r>҉ 9d 9_$`FYOFH' ;XۦYYD}|H-'?S=1,Fyae`# ;\*G$TRy`iڤG+8=|80y:^{j*J̱xb=[Yi%aB 7 @TPy>8 kj;o~Ao.j+TޤW I#1UT*Hs{k#ԫp 'Shdg=({ * 5i}K}'*@$G>7{]T1:ON8$]comMUKfs嘕aH#t72DXgn[F?\ m,EWs:k)45kv ~ߡ8{cg۵P|F2.G'w`;!.hǢ56MW4=iFZ4!pCwIW_>\E+}M"CP4*A%pzethw__[mzYG5vXHZ9eº,c RAm!ett(k.̉& VE+ p]tM -ZQ ѓWqA4@JEP" fk;/ELTH*5'1ԒTdN9l`NoǴX=/jлASYV;S\"APԷ j F3L}ͭewEk]dvB#@fR28d.hdEq@YTc74pNΎIX[RQ! ˆj#HٮfK AA7rE _õvB#@j(xu$!}ǫFnkn4*HaZX0DBʎĂ_!DQpzBIOQ,2\foT,-9PHՁUXn}R%9WTHt 5ǤءB+y { ob잤oj%!AmW+ P,d!֮HgwPK.}O;!s I5\^-Kuihђe`*cR-&|0RhѝwjInkkQ>%ޖIjCM)< #@w黲ƢxX;[vYnJfjin4I S£P HK*SX͈2Z6P1f*P"HYXfIJ6 ZCj5JkmYwnh\(/6Xu -~UN~ꢎZ`[Vb='M5+*鴭QX'Y^ {ݧA J"2ɻ,B։{ܨtzp* j}פવTTkPC R:.(0;hV4u ţ]5<0ZQECjĴ KtbY3:Hi#2_+R$\+VG9)Y@b%v$X ɕV9 C5{Ua?3$ TVK,m6cq_o˾Ֆe mW kV_s])a21FQC{UTES26R'Xԑ*Y%ذ0AYW~(ku),sO ;!*"` rp$2@]'osH AVvn 5c BeqlsTp=!T/vTS99$x[cnvVL%4uU2 pt P(w>?#[yjidXeR\dpzRWH.hq;pOpdfYwz;:D$)$y؎kjzx|J J]}rJ.A8?'@ٔI3Vr8g\hu(Qʶq$9'$ 8֖㍡xÔ+E JNÒ~rncnQw&ThG1 ;)f`ʴT$ c$gWyS`1Jpq(\Ϲ#b@ WpH( `8Np8Qv`Vi0srĖ,Aڷn]6뇚M=>y?#иEw?Lywg>~#JZ:6))2?QB}(ϑP¨Rꌅ˝@-Yr1);\j7}o{1bHa#)e,-D7g`q7@XA+ Kdd3N:VY`*1Qp3pps5byYeu pC0d1y#`x p($y% o KI!g#^)#sIs%&"JV0})Hc1G%z`c0 p{k uMF H#@Zz6bqu5IUF2[1S+=&^e,Q$8S>x`t"oלn)؊A]+~H}ȱbP0PN9swf&Vގje`rp-W4-R&-PFprsӷVd2ՙ}V*vgvZZXd`0;A)ʐzyF6$V#w z'2 c8>Iу 搳G-z^'dsCA^>L*UfVܾ7 2R8U=I@ OzH1 PL2x'矞k_pz]#zhۏP` Ǝ ;T<+7+O#zk&hS@岣?*p3A\}w`repx8>|`k#JHU9cˌgzdz::(N77[32s:rըi 0 +dd*2[<48v|g$80*Jg&g B Ao*9,>bQpYX Nx㍩iџa6@VpN@|pO>Jj'E3*8 8\`HTfennAA qˤfs r9$`yay%P00p 98s Ѳ;('08 `e>R Tr~8òU@ 8,9*oK>NONrsjgTPH/#`p`&eeW8 qP~Gx33Ru,*H$'.[9C,,@+JI~NES"j",O*|qEuo^0 ǹ%^T+x‡9GZbfwۉr 8$=|(f&=$3><7>|Pn5["6yGmaSj㦻U-{ezԴK[Jq*HSr'L }UG#EYdR%]mw!$4LF#1 b`t;vg^ib(ijўny%XW#[c0R2nHY!xz,O3]G4B4-!Ҧ*hbAeYRFppt-)Һ2H&2`Ѳ'#jr QgL2ѝ611+Pnry@D֓8`] iK uT#,$ ,r0xTwo9.VnXd dds #YW97? X6y[d/p4uĮ :CSP4@ke`FzXj[]XH^j=:J ZKTN)Z:zұ8Wn]\3}뇝#%Fӊ'E͸H\<ޖ8WŮ{[k}Cp/Oy!zێ!處vf\*ǒr46Қ uj5D%=EuɁH,@ cL@|dO++ٟyԪ(.@P5ڍGMA1e!55  $.XhilYw;@w]o$^'nK-ά\&8mG*ѫl+-b?q!1 =J/ZFgHY)US4-A ;4@%0zQCϤ;Wz/Z)MkuhX:"kYҦaime>aSEl e^(!6h#PoH=h]+|VjlUeq7E-aLV%L//G6U29\G,he&:nBEK+ML0;YQ Rv5/laS%eLڗ>]Z in܀YH=|~ޟP-r\(ԚYꞒ% "PϸCɉ$S;[KP {]/i($e#A2I*u7acCvzr4qRN+H\b9`0z<3r'xnS,EfLWX- YfUY$dWAMlFH䍙ZS45F-#,~er%Ae8'|Qz [E\)V#5SMGIȱ0*s_c[P* MU WvMM[%$#Hh#,UYaxcp$ۖDpjp[l `H֪wlQ]l71C4D[uifVY=9 K0-6'qx4!ȩYy%"E'Dq9vY̠([*1,e+"l5i@YkZ 1li5uX b H\zvi0cc{'u~m5IឞHv.Iz ?. p/'d3VIm$5tTXiќ4pvz|fZa4F1=4L!],x(!\<9?~b*&a3 Y"YA+ `R@ lG=aY*i+*`Rk,_SiiƖX$$Y*`f9cyHIJez{EXѾ)jeK]B@b-z垊e+oZg#H[K{tzɠ!HfeFć,%U2 Ǵ3[(0є0Ie2SPJ ;kV!5Ds$(ӾQtY-4e%GށYB;p`Y,mgr(}!Q!)kI-<2Sf5S&@ CJ$FAXQIvجvR[Hi2O,JV1*2_C!PN PIB .K1A_B D8QC{P7 =޲;Ue³JZ%LثX &@Uow7JH a B<23eF:;Tf“BoXh݃,Q`"`I#qlS9vtZ=멦mU,(lUPI1V* @=sp !.{ʋTeeb +{13CfJyp@jjTv:T pH, Dk ƫ鬚u)hjG@CAFvۓ[=Xz۔bJU9U#`[vۤQ3ʀĄbulX |r,QIQ qߒ )9wQ 2A,ۖc-^|lki bF\BGx8蛭DЄ͐02<G>|ߨ -e*˗G sqiԷh.+’rsӸ"mn zXW}iVU#e-fNy sOٝe*Jn_q8? `z>VpIU$*src'!|%oBfEBD{K2?l<;x)$l;`uG8hc$rF7 cp? x) O*#J*>3' THѺ`*F7bόpFOY*_Kj]%!*RZx&1.# LYÇ1W\! y W1tfX#.Ȅ`lw\F&")vǽP9hrM39dF#HT6T:iqECMKRDp7+d@C-?c/%N=U Ǘ5bYŝH22rl-QpQ՗d,0x x.w/FL\U'@v, ",v /U62^ 2rK (zAd"\}44ѶE!JB300n'uPHjezat9=fR*53vQq#  3ϟMhu6]A4жw$# F O{5Ayq52#X\ %e n6ůš2j ]T&C{_Pm>3灜PGzz刔x7d9[*<%=,Ā d*Ic'qnA_4܈VE@~G޹v"KlݥJ#P$9R])]r# f|C1 ^i+Y//V*&iXYuSUJ8g^6z &j}Z)(6ťt[Ӗi3Is{~~q2'H%gh;1e>q?#0KP!I8 g8?)*6 ebϴ3<z/w^KqOI Wz. lC7}fI$6K '2gE(rff9>FIPFAA|0I9<1z,^mk][`+DK;%CJU[j9<Ė wɽJHe8 c9G]V%)x1HI FOd9BA[uj㤎aT:J*ZI;NW^\^aY#\ϙ#1gJZXuwU,l G:IjY/Fy8,I2^* iJ>E#pX[q{O]U]cҙUU5UEIPD,Q6 $eOWEۉQUo6ZjVT/;Չ,3V?I>"+溺Ӭ2X~aQ-Vyčf \zAb5]VQ߻>[m`j9M@nV5W'2$p'P1Ұ+c*I"B1 ~A 7x/>].ꢘ1514 )٣p!\[\)ڱ#YPTJ!$1ٹXFGEC CU 52Ϡ [ X©M0z @ Y,ʁm; c #GIWv%rTF2@~9d$j/ 0.pw㦑G)a.;HWw#63q:B zMfRrͅ箞#8, _,^ޓ/% ;`2|pFi`C%ބrp39$ot`¨)m1 A " nJ YbX!Xn 87HIV @qy1tI`(!>O=0RwS)%ro`BR2˱jvld|rxʺi)`:IAr'jI,1*'`)||JI4@#,N '#x,3[pR1R]O9坘~'Ow IDe>g'h$ <NMոY `w8 NG*<<9m+`X?銾Q!RGU; AgAy[#,fV.d xڷ5_0*&f'VhX W@܂򑑂ON4M,̂qs'v fӻ9&g2Hsy%9#qIMO2Ty r| Lo>  y۴rr0zK*[xPR+$.䐊7).Hn'k*3/ؐs®'98=1(DIhL~nc6bTgrp @=8U8cԻci$$dVb ц4sc4dRVA$mb ۞sZGa11ezdр|`3cIrzM zbaoXc >sz2kP6LSWb88B!nH,xvv |2g8 $ҁ$BN+<#~x $؎]b]3I,>&HSkN :z5^)e#t"McU~C'<UUښ1Q(°F1&ZzjkqjEDތTIn$8UD0$UJTT4UDMT -&I vzwf֝ȿ^xTꔶG_EE<bJoJC:m⑲u;5fͬnVjJndO5Z*t]4E,=)btit4~U-vK\5DSF:h**䨅ą VVϫ;i*idg5sQ< o8b&9 IJ8@tIL`J 3 u"yRUH5յ/md ;!NWU4/@+}'HV9$tV Qpd±E),%Rw*F\ǮݾNw'OX˦ڎzjdj0P<"@@wΏM5jӐO})#FXFvPKW,қCl[:GZ:O&p:CIk]ѼhQHݸ-Mvֶ2B7S`ǩGh ;e2hejA yUhK=ںGf롞_djDc`FϥWIjOIOYq*"=Q`^l};٧,9n:_Y%0$r($)#s j٪UT%u"TUK4Rt4Shhf3(pL,"㑊6) :lb!tݙv\ r*ck;m4zV[ -/7 տHQdjjVl;cO~]wNd߱2ϩ4ڲ;IR9 e=T gC3ijH^w%Vj44 \$ )hQTh56+k5k췚%U/ jjǧ=]HHU$H )Qrf2떏P "r≮2Xt1Rք)l(G2Ƃ+mMЄҰb QZWvQ9j5⭊-Z{57!k]" .5Iܣ+kѨRelRK4GDYJNQWf5o}Gu5hȴZc5iJ%ZE\N@AR qTaEhjvHRUWHч0z& 23y4LI#1%V*Hp: L `jVo[mmX_(#ФX{9C`P~ApШ K'!c r]_ 9b69 [hP .H-<&AK92Ñ-rIa'=ˈ-矎s6qտ_ڙɮ;ܺ^ gz]Y`͜cOڠBM:!T#/,xQ8w[T5=80Lp2dG;aH<KT4K /TeOs,,FG >H}4M(X޾ LzJ'#; />$pc2U3]\&:bH( arGpO$O6'rW;Y2 `k2ȑKݪ!z*`]tҹTCH`Xr >Ol@k Q`>x:Y%S44RB)Emcd*  <|W|8)ijðzm' c#xjܒi!ZM2?pr3GDO0!gh ,F}p9Bl4÷w0:WTtɴJޤD#$c 'zjTp@*mBʂ x@Ԓ?bH# Oʙf c#,0[s䎛jBXS  _J(Xf5o{a=ń>Ӳ$$6`rO$d=<%\4dH{|u$'ZZXD)@R9vs1NV$V7WJ%r299ӽ$Qҳ3&5,c%p1Ժ(WÈr#܊U}ϷpO御ںS4&Hb_ N@*ndpb:kM>DBl`T1ё\$MPIڇ `I9jhKJ,`\DJǒ@-,ʉ8P]b`y't]0tXrepXv Srs A4[\mwù (sއeT{0$88g)!"4Rp8#у*I.ͻY9;@VH$>I4J }V$d98.m!]]+/@<)Qx+tVYԾB73R0ps 0ayTSiV*QT}(}g$q:^/%I!tm0px"EX+;Ir}'IB\G'$xǃ e_6Ҡ m`7VEa<rM7I!#>2>s Lv92 v3 >A0MI*' )ޭ_ g?隰20@6`@'O$y8tS3bpKՀI'GtvnTXdu[}.i*jU2cHW!KU.OrP}'`{^Jd*i*K#r ɕ# 5iG!q4$@0|=|@$I OG|.DHslrhdA i:Ib@fO6,zƲ 4}nQ#GJT8$I Hf IKstHҖ%LAvK5SEiO4IIWW=JVWGX5f+cC-Q}J"SP#ө. +tA)4u^j Z7 uy*Zm.)2s&EᄒH.)+R.G*WCj4rWeufyXlo[i n]{<[jd*@Jb / `R YǥmZ{D:ؤ5d4e Mn2@-Zç)-4G3Ȑ,JewJgp1;av[emS@iR?45 (i$9 E,ePHݱ'h$:OBB.ԋEm4`ORۓlov$.";"bfIX7f!}͹=$ b;|*Cp\xJDbE 5TܸCLРIͽN@$|dYXbFW Hƒ @@s D5iR8߱{E`n8^Ƕ682(BCFd339 9qZUMZ 0pwg!Oip3KE/ے< 8I%:ةgՙ UYe@Y]v:#'_95-QӃ|av[ n珟S՛=}-0dͥp`%EpH*NH պ#R=֟:RE=*)i6sJzP:6Wv:԰SL o!R 6`<|thjbK2f }L23~GYx^^Mm͐'Xީc"cbΊC[.a32-U?7yo:WOi/j4,ZntT.,21Ks!, -ߣ*+^QRa3:XPp7mRTggch p#ۉyI sLqϕ¨.U5-/};qQP*-tnžX+bOELa*90 i&яʜa KE,U&|2S˖,:(Hc X~C$^5 OجeY-^'L;Z ~M9IM:n œz+ xp[iࣂT"Tr&H#Wr2̾9]ojc$v=UM dA12QTT/l r0 {N:'MTlQ-* !mD HʡA [m][A%EԥdU{!s):f@ M$d/ϗX20f{˞fFW1, $;L--GȮE)tX 2)UҠ}[Gdu--w*ɩnĆj\T,-bc̃h#4M^5C2w&㧩ml\FLQJY [TD G{ީ5 U)Sj&2e`0RN)4n;[AZۨ(heMFMKsqcL0$96GPgr9\YX%es3ŐHĔ&Ŵ\R t!wPe'崯 H!xQ@]Q xOR賥O&stjt6یT0ۧx$lG… T/7]9!zWWA7vGLF3m^q흮HRTB #1SW#JlH1Wh%&O9b潕hzMaZI)-撾`nuACTs$vg)k3l|f34Iq%C#Le$זX K4f8Ɗ+iClCPS }Ʀ^tԇ=ƨԚXa([>5GԅNmN*5ua[id CI C̮@$D`N_tݳVqZ7۵R-WJ)}5 ԲE*KGf2J{VZ{g_g[[a֙J |-S_L=C4ndzo$G?Ca*mK'.YQyT%fiR|]h3in@5HR8$0M$nO4w]Ou9.F6q.`D]NI@:-D\% / 7ܻl{u\45UNmZK>UvwX6PI9+AjPHmZ{}CFcvhѥ+$Hvff\!r ere1IG;d@  eES-KKP,q20u)cIU'TB^ɩ򷠮 U;LUM#,eܙ4kGnQUMB{4.SHUӳRƚJrh1e~t޲kzUz(ƚ)ԸB:9/v,ZYiVOܨvOBe&1a%dHԯ#DxRd,Kr8 (;Kr h4eA:g蚺8)nZ*ibL%W Φ"f JXoZ^w.rߡڿ%sOON0IāĪAn,O5y'ICM3,UO`U:dSBj5H\E%3jd é;ʉ)~Ivd3:UW#IАK 8lkskƉ±k4O^eRIHDpC9?+DfFx2G!IѐT*GYTͧvٴ$`:ḭXHXBʐe_E1eA,~ @<`AVoj1yromR0^xQ˸ S`z(|h ڡK%$Rn;  PKG/Ьʀĕ5_RtKJhEKYtzK &fBX^g Ǽx4Ev -P}]ܓ}ĵ$ĤxV.)8w7y%8̠D>d)#ܚ1C2hhÕ)s1U4Eeo(@˩5 PEtPg42(p0ps};䠦;֚a,sRGr|#W]C;9fԵUWŖ+\;($p58gI 8R! m©$ s5MeT2O&P1$* czx/ı&Du 9ig<٤R*f8\hҙ*EGy*)Ҋl& m~єQO+O1Rj!WH;J@'LBu1zHZXı0|f1wm M.sj*qOHĬ IR-R.7VՈ#Zs@XKF0:řS#]tǗRI=Kk8@uZ]!sM  *ڛN?TTՙhy Y(vX>AΏ ܥiǦ2JJsn=c=*j'Y%mƪq#C)QOhs*u--姺XS -5sS"l1Eu%P nt3?6{1yPQI̺Vb$`*īzP3KNvAQkv,j*IbjɥGwUvGR+2Fvl$ ͬeH9vl`1y8'mz5:S+XF:p -G(R$lK0.Tn=k'i?hQDhqх6ڀU0Q]DjZz j\*ْ K@I` 7@Qd*X bNg#ۉόϜWuu%jSe1:A.o1#i#nKujKnCƥ 9 pA?9c8ɞ ^EX6񹍸&e!l 'F`AN2{{atWV# `+yt47 GO!Ȓ(,  dQ-U~ FK&EH0Y%(cT A8=uD!p+ViBrwybxr tJ۶ TM4H$5,7ۿ66:hd(<PT!Prw+OMqZ5-  BLw8?s<@vcm\p<`Y+i(=zW q6sgvL|6e.k3 X3]Xv'{bĹhY6 $`VE-a:rM8AIILX<`i#pG^띣Ih=3Φ V"5IWsc(`W2:K^ijfG, ?pdr$OyȽ;K^Ӷ5TReFi cv#A3kAʢXQJ TߌbgfB I,,i“uK{懶7-jjc,.Ec OHYAl`HPofrs8okMo)DT{A:"$XoһݵF@ U4 *@ ぀=n^s,L崱F섃+ulBN9duPW*ph/ጴ")Rf1`@'OW z9ގYbF9ƌφ'pʒ2@:zjg% FЇw$Fwd~\lH2@hة;NFAg$u)E}s_'ڽ*}XmYj" ɚetT'0PpH $SeԕӘ̳TzLC8f 9|?znբ}Eq*|29c\+zq@  `78stfY"Njgp!RF>ՅiYA7$?''Ro8jыz(B61`v n<_zW^qe\ HHIRD+Q;9R9\q3q< ?bN8ꥯz0% cE|98RJ++G a9!ܥՈ<9sѧN`u[cA㍡A݂)6p| td5t!(j  q&1 2 l׊ >S=9O#9qTqa P$8 >Bߧj78naDt bL$#ocd9`H'^7=/Lvp3I7u>zm NTcy~ߥުT7d*.GyM~\HikěK?{~B[' A S`HxQ+[_SHmg {B3*R$|0J ҢH$H?WI #';@Srr9ikX1-9@>,>T9<&E9c680Sq,B[>P[$1eMn1YT=`^:qxIQOM;FmA[#r8<Pݜ$`rs}srT5 U0H=J#$UE6XĊzQzjOH9 bo[˰ rz#ԼR&ve9K?¶NyjQ]*V@U>9oכteO]j;%r'`$h sJ%CTl/'{8$/U:$3BTu>T 0sO'r<$P#nĐHFNs,S$1vbQIX0 >xoNt.d"7(_4I T|3svWVJrRNX1Frl`pQEuՕ+IUS;nPImdb s0W=OP=/&wjM9X֥ EVg`ssfSH:`IrON9VՍJvt's8  Wz+ti%ؑV^SBn ?#=%mVIF}i:J=Y[. E=p T&Zy"dC0JןΖԖk=CI\)"m$ORݧ[*ijKR謲o0K#j|KhHp㎺RNowKMm-ʂW5 EUBRU2 #2=Td#,1(R@AI HRFPq,SI>*EuG{~t}siV^vj[-$qWQE'moD >²zUE)`nM3+>>liQ804W6SH >*EK(1ުyտtEz:j+[gx8 ӈŰ_OX;},6]pJmUҞ:N=OB4h"Y(Mgb3xw\E3@R'5{$:1>"oz4SmgZa1z[Rzcjԥy,ˆ#9ӟWtڪwD4%I\CWZ紥utt#G ,Kw(PnMgVIQ[b[JTLiHB1S }K+Xo;gޚ0쪹͓EZnwI;*d7/n| VDMZX28Z01jW1\y;Sڀ Ѱ#薇T6ۮi5QhvwKF[X)eYؘ1z spEe=./V&^sI J}C2ºviX-@$E t4 R QXjĊrTX{٣`kybg EM 3MC7$7?T$ 0|WUkL1oZ0xǟpπ1z&[WҊIYʲu*0W#⺃֨XjROLy>^~U]vu(M|o?=$o=TiҶY ҴU8P\nMrդO Rv2㧈ERg"E@#(B'ϸ dtC7fh%>Ҹ#$=87K^vںϑ۟qOD9l*Q19'$q5X]@vT#673YW#1ʫ~|s%6Z)0ڦr_pޣBy$ǚa0L@G(oq񞙪)+T.{{mR!!؀7ܕp'1WZ 9 7#>FD9cp~|i2I,*29#>@<}F[zOgSƩӠXKXg$ςA:[8i@ꄪm pH op K0si=? vTr FPYF|`v3T! UHzDEDdRA8Ibij6;cgq㮍,PcGy-$ |9㞏IU${"7 8s=ZG}=$ŀU>8Hd ɀE''_ϔ5Q%;$;s=T1(=y-ǒ 9$ ㎛j˙" $dܒy$#="i1er@R ck(WX U2 9?tno򭻏m#ش1yS3:6I(2 ?gªA%merSRQQ4T28Py-p9ឧUPF$[QYQ1,biKef m.ʪw0="Qcun7qz={e.5emږ]O>/I+QL*C}CwU۫Wozf5!3As,,d JVPzTV=1K hA1BP+牝$swVUK,S{U2 ($ |<&l/ grt$T'SW@Kh$EQ#(ԪTMd:H/o4=VHrZ;,ijvZwd UU˰9r݌ tgRcg&2.ʆyIUC;S'(QN (f <Q‰jF@ nxES&KSYmp;N@’&' 󆐃gv˱>K灷#x/U8},sRg*̣$0~?Qz$ BC=ˀss=U)vJT 92J?GʕRYbH47*Al$p:]+ߵmw ~w*c )2Aѓ$r?O8ҘW_Q3±#ߑYV6vb09;8y_FT00 [tAU^v <*2HbR+6'$PIHsd+3G''EAN.$G W<`03ҊﰣWb~|!vr,=8pUWT(!@Q89eGimr۩tɫ+iާ}Wt*дSI ]ĂXbu`N9tPASN fHr#2E$Ij>1 xHr:lFX)pč!6h0, ;XIm_ܞ2EjӷZ)%ZIuGSRLxG\OLl1 .$Ru61T:u56 =<Ѽݘݤ*7!vEH0 *rlZ}160_rpsjfsFy4*Nӧh aEQV%28/ QXݜD؅ P6[/mutU Tm4_YjVY*rs, v:h8!ח[+NM> uVF C| N:ҪziYi]ť!P{N2@9UwS5M#[W:s5-I_5"R,$KREl܊,0啊*Q#M _eĬ,#X(Fm]m{EKM$u5VY542YV I9.#ң`R;mŲMyO"XJj#dq"ILx [nFTjNws_w-I5JcULK3rw3 :Y{~O}OD3] *+$O PtjGP^jDӴeLSU/kE*Ʋl7 Im!]GC,Pv-W'rgCW}MmcՖ hi53W.G]yS4q,X/9 mZ߼;I;EcQCszԱ0CSY#B>ZӷMOD;}H?T ]m{]d(s*2ӵoqjiTFuzHY(mhjXKbvU6]_,=1إ3 3q&"`fIAȬȘIj-"XaJC*j MJƬb0u}Pl-Q%ejd,a9fPy+Ght溮<@yU)Q393 H9 ~cTUڱITT.3k+}-Xhn5Zh%c׈J` 4dma0r)i33+&:ˢIY($k E8wZCP NL)"tu@w{AAe7WdwZ+VWAF5iybtXJ[6w"Kme}9o*Z)Pds϶=QOu΂[FS,XEDڊ\J` FB(cy1ZlM}jҗOkz\)BJkEU@lr#l]Þl.2oêV9rii3a?˜d?YHw+ k,d&2 }kXbnV8)367P[*nڶ N[j}@YSO &$_u4ed+ʥSRj[mecT ,r* 8"+ Yj*Ԗ}AHU@dHe2,6h -f^[/m)xoC=4ȋ))C8=\3ELU^iP!|ȥiYg$0eck;@c2!b臚Kj*:TSCU%,'XcUw*WdȻCϹd d eb*/5W)#u n) Ĕ%;c3Q}EnvwR\(*ĖMS՞Wj_Q Kgy }[{]ӕ6']ErҚ{HiK?Wd)YWO;4#!ٴ!xRr~"42ڢ8/:+DR'YRSA܏(r ISKIa+S.LiZn0SM-UtPKI Mtm8?mO XL!]Ĝ;uQ]w˳ǡ@X5ɆzQ F, ַ6M%KDZQ|fJc1iȁCxeJviA 0ϠnNyGK!J9e}F{Sn81ݜxdxXxK$XHFG(S10T 3#Ph (UILpTiӨԨB:=4FdVj&y3AAMH:`K6je yYWA.RE5-e-RG#eG"߆o\ =MQQk6]5i*-e4t7&f2W#%wsK]7YmԖeXҝ+L̵zTdmT\^elYhQ,C´6b9JLF^)FbV ;\U;2**Li4.ӗ+.*Zgbd:ˆct`S==Ҹƛ)cilKq M\{#fhj p2) ۭUj+ЮȱY%M|RB2*%euUpyij\RxTh+qNRhTaR*>_TG,5"ihʐ:dmhс{,1:"ޗ7%v_Oo2KO,MA&2n @G`ԟFӶT;5s UU^U":Y\4241W<)1TVd5T*evǓߝqsԛNkUiM%9ihڊIdxeWAU/e9(rdXIWxf#w4F:€PZY9d<*줪IH(Um.5M+ڛ>Tꊍ_jt:;LTbjXVLT nFs*d=o󠞤RnɠUsi).lVɣ)k|W[啌JGHZkz}_ I)̵zhmW {' >GI XԘKܤ0 ᲦfeS2ق_fY3Sd͊)" R`)Ēyc&[.V4WK:TMZuZM+QԖ$b`Rbn[IZ^ )ǥLC<>R8\#3rMMC*c-EQ(JxvST6">U[®zsxlkudttSjz-t$m_s9\ ir9y8XW$Lu#mK3,X4吔ΝZt K7S ^55-= *SIiQ;*I;F#Aې:ҶgIsԺT#h֖2B(b=prA4jz,U̢*4"/QE@Jm|O(fQj;EMF[ T-eRV~L 6Ko C|_&3+yXI1$#Vu l7$q3"$II^n[m,¾I \6wg&I\q66w9Fn"Wu5MUCM2v CESxwR]+ӲAkg)%ʢ)eqCX3NC #1KcjhEQ), ʄ!`e3/s͝f2XNdz@ +z{wKWk %\ܥ*AR 9f#7c-m榸".i'T,fuO{3H˷jqQW[(GI:0Vf1\HU U\ PDyT>3\.b/q&C2uCQ!)EZ28(m"&h4rBzYv]hSsAjjhQTFXǷz Q]mllqNw Pb ܇ `NUӆ z 2tVFAg9Tr<kJ RehHV$i㮿ſG,G.b ooHo20K m;P׿9_ env`4]k̵j^+]%mE*)Y7IHL+.:+miVz`"İҧ9dk(tsTs_J0^i xA@j):7*EFR5e-$lWo.W7?Ꮪ?EaXapfGAnuX R z@HPhDڷޔXGdJ=<%NM]+nmtݡ5LTݐXQ^emU,{&)adq8 dl-Q42[_O'U,N[#4:`UIaTƵGRiUGrur&0&;b휣J(`eeT`Aۜy=_}tz~Kd¥epA̍Cm$9#'pcԖ;FgJS?@K X7zwEZCM*Wr+9/g˓/#i +QdyܔYC t7ww$L,Ӓc?q֌ֹ;ueM͇TL?8##<HYm[ڕI).ۏ91<29O8?Ny=iVКϢھ^wi RRTB`=c'qDqI,QP~穳<&I& k>XRQƣ4\"0Xء,j+VhG_O]qI卤#G qOcqք-cjBzۑC`{g GXzA[E#jCpGޢ20#?RΒoTEOX#X=?+?I"R j aTbGIuɪԴp]=zzwa -%PK-sύeM߷SGQU+Đ @d t|ey9o :_glesSR;v #h Vqn<'˘O2 F %Y X 'u\*z}YdqǏ`ImRv+;cGP[)0TG}Ju۞&B~-Ϗ~:I}Jڛ]ҐEX)D 7hUK):,4#4iK-:xOriqD4t"21܊7*6SqUAK5=m<(J,Q# 96:xoU._ /@q r0ۏk6|㮽#1{V(BF{;-hȑXn򒾲9)$f,`;0ќ=zZa4W4V<:ZrLU1@X@VpӶ[ޭ{Lg`!$vn<__P:XikUhjk+&DSM$:q*3BF87x.{9vf`Hvc@Bk ,!~`7  v;vn3Ak_o->x(㪚V%d;E$#)#fGkfYfde#`l9#~uSD5SR]ȫ%a9>v{.y $aY mhp 'O  ǯoHik"Hxq.O'{f0dTBK!pvTjFD-3Do< ch_= I`|NS, rO/UrB1' ^?ۊo=f[ZIf&BR2*a-ebd;VX猪89ղ Le=:.̑1h i1'M31xUodC,pqTx$h,Qu|8ZU殃ہ:a;*W*Vm҆l pr͉ٗP_ tnޝ; 'z]x89]%p ^F̮C]۰0FO"ӗi)'hղZB>a>:I9&b:M_SA?ts퍱MXT8&Tٹb7@9ʊZg cQ.9X6xe{,EXp98%HV0KlNv,i!IpAUQjށ; RhZY|O|o4ԩp%f\Dba% d I`2~OQ=P+bRH' sF@=5n_]ZM!XifpC,͵irU~YAgfjZmP[f'x%;#n.ɠ*1cUK  %S#!Ab2[9#+ZII`b8bx3x2:ZOf[M-***#ԭv\QC:2 _e>Դ[:ޖJ%9h%]=V1,PȁI'9#U@a:[QEzH`J+opOjR&I2πQO27zKU~Jiޡٛ۴0p+0ns2yiUh}B܌qOWtU7Uh}4' 8:LihiEnA=C[G0yQ&CF$d|Tr:# mw>X/joQVƒ4dǴ ~gp tגz_R.6̛F㌌y|^uuњ+y[wJ+T5wjѻKQ$E$X>hvᬣ]N='t ~Hetj:N޸s; RpdxyPI1Y*[ ,COL ӿOkGxԺ[EBM4ګ$i˭5@V,q#D'!c۞uKKzWWwhG--X h4,#OK)e}cN)4U1}%u#*wRzpwuwokH`{cXC` $,tb$#U" 'y @ǯYu?sm٣DUw*znxj#,SKT˨' }}.",NU)[Pjvvzor# Y襡]X@"롣(,F(x੐ =sSMEh$OVDcP :1GЍQM<|[PZ5lH,+x]FoLT!$ J#7<z+J*7X;L6 #R-rYhϱѣ+bIœ8'@u맶b5X_bN]=x9& l B0\u@y.Y[ Hl`dϐp:sNVUԻJv'};@xs9RTiD +8RA''d4cz7bkP)eCa=8䯞]+u֡`Jd !=3\䑓͒H U}rH?<!җEBCSbёfN 8pTi˿|%?oͶThKmeY#bBsX.gB\FQU@#BqTzVK1&diDq *cxih!`HPX;yq\NG|~p{cLOwX0E+bI ]%I!q%=*A]p$ OUL4Y,U͆nrI Tc| cgPUK@Dv2I(^Gkz7Fw"ѯ-M6r; h$[8ykTF$~'* eF 4V"GN Vo݆$rN20|`s:ߤojTe_'j>*H< ۞z=:[7@ 2AlsW-B4QS16r6UD lqHF=J3H;oP;bة\"Xu}q x$`󎛪.1Ew~n$NrHP>Pt mlXrr1"-$l#6C*Ѵ}HMA6W{wę.RI"Ҵ@#UPIqy\O4)Jwc8$9)6 U29~ۉF3pNzQ(`:m]'pyɤ~{tcĬ<ލ#9$)<@8 z-nM#H@e$T%G'I/H D H#8t\M.EDb%`}B78=%o~\-2`@r?p:6KE&0AopN9##qziH(au;pO<#C8huv R>z(*R)g#5MUT 1 #,j]ƞ쳲9t֚ZG-娬pB]aJ jJyvرF NYz h5tWsLuq.R٫WY)婎lţ9UN M/V6A]f hIyicwDs:$ $s>ZD_ʦE.QHbרﲪ׷7~BcWw߈v4%k.QR@ͨd%B#G :,VkƆ1sKR\a$f92"ġB:j+c#E3 ;\/#8x  }}$c@8Wes:㕼b4B"l @g,*/cz^';GGf[8X752HQZMn`=8'G(ΡAA)oi9*71*T#*2APQgσ)\ifa\=^ * *@; $Iw$Os-%+mfPl Ipy)d$r\!!N`˴B:T^I!0|fzhuYcbcP~3NF K(f'aGyN d\7{|x<~6j#T;NC߿ *.B3'`2\ I;r<ڝ\qp măW5.]vMy,ƣl{$8V &(@rVX%\c=Tuk*}C=QI,Jd _o dRxԶɣ5"$XWXTJ{p\ 9ꬾ5Pd7h$P"Eyޕ Df.D*zUY#oqvm'!#:5?{4m&ZKvJh%jB4HnU !@Px۝n]tl52/ #bX"gjI׹]špjh47)3$hUa{`cNjueehisPRӤ.^J&6H&U B"YXH2 )[aKt] |Z5Kz[LZghJ۞NOOSxʡjV9"qXqGKCnzku%jzUQT, [J)Ch#ix%c;;ܝ:ޛѪxaG DWG &/ԝ}-t5+i^aZI,N<ӴHba!tI3JU3#Uxgf2ĔSEg6և͡k-l:$-;UQWޮumAkQ4l,KT]}HmRCHr0+ k+ֲSj֊6 -v +C)(=7 f֝P[nzGFTQ։e{=<d9N ^T5=_z.sRGhaI+Hj*竐6#%WBNsVkǼ5&S9в29lpDX#T=fE"D)3g2\!-$cQbmV? ELgr IccX@_{;=5^_.6eK}N-,$ Qnxj7lnf=ȮÒ 4](D8awl?$RNU5-uDi\U\MtB5J3zrq\KRL{1,$ɼ1S3&^$KwU@B*G6Ys`G$kt i魏E\tDdԵ׊ ^bC7IE׉(R'%P :FVz y(a ^YyL@ unzcRRE]vښ9*jae&JqF\ 98_n}R57rH׫P ڵvي猘Tz_ _>J<煫@4M*%?4rӽiI"a39\&0HrHd,\a>ҞN6IU ~A=1C3̾fH-dxYaPX~|ŮY:S $kc,(< wlr`@T,tfښ ~kd)*#uhVG$ .q։v7ЕY q(um/G榘 (\;u*i)TltJj[nv#c/=턗JqIUoK!Q Pcrn2)?Y-h|9Sf32%yäk*t X3Y),nX8YN&%I v #|mVWz 槹5 n4h9elT(%rVZQ*iMKcQKmX"JrY%"=WtK5%[Gbd{m6(eETyԨ@  -,E ftTգP @$͘Ȫ ]S>mBQyc!oRK~%B5$A섵#Jv>f7 Oi9URQP1d'z nS؄zmUL4UJYݡ2JDb$ "X3h2\ؙ$JyyKms3^'1[ˍ%%@f#$ AQj"*g@5GlO 5-OHzyY{mQHc^9BrE`r:4uh/Nӓ_j$[,qmZ_L74fs a祺t2Sk ʫGfJ#!R ;?$*d`> "T݁08Az;M(1 T 20aH;n`hj)/,RdHq bc_jjRCH#큏'ojze R$$_ Ժchil5KbܦiA"ДfX1ː]T 0#6r 3~IT! %rV&H(cD7URldc&RCS5,F r!G_q*|xA`wk%Dq?U5K2#r?߭1ŚJiQ Zj8-PŤAA Uڛ0Y!%g+9l`$`y{0|ʐdRD *HI]$X('q~dd[!y Ѹ7 %ED{+HM-1ijHEY},[yγҗ(u>#D(uqjuw&X$'lr6rO-㟏խٻMsS"FƎ4(J?NweBx3ET,<1x]²U M3H9ABǑǞ#)qfE(&7wZ$3 OUc2̱M; 1),XE{ōed];qXfg&@}!8>kJUqztD{`+5;-L󰝥p( >`\nnx0ijuϰ:r9Vuͤt<+- V@E;'1 24Z%)Bub(Ǟp[VjY:iH d~9_vU<Ҁ3XFx `p>zazy"rX{#?ql1$/gaw gN)u 5l" @c]};G'O{wJ)ew` 1<瑌c I<x?=9IYlo)C#H30U|~u&K0l G!tRpKX{F$Ш(R1# z'y'SN&UyYWhrTߜ8ɫC$sաwR.iWJV!I,IBN9$g(.tTdXm "ǻ x?H1CeO.RY֡h0e+V0̡d(15_Hr$zH$DbGf7* ,.+(ӵdFe$O.P^2z AfϾYǒxG8:eܤ*k\+8Q"U0>:CN$!R#U$V8̧#?DDR8XFONkӾzB,N|/Ir!vm7P~Oa6KE%5dUҳD0Ȥrx$d%ѷZ]PWdgRH!cbH,A'NP+L;5QIeQ IaFI`pFR c(0ֺ SI@8֦Y󐬙ȗEge&RuE06 -7boN*H!bPj $)(tyWft}O۠))锭MIAJAڱ\Q窊+jKv ӵC7L0q'(x#Θ/D\.Bޖ>Dc 2!ON-WbZ5یN2う|rnCA/4чVe:WOʂ~5(CQ#|ud%}+P d.?bsSk$1#QsNN9 y$D81~ UwQUĭ1F!x>8r6k;_ :OQ}+.Ss")`bR {<FqbNR&qSBmv'Ih S7@$r2#ӥu+EDcf[uH60NמεZvKhiJ*Fj[>rw99ZLQV2s2AܧyF9r3x#=F(.Ddb* ,Gqs%M,x'vlWI6{vOUc~EV_o&A;4 ExKuӧ%#oLnFLDZJU5Xk.\k/l0U4iBɌ`X4iJ37\ qF>lQ'6E6LI/c<Hʳ6fV7@5< HHtо(X~1y'K)(.U6!QC-͢?NJT$D4i*#H;Vn}XiWUOzcNZ"Ӗ; if:;fE TAͪ;N[R3$*ޛzl*T;r0Pp -o7بm۝uJh$.r]Qrے0z\:|1$bSPؔfg@{څ6)Qt=3"?CZ/ҎOAu-AImItsZb#\zpy"UUF =S pUv}̢z;Hh+&.bdMWU bY JX-hW =='9:x'vÜ̈ʮIBUխh5(ycӚXHZ (&8]"eDjπ2@5DŽd!z͛U5Di%Ić5;צ?IRR9J(Oc;'bk> GuW/Qˠ/+#j TޢkMʙ M%gRZ%ullMQ۪k?j{Wj{?Z⤑LYdo*/H ߓx;[h=k#OMj[–ZXDE Jwl׷:=I9d@奦tFZM*L߄잦pᨎ e׼Hz{E]-#(+Sڋ" ߧCiT֎jtCogMQPVT\++^N5P$9P;Cy|̑&uղۛmdii]0'c#BIO񲵷'}E޺+:./q$BQRJRiaB7H`z;{{:k8#]*5ڊSRUJGj`1Hݴ_);!]zYzKk)`9XU⮖K:E}P'/+u/ڟo]n JM#K%ʶ<IWO &! ora)ȝ-$m Ĉò?mK1&x0DޛEwµiŃ@Woفv;nQcv /SwQV-d["5gdTcQxOIލj ds3~; <` C dyHzU }3 #I>s<9ʦfVC=Aǜ|ztOE UxdR\l9l( zihTa$(!Q89`yZ#B#*^m+a rF1:}K TĊc2<#b,23^"n^0ORUI$Y 2J'bwp]HD'sNpHyIi-,tS+:/$2YFߕ$(#r]LpC,)]ے0x52E DZY2\iGfO@bv&'oڰ,=5`x.p mBqp'du+UXEĂ7qOTRLq6ȡ'yRbr<`4Ր,gcz+zgr/qmֽ @ޣFT9`AOEUmTFOG~loiYv2mUBWAOXU]Ϊ(QEhb\eAsO Ĩݎy\>@=;T$.y\>)bJ%:^_If> ώN~jMw<ߓ=p"*D<3cn~zi%KG-LѮ,iϸ:e86V< AHMtvږ$h3]K Hw*G`ǀzӉ[-RTSX5keIg3(2Ӑ +JՉD (0iDwazmT..8F5 dСl…aj)]QO4 qFJBShfBF_p;O :{X6IU(S,rnV7s |>Q](r* W}iK3lTpySIB+U82GO vdN}s~;%eNk,Lтmo6#}#n^t;̑2 par p ?UWwmLi4}ֲy[%Fa2S5"`iI"2pۑӮ׺N8'WVQ"E]ZV lLj:zJ^JpOհd=D s`W dbLr9|?񑇚" AD&FU6#8r.bI*(lb$Q9m/~Uj[v<]ʂhoCNCOҨۙLX0!OLPk {om=}e1؅ݤzDK s,K0O:u)ev'1/UNGv*\ Ď6zSLh 4A4=1OܥeFbyMF5ZTzP*[5jzR35 iU$Mfoۨ+jNcPEmh@ޢ;iCrJgNoAiSR*XPB1 ]WptHMɱT*!. a *21ЪSJ!tW.G8ubW.A -!q*JZq,ueą nvOn7QcԚ"MBz;MTJjuJP/R8>m3BȜ9gHҚyMBOJ$ lxG_MUMc-(SJ/ !`۷`!R+3457j(TUU  +EIXd3,K4q]s.$̎N**@bItUjrGr.ZgN*Ju[j2 S Dl<*A uiQEOQq`)i!Mܻ\ }vr VWԧo@8ۭ4 J*[c(fk309^-rOVIa4eXI#4HX-rU4KQ&*2Ce0AUmd҂ATz R=Yk,5]J(i!5ج`vE>\Ɗ+@iTVk'5eD\]ɞP2@c -])[*8Hh5Tl0vFʘ$zSH6Nф O'9"|rن%ɴ [ʄU*j.kT$E>nY@1XW nMjsBK#HfDFkHR*Z6o86Oq*hdT*`)8u@ GgwT,BʂPc jY7c2eH\vTHF^ ;!і{l/԰[i2)j;J;͡, bӴKSU!̜QPC" ivH!zh;_`Ӷ;FޭzZIثO66w(DJ.=K棷AlҐjnnrchI]41HUaCGhc6N W_f1|E,ҴYY29H^MiPi$-F^9, "EVŲ۰'zU ]S[]/u(inFd$I#99POU=>Ѻuq%Zy􎗒U Enȵm,`^]K u~#E]Y4PjTGƛ\m`Uu|Xt(W)縒#ȯ,9V HYT~@م™EGG\Ҍ̞֩ uO0&Y-)XR0E֔%f$tv nd5Rvô`gjxRѧi$ )UGreQ"lԺ5,V6hݎm4ն/S3$('\$$[Q 1Ԑ%\!"8v`r0yl #'u:%vt܁8 JH<v;ɚ+ 1'ẒU+ ĹQI~W3uU@͘@ 6Xu+=2(]§Hۅ4u'K$4R\#^#Z U=_3Rw gvud"kSk-Gk֚)`6{S$?qи9{ۨ4-OY5xeUB6% %$.ղ8Vii&ֺyM#kX|`ԼWbu'r Ѓ>z|eYP$$HFˑ|Ϛ2JY'HIVիrY 8j4Uϫ֔IoAb<MH@y>$NM?5V孴֒]wEʡ5Q aiڀ6#=YIqWj͢+(QV$ [%TcUL" `cG{Y !ϤeS hԪT(͏I&s& fLp,ǝ¹hum+Ke]LꪱgCD,p.ʧr63ڶybC-eVS]+0G6{Ρ`=B"ju St)1B&yoWﲷ CL6EprT33>HP6^AR.9S-CU-GWW,$u _q,1oC;_òpJ' Yܺ UiXYf%u1&9 ;xB,y!+eyaefI"ux7V `@ 9Rp%$/=L(,^lj0QS-oybۤjSXZZy%)`yq+ 5`T^*"ݨmXi,w2H*=ʤI+FňBxg+9%$лlbiRdXĔ$XRJUG .RS.z9"J8R$[p@R)qlҞcRo%Ik]pl]o!*GmF` W}o)!YƂ9eXdrcݐ2xlvQmON=Opʁ2,OPr=2Uщ *lK1YO~K=꺂O%aL jDfRP3%@ _ 7̞!:d`he2ȱ*RA!qXCF6,(!Yj o0'ƥVm$nE>UAMk1ώ3I r>Dva<<ek]kB>;zZ`};}U*'X>&F}ųXh]rDiUMPcYGQl jrRϽ(*p' Y0$/4 c%t)YQ uYU^`.r  (ڱanuĕWjGZzL-'10} eWi{k<4-L# $#T/,<iIe %U]VP7rʟY +)u7]fk/Zܭ-$ O&Y7#Mlx<i8③3 23ГBx:H6ɏ-[/">YC:@7Yrv^æZy!^8 wW+hj],j7 OIj,7H4ĊM>Z9* R9܌ 8]A,nXj4rU?P3 q(U8c$d)4zG/9=)gˉQ%*Ur1@ ZY>PMQPTYN0z֬-sKD0SLhH.Z]H32s-rԢlO U[R4X<ՌV<BA ei(ij^C:[6A;vzhQ5D8M L9&xBTQ]w|2A33l.(H4h3XoNJhㆆͱ _vn \cXO4JJa81 WKՎYifEpV2:Oe}Y wIq ڶHO'0m!\+AQ&xU)O\GMa2|"TҮuLigG!QSR"w*-ڼC -4hFVmoSW S] o)"!H#xD!# c<UsFbj*ija<*X܁rX|y/5WH#|&Ȓ%DP jFmpxϜpR"J@OzoӞUTqI<~9Mڞ_IQFF-Lg?=|_"qRʌ1lrp8?! "u/SjjV?޶<`b{|tfm^ii{5;MPfyy$ :c ӌ2In ;o3VY,M"J7@3}Fico.%veT$ 9W*hHHdo.x<^1 ̋rƉ~Z8#I{7@B@E!nmxmvpDOO4.k0=e¸a걼+U u+9TH edsEKx lTơ9 ڧvHtר.UFY*dS;Ƭf7]26ӏ<|MgØF[̍5-Ǚy }%A+GN/7j64F]oZ* ?>I?{}YڎxUN IRnlv1qV(2/?c:ж-_JbGB"aSYX* ʂH/ /~6w,skd/m7ZWCigk 'cJe  >m{b#vҷKEdlSyZ!WߪjZ%Rb" x>ђ9Z]ҠZH $ `A@H8O[4u#*˸I/"1FUݜ<4Sg,E(EWd Txb^+es(#I ^@"+f HvtW2;9O$veQ42G Y?P*H9#c#瞣JF8+1HJItvVh_lEv4G`"; $=87K+aHnπ8sD6f\!68IdY@"£d8~:8QKf5ƻDMW;s gfb1{lHâ>8?zfqJ:`pAz0# ^4mU\t̲Hx~?n5E< W0Bp}  cQ1z=q:d3<2,ٓp ;6ÝOՐj*Jb]ضxU~2:JA=}Lo\?ЬJ+X'\ z}C;|?_:>\YyB0_'*RLIĪ 2:+jk96fI!4E?zGmx&H`TȮ$b[I8+ɛfE r*J`VcXK̗ 9=5D{:=.+@P9O!@IGHEji%)xpp Ad`թiHHc*F˹NNq㎍y%69_3'ey>lQ?b[̐p^q\W[=1[Ǣ``䀅Ox?ʹ, lrpXqxdn*j[%Yy988y1ZKTT,͐%O [$gx& / $< ~ھ+OniP+gǏ8sS$W 9m,88?9Z5AYL @0Ulml(!O?vg[|%=\3F*]B`,܇=02w,P4="llF9[|j2=,$r%=n%|`]7mu3 R->EBH0 9S٬54Ƣw UdǎNzUL&"4uPRNYC:R g2AH`qGn`Fd'`NAIm_Sa ó"0*L{J,RH 0W,&e+"SŒU10si01ck#QMbR'i*URn8 Ԟ]Ml5 4l& 8df۸6dtGCzG@ѭa<(Wc|bžKϩP_L9H(ڎbߑl{Md#,J.jD%9;t\f)4$SU\#MU)`5G*+1RX*W$63* llWV'g䋳mvkS3k7۴7G9tYb%r[yya4jmDxQ( 8˭NK%%EUڎ$űbnQ_Ӗ.*ap4@iw{H y2T}ȭM`:@,{v߿%IQ\-јhFETFF\ *m3%, V*ƨBy9$-  c2z2.wfbAb IDTEV66r%O}$rA=4Igz=ޮ8ϧ*MIw4.H$JޤI iأ1".X䉐( `qUy!ZuVVT 0q q^ᤘmAB**gzAL#jItNܓW_k?c*;mzqQZ4E ,RII;Tb 2ܦ2S\,v+(]X ?'=FڣCM4owނ ),̾1I8@򎊢hOdUVP!Ձ8!pHװkY܃? ?/mqamFX'h2̹br}]c1ƂC5&zXL4hxE,I81AK, x!(BĀH>G^C*ːWmAz k\]?ESvO獉W_$aW4k`{닾ϤW<%FQc mHAƇK2EQL𺪁uv8o.e&=e-0(-#51$8Y8-UfBN[#=hwlYAu4uW˴RSTd*#fS* [SOxE}6Lt$oxupYIaց?WM:%7~ѭJu h m 0:qJNTEzXV:I ?1>'UDh!WuAloNEnollm+ѥ}TWR]TP/jsԳ=93 \3g[z?ΓLڭ:OiDoZwDG.&\2RDR(g9ө CohģەNkgq4+U=; ƒnZF\Ty )0mz ZqNTQj[tGzRFr)%E=e-X(#j݊((52R-ٜjܛg:C[h{cج@5d:{Qzث%.P1BK/G"6mRu1gOi +(ꀽH蚐PMdԗXpe0Xė]h:ձZ5WAdw= . +Ҷ[-dn$hkbhahJ=kW`>wlԯ.Z6[*+=EUQ[ 3lM($i#}^W$Ub%Z!b1:qlķ6G*qe!_.řR8`u :YO{5nj5i/6zm]]U]چ+]O4Mj$jKȪzov{E58x U4"hk +,E$ /ێjJ ZXZuGmB[٪fVj˽]3pJdW4THTMzEuU}nM[vV궎)g"h. !S2 *Lꡙs0B4 d!JtvxI0}*(> '9 ƭJnt*_֯ȭ4΋U<t}Ы 0V c| Aw%jYZ5yW cǕH+V(j!%Ϧp9LY1JP7冢hXAO'Ő4FXS91ҀAǭc-uHV b1b9| u `hָiwٽ4r'FBsأ^ܯ"vP ܃\3ӽhj^! dE%v1CA$8/}paZ PdDdi# \dO}zrn*F!8 `9@V\'8npfb}USTN.VcmM2G# T`Vkv`©fR#ܥa3<:f5QR#X!`sz@+I#pAGH+饨zfxȎue HNO>|tfj/TlV^Kp=T >rI#rw@ M{sb]%E =IibI∉ڠo8ITxKe;rP,lGc#EIZO!e L;m qz咂<0.})` <9@b~UC{?:;w5I|RJ"I 2IU?N}yR B3!7n `H9X#VBAeB]UHU$Bӷ!+NZ8v0'!A)#nܝ=-.7w߷v%փhALL= ?l[dSATR[`$`?VA8cr+E["n4,|M|t!(iS&p B9 1# ^mF>Xr4bYmf?h[<nHu_gjJZ@)(ܥ+( ۼ$6eٮTop[ {G' tR$δp)s27K-6rN,Uq{:Pv~|pJ޽-#UHI#1Qgc5/QS[\@ZId@rNpF܅$<5*PA=,;(Fi[ɕ7b +F<3F21 vARdx?JHP7]+a`gj"$um/Q@-cLrO '}+"%Rd2'zR$h(1"| #Uڥ U8w2ڬ"\p$@POw-r~[=Ă]R<#Hь:&A 8P $vBunjkeWF[) ۤX/rnD! 8i#++q6p2|UZ-i5L5[֊kPZJbK]ZEHՆD A'0pEU5 ]U =E!6oWsnF,kƠRpZZc4kWphhyj!9\`VК"q[gMZ/ %0"cFqhܐ1=o]CfU]=-,4,&EB->՟]&QIO$HЈ¨UP$T`|9bI=$#C Nڱ}[u]GmQ;wGk PG$WHR6FXfer9?X$ F}LZ fm9wP[jt,9LCW S HjLZ+(-vdgDXt_T(b@#}=$V^)d_V9KM3&%T1#8 }>3݋s63Ve`r*R}TI S}(kPwBmOGI3&-ibJ)e`7zr9f'ŕ8ܶks8L̞$/H JT);dby0VN]kƍ DKd8gVU`4tKM7 q$wT2]JI tݪNJBR6fVC*##3 2_wZ5ЈS*SC=-V(BtTS!$rIQ!A쬓zeH 89ϑևI3N&|sųc.a>L0hXj +D2El4B6#S=umz6xUv;ҽR@*#BG"SiVEyښ9}j R޴1Ly P1-KLR"@ ry<'5YA6UH{`@$*_9s_ iIHӣ4H5:xH$356R@]P+DI 3ĴtTNWǽ59X*E+I.Dͥ} QWZt杧%M<bG09H:NgWNL%ld];d< n j ls#CoM%>1T6R5%l-lKWü+6 $uɪ7BYeR+f2ڦf$s%mHdn.SؒI6/H!SSC;3H$.zZIi v[^MCjZOR427HO"xVXbmUQ-<*@!:xHT9_MKrGU{]f64dk'ݤ2Ij&'ƦHr2y)Ye6fLV89U,%1Dy(͋Y4ɩy5M2i+22r9 h܌HlvInE"ʺ<7$8(]"=ijU85lk*SZ)B/!3=L}Ѻ-]fӖPOKGm_Q,+,0S&!<{ -ՖSm˧ ICl%kSU xteOP]zՋ0an4)3̆ e/ +!ӯժ]X-St[%MTS[ajf+ n5L *gu W-+KAx7:֧WrZbܴՕT FU%Us 9{EhQUWyiHHiJj}%*4(˰Kڪ {^YUۡ9g":&X Y\S^w1YK-sp&eRsfi ya1(Y#pK1% YYjp[n)+֨H*XĮ* 6:vgm-\q5][RV\ *&Eaqخwug)[0"/_21ʣEC"K.s0W0r0C,e!X1ZKk[CU*G}HwK^ݪ*j!)- ouUbE1I'B1bh$5%8D5S*F9lq'Խݞؗ=?Yh5pϦu4$7BgBVݓv$MV~PJʦ‰ԅM#9۴px//Yf1&X<~jfu%-+HŁM$H!{4h\/4 i]DEC޶ZDHc?(Rۭ0ZryEL\]sfRy\Ot;E:jmH M%5u2Ȇ%4jIzx8c |WXϹࠁd( =PSHG;;fHc@B%7[YT;9Рp\ nр ոڨtxX%H` K(AQJdn#3ӍTY厞lj <#md<MAKSTTMO+Ȼb(Œr?KG&EIM!*Kc ᙝ0yYsD2}y2NF@JASV-{(@,`,e#rI7^C|-fZ(^Ys}L);Bp;g҉du!TKҪC&Fd |m]-_WaR,Wܛpw)QQSSTvi2ecBqz[0C$* 1T+$1,+U+7 5i=jShxd 7 I088󌞢sC$`wN`1g#?鮫Jh#xQ"D!.v[sB:Z1Fs >v_tE 4YJ3YF_ K MJ_@(WU]*Gf7dX|<`ctjU[L qҹ#?/Oa\ y'$rEoTr@y#8iMḩz[AWQ,:X&;m֪ii))—/͖'i>$uI9AZ<<=%d?<~dJR$5I\`r8?{ካUdn@XNMQ)~p?qqO=%rR*CH1׈J'O8'BpdϞ:/q8$\3'2*'Ϸ `?#}$)dĀlaB'9^zi0deo}@QUahZ͋.]%y1!B#>8箪=4HM0ǜ p?s}K"-_S @#>.J3#QM$SedMem'9,J $_#pk #idݔV|MtE㪮zN rI1{_RLH I#'D)'Q'9H'I?rzl٢r b`᪛S*H ?3e |O^~?9XPȲ=),!XRr5D ch<RXWNp1eq+$0~>@bs2oHC3&7JﵐOM۟qeԳ\dQ*ITؒ%F!TOj5AJ *TPSr6HyՑEYkAQSQ:nq*G8Pc)#8~:r_ffW/#Bj,l($FÓl@7$HKQ@ Q75w\oXpfV _-–T*B4Υq\9l7|g?xhjf 9A9C?۬:. WmlFA5_!qsvsum$ }"gGpyq y&b~xqugjaeQͿZwQ쫎11w-G=V1,@aʨݕq[>9.O3 4 -8(FH).c#kQȬeʹ]JXFƢ7POOKhT@{dK{@9*3ǟ,PS cBL+)<<d ֡؞9Ք5I t :Uq>IsKnIcGq;d"b'|s66ݱɐ=N9#i?#۩ZMQB f?3l F% (sၐ_Ӣ2WāEUo뇭@G#t=vwjղѥ8hG0}>MH{A|x#=NI8秣+jFQv4CXou0t4$Q;Vǭ?zieYb/F?=K(-U ͉~T1c(H9 9ΓKU7`]]Hʃ/Y ['NC ~Rj99דԫ{}ej;- PSP$)Ei!~ά~|zX."qJ݁@av| sskteu>fa2 I\㭬Ϙ9d\;g3D@TR0*,mFb%T-FeݞuFZ''ZCjhDQO<~3ףuCET%%}(RV  ݟH^chMIty) ɂ鸏xR@%HϐG=jQE) W8U4*‚N@20AUGMDI'*}auVih:Rc ͰH\lbp0pbTB&h抖".O)~6w|=0 TyFƒ[E צi%l , 9QA NHʋGBTuUL}I[kp줮@U?j*'HU+tkk#G h䲡,Xn_j~2Hˋ}z~ U^WT9#j.Z7P(yQ4ѽB_i"ۂ OiVBV]8DVD*qcĘӜ|%R PSWCq}ELRc1,h]*v`l{Ջ$^ D ;xKB5P+= AMzT!*ˀ6q1Eiha֭ RJF@}[Ry?)=,=͜?%Ek)2F;Kny'VQ۩/kKcZm[=0UjvRP:bdYj]Tpt6\qp:xo&Sj&w#«*),'dtHz)nQA%#2A_q`X8FE$({?j;{EPbryZ,ȪC;k:}1#(N UIa%5e7VSoUt#~G\f%NEXX$Q0\1GuQVfam,2UAڹ9hm۾>5(֪^؎*gw}C1NI}6*0H*9Q!xc."2Ƕ<rA#9Һ+\3/JT}4oJwe@݂*<iQҚ85PA dܡ[q"hvRpQ~w@7*K4UUҤ+M]"HR[';w*rHn|:`[_"&kmu¢*I52ceprŔ1تanHgSpњ Ga?3pvr$s;HUӖZ:S1c,eRp΁w(8'N3ѕ* b8$PIcr@c;WÜ;ŏ G+Jgާ; +=<‚rӛ]D Q6 mʍ2}Mq5GR fl39g#W.Zc eٚD%Mc4[ȨՒI121DcEE Yh[6ܐ9kܞf 7=AQG|q*SQ=kQ 3+K!19_HIᦅMju -%4ulv7*Ẉi-;O-5wZP`yZdjXeoIث yp;cvXv;L+vK$7K MAQ PWnwQi4Pȑh Sy UCV\֓:*Pw:ƪ1)elA@%A?UWZMZh#mjSrSӃ OjZڗ gdGmnNZkXƄi_n|CWRR\d1A%žyC,qS,AXJT׺-OߋL؉:-UHNk৘5(AO@1]FC}'Gt5FƬ}7-MP6u|XAzZ5KkL<͓y5 RNue3:a$ IUg b2 ոbl+q |ucՊW:uR3O$VE!!bKܩP@^ܻ n] ! a`M tM"FcAQʛ6a֪ԗ}/p\mRXoZV4WT\$q#Ij/Jeeb 2>nzݽ!w1_ Mon-bCCI%+nTYDTo2:E%r'JBdD{&D$PӫUJ ~hDKBz#H(ojl~Ueh.&7(Z=Eax=6VQV$YԍSK扼wp[U}EPTҢBI E$0BQ U>~oOtKY ۹Be5iVSoIe5=A|lԘnpr>zSS^;agmREsX$0)2йx%T3ng~FA386 btp; uEU=K2K#Izv-MӨ)G]nI Lj3cwO#-Uʂ곸u~TL.I#kNeiQ@c_MW)7n YgҺZoUZkVDZԛDCdR[n`Ut6橆DY ;$2mG|p Ł;1e"@dLEYk 4A32TiN F]rprNC=hIATXy%Yd|)`}iPtÛvwM~-O eM_QU=mS4C B3 :,A3]=W}_MuB~ ,Tp vFs:*-0U36rrB9@=,VR ݹU<*`Kt)TP(_ ={`6w${c;iKfn1cDVA*$;P"w*P +Ġ5D2+V\${TJ s[ 18ۑ礲i06GP xsK[_a(]t߿Ӟ]v>REQL$$=E-91ɒ]ϖs'[wpaI Z72100=,O  ƟW(a>nbʈ0IwapѤef 22N@ҀpW zH}?O#Uѻ L(º]H=QXk"4b#p+dX| `8)EM5$Lިl*I\.^zD4U3rXwspw(u[ u G/o{E͸1;#ؐB`X =Wk2C>ZZDa(Ġ] (hmas 3~֚]5SKO$rƲ3SXp'4}ӕGz*[M zjH) #)b6cb:|.+&p@dWYHbS,,IY#-$*Z tvCJ8 v%\jiXb=Q$:WEohZftݶUDy1Mc& 7k]EUu)D ,HUݽ2ʑ:{07$H@ `ٵܐ:5ݶjKMcy&E5RTuV)YcEHYp4Y8eh@"E2("I)MďƼ  #' {jZmTvRl5W:tK6ԁ73Q5=FUO6It*tb>Ֆ~ֳO] T.y-uc*w:EEA.3jndHeb"J@-Bc9/#Jǒͨ}IgulJudNc̷#9"~-N .=2Y'9#P5MpvknQ*-=|r:FK,N2[3IJ.}, jbꑖZ=5 w; SWT %$fԀʻ`AGIK;6]ˉK;`9w],w[RQܭ+ O&d}N:ԩ1XlN:t;).YNHIqьi31HWI8: E$p(;e`2 dP7բq*2  d~:W^SV,~@RXԊlņ%$1=It**Ը51R˜į|@<|E@oUZ6}!tz jpl| jdgԕT2\+-,=uBiU<2eˤVS߭3:%ܠ%rUUX⼽Y/Wk Am0KۻeQYwj ԡAax=;T M[obʊ "L-w ehp  Fx'3bWH:>a )'L,v+`QeQ bZPZ͘@@f1kjMmp7*cn*R]" 4hĈV]e?J) <0TP֦$VPS[fRdZ Qā*@"YE|QXi%ت5 U:1j\GVniWjIE mXPh4\ #43ϙWEƹy^[m e)0jIR*ƑA8&0GXٴbԛQEMGsz'tm nQ%?ݧO`C2mSyGtEQtuXd GOrI+%ievh2J-f%T-3k\л홆V* ؕ2$J8-DkZ1UuumMoѤ 22TLфJYx]\Cͼ49UW~% LpT̊I KG8Q8a;wsl#mzP]5eZ:jӟcoIJT2 #899Sek"+l-fI/U0ص!!&FD*@!7GkgdG][I%%CM}d45ZYR,)H1WR/2ۦ栫zәo7^jX*2H1 $3f "ggPZILāXđ+ŠMNʙp.gL:Yc\PҨC[2a gVO;UWRKF$9Th ʌ?a*,00rDۻ$qA=h&6 $U5uS ̑C1Yc,eݕNsuRkM|_(Q.a`ؾ'+$Mg54}[x2 &ymK%1s+2N/i )pJ* :ȯVٯhF_ UUqq]TviMYUI]3^ZjYJ\Eh[jO缮JPXb#f%BIlڹjj9縘-UbZ .#u @ x[f2X0#əbG&wHyaGe$@ruW +ϙ H +ʒNlq *Bub ~<`~H-W)5If5˓h[hc(=Kԅ &HH ۤU@d<SNdCǧ(c\8:O$aE(ITX뉊;X$v;Qc[mX>GEog wj<ĴH×0gE][U$ci$wp%o$~2:aFSꬋ0!"*s 8Q1w]C= MZ C' %dTHqiUVk%@M fad 71ľZ3FF'|r?qӽ- Ij1V gzB+3Ƥaؑ 1qmxUf#@t?Z<~mJcC)5TU[U)MAϸH}t?z>kI~84n(Φb_UA'>DfmʏqMNzJI}H@zYhBeQ+ #$FH>NslkV6ls>:fcb!ɪ4STآ!R^|qk$lu( uKIApeҥ*+&!v*H#?9lsMYi)h9Jy Wy?FG}syqP ?O1D9妑d7p5pwшE+S{>c)BWǑI:JX'堏h9O|s.@ϦbB}$q֫mahzz[҅jw`QdČ8軄4PYe$m! (qFsrxjGhf|3FT G㤵W*Y@Dy-dߌ|i & Y+^}ENƅb!PPjI{AvnIqޱ$a=0|g6L׏_  '<fI##K&Sl}~MU +tFXOdx2~Gӽ~\TNZj)$1]ZB )%OLȺ$@N[V!؂QOa0*YAe6Pw|A<9tm 8##$`?=wm\ags=:4k+m /9#1yӠ0rIQ tHpuGuK{EeCGAWS0폘3!Dga<<>>z ;Ei  j$c8chy''A SS־O#SK 1ֆjSHPh[HPX ܖO\VB[SXK7;{ Vi9Ul3P1;OهO#}%4=8hv9Ry=OeMw,${,GbI꭮jKrF2ē9>鎦%Li"eȲi$!(F&V2Q"*({H㔬O #qqu%4ca9e b8v%U Ŏ1=D3S%=*cԦbTS ` xH%!8?[H|C7Mf +N@!USHKӨW^%II! tOoJI*iġcaq$$:}ӌmJ2rN |9>zW4@ylƬҰBh*OƆ_֪tm:Yґ02,%`8cR2Y t 11I2 Ay8>s9#E~KMmuSѨRx9w*,9e9+ꚽc I5M{fy#1PDeFw7篥$?[1#yd%d!2ʠZ8PF :KzkLC "CS((㜓Gd*4A vC(W%rT FG"5VcXcpFQ0$8gt׋JEAG'tpmF "v*׀NuBR;)UHgltW^*T'i[m8v; u#Hi@WccU0VQ$V=sRI(uUJBrvzo`0C[$ %S!_^f#'16H 8wV\A,KA&f¡I v%q΅v#'o{%meM1+̡af2$O?Y`YgV8.YtX`t ^99RJ%=L_W  8m nj#ߪST״iz4Mn9gQ"UTeZ2KsOe7`KUYhVoB#P.pofUiH"s2c'1 ؈!BPW+m<kVG| x&`xT'1Ż Odr`-,7гpܨz&Vx[r4D`N a9cIa|p3h,`BU ٻ7!VRTYA4y>c.^kvJLPëfm%;u`ZT;ӷj+!:LG LRpGGYzbKn=(8n3ܬꈚ_ ==%;dD5ՙG_])?stjkt{l 5Jk5j֪pjxo^@\߻ܯjM7~ۻjXsL 7kWY]PC QfVzQ]m\,K'1 <dvY12yz"2S b!4^`B)6* ~{%5u,"BZ˭.U2IiWe#WSwFX2JkZ.7NyzNjZGf*ijʚ)Y (I$bj;A4^:2 s4}RmmuI⨭&FI"T]WCiY5ۮګM^uUOpE=`eyr|RJ|h$,Nc?#o K.ztbhIHfpV6{.ǶUG+}H}յT,{>K}uj!Ȑr$ +,nis{YOEmwm;Yu\lXZ(o&MY= I?! 2o^8WOLvlUW{n ;]Y5פTTSr!G fݮv;k4Σ [ڪ" V?cxdJwJXa-L&d|S03n=&Eaytۨ4Z:t\Ӕ^mq=2K%Jت7O&p^:knٵ>wbRém[i.)YuO%EZ%e9rHcTb!<[RԒjC-XZ5GI̲JUKRTo=MPj!Fjv-f[ӑ"G 2U\ T$db(P$DPGr #8b~4t5Τִ3Si {IIS,z($X 2; <Խ׀N KWNzH6yF1#(gP@%E%I , @P_]i*@;(rē䑞SnAHFR9L0&SH6 "% km|TpvB gjꄗzḎ j^INNpv?.P>{~8]kgM)6v(o0%u_KDUpѵ\"Q= JmX {1d9aNdj7Y=:*!VG =-bX8Ecߝo[ ?JyBIUO#WHPZ 9&2r 16O_)LT Bty#]bAϰ]wy'Z4~TY!Vc>VTɻ  |4aRZfm:]YFYJ*r@T$$ژh$lBG6]Pu77>S}:d4eO$'@ I@Pu#."ԯFicԩU%g ޚƲFhE_U"U㟒:Ug[U0kg,:(ېTvخaK$CӮw!~Έgy 1y?/sQ]RP"RT{9]o ̋ \&^E Dr Fx&z衬!IXf8@'!W+mj}?}'m jln~;DՒS&E+\q˔E. UdP7`)Hݒ0p@㩅efD$$l2Ő6!szgyg7HheZv@dkIevr@s*D H*v\(%okc}꣘-&Ya,3PUJ䍞A<:pjK h*{}J ~sFe~+dg#{C#a!mY 1\2o҇@Y;çB7Mi&gtsp2@>s1|[-EwG2|d|<{>4 B(jLL <`x㦛MJتwPPS,)-cQRb}4ÖbWvw E+5D*щo:akA$njL"gn%w"ꤙ99*-,셊,RFSlq2E$GH!@iI HtMAӉ]Kwje[I+БnbI*}p.;D4_snX"M$1db.@8Dˡ7⍪̫%VHPofܵd98>:lrɥ`v$@%p[稉 7u>:Y IQFYr JFP\vbF},y rnVkc5Or5l6K $`C嶞GURikN}-a[NԶV1j٢CGwx}gmI!ynOAl]B"DoUpc9K {r#*sii=? `Qj! K%*~ީ粞 ƫ,Ne9IgA*L5R.\31EVDQ ԴK-2G[N2(gp,XA$㥐T354BUHJyڋr71xEʔZjMEnRfvdwJ}[STZn:rSK;QUe4bi  O#f菎V _e2Ύ$y'3KHI3<x#J3 -.@8,J$IAB)tֹfzc"drFXm SCn:Ҳ SkjC+X+0[CY`B$Hp+(Tk G%zʽ=3oSUOEcBcMoBdL+H5U5޶_ M i'cmB[HUpIrFH%/"Xg1R>JE)m-i3ƁD q餙US@MʩSyEM,- $2%aATKT];id^[]jh*Um6{QnV!f#}74$\r(tpz퓴&Ӛ=j?MB zswij.& 4u [5吰=TU"r-Li]n-WwFtLD2c+BETu01kt<Ԗ 9o+##?91+ ֵ]%GWjE"7K54U>d`R0#)Q,T e0IIo,QfR"q ˖|&^ I`<#a+JxiyX}хb?^\(di`Ia67#u w뵔IUp1R-xQ 18yjWwZTQi&zO\w+{) XQK=uj+yt :Lg^)ʳH# JrȄGW%ذ; XrE@g lX`T= %E,qMWY+6LP,_{EoWI֪j}CkA-*QGu&چi"S#+0,{lA%9 6hؔerqv~L[M$504@cdT(A[s2#34tJ6BYF93wVb*E  eI*G-?sq8tGr=4UQ-36jifН!svh릲Ɛ=X.6*n*! CCdk}dB а "$0_(K(\i Kb]JF,oI, $djy2AR1h%Ml '1- j$U*ԅY3,2C(nV'WA Knd-pܵ}J"$rG)EOw+SQ^o'As }Y,PM(R@Tx|Ŕ껅UIsd8RGnvOD4ܮt1\n5PQ}#" X$lb[*Z,b)RB91/79;X)a C);f cINQ9˟3O *H 6XN!+()6KydR6 UaƦӐŨHAzI uF>d!u=w*jj-Nզf%0"=S`qhz&-\6(ih8 URTCʀ*"7خT⓬]|u4)F-6_M_boɒ%E^Xr 2 š2l F42ٓ8YbZF ҫRHʀAmu%m<5URʻɷv=Ȩ\Z⩍᫚!Q"mU2v#tnzwʅxR}TnkYd0,O0Ǝȣ?<ݴ5 KX4WzzgWK))'׎ p A9sb8sQKq#Ee3*RθHbX׋ " RjJM1+NUE 1Aep^w{UtFC5iRFTQ32%4]dlY `]u!l/"zhcxeYce@J``-fU"R}y$.PS_{) Jkh&ETlVkUIJiLŊ88˝ $ˬ>ryg%SY,e~s"FYDO1Dn%U85r̶&Zai 厓j}LI ˆLQPCL%ޞPrvwTPH\8䶭$y.RI6 5$1hV+Rnf#Gt!p``u jd|x9x*V(ґ@Pv$\1,Hу'ې]$HWUbEkw /ܥ#Vf H`[@YUS[Q%M\<#|ziۦXkjklP/u欩޼])S#* ;IbMv5-E&0(ǽ'kr6^ya™8I9'#Fg`#Ԩ@F++@%ʨ$0t.Q{Sq#pIX=Yy#WSL%i CDs[qA=W fptS<v  #ܸy8f l$ڭm=kfPҵ-ۋnu{V>vl26p AX5i#`0>I??qN?099~ǮzFmTz8}TUglCC9t; U4s9@W g>22?o:i-G=C%HԼbIQP8F|uwfccܶrLG$N;2NYB " @Eb aYu+(*MYmuKS$<',|O#HMlơ&v.`rq`.NI?w*:>9~zcf$rĒAbAdپ6 QRp+jon6US|䞬 EdFVVӱlBP]{i#r~C]h)0vBM}tIbI'=}Tg9?:Bّ4l(_pdmlqu)?~L0|`Tvf08,JN SOGjz\1Eh%JL%w3~T4"(-˹nHAT~bO${"`\"[`Iڻ#*T=3;o8Lfe+7Q,QeU,y<91ex 1DM5Y'7>: gx&6A 28뇖8#wfc 2 >#::kI=($6Uwɔ`8JMFfS0rO8n 1@KQQVp?2A@bÑ[t$z{^&TDYUjSE9i$$8zIIP-%VR1d;,j(]/۷,}E H GfSA!ijS2xFV;X 鉰:>7Ͽ¶zG* Fϵ 7+m]Lѫd'0c<ǟ&5Jj∢N#>YC{FsF ⮶I6:"p@DUheK:ގJi JzDIoU}cI8tvdpw:(r@f[p'93ZU!@5ZT؏g`oaAߛڃV$Do]E3iWWoWYWTQF@`m!)8~ѳSO VJja +`IK9:&S+@߱GQq[IAU]OML.jYK*sytA^L# i$ᶚ $jkL!bG8=Km'h/X7#GU1F-񞍸 }̈^QL<r9z+HZ m^&`N7AcFsGqDmYm+ۘ)Wa!>Ha|tEm03{ӻ&"f(|qaxeQ q$q+=4;%ALm&LfhʐDhŃFrws|I"'.9I'жjlڷ'8J\> xp!u8$9_#!F\ۧzjɆMd܍8œ*U"z 8`EGیD r蠖_VIbIQQG =2L  DDSPlbu zM iUnu'^k[%r+'C#^E#Aܹ $gx2hl$rz%,jp]#3+" 4 q k&y 6HP| ,a#*A$.y tRCWf:ĎɞJ9AZ4P]%tѱv V~kv [ql~$|NǢ@!Q܄ +Ĝ @bg]+l O[@% DsI9Wa DFN>Mw9h"UJcٷ#&ׯS4u DdFfseB.@ 'b.ߗIirk\ؓW|_~vܮi{mZ悪J aj/]eIqIC%L5 H:w}}M>ׁéhbWE prv=ꒁ4i^F3[&H–AWHFqnU >>{U'ywV[qn;(YRHdAzʹeq|8BYBsfv iBA$87ZIқuqGwԔzK_/}M ƯR_isJUKs-3NZON%F*@[x,֟~v=<њk9mv+\x+x(eoQ۬[{xme\UnS!p lDviZ{G~;GOsi4z[Z{E[!Ԕ8V?'Fb ޝflJ<=:LXT<|W oڋSKcҺ~M~jʊz{|vBN]>C=祁|qK3"5!#3I$%jYJD2H`W c1b৘LQ[;*_z]h_*%ڃF#[ki$YđOK:<$IJʥٌ R#Kn]uGNu֥k۬}54Z^fL'_戳wY5-O-eYqM,k*v$6q:/]]:DwGV6i+)]@ӭ4/MC5 R"㣗$ GaC4pFRRTAXi7FZ`([!#~T0 mv}Wx,Z-ma MQW6Zzj%GSN\jZTJjhY%ڗӼwKV}v [[=4VځwKt}q)!YIXDH8K_!6U[Y]ճֿ5u1T)_rflz,T:Z;}`;Vh^jMK55zږey 9gH4JJ.o|G&eLSr)Zi֋UsƼ*P@ )\Ta@Hagsu읪kGnŠ]R.zmkI5TXU@Ӎ$LO1 ı,TWWK%֒YbTO$QMN F 1RWro$*r1kGEL1Q-u"ޒ倍AeĊ[hєL?beT]xhxi$j:Z6_^Foq<447!XTӬ$nA#] TW`R6Eж I?K=F = W‘4*xbܸU&Ceve;|=^NQfwl}U׏KY&HUQ%DBX}Ǧa2$ሓk2&\3G_2&`W H8i PkSmk޹!A٬:im\v? u.HX4F앥<Բ?v]};v%A@ c=7U=-SEIXUr6X iZ*n+@`)=#\VPpxOˑM.`q8{U{@5\tv H''9qlpD<:u5RN7'*2䞡pMPreI`6 A8&`57>ېA q:]]_k'Qe\-O`HG)֒YJzHp9;OmT,L^8I>9QVU(G]21ذߧN>O׸ۋďѹ[e'hQ;ʯy]<Ӣ2FXTU o Xyy=5}THfs7blpsEMQ,#vYGʰb> Ys=yKny]UCKD inH?r DUsRi*'Jx?feƈH ꚺkˤ<]KK=R/޺cq$ EADx#OEl,mƜ`*dw/>юy],6bP̌@aтM:u{ywu0b#M*2H$gUC`g)Mp6Z֩ƩA p(frT [p)ZG TKF ,j6p L,Fz"Kڞ- 2LT`g#$q$9O-Rxo2RP* Pe`cL2&[/"#K5I$eAR iD ClN 晴U$*Z£j܍ 58QJG(Vjژ.W!Ef"9T.I4,3tUTeHn~M+ I3 '`7sЪGtɑp( lxjn4ArX^DcWC׽_YzָncxL`ڷzuQ$9 7# f-65HW&㙑5$d0N$dP3\,TRWU-#RRW`XSP)j˥M3-I%XywzbV@2w {1vlL)RfYkH1#HZmц5k/UPc <2H6$a]]j:*q=,7wzYyo11QA{i1,d7z-G׶Cq5aKYa G v.WzQnvWL-O@-֊jdZYbEY vךIB38w%]4^6Մ8J)l":6eL d~^Y_˴YhɕuɈ /bI%*. IUQts,ZxH̅#R$,4P+Lϩ%siJHCRJf)ŏy tC=-K\ar/;E+rލ4va@w0e/nlt1Wjڊ-Seyt{^<:S@eN1s7mIhr<_R$VN"Q˪ڞIa32<4DkBBXRx䫳-7%qWMY-QHشDG3TJ-Ynz.Z]3Mw{O%Het)H GPʍw}uZ;vJJeJkUuEY$`ǩUWv4%NՒEWPS/X.@hx[B3L(8fÓH֡|e,IH64K:Lg2@C il,U¨UL^k $5v*jp(`DSAȼyGatSaYh"'ƍVM+&C.u5R_W-#fhc%Xڦis#XDGvwOXwJǖC=-Lh X{\ OfFia&LOb_i!+Yss^e1vma cጲsbQYD)+[`AqU gGk>== ޚX&-*bJ3h[m]X Z::_L}#ڭ1ƤeV0}z~Y(GaLJvjʚC[Vp Y*^Pܧo9=|i7--㠢`@Ȇ0o C|߇,g%dy|jyB0f3VXg͙2Q)DQPH6D(P*Xm\:_LK=aF]4Q aB\pXyk;CV !kztzAqWghNW 0xDΆvpwH8R@giĤI337@P;&n䭎=Bv4@$7 bEW9be"8[yPMkQI%W"44KW)N="Ʌ9d 9'qv2V$!l"aS%-tw8jݵELWPiꤒQy q^%KPǐꌸ[tk'U~裎sӘedaUZunRMYiF)m#`ӯ m$.j+~bԙ"C!SC1E$\/ 3kS9A,E >@)4Ad-~^QD賉 ?)x!> j`%kNںJ ΙkmCttu>ۦFHpq#ZHhz+%=Ξ=YM-V[`3m;Eu%F@ M~Vꎶv׼5*}0|۴̎L,RzSeֽ44כ :Yu1%ls,g[%3Yة+:ʓ93QgrA2!V9aB$Q().ř&Zw+$X 6*1.Z6[X#* \ DpNQUE}F]pAEgf݂##ϞO>֖-4wn(V+++PJc6PG*ki/tPHqE-]Įs: !ֶOFĈ,q"V"cʅn+dN@MoUt%UCGVP0PF*7)8g%~+n{RR)%WUȯd 6%rvs9=)VI[E[#yLfޠ4!R Wrϸ㬸X姌.VYO sJX2hݴ@4,dDrHR5rC( $`ꡐ(l-epiVnvz{]EyXYRҬ%$/"e.җ8tmwj{(ZrSB45UU $-u\t)Ev::ܪҘ<z=yͅj|惷z"F)BAC,`p|rG1#g2\2s k+ dId,Hҵ6-eAN3S", Xҷ2BҨQ#j[c^^H.~܅cٵv,ۙO˼1'+yI}Sy1v-+!XOK4& 6 6'>TS#kP6VV]實jxP|PHi~]cOX'ORCEs1ӚǶ$I_L2@Yq+iOefTo7ұ@%jJTbM 6IO$Į\HM&9j)lQtTHT8E"iY7p@?i{,:m""(啢$PA  (PR8ꍿ[4|T lWhoT*jci qSNN͌)<LS-d246ȡYps?4r#/X ŚPϦhfX)$/0 IFe;|њ[GF*[֪CiatbCmtԴ됪]%̟cNLmA` 5f^כGQZTJw!W.Üzn''8NJj=ҩ-J  %A'%)V"$A,"WHLz1((]TkЧV]$͆8>3kG!R+xcb6{O:dW!(zzJ $?u,X}+  m8 TxqϞçd2%#f]^-h5h4+b+eE ~`NoT"#'8|>nfU\?G:9 H (r8ۑUT* l+ۑNi$Y'o*y )gA pH1yeEbK'9?>-cUL W$_>9??NQ5q|瞤P4!EwSY5~O?: b@'^dJm x?[$j~ <  $I:H&(UF㞾+C,r7F둑 KWqnUA%G_ʱؗ"@*V̤:b lm\V pGCME2Sā2z>b y 4hn(uiaBn`P@?xqtΩ;kv` Ā(QdH8?Fy㮐3FqT>Dl9=X-Ps J#랏`,%c?h}{Ԓ7#>|ğ_:!bE}}0,Wt:It: Cуt`t:0:F 6e<%VLX)9Z=hUGz4B>\DN_ȡ99LYe<⁊&`@ٮ/W;.ѮUYCtv!GЩ1rI_lV}%Zj:XjeVB9RN$Np.뺸⣦e2qĉtnlvTE>'AaYi|ʞȢל)szlò@&nh%bjMZoz:oGz;SO[f)")ajFq0 R+U|;Q] z2c"E2ITJ0\ sbĖbX$'i& P噙ԅЪI,H6qr5pMP1nUro9 T>Oq 3ΫM]>ؔ.2p>zmڊѡ*%4%wJ( Hzw*(i%`ƼIN?I{4I+Z c+sz?r9̙2A$3geԍJ$ JoM[v}BQi;ձ]O_= !)B¹ ($G^j:vz8B l#h  s@r5?o*ܳh,16gxN\ڂ]U,YjJ8 eH Hf. {|þxtqa3Rϛ4]gi+AF$MN8` Lm T@~a-TV$̩#2I'*xlO'TXB$T0$vc $9uWD8 ,LAK`8烌0$n\u^'n=v.9#82?O#z+Ў}ypM/^80u?e /2Ȥ29byԦ,Jh=DB L $/ #-=Li& QQCm$LJ$$ zU;7 Łl$ԁG sGnzl}pk۾WMiOlV"#eT9̌22O]YFk.C* Xr #oyjk ~qǼp*I<~Mh*8TvpqE27=H=g-^9Uv?{VoP$1ۙD$P@'!RG#y1ӭ+53,J72Hg<py$P٧QMMDegybX@@@9ry3J+U;-OKec Fy9?BkW( 9ۦ;=jK#S[$oZ%J; o$ҪϾX MK 7 I&Ux')AE0 s<n2A}1r*,Rڟ; ĂAmCm}u7+p6|X{E+)m-;ӲndD9ݳ*įf)wةXj6HR cఙnO:lIĒ* } wGHX=i]{R3Dj] %L6ij#J%iL 4,414O|W :I`@ӯBu.,e&E?gZa}:0I@wm,V m׫"R}d,;)&+WLhib !A MůiY۪]%ALOU%&E<7Oh]*UT=3;/qLv7+ oU<_;{ajk$mn4MVD%܏ *Kã-{s!4םAgݷ&ZxfJzuCCMY-4&U7<3 ox3ey?dbb af!H:,\Ydb⣑!MohE][ іV2E8hTm>[%C"J xP,TC/=5,$ϔFI,ŀV(KNՏE^ɭ?S򒒷TgДPOյJkMʪaHb4ʓSHe'1j^w,=RzQ㹬}c;TZL Zw4I 'TMKܮ}ojjhãI*XTf*UcFdV&TuLP}f;GAkjZٸRE]Wk9`Renp^h0+(er>\f+/ EIFo qm$03%R"H(Vq~ۋ$cVD^j+}vMHjWK*[|ʊGo$Tm12ܦӽZ߿.Wk'iG]o%YK*eJ̋IדR+}Qb^kK徹p3W-,,t)Hh'R}(eT}ﶿ՚馥Hݪj[?)nWlTMMM T1Wx+J"nC<:FƲExgK?lregHu)bޑ~qpSm*'U[1$jdFVFa{6S v֯vڪREUR3h}B\jH`todiv>{Sk^}KC;?܍=:~jᡴu==>h)u Φ٠JaQO U4NeHT S}SV-?{tH*U]4R9hGwc=.x핓HUJ+k;9l=:r4thijbyZc3F$$ 17UcZCM Z1N@4O aT>Zud䓵n/7Ɵ2_5z˽(@zhSMNr6TxKP{ۭ/b-ũ1M;Dnu~ oY>~4`SFBOʻBϯn.P@Gxv<:(ȹQwFV-=h}H ˕v#QV00-8R .@#qN*ҢԤA#!_΢B Y]Kb)>Z j?9Qz\3RXUfQ PRVO<⊥dJjDcR FN$bT;UJq.A@v>LfuKQ]rTBIAn;H#n3t@&ɭHwzvMm,{VCAORwO 0I^>Q @U"7'IcK (`:M7;b%\3D=0лkRFb#Y's3i+ Q$S"@W*O%6`8H6 wڶ/pIJkfU L $Ne~㨸K47djt+H AP,$Z=fR d*d&ZE,ņY}6^F5.w |5x@ bʀH^nob7qǷ?#VWJ"u`ހNe%@9͉4$vz;Q2Z- (g1ڄ r, )dF*p= Q2:ܩ`&j*6u~!P6FF[J*7ߠ =|/Y$֒IӸ۽ypT :dz* [+ B&Q$tl^eT@w&nAFMM= v KʇOol+XBh}y(22pAQw.yH@,c{tBۡ4UaZ|Y-sklUATvbp.npIA# ڄ[A=reX, c y(s$\tԋC(ܸ&2c'C0C; TVMX{#sy} @**MM {V@ , #3KedXr=88aTQ#3c29b03?~@ꉝJ4 O[x `, vrqB`QTYI+> X* m. VhVO#?P7 Dc<on?o z]5A{Aߜ0kkEe_`zbrJH\wy#/jP4I.s0#bOMP))(ҏs `s ;V@r9'z|k2>_r(A9ʵqg8 w;]o1OAr]'D'!Gsӵ.[ey ,OAUz["Y b$%sFUX/tYe̢hL{ `]X8۷ϐ/u]W=nAY]CITeZpVR3A`* Il&j˝Bb#eۗߝ.ᓿ+<Z$S]K H&J\cf, Sjv?jmFYI$~YB lb/z]0( s@{sֱ4zEUKEqY$o|9N Q;̗SFH$8vTq#f 09QMf,j[m M%]]Ϊjx!,hb1pǎx+ȅwKizhM\Sm#Ssg1v(m 2Iyx輼zDQ.j R&`I ~a\$q=7MGW_GIG4Q܍ʅevu#JC̪qo NMCW4CS=R]W\7&g` 0䓁߲ZRb-ܠϵn7 G*R\*gvNbvIZ2&zLIe2$,Wjb!܆8W;Be!$8'sDR22 ˎ;Q@ne~]նwO@C:U]eȾ2 ,s`H1<3w*k0C{[RICnd, bw)FVF,W& +͟cb}CkZ& +7*[kMp]X(VvBT9JMmY6lKrAKQ]DT; ['AQ8)Tei . `9.REcSlZ{8iS1L%) fh*6¬I+O1"mj߄L2JGF.VPv`-6H2Z՘1@4j#kwSR]~v=;GƮj-V -8EPU5{BXJ`I]_˴1h:kSIq\nm=h&@hզrFOPp@uVzJ])5 Efa(zdMJuYO3#\nQ+vHj+GwC[m-}ƮG4vD Iӳ  \Y2G3I?A LE3j#3@ZA,Rd 8e2FxfDY|Ƒ^DBΉ)|Ski{Fu[Y7K|HC\ʏ"E:[v{FJ,S]^L%5H8D*̲EVL"H׵z2-=):5{4ZJycy(3q` RDN 7xd$c&Ո?2!5⯜98iϙwl%hǥdvSEtM4Ye!Bqv-In(i>^5+n mSfҪ5Lf]]REriZHܠLq Q[Q<YN#ڊrN4lTTTF$hQ"Ʊ@M+QM*T*rI9 ߅V#aI);jȤ3L *xj}Zfj ];G +]I܊X@b̚G'mT\~KU'0@` X_Aq <mᘨI!x覣JǸs*vqrAsZck W-$hZO1 44 Uۊḩ TQB1g1?RN$?OM+KL<2F2=bC$Bp01꽗_k{YԦjWHԏu 4ro8`I4R[}ES& ;^ dƲ@,1iFinO\ijR_26PCUKC{m"?]0+r-hDq*/,vK?prMW,zzk*MP1QTv +}ꪪ-qM;k9d*2yqyElR-%RMIT-X *| V;2av, mu\3=#Z qّqtu?ҽ>#]d랇Ifvë{C0`t:CUiT7?ߥuO#و*H(+R,Pɽ]@︽i[k|0:c~ס<;t`[ݿ$x=Kgom Cot:L.Cڊ(bCr-y꠫tJw,ll>}JK@ Mz{aCvCAt`t:0:F CуG`Ⱥ$_>;c8䎁9$z?#zҽ:t:L.:T1G=t]WOX֨_hhY]TFwF#,@G#[&f!ETҤJ1X՝OGHMl!T7RT[t:t4i z;TTnd%ԪI<_=ԴC#U!VIbWڻIbA_{KޟNۨguduXEZQ$WFnr?Qw= ԙ$r8Ϟ]`9TܮnR$$XXJD•*1ÛXdt!\lO'ђͤ)QF0U%T(;>c8&]u] e]}UDS JT>"'>pT^H?y=]ݟzV^b&&I+3 Ah8OnYbd˴1ŗ!+*[Uy8e|ĄG[4ќƣTԸꫬ4ڦzWy6[8 9pC.C"HL QbĵU2oWMQ*%Ipd7J pI=9U*c e/ja$Җ!pÌ:]I`*6H@<Ơ5cJ4,aF&?;b3P+ᤩUv n`9{FDZ$S`3et+TP* "NSXp ,y$J#ɶ$4M2TF.gԨE3DWWo|1OLZjgZgZ _z,Jc}]j)L`ʣf1 npbA玑UQd |-nB7HF0Ksw6܌ tG#+HV9qRM^zQ.īHdb&ݫmb!*6XJ?0H};,jbza/y_ǜ9uiT]l\zuϒK;3:Ccq7B@8 ؍=d ކGvd)hQ(eAāIp3N$8ӊA7 mb 62sUQ5HT<@8Q!۞DK GNM)fhfJ$W8#(ۻJX̱ă[(SqQ@!g7"}}̪RS4J%)%ݕFNxa L |WQQt;KK9ېg$ZCY:6ƀT˹]|sԮ{4p@QĔo0r6xгVf,9  ::S 7|hoN*Lj+!\TDdޟ6Cd'h`IL55dIeM6{.@]n3XRWAUFpcСH #)$8KuԘLy"f # % Kg|<@H,(n _=lYP@C̲uܫVAI,Y`q!6Zh ,$*m \dI7ZԉT46}8wnj7\⤕2F$*1I֧RvYUOP=ӌOHiI6H>~6;OaXPM-\$eb/Qr$ܻf=q=}zJ-֌E)1vOzwh0WjRs)M@rp3_S1( !X0{K&'15zF@kt=~XSnu5j.ҤHIPBd`tq0ST< 2&+Dd+z״I5MHU nHw.99#@]Ǡv  00|UӷHhJY=T* NL:dC[d dW]bҝ Է*W<H7C' οGnzc:BI{QVj9s4۬F;|qkDTӟL:DNCo` Bv8<mn YXnb,ҩVπl(-pqybCLthG! Dł AH Gu`A] ]Z K-=QruXTmԦڮ$޴R[kiY1 ןLGN5ZOڣSv,-!&ݨ$4jbDT##XXf@:"c-! J[ޛr4SMI?]%MtuSMWAOMU%!Qi h]*^}ԷvcYk+ž* H.OALRYhkZƥ y#TR6^+4ֹIURV.ݩ٥4p("w G1'ۿܽoԲ}yv]mSY BemJSD*ON3$txZϖ/kO |дz(azYlNGEq$@Ju m7[{'YUz;Mo7#=5Yh@%A*WEC#H ^uTt5=]~zU.VUl eC.Eh]]kQVR ' 3ӴW'=_!&e F9ʮ13m,'H$S?#$吆8˄(uhPB'Ak!X$QH[@[gGl)sn{=h]=k\TV}R2apvGoh'o_PNԝI CSSn[ڂ T%CWPw,r ` W4w/Dh^jF[rdհ :mtkm=llޭTH)Ē0ʏ1!SѝҝLhmVnڶISzU\UڵRYj#tc_$/xՑ@$DXݛVr іXJSS'k,U ƪ4Eo:t N1&;ZFJsC&.|eO6QTT#;Ki#ڨ@U@,0A-IiDeT qQr6e'g]R`h:m^HpJ; ڀ^z!AjYV `H$c'r:%j9L RIc|^9Ꚛʾ¤wv0'EwIM$Tj/nXRO(V9`b ){y徛Smn@kvC#!z64U%c6@W( Sӻ`UG)5V i"sU$A&e<9wdi5q<270>3 #9>:׭Nj氷B58Sț@xc9 `I*82MRUI6>؞2?3PHzKiw ng'#=*ic}d"BJv ;dF F+zOn wOJ5z;P75 'Ďhǰ7`UV0v19REfkXK\&{ ({JR숨chue*X 2y&L!'h91#7Uٕm[(2A;v A{BCB'_(sS55kAJxV*N#3`9c8顡HSNr#*w^#Aa.֍Ks)ARsPVj44l!e! NNss҆[wjC۞{:{=;bҵԋ4R:z~6i]W%T䃂xc6m7 {C1?gb*W0#xᔜaTc=uD_q&m1,0JOKfQ#W /W2eu4ӥDX̵,TchFӎ?SDqiaUQ2~s:`joXdIbQp1V +W~jۦG6~g)̑KZĺFÝʫ''I)[W6jeT40D𴾘&]@GǴ8Ũn*ickzI SHefP8[xh'@s@xPx9Kw۞~߸<0Qm[qGJǦ&W*2TGRrrZx*P*EX8X:&A  ˀ2x:d6fx79I0?au& dѨFPjX>6 98tWm_&P}R ݓE,1cy䐙'PԘhzZLB5*3b]O`aϏ=6RkVh\BA $9'<2InI#sA[<V lH)E'$􄐤$Y/#z ˲Ւ^QieH )@نUFTPl(juHwB&ݿr($8Pcsz*$Ej$U NGďG4.1ೲlq0BҧQng攝AF#jWq*c[j?bjaY%ʹ$)$&ӏ'$ cdRI-bw Hav–?yzRU)42Wǽn019;uQ'}26 F:Q4I@ }_[PlONտK>(Je.vUw ( p2Ǖ$gi*d"8HH8,y!1j(a lC6{OFAs秹l-|tp4Ȑ$"9BT*x$@'׸ ׷N+9j6<+ޢ换I4zhX$svzkmkkV N1:mڪp&*+@hUa!$tV^TߪnY&VSQ7h*FQcۆlzg1ɈdT/p82泏|䙈rB3EYK|Lx8A rL5 IWMi%IMj UeuUKT: ;*IvN'MRSUIC_SqW(ξfu1Y[e;9Fs5kW1G 6gw# :UtGb@8 RᏑ2y(i D6ߥnVi.jyTݔEa,! nKti)TReI“Fc ,>(V,<9ʂ; hҳ %ޒXRUxpv[Q܁ EedYLmE)ES"(UzFS\t7; {M*v5OPh:tD6PI#S zK3gh,H<0r9۝'ZbrGQGC2bTYf4Iw',Y=%T40BޤUH-#i6Np8窧_)tƊ;(ZuERRGXU+Jcd ;L^C}JfC#u ^:"AI͂^*jfI-fēlH Z8љO•Cg? *Lx j9Q%ck̂(GȉXSp1c:O+iEtWJ٘{n@A,NsvFfڋWTiՔQ[qQ&$!*S9δ]k+e"a g # ʧQb$!$"칟u;+4L½_O/+Yرg% .6~Wht}(E2A@̯4Hg! Hu"[hdfjGbbC@ppX6>q%0k6ΐ6XL1ewQ(4[J]WL[%ʡX=.U2/_#Dy9GEZ pAfEWQB/IXi#T$m7`P"a1BJ\{<$T%i5v5D%=&hl( M5TJJ%!!\ f|kI=\5%+YJĵ4Y|r0F,ORR?+ j*+lAipy`wQ 9q3sH8"(2b fzwif ہ_ F^+~fyET]PP$PqBڞZ)}uI"V,ٜN=('2Elܤf-wR4U Ք6 1mY+@GZ,(]:r ~v(ے> u/TsEoOoJtINUn2lI>7xLPA2!X 25kFAiM`HƠo䦛4!feh– i1q޵mkM\g f̻Tc_N%elK XZ-am3-EPHGlm qƥwl: X,#j`IK5Qh%H+(܍e$MUUYm7T ZZX"e4+OX ,C#<ٌg3-Q9dXՠ`'SWS;7-m3P/V`R5bl)5wEGjΦPGQ_uhjbHZXa8ޠD#QJ4x{{6*]H_k%Bg2CQȊT@HrG]ImV6V` t0$P ޢWL[g>`Ҳ-5uLR%K&%A.gwWhXe.GDם(67䘀QAyV B23,lRbcQ@o ͒t+YaF{.׿z;VZY$cEo;Dpf]3- qTUQY KO2KX NުQ($/AS-קIӷ-uaSi=ೀ3:--L*P5D!RUz #;vr ;a Gg2y4dcx9'3)ʗNlb;z݆q敒b$@jU!m1 j \Atƙ2jUVčPv*IGpZ"z[EUUvzZp&ufm !Cti9+TM]v=[SC n$vRT\&pSW4ZG  q>ٟtG ylYHb+JKEKV/ P]VP]{B YmV&w=Y 7GW-JSU®d) ψU %>WrhDcMXp 09$L2.gLϖ>$#?:̗z&H,Ec+2yU\r 0*Ft×TH26l3ҠPP%v#H䰻yI.#M8V(mPQ52A4pgb.ӢRQӤKq4$Pd`FON4tAv^yV9F˒j%0P ov>ӀҿJWo_ГG%\G 5B#M94*KV,^,ęi3cΘ$j Kyi5a4!uiNt:rt:0:F Cуt`t:0:F Cуt`t:0:F Cуt`Ry?·G1t:0:F Cуt`t:0: %G׎X=O4YH_]#`A#?@ŋa Ѯzao V-<*pK R cǟߤUM]36ՔF*PpHO]$?׮:sbB3NJIUKv$ m"#$,aLuLHĒı9I$v%$䞇9'aΠff$'rI& pÏL+ OPr 筑{eӰt%QO$s%Dɔت]T' Eq3۟=MPМ!9>m7|FlZo/͑V}(hzCUIP&BjҪdh;{o`}!u.EEYjSSL@=c$|ddS5 ,q>9yסuojjI*2;")DĕP':=҂uQ2G#liw0bG8r9L~C1Yee}!ke]Ge }4O7<|mq| p' Ziu 4/82@zgy%T3Z8:cHv6Jo"㜐3րPXAYI;mI,4X@ލ\^_('}Dֈ6x_s. qmAKPY';' HP@[-,2KVRR]%Em=vlr* $dH8$gIIoFt "1 @DuKJbdF=@`  m'rLB9X*C`}#WSڠe+Q+#;ap==c1ڊu=;̒ OUB2 Kc%#8ۆڅT#Ӄ Ԫ(EpXAH{hM^]7}4ji鄙!6 #=.LQYdڀ,ǒzj(g1̬ t*## '<|-q1]# gVeST #Wc'+{S{{-$K%+HN 2]>H'90v-( vR*Aq! UWWzEi_, cY[PgX@#$ |:Mdwt@V4RcQzց'X53Yjy,K9mʀydc bVL#N9߁jۅ բeT{v* rNN IjSU]qDe1 ܁pN:^ (;r ۦln&Wqs`i LE*x f,[OztkPvx H:G.QO7,JpIK)AQǖ=5hOFw!A# xr3Oŕ!HaZMautYxvhl" & Uzy8ĩPǕ?t&0'P䒾dVrA}/qeFUf; r $XigZ!jۢ^cc٪)lp8dq~jcP[;ȊL,s` hbƉz$^=5Vʬ#p+F9PX sMLՎNY]ՋFX`r8OG}qU6YM 0# P9!JdQF*#@ ;NV$vo*<]U,P.ϽtI]⊞$L(N}7KSQv@w/EF_YU\Ғm6Kx^H$Y2HRV@mC.ڎ_ժ(͏ENjnՔT+;d!"_>k.ITki(s+n-"} r:f"$Idd}YWe䯟+ Jʤ1W"J(I%6&4o4ri7{yQ%I&x%r@U z-=÷V;omM ]UA^)eua2FYFSkaA)X5%-B&ۦO@4oO5WiEd}E$^Ѩ,;3fj{׭[kXݮ5TqUPÒƭ0B:fXD? lϦ0K@\/gҷgz \G[!PI#($ -|r0~Iz̖8]RY|); \dc#8:}-MRUSoft ) V@*F%. n2δKW8dP t;3cACD@⅂ oj}²4铓LtѰ.a[Qn5KtPۡea+B.3>P  :U}VZEpC}q>8'~'s퀎@;Qy 5EM@ { br02:puIVՕ;JS,JT%<g`:Ix'6dY*UpČnWhzi{|Tm,$w8 X.Íry c$77W7c{(sU[^mvV(cЀ̓" F6Tis,u5 `;Yb>FG) 1 7m=jNjHP}: %VA21g45$,JW\z)22CI{=ZMahD8__h]E4'Yb)rp@H\*G㜏Ii᨝fHZI9mwiM:+S8'3"(n7ؾ|4vM?ȫaմۤc;b6P71xDc6M}JzI2K#E'';0awcoƢo8)dAb(gP܁]0"鈡JvĂYX`y}7 :A|/^8զT>}EϦW9'>6dˑϒEM4ũ! )R vOdž|6wjZ917Q݁rGJ~+n76yVxAPllg UIUFy 8{$oJ I}N,,4ȱ8"Q M3QG; 8bv>F <'hw б_;B;_5ߵm]fZv֡VpYzJD( ;s\v( gVJf1 I0I!@(=ij&P*0(ېyMĮS(&SLx ySG G+GM,FA''2#<:`*G 7Ga}];t#:t+`2p=dd IMf.gۜd(byJ 'zP1l+sy='љcرAN8Op#[Vv^oZj5JdHzTXw+38KP뒿v.6WhsIKuwkkEA m2]Ha= U#HpԦJ,%;>}GtF#@?6K]8 hbMT8$I5SQccu)s3eZ/˕YmYH+\fG"J$-J)E|jFb_:iŢ,~G`GOKC(Bjfy>CaDUP$Cd,4tTP"/Mx]Sw.FG sL5E(Փ& rʧ? yh(ZR &:xi $PAp =_V#/X—$zV+qFB:dRrZ3$Iܨtv.Y(jԲPp,oMi"JDQLPBpi&رX6=t541&$mG(A9Tc ٨̴XHnSءX ފKpWuY9bɕ|^SjP[f5 fD,bU̪H* 1JwQD#ҚAbQv>]cV^"GJgaEN[kb"I#xI EpHZzFdqOL#KUAU)h,Ԓ@x|.T_+66J:l ifq,q̀$XTVɦ-ؾ0h ]CWWS5_*Դ) ؒ $d&K% ]2T`7QuUΪ::$wjYق*b.E$DњSHѢ.#FX'MD+ux:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F CуʅǏ箄GE:PUUW C[@#랇C`t't`wXρӎv1Bn|G*V rH9?z]m=?\3KqS㟗nzE6ܝ L~ߎzQLc9 9?_.]A: GgaǞBv >1`c U ` #~qk#lO 2F9 3#<:!m9>Ku6Ԣ6)t 5hPoh8) R~ZT`EYXzY.HIhBs#$_`991jj+j˃69Q0?۫nݛjmFࡲA$#;N621{!怲В+n64v;?O. I#V:رGWc3WVy 2Lʇh*=F2I3UXE4fGEu gk¾u;P3sKTas©0cd'j1wZr#I;d)6`@=kE4s/A& UdB4+PWǥxMOS"GUxH#ˆ!FlnUI8?=IՂ_DJ ,hE\epp]_qf81ʱ$ rqcsuQUm!4nO%,VbqI % ܌ƶiWe)$(P;non1 3&X c*H99zGSbV0PL%42v M gJLi4&xd7lu n9OJ@Ǭb%j,ƢX4l 9zʹ:vnv Fc֫~9 SG(FfYw20!v?םJ H}u )ZpCIk:Ƥ2ۅ:xd+T1$pJ}޴ߩ}''o-w"Xn"9􎫾-}ںINh('Dʵ22v|*]DTj'C[KfIj{mqPqQH\(,PS=㎥*faCxr[`Y\Sbb" ~F$~`-4k?_џsSPJz[0X e Y.4y@ꌌGڻGWAhݒ~} rgY֦p4h**gGXF5CGDwrh7~p5 -$-5B$#zj.mO NzbLhY1;{BU!A@)XGD6 ͔,Y#hIb!ׇu$--̴9fR‡Up  }Q<)8jpklMj-C$?׻'ISGʉX_d/E`;zEwzPmm;EֿXBmCo;TpN}6wI5/67߯k}8V]U{nWyZ3*zb@F.TN5s;#t]/L r]-5jt2E4^*:ʤDK|oBWU')Etރ$䳩 _'.k54u!VYؼ%(U&ܐF֔X'H-<,kE6+DF쭅n6w %pGo40eeOqMOv:{{]ۤcEn4:#̼꿾zWjMij4WgmS]A)ܦ޻;Ubd'h pWk,M,j#ue)erİJqˣŸ8,W9z7N_+ e`qK0Y[\Yw]tG=>jI])ԨdCt@Ulw5f[4שn[Qj*gZ)@gI^"Oie+[e7jqR8߆`v]p0[ieZq4h0vxWe8 rHSlVg"T"G Jrx<ٳv8hl1T z|)K´0[h`HEM\ XсA\@'ϦZJ{!гL7ut9iZMĩfT$?`$0>pO քJZzZXg_M*c0 %<`2F,ۯhV64A_}M;f)䊪&Ǐv$ r_-ci2V 7#3B$aʨ6rBj] d))Fc APcr8=usL;eE`/@Pc,%, 8# Q@o~yq;PgZ-VTY[Ց=$ 2TpH`+V=C11N%v;H}>hr9RGT#VY(ZE@ h+9o-1S(e0UA+mLʂDAdr9=)UmK6齐EٮxsX'M P= !d4RRP!f `ǜgj.U5 x#WgyU!T ?39,`#`Fmp3|yZF{t5n@d( |t+*PaX#VA OPj+:~ eU4 4 4J(ioMp :01aKj[穧SVG4]sD%LQ<ߏPUA#$u⮶s[O#1˳v6S(S@ *aKkU8'DX,1ҁèQJcBP l٤85`%ղ -IL3$,w(w,yXbдv!cʙC  7}}G/@R(RVbH(#qnb(8c=SD"neo䃸ŵ"ƌ *H$U,[BFuao4SVw~,|hӔRuȬqN^1 IAHid p<2z"B %P4M$1i&T88# +mw X}LԁxP}6r\]Ws } ;[Yۏ|9$ôƠ3;ӆ$4VcIWemځ8p#q%65%0=c9ci[X*n$o긳8`7wu׵{8k(jTNe\ Jj~@ÿ"Q.Cd F3:n+OW5%\eUBIH7Lڕfz8ੑ\mW RLf> W]}ը D V)PQFq4 ÃgQb q86Mڶ{س&K%j2#ȢQ!22'ښ"*,jbYS2lNWZ*z}wy0ػ[$dcG, ܤdZiGr'nrs<ך!ZE HX'r*kr!- c> 'V)ZԨ*BQ+ %7|&s*cbڀہY򡞜?UIN@ϻ?BvD"@T2?А91]=i}#Hg0 3sH7)f|O>:^5|p4CJb2GI 8'A|iL馚F{9$d^H3l4חcve_8 ~/jŤɗSFPin7;l+-:#:fNJ 9tI#B_iWۃLn>wuo:$; ؖbS.Yoo,N0 J/:֕{ʂpGA%c,c>3Ȟ9i-7ȑ!r@@@ӑ9Աf7=zSVwY 0f%ǽ/Am$[ G;1 {yc8\/r@(e%AS&WbW p5M"z;ԘsI~_n 9aϴ _; z'|3?.ˆ վ۵X, <*]OP@1U$?k%kִ4CG Vi"U_i>q0v-MWՎwi7_?6+3M4jGuUl\+)ۻBI G~ONQhB ( pܒA9fLecpR(g2H™咮VvH$#JFiH!Uj@PQn.nh@h+L54OK8iV89aޤCpy#.Ѻv:;e 56LYÏq Qr|:U¦ec9Pmʍѥ6N4r0y$dn#ʜͼI3,hP%=R5l Pyb%vH3iV!K0PI7=pcYzږL<1"$`DQ+w\1XǂG9;Ts\=mF4#*ehԓ  sVo 1fU>`$Wex"-:y\Ku¢GpqC^rEVY!WH$stquLQ%4Q5jXҡ3nd NpsύePFNB4?J(/3E1ORA$Q *|ѱX--W|t@0[7--@J= Ӡڲ4%e,B$3[+i(EBIMIuv'^Y3͘.@? Ή ,#q,cmk!RZxŘʪj%#vc1$G-HP0=SQzv[޹+lQ Pbff%QQH\M Q|껕U%V;E6a X5PDeU_HwgP57kޕWǮKX*b}՛_З*aw^1-Kj$J 5+NS0iہBOV-,1y,ssf6pGI!51K.!¼_eZh f4R|@6|/P46O1Q#@,#vȵֆup:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cу=u$  ϟiqrW-֨8bۀc<F@8JbbßOcV8  юH t;KSR8J{N<|.K32 |rI90㮹#?zq+px>G3`Xx'N2>GAP$<`~q՘VEKsw=smSbV W$ cNGF"i6s$wϞVD@# Y|9ĕIAp8#|~Z0 u@1$]x'ژtzmm+),$Kʓmsp@F-U' 0?'8F'*̻c3Oj:LpFr@>yOԇ?ݤ1b~_?;߹^XꋷRNv;q><Ơ7y'? 7 CP:88ۏ؜tw+]iU5I2` Fx41nWU@i H*sGerYi :UZ@`g#i/oog}7B 0A>[pb<KpW>灁3AQ(ɀUP'>s+k@e@:1~(8M2ҠUP>] YVi$տ*}k߃J:'Y2o'c^S;U%*P4H2Gr9!d*̫2VIEGX'IKX8( *-nAkP9OM \U}GtZҶ{-2IfSBj^64T(0cn1uXUDJsʄ㓓$rw]~O=*%jiLN{A'B:6ZEU4ڭ 0 R:PSԋ;_^-_E^T4썮oY+hi^ JB҈W rzkBuNڃK'ii5%ɨN[kVPB楣U! gCKVZ2;A2 ]B9qWUU*$܇>goYNC#H|e}A\e}[dIAm Hg A>Q2ФX6kZ& <vBjZO::XkvG]֍Oڌ=?N LvQݬ7Qv:}zK}6Z[- m.jcdhdvPC{~;WM;͙(EֶLaj=(2ƌLA W_kCrwNTS-:~H[<2Vew5*ߕ 7YR OZy22d3y$PS20bZOd9(WLIܰHFI0ƶMKեV%N[Dǒii55,r8; aBOD5/gtl2V;5O=mX앴Q.wA2(`J1}{8vs6{CWޮFFV:Y|tvo,-yhh٪4zU3SxᮜV)AXiY*:祃%Kdqm@ S1<{Sw[I<)Ϭ =L<] m`uWn¯|un3ƗĤ\ 1#pPX ]?T{^])#j ~+e,]ԵS\IĪ[%/mWoi*M17j*3I$6I]r0FB_ASGo/ү[NӓRcR(d wMlyp:/0gLQHl@B0:n7:Q^ qHЮ`06R -t#@ +5[-JT DT%؀PUq5Y$#jAx#U $e۟o_W]%X?wGTi/q_;hHi^#4rlh3#h'_b>T>_Z/nW=i158Ӵꇦ1qd &z|>$+?}w- Ztm&B,y"E"z%UK4*1MNf<?8G Y( #8O(eBM"3I'<1wZ~߬tqيH\=$qsUꪊ=Cqa^Rc(GG;AwJ^HT ,w\ȮjZ>Pm'QʒRāѼ `x:AqDIV'g(bZR$,IBëv5iZ-ӱ%Z(AB6~A1Z|LEeSU@/JQS0dQw3,{S?lik[х=@j l8ox gΚϭuU=#o[4?pgκ$Z4WfS6)gfuHܢ<諸Ttg_<}7jen[eQ Mee%eE+5lAe`+4R9JI.|@@G39+>XL4aLyUAdxy3Gk 1h$C]ϭaڨrf2&Cj;&b-.}/U{ (,h5U1 7z;uzH^8*h0f]#.jOA ҪD忏,3J(択&9 d _3ZN 0PRD3J=C_p\xQ+tsXJKF X9 d(x|O$2F$ۀ!BF"($ڞCy`hmd(jk8ۿڒ묩,j}=G }&Aq, B-z|U%f'i) CyUCLi֘iN R@ -A=I"'jkE3HۓJO≢My䦕d(Ɛ ZVsUtƳH"P;u===ezOU4;;9hr#;ݞR:7)Z9^-vʺzY I9#i Z=m}"uL2Ta|rXmo?pvq=.B p%u,Kr ) rzViKuTR-J ?@@ӎ,6C1`<*dEnƺ6۶w 7$_VZk0o"\YY'@[8e! d1# JW‰ q`8 HRl¾`Ϧ)ǷfG'xy$=TWi#ێwb;rk6*qVy Ӛ{DUZ956a9 \F*G,scKiPM"B]27I L?:q]F8IGOAJ"hZX8 p@<=M @0_E#c'Cn}4$rP[pbFfx`N39QiGOF72}ďp]ʜ{+@4rU g>?zJ"dN;r O#@" ڏPx_# 'tO.E,hTFA(Jd#w Lni CYFI 'igX@GV0U+vً1 8>85NKSOeOF \Oy Y~+nh B$:mی Q -ʑ2NNzzˬql,̣ 1:K H9Gqf0z*2T,$Q HU`$`e6]@7߯ `I_o u6%ϱ\Tr2NHu3ɺ c1xʲ#@xK6_sI\@ W]$iwnr>8~j=Gqt{E D*%)\yF[؎01=!4w5FKH4 ʼnWsէAJ%cahy1(#*+Nj 'coSs ڣA0ƇoRANׅ wHZ>9Z_USTV '-$tƦJ8J΄̜g csmܧyi;V6(+'$z82przMtJ!ڎϴdC62H䑈eѹ,Y$n Ѫ8fqi#}I%ipO nGKHVi*f qkq3@$~zTtJzS1 % ;N*߃]$qS3Oxc P Rfu?YVT@8IldY]H$u;ulRo..+XcVvۻ'> Ԙ[mx7R"6*Bh>3M>D,q0$v-x誝!) j)pƒh$ UJ6س A 0lyFÁG}-F)ն cOh[ &1rO% J ->dM8Zމ$bE|7Gab\q|uC7-ƊDr\19c~JWB*bW$FQ,Rm%*KնF} [ԳGMj*># nBriXɝ@fxYɯ.4i\XK2zY<1 n8( (! cce8SGMSi+Q%0 ( y9BثVJ\(N[7:Fl4d#Tpq|&\50E" Y;Ym||o\A 5#jۚ NfY =8\e 2InW2ӦTh 0ˎUL6` Ϟ*f7(`F 4/2Z#)&E$NIyti) 1u0o 3(6@}͆N +|QD̏ 0)yOJPjm1$lHH@ Ğ7U;Q$A # ryeұ/<-Ilg>O&ţB|>myΫ8%xƁئު@?{U,gŹlO#;]eK" ˗.F9,/j mPHlwn3X|c! QbIh),d*<7m;dAS>NSŕ|LSH҂nnO$9ZUDV߹W->AV5RǾW`cS .};YXmI=Fv W;ezbiJzxP,'k>ClTGtW*}%.cg|2c7۾ GGMzjJd(("ȣn읣x>a9iK-$DH `ʧ321H`9E@[MO&t湫6AtZq7 u ǎv"ޤQbp0PkxHMT@FP"G(KۅKIkD#YuFڴVN!) 1$uCnE :@*7o8pvGB5E3"RYJDâDOKZW%8U+KQAWv6UUYܕ]d /vSHXQ([r$. aH' #8`ĆXЍÐNTIYXj&WϚUD|Ȓ&Tv .OZB]ܚeh!N $FU$WBFl03 mQO@IpWZhĹy$ ru Y,oâj]l~cX3%TlaWEf;ܑ0QgҲBTiHkn."FERNb}4ʪ0 +.MiNޅUpc$4IQ:)!j)*H79[]mTfGHvq[SG :+34kSA'1hW's=dyc7$!|pXg|QZs)(]tϔ. ;„ 3(ByjT0y䑑4IWBd ]RH X9i5^[e־kJR( b HȲ(c#h('tzf rCGzK}EšHV-̱LJ#9\1MMuvUe *RSH*~Yb7snڻUiB9̳Q&틖 ɷ%3˂-,sa%9G"Bk77 CQ ! "&,(XzmE.Y*uӴZ^z֚Z2򬘐2lpMSE[W4[DU+#ޕLCL qȾ n&4*Ţ#Zc|39g ݰ0Q;5hiJiV(WЩFmi,~P$~I9>%f3&bIU3`dUUf2M|XF+JVFg\d<>fRM+m>\jW UY=='`۵Ql$j$RHtl6GKZYcypK0@.Iʌ Ji 摢\k*Gq_ZJ;tH1Q%+KYk6ta{5V/0yl̑KPB>0iq]sB\ wY"Y$`v@+O0EJZ]65P3T$4dLȠ3jv^{9#j⊵j`M.`}b3IM|7 M9Ե-Ri%D& M2 TQܻz 6!`H%W8ҪayjJ#"m$V"Y9\x#ʑ3-|!\H&TYfZQUZ2Lĭ xf4uK3+l52td%UD8FwN"#Oj ʞk=EWE{]j%4\VTd+胿B/ԖSuZ:Df_d[~f“թÍoRn܁jb,m$QrN8hs~%w/>w=ǎ??ןb#ŎI}˿0}i?y??~|y/]lЭ&:e@ \.2pGGu$gqҕ8oLQ`j⦅sW`??@}>O\:} ɳ쎛jjAd㯿98' ?[<]oǟqG4{ ؎0`F9~0|=S dԎ?'>?Og|~#(6 #o 5.:un0*Y9V`Խ/pp}ZzJ *jB X+nz2Yu6~DOyi7 9??qqDG"ǻQFq'yEA|~gq??Q g:ḾC¾'9ںH55]* FTye^GF01'#91ѻr?|C6.g0\mF;+rcU~ͩSOpgnX,ry$s'=%pBS+=`[#pǏFCҵ˻v&T;iU>o 0*%0r9x8[V*$1݀禾H&xMlW#00Jmʛ0p|:.T0tɓ|;PcɎݷ&M ΕnغUs< cs>|ߣ#U!f7J<xt\|Oz 'q#|mПO^PN c~O-'~ {1$N9>s2 ,q`t1!'bǚq} hNntƱzQ ]\HMS?oK|l瞒~B@>FAQkLwc$s "NSH$eL,T6ÖE$c sd B#S}9ۑ%OˠRidXUѨG=Sw;hEUD$l|If$g#[V踮d4E$,Aq1z:QN0; <+dOxz#y"$}*El!RŬw`ȽǹT{ޯf,*v qQyjY8?y8=]{JR|:!ց, S ߂:m>6?N(pv^OuP *a8*9SܻUQܒH*b UJʸ$#&A #GyCv)'~>sgi@F;qͭ煳ޱ^\Zj !tS&~gCU.ԱQ)JhJ\`vHpW[~ted¾.Kce, *]Ϸq9 xxEm+yOJ}wcYw!iYxfQ3Uزڏ+SSx>^F4= 1bEՌ#dIA\aDq#7t&2cj8$ |;E4jLI U6g%7voIbbc5p9 N\$@s3$I8_քƞ 2GFN䮡r.؜@o7{m$ZKVVa'!Fq8 KM QH!p&` $9<z~;ci30d!#ՃE޽2bgވA(f## >61OZxN~to6%ձҷ 7k2_s C+c#5[m^NVW<Tc8=cNi[4K@FP9)#$A>F RY+O(1R;.`9 ;H g#5; FŎ>ĈZ)"G^藍9+mH x|0"wdRT!ے 23;xGV0ٔ kj ;Ut H?Ylw211'> I+_`ytK3ľ_{V<Ϝ`qu:iv_v88$6|gtz7y޺ 0W@8.Y=썏gv| Q$/!G!08=ʿJgŒ_fA,HCQۑ[E4S8xG9#&E`S#Ӏ1{m,T@k$G-Ǒ㢆YlmAګ:bW=*po%txu J(ry,F[R:K Ti2,U±)(A<R9⊡WҮ+±6F0Nݤ0#)!ddg*Tb&b $@" =k]eOB=[8LMl1.<`K09uesbEWXi@sʌqp=9 :@٤ !~@93K_4-1t6vh~S٪2T3,.j$"kZTf_`[ QdY)$ |I['><>qȬYG8s7؍Ikmaja+^-,b&J0A?~px-1Ս@H 0apGVlTI*6s8u,+HKA b,rqL qMЖ׋޸{qҰDa?ޏ}_$4ł$)V]s9.w֕_OA( 3F!R`FrA'IV%e[yscT0<@*g+,FR  }X6F8`OYe&i-"ˠ=Hw:Woxd.3\jWOm5³ N;JF6ga[50֚xʲ6?HH=0=EI@8`[ێ$yǞJՖJČ.vHݓFN|a|2AGqs߷DCe7c y'kÜH,{R0p<<@ |O{Q}W!; ={ 9 c9t MCS,rcz y*O 󎍚"[L(%*R<1 O!@iZ;Pa]45β ͛;~ D19H ģ`Y@w]<q\vWwZ"gg ,̀`۞*flHYY Hp$ԝ!uW{Wnnb;tm|(YN*rp" (8HjuUZZeea> )釐?'r e]ʪӣ--O}gJY!RHAztSʪ msKM[]G-`->Z-Bl dIsIF.F?We wIVeH ~r+2g*EFheLpٗ'2"CiytnDA9ܝRh%m,Tzpyijh #T 4OUL! lV+Mq>Ĩ)R$1> 1I8zŠI x TA1cy(,Zghnb'q#1c\er@Ffq#&͖;rY$id̍GVPAP>mW jf/+VO8#f t|Ԛ_FᠣvUYG;;>ĞMlh+*D"nydg>Ր`ʠ!'nFgﺆ$K̶Z*ڙTn[Ա:usձ~rG0rZ,(ZbNJN(G$y0zsvMYmS5uTv -j9&9*cw-URr8Gz}W>zzk5TMQY XPFc#'cżG5Q|7^]S'yd k'?: }nV4xǫ3A͘ i5RVIFVt5Wq.f^RNYѶRh#DtѩFK;){T4ѱ]5nXE5E}3 {sB$jJWQ)ؠn@,ЗlxX颸Td!A OlAP6˭wv*;NYgzJL(W),Nb1N>za! yo"x')ȒXrb0<٩Iidfv CsM$NѤP2G,]輱 $j@UFba.REN5E"Gt aRǷvMΌFc YGhZSj{j{a% ̣molH^6+ƑCfMM)ekin^Zxs(*SB# JG7$UI+mv֬g5ƙG=ʞ<X Cg禛#d$ ^@ TITj4b4A-ʬ*DҐN  IT]ڙU* *b{+ֈnqD42T=OJwxIXޡTMM\ƒ!8#Lɨf,A8WotV՞ N*fP|(,Kd<ۡhZNRS {eoIgRPP'h=yjO~"*fˇE/$̚:. ő=QZމe WJ*+izR[fQ}0O][NiU;UΧjSmD3ÆK/3"92 ģ=џJ[Mn=SN)j ,HA֝̚׫QyS:աEFh TIVeƛ:fCC_O--V FjI H%OMW!8[1!f\ M.QDnT[Hlgf3r'M!̈WNl%,V'm(;K-"[5TRTF˴' 8e}]/L}%o{Ji-b%UCUCE]i4\:nONSIumHFroQ-AlOPkn)M]-P$2bJ6%@#`9x9|c=B>_.XFbR<߁`-_`/]>2?8:0HbF??nH$d~Ӣr$|sOK1ߩO;߯{s0-T8 !||Cq|e'?=}(קjS~߾:s0<>G1tAg?u8>x /b,}pf<G<\% cE0Q~ r<?۠̀y01xOIwpI??۟?o]`߸;{pi7zx88o_L9<~K^)}q^AA>XJ#z8H9?uG?_zQό&뽠F\=`t:|3:0cC)ٮܯZz~Z5=Eӹ+њtJMʼ1=z@6 m7n >ڱ0%$nrP! Wv'PQ[r^Me,["f2S(O,),e6g%ڊ%4EtҺ(a JuBP!TR erč9x>~;DFi!B0ˢEi%V1#1cHYT}Vmk6@g*֧I `l Q;V XmT" iڭze ABJs~$ʛOUoiZ`눓 @##q.SHC:TS(@P5ukX' ee]™b(+''*P ;`Q.m?"`Nī&Î}TkpyoұU\7ScVX.q<"կOlVB cKN20qM֦X[kQ',t5R+0S2O1+ JFʫփ5uRUUj1$1M>-,^2I$Ql(ʾI&96}ZaQm+&b* 0KU`fD}6$f e^'fh4 гr8}a_5قX>ۃy!m!iIJ)nG%99'`qtL+pYB|gA^-p )ݥ2@)Y7S9 u-{LbWTuW 7{n>9ᇝNU|`G-MP6 =8i9@:PO"@,:=wwHfA&xUX|r0ry;]Q4Lٷ O$`yii +͸`s cmb(eJ 4c%8;Y^[>lJDJ +XG;#5:>٭elIҁU0TwPAe[mu]6F@AGQ Y*v@$mhsT䓒Ƶ=ӟ%]! gx#<3gV|fhLrxtդ8G;9( f[Ց}hM x|?ыW@I㟑IÔ>Qł$I $U6%n$uMx ρs3芦wDX1ZxLjK %u? S.۲Qmz;gtUg'.T@V!!{,ԣdXܱ0y ǎ{Ӕl+<猟F|G9you-lyPfm3ҶY|++'Yn{W_5{8T-X#mT7obͻ۷I,uȤTeY܉BV'i\;ǹ#FA#R[fZ # cR |E9DKP }qRO@f?.wvǤ75hcUp&ݱOl`(Ԇ*3 zi&D@pN@zҋQL*%F#9Ž1=IUyfAڠ*n.W =ힺ(|)ɝMYUkjv}qHNmN:Y46G{+z6~8!v 2.1o8$OF䬏p#$BTiҪ-EK.<0cx H٬"D `0G32$o쯎~lRo|5)8b<;W@:uƬ78YR&e۴znI:%`>sA98?? uJګ`,ѬŜ<'h갰Ҫ!b7RɓzRP6#Ө1T ~ǃOSm!ˀcrf?NRP)p>X/3ڹ$r2szM\m/(A$ <`?oY S36ӵYCzhk8u pQb Cn$'ʞ3\mrz(sB F?~W\e8!1㎈k`cG+,w(`y<3|IqfU9929 ~5ʒz]Sq !7y!G$KQK$IG'w1Vgq7ݢDSw6?_?Itm,8nN2?`g̮pOGF1$c=" 3<]d+ dI<"Ur>)Z:z%ܨ.g s=&ƍ-it ,Agc&SUF+RXdA㞾fҸf8Sr2\W"6I"gEd,vy3<Bo k"tGnE_ #:SpI]Z7NHn|q3YYQ+fSs6G9X13UԚS[.USj&]4,= s1L,3$p%L;(Ӣ2xhڎ\bp D#fe|*B}O 8 1_6|,<͢@$Tt">tѱ}'siPc[TZzW:ؒ502jkEIR1FFҒ0A|⡭kv359UT<$WڳX $=ój!תʉ# V(|rSDљH899QcO`ӴZr4HڶYP`z=5Bsr{!FY|ue#褌YU^ YS11`Dl!+IDҡ $(MCbefZUt,"ela$r^ $F]'1=Iޖ'@o>3 JIBd)pH*𠌂H_'V0$qBPXR5 (sd$33Vf6XMY+di=YaGWHu[]Zwi!YkVQC{cAc C#Lx`ɎIF H΢a)}* ZsyvO6雕5m3R\"#$E>2,jpN@ >C_ymQsz4YZ#H⥷1qDI8Psֈ_?jZ(:Bɱ IPdseLqԞyL̳O^L'//.e1O+&*s$nXnk5,H*M&j`"Gl,*e@5VtY-9h ) ! ( ${sm&UT:SS#:JoG+)*(ڃD^Q+#خiu/Rm7s8! 7=]W[(>Yp[fyX'H%e U$G-6x3>O2ZfN|d2\@VX@1I]bU.M ˙ڥ AV zWeUuocۧ $T LSK<.$,@kM޽du}ą*+#8\u[kĕTtijwCPNWs#Ij*[w%}-D:j˘h  EN3ifr-n!!.f\o Op5SH >c#SzzFdt:x6;Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F gt:0c$=At:0`u'·F Cуt`t:0:F Cуt`t:0:F CуH:0`t:t88?|?$t1sҎc;`?uq`y3~=| 3c:7k?J;|]]?ۏ`'q??z>?'9><Ԡ{6;l{>;_AӬwm~?lg㏏z 9^OvNv| 3x뮇Ew}x|yAI'}t`nn4.NGt[bi']8ld+̤䁍dK0ja@S]%Fj2)dL[ܠ4]УQ:Ѹ?R `H]t-FR2]]–6'r=,K"O EoE"jE ;֠I cf2REu)+nhaxP9WR( J6܌9FA<[-GdJ0lϜFwZȭ* W e fGF;7>іD&He"/0JBmY.z3WQ,l:Z)t5ZzYzA'`:B]Xm.*cq@nF` mRFI^a?sF-CD uRRW< '9gVaϮ]Tš@OQ@ @'bwZ{>ڄKPd(6$dQ`r2J$|bA]xK0dbS#><8Up_!LmD3f 9=>cƁm* 3DZ$e8#όuGxuEf ^àqMjWmckO}% `G@3 9Q < Gh !kl3(]m|pI0y5Vck.Kc/;vd(Y1tKṚ!u$ =\]"]wb=VFM+`EU`q@a~H#*ھ\)Q2w32 |s֋2𦞡ʨg1)DF3;qhUd^f2'20'.csOIT|qg|J%)Ryy;O1˵6 S z\{*gQ8\|Gjcf{wdG?>HTX_N*ҫ0҆mס6\2>]x' Z52($D#Np=3D; 1|?LtYj #2WFeh\ Rq֟#fDf4Y Ơhiъ6F`, G؟[撡c&BJw|pyP@c(~׎Ja0R2CA%VgDp$)@'6.'åL"5e TI8;IyO8Zxcgx%vC ;>3ٳn_^G ~G^^G5 sd?a9]TYh%U o| 88QMrF!GB *g§$vq-5q,j(vb#  8`<˽nk׿ZߌK"RGRم#xe|_e8 @4;rX 2=E}*>K"Cm$)'iF|g95TKK] )kD YW}ŔE /QK/HyYuu( 16"$DHԠFm55SluC6n8秊*jHѳS6R(C$2grx<jN-xZ$kEZ;9@TR a/rm)5ڊOTԬH.)Dfs+?9ϙR(RpE uahn68qOEuJRJ؞7Y󽪙dUEMKMzکV 3H f.sJ]?u.0kF}?,\ҙiU-z<RY=uAڪT_NPmEEJ ev/ OW ih)hjX8!JTC r9jK'1e)X9)JVH2`"LТ HU ɚ#Ԭ-`Uݫ˾lp4җM5) Gu Ξ*˵ҭs5W`F}~}ZMi\Dơvv8Io8hRzu~8][d Pd| 8gYzUwzSMI[YflTW#EVlͶ!.`~p5rV[SRdJiI d"LAWYmw뾫S_U\b>M k*!Q`*x$sǒ9I˜㌀Iy%xʲZBuHeXu#0Y 1Py8z?r՚ORe>Jh'`CN񪼞i%xzi.OYJGR%sztF"/%, |&aIN00I@(2!*X 3m>umʎ;:CGOhJx\ڦ۶JȩGMShӂwrdgdӕΙ]I̴*rd֕PTpBlQ=Kn`TFep!êMMfd7.Rç>G ӶSުRSR잭(ãey7'Y2ͧ4mji@fh \OUo,]rUg<7( >4y)SY6 V Uf%Dm"ݫ) N|Uael( %l؅\y(sf!tr$UR&7r##1y<#WBZyfX"у? 0PBF54E*-pe܀RX>e9_zGKzRfO]ZQ%4Uqk2ޮw]CtƐirM[[eJLzQ(Rn- Afku$zqnӰRM_Q,Q" a"v'&bHbZ]2FXb)̣G.Bc͛>k+[ˤy'fhݤKRubX\5RPAjZ/Zo*TQʛYQ贛N!SUOpvATs=5"ḃ/ */HmkwKh{E,mLR}OV 1 TywGikUTkSW!7GC[,#YK'\sga2p4SL'~;ijCJDfuYΝ^ymS:stS/Q /2;T/JR)4uܻOQh5:{bZcDhAD&IF^Z b=G#nQzO46AGU/^zͶeLn ` s"r՝ԋ4)=4*,uV(Kd |֛$}w[{eΑ&YDq+JZMs3Ys #G-}`q L$pȬPbxreR!=OPα-됳6L*Y 5VefKW;g HN sc$:k{KmVjMGOIQx80T:H`z y.[jrM~VLK=iL'L m tEp2\(jۍҠ&Dq#D@O\ 2e`F|i2E.6dݙܑCY^A]"X/ P5l,*[V-~tK̵WӲPTHҊ+8ڤHʬau%vQrGY[®U׊v̒N%,`tbKe, WWtȱ[5{Uw7< {/< SLshܤ9f\٥%I&0%k:HX ^8636?5"/4PHi U]5[ g-'j&))qPIB.pUa0$fhl=U<7LPPͲ6Ĭ*7v?Lk5*kheZzX7)F,Yv"䞪n/, u@55@UT#/`t?o:Xh ZZdW_W' +<'3Ǥ$YцLh0 ʬ8(W*5? dG:W_bQҦj 7CCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CCpKx}3d|mo^=C~Ct:0`t:C>·CCF _@_?GKpcO?sCqpqCJ/_\;}mo2q$g|ʌ|r9- =/6*s`dӎ$1g0| ߁:`Ԁs-ӓ #woqU]#<u߿;8Ϝ u~d?^́#z1N9>H<?_wӬu~|_;{aۯOއ_>|~:1d=}t: Cq?JXH3|`rH$ 9v1s?9䁏|'03r>'y#'I(cvG :_J* ebЃ|ys8C8Ny?<~ԉ+Y*G;aQ>׶)MtpȪUk܃.9$xSIzY% V##I$ib@ ۟z@#~XFJ2̒(mS4S;6XwʘM  o#lGT̨Ϋ+)-Ag㏎a+b,Q gόt FnK1UWzr8bpA9uj*ꔊ# uL9$!m@SJ@x%eVPH`,3Q(6v=#oG҆*mwXfZ ]C@| e\ CgǸ% Rʭ=Qޫ2>@ 3qyjHdXe|`A$qf(l\aHHM߁6i@$=w#m;] #evG'hcD]tTR0a8>O>:UVE,l댴;"yee 0ZYe\,`vH un9bF Aի @schJ; LPz_߷ : 9a-3;Od8PCybySy @O i`% V@#:anUTUtT BMᑜ8žihDKlH )rI8G8B'i suVkvVޛQ@j0dvjĕx#`f!w MVT$ p6In$@)j2:cHn23N1C@J@3F>1Տz%#N#YIڇnn7)l|@A(AǓ8jH$RI('?i\u irq r@=7MkO†/auwDy6| ρFsw#V #ՀGc^m3IrHJspƓyDf+G3aV]$Nx8`pH?895Y{EL'y"Xq묺+[fgIBw(V- w#O7 |P# V5֋Ƥ "woy0j)H|@:UOr$0?ujzpZCҼͼρWtHDy%cPIRN\8'|g7s-E3g 4J;"x2 {C`t>44q\fJc 㩌VRYuD%}Wl}L cc㣛M!.I0DLYAzyRTF+:Zzj]5M o q `ۻ1c =?X5壹bѽ5_{4.byc@4UX1!suꖡnK̡dO)R|CLѐqN%x Ֆ QU& c mm)Et/q,@%U‘}jʕᝤVA铁g3(2*zav ɘ\!@D ?G(4BRE 69c{뤩:d Y '`yl8iozhkSCKEp?nQ !@̣2}i,tVEa9glR5K"}dOQ#8"MpUv]@nG7UCsp,^?4Y.cff,ze*cwՑ*şFUK̍,5aTAԪ9 [W5L;c-uZ.BVPQI,eW>E޹pH=KZBH6T5WAY\h5$ TAQ!k")!2+EQDdXNCN 'y Ȗ /2,,H.*jZRDR@Ju7"jQeZ; > :チ=G%UJ8}E$2q`%$z@.? 14en KTn' < c"RZԠ_ S4C""/ ڬv8~IXy]  &jwnvYӾ<w{aVE8^D6J2X4L*Lp9wI=ND׭E==4s4¢bV򱢡  xQԚ}K~U(gxdf)+e[ét - y$hdx6J"%ӅE\[c-9ek΢V8Rp3A&O3&5Iad7I 2?cQaQYb.I(Jz\,w}?iTMO d3Np%$srC[tj NNV"g>x)7`` WZ-_y }G(a푘p''G.rmR [qFVB#0~2x=M:C.֬εE#Gv %2C`vT="9sa ,jv>Z/1VUF_kDr=5s xoeXdv֊#^bCT"FPFfs4!GU )$JD378EO$tM4UFk&Je! !spF1N{u G![;@YTLG&o |u:jjPMYWeA 3_)e*ڨۛ!:h}5/E(x*ޡ|uUeӗ*I"VaRCQm+ҍs0JEke]LYaZ!)Hd\UZƆ+GnS%E3$e4m5 8!9=X5jwZX.@'ώmޢG,)fu9iclI"e`6B c%-pMטY#LEܲHɵv13(+du\i4rf/#˗22<ӘX)KD JK]A'աSA-m%3Y-E*pME@pǘ!H8?ӕ6ke7"+Koau]؀@3eT z]QD(Qݘ9 rO'+hm~jkpBT*M,U>ee4S^z6S;Yʙ]dϜV9H aH 0Fԛ:Ē#JZPaVvueX` 4+$FaikYRK3AdHίZPi4VZ&EaԐ7FAt^os R WbuNl cuL D]ʹtYUDp ^r̚b7O.GP`3`<2Ѧ^1^Y YTZ,(6;Ǚ}C2Mt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CCry?z%s=NHGm`~wqI2?zk0j_<CpCуt`t:0:F 硂|z}]LG|~1>s|V=M_|x~㑏N_~??O퀐9kh `ߎ89981?pN|Ӊ8W;s s on=ڱ׃y㯤d׮砾F~x^:@G<^plmb{;>3 3y_xdmg'o=p'3<ؑm6 P/nޫb מq??u?_I9q},|{c,0F?c]?.~_c*-<'뎇F}B?„`txd&@WFd>+?dx?8y y>OFp3?u>@޻fo?Ӑ?祫NgkXOtama/ww8Od42sϟ2#?9<F?sFG 1^}TTmq?oF ώ:?;>~0F8zc:Qt*Ő:ߵǛJA]l9٩jh֪ƌꛈRHTp9Z~=,5 @ꮫ-E; g)+)8yf0$29u?e9S?5TU˦tI/:~X ^ontAbĆ'UO/Uyݏ8׮UG[q`h ~eP`0ٻa̒nUj6bս LʩYXİgە%Q$4=&NL~7?#-V#3#1#-^֗jfi .1b?ߓxx>q83YYYmd5 lr@I^)P 6p6vI4_g㎛?tkL͜<?DȢO%x2de!~82RZ# J=086%C 8b8y>'7+ΰ bH,磆eIPF)Ibb]Cs(V2z?*BTjVQSDp7HPYk֍j}%2V#LOSiJ4Vu˧.껩)+gBg4`zrA'94ʐ4pyfsl@VF6&_2Y"VJ*jwW d# D2颚HhUo夫K \p2 pXsOR?S<0gu}|,LGOztwuF ӆ8d8Vd@ cl-?C%C+)pK:(i#;>g?V͗xL?.vgFR Qݥ'YHK'f@/A/;4jnaERCE3Q^/B}@Һ16rC6 98frC{TR xbv1!pg'u$mmA];YteS\2IYP*=FǕw6QjMnS+in׸GCE +X`ÕRtexvO-f.ZZ d QuƑXmvITfYUU@#CT$Qz*).^r5e MmMD]iٛ NzSE tVf :p\mCwjYod x!d0NиmTe .#Ĥ3/TH̚*MHzPa;!,dp@j *Rݕ6'I9Z[ \e2`I2~@d|㎣zH5n[u\DŠ7K6Y&h* l9VŒzphtvk|]G\AK+ t"Ύs"p8cdQVlWqnS<V ԫ4ԏ(.Ci@>V\|['pL|nCYo7H'ҏ @ 'ӋY.itkQC3/lԠ?;*YD ܨ7cN3giY/ɦ=ɴ-4&E,sȘj8QtuUD}ӳ0O`E>]TPs䎮=OMմͨPR1KSPC32SF@vw#',od`WLry82mcf>DQ##iZJM3YO%yiM30X PA! )K5t;Q3ghA#ޫČK,E?ӦzW"J)贼2KYRz`LB1~R ''j-s5BY*/s[J52ȭLpڅ%ۀ3՗;`gI,k ꢉʕYfYTgx'99IcweUO!j(dd4aEa&S[/O*2 UP1X3jc0Y#,h[- \:(+` dFyQnZi4Ji JL7(2q[UK<jZ)+*{Q׺ LDcvOx0UCW!T:*w+;8yS2˅|e䲤q4id ݍZ=R%(( (0^]ZIR@eI@-\$ p1.ѐW W\J֊.4Ă%iTrFՖÀm9tV9Z%,w!xx$zIWkXURhfCj`8C 2`'qDLP1[7H$k"P$s|וkη$ڮM9+UZx-4<wT}I&̀On~z$ <cUnٯ IawV;0@T1r@Ȭ7pz]eqvЬ,1}Čqʫ )EUeeÙV X`L/d%ݣ}~ተH6] ElA6W] 째QU5m(=-}S 1 sqa5 @1C0rU=zq)6rJ}8bmdEm9 o9;F<_+[TO-p-(`TlhToX^ ҶDUX$XA}LuWln9&F]޴w:$=h -gY$H*Ǣ ksqOAlo/Jr<-+9 y.zٸ$0,I&e% 櫣ҥP{r1N:cCu\s㢯=CCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CC?|t$~?ߧ]}G]?Oξ㯝Ot:0<N1:8 :g}0`h@??߮O sۜ^{񆰰G<~p~Nwc^Q$<|o랇Iw{o+\Uv] ggyN߿˟?q?os1N. o ڪߩG_xq㯝&:vtn{P|1硏_ϞM v۞7;[qXϟtIǃCeF3Ǟ*~v G}K? yߡ/q=GG=|<pCo`; G?uə?:,p@c|8i]{~3<'>O:%qF0ǜΐډڿaw~{}~\gus~>?뎇IJvpg?|נ%؎t{;29^oo?랇Ig;~olcqntY~1s@Oug}1'2'O_:{L;LCap:F Cуt`t:0:F Cуt`t:0:F Cуs:`p%|g sT};kiFe^FprG?ևfNS9_0`@Q d5R ¿sU5Ruw~0ޣ0`9::JO[wf U08e8IcS'>I 9?$Z*\IR['v`?Ө#y2Ȫ1eV@TRV{UFh \]>صϻtaVo2FIڮQU_|:T:I&3$sĻUK;6rz%ꖖS@ 6XFrx*[5{| 32N?T>٦jLeT吰UC_}زT(Ł*54ט۩VsW=R޴M;Њz'cY%^wTCnT\j,l" N9>8jS EEW#u"v嶓t-%`#`86c)FSNfxUjPK ̃KPCF(̎nI *F$Y$lUNO557IX/7O, XDPtc'c<OTܔ LqMN =EnךR*X'vyѱsh2A 9 {mmibNNFry$tg_́0X6c1"fq3yJKSLwv,FJ%- .^{֛438_nIrV@%`!! ?N f{LaЧWYV.U(|8>+˅־ D8A\H3USS,q,H R8)F7Y&ƹszuclwHbAɔ0ҪJ t@4]qnjk暷Z)n16HTSp+Tp^*/M8$ y6YI㦺gV5;wbͰdn'$_zC Zpvr[ ωȓV0AWbTi$1Хdpm&lF'ɑlϘe!83C d6#$&D<Yvټ9Z(Vo/Ii];Q4q.W%f_yxLrA g'ތ3*߾3^Bxc ) +qz(h꧓QZ֥C+O,ǝ9#՗eNl ZgBԴ,ul+#cn၌N_^2+D!P.bys rSQ8 hU) Ml&XVn9t2GGC:Et2|gF }x#Gt2'ѷ`:F CуlozT~?9Nt:]a7># Nt:L.>?_:CCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CCQу:F C1>r#?s#ۯsQ޽W1?@y#z߷_l"؀xe?뎇Cy8P.>Fr@]|达Hx?҂*A⽇>nzgx~uG9?GA&on}pA_ t??rzxg1}9? qΏWt:0}O΀L|7?~O_:-qg}/I,sxC{c·C}Ct:0`t:CCt:0`t:CCt:0`cώ?NCуt`t:0:F Cуt`t:0:F N[mUןQ JKK `$ T_Wkk Z襝!3B!A`?5|Qҥd&'m}qGCK)ԛ}v%'vڣYw1 02:inuqA6@!|c<|,ܱ2d0 >:9J( 9`䑜u魖6 k_'j޶oCmdICyŝrF DdU9 p2yAR12r UG.s )` xJ!VB6 p1yTgw(B 8l083*Y v6+C Iߦ˘ͣ :0mҹآhoCi'rϸU$*1DiHR2H m8xQfUP{8#'I*]HuZ1HGGfq6#qto^ ̈2B%-F<-J~[<ق/.ѩ%CP,ݫa5j.2Kf]ǝcK33}A88竿Nvk\;lfyT(ƣ"=$ˈv|ym+K蚘Yz+f !ǐϻ*9x]s*g0"iɠ: F ISwPEIܩ'PBNDP4v[u$sI~s*#)'H81㎥Sfv]I㡩q[sy4{w2w 8aI: q"v}㯝tGჩgt\?ӡt0X_2qw]{06k’_8F;x 斊r\ |cIuHgcS8yd}$ղ:)$@64{Py+ٯRNN!oXir9`۸F7x<ǀS ++ॱ[% UV (yȑ$uDTɤpRm!Ԋ۪4+tTtR̐TF% ` )8#A'#t#tk-Ar*BsFXYrK\TP JӜZnskw[-Қj5\3dPI꬚j@vZ:"L^S#xX.,7cCi(£Ց g# IEr5$u S=0dRr$cq;X[021J FT{ilw&" {n+(#z*Id@-F-AK\9'U81Y eY#lsy2.houc8ݱ #ԗ=/5dsRZ9-T)WFy2Rx n/1Y%)Y228klԅ[X6*5P"abW,w|jfU12PM ʗo-Cj!x;Uk)M;ΔJ}5 =I2n<gii nNq'??g3E A݁"5HG*=$'bWD6@r IwP4]C3XCCt:0`t.zQDI5p[?ǑG_I8?ԉ#z ]_k(ju}l-UaKV, O#.qx⡋UfEd#-8<|eCӬ8Uc'uM4npj6Eo2V@I=N6JPU۝@:]񆞇CYt:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F }9sׯd~ߞtl52&Ge@r<89=&?bA(ۊ""vЁGWqqx 1մTi@]{lrzD.Y&gSe$nsؠ9c tИ$8?|e@3]- MA~J)b-tBm_ ([ <1,3E:; 63O`:[z-Ţ2\|9PO?r8~#o3ԫ*P2c(lWgsv Gڛ ،L'n)D0 p<cNO{Q%⡶ L4 >@O'$zCT:rd|cZ)䧕A"Q @1Rx=XL1eeꊬeLjW`mk>DR4FT*AU-MM SGq aC'6M-u(`ѪxPv# `XT⒊aG4(ea9Q|n 2pT0X<3:/'.j${;cʀ FĢ d`# hm`Ă ' tU˵jFӍcs|':WA%iҩ II/Y $ddzuCĥG.dvZG.j<$F)H*I$MhVP1 nOat:ŜCуt`t:0:vYnI$H*q*I|l{ ]2D`n4DBKn䁎3Η7+BV?A4Bhoٙ*@,BޱR=%LHUe%GdsϜqы(}͎r3]hV>)g%PKy zO",Pq,36q:?6[KeS%C"y%iQ[ ,f+·C=,Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F 8CCt:0`t:}3uуdxx|Nqq·FCC$x8t:0`t:C㣼yo#?螀ӔKn eMolt䌒<_z tap:F Cуt`ŠX EL0 HY''B%|&dbLʼnf#&RVD&˷qP# Ir11zX䊲J`Hڸ!%$QH=nL-fUX 0^YB-qA+Ƥ)Ij6 =wErTRC%Z$F* r@`3CU2\&466w%Z,bDP N@ #S\r`% c>WؐO '2RBAAlY}Ͳ8t0pդ.AxC7<Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F CуCCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CCt:0`t:CC<lt:0:F Cуt`8t`t:0:F Cуt`t:0:F Cуt`t:0:F Cуt`t:0:F +(_:rYuVX9Fs`ߟls(!yԟ:3966ƍ/z/|&Uttagua-1.0-alpha2/data/themes/wallpapers/Dark_Waters.jpg000066400000000000000000021623611077523320400231160ustar00rootroot00000000000000JFIFHHqExifMM* (12iXCASIO COMPUTER CO.,LTD.EX-Z500HH1.00 2007:01:14 16:16:37Zb"0221j~   |V0100 XƤ&  X+ 2007:01:14 16:16:372007:01:14 16:16:37wK ldQVCI@P P l ~       $ ! " # 1 2d 3 4 5d 6 A B C( D E F G I H I J Q R! S T U V W X Y Z000000j000 00002000000000000 0!0"0#0$0%0&0508251100N $& @x U%+T$Berlin         @" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?`Lֽ({[68^sv`)Һ k|vAj@+vԖ[pgG!ڃlJ;V0*!GJzӧu Z @1[pZJLܷY:X-a[PZjյ{W;ZN @1lf8ZclAgW;jR6֬6աql[v]CNC>+@zohAZd+ZLbu 3bZqZV-DɊϞhikgҴ㡬CE&!Z1Ykf $qW㎱x3uFQM~q#^%EtUbX^%et⬭ZHjGxuƋ)Jү,X=E\rť[fGmWc"8ם `v=xQݎ:W+|Έ7n+ .85z;;ןZȭ8^-߭Z02*:]ւk=0kXX;5_`\#8#xGWQ*$5#8#Xn=h~(Bj~(#>X_,zZ|Oj~)WtVKRHʃBǐV-_uix OY .Ļۆ20s~t; xIé*"D1ʲ8!+n;qyPP~Ⱥs#.5OR7R.ufY.۟f/a9ʧ+6Ez%9X_l@'Nqֿų[i9)c}QV⳹U bXO*A;积ik^S({-fa_hgAU$8ל?koXB\xEPlG9x_VwwD6ԎI 1WkGR P;ޤՓrF눧9O}n.m!p::u] B(<" `Ӝ_Ƴ/hJI qV_B{m/N+xWgwMbZ6\K4ʏj[xI?i]qք_92R?m.(OOOH41& _NW;:OqMEMW4h%m̿5T "qɞ}9ma4v%\/YIas=V{I|vqYZ?a~'k@9=HnEx"RGm⿚mOKx DIseYoJ$-lYZƠXQ gߥf/ _a~'orxE'{18kY_ѻ;yɐekmJ;pېҬ32+涣7Ouxܲg?sWt.2/ShN>Pퟦ@~@8*Q? WulCm^Z9MpOҴ#'q 뒬NNy+. /Ƹ8'Q/͡QnZ 9pP9L}x>ty'd?#F*cRXɫmU`wpq{W4sGJWg[ᚱG~>?z M'KP=DG:_/AHabxb$-%:=cB,*?&p/SCu~1+6b'}NEƸ 64ڃY vC(el(&>;67ްHA>g m:S{}Ry?_[)6?h7zROxثTW5 l+Ьfc$0#<י~oSmith~WA#Qj>4Q\\_ģnViTcϩ]Bdž/56wQY׿M.Z&B}Fkе5xuyapkJ Mi 'kC,O#r^j>y\kqY;nDbN Y<;a$$adI# r8p:?}"ڰ5|s!ՇBmɤ*DqU:Ĩ4YxU=m![9[/_dKp>ۋX&!{wY'LnW+#i,w09og~W;<1xrfX-cA.sKwI*KEV)9?׳i;d ɴG窱c?Zߙ6>(/+mpH>;j]VķB4.`PAq{xry-4ˣ# }E'>e$H0IKz Mt8ik؉Y҄-lcsV^0m, {ֵ2i2~>EN6f?ʽvHdg隮dEğחra8\{4&?jm w˾Oa~k~]K s%qۧo/N~t?jsǟ*V5MjuYaimO =Wq>uhvI,w1B[s ]]ᫍ>Q4[\Z/>Y?B:V^w4xH(DF<DUmj((ie]bb1>i^,_!ab-'g7koivi񥎭ir#,&PI|֝{<U)CҰ4?ȗjY Wi8t\_Z~2x3FO_%5r3l3M`YZj6 oRN03 >FV[OG?^dޠ*3zᖸ-`Uy$pN/ůxB&S͐n8b~={Jh ii\i6LVWt?/ %x!gLyE]<9wm7n1Hm5)lr'!פZ|Lm[y$pVB}kUb:W@ex{Pt42 ڮ$Bݺ`ySibkɭɸ)h!=@3WB\ֱz;jmºR[ߥW,]3PeڴSck]$R1~JMd fhκZˎzט2RVM`WDdGZ|SլKn@IU>lk>s_>wgp==kNf2HFW*);N,匶gž#qiXM`}<_ikV6<@C $Hd+~[Kvl>۞jAO+O8K=^cxC ukzMҍZJmG$vks}>h ŪC*1ՋiiNX[Iѐɂ=*#86:zXaִ˝.yD֡ 8K+Xnq궻ecxZ?0c#U~Zc%Pޚl*G)/g.Ǐx[Dn^.^@U]V떻'ws>t+y,! `֮2H=k.e5备hN{F=y^y#m]^AXI=[{I˪8MKG-&Fxy =:?>FlZ)8*:Z5nJ7y_{ْfęGQ׈X|+rA7 ؛ROzO +=OaѮ53"xzͥql~Tcx s\&2dn\_q۽tۓXOk-&qij} Uˉ!w#iztڮcA$ymQo9=+5_5sm?:~ @yQ_,.?x=fh[x|M20 Qk2IG'XUT z|X!G]~u>xQӮ+*ÙJ.܌:238qk@omb-Wdo5S 68_M- (gy'lWA_ڴ%W~ z ?{5K$[BF0>Gi3TVG֍]Xڧ]Jv A[8IcaS[Ÿjs7#]ލ:'ZO6 em{HsXO*Xd֍p}_z;VKoF4MT"٬axYe6܅ew}ZSO./vJ> ]c1ԣ'ľg IFOcwzg$(OsšwU_ !#ξռj[&X]ΚN.>27{[[$~}*|k .=cO3b#PD+_P\R:}3KvvMt%p2$nyb]<كOoOm*oWd3,|{Ot_ݩO#Ez̃gyDŽ`GW_^[J):6$bd@$)7A.EfշMIߎҫrv-I #{E~6GHϵIa"+mq8?V&]9# J,v㟡og$Tw:r*QEˍTgV r2?*,", 6{qTb3Lw#`v'$k:(`v a~3ǚ_6$Nǁȯ#PY!p}}k^)ǘ^&g'[ׯ 万aL+/ei[ɩ]D^2d\_'5r.mH!pn6}aֻ%wE3 8ū7"hӆ@3*VӤ*ZG.bzl`T0!rP.qk5>Oxi6fdB0pBB>8'Nqzdrq eO_VRW'h ASiI4G>frp?+%{oSx<{VM^,Xѥ}_njZz蘆id^j;+hnA<ֱmcUcӬu( ӑ]=~+ȡO քW]v&q=M+\߃^^oY8:eMn}̹O/ |L\I챍ï }k/xLdo6Iepi)_/E,.ZF#4TpAi:RUmdyXݞ\s 7cׯX\7@Fz%y־~5麄nۤybG k"/ c@e ^sIӌnCmJESkw.F}##wH۟sLo6Z_&vȐG^:T<: 1'$+ltbm sr2%IfyԹ!xⶭ|gҿؤ20(~SbqpB@bb#"mg(jI]I5VLz0~uݭbw&>?ʸ}SV:c[AuP{zTj-Xœ_6ѝLOGsV%/n"6P|sޟ>7Zǖ V֨ZiD_?y!ǪO~ޝ }úO61` œrsK*ָ3뭈_nGmx\ý}w|me,M6G ǯSX6oi7<8yKO߉:sD#`8Z+Ћ gGR11ǼrF^yF&ow3 2~FwUğ|?PԭV©c$7ڥjR\] ܧt4$2&_^Asjx67[W=of߼ ^n]Ί?wߞ*lv&Z!|l1|d{hGήenS$!%#U(mY,({=T2>(g#S@~̃j˺AA;}- ~nV揧ͬ[ꄝkK]{l,5ZZsуjHWVvzRMCM2,: nZ< qǡ8aqaO[Hx{luuUGnd-n]f=޽Dx{LF da4KuA~2Gf f)*vI W~}kssq\jB'=ձYwm(Tc6sϧ"=zqZG٬0A6؀9WÁD}6֖6q.S0%g׭t-bn5v/B|wh&k}yUNA;F3נþ" PXv6AZ&s:M;s^}eqpIऑ|i.ZWk72)]>Z+ş@p cxqۥlwg(|X_4O ^'{_=jxn<ʼnxױxCA:m$]T!\?<g}vF7r:;]Kk/9HL-o*/iAFɑ@#?ʻ [}:&:"b?LVOdsƧe2!eFx{֤?6!۝_?iOj]+D8ONJ߶KIMv" #z=;g&[P?@%tԫ(i`=>*Cm^Dp9+? xA#an#o֕ 5 r̠~}T;I/YqijD.c[ùIJ'x[2bb~Χ]JF6I m9B~$uM=W< D kfȒ;~q*AiL[푏\/ nnj~էҟʼ ~RH #گ^-[7i-o`hɎE88[M`o'K.$fer1܂x?IV[O+1.+hJK6GI11ZIzf-Zh2 Dc$ʑAGW&-nb?+L\>y_Cw>kxc}c"4_/Fי}GMi8m)IGסKf~!'E]Ũ^M8?chF|%|퐆Zq{nuznm{+qMxddZ5DtK0c2/e?UŲM؎AsWݚkY;ItZSɹ|d󎿍Tk`)\p6WaxhT $~<2rlt&0%CrJͣ>_qXiז<`r?ekڠ}:C"ȸlĩUFCOgeCe#ΘVCY^ll% FWeq}5on gT|7Rۆ㟽Vekܵ"'ʧ\ɹkҒ$''#ZX^9.#H0[#<5x}$W?$X㧨:^2>+nۀ2:gW-K9Ȑ`sZ͓JDդZWU]cGh, K |@ פMiow}$wb3(Iͭu5aAL}y҆ԛ/3Bd>`RqF9hc]Ae"hV38ntY%"B q3ӭTFYv$PT0lXŴ#c1H6:7Gw}3מB3+mAUMC_"+h'|G4^"bc0$d(qs^Ʒ^ŭ.5)]V"]YJYL3#3'5 C4'jxc;Mŝ]ݾaGV+xs靬8}OguMBS1(hhaer;_&~Ȱ $h I8L IKjZ:8dqkXr;BM򭻟$gxEk;X<ƠsZ.ݓ\^ЙdnUBz_8xwҀb6}3_AELiZǂϭ08gn9:g#Z_St*Cg#F.cD\E u\p;V[/MyՠY㶂ɷ)i ?VD=-˰Uyvd屎kJoF{>5Hy+߆_>\QTf2^)᱂UI/|E5ׁԡCH#؀a E:_qrT{^qً+ּs ox~O$z#1qҶ*,kEĢk6f۸zdV+e'XC)*?:DE+p?ӭY\iA:#Q\iP8.%WR榎",o"+ZrζvEF{fs~Wo/r%۞v{95Tm6xk[4\9!9Rx(z׬a;XpF8?Vd\+Ёȯ)2,]CtSͿ]2vW9. {kRc ?/ q2E>P=z?4rxNv)Wyk'~RH+92GZ5ItamHW#n>CA>q#ƌ'#C]$a[xH O\PsӒJ$8~|Wr~>W]{MYsn ƳFAFh&  C}FN>vԅngW=Oq''֝յݼQ@WU!s"@ZPnC8P.YFe> |w}9AII#_l#з&2h?J|,XӒd?&Kkuׂ$^\ŦE c=}3Y=6){۝eo.w e#&'H-O1? ڏv6%ʜc`p8^o? _V?R7bqFQ`Gu߳#eToOL Ia;mA䑍| .mQiM|Ȍ)׭cftku=XQOO»]?6؉+9=98ⲵφ]"Kvτ LM= .uVA"p=3+7g]3 5%:|,U\uk*WXv?Z;:+OaNON\sZ8Rt$-y?7Itv f 1q}mj?&7Edub3GkuCWE+)Nz9;-ʱy^x0²%/5a,HY-a=q}G3Oje԰Lq2'# pMps_3SG !x E]j^A3$=7nUaӅg^9zW%[ٵ[纶q~Mq6"Ţcvg{,3 r1jM@]s[ó1\\>"N!]0ث&K{I^޳OF]wAwGqo~IlK |d ףڭφ%]ooEr1+n, 0}st ڴi!byGϦXt9\WF(7溣F6s>a]iĆ[7HFѴa#Pz~̚Ngm7Y-.e{XN#U<+kXwGX͹NNq潧><X)=s3]Ҧ⛉ş隕d񽿖#>n|#_ZBT7fH/{_hso)-rۢjsӃH>xऽO8Q(x 1z抔\OOvexU d,88?^+4EkiLs:ʒGr81Mq1x,{ξpz;{I>g /K~J^G֤oZ{kze[[LK,hOr<Bń7 H7^Oֲ_PIq`}[g2;[;>6:e._3w=IZ4o^`k6VOB=3{;bWʶ%H\kjL㽚1`MaTzߋflycyoh}yߊ-x?m,G ߞ֝ƃhsڗ~R8f'IMB4cP>k%&r@CBʧ l7ozJhXFY'Xhic2`F\uϵdc*'Jx ]Qޝ [=rOS ھB[g08 A_VzՎVqʟǵZGx:I?Pa53+jf>Ucnq H<&N<E#oBN@azdm]"YY玛 Vc[m՘7Naf|`!)}>ZK 1=A+p=Մr=ooQR.ct M-!6M=*> .kI7i_o}Wx}> %$60?OZna|g-倗|JXu(8=Ik A(\b3u,+j^/).Q{|Cd="i$D(~`=*jVcmѩ}Eog9*wv?P< I96z0!%Vl2y~޾w>!]x?QDieJҵ=J$pqW|4vOyn6D+SaipE='^M]I7R980100Y:YB(YJHHJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?"61_{MF[p7e޳vO()=NpbF-帒w^H*3lIJHϰwFV@A#Qt;{bef>RwRnnO͞^٭'ԉ>dP!'#S.RO,tY?ʩ@M"=65;0nUsזHK'MUBjd1Nay#=qsQPH?&7jͲ7"eaڤ)#jK{ ˿RHeRjXm+l4,z֛&xcak&QT+nN$?uq%\m;$ͧJ~5+z¹Ԋ' Vݝ |'XEpe,TSLJw\sgm͓5 5 zp>ϧ8X7${Y27 5Mh$B}7'Q7.YDq>tJI5fIH }7]+4Jz43@. fHcר6-|og,k4 AV"ӉkI@T錏\-MRV0統!=Ͽ=k^ӯ4蠸PGd/ԁH1֮hW.0yĢgT<ŖǻtRqW2[Z9sT}*UsklϣoRisՈrUȼpfPW?Qrme(,^_Fֽzy$ddBFC8xKu1#9_?:֒vbpV\J{ue$h E֖.7N>\?ZG5-FX7 "׭nә>#j2.]°k\q*0J \޳)$'=p*6(yf`&SlY&9%򢋁Ѐb[k1%x^1ʅX\,+K&97RsZk 6F g[HOt$P(B1֢neރS+e# 6Li&ȹ$%ɅIp3N7'[=kdf2e άr1UqXٻ^+i`{ W%#6sNy95njMãg5x~5{t_̎'H1gֹ?(X5N}@ϵTdKW6',:3.T[YNh#?v@2C_G.op6 ="ii"b8Nw)CqO%Ϟ.2AZ7.tFar2x'{Kgwf8d,v8u;e;Ȯ<0ZƼe.[Zث/]?[ZI4l3\:vj hfwz! l\t>N_\/ϒO^F$SC2Ӟ*\N8:Vr̍|9܄֠kho>yCmyg%]>ҳ %Ȝl EtSI /&#~?Y9ISy$c|A7;ךf|Ydshe"sOcqn4hRzF?Ҋ.^b@aŭ1Tsmt@XseXiіF\Emr0YSZ>u&KV eW#B ݄kY7G:V\|TF xs0֕b]Nˊybt`boD7w,1gNܩXtfaE&tc’dzQa܎ӿoּn4Ze`n$jl<{ڰH鴟wZu:6)FT}¬ũ1E9??f{Im8}+=uYeVB@= jCjZ$K4eARp°&IU=6ǵ-ՍG <Ϋ>e.C[ED>rm{X?.耀A=j>6b'p T_J FT"au xsV-ky^ۯE$JP !9ϡ֖1!IT;iӤ m8Ҽ[d6D8u*/9B>R 304gCq;KĝNV]؈,(O]? }(# HbqyҧEE>j3)Y4wVpELݹ4Rr~UUXȤHDt<8<<\ Uy_L l>w, G0X7)ݰmc{VvzMsfϽg 2N1M\] >=BV^Z݁ÜEZHrnʗ5a4/ESt br?(GLG$_^8`2[Sκ[}[E F*3i =R;|^svYUMB|9: gahvi :3\D"2̏'~ɢ_3)54i[*r+&Bt32+sz 8 qV9)4#恦I?t\ BaU hs3̌)-p@.mlV1+oĉ,eή7j`g=N (WVԊ1i^92@U8)Y p $}HoY%3?ԹP%s; Ir!ݜrPv&axcUʱ(S'8XQiqjda6@J+#.k<iqT# HQАOUة4wwr?yBdw5vH]Ydn=N7@'GRa Y6 ܛT<3Ӡa⻈I.IN? vCdgc#T5Qa6XU #~Xʧx5Uđ(h!*<9rO$Mq_8G}P:K浕yڳ|e'+ū; =$6=UA K~'C˘o'P#,e r7$ukMO$;+?ʼnEӀySL-bsy.a:y{ PI4jE$7lJFԇ㝒D#߁n;O&+m)#⊻EΙ&ޒٳEMʱtb(*dt]+0*.J XdJQ>!@$3MIȾ$3ҤQ;n}*jsl#n\cTܖSUD R'فYIVeC`z^{sO } C]D>|@c@{MYHۆ#q=.=RDF/s8v+A/ӇV`yqμ qgz5gIpc ɧK;4`.5 Ԯ8с~qdЎ8Xa3xӖ#goD?#+?ƒjj*hU4ڥyX )]CNҁ"H#QJ74R旃cqҔ|"T@ R;b叹NʃIqރhsOy|_POFz֚lV,1*YU=5+g]C9+KNcrօ`A`t2(uRx_)&3)'s+Xg$͘ElŁz:\V\pr8a{&Hca$ʰi9؟L֗kr,%ddӼ`2#5n#pls328B5WDٛK/ϻs3O3?P@c X~u"ޓI6i<Ȕԃ)LʻCz'>NC1 zļ3d_wnqͶ\ES.3\Eeby'E:P1x4Q@R P-ɧQH#}iQLt4 PҒ(BzicHʤzE;BEgu;0*"MS1qrhz>tdFrːy[W,y\RM R<$d߽♩z+Gqu92ܻY]{vAWRg: N7%F_xcza_ezm>.lAw(p&l,)ɧbRIHq+;xhp5T5d@ s hzSUom(ӏ׈Yliejٸ-Nm~-t >MIȬ(m $cb:Lnff\NQcl_^cW2 q⡿ ߎW%R)q!m+{~=c~ l{i ̶m }m fÍ6 OQf6J/!~~VV 6mF $IrY2.>7)Wm Uōh'O(M0!Yh2#JS)IM6DfT0Π`ϔ~13OM<'}EMM~VH˛XqkDb5DաjAvhAp2wSc:HNpڗTt m}@d\ßbՉZtVJn{RyVN>Q{:qU-3,0O"ǵLh:U'(m _D?5Gci7|l2Rqe\&bgaQ,3 !岌 /^$x% Y@ZXpm)@[Nv'sq]s,\=!V % B-lM_ʇfk)C)%`u=&O$X+7uAn0ޤASyE)봢,v$=/MK2*,P% nokcCR':B >k: DSL($: Q'ILts s.>pF8=sYRmRHM:E85 ?Jҕ޼I;l` j̄!:nRgX*=hC&&ýR:jS4;RA޽TN& 9Bígen871V>eeF` Ho#q>PZXR%ċgP@V̈ac[ߑ^iS SjB@0;ߴJ֒] }!FgAg5 YSؖmD@n>N(PSS!nuꏐ2?"VBTt Z ݸɚ >]tٲ9Ǭ-)WWRn MBU*J\nvCbT@ŏh6P$DfQaKdq掰tFb^Pޗq[/G6UVCrn c:,ԗCu rb]J!|o8a h})z6ShNr>)z!ى^~^aƅ/}m4uل6Tl @?//FVNx9{|qBcU48!)T԰eX|~T? ӵ]>F&]ZdXXbtgTFr73.[ \8)mvbv^EyQ9e`ī}Dc)r$ϮTݷ [bS9JJݼ51BJ51A2hszsGPiRȑ4̰) 86xGZɐȅ1ZsTrR2Txˀl]e9f'2SP*m(%972Ue5/?/8ڈt8-F{Ɗ֤ˬVZsͼ?ЗPB.+RE̶ qcJ3SݙUpO'?hԉVDq@Y;Dtܶz?`EZ,E(&kt]1LbYR^mxv$u"r)@:ȿ|E[Mu5^e˽,oVӓ-ށ"{qdȬI*TCj:3Q't!2s O{t i6WdI YAUqS'(ڶq4.^l0I L=dQK'ź[A2_jֹ&8r2_\J=q 'ZKUϤX%C4$*M(i ڔ/gӈmwU v+SAevB}$Ry-SN:+ qD)"1` ˲R!  K%V HwHkJ zVr.JfoQ:al=L9.wQ@[kZ^CU) Y _O(jJrX.-EUzO-tֵ]V&%n׺wzړTME/ni)MN nԂ[e$ 4tܫK*ȇca]O҃OQ9[ͥIP2G#+HV$-]5~+K##OX_ZMLԵQ{t/4:lϐ3o4N6ݝ!Bd[ckU2.ʲ2>etG}OLxV 3Zy(zui--rg.\NE5L5>[srw,g"ўWzCiEDmr&n(+ai&aNyVS5 lOJQJV6I&XsE4oߗsqr$#1F|2k7*;Hu$[ݏGQ۱獛Ml-S*䶛̀=}3mAu1RKŴҗw!@ǧ{o>}-o ̸.S%x JGHjG.4bZaHm%KI 4A::0n6'8ǯ^_~z|7EjV8)YS[qcHz2҂.s& UJ3JHEsϴ%;2ࢻmcZ=A~&)3;$%N9;rlF=Dcˡ:vJfmAҥ,{m{E1KO&-ʫRi`ܣcJ;ITF_RYJ*9ƥ)I?j."qOy6}aι8)(0!|~ϛNrAǼeX'u~M9-0-9AI>ٜSa.BU OTL _sy:j+GV ư jpJM6 JlP&5ADMlM~W1+z,S+!Qٍc>mHZ{,6ff0- JH5(  !-efxu3BRrq+(E-/1HLSCm(Pq>ꎠTH)mv7IĔ\TZJBA=jx=u\WO"wRϥu}*B*ۯK0hi=,ĺ-"Qv,G̈́y)(X]HYN- yH`zEsh?5;)P<5|yJ*0cԪ֡/NO8d>T&&]R[$XlnΔ$GM;eʴu$_YJJQQۗq%vqsȰaVJ@98Wy%4L]]JnPϼ׈sGWA##n (/) bdw'?~3&v ymR ߓ UQH2҂8nl}KdX@[Dcs 8.Tlx[rB npoƝY*v׵~m-6F.a Kߎ`6ޥ$,MJߚ62Eo:Yd.6(ApFӼGE H0GgZ** Rm%^[Kۅb=--HQ[bTH zfKjyŭ]h@>YaTIq)+5.Lii'n ZIؒe /j}hI6#?ߤWUx-jBVx$HQzvܔlj&ҔHͶQ5WKIZM ֆT\mRINmJ‚RYC3Z7SC+u )H*#?HK-'eOk'p6d7fe18 86aGDِnE bۉ lCJwߏJ e%\C$^*SZQIGuNbjŰ-ܜsP9O(i?1G:RZ,EEͽ? &4=H}-M1$DR͊ -! (Q2B{S%OÂĎpEՙVmG܎csI~gU FI$|W#":Qqxn B=4εO nimԴ,sl^2qkZJJX2kQ896A| ^a@MbMLEċD)j'jf5O07iӪuiX6 )^/sOm\]6"8 ~n|STܫd%i$(z]rw N81=%݄d1rׄ[SqڣQϘDR:4]I/$2HPd]OA &f2x$(O0ڀ}~oTfd J BE>>ju ġ;R ;;xVi8m,m8sQKVL5WhҬ˶$؞Oo?n-%;hJT/ۋC FZugi Qb$[GO鞑\[s>Il}o)]?Mjg˺xdpx6LPPChi`E-RDrUKƔ qnX 8r<_ {SLiȪ)::%#"SI~~[ iDƥf7,$&7D?I~+=ը~Rw+"v6#FM.td6jhZu aej\9?H53lu`2,Uq$f>zgҤ ~>ѝ%PA}BI6>qˢ&|zK]JtܱRq/o5N_ժUܪXl*X.~6ŠwSi.sJ(ew&ul:5l֜z=NqHpXmb#Ϻ}Aђ4D*/8@Ag.ГW ~ߎ;ECOtrOm3⴫X\A xȌev<ӏY*nvQ;|GPa@3oo,ګጳ8:WuoLOP$҂mmAf&.E7iPM)2ueV*%P \5U~dOH0Hi@ ;Z?U5FJ$XsȋΟC"Q+R\"[ "$D1(\QZNsIMAiIɄbӁcPSkN%`l}Vw\I86ecu!nOaĤEڌ6O* uSk4А|7<%H"A(>`qflw/֝mjal{Y0U՟C;#ʮNme$(Ta ~(q:'XeMMquC=I8 9Kjck'F#qV27O]>6ڌˈؾǞ4bKJjy3Jjaғsxmr/b[Iɭ*BmR ?59.LQ`mlDԚ` ?2K< ϡű(òHJmhL堢Hq[`)<,lߔ$\ (-jL 0"&$%5. 90sH,LQ>AɹxmE=,z=:1g39#f^(FxƦ&ZTҥ\yB(X%C&C ~qW\"@KS  $n.>|fTK"p Ulbђ6Psa [w%7>{SAl%jn{Z"Qҧ_*p1[~acbn8HuY"K|:njXi>RRqD*גث^"gtva-[ť?C@WDh6XZv"yr`ń`eC2jZsd̳e{SRt{SR^y<7\AO `#h*dnK+RF #Km.f#:>0Vd4Z;vF%$Xu=;7+2 a&znYm̄W6sC5-ESGӥfx=``:O!]07&TV[д3D$Д=WBF86M͌\j-veM^.RYi YNb?-8o'×*y}B^EHۀs Bp2PB'8_SD]MKu;$6R-f+tVy*SG ."5Eg F4[q!emt "M +nG1bSZ4h2@]9r܉$k̔$!)|Ë{$RG a$͠-K.kJe;,[tTHW B ͓=i-ظJHϿ* OHA.6qh X6*-!˨J)לU wRr !2]J]?(ܯ(MҔ-a#[h{W0Z3k@PQzq2 Bn .ڷNw.V,H %D 8' qV57ˤyrO8$B qi6RA􉓶/O>)Vm7 eyb. Z:Q${AlF_x)ȶ?"d5 7)Aa5Ap~ B80z%&x D߰RG/(3ń b \ҷnow` oh䰠lF,!;*ɾOsD(Y<,ИA XS(VBN2 'ᕝYW۰ XK$WSVL@"% Vr];@6)<@l?MKa76܋Ek~=III a¨j幄dfH2S6/QK"M1bBFi^ejP2bY `qP몹@'#DL8ҼDqx+oM:qe\Y)JTsxRnxm3@A^08A$b>dk~p`Wq` /o`%Vc9) VOX*;23t/hcdfKa<Ha*=%0kve")T{9&d 'B_u% <'%P 9f(uU(Q#QW=1I$ЛKfRB@} SJa-+̴n2y8TwZ4DŽ?gx:0zS -xaY$ y-o*HL$X ~䈴iĨ-JdmaPӛTHlϵ"qI^/{ _#DՔojBUa5|Pu>)Ғ32]|!g5Vneֲ RBV,xuY/HmhJ|YmbO ^۩韈TK6Jm~HwdӮ-]\[ƔL&e8Z li:JBhN!G*X(M|@I7>J763ajU)( _bK=8K mN"훓cqu/OO|GPHopHA6#)OztG^o66Szh6@O_F4ʓ:gR]=Xz,CtS*S RVz&*j`ح."r],r}G|j5%>2Э8h&=-:B~p8;ěļOYԺHl.`Ar8;W}lړ-oMs7$fdb=5%&Mi-6|I*~yLl^t91Kf])Z?xqd̵!!(`WƠIN͡R/TjZ^vaS x؁x,,cG-:U&ɉr" 3MC>_LiXBPo[jO+S+*x|׶mͫLTNYp f7Ϥt`PVK/jm;±e8qgLVX‘F3OYyn ߋhGFӤ%o$͓eTn\Iљ͸bԡt(]I1T&\\R6@(jY%6JO's2cTaq5&M+de&6TRlBo eӬky.8xih(])QKmYff)Ҍ,OƙҍRS.߇HFkY5'.JT,pą")HeJbYE&Oq7}6bwk캕$ب%6{}"W!Se{!Bxjkc{-zfk6cjd өʙ Bss=,7?^"z[ ?1TVQ:oh4]3x9o+Q=a.X24om@G779>*;&;D@GfBHuj`yRBm:gPfI JU",ސTTg[}QimF(1/7.T!vOS2ؘSf^ Y*'h#"9*fÒsk DsUMA ݵgɸo$U: T 1^%@8h<8_ ]^۞ݭ5 A6szcSS$\JB ~bnN`=~ePjUN㑌:O:bf1νyɤ)@xN-dB0Ӗ ̇P$j6J RgAN.ǝ4޹H.+)>1?J4㎥6\制">BYr^lOH麄TB钖L唠=CB'|2>, ESq1ۡԚ?Nx/@.}KifBJi*xuz5q0R}ٿ?h;U!Srg3#L2 dz׍-(eJ9!H iU.#q͂ U9Sa8qcA&>q@v_~TI [|-2`['k+*#̐`^59+׊l-5JZu- W;/c6RO3:3]11VK)1I` 3hicPbG/*MJH9`LT\<ΉU?bN gd]aH e2eޘ vLMܔrNbE(I&+s[yRUp2(j]T)je0M;Ts X}v sT[HɦmՔ7>kߏg,coP:v2e$8_ArV>jmO1$^yP3qn[nQ<,3gN)K`{͏ND-_16&^j=i~D-()UsPu*beL4D3>|IkmѽW1LR.%8D>P $_1CP5)RV6MX- ~dgzGHVS첆Zr79Ibh*I ZˍZQ;o-'] &\ChGȹ6=]hEs/U#>G8j7#O]G aIJrp{ƻJS0ʒՃ>tt/{YA"sSH RӁJHoq#^y|%ʮoX &U[zOUzAbD .I'="Z֋ԵDS|6?x'ӔJrPCe- oC??*+@)C=x16)؝f|:M7je %7 P@MbtƦ ?C:ҁajS)6oH}_˦jS+-Gys Lj62Gs_kPf}nN8`G9T g[Rg,7816\Y>"TÏO\hS,LRI #J.D[5B٘X#uj'0ͭaeΥ6UH>׼)W"K#{qԱa°bNRfYQ0.Fne+2,u*爙FK6KRͻl˳4%\89Ojޡ&u0F֊%3'2SH6Iz%&tզR.=}<:LmRO++j1fw=#Պ%3ڔ2 EPsZ3JAC@6 yoˤ(P6 #2~ד:ĢPM,vQoG6NVgרAM˲OJN:ja$,m;=qT$*| $Hϼy?j/Fo {ⓨzoh =}' ɛ\TU'>XI۵&'Ӻ)II(wblmuR&Dg׽lF{:Wƿ )V(k ?K/,)> m};NoGhB6B{`?d2>Mx4ڭf,Ż}"/սa\T)-ܴ (%4LUY53\y@V܃ȵ=g1aI2XX[P3tGQ22OVK-0]Ƕt/'vqٖ>acG7G5;]$˥h"/Mr^p (IŶ{G#ZP\|0!L;zb#+d[ximXn1s5OG5!UJjJ Zl9'oUztfb'Nnd>!&Fqcuaˬ7urh .MVfȺ|ۨ8oCW^>۲;.R<,7G@ԕ0ET/\i-SKIMQ#XN3M ȿ0\aoy)q$3fC}MFLef)-*]V.yMseSt#nBECUO5/41c^Xj ӵ67*۽&:phݚq9JSR3#R"'V*t(Hxurm-ᔸR3GյlϨI$cM9 M}5|ݿL7^[m')N Րm$iiRR)#bN8II9otkyoԔ{,`x#aJlH6 0.:Ca""x`]t@m3SexP ;j1ۓ,䩯1U0&n~2vs ,bM,9fk| v#$g*Q)B1MDfzpՋ`fL, Y$ZoOyaf2bSR*IHaX( g@!J$riI R|%+Eޘ*^Î=L2P\Nbd%D3A2E=bnہ"8[)2UqL$lf[".G!5(^=mnX"0T@ˁ' @ku$%_  ơQ͇FEno slC&^D ^m)r]w15Po[I]+nXnR#QH D+$/(!C<1]V@_$$KHޠ3I8{[q9 >m/wŕq6 xE~"dh6$M"nKA99ۓڒ. ^ d;kAʼ^EJԥ?<*)lm9'h;yHky 8$j!TڗlEEY B$7'0ThyT/? Nd6Ҙe58 ';!Rn+G4iN9? x<ʐDBv )çW(Pߘ`zO6 R96ed_i6Ö^XPr,@q$'WJ9"H׷52,dM9YvM; "iHW"x@s{ OIR}`]Ʈa ŏ0]+ R@p=np{@nd\PFm2,}-!36p$ؒ8L42GYԥ! 93:1s*RQXjFFDz_-gz: VTyɰ7bI65:RAwT+@jJ Ԩ ؂btFGiEHd 5_́ko4ӕ UWXidrFŐAs6/T M$w~vʸX41,x]i,KWBa9UGj*6Lַ^qkXM#:z;\IM/ygˆ) w ?6J зv]—6% HIcIydG~t_OwUZM?<:ĝ+JTSx6.ˈlXH9AֺFVkJM̲R+a@  žrUu1` '<5aț#="5osIL4[9۽i]:5Cs'8@q^laJ)U8#>VnYa-d[" $qѬK%fd[mɖh3M,ؿcRhmA̋\|w')\]5 J}J-'pڣ.)ZLL!Vw$I\%,!$$Dt"Shq ( ?9ZӒTyXmEŶHjX{{j@6_?H̡͠3k lo2zf-ɮ{u&*MnR/o1EO׷&A:1 Ik Әi+P*Sc`YM/ҟ)14&/"9T]HMM=BKn-}/5 f\1bT|Zfʼ5wR}\.uT&gP˲ϤqpUQڧENsaw÷$O3&m U5Z%Vu-$4Top=,f X7Wxɟ ].>rlTd-uJX>ڔ[w#cuJUo/U\ xM;ks RC )mV$sFjh10 d%V4ZseO͔)$`î6+e(}.:ʉ<q̈́;Ta.,q)zsSMGp!$rMnD|L'wlg*CFܙ{s F,I7jD2Kqn!:B\)EUڞi.Or-@_rq‘0muJFdc5<X]J.@0Z|++ػSBQ!"k.=G|_1ZW !mBT|8'@J@ (>A'P9)"8\ՙXIKsylB׾1)})hQH󃸆e( u.!$*?_óU66XI7umÙ}BGj&Q'ӫ2?P4y+RJXȾ/-\krBgĶ<[p={o (Ud k{z S?8\Z+qm`,GҪO6gh1bѵ&Kn䝧ӎ#˩2M!\l?ZU'\qnf1eC ͖rʹ!C$CIHThx3&X$$1aΠ'鉕 ~"?" 3ĢMi ,~*̲#U00)yDV]"~4P% Ԛ+V|m;> z2=]5 Gܷ& ۝n=UJlK. X:)F*1"¯ޱߤƫCUȜuωZ5v/5ޤrVmmYZoN>z.ؐ(i[xkFgzM4Cj2yG?Ï>U, im!v=*Եޥiک5YiIrޗRpAK4l(g#'}SX=0%$$4ToQISe(E.R6'i2TMyN ':Ny[s|>7b=-< JhmՏ$$,iڂ"->oXԽiв!96eH;no[:!QZ#`sϤc|LNśO̼%-%!p}3))RlH.)l-D}V#Ț﮴k4ܬˁS(ZT]ކeZ~+6+vUI E;]  'ANNA^*9~DiTϏ65--߈|2Ep|:u-<{qO֕&eې!7'yl[,6?j{ϨCA980{Y@{RWY ]M{ha//ZG y|ڐNMn=Y}sZL6l?"w%>=%%knfcPTYi6[l\\aǬyK_jz &JZ$b}U#)u>jslERRPMɵ= /±ired[ҧ5 TmJ7o1:n.z <(c0lU`? /6*y}j7%Xێ3#@;,IU%*y0jUkO% >ugkD4fs]W55LY)JmͿN&Fngu:u βmC GskRA=څ)MnSn>O~,M@;2Mϼ&jHtV͖j~Su[-̤ Xu^Qmc+2zH$\^mc*nD+ *' MmxМ1xi'~L[<i%܀ [ժ cRJsy)Um%" EJI+Ǥ1ƞM*jJ}n ?4Pޢ #6ړ2rx ӟ4t7~Bc yrвmTro*z|$~R uLA 7'ޅ]@B7&RRVx+M mcʩ~qHne.d$_r;8IhYQ{vXUO$R3FhvV^CW&Sy6Ed!cܝzqLBEn%G (q{XPUzfӝ6&[I~1 wl,$*L,Y(^I-KQo692 JXB!l|;#hlK`3c0&qe&mЫr a@@Dwv@Wx#lO -Z:D_"Ø<'iɂlL8 .T7J /ܒpaNNj0P=`)J6I@ej ڌ,oeK*.+ .\NZrxP2ڹUs0 b D7= 7f7m7d@9`K|X{AXļ0.{A|^PU6h(t$()jim7R$TaY;8vIW$Jeo0=4Y$((`,b|o16J!s1ͣP$~s N؋0F30V1eimb I0j1?ੵ m( rqsԕcȯyqP0"LG(Z߼qV|͹P$y}`2rѹ.qȅضM Qpv" 9$%ŌXT: '1O|'rEhȔ D%&a=(N=bԙ?l""ٺhB0b#9-',p/|z2IE,81Y5_-Na+.sDLHˤ+XX /%V3$߀y805GmS] k_ .mX9ĝ15۵0iUB?R EMJ mor8+-/&~xi6HI9#k<p `)7#>쎇HɢaܻG986wJni!DZێ~龙jY\msD,~SjzHm !X 9=}bn >'H ?R:UtˆʷOkb4ʃrsa]J5 ?QW7COK;3 mJ7s83kX4O-K*A${=ju?QTCDՊ1N?6BiŬ6}{GˇٞVLY< J;3-%+x>U+/TW6ZI<OI뙃IpT]cn1OZ߶I߼$\0cb{wGyӋ*qJ'ԫ$S *ij=TK5A%Tu p nqZ "`TѝJdo 52 JXFEۤ`>=4* +9PD c$U@ҚR +U#C4e v/oh_KeČʩ3*GP>ziKLn*oBzC2XmIR쫓=M=9PY+ = sHUC }vuE7on;G:CPz.۫)6dǕ&3Nz"2 )ҢS/SNJRm!L1q*z/EK4`nxLK B>|b&:}rVn\w G ݔ@Css:Y̹3!kI#5O}#lM˄õjNSKTJW vRE*%|™4 oZi<<ۮu^WE.mu˦U8PlwϬF]Gf-l)iMűEp8RA~nuRxts2-Orm"˯z-(לi0@>`@ b2+\R_VT#%+d$ID7^ȇک{N<>:;5[yxffvX,^`@8tt{DURZ-*ā\\(osF2܌CoɱQǗx#Nenn=Naxm+N/gӈr'N':>u^[RyVA82Ao՝'4sQKQ0n J-y1*zUzi<'t [9U%)Z~ET5p] qz5`&(*| IAxqe?{mHDTs6@'pO&lM)-SYA$DH!j||ԑ3/P>'N!/%-!jRodbZM.J%($&lv( J*TP#u%v_5 ?Cjf]2&X; 'JrI@c'*$4-6J6B-V.o8\'}8Pfs*ebirTFhZd_uJ`8Շnwm Pq R2_izTZnS[n̄^y0|r#u [!f$kLSkfs{M2Jȫo%jyYtݗT6,mIK/Z*odT%IINtǬ.R'ƜRJbm.ok&阥¹}OJ՜ae!X$ƨ}x \T+eh 'zVȹ"|1ʸt4!$]{j^ @C+ {ʷ̲}HUI3 &6 -GESOU7ќtgFfU*RMjh,7Z$lj ~iʌY~i<&vNWkdܜ,*궸Rw/6 qY5zm֜WTnT<}&C *sf*a(R0TY ;gY qӈGt' j^Mċj^^Yj %[N{,?+nm 뎸@uoqB>Aa{ӦPq.(xʒ̾wIBJ&.m8rBnؙiWp~/iR%PU5:NY+6=LE&s )%h]Gj10g1q( ?[}K B%޸[6KRQ6Mwgz 3NRP*RZlnS)u]#$T!^$FU˾xa77[7zio ZBI~aIS80 9pVaxDj7_[ģ#P)e|?+O(n\޸l*k**#_(ߔ6* gsKlMH8S2cWdB$[ARwbI2X`-% C%mpu*yZ9vT-Iq%6Oz8%B,ooӁMʅ{.oB >яDʰ7w/B 6zA} 3(#&Lsm/`Dwsv"* "\$Xv0 )Շd- yIPJ ܌wmI\k)H ?RqӔzq*Gu8ݛ;nH!$z("Yd'b=Sù8"}Q0E$8 z TֱscKӛs3)}FPLw&L qȲz *ʹVl (^Lו)RE`]$ H?̤ 4raq"2IIA.{ AG&*LlGCRF-(|w2 1: ;ͮۘ)D u8nn6*&׵O).W40(,U[JA+o* /HN'ls~xx " G{ a &D% 7HHTpetb"An؛ B lc(< ѩ+\ +\vE fzlH7JR=Ɣv ۴=q)UҴqaTTݓqs|XG khva"b,8˭k'%܂sB]zǻrR  Kd 7v+kkFDˊuJ_sA.or!OC9K^BLmтerV-h:عp`}0ܵe(b!R:`ˀE (.L{;TZN=okDl/Ĕ\wBP,2 k&8"օQ2;2m@ 'S\F {,~`ɟJsdTT V;WM۴.È6kglI*8"3CZ$o@s*px"PY;q ' x$_=0:SIs!s 9py%⤕c7EIm {%Ԡo$&)PblxB8RZhNIje͍Ϩ?.NN S[Fl1$)D!5M,j(*I&\˄98=!(+i?!-a8pdВ7d`vTI 4$ XNZEʁ WatrG\’J?#*OfRBwv$ q{mm8mM'uԼzTnG 6eN^r]%JXh;~zuGq?CbZXV=={FLӒb3h؆#7G16F$ffڃYuL\Eeg}]*RZ`ZZN>CKɿ{V6H򴪤Se °vө `H%>Ų,HW޶qxn} VF& &fb*ùLZiIgCv?3%+,rr9VDRGBW(_b-Zu X\I,[nRմl h]4dc3zX%.\Gd];!6m:mLlExXCgҀV6W"rIڿawTRw& -oO)%8 EV;3*|u6lbߩM4kB?y jS{\| ~OS4ej̀8TRl >bǾDVys(JD|X1qgV=e76Ժ$ϸVJ'~LNk:-za)Bk`)X87=THAB<}/x?[/Xku96k] ZcEwɏ旗EIeoݡ)^}vZdK҈r^^u7\}#T ]AHCrKS_bT2?.B`eBO,O:e8'2Cmf7twNfPèO.CY%D`]A7=L%N,؀,>r SD5P4KK!rҭ*Jm[MaGγ,T>r/{Cs[sII%,ˬ..U< oa  EA#n^:}U'XIJ6ѱȏQtf+3 吔Uoht%l p8%q[H$90c= z'HkKRF'Kjq(elF?[ : <i|ӅJ okǦoPS ԂKgrܑp;hqSeM%}#T:KYQ~.TW@jZUR7OZִ{MX~m;V/Ag+N4gLykZS~ yX^Ӓʥ$ Rv˹&GGt|hp'rPm1=Q)5)DUOgdD鱮0*xgzkKnP3 7^\WMKeÈ=Fc.r= m{HQ2^|%gq%Ez L ^z5nT--] MO{{ǯ5*^]BU㶰@Qō9)K \($䂊.vv'8IM)6I yM$7~.Ѩc3qFjr;ۢ6ڦq˂Ekškej6۽JDF賍)SwK#c좚XpwWoQ6@Eh%$\>mNv4>&Cg$hIK8U ^~UjZ7T=Ђv7}שcIVҶ Cmw柈\*ݗZ q$><\vE2FVCwK,~W5i8%U<$_hҏZMӺĬ&b,@ijE6dN"~_&vFZq d4k] mshohAgRc;ϛ }MՃSu%*Be){etO!~" .3Z3wUzm5A vaa֔|Hq7zƾSy9XC_q?=ȎmVC0p ?Έ5 UU/c|*47! Gziͬr¦C ǂSc"O }RCZq&LIzɌHL<Rֈ-G+5O97)MXudo.[4'Вfe PJd}yPv9^~jAr?0Lj21n 1εA5E~MMKNX]{Gqҍe HH(~̫ӎ14Λbq╧\M A{d߶b_Қv0H4 ʐ bNi-.~=HI]-RefDm_ľt >ORAǶxS-+-%}BCmn_*$b&Q2FVuG·OMt,>.Z^@_>tVhR<)/n5~˓)iERE'Y-3(ۊXw$zP X+ʵ_Kul~37BJZfem[zCM8% 4OBtZU7#'E1Y}8a;05V>Q3'nGk󊆾FYsM p^ֽZKO<ۿ'w=oX| 䨯A8G^ne BŎ.SϼzZ}Vq92E!jCY՝Y{2ܓKv#bČ[Ǥ4:UZd14Vڗɐ9wT Ϯ OTe(&NI+e+!w#/nTsj0xj(ɺP'$>P{'33RM4@OJXs-m-C )a R4:hU-@kQ Zҵ_ir2)Q'#rUNI$PAQ+]wsO5%I)B|6֔I<_>kEV0ԓ˺/Lj iNn4*Єy>01cjapw[^'5M~VE4t( +^ָbHzR&+4Z%c Gu'.gIϦ%&w2HMv%+>sBտ4SFec`Epv;_vʚDuo/fFuJLi mcvfeYIpsF'>0zܙu)[h`,~pOjg4jKd(RI ySpkLYy Γq30@S ݵ^_2l-cw>ohPw9Pl 'jn]N[BLX<"w?=mR^rL+DtOMzihzOHtĩe$<#)qvN۩A7$' ?ў2ƇK* 6f>'(\?NچORM@QIR Nߐ d/cϨogCMQWAMKϥӸL8ϗ[1Z@:=ZOhc/_m+_Ԅ3 :[+M55JaZ`6E#N#E|ǢǛᏧZZzGiRI.ڀQ qgQ%U{xL9nW~уgah:Eʙv- *2tj.5EH'0نMnQ;1>=16԰Q 4 *851&G)V[Iˤcqihئ4#{l&[zYab6J^$]t;((e̺=0:[%Lu*ndM\NL%jܛ0!G1KqD >r)@-]BVp x:Z ھZjr—1.Ԃۿ\Ktwf37 &{*O!KG؈uνrn'4@x3GѺ'H(0(Z)SX[Lj4_]:fC/HRkglHٙIyVv2`.,ENRKa~ JopG6,#z*ϕ}gX\*b</3Z ,%+(rT,IsVY:!Oځʼ\Z>KSeS-(A6 hA꾙Lyf& bd\f8rϔ;GN^l^F/[Ͷ’J ?}Qo{D&e+/ڌu%Hjan2ͶT-7#3鞫uTJJ $Zr2O}N\p#U .} SB=OhdFxh̐RlOqD-sx!QݎВ2 Q@]o1D.&$IkZ[V Aqm7%i"l+{G-T`1kCJNX|4ZauZaR}aPP6ź7%6Qx)sXe;RxV7 ݷi; bLu&lNn ;;`Jc I;DlQ Q;\b"XJn}5jC$nIR`;!2φ(-۞X6G]kc9eeFF뉅C`@㰄\d X'YFM-0ڵYGaXhETlbDnHF1 8 BDAA)H)V8ZNÑjmK.x<\MK6)JN0/6AmyB9s ٱϦap' 9sL%1TIW^mon@l{^e7©d"È;G?I K>qKq>*B 1VtOJڟ>R7>VRYf^DcB>ʒn?XAMq$_$҉i7B"!%m8#$q-[׸!|I&U/r R}MrA2qW 7,zߒxs !CVJB 5ΗQCjla-ߟI[j#FT oܤߑp K!8m4ΚhPYG#pRa,]he-J"{FcDꈖBPMAUz7W=.@`|u3MLBZaԇ\VU{~)L۫6ssh5^յ/|4UɘPJRc'1"savuEsz~VTeIO]ǬWkzm-,QVt$mr?HyKY/R b8r$IHx?]T̀+@zņ]L2X"s e -KB6(zc.VABt(c~PҜ7n,1-B$RQ*HUoj>Su{]P LiZng%R6 nh̄A ێ-Պ(e RJUbe$8 nZrZ\ hJZ 0=Wy:b?k.enh)ɳ:1&z[Hi,ی򚆛Wy{V㘫u>sJjTtNOe'/>lݵ$~H>W,ьmU4&AA{FHƿQ?ۏWN^6",E-۴y#JZeMTp/n~R:yzzR?5$@ Imb~*6Y xSC{m=rDI&88$X>T ޢ=bV5rXKyB^*M7P|::78REMЩU4NA+J#N6]ȱH*)>& 9qW˟.,zOsHJ@R"֌ҳP~ZV`(<ͅs{g}UAt` \6Z"ru4ùW =L`w7OnsD:W)7vNݚi-ޅZgtɗٔ¼7G?z'^hJIlPG|G흈STP[ersBgHq2#7mqSC>}?_f_1 RM5N-sncdQ *NWK&aKq`(l6]KFBuL!j.&WQzu1:O$'`JRRI~@1TJ&RrsO\3ˀ©6\ =(ΜW"5 -ha3: 65eK* ߌ;XBDݒ, n=ADtU`m{,s*|Kn?\))c !RHEГo4\3۫S:|Wl8 6' !lQI*# nyiʎ <7o+3MKJԀo+ hMiCUD 6;`0l$nԖ;Q7\gY=MTJt))7"\Ti+Wpf'BeO($Z'i<]hEX6YIR@O7;Êg]nL-Nob9A!1N޾)ˑO3fgR փf0C+,ߏc2uĀڂp11$ɖgQ\p^_6GP)MMq@ Χi%k0&ܬy f7|BL٪%mTl PBTvMy 9Hj !{\7$\_:fyIri@Bnn48EuyQɋZ[zTL ړј3E)`'j}ǿ>uk4ZaFZЌ=G:'+e&mFD$ pY/KH\RFۀ,"2Rx+w`ׅ֛q mnT؄dsY ҲHn"^#܋mJM!5u2V3I[n)A`!0GNTҡ6ls`M(%532-{rCVͧg;ĴWI$%ppB=a!'0A7RbZr`:jmX"-yw7׿ >l98sb=SKS!W閝\𒬩X\$&/BEa U*I.2Gr=!`x0Fo4T'ڱex DGF|-3uRHJeN7IT|`|5 b$H\CF @>?P/!Ŕl1OѪKLr]vnTT9+ohVF,ʓYzuWM'Jn@HkHmiFٖWWCnR)$_w>ɉqnAM孻oGӊ%&.YM@)WݪWHNDmWڒ9"Q>-C92)u3ITiMs{-mՅ{J&TN*M6ܡ`AW}e]K OxWoszNLl-B6aoV?HmYf㊲AIG}H4ĢM`69X4U^}xk }/Usر~&6Uaᑑo~`ʪ=Si qM iM?DJfa۶6JPB5PP& 83",J_y(QćKNo)J|kN.?x~֤ӯ )I7r7Uw@Hϱ8 -{{vђU]I6^c$L-B:N)6€ P$BТ mFe*H'()4zcuAȱy.K"Ă|ƅ9iID:}hm ?Y{-5DXl0+o)"1iJJTYC^Gl}b%4Irۥ_!wUh4pEjk^QS2X$(n#8 8j&S~#:e^fV̄ 6O+Nzgm\Gdwm#`URZ(R &V?IQFLuyb=.٦fe̎mYMuOӥܬINԬ(]@:@ɦ%w)wǒ$z1SԩDSs}n/Lm6{_S' 96MrB7=B&6'@{Z:iniU)\t'\2^tٶ$aUnnufuPlB,+>Q{}/hʾ #G@CϭY^ѵSsWdJԱrw${cj5Xj/It^>'DTy!*%ԗBBs<_ ;[dk<[VrYH< RTEx6}?~-#h?jjzŘq<Λ̣ dܩ- DUjʑ2]OTD+n:QJp 2IJU:{)RʜvL)X8^ %w;7WEFejw60W$|TAuG\JSj&2jJlmqnb93E?8(؏xbVs|6vWhEWKba6'Pac;*`X#hlB>@=/]J^ʤC$~irI68 ~Q+]m2j!ː3Ea URD/ٔ ޕ(Zݡ ^sRԌ}a5%DmJ |qs:@bVa7KIhyshFԧH.oIe%vs̡j)GpAY$A+p, Àf;hP $r `^Ucl7 ">efI6Dn${Sj8s lOox'S!L(]8b7F Ҵ\ &)rV $iYBXAj6fV1Y8)76 )UK(9+Ԃ0!2ڍǙ&$]JdA(H X} yQoXiQ̄ie՜MUzCHJ~[T([nEG8 }L6RA6vP└ņ}GKBېuw#%D6͒Om[3 g 1I)X ht Pi^  ^U榔˃`򔓿7 @q|x2]kX~eĔCVOm/MnoExm®32GUUola Hh ߘ cwTmRI72,--lyNNPm1`-Q_+aI@xplDD_EqcŖ?fjTv'!aR_Ir/ ZBrIIJyQxr<%qFۉW`=H/%fUNhKS^(BBrƅ4^#RJ;I'(.g5q|7A9ScQUnE4U}3RE5I:.1'D.MXU&TyEAjHr>;Pe2Ԯ__t * Up-P@/aI\^.kJSW{X_AaHGaOPfdmJ@ɌVo-C@%)1OTÄnU:5v-J@>KjaNx !a* 8h)^CV1De^Vd?hKYBUUu<íKh鹱7SԉtS[6 Y&KTkT}^{=UmkQK?o-T*JfKKRH ZtũҦ9hF J+4ޕL5,*O66hk:BVi.u#_g# K>ڔpJo/bc+,wpsG!rY)r)r/5V좀AY*ZT,bEZmIuЧ.nsEBJRD`gqɴ-DogNb9(;Pc{Z^p8woR4ԼR ~Hi)M_iAϨ o(}/tk萦lqcjfqff]_Dd4- g A%@>iʟTnaJIPEs>̖ep1sJ 9ϥ -`-{y~WUi'd)zmJPbto7He;2mD栓[:icw {tM!iPЉ穔OkTdKj%[wxU^JܲQ#?2V~3JJ&i§v䝉6)շ&1)Ou--Ie HMS!vtVb~I)ݢ>F&Wc|mah4CAPq).btsɷyڌWF*&e]!$raT賭U߭-)(ͤ6?HYgWG%J]qSKVr)jq$_q/gYMF/wz!ɽO^tz $W7˨_H::%Sh qw c=v*dU)WR%KdE]qjI_gsLɕ'6 ĦϭψzI<ܿ ]UWm$^BQ8ߘ?XjF&U6Q,e.Z؁zDX|LDf W g+<7.c^"WW@4|%dfݏFOR~aAsj+bʷO`-SpF:Y厠QZgX\Tmt!$wfQ!i`e X#Ɩ*ohJ =4MÍYno{ǵ`EMVR)RfUϿ迆n% 4%_&(ؑrk;f=dBNY3O-@ 8B$ b6>i>vA'i͆RhkNJx~qi XpTf>3L&bFitVבd*k?>fkjFhI:SXQIܜ붃>e5uu6% E>1EhN2M-/BJm|W^Ć@rxN~s}&pRU<̳JNێq~Q+32l% qkǛ(Ujs :[hJG]W$f%BYK@REo.q&:8-@q'nDS&P,v<}bߪ9teq),؞8 NTfQh &xrV匲!!J͒v94շ;><hiR+,s(L7ocZ˫5M.( iRVӨ݄^ָcW:EӍIIeMM4)*ʼn#~QuSFK:uRf)ZWsJ߈J/|S߾c]:Uiˍ>Y@ό7*{X|jYF)"°{[KF%l<$.vُY#!Zz4)F鎶r[q*ˆNӎ-=;5&kNIT6 ]Aw]Ogcir[n,A*IyDvBmBkks9N@# BDN S4))xj7:ȿ,y {$~񶬔鷿x^QZu(V0˛bUf!^;bq I>WT.M"T94 ڊUrcOHoM)s(m bvQuDz_DdL&K*PNqWRLIl݇=cd#&9m-!wlFB)Mqq^ YM@űF:MrN`͎b/Uu ,Ͳ m6pޗmB jvo2 &iv[qoa|q UʝZjIu' ;_](.KQ II̢I7~JA}*ImQ%[IKsX fK-{ kj \IY)4RH)D62$.ӎY"tIe*cj@ )O )gx.n217'X#Ĺ##o0N3)ɹ|dnĕZK{LĴ,LKdJVY_ g+H3fF׌@ۛtp ܘ [H\dŭҒ1H80:1RG"[ܴn| bIV%R I "By}`m-%%%>㲎t>"CyiRIɕr.bZ*_?AcO ip¥~1~;Z䚩iɳ3v$62]UK)&$ˌPL#%fydl1 ̓s,zMM|ɧЄ">:O_rfC),>(<AoTV\%$q1 :r BȪ~֟Kk9%B'0Ro$>&u}K-T\nJ[SI@ Uo5qɏ5; aI#{f[RA}ij`_17W<Ӭԡt.+ych'ZoufVaí!IZn A_&>15+0_ӖUkuNMUթ ۾͍>*zСQOmr4[K *BA{sU-w^m:TSIuISyˈ|A+&$s/(-8 6 ms>*]NnT-]1χrژq=ߧ"ԝR%_rG05ߜJ$_tl?ُ#g5-2ʚ\¦_H Y׿iT*LSμ)>hsroyًQ"4zv4Nu(i +$c!䖸jZaP5WuƝKoe} [oL)U--={F] u&|G"$d֔!e*Y78Z69Q(Ui*5V-wm˅^Rn/cy#(Risee(ee6bIǓ.9J!oIjMSHq^ +%n(!!\3,uF&ӅBdoxAꄿNUKzR Bp/Kߴd?}SN* mi{[Ɍ XY'ĥ&^%Z(RXP΀պZɿr.$߼|]Yn-ˠ9 pmgPz}22Vx+u?ϵ WqY%0|i/J5gE9)_y3RoYveIKI5Ryqk 6$n'}yѳA,ڝBIr!&SQ47( 70ϗ69yHق#Wh4>M-)jġoO^P&ͲIhHs؃*쥧*"QI 4 Pž"tN56٭o%i; YiQ>\|<7I=:fn)J RTW֚oSNԚjYib T+h V4-4gRY'j9,S]CYJjtQNИ *UOzcViJ{22E+V9DFRyELSj> YǧvgZy+D[=Tfv XcGzOH Dq;8M<ۅMxKm}O[OKP vi*ԻP9 _=1^.r҉  ^H|>toL.tT__ε@)]:NWdDqmH-Z:ѵ"n~$EcB*Q:4xBA]]`'!&l|݇LjMbL[BI#L>h7^~;qjA;Nx>h`?C5%3ڈvOJ:*o7R\VNg7UB,I|E$*cؔ9$m> 1q0YHF)TSdp ӻ@(Sirl#\ؒ'iRNG*] >*6nNoG\#GRU~= 0KMC$콿 {AmFn`(Ym{rM $yҔ#r,q$hIHOB P7)̸M%74xB3TwR۲ dgE.x@w =L)(%D"|iI9zJQHTnoB* 5/F(=$bhsS* >{ߘno`\r#5J}6Z'Ǡ2Ȥtq -v=UK7{[imFۘvfCJ/ɶr9lsY!\)`}]q9 S\8=1!+LuԴp2#mQpCpJS]$~E#SK.6&b9PuS~5ۘF#!lJ9G[y%jo(/Xu.¥@De'[W"fcy'H*+H $&M = |]bBoa(rd]*8)ɰpRl󿷧xEH] ۜ9 6Ky/-]I_P,-Cy>حW-`߸dDg9#3WEKZQyէR?Om{Ҏ"SZtX$KaԽ)=BlNnDrp\@Re)].ϝ'uKA+i)=$% :I[i?Lk 8 LYGMn(%ɿ$Áj$85xڴG } }8mDsvQ;ῢ5UR&2 XTlo/.ߴ|Ot]:Zq$dD#z<ܫ׎{ W%ӥҔF\qN(|8 O32IdjMH1S54I*Vd)$XpTuOOYbQLV_a?=%[n 8Fq?XbbMJTXZ?G$R8`+PqbuDܓi#u|q42}Y3T' t OO6toK \ZN{q˨ʼnsG^:FV?da Bv'U\5J{n?x鄺2PȺ qx!d`3bqu,23zԩ 7'K!ܒnpMck:dxq&>H)J搡@EYWb[T 'Lr4msI͆=l1*sMԼy86جmjz'B@vN\mԷ/tV_8apSR^S2|f+ 7v}b)Fq֖]7;zD18䒥^mqr7#<74}]t!^HZRڈ@ v*|М񔕶vXwJԳ2Ā8}!H"+\ ҤM=1PumA"YhRi!AFIN{uS3F$!xG4t: ؏!]Mў%ߘl-~"5+iqWQEIari"x ytmp\ ( HS툓S?*IowւËA;'b"^v>$d]J= *4Զ=OQ̭A%füXq)e^t`] 'A'46Gx=0 !ēfݘqҤi=dʆ E!_o5evS DnZw]0PI-jT,KWoxfUD˸ݕrU ې#;MLGiڜRcVH97j'-?-7(Ė`fHRӹް>Zk?bǥ(f 7%i#Q6穩&nqr^ n=Y4 W0d{Z0mYpNQ%K#%GEWHg5 Vl▋VXzu>Y P<Ɏ̌KTK M^JI-! }5m8ʙZM`_Ogl%An9rLWuT3Aa%KCWֿ>zEP 9 )9`?:DZ@ yt-T!&⃸yIt]5vUثf^rY($tE˨D͉H_S>mFtqM$z\ێMjZ+i5nTczOMzLJ4 gET@#'-k.kT(zQ (ˡm 1+"scϊɯ-KW46⓹_S,ǏK  o{_t;}DnP}+uƓr18mtJLRHސ;wx[r}'LQ* e/ |F XC/+h͎aV4l~)RNpIBV%@f; MvDq+KƿdRwtLI!Vi SH(JIg= V 06ƳM,~ Sid(:KW)Z:m X}nW%(oL̶ZG7n)&hYdW3Ke {хF &eŦrVaAHXMϿ=okbўVJⲧ;DF5=>ٓ S-`mco# }zѝ?GTf0F )kd ?FEjXjI$CT6Shq;Bܪ6}ۦ?uiz$[u-VOLc|@[#ӮV'=gN5R*Q $C+l%7 EӜU&p<u-V;I}Q:XѣIjfY(ni.;~H3g1Ӡ伳χڜ܄*l9p\õ0ɠyRiC^i8䕜|sz=HOE?2̻` XELzCJ[PE.rI/GnR\J$ҐblUqo;qRPL 3G:ғLm7'8t/ETE RS%078ܬ^kSJKNCXXJ.J-&GlՏO5- EJS ]Ck؃鈛,#r}􄩨H+M Kܰ3W2AJfFrm 7JT!)\7'IyZN"UtK yR IڗSo%D(\ ]3rR JN{Y-u֟u dijc[;mI*<sW"n8Bi)Di:VTӳz>P.tK,2GhRG(=f]/QSJ妖k*P+*6H!=O(0\ꧪi}L5 'zv,3q3/r@I*6[UaX\=iP)=~;N%,6cZC˶ƘnigvţH'4⍉'ߜs%-^[J|.bWJIU% uF>dUbƜ &apæciԨi/|V[4eż6xhz~ᙒ|$$!:z^A6,rve!:츝 .J7 KNNkJ us3ԙ[Eɹܠ/]v#edg`hHOe/k"ip0SXI*Wa ѓH:Rl֕ Et ,bDigKl('@qBu6OjjJp iHESmm!qma4NJ,[i.V~sYhy)hg|aq"4(ғrn^{\4*|/C^¯Uˍ;,4>Ym­taVqIH܁3J_K(ɱ&X yijΥ-4ܣM4Noo_9nI Rn|QLjJ:X3L2A%l/q{Ǜ>.:SsEQbC ;a-˛c{IgԲcr]hR%AGuu. ;O=U2WueWK(KD?'x~&4jGRή}M Ys꿅}K.,-J.ID}M鰂_pPb͓.ZӧWnSkRSI*m^&ҴoTHu?EĥJH~( {l{6tJ[¨?2R<&I' U͌0zI)0$LY&2JSx|@Iw;rK<}ac?hHj5);uߚ`F޽ k}J-?Wkuwh F(Ή)CsM2HKf*5a2y+Z*Al:éTZWx5)F4N͹:S mHHNq㵽:RUtX[XB^{Z>*TmTq  Z~QPïT;UΦY7CvfkB'ff&mskͳǤz~^(Lwg8dBĝxSJj}*R] L̤|__6RO5)+5 N1kwS_؁BOAڞcd&fgh9Ih&m K@JUOL(gD;\*0n>`G~o[xݥ4Ν2Uʕ4w({hu]8@vu[M$X1xߏ9POMt[*Խu ./g\]C"ؿΗSҲ"Rufd8i3%_j"&J[xH&Ǥ/jgM7J]Q.^̂7dF"1]+uBfqU-t&d27.INqמoV4HWdև>@"v=G5R:@mN5bۣ'oǷyPedj2ٖt '#uAG8e=sj1`yot~W&4\S) M>uUr`m(T,OacM4ejt- ;0 >}=Fh=g-I$m{p# n3}&WK^~@hzEC h)G7ɸݢ$KJZNTI)7 Iڬ 0Vauo(Y r=1_eٺk 73&ZS!w&UmN̂87DIuwR֨=FcMԔ*y@TJ JoO\q j/LRtj)o=eyq-Ɋ?P:{ -)B#=NE]n,=?J*Sw]I7e[*JSe3L&S~cDx EEa+ B6$# k +\bY 'k$v"ZZv]xpZ1IJ IܕNbU*)' OSѓeI̽A6$G{؈Y m!tohIaPPE:Brimۑ`m׉LӨ+@cg+u^2PBA9'bra%ԐR6)~n:rTg|0̫jRR,qcă ݛ )YH݀#0c7ȕ:9u ؑʏ`}9ڏlS[-IUb{}bBJfj |ē6\ 0Su)]b7-;J z@IY±47PϴS/!*!Gg\55)Fa<1,9jG\hF|iEĹX]UziT(t)dyP M7 `ni Ȓ(q _.Ο|ZĦQl.U?qg<Į>08_-SZh]{ƓӞPo+ƙL&A<a89CrZ\ ŽF{G[=:UaxMd&waJ΂e\Y!9ޠOWi@CmUJLS+q*RE-؋!-Jy%EJdž$Y)9h o"v?1R\![U{_b*.OzTtN{0X Td\[t-lAt`5JK:iҮ1(Zlu>*) ܡq/옌U#5 !Tœ RŽbP oG6oi)RJC޻ZtYUqM]Я jU9;/;4OG%53,U|ݸcwTVbdOo+i}(KKb@ͭa.ꤥB {9rWB_%>gO*7M$7QRJpڢVT}xDֵBf&U̴1muCvdŤ#1 Pٳ)V d1r~LS>Ƿ_+Dӏhb@7.)Var/sy 1ޗmǓ<&} % a~\SԊekQ-5]CEBx!+IJ3]]+6ÒA-GR^;^:y].;r|wjuStE7$sMH&R7SX8PTk4%ÉZr1FF L(iOe)|N;j-N |NHsE73+lŭ6:Q0f- (oHc(SȍUZ9 E.eTQBq[ oR'؇^b~Qg&6&%>9,Tʎ˻+U' ReJSe @Q>MYM@R][{lܘڙ}H T2-MigLRpoˬ`>X]NۍK}Xlct* W"똬#ql)'wNj@i( XRnu!%{;zMtve%^%F"[FIj)VB)P#g4ֺ+e>\7#qڝ5G'P EG*sfMÉv9H=D  RӁűxI u<˯ىu~bN̴nNGak-Ї{(.7|~f(y?JGIzfWbi^R<#gT ls[9 ;9W5ӯj L8R<7cxiKzZ[hl~f,Hw+2'.!_1Ϊu[KSV̙nܔێ'nO@|=u{XQ:==<ĤʉMQrFTަWmFJm}ۢXҒU$mҖC3sQ\{Xs+v>rC")J*l#K=A[n8 RO8XٙzQo*Q%^OXIW5f[&iYЧ!ړo@LYR߸xgKKkI7s*ʼpY/A/-З !W  VҮR% m[ˤشao궪expO矬!-A]FZfaD`ms)jlP8t[f'"|&6I,_uMIR^Vy%nksڧ!90楗+!4PlmA:E! _+*8 ot'?lԖ=P{FkIܕ6͏KXeS#'4e^VqKܭ X XoįX5o^*UZ\h]ZIR*W>ՕME=%Oa-%ė=HG([NvOgB4۪y{|4)WWaG2hDHQ%G#Ǔ>u?z&)!J~LjvJE/O7MCP6)m RErF]O2}6ARmbaTiA <ŮFGv +uޜkf]dxӲق[f!FTei!TړZb'4ZiǰFw 'Ye Y߈`5L(~r?n&' KwĻ"mrNta&H;ԕE.^I;M;*Zn?rԡ{ (:\MkZ%󉞗 !J2+ra-:ÍAWajs?`rE /X LrwbJ,U߬5n(FrTS. ؿ ?\H8YJPm-*߶o ^=3YmJ-"'͞#85yy/PBKr@6;!Y˓u #X- i!Z"\C%e!@6q3ꮈT)tB*J }/ۼgU-}T4ZeA.oZ@rG. -2g")SzM?8ӪnJO):q7T{zS4\emPJ>DΞ]RnjIڔNlYu %il($b}֙lz@$&ߕ H&J2e+Nz| oLdJqURG\[,/ӟxɐ c̯˶g U_žcI nr DӨ6@(H# ڪ(MB$_U@a$u5pstBUR^$[̕ZPE6V2s^4Co⹱7=| *}NU|&- Ɋ6,T&~x4K /o$cS @LI$R> n!sjuכ;mlw1CMFLJ&B!h_15Sd{10Xu+2dm,lRv/uVbPҔWNKk,)ӎ#*5תR** A>{[:K}D=067Y&HrF刌MWZu.2TV|2U?F=Rzn`,\VO5j}~Z%Vd,DEN@x3PI!<0qԤ)%W*uRRNmJu!* F4Liӹ.mֈUM gAJVZP#n9Rv-rSBT"MĺeFۀ.o=1u %.qMqY~k0=o _1qdU6XBvmGI<:;K>KP9dda~)U9i*¤Ԁ\j\&x{Z%d֗TRÁJZ'}{ǥ\#*Gg>Cayo_DjcsiBȥE)I6ȵFۢt/M|PڢmI}!$~~zl7ŲEVa<ljGbOaE;Z~ZwMS9(<.HejzUMȹ;/G5$lo="ǑX<nG@SKV:׊f^SN$u}F5טԿf]jRJH9E?ՕcO<)DLiv >׼gZ):g1P3YNS;d_'$[>~;|+ڐ;> .m/xu^ͥvr8Q>k I̩~,$d1׿͉'#+RҒqℝĔ'm׹#˭jůN:\o3s%Sfj!4@ n8xνis՚I'OB2L[&?sǠiT[DAYJNtoU4֮ͫ}sǴsQ䭏l pg]`V oR3=I ;&8x~ K0ɖ O}t:L:uG}/piՓ7)9xKC1&>^]R`/A=˄c |#RCBnf,4g&\EJJʬrq AH{ψ%nl8DA5L4nݍ--re5֐yyT0r$͍*sO!f9PIy .W:%U`U2MAqAI&z3.:ag-*9bS{Aj)z/0m)$ZX9br1l MtFR'ݙHqe^"SܜscZv^T4gP 76cSU]Z¾ڜqVKR 6 vgi Q '[}#[Q~I&M-BZ'ufaʾ)%mlAzӘ&Օ V-E-6onzӚRu-.ʿ ,ߴ4=2SerSHH4)`R,q1ҿlf;hy:KURR<ݥV9F v%KRjaY"UIy$v{UخP5AX8 Z0r DV> ߤxJClsI B@Ns:TC5>l̚2kʰ B63:VӍPӮrkzFnk5f4:J/FYSbII߽ v\a6Y*]I6>FuN YmT*46amR)t@0Sⶊe]-@PT'`H dZ>k-Zf$) 0B'|B*n;[gMmUۍ#Rq7;CV˖;2cz&QKZt_Nh%A$yq`4_ކj\>'5' Y&"SBUhgR&ϤMsΘuϧkښMb|#Rl=?(_O&,ӌ%Щ916jA)yt(ۺxϼ+_-*=K Je D,C'ʴ*E>VitS*T(u$)*1Q^aO`kďd楧Md e.E*Yk^(^$(6MkZ"}CzG뷩2Sr[eKY;UvH5ve/% 3+~Ņh|ˁ7#<<_tRTtL.('q) _!,`ab]lxȏh߂S&5Vj6bNPߌRmwgwIu7O* 0mI)Xb,@Ý>үeMÑ3 [7_;qCm  ȩR)*¤#sHPKd ai}jR]332NcSzvRu7Meav©G]JyxIZ2̬K/m@X1+Oҡf(A*BRZDJX;HfPDr{LT#DFji<ۏhb枘!)@K ytؓD)'{adr 9yU6 ڐ#=m 8bR=J2G7jZ]N5pܭH9Sa~}vX)[ͣ-S$Fێcjy rJAɹ-$Bx=`"[nMǨ$^'Biy q]] ܴ/_5b |AupMc;ADa윿8J#q枘 n!`R?X.yAͻ ڬ3AsȄmp90EDV0Zi{n֤%6$$e7R1'msVJm@qUJA2_&FTNRyj Ei2 d4J[W$-y'!2\"HP!Mh):hyhpr1R%rjzpCm>Y'3*ڲ;}ˇ='B=y{Ak. m6ܑ?XT5ؙDIZ) ԏay)fY!>sEkvi 8 Qr07(O')m$^>P͆+;nQӁm;KTԺ֠@)P89&陑|BˋR_&5jTcVSj|BmߏQZҖq)orbVYR%$]K?""_%'CY2A<:T#9sS&6 DI zYάɖԥ% b޿iZIIH }=?3&DXUʼn"zɔqܠTe&Qhqi(n88BH@*\`ʩH Ry1*e&#R-ҒpNx۴L[kڕJߊH3E*&!BIVb Zjy ^A&wʷEVu V A4j]ᤡ*֥1 jkU5:bF1ay.M\ "LJmJ` U$Ӵ̥$#2 L{GfK,H.8\N3, ) )mb.~0U 3+J҃u1 *IZU(FWӌ4ܹQ 5:>Bp-S HRӓHuZ716UՂms'"P~[:TuP6B߅--$ܷ!DS߄6eo)[Rq~F~Rc,8 a䜋@2$o,Ms#%gUu'"ZUY 9?C 4x.Ds5IO d"n$m Q*S/adYD١H(U Y b֣uLDXc(Y}nMC-m=aFK$J-`s\{b}"M$*C((X$ Xv0z,ԋy)x6J>^bF\qs9JAʲo $jE£łmqJ JH6ʥS̾ 6 l]X$AF0v#*9˧K<uѴT %7؁s#u =KV))ͽ-A(@}>s*FY .-%8/bT[ "c1(܍*_9-0*OZ<=?3+LR7C#&=/e Tb.E^EbGOJ8v,UH9k jnF`82Vbl?40XB-  KٝxM)%?$ۗe>|V`ldЌcmJ%VZ<ָ+7P^Еqh|2IZH=֢r1"e>dm\*dSn?ni pOʊeJ҅ 3JeI1^*VW߼gJǔTթsS5VPUe[9=N[NgZ-OBmϷFvRfyg ]Ϲ BBUJOR%gZ7bš ]m/2*u$~?.LCO)ͥL登 [vZ&JTĪ$gn^ǔP޳|T'Jm)zA(nSs8n\hy:;juSq. fCixrh%: II9917dTْaZH0\~3))pQa~1CvVT8T;1yu6*H[uEx<l)RNA15-B(*#ð Ϭ` CU:g#no;֖{30 9-ĵc\ UJsOxr?y{4y%g1fj3Ĺ}B*Z&? '&!M#yǗ3)oǦ:YLL n\k-e(ˠwH8"fuj9Ę-j6_ZƠw^ AI.:rmh\M)`c|gf:DdGp&l`_3î%[JB+zp#xӽEr^Yma-%%G h=qn*u}mR~֍]Ytgeҥ YHJHH2rU DM@8a?H՜!%iA~3hNNϼHH;;tDRm%.jE20|B_h״SW">_h]MOK3"HI8SiTD>},mǯG&lOѝxbʶ'\S;%i(WhiUZÞ3敪+rmL68VEAHyZu($+׏RI(Zg$=&JwC]MhŠFtja6v˔)Ԁn ?OSI]oNٹ70*LaN\X_ףA&g6ORU!vHRlZfM/ï n>' ]MvdGTSkW1 Z:Z䩅+qpsh.UiŔVqEd:ŸQ|aRiTIj9aNL%%Jq9px(dMit\dfZS%, {zv2mنB86h~zGQk$j:LrL:mni4>Ki}J^VD-St/9t /&=M4c}dԵ4eYڕ)ߗ>/SN!g喲g#i3}CȓCI*XRn5oG2sai/|m\gNJw5ԭ};*ɝ[ Boir5) 6qA+؎=)龾T)mvs~.t6e [߼xUUOMrvnf^BRR|@/bbd@II )ߔrMɚdnkdޢrQm@ 8آ81=EM3]K80RlFeH BN?% uRMaEEYbf|Eg:KUR>/UꈉjC *b [Tu9#OS JJ C9'ZXލ+RIaAHG$g4\qo<{TPD[i! rl)l)Wט$PJ#V ?OX9M!.-Rd^fzeچmC ldsItV l͇'َki[)$f,uڵUŔ]_HA6G2)_z],=&N~bbV3,-۾O3&zyʜΩy傆kvnSU5S]U'{eHJJű?'p=q-j)9p{ '';Sjs=.˺\IH;.\ Rr>+zP&ڟ[dޗin=bjǤb,̻F U0-lR.0d֟ ڪVjv)ص:nKP&>~ɡwm r;z]GQR1.6:ꕶHtiRw3Q&3~fCNKiJ|gbnOa*7O߮咭%TCM:dpl-G>!>4Z+ V4EEW)9*q%>sMulޕ"u|LӒ*m%;2x>Oß pw3́vbY4GtZsm*i?4 ~` vH*jHLL zd12(QuH[chÏ~֊FJF$?zQ/t>ǬpxR„T͒JQzS( lS{PUms(A)2̎vQPKKRkstW-P[uבZKͳ-TL)uUzS3D.jBrffYJIMErMl xS:RZ֡fC׻(%6"o(tQ2$2J69絆aS\Ezʝ>|75Rj)LayEq`mah$_Ky6)t}APir`[[6ljޖjiJR &&\dcܓFvU'bgf0n\$!mmG7^+Ƿd3iJ[LVjMee:Qo(UoF'H}jEg;icp7{1U-9!Q|`D*O򊌴'G'V┰)q` ؛zijAFçs]AI5RS쓡.!@Hʃu+*xY7-61#9<$"0 q8]bAueRWo8rթ!f,fme4&\Y؛\{ UOa9BnTM}mr}"Ƶ]6c9TfZNj)eZS%8q6%;nnDȵNq~mT@&1:2Ì8/x(f;Ox8ړ\kids韼S2.U+0Jh-f{O]iJj%|"@f@OIST- 1Zѩ:AT)RV '#~Q~|#ϼBR $/Xĭ6e<#S@I9ɉBw;mτv6FiRv`/O3Z=ZJţGLY=":fUw[BI T\UɷR-@0rID~"B(K7Vr;N`U] "nG"^+kMM풠w.7 3Tp+ir'\n2I1\q r9I yD)!Cqk Xm\y]RML#6!`1Kn+ra(7?8X/+uIpc-Rnnei_juw {G6l(ve'!WG;ZeXid0BHߨZcJEuUzlt814On2)r/lL)bxJiimCZd^D;oEUYLSC7'q!G5NЦٮY LKeJ^c8ldcxپK&NiՕ%e'~Gʙ5*yoĩ؃Aj:57\q5 g05&V$oH1_Ԕyi,E-f)bLltZ 困}FmqI\vGp%yMzn:u;@*.oR ue%BLm/J@\p0d\Z\'n^$dTH  Z;0Σ~H'@~.>8qm.mEIV xJێ8i*zӦ喉8vY;֗Ҕڃ*Ev`%N6|2|c 鞹nLʜq%Ql.R{Yj jH_+q|lG:Y2]u¢ ns R1KhZ[VTsh'ا&齷e4pjͥ!*hc<ɓX?dz/C+IHh&\RF\_TG.O+/ KcuvPZ8-^3 MQO4FMc^d2rimmOBS{3YͣÓl/p28-_RTe[C4Eh]O ="JjU]`X2Pb%yJӁ \ ohR*`(n8OEӭ\$ "19O`ɩ{(9˄lglJuETSmJ)RiC mE6;rR*T*niO2@ږ݁x*tdjLӋ#qYA7q#71jԱ+ad]Xg}SXvq*uˊĤ{qФN*esn<̹ G[ݴْV0A IjlnUOMM'vtGkCCbS#X2aԾMN=ar37"-el潱ѳ!5-=Tv){1ړP(JZ n? +Z"2 iZM̭mR=⴬.*lH9wV`E?SЙPKj*Z|Q|F'z!{'olϦfbm.Io\tbm=yQ9Qqa]V9!feelrmrzFǃ&c&+ZBJ]0N-kBlS1=,9{_F;eT:, z>*e$Y+jNQx( ǵ`EX#7mEŮAg j*l.H^{vzbeSm(#kK9-3wB7L|՞%kʔԷx&/]T8ؤv4ɼٿ$9K23s 'jm)Q0IzqoxP42\?9F]($$QB'6&fs[B)=j*C( C hĺ|vյ\׆9!>[U˯rŔH뮒JR3(ٱ=/0٤6Gk5a ݽnsO3nb6"9^jf]),.~]䙧-R$YzxiҷnL#x|mfCFRe*.3OraqiUprO:{CZ$nv]({N1kɭmlJHn.<=%\bMeTG)1$y)"3bGUڜJXed{B krJYqVr|㿴D=0㵸y]JFMlV#qBKւp ^\$b=KFS1Fm  FZ'JM{ǥ9a MA@qzw];Rdᔠ 13A ;I?Ÿ pIہ~8_ e܁[9ħ*6,lcۼV SQH>k.u[xqVUO`K,XGH+МJ0척)CQPָQ:w+|<ŠY4ͼăoSi4(,@n& KԬJ!yճ+yKSևR܅%"{C-X(R*ۛ8IMBJ|Ilޝd [/hsù=bdJcIYRUEU/tR-2#.˒m6I?",XN{rrqAHrDoXG<<XNEVfQ#o‰7o as lBlqaju*hPJUxȻT/"Ou:N^CMe(&&Eym~ԙtt>[fʌZ.07 USaSRs "N?h뮡5Tò7HC(J*yY7e]J4_)!6b97ҡ#3,CJ%i +Lvn]g >3MLj 4⩉۪ھ~=+rZRZU1,SռX߼xf'ee*Wtx ff)M'fd_UFF)ǥ]LLC.)-Z oh;n=i3X8EkP^օ-Gz !XJ%v)p-l6'QtʊRݔ6{s;*M lYԓ]bRN-ЗUs5'-Y3QKmɽ3c9Va n <m{EIkEEU9Ǜa! 6'h&;Z4?Ii6ʀ)LEll7/kI^jV) j&ˤ+ʐ2lxh>柪ۭ,>]ҝ FSRv^T- aB<>_V0m>o_lY |L?0ޝm̏eu۴S[\m[C) C[JƝuGg TPPVqͯ~E$QM87{+9Gm.qIEUseKΨR鞦Y-/[ȻϬP3&~ekS`ƫt^Q,f%jU1 >*z]ZH~ݣ;"TNc0F}@n_UdU$g4ӎU!wPڛl6Eg rqMʥ78I9Of$ElWsд}#!1y?HʂFEŎ/є*amssq Q\ςӊ7܅pF*Nw!S uզn< P$Xc& N-%W==ZFfU%S[t2Tۮ6F9+#uI*}n pI7UPƅNyQZ %''ч?'4S k,Ѹ?yWJV]:<7bzڇu BJZq{N|k,];ٛ F7,h-[}$ H7/GncEI%Zt =kგ{b8!lcW|K21?I1ޫ5Vy4f , ޠF1Ỉe҇V2nq`-#ZiZ]ƿl7* ;F PhV_L /@qnT\e)k'L+ B[{#ŸzG:oK,KT>؄/ B?Ǟ~S]-!_^NKis->ټ`C޳"vKo*9$^_ӈmN^o&Ee; k/^vmvW')JJoqLǙ{\<>VuWG>![m6HYM RϹhԫu:aX ;*NjZMmi즑RUPZ%#n1|>ݣ?r:_ЀC/0wIoNrndAڌfgOucznoOM8Fh4.Uʒ%+'uSGħMj:.TjaW^ĬL>P\g"E2y& _aD*0*opi kJ<u:J{[Ԛ3ڻX8#™Ay”$qJ,ގu9m'<^X]z ^:tzr$9N*tn6`ŧdڵl 'sGîՍ>)r@7]wRϤhڍNteH7}ʟOj R5alZq r9+z.,MYwr/ױxG!*,Og5=jSjFuqb3QRE9|mh`9E NK:DDi,MK.ӒIM}}!Q:)'2̛Nͺ e9liԏԃ5 J.Mݢ-$JE7=EXMM6[H]d;#ʽ$ցO/I8r8?q@SuJsiҎn zG.DO[G?JޤFRS$UI1HeLHeUq9F{ ~p]krmnq8fRϕd5dL6ΨDx \9,9rbCu= D`fRe$$5:x`J¨suMEgB x#UՏS]G%ʼv* n ojƧj9*+vLL%DW;mkr8rly*.XDXm^on9L[JT L;НloF:改6e>2e;*ыInMgc3kATVd gIOÓ(&lӟ+,Ro_S}ZJhE @_~n}NOә,_65i+# I7G]uB59>]y(6n-#O[4>]JQ|4GL\T?V  gkԭ8sh8{VcxMg+Vqǝ/3N_IVQ,-Xتc"}'pԣX?Yy$ Tn(U. o."E)] bHTMZu~!l;`GQU[L8ڰx"Jb欔]:EZIM~zOlQ:F҄ZZovLxiVgzlnN! ##Gb΋ҩ^Z m$uMƤl&fni*>\͑TZI;CV)iS(JMϯDZD9>~ Eٔ) ^2zcOUU+%3zR r#IO;څnBOE$(<)CV}bЖR h&?z:ueJP$#OK*N8zsBt mЁbF@F[t!M."1M":*8*fIgwjM,I{Eht _t W#()WT'O R1pq5Vx\^#:Қ@aq( [g]wiw/!-"ڣI-U!ƎU.~O7[扚KgM!wbJR$St$\"]r1dg]rcRAiijR upH9Ѷ+R,ӗJT![yQ6 0UЯRȲ:ÅJU߸Wm \?D*:;SnfZa[ AQ M.!F-&%0fI7-cQfh&!fbrbVpoX*(ZX V@RP *oTLVӥ&^qQVm$?ӝMW*)I=!S9Wn@%4p,p-(u :eRRWO)Z&ش74W̋ۯ,V:VƫBRՐHϨW"qԔlۋBVlÑM0q>)䈳P:!mJ)QX~X?)og)0ڐIi'"F/?N:oSiI%Ѽ8ŀȵ{jOoِG"H2*1x [5Xpɶߤɭ7A-9jS1JkÞݡNN5Y5Ijl Z3=E_DjN= VTeUnNŽ"oeqn@ "Û^=Lm.HȪ/GWL4lӉp}@[i24h&&VZM鞸o;xQ7y:唷dgRP@QO#j@U]i[Mψ,$i *ڕ `M6JDR<7sr~b=a4'R'ggXqIZVAv6hOCG[73_ 4dڌ[)m$q~?{-BUG)n-#ڂMR\za62&OdItڃ.rPn̸FcGZ7&m&&mu_9h2AFqsV;\@LU[ IuhE5'N:n˪Q;N{}BAxJxR,>Ǭթq>\+#9n[_n#7 bIKCk7p骵?eIЅ7Y:ko+d>.|U?Cd!>w᫨TԇjQ*T|Ѵ'|5kNBT'MX|q-QJMƟ'=643*L*MaKw& O6T0E"zq`Z>돁iLȭNn% x╨~(H:нߜuŴ&lϟhmi0φl?"5=(ˌ͊Yu;3Ly%'`GatT;6dA&ߤu JdH5eZo¿:ԚvV@#mKDjyF&$mϔ zb%"]%/NFҺ{LܥAJ6Plkije!|H%=LϪi@яm!#xx*O7(R+ yPR$Ƿ%5]$TW0D@s i*]p~F eUgo}H%j~,6#ӽCRSR+ip#uYiyIDw2ۣCujlę"{L[3.6ڎt]8L]Lӥ ʀ {XpJW^tΜz*FA&|(? 8Iv]~Õ&q:1bƪ e6i51RvI 4BI%TΡ`i뜶e%[@V-a#TM[ԀR2˶< lͶBR.Ajת.Km*;Ic}ܚTnxMAOB$;*$*ޑq9yVzRAA.4`c&#ߓaBCmHOyMt!*Mf] #>Wh&Hѓzgh(B>7̪#2e-=:G>'Vh%+ Z1q{NǏc]_6խ$d~}O뮀a7.Ťn Ekߴxpog U%3tUQRs10kTP Ae>J'%3N.S[طcq:x BP#*ukM $K1V#C7*Q TL$! l!)i%))EbIޚTɂ.nH"ÏlKZN:G ]b^\?74@%(7DE0 Hc2dC]/C,$*jFTҌ Zs+ __ɪ&PtK6Gn:PGԊӶ]nwEͲm kg-bt\>lMfOhFCJVEOmN҂atdk1IPuڔEVLMXZpGeaԒw1JԺlKwr;E _K(Ķn6&je%[KAY 'n2E<)`Xڶ~r"W/Qn9XP;1LW7uaf%˴֐e^cUk<6 m:POH%uNXyU·n,n.chY*{_HKCN) ޱjέ%Dd}SU*w9MYu7b= B)DI 7>oטfffؽ{[0aQKbULM.GH'dǑ~NhnJ!Ba ɉ:.&ؽ|xS66>q[5!"rSЃ$|$/$ <) T͜i#N9n;&TJβI~+dܠ`B&I\XiiK@ƅLؒ%m3 ,-ǬGUؕʲn,<}bYH2*$hJjIN9$£T BI!^ C@GXdSU,FHRD $>0nM|zD.2>AA@ ěZj)M;!.*^"b~nE`X?Q ]}—ܘY)x' 9/OUVn@BCIjm(',fa%*FXiTԶK)'~JUfQp8+87w3lE&zNI8A/`97qHu(H*P oXc2ܟa4Or J4ݩ*{z;/,/0A?VBNv#'򊌊E]f;i [bIqb]K/lXQͮ#[*KLij!ԥWP g)Ғ,З-?xH8*;r*Cl3p{F*ʞBʏ1K3.WmFK2JJfu:q&6$ܢQNB}J.MAb7[֍̱8J*O[.ql~=2%) *8)اV:бa)+Q\ _CRF])ZBHڡOCDҜQ)8H#5r[=ݏ$9;:@?X4jłI6"Znh #⌻H4 }rP{FOMk+Rp87O5I,-6A*6"yV6W6om6%*I36PWhZ̫ukErcXԖ~;@! nIbiI$\,ó dیf,ĐTyWevLyǘLLR*镓~PN/nFoLԪB"֦ sE@拮߫R,QeX ѐT4e]ꓬ&_4eoa؟H5BJ"b)&Z~%6B>WR-xeYRoxbMKCe#aQ* b"(%U'e;ѼH#ks0b ItRӾI%)T>}$73cx@Z?j å>TqFҾ0M %Je Jc6wVW/Oay)(c{}- fJfT8?3fvd)6OSj_}6W1Zٚw)LIp :br7$ bDe%k;MU=k3) 08KX]Tdfԅ:7(`"^7TUBڟWQ [π[$x ߊQlgiY+zOyJBXd +RР}Q&^ĴĀ w-Q*X ?2TRELq(p F֓d޾lp  sAk5RK) IOe~B^J|I$+N* "m3 Jpx@ټgj^RuNOA'c%PMʊ[ KcppSE1t.8Wt9Y"k*Q$T $PZr  9ԇ:s@HgZ]sqܥ ~|z-ٴe!x`%K!"d*Đo}L_RqH^ŇOi >B]e\6mMLU4ZttU~/cE$DhXyjljI"qҺڭD"Ml;">GnKܠI:e)a&QuVN36Z[^k}.۳Rͬ6`,@7^ym%'Cu.bSt͓JzSHV wk@n=$[9ZUFNاN-)b02blz,ϧ-ԚrYЅ8>]%OXNŕd[HuoOSyp%|ʺo|(tzϊ7J#9ljSWgRD_ԓQ4K G0l//}*UDbaT9>kC%'H˩%HZ'8C~FI n{6>|ӮP+rL5t( hV0Ri) Kv d,:)D۾q- nx~.wGh3GK# [-q~@porOC.-kM~u ba, a"뚽{YL̝T+p#hшU/ڳ*̷؀9B5mvq,r򦧵4?j#LK4u$@"'mifĻk%% =ct_8Fmʂ\VOKҺ:ޘtcR-!ٶ6M:Rz2<_pq󞩛Ꞛkr5"t|$'Owwf̼9Tj.CnGR zReI4Kmv%6Z -ɇzJu/SʪLQVf72ETLOR6wXHy%M%vMØI~6)n#%hPl:96:$zRwVv,{,ƹ̭+~)&\8r&:ښOkEC Vd*pmWW~&nίUl@ߋ}nRR>BBP;s#Fj4݂r(wQX?ycC|D|KNS7=uQ"zel.v@5Yζiw&PT.`߶#ՙL̶Sy@YiVrm7=G' t2LۊͅF^*J,jsbiHO3PT晚NxeQ|foTz6NJLXJ}"2Srۖ*Ca -zOecN!"gq7=6#o<>aH$1U7ex[B <e'd&RKKT| `?(} zi*KʫRJWnY90ۓ4$w~!x'zSuZܜ#]CrIb::X&GR8gDRjh9]!2 Pw؟1cеRӵS)K;HO9 rl%LjBKHX6 7.NՐԻa >߹vD[~SjtL8\jY+lMͣskjthye>H$F}:uMMHJK%.[u\wݞz-MjQ;J$ߔyRk=1&B~@h!drY[-Ruf0O=G]jRBH!N ֳnWR :w\Xǝ'jՙ*/i4w{pTɨ_7r&zJ"O}٧q-66:6W__Gukb^E2yiAoyd GNAj$Xj@Q.W'q!*MƧ_7*1^lT';7i3j1(8dr>d>Cwyb@/l#_]"yץeVor7$ m%X4'Ӫ-=e *R[RԔ|FhΥh: s-!nR{jǐcVsa:Y=oGmrrNۿ[3 λL~]%V6xCK!:mI:mDx ) )lA1$񻃟?ˈ z CV9jq67 zG)}3"̊JJSrnRoѼu/55HjWM% '7SJ GEɶ,/΢:O!1,\Bo,8>bPr(+HF' G$t]S6dgYBRy9Ņ{ߘDi-uEj%hJR( V~ @:Gm=(}9~Z?HJ5$RL*lsoh4|T#.[a]jIy₶ҥ8 7?xLCK*M MϢŌ !vܗ`-#%̰ܸ~$óPRo.튎36KDwNrecYx4P`!F Qc<3.R͉&[k% ɸؘc*'eMQ]DǭeV]xkjP혥j~HS^mΤBi"ȩ-$l1DJE|OQS )R %ԍ_1>f')m*MhAQQ<[*Ğ2m䥰1%/Y2U)'g'͸z$j FIK^5,$#ԤMPS`  yY2riMOEe|Z)IK'iPS`o"%X[hdW~Czֲq6˾$wK2tE:J6v/֥Zj"슒z IW@7BJWX**6(ͼĦ/MiM3L%EJXQ;Uޣ1 [tMYs.,/uƧZ45S%M%~P X3)[ݜeav?ua|li,ʶ$TD.䔦WbRV5Tk+HkBr0--WZ+RU3L؛q)p%c3Z*[w*]Cz*r/P\NY,0A7=”Ύk-UOS|nXϠ70oj&Vqwҍ;%Ds]TT1KLvmYln ;]BϹ){s i$i!l(+2"NUi!˥_n}Of4ĨY.BwM==m̦XL|RB7?2 dz iz뒮oH iպ2**m?ƢEyYmkFn 8xfJ)M-6 zG>|Zr8}eiE_QIͤJ! BR#xKszyN1WiJ M{\{UB*}?!"$U@H&O-Mf$RQw[+5IJ%̔&`R-cU{>ԝrQе(.FN,,K/'MŀP\}[5'"1(^fUePAw`D`F:Vu(Kp T797II8f7 wSuoH5t!h;T%)a;t!]ԁ2]/d4\2U((I*QͿg]@?Dxݴ􍲭*IeLP"ßsENSqiDnl/n?8l.yL8ix/MMiBZ*Skj9m*)*C^V ffm6[ψ-A!S"dW]xu"A5y3lk>&[S oTgrny')&p("\+y:v6zOW3/ÃGǭa\t w+c;VeQϯ91涺_S-օZS,bzתɚRws qc?QSRߌË'E4BS0 &pEF9iR\~fD0+p{c5~E˸T,TpIoXD(#j@k GɕiC2aY_nBZT$A>cb1A:JrY` _5IffiH@yOcR5d))ɾrAs#y&zLӳ&_-EjI !:֚Vd.&au n8F|RZ(*=ɿ{#u)(@$p69 N=^*5q['kz{i+!AIxEK qJ*];nW>je{5-q+-*.ӏ!$@@D֟TQ5Y6 d{ q ʾѩtYi|% ڠ6}LEd,"=EzԀF2$KR؞-W74lZţQM7i}EEaqOEtYSr5KKJtϰI5E4'tZКnF-Lnj|oW UJ9=CS1QK M6-ohϪڪM3/ԍr㘞&|{3tuJ~a2) +#:e$₯c{K5ESmܦ&tNܖro6?bG72kjttSJx [¾ LzҚam= $_;7.jM+,qE HK꤬̿oSUvԍ)?YRkX*#Aθm@s&ԓs}ǏmM[Jzugi%OH@ڕqq#+QK:v/ )B`3P NHQpR = )BǥE>3Y)%Qio#MT|B%]"rXj RTˍUym v6ZP-_qk+>[qlL^뙕Bj5XN)ځ# <`-TT@voT櫍ǧ\Kͨ_Tfvvbn'>`o.ڡ*IezVeYi+iK)PIk=&hIjzZ/,)\bډ#R TA;1=-6T˰ ImngPnͬ.V[ 'ZM5$=.Z}ߐU5Y$4toReg(@r3oHagKnnl562Y('xzTJEœF* }6\wPnZa y25uyT s#x?j:pΨ%`=Fhd)[52R)͎N6Mm(+Uk[0Ps]YŐ,(8ő|d&_ת)vʒP7xnjLĨ__2WGFm>+\Ks$ML$2=Q7P@mǴQmm:d!an%YB˹>"Xiڜ Yr Eb-}ͬ l(np2GFF5B`wb=o6t}#Rؓ̈́(g&j5=(RKni  yY- BKMc̜nՇFu#13.UŇxRޔ|- oh}/ HrCݩ v=(v%?Tj4ԫlNL0ifROqŚ @ {vM-kŋ6فӒ K"RR?H~ڙv_jSmHe[Ҙ&UrIi^s`0d2YD-|ҧ$[ΪnjCW e  s{_UhPe'aQQ7iRZo&K̩6W0r|L^Ðaui"VĚ$] KmBQU99a ̲U%<K$lhI;i*mØ`f۽nCy9Ո zPn(t𖡢0Jwm>֑*Pq70}bM&@$ ; vo3zaŨm`[JAWAtv Rmb^>Z>4Zb|{ҫua /ܟn°q)MIZ !@mPN,,ůTa+;ͣ Y5.U+mtnpb>Q|eXj%aDYJV o yڦRi$BN\\*q &Pq92+>;j!XloxP+cmܬVks9)e• FMk7)DʬxMRɨ&coVuƈ}N"\GJN6|oG k 56IBA+ȴCTާ 8^U%VE^}-6RkJe-IPRT03+3hSnn<kC7$Wx.rQem$TlB%ڣ-A+UP=PP=*(7:.) &x"0 Bx7j@6q4U!Tag H6Q7b"O>[vb/ufficm_Pj*-MaSw .6a!]H:(5/^gȠ hc)Kcro\ITRH3?%\Y0?6(i*$er(U:lҞ(d/M׺hk-5U9ՇveX E>AMn$&+ge#'!žhp~pofI9$fR'pdc^'4mMh=ObA\ X w{#ȇqhͯL'?EZB1h:;N+*y[oqcPP>lG3&Z2BlUQ.̫Xsqڡ[P B(ʑ;S]($9*1q۱ q(Z0@?*On'M֭1="]CqUc_ӉS"gh/4>lJ E"?(*Ԓ,PzkﰹE%*P; ybYe1MCPB7]^/RA5 :Z3ƚ3Xޖl|&1QTڃ*J ۱9jO)`LCtJVjI t2˞!l׋(r#QTMX[JrQq_Nhb6vϩ?[/K ̽]B@ qn{O%zgi wV H\=9!'$UŸEʖ*q7nѧt=JZR܌lT\iѥLJϤ]tKq YBF9ZXlTچK=dk\q/G3u?ֵJůɸ|֡N:คX{X6V럴U')mٕ˞x?H ʆı7S̢8[HpC86VNJ?bJe 2JlA TĬg% X'u5>fJ~^nD%im^w'!q `'zNtV_)Oo@._;lG1?uUhLTφA:)rϢv< R(nLy/#a?1O:JMZrN-s6mfV 3T*Yg֚޷11SZT򔐲1KFS=RPmsc,hLi€Rue>rspۍ}^-U>Q)<ě/c_KbjZӴGA8ܴKt'-sWBt\eAlI9x_]3:YSC,*B [vJa[%]l 'OY[߭l+5 kn|F骊V_MFӒX$+|fH97^ԎڔZ5ZiJr6W,r3ls>=zMKTI]SKJY.cԿ OEN8&R֛_mkY+E䪵zUY̺=!Gֿ`|~*+|(k٥MLZRlTߒ'ФsM=.rN^zuR3֕w~>wP:==S+zYfY)w Q)![3S*i N=J@ޥn,2M>Y߀s|/-yry7០b?Pel:m) ({`W;vֳ­z;*uIgi]<բӴA.1A2%@kּXiKb6x!מqn\\GkNBqAxAەcjx44MGQu*iGfe7)2ڔgȪKReK$I9*;b'f_ ?CtPfѓaZy)ř B >ؼV]Hp92-H"\OAtj .I>dBQ I?X:AӅ9rQ$x*>jx)-D&3S,_ YE\zaPhiʈmv Ao"-M|]jEQid J!=je[6&#5 r / ؑϟ@z2)BDnjI[_j:}}*ȼA1tF7yRB 9tG,YjfReKRkX_"@koJZeJS+[ ږG8o}1њI3E-&Z نѴ '#߷yڣH[RAkt)6$jU$,HHB2\'e9w]^mʶH.%䄨n#=7z5j&ݵ42J!7|ϧd,4ʷRםGS.loܑ:?pFsԨ$?iZJNBuO'F]5 >F[f1Uzs˘[I 1\oDfU{TL!,M'wN9?C]Q`J֠^M{OQkAI͢zOg*tX#3z\e4ķtJdȿz sOB*y L{o(G^ᯨ˵DMB=gҾuBBrɩ[ MxJ%H7VA1+ΡNq9J EU 뛓`oyर0ֆ ^YSMu ~3,@na|voEffVU;Q) ,2oޢQېiRNUl*#HlN؟}7Bh{Ht^yǟIdWQg ʒTeZ6]O% 7&,)ܢo8oWPJ;(Ŵ.zen|8y躨ujaHJ_ 'h4EK Dd53cs nb,ޥ+&*X=1#Zt 9*ILl!m{`fnigfRm?2YpWH7ywBj1F2f e8H C:WNم8+l[@32u>Vno[~2/Óxm~qsp'B#j8蛢g\i{OڟONMge˭jFԫpyMEPÒ&d >SoQ7R8I t'INstزqȕ3nz~^` p-M. yΡOUm,07.jaAxba$8퐓6=r] ̐/`#1dEg2?EzpK0hMЕmܑlz[tt '1zy+gT|؃|ߜBTgQ!X\wӣŷ)%,yRq=*ϨkW9ul|̴ՠ\eSUVgeHmu#pM R3Ioږ2Tʊ6}qf.OyBcy7qTYTy pK:pQ GT-f&P$HK'=.SCM.$ [FUk !3N0ҟ9sȸ4_O5l$[\7hsc> xrT( zIbwXӟX֥&gLۅew=sS::p~) +w ֙Sin@+rY ql |fy5492%m [E)NؑR(w;}?6zY/&8zD~9( 6JOˋn@jy!7<^%t cEۤT:5JRW;m7=OCQܽNR¥Mq{F= +MW*-7 'Blz](̯IC +rW`&y7Aò3(g^LঐZ׏Qm>UQ),(b0rsKOCiZR#}|ٍz(O0umap9$,ޓ{qX*Zw]V GLu"%i`ROGz_҂˚SKhtd md`Wf+HpG`.|uwc ~77H7K5]Q2)mh}}bb> 3$^%) 7?\9^Ϡɸ<#l{ޯn5]e( IEu"SW8㩵'ŁSP~'*U䬣Il~5kE+=z/ʚL 9=zq(ޗ@q&Ĥz<<;t#i2Yt\LHEN+rodY@ O5X57'*rN}1%X[b>Uj4ei Ҍ}pqVm IMVBT[q*9ڤhĠKƟK{ Q3v(w`(~&BN\ܪI݈v|.V ҡJ¼e)'r1#^ 4Ns[\A1.ˑ{`ERd_oQmFl}h .uIVlB̦,JyT fB`MOVױ8;2oz7ČJ}/έkp }#g`%֝m|D?^W(SSWxJ9azOV.Uڧ71)Kq%w%( P#;VM66j[c7A8-ڻ {C=yUR@Y7P㽳"0*IU`uK[dkaN qpέR#7"L!k*99IPg\)ۊi %إ}XI@2M[I6cKQP>X_QgR| 8w /z*|y)b"!SOJG*R@Wc30{9g^Ŋ%%a7yQ9̺j)3yZ}AB<ΠRP&Ù]E2IZK<2NWKS/`Rk]A@OiVKJFBrl:nGmЯJOˤqa DDco0R/$Z1ҧlEo7MbSaVH\qX70RX`1ޓٴʓs%Z@lZ-S-bA¬9?Xi:a IR,,.9eV|NM bM =Hއ|]@GB@􋌴-Sk 9q.0IQIp/Ȳ%Rn QgKL! I{CH!b2O8hy6́O23MzD:(Z'xQVLmLjaNx*yip97AMq  \_7%n{M64" pǘBCo?.(m? S0ڛyEd,+(xǼ=#<.q (X ]-c]mBKz6eP.~yC9pcu a[̓UIxRT3s8.y2 Rn^l\b*mY+IJpNbђ3ƔhgPa! 0B P7:p@RX)q3Cjeۮ77$Xĝ7OHYQYHY}˩No=IL(!BJ0H nnmm%)8)I\!D߿6^N^-Azin8$"ms*jy=4T&*B@O Z7Jc{zGA#5dk^dOXZwy6.O"۠5LBH%XcIe.NN6 _۹W^sJAGCp0ڢ%StZf\L%8 &4Vr\i 7ͷG6Nk&et';z":+4R6@qpcO>Y0^y]>jA7.۩77I%iTtM3D &^<܈LGSq.qo%^JJ}jv8P8xFX%bUMۜq yX҂,-F۝ÅQuIJ"]Hp HcFdl1AQ'4](SL,XkIFgC])"!o_H΅'e$v4=$-(#o $b $hfYJwR6aL`B@䏴Uq12ڙCAmۛHеJ}M0~nϩ%n8XVm Z!D Hߵ"V^HI]ucaRn{ |]4j:حɲvdžA7$ǚ:7CyHz+DjueRQsA$}Dy;wb=}!4ă^NEHFEP"V~ yPyqF TRau}}~hg7$-DMd Ke+@fbh YG_OhyոꃫQH%@}FK!Xsr BgwT ?"mvˎmkW7MOM(jiC?1cVӡ]iMϴAy:cSK%Z)iRr8ľ~u4F I帗\=OXHRRqR奅_jkwsZMM 4ʃVNzzǛ^fY>C )J:ob*Sra=G\MLhz]I >ȌXvzXngm (8ȵGzrzT)=9ӫ 3z3WK;QqޤC7/'5uy2Ra{Qji^ԿMY-fU xxV; څ"SyGTJcmxTzڲ3* Hkn!)tp犂TI 7zc\ ~m.PF~?_MtMA>s. )vk$ve~"u-M)~UĭŅP\n~=}MCڢ 7Omu+έ\_)zAJeE$MR]?^H#DŽAӝ3֖FڂX^]ZRJ@HaE-huaaҏSi˭,FT9xM~ &i4U2 ƙ`#dG).:\BmhL9O~N|>aTzY?uJQޟ&[jf^i-K"{P5zuJyK!d7ɍ\,i)MʽGn!WnޕԪ @0]7G#p$ۃq;~$\ ]Cך&NZ7\f0a haD[IyHWj쫒BDiLlBon<9^Lx*s= 陧RPI=b}q޼tr.[[ٙyj7!)6!xt|cXeץtdu%1z Re✗iVQBEP!RSS_| Am8=c]#&F/|仭m3p%ψ qd9g?7ũMLtjBeJDʊR״m'u;F]cELMƜ|\Iu<'v:{ a~)c O^ myAU[+JO!΀h}gJaA&mp.1cVL@~ӏl}+b=StOQ:Y/;Y);q8-v&Q"zen?χڃBrOK鮪U /^hhFZRXh:T \CeYDvlgl_GJhSZ\ME~;G/|GOݔ@oi_z"|ѿͅ~w@-]AQKҊ24hvI.!aR[$^3.Cw2*}F,7; BUk,*u`Vv m`u>Nm?1*ԥ!K-<"5O lďuBsz_HSzRTH mY g_ =$v$2U)OF/YxM] %p8WVNq[SO;C>T;]rz:>VgQetZwbH9Ӵe3M\om0#ɅԗEC˖B~{EcBjTp,zB"3"S>+QtʒDŽDu ۓyGJZ1BU, H1|,hVNMj֥[%>6Ss_+\uM%r)iDO%==#SyP oҺ]J& JaKx77Su:f)5g6B#%5Wf'ݟSlISr{FtZc:['yI6Ur9a2[2GMuZB/4K4LjW(׺5 F*wYL>\ Xw8Vj)HgnI%  &t⛘S4IJspc*wc 'ϫ_ ?zؔL56|\ֱSI)SN.iBOY ):w֍A*o묔Xh:[=;5zPVWNfYaNm kccmOTt67tVR]6N896?R*֥. 4xNYJ6 lk}YG7پSVvvyJ_tKZ-7dܕvSAO 妜mxROhV>/2*q-ל 8y xb߼tVJUZXC*`4#G@̝I4F_m.A$F@ :ozyJۜi*v8r><Α &zUt"cY/$6i۶#V ԣm)qNnH!$ kо+0mBTbIj jfUI 4j0j45x53t+;gK  _ Ž@Vzk19IгȭLԥmEA>Ti= )L]nYG9.emb#jG-Ο%Lb~O3'ӵzԀumQby~Jd^Y+O6t@u&Kq8 AuYL"VVV;.tal^V}:Z:USUe%<PN}.;w%_ idyvX_*)te'?O'k4iګO dn[n؜iGG3QˏNYRޱrZn]T{ͮohzTΙ3UX xH59t6JRP!W ^K*L! !j5B+2ܨi+ 9@v]l䊧%ds̔["@Q+T mh6PX >|SB[UIJA[c$HugJoҥXx~*iV716:aD 9"xB^za԰ +8o&[4eejIN)+lU{ߟqzTPb0lC!]l@f:Kgen?#-95<6%*6EW%nrT<@9<easַgͭV1a`S3kIfľڬEo#LRiT%0ǃ{VINK HJV6o^Wf=jZP&q'jp\&19.i9VeK)ڒ *uԜZjB ~IN8K $~q'@nZ_Pe[6EuzfZX|oi8I,r\(qxr$M% QtajRN sa(yN2dnCcJ5r.l@A?HI$e;oʡ-@~е6e]).? |QZ /p ʀu &)#Ijt6'rA#hkA%HS`, ~}Lx\5/iDIGqV2PR]+"_MīAõ/\߷P*hSBncq)\yu+TѨOP{-~ro1EPWKQ[_B+2 +NL<| (A^Y/ʓ.)$q:1nD$-_zj:i:BM>eU6;0,6,9?/hu:eU Kf3&Z%*a0ؒ=?(R(O49/S8ŭ6ʍ#+љ"]M9EžƻbXJV[7](:j~YC(% @;YGgu?Iu5ހoV&媒^YHҺg&7Pxi;H=*A?((y>I 9OyaDOɅl#Mrys J~֔KoRM.ESN;kivrRH[i!m( ҡ{՝ D*jQ.;n$[tz Eh::n1P>Uԭ)BtI3Utd{OQ*&[~a$P$ƥiL*ZrDi%l:,`}8]H~ZYmE9 alI5cN- 7%*]jO{~h&T-BL2P[Ï* lCw8NPl'Q>+ {c? ^s3;K{AT;Z[{AyO0`bjGl*Uq?q[7#B.{d$(b޽ŻE֎9?HOA3zPN9ۈ}օGsb5V-0Ҭ~2#M/_0E?XP+Hl)ŕXeRFv{u[ed63a= 3ZFR6iVbJP\E?OXpDfSyE1Lq +Uu ӿ6̼hv͡EK Dzj ܛ;Zhܘ^DLv-zLSCJje*CEʆ}DN"\ m9S@hWrNyɩ$|rsEN8tY'rd 䉵 )) ׭Ye~6͠mMzǺLUL̈ !>\Z-qUFACiDӭjI#o$ 橈R*IHh`ȨBx`Co0{X҉xJICneVgN,BH6_hj5IG+5$h3"üW±troNbFSmR `Rz7+$je*+}=#ՈAq;BH?Aj5,YӧNP%1ZL%V'jN}b VD|DzVeM&aɱHE ij)}qH#@  E8J&;"[ OxHM% yW|{FWpZ7TB_%)6 i'[7=A]3df}Y4 7kۡ |r{4 hyU=b"h)$@2-2  K,he39KSKݵWVHLLj6P<ѮGHКa/y87 J6Ct~2R@7g,zȂIc4J^CkJJnh4mcLf-)#p'}"+SrЗ 6Rp\a{P ɗi gbapeNVfYiRuj(mj7u+BM.i \Hts! s3yfaum.!$h| <|(J]ZVU帿Q䶓8aIPcdz_Jگ)ɺ2\K(R sǹ#]+kLʈ{dGjjq3bϴIf.%$b=vP)/`c:'IM5 lӷ 6ϰ][WvYwlQ'tl8rNjyߜj%E\XwNj"iJJH Z(M6E{FITReA_ĥ}AJ)~H d$o FӕU 0J1eB&HJS9YJlCJd>̪ ,,{EƯ.7,E=aNӻ?̯Ә΁I-X`6m{X8􄕢dViJW _-$d$0V'b(DF[s.8)N0I.Ԧ\d~R-_Av{z{NiNbQ*ڠv`)K1]YM̎wHS'̴G[Z`P+C㒔 TT*?.@$T"ӺtNa2kR-$&~EagGXm3ԠvOqL%VƦ̨ 7 cUZ[HKu` b#v(fa.N` z{9Zlѧ%ܞ<$AmG &$>ba*QHgZzEK7Z̺ܧ[|yGrNtmSRkw5feiRsqD^vEE` U%iYD(YDIOI$--gVScIG\;BoXBYn񲕀=HU L{zzÅjI w*ZzN}Ba۷#oPm|gk'iWrE+ mcoRk8 Uqu>׍Vh[Mo={FJ!%Ilw*XqɊY܅֓;Yqi&#Á􊲘\vAye(O+poCe>zT^\>RT}}="LK J`NsŇQSuĔP+).{4%77W17 Ԣg}/תM"YNn.=M8}} 0%WǶD|uʡ1dm6q,n6X/_'J+wձ"OOM5C)Z #IL|ƅ \H߸ncF"gpwFh/>h LPi˥KMWa ?<ѪOLNL.iո,M1hr}6LK\Jl"o2oCҒE|7ئUm61r75#PNɿMrfiK2e!F*VmVͽG6M 9zLH,x.,*P˅2M61`϶Nuw"kXu/6na w‚F  W>ZVޔRHA$HHT֝%]:z0Ul:ogfM* ]%j h'*ԬsHǹ x,o|N/ergJw4%%*E773}nQqmq'5g.Q/p I>e=|uY$gy Pv~1ΰ (%%+C 6?HF ؞!cȞj[_I'J4J <$ lq9OQj馘Z\v`:ɽ&]GoWsA.7j(>L0nX:Ops/uq9Tg78ql,4iӍVv,yšݶQSZRBhG+)R0te{/Q3 T<%O`5zTINw p $$'hIY‰AEҨ( DSAe(_C4Ǜj^mss3G5X.:PZchRO@W5 .ILU_]:'&ֶi?e;G ~c!Mbaj3RT.bڃ9!R Ph]blE`y$NI8l$6} ʾӪT㻐pwX*Tʄ)sM@$O<U3i J8l R j)')K#.)w'߈ZnAKL9cVn{'}m ;0-\qnN4&Բ|Ķi㥷%ZZ [OИ:zi)+-k0C%Q"禴'\5$T*۝^)(<%iթm*Hnm1i2jL3 [n[$[F˦rWGdpMN~Jmo $Z= z@kL*>3+A@ 7 ֖Z%;.R(hvSɭLƔqvįnb&3`nzv>⒴2v@󻛞#ٿUi}"ӓI3O]=0(ymk[c? q^UK-Mˍ7zTp?="2OOUvbY[[P~~&S#9ww3ByDq;~V>T%j,+h+J͇*5!FҮE*q!{yVk?=՗ztzqB,d ;Udx_J]sMxs/pT7+hz4fMR(ۭӵwb9C;>jz J&ZT` VG>j}9 ӊ쯂ZMMܤ_x_cӀzoxUsMe;+/dXnu$ӯڌ4x,yKbKT8#TΫL\ O!O!z^*\}fӌ\?^ۏz W Vc5ߧǣƦڒ:_$0pCGo]$ұmpw@"<=˟G6,`MYus_]b5^CKy+mMB@{gZ||et9Z6bU(;)#:V*ͬ8n3-KRď2M웞#w?QRh Ewu4 9M6&ssKUu(*0ݫR’@ho~:YfYn}n&.=dLOi{*>s< ;ըYRCy%zhu>ZJRG#C[IuF}֮n[\PP^O~ VG~huot>OyIBdBJcbPlqͿ.'EvRv"OKW4֋ l.O,$lJ,c}7@ukOΡ DjVMVPA2tOM:PR!Nmt6aV6mq3]L![7;4[.vW*4ŦfiN- ǯ.ѳ8{}G&ԶNМ(Z9M!"y'Ǔ|91tzm)7BvGVm,;FxU- I(Ԝr#d3Nǥ4N71qJ|/3!)(U!-.-$uCTY |R aR-nh"HjǪoIKJšKjTfVQ(iH 4PgeA*i`׈t Ws,,JrܛL夂R96RV-J>- )3po` `#YiMVJ3l}8 lG@AS3llۈ՘t:WW1kTs)nlQz+f}>#BY6>2.9$uS#$Yc7TvGHtQ,-拉U6jRl} "fv)x21sisZȲ{ZVSqG;.Eg+\5mܐSDNպ4T8c/~B.'i_9*z?j06P,N?EGT;|<7SZgp\nUudKOR [+ڧ3HAi}ǟES2Ԩˀ]o鞬}u %Tn[7mҤ/q82_k%l?#SjnY0_AYDkwdBAؔZؽMҽ}3 }--#/Q{+~^g&> ''Qa)TEh&~:IN+C%q{HH$BcSS>+N|wR(A\]E` ,؊~ۃ_ )I\[!V `9:諀yu{VÎIV7g&# ) m&Ru4JaAm*>Nc~+#uJ1A:2eܖh^lg'ZHylQo^HuJ#%I; ،R( 3,"bك72T?籌Y%ɵJ[MxQ( oܺ\uW2 6bzIA6txS9ZymIJ E'l [jZIPR8}?&Ro]X7( QH7ű @\Ùl 'pUUbIJ6!J 8F/~pZnu>vUjzTj.-Yڹg if 䛑H=+yݠZu0h=-Ba9-?&(Ut۹}=/ zO_~s嘓[xd J6},}!v;*MA4)6Ͳ>ր,IR/.̺ܘSF]*;CfT&p$Bn-uvnO*'+ܧ8;*\"`H+Gg`;clQbLm-no\jMJpe<5xE,ҕ@`6#Ks'JMK.p/T] X*HRp E˵ Rp@TmC-ٴ.DJm("WvEn;*Et!ANڐ|}=4q HB O0ڒ(bJH\Jw@zsp˨(u3M"YJ jJfp$Kj"ٿ1Jk;/n1sZRJ?@6&T+w,0ıiR :JY _"c׼'Wr򯅥# [@#n7%h& JAr]{،geZ7nE˖~-5&J.Wf))h7F`F6M%ePHTUc6Nt5"ʖځ!(&#dREm%@% ?1jkBSdGlǤ<`јzɭ>arokA).ʓk_l4Kmn$Y'H$lEc[NusR'<5|ޑmy )>RUEӏ&gCjyM.)1Iu(ISrM8h;Ų*a l.8$KT^R';B:Z`%JI qBX ;FRM8)Q'jRxPKӒ)'({^*Hj6Rv_sI]ւQZ`M/aķI]Ά[PP(jU*pWxiu)I`6G!e $iDW,*#b2550}ޭ]PBEG :-!,6ۡk< ^oufV۬BI6q mQ.Į {x:ԝ:%4%'@iZbqD)% E)5 =>HZ>[QV eJ+ԽL%9oqp{ݚ`T*S| `Evehz,m)J~i^X"Q.g2Sh  qi@~>)u:ҁ܄$$҇JuypL$jr<"dъ@Y6ZM9"f!Ie8@B=+i[smOK ޿nQISҒ-CϯUw}Mn5s"oEUVS݈ cA&ݒy ~u2ef)[x([yº0\Pqǫ+$ƽtHE)BԊ>MRu=DS6A]q-S!vU$ ǯN~Ci Z Z+341؍ZմV<2 b4󊲍@=aDWNj|GFl `5Gu)*$ᄼ;AjC3((n(\{G1 Q-ZYs.6Rd4 R\r+ ]l3V 2n o EC՘b̖АBڴ"3XvJK6[6fL>6Q H]FQ.74TiܔhJQyj;"vE?XeT! ܀&(+"ms&,&c#(IRlᵮ=3"VTUue##=Xm؉ՍxJo7U7KuYhOQp&y2Rv 籌NTTZ\RR0F~ߜIZ  qr'MfZaulˁsn>ZMTE )SR4uawMIkmC-:X} +ޥV n>6tR(!KSnemKjiꊋu$)6lo]ZV.0MUr I_P8Z*Y&ÞbFu4ܛ\6(:KS4̰SVݸ[i{rr~R&3&%%*y# q>F8 ɿh5əyMpSoXm;MI`U2ӑ'0BR@H,j%&Ⱥ;:S% Bu4ͿȷXf/Q l烰m8]>d)*ϗjy9b)Qd~Vfٰ fVW[$u*RTX=~J[g6")B.1{Rm\xtBS'ea$ObitF2Q!X o3=+ ڒ#oI)SnjX<#_vdq;scu]AJP̅ZI@ĂnGy= ɚMvT&Զ,S|qyLR33t!CHK0%RMݧr"U{Jw/CIdSrO(\7*IPxʫY>)Mx6JTV%tq-r2yKk!"94LX74x2;WHO˄q;;G]I)cI#e {`C60a( c^FY+PE(0HJm*67=kz [iuƐ9%R seRKu$zGO{M }~EߝH*(]Jc dgW#WLZkHiRxbS߄Z!;{Z<5qf"mx|pukTh}$Ҳ\tڀ&Ņ fiKJl,T{>8q~&RMbY9"MԂKy”Mϯ|ѺY15Tw .=5ՕLyy@9i93 u3hDہ~})IRe &4ÕBYRr)XB$,9&!73IZ N$!) !TʧLBVx .d)`ssh.%u>XQge\WO&29YaINM.2 A&s\\!-4XP9)م gEI:n^`Q) ߗQ9mʘQ;A2U7q*up(@2'‰II(ra-r-*swlC_]3x[Й*]Ix8)Vې{@{{qK!W@bRvs `ـE:+aI=sr?Kܫ}1y/Z@mHVJP&<;,k^[SVzP#>r(ks> X>)5U6HEH [gV۫jSRZ5,‡8bOZi=Q#QMB:nIv@R8,$OqkF+nO y^Td<6]sVвiڬ_j,E b6PRgff7̼|qlEw]Y9>Q6R@`Ƅٰd U!k K jpHO /z{C|'92$V*DZ-4!^)^b*UfrQ+ M>Hzmɔ]ĩ|^=M\rܠڳx|OPVF^iS*~]I!o5ŀ?5-~Niʠ\8x};KkI <SQhtOuLa-MrO.ZMm фk^t1.KO5\%<־2gi7A~aհΡP{zŲOkSzyD9nm]9=|O'rߨl*֓Rͦn}ZevP[N#UxfJKu #r<v<-Zյ1:YKL.m* 1;qs"K 2[m*@5$xw}@!65Eb׳:P 5oO3,ѵYP&H61LҪJJ*K׹Ϟ"]Mז*IN@( d"ţխHRM,oge-wɭQiBuxi6>hzJVQw0[mmw1w9M* `@]g/O jd2󌗬-vCvJ|o0'\Z4@<NjEnJޱc̏_n#O7Ju" Uܲq|{DRe7Σ|(5'riЛ ~buO?6ڔit\0\|w.ՂՏy/FԲ^CJ mrU֏yf<[^ӳOI!3˥i9pn9M"NZi VE,y99mܲ_Ǎ3':CnNɴ6ڮ"r?%'a􋿴̴7?iSFvXe9USmBPJmf*IGA)X O~ө2 [z{RiY4mRj ?Lt (jB"bm2STQSo|<ְݢ\/huL.8E= WZCT]ٔ7.eQn9bEwRfS+ ];T5Խj`=LCG*CQ4RekLQU<+ZPh 0Vj-|G6fɘki'd'ԹW9[m_:;\HO)k.Ň4bXQQHɍy.OT1iHË;}]jeQk [n3U[uo8[ f0D$Q@h%6ie{TiYWXa9&KM @"'uKn5T\ n 8_"8ΜKvPU.v8(j{s*,hOTqaԔ6gT5 oᕕ0c"|T\LTePB6X; ˽,JE;Ip{g9,2rIcWaSĀ;WOA68Rk}B}*J|t]WoqrS`-ƍ)ĻlM1F+K-S78R~o~ji ' cS:YMYNI.ʺv|<*uf"ʐ߉`J=%6 yNqMKfVUe>ؼEݼܞꩆ6-Wcu G@.i˿{%o BTB 0o{)<eEDE1Sd'bdkjI7A9n][jo)JlfTW җQq 7 {[O#U920S/0ҁ')X)NQ/8pFxo X*:Xn5-*źܴRxu9X& 9e%(]%r^}%lVar*pW{+UT(@3IMck6%[o|CVB9u(-Pɿvn]D/5[Rj-#~~7jubp=mmsKe`rsq縙Nֳ.ZBfVݯ(2dx\^Sy 8X?(tRerTP%,Q2tJ&DĤI81LaNk^5zRZf nUr?BR) I(Ur,ȶ0v̮yٝ!grF{X`KwمfT[Cٹ-/F}z]6n1⥔n9: zxgHmo.+> M`#P)e~n.~{ <̅'+s/`#UQjfYuÉM3Gu ,viɿh"|Q<֫}iZ/p7x-MQ犞Cw*^O4}mfKkPJ){>K˨J%e1EE k4OEPe!Ҁ WNI_ڇP[ LFu2OY5$~xf N6'B6 Rk,"L(W1m8e7JR adt-RɕC }#IځDTxiMқ`PڷrOa/:$czȶOխ[Ę;vdڣZBu~#t漕CJR)@X{{Fdan3nOSA< R(Q|]"3Q12_R$Œ9Zz)74lD$DXu̲PFkm4t )#Wz20'j|W7?{ҔU6CE 2oźy!_JFR--zFLfnp 3TINW bՎ F>xPH>vZJUǸ~в܍D,$a!\B7AUFy,lTbɧiLˡ!)ϚT%jFS:I+W[˜u*޲Un,1;R*h0J$:u|mc+"0,hֿ2nYgutZ;on"IUc)D(/:ÊI>V%a-ݶmȂnđm3Q@_7d|05/Oeeҟ$ S !fsFuJo^h,Qސxlɿ D+RCN//ӗ'O d  dtZ5BSm6ZjJ(i&ܨ79&,]4E5SKWt|u`G Õ|IM/7*JPDa;8)|y~!*!ˋ#>2^׎ 4sgme 6P1\д6Mj͸ Ä c=rPf:ҪZXjy7]kBfUӑ=negr(Vn-Fo'%ԧܙR )H@nm}H?SuЃR̵u)oHWIQMV]MFox]с2m ^%&]Э{QG| ٘<K_ ~Zܢ> )hc&*6xSbsUE*MԡElRy(JFKVt8,@9 &U ds[hqqRwTVI.ڭFJGSp9(y@= >x5<@r 4Kh;bu-JW%S Woqb-5KD[,'4V&zAgs`~+[FM)r>J$\E^$iU$LU'4AM  f~;Ycso(D%~PZqʃnĺH'r kPqy2]չ]a*R^~tjZҲFFXxKQ n7$q=-RM/XVaX E;>sKiTt:9>U|zf0Ԣ=Pc.ƒ2 wƺJV|_2ZT*-$Hg+GJZSrQ64ҵL-mk^ߔ䚥U{_cE|Hi=TSOIXݸxvnQ[ӗ M ϧ(mş $[~ zĶ ,؜۴Ra*.@+XXI%+0N#&O:jr\.ļˈNqs<\t0n`VjZ'/ d%H\&i'Q8&e*s@s-#2l!ss4Mwbj+>0؁&%PI+e}LҮ%ŪQaI$vNUbځC~Yީi fR sQ/S)zZ։48 I*:5rEjyV ^so6Y7hnmW+F0ʷON n?x؜' pnYIF6brM0-W8hR[cOL6RI}(ǣ6E(ZDJn0P$DrMm$*`kɦx>ړe55(XK{g'LSbR5\%A.qԦ?W_N JczID.K݋cMHU:Yp690ζo(X.Z}d$|Z)z:+Dӄ%͈ ߜc{#<5w^xRJR>dL6pҋ_:7⿤4,șҵN˫s֮id#Ba,$stM%EcI$gR:} ZMЬ6(Q5-!O'T,(WŐQK3RS ]'h'1Bџ WO/֕EqnTUNSd?GQOU\CIT  mM|;CmE.,v?X6P7/($ L#I?]"d(7XF'Tn69uNܣsq Ro NHZ&jfX693946 ps"JZAz㬤ϗR2 Y 6F3ү '#$LLT֩mk_#|AY"Н$ɒ'G"=AzNu*K,H@&6LTѐnHJi90%^_fC4 dw,N52Y"B%,Oi{HuT6|ƅ}k=INTˆMakĴLښi_}x]Vhe`Ӫ~,8J&RnNoKNo Ua~~Xuz*P)7"ɰyCucPRTWdrMMs3;6 s#Őٱ/@ùRKқvel%Hd۞"(1N#) al=Ki 7* *K*ru` EԤVHLQ2cc^X2yboj78?hӵCJ{py+]RQr.({$qR/$,8#q^zXTP Q*.72*|M3.6\5TU ?"ÉN*Eζd 㘒QS, qIReП o R-DDMɥV囝32Jwm&ě-z,99(UD+ň77*. )1r.+UJh'p 8Zd.UʤyZ#Ij٤r7EH'kZ}W ۃ߼-L+q%(ڞ1:h־x RڲJ?h5~a;݋fއ2݉҂[Pc+ <vɝ}Ri`+ dFOfQDIJH67JV{ q€{ b#'Vl#c}D*sJ!}aӏ8B@FTY +5'B8 9*sxd6 Jl;|ˠ8J߾ p!mqYR.Tro`p}`0>aw-bn~c_t,Jl rr $}o p N4@Q9-{ !$ͳD? ][ `"OXy*oL@&0|B爅KIA)?}/_)6ANX) akI6NێbSJ. JT*QCZa6^iRm@rG i>^(VɊo4f\vG^I-)h"IZA}hҾ[8il-#h h=.)-xv@*#ޞc7Îjdu9u&YK>mol1KgKКMH={LȅxӔ[,8!J(IŸ t|7i74^B'mw#pI(Mkc鞟tLDĭeE8w&ǟ>+ܗꎱ;:򘘘ZWᡧ,BQu_h~ *7>q O]4ɲrVO9.&*iaZF_5'HbJKI_轮SǥxhN]ҜwU^>3RscRȤe(i)^_đӿt'/eւJ$ ͔ 4-֗UܗiO%dnOVS5ZCNϸI\ԛ_Z?QSKuM>6 ;f8O]h]W:=5ZfTԤ4- P9NuXuWJ5ͩ @'6 71=]zqME+e E6 qbBw1ZZxvab[RMgQoCSR+}4v9؋a~xjw5F~D87PrTqP Y&G[M\\p+hAߑ&&hޓX̒ҳk7cl{)41Nd.`,d+0Խ Fu>좜ucjRBR =x|hG:UꦫKJS8a߿zTiz.^r3FL)Ge\G28U&VޑyZZ^M)#ŸJL8n15\XR\}સ .,N :Rq8Y"ײ8]oEfivܡkpnD'eDe\› j$_iv֓m!L[MI(n, X\̬J"D.khV݁& V(x{M];tEjbg8lZXl6=4uE%٧*OIpߞU/I4Ժ⓹M=ȿGw5 I.YGo&عCU.m>釙3ꌸCe~&Ѻ1 ^vE zM68a vҔ%&PZ;9/U-u%]Ϯ>UEq+ڊdl-JIc;CW3$pJD+0:YI[kTH#?hRSH&esc;_"̪:z|{@WqF|Ϳ/LtYbF!!dZ(:ʂ!J?@h$83(NIT?9bnGTH}w(N#2Ԛ%NI!{rNN/ )QywnHmS y"H-N䯍x`Zр*y J{TǬ2IHKjHѠқJ F7*|3|o? ٮeH"bAb8&Y%>ғU5 [f}[I?aE&':Ce%д^n88.4ؾ Ft{Iax)ṆZEEx@ %Mw!ߘRRdV#d;ŊGO`$R,< vq>{ET#LoC8Hoe{"&kx+el1q7?JfM)ɚC *Uʍ0øLJeq+}96~j5 4]Vm)!G6I=įRj)Lth 6?'rfR@)xV'<% N픀 shNʽO/ěˍxrQL{[2N*m)RǛ;D:]NH 1uGZJ&ڬюqEȔMsWOO91,aAf3I*<q:mRN\yV[.7 Xiתi ~YC<d~:Fo -NbeX!"u"AD) ohhl78ĭFeդ'eVb2f^Saa1P967Vur%H &TpH @ɺOQ5E-Թ!8f?X:Rrč~R/PTv\ZJZ[vQXΚ뮥~Z̹\{sJ匣Eg~Y$z&Nf]jKX6`nOsEIԑ_ܶ {tJ>#5Ta`j .\0I]j$h(7)?iT a-)9bvOyӎZ7<-:7Zn䦬_S }ϼ Td7ڿZe=*$[b[3iBFB90"X)V{fbom%/ _0E-rNc` 7>~X?qE `OsD^;TGHNzs,VE½CCdJ)""'eê [,a(`_TgȢQhqf'"Er9cLZIps|.0J)#i5&N?=oW0NK1:A6ZEf'~vxq-|quE1O:nyDY*78iKk''cOF dT5Kԕ3*0Qp0 M) W=!)RVAJQ&ٌX cGD!RsbR>аa?P^[#}!躈3XfZ"·r$e%߁y<80zh50>Todк)!BS{yIkwQrŞ|v>Lpj=#.^}“ ߴWvL۩")IC*cZ#&IH8 UiRTTW 6IOYw)HB>fm˒ z^_0ʜ*6xT(Wt(^U\āBJ*Nb4, E%a-v 24swێ Rk?^[)P6!Q5ws 'j :ql33.\,*}DXRcP$F?Xt}~#1Y9D*^an8*qͧYi*ɛJN-@hZSZù)򀽏|Sfl$ĔML߶- H݁QͮS:Txi8b3ң}NHUv!W!SYNS @&f&2cntߘZ[m25ϼ>` >Оfyys!{o T%_ʡCqh*bW!Df޹]?K!8ߤ1 ^wCJojn/}(Խ@*j]+IU"<@:I^jSt hGw&dRX qnCOOK!=J MiDD=;F+rJLE,y~])M1翬\)UJ6.MP.6%9'׿hcmqq /}'%zQ7)Dboniݘ pn/=i\4"F9)1>N&p}mSl)tfQ8NԒ@H1zT 7>OU)uyRFo%%6}\Z|5 Ecbue3g囟h9`}3Kʥ ) kMvX|ҡY hc,N;Hޜ#FlrZq; A'VRY ċGӭYڅKy95ʝ1-Fo_\&q,Le:F@;JM~0IHnU(l;4ĉd*7߈޶.rmA rp{z7Q)[$6IvP9bΊWTiz gh cymd'QNK*oX5ԼB_pN8܌'ӌkUo [W_gnm!l[s%AEeVWa7)ZN(2<0y-  Th/RrcJ{n]2q`{)@aTh79 {)ZUn AC e[,H)¢7WHJI#s i&LT[$6]{{[*US7╅bk*$)x$kE啻hzo?&fbGdczO}a̙ohmZ}I js$^ސbmpwA&f2yŰM Tj*&ϕ>>"R L4CAJxj)qEcmG.zI y)7 @ĭfJ}2%fynb1Ef'-ES>Bc1u_š&VbnOxU7)1di&mCD-hRpshR`GF} [ڣ{s!C ,q%V R_l%vQ6twn0=aWIJB6CpTѨPWJM!_Rsϴ&ցu'CAbbOA Ǥ$M?a}ƹң~*ɶp 1dgrް.2bQw1m+,ED\uHUL^m)4!pxqC_8@ GSVXUWx:ڬЮQHMϪ}͑iZt咶R(c ]P֔LaلjmpcQ[jyI>qCմr%ߎ0*(d5e-{ԝX#:%9QͶᰰG]^93IC)2_!e$!\ FDˏ.r8#:=u*+/ rE>Z?4G>?K>eNk +-0o%JJ8Ż}֕lޡarX[qq#u`FccNFyW&$@'j&kJ6ӡRтZ3ެsDգRQ:i6-*r_HiQ(Ln]ԥW3(mfiWnm"HqKCXU{}zK\tjAFm*7ZMǥM fmGOVZWڀ76Tz#CN2l@Qܣ0^S]7&KL,] 8CI$c]諾D}&eQdv#r0RpnqvwJuO4:WU~ͩR ŷGi>'ʪdrx,>i_MUZhL%ߘ~(Ua.A[LzC5:wR0jRI?r "OZ9T,™ >*f<{sKOD 6ʆ;Dz:ǭ4 )Y*T.lM՜qٽʬ)d-co/}+]lȩŭ|/{y"؈#Nw$Ґ>t&ץ4L^݃{R&8Rx5gTe3fN3Tʃ)rY6/ cX{AtFZMN'%<]\qD|-.I{pإ@xd(Tliw+-RbEE@aΡIp\&޶~P?5c\c@3{{_ ޠk~W2˺S.&űcf>խ )۶ӀL_Luq_!eN !>kc gi)6!˒7_&0*&Ԓnv[^Bskne%dz"gtuDva!6)Ẹl 8^tMmN؏OH8R a=ƉPP!"AQnı woQUtf~R=s ɱ6l><LjH> lpHoa7Da$. UɄ,E QF|4oR!dqA m'$q)XC[|@A@0<.)V1/Lԓ I RIHddyZDq3Bk9GSmƹN.Vb:K|'pn~!IidnXa 1y9mش)*i5MIJա[OǩԵ,\l1G}yۢ>[?XtA1\}C(41kXt7@ir&i8iORHk//Ӡ#8''ZLƿe!i$!=og&1efi q[R*Xzmu M.bR&zIMqr,Yt)bֱ6>{'&զNPiWm*Qu!N4=9+sm TTHp瘠ދuڙ٩zM*ZnvO?UW3,QYmir8ur3LS6 RXϦ>k!h_azO#Stյٙwwhu@(>R/|~U=9fZPu`Q;L-!NnYTGqRrWCkiSr6qd+{QHxWz=cЭ)l7i]_wJxdӌzkNN6y )~NoƳ{5Ha)$$Eϼy9a֜u ɞҝOsnK:ʯ{bХfbBed$dch~{L.sI$@q#Jچ~=8 \/b:0ÓjRڌVVXvE>$ʹ%*A~߯IyWD㹼GHM͉E/Zݰbaso EbH;ABԵؙpW{:O6{Lv5?L[٠7J1)~;)\z^BIR]hfbx%('%>.oxӫ'[^>;3ݩ-)p?;Z"y4CAi-9>IRb8Qan˿HCRMŒ7!3%D C9iY%HsEgL#f/RVkSqJ @^&ƚV 罣Ni^0RiPnjbmR!lARn}$GRh-J<݁A60jYq7Uʈ[StFm2mOn_@ -Tx[7:+`KQ)yٺ^ I#-VӛI!N[!<֋}&B&ҝmT=Ex1,>1Ĩ]L,ϋR?Gߴ3,lLħ9h5-1el1GG)GOOir >Oh`xd@z<җo~M隋 -%JZB t 0<߬V4y-oP `~#+"Ym⓱6$}EĠ\ʤtvHȶO) _S1d1kzX3PMNvm@eخfњrL>V¶1'vX:V/c ꋒm쓜[ӂSkAc D8ǹXZajYq*BǞZ*LSVʾM/[ZUEj$`\XFs5\JwnH.Pi(pJS*ϛyU )~qh{EλbJE$g%F16VI 8sf:zi,ɰNf8Ccj&mC1=,&)Q!!br!OJёØ !BM>`8 /g4)4*h;f|xhu@6m]?Phm* M3Zfz*@ﯴ6f:P+R ȷM /Jv0a9G4덂2F7đDK$mDVW/2U"P똩V?i(li%Z\JnDP('k ?ZO+/1W WHunb=)! dۼ(6"\0GLҚ{Foؕ[}OaRT2nM bHu~:…KI Nu%۹11'\))>K+Z/Ajx;toDفos!tUژ;VA#3Vo`\VNw/f| _0F+RRBA AbJrjvua/dc#b|jENԷl\EOQQumAy礦^C4 M.mFSIŹrP鸹d##7CeP1p{@=ûT\w=y!-DN?MJOosTT@O?HxA8ɉ)IN:զB?#CWq(#BN! GM)wZ&[ޒ9_ooXPVMF 5DǵrR.G7~K<[A.+xkӘ!Z4Ezy?4bl%:m2QNo5 ),cfeK%DOD[q1.)yVIZ-Vڥf%M}rc\X vt؞ h O2 Jp 6PFE06&oeo RF _qs`Inn6{n!}LBai)'ӃޯX`f2e yY…v&)^kq0 'ɝVܜ Vd ۈ.oO"Ztv6o^N,}vJ9mcǎ_)pd+*]ܤX'$Ȫ9yBk5.YIM#>ZL4DJ7ۼ|TSZRҲmC$HEIKGٞLIJ)RfZܱ>)ؒC$h9NgEro!1Ie.x" |g%Z>" ~J/+<AQL|f/)&:sKП`= 6s|nRN ˨@;}EO] TV/8 Hhg>Ӵ*mA6w<!=^8$WKBhITy)Û^aM`WP8㴚kmeFP$4b]m\09x]'u-1,CImH`#jkO|eT>_|׬NuLN%h hsQ$Ӟ1TMZY CMS ;m؅yhMaRc/% H4Ԣ*sU W7ɵ*"L'#gMmzJDsHTY ZJHH)Rk+"^SRz}&񋋎mWch<:dCiK(FbO3nیKtX:210fnRۇg1 Mkc)3Ŕ.b2 YtgIt;12jqmdJ>!J(Pt7AJ^D2Rq]\3d-Lynv܂{DQ* g7O1)_;J,E)/."ȼw( ,#uHZ[m{G4̀S8WϥJZM[ b&nI[I 8Rzr]Ɲ$)ruܡl?4T p2s{^3R"HE4ZQߕJkkBWЧ?i\ش( huwŸY4摚fN|ǑiO77I6@A)}RqMnX2.[ՉzHLA'p}MXұG%+IA~aJmrȲIQT(-&L9q7"up?P$88iD޵3y3as>m\q3n&(zdNL(ݴ"鞚fm>cWɥ3uBkf% ?>/''>c<|U!)dqhbqhh% '^=D+6ֺ~f=.B'-**+\ C==T$[mA)$m\+y'4J7WרqogTѡ*\:Wcsa@/Yf,Ӭ#xxE/H-{CjfujSN)Ж *-:{TU:nfYּ5$:TmXDhOp[mUȴĸP1pO_5tӥ4eʶ;G:' 5U4)`yEIU*n=cӽ(J'Sg;RVҲJ&~ڽHH-繏Y҅-kYUi T7 8g1F}1^CMmB|#G?VʷPU^H 4 A*Zҝ[^a+޳25ϿBuƃfN<m'iOy,ğΡJԤgu23rJ4p ?;Ai\)لI_@}d_5Lyy@ZSϭڳ6KטuY 'ڡ⁴<):3/.$&fHB\8']43&LaJKQGXva(^uVRmE)CxplM0/cy65ƤIh~f5:丰'\<ӎ!l0""Z"FJm1d~gzu6n2l)\s.-SdnBMWۿ|CIiI璗$n"I!0JPciABpOm06 v{ieu 69fQA&}I#s$oӘFi9h ¿Ch )Bk8J-N[rGj$< lЌi[yXm۷xoTc5Щj*q^&m*iYPյC ?\ʒ\V<􉆫W(d noFbfN5Pۭ?8-hu.Y.5( 5J{<ԋo6?o5n^3r!_õ{ x᫋JS3srVrfQЍbDisJ!Bj/`e >H9͹T ME$́0wp&Ȋf2݉_oA'jqa)H qkX_ UWeRO¤׵Q@nrky **ZFœ=CETչ6U-jt4-X~LZ/)Stٸh`:1/];6%?YkjtR;mӼa::ϴݶ*9c{H֤;+h'<^0N麦xӤ”#r|$N.0 z8BݙmZ11PJH7BSɪO!Wboz䖤V P$`Z"&ۏ8{|n QVؿ;, ۤݴsɖ\RZ)ZE8ƒyޭviS,q lA fE$u"7|.MH39&vԤ׃$Pй'55ER8NBPO1= !O4U*!2wǬzOtC;!Eeh0sl|4!&JSP apsZQf-fwt>SnbZxvMi봫o,MzU'u=S԰[p3JGjrfmrJaeBJ~0GuPs.ƉM!Mf6璀봆RMN?*O52`1NNi$Iܴ sZפ!^&m)EBZ\VScUn&$W)[}WABS`RmxUzͩ ۄc򍷙X+M97GpPKS»H5oZ*#oIUkUY`~q6uS:M* rewloO )Jq\ Pń\^aH!؜S>=:O;BYv b_2ʶ*MmEwZv2GVeEG'SqM_AɄH,yI J͡ӲɛĴ]ϫYvDlOuԯI#M]9dnvhn\%.7r nU3l &QRJշ73b:fܧpO^^a>&_f%e`'jwt&Ҟt1b ԩ;ޛ\I PP8 C**$ VT'Ci>!btPX_Usmߞ"@`)JB=q̊[++tn&8]da'ӛHa z)Nkr!ͭ"3[^0CĖnxh3sĄF6G0`8zrraW>e`&v*=F`<œY_9##$ˀ M7 >p ʩ&YAH: 5u\C Hn'mk: $[:7~3n. R THR{YcrIBHB7fn,p{p]F؆h"2AO1!YUK:-j8nᵸEԙ@ / ̬$ "u@ܫ@2@}3ODh]?ՓJq32/VNb]BXVoZ,\K q O_Bn|R Z w}nJ m.yS3t6Mǩ XXj}[yi ^ ٱ$o9h0'(6U2n[-'p  Q4\a"Z V&ՎZA-,釛9r1[z|`#=1z%DAPwzb^wԖ)mZGթN>^oKEWp,?(FtbU뮶T5-ENoX .vM/xWS1>gJ2=aE8B$1|cr-k GR;lmY:7#"nn~`mpyE:.)Mqk*kAR]M#ft->r2LI˴É9V; WҤc) ?_$,m'mlY667@$A xpP0E_ >ccl߈[)8.hb/7kA XYQe`\w>n xdkRw_ncq4cW\YJ- Ґ {FPδTUCIxn<;nMxM !^c nщn*Y6IVOxE D-ok@0Vr #9I9܏A#&B@#=[$~P07BTnAn u(Bv$7E0QKdh.{0]\{CRr,/00-F?I-QakJkI)p,I*qPG)j&ރ4^hj|9Ku$da<&Msȼ} m kV)-n!A;.-ͲLt8,iɩli;it_.&ie>X-XVԒ,/Z BfSLKJΠ%ŭͺYҭ+Ӛ Pe0ڬn 7'HKwy?&ˡ;Ɂ d<:5 16yԒ@,Z0% >ǝԫTV'i#$E Y]F *uoDXVܓ>wGUee@{EurSyVJxHIvܰ|NIhITt)`s)!z NH<"l06PIII(ڮ l>즦D2QΤ885j is O )[;B{_[..C.nXLѪI*`]N=[i:|ͳ.' g!4jVaŀocF:,܃sdK-CnA?Sqvc7ԙjZ|rRB Rp0DMK稚ao:(lO=q]6zE E ./cICȆ6ܥai6>.矡2jZU23RSIypN@wX鎸ו6qXu'68E1YP`f& 굲%k4X$lH&E|oO^ߙ~ʩ2J7(|&1z6*Hj'vH*N=^zu֐MD*+l6#QTޗӢRB).*J)_}=~9.>DYMzmZJJk+$b10ظPu{<&>(f)kyM3/0p' ȏ=.j 4TR!cq |m`3r"ҴTKs7ctMtB23RRB ۘd*2v]=/}8uڲ u^CmŲNRLG&4V![+x]mMkFhڻ V][$ m`o]> ԝ ^hiR[}ɵ|anrtKӭB,MxM17 k;4MFEGȞġf[}3tҷ{}pbNpOhO<e%WQQ)]5ufu-2 OeCnLje0mϖJ&Sd'a>R mpis9Gaߜ1w'5í",ޝR$\}UrZPe)/,'do٪U*J@kE>Ft~M.J*YR)GP"xnJ)H?8ܣ!Ӵvuև&W%Hu cUKM \?6N|DYם~Y-koq%^9ɑ\N߇jt<[TrO>~YMeĭZJ E( /,倾qld-UP 2س,\;ۏKF;5Wm)m{l[hVhizliJ jKUdH^ $ <^a[mZWl,>tb]ڂ0 @uPu/TS+ *uE '>ӣOH[j~4oL24\7qЍ, _p"یvTmb]i&eW ematP&TL҂TbShj}2BG{} x~üO09<*MM Җؑm/jnUvEM+3)6)S;4΂\'>xLzI*.U4oޖ"Qe䨮/6n8ڥR}2TV>}nNKUYmb11GZ9[jVMϔF=jHK`\IzZJ(bU '} ^d7]60V;vER64X5b`98rwZQ/H6Vl oa5FRBI)S[&Q3*7Q9*s'FDž#!4fRJs'8_tON|S& NRoɵ/zEĸJT@/q~"U!Z˾:V؃Flί {6V٫Ze PSXZ}'eN\񨩝ؠ7.T !8U9Iy! o >jnZ u;!<`g`k71>w7maI*j6𷞰R@Z&Ӻ;rl]b{pԐO~QSҺ=^[)2[ 2j|ES2E;J#sU>,2cSxFtȴ>e5?\( }+J|GԑTR-X`f~qTս 5GUǘ(^%[BÞփtTId/)*ܲ췔{_  93iا'tEv8?wxۋ#=CA` fNS3^mT9vKvٹ+!9xӺ9MWCHkelM鏷Lkz2c'zQbBq K8G=v۪$-?q[!im;,0SlR6A^ϖp8@ޤm<+QEάly:ˤr#03 X0sZQ*Cs!Ax%>QR>mro_Brn>Rkfx0G+s> ImX?89'  |UzK;&Qj/˸E8EP$e %JRPXbRe;RE^iL+h4ƩtO&Bu)KŸo>:[:.JۈqZv)Rϑ@+Prk!y,sRE+(qq5" .ɨFpqQЗ mib'3al$##&5,nlLL; P[Uxǟ8̦8jP?,J?vV*]MԿ .jtDOs`=5Y雾kQqT08ǿP˵-nkhnsyJwjM$ l fJO%SkQ^ &߂г kO6ܓh Q[W[a% chӵk)Ĕ n6tA@y6 IuDaN![avfplO<GѨ>\؉JFR}oFc/SR~si _3LcTHN2AQ7&(,^ђi-/p &mHl\a* ~/)uTkJ[. V|%*EXyb18@JuWEIDHU&O7yZ3yqV}=bTS+a#!L.r)*JO0ѶhƹR!٦`4]X07)(qԌuJiwrqAtץQŇ{RA Rqafßq<[ "ffHU #1=w I*>Щ} A7 -X OIx$矤3e=Ba6CWZ&㟤"BBBJB^W%~px& #|;j^lL'̓1!=´EBXTX 67ue_m Rv9& \{nD?P2 &ɓ0h׸G.i9ZS0MI H۽& @Yu]7%'E<عǛgYm]ͼ"jĐTHb|mv*4W)yB/[iR\Qǿ1JN]`qqh>ri=u#V̤MR!/<͂1KyIW?.T3q|2/`MIpy&`"O 6絢2zD}L5MH2veܛX$ψoAix$aB*,[HMIV sn%m& /"]*_fexhPp $L~Es4j)ϼQMӛ32mEbZS)PO@_pOrc*cv&n/^m+9TmF/XEF7ŀB ]AHY&bB{fW;./ϴe(M*|w#@6j^0'pyjtI0`O-dȼJCq҄4nl ~J-BњSJ f\ݟxU2m6 Lq g̤ F/oR6b'ho6od㹮KByy ;t;VP:ZfFbY-!kH|ҔʊK\G3tR*eH[ʹ'ݹ[ MRET^xs?ZHeTEЄI""rlM'ebCP=FZ5e9Ũahkh ޛHUߕx&Aȏ aSGoSԷ5ݨqY,zS) -OHfZi:{X66VzhRmoa!z]ki{n-p{^sR%Nx~>I7\Y>fVD2hKYD1W89P$\'C7` !$ -u l݀h *%&woI_J2N]p8V #ZP<qr ϧxZe`(X|`CUm,%+*r,"2e$)6”,R6›(-Do(m6{:ZMA{ \@ L̲ԾSdiLx*$J)=#:j ht̙'ܘ %"Fs+Sj*jqm8ڃ??hjkN66(ۦm^"zNU472-$\՗V2ͦ5C>&TL7;Eri,|&[\XG4gI&*lҐHۀ.]U7 m{cHS4'nMśӔ[7?;UZ'5k*~)(S7kNin4L3K3+x)JɽzeI&T̝yJq3NP5+YT.NĪl?8kP'tyBہ~s3y Ba֒l/~#5J68fBw q'nHQ2HRQ P&U_J2 vCuMt9u)9Żl:Vs蔎(̅i=,-Ne`']*{tFkzQ89縍YtY<بQTbsl7_TiIMW%.5r@-squc[c O[hjɩ2PIlwIWuʿn'*lJLui*ƍ8䔳5 7Blu6q I^.23XϤ˗aĻzsRn2BmG&I.3…޹?Xh Zpؔ1pВz]>A$ Dg:_SmzfqSm Kze٩O>vIs QȍTɄxJq ߂?UfR*IXRv`߽K#h I#}1턡ƖHb ?X vyvN]3LNR5n< @1lEçލ]eS5#/Seiy&0M3*ru:m0Z[G@bn`Ɉ^}Ĵ":Be ܂U*%i tqn=hnJZ'rwqoO% 2=r3"]͏Sս'ZEu HA{!jFT{6 qM%JAIUruLFU^MdsC҂M)Q2RkYOӕIBڟi\lXs.RiMf)<ۓu=$  XB#j&mAJ%!7ܦx rN.]čF\R,҈fJ)I%XPT.6pg!T(74 X* S,3ɕ]Z2qҔŶm '_uI JMzZ1uCԆ83 tx >+M\YE&9̦NpXP8F~*vۂEÌߤPuU'j̇7pRv98\d!`.}I(. ҤCD'/OC+RKJܑ1*ROX_,BD`'h3-!wb!&™q.7 2 i۴zoMt=R Ho324C~2HH6)I.UnpTS["8˅Jfe*e$}竈Sa':,uIzATm9biwIlF7[6Bm;LʡͮlŇ׃-/3*ڃS*ga(`E*D2u&Ԡ˛ڬpnlcޕ)il- Pzw8w-,~Owb͎s\Zn;GHJrr07ܲ.%@-_0R ӏ-L){J%\AwMWʙuu{H˭oYR"PcFnJRa*P1.R]C&'lūF=?LIC,^I"l˥^yi(]X֨5MB%ʱysET S8+A8xGI^Favo O&_2~pffVIdo~jTEޒXw5T璡x)W64ZjPJus~c9:']¡פhtɆ&ha<XVBiMz[Beٖ9|öSlemxMRyG/nO@+i3(lbN~!V;ORi)I!ŦwS䬃52R-k fUeUmWvͭzq7'YˊJP&۽3oBl.>.PO rx-zX^Gs91@[!@ ϵ9zrg{rwWsF&IQk=:.$ѵ`yC4bB0cZnb"BqbY-9%rUPp״eFQY$ n%&_bYe%DYa'ɴFzKJ*o#vW&u%`<0m~ck8P3q18I+ꗡʩu('?sM#Š?HdWn'&88R9v 8 ߗ: H!ܕM¶/vКzʜi p[H;FqQuJcTBvߔYI #'4t;co7J WnUM2IM@9;0$[xm-&k) "$J]e"5]akDE嶏`}%I @~sG~B2aV,}H!ti.ʮ9z]v#or7Qaܮ>6 K>lyE"H9/;ZƝ&v9 ZJM,%XxNfY`we(}a*\aĂ#|]Otrs{Cyo2sߞ"&HK0{-! &!V볈 {.-rk=-.[M. )C@\,QK&`IU${O\q* 67Z?U~fEۍا `ȂV 9rQDs"Hʨd cM܋TiEUR6 J0YJzZ0ԯ&";%6nLRŐx$.B"E / =LYNHǍ9 py%A2$ZxABtxu( .Q IݠؐUXafp,7me Jv.% TI[0Neh &2e@DcPyTd˾8BY~Ua^f](7Q PCd_ƶAfaĹl)`?8Pbn{ u+qЫ6lZyP lI1Gw|Z91zBʀ9=ZtFq(%Jayy>k*l &&=iR&A6Jp~f?jICRZ0dO pfa670nl#ܘi4L V)k6"2S|ZВZM>Л)M#{ 4I*07Qnds%D}{Cj6J"waTMmL:ubO0.=.l ̹WED( Eg J>32ms8B7=d.˷b`"L/6IY 7xZ}8_R2Nmn25+빶.8A4jhzm»Bndc+0 Ϯap OkG}W[-oJ_^4;jaAaAV4ymǬ2C>TUMЎt [aɞ+!.s!F$pqnb5 =PS*rXڑo[e yAZ'0.CaNYA}s4\4ٔ%~T9ro^IدJ9/()V)-3XOwUiF˦,$ h=]\yW&1rDaqs<'h ˴ozhL,T[ ?|WFGS2 Uۙ){G>2)eC3`3y_|8FLk`iâ6z柩[rUm-#̒ ^l9,$ 9t&]଄snaym0]BG{ϡ F2rt76ڠ~hMP%) y>1{E5)[ le@^$(N%С XL9NĶG2™u" ߿ʿ=%u iT}BHjeXohM;\S'P[ ’+]R[tI+|&ޣx;bQYWOV'[Y\̇FH$ؑKk ORu?f)h$&7l6 Z4*?CjV?mKN!*CYKjcT9yU͢S_6.<01Zj|*ϟYr~mAƕ4˱P-T)Y5tI\)MEka ?(gruZ)Ϛ]%OEw1¡U^f[a)% chŢֹڬҒWab"߉ĴJZJp}.cxS nbn[Z\x᧨27 gUU[]k:s7Jvq`Vrk:9=luCU6k0()x{ZkֶbFT(ljzٚt)62k!irNy+q z6jm\ckSK",T WM!uIoQgĖ )ܛvnPi R6UcFU'SnkQMμS.PxVr3 8|@SYtץy<`a;M==x3+zc™8 {sgXIѤPJL[K?-z5RZg/=U?hhh99ɣI[^ҺRLƫh$.R j}1Ɪe.[_rX[n9x@kW97^jU L).>SG2Ҕ6f- *>8!å!\߼SS~r'PRj)${O=PQ_KN%@D|}׋r$AV)qhTt@%ۊ]d Ť(M4u5>U4Ri% 'ʅHc5Z2(^Jp3(Qt4ےP,rKlY} xu*A rY;\d=vk>bqzlmW3ɠT|9k/K.iCse^?Uf/.)>E{{SU%%yƭ 9fc$)5G|@/59M*ae ^R2 IR.JB}É o1:J,PړoƥZXR HXJkjiRټ VY&ivߏ*XsDH;JR8ݒFoO\(DÈ޽mj~G5b]++)G{~VZݮ T_z =54n} E_lE"=Ra@i9nH.8ߔ2b9MQ+)U&\H 6њRx-D!<\X}=u>T [t۹#Nij&2v6 o|FB&պڻ'*{Д+)I7ǼX:] =165 ]Hާ8m*&mN.mқןXƒ*P]CdtXtM:E 3jv3p~!wE"Zq'ool~~9&ܲImo*BnB~a) lM@6#w|uHmOsZBZIʒxi*Ab=*ۘbGTKXq'P'$'ٿsǗQc8M([e-\=ȪP)D #؋]MI'ӿJuӎ% (Woh&ES\JuUqggʁM8 BNb;s&K();I@oO49`:Ocds J˭-fCiIHkp;Jw[Di 6^Ӭ؂B0C̢nTs;7l7 {߿NJ4P0SCBnlG0崩.+pPz'KX2eU)t;{U U [>_K+{mx7u鄺S(Io1"*`]Cpk.^K[^ U^]t!ܕfUxobϿ|A9 8apqP2שQϥMN, |Xau*XumUt9fIk:VNci8rm8a%vjLuʖGF_9j;qoOHZ}M&^e `1Tr3 qk~مIgqzEQ$^)WIzXSu |3>FU^7t);(Z!zzVқrX~5N;Gp& nl tQβ*VᴶMlZ3IM6&M6>[D^} +0cEWL6Iʳo1ϗx*ufzOA˥{JM7 cB;=P,ͼD$80zrH!V"&zxLx-۟Ks:cQMt`+{jE.X Ҳ*tݬH;IߜPM2ßQKK*aR bwі\mDҪԺrD܌A;{sJR\y֘ +vZ'6 KTjvdjTlq)tC%%jQ$C! óB8WzT&\LPڇ"=k9E%!@YKU/q1;W30ڼW[^ߎďxVvu )Rqa}K*Yg:Rl0\)cRH"0-, zD831fIan? пGn܎;AKKǔX@nO3 RrNmؒm=>Cy^SUR넟9鏶vH;X$(aZӧn]9p6 sKlTslnM%+K6w+XfzLUhtN)#%IuF.V$6M!l)Pp _{RU{tdsFA>AKZTsHHMVf_ ( 崼^6L5^ -@IL\"r ZinroMH};Q7QcͪU!_ϑ) 9RRKfLO}4kFXXR.Lˡj69ČܫmSMaɷs~ʴwM4&X~Isqy;Dܤm mD{bF#o.?߬Rl\*Y?$fѣLNK JO +nRu,广F!p6&?7@Ϭ4sO#po[/Ӳ9蘊p( -)T`H Dv߼\\CT"V"߬Uڗ~ro M-8sqH j3M"P?n \Ft ?A͡jid 7(`sǎ۬x=)P":dژ-CR=716XRNjdaQq?=7EqpڐS_vZOn KUa]^ 6x80%-}NRqkZQ]XS ܙ \x75Ty/2Xk V/nDSo7IUڬ05:URaE6;VNQb.E-'QTVI=ZDػ7ͣ)l  % PRƲ"VAQ>980U+oʰ1xi38v`yͣ$[0* rq J1"I'0иmpsK~S:LyÔ:MEI"b8tml1o8nx0ǒE􆏥$G`LByxAn]W|B܂l`v`)Gqhkp @ qFUn}'?  6 p#\LW#M0x2T?iT,hU xA *>eI6A;Bq Y4 |P{qu/aKJMV*}_oQ>a.IXZAVw+,nN/x Bk%NfzH-`͐}t&`*6@!;H jBZoIYU~3hp⒲ `q m'6ǴĹA!$7|¢d˶D;>E~8@$qӽ)w"g O;>`2aDXNKD7k}k:%5EK6B}lops~ +[!04S4Ex7N+eRjiSefޑ]EUOVIHqb8;}N.pIO@InxtٱCL2z7'n̴vݢ6]5Z3m-?Xk <Ӫ8Hq$cBZ;i$ٕM7#\-wvUXjV"w+oq۴et-%1.KTxܤŜVؔ@LֽB>$2p*Z槗QWη a;[T3/sHBB\Cj槩R[KH .~Ej&fOr˷>qd(Dig+Z4M2T&qP?j$|#n1{qɚN)i));Hd-Ԩ\XNxlls9S.C'ޅo =Ija:7K7N|)HQpJUn" A1MhucSh.ҿvH4EX-k ^@y4 aTڅ@L$zM4'˖QJ*R $RA*h9EWƒ*wݸrF=jשj&tbe7uM2 8LJPXVNAKn֜0En6ډBlJ}װpkuε;yD_2JU[[!Iɷc2i}]ԶMfK}8X *KM;ͺIJ*?ֽc?C?ZM:ۮ0BTln/c=/ÓqTgx!8<]{]+3.=!(uHTGЪ$oC̅T[X\XΤS2@InZ䛁d챞,xAH]wҩz%dn컾m˿}.af@ӷ9Mx*%I9-uDeES#p$STtQ[$W-./[ui%ҐNmGð П#閥rb%@tͭf*Nעq5=%SS<7(J\Xh_!f i+zYJТM .c |/2niY4f &pctéPoc<,.5Ym'[iVA!7)ZN-GD)լ(A2"sZ#٭kJe2sh-p=~Vֽ'Q%)ޛ8AJ ؊DPHZ&3eJ%F62\ yQmLg1KjiGz}}c q%\͸0ڶUȉ67TEMBjιJ.mB[hKO9Ǥ3:R6Ȱ!GmV42CfKiI'7y S 8($Ǡ5}>p۔c qcPxBu- Ms-!#:od@}oEcfQBQKEϔ8UJ`}Jfā[s7Yq6.#m)'0CaVGoS(W*߉uyHP,ΣNM2~bWh'.%̎{[#eDG)S风6(? j&5}m%^\Ef+=V%Sa;/;  cV6LWhfD)6#DԚW[Ҋ{A#9ųnjڕ3IBxP#i R sao.6LE'uJ~zaE6 &#k#qJn &/2IS`ܔPGP>(#* O86jbN!eJDTu>-L +Fp #@>:ev%&Xȴ;R "MlDٹ|@J$yq*<_Υ/*P~R%d[6IG}Hrhk$ Sd9S (I 6k ehIq Q*Pl, @HR\~ /WfYI.?69,s^~^n^d(Ď8AO쌐o8La*Cnma~b*KU'g=s3UĠ_+h vH IBATsHLTt㟾= R{ro{71 8 LK(Zr/ew[S.8-UWh$UUak7\Xw <}Uӄ)7#5ҪJE> -fyY WVBy Mkq|B/}wyeεkSu(~,Qfa~bv^EjPxXI͹--QjbM$,\wH]PL.i:^fl#P!jJ[wKԿRWt&h[TP0B(>Tz±@x̟݄}zƊ`HB/~h{K2iA>rHq2Zd;0RRN/ƨTYZW6"Mp$kq)RFP˨ hbzBN\Z(Z\Ov(i&"j-&$u, ҦSyN {`3qjqA@\vyɿJeJ : Yj+!GbI/i2lRaC:ڇ"ɷn !:;TR~}Xs!:69YfQ297O;tR-n0~UzELYk).׽o 1^i) 4>ڭX]AҢyߗx<"HZK+N)Cw[+!>`7~9P*^hIE!VJ{ IB1nSpGb?gCWlW!8HmakFG1)]DJ /)do6 E&V/b nkQʥ{P?|OE4u|AŀLkRm]3xe+m Zo1U5b݈? ت`pfj-x, m{DbR{\Q5ov9~m63{d!V+Ze$m~€H8"$]9i*uF:ecP,` YIaU,[vSzTnR9$B09bꥦxS\dS6J$p&ܤxΝTR66ϬSCKZ|mЬ_M0WJY%34!7 /J d#s(҂\ RH ~!G 3t[3*q.AniMZ _B\ Se&˳JAHP@OtGQDmP Z^INJ6nXK-< ؘ3`wT8na2S)WY7)eNX/x̯xFpy\U. a$'XEuDw֙&. °Ih&%+ nbiiJ_>,XǐtfȜZPQĬlFmn))6;ahǎZ&qL=̻NNKr˨7 %TuR '|G<Ca?%Wh^*6dZyɒXB.s}7JH/Xji;T6^KP-3* nfo2И*) 1S^#i5h$,dN旵D!TB>;MZ};(:s'[βlCvlAAmVQ+rϪaE3rBq \JDA [.+- 9FPTp03t!*➗ BzM3Hl;+*䢚آʏ*/LJe૞jgJk PHb( }`$Y'\Ko8b5.q]13"X[Ռ~-c krlbIًIKP&,x50*_RI"o $+p LMI)i(v~;x`ݣzý#q0k4лs,+"|d:ʉH7RGNUiRA@sZg_FԄ;%i=Mui$x?6L\XU +^I*ZJ /ǡ1c:&Е2V D-'23RRXC%2۷eI3=Z͕km,P)*z5#<"rt.ɹ@q1#*ӺfUToJnC/0Ds \~3+ $DTٶRBVN-n c/K]6ja/2-n{w3[Q]u)K!C)ADrNQo]?3/],$_KT|k+[!Z/H0Tӟ0w`')z tF7$(M@L-wu\U͠L# Cշ\dlu))X3j*d-j Bk)}3єI1iK+7 7GE&@T˩R?6_ca#Vft~ɖS6ih61A&zY>@RwOkaLʼI,; WeQ뵠n% tb;BȤPoQj~Ɣ^R\V$\m瘫SKKԩkK.% A> J~SZWQz3-D[MV_, |;/ok-̛aB>KF.2W6HJ-6#4 2q9BdϽUӍ,&)s2I+\T P$,sq[\N̡AJ=G@89Y>M5=LI\"MbVZ QR\ޅxjPoQ ĕf*L( i6/ T*T l%09OD/aDiJKf1)eVt^|Lt9(rU(JH4MOЋn>HpLg/|F]is:NMह&ZϚ;t#5S48s+5?cTD~] 9#ڟECLԪ,LV%M1nؘ>NW'$fe.QQP&Eλz|ކv4ouU%H[f9#̓BoFOVWL_Z>vUcx,_]M^5/U"4l̃1"{Mk-ff]i/݀Eonк՝.KZ,^Bj~FLӋ؋l~M̐7lfk-#S99Gf,or,,?wP79d(oF֪3R˼BTA<13t8$Kx|h'O6t=j/.ˉ;p*5tߩ)5ج-$u%\' aRS5J\طǛ[.O&:84-%oM=Vjr*(p<0wR5K)).RrЅ&vFcKI~yhq"[DEni*tT웨q$-źk[x5qӳb:cڙ3"idl0m{=!RIUꐵnx-(.NUiq(RZڕmqޱ㪵;UϻO|: —YJH GՍg9W5醪.$YhFڰ2<֓h aԵ݆ӟ3J hoÞ}pp.LEKԛ z_ќ{n]N'--J&PΞqROw7φުu :+`T_$my [a V}@=A۪QZ%"^d!uXqdl)V:u)(gґ6daqQo[zsPrS,|GO]ENGy)؄*< ^}XMI6%ĨyJ|ȥʿS-JcY+ZS0-8}9P$}!|VְhŠOAk/5_BnA2X"k狘$'L:FN&`%j I+C.p)/j|V~1b\, _޼E$(گE?r} t+LL,junou,Ů_ $I9<2ʁR˗GvIdҢ~%zѤgޫ! ,95Sh,m*-(,/b,Ht/KըnK߹_T2v DMb.k ue&k 'i - !-3/BH2=ҺK7SarBhwfjLn4Yh/s]B8OX%5% m7Zҵj t b NxqtiɸI6;b-k /5TN=Z]q@{sGqIۮK$IMs@cpsq鑏v'ò H>G&uJg {{j[khRlJoL7$-iy6RmRAZ8Lj7Qh)\_͏c1Nq4O8 Bl/{D,j%&RG(S3|9LciwK mßhwSӤٰ?l#Km/0Ӷ$-AmK3oЧMȶ=sa{X2,Pʮ-oԭuZVsP)[dXUxy@I)F̛cA`j?y|)3C\otߐ*[l/{G^&";@Zo5G]SOO*h7)a)>(`j(ւOPOiZL |EfAS. F>/ *}S{Nh?jκrnFyta]ᐖ-JA $Z%m8 dqɱ C4l/1XwDT)Sޱl}~dLJjZb]AW9@Wb$%ZR1/<6l%  *aR#K:G[)ZDUփoQ ,3Jr&v60m7[ U!p,XXÚ~ڹs3?E) JX{ ? J^ٹ7}cɚ:j3 Tȸ 9'$pN='.~-OxQu-mt\kHH?(Lê Y!`.װ6&2R wٷbJTZJwpwg#ay 0rƇf*l.7d}{P› AM`W>/;Rs|z[o#_TUYzeehmsCfp;m [jT9I\{=|c+:(S+_#rL7T&Z{7܈Vd]p@ MG(SEE=ſXq5%J8.A&25UDI}bRR+nlRgⰺI; }Bjz`"Z@M$BX09S,L$rTe%9͖n VgjTwT/c~GCYOL AAvbi%lؘJ)JX[.!XD!="eEd׳,5.d޷ģRy~;nELPg'|7aUMvH`#.@{ >bM9שKo-}FW%^T&eJLMfAW$LJ,A&9Ӌ)#La $ؕ(bWejo*zYĸ{["]jg`oMTvqéN}1?*ڥRmAu)E#3 EUٓp'$[E4TBY$7s@*eEMT2{ƀ̸hβTRR ҄r=&\ AQ^!͕^qJ~!)\ [A(h<n_ǼAdD*@& Vnx=p9ɍ q/rA;ELK%ŤrLyp8*J 8#`yVerO˶GW'  4ZriD6?g]E¸" ;*+JUԡ$UJTGfjad̴鱿ah L2^;Ds+;~ s\h$(˜AԻw ͽܳ]:HZAJHA`d {ġE;G86>tc{2HډOotr0Msꙴtl oOBhejfR!)*^'ϹiފAhIaIWڽs|}Zz]|ٽ"'ULXPztddҕ$dž/{)%\PMN[sNܬX}ČHT⒏*hZ (\NTTXWа8ʁ [$6Qn;K|HVJde06'{J V,e^j83ht80=U[~I7I'5/OifBKC9) *˩p/q(zmC Կ X_s]a6HyfI)>+L%kH*HM?hxP0.pA]0ܳ-lإ {D:f8ȓy9VW$(/cͱh4IokYsJO-UswkO"2ﬤN6pVI9LOɬ/Pp?#PTsFNL)M3,P96߬aZhL`؏,Q+i~3" ~W- g+gi)FD3s dzmDG174Z'Q& :e@(􉪵)%76qtA_;7C{ KWօ^8O[4Znځ,V `>t~KJ.'hH)ؐ`J)s}d}Z(T4Bji ⿚b_s.ڎz2ԝޛsߘV֒"\HIw3`uC˒ě'xs!K[Z[Fo|x@VĻ?O+] RRcً%7r$-S۸(ߎaBf%Ȝ,}b:atm"n2fZQ2iO Lړ JUܛ'Qt>WT۫* n"WAJ@*]+BM>O2z ouJzS. ȿƤ?j8ݮA7cw͸%8JnR|qé>ɦ\T`6YASF^ӽ"ײOTY>$IxLi;]MVҴH`J)H"d*L< ’.#$nFgìUۖtB,@6\e+H6M Ut&:10)/nNI;}Aiu966Iʵ-MgM)eK ӷzƩʪ^j fo5uF(~Nw5M1Im)Qb2NPlT%ۨt,1n9 ;%2/3S"qvMFuHVBuZS (8)8xZE*atawPH@m՚Zɚmh6R^I^9276VפǫŁ,s|nP33/̦P(zͬy-B꘤M-(>IϷyΰt jza A(ewA4_9tj;"I?x6\O[$׉.NJ~I/W)A{J-QeSHӈBݸ>IH}vrm!C-ŻFcKSSpT;"|FTtFt=aRsHR@BȺH6qh?S֔ܡ2/BI}c=N(yk+N-gKtTXmY%+/smnL3bYj -ӺUQSunb˯5-<@2aĄ-Z<:gDRC$(KQe\bn&Ň&H9 l|?*Ox4MUѽuQ3.|DmE#&4oK7S+-V[\*RZ /KTOq6"fID ''uR=fԕ7e$Xk\Gn&nMF< GO[LBs1=*luv9籸Ӂ)UZ$aSMPa_OHM1e)m{$kc.آIvBM- eǒTn;y#u&ݿ>@qn~olb@Rll-@ydS3TQ=Ip]> E!C$Q'%d֙IQ9bplvSԤWY+HHq;H ('D ԗL/V><ѵ@={b߬Eӫ X6"ޑuRJ Ry>Uijl)d{{{IG9Нnz=S.KT]mުtƣ_kꕘrJ~+ ~qzoϯJ^R]OڎaGGBS:P>rHGhknAń4U<1a N&TIRU\pVSTJ' ~&쫕Wyid"RlucZ۩ODY^Ď_ֳSEK/(;ak,T޲QE-R/1*Uu4/.#134Da(Byn1o(%nmF4~`U\LJ#0nyƾu=J뜵0kODEX~^IRRIΒ(q=[wjDzz4{ VH0G[jEJݣ6kdfXQA#ڟQ$HP9Xsb[KS՝|8"sNunFyAF{jWkX Ta9)Qj*Bm95SDQ1Q'YY6HUҢcsS3C+ N=㝰 d=AmE^QF MxL͋Ȧe-U ?U f+w#~b&&d`JBzP~h(oc! "wf=U{H΢Rv`b4˞!Mbg PnOsM8ڃdmǯhLnyƊ,,>yP:9HJnU{bKJR? OoO}:8GLyvB:scb=yM+Dm))IHzǐ($K~߉)S2Pv#b;>WP&?rASK, EOTiRF+}ʰPI&2:ʤ=fn'szևY! t6Ī's::*-z=K%GqͲkJRZCU-|%M@C5eC pm sr>VYR`;w*:i ׊2򲫚V' wǴ^!- ʔdZ-h/  Z GfUuWTU{ej#<=Q4Z7)h4){Ⴂ\9fEhS+rfi8$!*m V:ĩBڛ83bZWe( a*Q2}9PjE4Wnjy=̿Rr|CN4˓(6>˰4}/}c '_&/8.\XMeB侕}aK-ms \X KG4͒sq+Go̐yBPeo[t'5JP.JbTH XsPnbo.á~p=+wnAJ]rbN:@RM+W qPnysJ{8XRzI2xdZzEɤO-ͱ2@8y!Hqܛ! cgTrh$HJkJ̚榐TQ/6s Q,Q)A^-wǴmMPY9z5y+6бFj^T>=) I=JkQAn^A6~k饦YɄc7? 7b)>S+s8ٶHN̴Ʌ@;/ 5!IaSqdlB@r!D(5CL^,lQcsDKUNxTVnY dR#B/G. -&.]3^iqn}E7O&%ԋ^19RWU!ܦ9LldpmoH2Rl51,OrvV vUvL-zDay60qgn >hb+Us?XQeM,&VM`+5Zn\㐻>9u$6? K!Fzn$)iC J?Qͯ|ˆlǽf.b1\P0vREͮaAqY?0](1Ixrr;b:X(s x5c`/qH83ϴSr?x يV9maYG7J-  G[΀nH4d2fűrU\4BhUЇk)ESuڥ),? 򎂿 3p}8%N  bhW nIM*Q= 8U \f$C*zzA 23Yq>Z J~d&׿4 <枪J6?'7ZJQGe X CKI؀Ϗ2"'tl$fpAvj42e?,zf.zH9=s.WYcU(C0BFZ\HIIrc)'1U<̷UU2dV۱UkDKuu!fH)ۂHF]$RIL.->N]/9&a3;@B,o{8݇?مM)b- νy?X I+Im9/S4]c ZRT| +=tD)ԮNewڝG$_1Ohk#Q L"0.Thi]hC K%{EДW) i i*,mXcnc5i;tɅRA~F3`2|4z]=2aĜCh}-5"b윏(2:]Sre%IH $>'Mm>xy9<8ގ60]k~LU[ANb>Kq)uɱ͇hU(p٩XW(P;O;n G+'R~͛7\ 'uN"M%&ϯh]*N(J~'ՉK7G0)b!rIޮM3j$734AIRTFf&lڬ(rV6HiEaKuD~v÷.sHY_O2Pߟ:w*F2!_L D~eڜZ .ԧEJRt-X) 'oF ѝk8`q"zHjernlp#Vu?RlV&7 dAD6]3'YzJqI>"^se]`»3î: ;iqd#iN ̤*EěԺrrJ\mI^ߧD~F̤v] IJmq0K[NO!(hE} 'JPWIͳ1H+$5ƑPXmHqN V&4F&P*-럼`k:lْl\zsc2oMUpSkG NU™:DޔqiS,1nކlwe*iIظҕrB.MmCnΩd!JQEf5RxuZ\6-Rfa @QYf!eԡ$ E A/ⴚie%w r{1 דAakch>J\ZʷwzXp9uD)*I'#UN-F(8V%W)l}{CMK;ES5v8 cR81c#Ӽ0]JSl0})32 )uI$,e J|cC7ecsyM@0-|X٩8B<Z#{OWhzn)SΠylXe)n\2"s}a`.Z[Bls ɆF; oSO98̻2 e O^:) &hõp|2lݻcuTĄJ<1:z2 JkAsrC:`]-mխVW0;W\OMIʘ,xn?X}o 8֜dU [[y1͑5ʼ̩|^ ,ӍLVX%7Rx!NB (ԼT:IB*BFs똋:?y%+'ԘYN|+zK'IPZo DHվ WW+ iHJF^џUJ_2ؕ/bVaG[)*FAU"&:+Xn".$MgQ*u!Bc%ڪzQsj?o6:^Am(@d<ӥ&Þ*ʘi.!-uMn(/$ÀfIjܣi*P3`^Uvly H?_H-?p1XHJǂorM '*6^hoyË^TfSpr/c4vFIPb|lRw [gOͷ0 6ċc+Y^𛀦7 ^'y36zCKP7<@?HQC&?J5Ttivu(Q##RR.-pr}a0v:2TMx3nV YPP !REl_0 _zki!˞ )N+.,XS5C6=ș \jXHm +<[@8yMMfmlC'I0SYH8FSRDnLp ] 1]Q#6 v=M8ُ͠47߷7C8VǠl5_&M-3@ôy |*ǘ3 `l-l-ЌBVuUy%PߟosP4mAեRXU 9.WE54 )ŐMԔëI6MN"))E!&AԔXڂ9 *r~/gۛu1ѺAIĠ:n.""f:u5>< Aiq" Ucn=p WfT8!:Fl{] [8.n?8-xmsxiMKUy(fGqv}ZIx+KaJ6t$_6[52cc`T ų !Jq)bJu8Uv\ۏLjmҡ;B*S,pٲ)TF8\ph-Ǟr7 tgPAB EP9IÜԡ6SxF:4q݊ʃdyA023IVо-nTہRn AOT76PmQQiAMm1PޡZuJT$~br1Ϭ Ǥљ<~GTհE 8 0dkGB''SPc9WM7%#%<`Œ/^SfϠrΒB_v@!X_6r=FJ ǂ8j&t>aO^d* htFL<6H &FD.H:14 Z{@is+$بD΍1LDyxp7e}- gtM>iJEOr;Up%ؕ~!Mz}7O`U7EOr:*Yei 6$$~jYţGi9" ꖎu(UPAL{C* NK-$:iEcƷt=SK"oW_DܓAMVrCYcmԶ,b7XN3bqTJnVy8b9'03)K"*0`W%VPߴ.~U ۓxRr^P(y + nIebcjQkȢA9. ڶ+9x_CVIWS74ۘB@$d*H\VI*%D b+PS,Sqͣ@5k$ӵTLW-&.uRy"lZ{ZR^qE{gF)M^`˛FiH) ݁*u돥Ɗ1LV5ꨛL:Gq"M}s]&񒧇C6J6&lF$(M~1BRNeB&ܰj"GOjZ5>y TC,!RҖ"" fPW̆II"r^]ʜws+$l $`k*hm 6Q1X,L4\׈(y(UY9'Hgɑ>m!7N g|DiWX“ Xޑq`cRT^DK$,vz@)0H9%%JdxJWKb>*j6|} [d`!NqI9h.FD+@z@ AlE#7TvF.h7n 㠛%;8,rv%{{Z%aD|/GGFwcgu2$ [F+&qb"hjkr! } LL6Ғ.JZ-dǰT(M˅LJ]xY o8/Sj\&rT]E?xgUuN?}֕$$~]q>U!2*͓0BA*nz栛nNVLCno21VLIo+kRs8}Oh:a/3=%Jbq%An@/qȼMsD*D3`ni8r>ـjZFeJBM,sϭE ia)lq~{Al5N^ds9)7'ul$RSt"J #VH2(y b!f:մ zz0ʰE PD`!$T?C2{5fJeiu6WIuj䬋؋EWyF3p#r;jxSu)=6nJFAVi E6̬5,RBI9:( 'm9$j>)-0It6{zLl}zV/uZLq>!'{ߏX#H?.~]@] ^)OI Iɇ[Rot״:e24ܕFD{^!rc$$UYX X_6U&C`zIJWD{Q_z<7nD T*ζ[{zsa ^QZRJ ?{xc"YLӓCw oo$ ܧ˥aJFȈu%Tserm(ĩ[Sd~-2{b$E0N$%GwC1$Э͍L"J ̑b3\hܨhHm8ؖRMkЊn$ۅ2mM{Wਅ!nO兰&88 cxQQ%mX<+ mIVq؇2Я L-07%P6xmMԥ!Mvp 6A;s]dߖmhQs"_q2*s KQ-ҠqnaP HyEC8U(JH'i97g[O.E[26˅VEh76(?HcjҭS7R\@ءr EKtI} cAS{"(#tN&rnʁ*MTn XFmOm~2(Kw$Gkv)ۊ(]Kjou[-5MW*,i3'J\ vcRL0V[9pB@}6QU0 ytze;<}!Һ^awY9/c@^R@.os'6 OSVamPxAS6r㰃oI 2/ G6E=jX۱*=;*989&6[' BoEnﰎ/b'|\=,PnAO JM6ܣagp&[!779) zjj<3JNBH9&JEa!V㹵 -ɱHBo0:K_>Ljp=3 H7^$/^@j'rW c gm=-& `n:bqj`=>+baH6)bul <Ģ IJYU9nƢdoɗ/%;92rcIJ6_4ATHaH"U@ Bl~ڴ"a9'$[ $؛_q`,oT>7LrT,FASs;ndrM͠{ĨD5[ӷ%F j&nomITfmI2)O 1PEҙakZ)Nqj],gtBmeL0 yOhʫjyD-"VN" Ž>ޑQUE<=@ C :::9GGGFttttiGGGFt++0e\}B`Ȁ4TDRճ sTzAA|B-dv" eT}/_7* "BJF-)GTT$hlSYS@ژFDhQ#3eHT=F)RPFrԴ&K쩴r 2Z)F {xG*FyA#""i8IV9t\UD씻JK$~+QT'> {wOrPJ*S!K͓a s 1 ijh[D iw8* /YP)5&ldr#eLܬG#FOʔՄ6H)X @OK{Q&E]p>7*(2cǙ\l*RҮ('Jqð PEъ:*iOO6T]&6{))KSu ״qg)NA.;]$Pr`vE,Mnߖ"y:59鴩`nӜ}ȷ70OPN6>+u y?h k<U.lɦRUe$-[Λ)*?\zwuHz~]!}ϡUm[uJiNE{c ֗jڜKkd0ۗeAkzKRP&uR)}W*`qE]tʃa^[*iݒ(hJ_TM:~Q!6/*;:eVb<r* TO{v I87"RFYļʶ;ҭlb@OӝCBӲ3,Rpd>.iy)GjSeXa-ҥД ~ vi-,ϊ;kD>74M5N * eBֹ'd4zT,nj,6aZ Hh>پ!?L 1«Cni;NѻLCU5TR aR2Č@Z$5QUJIܘ;#L2ݙvrU-S WQ&z% O6BаXGh.AzFBǃ (u.;AP<t p{Ki<60J|Wt,~a˱ N{F-=.f[n$'*xkEQųk㈖.T&)qv;&p(;"qn15"*H yˑA JHؕ~L7k `zf1 b;`H=S)ln;@qt_H2^M-S`oLK[`a\Y+SoH6A7@ 0&eN~q41xDxѸsHs ..o c ;{6l- )o&ǰ11y6*5Ph}!EPI"X< t&B&`x#_6\K"ooB) P `˙Vy\zh>Sx0~s  cmB]V Y]; TJFYUEŮ0A(a6<ַ!#A8[_uK.G0e=d[7]^@'zմ F 5u`9>ͤ ~!Rk)'#Mn>RRkBQ"EM􆨶LsK|Fsx鹤-\w,\3a> Kҋ-7J PNQ+-"]EYIϧ1QVKQ`\z鞡E?W5sДw)_ IĂ@-kUZHQ $)jޥ:hҥ 6Bp9?5,kUQ6(p@b,>ٸ%:@vҫ̢HZ=5Rjk^`z;ʹNí71&{fXu:^y3Kk a.& DΕMF .|祦UyWS}*Ss3ٔSQԧI\ $ƽ'.e]mJnwLl2.l9VlUIAm=Ix5uGIJR7bJԲ> )e%BC E)ũ͸>̾nǃĽ"Z\Z y6JKidh䲷QHHֽ(2]^UV$қ6 pp9fzC< HIMRxeSDmzW*TO 6a]f=# s1_:{KՁM2i ͯ iFDYhYQds Ȏ?ByAԬh:MD)Jl6eReCe-C"C iPa#^K"'&\K@O^);sə]׸r6nkLJmD9j./wV2/366uE$ۚQzw)LʔPhé[h )vm\!ldM9?\gnleOϣu]8|(_{Nr![Gx3&Y\C' cnWUa)SNAA7e~O̢3Ri)j Z&C αTC!U{{SCjn9JRk;0mv…ȾG5ԝ9*󏮣.%J\ߔ@lxfm[kj VRJ.=}~i.W%&iMvvskzVRERmĦf\ؓpA>v`q%S%%W+ HD.2 ,NqܜWJr[è.4vbQ)4܆FE!;7H޻LSZ (Q AJU<=uC3*3ν$nM|&9['Sh4QԂNI=1b~k6+̹K U"&$驛 iҕ) aW}cA{OU:ͦ8J⽪/#Q-94(dMk.2"˟ B/>.?+ؕF7xZRAA;olz)et-_˴߬]v~E-)2)vLJqbX̿ R?)W2R,ƍj(.l^.QBTSsPg)F\_l3 L?+ k>`X#!$ԱTW47f;R ZD, *9>7R `{rbm)qDGl@#F$j-ݧBosdh;ZƬCWXse߭D4IP81aN:q,-U!W ~9]mlX1q_HikB9(6QrBMIGeڹB|42/lǛXLT1A@$X`;rҥ!M\"oN)Nn?XnJܱ$HMQIN䛏ÁnA@m7Ǟa]ljZxNmb.qoSm6nl^`=OhJpX$H"Q|̩ 1&%)>争Hދti$8S@v7=&3͸@ln*7YLB 'Za @10m 1]*shv"yh]D*A YH$oޝT QXJTÛ0oHsMʎ/[6q')+Y>lPm{:}Vnb*cEaT Y*%W8IRmk j6<͚֪ EY"4ie~Ho )=E=TK~C]/=1t7ɗǜ/4*Y(;n? +vf%nXjANVlC,?RDROۛFTU&f:Kә*y H7.4XbOoZAD2Q\|\An@.7Sm&RBOT@" k2IA8rE.r~㈭iymV}[TS ӊi +id"^b5*ӦUҤP81CXf dv8>PȁeXF=/$*`SkvzBUa 03)˟r87!*l {G6 =#+A9ၐ3w @d5!ɑ`q@͡dɀI(.)ٺ}a,5ٕꪒ- D2YR()"i`؃CRs`GH<~Q3KAnDX8b8/l["вK 'pcq $h:k[83zA)6ʳxb!PcH<;mQ{ZN?CM+brGSD[x%8<^ Cw&B5#Q㸄d?zE0q:R\_7%7EoI; ϥ K6RToHw-iQU`E&iٱSMzJ#L)\T`ֱrpmX)]eV 97))${*ĀA0L RJQ<@*@ \\=[K2mP7Ŗr]IZE"LN2̱wb|sCd#BuTV$M` 6'gP os5qc38LjSoR"-{Dĸq@ǡp~ (sBb)?2%RA< JU668G1Js|GQD(M@9JQ:u;^&i !kCD`Yp'ԂJ *RdSIe-8hҨ=RPy}xfpKۧӽ %VG`!##n.F[E#Dє)fTӒl"^fE͌`>[Vg+x?M9!EsO@iS+J=l>G*p(z`OtZ^;^^h;^^hn zGlWia^OX媊KX6)A=iƛ0vXʇ{zn-9#tD/%v(/]4P? &F5y.R-?c %T lwsǾ'%Y&)/k*\!*UNxA y,aaϸ0JI*PLgEД)Q5ZE6G줺s6vHɩsSerL1}73:VG)c*mɺ^2u"JN/XtER螩6{]Y4r'A>ҕZ.i:ltzwȈvƵ0Gt4S&O֌gSkԤvyƇ|C4[ۊѐELrDJB~!x>N(؃hb&J_ohy*uIS[ޕ~@H}Sϰ'cJe6׀gP xͅ\22k:z)5)VvK.q b&rRݺ X 1 6f6ڍʏ?Av)yϏo#֏g=0eU3yN('E`kf.]-賝I(̺>vywfHlL!K/k.]8SxUU,^ t`@?œļ(66f[POL ԅ: o*JSO>aεsNf&\S-YnrxLU$fS<.&h9YFʵn h/Lըu 4JeeHBv6]BeBoBϸ;,# (۰2G(ÎI[&LM)]XjVo-5j݀95mH=naڔ@Zl**=5@*X۹| yP@;L]=K.ڙud J EӧzTu[ڊi}7J|^g5=;03J.9;]ʻs#0K* E&69R*7ѭ4-~(i1mP>]IEj*mq ncRBIFJ@xhzēSJ^uP'8[l6\*^́|2tGhTt~bnY>RlFX.9GD8Ia|*~TvD\|2)< ߕfYn&>dC!55NmVZ$sasV4".fU\*CX].4ZRLc/ܕSl6UƁm^R9eTIS'4]?T[QU`UON&,"T VFڴJRmhkim:R&eAui?=C.P66,N,?*ץ)q-Ԕzrfih.X[y1WSc!g/˕~$shnaQ0}`a1Vяh6. r$€W"` B@=`X\(zqms{t{s0];oy{lq($ Y#qzDrqG;-q C)A* 4@NkްI YQ+'hqIБDXibJH D,B|˰e.UFN&0 N% b9R<`cbt돬xV BR/I6?:1 89G-=D X+)Z6HJV@ EmE,[RE}SGJR<4haچf* Uc7ѻW8\0qUBa:b^$jzUNCI>Q;,E~ؼdR} uC5+:ɹ٧uñ)IQQFroVeP۶ ts]DNfRJsǭǧ&LLٖ#SzwӦukըnh.ǘr9nќuNZTqejN \ɏT:%bEdx!A]@莚T?ڂJMz8/5epW8›jĦ mihNԝi&j?yw 5IΔ:JB7 yiH¢06PN-~/.R[:GQ%-%&*m=Қ&i$e⒠$Ydf|Kj9[JyIP qZ]rfvZI@;;c1NU}'~H=z&d as U]BTRwxaV݃?2 P_+UUɷ1+:ͪkTŶo6y ?\`cFiTP%g(ꗛJl \~.EuH)4CajE=-oYbzD6.)"hu9MDRS coES.<~V&Ch~0uMxnlPYIT@/X_낤%W#5::V~zo)%*jl!5>'QPz7U*LieH_gS $*p:A"6EKrMikq+Vs|dFMja.UlӸBeNRv1kgc23Y6{Ÿg_%ϭ0zf.A 9m=EӳhMh /V$upB8>Ht.Up9BԺ)FސE}u-gsZJ-qw֝VGtf*M9$m$^Ӫ2n&<<:!K+w궋z:U zv_S+U]e܄RF T 4Ql8?B|'䈏VMFjX."_%re}C`(M'ǯ&a \u+;Ѻ[\6tPTHNThH>M.w<\n>&&eSDm݋_?ITKa@XQ.Q"z03/H[hHB;hoںVhN>;t .F-o˥ &Ghg+P;tϴgFyq~%I]c~O !(tF&ēsC֍MJ'UVD}Yogx {^ k$J̖XJՍ (Px!sj}JjnMm_.$_,ԝO̢eFh4KA@lF%4vҗrpm@9L [JHBޅ&1xta+::u%GmmoxW4 n^#sahCLϦ}|A>Ąѓ3fUġaA ]~yH5͟i-_@70`6ۛF/ڵRd+2ia*Jrl;F_? f%jJM~֊OMTB洣 '1|CC`Ai2ޥnufFqZ?^VU2. }mT A7_zZml70ҥFśqؒORڌ_2R9BSoC/O0Y1d!q_r=bMφN"MF}~;߼LzV7kdV}A*fnJKhy7ȵRZj/P/pz!ɼ2'n6T$Je )Jnh|_Ƣ_FI#OJ)$RJ[Kdr-g:WqdӦX<䈍飻B`+jAnWQ '7L>MZ\r{ ZUqӨ{5'O-MH #<y, 7d] :ꔑCp?Qy(+  ~m8zYe* iw $F;/kVSҮKW܃HIOf״OU4캛 \PiD_ PBcdKnP?"JTbV[KLReUmСe NRN.> į 8B9s:c\I P*ǚʿxyTг  M~ =fQ*b 0Cu%tkŬ6U1wVʸ63Q!9[m(yԜSPxB6%B8bv"P'vܝZAdkp1QEyi)rF~+MyKoZ I͍&R-9.>G@Q'cG\*B~oEvQj]'&OtD)[K.{hCU4Ǒ%i( II;!h\\b>j熢R,/"f Hs_^ilgXRR{sRAIoi B 5*jMU]fnpXgCtI rckLjb@CmV@cxj>fa7LN׼CT4x;q 2qj섡C ͬc:m.s]hQ)7"#ݤ( 6"{<@1buS,A76 *EBwnu>/]!diߵ.Ҫ|XͱhRm k"/U!;IQtTے;6K [VI78M.YJ^ҹ)&'ß&S]}A7\$}EOxnP[y@8wMeC*ORY$7Şs25_7J) wR.*OnR[& T<,F3}HtMht)CkHZӲdNG!!%+E Rb֤zYZRp=.We&T& XCOkZ ҋ[A)rڝӽ'; 1igJw8] ҺqqÁ R3I/qMhM7 oHZ=gϟ ;>xsҍ/X ^;/X ^;/X ^;/X ^;/X>io{Gx#^;ߔio{Do'nq^]avMFbfI[%iKn _LN)> EVRlg)ʲ?7KUS;8BKVC8@ 6v pWAu!@ۈTctV HQ%>t":Æ2juVe76ES,<-xQ*e'X2m)h_r*;V RLNHR\!達3UuLȵXzX )BX㸏?MNiTLvH>~ޣTʭ*ګu?vk/S*g*oRrF~\҆9/Ijʩ+zs&gKkX }Edw*M>e規P̴{n9º*ƁQl,떒sPo7.dpg]X^*TĕX+r.{|zSG LwQ1&e?FM&]AEW޷.)T 7'2dt.$Y1+*)-2FBṀ"aFG3RJY\P3O~s#hI8#2,s7`8p?=KCJRV@eb`m! @[>imIue$SpG&Tv>HYW:tl MI[79~aکӍM &CJٙ%VUPyVf"&Ջ^-gt6EK2A\I%(A<{B *AKij6R-*Zor/-,7W1Ft5t ʚ'[imU _6>7&mT7ZнJt̮b^Ifʼ2,; 0ضSq=KL+ĖuH'}­wr KRZE.l8[FPd*RtJoHsjKh6;ԈkҲ&s S[-RB*JG(RO6Z?ߴSF}O6T6] )Iaj1x2ÌIڤŶ}A0t)}#tÉS?͞GAյEFN>\qO~"-;šøz} 9%ٖszKrsbOĎS+$l<,A#lvưMN"uIJ@SWb?HA熶v4Ҍ݄blu23ؚGUқLZqvihy6YIk3) @%)%\F-ЙJ栞n_t5#OoÔޒe9!\5 z|J!$"Ǽkd6i6v3!\d&/ *:`2ˈrtT6SՌk42ԾʐoA,ɰ_PqБcd cYPpZǸ)2q{mBx8H@>:ʰn:eLfýh;4S~ɶ !&p!D>IFGwH=" 1~&@ *p|Ps M }H1v1ֹ?3zB+Ц:;3`c7[@n`mcqo5779"RX2ExXq`d 󅒠 [ s.$Ax;bU1@b/\B((^8k׈Q@v0"ۛs Ko`@0iXHƚdB+2yn={e98E-V> KS" NA^ ^U7$]w?ʌj%ĻY3B.lo ԓ&;W\ek܋[6F.n “ޟҽPD(S{E`"OfdH;onUn1Ðq &q͊Y؍*]VBEAQ{"Nս<ئhr{ͷxr681btd LI!w?rlcH,VJ(yq%])$˶\J\QaUuSeW*r P7)C+ܣ H왹U8 #)}2BnCRȲ1`%+_?ȾXlP$XGJd׉P@ӈx*xHbH'؋oERNC/8Ӆ~/H}jhʱ&U X,4OH^WǝWy)#9;EnZJt>CF+KJ 0?_HJ%uT'$%< }~/NՍ𠫅b( L66 C#uktJ`.Qx5$)hK5-hv?,KVn)%#ʔ3V*RZ sDҕDUM)e$-\-%&X]1KRc͟I:jj p#ؐq ۇ3`$X##-ZQVR.}!GXRHjhV6$v~1} T1I352<)E-F!䣅?b8;FIԉLK8BB$%%4vYJe^}-Pޕ| w8T;?ʀh87|܍(˦7BpGRSD<% 3'a_*c.*9kqMe mzuN sb1GL:EOLɼ6T)SA-W$IMWKs?f'4,2I+&?()OC>@L)ꘔujV .{X)Pe\ QRPvy/r#CABmH )T<7dS@땗$eTRPJ#;z%[M3kAK@ce1[ey6FֿNLbHZ2&'߬x3Ӎ} z[>> MC ';>XC ';>?ƚ71>Ow}M1>Ow}M06WxDl} =9.gZf1iT/{7ü#H(;qiԢRIMӺ0ѩۥɒTObqSO`V[d^@y8&g#m%n|C&NM/LRU}hu*-ɼEv]==@ OjaPH77f\*aV+"xSttIP7 OܪfLp[xUi8ډyI#$\}"A)M͇N#Fz`32TN,->.d?CtOe/LMXN8D N_fNN8ѹJJPFEmqE- uK0vIOeÓ.! m@iIFҌд[d N9#B8v_rM1!QQX6Lʔv oedz SO l@1 F66|P>'T8PĄ(?%G`=@Q7 Zw}ϴ)q`[G$9#DKdb RR cn4$I+RP6YX ][JVShem'86yp :KaM`#sc{DoJr,M#0g8wF4A(* Hn1ţcM%zRQVl-M5L$ݲ,@Fӽc&ƛfVM*P;Cx\=bBJUgRR -(#$QCK*qe 7r,>?^1B͂а%7y"~R0V6qhԺY&$hDҶ!!p6\"nL4S)Cю 4WŞԷLSIPn1=RS$x9Mِ)adP!+Ulb Î+qoKCrAbTq0s!GQM90M4=D|XG %'4ACqo*N#hhзԈ/htpPŲAipFGHs?XS捋w?H|ñ.IsF;bI Ȏ ܧ4H&h:A"vt2U7.hDC*Bے~7eqom=!e QL 01HZ'>,79[`q M- pqbh@8'Ym;ZX`%Mm[i$ro`\G)!x6)*L|;DLXh4p(_`=s4n&fy v GZu)H籍 +7ZZh!8?A/|1ʮ78ŽBl`aN6FHH$uy뮞|f|N"zdt6L\[I)O^,UԨ2 {Xĵ 0›qNT-:i٤R|$x=CQP*<3,WUKPIq [1GuI$*Fl"ozza:aM%A< 61O~EpEu % *7R H'ɺQ߶aIÈ{0;YmUǤ:b%jxՖ+o:dfWkMY}3:*(}S 1O0)M4.CZVEno sMp@c,=WUi~umr#ͳv{^.R7:>NOSP+OMXX8Xi\Tۅ*RH(Z(VM% z`~ w_f2ݜt7R*]m0%eu ncd}9M)+<5 D!Oc)?X<|wŕol'+!(6iڒ/ }s:.C҈.4kZR>Iu+c!iJ;hNn/ WAO^#n_$"秦j@);OQyJ!IybeĎ+[~RRɹRx:̔pH'Q Yexd(i KW gV.+{}cZ6AI&)?/\:ZRPYTqz&Z.CQ1lO؏0%q!Prf?V}oJoV2wcǜQR@)>U-oIA R_X H&pI@~n)Kl,챲T xbVt}@xS/ਁ~ޱ'| (xƴѳCę *QqC@H發Km(֙yM:k ԙPlmc>CYĉJ1BiDPuvXwb6dRAE}f#5jS>Uxbau^ZPAw>E.AGx6Av3RJp#'JӨR'X,|zDyA3s~=U}>yĝaǷDW&|`\UUfWEuMJ6V͈6'SwZ2yn$y .$ny BK P_/`! =M L:.YܮD2Lץfd_ߔUGU)!&PI!噤ݷ9~ A&FC%ݠPaՠpFm56԰U^ `$؛-@2j!Z#ڎ) t&xuIee7#.NcxYV"w3]PW YI)xu-'PTw=+IewseZ3r-JG<ې&^Z p^:H/ wv$_C'%n ސRPV0c6 `|M%kM9}qɇ-uvA@ڻbXc)s[ӦNlaΧx嘽< ~ |MR殠Š-Kl1CI3s)i R|"L6wRީ Eu}1F*\AJ3aznN1+i$HŸ[pWzYcqWٹĔL2o=D{tH]E|RRT1]Fe+w),TSFOfa2%9dR֬ ':"V}iϯh程ws4辨ݺXEl>>JT*G'icЧ:FMãPd]pg(tf>ܬ5.xM͔q1 _ΔԷTk'纊Qdk?E[dJFX/R̬I@76$]Ad9F\tmOr^ev1k9N@81*MitI$]楞_`-$m15/ܸv`pM` :9p~ZdHHV\I< y,L$ͶeE?Z Pr^gn=AnS-.  ZKvȧWJzٱa)V<#Z2j%ĺEb2=0ƠQ 2ש ɐʏcTUߑt }@>)Y'Jr]!{'E`T]_ZA^:Ud1,Z⊁VAkуzVVU{^1)A*MxH>]N6s{=! .Y.ةcUN@[gd(p ''\BF*RE,MEM$x"UvНx)^oߋF Rva. `[Bg*J&#/~"`->ᣕIQ9s{D%u VgԙT oAwUaŬ gJ9uk0A** fQMv`x@"fn֧eB qBfKRI. E!HI0"2;(ְHW& !!,&QRU1i߇.($ԂS(Qn@ 4W|qR8"kFQ׃FiL܅{J5AJMuDerz`0w_baBhup+$Yv"S`XAh&/@UүJ^'8PWB /=0u_*m2iqm}6P>kZ.>ZGHk7JN8 QE6=%GUnoq%*zQrMTJc9i}x' vcŞC> CD n|0@0!=0m%Dӡ-$ܕ\ 婆Tl, lsgU=\-()_X/{_<,H6шw\_  ,h_a]oi>?w m;gi>PE&ټa i%x ex x@_F!{ Âݹ`1x^;0cChG}c=cMOw}}mh}8pG1-ƚ!x l1' amm4 =UҳH@SsҢHa Gfm#*+(OB70n֊M)I# _;P c!b({L ;dnBH .dA`"ذr`YG60ffI$r95C8bHj}7h&*U{x)Uo$P6 ` -m*f452䴰yFnxFcZ~{FK:iَT -%7oq t]uRusKjC}sx}x"if%YuKHPxo|F[IsZA1KKNh) qtA<\  O0Nv Z$5>ILL0X;lM3qj6(X%>!>zFv JTVmj6P "\Nje;g~iԁd()n\JǨ0É2],V%">FIL¯{s *N3/&\|L^ $YuC t+^ssl(.|z­ʨny*]ӻa 6K\07p<m;RNT?eENjmGJJLU$٨(}u.RTJp1+t0A Cr$F<G誜zMOKZ(zSU4ZyӸhߪ**=EӺk\Da"E=u!00O 4O]8zVqe0xԟ5U)YCPU8)>jEJH yJG2#%z0 Yr8=LʝP sޱTLm+)gqljR}fֺYq6ZwVDL*ܣn>צ!k#1>Ϋe34U[Ox #`xjbՙ>f* 23p:u-VO.UrxȈf&(Dh~XD€v&֚*jr6JWúY* Q)Y* ?cҽT,0o2Ǯ`%54% JA ~X.E+zp-qmx4me-VSf05*3ՙA,նwPTJ&aɗ9L{( eglMJ^uJR%7̩ +3g( ik0nU7697:N@~Pg8ejۼ ߘg\Mɸv$5ӆˍ)K( 6,N@)+& GL_~;k, $]Fl<7iy]3$Qe՛r\bFa!q d_;*_Y]T !^~`ג^m9;Oq5'ęMP3>#آjV2T(,5Y*.8? )QWIJBIk"ҴᗒSͥ O$_n|l$ۚemM-rVlnaǼhdgBV0iʫedP 7kh&*vjabYԟ-ͷQP~dh=&] (9,5UeRy<}[5V,F- Q4mc(Ea#IJM:B,|,t>Q*K2K =cгtYoM%_„8Eڋ<'MK􉔭Hvd|Da:.Ddur̉ZlkyF'bQfMym; {21Fu;W^ ُa4 }OTã<9-BE#ΓkcOT>mM%e VI#_t,M-k,`ȜMq.j-D*Tfԓ) Gh2gfw<1Ĭ2m";7G>򽛏[ Q||q(W\)] X!9 ;yKZkr8jdL9h_AyU]]d,)A7Kjq(:WUd!R+mi6@9~$Mĕ#])5AϘ@?Gā]鈊_B+U+oVlN`֯'=t^9,\VϙUi@JĺE NqjWt)\mp2mL6]MjWb5*M4I$o%s@;UΩ(`?SuJyC]^`sD4~䤘` $S8~0eU{vbU> 0 !:SaIo yh* 9LGͼ˥nʳ~onf/D`\J!7w0L[TPPCi%r1jlm kch,E&쬨4L:U8F7Jd>fUΤKQM d&'I7;a0cShcC l;`1>;a0`|0=cM-%)&,q l;`1>;a0cShc_aml4 ,vv0`vD6Cޗj˕-ōF/P/up9,(Wkp94I JuAVG6ǬE}$4gH=xgܔZ#Β;F52˵6aC>p{9M{h#]&;a0l$~^ zvC[`14Ga1SzDvCʍa]Ii}2 lxF0! ߰Ԕ\[HOk۵MZCaa~ASzD<1;a}l4m>=LvcM} vaml4qx=Li!' )1zDBH8=L-ɍ4Ca1'1(n8A UZN^PN)Kqfܧ g09FN"GTqv1lĊ&eVܹGS%GI"0, * 3!~  ,HÍMŴI)&#,fRU]t+ (cy*V 2{~P`֤VHU2#, ]}}!E7"A6778(Xm@ =x,X@  Rn;X,-ld(m- Z`tFԠ{ XRM|Cj[H 2M6+oq8E ֛C/EC᧋!꺦GHRݞQI"d{kSz̬L)aEon^!|A7=z7UiN`^ÞA5䪖2BIBނ!VGRʾP|m GkVv\]YECeec6L[K$\s&K-^MZ'`0&n>J  -zƚ%6C l;`1>;a0=6ShA? Rn lO#M5߆UPHmOLN/ͯkwFPGNW/.ĵEӾL7+vF@^ߤyeJKhpp`J⒕ݢcS0,^7% !GzI3eU#ks5(g3a9 [۴Z):%Gt&NV HL"}@<s$*][t%)?{AhO5Hu-Akr '/$lv}R60 );kT(^1loQ$͔/)BHK+C'*m 7GVMf 7G9B,mo̺B1kﴪ<$ionIJ><4a`yuClYj"fb}(m&"$Ok^>iT#E}ɛ2!:JHV)KE /S6XIQiPh?Bq..j8Sȕjo\Ȱ; )[.Q IS*&D|K+. ~Q_Y1 'P52|i`TbJʬiȸǂW6QOh=2*i,||4&b92j4_s.DUsȖuME-J7?Tej*ۿoSeY|TszDbdQNKۉH7*zi&aҔ G 9,ϋ="LIy`qhpq>y?! gtsUR*?C67'Knnنʬ6nU ][ڧToxɚ'(N)$|eVi*WhzQt忤T%&WT-D`b, m2Vd-.bR 謷-d$YxhBDG;pG#͘1WfvIH"&*Bϼ a$@&&A;'*[H67I(# ؛szDx=LvcM}}a]8{ƚ%]ր=Li{=6x[`>4Ga}]l4-;avSF#l>`v'ƚ%8 M% +zƚ%l>cSh»=Li{ qH )zƚ'avSzDx=LvcMcxS`0;4KaxS`14Lm=LvcM MuRHu)&-J P#6@G^'e+J?arL%=d9Ȉ'.8X,*d껓L66?څ$ UD@V,TCfCWXpl/Zݭ+.4,Tx7[|ݰ鲱kydKJ]B4෡6JKQ#jc0F HL.IL88DQSq$qsjaKP1asA0ڷ$zX:ËI1xeu<+ܷ~o_˴4Gq=IηO.kI0rah8^b݁ECچ^1D\P]iu:*U2Rc 33,$TA'RI7vSEŠйvx=Lv`c?xW`04Of9Ml4? =LwSh}`6Sh lb}Liha7 μ N6~aPSP.2^ak l&[1.}ؚՉE ;3ӯj$,D6b6Lj wy]^6ܔTír{ H{]T U%$Xa9]CMozp̠llrzDԓ0^Ǵ=yJP GL0̺d_ HX5Gb>T\)<^uKI6DH>&#')o˛@KXcƟM.m Z^#M:?v>aSu%Ja6lx Z9 I>oI/}*UZoNQnYśwm!FE=Ku"=&'hUIP_ Y4zAbI,NۀƜg|A a*$e BynRU^ 4H?H=A`ɝ)#'06]s 6ȥqn%ŽPc48: ;?vy.Y²+qFZs(xPlx&8C) O,4ʬM(X;Rx#)2-%iM))Iܑui>itnRȰƞu@IH!FbԚ(u/EY:|M4,mMU#iMK Sb&/EJ&ak6ߜ--5%!N}{!]RNqh(|1esa&R-3:)rɺa:+h_3o͓b6T]EIR͐n&.}sP)HL+-П?C[I'MH15;7kpeJVږ]7"+MR&MV/Ok+%;{MްMz7[ !%u6V]GfOGZvgjy FtSz1a7 ?{k cuC5e?gE* ?RS-L).7U~WCTYoL1ӵpbVʕ#`өWh{Q?h4RAJ*Kt*_IQ[ki#nBSԂJUzT3%9xw+էGs7Yh ;涝lM"E:Yn:6 <-:{XP&&m樚iomi)#5-iJ!Fa@bDT7/Sy"_Fs5TChUϘB4!l;hHqt6=rB1GVKz2{Ն]z.^i㌈16aҠV*~+Z pXo> ՓBaT^+W-\q Fọf60W]Tӵj'B:_Ir(^o7b\Ѭjo#WRUn"+d x^eeLߋf{Ayv[8B;fzf5<(3r7CV 3@ [f1hv\&]8/l/OS3I2{&bqj>\Ve@RF03R4ISĊuH niY'13Y."QMLʷ;f~'W5g Hec1QQubۀ\ok^)ڴ܀mW|tE)O/ꈷ0ܘTMj" qbOXd}tNK>ܠ-SJ BslYdֱ`MxQzŠI<4ccs\t56.ox4Vg 5ŢL}/70ÛK pr".!oSΤ|IJqB!VԨzCeӥw.~a̳*. EI4URɾsv"+J~1U.q|Z7ê%EVKHŁͨmfC'uUոLD--ݷxb!w8'3$_C]eeM:mJ|5Qp uܲJmQ Шz&͌ &T(\Q^M܈PV|6Xx%ʹad*xn8A}0mQϤ)3${f®}LכU7+.,UL 2XN͛ys{SpoxTJ]$ͧm[#s1S)Y!Y)6sb|C7&M؆HQq[q7"xaT؟MدH6$WE~qWqB)E~p;8Dִ{JHb}Mƚ&Bh{BŴm&?i{^=OSƚ'^ xc?4Ob KjSƒhEϴi}+s;i{^4Ob#+ǩc1cMدH6'lOQWvzB{+?4Ob#+ǩ`6M ^ l;4Ob#+ǩc1XD+;b!M(Ti{^>4-دHWO؟M)QV;Mn@ɹxc_4}&KL%(I0qdhRPI`lO‑=WyKicpQ }UV,CD$Tol"(;6I$70 -Jrjʙv\~ʛii) R1M&^'ZqWQ_b*ܣH(ܠ'*@?|E$`g41=دHSq4=دH>vi6+;b!MTvhzGlW)SxcWvzB?v*4=دHSbOe~qWhzGlW)_v*4Ѐ,p 6ǩc1h^I:ۉ ,&#=@@= jex<>ԵYU>e2a*H#VV;.Bp4PQMFdҌ<\䐙vbARͤ,]Aj=?UMyq$[P&$B(``!7ޡh]øzb4}!Q8EuIѴ>Fl&UoB#S3-eJS }as Nx5uQf`yd8ǩo6>a+In=aPQV& Oh\06N=a뫔xX.d*`6"ԱgnqOh-X 8mj;\rPM Z /rU3myR qWt-QwS0ź 'IRTIJϧ}=o>l2v\m6Ck7g'Zl{LOɥ[ڽom ɉ: Jm ۈ0+6-*(>W  2~` $õR EKS\.TX޳%_S+uEF^ޡ"/6@) JZ0B 2k6+LJʲ8Mb_01`c%S!QthnMm4d""cT @[C[Z6ⶭqm90j(su CÍd" 8nH#N#Ď-Osyğs^($:-吏?/9(:ohPoVTWgm7;gRI̍a&bC̕s *Oٲ96x/msR(CKbbRB p3q=2a"Q-nq{>w~Y VHVI0RT&'&+0Rf@$D>3# T(qB M#.a1j+Ex)*9%$%QnB%ۗr0OÛHoX\ꊔ)@rxT5GuVɰQˤ >9O-Rl$^=!nukم z㘥.¥$@ew~h&8@y$*J^J>#M|Wĝ7:=/&l̂eyI{}✷ 𠯧sJSK%I 9n_ $mpAXBKԦ3))^1#7\@ԛJ"(zţ4tj'LlF uݽhdk_.ʋ(wMekN A:1H.B悒GcEԂn)mUXޗcX(Aگm%uLZ;(|vHe6\nqIr!&HRў 4X~.jTe\) 6~irnۭ0&k G~)_JO'Eę5M0Um D-2fvT3u}hY onN80tje{CMOocჱ;e1L K*d cĺAW tid _ G4*;'oscM8ޘRBq/NR::4ӠJP+;A$&tiE&Ў #M::::4Ӿmgak iѦEM::::4ӣM:KR0ѦsAQU7hE wA %DaXf d x`#C::::4ӣM:tic+F)tX4tq$cM:;Aި95C=Yp/ho+Whoh;Ix1ǡ45 SzGxѦcc}L{F o4l# 7CzASzƚ 0ǡ= iSzƚ 0ǡ= iSzƚ 0ǡ= io;x1c_uߤcCh6?c`7C4l}Lu=OhA1>= iTuߤcCh6=c`7CzA1>x1ǡ4Sc_cCh6?c`7CzA1>;z}c4Ӭ}Lu= vcM co;x1cc}LcCh6>:o;x1cc 7CzAhS>ǡ4S[q;x1e7e7zƚ ߤu= vcMX#OhA1>=MX o4l}Lu= vcMX o4l}Lue~ǡ= i_GY_@o;x1c>x1ǡ4Sc`7CzA00]o4;x1cc}LvoLiXSzƚ x1ǡ4ꎱ0'wh6>)C'vh}ޯX&cC ^Mx >zoW=M^qzCWvz7CzCWvz7CzCWvz7CzCWvz7C{Fzc {GxѦޯXx= i;z`ǡ= i;z`ǡޘCoWvz7CzCWvz7CzCI1?`ǡ= iʀ= vcMo:o;x1cc}LcCh6>:o;x1cc}LcCh6>:o;4Sc`x1ǡ4Sc`7CzA1>x1ǡ4Sc`7CzA1>x1ǡ4Scǡ= i_GX o4l}Lu= i>:oOvƚu( ^ >h'q7@W0ǡ4>zoWx1ǡ4>zoWx1ǡ4>zF zƚc-x.cCh}ʽGoWx1ǡ4>zoWx1ǡ4>zoWx1ǡ4>zoWx1ǡ4>zoWx1ǡpI=ǡ= h`pox.cCh'q7c`7CzA1>x1ǡ4eGX4cCh6>:o;x1cc}LcCh6>:o;x1cc}L`B64БМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМti FG\z$ti=D $7w iМht&/hw[iИxE#8E#8E#8E#8E#8E#8E#8E#-4Rr`7X$tiO䃜Ѧ&G; h7{qѦGBqѦGBqѦGBqѦGBqѦGBqѦGBqѦGBqѦGBqѦGBqѦ@\z$ti=DuǨGF)px1МtiМtiМtiМtiМtiМtiМtiti=DuǨGF)px1МtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМtiМti>ti7;z`#Mzcp46zoWG\zA1>r}`n1s`w(wzQhmޯX XXAޯX4ޯX XXAޯX<AޯXzQhmGoTFzoWtiWvz\z\zCoWvzn=D ƚzoWtiWvzGFznWti\Si>r`#Mzc:iWvzGFzoWtiWvzGFzoWtiWvzAch;^[(AޯX?HFzoWtiWvzGFzoW>;?8CoWvzf;1^_>46zoTtiWvzGFzoWtiWvzG}MzcoshmޯXHAޯX``@mshk+H/ s{zM#A7w%C@n=@ߴ&¿H 7st*8ؘM1 *_qB'eq08MTo~P͹ B\>UmUlFaVq|ZxHL(\'q1I0 `JMu kK y4 ']0E8ƚp*<u*_p}` qiە^Ϡ یFەTɁ*UܯX#cG 'iĸ;@nW7H8U[(4Fu{^$rR#M Gmp#?(YiY|no5#Um4V`v VÃiplOرʠZQ۔4¯RaTl/ci{^Mhi(w*X@nl`mh91rٍ4ޯXviGti\SԳdD½Wh/Foe>Ge )fkk<'P/T_Ć-K)wWl9!_l %\8"X#0Jjlk"St{3(ۤ g׀,/hAu]J78U?$)WPՒ  taƛP܆Dߜ*R}#L~ʠ'Kopƭˤ w'ӂq[C5ABw x]a+V}I#"')BrY2SoMhj_`ƯQKfByfx赯 O?'g贶Ʊv5¤-@ޗI$uS\<< 7d2zwն57KV$/ R\ (xSIC0.78ި*"n+\2X8?QHE¬h|vКj nIDa?&4Uqɏ}pMѨYmW?}nX.$7YE֯q%L#+2Q%!~6ZF8g[r?Q|5u١>VnE-VP'U%PlZؑc?8'|VhspxhⰂE-cL_PWPw$˼ 'I-?Rۋc 7 A%Ei)i&6u2P\LMq_ʏA~t,)JFqa'[m``/C W^$KEughxlB8И{˞s#^|GUߥe#['6R's'> Sj鞸YR?0Pe K1R. HIs4v'pߍ 鹭 Lsy9@*\B]I<^tR6vT -7?k_)-yzRqDz:n`jROԈGꠡiWnV.8J~ݑҹʭ T&!)Ty?UP i-S%sOs $]) L YPwL k'u>ږc؉!ͪ7YH*za`=7FctT|Z|Ŏ`](goHK-e m$¢əcrLA.Wo]oMcP_H!!Mww 'G}a *S5*I*ǽ"w'Ι`';@O6T6,MXezu:jNm sIEu #vT$ XX X?S&NΉ):&) (Ug,mV,T4Ƅ̽MOUi-8l ['U4Of\N|( I9n4:B)UkAHJ Ӈll1ʤS")tish]''5%44<ڼ|[8^-ǢQnR%7l_W-BAIKWc6V[H-C(zJ%}ʖ]>}z1B]ڒ@3Y2 rolhڢb43Lm[x4iwɩ2deZ|ܢ'?Nos1kJp X? ȼJvN?8giZZQx -, Ű/1שv>NѨ*,S|N /]_l9t]S(@9_{} 9M],ճEoNiIeO T R*P#(Чw5/e&fu6߃QTA˝CRU'[@[G? t)R\#Ȅ6MqF:BvU ϞB9HU|zz@iz&Ӂ2Vq3?Ĥ_}}`_)snYFLb]H͆4 i)&Rɤ8G^Si=, oI@(HgRY, NN2&Skjq}Z~]`Z,I?gzLVii;L"eM,-d*>qteU r@^J;= f:Q/e_Iq,.R-"zIE0EjJӺI%t/8~ }NgjiHS6MɎ*$\֑3 ?J\Ү"h. G(u ژiLڼ]^Jmo:{CQ\a3sl>OBD- AhtxSy,M"ađ.{p"$_MtD366/%g n7-<&'m;cIғ #d~C{ٱ6jLj]۲l8l V%0z#P0ީߒn=r!_H̢jwܥ&0Zqn(o`楏K cU#2&pM7qϤD'G~Ӗt]Z\|BZ<ß'Vq3֥t@/`TG' [m~qtzPI~XGO8URuf*nQa2)&Z7s&5PDH(ޕmR@8?,!JPFsޱv"MCVqjQKO +-,#Z Z]JPH=r_1x,4ԋdqw)LIj$\fT:Mͮq 4dή3$H7"9RP4> #rYQ(ɾͪl%~hΊ/\~eIEH `;oI5(Ӫ6e\9-T亦.JogI꒿V2ˁ$+]m6+amˇ&YZU!C]ljEL =(>dqirMp21'tanmJypD7 3VYK@ Ӵ U| R4B;A#&pN˪bn0]Щ& ?XN d"s 6 yb}VeE:l e=4ϭUҫ~ԗSki6 Ƙ H0 w3I1,ۖ[0,ȶ!jk&5Nt}59:{ )yyAHNzB2i10\mxa!)rNͿ8~^K{`=3CZL7O̍@ 2x,~] p&Ƒ$ K* z%VRX$_6LYPBkMޔZ#"6-$aA9qe[SS1:˟Rퟵ*]r&ezSektt/)oUX23.P<"V]YXjaƐH4ȸsqlXifoAxL.,;@K_2RM"ƳZMrt۰ATPGiii&l<E2/[_HF2֓I}J6JEDX(㛖'ԀcDPdq2jmU!JQu-> 'yf [S>Xi[[sKF:f:֋};JHͷ ѓ)f4j""Pg9o'hzuPvQ=Pf<u CvHX ^v-8ZIhU2Cky4w%@cvsR_U43*o 9pkx>cmuA̕$YuS̝%붺(}t"?!@T^{1qZc/9)0T4+$c6?GV&fPU(@;TqToo#54Ssp% b|ÄViQ2I_P; NӟѠuD\N*AlMCmRh.]*@]%IJHy )o`s7Jɖkү5$)״2Aj1Τj2ߖ- u654RiԣcLVFJjJ UDm{q}g*q(*kǞAQT:mys48/HnvruZA?J4FUKlZ\ZT;[oE|>i|FeG-bqQO> VɽRY?{m"7%eйfpiܥOA 'z9XamHJ|ԓ{~~n+aZ܃DO:qK_HFLj2& ip/J`lxi\Q]e*[ Z&~y&TjQQgAީwchÒlH&ϴh-hO!"y67Q7_Z6ܺ|2onAHg.~a 78{/im8huRsAssɆMum/L2N\"[r1~ް, x$hʛ%V^s3Nq?vbG֕L$U(@ٷhS4%ofM${ KBɝ[J6C) )PEl.Dnl BР <9NV-L!@4k3q? ,u ӓنTnHpTҍJ^߈F)YkSNE -nAfW-ܳ0  O {ftR{(\G/O67nÒDNN٩m1EGUt|ԫbVY΅["-J$#(.%@xL"(kc%YKz.[ Z}DSIm}+"s6j٘1cĈ2tDCg*iQ*#60F\wO[(S*3f^YS#x>e@׋lpJצUKx+D*MS.;"Hw|A:~p;%*Ϳ ]3H;6\ @E]'CO63 ic54:u$h)u 5ԖKɩK܌CcFu^VQnѨOt5)to8M+= 6V\1el-~  'Rng2Vvi;i(Q74:RKiJ&7 -7-M"ZnEJzT ߜ͡*, W(\PGkwHRP„_'iٹFRyŭ6k@=:vmr(]my#ԁ01"@ ܧmN-C! IYbcw@H'zG'.DNj`XQA+GRW=U7`JSmUPRy}QF]B2SF6v%?HYy䔰Jhi:Y=RեhJ|19P)im`m֥]گP|vao+QHϔ@@ lܨ =of)NV71(Oktk4}ŸJGWTU 5FZQ+8 G Ӎ8ZOVb^SL/e >!6G#:nyn.J0J*+RmEk7U@} &iM1St=>.eJVnk-p{ -6Vwn9ǭ? `{̑4{IVwEͺR|\+{qhbQz`/Zd$܀/洕Vaxn߈ X~(cUM`8p~Yv]uJVЖrIJW~vKyV$+Z7n^S$)8ө MmmFFsxZ٤6*URԪCKjzhۮ2%G[1-a)M>9dVM$P铪v+ij~76/.$cZcT,ehBڸ,"m%dm%=ńzEcd NfeR|&Dܿi?Xʑ(\ @T ļ2Fhb"=*WjKlvҕ*?SqϿUn|!M0gdO˔XJn*=-; c;$ӈo'=ҶYJj6%(w6C?@_F:"B@ ?P|5'A@%@}/~~Y;˛ U3ĽRƦP^.5Xgol4q($?" N!Ka /RҚ:I)rmmJ2)ĄWBT"(UӰ=-=bjCGⷽ,7w#Ӷ>!]+Vvsp9N?,+ 4k'$4e"a Vq.%@[oX 8?KDD)!spisae%Z]ɳ;r8CU̹[mOB*R-1E ˅ܵ'm")!;s|y(׿΀-4*Ӡ\{”ޑJԹI9NRBv̗]-)S)*r5)1%l =WjօZg7Bt4KAzm{( y kIpm{yG۩P%i[vJBEna.DҼ%Bñ`]BA?\BFJ;#"1Ve`Ԧ4*p^^oxsDt2MQi#6Z{ǯ3J>Բ+T796O,Z@Jk)EԖ{rq&mz'FPgOFX&Įl M:sRlGKtoJfNв~z\%IgT->J<]Vf]dU҅kL`Ε!1+Q0a�B;ğ6\mȥI22m]-SHpyo}'эRsJj263poO3&i>"ؓ/^Ge]L`1k:ŧ] jZ 4SZ ZH95J(&54/em-9"v;M[T`)IY&"㜟bҚW-o]S;F v&<6V3%~֘`֠(s~Gɨ?YOX:HP|ֿ>;C*[KZ F~Q׾ U`v 7S:0C=k.Hqkzf1Ǖ6XTesESER{QuK3i (ao-Ld> %Q2LͭCj-n-~#7q(UVӟ-H\yOr*IHf(>A#k& 7Eju0O Fq*$˼M[`KTɱF]*Wr݊K z-܈sQv$̕Xt;eԵ#79{w=H/uzDRhm|/: ):z|[G&TzÖ_Gʉ #%v緼se:7_O鄢Qao^(yr *EOo Ż5՝dQW3N3̦xn8j2h'{U aN!5*a:rVr]̏18$'4Ï)@QҥQ}N1]cEZ`xZ{Pk2 Mgdhm2 ZEe O|Sl$jNMi-I)n0J6 D5o=4ۋ[D` -g랞}J\ٖgYalTuC7M('Tmж5.!!4LKhrU` 9U^?=XukH!) QEsoZih: H-0nvs2siCr9ɺy0"x/o$KS fa]G|<ͶS[RQS:ebOۼ-N[jI΅6.G`Kv?[ů3rF>7jB4kM=e&&J0w\ ;ӾjE:n Ga.ldE%{MWPG1zyf(k(D6<+h^g*Z.Uj76A[k>RpV$pI_{B3}!Ryl{bͺ쾶R[6U H=W?FѥM"ݽG/ko-g[P(]FycqH|4˼ʖܴڅ{]GߨJ"7%ryEjJA' N|dMjz%:FjT۲#r]lT{S c<4gZ:ޒZn[Sn҅'2cÛZH ͏Ԩkj>Lֲ M?(\H;3=mӝ"SRMfZaJ.ǩ^׵α=T30ؑ0u&(e0K%<|_$,YEߤXY_Qt զf|yBc '+rȐv-"K;${9= ̽{Ǟ)(. y.dfٰHS4TOLO&IHCu־7t&\:jWV hʒXJ49|\XԱ.:Zp)^ø$0;ho'pR|Iv ;TnY^&%C ) ss2–C^4=ݛ*F3&Աc{"X=!송 KL̪u q3^*ejRJăs_9ޛcGVRW -a-bbWgR"jr&2U}&TGr"Zŀ+e %׬ADVvM/qjOViV2ҖoZO[ni)7yAAW%Z~q@œmFU&&+ߤlīS5)*)r&Q el@%${KR*ͣFǟlxٷd:DFRQoj-MAjFSS=/rO0ҭu4;&Hu73+z/@AJȫTy]0KOꖟb-!ċ$UrC"UbΣI̦eUݿ4 pwoX^h3LmX)N}AL;Z$M.E1lB)LHlI7RS[ZeS O%>TkJXpId`IJAhizV6/:m܁+UQ$DKcbuDݲ%^p,|V۟!N0=qlpOIӜJZ4K*sJMRKON R F! k*6Wԟ\%PB,;*]LO;}+\Z޷3ڡ )CJ^E zyH y;岀i8l+=H.hnJZ{o5_ 54*Qm6V94㱺1kDc]uO AnKxlbZONzeU&m RvPϧiUf'o;.ٳE '(rmqDJWl(=Q :wSaN`#FRs)`1 ܫjmR.g JzNzIJ[6(P6&*O8:bod6 p6b1u[Q\8Lě<WBǯw CdeQڊeVT 13뒢H?So8Ҳ6sM/<)[@_U`MA)MYS薔鬣.ҒHXpψcd@{R(TSšEMl7?_LTzGrRJ)Qܵsc$c~N-~Ԛz&CI$$s%M<ܕru%JIMִ~[nE􌬊hf2rC4g%&wuˬP-@mn'JZIԺ&Mp] T17QޤK9''%%#ǧ-6Rx=O^SuBR~QRIɰ$w!dI5j(U V:Ny鯓N'r%Yeo/oo\Cƺi_۞tL-%n/6Y -Б~*JiUj;8f@ qM;CES?6X-;*Ϙt\Tݛox8ܟODqa^$g%Q)ièRR劀6[ҝ3Zne!@B%'ze/I"I/V̲TVGlsezͦ\tkR&Z亨+ A`or6e@8?@.x )E&4((e"M87,j3ΗJj2K8Y'1Nuf:Sʦ+P'o*B=\s+!FY!F2}"C>5DT.eO-SuUβÛʖ\{x~FE=%'*:yRRZӽe[:/m%V~IyU5ty)yelP,d،O^iIP3+d)  C#rlrx=kZks?9@eՄ&V]2sc*zN!ȖؓR!Ӕ+todO86 u-~{WRLQ^u5?pb1P2.=/HLPBe܁qxlLB}L;|Sc)}@JHwG-<RPxBGAقݳQq*)'FI'LR))$*ۥl7i> TV{*(2e؋QQrc I =,ٺN{]l;0-w76C}EU1I2A$n_8$XD|Q+Z3uObEү ,)M AV+/$rgB)6>|=NDvFR' 8 '2Kﺠ$咤0݊!zLU[> eR78lR I BVz:E&BWO2 >TڐTA NYƺe4ۯL V~zlN+ )7~qcEf9$/b[&R}AЕdSnr-~/kԚjԵ7,TڤX+$81z/ ?VĤ1;R):k\ m \`_1Rne/XR\D[$\M6k=#xJ[RKr`( țU1Fa0Am: E Vezˠe.@iE釪\~q [m3Cn\J=P1y }%N6K;O;N$Q84d[' zQN }'S\|VU~BJx=!:vQ\>Eš' "%ӾTKhuMlZ|n؎>!QGDQEk}a=kWf^GM˗M_ CceҚ)57OB ^إ.qnaK4DχMBfq{nN}bu#OJ"^JBŊq{ ̓ bM>65 ćgCm9W *ymfX 80£ֽ[Zyn'JFЧVWGb3Hm+L!W}!狇-FJy)M2R yplF>4o *1J+`۲:uRa*K`+ 5[fi1RnUO6(7RqȽ&MT撒m Rvp~״K*)-3 H?噛oR&:W7y^CA,U58KǶY7?O#.l+MJ(@mI8$m['ޖ&ej 8wjf7!)&4uky l~=؆;)4GrFk0>ߌB% o)uRι+%6Գ/+~-W>bT>E]C*extX#oVKs^I.YwlGI&|(,]f}71ZiFPQ ŮXUiL6y&!{IN}=r"_yJ(Źd7qZ!oD0Kx͂sabm+n5+T?WWʥ.((6P7\ {d䬔˂Ϲ0;0-:WWaKK ߡh-8/jALOl2Q> n+-EEsh֩;r(#Q*@gQ)'4.6Gf< M;/+u-f՜RnRn -3Zҝ8ľR{^ &/3CQx!lE Ĵ_j|a7Q4*Q+ZOxu*C@_>!R>nqҝHLA\ȸ{Iid*Ma،ߜD/,Z?Bș g-mP6D&20ڧQ%FeI> \nW|SMnjM?N;wK괤^!Mx+S~?I0-GTTjFY;Brr(*I3iUdUVs|yOŁz;@L);Q}*XhaE\ɶ=b/:! P!p:̀Oa}>26$ ^gLI/EDEUD[T.^m ;~=bmO~!DpU~)fy̭Z*Cޘ5*oİaiPz.W5JfS[6ՙ+:bHa[Sm̠XzqxBSFIϡY 9}u/[ b-ʢ?RShq @Q0.2R(Xզ*~m,Fؽ0ě }*ڲ:,+IǬ'.9ƥF2Z8_HI\W=_cU~@z<$9TB\;䍀J.Eze&P&܀/p1sh/|Fa) S =3>NK~Q5GY+TTɸo zv.-Ufʓ1O HϥhJLVnuS"Y (%0,-=Uj MLXy/>1S.or>&4b;+矚[{]J]Q 9F |2BHU )>?:ZM3Nb]O¢/l}Υ-ȌS6}[i4ghUCvOb}!-rndU9~eжh)=ֶ ܓqkbO,ʥ}Ы$kpZߔ#mk̶=d4FSt^:MK&8x"izcFJM/phA&kuL&E(l3pDDukWЫ@-qco"ڝ;P_Lܽ9pM;3`N/*]2rm+Q'W")Ժ""F[)_7MwnxRJUm/ShŗќczzN.؝b#*ٻ6 ۼT@;Z2BG)ۈF{BK~{ZSP+8m~@9bɦDzyʁK{ܩM͌WLEs(WhZ^N8zE%'JX60ohf'-,R ×HS{vHq\vb+(PB.yXԓFl)ՎU<5JJݜ՗۾"eä J{=_eZoky GkZlKN6.Yhw*?ocAX퐳UMrmƜvOɟ\ v0^QOx¦/ #uԂqK[Jzu6%)~!9:M%CC$$ehO8 c6EE4!BHƹmܡ@Hq)M,vQK^,@B*ڊ}EÓr5#6A\(Q(̶./B(H҄w??׻txDq!5$jm+mMTV.熏  &mMJ7-T #iD[p"w7P7I4/ʟmoX# -MK+!;68#1 D&R0XAMS 7{KtMk}ғu%I 6\bWMepKd~UɄŦ`Px?O!.I# ] *פZI vyg_V599O-2$Ҏd(pAO|)!sUi*XTjTAF"ɾAG'Q"V;*OrfrbX<C&͗HH36!X +b)&Q7(Ԥ-7? LdƌXp<&hp; £0WKQ0Ja0!J;~yyL4@CF7]eđ0Gsu.GpaFeMm)mITċ`n%c9zb%iʔz9a _?hZNRe.֨NN3N)nZ:̡It7Ϥ]2_)7tdWh_S%Y*b] xcQNĂ-,Mg{ tJ|`1yT/+'/]~iתEqhrti!ʫ7PX}vs> ` N K,ss*QuFybdv[}!΍m DΪaiJ[aKJI6ܞ3S~SOm͡"xi^$Թs3 H驚ڍiTJwmP<3}09Jfy 19 ʑH 7CR₉s2ZBfPD-F8'[MiAMERuSj?s`hkĝZmR]֋PtoIǰ'u*]l!RʜH3uoԋ{`x}% 6|Fy^JU9Es}ɰf 0q"7`tcg]UMRMsyt_PBΘB9ܜO6Խ5 zKEō.;=bܫ#O%hZK۞!N>J/%zP=&RzaiCM W[%N8t8׏x[{v=/0Imal~# $ztC7ykuׂ&Lx6旾)$.5,w/A n/ONB6u[PJMI(?=/ӏ2: I PT*Iۛy=AķIp@ڂMQ0x#lǍV18F6d#iq{yH9s3 RN\k6`wzrc{%*bC*wguͲ(cw ^t).Xݻ"0;(>uCJ*|Fi+ ^SiUugM޲txrZk*]$K %rfP >bk])3%/N܎HG-fF"'~)x{R- MU/SdzW mX' {[)U+I2G=!+5Щ[m]Pk}W?S U-Wm% )u"Ia2ږ^*)[:Ab-anHAy'[*⧅iEL!K(MBŸyY˼č@KUZh K*.׮ !FEQ;%6E>+S6AL%G7HSl7&.5ByZ[ߩ*[覥e7IM%6 c \Kzr2eNy6IGf RSJnRĤ'.}~Ế~{QV,l al~ lM *}1|Su%ƺ]R(QuIv-NUq}DmO *L{mYOru4BJp1EmhMod5*BT-ha5uV*iܻn!%%ɹJ8kʰ-1 Rsz (kتu3op)>:&NP-n%Fzv.K#f+C|lT?mLv\Lⓞ@lw7 5De"tR,VLwmFd[}vCF $Q7uY`\erZƜ|K`-z]@Ύ:E朹M(Mbhr NxinFU~wZmy}?.p ZBI97Kji) >mY9t2fM6.սsV_K&_) I s.n{}_BjޭWrH8.$Xsq Nohg#y٧â֠?IIKcIU8HR*q !NS,Nc4voZM‹GQ{'GJ&i-q*{{?xf|w.EGyJkZqO,(xmP컯$U'li.G[1?e,oj?YZz8l2 ȷrw-Y!7tR.dJUs=ӓ7e^U>3(Pq2m{ -7$…w΋ 9r?"U}SMA=o0-6bIԐyPn~.-?0m_掝u2Y-Y˸[77 )6=zP|9j& BYݾZnX~ o|= j)E/!]nciA?n/KÔZ)ǝ ͺiꖱ! BVyzDOL8?\Vکws~#Iiq0 [q, R^)_ur8~ӽ"麊&zu6sI}scrM~ڬ $IRDsܒ:$+OX|TcnnaX։]Ovev[i_qq;1WV)i Ŵˋt!I[y4=[[KsF͸ ڐ c`-@v2 4+5.Y-3=PeHpX\nOmxͪ tzۍi~52ZHnf䝸84*M4h܏ޗi{ְ}NгL>d4҂ ?1._OS o␥MRg”Ґ` y/ҟzN./gb\VHrn#fWYCJ/9k ;O1t9kfgy(4sSЭ<H'8JAl/}[%ƺN>tS(WZ8GuzQ n*cHYޤ,{d–Xb$aX_K5*zMѝ}e79{$`v_wQI~=Q3m*mlHj%QP $E2bG"6Om&:ܥ [IIA_6|G 9Z϶Nq-6 7&9|Nbt.-O.S|ތ0ܿi(rs*}CVt5,,,xWi4}CkIyuK^q&) m}sESzFq5IKjRms(X2C@zXD%ezaQ}-26MMM=vOX&ݽ;7~e45eз7 vK2҅ ~{ǠtֺZQ,U:h71/[H6WaqM>› ˍh;\𶸶Ⱦп(6U>ac@OE+~ǯ %JT8D "ぞ1Zԕf&-!1RSS!{ bqu\Ir4-lc|_b4G]&GP|/93.(q % }+mB*'oꪌ}Ígox~r7q*ܔIFIT8ʆ}-rV+tvHuIma\ q#ikON onk[E%Kzg^ьѤ%)ieB|_=h}}g]S|>˭7zsAPDl]q]>'[߷ڙ*Q l%DYmiKBf&1V.XHf'[JA,VC`BCNC[vlނ{kگ h-7<Uo/DuF{XMK &IѠeI)XeJrPW7*N˓NPe䶄 QXe~KV; 1s*֦4e\ ,TRS[bwqӟz6>ZX6CLSqяWl֐EYB[RS_BT:U`7onsx㬻G{J@S$䂒Rsͭ_+xj*TeO7k}Smj֦BN IXӽztNk*"rNa)a$E~ЇP~*VmzR$A;l;s zKKL7h˨Oʄ ⺖~5S. s2-"JPy8y67=ԓ ? <Ρ`5:99ZeEI&FrgT]=-2 -@iښ!'nM1uZS]3rI,/i 7&ۅͬtcϚdBo#c~Vz Zޝ*uiu麃7n> Q^VŤuōHȷ α4Ω|V{Y9:?3}znl qNĀ=s_3b#.NVQ%1yj̅Yr tƆMO)62O*Y\PyktYS-dn}}(c=he}$S.Sԡ 'Yq*Z0cɐy_gύ4VNMYj}v6ӑx{/t,i$vJ["Y`,x'uNx=/jZ_rܒ6CUԕJbSrOh:t1$MW4itJrLeguR[ <ҚBQz}OTɨ17ZV*);BEF"R4[.Q nVZNVыM}DJkE6=febo:u-4=cg 6MKRYRvqD^jZ4I8~M%B797?A Adi:6ŕ&Yzr]i PcZ],NꮼNJ S.q:&%m?K&<me/^ӽyOJ~Ǖ)nX{ AM-B*f-,\!HqK Jq$h /OU)d@`n ,&şBӺ!]8R5 Shʅق1ꙩE'gtw\̽<ƒ Jja_{iReRPHMao)bZSBVd\H$疕0I2RʜmB׻"FSajb0eЕ;b^S@iQ#Sh-%Jy7]- :F:x *b6^OKn@S$E׌NE.YA-̢ וPSw+In\qC:S\?qlh19Mc BbǕX Txuc L%xK\D?&A@}.s fGStZrVj C ]ϤC*CeRq.fr`)GFުZ[?3.a)*"<6i.ij %:_1s.< C0b5K+Rڛ ˩m,O<%f:,2iRT0P/(p>3?5GS꘧\]q']&,C9IJI MJT{("󌫄ݬS(i9'a5=Ԡ&MĿ(&V*OI%jZXԙ**+f*š6M5?G/J DR7Xb']^ML }/(^Saـw Rnrmxf3A2Z.Hiw]@BJcQ뇴1&x:;8H=Ϭ^)kEۏ`wᖕjFjnjvT biwԃ9U΃ +6)og'Yu>#NH:p/n9+u4jA6ȇz]{$E[@-Mi aR`뷨Z]"-U2km*-v?BTbEAt8/}2}&c>"'n olZml#*2 6·޽6]QVo#Ut6vi-4bdVdJRR9_yJ쎖Oє*jHC *ugiovOH,<? e伢T'1FS)p<~zf \/\Rs[GLU*+f[^KLbRFR](@z~z>BF֔Ƹs\tKU+O"j$£sp{W:vm?;TO@z^ii4TqIo&VBOcq zS]KSYԕ ǴU1jn3+5U6 ΐsbvy-K̫ZŔpW<^cAT44ҙqO7HV{k׊ma$SKUrAq!S16LℏhmS7C`v8ӴOf* EC|nM;@D)56n9*߹MIkviOJTmm] ΔyHFطkߘS5r+MNΝJ4=1$DŽPBIG;^*nRh{ܥKꊀHUReJdӒSsZc@fҽ #M*mWLuNr^aP2V7oD`Z+!qfMmtޝ8)VPXbILK.5no* +qIxRKq+Ri/-^^*bSv7R>_E]\.Val-rebx+1[eiJT>k{?\BԢ7<=5+}KO.-KDrʶV%]ݍd_zscL?(!I sCeɚFDԂĭZ{7k{Dm+e^6rܡX&̾9b8œy 'Q)&oh SR~O`8[An**#=D?-GvBmMH $9h‡o$9^&U5R5)JL ]qɿEewꮕ5OJ> ׺׾MN}bˣtUJVfҠR&@;qqi}%O|R FMH>ۛYߑ7]Np|Utxx1# %Kn䧿p>wYu*_U ]dg` ZGMQNBA5 }QB$+x0̡JBM=č?s^q26 ZAE<UG??h+ 3jFv\T e)8=>$&C;QMg)"CmSd^ 3M։+h'۸ebKT1) Kuش} "1 [4ߴ˙fBBPv i!\}b5D kTM- 10/4#ZuJwTޠگn&;\ r!^I%h2{܄2BpH㿼@dӖ1X1B詉ggK>$.f(J f^Pد?ܹ~zXKw\o1ߴTÅj'&<6. 8;> iKQW֖tuITԘ)D!6m3Q|))mI'C.)eA8$ds\ӯPޑJgV)\z2sW]өidiI8sx:q?z.9'&T>`rbգ)jT)nx`JIǒZ5fᴚI&C[,؄IC\{ėX*i{MtZ!:]L %,6U B=qNk{M(}YIôY]q^2VSwPX#'~bJ3(2:ɹv,x,eoJLEr FϘK%*I!%tWK/jSe8%%m3G/fE}0I#&=7NKT&HOEl= =.(MII5z#&<)*nak9KAR] SJ­k׋!O }-GO%D wHҾ:̵M_Zv8e5[ О.M=HJc9P+4u1'rP>ĴOkio.74BR$=LJ">ݔ,}mx'\ I.(sɮ6etu`+j34 FN~M_ _(~1$3Q F`|XoQ?FWT}HLKPeRBn歭4Rhf E *u7=o@=:$i3ѭ 㿼u5tVL$ 92ZR@$|[$3QG[YD$l+b/[LZ_B)LSA}U+ UKN2_?ZPk`'Ocac-uI$H>%*]׶o,1ae%DJIQ8Ț~`Z6UsӈQUUkpXNL|۪/ԹfR JRl6fh]WLۘUU=gbx(qی>ѵIUE}c6K0\n~)ZS %ԴJ+;6 @U:U7WUEj'YX?Qa촖~yhW\IT(m+ $$dx'?i} ?YFQTnaڝ\'jkgAX0 'Tj }w}(z Tll9I^_I9AK8]aaA)_"W T.=cotF],V*J.(8@HYo/Z \ vRH7=6Hu i xsSBVeJ(@u9r(aNMboFńikf^J2)S/j\/bXb,@ݒms|J"Z ]vA-([yH#Ӄj>5<۶(`R팮[V“Ls*m\ SŻbZ,0 SM#:aS3BbgS6p.oXќPԗvPm67$n.Ghc'*n0[eKh޹DJMߊ9P`;zoYFD[dTlI¸9ځ"lI^^&X濓z`42V)hpCl;g?HJٙnSD/mp{\FUrjO2lZP`\ym?fZV1YQM=,ubbőnɭ5EU6Pߒӏ9ΥR$(uď*'9M"-LD,֪SڐA@8Plq8jmM4uJ,nX<|A *L+b44O+F[6%#/mT mM$%=#XFq#FvYǒ~p:u"EzPS~sps` D?FˌjzAB)HlI%)P290xL zBlcB+TheOLJO]R,9ϱ<2$BeJ<ӈNPJI~a`שHwp2OTuΥ]k~Pިj&XPo\D @ow:ޞg79!J78CN/V*Be̠ Y>}Ƨ`:vBSƄYtHj&3cLDT7,l ]OCtt2si)gxzWRK(*wHq%ҝTYeɖ dNm+E>`I7=wͥe(8 zS$%ECLKiJңm|lIEuR;xJe#j]t♦sMD,Ў2?_[CUt*| fNڑ E*i\rOc7Aԗg:uiK$a(]iyemc}}1ȅML,uM#ur nhc᪍(ۉLb-C8I8:Jλ>fԠ`)LTdZ>Lpf:´3yl46G?HhY҄L'!4.M+XJC>JxNuS q8@mĜI&TV&3)Ch)KO+ ذ t{5NB>o-%#=y63%* ,, {X :U)r)SaMӚK<  }?(k߅YiUjz6;b&U-ۓǤU(D{BWSj%%hlJ<sr0Et:V= @B^BW(HΉ Hԥ+6ms5C䮤B{-fq>+4}V13OjeU9yV@8B|D#m6L ^#Z"J U?9,%`rhRpdo4#5z1%-8 5Mޢކ%Yu<&Vmǖq*iԛ[RH$_US'YIvn\̷0RFnl;u2F0Իe9.}^|'o)Σ%owgBǏ}5Z[LVTE[BHQf[EY ;IJFQ}Wf[Lfi'*Gq33LT(50C׶l>? վmeNH1SŖLZPN,Z+dO*OéOL,n },/pP ٪uL˰ Af|(:p> kze:,PJ% A7 6 ǯkqVUD"2ϿjX.!ETO_hbq2z.874PH6&{_".TIy[ X!C ޛvܡƙ`7{.SͲ8}6x16l11Vk V`9*>VO~`X%"DR'5BV&Q'%*"Nڛ*څ6m@\.s:t?1jR.>iKV('g @6Xiʫ5j2A{2T9@ĸM,/h_ܞb%4jRsLu3^KJxeuY,U`skrT'^zGBdT M!&;12|8jWCQcci<T.{$dA:φP.<اT.l/k_#$P9'K 9KshR*Tl.|$3nْt %!>+Ү6Ņ؏SudfSgh |!ͩuRRs`>}/>:ڠ6Zge)Iu7+rz_Xu> q .ͩH }8>%~!雋2rhmPJpn/))*q龜H*qUʲRon`é^}s/.JZ@)hmʗ5J!9ҝXLn>6Jo&]bmޛԅnKL%`_iQ$EХ[xY cnSԺEN/Y?e5즨lJuwsfk\[AgƓRO`L̋Pu z1I\9眘47i 9RX[umqֺoP%':7賞6E%@%kMt,>^)mU i6ǧ:Y4N:]{qnr79Sn6oϨ1|-=]zꬻ&MמKi)I:c9E U:imNeRF[P6>-m;7&% ,*Y{ _2GruOL4}.m/:;qMV#0d~i8ӄB HZ>\1Y2;L֧Sqhvi@NrlshjcF*|o;LGaa{v&teӠ iמI7 n Q۳[č^A_&ZRYN%)Qݒ+X8q3eh`ǚFVj234VxFB@a\s~t2֖]) )H 6<9WufZt.{H@rnJIܡvԛMvOSa *u/(|9KmlXd(8-{'yN(voJ%O]U5:e S[a+QF>ԚKmkuM](PHĔmF/QluUf-4kdY6wh]H|sqt> Z'JhMTᛜ6p\% |l˸S%$6kIr=ǯ0= P 3\+4wiւ)$?qkDҵǼߦHiTn z\?\xCF"fŷf{]a)%+״jhj='FZАO[7}Etij6gpO3RnB7ϤkǭP^JRG|ֹj|3Ir ʶdpI><@,}|\5#4^-nKZv;cYUc5@!2ֆM\m`[PDH:\i 8G'"_⊠L[HR "] H>bklNon x n>D[vJFYi&ʷ4_$Iu$p2ېF)Œezrڭiqa^scʝz,ADE/ZFV_59m9_$lYR->tθz&,P o~’5Zߘ|*r%PZmS,E?vUOUWJn) $+t f*@ӝjRgCJ3&A1B4 >߈ ꮞK)͡! 'ԏcMǥ$ }nONa 2iM(,NObt}&\MVaSS2 BI!'"Ĉ_čt"^Z<:a>K|mֹ^+j]#f]B ZL{ K؎s`r-_UMj!-j/J՟-V۞9]N]̂S9׮L Otklx*7&´ήm-yCB%6?XئJ65ɣ(ڊiUT`mav4IrojRReglڀI{ml_|5)Rk]%Sne+yqw `r=sEvje{Tmřp7`F|׹m Y.a-V/1JҔc" 9%f(䓍I)*\Z^$r@m\r*Ñr231;RKnPPܾ?DUO:nQrm-:Z?e~F6}bnN]PZt"OeI y&Rd6[SuV)40^дqp7M88E;T:50U9N:Mw)n^^,h()yr͕^Dj/ᗖYRqM_#߈eV,q]'VP8rR_>PԽle&RnmN'&}>ݢ͠*e[PH!̓lO~Z=4ԒN!󧦒ܨ6u j~/S=3mxROQߕp7Qܒ -v~IV.ZSZZo$mJ99"YiLS.iK}%VZm8FufT/=2նi9iVJPooCP:fQe-J d8XA1䏵r4:G\3T۰9%!+D9f3jISر'k[°aWڊfS$fߤFP~7%ؕ5M2X;"f<ܭ7JnH~WPz%UF.5WA;R H696ȜU5hR9\ߓ W:;7"ӫ@%)ǸݴdgKZ(ʥ)+ZipV|[.x*h#uH6I+*!&P&ۋ^/.m&w\j ;PJHNVVH >$0c*ʓQ ]^\}/f <:u#mՔNJJ:̀;@6sn) +f/iUp Bųq"@Ӻ(sjm`y+\<3 ֕=OJ[M2qe6"ާHO77ĵR)Ӵ*|Z~;Y]>WiNǬAB]˩٧J~>FQ]2C+~m-2_{kl.Qb}žtT~72JD[b0x klSRڛWuIf[YJ 5*ڡb/n_jjWmB06>!E/x7ΗT$ksm#q[cjVǼGMMhN]5zf!OC>o 9 P%6irJd(J)R~NysnUiXP$! _x _SF520&qؽmvb=FĊõ*#Ԓñ$[;Kd:R /UQmǦRLHj_&KӨAZ*jy'Ε>/oSV+)6Jݗqbp99crh\m'Ƒt16)]@!Yԥ%(GmX[ ~~5?%Jr_U- 6ZLZRHk**6RWN,$o2o=}MԖB+"eX/Ze5%ޣ%(YR}Әm2e鶂ua,ĔN~nzmҲRqo+PqrzAKi ЊaRQ 1l.PM2 l}cQmYްUņӹVeVuvRnMq*FqוI*Y*K ! Quc񟒝q(̝W$\f^h'& 4­c4F[pZe4:HcޣIWpOu՚O\&MM{ A?/qH3Ag鎧WI<;x ς%A*c\g祽<_LVĎ_̔Uxec15IBG'}=*M&*y6jsO'"ڥ8i^JuYp2A+Fŭsq8riJ,ii^!Jɸ7T榥!I[//?S W:B61 SsK$F^NHqZfHOwB$| #6Q6ljkg[э99~53jp>|ȸ4{xXrgҙLTR nnX"ٽhëT:\UW6LK6\Q+)[Jǂv BhzˇP~/UMNƞʥJ3Kx!`,?HSꞿKd2a 92t)6R<˖v*ֱJRlo|sש)Z [Z,|D髭NovYt-WW w8qņMeu%'Φԭ%TYKθAEp8R뾡N:VBK )) F)=rj[𬖚&ZwDhz*k5i$Y/>2(Ȟb>R}FgUTl~@* tRQúxcSa+ӟH J-l[xOEdgwE{\Ϭ1'\y򓶦[O59Υ{bvSOөޠʤ&3CM*,e<͆9:rۤ|"PJn岱3Ty?ciPKWƒ(Y$[&Jvd9=743Qre]}k#\(r_>N Դ+M%B s1QZ|j%5ԫʕ6-q<, l؏c:0iaԬA)Wߏ{*r=HQ0 #J6k&Ji(RHiYdC} mD-T a8*6̹*/\5*W$tZqڳmAo_u)b<;?Y̓1Z;J,6Cj7F9bRBX~G: IR%O .MMSTyOdQp/qT]>UScV$mIJ v.sxvΌ˳ m$RBR-֌||K!`,G^7.ķR qw p9ۈ;2%$֔/H\m{ QOZEEApo2oQeʛtYH}([9<ė޼vБ}7$ٺ&֏^MN֩r*6 Ӯ30TQhq6JeT3g~# AMK{z\W +fC~+^cu_NekCґI]]KT’b<"鞡ޣ#Vln)͋8?x=+^}0w)$7_Pp%”ŕ^ Q9=1Y(mDJ)&2mлzsFcX6^Yi, q&|i*PB GkDU R夙W҈IQp;f6*\,&{3$4ܙyfȹ܋! ~k*yfM_ l~_I˹ n/U:]P'RE8vea"ǟ\ă5m -)Z$ӟxqJxdYtV]eꬥNQ(-[-b/{XQ*?=L-勆CԠ9'EI/A%e6EMHCja%9Y=Lrn0 EHKNj{,Co;Hhg0m?ZsK^iM1`nu,⅑ߋ ή[S(wXȡ 1=6|ʠKGKI%'\}JRR 99"^J$sE8Vv/zß/Xiw$vl&C& F1\Sb:r !P&KZtQ RYRBޜ`74a)  #'fnG})S7l{TN*Gt䜴OYTHZKC9w(3~?#!$gݦ*6e_X _3%U/OBAʉG'&9*[m)jxk TH@`x7][״%,4I6"ARg$wS%yG6* Kn%' LjlW0AyRܚ$esl\$r3+ -+[A\"e%(Rܲm6oQ*it [)s*1#IQRVQ* Z$/cGS-EɄnXKh~VkօIԄHUUbeTMMŒ;yR &폴d9 ӝ*j}$R)('^G<^6E6Fi6o_-2 Bn/ dk.ɑx*eu(?5ۈb1GH4J%]:n)alRRGY oJRF ~n==b!g R/8VARI8 M:VrZ+JZcnXO?|z}Xm~mļ)hj:T&N]7,\(X{Z6i&3癭tuROmHޟY%+J/޵t _'?T >[] >*B$$㈃eX#Ҵu <씒HҚsͳPVgJBmAF-BSSM\uKlRPq`BVno1@>l3ê-t_mSnPvk z4ٜ2yB ֺGPQ7U1"Xlc$;fܻ MB7BI*LZoY6^>"\ P$qFL4X-u5VqSktv^tKD5f#aV6h-mNʒBVZVH-a/i3:r]rؕTgRmbla32ԥJ"\>m'wz\Ysȯʔiꬫ LdpnʷPۜa6lLK*,jt!{}SN J"ܣsI1F8.$< k\b$˓j P݅8`%! ̯q{b$wP4Y9e Nl0oYO4C`- 9 ӾDYh꾜;3@ZQrZl(®;E5uy2`)R^ld$rQ)QmL8yQ ,9M2RZ-+corfY` h%Kv.n#h*]kaX9?sՙDRV \YmO'IuWȸ X0$FμrbeumCq MQ;^ ٔU6rwVlE1IԾY;8ŜpDHv/~/l MeIy% Ϧ62 .MrdQltՖ\ã)P;@9J;C9DiqHECs Sx)tuU5v ʗpe&ܞ}^B4Ri>HIIX*%K7\ѝ2r"ӿ8l䄥> <=OK5emnmH7WI'JUrf KmJY?ȃԴzѳ,%%VR@ n9MP?Nj ȼe Y{bfm{r6Tب $Fa٪a=SRvvT[Iɶ<I6 .Qָ!.rkBҩ2c͓ı3i7z]Mzj[j\K% Br65d|^j^U^XufR`)K\_ XChJSӪ%Ymj @dq֨z˼kT%LdJ PJ-P}.183͕NCNdeZR @I nq鿈:"NcD֥]M(:R=6]7L+rbNlgD#70V??MZ-ITB$[U-~3Clz3KGĀqij‰*Z6_̔>i>i/0FH*xoUTBzj vBm `aQ.8 - I>$&r)#T-_]ۘx(םfSRuVABWAd<ŻZ,Kƥ?fթTI堔:erX'R;[m:O|UjsJ? .HloB|5@"mL%Y\E|9uA_Ӯ$j |Z%zqqTG{`&uzMZT ,ZK9]H>%sahQ|AԽE6ez])P7?SkdDÞ.Ŵ޼,, ?Q[5Khޠ1NF6fCE !ME0ɅFI&1E1DB{DJ( d˩)OK8 H;wlV4hT٤ թּ@]C($0q>3Տ J4_*KZIB<];9b,>\P?IWPuv);Gm ma[%^eBH鏈Tμ)L{~at:/q*!Y<{ΌuOLRed>))#bR(ΙS]:ȹBS14PRA&=Q_7/3dus\%v-,%JllԢkEjc'MrONtOX].ﲍ86EÒSņDezjם*K)6rdr P^uGn65m`K^O"Ih %Z{Sk.Ļm%pP7l[0Wz*joԁej{×Zӟ-l1hRzY$KCN%7M!!,Nc"Ծ"֩RLgR.]*Ogf8'wDAB/Pm.<7>B6,{y TS>"iJ>#3c6ܝ`m#hu#I_ʪB;Q-RIId=! _.  6vn: }$~@_>Uh2 lIeQDY>"@akt"o{MȎi;FյOAPW% nmUUjvrZ^;Zsrf8 $*ݸ//keiePNԖ6~U-#e%J9=sσbr Qɶbes3 $&NGD>NӁf_^DCOW&ږK9Kn]J)T XCǩ:-rs2]HZ%Дω R]7s|DgzB4]WS49-4bYSX[ɽ⏨gdQ2 Ԧ</HXI[|7`y[@{lFi_1GO2j*zl2\R”6ǤjuS%ѓ8؞M;ÇH(8{$ 6PMoD©R0J9PJJͻFAս^&|?V2/m\[i&9S$LBӕ\EjJN.mj?Yh})K(2,:V<5ۃI $R. VISW0U|~G=Q@U֯fQԦ¦eװ/ZPj6[gK( DE5#6M7܃{\pTjuNjUjƤSf+P(_iQQoc~K:f\j2TŪdHEǯ*CKSsw>Q3J;Ӳ(K32zerKYlFۜ"I{jɕO,@%SSm)m)8 /hsYR6jiSn=#e.$k csֺ3.+ت`M8p IJ.oE:[I)N6njR\ ]x@fA'qef@S7sM$;YfsO* Ͷ!s{ô-~%ʅ[P*d35eؒVn1fև,qA(Ÿ DĢ@Ŭc۾ %W&۫Ֆd^՟]ʿ<91p;79<>ҥ)ѭ556W حZV91aOG4\w{%Aӫ=7C"a66ZNmchy+}5n{IE0A6@%S7RI@<`ܘQg4̳5'2PۍL {eđS߆{OǧP\?9R_8oRҺy;44VEd g&gZ=u#ciK}+-_:WUGoiL)Enɿ1 _2W20IL4$nLD iUnjX%d&XE|$$ xuO}Nqjj:uVFlm\ES#b'5jh;Muvݧ2BA7֏'J4+;/Xd.0m8e h6E>E2[]K-aَ9m._ӌijgRdxE;j;Rd%[$cXλ-*I㮲XZl2wqǤy+[KMKP}SkscPFnMk Є~LI7w/O)*U=(Fd:Pd㻦IٛtST]M,jsQ7^MrB- w7Kެ90! #jҖOk`śO|47P#%f|ZIu{VևR Jf3WҜO:R,:ς $(ro#w^U&1]@Xqj~*㔾RgSHX-UYPROl`g=c}{J%5# -KJ;opI{}!.IA2=78n̻s)|ZnT*^i xmXiS )7.7=-hɮP&Q'2i<z/kZ۔ g=JSktHO|Vj[QFl]nsG2xZŢLͷCA m:R]nH &GFiҳmJm)x[CUnbWVA)+lpn}]HXI_)ϵN̵P<e.τrJn;rb=֠$N-j]ֶeo=QНgK]/$P7!~N-G7u֮u mt6<ÎÐTjikS4KVL!+aRO+QbtMjiG'$^.J;YmOJ ~'RijW:H*[IQ*FҧdIAB'$&qR*'Hߤ5_LI4 t7$0Qt(+uh;C (JShLn}65!ͲK)j MoA?2KPR'[2&'RsMӺJ*y9H Cn I>FmJ. _TI67)M6ZUoKU4|өI \`[.ׂf5mKp{vG*>ʂuuQǔHB۩mAsom+۹6##^Jԝ/LBj? ,!B\_C!Sc˶T6pqZ(,ޢQ5M턗um7w]D: ڰcn`1M[+@t嗓=۞ JHͶ׈Ql3Yw@"in6qh?y|ҏ;0&rˆ _ؿ]Y*T P A6׀F^H?BdjM0Ĭą7ILL%iJ̐7Ÿ]Y=x̪V!.^f*OQn.=;xScRWYj.7&awWٽn BzS&m \`fiYUꪅCë;RE{ܟQ̆̈%Xk;ӎmO*ڠĩqh7}tZRB)NOĕKT,Z?떅[Jt6%.8# g؄wMg2 D֞SKEH֖۱{ńh])IT]`ÉAe-)kR{!J#7wFJuKҜ@#P-۸uM.}Q4PMJ%J7`\!\L Iޛ4ԥJwJi]p90oPNVEh3 &bfQ7==CXRo<)pڔ>`uR~vsQCWwWuJMKd:m 7bϼ֥Ki8^y'ؒp}?QWg+FnU,R]qMn\D+c,I UʰҁJeAfq=$Wn4%UӓS MnZn eϧ=BlJV6mA> 8}٭^,TTk0" q8)Zoa&Xk8~7<-ogR7nLQr`{DyoY&tοSo5K`E )ZԙcvX}Z^* }|ȶ, I.^{S_RNx=y[ENQ}X7i]nMm8f\RlTҸR."i`J+Si:PP'n^lH rmm ד dQuqp+Vx#pu ߇qne3>ZU=0MHSL %"`\nMK:vL^AO|vKjumEj>)`p Xdf/Z;zUuMQAlyNG?*4yQyā֭ڬ[9uiJp?-+k5c ve"ؿEA&UVs%(ޔdlLi i@k Zȵ՟8r*cjUui,g[M&Jn3Oxf杠,S҈ЁG4NרJ|6ŇEnDꞛRW)Tgyu;Xm ŷ|a°UDU˸m7$;!EoƟmr`<H6[mIL4 ƭzǮ4 %[,J䂒/2CNW뺌fPmH]'rJ`JsDr&S^ 6̤Tf\4K`69]Hu> {cm{~N|aBڦQC)mKn X_U5ƯT5dei7$eDŽ-k C(R })4P4.HhrR2Ғ7x^Ѫ䫨f(fb]!=^rbͨ~ :iRA 1%2C."8eԝq8몤 JwȦZ>SkvF$%<=szuAs+ ʩ; 6ҿ Us~Kh|Iu$0|ƽj*ZJ R=ӵ7Y2I ޗڊMS2Y)lV IxZ92 dar:ZQMgWͮU(!Xݽ'$GhY٦eLD!SmbmxrFWWn 2Rq1u"ӕ_:,/<$H” \؀gAUh4˖^qO$0BnG!F5VSTN2(A+yHK]bdhJY~W'Q/bo։93$2!{mhvIJy{-9QjZtEt<ۏ3*@E2F Ihl+s4E@LɺO$ >u{RWJZlD:@lƒ8par=VLޢ]Q%JS0NvnrF[`oƭ]}/Tn{{,~6JPBZ'hk=3uRڐ'O˭ ݸ.sɵKUҺ&/5gBn]eWϗqܛ ȱ4e:]J\RYpc(q?X|ȱGx1^ m %!V 1:@] ܋+Ә &Ĉ nO|>ґd I/ @>~XbG*vEahVqr 6pà 30 ,l ;Rn{ 7=q&-ī#myN/p{ ݸF,B|ECA0fvoO)=`ͺ^`+0m=v-Fs~@2mJ^GkA? O>aDl`$NKJ&ذPXMv'C ̈́**Y#qTg \babWma;_VԀYtLӗNZ,y8^%d;/7@b$䵄V{.g- +*Uj@;ESHs5ե[MTWAo*V&_WT:đX[;`u(!5hd6P+o%O RzUU?1Rh -JoTu[BEAa|VtdTMd+?xx>"gRmDj+nԥ?r-"njOSVj5Y`3TֆfҠ8NJj]aQ-+S/90 ğ^4GN ?H}rk)CAr^DSS [ҪrJ u)|MTU0HKAK7O:}2ꔠZ7-hv=;T{{AJ.RP pTI.%Ë`{_"7g1 %{Ujn)}qW'nŮ-kCm)VHp*K[hM<DԄJ:igQR|%Immcה[PN:쓩vAI{gm|HMjL9?+il_u'Tq)u7+QMeyd%C cMN"l)\(`q :_&`ʔ ^ie|!@A4Taݭ- E@";Yj_Fu4fV "~@ĥ{^[j$]3=ԟnD]H4۟2¬2a&{FzɉE#fշXHciF3u'=ޠ^tKt69pqeXJJJS'IHza(@]*lI=굃~S73HL";:AiS3A> O=nmigL*,ϊdR+ 6&1m+M螬LT&5dԒ%1My^2RRFיk_iƟ4WGnb^tjS3nP )ʕ'Tp`>6$Es$;zV+=La+{J4ԋ)ۼ%'Lao/,[ P>H<NY-iOL ?:%aiQAI $Y+BIoW$Ï|< U~-)oCLU*e\I;U4 r90"b@4N%pCX 4=:^t! 'RTR 2;F/ ӊz_< b7m_Q/)E^Zim&`KSZ w8H91e/ue^prl႔,(͐1-*i!>KV睊ci7Q@~DDPIie|A Д> =/&L ~PiDJvw^Z%f’yk dĹ鴵E'H^+jHqNo-hzzD3zH&dZf:Rݲ#7'+NU5ڒͰ-{,2-Y6I-ǀ@}U)AѮ.8zYʹa1Z9䎷3)i%Wˆ-Nk*-=-glF@)(Y6_G+WqMϋ'$BMFf;s URzI4U#Z6/~")fBe)b;&T ؕ_"5] IAV\q'ukm#NlAGU$څ$۔ (6A~ Ÿ(aQ3mķ%(Ӂ4HŻ$DMSS/MJ/hJ\юχΌm QxnHm51)K0iR?q0yك 'zCN)l%O7#O/vpIIJl;_+jHi7R`J/Q9$(7rl Z*/i-n.%/}F"=#uR)YEzRDB|(J,EI&g dGEu#tKj@ hwȍ_HS2AuK54;I%?A"ԁx47RYBY{ʤ3lۏxhUzY&~WPS%WO~^XrKOo$'6&{r9$*P3v6rQ,6S gY^Cs:ۧiYQ!}NI#a]lZ~.mvJ}յOD|<&yޘkfH{L%ƒloXut̓ӲsL.-d38eVuOxtfS.JKl&\3\ӌ*x P.c$s"k o*DMJ~鍉}{dXh~퉭C.8AŹA:Й9?y2o+d {^sΛa/'V!>UJ!VAP'Ƚ 49![ю8%U`@$c1q(ỒfhsHg%2ofL%gYq %wHN6:슉I xRT6#=3mO"fG?ҵo2Row?}% ص0BodZ0.q2ԠnV,ZJExDK,srM`;(L?9Ja x^0}PQͿ)zFyh J4z_!#>Z$h)"P'ojmۉXG4+4H)JXq67<HɞR$ a뛒42|R\2b.䔯MfpT[p\M+Y : IKlgʷr1 )/ih*,KKn6ve@~֟֔CTęYlO7864eM;1O5sYI)QF!O Rit]e; pᲓ)t~NFNT4A)e\!#m{3#5]jNJy[5Z4ꪳ )]LS|@' |lONѱRu~x"J "MV6JN/lslE΄RZߡN&`IH^)"c%[ GOQ$s(Gl2SI6E)~]qnjE甄l(źFKLiNQgZ.).˲_lIHb$[fze=/ JA Ip/q/m ~^~K&y ԀyH{Ŧ޿'e^$J:e/F[71=44!;by^k6.>(uMCMθ)NUsaohpr3g [Q%X=G7NRZ|)BA~Mۉ>C{tRU bu߳^r|7 /a/ZFh$d4u&S ed\nsca~ $ksNeoYޠ 9p{x)QdOJPijIֶݜЪS;PY$zº[tFS@LU$)LiMʓp{rDkpNS9?Ea@wN] ]uzjIɆS=5.% i;%H(1u-GGbql.uwDmިFd+VMueH3mL?,iIujmbŭJ!G7,t$)!M%[q98C|7WGrq0,K&X"\_%~+ЎKtԓ TRSk){p!VkKrzIՖ͐EF-0IgM<):6̀CgohB vzI M=%lirkSoB7\ܤX3!bzѪ_?O2yʬA;2@W9"%@Zaʾ[DĹ6(PMpEGjuGޕJ٧ Ҁ#-o m@:I `7^U_Q Z dNτʜ>TG2PM\L4D (0ȷr\MS2ZRxΑm)rT )%f A}~QL4QfKLNc[‰:etyW uBYx̅jI+3roIWB>Z Zqk*I ]:b7TqRIMT+ qA;a@N|gGmZEbN]'j*kq޸1o!Ad_6 ROR)ZOVJ4Q+k ÷1y2W[f!ԝ8%H ξ~9e=xXHZJU*NtLRAԅ`3ꚛ>cFÏM?Wk 9Kҕ(ҐR}W`o@Ņc+zcӵ癑x2+"]{Q.MU avy#|Q01) /$0s)̕S)tل$y*R<Q31ʜzMWAE]Vn78l9- '(=sPӔRq R<3*ܧ0??.Nd(dmK! S$PRFHP=zuV>rh۲]4tn&"Ѧ^X脲j)\3l,h7JE¯qcqkwau+Hhy)ZE53@KLW>WX#uH#&L d:7-R>^UX}!AVҞjuҋs ecpGn{v!_ gh_ 4RONVfm.^) ++S3Vf/`qp=\K[Pj}6[y%/9)Ge*Ml6yu.8%h8D4h8mn{^ J\ܭF馥!yȭ4.gbƶ?^$YoL:qj+t}- 6BֽN:ƈYmJf`=oo%:s .У9Zڀ@RpF}{ēZNSz}:OS\gjӯULjEc9[-]L?gu"^$XQl&ůzՉ"zL!!,/Пu6fYSAasc ͽUUu|ҩIUKi/TɖQw;G]p&rK&Lk:ïZj)>DT ]R|u.i>9䤛ǣ6[eyK=0BehӋ8؂qF>UT AKKTghJ^q-k D P7-dAsӝJ%K\r@m/Z4d%ՁGi$Dޫ~S+Mй6C``R}^Aj.Ӥf Oԙa)p 1ŧ͎П9+~99) | E7(6(fR;ب^׶#Е^izDTiSQCLJ (X=h|>:Sm[,IV?}*~S̊2S85C>PLsȱ DUSZ~h4O˭keS[ݐ/rqkS/S66HZ'@M)i gԾIY~2~Ddň.2^5( A(5<;Sҍ%Qe~Ө S'vI7dh8r*mI=Z> XzhT+4>^y-se6$xϴ N-~gͱzR`u1[#)srl-k}Y>o_ڣSuIh}BkE^Tי"u ۍA0Kp_-t*]I"rCϲ8" !܍y/z R?} ]~p ؤR1^QR&~,{u5Q>RHIWwWj7ep eĸJUG! &42<4["w"#$,Zޒj3)4 eJ*"X[2ZӣQEPa;Ⱦ6NshӪ }Cm:!lˮ)QVH@ ٍ(5IޔKr#-iI?4ćBM8t' Gi _]I\ѐXR%Ȼ#bk1j/V"Idwz!\fOuS-^.M-r.,}Ţ+]wT=OʼPӁ@[/Y(b_vɍE1T+l"Z>"gobTL5 ҝ#f{DΝN%u%s2"z}q|OQ2Sht !io*}>؛#^D`?YхyHMz֩S0J!l ^tT۽6DeQ6YK~Q4Ϋڙ{3ӵ$)ZVBD6 OdX6qBޕn?F\ /hRHAJe',#o~" YjsY$EGcvh@v xh:3.˦ h%5A^ pNvų߇# _A-~4a>M^ߔ=湪)?)Bp(eAa.̇}=)!*)A#]@%6Bi2' lm${w.=3ez[3-q2;fRD Ķ=Tv iiiBH8g># }AOauN&1Aۉ N3v-T-z}0&^OZ3$nREAHKꪯH RE娖5fՐpWlc;GER]MNn3OΦj.(7@u`'N=2iq3\= rFuLsJ%\-chߜb+5ύM̝?T,UeTBj^QlP do3iuʭBa[7oUNT& 3$d-slrr/S&JMOjڴK/Y_35%rN{q-)+20[LRn8DꆧqW7lDnZORJ*L aIBҡqQw&-1^LSAӓJt i4Xok*']MFz8mL*@l~|úBhJzA\-Hyab*򄑁~.~ZsP_2 ҥԻ-~ޣ؈|L>6J\ܦ  U||mxuDD˚ 8TqAi<at_Eݜ[ۊT,lws~b֎mYtE0Y7 ͦWje?Z?Riٺ^)90HM<shK3呵+B ZDEBsZf]^dꏪP>֋&LuRb^XSHrBUZ/fdr6Ee_bR{PN0A/BI.!ےsm_ö&4kqs iNX\n('#ѝtIԝlH˘2ZN@6֠OGꑤ|HQˉ[t`Zsxbx*qZW=RGĄB}S|0 {c3?RF$v|ˈ Jnl. #z[H=[ՙ:? kS\oK>ua虚H oĝaF0$z1YQo OҭD[3rWuKr XG"CKә\-;^yd/͋ǿ(|+uNyrձژZyK%ؔcI6-q0pa ~Q^ *o;MϨ/0Qcs);-dX nJmxH'K= roc9AIH G|&5)'̯)~{#BGjH$J{  T7oV1 'qGǙH.pRnp ͠˚MrshB&%GK66[t؎ ߨ9"`IytxVP#@[ۉǎDJψ-ei=khfZԺPM6&7&=-yr"jꞥ ']Q5FK)2RZA P 0!y%eTW&J}<'3ۈkΒhYZ۴mA7hw6uFqӔi iR=JIH69nuǜC$9DWmv<劷@)k3ZZɩ*[Alm`8Hzw5MJ-*^n|ǶL6""\N`F Q`17CaeE6 9>i3)<ߤ\O*3Ji6E&b|sls+C-;K @RNNqwB̶UTR:lڽBRG0i&ʚy)n{[,) 2V|* 6{x=q<veZm_(!K $*`^C ]DҘRR.N7(5qFqL⮦l@87#mJR`X)@qkxíE!l`Cڡ<=[VBYBM'ߋ--zssAv۸3nYz %ЗS[~ 7~\t&10[LHؚ͎#-^=*]m˼Bu+JĚ-oˁAIq8Ry61=TRM4|KI)S%J@Q8::]fZ[Ql$)V͹lmB왉sgΔ4~,l1~wLL6#():PnV6-8AI*SYl6ʛB'qۃlI9N 94饷]92dj>#H3o!j(rX.:PR{P7XJ| S, c+KIWSF@A _qznY5586*ʯ7Ǭ3~f-˯jܖٵn{9m'tmKRH F xKnE"3:J.>_ L\bb,7oh4u6zic)!Ϥ,etى'JAm2G$|2717z}#Ф:9kV˔jjS&ӗ[ʧSMJM;8(2*qPOȇ4QWjSoM HkDZo07N:ijZ.b,sŢaV@bG>)ڪGIi+JЊ${x{1w=5:[gZLPFMs|)]YB+LL,}%i#]ͩ6RLȽcŭhc .>8 65)ebi*P*W⹪?C6Jz~π-!wUQ{"%ʹS̈́?0 H'`m͊/D%{GorjfD_qKRR21DÏiQuf$2?XKԛ7{-e^/nHL})BPbNmMϋy1K=5Vu]gXTP.A q~Q fWqʖec>A6ڝOULT#KT֮BY7/dT4^ (qٍy`P  uVd}:֦$!vB(Q{3!RCUꦞuԲ$Snnr,+v,lx5,7TI:P$i;G8)x8U={ĔJz0l|owrZrI M|.|CM?JGƧT0 A'aAGkN>a5Ml ՋJڳ<=e&#EnHS)+Wfh]!'\R(Jl-k_*Wk*̟PL6%B,BӈV Fc*~-:hԝ]Liaat|9|xjzwMm!s3To#~al_ 3pD׿ж囟]GDʔ|E)zYI G` Ro/ߴic"Roel9@_$\}1a٫ _i)aɵ,.aly1'GZRT+k_ӫP,y>r9ZLVV)Z*,*ͮFѰAx=ԲrkuIj))YKmlBi 9 _D~M?0LHKޫc b&#SSU:PhӏfH 䟿ҘȾLݿ]u*url'%"m[mcVc՗4 ÆRTL[^&`m-; JKBE*mH*P7Z \՞\U98V|U: ،rn ;kqH "` ̪?u "u;[HSkU{\_1bѝNY䶍CRԟC%V)t} /%*xl؇l9; ;*"iRr]@ iYP@J1;xM"wBvYk }4Q4)D:ۋA|q$\݇Az uS $!N * #L8ª.N,TW;:ˋv;Xw$aptGT&zn5|YJ%;TI=d6fTC_SY]:Mդ))S6@wŊOc2˚t%]IQ]”A8itqJhS. iIl/wmԒEk0W8M.ZzSGN.UChQRxaĜ{m>0-MMSXuXԺQ!m0F{߄[񛥤'EYAEjlTx#b='M}:Эhn, )A)jlT>)3)MJjw.76q6+O"kP2KpyiԓLԒwZv Pwߞ CjQUҮv%4`$+ͭausEKSRlNM-h}S'SʙIiRj)v \'05*5F t2/\I@#a6ffIK%m%Ĩ.wf\f)5V܀TJ!EGpY"&#<^,iLKQPl];0yIsR(D$ wRPUk¹fU+=0 $ *1a/u&ڦeJK3M*>(9Nm6\[$\\IQeRj~)ᐔ ^=̚ݹfnC2҅iHϊ(?b;siTliܴgSYJ,(\qp{'oHr/Z >ʵk3E\2qo*q{9opL*e*@cxI!Eո4@"|1i)Zw\VnQM{mwRΚ:ErrYMJЧ $$zfeԧiSLI i>YAhGTm7|? #EKnѓHMw'hŎ$^"%%9&ohg4ZJI$Y]]gNTԺ̻ad}a З\Զq丒&ӭ$_%*ߺЄs2>G􊫙ŰiѭAR1ȿ1V/?Pjiyd.\6&C {][49nvKX9lsaU-!uk bK)򠽬ʥt|ؓu$ͷuq؞ uA{OW(rW-$c6JU11?NmZ6V$o0YG+uYFj7)PTk](*6~GAqɢea%'Pֵv_]/2 )DSbS{x뎧uNI)ޗAxjfE\qk+ЎZp4eDľT tnŻ=;ԺUknfsa+mM;TxFJϏ'ԮHmi K3 V9(_6xuXM3RbKIQQm6$ZBTĦ110C %kXɱ"SnPMT)Ki;u􃁐X'UWWQ%P%I%N$ɣ*~!n|NNRi(nt sxWZn/4 i Gª'UWV Zcp2\{/ఐ}oŲ5{eߐ/:ಙ7EhѱZIuz(Oy7/<#bX0=aaV)4֙bL<%ը "7[>j&oBRV嗴N3 V U/y#|;+e[ RҴ7Zy* Ai\X1 j?bBTf?]^HJTx8zQEߏC&XAh&˞8Ut!, 8߃8jԚ$+Z14,ITx (cL>ye{yN؏&וRR}د"Dt%,?|hCxB 6nY<?LU|J`2E\lz %~z(χ/mDrYя[& ٹܸ->+N$1띃ҐFekjR-4mRfjTү'QUqT`[YR=EEU*̢~Tx*N(>-Gf*$Tm2`u HǤx[l}1b )Ɛo~*Y3J`m*Kw{g?tU+NP埩8qIyvzO KHK@V= IvE1~ҏ?QrOTMjR6nlQp**Z@8?YHâZJZ4܊nMHqysk_DqƄ"rV"p< '/B%_ ҒLXZ [cPY/ ̥W]tCNM%Bbh=Plm-j! q,T*nbo jfZpMjR))|ޘ{Nu}.ysLJ7bj:[ھtei䯌ݒ,NmUq*8u|+J\@^M S+-bˮtsoHY7$ ZRxF_T6)>P(c02Z$5_C586P]?:t 9d50OnRR8 {fs]6i$]KU+`'#^g!(Ny|[(?&|M@>Ɇ斤*v'rԱ)p9B\ӍT2 8Mpm+?Β_PCrp4’o `s\8nV*\*'[Uk.|zErg`zܻ AF$kn1@%CrFUdKM7%[Rl;տ qYenWB<;g"L84YZf9A|Օt¦$)JAds3Em4/{W=u^/97-%(h3.vڅXװmK5sl%m)r!6f/kb_.N ̄^7Ңi׈l5IN l?=-cH/&S{c? ;-OА2oLsqo)<ӤD%Pym [Չ!叨=K():P2ĻmNz~Q'aMb[ C$_lE;D[]aiʛ-O.7sahq3BHy3O|n|I)uᩩHǛ'c%(+UC]JCu)JR]d_6GlѺI+Haś&&۷:|Peid:=W{¶OyPF\\'s215#TTW*%~!TCE}YI7ɴXh`};PZl$%bѮˬ2NS99K52q7$ZPfn1@WDg ;M7:L(/Q.Ynx %;E`MҐq7Sn{,X[1g**J"njܡ]l8JO1Bߘ8B%}7P;6WnRSbqG{ZB 8AM{@X *fD[*^=#*E cX0Vdp`@YUPNv㽄-F-0X$v;n*$x&%@nR'6,eRtb9)caj,qsh2YۼCIt;ı$>!l\a_H:]I*!{[7N/|E7 MnSʽ\m^d~IO_h㹃<Ѕ>`KްE#a{(Z6o*@ b쮢I$ݠ|JҴ' nh"h|A|69<H:] Uqa 8_ZN,¨y-}L1R%+ $O'9`EvȒm/`RE=dOi_83oGuh&(ɦf Bx BEʨ!`%n q -Nvb5R]nno䙫)BqBvW\҉a(t$\ &gRTy7䄬)y0&(  S^Db:7%e@@㄁2+DWWb |Bٸk<;;i[!y*֥aV(]\X)a=xTZL+B #=<9GrW2޹0:GqĔSjleq %J] "$Z0W3ȵbiZ|Ӥ$)t C5\n7Unhi"v5O 6aVQD8W=! 8;3}yҌ+:o 8ugzM MBO( 6 ye aM8ԭ('{m<+>>(B1US:LmgtIRAQMpx#OTz 'gEMtˏ,x7W7V ><-Vڥ֭)67bNSS(Xp7fۓ UizćQ%R~dInmGpR%+pANhjIIB_\)g+mw cC󑁍;C b^1 _}9&&u5 VġS ړbs2Tn@Pq-Z`k]<խ31I2mJT/k9&`[}#I+:Ly-#G6d\G5:M:2#^y?Sv?L1uhJVmO{[iiꑪ+sY2˪r]Uf,JlUUKJSe"Spr>|9n*;c̎Q҇NfKҚ2VQ,w%y*88ޒIsNv_a麎m/r<_'6#7hntԴĴչ$r<[-ԘJ/NxJTmϤE%*P*4aMu_q(eu@w~Fuu'm\y_kx<"rEwQZMovW6ZNaˡ6HB97&i+(8\2GTnsvxPZHq|[/h+*hS^wPBf2!\ElP)fU%e'7 w[RTS63RI)<9<|ɐJ7JS5 S'Qz&N@+V%J?hs# (2MƎH$*\*;8[R+6a,BT@rm{-[44k ŀlByI#)q8.Պl÷MfR-#VM2\ mNWaCʈKSHbOcI*ijnbW7p"ssNZf)mD@X mֶaΣBa Ͷl H%Q"]W[~RWNRI)j]iP2`*\+#ו9jڃq>FYKP<@ҒExKꎟIʶӴ oslmy\l8l+n"7,X7xѩOcN4jmA2M#'x3=d iJ|K̇hԻpF f4&e?N=˩.#V8>[ts.%2LȕCd؋*@\qR";*R%/M螺m[2r)jDȷ8 PLWus_,;{HXR2NEͺmzn}Nb)5#UzZ5D BCeFp!E$bً$8FW5˕9S-嗭sA*rNԧ;YEG X5MX'Ĥ@}6hfJպG)MiI A.ʵe*>Jk%3:Iɇҝz6aEh~Ž,.Y7'܎bf=5EM2MO7B9K/M556jZA‡Ȕ Jnl1KE6cۭ+AKix H'7A#؃8w 7P-/}5O3A)Ct>Q„&^cr1kDEgYNLOԉDRMɽ͹MK{YRڒBfmu+no[#CO;m"GLRFf%Uدkߏm 戋pܙp,8Ѧ+yPGZ@m R_NijMRPRO0n<)1'Gg؜Ҫ٦LAI͢WVS-zNzJ F="ێ%a|hfVM%v ||Bi%0R熙e~(* '["C.u+ DS)Z8q4=a/TK];Z)ZK`d*{^WLQձ2\N'̰b !#HW6M]lJ- sizS70i QIIMZޜU>{ԤږRwXB6x٩~Li#( ANKT7!JU85TiC*yPФ-7nP \(S9Ao*;F"itpKZޛ[);719:[E(ʔU`vҤnf<+zzMet\|IxKNnA!^p#}WGIdJ TJ{ qrhTA#l v!VS_,u P=ql-ҘTT}*q,nqɿyz_IN/^.Syש-]vUOJS3lvWLRuLCRO%۶tq$Ăώ.0PJ'=d%5NJPeȵ&XM8``\cfRA*x(N#<&*S%IJRW|r[9qSTzJf%&rI%%,8f] @*m Z?[CtI]FԲn'DVmX6 .Ni֒Пmq%INŬ"qYXhy5]$ [i)}$klc `@uiJ;MpW}S;9VuyK<&x(pV#xu%R3RᖘKHv]i)K| v ߎcl2ޞ!Ԗ3 LݚQa8B}Ljz[cne.~Θi)h}~n UE LkSL=-+[rgG:VEV:vEL(Vҕ% ,M͇֦"6Bk)1_BԝD>jyts}ʲmE&ur=Gģ .yۢZ6I^ݸGjG O*fm)fC?C9C)5STtХ(N=M᱇\dXUԞ)78+R) شQ[I qۓ^Դ%2334v &􇊲R-7$Hu -_њI.(&$2$ 3) z]阥_+d\܄_$AhU2;}XTmNleUjcquOK`n#g!8fYs(.HI$`O%OGeT4=Nk&ܣ6I @%(=EB2PBVTEE2䥁 2l5a1u,W&(K Z|"okshˬuDY =2Q#6Vs5gÂKt1.H jPM3:Hh{Edj yLEtC6](։?s q7+3x8,-F+tҚT6ڬZ>n>5ďOcLjoQyW?LY da^\3RSN=WeN:Sc˴))ٞ'w}=8D@}-M r%H*AQE #4ME.9Ǭ{"IקYjhm^-֒6ͮ-j鿆gXZzD)mPi;R@MqߓV>&P(Z6$HU[]Cs pe575Sy>dMPP)y>jmT֍- .Mk)9(iJjr]@C.saJV1-Pbm){js-~;d˿7Usom 2KRzdtmB:)*Sn,, pE=D"J_DԒcO%i9psFHT-XN1-|>߬s 6ta||o}\nR+WE-lnS {hYAķ ʑ9/<‰V6t)6 z(MiN ʓ>|Sk#ӪMYtKO8Ti.4S lDV8Ŭz"ufQ-*avV  $6A.?Sr*BeZtr2&&yY5^nc-/EιXڳV (+$7&bӯzn:90fDu ~4 xB\҈HFNWSi! K.Ym. {ߏ״fa-8RRs*0.O|j,ՁR=Q{ *᠁x_]X8KR4TA?[di2I Q HNbqjWǼsN]O[3 jBT.ZlEcN _*ϳHD!L(XP~OᣩKS:Tܡ{$%c=&MOYO6|J68>r]6AcvzAu:4ԆoRtrԕsuUH{7Rk@?l)CufZE&=/zWin>`\Q[6~oni%`ƞ $RRHxL:K\}N&JsNҴ 5QMbmZV1bqi)LYXFDP*uɦfrӏPڀ/rn=gX攍qMYOZEH*H'NִL*%B P;o&BbG)VezKem1ԩ^U¯%DY?}OҾK2ʔjVut;r ?#O[NЕWnXJBJwyn;M7\z8ʖPېk…a@cJ# w|ywwTt-ktfI7{؋`fWku;ӿeɶ\܃/.\bW+?ztku%Y>c~F-"6sQSXKiOW7SΜf׹J辩i-z3A Jia %` _0EfLo>%'xWwGgUHQJBq H͚zQUWPv8RM<$3j L\Xt%wL8**!) qMu\ {Caçj) E]iHRPU=#Z;hzu)OXKʩ*%B khoa%] :R ۈ'1> ӯxw+TU3k/l4YS)prF>Ђ:3*ťHJa0H \qߘV(]lWjre׷>a*,cЀĦ`*>v|6.m|O5l|KXyF|-yɑ2f^X6:E{'d>zCxv?"zEh3LM86t$_JקTI誠DLI;@ŮonLW[M}z42΁Oެi򬴤 J:`ߟovSL$ OIwUF|2 e dep!) ѳ/n"ADm?")^a RVT'6_lvܠvE<ʔ UF4)tb파 [D%O2[9d,I͎DmSZrUBq L&Hwv㷬dJ_U^xPnchmF+nbivjZ[ѝWfYTf%))W)Ga|;UL|C6% ~KjRGp7m$( ҉wVjJJg*ʻ\Nz~4+넬>yLJ܏}! WONQKE?C[A)Es-- 8JmԭD;NsFu^bn7/TKJ F˴m׼o4>]>F4nY,fK[@) 7~,GiAܞM.EISysc:"&&fL"gFIL+_Au iNs1T4٧j'I:>fXXMTSm7÷@6mr/jg̶$u$pOs^4_Ft^r4%$ѪCkQ;^IY dDUe6W

fȳ[ULeߨL"F,InP~ !<%[Ze%-G&]H' IMxGWC5"a 5%gW{dZ"$uV&Kfr@.,${$p2@&4_IeWc>h~8鴗&DYHA TtńVX]XX@V/UnsGЕ|0Q/AYq jKH>`m}TZgE?u$ .H)/x^__ӓLDvlR/͌_Tv(g{-^')M#C3U3O\K*)7 IIox'W> PNJw>:.ˬM8ͅ\^-O'+al);'EuRWQhR˯n02RT.1{B3SkД+maAeǿߴWRԱ:_`AR\MȽFs#VѦ OnLLI$$d QiӯoY4RtQɑ2RXCE`z$qbm)}Spo097?1ӽU^4]uF%uReI<?2Ltm |#~{-hZ^IA+u3#v}!ĉY,K\jeÔl@r# l-XoPҲGq3 .0\nbx)mvB3hQ3Lr'%90P$( Q k&"؄\JO8ySзYMEM~ = ,峐{„Xkv0Eq}n֎;JuhܟjAMsu$3 R.8 w#é s9 ` -Q7ÛLarlGNᐱ))#Әl }&7 ~yvlʹ>I !j]s11Mk/3xLbYH.&Hܡ9*crw(Z9OX`M(6qCeW*0q*ڔA; X2TO UnmaRSmoyL)S7>a Ȃ)7{b U15] w*kbr9rHShT"&&'umqs{VjIm, ǘ2J T_9 ARAk=0oZPGn`}a4؛Z< }Ex%JD>]b -;@3FņL4B*qp1~eZ@z!}H%D9"y`URxB-֍BQ J┨BlE`}A [m1 Zݱ\”6$c`&{#%K$`[Ek/ '1*MLȸJs۴u`\![ߘ:w-h*F>_QvBaS}/+ ;8-JrAEv>ͱaiy/dJ')hJo%) ò D>>́aq22T-@ ,Ӎ#^"ٙ[I6:y(`B{ëЋɉyℐǪbZ,,mmh6RoHPZˑ[fnI 3/?ÄwN) ( ͣ.ԥ R|-DEw):3xg t(R)mg;JF,/۩zf}UL77U:IHz۹s) IHPIlv}a+$!u;+Ӝ 64ɋggtڒ+龟[Gsr}Dxr'm?[OĶC5M˭Q.d0WvOpl攁pEOjrM#/Zx ^djҝKdHiI^8×$>bxۓ])_0N;6qS)vDX+/k< SHQ'u6rE[IWnGq=>ײ5?*RxfN URiشdfҽ.~ U`ztj OW ҘC/10QBp*ZgIhhr :̈́*Y2쥻'ra&t^] W+imΩ )+Ky/caxQ׮MkֺU'Q))B.VJ+͂nB ǖ~==3jS:Z/0Rntuv310uUUZnX=ҾkӔʏRih Š? .2PXU`O,:7OL, zPG(96e>&~%*ȟBJv+alӻTP&+E4 )&;O(L_z%zkᾱ]qIvZ(YJP skzwW5k*kw 2RU9I8 6gSߥڱS zs[,iSj$M1+ P%$i#&s e(BI?RmKU;5IRm4䄤d}O&pX Wܣu}3&•iȂa 9% RUmk{қz5ֲ$e5YЮ4A8/sDޜoB9+ KFJo(8qc&uW>S9"U>9>ũ[v@AS|I)X}X:JԉZq!JR$}1-}1TƺLLqrIk$l|8޾'Ms,zʕ{n{[Q3Z6Sm>R,@xћD p,/MC4v*Z]Vi2w@oؑ3N0rJh:TZK-RSk$ Ůhjb:ΒS:BU-3;Geƶ-KK JNv߼Mt_ 9Ԛ&  R&_m(^ę!ҥI٥YB'l]蔯A:W473.Iҥ6^p<_`:?f9T<x9%*€y'"ݻij5\f떘c[)$X),qe˃M7))6T]l&jpSsspU{߿*vK,x NnIMl"O⻫c )#eȷ"WNf% 94jAIzX[0m d^QG×M[qie A!ĩ.,em zs f:U8yiSdBnQEbʖM7]W:fvRq=-$%*<dx%MK92V5 :|—us}N9&}J"O-G+( 9E){{.NL-u&e]*qiH$+oۃ4^5Oe'@Ϗ%V^RX~ "W_Թƥ:ꜼQY7b xm\Sm+PgT9`iP8 eL[CYpPoIɵx5=Fj̗ u ~a*7.MO6 x7cu8uίJ%=@LK%Xbҥ`['9j=(S_Qxi +$EU??i %N/gZP7FmcڀĻV:f"ťJЎ!eJ9#b#bڙ|ij5h"flYLSjR-6Ȫ6|2jrS*&rRH6 6 ߋE~jj7ei;[JR&'#?LSzӭ7Vj~a$_+]hdǔwnBSa~a[D2co/&VPf_Q Zc"#J,Jj~LQe4MHFչM2!JA`n1:VtV~^a MJV IOarmjּE- |C`Lu6+1<#Z\{, R&7؛[OLĜ̵b"gPHgfԠȫnYڤ)W{1xBSUh4SP [ ̲܃u{OztT Ki/n N >TӇ=Idfi]鮇Mč>fkqO8W)&61lP Έuf[H%_Ƴ>㒳4J[q&K]*U͸=#]T֋ԚHL2ڛ yW~C[a5fѤ'*MJ(\jgK\I* X )Xxվ6Z:]S d}vȍURKV6%K 5[d&s{TMtɾ 6n8ͰJ֘P)ԟZ]){I6$h lq혱R5gA*KɔSWPbU6#NI*JV]DD]hI%YPUT'RRI[#1ҸsݗZ:KA๩WG" ;m)s}ᕡ``3Di̲MU>NfaK4ɾ<(h}:unbk3(.vW,1p\^ Pc('o'^:S\zjq֒%FME=f*Sͪur%ii"v^\] vP#8(R_ EJiYkT˥^HJϰ?JS:>S 3UEo.Bpt'&/QR%[S}{ӈmd\PAml'M&X-UgcaE@s{H^z2 Fl8f*ZmҕeEn|.O'03R8NYG̦^:9'!#nܓv429i-kC6p=mTDCMtV–[i+ (qmzkޒOLtHMKiCk<šJGq #~5T9Q^:yTқϯ#Ħv=}gW^+"^ om#^ֽ(~~_-$u sM փ2Nb5+ը$fhX6駥X~pm 5eY\ޖ yI2]^M ߑj16?Nfz+oH=;I7.'kNJH'B4V,JK~e'iEZSB(i8u.OkCp<5 5}DV R-_6k+Qa}ҵ'WJ*8>3rW\BH \s{4nj54"}C6k)DX(8T6RP J1?$riWx ӼMi]UMwUd%{2)nXK$0m&+Waq+KJY}$|f[:6wE?HwN]7ZN(2:ͮ1 #26Ӫ\jJSN%/ yWmC*_;diK6xRFW;Qr&>\'ڭTHhv]4!\$rBn Mm$?v`U sly~k#C|DMNj.X)emR) -r؛a3_5>n, KSrR;wRb.- >. fbktζMLMkbD Om ;fڦR4i8' A87MU=V)O‰ʭ ݭ)ůhiI@aOPҕ#>ܥ |vt7<¸CREq>vUbu T6YǷ{ŗJRT"ZaS)W˭*B *D#]NU-"Ih~-^[eJ]3uM&-h`$3 Le _?s7Gnʝ`eIAM??"?ěR)ɩ8Ef]J{lvؕh>trKD6-RJϰ爙MyYUkHĴ|L盜֩Cm4Kh۷ncT^%PkԦ]0- QF_-iTY (1I:άLjM}+ID^"*g̵gQZ'WTV+Iz)b_Rj]$K9MH/3k:m=U^&hc,r|b0E3n;G{zUzƧu)JR|2m߷$ɤbreĒUaR}3hcjQԲݑ=)]7Dx%)e=!/}SҒ̰J152-!Q,Z*ahKS8o:*%-2j)R.sXȭ ljnOCԏ/EuNS$džB4>$No≪~3~/kv?::Zq)SA1yGӦԦP$fEJ̩n1?dX6ΚjjzԭQqI X+6 ͡7WP6V3cBSUHj>i))+I qnR>9Q=/QIJ҂ Gܜox h/fQK6򛀄A,o@Y{Xez^RI6lA f:5ܴk9H)e՟tWiNRVЃN] {{f{IUJdžRX̡Z-r}9IԺ5Q/>:`6U*6' o2Ԍh͔eGyoj/{zxt]'lϵֽLÔ5/T WS尅$$$e,Kd`tg:kPKsS9&ڼoTRCW*7HEtk.BO2ԉrs!$hZlߐ~#L> NꞭ *eoÂxjQ{ ":4薤BYJvDՍ) /&R~vQH_XR; ~9V$?Ul&(+)+T̵l)ݪbKz *$E{43K6c(Rkjq-jvҮ>T[h,4p'7-Q[WF% TEL#N#ͺ@?`~YkjtĴ&kKN8 Vu)g7L/A^OL4 3ٝHHSOii[ Jbqps=-Yw&eLTS+DF5!$s&GLCϴNpRXƣR)TT)8 /<'iʯ :k6<\TꊘfG8R %nXX ĴT(^꬗< l#u/`GG 6tu[[S9`J[ @;/ǯ@4nV]b`%&g[߰'w_I1cag3Pe^[$B{Žt&zԩIdA6SF\xz}͉u?(Uf%f-͈77&z;&XR7Q(”Yp Z.-#٬hL*q*<\S68eZO&& 3ADfS44o#k X'.G}>CgtQ)?줲_Q/=8@QC:^hLw*bFBo}^ rҕ}^J7KWi99Dp(Y"֏hK|G+1k,T=6öRM!)PNm͍K΅Uӌo.&%Jn=FS%8j"xFSQl%Tf]ZAI큏HoS5d%#5N\m1% t\K5V !珼R|IRd,@Msa[Bl.2UԹI8(ߓW7sz奔 T!XjZ330 ;~bS53t4Tʛi (UqU6-2h3ͬTx,O>R[;:/TBf,_^ʔ,Ţ>Mz~Yo3lZ8Gډܝ(yBSOM XSl$JVo4s~PJ j V8}0xErE&,R 6Nq@%(k>I'.mV0ƝM6p+\ *ރ=f=7.u4)m?YFejCmyHY:w@4۞#R:[gUϯΧt&etvm#v.Gv~rۅ-HVꪴR(aM( Uq{ACm?%wω '\,ja, ,m ݋b3tWTTƌm d$*0 &n8bŤ:!,h *SHHoo"ֵY77D2CԿuxi+o&m6՚Yd .Zw-A$y{\=׺}UJPL!:DAڒ6p66·uXͱSԴڜq_12*)SQ86"1M|V:Z QVWMO fۂuwnNORpVם[N~V!IKՓRIE>X ~#qĪ#@|gV6nu3-B9 hf~%Rf%?J鯂g̜9LBnV$um^Fs3:^%Q5ւ'6d(򍻧wS\HU|@~Bz8A('G=ִzg+AzԊKn$)?mD{"UPWVML+/en9Ik^cÜO^nr:0,{#=-Sz!MUʋSVî[u\ <[Ʊ=_:xum[Ou8RH [7>hQ:Pk:uj%ÒJ#3r6Fӯ:OP*ug`Zî c1l`jě6l{T 4R~jz=E ,lm jI"ZGnDji GCa fBfZIYw ϔ*Xi^W5+IrU2l*JmSd(^w Z)%8hi W`CiS9q(%e/ZkP05oN}*!s!XPl4q|cV ~d.P֡T]O$?R̀ PyVۅl-%@`Qӝqiig;W.J?2-U:P-~}q--ҊH^#q"a$#,[>le%b߽;zk0Ji WZ4TT($G".ڈqd-ohjkOJBZ! APHQW$cݏxNvr3G_Pٸ}?> ϐq%Oh=o4 =l-L:?l<*5b>)M7`;˒H( 7>a 4!֍xxPZn;I *cglo$@z@#  B"Fy=(|zGBސgτBSu^AJEE;؜By6J @ Dpyh N RJ2r;A ct؋cow;][0*Q!vH.ۑ6*JڵGbLe,!A ջA;d.6w<1 H/rH>)؊ @)@h8(idi3 x?u8} (⇇ak(f0O 00CoCp&Hp60U)  l۶H8(Jm nlKi6RK~86Eԛ`ਐv;_0VGCq0bP(_ "RawVTh'q7r6Y. P|G*,0p&ZN*j Aڝn㮠f u(U5URr]Jou" "1͡!roF[B J,$ HiA'­~UXz^ $`<BJB.mBKvHU8 'n&7@tBJMOp!F޲9;(e#mr hk7"xEjNsDRXJU3Xq \IJ>h (xYBB[VTKA)6W膒)pK3(D3Xqhrn0 0>8_I*B˘¡FӻbX,{퉲rS]~]L:ݛ%#")ަ֡m3ij6I?HeEz71(4Uԑm19J%a I׼S異)-\o+Sl%U"'ω-4=RZqƥm9!H~z4۽)R}:;P̏0K0A4y)jaM(-$pq>nqXoRA$XX\o|tڂQ>zUe53պEBi27Piqĕ+-옺A(Xv32BZCUjj]ԗ.J/`EMS&OQ=T$BqSTrRPlϿ1=@GXY RtP4M*)i Sͧ (6Eu`1s&*ln zѧL#LVkiOJMz\ MqGyn{b6=chum"4Fr: QзZ{iR!I 7dy2#?NWhUJL%Mplڤ_6ܡ~ &=gCOj$s`]E.MI+91#0jljJ䄃@2f TPAs:OSgT( IN)5?Xre HITJ*{жsWզMMEuiqL 4-%AXX_RIMP+SuV\2VX֝Ų/eJ䫴2fSIRdK .--Cܩ;=B8BeYE~}mܹn\bJkcEjT۷aS-"̺9Zv]jU-鄏[M!{x<&TOQ1T4Y)ғgLԲ*5"ŠVݚSxltƧ]>;_M+sɟ32\r !6}#Nu*)i}*K;Ā, 67hkXݒ{SmI!L0 <I-oh8!)M159-6wv_mtpٵɱ)P2ۙrm<&%O%KJ,[Ub0mȿ1?kNOsCZPZnSRYݰ%,pM ڹu3_ĂݖsUsy&\~ur2YS&:g&jZCLϰR—EqN!D&9kRW[H+--:Pm [q8[}bɠ:KFvPVBem$pnDXg/VuUA_R-0J@ "^@ZF˞"ߊn} R=V:%,&Idw&R?yA+i"yNk UB$Q6b m J rn-цe%j &i3 9-0jdOl̿JB R o͆~B0 "a$|$[M<9{Zx:FR=OW=N,ssRfw6/JrO{ڏímTԬ&eJx'6P7_͞HtMju4`M _0+Z"Ѧ-aIL+Czm7Aim[$` *\s3UK[P)0(q o96$Cd*nVoVRr}K[U`!pe*(]clfRz2W ␲PY&F۴KRW7JE*d2B…RI [S97ӤhqvFTn|ES +BfhzDW>*FaƤԒ|@5eI 9)OӳK/(䴜S^]ei%K I'wh$\ai%2Ue%Є'q$q7kKuR}U%o$x{HJT؁{mUy9tvy,;ҒlC$M쑂1Bʤβ}k~iak"$q5]M3-LԘsc1,M%B fQZצ:WzU- u7D)nh-V)r  c3qZ9FKTȖieH;T7N"nKkˁ%@SԳLjj[˕-ߞmlU\ a:kBMT4# MA I72 [Rk,ؚ)* cn!qdtŶ'%22Zkao t_i( Z부% _ڇ¨3;ϛxJnv*`z U޵%B]v:<9Ǖlොm&@Gyv+M'u?Įy}u%Y-RZHA$e8ωKZI$gPcW.zmAI-b}ONiJrv_xސUp A:ҿ]jccq +#̌NnRx5ʂ?y:7SwnVd 뻦&vJ/'?K sM( JUǵ5YދT)4QVe (،s+⣧UCJcQe8ZUMt4ClKե]AO0ub{X`bzׯjS-ue$_Q̕1 ܕ-aF#8 Zl3=f]Aġ (2{}01\|ԙ[ )%_C63bTkO\o"/v&F.mB֩VU*SvZhzF1:Ri$L<m#~Q [U'483!!{ԓxJB#N`0\Ik aTҮ6ߔ(yY %E4PCt$X]-hx]bt"yT;ؒH؉w[M[CP@|9x- ? * ZkjSO grR ɵP!=n 5]vU%"aiמuEl {qGԵĨ]S_Qc7kb.4oY ħOUTRХ1|rETi@Pmfr{NUZ:͟@J -s8h3 Kuo7'F)7վ]slg ,pUlEKu{73Re-.6eLoq^!2d (0cŒKUK^im_S/?åealH a${!j-V˰Q} O.1l9m?ԝ-2SNa(Z7򯲭6p\[XYk"i;Gi,;83P_kъ2΄|8IMna JKl<@ X_ TQQ3G\n/b'*^*_+u1ufTid)s2gMsC6:aT2Qʔd#͢0/;2;;ѴJĭյLRmZ ,/‡4JɦiIdIkߞu\h2HEA {zh2d(ғ{֕/xճ74̳7-,e&^)>B^ʲS@+*ԕ{aSV]oHi ;XꬰKj J!E[Iަ!(K4mB]waIRM*#n IE):_NN]CWh9\خ4FJU9zgjf_Yܞ 5Jj4mRӡo)\8ùNuNf%(˪_'i ('yN7mm[07,'164j]ZY-Q&شɧ;;'_≩ع(@G]zJnQCp"`v]w\N|jTYd۲-1(r[>xc̀<'U٧~Ŧ$E#P =VK.nYaN6rXp Aj,*RULJSJv4-$Ei >8Ukies;LGK  N6>vtF]`)=PLUe,;a6GӉ})NBCɭl2^-B8 3?0jY@6ĺPl1%Wy20zzϞ߆M Ij[г.<72,k"vusRtR|ۊE1ţ jy\- )D,.W~1B״_)fגKBCCRqD0[y]JGk/H6*R֋Mi\n6UڵnqUI)VW3Xm2Qk>͐9Eu4H594֜UeTS;fẒ|ӫ)S TfKM&.mA"ؽ3i^֓Cn;N0á$C%CSB{hgS+4(Rޮr -;>|=aoyMZ9O,H6ӔB YJ{dFT=3)uqp#jmMpm6ĥuUg[WJ@ b7L|2fQg]KɩQl̲)#$k\dcm>Q2b)[nz;]3^dJf_ae'ݣǴfZᮮiiePC`t4jr )XqƮu%(RIH!BAk㆖%j6!%LJNr-{bŹ^:f:5FOM4TYSl''h =9YPl&suyymI. 6fKԧdtRB`6׊ 7Ŧ4:]ec~!.J+%cmvv;V6V_O%4M}2 ePH7>V'"N .+qg9'qK]ε59g @ Iw ? "!\N.jMďtJҬ.wO=s?#Ssԡ^jɪg5OQ: ȗJ76[d\}E_K!DNu..ӍE%p3:D|S*}z6@|i9}JC…>fjR=-TPu#ri P)cP F榤W3ץT2 $ym$qɋN5N<'iL͹V/ٹiamVHBn>7L%]1)%%[$%ԅz<@˙Q88xf4](kYw~ӍUBbX ^zԽV[501I yNMUb3Ve 7z+K]EW8=.Jᓮu^cC.@v˸<&M>q[>D`H?4˸KUzs,C6))JI;È.-pS yW%@}׸9"֌Shj9?v7*9=esAuz*3pRҭ< [6ń bs c4d;z]?ʽ>T~*\!9C"vkutnZSܧ?fM &8vu6ЛvIЛlڐ/wS+sMz3d3, $s0 c3-=|Wu_MTeQŊG@fu25<̼R>^af )M(}7}Rmddd(8u#7HeG&cG*74j*}BX-DR5wKT[ךj99/4K*. mKš>k x֟湚)yvJI Z( vaɩq]j/6~5@ngъ'Uks!TEʞyN>RGo69zujj?ѭL*[e9R 6^9W}߻yIϮ *)Rd$%J}G>pH*ZYNMUi4+- d!{nr!Ŧ}iY !58$>r6pq8Iɏ J>Sp)۪&~E!gѩψΏS.\nS0T_ hh-a0;R  pR;CV<ʐ*A21 'n#'$ߗ7irmXűMdcH"}`PR賚D>;% x Z>4}6;]<&2G#ceuCL̎RFMx.Iǟ)tMuFEkr}_YNGyF!ĺbWCt֑n+O.eQ"))lgE zߤ^,RŰ@E89: lb|Ffe7ҏ*ITh-J٩8uJ{Q&䏸BM}=;eCv%CL6یɼ`#%?U5bPgM',S\(wBqy Ftw쿴!V`IѮ:5RR*K%)r Lغ,{d'89GwOO 7 B]JA@)D@R9iIOf)0R1F4ǜaĤnۑ KLUVn] 619It\K(P,.=O:mT9]eH]^t˶\I3xJ g&)̽p@*6ILH͒-&g[fZV$(7 )ZHܑ|E73ChΘznN35Qy+Z[RM|&Pi&yoex7t@nibYɩ6>N-J$\v"ILN4UȂ sȗo]%"T-@.Fզ!0 lX߼WMBE֐-y(R@"l(#q 絍 }SuBX0]l{A*3 uBN,c- )a)؝ Ջd("DŅL);&F *H1}#*$BrBvoxSi0) R>ցP j &ް "dwRHal6#@;';yJRn#*fVM7kP0X{768VN( G$SBn<%@e\XHm }]"8qJE|0ܔ}"H#vYOkf"TU؃A$И!u2[QIKBRMŊlG# $_1\LX@,nWИ6Pn}TS Z+T.i$;Uu\ #QEy758tLjUL 0*q opmA0_[%i/ p=7J'6`"&+0vR.W> Vk¤!FxaD[U* o!m أyTңp3uBVS;h0K|* h}6X;6bDg) P5%)ƜXRcq]2]9sn lpXvɷ1˜C^8_>3Whk"ENVi^]զ$!o XIu]jm<ʕĝֲny<O뾗]&GO9FTϐYN;\`~:1%,w_,jyS* ~ĸ Mnq iRm-Kii(@=2uĩH mlxB< jcEcCD-vn͙-6 ;r=ӊxݍ6緯0"Z+@w%ԩ(7 x2&e.*feKV RԤ<^К lSV޽ps)0J!`L3mD~b]+9;˝N*TZJ{@V1Q(٫Sivˉ q[K4rEnPr+ RQ0%"Vx g*q=mZZM=/>i{MoۥܛㄛDƣ~Frz}H ok-%yR06 1t;B)fzi:.vs$t\U^am%@4Q ^4f᫴VKRUd+_MNVHM:}*mӅ!JB`r2յu:Bq2]dH @J1tM ~ИTA\MsokHU$)7t-\ЅqS[H4wd/*̆l ?qp574;CJ˷8Je[+n U8ZC}KȲV;%wsnq h efJMe~3(@ 1C _$̪=ZJ9y)eM:ɻmJ9ā{&gIϿ!/nYɛy-) `ϱVfqT̷BP7܂'7Ĩ̳,SO, =` Z]D8jK%~ONӿId.BnWI;*Y=?ԗWP/:Lm) ;JQ{66Ԕsj[I7H- /-T-EFXNӐO]53{EkG)jJJz}Vm< h5unA:Yv*x3UIFT6 -kXcFi7Q|xgA9!@4/5F~AŨ)p;,,K'"ͯh|Bby{]cvyc]6*vX&iJ^ ;U"و~/1&΀kVUK3 -d'$[3)- 7KH"T9\,5.1CN8{>L`-}~FMF4SeU'BPPBT!>*lGQ_W]%~-J+KA#!>^6w}ZK6GOA6:ی#+PmyURa(+Z6P&ױ |G(rgMQn$7 *R)ZMͻ$:M˵p}XYKZZıQ"ZIUk7bR~ t=<2QVft08lR~۳as]NԴR-XqЧP늒Cm=Ӵ>awZeLi_YF*+CBI*u=|x^ԿZ2M2rwV-ka ʣ+o<=eXiM9WvkifeK5[;/'6ۄkjmaM[NtZR)ʹDhH?-wD-_itャQk^Y*Qj>G%ۋ^W^!2+t%En93Xx%JINlMZW}um>aMKHeH粒A `$&?Ť7:zq*rBjR}IGlP0aǔ dk )435)R\\\TȵȊ6 Lqjvet.jR;*䑻؃l6^9%dh:r)v~h[''*Ż#T扣O6qy viFr'y yi /$Ͳu9 O*Rؔca1i鎄kjsꣁ3%s!ܱ7*Xtd iw_ 괅gN]^uV63k[aZKLֺq*rI>u/h/tRj ȉ/˶*®Ep;EzgϣsV |C V'qƧS$}Mn%}>N˰EU{-q{I$\lėK5diK8qIEKy X Ik\,~ӴFɤ)M[hTҰ Fsao^:?.d*Z`CSiM2{ lH# Ӛ/uuM'-JTu{)d[}hsUEf*4‚fLFǕҕs//܍ 96˵KFylK:f4$* )ڬz/zZyP hӖ^%nXv'ɷh)=O['X2MkB-(l9"h_}w<ԥ v, i@!*T [IԝKѵmR/GtYrRʴB@CSk$~A'`8[=&F&B̦hg˨"؈ynjծɹ9TIԐ$y;x+=9fqL >enh}^[M>[.[aX\|%jjjizZ8u)MyI!xO׿"B&*Һeʠ\>y.;jɩk-elMRo6[0\HquM41T@]ٗJ˕pvIcap*)ⳚZj7E(ΫiqR雛 ^ͭ8U:ZkƩk vN,7d oHqr}S%i&L5V4Sw5QfJO}k5I:SK zrOs:Sn ..|>5y3 gHG>wNKm¤la| 5⡺ 7מը`jG*TҨ)w-$zvU>,Mk&' QFvaa3Ϙ۱ϼlտާihzcS g  `O bb5&)-T*k Z XdiJؽ2jj7&&e3I~R*\\uVR1c~4jiIrѭ6giErԱcφ,s{g;sNx9UfI(KoUgpb~GҖ]c B3ںEb98gvߗu(m mA$A;iuOUCH eSJ])Phl ۵zRnlZR|fA /Pd}-;A-=.>tolC#z]!Qm2TG?--Ӑ'gk u7ڡ-F$:<|A?Y#S'CR,> Y,0TzQdSۛ 7d[s--ڙԸ{T=%0SYăeE'4H ^~kt/|S˕;+)o)ȼ|˨4P}Tz( [)ͻzg.RQ@+0vT%7U$$ 9?̀o#`sBT;R=mNH6hC*U?j}DMUU*iee~#0za˚5\"ĶԣR糖s`O?\hV%ڪ6ǂ,U)7g6õm&.-y䩽r!#,I oܬ{ݎ"}izjlLTRm¦S`ZƸU!]޴E稔ඬ~9ʼn0ė-iWu?,Եk9k[ERR"٪*/HmԲ#=lߘ|E_Lq%X͆X>1>"TfU;n%˟5߃najV[JlT@A$TVs`"~t"eJ痝>KL-+Cj;u.JNdCKiE$nO=IUZI*&eVyhkJ%%>JrHy`|<śS 1/|9O|PJ)1hB蚛iַv]ĄhQΌΪ]9sKRr%9e@X|sB7eU4>&[B|>O6uI'9 eI0ϚCƞb^6~ai : Y8N7ŽEV(єEǭG䵏MSSESdP䪊%&@!;X%V7cuXtrYIUu^rÂ/ICv/ϳ&'e:w4]R@WTz`(c%-B6ÕWV7P>*Kjn| JrQ¿*Re*N{#MӴITeM `͡>L|<~$:H?Nc_I/XXVmvgA_T9U_<')[#ԊnS+QM>t&ktz"{HyySWni:|>R4,TmD~\_3TK#̓#؈JD34vPВR.,<}#ϴ+]CHLW:?7" Xz 6+ OE~w|Fj:J6S23D zFGuYbAU{R\fH$b]%VEOEQ=)J>?MJCNlI)ȱiRBLJm AflBzLJOqIjp\JH7JTrN6#W鴬CI[-KM*b_q$ ˅m|BOgE)uIv IkUѾӋ5Ɲ8 $RA;J&ध0a5.Ɵ/1.0sH*QȾ3|SU$2i0)<_'}=<锹j aIqH5S!FV* ZczHdcc]UǑ* $8 cA$/.Λ Ҳ|mV &tOt-4G7V 6Q{cF#47L[irUISzLS5t{7nT=)z X~& !^=%մv]mmkf tTmQMz=0_RuxmIl \Ot^Mm)P+q_[d>T4A\X`MHL6DW"=4:%Cq;J=`[E0r,;/-I :RuVp:GkGG&FxwwTnvLSuZRM4'\H)Zʐ!$rbK,FtHϱ-Sye6z\CWfrqmUJơ/5SSn4 L)~oSb -i$]p>PaI>4B( D;~5"5,OUU7%HU'{jJÓglR$_<']|,k7VA=?hfnQ*GᓗNE`U nsCF\OB̅mڻ(ُO, 4͗LRI! @BnK6íCU3_vO-$rv6Lƃ>LjuuISy Su'f6QMƔ~x0H@穚 rI`QNT%C<A{(I״lHM)ȵ{G&3#&PdzXRN yúX*bm7]2787R;AXM"`&+h*H?U=q@̴ڂ{86!)ʉ;sD IN&!)PnO=6ľB# /~ mLCc#Rn-W4Ǽ'ϴ$߈P6Wmm%o+@r{XU`B(IP,1qԪF''oBg9T Rx!!rH0*K6( oa ѹ Xͨ!%@y`إl#e+! 9 SFZTONm P7a~-HNەg*jl^ްᘘ 1( P'mí$y= ]?(]EҮ;Z+޻)_{B x$x7"i6͋E ČQ&Btօi G7HY RRT1hM bo|Kܠ,P8QgXJ0>Ke$+7M} ]Y c"E7Q6ЪVڛݼ+bKK8x&T8P%b9V *Hܞ𕿵&')P+ۘ Ud*FސeV`SewJm@.Β;`G))@+JxT*l`n<;Tl}`X *M%*O mM0߽[7\pV -*!GST& {nz90\۾"qAl|Ņ.b@_/޹o/mRTmn/q7JOD:EÆ~7"̓ju ud)JɰDJ^>UW/`&\Jdmf! tt:RJˊ|Q>T$b'yiIGLBiU qa |E^š_"<æF=b{ mC0ʒy"ǦztWu)-?Oa/.n3PUva=EuCӫZ^̢wZF2 NN% ʼ; |Q ?%Tir&ܫcJNo-Ląv[?j0Ld@?Ii.uMc)$cbʏ}L[%~.")4qJӮjv2ڊE*RuebfaV-LD5ٹW>g Qg$Gt㿮=?=>ɩRٗUo/k]y9ܴ'|,: yW6*y ?XvmhYH OfP!%iD}Ln,GsȪVu 6!.=Sb?Ru4ٶjc-h3MNQPC6P.HX-8˫ ''nbY8׊ O|@U)ie$LQg5'Ym2 ڰҵmK O0zNianYɤȹP'mA%ʼ"m> ML&~pHOH$s{MDo=,iud) >E@ ^U p}x͵OWvg]WY**~iN禩ZB7ZI7$.lZU73+T:BU4 !((q Q]&MO']2}Ͳ7>5=};}Du~ܫt kIɴ-??ͤ'̅LBhj ekyӺTy,5)`R7Az_[T=m9eQQЕԥ3E ݒ_6ۍh[In+LKζ&}>o)ڴS؟B8?Mt^qjl,@aD}fT2itMI'̤ۘMnƜT4ƦTu'dTmIX;M}oM&) FTH3HvϊZK -ń!a(mzr/aF\ۅ}y?l2,;[)DyA|knm3krܕ$hS*4?! *[+6 v~ZfKuN!KINIȎSI)RML’;9Rt^zuZb*xM[Voakb-) u"ۋM?$c;۲U#. S&66P iT AJҍʬz{^hgdd 6Q8*7JƑz%W"+^p Pj=I--!U5ʹ>P7 ,LR@˱0NB.鹵ImB%Ó+@PPu\JBMߑaFdtFE2Q%)%RPa#)8,jtYr%:$ {#|f ()ۅ]j hڋIӦ[(? ' ղrNɸJD6Q<"RJvmlPb!>H*A 9#Wr'Qs,)Q(eGNRHTiɖC -aܭ2i6'"؆k\܄%XtZ$=9HNsӰ#7E:؞*‡MY*HRO0'Nkt9V;;WdϗuI!fz 6C(RJE/̽_LRSj]Ҵy77GV?o|s|Cƛs$ZSJA 7͈IOQoSDļEEGatM:=[.RWu˲R<`Mp86+Uӗk]&l:gDun l_s?hǮmNwAx(d5U"y. .Njs~,}b(4$*@jEg8*V`sߘOs eޗSf *oRio)lv d:!t9/kZ1 ih) _ m_( .dTΦz.˲dp.?z]Jr}N->B I) uxQT-ԋgB]E7.Q+UemEJ;V{;z#FՒ؏bӚUsOi2P *beT^*k zƗ!4NJlqűs7:u)|($w8[U*t$d0VؽnMmn .EbX QDg5z^jMfQ i @=D~/WQo۩HmU|\ǗZ^rKܡV<ݮYe(7>Eb,uNN!fY% jfgKI䷴EY3HS$KZ]Xy%xIm&<lo#1iR?+ΟLR}%&4.<)<& V&^ %u)46P^Jm{5w4˒Ԥ12gy"# mP5η(J疩Cz(JGb E=%F3I~eF q֩-:Za^ l8l 7%"ٵ@%_)_="v8Py ɽUڧJ5Z32 &P.bk`i"ko#'uLSuj>-M8[|m;[ȰAP IsNL.P5SԴ8v\,TDWO~(zMƍt&}5UU6^AqHP?G"OX34ʋUV%/|u)[p,olCy}_ U.PY)NS-.b94l$aj6Bw_Tkb/9=8 ͳJFJUG n4fM:-$ ȵ%)E{EwTYH鲥)mu;Ғ<@ hA;V('Fyơm.]!ECQ2Jx%- KwVKJq{2Hj )$oxS/V: %uJ9$mkmVOjZKKʭ )>Lgͻx?+6D_(]I (Hc]ՉYim%\'ťy W /ZWEUԵ j:aDO@͡I5$KE Xmu*+'%:ѭL>wԋfV$\ߛ^Z'UgȟX\7ӓ(5nS*rY {iIpco\Ss=M$d)uI~a,^J Gqq /Og*3:"vT-i@V@t6WeKS)3|xwg P>Í$s1 Άb53t*vlAJ-!f1*u(K3a.1* $NxWCV?3(|iR'ʢБsRR暙zFq,vIo{w3z[OȧÜm YMp.F_aϓIOtK 4I-l{c1UzJ`bsqb{#d>3-z'OKa2iVou {mԾ*˓&]&1ůlE|OI&uL0ÙvkG2qf֡A,1Y)YS-}@x85=/譴dPN.l Qu4S1*奈J&>\kֆŋLX6SA 2d6BXBmyǬ8_T)S W˄oiHi)< w ؆Z}*^[q*]cY[ 6x-yHsLMaSjoO6M9&,ω}Ljҵ;fgBR$pTPP{q}\QHf.9.׉1Oe3T.EP)$Й4ǩJs^jWj'yIbxNdrro~l;**GpL.Xf=5 ֿ0>dP|KbXzRZi*tPK l 8ԺJ,曬 J7K ?iTU):UBck k,|9jk"L̲06$(3]'v̴]lTKn*Y {`)BzDH79΄]}hH|*Qwj쀛R[ęEd~>= U5'̽54O,EwX@k}#К;5 g)zƹXRǖg'h H< "\zNm[#q!XN"[r+6>67H 7V $:Ntƨ$,ʒx' ;ǯ/!gNkJmMX윻)_WNmwMTaUMϔU_)#6 xB3oUw7GD%yt$d8$}EySIM!HL6d<7"zKSFgdRw89tR@ԋ1_2:"].Za ̥8mn3ů@az?'`Ъ}Q*aRf49E8QR$@ثKmI̠8&[Otjy爈cRuF6( t sfdLnI.V;EDu41Y+/O[)*UMsE7Bs` ٰcύX`87򕪯NMRNnji,-`lPos:ҭ\''CIP^g{ֿZ!?\1GRFr@ Bk6uύĢM{LTa'9@i "[TL9 7hV.Ӎ<&[}/26\m;ɹب[6?3jԢ,)܀RMOn[|zҴuGO)}2uJ8{v&ѽkAhUUgIv@̂lM8?YJ٠I6e_/T]R eM)}MgO3 )* -xXr?ѨgdI49Z-;$)\} 1֮ONJ4)q ZX^>IQJV2jiGjl@o*DkUr 6fJ#*ڞ$gH&BL8})5#NiʌV̢pكOy'mJX|FmAaH\Tw eORg(M.(-Q$]N̡3:A 8HEۏXҜA%MgPid8IHUvGӰ8G.uzAp|mRM$s 5yтG zω7 3 d[ıRTշ'qFq8nI1=f `͹'jRw e  n}`EСb d~!*"\F ; AM}j*p_kfEad;nEᕊP(YiJZuh?R% #@[ϘVFiY(˨W]^ѹ.z!*AԹT MB˭Ñy7_:?sgћpZ1ZJ,4M5 R-O2f%A !#Li1$\b 6.N>u]H)aegc{zŚ'&<fsh=)dᙛOJI G)o:l]I7f`C5)zr2{L*N;ĄXMBA dgWtP$ݮ)$=~Pb&zwNx:R)Rᩲ./s~HS4.OO&Ye8$=)(N6KPw]ī /31tW?LVBZ)EQs{H9NHtҹIyIPJnި[6ͻWҩZ6Ժnu%N.-Ҥ%7P$#j>ҁTO1ĕ~Rd-!{6~1ZHmJ@1Pnam o#7N~:[jbU32w&ۜH[FUx"<9ضj싎jBd_l$ w<c$T͏-9|V^.8x"F8@'ޑ.y^pk.Ȳ) #l~XdKM$  TneRٲOH)"*hALpvR /ngCͶ I&VۊZ]2Tl̫F0y`Y7sJqV@B6SCi${4V$` 8o ?[vRIݹ@+0ﺅ)!;B$!d`v76'E- %7 T,ZJB,=Tr;PX@9RRmmc[up>ԐIaB`bjieW )؈Ph=F܄ 2 XA"=e[neFMwuڰ-Mɢ۞F vtu$? lYXkqKZ1KY`*QۼljU۾!O!98)yH6< ? t›J(P*y @)l7~T ^n6olߴ(7Ze{mx0 ~pas2 8HX$b;/e S2[?K'̒mn(7hw: 8F-`䰻Y{mZHWj;ϡ8@КemJP%D+6LSY$Q*.`KK) H E$zBl|FaHCo{[0iR?#"@pܬCaU&U-IA& HF9>ᤪ_p1~*Hp.㰴,K oJxoxH=  hQ΃}!Fe,VP.׷] N?^ 7. *"efIl^nc)\dN!gEǚn@7&4R'TԸAWn=R1m% &0 |CU,9iԒ$b7JvrmR`':TMV/1S!yy7Jn  ˻$iu0P)@Ԑ8w,:rUhTly)âڿV9.8TBU`7[qx] `UֺYK7ZZSm)%ߜ%7N876Zg:P$8mGtO+i 9JMJ"J[O;K[Ps?=P)Qtv K\AD7(L4Rfc9].3Qab!LV^Q`jѵ»k&7SJm/T D0BQf[~mɐ#Uu:>j0܋{>HX1?~z>vS,i myBp67\Z*k>&j|jK>]yml0}z;yZ.[lDIZ7r1mf&ufj4j]qNU7OMFarn98ԭJҪT_\*U]E: %)m,|bNuơUS26l*EN;IWl-''4z R78&&_BbQMlI. #n2B|E] P%'v}Oi5ir 0>UH"EܙN4*zV+\l;xŒHVe!Jz /E'!%br;p"9Bq:9nVK]Qdm$^rao„n'01GQ[6Lr=n,o9â$jJ%YR``k8ge2/s$$)ENCU&tSny*9kQ94Pwq%ccsECnA T|i$[ȩtZs?HGN9RRPo %’v$Yv{f!A˟p4| *Qs4O<[a:p90xJ$*8YmvcMIf^`T†9o-2o+)mql3*K6Ce l/ꬮ@B0EɿJGƻ[[ARZv\Fs|SO7QΰRz$RRJBy7XG\%K.a躒Fu]'i=';*sr`b6>lq|gⅢk|2j٦@*GPI( .?H4Vq[.%_KMVIH9Gais XRP)*nw@f zI tWteMi*HEZIػ{X^К bSbgO0%O@ )Y;sRSDt!ZF}PZIx#?ss+kEsj6>$D ؝(߄9zi[(RṘ-L<`k.".2hX2,u G,̻tdTd-$6=Lh?iےnTP7)TR4$4A< eA9Y^Qiqi~t+̥aGk^5ogGZ P%CA'M.~F)ZzBGtlޟ;3EQ,)K)Woq:Ebt[-U:C` u@ %G67yLt?G&,)IuiiRmMiU/q վ D[Sy.IZ@ 6 vg8Gѕ9rװs)CrnEհfRsRpp8TS};q$u^ :?`i~ђ{ qhZR˝}Zrܤ-ZE7 VM3nf Bl(('&RU&).Fd񸖜ZmdECT)Jl& KԼ;Z5йZ~3ڒ:Oj(-qt<hWfSQH=i;ҽۓ:N+gcU[n܏KQTtקS=t]:mn0gdJ`?3Oٍꪽ5ꪵ&Ԥ6:]_|Y9V:#IjmCWd74-).*.6}}u%l?hW5mQΤ#asWCi4Mm1A*)$vטO/U to;,Lߙ4! Cvh hПi)g&3Eɒ^3ԧ˸7wD?WteSfMJ`,y¥ қack`+NyF8ryY /rBԇm%e'l+6Pu+>#ʽe >)։v0iB7jϋnWvjCtKEdkJ_BMx\~u-,@bEUbVY-U`孎}'6L+<~:P֕a[EpL:lB}P:B1C4lc=^{вfru-ģaI$q6^3-UNZRu?.ě K-- ⤛ʋnmUQG熺tmg?7'<3AXJH<Ѻ+J[&'C)dJI1nZV%uuzfyRBD XXm{~gc>jJWO>e2 \sĞ X}>f\S) FJ9\cL2*e©ZtSo6҄ēl%U5Y%Y bqٟvXP{Amf$kO˷&ʑ~"}RΧN-`Twr\]iȿ((vu]h`{JnxI$uodX4*%530P) I-cDZ\ cKLqKKjIB0QN1|]3S֕9*RjUQSt'[ScH7 -4'<-M7u-]qŸE𰕋9|>>{+eٽ?R`6- >V!Zө4 TO:l>H3]WҧiRͶIBZ^ 7 Hk}7 ^`M RHKs|by|&eXfٛq+@9{%C)N\ƪVBR41 #9B}5/O'OlJm2(XFviOؙ֥ԍt?,t)] s2z^y֣[?-2g,4޼1%Qȟ TvlhCEj sb:wbujBWZBG9d[,:V~q/, qxAXr GzwK~QA'B2w$rMƨۅJKRS Li vgt^EBnU ZVI1_3J0mj(&77ǁƞTe@$̳m-mnx-B1N]2A"U7Yi3:M~-2va# OUO'ΫMqud-zE-ǮF#F|?.ļf !Xx8= Ť鴩t.vN0sckS>,e?9Ue%&nS6F-ғȔo/}"v&fK 8Q"鹿S@:I9TTt$#sEV  h޼uS}|9H*[V7>kjUQtzXTIm3L@#\M}RoCjDFomLmZ2 "ENPmaͦ~^};}]qs4ɪi-PRY z&*U-G&شTʪuJu)qǯG>tgIj>:9ޓӈ\ !C_`1khOU\2JڔwO?x-2(iZΙqҟ RbBTOgzBOhGcUQp窳湗K-_~>Cj4x(oS%ZoPɚN% |eІо!JXi VK *[IO&ٹhQ騿+*'ƠrUڎw`%N29ge*zoA hUKAj2tI&ᵬlZw1_=5y-]AJm KY)y<{qX@s"´€H3ridʑkcEL|%>~&2rohRR52*Y2<?BҮ0F@1jz319/Afv 8P`d.>l,Ğ&O3k]*aN\uW ÚON4f442a!9[ȏAEKUɴ$$ Fvfsc5jJLnJjR w_n8h<T=R3:$_Vz[NwDL-~#_>fUt)/n($X^ɴXWh4$DڕeMEۿ믄ƪ3?N%aTY $ޡf҅|m^TF6>5}dE>27(4Td5Q|n頖A I"bծJ.[NjW&߈K2)u)jP =LOޔu9ꃕziBso1_?8ɵK%6'&jғo$XMǩ(Z0kJ5vՊWd]qY5b¬c1L:/5G1X֓3IgouV | F/N>KsUi<Ӭ!䛓vYs5C(330Vf S`T-k T~\:`V[L]yDtMsZvP $e~ys 9 \'zY”OaGq{z=^kʛ}*4~^A *HN81:ÆLSJ]B/ ؘ[ }XMVjfIHSej^Oq&&ac5ս'Tv]%^|a)"pUg)Gʥ,$im)[R:Rq(88 Jtcē ,:Gh鶗HڒD^Jfije@xj qk3]K+Xu榝SJ7$$dbD2IJe$t HPj)uy9a46Zpۼ>LJX9Sf gs[j '#e`lcHT?.^Z@+Nabb,n#Gr`)YKd); 4ĿXq_:u Rjst]b"J{Jv0Zm$lJ7Y݁bjӝ/zm%Q3nveRdpқ8gI=S#5LQrpVNVA<}#<}-iJvn|'(vt&6,3(T^RqW7v[#+ ǐk'1/S*ZYEe!Lsd4SL(8$qc!e*#qtLո.Q@nGBpIA0/ƻShp=@ U`v8G&TĂx {mPB{j2ձT7*`)>A<,M% OQ;HAt¹6_X4\@Qb;SnN› p \!e )HB.$R&a ;{G(>l!j?_73 `JV=IZJlZ0rXbt!$@BXrpm,I V˙y0. hд-[Tq|G)+A]#C&֎S{l6~ɂ8Fdx-:l .V 9l*WHT cqML-'׼qQ*pYRlR8'^I*A'HCrfB331Xq x%f}D -L<ʜSj@9f%J2-Ȁ |g@752.?ʚ4<%PI6?u ;Hߑ uW" aBCkQG$N ~J6T"*@BHqȃKG8)(s.#qaLRVp%b *+IhCDuK =MU3!6Z[2 aaI*I zGz+ZZHnW.@Hۄ7!ҕzLRDRͭ5 %K vVe2%'P1V]=Θue na\ۋ︗ W{~Nc BVAPV[Jʈ'#$\yMյ« niQt=@mLm9G1 'dv~xׄ`}ϬI!,nFq|ߤr DFX)b*g_-`==`V 3*[ Kiq(BTvC5TDBm qJlBM;OkdI$*7OXS(˕-@$'bЩqIiJ*rg#S2Xy ;\)Qڥ(X)IHJFd}ғcpma)ڔk >ZJ...3lg^YDNҫnge(~{gj#doP*4ո1H0ۉHPJM $Te%JQ F-Tt kn/ٻyp-&</(A)Hch7oV\.$l)CvXֆ2[B-wc%n:R}=a6([=]Dfc*i:̵/AP(67&%eɗ*YVԸT.sjabhX!V)FiUqm{2$sඤ?RR֔\3yQF]S l-Js{}x)T$rT}@n(J mq(4Ͱ"N%OSK3*;HOܜЇ5xpP.9ɘq-yC6j)jiN7<񽥟2_A7"@1Qճ)2.je@o@p!h`-Fm2״>%7i h80"ڢ/XW/75w{}b&hI5rR&0a;Hrm)BF89cQF -lK>Aה)-UblOn.PȮ^$cc ˤ-s/o)Ahn-廄33u_'ߵimmi `pc}Bz3S sT1F,T*q&܄\nD 9$^ BP JkuZ(FlXx6MsVtT%ure$ ˥=!NKkωqiٚ)|gE߉2U.<Sc>/ +s 4A2 Tִ?XQLUS>Y 26K~15Mi}r rYZx"׽J}֦]C$vA疪47g VTPX8(,6B r4g_%'@!7ﻏHtҞ1T)2h]A<Tvb ʍ q QJFp1{__HJ$STҌӺH?U*b )|I -cuz?8 ؗzGL%tXI?5ufTS_(O]|t#UP 'KO2=<<vL:)i [+f]oXGU=§ÖKJSShXmIZC*Uq"NG L:RL*wW86ݭshZӉNth=FVKug mm @$H$ ;6^CJ4YNjga_eN}q<؀I'6=>5%{OWt9@oIJ|QlInc&տyѩ>>;HK_̟ܶJHB Mv[Y#)~fXuIL(!uɦW{_6(?9X&&5 Lj TK\pQD|uIK5;N_eduVr>}E`gWgo(vf.#qx:9r IeQ*ֵ=:ɖJTs|cURj~1,&܉eK؇ٰ݀rM ]T]7Z|9k֞Sm%{/&$ |,/ޟRKUn(V㷦cAn |uK{H )N$v,W`GLiսKVzVu[[QS`xDGEӨԒ$w &e2R ,, ! f형&KuG,ʒP{}0T,ExUj/r_*;JHu)+־Hlh`~$&TS] HmGAhX671:\ *4s2^ % [7 \+,_p8vA@^$b̗wL[V)8ޡ|7Ze|=瓴袵w8__ zڦYǛIKImR/GdCi.B||usGH)>n.Y "X(1tɤ3Rm˻Zs=е2=;CY*е܊i ӱKxgT O._L[yN;9I%ǚ}ml WOa.jTvܒY Z=5!R#%NJ @9>G=6BiC0nY6MRP}f`lܩ _6is/N]-QP+X87~!@WEY K%V/NW%:_S_@˲쾠6(7"5'^tfcYgr۩mE& P'N@f[AFUE2 @]x)K~!a )3&-fL=$ [Snaac%-d &R:d^Ni @-0JBI8> NK󆂂ۉF٩ )Ii |xr&;U1TcƦiSi3 ZQk\(yIĴ!uΝNˡ!y9ke6BH':_?F[KƚNs3ohbh)?yվ:]IjRjepٷ죃nSbbk#uɦۣb.NkMo_PTz_fF&BZIrmZURw oRzy{,R(ZTsܝMtbRl=Y G[f!KؤG[lv>,ojkHk{.n].aexߘFF_Pr0'Kskk`x? 2|bxS|u?N8šQ* )_>)Tiũ?qr q5bM%K_칸6iOM%(sT*d ї9"P<#T/Q48 60Q>@Rrn3=mP5+*Z]+LܪSJ8pnmkDvsGi4 m-I? y ExMé]3 60vjԤܨʷL6pJ {\ RiN 5ӵFUBmTI;r55RQ@]~z$2hJ ZeWhT;k~tanY ]T7^afiD׏Q3:/\+Id*^Ó OUO5M@Cg,U5_Z)$ +Vjz"Ϥ#'%MV#e>(:].hWT[*,iD<`WSAT'W*"T̨81Y{ J|[]Vؔ Ol ir ׉7Rj>-Yp.}?!ؖ-%*S7vy Ϳ6 ;DՔm]ҝGL+tmj.RHB&h8n-v"4{S&pK_y)j~TI)~  ˶RN *zW:9DDnh=t̼J^Ӵb+=y>fGM:[PGPSZMev?SU;PfA MTZ M8'׿LJ+?|0U|O|MҴ="9O}AH˶NonbC[:*ܜ(ky >S{{F)0nombZjY bޢ/̤BɾRRSA-u]=`5& G2eM G]I ]AfRhpnM>Mպ^tjі>ܕi.%[rB Uһbu\Nޭ+>\BlP ~׈:Y:JH4zeEsOIBo*H1\Y37{L Q}@fJ\ >3N(|H ;Jo =;D_ :zVMuR(*Z\IMlf?us4Ύ([: x+49IVt-rב5t%;rx qoh٨8q.2?+I3-wNiκځixI)O dc0޻j)q_My@[`Kta3w\P2^dxbq\#"%ְENb`*cjw[lmbw"bhCØ|j;{["DRehyhKOr= b6E"EɻgjeXS ,oմ?UKYQv?K`0ڔ4h<ͫ>L$+>M/%%oX܅m=4O%)IMSSBu[R.6Weu2ZEhr>Hegtg]鯙ljzl|-Zs%e(P 6?j 2lhJ-rG6#=V̖*h3-x{~l[j)[Wo*>8 _zG6s@N|ö VV@m/q*)߷aT98MMI Jn-na%ԷejA0`8^} HTm&h)POY`Ќ! Z^{!PyHƎmj2t)M(z#vU^8CJ(Xy @,-!+[K;]7ck~7,[*<6N~~zJe֔?HRQT3rn"\JҰ7$*d *Iʥ Sqrm؄G6 &uԮR4互(OqH9hѭT%6vaj*;jDqeyΚ֒r~Pڎmx~6e3<&#/LrgCM8`}פ)rMX[+K.R&kn&R_e3Ryd^#fMjz~jGKiz]U! w^ä4ZScT`8 Myb6V`PYkOLt+FL.: D,abJꮬVy#mq_1Z34eDͧe]cih;14^nfCP13+4NAHm&YG1-ːO3&ԺY+TjjT fTkcK*]V6HZf($IMDŽ؞ PGt/PiNJTHt!2ΥmwHRr,-O.Nvj]Eg\"œO&5tP5!*!6_vQ<,-Kf[@.xm%*)n/ů t?ST-D.KhSORӬrIHI6 acŏ^}1}4Yi +$hJ)ɹ$\c9NFePYqNj2[Hnz*3f`0(UUoT"r_:NI$%6뭔CN qkZaG<*7tIWl⭻qRAɏ(P“(6 y^U=Z7QF{mu*"ehOZBwFm,*_&V.6SiNG7H:vFSu)WRVRskVͩE HGp9WxIS bl ܰh7X繅%Z['Nh-*Fݼ°R¢T-(-+[0I5߆᫾.`[Rb(GU&Pr @] RE[rs`.ZHbʇWspO3Vp6--S.) cle瘄hRl9-#d)R\bT& j)`TW0q!\II`6&삒|5*jnHIں/-Dw{^ O0m;fԅ e%HS  +D0`}#Vڙٴd*q %vm dra7 F{Zs1q;lo| B4SztԩZV} ?+,+mctKѣr+@A)&P)[ mO!{Aao~cKMOزI:&u+m~cjplbs~#ԌXV`|) m&!w-vh4E7\k}*uS&秒z~24jKdכJX[A6BU6&䓂-􇈙3 ;>)%)x4R2.pmxQʼ0*Ƞz̗OR=ޘ,0ℼʞ[I ZI'M<5+OfA%14! HRrNq"whަjfiS*aR ZF@$pNleʌ!%\)V,{HliX<Rrۿ.R(?⦶ }"Y~q7\˜RI$w$kBUFkE䬀ޞZ]{\Z爟,y%\;ZBTCPͿpq.(.8.n^mh*T>ӄMTf^Լd-`AcVi|uO a˝3~QA‚=Qt` q5ԺVpGhr&k ['(tީ>{@F;_ldaE;Uؘk/Ch`i/%@1kXV俘1 Ƅ=r30BeJl} 4tPihԕY$ qTBSaUXuKf{v.Hu $X$16۶3`-| %A)l9h(y[Tr-#)`2'p X~E|_92k]H!n@2`:WamTdYNoDU6x$zf4H 9r='@ DiD/oW!!##vg<'e~wT-El>D 8`.HP2Ay+h`æwv'Q0.(nlJd]L MĒA?Oj#2怡WҔ4v&U;z},ͶVHL+"Ƕ"m~ Z|LPڗu-n8U>57[NqIIS4:A܍2֛xj IE[X _Kek5C].Ҵ̓X 6i*K+Hu/6^qҳ ,nb9:Z+5Y H;_mq|[""Ԙd!/p9 ܛ{ _1_`&ꀖUTdRdfB2^]2KM)j m329ͱ Rᖩ N%q˺e*<(qͳ 97JjaK]}"v mG`~cg=s5MNRX67hF]%k3aPp7x3L&!4M=.Ads~䭌&WNEk9]B)S̳6|^2gSr*-A@B8FlQ1ZvazmN,ʒ뚗)tR\ʡ¯;hki?C?*BMJ-8RȫiH M_&A)6*"V]W\Q$"x,nB-nsCՔyW]or /aknц#1'Ժt7T7  W_7UĴ3 ZvA m8f?)Z7Y(N3'=[4;iKiI 'o^;ĥOk5GT(rW6ӆ@pE o(UKϮԩrVIiVqCUiuNFA4&̽HPJ9VA1"Z$~?&V%͝7;9IR%K\e*ޅ\XZhtQ2+J56,,2. ?a[ i/Hī.N(V U9"O]r7~nnnE3rM!7ɧ.b$}xB429o|ym%gǶc5BO*^̅86R@ڔoK SSS-6Ԧsl%`]ܲdZ MJ2-2NS~,ʂBR6?5oEUJKTGKy;rOZ$zR&fkLwnnn/{aI#];vQ3xQql}\֠?a2MޙDDRe Y'0_%I >S0(7j}EɶXYPH‰91N66V)(<=oqVNݒ-7RmNRոїYqP~t~S|3R>Dģ7d摃p,SWm3U?ں_VTT[™JY"p>\+;3I듢d"ͩ/6\z\sdOͺvtΩa)BYsa* M w\C ?yjj<-<]vXăF*:NGK[촀|0ϵKfmźvEīiI sn;QUpS˯)~/2I8:\RoBʛrQg]v@6UĒ1{ʢer`ɔ6 hm -ĢOR<^6NԴfvfYT<;$ -\XdLD yQGn"ᙉ` \c4v)?њб&% K1;TӚrI,R#{AjQMqm)(`lI)UnyL61!ҴVM[LZfK߅\_kM:MEY"ݳ|ĺ`&,p=&V2njW'g^VeS\mb μ6PF^LH&ױo.cQ]Q@թ Z U/J(erQ%us-lʒ̥qtD̿'< * c!:JSa%c ߃kv:p* R&Luv8jI}e:o&}UsFYuIfO~MI[q2+ &cߞC7$L2`eJbr$Ne$Bتije.(­?Ѝ}"ԥ=‰ #lDxQ){L8Ol>L΂כIӝCd!v *I'L~ˣM8YrnLu|a# 7lb}faj G9^H$6-i5;0iw%uE$KK]m,RU`Xg۴d{R<-VBpdƨM9Vo x Nk&'1ymkKt &iP@B¹ 6M#76!ĝ" gro0B&a% #~lgL\Ιw.)M6۬x>OiHRymzEEP 8 Q+4i4 lj[ebi,@ӏX边D$力6E+Rnw&ꆃ6Wa9$]hU@$0z.n0cr-w ˨A'b}q*|6R+u&uymr0pRI)9X;׍{DfKKW8n~%\DҺAɪM]jh~v( vԙhiJK4l} \#2i֚&wW(ܙ-j RgGmL$FԲ@eٓ76νuYp!$Js )17WuĬԇf(iW!CQI"qiڨQJn̳JfS6ڜYChܫqBsfhSmļ˨})gͼfee* &C z[HTTSD)J6M_\{cFb][uͲe%J.u3jRKBʑRqkk$ Ug ]ȵP2+`>-ZZJPcJXc#r~ I&U!ih{2 DIAHǡ‹HnM*XP"d* ai7 MV#3%Wsis$n/apyRa{J;nxd*#(y#:Btzj*i+u՞/zwDBlޱ t{IY*b uɴU@#0>#}ߠFz[:naS:cnʕ+-<؈O*mUthQIť?J-/,p<伤*ln$O7*K5z -&$ 'H6Lc,l)NQuz+׳jQ3I) J ݻ-bӽCzj&d*]}A JnH$IƬ[P'vͶR* ơu Ch_Lg *2-&À-k}H؇>i͗K~| \u9JCmkvMY@PUIL,Z9lYei z-f - J(TI);nI1~ ]7sO759M"M-B%{^.16L!7!)8VOIS􄄋VfU4w_].1KT̑Zsm:] )49>3[OdXCrP.H4ӹ]t[%(,v %bǿ) ƪT:"(YH;vQKAN[`rs}¸WMh4ټ&iNbN`@<EDq%wr-o*(ՐoQ.;c alMm![Yu$kA[/Rq!4H?SC eF,y,F|K.=>m;q{sd].W^׬qJ<÷Ut)ӶUTp@YJq b `>eM~& eb"l4e&È#LZ˯Plvh\‰Zmn!/Sh{ǘv'Reyaܰkw'$+*<:Pcr Q&*+-xRX\w> n“ܤ; u0@Uɵ8a#{ *E|L8A *&iB'j L1[&dSnLM~(.~9xxfQ!B_;%}="%[!?vN`()[wjC&51;[vEnTKsy7!IߴE%[BҢaIȖEGZ% [wlC32]MLuFK/I#F/>j8H<™uKIŠ|97Xش_r\XD5>PsD,oE#H[ǭkZSRyfIEQ*Em#x9#Q'Z&&; ZRk3"xe b$sNm80Hmkw/0YӲl:yfl%wĎ|\Q6<gzYiLfԎ3X_SFmHFoj 6JGH4^gjIk (RKmK&gGWt&wu_P'nJmIOI=B χwVv>Hq~*8.- $t ?neX0$De+RSk~XYB RK?ه565A du&:BkW[PJBR@RZBoNCUWM섛Sa?% ^,v7"*79 Z\e ZB\> (VSr]q%fI.'Jmc.Gj}'m Sԩ϶ Z U{׸iڌ= Tݮ,&i+i Xzqʒzhf'$0g6)`}"!9_;Ol: YO$IوJl37UJ7w\$78?XJ(`'iT.m| +P.U6+`f,)$tD,&i wۚ%P4Ҡsk}]T[uХx>\e&"Wm1,椤a Jy0HRִy4J{5>ԽlN?O Y ]db)wh_d,6ۓf /2FnBA=:Oڦ #i"lVlrT2-ca+Fy/]> q)q BI1\` TYp%J*B6M p

gZfq4vJV8}>0W&ԆLKjB("FSŴpB7$poodvl.0 (Z?+KKRh8:ђR wbU6s_֭:fd&H%EJaPr<ŦJtJ SJom ;\ZؽcI Kj(i'|y--au+S.m;s I)ʦt.FvNuK}ۧp'1`ZtLjITδ16˥ l^bsaЧՒ}1!I ,QHq㸈GtCifeGcwnVAm8aĵAvy)K ^6%Jۜe+Po}*zkO4쌼/%rqǃH!&F{DƦ@-5ٜhY%R]$ {+hw Ɠ$\],,rL~p5-GC}Jܤim֮BRxbWA)>-BXyr[XK_6f:ɦ8I)2*؀6=68uZIwZSKhC2Nԫq,:<*rAڼ&m&8[kDAX$#c \Ҧ Z[m͂m4Y};1YCT@rART( n;9m&ɎŸ̶Vs麕@6ɒKtHRIgW@i5nkJ|/.&nH "8DY*6Z't-!ݥ!d\$eNzZ])ycF*)j \7M7b 15ޓ-ΙzHdLn=.dT68 <j -]R殣TK;w&Qeͥ\a*㛈iWUOIzV - Y H?U>LV_ %YǤQ9.'۶/\2 dW-%,9 zB椆HU=]% Z| $g$I[3(bU-5-,BGxANTuHajȘdl67Q1="m ršN ǵ;XJđo+Tg95%d&YqR-ͬ1oAT̄iu(r&qǕAÕK*umh% R&gQ(zU SC dmxq#BiJw`d":B}ͅ%t}!E< MN4m!cp2-Lg=x#a?jd%ǵK*KM\;PTGUs^OxVeCR#3nntb 2Sl-Ԥ8矤q/!PBR(9y5w];I؜~Qxpwh R-nԘ ʃˉ)&l.`>K*XX탘7iE+6lŰ{/!&% v캖X\ӯ>.%)h2mcד2MICqMA혮U4&-kZR*&YbQR!VUSN̨$)mf D~*)S렸˛K{Cg)7[N59:GFŧ- ;=ERXZvۋB.;fӘizÈm&' =B?!hJV1b ڒ{3H#;$̰Hio|ZI'mAY67z~ӑGLj7'-rps|YU))DyM BЕ\@#?XFOS#1 9Hjnxh\ԐAQ?Mq JT&-)Hccla 2b^W[IRnr8A=FBW,KM`4"su*yJmS众lɷ/{ks tDZqۏPQ6+M^CYȩMW%p X  R%fֱ͎#Z_4N30IyKh$yIލ􎼕zhB V\yXB $p}"#.^`Ϗ p\Y6o~& J.JN|%Ro}PXٹfw &'u/WJVW=XnDS3 [6 $Xw/5e)Zy$ k ,~^Bfeg2eVFVHʳpOecMQJ\Z/7(!r6e(m&ZT.#9mJNEQ4li$%m69<<*&4.-ȷ#̛`l۹IP[VQ'9ņ8uQ=$9_px?, d9p/H<0UYP֙m~Vō{߭*֦ӭN[6jciyR o0ōhgQґ/[<֕uG'Q )|Ź'Uu&qRH8 O𝗖%ʐHa.(4sHWj.:ޣIfXM^]}̥ͫ(%FsKOӉxz2ureR3z]Ԓ؋[OQ̳ ?.9, %ڵ`9'߬z^z4HKY3+' 3 vɇ!P2-(mNR%%$>ѩiL!Yq" ۄgaP"أ/˰NĞ6r f(sEa{kP'nyrVꬍKMPzQ[\}>)`dX$jF===~j]&5u L-gxꦨU~ZoY&RPRdZp6w>RI3xQ:=W!U-̷{ :;,% l<<|XtI Uj[Ud 3c mD7µmrޫeTīKIQ sabܛɥ?0۪!B J~ٖzT՛#-C5\O$G#:q V"z"aJ'0w4N .Pw@p=csTw;-X9yC2m2@$/5$ӈ/JNS )*;a cÄRr[[+46/Np+^a!vV\D!79 JMp=7حbl\  h !80lb BA^0y$8P6.)hn͠_u -"" rFX`A6\&`A )6'190^(;hfq5 ?E_SޖVH Pdۘn\ޠhF\LBzh{JR`ĜUf̬JG^qe&HQ9#a9<"crVxG'sRSr~[څgFӝRPW;&aI IPRN~ޱً.|,ϑqD~>'\i 47tNemxEСQmO]5 O{RRDYU2ٱ Bmq +dT_ x, .\LGi%}g0×7DEnXLk %]TfjMՂԴ~űo!ƙS5rj5#%tTZH9dXf1]6MCԥHP`pSlu/ fn7QB+PH!+aNA2'-9(2+pvZX Q&bWIW2*yݵ68} HjShȡ01HRVA>&6A&*l`@(hw#]\%JE5&Txe 6Wt$ڔ$.XJYJɖTS+}7%R\m]K=,c+jQ!N\n"험J!yݶ9 =L"By0!A@b" "%H#<.a19rm6|CUBo%1/=,%;V<{ `q`DyR.;Z01Jم`8ʼϭ`s7ݽnۛyqP Jn- a TW `֐cRl !kpadFQ*P6OYA'730KB'׈Z8!<`RnAfZETJlZ 2S.)J>hrd~D'0e4TR2s j%j c[% `sr`[0 dQr,ŏ68LF&fjU%,oRth `p-GbU#f, d@ !l qͤQ77QB"jJ$ 7T7Y#2%W6w8T;GPZo{|v nHܘ`/q-?p/J= C0#8 <ښKԓJm.L%-J6n{PD$de&2~ r؈F$%Z0;p7u^Č+T+p YfUӄ90>oXQG{@+--^"mփMô IPzLcFM&q۪Jm' xrRMg$WW0]+Ձy$/ l«=dP2Q-bMx})9,Hq QESZ]Nr̼Ǵ6RmyME7&W%63*M#,RGըmG4f̨JbC5a* $g 'ILPRNNo4joSkԜ: (t~aXuG$ ?c1n)K>=O#0Ti*U蹿|LirAH H?5q aWR<Q5EQO7j TqoZT3IOZF7Qtl,7/t!D }6ط5#"ò.~T-Kt-\ ]0DDF'>NT $*F/Г)[_LjU@!e')q߸ Hy?Sz+N%[eT+θͅaͣb`ETƸ]i%P*mLj) i䀤;H'Upo#'G#IF"sRi ).&aStVǽ! U>4e%P.")+5y^N$QNSgyY.m[NW"9na܅+AONJ&eI7\BNNW̠ 'Se.B,:p] -rpۖEUz0(Tff[p/JEɱ1!Ps%1eA鐪 0nlMHo0{̇^uL2u34nIمX?=&*?#EZ^ Z٘چ9)G7fz}T6e4L/c *"ܓpx6CV:3uoi6ZeU"JMcorD4R-'!8[*!d *>+Ihv\a#oyǥ;қo}{H1:'"\q+pkJA0E2};ȢfeS]i+!"ޙ&zG,X&YĵUG^4C@65M mQ(87mU)J+&eS1nUnLbR?BrQ ,&$;=Ia]*R%vu SK}K 92Vg6\MoiJuCJa Vɉi*Jkz _&$AfRDUfFߎ!Z*?T):Tܔ̂t!LF%i*|\k ;Uw[j:t%Ʀڰm\"ɽǦc'?:i4n@n 䫪JBbs{rF-]:?T (˼&}N4yon>P}JLJ57jYw[l&F eI,{ SipSdq~%lN%S-,U=TAm~[X uDW44t'P6mpRq͌# ƻzKgYTj.+vn=>JSҌumpmaBsSh%.h˃ #i9|K?֥G圛B\I̒ʺ`ԣ|f*9nlR,+*ROp;@JYJLj m)(|ܜes虦Ҥ n&qxUVBkH-%*}hܒšz5RfQJ:0oz(>oѵtĄiy?zo)%*vI;gd 6ciQuNzPdk]>Ԛyԭ+YIJTx/~TRk`UZMb yHRn 7bש5 NҒe,ТT)U}M4^d<27*+6AֽϤ1c䣮4RTTEsSe͹%9J5v`&)(Kfٹ6ߏEV~a8ʐپy"(Bv'O`4 »zX}%tfM9ReHe+{L#3ǙP-gG<,H:˥REG7;5nH`? `0Cjݵ)$NEnGNN"H\w} ہ;KӪRYeiOo:BoDbcPZrUK)I$STHbHŰG]E;9Cۗ 3 STZn\~RfZT07|SȽ[0EagYe&Ë`؇. ++SӲ(UXe Q73Te˸vIҗR_|p{g6Xp*CCy2{sWNȥEAY%ICT-wܭ@FUi)d5:Tw,*9?I϶rJ$ zKJ*dTNlW[r+9*(Yü$ynpbfJӚraFMۨ\xvβW'r%yHp<0Չ|MTk)M *a+*C2kDsFYCSnn[m!m~,NMv2I j `*MCrSJ6>6$l2nCԋ~P/ZUNn[7-{s^h/P%XI X$&UMJdxeew 1-J%~brfUCRfY+ŮA'bHYUa[ L ,;2!Hnr{s:#3#rcJژRCV ZVP dCp5lPqHXQ b߯:RJ^REXyo|Ha.B|AUknNWyIK*U:,IĆrk2;.%N][˾' mQ%shaƈ+L`lc8q-1R&eFV,PM 9EQ4bk~bOo/䀡bE98dM+q5t)saIH XyyѾN*5ea+RIwM;7AWG]kQOR]7}22r, $E0|7ϴ nm:ZiSsSOJfm Rv&yvJukiJRqvdUATz}|M^fQR6/wocN˄蚁LR +Zsk*Đl;xɉ;*qV:RiJm+qiQ)viPo`AJ>nEHiO@ #ӓr.PL'J\U2A mjZ Xn{#$GUfd( }.26I U"JT$5ˡYHa搐fl@{`GHW^C94->m8{<gO=:EZșܠI(&lb ̿HaYp-*s$xHV7 3:Fr)c,eJW}- f6΂YrLT3}s }'=huJ(`U p )Sbj/Oc%*d;$Oڭf9(< ;Vo^I~iBd P%*Hb'*T*T:FzxPT77RHPX# ];M8^T׈eos,p I66&wVzoNUYfcke"Uҽ!@k+qWo6ڱf+$r+jy$͗T i''mTOj >'[vԅcH1 4ve]?h2.!P EoFaZ !mmGZ=%\1t.̙uJCYSiP?X 67Ԓ5>߲el8stԃ {yުi*2+RO-r2-;WPd=/PRbͩfO{ Z=Ut>^oaB\ PJBHdXkfZF֧&)6q6LҒp A{%w{O&)d(xM"im#Eʋoa C@<'ӈ-$,{A J? !6$ ,`Rv114b*h *."X@23 '6S_1 jy((r!iVi_T;@7.+pan ϛvG0?-> IL54.0 yMJeFy@ Dk9"G,88A8`6PV 0RA$w[b L)@ H] v~2&]Sv1*xP>UdD aa[eaD*0J@ح ?N!TM'Zv7NB_qTܽfTJ>̫k[pG.f›VU= )$H4*8|M|q!`R?BsC32P{.i)c#a#E(׍@1eΡ nxGDߜaD!*Ro݁߿:hJ,Mrs %Yu7hRfpmv+ U`sq;+isZ hVXYJv)` 0m຅[Jr6rwHYJ3s44. aB^ OX[T ȼR6~Mӈ_/u{% [){5*I V'zwAJTnx+O@Xu/(ˉ R=`kbja6T @) \܃K' =Sszfck qmRd9$e$rKrĂ.ט#9r=!Ӎn mۘIp $ThBzREͺ ' F5`ԙҒjcsUK CV$mu&ϰ/+2۷&sE KH[ĕWߏhS~%'4v$~Za;b zV#sBrPWj OZ5T-BҐۓRȰV/syp鎶FsVJy3fʬN`!'_ޤ/L*Sخ {DS|RlGpS 69ǧϧڵ5FAm;CT!%e6;Ec'QI,Y*2!IMjiҫwr$Daћ+!ϒgs" ZݯJ2 6 u8eJ"3m!zڳ'e B`ej(ZH^"椱kq 6 q dYVAFɃ7Xk{m;65^Ss hD7& I8Z 'EY?"ʖ•56cvyg "83, ,͡fVPl xM1ve `-(ۋ@>ԬJa۸ 3!L񟌤*;(!JW=̤_XXguATD1RHRǤ60\c )mM'>ׂm¬FqpNE{Bm7( XP)NhQ* xn'>d+eMTϬ*rī'm@!'ahq 2ALо.!{\~>Ҝ[`h s&q{R9 cZBn ᭇas!,H<kvïG8 يWX60t6"u)%BEX>ٕDKqdw :,mHo KghI= MBsSImʂ2Ω+RFA$R "L(ۼ,a[Gi7nQ1ׂڅ S(k,d&rA[jq,VUn+vt)j­e6˂Ğ,-+m].Ĭ\*pE# uJR?քj uMd=nj]d/6᜛|[丱to(bh뫢RT \dq.ɸ 7b7R, Г:'C|6$, JRrv~쳁slڐ.TņraSuʵa>MMBAīO5#J51'ZӒ3mMhP>ami ;wGgIhޥ-TU֧QnqBn܅N>htsC Ղavxg';yx22kzOӏ 7+-9(Si 0ef9%ߣSo[Vi(?Ԓ-SLvIi3-yʆTn ԮOMuF(ͽorn .?XuΣ7);XkC·/$&\"f pLY94#5kzZ]:CPC%/ٛg`n\&!CiASIJ?Z7nK33 _cE.:m:/mGәujfEq{T^Wsj S3 lmza 6yqLqĝme+*IJiUYғ%5( bQ#L;Vԏ JƅyKŸ2NrFZĪc, DSB.n^0@eK mlΫ֔/7,Tf- >kӴ6̙=!3s|X8uo*XmG28-޼{WUQl@bkkCi \mTWl9=guL5)4(:iIPUpk߹WzFi:vf]W3r SrE{C^'.e4%5~nMJC@K9M=%SejqX'PUfMԝĿ=#3SOmlEͮ}1 ?dtԧʵy} ":PUK'Xv.BBO…9!z}S΢q i nOq62ܛ;AuHE>)M씤6b_8 ($w3sz$ۛ}6LP9ǤM$]%8Mn}ᩒE"/zoapE8*hSd+)̐#ipoú.}A۝l {[ߜiUR|mWkC*!Ԥ7@=g4D<5R3-?Sa96$nܫ*cox3S 1WC-aVmgE"ES{ު8hQ[ *9c`laBfW{uŠ[؟HQ$JP9Sq*zv,_+kKsR|&ĕln}6n#_[|Js( [`ب_=AWRr-} G %K%M:Q/>ӄ$O^#m1uSo+Z~zF]j9d!Vcg0i&jN/rYu a)pzUYSU6^!PGcAX;-ԉ괥ؕ\,ls `R:U&`%L-h^gRV**snl#k#4Y f069́_cOVf J(Xl%-( OAn@q L _,]),.8 1UIi6*q^*o̥|4T؜Uo}OPe>aklmJ.YFN±p}9=aSյ'~F-oK )])eKӋSH\Ƅx WƑ~!45ʧGo{.pAIKZꘖSˉ(p$ _Eqc-SӚSz"MZi Ll%Tb1ęP_\m5wd,ޢP6I \#(y$f xp>kP;)LׂPqVS2勺=%BNM1LjΨfY)BY*mHu۷m?H cdLΎbP 19: XMͻ~[1-GLܵ]ZV@y/8d$uA 9]oX"(>㰈*TԦ1"mi\w2ԸGH4U*졇 ( ~> ѺmOKmftnujl:rr=Wt0̼J`T' @טy)m65νO13O0쬺] ۹&x&8ŢKzHS<k)& z"EWV䞠D%ĸR`Rď9 ^)cb=/OV(fQقal4O% mYޫ^H0Դ?H_YVsN\ X0- !VDcQ@" Rچ(Dq!@*MOfSrBҮ}D@ z~#jD7JL: UnBm 27J13Jך,t˶ASq3=C12[hDXQ7?]]Q%6P oisrwԾGvCwYZvv{ .]e Ob8XMH6J!aY*6.6.Dˍ&#rBeZ!Ґv,2#r9cK:m%Iڦ>0ZF;fS*VP@ c FMVғfE-h١30f $o9~E2$-sj"8b 3'6 βc'=ȖZ-Y% ay5̲nc YB HO `°"jVRN=q7l#|Én I&I"[8{.RT?RlD8a1pqc7q Y Nwbñ| n 0BG >ZJJNA`Z7@Yi 3>" TNhf^i4m0K/v(fQI`~)nJ/v"RBS$gM8!ܥ%G= T(᮹u/QRҊuڂ ͏xhv^8 G 6`]s8_HM )9Ў}`X83)j+q`ߝǘG'BP$~¢Ӧ\eM)i ~uec0Jzm[&]cW Hc6im Ͽx1XBO1n `fpBA [<0Gm?#AJ+itj࠭*cQ0]"ZN3L ||{7PzC {U&PUCrn` ncJISN77kn Itgz}={^0M;60N\X$${ 9y)Tͱ*˖}PfZPAsYV!@U@% 'osѸ@J hp/ )(ZBˆ\~bS$ +ט;R|&_R>w 67) Â99pnsA2mn  0ӊ-V7[I]42Rnm!M81֋% +)Jb73Ԗ+Wb-r%\=a+) !B<2JфޑuH( iʡR1:a "?x"R!<5PTu;(\6 Ыg,2e.bdK{R y˥_fMJ= rfqJyeBN\%6Ă( x/ZqsD$aHSTj)3iٹdK8lY o,c I]K QK 0cSH<hO麊DMajVa 7[l;3 ^*)pJ2/,y@ ƗuOMeI*U0|Ruq)g7GiSw%&msPdIϚ)sj@ЦNFy/FfijIpVJp $B!s%OxeRAZiU`aOT%XDkPyZ6ZJʣFWtNov^T"Og!b,$6CotORwД9T;Ԭ6mYIW@J׈mM( 9<" JI_iu&1Ni$TnÜ` . JE¸h%WQ0⊿#qTbT]Cqy.hPp%6M%1{oc+ ZRȈ`/DR!;æfF'/,Bg"B/n)Trh5$.$ZDIqIAE'i_Pˤ٤;1Ka^n#bRm6[l,IKj.-D([qye>FŮ2JKF+c3VSnn$L8&[iW=ȅT9u%KexoqlVU )deͨ\(yo{*FY Ai]W\~DaI@&т,"OuOQ~s@e'sNOFAM{Fa|2Ip$F}DR!Mffdn IjbA^e ǧhJl\*\E/KCq:JP{e^g7wFUo#6W⢂x A oߑ $f uRہ%W>)Rqԩ E)`ĝ4)VĕwELYKH< l}/I˫×aEWޤ_aaPiO: />N^eŊILO8[I6%ZJ cn`~W\~fy2 ;}l1xiKMۖ\ޱzzJ[+hpwȿxǥ[%.9= y 'qebJI L%[lr,S+Jқ W&&%%3Ӟ*˅E"m 6" h ^cܤIJNW2A=?@Kt,ɦ]Hxm!mWaE(kI7->*P+91TktL)EbaHq۞-aEsά˶Tӛնjw+!m)!!^bx#R3 V?@,IfĤfQ<%fa&z QJʥ(\l m{g[Zƭn )͸sMB=Aj?  dzeVhSRHbr./]Z=BF.5Ӗ|@Pc,BI(ϴS)L9FҝAXCrN H@1>=ACe7Ym.]IRmϴ][AcǛ\yy.]̸[F-SÀ5CFɊxQ/$N\ؤy_w#X(F:TjJmRRqS`τ-BPGq+Uj+b5=.km\y ?éeB60u$)۔s!TrL#t! IHI ߟL2[*aA6YlC1` #䄯bm&TE HmNg;ȕHg?/2)jeV9i6?XwI&7uBeh$ @1*T,ijZfԓr3QCЂI#}\6&>{RT:^#;$4R6-)= '~*Oe77$]w'/eK6+m@>ЬʟU~N?]E` T*q|8+Dss3`l{AV51X2]m$[I*yn\Uak7a,*rͩBT|VI{[/4꿳4Sx!w\ v={_;qR>V1 #;5Yo7%>n3f 6{fHo0vd1l{X W&6ɹM[TmIbP\1E=O%(KI>-IĂ&J LM-w/JU*M<˳dzsoxS@H)~TetMY usR%UUlK,^`p [4$ʿ V '2CmI_C=ȇUun{eYQ!t_WΠ?)g%.I?a)6<8I=@̸-2pݵԛU4KTJ^p(x턭X$}bUv9<͎$l0Qp/C0&9KrV5, y s‰:i.6[zo&F)>5"%qū-:ԕnIF*GH-*RA+ E>%6>O Csuٹ`7.+#VCKSqռ%J3zzQO=Pnr]CCeɷq^,;furr!JKNrmH;AXD1]Κ׬I+ l~lS|cS e'gSfgRRXe)We_axNHK͹PRv s&oχucFVSHjm =ɅY䤨x' S$rԂAsĸYP>ΛȊRi,䍄ߛ_xcL4jT y)PEtu*=qbz]nA OV[0\̶B$ٺv?ER33⡵f$ۼ8J-R K [|j"5 El9,˞)Ī^s4RZy\dH0L/kN${s );" N_-c.C:m Y[:ǝ 9 PJU|!U|Ӵ2GL86PbQ,nmtVzXL, 8Ő7zDtm)m](CWIȱ7B4+y,؛v*>%3%-*}.~@H.90ĩ[ II'c8^`LH*-K:A=8<¨DˍJ"q?m ]6Ǽ \rb]C X#T`lc:">fQ3ḽo@n}!<[֖zUjlZĪvOjMhDAJvP?0ĥ*XMVE̒&? J0(jzVE˚urf\gTJ*Tu%C͠=WjA_d!In#w66AQ)|PK}ߏx]\i֚ފe RtB\ӴTD̰mJ[o*;g֒䌒eԅxz@<06%r[qQ>O A(;fQndj&g ^z2.nmal[ل3;$̜N$?.탖9I1kZV;VOkTJO\-onH?Xx,BLpde{M鉱:3.["ͤ(r)ږrRĺ/NQXK̩@,Aͮ-kttM6׌ZBfK{T e"hI-+i C&폡"T_ʮ7H"M Vu*U`p8\vhZam +xG8Qc*p&p甭ܞ/$A n&@l6 s<<8c7P[J% ^dA]mĔChxc=1VSfY jc7R]aHU&ֹAQ&[̅ w钮:ۜlJH '@&wcK"a>[(aLs`ɿk[fA03Ox Uܐ=&~A<Ѩ@ t39C*To~$FZ8ƚJsa%.]lqKeVI…Ŕ# &TlH! +I-((NRQ Y.Tm8\+#URTSk<bK>Fduz[joXf, `=zTɺ>E.P12 X Q0ra•>m%*#o)ָ!W 7M"fṉJ MR\PB81ϴ!#^a)YZr~?PeĥJ <$&xKB#™d-V08@+H|xJANRW ^bfYs91șVcstɄh#vVĬbN0aS[b"֌!6VNt.m \qg!B١[)=*Uń,Ya+CKEBQ32s (ĸ嶟OǴuJǓJ^֏qӔTK$(bMr {bEie*mMLJ:L8Xɰ>D*nju8a:ḣվԓq%ɹAC!)Js~-2'\r3 ˫Vp'zDԧR3Rqes 浭VOsJstַ8Yt$Iǽ.zghTL2߲ҫ[OILUNnyZ+ĦU n{^fRZgepnC* 9_؊>S4yyml 7s QkE]:\9`@LR5vIr* oFJɺAȋ8*l2[2W'4@9JL 4/6,qb(_1K#>mm9N^BMɅl9H6Y8C̕ n,[EK)SjI62S0BT8$xI𮢞F QSZSdw<YT'%YZ[X6[[2Ssf3RBEjB-u,= l,87(q !Ķl >Ӓ0Y^P)zI"=z7ah\%ż[D߸rYi9#PL5>m ĥy:\G-8TO-VഇԊ<-ڲ8C)zQCAe!$JTT Fm,DڧV%,,)Q=oĭ.F˻BnY*5h!34nBBJB6 r&i3U jU箕]ԐN/[4a$7qFx1i]~oӪRn#Cu 0Id_Mrmy]K3R-*uJy۞nsKm2M)7;f#$916,B!y:*drIt~Ÿ@cQUȹƀ VMLwSLOK:l + ahgVg?C3, NL7m']2m: R) U;"SĨ:#nl19a:B6Jf[|ɺ7^˛bHNYѫlTeSe8T2/cD\䮗Ԭ^zDDdg R1!LүTp\$![9 A_Q2>dYMllm}= 4ex+nT- )Sa )eԋB9SxeĄ+*HqdNV(\Ԗ}Էd;*ݡV&|NΐEs%ҕ2ROss#&xʹ276$NJ#Srk?!? Ǭ,@m?a۩[-;.a ̤[A0|\E3(2l53Tbg% ( (,MqUkYH8RI %.Vd۴( a6XU@hA3z2ԍV-Qa7-MHvKu,%)%f~Nv}!E KNnw\fBaQ23=ԓTeRV6Kq鳵i-S, x8IOݔXrMϥHW槦\Rl2v?H< Zm A^B^7!6aKR4lHP.lb1r]ƚJJ[rQbR{zz.;K0*W$R`,$zg>Cj rBmQW<Jöwhj5n rkEIh UZXUJR4J_` >:˭ rd~" &7&PHQl-x|N9$O\ai\9/}=TT)NaKQb*x%aAC<6KVLӯ^zPq F])p7q#W+mE%!J6ݵ͸ ֞L[vQt?k\vb^EAD>L>┧&^M uIC)JUtBM<3NBA~ujI$y2gj&cXiZTIĔeWNU 2%!Y.m}fο*ezW3]?i!eA O6W{q40RXimR}s8zAJtƍ8k2n[svyRM5,I;a  rG7P|ZJd;1$q8@X4:"ie Hnvnlkf*'UQ5lI:a*76u( Z*Um!ǭJ]2 4X{dzqs3RF]id܋ߑ.,u ̺rAmknE)ѱ$rWОT>?ͬT]tI?f6(!{Iš]gf[}Ӻ&BNuhoIɰI=oƇWC V+rnD5ljgTYI.ۧSSukK.eb}4IB݋&ñ1}v C xܑ \ .VH6 +#"5EKE~d+[6A#F,1 c0a I"BVҞ؁S6-EBU n+q? S eGZS9R/xy-YtwD q6rZzv^h @kii =A2_vpeKl( eXȅWF0n\l'xp)2GdޑN't6.JmhZ o7Ȃ  -Fbru) 6 _NT)_^UKdf1L?ru9LinK%&WTE[ěxeBўJ[gr-n*,Í '/PRU(#h!Akn(XRZ6qCmiw0iƐB̭VqQ$mZn" C֢*i$97 &̤K,6-|왦V2n!G ( z K:R93fm7Ō i"Pv{A&d@KL (m9* Wzh `I)) CL0X?"[[c|cB]%KMO9h+j//N-'6x8 bLCm(ASĚZ7&AW,KZCMTCHUL=uPW ˜AP\!Am~ 83+N Iڊy8X> A /M3xLL:,   TDaG@ K79_ bR-u $(>%ٻ$Uqoxn}`xTyBO8F̺RB<EKL{vS*BNchW 'Gge &UyQ-(6xh;RA&̭%v,3n J0޺q[u;vdYmNUa` 0ᆝiV$=Nol`E /rrDPw<[467y(ndl|MNn{_SQe&d%Ҕj@[[V+Wm %IA̲4k[9TBm‘,*@nd1\*%F !Q.SJL> e ,/ yE%EC1~L-FQ;%΄\ygwVҎɻ4U夂{@azn̥Ɯh8$+Gck{AHzt,:pԯh5d$_>ֶ!i\5P)t̛_?5S{ B7*IȁB B7YQ4y+_lZMI+k# Y'x䬤 '=zm}FAŇ04w}ۿ v*6;n-`*麚9.!**CE|ڜ* Fo"l@'p@d ˸T*hɊ~eJL i&lG2϶ ʲb~N3 &Ǒ '^JSIG7lx(Xq7MlDImb9?j?{Agُ iiछ ۻ_}iNoDֺK%NƼEZ  [c#0DԞju:R҄VGe 8pX8q!v.#jq|E<%XEQL->iPJpG6.xTL-%+'6>Ig6I'<-'9Hպ*6X2jB ^Zϙ !'봗ۺX'~#f%!pOo@S o#ft)۞]ԛW7= `Jˤs[xPiޢ.8)gj{爈rrER6 )l"Ovvݔ r!T6ٍXy( éi[XveJ.M1Ŭ6 tJngPW L-h )M*=@x:$,eP|&W祙s.Q s_gNi=?2/,gR7==mB$iel.XgXR6 -bKK̠͠\Pr zgS0 #2#(mT$YD% ]<}xud5oĬCc6A+yGrVr'ňq֒c*IJPJ @l}EjDBv eKVHœۨ)"D0" | F#~^fJf{y!AaBI$M8LU (%kr~õǴ:IEԭ{qXb AɌj"8&4 >uI5>hAPj2jFd($?[rR%Y lqšjS3KKQWvDW6jʅCz1צie\-) I,:JjVEo-3- b݌Nu_a P&@ta&j'rd|H„͓e5).Tʏok1xVI^դۋ&E[s5f_SIM@ S{@u!D- 8 ^8r`;INr6=*h5EUS6 |r{[fvj¼s2'K)pŤbkVu2J^JIDP<,b=: v0MB<q* q{>6lkۋEbkómu XN70>Rsv1qIJdš]2Դ9j0˩2h&  aŇZRWmijͼf%D,z8=I(ruϲצe_1cmN -n䬖D YZx])t6e\ 6l8cߛdD*a 5.9j(|Zk ǔ܎-lA8H$ Uk-9&jnE8ٟ 䀱p=AlЅ|lOj(7,?OiZkS]߲qY􋮋#S5\nfzWBR[x/HL`LKPZ}+p  qr8擠ji%f'ȗPZ;ǡ9c!:vdGD}巤4wRȪ&4L%n1m@A* ciƀwL:%Qs;JMr?yW|ƠՅiR'TNpXEhW/fўWh7:q: ޱpV8?QN YR?ߤ5E߈vW)(2AJڗBʸ$x8 gJ &SnmV6JR06. TqLsOJjnI >P;PeG#6gwn~zLپrcL/6 }[^7R*.77LϰGFujn, ǛhXR@$1keQ=?\GSIB3aA(M6=>%mQNq6IP5$X,6ԌC#E5!7KV=nۥv9l |]6b ܧ%5:Q14^Y$MEI''tufn>ˉD_lp G87ttr O?hӚ yh)y G5L_fo5)~2V\p2nEk1䆕 < Ai/.o+Mx7:M@jo6*#&m[MB6Dz@ +k9I;**m!'S@- JG0hi8]d!n34 .l~dI̓xxrtH"H$ydo,{B&y?Xr` <}H:po ؟8ǹ-(m{@ Je& w%V"u#~ #xn/5\dϿP |&'*q$FҝY@8r:6"הJ8%D9RnĐG0xOz7k/ 76mm#GD87ru3 %MO-\6n-E@9<:6&[8&JKÀL:vn}L.&Dh7aI"E2 fևmc~`)71[i%+Mi(Pr"PKj&G- Vr psthl&IH<4 : ոx<<)5&9P ʒEa6eYd'¹# NFGx2]*WD*Y]hY ޖTY-w ޶&#olH!MM \P9AblMɥ>UNl%@ ""MВ?9Dᤉg?#h`&CO('\mH{@ A v$&nXqkgTK-k(~" &As$_3՗]>b; b-, +)Skz@L. I U(@}\ eReSN:Hk )3e eck,-T]--0$hZ &TVNěvD˭-c-I6Xȹ  HQYxa|`ZH>_[|v$:ځBᏖvZۍD,JoWH %T;Xv^LM1&Y*QURMn= eXDXAмL@=9BvP!-qA*7TVkdm{MxiKKB|K[iU%JH((X .5?Ɠyxl)IP@Ee$)9t0RWŇ[*0u)!e\jREoBV^kx()Gnz[C;n絡Iӈ@e%ܫlb޽fTnˤZi-# oHiȸ^ ܴXGi`R +vo74RR2jQ%/Sm I0PO$n0 (Oa%Y}JlH{8SuޔVO%2~2ˇm,/&߈GC˛^}C/ÙRc xhKZ͢&umHY -Xa7DskB)CES(G*q[қDYA,}b2jA-܁IY4bx`Y%Rsn( Y'jVE8FkRSJm5L ]B,]-Ԙyť of0k$F,ӭnR 5$ē, Vl}smBևEe)lY#.Zt!g(oK0 K Xm/;3*bD2lS$ {`\&(4̸[-}9<>[W'>@]OxюkD]*Z #*n?hz!DfTB^ISV䬳!@%\z7fAbf*WXyD'HI@7EBk 5*OYEW|vUiPH%*>5id +9xxuڦ星}I\mK+AXZ}r*nS  [:6`6r8xSLN`ӭ%V=|k9uiI%(\0M!k)iI/P (ne68n0>FR6ڳlP[J& 'h˔S"s;4bhsJi t^ ùj}|*U{;IFӚ}/QU>f^OUJgh(J >b @7:&ԚhE6YntӐT.}ӛpgl6cQd|SqlD<(Ub,/>&TW!7Ǧ{m i6Q I/!FYqn`(|zÖXKMYBOp"JF,[|\duA9}闥Z.>{E:ە $sFwIu;2]Juf[q?ONKIgБma7B ZQCj {߁$i/HTLnMN ުSY`H!'pH_P(sͶ->g@:AA61!&Naɂ5$y'赕yv-c4-l;y:M <=_x%ZVI81t`'\$u.~ -\Mq}-`'cYBKyj %QYqǣ yZY3-> UO t)2%$F 9RzyIPzS^O4X TRqkcÍw(^vQv <=i󻛩!TlPSqhQtlR&u}$FEIYSlQ%rN&mP7bc+~˸i_MKY~TC*Ph4nERBXEz}OmkOY3G}㲴 ]ll}zOv31&-4mj@:Gf_3OM.o^ӫﴔ(Ŕl%4ž Ka "2=o1ŵi.~Q=BiPպZJ&ݛ%/LA;ȺOk_wE~F6MoLIR_ 1=-ԍg'Nן Mi+=l}jڎZW?X?)ĎGjSy!*6\\q FxM6Dާ,:NL(vigJE $ߜY={9=YQЍQ6KPI ~Gվ}4̢Jtz_R['-HM)Ntc}&RoB6oj5F]Sr3) -Pd͚[\.e ڝþm1+ZZb[)4+(RI6)Jol`"MS-kySPs˅m%rr"N}RݶqnPo[9Ou10QkZbV 7YEb,ζiNJ딒B16ڝ+Y/òR P^&V,[BMܛ`6&zaܴ-k-[m/Re!e2ї$JPhbEKY1"~S8Gn]kЊؚʫgשvfP+lm rډEFC:rx Q,$CmT˜Sͻ 5fApu.):.v'hmbHm-NSj5p?N!ODm'eX[TRUbon \1Wr`B,HQUܤlEu:YNaxUuI=:?@ؖN.%DY+nHSB68 .i|{[ wy}AJM=,mȆOZTCW}E23 xg+?4dS IFuցb忛16l^PO=Wv] xW HNAs8VO;8kQESS lInfZ2Ro y2J)JFH޹2D39.-p2~ V/öPRsxTH\hX(Re ]U.!2ii??&[KmWM|c9S\$lQ0qXP-*'$XԦ؂70osmV.T␵Fۯ˼n]{"ޘuQnG9搩%"Qe;AD[ +ĘMӷHKUaB%AYBX P4O:D(hGlKi+3IT3p)7Wn/a<'t x2E"f;ft؏kve.Ll7F=W5bjΧgOWfgUe"I) Z VTl8~^ADĽVYXVZq9^J%H$)*DDUtOj.ֆvܮVX4N$ #Lr KkϬuHM o%m|-w&&k46ֹˉZ!`HOajgFitgiy# XMہ{zzK*#_/ᬭ ot `͟l:S&iu.U>^sOWCtЩHӝB?)%\L2^+4f'ܒR.Ny¶()JN 1SњZƧԩJĩϺ*qZsSI.:م(8py+#sǚqbːy_M%/>zT)d8NjEj\$meEAMs~"}+uS(S _\RtW&P&e|,HvP+827A%ʝM,Mcn0ͮyY_-q`$ XZ"vlJEeN|!ʸurw~[ lGl6YӵiWKVYu #Z|~ØaSU j_ -2Prp`r" Ue^·Uڅ{A@ 2EU})S#7?GkțD6O0<*!D )`%7&umX5\ʪQ VʛI(* bNk*lR5E[ZAcncX#ؐxYU8%u9އq*} rM\_8:'W:w$)&A?-3ɱXR\In 6#Z{jM<]luEGl giC y}m }૕u kEAŵ1EX3 68'ʠ-i [( ̇:-{r ~͹j&вj^qMJϸf),TIP# Zl 6 *T HI#2+'bb:m{DĘT& XhMHNO)8֔&X(y whaFe.]D YsA?h07V< ;o $q Xo+0O6E_A`>gQ!WI>R 706`u2A \RTT?\* 'p(ukA5'0Y#} ж'W^ <4+zFcY9p (-j"S5o<ˡ 7+0^)8"1SB7bmJC[w[wa2A~l*E8AGqt%>`{rث\7Pq ^>*oSKfA?q]X$qD. (_;T[e)0^Ѧ,w&am&Ѐ$w*&4fzS䴘q(ԇXJ ე6"7Bd{FBĞ 8͚t* \=¢6 Q, Ӻro $r"KO.nHxI~ H~&Էיa#hj5͸bkeV+z3@EM_ ze.OD'X}VgTiVԕ\[)7F̪Yl*]wm $,䴑Dyg Zw! [d bA}% xbɃwɉ\؊iLXgr3Uչ+%Py_m}Y$d@!d]H)y/7# 6Rʼn$(YD#a _0eK#9[046&Ibj}S )JA P W~@ԧf>nziǝ *Ì+N*@A(·[ڠpHVZ~r6'q\}AK|%)'ɗvA0%H0+tgYjkIz}352+E{DvpARV+LdcyiK@r"_A=SNnܙRA,{g4OiȨQRvdIqB)Jo/]9,brUق136Uz х4_J$UA";<} J 1fFmVF 5*4Usn?VS:IK2 d`Cw#?FRB Km )0,܋O5cԩچ(7)?$6QHT]RfUڃ/&aBtfjt9W9?!s&Rbh%s6S)&YvDL/{],DfrbveOOͺnT8t)RZp+#cj(N-qro >"J6l$k4Pan&H7$Xۃ}>nX2xjPBէ2<YگPN[(mBx[\D:Si[k[mdϡxj "-iu o,:[_T)MSڥ6]+n-J(;PpL˧n͡يkAIe}GGUOi.#L6K*$+soLC:{^ܬmI4/o0몟ҝ>ѓZiʓjlHH|L |к^QH&Ǐ&@3NͱkdζQMqo"%YJ xGrm/VL͓!i aRkC23f#Gzf7^ Be'w4Ȳ7c`=AiK'$!mJpG0?E\6Jӛ*eHIR2,mJ~⣭4_J*'ucL˥ÆcsEw~c5:TJe%R%(cwpll;f.:'Eh`j7:U/ b9hj|}2_ާWRXҪz]3Z+T}ܽɷc`s!e%ߣ.pe)r(+@hoLh Ӵ6|#k:E(`c.octS P-+TXKmo%Nfq\ GW 6Gqf=klS m7P7ْJH8xV"jK* Klw<'NtX莣7/G[ʖ>̼iKj mr-91^ iTN Û[|Ss._ L;W[3u;,"ZyJZqͶqt9 PcS}0SI< A)YVOK)jZd/{9s|4%g^/l RfY@h8ȆGjc#@MϺ[UZ wwkH|IPonm4?Y覥jeI;Jٲo",tVIKA7@[I#D8tcZή1K,8ݷ\H699 bT0JfJڔ,CPTJeHmDshN}mPرN{w/΋ե%(Z2 Py*"3:Ɨ9€صe*v-UN!bBnlly7Xuy;AD8|ܻZ\CaJ.G>QUi}-b2"lK܄q*Vݽpxf.QY7tCYhUT%а([:1>zTBANеt\2`&4IL4SNȼzu/g6-jec?[DM{JD qǏRԒhS*fHګͩ!(Zfbm%I]({~WwBeBRx"½cu*30S<,%kY$#\2KR] %СA&kMSs{t]"#?, ّ-ĩ1RQ@Cq6}- &U! ֝7K ~Y[evxAolhx76>EJIPg {mJ$oi}4Roa$_[J? P^nDZY 3SVP`hI2P씃xR.Xo>d*Aʞ"B:VTVžm4yw[8K ܁a|WP/ poO&5I_m6CXp`ow`T`oH-iW P#0t[={N,xٝ&Cc哉y%EHx̄b-4əi9%'喲IBf mBp8ZlH #6ZOF"qĘWval ­f{JUp y"My ķ}/\ɟqK+[IN ĕniee\y?qեi%&Q3­qH}ԖO'N9*\@O ,Jo`yI 8R.UfNSeP0BQp7aF]Jlqm* pUmZ+q1|Umyp Sp|JD9./! ;HϤJTQbl:,I VO116XK QB պøQ+ -+=D6NBPŒSqkgqdj.pTk)hmzPV&vGKt[KZScx%Gtiڮ'ޛ]RR~Hz0D*y0"jUI)Ki> S\}%m.7q1MXUߘgmS.`)*M%&jշ7৓F=u -J1vn~iRZilZkuD'6A.HSwIH8ƣ^ _*XSBU”X*"MR; W1I}Eꯥo ! ΂'s+~9i JS-MG. Leyt(r!ѨJ18M*oog-%WxPm* w1/Q` ^S|+h!/um)'rM-I \C|dJH"+[C>y.6s̳/&RXSq HHEƔ˾A9e/~Ɛf\~]YC(5Ve ӊGS &]8oKKN8YmaWNLL˲Ը-@BG;iAN\J(WUM!))$_}O2'%/~tF""fXIO4b m];C$L$gN4Y7P L((W=űU`B;=2ru˿6CenذCGI4]KbS&R@M✟k . o` %?GH\is%|n9jIAIs zQЊqyL%(n1ᖗl90RX7jepe< 0Ѹ)QȄVl×'f6-x#Bk}KMf[d.ew '&T%̉iuW]``&BsLTC.vSs>E6;@% 15 ZG< i-n"BPZa2 ` mvn8,Sbh]RnfSpmds V!*0e>'b1pNL+y×q qYiY(A @[RRBcm w Ǥʺ|)$(}l(4ݰ-d@Δ7QZ;}K,N: nxaT)IP ?P덒[W#"Ze2 xR1Ush(mCTNx&23,p8H$ QDȭ$y'>5TRߴʔ{lo ˸)5 xaM>XD+m;Jx[p9`N,ql q QDDh)Vn>O" kX{q yl.`YBIېcAHd<1 fYu&8#8D&ij'Ոº1׵J"ޢQD*(А U'RR% ~ }!S(i.3]IYtnǘ^ngi>U"6-qݠ81kZNI(scn F]33 .X-jRx 6ƹ/(x dž/pqoH_2PӍsq I ;SɹP?L~=&1$;E,Br?h$`r3&Hmpa& 6-3QwŜYY#̮'$&\*dX h-.#WeJ;o9…{f@7RMh?IXXw/Xam7 ϓ{8nhmVӓ9.Il*t([?\wY\ŠO;A/ $P/QRE@(;w!NS q O\%ŕ_ 68ۜZ q߬KwRnFG fdČʔG?BI]I# Ktthimnԉ7wEk8$D0$5u gz‘ӝ@ oL6t $BⓩZ Ty&CSoJ[ ^pciYP-_xI.Xk9 ߟk3O90`T0H?Qm m`Qv2q)Ph&΅'.*Ka,2[ E)T#d TvPR}?h}LM]J+nnm gleGuGuk]]Hvus+ p $$4SezAV#[~'m-X0T W4mL:Vnj?vJ!$߷[j)ZНY%s =sm|ǭL聇q9J#YY74Uϗpsy|AJ\eynFtf(?~W)D }U@m %ᯊ]jVC8&-4U]cOHKUi)"IW=b=4LeT .Emq:bАjdλ2 0ȷ7ϼC~QTp'j $irԼ’ڰp9Z Y/ޞqCcţQ;eU 2sZہ $_?*FK,ߺJR[m \\;k_5,\9"Xޤ% )j=I)seH9t_&]CX<*gO@u&|Aw M4TdZ5u±fHn2BDAY&[pqaLJO6{MֳܙArbo V8&|Y{$mS2um(ZFdwN{CO;w#iZUP6Ƚ-Fp_mU1em^)z z ^4~xep X;1(x$XkŒͼSe7{q8~T .8TQ2R9fJ?w+*̑BV喠L9Uf`8Yi*(=bVͥ BƩpb Lsi[܏hI)BlTC8 DKS,",kH^KI;OԎ`mD[s3 XJaQiSs qn6UKN +h" ;X6 n'TpaQD`aK"i)M Iw*)W$;ŗu 88nP4a:ϝ8 _ٍS[(!*nNgT 3?is3vܙFAǛH8hN=H3[LNll8z3GXM*$h(n-H&{~VUuq5oDڮE~&b^Os~fQqQV6jXa2\ mjyv\%DC^Tf$?fרTġWǠ%+$ M9-u:Lस%P6*X{qwX R Bzq] N-I! #N+[mqǘmnbgQJ)tխ-ԔABS (2Ò3iǂZw PIP-{/ rwMקzGn^Bl/-2¸]699oMjjEMڭ~iRPȝJ '~n diy9%_J:YW&@RU*\`o L%g3Y+0/elI wXfJVIhy=A^U03MrRl{IlņA* $!ԇWỴ{[p&n#?ڲF{!G^ıL!*mBܖȿo1-%Uέ<2o(bF=3>_X~S粗!6n>T* 8*!DAq~ )&E`,( YلL_wBDKo4 # 4@ Na춐qQLNEԓ1 U2~)1Iy*tbRane~bt%FWx]MW.MXttHPafp na%,̧;Pmpv5̳.[}%ɿ[A9_pvɜL*ر&9x'@F(n1H %cSz&HF:gp * GR :Dۅ4eke>I0 Me%Pm hAY0s _07$MJ$Be8 <'\y)&H (q"aɍUu @,L:\D טEU6!Z 1I Rp Rž#!!@=IG  ɷЫQ3곩J@0$2HpPȂ@"MGuI&Фr0[s;aS)| yỦyȈ2® bZ(L:wmU코OԘ5RkYdV%$,eIu)$vT2MD#.|P}A0x.Y>=U-a/ 7HZeI!6PMary[P! t:alzB∨kIP@ A؆JKL!hLJP ]Jڠ A1XQ샛IJÒ1)M-a _1@D - m0MIKhݲ19@!{mMlhjIIF{*NUry2G 06c"R a6+ؘ  RH*ScHw`D4Ma.k{@Cϙ0fZ;U 77 .YY.&Ħ{BHhQ¢RSTOm!@Uo^#h™UsUƪT*$c=Ry0RIXFM:ԒJKovr.!U`;J,#e.{ߏqƅl7 _]+,/JHIM%Hq!Xn6ԙuL@@1srtnJ%R`Qo)?[B]B1h8oÉLOV|$H 6s 7(*GBL)ObL0Kqǖ*Q! L{g6Kq<|ͷπPMaX ?㔄$6 E!dhvd,Ӳ,><<'iHj^8Jl*I:UuJ҂ 7ʅ[))!$ 'jvùii @IQ1&I*Q޿߬,xRM;ļ*$) [-^|= $zH!*IB) &8$ZF!Jw)w`Vmm Z%+4\ I Rk-N9}" xbHssxRVU(A6K6 G 2&정f+>`)8,:g[C%Rc.om 75͠:@좛 -:c{…-ߌK`$_8ڥ(S .̤XZX.(]I>\`gjAeʔ`&?.,^i$aO&Nv]_+mCsвg0qh8oP= "ܳAcR3@N7lth I?(eHǨSb#au 1y`:mJM61E#Pp4 Cٌ8d߉/2Vu*q"5$XP%C<]^RAr"Z%8Q5 T|0#2TS'qLZT0&X,$*':F)ϗtJIS;42E.dьt-SQԧf1 0RrAW?H4J')uwԭ=}}~sKtzâIiċ)S (y^̏ Wq:rz*KJ3JEPkzWS6;fFȘIɒ~bә UEETæT,)VXmi 7%"s&ԝh| ^GPҺn[MH{M,d̲IN+uJ¹"5\cwTABl=9)U `!j=SbvpI'uM8B-TSI}d->`8ҝ[ )[MBnL5Ƣ@mt%7̬>X8!EVؑCꄪղ 8d0OG"uPHJ6yd;3HERSǗ fV)JX :euKuu8o49}f!H[Z[-NmvB?NLAjmH?Z~Ne&:pU}Be_c-*NxȻ'%;*ܻDr/B+`.`:UL#WON.R{d&xBrMg#f^۩|uE#-kUiI̥=(V0m ȱ"]t)WI<N_(ZfU0KHǸPqԹ8J*>ݣ.c#;,P)w\?p{bH/fKN`{eÁ<Pcj2N;0R74id!҈Z新{l䃡[#o26NG$ܕzmJ*ww#&D Z|$ .ENeĴ{bRmW7/!˭*ZNC{0X$lh-O2>DBJ{IjyQɇ.,/cnH(~ZYV`$SLqdK}ᩨU /["Ɲ끂T,*%|^tP0I *Qߎ9Z(AJrIGE70U={-2D)/({a'0Y$sw76չx+KHP) əw•u7b]ޗ9.(rV8lfc9sOErd#N {UpKD0$FaS\yIX2tԫ"}9AP`16K[em.9Qm(82)*QWMw G1" AHbFF"ߵR|F#x&V< u6ܯޣ7 ~ԞC$HxyEȐ i@Ry8ZeL 7jy(mbW̒n3)k(ZB(+L x {>jL=଼- FRNtS #)0ʦPqhh&ޜQ-Nh&&߬V>;FRNO BKSgA6ԪTc|27( P"lnpL&M#kvTԪ!^Z;vr,cb@)d$3LӒ:BN k\~f pp9o'I~eBe 7bJ>U\e%$\ ~\͸ZݹK $\hSI RgvrN:pHߑ 8lR9FJLc#+:RoI!El~8},M2,jj])37)&7 c`>%-v2R$>NԬٷcRezOɷd1RbK M1.a f`,n&zbҿnQ9u:LyѼVOĬZIU%e.Sp4kP' B˿'=\o5NKmFmU3m[m!ܞԴrn(48;Uk݌Tu7HubTuU>+*e J}Ca8>Vw&T7TG6W&[7Qh\rQ/R%VRvۜ \g޸Fm'Ri5|fe͍OhG2JId p θȣ` ,xTGPx1Tur,_Dk,ff4 ڂXyɄ)e'ma ċ˟Ⱦôs@><4o]zG.LM^E B])Iqj[XY6ۗUqu +7\G*>,GıWeϖ#9ّum?XYrNK{EVD¬ #P%e*s ZKS%]./ܙY6$$fIƿ[!~;CeT$Lue-?'DIZH ^3amE9+Y԰%\_e,U,.S.Amee 9$ w`Ho‰B֟/7MPaB6C.nWX\P+%'wm"1:JBrDrUք(o=cy*Bh3v|:$@bb- Ž2Xv!’na}m ǫiJ&{wL 6)O0zʏQ$viʬۛe: fH=cZ̒4/ɇi+m\׈&~A H|y#Jxsu& ˌ;-4Bų &VR '18Fy")X˪ð8P0֛쳅.!1;j n',w*'G?Np]IDH0n*aeJv_{z^ 9Y-YRA$Үcz(qcj]w(hLM"'*.T*#wHPA T!S,*[#``YwKIXeFd9S i (E콒Dpq 5ᠡɂ8@ϼ4ś} S0.-Cqɶ&1mlIE•G:w;}>#aAhГnKLrԴ (3%&J2ܬ{s,ǐaCޥ `S*+H)fGʊyW(/ )kI *%#{CٓZe02OUOp"*1_'S4񼤩$B?7SG]'cq.$(wɅSF^2Ii‡c BaT윻3sRKs *eda`` 8lZJq{5iR(s4|Aqw%/ů/"j")?/ DBƉ 'I8[hq$yz}#jh ɞa3)LԫjR=[1NI3i IV6 {x;{}֙ geJ$l!ܥbv sfX $hFE@a&] GA e%B}_hAyܖkHNI"AF{\DSKŔv0[;Z+ 6HmIX+0f0XRp(MT|}dn! ߕ3R6J tnT c)LDJT@'&9XPAp䓐nгh~e ۓ!QN K- 夔v*obzb]AG%V"R =os JD8TٲQk*mԐm82iLtRIed̳OI[xJToWh )D3nK\/Fa%TK+A}(m> u%~x$Ͷ%[Nť!W=0bvjqqjD&@{[՗#2[hZ#y3sSLZe;J˫ ssAS̕6R+!4;΢GǬ2IN*I\8[N̮x($$fނ JA0pjQVI qpvTe@;8IR7 *IAwT6. !a3RII lss ) J}^n#Q#Hj|JS8#$̗^JT=Fg{3B](@U]>ֆp ㎤#)<[ J$8!HM9ӔZ5gȖtBcFR)7`nF91+1/A~]Q7yMStKEy3r(\(mi/vZ)ܰl`{³U&%?Z )Renq Js+Jbp$/PuHMr(2]Tl$8#G=h:,:Qu.xlcxDNy-Y=zbcxnJn7r {w:ϯ"vM]-R .jJp@ 2y\bL3Gxnڼ9og=2Tn-eN-FDOz㣳:Ǡ:4de$fd$+Rq'(EGGUt5H$7=.w%KNRVnjF.&ʶZ'|ĺbk*أO`̢CTP.ɵ6%fqTRRqbAiə OIm }-6n=KK|YkƜ]PuLTj&x YQ ~T]'Eu2>G+=4 6IN8䏼}N q8݁5'x6']LYP&vI[ESϽ}]j.ƢmLeA>U(o`}b]~U) )na0!-;Fi.Yd XmKS#n m[r8)BseԏS+KO6FH7^BRunMaI:f^U7-%*|6mߘ˅G_.7:~4L!!@nʡϮem^u䚬}7%-=}"0E'd90U-*ޱ+PM>QUF(;2;c7- s0؋M0xINLdRrDh^If_fZJd6ͬghn36,ix3-N~63@CMUR[P7$.羣}IX,~xJ% ) EZjGޘjWrQ\J;r@0IigSVJn;HRR$ ox6Gҍym#o̾ZșZHPv9F6ӓMVuv( OXhs/~U\Zvm~;G5cjJ&\5g6?O'PSx- TRQ4DsD쫲~d u6KcZE˳l6Jҟ I 8^zzjgXABŠ}8a*5wÑ /xۭtĄ.<=tM sk {IKjfvUQ2E|عF!J˸l/xJK]UҙJ2@CuEG 0gTW[{k 88IWRפAqƄ~4:'4f-Ф?8q!Ẃ7DܚZfZݹNnA)\WED=$ax1T$%8$SmlA& fc}J>PGSeޚr~ڦR%[X-͔rCG'R D *[tuޗ[JyhNۯhJYR%$md[>i:?2[4VdTTlTSwTx`+?YQትKiJPvC&֫Rݘ~Ԛd\JCbX\_m~}g1pPH*rJm 4 )Iot|߼.TX(/~Xƥ$*^P@sp8TM=gYQjmfJ'>"l{wX<(>JYWVa9 u,a25Ix +&~iRO̱zUmV(UuH{H #b! 1&bv?GW|W),Ju+h:L9SF'Τ8~CO[T[11#,wN˩ީ_ۿh9ΒOץ?K2鄨`/u>أ,ZUմT,MU*Kh)IDW N]@0ʎP*vN|-d!. %Ds@A`y֛HqhK@!V AgkM3rH>!| *a%!L c$wY ¿' ?`"QL oG!W'3Re&LPi%eY67oH<ܩYfH(>ݜ1hJ"/~w{H7AĜ[mX*Co|6Ӽ xxF(j?Z:d ]eܤ؞F>Sv*piL8鐖M񋻀ޑP=[m%V,)ξJf l\e)ILG=Zi VI 4k)XcF/ܱ|q|!3A/>R͠+ `\XR|Y G}m#q%/a@*CD{h oɄ(CeP)$2Q>o/PJGB.$x2'cvl6.AJw$X $s ԧX >[ߛqxb2tmK$<(תL3Tq!/6,p،_/NA*P $eK6 !J 0ȍS'_)-9_u^3 XٻpU)WK%v;RH';:TЦ8T¿Co$lݰ/Ez4''Z=F[\;EpF:kM7 QsA6Pڥ'+qVSnX)?h 6LN(4y+JSUw7 Mom%p8$Bꘔy(Hi,qcq^I^*yYt$TqJwAڿA 喹y,e'(A&yJ61 f anQ*Z,̰Bxs 7,|^ۏ[Z:qB,ˑMH܊<@u'oCO, c͢6#p ;497!+Iɸ¬’ mG Gx}Pv4/ӱA'P*e*>PUֶlu*mh)x ~ECF:~qǞ.Bv<3O3K=ȭ3zRFJXt\ILcD@T4h̼ mmKzCI䛍)ZH0fj,u@Q ]8/0p$"D-$*dU Fx$˒J7OSƱ?`!,#`h;rGl A&6?HP: P-RM>0h<@.`nTğA[( %XsL2m)IYW3e09 g.ԛ [=a zX]qcZPB@nb)r-/"-$ÄLpXl.aԿʺ,;y 73+2BfrZ"j?x#oE͡N=уI,R+ bAmąyCb݄54n[H㭎!d^[ 6%CӼ5DGv^y6ؽ%~=\Ã[RJK@) XC}EJI ȉRĦ6 V8\O)+ܕ̂wow&UkcMteˀ Swt%n!q#m !kh";8R{% AlAq~Ł%ʬF;C_lK\i$H:P)ϼ` o*XHE-jnMp soz0~FbNR(JӵĥXP=iyʴIu!o($.bXU j~VQɪ{^Ii!D=S'0|),Ki6_%+26&K7ܒmoE"=z@V GS&rqW%^po"ϩeϮC )m6%| yJqǛy>PRp/m ߴ( %IJ#z Ap) Qϼ,`2JtﷴHR>e.CmQ#XA,$+ Rq>E͉Ug5AG}97 *IQͻA(㊸ [U$6< иxca3$&~7JJTaQz mm oÞvմphRE*l,sh'$ 6e7?B_9B@6?HT>Y:.<9lzSaV[E6e }ܘHw T@0bTn ) wu=DJU n.@R%@hm=?Es'ShlJ/ u[qmLG>L/dBWҦ_Kxwy+2! ̶Y8qP~Iqr8?7ˠr\w 60rChy"$ 0n̵Xmmԭ0v$A8CH9p>w_3OXE.`"%i9:Qa̻-̅+Ixfl:³sN@!+%`7&g$RVyF|_B22kKN:%?S I&\>-"yE[׿mՄzqb}t)}Jrz[2(e5:L\6J-iʯS3rSwA^SOaxGASTNTM&\IPoLXu fffȿ1$Ď~V-I0_uf֛%i@(15~(2QS)lP$C(pY ù:F.ޗ(]1 $؎9浱 wJGJ[+t^9)ѹ[Ӽ7 ^ ;&1 "=u-!G?ooFօW%%C͎)2m{# { RߗZ&J  I Qej0awlӅ;yI(C$Z|E4rpyeE#Qiu**F`zaJ}/ w9@Nxdj̫*O`f%dZJe ?Oh$pw9 b51bҵ' gnH܏0$nBqTu0Û["Ĝ/1@:&)0e  *cx<];AF*UTeرiAϯyjRJm3s2 jVP JMÆoCP+ &Y̾Z TN]\F*I:zPVmd&{s*(S^198mbs>?I2<-[\TÎ%4CJB@טMʲa/I<\4pGn4 J_Vʵ*^N8,{Zxv6W f`U(/51#zCmbwI cf[tY5vLI̡t.* WB.1{\K׺E2,ҥfZBfh Z{.9s#;H%W罡TP8/UNOju+w5jnrm=10fRIH:ũgة&qפ4HW<()>e h{ |u䲥(UfaSޚ'ViP:"$6D/DBu iͮ)B vg-O?OpRA1J'*?usRHx!ORHP+s*U:lҘ}vG)1ju%wL)ckĜ$_"Y?+4IRdpEOɦ{>m>qG3G W~MĮmHf @# aCCRS򮰹|@:Zֹ-#n\ܛqĝ2`IǑ̵"V` p 6X@ ALCawt [jhcQԤ nU(=LtfIMNIfTs-.f'X(]?˚LLR7i}#q~&|_m5]4Ҕ&}n#P)t5̆4T\*qAD|Nymhki-YyBJ`HP$LMiuQRm{p&5 3m KtZ#uiHZ+ )$?Bt>")Tk%(Q`_j8縏:/N6CfJl3BUGYQqԳpVvߘfhM~jHC=[\?ЪʞuA׶˙].r]u*֜MQ¶Vy 3-xM DR[9Qh.jSK:ȼyZWV NAƿM,"Z?w}9bx4yP5$HDi 25d0~bɰ!N&iib=Oݾ̀<~$jZ%m ŋqq[zVN .J:ԘuUQl8?h2%/]fk%j M/O#*qB-O0i2ֹ]w}!o?LFcy) \[ݡg*))Zq{bG@$EA178] Q3(6#uKU5L yU\ Ԥ qA$($SDiEIw_0xOI2]O>YHBc!TJc^ɑ9$KRԦP#r *iֈZUR~!F5,ҫ ͆$Vsk{a)R%()YAх`pw9įrU`I&\ diIKժ&QBnosIUema1NL{n%/Xr]@tcaO}eI @~%)R0Ia-+nH#1j=IGmL ӏXR$4 L斕?x/<[ǿ>8Uܢcu䏛|M[-k s >A orS|pO{Hi74˚K^V @NV"}EZT҂AI7 Z_ DRMPT 4aEYl@ h40;o RP-! &Kԕ@*ڶb~.ʼVl? >kz@4M! mBm VńԀ@P`ǍH5.gФ'n¦Aqlv M%ҤDsp7.Y39QcMLVutK( $9hƶIi)<_yWLa3/MäcD|)Z?b;X%=OaׯLA߻@JRMa)*+_KQ2OxFa ӤS) pmkUfօɺHeCě3X}c8[)uR(%(pYEVŁɇ Yp"l}""L94jo* A܏=[l ]lxS60^\3Elݫ)2u6 B7>}i77V׵fbffR_IPTZ..6/~!Wp70%h#ӿ>έ$fVlS~׼p-U:ÀAMFӇW躽*ʓZ+S-rܖ -t'1:qKu/Q+_j-)SHCJ%L: Vb A9^3ScShX(U9e^R}ĹP)% *MXAΌҽgӿr(TISf(QRn x.\d N3z՚]yt&gIjvE/)PE,K%!­AOoTm}#T2~FzNnRڒrJIb_z][IhSCJe@[6,͞ RTժS.J5 rhJl7w7'Um `E~DОɩw\iSz]$s6@V,"I+XUMJ;SI 3(֠eIˤMyuԤu™yJkPvZ^B&KZ6rmM~qL6eh7 2krVʐDĻ?Ma+uF`{[KܡbnxBXGA 2>$ '1.H}ؑpa]QkTiz ÉA6ڥ!~}"%9dgF!Nږ/egd^#*Vh^R@N{Aɐ:7-K5?$L,̪Blbc?hΌdf~[NJߜ  w ;;TB K0-,)&81حb7IlIˁ oB=-xe5C=,D r 4r ,30J'a9h#OJ$8TpddsjT?,xn0Fך.Opc Z1;MI YUGl·m)n@ER]WǬ.6$bEԶMԂ@1#M"q&ַ/`-)pbۃq1I(\ja!*6=h@$-Բ)$'6=)\b~#c+#x="Gm6Y/۰[0B,H"Ǽp'BŖ̥Ԓ[ޘp6SpITgڛY>_E11|n;@H3,!(r~ c,V\ 80ަM;.HS+ IN#0Vej?$R IXPvv˒#RC,hǩnߤs)=iW݋ÚDˉD)IH7mrvX}G oxq-;R9߇CJ*M^a+,Ͻ/.HKB$919eQn}E+uBՉ*%l2pa؜3y@AF ֔؜eUb;R7q0NL%X$nNaf<7HFăQ50d$^%^TJ\f-7(N6-[)RO\C=fNu-6q 􂂤xy0*l%sPS&} B/V-# ^t6l;6H0]vm)B1 )0mhPZJo;mim)YDx8m=J6j9[Sdd%GM'O7B&R vK ʮ]#$lQ{ӺV/1%?*,̷q4oФR#DR&R/ajQe^n +07&(}C:R}Èض)Rmk4/ t+Y$S+ywB $peEUM% .ߘkH ׷LcP}qR?rZ0)"&{u$ *^yaI?LM}PT<8'mj 2JtuT…/9tӺ3KN~T-9hq dmakF k 5TnG,̲r@RJO xJyקf90[(j=v58-0|N|LJL-,suF{t`gi>cT2&;J"'R q7^d[ !RQ&- ŢêerJ|='6m9CsFbǣ״ IfR㍶#}MS,T!L)6ximU%>3u,fPTd3_ҽ|Z|0^ZKnh  '=ɋ!r;U6pFCի),R3}-WDeMJʓc_N4BjT9mKϼ\)wtKKԨOg3DyBE|q;7%U͟Pǁ&:ѕ&_MVL+<.;n=>}&/oj2=lK%-8jznoh֕j jVEe>>Ѹ\X);{C}֚'YeaKRsTmZzi%A,`+m'7LsSWZuܟ]Kq68{=vW'L{yZRLukiB]KR4nܮ̳Fm[ih= xZNi4SPvwb%/;P//4R<;^Imn]{T74 mwպTf4#rɹi(څAZ.O똤޸jdߩiڥ&YO]T ʥDhFix dmUnT.U==%gPHbzM_w$!᮪ K0B_O?O-;EPR$q߈}\Ҧdt otҩ[c o!<&%566,ݾ&[ATjQZͥû& LȻujĒ+>,:Q񌊁خ#b^%([seF^vwjN8XB!њʪ ty(i܁kw= jxT&mRv$l p/ M}}#māsR-HNK7|E~׹}$Iea:rBC hkUgz յ,ٺ-L<ǜHsJL2մNK D_"?hs yL `q Z׏ORxȟ /Q#1OkC~T}EلSQ?Px=BV&Q:< ;oh^fv?LnXn%R߆7QOaA GtɝINidW,(*vXwzM ӵ0O8/H#ߟ2J3+%2ڣc]6^8f[X/b9/k -{13MgzRNQ;Ip~u?u-5/(z؏曧Q&je2Nex-Ǽ+-.kKiAM< skb u 2&,qبv\!5י'AJoj]>؁v!'&=ԡy CCyEɥdNҶ"*񌛽d+Ȩ%hL dR haԳ\M-PSHdĐ!)l),$fI@8(vIO2eI;7ّE}+UA餵T\JHKOy7?Iܒ}a%Ч[y/rI$ ]2ԇisfU*\aX9$dssK]sA+K[JA Lo ȳf~h;3:Ddmq7P<}NN1P{tiJ>v)Ĝ%Xr;}Ki XJ[S@oRrGaБSnPMOK֣{-+mu}cnұSMhLS}b@xH D6X h g+E8wa活<žXӿZ#Y . Fcf{#z<Ԍ_]$5 6 LF.v[~'8et,~a;:v( Bȅh뎙M-&;R)jj+b\UucҷRLŦSM+T"`0W+L+VJJZiZVihµ`'@+B6t UITu+pz$vnsWSF-Dapi-+O$^jlKʲ6w#Ȫ#sC5T lqk˖glzҴFV{vlwq|׻e+tGu?$7T "'H87ڜL ;J`ozחZ-j"de7b=9AMNXD3Kp"BJRoK߷4I;VDz㓏czEG< 5VCfDYv(7 a^$AhIw/*c9q0KiihaXlӂ=:=o$R+Q)ejy[h+_jzVqNw% ``?s8oF`nk}@;p{zӲaY G|uWO-':i'd<[cǷjb7:RXUp*e\WK[JT]D0tך6*\ Y#?>Whk}R܆QTII$:d6^lVh<0'n- '瓓V6bxmqjk,da02~qXEw4rDD[$:{ջ/ ]\`S<ԵAb+k:$ky!X^@_jWِO,k_Rۘl_*ڒhKBsSK+W`pHvDx9&~UiLs;ĤTvVvkk&񉷂mt8㞙tӾl˞prCū]!;3]>F;@߻ON;HKP2$cV⥞oP 0?ǧ\V5q`rF0w7\f "-,jvQ^w-Kb`PI-[ǖ!Hyg Og*Adcң-sbzE&=9Ag& ǫ*/#ꤌFri|Xg9l4Т9?VQ0~l H[%T`f62w$RmG8` Va>aq>qUqXKM @uY$Q H"^iRv,@ћ~G,e9'\FqOv6A{Kg>H&\k]j bd1ypzק*b`ȸ]ˌ xQ"\F@Qץp7+tgxjjn fIљٜ@ʨo$>n!K}Og-Y,سQKp!5<`f-5.2>UT::MH(=3H烸0,?t[dX-yk?֤XXJQҜ+۹P]JXR~n$o'00<:R!8CUK 5m$?(+lb=8N\u4aX`*0<5$vIp5c$52۰uvzwH&{PG)U"un솢"ZXH8^PVnnC2I^I!I銅'{-$vW#Y mbg?^ʲZ2c׎tU+^:y $)}吒I弻X~k w~T1j1c޶&O޲<(tM#U}sʪMat%FRAG_Ƣ3JH.}hJ}LTr< qk9"Q}LViSp.|'4 ibYw51rm(!Yw1ۺ?yƤK?sSՔoI !EH&[_>!+m|0c*ȼ/.\ p1VF1o3sWn^kV28A&p:[HsU^ᡏ|l s'h)mER=e  dZ2[ WʶGON(XO?6i$D8'|pyp< +fx u{Z;PЫ$''Ol{R86asAG8NrzO_*tۚ5ڬ*:x1xU"f.D:9gVt[Hmq$`go2Nx%dursc𬙠6̑h$ZzttԍuT8z֮-"H<2/̠aWScngezLQr~V 1wS-cE<V`vHQiD{ x/[%8PJ"@9;5@oOm$Rgq+ۊլǮPrC Ց\gˌ2_ztYb*dÞ\$InNGVP#d˸ldܴmH-ZEc!]ONVEnn'N+&"C@Wf`H'5PfH^đJNLvB^{ը̬c~^i+4a$L|s&m S&ތe?LaU֊ϑu Vve (nO}TZ^NEd#@k `cE!{VFLù,i' ()2܎4hȤk7[!nn#38ӥT#ۙ5RCpxl8D "*(NisOrH-}ֹ=<+q( $Ixj犨e%FD` s (*(rzfga=(0{ UR@N8Ƚ#@!0>(6ަq&Lǩf+F5`F~T97yt[#S3;Š(gC  !"$"$C@" J!1AQ"aq2#BR$3brC%45ScD&s1!1A"Qa2qB#R3r ?@)F EkV~PphHK4b@E*v"3P"s@SDzɢ8B$OKUYG8O=Kc i6=oX 4TXphS(+jajYNОjxgiE#ǽ[ic|s4 vXHqicAFiO8'Fҁȧ{U*AJ'D瞴cE0TA45H 3@FqithD?4a3K( #N sN 89Pju=iqKaR4 ҧ=GC@ޑ(Џ|PPؤ@$bH4rf~*nf j4 B=( 4O#"M4LBgci@ (F;S6j 4G(9{ OZ<G(yE)xR(7("@M (3K 4(/(1HD8 1@Af PQ`r)D =Pw w((Ps88v' R (ғP ?ڔ4OQ@ iLɡ@A2>hz(iU &qڛ@:sK(Q( >i@P>(whNg)#^1h}HCC:Й8l٪t~(A74dsDJ3ޜA:R撧KoqdFh[dP}BТqL=  `$Cg1N4@#@Q ̊7)D<4SC=E4"@"H3N .9AH=)jii)8?2fE$'"b#P=NzLLN `MK1DqB6dZ'"ICOmǵ;Ъ c)QlfGIIBOg i@ڀ|U#ҜhM 2~)DqD~(< D1@ ɞ(ޜ{dM "17 xc)ր{ Ё E@HP2 9CP CZ4yD"&cL4G8PsB(GE 0᥈t8h,c z50x>3 ㈠x;MPЌtN4=K$H)sƉ,O&i| 6bLq9P ("@. ցO[y(ވ9E.hAӺtP":Ш8U(,phB43QTP*MM@"28)HNҌi?4cިA3ӥ.AP?^(RhBzwjg T{D*`hG~dqB=4 11'P !)( w (04zR#,|ҋCzK3G@F1KS8@=i$u\i"v1B&8ci@lsJ'D`4("R&v4SӢy4jaSp1׽8Hj'11LLЧ4#ҕ|6#8zK PA@WE8J}QH*ڕ F1J$4ڝ]*f)p#wښahlP E:ib 4 QH qNR0G^4~F*a4O35H4 4sHQ09r3JEBSH @: w4qThFbJG"E.(hfCB'ЏqiP=L5PCSCBhA14ɣ=Шfc&}ER=E}x44D&GE(0([ihz@4;qB3㘣UIcF)w~jDc4=h D8)b=M4 $S҄1HX$zqBGL=i{ R9jfߊN=4t)b(&&;i{P&&҂vzXLҟn(@73ҏ=*#MVLS@YމHP8B0s$B "QFځ&B\P"AE 1֜@O~I`Խ8~ӑqHKH3A4qHAq҆ZtH @юJ1ւFhrqNW#@S9t< $qKdTIЎIV SLLO)E@7@D'FhyN M1AOLR8MR@ (ȠA*lf&1Go((ցPjSߚP Z >)hbi48Jƚ ӕ(1@)إyziƁ%SH4$ G NhhlIwGōM8P=dж61""c4'yGc@fg'✡3AX=h#4@=i{bcs>Ծ)tF~h@H(J:E2zQ'?jw4;ȪN{ TT1BH zP(F=؞hȌ4'ޝ qQ1=zSNxϡ F)P"2s_,BsU #DҩFTM YCЊdJ426Q@5I@=OJr)^='P4*4CUD9։@ɪA9^ԅ s4ii8 # !ނŁ3ցɢ`j "biMEP7߭aDM/yT4{E8z cDzS҂ "*)GsրtaM(#<j"(d| ]2i|941oC@ " G٥c?Zޑ瘢q+|PD2yP~Fxjyf;UD)ČR=jczD3ҁPPi}t)t>HOJ愈Lڀ(ASCT MޝdP1t .~((iӎ8E^q"HzP`y}x zJB# bDz" |QM 4 ȡh PbGz|{fNAS8ϵ.'U~b{щ@H44>(ThE8*tTh㠠AFxD5Hc!&h)ƚj>:ӳSEQE"@$E3#5@@Zqh4!4":MqTL#M P #G4?(QT ӟqH5I`H$P7cp:P3Bj$R)z?!T!ЧqCP c@G6"iG=htxJ0(di3zyNϵEK1Rx&b:Ђf` CN"'j @{SGnAN(*{P~F:P3SDjS N1PG\SqNPPhxP8p(pj" hG@ƜbDJ@8@8P8ϽB u?-*DO4@1@T1C(09gzP1 44LR=`q=ji'bzFG 14'Ch-9<0IIQɢ"E)DOj4eCyhw3AX 3GъX &IL Ecۥ$R3X1(>@B4=@sCGڑ`49TvS,m/FRPz>Ԫjiby,i9#N›T Dj# <@>ؚvgRjn>hZPCT(u x@NUH4ڏS"fFhQ @ThDcs84@ӕM#ީE?b;P@% DCU(#9?Z@S4 Y]2(~(8ҕ":ކcv?ZbnEji3҅`#DC C)y 8p)B&h{ӱM46"dޏhBDuEi)5@'0<flF( " iq)88bL":D~iws~hM;NN(ff(PR=qJ=+*Gc9@HPX@ycԺM(P 8 GN#>ԇ8FO1J}a sN=h{RH84=(?GY֌gڀl摜gGZ]@ 9Rh'*xȣ)Eґ .iHcF(N?$gބ&y#4 i@gԣI#H#M⩖ % b{юB~(D=f{քO5(?zi'2dIgT'`dP R 4"hF:ԣ2UR x7qUF="d 82GHr}T3(SR2FbQ j)քCGE3B qHCҌ{Уb:K"Nh":ӎ)tfy4OhF(#1TX:Ќ'ڑ<N3MWAbށҁ A>p!ڂƁ#Q='J?Z?44-@(t4#ACzQH DU%iqKzP"=M4sjQM3ҝ3U~3T{R=U4 UICL3N0dPX9M4#TbFhQ4jPWCDK*8抄THhӏE,KHY@H@=]y wxt(|4 FE&)*49O="}))*cӧ T "(LQV)LtzfqDj[D!7@)`iN?  摧M=)dFhuG#(NU(Ӛ≥ E)GjDuMމh@GcڛNh?CpDDq:M#(Njڗ^iƛP"3Si8DT P5@@sq;@1҄@G< zB>)Hؐh, ")9ffv׉GC4 NH Ei1P6#)NVLvTAX1KzgĚ'(yADPxU;8i<*&itEP#4UGD #JG()"B"Nff`fjcљ56 )'#3(Ȏh4=2i (P)=T 4A {R3R$b4#PGZmAwE qTǦRP =hqHq3@ڏA"))N#b(b(i`}N9A)i&dj#>Ӟ 2>(ǧP iGaP Ͻ*]":I)(|M|s1M&ɡdDu"4 F'>EG4 ҀHivޗOzD_lR$C9% GQi R;MjAK4Mh=yqyTǽ&HOJ~xG3G@#4 C Q@=|$Pi"$}FhhqJ3G4*dRj@(5@H≊F&*4LF)@(Cz9u=]`>?(P8 :1E@D׊SB ?jSBi;J'ULN GzXD̞ }t3)]( > T@f≤xB Q<#h,lfJ'4jj4j8z1H`E;FO#5CL!ZiK~xP:}/lcC43# DPJ?jQ Ӛf4Pozi9<Ӡ R KLCi q4њCP?8qF{Ђ~yT jADR;֗Z%"pih)<у֕;P #<1hfr fɚqO 4vHhqN#?t;F (hA'1HDOjPә2qYji)xaB9r4gP@"") :Mӑ(0f'34֐>BƙIQ'.@2~(}"(;hm(&EP 43N<KF&$TsDIPB&3K&M,ERHD3P׊@}>  KۃGA#i~)GXPґ4ENq0hOCCN2bh @(O;ޔs@4⁙TEP?zFz^T& ѤcRҁ83PȌA\tr1@B ;rFi=qTg&hc.@#sH<+Ȍ)=xpM!R4CSP((iց;:& P1Jy#3.y@WH~Ap";'@=@G4#=b88ߢڔHzƚ<ҪM&dU IP3`CQMH(E#@EBp*DHMhwij44KF B=Tiiǽ*zY(s(Pj):#<6#HEK,ET=()fO74bE#NH dP ǵ"f1@ O?Q#ޑqMGi~@(S4"E ffG7JQЃxD(q@ H4b1U#n31@)|s`qȦPf3@GjgPhDЎL6tif C摡FhzU 3" G:1BP1֜qhbx@0(E$P@GjDjf :`f0iƛ"=;ЀEj4}# c"'?zw TTGR="P :>̌QwaiH=(օ=)(x@hQ&D*Fc4f(4Drs@4IqCq@u@ޝiOBҏZD &`fq?/MsGR1юh94()i -MQH (Gc4HPPP 9438)#Abiq:MEPsR#&h)`!1DM  sމbL@⨠ OzrVv&?jdpg j HRx٠xP5BF(U ޔ/z~hR8(1K犤ҔQ$sB1K@ E/RڗI` Gތ⇵R34:3@TT=ribFzl(13& h?jD8N{U?4BAz除h 34zCjR(OZ zS:U3BE 4O3F @DDP2y?ޅމ0hlsҨio@hS(}tlSP @֝is h4I4~P PEǽܞhFibhK=&)g@6)≚֩FDv~:sMN3ҪdSc4P m(Qh8,F\1PhcqI3K1ڨKH摉@ LOBi>CH1K,U#(J$F#څhz&:)1ڗNiR4/Qh,jMSȁ4:*(#iIB?A@1,vf҄Aӿ)~E CGHO3D.GA@M()=(8T(q:R"HA#;((jP31?ĊH(4 yP@3l0?3G"{EAcOކrf ֨@)`(q :f#$P3b)H`ޑ3<7P P)*DuNR4 Y֗_jl^\P5H TzT35Jwh} 1@ҥ֨(x9eiǚzЕ`P@B3TzRGJ9dR=*vxҁ|SM8q*oN)Q2h s@1Q@18qi'ӤԅQCO14Ȥ@iLE)dULuii4P ADf1QFM;RvDZh3Ҝ8 idE('i簡tE1NIY";RLR #'F pއ 43(3ACG9?;҈v6 Lbth@A(dqGx@3CjX=@h*qϵ83CȪ":p9hQFNi#<9`.C'N "@=H4RiL)@<4@Ͻ@DE:@ciLB;6Sv',FhCYR9DP( {/уb*QP@7iz|w")SzdSM hbHڄ"Niu40q<Р|7DM"Rm(=sHsA`"h\P)&fh>( H;i*9AbhR"di4="A=(1( ifhtiR4@ZEzgH424C$ CD4 R(Ԩbډ (1Cބ`4i@PrsJ}c@ #GLv8/=8z?ޑ)A)AB &ڨ~(iNJD}'4m P""1T #FOJiO"{8iӌ@4f|Qz}M#ґ1@'"#()u(|ӺMt:bh C`dRwh(3N4 '4M'F)}9.}Hfy(rzP҈344(:sCRJHCތcд7(ə#iOl w 4*#) UbsK< 'h HC(j'Kh9"y3&Iɉg4UT+h{SB ⁙:qPNfh)| zD @<"1P1҄Bi({U 鹧zh։ J]h PbRzBgYxbzRciDfx?aJY4$@@ҜqCTc{Sǽ *>GDF$ck~hhAfȊ1h**E%`q&S#h#*QB~)RPDqT)ބs֍(P7CN4}Pڍ#T(@䊨GB33ީ(c'~EuyR D#D ɠgZ rq@@rpig44MP71ҝ@h}GZ_ބ$i~i&F8JqP@)@*ƎDR8ӳM wAx=$fNzPzJS1@Aj4m(hR#Xe@L℡S( 1H4zRT}P@J1IRy DH$D Rb84ii"(LzIs@y6"`PSZ"|O#R(MJ$Q981HCUzQbh? =E4H4@I:P Dd]rjiPq@5Qx{QPhT <}ꁼqD MC(A&qi@DިP9懵P(>qB*P4EM 4RP69jq4qKQh4yzR怚Pވ 4Nq.zsJ1jA<ɧ+,c$Fi~8gO?7@(Gi?hd4tM7T@җ 1P=bsH8*;1N@9@4 S&M &)t1K 1<xR*:)YP,s9zcHڭЏt|P1Ҏ"M zHORSDi $:R< jGfG3h(h&Ld4HDڕ#$)҄#)f(sB4HHhCވZOx <l4ЊuijzP8x@Tq>7JbتdiiQTN& BzQ1JA*f(uP(E;B*P&{Ѝ ?TQhB 34> ;NMVEPDtE5T ?z\{34کGqHa 4>jAhtGJ\{3@Ɛ:G n"*Mh@s3?z PNU ;R")ƛTfDWzwq҉3M ;4hQh<LD@f'Gjl}GLRޔP!tyJdP#AyT0= G?D .3D5JJqGB;zDE},̊X揽.M޴"h| HuBhiF(A8dN#5Fcq)õ7j%s@cޏ#)CB:B:P  G5H0ȥ;( "*b)QP 5@:qC=DH{U1SP )*(L<(BxJJ}/ʊyX95ˌl["ǚjP[@Vzrj4'*uM8|c);Xi  tYXy ]Z'`x)',QG[<ųoNTs\43:S+eK0 $yGdb(fqD<`T=ѡ@Hj=)=#J ĊD9/j0("";U 7RhC@ 48@1@9ym.h 4)jP"|3ި@ ЧdxA(FLPT 6'杊B #4ړUU244q&=V ff*Ci>s8dF()Z#"@8'#T:)4#P!G(m ӳC^f'@iGaG=s*!J3K9E.تߊ ӏ4⭒tM@3@zbP7hQךCzJfqM@r)OJQH"z34wvLbQP/8%\MLiF))Uz}g<Ӛo"*{ud*͵ uʒknE.65[lBB }_+/| 8[Rp\+~]VW b` E{~慦}J$׆b; on}dھo2pQ{(n̾L[YKp~b#D۩AK)BDGJ˭FP\[߭DI&GyqMsIN;̅5M62 [ct`4iaM87$8[~֍4녡e%KJ6'kES3v(wIRV-+BI2=ޙHHR`8PR=qHcwJi #NM4(3HQfEҁhQP4,d\QQy#4F3D u@DPgЧ;P(8y\Ѐ1@#:P`H|Q@U4vfcP)G#Q]Ыhb## `){ӈ"@Tv5< NGJq4@0sONq\Mu88G(MdcBqqHq@0EXfHQ'1(M3B0=)&IyԱ)֏HL )FZ";M,7J1HB)@C'':P DQQHޔ M.<P>(b)qB}{SP cqQ4hQ@83֔g tsxɠG^iIPjX3NHQwGH5( %w*<Ё>z]Ngf(KiQTs@q@)G`qB 4OLyp~԰jPf0(1@J@83Bs(yP`iǎ)F(vTB:3C5@9S*~#4H<4]hyҌqDҊ@*Fai4U Pґ.HH6(QA ЉSN0)ucu~b)ҚET:4qj)&hiǽ#ީj4E PT~f{ (M:ZIb 8Z&lR'ϽAz|Sިh=:Va~I(JS,sqvǥ IQ=}ey-|vynp8*$,p+2嫕3L;{}&5.\xg$a0tZ.- o ֹT[m>:78-;$`NG1ԣz<8G¡!,2T~$RY2,5e,y,m%Q?~xwMonR:IrsX2ͷwWN+ Mkw;rFW%0#ܜNHlm+1\֢^ !T'W/GޮẌ́q*Kͱ8LHȮSNӷҒnηxY^ݤ,^ѹ5IS%Tp1_Do6෹anR'c3[7)C/8RRqX/xTnS-o;|#_%keO_VmЭZU[ϝ*0GSM6jܕLӯ]mJ{nFBm 0~lbM q% go5U )*أTğY^mNrPC U漍}AZXBPR2Mv@ծhHRÒ,$t(bHNiL 84}P>h:uĚG p"B P2i}MQK1K1T2"ZtR9B :1(Z1#'HsD7Hh P"f9DO_ڜF&(G8)tp93@pfR?OcS ⼳^6uዯ?Oֽ)f۳r>܄+N} hz&;f@f1@,)|Rl)ƁN1T*HP4(`@4i)`n#3D83 qMWN8KQCJQDj1J*R8DAhpsOFjsҁM;F"f:TM;PZ hSJ(o8HR46 O~*~)$fb, ?֖(Ўբ|SE. 4FI*O %iPс)>V)BVTGI nKER%o:v W>|2Z_R>ǧW-ܭ) RD ysWolV,C JZ6w6V^],mUځ'6>i.Ҽ-oMeB&>IQJ-᷶`$8e8`%`] 8/ ;þ RрeK=<עs7&sG5:tV)5mLݻ7m: ?|T߅t>紡OAV//tӗ@pzOc|m\Y :uԆȷdq?TMֲlSmIިw# n nS(OWǗޟ<5PgɁܤuY߫c+HYEq4ǘ7y;܎<pSOe))lju-!JrPLLEyW%\nݢD}7LDޤ}ͅڼ9GW}%ii1""%P9'wj_1=c3^CpzCm)P$WɼqJ@,fG2{2Ibx" Z>ZU [g"<]РГ4dPzUDJhiRJiT~hU > P84x~(9j| PM(׊&@KHsP6$[!R[2 IviEH)@p$JGZWoV3TY9Szt/PpjҗT{,byaRtn8-e[V%$s *-CKbq#\וo+h)P@[BPRkYIs~Lƕ~ZGV9>DqB+mծdžp S[G^\pCI=r˽*P@$j\ٽkdlh6Q*?O׋'yu6?V﫪$⦼'onQe+qj$][ҬԵ=k?ck KZ%AJmz N~/5(aŨΥM7emj⽻UU]zoph69 mNԏH(zK/S+_Œ}{./gMݝm6Xit+zVuuIa ȮWIx0lRi sz^"l8Z5pqh*qf][hZC6iJO_WoEƣuna L}޲uZӶݺyA+C&?.+_5"bTN׷)\$OGan_epԷOwC%kFaQ}mI *x]U扨NvI$ʆWI5?tlnC֑WQ3^ mNmF[U*:=嗔Zu@>+JkUtͦ@S Os^;ƶaeJ˄uY֮Z$@ϰt+HVk{H_%\0.7eJ'3՝["ۇ\*KdUU)"PNUHSnٻR?5~4q>Om1<Ҟ ׵;_J휻mFTDz.&j܀R'kۛS}l2m]iղe;H08Ӆ zҹqeW ^I$wRrTS0Uڪ+ di="/8RmpRE@mJU#d5Lo! +w];K ݲAX9$/]-w8vkHJg̼[q(K`*!uiNmg5f]i k@=֞ӉQrg޳,WԺ4!+zHgԕ JBwնe]A 5 uxy%#Xq)dILUk4򔝄 J܇ X }svtT:l\,&ѦB-Vn--T@J:U˥\8u]s Ui}=ID%tn=lq»m?5byT`)\E,H4vR>ԀPJYGj]iM!3H E9~jGO*ELrq@1iǨ&zmif2 DfiQڔ{*s@X摊i3NP 3@AGl@qڔbFhW ,^`#LpG]oGRU懒#"42Ցd}2ض R2~ӊ[fegE #uZ\@ZRHA漂7*t[;l[֔Zg,u=A [q++힛K㗮\;i更?2"#TvWk~'svҚ㑮 y@3cYG mI;Tڳ٣=kze!G_PjEַU>f\VEˌNB=ޣEXJB .HЀNk?\ttzl,b2\K"M#UnڂުVe;t@H7QV&_iVQ'pd{+-nTy9,nаԴuAR V92٧N6ZhI=u RoP?Z>\.y"6K-6RAO3]?u<5 eK?\5hzfؖⰁ.Rtn#-3c6Jp*BJ[hIWXc~cxs8Xw2 mlun[Sf 8Uʿz) W,xr9[TtH%Ka">!njFjlhJS?},Wgk2O㈞v'Zzuޥqs-׎$Xڻwt-XLnZ}ZCm'q\ZǑ8$GL1K;ky?Q? 3ujR?~Uo I|T5TN9e rjuSyjMqmx)δ$%JA4}QRajH=+T8K.F=ƚۈiH.*csƟnk[i+QVҒs1\ocKCЖ.3,7p8V"kuYƤwzIjq떙u ڣҡɮ[J1OU P\H0ڽX:9z;:۴ N }Xq}J.,B*P)X2ndT[V@@*Ia]w՘٠ޢ e ;=ѵNO\@kYn #lOh[TJI'0֑_DRk`0AQD'ڽ@y j<&;ֳ|7\l4 vVw+WA/jѱ!Jqq jf\#݂0R~;,أCf\.$9>b;׵й Tv$[}k_neۋT!ڞs]j$opq?gƄ<|JSdr7Gm׆ž})ĩ`yhG ɪ~>+ o ; \ }|)|H}Ɲu2-c^jqqvΪ^mz#'sEh}#VT'rz* ٭ĥ%*IVF? V]TǨLZ@p8R댔,Ő[+\!CE5-I x3KQ/!D+g* B1?jU˴lH (SJp@VM= 7j IIq)ܮZWq'ҭh;fy0-|Pޢk]Jw'sbRDciF{eSBt|"=Qj6$mD*Hڨi[[--Cli+JɖSv[;W(f:T{jBTRw*O3Qr`vfl( AGaU-:$Hs\ݮͪ/jVLyAB`GG!i€V/#M]mA)[mMR#詶͆_(eMT~Yh8yinC[.)IƱ7vAPZv坂YRl;|rIeu:kebT! :G :biюsCjhGYF)LP&M⟊i"@J#P &(`N*"d<Zӣ ($M 7 ◵61ބ{f" 2)349A#f `jGZp@4 тM$bP9ȣ08#,n"&K9CH4LE,УHȉ׊&#")GPidHDq&DcG1HU肜PGNxFsDjDE.DP@RD`bP 7g:4>(w&)PXώOzs@$Ѐ4S1k㧳{=ˀJ&sAWoBӻ`IIt3.ڛ)Qe!%c#cb1Y[L5r,45$ ҬZv(%&0{?jkz6BJc@+gOiW6S[V T}hَ͆ߖջR*-[q=y\SqDzL|-kT!GۊT8˲K)W])pTTxth[ZMq笼v" I~m\[1IjS050խ.Udjҵ[]㬊mo^t<>wV]ݱom-Ƿaİ씮?<jtnIy.ms6l;o \$*?[(m ZvViWEիw 2j_t=IЖږnD|[T$J4e5x]K=hy t^]6]i ޼1s%j)FJvTʙ.LW뺅aJZH$T6JKo7-ѧ%*D5}rSʋ:uRIB*i@md@UpR\ W22ԇXJ(2jg,YZPQ)&Mo7}oځ4ˎz*|E ~N&c\,/ZIm2V$6U+=+SC%އlmK;Vy˯QL˱eˇ6pP)''TB%p:=iU.y iP\?&5vU*rk(i.$g4p>%nw^MjgVn%o=f)#shQz]m?OT.umKFܟ~TdP \*ZjZu +V)uQX!rU.+GGAJPd}گqBtL{GsNi%HcefӦ['91]=5O~^mA5=lˋRw([g'6Pʀ*m.H=+SPRP83 +KY*YG&k~el&H.鮋gl+ ZVD)W);tT ֲ PLI3SJS{LypUJ$+ȂJoTV[l\H_ ֪Xr.%Ѝ=O?u r̴n ;'9$m\,%Kva. pxm ڴ'Yn Y:#pe.'+*V q$r.lGpSqNGX<Sh`PTLsLqŷoy)Wxrpvin—[a(-M0ҋl ܶPmuKf)j+*?nP//7 \ˍ5 o&۲d?[wsrCiG ēҸfQn1[U6B$(=S.8ȿ%_E\8mDH_r;m#KiE9'8y5WO@ִ\!JH@Td+LNvޟgS50Q8w䴴7c[i歭s{vV%dq+nRm.uk뤥Մ (DkŝwYy +ujܕI'={EcxYjL؋}*{mZsWgzqC9rVʀ\:ǝd3:+퐴[RJA$ַoY.7" A6hY7$kt}KE:Z=[OV_KaݷUJewvwb:UÀW. \7l} tsrG5Z}: q J ]ЬmH&T3wP+j L'2Gގm0\$U RgT PD&majH mxeAQ+2ҏ-Rz|hyZ[p4 fGJz.yw ^AD)$I)[QqJk*I>GsiŴjopK8c$V3.*VK(ʄt^钖[mJ#Qm,zP#=&&Wun}0CI%o:M_[F9Xv&Nڙo RZ0>ա+Eе0IBdpM:Vf_& , TRwy2D`T7Bi惍B>۴e)F+U8f'h^WJÏfJؚqz-DhQYԥ),%F) juif uߴ(j=l}B$K_lJ.R'[LЮ]~mCILrxX:cR6v BRPR0z\mBJL(J 7-l>"/]ZXBOf[-N?4ۛڐ'v"S+1*C t4cHՙR*.$za++[J@JRnZU {[;=M K(\iE T@@5*V‡ tL= [{- oNRU5ƴ4v HZBpV.[1|"pFz/:>E"+tte[G(N :VJu;7->xm0M=.@]nW25mUh ) W?EU5MC" l-գ!IR%JrۖsiRT?z; ]hP+'NTۚ9ҲfQosQ8uC+ާXC$+0UMgVvڋAC = # VzMi[H׫9ެjV7#dW<=5\vh_K.%pT;(w?x6Z@R'pJ˕z;(Ym6}EY^zc]ѩ\Z6\h6J @ӐHGJmRV P=Вɢe\%% OY=j r>Gyl$6d;p)%PY ) $$O*d ĩ# J)IWn|{u)aA ?U 1PJQV76܆\T:n)J>=_MԔo-PͻyjPjBT&mkV-]`,IjuZt'Z(?LJ.Owh(JD;f)+F1؋U6VJA#Wj")8]D^-lnåe?uǵy.]_(['y܃^9ݳؿvղ.p${⹟^jI{t;C@ 3՛ào_[do_d1^tI [Q=ڜUq4{dźy<]pڨfTT(l72 ʽ{5T2/ \zZZvm6 W?lSqV[ @Ԧ gmMS!G]5G){u[PTWY)ZDInt6.$H~kU@Z(9V)$I=]TЦXgڹ۫nlҥf{sֺgerbaB3}Q^os|I[^v(FnY^2ږzGx݋u-ǚص'Jy{n+CCp2J@ZUٷC/2H_HVkjNߗ|R@Ɏ3MU>z m[0fBzFojhRw ԒHwTS-w8 Y=.˄آ`T"6!$U◚!+@ \RspҮS*I- ȜrwHq 8PV.nm)m1H[-r{ R%^6CiY\<$…ʖ+RVsP6گ2'<'ޭ-L-<%$ɜ|4oE1naD,ϔڊzjK$*(FjŶx ! RG̤֯ނz\VY w5\J  JSitjCH<+\aJBm2]2丒 /j~b[ Nح \rD,۷z[I LHkSN4ΟY{(TéH"WqlD)=y=:RC1^CZEh$, ^R'ɞ\*F"c9YJkgi8EdH4ɡ#@ 4DP$T3ޑjҀRh`w((3G@1B"4<)9 jtsD83߽Ҁ ӈ@F>O4zP–hР}`R"E3@ӹKMV"44O/iE8Ґ4qi#ڟ ?zPJ]"@hGjt@1L85 )cdusD Av:sQ"HED(zPqACO3D~)U cH.1@1B AO4zr1N0dqޟh*3X}Gl2d'D4"xMi C$DS14bcCG15@84#8 @@1:*u;=F 9jDGJ3C#~qH)?RJӌP<'!ӠE:P PjC9R 1#FhA]fiAGL)u8,ځӨf]3&i )D )5QFj L(Ќa;Syրi4)\L-a{ަ.WOӉaAA'dR6lI3JZIaBUunvJ=utT=~h_4 G},H({ =lmt] {RSߌ055b()Sil^\!)@{XSn$@3޷IrL%ҝLwze`^rWB2\8k8J=%b9+./')Yzޑ\ş2n9X7JB`}(fD ըqzG=$sjݳҢFC~8ӛ2c9>fࡈIUy[x$ ѹjV 1*v PJH 'Yµ,\JbIHdJzֆ{ujrI#;nT錅*HZ ꂌ HOZ%=7ffS +oLܹqNDHҡxm&2v')J@zB}4ߩ R"pK6ԀԌP%IR;WW+R m'tUK̷z/u햿9"Lz{wu۷<@PkHS`IRHYvkFZ z F蕤@]ROC H$}ɦi򒰦[XapkY&9gpeX)T+Cɰ悳g\Ͷ4J;R"Gf'O6PLtS~Z,YeJټjguAyt@c޵~ISN49i ?5qqy-EBg\'wH2l-lSn\. $M-AK -#Cd%'t}םiC-wV桸ѬJǬPz`rsMDܺښmH'$A'fP.ތUgԔHMrڇ{˒EIL6{?\:.-8,ŬʔORk-NuZ!~tFf:g'+3zY.)0y]A&VwbݫOC s =߼֑jYqAo"hmI1jVgr{־ep-*ܚ47R 5.XJ EE֭ }- +^ ;FINv"U)4UЖZWeXGec)(` MhHZ9漫u-%^B?ޫa oѯl5+$++Pqۭg~*ڍydΠ8J6kYs4DJ7IAqFO2}+ ASשMYJѻnޙ4 }JTAoz +GR5*VĨ(u֜HR3MXmmJFxE(JōB)Pl[JvTHHI~I:;\QbRٱC9fu-Чn1VtK*%ł@Bj!րl) OzgA6VYtR@d[bA+N= AW7vϺ'']SiiM_j.AALH3io-=HlGo9#] h9/<;5;+[@JPu1Y M @J6(*&!I${kWF]-mhq,INqXX6$$aGү% A4jڊ'& X\0R=b[;y)=~Mtɗړ+ 'b-k&fN-N AWk!W8x#XkKK[;~f,l_zh yq>kΗ=lwJAޤYWia+qgi@DЄ۳ik]9'r`TImW- Zt]?Nz~e =~z_7pţo- .1GWٕQ*"{NYf qO#YlZqaa{LA ⺴!{T%)(1$c0k>SG睫*$pr*{KQn)d۽b rioϽB/ Aڥ PV?cQ۽J!wSS7}mr\j+D J[X9ryem\H8O^;aǖ\AXLYv~KeE)ubv=V1FFݕom[}Ɠ`W^{UtvRJȌEi;-6%*"D`o.6ض68<ӔGޫh!DV:W+S[KN$J\iaV\`p}v體ړ?%'jpsGQ΀b(Ehp3DЁ=hM@Ҥ=bh{S M*C8ӵ'(PziiD #`fϵ;RK#@4tGX?jwMsNB"1K@CN#(T4(MP@ϵ8AKG33@0GADSϽ6' E zеDqxޔHG̓ޗ8PP ӏ1ڛjO,E($@ D@yd'=3BXأq1ɢ3ACHJ3F @hb: 3oRޗ"GnhA< F$ 4H@sJ34R1(,NhE;A i=Sȡݽ 3Gڑ5@ MHvBڝ3H LR(Q҉i?JwX4Kx~) R"iR ##>JP&2?JDHJI5Gc@4Rg4:Na[gru 4$]hMtvиt0*Tzӌ0,]==~3ʎ1kܯmƐVeK{񷱴`.WaΥnlf#.ABf@g5/~PclToaJ6\iKk )Cޫy(٧۩=J e RU@-aҢP(B}fv]._ywNr6R`-4:lLBɮIIiyo<&SZu7 sװ Y)ڲ|K~m1e&?ڣSm>cZ/>m7{&HNLRWϽG9:ރq}E0r|UfAm'sZ:V1GqEARҀ}4r;Da@[G~`V<%)yR0aRblɵqߚ)mn/м%,r>+J/l|Jm 􀌟lJXz0e-HQY^,le3M[pZY4IFsnD!A5l(R+3=y7wJP1*Ku*eBLHRXY@1+ݳQFv(y݊6`$$U]Jp?^*[[][h)̏[7+u[5吴ۡyܒ9(ë-^KBDn=븺m t]&!j1?[,3n6Rn?=}ROJotL،V?'t㭝S3yK R:qFzԃmʞ%K>ivI4:$OjnmN[~O\lVl}j᝷tJ[Z4?_4mp'rJAzEpoijuD*izd Ǎxl\$3ng<\[o^[i.6RJ:2Rr 0h*PiY;<RTgk:۰R]F 2E.A>kkG7BLi)#ihenFl{Q$-M!0d XqD2+ol7 jqkPrc5&^zmԪ[apm:PanۋҖ$mxHVyn[;g)`[Mg85֓;4+rDQZ:.޸Q R&da5iQ]TgϖA~:Ƒ5-{)Z pk9oTR(}Ux}S&)\)k;̀ eSx+PNH![@ DJvq=Q۷B [[wQ'Q0;iRܢz Z\1=hҗ$[xL6~`c&-]p^]:TD :It!VaZ ަDa)5חN:qN\(ˎܥT)@;PT\V(F\ܲJKdnW5m [ )@&%ȞܸV*JT`uvBI#fS)}Q;`Y _#d[!Ă~AK;T?vRcְݽ6΋M׋K'8*Y-6IWɈߊ'ɷʜ~>R{J./Oq%mBV*֝R1Lzo}72OTwa2"fEeeucj҃}jmwHǩ^ImZA vJlҙIP^ \S^p*+YZ].-JTďvAv6pn;'!ݛ*ZK[{Nh#3rMYQ0ye^Q +oz#Z >`kj N.4%_h-QZcPFW/)G;t$ֱl:טZi;qē5莇JXvйSrAQjݡ1ylsVVT)(<$p#>Iw,VmnJTIJmmm+}$x=ڱmnϙn[ Zyoԓu:Ii\-$#ܸq+(B1޳5X0Bjfݽu N=Ȩ-&huTBTV+^խSHeB? HUumvj@CMjѵʽzTyTSHDTR6 ԍZ2N֙ FΥhO!)*QPxPIoijBJr?Z"@垬V* z§ں|wЊ7qq҇\ӹ;[G`D{\iA1ӽ.P.hF(OZF#)ޚjء@)f4@lf8uPhSJ&)R{ЧM;Ԉ)PP43M3@ Dw P@ӨAךF=3@MNT(4c8bgL Y@$R P9 ҊiBg2@4j")r"c4&($(E"(/yq1Dbb zP7#GoC43N4]({M$N97b4"~)üM?JnzyOE4iD:hӊC9@PWD@P@7f" z (sNR#"uB4>iOibB1N&TB('E z*Zx5~TymH"bu֒ʆҴ}LãtgʬJ6rd} Jza]2?b (q9D ibٰ2AT.J)Bvr{ PCG0ɁϽUlnsiTv=?OK9 JNRA&?XfbNu2 ԉ+ qknP$qRYS#kc5:BAY{WT'd{m%sr6+~*<.|D*ڝpmpm{boxK H^vvNi|čn$(\ŕ>PGl[FÖO;I_7JܜuYycaN;ތ /awm RBܯ1*i%R"@|m+.\=<_KJ G^mнԹn| >ĊO[Vd$zZ"TGf!.[2\zСcy$sTMΙox 8K']¾;w"1Y-- X֥ ՜@Jԇ[ޕ%D(jTUޘr\"ƚy RBIR RHi NjJNiWjlݖ.H}L4d$ֈRt[$>ޮhn-Vˈֱ+W'iz/8e%#OZ(2aPʀI N&ۛK{U&W"P?5 %\^~j:gǒTo{W4fMi3O;rgdAG(xT245+z} l ?wad9#$LsU4a[WSl~mV7ĸZ)2)FtŲ*}z`!-s?AXt:%H{LmaHӔs9%Ƒq+jgQ łZJI+u@'UIzu{)`#\2r80mq˿ l!Jqm\h(o&a@)Kn-v >W&pKiUS>Pޤ7EޜocS%j‡߷ڟy⦂س`[nV &܇z PcVl,;k@0tz4-^ODa^$ⴴ1+M!WY7?N- qZp7pe'1]}QN u;ILymDaZ: _T~}䑞6ek_'P;{~±4Ʈl[CzhoQp zSxV}V  =ke6md#c^eoGUQ[4tmBs5fIKj*aBYeҦtBTDpznԲn[iP3zxG6ݙzE}䶔$@& h^7)[jV*N UuMRw M(( VkB")PgqMٺ.l5[ydB}Lh]!6RTH"Lޝ}>Ӌݴ;ikq/$xC )I<$uT:p )~jTP[p +ot7jJZnzjhmGY^ 2+V0Ȼ #Nq:z2ITmc˄:ZGGo]Wn.i{[g9ڋN_[S-5:|"zGSJ [@ftҟ( h:Nu{rN0swR{̿F4nnT! $nl}Nv6}#l$ӖL!n>ԟ1LGj\h.]߭W&a QZWͳf1PKo(gҪKN6z%|"ƞlfn[-S*m=KN6ګuh=On<*:V_Ps}.& $x}JU5|Ҵvٹ Ӹ.Aˁ+)ktsbC_[ʓ9F޹+I 23jo _-PHڵ=l_afn)L'D,A@6$稭&YRʈt$F{յ>TٶS)ƷNDqoۋiܐDr'5?Eo.uІ\d[B!;S+ѼB>BJ "w* cĚe)0TsH}yvVuIR1Y/TBI5Z8}Y[k% ?-WzX}e!*hbN]7ϩ´aؤa6w Z.E'vy՘sU A(*pc:~N]-)J%j#qXiٺz[.H+JnŹ[QMԯ^)qǙ9%IOjXv֟RdS zԝiywPT ]^n-fBgrF+Cp kryZHs"UoCbjqN8HiyN,), c-cQbٖ-,vk"VsQܷV n[FoeEn84mVarq%Z%p g?6Iu/!(uJ$+q% ڔJ\^:t 2w 4?*JEd8n'lMp65mՅHTL];pmrJRg)$侎$} V@_juM&P_gb615dGLdɊp$gDvB#F)q xW8 p+$չ$TJdT浡b]ȵV‰'TkOp`Hcw+kWJA*4q=f%)ilvF$GHEKgCU뺛M8BRG~)' ^CBʉrh:ll(T ,:$ꈎ+f۷>7nҷo6ퟛiQt`IR'=hsِ} ;R 41DsB;P O}h@"(vI)H@bLQ@7!j1J4 P'ޒ I\ҏjGT FzS"M) G,'Jvs@h}dB1)9GZ(B$ӏ妙=)Ҁoɥ(8)Fhgq)RWޝq=) z'{9fbjDӊ|fO@3G'P 31Ii̊ɧ⁒b(QB4mD jH)I:t(t ݧI)HP9U0"xq81%"&DwD:ҁbәq\4kK[S `ś@-A9Q4jI ܰe$zHb/v$'?Ywͧ2U@`sSeB}A,䒢WGOR_L?޲7gqRio&.7t)wɰuX6T97bþPIS]#%P1uj]^KhtΖӮn2AQE٤6Ţ۴YD${U[Zr*V*]x[%PSVnW6/|iidmdV(>5E,s >ӁUr63u7LGK͢sYfsV6k*R 5N(Ae$cT]SA0h1)>¹k]bNVkJAVpi[/TׯV}CHg-hMʑiJo]qqg2*Q N;ac?M!cUtW-І-\j2QfrO4$d] %l)[֝"8 GJR]#RFVԞr 6mZz|-HuͨJg~+2Ț"Q_ꏼZ%9`TW:RIk`u3P9}:崤 GYIBL~Qm"{t|[$&k@R&iVI`4$ou[Rd( ]e񉇶sP=.D*ڳZmoF~y=ۖ7lxiz N%)Ϙ`:#>%6Y!QMh!(+V$s]eUnu1$|<5۴ܲV3 wπű6v2ڌ'ɪܾ–LWwڃ%QzkeEʒ zT8p}ўKyG^GCyӅ#hgN(g>V-_mm%7!*b3B2ۏ)E3GC[}+\$,%I|{Zdzmz,(F0iͫȶlJRr}^RRzgR˛-'y#5rڶKUJ(g6Ktoe{qW|6,ڭ-bMMIS;ɹ3}SPcKmO#;eo [eGYZsOb̰JwdșmZw|T5mߓ2Z<v)*U7A}mv: vG$S} ;Prѷ$4(JskgHMͭw/IL5x ASbT_ڜ9YR}6mPIj &Gd۾e?_ڴOiMn<m2?K~/Z]AD<*M >iL}ϽD6lM@iPIX* ubRq+[WUm߇ 0jS&[4^6!DK*'?*ӭu]u0~*>G9%/G^~iN+Q_,W'ںi^MMyŋP#%r l>)ʡ iǽ#4jI4hsT٣h+j~iX8h/PDDS&iRU GqK)tQiDP iԣ5@ȃgI63A@f}8(Fq@69<$R"f[A3ڧqQZ~SIvZe9C*HwJi&bz{ҚJb4j'REԠ(8T3ڀSTE 41D XNҀ4vLN)p3P?4D 8~i"i"c Mxwq@{#8H("dFp{ҌP~iq#0GNQӠ u9@ɠDhqG(iA(@gN9<&:6SN(QօDD A>`LZ0)< xT0m*Y&@j9%TF8% I]}j\lYzn+ ]`|' :rOoH YB^-}%?IaɯU΅xVȲ۩.pvyX\ݥ*)qx#:#!i[>+-bjhڕ"HHI7\6` '9֨8ډm@Ԗ Bt Q^rzGHb?2xE|MmC -A"m)^Ĭe*޻ֻdƧrZR[P7W[JكsU+-Z/b #ԙCCt`ذu6$D+͏+T-\ڤ&T3ˊVu$o!)H k9,f<"I)ZTWiKwm0"w]"TSZ=yԾ%N`ǵtGoMfƆa(L`p,Mo2Ve ]Nw)m]9A’P}& ~x3֪յMZJI@j|Q7FUaIZ"=$?2R;֑鏏33>RI.;RjɃ^cg+jbk%4۷m/[MnB*H#H=Z2㍫3Y3m9*J.Y? g ˍBK_K&=U$I2u z{OP׌9v@W_֤s;j'8%$߉QWwNiOx6)Pox?-NnHEKH&$}^}upRBd{W)\♨Au5krm)Y tNT9&U-H̘҂1)Ʃ٨^%;/,v7 :[RW=\o^nrϩ$Eu"ԇPs4Bm-%%'$ | ig3)V*"Džn@pN`Msh17ӈy&D[8ڕ6)~b]Wv\t5wK<¡ؐ&WS+&\[\%Ŋ[?#5!)mq )bҼcNfӊm!D*Ql[2 ,ck'[rp^Ax-I uz/FZ]յ+XڭHBb6T|: qNԃjwƽ[:yn$ᦞ B>O?q"֯5eTR qt Lw mE@$]_uK–Y!wI)KgXIU-!r67<C~[v!q"4k0X5xwUCZnL)cѓ=Hyu[2fs\fuٲu;f.kl˟+TiuVfHaPLJwUx0Uw% -.]![)V1}Da0d؍5lC{Qxѵ'njͼ)#RWǔaEŃtH}F7nݥB?2g)/G-ҶaQcH_<֑t-ka%R$rw7o-SYJ)1ll۶0|SiioCi#<"szS*q`@MrGNA b [pEqq7RC>j.R5%8A}I7*Iq]c#f m2'$ejRZUU>j&*yBSzFR6qbTuI1?Wrn) J}!H p{c/TSJZשjBe>j=Ihty)eDbrѸܴ,][֮ )={ʹ6P}3ȩ4iү7hHFTzu%P ‚cy:9tmvoxMTnLWm6O÷I[hl6NHyOTQh7Lrv%-<$=*3ޒNqƩh- q%@Csyn8ʎ8⪫#ٛp6v$$JgwJ׭bhJLt&uDtU! Y*IqX=AF=Es+FFOn%MdqRW v䲷|ی[vxƮ'P + :ʶ兵N)zWmW-&pcIXGQF>1VGVa-,$ՖtEvW lתh_)P4n0e)VH"~+_s'HMOuNs?HsZp?׵8]2JJVBVdoQ. 6-W]YZ}Bkn嵉kŨCyG?nֳKkg/En_u>h }1zSqG^yB7eP޵T[S +Ry6l8$Ξljkr:^.}`ly9R_Cy~b@iޒJTA"dN>Sނ)R 3IBDfjGs@DSJ r((i DA#hqBN@6H?q:)h1ҚA?oRE=B `SDUF.@q3@,8=1$4qOI{Ѐs@ӠqAC~G1IR E :i9C S8{PCLH:}4 +`YZ 8]Xܳ_\_:6 kW7>wSz>%q[1Մ&Jܚ}ex;8VvfV=&v[-9e= H+ּ_^in0x¬ԦTTΛ`֟UB!dx.{{g͛#>X+pfm|>E\V;{T J@֤霣]u)J⵼9jT ^I߱gʂ[.{=F{O%7_P)R,51r]]ycr[dQsàv"K3'5ΦVX[[)\̊.{1Vm֣'Aw5r@ ށl@vma'*?w4=W\Kc<ׁ]-rAl潋7:恢^LmG\mAӉ\%DFy^y+l}ژuPӡ~mms%kZt?Ң6U:WSLG[~xeZso\[$ %{ thk߅zXeU G \P u2|ծxÅmEum(p8_LW)T:%&&擥6SOW^Z_li awi z? hf$hyw/H3k~&[Qrƙ鮙CrMkLa<!V].OZ-WJucmѰG& ;^KOZlZނ1]ira tO3ɯz!7+$yS/8yW[SmOU皮6VRrGrm.^;%'r$?yrl\j09Q]Ғ-@'U n1]p+[15S1υY¬W[|ǔVﴘGžҖv*A>Y=WA%j9r  k r]h >/xZ~gHJ~Q\ޙpZjA@}븻uv,zSn<4hbţinZ/ںVG?}5 G_{K ;QR&1[w7zcIV^hd'NHr#9Zf7pT N?C\IѸK};~k]_vT[~1^X[`uuMTJJAewWK1$wX䒨F1f KYJ4 vOQ4Qwet--XG Bq)Sx^V6o\ԟ9 SOZVhղ}^tzi}`]}[akQrS )WE?i?=K¿z't)u"謂 H]:R9cof?C7K,% |֭ெ>AIWWm #Mfu ҩ&6Pʳɬ#zMcƽ- <&ګ{VσnnzTj⏃ٲUѿR8L|fh_^.zqjy% Wb3~Lʿ:h6 Gf3)a3h!ck)N9 /VJ]ĥ<M+Wښ7z3$;csO/z)$T[ВTqJ&Su딒Đ̚ekrغu * vnXv޹_VZMXNTG1]r ,:P}y'lx𤶀%E(ɞY[F׳ɮmu7PݵRLzL.w`P~MzQ[2<%JIs9[Oe. A φuF/ Xp|G5Z͛'1pˈSZҶ_J@lğj<B6rGIjJ TqN圜< --0rwSivC*q)'o$bY]S涡ssIm٭![B6)#qPRRſ6*7.Df$*qRqHZ)'8@l[ܖmI+ ⚰TRGx"_K*R J@V~ȥBGm>IXXx*vwZ^ 'TmImceF ONjɼn 7qW4J6V(`LbW;}IidQ1,B~܋+'1XaBRRd9H=ꮛ?mueΉ޸gθh ^Z.$1"z"qk~CsL$ t)}ޥz|ܶ-X$F8~ʛWZmoݺAQ1`7WG6E\QoIb_ۨJzVE.U3s-Ө(._:ɮp q!Gv$VRZr h:xGI[aCĹi2p*m*ԉ`V&(9亝YOX9 J 0vZ\:$nEʒzmXb26_59vQy$g7Ni4i ?gmtTSz BS|C0cYAJ[ZmQ353yғiKlk+RJ}"\BɒJWzٿH6a0-g$ϔݔ$$ @J*3v"Wb]KIid$L<8vP-2DgޓVVS&^JFWt;ATҰܳ׮eN22>ƽxu-ykGKn7la F7 v!m-\\ ' =p\#܁UsL!_GxG>̴k1z*uZ) YN|<Y[d{,T$h)!Ф^Yk-VuXwwzKqRRsTZxt(TU B(3jO~M!SaRRA5--nF`q3\~ӬjtOi:݅mPLz{WT='roͦh\>a ;sY]z{zR.܂SS<$u5[V0O$q>PR֮󣟊c3𥽭lLfn8ڸ`䩿G\8Q@4* qą*vJ%h "kc̥d$LR(SI1@B$AYB'440DzDuҀ@C@(&։(j@F{W!%@-/z "E<8 RP1$⡦0#49@ Av sB3N1GX( SP{XJ0#3bҏz|cP@jYF(|byRX:tF#8$vS0sGh">$L XC@iHi8eHh?HCM]<$n^{EStqi<+Sߏx\nƙ%r%OQT~+u _čz|KR 89q]-u-S7wN!>t|?[KkQ'vcy G,#)nLO%nxFww 1[uTH@Nu[ {v_:Nݝ+n8TQnRH5Y–3Ɋ9(6V9v3iipܔjuB,bsPJZV‹a^yW JKi*J)&}^k|}ݟA<(qe0j.dN(ŭ;D&YqE +ަ[ϩ kjVEn6Z4ii;$؃Xp)"Tc R}2;淍q'-M/LEg̟0- WOS-V^ ך:R͇L)!b~kܸM]*~k'g@PSLͱ!:zV:`yVcq ^^i'&=M-=ع}[RN_QxZ}IQ՜)NA%N;i%@GuEZm2.T6~(n᷌z܊Z흛学坿p:߉<.ł0Nd߷5FlYJ!s$u\?kgCfݵԩ!'rIrOy [W (szÛS'JBf$+S]bn˨q3asofY+}ixd-c I+?Gyin\ܫp%,keޞٷu}jCkyҵ8=~*tZb!!j;Hk/w/T{՜We(m2$_NZї]6[Q׷d'U{Nґqp<를I@ xzοͩJB z@Du=+|I><_KeW9 R?"bkϼiut붺MZ6t^)wx_Wl q u*vI  -ܶp~DѪٺ7 +pIsoStƠ J$}6o^\ 0xR),+CJ^LWC˛va 4w'}"غ/7 V#]c16_oIC muPRJլTZyJGrHk߳)5"4=7wo=# #~ߔKUU*7wiJ[@BT%C5;}1Zߐ0E*A=)Y7i|C* RJ"kZ)uaSʃLS@dH(*R~k| /XxlZfCn0b J犿t%8}>TZN)*!3͛`V"MvJQ $w5/CiwL7<>'xJU ۸m;sYǁMu6+K) OQ^LR; /x_:Ҟin}'dbɋǮȕ6.U x{ZvIK^R<۰5k~3UίynRa^Z ~|j0Fo7CV璅JCR:OCև{Ư}v=7 z6㉮JEJgH?F}x_BS!wOȟz_hI6kͅAI)%5I|vѹkW̥Pw`6ⲯ[CRLMr6~}5 p (E[RT`;уo(t^M9=BH1LE+V҇P)s1Omѵej[قBaNx/^<c']jԙ$`Z,jLޭ}vSh-Yh$oGPFH5QBPڡՐ<=|Ųzw [ڰ^V.H<ʁsrG^1}7*[;8/}X^o|[+' Hvj\BV()֛qbn[.B|W MtR!~7ֵ\fSz26``LHp_ӽ@*P$ Z,\^V)mb菊ዴ[\g;wnsHJޢzynͽPnQAPWYUZ5yK`kܤ`T"Քeubeҁ[#jAC9n_.8u3gۡ녲[{S92g^FKm8|ŭ*tY v! \Cy(Se'n8`qRnV(]Ӌm;۶jW2[xC2xֲmA;>ŧ*)[>孩j%]*CijHVޙK&%W Ve5J{<%"YRqE2a A늂Ββ2[M6AcSi<ILaCGHU NZk2|z#|.-.(82VSoN3Lбڸc)&n92b3p2 :_mA)O5YUҗIV*ͳJqj[V٘ŷH_DEԵuͣ?%5XxmBw^ƅf,B{.86^?H#PEW> {'Ԛ#EF毺S%&Mc^=t4XuҡMy;gie ؼSmz(=iur< pj ?mwZmej彻JvQ`=}Ş O-Rn$UImJ̱skKq60*}bz]syٗY=ALۮǭmz\8OG5xa߀7NL̾& ׉(l'"wAp5;Z@JҐ00*5^8 ![ǧ{wc<ܨImعK`V44P2CꮂAܰ?jVTO|V'㩛gAJ\%\Ws&ͶJ5%C4\&+J5ڶOҡ ^i-;vOMN܄-R4AP4ڡnRBN@gD5 =r]q'*3CV J Qq5EɩZ=li%˫o I%[^=9n 8&u-?][K/:X \zT'+ɒTz.ν?p\3+߆wo&/nP/IQR:th-7%^fS*6DZ FGzRgLU;<\ҵmN*-$KҘ3ie7R/XwKOElJlWx{];O i֒Fҳ?ڽzhy^"Fw'/5AeJh D :(GDIQzBqD0nQ K˄[Et [[wrH7zv`0rIG"tZoo}rk'Ol#OMã>AW^[pLtW?0NKsvdh~-t0^s*Q+vhWF29#khiKhyRH?־&L#-H4o6ݶ|$?zճn(=lEssmS7He@QRHcYohVҞloG+=.%ÖZp#V-FM qZqPwjک.4 >TXR 5ZOi:BpG5!7Z>VH)&35OOmMʔK11nI"Ȭҋsj]= GZpJ2HG<h@2dq$uf&[cE>B#ڐig&i( H4яzh4Ѐ4h5 .ȧ#A)Ʃ20gvءZ"hDsNF;:ЏzR"jM{M?l&JbaD=GGoӓ@3m5?뗡n9u0{,.Sz79ˌQW=֭~XoЂBg{Vk %EQ +⛡i:ngIHN7RϹ8΄[(s_OJ>>͛WXo}Iڐ2cSÆTaWTe {SPB&{Ze (m*Q<[4 ]Ǟh: x+9BO&U+WruSmp)#x$ @qW(6%,˭:Im] jmy+{֡7M^jJ|ҘLbAɧ)_< GɲVַw!'|I99Lf˥QZqڭ[<׹i%*FaXjB&it_ih/O\@ZJ=0QU܄Zس/ BXBwV]m\)d+rX$! 40>d&zN%:0 yXlte4]/Ԧ-ZZCQ! ۽PnMRZcq߭ [)@b\-QUfswFe/C]O=j4I3ԉZT-,g5ja|3Ԙanjŭ)#fOkEVs B}hqRܢ WM*dILviIyjG#Ur5ͧtm4tZ5mPE|m#^M96߬u]vy!"cD2៊ e@T;Y(˳Q(G##P |6ޥp lЏb1Si-N-Z]}SҸ ~%]^xJemE/e4s^1\0E8Z@PU3UV/ڈ sYdy>?,_)2iڊU@RIyhέuY!IjQL=z 'Sv.0RUČ7> ?6Yl}zAK?̒8s O"Mނt΃,ÎK{)=k5{k{;֠$r~+Iy=e+uL+lHWqi[L[:+miv>Rt2II'~h$>@~tkH~ՐTl)=d~j~ Z -V]O!`^7N=MXOKq@'÷Zs<o.~PbOګ6|^S$H0k4iJȒI=`$k B]ܦڹWSFKղ{n >bҳ'CotZ#̄d'WqkVw@e@KO*fKֵZm,-e9iֶ.ompT$+vqRxU⮭ ?ⰭD:$ҕnw^/KhαҺ{ kkV99v'Z-IGHh\_SrS:R?h~EӮZPC(i_ 6kV +v&Ĥ}ȮO j[Z;|A@kB:NBWmP]ᲳKC 1rJlvݝɷum)znMkPEq܂$$1zo(myyl *7.걶qv4-IVMN^(vީ\"%!zxTk|fжu KvK (!(D~_m0n493.ҥv+򢕸y/V>NY+QZ?''D)AJ{LɯgOh[i"2IWHɯ?k⋙oB]y7Irc⩳Ѵ7jyi\1mvrz~ƼZӿCfNs*meWG閭BPk#>ԚSHiANh}ͭ96n2^'A[~gL{ĚDPU'Y3\_Y*F]mRBԨU/Ƿx鶶t`"iBm 4FsSأ7q⫖>yg3clf '1?4[6EJԔ0=>xSK~RԋT- Zvel1˛+b+˗GlOB~- tjk{}a j/~%VeBVP`cOƿhVWzaJm+|IOzϋ9('7Wѕ;3mqhέm/}9J`ӿm|*BimrZW歾$A=fFU">=3˴}3Ǝ}/QӯbEZ4«]wLHC)Ow[̼lJ` ?ڶ{P`j!ønR2;~B_ Gj?Zt o$$ ׉ 7 -OQլ7qn>)GٮK3V МiI}>pח U7gL$Z[R v_yh>ՠDJsԬwAm}@V9}yc:gʞ)Ar纴h73i8WGYW:& ЦhJ]v׶rҤ0{Xn31I]3f 9ta-OFIAwNiR mkL)“ߊ'U:P@R;bQmKtsWJfĬq|T7/v Hwn<]˰>`">اhZ;.Z,mIJ '0+u㮦Ż6md6^'߽FԕsnR\+$HseorfR,gEA]fbB7 X_F,®-2PBT#<Ú~W{!, 2zW:BliHq+h72?7;L՜alJ휀*0Ek,5=Q9]YRTd :U9f9UAo}mO-[!nzU}quB6#5-;nVRJGj8Ζ^Gq}kg6@zWKj ߅}\2NП,w.[n izbuJTD$Ou֬\!R q x5/uK-B܇I() I0Xv! EFИ7 {dpqVYS4V‘%$`YrkجYf¶;Uȩ.5D+ԩºݭsr\iK)ȞXZy x:$U~jƟg9&7iXe%3EԴ+4z!MnI>^sc$p>;W&)pP峷cS.E8sk]>e xڅ.,Qj§bR<⚊= ڳqWRYvZƣ6ݶYqxJ@x3|ԅY>Dzt`do$%c۷fquTu{KYSjJ=sڴp[p6RVUFc_x;)MVWr%Avf?z3N_&{KHKhs*j.K.k1ޕƢnš9mWڹiJ-]* Nקr\#l;bKD8G?SgLamn*|HP|)=*ʎ*6t؏˳?֧SjxX ${FBB$) kڤ̓@mU]H"}d:z_h;jҎSTEkV9M1-vP(|%W4Uٺ%ܓTEA!$@"Ý_yWT@)H `Vu2wV/lbqTZo- <3^v6„+,xLaEl]rfV|US>fM`'o [VRT6 ꉁn>R^Bc֡fޢ#hlq_SVYy8yeݳj.)7Rz6s|(Lر=MWHb~Mh9=Zڒ \6zg&7.5& "Ʉ!-Z5H",P)уX6ݮUUn,(iJr#?)OqFш͵Y eagib+b̲txg( RdE#]` zОq |RёDq@fisNT(cB=)(E E$S4#4D 1֟4 B82i&OHNDsެ4Î!)d$~nMAN5/GHb34@w.D]Gԙ ?C}HU@fI $B5cpՒ5޳eݲ}Mw)QMÑ?M{PH[(EiQ'y~zWM}b%ImjֲFyBbRWxIq{F~NUizܤwUHZq}3. v#1l(}?^H NjfZO@&O;TI[*cq1#u9xW)7 3#B^H6?:Ez$[3jպm %dKD#Gg֑(F }~wk}XU-lYI df SJ0c񋜩{=9uK;%.+Q05=h26IS`1^g1zu\,GQ]t-4݅ٴa(HO89;gE񍆭tmlV$7 %N+?}a7*ChI-hqSRe\VH}$u4H"sJ[&*$'lv;ʀ53(aP(b[]Emm /ib8M)ž Tج$';562p:^{tnV foIN ӂK)+HljF+ &;Tm$"XHjV@3QN&P19]m=ݒUSfCa#Nקi*K$9<əX]Z>kXHQ w"*kD_@h+̘Ls[ڸHiz,Zϔd-W73gHzGxÚ76>%VwV6}5jZ巗桛N;nJO~׉es %{C?WHnIfMծI0=ÑEs_Et7J_o`Lu{I3Gtٴ+ܸ/f$rH|XEai_/4ʖ0BligL,oߵ۲Pl:IZ"zrNJ$Q+V ښ;V;mH~{ܸRZA!7~(?5WY!x Z=ԮMs!GԵ5:J2V;Ra 1X^6V4>?s|G=_:M6:Д% n#lzgt= [ jO)*?Ȕ+~-|TG^Y5 BS\JѧDa5}\\iI &p0>])s:p(hP>xМSFмgxB][6vv)iP LW!ULJZ-mjK#2GxGEo'`mZ1{Z}ZP.?{U ..M<5(8.JQ$ל @ny%6HD(q-n4Zl+ytD&Db+bKJ[y)S)}QB6Ƣ .J+eow MQ+W`Oנ[/Z3iۧSOH5YjnkZ o hWl1 P?F^h5UPVVVz^DBqؿp %3ʀ^e3s6%E ,1eOLK./!r]O}nY+d[>ťnhN|$ֻ UVgvZs(JT!Ȕ$=k3EK\Ls>[1ymam4Is^PQn/Xjw0O1cl\}MsVՊam(2ؑT[|'pºulϘR=D}+kY[y$Grr81mվ;r 2䔨mڊYf]ީl j-o<ۛ\WaViZ]so<ҽI`d=kS!nMJPuo۔[\]OC#< spWv{i~m6V֬GTP&Zo-hWt)W.  aB&}颧G_2tN y6Z1<_]|v&AZ{vXz6I-i]Ozﻣzplyv㽇ʮ͗mVۇ`#ۊȲgUQV!_6c\[zH%Ԗ@Kg)|:&ٷB0BD'=+;SRR% #V6mm VXPLVt_܇ ]y<余Q~MU yvHl۠s8ӻ/ ~A?jEvC!e IYJ> i{ 6n$YoyrVws<ڤ{ybݭ$jSrthۋO nyX?szʲt]:8l '6쳡k7Xح7Vh(rJM!MJP=6n+*#jc=iY)htC$?5mՕ_Ūx]Z)[V)#+&mΜBPẗ*rㄤ$Qx$۴5EӨ|%#Q䎥 ]!nJH#jz֩L))@owZsBgPn)oA=Z4^Q1v*QRw vr|8U7  /ުjU2ڤҽDۅ$IW]iwWP=E^LG ۗ¬~g8Vm4WtA%PkMX4%2d{j/5۸K:SvE+uCrŅbLVд"NyI;P&4k4"ZwE'ڠ/-iYoqvٮQ#@b} Z; J=\~nKO-%J\;xN5wcpS RBBȓTfYWCqJPެ(;Rf=Ĥ)homu%3n@tiqj\.Ê#oƔvM)ivbRs@r8gh~f,>RTL$vmǴyCM[\e&P8> RBP\pEixuKnju(ܒ=(;RwBU>W,bBCKVw]% WUt΍7p$GPd^y#sܶRvG%3֓WTP~ZqݒX>ƇWjͻ\!+YW]x/U)/՜p>Ej*Ն[Z\ʖd(௓;%#݋ĹHjnhʷ ")i]ץ!0k״d5 BR 9jvk)nɷ\P; o^/:Ggy_TP {NQspBFp&*ի)–W%i woj)y >v쟙IEZ8{9nwo1.&{Rz64Zpa`*ޅrO镙/ĥ-Ԝ)NnWUOp25iznQ.!iPzנ۷kl$$ |_nISqHDk:? Ps_O Q4.) IZZ=pѴ\cMn7A)+*FʇoڸCS˖RqeZkiyzi-w1ZŖSa+"NNӋm@v9?+Km^r-D>) X T?7mŐ*S_ғ xa(2G&!SO/BRQ˫를Zgoj@3RwO6낹sS.[9p>ඁ$wӯoGŗ>M5_d# pdA1Y<_uKbRA)[F=뤡iwYz[7*-Ftj¿oP6Re.BG]{76yfn7 JVVV׮. _Z%6&xV|G͒{zn+_%j^%AyЇZc5eKJ-cRʞl=9^y.UgnrJ=^"`:ٻ< :Í?z뎼C (l=#3pE#zdzU|ȎW.\(ƨ׷l/UsnI'ϵij\\l%>6Т!"bCVYd_uUF+S+q)D~dC(4!sƼ\JNLi ʔ{TW5Smk>J$|U7t}Ivu6 =ѭΥ.T20cs\0n ii!20 Mi%&^M#}os0z~*KvBs]6 >H'rƛujR%.G&AQErLM 6B};b~/.ZNҬSj֞'NBD*Ofw: ּΒ_5#qFzi>.q<}ͻV-V/[>/iIA kы'8f8یv| GfJ*#.e>VθkE[᭩J嵶HGս kRP@TMeIܔVgP{C&7%uZ)E7ήpp*߀2dbS4ZDrWEvG_uܒ⾬;=LtM\D!~ִ<v^*+tBҴ+H=+ЬZV֯P㑴|fg𺌏N,"鶉hVVa24Uu +u(uI?S:P[ˋ)\1iܤβkHɶ-=Mi$ *C ~PUڭ-9n[mM4ʛNެ m&HKqJ9b}eŃ#U18wRJ4~hIra8S1w zE![$()8 \)nGOՋHN{o!JAR[JSzkIuB)IRz+gR~lY's-[=kR6#|mbsf(K5r1/G}f;Mn/ג@Ү:M-kJRz_(jzvupT2GqV]V Ԝ ?iy>w\ư'foN*i⳰N^woQ<\R0%^IaHVDj[9KƜh ʡ]5[Ob©ոK[%KQ'j;ou SMc\ Ҿ,9@0zӈMP0 $yv=0FN*$&*D]}_!Dujũe21bc4LM3Wc?=E7KrndV&)8 fYqW@zAPAW*'G4e0RwÊ(a)q#*8. P\TР3̊(ʓ,nܾ9%BրQ'uT6_l>QN䎵@U{M6!*oPCَ}m:!`83P6UNżҕ:"$qW5JSh܎JA|9'Hk7~K]؄uJS=x/u#[3$Go [<ƊoKD&`:ӼQ kMۣa_:n>f_NPÞb Ic}γ攝>^ ByVe\\@Jt '\׬x 0V#"&.Ca ^Ob@[4*">"te.Ϣ<;-Kգty9}ʔqO֨Z7'EPIU vo-ڤ6T'bD<ϰjCKX$AeJs=s/uN7tfx+>kϼ[j]\<IX-da妗{Ol*n#5ILÓkʯV,!OQ?P+,@կn eGxyA=iQ筲=IVAUft: X')ZmZ^,wuC կ9@]6ьVIwz^e#&zmj 3v#-SBP1e_ՆH yUE e֐2GޢMw4]#i\z<2)b]ODɉH¿ͺcފ AJA2LUYwN.6̄ J:}UIud1OXE y JaLn ~iHzW9R:G#GV4CHy7ԀAQ K,!kO)z卞!`z+?eJR. ]OfdYvPeMԝF=.+p?<55 07$ܣ~Euݴ6%>@D"b$ ]% Q3:P{OZ+ Jr9jYshŻ1s\]9+sp?~ŝdiyf.;\u#zj]iW {(YH-MbRW L][~ O߀v|t+TR/݆TiiޓlߔVa;@L|ueZK!m\ QxYku(E*?p+J=%qrNZUܴCf7'jz-ZB[7K-mR+ho)` XG"5z:Tǖuk*(BR%h'6v7:R}DG'[A S{cEQU.F"qq*g^֑Y R?2>Eq>-m6d(WkߥjC^ů9^j.hqG+[{{Q|BtH}뿝8ܧ6֍<9÷H֖~>hOr)lD\ *8įOzXW^$--ԢAWGyYb}I,Z -!$I玕Wþ7y:ewS@(Z't{ZƩu_;n\HAP)hm4pʎ'}\x6p&/LjܽCx Aa]VMmX}';SnW\ZK" 9ڴRlH)$$gEy^IFW>$ ; aXM`h w~Υg{"ˎmJLr97j.1d˭WLdAQiw9v excڒi[;/a <e$"NR}ztKMNK>k_RIj Z>Pohm $:g,ZnԄښjGMݫNzٖ..2Zk8"\yJBIJY+"n[$)w@3"ӜBJlg1+sq:&շ|]_4mhޟz N@ HQA)Kv1Vb[JIZ%jܨջ4Pf\\n l- b< \ޱ)?VGpk l>ڲi|7NN\)V7)4K,뤶n$H9^xzkn} 'psEU™Nn4IKR8=OV11j, ~ݲ!l̒z &mKɮB; |Ձp\$gv,Zmf-Sm=Mey4OoG/7SYn"<ͅ~ձhvwڃiQœ8nÖ:?vөk(h:P?=udhHgUqæZlw"y,<$z3kA2BoOֻ ƚi|?wam.$2k-AWv_e k.mm09{Vpe,L!d{f_i?7iAjnRSJU+=cڸx{Y].=,f%=B޼F\N)'sj+^2,n[=**Q]?ȵ.`}kN"nCe[TDDwްPx-F|0.pgOyR;ƣ?Xx:r?ş,a2!''>SƮ A9A5#CB^խlR S&XXV;--->ZRuj)XTQ3xMKgxor(o_m%P#ۊWi4ܶm YIBd pInղ yZxU=6Sxj)3RSsޅmvAyJFkVk¡ z)Wv$Du51póN*KfǝJJe*~EV v: ůƋKP,v 9S t3Zo5'TotI Y"zk jl$mLp5 a +QZ[7*}Ld< nM:on`T_~ܪw;c|Gvs44qHL[W-2ڔښRJA` @w$uw&b>iCwHIl#r+DY;0ip j$aI'I\ >ī3M`XE{BVLc6ӿ#SޤIYRihRA)A&.7"ꪝaJVx"}'2cR֋21抒H8Pa95I2==*텫.]-j +xpڃ(s\'FA6-<$ګjq^JZS!T;mgp$Fu8iZ\`-Jk/R]%JQp)˜'U5ٶSl|]x!ՊaЀ";oz +C:ݺu-)F]a 8#&MQe1W Z1?z.sS '  m֮ 0kwPCi#LLǹUJSs7u@BI ~߭O~t<JOX4hPa1YyFZ);{P \$V϶B SC-9aŲ6.B RzcJC)JY M.AdNU8̚˲u8lCKb2M?RO^(6 WLq&/ZuM[_H X`-ďl5{ i:ۅyI'g2>Zq#@)2hH&N!puj?ҴДu{$)%[5GҔ- -*z0-%`sP*H)I(H8ܬ֞523%B:57p8n YNf%]2էv dĩGڧOJPW;SV Wc, M7 ?YzV^hD pWz\BJPl\hn}x(i#sHRIeAcfvm}r;wQ9 U]a+u޻ w%˲P F-oC-6R)lBjZΰ7 dZF`NmZîq;I$|S(8{#Ž)}褧O1WWJvm1gb?Ak8:(8x6BO ņ$h7~tfO*p#R+Ma1VRmbݻA)(M-^ >KZn.`?Z׭49<֙2&fݙ#QMTڐu)wnYTgO$G7k oų;@'z+5vRkы`~H+մ`$$̞ Kl!8: hlzUz'"\rNj{{d(:vw>fE3&Tq֕lոU$Z[>PKLaݔ!_m$ {T䄵ʱII4D FGa?`̚(5@7G)DHBd*W^}>& PS?F`EF ʷuJ &i`{n%*̙dDH)Q22*m6[ J7;Ҿus(wnۻ0P3"*2 Zzfy)hN( GQxkjU!u *P=m#H_T JR崘h6Պm^@ED@e|ޓi}i/K,z'9I''R/]$AkZZUK6 - _K*ӯC%#?"zfU5vRBQ֓IZѷ\ B٠ r k.oot)b(<Էu5N[ IezȮi[fZ}Sq#sm|IL,@S J;G M3vŝnZ,9pd.&fmCLu,G0$$@y7񍣾,ۦa2H mKj}0JJL^ͮk7\\2Ix|m^~ՋdBmp 0g+;&GN:d1_#"nsf:Qq&JS=)X-^Q}۸4ڲoZd OsOgEU4ަ-qk[ Iҫb@[5d6-j [?f@4te$KOh5p[nJS.JRl4$5i VΆA(zW)}[~<3ۤ%DqgSn- ptИ+b&L6ͲR˚N2#(_֭œ>$om@mrHJ񅞉jU[4!e Ia Q8&SqVh(`@k..WZ,4ZNZkҵknm zg>վ֔$Jli$3W)PT' qQwY6ޛv=bC\Y9rDuImbr 0A7.Lm%Ga:Ż(*vL^IӮZC,:w4Y}Xe혌6Oy4Q++{ǃ~6DTM9()B#h?5eEG2ktS~vT dOjOuR֋6ҕPT,Xm cq5%cj%o1ka]0+Io7c.w%VS/84FmBLyP$"ĺ}c6R[: H$}JCe=u[9Y)k\=FZi bR T CA*i*EtR92zc3jLފKe2niI@=ȭ8cZa[`SD!,A^@PJ+=*P|oJJeJr*ZT x)^[F8 s%_S(ua"JPv5P1wv)#q!RTj C 0+Rh%+ҡpHP UJqH)}ⶒf[+6JT A9[yR49z;iБ4p*ml[QruR"d9N9r)njqDaҢ[VV8GIp:s퍷eTa#w2Inxþ"cDnflMU!#ͱAvH$GC5cINPv*5O4^uqiֶתq)+}ƛU\&^B~Jxj/l[B\@]||ʟ:=*ͻU*޻O hQkPc@JRԢ H1\GWlݦy{dL(JVޮ][/\#L҅>޻ k{f冾zBTvo#AY=hE/76(ư5-6O:lv^ZRJJJ<|jiˋTz'bYh᥄'$Cmc]WHr:ZČꡔ]X-N%N82>)F]mtjܖ;:kŤ-l/'-<7[.JmljEJ[ Ce-)Nbx%MCO%=˶6ך&rr3[Ѯ<0K:WA .lLz@` ר>*~zUd[^e]hISN}Kk! TO5]qlMmWTȑ;IW79O~5瘶 U) V '*W~8C⛻+E1jTJA{&t?i:;:ӡ ).$-I \~< ̕$z2+ղѼu`B[i-ةn}BԨGIOZX.];AcZvi5[ݒtA!% MA3¦qQ27 @'tb)4Ţ[)Wh7z%H @ixNQq`G5RVzR2{uƠ򔴕~nsWIS*VOzbFjՆwޢ֓!HQb0Djs]5jMAxu}UIJ[aI.!y +vhm4 7R@E| vLj7\廅X9kH߳oi (r=STnmhSk ?yo=MkO,7[xJ9L^gqhŲTO:H2+׏ORTyA1 $̣R0+`8$dSں`=f >! H0gSyM8 5RRQkD'#MR S]u.6 MYoTmH"AmAZzU3qRrze._eꄉ/g)!kzf c?|y=hqAsD"fR `SLպ#B9~h( =U}U D@#9"UO1 $Q;(61qA9 lᜉ 5YDDǨD $`iFbO~h֙x1x*P5Rqީٿ>!SO]ړFE5mIFq1Lq)*@jq-FZTj ==-/\GP M7r$`u}B4 {JZ$k]LvIRSopm=}7.rAcg0I'Ҭ)Bݳk7riSIݾZ8RI2h!S?/JP[m@U}նwC0jG#F)moHx(93TG>b{TPU2"** Dm=-`npzի;pNŀ3Vl-JDB\$tFYJsZHJ`SinT\CJH<յ6%*kI6@B[1>iZ JcgӒe_h [B~4ͪ<(\ 4d ͺaNCﺔAZG)$u,%"dѼzS%LqYrMRpT^J#?j]ucޜTW7Ϲ 5n![ a$ZiXM90ۼʟTrPsZhlKy!;JJ$W&Ůˮ[NИKI,[I>յ$kc5_ѥqMn0Y)L 6BLr QEK-n*ɦj^]ZR:ƹPsl{[ܨ*GoB,l.TSbB L%BEF'~4|l]!Cq3ޫUEqGԣcn% =-ޣ YLN5 'x2(ɤih[vFL2h3@@L%%IKP9Ji1E'9҈|h)$I'E.tU"l>h⚈3'Z0'oNmWA2?{UA?]ЯZKz;at&If鵩mۻ֫ Y.'cڮiL/̲|h/Ojm^Ys72WCyܭ5QhEv)(0P}&-nX , HW lZ^:SlHϿyUo mn'w'Wa= V, tDWQosN.Z5 2-+qI$T~+\񷈵+V[nEpipgC?jj)O5{gKHJYVGiŽu-0Ls޷~LmYJs^+^,ۯBEn\\p2;txU<)&ES$aƕ=]O4D/cA'I=Ca>[Ngojz;+eG뇰H5j+f3X?IT*]tJvY0KHhJXRӐJnbcDBT Rg. L}*<@[!wZfgq''Vs(јσ;;ˤce=*{_w-/5.Ɵsx*Q`[ֺCƋmZR-̲dn8/G.íl>]ҠkmX~ݢ7ŭdL- Eo[k[ӋNq.~q, ,^?~fU4d ͞nHqEmIij;|VHVڹ$VnnqgRIuK{ &ݰn]UӮL{+~醙eM8nRL9)CyͲe lOEPIi;P,qhǜBR⪳]7*Z$FfMa.@)m*WޘW!+I@MO^)쌨㡫.!Up[R眱(!#jNj$e# O {$i[5+CmOJз4ˋwwԩ~6<AXdYXuf$?Z6[ TJC5h [wZEN;4 3or HJUFs~E飢]2JU_?prJFzk׶jI|I=JRޗD YZ㈸WSͱ%!N{HqYm4@K [zݺ B6iKVrem sUu;=R[\i*ܟ)E㧽[Et X\2 c{ QImE/Ö|Zq@Hup*ƻ}J,!Zn⡡B _VmT4OQ̎D8RO&?9Jnh(+-Z{C*y7Mtv֞76$a#`VSPKJΡgjuk>JSVP=kɛɂvz1aWGŗoRҘqca1ԚV'J}wvseBs?ұaNgtFFGLf?M+Mrʼn;f>3nx\) [-ؐQӯ/Kky[x=Mz<* >AVΕ6Oڪ9*[l>HdaZG^~ yMR\Z듒)#ŻXR~ a_i'2mdip>Z))ҔS/:'f &ĕd$'"ʊʿهĢmcZ+h/j ߾RvJ,zO ,R(*d<58tZewwHqn$Vtu:DIӮ-HMZvށ}cjimQS_ߓiWEY35kgVe߫!V N?Xxj.uE8lCnvfVrIZwҤ'?]ռEzRMTb%"wx|<[{8xZÊh <@nةд_'j:r-QvmmLt qOfmސfo.ʂIjߊY YxwKm^ 4U9em&&|=n57Y[VWO^+Bk+uҬW# xDE\[qN:}rvz3^6@DR^<)+#0~irn;Z =?T<cggym!+,OHo;S!-PZi:U]7_Նegl%)-$Mt{Vm*vdCɵJ6'-lv媛kh*޴h+?<#%axyb7p'holkL~Mʆ{x^FR'.=5&U,V6L`MqZ%VW$fu%VSh½!kwd!w )h3G$O 6)NJ%~l5;+K~d%WS?mmrCVoKRd+J(J zmCv-&RVrVf#͋A(>cIdoy˃ $炴K%]T4n|?BPFGs]gლֳ2[~g>+omu謾Fb#XQLWNY'iw=X6SM-%*y1.m0q;աs^/Ŗ^](PkrN\,PwMaM)o\\ < /3lzmit=rk nO4u!~Fۗ} wq5hw4"r疂" U״ǭrqLa%|*xIl%sp-lY2b{U5E4<}jwMiL\x'`JA5O,|NO t-wpX9)'}*++RvS_9ް,\Eջ).Omǁ+)ng1%iL]iQj-R"m 'tat֡6)KI'NFĮr7Bʹ:+ QWnis' L\PHUբ'olѸ[iJIJ%J*ۮ>R@;'of[(4RtneW\^36,$@qI )+r(rqݝny=cP~Kӆ\x$dMvV-댸(̠t=Ʃn|j KJdVmo]JR⊷8 IJ#ܴ/iڠm 넀˘V+ESm_<%w ݥL֟ p$@?n-]ם%6wf6HzwK)SfPV&խmn m` 1D+KN~Z@Fڮ΢tۋ{Բv|G1^J4@('Ӕ5IJNWlǞJ`~Zѫvm#p#2+:F8!Ӯ eiQ/W 8A/!H%**0z(]S@(Ž?z=)$@5P*4)3|ԍH:QveYRԞh""] =G1B撁OaH9hȃT?jYdADRY n@2MF&s)("jക%J%(Q1RrHe6T85pY+ Zra=XSN%{tO#gX sɠ`0H= V, EM^Hy(\,ٵތkK5w~Ajl8!IBCa UhZqeMdz P}vJ6Z;T큓PܲPe HS4GovلQ3 ( {K 6dĔx1eS'zړ>X5ci8w,<@TZ4 6J)ު]ݥi$*o Fy(HHU.I!$(2ie .GZ--JA"fS䀈'+<F4ڷP? e]ܭN#&*|әSm6=jFU7fb)О7mдNԮU(-o RTPO]2]`N'WXZ.="+Rᶬ~)^w?dx:d"bzWa3M&fRE)Vԛ1!{ f}Bˉ`A* q^NtG #)AV]ҍ@jkٹSZ+; pk1l7fMOaeJIY #?ҦV;yJ]!>Uo\jNrea i<Km˧?aJB ҄Vhhvj~X6 y$6 '?a_iw X<+P On7ŅOKpۀ8<gosrCrq^87pM0б]?Rԭwkt%4k.Sdڗ†ѵ{7euM ) dO]9ukPS zÃ"ϣ-4p"((yi:3$ NjJ\C܈z=ln \z,R-6Tî*=Z31nۖETZu# / {w˻p@2NS_p$zڀ?ֹtǍWqW/#PD45Kf3?Juo q]ՒV.i6hoc450oM”w~YpǗ=zI𖩯ZصRTtgN ޗZ.4pR ,{q^bËC y ;EYԋViLyo}^rn ˿WתY/ˊf2N0+ʹ x}%WŚMU xޡFOMEnWW %QQ3yʫ8r;W%o;F,q%f1őȮ_ğoxmwVJZ0̸@HQWegSFUd$~E[wC?JHWqpv$k-%O}Sh(uՕ֜ê <*{8֋N߹ &H#ݶmJ sYu^qn>eCNX[bAgLQԷw$ɁdGYHyBIY$g̺IB]7h۸r! ɬyyt]Δ:*RjVިL4S Y;RGIz:6lYou%4AKe*z4Қ T6F {:vn/됝 +"VO)@kHn˻ũ]hW;BO^f.<{/ v>N`neoJCZw}CuvS7.zZN%n^)yq;OR"8VӣFTA )#?<յ"rզS-RTS֩Yմ9$%)TGOd IǽU&Ob'vJ4k;S}|n%{̀´;$BEo^CvʳmRJ¥E)ңw,鍴^Cn:A!ÜGn1\YuhY(X=R!MoaXXәiiw:zEJ}?_&az핝őMЗWn3;ҤnYʴ:Y֬ų-)ù-Rd̦2 oE tZ'୭1uZn{OZ?^WUqEW JR{Gzx#X۲ǎKvҬ6!f!XW`p"{ӭ㫸*RGHMO#R,>rq 8&gk^xWj%+$B `3GJ%9? %ͣ)%qqI?jSof[ir톟iD+qBKqi. %sn03l4.#hm)QB31,u},_i--dI}XZrVrV\0,v<5%kv -I*&I#^}eia+XIK Z" k- }+?ßxoCԑq{8,m6[uZ9p+i3É,}Q?q^K~67|ս9k4`x3a&g9Vt4F7p ykG3^Qizn/p\.>I>r7첷|I>cPL]2l<nMơxJmZ@z6ڦY\qq 2k<3VR_]R'Oj,ؼxٙrGZnY9l؄{7uƵj! Wzk> mgfQnB6R⻪yim(HvLZV5s=M}Qqin)qm͕{{o0VnR9`ཛE i:fogy|Gg*)ݖ5'*Qxƺt_%aǼ9Ѭk~0el.C-0ɓi S"E= xsEK:ڷAT̞~.Nj澠/Qlz>֛UqkjZ ` 5v?yr>n${^Kh̝"+z.Kﺮ]T|DVJ=8$ UujPD Lxt-ZE[ yWOyܶWU-'*Z:ʠ9n\ӥsc5EgrèވZP!??d9r J}]ҟypR{vVZF<Ĕ*{U}ߥK OǩQِ,7TQH2ii!@椵aĤ0a8 EXhhrgДj%Z%J}k)9 T ^4zvߡJλRQkٴQp܄-H3+v=;I@HM'p;ODnȎD=qhQ@%(ښR+0U2Ф   ЀMJD4xTRJh޺mi$k?pJ=&GaLPp+0/z\Wɬ-%{Meۛ%YUԥ6G =V-᧐* 3݋Ѧt ÐAILX:բ )bPc |9{fZK7-6a??coj[-m]v(JA Sat6-rqɊRF&EtԆ\),+ (W<["RDI_ChV;F'r &iTJ&'?f^rU8`QtJ "iJH ( DTqKPR#HD"h݄Rf" 1PTlZ2NqE Қpv''=Fۂ@ ZB0:S7r/&OPxRVQ:UcCcflUrРq STK@L@2@Hi8Ti[MХwƃB@q)Oa0`u+y=yRZg$4=h8§S8(0ԌUKeON&^6SM_&&rOz66?z[X$%җ^ J+˹&Q%"$rZE=).Ӎ++p&=hhʠ0;Ȩ`uU6bv)k##ln=iDf9!CaRB]HhGQȥD\(RZ ;"+ AD-m0 Sn}R"yaՏKq7hZJK~l O\n;ܧD8NcRy )Jy4%(=zUk4s8*'hm8#/SI9* [$zu apQ8lZBBDjј:m9%((9ih@LtIpJGT.jRUQ+NR:-B)KpVEQmV ʒ*F֧wOS׫KlJ1Q S?lPAHF$1^ף.O+xF;bM-H< RfՋdބf"H>6^RR U%$=je"R}>Mn${! BO f҆׊/ּbjMBD$+N[TkiXǽ^ok*7{z28}jNI]d$F:,OgH?05U JEX} 7I[-LuBqRB% EI)p9@m4NjI%Bp35UT4 g5`s&'VP(4Q>;QdGԌZDkBfid|EBo5e5lY%@¹ $ā[c.@RjAH XgUH)p*DIDIܜظ[Z$8*MqIoAO.$?5*JB94B@Y.,RC~r"JR|TE`) &H" -[yęBˊ&gIr~Cc9_ :=ZmIQ8j^Df隩Уִ{Zr `oUCKov x./ޢv&5AO )ҵ'&PwR-ڷ+jk ZIT) *Q͟jkArm@@RIZ쮕"'oD\G?ytc"kJ&Mj3zi Q4tۖV@;2e2˽q2vj4Ҡ/|(_p+}R/:)>ZyiV@VH'X%EJ>}K |ھ ۹[ sRٔiܕ imuQW(ݾά۳QB H3ӵg}jij֬@ $ yazM/TR[Ab `7a4֬tR GQ/tbZjɇHڬL+*2\I~k-[[ڼrksT_/d^!Ch~+B$%*'&k*G] uiLH9jŶ xVMZR;n5)> 5֗꨽\܆̥NG+ωKuȣ5 i;qK+"}^woەk*m1$O]꺁vÕeDtjKd]I)O48|ޑvqg KòٕnBt֞ H~ݢRV~m6z͝ʜ0Ql⑷ܓG$ÄF-_!%&!{?V9+WZmΚV%0r twV48NQsMt5ٺu![ZR Qy܂P=2evX#JjZqhqv/t=f[\-Li?*+G&)*R*yvu)KiܡY Bޯ0{.Z߸ݻil`P|5^ȾgY.\)@6Uv@Irݡ[۴dLn]J/|>Ŗd\RB)JB 9;TcRin)za%:wmRioYF2n5׋% ۘ<^ab橣퍽i Rc޴;y]!27Q'8_)g_xv]yp(yQ,+Mj锷怅O8լ:ӆrE[Sc}x]Cj}Deqћn2r寑i_Ҩܺ6iLEҩ6(,I#*5O璠K␐2O5j+dAS ۴Œ)ՂWѭ4 :dyqYX4jEڮYYXtHun(/=ιܡ,%6-{9ke}}n[OwwDv|{[f/N[m[ 9%@}y5F}(-|/ -6$3rz`UKt]gr >kW]T .\(qgPʬ Y\()j-uEhǑtKn͸`+Kx4(!Te#o'r6vjq@JNA ;WܼyWC#nIb8[O"KhWlxlZձ8Rg+CWQ[|"{FIdd3^y6E.d.5 [ٻqm}-d?MʛC"ޔt7R}+&afjIe#vT'}^Vn[3kJUk6MVc=V?NPBTr.-#7tw^3?nBHLt!1McڋS7WO}B@$v [wWWi-pkdʌr c15нk)ZgwCQ ck8;^Αsy7~k!n3(]ǖVqjTx^յ=> qcBU/YJVPaj=CpgthzkN_'/P┒i'*]-ƈm%Hu7,t&`!onHLtZ6wN;RVSUKj(|G;i,i.Yڡ m2]#\mez镦 P|Rn(%䊆x| =wtf8Isr<-7Z澭эD1SW7<ռJ<{cqkGP0IQͯӶRJEj0]ՌgQh3rTJR>N3*e(}{*-+q)035*dջH'Nnà}L,[yl0pe$O߭7AANݥڶ4R;`3twMͩ;BOR1Xqrfq.(+xJkBD ?>՗nNg+ .LSR8}^a HWJ Ə ;BP$/ |֫0mɰIyWK >6we^'ѴRYYRH#grzB]3 _-rZK( [C/,RΎzE/!,um^iiq RNGڹK+G$׀|.eZ+ BN)tZgKm&k)5=gK/f@)AANSTQeMEޥjämN=~bvH3b)%*j\m\,tai4{;NUҰI8ZxZl,-K=.RJ*GᎵN]ŸJV8ղ\; 9~~_bQ m7nqҸ]{S֟b [k-[6%n`K0+OWXnmEr)Ձ*sEtg=CC֋t\-$VkP! fM{u_inon4;wpK_bd+qjJ'z#K16֡n<үRQVƢlou)[BRPv_4x8HRpRzomlROYnFcՔ}%ڡTuP2"fhݟ/Lw%jRNDm8LD wbXl15>WSoI$WK0@7皹)Ѹ''ڶZrFLfbsڪ嵓?+QT$ڹ9[}zTYs#X$JH>I'8׷nOs&#cTnF)6t4HHP5\ ;>j%(YJrLOb)I9bj0%QTGAQsH'xS,sӹ~*0 azB IJCoj8bP sNq|7knՔZ!,9<)ʤ{{WVm[04TJ5nm u9V}xANJfHqp!'xT]PIӛS SGj0'R^Z2m!%>&I=,:5ŭ]ʎ1EkF޼jjPI16~ߤhnQ<ܨ!;$pE6O!n$cXEUwꌄ ETr .-iַ[3H:.Xf8H+rO䃊`86 +OGu,BRG0VksP=ӭ۸ jֺJJQX/:ܜD&OV]OnݡG(\e=; RƴDrH=k9rGu%VcZMΙt_D$(32+4^eyrkBD+tWwmK*'n@^oNy0Ν#>5ݻyODLRO扐&j>hsl'4?z(RfHR[P!C=5qެ ~*ݭGQ 8y&Cx'tCJ>w%=sZD u*5a,6!m@ҹڇٕl(nRԎ[JUh+{#UbeO$g;XgN-/ПP$Յٔ]*l*louBԶ$9PA:FI?\喞pў$O b S2X9ku#j aALJ$ J-jv6h;SOi][<A*GޮUC{Kaդ`::Z./m-@k:U,7Ɯʕd5AI SI(qC %Qu0r=!ȔQN-.7,:?4` R]_zտ-.%-7dejz)[m)XI k^!K'L a[1va2c$?zÒ;lȟDՔ̜F<Wpf!G$<#jN6ʖ *ȣQ2kNМ-k"OzZ:ð Pl#o[;Yz ޠB*v&BY%&I$㨷^ dUqO}q; zQsL/m K"+;g)6PLѽy*)aASy# J!`u:2tW/ ktj NN1*W/ PWAV5nPcK)lA9t&T}j9⬍ٴ,mqHҪ. u%l?Qm ȞQ9kޤ2$ ڳ4N<ܽ"2SN -mL$,j&.mWpJ?pTڽw'Fie.|2r{{/mԫ†PI'" ;RvL( v<% _N}M) &#g"BL$DϽG^(bgH9@*> p"X4@d74*!!R[ nKFy80sfø{?ItO Dܺ(VZ:n ;^0*>UPUӱ~0jmdi2iԼڊI+u!n$* ?Lm{WA*)V[ElҿR'*ɞ(+ۊhA\*2NbqP2EiA15lhE"( QL3ڂNJԴ:>ZSe[wU͢GI=cOomX)eB,nIWh44 Ny[77za&P0@s>ΩG~b*EV፻նT?ϑhTbadDT8:\ٸ>4({}kZ͹Bm>ZvB: yM@IsHG1qNմ= ZN۾e?n֤gڹ5e2AAk.Y+XK<ObI4tMIWl| ׆>Em7l!)Ş!1#9C^jU_>T2ԦD~R WeMa*$@"m6 cy9#._ߡhV[Im山D $WPړ(tY'f0 >v5]:n

-(ؑ 4ע4t։KmX)ƊrJ$ַW J^+ZlWB=]?):ڦ.`kBnLG9~nq*}vܡ3:+uE]Z]_ ۤPYZ2q֞f۟>aRBqW9mlZZ[ V% @Bqerul#&Fw'kjSGju~]*#55Ji7k zJL:W^ݖUa 2 nY-[FդV斏eu!.~ JmjoRظqmB#0&4jvݷSZ6J@cڜ^KAL8$]A6ѱpˊJ҅pU^:]Υwy EK@{/UenfyPN=OItMEd[Ŵ)a_;IPLu8E{`UqlX$)d'_>ų `Rc?1]ts}^ZK 7$uNiZ4H cU$[=M[5+nȖY0?YU5 mi=-86Gr{WCm,)![8uz-q-ob2N(C2wMU2q$:VPoXi&+Q8W𮣨j72ڥ[.w m!Iۍk'Vm./jцZYopy'm4fXIsike![o²zH<^Z@JU>m- $v44h24eIݽPjwߟ9~4?/OoZRYjI$:꒓:[*; =E#y^cSj{kM%%n/YVFxޢ^ۆp,1$ӛnL|t]NZYRL{C Śo en(M3lW-rB%ŀ<U+rZ懣K{xJR'S?v=1:TtxI})q>=\+:3>\|ԶI |$ٷӵ-3]y! G֭@=1^ M;Rݸ%HMuЀHO5PRobSlxcL?<{?H9$zvo6RY!_Zᶻĺ6jYOdU Y{T|9Z|Gmi:ZT8JQ)t[Tk}8\ #Jjz߈凇Q6\QDG_t=-tkV 4n5d<߿E&mr 8QP'&1\νu9pͳ=I*/?Ŧ?>Mr"H֋yj\& "j3%;7G[yv+6Jz5_] ^ ]͹lC 鎃ך~""^.@! 'z<CH q 5GLO3JNoFuzY0UF5P2rf NiN;iYNJEV)-dIҽ )Y }A4B RA)YW6oV¤c$%Ekf< B HLYn"otymK+[u,-]tL &AĊr9ffslb>d ]Ԙ.`qVBM$jQ\Tc=yVϵA;s]2C(96څځ>(f Q) IPLE4 &Ta 5[T |ӱ G *pf[Үip^lTɏgf--y$d{[NڗzTTBQ3KNS ġ'&rʔu[_Iby5#d*QWl[j:뫑aZ-YKa;@]T1ʗ⵨&/RlLHRjI.TaS2ޘ\?. 6fby5wҤ m@Qyp H{^*F$yҷ i!a2ZLLa#sVo CEaRx6"pMI28Ïk\%Ih! @Ʀ\iě"APڡv-BT2DdAнr^fxV k^}x$8RI8JB[v'T#:LǑh %(\'a0fkEzjn§l$cLִtUrw/T$%`aэUT&OxsۤwǍi7M-[-K#Ohw(yi`@*5voYs!{ar{U6Jliu=Eg#x%Hꢻ1ЮSe *T;'CH mTaJ_Id3i[o$L=5gKatHR2hWo`a 2dw$Y:v%+k?ީV甆.Y$t)-hb;#2mW7^nVҢ ]o[-0Tˈ޼֢wںiم4ZWՓ|v&OdoP/%a\U﵋}R%0xn^lH<ⶱɭEK쵤MW Z;TWj:zr 54'UsQh|.Qї4,!EP;˾.mvl̟IXJvkJb~ۛ%Z%{e05&\Mٸ2V,51f~m!wVnxm["А6ʻav{g) H z5[ja]PڒGkJ0pUqd=meȀ65d~iI omn^Dk)V85:!JjŽ vֈ¨49gV }C"M$"h@GD$@L H9M331N>g#&{b9TdrjHMШVj–CGikQdheDb*59>4IGJ6D2I zB"3ֲ&I@<%-V֕ql()G]'%OdnβӼ%"=@(JI;@JsjmzaGR+#۵En}3XRZohJJg sZиII[iTUr,۷6J?3J)ojԤ7uO\jZrX/ lKa(YN9#ka qIN pR\XkFSR? mOɵ%o!I߽sZF+6%:9گ-طxfæef ?+U4k=Hb2]56N6mڑED+V "HYR6+wj2ĒQ8N9ڤCA@ Kgk/E?Xm &}F]K[:m 6ō;s֖JQJs?M4ӊh6)euH. Sokq`Pw~:VE }eH[Tbxjݽn)#2jIu")BFTxֱTno޻z-*'RHIocu=B7LT TFc޷߿޴S %$WLwvsQ3\V VZY"yWSǮmM8K \KupZ" AІ$VGkiu*}IL2rDI%ELE/S">uEeN9uo ;4K6[ט@1W2ej-$7#jc|WAxRեW;<-&fW fm:VaB. ZJ$XԾ3NҴ:˽@˿ &${Vsi =.l ;m܊S|,XS9jV[u@Уnf?_.<=Yj[ ]܆[I)VXTԚV4oIsb&JGIuUn38$%)@L&=S7-!B 9Q{xcN3eRa֙'b(` j<)`-;R2ц[vQ,[JdUT!IZBL^jGnw 5+!Lѫ;w ]p$!JDL׼1akqh[]2+) 3+͆ ÁŅ *Zjn*BxNJGJ,rF(ij)l}$wN'ֲ[,]8Urºn{vWI.\ *Bw8:PWxZ9ɻ5.ӥ.B sY鲽y T#tGB0-i270:U0rW̲oZ.h35NKSFxRdipnr_]߷l/ T{U.wTlz@rtIC)@!'zۄdQ}]m!7,!~nOD{TF)sPyͩYpQqJbD-EeտihVB6<@s GO̎WzM,mw:7gpll-EuV .>N+-z7j A2ԗ:G;K`l/߶ PmYAP=̊Ooۻd6ylsar OQ[CKӯCBm ']hYKˈ*YHW>2|զyM|9}(5Gihn-^}i@"8\៉kuOO[\\~P^Z~W\~jK GخoĚZ[ T׫$ىWgӗ~{OGJ +jz9 ?t_ i^el0r$}?/QSܡZKImTvcþ6o{Y/NT[CQuNd(iX'N{OyW`SzEpefgN6>ZO`0G ^'+o2VGↅi?ߢT#N;9}C%vtLW\x>RZ!HTM7DkþV LgbʤFEnۿq|.ܿ)G:f)xY:J)w^sa ܥb ?Qłku$J%U8Mb\1DXF!z[Bi@$d'ɂRK-p6$mQP V'JaKlڴ`>N8;T4=Aych$f*ʚBV䄼7* ^95)x_Y dmo n-d}A3JQiZ6I:p[1E=Q_m@Qژ*rSM6n$5ړȮm[Q"ٕvف&[RV tZ\F:Vʓ޺m-" $'rה+I{-@q&.TZB$BG#uFxA&:VŻN@#ڳKRQQj>&Pkђ@ppL$R*0L[i @Iՙ1ڗUH(ӊQ=jJ@PH?Bi(9=)E6ZZGW]̲[Rznӽv VÆ Hz׏U:;e;uBʈ lRNst^}jϥuM7LQ[)BesSjZm2?Ҿk5?4P_0TI=Mf8ej8&.VXSEn[dq\Nu.-e[>R3,ѤB~Nil%fV}`7 h_1)D׽aG''Z4ucҽ[.hJ}e*uD$~7J@z*_z~GEY4t>{NE< eOtǟi}9o8ӽsD-]_V)OY.Wlbld&Ծ͍Z^.@zDCIӐwiCD##VV㫷Hޒ0FJRʷ=WER쪞w;r Ss9$ciT#kN^h :SAxC{eIY!TY,lL<Wҵ&e --YWlڽy-ZUq[IG!1SFթ%9h^Z=op[q#ګs<צ5h2Z K:Nv\YX'[kB 5[t 585lֽ[/2Ѳm0OaTsJ!J` 6 &=Tj՛&ѥ-]Ef ݈ڠy_֐H#8< NSɠ c5H LRy℀'dTڒ{Q09${֑(*Ia@хB444gB4sMN)}2}4%A#rRTLr0k6P6&6@2H√|LMN" 4 PE%I~Բ=z lTB3VMfjO$?zi7:WHA?Y="_ $CP_zoaͻn _Ԑ3R]JԘ$uۺ-{ ALq[(>r3IQHFB05heM-՟s*Qa.o ;t\ڴm|%^k^K$mjî($*k̔z5ګg@ja )ą))J`}4?pW0\Rff+qŤl67ql)*}@*/ 籦VR=kT Mz0CRf%OhҷP+CksO1l%[ nڧ&U -Jm0LZ6$g5djnPpdAyv۟WtnROP*R끶$kSwNZ?Y~ZJT "z?5MGh}Ž,%N22!)Zc͡$ܮOTڍa*Y % dpTW ɷZ$cpK-;j;<ږV#W = fp9rf%np:YJuk\Ozu2@\)XVfej'  5ўium~_]\4EJ ܃ WJP$zo~iq@?1ZRf P[V )hV R*k=JKا;棊쩵|}F&[%QS[J J=T5dLgjVk"\*`(:p&H|ԙX3UyJl)AIZa[XadI8Zd_M߷ JA.@5h)KR 3Fŕ垒ͰUp앂S=tԫD{3'HC-!3<󒴺J$ktޟmNZ>HUÐ~aGcW>JJAL`ڲmđUl7YN%D*k=UN)E{{@w5A()p+k۲S4mݩ֗)u)J`IY.JPHZiqpˮ%a*?&":Er?.8v vxyGi$2;5 BүHQ#⬱ra Bp`TA$;CޟI&F8',a- #< \=5T45%LFn.Z]Ҝv[6+Q$1y^-/F(31(QZBQ!=i~֯mt6-(;GߊcGO9Dž|5 7>la%KxӓJ]ŝJNqlYR Z+<6/  |Ū޼lӊ967tz8JkvcOӭm 6*"INݥju ,HJGRWo՞6WWwkYC[JcIϽv%rL·- h0[֚如l2Orz#m(oxD8T2hzۗ ( !)HHݒjq PCAs3[\LrSLeЅJDdS1)@ SU"lReַAKBH1?Z~zIԘ[;B' I1jalt}r42[=’rA3::G+ v6%Cj6Nm\AWKӬ4ޫR.4!$9\fkoV!Ö-")/oh+m]g#1u{xQ;ۦZm!M9Ȏkˊ3L7mZ[[;g|yK;P#g&qXZ֭U[X7n#R9'5ecKj[ʊ~+%)@lv#}՘+mI DֶɰP-ٿFX5mlBvڲJ\ZqF;65-S wV8fR`+y,KpD`rB)Q$LԈm{ 6.5nܶ]CvaHZVIT}k)5(|T K#}v怸RILSIkni*Q&t̯mS[ uJAVo /oA*LLf=4 Uڤ:6!UuY5b*Oh4bT\ ֑XR-1)i%DdDٞ`=AD 8LN4h-{Oh&> 5 !ޚȎfqJH 2& RjͭT&'8w(G[4ëy2y㳬;64^]PP"OY]E.̾T1K;:7, ~Ajx:i J?iW+#?ּPPo5&q>IN>ՖQ4%0}+p潐ƒ9dE %8\^djv'pX $d%PG4R\( 0j-:)j[.,2$8޹̘R$Or/eG`ުƛVBTB֟\_$I3 MشpI<1R˷M0({UK@j9E#MFRS,8Ґ#)EaN@JՅ>ovԑ$˜ jRF@15 7ɛ j%% |rd{u"*p)8>y ͽḤJ̰J_)SDqQ"J*+Q\m7 GOٞȭmAКwrmlt܄%T}d;m-zHX)~OZViF/KM=OJyubddV)5MBEKjFލI#^Zw52aZpN%ptoAFOVe%It }tyRRZ+gjc4J )N8?% ܄(}:(Yқ b%Ve{bA9$ I$Gj3􉞴ɚ@h%GR8 PBs(I*cGS'(@1ޖZLH0sOaIHM7tqBbdH A݁A@yƑR H)cء$bvNhF%4;sNqV 9j%dӒJcH`sIdM `rjXHI$p#wf(Nc4TTD )8O4ʹ:M%~nzQVGz":v$T@$N)a݃fR'U5Kb;VhɊ $V\"ӯusk*w9fEVA 8en9pPlkF[X.I8ma;PD'+> 4 ʸc"Ҳ2EXei)Zt*m5mwqB=*QS]nFtF2RjfNGj L]E:KH~Sq~!6iաJGvۖP)*U+/}8jtnS~jv)ۧHzSA* I5eZ-/+26xԡzU(ŒϖAjFlޞ\Qr@LVW (٘l"L@SpqsSN˕҃UmFW3#V93A* wO\[G8 Vp'Ţ]yMjW bMYy.\i'ԙI*E `-jP]-,@iڥ@FGfECK )湬 mVmj(bPpFnrTfMW(QzTsT哶B>k9^rUbp)pyD> nZuvɶS{C *c1eX5a1Cu^fx㺊8FGkڇٵjz=Bt<C$>+2޺;+nb Z>:֧6ߗ{&= e~h*}GMo_Zt -XH$P7\c<ߋW&Pţؗ<<`+40(n;fZ.J&Pg2焂rԽF  ϽjTgs ١l ނV=I[J)֏lJChH \۸VKnR6J{WG FJ),-! $ջ S(Zpz Y$[);Z`#ާC$KmH[T̻l֮f+Q~/+A)M:6*ɜ()0SjHi9 ?tq bIô=*R#O*֤ϤLWhͣ-JT޳lABT*+c[qf/ʋ(am9?6\]:.9%Gj|4yIlQه'GsWu-cnTK\s2k7oe%0ڨ٧Sﭮmt8BRfsKUn~*Yp+PI䵾ev,K(!n?zOu:u[0n#܅4R[^@ԟ8_|7qQmOM7 h>Q\z҆ 7T5(K~;GJ.<ږҕg Kqp$ \VߓTVwN֐MRZ}:rC--/O\*QUcp+ oO^fuxL))=Γ{ep@#<Ri6wmd,m9ܸP*Rp*߃/< X( )L9dH(hzu [ےQ6O1^gٱq ծ*ܤǖn՟]QiurJ*jc .,8@pa1|3Jx]Xh[k:.us6* (*?5zXBDA$"eCs(H>ڹoINv˗v8I (r")qGQIlt["6 ݣn [R8fE^X\êO +%/PsLtkwwA=9?zn5W{Ian<4u1wR7M!/6'OsnXrٯ % QB?L38WtDxdof͝de;gpq),I~ݟ5ե\0Oڇjx}lTgڸm'l$k iǜ&26y$D[WlI 3Y:{nde#wjrPAIH2:׫ I+a0hr{ 2 dFcded@&N =7Lڃ;+wd +n- CbNcԺ 0 E5d@q<8QS2T%xLEP9<24ĠJTE@IbNG7Oj3YTV(P#=)6TgqP&ik:@^0DѺZ-%v\yj%b85iC7½[3OEy֚Hy 33Wyr<% 3=kstw@lvJ)O#{t:{a4·U$=u{pRBXǴt7,iV\4uN1M%eM2ǚ.d!ԣnidMnM_kɶZzsRQ$ڭj:}4+[/uBy 8 ;XB^)I0j`@OG.μC^pb6/jG]@K%s =#jHQ %T\#q*e@ bcI 3L#IIJ.:mil fu~j7*1VR-OV LL}r4N-/~ӷAlg)ɌJ6z&RV8D0"x&yT`Ț_ЭL#;D)PWƙǵ8'4HsMQdIH\S*Bzl5BBL4t*%_4EbhlrIdԷĂ(WX8?n(_i^o)'@$L f"(_izw["[Y1D8=)Բ< ;PQ11JxL`Q?J s)JE)PI1zZs2qQjCED۽$HS ȧI&V#2zR @USD&5+92R$+jSH$ {*1ev+pH15$$ l'VBG5(a3O&)(3HMP4P-D֐-> 8jTjGڜAd5mD֞&qMSj=Jf3mlY)JIW- m w|W7epo5T{5R1ԃx.LvmJm^٠U+mƿmp"f>RCYgM&s:GE17$O)WuvNIjPN }Y9RjA ܕ\m[\m#ѻ-XZr%ɔt]2phAP>1d̒M\m̢<ĨA?jy¿$Ll%0"g[ \JPD mvAܢ87B)sk 6tk\b\ ]cK֏5۴STn^ L>5[\4lޝYL9[_RҔz8r.De4nkFܵJpy)nW+Y9*pʉ=i[\2m#hP!|wl]4: VOGJ<=kuv[[=.J*m_^@uIZ=+=ډ33ڜoZ5qv\4j6/Z6wyJJ `kq5Y4kt0tڸFK|9ҟgj#}/o԰ڛUg'儥+ړ:nWf[Z2CA)J TH.IR[ $cER*.J+IvB\uH Xff/@|/6~ )K8 /xOe%%-17W^{qpuZuB5qkBv E2]!lGŶ%EiZeDގ՚tn5A$`9 +QxmQ@ݻzs?ﭭ_N7j.%rGxU=']_8㖖m"nԡQҤ>yܖј6V|1g$k֦:]㎺omuN99{TiF _0lLuܣXqjNViNѻ-/)O󶍱yebS?u:݅ޖ݊ea+t>ݏyփ-iE`8JM4Ta] @k"Rl9\[>RG2F+4+Mpv(Q <<[꺸Se lmM$n-yNmIyV(%)Oz{+gk:n_ ݲ&Lzgkڻzjѷ\!-?"z+\C쳣_<&ظ)*E'\chmM7JԄ JFmF(.Wjoصu7LqOR: 5RlJiF)033Z>%cjQs`G=_8|7geygmb-AMpMYePFV5tcu%x}.-S(T&?N~$]ˊwRv8W)yۿ[/Ficu֊D(ʤN:y[uSkirք4h:-". 2Tp3Qi6;[A8RgE06q@RJ`3=To ABcveS 峺zy FyhR ޭ\;tZmK);Q{$e-Ւ3B0"D&ܲ5Q ɁZRцKfҶJ'-E A nRL`RG@gj[5E[%4n!hp&䡒H_fҢ6Uli a~U꠨EaDp siZYɁO[BA0JJM.Dz`tox[Q'eHA<{RKm*'e9W&*8[BDh6>rH 1'zulJJ Af)ɺ!X8W|89I5ϥ:zj}hM bUQ84E@A949&>)9yRH< sj NrMX ){ByWJPR 9/[V͉ m#S$@Q{V[O7UåKi^XKIRWo,D'd۳f Q!J<:5Ve]}VTFGcPVE_K<LI5A" n2-Q)91@xz .Pebױ ip,$ԎNrS}Kv։w֒d?ܼ˨x mZjVlYZ_[%yC%Dړmۨ]QɏJMpw^ E˄?o4LzVy"VPr`WUq[g6ޑ^𧆎冣mm7|n<3۲ҝԔ76Pi@@A*],uZ l|NOkX\4 KFGvtd2޹p|6LA؋]ou[ Ԅ攅&&sާtßaWqsw1XjB`jRFF}0ܻԘhTrhNktITwzG|/:}UۺBZZ\8YEfY)F z1oyn0uh/tCPTxbY$J1s_ث[eC v~YZh%_jZgv?ޣVצ\3l n<7-s஼iZܵtƧpҠ6W ږ\Jc8:g_<]b%%JK?ڭsKy'-JBdzl ʮ/ڋbUV--<`Ž ;kEQ^mUItDšnu*Ox2^mpnoK*B@԰HNխ~QmHXEA>8ڟbs1]ZJ$&+HI=wG6[/PxGx۷-;murI$ڴRH8W_ajB2Nd=GSHEPCG<ȮveyXFoW md-yoJݍW  ۸=>+OEb[pHIR$LԌ;wm~0l3mR}S\o6o0Bm%$ <y7:gnK(e ,ZUBʾ4; d9 =[!nPHۼ`fxW˔QU3Սzc!THY^0+vmbnZW+Tlt^k_*NyԧWZ%ʓo#{0rpik~Qjm`$=biWl6amuBPh3t-_8D5 i6Du +QϷz\iQBmT+|-KLenĢ͑+MvsvߚѴꚠMZI mBLĊOS:|ݫ]И< ڹ9cYrmFqy!)*V<Č{|sOR\&e_u"= ]ڿjmsJŷs'Ⱥj~v*BqKoG)FOqQCͨ\J>i$t?jbBJWW#b{vծF)7ajkݙE+>{R>ڑۜ\pW]N$te-V IkznJ}I@M4shSv .r^KL-uN^D$*"T^ɝ5!* Z "b7:lm'8EAN!b#5[V E@9#^LJyok H#wUS[)Z(b+Qm|x\Z2ǚJh;Npʎ {םϓaHdlGXl![l $ ozmݹ/,ځjViEǖ̕JTѦnRL qNOJXYRPUUbhۑLliڔB2OsQ{0NHtr}p*͒vɴ,)R$%g$Tz)/#>kGAVf*yI[C $‡JٸI}P GX,J@* LOG&;Vd[݅!CuY J&;DU2J -Sm'<JAqVb;U/QV#޴[">ˍge@׭\a;Jw2MVZ6:d(;HG4$943@'4M8 44DLz{҄z'&*2[ё:*$Y/t 0#"y~ndgknX AJS&~DKPy6䂢 eܕ\TA0z/9]:StFڔIPg$Vv!x-#x復JJF'&vjj2LHx=Z+ȜBjP^PIpMJ:SJТ=jl$;u\w/Ct-UiGOsTVzբBG/teNfUZӈ\rr8v掳ɊoFc0 SMFb =N'ޯn˅,`x2:Tj.Lh"t2)#j4>R@\VZ,lY]|'JJ+a&`zsIE.V 5)e[jPuk Z0#*JWT8)[upj$6(HvP$u4m VEZu*$ hi'+)ʉD& SR cV 0zT)8u1OCųpj2Ih+"`١$f*`21TckkLZrOL.BFRXSYFz6!IQ$;bީfz֑% AȪrO5+Dbv#U1T@2zғ0(ޚCցM4*8&O4KF0b1N "Ojlv?qyrhsDC#@*H9JrFzS Wzբ{$$t޸RID':H9T #&Hr3V6E<3N6ij`'GH&&2iA*aȓ& 爤U*X3h "O@$w )3NhȊrfg:Sd"F2)&' 8cB94Ha!3@uMTRFz ]H E5ēVQQڶ,V6D֬[4BAr+Tq4f ZLdlBcr$Ϸjϵ6Bd${jS[ YJ5IUsG5ޑpYڔz}ͻ[[>,Z"CmZ &8'V-e>X.R1DT^drJknFo^^m2UlmZt%k1 Y-2T+K[m)F @INz *e: $ 28ׯ)J0* @ "~UDxom@r Bf;'~u?n c\Uj}ƞݴH7r}ZݻB:}JI( '3Gl56'jJ1V zڼJJqT'޷5WoK5MY]>p֠gpZ[)bѧ ЗnUܟ4%n9rØJ;cjitmtnWjAICFIt~/Ե<֑!ŀFy$^sX~".6 }׺}y-Y eM crsZ=zgg|Cz)NnHRAGk{TBZ \`OVU,ԡ lkedp}W夘8ּZ[Wjji =Pf3]ƍţX zVgڹ䛜tj0Q{=X_JϰB<5%.^iA[cTٜs=TPj*ScNK:6-o2 sk8쬑 QUz \s^՜~+ҼFŪY J)J{q{LU5tjR0A>ڸg.vg lX $XsIԼe{zͪYEIPݸ4'AVٵU [q*)șJ!@<u]OK*Uh;T"Bb:td;Q^Y6 SlI*> u!ԮSqH-^/vL<ɚ̒ze{NwQy /k|w(DE /Xh5x QJU03^@mZFW.u]*. ilHQrL$Y|%wju+g.. t (ĞYL,T{J)*=k4Ml\\[ZOn+VƗl١ox,3*cך~<4z~;[_ւZ b$+om3\}sr9Sc~guVu|Ԍyx"$e\I1GXYi|:\a%q ~'uwnmʽ.[,"#_Fi*1ӧYX-TI%O\s6.GL\#6:]h:zcx׽DU3}J]ijq&:VђΜ%9IVt}ZjvY*$EGuj%"gA#_ui-ap&s }PfMSr$ M#󛗺x(dQ (%Q)]@Z9OCkPRAT,T|TTdJVdSA?*QDP=e&hj:S J  BI *D$GWN"JZ{7m[lHud * m13?֥-R,((6p`5)V3\qTRR6YBgf-۠$޶T0NI*PnH9FTƊo )4*_SzHL93RQNq%d"b}IX$RR`Ԩd$bVKY'KD"iQDmS ]JM$l*ЕpM#P5 Yy6l%DU|A""Y%-*֣Ks0 JDNzӁ1$|ӡ'g Bi{FsEE>bBf*#ޜ)yXRBS֚D =B*`f. f3KtV4+lvVT@ 95Y彶ĥE@ҸȄ{aAI!e$ջ  hBcYn(PJRV֠,]2Kv6LccJ,.oQwI @V<82 iZj^a-^PRA=?Z]aX<ח.guj:tOeqi*U53DRղˉ;JӔު<[4GLiz 9ncqZ6޹RE]P5ܹfIJJAMP_|VBr*S}J>}޶a[Ld&fMzD[R8B6F Z@)Ijᄮw^@EYe09]PY{Y}rB +M‚x8;DeߔLUb {$t:TLg3@) (7u[>` a j;!#zԲ+qB%!C`(n$[51 H*D [WsPOgMqf&{foC^ yRZJ*rzTSꭥd!R2 O iI@]bhrf)n@2vT'R0@;hȐ Iڜ0i)*l H((4HWBSA 8+8#NҒ$Ի)۳AQT!m<O33@8""TT KƣSfxVhPBRִ}E0l\4Hl%jr#ڈKKiQ`|1%YX"[ԸHqDSwuĂI=]9[-T[օR%sS,ĥtU^Wn(2Ed(=:՗ԡ JUC!$H*Ң=]4PVGJ%ep3[SWeMD풔_#Ԑ{Zc  #":PZȐ)'Oy+]JVrNhzjMl,mi%-!B`.((m-BnFӪJG"o&$ D#ڂ OfKhڤU#pPZ~^ni8*l5YWhC@)}) 8Lxܒ9K%nTӬܷZuiT"I>!AiR@ۚ4,-mr*e'K_%Dn%\ep$$}eJc).;pUѶvi3閶UU;q@Vd1bA%Qw6`J L-P%  W*GUk)d?l2[sGTZ5%pc6>\@0P_Y0T@TNR4Iy6̶I8MW[qN%L{VZ]l.rӹ ?8iL82R)p}[SUų W%I!k%>I*TɮvH-!@QNlT}6U9CKzNkMo]TXJe_3.CjqCUYFh Sd;t}I-m)R Luo-zxa˯5Jqڮj`gD(9n~G } 6jRObc_:<ի12i@<3f)68Hݕ$ƩkWl] sko[6uu^ܥR˪p";sj%?)e^ֵkCO;clXBNdzjw #LJSys>Nނ;7B}9RU 'iRTsvo.i7/eE d)XJKm\QA}rp$2l.T 'jr]aң8zEaZs Ըht 8)&At,NK -pIO:]^FO:0mKJ~)B$cv]qľ? Dcohw d^4nmQRR'bF r55Lf) G<:7o$*g VrKM%KmO'hS"ᘾˉO䄞z?C]gMtmZj6_Z*d\4":F[08– TZʀIin$*y'2柣>9(pq 5IS6iRT)0U}R]ڮࠅ"{q\: հNx|W'vz7tliZ֩\66'i5oWU -0%B~в ]Vmq^y ]^dW.;0ۛL,^ wֶf[h%(VRu*mY'Ob2\F:Ջf//q2Fr9d:v&KlrmRJmnV@$$LIa*PLD[]:V`@sXRUZ8v4@BRIRAhiwWۂgYo"ܴDP߾[ )\`WIAPq)³8"^.[S-Y\4ͤ4U"*/۽ dZљKzKttTi.%HWTK/)fJHi9#ϷSG>+c N@U1֑ZQ'ւc0ȥtFϨR6Pj281@L*$q)Gui6fAaBsSxJ4$z,kKI'idk՜ YAB8o6ZxORp rh)2J15Z岂O<^LR1+emeM- x5gDFշm q{Tu5TIy?R]V5A4sUtd"Ÿ=ja VTJhƊFsD nۡJR9OV!FyocfEMDC@&4OJJ *0IZ jRDӚK6(z įeԅ{i"rJj/8n@=z۪HRG84&"f $mRqn)nAQ=&SgrL*;Ӝ(Ehqh$ҚnI#hpGzk}sO$LԊC0[ܤԶ6oK)ʧ9"QI$PqSt-]2J+iTb~k443j۠ L'V2f5Ufh2c1]~Yiv̾)}̒Y8Bu+]p$|T).^\*?|\bm#pOXw]Jڤ*{s{zVBUn+:yRrPGHqĩ905AҔ=ƽ~d%J[P0fy`Z&Aݡw ؊qz㤅($)5]NmDƼD;c;yn.Tu֔"v?z㊲ <ս2WU<+WrΟB~Kvn 5Ԡ|4rJJTvn0-q!֠bj^Nn†#=rktW-I4HsRk:lp-C UזV {ȭ}e7.uEj*Ӊ[b9R\ 6IVuE4$Wt+ iD%h$䎵%Sa3Š952rMڮ~^i<ݘ&׹YDZ#vN*{W R.lM6("I>ȈU+iۡ HE6o^i'ws 瓍lҳ3Q7j~*ULWWl\mYDD͸mJB MU$ʪ$E12kҬ4%)tB? ǽr,8IZ BG"3F}$o$~[ye n`fjЙz!e䎵HBH[A֔wm>^Kqf05K%X߻jَj!j^)7#dIH$sQ[=liky O[c5ҷFzUN(ȭtk[pKŸIR{ՎE"5Luar J$j82 %I y:[*~g3IHR .AViA#}j39v` ր4d ji0p)}T1=h#3E8Q' 3F$N1~J##TIӊ Wj)fOLI8N)A=@ &2h.1ֈ8O~ypN M(0j PQ<ӕ@4F@8ILߐ]*JҊrrbMT~i&`z*i"7dqN sNh@,ӒG)~hng~($R3L\TVRDqBԒ`dsNPc1ɫKvH?=9%R .BJU 1oo+@ǹK q `tx[-g,/g~n/*榹 blm8OB~*d]hJRm[B J0}&\AqV|mRָ6}t!xcQpEj;)ɘ9!(D$ʇ^1E[cr 6qfqF P#⍽yrf9gI[nTGZ{U44蓂G5a6/ۭ'x*"yEHǶze ܨV8" '|Lj%0| 'wLe)aezT gƭ8=ThDFdJ'ԷD&+7ZaIled']wɶ J摶nst%3]fAvas`qO&zԯ)* IUJzOdwV-.aip bxku'zO.|Ο3Ъ;!?cQhrJK^%(lSWG7)i x(QXI:ջ_S-V[ּH!)]_2'5uW>K ܓx?nJ]y>d}C7/> pH>Ol ځN*N޲(1Fr5 [8W)jtZf~@ϖO9$We}szZGpuUq4  YtŦK=̕+2ۖh~Tij-eM&aY __r֘ #޷n[M>$9ׯoJlizRϘR7#v{sJRBZ&[ٵH#%\s]ԛqgunJFsWuV h!*ZV6`T?nhj%>!2Ur:kD~JUԊy R^u֠6>曨B=GbNj-F-QT8)AmEA*y~g=bzUy E]fۑ'NHjqH]FjcM6-.SzszdjveEo7 $@TR4R[trVTKdŕ7VX[d`1֬vn%eAqnq 0^OH~3-Qq{)Vp*=vˑTB'$k׷ elU tN;,>r8 4-r3N1[Zi]^+p 2xV]T3T8Bu.SAQf}HD~o1jFzT)ܨ1GZąRg!lE dRs?zdlR`֗edMVkDt1yE 4jl6%IbT0 Tfq.ۡbgaV).\s1˵yHRĤWn4qwgN H1ڍ.t ҟl;l[uJ#wkՖ\t3۠@5m+D:h8Wï:eJL *HkUTG3؞ ɶ:dUYo[e%; Hu庴-.M␴ s(%f&F8 eWC|+sK@I#8+OqO^_t+FxR$J@}2傕vL@(N& iY ȚE+i3EXKYye]KҘ@{%qޛ9s[6mJI2il\QA_Z?hNg kǗ ~f<#5kTZ%\(a)`Wag1bTJrO<~דe7֌K>JHk]SR/.uBR (# ̹Id\v  54)zRB?z|]8)P-+RI@{T(y7v7M0ڒ'l^ھ[$dOR.R؁9U5fjJ O8$:#S]KYu¨*42ji 6r(9ky%44R1MVeA$Z^^!۹WGTq*͚.ڃIJBG&95B/.4pO5"L$tSڑ"kmIeZX@S]Yh)# 3IQ`mk3Rp }d¾iPAQ+篔ҡڅ6ϬR6*=0="BZ~5ay֢BozUJ Z6RHܘ-n);ȤԌPevo(TR O4 ޴,B 3_]~6q84*G r9Py&)`49&U(&AFU)ޅ zrN JݕZi;VB%)\ ?$c̹DJa&"kM* <=n(&@ &RQ nNuAiZ$ MLtJ^aԺLMyM<ڟJ#'٨׳aw:cvwa-? N?-mnC--P ;JG4BQ*:^H)I6<|-Em[YZFqLmJP)=f9l4oRGjt-u`ee! R>i3ʊom*$md0qS3rLCk2:?闒f j7>ceȣwx$& aDmQjPVIh[IS]IIH= ȅ< ?z GLRcO$.HRTzs]֑'3WUio p=OMR1jI.Y߾JmP*f\]ˮP&UY"<|\hObpSvq&ԗ7j5[J HMhJ gwsn:RSf)(y8 9WQ֭i h_^Luui$"ۻ!9=Z6̡:^uw\"f*d)X'$יs#Q:? Y=Xm>ڂ=II`k߸RTS+{CE`8RLj\ucn)= uzE,x} Rɸ.J?J,B꒲a!#_Ԭ߶6$&T|o"R"t7V.0TPY~d(.p!K %JGarZTŒΊrAă=M .  \@Q$z ~aVj1$%@jE=Vv|-5;y5]E@欶Қ98) ($NH] $әza#Ofj l-HԷ XHeŷeEmdWlonہ)Ơei0IM@e0LMt$ .n!>ԔBGH&D$Վ = 14ՈHT uȉ)B _aRj&*e$ĩf`k7F*pQwڞ MS,,j$E(*2"~vqtJsDdsRP䘥8hN`◷ji*O^Oj@AaI4fIJ)8b *b)$VP DL撤{K*# uRn HJr(ATPdSX O4("h$ 4DOY%p oa""zhW RBJq,O!uQힴr1D). ,P3N!J*=ieC{zվkotn\H0w%=j՗(I15UJFR*c;4E(8j EQ0y:~{j``9>MaSn1B6memn s{=ise%j& pβnI$v4[RSe3Iq .WڷWdnjr-nI)9u|)#SMCЮym%- nH j\i#H,$!kzgl{-Ɵp<3]nlmܷa<*XZ!i+YRGw,/FӐ*`Q:سܷ0|GuO'Ovrw(gPӛuk[Dz7g޵t[?勎)A#+-hI,A<<̼K2k9<.Q8}gEpy+vYmŅ$*1^Dˍ1 RG@} +Zq)1H42`jZPG>u}"-7GT .=3W5bբ K?5vmͽT6lJp$qY)EQW䯑ohaA%jީ 5{&t@B*i\(LDW #- r-ٻyn(-Ӫ.zLZA LAPP .th;qv Iq"Mo2߆ٷuH@q^cʘW%k|[RCOQZJלVe6R Qfc[yj$+ ~² SjER&2etMXZ߿B9E6[%xEA$*fjӉAcsUT$e4 V v@[XDuS;pTOLDSVDvs=hHtZ )klDP P '*3]-CrvNV$MtL!G`MN0VR[ڠ#dFf.Ve fYVLET'*0 3S'H4@ɤLP9"=@+8P=42siN" R)'z=f V,j\ީܛo\\Qkj9lr ?Zj?oRDĦAzlӭZtSٶY [eNԦTy[:$W<ġzsN [=N?j?jAhK]Z@=:ڃ }l2BA)bMi.4Z u2(œ5ˤs)ڙ#=k)N}2P jMVZY7 sK㉕%Q'{1G#vw"ݖڶXH@- jq^X) ʻT5+e;$P&:[hulI#~*:`rj+RRSBFk\>Ykj͐}9&phdY.8n9?NW 3U쌿n a3'jBe^,Jd F w5N]jnI;Z%_?ܖ*ZLnXi/@oTQ޾m#p'M!`Jz*W-7Mb8ۏ1 L"k !GSᛯ1 OZ HQ={~ pH$ [M3pVɌIL|K99fyJ9HBT ޵#Зa n/: ڻ ! zIm Y%ilͧiXި֓׉MFG@:Vs͛T;WT_jNI𫍵kpT9Ѐ׉ϩ5TWkKy-PH1ZʿԋV[ ]I OxMc͵Z0%bxj-X krȒHWC)UkJ.7}n6f?Aѻ)udTHp"{㒣u)#{k73&) J}SI~\y~5FK%HS:)t)ǔzd[ZFHr i&C;O]hښgF-t{\))*Sn,! iH{B-VwO;NՆlX0Y#Ɠ[ nPI'8-}hRtU}2J қbC,J`t^+G;`mu>vÅ11qP(WH֤Ah^jօ.9nWbWV 5jF BP$j"JqԂ)WT@JFs['}ĸ|) 5.AD(8zCrb21F%2$ߠbK̕A[ Mftx޴ KŲ=%C[Dz&U:q!(p/-mG&לY}[[$JJnSiJ梂Kz Ǵ,plPҗ6 Z&j'Z[ڥ z5fm).l!*0lnZjv}&8SJoV͡ Q:ڐq)N䁘:)ZmL$|urW .!Ju4cg((teʜk DPGUv2@o5ȚVsk 05GLMhܭi.nHeʹA#_bo3]V,ޚ4]Sc$q'F.)N;i`)M'櫋@uRjL =b*rT۽Wҵ-9Vچ)^:Lw5cu^8qjqKABUz׻jiCN (Z|cU_4gnZT)`OX f^/f^˅.Z_%;'¾+rZuE3# I"n)[2q3m=@`U'֕(ʜskZ V7 C-q l @ҞJqM^s鿂 "zvrh#Ţ%%]?Vf<u;6-n?K; @'ՎHiĕIIO_IգU]QKr RZc-ES _1U–` I6j-{jD8RF:1GL }y+2gtSp=Zn9@Teĺ,nREpzî>J*秽vT$bOR9&ܩ=z6y)QIޮǯVͲT^-'EQSWw ]z3dڃgxzբҀAޞ4ߗnԞ<㈶ش5(m#yq?5loˑOrXYN,ʎO@jMcBa=Ħ/Gz1XK$'~㟷jVn^:ܤaj8 ҴfH-ԥJ'j7 q$ !%$t: n\=ʣḷ],4RDOQ]Py)=*i L$,b۰-\{wԭY KK) 8iQe"]hmsWN m1+X*ΩAVQj u14cїp*E  L8XLILD DI! Hf{ бP'"!\L#Yu*@zѿUoI)Tm2E5ũkKz5kѧo~ZeIlu*YAFA)ʅfj(v7$dSв~f6" iuET42cqj~擼6Je!1V.n]KXkHEWoE픡OPx)6 VޮݺlZzT.\JCe|3ePrե%[Q Q#yXpB ʔAEKvTGӹ4ij(+5ٴض[9q꺷` RJ:vI_n.f[H0?jRm,VA*7Ot:efc)RwP;Pm%TnԔ̑%C'⾌#9;o1r]ZFڰ'5&kT&ORkJ*kkxn.n6mT}1Ѧ6ٺXSL$ZyЋ*_ *ֳƗqt<@BJ|ǡ$W8NUI.YvenQJiuC&0>(ٕ.4n*UVi,8/nz ?RY%YivFݽi—VQZd**U&߾rJޠ ڪ)$L8܉~ Sj+u\ ÷ 9zRcƖS9ճ9y7 ⶅ u?ZdĔJɵk֧Ԧxu W2qH+W浵b®M?NcdYÁh$k޲SkiIJ"~*åJz⒧)֋.<tIĢeEaE,(RNꊍp8d#)t%MD&$bEV 5 A N}Ɂښ7Ee#Iȡ$I"ĞԈf(qT8}S6szz 3UzD<ԏlJ&{ёELU8j"$ҝCW6+KU~@"y%/(Z\+n︮9#ѵ$ub{^u B ޳u;qAM/jx]QIcbCt$] u-ͩQ=kp%&WXIik8!uHMU }8A c 3UӘavںqnxEgx=jƸ8j6[E2gn BȯB$ߥ+pb^Z炚 uwPFYgOu8-'}e봯QPGq]3i/ "{ɩ/5+o=@ӵQ.)Kaũim+j-RJV Z)j+vօ62;=k]C^0w|VSڪHI5kĤU3YH XbŝUΫ,lo^ܩG.N;V_֖_JI$,tj~k06N-С%. q<?yhNT=EU󭭥7ТI1S%Y [ʜ}jsGM]tBGp9eo-x&jp)i)J|SE?]tvBP Jm+ ֵMռ#Tu-K QIEkDі=E 3-UmzĨ5y,=fЅ|DV.GJ="2s[ŗϵ3%pAIU[mI#x + {[@n+ h44M\8ŖI;W *5“䗟+[*ExM5oܲ>oi륧Q(mԗ!JvoljpnB'tѶZ4j%$D^{+s%8s.R- \/`[Rj, H *=B}hիYbe HPmf@ ec"\pQHIRO%+t)"&@=0=Ul!䄫qHpYwx9jlZ~専7G p-OLN>!CpV쨎*uq$ՔiY,VՂZBֱtdDҫeHW/{d)!S\cKij% p*YiHZwyL uSh0{SYW+yBv%DG~լhi!e l>x௭f)T)Ds]x q+il)K[w*RK-!ʥB}Rl>SDo x7%$WkܛT*ej1v& m%}jpHReNjͻ[J`-@T-Wp[% q* ʽE{U<NS=fѐ'pZ㏊N@' W_euPm)pWLs^:XRڴ-i!9km`B[BϹCKG;`#WZSn)D_[&߷y69XU!mi0xPW<5D\PI9&,7.nZc#NJ*4"L`<*:|PE <,zrclicEd8XTg1i#u dw9&;TpH @ ,tME(Zu35h8)!<@R!B+wJn+.9^l䍩%ldy *| 殬*Q &-8X@'ǽj\[ivH2s\8V͹Z74ߥN,j'$j޻ V tֶ!:Ao`?lP޹%Y=>hn*UϵrwK``ze6:.)в{|MIm>`)}x_]9].lt[*@Wl\1'!=+RJ.ͫ[ Z&3xCDZƲj{XTR-A)DY)Y4]VGXh^ \Cw"l!m5CKQSj$H$ڕ|}Dr@'\yla#Wmߝ!IГn^)ojr씌d.!IMVv\s ~ev M$Ӥ5bi(ʀ~p*FKȷ%aO8B[x5iTp=pV ɏ{m{@IҠH5]ԕY!ړ_Gz)KW Tn* ,N:ק}I>Y I$?&BпZc5ܼmJ2k =g& [D`8%%se Lh  Q'?|P>pݑڤy*G}P4G5c3&E f0cRhhAfr3R 1eS5KȁZ .&DA5-ܩYP4$$k4FHg"hsD5ȭ 5f6sU#'i(&+m[VBHlѽ ֌!1ʞp6NMV`(9E-&6H3$U+HT;)!$f(d)M1n& D6DzO$Tj8*=OJSH8x2`PPMJI9B1rLdcK/\"A&:u'H.8'y=V,_J\BAm6:I똀+TiEmi8.Zw5ePJصVw)=TL%}m[7nڊ2EUW (ד7l4d-+{bA1&m^RҩA>GJalYW8]K5F՛|0JԠHdHH¶V սZmVS@LEwZ[%/ֿ/HI*'ZCOFJdkI 3/t_ .a)1w#KqeePLDTqÉ*vPl\"hUnݪ_eEA3RgPu+i-EDwIY+5j*qkJ.41WM FvVݜJ&9hPAbAzˍ ^Uv?䶝ƴJFJAP;l)Uun;SoZu-JBvIR&OZŴXMuvM<ޒ ȃՍeJ t4w9xۆԐDR= V2{WEomKa"G/y!ҍ)$#-< 4ܵ>٢eZ)5}mrD{\opF99ܦ bSmQQ(IVjBV~+iGhͪH2kVl&D V E2H+Y lJIFDD ܨ@[Dj0 kD76͔%_olgۻqf(iaVv6I%t" (HDujE94A [8nyIV$Z\a-}JZb rV.{"-t[25QFDfjN8zֹmlܾbFG~֬Vnb ZujZħ5ʁ#qf&2889{ln<^M0Ej1Zq)}jp2+"e1Wݯ_!)295w@_tn)d6; rԘ) i7;G1ަq3Dڈ`)^sIktݫ[ͷqxvʡJ&}@KQP - ~<9?i4;2H=яp˖!eO5 pg) ;T!dax" ,2U#1Chܞ4H=8 U}J Z{a ty DJ ֣'fPR:U(G{ ݺ[ Wғ[k6PWS(r\}ަ”#e9D1Ӷe&K3z8kڗAd򔴐LjT!O>PL[-oe9[D}U𔃌RR(@03",7NT&s/KךMldާԼINJ;k}IݷbvYU'8ݨ J*W-*Izh"}N3hKL4vrL"_ay9jZ_ː),MʗEI:mZJVbBj4U)/<~GD|fTOz5!xGpl\`|Dz4,Uiu⫨q BIḍ;{^!uuuCV Ǯs#Mg76BԨ&&zضVn9%Fjj\޽Q)y/Z|Gt6W,I*0iKr2ETfS#C z$"IՇ\ Ck;B3L{˸x͐:I1О)_KTAi&K/?$1NqZCI*ݹ@j|T ۷q>_ ݄֨9 $5UP(5j]zR4ղ/٩rFS<ը6-" KwiQ tVqV@DOhBS0qQ)- t!ުjr3 )UUZ*lVRԶGJ5$\N 21 G~QE;٥`Szd D%38}DmZ `i=۽.m+V B(QޠU["0vgY\ ʌg:B@R2R&}څ۴m&]tQ$.0d=zUhESt7 OS[/&嶉 B8Ne>QRtJuPɓ5\Eu'zѕ{N*1d a?nT.T$  H-*d (*Q եB61$~j\mD&UB#l#+WmoV)Rjn { '-&H@dS=)С*ƔՑm Z*=TUѪ| *=,VpBIPꬹnTa$$e)2{V#VvtO#BITҩť )V6#FB6>Y) ŕ-P=eC֥te+gZf:5&hF7+:.& H,b6y߶$m}-Kl(McZmÁ{ EZJNb(-kj)%K[S$@wTJ0Vu6&Œ$zsr}4NGq֞]qиkd([DAtjPʁ >J˖ mFwzV>?Bjv_}IR[X$b/mnUGE2H0隑-VuiK K\2}lu)$nVMʓrRLkbvഢp:ⰵ0<)2$wu ju6A -JP ]$·}KHNEXbo*85=(SChJdVAP3L V:sn( HRjKn[ڗ9=MVuLJ5"|!C#"M2%Y2@Yc/TUlgDRK3ڝCdNM9[Tߥ0i$qOJyF@2AS%Gl*\Hn_DYb62;N'TRBTIUEauplȴI)Ҡ>oPmXam_tPFzzh}ԕ|TTEY' M Ag> F:SY̨4{UD`a*ݛ+e$G"N9SR eB$滤7~4Vtd5y`wQI SP ТN+JmZ N9]__Zυv2lHm;iOifi^0ԞѧjW*a[Qӑs8厢\|C%ه&$T#$2)Ͷ1^UAzՐחsnFd&q/'mi~pYRJ#|wjOqWe'R U1n|ZnOB StmA%fJBI O?)snRs R 2@MzO.?\xNY;;>bSijDthiǔi?nmii|bᖍ֐ Iww'rPq='湿;KVc$vr~uiJrGEGOzOnaҍܜjYi6IR*Q_ Y\O66iR7ygy*nd: dnaGrdڴ5 )k= ,H3Ucu -3jX&({N;B8ںk!^th iNy[@f5nnF1kҷ vEE4+H){He*A1WmЖʢ dclDv^8E+G- P JwIZb28 A(a4%n*Av$E;W˩stNs׽E\6q"R0U.l\?91ژLUU6nP.wu1^ZNjօ %G[]3pOY!]i=hnKUwVZC))NՎⶹqW%ݶl梵7bJBxGt X{ JMZT($H涾$A&H4 Uẑ&gFI@N쑚t@YG=ifI JpsNDND`")'mLm1'j6A%"q\ڪR[ŵ e.(};u2Q~bV{[̕I YOmrxލaڔUFW._>Zwl6l;%SXlo" $ך]JR)=Q(ݺĂT {w4WfRB@۞?ި=xCɂR6Rٸ^SJL˓[-\(>VU~iVBUTXϨsoEoxSA\@%q \6AOb{yۮ+$sIIz2f=2A⬦d mUS q=4Q3GD j+q+S[P`$S.@BpKO'!;;Ͷ֓ae {[&nJS gܲǖS;1).$rjzi>zbwړ)׎!yS 5ŭڟ1 #1ޣ-k'ަQHܖȀ9f<;BETe3kUS!)$&ytvڀ=QUٸJ|ԥȐGZ2¥Qd#EmŴ䁹Dj HeiBTP]\HBTIZEP&7-6dJ8\$Rg Hy;DI#0=[K&nj^կUHyZvhKj!P1Sr@jѶdү-`k.Xt8dT'.m) "55fla"m%hBp'Y@ n*4]8UR2C.VVvL!9)v[% &`y2sV4;ޓMUJ SmYS  DvQlpjM&ᗔN[#P,)go|  9$8wq$yH8qIN'$UK] &){%QdN k6w@OOGӼJ4CJZT 1Ro+TO1*C)NsYwuRRd%[ZZH$Un:ҤH d֌5jvR#b9KM [UtEtw im6RսkVI$t\鶾u@rdvjV/p|ȏZޢVFx Y*< mAtA'2 Nfڴd/[,ޢt-m؁RN q^/R$٥Pn jAhvպ'v V ;9_=qT]\$#Vu֡(i%Fzv4M-j$(bEIˌHˉe0^i%Y ߓYZw@K2JFཹX^x(t.)IAZjm */+ZW>|N8~褺&9pZ @hK|t֓1ާ6|:xV)Xye 6T]+t䶄TJ=skI뢸J R D8Lz^˩,1'Z.8[!)pݶ]ٙA5#,vTB~:Mu[x㩬m3 $viV%* ֱ }]=EiED ޫY8%Twj姟A3Y-[+RS)z%"hEuNy(6QB"zhցh<d@_]fnV*%P/,+`8ޭ[Ψ irg6+PPHD{Tm ye GfJݽCV)@U&{H^ eA8a޹%E*@ uܩX)G`6DWQֱ-2SbFyRT8Sֻ)Rй #Unpˆ<8&:CTi A#T^䜤[KrvRFq)u[TҦm]c3Da!$&8P?=k("}6@ ~E}a#&GˇAjƙpP h_Ȯ<\J0eJ=Iv[d ԷaD@j[n+l=n)&#M`PvH`$D q H\%Kh(nn:H㊓P _UZ}R%=j=^kIՉ8׷GDG_zZnyDiz3'W.8m;#Wѕdh HJ@;9hZܲ@-JFd,`_?ԕAfV^?cUo4 BAUYLq^8\Rd9Z6d0@!Fr Z֫[x}ԠTʕ<;S*`Oq.Vyʳ^idgXω>Yjkqai`).7Raw(qqO8ΣhW ;C?milEmi _ *?i|N"}9ѷs8'kXR0ެ[v*QwI3JmlSL($m8Zy i8>JB}뢳eI -z F76̣m 㪻}VNmܡ );cug"!i HHj$Z~# (޳\Kj -K"e]F*>n.ڵiNZQ?s[55۸$)ɎzսIV1`Mq봺7o8 QT}T9,C[RIOc֬[%X}1CR ¢[h .3ytq_#MЦ<_bwnMuKz^:Hz^j8Z'+8 )]{NPK-w(1 ECg0 KQ>0~rY-.kѵs6Py$('ިj_Fb两P8{;_e`Z$IACMk v;](ykCm8GY&H@ݶ,Ϧ>|G>[}Օ8ߴBīZʄzTjN\ؼ[Bp :M}<1D6`K+44wB3T'TApg{m".)JBbeAޖrK$"jdAc@szڙ`Xɑ{[u:5`4$$ןY8w]5 6] teĤ5gIs͕ZC7dkO:lZ;#tO1\se,6.$PO&*ٽ[PL( y%5[W<.ݺHQڜշ- ,RU|(mo_ԋHJRgȒ=ul᠗.JKP pO Hy?qUhPHR[Qq`Y km2 {-ݙn&n6BKvy.s kS(ϱv~UBuGlIneTܥ$zEV͛`YZw_6< EVSҼիY)y<"6 w|3A{mrz/FdFޅ|nGwQ藮_4ҙ[h&ђGzսҵ6D@TuWwVqenrH_ɝtiҥ6KBzhGLcrJӻkZ9ݪK}O[8RcaO?zZ4KܡęMw,ҧ#z-IXL 1M@i޷R/nݤ% ZAS-b p[WWEˋɷn[mDIH<-ͺx&3l6Y o=rWj,Od3PQ4JArbCSjZˆ#$~~-W@vUKHrR9jX&ZQK't]wZwa-^jL +o$QQ R(!Lo#c"fФP5n$$S#FI+*x4ԨQm!ӌH5\1NLAjV#_YiZ[BokDY>``'1TIAHk1H0E(-M5zdL &$J4zЉ̉B2x1VmeX)eH~w ;S BxmFSn8R`zpҭ- +K@u۝2y/)EPBG'XW!@`i#܍z&,=prN1gsSxv'jT`h:d*cUZY$ 4c[aHڶDu6!Vm2(S(R}G&rk9JU: q¡Қ 14ԧy yl$>'ԄLnb?'hN-hI@5bJef`ޒ2WT@RUs͹ ,AUS'jg^S8$ 01]%<օUS -0;nmT?y~vDI ATWj0OX2>Xds9Vͻ`FrOFe>X;5](.o=R ;TDgYCR\BH*TZ LjݜGE%j- ʈmHZݹmNI)pSd\W*fą!nnI{A-3R\Fަ*8]yFsbesr 1^ջfĜ!+JW1h˜)RZ6]nɔGJr!q\yDlK@vGwpz 0j(t?ұ<`i>R@n-VF{g6Ԅ,c`q&bcmKeIpH3v xL )S RdJ~VOv(]Zz]=d)^2!*9pv_%$@*9|huRC-qG$dӝ)BNg۷Tuo1e@ʻo !jS)qkPJ{̾ 䑰liVlIPMjZVS ILNYE Z J@TM\V(@4s/769KMYK!\N*Sv*J& vNzл)(:ҜڣM[ʥ{vǽh-(.@z[LƉ4ԕ2ZfJZk ެil*!j 4\)VӯZ-n*IT#>R;ǵ\l-҅m)wMvLnd])C芤G-3`z )p!M6-aV4ihrBk ՁmIO~V8ۉ^ 'i6ޤ ;ZB}K#4X1u:9jBjT1MDZUlޠ9$g#;{)I$ qֲJ(RAn5қ ;9#0{V=KRrO4ƴHb_qMWХ!htY$WB [ ]: 5Pv6aO|!YT(IL[M(nNFR1mlE(t)HnTdJ A g譜i%k+`S ɓP_0D,AH呚1^]m wÉz^-9*qi2+XJ< Wq[e]b }M'SR⯆On`l TaliJI*͓-&O'BT')P 9d wVR@Pij~[۽ItBm2Qڪ6$ b[{K6ڭ>.!R `;QQBӭkiN)kF-|Au_kHҮ钋EIt~WX*eޱ%ՏQ[#h'f{fn%D \HOTAf:ti+cYXԒE '$+BRQAǽOpKi@I$` ֜~V*UJKmm*Ϙ)@p":UQ)'e_"VTt:cҠ ~םi&LNe8B0kZ)FA|>A'b )(JQiX>J%#Je{ANIX @bګec jK]B:d@ mQD6$n*SnvRTH#ժHhhInї Ä;UP H=j*ـ)VdF2k2zo)JSdI~B[ )K_P=@naJUkT#Zx3(}bBbaj v ґj+]G#V3wO%Ƃ aTCRJiQH{UMY{V:W%#[E_vmVNGV=ډ[A3W5hH$LUЯD-䜂*kvoA=1VV,RG"aL?j!'UJnԤ0}@OLZ +Ͱa`$z+㰭"JTԒG[fV23L7)H"cKJBdQUq*t߲F/ZL8-Ч֍׈uYDHszBlpKP)@Cϯ|wJ-t h<5-(KsR W5yIH@5_l~TEE5l'V䑮o{- ; )\< <\eSdrHj6.f/q &>Ԍ_eNG[z"%(R LU}3RM6oY%*=vLjseJA(\o)P9yeKsxUwXWUl@;9?Ҳ;kK^eVVH3?zBTW|תZ4Т6tM҅6zVD#!0I欰Xt\!@+A2$o*TJ =5Fa(ZC[rCpkϓB. P0},(ĤI]ćm$'}ukGAot AT':J@OyIQR@#YWw(߳q#QӉQ=! ќ*I*p!"H޷Ӧ(Jh% P Yd{2ʨ4JS=n~ AR8=2ER(%A)G2bb~*v; ck ׎^|V1,YRZ1.ڭŚ-!CI WۭYuT!(tR鄒SFkٗo6ʔ? PO85dr:U py|nKzWV'}ًi0c-I,uznTfjѩ1Qj%*p)E866q5gf852ӜKؙƛ|^d) N}ARX2Rj톙/jBlø3WJJ#33ݪWc6L%  IPQD0.y`JP b1P@HP+MWwF[jzWTU[n *y+ϟ̎-{*^iڬơRfx?őS"V^zwǓLֱ4KKk[4j )P⼘>-l8mL6)Yݵ;mQܢJ2\eJ[[C e)?vz %IU"BoE6ݗJDM2 Re`DԏfNFBbAy4g쮄7!T`=JmXܵM`{%{IVîq*LYQOIJ[$;CWj@S*ov_D.Aqlq!kXT@b76-uJ%G&{T [zA>P  zնfzNp'hOa.mevТLxj(t0Jޚ]qҠ[HȊ^|rfRE5/˻i¡ܙ1֮۾ !'nLEb['p {QnkZIw|D/~DA[.灚]7-5q()<$:#mR윎5PUQan+kJ%fqWN²^yS$Շl!eKX@[(>W;[*)j)uh l)[rՐ^'.p4kM-[5Egy9=+z:%p4^0SGU'ۼADd՗nRBKFWid{MN|vV[wn;Lݩ, 'YwҫcP$~N4Up,6Aɭq/4f@@LϽSsqT6Zm X˓ B{SQ,)Ѻ:rze!@F꒕s6wzDLta]NjvA&h\?,9P`qR_\[\Eh mMI2ǔ7<&ӮcyK mRx(\mIZdQCZcHJBUM3Ni,حKVo݃*7 R18MoO *JN+.$dz&h R\(I9z͸C9'Z()>n ) +&%Mp ?UyJqGڳ┼:8R FREDn@x*u @g|JN9ΐ0$7zߴ@EHIaMeiN6piR*HI(i⠸IK$|q[K;i zOZ FE,+IU =J]Zӽ:f oaOjӊ-*sڲ5'/)p5~!A;/(A|kq ̨yW%ITgY<Tq홦<'2xihu$ D穨@Z-"V#T޸ e@x̀IH=jq#4\HqBJ \”?aZ*RfMIC(yHi-Pj  @.\YWN1@w"n QXV8h۠0L^  EϩB\`*Ζ613BN'I`$6a>L2^ekQrH)CJPGB9Ǚ mP{%]Tu֬XA B\HOJ$:Lɦj.\\$9pUK]gPrjnF᦬fwVnn<$T7.)9VA˵&ALҵ\UiI>bkT!+ZVș?NyW+p$~Tտ4AGZ 5Jj{P2 'q&f>edGMN'& VUZT&JjQ Z–BPqg<Ͻ Л:7=\j YSDX6 )J~jS{DwjTZZpJo|[}⍉SBN'Ojfe( ꨤBFѥ8NI?P(QHV︨C6)iv&G&pJӔ?zFZ!Vd>] Tt>IjX $ZPyX8VH (ϫsvY}E"I]@t*rڦx -=Oz\4 H3WJ{l[J)2zh]:zAHp+ ' uune ̚].yF93?\Z\*mUiRLB]Q[*ц?R[Ozg|Koz Čb+}=R'ա ~ ^|W-$F5mJSKne bh Bu-n3] kwb).8 84WokN(>/F-p"R I8yEO!ݴUyj-mЕx$p;>a&ۅWHȖG=fl(}ؾS)Niܠ/z =),[۩UvGvva~2DT5K2$`AOmm 1׊zTq BAT«enr))\Qu@5yvJ :L+&E -KQvLZplBBS*[0Å!S>n)%Q$Xo*1 ܐ nij-@#LGZХ8+!{OpBPi+*q$d POڒ^I@{hQZ\j(NI|jbs*t=fݩCyM gYABӵ @ 0l$*i* IQ>jk( ٟyz֘O S?U."$?:$(@w9J'IQ2XI%e&ӂҠʁ8qD-#`( (XCPR`ӏTJֶCQ) /sX ݙl]\%h^¤Rbkūq3&87$'bD84 [j*x45zTbFhRDITbJ =sE2Gtk2 o;8I?ұm`iMIY) =Du[YU^ae0'W]zHRe+IZw)[8(bG52Sqoں勊B[RҞsYQBf گ+vX ,T[| &A5uECqn)TWyy~ef:OZB Nz֖8tHⳉ:U^KY +AY0Bui$DgY:Rd)=M.צ}'Npܠyl5 'tZiS-N S ڸJЯ)[[5p)lnYk%cIir⚢cq~n.2LTJ; XںEd0ڃsNwl5Y[ANy*HHTUh^8.I)A=}_6ӷj<r95s龞̸mlzD\@%*0ZԡvexI ޳ujm'޵)P-ORq !TGA?ڗ탁EI Cnn *BFzkҡQi[Ԡ8AwMe=&\u-}]syZ`>zUvܦZTɎk\У@hVoYR {k90EC+$ҭ[\[2pnRq#CNHdO/-b+ڢ23ޡŲnl)I;JPn\mޕ k]ǖW=뚔c/ M?qpV\}JH?ޡ6(R?zгMp^u`2?^8%Ѹ_pN+כ6RϐmFBAzeA:1Oa)riK0A\Sn\v HK 2\ZڔH3ڲ.}TT&~P9 G{AfvVrmYp gPn,2}!;RYXZJMn Y-ڤ% Aap2B%J?͞8ToiN!oZd%3q$􉉨m)$zUgQGvBn/*(F)C&U7MBHK~Ҫ(lp2k-l)& wr[X%c±_R{S6Mݧ;RGj)3n)c% nHQPP:Le*J4]=m޴ͯ"٤Xd{:ƭQλ fx*S(& Gn=hLGVw-m!DIP\mQP:sd~D'FRpKSvg57Kr,[MI Zo9rA搥jV╵q $APxAeq<ϕ6N@f&i#LHRR JmdΤ[wG8Ujͫ-Ml)Jwf[Rټw]/5UsWz܍Fʈd'v:ɝC84ެs6B7\dHmNRH\ΕujN\4`!)p<DZV:WѢ䭖-Q(2bI3kFy\ͺL-!rROWR}/fEʚyŰB6 y~ZuCs`%]6y lI&Ip%}>+fo(AR*YՊ^k$@V |{H"(_UǼS]m!@uF[f")SkFRWZmBl<~`D Eղm.'*P?z9NekT%q>E-):\M܇-""#BS%nQmVJ"TSvn4g:E&Z~m#x%$&aiiJ 3?1R\ ilzPN_Hŗ<fLjPl)ֈ\~jq(ӂDQpH8՘̥e[\,'*/[\)S@[l,mR#JWMn'ں,Y#;E7%*jhY2:ִKT-?_ObݲP(! ,џ|nZchӪm{޷e !'>4NR9W|W/֐9 ei- 1 ZʎL+zTnصmO+d=<5z[v$Sޭ|jLg2+WRy& fۭDy@?5};jBP7(n 8)).GFMin ~[Ґ*H W1nҝaN:H7Lnn5Y=5%ֆb4kTT!3~ܭ9s.>6;QRpȵq-Rs{KFvrٶH@wOllOVEq-!D{ A}9w}_MQrcqiTI xX`lJBR$&G}K%?O2FON ]h*1]tTTRm)-SyoiRFCzR ޲MԸԄ߱LJ7 d*ZNʈxV͢IRQfИvaITce11'ē&AK[I8&h (kK, W8" 6%M(=Z$٥#rP>TTߓnva8W), W[W`G*T%]^⒕ x8"OJ4n~xHDp*'<RF42fH-d^)gЂQIգڸvZVJB= F[BwL`KY I\Ɏ V-EG$rFԦC8TųʹI⧳\(dW){aD`*ށҘYXY= MR}CkN  *qDL+#8`%295FS#A\Í 5'2,wQṔi֐ % ԉ)Yy*ȌVݦ7vY[%3eFI>][7`.{YBDIPq79IHT6kKi1{֭ʐ,[ hܖ'bNnݴcZ܍lIRT񈭆Rۺk PGbjvVvoujnꐙ I mQrSҹrrmNT栵O)pae@HHܚUi{5Rjlb`lyx"+SNpzʒ:h4t+r4˧ 8&vրJVvHiF[RSCh5$߳4\ijj$ygޭ!)#K<5Nh'i 3Ͻn&7n2䃇Eem?J{BR+JGSM2E!+[jZ8)Wo50, Zʾn]<6@jngӺ/2T`CPqvpJ`W-lݺ$%* vWm#w5{pRF`qU81I•-[L$HBv8ɯ6HGJHZ8M%A/m )ؑJ˗WJz(A0LP` t2؀ , d"BZ L9tF?)9094T[P9 /^VjBvRLGYeRJrSһO ^W,2;Ua)G_:-}"иʂ\ ya!ZSk%aBBl#T{箔מ4@Iĉ1Yz%qdRn8 LH 0Z<$GNR'$f2#v*P &L_U3+qВ] <ǽR\۱@tUA.)چ"j}]Z{E,P !^T,<%;+D4ՔxҴ5և PH=:>Z*=QNqa`ҀSk'*+Q$l7M8皥:oѻZã IuP }÷2p ?]x: Zmbo҈qZ-!;RQa<3 V,ӏTpky+=oH*${v$IH,Z7w^bJpZm!Lb-h2Bcf:WK Ojsma@ǵhٶl =VEBPOϽhO!8Ä6`"yIm( aɽ0!L"4Vm!ՙڔ5ӑ#pPGWI-Y yjRm@{ԷMI++LYPwA,Ffn8޹[2jw%ҕgIdԗ*XWWB .sh-Eؓ*Jwae( VX}>Oj1:Z J ~OK~]a&OzԵ)Q}y, R r*J@B=i%ۥ{Je{P]Q@ ڤIz"4˛RJDPѺHqhXڤH"KLZ)JPȘ z4̴Y$HDNqsn /CT[)UL$G"speHŽGY2ef.,ou$=* .[BVS6V@$hwkR`Gjҷa+,aה;Ԗ -)WjiM9 X9[Je/LMH @ Koy%ޚ㺀jjQQɚ{pҭ6˛s%@FsMT+PtR1$4V[{ Uy%*W%Z *<OR-!;T!8E&VPa۶$5c!߬M\-AD m X$ZIи@gTyn!k/$:S_I澵  \9jlc?N8qIgZ۲ǘٵw)#mepB)mp${ ԳsR $} Ӑa/% /ۭ2jR뤃J+gX]^FT?`\mQ(\M!+ [7-馚NyaaMI99Tv$ $Ϧ+7yYI g汋χBs$Myݶ!1C#ewHS8&G&ud++Oi ^km2+OSPbjܨ}"֕>'i;YK,ȺA/pI nnTV˯'\*i鎛}TdIih4m_'c` WMH*Wޣu{∅L ur61lF^46;q,UץQ?gNCs&DGskH%$hhҀ*Q"9#- 䋍 ɃimmfcGA}Μқb.$G a۵Z:yiQ<WYf[֚e l<f* qPMMzZ4ߚܠ$GZnR^X>h}-%iR#EJN@⡷R Jғq" 8.95iZ+^&LB@9@~+@nH)8gS57F"dg&(\[tGn*pRơ fhVDjŭ*$knB`{;F;n- , #?Zd(\YTƦR#qUe)y1[8[ j-=omE$V` 'z3MXfPvHRʚ]6nZTZmP:Maչ?)jZ6U:ՠĵ&'ڰ{2XzۍA¤fsY>R);!#ںm5,/owkR ١n}[z 1z? ~Dd@*gv[YHR=vN\ 6QlC~PMknPӭnZj=]uZ2J$'߭3Q*IB%X=R)v#w̶mR B ;ONa>`jiKo?*m%hLp:GSZδea;tF56 mCe3ȫW+JV@RA6nP= ~cҝ)DMc%R-Ĩ{W5D֢_ZRxk3PeR$эWfCGBZ qEI$u EIBs B-THZE7Sw{I'0OZe[([)RGJWpK%F "GV[DnQ*KZ$]$'ބ)8VLo)[i&=I$`j[$$GUuEѻXp OaƱ5R?B;e=֑6J K[XNztl7PU$GҸm@b^6.Z{^b[j ZEh4ݤA2Mr$bIy7 իlp򁷎k.8O;0Oɭ :Vʥ\ jkbn5Z88ⴷPVBaBf&OrM,As&$H%qUHfE╻MhY:{rɔ:-mڅxLzWrUjS"<`T$Zb*Oe[Y!R EߊyQV?j +*"q@*30H?U]O(%kP)@LpdO[sJSZq*>.)q/iv^& FxD啳o7%J_ZRJA4rTwLoSj/0+ԱI}\R]Kl]}3m-i 'ګx7 t_-hohܢ$ڴfm,}J Na4ia7̹!XaIJSXp) awN! >-JVJ!{}s%Ry)f'}TW\qK_S۽*5aKr*o<+1TBVS;PfYq$9bg@ҞlyN㏽IdrU͙VRzj·kIqr:nx]a(6'ko-,\5tBSj+6߫i[.3)jlq Tb5hXH $RkuiW:zJ. 8P!@]imڔִ҆ AAٸ|Upvf'g僐8ζUe+  L]ұtwb+]{Vw-üHurHf[ '4[qUH5@^xCGO3WxK@WQVʕn(eeR?h?v*H++HǴm; hԮa/+MRZ!!(Sg_/? G/vѽ%oZwiR)"7#Ms:>NVQ䳸̨X16ZB[Zwd@[uZC- 23AM W/\]as15Z0&CHRҔO#d"y()QCPA q_;,G6‡VDF:Z3M3ݶQ;OɪڥzKEdm Q~*4u#Sڟ H#\/JjJk"٠,w!&IoZGŒ6PL{>{FBn,m2K m[w-8}*CG߭x6jfn%\ #bc&nsNԓ[bܺ\7d{{[u\qmD >m"^6ZGʤ$I[lYfS{p"/[q3wdGSMN0J. r"M_[ &y>!=T Ɓglysfʛi=z (xZXa⒒“)Q0JDڲ;YM㫾J :G=,:>2%ż)͓6]+EŽ(Pm8*7އ.-Yp檼O%RŭJ˅)K Yub*A 'E}k-A=MzR|\+z!РA'\nVSe:}vA8&d87!VM͍ ⥻L ZFbxhR]{V`%LL @.2mZݔA =D]c-F5R e6f7Q A wj6W~Ś-B#5e0cCI 1֢B< 4A8e$ޥ.VIQ@N w<@ZJmk'qipOoJkVmnVTHt}cSm9 evH1Ӱ @6dc2kVrKavSJ&wʼō[΍hYR `RKnŪQ#<חDαmw7_P"{44߉MeAkgOm,Rv)f~y55gP %y<݄W; i"ծ[)Jʔ{&RTp f׳'Jߺ ֞а5B\CCjȜ \ָ!I?17 ՋC![M=ȱ.Wv*u[*Z&I[B'yX\@=*E"}HJTCH1ZʔڑIa^8󲝆R#撮rnLN{%>R舎8SM3ҢrVKȅ5R5vDoH 3o^6aԀ[GJTțDw鐧yjIRLd) m!H+2i\oF]Nm9w!eb3^C,:ldp({k!VTHI:bۏ:*IYzjK[D60zwB.H[M(hڸve#L:#ivO4R6 5Ϛ$_]6R՚㮋E-ޥ[%BXߴIRzNv+Bfբ#&mmiVf8i[[zuEꖵJ;U@w轌p,ۍQOAy( &,q^<IIGjC钍ۊq5uU T+.[TLvDۭ:rq+'O;[;O"bLr{{6BHRVvĀ>t_T^m(B|FcʻXm􍓺)>gfꨛ)F)S6] `XzQH&i7vN4$S1Ҭc٤8X BPW&{v5F@!)BG%Xw*ìIN?4Yȷe٢`ޢ䔔!' =O-Lp5^]֘-HոiJ H5e[d&i0R S R 'jeV(.O询כkbn@B'i1+AW{"1ڨ&s\{$U3.y \oxnR[TJGް7N+_Huڝ3ZȭI]s8SaGMh߸XIUËmj*5ci~gęH1Q)$k'h2>բ+i} ~ `У;H#8 |(;P[ Q@&hq#k3*JamupC<[W3=M;BS >ɗBQ'Pqr+ C g>*->%8m)@־K{`jӯݧڊRV8$?T(@BŁ塸$VwWyؗTJgX^!e/haJ";kpRujnIH3n-ִ,[@i+ߞj•~ImJBW-\)@uDq覡vWM0LzGڙa|յ}*^B(1%eI34ǚSWrv#5t/jYy)ZBC^ w}m [6e$rp+,hX WԆVz6#YqdGU]7M6NGϽg]0&ٶ҃ [%2 jyhID G3S4Vʓ2czU9L](IJJ )B3֭YېC9ZʀdHձX"M (D+D#Mb*AWmM.oƑ k?VqA9ne"r Su,]RaIgQ&$ *4|$< p$&FꈭAq+V4amR Jsۚ[>Q`¿w!@4;-R\YAX%IK(iY*GzO<͛@%^!4@*/ K q%NJR:@3[^3a(P3#?|3u;} !pI$FZɿKOխ%"6;֭*kb;QdxEŢ\\nCpX/*-j$RR@]jm*%ҿ*c:ŵHrr*eo-vbL$m%y@3h̍ʅZ6)VH/R[*R!rO&[HJP[ԑI-vkӇ:6޼T5h2wE2L" 5G:RtW$1=˵W- <@K=*i :m-nK@ڡVQFlmBT EiN{M/ !Bs`J{IV嫺u.SmpvԒc+:fWv "ðBp:LihΡq.|RT^' V5 ]Cq-AAUcӸ[Yo*(meuEVWtv)!#h3"kezHPe˕.GxYyVP Uk/י8l`#87:U߇kaq.alv? wL &[MdGC^?9qM`%iWaǔ ~՟spuMne0qpe$l}C}E.2ݧ SjiHzPz⠸yO:wփw PZvJ~]h!OS\TJK `Ր UU(D;ELqJ{Pc.eBPJg8,*J !m+jGJ7A/ݳruL溢V_vgxHCX^to[)P i'Hǽ]ZS1u={f=r{em_Pf𒕒.OU]l"Hܵ$OHmM8<ܒ䏵UEmn%pWz1\ķFFK+n eIChWLTԈw>",eutRH+ܕ&%'Ձ]:B1'w~'fں^) \ICn}U-9}Bv*zO&x֟P Nt).-1 W*TޅBz)bx90D[/-%dp#Ջ+4PZ0tsϺåw=uVmBzU_4 4kR =yVzmnZvB$k˛,Өsp 0?DڪPeÆ 2z+a()m_l JѾL;p8e-/[]pگsgV[VQy7 -CoXi֫de) Mk:{}Mk|/Ӳ!A q!+rTZ-%R.A $ JPfA֣O\ќӒz2ѱt2*L\ PR[4HNH䙮~x^ KDHŐ))inT8"bx5;(K!KpzLU^u (&TT˭:۶ATuZ0YpHbݷK阈eTTQ-%VC m5Mc|BIWɀZZTLGJ-6ˊLZot,j A oռyi! 'kn)q@>@"~~pm’qq3(^x6+{}ʙԚK>o3ZmH-5(re3ZPp3?:wnYvI*ȔoXyKJ+.-) 6ʰ%q֛e`(RhY(ɫZͪ[!dA+Kk#fҺƚ! EF|Jwǔy(-V[K l2]=}ܥ#An:sL[ItDW )I$nQ4\ h2 ZEUՙވ؁U]d81F\_Mh5/FVR՛a2ٰ+q NHLT[[[FSoJA'm-"9O}=l3MÁŝtjM!(I&IՒ[-njbc.n գO[(5SPRBDDBM^k̿ pMV-<ʒSm.}֟ʮԵK.q!i;k7Z,jsa[R Ak17䛇Z0ߡ 0[7v-Gԣ53Y/0(`!kEيtM35mplBB=MUmWNۄ-AnbT%=n- ~k9_dvtL”:JvԺڄ繨/n\iޝ`pKnS!CH'+ KhҲ}!$tÏ2΅=*J8Vsj"ynQRJ"u%˂Ӫ0:fjz3LuoT?rTd 1S>^m‡Cɥ+h^ݕ{Lmcfwd9HUr *Wq!N+f휐*E 6KlV2f)2o}E2T6gLCKHQ:5Z5Yj `0cmr¶Gqz d)70pBy\^6$/s. ~*Cm Ԧuqz{T,dJ5EB]zHzXv%0GQtHA$/ ǽ"A3X.RPHҳu;dn (BWߜBߊ/ZSLkeLԇ(*֍,f7Y͆͵(Hdڙ5{$u3`'e.w6aAa&7(VV'GQ[me! R/Fb p&0zU۲Qk*j^n*j}d0> L#Ԓ>H 35sKua@l9-m|ma%9QOd2YIFM_qNIwzAf=-MiBڼR+,j[!B}P9*jHJ9L8۩8[mH=Zf-<5H0ZםqmQ>5V-o%sV۩%_U l:}n[Z]XGCMmPMZndYWjD⨰$yI[yKx'\h2ܻtP&+N閝W,J9[9\йtБ Xx};iI3>!KS}:eV^i=+FնtR%qB[إgrozZbҷR]ZOzafs J1Ӛljs4"GN2h4N3HM=R:")S4T14DJSQ d6d (Ns@IL{QI@}[RpTζ(SjݸJqP6v#pId%J5`Z9$1UQrK IR\W,pR 0)8>5[M#h ClJU8HO5t"m 4$@Bfr~VI|&* D+'ګYjWްJOI⫸aPNE v~@iT;uAۜ*,ZM 'p&kо/YXIY'o}\@[:xw)YB18yc;dh |)CmhuӶIRRk3Pbʖl۷X7,wy(0z r>5͕Y,5!)[I5ݛUukq$`cT~ A[[KmZp"dⰰ|5t~!WF(*uuV5րYOu;qNy gq^&rNmܦf揖H2 xD+jyn$8*y 'pr]%8 U\5JWC(qR^NڻjvMn^q 2Ԟ]P#ןYvKEf=DZ$f(KRNܸBN>㊁Ol2z$}Zu7z%0 c=km$8DDת*"-IfAƫmG".m+*t?b:6TNٮz)"K)&jKVBUrS55ibRBZ%JFO"ԣTÌ* <34{k7Iv- rBɸqw< ;DWY_䦎m̶4vV.xÿIT '8yW1mTwAnZiZ^md/<:%B;jq{;S.j#qJ꾴ȳe8 )a>à=jcOvͷB<t.W!$A&wHТ/4ye~1=)jYqH3PIP.zh[uBU1Q@m|I SJVd q9fj(.8p;9 Z*UBJf=£LqP"8jZM, I%Df\! Tz W0FzC o7Ooj4Ai15H{>i%ٶ@H')Er,M֗(RLٰ֓6:}ӭ.-ܡiALTuMAƟ6.R%Dc9RrYkr])BJ[X1רՖK+lYvl <`UC\;iJ# 57V!ۧnUpmRʳ'w=2M4 y?iD(bV"IV3LI-/ܢI 2>*ҐTD6-I#jڭ۬m p*bu5JPwD)ݶIL9x$-JҠ/~kE"e{8T xp>kT Iޣ|/ijrk~6܀m Q3xߙflIMjaX}]Tk1p*-'ToL#GVZ.}{zUx18*֘7+zf+=+Rr*"ȔBMm̕ ޷ճ$0. !4WGZ7n~Sa#upq\$j^SkkBAjXm! %EI&RAI q5lئtj-HLIHCK@VӼ)U7t)+;? 0+z[p@MVlw*q2GZcH5 {@>5ٲåBFbqʠV $*}d7 ghҳqW F6f(XHĘ01R2V6rR]R*Au.DJ ĚZDO#Rnx\Zd9_6\JG]Fp#"Eh^U;ߤf_Rn'VО(900Tj+ۻ#"[eRJGp6%d>*0,hF`Jz4U˅aed$H8W~j)7U+)gLJVtyKmNՕ~|H33hin*YeACG VrWN5-(Rt+fmt$AZ6I_mIwC'kܔ&Z#ʉ]))%D+SZ2MJOIZf)/ZiZ-h.TԞ˙Lm֧nGRbL˨D q]奡0 Pڢqcnx%eI =G# 3Twh'hN?z}CL>e’vF0?ZR78R %"01XVrֶ]݀z$d9#Q_HځTix$&te08$MTnn!MqXSMGpӈy>`ZT=&*CRMg" &j vmQ֪m:JrH8Ps4:7fg>ӾMoZtR0!͊Qs[zm$0=qY|Qz2nVRHjŭ˷(99^0T|-zLyf#W(і4) `Cgx/'XnnS%'tf[w[l4Wh֍mPݦ1>[/Z䨥 )&jJ٪$A=o,@@k 6+VD[UBRd^2A ,b0[x$J0Znvt%iEJX;AjN6Vj8 XDIATIs;wô4x14}S. 9wa1š.$ NVfw+o 0i3&-~&EM{RL/dfnP ifViڊ Q%Cf *H5$Dh2Se)@3eXth$ ٻ%(OJJWFRm-V)ye2 bGX,]2Tˊ.8A=F|-Goک/dy\>Q£< dܛVھg-W@a-Ww[ĺB4U-)[/iGw/y $*X 9 5~srǘP7#^m8EQ 0Vd67 uZ *{8e&dLA5YIi܉,NLW2)L'a"?ޜ@ s97c#PO+!=3Q3>Ԕ TghdQ8ɦ (0ph(+pĊBSH(s@LIOZ;CeC|P;UtXyw$lP.SxRLQ+vڵ[[RJѸ )=f8?DȄJBs8 "GCQdbܠ'1T,. B;d(8[eB3&%P$HOԤ*3f"TD# @J0zP ;@tzO WְXmՐQU`8SVdDlܹM.yj?Ҥ}UۀϒМrBs'\Qw\T c/Fi2-~^clqP`*l!@eĭ$ 訕Bڅjmjb n6x u.)RA&0[;iM9MSBRJZ+ɞLְ3G뚉4*B[}Kr06CJ)V5jR <[{w.{ VAFd `N64NjRR rN*})&JxaUiEI%ki׀#y!)N4[g[!#9)IioT)]޴(&ʿ$LARqO>"Ғ: )3)U+Y ]Sl Kk#F~Mr l^cMS^oImrH#fضP\*(j쭒=N+jS#jR2G kk{wR  )`􊭦k =w/kJP!"pG_xq9^m췭ŸU,hm*'fYuZ8v  u޶@q*KNѻjI*AA{ι] O:MVˏyo&Ϳ79P*[ear4'b:6Cm^`}-੭% Վv:n=#Z.um]>R%('YVZ miDt3i:en\\Z4KLyN(#^xdtf~m_Eh ~bbz#vQJ̝dWµݴfMJVUZD:K/spzz&j+gPne.VK-O ].]l]0oRS9\qn&H),;q3Pv%SO֡t܋!8ec55?gq.:l PP@#\ņ5֘vIډ9&|m|ވL?`ϜS> @ô-@rD65'DjH:ѡ^Z_gQԯn՚R S*f5 [l┞j(5h޼*QؐP9T>ƳoNv݋B֬b>I$5 %n:T0júu)hVWo)ҰJ Yi%:2bkݏF襨-*&y bI=ꊛR] zE:ƭ-]VɊg&R\h$R`Wu_ eW>QmCDqj:C/^kBNj^,X,zS$޴o5Ĵw-JS41dV9;VJVحhnpv^y*H F1=jjuq@\gY7O/#ӸWmlo5u\X:Ӹ+P* 1+j"if)H); @z#PԔ+ *JW"AJ))2LMNҖ50848()MݒAbh"&[N%mPX%J) H$T:A씜&dM\Yl&+ᄩ0v )Y '#1@I$qMBqM'$( I$@ZGMhHoP i)*7WkZM-\[ bA=q߭yjWkWOЧ9 UXP;V⫢`){T(@uډ5.8FVN֚h穨PR ,K r BN* zs;`{R޷p)<ЯRn9-8w8Y)LsZ72ۥFf,%}$L5yA,RI1\|FԞF+fĭJ+-CdK(YJАpO=5"T$'QAm ɚN`ҟ+Ӻjn0;R0;MҤ{VmLLV=ےg1ֹɲ-(ą#_՛pJԚr]nܒBH+ա#Jٹڡ> nz|SuE.eHXl0tkU`l䧽UC **Kg-k(^b6$c"NxGbD oڟtU]}m9HQ#9׋A +x IqP^|6VVmR/֙%a--4Ӌ;FUiJl!_3hxΒ(df;RD9hQH XVd ƴNRTj8+ QCRҶ"p;P\0~k:ȸ +"iDd%K HF7D.[K)\+Wwi$V(Jw% 9kutX&H1R0i"޴!{NRd{.R&&:V;Ŕ䤨>d1yof)J)D]WetZy%,n[7I ޸@v SҝRR)j7[ݨȩ_5FBq9@SxkR7VBPcJUVFV A,i36k.+rcd\/:gGc}IZ[>v# nTڻFHAdɐ`(B.T ܤzh \ݩ֔ zun.ݵK:?js˦n m'lܟjFR׭2=G8SlڠTSr?ʮEtQgTMyH8=m:v)-G%Bfvh{n c MvѮʹݕHi@;G <#DWYĥ mK  Չ(ĝ/ned)h )zKE}Ck$%BF'BLW8M4i4" Y0⍺[kp: [&DOճfstԟhy[MLBZvݹsn5 Y r UuA$wPkʧ+2LaԺˋAPIT dUR>zr ͱr|KgnzŘJlKjJZhP⻹:tR-RVz}ܲ)HR_ '!a(zd/Kv* ēZl '6>6,yyA7?ҵ-v-A[`TJҡԒSJqgJw4RX޳,!W,o銷)qP89_]ִ-"!ajɴQzt>Uˀemb0GsJݖ:pm1grfHtA]q'ғֵ EK;ni{'VM6$[=^8i.%Kkz0 f~+ҧ'trN%2b\|Mm6_CfV[RLmAnnRB$a2^^ 3}`A %!GbIqq(JvҮ!MyWU/ROHpq$TIgB+oGJEvdV!iL'zRM]k))A 2"evkE)n$I?.{'R#VMr7(H%?ur#ȭ O2ؽ^ZF5L}[^4"jx!  W) M?Ҩ@ A&HBzu8)f8A #Ii cV²ٖ BG{-0z#B0*'j^/TGQD)!As &@))BmBR&$Tae.p 5*uH T&@@Z* znH8D'yc(Qi XZNz-$&PzW,BƣZ)=ӷ-ԥ223TIC)PIZ&ö7nJv_\uvjm=R%39Qqgouj٦[} .OK)`uک7fŠ%\*;mJDu?ֶU“4x5M昺C^[֧ZPvW36RU%j|$#ڷ1^ )ƕЁtze g\NJ(fyV@)BN 8*GIiݍ֡mnMn(()IUGesb$:?3dT)ۀA ȪK`i-TkdvKx8[V UT%K $Ncsk ,Ic4lR}]Ք\tTj .V3 m(RG(9EM)jE-5 ev9>4}A vɷ[Gڸ+by:p+|[ٰ’hM 'ԬjyI%l̴m Y[ز6"ABdۿvՇ-PU*A@-AtMA>b{{VvJA10ݭ2ܩo9y5F;#z1PS_wuvA(F($d`jZ95L9]41Iҍc4I3̎{UݸB[D_QO =QQI``#DФ $df<Oȡp ɒin;@ ` Q')v iؙ#4iIIG M# hLh *gv!JY#lwM;K[fnHlQR>-?wrBԤ9U5Qčg-`DOҹ[;fU.-(ϠI5[kckB(\T'R%PzGyuwudYmx}+tBpkwṱڭu۫ ltAhQ ܧr#qQo:Pˤ`DF8%dI'}()q6L\CrTPoz.PۚKj=-Jbdu59DRveIʞU@jw(PZФg'\ܶVe'bB2: 1rw'h?ڢeI} ?eqR-keD;Sm"WӛQoyh%%ĠszUzvHJ"*kRCiޢ?QJ)m*#pP!#i"x5%m.L#9HK('ڢTyN;ukvq5qmpKo).!)XmPe _eHC \佑)mHR':퀷S吢0wwCJqa> ]% Vb:e+5)WIiВ (严L׭C1R(m޽'`ʈemKa^"АC*)[ js b DJSrp~h$ʣRۙ);~ [+q'%F"m#tR`OEYe* {UBQ3VXpJC% Ͽjַr$Ys\ 'r7pV2 Fmj /jܕ<{U{륺UEBj 5XPTpE%RB#ITMVph5pYw|L֌ C HGeГ$ҝjiЅ%b IѹAIS{)^5`Ve-6'i&lE A#ֺ6Ao|,ZwpⳜ KhTTIвiNJFRX'rRBWc Ri)RdxyK[tM]g-B/2ͱQ TTR7Ek&?X"7 ( WQNINZ4VPJW0iln?`m8@ S \u%Tmim.Tb VS-3tRSER04#&4ƫ!+QJi)$`8LJI(Ęwl[u;O[HUiPܸ CqPA^1b$C!baj2I_"2ŜܗڅnQ+ 厂3XlyB;y-$umիy={.bXm {)sҳJ/LwPRnDp:Ju+Fmǒ/| MZuJmBB \՞-!i*v*҅ʶ9ڪcn^)%Jk!$tnn=@te%E8Vzbz|B7 z.+ik2ĵ-<ڷ>jR A r~sG]r*E$R;jäc{-H+p gv> e Z%2K>˖ɵ%Y wU]]ʼ21yJKTElаj-\,@ ϸlZ% A'8:[9nJr\)U>HR:EmKa:Mm0S f\fzXnU]%+h[Tbk6PO*^DUu9lU%@6xrx)ToV}a_y<% Ap@#NW) %S0BD5|ܪRWC`ODZiW*qL&{Q?2nj5і#[6o-nGyKgVZ$)Z5M[]%^t(صؐTT Ȋ &coP6=23CjGQgQAQ+X;؊Q'M@h‰B!I<ϽHWj eX3TI1&h8Td piaq阚OX T)r1Cw TڈL {P1%KT N*ȩPiDglM@q@S A)M7b`ӐH"r(&}Q@i[]%HR].i.2{+IHjRA#fXńGJmI# [f#ހ14P%) 6Tjn2zAa#%LA7z3T[&A"hZdxBfL'r{fJ$*֦a݊ X (F 0}j`{TO D 0)(tH(P `gHLAFГON.ā+PH5M$ǽ$,4"ǘZ VCRŠnyΊn\V] +mn^rSH2)m(|GRrL#ë2ٖHu嵧aݸ\lۄ!>Es}6J}@t׷-\]bْR玃&U!h۸ wШ(@@㊋uv5S-L1OnkIn! ?hZ0V`1^7[7h% {E@78Z+HR׭U#b3zI"zKھUJNc޸kt2"~kM.IJ~åsJ7omT)֊Cd U k=8y5j촿i! m0zzxuĶNrK"`Zch/PYxLmHJ Ek]6A=1fAT֕&HLR6ԅjJLkFVcM")d&@i#U&4Tۨ@A S2>([kes1ⲥK3Q$fكE@$1LO%FioHdQ_'h rHJ,6GOz}: #"%Jo2RR 뮥@r3X! e YJ5vO *Qk,*Scw Mͫ"HG{9Ih;WAqd´tU)⼳!g,m IOj׵ki s:[U#S[G 0{]mAmF %A◼Ayů}JuBv ج/u!gޭkq޹p|IdeSϵW PLڬ0W֫T Ik*j瘄۔1Vu,MOhVODgm6{䬤p:^_&|c2._۳n&H=FVjR6NJ|ە*Ie> N s\fz&Tͺǵfl$X>rcl<*@u鍭zLLZ p4Y9?ڙrR6Ni:P#iJr"zԟR ۡE(Ń>i1x+UoFԵGӚia>q[R2sҴ=W0SxBA?)'T%]gNJz_z^2e*Ӱ_7n1tSlu76Ļ-AT-j_jP KRiwNp gڿf2Uh8Ctt7kEőcx}UiEKqɩ.R NV>8JahR$nRV=BC)j;:EC'Yl ZvzpjonwSY@YjiŢSwf>qӳIZVw .\SO'x 2=>jˮHwwn35*W%_QFgvlC)R\m<}Y y iPDOެ_YNZٴQaJI(ȞiIyy,:7)&}#ڛ}%V+D[jh!XՔhm Y"!Hul. !@@麲Eݚ ;s {㘭E-n:VzՐOj)% qpsU8P$ %<ɢ$A#B(`MnDgY247>a'SmҸ@Dtb*dS NԈ+ie)lRRc1ES £S@RRGji$sҗ#84 N@ǽ'9){ A@$RH4 AڥARX@2Ä%1T`Hu$tӘi^l֤$V+?> %ht+͛NjTr^Ӝf[=júi$>Rp՜u:gݵM_j/;qrOLe>*ևZhݼJ;fr~yra{}Z[7TGURڬ/ LPj e欭 *Jps^iVZsMBGd+ϖ'-ȭtNn/.m|)@RxUZBi#jJ g2):6~cr+cBnūдy.}ף1rʖʥgS}EԷnk(^S*TOjm+p!ZaI @k6{o5G>k^<߹Ei)jBa)kpŎ/bZ\]JL{ vSM(҂#ں-*IYB(yj)\HY>C t3ہHtJLt5SC :ti@m8b ܎Vۍ>5ҕU);#[bٯPm6 QFqT5okRvL [$|W,?هfUC}Ksۛk/&éKJiG ZII3?)/C˧$LUޏ5ة ץtP(mB609'.Zm۶ Љu@ '9\˭\۸IH͍.ʇ?Q)IiN%+R]Zލ-fTѯ__ !͡A@i IYt@!R[NLAEv爮ʯnӛy7! #F(Jܣ6f^S'yˆVb"j7$_;RZe eN0HV Lt=!I >j_(tBLֲTsQ%2Ni[m4}aC?nyISj>sas*H\tDg\PC27uZj}%e~:2}tie86&vҵuT2Sb]sbnARMmXݔ6?024쩚~թ0Sl5"MvNZs 4[^f)Mq [̈́\+1ȮzmlOO@y|̴P]i  UعuxGb9l֝xJgjV$! 쑜qxqGDZZ|YCQڽ1_zɻnWUlmO@ 9"ݳ|_ ORH=lɚQFӰV9Ȥ]q\gښW ܺ*I)R#L'bHqi*)?zv3%ۗ6A ދg-ހ~m0k;WNn zIP:Vf]&(KnlV2T}Y-nI ,Yʊ $)SuˋڼDfƟ[’ܥDҺ'[z1 wChڸP"a`.S`*Wep: oY!/0RDj~{hzg8?:n_JXmH$?;o%{]樘NkJ AFTWQXך^Dre6Z{Ce?`DѸ$F)FON,fūE䤕)! G'kUfЄd>y[46FxC[l̠6֮xuk@< Fc8Rݒ\fn)u Cڏti ز!RǜڼGwfq%ڴ޲-M6vkR70 ZCr})@ڒHKz*!;z^R贴=jA-G&v-k> j׆jm-N4%ADqVc:S, ʏH[M+EZѐ}N jab֭_T5ܩk-6"Ajf.t$ϰ6e7̸t9Ԝmip[IwAmJ>XʝTgrݳLrʎf.$yt5&UvPN$;[d<eJ'{yWfMim)6dA'V׃,y)JRI_It)iQR;mVS-nIjdo[%!˔M¥{nH< Up&RGj_:\-}ǽ@ sԿk]"% YpGVЗE-#i'"h붆(v>ubn3JAY9JMѸ׵wuޣUݣ J6GHjI u,6;PpTOjf-7NorVH|+gHVEM>]@l+rIccY C!$I+gTmv 8+]MԄ?25EKgߨ]ީADU︟"-ʁSNx鎼[|W5pSH[WO8158n0VĹ'HJ+P6?:Mt rHQ:BPM:0Q=C R-*RL(nښhڛ#MFgJoRg5)iCj /Z2:T2Oo m* +$*P A2AjС.a%!`rr}UTJ탡% k5I{_*J}+Q35ID*QZO{T%v6T ):]-aJq;g5KH[Jf0d)G8ٺ-ڴ,&a = ؞OaEng{X*> O5crqd^ĕګzOrvoz̸nDsN,)CJi)))|gںC83+2B\Bү0j4ۏ0%HV9^}=n'=S!N4R(ctLڤ`Q9jF z}Ejk 8Gz!b @kpUmȎj=hue{Wu/[f*346*BTBrqҢZgl) N=Rg@PFb&&`v9VD慱f^AQ(J(S{*HU4xY/VV6moGk" ӿ<5S1{+c4B30)T Z;P15"}*NfdH>B@~hOQ=>## F&XTsMY[Y6=(F=z'bA<h3Hiȍ cs]0A4 HA&HN6R,RJ\e(6e,oWGn+ AL.5=B;iV.4,6/)kڴfv[1 $2ylC{Zoz _ۗVz+^OC WIH]mosNURH ->&KPZӧV:+YZU08c> } 3kwdm *@1؈/|,JPiw” YaY~& FZB%l9WI߽s+m6B;!RDp30WUE4wS_w-o[Z-(j~^Mh6w(Aa M%M0jk`Í)!*B!"lVl[!T("s?')h W}cv{7m$3QxXJVJ[zPN'*POX~կ65jxQ"?/B*llPJTx̙??ȓ+6M#u{۶lJPŠ$~+[ ۸B*Ro۫uuvK:kRT†_Yᣪ' E$ZBM" * JR*q[TG{urҷ63'7o{_$N?Jy-E`W\KaaE0 Ӹ8IA%2}J;BJy5a=jUgH[m~Q^(H'DE'3#ڢ*ϵpO\{6HWBO`M_4 R+ G#򫑻fh|$^Z^jԓRGRoyZbͻ[T0RFd3rїwW(u.~fR Xd"l嶒X!D>'ڹknmuWI0^h—pZQY$p+OfkDZ\ P p$mcZzZm^uIH' vj7j'#(A$5+I[DfF5QVbF piN(1 `y4 I0 FzSDS'8Bڔ\;'Ԁjqy qT"q6W d$KJNw;VI{mRJJǨ~Xܲڭe$rAjl˯'8] !EvQtn@Pf%!}ڮivQm(8 ĥ1U>E5mRul`qHO$Z/P˗*I)#JڸSSI.,'jĺs\p TDŔAcH"9+/ Q%)T!llTզ_@qJB-`$Mkh*qmiFx&J(ʤSWiv78Á dBJPP$(b'tqHl4ͤyf=dlصJ͚[q-*?ҩݺn/FlP;}>b)/hNT->c,d%d6I$3]'rdFqy5blrf%R jM=,Yި.3kM}GTwzV[HE\☭ǜOz2"l$6*JO"}SEt1N-(>'8'L~(BVQZGZ.i UF'eP3Y#@(7 Ui6_e0#?"$nȚhYy IBwH岽 #T=_3`!8QGlAq²NT"$cj۩[u_ +'q1urSm!% :oUljEN * !I3_>x*g?dÎ B\PR sWuo)$,(sN6W6FB1.ԗ\H\kTg]4BAP?t]fN##VR[S?mn^8WAujhj)/S,-;dZZz#X:xZ[8A@]iNY'sA;9Ґ)J޼_(KDRAcJf6)(QEln?O4E6Vi@T!! ~zUkk{vdI=9NNnIJlyLU&upںP)vNpGU]},}JA+t,VNJJ TdYfhS+ R@'5dݦ.%FJ5q-_j폜Se37A<ʁJIQnn֓V2:"TI$(LvI-Мd{6E}rINSKjS NE Kȩ!!I+ADt5Fb)0*W..*Lyϥa WSR-\^UqbBa5b-m>޼S/Lj|$S vwckpօjBmd9)8[+t R1_",-kuqzf󺖼u%Q fzSi^b?2YfwMQĞ..4ujvmo6PANg֎yN8)bU߰uǣ+8)} 6V{S;Gxa B[K"cֹ[DlQk q;-&ĭeA+ݫ:5mjͲPe'd&3`=Xta>.& ǥr[Cj>ʔȻQ-* -\+[m gt;9w֩?字 RiͥhÍߔœ iJ`TVm#j}~Ї<@8tV]])j$nG@-'sd@1Mf1`ZH RBљ5yyC*JIDaa(JUEdt[ٕrkR.S2c+7oܭ-(S8t2tV]'{ևmu+_4bn^,JIAʿڬ~ 5)@1=Myj$E{t:qV%I"pٳ7oa* LsUnEO$ b7[\C)qEj8sʑe 6 u_m'ɪeˆ\Bf@.!`LDM3H6m)?rLJ$zDqbY=eEI OG㑟tr:amBZlB@N޽&n݂;hjRj0jϿiO[ye$-9$:j1۸+ht@溛㧶7Myw#uDظunyW BLE\߱Rt-dzdoͧ8۲͵vJB@d#Vr>;VwzyZ=Oj-uvV'm*ͥҥJ=*' ,iܰo5wj A ;gG5k-)E[cB$0J=~m(SK'Ik䛖M*3{!Uؓ*SBI>5'(\5rVfa9%%jl)m8"x⢶uPTԊj,mJGH[V*,Y\Re>̚$Yz;]䶤(9jHR[!4* )$Dtai(iAϚ}+Q *њPbbfj53D˅K>|͵ Bu K1N%IpNxR'nT䫙@en-+ dAДGwvWW: ~Q< L\)XLq&<ӋBRzdUfS4|hZS.`8}5^+zEJӵrzH Pm)RszH`".wJqH7 )  Y+㎠y>Ul1Q;\ iC TU-H[B-̕mH +Bң8Sfr Q(3~j,]ۊJPJzjSe;œBL`,YNmO\Yܔ>ȁ&޹>JsB򅖷nҸ}5OP1>3! wqI Zj{A蕚o\]3R"e #Lyd!_'|3n_^re&J<(*kw04A2}/U{{]Qma"H;WkY |BIi;'[]qH^(e0W!(|ٷ"xŽq+Q.mMu'm@]lrAw_[OiV;p=9srifc⧋b-FfzyN^մ`RH3X6ZRʂ@݋\!^Fbjm-K*;p9rv.^,KhfU9zYE 7 RFOZSiu.-E-nNdޝ-YڶKvZd*>kGT0#5oWS|TسnPeFLdL[WÍ IRR{P}{rVJc{WDF6Hkvg*ۀnb&դzIJg$VRn&OY$і-@L:'j]L43c">%#hl(F)n5TOe<2ڈ;B#$9wTvP*)E| À,m\%k0I8fk`X+J@Vjބjq(6ai˵"KiI7mR~׍@+B !IH@jW ]Q9Q̇q6"d#`qUM4_]&uuP ?,[!JO\*jٚy!T@n R52HJS9>ƉJ¥*"+" UҢwnZRWQ {g y4IAS7%+¾b[hϔTp~e zϿXB#kf sDd-JqB=K.^ͫ92w^C5Z^4Xe(O{V|81)J@%Q #ÿZTv-x%!z\[Ip6BT`"kr9J[3yL FVjm]WZ ʤ1^lݹ[mդ yn;ChR d2ubOԥ>/tF}Lt>J*(P șӵ-CғtlQ P#\u7gZ,Jql̘RS$LXKC[TT ?NFn?-_++}(nN„ڜS开ոLgqJjq+E!MD"OYy h-}pjjR``$ IY)dUGZG~BJV.&sBJQ" bmOC<B ؊yNUC\OqS9sRCV'h1 J#>O${U#D0w qS r%&h@K $bf[;)ӵ$nU8SOjnd9VԩQdP$ І=`_mHJiup[7\!lmBd JWi=~ oy!P%i^\sw?hF$U1]v@VQ% ;GsY: ڃ*҄*b|lh4&޴E)WAg^JPikQF~iӦ:_}Mr%zݵuP0޾sgnh'p]n z$|Vt]ZU;*lJU{ֱx@%W.]4T#j0>jkRrk4%;k {O%VzlM1k|_^:m)(S Oup͸JvSZZmܰ!J6ዴ;izWT IzEA}/J mijd8L2|{TZMXRM*DP%Jۇ-[С! `2d,Z6~IW$j R(Sf!J@x9L-\\rիͲYv$j:kͲETna29yԅ)]՞ϬCOvU}W!yx_l]z[D9=s^Tcu,)$ 0\TV+BRO|StۺKjqġ'ӴIl7w[IY0,1K|MtGmF囆ТJn+ӒoH;mR>2 *+t->ͭj֟or7.VAW |?'f%.]5{7OS= XMpx6cq"f;WM!%eB+VyaaG8cqIP^yK$\{~`jݲVJҰfo[Vv6ihJKA%"QهJ.SQkoN탐+GKn- r?\Q[~o/jJ) MJC @R5fEԷ:pnZjƒNT+W n[ݝB|TW%WM%[sUǐ<%kpA#1ڱUpz{J3kftҗ^2?4Ю֠U !YHzaFi&Ht$85$Õ4kRpҷe*n-Hz++t\p4wJcޮ$<*IIlۣTqVR6;yv[5 %OZ?p;R uv{v]F䬑GR3MM?T|}mZ7>L}FPR%;Di@Bqµ.HۏڜIu-^^OEmP AIToi TPPuvn%.)HiFF^]ǚ ШGEuq@T8):{ӁTa…H;LȷNI0Bf9:w*SaMgޜ/[ JMh*i ?JԟtY$2)>mC $)P'nzDؼOB ^Ӆ'ړj~Ł  XeTMe0BË۴Kcb¦l)([ >37Ą 6§Zybu^pKD*'Vna ZW*yNne%DG ?D:Wq9QN$Kc\Yyd1~jFlJ*K/X)6n@zAUY9#zң@*V. غiO'Ґ27z ;S2pjHKQ%Bd|XⶥN (.-Ose)eIRLjKޤjDp( @\ Ry6+iexK9GIFTjfmT6)G>4rej[6ӅLb#*+8jPm6$(i¤`=Ո!\KqQU$q6K(fYmDI{\0 63pmj+PRdD{PSiZiFNLmRW b>j9x#rjVXJ.q%IOJl%-(\"GI欧R@[iTx>Y&j+T<1i)D.[D`-(O*ShLЅ Lq4ot n[T(ӴTW RJ\ '?51J $SzHJ<)DOJQ5 Ky;JxREf\cOq[ =%15CPU +wޢZTU2BFsLh\=N' WѹVIt% @hB7Ԃzu{U'T;qXIIAD%s{W,EzqT.MV"zSu$AOWYp_:Oyk叵@Wpk*XN̬Mk8r֎{bjn~ix+VX MHHrG%@gmMEnzB̈Oҝ$^~|gi]mttw@)qDSl|*揪#U(Wh]Y oHg4+X.?qֹQkĚNwq nbJw"G5AUH]cVG$D ORc-iI+lNիK-;8|t93[:u/\O8ڜG_k w Rg֮hנXm ~YyWeN;.#PnC7i3U=ezؐ 'a+wn((g#U 3d[t+t<;$^h-[q9[ Y\ ]_BFP.d%)ճ }t[w~W) I2Tsӽq$qVSt;ڱ -z:Bw imwljMJ.xPoaRkrLhY=[S0ͭ},1%{BGsFx 7\RrnmPp?C[y}%ʎ[T(Si('o$GNMۗҀPµft@JCKި N1VUꋚÍ GꤥK:==:Z{!v7 ӽ%j3{wW S-$IKc U6iǡkKi#$*]65hQ{TTtJU'"8]QP9M!($O 0#Y(Z[AWI]RB]y>Z=&˷Rg< EƮD))9uF棪1j˄K## ,~dΥ7跶^ ZR u1` Fz{WLZb~\c+5wGտT)[~_X[ -쌈Ly/9.,-C5UJHHXH&{5>?ѩgPk|zPR>-GR7^%T*|&LnNJb0ixYz[VB`ĞyvHʝDx/,):$~cZ K"ʁ⼙3Te_gPt6wBAF:Zѵ;M%nT ^^m7Gfݭ[--B|^v~_-mg_Y0>B2 s6 Lwzl.nR{ n#¼6LݸopLS'~/qpcUaz<]Z6+M6VZ>+R\H]ݮget#k'J[Na٥N$&XT\q)7iH>&/ܵxa+Om'ֈ%d`'3xGTo=2T yt!!D@>>#XQ_M Gi5UO 8Q)R]yHvhRRx+8dm ZHp[G0i~䠯mM/!#V(BZ$)@m܅yNHcR+UjTۚNK[cGke )Wn}*Ug[*P;J 5%]=C(@WHĒdPQ5mK܀SMBi ' )*)" x&KOD޻)i <ڽ0)j:7!)HWx+YgGԾh u=gۚ !mY8EyFNW豾Eդ-JJՂzQlui喟By&; \ [@np5vuk\ڥ +l%E\DhN*iÈy*R[ڥ~= tHBG6 琓<,j VL̑MClٳuH NùQߤ gJ_IFݮ$;{ӯ{629pU8sVT0J@Gkmp&E&\eޅ; D-\ L+؊K&jͺd:L(ҟu!ZS(fLFiٓڢT{VoV Fհޖ RCf^'+s^JRԵ)3A5Vȸdʔ<֍z !)qF#&~+7KJgۿ΃$@t~ٗ.(]]޷u&ie@ukí6w>y_jdoQ@Rkkn@9q^\^FYmE ԭLxT@ȓW3Kߘyoj'[׷i֓n]:2OsFInlܜs^1G!7OJ/4w95 ҞNްT˷ a T wyAy^6F7%ĆpWSNd7cgֆ\qHO 5VC^ٴYPC͹6HEOw:{Ϯ奩K@ARq qo0xa t?%^TZݭ 6ⱷ=s^III]-䴢m*G@+0\eFH;*-8p;Ď) .lJN׫T6-ԦuH#hLֶtWRnTDS%JgiW,mqa\ w]}Mh!L''1/f\i{jK 8$jβ/CP JI;}3eH POcLBu{?.7(F"9_=&&bashCS*ni-[*$@9Nkm_2-T\K\#ock0c+ۊb΋`.[^8FNݪ9?5 Y\ܴҕ=zD~ @J%! kB6.Vn $ *$de t@)Vws^Zv\BVTd¢eףmV4` joOvv?*6yW\eÞش&$SߏJhŽ̋E.\!FB S[^ז-½3֩Q*k2fc{PR[[ (Bs=[D>!(.En̽Mۛ4LZcnR0*hI6˓Q i$gzI+L+U9r[w)A)Հ$(Lm5RU"<|vqė$@0E=/[m%=@6nv`*=PEDmcޥV8)%!*yRFv eź;(IC?jܺ.*ѽB E dҕXi  O9i\8qO"@JPLgު\?[g17b,RX&ߎ&]˗% Ut-JSUv,>H`83&*$=rөX%a}S]R;jHy 3+ uIN& ))Vb:UkF-ڵÇ )$欽eh<⒗WL^JqnJ6jYZAL=ڥSZ^MФSp&S dҗ[^k7w;E-!%E2;UCuJK~fdOIKS*-\,?``+4J,e`.[,a_F$T&!Ђ {T`8ޡCwwYu)J @iJK p/zHq).:ÄO~,KI@'lUgo0JIe\-E[eͨUVsHP$/"cڦf-%tzgV{gP =G[gmԞ)Hӱ,{ՆqmI?ʓsl$jIZ]RؤnkP ;gp<~]<S%sqǛQv쀯:ԉ%ړ։LȖ$w4zjw-.99P;7Qr2Ŧ'˃tQuF\3$1JҊе1 $jkHԑʏ?PIQ9]#-%A ;zdPjˊk!U ec B%Q*McvɭnCȄ7 A5!J"ap{[ ePv}*֠+RҤ0rPZVnIB3lN"ĝ&i0_x=e[@*a(Kq`O9⦼'uhTVڶOWƩM"'6S~ *WDw?[vz^n{F\W|"'ú]7i;G ]QpO8O"?6Ѧ\Yy۩j=5 ?zB+iK|u'l 9׬% %JBN'WgJѡﶴ] {u-9ai"FٟךkgCќnݥ%s\}6/) ‰$to㍩)6NJA[;`ï%.i%5E3ʝ>w( 8WUJ]+.?-Yp6k k=G*>동69.%`Ug=k״ұ`} VNKe$/8$d2VSZP*Fԕ6H+NFy$e$MnѫL(91%vX-1eׄ! eD Ǵlt6`Z]8C\Tj4aVF)#=SLSN$Vs:&')+A;>G' H1Z(РDւTPcQǤ(pbyGL q1Nw; J(K!3J@@9 Fڼ Z6M\+s\vXnŽ,F5Dn;F+`L7H<ں|oVo\\qv8<fT b YBT1.TqS"$D$l1~LsR6Q>bҫ+#08NG.RN|(zwҹ=S (سOùvrNP~Z:o_}1:2d[~5*sjV:m`AP5㟁8zvX"Q ~-ZԮJMTr+oQmѵBݒ[]ٮZG X/3ƇxVt6M Zҗd R S^2>u.tT%D=B3_K($GktMR*M<^Eu)JWNҿC1U~ b!$ZKW~+"չiFhm^]-<>MQuA BRjS_50Vm(G&95ݽj'r%̒Rk,Q_L]ճ6 ½WOaX4]>rT'VԵ&WhX,$>պnhB~nBB #%+)+Y2!Bw0Od`M7K{MnA/#zS~rwFA mnGYMJJ0NJ.- R[?4||AZqѧlյ$tzaTڼ #bPj.MaNr 9?zy70DD FjBi, {]lV6)3*[hΊDy:*~:U* Q<+j%(Y,YBwvbuMR凮wЂV{U[G`0 W'p[Ut8皠M0(ʈ֪T+B!qȄ~*J+v*}K8X҆j,Xj ^sq8CX Y[^EEvˈi0AϵrypJ*@5GRC X}(I(޹} D*Bg$q^?@io-4NS@Oz./nm۷; 'j{طuv }4+Q2zs9ɷ{XՃZSJD \jNSeK Τ'VHV5wmB,%q۾zаnpbBN [tޔ\G.#/XRQ=:EQcͣ%JH*Rڮyϭ mGqO1ڢԮJ Tt[n٫K}` Ƚm˅^1}{q@"v&ɺa*rnsjR٘ {4PB͸رpGh5I89Mڬ$JGZWV͟ǹJwʞ|z\tU]} t)qPԛYmI$}+96>ƚͰ D*&.[W;Y =豧GAi_\(!CֵK]oIJ9uݸI#t]=X86mA[ARkH4n;nH7Pzq.RIM +7PJSrl>bY2Q1W{immlBV#&\B!%+ȫu IZsz}DqYn7[e"+*![((l!eKc~ԫpGS]C[LА TOD>+5IeiBԏR I o.wFݧCo(Ryf--Vڒu ˛*?M-#Jӭ߽y!¢TҕA{N6D O@kǛ'F\]4ūJP 'ԙOHi WNE귳n 3'Cĺc,] T)'"b2ŷ1尯╅D~c'j}YVUܭڣZIqAKѐڝ6lS }AAv UҬ +e[ZV|E?Izv.&dVtեݛ6,") cV{p;6Z.pMATQ:RXN k%$D4{bePRNJ@]BN5[`%-ܯJ7 :Ҭe턤5i$3[fE%\PGv zj/̸$UDٯLB - kc^@EZa+0x]4tO]׾PW̘P=vK); oRuMe QVΆ!(q#֨=Z#_G;l% *Jq]BˆO4ܸlY􎃚-%/=z_-윩:m 9<{T6[D3k5PV 6-i8*WYFչyEҕ&cNƃ)HWWҰӻA^m!7Jv%_jX)[B׹JVҙ.B[)G5ݪh e>U' vZٔJr*hRCm-JDC#%}IKD6Үܺ]GwkG9Y!% 2$R;bHKm,7|sSPe9ZGIøm>[b=uv)V7 5^|j)BT'n*ʮ/TTAER+VaAH&?J.#˒{VnьR?A 'Ot_ܲqAk1[['j?,(Z| W=YL?1[JL`{mmtʖĝ$jW) CI6[w:ԔL}+^(|{Pdd$$ 'շl[R͍ğ6␦ʖ'q[~MSspw*r~()Up -BpGZ P +z6m($V/JFe[yd7eݤrЎke8%RB椺K'i…9ʔ{!Mk8Q A \[N!l)"7$A#߿pf{zJvmj) m!JBQ15qA*P@#3EQ(2ʂI3%4IN|?tJր"R)Ky*tT !;RzSQqkp%Dh~hLSWPLzr; mG&w) GI׹(*#h(ZRJ2j(9p=PUО)UdH;]RS呎b zt&Ra(i %D)[sҊjVS$v>ԌdccrT?By'?AobmTe$ l s]*]}uIHmI]ue{q=:M\iXDh$˂Y$9#n(ԯg6Iridx9Nj6TA!Y5 qa'`}5I۴)$~EJbROMI #TI :Px2×jQJ՞ME7F86s.ǗM@bzzV;hHI<h4_>PywQm}/ӨL^\_@ ڃ-HA%Ȍw/;GGaj۞2Bq֛@N&RI?+|:/9oꊀ#ڠSkn ېcQGQiҭڦoHOcrH5,uWmvVgcl4#koІ.VqD+&Kue;hSkd (%Gs]=m[? ф"c '^^GųfAפp@@.^au{U;\R]yhܘҥ[ uS9@ gm5VTI?T|CTfݛn-}m<ՕݖR.rII#:YqIRhʇuDg.nV ݖolj#|Inm`;EuN9h  {TeZm}_G׭j_[e=-2RR7 dwT.ҽj5uoa)G${II62(KKIZPo#)JZumjÛ2sC3[v비D=)=\JOoTV&k}Y5}afYfS A!1VaȹJT+I;O?5ިCdDAZϖI*WE,nV8 PJk,dy=wC˷B[m.wJhOYF2P|Duԗ7Ke+|Wl}?Z j^8^_wlh5꩸kbۨD9ܕ|OH_/,P=ꋺekkٕ=wF.T]{PZH H܊;2W(s]峍h ok'@yy]l|?zEū'>URK#{gQ4SdDb) OLNb!^ Ɛޖ͋ Cn PĘU ]Z\6ڐJO 1Й2}L4yhY'i&sԼ7[ ejiz̥\9SJV- [vKgjPyߙ>"=JA4yzִۤ\\u31FJJѲRQ^>FԘj1N(EZD:mTh7v7n8Ak"V @*גH;YF"΃4KjJA) wAe NS 4GLVVF_OžUzXpO z_ƀi xI4Dq@7We,;)JW#'i\cRq-yikڬCզ9#}C ߆uKKG^m%Ap$m0LsUƇ6e)WmX9"ђ`U.=n=$V] XDYJTVBEi*M$i=7cjZqh(X ,(X)ۇGr;`bG5 IQa*C|Ai Q 7qphҞВx@&GXSP2&jvgqRj0 #ӳҞ@)@Ţ p65C0TgqZ CJRɁ#5-Ӎ&`9#)t?FBdH6 SuY*v(iI2x^soYT$j }5ug3|}4dǟR}:W>?zPj#VP ,nRRHu[ P'r?{Rm.N,NFzV}o]ImčiOYT<r+BPVQ%sRDZ\ItwʤG+fX%-'JIIX;䩻+:Bw%]99jֶJY q:֞Xj%ԨAkJ.tT#.jwnY}@?ݦݶUp)Lg[wY`lJ!`@Xq8H}BҼzABk񛿉Z-q-)^yUD/SilǞK1F/Vwl>jZ퓞BBKm k.(˓z+1klUcQx `ܡ 7`-S=f'XRmv]ibO^(~¶B} 35I狊J7 1\Máoa!DVTqv!J-I#kĠ4-]S NBT­ݷfuW- hR*n`JY??Bj٧ZШ8N𴄺ڂ) {omt#JqiAغ_0)X= ()У=kL}+wqm#֞G=X^KIpFdbgWz.|IK!]f8I 93Ut}!V˷;%@'(??Ln *P=%=NfeƂS).&\5[6AB! ʘno!-~_u|V]HY)I׫ :}ڃ6 _Qo¶ɾaⅇ'޲u$n )JJkWS6O\'n^ԣϬNmmTٺ]TDv n[yBeyAQj eA[vBA»Wv<L#kKvT>B!JH #ץ~5rͧ ܑ ָVKm0-a ,}O|,V: 5N$.h,LܫOjdĥg,1ƞ-m!IL`ԦTi " wxfp 6'JKYqq2^0*ˎ)0T*xaWnEPs^iŧ~[;IJr&6NoڐӠ1ԩl1#޾XSOIL`fi̩trH [JHl`ޮ\X][tšRF TF RRFjs.4?MjRA%OM:{xlJF$V^LR'ZLo-oV6,mKL뿧H$Pg\RG/*T[Tn,y1d346im [5 W[%ͩO M!°=e|q3z,d:ZPe#Ґd >jm\Rʐ\-$-'jp,,$H$kdqV+pT:"BRZ$])OґHN{f* .'  rj6gD oA&y, HQLڞ% B#Wͩ@/y¶pAnB\DȜޜžuZ}\~Oj} jo}[ )*E}1z<%-({=YJ.7p?cKJIWCU?ЧJT(]UJْvklY A; |Utjs]w )GTҐH+^ { FHq>cѧmvD(ڡj>bMvVH@{N2^0@Ȩo +ZT?FY&%-Jr=jFIJɵ%a$OI⓪qư P1Gi\@LԊEѹCh* SIQGnn)OuE۔<JBĭG1llW>Zd⮦b .lMߔv)^uup6& X\LN<-N(O<չ%93}MXHQFrvUF$ qTQ?4Zݪ($t~OHՓ4ۈqRI۔Nm^Kl%o`I')%[XS6ۣaFV@ڪh&t %B xz^}A ܄$fkP2 %6QJL'UUivIxX8}#z/+z@VmV̘ fx?R(@{bH3se1*R)2$X;w[Zȵm `JlLkVi7YZ bmK /P sVse]ZWv/۶L:xZrѼN]I= fҀ()J`9BO%Zp۷,zףV#Pҿ Y遥4^.B۴8)QߋuZrlnMi}M2+9tMI%WW),CHVD@|?KGc[tn}M-ԫ H*V8o,U=M 6ۖM[U-GJR l_Lw>/]Fq)JG92~1xN1sm&e1rݟ7JfK-RADSZRr尔gq4|xl#@7QM-N!;v?'Z2_@JӿT5Z`eG*-Rw8Q6Rްs1UYeoM$:tw+3ЗJ µZnwrhf[% x=>(l<)VjZREPZXVJ&q,r =7laߨ T$yQ-8,s6ˎ'i'WůfV{+P:AUn%$( P.hRHfgunPkմ-HTYh IH=TҮmw7/RtJBP$UBrRgPRR?S5W-DžVpu *GS֯>jpa |魈Zq 1Ve%^yqZ1"zbfCjeU<)2j>B/Y󉒠p;Uo ÚV:?HZWn ڱ`Y=ڽx-5 hMJ(ۉDi{(j$MxM*Zօ$5{mY,8ɺBm0%?1WN}:`B3IihǮ ~Zߠ%zB˂-\BN ֛ocMqQNyQۉ!O V"gw= \0\y0SN^iȾӞbOKyFw jY蟌[F<è-/jTbk $tK qI޵ |kuA歿|ChHHPIG*9&^&t]JԗPRT x clex7AO\u{pۆA@R>EgBV8Qc֥ W)p)$*DhI۹T.R\@GI//ecҵÝcXspX+>2ujҦws)Ev_'Ĉ9Ū둳h?rEaj *< [H9n$pfZ@PoC1*&8%-J83R%CfSր!'zq8-}A2OIU< xIճia kC~L%Pua=a;rRim䠧0L&ym%6VDnW$N|d qBD'c<}[RmcIp/iHT;-7O\0VFH)Ү;jK\V`>WμY n=(K/ZIٵK ( j)I.r uzn{Ry2@ɮY_]KD{zom-_ZmP''$茼mjTnyO2jb^%Ix鲱Uͭt 6rVssHi*ZԦ8H8Wuqtҹi2 :jqj6yҴ4+BH>ּrΝE}A6O%}THU v]RVYBOjݫz.!u`__ ۄ9vPײ1S~R@"5mahb{5 ͅ'qCg<ֳ6fvqݼL1c+BP[Ue囵O&SM/^R 7r)VKl鶐N9{nPQuA P۹@JQeWZxⳭ-'3ZQh 6qK)-.Gmjr pp *|LwYw8~sNjMv}՚Vv(EۃT8LslfmzVRN:P/L1Ҧ[ ;GȮ9'2˖]:P;ЭnHIfBR9MmNw:|]^s?N򞛄QVj/ȱbإ\F9\ʒgPkWqCv#5ꌛT_liE].[O)Tt^Kj,V/# p6sXw-K[!P f@5kK4 |wi $^,8+X.Bd s$}{RR@p Gڤ/[9K*"Nx]z[J=r'ћ|ݥ6w \Ĩ;p+-vqbfn.?*- )CcoC(JVH{q(ݝt{aus)y@7o1]Uޗq0aԒ?X aGeXd %WdwW'$Fݘ셸<'͹B-B.b}jwsaC@!0Ez!kv$jכkszbevV9x ԖhanAmN/*)7Re-s\TamUnsfQBT2,< W=y|wIzƘ67)+/K6p(sg4M%d͝9p|F6i8a*ɯշ+40UyI_և|m/9{ ancv00=! 5ᔨߵGzUkfc ÷9$Pb9]s5{5G7x;WVx,[[9Yde{+6mё54N,A1m'_(ot b٫Bj@cP;GqT:t˕Uc,ѝ'}_o);5bܢv: fG#21@52{۩qvgNYB9]}8?^ej= |)'-OCftAq^'Pom)?Z] DTw#Nܪc;G~bB~1{ťM;A_-s|1s.5H4˻G7ְ4ScA`|f*ssV?k\僜зoeZb[L<0 xʌ5~mGWL&กVaѷO FMrֆyT% JqVh𦑥|ҵ(յe[cvbhbFT`vS/u%0GOzy iU>m~ ՂkVF> ^~κ}HԼ5mm5+b.܆vTFoip #]|4oK*\#lHݒzzt5Go^֮un WYy>X( Acq^.k% ~ }9nFRխ=m#jM-FM7ʎHTsa=p4Qi+ &On=Ze$}ju)Q;0GX'"M5`Y d8;3O} p lˀU0 M;䎽{W<ټ%x"̌q#?3Ȯ_j_y`Yrhx$O0ʪ˿h$XO\H#F ,OA=ua,4kgomoD p~* y$6v$qA"f9۽Np8W˚GFэAqq"jr! f1w`W.F%)FUP܅z{+*S=ig-,,p8q~[͕׉-ᶀ'q^_KZd#JC*Q]xJfha )#W7~=q؇K#&Uo1,"aٕ"o3\G 5' t?ᥝǧ5BdbLv'6|r/=L>=w u%x g:|Q2$g.08gj2̅LGAp}'־kW|.X2N5a9S6 >bxY8˓9?k'"68 *qOoOQ.ɬeaIuP%+=Ͻr&B}&]ٽc17NVRO޽7~>x]&!j6Kh I3q\ڌ{8tl=C *$f2x*F'nNNt]oH/"-'M(''Oҿ5I*HZKI/kcZƯ )9-RX8ǘ+`SW٭MĽLXy,v۟=+:t<}ٵpGGs-ͳ%5?h@U<ڟ/k^!gS,v\v_]5)ibbԒ?ڌ/4# ֭;(y63+/Ȅp3־8A>qnⓌ#jU$TQ<3 3&5ۜq୭&:%M|D$% ٳNG|r[ %= 2V=s <` L9rG8>4v711랇k?W|/⧫ZX##" v_D譺˴geճ{pts7}QSpZgְ:ݴLXsN7-=r+sCeu<_ ;TBPjwJ {R*II-SZ4%Dm&1@*ǵ}Yvj:N=c6iYRerʥa=|yP|Wo?#V'sa2Icq(z\_jI#HA 8$ ɐz_U{["g5LS8Ʋue18v3I=l3Zlq'dQ l>nyŨ1#+XW/Gְⴱd`ӞW'Cgogn\G!{ns B^D_jCW6)lׅ#v:vޭyQK5RFpI8-j7ơxE1\}GZʥ9$䖝ϥ%duK &֗7Mw(Ҥ'# KCW7W: 2ݦgX.EU +J $%;h$߶:M?2&Ԛ Kmm 2*F9)x RM~VIn 6HPVBqM}W\iԃw^3Z/~? X]\mY#$QA`rpUG,Jxi7׺)o$h#3XCV' ϛFy-]^_sk¦趩{e(qs1)â#E+L7 [E+h//bCLJ> /c WgџYu Neo*+v# C5 pX͌FzA&0 ƛYؾ㧷N T!sͭQV*3^]6+i2>+nM*HG ~]G!#+!_O^iZ2d157dyn$%qǿ"O6T`O#RԷ9elatT vqOXV:p|S 5\–|@6Hy=ka!@`u> U֧rKw?k4wr\GKI!p$wڪ6x![oyܖfI `Nqk,JJ ]h;Z:Bۯ9k [_şX×0="䣹/J`T>&o:^ IayR20@Jc*:gc"muvÞ5񱽳y2hwl )ۭ?u+A0&ŖdsOOO$(WzKcJk̀Yj)#%!N0 ns?`+/O}:I--/%oks,+*|ܩb^yiJ0?j;sU]&zS cebIw *B7 PeE[B8uc(TK$Ebs 1y;ƿ3Kv. Ju֛ Ric(Umپ^x8 ~=j$MX5sr}2x? yB~ Nk66ڞ{FҹO&eb2uJmlSS<$ߚow➗} pskasp)QI=Myj4;Onmrᕣm/ K>k-۾`:n(X͞Xt#YYIrF4%Zlt,y2)|} _:ׇ`Km*'$q,@ߜW!XEߑ?k Mrʢ5uy>^IEwQE[+:&[N8 ޗ ƒX$ޯ߀{$x\*rWPi?keCi:է]AݽvO ɗ-*Cv_|KC.Z[ !g !Yn@<{iTpV?b%J<=CYuI4JZ[]0‡!aH;G\(&_kj 5Ko̝"D" B8 .@Ré5*:kcGxtI'we+`\N* Ey@rFw9=W ,z.X=̢'̈> )kX&apn EC⏄:3Gҵ%+38ٰ%G*H ~5(_x_-VyV7l8JTI, o0$T7|YkgK%EG*Â0@"% )HM8JKC/{/?hOu9R u hiKaL |̀*0^ x/߲z3Amed7<,bH1b]ӝ- ~6u?;ry=^MHmi{_罼:5)+wĚYZC"k0?) NIq#> Y w!dz( kxZVS˗~|U-smՔOq/ exR1UѾϪ[jf 8|RH$[Ș»6.7p 89rjN)%x~-5i¦5ExY]Y$fAYrAU)l~DԼ%ڭgId98 g}εc' „♱V \Zi}xwJ9Qt{o<uvr:[K|@a@a6A3s՜iEJF)g{>.XiZVm..$Id]A6.HݖSϳCyW:${SFHR;^U7pM.kRg]Nbzo/|./|twiY*s >GZ?%{Vsg;XC%1jRw8麵j;|U-ӧCp7VҼg5O k0C::P;aDjAb0d<^*=9a۷$o/.d ¢.<0k蹛< wSNjs> */7^:Y=(T6@88=;e7xgL{4JѮk?k +8Kl!(쯼Aiim{T$9m*2&x5R/GEA֫ŞM5%rR7eR0z0W1 {Eh-Ye~p~Q]ܤl䈩jBx{ž5=ʹʣDc`l*챺7C?;ZI_]{ӬN00p:O\׵)cUVPvRIz5# {&1@Ak܌ = ^k ЌfZy$+sӏ-<ѠZEMԓKKı?8 HQW]X> kK,]fF]sc8Hə:-_[~]J\ek ?fDP@ R9aJVqVN4.6rݒˎ2*-}*=5@ּ?MRRo_I#%~}|Y=tw\0\{kyB*XeGr>^(YnyƵVw6#RB@?_` pHXIZM.JI# DFp{T]ܑQ;,ҫn˟\=WmظI%Ι ֞4;[ɯ4Ԍ]DӶ@FP9f$&- ĺGeX]dH.x.ԳT{I'HڤS{/t&_ WydԼ1mw,0F8U z ߕN,ʼя&F/H|37OZGkghFcS3DbRʭ Rff 9>%^R l[hex˜ǚ@]->X Uwppr:QֶW1 #+8+-np2zg>-gρ%ά p}up.2@@'l:~5tܯSzO'h:VZM%.% 8Fû=JGb(_iwv; * 2[KfU"C#>u⫩;KJemde1dT1e3*t YF3Qj7i~/;x> 2xzޤ˫_">UPW$dx.o<'I{p;㟽r|˨S,27^Ѽ!o}mi$K[y-ʱّH7i{j?w;i΢얒2c&fh @& : 53G[8ڏ~ G<9ɥ˨ZںVrpy$1VO1fp68l 7Nob{I(WX% ?/t{WĶ]l @=d·k&2qj_< &1 v}+j*>ڎ 5|t|%`i)8$qdk-03k;8l+0,cdW:x7-m4yeY7Iuymdx/!j퍊|^m˟uq@VCM ~{`?JxF _ێj. ֟Z,@O%t[- jֱ],>7v%[`%5Z ܟ@oKɬ6xYEy_Fc?q3AN𗆼G/ţƺkks{/08@T ҧqw"5Z:k&mxxnd,;>}sjƿX'쥸 R|A5jjydvMoA+K&5`E 9UiAzU((U^UJ޲mVO#M6#9z)Ee~ۚ͂7O?:7cUhue-ѕJ78 14e<lғWR9H8,XEs<*d.,Э4m7jrY >? vڬYz׹NjN*[WD@I޺u!hƒp5/$k:я āukJ0KUM/IV|S?*헖o˷,̼FxnazU] rF .cC0~lkJFM/tN1]=e' d897B##5AKhơWgCdw1zyl 39^17m{cgcolU{V]\_QOEv˘nSn,ndj hl|9[cqvii3E Os7G.IĜ֠{'.FSL22}i'S'[U c=M4+wr͕go;['m ݅hLg6ν'k6tFMoN܏sW)YǢ_}YE:ꈼn ȯ)M->⬤*:&|9m?-ڃ#q=]HƐˉk@1EZP[+^CAݪBWk⾇d;??_^'1sj{]<9dP9š{n[Ieal&sW\ i]p5)]%.X.c9*zfRЬ,ޒq%Oi 8\V9\Iaybv. 7 ^Vgtq.TA\g@xdu$z[gc]mE0H9ZNrq,*8#)s[Q:25Fp*8Ab`徧h WRrc9$sO0%X`*9eqN*0rx2x0 @f7 5"x`[ ޘ@(JӵFa(FҢ1VO'HŻJܐr=ylQ'v1T9S vĸ^<ں߄N֮扻B=|-Jha@'zS{lRlyGzꮔ}qq$EՍ";/=Mϵw 4I#n䞕Z0<.cv>4ׅZ$ EZ tc eU5hϞЊKm'1*/cV$!΋H:e̮$҄,䳎ÊK|JdƢs**ĶS\^0 %ZV jSA޾g>9/36IKP0I#)VSWC6]3z4H5AOzn0%a]tz/֨|Gv-,sSG⫕Q-wḪJ孓 9ܨsԑO_ 8L("OVE@sVc0Ս<5e&2̅*#m=&O8n c ttV3.5'\Y$g9ki'Ҥ$dqNR02O\ySڲ9?'> P$&6(XZc慢 ܳ 6ЙHLnCSNt[(nI=ud%R^֢؉Y<(ziT%\^XU CdiwSv[E7u >e=+n$yda$icjղހ`zWR#- Rm%ra1g &9HVUy1Jǥ JWm}۸ɪH샑WR%wnNc;U^ͫ2ڬ5^@X8գ9}Gj~naʙޖJt >҇-Jz#"8" ,)TG.܂9t:=dWPazT(*\n)2xϭ;]]PB@`R$5b[OrΣh5 9c\`QwƝ nrUq%d5f-ac,V:|eb8 ̲°\ d%@EvӊM#ڑ IYwP_ܬvN0Tpڝ솒[ݙ#69i==3\0 ׷4s$fغ}eICN+3&8xʧ4BO&divXfA0 r9^w<(p0i̮f,x +ȧ-ԅO6S$:-InnW8u|A=l t[Xx\`p1UKhvhM(SԇPA"l!jps^D=:e(FsߏjƗQKb?QFl]X@Bp8֝pKPP$q] (/ IFp?*1$݊gUbj)TH7KGh X<0GFjHz{TKMKOkȒmĉs"cGlV1ZץU%@:޻+6d}*&MɆQp~irFZruRf$XMΊJkNxOª-jʟinZ4g6&ė]u zg.ɶC& *n|Ic=Ms:Ă?XfRj ɢilyϛDAumYE,hx?dКe/C:Ihq5O]AaA~\#lYVh-e=A}^ASUק28x3w ZǺ%ⰩS٫#jj^INY~yTX?tMqVxec=ze*h;FUtf61n09j-92 g 1^K}OJ+wn]BBsG2QZG[2]K3qG\q֭jҳ^U`2NA8rpĂ\Rylت V~34d|ČbSCJcaߞjug懣[KA2\}ePĎԯ|9Z ќSQ&F@~h)j;w0@>9 Є#gQH@,F;\v0 G\X nޖ?ŕPdNHF}q[ +99v1Y-$:{VL3^F+֮{vh34u! 6}}ꖾ$wis=:H,apq\Y9]t/+A.^ҹo0ik"ԭ уvb3Qv?Ծ&b=R0hgz#^b۱td=i$r8}9I9kK$:Q @zC[nD *qC&T~dz)(SVZTʒH_B[CІh“@S+3kwFNgsU'5{NNU`Blѫ/+3֭m2IEM=&ry_.F6$A^DDzebҸ[õŊMQf守=H8 R-,l\8ʼϹMׂKL2ZQ$ypΝA+׺|]H"Hz7٣UsS^Fo,^J6sK SgKA-EU N@#v۹;R_{ @WdǓiA#Rmg')9KpQ@9~:'ھX?y+ays_wUʮf!K?' yrĊ9xǨ\YhJj~q[_S,=5^̿xC0C(1+~¹-C]%m  qk\1^3pH%O6sl"E{dp*4@UK.G Jvv w{HۜQ:9<ӽ֪9 DXoJ4ho% *Cxyihz6ʖC*1(:9㏥WxFYc4-Y1RiV6^޺"fg N[j֪J fofc~d<~eNs*oݰr>S ҆ 6xDd0ѣc"ONfuWMX#w+S\ju$=&u=sJrIj vpi ?'9=ly@FN8$*GĜN Ė#q;z]*rq:zm8 g)00\wws$s!*T>ƛJSu}WNErc Aۏ־=i1Uҷ[­ d3Z̚B^ea+Fҹ_NV^ė\>u6!OU7ulT֝t㮗 u Aj^I--6 xwLӕ@6(d#.&uqoq䟩t1A$4D^)l{<gz56_l-mZW\bA8~k#M& A$h{xl 꽏*=_*M3ڪMO);9 NRSr;3'tW4[He! Q4s2kơ$3{Q-Ֆg2J;oU-gB'Ry>'2(a1+j_1b` ig9D,p S$8i%RFZKb% `}hwYm.0V8`i?'M qsY5N\(G/5|9&%U yLonU9<ËQ%TZG (vI]D BS +**Gc;rx#z2g('cBe*$wR"0t> AcIY PTT5gɒr9OTIkv9FpU)(縥)KT {U;Vq-aK)[>e^-}ik.7d$ryUl< z[kI!i9%$,CN+H-1sf<+iȋ!\qLP@?Z+[:3sLiG1=z1l"9bF:TA>m=nߌ,YrĂz9M|]P⡐B9OQJ?LHT2zN Zc-Z!x$Xd`ӵحfiFӐ qȪ@7dW<:iYb18ϵu_ \T0]?yؾ[Jg`t2O"^z[\BqIC{],KzSW^wMXͧI ԚN2O=+_h[RX{WlٺddI^?2IˊI* 8][pQG1#BGцEj`^oy6އQ SO }krΔd~`Sv:7J#=SJa=( (iRt=FS&nM ҩp:I=FÒv1K$l?pξs*GVco'Ih!_y?PHY4#Z詖[iWDQ|HЯ4yRe~qk&BENp?Je|LӚW?]R9 ߪɎaKO:l\wa8G(͵+orW'ȷ"Wf9gIٝ}|.-ҲV5O\O7_e"6wvȯ_+{InpכiV{wu"xз&6z8-wUI95Z`R?F8Իܵc 0LsTe)*wh+ &'={B֢WEQm烚UW{wخ8W)O-4Tcz$@LsۊO*ݰF8=UviNvCI6ԧu,qgRrhۃJS -O㚩4 ǰSz .]!<(ⶵyԮBU\h|#2U\,\e!k;H"#*ny)U|_!JѩSׁ*׆ӛ Y}"#ZpwLj7?ҭyw33eI ͳf^j6WRS{t/:M *zֺ9>ϡ}g0lj9Hx0ܱB3ϦGJEs`I G)>k="Yu*bH۝D 晲5לI 6P+BOt;IՄg +Obi0@'by7gc<_!"E,Q+fKkqC9utc}9- )q3Dl=O([h-A+ԃMXQdw*)gaEN<RM~n $aPܔ.1rG_̛֯{uPs88P:'IkkeQՅJ[9$B<54?8bARh68 )s5`yn[z FFw=Yn@ (aGDhjQ!"%8@jdv|`Ɖ@ygin1mwJzᴎ/ZEu)]KB)HTPH*j׉ 0ɓbD%jV 9uAة8Z|;?-IR~R{e\ДߡtXyi$ђnclYK+0 ,r‹э(@0zT%>$jZ5.'$9=ywNw3OY\g ͜[7Xub0r{j|6yT݃o3/X\)|'EM$Э6mNV?M{D$aW?ב' k"ㆥwu kg#yH5mQ1_-b&n!ȮDaO~=,8$I3BOvfl)`}qM>aɮKvq2xґIǭ [9r~p {n(#3+X\ÀkڿdInh N4Z{ [XHU;Xcl6ɦcͧpԼlm|_.W2/H HHڿ*E՛ϣTW5:׌e ѥKp7g?Dᖎ6"nvFu~R0Wo#~2@yN,JG<>W!o?4먮d~Wާ=xԵ1 $L\p FM~~x+ LxwFܗO"?C+6.%yIߎ? 9{wT-'thN܈bDʷQ6#PsU]%hbG_S_2q6F=hM֏ʴ 1vܴaXqEz*<ĝXk,!NVVܛ9chj9I4I-Wgǘܟ)FҸ+M-F'0)S:U؈]s+L]?%T.\18 ;\~$އWdP8$ 搐G}j$ʪ`aN?PXLg&,6%!ztm?7?S{28QF)Hz)<"9|ӵUe[qd'zM\A)U :P`nGBYbF:Rm,CvNA=)a;rh%U$TH?nGOZVh#$?+89pվ}ƈ \)#uK(d|ڒVv"xq~\K]D+LU,z=Mgovs0эn0{J 7 <˫"`dcWtCo~ZIp1ң| qO48 6Ar(,3~- YF\7^8=͘ir KQ'r'dT%P*2v°q*Yvy+R<6:mZ7 &L-l{q+^G()A@0ϱ*KJ1Rz5ܯ py~;H?t+2$}WW՟N,H$>ĝZU0җ~7S\mwѝL("ddXfwUyc73n庑Nbj)Ӵkw}pG?}&R8*NwAmk 3P=^cvv7Nk)ua`4 G-eyZ80s_9V덺VQ@Wښ#'Ì nzZR8(-di(hRv?7͟ƃ_NËF#?P)J2FOi;񌁌r(U@ Xv֍65 :Äg?z-?NR$aBecr#E]ƥ_)ܖP9K ўtRfR3b<,uU{=sxL C^Q]TPNfBkba+3gOW'|@w.;m#Ҽz2C"\DP9s $[RzӡRv*pnJO8=&wn2zkB?qE5ܘ-z+w`qkYܞ^Bzu"qz֒m$=@❍nEO@myZx`IʏyO#1M `c\ѝmW (s28wb^ڀ9';qH3ANip;p9sޔd=ǭn' 5NﰅJp0qR&MZaH)u")#7\RԿ]]yimn`Eaד5?nn `sݪe~G5˙FFCN8r9rT#񓉵O(ZB=ʟFai~m)UKAZ.tVC>su(5 '>,~;E^In"$wbǞZ8B[OCU%*ܑZE~&䑞stRŇɷ&.-쭅.3듂H}Jwf$ۃuGsV˛`.# ҹ{~5<6LBAڻFwW̙H@,2w N0I\"D۠G3#&('#'eKFe(eiQ2{TέopኜI'4$qI:c3ge l$+Ftkюl66sc#= [EySrFhw&ZGAEI"y'U'wqВ1 [*b+䑓EևV\*(OR:Y`CI`˫R9,0M,cq׃IKRi*99CX*-$qHKUs/OYə̪i+Vfu\w෹zTrE"b;ڽt9+B#>G^UeweN+m63yM% wBJQb"HeDB3GҦn6 haO * ;@ u&K,g]N/r1HUP0QOqe4b.UHk{=ѩUwca@P=^jҩ)QsYא{5w0ٲ܈[UP({ЅEq21ǧJ<`8pR .zF 9IA$kDž;Gq֪]b&$Z蒾;J6Z*쀀>W_ It=XsKW[w?fgH#+㖅ycZۿopGZ㫕(YDθ@&>_{K/~ϞPl2e%7&Xt~t$zsI5IYӠ|U%mj)7} <)'phZ+|"T3 cQ~a$5I#)pO8&API9V֑F+xE3ٜjCe'=*UU@UP[hXŪi6wG4l2E|+"Hpq?w䛔V")S*Hu^f,nHWɆȶ9gC2O˃^MvW3 RJ1Ż8$s/w~8Ug#j.$!AV&Rd%b1it'v^LHau+#Ś٭ϖ1^t%ierOZSs4TMm :4K %_Uƚ3jZ4C1i"T:JodR`՚rqu)ܤR=K8Us(|#; +c(B~l gTHḑf`88J#IU";o6tk4F m`:,$g>mʮtQʳH  1K| -+.';ۜU죈[*{ zMmcI e@%E-`vN1zQLrvHr<xNndL9Uf\[w⧊@-qp H+ sbCܩ-qRKFO4e3^ǘ5s@ 2SUԄ#?9TlYc+֕LA e FHocetnc.dq4]F#{0+7p5#TNU@R<玼U;4Kܧlc`I⥓@B*ȭ3'xj7|d} SXTeH0Wlq Y*dE(Hq{Q(t;ImVʜ*%8'4{2)Br[*Tdar7qTwip0xtɨyl SI' $sU#R F;XUDʎ4-򋘶 =sT6\w5KCt"?/U  tCK_q$ԑU#bp22}hd{&Fos8?\Ұ Kb6x+f\YGR2Z;צZmC:@FǑPMRUqJ/V,> R0z U/FhnaP w mw2m*# Lc4;_S+V@QR_{V.CZOrcrMt W~'LӤU2ǧzjA`q`vtXSLPkϖ^ YE1:sRsc-Ywh [R;@5;u$$<>Ŀv} AsQ1VGnzWSCsٕ rd&րdy%g44kϴX ry5ՓwC:G@z7,~ڕ@]v(Vo-m>Ɇa9Z[2Aq )L~u\e6܊i$?Zꒅ8O9/-+T0C^-mݝFsYbhn`@ ԯufVi/ZBTpҼ=]I ;Uaeȟ;:5"WvJӊ2]?Mo['#C{dU}SFk!\]jNYJڟs^"O5Ēw^E*ر]U:X\ 2Ǩ5nHJnl%$z$"\evd`{NeR up4'LYV~.Tj:6/#:8Co_`R=EcN.h۹BX{JB.32W_8{z^Fj :`!J2Tx{9Rϥ brHM;I;洠^~v*=}<;49\$NXlyL|BMKwCHz5+՗8ȨSm(?Ta<.#%p1wGHĭ zz[*09$r[2ʫ4qk,LcH=ꌇh$֛؉+B 8 ;s+q?4'>nJ:!|;ta]@ zJ;r AS*B`kRtPq߱HiF*?^y4ģœ1\w;W`hB\Sr3G]JN iJ17Oj$`~RC~'hEw)u,@=Y~ xVP׃s -[ڲ±2Kvkj^ҮӎR!o}٣R슸`Cs([f9nrUp隭{mo~+sI~E7}Oi3=D{I&9ccz`wUA$kӒ<[.F :Vv}G),4Ja -?BA(\´4X!+NyKdi {s^<Ȼ-B%)uʎ}7ySi0L?kw*+UAi~YJ@ǭJ\5؍F!mY>^ ѬQ8Kj`ܢNC=+j[ Ȯ> m̧dkGK Al%r+>\'D#׎ԒRR`+6I x8踻+3ܻG#c{àcZnRX9`V ;XιH˱݂NzfULNjBÞH]`$t5ܞdRg) tUD?J MtlJ+3KǠcTՈ/B%cqhZG9jdž;'NwLBx50:s֓Gsvg#^) fz2i1*JzP z)SkzP|8Vc^_:88*) )m{n8w%֯əiAeR=a>˧s]kX}ߧƱ*nd=ȿLT2xra¼RqvZOXm=|2' Zs6ЫTM2?~ hl_-[W>=X${l9i!s,Ac:u.㋵>KDi湍W,mV' oъq˯>)`ܨģ< ȼWde>ϩ¦?wEN:{S|C_ K}J^0#2Fuω6'AS::,C9' ZQBSksm~'ʥ`f z zdeW7դ3yMy643Nm!`HA,!>]M?xU~MY Ǔ5|"Zҭ#5626&-;#_lw+<)?)X+Ӯd;L7$`7nGZ^Twvvv1Y1 f>4-( aNͦe'}Oax+; q_Uj*qЕ&W%M4:i 1s5nޫyHXa!F|AyI!WTH+ХrW/9}Kܱ'ǗkM+XWҩS921 )叡U3*tN,5ki‚C66Vdi^bwV51jdԊ+PRWP1X؟%X&&֌]H9rwc9FF}O[ax匼SV&Wc*^'I9QTQa˃*TyJ,{{ lfv#[=O14Յy!d/F:3"ZIhrlfIifhrwqrGT%ew0=9ҥkf4= >RWtoE8ɮF88 bJ8⡸iII*`Wi b8tҌ7hLvW() IgZQA┼UTpsU$c ǒ۱ţ*L*9fBwއ-.-F{r[Ur.qPejWbyc5 ׏qC3֧tP3C,eNs=C?TM'ҩɶo 4D2A\mSSMۡ<X{R ~?ԦYJ i'c1ӊP0z( H5Q+*muq+m#e GҚ0d59SL$9e0?jͼom}6I-y#)a?]cz.#wT_c}ko<ŔLCt#ӽ|x]]S[v u.cFI}s KmpfQB +=wS(Ͷ}ZInm-`X[g bTfFG\zfx:(3[.i[Wʬ4[1x٭;J0Gֽ;_=FH).fݸ8Tzj3ն{:Y3NqI1: ȯbY"|hI@5UHKyo4c7JdPR w@gĚ?$oA֪l:TngfT(݁e >|DN7@Q5N:%Fv8J`wpjP0gnsNZhTagcCHAxbG/(*y8+ƎOh{{?j]60aݜ)Y>HacX9;cJܤ6~b{9=l^x[󜞾+D@\KCy pg⩽u8㞴ˏƖe`rAHr$G)+c}>|;43FA?0==^a4nNƋ.jq#;Ƅǭz_C-%x> YcFx7j]*>tF5.@J lozti)jgc:qջi*|I_vvi"$hllI-rqۑY? |=ֵ=_<*I&mk xyUDg_)UT;k,`S跞`5PuP?ȌøG4w/1rZ&a&8'}E~{GJ.-ş/ՍDqs<'yO5.}5v:!Icr@[]cs*Ek!$/Fj]l-NN'S (>nWٚP;M5dZw+ɲ5|v;B^X/͹YntK~jjG' s=+Ч:+KWhN7aOOѕ4@QsUufED-"{vn݂k6WTz`tQZ tgKmɒu0Vfs3T=v5Z-O[Ӳ41WӬm,%Y785Yy^sFAֈ)Ygzf$Cwy7G\)Oچ`>eJܶEhۀ cL=>8D(ѠR%tȄ!w~Nk}@Wݏ gҭFm4C Y'/01H#I!ݥ+8w(@JcXs $vqT somĒzC`qTne06Kޖ!V]'5BKr9b3i7إدr ؞ dhQ{қSWv?ҩ#v' [ ں#sWtQvsUdQnxQC&MFz Z֤7$d Tw=S„G'5^`7pA3]:YܜTN*:TC$BہWXW&ͭ 88 N`K?Ɵ5RM^,G$T.^FJ3evWG,_J,!!"Qa{ɠR:!9yPDuеQ%ci԰‘'Qع$cmFJ:u/89khJvfv6}:2USJ7[\qn0jvg۸|?IQX'gsf6L[z{SҏncSI'Ҧ)2َT[kkrOoZ/9V^G?' IE%p ؊UֳL-aUGF9ci9vBco'r6Qօ!5v1q=)vw>V > 0Fs1r_KcМci>`Ҏ{HNQD6>G͜ZdtgѦ$6͔>$`_03|gKa0aT%8֥h\2~OIrq(݄Ws҈-4le;}+^]ul)H[Xt<) @C6g*ЧԌ(TuH7g*TMN-w=sOL|,@޺Nӑی:7FDc(h2cmi4s,Cxnaۥ}TIJRhtR( VPIum@m[btѶ| ѳF5櫦g_\[MYPyLz9]Gch ѝ9kYw?.,;<G~=)Bq=i]1*H8CJJوH&\$zsM,cՔ)+砻y;9})ɖ`Oh@|\ V4V'X< ձ}jmRfћt7E< 3׭9=L+T^G zs |Qd_QH1I(@,qMK6wiF˩}SIj +f;&_͑OA|5K?V[-I,rYt"ۄenʲ͵O,2/]Tfk%Ώ9K(su_2{ևs98"Pa z5t,0܌sDW^SZy&i6TWS 61x;;) i evָץJ|؎Qv+΋eNHUC7MD[<`OcU. ҩYJ$.?.jee%{I'AE֐6:PH޵s$^*:z Է}ItDL1bf%1ROI4Ж y 2tɪ匄+u(Xžr'9Ara[-]̹h@eҧ2gpGcR\[ӡZPN?jPȽG8$uSԤnF@ vfgkovznDag+m^+=F91+Rj506zPm!'ұR]Y, <J~]u1(##@GcNP[ךuJ핬4`$<ҺZq.ÿzFFAI6)P.TTp1ZFq{;] @$U;?֤2>P'fW\ZNA&cސڗ=(k`_:ŸicLG8]!VGx %#88bϮ;IE4? vOʞqҿ)އҴަ?j oK>XD;z𫺍vs(p@>?Z*ɴ1>#mMw(/&T,29~<:~xi*{l@*9sX=-NZ.9R61'O%mϮi FrOJQ8R1QqB]*F=qNy5=CsBHzlJ{iLN3+u012l?z-pGR*ήx$7GŰ}eU*X )֪\qI] =rzIRHJDI⢛R6 w/T:Pr`b%%Qn#(h-'d%v78'U==1Mc%yXڃc }Mn|7o8iE]k?I:zTˌH5{PFv? qPxmzHݻK2!qQZM\6"Il:QrzՄ%^'T:T$@Aͭeg'S&}}‹\c#m"VMr I#"xsQ4ٿK1)|Ao D,4(ߌm$"p)/#&>R9®s%S^IitFI&H7QWLS't~灒}'6 u9iC#$;KT͔D'8RdJmD1I 3&yݏ@)8Ѧ )Gw23_¡sOJk jZR윎 )Pr2{T7 G~hZsҨc ǿҕPs+S묘8*Ńy?wڟ2غ,[2W#^< _ yrhez 4Īn%G=3_W3JlX~j =kIzfuHI:VV%R\gވfT^l[õåUwOo 7$1z{M5*1[ֺ;ϥyPVdk١@ c5 ΫishR"&rsҾ tTjzEqmkp]4CKzd/K pKry=z]S˚X!ɔנlBހ%.xM4|V,Sv2)w' VCgm1lb)]!_*0̣qT`rnsSݎN;KBTڹH Etv*NJ17*ݳZZ]lr3PvfB8=֢٢=MZI6s)/sj.HE=Z ^!F?. xe)eOD|ݏi5F(Rx%7uPNAAhyWblK894 e"gzkE=IJ8 5#Y(9Fr*ѓ&9P@tr;V `PjSIkdXYu/5=&8g]8e" >U`:?z̖֯ح~\ dK#1 ]H`pvmM];FU I #4}eXad`g,S,g֩#BsFe)e@[K.`c'%VfR։jˎ* =GQH@Gzjȉkːt3=j]Z;39sv5R{c1iVvU=>)0*{vg!x2*և2/9R,vbzم?F?+:S."TNC+4G&cL *(C)`{$_iF*9P2qQn*vMCCgJѦud*pHgBGz`uVJ9\*Bʹs歫Zī%dQԈ?CUlr9iݳzR[HC 1Gf#=Qut񻣽Ձ02jšFN3ҰoSͲ#$6%89>pio .m$iŇ~*jtDw %ԯOjQ˒  aدR1O@sKqڿ2L c=9 I^2NOϚi&!x8Jp}NI%k̛J0h|+o»+.2[ϸ*RCmUYx;F1]YxKMB̪RZ((Tz.!HpI(=I9Ƈըc9iTm1ǹۻ}lr 9Yr T:viI2XH#,#P|LHr 89&n.pONHM+g֪=nZU On=iwd85:1}C;5oN \Bc<. 5>aݏ*`ՙ'Q>:w).-/cdͿ Ŀ# A^khzN[p: 1cUiir-XAU[N@U㫻 `#wP9m#v.:c"6i#=iGV=N+{zZD3֗=Oõrvz֛jhsnғKc}_ϝok/Rp ;iAo(O)$FkB_0ę(i1mQ˒ o㊌RnQTLak8ܒLds_j6\\Z^DǓ ' D}M)lK)3 aO"?n r`\~U@$}DpU~6]_acZJiMs+89 cgyc|ae[9Teb=R7G1"~73Lӡj6<澽+$|/@.V؋R${YZGg<ʵՙB"G Đآifgv0?*W+۟1sYDG*_zֵ% aq^by5&ˉ\'#4O0 RՍH2UO&IHTtvnP$SPZ.L EdGocBi ˳eJf4YVc׎@W~۞rnG'2NjѪ:s*w %vP".~7p.kmgTr7qQ'r}!uz#]{ gnDp]sҩ:Xg9BZ {{pu_^ PNB.j0q{-vҥ(^A,*H :3]9Ԥo+BI N)l\^dI9i²izgҫ]J ;]X{]XȣnI$l=72vD)OlTGԻ {2֫1@KRѣKY]bC<ӤeܽC΄DTq[vH^T)1!w\sǽns8٫! Mق{Um>gQQVvuU.~b:4\#xH@oZ#ms`5-qrg&[ vI-LnA* oH5ZU8RuJ`zSѣzHO͓֭OHacֈos^[3r.s*EoX]Ik[kn܌Vޢ1#˵ 0n}S AޕX?]}mat~rk!}_R6H+^RGn܊R1ֿ2jxpI%A\`xԐڻ#֖2$2)7ih)l`M;>]Q|ЪqJBtkZV|c/=*yf>Dxg҄ww{Ln`?rC]d)w4ˉ6yUVf&4?[Kkūp L+ ^,D o L$a9bSs[&^.G\<{;Uχ~-[Ru+Mv^URX63@]kO N)+wKz:VѠzW;SOzo 9%|-Ki03ʥA]\_B _38XH*j~Ƹ'jɟXʞpsLo3/{cD58@9_ p)^1Z-V@=Acީ MOXx Rs{W H7 ݍ4#׽$=M?9 qiLԬlLlN7z4;Qh±eIsU,gv?jytpcֺ4\XN~Y+bg}-kk1d;rW"݂$dg5g߷ռ p1pЖ qBLC־##cvvsJ UaEFih;t9^!wvG%ZiV2a]d{.ϠNFXxh# \z;\9nkZ< STOi俚T*FIm;ܣyw׳]Jμx*+ݻmcFJϡ[VaVb1?z7ihyW}&v&0Y}kdMYyЏZd̩'w`*GڜvC~$YD m븊DHx)-4Sl=Wiyi^r6ٍk%p {⸄ hTZĊ1NW% @,}H{I.QTI q+9jʎ.$a ".3) up%e]sAq{a)7 4I؏OgNXNN\9(:E9s+uөN ܬ?r+1ؽEmzL[ 麗mq+JƛpIEw-Y $U\1+5/*Ŵ+^TͲ7s{ RIjC|̦ 1*NI m4?ւxFfA:\3I*x0潑̪֫aCD!rxpUXpxϭWʭ~eZ$e!I= ~,rfE8#=km֑m*+!3'ZT7vQ&C35^1M5áx[rxQ5ـK&uۄt >I%~Xy"Yu k&Uơuirϖ x>(^{^fkT4oHeo=Yܙ7P\Z#i_xn3޹c,ރ=Ԍb۟/c֫ Ʋ[ ^A">!}+i_\ޗ@:0C : M=ޞF2*{ᓺpxtk!q޴ӻ9 LQG]ǀrk٭o:^֭O],Ѩw~u䤦nqovmU9N?uy7)ZWtl,."IOGވ@탊vB}5{;>t >[_. ׂ`f`z 쉜5vќaNdkFCנY[IƱ&;+2~=:rKDr9mG]V3! py,O9:j'JX1L6$ JMۻ?lFs;d skg{"gH'"\.?ءHZJqX]ܹF Sʑ֦CMIc$1i 1ƤڹԙWXk6 OX?P~c3FC\kL ~\iCMG&|sVIRcxCH=3OߴcЊTMɟNy gӚz`}kFg1@9ҩ^и<6O}ӷsYt4#83ޕN@'ocЬx*?Ji8<>dgsYG౶/M |޵^FI]5ZlgRgckZrOg/xkDB!m[H7t5m+ϽML=XU|:`prG)Ѐ@$zW Osmsh!/.徖V1{TWh垧*FWC{u%"1/4ρ:i#^j<=m%=>دLC_=[.a9FrGNz/fm- P`{wVj<\Ѿc|%1:tax8:jg#K0t R=J߂5Vܖ6[.I[+*885#z(qI{gcӮmT%K"FĂKܼʾ_*C ۔ڻ^el+̣jLWQK{Mo-l.PR>_0c+9;SfdUU QT=Oq\)Cz4ݨ =wci0zl5X=3R[9Bt‚1I\=)q ;ulZr﵄i$qFA#ZWQ=PnH#;̼;Qt=eK{wxhѰFzկ%^Vi-B< {9d^Fx=TDC(Bʟ3tGaΠӫ1] 8MnNw622jUϽ&{T#S&qxAJ{.I78; n)6Kap$OB2䓞* J'$tFͅ~|P>:zRZ-Ee$Ulj ,c=*es9гe@9>NTd պvݦ p *>]|㵢ˈF3PHG&Ir2faS#RXdMY)I-OV޹l=>gbri@xԬgʖtd2NO}:m~*sqx#:4F?zvgq\'ٴDaĪTwFg Tec%GV򑴭Ln\Fkԡ}"8#ʙZ :+jP)T1 * [˕~X$/ξ{ <_3WeؐjUrO0UO9.>Phu8'zo{-!K$lA%]W N4{uϣt43 G`f+Tfc4_cgU~D /V2G#WOڻH;T#lb- &x'қp<#/"EL4Ц{KUr܀*բ'@>cҽv<&e7\H^5^YM[O4DZO#;uej ,~DeѯHC֜+TKp$B4x O=l.VQZ?b 7ad"I3N_wQDr1$gNc CLV}5^b&`c$MR0ީ\p6VLЪd ۸U Kb7ICzVpبF|˵ӨBǩ.2iJl}'9F1X3Rj"rpG'@k;A#oS(M]GJt۲F9攴Wccj2JclUpmkR IS=U^uBaGnZT7գK`I|qҠj~QjqHëyKߓ#\.Tpqtɛ6W vG@&re^~kS_burx+'( @)}2qS-4e^p>ҀqT)6Ю9'޿,~LĬq_H_g" ]7~lҺשݪ+ۈain/%zLsӭ=&krdgY1AۭS<3Kj94]JVf-@5ޥV+m➧Ѭ(8#6~W)^Gkv9xv.[ȥ.-\dOqֹ;?^!:mQ);G}[ףYjDhYI[~(SiI2d!Nz~Ugֽ&r$F{W<:_ GrOvΩ~lx ϸ5wcZ@`^UqQN=!l0@gc9=jRwGbq\w[=Fu+k[xA?/§:ϤWeWρ.bdWKIyFB1?[H͟ījc[;lӍ78с+xD ;O)e2kSy *#F6֢56yv?PN3 It ~es>Hwv'T*?ZKrd]۷7AncUw`t4U"KrɐӼt2i;tmʊFr1ާLѫLi=MDo,YF K,>+D*/V5[p7ƻ0?F[PFb  ƋMF)"Kq4mK7m:utocV#r1I-AԞi^܀=)arڸ['G 3KB sБM`H{u)[a *9*[}B+X%:lmsf,g Q($uM&.= 6J?\W:c~i+bYxmaq$9jniFV 7/c_>*E8k{zUaH {qW˓F+%gJק[G!o2"<>@|:cدu:CO9 9 #1@K _aBV}3;Qd,-wOִRoC6$sC0AbSGp)je,dEbzԚ4n$E;jy\Z)0{~?,aujE^RJl ~l͝R"AN $JjAKbKs|HMx,A}?ETj!"@VnQW|ҲרBLb v=37D8Z(m&[Pa:&hu_F8)dYq{Zj?Inc,m )-+ҰNYJ #m1#6@d^C9{@#'淋FsPx5O&"$U H*y4TZi^7;X%8c00pvWZV!#%9K+8*>l ]cu=5q)8fT)\FiOAPKϥ94 #bX60=jt69ϯ#җc*NcqUU;n Zhm(`sƳ#A^]aJuREAti'`z۶D7TRM$s[-Lfdga,1i5{®Rmi:֬670=p:l6Ohq4mLFK~(Ii%C.ݸ`;s{s} {Bɕ;g$uW3odWt "F0  *.un9>_F\}+SHh]ӫj[ⲷSh=-U$͝r~uu+\pcl]ƛ񍣁Y$Zz&X8^Ey+WUlOgm$ivnٕK ڨJ޵"*~wuy'.-! ǵyѦtc?|e[1c;^ikh\p;s[#0ZnRܕN[9)I,9pW&p/=ۨܡM2w\c{WDsJ$!c;6P(gɈ; E~UO>kFe5[;<:R< 76SrB-yfHqpOό׺ܻM($uA"/wx4mV|H`e;W·YөV9 ,;qym_C)&G-(=6:WzVE7̑xtRU;^{Sn4o2f;J҆^JQz ڢVHVBΒw hRLm`~59L`7AϿsvXnCrʤ2=w |`t/r PPZqj-֏4Ow!Y[ ,^jT` ?B442A2 3g?c%(x4CB@ְGm$n /GϨ^0 87O8E1?Tԍ/C|3QF G\Mfz5BAK*8 c4Љ+k|*)>rIyɤQ}_p#wҺ|p:i͠mنRH:F5F)ct UZڕw3\h=7-כa8涾xm ^xEI#p7$LҔ|-{"p@)}8b Z:u-}%u58pxZ~w'p's[=~:7 0)ߢϰC2[#<cM52;OY1$u+XjlU^IԴ<0_A38aj *7dqⷴYʕ=E}^ZIBѡi"]s3Sb`Ia[5fd #K1Y;ʵ?sA6ːt˫s$<)Lq^hw%!F#[`(Kn;r*b%f.QцpG fPBnz8<>k(em x8$%kb0UGS40@d;V WkhyRv.0X*'~zSRn%S9iSdych}+8&݌e>fJp)-Fݏs*T`]gh5+n9 9N09ޚGPW ),:*o= gk`q-$L)EVoW exc9{MٟR . s6BXdArYUdlNG9vqzULx(ߜzp3v5EZN_jSS/vfް#LSqas_SHbKj28 ?ū9;f|pGQZcl!<&Pug~+f, Oj)KKɸ⼿$.GWq#[s }:!A9Ze"DIU&ckqg!2~`~W|!⛭FȾc^ONi,DSyH0J…Z7lȚM:]2+|BˠmnpdS0{c+'sU9ySoZ0CЁOR08Wk-v/v ǥ^}9{%}+EٶFN3%rS\h=?$i9L;n< ŽGO{_% czzX毬5hu.EmX1eX8Mn1<]|:=7rX^cG5!sy\xzSҽJ=kE?t|ѵRy"iB+ou:c~r۞M\7*ʼnz GbC6"ӾW ؀zA: 1F0OZzo/!{?QB0s#Ui٤V59Y0((~p8⺒zIebU_4hLn8Ӟ w?0,`+ƙso.&>I1c${l~$sqj)"H\ͭŻdT2?IḂ=š3nEpҷ䶶fVa$(p1w~MC%Ն˿o0oJ/(%?5v154dJ|Iڪ?RvB 9>%vz @c8B9䊩$'Ј :nlr3Jh͋88=9hՉlg=dvs׊Vޠ |?LsFrp k!l6r>%I#֗-,c"InRܴ%bj:Qp$kEhбkzui|#٘`B=q޽ЎNIzۈձL,$5s9NHCg_S;ƾb?|Wsq_>[}+{\*5Sslh8ni@ŹVp9ڱ^eڌcҽ;s- f?|sMw=Kg~M.'T;;VW4vT:zɪQgWW3NV8nU*YabC:c̢F<<j)UPJ=:SqIY4%x[Oүr0!y8Eyzh7[*٪R7J -ʒ܅w#zPwŋ55*A'9gkvh䐧<6CZMR(Ojf+y{L``dbXmY!HFw1ШG\8Q{ZAyu$N JG ?:/gT:LVR8j^D0ݬw!~w3`q?)"?X 4J~f&X!`8]#VL^rFO5Cj/VWMjV#H;kNz .#~jg f&eY2F1銅܆Dlvq'},avbE#ny'bحw*^"'Ϧ* lF8+̪ `$qTK6{_Q?։feϽUpKoC̀8U^gq;SZV\1ϙ7ؕgnr1Eˬx@jŧ6:sU扤*O`lD5r"r^6*NHu5s  7fv`S.P\twr䭯C6p+1c5RÝ7n2$M*wz֜RwL!+ C1  Ѽ$C2IN3ձңrJJw5˩x>b$G~k[Nh\9Мpj' ) 1^t ѝ|3*-E,1YViaodc?})Kb'\0M^6̴qzUiZi-NV¶n轩8}A{رGU^uNC,9S7{4)$Nv=MU;fD>>%jG+iwzəd´; tq._jR礤Ǿh::e.14q}h0j^#FD)rCQ7KGsPrqAN\Gخ+]o1ڔFN񊙮~gԮǧ?C*WV>ͳSfnFϵnLaF~N ԲZSFn}=jMQXym:Tcs^wfo+ڣMo)[r}A: j3}==x$u7\X['E\S@{Uoj6:isnܲ5(Ywte5tj2Boaxg>~tKƧ+c+_ᗉ}ItkI[{u2`t :ZՏȏNِ{#/z|Weq=LSZFRM;EΟi>V`]ڕ6w}֪8J.YܠXԱM $1naUWՉ[<<ֱRTde9kQ]{Ĩr_]֝ JX ۞IGqY ѵص nIZLFcBǓSҹ5NryNo\ps\Řc}oXLg+ *h4tX"#`|ֳ,rn!1h[V d,@ֻ^D*2kW_XMUg}3+hjԟ2&Y񅬪"Cu |{@?rs/tkB@?jRt޼SW> ,_m-s}9fI6kxw[xѧe&7Qzlr+$*gQ^UԢt\,6!eߎ3_7iMIxWl1$: hϭmi6+cds)c ȣq mjC=r==9X0tnVDWņզK[ O5]$`OQSmn55?Y =H9MRS#gVi{- ꌲp@9$E^ɟvE݂'䊆$ #1dQR{RIe C QH88?`˩iG5}HG3nlEt'WY'ApP +;m3o`5q3:ғHԺCAaQb[wkb  }:m6v7''Oj׹Pڋ',hPy=o X nJ1X8rUO8)Sw Dή%0£ ?F-?w C_tmy.{̬0 Wڢ@/ "S]Zv:טۋF$9ɥH-ndz?Ю ƆR\ڹyP 2q}G/-xL ė1m4 s-j+]a_xU*_J =''F+O"]D^FOCd [>ѻpS5F΋7=j]VP]#Wojg~n-6z:mJbjBڞG<7^xo],n 5)MǠ/vmW=n~RiXHa=9>>P&X]&kRNK>\%th#qX8kkbPp~SYB̠vklTgu'ޟJ!^u#ew1k]"D𽓏Y`++wVK;qW(6Z'oVzljsui]dNk2ICpOV H~䟷~_UY[}5fJ:UIxcbGBK7Sq6€xR:'ڔ@Wf`x'zIJۍX$*6\}3W FO>2zqZBT>^kw:vXc'#G)[; =iq8>ZMYMY'i9z֡5gUb#o&('|!2?~j&fѤ҃1־sa_q7s谕9]@TsstE|t§A\$m꜠=}x;d WEo3ϯVhZFN@օ6XۭvWedh>VSRz> ÷Xǿϖ *¯{Cٯ/qC¶.NqЎ |L$aTX)Qt>4JzEfxcS- K d{5wֆ<yW`r9v5m]\KIXKˀ 1ZY]/"-,3,Aҗ)9';$g\N*΄8{+DI*•G(9 R德rcyy \4Wjb\Տ[[5H Q}n<аvwyVR# rU4u8敌LS}#wK@Cq+2(I݌*`{LFQc]`8ޣRNMݟْ+X`#=fJ\p\Ȯ{ǟ}SG,x\ֻƕv$$U9vĎԭkٙPGLT3:꧱ւԂdd(%BQ2N}KvV);ֆrYڐt !zf9 (I dg9Nv]c ZI{jw0֩{[B\ TfnZ `ڹϊv9Ӧvd`?q[sGf꧉ظ'UMEM!x%ʬCFcک?W";K+^dfbg]Y^++ p@$\Ż>ýGᛛr̍i2+T\W3s?lWZNC֜r3?ҕ5nԮǷL(^I~Vg=e??ÚAX7m`f\%2ցێM(E'1)mf0Ku_C$e,t)b+i\h_$wuP]QF{ҼįcпBX-2{U1h Ն21*JҰ$}zUL}YIc(:}sB"?[1e !2 `W@,m7i" Hϡ^zUrm]DVFwnd@[T)>#)ΚjFvK}TOĠ@9yWxOR:Ƒ@S_jJJ*GE@ c9 ]޼~sʻu+yHrzx읏6Gql= F YYyORiT)5Յ-6x@gjI ; # d*'v%LJy'Ⓘv3╻<܃ -U%7[DQá:_|qTӐI"cO 8U[Hԏ:&<<+Qs{Wn}-&PoU{ʓIywBtxWx Fl xQ }w;mJQq\)PQҴ,.\e{A]HfI 9޻v;`I"D0c.sھ{ g{8x6}?Όac#qoHm"%{DUa^z;WvS E:df;CBs޽EVQpH &ФC!c`)ǡ$ sIv Ury5wvqdT{:"ўy mU;d5#S=,d۳!S YT;hUpIu?e9 pT*Ȏ^q[V`c=9O-~G5eMQ aV_EN=[C7}*6 ֔QI.z7)(?k{KJ# }EDH qҥw%+C"cr98[0$7QBFЀOZI=lYc d%A fb*3LCP`מ;R|Fr@gRo<fKB"r@ B_/8;)&G|0@b88+gy35*lq8&!FsP)=nwdr[ZϷcCr+*t$gDug'2XŐgmZ/#=H5+ζ%ȅvH+bU)jFR΂v~%F$ҧ0McO3p%sZjuoq< vWRMt1$h v5JVЉZ;O:枇'~$΅a@;P6JЮ+0h~]}e3DnI\V?HԸ`@k& H8K\dNO^2w{(ѩug OF\gpᵿ鷏|?m*lzW,Wv{3jÙ\.V×q&@~7jGw:_ |<<#m Lr.ώǽPi%T$uI$VNYXjrZLT8#7j V4:uLHI!ti-|f9w+*YA};-{8#ϖ Fd U*+Z5F:^bZ- y Z0H9aGׇZYܯ}k-%Trg=+z7C[%S&85\ݰ0sRY9;8 rmImtTbFQ1SIk^Kj0G- sW_3iTLݰY]GmQ a`#<՛|IoV1~q?ñK>LDL~v}>k+meP6o5ޗ,ny4Դ0m?&܊İ#b]$Hϖ/) |NJ㟭'F#R wқ*<%i :W]']LHE0c2iV@v&23֓COȄYYn`. O`hɛخn{ژǧ<{cۚ'bSg\M(#9c'-lWB'LB&*.;׹qYѶ'ɩ K1{SQc;6 "tH =b68wXMZڌPLcO%rj{R΄?̺\ ~\ak/u\gwLI9`T|JUs+Z] %\wwRY:VOϥGy{ɒOQ@ ;Hj*2|sޛ;+g{ 1EU4m{κ1YOKkh(4v{S^|iYPROsm jLqMԮOێ1JW©w}tݑS[Q&v L.2GSHR8M=hɣ X 99rcGTqSCI]?Յm4ԁϥ~R>C%I(`sbkҼC4s\۠Bִ"%]֟y q[rJmjFsP?}4X "PEw֦Y֭YFA=sJ'#<_Z=Xs=<8< BoK! `hgkx\V|n{ZImdG%`$P=s_Yh};SUԖO3ˇxrknt,q:95ق[ثY^-ªcmRp c#v>^5VߓPRe_w֜RU3;*O'=sT̥g'5y|/K`OAY|$ Z)w3uWzŸˑ7.tVY$+?{:Zchb6nKj[:)Z: _<Ǵo`6W8]Iq 0GGV[^E֟j'7ZhIDp8Z^u6K{KѲ $ǯLS%˩I+vVz0Z]X'uW"|YzŮWrAˤr2;I`7yp?u!HRW8?:A;hߝzlsPHA!덧vd(nrs)׌=宂g=SM`d'hP!fpOc֐@RMv/h7C xd"bFPqCgSbgR?d Ock2WBTϥ~qAƭJ.7*@89vF_R$E:Y^5@/oJO,O[VBrTz5QKʨTqֻ߃Mefwp6'vPg K} %#H tV'ݦAg}~ޔORF]ގYJױ0*?i0`pjDw&wQj4Nd%Mi (a=, ?grh摣R;»5E-laȨH70#SIJ2mا˛#M(jVOR1q 6fx$wڰ'̏ ;xr෰TU8#wSκ˛n'5%n᎘Ў#\ǜRz^xٮma؂7]ƵԆ IimA3p G `yȪ}EbF:}PlL>JA+ВDd vSF? zEyB;VfQz܆BeI.#߼J.hY@u4z Kn}*f5+9j 4vlFs8XJtbP[959`cn=\`k/`/ [Ֆ%77 .`1s՟_HNNzZQM$&~!k~|xٱE$`$[5{ 26t|&~\:jzZrK/1m=kVF;{J#ftA#AMM9EJǡ[:cJc-~M]I[Ar;O?-qsЬ{S9Ga_nDKc89? #09QҷJdOFwdq^)6OSj(8(TւSӵ&ɻ?ш :s_I[{jv:Bw TYq ) 2p;>1~MMs=UON Gyd}QVR@ ]'LcTRn+Mis: A9r=j9XyR(eO=Ԟ;W ћGGޟ%yor|I3rk&[ GXN3^dugېHSX,2^}ыtڱ ٫2Ӊ!e\ [¹PryzRi|mFױ+_DKps n0wP~VƣH A0-yh#pǡWq2[mU!rC}{szkh$*5u;ZkYxs;=\nls%BlG)qRTt8V v+ґOqҖBmE AaG˴zac쪱؞ҿ(i\v=v\7&1:v< z0PۡO~}Q # U.8ܚ:sĿmIណ K(|l!"aEK2y]w81 Խh%8bNcҴ)}][JCHp`(j>xn>!t(HSvJ.L gkm .`n_=Z٥({gW6ȥF#h>YqX׭T/Eǯ9#ڤRGŸT6,k0OZwM\u'MHL%8f$F9ZP{];jVtQ y@wpF1UIDSoD MIt[FAq58Q *#A?)cUuM+;[n2+3bUnpy+]6{J-,Mc,C{qrqh&۹^k(!=m H&$n?Ҥ{]2Zid t2yL)*pk6q$-OF<ԒP6E5+W0bAQʞa y={f\݉97'{uY)b9+)ŷqHd  T\0M+DoePsA>Ytr8U ܥ~N؈'T%B#tDUbB j ˖#^t6c4 AFJq%Re ڥ5`uMgV4׸R4۩zjnPK bi& Lͧ@Y*:߰8bJ>]duC+؎jŢm8\_%[m1T'\ʜV׸;uÐ:7CqiKKMi4[g jM?Z-MrHFD_AڝDmvk&[XY:;EY@Xl*(gSwv;6mќ$5:L$tRv:vk>Nyb )+aR^ݸ5_nldF󁽿@~eRf{ڎ43/if ܶq$18©ǹ5V(ӥ'e0;$ Ԁqz]j>ʤ <֡'8Ak̖d|_ %㵐\8W~22kϒDb g |ךO!WB=?JCvPk6~u$28붐vNWTjJvQmXWYv`OOCS(U;e3p4(гpօZPʘJsRqz #Tmm-a*Ki Q$md&i1w 4ѨFϣ d#56HRGex譮3ټ/˟8 *~wE5gPi䜨ʐp$Z9tԘKW]Jjo-uY9̶ .5n< Ú樔ZGUikEXV3چ%pF J|<u,޺pZ]E4B)*Fx茘g x+kVC2Dаf^pA$Dž-E "Fht*zV1C6"JUsқ?+8"5jG#4*=p%GCP87r.hSzw۹ϭ&u_Y_luTԩ4XCT33Օk$t#bryTu*I[_֗)̸o|s")++ 7^jXX<Iܒ)qLHH]'c;%9ae7GݯC`5K u=}+M_Hu,;H>Ʋi AQb^dRdp ڻd LQ?ĕ8? hSk|C]5ۀ4c%t~΅aoe繖VANJ\=&h;l7ɴ=ɧ >gB#4n[19%N{Tm˷pGaSI3Hk|j oj! Y'-"WI+^o;o"MExcnsO|-6 a5EZ.G)Z˹[CYRE@F0 U֧|AX@ZS(:\ۜ#1ڱ"{pvm ˢ: xW'h᲼k^cBH WoBEYoyPs߽lU+5tȭ]e.,3G_BZcp륻+J^M_ZhY"|nUP~xS[Okql_64y3u.4I%CX_T"ٱ5c 2dWA}cVc㓌UC>&i[d,L1 9uz_I}KjvB kCOGwѭCo, cQ_?Zfstœ´dFtѩu2r3q4 BFb'JzVoi1 e Q 'I7v@= "Xzuwd$7:qJ-MB$+J.?R}=sl2r"BejҮ δ5I{Ud% \ v WP} ,Fs5VXƼ4tJǑ׶'=NHY/-71?J=&ecݎt_^>br=@܊NA5VYq^ (~k?šG/,٧kd3pt=x5VW φ/p< `\E5_S%UQwoZAw"!Y7]HPOzokUp:yZd sP<]M5 spw//=AQlvN}eMܮF2zu/bnmɥqTm%#e-/su?ͧGzNPnZT3]:~cJ@dXGFOB}J_ -He œQ-٥+@HAp*{5#<ɢt%ە]S^o^w 8}"MR=\jvpO־Tߋw:=RodcPc{um.2+ak;kٝ&pnbČՐuj7pG9&+jTncԮbNGjr ;S,Ҹ5|:v"2_ʷ»)虫Ib#n*xrq۟҂y8t?Յ׃1Qy$c&*[_ea3ПJY9 >]v;>=qN*0{JkO#Tք.2ONf$tQ_c9W't+9JcPSF!{В)Y77'Woc2hm3 h֢v.sM~LVb'^_g-,8( 0OUԤR*Ks]g[oSHiH*(PA%1kRG{xRkFPѤY&\d5̲yp.%>G˻:u氝ҹ?B ^++jcp}5٫o1WH=;bRHa&:pA5OaHp_ˍO鯺'x^#$~UtR^g-{'s}oNX>V!ÁКfdX@ CN}yk:Jz3*U9u8{lA;VM|Z+$dϯRԪ)kr 0 -(qNk͒U'qm"o?ٛ@@{c5A]C#SЏsC\+1XAʹiYAi鶺VdrXn)ӽ숪֗?gxNTDܧ ⾞1xsM\<;[.:B3ڪ ^2m~J| Ջc"Ѱ;ھLU8ӚmP8ߜe2鎆!L[-ڽJF -6đ%Me1_/AQXIg_ح'#::"8qqJ>ck_Y^(Hы7"#HkBkk.זnE"s9= O `fyQ#l$H ֻ۸u;[`ǡǽ6h3'SH4(W.NѳrтaVDnT=Z]rU F K[gfgb98O98"ecW[RRD"H?0I: X+ 9,/vUr܋RFXFAQk6icMs;kא6g#3T2_$F*솊 cE[,1ezpۙPĂ0y"v |V"[a%:Vϖ̬#=3QAǦ)q%?0Ңx$ՆQaXpun7OrT`PN^sW%tgeԆNH9 ڡ3䞤wNm2~[ +9yVk0naO#!nd1JF.kOP("#q)oC'}$grj#62#d]r1jΫqzڷbgFG8&v 偬仛?otȊNo65sJ<]v$:yGV\`%bcKSU>%dzJrZZW<(<9c=*r-WwQF$OH4^/K{i~CgϧZ,} X+ZQM##ɦJZ%&7rWEkqR@?B~[A+v:[XC @8f~QsTٴ#e;H9NzЄ@;:`|^d}%x?6uX5Oъlz 04`1X$ 8(PkUѬNv__GprӜn;ٱ SյK{eǁRr}Jzv[aIA{yԍ=pjمeo؏Rh G;+g!E}Ł+x{+v6VqUcpsއjZ͌uZWвn;[9{w/SPjjٴ=kBDlӿzuQ Rһ/luR'|H,F}k([u}QK|!\29]<ֵ}FHeg_] G3BGKe¢\#<޺dd#_:2*$۰e52ࣩRΎgPy$Zdmq/#+:lE?g[/znpt'e`W.[ L1 .$SRq{#iIPr6pK#9.=wy;X"-g;TɄ]x;MwIt<76H́StbѸ<4nlJU( C`1|;p 4sX8ȱlg7=hĽ`lkQqp|!H{)2Y7C2p{0'r*9Е q.R8,j 0VmlkX2py'rc$cvzz0'wpk?v#V ^BjrD260 KIR+~=j+H̥IvfmxBx@GJM֚J:YOcիv9 diMxNiĭ3I8LH6CҍŢK+ *`ev =6u gZЍ\H 9P, W =Bba=G5QԴ:׵a~VLZ)2Tp(|g؃N:дG։38_ϱ\r|& %#C׮*@8 5:0]©8^0;Ԥa=q;e8 dzuȯ#y=2p&TG_J5MWZyi߁WR:#ky#%)K7%𙡁5;Ff]ԏʨRڿ_1a=+ :j$=6i b [Tou q]p2ԋ|֠Dn̨IFy6w6oq(`q8H-aU;YKeA\ mP״IM<VR\vTqT\P۱\x~Ė"%vN0XעtfRuxAP@=ZAkEiE4mϡ-t{[%b0/(}?E8 %Yr1jtc̮YҼ- AHh>;eWrn UryԮwts]i*AK9?㿭u-Cq\gV_i2_a}7+̫fU_9W9>{gg*F>c?1U 39Ù,yv/vqQ^}(֋ Isvy8Rm+3:[4:f&r i:ZPswn 1OS%QjU)'dʞ/[hVj6{ld-Dlzg(PîJSpvzTO1A^W$1î;ܮ5*=H-U}rI#e}@mΌjV׫zT޿n+vpKS:ڴZ[|i]ZDHd8E}_"ղık!SMEAY w!$1_18?xWm_/?l X[ 㤂AUS?}O ;R8:O$VVqdVfۓ}( hCρqIrvRec1Sο+YC#J@=Np N. #9RIWDI*y;JjjdS豳inǵgŪ$F=%2Fjq+B1nF 1Jȹgtmbk< [)k3\Z1VYIGtҸd%qe2f'Hf5dhqWOE4O-3+1VU: 1Ǯ+7?( ׌VjֹwЮڑw|vwsz Jp+DǯId{|˜1OΚ`3ֲ̫^#,AV+r_.@I~i?QJdѫ]gANSmZN ҉x*A|1Wn},d~x>9G'K`ZHYTjxCa'x-_() LS*rn8d1|0M~JGjϵ?N>˨i"F+wo8oYO>ljxWKA$2y\1E`+yy'F[0c;?E5B-KEဨcϰݦvI:ְ/i;x)_% w4'^pXV|u!0{q=N=khVQ75gru!32z(*My}qjvPۡm. g)/ecwO,&sk5(a2[%v}2R:Hp V+r{^dܭW5׹*Ť!@Fr"M|zVv]K{x=qWma `YTkԮ3Cާ#]{״|EØ:!G8Jmչb'jzmNӮ$vX}MZxm i}<ϔ')9`Dds#XyHYd]kk,XV lRJRiY =NBg M9dP[ŵYw!Ts"{o7>0ڨIOTych9%oM,v AV'$`NsZ,vsq؁sPN xT.9G,T/$ԗ ;O?P+h=>mY[m.8O#@rgJwסN=-ŦVMčuz!9@L}` -4K9d@e#>51|̿$oC #Ҧ"i]]\W^oܞ*%H;%)2c(1NJVApB nVԣa?ZK9[?3|`Cs5B}юIއ&.bGe9.jQds2[;dUK`Kg֓Z\)Orgj b1H֚08ca;+=+iV܊}ªCa)=HK; ˁ#%]2D"R֪K6ĻBSRotY GB* zZB&[=y4hK8ղ) I9 j6`wUԭqo;қ4`ǸF8QmQ9犆ԣ`MٛʲnoFIf˂O5i%y;1p:i; (V Eec9ف}J*CFS#8=*.KF3٤bz 2PIzԻ7JT8~ <¢zJ{^mwڠhw5ݙ_2&p3EurȮYZQu#͍/#6a{0Mw sɩ%0} p}*q œovecq=*<99X,]ࢶPz%̬a$кC+p_c)]A;On'fQ㍳.W$ fL[E"8kXOw$ʙE`ْm)1WWI\uRQn<Ζ2O@׊jSԭӀ݌(BQF>?o={ ~gn'˩1zST``zIcmsqH-Qծ# WiϮ!R9zPF tR{0aϫf>kʣ nvv)jֈp I`ՇD8R9O 8uZ"$u#nҞȕjoI؉,iJ4}q a&%{#sږ3w/n%_F#ǶwQj]BP"!71$aҽ\EgVjIi8bffY|1d"DHJ(8 kI ҸqTf>x7u Tr29l 15%;<煍lzQ]QNHg>Z]XF|UضbIs[zWk-M{fRJ$r=9biNaj[`a5f0݅-Yi:LtP\FXi3Mkv[7I0>?ZNvI54bYCav/_8+U_ ˉX?5iKI&Z>~Q \}F?*E434!3  :JsEQ$;H/"dFhl;{X환V$v*arHfREK1'}HiK[;qqi[{Vv61p'֭Zxd\ `Ce"+=GZ7W]:#7},d:޵-mOUiFHWKvi?†N [ no dlkwjv)<cix&VNOŒHDQl'ʧi-RO-̿&p="QBNi:nza,D<8Ey ȵTޑ!\zfL--f\Zy6^PMe*CR; nTdXϭ ZmhMKv`$::qIkuq߻w<}*UX.7vwm nNYp :|#TdW^aՐRdz{T3 *v5%sudyho~#R;i|]t%jR91Pѫb2W*HzUA^#Q-hiSk7qR#kIȿfӡ-[*>?0k)Hg\C]z[k i&C`cOd|ܳ:@I#ڝo xϘ #kgҩM [dP,x4Yߣ7RN޺Yn ̋zbtQH'<ȫl$A,p1m1G ݈*B|p@ &L;k9;hTǽI\qg]+}u/?U!.b^%'peYب HCr1vAI΍R?6 gְ ;9U4`F&K%g~tdƌQv= 1`z]mXy4d)^G/s/#PTx>p"nm'=kAʳ]J&uK^o,MF>UAmJIyHrQ^P.yپ0NdM}'"j _E\0Ck=u)lK.SXrNAk Ѯ9ҕNA+a` S@8ldzSRكo`-H9POi0HV89=; 0UAbrzf5bQ҄x[O 6sO N݉!9!|5jyzgʆĞ W"na9QIeVɟR6y^XH?~H}3w<ڞ[-زFtbA/~1-EMkuH=ѿi\Ja7꼟mCO -ͰH-wrTcg`wU9$:ٖiG`-Εr"xu-LA;7#ʞ o7G$!,d Q,3lTrk:-,֥e!wzRJ7GQ^յy7cbkCFRh³\58PS?C%d7^+O?gYBf~ Qa>KmZD'Uq:` ~twJ6 OS) f(֎aR(q,8b0u5}Q2wL=mtfyS  ?^,ݣybذf8]s㋹vb1Ul]%ҨQM7`ԭc٫x ~%$?٠Eɏ5~6ϩ ?5]SU8-s QE6v7n;dٺrFp+BP@Ix211 }kǏ|=kuѣi!؂Aʓ_8g\1%GWp[XD.Y/+F >OS?bX[DP `wW}\$ r;+Rޛch`''3gZ46C}޹r,`ܤ+JCQ/JXJ<Ϝ? c 1ֽ5G& 9n<Zbƃd4nhbTV%b*e$dboF;J `F{Ք}Um:ġ6YXqM#F6M] KdF cMu6YI9l56Ҹ?1ߌ pEe :P7aBqU3h|1sަ G#CG{bW3GQmi2Gn)G6w4e˩k1ݒ6w֜]%df±KsEgO~KN0{f$[ɗu8%GtXUn4Pw#YbȈ/,2Rƻ'bnIryOSD`ٮiJF:gq]|$2ç'q)yT(*^gp nIնe;*Ȥ|ӨPz&ַ8EsB0N?KS)E-JHU/ǜs -=:ATˢ*RXLFҙ:ss^Zˇ*Gv;I IhBSDMnj Qq%qBuO4E#=RsҚ$O|zT`Vٟ5 6qZdB`G$S vUB+Υ;[3׊~'-s&#mw(!{hUgPa$=E1addkߝSKb [kY;?g%x֚? a*MG:a73?/nWKWm*ϭs7إҽ#NZgM`@ ӳv;ud)~ /SOZ8M>M}*1Dcx9.Wc||,mc5}b4#†'̜ &:ma_JUY6}X$w7jbtAǽiݞ@jӓSz~G>Rpei ǰOCOJ+ԭڕqOc_߱ "':WE CB)$k|?';;#{ѻ'ǽsӺLpC4l'A 3‡cv8Eh\QǬרK:$2ÏlEZ}$Z.yp8d<βhvw{6$RjW#K@< |Tʑb}?BKkɮB8d1ܙuNZJvSHҰGYፗ#[-zNV )ud`>`~_njcT]3Jio$# ?o.Oo \iTH@NIrxhG2M$qo6;,aKZX]1qĒ0,e} j7EiM#vn!alqJGk0|+7BR89\ך-TbKvokCPfHXnT5:m=:\0,逭çOJshOW.5R=a9 35vaDbXLp|o+YZ[o漚9`&0$_^zU/R8ʾ,՗Aݼ e*'wrA+o7VmuM{˖n^5BN#I#$oʥV5?O~&yR +L֮D"|? $Ia2z/7k6j{qfHȎ5O֫jQ3:4p1GOKR@ J#keQٗpV}M\caZUrgy?> k@%Aך%+ =,gxI܂Emxw!.{5c,Ern:%+3<GzKOhGv)KV2+,Rs%7D1dd=9WB6q496ZfVl:LZUbRk{IX- aBΉzqH&eXpT)9TJ!+e,'#W~cNRY;qUVA湌4BEyb1Ԑ5ߐ#`ӚX7W%v)J1؄`kr/q aYjȡ |8~zX08#csc$s2i pUP}н~Sɔ`oJw!AmOϞ(r6SǒpTr B T)"Jp*!ZD,P6(E dds89 N>$yX!wt"sRA=Oz/!}1 vO7qY2F3`=Q].S:-B op; 71(&Fd,/GvʐBzq%B ~ F;i>lGҚ``T.n$<&H5UقD2񱓐85i cjZO sU*Tv_fWKg y9mgsfѦƇ''%c=Gz˙ֲ?ጛFoNZ֬fM*?qsY^li_Pi `7ZG$C d5s渍j6}4R `+¤CzLG^ +8ٚrAduN3G-NЦW_=>;=Gr:8><{n1[5bdw=+KWpSڹ=oZx[ Q]Z^\Uω^^L{J~F`9bzٯkKs)bP"IK,NcK%6S$ds+t)h.c`?YW?RWk_]cS&Y ㍤)YH? tܨ3҈Ojt;1Evڿ(쏱Ln|myDs u  h$D+~@Ď54;c8a{QVjlv65P6CJZ#*Bj))9b2s_#98 B|Wx e3* _zZ?W Z.,4˩^3R`~>iR{Fvi<:Rhf?-IR&@ulbIm+M?׺7;wXy{eCyE(wulnR;7yI?; ©_hvڞ^xa|wډZ¾{k(6S!K~a玕iwIZM0AY~FfT} 9@p` z?&ZOqs$w/Lw=z իCM.7i ua,\ ?tYf ZsҲ[QZňB u|ێ|6}J{$$8 ^xi=umQ&在F4hclf_)cm G#~O[9sF$z[]AV%{cV1hX՚J̺qg NIIq5|.A %Uhwy嘎NJszʙ-وm-ޤDs,ykUͤ*oS#u4{6EO5m,Mʝѣfnjvz];S,zRX _᩼͸/tD5[eBG)gW͚x$J*/3 >>|mdʟj4i L-U#m G(gԢ>W#`-{V`:}k+XV" l#ڮg\ε4}7eϫK,a˖Q4D7}1\ ڲ 8GzWWCw |&$*Ze0'*zڂQzwnS-FT=.VVI(έ sK뎢FA|j7ffS)^#+*/-Ndo1QiinhUmHOe< sU[$fNe.օ#=XtIo#% vM]),C'!qK4D])lTF^8؆KKU5W1DV<9U{VGr*8hs!hm6kb!AQĿ!W# Ѷ!GhǴsg[,/ET[r%T>Z zjm,9i `#A3m $&ֳxɷr g* $Ek{r@:B+Iܫ$WHF,O^^r#V 0} Q-ݔ^mTS,\(GSZ@bUq+tRRNzDHtrG"PI*OsҦ*$[\OWr(#mX"r$p{ics޵K\̎{8!pCIIi0Ϙґ݀rW-2+ʡ RWOJFPNykO)\ɫɕg\`zJ0p48YϮ9& `MWdT5ПoC8K Odk[C`Iwt`˒ꦚ;#V|-Iz^`txI@}BCj+-ެ,譎FҢ~ֿ̈́Ju >jΚFH}(Y߅rlRH1.6ϦrWc Oڹvmot~Fy>ޔUIu9N3;)7rgԬC? `[VG;  (xrGG_FucFT`u/ yˋj)E $FO YK=찫"m#ڮ]9{55i~!x7K+HuY0?Jy/-T;o_^:~sk¥?tk եi&ᕤ#,|ZOA5O<ߎ k"i6~Ԁy|};:F!9k+W.[lAxdP֬GGZx7p=U<>T jvmNJ`iH8 ͚vĚ偱'_.,;4OmcfmL+1`sn>(#+KKF@'cV#l.@\f4ue70i z~Èdž~槁ΐ HfSZmOo2!k^n8T]y?X$KTVX[AAjcqpFW#s1˺4۬ [Eg]jL'8d19xqЃ4Jq bH>n22=\0[)G!#1v4AH#ovhıS'8ҩiv,DL^Tk fGnm73z_[h4*g܋.xRߍY/#?nXc *''uj 6ǜ|́{ Vl,o"W鐭SI8*MzuvEA!^;w`ʪxMnXY\ś8+7qKI"_:UJcg0PXq9>U[_\ڽ}4QF@ ;Ҕ^^Tm{yys^KDb`LI,DžzYܚZ]]Ο,&iu%U8;y5+m6]\#iV== e;J YR+ c2 p~5xz\_6D, Qtl ڥĖ2`IU(y$vtw$(D6 `n㿽Bmn:5'UK6s+/{kN q&?l Y`Fj*]JtSSISLRۙe)#;Z(GJNAY͟XWouG%W Pؔ$+:z9ccr:@>i Zhy8H:;Csh%DZV<@^La#󨋶KRx},> Vwgilʛ{ÑTuqM asOd soepK Lk-negk+/$l2!TLkݘe=Q:WK;ZLE>zq^{MdGdc/*{}knǣ qwܥ}5([.=At j䫮H 22t.r&vU NsUS>thXaU@C\]YІkI*`-ŬH dZ:l0IbsۊqnBha!TdqdCi ppWIDmMRLH1ˑsYpYKN᜝̇TV-ͷ@)+vnZx#S4idj$N8ag?Z WTSy%7O]<.:1S젍rqҽ 4<付Z"2cfʹ#Y{ȨhvBGf%sc'-QH>v&+jޤ)ه;v)A{M+EmzZ`W]WZh#I&1jzsl|9QwkV-f&9 PȻ /2̓Gp`m>4B :RLϖy$.w%qnr٘9$t=~MaܣhQ9&ӻЁ& ,Ȩ/؞GoJhꪙazU)a IJu$w5ǥ X3銡8G\73~s+WiUveǥCu~iӚ՘`Vuh;;f;TsG\ck ?fzyĘJrd~h6}O@ԮImƠ=KCvxz|pR(yk3P;hQBWZm>umErF}<4C<ך~ry\[ʺ ?ZPH>5;;1N0>I?SQ}gЪUֿ){ZuqQ\0j~nGkU j;f&(@CARH8\qXYh XsUme C?+Dn|cͿ]GImlמ/i$z_*nWPLL zvme5ψytV@:j2e[@WYQumL*|So ԟ܆?]cx\i,C// VO:b!m,HXpUp >u{ȸ^vҴs[}Veˠ2S5<¼>t#-,tng m% 3mH)97'1QJ!jI8bGq JvZy ls^m OTeY٣/,I};zZcZ\ ' #t!X~$>swkWIu 8Hћ =ϵ_t?^K%-`c|8Q^~zS<ujVz,^DM9vw#R8qFˋN5u)k;GWȆ9戫bqGq"^g6`N%iV;va#xV^v3s= rImB˪SʪY1=j KobzN>Ymo <ֲQؘԒ=:84ieS*:zׇJ4ɢi1m'#ZjwdXv1ԋI޲)(Ր xM_E5[&.mާ2۞Gmt3WіKS;:'8VnFjzŦZ0<0LBzrkI+*wHBOiaCi"skvko:p;ѷ|;)[iݒIIu)cq. Kh|~XFm&Pd.[@1wkzB՜W:5[TTUxBAzՋ&*L#FocfHoRvWYxJxS9S vD͊jnm)v@27Upsf.Yl}!p.;cRY13$AÁ`l>=&, - mC a䏼=jϦ>?%uzF^$qDWkfXkPIB!Q^4cTg-Acz}yI)$ОG̺NS5Yy0TVJnqVa1BfyeEV.2Nk=Lj!cf Yh>bg4ZJ5Itt >6ՔѾ$"r3ҲmnX)O%,rS N&;1(1ϰvœ@1㚯*TvD7Krp:\5*p3݅;|w &9ߣ" 2*b\dRY $KP>L䟮(Z4֝FR= Ex<7ZS蟑\lTnێLW7",x*OAOa:fse«ʊv֦]ʅg|1.Qcr{ZmlԂh<$ zR A4E`z-}*C,??Dfh,#A#2;qHTﰥnI'vB*SJNr:jgkSpNAϿGpI}I8ӺE{w%I31U}4wV?#D ޟ0ھA0*;+u-0qJfM1ҫ: K˂ GֱUbֳ8;X'vXՇHU>(S9Uzﭧ 7CQڹ;"M1>lx5[B0NDUЛ{ uNKgJ)ޙS*mڔ9r#{Vtt?o_n3avh0y52/X;Q:p`g#[)t@4}T٭JSrў?'bԭzRGa_[KZ+ҸoɈ4i9K? Gkp1zԥH^1YT\hQwH`:_tT1RV.r+V?_֙[e@Od`s\Y ȶ3K!CNkQmQ2T\aTu+cnGUD3;mhΧ<2̻pD=2M;JާoƖinDp9G{3u^R5Ǚ +z(|1{'"ȫ=^]>|.,Ίe :<(ҟ7Nj1O֫j)[^@I>}sVA#ֿ*Nn=q4UIz0MKwwW\\6B3+[ƥu`R zTI䞲Ine 6D8Ӣ!p;WJpnϋo0-%dGoW\Jw9T|xNws n"uPWޒ O1g(@.?1Uv֐Y ėhUI>iwmx3޽ִVr2SVm:o"B G$yz+Y"?HeAg׃Z)_sW?Ͷ".imEgm4Kk׸6B<[6BU)r=? mhL۷GUoqk2ķZ[K;̌6JJɅQ4CzVH&s\0,@R&/v\! |{Q^3Nƙa4_kf4yldAmc-nNG@*:M[H5}=m Ȏy)IW_:춖>}^R.*ǨU%6MfxmI>R3c~ƲO*Gd #$N?Z.=ٻZOҭhTdg{ ,#6\{SO*pbkmB4*rCn;g5[[M =h%nƬ֥&)_V^/ӣ%Ԃ0ɐ/3ʰKa]TE?>Iv6>%eM5 pkBXULc VtUH|rp=?BjƢ[|$?wֱ푡I!n Vs:] s3RZt//\n=*uȎwv;>C9PChpdcLI?*5A iV8VN>=+3[ڕܫpZ3ҍSr2/2yǷRwr3D36#)[A/O$F%G'5Y3E4A~^yQ7`Q=0{mbYL킲8t6}zMݳ=cTފ (Uv^$߉ҒX}׉!+xQMK*F1E!#`Iw9Uq<|٦rAT; wϵ۽r+rPlޖȈq=hv[ ۙs8#Gt{t#8=jS.RXҜз5 ́գaVH:g Y)b}3ޥ [ٌi >| FW{e1OO{Iy>՟zJOm+cXWssZ)Rb}Q2T8根c"tRnwjij>k"b8K"epr7}GK.@CUAZZĵdUv8Riz^n(ɫVd]̓9 u:T .`\xZ` ` 3D]4@ɬYN 泖Եsp1 8{3y+3!b;,o۞O&u#X\bmJgwf^gV(2JTИ9q:^)8')q2`}jh!J6?OE"cn jA;ݝIG8Avؕ`"MIՙa%xi2x9b+kq$^@hizЬ'sKG5K쏮@/pkԪ5ە bpbi}*ؒG27 k*ӒR~bd㹮K:&kx~EIP3UcQ'85`_5{VJypi;t"dpٖ |F+t{R|P$WO\g 0;N3=씎c?گ95ixt`>'}q,*&F ykzʿ:" %[4A@ o)xLV el3N:ڦRts.夜,HhC*B3u` ERs:W嘦W~IF݇0=[988 1ebU+ - lhhɶ2$J;V2CdiKk#큀9C rN+E} ]FK@5gU,G'?|&EnkeIsfaBz՝)F4.OT9G7FCg/9MH ]$ٹW8f?V9!ԢbA?雌g٭q0sXSX,v G!Jۦq5jWWc %,ddk9RF='F,4$j- !?j&KK&"e0@6Arq&y ܆O$B38u5 ]S|SjQ[n$)2uOJd>NIwr9HcHw;t]Kr>߰YYg勳?g{:d/q+B)]hW+A2@۵)̇"59*3]RMwZC`ZxdrFT+ Տ$&DZ9l?*|m5yV9mJ@Sӛs7oDĩ0FztrϫxhJ̐l}Fer!C~ޮ<γڌ:^ ]I1m|I!kraL7IHrY]tԳs´0*; ~xn >͸i\3A隷f$CQL%E {Jd#TGV.m3"Ҋ}7$c),pf3Z;IObo ,rc ի{f<_(qZnwW lXs*O/Dg-hP}ҵ`FqIyiA]|*tͪC|xdd159Y$yp?})wIbt7).ѩB5d8݊oR "DH8hVe7/]jwcIE];R+c;1iAo* 9w+-Ģm3_eQ`)"5%vl.m~lp$h$iahaUrr94&Y9r+{.h`0xR78$=WsVEͷcޣm>&/sS5mMfNbBuǽ-H=?JwUXTFNG>E 38m i?G<UCۻ nɳ+28E=Fjc:* r*+NYQi6;J:X[s*Cv*4X ݍ5asb 2ک JHt[C;" b\LP.=Jz$1AQojJ bXu"&F8})=G֖ͥZ!DVM?JգR\?=zuYN3Ӿ˧VxH䟯F/'xRVeyN;U; ~f4 [ۉ`?/ZΜHdj܇+!A~餸Uw;H [тJl8eB@!߀ICnTzNLQ#=6lVVfr )\FpOZ!Ɲ7kR; i'`DtMY6VWsQ,FN{fm?R#:9\ o{ٓIB` +2GϽ8 #r5]UGNj@ }DQA۞S;H#=?ԮI4l~^GmbÞɮ'V“0~;V{ sͤ>XboqN"_4)c'+'~U1Ob\"#J^I\*?gG=GJ5QKK W s+󷇂'D|84|Áכvw<㵆;;& -l\<2dV QUW0աiRcJm-m5)5ǀ>q+x֗73 HR}qںkxY>{GR*υlnNKHCn'an2jfaf(gA^F=kl c#Jbw~t f=`CRlP8}ki^yzppH=kKc(jiOC+2 g!9)e: Zl'Xdfc~?UJG CQRpGzJ+ĺ0t?7N($2Y8ӎjokK@|r)(C:21ڰIsJ\Y8V dv~+%d,Zz(95)_VsM35:Yl5;H#"$قZ<-5 6wGHB&nq5 +I&-u2NqA5hT5lT+˒}*D4&&E%WKpHQ AGjhWKk4wۗf)N3Jn.6|P$ ĜUoGr˞puQ'9z- #j f%p>@ԣ'I̡2z1ҪHsG,0#?s3Qi."g&B'Ӛ*M9# _ųjӲ"h"XNw1Lk}ME,y-+ pKf]zR{I7'T;K,7[X ۀ2}Xο+V7c> FM[]hq%{]9⾂χ'ZiZEHɌ=ɯKEϙ[1R7㚦R+[gc 9m+g9cLlgbN@;Ew?ZXqy]*a%IpIoC5˒M\r;fr0 'kmȏEBүO]Wl\zZgC[8N Uk :!tҶ `rq,-w~!Đ?\]jVaQ!v}r=sEMWVLomqbsy qI]jϡ#F;cF$hcQ_3DlB|OLSB&Թl]xR(K'tV=5ϱ53fMK "/t<+ʢΟ,0|1>RUɖ $оAoak,"ZO1!ZQVTٶ"|hO:%-Tc OXꚞFYdf,NϠlD:.X%c|5] F}xb+$A:# aF_;>fumr{m ,6YghBD}Һۋ> WBH0vdp+z+2+K{`VxAio8>d=sY~uw5]ɕ]PddQt%+Gj:<B[I$ w=xaנx1v&hnn."'sʠVѽ3ok o⻻ 'm#T}*yLڂVĮs\M?.T'{3[PբӋ$H|T|URS%չc sܚGqzMJ!='l<V`@Y'@x*d:-y7#taR%1)ݏ^*jؚqPAhqcZin1pۋ8ǥ,2ӶO˃] 7)ʑ0݂95MO7TZ[l5YtO)W aVoD+6W$VۀGz 遏ZiY l5{[\c9fucq\=ki$z鴍;Q>V܂Hyp-ij^C-6Np+;١<`wlTo󧈥K`:dw1LApwh3I^A7ap{!b|G|YH>֫0.!k& 9nG/!L^# $ UΣ9?}\A0e;5}kt [Ȋv',~sÖ fܵ6s$\P w6I!Cm¨6--j=5"㹰QmP|F|[ZNۣ=GbkJ[l#MZG_ibwJ>IUc=h/1̈RZњv97~*@t=h|ש"6^G6Zbb;~$x*XfGCJ:ꇲԻ.+t {C ޜj^@:m-p1QJIN{q~F>6񍟁9ur<*D29k~*T}^:\X[ȡUc R*VfZuOe,V&%r;p1ہ])q<e{V8%fNw8/–o܊N\snɆQ#ھ%hz-^ N*eЧ>Zڰ&HZII)uWs4i-xg֡i"DWʢ; fIF1pϨi6)NSQas3-a!&q*e|{Eo{lQ̏ Z i[PjJ筣?j5f6x#/[keؗzs"{|9z4k:?Avsoi]Ĭ T?t]4Askcp^s+z.ͣE@%-ѫE ^E6D5ؚ(\ĹQ۟ʵz+ߍu3+y0Fs_~+~*=p\¦@I#!H59s"uX ̦-<HWxYtA⹫>[X>1iL5&rQ]ừJ;k}&#{/|Cm {o|Ys&yǏD[68OzoM ֏vҬJR$<XݮiXp!ŦrOs<H8OGj\Z&m$&7p R.{I-|-i̓tv9ZZ+3y$:IN1KZEiy;Ccz;tW6w$8gϺkL1=R4M fimV<_efWݲ?žHN-CN(JA9#M޴n>k2V2C=Îy./fc+N;> $;R_&'oi)]RII2yQ`O{TSy%0w_I;7q:ݖ`$qN)d(9FK*Skxu/j,11tc*If[^k*O G ;%`!#)bz M Oz-^:$.2QtHpL=ď#=O;HRH9=+{X[4ƬII?"]'};PՆ'H>jlGL --4!Ia8l1+)^Òұv7 ʞfȹSȭ1Ve#rE6|ЎQC |9;XN7zҺ\ Y[)AP4$$CZ <;r͓fj+-32F;pVbIq/9="3t: S$bW>ih"<{T06qϥ} .)@FnH"Д 8S.1r+?$kN Q&J5x멗9#&r䕚=;pngx㬫$%1޹ إn|~[a'R3+sڻ)^ R8|T+&}2Vw*y9ڢԮkoPqG8-ӹ5z Eҧ7fЧpOJ=+>ysJTv,˓iKMB=; :AN*mwuiC;៌>*cM֘+ak0ENb۩ҡkk]نt 9p6zgyʱt/&9N㯠49^ ۱Vm',L3ةIt?jo<ҽJtQp:ZrfUSg٤Hu q:qֿ$}4 xYcYm̷+ (I\g5ŚfQlo>ܡN*kNz/x>oix fu+q[prXG| +L?69-H،8$c32N$7CQ,\ŭs<~fH_Ȧ2`#w(;ђh+,w$LrsuVhcgpzmݫt2uw@qՈzKGv$|h*L|+Z w٘'&<+^jKe=<,'tcߎ>o~pd۴e~=+<#lKG̸Y#xsM-OO6[A,nm|Sf"/ x\[\I{RZFO#\x*)TEͶq!G}rG_3T00]6Nfٕ:?<_:xR ^UxY&1s^md6ME^@sl.VvWPAs׊ [3]\h <+gU(^'N)a7/$f_fe+99oV[sZ)szm<%d,㹹KHSm#I}+IǺEƧ6:mj6m!VI'#Rpn)zmo5DRģayd+j W/`P)K>B6Oں[|A~C/&S{{k2f^w*zS7BiAZgR0UWO@jª5 @QҾ-m\=J;qW]!{iIOmogDAL"'$p3Q%)+ɯsYCÂYUq WSƎ>rQ1SJK0T!C񤷒[kW'%s1W*.ᤴIywEGi| Ś.p+n8iHH B* sxO7iwpn*=?{ӚB.y6(WybRXs*,#UhЙ^Nyni8,F3%n۝An Ib[X؉ ]#2`[k"dKw?U4Ϊ9lUԗdXC$v 6ul vD1D9vOj$b%!3RWҴ:`䑂+-dkGCC{^1ul08+s]XޠF&B#ջgcCYE&hhq8bsֺ*N zJN;Rьu~v_nsq\Wj/ݶ|c"I +7Dp\>8 {R'{ͣ u gN3ϵBdSIي upԦSql\[GS8=ҰI.>3 uY#D;:i9!U_B@ #o1bpF# W0PgJwȪ!7fxX}q^nm~ EcqU/?"-.AVT?q}8YKm2 yotv7b9<)]р'*}m%t NyڞqJ瓺5z w9I`5aػ8(^g͟`FTCr̠$sHIR>[ ]x(x9d`Iqf^i6C,_mjے C 7?F߅>^y2Kˉ 18 9'?r:0Q;IN8 ־01K, ^uBU#M ʞGjZ=$aҢƴeucUs Q[ZXIl,c煸 yMf㦥WW}N"݃oAeĖ/67)qҎL5c夙Xo-[ Yxn 5|& <چ<c;TEvhymi|5v.ޠ;Ǻބ-']A"U u+ k[OV:g ] јqf^$đ!df O~3wXOKO)DUGp9`:fc^1$(X'ˡMsjz\_eՅx/!z/jF@eO7Ğk\q+|bڽO`L6 aV,y z3] :FBA\ d }9:Պcgcc9I >Z؊1̌Y j;6ݚWgw5,itIoA3e,,&3RGnjv4TtbGJB1ӊJBR=WoԻ9vWx~ =WRx@,>".YϱhDz̼2H=HG-v6j cBDl򯍜9=zJ DuOTL):V KvgpB30Rj=8'R)Fq1IK HOzw8"E,S ) k{,N;ˆTQ-+\6VM0TYI>Ԝz lI$w 뀌pOKq#?Έ;NKUH"B 4 u?4B<]W<.Vmݐa $@8b=@DYc$Cc&ՑQՙa ar vml7I8}N̵y0q`/$t*"Y7LBW?*-(EO9?S%`sǠtgZ\wĨ`qY/|J7]4A'HbPۇ]٪^3MoxśiE_Fi$3n6; ޵pC}=dwxUL_Z.f3Ct 6ʺ@ ZEf S=Y]P8f<"$,%}n٩mC.!= \1rXi-5?ɠ(0(^qU[60;wV9e PqI/pj^%VPA* &(hp'_1H0IqXFyXs7nҳ\EkWVE?jş$B0)v#5+3 T6ub^Z[Ȕ)b:sdNzSv"Fv 6'RSnd> 8N階] dlՙz+1O5BRKps>P98"& q*ZIhR"<3Zzeߊ皹OA'& zCzQ o )FXjQrj!ғc|GXbƼMyF@swVN^_#c:FHȌ2+b\?資*2s++=Պ,A0Rgjg N\˙1T8?=r1ڳzjظ9֜ gчЪ)OcJd= 2Xr=*-I ֔GG5Xu5mt )^n0F#|⪜2 \#]nR˃ߑK—~#:tvKW#+WV_{_ĎX:û<978N'i\X_hu)a)&[xkָ-׵N9r{z*O~2js|o1Y[dH?zkgjR u휚U"KA.~pچk-Hb݆}+ c}mopFyzSg˲e pOjXO hLmj\7hN=kдbl;翵Z *l!#+I-1{g_Ā>fK)x#CdUY9juN-4[[…MO'ۻXG5|Ȅ<2f #}k/7R[M0zv'xISZz4$prWa:bYuʿ3\j s^YF`@Gq]'<;g{iQ6#2raj;WsEMoige~ eW0%,$]ÑtU*/]mjIOۚO2Im޼w⽏x޹Om$VHw8F3EJ|iTEyn\[;ۂv2;?}koR'[ ++w%T?[?uY2*|XPqqTm⸅HݔG-Mn[kwo#s\'S7-x)DьsH-K3[<23Wm5?.louHEnFXn w74<=$:i~D~aun7䴉/vk'^m/Mty9{#׋Jޯkѧh8CFD!I$mR ƼϚܱ+=. /($b!nm LO~Ҝ}sI?Q]q$*Շo#K:zz3͒*\J,'ԛ BPVV%)mvQkRmeD04bDF`8U73󔷖9Šy] zvɫFYqS_..`6}AZH]!]<壹"YXhԒxŰ;@/CyqjcR"*#'Hu},;%f{>rCIEF ou$@u`z漪TxeIٛz.7w:vf8`y$v;oR'f v-?گGT/'jq9Ϧ*[n̴Ԩ1ià'}8ScPޥ5ppzHjd-cÚSXow wWbfs|=IaJ0#I]cz]Gumm)du3J1ZU9)S u:+LKaA1$neU#s^}OzW;.Xvrx-';drqUu_ i40SʃgW<"<ʘ:ͥ=h- R ø[^:iA\Ijz~*C֭gq S:K2:r}ju8kjVgӒBo1iHQMAVOQw@>*hQq@5QZTa;sأ)taU1 x4蘫.st=2ى Yhz5+d`Iƒc# V9D(FcmdzkLxymcU->=Sš޿2r֡E2+Oھ޳"7J8"+A,qV]d\_5]bh|]&A럭lh"6W"T}H5ˡjPa[<\NIOdjfֶ;?^^ǝ8MGgYgE X[,Rheˤ]VVO׎\i1;K,EuY%uWBN; ;{_V+{4eD?Z ށ]BYx%lg5PD7lyL-JHJxҢ׈t+r uC;A{ViL5ReQ ( {wċE 6P8?\) LZM_Zy{X~]<֯KI,p$dQU@Ƹ)uD Yi|Z_*5 F$.=bOҫ׷[8CEj\J1ms FvAuH_mӊǷZd8 NBF=py=SnZN ^K *%`Qostء"d.2q>݅UiXDl?ڲCy2GAȭOk(G%2N}Ij"45s+3ŸsGJIa+6XWS*-~[6_L{}j ?PI4-dGydRmUSOЊ9heT|KMe_?N_Œͧ6SF|“,L.*@{ko7+ŨBrB#}M7}—{Tr˱(nFX()c^=V})ܲ3z|iᬗZϪXMU Ҿ7 MרVq(KylEW6dt rl{g59>\ ˞I\UWshvBcI/C/SY@o(z#9\*sA-$V2]ʱFTH#F;WsvgkSѭ.tgj-iF NI5Vnf"Kp@ 2ӵgM-8 z;3EƟCs,*IbݳSnmfcrp3Sr: $Q0]a#5n"̂S.9>cεeo]D{L2g5-FKyNа!)JM.xIt{bhR13 mXv, ]jg=y1c8>;)t?KV|wO>֙AXkKi]WqNT f=*&PЯv.WpƱ|K]UT/7+ylj,z|J`:fxbWޛΪ);x̬\QU6Aj8>]/6z{+;23CҴdJ*b ;Z/B2%}\CQFpi݁Hw@zr``nҽ~c*/3ː3 ikB܆+JpH:t".I HT28j6'%QLbWDs-HF2|׶-^IUh;RZ$LUnqBr'1/mtxZ>Y֓E+y$۸V j( ˦P28'-x y՛GUM5+HY*\ʶ|%)4kYۇSWBQc.V=J$W,4rGB `9~ΣcþhrAP \t6NЩҜafg֡rI9#S|zQAlg#g==wӃY%`tG\c3JIš#pʖ#jX^mbH*z_BJU/Sct5h cX83 #wjkqsnʥ3WRJS;uֿF*<sK_4๶nB( v݉N5T#*TlUM 3̤]l>f9\9J7yq44}(V[B"IpcmzqiKnfc.Woe<]K +g_E²IFu?-47Q22cVJs5ȴJVn0P-T$`}zΖ"v1VE t*59_\i J9ntkDW.(uѷEX-CHgb<~#޷:ҫ۽縥Ji-Qaw#yuK\NTñӮey^#"e#$Ϫ닗m&4<7j:3,K6jDFY!L;07/>J3i2rp| ^iR]ZpU~3_-j oM-Oq+Hھ |:S̯K$mr=]}(vkutB?u.ҾeGc>ح E[:?Cu<כBWzx54{;[LgR Xç99 ƉY&>9*?*k~efVnay.6ޘQi:%I-QY>EE'(ZEjI+ pzIt}"KW"p?*NR<ֹ,#7)NGO}[Xh$wc4=ұNc,TQ@\Ch{{;I2* +KR ǩO򮚐rj*-M]:s'{b9"0QHZs &L1YZք7ϖʂ=ZZ[$УQ#?j__ɢ ;m)_~Ugic 5msV'+X͋rB[n;sU>&F:zoȵm 1~Ya2%RpIm}i9-qg,h+-"V( ^2O<[ Z&6>剦orHJ/N?֤h.հR(/j1?X"AH䚞=pkǜ5ͬH嘃v=p!f󜝠tC|nUW! mj{v[hfR>? QdVkrI(+Z7[FMfv8S smнڼM8§V?W5bmEݍާYDU&Y;*Ri~RX uvJ۠HUWBkDS4K;6=vCwiH޼qו jƠ˄4AG4?_ziyPz/nc3+jH7F2ꥥ3S4fʤw"x]HJξZ95ݲ$r t| DcՖ7H,h c>E۴ (l}:Y"ov?+V3؞*isȮq5Hˏq,9N@bx=i7v --F'8wEJrbpj7V(83S$Vn{542FAqVӽ6dF*w=HUZ6ijs4k܂A.€'ք/Fx y{'RV܊V!k`ßG(ʍlU B0 pj.! 1 $$R9dJ 3ӃTnԅbsRdjm zlg,I$qW.0q\m dI<{TEdhnF|˯ PHsQ9Z:)F3{X8⹯}\W;hӬZ5A^qԚ O9Dp F{Y~/p%+Of?_ kzd;vyҐ+n-g%#9c'SjוI8Ih~4tut@p@yO.k3y/6xCs*yz[33 p:p|񔹡LkVTܣu඼BZ,pFq;WT~(Qp`8¬ Ubadgw+֛5].)@eS6%}T]-5DtMy!؊&t<6;iWM˖VE͘ B?:@J:^S'ZDr3f댞q_DobI<[`~U)gR"1K}f+Q{:] m?-cЩ.X Q.h w _mTzu!/N t'ި[BӜ 7.=qXcnnkn隞[0-'}uX>h$C2" .ZH+=kic>\:*54hAl] #a͞U kXt'fln88`2IL*[ٺ\۫N]vf4+mX1 A(,RiKDg;wu=n'DpB=6tfH.<oq%>8t6+7֋4c>܎= fII;[5[ȠP6*ӊv6j\0!Juv"13/~lK*\J%{3oݯ9jVwGߊn4Q+/U$c!|;zUPI ߑWq;K{1x}_Z"+kX\y]_|3U1͉CѪrxP:ac)(ՏJbܺ;!]*ZJ!FT ViX*bEp632E0.6HG vus_~K>S״~ۋyg1ȱ|z *+Ȣ=.y*rq< bS'@ji-qJ -}=J/;YM*"O\ȧ;@)+nF}w%ؙ൏ϸ'n\ҍ2Kc5Ku8N%6Ρ3b(՛?j'jz=*Ykx21]GoOѹK|`8XAT}1\Ѣ{$WQٮc[En-O>n4Bd;o!^y=cV'eOx c- 854o5qj'.bW|pƛ:}Pk ,oq&GpOt{% h׬4EOK .N\ef9v0Qߏz뎇Wа\~mjMemS Ynޚ4L|nlTAE09&&?Mq"p!sWOܮs%kLj$U_Ri݌뙋UADKzJ6NvERy㚧5D؉: hpzjҞYaTlc<ðcR!,b.@CwisdUY³ԩ**&` 0z~1ۅÒp1U2 uZjJV" ,ܓЎ Ib>>k1X xBHQr9}j6*޺ NڟK`>U#gav=K gu&(sE VW K][GoP4GGQ l$'sT!Sr(^Gq5CШFў}(k>vKi7oi7Jx*d8ǥKmڀ> Y[I4 UECtSIԖKFQ>j[ϯm>As~uNe~;@DUJHcۑ^|Z#'^$m2,=1nf+9r?Ew幬i-+ֹs3j=nD'$.zͺVӣc`:Ӟ:Y{x83p2@'h?_Ju꺏T)rEDvp$y\w+=})H>A R -]JprSF@zMc5f[Km?P)u5RbK(# svL:Bo*\Ie؈訾*SkDZi:ZlW11p2M! sc*UM #s$rFIpz_jU6lTU-`׭)s~QGd+wYUrH\qZTe!IPǨ#\Mugcj9;C37ddßuJԘt*;9Q%(˓}{W4]ݍŰxz&I0ǃjfq=V"}(P?M:$+<:CQiK|mongpxÿĎv^t5ZV~i&d|qc,=A՛H}oMUmC#⧈ -*##ּnIKL8V^fZk>žiDWm$kBϗ柸YFVA\ym5KŎcp *dȧck+['ea|+<v}XЗFݡ'3F 0sLUL}abQ1Ӡ޺} ;?6ZҜ9c:br~7_4Zޡoor`F=\NHm ܐ ]j>TtP̹?[o7G-.=rQ y(- /v>ҠfTcox|Iٌ} L*rJA?s`otmuh |x Gqկ |p^F]m}r=+w3Z 3X`Y#R@1m2?+KO4yY\rҷ}g^I)zͽzf"<&ˤ&N.R[k2Ő#f'2)HR|)ĜI`nB/s泼?7NMo_}c_p.qR9E֟y/!'T-mAfmQʖ8"5d]. 3T8\ƚܭ+Ffld*ėk_X'FK`4;ΞO']'ؘۅFc8:ЋZK'ԧhXE;ӧJIh.^}ߋ.]$SrcP*ٵ}p,#>^ "m,ɹ̊IG,%c>})'W?ο{5[A=F >:PYItB@WG59lwwMk7,OY),zlp'$.:jhOu+yӶ DqzᘖoV m&H"*{ vSH9VD &{qQ eZ99C0?&Iwv*q# KQ1;1뎂̬_Wp?MHҘ* GQH?# 凭>eW!AoJ9\~!Nd)G9*` tlTСuszVb|TJZ +dֲ`Y栝/qZ.Nʳ퐲`*%zޚbq+\zӶRIX<~_UęCɤĬ?˕'B* =-}zc: WbW%0⣙Dj0>4Չّ,{I0zqR?YVL@fqj֤r9yMo@Kc h)ǕH$I<v #i>OG2ycd=)2[|'RqZ܅e q׏֢d*'JrKr{dsU;r9SBJEM=`syW˶<( r+:L@N>N+e5mRҺOxhz29n>YT8ҹFY؀ c7Rfqii>i%Jv8_HVmn޼Q31o^[nHӉZShC`:78'&:k+u#G,@B:v6A'aWm5K;ς %[+"Ȯ@ǩPeWb#eN8z{^;CԬ ޚ;kh{sJf">{8$~#'$AX BX$$,W+3B`ڟ/R0'25oUY f^~u)KHw'@IK6ð?LW5Odq^6a-M#kǘLӊ̶^:$xS TRU#筊64>?bu𼀑T75~^&<5l.2¶Ỡմiacq}ݫ}P$lE{-+/8_)uo[guRQFI)w;ԌXg1OԶ~nѥ0[M  S_=aBNv/z|# {GߨfGqWSתIٙN6W\J0]z`]$ʜ)e~lTiYV2ʗYqDZm>Q?2>B^m5$VBbR o:U"\<0jPݵ~V$q^}8VG]I\2i${Hk2ʇS VN\?*烌{U8jsM٣)?jMbd*+4 ЁΥ{u:.n-%y.Jb8sSjYḦ+P\ ˩y˂=?& p ~i;iV:ty<G  0fW:kL?VEg:MId@wO\^\Inw0.˟tRn7+I4k>;I&cws:υW"OOTϥ6tqk[X9I~'O{}B)d;Qݞ~4)Kq܀G (0{Wi +ZIs#6I&rԭy4tI  //F3#ֹ>^rTw5ت9]E/BvZE+yrIVVVV3XXZXY9u_H9cg/, rvNƾ0`,o.ɼ[&i -kv<y"t8xZ0bORipjkcf'p2~²OZjR8+asiӤܬW:6!"n/[2@O$Fc:umۀ9?_ҿKYad|tWnu߈[G4o&C}Ss[iS p${^]NW96zf5˱ z zTS-Cyڀ'- 98dcobƍb7'Z՘]d`S o!2XLV-Z#@ Q_F6ĻRHtɾlI>r_Oaɨ;JKdQ0$8`})^ ozfe1 -XcUw";vާi:lim5?;OZ1 ~Vgs}ƴo}EmYq[cDr*!V{rO$L*|Vi6?tuj+g8?mh~?EDY0Zk6q-~/ij2,.3:OV+u!ԧ j~G?-NN^1UHfjkYn/-yҝZI+%^keǖl \23Ҝ奬(dLa2}4) ʖ\뢛ϔTC܂rx+gδZ"֬t&Xn`rkW]Z q,0@8Ⳮ>ErE\mUIeĞ\{sIѺ^ h$k:yd'vWEzV)Z!}ڑtZjTVJntF~jkhS8҉|]x-"J\Es1>#kWv;J42ބ 2dEܤY+9[ZAuXlt<큏nu?S8<?;O2ճ89Ӗj՜k2uS~͞,BBv\kCXgFm^wE}?Ldkb÷ YΔ}L*_2 {Nrl&ڼK#XsYH#U86)4O ,rF?DTq@ ;(5quO(8qz f2q`I'Ab;-BW08nʴRA*Ҝ4jif58$zץl3CdHX tg%%L)IGp88z6͙.$Z7`9`s\M7` c'&bIY-m_RD)Ͻ9f.+9Isj6^X'N?:ݲ%&*:1{9%C1&%=P+XY{s.XvG#nI&vYt¦0?N#j+ɞ։c+Y7YF `|k1\<RV-Sgt6qּ.uШϵ8 }HM>n(c'#=0VsȠ'r{Ѱt\5, S^ܛagcB:'vq J?*xgxZḬ"v?-g@oS6vLɎs׬) rO=xXUOcԅ{/zERGyժ umc5i$nn_-%s#aNG#? هi!gQ=5qqϘӾ^ZCl-f9Ng-d^s]|OhFolkp6c4SO|WwҜ}?PbIh?vǂ;ȥIxau[.[YGq hᓩ9wR=o3q[] tɌSNUv\]6wq6w*s5Sޱ(!Y=*ͬ {*ʃkloO}yѩsP&>$Bm|d$J؄_=+^ecVqneR5<*P6yFή yZ%' #cFk!e к {lY#ʶ}jfOc<_fl?_ҺhEbIc\y:g u'M>8KwD)E);Uqu{ufL7oҺcej5G-] ;:" Wa^]6K(#~iɡ[ڔi&Ф~{&h!XdR c3Ȯ2VY 9=+VƔj5UYFl6ه#&IH[INp3'?>fk٤ֺɴ{K[։庲#pǔ G\+F-W7+?ͯ[`p N}Vwo˓#~>W.:5&HB.Z(G ܁>n/.mF71?y8kĖ[F1{e&TIM̸HАJ>5^#Ĉ(a=tP)eV99|[u f- ϸjk9TI/_t }Z78kiln./HWC9>\ 95oq5`=KB]B&8c,sMkgG)8tp͞ 'Mo[RA"%,yVE,E݃Gp xϮj\[s94x`Rz͒x7>N%kn2Zr;ڍҺXkp a 8Y5., +{g+5-YQv5h\OJ,`IWfR9~>vi\i?uhRoQwm%Fx1pq՘5Ceȍr>5oܐ߈Hg ͜\<"&.;ڧ]jՁz@ErBXe9`k}cn5 Z];3zȠ$¾zQ`H+z8(ɭC$ܹM8_QVz#7 ݔI䚻m}BB̉RCljtTFkb$+PXϭqR]N3ߎEՙI 9 ms"xg}Euޑtu9.8|+?kKfSEM>=}֍'p\{2fiM'k}D7 M~XxDjpT~()[cyRRcq壉ǒ=fw_Cҵþ_v%jj6gzީsp'(E CҼFq;bDZ TBvT6-hg7|WI]>[qg9=8r\2wg" 8;[[޼-Y#Ԭ# s+vr\/L|+e܏ r@= \T~3.rXgMNaՀ*0N1PiV켂)F>5TftEVĺWخXci_ϳcPO${өQ~̿xDr&gcko;3 ,q&UWtEj+2ǿ \2IwFrAx4=9$hIU'WNܫ  $g޺9;hiKc\2A/+W%)n{y. aUYٕm41 gJ匆S#,?=8xϚ[3O F%mYJ䌌HnםOXvU6ogMULW=5ݾѮP3TlՎ+ X )9*'D1\3 nnu4薔v|0"jw'mBv=3](y5=\6-.m'!sҲծZZ0p{XIVN"& |})WRdFI@8[qY;ٗ8+'ͿƢeUr@W#CM꺿|)=ĀPʷ# Ir׀uG@9xW?HwMAFs-3ֵy1 Z|BӴAY݄KNrW܀xUc_Kԣ$H$#>b vE`GйyYw䞧ҰIVLeʊ,&l VfTYdY$cxZ+&e'ʉu}vIudXぎGvsSZNUit ]+=qf`wcEIsq%B7xHF+In>37.[=?JXҭ+'#9Sd" r)]͟_kmk-!J$ qWNiq>sW/5w0tk ᵅkyD0U`zZɫm$4#ڪU..L(T t?֮)/}Z榗$$+ΪܷAnk W.;qw&JGH]A끎~ʲy^-#D#3ԯAcx8Pz`)z}qaor\XsAf`M\iXc-z2>xAՔV7yo׊4QJ6EQ.o$V=קn {˗:u4h ԁɨvz se"!PH)ulW<GFlc4Lklܤ1< 9Hnб$}*Ֆ+㳳qQ0w,X)%U-檒R e{ ]Q9x\*.'+- 4Z*^7( ԣv*x*|E/vo-]8d?VہSIunňU*zڠP'vzZvp,K)(Nі1r*(SuD[qT$4;{V1kDJv3V NjSoOG:#o &;}jܪXVm]O4Nd\j-~1y+süsjFnWƟ56qɷ²wɢI8, oO"l`\繷;sH̃,ڒ4.66@2YOnդt2z+gonku6fh +渵7~I]UN$r=|u=?Ыq#.w b+aߥpNyNڄuŸ~9ԓR njc99lv^v?jZZ&.b`F1uw.yrOM~oSЬL:(9#HROjm\zM~)ɥۖ3we+hlu+h+~{|7Y-k\InusY>ɫH1Ȭ.%ǣ kY줷",z)~ֿ6αqc0TiT AS^mѱpG@f!A6RvH'<ޓ!y=(Z1ramt R3ֿ$}OKKό{U ܋Oi8/n05|V<伌m+ĶlR bӳgB{uI@ ȸWmukc&\hԙືb^٘dFߡR mAv2Z\cm]\3B=:hGKy*ܟfլ;9ˑ޹f-Q .I2[;nTq{WKsX&_5x=y5"E^Qcӵ%U8bHHS/]CH!rn9uG4#AU!@'#+%]eˏ,~Rn}*KȆ (b炼\@qxyRhor" ffAҷnPrH9yjrLD$T8]dJš+يFJV=G[s\ϒ-8Xe]zn:׺7*HU=Oʪ fwVߋ?xm4NetE).EnH_YGSM?Nv{,}sXI)_M>eH*{wo-ßPr>h;Qoj`3'$j_jcǯy>,U_[8 >KMъߑNxmg)'f=[^HcD*zd-rHK0cl/)ɍIGXknz14c c< S7#[{u< Vy(*Q岹|E'wć8= FDI@9VqS_=WR3<%pؓ\~'ේBy۹h E94mPB =@?+{F5Kdo*&q;vZ].aeKhz{t>IzۯZSi,3e)R? NI?ZbRخE3ϋi"ڔ7$.ˎ~ Մ02Z@JDהc$wm@U!.mGXKs" %B.8'8xKK|ffe8u.9]$Oyjh,Q* HanG?:M}~,$Ids9E [ZJbx.:J3+x\'"~r _p+m4MCgrMTbǿ,NAa۞6{*G+.ijjmRH핤1@[8lE>Ȱ क़F? )^V1n<'}+e$2{es-ִ)k9ʨQx=Iŗ^#UZd 6θxsDM]E wd|8#˥\*23M2+ k(' Y[￵x7?PkEv1<]sۀVU@i^NFflc[7ÔOqCJϠ9nT i&sf?+O\Mנ\:,bgzFs|PՕ{sQH9M-5  %N1Fh|5QE"ga}z [Tfc)#x Ғarx5FW>zPqхr3 rzad %%Kc*8#fb $lY=halk$DT D$E{|DBB _to.8rKlqշmIGWKq]+Wş߅hfHZ;-Z9:}m%;ҡd b5NAekN@0sNnG^51Bb!Ҫ8 I!؅V㊩v1szj["\JA8=뚦x|' +KH?SmH鑒9jV qɬe6a$m|Ap^lxk9{CIyFnI?2q ̋]5fVqՖK^]T~HWU1Hњ+jC/K,j$zJ;Nr=j/hm'*XF^ yagptҾS}V*!P`40ҾZǦԨP1㏭*s{WKGd}jCB# ֥rN|t8Hݒr~@}M[?=Ch^%NӮ9}d{֖÷a\40_ZSeƲI&tNLJ(CsWԆRA<NkSpՎT7>O~6'ڒ0x$q]}i$9S5Y`|m&QHHNIrmvk/ In{s~NھtIO'8Pdc={M$=j]Iw*0ܐzJPEi@>\hQ޿#ngvЅ ӌ )Kf(*sWʲ<8bnqסgnW:dPWy08*qY([^+٣e>A ͎~|W"5G RK#;2Ns+5"bŒԯBgcCc*C@Oڴ+ui{Qn`E)dl"A\fF,qϽtzZB&m ӥ+^W{h se}L.-V[Td.2N:`~UM-~nuKy>`Y |٣ЍY9+oSX2S[쒲{H&UV#Yg84G)Xn J+BdCdad0pORZ^{hvihqwaϠB}t(E+a1D>$[fU|- Y$ '!c:U;-.E64[S 9W5VRzRGr#ۈj$ѯ<5`4[ 6V˜gxɍGr(;h#xy9IJdGҪYcK,,jca S8jk!05*7^@?X|Qh&V)`3US Bj:0GwHew(:ƮX5sYAqskLc6N*L˽f .>}22z:_%$d2q((O,m$zS&/K+;xi?Q8=W\eS,NN=捙fxgs"@ĐNcNxyg,N1^-淹GPi}V$)GxcUCq|*<:+12?:|J'!rlV66e#A$jd,:4t5TǛ'#Hø69",lk%#t?s[c۝=fWzUnW|")m z \mNdrju;=4%OsH<#Dg(ݢ 9MVln@'BRe1qUTgxm^1,yAk zD?$$5'1%}:MhogfuZ.A*Qt[BF£F_ ٱGjf'' `YݚIyOFչw x:&vMV'p*GW jHjVDRKLgW Os5ukB5(NGW6e@WRV= ѱU68OR }|~MkcЩ H8ӃdqZwst ?𤏘PҰ4>oRKk 1=41@OҰ?oZiZ.ڄ'\ңSNJn~M! >ΡN|ZI&Y46Nā7 &xOf^J3,AU*d4IJQڐ1pۨk(z%džg0ޮ` n#9άO^0/t)O*kR(>դHӭm( |Icmq)auN8s Xz%N=S$ӽr6n!;O=qNǰ%++aZQ$]+RW?pq4s޿#{ek bH'4p@-P]Z!iK][:rGפA86TΝx] ʜd}?Ƹ'cWEOw6LgzV3V HaMJrp{շۮ#4c}+sVR\ڰSK,rT2y'bwڻ_< g婈ZD/Vs MݙʹE՜mW1'7v,x emNde xkmHf5B.mColciT'Ioh#bROp0ه+$Q~T剳<ޢ#9*K7,EWHLt+ZZ][]M51%vcs-˴_e,wG?ryqV]KvK޳*k`A0fTOMil1۵A9xC8V?˻tG(ZfpѬLTzSOsm%@Ӈl+&#[&9.ȏDyD.;sңԼ`fKOYÉv~*\Rb7H /(Pqj֬GB*=ʣmRwES|OL`k*@?*UެHeC/4= Ptqk,ʠD4J7ߩ>)T1 ,7AE#jXVylhd8R;A-^> HZux;'Yw~Ȧܚ'tVwG 455YžK%`A8'qWՍslRK!{{g&`򯤅bR)E80۞{Db1a6p䔺϶>VPj2Jō H'?:~f>_J e RƁɫ[хڲز!sA-]Kwžv@L3cLgJ$`=S\fEtszGw s $guT,f[``d}*qd& x"Fwܷya[= H'梸Ya$Eh`Vd1eI~oZ|++܆KsoHYA*@4T[{t@d@I?Υ"8եF~`¡q Ę$vpG)Ż]*1'ǭ2F뿓bJɶƴđ'JjR@<22TGZ"ж?~$+YVi-`m2~Z'\xElI&/Hk#Gc1QL8ڵV?p}HdjW \UXwU{?9>.%&d b*'\{0Z-z;i*\v:a՝f APG[8h!KJ2L CEGZAPyqy\)^I#"Oֆ:5#֩8xS-UP4p?,``m:WjGd>P FXq֥CU'>㩧{RW-K,P:׸S Y>R^7Gܳ2XJW8{_$ԩ~UU}m( v)rOKm I8PF#{y#ArXnZk4)t?]\i{2 eY.55]pO+ZSWucCI uO OqYF \kd6[rkj4pLnv+;Nam|LC۽M9J/n%-l`ueK Fj[ ۰1dckѣb!}LeBZO -| c2't/9ף˩!O3\2ScQTۊ cA8zRr.ͥBwsixu8~H> 8aozIg]#Qv#ڜѴP(?$3]%3+Pxf8GN;HFk>!chG';A7|K^CIC@x-֤C>QVi4ք2pA=SR8У6 ێrEQmI&mnۮ+8XڭPG}<'=gCm$# 0ʐ沓2#).DO WAxKbZNH\v٭CkfO6٦BOZh5bѻ(8irٓV\ږD{aUNXW_>N<ws[M)D+rgRB'*MuKد#qºk˚tfv-G̽ҡgxPBsQ2ŹPq愕H:JM=pMy/1$ 1J/^BObFy\&:ULos=בht!xesVOKif>US8ޡKr(u?&O3GwvuN?5`PΟv,]JsRVVLlQZn5đ`22={TשZrW*U,z1}zTz' $Vd,B>sғi=KQBgVwsZ]`51'1si#PePer|8sQS=ЬOx,'D0x9ژ4}G_#!\lvƶvR(^wm$gySۊ!{=o D|+ V-˥ix»cYuM,Z÷xJV߅L*qriZkl.rCۊF`KВ d?,ҌG}u?#)Hӯ^ &B?VլOm1?u4L\U;Z!{=Y+%\֩i(dn5:Ew9F\r*z ,"12N-1ܐ8?NA=X4XEdrX@)c{\2H.UD6vȄgd6x\5 o: :sZ1M$b5ċ49gIhrOwd*PjnuH,{vaXԶs~4՚"6hfܒ6SJ2D,e%H*hwBV̭{CL^GOʳfY"3+1 #ކeCEOǙ,S4Ep S.tt|YxI;1ԉTZ#l7PS{vh{cna(]Cϑ>ݧҸ CW5A94sBVm%*y^Y]Z\nr5ѤnOo;D c-")!9eu-+iԼ;ycnU┏+q4Qy UP:y_6 ѢyGB:/&ncZr<59NȞ_i:'n|Xm-55&9W{v=^Zt=, ST 2[@2Iסx?bVK y,EEdxXX9HOټ+j6C!VF+gh'ɭk^S3Gȹ^G,kjwz$eP6v+)U>DIG- *Q&>6Rf2vt0AwdϘ8ڡ$u5g'}JᘜCwwRPR舞=.A -}PIX8]z6W=Hٝ^?q ^3w$+p+ttXX(ql֨Z݇'=qXJ+Se|`j& N3micufrzW|jP*+rKº^߲=^BcoR0޽I>;;cq"i Ab8 j˅žNtԙ{̖/_vvqB *W.(:x`Fȭ^m\ШXJW ϬLr3XfAay{U#>Sr` dݩ6?oe{>=I>j׌oU<[Y%D9qg5aJj..E.x]m?/"HK=ysְ[Ⱎ9 (r2}+[ҍudoxA,0Oy?[nmR9k'գUa(4 Ng֝1?k7;?=JZAa?=Glڗ4v;H NIޤ>$Ѯ2bB}E|oc%cI H_,vkĖNAU8S21.=Yhkp#(L$yx~;Z\ 8)2Ԩ7Ķ7zBbnZ @_DglHUN3^97S^Ib^Szp׵|᠏.%h!*rFM#w]Z?Y SQ Dhk9epcdB|MLڡ:j\h+A `RTC~)AE˾{Y-I)IicϟYH`{`EfI";|N$$δ`]~\~sV#rA:䟘*xlx*5%fgmKvbA;rEs5L[ڮ*\.W򮷢>51/z4u`YP+s)%ʣ=좛mɟ7nC>a:Nt L|,iM-b|0ԼY |dgLu/mm p7ǿ=ЩMI(>ToV 'R;b7&kvR t<+wle28$V.ϨI BWU8Z.Iǻl3޸UItwRevB:EM9F NGX[H'i>{ius%9O'+Ul>mZXYXr/ߗ"*oH׊Mt9=}O>4F mkHyM8=kϵMa5vIęT|@+YMIit?E57Ry{c@9>4IM-Q7Oʫ3ٶwk Jԛn9z(JWONF /(GMͻ'Ѧ¹#Z0ۙ!7) 6*>Eos{(]xz5ty)c <t迱+kG}mu kCbCVɓotQ;Ǔdcjo:H5+a+ nH@Uv^*[LeHmU$Ċ|Ƚ7lg&{÷646*nM32<_9^M7>i%Hcx{MR+զ}'?*Ϊ)Ժ-薗èpo6ZA7c=s^Gt&ӯCԟjZ";S[+" fҭYkP ؅ Ic,Gm4L!t%ž]>!k"h.ZrI>$N}4#0;OC9LQi 8󏔓3nWUd$(%c5K;f!RʬnC7q5X:3iTUE]B!/OL+-iF+x ͚X;}y׊'a@ Snr}ޔ.[%Պ F 6UdK !ŷs_`Cm$ׯ*$`6`wJמ61Jp pi9^ӱk3*k6T~^}6;)Ym*hOV6O1/1[iln9XZ嵭ܾ{g"n)m iik++&jũo^EfG]{mc֧K 2[OhAd.!Q{^$FKK#frw r@sZEiKmOsOo/n q'F=z5Van.-HPkI66ZY>ċ=5mvǡjvI+MiXGʄ(/3/BFHȩ [zWVv"o G/7ey~YL-_/xӵn~? ^<ѮmM,XdC#uaO|OݸEy%Ťﴰa̠?/YW d#접t58-R,*XmA)kzRSWk\<摘DC|J`KO[jXHvFZ'shw T'oJW q.oќz8V+BysG8jnsϰZ5mN8ڹϷcZ̶^Ayu^BwBzjR|߂wgU{cn1Ҏem&FZh q#+ 9Y4Κ+Cə/#08|@;EsM5t=ش΢ݕQVH e泔ihvO %.0jervDq؜b dqqNI?{LrBF ɭB!A\5-) ȄG$Gj GS~E>[97\*HB9[G+:[RN@N |L^ԦG8Kq_j}c.sT?7$8 ]փyIsDtޘ:$-nux7ki٩8SbsM$se!8EZC*ޅ`euN{fk:Ou MƯ.:cұ:-YVГQfyqmA Oƴgҭ.&z#SfEE3I.Dt}5(@V}\0/Z Ʒe^HB/Sퟍ|?إݵr\rlsZ62'59H"5l*9gsqSW>`Z7 Ab$ϲv2AsjC)o=S}|A-4{{+a$ᥛd1G^1ף鏿Ld qcZylK!~\_=7|L"!' z3Qۺ#g/?3jOH;)`O^UsFgk7NjOWg+t5qBWbL1vo@沃{ۆ C"\G$W?^sDEٳ/]7V˶6\ ]Yxk &i%ubq<V?2SǾ:Vaa%rC"zڕ<2·r?3U5-rX&Ҵ^\X] ǚhӵ{U_V1叽phss˱ A?>źg$${ׯ|?loI1ae5ʹNu5/uxÖP`w|ܚxF6b#1ݱ>>%֏|"Y[' F9l'Z]ܢ eGsնo}:.fCoJg;m t49&5uI ׊jwS ;8mYpZA=?*Iu`̙/,/5S%C|값F `@>D*)CY1Yt!mtYٰ2A:s6 %[ =ᥑ rG$vM9je~uu . 00q;T:|iz=2j{VCZwzvS_ZJtm;싨W(h8ČYV= L2C+pQ{zR(zIKI`i]Ը}9ӭ8` 8pǽis%aF' 84ɮؐs{TWi"HYaiD)G2ֲ)*$8VU什WҪȧv8zZSc#42pGQmE%9VbTՊRA, 泵Ek4zq{W/?<9_Sk\g3)L};#/t62RR.Fs{&ROtfK5{!%s$Vf=GV<:J{W\9V y " KB0?Q9icXৗ^I^ ~U5{/5'20zTo2Z;5#c1ٴ>p2uZ'uX_XW"RGy=S`be_SRJW]X)H}+_3BA0*0x9g3?^&]) %$|?Úīعӝ>tNՌyqGs_tɭ䶳,Yކ%ɯ*h%>e NLp_Փ#<`g ݸS%wtE {qޕO=?nw8JR\1Y#S:Rœf uQ"GĪ+9kɹ4F2+Je7g8I̛j=qWt$x @;g. F6+1C+qi6q Mh^i/%~}2iۡo GrNU:~FB 'bֺj+uFH7i&@{V{&NM{N^e1($ՍH9Me6n^>gEa{RR>K.,%R,>u%`ppk=ݑ`ï՘ݵ~3g/$h:9#u 㭻r _*IS|'kO2 hg'ֻ]VE)9cg]wdy؋F`Kn\FrUկeV \C"_rp-s{4̣^_4uj)㜒VE#I5KoIj{4-ҩ66i3[J&Xͼ~MtN1eicheE_cߜU;ıJ8FazI'sƦ(izɾ8BuYja-i2#6V v{2J_{M~'Yy|/8+*TzqU4I[KC1ۖ˞1CV1mB }.K"^`zc^q彎y60s2?֊FRs.},*]@;? " H}=1KFٍI0RH2<1?"{GZijr`Eh||jMI\\+S4$p`\2F~N4w^dLK"i%/SJ/RUmAPM*s¢{odӧ2,xlUN|씒v?&cXC]+TcVkm>(@ivbYŵ1V5 I.o c]A[d2]ijXM,#>q3 c==+9I]=u5KYsCykrI2xړq4F֏Ah&$$dx &f9(ux8'|֪qs״ۈ@+wB#*c8i'ۭY[饊[lDbU#jKqQmQ/~DO-=pCPzɶ !3nqWIjFݚ[>ki䉋dD=2lDZjM*_zzQ˪E98$JRz|iY7H2#!}1dU7{X˙?NAq XX2珔}(#yC``m,YܬG T*9  $ST Rߠ/[+¨7=W{{& TB"xۻpzV}֥%SWD)<@̟eyc$1GJCpJ`),C]JSmg呛nFZ@prp~մfhH'X9e)7cTtah=ZZHm*"U84EjrN|@99s>g-JA4X Q_\h3ov?:7y/ug:I(@c&+3:%\}Ur +|:bMfbu>o3Gl9*'*0;yg+9ֿsG|&[nMԖtJsI_,n2_| criʽ2wZMH.b uܻ@,8$mҹ.kW КO/I9Ҽ*Xi9}e~N q4WŻj{R?ԢIV(nA#C_7W29IcքTB R-t銔aK(?78oƚ}8huzص_ܡPV`I"l5?P (# UzKMMr25"jo5(_H-K$l#A޼_*_2X;nJgtgW$ - גס>M=?ٗLX[uӵ@W!/kZ]ϧ2(#WNܜքK.Gp{X]6ȥcv[9ksU8wXs=rA5ZB224scSr*A*18Rr?h=r:gH[* kd+AOd\Յ {^H"Esm'>ϩHg{$&9H®@>DVAe ;>_UzM?Ș <jh +vY"* d{qG iWŏ֓?dE]' çLF |Z8"qdamd,pOaKp;GɒŮH0LHN09-eE&>Q=174]d_ v'EVrIRfKvZk6 ϙ8_ FxsbEٙA,M=ȩ"t?/sN+ϥ\(zW9}IK]դgex%b3Y-?\fTy¯5P՘TOC҇z\&d6Z+yvCt_;ڄG<<'T;cxxo5qSiǪIO/cۻt}+D^J*Z/.,__JQzc5h2[_k{lgZ*\!IhxˤKIo\qT|Ey{ bcGZ0ve7O!3\O)xDL^4e=R}qWU1o\mF;|0zu=M$54k$B\[Ǻ'ߊoaNV^JU$p>hՉIO_Rҥ;; O/; ĺf!TL֕bх8+ٯ-ēI6?zwg^mrOhue|0)A"=q؀}*=#CW"wkV+;LWJ(TݑZZ'cmn7V]:d"hnGKzO{̺y# 0C)?׾ܵ miHgxOk}B}'*Tԓ]wLRV!tka{ N%O4BNxys'ә1CT<Ȭ|)ŷ0I>ۦ,MKOI)|4v+Mm50D8qjԳԪךUlym>K-[gȺ&O|Ѧ޹9Ԟ!wvi(lXȺ7ymӐ01(_Y}LLtU69R иOF#u2Ḫ qP Ҝ8FC@_50G)$B\Mo# [ȡ.mIqi5m>6X\9`y^?\iL)g2++ng=:Х2u0r"++?iim Qn#?)=kGHKjSH IMoʜ7np*luGƭ20Tԥ]䏤]h 8exKu]u< +.LIw;FMh)d{%*V.o? y6̊%3aCWM O,tfխ+{yȰ{XֶW4;MV(6' 飗ŝ/OФxo-,Sy%!cL-&1&A9C,Ieiܯ21'S;bR{òqSe[V{[%+/n.*un J4"r3LԚ>hsZ~`f<SS˥6я2 cYSv VRAzEJRNӮukȭ4yn8T?W|*'~$ XeI;AoykJ֌R_3~'+Ӧ = =GݚlGl/}!ɥ֑eڧNTgYkZ t#i3DZ4Ӳ9ڰ85X$٧ e}lObr=ήTXy:|3AyW/L̰xs.`}9ɁSsVKeԑsx 7to3Ixy1 YɕM_3Dߴy m9"ԩljX3Lş,}jiIF:xg~͵7g<*-aqk'q^ܢ)u(B>`xB?Z͹/ĺ%8 j})ʾ<wɥ"cv^:żp6Hܶ3YK.5Lbֵ{rr0QYUQc x۩kuL襘Ԇȯii3SwQ_Nj :j*机Iwk RKJ5S 5= xsZ3ID+}W"ٵ&jFV8z iLddWQZ(Ú6lZfGwcۛCVK+ Wȧ#HUc3T!ctss D$#q^ת2x;9ҾKɝrOcOCn1g՟СwCڜ;,>{y์95/UrazuS;ԭ@Vך-a}AYj;T)kcO[? .O "C"rÏ\4RǡsQ?ǤZZrA"Mw]Cd/UeJQPfOƍ0-&Otcp3XGcmGT W,}NN,|^hG8+&  XwQ_A,&DUHÎ[I; \*I#TKr0 TO?Jrw3/4-D{Ԅ?ˌ +9Tz9ɠ=4_ub;c*8)GFc7n$P\5Y2Sһiԋ\B1}}EVoi$o)%'ִ籔rŖcB5ŝdQ:0*'Ogkʣt FSM;2M3&mJerrOex6i`~6JXסOV"ܮcױ}:| eC)y0*zÊLoe4q-ש+tjOtthmdKiP0HoN|Ѷ;gFH$g rX\RԈIFx߇n s%m,j8푧Ǖ##ݽH|U "WcWǬ"76ZWh;-o\t>^ggRECBn0+ncY>bmp]wq3>9O-VўqF`vn.rF#(=8j+Ju7ڵ ; @9{SWX[mid-j?\1ohSd @=]&"G3orSs.1򲓂3M\cdvvg3Gú^I}qN:j-K^]>BEO8Q؎hsF^X( k{EVX ce:3Ҡχ.o*ra \fzݓ+-RԃN2i6ZӯHf˜2g>y4S+ ъYIW?ħ$TFJQRemV$'h x?P[L?v ~8e'9=3Z(_0?y-bw(a"RJ-鑁uK.v9699z1Zz'55G]`͌A'Qҫjzt1[c4򋋗W)`yDcv6lXʭ!ܱ03=E cm)0р6G֢qly2}HN+$;XW-;h+~U"I AB>u $nw7_<^]Rٚ< #qDs#ls^FM"Dž5(B(@q}sC 3M$;^Y'ҴdrG2įO$ ׷Y)\],MFr98vfidt$I!A`}qҧӟO[2D:rs[{;:jZyE)8|G$ Nj-ZҲ8pqOa* M^}%R@'{T Zx!iٹ/_ϧ\rE?~> |/[n+&lS5KK*bNNs⾸E7x7~%ֱbU90?ZK*Gi31O8'4N :Ah{TK#Go+!9++-.҅E9K 1֔эEGoEQ`v|~:ܷ$٧R&7b#kzlnTt՝L9nLI5-CYM:]e vp"hEx*+1S`v@8'7HTjB-o@'O<hڪݻvNjE #v>Ԡ׏zU?<~[Yp;G< rY;0V<"dބ  R`HIH-;<_aꖏ{%bHӚK54V\cΘ s_gM3e%=&|=}[d‰^ ?۽fXꡲb46J_k\w֑<]$4ץol*@ 2O]tnLck>&Q}0jFsj˔:ʺr)P̜C6-':OFi %">^Bc+04!l$KɏOGp^ `u.c . H v)讁KN'`=T%aldRr'ֿ#nfaǥJOqMFĿ!5hb1匶,[hb@m0J\=1婎ـ|MxJfdYY?cv-3zT3+ ;$цeHkY\dD0C{(np:}0k;+\n[q$[$9pA>2IYbݵʴ$Vs $:רp)JL3G8KqA',QOzѫΊ #Q"Z|E)93;V^'kr;cZ_EvBNOqZWqT)  q(C5 xJhkRFX4sJ4h"\3eJ=jT,$]@OFSdB?Pj;nI[moWG(!= { YgbNLp\mFLl ^L\Sqz$ t#g'.I'\X\tK{nux3TNkM:ͅAĊ'ߞ?i\0uԯi## zA2{>?%63}ҳ+ב3CYECnZ>``Q9H YPgcR3kIVs$hiZk!H1`*l&ErBpY@#S)4ux94ç%rG}ݣjoq6hH$rHZQ\Cek ir=,m2~zn)DƲcKKxbW'sZ.u_}$֌Z燑ZSEmSKnnř K &~c M8Ċ09TkVEבąъ-wQIe^_IU$`;9l8E?P%uQ-=u|A,-L0E8|v<9%fegpU< xib^Q,eSCѢN0_Z&ܗ)NK[\-,3鷌OAH|--Sh<$Ƥ '#ڳRIf-9%{u@GNxϭT˩[KyP H$ 2RXn-AE#=G@Er Dz[sqs$:"J8ۀO]nf $[ ،z֛+I>uةwP-J۰`wc82UK,2ޓv'=JΆhrWVha"Ke%;4,,̒@)s A{A'2*;VY!ldbF1Og\R\Kc@t֮wQ3kZgeI$}瞹gG)fݸ'ҳliv!283Yl|]`@U)7Ȅ/_hL,pA=n+Ԛ[H"gQ,َ5I49O5-Vi}N\4q*=O`wujEBX52nfr 9gu-5$@x`,!)ʼ~P#z~vױu:{,Q?j^ѦM4NPXti }P5ĆIHdCB?c94oi4XL7%RHOjƻӿׅzس|8@.[4j}٢l\HUr4jM3 "^N.LBqo$S$"Whk.'Ƽ_OJz!n=9W´wNʠ>{hq0.2 /trIٵX7ڲ{|T> ã ccP٤z]OO 8"o=1Z'6?lkÀ1{׳cOvfp8׽k:ҽ[I '~c{'Z93C(rIzQ6Y#'+L2QpG#M3EP{v^qQfUx zSH,~cgpcPu m=rqP)I_rƣ|ؠ`j\ߑ%c{Wzrֲ HRa'\u-ţ;JRqjd2e jRw@$rG31}raݪ+"퐃Ԟ$`8+!g6Р==riA< ~W}e,0GЊwP2?!I+2HJEEA-( >'|S:Υl5Om:[ pVeGq9֛YmmV9ēe9m%ߘuB o;n(PIFktӋ1p4,{4gL Y #iݠ#?βd.`k94֖6|-IgYmܬ{s]^- QȈSGYQْ[,hܡ߷J}V]bp 3sRӓE&̏nEn8>{ Zd, 9@u=O#қn"M?{}B[O0@ TVKtb['E2k;Vy|2H5Z{vlT{u- >|ާZԬ7%nډչM'uC*K(mgO*%VݜxYǧyvW~-uir˔$Il8us!K`\+X0m<)El2!S3sXVqp\%VIŽwP:8qw5U4ZHPq Ag1̤NuH~} sӊ#˱cVnU 5֡~ >e&p qDℝbWu6lt|cskF]jW\]=ܬcG=qRyU?jHMEcjAIsUxu(\HTnWc bť V ✳J.%;ޥ=M9TSG pőFPNO()`-X幎U󜲐?S[1Ozx 31ϭiNSmYk+NUU.x!l+rJYRٴMJ9 \1]'ͷCG~,]R(_F:]ޗm4Wwus:T[R6[V1.qdO]V;GY2pIJf+ۗl=cl6;E=X\)s# gRjM.] lyS?A^`F놏á;Z~E;H x 1 ߽jG [8T\cM qXa{bOT HCAZWho2+oT$8Lk*Df È0}[1X坯rm)GF!R|(Pc5x$|isezqv699nŧd_`]hm-j)A@;#s<X۵,8]8 eNe%٣ L曀G {(M3e"+w㑓ڽ|!T{h|L6F yjC<Rkrv *dbNrzV^fkJpp=gPkzmZ$m_7I~'\zIT,vu9pP3g+\^hzw-ʊ<]k_Z !U$lkPFۼ gʝk\.!F)Ih}"_ tIu ipv7|?7'ң0}Q |R ͏ƾ|ln|E Y Cj7 cÏk?\Ē; #zUK+ݻT:q%F|9L5y5z!K1(l, B9}J٠ԝ,Y'4sP-[./ P᷒r)<吓q\NM;36qDƛ;U^XUz֮2EhZ7g #,k^Tf>k8軔>a]*1oViWVٕsU>#˳f*{Г8STO;d9 :h c*A'u=by̎Tk(XZO*]}9cX'AC 64a*NǷJzN#`e[먣Gnz1awnx3B3؀ixM'_޷VC=3sF?去Um-X[eRH6A g# SfBn# ֪NQVv6na]OHЉ'V )=Gl9|E>c[d Nqڅ+W+KiQIeme# T\]eգ QvwڶFgM\r1zVRMqAaIǿL)SNFfڬ2!b S ts׽lw)n2 ӷҭhros4۶}p9XR1;{ދ+W)-#Ok+6pyO}̍j\D)w' #9&|em/G䍭DP2ɕ铁ku.ecZ>S3Fk9v||M7RS [G4#i qҲVJ (r4L^yyuHb =Ic\Lj 3Yp$W(eݘSqN7rԤzVswnQ0mcHm'T{{+5iY>b#Tw۩\S-hmO#u0ҭhB\9.Gy}ȩ {Y-9*vqzZKDc',(ZMiPGhgd7`=GLV^p%c%^Rx\jg-k<k[qɽAlqVomREg;bxǓ\z#k$Fl؈譮8 hPIp滑bn: xOGw?s_RH&DiLұdXK)GҮjIw [^b.$@FK? o|Csi~F|\M.g]٤C5ܓJ.b<pHaY{m̄ Dt>ms r^%[.5GD LVHm-O,9W({8lm3um/%£)*9 W˅=ASZ{eŦY.q3m`85K#HYw{-JuFb`щ ֍.7Q]t2YDDgG-~MJfRX?OmtgwyIQO*A)'v)7LX c󷶀#w U9L};l0Y>s;PR{uP[IOKi7N:qեms7WR<-#@սF o5Ppq=Xmn1Ksݨ&a{C`IL`p}+~BUN|z͏mQl.Gu9Sm?7_7vϡ^[PCazzS.?)]V ŁOHN{ O[X8#-Iʥ'!]sP[C0V.]vJIGLYb?sb٦G}}'lQ)woa^ #=NX,f[lqS]57=cj:qô߉uT-4V0&6! nb?4gp#Tڴ=/SJ xQϡBOydĝKq_/aV}2^Oy#Ӡi8 ?|ufEې3/ZѼJ+=wZnuC,a:V#N?y8jcprsdRdy'VM7OӉc$Rɭb98=clTV$7WŧdO(Q] $?:AWѻK+a9'yvV4m, `Wڹj7Ȝ_m[RV%d#*ڛm"?{V-kq¦2+M4@V~NETtSG'+GBԿgb K\D $Ԭ?-$~4ܹv1t.ɞɊ1cק4R #e,X'ɦݑl7sk ,99Ld:=KYYPdBT8A1M[SʜgLƷ70dĎu%ͪ$rKy`8?ҴZ>VMn wmx^&\Olsgx&KE1ME&9ȧ$8 Y%QeS|Ct(tu\jdoӋMy>{[F2h;EUc#.B`=IⴋM#cG g܏g;de0=xf HݼˆS>c=);[rgi%$bLy};&Ds,dmjSNϱ̩l 6;SJqjf0hATw}> LZ]][UU!O~}kZ #KFInϯ?\5W9ƻ KbBmn ?Q V-̶-.DfYMDRjVn9;fk˨7XZF O\j{M , p*J$hF[%D\d:ϲ#ꤔϧ_Ƣ-(cU9{GRx tц7C7H=dUȊ֕@%X{Ԃq̅>o9Ꮸ Kّ6ܬv'JNv$t5 ΡmGqj%ĐB֮VDkλօͬ9M!'h.:KW.D *0:zKͻ??}4;u{hܙSGޑk|IDjzd ڟIonTE>R=dy$c!Ob1PZM$ndeidqTd(ɜr^߹$sHV:]]ioK:[]촻?{zT驤'mbɏϒX -@r?JuWІR@H~A`cƷ̗_挴R<~uFvг{s5keI 0(COU/ޱBÐsȧ>fKmRȫ 8G5sTi.b%[:4HyMی j;J-n-3^ aZ5Gf9=O?ZFsNeMۄ;R~W,oM^[=ݍg{qjf6[&o+gqza-q2l@?+u`%i4ވ/tIRk 6^SB$=9\0v,ʧCZlu@ NbZ^!D]>!ߣόZG╾S8㑊h\8潄2j`M) s^ b܂ (74>=9mY1 y8iǧ);;ۑ z8G'y)*cH.)N6PyD]G5j-T6^%ꄵb,lMQ4AY oApF2wg{q%j85Ŝ釗)^;8}99{GSߝ?ԡڕ?S_}MTr)"b(y<5.+OM\w"PZ:jo_k7_d7%Vlv8јskD?~kJ>NY#NwL%4X*@'=rkb3+ ع1#ڲFҴ;V2~0KgPНjzX>iz=_1A=] 6zi(zFcrk%Isó{9rc?_^3\JeJnO~MCS\ݶܨ9Z٥u%-Qٶd3]Fe#vdLռd%Bk-eJJ)D;[7Im$W9=zVj14{cT}Z]3۱ÆHmX;|PH#,%yfClcJ]&QLY-dw d oGԤ-5,H1N(I71/n g)I>GBekT+,Haak6jٳ/ek׿16"v<{wem5Ic%eb7cҢZiSzkp|Ko.cĄ+Fj=64 Uw`Z-O63]E=T\皧k9]4e)nCeNkV(H`r=>F+=<׸F?AW5{mNJE׎~7v4IY.xakG\$w#PbUHBTdzڭ!S#\3|c`K<FXC~U*.:LX*#zIۑxՍN " 6gb>d}*\n٤edS*m!%WltqXOVʌ?S:0oNJ:"\gHr\-nc(UA1[𽮜i5Wr?"*$"RI\*N'3yۙ]WOİ,2.0G>:}j$dmVPr;dj͆w1x[sF$Be *+2o)N7z%*f(z֥rĤ"8CMABOK;51c")U{oXhzeM HnN|ְ.ZRYYM#>M2A?霌_zijO]iA2%՚nKedt–o^O<]p}0qS=%]9.[Kʌd <7ⶵf\[öxNW7͌z ubY(?o">@b³l45;$2$4y,8S}X}) i$ ?38XV=A*|s5zAs"ƉC ӓ:D;e`Nd;ߊ//4됯L'J\M4z֭$q֮{ź 5O+.!zJ-Yq{znSWi)`@kӥװHB6PYש{sB"NP WndGˌc{ Flpn^C9`Վ`VDLH{%kY%X=k|(ql;xkhzûg양`rz ; ''co{nt'Kǘ缹!YrOJҋ$񎪋hq MMǨڸk'\G@? VCW+#ڸ&σ.m|k^ՏLQ43~mAD18)mߏ:7 鴓Z^](_NI88A܀Qkԝ+j^A&r_R,-b9$[903N~MrbAьIfJS}bZi+z׿N V;j^bn(e}: L\G"^$l7X`84֌oCt9'h\H k4¸!|VTXg888'a0 8%٣zM<>k$RI:= h* tj ·?09R m霁caVkkX@?9 #l#sr7B!_m~Rg. s4_;k=Ā>)'faNxO; vgJWiPyp5{}^I$9Q]K]| i;; W$ Nw#rX(:օ#c泖;hX@V~e$5|Aӭe6w#q1-Ա RѢ T $ω 9(f0N&G2oIݻ+4Aqn֑0#t$g؞⃫ͧY} s$ ʁޡ;ťuc[H񵆤|rd{VXjf#`:jUS)c[]r) 6;Fבđ@秶hnS7G>ݭ0S*?<δWkvury6k+D -JWP#XdҙiAs&nKT.ܜt +{K]K,Y]Cze^4v.#\7~9[׹-¬p<{s `fV |*rT% UqN,@}/ˉ^YTO]O9̵ V2!R`Xg#D7\_ŗP#h̝ei,,AR!ۗ IN:nmԌ*SiI79vO7oNJ(q4nҸk_2bUmA<뽑ӇVGY*\G}kў ꤈ij ר|<:ٵ9D#緽BѓR**snMC{^2^8Ǩ;UȸE?B֭n!RXȊ4(iwEe-Ioс*3ӭB6Teo[$Kϡ\i@8}3Sm̝ֈ̶j0H0KRr%R;]akm:/q'pÿ\[{Dj\I%D3DĹ'A+9.c71 N ]R[a;X_P:|}EȡlM[&);>R:ma^fsRFxa˔rwe?Ҹ=bge@=ל\92lYATRkʾ7.I;z?ܬTmI.9|8-KA99}k[jpXV(Ҹ3sO66.r%ĺd<0D1Gif$6_sθ$2јع9JyDc$}ZDoq#b zfԮ# WYaчhyc&VUA9㨯i듹+s<i}ϩձ8`KaCҞy %qi;`sp)BG} #s}>QGe-KHeOhO1_aBpה4^4|UŦ[[ YgDz 6 ͪEou UA_z:weԘ8ߡM !)RBV]:;;2!rV:ص׎s\GǚdQLp6Q1^QT]qg/~ڬW,DC +-H  8mUI!dq={cOuoD eq:It34ӹtjk (pq=F:.s42)scV6RDMJns5}?6d6JymM\\^p-k\{X3F\cfpѶz?ʳLW2_Đ#*TV-;سJ1n_\Vf.}X es*C!\8"诤Y0L1nCo+Sl'gV{^cJ].GiWkҭTM4VN/ r0 n8['Fhbp2 99sE(Yrf݋m8ڳEɩZ ̠6l,nd:`\̌OZw,Cm}nrZ8* ch#Q}R欮mKk+,hǩ!''yPǦ3*M{"XGsǿ}zwaERVDfJxm܎ǟni0F~r(VLc vGPzp$'*Ⳛю1l[Vx"iNQqt:Q#k(^24џ-=:;;=*].Y^f rOCi0mrr9Mml ɣg 'xİX]{9`rrzMUÚ\?4ƕnLۀQn{+|Am%kTrB#lOsxGRTig,J7!bn>R1nHn"%2WNr4E73Hlչ49X&U62y`ou+7ylT楲iʛ:!pð,;q -a#չ@5omM׎U42Jåۃ+{ЬR)k'~xiW"[o?]啲iVDpF-PDG+-l\yϹIL.9=@$F.g(]ùX2*8K](wr S0k[5ߵZ#A7ʮ](~N7rbmC47JQ+b'ּLg^2s-w5!pk' y^ސ6#/zN?4B2A%\&YZŭcWe {0z:VDe&GCLV59X0O J]r?g5k; {%ǟnZotcVj6O, DiZ?M=xZA`ȼM2 j$ǥ!%ʹd%qja1J*+(@O#(OJXز%qRr7**yd^z=c94$K1j5}b*}XTfEE/*3?' 7Gj?( t'BV@UvayV+_'U!g-Ep +뗪:^ND>% mw7{_5@T_vgsrdoMGy)>a}+l dh$sAʶmN#'vqwXG8\aԣ5Ÿ>wg$cp>i,|ϣʻL*}~m Sngb.ucs7zOfLzx`dx;U7VhE*!·T֓-u*UDl;,Q) dt7lݱ\NK9N`ܜ?ҭ*}9RrAǡJA'Kq##ZR22s84j7Ԍڄ A攅{#Ӏ>޹u=U#y\G8I9ۜclV68fG`c=G!֨5]S0C'z}ʿ]/[FӞN+~$IxP.6F9xe'ױ=ڑhC# xZ .[n8Hbw9 1~7JȰb@r1N8o0\,n y~-Ou)ζi5X; 䃴*ޗoi$E=c }*k;ؚ-ݛEs T1FjcI!i!baY[2۵ChrjբY\Oic J"дK:}S$#?^hZBMx?VGCG՜\M+:QWcӁZmy !LcQQ8%?t;;^;t ,pyCkG ̳ZR+c3U>e}fքU\2,?֞VppV %`~|L,2odq)Ncu#>-kgO*#LҦNU֛TQIH̻VT4VY`e(TŻjj3Oѥ;0 R]ضY$d*?TunŋkY%iC@3#M#ZeΑf@$7#r?\m(ձ{eQqmldF T3W_R; {,u ~!?SyĄm0I]?$I10 ߕH2* Wzs;BE}PeV;GOUDKGxD^m'#+DžJH~>?=+S[X*V1$jmT'(ֹ'lC EX\p$H'sGc$ BVO$gֆ8Bw2hi䷎o8W)< ޵Zj0j3h%&HV?]VD5wwTJӯo,pI:wzǏ7VR\6ESXd/>lE8NDf`=;Ι7m7S͊d2Ėlv'5Jʝz<0R?`?xƆ/S8@~_Tyx"Y~&ֽ{gᲹQ$GK9Al'`Sqߥ v,ݷRk ᔏ֑8a3p S'# r3PA'<ڤ@\NBܷ!b]/ ЁMee^==)Z݁*riD?r{6"<..4ڃ>3<Ⱙ.kq I5 3ӡ(,n5쿲:(WEz _i=zԁnFO\$InR͍tb>R@8?<9 CV+_p:gS]Jq8QFA?_ƥýo&Lr>~ Wzw"F3{zWHT.ok4ŕŵ+*p3]b0qpj1PU0lsH&}q\8w:tX?˹xҞ0.m_ZM z͠o.bQ,50 AwG/ž}ue$D 0a3U|/ _6x0As_ʌCH3PFH8HޱzDTXH#RqI*N9P\2; '׮#%H<`S?0ɞJ iBA;{uYOcHP(s[WM? @Q Ҿ%/3_CH'=x5? i+*?aÎشeIg;YqNGAZ!+)Y1BxR0s]*=E`{1*Dk6e%9o_TvMQt?>&\uZEF>[^u_^GAsl[dd/#?dB[Ihfz3Qq #jk+Brw$jwjk]Q+6g.?0J "@x־ti14{\l*EEhz.IonWP ZuexmL]U@VMhY6[[&[۔E>cێqnէ5wB²#( 8lS|]ki'1qU7XYe)y` )ϯkG&DjZ^FҨHE# K .^t d4w}{݌xvOΒ}c^}a.-6d"@=55" 4|\D`U_$9{H\Y6vqȫ [dWy-QԇH#(GՁ\t]fQỳRtC5+=L;RR ȄyHJZ"FXこ01,U3 }AxM¥EtUB(wmhQ?Y[LO!nlz2k{ai0{~5x…^e}5Ŵ~[$ }:PI2DV:Ci++ p6 .vӰރiW} ?<Pr; F$[ %\ʢp,r=ǽL VxSj 2֑V9$[;+ P=;O~Uk&xmf_ڳCt%\y:7N#5W9_TKT#J˽dKZ C.5+sk]4HȅN;W{u6w2{fqdQ=bO֥]N? N:-K]0 ~DW;npDC Hުr={J2|ZlΑW={?*̾e.6`D%ƍ4.]\a'![kB{XĪU LJVE_cZWO-?{$(rz Ջk6iG;]nm&&6oL4&xd{r.b8 եmi5dbXZ_06:cF:r9]N*Oi]ʪ+"m'SHo<İ˰HqV4D`̝z ֣zj YQ$ 6$A -Ir֞[ۃ.эzdV\^6?\lrCm89~G_6\f\?~7~8mlm1̒;,F;Wx3sElS}(T3W#OµoDs3c!v(AC :8I݈;U8c vɓkeefyS@5=Ez6:آdzd5$_y$9S}MSd$tPx=*\ciVHT*o")\]J#NڔcH A54x\JA+z*x E\ðTzUJ֯"kuS5$7>]JvGk@MarwڵQU\`gy3li.T4aW+ @ };D#޿Q_}Wԣ>_Eno q"& nA'WLߨUekE9G{-ƉTv-\F_ӕ^nV+IN6f800J_3sZ÷:G5C5mV$+˰ WԎ* ^+ѭsOj|x:vS5MJ_6K0q^mqI, +p4R;0Sn3%OzHI*OS1}E,8M;O>j6ӮrP#8GZ]&X$b=M6[J渑aCpYhn y,U 0pQ_Q逗qiRp9k~"ݙ)߲? Hhʜpy8u'XTvz 4k:Zm!3k)=.lr9+5nBa5w4[QOß 6R#k'Z˅B61*{ -E?![ }7RG-D\DpW׽kUY+=)=ʶ!bg=&rA:W=VCx2VOn tšZX9opBnOs4l)N'еxk_>VAlUl]Y)Py[us]sv0Hldnsul$; HUZdM Gy1%ӢG|v/Z}22)4&a4B;kv3B.dGbbqWtxo-.}6f]Dcl{zg<֖3jhIZ#t@)46G=C$) ,d򻽎3=NVz~-couE܁!Z#Ryh,T̟QG+SiԆy]Xix`J MC&x2Ú!4ʒW=@q[~Ljt ]%Due=pjFwfݔ[rL qUI}iX"b\ vz35B=+ex+Zѭf܏]NHǯֺ k3M$1ɒfč?! V%Tۛ~Ֆ.b I*ˆGuhvh~ iJ9*{7q/!E,pA9 '<v +{ㆺ^ |]h q8kY$mlmdVRfo <&ي̬\x؎U-uWlQv Y"ޢWI+ƚݴ2wc(V1jz##3 O\´j9v kU58'c0@a~]džOisNe!5INtLA$pO #Fb;8[6w$bKIr={lTagX]Kq# =A}N 7n<[ӫWs9^cVOFE*nlfZE֓*NHa-4sZϚƯxcjKkc kFY^Hճ|(P}'pHe9V_qm,b,F72#?Du4$t Oڍ4FCK=|5u=nNcўQȌx %c,R֦WբhsԎשćh'0$A[GUղ,=sN!#5klq5w "b8eW"U޼O~)ٴ5g+\ S!Pi рՈgX]X|ԭ?ÌVY` `z#[e7[uDA$Gee<סWPhqAqs^՛HLQ"U 9 =OlpTpMo(8+9;%hccfX!9b ~)QgnƔc5~n0xنnBG]!͏|dD QLK@] x*X|M Z[Ookx,O<\,$rĭOC:ȶ dweη[{W^_?d)y\c9w ݏ5F'@?wƽsG|͒g) d'z}q={73WG-t#g U!Oc)n,8~0VB1̪#wcB1;HFH zM 1m{ڣ筠y=:P6* w?NsJv8’z7t 6،<ЌBOXcoaYݟ>O;&?6\R`v+,mSpV[HH!Ld899un`90qkݿg=^^ 8xۡegK$N74R }ipҾ%-fS S=&ϧRU$pGiI&B(`O=wm<Ю XV88^=sIy'FE@vѴHbPvsZKk\8ߚBsMǡu(;VEiEq sZ BV*"uSsn,HkUB.k5:{[;w  }r9.~xU,{$ nMA[$|HDdt{Wӓړhl*SR׬Am^U W ]4}w2roJr$/M {sr#ws rF I5KRm4eݕx-לW< c\ ׏XZh| 420t򘲎6QZƮ)\A VíbݭsUd&8sqVl'?Y͖GĹa$tF4gba\WiLRҤX,zV;9YMXلm!PaHrߵTmyFbpZj\+ 勱֋]DF_y;tSwC[YrHfUk`mNI%W%66=.,Y%O>!"2p3$WxKbac$}魌tg<]"%6%!Ќeč>DP,7QE<+0 vGuM+.Rs,ccSz\RѣM_FE>f LaV! !5 ~u\ZkIg3aX#mLL{ZiǨ_2E46kqҝ?]l9qN53thcA+ֹ*ӷBMͫ1fR9acGQwк ̗,N̐tVIxKBFJM3&j(cʕܼ-®Z0tG."P4nʃɘǧY7͒ΣkQ?'7f=,ECpǷTZG^6 6=F;ήl{ݙ&.Q/e_0p+a{m=sbO~#M(m]?J=i ķb\ZВ*u]g\kc&t'Ac4(}g'5^[]@ 2Ik?{Φ%02qM)S$r1j,g2_o湸Ѭ@CHk6{q{W|=";Y>L%dԃ|FN:?Ixck9'kQ*ʇTeY^ /tf5 (TIrۘnEX0 |2ۨ='n;xLGMs5fop[8]$1afGpAbON}͊>ol.kopO5~X+!ujnegLv= ~鯡?eOXK\\=Ϋ<y0rH(hgU8ooюD13SnfE脒Mܑo8 81M'JןC>Vl (c&ڬv\(rz N)Ybw ߴ scMx Jz<!|F {ԅ"6dSJ<!GdSFe@O9*9{Ǣ'!는YpF9=vv8hth_\*݊ z/GέecƀV-Gz-a8-di&Hp繯>z$\+֣h&2wS="\~"ktR6J9\QV#qB8oc@pƓ 'mUߛlU&;2?}<J8y,Lw%CmCJM~/k:/ss;]˅[%Ό:o> Ŀ`KS\Ȥ|Eih([ڢ&ʈ5{?ݟҮ詶zI9 gďm>jqe^幛rA\qNSOR+Խ x$RT.xֽeEd@eޝ7}; 2FjUW 1Iu@ WhV\\M#'ӶBds{qοxC]IJRǮ)8#!%0B4`>l:BUI>Rm¨U*~F{#)<9h #[ct,R1y!A `f"3ndW8"K*Ȫ.m5JbH𯁤.mgk*K*PmД~0ԅ}v,jͧY92j7|)F`cR Z ?1=烉 \+>x>QH"0k3|=&Ugcuܤש=*ZO6"A9'׃ecQz@qϥ+'ﯭ#=h4Ӭ9'<|CcZy\vOFRARإwH7oq9d# !" =H_O)y\qGTyZ-\pઝÊ6)۱:\9洭@Tg<%J-QZ6Hg3Od[[Tpsi8 猎Gj-#"esa) :u1䍣HE 9faV^Gb1]e8Cרf% UI64Z6"L`9DdO*7Sdoʳmrjm9jv1Y=ҹs?.rkmLd-2za:Niٚ(bkKysBX GQѭoC jFr>iᘤOnM"7<9PO{[(oЦeb$wʲ'Rf)Xnm?=+\u x64"Ppxt'hiJt;M:Q"Np@4r D>qCkEͪ$n%Ө2/ gI4`ێƮ1]O*|3VojNX\_sjree~cH{8 z٤\ ǫLo#>fWy|A6۷nF^&G+uWP|=F#k~|{W3–~+phpŗU;H xv2a,8nT~r?U!tOV9zza^4Щ$RkhS;V?z\cVA9fSȃڎq,+e=X[6m`9y{XZaHA^Dr$_,\uZkEtu^&E(J8:ƺM6mʂVdg RʡLqP\7H0Coµп컒Vc~A^B::gִ W%DRqMI[-K] ܾ{Vd$"mHl}>Kc;7#sa ;G2+4\LߥrZ޶/Krxf?+=gW[e؏.:OE ^O `W_)}rkDQl$WY6o-".`9Ҳ|ӜU^$y<ӝoLQL!zxQUIj6c)-uK/!0HgpRP~F{^׵51)E[U-$mCĿ{)cGzFp5~ O1Ԫ9*X*63D=;SQ=+s"Gvr8ԋIm=֑s7jg4^"W&`I?xg5q=xUfmLROqʬeۡ#MmU2>|GkťSyb0wo#? LAH Sk ?)aC`c2p ' Wcp猊aYk{>i2Hquǵx*mҸy`ui8'dDNx<x"=?Rר+: sQ^ݬ|} 8Fޜh)a$q8cP2upx,IOʧ~=CoSK7>H /9#L8x0ZBUg0gHA˗ݝ0Î[?֥w}q$~dV,Gkj5&ʅ7c OTn5~[sb&mt;gܚ~2prLFnGP a?~[ wcn? rdƛ cwNҒZۓpBiߢ6Viɔ #Bqe7@\!%D=~q dTu?>8>O ?ZɋCvا'iA)#r*#8=+rQl@uCU𦕬!x?hNxM-,M, œ[ƺGaA' >R]cpZѪj캚 x_S^kGJoqpP#)5p[یJ$CZתwF#ڞ_嘓uFbFH#}hY _z·cKגZ]ş2Y?RBxO3@R b+mV>|g;P:9>,xG!7nNǚ8ie\ۺH?;OJʋ8p?J+4•6ѥߴH#Z6"UQYTQpnx#ZѰhֹR4WXfY<O|򥄄(G&cA# 1mN2Ki"Q7DiOL4Su98ǣQkij섓4WP ~f K:Uk5Z&W鏭rVltѯњt:G+W4}y@U%S.ߡ֌Vz3KhAtPeiЀQ`{`֑KUW0֍* :z0vVW!_ay$md+g|MEmm4۬2vYvִZZOc|AyenlQJHc3#N`\+U5V: /</FS <$`PCu6TO?cxWRD#\E gcq^$&gyOe)[ qs6,lU0<ә 6@ Ep#O>)Cmk,]lҐSH\8f֨ܰ`s'j#*$cv ұf6@ i3 G)D{QH2@.xz.Xr:Z0Spб0mDZȥq8y $nD_'==Eա& ,#cl̓A\^٤Rs*1nT߃ZCc9Oqo#x89^5f缊8Ģ7b#X+ei], <#7oiw[S[{}IB? R]Ӫ@ߏcҵ}En %?JVG6VH7c6i4, u\ɉ pZs(lyuakjj-~u]0w#uu]CK(}oy:jX1B =zqMbv, ڽ7k¥Tmj2TqN+n hڇ=oBqi["d`1I$ypzM+1t4' Sf2V-O 28=+j:6FF}C0{hW ٍ0&@HXn0J)"la[~:0y~kFD򓟗`zJr )kaK2p3Jd`rzl\Zczp9rzSn lϧA~_OnGjU~Դ@8>$Rg܎8+k$F}ݽTިsɢދ2]x 8t'[$F:*vU5)FΛ׆=BGK,|jQC Vx_ ӽ#6985X ( .9zs+\~4z)"rB\cVgȅn6cG_zb>;R#d3^Cg\b9Or>'JZ ᗓy8 iӬJ =3R=>*Sɥ)'.E[zgtk-"X,= >d$-5E)݆M{Ԡ/wc*޻c/"둊xCD<]}qyMsI]iM G-Ab6AV*(;3mXRԴWW:TV\d.HSSUptznbX[ò#3^1{`˰v{ T{fb'@W~%hG[o1-ynHh&d?·m:{}N XaC*᫲0߲( w(AM>>F]՚)Q`=[(Cխ #I[ lu#?ϥk[)=H]l7\q֪0wL5Uv>QI>&]/vQj&~`p=]3̥Z݁I_}E7vl۽NN@pu#OD-m " }Bؼ (i`&skJxEr+G:Hg TudLŕ>ߧ*!Id(9hW+Fc@b>֪K*?Oީm[pB_Bhz*}8Vvw(deq=\[]NL*B VLdx3?u6wQDp(ζe7AG~ MLfBDSyH$.} Te/x$%\1ޟQ#[nţC0*X׾"H嵜oʓds}5 4ɒ'!?Jj7\.w(~IJpiF/ؐB+t}5hI dsϿZͱJ'~s|i rYs& 5ZHmșI\dt~j6WBHN{Ԯzr  ]lONƤW9p;"DnOx4.it"F@d0NS)$AbcHP 3Hp. qS^Änu>&ij/B;[.v/ *et~6_|)veobH`AaN+׾\$%%1DBJtdΊw!C4 yɬF4+/5;X4Www6Ј]qSG?*-4 Z4Itrಯ;%o.OI`|pVm"1\iN[ MHf2z0,OBqHNGz: Mw& d<7īM:)y.ܽ뛳c?GbXf6ܓGt/u+<*jV,GϊV~F?dY jY_غ[H;j/OԷZ˧wZz(;"EWxKAcVka2p? -U%Ye('[.3axErqxFwwP쑐c<q1c/o5A0h,@=}W>v@RTn5GLBԤ#1H tbuݟAڜ*pxG-&N0RBҁ!cpqs׻mYXٜ0Tu:Ӥ9$x4 + ,80(meiWVe,G_R{PN#fqj򥶳{m+I"c8]^L} k iP$1Rj.!ZSRf^?xP B &gLC=^ȦSiX 1ׯa\lu˨}O\!y\qђѷ9>JxkJ֭Ulgv$B'ՋwL2iX4 5oV%dK.MJ qK`E /y9snRkWKf̒B β/ .P߄aE̷e$y*sךl-S0 +O56`}UOᕮm7u0LHgn=B\˕:2Kqomlc$u;4׳4Tp?SQW " (v%ͤwH4y*AJm4:"g-F2S3޷RM/S}[L/k;0|;6?p!8dlC5lȩ6wiKE*6$" r=nj]-̱׎ƭ.i1,uў=SK -pc $#?z7|A=ݠ%[iSA>ET]O5ͧC D5``+ͫG+Hkhpvxt-x'D+wNN,w3`bOqኈ˪ F6oZ&8 dn*K=@JJ̵Ş?+gfRܾfr6w=kξ%hdL0s?t EJI 3N+Gc;p{ƽ6hC>qFzWd.k_24i";FVQGសExKYQTc]=MG7V%d%Ү=k4{ ^o-X<Њά47ˣ5Koj[+Ag\v]Z4nMt$gIZ4gQюךЊHfYT6SJM]ғ/D1lБ#u{4P50`vH[z}nt,+{3(b挎 mJATzVӑcGIM9W?[q]vHEҧD#=ϣ*m3 li<`A48p8n?.Nx5|rIғ-: AkУº!Ĩ1N.~թ͝<?*Uu5)j 8&"9۸gIcLlJ)YVcSjۉj!$F;gᗨ'AeW Ӌy^w5ʵTҒ5$ s3MDQVmVq3u=!7+:hҊ~mBGֻσ~ 6EE'U"Ψ ڳgzkO^.KG+bF?ΔV-ܩS_hv ~ugaf @ſ:o7FmO[!W 13Tv\ԛ2>{|&1] o.^| $^O@?][ٔ㡩n费[L[6x#{TH{8޽Msf8(~Z^@ي'J~0kᯇ:LReѷ#s >ZM5Oy3ۼro)wlzWqeuQ<}y;?R^L߃MY21f0P~o֠T ?/>~h]Ol:6u18>12GVֲ5t{u3OHB[-^wǍ@ܑ?w3m?B7`pMzG%h'sL\ *Ԯ|BC|Ǡ#vM x7\斁f*eFG$BH14lC'R\v0r8KB(:R'҄NГJ* i%#<-7=) 㩯,k8)#On[q =N3Wt=uh>L cg.[i%o\jӽ\.. ^:>*X4 $Z 6Pqϭ~eWVqnӺ)- A#FF+3;t楻 Dvl sNR?t"8:3Zʢ0˱5EZ5]>Kd!sc漮]#Tۙ54 ʅ%ʼ폗#zjԓ-X@=e6DV b"c ?6Q[<O;pf2^QxɺT`y׏n&m"\8)Uǚ6zе;IYDQSBVc\"o=Jl<<b**99Rr猊kސ|cЌt,I#77sY:ko n}X))ܧ{Vla *{7>dO9{B)w Wf8>l5 ܭ )e~}GWR0q+#-$#\<1"9v?vzGqyewe4k jf5_:Nz"h+h0hPB`ks ")ݴ~?Z$eS+"s&ӜI"B²|AdoAzUU: @a[J~HqHi0N4#k[pcs,=ϭexIU.Jl)~iI6a =s77))¬vn<#}$.#Ut9,=+':~HV9 <}+Ӵone9% @B Twg^i1#$~uKS@dӮ Ĵ}@=EY+SiڿfHejclBH޻0vFkzIH=^`J+A\X_nM9й?^ mO'i[R <.zg1 ` )jáZbI"ޟNc1BOmmA.thZ@=qֻR[<9*:-J!Pr+/ǾdvYoAS X$K_x Ú)R92-mݱǯ&? 6~"Q+[a;~F:K jZDעIN#,+('oƶXe\.:T5wm۸pySD98I1F@q1Nr1ޛ#)^dq'EζYѢ|9=8|zL? `!pV,jnZKcb9D%[y U+&d1xK4˘$EdN?#^dk/2mgZeMfsHi:V l9T$w޷m|K*RrGf?m_8x?֠G9b`0IVFOH_J>5U~"p=f!uaUml^ڢyo쭌p,zjFCçL;>Ve{2>5΢cB!ihqcti:cR\)iGËI(O')r{]2~W%1B8kRw?J㛶Ln8}M[~0{Xͽ LpH zƦƔNR2?疅F坶y1b_1Rm3҆NQo†gs@/G$ "$u ^ *-}>%ϋQuM ~u^}oP3$)*I`~׵vG]҃mmQDeѰUHҴ}z mVAӟCyr: Y,\ިQѭ  0 :WՔ. jfxSp+?T]xZO MmmHZ;~C-彫\Xϖtz;y v\=*96?2IfBc%c,q9 z̓E #eÂNp~߈`/iZCʊV.d[82qqUsZndfJW6m-͑(0#d=[Wz[RwA(T8#&;0=s+)ͭYFs<+Q oKVc;ct:KS);r9#FU}*qRHPZ=m*hI zs[;QG@l:{ⵦ)=jx햘^Hsz6kc=SJxIunXrÀ{oF#N7S\W+gvXCѹ喺 =TN\N֎ə9I2ba4AZI Ѓʟݲ108?Q~Q-)?6>ңAxwpAm%%]@;l}2*7mv_\]_rⵃ\-YXZ7VIYY+`#qz;k'+'9:޹d}5\Gw_QXI7Ћg@-y>zMr%V<ȣ8qωr ΓV?NOm5O[6HdDznM{1|tі&_ubA5{M"coqaOx83n~iu!~!Ea.,rdZQ8r2}+#,zRnmʭ(2žPݯ9Zpjh|׺ XX$ܟJzc)E>> [le}8wW71Q*f]ʸ3J9o.Tpz32Xк6#Y0QZEq]?NjOÈ :+H=I++TyJߙcAg.*);3ҥ+-xi0--(>fًH\oxa|$N@5̪,QTA8 h< R[,7qǥDBI+].|_p^ɜٮ Ɍs>8=4.9-Ns.^և4Nz("*M#*[nlԭ)lzA;vFsVW`ԌW>qoG_TsBVCgnΟ$1]M\lʲ?c< D Ux`Z9qJ W%*~黟 V,֌O{U>!Y1V݃H%xȃJT^m&f~%i~$iz6J \{W"JbSYf46Ի?̙wD]0HŞtP䌣-g~iFű(28+okojI9.ibmF>ʍH789M?rU] Yo9 YB'm;#lzO  c =_ =1ZhʊqW;H_7(n6i I J TԊ4삤S+W(pYɭ lL(g#}WAiB칥xf٢']>N7#`I"n W@1 ӎ)3]?}CLFKcqyϨ=*uocԚ[gP PU5ё8sm~liMyaWYWÁnA&ATYzތ29*SItIG9C+Რ27M5Hd,s?tE{SwW3EM[Ǩ%dOp#'ҬCPB$1;0#|зq+Mɵ?קGPvR4_[LKv̵z~t4(˄#$c5׋I#éZ2X,ԴnKkTbnj`Wsų־'Yu5[j'գՏwfS;-3hL\#? Բ}Rr5WWu O;Ŗ&f2³1.bEG, zQYچ ݟ$"rsRN ^)+Zk1J4qFҾHzח{J+nTu_n$j4KcUmtm:{Rxm ]J+ -Y\HU侇fUe$0+Q)g]fMA5i1GGUims>KAڢ4f忐ϭ4q{qvPF+;:=+C\߀:5gSZ񦡬xwE/$eo[t \3ڻMCB(d'cjQp)x>jӔ_T/þ'h1lDQYI&1$`[.U#qJjOӮnHmBHf&;X+-q׉x(ҦvW^1|?2zRv0һч?9ǭ9%S{vKc| A8CwBZǯ ڠ:nV3n3מ׹ Έ>g?"2ïfiKy=z}+潬|kKHH4iݪA5q#4vz}kj8'FǧJiXab?:. bːϥO%%J?f[kbx3*l /)qWKQY|T@-Ed!q#W!#f F/fWOe|ז0Na6 b\Ǩ5nQ[2!!vhшToomd,Kݲަȋ ϹTʬ "y7d6LT[!r SEXJ 0 }.fOSپA|6؃PvVan5E69:iٖVTb{dc4~.Wbn.;RI.HAٜ\>-x ?-E?GqHm! ߏ>LJɡyx-ݧM+ԧV= K7CI{y_h?oَ#go ¥9hyZoc8֡=FFw};W!o麦ڌ#NndHފ?QWfUgʋ y[yR1ݷe'c演񜏘^I [J.﹈<=q9sjw9[ piL~gckP@ dd`zS!~SSh?;@׌cTl-qtsG ԇA'n'͠KMxX)NqO I]\OS/jjG'ORsB}a}i*9-"sІs1UL*T!+$XDvsS]{"*?ot79J*qcp~dyF]N4=k罏#G>պP9UӾ1\+eU42&۝'4nlu5Ϯ4?mo_[-N;RUsz_nt{՚"4isǨAI%~n m;8nI0է(' NQt^s)>8'o"U K`NzsF_XzY^6*6nXk7Q8@g5u8걮-5k9xތS>G,I6mcqӄVV_^#C:d0Yi<՚gBq9#w~HcIqWLo]>!6yGF]ţz3W1[s}p&e6g[n1K0|AٍrY?Z/ x~(R(70t9#:XW[-0—62DOcgUjR\xf+Y%IJ킞 2*e{F?F #h^26C-ֱΨGMݻ ?׮XZ =gKYbB;|J/f(ЏN>!Ʒn-H?CPOW%|+_~tՓZcmqj -y,pxZ6%]%!p \u Tdd)"_aE0yJ>z oO`6I mb@֗.XfpwI%m|K9@d M_َ9$c\.ZػjƱ/9qcJ<$J0 ڶЁIZH:&PVu ˅ʜZz.sx\2+F]wpj<@|ĩUU$ZW&iJ 5xTWK&Dg9enV/'،Wc ed fK?Bs\o#VY0G5v\!Lv+rq*WphؑHdy|Ҙu]Cs$Phb,m)*rW1^q\Ԕ 3)A;R1ך9F9i9<`+ī~V+u0̜た³Ff8k{UЏ1A²uo@q&lW'1+ wGX 6qsrMqgqΫW:-Qcv&k6%̅vavwz[ Qn?Rֈ$xd]>WZ+a C!}9R^BmÎ9S!ӑRHXf1\ NH'76L~A>pemTDUTzNJLomM]N_V`6oj։|_ng!4q#SQҟiڌzmI-oGj#|u%7f$Љ|\@ɵE=N;źxGWuP5V$FaFU>^;r\frk(T3Ё5&jq>29PYJ*Mpݕ:k $}FQ8i Hs!UcФaisn`kǵuVկ–2}wybe"f "TDHj^rZ<rFCڇBtׯxWZ m'q ǜ})>ѹY9ڎ }94o \]!2FHM Vs3IvS5f N;HPXVOPZh5#pqFhd3EA *9Ojv̑q4Gb9b~wY8(kZoZs cP@5#dVfB(lLg<֗l]h9nG$QոZ -R~W SՒWv2>TۉG_mBݏN?·F~cC QvVw*:tŲobK'e:JH %8i6m-cܯ(MV:~5̠W^kE s?yh^&*18EG VH;>v:[&$mJFmI?$C'ğ۹3%}ECU7,C@w)=JQ$\҃$q6O 9=zzjq"}5"w?lNpi.WVvgςIs^[qlgҽ.?C,W?@aϡ5vn@OMrrszU\cXUt؜r6?:x#=}aQE`eqq}O䄄@ P_:޵1Nb_/>+V Z66y х YNGf1`@zv O"hFrI~ʷckc<*F̱:($nV[iW7o,q#~uJ^gz%TkVckve7VLj9dik$2ـ2(=8'UXH۲uG4 VwH}u}nnH؇\ӮݝKXФ pvV wx~qJýԙC%T0ҁ s=Δ:OPLzD\$5 ]X 䁞 v=r( JJ=NWˀS'9Qy$GJ#pw W()f[@F6duP) ;Uƚ-#lʅLlc p9TqD;gmxMZVe.o9qv-M;_hE&vNXszⱵ_~ r@+4Xsr~Ϟb֚-Ŷ FqXӤ> %)dKz ?Y_h},>tE$Ace1Kų\):IIY1uhz'l5 9>PZM+D ÎA]ZLi+O((&9(1hCY|s9pZiFv&9 ֍&tH d Y'1tOiuAu#~z擴2zPl,Pmq7@2O\ҋCzlGjFRNWB!͋$9:N݃NA E{‘NUy*v]F;o$=ӨhWqkgs)S:س98k-96rLw敚/v?pqH']F+d>V`ݓ+EGt;!9'uPI/ O^՝=i;_ ɣ۫Paz񣮛/_ Yu9<<`~rQV2dxg\xfP #ȉpZ%B;d o׆M/EAۡ)XD=IW44& ,6WcXբ@5/SI7v>1E}mZOsܥJLvi#:7g.N.dLnIn$q/$sdJ;ѳ-OƚsM٫<-Z9'+s,ND#kY?uTiwmϘO'Wb>穯,<]x[υ%{Kk}ILiTODmT#>z>by#@};:6ڌ]EȌX6~IWr6zOQv&%U ?az‹/ @'iUŠWӹ=/~{q]$cj+LT}7mJp 3r'SB~7V4f6eu #ϊk&E/0kmŇ!)jR΅' Ԑ(漷}kBƝȱ|yU֮ScuM?_gɈ&D 0Yⱜ2|- <利 ]+F)7ZUʒ sU|/(!^jЋk=GjfGri=WZ6=OHx"aoS͚Ed1S895bFң"n ڪ0zZ[8zʜ~Iѝz8 3Oe; ]mͼؐ+u'y U}曎YUI$8cM;u\_b.Ø`~ITٙS[FNݗKX~.ukyð0աlNkJew2UѴ'I䞀T6WoN٬$Zzl #ޱv5U''=)N_<ޕ(Vh%#\kh?m7LK=c^Q<uc3#'!$Z&zsypdQXUs+M=e ܲl=QkkDԯ[&>a䐨NSiQ [i-evDY$GA6AyRZ&ZVYۧ+ZnW~*l>&9h~WMc3:]ռѹL|}xvPkɆ@/êՄp\Sm=LP،ӑ*=Z[rԙ |J25vFC@ ZМ?`^^YpZza;`VQmR[aݻ89 77 29g➈@2QQ} 9ѽt2 P{f%.RqAEpIkxSMXMJ r1sV%"b`w+&5{.m, G!GQGÀUI䊚z2+\זHc:g3UJxCWI#̊{euBT97ǵnֱq7~78c$IIeoq-sBSP<@ Fq{:[ĦXB'#kCp4ɸ#DEB5·Qn'6"W~beoq4`'# WݜCJXcPm$c4 A卪^?;G7|`tgp`gy͏Uq tY,FP*y[Ḧ0vxc JSL[#*fl_4tH3]?$٬574oF_."S³~#xJOx7RҬe>g;x~\zW8'|OaMGEWofC^GO]6a]nvA][ؔrop7cqP3:wzdm玵k[uz:\:B9bycTw$-!\E`_:\4Nwλ|:> >$k+Ȯ{9F3=HQPݤϗE}:,l/UłJgkͣF68ZqIIW)SоTѵ n6],bGJ䕌{m Mo7B?hvя-_P  -cwCa&_| w&Dv=2[b[bOM3|}Y=rOr^2tzw=2 "g=ݏ(pXO xLsRmӚ)UUGjޡEiEId.3pYUyͨؓ;׏^]9gMu`֬$GX:'#)X2:jwFOsVrx4Œ@R Q^Z}LOV4mKm)w#!wFO(9mJQI-$Ffі'=s`(9c*(b9\u#b|/L4FNCS-YIh#v8 m#!t4GUI ښ0=hkDbm$ӥb~;WN:3 )Zx?vUb Cd4p2O ZW`$Jm͟RpE)9 >1qwka8NFWsf^Ssp)~)hʅHҷ_?ș<}sMW*X|Ǡz)?mGVTȰ6|Ԋ* VIvW%7;rMtRٍIU?*c7ڝͬL qC+('~JZHsX^M 2 ~Us7aOV i*ّʞ/> xRH ?zNW嵭),Lf9'9|& :{#ka%gRC%9V|/KxYUzEv\t1 GRIGcB@=;~y9zo,JIAf0`=Vtٗ슪=9튎R Wf+}ߙR6@$\GxQnmOjȶA"ɭSs|K>JKimI\P9s5'b>򭙷2/PI=Pv2i| 0;̟ZY,Jq5+hNc`LgbqC^ݢ1A\ˇLЌ9Jh (!@"솄eǦ 5B_Z72qІ'ҜHqzZ25[=ڠHQN.BڰXgmN.H)|NzZ#bYN,UY>cth.&a#wS:zjpYXGNX.nO7fb64B_+?1?J{ 2By*+ JO J4vj}ougk$Ca uֺm2xom]dʆb0lϷm/H3YM:$%ymnd\5^:ѿ}RYŶf:zѝ1s,M1咴Ic\lkB vRIx oB-\*Px‚=+0jzFH=h#w'lԗupp@>JmFXOZXoJZ1$J76H'#{ֱ{&FNR+mAOz!-[tռ$M2ѯNQ%u<#Hq3]4ieQ4"nOnpLpj=X܎ћڃ*sQ)'krvH1Z3-A^ E7^}iN,jɒ].^ 8#5 Feu NQzj )RinB@N+.^YXsA_=2##:)Y?^W6}Zysni 88$qI; 4=dM%qQ#)!=q4^Ӑ·bCa4Ue 85|og+q+o I_EHQh/ ۩c9]ךʋq?/Ҕ1=3ҚQst#3)sގaTBA ~1Ww?*''Ž8^cEQ#)Ԍ`Rń+)=6}OeIcg:ʚC0hԞ:S'ebk%rAS]/ǭ[8eI]KwLm 𣊲02Ac\P)5^~$MxwN5# Lvq#k|*׮SϽvCgwkLRuw$R1'.Y s7->8$RʽBq?*¿1BE N3JFO!PH69r V!Uz?JtԼ]sM6OHa$z֕)F9ִYqOG@=ݣx݅xn9TkRXϖG#5j?Sb6JK;~ZԟtnpWӨ/м;ş76֚bAr^̾qZUw:oI40B48.}l\c2_F>uœat)d+I!H4N\?K fjYlN·&DYCVe䠭;3j#mJj@# W$wFɓ '=#. >-R4v?pW?J:M8Me7dRDQyt/?MOQФ[Fȣr2[һS Xg DuF,xyɩ[95(, #`VPp?wEr6m! rApLȧq{ؠʻGlSתPͱ wF 5_~bW p*4SNMoǩ[jlȷ |>sHKʥ+EՖO$3%<D?x{m/MGL#?Vؕx󟃺Z/pi*y`r7;W>)rv&…Vc OCXc% :Ԫi5qN8ԯZБ8P9JpyՏ8&9MuB=W dgPGAޓ(/'BЭgѶWhz@>uYerN2E3PKw)PMS@LtBxFCuW9E뱐n~a֒E9s]MQұcζ`#N2My2ז-Ymܠl}ӸrqUJoelH6v94e,]D%TnfOېZNOSF6?ADhoֶcN2iřqr“E=I6Ŷy0N{RZ5S$m?>d+wdcmŘ/A`54Mz đT!zq^}A쀆Sm j[ <`VHWil u:Z{Py )hexrH"®TBW-t9eNT9?xPu*`c JBCy=҆98iO]JD \?]U-ʨNxj5gFq%HdR/Nq(-5g/eAw}+׿e6\uY5)wsˠco̖f>.1{kC/ ,RþuQ|t!%|?~#hE'; u1ʜ/ZRw1}3]50BMbJ ޺7p+1,Tt_ƽ}aY7*F%<ՈC͹8'ڮ2w?3X:b.7=12N 35vs3Qa#s^ԒGΦ۹qNw&O#kXow"%T+Ig暪0`jF#b(<Hv&q^ itLc;sir8ƿ8xz]9Sp@!qWI5:7w<{iVA's\vE!ۆNHx늗{'%H98^Hsu|+۹Zh;+xTAlтBw*r9<W;[ p9ЮMlkc.x)g~m[}*.Pd߆\躓jVxg%ESU>GcUbZtf[|pGj?F=kⶔRj{)|2#PVva4#|3<õn-؜z~N'Jo}Htt?򟋟 j9)5~]c+xrFlGu?|F*9P{"EQ U8+oطXO?x8[K6W 5<<kR$V JK/85]{fA-׾k6 df=X?mJ9d5֣E$\[ }j? 8X 61mXzq.H?5IdN@]یz.~9Z?-h' b<sWEj͸W`Y9#ݞaTzT#ڰ 6<-;\pGcͥsKs#]+~gbb ޡ>TL?('L[I^$rNT/s\}iαxy<7aKrO82Tlf%i I< U9d IC 9YD`' U #{_˞+#y,$#vc;'D JFx?/$zmox$-RT׎)XF@<҄H;O]w=LC*!UQ=aRB- !Xq3Z6 }*jjZ,Z$??Np{2#voim` 5Fް6Z ' J߭sh0%pAҥU)“Pr84t*yP{RI8+jn? |} 6-1Aiwf8qzzRV5nubhո O@:R2'5k,_Z %Vȥ7aeӌLcsv,ڲх ~T sl֚3Q,8演m]jKlǖy DhNОnx8ɥ%Fx|hYFE+}qZ1R7q1Vy9қ}ۏݏnyf;Β@R{3M< xqc W321u.1KtS}oƦZJ,N?gI#*BG8¬ؖVތr)Qx5/P~߇5Uu.|Gw}+dzy=97Da):XW&y.oM2*'׆uFѴ6{;$ϞSsR=_x/H[ᗶ1&r'8\Gb[x&hc0 bʖaFwgeJzW;wr;Yg2]]^spdGl 8t.+:+:"WƧM׌dӢ - %M /1AI-]OӬ,mܼ(H$u5|SjVht'rh@Ty՚v,hz}Z}`Ŭ  ͷOGE JTt7s DuKӮ8S FU C>va=$D-f^py5$p,k0`8⺣-I?v#UzS0׹k;{;26Q 8`H''eAjV 9)R|N:OpW[%c# /_֝}Q5$6c$c׺hȵYIL8 ,~`G`29Jg۵'FL N8J`G%M4=#$sO`y?Z.c'f?S&AGA]ÜkLF/ q\fH?ҹF\xsJiiCW7+C`҆7ܐësǥ*w4Յ `~&.x!Y3J % s3+EXBWK|'Z_ cթJkvsF$%AuⲼ]io"V߾E<JST[jsZ-Dz]H6721Pxw;luD+o$SHO#ֽ8e5KG-?m] )iH3(o~(5xfGn`͵9+JvxM O) 8Cm-DHߥZlg5-,~Rш`ڒ!pv+Ϡf}LWhcGr>txiцi-J^6-DSm Ϧ*o :S jѻE'W/K&ii=qa Flc ܑ^ 3VO|^ErGWt vRXĻTrO dqB|U~3ijE+þHGGG}*촡W~?*颹U+4$U4n>&&}˘m?*vr۱-^Qs&A2Cb%oc4;yl--GËyLzTzb1,`ddf{:=l \4Q}z^gt@6sBbOC!ᣥpD#]ȬqJTZ 8"<[ԕ #u/F3k09<—qxxQa'}Oz.H=y=}+"dQ rE&ޗv9t P͆ ~C J %Ѳ+vpN p|!; H>%:M]"2iįNfrõLJVzػ-VG'Q{ZҰ2e^ˇ ^ya-oԚdB0P$;~Z2rpY\$y&am8$iaX$JHjdrA#w!WՄB!OSADR#mWn3׊j) #,D(9cɿiX_ GnI&B>~jL6l(=+r;0*#OU8=3TaI}i!tRzee z)E>KS,hl8!9+َ-jIn5+3qb-`@~9=L{)6ZHx ++Phఊh5`~ܸIXֶ 0659Pss֕([QԖS@=. xyN`5[?=EUX"SjN <P}!FU=]6|rN칬}ǭLeTzW ;QL~IO?AD~&yTI:=їqXG?děH:zl5/s;t=GGM̛R58Q}A0 nFc{껵c e'>$ٺ ޛnl.,x\(R}/oCxV MBCW%x h?3OZܾҡZ.gIch0#8yXkz{WwcTq1ZGDd4ojE >g)rz+g#!U;q]8Udc'v BŽxϿzU(IDV{`$`SFAz9qmc] FX 0tmAnFAޔ.CtJJḌᘐI#ia`0Nz{Szj?$,)ֽϝVN[’9җb/@jS-q8\u"V!qҬX߽̌nG5Ûs׾N%4q* Dу¸k+JM{Gci$R,Q,+־5d,73PbU$V7㵴cQX'9w:w!ߥ\oteOzД.&[Yb WU |J"g\jEMb7}?Fy5YLi (8:Zg]e \D& a=vxT-+PꬸoOZ+fӱ;/,QYK\B$>tum:\(Q%gsJX` Txm K_qE- RKֹ᷐ap"eyJК))(;G>-w5Wӡ6X;}#6~G-48A]lR@Br@NϠƇ $js)FskƶJ`zr0d\b9j< zr 1+PđG|y`I8\1dA҂h WzuJ2qޚk Qsڔ7py66?՝ *G9oZ/Sz\ų=09;RSLtp9`g>튱=uhPs]%.VC$"ƤII¡nA8'<,6[ֳn.8M 8;NOA^TwԻxsmGcOU Jk@ݏi@9Dl;E6Kq~N-WRB6l4 >RpVd9%ł(J7*e dŸ+'s6d-s fon!O;xhKK>'ݜYE^GZh#kfr>:R"@=.mE$ c9┐@$ǥ&69t%;5],!2H<TIn}p*hC 8R.q9[K!xʠ_I_q)&>IW~8Ō$-w 9/Qt_9lO-]dž +d ΒJ\WEmuV1Ucku *Uԃ؎.1_+y[!MH@Np8dfGb%ΧX1xoX'=Pqͪ_u?=ҷ:5/v[hMTztHj*+FV[7:v?+o,r}j?yfhQj?M->[BnROc|:5o&}N0mLB>NqCh|:ӠH\moS'PpvoMΫ-- 2\}!H?Դff*8ՍFL&gW:A13ֽTЯga4m,W8($0%OO6wG91$ үa^`.G!#o -ڹ ٜ ÌP$/Ok\NѰ<6(@rh}V8'4O9Q>LsJM8 2G\\OH'GrZ.')\\1רF%;kGŬer~Q950#MƯ ԂA S*2G9W ˦>=EQrIЃq$R-;$OHx8=@ :CdZm`qM8Tvg?vqImTOZYw;gInrq]Y,ͱR#wcyG3Ú,-]\J䕻*\v'*-;|0}+o2N5"?^W?CWimqҮsPV{;y Rqi۹5J.$V/9au;k?L&aBGO#̬v|'No.&Xvo`nv tpE.-==krw?-u&hXI1n` jױvYAo-Dn%0E (BOVMe;vq&ڧk:}8;8ϧ=)\s~nO0{ WJ\cm緡EwrNE!|GOjP'N޸GPlѕTywItȻoA49D' 2Fo`#Ҟ!-w%jC5#4\ =';n=ұ`6͓x43g9kGG)$w~WG*Z\pS:B&Z> ]ok)Rm-6{SǓ'}+\,A } 2teWѡmnPC8e})Ydc cZ3-VD$BX~75 w8➁ d˟ 7r;T*2{Ը?I#JtnGʶ6ʼBy(`9808>"zGjW؎aC/ld 0ow\.}ǠEKتvZ2 ;e*C1JWw?OFm÷ʮ ;{WѝO=~G `X{JΰZ]cXńb ,`v'V]-TJ/ VfaW+{V^k0'1*E{Ȼj%]-tHLjW3C*vGs_@-mkFo^\2!X{sSQ;;O?ljS{iiʊ>Oyk(M2ԵoRRx~s*Gg⃻HOZ隄RBeж?2b=b`GbF:MgV; sQpjCs)ܼ==<>V8+Rrn\0ԩ0C6[}G4јmw@f+E$%Ei*㜎sN,7.yƜEk#Y:Lg{}NGW+vezmnv'ZDd9zֹI#`|>&.>"yҿ3GҭCSgjB'{港IN6)9m&vZvM$v sʓc?vLi,G9z r+Q1zt2pt}BNzPC.T=86My-^=*~Zݏc&[^u9O]p擋dOR;#3c4B7Ԗ?]/|RVzj3'w5{o4( I8P0I'%qKFOoZ$PY5sN3-}r8>>2-,߹Ir[;3ji"Yؒ1$ Dor($6WXn6j߱?cN0+^8V"bcֲpc`S*<,0s\B`l?ƈ6.W-'=Pҽ6/4ZL` 98`?&)rɪjھ,g-;*xw"f+E~uei3{K }:S%HObc˾"'1W|1<+xXbӂ;? HE?j $Oxk aUO@;QNC}`Q,(,{T3MR1)$ϽtA[Fs_SOxG$0<7(،ts[խn݉%4}Ь`՞NO4{eC"Hӏ^kVxfifCǯ4)hLӊFO{'Ov2BBNgJ\K F#Ls:J3oP!c涒kpHYr f8؛GƴGxYI uF?LW6*IΖWk`5!P=9=Zzh.g AぞS] WKS8sJ w *C 2G7 I~(qjvIc`(B+)/u|Aml3*C}HT ,NlVJqG^ZsLԃe1wY3?5M&[ִ[REVu$6s[qFNWF6Ie ǓceJ7l<9x:8 6cϦ tx#5++e?֚7;^: Jf x\ibFq&4[+[xY#6avdh>n?~xk@$vNkxTϔٹ1H#WN"*aF6$npà.~nz:bV1};l`~^+6#sk_Q.:0MOKb;nSiF_[lRqLs@qQ- MhX n\k`wϨ5_gZToea$r|$rМǵU:ӣ6fkW7fS\oIeVhw1;tKSV:q<) 9|}{<zJ̝9\mT+yc`֝դ-$% %|bͿ5۔$G[6uxh 6쑷Qqw嬾+kPIu [u|?Y-birT?μTw@5t OryI7WĄ#;2{g2BAhoXaȒ2G*QpjKPAP*822V"nՁn ?ŊAPE>QcOJ8  ~iXgWI=~Ь_ⶤY { k"d2.Y_%O Ws=m(v73<3qWE.ɫ2]_\E46g*NXX۹z>VK(<6s$i}ʞk@J'ss6rv0b8^l"}ĸa"bBA9X:;x߼ ֢*m/|=ai$%Q%V-ZR[:~dWxd;ܜ]1VQJOzw|ɃdGL g\Uq'9'zՀrFN=+Ɋ9ڐ_q#0Hw Zl~4x{)? r2>R*oGjE%5I(`{RdH8MpXzɀsD䑜mwي[NN9|0ߊm艖Ҳa;H9?ZK,xf ;.|3V~KO;+ ;+mnm5ECY:bjڝ>' ٸʸid[op_lWUtulEcʫq_2xݭi.KK%z<-/ec|c#OĶ"7ݻTTIs#xQ}|',X'dun}y*I>F'&^|1:cН\b&2i6$\<1sd=ib*k6Û%d.W8ν53ia$ٱcץpb[ yďG5im&O6;{WUFt7QL n1ڪM6hNH9#$e/Mf-&->GoBxݜ`mJ7)6KVfs{T!k,@f5TֺUk.o#H'&𶭪Y]_\aǙ Zrї#Ѯr< =?]Z<7^*dfd\ QXN3QOjNH!-mG>pʆg 24E޶-~중Ӏ@qziZRG|o -)p{\%ǭm?fKT9SqEs()>i^3(t/.̊5h!sW'QwOsKIYm̚@;nZh5IzwT&XF>\?J. :=3I=vBC/HA* y D N?D~x[ R2N׿| wc`r$9AY׎`%zĿ7!y[d\DWOR? ]yo_5r}A4P7^e>yEKo6c!lJohVRl%){UҪ99ptdұLTvOBW\+Eb%{Ȏr02= P+F@'#̪QLں[xFآK=Yn2UG`W+qxPg59%A1n鱶N%jZhV2^j$W~sXZ՚\f%o8tbV.eV#Y[!GaF.i]hyuB[Nq~u4!i摤pʟZ)rTs8XAIn$.䑢pN7>8_gҹk4epp- m\} SėOP: +Ep H" 5̡b`HaKFqEIVU#᏶GY׿6'ϧVǽj Xv25T?4Hyi$g?A?fzdsgGz`2l_4%{3=Y)xm&S-Zs&C b}Jnً/TO^k[00o~1Z i'(YʋEKh_EcG9(Cz`H"*}zsX) 7SVtRň^R-3 qy"!GIp֑sV99J{Բgߴ11Sd(g(^A5^׺: (ivb&z왣ĺܹ g۾v?[ӭ/.m{RL2JdYL0TװI j_QIY^Bևu+;Ϗe7:]1I ȏ#Vꭡw?ka<j=yk*켼v+2}ɮOm$gZZFW|cI:Ҳ,pĥ丑jב|z=ٮ./mETۭ]sMϕlzn)6e3޽C/ .9A06q@]wGOZ[ W) 9R)MG ` 6md}Sj6B#c0>\zET"HKVJAsJ%pr}k"uk6RUO>*̫ ޙ ?ʒcS~$m$Xֽ!c9[K~WNG,y/)/6n?-4e.-Ij:zR9_]}>@i2r9IaX<.*d`c )4Y 0*RؘO>x6s޿-NSf7N:Bۊg`񅟊Kl9@Ь+O @toڼjJG\~uܦ"QjCKY 8*Nt6R!A4/E5ݵˆF dpR~%(nln 'a]#ESW$H@9kHk{&voXiK;+Hc_HH y+cHDd#U+gYMkOpfH#v=x_xoRRk1(=V`"0Jw! =W[]c5Յֻ h~5aƒź(n$(^G*QmqpҹgՕo![*hoRh^1nki2#xW zec4L g Vku&;GV2sZecGM=Y:fw0 wn&)dw~'=2GZ箽wsԫjVe3cۡ#Y}2giHmN:1dZW ^8[ '$bM-F0U FIF[լx`d;^?5C+zb(gIQf:x7k$MRCm K `jd6!r~[FǵpPƬvqLVQ"hNӓcݑ29=k>1C{y-:~c+_I]IՖ}2Junb2U M35>n+(Qگ^)$>՚nGzn6vd{{W5҉7iR c\;hM881; k(,IhXQ#n(z\|N^)GZ Ԣ Ek&-mQd5 o>թxKCcGod`3d;:XFyj$-*:rx?h#'Qt׆ODUYkvv~`u<+lFF3K0 v{ I kzsi*@'!z-gnYUbF 2I]g #khW´s뒛2|ϊzcwonoWGqcXe\D۱̧SߜV3]7Vv}+_2x;Νiuyv{:?@K|@nRt-<8idIa{9VVS\Y|mk}Pm.{퓑漖{1J:յf;^5ОH|`yLTrjݳw67ЛCMos"p= m<=G\\#3ފ=ɮ)cR1~%ڴra}c$j'Z;qwk G,;WeRt7sI]xTP`=ք1>a^_[4]Fkqx G?zvdRJ\gy&TMT}Yx=4&EE`=+sr~msK OSk;@ꅣ8QMdi bf܎T1l5ݸd3+wM€r9{ӝ$͞)[BڱU pnvWʽfxAѣ]ɜzښ"HBzQ},++'3|wRhtsT1@56t8!?6"SLmR1*vq1l0Xri@A'š02yS$@ ?fAS$ c#'"8%s[ִ5ٷ4d|ɭq o2i&W$\KV 8/BML GJPIf3CN_v&qI*z`}z 672+L2EbwGCo o8Ksڸ<_QCхR8)9h[V{DE.J$P?XT h d+9 wg뎽k"(ɞ_V߇u+YOJ>&#~e0qq(CK+h!|@pLW-o}iTY_LE]{I h##G 8#j[Qiw? p{ vpXo} sГ֥w <:Q-PGx,gJM7SstWW(q;<#L0\6#\LT~Τ9?S2_x~Z.&DPI UA/4(N_.2<1'ⵠ9k$?Kboei>c# A@/m֣*Utش:* e"U9R'prX+-NܶV?~:TןL}1;My+D"#'=} b盙!v~EUxwo+sj1F2q]Rj~.49M x @Pi5>usERIE&I󧹿|j ƩtNKcf6m&$ A$vegCP[r67{z#>`7/A^(q%yVHQFG\;T%e3|GO࿇:y3#E𽷅tonw 0Ȭ+OChR>?JlG__J=u=6Q0<zC1G* X%Dysh)9K}l9{R{Q 9 U$(UG8xZWRMisuXtt^؆"PI4@M w?\F2{$aʀBT𞠬1M*He<PCpr3ٹ=Q dN0(NZ!3 0שbxZ.S# A^9_Lc,wk7C*unUUZ~chXڞjи0QE<63Du=(cֿ4h)v1P @xr_<3(zUSEIQ<:\DS05)VE9<w)]L™nd1BYysS[K<\`=?S_{̛'Y'Fc#66W3 Yi{ZB|W~mh|5?öȱBB4=k\)OqzWi92X1x3s)y֮j%+/C )PRNO&/0 Kwǯ=guE 8H2v;39$Sz j. ^iOq޼=Ε+-N1?/|TmH:,M3ɡŠn׻.=)nyS5{]~m{5|Kh4?ɶGʼcYj $.9" iifZ$ 3ndέզ%鎒fDKwq/M;h95%֬ {%O,rO5p˙G9Y/-"89 1?Dfu|RWSL"GE?3~?t aZYWFQAJw4*qOIeoZpB`VĘO\~'[hJ2G@I@5CRKx,WgFc篵Le+&S\ú;Cuo(a5/fV2U?xb柼yRF?M2wcwv?ը$?s-:,Rƛp`'?ʽ6;u2!9ca[UؗFM>rc{vL<#>HR-Žfy%r8E_ %r{ZkMu[x.#v;+#5(Z؋yLjƓHma~YY>PW'R-x'-6N#5wwlG׮:qM4-om# ޲~(iJ~jQeU@pa/W &)TJWw/9P#Խ^?ml5o24wA$3;0H"gQ\SEJ2Hr>UٖJG^&!/d]Vg|q0Om]Nѱɽ N_D뚘"wBVFtڜKPk2b9 [|%>XЏLq𪓵||Psg؜O'i*A!PŶ 9M6WCfbApHcCژ f}Ό &]UXP Q_E|=eNndzblj٣Kh)S.tL/[.dU߳2zy*]Cg]-Bt-Bc5uЄzMJ:%gœs>-X!`*Bn v4?IKF85@L#m*0'Bc;sƢlOTJ_(r/88t46ì5k4'4MHuAWV6?k(+=XFUTQ~g_Z6@s5;Fl82/ :sUH#EM0:gz$3u(lgSs Tv\ʑAdd@-|Ycqhr ]rѕT O[vUH5ݜW*iZռNzYG18=ϒ:>6>-{9{ZebUqI;+J2 B2 W OLRp+,\)C㩨o}hH8!x9ua;ֽTx}c7H+ޣiUؓw!`Cʀ){ڍ~JU*ˌQ #4)j) nVHPBν[ CPqI(2q=qB';Cnđ3֞Y@\-EU%[WIZO@yixQkӛ2+ZKwf6%O=xlcpkZU$IBu@џU Sx_kPrsS/a9!W)u7Y;_8V}JzФ#vr 땮@^OwkVpJP\LGV8D<'(iP9M:UvU*zWҟi!yRrB80+oHLg˽mOJ.Nēzrs?ʑUg;F}yMu"G^YOMs8KM;ӄKځz_Q嶣oHNK>4DfkV+gwҊ[-sw7mo( >ދ3\-<~+­N:Gp>!![6i$bAM_]Oӹa2$ygP}{bLc=rx~\Ւ=ےI'=9沵;{(%t(TH£4] #Ю_ϛk{Z.yx#b{ڭjN6vͻ;ڴb{K2xo,|v[G1V1s޽^V$fJM E/,0.d˸Q,JKRt4`e==jj+YԽ;𵽷~$jV-^"C`(>~n9MKIc=ml~"r=54qM]O:~h+xI;4dmB⟈z$t,!C8v $ }Mb駷NWδ ͣ(]G$N5 :?%gW%7nQRQ.PI}bG4:tq-FLgV4 7ֶH@bIlSn]}XXlgܬT@׎X^&-Mk=6-<f s[abٕj H~Gx~PO>=I"TugVHxgbLTr;y-vQ ,Gz#+-ɽ&-B?-r 뚡?oo#A-ەa'ub&ܽ?H@Ur:CJe$cМ~1_ +wެ㜎:VCwhU'NҵO\Qi1t$gK(; Iq6g+&fV#?UQ $LGlj6.a]ֳkYEmׅx/KᱎWfӮ~£ss0ZT]Sɵmb]oSlq+J'늅n7X'Zh&亚z˨ l6d7*'[7ԡ;ӟbsc^N.NHB F9/ $p+F-irDI\Te ktҭDTmC`5WWPڽyqG<޼ΜoeHIi!Hn{ҹ׻fZkr@NR'Pou;$PP2mȌc2 GT/OG_Fj^&Sqr 1"N's\ŏmZht $mwX'ԻëmSmJȊJ '?.igeikn$-#,{׺M`ıI]5Veivxᶟ[jpYs.S;f[^zixvrCIe8$gU^mQvdkz-~º-֩LX>ԟJ] g6Oz&C+~Kh by gUkX*/jEj?v]O\jo$u->U#wR3={АG?)pPj*9D{HqL)988+ؓw>ijMJEj䞃:ҽh2ncژ>8#z*)"c'bmqw=FާuTF9'iyPyֽVx6z#s1۴;Pm;_'w@;~4`,cyMlqڣE CZ39`pBlnpv99>½*6wTKڇA>N3SXlBXd?P&Ogh0T}]gr烎)7PSK$AVv ᾠvzl{<|)9Yx+a?kY;^-?ΞS>rܚp :R$ {zԻAU:$aAޚ&O?SN ۭSz W/\³b:ZQ:NVF[\}}?]SbdWDbu2zEmddA{ӥfFpGQ_{OGk7(a*AAOVҨԬTyu~:Rīs;^kG Pxksx#2:84ky+}gW"mr'ܟZ14sys#sǰrHѝg,jRэ->QxOCy鲘ax\?:৊Tf=UTDJx]{M μm%zZ~GqR+aFf.đ6@XQG(gגH%:SG98eTܡxp\W @o4 KnW8^HRе]j[HF Yc}7M[O L@_$ />IHYػ9 tk\^/I].Kaz?I|;_Eu{gǂ˜ckQa*ik\jV42L ~fVQxy-Nqv(YkKJ[BT74՟mrLxdV̐y!©+ bkj<ҵ${ lzOWNK)!o\c>[FCKPƁdVBp~S޸>3,<4%Dp|+ՇB*ԕqb] .˙/AK70~ 2?ZFH#1VOٟ?^NuPQtl~5ѿ\6OL񶱇x>Y.vDOCTh'8Z959& xNSɫI+Ivd?Ҿu!>L :f-՗T~[#c:A ,c?0?; Cxt%txSitf]Sي`5^sOMF; YA{Eg^ZnB3̾4'q5>PI\/`|ѮGZLγUj]Xj ڕyI=k1ɖn6㿧Vuۡ 5Q_=>.rA*HՇlrsז}ܬ 8ݴ=gKH\qn$J/#b>m'Thc*JStiΔIf$@O>${=:=2۬y?Ƽگ6ӄ @@jR@Wm_SNoDŽ<ޓz؞[Y$F* 玵>{-M)C؃TOUMţף?K'*/b!fU >YA>=kΥ+wJ9<r$զ1\)9…G =H[!sн-<zf>"ldzsN$2㯥I͕ 4 PҎ*6ҲyG zBwB83B8kݦI8Rܐ});l &v}kh į|ɥdd\+E"XVU:0R:]5du>xOwUI=YF Y@X!n W%?ƮO:rS.,m,e6q!U}Һ='Nm_UI'}RIXTٿCkwC;)>$k>C/ uV1ϵMCg߇<)mZu;Y'$ףӿVrו%hmu; V=^OpdeIy|qJ^G= _4|mqY]+Vۯ 3j֔9Gy$s>qelRMgM;<^*JژJn毂<iFk*)IA܅f?T;`E>E'W>eEFgyf"r2}kv*O8=*_-5sp 75s['(+|g m+͏Ǵ›BݪT/4UmyTi֛:{;)8 DXo|lZz6,xz$.abB:n$A"`dVu=QXҧu<0ymXVJeT=jQxzm=zcZ;s%@}+l. 6"`*N3߯^1ލ)FtժIG4:. uS9ϧno^C=?xX[8:XiAB}O8&{>YZxm\q*+SXS}ŪV1L֭Dp>6O)sڦ35Eu  q<R>z: ^!fc׷J8N_*쌫]+މx~OѤFKoVσ<8#kx%q228њVCoktwh?h-5d;S}Ȯ47s0~)Z-;ƷaQvT|5OjK#rpW|͊P"$oїP^0yk/'VP6Pd_^]i/-Smj9x7p1܎44tyZw 8,8|JdSb9_w仛xPXu8piTOSqJ_wݡP 9TwFܖ>zц:s-Z.˪+9jsZHw!W84դ M$*y@Gxr?. ]mƼB\0}mew! TTHPGZ[{9߅< 'id?(]zé4<]iRhx6VC1p4%40AryNҞ^FAN)> ؍G4X#pms7dVcn+ғƲ nD:;|yD#%Qk)śїŰA$|6մ#;fȧLRvgAa8dռwar;妴9[ƚֻxZI5ˋ w FƪԓT>!xP? h qύ7ǵtRj$c'St^ XWgUyL<Һ^W,S#t+RRf#u+ykIGcއ-gf4:+K7JM+P@OeU>+6/+s%Ɗ|)bܖltQSE`3?!1Yn(v9;@jmtec>|czǁ{6JyE+<{%gZx{K&(T }߆esR[Mwl r\7Fzޡ[`H.#1*2⻭LdomdC<4c͞*Ջ"0K#98Kb?vўIFWcp= qJ*ÖUAe댚AS3+%.siAm3y$ "o݅`N1c)XLFx?'-H&FQ464卣b9*2B=Iv<G(U=BەXv-q6.FA^ӭL&SGlR՝v>E=4%) tх!sgO;U`=+گW&sǗ`+AV?Á\FhW'AOqٮ^VhǬ84T4wgiCn DWZBa@'^K`4l!r[X_Ww2~1WIZic~f|1 ұ홣TX'PQr6 Hm^_v~Rr?h!7P+Q_K^).m 1o<~j֬"NY+=t'Ϡ`Mx(dJ9gk1ƌW(Np0I<{/%<4Y)ju9^h)O3|iWFOe!?JM>\೔!a[9-'n_+k .m39 ~2f,:Ӈd<. ɯ> D~9.C؀:B Use< i26K-˩Ш?Ҽ`a;x4 I*#s^9Nb1|s?:֪јAGI|9+}IV[ [=<=YՎſ2A=G$%UkF՜Mh~M+F~QhX~ֹߋpHݥ?#Q\2o1SNև6뷍ۿ^,p<ָl}ZzJ .mcmrbK2,+@#نt xmb AvhBX+Wv>ބ9iǛ{/>_.B n?wZ.}ML6?x6gt-J}ˊ8#s](܇wnӣu*2y!@ݞTdt#5+@vлևl ͓Nó1澂ʑۿHbAsNNy|)$dןљ'?$ ;(һR8:m{'EuBty~՜Ui QW,:}GUaj36iG-b%e]D2ca5Gj>`׭SkѧUdr|Ђf|w 0AT +ML[z[G+@dh`(ߍiZ O|KDu8Rg1#I)NzrdG58$6[ӝZmIJkFSh#bU9/yb4Ck_ w|^Srl/ v#91ciRG=)@$ڣEKw6QOS|#T[u7 Ԍ7?t[n2~^xaC=Ԛ֬x'*} ֨ * Rmr:d9M)[?¾25z)7a4kgی}8?gɩ<=x)ocВ~NO< NAG#jGQjR`5XCM?Hi>Qȭ){Dz-n|E&v$IlQ۩"[FM'~kNvF6EAc#\}g>U͚+Azh#+:f%=]/529OBzըqg7aOo&ӐWާB< 6?Tsxna $`'l&4s⋻XF7zr~4\W x%'7 ~ikm (8 dr{yW>5xjiMQϥeF)y82N;o^X[F=x%{Rq{KCX"''&mEfRQIv8e?i'1"TIq\·mnv՝ehݚag|MKk]Kcv 0GN_u5ȟOXB?YќTR>hlT ՟h:)$4;>z Tv׆ y}*EV ٚZnN' \T}ܖ'etm'Oy[TfyL= jWMjP@LVlm':Sgm9`ϩ׵Z-`lq{s1^& FϬ:8k0늑FNH+%d1I T2䞜b ^qӽ9 Ӛ'}ԱsJ b1Oq1#s&2;<.A gv.@ ^ic`L{7=3ӱW r"$$kC׊!E$Pu{VRҤ(c%奏TT ~6찒.@`Aqw?Go*ӈwa\׺sV -mYO-gJcq(?Ze_jQ0Fk)ArT?)Ӿk]SG4ܮGkPdWVQF@R tV'K RiѼ!"8HdVZgQF|R5Dž.-h6^mz j`*G`w~~%mvXmջc`eWR;c_ |vrVU95х;F@$ed;We(~ŭ;sK-A9sQ Ī+nWdQ6$Py#k8ڟH! kCb퍣۬a! |zc\]! Q-s(lWRxDтO%6sJXʎޤ(mښUHpy"Hr6:POAGUVMēpM=wmɯMO- >S Cnʂqʛ`Ă1'zR#eWwޖ@͞AۖzU&NHeNq3M {c^ǃq c ׺-`9s؀ɞ;v\(1WK0˞x$$;"??XDd}KSs_R-I籋ߢHr9Z>;HCtۂ5R|>cPx2iczVX[ |mҢS wCN GN5=9e[w|PymGN+#GWܐN/𝩈?J-//y I^7%k֭3)EU2T|+e:]ȬH' WŪūu=ȃK\ N!TZ4GIU?Y ;wtF_șay`RkHQ5ۉ>K]So+}Mb]cTIڿ* )n5hnn!BۮH[z5EG$TqG" iR7f#nC 4SVSβi5@5BmWcg%-%ߌ5kvmSïC{=JG $T\KTz)n/Q$W rG^5gK3Ǽ[}[AR^6@;Ո`\2F]=خT;Uhm %v|rzs_=$۱Vrq{F `9֔sӧM[gNkۭn#q"U~r w:]J\:g3»k.L|Kevm1qdFG$&_c_٣K/\#09uX-#X[s,r#( x̙\lK芠tu(ETĈI$CPwZ9C ㌊kvz3 Qjz'ST i$sҗNއpnSҙ S5QǘGN=#1 pE=>Tӯ4^TPFۈ?S`9ʑ7Jc8\Q&)i!BAj X5M[]Co-[2 \^E>[?~մ.4袰_9e\Þ'Ŀ|?i֋&lԚF^1'?[*]vԲԾCTHq3y]݉VW[CO%^EFbA$b|k| ={NݜS|V?;A\'ӯ)G۝Uw0'$2ZTO alveu^8F02ZQRX\_C+^K/,,1Qj}?T[ G| IJ|%Ӌw5Y_=89տg>YH$sN33G}GrS6%_졇͊?u) ) ,}^u($Mk5{{Țb_Aץt*AL/,ZZcj1M>k<"t9`˸Y#)ҸTy[} fQIQ#p#R(P7.>n03ֹ9U~=si:Pn Q^zB_ZMN%h?mYg rqҽ,dbS'yxH7gXVaŐ8aOZ{9^Z!0@v!|sUZRRקzv拦 cв@`3SXҸf1P+=4I,k0`{,}AZ=c*IƤFI5>BZѾ9sԑY zr>& >cx$Иd<)$H^:3H$r5֞DR+i(\&tCcnTU?äo*8湩wg¶ !XNs4K$(>s[~#d{м7%C-2*0QOlWWGf|7QmooAa^Eg|q;4F22H6rp=SZYSTQk> 7S4,ff]^4QNrHo{BГb+erKm`1ɩ-N';?<'h(eI $v^;7@Uln#zT?3JұL9 $tJv1-DhaL[W6ޢJƑ.a A5bm2vRʊHx܄r)8Uѡ'a"5"C PS*w َAʳ|TM \cE6*m$VSv$dv*5xٟ DIN9?{hQ$S>2TS-cՒ<]akSw0.˒Ls]XqR#7̮r++i}2w޿ֵ tb:qD,J?諊 Xϑӫ~ju9/-$1q!WMH ">qjԓ̥{[gc z^HF `t۽qԯ9kZhQ8TY ]jJ$c*d98+4R?ӏORP<~ 9k=k{,YǶkGij$Q2pMiEi.iqMde;; r?MQrYk*۪F_$`.v~2E5󧉴o*ȢC9?xk.IyfVMt֦!ngN?[f.ױezqT ZV5X^8JB/bU; [Y we!05|c \4q#$~4cjrQ\ jO@Q*n4?TբP@縫"*p83x+#!ჶU>m-G) A=JQϽ]~Ѱ89i䌏Z:h ą#ĜR'\-C9Oz&䃚jCbاp;UZVoqߐhM8VAhڎ<1O:vyHIs}kͭtxySeUQq֑c8Vc]Bd}i3Z, :fCu<8!ӭuq WWPOk77TѥkY0qƹ>VqVVg]7bѥzXFu)\`Vi|N4VڅҮi г@TW֝I"cmKy2d ! aGw;}| 'JtjrŤ x3H=;RlotHR[6 h뚊ZVZÏ"'\Uq$}\Զ9*? OS}yo>Ӱ *O^Yo[..^5fh< ]KΥ/ū?LpHL,`Ů.3^E+/#me~zfnnf]-ǚ'8#Jۙ>1xiZ^bgRn,eL7Op5GU5vąی끃ϽDݵ*r?.?$YcY#iʑ*ȑVhpB\שI?Q{I(bjpv{Ԑ3@p]L9u VٚSH$ e(@vlRQVfK씱dqW (ʯAwf-`vw`O-^<y[QI@H) q]-B+[pU Qq1Cv`i D j$WorNm\`o8oBE`~Ri(qМRX!q-uZ%B7bǰJ射`XWBs`簤Y c,s P?x!X+FXv99Twܚ?2EUhzVB6)ȨF >%vǷlWW @#Zq6_#\ꢬO\Igcӹ%cե+#/)nHױR$Y;@ nZvjx s\c+F}:TY!YᷜOO~sesݽd8ϭ"ڡSCˑӡAB9gkXIYXP:VVi M;~+ƕܭ+h) ϧL#k[ΛWv^kS]ZڤIe1sZDA >b1ۧMmds3kڤFXV;9^<'odY8'߰8ӧL}&tqi ?̟ ^s SO؎KʩdOZSzD9`C;,QA܊0=R͗\99AR@Bmi*u Wo{C"euI9D6׆GW;NGnI>3l{I6Wh$OfjU1Ή"r/ u1Np*ͨ_0IGX<sm>OV0rYb2rRhиpx,׉5'U8i؀A^ E/C2-+3 |SXOkkS\dpf\ְ!T5sqPv~b)%{ kX![W]Vש)Tdp?hO0tЃaʞJ s5kVwiA ?x_ FI\Ӿ2h7ED`q#.?e}2Le\2mliC~OpjTբ=$qzjKq~جy9+Ku\ I"duJPy8w=GzxoaZrVO?\SNO~8Z ~YfȕFiyB@"Rr,)'z\19#8HQ7q]TZQgBVP61Vǒw ~uMh:c|:Q1 )]&PeBli>e54Bcԕm.':STuǭ|N:IUgtg+=JH@cR+ugKjHQdP)CA_ҫw.T>cP9[+ZGkQFTӮ+=9GkDe]|Yiك'Rű+u}Ul|oq 0tf#f\IwD|1V]+Vs&",(F>iBW=YԟCr`Ey{օҽR9+:Ԝf"Һ9ֿխ[$d@1+w{i[SK2H{t#OE3Di0T񏯧C2\,Q;\HLh3!Gac6ֳj_/SVz8WF1PhXO G˄s-F@)\ΈJ'V>mrӯw)9'-5UrX;Vu[ONV t_J U=G-1-]Bqf+a* -R+eX4]\]s9MŤIFzZƓҷSֽį?d #u4|Wnp Wk͔vDGBd!1Ң:z皞Ur#:!8S`:G*6qPg. rv*҉b$۟K5N?%)i^^1].s"?ZE3L:iPF~)%m #:xVH00)5wd%yhKm=kwwVz#?.s ^.7 C!ZxyP76l|e^(k{eSUkҏUR J]GԢ(HFj;Q Rvʴg8ϭW}1\]Ngks*A=sӊI_W\z !ڤ-qԧ:h$lKg$uԽ[:dS-Oո` *HgݕʇyG\Ա9&+򁞼|F; "jZ2eX=ELڱt7&Np8i6j fPs隚+B[J'ZsƚG7t^9ll,Mƹ%iQ^ moz5cZХwHH˟^LW&{{dQC")"4^\r.xD׈l{c9`Ij即۠Y^$mhle#i{TDE皉2Ř6zĢi 1`0v 4iTlϊ: G< b$(+F>l 6I2=90.p:⥡k?A?v$VR| bR3OI3סa 1MpT'<', `x4Cp?1^dqcš48eUBFUFqW4V@eP2zWV9ӿ=L#WzT ҷ@ stvIEftMi00zHXs8+I":\zUo;q+`vێW+f]8>F9뚑_}_c4Βp9-`R}k97g{8!xTΛp@?"ANSXmoP0$Ní7Pύ ’w?5ի7lgFK.)!<Ue\9־.)Wz-}#wҵ?q2FAڴ;bZB[ﯧ$k}fPUzJu-봻v6Pcs-)u1eR9E$~?μgE)YjZ-662:WZcsk R"Fpy#(hvFWGYctX̠G?֧B)( *E)54YBI9#9Ę$GeQO^Tς:G׫HS\ 9#$Jg\wgX>*mgӮԲ EڥvʯR]sl{dy;'݁Vց=h$<9IdzۈX(We<Tm^S7ПjQ37Ƶ2)qޣ,M1ckKC̊oRQgm8R1)I C² #R! m ~)]ݘӡPcԞT;ҿT <2~p1D00!c2hNXq sSʯrWGI6FQ}GzU;g-Fq8j7ҊCОilkvJ*5$:d@ZA5k ښ> 8t*~cY`'G)+Xա{ 0C<4l9h&kI<#8GLس]Ň;w5g+P`j2Z#a|{{Kb@#'a$Inq88`NV'i8'94Q_ ޔ9{z\J=J$o9e$Oz$~n)p;휩4K$ڌڛwvTpWE*8(wjqv0Hs^~kStބ#֙h;+W W2WI`s=ic7XCDr=; )NK1)-t@ȎA'{;Ú|sR@gҡi-OP>^[F:w\]wa횕K7x% @ҤrA֒I9 |CѴ*xmYO g#+Úw63#ә#|A}*hD;CJirxbӊm!14>7͎95Q^<ƖImAOjGe,ˎX=q9x@Z`)&y cV?C7?m5 $,{NlTæS!Q\ k`A ׎i|W`[ x@5h(-I9hڙk4!{,I[S\`UҰ:-.T.9%F@#0O0w&V}f?:Uu5+R[)V#Ҧu++B`H'5ͳsD)=HcY?I` Ҍ~rkaĐqA'#Ѱ~GQWQ,ֳ<Ҧʹʖ1ڂ>F&8` Y9Cr}Z~I{SCO^cCaTzz\OJwy«aS5K $YTiR{ڠʱUhf%"dQ#krcxvAm V,19珧SIpR8dird9?͓w6K-RI$LVk5DN:rÌ:I=bv]9uPDCd)Jlq^DЕՎG屝@{םe:݇duS|⭠E?ӡ88ns8#<~in{ 9 CX*M64siEݵ0<skP _KKv\lzē[N)q] ۳3U[kwbrz{\˳1X<5ܪy٤O2(9MHFzՏ6X?v )ؙ }F)1[fa@r[n%▻dh6aW9U1 R ?,SkI-id HpJ>rJ-gۦFJGfsJgd(F)蝙NJ_BvÑT\r3(S|9<7LmEW*S޺qG kR <*@fz4M4C?'@늫'G(NxOܶv+ڌ@8WüUO#Tw4SF]$&mH(pi)C6x g;y#cQ?O/a˕\bCݒ8wkXX%gQ̛IELFW!Oc^'&cɁgKỶn"d~ Cck? ڂFqjZxO`mmSl\-Ine>k1:`jx$`@#LRX@*ejwȿ#=}$(v4h-D繥YI8'$Wч6=DG$Uۏދ %O^9a?Cp?;ΤOHۛ=* 6>} <6[#bTd玝`JO=)ZVuszTV v9fT1BS+[F=;zҗ,cJi}M?%dMD(Fq NVW;ݳR uJ{by0n'<ԁ' Y9$0A6Yls׽K)4՛#5"pHNS+F>ߵNr9;Z&OhZREp~Pr̍}t>eڂ854ݞBv])BLCj`2{_n~ gRֿDl $Cxʀ*}3U5:ttn]JX>UꁏA^ ' wk*oz;xOGMS}LWz|:Fmok Vu/+$/g⦞/ieY*@Arrb5#)6,P9[>a+ջ^Ä,H ,PرPh0~bH4r$$g9C-wz0F:ES% ݝ"_c2V#Ij|V,UT3鷯"9q?x݊q8>F?LҳzYPpBb߻f?=aqBA*j炘Vq<>[k^h%ՋWA9ch$0ɸ>`:X`eE;MOUGS]z5]lu=ÃsںM7O q'vFPKXiYX(g_ȧErϹAO+s֦Y 0m\ƃ*)?w5=swJe)ȊrkRF +$g5zR싄L\>jP`+9n[SasE(lW/}(FNOAORX Kk̤sT7bIOjh5Φsա{{fD $һkZ]g[A lRlB|*?|}N^V=Js uB988'Z؅3A}RMzX .*BqwcZ!'2wRtj";^e(`cMy76~~-yRi[Rӏ+\<;i-jVN8ϧB斧CX<z\2:1+;[K΂۴,W?15wgLɤc;S*hcI+SgףNsV _rwzNX\7tx&4^6K9.%#8ps\C9ŵc1pjS#8sވޤǤug+޶3,P(Q(˞Fk,l8Hw<&KV݁`ri')i jHRp:R݁C=GApu9%y-FvzZr='mE9"t&T&ayO4ꣽ YE(Ǡg@ޛw\c g\ WY7Kg*\aA#[]6[xvNy߯ZFlBBpG *Cإeas{y|0~POr5U&zֺlpFZh@Pzp /NHnwzDu9Vi|"jI1S:zzY  )UeԄT(ܮk#NO ?:@UeYCGhUDj.Z,~Uv$E;?\3ZQ5 f32LRkGO5CqOB9Wtwm&x\yl8"@WJ4隀UTJ2L!!j_#&/rOQ])# R֫kA4ւrx*F{\RyI'4|#N#Q?vM`kKv-y@1օwrOs n8HAf`tn?g }iz=k AӃa_j+AUl}'>6v `rg'gLT۹ЇF#>Y\dW6ނsI0n cMt$BX.z:pm9rXo&nx'7}O"|G:][܁"ywP3TN+:~׵7.:E ۊϖg Pw叆lLk{T@ u>'`ֳn2d S7Rլ#ry~x@+c[+rK L4qW<컀ڱsOC~oΟmEGRYAOebF:Rl7ؐN@0s4&@ .`$99n0bVX`:MhU#&=X!e0;II; h90O^"`ՏvRpnǁBq^x -PN? i%A?PqNhʆGw^N20i& Pۈj兩yP7qSugúi2@5ZEHGZ*ost"4a[Ц W5GF::$N^Gq'kqƟFW&4[EpTqrr"c*7L̙8S~:-c5Kpm]Nf>?JUeˌc rj n?x9S:֭'lJ_*;Ş'yICVb"a,,;2k*czjl]H@ |EMr6Ҽ$M7$z 6nW[c'4|3?Y1m|W g:5WMG(?kKR(Af.H\U_Dֳ0@F7vCk%5g{i,5ۗ] p`@bG9QQ&隄ɫ^%6d!F@o]hhks%Ͳ[܅ \]կciGp~_aMeV#'*MMfVcU<-ulUveHqOҾr4R;SqwgUdxޣ=<(VvkΩe'˱k]@|s*?+˝ܚgL]ǫ:s*9'cӠF7 @$`5v6@95(9㠬I;7HێzTQ?"+;OZ6vrدW%}cSUS(h\@#bGˏnDI8جm8Fsuؕ] ==+NUt`(n2} HSub$*p!m<+Cp$i>֦K8$`R 7g1܊kیaGZSlBԭ$gqV=46B{)A I@^TB1Inv*FpcJS2(@`=) 63"Q{ڀ\8_sAh9\zk[8:Nqz6vgtR5(̃Ԁ)OMzОm,G$shq -ԞP>g̑wg#A'c;M #J3Volں"p9\&XD1ӭR\* wz:Qm5R)\x K&3܌uF .I8R54")*%Lnʓht?^7SS\BW_tL?@(v ݋ֿEhʷQ[\LnkFрd,\0qX:]tYLx_ҵ(WlbOQ5v屭mK{Vd~^j:ݻ!"FwgqiF 68cӭ*\!s\ Bܵ0߁J%f8?z= ;9br}Ul PqYjMzRy29#(Fnֈ*nNOcKreb3MQBFrʛ$gps}'i$\)xPAONF$`'ƉJqwSO EjM %I@72t'Rz5*5;c9)h!ys7Ϋ\=#n:K ܤ'$}~j y#+q{-Q]-kdC+lO6}y33~qo5(rt4]nb#~2~|FgC!w˩Ϸ\%R8Ĥcp85m饩:+tڂYN s?BW.vaє#T놢q܃))u~| ǀsT c;QNa]2<ֶ˟#Y1Gk:9yI`sP~^^I;B*ǂfa8'iƷBo7$@vܶ{> e* d/t`U<ZҶuJ.qb*a9uLǕcWOզ-pc2Oa[BHe~j9hDӼaa6K[Vj{ 2_st=/ 'Mv?*3ڔIzc+[A'Lҫ|kA=G (xhcՃH@{`Q+1ӽ&poSʳv/ XINZ/ni 7cZmGV4(x}x:QZ pH.iX~G&]CvK\ݖ wZd4Wc֥[x*=&B=@ǪJW9!#$p{sYr.gU'P+ BǧZP0Nx=zҗK ]nd`$uƄ iFM ~/Ήb^4eN9Rh$?g!$#C'-$cq׎ޝkXaBTRx7s.^gSvD6tcimE,8Y F #I+Xpc*J 瞔J@sگ\$6: jIõ$}McZDKO0YT*m sp9;1Ve~ê=%XA!tI s:bݑ~<rzNK|ry經Lwق0RGsNXtOjkKmrx Pܨxɦk6%p}1_)Tg':SJ^vd\qkjyz Jf*.s:cN@48hgJmH)]-SJc$ A']Cjay ZENz{Sa$yJ #Z;Ie7{-tboHrY·c&O$8@JܥߡhJ=kJ-ZTyNv#IO2rxGZt:;J o5I?WUb1z03ڹTQǸ&y 9EVJPc}1r\qFj(G$|{ĸҰՌJ@Sڞ& >+:SG&9'(Zh;wۑQKyb$qL8|Xmb'ytVPx}tzd*)FSLC?'ӬmSĽxWgtI#i*=LORLYY)`33\'-OtHݶğ?mFfml0Fy U"TLZw ;$m8<FDx=Fig][[#ҳ$N;Tl"*@Ps-s3֟*"~ wcW(X@a, 1H~M;޵|ce# 8H"nOEˠBwE 9݊{ !W,C1Iq4gNa5pO꽴>}vcɟysԏCw I9sOP4u&' !mLX$tGz¬QkIR[joCy-PE&MfbϵIv& s&y$k'v ܬl:oIJ6ޅ|As\(Q6Ѭq.Nn#9>$]2Q\c'>죚a*g'⫑;,bn>+iN=Y|W+Szq շ%PrG5\%<ݻ j:)N=u5l;pOZ%Kl83۞(@ y\ЊVZɃ()r xţ<Ì!=i4;qVNd`(H/q0Gg'wqϭ [QG׭$hwgҺg{n@ &~e©Ȭj`} PN7n\o[&V zVmM%Ż/ ,#跄uP\Zvɺcqs\NWX]IHYrO5( ܐsTh \xT}n(Nⵝlj0>(@ i&ѫN.r bkD*c@=?oK `LSYN;gDPp9C`y;j4AXRHvXsH# sԨD1yma8.X R8 dZ}8z00K7U?{pc{QQGA!Aݓ[UxR*+h9B@Jt?c@^(IMX\:Uwf4#(6 (?]za3*YW Qоk嵕>;F`aQ 0=j~ }2;}yl~CyGT*Z|KzdghMI&!bQU=?B{yn-.EaFu*յ)kذOE4\̏ʀ 5KTk:S,jQ^XZ@5<ƴX#ZiF=~z/,ЬS hbm?M5slU$Ҭ/ŋ8Y[{ٍ; 4Sm$,sqGZ;@ MY7}OȖE ?\drqvǩ-\w$¤qOwZܓ 0<,u_kSNס7ۡg5ž(dN89dۑNG"d_2i55,q9KL0.n‹aFAjV N(qI}^63LV$r:]`p=8t,Yz ]p>{0QZjd;b^,یRv5+Ŀߌ}*d]r~SɠM[Q :L+TSq*ùC2O~4;^$\`)%UH841X#nZ_$}Mu'mO-i1! "ڜa۱8`O8p}61'H_r1G(cV?֐X{ KGb01ГLk ,3qLKR3(!.pr=j *\g'T𭤙ͺ}Y?.*[иM3'0jLNcb>pC&ŏÞ-Ҋvx6NEI}5ʶ7˞,? a BsdN׭E-!91Wl>4[0αcY63p+XYF"mjAcB jବPV/[I0Ȯ'`ʥM;MoۈVPG 25:8>j- >d āSdx`;i|enD#|Y^G;cdmˋQ랕nh*@~ږqcvy$R7*py,2R3)YEgybyE(U@>wEe|)< PIޫ= =i!`vT;m$,("+ eA\l '9b ώRh!;Pɓ(+/R}c1;yrhYvd)  ݏqORlt4-103W|ٜA)Udq9 CN憉`/Q]fBMLm!c 4Mьrݝ؀mݓN6AE"(6w`є9zy]&,8ޅJkRcx"cMmXZUKj];J۵ "RT$g ְФIKDa[Yd'DҮrB}O)c*ѯFQ֯B6hAk̭W5;oXJ0.u[Xe3Fp~a\ԧnOrwzV"bNZgѡs&+,Ho1Gc$|VYzVPN÷FSUa$㠯QI#¾Vؑҥ6Td@0!qTGӊmv?Xw y9u{\Vbddo1nIu]-{Ҙ. Kmpx4oe`Ѡ!#XOFb^ )>RHIQoݳӄXn@ K=hd \cҮ{ lA%A;TW_eyS`.F;\i#;ɕ䑜qӮa BI$c4oFHr݈4 )J64l g-짧R"('p cB6?*x׵*d/=+YOV) \+Ac`)hkBcjINO#ʣ_5. = =Ĵ?Xv.!?t`S"mSvSxIl=ZXhՂ62:]V<ǤLF 6<;{l $/ˎ9< 5}0Ԫmh2p#R?熜# 6*#u5uc̸gLcUeh\Lxꐻq֫?-nޙҹJe;]*ֈs* 80$#SkF ?sR*4kSG 4e`GsB+ia.GN/t[:vm(pFU\<50v1-/D}Wa٣e[:7};Rw>V^k[ Is>:żڍM`x+;mq9>qXtY]j,[ؕ88iRjpQ#p>.Wib"UI g-yZyw5S|߾JЫq;0>4E2޴!}CHXbygGCFEbN!zCĆ`XR"FnI*I)^a{xq v5@㨤t0DžoZ@9*B7=8X0CsX_N2rG;w=})!1ALGz@NJ(w!UGss1Ezϫ0e2ʼnXH- ;3=ਪA\³袮u:Mv@ d sIv(( ANk5(rgz}*.qI,ԌbhqoJAXP-} !Gi!8GZ6.rWLM3dשnd$ AlqzaszV5&0 v0qJ&PBiKQsK %՛Y*p siE{{Kۿ?Aң8>z [X8b QaB:d WШdX *ρOG|xi*z.b#85+Q?x:5i\ZsS-P:sS]IH>ڶt2dFՙKSЖV槲!|KY,=N>}7$~qa:{[=+5'f4#&mi@ǵoi@.YQ\ʩBŴ:{^q/iAw62I]z dT[`1vJ9քu'(M͑9kԈqS03wDU?D|I_Jx8i8 95GkՄ4c8Ϡ @=FUڼzzsFq(NwOQP4AHݜg_γ{dTP2phe+{Wq5ݕ*y)seN:qFoU#$)%*L\>cȗ`cbK/QOW !?yA'%eP(PJW<#>b2Fy|>KBҠ~T-)Oh Rѩ_VE+حH"-abP~y.wuEzw>nZ"I)Sz Qu؆s1Vod8'4̐,y []H{P 2I?(Aw?|?֚O2xY疂gp[9> >Ԭ1P!z|l+ n' NGN]1JᵏSzBK{z>{Whڕc$ov%p  s`lLa%[p؎Cz y@A do~b\gzW|W%h$ 4CiKCH;_X(|Úp@@z+!esҭ@L }'((i)z <=NOM&bdyXSOd8ǨnÃ)jUrMi_QsŢpaJ-(%v簯A -ʜ0Bak zRyJj )\Ij1x6rr=I6j4T#$C!AzNV<\k|`x>ҖӏOEa*6B񎘨[Ùbz!jE7yМ-ދY'&8:8ĀV;zG x&YGO+PЪcp1ޞ-Է~5kFArWcM@(cat >&2))" dh_install # Must not depend on anything. This is to be called by # binary-arch/binary-indep # in another 'make' thread. binary-common: dh_testdir dh_testroot dh_installchangelogs CHANGELOG dh_installdocs dh_installexamples dh_installmenu # dh_installdebconf # dh_installmime # dh_python # dh_installinfo dh_installman dh_link dh_strip dh_compress dh_fixperms # dh_perl dh_makeshlibs dh_installdeb dh_shlibdeps dh_gencontrol -u '-v$(GITVERSION)' dh_md5sums dh_builddeb # Build architecture independant packages using the common target. binary-indep: build-indep install $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common # Build architecture dependant packages using the common target. binary-arch: build-arch install $(MAKE) -f debian/rules DH_OPTIONS=-s binary-common binary: binary-arch binary-indep .PHONY: build clean binary-indep binary-arch binary install configure tagua-1.0-alpha2/debian/tagua-data.files000066400000000000000000000000401077523320400200730ustar00rootroot00000000000000usr/share/kde4 usr/share/locale tagua-1.0-alpha2/debian/tagua.files000066400000000000000000000000411077523320400171650ustar00rootroot00000000000000usr/games usr/share/applications tagua-1.0-alpha2/debian/watch000066400000000000000000000002331077523320400160740ustar00rootroot00000000000000version=3 # opts="uversionmangle=s/-(alpha|beta)/~$1/" \ http://www.tagua-project.org/wiki/Download .*/tagua-(.*)\.tar\.gz tagua-1.0-alpha2/doc/000077500000000000000000000000001077523320400143705ustar00rootroot00000000000000tagua-1.0-alpha2/doc/engine-intf.html000066400000000000000000002232251077523320400174670ustar00rootroot00000000000000 Chess Engine Communication Protocol

Chess Engine Communication Protocol

$Id: engine-intf.html,v 2.1 2003/10/27 19:21:00 mann Exp $
Version 2; implemented in xboard/WinBoard 4.2.1 and later.
Changes since version 1 are indicated in red.



1. Introduction

This document is a set of rough notes on the protocol that xboard and WinBoard use to communicate with gnuchessx and other chess engines. These notes may be useful if you want to connect a different chess engine to xboard. Throughout the notes, "xboard" means both xboard and WinBoard except where they are specifically contrasted.

There are two reasons I can imagine someone wanting to do this:

  1. You have, or are developing, a chess engine but you don't want to write your own graphical interface.
  2. You have, or are developing,a chess engine, and you want to interface it to the Internet Chess Server.

In case (2), if you are using xboard, you will need to configure the "Zippy" code into it, but WinBoard includes this code already. See the file zippy.README in the xboard or WinBoard distribution for more information.

These notes are unpolished, but I've attempted to make them complete in this release. If you notice any errors, omissions, or misleading statements, let me know.

I'd like to hear from everyone who is trying to interface their own chess engine to xboard/WinBoard. Please join the mailing list for authors of xboard/WinBoard compatible chess engines and post a message about what you're doing. The list is now hosted by Yahoo Groups; you can join at http://groups.yahoo.com/group/chess-engines, or you can read the list there without joining. The list is filtered to prevent spam.

2. Connection

An xboard chess engine runs as a separate process from xboard itself, connected to xboard through a pair of anonymous pipes. The engine does not have to do anything special to set up these pipes. xboard sets up the pipes itself and starts the engine with one pipe as its standard input and the other as its standard output. The engine then reads commands from its standard input and writes responses to its standard output. This is, unfortunately, a little more complicated to do right than it sounds; see section 6 below.

And yes, contrary to some people's expectations, exactly the same thing is true for WinBoard. Pipes and standard input/output are implemented in Win32 and work fine. You don't have to use DDE, COM, DLLs, BSOD, or any of the other infinite complexity that Microsoft has created just to talk between two programs. A WinBoard chess engine is a Win32 console program that simply reads from its standard input and writes to its standard output. See sections 5 and 6 below for additional details.

3. Debugging

To diagnose problems in your engine's interaction with xboard, use the -debug flag on xboard's command line to see the messages that are being exchanged. In WinBoard, these messages are written to the file WinBoard.debug instead of going to the screen.

You can turn debug mode on or off while WinBoard is running by pressing Ctrl+Alt+F12. You can turn debug mode on or off while xboard is running by binding DebugProc to a shortcut key (and pressing the key!); see the instructions on shortcut keys in the xboard man page.

While your engine is running under xboard/WinBoard, you can send a command directly to the engine by pressing Shift+1 (xboard) or Alt+1 (WinBoard 4.0.3 and later). This brings up a dialog that you can type your command into. Press Shift+2 (Alt+2) instead to send to the second chess engine in Two Machines mode. On WinBoard 4.0.2 and earlier, Ctrl+Alt is used in place of Alt; this had to be changed due to a conflict with typing the @-sign on some European keyboards.

4. How it got this way

Originally, xboard was just trying to talk to the existing command-line interface of GNU Chess 3.1+ and 4, which was designed for people to type commands to. So the communication protocol is very ad-hoc. It might have been good to redesign it early on, but because xboard and GNU Chess are separate programs, I didn't want to force people to upgrade them together to versions that matched. I particularly wanted to keep new versions of xboard working with old versions of GNU Chess, to make it easier to compare the play of old and new gnuchess versions. I didn't foresee the need for a clean protocol to be used with other chess engines in the future.

Circumstances have changed over the years, and now there are many more engines that work with xboard. I've had to make the protocol description more precise, I've added some features that GNU Chess does not support, and I've specified the standard semantics of a few features to be slightly different from what GNU Chess 4 does.

This release of the protocol specification is the first to carry a version number of its own -- version 2. Previous releases simply carried a last-modified date and were loosely tied to specific releases of xboard and WinBoard. The version number "1" applies generally to all those older versions of the protocol.

Protocol version 2 remains compatible with older engines but has several new capabilities. In particular, it adds the "feature" command, a new mechanism for making backward-compatible changes and extensions to the protocol. Engines that do not support a particular new feature do not have to use it; new features are not enabled unless the engine specifically requests them using the feature command. If an engine does not send the feature command at all, the protocol behavior is nearly identical to version 1. Several new features can be selected by the feature command in version 2, including the "ping" command (recommended for all engines), the "setboard" command, and many optional parameters. Additional features will probably be added in future versions.

5. WinBoard requires Win32 engines

Due to some Microsoft brain damage that I don't understand, WinBoard does not work with chess engines that were compiled to use a DOS extender for 32-bit addressing. (Probably not with 16-bit DOS or Windows programs either.) WinBoard works only with engines that are compiled for the Win32 API. You can get a free compiler that targets the Win32 API from http://sources.redhat.com/cygwin/. I think DJGPP 2.x should also work if you use the RSXNTDJ extension, but I haven't tried it. Of course, Microsoft Visual C++ will work. Most likely the other commercial products that support Win32 will work too (Borland, etc.), but I have not tried them. Delphi has been successfully used to write engines for WinBoard; if you want to do this, Tony Werten has donated some sample code that should help you get started.

6. Hints on input/output

Beware of using buffered I/O in your chess engine. The C stdio library, C++ streams, and the I/O packages in most other languages use buffering both on input and output. That means two things. First, when your engine tries to write some characters to xboard, the library stashes them in an internal buffer and does not actually write them to the pipe connected to xboard until either the buffer fills up or you call a special library routine asking for it to be flushed. (In C stdio, this routine is named fflush.) Second, when your engine tries to read some characters from xboard, the library does not read just the characters you asked for -- it reads all the characters that are currently available (up to some limit) and stashes any characters you are not yet ready for in an internal buffer. The next time you ask to read, you get the characters from the buffer (if any) before the library tries to read more data from the actual pipe.

Why does this cause problems? First, on the output side, remember that your engine produces output in small quantities (say, a few characters for a move, or a line or two giving the current analysis), and that data always needs to be delivered to xboard/WinBoard for display immediately. If you use buffered output, the data you print will sit in a buffer in your own address space instead of being delivered.

You can usually fix the output buffering problem by asking for the buffering to be turned off. In C stdio, you do this by calling setbuf(stdout, NULL). A more laborious and error-prone method is to carefully call fflush(stdout) after every line you output; I don't recommend this. In C++, you can try cout.setf(ios::unitbuf), which is documented in current editions of "The C++ Programming Language," but not older ones. Another C++ method that might work is cout.rdbuf()->setbuf(NULL, 0). Alternatively, you can carefully call cout.flush() after every line you output; again, I don't recommend this.

Another way to fix the problem is to use unbuffered operating system calls to write directly to the file descriptor for standard output. On Unix, this means write(1, ...) -- see the man page for write(2). On Win32, you can use either the Unix-like _write(1, ...) or Win32 native routines like WriteFile.

Second, on the input side, you are likely to want to poll during your search and stop it if new input has come in. If you implement pondering, you'll need this so that pondering stops when the user makes a move. You should also poll during normal thinking on your move, so that you can implement the "?" (move now) command, and so that you can respond promptly to a "result", "force", or "quit" command if xboard wants to end the game or terminate your engine. Buffered input makes polling more complicated -- when you poll, you must stop your search if there are either characters in the buffer or characters available from the underlying file descriptor.

The most direct way to fix this problem is to use unbuffered operating system calls to read (and poll) the underlying file descriptor directly. On Unix, use read(0, ...) to read from standard input, and use select() to poll it. See the man pages read(2) and select(2). (Don't follow the example of GNU Chess 4 and use the FIONREAD ioctl to poll for input. It is not very portable; that is, it does not exist on all versions of Unix, and is broken on some that do have it.) On Win32, you can use either the Unix-like _read(0, ...) or the native Win32 ReadFile() to read. Unfortunately, under Win32, the function to use for polling is different depending on whether the input device is a pipe, a console, or something else. (More Microsoft brain damage here -- did they never hear of device independence?) For pipes, you can use PeekNamedPipe to poll (even when the pipe is unnamed). For consoles, you can use GetNumberOfConsoleInputEvents. For sockets only, you can use select(). It might be possible to use WaitForSingleObject more generally, but I have not tried it. Some code to do these things can be found in Crafty's utility.c, but I don't guarantee that it's all correct or optimal.

A second way to fix the problem might be to ask your I/O library not to buffer on input. It should then be safe to poll the underlying file descriptor as described above. With C, you can try calling setbuf(stdin, NULL). However, I have never tried this. Also, there could be problems if you use scanf(), at least with certain patterns, because scanf() sometimes needs to read one extra character and "push it back" into the buffer; hence, there is a one-character pushback buffer even if you asked for stdio to be unbuffered. With C++, you can try cin.rdbuf()->setbuf(NULL, 0), but again, I have never tried this.

A third way to fix the problem is to check whether there are characters in the buffer whenever you poll. C I/O libraries generally do not provide any portable way to do this. Under C++, you can use cin.rdbuf()->in_avail(). This method has been reported to work with EXchess. Remember that if there are no characters in the buffer, you still have to poll the underlying file descriptor too, using the method described above.

A fourth way to fix the problem is to use a separate thread to read from stdin. This way works well if you are familiar with thread programming. This thread can be blocked waiting for input to come in at all times, while the main thread of your engine does its thinking. When input arrives, you have the thread put the input into a buffer and set a flag in a global variable. Your search routine then periodically tests the global variable to see if there is input to process, and stops if there is. WinBoard and my Win32 ports of ICC timestamp and FICS timeseal use threads to handle multiple input sources.

7. Signals

Engines that run on Unix need to be concerned with two Unix signals: SIGTERM and SIGINT. This applies both to engines that run under xboard and (the unusual case of) engines that WinBoard remotely runs on a Unix host using the -firstHost or -secondHost feature. It does not apply to engines that run on Windows, because Windows does not have Unix-style signals. Beginning with version 2, you can now turn off the use of either or both signals. See the "feature" command in section 9 below.

First, when an engine is sent the "quit" command, it is also given a SIGTERM signal shortly afterward to make sure it goes away. If your engine reliably responds to "quit", and the signal causes problems for you, you should either ignore it by calling signal(SIGTERM, SIG_IGN) at the start of your program, or disable it with the "feature" command.

Second, xboard will send an interrupt signal (SIGINT) at certain times when it believes the engine may not be listening to user input (thinking or pondering). WinBoard currently does this only when the engine is running remotely using the -firstHost or -secondHost feature, not when it is running locally. You probably need to know only enough about this grungy feature to keep it from getting in your way.

The SIGINTs are basically tailored to the needs of GNU Chess 4 on systems where its input polling code is broken or disabled. Because they work in a rather peculiar way, it is recommended that you either ignore SIGINT by having your engine call signal(SIGINT, SIG_IGN), or disable it with the "feature" command.

Here are details for the curious. If xboard needs to send a command when it is the chess engine's move (such as before the "?" command), it sends a SIGINT first. If xboard needs to send commands when it is not the chess engine's move, but the chess engine may be pondering (thinking on its opponent's time) or analyzing (analysis or analyze file mode), xboard sends a SIGINT before the first such command only. Another SIGINT is not sent until another move is made, even if xboard issues more commands. This behavior is necessary for GNU Chess 4. The first SIGINT stops it from pondering until the next move, but on some systems, GNU Chess 4 will die if it receives a SIGINT when not actually thinking or pondering.

There are two reasons why WinBoard does not send the Win32 equivalent of SIGINT (which is called CTRL_C_EVENT) to local engines. First, the Win32 GNU Chess 4 port does not need it. Second, I could not find a way to get it to work. Win32 seems to be designed under the assumption that only console applications, not windowed applications, would ever want to send a CTRL_C_EVENT.

8. Commands from xboard to the engine

All commands from xboard to the engine end with a newline (\n), even where that is not explicitly stated. All your output to xboard must be in complete lines; any form of prompt or partial line will cause problems.

At the beginning of each game, xboard sends an initialization string. This is currently "new\nrandom\n" unless the user changes it with the initString or secondInitString option.

xboard normally reuses the same chess engine process for multiple games. At the end of a game, xboard will send the "force" command (see below) to make sure your engine stops thinking about the current position. It will later send the initString again to start a new game. If your engine can't play multiple games, you can disable reuse either with the "feature" command (beginning in protocol version 2; see below) or with xboard's -xreuse (or -xreuse2) command line option. xboard will then ask the process to quit after each game and start a new process for the next game.

xboard
This command will be sent once immediately after your engine process is started. You can use it to put your engine into "xboard mode" if that is needed. If your engine prints a prompt to ask for user input, you must turn off the prompt and output a newline when the "xboard" command comes in.

protover N
Beginning in protocol version 2 (in which N=2), this command will be sent immediately after the "xboard" command. If you receive some other command immediately after "xboard" (such as "new"), you can assume that protocol version 1 is in use. The "protover" command is the only new command that xboard always sends in version 2. All other new commands to the engine are sent only if the engine first enables them with the "feature" command. Protocol versions will always be simple integers so that they can easily be compared.

Your engine should reply to the protover command by sending the "feature" command (see below) with the list of non-default feature settings that you require, if any.

Your engine should never refuse to run due to receiving a higher protocol version number than it is expecting! New protocol versions will always be compatible with older ones by default; the larger version number is simply a hint that additional "feature" command options added in later protocol versions may be accepted.

accepted
rejected
These commands may be sent to your engine in reply to the "feature" command; see its documentation below.

new
Reset the board to the standard chess starting position. Set White on move. Leave force mode and set the engine to play Black. Associate the engine's clock with Black and the opponent's clock with White. Reset clocks and time controls to the start of a new game. Stop clocks. Do not ponder on this move, even if pondering is on. Remove any search depth limit previously set by the sd command.

variant VARNAME
If the game is not standard chess, but a variant, this command is sent after "new" and before the first move or "edit" command. Currently defined variant names are:
wildcastleShuffle chess where king can castle from d file
nocastleShuffle chess with no castling at all
fischerandomFischer Random (not supported yet)
bughouseBughouse, ICC/FICS rules
crazyhouseCrazyhouse, ICC/FICS rules
losersWin by losing all pieces or getting mated (ICC)
suicideWin by losing all pieces including king, or by having fewer pieces when one player has no legal moves (FICS)
giveaway Win by losing all pieces including king, or by having no legal moves (ICC)
twokingsWeird ICC wild 9
kriegspielKriegspiel (engines not supported)
atomicAtomic
3checkWin by giving check 3 times
unknownUnknown variant (not supported)

quit
The chess engine should immediately exit. This command is used when xboard is itself exiting, and also between games if the -xreuse command line option is given (or -xreuse2 for the second engine). See also Signals above.

random
This command is specific to GNU Chess 4. You can either ignore it completely (that is, treat it as a no-op) or implement it as GNU Chess does. The command toggles "random" mode (that is, it sets random = !random). In random mode, the engine adds a small random value to its evaluation function to vary its play. The "new" command sets random mode off.

force
Set the engine to play neither color ("force mode"). Stop clocks. The engine should check that moves received in force mode are legal and made in the proper turn, but should not think, ponder, or make moves of its own.

go
Leave force mode and set the engine to play the color that is on move. Associate the engine's clock with the color that is on move, the opponent's clock with the color that is not on move. Start the engine's clock. Start thinking and eventually make a move.

playother
(This command is new in protocol version 2. It is not sent unless you enable it with the feature command.) Leave force mode and set the engine to play the color that is not on move. Associate the opponent's clock with the color that is on move, the engine's clock with the color that is not on move. Start the opponent's clock. If pondering is enabled, the engine should begin pondering. If the engine later receives a move, it should start thinking and eventually reply.

white
(This command is obsolete as of protocol version 2, but is still sent in some situations to accommodate older engines unless you disable it with the feature command.) Set White on move. Set the engine to play Black. Stop clocks.

black
(This command is obsolete as of protocol version 2, but is still sent in some situations to accommodate older engines unless you disable it with the feature command.) Set Black on move. Set the engine to play White. Stop clocks.

level MPS BASE INC
Set time controls. See the Time Control section below.

st TIME
Set time controls. See the Time Control section below. The commands "level" and "st" are not used together.

sd DEPTH
The engine should limit its thinking to DEPTH ply.

time N
Set a clock that always belongs to the engine. N is a number in centiseconds (units of 1/100 second). Even if the engine changes to playing the opposite color, this clock remains with the engine.

otim N
Set a clock that always belongs to the opponent. N is a number in centiseconds (units of 1/100 second). Even if the opponent changes to playing the opposite color, this clock remains with the opponent.

If needed for purposes of board display in force mode (where the engine is not participating in the game) the time clock should be associated with the last color that the engine was set to play, the otim clock with the opposite color.

Beginning in protocol version 2, if you can't handle the time and otim commands, you can use the "feature" command to disable them; see below. The following techniques from older protocol versions also work: You can ignore the time and otim commands (that is, treat them as no-ops), or send back "Error (unknown command): time" the first time you see "time".

MOVE
See below for the syntax of moves. If the move is illegal, print an error message; see the section "Commands from the engine to xboard". If the move is legal and in turn, make it. If not in force mode, stop the opponent's clock, start the engine's clock, start thinking, and eventually make a move.

When xboard sends your engine a move, it normally sends coordinate algebraic notation. Examples:

Normal moves:e2e4
Pawn promotion:e7e8q
Castling:e1g1, e1c1, e8g8, e8c8
Bughouse/crazyhouse drop:P@h3
ICS Wild 0/1 castling:d1f1, d1b1, d8f8, d8b8
FischerRandom castling:O-O, O-O-O (oh, not zero)

Beginning in protocol version 2, you can use the feature command to select SAN (standard algebraic notation) instead; for example, e4, Nf3, exd5, Bxf7+, Qxf7#, e8=Q, O-O, or P@h3. Note that the last form, P@h3, is a extension to the PGN standard's definition of SAN, which does not support bughouse or crazyhouse.

xboard doesn't reliably detect illegal moves, because it does not keep track of castling unavailability due to king or rook moves, or en passant availability. If xboard sends an illegal move, send back an error message so that xboard can retract it and inform the user; see the section "Commands from the engine to xboard".

usermove MOVE
By default, moves are sent to the engine without a command name; the notation is just sent as a line by itself. Beginning in protocol version 2, you can use the feature command to cause the command name "usermove" to be sent before the move. Example: "usermove e2e4".

?
Move now. If your engine is thinking, it should move immediately; otherwise, the command should be ignored (treated as a no-op). It is permissible for your engine to always ignore the ? command. The only bad consequence is that xboard's Move Now menu command will do nothing.

It is also permissible for your engine to move immediately if it gets any command while thinking, as long as it processes the command right after moving, but it's preferable if you don't do this. For example, xboard may send post, nopost, easy, hard, force, quit, or other commands while the engine is on move.

ping N
In this command, N is a decimal number. When you receive the command, reply by sending the string pong N, where N is the same number you received. Important: You must not reply to a "ping" command until you have finished executing all commands that you received before it. Pondering does not count; if you receive a ping while pondering, you should reply immediately and continue pondering. Because of the way xboard uses the ping command, if you implement the other commands in this protocol, you should never see a "ping" command when it is your move; however, if you do, you must not send the "pong" reply to xboard until after you send your move. For example, xboard may send "?" immediately followed by "ping". If you implement the "?" command, you will have moved by the time you see the subsequent ping command. Similarly, xboard may send a sequence like "force", "new", "ping". You must not send the pong response until after you have finished executing the "new" command and are ready for the new game to start.

The ping command is new in protocol version 2 and will not be sent unless you enable it with the "feature" command. Its purpose is to allow several race conditions that could occur in previous versions of the protocol to be fixed, so it is highly recommended that you implement it. It is especially important in simple engines that do not ponder and do not poll for input while thinking, but it is needed in all engines.

draw
The engine's opponent offers the engine a draw. To accept the draw, send "offer draw". To decline, ignore the offer (that is, send nothing). If you're playing on ICS, it's possible for the draw offer to have been withdrawn by the time you accept it, so don't assume the game is over because you accept a draw offer. Continue playing until xboard tells you the game is over. See also "offer draw" below.

result RESULT {COMMENT}
After the end of each game, xboard will send you a result command. You can use this command to trigger learning. RESULT is either 1-0, 0-1, 1/2-1/2, or *, indicating whether white won, black won, the game was a draw, or the game was unfinished. The COMMENT string is purely a human-readable comment; its content is unspecified and subject to change. In ICS mode, it is passed through from ICS uninterpreted. Example:
result 1-0 {White mates}

Here are some notes on interpreting the "result" command. Some apply only to playing on ICS ("Zippy" mode).

If you won but did not just play a mate, your opponent must have resigned or forfeited. If you lost but were not just mated, you probably forfeited on time, or perhaps the operator resigned manually. If there was a draw for some nonobvious reason, perhaps your opponent called your flag when he had insufficient mating material (or vice versa), or perhaps the operator agreed to a draw manually.

You will get a result command even if you already know the game ended -- for example, after you just checkmated your opponent. In fact, if you send the "RESULT {COMMENT}" command (discussed below), you will simply get the same thing fed back to you with "result" tacked in front. You might not always get a "result *" command, however. In particular, you won't get one in local chess engine mode when the user stops playing by selecting Reset, Edit Game, Exit or the like.

setboard FEN
The setboard command is the new way to set up positions, beginning in protocol version 2. It is not used unless it has been selected with the feature command. Here FEN is a position in Forsythe-Edwards Notation, as defined in the PGN standard.

Illegal positions: Note that either setboard or edit can be used to send an illegal position to the engine. The user can create any position with xboard's Edit Position command (even, say, an empty board, or a board with 64 white kings and no black ones). If your engine receives a position that it considers illegal, I suggest that you send the response "tellusererror Illegal position", and then respond to any attempted move with "Illegal move" until the next new, edit, or setboard command.

edit
The edit command is the old way to set up positions. For compatibility with old engines, it is still used by default, but new engines may prefer to use the feature command (see below) to cause xboard to use setboard instead. The edit command puts the chess engine into a special mode, where it accepts the following subcommands:
cchange current piece color, initially white
Pa4 (for example)place pawn of current color on a4
xa4 (for example)empty the square a4 (not used by xboard)
#clear board
.leave edit mode
See the Idioms section below for additional subcommands used in ChessBase's implementation of the protocol.

The edit command does not change the side to move. To set up a black-on-move position, xboard uses the following command sequence:

    new
    force
    a2a3
    edit
    <edit commands>
    .

This sequence is used to avoid the "black" command, which is now considered obsolete and which many engines never did implement as specified in this document.

After an edit command is complete, if a king and a rook are on their home squares, castling is assumed to be available to them. En passant capture is assumed to be illegal on the current move regardless of the positions of the pawns. The clock for the 50 move rule starts at zero, and for purposes of the draw by repetition rule, no prior positions are deemed to have occurred.

hint
If the user asks for a hint, xboard sends your engine the command "hint". Your engine should respond with "Hint: xxx", where xxx is a suggested move. If there is no move to suggest, you can ignore the hint command (that is, treat it as a no-op).

bk
If the user selects "Book" from the xboard menu, xboard will send your engine the command "bk". You can send any text you like as the response, as long as each line begins with a blank space or tab (\t) character, and you send an empty line at the end. The text pops up in a modal information dialog.

undo
If the user asks to back up one move, xboard will send you the "undo" command. xboard will not send this command without putting you in "force" mode first, so you don't have to worry about what should happen if the user asks to undo a move your engine made. (GNU Chess 4 actually switches to playing the opposite color in this case.)

remove
If the user asks to retract a move, xboard will send you the "remove" command. It sends this command only when the user is on move. Your engine should undo the last two moves (one for each player) and continue playing the same color.

hard
Turn on pondering (thinking on the opponent's time, also known as "permanent brain"). xboard will not make any assumption about what your default is for pondering or whether "new" affects this setting.

easy
Turn off pondering.

post
Turn on thinking/pondering output. See Thinking Output section.

nopost
Turn off thinking/pondering output.

analyze
Enter analyze mode. See Analyze Mode section.

name X
This command informs the engine of its opponent's name. When the engine is playing on a chess server, xboard obtains the opponent's name from the server. When the engine is playing locally against a human user, xboard obtains the user's login name from the local operating system. When the engine is playing locally against another engine, xboard uses either the other engine's filename or the name that the other engine supplied in the myname option to the feature command. By default, xboard uses the name command only when the engine is playing on a chess server. Beginning in protocol version 2, you can change this with the name option to the feature command; see below.

rating
In ICS mode, xboard obtains the ICS opponent's rating from the "Creating:" message that appears before each game. (This message may not appear on servers using outdated versions of the FICS code.) In Zippy mode, it sends these ratings on to the chess engine using the "rating" command. The chess engine's own rating comes first, and if either opponent is not rated, his rating is given as 0. In the future this command may also be used in other modes, if ratings are known. Example:
rating 2600 1500

ics HOSTNAME
If HOSTNAME is "-", the engine is playing against a local opponent; otherwise, the engine is playing on an Internet Chess Server (ICS) with the given hostname. This command is new in protocol version 2 and is not sent unless the engine has enabled it with the "feature" command. Example: "ics freechess.org"

computer
The opponent is also a computer chess engine. Some engines alter their playing style when they receive this command.

pause
resume
(These commands are new in protocol version 2 and will not be sent unless feature pause=1 is set. At this writing, xboard actually does not use the commands at all, but it or other interfaces may use them in the future.) The "pause" command puts the engine into a special state where it does not think, ponder, or otherwise consume significant CPU time. The current thinking or pondering (if any) is suspended and both player's clocks are stopped. The only command that the interface may send to the engine while it is in the paused state is "resume". The paused thinking or pondering (if any) resumes from exactly where it left off, and the clock of the player on move resumes running from where it stopped.

Bughouse commands:

xboard now supports bughouse engines when in Zippy mode. See zippy.README for information on Zippy mode and how to turn on the bughouse support. The bughouse move format is given above. xboard sends the following additional commands to the engine when in bughouse mode. Commands to inform your engine of the partner's game state may be added in the future.

partner <player>
<player> is now your partner for future games. Example:
partner mann

partner
Meaning: You no longer have a partner.

ptell <text>
Your partner told you <text>, either with a ptell or an ordinary tell.

holding [<white>] [<black>]
White currently holds <white>; black currently holds <black>. Example:
holding [PPPRQ] []
holding [<white>] [<black>] <color><piece>
White currently holds <white>; black currently holds <black>, after <color> acquired <piece>. Example:
holding [PPPRQ] [R] BR

9. Commands from the engine to xboard

In general, an engine should not send any output to xboard that is not described in this document. As the protocol is extended, newer versions of xboard may recognize additional strings as commands that were previously not assigned a meaning.

feature FEATURE1=VALUE1 FEATURE2=VALUE2 ...
Beginning with version 2, the protocol includes the "feature" command, which lets your engine control certain optional protocol features. Feature settings are written as FEATURE=VALUE, where FEATURE is a name from the list below and VALUE is the value to be assigned. Features can take string, integer, or boolean values; the type of value is listed for each feature. String values are written in double quotes (for example, feature myname="Miracle Chess 0.9"), integers are written in decimal, and boolean values are written as 0 for false, 1 for true. Any number of features can be set in one feature command, or multiple feature commands can be given.

Your engine should send one or more feature commands immediately after receiving the "protover" command, since xboard needs to know the values of some features before sending further commands to the engine. Because engines that predate protocol version 2 do not send "feature", xboard uses a timeout mechanism: when it first starts your engine, it sends "xboard" and "protover N", then listens for feature commands for two seconds before sending any other commands. To end this timeout and avoid the wait, set the feature "done=1" at the end of your last feature command. To increase the timeout, if needed, set the feature "done=0" before your first feature command and "done=1" at the end. If needed, it is okay for your engine to set done=0 soon as it starts, even before it receives the xboard and protover commands. This can be useful if your engine takes a long time to initialize itself. It should be harmless even if you are talking to a (version 1) user interface that does not understand the "feature" command, since such interfaces generally ignore commands from the engine that they do not understand.

The feature command is designed to let the protocol change without breaking engines that were written for older protocol versions. When a new feature is added to the protocol, its default value is always chosen to be compatible with older versions of the protocol that did not have the feature. Any feature that your engine does not set in a "feature" command retains its default value, so as the protocol changes, you do not have to change your engine to keep up with it unless you want to take advantage of a new feature. Because some features are improvements to the protocol, while others are meant to cater to engines that do not implement all the protocol features, the recommended setting for a feature is not always the same as the default setting. The listing below gives both default and recommended settings for most features.

You may want to code your engine so as to be able to work with multiple versions of the engine protocol. Protocol version 1 does not send the protover command and does not implement the feature command; if you send a feature command in protocol version 1, it will have no effect and there will be no response. In protocol version 2 or later, each feature F that you set generates the response "accepted F" if the feature is implemented, or "rejected F" if it is not. Thus an engine author can request any feature without having to keep track of which protocol version it was introduced in; you need only check whether the feature is accepted or rejected. This mechanism also makes it possible for a user interface author to implement a subset of a protocol version by rejecting some features that are defined in that version; however, you should realize that engine authors are likely to code for xboard and may not be prepared to have a feature that they depend on be rejected.

Here are the features that are currently defined.

ping (boolean, default 0, recommended 1)
If ping=1, xboard may use the protocol's new "ping" command; if ping=0, xboard will not use the command.
setboard (boolean, default 0, recommended 1)
If setboard=1, xboard will use the protocol's new "setboard" command to set up positions; if setboard=0, it will use the older "edit" command.
playother (boolean, default 0, recommended 1)
If playother=1, xboard will use the protocol's new "playother" command when appropriate; if playother=0, it will not use the command.
san (boolean, default 0)
If san=1, xboard will send moves to the engine in standard algebraic notation (SAN); for example, Nf3. If san=0, xboard will send moves in coordinate notation; for example, g1f3. See MOVE in section 8 above for more details of both kinds of notation.
usermove (boolean, default 0)
If usermove=1, xboard will send moves to the engine with the command "usermove MOVE"; if usermove=0, xboard will send just the move, with no command name.
time (boolean, default 1, recommended 1)
If time=1, xboard will send the "time" and "otim" commands to update the engine's clocks; if time=0, it will not.
draw (boolean, default 1, recommended 1)
If draw=1, xboard will send the "draw" command if the engine's opponent offers a draw; if draw=0, xboard will not inform the engine about draw offers. Note that if draw=1, you may receive a draw offer while you are on move; if this will cause you to move immediately, you should set draw=0.
sigint (boolean, default 1)
If sigint=1, xboard may send SIGINT (the interrupt signal) to the engine as section 7 above; if sigint=0, it will not.
sigterm (boolean, default 1)
If sigterm=1, xboard may send SIGTERM (the termination signal) to the engine as section 7 above; if sigterm=0, it will not.
reuse (boolean, default 1, recommended 1)
If reuse=1, xboard may reuse your engine for multiple games. If reuse=0 (or if the user has set the -xreuse option on xboard's command line), xboard will kill the engine process after every game and start a fresh process for the next game.
analyze (boolean, default 1, recommended 1)
If analyze=0, xboard will not try to use the "analyze" command; it will pop up an error message if the user asks for analysis mode. If analyze=1, xboard will try to use the command if the user asks for analysis mode.
myname (string, default determined from engine filename)
This feature lets you set the name that xboard will use for your engine in window banners, in the PGN tags of saved game files, and when sending the "name" command to another engine.
variants (string, see text below)
This feature indicates which chess variants your engine accepts. It should be a comma-separated list of variant names. See the table under the "variant" command in section 8 above. If you do not set this feature, xboard will assume by default that your engine supports all variants. (However, the -zippyVariants command-line option still limits which variants will be accepted in Zippy mode.) It is recommended that you set this feature to the correct value for your engine (just "normal" in most cases) rather than leaving the default in place, so that the user will get an appropriate error message if he tries to play a variant that your engine does not support.
colors (boolean, default 1, recommended 0)
If colors=1, xboard uses the obsolete "white" and "black" commands in a stylized way that works with most older chess engines that require the commands. See the "Idioms" section below for details. If colors=0, xboard does not use the "white" and "black" commands at all.
ics (boolean, default 0)
If ics=1, xboard will use the protocol's new "ics" command to inform the engine of whether or not it is playing on a chess server; if ics=0, it will not.
name (boolean, see text below)
If name=1, xboard will use the protocol's "name" command to inform the engine of the opponent's name; if name=0, it will not. By default, name=1 if the engine is playing on a chess server; name=0 if not.
pause (boolean, default 0)
If pause=1, xboard may use the protocol's new "pause" command; if pause=0, xboard assumes that the engine does not support this command.
done (integer, no default)
If you set done=1 during the initial two-second timeout after xboard sends you the "xboard" command, the timeout will end and xboard will not look for any more feature commands before starting normal operation. If you set done=0, the initial timeout is increased to one hour; in this case, you must set done=1 before xboard will enter normal operation.

Illegal move: MOVE
Illegal move (REASON): MOVE
If your engine receives a MOVE command that is recognizably a move but is not legal in the current position, your engine must print an error message in one of the above formats so that xboard can pass the error on to the user and retract the move. The (REASON) is entirely optional. Examples:
  Illegal move: e2e4
  Illegal move (in check): Nf3
  Illegal move (moving into check): e1g1

Generally, xboard will never send an ambiguous move, so it does not matter whether you respond to such a move with an Illegal move message or an Error message.

Error (ERRORTYPE): COMMAND
If your engine receives a command it does not understand or does not implement, it should print an error message in the above format so that xboard can parse it. Examples:
  Error (ambiguous move): Nf3
  Error (unknown command): analyze
  Error (command not legal now): undo
  Error (too many parameters): level 1 2 3 4 5 6 7
move MOVE
Your engine is making the move MOVE. Do not echo moves from xboard with this command; send only new moves made by the engine.

For the actual move text from your chess engine (in place of MOVE above), your move should be either

  • in coordinate notation (e.g., e2e4, e7e8q) with castling indicated by the King's two-square move (e.g., e1g1), or
  • in Standard Algebraic Notation (SAN) as defined in the Portable Game Notation standard (e.g, e4, Nf3, O-O, cxb5, Nxe4, e8=Q), with the extension piece@square (e.g., P@f7) to handle piece placement in bughouse and crazyhouse.
xboard itself also accepts some variants of SAN, but for compatibility with non-xboard interfaces, it is best not to rely on this behavior.

Warning: Even though all versions of this protocol specification have indicated that xboard accepts SAN moves, some non-xboard interfaces are known to accept only coordinate notation. See the Idioms section for more information on the known limitations of some non-xboard interfaces. It should be safe to send SAN moves if you receive a "protover 2" (or later) command from the interface, but otherwise it is best to stick to coordinate notation for maximum compatibility. An even more conservative approach would be for your engine to send SAN to the interface only if you have set feature san=1 (which causes the interface to send SAN to you) and have received "accepted san" in reply.

RESULT {COMMENT}
When your engine detects that the game has ended by rule, your engine must output a line of the form "RESULT {comment}" (without the quotes), where RESULT is a PGN result code (1-0, 0-1, or 1/2-1/2), and comment is the reason. Here "by rule" means that the game is definitely over because of what happened on the board. In normal chess, this includes checkmate, stalemate, triple repetition, the 50 move rule, or insufficient material; it does not include loss on time or the like. Examples:
  0-1 {Black mates}
  1-0 {White mates}
  1/2-1/2 {Draw by repetition}
  1/2-1/2 {Stalemate}

xboard relays the result to the user, the ICS, the other engine in Two Machines mode, and the PGN save file as required.

resign
If your engine wants to resign, it can send the command "resign". Alternatively, it can use the "RESULT {comment}" command if the string "resign" is included in the comment; for example "0-1 {White resigns}". xboard relays the resignation to the user, the ICS, the other engine in Two Machines mode, and the PGN save file as required.

offer draw
If your engine wants to offer a draw by agreement (as opposed to claiming a draw by rule), it can send the command "offer draw". xboard relays the offer to the user, the ICS, the other engine in Two Machines mode, and the PGN save file as required. In Machine White, Machine Black, or Two Machines mode, the offer is considered valid until your engine has made two more moves.

tellopponent MESSAGE
This command lets the engine give a message to its opponent, independent of whether the opponent is a user on the local machine or a remote ICS user (Zippy mode). MESSAGE consists of any characters, including whitespace, to the end of the line. When the engine is playing against a user on the local machine, xboard pops up an information dialog containing the message. When the engine is playing against an opponent on the ICS (Zippy mode), xboard sends "say MESSAGE\n" to the ICS.

tellothers MESSAGE
This command lets the engine give a message to people watching the game other than the engine's opponent. MESSAGE consists of any characters, including whitespace, to the end of the line. When the engine is playing against a user on the local machine, this command does nothing. When the engine is playing against an opponent on the ICS (Zippy mode), xboard sends "whisper MESSAGE\n" to the ICS.

tellall MESSAGE
This command lets the engine give a message to its opponent and other people watching the game, independent of whether the opponent is a user on the local machine or a remote ICS user (Zippy mode). MESSAGE consists of any characters, including whitespace, to the end of the line. When the engine is playing against a user on the local machine, xboard pops up an information dialog containing the message. When the engine is playing against an opponent on the ICS (Zippy mode), xboard sends "kibitz MESSAGE\n" to the ICS.

telluser MESSAGE
xboard pops up an information dialog containing the message. MESSAGE consists of any characters, including whitespace, to the end of the line.

tellusererror MESSAGE
xboard pops up an error dialog containing the message. MESSAGE consists of any characters, including whitespace, to the end of the line.

askuser REPTAG MESSAGE
Here REPTAG is a string containing no whitespace, and MESSAGE consists of any characters, including whitespace, to the end of the line. xboard pops up a question dialog that says MESSAGE and has a typein box. If the user types in "bar", xboard sends "REPTAG bar" to the engine. The user can cancel the dialog and send nothing.

tellics MESSAGE
In Zippy mode, xboard sends "MESSAGE\n" to ICS. MESSAGE consists of any characters, including whitespace, to the end of the line.

tellicsnoalias MESSAGE
In Zippy mode, xboard sends "xMESSAGE\n" to ICS, where "x" is a character that prevents the ICS from expanding command aliases, if xboard knows of such a character. (On chessclub.com and chess.net, "/" is used; on freechess.org, "$" is used.) MESSAGE consists of any characters, including whitespace, to the end of the line.

10. Thinking Output

If the user asks your engine to "show thinking", xboard sends your engine the "post" command. It sends "nopost" to turn thinking off. In post mode, your engine sends output lines to show the progress of its thinking. The engine can send as many or few of these lines as it wants to, whenever it wants to. Typically they would be sent when the PV (principal variation) changes or the depth changes. The thinking output should be in the following format:

ply score time nodes pv
Where:
plyInteger giving current search depth.
scoreInteger giving current evaluation in centipawns.
timeCurrent search time in centiseconds (ex: 1028 = 10.28 seconds).
nodesNodes searched.
pvFreeform text giving current "best" line. You can continue the pv onto another line if you start each continuation line with at least four space characters.

Example:

  9 156 1084 48000 Nf3 Nc6 Nc3 Nf6

Meaning:

9 ply, score=1.56, time = 10.84 seconds, nodes=48000, PV = "Nf3 Nc6 Nc3 Nf6"

Longer example from actual Crafty output:

  4    109      14   1435  1. e4 d5 2. Qf3 dxe4 3. Qxe4 Nc6
  4    116      23   2252  1. Nf3 Nc6 2. e4 e6
  4    116      27   2589  1. Nf3 Nc6 2. e4 e6
  5    141      44   4539  1. Nf3 Nc6 2. O-O e5 3. e4
  5    141      54   5568  1. Nf3 Nc6 2. O-O e5 3. e4

You can use the PV to show other things; for instance, while in book, Crafty shows the observed frequency of different reply moves in its book. In situations like this where your engine is not really searching, start the PV with a '(' character:

  0      0       0      0  (e4 64%, d4 24%)

GNU Chess output is very slightly different. The ply number is followed by an extra nonblank character, and the time is in seconds, not hundredths of seconds. For compatibility, xboard accepts the extra character and takes it as a flag indicating the different time units. Example:

 2.     14    0       38   d1d2  e8e7 
 3+     78    0       65   d1d2  e8e7  d2d3 
 3&     14    0       89   d1d2  e8e7  d2d3 
 3&     76    0      191   d1e2  e8e7  e2e3 
 3.     76    0      215   d1e2  e8e7  e2e3 
 4&     15    0      366   d1e2  e8e7  e2e3  e7e6 
 4.     15    0      515   d1e2  e8e7  e2e3  e7e6 
 5+     74    0      702   d1e2  f7f5  e2e3  e8e7  e3f4 
 5&     71    0     1085   d1e2  e8e7  e2e3  e7e6  e3f4 
 5.     71    0     1669   d1e2  e8e7  e2e3  e7e6  e3f4 
 6&     48    0     3035   d1e2  e8e7  e2e3  e7e6  e3e4  f7f5  e4d4 
 6.     48    0     3720   d1e2  e8e7  e2e3  e7e6  e3e4  f7f5  e4d4 
 7&     48    0     6381   d1e2  e8e7  e2e3  e7e6  e3e4  f7f5  e4d4 
 7.     48    0    10056   d1e2  e8e7  e2e3  e7e6  e3e4  f7f5  e4d4 
 8&     66    1    20536   d1e2  e8e7  e2e3  e7e6  e3d4  g7g5  a2a4  f7f5 
 8.     66    1    24387   d1e2  e8e7  e2e3  e7e6  e3d4  g7g5  a2a4  f7f5 
 9&     62    2    38886   d1e2  e8e7  e2e3  e7e6  e3d4  h7h5  a2a4  h5h4 
                           d4e4 
 9.     62    4    72578   d1e2  e8e7  e2e3  e7e6  e3d4  h7h5  a2a4  h5h4 
                           d4e4 
10&     34    7   135944   d1e2  e8e7  e2e3  e7e6  e3d4  h7h5  c2c4  h5h4 
                           d4e4  f7f5  e4f4 
10.     34    9   173474   d1e2  e8e7  e2e3  e7e6  e3d4  h7h5  c2c4  h5h4 
                           d4e4  f7f5  e4f4 

If your engine is pondering (thinking on its opponent's time) in post mode, it can show its thinking then too. In this case your engine may omit the hint move (the move it is assuming its opponent will make) from the thinking lines if and only if it sends xboard the move in the usual "Hint: xxx" format before sending the first line.

11. Time control

xboard supports three styles of time control: conventional chess clocks, the ICS-style incremental clock, and an exact number of seconds per move.

In conventional clock mode, every time control period is the same. That is, if the time control is 40 moves in 5 minutes, then after each side has made 40 moves, they each get an additional 5 minutes, and so on, ad infinitum. At some future time it would be nice to support a series of distinct time controls. This is very low on my personal priority list, but code donations to the xboard project are accepted, so feel free to take a swing at it. I suggest you talk to me first, though.

The command to set a conventional time control looks like this:

  level 40 5 0
  level 40 0:30 0

The 40 means that there are 40 moves per time control. The 5 means there are 5 minutes in the control. In the second example, the 0:30 means there are 30 seconds. The final 0 means that we are in conventional clock mode.

The command to set an incremental time control looks like this:

  level 0 2 12

Here the 0 means "play the whole game in this time control period", the 2 means "base=2 minutes", and the 12 means "inc=12 seconds". As in conventional clock mode, the second argument to level can be in minutes and seconds.

At the start of the game, each player's clock is set to base minutes. Immediately after a player makes a move, inc seconds are added to his clock. A player's clock counts down while it is his turn. Your flag can be called whenever your clock is zero or negative. (Your clock can go negative and then become positive again because of the increment.)

A special rule on some ICS implementations: if you ask for a game with base=0, the clocks really start at 10 seconds instead of 0. xboard itself does not know about this rule, so it passes the 0 on to the engine instead of changing it to 0:10.

ICS also has time odds games. With time odds, each player has his own (base, inc) pair, but otherwise things work the same as in normal games. The Zippy xboard accepts time odds games but ignores the fact that the opponent's parameters are different; this is perhaps not quite the right thing to do, but gnuchess doesn't understand time odds. Time odds games are always unrated.

The command to set an exact number of seconds per move looks like this:

  st 30

This means that each move must be made in at most 30 seconds. Time not used on one move does not accumulate for use on later moves.

12. Analyze Mode

xboard supports analyzing fresh games, edited positions, and games from files. However, all of these look the same from the chess engine's perspective. Basically, the engine just has to respond to the "analyze" command. Beginning in protocol version 2, if your engine does not support analyze mode, it should use the feature command to set analyze=0. The older method of printing the error message "Error (unknown command): analyze" in response to the "analyze" command will also work, however.

To enter analyze mode, xboard sends the command sequence "post", "analyze". Analyze mode in your engine should be similar to force mode, except that your engine thinks about what move it would make next if it were on move. Your engine should accept the following commands while in analyze mode:

  • Any legal move, as in force mode
  • undo   Back up one move and analyze previous position.
  • new   Reset position to start of game but stay in analyze mode.
  • setboard if you have set feature setboard=1; otherwise edit. Exiting edit mode returns to analyze mode.
  • exit   Leave analyze mode.
  • .   Send a search status update (optional); see below.
  • bk   Show book moves from this position, if any; see above.
  • hint   Show the predicted move from this position, if any; see above.

If the user selects "Periodic Updates", xboard will send the string ".\n" to the chess engine periodically during analyze mode, unless the last PV received began with a '(' character.

The chess engine should respond to ".\n" with a line like this:

stat01: time nodes ply mvleft mvtot mvname
Where:
timeElapsed search time in centiseconds (ie: 567 = 5.67 seconds).
nodesNodes searched so far.
plySearch depth so far.
mvleftNumber of moves left to consider at this depth.
mvtotTotal number of moves to consider.
mvname Move currently being considered (SAN or coordinate notation). Optional; added in protocol version 2.

Examples:

  stat01: 1234 30000 7 5 30
  stat01: 1234 30000 7 5 30 Nf3

Meaning:

After 12.34 seconds, I've searched 7 ply/30000 nodes, there are a total of 30 legal moves, and I have 5 more moves to search before going to depth 8. In the second example, of the 30 legal moves, the one I am currently searching is Nf3.

Implementation of the "." command is optional. If the engine does not respond to the "." command with a "stat01..." line, xboard will stop sending "." commands. If the engine does not implement this command, the analysis window will use a shortened format to display the engine info.

To give the user some extra information, the chess engine can output the strings "++\n" and "--\n", to indicate that the current search is failing high or low, respectively. You don't have to send anything else to say "Okay, I'm not failing high/low anymore." xboard will figure this out itself.

13. Idioms and backward compatibility features

Some engines have variant interpretations of the force/go/white/black, time/otim, and hard/easy command sets. In order to accommodate these older engines, xboard uses these commands only according to the stylized patterns ("idioms") given in this section. The obsolete white and black commands have historically been particularly troublesome, and it is recommended that new engines set the feature colors=0 and/or ignore the commands.

time N
otim N
MOVE
Sent when the opponent makes a move and the engine is already playing the opposite color.

white
go
Sent when the engine is in force mode or playing Black but should switch to playing White. This sequence is sent only when White is already on move. If you set the feature colors=0, "white" is not sent.

black
go
Sent when the engine is in force mode or playing White but should switch to playing Black. This sequence is sent only when Black is already on move. If you set the feature colors=0, "black" is not sent.

white
time N
otim N
black
go
Sent when Black is on move, the engine is in force mode or playing White, and the engine's clock needs to be updated before it starts playing. The initial "white" is a kludge to accommodate GNU Chess 4's variant interpretation of these commands. If you set the feature colors=0, "white" and "black" are not sent.

black
time N
otim N
white
go
Sent when White is on move, the engine is in force mode or playing Black, and the engine's clock needs to be updated before it starts playing. See previous idiom. The initial "black" is a kludge to accommodate GNU Chess 4's variant interpretation of these commands. If you set the feature colors=0, "black" and "white" are not sent.

hard
easy
Sent in sequence to turn off pondering if xboard is not sure whether it is on. When xboard is sure, it will send "hard" or "easy" alone. xboard does this because "easy" is a toggle in GNU Chess 4 but "hard" is an absolute on.

To support older engines, certain additional commands from the engine to xboard are also recognized. (These are commands by themselves, not values to be placed in the comment field of the PGN result code.) These forms are not recommended for new engines; use the PGN result code commands or the resign command instead.

Command Interpreted as
White resigns 0-1 {White resigns}
Black resigns 1-0 {Black resigns}
White 1-0 {White mates}
Black 0-1 {Black mates}
Draw 1/2-1/2 {Draw}
computer mates 1-0 {White mates} or 0-1 {Black mates}
opponent mates 1-0 {White mates} or 0-1 {Black mates}
computer resigns 0-1 {White resigns} or 1-0 {Black resigns}
game is a draw 1/2-1/2 {Draw}
checkmate 1-0 {White mates} or 0-1 {Black mates}

Commands in the above table are recognized if they begin a line and arbitrary characters follow, so (for example) "White mates" will be recognized as "White", and "game is a draw by the 50 move rule" will be recognized as "game is a draw". All the commands are case-sensitive.

An alternative move syntax is also recognized:

Command Interpreted as
NUMBER ... MOVE move MOVE

Here NUMBER means any string of decimal digits, optionally ending in a period. MOVE is any string containing no whitespace. In this command format, xboard requires the "..." even if your engine is playing White. A command of the form NUMBER MOVE will be ignored. This odd treatment of the commands is needed for compatibility with gnuchessx. The original reasons for it are lost in the mists of time, but I suspect it was originally a bug in the earliest versions of xboard, before I started working on it, which someone "fixed" in the wrong way, by creating a special version of gnuchess (gnuchessx) instead of changing xboard.

Any line that contains the words "offer" and "draw" is recognized as "offer draw".

The "Illegal move" message is recognized even if spelled "illegal move" and even if the colon (":") is omitted. This accommodates GNU Chess 4, which prints messages like "Illegal move (no matching move)e2e4", and old versions of Crafty, which print just "illegal move".

In Zippy mode, for compatibility with older versions of Crafty, xboard passes through to ICS any line that begins "kibitz", "whisper", "tell", or "draw". Do not use this feature in new code. Instead, use the commands "tellall", "tellothers", "tellopponent", "tellics" (if needed), "1/2-1/2 {COMMENT}", or "offer draw", as appropriate.

If the engine responds to the "sd DEPTH" command with an error message indicating the command is not supported (such as "Illegal move: sd"), xboard sets an internal flag and subsequently uses the command "depth\nDEPTH" instead, for the benefit of GNU Chess 4. Note the newline in the middle of this command! New engines should not rely on this feature.

If the engine responds to the "st TIME" command with an error message indicating the command is not supported (such as "Illegal move: st"), xboard sets an internal flag and subsequently uses the command "level 1 TIME" instead, for the benefit of GNU Chess 4. Note that this is not a standard use of the level command, as TIME seconds are not added after each player makes 1 move; rather, each move is made in at most TIME seconds. New engines should not implement or rely on this feature.

In support of the -firstHost/-secondHost features, which allow a chess engine to be run on another machine using the rsh protocol, xboard recognizes error messages that are likely to come from rsh as fatal errors. The following messages are currently recognized:

unknown host
No remote directory
not found
No such file
can't alloc
Permission denied

ChessBase/Fritz now implements the xboard/winboard protocol and can use WinBoard-compatible engines in its GUI. ChessBase's version of the protocol is generally the same as version 1, except that they have added the commands fritz, reset, and ponder, and the edit subcommands castle and ep. If you want your engine to work well with the ChessBase/Fritz GUI, you may need to implement these additional commands, and you should also be aware of the peculiar way that ChessBase uses the protocol. See their web page for documentation.

ChessMaster 8000 also implements version 1 of the xboard/winboard protocol and can use WinBoard-compatible engines. The original release of CM8000 also has one additional restriction: only pure coordinate notation (e.g., e2e4) is accepted in the move command. A patch to correct this should be available from The Learning Company (makers of CM8000) in February 2001.


converted to HTML by Steffen A. Jakob
tagua-1.0-alpha2/doc/uci-engine-interface.txt000066400000000000000000000631431077523320400211210ustar00rootroot00000000000000 Description of the universal chess interface (UCI) April 2006 ================================================================= * The specification is independent of the operating system. For Windows, the engine is a normal exe file, either a console or "real" windows application. * all communication is done via standard input and output with text commands, * The engine should boot and wait for input from the GUI, the engine should wait for the "isready" or "setoption" command to set up its internal parameters as the boot process should be as quick as possible. * the engine must always be able to process input from stdin, even while thinking. * all command strings the engine receives will end with '\n', also all commands the GUI receives should end with '\n', Note: '\n' can be 0x0d or 0x0a0d or any combination depending on your OS. If you use Engine and GUI in the same OS this should be no problem if you communicate in text mode, but be aware of this when for example running a Linux engine in a Windows GUI. * arbitrary white space between tokens is allowed Example: "debug on\n" and " debug on \n" and "\t debug \t \t\ton\t \n" all set the debug mode of the engine on. * The engine will always be in forced mode which means it should never start calculating or pondering without receiving a "go" command first. * Before the engine is asked to search on a position, there will always be a position command to tell the engine about the current position. * by default all the opening book handling is done by the GUI, but there is an option for the engine to use its own book ("OwnBook" option, see below) * if the engine or the GUI receives an unknown command or token it should just ignore it and try to parse the rest of the string in this line. Examples: "joho debug on\n" should switch the debug mode on given that joho is not defined, "debug joho on\n" will be undefined however. * if the engine receives a command which is not supposed to come, for example "stop" when the engine is not calculating, it should also just ignore it. Move format: ------------ The move format is in long algebraic notation. A nullmove from the Engine to the GUI should be sent as 0000. Examples: e2e4, e7e5, e1g1 (white short castling), e7e8q (for promotion) GUI to engine: -------------- These are all the command the engine gets from the interface. * uci tell engine to use the uci (universal chess interface), this will be sent once as a first command after program boot to tell the engine to switch to uci mode. After receiving the uci command the engine must identify itself with the "id" command and send the "option" commands to tell the GUI which engine settings the engine supports if any. After that the engine should send "uciok" to acknowledge the uci mode. If no uciok is sent within a certain time period, the engine task will be killed by the GUI. * debug [ on | off ] switch the debug mode of the engine on and off. In debug mode the engine should send additional infos to the GUI, e.g. with the "info string" command, to help debugging, e.g. the commands that the engine has received etc. This mode should be switched off by default and this command can be sent any time, also when the engine is thinking. * isready this is used to synchronize the engine with the GUI. When the GUI has sent a command or multiple commands that can take some time to complete, this command can be used to wait for the engine to be ready again or to ping the engine to find out if it is still alive. E.g. this should be sent after setting the path to the tablebases as this can take some time. This command is also required once before the engine is asked to do any search to wait for the engine to finish initializing. This command must always be answered with "readyok" and can be sent also when the engine is calculating in which case the engine should also immediately answer with "readyok" without stopping the search. * setoption name [value ] this is sent to the engine when the user wants to change the internal parameters of the engine. For the "button" type no value is needed. One string will be sent for each parameter and this will only be sent when the engine is waiting. The name and value of the option in should not be case sensitive and can inlude spaces. The substrings "value" and "name" should be avoided in and to allow unambiguous parsing, for example do not use = "draw value". Here are some strings for the example below: "setoption name Nullmove value true\n" "setoption name Selectivity value 3\n" "setoption name Style value Risky\n" "setoption name Clear Hash\n" "setoption name NalimovPath value c:\chess\tb\4;c:\chess\tb\5\n" * register this is the command to try to register an engine or to tell the engine that registration will be done later. This command should always be sent if the engine has sent "registration error" at program startup. The following tokens are allowed: * later the user doesn't want to register the engine now. * name the engine should be registered with the name * code the engine should be registered with the code Example: "register later" "register name Stefan MK code 4359874324" * ucinewgame this is sent to the engine when the next search (started with "position" and "go") will be from a different game. This can be a new game the engine should play or a new game it should analyse but also the next position from a testsuite with positions only. If the GUI hasn't sent a "ucinewgame" before the first "position" command, the engine shouldn't expect any further ucinewgame commands as the GUI is probably not supporting the ucinewgame command. So the engine should not rely on this command even though all new GUIs should support it. As the engine's reaction to "ucinewgame" can take some time the GUI should always send "isready" after "ucinewgame" to wait for the engine to finish its operation. * position [fen | startpos ] moves .... set up the position described in fenstring on the internal board and play the moves on the internal chess board. if the game was played from the start position the string "startpos" will be sent Note: no "new" command is needed. However, if this position is from a different game than the last position sent to the engine, the GUI should have sent a "ucinewgame" inbetween. * go start calculating on the current position set up with the "position" command. There are a number of commands that can follow this command, all will be sent in the same string. If one command is not sent its value should be interpreted as it would not influence the search. * searchmoves .... restrict search to this moves only Example: After "position startpos" and "go infinite searchmoves e2e4 d2d4" the engine should only search the two moves e2e4 and d2d4 in the initial position. * ponder start searching in pondering mode. Do not exit the search in ponder mode, even if it's mate! This means that the last move sent in in the position string is the ponder move. The engine can do what it wants to do, but after a "ponderhit" command it should execute the suggested move to ponder on. This means that the ponder move sent by the GUI can be interpreted as a recommendation about which move to ponder. However, if the engine decides to ponder on a different move, it should not display any mainlines as they are likely to be misinterpreted by the GUI because the GUI expects the engine to ponder on the suggested move. * wtime white has x msec left on the clock * btime black has x msec left on the clock * winc white increment per move in mseconds if x > 0 * binc black increment per move in mseconds if x > 0 * movestogo there are x moves to the next time control, this will only be sent if x > 0, if you don't get this and get the wtime and btime it's sudden death * depth search x plies only. * nodes search x nodes only, * mate search for a mate in x moves * movetime search exactly x mseconds * infinite search until the "stop" command. Do not exit the search without being told so in this mode! * stop stop calculating as soon as possible, don't forget the "bestmove" and possibly the "ponder" token when finishing the search * ponderhit the user has played the expected move. This will be sent if the engine was told to ponder on the same move the user has played. The engine should continue searching but switch from pondering to normal search. * quit quit the program as soon as possible Engine to GUI: -------------- * id * name this must be sent after receiving the "uci" command to identify the engine, e.g. "id name Shredder X.Y\n" * author this must be sent after receiving the "uci" command to identify the engine, e.g. "id author Stefan MK\n" * uciok Must be sent after the id and optional options to tell the GUI that the engine has sent all infos and is ready in uci mode. * readyok This must be sent when the engine has received an "isready" command and has processed all input and is ready to accept new commands now. It is usually sent after a command that can take some time to be able to wait for the engine, but it can be used anytime, even when the engine is searching, and must always be answered with "isready". * bestmove [ ponder ] the engine has stopped searching and found the move best in this position. the engine can send the move it likes to ponder on. The engine must not start pondering automatically. this command must always be sent if the engine stops searching, also in pondering mode if there is a "stop" command, so for every "go" command a "bestmove" command is needed! Directly before that the engine should send a final "info" command with the final search information, the the GUI has the complete statistics about the last search. * copyprotection this is needed for copyprotected engines. After the uciok command the engine can tell the GUI, that it will check the copy protection now. This is done by "copyprotection checking". If the check is ok the engine should send "copyprotection ok", otherwise "copyprotection error". If there is an error the engine should not function properly but should not quit alone. If the engine reports "copyprotection error" the GUI should not use this engine and display an error message instead! The code in the engine can look like this TellGUI("copyprotection checking\n"); // ... check the copy protection here ... if(ok) TellGUI("copyprotection ok\n"); else TellGUI("copyprotection error\n"); * registration this is needed for engines that need a username and/or a code to function with all features. Analog to the "copyprotection" command the engine can send "registration checking" after the uciok command followed by either "registration ok" or "registration error". Also after every attempt to register the engine it should answer with "registration checking" and then either "registration ok" or "registration error". In contrast to the "copyprotection" command, the GUI can use the engine after the engine has reported an error, but should inform the user that the engine is not properly registered and might not use all its features. In addition the GUI should offer to open a dialog to enable registration of the engine. To try to register an engine the GUI can send the "register" command. The GUI has to always answer with the "register" command if the engine sends "registration error" at engine startup (this can also be done with "register later") and tell the user somehow that the engine is not registered. This way the engine knows that the GUI can deal with the registration procedure and the user will be informed that the engine is not properly registered. * info the engine wants to send information to the GUI. This should be done whenever one of the info has changed. The engine can send only selected infos or multiple infos with one info command, e.g. "info currmove e2e4 currmovenumber 1" or "info depth 12 nodes 123456 nps 100000". Also all infos belonging to the pv should be sent together e.g. "info depth 2 score cp 214 time 1242 nodes 2124 nps 34928 pv e2e4 e7e5 g1f3" I suggest to start sending "currmove", "currmovenumber", "currline" and "refutation" only after one second to avoid too much traffic. Additional info: * depth search depth in plies * seldepth selective search depth in plies, if the engine sends seldepth there must also be a "depth" present in the same string. * time the time searched in ms, this should be sent together with the pv. * nodes x nodes searched, the engine should send this info regularly * pv ... the best line found * multipv this for the multi pv mode. for the best move/pv add "multipv 1" in the string when you send the pv. in k-best mode always send all k variants in k strings together. * score * cp the score from the engine's point of view in centipawns. * mate mate in y moves, not plies. If the engine is getting mated use negative values for y. * lowerbound the score is just a lower bound. * upperbound the score is just an upper bound. * currmove currently searching this move * currmovenumber currently searching move number x, for the first move x should be 1 not 0. * hashfull the hash is x permill full, the engine should send this info regularly * nps x nodes per second searched, the engine should send this info regularly * tbhits x positions where found in the endgame table bases * sbhits x positions where found in the shredder endgame databases * cpuload the cpu usage of the engine is x permill. * string any string str which will be displayed be the engine, if there is a string command the rest of the line will be interpreted as . * refutation ... move is refuted by the line ... , i can be any number >= 1. Example: after move d1h5 is searched, the engine can send "info refutation d1h5 g6h5" if g6h5 is the best answer after d1h5 or if g6h5 refutes the move d1h5. if there is no refutation for d1h5 found, the engine should just send "info refutation d1h5" The engine should only send this if the option "UCI_ShowRefutations" is set to true. * currline ... this is the current line the engine is calculating. is the number of the cpu if the engine is running on more than one cpu. = 1,2,3.... if the engine is just using one cpu, can be omitted. If is greater than 1, always send all k lines in k strings together. The engine should only send this if the option "UCI_ShowCurrLine" is set to true. * option This command tells the GUI which parameters can be changed in the engine. This should be sent once at engine startup after the "uci" and the "id" commands if any parameter can be changed in the engine. The GUI should parse this and build a dialog for the user to change the settings. Note that not every option needs to appear in this dialog as some options like "Ponder", "UCI_AnalyseMode", etc. are better handled elsewhere or are set automatically. If the user wants to change some settings, the GUI will send a "setoption" command to the engine. Note that the GUI need not send the setoption command when starting the engine for every option if it doesn't want to change the default value. For all allowed combinations see the examples below, as some combinations of this tokens don't make sense. One string will be sent for each parameter. * name The option has the name id. Certain options have a fixed value for , which means that the semantics of this option is fixed. Usually those options should not be displayed in the normal engine options window of the GUI but get a special treatment. "Pondering" for example should be set automatically when pondering is enabled or disabled in the GUI options. The same for "UCI_AnalyseMode" which should also be set automatically by the GUI. All those certain options have the prefix "UCI_" except for the first 6 options below. If the GUI gets an unknown Option with the prefix "UCI_", it should just ignore it and not display it in the engine's options dialog. * = Hash, type is spin the value in MB for memory for hash tables can be changed, this should be answered with the first "setoptions" command at program boot if the engine has sent the appropriate "option name Hash" command, which should be supported by all engines! So the engine should use a very small hash first as default. * = NalimovPath, type string this is the path on the hard disk to the Nalimov compressed format. Multiple directories can be concatenated with ";" * = NalimovCache, type spin this is the size in MB for the cache for the nalimov table bases These last two options should also be present in the initial options exchange dialog when the engine is booted if the engine supports it * = Ponder, type check this means that the engine is able to ponder. The GUI will send this whenever pondering is possible or not. Note: The engine should not start pondering on its own if this is enabled, this option is only needed because the engine might change its time management algorithm when pondering is allowed. * = OwnBook, type check this means that the engine has its own book which is accessed by the engine itself. if this is set, the engine takes care of the opening book and the GUI will never execute a move out of its book for the engine. If this is set to false by the GUI, the engine should not access its own book. * = MultiPV, type spin the engine supports multi best line or k-best mode. the default value is 1 * = UCI_ShowCurrLine, type check, should be false by default, the engine can show the current line it is calculating. see "info currline" above. * = UCI_ShowRefutations, type check, should be false by default, the engine can show a move and its refutation in a line. see "info refutations" above. * = UCI_LimitStrength, type check, should be false by default, The engine is able to limit its strength to a specific Elo number, This should always be implemented together with "UCI_Elo". * = UCI_Elo, type spin The engine can limit its strength in Elo within this interval. If UCI_LimitStrength is set to false, this value should be ignored. If UCI_LimitStrength is set to true, the engine should play with this specific strength. This should always be implemented together with "UCI_LimitStrength". * = UCI_AnalyseMode, type check The engine wants to behave differently when analysing or playing a game. For example when playing it can use some kind of learning. This is set to false if the engine is playing a game, otherwise it is true. * = UCI_Opponent, type string With this command the GUI can send the name, title, elo and if the engine is playing a human or computer to the engine. The format of the string has to be [GM|IM|FM|WGM|WIM|none] [|none] [computer|human] Examples: "setoption name UCI_Opponent value GM 2800 human Gary Kasparov" "setoption name UCI_Opponent value none none computer Shredder" * = UCI_EngineAbout, type string With this command, the engine tells the GUI information about itself, for example a license text, usually it doesn't make sense that the GUI changes this text with the setoption command. Example: "option name UCI_EngineAbout type string default Shredder by Stefan Meyer-Kahlen, see www.shredderchess.com" * = UCI_ShredderbasesPath, type string this is either the path to the folder on the hard disk containing the Shredder endgame databases or the path and filename of one Shredder endgame datbase. * = UCI_SetPositionValue, type string the GUI can send this to the engine to tell the engine to use a certain value in centipawns from white's point of view if evaluating this specifix position. The string can have the formats: + | clear + | clearall * type The option has type t. There are 5 different types of options the engine can send * check a checkbox that can either be true or false * spin a spin wheel that can be an integer in a certain range * combo a combo box that can have different predefined strings as a value * button a button that can be pressed to send a command to the engine * string a text field that has a string as a value, an empty string has the value "" * default the default value of this parameter is x * min the minimum value of this parameter is x * max the maximum value of this parameter is x * var a predefined value of this parameter is x Examples: Here are 5 strings for each of the 5 possible types of options "option name Nullmove type check default true\n" "option name Selectivity type spin default 2 min 0 max 4\n" "option name Style type combo default Normal var Solid var Normal var Risky\n" "option name NalimovPath type string default c:\\n" "option name Clear Hash type button\n" Examples: --------- This is how the communication when the engine boots can look like: GUI engine // tell the engine to switch to UCI mode uci // engine identify id name Shredder id author Stefan MK // engine sends the options it can change // the engine can change the hash size from 1 to 128 MB option name Hash type spin default 1 min 1 max 128 // the engine supports Nalimov endgame tablebases option name NalimovPath type string default option name NalimovCache type spin default 1 min 1 max 32 // the engine can switch off Nullmove and set the playing style option name Nullmove type check default true option name Style type combo default Normal var Solid var Normal var Risky // the engine has sent all parameters and is ready uciok // Note: here the GUI can already send a "quit" command if it just wants to find out // details about the engine, so the engine should not initialize its internal // parameters before here. // now the GUI sets some values in the engine // set hash to 32 MB setoption name Hash value 32 // init tbs setoption name NalimovCache value 1 setoption name NalimovPath value d:\tb;c\tb // waiting for the engine to finish initializing // this command and the answer is required here! isready // engine has finished setting up the internal values readyok // now we are ready to go // if the GUI is supporting it, tell the engine that is is // searching on a game that it hasn't searched on before ucinewgame // if the engine supports the "UCI_AnalyseMode" option and the next search is supposed to // be an analysis, the GUI should set "UCI_AnalyseMode" to true if it is currently // set to false with this engine setoption name UCI_AnalyseMode value true // tell the engine to search infinite from the start position after 1.e4 e5 position startpos moves e2e4 e7e5 go infinite // the engine starts sending infos about the search to the GUI // (only some examples are given) info depth 1 seldepth 0 info score cp 13 depth 1 nodes 13 time 15 pv f1b5 info depth 2 seldepth 2 info nps 15937 info score cp 14 depth 2 nodes 255 time 15 pv f1c4 f8c5 info depth 2 seldepth 7 nodes 255 info depth 3 seldepth 7 info nps 26437 info score cp 20 depth 3 nodes 423 time 15 pv f1c4 g8f6 b1c3 info nps 41562 .... // here the user has seen enough and asks to stop the searching stop // the engine has finished searching and is sending the bestmove command // which is needed for every "go" command sent to tell the GUI // that the engine is ready again bestmove g1f3 ponder d8f6 Chess960 ======== UCI could easily be extended to support Chess960 (also known as Fischer Random Chess). The engine has to tell the GUI that it is capable of playing Chess960 and the GUI has to tell the engine that is should play according to the Chess960 rules. This is done by the special engine option UCI_Chess960. If the engine knows about Chess960 it should send the command 'option name UCI_Chess960 type check default false' to the GUI at program startup. Whenever a Chess960 game is played, the GUI should set this engine option to 'true'. Castling is different in Chess960 and the white king move when castling short is not always e1g1. A king move could both be the castling king move or just a normal king move. This is why castling moves are sent in the form king "takes" his own rook. Example: e1h1 for the white short castle move in the normal chess start position. In EPD and FEN position strings specifying the castle rights with w and q is not enough as there could be more than one rook on the right or left side of the king. This is why the castle rights are specified with the letter of the castle rook's line. Upper case letters for white's and lower case letters for black's castling rights. Example: The normal chess position would be: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w AHah - tagua-1.0-alpha2/doc/xboard-ics-parsing.txt000066400000000000000000000133501077523320400206270ustar00rootroot00000000000000Parsing of ICS Output Updated to match xboard/WinBoard 4.0.2 $Id: ics-parsing.txt,v 2.1 2003/10/27 19:21:00 mann Exp $ ============================================================================== This document describes how xboard and WinBoard parse ICS output. The general parsing method is to compare a list of patterns against the current line (whether partial or complete) each time new input is received from ICS. The patterns are considered in a fixed order. The pattern matching is not "anchored", so unmatched text at the beginning of a line (including the prompt, usually) is skipped. Whenever a pattern is matched, the characters are "consumed" and matching begins again with the next unmatched character, starting at the top of the list. The last pattern is "\n", causing characters up to a newline to be discarded if they have not matched any patterns. The pattern language is very simple. Every character but "*" must match literally. "*" matches zero or more characters that don't include a newline and don't match the character immediately following the *, if any. A "*" at the end of a pattern will not match until a complete line is received This method of pattern matching is rather fragile. The patterns have to be chosen quite carefully to avoid unexpected results. For example, at one time "* shouts: *" was used to match shouts, while "<12>" was used to match the start of a board. If someone shouted "<12>", xboard would succeed in ignoring the <12> only if all the characters from the ">" to the next newline were received at one time, so that the shout pattern could match before the start-of-board pattern was considered. (This usually happens on TCP connections, but is not guaranteed.) The patterns intentionally allow text in finger notes to be parsed and colorized as tells, shouts, etc. I did this because Zek once said that ZIICS users like this feature, even though he originally considered it a bug in ZIICS, and so he doesn't dare change it. I may eventually change it anyway so that people stop reporting it as a bug. Here is the complete list of patterns that xboard looks for, in order. The list was obtained by grepping the source code for "looking_at", my procedure for pattern-matching. Some of these are specific to FICS, some to ICC, and some may be outdated---that is, they may reflect messages that no ICS produces anymore. Occasionally the same pattern appears more than once because earlier occurrences were inside if/then/else statements. There may also be a couple of places where I do a test without calling looking_at. zippy.c (runs first if Zippy is active, otherwise skipped): "* kibitzes: Hello from Crafty" "* is in the computer list." "* * is a computer *" "* offers to be your bughouse partner" "* tells you: [automatic message] I chose you" "* agrees to be your partner" "are no longer *'s partner" "no longer have a bughouse partner" "partner has disconnected" "partner has just chosen a new partner" "* tells you: [automatic message] I'm no longer your" "* (your partner) tells you: *" "* tells you: *" "* says: *" "--> * *" "* shouts: *" "* kibitzes: *" "* whispers: *" "You have * message*." "* has left a message for you." "* just sent you a message." "--* (*:*): *" "*. * (*:*): *" "*. * at *:*: *" "*(*): *" "*(*)(*): *" "Notification: * has arrived" "Not sent -- * is censoring you" "command is currently turned off" "* * match * * requested with * (*)" "* * match * requested with * (*)" * has made an alternate proposal of * * match * *." "Challenge: * (*) *(*) * * * * Loaded from *" "Challenge: * (*) *(*) * * * * : * * Loaded from *" "Challenge: * (*) *(*) * * * * : * *" "Challenge: * (*) *(*) * * * * * *" "Challenge: * (*) *(*) * * * *" "offers you a draw" "requests that the game be aborted" "would like to abort" "requests adjournment" "would like to adjourn" backend.c: "ics%" /* right after login only; nonessential */ "chessclub.com" /* before login; turns on ICC mode */ "\"*\" is *a registered name" "Logging you in as \"*\"" "Your name will be \"*\"" "* s-shouts: " "* c-shouts: " "--->" /* seen in FICS login, not a shout */ "* shouts: " "--> " "* tells you: " "* (your partner) tells you: " "* says: " "* has left a message " "* just sent you a message:\n" "*. * (*:*): " "*. * at *:*: " "* whispers: " "* kibitzes: " "*)(*): *" /* channel tell or allobs or admin comment */ "*(*): *" /* channel tell or allobs or admin comment */ "*)(*)(*): *" /* channel tell */ "Challenge:" "* offers you" "* offers to be" "* would like to" "* requests to" "Your opponent offers" "Your opponent requests" "\\ " /* continuation line */ "Black Strength :" /* need to issue "style 12; refresh" */ "<<< style 10 board >>>" /* need to issue "style 12; refresh" */ "<10>" /* need to issue "style 12; refresh" */ "#@#" /* need to issue "style 12; refresh" */ "login:" "\n<12> " "<12> " "\n " " " "* *vs. * *--- *" /* move list coming */ "* * match, initial time: * minute*, increment: * second" "Move " /* move list is here */ "% " /* end of prompt; nonessential */ "}*" /* ends a move list */ "Adding game * to observation list" "Game notification: * (*) vs. * (*)" "Entering examine mode for game *" "has made you an examiner of game *" "Illegal move" "Not a legal move" "Your king is in check" "It isn't your turn" "It is not your move" "still have time" "not out of time" "either player is out of time" "has timeseal; checking" "added * seconds to" "seconds were added to" "clock paused" "clock resumed" "Creating: * (*)* * (*)" "Creating: * (*) [*] * (*)" "{Game * (* vs. *) *}*" "Removing game * from observation" "no longer observing game *" "Game * (*) has no examiners" "no longer examining game *" "\n" "*% " /* end of prompt; nonessential */ tagua-1.0-alpha2/extract-messages.sh000077500000000000000000000031711077523320400174430ustar00rootroot00000000000000#!/bin/sh set -e WDIR=`pwd` BASEDIR=$1 [ $BASEDIR ] || BASEDIR=$WDIR # root of translatable sources SRCDIR=$BASEDIR/src PROJECT="tagua" # project name BUGADDR="http://trac.tagua-project.org" echo "Preparing rc files" cd ${SRCDIR} # we use simple sorting to make sure the lines do not jump around too much from system to system find . -name '*.rc' -o -name '*.ui' -o -name '*.kcfg' | sort > ${WDIR}/rcfiles.list xargs --arg-file=${WDIR}/rcfiles.list extractrc > ${WDIR}/extractedrc.cpp # additional string for KAboutData echo 'i18nc("NAME OF TRANSLATORS","Your names");' >> ${WDIR}/extractedrc.cpp echo 'i18nc("EMAIL OF TRANSLATORS","Your emails");' >> ${WDIR}/extractedrc.cpp cd ${WDIR} echo "Done preparing rc files" echo "Extracting messages" cd ${SRCDIR} # see above on sorting find . -name '*.cpp' -o -name '*.h' -o -name '*.c' | sort > ${WDIR}/infiles.list echo "extractedrc.cpp" >> ${WDIR}/infiles.list cd ${WDIR} xgettext --from-code=UTF-8 -C -kde -ci18n -ki18n:1 -ki18nc:1c,2 -ki18np:1,2 -ki18ncp:1c,2,3 -ktr2i18n:1 \ -kI18N_NOOP:1 -kI18N_NOOP2:1c,2 -kaliasLocale -kki18n:1 -kki18nc:1c,2 -kki18np:1,2 -kki18ncp:1c,2,3 \ --msgid-bugs-address="${BUGADDR}" \ --files-from=infiles.list -D ${SRCDIR} -D ${WDIR} -o ${PROJECT}.pot || { echo "error while calling xgettext. aborting."; exit 1; } echo "Done extracting messages" echo "Merging translations" catalogs=`find translations -name '*.po'` for cat in $catalogs; do echo $cat msgmerge -o $cat.new $cat ${PROJECT}.pot mv $cat.new $cat done echo "Done merging translations" echo "Cleaning up" cd ${WDIR} rm rcfiles.list rm infiles.list rm extractedrc.cpp echo "Done" tagua-1.0-alpha2/fix_copyright.rb000077500000000000000000000012261077523320400170320ustar00rootroot00000000000000#!/usr/bin/ruby require 'find' stmt = %{/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ } Find.find('.') do |filename| if filename =~ /\.(cpp|h)$/ code = File.open(filename) {|f| f.read} unless code =~ /copyright/i File.open(filename, 'w') {|f| f.write(stmt + code)} end end end tagua-1.0-alpha2/lua/000077500000000000000000000000001077523320400144045ustar00rootroot00000000000000tagua-1.0-alpha2/lua/.gitignore000066400000000000000000000000101077523320400163630ustar00rootroot00000000000000include tagua-1.0-alpha2/lua/CMakeLists.txt000066400000000000000000000035361077523320400171530ustar00rootroot00000000000000 SET(LUA_SRC src/lapi.c src/lcode.c src/ldebug.c src/ldo.c src/ldump.c src/lfunc.c src/lgc.c src/llex.c src/lmem.c src/lobject.c src/lopcodes.c src/lparser.c src/lstate.c src/lstring.c src/ltable.c src/ltm.c src/lundump.c src/lvm.c src/lzio.c src/lauxlib.c src/lbaselib.c src/ldblib.c src/liolib.c src/lmathlib.c src/loslib.c src/ltablib.c src/lstrlib.c src/loadlib.c src/linit.c src/lapi.h src/lauxlib.h src/lcode.h src/ldebug.h src/ldo.h src/lfunc.h src/lgc.h src/llex.h src/llimits.h src/lmem.h src/lobject.h src/lopcodes.h src/lparser.h src/lstate.h src/lstring.h src/ltable.h src/ltm.h src/luaconf.h src/lua.h src/lualib.h src/lundump.h src/lvm.h src/lzio.h ) SET(LUA_HEADERS src/lua.h src/luaconf.h src/lualib.h src/lauxlib.h etc/lua.hpp ) FILE(MAKE_DIRECTORY include) FOREACH(HEADER ${LUA_HEADERS}) GET_FILENAME_COMPONENT(H ${HEADER} NAME) CONFIGURE_FILE(${HEADER} "${LUA_INCLUDE_DIRS}/${H}" COPYONLY) ENDFOREACH(HEADER) IF("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") ADD_DEFINITIONS(-DLUA_USE_LINUX) MESSAGE("* Looks like you're using Linux, lua will be compiled with") MESSAGE(" CFlags: -DLUA_USE_LINUX") ELSE("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") IF(UNIX) MESSAGE("* Looks like you're some Unix, lua will be compiled with") MESSAGE(" CFlags: -DLUA_USE_POSIX -DLUA_USE_DLOPEN") MESSAGE(" I hope this is not too optimistic for your system") ADD_DEFINITIONS(-DLUA_USE_POSIX -DLUA_USE_DLOPEN) ELSE(UNIX) MESSAGE("* Could not recognise you system, lua will be compiled with generic options") ENDIF(UNIX) ENDIF("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") # -DLUA_USE_APICHECK is mandatory for debugging! set(CMAKE_C_FLAGS_DEBUGFULL "${CMAKE_C_FLAGS_DEBUGFULL} -DLUA_USE_APICHECK") ADD_LIBRARY(lua STATIC ${LUA_SRC}) tagua-1.0-alpha2/lua/COPYRIGHT000066400000000000000000000027701077523320400157050ustar00rootroot00000000000000Lua License ----------- Lua is licensed under the terms of the MIT license reproduced below. This means that Lua is free software and can be used for both academic and commercial purposes at absolutely no cost. For details and rationale, see http://www.lua.org/license.html . =============================================================================== Copyright (C) 1994-2007 Lua.org, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =============================================================================== (end of COPYRIGHT) tagua-1.0-alpha2/lua/HISTORY000066400000000000000000000173431077523320400155000ustar00rootroot00000000000000HISTORY for Lua 5.1 * Changes from version 5.0 to 5.1 ------------------------------- Language: + new module system. + new semantics for control variables of fors. + new semantics for setn/getn. + new syntax/semantics for varargs. + new long strings and comments. + new `mod' operator (`%') + new length operator #t + metatables for all types API: + new functions: lua_createtable, lua_get(set)field, lua_push(to)integer. + user supplies memory allocator (lua_open becomes lua_newstate). + luaopen_* functions must be called through Lua. Implementation: + new configuration scheme via luaconf.h. + incremental garbage collection. + better handling of end-of-line in the lexer. + fully reentrant parser (new Lua function `load') + better support for 64-bit machines. + native loadlib support for Mac OS X. + standard distribution in only one library (lualib.a merged into lua.a) * Changes from version 4.0 to 5.0 ------------------------------- Language: + lexical scoping. + Lua coroutines. + standard libraries now packaged in tables. + tags replaced by metatables and tag methods replaced by metamethods, stored in metatables. + proper tail calls. + each function can have its own global table, which can be shared. + new __newindex metamethod, called when we insert a new key into a table. + new block comments: --[[ ... ]]. + new generic for. + new weak tables. + new boolean type. + new syntax "local function". + (f()) returns the first value returned by f. + {f()} fills a table with all values returned by f. + \n ignored in [[\n . + fixed and-or priorities. + more general syntax for function definition (e.g. function a.x.y:f()...end). + more general syntax for function calls (e.g. (print or write)(9)). + new functions (time/date, tmpfile, unpack, require, load*, etc.). API: + chunks are loaded by using lua_load; new luaL_loadfile and luaL_loadbuffer. + introduced lightweight userdata, a simple "void*" without a metatable. + new error handling protocol: the core no longer prints error messages; all errors are reported to the caller on the stack. + new lua_atpanic for host cleanup. + new, signal-safe, hook scheme. Implementation: + new license: MIT. + new, faster, register-based virtual machine. + support for external multithreading and coroutines. + new and consistent error message format. + the core no longer needs "stdio.h" for anything (except for a single use of sprintf to convert numbers to strings). + lua.c now runs the environment variable LUA_INIT, if present. It can be "@filename", to run a file, or the chunk itself. + support for user extensions in lua.c. sample implementation given for command line editing. + new dynamic loading library, active by default on several platforms. + safe garbage-collector metamethods. + precompiled bytecodes checked for integrity (secure binary dostring). + strings are fully aligned. + position capture in string.find. + read('*l') can read lines with embedded zeros. * Changes from version 3.2 to 4.0 ------------------------------- Language: + new "break" and "for" statements (both numerical and for tables). + uniform treatment of globals: globals are now stored in a Lua table. + improved error messages. + no more '$debug': full speed *and* full debug information. + new read form: read(N) for next N bytes. + general read patterns now deprecated. (still available with -DCOMPAT_READPATTERNS.) + all return values are passed as arguments for the last function (old semantics still available with -DLUA_COMPAT_ARGRET) + garbage collection tag methods for tables now deprecated. + there is now only one tag method for order. API: + New API: fully re-entrant, simpler, and more efficient. + New debug API. Implementation: + faster than ever: cleaner virtual machine and new hashing algorithm. + non-recursive garbage-collector algorithm. + reduced memory usage for programs with many strings. + improved treatment for memory allocation errors. + improved support for 16-bit machines (we hope). + code now compiles unmodified as both ANSI C and C++. + numbers in bases other than 10 are converted using strtoul. + new -f option in Lua to support #! scripts. + luac can now combine text and binaries. * Changes from version 3.1 to 3.2 ------------------------------- + redirected all output in Lua's core to _ERRORMESSAGE and _ALERT. + increased limit on the number of constants and globals per function (from 2^16 to 2^24). + debugging info (lua_debug and hooks) moved into lua_state and new API functions provided to get and set this info. + new debug lib gives full debugging access within Lua. + new table functions "foreachi", "sort", "tinsert", "tremove", "getn". + new io functions "flush", "seek". * Changes from version 3.0 to 3.1 ------------------------------- + NEW FEATURE: anonymous functions with closures (via "upvalues"). + new syntax: - local variables in chunks. - better scope control with DO block END. - constructors can now be also written: { record-part; list-part }. - more general syntax for function calls and lvalues, e.g.: f(x).y=1 o:f(x,y):g(z) f"string" is sugar for f("string") + strings may now contain arbitrary binary data (e.g., embedded zeros). + major code re-organization and clean-up; reduced module interdependecies. + no arbitrary limits on the total number of constants and globals. + support for multiple global contexts. + better syntax error messages. + new traversal functions "foreach" and "foreachvar". + the default for numbers is now double. changing it to use floats or longs is easy. + complete debug information stored in pre-compiled chunks. + sample interpreter now prompts user when run interactively, and also handles control-C interruptions gracefully. * Changes from version 2.5 to 3.0 ------------------------------- + NEW CONCEPT: "tag methods". Tag methods replace fallbacks as the meta-mechanism for extending the semantics of Lua. Whereas fallbacks had a global nature, tag methods work on objects having the same tag (e.g., groups of tables). Existing code that uses fallbacks should work without change. + new, general syntax for constructors {[exp] = exp, ... }. + support for handling variable number of arguments in functions (varargs). + support for conditional compilation ($if ... $else ... $end). + cleaner semantics in API simplifies host code. + better support for writing libraries (auxlib.h). + better type checking and error messages in the standard library. + luac can now also undump. * Changes from version 2.4 to 2.5 ------------------------------- + io and string libraries are now based on pattern matching; the old libraries are still available for compatibility + dofile and dostring can now return values (via return statement) + better support for 16- and 64-bit machines + expanded documentation, with more examples * Changes from version 2.2 to 2.4 ------------------------------- + external compiler creates portable binary files that can be loaded faster + interface for debugging and profiling + new "getglobal" fallback + new functions for handling references to Lua objects + new functions in standard lib + only one copy of each string is stored + expanded documentation, with more examples * Changes from version 2.1 to 2.2 ------------------------------- + functions now may be declared with any "lvalue" as a name + garbage collection of functions + support for pipes * Changes from version 1.1 to 2.1 ------------------------------- + object-oriented support + fallbacks + simplified syntax for tables + many internal improvements (end of HISTORY) tagua-1.0-alpha2/lua/INSTALL000066400000000000000000000074341077523320400154450ustar00rootroot00000000000000INSTALL for Lua 5.1 * Building Lua ------------ Lua is built in the src directory, but the build process can be controlled from the top-level Makefile. Building Lua on Unix systems should be very easy. First do "make" and see if your platform is listed. If so, just do "make xxx", where xxx is your platform name. The platforms currently supported are: aix ansi bsd freebsd generic linux macosx mingw posix solaris If your platform is not listed, try the closest one or posix, generic, ansi, in this order. See below for customization instructions and for instructions on how to build with other Windows compilers. If you want to check that Lua has been built correctly, do "make test" after building Lua. Also, have a look at the example programs in test. * Installing Lua -------------- Once you have built Lua, you may want to install it in an official place in your system. In this case, do "make install". The official place and the way to install files are defined in Makefile. You must have the right permissions to install files. If you want to build and install Lua in one step, do "make xxx install", where xxx is your platform name. If you want to install Lua locally, then do "make local". This will create directories bin, include, lib, man, and install Lua there as follows: bin: lua luac include: lua.h luaconf.h lualib.h lauxlib.h lua.hpp lib: liblua.a man/man1: lua.1 luac.1 These are the only directories you need for development. There are man pages for lua and luac, in both nroff and html, and a reference manual in html in doc, some sample code in test, and some useful stuff in etc. You don't need these directories for development. If you want to install Lua locally, but in some other directory, do "make install INSTALL_TOP=xxx", where xxx is your chosen directory. See below for instructions for Windows and other systems. * Customization ------------- Three things can be customized by editing a file: - Where and how to install Lua -- edit Makefile. - How to build Lua -- edit src/Makefile. - Lua features -- edit src/luaconf.h. You don't actually need to edit the Makefiles because you may set the relevant variables when invoking make. On the other hand, if you need to select some Lua features, you'll need to edit src/luaconf.h. The edited file will be the one installed, and it will be used by any Lua clients that you build, to ensure consistency. We strongly recommend that you enable dynamic loading. This is done automatically for all platforms listed above that have this feature (and also Windows). See src/luaconf.h and also src/Makefile. * Building Lua on Windows and other systems ----------------------------------------- If you're not using the usual Unix tools, then the instructions for building Lua depend on the compiler you use. You'll need to create projects (or whatever your compiler uses) for building the library, the interpreter, and the compiler, as follows: library: lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c ltablib.c lstrlib.c loadlib.c linit.c interpreter: library, lua.c compiler: library, luac.c print.c If you use Visual Studio .NET, you can use etc/luavs.bat in its "Command Prompt". If all you want is to build the Lua interpreter, you may put all .c files in a single project, except for luac.c and print.c. Or just use etc/all.c. To use Lua as a library in your own programs, you'll need to know how to create and use libraries with your compiler. As mentioned above, you may edit luaconf.h to select some features before building Lua. (end of INSTALL) tagua-1.0-alpha2/lua/Makefile000066400000000000000000000551001077523320400160450ustar00rootroot00000000000000# CMAKE generated file: DO NOT EDIT! # Generated by "Unix Makefiles" Generator, CMake Version 2.4 # Default target executed when no arguments are given to make. default_target: all #============================================================================= # Special targets provided by cmake. # Disable implicit rules so canoncical targets will work. .SUFFIXES: .SUFFIXES: .hpux_make_needs_suffix_list # Suppress display of executed commands. $(VERBOSE).SILENT: # A target that is always out of date. cmake_force: #============================================================================= # Set environment variables for the build. # The shell in which to execute make rules. SHELL = /bin/sh # The CMake executable. CMAKE_COMMAND = /usr/bin/cmake # The command to remove a file. RM = /usr/bin/cmake -E remove -f # The program to use to edit the cache. CMAKE_EDIT_COMMAND = /usr/bin/ccmake # The top-level source directory on which CMake was run. CMAKE_SOURCE_DIR = /export/work/yann/games/tagua/tagua # The top-level build directory on which CMake was run. CMAKE_BINARY_DIR = /export/work/yann/games/tagua/tagua # Include the progress variables for this target. include CMakeFiles/progress.make #============================================================================= # Targets provided globally by CMake. # Special rule for the target edit_cache edit_cache: @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." cd /export/work/yann/games/tagua/tagua/lua && /usr/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) # Special rule for the target edit_cache edit_cache/fast: edit_cache # Special rule for the target install install: preinstall @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." cd /export/work/yann/games/tagua/tagua/lua && /usr/bin/cmake -P cmake_install.cmake # Special rule for the target install install/fast: preinstall/fast @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." cd /export/work/yann/games/tagua/tagua/lua && /usr/bin/cmake -P cmake_install.cmake # Special rule for the target install/local install/local: preinstall @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." cd /export/work/yann/games/tagua/tagua/lua && /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake # Special rule for the target install/local install/local/fast: install/local # Special rule for the target list_install_components list_install_components: @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Only default component available" # Special rule for the target list_install_components list_install_components/fast: list_install_components # Special rule for the target rebuild_cache rebuild_cache: @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." cd /export/work/yann/games/tagua/tagua/lua && /usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) # Special rule for the target rebuild_cache rebuild_cache/fast: rebuild_cache # Special rule for the target test test: @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running tests..." cd /export/work/yann/games/tagua/tagua/lua && /usr/bin/ctest --force-new-ctest-process $(ARGS) # Special rule for the target test test/fast: test # The main all target all: cmake_check_build_system cd /export/work/yann/games/tagua/tagua && $(CMAKE_COMMAND) -E cmake_progress_start /export/work/yann/games/tagua/tagua/CMakeFiles $(CMAKE_ALL_PROGRESS) cd /export/work/yann/games/tagua/tagua && $(MAKE) -f CMakeFiles/Makefile2 lua/all $(CMAKE_COMMAND) -E cmake_progress_start /export/work/yann/games/tagua/tagua/CMakeFiles 0 # The main clean target clean: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f CMakeFiles/Makefile2 lua/clean # The main clean target clean/fast: clean # Prepare targets for installation. preinstall: all cd /export/work/yann/games/tagua/tagua && $(MAKE) -f CMakeFiles/Makefile2 lua/preinstall # Prepare targets for installation. preinstall/fast: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f CMakeFiles/Makefile2 lua/preinstall # clear depends depend: $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 # Convenience name for target. lua/CMakeFiles/lua.dir/rule: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f CMakeFiles/Makefile2 lua/CMakeFiles/lua.dir/rule # Convenience name for target. lua: lua/CMakeFiles/lua.dir/rule # fast build rule for target. lua/fast: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/build # target to build an object file src/lapi.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lapi.o # target to preprocess a source file src/lapi.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lapi.i # target to generate assembly for a file src/lapi.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lapi.s # target to build an object file src/lauxlib.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lauxlib.o # target to preprocess a source file src/lauxlib.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lauxlib.i # target to generate assembly for a file src/lauxlib.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lauxlib.s # target to build an object file src/lbaselib.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lbaselib.o # target to preprocess a source file src/lbaselib.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lbaselib.i # target to generate assembly for a file src/lbaselib.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lbaselib.s # target to build an object file src/lcode.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lcode.o # target to preprocess a source file src/lcode.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lcode.i # target to generate assembly for a file src/lcode.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lcode.s # target to build an object file src/ldblib.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldblib.o # target to preprocess a source file src/ldblib.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldblib.i # target to generate assembly for a file src/ldblib.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldblib.s # target to build an object file src/ldebug.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldebug.o # target to preprocess a source file src/ldebug.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldebug.i # target to generate assembly for a file src/ldebug.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldebug.s # target to build an object file src/ldo.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldo.o # target to preprocess a source file src/ldo.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldo.i # target to generate assembly for a file src/ldo.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldo.s # target to build an object file src/ldump.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldump.o # target to preprocess a source file src/ldump.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldump.i # target to generate assembly for a file src/ldump.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ldump.s # target to build an object file src/lfunc.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lfunc.o # target to preprocess a source file src/lfunc.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lfunc.i # target to generate assembly for a file src/lfunc.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lfunc.s # target to build an object file src/lgc.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lgc.o # target to preprocess a source file src/lgc.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lgc.i # target to generate assembly for a file src/lgc.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lgc.s # target to build an object file src/linit.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/linit.o # target to preprocess a source file src/linit.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/linit.i # target to generate assembly for a file src/linit.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/linit.s # target to build an object file src/liolib.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/liolib.o # target to preprocess a source file src/liolib.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/liolib.i # target to generate assembly for a file src/liolib.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/liolib.s # target to build an object file src/llex.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/llex.o # target to preprocess a source file src/llex.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/llex.i # target to generate assembly for a file src/llex.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/llex.s # target to build an object file src/lmathlib.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lmathlib.o # target to preprocess a source file src/lmathlib.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lmathlib.i # target to generate assembly for a file src/lmathlib.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lmathlib.s # target to build an object file src/lmem.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lmem.o # target to preprocess a source file src/lmem.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lmem.i # target to generate assembly for a file src/lmem.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lmem.s # target to build an object file src/loadlib.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/loadlib.o # target to preprocess a source file src/loadlib.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/loadlib.i # target to generate assembly for a file src/loadlib.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/loadlib.s # target to build an object file src/lobject.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lobject.o # target to preprocess a source file src/lobject.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lobject.i # target to generate assembly for a file src/lobject.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lobject.s # target to build an object file src/lopcodes.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lopcodes.o # target to preprocess a source file src/lopcodes.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lopcodes.i # target to generate assembly for a file src/lopcodes.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lopcodes.s # target to build an object file src/loslib.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/loslib.o # target to preprocess a source file src/loslib.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/loslib.i # target to generate assembly for a file src/loslib.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/loslib.s # target to build an object file src/lparser.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lparser.o # target to preprocess a source file src/lparser.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lparser.i # target to generate assembly for a file src/lparser.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lparser.s # target to build an object file src/lstate.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lstate.o # target to preprocess a source file src/lstate.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lstate.i # target to generate assembly for a file src/lstate.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lstate.s # target to build an object file src/lstring.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lstring.o # target to preprocess a source file src/lstring.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lstring.i # target to generate assembly for a file src/lstring.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lstring.s # target to build an object file src/lstrlib.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lstrlib.o # target to preprocess a source file src/lstrlib.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lstrlib.i # target to generate assembly for a file src/lstrlib.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lstrlib.s # target to build an object file src/ltable.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ltable.o # target to preprocess a source file src/ltable.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ltable.i # target to generate assembly for a file src/ltable.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ltable.s # target to build an object file src/ltablib.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ltablib.o # target to preprocess a source file src/ltablib.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ltablib.i # target to generate assembly for a file src/ltablib.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ltablib.s # target to build an object file src/ltm.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ltm.o # target to preprocess a source file src/ltm.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ltm.i # target to generate assembly for a file src/ltm.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/ltm.s # target to build an object file src/lundump.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lundump.o # target to preprocess a source file src/lundump.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lundump.i # target to generate assembly for a file src/lundump.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lundump.s # target to build an object file src/lvm.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lvm.o # target to preprocess a source file src/lvm.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lvm.i # target to generate assembly for a file src/lvm.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lvm.s # target to build an object file src/lzio.o: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lzio.o # target to preprocess a source file src/lzio.i: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lzio.i # target to generate assembly for a file src/lzio.s: cd /export/work/yann/games/tagua/tagua && $(MAKE) -f lua/CMakeFiles/lua.dir/build.make lua/CMakeFiles/lua.dir/src/lzio.s # Help Target help:: @echo "The following are some of the valid targets for this Makefile:" @echo "... all (the default if no target is provided)" @echo "... clean" @echo "... depend" @echo "... edit_cache" @echo "... install" @echo "... install/local" @echo "... list_install_components" @echo "... lua" @echo "... rebuild_cache" @echo "... test" @echo "... src/lapi.o" @echo "... src/lapi.i" @echo "... src/lapi.s" @echo "... src/lauxlib.o" @echo "... src/lauxlib.i" @echo "... src/lauxlib.s" @echo "... src/lbaselib.o" @echo "... src/lbaselib.i" @echo "... src/lbaselib.s" @echo "... src/lcode.o" @echo "... src/lcode.i" @echo "... src/lcode.s" @echo "... src/ldblib.o" @echo "... src/ldblib.i" @echo "... src/ldblib.s" @echo "... src/ldebug.o" @echo "... src/ldebug.i" @echo "... src/ldebug.s" @echo "... src/ldo.o" @echo "... src/ldo.i" @echo "... src/ldo.s" @echo "... src/ldump.o" @echo "... src/ldump.i" @echo "... src/ldump.s" @echo "... src/lfunc.o" @echo "... src/lfunc.i" @echo "... src/lfunc.s" @echo "... src/lgc.o" @echo "... src/lgc.i" @echo "... src/lgc.s" @echo "... src/linit.o" @echo "... src/linit.i" @echo "... src/linit.s" @echo "... src/liolib.o" @echo "... src/liolib.i" @echo "... src/liolib.s" @echo "... src/llex.o" @echo "... src/llex.i" @echo "... src/llex.s" @echo "... src/lmathlib.o" @echo "... src/lmathlib.i" @echo "... src/lmathlib.s" @echo "... src/lmem.o" @echo "... src/lmem.i" @echo "... src/lmem.s" @echo "... src/loadlib.o" @echo "... src/loadlib.i" @echo "... src/loadlib.s" @echo "... src/lobject.o" @echo "... src/lobject.i" @echo "... src/lobject.s" @echo "... src/lopcodes.o" @echo "... src/lopcodes.i" @echo "... src/lopcodes.s" @echo "... src/loslib.o" @echo "... src/loslib.i" @echo "... src/loslib.s" @echo "... src/lparser.o" @echo "... src/lparser.i" @echo "... src/lparser.s" @echo "... src/lstate.o" @echo "... src/lstate.i" @echo "... src/lstate.s" @echo "... src/lstring.o" @echo "... src/lstring.i" @echo "... src/lstring.s" @echo "... src/lstrlib.o" @echo "... src/lstrlib.i" @echo "... src/lstrlib.s" @echo "... src/ltable.o" @echo "... src/ltable.i" @echo "... src/ltable.s" @echo "... src/ltablib.o" @echo "... src/ltablib.i" @echo "... src/ltablib.s" @echo "... src/ltm.o" @echo "... src/ltm.i" @echo "... src/ltm.s" @echo "... src/lundump.o" @echo "... src/lundump.i" @echo "... src/lundump.s" @echo "... src/lvm.o" @echo "... src/lvm.i" @echo "... src/lvm.s" @echo "... src/lzio.o" @echo "... src/lzio.i" @echo "... src/lzio.s" #============================================================================= # Special targets to cleanup operation of make. # Special rule to run CMake to check the build system integrity. # No rule that depends on this can have commands that come from listfiles # because they might be regenerated. cmake_check_build_system: cd /export/work/yann/games/tagua/tagua && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 tagua-1.0-alpha2/lua/README000066400000000000000000000025421077523320400152670ustar00rootroot00000000000000README for Lua 5.1 See INSTALL for installation instructions. See HISTORY for a summary of changes since the last released version. * What is Lua? ------------ Lua is a powerful, light-weight programming language designed for extending applications. Lua is also frequently used as a general-purpose, stand-alone language. Lua is free software. For complete information, visit Lua's web site at http://www.lua.org/ . For an executive summary, see http://www.lua.org/about.html . Lua has been used in many different projects around the world. For a short list, see http://www.lua.org/uses.html . * Availability ------------ Lua is freely available for both academic and commercial purposes. See COPYRIGHT and http://www.lua.org/license.html for details. Lua can be downloaded at http://www.lua.org/download.html . * Installation ------------ Lua is implemented in pure ANSI C, and compiles unmodified in all known platforms that have an ANSI C compiler. In most Unix-like platforms, simply do "make" with a suitable target. See INSTALL for detailed instructions. * Origin ------ Lua is developed at Lua.org, a laboratory of the Department of Computer Science of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro in Brazil). For more information about the authors, see http://www.lua.org/authors.html . (end of README) tagua-1.0-alpha2/lua/doc/000077500000000000000000000000001077523320400151515ustar00rootroot00000000000000tagua-1.0-alpha2/lua/doc/amazon.gif000066400000000000000000000014351077523320400171300ustar00rootroot00000000000000GIF89aZg >>5p̙oo_䯯޾;;ѲW~ .tłԞ!,Z&dihl;2L tmx<|2pH,ȤrpZجvzEAMzn|CB5A ,老dxz   p   yi{|  l {|} i ϡ i|l}|{LYk@ XĈ(? B&s  =eM=k~G ,R7qi@,M Lua 5.1 reference manual - contents

Lua 5.1 Reference Manual

This is an online version of
Lua 5.1 Reference Manual
by R. Ierusalimschy, L. H. de Figueiredo, W. Celes
Lua.org, August 2006
ISBN 85-903798-3-3
[Buy from Amazon]

Buy a paper copy and help to support the Lua project.

start · contents · index · errata


Copyright © 2006-2007 Lua.org, PUC-Rio. Freely available under the terms of the Lua license.

Contents

Index

Lua functions

_G
_VERSION
assert
collectgarbage
dofile
error
getfenv
getmetatable
ipairs
load
loadfile
loadstring
module
next
pairs
pcall
print
rawequal
rawget
rawset
require
select
setfenv
setmetatable
tonumber
tostring
type
unpack
xpcall

 

coroutine.create
coroutine.resume
coroutine.running
coroutine.status
coroutine.wrap
coroutine.yield
debug.debug
debug.getfenv
debug.gethook
debug.getinfo
debug.getlocal
debug.getmetatable
debug.getregistry
debug.getupvalue
debug.setfenv
debug.sethook
debug.setlocal
debug.setmetatable
debug.setupvalue
debug.traceback
file:close
file:flush
file:lines
file:read
file:seek
file:setvbuf
file:write
io.close
io.flush
io.input
io.lines
io.open
io.output
io.popen
io.read
io.tmpfile
io.type
io.write
math.abs
math.acos
math.asin
math.atan2
math.atan
math.ceil
math.cosh
math.cos
math.deg
math.exp
math.floor
math.fmod
math.frexp
math.huge
math.ldexp
math.log10
math.log
math.max
math.min
math.modf
math.pi
math.pow
math.rad
math.random
math.randomseed
math.sinh
math.sin
math.sqrt
math.tanh
math.tan
os.clock
os.date
os.difftime
os.execute
os.exit
os.getenv
os.remove
os.rename
os.setlocale
os.time
os.tmpname
package.cpath
package.loaded
package.loadlib
package.path
package.preload
package.seeall
string.byte
string.char
string.dump
string.find
string.format
string.gmatch
string.gsub
string.len
string.lower
string.match
string.rep
string.reverse
string.sub
string.upper
table.concat
table.insert
table.maxn
table.remove
table.sort

C API

lua_Alloc
lua_CFunction
lua_Debug
lua_Hook
lua_Integer
lua_Number
lua_Reader
lua_State
lua_Writer
lua_atpanic
lua_call
lua_checkstack
lua_close
lua_concat
lua_cpcall
lua_createtable
lua_dump
lua_equal
lua_error
lua_gc
lua_getallocf
lua_getfenv
lua_getfield
lua_getglobal
lua_gethook
lua_gethookcount
lua_gethookmask
lua_getinfo
lua_getlocal
lua_getmetatable
lua_getstack
lua_gettable
lua_gettop
lua_getupvalue
lua_insert
lua_isboolean
lua_iscfunction
lua_isfunction
lua_islightuserdata
lua_isnil
lua_isnumber
lua_isstring
lua_istable
lua_isthread
lua_isuserdata
lua_lessthan
lua_load
lua_newstate
lua_newtable
lua_newthread
lua_newuserdata
lua_next
lua_objlen
lua_pcall
lua_pop
lua_pushboolean
lua_pushcclosure
lua_pushcfunction
lua_pushfstring
lua_pushinteger
lua_pushlightuserdata
lua_pushlstring
lua_pushnil
lua_pushnumber
lua_pushstring
lua_pushthread
lua_pushvalue
lua_pushvfstring
lua_rawequal
lua_rawget
lua_rawgeti
lua_rawset
lua_rawseti
lua_register
lua_remove
lua_replace
lua_resume
lua_setallocf
lua_setfenv
lua_setfield
lua_setglobal
lua_sethook
lua_setlocal
lua_setmetatable
lua_settable
lua_settop
lua_setupvalue
lua_status
lua_toboolean
lua_tocfunction
lua_tointeger
lua_tolstring
lua_tonumber
lua_topointer
lua_tostring
lua_tothread
lua_touserdata
lua_type
lua_typename
lua_upvalueindex
lua_xmove
lua_yield

auxiliary library

luaL_Buffer
luaL_Reg
luaL_addchar
luaL_addlstring
luaL_addsize
luaL_addstring
luaL_addvalue
luaL_argcheck
luaL_argerror
luaL_buffinit
luaL_callmeta
luaL_checkany
luaL_checkint
luaL_checkinteger
luaL_checklong
luaL_checklstring
luaL_checknumber
luaL_checkoption
luaL_checkstack
luaL_checkstring
luaL_checktype
luaL_checkudata
luaL_dofile
luaL_dostring
luaL_error
luaL_getmetafield
luaL_getmetatable
luaL_gsub
luaL_loadbuffer
luaL_loadfile
luaL_loadstring
luaL_newmetatable
luaL_newstate
luaL_openlibs
luaL_optint
luaL_optinteger
luaL_optlong
luaL_optlstring
luaL_optnumber
luaL_optstring
luaL_prepbuffer
luaL_pushresult
luaL_ref
luaL_register
luaL_typename
luaL_typerror
luaL_unref
luaL_where


Last update: Fri Mar 23 08:33:19 BRT 2007 tagua-1.0-alpha2/lua/doc/cover.png000066400000000000000000000063511077523320400170020ustar00rootroot00000000000000PNG  IHDRE^N&gAMA a8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IIDATxKpy3,xc$@IQ/ 9r|MG_t%/TT"ǩr$Ŋh*IR$$žgb"¿pt)B[c>+Hh Cfm8.E]0~;dlz9RD^S,dqҕt יOhRV}]绢-;d$s3.Z %R;J>ɢOV)a)e@q= RǢt!eiҸ0A8Re _PLh iz(ƥQz;z= "aLT\V#(h O)LclCk&!AJv쎓LA%ƶh 5mQ:[ioC2ƶE5xxՠ2wp>bfRV*/5˟jljH4Oؔca dJQZQ6St:m3 eZssI^:J$R$R\u&Y($$Ρ! LLL"B5ÆI*/m0J1=o?t[$_$>!^y8Ado?w &?rzY&C%>KGgů߼r4O ۱LL2Ϳ?!_]F'q>:|9+wo2г5Mk\4&s)=Fn0RS{#۳gޘ6+Ϯp.R0Ǔ5"lOs2xottH)ǽx֛owigP!XȐkڸ_ntѾgǯNpzO^62 CGy; rH!j_o6Gl͎>|x?sBmqyΠ9H}s5P(㜾L:[_tkh%)iCC"h}>ՇZSFM H$ou%]?K7Wcߜ"[!^ JJZ۷g~_COq|nkؑZy`D#(Ksk{R?ٿӹv)e>_<}ڛosefal\T3/>Q.ҚuX|Ç"DbddR MY:[}>bfگg?*}=6C}~Utj,YLI,U9i;#{|s-Oomç 叆92\B3CowC,w#G@8Ӈ* \AJ^|OX;.=S[ܹWr]<}SN3˓|mL`ZUl瓋~(bH< ڼvpڛBy%|uP| oa؁RH W|Uk/h.}SQ16@wib>$өӄ|E^;N0NB6{⾺j(ik]F)^2yfk5|<(l ]yh?o\4Df1]<ϸ:bOu2y^=FthPz츌dg\!Q ORbHDn=;o29HD3Wy4-B6i EY)wxDuv5>dqh),WRȆdrܚh 84XX;|7vlo#̈,`qtIME7#IENDB`tagua-1.0-alpha2/lua/doc/logo.gif000066400000000000000000000102101077523320400165720ustar00rootroot00000000000000GIF87arvz}~ oooqqqvvvzzz !!%%""%%)),,55115511::::??BBDDBBEEJJHHLLMMPPTTQQWWYYZZ\\^^``ccggiijjoollqqvvttyy{{~~‰ËŎƐǒȕʙ˙̟ϡϢѥҩөԭ֯ױױصڻݼ,' H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜIpִQ:(RJI;HGSSFAPȑA!rC+j D#:S Y:A mSNF1Rg.=2 @ ;5A)s.:)v 0`ϟlnp#rdDD#xЙ 643#LTFyPE+]s2Qk( ;gGΗPfh ( oNr,NiHG0^s& *92;!lX_mwDGU7 DX qIRw5EA&9MdMDHM(އhcYC$#!~8@I$~! $pP |@ c11abRI!``a㠁Y2qkD;Pv}6jǍ0}F^ipZDE ph2+ar&C }t.GEbC |,s69 P( y0DpVft%Af.KH?,nb9"|/GAH"} A#w:p;x5$sE-I";[Xwu85!KV}[A]$ܩepG pYC@ڄkn:m VXf2 BYzD3 ,.zs9PBD\ lf4y",Bscdqf(6J袋@\[$z@@B ˦=5ɢE8H Dk8F{R= ~}Ν `g-1,RBHe-Ms (!{QHm ` AcRf!F &D `Dvd!B07 ,^lأRPIh~ @r)`$ hC@AG"yX mB4i Y(D8& F+1Rh KIH+ @EJ I* #RWDBhD ,6o| m#DxBЪV@$Y B yC$B*$} ZE @asPJoQ| Η?BYeJB8JH,iuJ&9a!r(#D|,9|D'yF)_st$ @2^o'ЯCh>@dz,F!QHB6I( E9E;C\oh2B5+$T}mHCه:VGjM0$8!mhApfBɏ@ m:O<6t}p<1@"t$H "BZ-6lgq,:@|P aF #Q!a'Qi];$}^V_xpmѳq8K`m[@(m`q! B /[mrg&^&qt$ 6g)l ];FpHA(]r Ƃb`QAFkq72-KMΧh xw=XvA@@m‡ƺXZO/ ?xă(+D,d9}Ev XԽIe 0]4y}'W!)] B|Fq D ͧ?s!#F3_ӣ738 N>@8lH q[ JƱ7(hE6,sI7)F0Vp`[%W25fc"8t.Aa!D@i_qeG#UT4PFxE vDa~ R t<"(WAl-[uf$P%~w9W@xwHv{9whV65P\ "ufoDd2g>6-c0(Y< 1"1O*p)ЊPj*25 0% (@BanS{ DN/%Jҍ  (3 b1$X]RP9Z*)~N-#r]NhGpl с^@FY4}b/M !0U|Me=dE$>pM ~rJ-&&@.\ 87{3`%0ds+1Hh22PK3 W0uE)*U))+ @50FtEOKHP@}^ jH0}U`10 k咹EcVUK$A_z`TEΑUɕ4A֓<RrfPGBza"gd62(ayImF"qc("gAyP0i@eESҘYO9b4"}"x@'Pupj`22,*&qٕf%E+]B%f0YJ3f?1,/p?;}XV5Q%H1Z4JmpOP7d=O y;!ӑpeq!F PP-eKfw.lzp`- j`o@EPOv*RzUP uS@Ĩ!IO*PEAO` p\ P 1{:LSPU@QzRʪ#4PG`Nڬ;tagua-1.0-alpha2/lua/doc/lua.1000066400000000000000000000070431077523320400160200ustar00rootroot00000000000000.\" $Id: lua.man,v 1.11 2006/01/06 16:03:34 lhf Exp $ .TH LUA 1 "$Date: 2006/01/06 16:03:34 $" .SH NAME lua \- Lua interpreter .SH SYNOPSIS .B lua [ .I options ] [ .I script [ .I args ] ] .SH DESCRIPTION .B lua is the stand-alone Lua interpreter. It loads and executes Lua programs, either in textual source form or in precompiled binary form. (Precompiled binaries are output by .BR luac , the Lua compiler.) .B lua can be used as a batch interpreter and also interactively. .LP The given .I options (see below) are executed and then the Lua program in file .I script is loaded and executed. The given .I args are available to .I script as strings in a global table named .BR arg . If these arguments contain spaces or other characters special to the shell, then they should be quoted (but note that the quotes will be removed by the shell). The arguments in .B arg start at 0, which contains the string .RI ' script '. The index of the last argument is stored in .BR arg.n . The arguments given in the command line before .IR script , including the name of the interpreter, are available in negative indices in .BR arg . .LP At the very start, before even handling the command line, .B lua executes the contents of the environment variable .BR LUA_INIT , if it is defined. If the value of .B LUA_INIT is of the form .RI '@ filename ', then .I filename is executed. Otherwise, the string is assumed to be a Lua statement and is executed. .LP Options start with .B '\-' and are described below. You can use .B "'\--'" to signal the end of options. .LP If no arguments are given, then .B "\-v \-i" is assumed when the standard input is a terminal; otherwise, .B "\-" is assumed. .LP In interactive mode, .B lua prompts the user, reads lines from the standard input, and executes them as they are read. If a line does not contain a complete statement, then a secondary prompt is displayed and lines are read until a complete statement is formed or a syntax error is found. So, one way to interrupt the reading of an incomplete statement is to force a syntax error: adding a .B ';' in the middle of a statement is a sure way of forcing a syntax error (except inside multiline strings and comments; these must be closed explicitly). If a line starts with .BR '=' , then .B lua displays the values of all the expressions in the remainder of the line. The expressions must be separated by commas. The primary prompt is the value of the global variable .BR _PROMPT , if this value is a string; otherwise, the default prompt is used. Similarly, the secondary prompt is the value of the global variable .BR _PROMPT2 . So, to change the prompts, set the corresponding variable to a string of your choice. You can do that after calling the interpreter or on the command line (but in this case you have to be careful with quotes if the prompt string contains a space; otherwise you may confuse the shell.) The default prompts are "> " and ">> ". .SH OPTIONS .TP .B \- load and execute the standard input as a file, that is, not interactively, even when the standard input is a terminal. .TP .BI \-e " stat" execute statement .IR stat . You need to quote .I stat if it contains spaces, quotes, or other characters special to the shell. .TP .B \-i enter interactive mode after .I script is executed. .TP .BI \-l " name" call .BI require(' name ') before executing .IR script . Typically used to load libraries. .TP .B \-v show version information. .SH "SEE ALSO" .BR luac (1) .br http://www.lua.org/ .SH DIAGNOSTICS Error messages should be self explanatory. .SH AUTHORS R. Ierusalimschy, L. H. de Figueiredo, and W. Celes .\" EOF tagua-1.0-alpha2/lua/doc/lua.css000066400000000000000000000011141077523320400164410ustar00rootroot00000000000000body { color: #000000 ; background-color: #FFFFFF ; font-family: sans-serif ; text-align: justify ; margin-right: 20px ; margin-left: 20px ; } h1, h2, h3, h4 { font-weight: normal ; font-style: italic ; } a:link { color: #000080 ; background-color: inherit ; text-decoration: none ; } a:visited { background-color: inherit ; text-decoration: none ; } a:link:hover, a:visited:hover { color: #000080 ; background-color: #E0E0FF ; } a:link:active, a:visited:active { color: #FF0000 ; } hr { border: 0 ; height: 1px ; color: #a0a0a0 ; background-color: #a0a0a0 ; } tagua-1.0-alpha2/lua/doc/lua.html000066400000000000000000000075571077523320400166360ustar00rootroot00000000000000 LUA man page

NAME

lua - Lua interpreter

SYNOPSIS

lua [ options ] [ script [ args ] ]

DESCRIPTION

lua is the stand-alone Lua interpreter. It loads and executes Lua programs, either in textual source form or in precompiled binary form. (Precompiled binaries are output by luac, the Lua compiler.) lua can be used as a batch interpreter and also interactively.

The given options (see below) are executed and then the Lua program in file script is loaded and executed. The given args are available to script as strings in a global table named arg. If these arguments contain spaces or other characters special to the shell, then they should be quoted (but note that the quotes will be removed by the shell). The arguments in arg start at 0, which contains the string 'script'. The index of the last argument is stored in arg.n. The arguments given in the command line before script, including the name of the interpreter, are available in negative indices in arg.

At the very start, before even handling the command line, lua executes the contents of the environment variable LUA_INIT, if it is defined. If the value of LUA_INIT is of the form '@filename', then filename is executed. Otherwise, the string is assumed to be a Lua statement and is executed.

Options start with '-' and are described below. You can use '--' to signal the end of options.

If no arguments are given, then "-v -i" is assumed when the standard input is a terminal; otherwise, "-" is assumed.

In interactive mode, lua prompts the user, reads lines from the standard input, and executes them as they are read. If a line does not contain a complete statement, then a secondary prompt is displayed and lines are read until a complete statement is formed or a syntax error is found. So, one way to interrupt the reading of an incomplete statement is to force a syntax error: adding a ';' in the middle of a statement is a sure way of forcing a syntax error (except inside multiline strings and comments; these must be closed explicitly). If a line starts with '=', then lua displays the values of all the expressions in the remainder of the line. The expressions must be separated by commas. The primary prompt is the value of the global variable _PROMPT, if this value is a string; otherwise, the default prompt is used. Similarly, the secondary prompt is the value of the global variable _PROMPT2. So, to change the prompts, set the corresponding variable to a string of your choice. You can do that after calling the interpreter or on the command line (but in this case you have to be careful with quotes if the prompt string contains a space; otherwise you may confuse the shell.) The default prompts are "> " and ">> ".

OPTIONS

- load and execute the standard input as a file, that is, not interactively, even when the standard input is a terminal.

-e stat execute statement stat. You need to quote stat if it contains spaces, quotes, or other characters special to the shell.

-i enter interactive mode after script is executed.

-l name call require('name') before executing script. Typically used to load libraries.

-v show version information.

SEE ALSO

luac(1)
http://www.lua.org/

DIAGNOSTICS

Error messages should be self explanatory.

AUTHORS

R. Ierusalimschy, L. H. de Figueiredo, and W. Celes tagua-1.0-alpha2/lua/doc/luac.1000066400000000000000000000070411077523320400161610ustar00rootroot00000000000000.\" $Id: luac.man,v 1.28 2006/01/06 16:03:34 lhf Exp $ .TH LUAC 1 "$Date: 2006/01/06 16:03:34 $" .SH NAME luac \- Lua compiler .SH SYNOPSIS .B luac [ .I options ] [ .I filenames ] .SH DESCRIPTION .B luac is the Lua compiler. It translates programs written in the Lua programming language into binary files that can be later loaded and executed. .LP The main advantages of precompiling chunks are: faster loading, protecting source code from accidental user changes, and off-line syntax checking. .LP Pre-compiling does not imply faster execution because in Lua chunks are always compiled into bytecodes before being executed. .B luac simply allows those bytecodes to be saved in a file for later execution. .LP Pre-compiled chunks are not necessarily smaller than the corresponding source. The main goal in pre-compiling is faster loading. .LP The binary files created by .B luac are portable only among architectures with the same word size and byte order. .LP .B luac produces a single output file containing the bytecodes for all source files given. By default, the output file is named .BR luac.out , but you can change this with the .B \-o option. .LP In the command line, you can mix text files containing Lua source and binary files containing precompiled chunks. This is useful to combine several precompiled chunks, even from different (but compatible) platforms, into a single precompiled chunk. .LP You can use .B "'\-'" to indicate the standard input as a source file and .B "'\--'" to signal the end of options (that is, all remaining arguments will be treated as files even if they start with .BR "'\-'" ). .LP The internal format of the binary files produced by .B luac is likely to change when a new version of Lua is released. So, save the source files of all Lua programs that you precompile. .LP .SH OPTIONS Options must be separate. .TP .B \-l produce a listing of the compiled bytecode for Lua's virtual machine. Listing bytecodes is useful to learn about Lua's virtual machine. If no files are given, then .B luac loads .B luac.out and lists its contents. .TP .BI \-o " file" output to .IR file , instead of the default .BR luac.out . (You can use .B "'\-'" for standard output, but not on platforms that open standard output in text mode.) The output file may be a source file because all files are loaded before the output file is written. Be careful not to overwrite precious files. .TP .B \-p load files but do not generate any output file. Used mainly for syntax checking and for testing precompiled chunks: corrupted files will probably generate errors when loaded. Lua always performs a thorough integrity test on precompiled chunks. Bytecode that passes this test is completely safe, in the sense that it will not break the interpreter. However, there is no guarantee that such code does anything sensible. (None can be given, because the halting problem is unsolvable.) If no files are given, then .B luac loads .B luac.out and tests its contents. No messages are displayed if the file passes the integrity test. .TP .B \-s strip debug information before writing the output file. This saves some space in very large chunks, but if errors occur when running a stripped chunk, then the error messages may not contain the full information they usually do. For instance, line numbers and names of local variables are lost. .TP .B \-v show version information. .SH FILES .TP 15 .B luac.out default output file .SH "SEE ALSO" .BR lua (1) .br http://www.lua.org/ .SH DIAGNOSTICS Error messages should be self explanatory. .SH AUTHORS L. H. de Figueiredo, R. Ierusalimschy and W. Celes .\" EOF tagua-1.0-alpha2/lua/doc/luac.html000066400000000000000000000074701077523320400167730ustar00rootroot00000000000000 LUAC man page

NAME

luac - Lua compiler

SYNOPSIS

luac [ options ] [ filenames ]

DESCRIPTION

luac is the Lua compiler. It translates programs written in the Lua programming language into binary files that can be later loaded and executed.

The main advantages of precompiling chunks are: faster loading, protecting source code from accidental user changes, and off-line syntax checking.

Precompiling does not imply faster execution because in Lua chunks are always compiled into bytecodes before being executed. luac simply allows those bytecodes to be saved in a file for later execution.

Precompiled chunks are not necessarily smaller than the corresponding source. The main goal in precompiling is faster loading.

The binary files created by luac are portable only among architectures with the same word size and byte order.

luac produces a single output file containing the bytecodes for all source files given. By default, the output file is named luac.out, but you can change this with the -o option.

In the command line, you can mix text files containing Lua source and binary files containing precompiled chunks. This is useful because several precompiled chunks, even from different (but compatible) platforms, can be combined into a single precompiled chunk.

You can use '-' to indicate the standard input as a source file and '--' to signal the end of options (that is, all remaining arguments will be treated as files even if they start with '-').

The internal format of the binary files produced by luac is likely to change when a new version of Lua is released. So, save the source files of all Lua programs that you precompile.

OPTIONS

Options must be separate.

-l produce a listing of the compiled bytecode for Lua's virtual machine. Listing bytecodes is useful to learn about Lua's virtual machine. If no files are given, then luac loads luac.out and lists its contents.

-o file output to file, instead of the default luac.out. (You can use '-' for standard output, but not on platforms that open standard output in text mode.) The output file may be a source file because all files are loaded before the output file is written. Be careful not to overwrite precious files.

-p load files but do not generate any output file. Used mainly for syntax checking and for testing precompiled chunks: corrupted files will probably generate errors when loaded. Lua always performs a thorough integrity test on precompiled chunks. Bytecode that passes this test is completely safe, in the sense that it will not break the interpreter. However, there is no guarantee that such code does anything sensible. (None can be given, because the halting problem is unsolvable.) If no files are given, then luac loads luac.out and tests its contents. No messages are displayed if the file passes the integrity test.

-s strip debug information before writing the output file. This saves some space in very large chunks, but if errors occur when running a stripped chunk, then the error messages may not contain the full information they usually do. For instance, line numbers and names of local variables are lost.

-v show version information.

FILES

luac.out default output file

SEE ALSO

lua(1)
http://www.lua.org/

DIAGNOSTICS

Error messages should be self explanatory.

AUTHORS

L. H. de Figueiredo, R. Ierusalimschy and W. Celes tagua-1.0-alpha2/lua/doc/manual.css000066400000000000000000000001001077523320400171270ustar00rootroot00000000000000h3 code { font-family: inherit ; } pre { font-size: 105% ; } tagua-1.0-alpha2/lua/doc/manual.html000066400000000000000000007320701077523320400173250ustar00rootroot00000000000000 Lua 5.1 Reference Manual

Lua 5.1 Reference Manual

by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

Copyright © 2006-2007 Lua.org, PUC-Rio. Freely available under the terms of the Lua license.


contents · index

1 - Introduction

Lua is an extension programming language designed to support general procedural programming with data description facilities. It also offers good support for object-oriented programming, functional programming, and data-driven programming. Lua is intended to be used as a powerful, light-weight scripting language for any program that needs one. Lua is implemented as a library, written in clean C (that is, in the common subset of ANSI C and C++).

Being an extension language, Lua has no notion of a "main" program: it only works embedded in a host client, called the embedding program or simply the host. This host program can invoke functions to execute a piece of Lua code, can write and read Lua variables, and can register C functions to be called by Lua code. Through the use of C functions, Lua can be augmented to cope with a wide range of different domains, thus creating customized programming languages sharing a syntactical framework. The Lua distribution includes a sample host program called lua, which uses the Lua library to offer a complete, stand-alone Lua interpreter.

Lua is free software, and is provided as usual with no guarantees, as stated in its license. The implementation described in this manual is available at Lua's official web site, www.lua.org.

Like any other reference manual, this document is dry in places. For a discussion of the decisions behind the design of Lua, see the technical papers available at Lua's web site. For a detailed introduction to programming in Lua, see Roberto's book, Programming in Lua (Second Edition).

2 - The Language

This section describes the lexis, the syntax, and the semantics of Lua. In other words, this section describes which tokens are valid, how they can be combined, and what their combinations mean.

The language constructs will be explained using the usual extended BNF notation, in which {a} means 0 or more a's, and [a] means an optional a. Non-terminals are shown like non-terminal, keywords are shown like kword, and other terminal symbols are shown like `=´. The complete syntax of Lua can be found at the end of this manual.

2.1 - Lexical Conventions

Names (also called identifiers) in Lua can be any string of letters, digits, and underscores, not beginning with a digit. This coincides with the definition of names in most languages. (The definition of letter depends on the current locale: any character considered alphabetic by the current locale can be used in an identifier.) Identifiers are used to name variables and table fields.

The following keywords are reserved and cannot be used as names:

     and       break     do        else      elseif
     end       false     for       function  if
     in        local     nil       not       or
     repeat    return    then      true      until     while

Lua is a case-sensitive language: and is a reserved word, but And and AND are two different, valid names. As a convention, names starting with an underscore followed by uppercase letters (such as _VERSION) are reserved for internal global variables used by Lua.

The following strings denote other tokens:

     +     -     *     /     %     ^     #
     ==    ~=    <=    >=    <     >     =
     (     )     {     }     [     ]
     ;     :     ,     .     ..    ...

Literal strings can be delimited by matching single or double quotes, and can contain the following C-like escape sequences: '\a' (bell), '\b' (backspace), '\f' (form feed), '\n' (newline), '\r' (carriage return), '\t' (horizontal tab), '\v' (vertical tab), '\\' (backslash), '\"' (quotation mark [double quote]), and '\'' (apostrophe [single quote]). Moreover, a backslash followed by a real newline results in a newline in the string. A character in a string may also be specified by its numerical value using the escape sequence \ddd, where ddd is a sequence of up to three decimal digits. (Note that if a numerical escape is to be followed by a digit, it must be expressed using exactly three digits.) Strings in Lua may contain any 8-bit value, including embedded zeros, which can be specified as '\0'.

To put a double (single) quote, a newline, a backslash, or an embedded zero inside a literal string enclosed by double (single) quotes you must use an escape sequence. Any other character may be directly inserted into the literal. (Some control characters may cause problems for the file system, but Lua has no problem with them.)

Literal strings can also be defined using a long format enclosed by long brackets. We define an opening long bracket of level n as an opening square bracket followed by n equal signs followed by another opening square bracket. So, an opening long bracket of level 0 is written as [[, an opening long bracket of level 1 is written as [=[, and so on. A closing long bracket is defined similarly; for instance, a closing long bracket of level 4 is written as ]====]. A long string starts with an opening long bracket of any level and ends at the first closing long bracket of the same level. Literals in this bracketed form may run for several lines, do not interpret any escape sequences, and ignore long brackets of any other level. They may contain anything except a closing bracket of the proper level.

For convenience, when the opening long bracket is immediately followed by a newline, the newline is not included in the string. As an example, in a system using ASCII (in which 'a' is coded as 97, newline is coded as 10, and '1' is coded as 49), the five literals below denote the same string:

     a = 'alo\n123"'
     a = "alo\n123\""
     a = '\97lo\10\04923"'
     a = [[alo
     123"]]
     a = [==[
     alo
     123"]==]

A numerical constant may be written with an optional decimal part and an optional decimal exponent. Lua also accepts integer hexadecimal constants, by prefixing them with 0x. Examples of valid numerical constants are

     3   3.0   3.1416   314.16e-2   0.31416E1   0xff   0x56

A comment starts with a double hyphen (--) anywhere outside a string. If the text immediately after -- is not an opening long bracket, the comment is a short comment, which runs until the end of the line. Otherwise, it is a long comment, which runs until the corresponding closing long bracket. Long comments are frequently used to disable code temporarily.

2.2 - Values and Types

Lua is a dynamically typed language. This means that variables do not have types; only values do. There are no type definitions in the language. All values carry their own type.

All values in Lua are first-class values. This means that all values can be stored in variables, passed as arguments to other functions, and returned as results.

There are eight basic types in Lua: nil, boolean, number, string, function, userdata, thread, and table. Nil is the type of the value nil, whose main property is to be different from any other value; it usually represents the absence of a useful value. Boolean is the type of the values false and true. Both nil and false make a condition false; any other value makes it true. Number represents real (double-precision floating-point) numbers. (It is easy to build Lua interpreters that use other internal representations for numbers, such as single-precision float or long integers; see file luaconf.h.) String represents arrays of characters. Lua is 8-bit clean: strings may contain any 8-bit character, including embedded zeros ('\0') (see §2.1).

Lua can call (and manipulate) functions written in Lua and functions written in C (see §2.5.8).

The type userdata is provided to allow arbitrary C data to be stored in Lua variables. This type corresponds to a block of raw memory and has no pre-defined operations in Lua, except assignment and identity test. However, by using metatables, the programmer can define operations for userdata values (see §2.8). Userdata values cannot be created or modified in Lua, only through the C API. This guarantees the integrity of data owned by the host program.

The type thread represents independent threads of execution and it is used to implement coroutines (see §2.11). Do not confuse Lua threads with operating-system threads. Lua supports coroutines on all systems, even those that do not support threads.

The type table implements associative arrays, that is, arrays that can be indexed not only with numbers, but with any value (except nil). Tables can be heterogeneous; that is, they can contain values of all types (except nil). Tables are the sole data structuring mechanism in Lua; they may be used to represent ordinary arrays, symbol tables, sets, records, graphs, trees, etc. To represent records, Lua uses the field name as an index. The language supports this representation by providing a.name as syntactic sugar for a["name"]. There are several convenient ways to create tables in Lua (see §2.5.7).

Like indices, the value of a table field can be of any type (except nil). In particular, because functions are first-class values, table fields may contain functions. Thus tables may also carry methods (see §2.5.9).

Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.

The library function type returns a string describing the type of a given value.

2.2.1 - Coercion

Lua provides automatic conversion between string and number values at run time. Any arithmetic operation applied to a string tries to convert this string to a number, following the usual conversion rules. Conversely, whenever a number is used where a string is expected, the number is converted to a string, in a reasonable format. For complete control over how numbers are converted to strings, use the format function from the string library (see string.format).

2.3 - Variables

Variables are places that store values. There are three kinds of variables in Lua: global variables, local variables, and table fields.

A single name can denote a global variable or a local variable (or a function's formal parameter, which is a particular kind of local variable):

	var ::= Name

Name denotes identifiers, as defined in §2.1.

Any variable is assumed to be global unless explicitly declared as a local (see §2.4.7). Local variables are lexically scoped: local variables can be freely accessed by functions defined inside their scope (see §2.6).

Before the first assignment to a variable, its value is nil.

Square brackets are used to index a table:

	var ::= prefixexp `[´ exp `]´

The meaning of accesses to global variables and table fields can be changed via metatables. An access to an indexed variable t[i] is equivalent to a call gettable_event(t,i). (See §2.8 for a complete description of the gettable_event function. This function is not defined or callable in Lua. We use it here only for explanatory purposes.)

The syntax var.Name is just syntactic sugar for var["Name"]:

	var ::= prefixexp `.´ Name

All global variables live as fields in ordinary Lua tables, called environment tables or simply environments (see §2.9). Each function has its own reference to an environment, so that all global variables in this function will refer to this environment table. When a function is created, it inherits the environment from the function that created it. To get the environment table of a Lua function, you call getfenv. To replace it, you call setfenv. (You can only manipulate the environment of C functions through the debug library; (see §5.9).)

An access to a global variable x is equivalent to _env.x, which in turn is equivalent to

     gettable_event(_env, "x")

where _env is the environment of the running function. (See §2.8 for a complete description of the gettable_event function. This function is not defined or callable in Lua. Similarly, the _env variable is not defined in Lua. We use them here only for explanatory purposes.)

2.4 - Statements

Lua supports an almost conventional set of statements, similar to those in Pascal or C. This set includes assignment, control structures, function calls, and variable declarations.

2.4.1 - Chunks

The unit of execution of Lua is called a chunk. A chunk is simply a sequence of statements, which are executed sequentially. Each statement can be optionally followed by a semicolon:

	chunk ::= {stat [`;´]}

There are no empty statements and thus ';;' is not legal.

Lua handles a chunk as the body of an anonymous function with a variable number of arguments (see §2.5.9). As such, chunks can define local variables, receive arguments, and return values.

A chunk may be stored in a file or in a string inside the host program. When a chunk is executed, first it is pre-compiled into instructions for a virtual machine, and then the compiled code is executed by an interpreter for the virtual machine.

Chunks may also be pre-compiled into binary form; see program luac for details. Programs in source and compiled forms are interchangeable; Lua automatically detects the file type and acts accordingly.

2.4.2 - Blocks

A block is a list of statements; syntactically, a block is the same as a chunk:

	block ::= chunk

A block may be explicitly delimited to produce a single statement:

	stat ::= do block end

Explicit blocks are useful to control the scope of variable declarations. Explicit blocks are also sometimes used to add a return or break statement in the middle of another block (see §2.4.4).

2.4.3 - Assignment

Lua allows multiple assignment. Therefore, the syntax for assignment defines a list of variables on the left side and a list of expressions on the right side. The elements in both lists are separated by commas:

	stat ::= varlist1 `=´ explist1
	varlist1 ::= var {`,´ var}
	explist1 ::= exp {`,´ exp}

Expressions are discussed in §2.5.

Before the assignment, the list of values is adjusted to the length of the list of variables. If there are more values than needed, the excess values are thrown away. If there are fewer values than needed, the list is extended with as many nil's as needed. If the list of expressions ends with a function call, then all values returned by this call enter in the list of values, before the adjustment (except when the call is enclosed in parentheses; see §2.5).

The assignment statement first evaluates all its expressions and only then are the assignments performed. Thus the code

     i = 3
     i, a[i] = i+1, 20

sets a[3] to 20, without affecting a[4] because the i in a[i] is evaluated (to 3) before it is assigned 4. Similarly, the line

     x, y = y, x

exchanges the values of x and y.

The meaning of assignments to global variables and table fields can be changed via metatables. An assignment to an indexed variable t[i] = val is equivalent to settable_event(t,i,val). (See §2.8 for a complete description of the settable_event function. This function is not defined or callable in Lua. We use it here only for explanatory purposes.)

An assignment to a global variable x = val is equivalent to the assignment _env.x = val, which in turn is equivalent to

     settable_event(_env, "x", val)

where _env is the environment of the running function. (The _env variable is not defined in Lua. We use it here only for explanatory purposes.)

2.4.4 - Control Structures

The control structures if, while, and repeat have the usual meaning and familiar syntax:

	stat ::= while exp do block end
	stat ::= repeat block until exp
	stat ::= if exp then block {elseif exp then block} [else block] end

Lua also has a for statement, in two flavors (see §2.4.5).

The condition expression of a control structure may return any value. Both false and nil are considered false. All values different from nil and false are considered true (in particular, the number 0 and the empty string are also true).

In the repeatuntil loop, the inner block does not end at the until keyword, but only after the condition. So, the condition can refer to local variables declared inside the loop block.

The return statement is used to return values from a function or a chunk (which is just a function). Functions and chunks may return more than one value, so the syntax for the return statement is

	stat ::= return [explist1]

The break statement is used to terminate the execution of a while, repeat, or for loop, skipping to the next statement after the loop:

	stat ::= break

A break ends the innermost enclosing loop.

The return and break statements can only be written as the last statement of a block. If it is really necessary to return or break in the middle of a block, then an explicit inner block can be used, as in the idioms do return end and do break end, because now return and break are the last statements in their (inner) blocks.

2.4.5 - For Statement

The for statement has two forms: one numeric and one generic.

The numeric for loop repeats a block of code while a control variable runs through an arithmetic progression. It has the following syntax:

	stat ::= for Name `=´ exp `,´ exp [`,´ exp] do block end

The block is repeated for name starting at the value of the first exp, until it passes the second exp by steps of the third exp. More precisely, a for statement like

     for v = e1, e2, e3 do block end

is equivalent to the code:

     do
       local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
       if not (var and limit and step) then error() end
       while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do
         local v = var
         block
         var = var + step
       end
     end

Note the following:

  • All three control expressions are evaluated only once, before the loop starts. They must all result in numbers.
  • var, limit, and step are invisible variables. The names are here for explanatory purposes only.
  • If the third expression (the step) is absent, then a step of 1 is used.
  • You can use break to exit a for loop.
  • The loop variable v is local to the loop; you cannot use its value after the for ends or is broken. If you need this value, assign it to another variable before breaking or exiting the loop.

The generic for statement works over functions, called iterators. On each iteration, the iterator function is called to produce a new value, stopping when this new value is nil. The generic for loop has the following syntax:

	stat ::= for namelist in explist1 do block end
	namelist ::= Name {`,´ Name}

A for statement like

     for var_1, ···, var_n in explist do block end

is equivalent to the code:

     do
       local f, s, var = explist
       while true do
         local var_1, ···, var_n = f(s, var)
         var = var_1
         if var == nil then break end
         block
       end
     end

Note the following:

  • explist is evaluated only once. Its results are an iterator function, a state, and an initial value for the first iterator variable.
  • f, s, and var are invisible variables. The names are here for explanatory purposes only.
  • You can use break to exit a for loop.
  • The loop variables var_i are local to the loop; you cannot use their values after the for ends. If you need these values, then assign them to other variables before breaking or exiting the loop.

2.4.6 - Function Calls as Statements

To allow possible side-effects, function calls can be executed as statements:

	stat ::= functioncall

In this case, all returned values are thrown away. Function calls are explained in §2.5.8.

2.4.7 - Local Declarations

Local variables may be declared anywhere inside a block. The declaration may include an initial assignment:

	stat ::= local namelist [`=´ explist1]

If present, an initial assignment has the same semantics of a multiple assignment (see §2.4.3). Otherwise, all variables are initialized with nil.

A chunk is also a block (see §2.4.1), and so local variables can be declared in a chunk outside any explicit block. The scope of such local variables extends until the end of the chunk.

The visibility rules for local variables are explained in §2.6.

2.5 - Expressions

The basic expressions in Lua are the following:

	exp ::= prefixexp
	exp ::= nil | false | true
	exp ::= Number
	exp ::= String
	exp ::= function
	exp ::= tableconstructor
	exp ::= `...´
	exp ::= exp binop exp
	exp ::= unop exp
	prefixexp ::= var | functioncall | `(´ exp `)´

Numbers and literal strings are explained in §2.1; variables are explained in §2.3; function definitions are explained in §2.5.9; function calls are explained in §2.5.8; table constructors are explained in §2.5.7. Vararg expressions, denoted by three dots ('...'), can only be used when directly inside a vararg function; they are explained in §2.5.9.

Binary operators comprise arithmetic operators (see §2.5.1), relational operators (see §2.5.2), logical operators (see §2.5.3), and the concatenation operator (see §2.5.4). Unary operators comprise the unary minus (see §2.5.1), the unary not (see §2.5.3), and the unary length operator (see §2.5.5).

Both function calls and vararg expressions may result in multiple values. If the expression is used as a statement (see §2.4.6) (only possible for function calls), then its return list is adjusted to zero elements, thus discarding all returned values. If the expression is used as the last (or the only) element of a list of expressions, then no adjustment is made (unless the call is enclosed in parentheses). In all other contexts, Lua adjusts the result list to one element, discarding all values except the first one.

Here are some examples:

     f()                -- adjusted to 0 results
     g(f(), x)          -- f() is adjusted to 1 result
     g(x, f())          -- g gets x plus all results from f()
     a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)
     a,b = ...          -- a gets the first vararg parameter, b gets
                        -- the second (both a and b may get nil if there
                        -- is no corresponding vararg parameter)
     
     a,b,c = x, f()     -- f() is adjusted to 2 results
     a,b,c = f()        -- f() is adjusted to 3 results
     return f()         -- returns all results from f()
     return ...         -- returns all received vararg parameters
     return x,y,f()     -- returns x, y, and all results from f()
     {f()}              -- creates a list with all results from f()
     {...}              -- creates a list with all vararg parameters
     {f(), nil}         -- f() is adjusted to 1 result

An expression enclosed in parentheses always results in only one value. Thus, (f(x,y,z)) is always a single value, even if f returns several values. (The value of (f(x,y,z)) is the first value returned by f or nil if f does not return any values.)

2.5.1 - Arithmetic Operators

Lua supports the usual arithmetic operators: the binary + (addition), - (subtraction), * (multiplication), / (division), % (modulo), and ^ (exponentiation); and unary - (negation). If the operands are numbers, or strings that can be converted to numbers (see §2.2.1), then all operations have the usual meaning. Exponentiation works for any exponent. For instance, x^(-0.5) computes the inverse of the square root of x. Modulo is defined as

     a % b == a - math.floor(a/b)*b

That is, it is the remainder of a division that rounds the quotient towards minus infinity.

2.5.2 - Relational Operators

The relational operators in Lua are

     ==    ~=    <     >     <=    >=

These operators always result in false or true.

Equality (==) first compares the type of its operands. If the types are different, then the result is false. Otherwise, the values of the operands are compared. Numbers and strings are compared in the usual way. Objects (tables, userdata, threads, and functions) are compared by reference: two objects are considered equal only if they are the same object. Every time you create a new object (a table, userdata, thread, or function), this new object is different from any previously existing object.

You can change the way that Lua compares tables and userdata by using the "eq" metamethod (see §2.8).

The conversion rules of §2.2.1 do not apply to equality comparisons. Thus, "0"==0 evaluates to false, and t[0] and t["0"] denote different entries in a table.

The operator ~= is exactly the negation of equality (==).

The order operators work as follows. If both arguments are numbers, then they are compared as such. Otherwise, if both arguments are strings, then their values are compared according to the current locale. Otherwise, Lua tries to call the "lt" or the "le" metamethod (see §2.8).

2.5.3 - Logical Operators

The logical operators in Lua are and, or, and not. Like the control structures (see §2.4.4), all logical operators consider both false and nil as false and anything else as true.

The negation operator not always returns false or true. The conjunction operator and returns its first argument if this value is false or nil; otherwise, and returns its second argument. The disjunction operator or returns its first argument if this value is different from nil and false; otherwise, or returns its second argument. Both and and or use short-cut evaluation; that is, the second operand is evaluated only if necessary. Here are some examples:

     10 or 20            --> 10
     10 or error()       --> 10
     nil or "a"          --> "a"
     nil and 10          --> nil
     false and error()   --> false
     false and nil       --> false
     false or nil        --> nil
     10 and 20           --> 20

(In this manual, --> indicates the result of the preceding expression.)

2.5.4 - Concatenation

The string concatenation operator in Lua is denoted by two dots ('..'). If both operands are strings or numbers, then they are converted to strings according to the rules mentioned in §2.2.1. Otherwise, the "concat" metamethod is called (see §2.8).

2.5.5 - The Length Operator

The length operator is denoted by the unary operator #. The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte).

The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n may be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. If the array has "holes" (that is, nil values between other non-nil values), then #t may be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).

2.5.6 - Precedence

Operator precedence in Lua follows the table below, from lower to higher priority:

     or
     and
     <     >     <=    >=    ~=    ==
     ..
     +     -
     *     /     %
     not   #     - (unary)
     ^

As usual, you can use parentheses to change the precedences of an expression. The concatenation ('..') and exponentiation ('^') operators are right associative. All other binary operators are left associative.

2.5.7 - Table Constructors

Table constructors are expressions that create tables. Every time a constructor is evaluated, a new table is created. Constructors can be used to create empty tables, or to create a table and initialize some of its fields. The general syntax for constructors is

	tableconstructor ::= `{´ [fieldlist] `}´
	fieldlist ::= field {fieldsep field} [fieldsep]
	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
	fieldsep ::= `,´ | `;´

Each field of the form [exp1] = exp2 adds to the new table an entry with key exp1 and value exp2. A field of the form name = exp is equivalent to ["name"] = exp. Finally, fields of the form exp are equivalent to [i] = exp, where i are consecutive numerical integers, starting with 1. Fields in the other formats do not affect this counting. For example,

     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }

is equivalent to

     do
       local t = {}
       t[f(1)] = g
       t[1] = "x"         -- 1st exp
       t[2] = "y"         -- 2nd exp
       t.x = 1            -- t["x"] = 1
       t[3] = f(x)        -- 3rd exp
       t[30] = 23
       t[4] = 45          -- 4th exp
       a = t
     end

If the last field in the list has the form exp and the expression is a function call or a vararg expression, then all values returned by this expression enter the list consecutively (see §2.5.8). To avoid this, enclose the function call (or the vararg expression) in parentheses (see §2.5).

The field list may have an optional trailing separator, as a convenience for machine-generated code.

2.5.8 - Function Calls

A function call in Lua has the following syntax:

	functioncall ::= prefixexp args

In a function call, first prefixexp and args are evaluated. If the value of prefixexp has type function, then this function is called with the given arguments. Otherwise, the prefixexp "call" metamethod is called, having as first parameter the value of prefixexp, followed by the original call arguments (see §2.8).

The form

	functioncall ::= prefixexp `:´ Name args

can be used to call "methods". A call v:name(args) is syntactic sugar for v.name(v,args), except that v is evaluated only once.

Arguments have the following syntax:

	args ::= `(´ [explist1] `)´
	args ::= tableconstructor
	args ::= String

All argument expressions are evaluated before the call. A call of the form f{fields} is syntactic sugar for f({fields}); that is, the argument list is a single new table. A call of the form f'string' (or f"string" or f[[string]]) is syntactic sugar for f('string'); that is, the argument list is a single literal string.

As an exception to the free-format syntax of Lua, you cannot put a line break before the '(' in a function call. This restriction avoids some ambiguities in the language. If you write

     a = f
     (g).x(a)

Lua would see that as a single statement, a = f(g).x(a). So, if you want two statements, you must add a semi-colon between them. If you actually want to call f, you must remove the line break before (g).

A call of the form return functioncall is called a tail call. Lua implements proper tail calls (or proper tail recursion): in a tail call, the called function reuses the stack entry of the calling function. Therefore, there is no limit on the number of nested tail calls that a program can execute. However, a tail call erases any debug information about the calling function. Note that a tail call only happens with a particular syntax, where the return has one single function call as argument; this syntax makes the calling function return exactly the returns of the called function. So, none of the following examples are tail calls:

     return (f(x))        -- results adjusted to 1
     return 2 * f(x)
     return x, f(x)       -- additional results
     f(x); return         -- results discarded
     return x or f(x)     -- results adjusted to 1

2.5.9 - Function Definitions

The syntax for function definition is

	function ::= function funcbody
	funcbody ::= `(´ [parlist1] `)´ block end

The following syntactic sugar simplifies function definitions:

	stat ::= function funcname funcbody
	stat ::= local function Name funcbody
	funcname ::= Name {`.´ Name} [`:´ Name]

The statement

     function f () body end

translates to

     f = function () body end

The statement

     function t.a.b.c.f () body end

translates to

     t.a.b.c.f = function () body end

The statement

     local function f () body end

translates to

     local f; f = function () body end

not to

     local f = function () body end

(This only makes a difference when the body of the function contains references to f.)

A function definition is an executable expression, whose value has type function. When Lua pre-compiles a chunk, all its function bodies are pre-compiled too. Then, whenever Lua executes the function definition, the function is instantiated (or closed). This function instance (or closure) is the final value of the expression. Different instances of the same function may refer to different external local variables and may have different environment tables.

Parameters act as local variables that are initialized with the argument values:

	parlist1 ::= namelist [`,´ `...´] | `...´

When a function is called, the list of arguments is adjusted to the length of the list of parameters, unless the function is a variadic or vararg function, which is indicated by three dots ('...') at the end of its parameter list. A vararg function does not adjust its argument list; instead, it collects all extra arguments and supplies them to the function through a vararg expression, which is also written as three dots. The value of this expression is a list of all actual extra arguments, similar to a function with multiple results. If a vararg expression is used inside another expression or in the middle of a list of expressions, then its return list is adjusted to one element. If the expression is used as the last element of a list of expressions, then no adjustment is made (unless the call is enclosed in parentheses).

As an example, consider the following definitions:

     function f(a, b) end
     function g(a, b, ...) end
     function r() return 1,2,3 end

Then, we have the following mapping from arguments to parameters and to the vararg expression:

     CALL            PARAMETERS
     
     f(3)             a=3, b=nil
     f(3, 4)          a=3, b=4
     f(3, 4, 5)       a=3, b=4
     f(r(), 10)       a=1, b=10
     f(r())           a=1, b=2
     
     g(3)             a=3, b=nil, ... -->  (nothing)
     g(3, 4)          a=3, b=4,   ... -->  (nothing)
     g(3, 4, 5, 8)    a=3, b=4,   ... -->  5  8
     g(5, r())        a=5, b=1,   ... -->  2  3

Results are returned using the return statement (see §2.4.4). If control reaches the end of a function without encountering a return statement, then the function returns with no results.

The colon syntax is used for defining methods, that is, functions that have an implicit extra parameter self. Thus, the statement

     function t.a.b.c:f (params) body end

is syntactic sugar for

     t.a.b.c.f = function (self, params) body end

2.6 - Visibility Rules

Lua is a lexically scoped language. The scope of variables begins at the first statement after their declaration and lasts until the end of the innermost block that includes the declaration. Consider the following example:

     x = 10                -- global variable
     do                    -- new block
       local x = x         -- new 'x', with value 10
       print(x)            --> 10
       x = x+1
       do                  -- another block
         local x = x+1     -- another 'x'
         print(x)          --> 12
       end
       print(x)            --> 11
     end
     print(x)              --> 10  (the global one)

Notice that, in a declaration like local x = x, the new x being declared is not in scope yet, and so the second x refers to the outside variable.

Because of the lexical scoping rules, local variables can be freely accessed by functions defined inside their scope. A local variable used by an inner function is called an upvalue, or external local variable, inside the inner function.

Notice that each execution of a local statement defines new local variables. Consider the following example:

     a = {}
     local x = 20
     for i=1,10 do
       local y = 0
       a[i] = function () y=y+1; return x+y end
     end

The loop creates ten closures (that is, ten instances of the anonymous function). Each of these closures uses a different y variable, while all of them share the same x.

2.7 - Error Handling

Because Lua is an embedded extension language, all Lua actions start from C code in the host program calling a function from the Lua library (see lua_pcall). Whenever an error occurs during Lua compilation or execution, control returns to C, which can take appropriate measures (such as printing an error message).

Lua code can explicitly generate an error by calling the error function. If you need to catch errors in Lua, you can use the pcall function.

2.8 - Metatables

Every value in Lua may have a metatable. This metatable is an ordinary Lua table that defines the behavior of the original value under certain special operations. You can change several aspects of the behavior of operations over a value by setting specific fields in its metatable. For instance, when a non-numeric value is the operand of an addition, Lua checks for a function in the field "__add" in its metatable. If it finds one, Lua calls this function to perform the addition.

We call the keys in a metatable events and the values metamethods. In the previous example, the event is "add" and the metamethod is the function that performs the addition.

You can query the metatable of any value through the getmetatable function.

You can replace the metatable of tables through the setmetatable function. You cannot change the metatable of other types from Lua (except using the debug library); you must use the C API for that.

Tables and userdata have individual metatables (although multiple tables and userdata can share their metatables); values of all other types share one single metatable per type. So, there is one single metatable for all numbers, and for all strings, etc.

A metatable may control how an object behaves in arithmetic operations, order comparisons, concatenation, length operation, and indexing. A metatable can also define a function to be called when a userdata is garbage collected. For each of these operations Lua associates a specific key called an event. When Lua performs one of these operations over a value, it checks whether this value has a metatable with the corresponding event. If so, the value associated with that key (the metamethod) controls how Lua will perform the operation.

Metatables control the operations listed next. Each operation is identified by its corresponding name. The key for each operation is a string with its name prefixed by two underscores, '__'; for instance, the key for operation "add" is the string "__add". The semantics of these operations is better explained by a Lua function describing how the interpreter executes the operation.

The code shown here in Lua is only illustrative; the real behavior is hard coded in the interpreter and it is much more efficient than this simulation. All functions used in these descriptions (rawget, tonumber, etc.) are described in §5.1. In particular, to retrieve the metamethod of a given object, we use the expression

     metatable(obj)[event]

This should be read as

     rawget(getmetatable(obj) or {}, event)

That is, the access to a metamethod does not invoke other metamethods, and the access to objects with no metatables does not fail (it simply results in nil).

  • "add": the + operation.

    The function getbinhandler below defines how Lua chooses a handler for a binary operation. First, Lua tries the first operand. If its type does not define a handler for the operation, then Lua tries the second operand.

         function getbinhandler (op1, op2, event)
           return metatable(op1)[event] or metatable(op2)[event]
         end
    

    By using this function, the behavior of the op1 + op2 is

         function add_event (op1, op2)
           local o1, o2 = tonumber(op1), tonumber(op2)
           if o1 and o2 then  -- both operands are numeric?
             return o1 + o2   -- '+' here is the primitive 'add'
           else  -- at least one of the operands is not numeric
             local h = getbinhandler(op1, op2, "__add")
             if h then
               -- call the handler with both operands
               return h(op1, op2)
             else  -- no handler available: default behavior
               error(···)
             end
           end
         end
    

  • "sub": the - operation. Behavior similar to the "add" operation.
  • "mul": the * operation. Behavior similar to the "add" operation.
  • "div": the / operation. Behavior similar to the "add" operation.
  • "mod": the % operation. Behavior similar to the "add" operation, with the operation o1 - floor(o1/o2)*o2 as the primitive operation.
  • "pow": the ^ (exponentiation) operation. Behavior similar to the "add" operation, with the function pow (from the C math library) as the primitive operation.
  • "unm": the unary - operation.
         function unm_event (op)
           local o = tonumber(op)
           if o then  -- operand is numeric?
             return -o  -- '-' here is the primitive 'unm'
           else  -- the operand is not numeric.
             -- Try to get a handler from the operand
             local h = metatable(op).__unm
             if h then
               -- call the handler with the operand
               return h(op)
             else  -- no handler available: default behavior
               error(···)
             end
           end
         end
    

  • "concat": the .. (concatenation) operation.
         function concat_event (op1, op2)
           if (type(op1) == "string" or type(op1) == "number") and
              (type(op2) == "string" or type(op2) == "number") then
             return op1 .. op2  -- primitive string concatenation
           else
             local h = getbinhandler(op1, op2, "__concat")
             if h then
               return h(op1, op2)
             else
               error(···)
             end
           end
         end
    

  • "len": the # operation.
         function len_event (op)
           if type(op) == "string" then
             return strlen(op)         -- primitive string length
           elseif type(op) == "table" then
             return #op                -- primitive table length
           else
             local h = metatable(op).__len
             if h then
               -- call the handler with the operand
               return h(op)
             else  -- no handler available: default behavior
               error(···)
             end
           end
         end
    

    See §2.5.5 for a description of the length of a table.

  • "eq": the == operation. The function getcomphandler defines how Lua chooses a metamethod for comparison operators. A metamethod only is selected when both objects being compared have the same type and the same metamethod for the selected operation.
         function getcomphandler (op1, op2, event)
           if type(op1) ~= type(op2) then return nil end
           local mm1 = metatable(op1)[event]
           local mm2 = metatable(op2)[event]
           if mm1 == mm2 then return mm1 else return nil end
         end
    

    The "eq" event is defined as follows:

         function eq_event (op1, op2)
           if type(op1) ~= type(op2) then  -- different types?
             return false   -- different objects
           end
           if op1 == op2 then   -- primitive equal?
             return true   -- objects are equal
           end
           -- try metamethod
           local h = getcomphandler(op1, op2, "__eq")
           if h then
             return h(op1, op2)
           else
             return false
           end
         end
    

    a ~= b is equivalent to not (a == b).

  • "lt": the < operation.
         function lt_event (op1, op2)
           if type(op1) == "number" and type(op2) == "number" then
             return op1 < op2   -- numeric comparison
           elseif type(op1) == "string" and type(op2) == "string" then
             return op1 < op2   -- lexicographic comparison
           else
             local h = getcomphandler(op1, op2, "__lt")
             if h then
               return h(op1, op2)
             else
               error(···);
             end
           end
         end
    

    a > b is equivalent to b < a.

  • "le": the <= operation.
         function le_event (op1, op2)
           if type(op1) == "number" and type(op2) == "number" then
             return op1 <= op2   -- numeric comparison
           elseif type(op1) == "string" and type(op2) == "string" then
             return op1 <= op2   -- lexicographic comparison
           else
             local h = getcomphandler(op1, op2, "__le")
             if h then
               return h(op1, op2)
             else
               h = getcomphandler(op1, op2, "__lt")
               if h then
                 return not h(op2, op1)
               else
                 error(···);
               end
             end
           end
         end
    

    a >= b is equivalent to b <= a. Note that, in the absence of a "le" metamethod, Lua tries the "lt", assuming that a <= b is equivalent to not (b < a).

  • "index": The indexing access table[key].
         function gettable_event (table, key)
           local h
           if type(table) == "table" then
             local v = rawget(table, key)
             if v ~= nil then return v end
             h = metatable(table).__index
             if h == nil then return nil end
           else
             h = metatable(table).__index
             if h == nil then
               error(···);
             end
           end
           if type(h) == "function" then
             return h(table, key)      -- call the handler
           else return h[key]          -- or repeat operation on it
           end
         end
    

  • "newindex": The indexing assignment table[key] = value.
         function settable_event (table, key, value)
           local h
           if type(table) == "table" then
             local v = rawget(table, key)
             if v ~= nil then rawset(table, key, value); return end
             h = metatable(table).__newindex
             if h == nil then rawset(table, key, value); return end
           else
             h = metatable(table).__newindex
             if h == nil then
               error(···);
             end
           end
           if type(h) == "function" then
             return h(table, key,value)    -- call the handler
           else h[key] = value             -- or repeat operation on it
           end
         end
    

  • "call": called when Lua calls a value.
         function function_event (func, ...)
           if type(func) == "function" then
             return func(...)   -- primitive call
           else
             local h = metatable(func).__call
             if h then
               return h(func, ...)
             else
               error(···)
             end
           end
         end
    

2.9 - Environments

Besides metatables, objects of types thread, function, and userdata have another table associated with them, called their environment. Like metatables, environments are regular tables and multiple objects can share the same environment.

Environments associated with userdata have no meaning for Lua. It is only a convenience feature for programmers to associate a table to a userdata.

Environments associated with threads are called global environments. They are used as the default environment for their threads and non-nested functions created by the thread (through loadfile, loadstring or load) and can be directly accessed by C code (see §3.3).

Environments associated with C functions can be directly accessed by C code (see §3.3). They are used as the default environment for other C functions created by the function.

Environments associated with Lua functions are used to resolve all accesses to global variables within the function (see §2.3). They are used as the default environment for other Lua functions created by the function.

You can change the environment of a Lua function or the running thread by calling setfenv. You can get the environment of a Lua function or the running thread by calling getfenv. To manipulate the environment of other objects (userdata, C functions, other threads) you must use the C API.

2.10 - Garbage Collection

Lua performs automatic memory management. This means that you have to worry neither about allocating memory for new objects nor about freeing it when the objects are no longer needed. Lua manages memory automatically by running a garbage collector from time to time to collect all dead objects (that is, these objects that are no longer accessible from Lua). All objects in Lua are subject to automatic management: tables, userdata, functions, threads, and strings.

Lua implements an incremental mark-and-sweep collector. It uses two numbers to control its garbage-collection cycles: the garbage-collector pause and the garbage-collector step multiplier.

The garbage-collector pause controls how long the collector waits before starting a new cycle. Larger values make the collector less aggressive. Values smaller than 1 mean the collector will not wait to start a new cycle. A value of 2 means that the collector waits for the total memory in use to double before starting a new cycle.

The step multiplier controls the relative speed of the collector relative to memory allocation. Larger values make the collector more aggressive but also increase the size of each incremental step. Values smaller than 1 make the collector too slow and may result in the collector never finishing a cycle. The default, 2, means that the collector runs at "twice" the speed of memory allocation.

You can change these numbers by calling lua_gc in C or collectgarbage in Lua. Both get percentage points as arguments (so an argument of 100 means a real value of 1). With these functions you can also control the collector directly (e.g., stop and restart it).

2.10.1 - Garbage-Collection Metamethods

Using the C API, you can set garbage-collector metamethods for userdata (see §2.8). These metamethods are also called finalizers. Finalizers allow you to coordinate Lua's garbage collection with external resource management (such as closing files, network or database connections, or freeing your own memory).

Garbage userdata with a field __gc in their metatables are not collected immediately by the garbage collector. Instead, Lua puts them in a list. After the collection, Lua does the equivalent of the following function for each userdata in that list:

     function gc_event (udata)
       local h = metatable(udata).__gc
       if h then
         h(udata)
       end
     end

At the end of each garbage-collection cycle, the finalizers for userdata are called in reverse order of their creation, among those collected in that cycle. That is, the first finalizer to be called is the one associated with the userdata created last in the program.

2.10.2 - Weak Tables

A weak table is a table whose elements are weak references. A weak reference is ignored by the garbage collector. In other words, if the only references to an object are weak references, then the garbage collector will collect this object.

A weak table can have weak keys, weak values, or both. A table with weak keys allows the collection of its keys, but prevents the collection of its values. A table with both weak keys and weak values allows the collection of both keys and values. In any case, if either the key or the value is collected, the whole pair is removed from the table. The weakness of a table is controlled by the __mode field of its metatable. If the __mode field is a string containing the character 'k', the keys in the table are weak. If __mode contains 'v', the values in the table are weak.

After you use a table as a metatable, you should not change the value of its field __mode. Otherwise, the weak behavior of the tables controlled by this metatable is undefined.

2.11 - Coroutines

Lua supports coroutines, also called collaborative multithreading. A coroutine in Lua represents an independent thread of execution. Unlike threads in multithread systems, however, a coroutine only suspends its execution by explicitly calling a yield function.

You create a coroutine with a call to coroutine.create. Its sole argument is a function that is the main function of the coroutine. The create function only creates a new coroutine and returns a handle to it (an object of type thread); it does not start the coroutine execution.

When you first call coroutine.resume, passing as its first argument the thread returned by coroutine.create, the coroutine starts its execution, at the first line of its main function. Extra arguments passed to coroutine.resume are passed on to the coroutine main function. After the coroutine starts running, it runs until it terminates or yields.

A coroutine can terminate its execution in two ways: normally, when its main function returns (explicitly or implicitly, after the last instruction); and abnormally, if there is an unprotected error. In the first case, coroutine.resume returns true, plus any values returned by the coroutine main function. In case of errors, coroutine.resume returns false plus an error message.

A coroutine yields by calling coroutine.yield. When a coroutine yields, the corresponding coroutine.resume returns immediately, even if the yield happens inside nested function calls (that is, not in the main function, but in a function directly or indirectly called by the main function). In the case of a yield, coroutine.resume also returns true, plus any values passed to coroutine.yield. The next time you resume the same coroutine, it continues its execution from the point where it yielded, with the call to coroutine.yield returning any extra arguments passed to coroutine.resume.

Like coroutine.create, the coroutine.wrap function also creates a coroutine, but instead of returning the coroutine itself, it returns a function that, when called, resumes the coroutine. Any arguments passed to this function go as extra arguments to coroutine.resume. coroutine.wrap returns all the values returned by coroutine.resume, except the first one (the boolean error code). Unlike coroutine.resume, coroutine.wrap does not catch errors; any error is propagated to the caller.

As an example, consider the following code:

     function foo (a)
       print("foo", a)
       return coroutine.yield(2*a)
     end
     
     co = coroutine.create(function (a,b)
           print("co-body", a, b)
           local r = foo(a+1)
           print("co-body", r)
           local r, s = coroutine.yield(a+b, a-b)
           print("co-body", r, s)
           return b, "end"
     end)
            
     print("main", coroutine.resume(co, 1, 10))
     print("main", coroutine.resume(co, "r"))
     print("main", coroutine.resume(co, "x", "y"))
     print("main", coroutine.resume(co, "x", "y"))

When you run it, it produces the following output:

     co-body 1       10
     foo     2
     
     main    true    4
     co-body r
     main    true    11      -9
     co-body x       y
     main    true    10      end
     main    false   cannot resume dead coroutine

3 - The Application Program Interface

This section describes the C API for Lua, that is, the set of C functions available to the host program to communicate with Lua. All API functions and related types and constants are declared in the header file lua.h.

Even when we use the term "function", any facility in the API may be provided as a macro instead. All such macros use each of their arguments exactly once (except for the first argument, which is always a Lua state), and so do not generate any hidden side-effects.

As in most C libraries, the Lua API functions do not check their arguments for validity or consistency. However, you can change this behavior by compiling Lua with a proper definition for the macro luai_apicheck, in file luaconf.h.

3.1 - The Stack

Lua uses a virtual stack to pass values to and from C. Each element in this stack represents a Lua value (nil, number, string, etc.).

Whenever Lua calls C, the called function gets a new stack, which is independent of previous stacks and of stacks of C functions that are still active. This stack initially contains any arguments to the C function and it is where the C function pushes its results to be returned to the caller (see lua_CFunction).

For convenience, most query operations in the API do not follow a strict stack discipline. Instead, they can refer to any element in the stack by using an index: A positive index represents an absolute stack position (starting at 1); a negative index represents an offset relative to the top of the stack. More specifically, if the stack has n elements, then index 1 represents the first element (that is, the element that was pushed onto the stack first) and index n represents the last element; index -1 also represents the last element (that is, the element at the top) and index -n represents the first element. We say that an index is valid if it lies between 1 and the stack top (that is, if 1 ≤ abs(index) ≤ top).

3.2 - Stack Size

When you interact with Lua API, you are responsible for ensuring consistency. In particular, you are responsible for controlling stack overflow. You can use the function lua_checkstack to grow the stack size.

Whenever Lua calls C, it ensures that at least LUA_MINSTACK stack positions are available. LUA_MINSTACK is defined as 20, so that usually you do not have to worry about stack space unless your code has loops pushing elements onto the stack.

Most query functions accept as indices any value inside the available stack space, that is, indices up to the maximum stack size you have set through lua_checkstack. Such indices are called acceptable indices. More formally, we define an acceptable index as follows:

     (index < 0 && abs(index) <= top) ||
     (index > 0 && index <= stackspace)

Note that 0 is never an acceptable index.

3.3 - Pseudo-Indices

Unless otherwise noted, any function that accepts valid indices can also be called with pseudo-indices, which represent some Lua values that are accessible to C code but which are not in the stack. Pseudo-indices are used to access the thread environment, the function environment, the registry, and the upvalues of a C function (see §3.4).

The thread environment (where global variables live) is always at pseudo-index LUA_GLOBALSINDEX. The environment of the running C function is always at pseudo-index LUA_ENVIRONINDEX.

To access and change the value of global variables, you can use regular table operations over an environment table. For instance, to access the value of a global variable, do

     lua_getfield(L, LUA_GLOBALSINDEX, varname);

3.4 - C Closures

When a C function is created, it is possible to associate some values with it, thus creating a C closure; these values are called upvalues and are accessible to the function whenever it is called (see lua_pushcclosure).

Whenever a C function is called, its upvalues are located at specific pseudo-indices. These pseudo-indices are produced by the macro lua_upvalueindex. The first value associated with a function is at position lua_upvalueindex(1), and so on. Any access to lua_upvalueindex(n), where n is greater than the number of upvalues of the current function, produces an acceptable (but invalid) index.

3.5 - Registry

Lua provides a registry, a pre-defined table that can be used by any C code to store whatever Lua value it needs to store. This table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table, but it should take care to choose keys different from those used by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name or a light userdata with the address of a C object in your code.

The integer keys in the registry are used by the reference mechanism, implemented by the auxiliary library, and therefore should not be used for other purposes.

3.6 - Error Handling in C

Internally, Lua uses the C longjmp facility to handle errors. (You can also choose to use exceptions if you use C++; see file luaconf.h.) When Lua faces any error (such as memory allocation errors, type errors, syntax errors, and runtime errors) it raises an error; that is, it does a long jump. A protected environment uses setjmp to set a recover point; any error jumps to the most recent active recover point.

Almost any function in the API may raise an error, for instance due to a memory allocation error. The following functions run in protected mode (that is, they create a protected environment to run), so they never raise an error: lua_newstate, lua_close, lua_load, lua_pcall, and lua_cpcall.

Inside a C function you can raise an error by calling lua_error.

3.7 - Functions and Types

Here we list all functions and types from the C API in alphabetical order.


lua_Alloc

typedef void * (*lua_Alloc) (void *ud,
                             void *ptr,
                             size_t osize,
                             size_t nsize);

The type of the memory-allocation function used by Lua states. The allocator function must provide a functionality similar to realloc, but not exactly the same. Its arguments are ud, an opaque pointer passed to lua_newstate; ptr, a pointer to the block being allocated/reallocated/freed; osize, the original size of the block; nsize, the new size of the block. ptr is NULL if and only if osize is zero. When nsize is zero, the allocator must return NULL; if osize is not zero, it should free the block pointed to by ptr. When nsize is not zero, the allocator returns NULL if and only if it cannot fill the request. When nsize is not zero and osize is zero, the allocator should behave like malloc. When nsize and osize are not zero, the allocator behaves like realloc. Lua assumes that the allocator never fails when osize >= nsize.

Here is a simple implementation for the allocator function. It is used in the auxiliary library by luaL_newstate.

     static void *l_alloc (void *ud, void *ptr, size_t osize,
                                                size_t nsize) {
       (void)ud;  (void)osize;  /* not used */
       if (nsize == 0) {
         free(ptr);
         return NULL;
       }
       else
         return realloc(ptr, nsize);
     }

This code assumes that free(NULL) has no effect and that realloc(NULL, size) is equivalent to malloc(size). ANSI C ensures both behaviors.


lua_atpanic

lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

Sets a new panic function and returns the old one.

If an error happens outside any protected environment, Lua calls a panic function and then calls exit(EXIT_FAILURE), thus exiting the host application. Your panic function may avoid this exit by never returning (e.g., doing a long jump).

The panic function can access the error message at the top of the stack.


lua_call

void lua_call (lua_State *L, int nargs, int nresults);

Calls a function.

To call a function you must use the following protocol: first, the function to be called is pushed onto the stack; then, the arguments to the function are pushed in direct order; that is, the first argument is pushed first. Finally you call lua_call; nargs is the number of arguments that you pushed onto the stack. All arguments and the function value are popped from the stack when the function is called. The function results are pushed onto the stack when the function returns. The number of results is adjusted to nresults, unless nresults is LUA_MULTRET. In this case, all results from the function are pushed. Lua takes care that the returned values fit into the stack space. The function results are pushed onto the stack in direct order (the first result is pushed first), so that after the call the last result is on the top of the stack.

Any error inside the called function is propagated upwards (with a longjmp).

The following example shows how the host program may do the equivalent to this Lua code:

     a = f("how", t.x, 14)

Here it is in C:

     lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* function to be called */
     lua_pushstring(L, "how");                        /* 1st argument */
     lua_getfield(L, LUA_GLOBALSINDEX, "t");   /* table to be indexed */
     lua_getfield(L, -1, "x");        /* push result of t.x (2nd arg) */
     lua_remove(L, -2);                  /* remove 't' from the stack */
     lua_pushinteger(L, 14);                          /* 3rd argument */
     lua_call(L, 3, 1);     /* call 'f' with 3 arguments and 1 result */
     lua_setfield(L, LUA_GLOBALSINDEX, "a");        /* set global 'a' */

Note that the code above is "balanced": at its end, the stack is back to its original configuration. This is considered good programming practice.


lua_CFunction

typedef int (*lua_CFunction) (lua_State *L);

Type for C functions.

In order to communicate properly with Lua, a C function must use the following protocol, which defines the way parameters and results are passed: a C function receives its arguments from Lua in its stack in direct order (the first argument is pushed first). So, when the function starts, lua_gettop(L) returns the number of arguments received by the function. The first argument (if any) is at index 1 and its last argument is at index lua_gettop(L). To return values to Lua, a C function just pushes them onto the stack, in direct order (the first result is pushed first), and returns the number of results. Any other value in the stack below the results will be properly discarded by Lua. Like a Lua function, a C function called by Lua can also return many results.

As an example, the following function receives a variable number of numerical arguments and returns their average and sum:

     static int foo (lua_State *L) {
       int n = lua_gettop(L);    /* number of arguments */
       lua_Number sum = 0;
       int i;
       for (i = 1; i <= n; i++) {
         if (!lua_isnumber(L, i)) {
           lua_pushstring(L, "incorrect argument");
           lua_error(L);
         }
         sum += lua_tonumber(L, i);
       }
       lua_pushnumber(L, sum/n);        /* first result */
       lua_pushnumber(L, sum);         /* second result */
       return 2;                   /* number of results */
     }

lua_checkstack

int lua_checkstack (lua_State *L, int extra);

Ensures that there are at least extra free stack slots in the stack. It returns false if it cannot grow the stack to that size. This function never shrinks the stack; if the stack is already larger than the new size, it is left unchanged.


lua_close

void lua_close (lua_State *L);

Destroys all objects in the given Lua state (calling the corresponding garbage-collection metamethods, if any) and frees all dynamic memory used by this state. On several platforms, you may not need to call this function, because all resources are naturally released when the host program ends. On the other hand, long-running programs, such as a daemon or a web server, might need to release states as soon as they are not needed, to avoid growing too large.


lua_concat

void lua_concat (lua_State *L, int n);

Concatenates the n values at the top of the stack, pops them, and leaves the result at the top. If n is 1, the result is the single string on the stack (that is, the function does nothing); if n is 0, the result is the empty string. Concatenation is done following the usual semantics of Lua (see §2.5.4).


lua_cpcall

int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);

Calls the C function func in protected mode. func starts with only one element in its stack, a light userdata containing ud. In case of errors, lua_cpcall returns the same error codes as lua_pcall, plus the error object on the top of the stack; otherwise, it returns zero, and does not change the stack. All values returned by func are discarded.


lua_createtable

void lua_createtable (lua_State *L, int narr, int nrec);

Creates a new empty table and pushes it onto the stack. The new table has space pre-allocated for narr array elements and nrec non-array elements. This pre-allocation is useful when you know exactly how many elements the table will have. Otherwise you can use the function lua_newtable.


lua_dump

int lua_dump (lua_State *L, lua_Writer writer, void *data);

Dumps a function as a binary chunk. Receives a Lua function on the top of the stack and produces a binary chunk that, if loaded again, results in a function equivalent to the one dumped. As it produces parts of the chunk, lua_dump calls function writer (see lua_Writer) with the given data to write them.

The value returned is the error code returned by the last call to the writer; 0 means no errors.

This function does not pop the Lua function from the stack.


lua_equal

int lua_equal (lua_State *L, int index1, int index2);

Returns 1 if the two values in acceptable indices index1 and index2 are equal, following the semantics of the Lua == operator (that is, may call metamethods). Otherwise returns 0. Also returns 0 if any of the indices is non valid.


lua_error

int lua_error (lua_State *L);

Generates a Lua error. The error message (which can actually be a Lua value of any type) must be on the stack top. This function does a long jump, and therefore never returns. (see luaL_error).


lua_gc

int lua_gc (lua_State *L, int what, int data);

Controls the garbage collector.

This function performs several tasks, according to the value of the parameter what:

  • LUA_GCSTOP: stops the garbage collector.
  • LUA_GCRESTART: restarts the garbage collector.
  • LUA_GCCOLLECT: performs a full garbage-collection cycle.
  • LUA_GCCOUNT: returns the current amount of memory (in Kbytes) in use by Lua.
  • LUA_GCCOUNTB: returns the remainder of dividing the current amount of bytes of memory in use by Lua by 1024.
  • LUA_GCSTEP: performs an incremental step of garbage collection. The step "size" is controlled by data (larger values mean more steps) in a non-specified way. If you want to control the step size you must experimentally tune the value of data. The function returns 1 if the step finished a garbage-collection cycle.
  • LUA_GCSETPAUSE: sets data/100 as the new value for the pause of the collector (see §2.10). The function returns the previous value of the pause.
  • LUA_GCSETSTEPMUL: sets data/100 as the new value for the step multiplier of the collector (see §2.10). The function returns the previous value of the step multiplier.

lua_getallocf

lua_Alloc lua_getallocf (lua_State *L, void **ud);

Returns the memory-allocation function of a given state. If ud is not NULL, Lua stores in *ud the opaque pointer passed to lua_newstate.


lua_getfenv

void lua_getfenv (lua_State *L, int index);

Pushes onto the stack the environment table of the value at the given index.


lua_getfield

void lua_getfield (lua_State *L, int index, const char *k);

Pushes onto the stack the value t[k], where t is the value at the given valid index index. As in Lua, this function may trigger a metamethod for the "index" event (see §2.8).


lua_getglobal

void lua_getglobal (lua_State *L, const char *name);

Pushes onto the stack the value of the global name. It is defined as a macro:

     #define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)

lua_getmetatable

int lua_getmetatable (lua_State *L, int index);

Pushes onto the stack the metatable of the value at the given acceptable index. If the index is not valid, or if the value does not have a metatable, the function returns 0 and pushes nothing on the stack.


lua_gettable

void lua_gettable (lua_State *L, int index);

Pushes onto the stack the value t[k], where t is the value at the given valid index index and k is the value at the top of the stack.

This function pops the key from the stack (putting the resulting value in its place). As in Lua, this function may trigger a metamethod for the "index" event (see §2.8).


lua_gettop

int lua_gettop (lua_State *L);

Returns the index of the top element in the stack. Because indices start at 1, this result is equal to the number of elements in the stack (and so 0 means an empty stack).


lua_insert

void lua_insert (lua_State *L, int index);

Moves the top element into the given valid index, shifting up the elements above this index to open space. Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position.


lua_Integer

typedef ptrdiff_t lua_Integer;

The type used by the Lua API to represent integral values.

By default it is a ptrdiff_t, which is usually the largest signed integral type the machine handles "comfortably".


lua_isboolean

int lua_isboolean (lua_State *L, int index);

Returns 1 if the value at the given acceptable index has type boolean, and 0 otherwise.


lua_iscfunction

int lua_iscfunction (lua_State *L, int index);

Returns 1 if the value at the given acceptable index is a C function, and 0 otherwise.


lua_isfunction

int lua_isfunction (lua_State *L, int index);

Returns 1 if the value at the given acceptable index is a function (either C or Lua), and 0 otherwise.


lua_islightuserdata

int lua_islightuserdata (lua_State *L, int index);

Returns 1 if the value at the given acceptable index is a light userdata, and 0 otherwise.


lua_isnil

int lua_isnil (lua_State *L, int index);

Returns 1 if the value at the given acceptable index is nil, and 0 otherwise.


lua_isnone

int lua_isnone (lua_State *L, int index);

Returns 1 if the the given acceptable index is not valid (that is, it refers to an element outside the current stack), and 0 otherwise.


lua_isnoneornil

int lua_isnoneornil (lua_State *L, int index);

Returns 1 if the the given acceptable index is not valid (that is, it refers to an element outside the current stack) or if the value at this index is nil, and 0 otherwise.


lua_isnumber

int lua_isnumber (lua_State *L, int index);

Returns 1 if the value at the given acceptable index is a number or a string convertible to a number, and 0 otherwise.


lua_isstring

int lua_isstring (lua_State *L, int index);

Returns 1 if the value at the given acceptable index is a string or a number (which is always convertible to a string), and 0 otherwise.


lua_istable

int lua_istable (lua_State *L, int index);

Returns 1 if the value at the given acceptable index is a table, and 0 otherwise.


lua_isthread

int lua_isthread (lua_State *L, int index);

Returns 1 if the value at the given acceptable index is a thread, and 0 otherwise.


lua_isuserdata

int lua_isuserdata (lua_State *L, int index);

Returns 1 if the value at the given acceptable index is a userdata (either full or light), and 0 otherwise.


lua_lessthan

int lua_lessthan (lua_State *L, int index1, int index2);

Returns 1 if the value at acceptable index index1 is smaller than the value at acceptable index index2, following the semantics of the Lua < operator (that is, may call metamethods). Otherwise returns 0. Also returns 0 if any of the indices is non valid.


lua_load

int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *chunkname);

Loads a Lua chunk. If there are no errors, lua_load pushes the compiled chunk as a Lua function on top of the stack. Otherwise, it pushes an error message. The return values of lua_load are:

This function only loads a chunk; it does not run it.

lua_load automatically detects whether the chunk is text or binary, and loads it accordingly (see program luac).

The lua_load function uses a user-supplied reader function to read the chunk (see lua_Reader). The data argument is an opaque value passed to the reader function.

The chunkname argument gives a name to the chunk, which is used for error messages and in debug information (see §3.8).


lua_newstate

lua_State *lua_newstate (lua_Alloc f, void *ud);

Creates a new, independent state. Returns NULL if cannot create the state (due to lack of memory). The argument f is the allocator function; Lua does all memory allocation for this state through this function. The second argument, ud, is an opaque pointer that Lua simply passes to the allocator in every call.


lua_newtable

void lua_newtable (lua_State *L);

Creates a new empty table and pushes it onto the stack. It is equivalent to lua_createtable(L, 0, 0).


lua_newthread

lua_State *lua_newthread (lua_State *L);

Creates a new thread, pushes it on the stack, and returns a pointer to a lua_State that represents this new thread. The new state returned by this function shares with the original state all global objects (such as tables), but has an independent execution stack.

There is no explicit function to close or to destroy a thread. Threads are subject to garbage collection, like any Lua object.


lua_newuserdata

void *lua_newuserdata (lua_State *L, size_t size);

This function allocates a new block of memory with the given size, pushes onto the stack a new full userdata with the block address, and returns this address.

Userdata represent C values in Lua. A full userdata represents a block of memory. It is an object (like a table): you must create it, it can have its own metatable, and you can detect when it is being collected. A full userdata is only equal to itself (under raw equality).

When Lua collects a full userdata with a gc metamethod, Lua calls the metamethod and marks the userdata as finalized. When this userdata is collected again then Lua frees its corresponding memory.


lua_next

int lua_next (lua_State *L, int index);

Pops a key from the stack, and pushes a key-value pair from the table at the given index (the "next" pair after the given key). If there are no more elements in the table, then lua_next returns 0 (and pushes nothing).

A typical traversal looks like this:

     /* table is in the stack at index 't' */
     lua_pushnil(L);  /* first key */
     while (lua_next(L, t) != 0) {
       /* uses 'key' (at index -2) and 'value' (at index -1) */
       printf("%s - %s\n",
              lua_typename(L, lua_type(L, -2)),
              lua_typename(L, lua_type(L, -1)));
       /* removes 'value'; keeps 'key' for next iteration */
       lua_pop(L, 1);
     }

While traversing a table, do not call lua_tolstring directly on a key, unless you know that the key is actually a string. Recall that lua_tolstring changes the value at the given index; this confuses the next call to lua_next.


lua_Number

typedef double lua_Number;

The type of numbers in Lua. By default, it is double, but that can be changed in luaconf.h.

Through the configuration file you can change Lua to operate with another type for numbers (e.g., float or long).


lua_objlen

size_t lua_objlen (lua_State *L, int index);

Returns the "length" of the value at the given acceptable index: for strings, this is the string length; for tables, this is the result of the length operator ('#'); for userdata, this is the size of the block of memory allocated for the userdata; for other values, it is 0.


lua_pcall

int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);

Calls a function in protected mode.

Both nargs and nresults have the same meaning as in lua_call. If there are no errors during the call, lua_pcall behaves exactly like lua_call. However, if there is any error, lua_pcall catches it, pushes a single value on the stack (the error message), and returns an error code. Like lua_call, lua_pcall always removes the function and its arguments from the stack.

If errfunc is 0, then the error message returned on the stack is exactly the original error message. Otherwise, errfunc is the stack index of an error handler function. (In the current implementation, this index cannot be a pseudo-index.) In case of runtime errors, this function will be called with the error message and its return value will be the message returned on the stack by lua_pcall.

Typically, the error handler function is used to add more debug information to the error message, such as a stack traceback. Such information cannot be gathered after the return of lua_pcall, since by then the stack has unwound.

The lua_pcall function returns 0 in case of success or one of the following error codes (defined in lua.h):

  • LUA_ERRRUN: a runtime error.
  • LUA_ERRMEM: memory allocation error. For such errors, Lua does not call the error handler function.
  • LUA_ERRERR: error while running the error handler function.

lua_pop

void lua_pop (lua_State *L, int n);

Pops n elements from the stack.


lua_pushboolean

void lua_pushboolean (lua_State *L, int b);

Pushes a boolean value with value b onto the stack.


lua_pushcclosure

void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

Pushes a new C closure onto the stack.

When a C function is created, it is possible to associate some values with it, thus creating a C closure (see §3.4); these values are then accessible to the function whenever it is called. To associate values with a C function, first these values should be pushed onto the stack (when there are multiple values, the first value is pushed first). Then lua_pushcclosure is called to create and push the C function onto the stack, with the argument n telling how many values should be associated with the function. lua_pushcclosure also pops these values from the stack.


lua_pushcfunction

void lua_pushcfunction (lua_State *L, lua_CFunction f);

Pushes a C function onto the stack. This function receives a pointer to a C function and pushes onto the stack a Lua value of type function that, when called, invokes the corresponding C function.

Any function to be registered in Lua must follow the correct protocol to receive its parameters and return its results (see lua_CFunction).

lua_pushcfunction is defined as a macro:

     #define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)

lua_pushfstring

const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

Pushes onto the stack a formatted string and returns a pointer to this string. It is similar to the C function sprintf, but has some important differences:

  • You do not have to allocate space for the result: the result is a Lua string and Lua takes care of memory allocation (and deallocation, through garbage collection).
  • The conversion specifiers are quite restricted. There are no flags, widths, or precisions. The conversion specifiers can only be '%%' (inserts a '%' in the string), '%s' (inserts a zero-terminated string, with no size restrictions), '%f' (inserts a lua_Number), '%p' (inserts a pointer as a hexadecimal numeral), '%d' (inserts an int), and '%c' (inserts an int as a character).

lua_pushinteger

void lua_pushinteger (lua_State *L, lua_Integer n);

Pushes a number with value n onto the stack.


lua_pushlightuserdata

void lua_pushlightuserdata (lua_State *L, void *p);

Pushes a light userdata onto the stack.

Userdata represent C values in Lua. A light userdata represents a pointer. It is a value (like a number): you do not create it, it has no individual metatable, and it is not collected (as it was never created). A light userdata is equal to "any" light userdata with the same C address.


lua_pushlstring

void lua_pushlstring (lua_State *L, const char *s, size_t len);

Pushes the string pointed to by s with size len onto the stack. Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. The string can contain embedded zeros.


lua_pushnil

void lua_pushnil (lua_State *L);

Pushes a nil value onto the stack.


lua_pushnumber

void lua_pushnumber (lua_State *L, lua_Number n);

Pushes a number with value n onto the stack.


lua_pushstring

void lua_pushstring (lua_State *L, const char *s);

Pushes the zero-terminated string pointed to by s onto the stack. Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. The string cannot contain embedded zeros; it is assumed to end at the first zero.


lua_pushthread

int lua_pushthread (lua_State *L);

Pushes the thread represented by L onto the stack. Returns 1 if this thread is the main thread of its state.


lua_pushvalue

void lua_pushvalue (lua_State *L, int index);

Pushes a copy of the element at the given valid index onto the stack.


lua_pushvfstring

const char *lua_pushvfstring (lua_State *L,
                              const char *fmt,
                              va_list argp);

Equivalent to lua_pushfstring, except that it receives a va_list instead of a variable number of arguments.


lua_rawequal

int lua_rawequal (lua_State *L, int index1, int index2);

Returns 1 if the two values in acceptable indices index1 and index2 are primitively equal (that is, without calling metamethods). Otherwise returns 0. Also returns 0 if any of the indices are non valid.


lua_rawget

void lua_rawget (lua_State *L, int index);

Similar to lua_gettable, but does a raw access (i.e., without metamethods).


lua_rawgeti

void lua_rawgeti (lua_State *L, int index, int n);

Pushes onto the stack the value t[n], where t is the value at the given valid index index. The access is raw; that is, it does not invoke metamethods.


lua_rawset

void lua_rawset (lua_State *L, int index);

Similar to lua_settable, but does a raw assignment (i.e., without metamethods).


lua_rawseti

void lua_rawseti (lua_State *L, int index, int n);

Does the equivalent of t[n] = v, where t is the value at the given valid index index and v is the value at the top of the stack,

This function pops the value from the stack. The assignment is raw; that is, it does not invoke metamethods.


lua_Reader

typedef const char * (*lua_Reader) (lua_State *L,
                                    void *data,
                                    size_t *size);

The reader function used by lua_load. Every time it needs another piece of the chunk, lua_load calls the reader, passing along its data parameter. The reader must return a pointer to a block of memory with a new piece of the chunk and set size to the block size. The block must exist until the reader function is called again. To signal the end of the chunk, the reader must return NULL. The reader function may return pieces of any size greater than zero.


lua_register

void lua_register (lua_State *L,
                   const char *name,
                   lua_CFunction f);

Sets the C function f as the new value of global name. It is defined as a macro:

     #define lua_register(L,n,f) \
            (lua_pushcfunction(L, f), lua_setglobal(L, n))

lua_remove

void lua_remove (lua_State *L, int index);

Removes the element at the given valid index, shifting down the elements above this index to fill the gap. Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position.


lua_replace

void lua_replace (lua_State *L, int index);

Moves the top element into the given position (and pops it), without shifting any element (therefore replacing the value at the given position).


lua_resume

int lua_resume (lua_State *L, int narg);

Starts and resumes a coroutine in a given thread.

To start a coroutine, you first create a new thread (see lua_newthread); then you push onto its stack the main function plus any arguments; then you call lua_resume, with narg being the number of arguments. This call returns when the coroutine suspends or finishes its execution. When it returns, the stack contains all values passed to lua_yield, or all values returned by the body function. lua_resume returns LUA_YIELD if the coroutine yields, 0 if the coroutine finishes its execution without errors, or an error code in case of errors (see lua_pcall). In case of errors, the stack is not unwound, so you can use the debug API over it. The error message is on the top of the stack. To restart a coroutine, you put on its stack only the values to be passed as results from yield, and then call lua_resume.


lua_setallocf

void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);

Changes the allocator function of a given state to f with user data ud.


lua_setfenv

int lua_setfenv (lua_State *L, int index);

Pops a table from the stack and sets it as the new environment for the value at the given index. If the value at the given index is neither a function nor a thread nor a userdata, lua_setfenv returns 0. Otherwise it returns 1.


lua_setfield

void lua_setfield (lua_State *L, int index, const char *k);

Does the equivalent to t[k] = v, where t is the value at the given valid index index and v is the value at the top of the stack,

This function pops the value from the stack. As in Lua, this function may trigger a metamethod for the "newindex" event (see §2.8).


lua_setglobal

void lua_setglobal (lua_State *L, const char *name);

Pops a value from the stack and sets it as the new value of global name. It is defined as a macro:

     #define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)

lua_setmetatable

int lua_setmetatable (lua_State *L, int index);

Pops a table from the stack and sets it as the new metatable for the value at the given acceptable index.


lua_settable

void lua_settable (lua_State *L, int index);

Does the equivalent to t[k] = v, where t is the value at the given valid index index, v is the value at the top of the stack, and k is the value just below the top.

This function pops both the key and the value from the stack. As in Lua, this function may trigger a metamethod for the "newindex" event (see §2.8).


lua_settop

void lua_settop (lua_State *L, int index);

Accepts any acceptable index, or 0, and sets the stack top to this index. If the new top is larger than the old one, then the new elements are filled with nil. If index is 0, then all stack elements are removed.


lua_State

typedef struct lua_State lua_State;

Opaque structure that keeps the whole state of a Lua interpreter. The Lua library is fully reentrant: it has no global variables. All information about a state is kept in this structure.

A pointer to this state must be passed as the first argument to every function in the library, except to lua_newstate, which creates a Lua state from scratch.


lua_status

int lua_status (lua_State *L);

Returns the status of the thread L.

The status can be 0 for a normal thread, an error code if the thread finished its execution with an error, or LUA_YIELD if the thread is suspended.


lua_toboolean

int lua_toboolean (lua_State *L, int index);

Converts the Lua value at the given acceptable index to a C boolean value (0 or 1). Like all tests in Lua, lua_toboolean returns 1 for any Lua value different from false and nil; otherwise it returns 0. It also returns 0 when called with a non-valid index. (If you want to accept only actual boolean values, use lua_isboolean to test the value's type.)


lua_tocfunction

lua_CFunction lua_tocfunction (lua_State *L, int index);

Converts a value at the given acceptable index to a C function. That value must be a C function; otherwise, returns NULL.


lua_tointeger

lua_Integer lua_tointeger (lua_State *L, int idx);

Converts the Lua value at the given acceptable index to the signed integral type lua_Integer. The Lua value must be a number or a string convertible to a number (see §2.2.1); otherwise, lua_tointeger returns 0.

If the number is not an integer, it is truncated in some non-specified way.


lua_tolstring

const char *lua_tolstring (lua_State *L, int index, size_t *len);

Converts the Lua value at the given acceptable index to a C string. If len is not NULL, it also sets *len with the string length. The Lua value must be a string or a number; otherwise, the function returns NULL. If the value is a number, then lua_tolstring also changes the actual value in the stack to a string. (This change confuses lua_next when lua_tolstring is applied to keys during a table traversal.)

lua_tolstring returns a fully aligned pointer to a string inside the Lua state. This string always has a zero ('\0') after its last character (as in C), but may contain other zeros in its body. Because Lua has garbage collection, there is no guarantee that the pointer returned by lua_tolstring will be valid after the corresponding value is removed from the stack.


lua_tonumber

lua_Number lua_tonumber (lua_State *L, int index);

Converts the Lua value at the given acceptable index to the C type lua_Number (see lua_Number). The Lua value must be a number or a string convertible to a number (see §2.2.1); otherwise, lua_tonumber returns 0.


lua_topointer

const void *lua_topointer (lua_State *L, int index);

Converts the value at the given acceptable index to a generic C pointer (void*). The value may be a userdata, a table, a thread, or a function; otherwise, lua_topointer returns NULL. Different objects will give different pointers. There is no way to convert the pointer back to its original value.

Typically this function is used only for debug information.


lua_tostring

const char *lua_tostring (lua_State *L, int index);

Equivalent to lua_tolstring with len equal to NULL.


lua_tothread

lua_State *lua_tothread (lua_State *L, int index);

Converts the value at the given acceptable index to a Lua thread (represented as lua_State*). This value must be a thread; otherwise, the function returns NULL.


lua_touserdata

void *lua_touserdata (lua_State *L, int index);

If the value at the given acceptable index is a full userdata, returns its block address. If the value is a light userdata, returns its pointer. Otherwise, returns NULL.


lua_type

int lua_type (lua_State *L, int index);

Returns the type of the value in the given acceptable index, or LUA_TNONE for a non-valid index (that is, an index to an "empty" stack position). The types returned by lua_type are coded by the following constants defined in lua.h: LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, and LUA_TLIGHTUSERDATA.


lua_typename

const char *lua_typename  (lua_State *L, int tp);

Returns the name of the type encoded by the value tp, which must be one the values returned by lua_type.


lua_Writer

typedef int (*lua_Writer) (lua_State *L,
                           const void* p,
                           size_t sz,
                           void* ud);

The writer function used by lua_dump. Every time it produces another piece of chunk, lua_dump calls the writer, passing along the buffer to be written (p), its size (sz), and the data parameter supplied to lua_dump.

The writer returns an error code: 0 means no errors; any other value means an error and stops lua_dump from calling the writer again.


lua_xmove

void lua_xmove (lua_State *from, lua_State *to, int n);

Exchange values between different threads of the same global state.

This function pops n values from the stack from, and pushes them onto the stack to.


lua_yield

int lua_yield  (lua_State *L, int nresults);

Yields a coroutine.

This function should only be called as the return expression of a C function, as follows:

     return lua_yield (L, nresults);

When a C function calls lua_yield in that way, the running coroutine suspends its execution, and the call to lua_resume that started this coroutine returns. The parameter nresults is the number of values from the stack that are passed as results to lua_resume.

3.8 - The Debug Interface

Lua has no built-in debugging facilities. Instead, it offers a special interface by means of functions and hooks. This interface allows the construction of different kinds of debuggers, profilers, and other tools that need "inside information" from the interpreter.


lua_Debug

typedef struct lua_Debug {
  int event;
  const char *name;           /* (n) */
  const char *namewhat;       /* (n) */
  const char *what;           /* (S) */
  const char *source;         /* (S) */
  int currentline;            /* (l) */
  int nups;                   /* (u) number of upvalues */
  int linedefined;            /* (S) */
  int lastlinedefined;        /* (S) */
  char short_src[LUA_IDSIZE]; /* (S) */
  /* private part */
  other fields
} lua_Debug;

A structure used to carry different pieces of information about an active function. lua_getstack fills only the private part of this structure, for later use. To fill the other fields of lua_Debug with useful information, call lua_getinfo.

The fields of lua_Debug have the following meaning:

  • source: If the function was defined in a string, then source is that string. If the function was defined in a file, then source starts with a '@' followed by the file name.
  • short_src: a "printable" version of source, to be used in error messages.
  • linedefined: the line number where the definition of the function starts.
  • lastlinedefined: the line number where the definition of the function ends.
  • what: the string "Lua" if the function is a Lua function, "C" if it is a C function, "main" if it is the main part of a chunk, and "tail" if it was a function that did a tail call. In the latter case, Lua has no other information about the function.
  • currentline: the current line where the given function is executing. When no line information is available, currentline is set to -1.
  • name: a reasonable name for the given function. Because functions in Lua are first-class values, they do not have a fixed name: some functions may be the value of multiple global variables, while others may be stored only in a table field. The lua_getinfo function checks how the function was called to find a suitable name. If it cannot find a name, then name is set to NULL.
  • namewhat: explains the name field. The value of namewhat can be "global", "local", "method", "field", "upvalue", or "" (the empty string), according to how the function was called. (Lua uses the empty string when no other option seems to apply.)
  • nups: the number of upvalues of the function.

lua_gethook

lua_Hook lua_gethook (lua_State *L);

Returns the current hook function.


lua_gethookcount

int lua_gethookcount (lua_State *L);

Returns the current hook count.


lua_gethookmask

int lua_gethookmask (lua_State *L);

Returns the current hook mask.


lua_getinfo

int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

Returns information about a specific function or function invocation.

To get information about a function invocation, the parameter ar must be a valid activation record that was filled by a previous call to lua_getstack or given as argument to a hook (see lua_Hook).

To get information about a function you push it onto the stack and start the what string with the character '>'. (In that case, lua_getinfo pops the function in the top of the stack.) For instance, to know in which line a function f was defined, you can write the following code:

     lua_Debug ar;
     lua_getfield(L, LUA_GLOBALSINDEX, "f");  /* get global 'f' */
     lua_getinfo(L, ">S", &ar);
     printf("%d\n", ar.linedefined);

Each character in the string what selects some fields of the structure ar to be filled or a value to be pushed on the stack:

  • 'n': fills in the field name and namewhat;
  • 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
  • 'l': fills in the field currentline;
  • 'u': fills in the field nups;
  • 'f': pushes onto the stack the function that is running at the given level;
  • 'L': pushes onto the stack a table whose indices are the numbers of the lines that are valid on the function. (A valid line is a line with some associated code, that is, a line where you can put a break point. Non-valid lines include empty lines and comments.)

This function returns 0 on error (for instance, an invalid option in what).


lua_getlocal

const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);

Gets information about a local variable of a given activation record. The parameter ar must be a valid activation record that was filled by a previous call to lua_getstack or given as argument to a hook (see lua_Hook). The index n selects which local variable to inspect (1 is the first parameter or active local variable, and so on, until the last active local variable). lua_getlocal pushes the variable's value onto the stack and returns its name.

Variable names starting with '(' (open parentheses) represent internal variables (loop control variables, temporaries, and C function locals).

Returns NULL (and pushes nothing) when the index is greater than the number of active local variables.


lua_getstack

int lua_getstack (lua_State *L, int level, lua_Debug *ar);

Get information about the interpreter runtime stack.

This function fills parts of a lua_Debug structure with an identification of the activation record of the function executing at a given level. Level 0 is the current running function, whereas level n+1 is the function that has called level n. When there are no errors, lua_getstack returns 1; when called with a level greater than the stack depth, it returns 0.


lua_getupvalue

const char *lua_getupvalue (lua_State *L, int funcindex, int n);

Gets information about a closure's upvalue. (For Lua functions, upvalues are the external local variables that the function uses, and that are consequently included in its closure.) lua_getupvalue gets the index n of an upvalue, pushes the upvalue's value onto the stack, and returns its name. funcindex points to the closure in the stack. (Upvalues have no particular order, as they are active through the whole function. So, they are numbered in an arbitrary order.)

Returns NULL (and pushes nothing) when the index is greater than the number of upvalues. For C functions, this function uses the empty string "" as a name for all upvalues.


lua_Hook

typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);

Type for debugging hook functions.

Whenever a hook is called, its ar argument has its field event set to the specific event that triggered the hook. Lua identifies these events with the following constants: LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILRET, LUA_HOOKLINE, and LUA_HOOKCOUNT. Moreover, for line events, the field currentline is also set. To get the value of any other field in ar, the hook must call lua_getinfo. For return events, event may be LUA_HOOKRET, the normal value, or LUA_HOOKTAILRET. In the latter case, Lua is simulating a return from a function that did a tail call; in this case, it is useless to call lua_getinfo.

While Lua is running a hook, it disables other calls to hooks. Therefore, if a hook calls back Lua to execute a function or a chunk, this execution occurs without any calls to hooks.


lua_sethook

int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);

Sets the debugging hook function.

Argument f is the hook function. mask specifies on which events the hook will be called: it is formed by a bitwise or of the constants LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, and LUA_MASKCOUNT. The count argument is only meaningful when the mask includes LUA_MASKCOUNT. For each event, the hook is called as explained below:

  • The call hook: is called when the interpreter calls a function. The hook is called just after Lua enters the new function, before the function gets its arguments.
  • The return hook: is called when the interpreter returns from a function. The hook is called just before Lua leaves the function. You have no access to the values to be returned by the function.
  • The line hook: is called when the interpreter is about to start the execution of a new line of code, or when it jumps back in the code (even to the same line). (This event only happens while Lua is executing a Lua function.)
  • The count hook: is called after the interpreter executes every count instructions. (This event only happens while Lua is executing a Lua function.)

A hook is disabled by setting mask to zero.


lua_setlocal

const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);

Sets the value of a local variable of a given activation record. Parameters ar and n are as in lua_getlocal (see lua_getlocal). lua_setlocal assigns the value at the top of the stack to the variable and returns its name. It also pops the value from the stack.

Returns NULL (and pops nothing) when the index is greater than the number of active local variables.


lua_setupvalue

const char *lua_setupvalue (lua_State *L, int funcindex, int n);

Sets the value of a closure's upvalue. It assigns the value at the top of the stack to the upvalue and returns its name. It also pops the value from the stack. Parameters funcindex and n are as in the lua_getupvalue (see lua_getupvalue).

Returns NULL (and pops nothing) when the index is greater than the number of upvalues.

4 - The Auxiliary Library

The auxiliary library provides several convenient functions to interface C with Lua. While the basic API provides the primitive functions for all interactions between C and Lua, the auxiliary library provides higher-level functions for some common tasks.

All functions from the auxiliary library are defined in header file lauxlib.h and have a prefix luaL_.

All functions in the auxiliary library are built on top of the basic API, and so they provide nothing that cannot be done with this API.

Several functions in the auxiliary library are used to check C function arguments. Their names are always luaL_check* or luaL_opt*. All of these functions raise an error if the check is not satisfied. Because the error message is formatted for arguments (e.g., "bad argument #1"), you should not use these functions for other stack values.

4.1 - Functions and Types

Here we list all functions and types from the auxiliary library in alphabetical order.


luaL_addchar

void luaL_addchar (luaL_Buffer *B, char c);

Adds the character c to the buffer B (see luaL_Buffer).


luaL_addlstring

void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);

Adds the string pointed to by s with length l to the buffer B (see luaL_Buffer). The string may contain embedded zeros.


luaL_addsize

void luaL_addsize (luaL_Buffer *B, size_t n);

Adds to the buffer B (see luaL_Buffer) a string of length n previously copied to the buffer area (see luaL_prepbuffer).


luaL_addstring

void luaL_addstring (luaL_Buffer *B, const char *s);

Adds the zero-terminated string pointed to by s to the buffer B (see luaL_Buffer). The string may not contain embedded zeros.


luaL_addvalue

void luaL_addvalue (luaL_Buffer *B);

Adds the value at the top of the stack to the buffer B (see luaL_Buffer). Pops the value.

This is the only function on string buffers that can (and must) be called with an extra element on the stack, which is the value to be added to the buffer.


luaL_argcheck

void luaL_argcheck (lua_State *L,
                    int cond,
                    int narg,
                    const char *extramsg);

Checks whether cond is true. If not, raises an error with the following message, where func is retrieved from the call stack:

     bad argument #<narg> to <func> (<extramsg>)

luaL_argerror

int luaL_argerror (lua_State *L, int narg, const char *extramsg);

Raises an error with the following message, where func is retrieved from the call stack:

     bad argument #<narg> to <func> (<extramsg>)

This function never returns, but it is an idiom to use it in C functions as return luaL_argerror(args).


luaL_Buffer

typedef struct luaL_Buffer luaL_Buffer;

Type for a string buffer.

A string buffer allows C code to build Lua strings piecemeal. Its pattern of use is as follows:

  • First you declare a variable b of type luaL_Buffer.
  • Then you initialize it with a call luaL_buffinit(L, &b).
  • Then you add string pieces to the buffer calling any of the luaL_add* functions.
  • You finish by calling luaL_pushresult(&b). This call leaves the final string on the top of the stack.

During its normal operation, a string buffer uses a variable number of stack slots. So, while using a buffer, you cannot assume that you know where the top of the stack is. You can use the stack between successive calls to buffer operations as long as that use is balanced; that is, when you call a buffer operation, the stack is at the same level it was immediately after the previous buffer operation. (The only exception to this rule is luaL_addvalue.) After calling luaL_pushresult the stack is back to its level when the buffer was initialized, plus the final string on its top.


luaL_buffinit

void luaL_buffinit (lua_State *L, luaL_Buffer *B);

Initializes a buffer B. This function does not allocate any space; the buffer must be declared as a variable (see luaL_Buffer).


luaL_callmeta

int luaL_callmeta (lua_State *L, int obj, const char *e);

Calls a metamethod.

If the object at index obj has a metatable and this metatable has a field e, this function calls this field and passes the object as its only argument. In this case this function returns 1 and pushes onto the stack the value returned by the call. If there is no metatable or no metamethod, this function returns 0 (without pushing any value on the stack).


luaL_checkany

void luaL_checkany (lua_State *L, int narg);

Checks whether the function has an argument of any type (including nil) at position narg.


luaL_checkint

int luaL_checkint (lua_State *L, int narg);

Checks whether the function argument narg is a number and returns this number cast to an int.


luaL_checkinteger

lua_Integer luaL_checkinteger (lua_State *L, int narg);

Checks whether the function argument narg is a number and returns this number cast to a lua_Integer.


luaL_checklong

long luaL_checklong (lua_State *L, int narg);

Checks whether the function argument narg is a number and returns this number cast to a long.


luaL_checklstring

const char *luaL_checklstring (lua_State *L, int narg, size_t *l);

Checks whether the function argument narg is a string and returns this string; if l is not NULL fills *l with the string's length.


luaL_checknumber

lua_Number luaL_checknumber (lua_State *L, int narg);

Checks whether the function argument narg is a number and returns this number.


luaL_checkoption

int luaL_checkoption (lua_State *L,
                      int narg,
                      const char *def,
                      const char *const lst[]);

Checks whether the function argument narg is a string and searches for this string in the array lst (which must be NULL-terminated). Returns the index in the array where the string was found. Raises an error if the argument is not a string or if the string cannot be found.

If def is not NULL, the function uses def as a default value when there is no argument narg or if this argument is nil.

This is a useful function for mapping strings to C enums. (The usual convention in Lua libraries is to use strings instead of numbers to select options.)


luaL_checkstack

void luaL_checkstack (lua_State *L, int sz, const char *msg);

Grows the stack size to top + sz elements, raising an error if the stack cannot grow to that size. msg is an additional text to go into the error message.


luaL_checkstring

const char *luaL_checkstring (lua_State *L, int narg);

Checks whether the function argument narg is a string and returns this string.


luaL_checktype

void luaL_checktype (lua_State *L, int narg, int t);

Checks whether the function argument narg has type t.


luaL_checkudata

void *luaL_checkudata (lua_State *L, int narg, const char *tname);

Checks whether the function argument narg is a userdata of the type tname (see luaL_newmetatable).


luaL_dofile

int luaL_dofile (lua_State *L, const char *filename);

Loads and runs the given file. It is defined as the following macro:

     (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))

It returns 0 if there are no errors or 1 in case of errors.


luaL_dostring

int luaL_dostring (lua_State *L, const char *str);

Loads and runs the given string. It is defined as the following macro:

     (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))

It returns 0 if there are no errors or 1 in case of errors.


luaL_error

int luaL_error (lua_State *L, const char *fmt, ...);

Raises an error. The error message format is given by fmt plus any extra arguments, following the same rules of lua_pushfstring. It also adds at the beginning of the message the file name and the line number where the error occurred, if this information is available.

This function never returns, but it is an idiom to use it in C functions as return luaL_error(args).


luaL_getmetafield

int luaL_getmetafield (lua_State *L, int obj, const char *e);

Pushes onto the stack the field e from the metatable of the object at index obj. If the object does not have a metatable, or if the metatable does not have this field, returns 0 and pushes nothing.


luaL_getmetatable

void luaL_getmetatable (lua_State *L, const char *tname);

Pushes onto the stack the metatable associated with name tname in the registry (see luaL_newmetatable).


luaL_gsub

const char *luaL_gsub (lua_State *L,
                       const char *s,
                       const char *p,
                       const char *r);

Creates a copy of string s by replacing any occurrence of the string p with the string r. Pushes the resulting string on the stack and returns it.


luaL_loadbuffer

int luaL_loadbuffer (lua_State *L,
                     const char *buff,
                     size_t sz,
                     const char *name);

Loads a buffer as a Lua chunk. This function uses lua_load to load the chunk in the buffer pointed to by buff with size sz.

This function returns the same results as lua_load. name is the chunk name, used for debug information and error messages.


luaL_loadfile

int luaL_loadfile (lua_State *L, const char *filename);

Loads a file as a Lua chunk. This function uses lua_load to load the chunk in the file named filename. If filename is NULL, then it loads from the standard input. The first line in the file is ignored if it starts with a #.

This function returns the same results as lua_load, but it has an extra error code LUA_ERRFILE if it cannot open/read the file.

As lua_load, this function only loads the chunk; it does not run it.


luaL_loadstring

int luaL_loadstring (lua_State *L, const char *s);

Loads a string as a Lua chunk. This function uses lua_load to load the chunk in the zero-terminated string s.

This function returns the same results as lua_load.

Also as lua_load, this function only loads the chunk; it does not run it.


luaL_newmetatable

int luaL_newmetatable (lua_State *L, const char *tname);

If the registry already has the key tname, returns 0. Otherwise, creates a new table to be used as a metatable for userdata, adds it to the registry with key tname, and returns 1.

In both cases pushes onto the stack the final value associated with tname in the registry.


luaL_newstate

lua_State *luaL_newstate (void);

Creates a new Lua state. It calls lua_newstate with an allocator based on the standard C realloc function and then sets a panic function (see lua_atpanic) that prints an error message to the standard error output in case of fatal errors.

Returns the new state, or NULL if there is a memory allocation error.


luaL_openlibs

void luaL_openlibs (lua_State *L);

Opens all standard Lua libraries into the given state.


luaL_optint

int luaL_optint (lua_State *L, int narg, int d);

If the function argument narg is a number, returns this number cast to an int. If this argument is absent or is nil, returns d. Otherwise, raises an error.


luaL_optinteger

lua_Integer luaL_optinteger (lua_State *L,
                             int narg,
                             lua_Integer d);

If the function argument narg is a number, returns this number cast to a lua_Integer. If this argument is absent or is nil, returns d. Otherwise, raises an error.


luaL_optlong

long luaL_optlong (lua_State *L, int narg, long d);

If the function argument narg is a number, returns this number cast to a long. If this argument is absent or is nil, returns d. Otherwise, raises an error.


luaL_optlstring

const char *luaL_optlstring (lua_State *L,
                             int narg,
                             const char *d,
                             size_t *l);

If the function argument narg is a string, returns this string. If this argument is absent or is nil, returns d. Otherwise, raises an error.

If l is not NULL, fills the position *l with the results's length.


luaL_optnumber

lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number d);

If the function argument narg is a number, returns this number. If this argument is absent or is nil, returns d. Otherwise, raises an error.


luaL_optstring

const char *luaL_optstring (lua_State *L,
                            int narg,
                            const char *d);

If the function argument narg is a string, returns this string. If this argument is absent or is nil, returns d. Otherwise, raises an error.


luaL_prepbuffer

char *luaL_prepbuffer (luaL_Buffer *B);

Returns an address to a space of size LUAL_BUFFERSIZE where you can copy a string to be added to buffer B (see luaL_Buffer). After copying the string into this space you must call luaL_addsize with the size of the string to actually add it to the buffer.


luaL_pushresult

void luaL_pushresult (luaL_Buffer *B);

Finishes the use of buffer B leaving the final string on the top of the stack.


luaL_ref

int luaL_ref (lua_State *L, int t);

Creates and returns a reference, in the table at index t, for the object at the top of the stack (and pops the object).

A reference is a unique integer key. As long as you do not manually add integer keys into table t, luaL_ref ensures the uniqueness of the key it returns. You can retrieve an object referred by reference r by calling lua_rawgeti(L, t, r). Function luaL_unref frees a reference and its associated object.

If the object at the top of the stack is nil, luaL_ref returns the constant LUA_REFNIL. The constant LUA_NOREF is guaranteed to be different from any reference returned by luaL_ref.


luaL_Reg

typedef struct luaL_Reg {
  const char *name;
  lua_CFunction func;
} luaL_Reg;

Type for arrays of functions to be registered by luaL_register. name is the function name and func is a pointer to the function. Any array of luaL_Reg must end with an sentinel entry in which both name and func are NULL.


luaL_register

void luaL_register (lua_State *L,
                    const char *libname,
                    const luaL_Reg *l);

Opens a library.

When called with libname equal to NULL, it simply registers all functions in the list l (see luaL_Reg) into the table on the top of the stack.

When called with a non-null libname, luaL_register creates a new table t, sets it as the value of the global variable libname, sets it as the value of package.loaded[libname], and registers on it all functions in the list l. If there is a table in package.loaded[libname] or in variable libname, reuses this table instead of creating a new one.

In any case the function leaves the table on the top of the stack.


luaL_typename

const char *luaL_typename (lua_State *L, int idx);

Returns the name of the type of the value at index idx.


luaL_typerror

int luaL_typerror (lua_State *L, int narg, const char *tname);

Generates an error with a message like the following:

     location: bad argument narg to 'func' (tname expected, got rt)

where location is produced by luaL_where, func is the name of the current function, and rt is the type name of the actual argument.


luaL_unref

void luaL_unref (lua_State *L, int t, int ref);

Releases reference ref from the table at index t (see luaL_ref). The entry is removed from the table, so that the referred object can be collected. The reference ref is also freed to be used again.

If ref is LUA_NOREF or LUA_REFNIL, luaL_unref does nothing.


luaL_where

void luaL_where (lua_State *L, int lvl);

Pushes onto the stack a string identifying the current position of the control at level lvl in the call stack. Typically this string has the following format:

     chunkname:currentline:

Level 0 is the running function, level 1 is the function that called the running function, etc.

This function is used to build a prefix for error messages.

5 - Standard Libraries

The standard Lua libraries provide useful functions that are implemented directly through the C API. Some of these functions provide essential services to the language (e.g., type and getmetatable); others provide access to "outside" services (e.g., I/O); and others could be implemented in Lua itself, but are quite useful or have critical performance requirements that deserve an implementation in C (e.g., sort).

All libraries are implemented through the official C API and are provided as separate C modules. Currently, Lua has the following standard libraries:

  • basic library;
  • package library;
  • string manipulation;
  • table manipulation;
  • mathematical functions (sin, log, etc.);
  • input and output;
  • operating system facilities;
  • debug facilities.

Except for the basic and package libraries, each library provides all its functions as fields of a global table or as methods of its objects.

To have access to these libraries, the C host program should call the luaL_openlibs function, which opens all standard libraries. Alternatively, it can open them individually by calling luaopen_base (for the basic library), luaopen_package (for the package library), luaopen_string (for the string library), luaopen_table (for the table library), luaopen_math (for the mathematical library), luaopen_io (for the I/O and the Operating System libraries), and luaopen_debug (for the debug library). These functions are declared in lualib.h and should not be called directly: you must call them like any other Lua C function, e.g., by using lua_call.

5.1 - Basic Functions

The basic library provides some core functions to Lua. If you do not include this library in your application, you should check carefully whether you need to provide implementations for some of its facilities.


assert (v [, message])

Issues an error when the value of its argument v is false (i.e., nil or false); otherwise, returns all its arguments. message is an error message; when absent, it defaults to "assertion failed!"


collectgarbage (opt [, arg])

This function is a generic interface to the garbage collector. It performs different functions according to its first argument, opt:

  • "stop": stops the garbage collector.
  • "restart": restarts the garbage collector.
  • "collect": performs a full garbage-collection cycle.
  • "count": returns the total memory in use by Lua (in Kbytes).
  • "step": performs a garbage-collection step. The step "size" is controlled by arg (larger values mean more steps) in a non-specified way. If you want to control the step size you must experimentally tune the value of arg. Returns true if the step finished a collection cycle.
  • "setpause": sets arg/100 as the new value for the pause of the collector (see §2.10).
  • "setstepmul": sets arg/100 as the new value for the step multiplier of the collector (see §2.10).


dofile (filename)

Opens the named file and executes its contents as a Lua chunk. When called without arguments, dofile executes the contents of the standard input (stdin). Returns all values returned by the chunk. In case of errors, dofile propagates the error to its caller (that is, dofile does not run in protected mode).


error (message [, level])

Terminates the last protected function called and returns message as the error message. Function error never returns.

Usually, error adds some information about the error position at the beginning of the message. The level argument specifies how to get the error position. With level 1 (the default), the error position is where the error function was called. Level 2 points the error to where the function that called error was called; and so on. Passing a level 0 avoids the addition of error position information to the message.


_G

A global variable (not a function) that holds the global environment (that is, _G._G = _G). Lua itself does not use this variable; changing its value does not affect any environment, nor vice-versa. (Use setfenv to change environments.)


getfenv ([f])

Returns the current environment in use by the function. f can be a Lua function or a number that specifies the function at that stack level: Level 1 is the function calling getfenv. If the given function is not a Lua function, or if f is 0, getfenv returns the global environment. The default for f is 1.


getmetatable (object)

If object does not have a metatable, returns nil. Otherwise, if the object's metatable has a "__metatable" field, returns the associated value. Otherwise, returns the metatable of the given object.


ipairs (t)

Returns three values: an iterator function, the table t, and 0, so that the construction

     for i,v in ipairs(t) do body end

will iterate over the pairs (1,t[1]), (2,t[2]), ···, up to the first integer key absent from the table.


load (func [, chunkname])

Loads a chunk using function func to get its pieces. Each call to func must return a string that concatenates with previous results. A return of nil (or no value) signals the end of the chunk.

If there are no errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message. The environment of the returned function is the global environment.

chunkname is used as the chunk name for error messages and debug information.


loadfile ([filename])

Similar to load, but gets the chunk from file filename or from the standard input, if no file name is given.


loadstring (string [, chunkname])

Similar to load, but gets the chunk from the given string.

To load and run a given string, use the idiom

     assert(loadstring(s))()


next (table [, index])

Allows a program to traverse all fields of a table. Its first argument is a table and its second argument is an index in this table. next returns the next index of the table and its associated value. When called with nil as its second argument, next returns an initial index and its associated value. When called with the last index, or with nil in an empty table, next returns nil. If the second argument is absent, then it is interpreted as nil. In particular, you can use next(t) to check whether a table is empty.

The order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numeric order, use a numerical for or the ipairs function.)

The behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table. You may however modify existing fields. In particular, you may clear existing fields.


pairs (t)

Returns three values: the next function, the table t, and nil, so that the construction

     for k,v in pairs(t) do body end

will iterate over all key–value pairs of table t.

See function next for the caveats of modifying the table during its traversal.


pcall (f, arg1, ···)

Calls function f with the given arguments in protected mode. This means that any error inside f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In such case, pcall also returns all results from the call, after this first result. In case of any error, pcall returns false plus the error message.


print (···)

Receives any number of arguments, and prints their values to stdout, using the tostring function to convert them to strings. print is not intended for formatted output, but only as a quick way to show a value, typically for debugging. For formatted output, use string.format.


rawequal (v1, v2)

Checks whether v1 is equal to v2, without invoking any metamethod. Returns a boolean.


rawget (table, index)

Gets the real value of table[index], without invoking any metamethod. table must be a table; index may be any value.


rawset (table, index, value)

Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, index any value different from nil, and value any Lua value.

This function returns table.


select (index, ···)

If index is a number, returns all arguments after argument number index. Otherwise, index must be the string "#", and select returns the total number of extra arguments it received.


setfenv (f, table)

Sets the environment to be used by the given function. f can be a Lua function or a number that specifies the function at that stack level: Level 1 is the function calling setfenv. setfenv returns the given function.

As a special case, when f is 0 setfenv changes the environment of the running thread. In this case, setfenv returns no values.


setmetatable (table, metatable)

Sets the metatable for the given table. (You cannot change the metatable of other types from Lua, only from C.) If metatable is nil, removes the metatable of the given table. If the original metatable has a "__metatable" field, raises an error.

This function returns table.


tonumber (e [, base])

Tries to convert its argument to a number. If the argument is already a number or a string convertible to a number, then tonumber returns this number; otherwise, it returns nil.

An optional argument specifies the base to interpret the numeral. The base may be any integer between 2 and 36, inclusive. In bases above 10, the letter 'A' (in either upper or lower case) represents 10, 'B' represents 11, and so forth, with 'Z' representing 35. In base 10 (the default), the number may have a decimal part, as well as an optional exponent part (see §2.1). In other bases, only unsigned integers are accepted.


tostring (e)

Receives an argument of any type and converts it to a string in a reasonable format. For complete control of how numbers are converted, use string.format.

If the metatable of e has a "__tostring" field, then tostring calls the corresponding value with e as argument, and uses the result of the call as its result.


type (v)

Returns the type of its only argument, coded as a string. The possible results of this function are "nil" (a string, not the value nil), "number", "string", "boolean", "table", "function", "thread", and "userdata".


unpack (list [, i [, j]])

Returns the elements from the given table. This function is equivalent to
     return list[i], list[i+1], ···, list[j]

except that the above code can be written only for a fixed number of elements. By default, i is 1 and j is the length of the list, as defined by the length operator (see §2.5.5).


_VERSION

A global variable (not a function) that holds a string containing the current interpreter version. The current contents of this variable is "Lua 5.1".


xpcall (f, err)

This function is similar to pcall, except that you can set a new error handler.

xpcall calls function f in protected mode, using err as the error handler. Any error inside f is not propagated; instead, xpcall catches the error, calls the err function with the original error object, and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In this case, xpcall also returns all results from the call, after this first result. In case of any error, xpcall returns false plus the result from err.

5.2 - Coroutine Manipulation

The operations related to coroutines comprise a sub-library of the basic library and come inside the table coroutine. See §2.11 for a general description of coroutines.


coroutine.create (f)

Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread".


coroutine.resume (co [, val1, ···])

Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The values val1, ··· are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, ··· are passed as the results from the yield.

If the coroutine runs without any errors, resume returns true plus any values passed to yield (if the coroutine yields) or any values returned by the body function (if the coroutine terminates). If there is any error, resume returns false plus the error message.


coroutine.running ()

Returns the running coroutine, or nil when called by the main thread.


coroutine.status (co)

Returns the status of coroutine co, as a string: "running", if the coroutine is running (that is, it called status); "suspended", if the coroutine is suspended in a call to yield, or if it has not started running yet; "normal" if the coroutine is active but not running (that is, it has resumed another coroutine); and "dead" if the coroutine has finished its body function, or if it has stopped with an error.


coroutine.wrap (f)

Creates a new coroutine, with body f. f must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error.


coroutine.yield (···)

Suspends the execution of the calling coroutine. The coroutine cannot be running a C function, a metamethod, or an iterator. Any arguments to yield are passed as extra results to resume.

5.3 - Modules

The package library provides basic facilities for loading and building modules in Lua. It exports two of its functions directly in the global environment: require and module. Everything else is exported in a table package.


module (name [, ···])

Creates a module. If there is a table in package.loaded[name], this table is the module. Otherwise, if there is a global table t with the given name, this table is the module. Otherwise creates a new table t and sets it as the value of the global name and the value of package.loaded[name]. This function also initializes t._NAME with the given name, t._M with the module (t itself), and t._PACKAGE with the package name (the full module name minus last component; see below). Finally, module sets t as the new environment of the current function and the new value of package.loaded[name], so that require returns t.

If name is a compound name (that is, one with components separated by dots), module creates (or reuses, if they already exist) tables for each component. For instance, if name is a.b.c, then module stores the module table in field c of field b of global a.

This function may receive optional options after the module name, where each option is a function to be applied over the module.


require (modname)

Loads the given module. The function starts by looking into the package.loaded table to determine whether modname is already loaded. If it is, then require returns the value stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.

To find a loader, first require queries package.preload[modname]. If it has a value, this value (which should be a function) is the loader. Otherwise require searches for a Lua loader using the path stored in package.path. If that also fails, it searches for a C loader using the path stored in package.cpath. If that also fails, it tries an all-in-one loader (see below).

When loading a C library, require first uses a dynamic link facility to link the application with the library. Then it tries to find a C function inside this library to be used as the loader. The name of this C function is the string "luaopen_" concatenated with a copy of the module name where each dot is replaced by an underscore. Moreover, if the module name has a hyphen, its prefix up to (and including) the first hyphen is removed. For instance, if the module name is a.v1-b.c, the function name will be luaopen_b_c.

If require finds neither a Lua library nor a C library for a module, it calls the all-in-one loader. This loader searches the C path for a library for the root name of the given module. For instance, when requiring a.b.c, it will search for a C library for a. If found, it looks into it for an open function for the submodule; in our example, that would be luaopen_a_b_c. With this facility, a package can pack several C submodules into one single library, with each submodule keeping its original open function.

Once a loader is found, require calls the loader with a single argument, modname. If the loader returns any value, require assigns the returned value to package.loaded[modname]. If the loader returns no value and has not assigned any value to package.loaded[modname], then require assigns true to this entry. In any case, require returns the final value of package.loaded[modname].

If there is any error loading or running the module, or if it cannot find any loader for the module, then require signals an error.


package.cpath

The path used by require to search for a C loader.

Lua initializes the C path package.cpath in the same way it initializes the Lua path package.path, using the environment variable LUA_CPATH (plus another default path defined in luaconf.h).


package.loaded

A table used by require to control which modules are already loaded. When you require a module modname and package.loaded[modname] is not false, require simply returns the value stored there.


package.loadlib (libname, funcname)

Dynamically links the host program with the C library libname. Inside this library, looks for a function funcname and returns this function as a C function. (So, funcname must follow the protocol (see lua_CFunction)).

This is a low-level function. It completely bypasses the package and module system. Unlike require, it does not perform any path searching and does not automatically adds extensions. libname must be the complete file name of the C library, including if necessary a path and extension. funcname must be the exact name exported by the C library (which may depend on the C compiler and linker used).

This function is not supported by ANSI C. As such, it is only available on some platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix systems that support the dlfcn standard).


package.path

The path used by require to search for a Lua loader.

At start-up, Lua initializes this variable with the value of the environment variable LUA_PATH or with a default path defined in luaconf.h, if the environment variable is not defined. Any ";;" in the value of the environment variable is replaced by the default path.

A path is a sequence of templates separated by semicolons. For each template, require will change each interrogation mark in the template by filename, which is modname with each dot replaced by a "directory separator" (such as "/" in Unix); then it will try to load the resulting file name. So, for instance, if the Lua path is

     "./?.lua;./?.lc;/usr/local/?/init.lua"

the search for a Lua loader for module foo will try to load the files ./foo.lua, ./foo.lc, and /usr/local/foo/init.lua, in that order.


package.preload

A table to store loaders for specific modules (see require).


package.seeall (module)

Sets a metatable for module with its __index field referring to the global environment, so that this module inherits values from the global environment. To be used as an option to function module.

5.4 - String Manipulation

This library provides generic functions for string manipulation, such as finding and extracting substrings, and pattern matching. When indexing a string in Lua, the first character is at position 1 (not at 0, as in C). Indices are allowed to be negative and are interpreted as indexing backwards, from the end of the string. Thus, the last character is at position -1, and so on.

The string library provides all its functions inside the table string. It also sets a metatable for strings where the __index field points to the string table. Therefore, you can use the string functions in object-oriented style. For instance, string.byte(s, i) can be written as s:byte(i).


string.byte (s [, i [, j]])

Returns the internal numerical codes of the characters s[i], s[i+1], ···, s[j]. The default value for i is 1; the default value for j is i.

Note that numerical codes are not necessarily portable across platforms.


string.char (···)

Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its corresponding argument.

Note that numerical codes are not necessarily portable across platforms.


string.dump (function)

Returns a string containing a binary representation of the given function, so that a later loadstring on this string returns a copy of the function. function must be a Lua function without upvalues.


string.find (s, pattern [, init [, plain]])

Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered "magic". Note that if plain is given, then init must be given as well.

If the pattern has captures, then in a successful match the captured values are also returned, after the two indices.


string.format (formatstring, ···)

Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of standard C functions. The only differences are that the options/modifiers *, l, L, n, p, and h are not supported and that there is an extra option, q. The q option formats a string in a form suitable to be safely read back by the Lua interpreter: the string is written between double quotes, and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly escaped when written. For instance, the call
     string.format('%q', 'a string with "quotes" and \n new line')

will produce the string:

     "a string with \"quotes\" and \
      new line"

The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument, whereas q and s expect a string.

This function does not accept string values containing embedded zeros, except as arguments to the q option.


string.gmatch (s, pattern)

Returns an iterator function that, each time it is called, returns the next captures from pattern over string s. If pattern specifies no captures, then the whole match is produced in each call.

As an example, the following loop

     s = "hello world from Lua"
     for w in string.gmatch(s, "%a+") do
       print(w)
     end

will iterate over all the words from string s, printing one per line. The next example collects all pairs key=value from the given string into a table:

     t = {}
     s = "from=world, to=Lua"
     for k, v in string.gmatch(s, "(%w+)=(%w+)") do
       t[k] = v
     end

For this function, a '^' at the start of a pattern does not work as an anchor, as this would prevent the iteration.


string.gsub (s, pattern, repl [, n])

Returns a copy of s in which all occurrences of the pattern have been replaced by a replacement string specified by repl, which may be a string, a table, or a function. gsub also returns, as its second value, the total number of substitutions made.

If repl is a string, then its value is used for replacement. The character % works as an escape character: any sequence in repl of the form %n, with n between 1 and 9, stands for the value of the n-th captured substring (see below). The sequence %0 stands for the whole match. The sequence %% stands for a single %.

If repl is a table, then the table is queried for every match, using the first capture as the key; if the pattern specifies no captures, then the whole match is used as the key.

If repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, in order; if the pattern specifies no captures, then the whole match is passed as a sole argument.

If the value returned by the table query or by the function call is a string or a number, then it is used as the replacement string; otherwise, if it is false or nil, then there is no replacement (that is, the original match is kept in the string).

The optional last parameter n limits the maximum number of substitutions to occur. For instance, when n is 1 only the first occurrence of pattern is replaced.

Here are some examples:

     x = string.gsub("hello world", "(%w+)", "%1 %1")
     --> x="hello hello world world"
     
     x = string.gsub("hello world", "%w+", "%0 %0", 1)
     --> x="hello hello world"
     
     x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
     --> x="world hello Lua from"
     
     x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
     --> x="home = /home/roberto, user = roberto"
     
     x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
           return loadstring(s)()
         end)
     --> x="4+5 = 9"
     
     local t = {name="lua", version="5.1"}
     x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
     --> x="lua-5.1.tar.gz"


string.len (s)

Receives a string and returns its length. The empty string "" has length 0. Embedded zeros are counted, so "a\000bc\000" has length 5.


string.lower (s)

Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale.


string.match (s, pattern [, init])

Looks for the first match of pattern in the string s. If it finds one, then match returns the captures from the pattern; otherwise it returns nil. If pattern specifies no captures, then the whole match is returned. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative.


string.rep (s, n)

Returns a string that is the concatenation of n copies of the string s.


string.reverse (s)

Returns a string that is the string s reversed.


string.sub (s, i [, j])

Returns the substring of s that starts at i and continues until j; i and j may be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) returns a suffix of s with length i.


string.upper (s)

Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale.

5.4.1 - Patterns

Character Class:

A character class is used to represent a set of characters. The following combinations are allowed in describing a character class:

  • x: (where x is not one of the magic characters ^$()%.[]*+-?) represents the character x itself.
  • .: (a dot) represents all characters.
  • %a: represents all letters.
  • %c: represents all control characters.
  • %d: represents all digits.
  • %l: represents all lowercase letters.
  • %p: represents all punctuation characters.
  • %s: represents all space characters.
  • %u: represents all uppercase letters.
  • %w: represents all alphanumeric characters.
  • %x: represents all hexadecimal digits.
  • %z: represents the character with representation 0.
  • %x: (where x is any non-alphanumeric character) represents the character x. This is the standard way to escape the magic characters. Any punctuation character (even the non magic) can be preceded by a '%' when used to represent itself in a pattern.
  • [set]: represents the class which is the union of all characters in set. A range of characters may be specified by separating the end characters of the range with a '-'. All classes %x described above may also be used as components in set. All other characters in set represent themselves. For example, [%w_] (or [_%w]) represents all alphanumeric characters plus the underscore, [0-7] represents the octal digits, and [0-7%l%-] represents the octal digits plus the lowercase letters plus the '-' character.

    The interaction between ranges and classes is not defined. Therefore, patterns like [%a-z] or [a-%%] have no meaning.

  • [^set]: represents the complement of set, where set is interpreted as above.

For all classes represented by single letters (%a, %c, etc.), the corresponding uppercase letter represents the complement of the class. For instance, %S represents all non-space characters.

The definitions of letter, space, and other character groups depend on the current locale. In particular, the class [a-z] may not be equivalent to %l.

Pattern Item:

A pattern item may be

  • a single character class, which matches any single character in the class;
  • a single character class followed by '*', which matches 0 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence;
  • a single character class followed by '+', which matches 1 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence;
  • a single character class followed by '-', which also matches 0 or more repetitions of characters in the class. Unlike '*', these repetition items will always match the shortest possible sequence;
  • a single character class followed by '?', which matches 0 or 1 occurrence of a character in the class;
  • %n, for n between 1 and 9; such item matches a substring equal to the n-th captured string (see below);
  • %bxy, where x and y are two distinct characters; such item matches strings that start with x, end with y, and where the x and y are balanced. This means that, if one reads the string from left to right, counting +1 for an x and -1 for a y, the ending y is the first y where the count reaches 0. For instance, the item %b() matches expressions with balanced parentheses.

Pattern:

A pattern is a sequence of pattern items. A '^' at the beginning of a pattern anchors the match at the beginning of the subject string. A '$' at the end of a pattern anchors the match at the end of the subject string. At other positions, '^' and '$' have no special meaning and represent themselves.

Captures:

A pattern may contain sub-patterns enclosed in parentheses; they describe captures. When a match succeeds, the substrings of the subject string that match captures are stored (captured) for future use. Captures are numbered according to their left parentheses. For instance, in the pattern "(a*(.)%w(%s*))", the part of the string matching "a*(.)%w(%s*)" is stored as the first capture (and therefore has number 1); the character matching "." is captured with number 2, and the part matching "%s*" has number 3.

As a special case, the empty capture () captures the current string position (a number). For instance, if we apply the pattern "()aa()" on the string "flaaap", there will be two captures: 3 and 5.

A pattern cannot contain embedded zeros. Use %z instead.

5.5 - Table Manipulation

This library provides generic functions for table manipulation. It provides all its functions inside the table table.

Most functions in the table library assume that the table represents an array or a list. For these functions, when we talk about the "length" of a table we mean the result of the length operator.


table.concat (table [, sep [, i [, j]]])

Given an array where all elements are strings or numbers, returns table[i]..sep..table[i+1] ··· sep..table[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is the length of the table. If i is greater than j, returns the empty string.


table.insert (table, [pos,] value)

Inserts element value at position pos in table, shifting up other elements to open space, if necessary. The default value for pos is n+1, where n is the length of the table (see §2.5.5), so that a call table.insert(t,x) inserts x at the end of table t.


table.maxn (table)

Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical indices. (To do its job this function does a linear traversal of the whole table.)


table.remove (table [, pos])

Removes from table the element at position pos, shifting down other elements to close the space, if necessary. Returns the value of the removed element. The default value for pos is n, where n is the length of the table, so that a call table.remove(t) removes the last element of table t.


table.sort (table [, comp])

Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the length of the table. If comp is given, then it must be a function that receives two table elements, and returns true when the first is less than the second (so that not comp(a[i+1],a[i]) will be true after the sort). If comp is not given, then the standard Lua operator < is used instead.

The sort algorithm is not stable; that is, elements considered equal by the given order may have their relative positions changed by the sort.

5.6 - Mathematical Functions

This library is an interface to the standard C math library. It provides all its functions inside the table math.


math.abs (x)

Returns the absolute value of x.


math.acos (x)

Returns the arc cosine of x (in radians).


math.asin (x)

Returns the arc sine of x (in radians).


math.atan (x)

Returns the arc tangent of x (in radians).


math.atan2 (x, y)

Returns the arc tangent of x/y (in radians), but uses the signs of both parameters to find the quadrant of the result. (It also handles correctly the case of y being zero.)


math.ceil (x)

Returns the smallest integer larger than or equal to x.


math.cos (x)

Returns the cosine of x (assumed to be in radians).


math.cosh (x)

Returns the hyperbolic cosine of x.


math.deg (x)

Returns the angle x (given in radians) in degrees.


math.exp (x)

Returns the the value ex.


math.floor (x)

Returns the largest integer smaller than or equal to x.


math.fmod (x, y)

Returns the remainder of the division of x by y.


math.frexp (x)

Returns m and e such that x = m2e, e is an integer and the absolute value of m is in the range [0.5, 1) (or zero when x is zero).


math.huge

The value HUGE_VAL, a value larger than or equal to any other numerical value.


math.ldexp (m, e)

Returns m2e (e should be an integer).


math.log (x)

Returns the natural logarithm of x.


math.log10 (x)

Returns the base-10 logarithm of x.


math.max (x, ···)

Returns the maximum value among its arguments.


math.min (x, ···)

Returns the minimum value among its arguments.


math.modf (x)

Returns two numbers, the integral part of x and the fractional part of x.


math.pi

The value of pi.


math.pow (x, y)

Returns xy. (You can also use the expression x^y to compute this value.)


math.rad (x)

Returns the angle x (given in degrees) in radians.


math.random ([m [, n]])

This function is an interface to the simple pseudo-random generator function rand provided by ANSI C. (No guarantees can be given for its statistical properties.)

When called without arguments, returns a pseudo-random real number in the range [0,1). When called with a number m, math.random returns a pseudo-random integer in the range [1, m]. When called with two numbers m and n, math.random returns a pseudo-random integer in the range [m, n].


math.randomseed (x)

Sets x as the "seed" for the pseudo-random generator: equal seeds produce equal sequences of numbers.


math.sin (x)

Returns the sine of x (assumed to be in radians).


math.sinh (x)

Returns the hyperbolic sine of x.


math.sqrt (x)

Returns the square root of x. (You can also use the expression x^0.5 to compute this value.)


math.tan (x)

Returns the tangent of x (assumed to be in radians).


math.tanh (x)

Returns the hyperbolic tangent of x.

5.7 - Input and Output Facilities

The I/O library provides two different styles for file manipulation. The first one uses implicit file descriptors; that is, there are operations to set a default input file and a default output file, and all input/output operations are over these default files. The second style uses explicit file descriptors.

When using implicit file descriptors, all operations are supplied by table io. When using explicit file descriptors, the operation io.open returns a file descriptor and then all operations are supplied as methods of the file descriptor.

The table io also provides three predefined file descriptors with their usual meanings from C: io.stdin, io.stdout, and io.stderr.

Unless otherwise stated, all I/O functions return nil on failure (plus an error message as a second result and a system-dependent error code as a third result) and some value different from nil on success.


io.close ([file])

Equivalent to file:close(). Without a file, closes the default output file.


io.flush ()

Equivalent to file:flush over the default output file.


io.input ([file])

When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, it simply sets this file handle as the default input file. When called without parameters, it returns the current default input file.

In case of errors this function raises the error, instead of returning an error code.


io.lines ([filename])

Opens the given file name in read mode and returns an iterator function that, each time it is called, returns a new line from the file. Therefore, the construction

     for line in io.lines(filename) do body end

will iterate over all lines of the file. When the iterator function detects the end of file, it returns nil (to finish the loop) and automatically closes the file.

The call io.lines() (with no file name) is equivalent to io.input():lines(); that is, it iterates over the lines of the default input file. In this case it does not close the file when the loop ends.


io.open (filename [, mode])

This function opens a file, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message.

The mode string can be any of the following:

  • "r": read mode (the default);
  • "w": write mode;
  • "a": append mode;
  • "r+": update mode, all previous data is preserved;
  • "w+": update mode, all previous data is erased;
  • "a+": append update mode, previous data is preserved, writing is only allowed at the end of file.

The mode string may also have a 'b' at the end, which is needed in some systems to open the file in binary mode. This string is exactly what is used in the standard C function fopen.


io.output ([file])

Similar to io.input, but operates over the default output file.


io.popen (prog [, mode])

Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is "r", the default) or to write data to this program (if mode is "w").

This function is system dependent and is not available on all platforms.


io.read (···)

Equivalent to io.input():read.


io.tmpfile ()

Returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends.


io.type (obj)

Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, or nil if obj is not a file handle.


io.write (···)

Equivalent to io.output():write.


file:close ()

Closes file. Note that files are automatically closed when their handles are garbage collected, but that takes an unpredictable amount of time to happen.


file:flush ()

Saves any written data to file.


file:lines ()

Returns an iterator function that, each time it is called, returns a new line from the file. Therefore, the construction

     for line in file:lines() do body end

will iterate over all lines of the file. (Unlike io.lines, this function does not close the file when the loop ends.)


file:read (···)

Reads the file file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below).

The available formats are

  • "*n": reads a number; this is the only format that returns a number instead of a string.
  • "*a": reads the whole file, starting at the current position. On end of file, it returns the empty string.
  • "*l": reads the next line (skipping the end of line), returning nil on end of file. This is the default format.
  • number: reads a string with up to this number of characters, returning nil on end of file. If number is zero, it reads nothing and returns an empty string, or nil on end of file.


file:seek ([whence] [, offset])

Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence, as follows:

  • "set": base is position 0 (beginning of the file);
  • "cur": base is current position;
  • "end": base is end of file;

In case of success, function seek returns the final file position, measured in bytes from the beginning of the file. If this function fails, it returns nil, plus a string describing the error.

The default value for whence is "cur", and for offset is 0. Therefore, the call file:seek() returns the current file position, without changing it; the call file:seek("set") sets the position to the beginning of the file (and returns 0); and the call file:seek("end") sets the position to the end of the file, and returns its size.


file:setvbuf (mode [, size])

Sets the buffering mode for an output file. There are three available modes:

  • "no": no buffering; the result of any output operation appears immediately.
  • "full": full buffering; output operation is performed only when the buffer is full (or when you explicitly flush the file (see io.flush)).
  • "line": line buffering; output is buffered until a newline is output or there is any input from some special files (such as a terminal device).

For the last two cases, size specifies the size of the buffer, in bytes. The default is an appropriate size.


file:write (···)

Writes the value of each of its arguments to the file. The arguments must be strings or numbers. To write other values, use tostring or string.format before write.

5.8 - Operating System Facilities

This library is implemented through table os.


os.clock ()

Returns an approximation of the amount in seconds of CPU time used by the program.


os.date ([format [, time]])

Returns a string or a table containing date and time, formatted according to the given string format.

If the time argument is present, this is the time to be formatted (see the os.time function for a description of this value). Otherwise, date formats the current time.

If format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, if format is the string "*t", then date returns a table with the following fields: year (four digits), month (1--12), day (1--31), hour (0--23), min (0--59), sec (0--61), wday (weekday, Sunday is 1), yday (day of the year), and isdst (daylight saving flag, a boolean).

If format is not "*t", then date returns the date as a string, formatted according to the same rules as the C function strftime.

When called without arguments, date returns a reasonable date and time representation that depends on the host system and on the current locale (that is, os.date() is equivalent to os.date("%c")).


os.difftime (t2, t1)

Returns the number of seconds from time t1 to time t2. In POSIX, Windows, and some other systems, this value is exactly t2-t1.


os.execute ([command])

This function is equivalent to the C function system. It passes command to be executed by an operating system shell. It returns a status code, which is system-dependent. If command is absent, then it returns nonzero if a shell is available and zero otherwise.


os.exit ([code])

Calls the C function exit, with an optional code, to terminate the host program. The default value for code is the success code.


os.getenv (varname)

Returns the value of the process environment variable varname, or nil if the variable is not defined.


os.remove (filename)

Deletes the file or directory with the given name. Directories must be empty to be removed. If this function fails, it returns nil, plus a string describing the error.


os.rename (oldname, newname)

Renames file or directory named oldname to newname. If this function fails, it returns nil, plus a string describing the error.


os.setlocale (locale [, category])

Sets the current locale of the program. locale is a string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category is "all". The function returns the name of the new locale, or nil if the request cannot be honored.

If locale is the empty string, the current locate is set to an implementation-defined native locale. If locate is the string "C", the current locate is set to the standard C locale.

When called with nil as the first argument, this function only returns the name of the current locale for the given category.


os.time ([table])

Returns the current time when called without arguments, or a time representing the date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour, min, sec, and isdst (for a description of these fields, see the os.date function).

The returned value is a number, whose meaning depends on your system. In POSIX, Windows, and some other systems, this number counts the number of seconds since some given start time (the "epoch"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to date and difftime.


os.tmpname ()

Returns a string with a file name that can be used for a temporary file. The file must be explicitly opened before its use and explicitly removed when no longer needed.

5.9 - The Debug Library

This library provides the functionality of the debug interface to Lua programs. You should exert care when using this library. The functions provided here should be used exclusively for debugging and similar tasks, such as profiling. Please resist the temptation to use them as a usual programming tool: they can be very slow. Moreover, several of its functions violate some assumptions about Lua code (e.g., that variables local to a function cannot be accessed from outside or that userdata metatables cannot be changed by Lua code) and therefore can compromise otherwise secure code.

All functions in this library are provided inside the debug table. All functions that operate over a thread have an optional first argument which is the thread to operate over. The default is always the current thread.


debug.debug ()

Enters an interactive mode with the user, running each string that the user enters. Using simple commands and other debug facilities, the user can inspect global and local variables, change their values, evaluate expressions, and so on. A line containing only the word cont finishes this function, so that the caller continues its execution.

Note that commands for debug.debug are not lexically nested within any function, and so have no direct access to local variables.


debug.getfenv (o)

Returns the environment of object o.


debug.gethook ([thread])

Returns the current hook settings of the thread, as three values: the current hook function, the current hook mask, and the current hook count (as set by the debug.sethook function).


debug.getinfo ([thread,] function [, what])

Returns a table with information about a function. You can give the function directly, or you can give a number as the value of function, which means the function running at level function of the call stack of the given thread: level 0 is the current function (getinfo itself); level 1 is the function that called getinfo; and so on. If function is a number larger than the number of active functions, then getinfo returns nil.

The returned table may contain all the fields returned by lua_getinfo, with the string what describing which fields to fill in. The default for what is to get all information available, except the table of valid lines. If present, the option 'f' adds a field named func with the function itself. If present, the option 'L' adds a field named activelines with the table of valid lines.

For instance, the expression debug.getinfo(1,"n").name returns a name of the current function, if a reasonable name can be found, and the expression debug.getinfo(print) returns a table with all available information about the print function.


debug.getlocal ([thread,] level, local)

This function returns the name and the value of the local variable with index local of the function at level level of the stack. (The first parameter or local variable has index 1, and so on, until the last active local variable.) The function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call debug.getinfo to check whether the level is valid.)

Variable names starting with '(' (open parentheses) represent internal variables (loop control variables, temporaries, and C function locals).


debug.getmetatable (object)

Returns the metatable of the given object or nil if it does not have a metatable.


debug.getregistry ()

Returns the registry table (see §3.5).


debug.getupvalue (func, up)

This function returns the name and the value of the upvalue with index up of the function func. The function returns nil if there is no upvalue with the given index.


debug.setfenv (object, table)

Sets the environment of the given object to the given table. Returns object.


debug.sethook ([thread,] hook, mask [, count])

Sets the given function as a hook. The string mask and the number count describe when the hook will be called. The string mask may have the following characters, with the given meaning:

  • "c": The hook is called every time Lua calls a function;
  • "r": The hook is called every time Lua returns from a function;
  • "l": The hook is called every time Lua enters a new line of code.

With a count different from zero, the hook is called after every count instructions.

When called without arguments, debug.sethook turns off the hook.

When the hook is called, its first parameter is a string describing the event that has triggered its call: "call", "return" (or "tail return"), "line", and "count". For line events, the hook also gets the new line number as its second parameter. Inside a hook, you can call getinfo with level 2 to get more information about the running function (level 0 is the getinfo function, and level 1 is the hook function), unless the event is "tail return". In this case, Lua is only simulating the return, and a call to getinfo will return invalid data.


debug.setlocal ([thread,] level, local, value)

This function assigns the value value to the local variable with index local of the function at level level of the stack. The function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call getinfo to check whether the level is valid.) Otherwise, it returns the name of the local variable.


debug.setmetatable (object, table)

Sets the metatable for the given object to the given table (which can be nil).


debug.setupvalue (func, up, value)

This function assigns the value value to the upvalue with index up of the function func. The function returns nil if there is no upvalue with the given index. Otherwise, it returns the name of the upvalue.


debug.traceback ([thread,] [message] [, level])

Returns a string with a traceback of the call stack. An optional message string is appended at the beginning of the traceback. An optional level number tells at which level to start the traceback (default is 1, the function calling traceback).

6 - Lua Stand-alone

Although Lua has been designed as an extension language, to be embedded in a host C program, it is also frequently used as a stand-alone language. An interpreter for Lua as a stand-alone language, called simply lua, is provided with the standard distribution. The stand-alone interpreter includes all standard libraries, including the debug library. Its usage is:

     lua [options] [script [args]]

The options are:

  • -e stat: executes string stat;
  • -l mod: "requires" mod;
  • -i: enters interactive mode after running script;
  • -v: prints version information;
  • --: stops handling options;
  • -: executes stdin as a file and stops handling options.

After handling its options, lua runs the given script, passing to it the given args as string arguments. When called without arguments, lua behaves as lua -v -i when the standard input (stdin) is a terminal, and as lua - otherwise.

Before running any argument, the interpreter checks for an environment variable LUA_INIT. If its format is @filename, then lua executes the file. Otherwise, lua executes the string itself.

All options are handled in order, except -i. For instance, an invocation like

     $ lua -e'a=1' -e 'print(a)' script.lua

will first set a to 1, then print the value of a (which is '1'), and finally run the file script.lua with no arguments. (Here $ is the shell prompt. Your prompt may be different.)

Before starting to run the script, lua collects all arguments in the command line in a global table called arg. The script name is stored at index 0, the first argument after the script name goes to index 1, and so on. Any arguments before the script name (that is, the interpreter name plus the options) go to negative indices. For instance, in the call

     $ lua -la b.lua t1 t2

the interpreter first runs the file a.lua, then creates a table

     arg = { [-2] = "lua", [-1] = "-la",
             [0] = "b.lua",
             [1] = "t1", [2] = "t2" }

and finally runs the file b.lua. The script is called with arg[1], arg[2], ··· as arguments; it can also access these arguments with the vararg expression '...'.

In interactive mode, if you write an incomplete statement, the interpreter waits for its completion by issuing a different prompt.

If the global variable _PROMPT contains a string, then its value is used as the prompt. Similarly, if the global variable _PROMPT2 contains a string, its value is used as the secondary prompt (issued during incomplete statements). Therefore, both prompts can be changed directly on the command line. For instance,

     $ lua -e"_PROMPT='myprompt> '" -i

(the outer pair of quotes is for the shell, the inner pair is for Lua), or in any Lua programs by assigning to _PROMPT. Note the use of -i to enter interactive mode; otherwise, the program would just end silently right after the assignment to _PROMPT.

To allow the use of Lua as a script interpreter in Unix systems, the stand-alone interpreter skips the first line of a chunk if it starts with #. Therefore, Lua scripts can be made into executable programs by using chmod +x and the #! form, as in

     #!/usr/local/bin/lua

(Of course, the location of the Lua interpreter may be different in your machine. If lua is in your PATH, then

     #!/usr/bin/env lua

is a more portable solution.)

7 - Incompatibilities with the Previous Version

Here we list the incompatibilities that you may found when moving a program from Lua 5.0 to Lua 5.1. You can avoid most of the incompatibilities compiling Lua with appropriate options (see file luaconf.h). However, all these compatibility options will be removed in the next version of Lua.

7.1 - Changes in the Language

  • The vararg system changed from the pseudo-argument arg with a table with the extra arguments to the vararg expression. (See compile-time option LUA_COMPAT_VARARG in luaconf.h.)
  • There was a subtle change in the scope of the implicit variables of the for statement and for the repeat statement.
  • The long string/long comment syntax ([[string]]) does not allow nesting. You can use the new syntax ([=[string]=]) in these cases. (See compile-time option LUA_COMPAT_LSTR in luaconf.h.)

7.2 - Changes in the Libraries

  • Function string.gfind was renamed string.gmatch. (See compile-time option LUA_COMPAT_GFIND in luaconf.h.)
  • When string.gsub is called with a function as its third argument, whenever this function returns nil or false the replacement string is the whole match, instead of the empty string.
  • Function table.setn was deprecated. Function table.getn corresponds to the new length operator (#); use the operator instead of the function. (See compile-time option LUA_COMPAT_GETN in luaconf.h.)
  • Function loadlib was renamed package.loadlib. (See compile-time option LUA_COMPAT_LOADLIB in luaconf.h.)
  • Function math.mod was renamed math.fmod. (See compile-time option LUA_COMPAT_MOD in luaconf.h.)
  • Functions table.foreach and table.foreachi are deprecated. You can use a for loop with pairs or ipairs instead.
  • There were substantial changes in function require due to the new module system. However, the new behavior is mostly compatible with the old, but require gets the path from package.path instead of from LUA_PATH.
  • Function collectgarbage has different arguments. Function gcinfo is deprecated; use collectgarbage("count") instead.

7.3 - Changes in the API

  • The luaopen_* functions (to open libraries) cannot be called directly, like a regular C function. They must be called through Lua, like a Lua function.
  • Function lua_open was replaced by lua_newstate to allow the user to set a memory-allocation function. You can use luaL_newstate from the standard library to create a state with a standard allocation function (based on realloc).
  • Functions luaL_getn and luaL_setn (from the auxiliary library) are deprecated. Use lua_objlen instead of luaL_getn and nothing instead of luaL_setn.
  • Function luaL_openlib was replaced by luaL_register.
  • Function luaL_checkudata now throws an error when the given value is not a userdata of the expected type. (In Lua 5.0 it returned NULL.)

8 - The Complete Syntax of Lua

Here is the complete syntax of Lua in extended BNF. (It does not describe operator precedences.)


	chunk ::= {stat [`;´]} [laststat [`;´]]

	block ::= chunk

	stat ::=  varlist1 `=´ explist1 | 
		 functioncall | 
		 do block end | 
		 while exp do block end | 
		 repeat block until exp | 
		 if exp then block {elseif exp then block} [else block] end | 
		 for Name `=´ exp `,´ exp [`,´ exp] do block end | 
		 for namelist in explist1 do block end | 
		 function funcname funcbody | 
		 local function Name funcbody | 
		 local namelist [`=´ explist1] 

	laststat ::= return [explist1] | break

	funcname ::= Name {`.´ Name} [`:´ Name]

	varlist1 ::= var {`,´ var}

	var ::=  Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name 

	namelist ::= Name {`,´ Name}

	explist1 ::= {exp `,´} exp

	exp ::=  nil | false | true | Number | String | `...´ | function | 
		 prefixexp | tableconstructor | exp binop exp | unop exp 

	prefixexp ::= var | functioncall | `(´ exp `)´

	functioncall ::=  prefixexp args | prefixexp `:´ Name args 

	args ::=  `(´ [explist1] `)´ | tableconstructor | String 

	function ::= function funcbody

	funcbody ::= `(´ [parlist1] `)´ block end

	parlist1 ::= namelist [`,´ `...´] | `...´

	tableconstructor ::= `{´ [fieldlist] `}´

	fieldlist ::= field {fieldsep field} [fieldsep]

	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp

	fieldsep ::= `,´ | `;´

	binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `%´ | `..´ | 
		 `<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ | 
		 and | or

	unop ::= `-´ | not | `#´


Last update: Mon Mar 26 12:59:26 BRT 2007 tagua-1.0-alpha2/lua/doc/readme.html000066400000000000000000000015011077523320400172710ustar00rootroot00000000000000 Lua documentation

Lua Documentation

This is the documentation included in the source distribution of Lua 5.1.2. Lua's official web site contains updated documentation, especially the reference manual.


Last update: Fri Mar 23 14:19:36 BRT 2007 tagua-1.0-alpha2/lua/etc/000077500000000000000000000000001077523320400151575ustar00rootroot00000000000000tagua-1.0-alpha2/lua/etc/Makefile000066400000000000000000000016201077523320400166160ustar00rootroot00000000000000# makefile for Lua etc TOP= .. LIB= $(TOP)/src INC= $(TOP)/src BIN= $(TOP)/src SRC= $(TOP)/src TST= $(TOP)/test CC= gcc CFLAGS= -O2 -Wall -I$(INC) $(MYCFLAGS) MYCFLAGS= MYLDFLAGS= -Wl,-E MYLIBS= -lm #MYLIBS= -lm -Wl,-E -ldl -lreadline -lhistory -lncurses RM= rm -f default: @echo 'Please choose a target: min noparser one strict clean' min: min.c $(CC) $(CFLAGS) $@.c -L$(LIB) -llua $(MYLIBS) echo 'print"Hello there!"' | ./a.out noparser: noparser.o $(CC) noparser.o $(SRC)/lua.o -L$(LIB) -llua $(MYLIBS) $(BIN)/luac $(TST)/hello.lua -./a.out luac.out -./a.out -e'a=1' one: $(CC) $(CFLAGS) all.c $(MYLIBS) ./a.out $(TST)/hello.lua strict: -$(BIN)/lua -e 'print(a);b=2' -$(BIN)/lua -lstrict -e 'print(a)' -$(BIN)/lua -e 'function f() b=2 end f()' -$(BIN)/lua -lstrict -e 'function f() b=2 end f()' clean: $(RM) a.out core core.* *.o luac.out .PHONY: default min noparser one strict clean tagua-1.0-alpha2/lua/etc/README000066400000000000000000000017141077523320400160420ustar00rootroot00000000000000This directory contains some useful files and code. Unlike the code in ../src, everything here is in the public domain. If any of the makes fail, you're probably not using the same libraries used to build Lua. Set MYLIBS in Makefile accordingly. all.c Full Lua interpreter in a single file. Do "make one" for a demo. lua.hpp Lua header files for C++ using 'extern "C"'. lua.ico A Lua icon for Windows (and web sites: save as favicon.ico). Drawn by hand by Markus Gritsch . lua.pc pkg-config data for Lua luavs.bat Script to build Lua under "Visual Studio .NET Command Prompt". Run it from the toplevel as etc\luavs.bat. min.c A minimal Lua interpreter. Good for learning and for starting your own. Do "make min" for a demo. noparser.c Linking with noparser.o avoids loading the parsing modules in lualib.a. Do "make noparser" for a demo. strict.lua Traps uses of undeclared global variables. Do "make strict" for a demo. tagua-1.0-alpha2/lua/etc/all.c000066400000000000000000000012461077523320400160760ustar00rootroot00000000000000/* * all.c -- Lua core, libraries and interpreter in a single file */ #define luaall_c #include "lapi.c" #include "lcode.c" #include "ldebug.c" #include "ldo.c" #include "ldump.c" #include "lfunc.c" #include "lgc.c" #include "llex.c" #include "lmem.c" #include "lobject.c" #include "lopcodes.c" #include "lparser.c" #include "lstate.c" #include "lstring.c" #include "ltable.c" #include "ltm.c" #include "lundump.c" #include "lvm.c" #include "lzio.c" #include "lauxlib.c" #include "lbaselib.c" #include "ldblib.c" #include "liolib.c" #include "linit.c" #include "lmathlib.c" #include "loadlib.c" #include "loslib.c" #include "lstrlib.c" #include "ltablib.c" #include "lua.c" tagua-1.0-alpha2/lua/etc/lua.hpp000066400000000000000000000002771077523320400164570ustar00rootroot00000000000000// lua.hpp // Lua header files for C++ // <> not supplied automatically because Lua also compiles as C++ extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } tagua-1.0-alpha2/lua/etc/lua.ico000066400000000000000000000020661077523320400164400ustar00rootroot00000000000000 &(( @DDHDDDDDDDDDDDDDDpDDDDDDDDHDDDDDDDDDDtDDDDDDDDDDGDDDDDDDDDDDDDHDDOxD@DDDOODDHDDDOOODHDDDDOODHDDDDDDOODDDDDDOOtDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDtDHDDDDDDHDHDDDDDDHD@DDDDDDHDDDDDDDDtDtDDDDDDGDDDDDDDDwpDDDDDDDDHxDHpDDDDDDDDpDDDDDDDDDDDGDDHDDDGDDDGDDxDHpwp????G( DHDDDHDDDDDDDDDD@DDDDDHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHDDD@DDDDDDHtGDHDDDDtG?DDDDDDDDDHDDDH0tagua-1.0-alpha2/lua/etc/lua.pc000066400000000000000000000012221077523320400162610ustar00rootroot00000000000000# lua.pc -- pkg-config data for Lua # vars from install Makefile # grep '^V=' ../Makefile V= 5.1 # grep '^R=' ../Makefile R= 5.1.2 # grep '^INSTALL_.*=' ../Makefile | sed 's/INSTALL_TOP/prefix/' prefix= /usr/local INSTALL_BIN= ${prefix}/bin INSTALL_INC= ${prefix}/include INSTALL_LIB= ${prefix}/lib INSTALL_MAN= ${prefix}/man/man1 INSTALL_LMOD= ${prefix}/share/lua/${V} INSTALL_CMOD= ${prefix}/lib/lua/${V} # canonical vars exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: Lua Description: An Extensible Extension Language Version: ${R} Requires: Libs: -L${libdir} -llua -lm Cflags: -I${includedir} # (end of lua.pc) tagua-1.0-alpha2/lua/etc/luavs.bat000066400000000000000000000013741077523320400170060ustar00rootroot00000000000000rem script to build Lua under "Visual Studio .NET Command Prompt". rem do not run it from this directory, run it from the toplevel: etc\luavs.bat rem it creates lua51.dll, lua51.lib, lua.exe, and luac.exe in src. cd src cl /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DLUA_BUILD_AS_DLL l*.c del lua.obj luac.obj link /DLL /out:lua51.dll l*.obj cl /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DLUA_BUILD_AS_DLL lua.c link /out:lua.exe lua.obj lua51.lib cl /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE l*.c print.c del lua.obj linit.obj lbaselib.obj ldblib.obj liolib.obj lmathlib.obj loslib.obj ltablib.obj lstrlib.obj loadlib.obj link /out:luac.exe *.obj del *.obj cd .. tagua-1.0-alpha2/lua/etc/min.c000066400000000000000000000014431077523320400161100ustar00rootroot00000000000000/* * min.c -- a minimal Lua interpreter * loads stdin only with minimal error handling. * no interaction, and no standard library, only a "print" function. */ #include #include "lua.h" #include "lauxlib.h" static int print(lua_State *L) { int n=lua_gettop(L); int i; for (i=1; i<=n; i++) { if (i>1) printf("\t"); if (lua_isstring(L,i)) printf("%s",lua_tostring(L,i)); else if (lua_isnil(L,i)==2) printf("%s","nil"); else if (lua_isboolean(L,i)) printf("%s",lua_toboolean(L,i) ? "true" : "false"); else printf("%s:%p",luaL_typename(L,i),lua_topointer(L,i)); } printf("\n"); return 0; } int main(void) { lua_State *L=lua_open(); lua_register(L,"print",print); if (luaL_dofile(L,NULL)!=0) fprintf(stderr,"%s\n",lua_tostring(L,-1)); lua_close(L); return 0; } tagua-1.0-alpha2/lua/etc/noparser.c000066400000000000000000000023451077523320400171600ustar00rootroot00000000000000/* * The code below can be used to make a Lua core that does not contain the * parsing modules (lcode, llex, lparser), which represent 35% of the total core. * You'll only be able to load binary files and strings, precompiled with luac. * (Of course, you'll have to build luac with the original parsing modules!) * * To use this module, simply compile it ("make noparser" does that) and list * its object file before the Lua libraries. The linker should then not load * the parsing modules. To try it, do "make luab". * * If you also want to avoid the dump module (ldump.o), define NODUMP. * #define NODUMP */ #define LUA_CORE #include "llex.h" #include "lparser.h" #include "lzio.h" LUAI_FUNC void luaX_init (lua_State *L) { UNUSED(L); } LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { UNUSED(z); UNUSED(buff); UNUSED(name); lua_pushliteral(L,"parser not loaded"); lua_error(L); return NULL; } #ifdef NODUMP #include "lundump.h" LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) { UNUSED(f); UNUSED(w); UNUSED(data); UNUSED(strip); #if 1 UNUSED(L); return 0; #else lua_pushliteral(L,"dumper not loaded"); lua_error(L); #endif } #endif tagua-1.0-alpha2/lua/etc/strict.lua000066400000000000000000000015311077523320400171720ustar00rootroot00000000000000-- -- strict.lua -- checks uses of undeclared global variables -- All global variables must be 'declared' through a regular assignment -- (even assigning nil will do) in a main chunk before being used -- anywhere or assigned to inside a function. -- local mt = getmetatable(_G) if mt == nil then mt = {} setmetatable(_G, mt) end mt.__declared = {} local function what () local d = debug.getinfo(3, "S") return d and d.what or "C" end mt.__newindex = function (t, n, v) if not mt.__declared[n] then local w = what() if w ~= "main" and w ~= "C" then error("assign to undeclared variable '"..n.."'", 2) end mt.__declared[n] = true end rawset(t, n, v) end mt.__index = function (t, n) if not mt.__declared[n] and what() ~= "C" then error("variable '"..n.."' is not declared", 2) end return rawget(t, n) end tagua-1.0-alpha2/lua/src/000077500000000000000000000000001077523320400151735ustar00rootroot00000000000000tagua-1.0-alpha2/lua/src/Makefile000066400000000000000000000137651077523320400166470ustar00rootroot00000000000000# makefile for building Lua # see ../INSTALL for installation instructions # see ../Makefile and luaconf.h for further customization # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= # Your platform. See PLATS for possible values. PLAT= none CC= gcc CFLAGS= -O2 -Wall $(MYCFLAGS) AR= ar rcu RANLIB= ranlib RM= rm -f LIBS= -lm $(MYLIBS) MYCFLAGS= MYLDFLAGS= MYLIBS= # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris LUA_A= liblua.a CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ lundump.o lvm.o lzio.o LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ lstrlib.o loadlib.o linit.o LUA_T= lua LUA_O= lua.o LUAC_T= luac LUAC_O= luac.o print.o ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O) ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) ALL_A= $(LUA_A) default: $(PLAT) all: $(ALL_T) o: $(ALL_O) a: $(ALL_A) $(LUA_A): $(CORE_O) $(LIB_O) $(AR) $@ $? $(RANLIB) $@ $(LUA_T): $(LUA_O) $(LUA_A) $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) $(LUAC_T): $(LUAC_O) $(LUA_A) $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) clean: $(RM) $(ALL_T) $(ALL_O) depend: @$(CC) $(CFLAGS) -MM l*.c print.c echo: @echo "PLAT = $(PLAT)" @echo "CC = $(CC)" @echo "CFLAGS = $(CFLAGS)" @echo "AR = $(AR)" @echo "RANLIB = $(RANLIB)" @echo "RM = $(RM)" @echo "MYCFLAGS = $(MYCFLAGS)" @echo "MYLDFLAGS = $(MYLDFLAGS)" @echo "MYLIBS = $(MYLIBS)" # convenience targets for popular platforms none: @echo "Please choose a platform:" @echo " $(PLATS)" aix: $(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" ansi: $(MAKE) all MYCFLAGS=-DLUA_ANSI bsd: $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" freebsd: $(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline" generic: $(MAKE) all MYCFLAGS= linux: $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" macosx: $(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX # use this on Mac OS X 10.4 # $(MAKE) all MYCFLAGS="-DLUA_USE_MACOSX -DLUA_USE_READLINE" MYLIBS="-lreadline" mingw: $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe $(MAKE) "LUAC_T=luac.exe" luac.exe posix: $(MAKE) all MYCFLAGS=-DLUA_USE_POSIX solaris: $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" # list targets that do not create files (but not all makes understand .PHONY) .PHONY: all $(PLATS) default o a clean depend echo none # DO NOT DELETE lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \ lstate.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h \ lundump.h lvm.h lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ ltable.h ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \ llex.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ lfunc.h lstring.h lgc.h ltable.h lvm.h ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h lstring.h \ ltable.h lundump.h lvm.h ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ lzio.h lmem.h lundump.h lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ lstate.h ltm.h lzio.h lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \ lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ ltm.h lzio.h lmem.h ldo.h loadlib.o: loadlib.c lauxlib.h lua.h luaconf.h lobject.h llimits.h \ lualib.h lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \ ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ lfunc.h lstring.h lgc.h ltable.h lstate.o: lstate.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h llex.h lstring.h ltable.h lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ ltm.h lzio.h lstring.h lgc.h lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ lmem.h lstring.h lgc.h ltable.h lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \ lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \ lundump.h lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \ llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ lzio.h print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \ ltm.h lzio.h lmem.h lopcodes.h lundump.h # (end of Makefile) tagua-1.0-alpha2/lua/src/lapi.c000066400000000000000000000537761077523320400163060ustar00rootroot00000000000000/* ** $Id: lapi.c,v 2.55 2006/06/07 12:37:17 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ #include #include #include #include #define lapi_c #define LUA_CORE #include "lua.h" #include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lundump.h" #include "lvm.h" const char lua_ident[] = "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n" "$Authors: " LUA_AUTHORS " $\n" "$URL: www.lua.org $\n"; #define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) #define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject) #define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} static TValue *index2adr (lua_State *L, int idx) { if (idx > 0) { TValue *o = L->base + (idx - 1); api_check(L, idx <= L->ci->top - L->base); if (o >= L->top) return cast(TValue *, luaO_nilobject); else return o; } else if (idx > LUA_REGISTRYINDEX) { api_check(L, idx != 0 && -idx <= L->top - L->base); return L->top + idx; } else switch (idx) { /* pseudo-indices */ case LUA_REGISTRYINDEX: return registry(L); case LUA_ENVIRONINDEX: { Closure *func = curr_func(L); sethvalue(L, &L->env, func->c.env); return &L->env; } case LUA_GLOBALSINDEX: return gt(L); default: { Closure *func = curr_func(L); idx = LUA_GLOBALSINDEX - idx; return (idx <= func->c.nupvalues) ? &func->c.upvalue[idx-1] : cast(TValue *, luaO_nilobject); } } } static Table *getcurrenv (lua_State *L) { if (L->ci == L->base_ci) /* no enclosing function? */ return hvalue(gt(L)); /* use global table as environment */ else { Closure *func = curr_func(L); return func->c.env; } } void luaA_pushobject (lua_State *L, const TValue *o) { setobj2s(L, L->top, o); api_incr_top(L); } LUA_API int lua_checkstack (lua_State *L, int size) { int res; lua_lock(L); if ((L->top - L->base + size) > LUAI_MAXCSTACK) res = 0; /* stack overflow */ else { luaD_checkstack(L, size); if (L->ci->top < L->top + size) L->ci->top = L->top + size; res = 1; } lua_unlock(L); return res; } LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { int i; if (from == to) return; lua_lock(to); api_checknelems(from, n); api_check(from, G(from) == G(to)); api_check(from, to->ci->top - to->top >= n); from->top -= n; for (i = 0; i < n; i++) { setobj2s(to, to->top++, from->top + i); } lua_unlock(to); } LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { lua_CFunction old; lua_lock(L); old = G(L)->panic; G(L)->panic = panicf; lua_unlock(L); return old; } LUA_API lua_State *lua_newthread (lua_State *L) { lua_State *L1; lua_lock(L); luaC_checkGC(L); L1 = luaE_newthread(L); setthvalue(L, L->top, L1); api_incr_top(L); lua_unlock(L); luai_userstatethread(L, L1); return L1; } /* ** basic stack manipulation */ LUA_API int lua_gettop (lua_State *L) { return cast_int(L->top - L->base); } LUA_API void lua_settop (lua_State *L, int idx) { lua_lock(L); if (idx >= 0) { api_check(L, idx <= L->stack_last - L->base); while (L->top < L->base + idx) setnilvalue(L->top++); L->top = L->base + idx; } else { api_check(L, -(idx+1) <= (L->top - L->base)); L->top += idx+1; /* `subtract' index (index is negative) */ } lua_unlock(L); } LUA_API void lua_remove (lua_State *L, int idx) { StkId p; lua_lock(L); p = index2adr(L, idx); api_checkvalidindex(L, p); while (++p < L->top) setobjs2s(L, p-1, p); L->top--; lua_unlock(L); } LUA_API void lua_insert (lua_State *L, int idx) { StkId p; StkId q; lua_lock(L); p = index2adr(L, idx); api_checkvalidindex(L, p); for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); setobjs2s(L, p, L->top); lua_unlock(L); } LUA_API void lua_replace (lua_State *L, int idx) { StkId o; lua_lock(L); /* explicit test for incompatible code */ if (idx == LUA_ENVIRONINDEX && L->ci == L->base_ci) luaG_runerror(L, "no calling environment"); api_checknelems(L, 1); o = index2adr(L, idx); api_checkvalidindex(L, o); if (idx == LUA_ENVIRONINDEX) { Closure *func = curr_func(L); api_check(L, ttistable(L->top - 1)); func->c.env = hvalue(L->top - 1); luaC_barrier(L, func, L->top - 1); } else { setobj(L, o, L->top - 1); if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ luaC_barrier(L, curr_func(L), L->top - 1); } L->top--; lua_unlock(L); } LUA_API void lua_pushvalue (lua_State *L, int idx) { lua_lock(L); setobj2s(L, L->top, index2adr(L, idx)); api_incr_top(L); lua_unlock(L); } /* ** access functions (stack -> C) */ LUA_API int lua_type (lua_State *L, int idx) { StkId o = index2adr(L, idx); return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); } LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); return (t == LUA_TNONE) ? "no value" : luaT_typenames[t]; } LUA_API int lua_iscfunction (lua_State *L, int idx) { StkId o = index2adr(L, idx); return iscfunction(o); } LUA_API int lua_isnumber (lua_State *L, int idx) { TValue n; const TValue *o = index2adr(L, idx); return tonumber(o, &n); } LUA_API int lua_isstring (lua_State *L, int idx) { int t = lua_type(L, idx); return (t == LUA_TSTRING || t == LUA_TNUMBER); } LUA_API int lua_isuserdata (lua_State *L, int idx) { const TValue *o = index2adr(L, idx); return (ttisuserdata(o) || ttislightuserdata(o)); } LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { StkId o1 = index2adr(L, index1); StkId o2 = index2adr(L, index2); return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : luaO_rawequalObj(o1, o2); } LUA_API int lua_equal (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ o1 = index2adr(L, index1); o2 = index2adr(L, index2); i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); lua_unlock(L); return i; } LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ o1 = index2adr(L, index1); o2 = index2adr(L, index2); i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : luaV_lessthan(L, o1, o2); lua_unlock(L); return i; } LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { TValue n; const TValue *o = index2adr(L, idx); if (tonumber(o, &n)) return nvalue(o); else return 0; } LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { TValue n; const TValue *o = index2adr(L, idx); if (tonumber(o, &n)) { lua_Integer res; lua_Number num = nvalue(o); lua_number2integer(res, num); return res; } else return 0; } LUA_API int lua_toboolean (lua_State *L, int idx) { const TValue *o = index2adr(L, idx); return !l_isfalse(o); } LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { StkId o = index2adr(L, idx); if (!ttisstring(o)) { lua_lock(L); /* `luaV_tostring' may create a new string */ if (!luaV_tostring(L, o)) { /* conversion failed? */ if (len != NULL) *len = 0; lua_unlock(L); return NULL; } luaC_checkGC(L); o = index2adr(L, idx); /* previous call may reallocate the stack */ lua_unlock(L); } if (len != NULL) *len = tsvalue(o)->len; return svalue(o); } LUA_API size_t lua_objlen (lua_State *L, int idx) { StkId o = index2adr(L, idx); switch (ttype(o)) { case LUA_TSTRING: return tsvalue(o)->len; case LUA_TUSERDATA: return uvalue(o)->len; case LUA_TTABLE: return luaH_getn(hvalue(o)); case LUA_TNUMBER: { size_t l; lua_lock(L); /* `luaV_tostring' may create a new string */ l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); lua_unlock(L); return l; } default: return 0; } } LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { StkId o = index2adr(L, idx); return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; } LUA_API void *lua_touserdata (lua_State *L, int idx) { StkId o = index2adr(L, idx); switch (ttype(o)) { case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } } LUA_API lua_State *lua_tothread (lua_State *L, int idx) { StkId o = index2adr(L, idx); return (!ttisthread(o)) ? NULL : thvalue(o); } LUA_API const void *lua_topointer (lua_State *L, int idx) { StkId o = index2adr(L, idx); switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); case LUA_TFUNCTION: return clvalue(o); case LUA_TTHREAD: return thvalue(o); case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: return lua_touserdata(L, idx); default: return NULL; } } /* ** push functions (C -> stack) */ LUA_API void lua_pushnil (lua_State *L) { lua_lock(L); setnilvalue(L->top); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { lua_lock(L); setnvalue(L->top, n); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { lua_lock(L); setnvalue(L->top, cast_num(n)); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { lua_lock(L); luaC_checkGC(L); setsvalue2s(L, L->top, luaS_newlstr(L, s, len)); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushstring (lua_State *L, const char *s) { if (s == NULL) lua_pushnil(L); else lua_pushlstring(L, s, strlen(s)); } LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp) { const char *ret; lua_lock(L); luaC_checkGC(L); ret = luaO_pushvfstring(L, fmt, argp); lua_unlock(L); return ret; } LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { const char *ret; va_list argp; lua_lock(L); luaC_checkGC(L); va_start(argp, fmt); ret = luaO_pushvfstring(L, fmt, argp); va_end(argp); lua_unlock(L); return ret; } LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { Closure *cl; lua_lock(L); luaC_checkGC(L); api_checknelems(L, n); cl = luaF_newCclosure(L, n, getcurrenv(L)); cl->c.f = fn; L->top -= n; while (n--) setobj2n(L, &cl->c.upvalue[n], L->top+n); setclvalue(L, L->top, cl); lua_assert(iswhite(obj2gco(cl))); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushboolean (lua_State *L, int b) { lua_lock(L); setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { lua_lock(L); setpvalue(L->top, p); api_incr_top(L); lua_unlock(L); } LUA_API int lua_pushthread (lua_State *L) { lua_lock(L); setthvalue(L, L->top, L); api_incr_top(L); lua_unlock(L); return (G(L)->mainthread == L); } /* ** get functions (Lua -> stack) */ LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2adr(L, idx); api_checkvalidindex(L, t); luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); } LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { StkId t; TValue key; lua_lock(L); t = index2adr(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); luaV_gettable(L, t, &key, L->top); api_incr_top(L); lua_unlock(L); } LUA_API void lua_rawget (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2adr(L, idx); api_check(L, ttistable(t)); setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); } LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); o = index2adr(L, idx); api_check(L, ttistable(o)); setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); api_incr_top(L); lua_unlock(L); } LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { lua_lock(L); luaC_checkGC(L); sethvalue(L, L->top, luaH_new(L, narray, nrec)); api_incr_top(L); lua_unlock(L); } LUA_API int lua_getmetatable (lua_State *L, int objindex) { const TValue *obj; Table *mt = NULL; int res; lua_lock(L); obj = index2adr(L, objindex); switch (ttype(obj)) { case LUA_TTABLE: mt = hvalue(obj)->metatable; break; case LUA_TUSERDATA: mt = uvalue(obj)->metatable; break; default: mt = G(L)->mt[ttype(obj)]; break; } if (mt == NULL) res = 0; else { sethvalue(L, L->top, mt); api_incr_top(L); res = 1; } lua_unlock(L); return res; } LUA_API void lua_getfenv (lua_State *L, int idx) { StkId o; lua_lock(L); o = index2adr(L, idx); api_checkvalidindex(L, o); switch (ttype(o)) { case LUA_TFUNCTION: sethvalue(L, L->top, clvalue(o)->c.env); break; case LUA_TUSERDATA: sethvalue(L, L->top, uvalue(o)->env); break; case LUA_TTHREAD: setobj2s(L, L->top, gt(thvalue(o))); break; default: setnilvalue(L->top); break; } api_incr_top(L); lua_unlock(L); } /* ** set functions (stack -> Lua) */ LUA_API void lua_settable (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); t = index2adr(L, idx); api_checkvalidindex(L, t); luaV_settable(L, t, L->top - 2, L->top - 1); L->top -= 2; /* pop index and value */ lua_unlock(L); } LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { StkId t; TValue key; lua_lock(L); api_checknelems(L, 1); t = index2adr(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); luaV_settable(L, t, &key, L->top - 1); L->top--; /* pop value */ lua_unlock(L); } LUA_API void lua_rawset (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); t = index2adr(L, idx); api_check(L, ttistable(t)); setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); luaC_barriert(L, hvalue(t), L->top-1); L->top -= 2; lua_unlock(L); } LUA_API void lua_rawseti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); api_checknelems(L, 1); o = index2adr(L, idx); api_check(L, ttistable(o)); setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); luaC_barriert(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); } LUA_API int lua_setmetatable (lua_State *L, int objindex) { TValue *obj; Table *mt; lua_lock(L); api_checknelems(L, 1); obj = index2adr(L, objindex); api_checkvalidindex(L, obj); if (ttisnil(L->top - 1)) mt = NULL; else { api_check(L, ttistable(L->top - 1)); mt = hvalue(L->top - 1); } switch (ttype(obj)) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; if (mt) luaC_objbarriert(L, hvalue(obj), mt); break; } case LUA_TUSERDATA: { uvalue(obj)->metatable = mt; if (mt) luaC_objbarrier(L, rawuvalue(obj), mt); break; } default: { G(L)->mt[ttype(obj)] = mt; break; } } L->top--; lua_unlock(L); return 1; } LUA_API int lua_setfenv (lua_State *L, int idx) { StkId o; int res = 1; lua_lock(L); api_checknelems(L, 1); o = index2adr(L, idx); api_checkvalidindex(L, o); api_check(L, ttistable(L->top - 1)); switch (ttype(o)) { case LUA_TFUNCTION: clvalue(o)->c.env = hvalue(L->top - 1); break; case LUA_TUSERDATA: uvalue(o)->env = hvalue(L->top - 1); break; case LUA_TTHREAD: sethvalue(L, gt(thvalue(o)), hvalue(L->top - 1)); break; default: res = 0; break; } luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); L->top--; lua_unlock(L); return res; } /* ** `load' and `call' functions (run Lua code) */ #define adjustresults(L,nres) \ { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; } #define checkresults(L,na,nr) \ api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na))) LUA_API void lua_call (lua_State *L, int nargs, int nresults) { StkId func; lua_lock(L); api_checknelems(L, nargs+1); checkresults(L, nargs, nresults); func = L->top - (nargs+1); luaD_call(L, func, nresults); adjustresults(L, nresults); lua_unlock(L); } /* ** Execute a protected call. */ struct CallS { /* data to `f_call' */ StkId func; int nresults; }; static void f_call (lua_State *L, void *ud) { struct CallS *c = cast(struct CallS *, ud); luaD_call(L, c->func, c->nresults); } LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { struct CallS c; int status; ptrdiff_t func; lua_lock(L); api_checknelems(L, nargs+1); checkresults(L, nargs, nresults); if (errfunc == 0) func = 0; else { StkId o = index2adr(L, errfunc); api_checkvalidindex(L, o); func = savestack(L, o); } c.func = L->top - (nargs+1); /* function to be called */ c.nresults = nresults; status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); adjustresults(L, nresults); lua_unlock(L); return status; } /* ** Execute a protected C call. */ struct CCallS { /* data to `f_Ccall' */ lua_CFunction func; void *ud; }; static void f_Ccall (lua_State *L, void *ud) { struct CCallS *c = cast(struct CCallS *, ud); Closure *cl; cl = luaF_newCclosure(L, 0, getcurrenv(L)); cl->c.f = c->func; setclvalue(L, L->top, cl); /* push function */ api_incr_top(L); setpvalue(L->top, c->ud); /* push only argument */ api_incr_top(L); luaD_call(L, L->top - 2, 0); } LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { struct CCallS c; int status; lua_lock(L); c.func = func; c.ud = ud; status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0); lua_unlock(L); return status; } LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *chunkname) { ZIO z; int status; lua_lock(L); if (!chunkname) chunkname = "?"; luaZ_init(L, &z, reader, data); status = luaD_protectedparser(L, &z, chunkname); lua_unlock(L); return status; } LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { int status; TValue *o; lua_lock(L); api_checknelems(L, 1); o = L->top - 1; if (isLfunction(o)) status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0); else status = 1; lua_unlock(L); return status; } LUA_API int lua_status (lua_State *L) { return L->status; } /* ** Garbage-collection function */ LUA_API int lua_gc (lua_State *L, int what, int data) { int res = 0; global_State *g; lua_lock(L); g = G(L); switch (what) { case LUA_GCSTOP: { g->GCthreshold = MAX_LUMEM; break; } case LUA_GCRESTART: { g->GCthreshold = g->totalbytes; break; } case LUA_GCCOLLECT: { luaC_fullgc(L); break; } case LUA_GCCOUNT: { /* GC values are expressed in Kbytes: #bytes/2^10 */ res = cast_int(g->totalbytes >> 10); break; } case LUA_GCCOUNTB: { res = cast_int(g->totalbytes & 0x3ff); break; } case LUA_GCSTEP: { lu_mem a = (cast(lu_mem, data) << 10); if (a <= g->totalbytes) g->GCthreshold = g->totalbytes - a; else g->GCthreshold = 0; while (g->GCthreshold <= g->totalbytes) luaC_step(L); if (g->gcstate == GCSpause) /* end of cycle? */ res = 1; /* signal it */ break; } case LUA_GCSETPAUSE: { res = g->gcpause; g->gcpause = data; break; } case LUA_GCSETSTEPMUL: { res = g->gcstepmul; g->gcstepmul = data; break; } default: res = -1; /* invalid option */ } lua_unlock(L); return res; } /* ** miscellaneous functions */ LUA_API int lua_error (lua_State *L) { lua_lock(L); api_checknelems(L, 1); luaG_errormsg(L); lua_unlock(L); return 0; /* to avoid warnings */ } LUA_API int lua_next (lua_State *L, int idx) { StkId t; int more; lua_lock(L); t = index2adr(L, idx); api_check(L, ttistable(t)); more = luaH_next(L, hvalue(t), L->top - 1); if (more) { api_incr_top(L); } else /* no more elements */ L->top -= 1; /* remove key */ lua_unlock(L); return more; } LUA_API void lua_concat (lua_State *L, int n) { lua_lock(L); api_checknelems(L, n); if (n >= 2) { luaC_checkGC(L); luaV_concat(L, n, cast_int(L->top - L->base) - 1); L->top -= (n-1); } else if (n == 0) { /* push empty string */ setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); api_incr_top(L); } /* else n == 1; nothing to do */ lua_unlock(L); } LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { lua_Alloc f; lua_lock(L); if (ud) *ud = G(L)->ud; f = G(L)->frealloc; lua_unlock(L); return f; } LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { lua_lock(L); G(L)->ud = ud; G(L)->frealloc = f; lua_unlock(L); } LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); luaC_checkGC(L); u = luaS_newudata(L, size, getcurrenv(L)); setuvalue(L, L->top, u); api_incr_top(L); lua_unlock(L); return u + 1; } static const char *aux_upvalue (StkId fi, int n, TValue **val) { Closure *f; if (!ttisfunction(fi)) return NULL; f = clvalue(fi); if (f->c.isC) { if (!(1 <= n && n <= f->c.nupvalues)) return NULL; *val = &f->c.upvalue[n-1]; return ""; } else { Proto *p = f->l.p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->l.upvals[n-1]->v; return getstr(p->upvalues[n-1]); } } LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; lua_lock(L); name = aux_upvalue(index2adr(L, funcindex), n, &val); if (name) { setobj2s(L, L->top, val); api_incr_top(L); } lua_unlock(L); return name; } LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; StkId fi; lua_lock(L); fi = index2adr(L, funcindex); api_checknelems(L, 1); name = aux_upvalue(fi, n, &val); if (name) { L->top--; setobj(L, val, L->top); luaC_barrier(L, clvalue(fi), L->top); } lua_unlock(L); return name; } tagua-1.0-alpha2/lua/src/lapi.h000066400000000000000000000004021077523320400162650ustar00rootroot00000000000000/* ** $Id: lapi.h,v 2.2 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ #ifndef lapi_h #define lapi_h #include "lobject.h" LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o); #endif tagua-1.0-alpha2/lua/src/lauxlib.c000066400000000000000000000420331077523320400170010ustar00rootroot00000000000000/* ** $Id: lauxlib.c,v 1.159 2006/03/21 19:31:09 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ #include #include #include #include #include #include /* This file uses only the official API of Lua. ** Any function declared here could be written as an application function. */ #define lauxlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #define FREELIST_REF 0 /* free list of references */ /* convert a stack index to positive */ #define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ lua_gettop(L) + (i) + 1) /* ** {====================================================== ** Error-report functions ** ======================================================= */ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { lua_Debug ar; if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); lua_getinfo(L, "n", &ar); if (strcmp(ar.namewhat, "method") == 0) { narg--; /* do not count `self' */ if (narg == 0) /* error is in the self argument itself? */ return luaL_error(L, "calling " LUA_QS " on bad self (%s)", ar.name, extramsg); } if (ar.name == NULL) ar.name = "?"; return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", narg, ar.name, extramsg); } LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, luaL_typename(L, narg)); return luaL_argerror(L, narg, msg); } static void tag_error (lua_State *L, int narg, int tag) { luaL_typerror(L, narg, lua_typename(L, tag)); } LUALIB_API void luaL_where (lua_State *L, int level) { lua_Debug ar; if (lua_getstack(L, level, &ar)) { /* check function at level */ lua_getinfo(L, "Sl", &ar); /* get info about it */ if (ar.currentline > 0) { /* is there info? */ lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); return; } } lua_pushliteral(L, ""); /* else, no information available... */ } LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); luaL_where(L, 1); lua_pushvfstring(L, fmt, argp); va_end(argp); lua_concat(L, 2); return lua_error(L); } /* }====================================================== */ LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) { const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg); int i; for (i=0; lst[i]; i++) if (strcmp(lst[i], name) == 0) return i; return luaL_argerror(L, narg, lua_pushfstring(L, "invalid option " LUA_QS, name)); } LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ if (!lua_isnil(L, -1)) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ lua_pop(L, 1); lua_newtable(L); /* create metatable */ lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ return 1; } LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { void *p = lua_touserdata(L, ud); if (p != NULL) { /* value is a userdata? */ if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ lua_pop(L, 2); /* remove both metatables */ return p; } } } luaL_typerror(L, ud, tname); /* else error */ return NULL; /* to avoid warnings */ } LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { if (!lua_checkstack(L, space)) luaL_error(L, "stack overflow (%s)", mes); } LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { if (lua_type(L, narg) != t) tag_error(L, narg, t); } LUALIB_API void luaL_checkany (lua_State *L, int narg) { if (lua_type(L, narg) == LUA_TNONE) luaL_argerror(L, narg, "value expected"); } LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { const char *s = lua_tolstring(L, narg, len); if (!s) tag_error(L, narg, LUA_TSTRING); return s; } LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, const char *def, size_t *len) { if (lua_isnoneornil(L, narg)) { if (len) *len = (def ? strlen(def) : 0); return def; } else return luaL_checklstring(L, narg, len); } LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { lua_Number d = lua_tonumber(L, narg); if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ tag_error(L, narg, LUA_TNUMBER); return d; } LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { return luaL_opt(L, luaL_checknumber, narg, def); } LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { lua_Integer d = lua_tointeger(L, narg); if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ tag_error(L, narg, LUA_TNUMBER); return d; } LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, lua_Integer def) { return luaL_opt(L, luaL_checkinteger, narg, def); } LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { if (!lua_getmetatable(L, obj)) /* no metatable? */ return 0; lua_pushstring(L, event); lua_rawget(L, -2); if (lua_isnil(L, -1)) { lua_pop(L, 2); /* remove metatable and metafield */ return 0; } else { lua_remove(L, -2); /* remove only metatable */ return 1; } } LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { obj = abs_index(L, obj); if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ return 0; lua_pushvalue(L, obj); lua_call(L, 1, 1); return 1; } LUALIB_API void (luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l) { luaI_openlib(L, libname, l, 0); } static int libsize (const luaL_Reg *l) { int size = 0; for (; l->name; l++) size++; return size; } LUALIB_API void luaI_openlib (lua_State *L, const char *libname, const luaL_Reg *l, int nup) { if (libname) { int size = libsize(l); /* check whether lib already exists */ luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size); lua_getfield(L, -1, libname); /* get _LOADED[libname] */ if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) luaL_error(L, "name conflict for module " LUA_QS, libname); lua_pushvalue(L, -1); lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ } lua_remove(L, -2); /* remove _LOADED table */ lua_insert(L, -(nup+1)); /* move library table to below upvalues */ } for (; l->name; l++) { int i; for (i=0; ifunc, nup); lua_setfield(L, -(nup+2), l->name); } lua_pop(L, nup); /* remove upvalues */ } /* ** {====================================================== ** getn-setn: size for arrays ** ======================================================= */ #if defined(LUA_COMPAT_GETN) static int checkint (lua_State *L, int topop) { int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; lua_pop(L, topop); return n; } static void getsizes (lua_State *L) { lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); if (lua_isnil(L, -1)) { /* no `size' table? */ lua_pop(L, 1); /* remove nil */ lua_newtable(L); /* create it */ lua_pushvalue(L, -1); /* `size' will be its own metatable */ lua_setmetatable(L, -2); lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */ lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); /* store in register */ } } LUALIB_API void luaL_setn (lua_State *L, int t, int n) { t = abs_index(L, t); lua_pushliteral(L, "n"); lua_rawget(L, t); if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ lua_pushliteral(L, "n"); /* use it */ lua_pushinteger(L, n); lua_rawset(L, t); } else { /* use `sizes' */ getsizes(L); lua_pushvalue(L, t); lua_pushinteger(L, n); lua_rawset(L, -3); /* sizes[t] = n */ lua_pop(L, 1); /* remove `sizes' */ } } LUALIB_API int luaL_getn (lua_State *L, int t) { int n; t = abs_index(L, t); lua_pushliteral(L, "n"); /* try t.n */ lua_rawget(L, t); if ((n = checkint(L, 1)) >= 0) return n; getsizes(L); /* else try sizes[t] */ lua_pushvalue(L, t); lua_rawget(L, -2); if ((n = checkint(L, 2)) >= 0) return n; return (int)lua_objlen(L, t); } #endif /* }====================================================== */ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, const char *r) { const char *wild; size_t l = strlen(p); luaL_Buffer b; luaL_buffinit(L, &b); while ((wild = strstr(s, p)) != NULL) { luaL_addlstring(&b, s, wild - s); /* push prefix */ luaL_addstring(&b, r); /* push replacement in place of pattern */ s = wild + l; /* continue after `p' */ } luaL_addstring(&b, s); /* push last suffix */ luaL_pushresult(&b); return lua_tostring(L, -1); } LUALIB_API const char *luaL_findtable (lua_State *L, int idx, const char *fname, int szhint) { const char *e; lua_pushvalue(L, idx); do { e = strchr(fname, '.'); if (e == NULL) e = fname + strlen(fname); lua_pushlstring(L, fname, e - fname); lua_rawget(L, -2); if (lua_isnil(L, -1)) { /* no such field? */ lua_pop(L, 1); /* remove this nil */ lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ lua_pushlstring(L, fname, e - fname); lua_pushvalue(L, -2); lua_settable(L, -4); /* set new table into field */ } else if (!lua_istable(L, -1)) { /* field has a non-table value? */ lua_pop(L, 2); /* remove table and value */ return fname; /* return problematic part of the name */ } lua_remove(L, -2); /* remove previous table */ fname = e + 1; } while (*e == '.'); return NULL; } /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ #define bufflen(B) ((B)->p - (B)->buffer) #define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) #define LIMIT (LUA_MINSTACK/2) static int emptybuffer (luaL_Buffer *B) { size_t l = bufflen(B); if (l == 0) return 0; /* put nothing on stack */ else { lua_pushlstring(B->L, B->buffer, l); B->p = B->buffer; B->lvl++; return 1; } } static void adjuststack (luaL_Buffer *B) { if (B->lvl > 1) { lua_State *L = B->L; int toget = 1; /* number of levels to concat */ size_t toplen = lua_strlen(L, -1); do { size_t l = lua_strlen(L, -(toget+1)); if (B->lvl - toget + 1 >= LIMIT || toplen > l) { toplen += l; toget++; } else break; } while (toget < B->lvl); lua_concat(L, toget); B->lvl = B->lvl - toget + 1; } } LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { if (emptybuffer(B)) adjuststack(B); return B->buffer; } LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { while (l--) luaL_addchar(B, *s++); } LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { luaL_addlstring(B, s, strlen(s)); } LUALIB_API void luaL_pushresult (luaL_Buffer *B) { emptybuffer(B); lua_concat(B->L, B->lvl); B->lvl = 1; } LUALIB_API void luaL_addvalue (luaL_Buffer *B) { lua_State *L = B->L; size_t vl; const char *s = lua_tolstring(L, -1, &vl); if (vl <= bufffree(B)) { /* fit into buffer? */ memcpy(B->p, s, vl); /* put it there */ B->p += vl; lua_pop(L, 1); /* remove from stack */ } else { if (emptybuffer(B)) lua_insert(L, -2); /* put buffer before new value */ B->lvl++; /* add new value into B stack */ adjuststack(B); } } LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { B->L = L; B->p = B->buffer; B->lvl = 0; } /* }====================================================== */ LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; t = abs_index(L, t); if (lua_isnil(L, -1)) { lua_pop(L, 1); /* remove from stack */ return LUA_REFNIL; /* `nil' has a unique fixed reference */ } lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ lua_pop(L, 1); /* remove it from stack */ if (ref != 0) { /* any free element? */ lua_rawgeti(L, t, ref); /* remove it from list */ lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ } else { /* no free elements */ ref = (int)lua_objlen(L, t); ref++; /* create new reference */ } lua_rawseti(L, t, ref); return ref; } LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { if (ref >= 0) { t = abs_index(L, t); lua_rawgeti(L, t, FREELIST_REF); lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ lua_pushinteger(L, ref); lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ } } /* ** {====================================================== ** Load functions ** ======================================================= */ typedef struct LoadF { int extraline; FILE *f; char buff[LUAL_BUFFERSIZE]; } LoadF; static const char *getF (lua_State *L, void *ud, size_t *size) { LoadF *lf = (LoadF *)ud; (void)L; if (lf->extraline) { lf->extraline = 0; *size = 1; return "\n"; } if (feof(lf->f)) return NULL; *size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f); return (*size > 0) ? lf->buff : NULL; } static int errfile (lua_State *L, const char *what, int fnameindex) { const char *serr = strerror(errno); const char *filename = lua_tostring(L, fnameindex) + 1; lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); lua_remove(L, fnameindex); return LUA_ERRFILE; } LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { LoadF lf; int status, readstatus; int c; int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ lf.extraline = 0; if (filename == NULL) { lua_pushliteral(L, "=stdin"); lf.f = stdin; } else { lua_pushfstring(L, "@%s", filename); lf.f = fopen(filename, "r"); if (lf.f == NULL) return errfile(L, "open", fnameindex); } c = getc(lf.f); if (c == '#') { /* Unix exec. file? */ lf.extraline = 1; while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ if (c == '\n') c = getc(lf.f); } if (c == LUA_SIGNATURE[0] && lf.f != stdin) { /* binary file? */ fclose(lf.f); lf.f = fopen(filename, "rb"); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); /* skip eventual `#!...' */ while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; lf.extraline = 0; } ungetc(c, lf.f); status = lua_load(L, getF, &lf, lua_tostring(L, -1)); readstatus = ferror(lf.f); if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */ if (readstatus) { lua_settop(L, fnameindex); /* ignore results from `lua_load' */ return errfile(L, "read", fnameindex); } lua_remove(L, fnameindex); return status; } typedef struct LoadS { const char *s; size_t size; } LoadS; static const char *getS (lua_State *L, void *ud, size_t *size) { LoadS *ls = (LoadS *)ud; (void)L; if (ls->size == 0) return NULL; *size = ls->size; ls->size = 0; return ls->s; } LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, const char *name) { LoadS ls; ls.s = buff; ls.size = size; return lua_load(L, getS, &ls, name); } LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) { return luaL_loadbuffer(L, s, strlen(s), s); } /* }====================================================== */ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; if (nsize == 0) { free(ptr); return NULL; } else return realloc(ptr, nsize); } static int panic (lua_State *L) { (void)L; /* to avoid warnings */ fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)); return 0; } LUALIB_API lua_State *luaL_newstate (void) { lua_State *L = lua_newstate(l_alloc, NULL); if (L) lua_atpanic(L, &panic); return L; } tagua-1.0-alpha2/lua/src/lauxlib.h000066400000000000000000000132151077523320400170060ustar00rootroot00000000000000/* ** $Id: lauxlib.h,v 1.88 2006/04/12 20:31:15 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ #ifndef lauxlib_h #define lauxlib_h #include #include #include "lua.h" #if defined(LUA_COMPAT_GETN) LUALIB_API int (luaL_getn) (lua_State *L, int t); LUALIB_API void (luaL_setn) (lua_State *L, int t, int n); #else #define luaL_getn(L,i) ((int)lua_objlen(L, i)) #define luaL_setn(L,i,j) ((void)0) /* no op! */ #endif #if defined(LUA_COMPAT_OPENLIB) #define luaI_openlib luaL_openlib #endif /* extra error code for `luaL_load' */ #define LUA_ERRFILE (LUA_ERRERR+1) typedef struct luaL_Reg { const char *name; lua_CFunction func; } luaL_Reg; LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname, const luaL_Reg *l, int nup); LUALIB_API void (luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l); LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, size_t *l); LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, const char *def, size_t *l); LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, lua_Integer def); LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); LUALIB_API void (luaL_checkany) (lua_State *L, int narg); LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); LUALIB_API void (luaL_where) (lua_State *L, int lvl); LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, const char *const lst[]); LUALIB_API int (luaL_ref) (lua_State *L, int t); LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name); LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, const char *fname, int szhint); /* ** =============================================================== ** some useful macros ** =============================================================== */ #define luaL_argcheck(L, cond,numarg,extramsg) \ ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) #define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) #define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) #define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) #define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) #define luaL_dofile(L, fn) \ (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) #define luaL_dostring(L, s) \ (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) #define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ typedef struct luaL_Buffer { char *p; /* current position in buffer */ int lvl; /* number of strings in the stack (level) */ lua_State *L; char buffer[LUAL_BUFFERSIZE]; } luaL_Buffer; #define luaL_addchar(B,c) \ ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ (*(B)->p++ = (char)(c))) /* compatibility only */ #define luaL_putchar(B,c) luaL_addchar(B,c) #define luaL_addsize(B,n) ((B)->p += (n)) LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); /* }====================================================== */ /* compatibility with ref system */ /* pre-defined references */ #define LUA_NOREF (-2) #define LUA_REFNIL (-1) #define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) #define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) #define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) #define luaL_reg luaL_Reg #endif tagua-1.0-alpha2/lua/src/lbaselib.c000066400000000000000000000404721077523320400171230ustar00rootroot00000000000000/* ** $Id: lbaselib.c,v 1.191a 2006/06/02 15:34:00 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ #include #include #include #include #define lbaselib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** If your system does not support `stdout', you can just remove this function. ** If you need, you can define your own `print' function, following this ** model but changing `fputs' to put the strings at a proper place ** (a console window or a log file, for instance). */ static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; lua_getglobal(L, "tostring"); for (i=1; i<=n; i++) { const char *s; lua_pushvalue(L, -1); /* function to be called */ lua_pushvalue(L, i); /* value to print */ lua_call(L, 1, 1); s = lua_tostring(L, -1); /* get result */ if (s == NULL) return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print")); if (i>1) fputs("\t", stdout); fputs(s, stdout); lua_pop(L, 1); /* pop result */ } fputs("\n", stdout); return 0; } static int luaB_tonumber (lua_State *L) { int base = luaL_optint(L, 2, 10); if (base == 10) { /* standard conversion */ luaL_checkany(L, 1); if (lua_isnumber(L, 1)) { lua_pushnumber(L, lua_tonumber(L, 1)); return 1; } } else { const char *s1 = luaL_checkstring(L, 1); char *s2; unsigned long n; luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); n = strtoul(s1, &s2, base); if (s1 != s2) { /* at least one valid digit? */ while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */ if (*s2 == '\0') { /* no invalid trailing characters? */ lua_pushnumber(L, (lua_Number)n); return 1; } } } lua_pushnil(L); /* else not a number */ return 1; } static int luaB_error (lua_State *L) { int level = luaL_optint(L, 2, 1); lua_settop(L, 1); if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ luaL_where(L, level); lua_pushvalue(L, 1); lua_concat(L, 2); } return lua_error(L); } static int luaB_getmetatable (lua_State *L) { luaL_checkany(L, 1); if (!lua_getmetatable(L, 1)) { lua_pushnil(L); return 1; /* no metatable */ } luaL_getmetafield(L, 1, "__metatable"); return 1; /* returns either __metatable field (if present) or metatable */ } static int luaB_setmetatable (lua_State *L) { int t = lua_type(L, 2); luaL_checktype(L, 1, LUA_TTABLE); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); if (luaL_getmetafield(L, 1, "__metatable")) luaL_error(L, "cannot change a protected metatable"); lua_settop(L, 2); lua_setmetatable(L, 1); return 1; } static void getfunc (lua_State *L, int opt) { if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); else { lua_Debug ar; int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); if (lua_getstack(L, level, &ar) == 0) luaL_argerror(L, 1, "invalid level"); lua_getinfo(L, "f", &ar); if (lua_isnil(L, -1)) luaL_error(L, "no function environment for tail call at level %d", level); } } static int luaB_getfenv (lua_State *L) { getfunc(L, 1); if (lua_iscfunction(L, -1)) /* is a C function? */ lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ else lua_getfenv(L, -1); return 1; } static int luaB_setfenv (lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); getfunc(L, 0); lua_pushvalue(L, 2); if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { /* change environment of current thread */ lua_pushthread(L); lua_insert(L, -2); lua_setfenv(L, -2); return 0; } else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) luaL_error(L, LUA_QL("setfenv") " cannot change environment of given object"); return 1; } static int luaB_rawequal (lua_State *L) { luaL_checkany(L, 1); luaL_checkany(L, 2); lua_pushboolean(L, lua_rawequal(L, 1, 2)); return 1; } static int luaB_rawget (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); lua_settop(L, 2); lua_rawget(L, 1); return 1; } static int luaB_rawset (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); luaL_checkany(L, 3); lua_settop(L, 3); lua_rawset(L, 1); return 1; } static int luaB_gcinfo (lua_State *L) { lua_pushinteger(L, lua_getgccount(L)); return 1; } static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", "count", "step", "setpause", "setstepmul", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; int o = luaL_checkoption(L, 1, "collect", opts); int ex = luaL_optint(L, 2, 0); int res = lua_gc(L, optsnum[o], ex); switch (optsnum[o]) { case LUA_GCCOUNT: { int b = lua_gc(L, LUA_GCCOUNTB, 0); lua_pushnumber(L, res + ((lua_Number)b/1024)); return 1; } case LUA_GCSTEP: { lua_pushboolean(L, res); return 1; } default: { lua_pushnumber(L, res); return 1; } } } static int luaB_type (lua_State *L) { luaL_checkany(L, 1); lua_pushstring(L, luaL_typename(L, 1)); return 1; } static int luaB_next (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 2); /* create a 2nd argument if there isn't one */ if (lua_next(L, 1)) return 2; else { lua_pushnil(L); return 1; } } static int luaB_pairs (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ lua_pushvalue(L, 1); /* state, */ lua_pushnil(L); /* and initial value */ return 3; } static int ipairsaux (lua_State *L) { int i = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TTABLE); i++; /* next value */ lua_pushinteger(L, i); lua_rawgeti(L, 1, i); return (lua_isnil(L, -1)) ? 0 : 2; } static int luaB_ipairs (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ lua_pushvalue(L, 1); /* state, */ lua_pushinteger(L, 0); /* and initial value */ return 3; } static int load_aux (lua_State *L, int status) { if (status == 0) /* OK? */ return 1; else { lua_pushnil(L); lua_insert(L, -2); /* put before error message */ return 2; /* return nil plus error message */ } } static int luaB_loadstring (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); const char *chunkname = luaL_optstring(L, 2, s); return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); } static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); return load_aux(L, luaL_loadfile(L, fname)); } /* ** Reader for generic `load' function: `lua_load' uses the ** stack for internal stuff, so the reader cannot change the ** stack top. Instead, it keeps its resulting string in a ** reserved slot inside the stack. */ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { (void)ud; /* to avoid warnings */ luaL_checkstack(L, 2, "too many nested functions"); lua_pushvalue(L, 1); /* get function */ lua_call(L, 0, 1); /* call it */ if (lua_isnil(L, -1)) { *size = 0; return NULL; } else if (lua_isstring(L, -1)) { lua_replace(L, 3); /* save string in a reserved stack slot */ return lua_tolstring(L, 3, size); } else luaL_error(L, "reader function must return a string"); return NULL; /* to avoid warnings */ } static int luaB_load (lua_State *L) { int status; const char *cname = luaL_optstring(L, 2, "=(load)"); luaL_checktype(L, 1, LUA_TFUNCTION); lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ status = lua_load(L, generic_reader, NULL, cname); return load_aux(L, status); } static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); int n = lua_gettop(L); if (luaL_loadfile(L, fname) != 0) lua_error(L); lua_call(L, 0, LUA_MULTRET); return lua_gettop(L) - n; } static int luaB_assert (lua_State *L) { luaL_checkany(L, 1); if (!lua_toboolean(L, 1)) return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); return lua_gettop(L); } static int luaB_unpack (lua_State *L) { int i, e, n; luaL_checktype(L, 1, LUA_TTABLE); i = luaL_optint(L, 2, 1); e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); n = e - i + 1; /* number of elements */ if (n <= 0) return 0; /* empty range */ luaL_checkstack(L, n, "table too big to unpack"); for (; i<=e; i++) /* push arg[i...e] */ lua_rawgeti(L, 1, i); return n; } static int luaB_select (lua_State *L) { int n = lua_gettop(L); if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { lua_pushinteger(L, n-1); return 1; } else { int i = luaL_checkint(L, 1); if (i < 0) i = n + i; else if (i > n) i = n; luaL_argcheck(L, 1 <= i, 1, "index out of range"); return n - i; } } static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); lua_pushboolean(L, (status == 0)); lua_insert(L, 1); return lua_gettop(L); /* return status + all results */ } static int luaB_xpcall (lua_State *L) { int status; luaL_checkany(L, 2); lua_settop(L, 2); lua_insert(L, 1); /* put error function under function to be called */ status = lua_pcall(L, 0, LUA_MULTRET, 1); lua_pushboolean(L, (status == 0)); lua_replace(L, 1); return lua_gettop(L); /* return status + all results */ } static int luaB_tostring (lua_State *L) { luaL_checkany(L, 1); if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ return 1; /* use its value */ switch (lua_type(L, 1)) { case LUA_TNUMBER: lua_pushstring(L, lua_tostring(L, 1)); break; case LUA_TSTRING: lua_pushvalue(L, 1); break; case LUA_TBOOLEAN: lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); break; case LUA_TNIL: lua_pushliteral(L, "nil"); break; default: lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); break; } return 1; } static int luaB_newproxy (lua_State *L) { lua_settop(L, 1); lua_newuserdata(L, 0); /* create proxy */ if (lua_toboolean(L, 1) == 0) return 1; /* no metatable */ else if (lua_isboolean(L, 1)) { lua_newtable(L); /* create a new metatable `m' ... */ lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */ lua_pushboolean(L, 1); lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */ } else { int validproxy = 0; /* to check if weaktable[metatable(u)] == true */ if (lua_getmetatable(L, 1)) { lua_rawget(L, lua_upvalueindex(1)); validproxy = lua_toboolean(L, -1); lua_pop(L, 1); /* remove value */ } luaL_argcheck(L, validproxy, 1, "boolean or proxy expected"); lua_getmetatable(L, 1); /* metatable is valid; get it */ } lua_setmetatable(L, 2); return 1; } static const luaL_Reg base_funcs[] = { {"assert", luaB_assert}, {"collectgarbage", luaB_collectgarbage}, {"dofile", luaB_dofile}, {"error", luaB_error}, {"gcinfo", luaB_gcinfo}, {"getfenv", luaB_getfenv}, {"getmetatable", luaB_getmetatable}, {"loadfile", luaB_loadfile}, {"load", luaB_load}, {"loadstring", luaB_loadstring}, {"next", luaB_next}, {"pcall", luaB_pcall}, {"print", luaB_print}, {"rawequal", luaB_rawequal}, {"rawget", luaB_rawget}, {"rawset", luaB_rawset}, {"select", luaB_select}, {"setfenv", luaB_setfenv}, {"setmetatable", luaB_setmetatable}, {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, {"unpack", luaB_unpack}, {"xpcall", luaB_xpcall}, {NULL, NULL} }; /* ** {====================================================== ** Coroutine library ** ======================================================= */ static int auxresume (lua_State *L, lua_State *co, int narg) { int status; if (!lua_checkstack(co, narg)) luaL_error(L, "too many arguments to resume"); if (lua_status(co) == 0 && lua_gettop(co) == 0) { lua_pushliteral(L, "cannot resume dead coroutine"); return -1; /* error flag */ } lua_xmove(L, co, narg); status = lua_resume(co, narg); if (status == 0 || status == LUA_YIELD) { int nres = lua_gettop(co); if (!lua_checkstack(L, nres)) luaL_error(L, "too many results to resume"); lua_xmove(co, L, nres); /* move yielded values */ return nres; } else { lua_xmove(co, L, 1); /* move error message */ return -1; /* error flag */ } } static int luaB_coresume (lua_State *L) { lua_State *co = lua_tothread(L, 1); int r; luaL_argcheck(L, co, 1, "coroutine expected"); r = auxresume(L, co, lua_gettop(L) - 1); if (r < 0) { lua_pushboolean(L, 0); lua_insert(L, -2); return 2; /* return false + error message */ } else { lua_pushboolean(L, 1); lua_insert(L, -(r + 1)); return r + 1; /* return true + `resume' returns */ } } static int luaB_auxwrap (lua_State *L) { lua_State *co = lua_tothread(L, lua_upvalueindex(1)); int r = auxresume(L, co, lua_gettop(L)); if (r < 0) { if (lua_isstring(L, -1)) { /* error object is a string? */ luaL_where(L, 1); /* add extra info */ lua_insert(L, -2); lua_concat(L, 2); } lua_error(L); /* propagate error */ } return r; } static int luaB_cocreate (lua_State *L) { lua_State *NL = lua_newthread(L); luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, "Lua function expected"); lua_pushvalue(L, 1); /* move function to top */ lua_xmove(L, NL, 1); /* move function from L to NL */ return 1; } static int luaB_cowrap (lua_State *L) { luaB_cocreate(L); lua_pushcclosure(L, luaB_auxwrap, 1); return 1; } static int luaB_yield (lua_State *L) { return lua_yield(L, lua_gettop(L)); } static int luaB_costatus (lua_State *L) { lua_State *co = lua_tothread(L, 1); luaL_argcheck(L, co, 1, "coroutine expected"); if (L == co) lua_pushliteral(L, "running"); else { switch (lua_status(co)) { case LUA_YIELD: lua_pushliteral(L, "suspended"); break; case 0: { lua_Debug ar; if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ lua_pushliteral(L, "normal"); /* it is running */ else if (lua_gettop(co) == 0) lua_pushliteral(L, "dead"); else lua_pushliteral(L, "suspended"); /* initial state */ break; } default: /* some error occured */ lua_pushliteral(L, "dead"); break; } } return 1; } static int luaB_corunning (lua_State *L) { if (lua_pushthread(L)) return 0; /* main thread is not a coroutine */ else return 1; } static const luaL_Reg co_funcs[] = { {"create", luaB_cocreate}, {"resume", luaB_coresume}, {"running", luaB_corunning}, {"status", luaB_costatus}, {"wrap", luaB_cowrap}, {"yield", luaB_yield}, {NULL, NULL} }; /* }====================================================== */ static void auxopen (lua_State *L, const char *name, lua_CFunction f, lua_CFunction u) { lua_pushcfunction(L, u); lua_pushcclosure(L, f, 1); lua_setfield(L, -2, name); } static void base_open (lua_State *L) { /* set global _G */ lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setglobal(L, "_G"); /* open lib into global table */ luaL_register(L, "_G", base_funcs); lua_pushliteral(L, LUA_VERSION); lua_setglobal(L, "_VERSION"); /* set global _VERSION */ /* `ipairs' and `pairs' need auxliliary functions as upvalues */ auxopen(L, "ipairs", luaB_ipairs, ipairsaux); auxopen(L, "pairs", luaB_pairs, luaB_next); /* `newproxy' needs a weaktable as upvalue */ lua_createtable(L, 0, 1); /* new table `w' */ lua_pushvalue(L, -1); /* `w' will be its own metatable */ lua_setmetatable(L, -2); lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); lua_setglobal(L, "newproxy"); /* set global `newproxy' */ } LUALIB_API int luaopen_base (lua_State *L) { base_open(L); luaL_register(L, LUA_COLIBNAME, co_funcs); return 2; } tagua-1.0-alpha2/lua/src/lcode.c000066400000000000000000000515211077523320400164310ustar00rootroot00000000000000/* ** $Id: lcode.c,v 2.25a 2006/03/21 19:28:49 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ #include #define lcode_c #define LUA_CORE #include "lua.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lgc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "ltable.h" #define hasjumps(e) ((e)->t != (e)->f) static int isnumeral(expdesc *e) { return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); } void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ if (fs->pc == 0) { /* function start? */ if (from >= fs->nactvar) return; /* positions are already clean */ } else { previous = &fs->f->code[fs->pc-1]; if (GET_OPCODE(*previous) == OP_LOADNIL) { int pfrom = GETARG_A(*previous); int pto = GETARG_B(*previous); if (pfrom <= from && from <= pto+1) { /* can connect both? */ if (from+n-1 > pto) SETARG_B(*previous, from+n-1); return; } } } } luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */ } int luaK_jump (FuncState *fs) { int jpc = fs->jpc; /* save list of jumps to here */ int j; fs->jpc = NO_JUMP; j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); luaK_concat(fs, &j, jpc); /* keep them on hold */ return j; } void luaK_ret (FuncState *fs, int first, int nret) { luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); } static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { luaK_codeABC(fs, op, A, B, C); return luaK_jump(fs); } static void fixjump (FuncState *fs, int pc, int dest) { Instruction *jmp = &fs->f->code[pc]; int offset = dest-(pc+1); lua_assert(dest != NO_JUMP); if (abs(offset) > MAXARG_sBx) luaX_syntaxerror(fs->ls, "control structure too long"); SETARG_sBx(*jmp, offset); } /* ** returns current `pc' and marks it as a jump target (to avoid wrong ** optimizations with consecutive instructions not in the same basic block). */ int luaK_getlabel (FuncState *fs) { fs->lasttarget = fs->pc; return fs->pc; } static int getjump (FuncState *fs, int pc) { int offset = GETARG_sBx(fs->f->code[pc]); if (offset == NO_JUMP) /* point to itself represents end of list */ return NO_JUMP; /* end of list */ else return (pc+1)+offset; /* turn offset into absolute position */ } static Instruction *getjumpcontrol (FuncState *fs, int pc) { Instruction *pi = &fs->f->code[pc]; if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) return pi-1; else return pi; } /* ** check whether list has any jump that do not produce a value ** (or produce an inverted value) */ static int need_value (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) { Instruction i = *getjumpcontrol(fs, list); if (GET_OPCODE(i) != OP_TESTSET) return 1; } return 0; /* not found */ } static int patchtestreg (FuncState *fs, int node, int reg) { Instruction *i = getjumpcontrol(fs, node); if (GET_OPCODE(*i) != OP_TESTSET) return 0; /* cannot patch other instructions */ if (reg != NO_REG && reg != GETARG_B(*i)) SETARG_A(*i, reg); else /* no register to put value or register already has the value */ *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); return 1; } static void removevalues (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) patchtestreg(fs, list, NO_REG); } static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, int dtarget) { while (list != NO_JUMP) { int next = getjump(fs, list); if (patchtestreg(fs, list, reg)) fixjump(fs, list, vtarget); else fixjump(fs, list, dtarget); /* jump to default target */ list = next; } } static void dischargejpc (FuncState *fs) { patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); fs->jpc = NO_JUMP; } void luaK_patchlist (FuncState *fs, int list, int target) { if (target == fs->pc) luaK_patchtohere(fs, list); else { lua_assert(target < fs->pc); patchlistaux(fs, list, target, NO_REG, target); } } void luaK_patchtohere (FuncState *fs, int list) { luaK_getlabel(fs); luaK_concat(fs, &fs->jpc, list); } void luaK_concat (FuncState *fs, int *l1, int l2) { if (l2 == NO_JUMP) return; else if (*l1 == NO_JUMP) *l1 = l2; else { int list = *l1; int next; while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ list = next; fixjump(fs, list, l2); } } void luaK_checkstack (FuncState *fs, int n) { int newstack = fs->freereg + n; if (newstack > fs->f->maxstacksize) { if (newstack >= MAXSTACK) luaX_syntaxerror(fs->ls, "function or expression too complex"); fs->f->maxstacksize = cast_byte(newstack); } } void luaK_reserveregs (FuncState *fs, int n) { luaK_checkstack(fs, n); fs->freereg += n; } static void freereg (FuncState *fs, int reg) { if (!ISK(reg) && reg >= fs->nactvar) { fs->freereg--; lua_assert(reg == fs->freereg); } } static void freeexp (FuncState *fs, expdesc *e) { if (e->k == VNONRELOC) freereg(fs, e->u.s.info); } static int addk (FuncState *fs, TValue *k, TValue *v) { lua_State *L = fs->L; TValue *idx = luaH_set(L, fs->h, k); Proto *f = fs->f; int oldsize = f->sizek; if (ttisnumber(idx)) { lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); return cast_int(nvalue(idx)); } else { /* constant not found; create a new entry */ setnvalue(idx, cast_num(fs->nk)); luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, MAXARG_Bx, "constant table overflow"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); setobj(L, &f->k[fs->nk], v); luaC_barrier(L, f, v); return fs->nk++; } } int luaK_stringK (FuncState *fs, TString *s) { TValue o; setsvalue(fs->L, &o, s); return addk(fs, &o, &o); } int luaK_numberK (FuncState *fs, lua_Number r) { TValue o; setnvalue(&o, r); return addk(fs, &o, &o); } static int boolK (FuncState *fs, int b) { TValue o; setbvalue(&o, b); return addk(fs, &o, &o); } static int nilK (FuncState *fs) { TValue k, v; setnilvalue(&v); /* cannot use nil as key; instead use table itself to represent nil */ sethvalue(fs->L, &k, fs->h); return addk(fs, &k, &v); } void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { if (e->k == VCALL) { /* expression is an open function call? */ SETARG_C(getcode(fs, e), nresults+1); } else if (e->k == VVARARG) { SETARG_B(getcode(fs, e), nresults+1); SETARG_A(getcode(fs, e), fs->freereg); luaK_reserveregs(fs, 1); } } void luaK_setoneret (FuncState *fs, expdesc *e) { if (e->k == VCALL) { /* expression is an open function call? */ e->k = VNONRELOC; e->u.s.info = GETARG_A(getcode(fs, e)); } else if (e->k == VVARARG) { SETARG_B(getcode(fs, e), 2); e->k = VRELOCABLE; /* can relocate its simple result */ } } void luaK_dischargevars (FuncState *fs, expdesc *e) { switch (e->k) { case VLOCAL: { e->k = VNONRELOC; break; } case VUPVAL: { e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0); e->k = VRELOCABLE; break; } case VGLOBAL: { e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); e->k = VRELOCABLE; break; } case VINDEXED: { freereg(fs, e->u.s.aux); freereg(fs, e->u.s.info); e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux); e->k = VRELOCABLE; break; } case VVARARG: case VCALL: { luaK_setoneret(fs, e); break; } default: break; /* there is one value available (somewhere) */ } } static int code_label (FuncState *fs, int A, int b, int jump) { luaK_getlabel(fs); /* those instructions may be jump targets */ return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); } static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_dischargevars(fs, e); switch (e->k) { case VNIL: { luaK_nil(fs, reg, 1); break; } case VFALSE: case VTRUE: { luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); break; } case VK: { luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); break; } case VKNUM: { luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); break; } case VRELOCABLE: { Instruction *pc = &getcode(fs, e); SETARG_A(*pc, reg); break; } case VNONRELOC: { if (reg != e->u.s.info) luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0); break; } default: { lua_assert(e->k == VVOID || e->k == VJMP); return; /* nothing to do... */ } } e->u.s.info = reg; e->k = VNONRELOC; } static void discharge2anyreg (FuncState *fs, expdesc *e) { if (e->k != VNONRELOC) { luaK_reserveregs(fs, 1); discharge2reg(fs, e, fs->freereg-1); } } static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); if (e->k == VJMP) luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */ if (hasjumps(e)) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_t = NO_JUMP; /* position of an eventual LOAD true */ if (need_value(fs, e->t) || need_value(fs, e->f)) { int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); p_f = code_label(fs, reg, 0, 1); p_t = code_label(fs, reg, 1, 0); luaK_patchtohere(fs, fj); } final = luaK_getlabel(fs); patchlistaux(fs, e->f, final, reg, p_f); patchlistaux(fs, e->t, final, reg, p_t); } e->f = e->t = NO_JUMP; e->u.s.info = reg; e->k = VNONRELOC; } void luaK_exp2nextreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); freeexp(fs, e); luaK_reserveregs(fs, 1); exp2reg(fs, e, fs->freereg - 1); } int luaK_exp2anyreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); if (e->k == VNONRELOC) { if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */ if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */ exp2reg(fs, e, e->u.s.info); /* put value on it */ return e->u.s.info; } } luaK_exp2nextreg(fs, e); /* default */ return e->u.s.info; } void luaK_exp2val (FuncState *fs, expdesc *e) { if (hasjumps(e)) luaK_exp2anyreg(fs, e); else luaK_dischargevars(fs, e); } int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); switch (e->k) { case VKNUM: case VTRUE: case VFALSE: case VNIL: { if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ e->u.s.info = (e->k == VNIL) ? nilK(fs) : (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : boolK(fs, (e->k == VTRUE)); e->k = VK; return RKASK(e->u.s.info); } else break; } case VK: { if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ return RKASK(e->u.s.info); else break; } default: break; } /* not a constant in the right range: put it in a register */ return luaK_exp2anyreg(fs, e); } void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { freeexp(fs, ex); exp2reg(fs, ex, var->u.s.info); return; } case VUPVAL: { int e = luaK_exp2anyreg(fs, ex); luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); break; } case VGLOBAL: { int e = luaK_exp2anyreg(fs, ex); luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); break; } case VINDEXED: { int e = luaK_exp2RK(fs, ex); luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); break; } default: { lua_assert(0); /* invalid var kind to store */ break; } } freeexp(fs, ex); } void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { int func; luaK_exp2anyreg(fs, e); freeexp(fs, e); func = fs->freereg; luaK_reserveregs(fs, 2); luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); freeexp(fs, key); e->u.s.info = func; e->k = VNONRELOC; } static void invertjump (FuncState *fs, expdesc *e) { Instruction *pc = getjumpcontrol(fs, e->u.s.info); lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && GET_OPCODE(*pc) != OP_TEST); SETARG_A(*pc, !(GETARG_A(*pc))); } static int jumponcond (FuncState *fs, expdesc *e, int cond) { if (e->k == VRELOCABLE) { Instruction ie = getcode(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); } /* else go through */ } discharge2anyreg(fs, e); freeexp(fs, e); return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond); } void luaK_goiftrue (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { case VK: case VKNUM: case VTRUE: { pc = NO_JUMP; /* always true; do nothing */ break; } case VFALSE: { pc = luaK_jump(fs); /* always jump */ break; } case VJMP: { invertjump(fs, e); pc = e->u.s.info; break; } default: { pc = jumponcond(fs, e, 0); break; } } luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ luaK_patchtohere(fs, e->t); e->t = NO_JUMP; } static void luaK_goiffalse (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { case VNIL: case VFALSE: { pc = NO_JUMP; /* always false; do nothing */ break; } case VTRUE: { pc = luaK_jump(fs); /* always jump */ break; } case VJMP: { pc = e->u.s.info; break; } default: { pc = jumponcond(fs, e, 1); break; } } luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ luaK_patchtohere(fs, e->f); e->f = NO_JUMP; } static void codenot (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); switch (e->k) { case VNIL: case VFALSE: { e->k = VTRUE; break; } case VK: case VKNUM: case VTRUE: { e->k = VFALSE; break; } case VJMP: { invertjump(fs, e); break; } case VRELOCABLE: case VNONRELOC: { discharge2anyreg(fs, e); freeexp(fs, e); e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0); e->k = VRELOCABLE; break; } default: { lua_assert(0); /* cannot happen */ break; } } /* interchange true and false lists */ { int temp = e->f; e->f = e->t; e->t = temp; } removevalues(fs, e->f); removevalues(fs, e->t); } void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { t->u.s.aux = luaK_exp2RK(fs, k); t->k = VINDEXED; } static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { lua_Number v1, v2, r; if (!isnumeral(e1) || !isnumeral(e2)) return 0; v1 = e1->u.nval; v2 = e2->u.nval; switch (op) { case OP_ADD: r = luai_numadd(v1, v2); break; case OP_SUB: r = luai_numsub(v1, v2); break; case OP_MUL: r = luai_nummul(v1, v2); break; case OP_DIV: if (v2 == 0) return 0; /* do not attempt to divide by 0 */ r = luai_numdiv(v1, v2); break; case OP_MOD: if (v2 == 0) return 0; /* do not attempt to divide by 0 */ r = luai_nummod(v1, v2); break; case OP_POW: r = luai_numpow(v1, v2); break; case OP_UNM: r = luai_numunm(v1); break; case OP_LEN: return 0; /* no constant folding for 'len' */ default: lua_assert(0); r = 0; break; } if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ e1->u.nval = r; return 1; } static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { if (constfolding(op, e1, e2)) return; else { int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; int o1 = luaK_exp2RK(fs, e1); if (o1 > o2) { freeexp(fs, e1); freeexp(fs, e2); } else { freeexp(fs, e2); freeexp(fs, e1); } e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); e1->k = VRELOCABLE; } } static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, expdesc *e2) { int o1 = luaK_exp2RK(fs, e1); int o2 = luaK_exp2RK(fs, e2); freeexp(fs, e2); freeexp(fs, e1); if (cond == 0 && op != OP_EQ) { int temp; /* exchange args to replace by `<' or `<=' */ temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ cond = 1; } e1->u.s.info = condjump(fs, op, cond, o1, o2); e1->k = VJMP; } void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { expdesc e2; e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; switch (op) { case OPR_MINUS: { if (e->k == VK) luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ codearith(fs, OP_UNM, e, &e2); break; } case OPR_NOT: codenot(fs, e); break; case OPR_LEN: { luaK_exp2anyreg(fs, e); /* cannot operate on constants */ codearith(fs, OP_LEN, e, &e2); break; } default: lua_assert(0); } } void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { switch (op) { case OPR_AND: { luaK_goiftrue(fs, v); break; } case OPR_OR: { luaK_goiffalse(fs, v); break; } case OPR_CONCAT: { luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: case OPR_MOD: case OPR_POW: { if (!isnumeral(v)) luaK_exp2RK(fs, v); break; } default: { luaK_exp2RK(fs, v); break; } } } void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { switch (op) { case OPR_AND: { lua_assert(e1->t == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->f, e1->f); *e1 = *e2; break; } case OPR_OR: { lua_assert(e1->f == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->t, e1->t); *e1 = *e2; break; } case OPR_CONCAT: { luaK_exp2val(fs, e2); if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); freeexp(fs, e1); SETARG_B(getcode(fs, e2), e1->u.s.info); e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info; } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ codearith(fs, OP_CONCAT, e1, e2); } break; } case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; case OPR_POW: codearith(fs, OP_POW, e1, e2); break; case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; default: lua_assert(0); } } void luaK_fixline (FuncState *fs, int line) { fs->f->lineinfo[fs->pc - 1] = line; } static int luaK_code (FuncState *fs, Instruction i, int line) { Proto *f = fs->f; dischargejpc(fs); /* `pc' will change */ /* put new instruction in code array */ luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, MAX_INT, "code size overflow"); f->code[fs->pc] = i; /* save corresponding line information */ luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, MAX_INT, "code size overflow"); f->lineinfo[fs->pc] = line; return fs->pc++; } int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { lua_assert(getOpMode(o) == iABC); lua_assert(getBMode(o) != OpArgN || b == 0); lua_assert(getCMode(o) != OpArgN || c == 0); return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); } int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); lua_assert(getCMode(o) == OpArgN); return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); } void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; int b = (tostore == LUA_MULTRET) ? 0 : tostore; lua_assert(tostore != 0); if (c <= MAXARG_C) luaK_codeABC(fs, OP_SETLIST, base, b, c); else { luaK_codeABC(fs, OP_SETLIST, base, b, 0); luaK_code(fs, cast(Instruction, c), fs->ls->lastline); } fs->freereg = base + 1; /* free registers with list values */ } tagua-1.0-alpha2/lua/src/lcode.h000066400000000000000000000052721077523320400164400ustar00rootroot00000000000000/* ** $Id: lcode.h,v 1.48 2006/03/21 19:28:03 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ #ifndef lcode_h #define lcode_h #include "llex.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" /* ** Marks the end of a patch list. It is an invalid value both as an absolute ** address, and as a list link (would link an element to itself). */ #define NO_JUMP (-1) /* ** grep "ORDER OPR" if you change these enums */ typedef enum BinOpr { OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, OPR_CONCAT, OPR_NE, OPR_EQ, OPR_LT, OPR_LE, OPR_GT, OPR_GE, OPR_AND, OPR_OR, OPR_NOBINOPR } BinOpr; typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; #define getcode(fs,e) ((fs)->f->code[(e)->u.s.info]) #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r); LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_jump (FuncState *fs); LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); LUAI_FUNC int luaK_getlabel (FuncState *fs); LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2); LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); #endif tagua-1.0-alpha2/lua/src/ldblib.c000066400000000000000000000234751077523320400166020ustar00rootroot00000000000000/* ** $Id: ldblib.c,v 1.104 2005/12/29 15:32:11 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ #include #include #include #define ldblib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" static int db_getregistry (lua_State *L) { lua_pushvalue(L, LUA_REGISTRYINDEX); return 1; } static int db_getmetatable (lua_State *L) { luaL_checkany(L, 1); if (!lua_getmetatable(L, 1)) { lua_pushnil(L); /* no metatable */ } return 1; } static int db_setmetatable (lua_State *L) { int t = lua_type(L, 2); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); lua_settop(L, 2); lua_pushboolean(L, lua_setmetatable(L, 1)); return 1; } static int db_getfenv (lua_State *L) { lua_getfenv(L, 1); return 1; } static int db_setfenv (lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); lua_settop(L, 2); if (lua_setfenv(L, 1) == 0) luaL_error(L, LUA_QL("setfenv") " cannot change environment of given object"); return 1; } static void settabss (lua_State *L, const char *i, const char *v) { lua_pushstring(L, v); lua_setfield(L, -2, i); } static void settabsi (lua_State *L, const char *i, int v) { lua_pushinteger(L, v); lua_setfield(L, -2, i); } static lua_State *getthread (lua_State *L, int *arg) { if (lua_isthread(L, 1)) { *arg = 1; return lua_tothread(L, 1); } else { *arg = 0; return L; } } static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { if (L == L1) { lua_pushvalue(L, -2); lua_remove(L, -3); } else lua_xmove(L1, L, 1); lua_setfield(L, -2, fname); } static int db_getinfo (lua_State *L) { lua_Debug ar; int arg; lua_State *L1 = getthread(L, &arg); const char *options = luaL_optstring(L, arg+2, "flnSu"); if (lua_isnumber(L, arg+1)) { if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } else if (lua_isfunction(L, arg+1)) { lua_pushfstring(L, ">%s", options); options = lua_tostring(L, -1); lua_pushvalue(L, arg+1); lua_xmove(L, L1, 1); } else return luaL_argerror(L, arg+1, "function or level expected"); if (!lua_getinfo(L1, options, &ar)) return luaL_argerror(L, arg+2, "invalid option"); lua_createtable(L, 0, 2); if (strchr(options, 'S')) { settabss(L, "source", ar.source); settabss(L, "short_src", ar.short_src); settabsi(L, "linedefined", ar.linedefined); settabsi(L, "lastlinedefined", ar.lastlinedefined); settabss(L, "what", ar.what); } if (strchr(options, 'l')) settabsi(L, "currentline", ar.currentline); if (strchr(options, 'u')) settabsi(L, "nups", ar.nups); if (strchr(options, 'n')) { settabss(L, "name", ar.name); settabss(L, "namewhat", ar.namewhat); } if (strchr(options, 'L')) treatstackoption(L, L1, "activelines"); if (strchr(options, 'f')) treatstackoption(L, L1, "func"); return 1; /* return table */ } static int db_getlocal (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; const char *name; if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); if (name) { lua_xmove(L1, L, 1); lua_pushstring(L, name); lua_pushvalue(L, -2); return 2; } else { lua_pushnil(L); return 1; } } static int db_setlocal (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); luaL_checkany(L, arg+3); lua_settop(L, arg+3); lua_xmove(L, L1, 1); lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); return 1; } static int auxupvalue (lua_State *L, int get) { const char *name; int n = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TFUNCTION); if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; lua_pushstring(L, name); lua_insert(L, -(get+1)); return get + 1; } static int db_getupvalue (lua_State *L) { return auxupvalue(L, 1); } static int db_setupvalue (lua_State *L) { luaL_checkany(L, 3); return auxupvalue(L, 0); } static const char KEY_HOOK = 'h'; static void hookf (lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = {"call", "return", "line", "count", "tail return"}; lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushlightuserdata(L, L); lua_rawget(L, -2); if (lua_isfunction(L, -1)) { lua_pushstring(L, hooknames[(int)ar->event]); if (ar->currentline >= 0) lua_pushinteger(L, ar->currentline); else lua_pushnil(L); lua_assert(lua_getinfo(L, "lS", ar)); lua_call(L, 2, 0); } } static int makemask (const char *smask, int count) { int mask = 0; if (strchr(smask, 'c')) mask |= LUA_MASKCALL; if (strchr(smask, 'r')) mask |= LUA_MASKRET; if (strchr(smask, 'l')) mask |= LUA_MASKLINE; if (count > 0) mask |= LUA_MASKCOUNT; return mask; } static char *unmakemask (int mask, char *smask) { int i = 0; if (mask & LUA_MASKCALL) smask[i++] = 'c'; if (mask & LUA_MASKRET) smask[i++] = 'r'; if (mask & LUA_MASKLINE) smask[i++] = 'l'; smask[i] = '\0'; return smask; } static void gethooktable (lua_State *L) { lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_rawget(L, LUA_REGISTRYINDEX); if (!lua_istable(L, -1)) { lua_pop(L, 1); lua_createtable(L, 0, 1); lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_pushvalue(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); } } static int db_sethook (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); if (lua_isnoneornil(L, arg+1)) { lua_settop(L, arg+1); lua_sethook(L1, NULL, 0, 0); /* turn off hooks */ } else { const char *smask = luaL_checkstring(L, arg+2); int count = luaL_optint(L, arg+3, 0); luaL_checktype(L, arg+1, LUA_TFUNCTION); lua_sethook(L1, hookf, makemask(smask, count), count); } gethooktable(L1); lua_pushlightuserdata(L1, L1); lua_pushvalue(L, arg+1); lua_xmove(L, L1, 1); lua_rawset(L1, -3); /* set new hook */ lua_pop(L1, 1); /* remove hook table */ return 0; } static int db_gethook (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); char buff[5]; int mask = lua_gethookmask(L1); lua_Hook hook = lua_gethook(L1); if (hook != NULL && hook != hookf) /* external hook? */ lua_pushliteral(L, "external hook"); else { gethooktable(L1); lua_pushlightuserdata(L1, L1); lua_rawget(L1, -2); /* get hook */ lua_remove(L1, -2); /* remove hook table */ lua_xmove(L1, L, 1); } lua_pushstring(L, unmakemask(mask, buff)); lua_pushinteger(L, lua_gethookcount(L1)); return 3; } static int db_debug (lua_State *L) { for (;;) { char buffer[250]; fputs("lua_debug> ", stderr); if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) return 0; if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || lua_pcall(L, 0, 0, 0)) { fputs(lua_tostring(L, -1), stderr); fputs("\n", stderr); } lua_settop(L, 0); /* remove eventual returns */ } } #define LEVELS1 12 /* size of the first part of the stack */ #define LEVELS2 10 /* size of the second part of the stack */ static int db_errorfb (lua_State *L) { int level; int firstpart = 1; /* still before eventual `...' */ int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; if (lua_isnumber(L, arg+2)) { level = (int)lua_tointeger(L, arg+2); lua_pop(L, 1); } else level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ if (lua_gettop(L) == arg) lua_pushliteral(L, ""); else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */ else lua_pushliteral(L, "\n"); lua_pushliteral(L, "stack traceback:"); while (lua_getstack(L1, level++, &ar)) { if (level > LEVELS1 && firstpart) { /* no more than `LEVELS2' more levels? */ if (!lua_getstack(L1, level+LEVELS2, &ar)) level--; /* keep going */ else { lua_pushliteral(L, "\n\t..."); /* too many levels */ while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */ level++; } firstpart = 0; continue; } lua_pushliteral(L, "\n\t"); lua_getinfo(L1, "Snl", &ar); lua_pushfstring(L, "%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); if (*ar.namewhat != '\0') /* is there a name? */ lua_pushfstring(L, " in function " LUA_QS, ar.name); else { if (*ar.what == 'm') /* main? */ lua_pushfstring(L, " in main chunk"); else if (*ar.what == 'C' || *ar.what == 't') lua_pushliteral(L, " ?"); /* C function or tail call */ else lua_pushfstring(L, " in function <%s:%d>", ar.short_src, ar.linedefined); } lua_concat(L, lua_gettop(L) - arg); } lua_concat(L, lua_gettop(L) - arg); return 1; } static const luaL_Reg dblib[] = { {"debug", db_debug}, {"getfenv", db_getfenv}, {"gethook", db_gethook}, {"getinfo", db_getinfo}, {"getlocal", db_getlocal}, {"getregistry", db_getregistry}, {"getmetatable", db_getmetatable}, {"getupvalue", db_getupvalue}, {"setfenv", db_setfenv}, {"sethook", db_sethook}, {"setlocal", db_setlocal}, {"setmetatable", db_setmetatable}, {"setupvalue", db_setupvalue}, {"traceback", db_errorfb}, {NULL, NULL} }; LUALIB_API int luaopen_debug (lua_State *L) { luaL_register(L, LUA_DBLIBNAME, dblib); return 1; } tagua-1.0-alpha2/lua/src/ldebug.c000066400000000000000000000373721077523320400166150ustar00rootroot00000000000000/* ** $Id: ldebug.c,v 2.29a 2005/12/22 16:19:56 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ #include #include #include #define ldebug_c #define LUA_CORE #include "lua.h" #include "lapi.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lobject.h" #include "lopcodes.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lvm.h" static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); static int currentpc (lua_State *L, CallInfo *ci) { if (!isLua(ci)) return -1; /* function is not a Lua function? */ if (ci == L->ci) ci->savedpc = L->savedpc; return pcRel(ci->savedpc, ci_func(ci)->l.p); } static int currentline (lua_State *L, CallInfo *ci) { int pc = currentpc(L, ci); if (pc < 0) return -1; /* only active lua functions have current-line information */ else return getline(ci_func(ci)->l.p, pc); } /* ** this function can be called asynchronous (e.g. during a signal) */ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { if (func == NULL || mask == 0) { /* turn off hooks? */ mask = 0; func = NULL; } L->hook = func; L->basehookcount = count; resethookcount(L); L->hookmask = cast_byte(mask); return 1; } LUA_API lua_Hook lua_gethook (lua_State *L) { return L->hook; } LUA_API int lua_gethookmask (lua_State *L) { return L->hookmask; } LUA_API int lua_gethookcount (lua_State *L) { return L->basehookcount; } LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { int status; CallInfo *ci; lua_lock(L); for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { level--; if (f_isLua(ci)) /* Lua function? */ level -= ci->tailcalls; /* skip lost tail calls */ } if (level == 0 && ci > L->base_ci) { /* level found? */ status = 1; ar->i_ci = cast_int(ci - L->base_ci); } else if (level < 0) { /* level is of a lost tail call? */ status = 1; ar->i_ci = 0; } else status = 0; /* no such level */ lua_unlock(L); return status; } static Proto *getluaproto (CallInfo *ci) { return (isLua(ci) ? ci_func(ci)->l.p : NULL); } static const char *findlocal (lua_State *L, CallInfo *ci, int n) { const char *name; Proto *fp = getluaproto(ci); if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL) return name; /* is a local variable in a Lua function */ else { StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */ return "(*temporary)"; else return NULL; } } LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { CallInfo *ci = L->base_ci + ar->i_ci; const char *name = findlocal(L, ci, n); lua_lock(L); if (name) luaA_pushobject(L, ci->base + (n - 1)); lua_unlock(L); return name; } LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { CallInfo *ci = L->base_ci + ar->i_ci; const char *name = findlocal(L, ci, n); lua_lock(L); if (name) setobjs2s(L, ci->base + (n - 1), L->top - 1); L->top--; /* pop value */ lua_unlock(L); return name; } static void funcinfo (lua_Debug *ar, Closure *cl) { if (cl->c.isC) { ar->source = "=[C]"; ar->linedefined = -1; ar->lastlinedefined = -1; ar->what = "C"; } else { ar->source = getstr(cl->l.p->source); ar->linedefined = cl->l.p->linedefined; ar->lastlinedefined = cl->l.p->lastlinedefined; ar->what = (ar->linedefined == 0) ? "main" : "Lua"; } luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); } static void info_tailcall (lua_Debug *ar) { ar->name = ar->namewhat = ""; ar->what = "tail"; ar->lastlinedefined = ar->linedefined = ar->currentline = -1; ar->source = "=(tail call)"; luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); ar->nups = 0; } static void collectvalidlines (lua_State *L, Closure *f) { if (f == NULL || f->c.isC) { setnilvalue(L->top); } else { Table *t = luaH_new(L, 0, 0); int *lineinfo = f->l.p->lineinfo; int i; for (i=0; il.p->sizelineinfo; i++) setbvalue(luaH_setnum(L, t, lineinfo[i]), 1); sethvalue(L, L->top, t); } incr_top(L); } static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, Closure *f, CallInfo *ci) { int status = 1; if (f == NULL) { info_tailcall(ar); return status; } for (; *what; what++) { switch (*what) { case 'S': { funcinfo(ar, f); break; } case 'l': { ar->currentline = (ci) ? currentline(L, ci) : -1; break; } case 'u': { ar->nups = f->c.nupvalues; break; } case 'n': { ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL; if (ar->namewhat == NULL) { ar->namewhat = ""; /* not found */ ar->name = NULL; } break; } case 'L': case 'f': /* handled by lua_getinfo */ break; default: status = 0; /* invalid option */ } } return status; } LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { int status; Closure *f = NULL; CallInfo *ci = NULL; lua_lock(L); if (*what == '>') { StkId func = L->top - 1; luai_apicheck(L, ttisfunction(func)); what++; /* skip the '>' */ f = clvalue(func); L->top--; /* pop function */ } else if (ar->i_ci != 0) { /* no tail call? */ ci = L->base_ci + ar->i_ci; lua_assert(ttisfunction(ci->func)); f = clvalue(ci->func); } status = auxgetinfo(L, what, ar, f, ci); if (strchr(what, 'f')) { if (f == NULL) setnilvalue(L->top); else setclvalue(L, L->top, f); incr_top(L); } if (strchr(what, 'L')) collectvalidlines(L, f); lua_unlock(L); return status; } /* ** {====================================================== ** Symbolic Execution and code checker ** ======================================================= */ #define check(x) if (!(x)) return 0; #define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode) #define checkreg(pt,reg) check((reg) < (pt)->maxstacksize) static int precheck (const Proto *pt) { check(pt->maxstacksize <= MAXSTACK); lua_assert(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); lua_assert(!(pt->is_vararg & VARARG_NEEDSARG) || (pt->is_vararg & VARARG_HASARG)); check(pt->sizeupvalues <= pt->nups); check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); return 1; } #define checkopenop(pt,pc) luaG_checkopenop((pt)->code[(pc)+1]) int luaG_checkopenop (Instruction i) { switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: case OP_RETURN: case OP_SETLIST: { check(GETARG_B(i) == 0); return 1; } default: return 0; /* invalid instruction after an open call */ } } static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { switch (mode) { case OpArgN: check(r == 0); break; case OpArgU: break; case OpArgR: checkreg(pt, r); break; case OpArgK: check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); break; } return 1; } static Instruction symbexec (const Proto *pt, int lastpc, int reg) { int pc; int last; /* stores position of last instruction that changed `reg' */ last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ check(precheck(pt)); for (pc = 0; pc < lastpc; pc++) { Instruction i = pt->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); int b = 0; int c = 0; check(op < NUM_OPCODES); checkreg(pt, a); switch (getOpMode(op)) { case iABC: { b = GETARG_B(i); c = GETARG_C(i); check(checkArgMode(pt, b, getBMode(op))); check(checkArgMode(pt, c, getCMode(op))); break; } case iABx: { b = GETARG_Bx(i); if (getBMode(op) == OpArgK) check(b < pt->sizek); break; } case iAsBx: { b = GETARG_sBx(i); if (getBMode(op) == OpArgR) { int dest = pc+1+b; check(0 <= dest && dest < pt->sizecode); if (dest > 0) { /* cannot jump to a setlist count */ Instruction d = pt->code[dest-1]; check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)); } } break; } } if (testAMode(op)) { if (a == reg) last = pc; /* change register `a' */ } if (testTMode(op)) { check(pc+2 < pt->sizecode); /* check skip */ check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); } switch (op) { case OP_LOADBOOL: { check(c == 0 || pc+2 < pt->sizecode); /* check its jump */ break; } case OP_LOADNIL: { if (a <= reg && reg <= b) last = pc; /* set registers from `a' to `b' */ break; } case OP_GETUPVAL: case OP_SETUPVAL: { check(b < pt->nups); break; } case OP_GETGLOBAL: case OP_SETGLOBAL: { check(ttisstring(&pt->k[b])); break; } case OP_SELF: { checkreg(pt, a+1); if (reg == a+1) last = pc; break; } case OP_CONCAT: { check(b < c); /* at least two operands */ break; } case OP_TFORLOOP: { check(c >= 1); /* at least one result (control variable) */ checkreg(pt, a+2+c); /* space for results */ if (reg >= a+2) last = pc; /* affect all regs above its base */ break; } case OP_FORLOOP: case OP_FORPREP: checkreg(pt, a+3); /* go through */ case OP_JMP: { int dest = pc+1+b; /* not full check and jump is forward and do not skip `lastpc'? */ if (reg != NO_REG && pc < dest && dest <= lastpc) pc += b; /* do the jump */ break; } case OP_CALL: case OP_TAILCALL: { if (b != 0) { checkreg(pt, a+b-1); } c--; /* c = num. returns */ if (c == LUA_MULTRET) { check(checkopenop(pt, pc)); } else if (c != 0) checkreg(pt, a+c-1); if (reg >= a) last = pc; /* affect all registers above base */ break; } case OP_RETURN: { b--; /* b = num. returns */ if (b > 0) checkreg(pt, a+b-1); break; } case OP_SETLIST: { if (b > 0) checkreg(pt, a + b); if (c == 0) pc++; break; } case OP_CLOSURE: { int nup, j; check(b < pt->sizep); nup = pt->p[b]->nups; check(pc + nup < pt->sizecode); for (j = 1; j <= nup; j++) { OpCode op1 = GET_OPCODE(pt->code[pc + j]); check(op1 == OP_GETUPVAL || op1 == OP_MOVE); } if (reg != NO_REG) /* tracing? */ pc += nup; /* do not 'execute' these pseudo-instructions */ break; } case OP_VARARG: { check((pt->is_vararg & VARARG_ISVARARG) && !(pt->is_vararg & VARARG_NEEDSARG)); b--; if (b == LUA_MULTRET) check(checkopenop(pt, pc)); checkreg(pt, a+b-1); break; } default: break; } } return pt->code[last]; } #undef check #undef checkjump #undef checkreg /* }====================================================== */ int luaG_checkcode (const Proto *pt) { return (symbexec(pt, pt->sizecode, NO_REG) != 0); } static const char *kname (Proto *p, int c) { if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) return svalue(&p->k[INDEXK(c)]); else return "?"; } static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, const char **name) { if (isLua(ci)) { /* a Lua function? */ Proto *p = ci_func(ci)->l.p; int pc = currentpc(L, ci); Instruction i; *name = luaF_getlocalname(p, stackpos+1, pc); if (*name) /* is a local? */ return "local"; i = symbexec(p, pc, stackpos); /* try symbolic execution */ lua_assert(pc != -1); switch (GET_OPCODE(i)) { case OP_GETGLOBAL: { int g = GETARG_Bx(i); /* global index */ lua_assert(ttisstring(&p->k[g])); *name = svalue(&p->k[g]); return "global"; } case OP_MOVE: { int a = GETARG_A(i); int b = GETARG_B(i); /* move from `b' to `a' */ if (b < a) return getobjname(L, ci, b, name); /* get name for `b' */ break; } case OP_GETTABLE: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); return "field"; } case OP_GETUPVAL: { int u = GETARG_B(i); /* upvalue index */ *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; return "upvalue"; } case OP_SELF: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); return "method"; } default: break; } } return NULL; /* no useful name found */ } static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { Instruction i; if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) return NULL; /* calling function is not Lua (or is unknown) */ ci--; /* calling function */ i = ci_func(ci)->l.p->code[currentpc(L, ci)]; if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || GET_OPCODE(i) == OP_TFORLOOP) return getobjname(L, ci, GETARG_A(i), name); else return NULL; /* no useful name can be found */ } /* only ANSI way to check whether a pointer points to an array */ static int isinstack (CallInfo *ci, const TValue *o) { StkId p; for (p = ci->base; p < ci->top; p++) if (o == p) return 1; return 0; } void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { const char *name = NULL; const char *t = luaT_typenames[ttype(o)]; const char *kind = (isinstack(L->ci, o)) ? getobjname(L, L->ci, cast_int(o - L->base), &name) : NULL; if (kind) luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", op, kind, name, t); else luaG_runerror(L, "attempt to %s a %s value", op, t); } void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { if (ttisstring(p1)) p1 = p2; lua_assert(!ttisstring(p1)); luaG_typeerror(L, p1, "concatenate"); } void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { TValue temp; if (luaV_tonumber(p1, &temp) == NULL) p2 = p1; /* first operand is wrong */ luaG_typeerror(L, p2, "perform arithmetic on"); } int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { const char *t1 = luaT_typenames[ttype(p1)]; const char *t2 = luaT_typenames[ttype(p2)]; if (t1[2] == t2[2]) luaG_runerror(L, "attempt to compare two %s values", t1); else luaG_runerror(L, "attempt to compare %s with %s", t1, t2); return 0; } static void addinfo (lua_State *L, const char *msg) { CallInfo *ci = L->ci; if (isLua(ci)) { /* is Lua code? */ char buff[LUA_IDSIZE]; /* add file:line information */ int line = currentline(L, ci); luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } } void luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ incr_top(L); luaD_call(L, L->top - 2, 1); /* call it */ } luaD_throw(L, LUA_ERRRUN); } void luaG_runerror (lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); addinfo(L, luaO_pushvfstring(L, fmt, argp)); va_end(argp); luaG_errormsg(L); } tagua-1.0-alpha2/lua/src/ldebug.h000066400000000000000000000020411077523320400166030ustar00rootroot00000000000000/* ** $Id: ldebug.h,v 2.3 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ #ifndef ldebug_h #define ldebug_h #include "lstate.h" #define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) #define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) #define resethookcount(L) (L->hookcount = L->basehookcount) LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o, const char *opname); LUAI_FUNC void luaG_concaterror (lua_State *L, StkId p1, StkId p2); LUAI_FUNC void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...); LUAI_FUNC void luaG_errormsg (lua_State *L); LUAI_FUNC int luaG_checkcode (const Proto *pt); LUAI_FUNC int luaG_checkopenop (Instruction i); #endif tagua-1.0-alpha2/lua/src/ldo.c000066400000000000000000000346171077523320400161300ustar00rootroot00000000000000/* ** $Id: ldo.c,v 2.38 2006/06/05 19:36:14 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ #include #include #include #define ldo_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lundump.h" #include "lvm.h" #include "lzio.h" /* ** {====================================================== ** Error-recovery functions ** ======================================================= */ /* chain list of long jump buffers */ struct lua_longjmp { struct lua_longjmp *previous; luai_jmpbuf b; volatile int status; /* error code */ }; void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { case LUA_ERRMEM: { setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); break; } case LUA_ERRERR: { setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } case LUA_ERRSYNTAX: case LUA_ERRRUN: { setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ break; } } L->top = oldtop + 1; } static void restore_stack_limit (lua_State *L) { lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ int inuse = cast_int(L->ci - L->base_ci); if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ luaD_reallocCI(L, LUAI_MAXCALLS); } } static void resetstack (lua_State *L, int status) { L->ci = L->base_ci; L->base = L->ci->base; luaF_close(L, L->base); /* close eventual pending closures */ luaD_seterrorobj(L, status, L->base); L->nCcalls = 0; L->allowhook = 1; restore_stack_limit(L); L->errfunc = 0; L->errorJmp = NULL; } void luaD_throw (lua_State *L, int errcode) { if (L->errorJmp) { L->errorJmp->status = errcode; LUAI_THROW(L, L->errorJmp); } else { L->status = cast_byte(errcode); if (G(L)->panic) { resetstack(L, errcode); lua_unlock(L); G(L)->panic(L); } exit(EXIT_FAILURE); } } int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { struct lua_longjmp lj; lj.status = 0; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; LUAI_TRY(L, &lj, (*f)(L, ud); ); L->errorJmp = lj.previous; /* restore old error handler */ return lj.status; } /* }====================================================== */ static void correctstack (lua_State *L, TValue *oldstack) { CallInfo *ci; GCObject *up; L->top = (L->top - oldstack) + L->stack; for (up = L->openupval; up != NULL; up = up->gch.next) gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; for (ci = L->base_ci; ci <= L->ci; ci++) { ci->top = (ci->top - oldstack) + L->stack; ci->base = (ci->base - oldstack) + L->stack; ci->func = (ci->func - oldstack) + L->stack; } L->base = (L->base - oldstack) + L->stack; } void luaD_reallocstack (lua_State *L, int newsize) { TValue *oldstack = L->stack; int realsize = newsize + 1 + EXTRA_STACK; lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); L->stacksize = realsize; L->stack_last = L->stack+newsize; correctstack(L, oldstack); } void luaD_reallocCI (lua_State *L, int newsize) { CallInfo *oldci = L->base_ci; luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); L->size_ci = newsize; L->ci = (L->ci - oldci) + L->base_ci; L->end_ci = L->base_ci + L->size_ci - 1; } void luaD_growstack (lua_State *L, int n) { if (n <= L->stacksize) /* double size is enough? */ luaD_reallocstack(L, 2*L->stacksize); else luaD_reallocstack(L, L->stacksize + n); } static CallInfo *growCI (lua_State *L) { if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ luaD_throw(L, LUA_ERRERR); else { luaD_reallocCI(L, 2*L->size_ci); if (L->size_ci > LUAI_MAXCALLS) luaG_runerror(L, "stack overflow"); } return ++L->ci; } void luaD_callhook (lua_State *L, int event, int line) { lua_Hook hook = L->hook; if (hook && L->allowhook) { ptrdiff_t top = savestack(L, L->top); ptrdiff_t ci_top = savestack(L, L->ci->top); lua_Debug ar; ar.event = event; ar.currentline = line; if (event == LUA_HOOKTAILRET) ar.i_ci = 0; /* tail call; no debug information about it */ else ar.i_ci = cast_int(L->ci - L->base_ci); luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ L->ci->top = L->top + LUA_MINSTACK; lua_assert(L->ci->top <= L->stack_last); L->allowhook = 0; /* cannot call hooks inside a hook */ lua_unlock(L); (*hook)(L, &ar); lua_lock(L); lua_assert(!L->allowhook); L->allowhook = 1; L->ci->top = restorestack(L, ci_top); L->top = restorestack(L, top); } } static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int i; int nfixargs = p->numparams; Table *htab = NULL; StkId base, fixed; for (; actual < nfixargs; ++actual) setnilvalue(L->top++); #if defined(LUA_COMPAT_VARARG) if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ int nvar = actual - nfixargs; /* number of extra arguments */ lua_assert(p->is_vararg & VARARG_HASARG); luaC_checkGC(L); htab = luaH_new(L, nvar, 1); /* create `arg' table */ for (i=0; itop - nvar + i); /* store counter in field `n' */ setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); } #endif /* move fixed parameters to final position */ fixed = L->top - actual; /* first fixed argument */ base = L->top; /* final position of first argument */ for (i=0; itop++, fixed+i); setnilvalue(fixed+i); } /* add `arg' parameter */ if (htab) { sethvalue(L, L->top++, htab); lua_assert(iswhite(obj2gco(htab))); } return base; } static StkId tryfuncTM (lua_State *L, StkId func) { const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); StkId p; ptrdiff_t funcr = savestack(L, func); if (!ttisfunction(tm)) luaG_typeerror(L, func, "call"); /* Open a hole inside the stack at `func' */ for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); incr_top(L); func = restorestack(L, funcr); /* previous call may change stack */ setobj2s(L, func, tm); /* tag method is the new function to be called */ return func; } #define inc_ci(L) \ ((L->ci == L->end_ci) ? growCI(L) : \ (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) int luaD_precall (lua_State *L, StkId func, int nresults) { LClosure *cl; ptrdiff_t funcr; if (!ttisfunction(func)) /* `func' is not a function? */ func = tryfuncTM(L, func); /* check the `function' tag method */ funcr = savestack(L, func); cl = &clvalue(func)->l; L->ci->savedpc = L->savedpc; if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; StkId st, base; Proto *p = cl->p; luaD_checkstack(L, p->maxstacksize); func = restorestack(L, funcr); if (!p->is_vararg) { /* no varargs? */ base = func + 1; if (L->top > base + p->numparams) L->top = base + p->numparams; } else { /* vararg function */ int nargs = cast_int(L->top - func) - 1; base = adjust_varargs(L, p, nargs); func = restorestack(L, funcr); /* previous call may change the stack */ } ci = inc_ci(L); /* now `enter' new function */ ci->func = func; L->base = ci->base = base; ci->top = L->base + p->maxstacksize; lua_assert(ci->top <= L->stack_last); L->savedpc = p->code; /* starting point */ ci->tailcalls = 0; ci->nresults = nresults; for (st = L->top; st < ci->top; st++) setnilvalue(st); L->top = ci->top; if (L->hookmask & LUA_MASKCALL) { L->savedpc++; /* hooks assume 'pc' is already incremented */ luaD_callhook(L, LUA_HOOKCALL, -1); L->savedpc--; /* correct 'pc' */ } return PCRLUA; } else { /* if is a C function, call it */ CallInfo *ci; int n; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ ci = inc_ci(L); /* now `enter' new function */ ci->func = restorestack(L, funcr); L->base = ci->base = ci->func + 1; ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); ci->nresults = nresults; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*curr_func(L)->c.f)(L); /* do the actual call */ lua_lock(L); if (n < 0) /* yielding? */ return PCRYIELD; else { luaD_poscall(L, L->top - n); return PCRC; } } } static StkId callrethooks (lua_State *L, StkId firstResult) { ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ luaD_callhook(L, LUA_HOOKRET, -1); if (f_isLua(L->ci)) { /* Lua function? */ while (L->ci->tailcalls--) /* call hook for eventual tail calls */ luaD_callhook(L, LUA_HOOKTAILRET, -1); } return restorestack(L, fr); } int luaD_poscall (lua_State *L, StkId firstResult) { StkId res; int wanted, i; CallInfo *ci; if (L->hookmask & LUA_MASKRET) firstResult = callrethooks(L, firstResult); ci = L->ci--; res = ci->func; /* res == final position of 1st result */ wanted = ci->nresults; L->base = (ci - 1)->base; /* restore base */ L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ /* move results to correct place */ for (i = wanted; i != 0 && firstResult < L->top; i--) setobjs2s(L, res++, firstResult++); while (i-- > 0) setnilvalue(res++); L->top = res; return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ } /* ** Call a function (C or Lua). The function to be called is at *func. ** The arguments are on the stack, right after the function. ** When returns, all the results are on the stack, starting at the original ** function position. */ void luaD_call (lua_State *L, StkId func, int nResults) { if (++L->nCcalls >= LUAI_MAXCCALLS) { if (L->nCcalls == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ luaV_execute(L, 1); /* call it */ L->nCcalls--; luaC_checkGC(L); } static void resume (lua_State *L, void *ud) { StkId firstArg = cast(StkId, ud); CallInfo *ci = L->ci; if (L->status == 0) { /* start coroutine? */ lua_assert(ci == L->base_ci && firstArg > L->base); if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) return; } else { /* resuming from previous yield */ lua_assert(L->status == LUA_YIELD); L->status = 0; if (!f_isLua(ci)) { /* `common' yield? */ /* finish interrupted execution of `OP_CALL' */ lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); if (luaD_poscall(L, firstArg)) /* complete it... */ L->top = L->ci->top; /* and correct top if not multiple results */ } else /* yielded inside a hook: just continue its execution */ L->base = L->ci->base; } luaV_execute(L, cast_int(L->ci - L->base_ci)); } static int resume_error (lua_State *L, const char *msg) { L->top = L->ci->base; setsvalue2s(L, L->top, luaS_new(L, msg)); incr_top(L); lua_unlock(L); return LUA_ERRRUN; } LUA_API int lua_resume (lua_State *L, int nargs) { int status; lua_lock(L); if (L->status != LUA_YIELD) { if (L->status != 0) return resume_error(L, "cannot resume dead coroutine"); else if (L->ci != L->base_ci) return resume_error(L, "cannot resume non-suspended coroutine"); } luai_userstateresume(L, nargs); lua_assert(L->errfunc == 0 && L->nCcalls == 0); status = luaD_rawrunprotected(L, resume, L->top - nargs); if (status != 0) { /* error? */ L->status = cast_byte(status); /* mark thread as `dead' */ luaD_seterrorobj(L, status, L->top); L->ci->top = L->top; } else status = L->status; lua_unlock(L); return status; } LUA_API int lua_yield (lua_State *L, int nresults) { luai_userstateyield(L, nresults); lua_lock(L); if (L->nCcalls > 0) luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); L->base = L->top - nresults; /* protect stack slots below */ L->status = LUA_YIELD; lua_unlock(L); return -1; } int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; unsigned short oldnCcalls = L->nCcalls; ptrdiff_t old_ci = saveci(L, L->ci); lu_byte old_allowhooks = L->allowhook; ptrdiff_t old_errfunc = L->errfunc; L->errfunc = ef; status = luaD_rawrunprotected(L, func, u); if (status != 0) { /* an error occurred? */ StkId oldtop = restorestack(L, old_top); luaF_close(L, oldtop); /* close eventual pending closures */ luaD_seterrorobj(L, status, oldtop); L->nCcalls = oldnCcalls; L->ci = restoreci(L, old_ci); L->base = L->ci->base; L->savedpc = L->ci->savedpc; L->allowhook = old_allowhooks; restore_stack_limit(L); } L->errfunc = old_errfunc; return status; } /* ** Execute a protected parser. */ struct SParser { /* data to `f_parser' */ ZIO *z; Mbuffer buff; /* buffer to be used by the scanner */ const char *name; }; static void f_parser (lua_State *L, void *ud) { int i; Proto *tf; Closure *cl; struct SParser *p = cast(struct SParser *, ud); int c = luaZ_lookahead(p->z); luaC_checkGC(L); tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, &p->buff, p->name); cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); cl->l.p = tf; for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ cl->l.upvals[i] = luaF_newupval(L); setclvalue(L, L->top, cl); incr_top(L); } int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { struct SParser p; int status; p.z = z; p.name = name; luaZ_initbuffer(L, &p.buff); status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); luaZ_freebuffer(L, &p.buff); return status; } tagua-1.0-alpha2/lua/src/ldo.h000066400000000000000000000035451077523320400161310ustar00rootroot00000000000000/* ** $Id: ldo.h,v 2.7 2005/08/24 16:15:49 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ #ifndef ldo_h #define ldo_h #include "lobject.h" #include "lstate.h" #include "lzio.h" #define luaD_checkstack(L,n) \ if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ luaD_growstack(L, n); \ else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); #define incr_top(L) {luaD_checkstack(L,1); L->top++;} #define savestack(L,p) ((char *)(p) - (char *)L->stack) #define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) #define saveci(L,p) ((char *)(p) - (char *)L->base_ci) #define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) /* results from luaD_precall */ #define PCRLUA 0 /* initiated a call to a Lua function */ #define PCRC 1 /* did a call to a C function */ #define PCRYIELD 2 /* C funtion yielded */ /* type of protected functions, to be ran by `runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize); LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); LUAI_FUNC void luaD_growstack (lua_State *L, int n); LUAI_FUNC void luaD_throw (lua_State *L, int errcode); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); #endif tagua-1.0-alpha2/lua/src/ldump.c000066400000000000000000000060431077523320400164630ustar00rootroot00000000000000/* ** $Id: ldump.c,v 1.15 2006/02/16 15:53:49 lhf Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ #include #define ldump_c #define LUA_CORE #include "lua.h" #include "lobject.h" #include "lstate.h" #include "lundump.h" typedef struct { lua_State* L; lua_Writer writer; void* data; int strip; int status; } DumpState; #define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) #define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) static void DumpBlock(const void* b, size_t size, DumpState* D) { if (D->status==0) { lua_unlock(D->L); D->status=(*D->writer)(D->L,b,size,D->data); lua_lock(D->L); } } static void DumpChar(int y, DumpState* D) { char x=(char)y; DumpVar(x,D); } static void DumpInt(int x, DumpState* D) { DumpVar(x,D); } static void DumpNumber(lua_Number x, DumpState* D) { DumpVar(x,D); } static void DumpVector(const void* b, int n, size_t size, DumpState* D) { DumpInt(n,D); DumpMem(b,n,size,D); } static void DumpString(const TString* s, DumpState* D) { if (s==NULL || getstr(s)==NULL) { size_t size=0; DumpVar(size,D); } else { size_t size=s->tsv.len+1; /* include trailing '\0' */ DumpVar(size,D); DumpBlock(getstr(s),size,D); } } #define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) static void DumpFunction(const Proto* f, const TString* p, DumpState* D); static void DumpConstants(const Proto* f, DumpState* D) { int i,n=f->sizek; DumpInt(n,D); for (i=0; ik[i]; DumpChar(ttype(o),D); switch (ttype(o)) { case LUA_TNIL: break; case LUA_TBOOLEAN: DumpChar(bvalue(o),D); break; case LUA_TNUMBER: DumpNumber(nvalue(o),D); break; case LUA_TSTRING: DumpString(rawtsvalue(o),D); break; default: lua_assert(0); /* cannot happen */ break; } } n=f->sizep; DumpInt(n,D); for (i=0; ip[i],f->source,D); } static void DumpDebug(const Proto* f, DumpState* D) { int i,n; n= (D->strip) ? 0 : f->sizelineinfo; DumpVector(f->lineinfo,n,sizeof(int),D); n= (D->strip) ? 0 : f->sizelocvars; DumpInt(n,D); for (i=0; ilocvars[i].varname,D); DumpInt(f->locvars[i].startpc,D); DumpInt(f->locvars[i].endpc,D); } n= (D->strip) ? 0 : f->sizeupvalues; DumpInt(n,D); for (i=0; iupvalues[i],D); } static void DumpFunction(const Proto* f, const TString* p, DumpState* D) { DumpString((f->source==p || D->strip) ? NULL : f->source,D); DumpInt(f->linedefined,D); DumpInt(f->lastlinedefined,D); DumpChar(f->nups,D); DumpChar(f->numparams,D); DumpChar(f->is_vararg,D); DumpChar(f->maxstacksize,D); DumpCode(f,D); DumpConstants(f,D); DumpDebug(f,D); } static void DumpHeader(DumpState* D) { char h[LUAC_HEADERSIZE]; luaU_header(h); DumpBlock(h,LUAC_HEADERSIZE,D); } /* ** dump Lua function as precompiled chunk */ int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) { DumpState D; D.L=L; D.writer=w; D.data=data; D.strip=strip; D.status=0; DumpHeader(&D); DumpFunction(f,NULL,&D); return D.status; } tagua-1.0-alpha2/lua/src/lfunc.c000066400000000000000000000110071077523320400164450ustar00rootroot00000000000000/* ** $Id: lfunc.c,v 2.12a 2005/12/22 16:19:56 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ #include #define lfunc_c #define LUA_CORE #include "lua.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->c.isC = 1; c->c.env = e; c->c.nupvalues = cast_byte(nelems); return c; } Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) { Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->l.isC = 0; c->l.env = e; c->l.nupvalues = cast_byte(nelems); while (nelems--) c->l.upvals[nelems] = NULL; return c; } UpVal *luaF_newupval (lua_State *L) { UpVal *uv = luaM_new(L, UpVal); luaC_link(L, obj2gco(uv), LUA_TUPVAL); uv->v = &uv->u.value; setnilvalue(uv->v); return uv; } UpVal *luaF_findupval (lua_State *L, StkId level) { global_State *g = G(L); GCObject **pp = &L->openupval; UpVal *p; UpVal *uv; while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) { lua_assert(p->v != &p->u.value); if (p->v == level) { /* found a corresponding upvalue? */ if (isdead(g, obj2gco(p))) /* is it dead? */ changewhite(obj2gco(p)); /* ressurect it */ return p; } pp = &p->next; } uv = luaM_new(L, UpVal); /* not found: create a new one */ uv->tt = LUA_TUPVAL; uv->marked = luaC_white(g); uv->v = level; /* current value lives in the stack */ uv->next = *pp; /* chain it in the proper position */ *pp = obj2gco(uv); uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ uv->u.l.next = g->uvhead.u.l.next; uv->u.l.next->u.l.prev = uv; g->uvhead.u.l.next = uv; lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); return uv; } static void unlinkupval (UpVal *uv) { lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */ uv->u.l.prev->u.l.next = uv->u.l.next; } void luaF_freeupval (lua_State *L, UpVal *uv) { if (uv->v != &uv->u.value) /* is it open? */ unlinkupval(uv); /* remove from open list */ luaM_free(L, uv); /* free upvalue */ } void luaF_close (lua_State *L, StkId level) { UpVal *uv; global_State *g = G(L); while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) { GCObject *o = obj2gco(uv); lua_assert(!isblack(o) && uv->v != &uv->u.value); L->openupval = uv->next; /* remove from `open' list */ if (isdead(g, o)) luaF_freeupval(L, uv); /* free upvalue */ else { unlinkupval(uv); setobj(L, &uv->u.value, uv->v); uv->v = &uv->u.value; /* now current value lives here */ luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ } } } Proto *luaF_newproto (lua_State *L) { Proto *f = luaM_new(L, Proto); luaC_link(L, obj2gco(f), LUA_TPROTO); f->k = NULL; f->sizek = 0; f->p = NULL; f->sizep = 0; f->code = NULL; f->sizecode = 0; f->sizelineinfo = 0; f->sizeupvalues = 0; f->nups = 0; f->upvalues = NULL; f->numparams = 0; f->is_vararg = 0; f->maxstacksize = 0; f->lineinfo = NULL; f->sizelocvars = 0; f->locvars = NULL; f->linedefined = 0; f->lastlinedefined = 0; f->source = NULL; return f; } void luaF_freeproto (lua_State *L, Proto *f) { luaM_freearray(L, f->code, f->sizecode, Instruction); luaM_freearray(L, f->p, f->sizep, Proto *); luaM_freearray(L, f->k, f->sizek, TValue); luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); luaM_free(L, f); } void luaF_freeclosure (lua_State *L, Closure *c) { int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : sizeLclosure(c->l.nupvalues); luaM_freemem(L, c, size); } /* ** Look for n-th local variable at line `line' in function `func'. ** Returns NULL if not found. */ const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { int i; for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { if (pc < f->locvars[i].endpc) { /* is variable active? */ local_number--; if (local_number == 0) return getstr(f->locvars[i].varname); } } return NULL; /* not found */ } tagua-1.0-alpha2/lua/src/lfunc.h000066400000000000000000000021411077523320400164510ustar00rootroot00000000000000/* ** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ #ifndef lfunc_h #define lfunc_h #include "lobject.h" #define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ cast(int, sizeof(TValue)*((n)-1))) #define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ cast(int, sizeof(TValue *)*((n)-1))) LUAI_FUNC Proto *luaF_newproto (lua_State *L); LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); LUAI_FUNC UpVal *luaF_newupval (lua_State *L); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_close (lua_State *L, StkId level); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c); LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, int pc); #endif tagua-1.0-alpha2/lua/src/lgc.c000066400000000000000000000471771077523320400161240ustar00rootroot00000000000000/* ** $Id: lgc.c,v 2.38 2006/05/24 14:34:06 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ #include #define lgc_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #define GCSTEPSIZE 1024u #define GCSWEEPMAX 40 #define GCSWEEPCOST 10 #define GCFINALIZECOST 100 #define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) #define makewhite(g,x) \ ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) #define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) #define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) #define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) #define KEYWEAK bitmask(KEYWEAKBIT) #define VALUEWEAK bitmask(VALUEWEAKBIT) #define markvalue(g,o) { checkconsistency(o); \ if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } #define markobject(g,t) { if (iswhite(obj2gco(t))) \ reallymarkobject(g, obj2gco(t)); } #define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) static void removeentry (Node *n) { lua_assert(ttisnil(gval(n))); if (iscollectable(gkey(n))) setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ } static void reallymarkobject (global_State *g, GCObject *o) { lua_assert(iswhite(o) && !isdead(g, o)); white2gray(o); switch (o->gch.tt) { case LUA_TSTRING: { return; } case LUA_TUSERDATA: { Table *mt = gco2u(o)->metatable; gray2black(o); /* udata are never gray */ if (mt) markobject(g, mt); markobject(g, gco2u(o)->env); return; } case LUA_TUPVAL: { UpVal *uv = gco2uv(o); markvalue(g, uv->v); if (uv->v == &uv->u.value) /* closed? */ gray2black(o); /* open upvalues are never black */ return; } case LUA_TFUNCTION: { gco2cl(o)->c.gclist = g->gray; g->gray = o; break; } case LUA_TTABLE: { gco2h(o)->gclist = g->gray; g->gray = o; break; } case LUA_TTHREAD: { gco2th(o)->gclist = g->gray; g->gray = o; break; } case LUA_TPROTO: { gco2p(o)->gclist = g->gray; g->gray = o; break; } default: lua_assert(0); } } static void marktmu (global_State *g) { GCObject *u = g->tmudata; if (u) { do { u = u->gch.next; makewhite(g, u); /* may be marked, if left from previous GC */ reallymarkobject(g, u); } while (u != g->tmudata); } } /* move `dead' udata that need finalization to list `tmudata' */ size_t luaC_separateudata (lua_State *L, int all) { global_State *g = G(L); size_t deadmem = 0; GCObject **p = &g->mainthread->next; GCObject *curr; while ((curr = *p) != NULL) { if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) p = &curr->gch.next; /* don't bother with them */ else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { markfinalized(gco2u(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ deadmem += sizeudata(gco2u(curr)); markfinalized(gco2u(curr)); *p = curr->gch.next; /* link `curr' at the end of `tmudata' list */ if (g->tmudata == NULL) /* list is empty? */ g->tmudata = curr->gch.next = curr; /* creates a circular list */ else { curr->gch.next = g->tmudata->gch.next; g->tmudata->gch.next = curr; g->tmudata = curr; } } } return deadmem; } static int traversetable (global_State *g, Table *h) { int i; int weakkey = 0; int weakvalue = 0; const TValue *mode; if (h->metatable) markobject(g, h->metatable); mode = gfasttm(g, h->metatable, TM_MODE); if (mode && ttisstring(mode)) { /* is there a weak mode? */ weakkey = (strchr(svalue(mode), 'k') != NULL); weakvalue = (strchr(svalue(mode), 'v') != NULL); if (weakkey || weakvalue) { /* is really weak? */ h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ h->marked |= cast_byte((weakkey << KEYWEAKBIT) | (weakvalue << VALUEWEAKBIT)); h->gclist = g->weak; /* must be cleared after GC, ... */ g->weak = obj2gco(h); /* ... so put in the appropriate list */ } } if (weakkey && weakvalue) return 1; if (!weakvalue) { i = h->sizearray; while (i--) markvalue(g, &h->array[i]); } i = sizenode(h); while (i--) { Node *n = gnode(h, i); lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); if (ttisnil(gval(n))) removeentry(n); /* remove empty entries */ else { lua_assert(!ttisnil(gkey(n))); if (!weakkey) markvalue(g, gkey(n)); if (!weakvalue) markvalue(g, gval(n)); } } return weakkey || weakvalue; } /* ** All marks are conditional because a GC may happen while the ** prototype is still being created */ static void traverseproto (global_State *g, Proto *f) { int i; if (f->source) stringmark(f->source); for (i=0; isizek; i++) /* mark literals */ markvalue(g, &f->k[i]); for (i=0; isizeupvalues; i++) { /* mark upvalue names */ if (f->upvalues[i]) stringmark(f->upvalues[i]); } for (i=0; isizep; i++) { /* mark nested protos */ if (f->p[i]) markobject(g, f->p[i]); } for (i=0; isizelocvars; i++) { /* mark local-variable names */ if (f->locvars[i].varname) stringmark(f->locvars[i].varname); } } static void traverseclosure (global_State *g, Closure *cl) { markobject(g, cl->c.env); if (cl->c.isC) { int i; for (i=0; ic.nupvalues; i++) /* mark its upvalues */ markvalue(g, &cl->c.upvalue[i]); } else { int i; lua_assert(cl->l.nupvalues == cl->l.p->nups); markobject(g, cl->l.p); for (i=0; il.nupvalues; i++) /* mark its upvalues */ markobject(g, cl->l.upvals[i]); } } static void checkstacksizes (lua_State *L, StkId max) { int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */ int s_used = cast_int(max - L->stack); /* part of stack in use */ if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ return; /* do not touch the stacks */ if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ condhardstacktests(luaD_reallocCI(L, ci_used + 1)); if (4*s_used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ condhardstacktests(luaD_reallocstack(L, s_used)); } static void traversestack (global_State *g, lua_State *l) { StkId o, lim; CallInfo *ci; markvalue(g, gt(l)); lim = l->top; for (ci = l->base_ci; ci <= l->ci; ci++) { lua_assert(ci->top <= l->stack_last); if (lim < ci->top) lim = ci->top; } for (o = l->stack; o < l->top; o++) markvalue(g, o); for (; o <= lim; o++) setnilvalue(o); checkstacksizes(l, lim); } /* ** traverse one gray object, turning it to black. ** Returns `quantity' traversed. */ static l_mem propagatemark (global_State *g) { GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); switch (o->gch.tt) { case LUA_TTABLE: { Table *h = gco2h(o); g->gray = h->gclist; if (traversetable(g, h)) /* table is weak? */ black2gray(o); /* keep it gray */ return sizeof(Table) + sizeof(TValue) * h->sizearray + sizeof(Node) * sizenode(h); } case LUA_TFUNCTION: { Closure *cl = gco2cl(o); g->gray = cl->c.gclist; traverseclosure(g, cl); return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : sizeLclosure(cl->l.nupvalues); } case LUA_TTHREAD: { lua_State *th = gco2th(o); g->gray = th->gclist; th->gclist = g->grayagain; g->grayagain = o; black2gray(o); traversestack(g, th); return sizeof(lua_State) + sizeof(TValue) * th->stacksize + sizeof(CallInfo) * th->size_ci; } case LUA_TPROTO: { Proto *p = gco2p(o); g->gray = p->gclist; traverseproto(g, p); return sizeof(Proto) + sizeof(Instruction) * p->sizecode + sizeof(Proto *) * p->sizep + sizeof(TValue) * p->sizek + sizeof(int) * p->sizelineinfo + sizeof(LocVar) * p->sizelocvars + sizeof(TString *) * p->sizeupvalues; } default: lua_assert(0); return 0; } } static size_t propagateall (global_State *g) { size_t m = 0; while (g->gray) m += propagatemark(g); return m; } /* ** The next function tells whether a key or value can be cleared from ** a weak table. Non-collectable objects are never removed from weak ** tables. Strings behave as `values', so are never removed too. for ** other objects: if really collected, cannot keep them; for userdata ** being finalized, keep them in keys, but not in values */ static int iscleared (const TValue *o, int iskey) { if (!iscollectable(o)) return 0; if (ttisstring(o)) { stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ return 0; } return iswhite(gcvalue(o)) || (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); } /* ** clear collected entries from weaktables */ static void cleartable (GCObject *l) { while (l) { Table *h = gco2h(l); int i = h->sizearray; lua_assert(testbit(h->marked, VALUEWEAKBIT) || testbit(h->marked, KEYWEAKBIT)); if (testbit(h->marked, VALUEWEAKBIT)) { while (i--) { TValue *o = &h->array[i]; if (iscleared(o, 0)) /* value was collected? */ setnilvalue(o); /* remove value */ } } i = sizenode(h); while (i--) { Node *n = gnode(h, i); if (!ttisnil(gval(n)) && /* non-empty entry? */ (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* remove entry from table */ } } l = h->gclist; } } static void freeobj (lua_State *L, GCObject *o) { switch (o->gch.tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; case LUA_TTABLE: luaH_free(L, gco2h(o)); break; case LUA_TTHREAD: { lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); luaE_freethread(L, gco2th(o)); break; } case LUA_TSTRING: { G(L)->strt.nuse--; luaM_freemem(L, o, sizestring(gco2ts(o))); break; } case LUA_TUSERDATA: { luaM_freemem(L, o, sizeudata(gco2u(o))); break; } default: lua_assert(0); } } #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { GCObject *curr; global_State *g = G(L); int deadmask = otherwhite(g); while ((curr = *p) != NULL && count-- > 0) { if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ sweepwholelist(L, &gco2th(curr)->openupval); if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); makewhite(g, curr); /* make it white (for next cycle) */ p = &curr->gch.next; } else { /* must erase `curr' */ lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); *p = curr->gch.next; if (curr == g->rootgc) /* is the first element of the list? */ g->rootgc = curr->gch.next; /* adjust first */ freeobj(L, curr); } } return p; } static void checkSizes (lua_State *L) { global_State *g = G(L); /* check size of string hash */ if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && g->strt.size > MINSTRTABSIZE*2) luaS_resize(L, g->strt.size/2); /* table is too big */ /* check size of buffer */ if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ size_t newsize = luaZ_sizebuffer(&g->buff) / 2; luaZ_resizebuffer(L, &g->buff, newsize); } } static void GCTM (lua_State *L) { global_State *g = G(L); GCObject *o = g->tmudata->gch.next; /* get first element */ Udata *udata = rawgco2u(o); const TValue *tm; /* remove udata from `tmudata' */ if (o == g->tmudata) /* last element? */ g->tmudata = NULL; else g->tmudata->gch.next = udata->uv.next; udata->uv.next = g->mainthread->next; /* return it to `root' list */ g->mainthread->next = o; makewhite(g, o); tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { lu_byte oldah = L->allowhook; lu_mem oldt = g->GCthreshold; L->allowhook = 0; /* stop debug hooks during GC tag method */ g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ setobj2s(L, L->top, tm); setuvalue(L, L->top+1, udata); L->top += 2; luaD_call(L, L->top - 2, 0); L->allowhook = oldah; /* restore hooks */ g->GCthreshold = oldt; /* restore threshold */ } } /* ** Call all GC tag methods */ void luaC_callGCTM (lua_State *L) { while (G(L)->tmudata) GCTM(L); } void luaC_freeall (lua_State *L) { global_State *g = G(L); int i; g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */ sweepwholelist(L, &g->rootgc); for (i = 0; i < g->strt.size; i++) /* free all string lists */ sweepwholelist(L, &g->strt.hash[i]); } static void markmt (global_State *g) { int i; for (i=0; imt[i]) markobject(g, g->mt[i]); } /* mark root set */ static void markroot (lua_State *L) { global_State *g = G(L); g->gray = NULL; g->grayagain = NULL; g->weak = NULL; markobject(g, g->mainthread); /* make global table be traversed before main stack */ markvalue(g, gt(g->mainthread)); markvalue(g, registry(L)); markmt(g); g->gcstate = GCSpropagate; } static void remarkupvals (global_State *g) { UpVal *uv; for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); if (isgray(obj2gco(uv))) markvalue(g, uv->v); } } static void atomic (lua_State *L) { global_State *g = G(L); size_t udsize; /* total size of userdata to be finalized */ /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); /* traverse objects cautch by write barrier and by 'remarkupvals' */ propagateall(g); /* remark weak tables */ g->gray = g->weak; g->weak = NULL; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ markmt(g); /* mark basic metatables (again) */ propagateall(g); /* remark gray again */ g->gray = g->grayagain; g->grayagain = NULL; propagateall(g); udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ marktmu(g); /* mark `preserved' userdata */ udsize += propagateall(g); /* remark, to propagate `preserveness' */ cleartable(g->weak); /* remove collected objects from weak tables */ /* flip current white */ g->currentwhite = cast_byte(otherwhite(g)); g->sweepstrgc = 0; g->sweepgc = &g->rootgc; g->gcstate = GCSsweepstring; g->estimate = g->totalbytes - udsize; /* first estimate */ } static l_mem singlestep (lua_State *L) { global_State *g = G(L); /*lua_checkmemory(L);*/ switch (g->gcstate) { case GCSpause: { markroot(L); /* start a new collection */ return 0; } case GCSpropagate: { if (g->gray) return propagatemark(g); else { /* no more `gray' objects */ atomic(L); /* finish mark phase */ return 0; } } case GCSsweepstring: { lu_mem old = g->totalbytes; sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ g->gcstate = GCSsweep; /* end sweep-string phase */ lua_assert(old >= g->totalbytes); g->estimate -= old - g->totalbytes; return GCSWEEPCOST; } case GCSsweep: { lu_mem old = g->totalbytes; g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); if (*g->sweepgc == NULL) { /* nothing more to sweep? */ checkSizes(L); g->gcstate = GCSfinalize; /* end sweep phase */ } lua_assert(old >= g->totalbytes); g->estimate -= old - g->totalbytes; return GCSWEEPMAX*GCSWEEPCOST; } case GCSfinalize: { if (g->tmudata) { GCTM(L); if (g->estimate > GCFINALIZECOST) g->estimate -= GCFINALIZECOST; return GCFINALIZECOST; } else { g->gcstate = GCSpause; /* end collection */ g->gcdept = 0; return 0; } } default: lua_assert(0); return 0; } } void luaC_step (lua_State *L) { global_State *g = G(L); l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; if (lim == 0) lim = (MAX_LUMEM-1)/2; /* no limit */ g->gcdept += g->totalbytes - g->GCthreshold; do { lim -= singlestep(L); if (g->gcstate == GCSpause) break; } while (lim > 0); if (g->gcstate != GCSpause) { if (g->gcdept < GCSTEPSIZE) g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/ else { g->gcdept -= GCSTEPSIZE; g->GCthreshold = g->totalbytes; } } else { lua_assert(g->totalbytes >= g->estimate); setthreshold(g); } } void luaC_fullgc (lua_State *L) { global_State *g = G(L); if (g->gcstate <= GCSpropagate) { /* reset sweep marks to sweep all elements (returning them to white) */ g->sweepstrgc = 0; g->sweepgc = &g->rootgc; /* reset other collector lists */ g->gray = NULL; g->grayagain = NULL; g->weak = NULL; g->gcstate = GCSsweepstring; } lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); /* finish any pending sweep phase */ while (g->gcstate != GCSfinalize) { lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); singlestep(L); } markroot(L); while (g->gcstate != GCSpause) { singlestep(L); } setthreshold(g); } void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); lua_assert(ttype(&o->gch) != LUA_TTABLE); /* must keep invariant? */ if (g->gcstate == GCSpropagate) reallymarkobject(g, v); /* restore invariant */ else /* don't mind */ makewhite(g, o); /* mark as white just to avoid other barriers */ } void luaC_barrierback (lua_State *L, Table *t) { global_State *g = G(L); GCObject *o = obj2gco(t); lua_assert(isblack(o) && !isdead(g, o)); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); black2gray(o); /* make table gray (again) */ t->gclist = g->grayagain; g->grayagain = o; } void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { global_State *g = G(L); o->gch.next = g->rootgc; g->rootgc = o; o->gch.marked = luaC_white(g); o->gch.tt = tt; } void luaC_linkupval (lua_State *L, UpVal *uv) { global_State *g = G(L); GCObject *o = obj2gco(uv); o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ g->rootgc = o; if (isgray(o)) { if (g->gcstate == GCSpropagate) { gray2black(o); /* closed upvalues need barrier */ luaC_barrier(L, uv, uv->v); } else { /* sweep phase: sweep it (turning it into white) */ makewhite(g, o); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); } } } tagua-1.0-alpha2/lua/src/lgc.h000066400000000000000000000061231077523320400161130ustar00rootroot00000000000000/* ** $Id: lgc.h,v 2.15 2005/08/24 16:15:49 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ #ifndef lgc_h #define lgc_h #include "lobject.h" /* ** Possible states of the Garbage Collector */ #define GCSpause 0 #define GCSpropagate 1 #define GCSsweepstring 2 #define GCSsweep 3 #define GCSfinalize 4 /* ** some userful bit tricks */ #define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) #define setbits(x,m) ((x) |= (m)) #define testbits(x,m) ((x) & (m)) #define bitmask(b) (1<<(b)) #define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) #define l_setbit(x,b) setbits(x, bitmask(b)) #define resetbit(x,b) resetbits(x, bitmask(b)) #define testbit(x,b) testbits(x, bitmask(b)) #define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) #define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) #define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2))) /* ** Layout for bit use in `marked' field: ** bit 0 - object is white (type 0) ** bit 1 - object is white (type 1) ** bit 2 - object is black ** bit 3 - for userdata: has been finalized ** bit 3 - for tables: has weak keys ** bit 4 - for tables: has weak values ** bit 5 - object is fixed (should not be collected) ** bit 6 - object is "super" fixed (only the main thread) */ #define WHITE0BIT 0 #define WHITE1BIT 1 #define BLACKBIT 2 #define FINALIZEDBIT 3 #define KEYWEAKBIT 3 #define VALUEWEAKBIT 4 #define FIXEDBIT 5 #define SFIXEDBIT 6 #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) #define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) #define isblack(x) testbit((x)->gch.marked, BLACKBIT) #define isgray(x) (!isblack(x) && !iswhite(x)) #define otherwhite(g) (g->currentwhite ^ WHITEBITS) #define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS) #define changewhite(x) ((x)->gch.marked ^= WHITEBITS) #define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) #define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) #define luaC_checkGC(L) { \ condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ if (G(L)->totalbytes >= G(L)->GCthreshold) \ luaC_step(L); } #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ luaC_barrierf(L,obj2gco(p),gcvalue(v)); } #define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) \ luaC_barrierback(L,t); } #define luaC_objbarrier(L,p,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ luaC_barrierf(L,obj2gco(p),obj2gco(o)); } #define luaC_objbarriert(L,t,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); LUAI_FUNC void luaC_callGCTM (lua_State *L); LUAI_FUNC void luaC_freeall (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L); LUAI_FUNC void luaC_fullgc (lua_State *L); LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt); LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); #endif tagua-1.0-alpha2/lua/src/linit.c000066400000000000000000000013711077523320400164600ustar00rootroot00000000000000/* ** $Id: linit.c,v 1.14 2005/12/29 15:32:11 roberto Exp $ ** Initialization of libraries for lua.c ** See Copyright Notice in lua.h */ #define linit_c #define LUA_LIB #include "lua.h" #include "lualib.h" #include "lauxlib.h" static const luaL_Reg lualibs[] = { {"", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {NULL, NULL} }; LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib = lualibs; for (; lib->func; lib++) { lua_pushcfunction(L, lib->func); lua_pushstring(L, lib->name); lua_call(L, 1, 0); } } tagua-1.0-alpha2/lua/src/liolib.c000066400000000000000000000312721077523320400166160ustar00rootroot00000000000000/* ** $Id: liolib.c,v 2.73 2006/05/08 20:14:16 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ #include #include #include #include #define liolib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" #define IO_INPUT 1 #define IO_OUTPUT 2 static const char *const fnames[] = {"input", "output"}; static int pushresult (lua_State *L, int i, const char *filename) { int en = errno; /* calls to Lua API may change this value */ if (i) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); if (filename) lua_pushfstring(L, "%s: %s", filename, strerror(en)); else lua_pushfstring(L, "%s", strerror(en)); lua_pushinteger(L, en); return 3; } } static void fileerror (lua_State *L, int arg, const char *filename) { lua_pushfstring(L, "%s: %s", filename, strerror(errno)); luaL_argerror(L, arg, lua_tostring(L, -1)); } #define topfile(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) static int io_type (lua_State *L) { void *ud; luaL_checkany(L, 1); ud = lua_touserdata(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) lua_pushnil(L); /* not a file */ else if (*((FILE **)ud) == NULL) lua_pushliteral(L, "closed file"); else lua_pushliteral(L, "file"); return 1; } static FILE *tofile (lua_State *L) { FILE **f = topfile(L); if (*f == NULL) luaL_error(L, "attempt to use a closed file"); return *f; } /* ** When creating file handles, always creates a `closed' file handle ** before opening the actual file; so, if there is a memory error, the ** file is not left opened. */ static FILE **newfile (lua_State *L) { FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); *pf = NULL; /* file handle is currently `closed' */ luaL_getmetatable(L, LUA_FILEHANDLE); lua_setmetatable(L, -2); return pf; } /* ** this function has a separated environment, which defines the ** correct __close for 'popen' files */ static int io_pclose (lua_State *L) { FILE **p = topfile(L); int ok = lua_pclose(L, *p); *p = NULL; return pushresult(L, ok, NULL); } static int io_fclose (lua_State *L) { FILE **p = topfile(L); int ok = (fclose(*p) == 0); *p = NULL; return pushresult(L, ok, NULL); } static int aux_close (lua_State *L) { lua_getfenv(L, 1); lua_getfield(L, -1, "__close"); return (lua_tocfunction(L, -1))(L); } static int io_close (lua_State *L) { if (lua_isnone(L, 1)) lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); tofile(L); /* make sure argument is a file */ return aux_close(L); } static int io_gc (lua_State *L) { FILE *f = *topfile(L); /* ignore closed files and standard files */ if (f != NULL && f != stdin && f != stdout && f != stderr) aux_close(L); return 0; } static int io_tostring (lua_State *L) { FILE *f = *topfile(L); if (f == NULL) lua_pushstring(L, "file (closed)"); else lua_pushfstring(L, "file (%p)", f); return 1; } static int io_open (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); FILE **pf = newfile(L); *pf = fopen(filename, mode); return (*pf == NULL) ? pushresult(L, 0, filename) : 1; } static int io_popen (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); FILE **pf = newfile(L); *pf = lua_popen(L, filename, mode); return (*pf == NULL) ? pushresult(L, 0, filename) : 1; } static int io_tmpfile (lua_State *L) { FILE **pf = newfile(L); *pf = tmpfile(); return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; } static FILE *getiofile (lua_State *L, int findex) { FILE *f; lua_rawgeti(L, LUA_ENVIRONINDEX, findex); f = *(FILE **)lua_touserdata(L, -1); if (f == NULL) luaL_error(L, "standard %s file is closed", fnames[findex - 1]); return f; } static int g_iofile (lua_State *L, int f, const char *mode) { if (!lua_isnoneornil(L, 1)) { const char *filename = lua_tostring(L, 1); if (filename) { FILE **pf = newfile(L); *pf = fopen(filename, mode); if (*pf == NULL) fileerror(L, 1, filename); } else { tofile(L); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } lua_rawseti(L, LUA_ENVIRONINDEX, f); } /* return current value */ lua_rawgeti(L, LUA_ENVIRONINDEX, f); return 1; } static int io_input (lua_State *L) { return g_iofile(L, IO_INPUT, "r"); } static int io_output (lua_State *L) { return g_iofile(L, IO_OUTPUT, "w"); } static int io_readline (lua_State *L); static void aux_lines (lua_State *L, int idx, int toclose) { lua_pushvalue(L, idx); lua_pushboolean(L, toclose); /* close/not close file when finished */ lua_pushcclosure(L, io_readline, 2); } static int f_lines (lua_State *L) { tofile(L); /* check that it's a valid file handle */ aux_lines(L, 1, 0); return 1; } static int io_lines (lua_State *L) { if (lua_isnoneornil(L, 1)) { /* no arguments? */ /* will iterate over default input */ lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); return f_lines(L); } else { const char *filename = luaL_checkstring(L, 1); FILE **pf = newfile(L); *pf = fopen(filename, "r"); if (*pf == NULL) fileerror(L, 1, filename); aux_lines(L, lua_gettop(L), 1); return 1; } } /* ** {====================================================== ** READ ** ======================================================= */ static int read_number (lua_State *L, FILE *f) { lua_Number d; if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { lua_pushnumber(L, d); return 1; } else return 0; /* read fails */ } static int test_eof (lua_State *L, FILE *f) { int c = getc(f); ungetc(c, f); lua_pushlstring(L, NULL, 0); return (c != EOF); } static int read_line (lua_State *L, FILE *f) { luaL_Buffer b; luaL_buffinit(L, &b); for (;;) { size_t l; char *p = luaL_prepbuffer(&b); if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ luaL_pushresult(&b); /* close buffer */ return (lua_strlen(L, -1) > 0); /* check whether read something */ } l = strlen(p); if (l == 0 || p[l-1] != '\n') luaL_addsize(&b, l); else { luaL_addsize(&b, l - 1); /* do not include `eol' */ luaL_pushresult(&b); /* close buffer */ return 1; /* read at least an `eol' */ } } } static int read_chars (lua_State *L, FILE *f, size_t n) { size_t rlen; /* how much to read */ size_t nr; /* number of chars actually read */ luaL_Buffer b; luaL_buffinit(L, &b); rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ do { char *p = luaL_prepbuffer(&b); if (rlen > n) rlen = n; /* cannot read more than asked */ nr = fread(p, sizeof(char), rlen, f); luaL_addsize(&b, nr); n -= nr; /* still have to read `n' chars */ } while (n > 0 && nr == rlen); /* until end of count or eof */ luaL_pushresult(&b); /* close buffer */ return (n == 0 || lua_strlen(L, -1) > 0); } static int g_read (lua_State *L, FILE *f, int first) { int nargs = lua_gettop(L) - 1; int success; int n; clearerr(f); if (nargs == 0) { /* no arguments? */ success = read_line(L, f); n = first+1; /* to return 1 result */ } else { /* ensure stack space for all results and for auxlib's buffer */ luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); success = 1; for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { size_t l = (size_t)lua_tointeger(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); } else { const char *p = lua_tostring(L, n); luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); switch (p[1]) { case 'n': /* number */ success = read_number(L, f); break; case 'l': /* line */ success = read_line(L, f); break; case 'a': /* file */ read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ success = 1; /* always success */ break; default: return luaL_argerror(L, n, "invalid format"); } } } } if (ferror(f)) return pushresult(L, 0, NULL); if (!success) { lua_pop(L, 1); /* remove last result */ lua_pushnil(L); /* push nil instead */ } return n - first; } static int io_read (lua_State *L) { return g_read(L, getiofile(L, IO_INPUT), 1); } static int f_read (lua_State *L) { return g_read(L, tofile(L), 2); } static int io_readline (lua_State *L) { FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); int sucess; if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); sucess = read_line(L, f); if (ferror(f)) return luaL_error(L, "%s", strerror(errno)); if (sucess) return 1; else { /* EOF */ if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ lua_settop(L, 0); lua_pushvalue(L, lua_upvalueindex(1)); aux_close(L); /* close it */ } return 0; } } /* }====================================================== */ static int g_write (lua_State *L, FILE *f, int arg) { int nargs = lua_gettop(L) - 1; int status = 1; for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { /* optimization: could be done exactly as for strings */ status = status && fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; } else { size_t l; const char *s = luaL_checklstring(L, arg, &l); status = status && (fwrite(s, sizeof(char), l, f) == l); } } return pushresult(L, status, NULL); } static int io_write (lua_State *L) { return g_write(L, getiofile(L, IO_OUTPUT), 1); } static int f_write (lua_State *L) { return g_write(L, tofile(L), 2); } static int f_seek (lua_State *L) { static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, "cur", modenames); long offset = luaL_optlong(L, 3, 0); op = fseek(f, offset, mode[op]); if (op) return pushresult(L, 0, NULL); /* error */ else { lua_pushinteger(L, ftell(f)); return 1; } } static int f_setvbuf (lua_State *L) { static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; static const char *const modenames[] = {"no", "full", "line", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, NULL, modenames); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); int res = setvbuf(f, NULL, mode[op], sz); return pushresult(L, res == 0, NULL); } static int io_flush (lua_State *L) { return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); } static int f_flush (lua_State *L) { return pushresult(L, fflush(tofile(L)) == 0, NULL); } static const luaL_Reg iolib[] = { {"close", io_close}, {"flush", io_flush}, {"input", io_input}, {"lines", io_lines}, {"open", io_open}, {"output", io_output}, {"popen", io_popen}, {"read", io_read}, {"tmpfile", io_tmpfile}, {"type", io_type}, {"write", io_write}, {NULL, NULL} }; static const luaL_Reg flib[] = { {"close", io_close}, {"flush", f_flush}, {"lines", f_lines}, {"read", f_read}, {"seek", f_seek}, {"setvbuf", f_setvbuf}, {"write", f_write}, {"__gc", io_gc}, {"__tostring", io_tostring}, {NULL, NULL} }; static void createmeta (lua_State *L) { luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ lua_pushvalue(L, -1); /* push metatable */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ luaL_register(L, NULL, flib); /* file methods */ } static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { *newfile(L) = f; if (k > 0) { lua_pushvalue(L, -1); lua_rawseti(L, LUA_ENVIRONINDEX, k); } lua_setfield(L, -2, fname); } LUALIB_API int luaopen_io (lua_State *L) { createmeta(L); /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ lua_createtable(L, 2, 1); lua_replace(L, LUA_ENVIRONINDEX); /* open library */ luaL_register(L, LUA_IOLIBNAME, iolib); /* create (and set) default files */ createstdfile(L, stdin, IO_INPUT, "stdin"); createstdfile(L, stdout, IO_OUTPUT, "stdout"); createstdfile(L, stderr, 0, "stderr"); /* create environment for 'popen' */ lua_getfield(L, -1, "popen"); lua_createtable(L, 0, 1); lua_pushcfunction(L, io_pclose); lua_setfield(L, -2, "__close"); lua_setfenv(L, -2); lua_pop(L, 1); /* pop 'popen' */ /* set default close function */ lua_pushcfunction(L, io_fclose); lua_setfield(L, LUA_ENVIRONINDEX, "__close"); return 1; } tagua-1.0-alpha2/lua/src/llex.c000066400000000000000000000302661077523320400163120ustar00rootroot00000000000000/* ** $Id: llex.c,v 2.20 2006/03/09 18:14:31 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #include #include #include #define llex_c #define LUA_CORE #include "lua.h" #include "ldo.h" #include "llex.h" #include "lobject.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "lzio.h" #define next(ls) (ls->current = zgetc(ls->z)) #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') /* ORDER RESERVED */ const char *const luaX_tokens [] = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", "..", "...", "==", ">=", "<=", "~=", "", "", "", "", NULL }; #define save_and_next(ls) (save(ls, ls->current), next(ls)) static void save (LexState *ls, int c) { Mbuffer *b = ls->buff; if (b->n + 1 > b->buffsize) { size_t newsize; if (b->buffsize >= MAX_SIZET/2) luaX_lexerror(ls, "lexical element too long", 0); newsize = b->buffsize * 2; luaZ_resizebuffer(ls->L, b, newsize); } b->buffer[b->n++] = cast(char, c); } void luaX_init (lua_State *L) { int i; for (i=0; itsv.reserved = cast_byte(i+1); /* reserved word */ } } #define MAXSRC 80 const char *luaX_token2str (LexState *ls, int token) { if (token < FIRST_RESERVED) { lua_assert(token == cast(unsigned char, token)); return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : luaO_pushfstring(ls->L, "%c", token); } else return luaX_tokens[token-FIRST_RESERVED]; } static const char *txtToken (LexState *ls, int token) { switch (token) { case TK_NAME: case TK_STRING: case TK_NUMBER: save(ls, '\0'); return luaZ_buffer(ls->buff); default: return luaX_token2str(ls, token); } } void luaX_lexerror (LexState *ls, const char *msg, int token) { char buff[MAXSRC]; luaO_chunkid(buff, getstr(ls->source), MAXSRC); msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); if (token) luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); luaD_throw(ls->L, LUA_ERRSYNTAX); } void luaX_syntaxerror (LexState *ls, const char *msg) { luaX_lexerror(ls, msg, ls->t.token); } TString *luaX_newstring (LexState *ls, const char *str, size_t l) { lua_State *L = ls->L; TString *ts = luaS_newlstr(L, str, l); TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ if (ttisnil(o)) setbvalue(o, 1); /* make sure `str' will not be collected */ return ts; } static void inclinenumber (LexState *ls) { int old = ls->current; lua_assert(currIsNewline(ls)); next(ls); /* skip `\n' or `\r' */ if (currIsNewline(ls) && ls->current != old) next(ls); /* skip `\n\r' or `\r\n' */ if (++ls->linenumber >= MAX_INT) luaX_syntaxerror(ls, "chunk has too many lines"); } void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { ls->decpoint = '.'; ls->L = L; ls->lookahead.token = TK_EOS; /* no look-ahead token */ ls->z = z; ls->fs = NULL; ls->linenumber = 1; ls->lastline = 1; ls->source = source; luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ next(ls); /* read first char */ } /* ** ======================================================= ** LEXICAL ANALYZER ** ======================================================= */ static int check_next (LexState *ls, const char *set) { if (!strchr(set, ls->current)) return 0; save_and_next(ls); return 1; } static void buffreplace (LexState *ls, char from, char to) { size_t n = luaZ_bufflen(ls->buff); char *p = luaZ_buffer(ls->buff); while (n--) if (p[n] == from) p[n] = to; } static void trydecpoint (LexState *ls, SemInfo *seminfo) { /* format error: try to update decimal point separator */ struct lconv *cv = localeconv(); char old = ls->decpoint; ls->decpoint = (cv ? cv->decimal_point[0] : '.'); buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { /* format error with correct decimal point: no more options */ buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ luaX_lexerror(ls, "malformed number", TK_NUMBER); } } /* LUA_NUMBER */ static void read_numeral (LexState *ls, SemInfo *seminfo) { lua_assert(isdigit(ls->current)); do { save_and_next(ls); } while (isdigit(ls->current) || ls->current == '.'); if (check_next(ls, "Ee")) /* `E'? */ check_next(ls, "+-"); /* optional exponent sign */ while (isalnum(ls->current) || ls->current == '_') save_and_next(ls); save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */ trydecpoint(ls, seminfo); /* try to update decimal point separator */ } static int skip_sep (LexState *ls) { int count = 0; int s = ls->current; lua_assert(s == '[' || s == ']'); save_and_next(ls); while (ls->current == '=') { save_and_next(ls); count++; } return (ls->current == s) ? count : (-count) - 1; } static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { int cont = 0; (void)(cont); /* avoid warnings when `cont' is not used */ save_and_next(ls); /* skip 2nd `[' */ if (currIsNewline(ls)) /* string starts with a newline? */ inclinenumber(ls); /* skip it */ for (;;) { switch (ls->current) { case EOZ: luaX_lexerror(ls, (seminfo) ? "unfinished long string" : "unfinished long comment", TK_EOS); break; /* to avoid warnings */ #if defined(LUA_COMPAT_LSTR) case '[': { if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd `[' */ cont++; #if LUA_COMPAT_LSTR == 1 if (sep == 0) luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); #endif } break; } #endif case ']': { if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd `]' */ #if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 cont--; if (sep == 0 && cont >= 0) break; #endif goto endloop; } break; } case '\n': case '\r': { save(ls, '\n'); inclinenumber(ls); if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ break; } default: { if (seminfo) save_and_next(ls); else next(ls); } } } endloop: if (seminfo) seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), luaZ_bufflen(ls->buff) - 2*(2 + sep)); } static void read_string (LexState *ls, int del, SemInfo *seminfo) { save_and_next(ls); while (ls->current != del) { switch (ls->current) { case EOZ: luaX_lexerror(ls, "unfinished string", TK_EOS); continue; /* to avoid warnings */ case '\n': case '\r': luaX_lexerror(ls, "unfinished string", TK_STRING); continue; /* to avoid warnings */ case '\\': { int c; next(ls); /* do not save the `\' */ switch (ls->current) { case 'a': c = '\a'; break; case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; case '\n': /* go through */ case '\r': save(ls, '\n'); inclinenumber(ls); continue; case EOZ: continue; /* will raise an error next loop */ default: { if (!isdigit(ls->current)) save_and_next(ls); /* handles \\, \", \', and \? */ else { /* \xxx */ int i = 0; c = 0; do { c = 10*c + (ls->current-'0'); next(ls); } while (++i<3 && isdigit(ls->current)); if (c > UCHAR_MAX) luaX_lexerror(ls, "escape sequence too large", TK_STRING); save(ls, c); } continue; } } save(ls, c); next(ls); continue; } default: save_and_next(ls); } } save_and_next(ls); /* skip delimiter */ seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, luaZ_bufflen(ls->buff) - 2); } static int llex (LexState *ls, SemInfo *seminfo) { luaZ_resetbuffer(ls->buff); for (;;) { switch (ls->current) { case '\n': case '\r': { inclinenumber(ls); continue; } case '-': { next(ls); if (ls->current != '-') return '-'; /* else is a comment */ next(ls); if (ls->current == '[') { int sep = skip_sep(ls); luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ if (sep >= 0) { read_long_string(ls, NULL, sep); /* long comment */ luaZ_resetbuffer(ls->buff); continue; } } /* else short comment */ while (!currIsNewline(ls) && ls->current != EOZ) next(ls); continue; } case '[': { int sep = skip_sep(ls); if (sep >= 0) { read_long_string(ls, seminfo, sep); return TK_STRING; } else if (sep == -1) return '['; else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); } case '=': { next(ls); if (ls->current != '=') return '='; else { next(ls); return TK_EQ; } } case '<': { next(ls); if (ls->current != '=') return '<'; else { next(ls); return TK_LE; } } case '>': { next(ls); if (ls->current != '=') return '>'; else { next(ls); return TK_GE; } } case '~': { next(ls); if (ls->current != '=') return '~'; else { next(ls); return TK_NE; } } case '"': case '\'': { read_string(ls, ls->current, seminfo); return TK_STRING; } case '.': { save_and_next(ls); if (check_next(ls, ".")) { if (check_next(ls, ".")) return TK_DOTS; /* ... */ else return TK_CONCAT; /* .. */ } else if (!isdigit(ls->current)) return '.'; else { read_numeral(ls, seminfo); return TK_NUMBER; } } case EOZ: { return TK_EOS; } default: { if (isspace(ls->current)) { lua_assert(!currIsNewline(ls)); next(ls); continue; } else if (isdigit(ls->current)) { read_numeral(ls, seminfo); return TK_NUMBER; } else if (isalpha(ls->current) || ls->current == '_') { /* identifier or reserved word */ TString *ts; do { save_and_next(ls); } while (isalnum(ls->current) || ls->current == '_'); ts = luaX_newstring(ls, luaZ_buffer(ls->buff), luaZ_bufflen(ls->buff)); if (ts->tsv.reserved > 0) /* reserved word? */ return ts->tsv.reserved - 1 + FIRST_RESERVED; else { seminfo->ts = ts; return TK_NAME; } } else { int c = ls->current; next(ls); return c; /* single-char tokens (+ - / ...) */ } } } } } void luaX_next (LexState *ls) { ls->lastline = ls->linenumber; if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ ls->t = ls->lookahead; /* use this one */ ls->lookahead.token = TK_EOS; /* and discharge it */ } else ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ } void luaX_lookahead (LexState *ls) { lua_assert(ls->lookahead.token == TK_EOS); ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); } tagua-1.0-alpha2/lua/src/llex.h000066400000000000000000000041751077523320400163170ustar00rootroot00000000000000/* ** $Id: llex.h,v 1.58 2006/03/23 18:23:32 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #ifndef llex_h #define llex_h #include "lobject.h" #include "lzio.h" #define FIRST_RESERVED 257 /* maximum length of a reserved word */ #define TOKEN_LEN (sizeof("function")/sizeof(char)) /* * WARNING: if you change the order of this enumeration, * grep "ORDER RESERVED" */ enum RESERVED { /* terminal symbols denoted by reserved words */ TK_AND = FIRST_RESERVED, TK_BREAK, TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, TK_NAME, TK_STRING, TK_EOS }; /* number of reserved words */ #define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) /* array with token `names' */ LUAI_DATA const char *const luaX_tokens []; typedef union { lua_Number r; TString *ts; } SemInfo; /* semantics information */ typedef struct Token { int token; SemInfo seminfo; } Token; typedef struct LexState { int current; /* current character (charint) */ int linenumber; /* input line counter */ int lastline; /* line of last token `consumed' */ Token t; /* current token */ Token lookahead; /* look ahead token */ struct FuncState *fs; /* `FuncState' is private to the parser */ struct lua_State *L; ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ TString *source; /* current source name */ char decpoint; /* locale decimal point */ } LexState; LUAI_FUNC void luaX_init (lua_State *L); LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source); LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); LUAI_FUNC void luaX_next (LexState *ls); LUAI_FUNC void luaX_lookahead (LexState *ls); LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token); LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s); LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); #endif tagua-1.0-alpha2/lua/src/llimits.h000066400000000000000000000044511077523320400170250ustar00rootroot00000000000000/* ** $Id: llimits.h,v 1.69 2005/12/27 17:12:00 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ #ifndef llimits_h #define llimits_h #include #include #include "lua.h" typedef LUAI_UINT32 lu_int32; typedef LUAI_UMEM lu_mem; typedef LUAI_MEM l_mem; /* chars used as small naturals (so that `char' is reserved for characters) */ typedef unsigned char lu_byte; #define MAX_SIZET ((size_t)(~(size_t)0)-2) #define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ /* ** conversion of pointer to integer ** this is for hashing only; there is no problem if the integer ** cannot hold the whole pointer value */ #define IntPoint(p) ((unsigned int)(lu_mem)(p)) /* type to ensure maximum alignment */ typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; /* result of a `usual argument conversion' over lua_Number */ typedef LUAI_UACNUMBER l_uacNumber; /* internal assertions for in-house debugging */ #ifdef lua_assert #define check_exp(c,e) (lua_assert(c), (e)) #define api_check(l,e) lua_assert(e) #else #define lua_assert(c) ((void)0) #define check_exp(c,e) (e) #define api_check luai_apicheck #endif #ifndef UNUSED #define UNUSED(x) ((void)(x)) /* to avoid warnings */ #endif #ifndef cast #define cast(t, exp) ((t)(exp)) #endif #define cast_byte(i) cast(lu_byte, (i)) #define cast_num(i) cast(lua_Number, (i)) #define cast_int(i) cast(int, (i)) /* ** type for virtual-machine instructions ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) */ typedef lu_int32 Instruction; /* maximum stack for a Lua function */ #define MAXSTACK 250 /* minimum size for the string table (must be power of 2) */ #ifndef MINSTRTABSIZE #define MINSTRTABSIZE 32 #endif /* minimum size for string buffer */ #ifndef LUA_MINBUFFER #define LUA_MINBUFFER 32 #endif #ifndef lua_lock #define lua_lock(L) ((void) 0) #define lua_unlock(L) ((void) 0) #endif #ifndef luai_threadyield #define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} #endif /* ** macro to control inclusion of some hard tests on stack reallocation */ #ifndef HARDSTACKTESTS #define condhardstacktests(x) ((void)0) #else #define condhardstacktests(x) x #endif #endif tagua-1.0-alpha2/lua/src/lmathlib.c000066400000000000000000000133031077523320400171330ustar00rootroot00000000000000/* ** $Id: lmathlib.c,v 1.67 2005/08/26 17:36:32 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ #include #include #define lmathlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" #undef PI #define PI (3.14159265358979323846) #define RADIANS_PER_DEGREE (PI/180.0) static int math_abs (lua_State *L) { lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); return 1; } static int math_sin (lua_State *L) { lua_pushnumber(L, sin(luaL_checknumber(L, 1))); return 1; } static int math_sinh (lua_State *L) { lua_pushnumber(L, sinh(luaL_checknumber(L, 1))); return 1; } static int math_cos (lua_State *L) { lua_pushnumber(L, cos(luaL_checknumber(L, 1))); return 1; } static int math_cosh (lua_State *L) { lua_pushnumber(L, cosh(luaL_checknumber(L, 1))); return 1; } static int math_tan (lua_State *L) { lua_pushnumber(L, tan(luaL_checknumber(L, 1))); return 1; } static int math_tanh (lua_State *L) { lua_pushnumber(L, tanh(luaL_checknumber(L, 1))); return 1; } static int math_asin (lua_State *L) { lua_pushnumber(L, asin(luaL_checknumber(L, 1))); return 1; } static int math_acos (lua_State *L) { lua_pushnumber(L, acos(luaL_checknumber(L, 1))); return 1; } static int math_atan (lua_State *L) { lua_pushnumber(L, atan(luaL_checknumber(L, 1))); return 1; } static int math_atan2 (lua_State *L) { lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_ceil (lua_State *L) { lua_pushnumber(L, ceil(luaL_checknumber(L, 1))); return 1; } static int math_floor (lua_State *L) { lua_pushnumber(L, floor(luaL_checknumber(L, 1))); return 1; } static int math_fmod (lua_State *L) { lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_modf (lua_State *L) { double ip; double fp = modf(luaL_checknumber(L, 1), &ip); lua_pushnumber(L, ip); lua_pushnumber(L, fp); return 2; } static int math_sqrt (lua_State *L) { lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); return 1; } static int math_pow (lua_State *L) { lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_log (lua_State *L) { lua_pushnumber(L, log(luaL_checknumber(L, 1))); return 1; } static int math_log10 (lua_State *L) { lua_pushnumber(L, log10(luaL_checknumber(L, 1))); return 1; } static int math_exp (lua_State *L) { lua_pushnumber(L, exp(luaL_checknumber(L, 1))); return 1; } static int math_deg (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); return 1; } static int math_rad (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); return 1; } static int math_frexp (lua_State *L) { int e; lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); lua_pushinteger(L, e); return 2; } static int math_ldexp (lua_State *L) { lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); return 1; } static int math_min (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ lua_Number dmin = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { lua_Number d = luaL_checknumber(L, i); if (d < dmin) dmin = d; } lua_pushnumber(L, dmin); return 1; } static int math_max (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ lua_Number dmax = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { lua_Number d = luaL_checknumber(L, i); if (d > dmax) dmax = d; } lua_pushnumber(L, dmax); return 1; } static int math_random (lua_State *L) { /* the `%' avoids the (rare) case of r==1, and is needed also because on some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; switch (lua_gettop(L)) { /* check number of arguments */ case 0: { /* no arguments */ lua_pushnumber(L, r); /* Number between 0 and 1 */ break; } case 1: { /* only upper limit */ int u = luaL_checkint(L, 1); luaL_argcheck(L, 1<=u, 1, "interval is empty"); lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */ break; } case 2: { /* lower and upper limits */ int l = luaL_checkint(L, 1); int u = luaL_checkint(L, 2); luaL_argcheck(L, l<=u, 2, "interval is empty"); lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */ break; } default: return luaL_error(L, "wrong number of arguments"); } return 1; } static int math_randomseed (lua_State *L) { srand(luaL_checkint(L, 1)); return 0; } static const luaL_Reg mathlib[] = { {"abs", math_abs}, {"acos", math_acos}, {"asin", math_asin}, {"atan2", math_atan2}, {"atan", math_atan}, {"ceil", math_ceil}, {"cosh", math_cosh}, {"cos", math_cos}, {"deg", math_deg}, {"exp", math_exp}, {"floor", math_floor}, {"fmod", math_fmod}, {"frexp", math_frexp}, {"ldexp", math_ldexp}, {"log10", math_log10}, {"log", math_log}, {"max", math_max}, {"min", math_min}, {"modf", math_modf}, {"pow", math_pow}, {"rad", math_rad}, {"random", math_random}, {"randomseed", math_randomseed}, {"sinh", math_sinh}, {"sin", math_sin}, {"sqrt", math_sqrt}, {"tanh", math_tanh}, {"tan", math_tan}, {NULL, NULL} }; /* ** Open math library */ LUALIB_API int luaopen_math (lua_State *L) { luaL_register(L, LUA_MATHLIBNAME, mathlib); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); lua_pushnumber(L, HUGE_VAL); lua_setfield(L, -2, "huge"); #if defined(LUA_COMPAT_MOD) lua_getfield(L, -1, "fmod"); lua_setfield(L, -2, "mod"); #endif return 1; } tagua-1.0-alpha2/lua/src/lmem.c000066400000000000000000000041701077523320400162730ustar00rootroot00000000000000/* ** $Id: lmem.c,v 1.70 2005/12/26 13:35:47 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ #include #define lmem_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" /* ** About the realloc function: ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); ** (`osize' is the old size, `nsize' is the new size) ** ** Lua ensures that (ptr == NULL) iff (osize == 0). ** ** * frealloc(ud, NULL, 0, x) creates a new block of size `x' ** ** * frealloc(ud, p, x, 0) frees the block `p' ** (in this specific case, frealloc must return NULL). ** particularly, frealloc(ud, NULL, 0, 0) does nothing ** (which is equivalent to free(NULL) in ANSI C) ** ** frealloc returns NULL if it cannot create or reallocate the area ** (any reallocation to an equal or smaller size cannot fail!) */ #define MINSIZEARRAY 4 void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, int limit, const char *errormsg) { void *newblock; int newsize; if (*size >= limit/2) { /* cannot double it? */ if (*size >= limit) /* cannot grow even a little? */ luaG_runerror(L, errormsg); newsize = limit; /* still have at least one free place */ } else { newsize = (*size)*2; if (newsize < MINSIZEARRAY) newsize = MINSIZEARRAY; /* minimum size */ } newblock = luaM_reallocv(L, block, *size, newsize, size_elems); *size = newsize; /* update only when everything else is OK */ return newblock; } void *luaM_toobig (lua_State *L) { luaG_runerror(L, "memory allocation error: block too big"); return NULL; /* to avoid warnings */ } /* ** generic allocation routine. */ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { global_State *g = G(L); lua_assert((osize == 0) == (block == NULL)); block = (*g->frealloc)(g->ud, block, osize, nsize); if (block == NULL && nsize > 0) luaD_throw(L, LUA_ERRMEM); lua_assert((nsize == 0) == (block == NULL)); g->totalbytes = (g->totalbytes - osize) + nsize; return block; } tagua-1.0-alpha2/lua/src/lmem.h000066400000000000000000000027221077523320400163010ustar00rootroot00000000000000/* ** $Id: lmem.h,v 1.31 2005/04/25 19:24:10 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ #ifndef lmem_h #define lmem_h #include #include "llimits.h" #include "lua.h" #define MEMERRMSG "not enough memory" #define luaM_reallocv(L,b,on,n,e) \ ((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \ luaM_toobig(L)) #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) #define luaM_freearray(L, b, n, t) luaM_reallocv(L, (b), n, 0, sizeof(t)) #define luaM_malloc(L,t) luaM_realloc_(L, NULL, 0, (t)) #define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) #define luaM_newvector(L,n,t) \ cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) #define luaM_growvector(L,v,nelems,size,t,limit,e) \ if ((nelems)+1 > (size)) \ ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) #define luaM_reallocvector(L, v,oldn,n,t) \ ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, size_t size); LUAI_FUNC void *luaM_toobig (lua_State *L); LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elem, int limit, const char *errormsg); #endif tagua-1.0-alpha2/lua/src/loadlib.c000066400000000000000000000451661077523320400167610ustar00rootroot00000000000000/* ** $Id: loadlib.c,v 1.54a 2006/07/03 20:16:49 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** ** This module contains an implementation of loadlib for Unix systems ** that have dlfcn, an implementation for Darwin (Mac OS X), an ** implementation for Windows, and a stub for other systems. */ #include #include #define loadlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* prefix for open functions in C libraries */ #define LUA_POF "luaopen_" /* separator for open functions in C libraries */ #define LUA_OFSEP "_" #define LIBPREFIX "LOADLIB: " #define POF LUA_POF #define LIB_FAIL "open" /* error codes for ll_loadfunc */ #define ERRLIB 1 #define ERRFUNC 2 #define setprogdir(L) ((void)0) static void ll_unloadlib (void *lib); static void *ll_load (lua_State *L, const char *path); static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); #if defined(LUA_DL_DLOPEN) /* ** {======================================================================== ** This is an implementation of loadlib based on the dlfcn interface. ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least ** as an emulation layer on top of native functions. ** ========================================================================= */ #include static void ll_unloadlib (void *lib) { dlclose(lib); } static void *ll_load (lua_State *L, const char *path) { void *lib = dlopen(path, RTLD_NOW); if (lib == NULL) lua_pushstring(L, dlerror()); return lib; } static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { lua_CFunction f = (lua_CFunction)dlsym(lib, sym); if (f == NULL) lua_pushstring(L, dlerror()); return f; } /* }====================================================== */ #elif defined(LUA_DL_DLL) /* ** {====================================================================== ** This is an implementation of loadlib for Windows using native functions. ** ======================================================================= */ #include #undef setprogdir static void setprogdir (lua_State *L) { char buff[MAX_PATH + 1]; char *lb; DWORD nsize = sizeof(buff)/sizeof(char); DWORD n = GetModuleFileNameA(NULL, buff, nsize); if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) luaL_error(L, "unable to get ModuleFileName"); else { *lb = '\0'; luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); lua_remove(L, -2); /* remove original string */ } } static void pusherror (lua_State *L) { int error = GetLastError(); char buffer[128]; if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buffer, sizeof(buffer), NULL)) lua_pushstring(L, buffer); else lua_pushfstring(L, "system error %d\n", error); } static void ll_unloadlib (void *lib) { FreeLibrary((HINSTANCE)lib); } static void *ll_load (lua_State *L, const char *path) { HINSTANCE lib = LoadLibraryA(path); if (lib == NULL) pusherror(L); return lib; } static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); if (f == NULL) pusherror(L); return f; } /* }====================================================== */ #elif defined(LUA_DL_DYLD) /* ** {====================================================================== ** Native Mac OS X / Darwin Implementation ** ======================================================================= */ #include /* Mac appends a `_' before C function names */ #undef POF #define POF "_" LUA_POF static void pusherror (lua_State *L) { const char *err_str; const char *err_file; NSLinkEditErrors err; int err_num; NSLinkEditError(&err, &err_num, &err_file, &err_str); lua_pushstring(L, err_str); } static const char *errorfromcode (NSObjectFileImageReturnCode ret) { switch (ret) { case NSObjectFileImageInappropriateFile: return "file is not a bundle"; case NSObjectFileImageArch: return "library is for wrong CPU type"; case NSObjectFileImageFormat: return "bad format"; case NSObjectFileImageAccess: return "cannot access file"; case NSObjectFileImageFailure: default: return "unable to load library"; } } static void ll_unloadlib (void *lib) { NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); } static void *ll_load (lua_State *L, const char *path) { NSObjectFileImage img; NSObjectFileImageReturnCode ret; /* this would be a rare case, but prevents crashing if it happens */ if(!_dyld_present()) { lua_pushliteral(L, "dyld not present"); return NULL; } ret = NSCreateObjectFileImageFromFile(path, &img); if (ret == NSObjectFileImageSuccess) { NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR); NSDestroyObjectFileImage(img); if (mod == NULL) pusherror(L); return mod; } lua_pushstring(L, errorfromcode(ret)); return NULL; } static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); if (nss == NULL) { lua_pushfstring(L, "symbol " LUA_QS " not found", sym); return NULL; } return (lua_CFunction)NSAddressOfSymbol(nss); } /* }====================================================== */ #else /* ** {====================================================== ** Fallback for other systems ** ======================================================= */ #undef LIB_FAIL #define LIB_FAIL "absent" #define DLMSG "dynamic libraries not enabled; check your Lua installation" static void ll_unloadlib (void *lib) { (void)lib; /* to avoid warnings */ } static void *ll_load (lua_State *L, const char *path) { (void)path; /* to avoid warnings */ lua_pushliteral(L, DLMSG); return NULL; } static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { (void)lib; (void)sym; /* to avoid warnings */ lua_pushliteral(L, DLMSG); return NULL; } /* }====================================================== */ #endif static void **ll_register (lua_State *L, const char *path) { void **plib; lua_pushfstring(L, "%s%s", LIBPREFIX, path); lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ if (!lua_isnil(L, -1)) /* is there an entry? */ plib = (void **)lua_touserdata(L, -1); else { /* no entry yet; create one */ lua_pop(L, 1); plib = (void **)lua_newuserdata(L, sizeof(const void *)); *plib = NULL; luaL_getmetatable(L, "_LOADLIB"); lua_setmetatable(L, -2); lua_pushfstring(L, "%s%s", LIBPREFIX, path); lua_pushvalue(L, -2); lua_settable(L, LUA_REGISTRYINDEX); } return plib; } /* ** __gc tag method: calls library's `ll_unloadlib' function with the lib ** handle */ static int gctm (lua_State *L) { void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); if (*lib) ll_unloadlib(*lib); *lib = NULL; /* mark library as closed */ return 0; } static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { void **reg = ll_register(L, path); if (*reg == NULL) *reg = ll_load(L, path); if (*reg == NULL) return ERRLIB; /* unable to load library */ else { lua_CFunction f = ll_sym(L, *reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ lua_pushcfunction(L, f); return 0; /* return function */ } } static int ll_loadlib (lua_State *L) { const char *path = luaL_checkstring(L, 1); const char *init = luaL_checkstring(L, 2); int stat = ll_loadfunc(L, path, init); if (stat == 0) /* no errors? */ return 1; /* return the loaded function */ else { /* error; error message is on stack top */ lua_pushnil(L); lua_insert(L, -2); lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); return 3; /* return nil, error message, and where */ } } /* ** {====================================================== ** 'require' function ** ======================================================= */ static int readable (const char *filename) { FILE *f = fopen(filename, "r"); /* try to open file */ if (f == NULL) return 0; /* open failed */ fclose(f); return 1; } static const char *pushnexttemplate (lua_State *L, const char *path) { const char *l; while (*path == *LUA_PATHSEP) path++; /* skip separators */ if (*path == '\0') return NULL; /* no more templates */ l = strchr(path, *LUA_PATHSEP); /* find next separator */ if (l == NULL) l = path + strlen(path); lua_pushlstring(L, path, l - path); /* template */ return l; } static const char *findfile (lua_State *L, const char *name, const char *pname) { const char *path; name = luaL_gsub(L, name, ".", LUA_DIRSEP); lua_getfield(L, LUA_ENVIRONINDEX, pname); path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, LUA_QL("package.%s") " must be a string", pname); lua_pushliteral(L, ""); /* error accumulator */ while ((path = pushnexttemplate(L, path)) != NULL) { const char *filename; filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); lua_remove(L, -2); /* remove path template */ if (readable(filename)) /* does file exist and is readable? */ return filename; /* return that file name */ lua_pushfstring(L, "\n\tno file " LUA_QS, filename); lua_remove(L, -2); /* remove file name */ lua_concat(L, 2); /* add entry to possible error message */ } return NULL; /* not found */ } static void loaderror (lua_State *L, const char *filename) { luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", lua_tostring(L, 1), filename, lua_tostring(L, -1)); } static int loader_Lua (lua_State *L) { const char *filename; const char *name = luaL_checkstring(L, 1); filename = findfile(L, name, "path"); if (filename == NULL) return 1; /* library not found in this path */ if (luaL_loadfile(L, filename) != 0) loaderror(L, filename); return 1; /* library loaded successfully */ } static const char *mkfuncname (lua_State *L, const char *modname) { const char *funcname; const char *mark = strchr(modname, *LUA_IGMARK); if (mark) modname = mark + 1; funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); funcname = lua_pushfstring(L, POF"%s", funcname); lua_remove(L, -2); /* remove 'gsub' result */ return funcname; } static int loader_C (lua_State *L) { const char *funcname; const char *name = luaL_checkstring(L, 1); const char *filename = findfile(L, name, "cpath"); if (filename == NULL) return 1; /* library not found in this path */ funcname = mkfuncname(L, name); if (ll_loadfunc(L, filename, funcname) != 0) loaderror(L, filename); return 1; /* library loaded successfully */ } static int loader_Croot (lua_State *L) { const char *funcname; const char *filename; const char *name = luaL_checkstring(L, 1); const char *p = strchr(name, '.'); int stat; if (p == NULL) return 0; /* is root */ lua_pushlstring(L, name, p - name); filename = findfile(L, lua_tostring(L, -1), "cpath"); if (filename == NULL) return 1; /* root not found */ funcname = mkfuncname(L, name); if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { if (stat != ERRFUNC) loaderror(L, filename); /* real error */ lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, name, filename); return 1; /* function not found */ } return 1; } static int loader_preload (lua_State *L) { const char *name = luaL_checkstring(L, 1); lua_getfield(L, LUA_ENVIRONINDEX, "preload"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.preload") " must be a table"); lua_getfield(L, -1, name); if (lua_isnil(L, -1)) /* not found? */ lua_pushfstring(L, "\n\tno field package.preload['%s']", name); return 1; } static const int sentinel_ = 0; #define sentinel ((void *)&sentinel_) static int ll_require (lua_State *L) { const char *name = luaL_checkstring(L, 1); int i; lua_settop(L, 1); /* _LOADED table will be at index 2 */ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, 2, name); if (lua_toboolean(L, -1)) { /* is it there? */ if (lua_touserdata(L, -1) == sentinel) /* check loops */ luaL_error(L, "loop or previous error loading module " LUA_QS, name); return 1; /* package is already loaded */ } /* else must load it; iterate over available loaders */ lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.loaders") " must be a table"); lua_pushliteral(L, ""); /* error message accumulator */ for (i=1; ; i++) { lua_rawgeti(L, -2, i); /* get a loader */ if (lua_isnil(L, -1)) luaL_error(L, "module " LUA_QS " not found:%s", name, lua_tostring(L, -2)); lua_pushstring(L, name); lua_call(L, 1, 1); /* call it */ if (lua_isfunction(L, -1)) /* did it find module? */ break; /* module loaded successfully */ else if (lua_isstring(L, -1)) /* loader returned error message? */ lua_concat(L, 2); /* accumulate it */ else lua_pop(L, 1); } lua_pushlightuserdata(L, sentinel); lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ lua_pushstring(L, name); /* pass name as argument to module */ lua_call(L, 1, 1); /* run loaded module */ if (!lua_isnil(L, -1)) /* non-nil return? */ lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ lua_getfield(L, 2, name); if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ lua_pushboolean(L, 1); /* use true as result */ lua_pushvalue(L, -1); /* extra copy to be returned */ lua_setfield(L, 2, name); /* _LOADED[name] = true */ } return 1; } /* }====================================================== */ /* ** {====================================================== ** 'module' function ** ======================================================= */ static void setfenv (lua_State *L) { lua_Debug ar; lua_getstack(L, 1, &ar); lua_getinfo(L, "f", &ar); lua_pushvalue(L, -2); lua_setfenv(L, -2); lua_pop(L, 1); } static void dooptions (lua_State *L, int n) { int i; for (i = 2; i <= n; i++) { lua_pushvalue(L, i); /* get option (a function) */ lua_pushvalue(L, -2); /* module */ lua_call(L, 1, 0); } } static void modinit (lua_State *L, const char *modname) { const char *dot; lua_pushvalue(L, -1); lua_setfield(L, -2, "_M"); /* module._M = module */ lua_pushstring(L, modname); lua_setfield(L, -2, "_NAME"); dot = strrchr(modname, '.'); /* look for last dot in module name */ if (dot == NULL) dot = modname; else dot++; /* set _PACKAGE as package name (full module name minus last part) */ lua_pushlstring(L, modname, dot - modname); lua_setfield(L, -2, "_PACKAGE"); } static int ll_module (lua_State *L) { const char *modname = luaL_checkstring(L, 1); int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) return luaL_error(L, "name conflict for module " LUA_QS, modname); lua_pushvalue(L, -1); lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ } /* check whether table already has a _NAME field */ lua_getfield(L, -1, "_NAME"); if (!lua_isnil(L, -1)) /* is table an initialized module? */ lua_pop(L, 1); else { /* no; initialize it */ lua_pop(L, 1); modinit(L, modname); } lua_pushvalue(L, -1); setfenv(L); dooptions(L, loaded - 1); return 0; } static int ll_seeall (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); if (!lua_getmetatable(L, 1)) { lua_createtable(L, 0, 1); /* create new metatable */ lua_pushvalue(L, -1); lua_setmetatable(L, 1); } lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setfield(L, -2, "__index"); /* mt.__index = _G */ return 0; } /* }====================================================== */ /* auxiliary mark (for internal use) */ #define AUXMARK "\1" static void setpath (lua_State *L, const char *fieldname, const char *envname, const char *def) { const char *path = getenv(envname); if (path == NULL) /* no environment variable? */ lua_pushstring(L, def); /* use default */ else { /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, LUA_PATHSEP AUXMARK LUA_PATHSEP); luaL_gsub(L, path, AUXMARK, def); lua_remove(L, -2); } setprogdir(L); lua_setfield(L, -2, fieldname); } static const luaL_Reg pk_funcs[] = { {"loadlib", ll_loadlib}, {"seeall", ll_seeall}, {NULL, NULL} }; static const luaL_Reg ll_funcs[] = { {"module", ll_module}, {"require", ll_require}, {NULL, NULL} }; static const lua_CFunction loaders[] = {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; LUALIB_API int luaopen_package (lua_State *L) { int i; /* create new type _LOADLIB */ luaL_newmetatable(L, "_LOADLIB"); lua_pushcfunction(L, gctm); lua_setfield(L, -2, "__gc"); /* create `package' table */ luaL_register(L, LUA_LOADLIBNAME, pk_funcs); #if defined(LUA_COMPAT_LOADLIB) lua_getfield(L, -1, "loadlib"); lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); #endif lua_pushvalue(L, -1); lua_replace(L, LUA_ENVIRONINDEX); /* create `loaders' table */ lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); /* fill it with pre-defined loaders */ for (i=0; loaders[i] != NULL; i++) { lua_pushcfunction(L, loaders[i]); lua_rawseti(L, -2, i+1); } lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ /* store config information */ lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" LUA_EXECDIR "\n" LUA_IGMARK); lua_setfield(L, -2, "config"); /* set field `loaded' */ luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); lua_setfield(L, -2, "loaded"); /* set field `preload' */ lua_newtable(L); lua_setfield(L, -2, "preload"); lua_pushvalue(L, LUA_GLOBALSINDEX); luaL_register(L, NULL, ll_funcs); /* open lib into global table */ lua_pop(L, 1); return 1; /* return 'package' table */ } tagua-1.0-alpha2/lua/src/lobject.c000066400000000000000000000125661077523320400167730ustar00rootroot00000000000000/* ** $Id: lobject.c,v 2.22 2006/02/10 17:43:52 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ #include #include #include #include #include #define lobject_c #define LUA_CORE #include "lua.h" #include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "lvm.h" const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; /* ** converts an integer to a "floating point byte", represented as ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if ** eeeee != 0 and (xxx) otherwise. */ int luaO_int2fb (unsigned int x) { int e = 0; /* expoent */ while (x >= 16) { x = (x+1) >> 1; e++; } if (x < 8) return x; else return ((e+1) << 3) | (cast_int(x) - 8); } /* converts back */ int luaO_fb2int (int x) { int e = (x >> 3) & 31; if (e == 0) return x; else return ((x & 7)+8) << (e - 1); } int luaO_log2 (unsigned int x) { static const lu_byte log_2[256] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }; int l = -1; while (x >= 256) { l += 8; x >>= 8; } return l + log_2[x]; } int luaO_rawequalObj (const TValue *t1, const TValue *t2) { if (ttype(t1) != ttype(t2)) return 0; else switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); default: lua_assert(iscollectable(t1)); return gcvalue(t1) == gcvalue(t2); } } int luaO_str2d (const char *s, lua_Number *result) { char *endptr; *result = lua_str2number(s, &endptr); if (endptr == s) return 0; /* conversion failed */ if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */ *result = cast_num(strtoul(s, &endptr, 16)); if (*endptr == '\0') return 1; /* most common case */ while (isspace(cast(unsigned char, *endptr))) endptr++; if (*endptr != '\0') return 0; /* invalid trailing characters? */ return 1; } static void pushstr (lua_State *L, const char *str) { setsvalue2s(L, L->top, luaS_new(L, str)); incr_top(L); } /* this function handles only `%d', `%c', %f, %p, and `%s' formats */ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { int n = 1; pushstr(L, ""); for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); incr_top(L); switch (*(e+1)) { case 's': { const char *s = va_arg(argp, char *); if (s == NULL) s = "(null)"; pushstr(L, s); break; } case 'c': { char buff[2]; buff[0] = cast(char, va_arg(argp, int)); buff[1] = '\0'; pushstr(L, buff); break; } case 'd': { setnvalue(L->top, cast_num(va_arg(argp, int))); incr_top(L); break; } case 'f': { setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); incr_top(L); break; } case 'p': { char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ sprintf(buff, "%p", va_arg(argp, void *)); pushstr(L, buff); break; } case '%': { pushstr(L, "%"); break; } default: { char buff[3]; buff[0] = '%'; buff[1] = *(e+1); buff[2] = '\0'; pushstr(L, buff); break; } } n += 2; fmt = e+2; } pushstr(L, fmt); luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); L->top -= n; return svalue(L->top - 1); } const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { const char *msg; va_list argp; va_start(argp, fmt); msg = luaO_pushvfstring(L, fmt, argp); va_end(argp); return msg; } void luaO_chunkid (char *out, const char *source, size_t bufflen) { if (*source == '=') { strncpy(out, source+1, bufflen); /* remove first char */ out[bufflen-1] = '\0'; /* ensures null termination */ } else { /* out = "source", or "...source" */ if (*source == '@') { size_t l; source++; /* skip the `@' */ bufflen -= sizeof(" '...' "); l = strlen(source); strcpy(out, ""); if (l > bufflen) { source += (l-bufflen); /* get last part of file name */ strcat(out, "..."); } strcat(out, source); } else { /* out = [string "string"] */ size_t len = strcspn(source, "\n\r"); /* stop at first newline */ bufflen -= sizeof(" [string \"...\"] "); if (len > bufflen) len = bufflen; strcpy(out, "[string \""); if (source[len] != '\0') { /* must truncate? */ strncat(out, source, len); strcat(out, "..."); } else strcat(out, source); strcat(out, "\"]"); } } } tagua-1.0-alpha2/lua/src/lobject.h000066400000000000000000000204571077523320400167760ustar00rootroot00000000000000/* ** $Id: lobject.h,v 2.20 2006/01/18 11:37:34 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ #ifndef lobject_h #define lobject_h #include #include "llimits.h" #include "lua.h" /* tags for values visible from Lua */ #define LAST_TAG LUA_TTHREAD #define NUM_TAGS (LAST_TAG+1) /* ** Extra tags for non-values */ #define LUA_TPROTO (LAST_TAG+1) #define LUA_TUPVAL (LAST_TAG+2) #define LUA_TDEADKEY (LAST_TAG+3) /* ** Union of all collectable objects */ typedef union GCObject GCObject; /* ** Common Header for all collectable objects (in macro form, to be ** included in other objects) */ #define CommonHeader GCObject *next; lu_byte tt; lu_byte marked /* ** Common header in struct form */ typedef struct GCheader { CommonHeader; } GCheader; /* ** Union of all Lua values */ typedef union { GCObject *gc; void *p; lua_Number n; int b; } Value; /* ** Tagged Values */ #define TValuefields Value value; int tt typedef struct lua_TValue { TValuefields; } TValue; /* Macros to test type */ #define ttisnil(o) (ttype(o) == LUA_TNIL) #define ttisnumber(o) (ttype(o) == LUA_TNUMBER) #define ttisstring(o) (ttype(o) == LUA_TSTRING) #define ttistable(o) (ttype(o) == LUA_TTABLE) #define ttisfunction(o) (ttype(o) == LUA_TFUNCTION) #define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN) #define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) #define ttisthread(o) (ttype(o) == LUA_TTHREAD) #define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) /* Macros to access values */ #define ttype(o) ((o)->tt) #define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc) #define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p) #define nvalue(o) check_exp(ttisnumber(o), (o)->value.n) #define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) #define tsvalue(o) (&rawtsvalue(o)->tsv) #define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u) #define uvalue(o) (&rawuvalue(o)->uv) #define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl) #define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) #define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) #define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th) #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) /* ** for internal debug only */ #define checkconsistency(obj) \ lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) #define checkliveness(g,obj) \ lua_assert(!iscollectable(obj) || \ ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) /* Macros to set values */ #define setnilvalue(obj) ((obj)->tt=LUA_TNIL) #define setnvalue(obj,x) \ { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } #define setpvalue(obj,x) \ { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } #define setbvalue(obj,x) \ { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } #define setsvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ checkliveness(G(L),i_o); } #define setuvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ checkliveness(G(L),i_o); } #define setthvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ checkliveness(G(L),i_o); } #define setclvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ checkliveness(G(L),i_o); } #define sethvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ checkliveness(G(L),i_o); } #define setptvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ checkliveness(G(L),i_o); } #define setobj(L,obj1,obj2) \ { const TValue *o2=(obj2); TValue *o1=(obj1); \ o1->value = o2->value; o1->tt=o2->tt; \ checkliveness(G(L),o1); } /* ** different types of sets, according to destination */ /* from stack to (same) stack */ #define setobjs2s setobj /* to stack (not from same stack) */ #define setobj2s setobj #define setsvalue2s setsvalue #define sethvalue2s sethvalue #define setptvalue2s setptvalue /* from table to same table */ #define setobjt2t setobj /* to table */ #define setobj2t setobj /* to new object */ #define setobj2n setobj #define setsvalue2n setsvalue #define setttype(obj, tt) (ttype(obj) = (tt)) #define iscollectable(o) (ttype(o) >= LUA_TSTRING) typedef TValue *StkId; /* index to stack elements */ /* ** String headers for string table */ typedef union TString { L_Umaxalign dummy; /* ensures maximum alignment for strings */ struct { CommonHeader; lu_byte reserved; unsigned int hash; size_t len; } tsv; } TString; #define getstr(ts) cast(const char *, (ts) + 1) #define svalue(o) getstr(tsvalue(o)) typedef union Udata { L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ struct { CommonHeader; struct Table *metatable; struct Table *env; size_t len; } uv; } Udata; /* ** Function Prototypes */ typedef struct Proto { CommonHeader; TValue *k; /* constants used by the function */ Instruction *code; struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines */ struct LocVar *locvars; /* information about local variables */ TString **upvalues; /* upvalue names */ TString *source; int sizeupvalues; int sizek; /* size of `k' */ int sizecode; int sizelineinfo; int sizep; /* size of `p' */ int sizelocvars; int linedefined; int lastlinedefined; GCObject *gclist; lu_byte nups; /* number of upvalues */ lu_byte numparams; lu_byte is_vararg; lu_byte maxstacksize; } Proto; /* masks for new-style vararg */ #define VARARG_HASARG 1 #define VARARG_ISVARARG 2 #define VARARG_NEEDSARG 4 typedef struct LocVar { TString *varname; int startpc; /* first point where variable is active */ int endpc; /* first point where variable is dead */ } LocVar; /* ** Upvalues */ typedef struct UpVal { CommonHeader; TValue *v; /* points to stack or to its own value */ union { TValue value; /* the value (when closed) */ struct { /* double linked list (when open) */ struct UpVal *prev; struct UpVal *next; } l; } u; } UpVal; /* ** Closures */ #define ClosureHeader \ CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \ struct Table *env typedef struct CClosure { ClosureHeader; lua_CFunction f; TValue upvalue[1]; } CClosure; typedef struct LClosure { ClosureHeader; struct Proto *p; UpVal *upvals[1]; } LClosure; typedef union Closure { CClosure c; LClosure l; } Closure; #define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC) #define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC) /* ** Tables */ typedef union TKey { struct { TValuefields; struct Node *next; /* for chaining */ } nk; TValue tvk; } TKey; typedef struct Node { TValue i_val; TKey i_key; } Node; typedef struct Table { CommonHeader; lu_byte flags; /* 1<

lsizenode)) #define luaO_nilobject (&luaO_nilobject_) LUAI_DATA const TValue luaO_nilobject_; #define ceillog2(x) (luaO_log2((x)-1) + 1) LUAI_FUNC int luaO_log2 (unsigned int x); LUAI_FUNC int luaO_int2fb (unsigned int x); LUAI_FUNC int luaO_fb2int (int x); LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2); LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result); LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp); LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); #endif tagua-1.0-alpha2/lua/src/lopcodes.c000066400000000000000000000055001077523320400171470ustar00rootroot00000000000000/* ** $Id: lopcodes.c,v 1.37 2005/11/08 19:45:36 roberto Exp $ ** See Copyright Notice in lua.h */ #define lopcodes_c #define LUA_CORE #include "lopcodes.h" /* ORDER OP */ const char *const luaP_opnames[NUM_OPCODES+1] = { "MOVE", "LOADK", "LOADBOOL", "LOADNIL", "GETUPVAL", "GETGLOBAL", "GETTABLE", "SETGLOBAL", "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF", "ADD", "SUB", "MUL", "DIV", "MOD", "POW", "UNM", "NOT", "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", "TESTSET", "CALL", "TAILCALL", "RETURN", "FORLOOP", "FORPREP", "TFORLOOP", "SETLIST", "CLOSE", "CLOSURE", "VARARG", NULL }; #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) const lu_byte luaP_opmodes[NUM_OPCODES] = { /* T A B C mode opcode */ opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_GETGLOBAL */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ ,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETGLOBAL */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */ ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TFORLOOP */ ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ }; tagua-1.0-alpha2/lua/src/lopcodes.h000066400000000000000000000176221077523320400171640ustar00rootroot00000000000000/* ** $Id: lopcodes.h,v 1.125 2006/03/14 19:04:44 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ #ifndef lopcodes_h #define lopcodes_h #include "llimits.h" /*=========================================================================== We assume that instructions are unsigned numbers. All instructions have an opcode in the first 6 bits. Instructions can have the following fields: `A' : 8 bits `B' : 9 bits `C' : 9 bits `Bx' : 18 bits (`B' and `C' together) `sBx' : signed Bx A signed argument is represented in excess K; that is, the number value is the unsigned value minus K. K is exactly the maximum value for that argument (so that -max is represented by 0, and +max is represented by 2*max), which is half the maximum for the corresponding unsigned argument. ===========================================================================*/ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ /* ** size and position of opcode arguments. */ #define SIZE_C 9 #define SIZE_B 9 #define SIZE_Bx (SIZE_C + SIZE_B) #define SIZE_A 8 #define SIZE_OP 6 #define POS_OP 0 #define POS_A (POS_OP + SIZE_OP) #define POS_C (POS_A + SIZE_A) #define POS_B (POS_C + SIZE_C) #define POS_Bx POS_C /* ** limits for opcode arguments. ** we use (signed) int to manipulate most arguments, ** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) */ #if SIZE_Bx < LUAI_BITSINT-1 #define MAXARG_Bx ((1<>1) /* `sBx' is signed */ #else #define MAXARG_Bx MAX_INT #define MAXARG_sBx MAX_INT #endif #define MAXARG_A ((1<>POS_OP) & MASK1(SIZE_OP,0))) #define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ ((cast(Instruction, o)<>POS_A) & MASK1(SIZE_A,0))) #define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ ((cast(Instruction, u)<>POS_B) & MASK1(SIZE_B,0))) #define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ ((cast(Instruction, b)<>POS_C) & MASK1(SIZE_C,0))) #define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \ ((cast(Instruction, b)<>POS_Bx) & MASK1(SIZE_Bx,0))) #define SETARG_Bx(i,b) ((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \ ((cast(Instruction, b)< C) then pc++ */ OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) =) R(A)*/ OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ } OpCode; #define NUM_OPCODES (cast(int, OP_VARARG) + 1) /*=========================================================================== Notes: (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, and can be 0: OP_CALL then sets `top' to last_result+1, so next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. (*) In OP_VARARG, if (B == 0) then use actual number of varargs and set top (like in OP_CALL with C == 0). (*) In OP_RETURN, if (B == 0) then return up to `top' (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next `instruction' is real C (*) For comparisons, A specifies what condition the test should accept (true or false). (*) All `skips' (pc++) assume that next instruction is a jump ===========================================================================*/ /* ** masks for instruction properties. The format is: ** bits 0-1: op mode ** bits 2-3: C arg mode ** bits 4-5: B arg mode ** bit 6: instruction set register A ** bit 7: operator is a test */ enum OpArgMask { OpArgN, /* argument is not used */ OpArgU, /* argument is used */ OpArgR, /* argument is a register or a jump offset */ OpArgK /* argument is a constant or register/constant */ }; LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; #define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) #define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3)) #define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) #define testAMode(m) (luaP_opmodes[m] & (1 << 6)) #define testTMode(m) (luaP_opmodes[m] & (1 << 7)) LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ /* number of list items to accumulate before a SETLIST instruction */ #define LFIELDS_PER_FLUSH 50 #endif tagua-1.0-alpha2/lua/src/loslib.c000066400000000000000000000136111077523320400166250ustar00rootroot00000000000000/* ** $Id: loslib.c,v 1.20 2006/09/19 13:57:08 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ #include #include #include #include #include #define loslib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" static int os_pushresult (lua_State *L, int i, const char *filename) { int en = errno; /* calls to Lua API may change this value */ if (i) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); lua_pushfstring(L, "%s: %s", filename, strerror(en)); lua_pushinteger(L, en); return 3; } } static int os_execute (lua_State *L) { lua_pushinteger(L, system(luaL_optstring(L, 1, NULL))); return 1; } static int os_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); return os_pushresult(L, remove(filename) == 0, filename); } static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); return os_pushresult(L, rename(fromname, toname) == 0, fromname); } static int os_tmpname (lua_State *L) { char buff[LUA_TMPNAMBUFSIZE]; int err; lua_tmpnam(buff, err); if (err) return luaL_error(L, "unable to generate a unique filename"); lua_pushstring(L, buff); return 1; } static int os_getenv (lua_State *L) { lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ return 1; } static int os_clock (lua_State *L) { lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); return 1; } /* ** {====================================================== ** Time/Date operations ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, ** wday=%w+1, yday=%j, isdst=? } ** ======================================================= */ static void setfield (lua_State *L, const char *key, int value) { lua_pushinteger(L, value); lua_setfield(L, -2, key); } static void setboolfield (lua_State *L, const char *key, int value) { if (value < 0) /* undefined? */ return; /* does not set field */ lua_pushboolean(L, value); lua_setfield(L, -2, key); } static int getboolfield (lua_State *L, const char *key) { int res; lua_getfield(L, -1, key); res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); lua_pop(L, 1); return res; } static int getfield (lua_State *L, const char *key, int d) { int res; lua_getfield(L, -1, key); if (lua_isnumber(L, -1)) res = (int)lua_tointeger(L, -1); else { if (d < 0) return luaL_error(L, "field " LUA_QS " missing in date table", key); res = d; } lua_pop(L, 1); return res; } static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); struct tm *stm; if (*s == '!') { /* UTC? */ stm = gmtime(&t); s++; /* skip `!' */ } else stm = localtime(&t); if (stm == NULL) /* invalid date? */ lua_pushnil(L); else if (strcmp(s, "*t") == 0) { lua_createtable(L, 0, 9); /* 9 = number of fields */ setfield(L, "sec", stm->tm_sec); setfield(L, "min", stm->tm_min); setfield(L, "hour", stm->tm_hour); setfield(L, "day", stm->tm_mday); setfield(L, "month", stm->tm_mon+1); setfield(L, "year", stm->tm_year+1900); setfield(L, "wday", stm->tm_wday+1); setfield(L, "yday", stm->tm_yday+1); setboolfield(L, "isdst", stm->tm_isdst); } else { char cc[3]; luaL_Buffer b; cc[0] = '%'; cc[2] = '\0'; luaL_buffinit(L, &b); for (; *s; s++) { if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ luaL_addchar(&b, *s); else { size_t reslen; char buff[200]; /* should be big enough for any conversion result */ cc[1] = *(++s); reslen = strftime(buff, sizeof(buff), cc, stm); luaL_addlstring(&b, buff, reslen); } } luaL_pushresult(&b); } return 1; } static int os_time (lua_State *L) { time_t t; if (lua_isnoneornil(L, 1)) /* called without args? */ t = time(NULL); /* get current time */ else { struct tm ts; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); /* make sure table is at the top */ ts.tm_sec = getfield(L, "sec", 0); ts.tm_min = getfield(L, "min", 0); ts.tm_hour = getfield(L, "hour", 12); ts.tm_mday = getfield(L, "day", -1); ts.tm_mon = getfield(L, "month", -1) - 1; ts.tm_year = getfield(L, "year", -1) - 1900; ts.tm_isdst = getboolfield(L, "isdst"); t = mktime(&ts); } if (t == (time_t)(-1)) lua_pushnil(L); else lua_pushnumber(L, (lua_Number)t); return 1; } static int os_difftime (lua_State *L) { lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), (time_t)(luaL_optnumber(L, 2, 0)))); return 1; } /* }====================================================== */ static int os_setlocale (lua_State *L) { static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME}; static const char *const catnames[] = {"all", "collate", "ctype", "monetary", "numeric", "time", NULL}; const char *l = luaL_optstring(L, 1, NULL); int op = luaL_checkoption(L, 2, "all", catnames); lua_pushstring(L, setlocale(cat[op], l)); return 1; } static int os_exit (lua_State *L) { exit(luaL_optint(L, 1, EXIT_SUCCESS)); return 0; /* to avoid warnings */ } static const luaL_Reg syslib[] = { {"clock", os_clock}, {"date", os_date}, {"difftime", os_difftime}, {"execute", os_execute}, {"exit", os_exit}, {"getenv", os_getenv}, {"remove", os_remove}, {"rename", os_rename}, {"setlocale", os_setlocale}, {"time", os_time}, {"tmpname", os_tmpname}, {NULL, NULL} }; /* }====================================================== */ LUALIB_API int luaopen_os (lua_State *L) { luaL_register(L, LUA_OSLIBNAME, syslib); return 1; } tagua-1.0-alpha2/lua/src/lparser.c000066400000000000000000001073411077523320400170150ustar00rootroot00000000000000/* ** $Id: lparser.c,v 2.42a 2006/06/05 15:57:59 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ #include #define lparser_c #define LUA_CORE #include "lua.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #define hasmultret(k) ((k) == VCALL || (k) == VVARARG) #define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) #define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m) /* ** nodes for block list (list of active blocks) */ typedef struct BlockCnt { struct BlockCnt *previous; /* chain */ int breaklist; /* list of jumps out of this loop */ lu_byte nactvar; /* # active locals outside the breakable structure */ lu_byte upval; /* true if some variable in the block is an upvalue */ lu_byte isbreakable; /* true if `block' is a loop */ } BlockCnt; /* ** prototypes for recursive non-terminal functions */ static void chunk (LexState *ls); static void expr (LexState *ls, expdesc *v); static void anchor_token (LexState *ls) { if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { TString *ts = ls->t.seminfo.ts; luaX_newstring(ls, getstr(ts), ts->tsv.len); } } static void error_expected (LexState *ls, int token) { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token))); } static void errorlimit (FuncState *fs, int limit, const char *what) { const char *msg = (fs->f->linedefined == 0) ? luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : luaO_pushfstring(fs->L, "function at line %d has more than %d %s", fs->f->linedefined, limit, what); luaX_lexerror(fs->ls, msg, 0); } static int testnext (LexState *ls, int c) { if (ls->t.token == c) { luaX_next(ls); return 1; } else return 0; } static void check (LexState *ls, int c) { if (ls->t.token != c) error_expected(ls, c); } static void checknext (LexState *ls, int c) { check(ls, c); luaX_next(ls); } #define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } static void check_match (LexState *ls, int what, int who, int where) { if (!testnext(ls, what)) { if (where == ls->linenumber) error_expected(ls, what); else { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, LUA_QS " expected (to close " LUA_QS " at line %d)", luaX_token2str(ls, what), luaX_token2str(ls, who), where)); } } } static TString *str_checkname (LexState *ls) { TString *ts; check(ls, TK_NAME); ts = ls->t.seminfo.ts; luaX_next(ls); return ts; } static void init_exp (expdesc *e, expkind k, int i) { e->f = e->t = NO_JUMP; e->k = k; e->u.s.info = i; } static void codestring (LexState *ls, expdesc *e, TString *s) { init_exp(e, VK, luaK_stringK(ls->fs, s)); } static void checkname(LexState *ls, expdesc *e) { codestring(ls, e, str_checkname(ls)); } static int registerlocalvar (LexState *ls, TString *varname) { FuncState *fs = ls->fs; Proto *f = fs->f; int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, LocVar, SHRT_MAX, "too many local variables"); while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; f->locvars[fs->nlocvars].varname = varname; luaC_objbarrier(ls->L, f, varname); return fs->nlocvars++; } #define new_localvarliteral(ls,v,n) \ new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n) static void new_localvar (LexState *ls, TString *name, int n) { FuncState *fs = ls->fs; luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables"); fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); } static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; fs->nactvar = cast_byte(fs->nactvar + nvars); for (; nvars; nvars--) { getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; } } static void removevars (LexState *ls, int tolevel) { FuncState *fs = ls->fs; while (fs->nactvar > tolevel) getlocvar(fs, --fs->nactvar).endpc = fs->pc; } static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { int i; Proto *f = fs->f; int oldsize = f->sizeupvalues; for (i=0; inups; i++) { if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) { lua_assert(f->upvalues[i] == name); return i; } } /* new one */ luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues"); luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, TString *, MAX_INT, ""); while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; f->upvalues[f->nups] = name; luaC_objbarrier(fs->L, f, name); lua_assert(v->k == VLOCAL || v->k == VUPVAL); fs->upvalues[f->nups].k = cast_byte(v->k); fs->upvalues[f->nups].info = cast_byte(v->u.s.info); return f->nups++; } static int searchvar (FuncState *fs, TString *n) { int i; for (i=fs->nactvar-1; i >= 0; i--) { if (n == getlocvar(fs, i).varname) return i; } return -1; /* not found */ } static void markupval (FuncState *fs, int level) { BlockCnt *bl = fs->bl; while (bl && bl->nactvar > level) bl = bl->previous; if (bl) bl->upval = 1; } static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { if (fs == NULL) { /* no more levels? */ init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ return VGLOBAL; } else { int v = searchvar(fs, n); /* look up at current level */ if (v >= 0) { init_exp(var, VLOCAL, v); if (!base) markupval(fs, v); /* local will be used as an upval */ return VLOCAL; } else { /* not found at current level; try upper one */ if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) return VGLOBAL; var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ var->k = VUPVAL; /* upvalue in this level */ return VUPVAL; } } } static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; if (singlevaraux(fs, varname, var, 1) == VGLOBAL) var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ } static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { FuncState *fs = ls->fs; int extra = nvars - nexps; if (hasmultret(e->k)) { extra++; /* includes call itself */ if (extra < 0) extra = 0; luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ if (extra > 1) luaK_reserveregs(fs, extra-1); } else { if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ if (extra > 0) { int reg = fs->freereg; luaK_reserveregs(fs, extra); luaK_nil(fs, reg, extra); } } } static void enterlevel (LexState *ls) { if (++ls->L->nCcalls > LUAI_MAXCCALLS) luaX_lexerror(ls, "chunk has too many syntax levels", 0); } #define leavelevel(ls) ((ls)->L->nCcalls--) static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { bl->breaklist = NO_JUMP; bl->isbreakable = isbreakable; bl->nactvar = fs->nactvar; bl->upval = 0; bl->previous = fs->bl; fs->bl = bl; lua_assert(fs->freereg == fs->nactvar); } static void leaveblock (FuncState *fs) { BlockCnt *bl = fs->bl; fs->bl = bl->previous; removevars(fs->ls, bl->nactvar); if (bl->upval) luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); /* a block either controls scope or breaks (never both) */ lua_assert(!bl->isbreakable || !bl->upval); lua_assert(bl->nactvar == fs->nactvar); fs->freereg = fs->nactvar; /* free registers */ luaK_patchtohere(fs, bl->breaklist); } static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { FuncState *fs = ls->fs; Proto *f = fs->f; int oldsize = f->sizep; int i; luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "constant table overflow"); while (oldsize < f->sizep) f->p[oldsize++] = NULL; f->p[fs->np++] = func->f; luaC_objbarrier(ls->L, f, func->f); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); for (i=0; if->nups; i++) { OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0); } } static void open_func (LexState *ls, FuncState *fs) { lua_State *L = ls->L; Proto *f = luaF_newproto(L); fs->f = f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; fs->L = L; ls->fs = fs; fs->pc = 0; fs->lasttarget = -1; fs->jpc = NO_JUMP; fs->freereg = 0; fs->nk = 0; fs->np = 0; fs->nlocvars = 0; fs->nactvar = 0; fs->bl = NULL; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ fs->h = luaH_new(L, 0, 0); /* anchor table of constants and prototype (to avoid being collected) */ sethvalue2s(L, L->top, fs->h); incr_top(L); setptvalue2s(L, L->top, f); incr_top(L); } static void close_func (LexState *ls) { lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; removevars(ls, 0); luaK_ret(fs, 0, 0); /* final return */ luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); f->sizecode = fs->pc; luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); f->sizelineinfo = fs->pc; luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); f->sizek = fs->nk; luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); f->sizep = fs->np; luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); f->sizelocvars = fs->nlocvars; luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *); f->sizeupvalues = f->nups; lua_assert(luaG_checkcode(f)); lua_assert(fs->bl == NULL); ls->fs = fs->prev; L->top -= 2; /* remove table and prototype from the stack */ /* last token read was anchored in defunct function; must reanchor it */ if (fs) anchor_token(ls); } Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { struct LexState lexstate; struct FuncState funcstate; lexstate.buff = buff; luaX_setinput(L, &lexstate, z, luaS_new(L, name)); open_func(&lexstate, &funcstate); funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ luaX_next(&lexstate); /* read first token */ chunk(&lexstate); check(&lexstate, TK_EOS); close_func(&lexstate); lua_assert(funcstate.prev == NULL); lua_assert(funcstate.f->nups == 0); lua_assert(lexstate.fs == NULL); return funcstate.f; } /*============================================================*/ /* GRAMMAR RULES */ /*============================================================*/ static void field (LexState *ls, expdesc *v) { /* field -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; expdesc key; luaK_exp2anyreg(fs, v); luaX_next(ls); /* skip the dot or colon */ checkname(ls, &key); luaK_indexed(fs, v, &key); } static void yindex (LexState *ls, expdesc *v) { /* index -> '[' expr ']' */ luaX_next(ls); /* skip the '[' */ expr(ls, v); luaK_exp2val(ls->fs, v); checknext(ls, ']'); } /* ** {====================================================================== ** Rules for Constructors ** ======================================================================= */ struct ConsControl { expdesc v; /* last list item read */ expdesc *t; /* table descriptor */ int nh; /* total number of `record' elements */ int na; /* total number of array elements */ int tostore; /* number of array elements pending to be stored */ }; static void recfield (LexState *ls, struct ConsControl *cc) { /* recfield -> (NAME | `['exp1`]') = exp1 */ FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc key, val; int rkkey; if (ls->t.token == TK_NAME) { luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); checkname(ls, &key); } else /* ls->t.token == '[' */ yindex(ls, &key); cc->nh++; checknext(ls, '='); rkkey = luaK_exp2RK(fs, &key); expr(ls, &val); luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val)); fs->freereg = reg; /* free registers */ } static void closelistfield (FuncState *fs, struct ConsControl *cc) { if (cc->v.k == VVOID) return; /* there is no list item */ luaK_exp2nextreg(fs, &cc->v); cc->v.k = VVOID; if (cc->tostore == LFIELDS_PER_FLUSH) { luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); /* flush */ cc->tostore = 0; /* no more items pending */ } } static void lastlistfield (FuncState *fs, struct ConsControl *cc) { if (cc->tostore == 0) return; if (hasmultret(cc->v.k)) { luaK_setmultret(fs, &cc->v); luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET); cc->na--; /* do not count last expression (unknown number of elements) */ } else { if (cc->v.k != VVOID) luaK_exp2nextreg(fs, &cc->v); luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); } } static void listfield (LexState *ls, struct ConsControl *cc) { expr(ls, &cc->v); luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); cc->na++; cc->tostore++; } static void constructor (LexState *ls, expdesc *t) { /* constructor -> ?? */ FuncState *fs = ls->fs; int line = ls->linenumber; int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); struct ConsControl cc; cc.na = cc.nh = cc.tostore = 0; cc.t = t; init_exp(t, VRELOCABLE, pc); init_exp(&cc.v, VVOID, 0); /* no value (yet) */ luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */ checknext(ls, '{'); do { lua_assert(cc.v.k == VVOID || cc.tostore > 0); if (ls->t.token == '}') break; closelistfield(fs, &cc); switch(ls->t.token) { case TK_NAME: { /* may be listfields or recfields */ luaX_lookahead(ls); if (ls->lookahead.token != '=') /* expression? */ listfield(ls, &cc); else recfield(ls, &cc); break; } case '[': { /* constructor_item -> recfield */ recfield(ls, &cc); break; } default: { /* constructor_part -> listfield */ listfield(ls, &cc); break; } } } while (testnext(ls, ',') || testnext(ls, ';')); check_match(ls, '}', '{', line); lastlistfield(fs, &cc); SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ } /* }====================================================================== */ static void parlist (LexState *ls) { /* parlist -> [ param { `,' param } ] */ FuncState *fs = ls->fs; Proto *f = fs->f; int nparams = 0; f->is_vararg = 0; if (ls->t.token != ')') { /* is `parlist' not empty? */ do { switch (ls->t.token) { case TK_NAME: { /* param -> NAME */ new_localvar(ls, str_checkname(ls), nparams++); break; } case TK_DOTS: { /* param -> `...' */ luaX_next(ls); #if defined(LUA_COMPAT_VARARG) /* use `arg' as default name */ new_localvarliteral(ls, "arg", nparams++); f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG; #endif f->is_vararg |= VARARG_ISVARARG; break; } default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); } } while (!f->is_vararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG)); luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } static void body (LexState *ls, expdesc *e, int needself, int line) { /* body -> `(' parlist `)' chunk END */ FuncState new_fs; open_func(ls, &new_fs); new_fs.f->linedefined = line; checknext(ls, '('); if (needself) { new_localvarliteral(ls, "self", 0); adjustlocalvars(ls, 1); } parlist(ls); checknext(ls, ')'); chunk(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); close_func(ls); pushclosure(ls, &new_fs, e); } static int explist1 (LexState *ls, expdesc *v) { /* explist1 -> expr { `,' expr } */ int n = 1; /* at least one expression */ expr(ls, v); while (testnext(ls, ',')) { luaK_exp2nextreg(ls->fs, v); expr(ls, v); n++; } return n; } static void funcargs (LexState *ls, expdesc *f) { FuncState *fs = ls->fs; expdesc args; int base, nparams; int line = ls->linenumber; switch (ls->t.token) { case '(': { /* funcargs -> `(' [ explist1 ] `)' */ if (line != ls->lastline) luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; else { explist1(ls, &args); luaK_setmultret(fs, &args); } check_match(ls, ')', '(', line); break; } case '{': { /* funcargs -> constructor */ constructor(ls, &args); break; } case TK_STRING: { /* funcargs -> STRING */ codestring(ls, &args, ls->t.seminfo.ts); luaX_next(ls); /* must use `seminfo' before `next' */ break; } default: { luaX_syntaxerror(ls, "function arguments expected"); return; } } lua_assert(f->k == VNONRELOC); base = f->u.s.info; /* base register for call */ if (hasmultret(args.k)) nparams = LUA_MULTRET; /* open call */ else { if (args.k != VVOID) luaK_exp2nextreg(fs, &args); /* close last argument */ nparams = fs->freereg - (base+1); } init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); luaK_fixline(fs, line); fs->freereg = base+1; /* call remove function and arguments and leaves (unless changed) one result */ } /* ** {====================================================================== ** Expression parsing ** ======================================================================= */ static void prefixexp (LexState *ls, expdesc *v) { /* prefixexp -> NAME | '(' expr ')' */ switch (ls->t.token) { case '(': { int line = ls->linenumber; luaX_next(ls); expr(ls, v); check_match(ls, ')', '(', line); luaK_dischargevars(ls->fs, v); return; } case TK_NAME: { singlevar(ls, v); return; } default: { luaX_syntaxerror(ls, "unexpected symbol"); return; } } } static void primaryexp (LexState *ls, expdesc *v) { /* primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; prefixexp(ls, v); for (;;) { switch (ls->t.token) { case '.': { /* field */ field(ls, v); break; } case '[': { /* `[' exp1 `]' */ expdesc key; luaK_exp2anyreg(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; } case ':': { /* `:' NAME funcargs */ expdesc key; luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); funcargs(ls, v); break; } case '(': case TK_STRING: case '{': { /* funcargs */ luaK_exp2nextreg(fs, v); funcargs(ls, v); break; } default: return; } } } static void simpleexp (LexState *ls, expdesc *v) { /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp */ switch (ls->t.token) { case TK_NUMBER: { init_exp(v, VKNUM, 0); v->u.nval = ls->t.seminfo.r; break; } case TK_STRING: { codestring(ls, v, ls->t.seminfo.ts); break; } case TK_NIL: { init_exp(v, VNIL, 0); break; } case TK_TRUE: { init_exp(v, VTRUE, 0); break; } case TK_FALSE: { init_exp(v, VFALSE, 0); break; } case TK_DOTS: { /* vararg */ FuncState *fs = ls->fs; check_condition(ls, fs->f->is_vararg, "cannot use " LUA_QL("...") " outside a vararg function"); fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } case '{': { /* constructor */ constructor(ls, v); return; } case TK_FUNCTION: { luaX_next(ls); body(ls, v, 0, ls->linenumber); return; } default: { primaryexp(ls, v); return; } } luaX_next(ls); } static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; case '#': return OPR_LEN; default: return OPR_NOUNOPR; } } static BinOpr getbinopr (int op) { switch (op) { case '+': return OPR_ADD; case '-': return OPR_SUB; case '*': return OPR_MUL; case '/': return OPR_DIV; case '%': return OPR_MOD; case '^': return OPR_POW; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; case TK_EQ: return OPR_EQ; case '<': return OPR_LT; case TK_LE: return OPR_LE; case '>': return OPR_GT; case TK_GE: return OPR_GE; case TK_AND: return OPR_AND; case TK_OR: return OPR_OR; default: return OPR_NOBINOPR; } } static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ {10, 9}, {5, 4}, /* power and concat (right associative) */ {3, 3}, {3, 3}, /* equality and inequality */ {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ {2, 2}, {1, 1} /* logical (and/or) */ }; #define UNARY_PRIORITY 8 /* priority for unary operators */ /* ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** where `binop' is any binary operator with a priority higher than `limit' */ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { BinOpr op; UnOpr uop; enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); luaK_prefix(ls->fs, uop, v); } else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ op = getbinopr(ls->t.token); while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, &v2, priority[op].right); luaK_posfix(ls->fs, op, v, &v2); op = nextop; } leavelevel(ls); return op; /* return first untreated operator */ } static void expr (LexState *ls, expdesc *v) { subexpr(ls, v, 0); } /* }==================================================================== */ /* ** {====================================================================== ** Rules for Statements ** ======================================================================= */ static int block_follow (int token) { switch (token) { case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_UNTIL: case TK_EOS: return 1; default: return 0; } } static void block (LexState *ls) { /* block -> chunk */ FuncState *fs = ls->fs; BlockCnt bl; enterblock(fs, &bl, 0); chunk(ls); lua_assert(bl.breaklist == NO_JUMP); leaveblock(fs); } /* ** structure to chain all variables in the left-hand side of an ** assignment */ struct LHS_assign { struct LHS_assign *prev; expdesc v; /* variable (global, local, upvalue, or indexed) */ }; /* ** check whether, in an assignment to a local variable, the local variable ** is needed in a previous assignment (to a table). If so, save original ** local value in a safe place and use this safe copy in the previous ** assignment. */ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { FuncState *fs = ls->fs; int extra = fs->freereg; /* eventual position to save local variable */ int conflict = 0; for (; lh; lh = lh->prev) { if (lh->v.k == VINDEXED) { if (lh->v.u.s.info == v->u.s.info) { /* conflict? */ conflict = 1; lh->v.u.s.info = extra; /* previous assignment will use safe copy */ } if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */ conflict = 1; lh->v.u.s.aux = extra; /* previous assignment will use safe copy */ } } } if (conflict) { luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */ luaK_reserveregs(fs, 1); } } static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { expdesc e; check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, "syntax error"); if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ struct LHS_assign nv; nv.prev = lh; primaryexp(ls, &nv.v); if (nv.v.k == VLOCAL) check_conflict(ls, lh, &nv.v); assignment(ls, &nv, nvars+1); } else { /* assignment -> `=' explist1 */ int nexps; checknext(ls, '='); nexps = explist1(ls, &e); if (nexps != nvars) { adjust_assign(ls, nvars, nexps, &e); if (nexps > nvars) ls->fs->freereg -= nexps - nvars; /* remove extra values */ } else { luaK_setoneret(ls->fs, &e); /* close last expression */ luaK_storevar(ls->fs, &lh->v, &e); return; /* avoid default */ } } init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ luaK_storevar(ls->fs, &lh->v, &e); } static int cond (LexState *ls) { /* cond -> exp */ expdesc v; expr(ls, &v); /* read condition */ if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ luaK_goiftrue(ls->fs, &v); return v.f; } static void breakstat (LexState *ls) { FuncState *fs = ls->fs; BlockCnt *bl = fs->bl; int upval = 0; while (bl && !bl->isbreakable) { upval |= bl->upval; bl = bl->previous; } if (!bl) luaX_syntaxerror(ls, "no loop to break"); if (upval) luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); } static void whilestat (LexState *ls, int line) { /* whilestat -> WHILE cond DO block END */ FuncState *fs = ls->fs; int whileinit; int condexit; BlockCnt bl; luaX_next(ls); /* skip WHILE */ whileinit = luaK_getlabel(fs); condexit = cond(ls); enterblock(fs, &bl, 1); checknext(ls, TK_DO); block(ls); luaK_patchlist(fs, luaK_jump(fs), whileinit); check_match(ls, TK_END, TK_WHILE, line); leaveblock(fs); luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ } static void repeatstat (LexState *ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ int condexit; FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); BlockCnt bl1, bl2; enterblock(fs, &bl1, 1); /* loop block */ enterblock(fs, &bl2, 0); /* scope block */ luaX_next(ls); /* skip REPEAT */ chunk(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); condexit = cond(ls); /* read condition (inside scope block) */ if (!bl2.upval) { /* no upvalues? */ leaveblock(fs); /* finish scope */ luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ } else { /* complete semantics when there are upvalues */ breakstat(ls); /* if condition then break */ luaK_patchtohere(ls->fs, condexit); /* else... */ leaveblock(fs); /* finish scope... */ luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ } leaveblock(fs); /* finish loop */ } static int exp1 (LexState *ls) { expdesc e; int k; expr(ls, &e); k = e.k; luaK_exp2nextreg(ls->fs, &e); return k; } static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { /* forbody -> DO block */ BlockCnt bl; FuncState *fs = ls->fs; int prep, endfor; adjustlocalvars(ls, 3); /* control variables */ checknext(ls, TK_DO); prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); enterblock(fs, &bl, 0); /* scope for declared variables */ adjustlocalvars(ls, nvars); luaK_reserveregs(fs, nvars); block(ls); leaveblock(fs); /* end of scope for declared variables */ luaK_patchtohere(fs, prep); endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); } static void fornum (LexState *ls, TString *varname, int line) { /* fornum -> NAME = exp1,exp1[,exp1] forbody */ FuncState *fs = ls->fs; int base = fs->freereg; new_localvarliteral(ls, "(for index)", 0); new_localvarliteral(ls, "(for limit)", 1); new_localvarliteral(ls, "(for step)", 2); new_localvar(ls, varname, 3); checknext(ls, '='); exp1(ls); /* initial value */ checknext(ls, ','); exp1(ls); /* limit */ if (testnext(ls, ',')) exp1(ls); /* optional step */ else { /* default step = 1 */ luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); luaK_reserveregs(fs, 1); } forbody(ls, base, line, 1, 1); } static void forlist (LexState *ls, TString *indexname) { /* forlist -> NAME {,NAME} IN explist1 forbody */ FuncState *fs = ls->fs; expdesc e; int nvars = 0; int line; int base = fs->freereg; /* create control variables */ new_localvarliteral(ls, "(for generator)", nvars++); new_localvarliteral(ls, "(for state)", nvars++); new_localvarliteral(ls, "(for control)", nvars++); /* create declared variables */ new_localvar(ls, indexname, nvars++); while (testnext(ls, ',')) new_localvar(ls, str_checkname(ls), nvars++); checknext(ls, TK_IN); line = ls->linenumber; adjust_assign(ls, 3, explist1(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base, line, nvars - 3, 0); } static void forstat (LexState *ls, int line) { /* forstat -> FOR (fornum | forlist) END */ FuncState *fs = ls->fs; TString *varname; BlockCnt bl; enterblock(fs, &bl, 1); /* scope for loop and control variables */ luaX_next(ls); /* skip `for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { case '=': fornum(ls, varname, line); break; case ',': case TK_IN: forlist(ls, varname); break; default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); } check_match(ls, TK_END, TK_FOR, line); leaveblock(fs); /* loop scope (`break' jumps to this point) */ } static int test_then_block (LexState *ls) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ int condexit; luaX_next(ls); /* skip IF or ELSEIF */ condexit = cond(ls); checknext(ls, TK_THEN); block(ls); /* `then' part */ return condexit; } static void ifstat (LexState *ls, int line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ FuncState *fs = ls->fs; int flist; int escapelist = NO_JUMP; flist = test_then_block(ls); /* IF cond THEN block */ while (ls->t.token == TK_ELSEIF) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, flist); flist = test_then_block(ls); /* ELSEIF cond THEN block */ } if (ls->t.token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, flist); luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ block(ls); /* `else' part */ } else luaK_concat(fs, &escapelist, flist); luaK_patchtohere(fs, escapelist); check_match(ls, TK_END, TK_IF, line); } static void localfunc (LexState *ls) { expdesc v, b; FuncState *fs = ls->fs; new_localvar(ls, str_checkname(ls), 0); init_exp(&v, VLOCAL, fs->freereg); luaK_reserveregs(fs, 1); adjustlocalvars(ls, 1); body(ls, &b, 0, ls->linenumber); luaK_storevar(fs, &v, &b); /* debug information will only see the variable after this point! */ getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; } static void localstat (LexState *ls) { /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */ int nvars = 0; int nexps; expdesc e; do { new_localvar(ls, str_checkname(ls), nvars++); } while (testnext(ls, ',')); if (testnext(ls, '=')) nexps = explist1(ls, &e); else { e.k = VVOID; nexps = 0; } adjust_assign(ls, nvars, nexps, &e); adjustlocalvars(ls, nvars); } static int funcname (LexState *ls, expdesc *v) { /* funcname -> NAME {field} [`:' NAME] */ int needself = 0; singlevar(ls, v); while (ls->t.token == '.') field(ls, v); if (ls->t.token == ':') { needself = 1; field(ls, v); } return needself; } static void funcstat (LexState *ls, int line) { /* funcstat -> FUNCTION funcname body */ int needself; expdesc v, b; luaX_next(ls); /* skip FUNCTION */ needself = funcname(ls, &v); body(ls, &b, needself, line); luaK_storevar(ls->fs, &v, &b); luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ } static void exprstat (LexState *ls) { /* stat -> func | assignment */ FuncState *fs = ls->fs; struct LHS_assign v; primaryexp(ls, &v.v); if (v.v.k == VCALL) /* stat -> func */ SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ else { /* stat -> assignment */ v.prev = NULL; assignment(ls, &v, 1); } } static void retstat (LexState *ls) { /* stat -> RETURN explist */ FuncState *fs = ls->fs; expdesc e; int first, nret; /* registers with returned values */ luaX_next(ls); /* skip RETURN */ if (block_follow(ls->t.token) || ls->t.token == ';') first = nret = 0; /* return no values */ else { nret = explist1(ls, &e); /* optional return values */ if (hasmultret(e.k)) { luaK_setmultret(fs, &e); if (e.k == VCALL && nret == 1) { /* tail call? */ SET_OPCODE(getcode(fs,&e), OP_TAILCALL); lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); } first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ } else { if (nret == 1) /* only one single value? */ first = luaK_exp2anyreg(fs, &e); else { luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ first = fs->nactvar; /* return all `active' values */ lua_assert(nret == fs->freereg - first); } } } luaK_ret(fs, first, nret); } static int statement (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ switch (ls->t.token) { case TK_IF: { /* stat -> ifstat */ ifstat(ls, line); return 0; } case TK_WHILE: { /* stat -> whilestat */ whilestat(ls, line); return 0; } case TK_DO: { /* stat -> DO block END */ luaX_next(ls); /* skip DO */ block(ls); check_match(ls, TK_END, TK_DO, line); return 0; } case TK_FOR: { /* stat -> forstat */ forstat(ls, line); return 0; } case TK_REPEAT: { /* stat -> repeatstat */ repeatstat(ls, line); return 0; } case TK_FUNCTION: { funcstat(ls, line); /* stat -> funcstat */ return 0; } case TK_LOCAL: { /* stat -> localstat */ luaX_next(ls); /* skip LOCAL */ if (testnext(ls, TK_FUNCTION)) /* local function? */ localfunc(ls); else localstat(ls); return 0; } case TK_RETURN: { /* stat -> retstat */ retstat(ls); return 1; /* must be last statement */ } case TK_BREAK: { /* stat -> breakstat */ luaX_next(ls); /* skip BREAK */ breakstat(ls); return 1; /* must be last statement */ } default: { exprstat(ls); return 0; /* to avoid warnings */ } } } static void chunk (LexState *ls) { /* chunk -> { stat [`;'] } */ int islast = 0; enterlevel(ls); while (!islast && !block_follow(ls->t.token)) { islast = statement(ls); testnext(ls, ';'); lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && ls->fs->freereg >= ls->fs->nactvar); ls->fs->freereg = ls->fs->nactvar; /* free registers */ } leavelevel(ls); } /* }====================================================================== */ tagua-1.0-alpha2/lua/src/lparser.h000066400000000000000000000043211077523320400170140ustar00rootroot00000000000000/* ** $Id: lparser.h,v 1.57 2006/03/09 18:14:31 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ #ifndef lparser_h #define lparser_h #include "llimits.h" #include "lobject.h" #include "lzio.h" /* ** Expression descriptor */ typedef enum { VVOID, /* no value */ VNIL, VTRUE, VFALSE, VK, /* info = index of constant in `k' */ VKNUM, /* nval = numerical value */ VLOCAL, /* info = local register */ VUPVAL, /* info = index of upvalue in `upvalues' */ VGLOBAL, /* info = index of table; aux = index of global name in `k' */ VINDEXED, /* info = table register; aux = index register (or `k') */ VJMP, /* info = instruction pc */ VRELOCABLE, /* info = instruction pc */ VNONRELOC, /* info = result register */ VCALL, /* info = instruction pc */ VVARARG /* info = instruction pc */ } expkind; typedef struct expdesc { expkind k; union { struct { int info, aux; } s; lua_Number nval; } u; int t; /* patch list of `exit when true' */ int f; /* patch list of `exit when false' */ } expdesc; typedef struct upvaldesc { lu_byte k; lu_byte info; } upvaldesc; struct BlockCnt; /* defined in lparser.c */ /* state needed to generate code for a given function */ typedef struct FuncState { Proto *f; /* current function header */ Table *h; /* table to find (and reuse) elements in `k' */ struct FuncState *prev; /* enclosing function */ struct LexState *ls; /* lexical state */ struct lua_State *L; /* copy of the Lua state */ struct BlockCnt *bl; /* chain of current blocks */ int pc; /* next position to code (equivalent to `ncode') */ int lasttarget; /* `pc' of last `jump target' */ int jpc; /* list of pending jumps to `pc' */ int freereg; /* first free register */ int nk; /* number of elements in `k' */ int np; /* number of elements in `p' */ short nlocvars; /* number of elements in `locvars' */ lu_byte nactvar; /* number of active local variables */ upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */ unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */ } FuncState; LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name); #endif tagua-1.0-alpha2/lua/src/lstate.c000066400000000000000000000130061077523320400166330ustar00rootroot00000000000000/* ** $Id: lstate.c,v 2.36 2006/05/24 14:15:50 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ #include #define lstate_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "llex.h" #include "lmem.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #define state_size(x) (sizeof(x) + LUAI_EXTRASPACE) #define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE) #define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE)) /* ** Main thread combines a thread state and the global state */ typedef struct LG { lua_State l; global_State g; } LG; static void stack_init (lua_State *L1, lua_State *L) { /* initialize CallInfo array */ L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); L1->ci = L1->base_ci; L1->size_ci = BASIC_CI_SIZE; L1->end_ci = L1->base_ci + L1->size_ci - 1; /* initialize stack array */ L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; L1->top = L1->stack; L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; /* initialize first ci */ L1->ci->func = L1->top; setnilvalue(L1->top++); /* `function' entry for this `ci' */ L1->base = L1->ci->base = L1->top; L1->ci->top = L1->top + LUA_MINSTACK; } static void freestack (lua_State *L, lua_State *L1) { luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); luaM_freearray(L, L1->stack, L1->stacksize, TValue); } /* ** open parts that may cause memory-allocation errors */ static void f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); luaX_init(L); luaS_fix(luaS_newliteral(L, MEMERRMSG)); g->GCthreshold = 4*g->totalbytes; } static void preinit_state (lua_State *L, global_State *g) { G(L) = g; L->stack = NULL; L->stacksize = 0; L->errorJmp = NULL; L->hook = NULL; L->hookmask = 0; L->basehookcount = 0; L->allowhook = 1; resethookcount(L); L->openupval = NULL; L->size_ci = 0; L->nCcalls = 0; L->status = 0; L->base_ci = L->ci = NULL; L->savedpc = NULL; L->errfunc = 0; setnilvalue(gt(L)); } static void close_state (lua_State *L) { global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_freeall(L); /* collect all objects */ lua_assert(g->rootgc == obj2gco(L)); lua_assert(g->strt.nuse == 0); luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); luaZ_freebuffer(L, &g->buff); freestack(L, L); lua_assert(g->totalbytes == sizeof(LG)); (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); } lua_State *luaE_newthread (lua_State *L) { lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); luaC_link(L, obj2gco(L1), LUA_TTHREAD); preinit_state(L1, G(L)); stack_init(L1, L); /* init stack */ setobj2n(L, gt(L1), gt(L)); /* share table of globals */ L1->hookmask = L->hookmask; L1->basehookcount = L->basehookcount; L1->hook = L->hook; resethookcount(L1); lua_assert(iswhite(obj2gco(L1))); return L1; } void luaE_freethread (lua_State *L, lua_State *L1) { luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); luai_userstatefree(L1); freestack(L, L1); luaM_freemem(L, fromstate(L1), state_size(lua_State)); } LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { int i; lua_State *L; global_State *g; void *l = (*f)(ud, NULL, 0, state_size(LG)); if (l == NULL) return NULL; L = tostate(l); g = &((LG *)L)->g; L->next = NULL; L->tt = LUA_TTHREAD; g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); L->marked = luaC_white(g); set2bits(L->marked, FIXEDBIT, SFIXEDBIT); preinit_state(L, g); g->frealloc = f; g->ud = ud; g->mainthread = L; g->uvhead.u.l.prev = &g->uvhead; g->uvhead.u.l.next = &g->uvhead; g->GCthreshold = 0; /* mark it as unfinished state */ g->strt.size = 0; g->strt.nuse = 0; g->strt.hash = NULL; setnilvalue(registry(L)); luaZ_initbuffer(L, &g->buff); g->panic = NULL; g->gcstate = GCSpause; g->rootgc = obj2gco(L); g->sweepstrgc = 0; g->sweepgc = &g->rootgc; g->gray = NULL; g->grayagain = NULL; g->weak = NULL; g->tmudata = NULL; g->totalbytes = sizeof(LG); g->gcpause = LUAI_GCPAUSE; g->gcstepmul = LUAI_GCMUL; g->gcdept = 0; for (i=0; imt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { /* memory allocation error: free partial state */ close_state(L); L = NULL; } else luai_userstateopen(L); return L; } static void callallgcTM (lua_State *L, void *ud) { UNUSED(ud); luaC_callGCTM(L); /* call GC metamethods for all udata */ } LUA_API void lua_close (lua_State *L) { L = G(L)->mainthread; /* only the main thread can be closed */ lua_lock(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ L->errfunc = 0; /* no error function during GC metamethods */ do { /* repeat until no more errors */ L->ci = L->base_ci; L->base = L->top = L->ci->base; L->nCcalls = 0; } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); lua_assert(G(L)->tmudata == NULL); luai_userstateclose(L); close_state(L); } tagua-1.0-alpha2/lua/src/lstate.h000066400000000000000000000115041077523320400166410ustar00rootroot00000000000000/* ** $Id: lstate.h,v 2.24 2006/02/06 18:27:59 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ #ifndef lstate_h #define lstate_h #include "lua.h" #include "lobject.h" #include "ltm.h" #include "lzio.h" struct lua_longjmp; /* defined in ldo.c */ /* table of globals */ #define gt(L) (&L->l_gt) /* registry */ #define registry(L) (&G(L)->l_registry) /* extra stack space to handle TM calls and some other extras */ #define EXTRA_STACK 5 #define BASIC_CI_SIZE 8 #define BASIC_STACK_SIZE (2*LUA_MINSTACK) typedef struct stringtable { GCObject **hash; lu_int32 nuse; /* number of elements */ int size; } stringtable; /* ** informations about a call */ typedef struct CallInfo { StkId base; /* base for this function */ StkId func; /* function index in the stack */ StkId top; /* top for this function */ const Instruction *savedpc; int nresults; /* expected number of results from this function */ int tailcalls; /* number of tail calls lost under this entry */ } CallInfo; #define curr_func(L) (clvalue(L->ci->func)) #define ci_func(ci) (clvalue((ci)->func)) #define f_isLua(ci) (!ci_func(ci)->c.isC) #define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci)) /* ** `global state', shared by all threads of this state */ typedef struct global_State { stringtable strt; /* hash table for strings */ lua_Alloc frealloc; /* function to reallocate memory */ void *ud; /* auxiliary data to `frealloc' */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ int sweepstrgc; /* position of sweep in `strt' */ GCObject *rootgc; /* list of all collectable objects */ GCObject **sweepgc; /* position of sweep in `rootgc' */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of weak tables (to be cleared) */ GCObject *tmudata; /* last element of list of userdata to be GC */ Mbuffer buff; /* temporary buffer for string concatentation */ lu_mem GCthreshold; lu_mem totalbytes; /* number of bytes currently allocated */ lu_mem estimate; /* an estimate of number of bytes actually in use */ lu_mem gcdept; /* how much GC is `behind schedule' */ int gcpause; /* size of pause between successive GCs */ int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ TValue l_registry; struct lua_State *mainthread; UpVal uvhead; /* head of double-linked list of all open upvalues */ struct Table *mt[NUM_TAGS]; /* metatables for basic types */ TString *tmname[TM_N]; /* array with tag-method names */ } global_State; /* ** `per thread' state */ struct lua_State { CommonHeader; lu_byte status; StkId top; /* first free slot in the stack */ StkId base; /* base of current function */ global_State *l_G; CallInfo *ci; /* call info for current function */ const Instruction *savedpc; /* `savedpc' of current function */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ CallInfo *end_ci; /* points after end of ci array*/ CallInfo *base_ci; /* array of CallInfo's */ int stacksize; int size_ci; /* size of array `base_ci' */ unsigned short nCcalls; /* number of nested C calls */ lu_byte hookmask; lu_byte allowhook; int basehookcount; int hookcount; lua_Hook hook; TValue l_gt; /* table of globals */ TValue env; /* temporary place for environments */ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ ptrdiff_t errfunc; /* current error handling function (stack index) */ }; #define G(L) (L->l_G) /* ** Union of all collectable objects */ union GCObject { GCheader gch; union TString ts; union Udata u; union Closure cl; struct Table h; struct Proto p; struct UpVal uv; struct lua_State th; /* thread */ }; /* macros to convert a GCObject into a specific value */ #define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) #define gco2ts(o) (&rawgco2ts(o)->tsv) #define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) #define gco2u(o) (&rawgco2u(o)->uv) #define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) #define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) #define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) #define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) #define ngcotouv(o) \ check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv)) #define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) /* macro to convert any Lua object into a GCObject */ #define obj2gco(v) (cast(GCObject *, (v))) LUAI_FUNC lua_State *luaE_newthread (lua_State *L); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); #endif tagua-1.0-alpha2/lua/src/lstring.c000066400000000000000000000060421077523320400170230ustar00rootroot00000000000000/* ** $Id: lstring.c,v 2.8 2005/12/22 16:19:56 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ #include #define lstring_c #define LUA_CORE #include "lua.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" void luaS_resize (lua_State *L, int newsize) { GCObject **newhash; stringtable *tb; int i; if (G(L)->gcstate == GCSsweepstring) return; /* cannot resize during GC traverse */ newhash = luaM_newvector(L, newsize, GCObject *); tb = &G(L)->strt; for (i=0; isize; i++) { GCObject *p = tb->hash[i]; while (p) { /* for each node in the list */ GCObject *next = p->gch.next; /* save next */ unsigned int h = gco2ts(p)->hash; int h1 = lmod(h, newsize); /* new position */ lua_assert(cast_int(h%newsize) == lmod(h, newsize)); p->gch.next = newhash[h1]; /* chain it */ newhash[h1] = p; p = next; } } luaM_freearray(L, tb->hash, tb->size, TString *); tb->size = newsize; tb->hash = newhash; } static TString *newlstr (lua_State *L, const char *str, size_t l, unsigned int h) { TString *ts; stringtable *tb; if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) luaM_toobig(L); ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); ts->tsv.len = l; ts->tsv.hash = h; ts->tsv.marked = luaC_white(G(L)); ts->tsv.tt = LUA_TSTRING; ts->tsv.reserved = 0; memcpy(ts+1, str, l*sizeof(char)); ((char *)(ts+1))[l] = '\0'; /* ending 0 */ tb = &G(L)->strt; h = lmod(h, tb->size); ts->tsv.next = tb->hash[h]; /* chain new entry */ tb->hash[h] = obj2gco(ts); tb->nuse++; if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) luaS_resize(L, tb->size*2); /* too crowded */ return ts; } TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { GCObject *o; unsigned int h = cast(unsigned int, l); /* seed */ size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ size_t l1; for (l1=l; l1>=step; l1-=step) /* compute hash */ h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; o != NULL; o = o->gch.next) { TString *ts = rawgco2ts(o); if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { /* string may be dead */ if (isdead(G(L), o)) changewhite(o); return ts; } } return newlstr(L, str, l, h); /* not found */ } Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { Udata *u; if (s > MAX_SIZET - sizeof(Udata)) luaM_toobig(L); u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); u->uv.marked = luaC_white(G(L)); /* is not finalized */ u->uv.tt = LUA_TUSERDATA; u->uv.len = s; u->uv.metatable = NULL; u->uv.env = e; /* chain it on udata list (after main thread) */ u->uv.next = G(L)->mainthread->next; G(L)->mainthread->next = obj2gco(u); return u; } tagua-1.0-alpha2/lua/src/lstring.h000066400000000000000000000014521077523320400170300ustar00rootroot00000000000000/* ** $Id: lstring.h,v 1.43 2005/04/25 19:24:10 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ #ifndef lstring_h #define lstring_h #include "lgc.h" #include "lobject.h" #include "lstate.h" #define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char)) #define sizeudata(u) (sizeof(union Udata)+(u)->len) #define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s))) #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) #define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) LUAI_FUNC void luaS_resize (lua_State *L, int newsize); LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); #endif tagua-1.0-alpha2/lua/src/lstrlib.c000066400000000000000000000554551077523320400170300ustar00rootroot00000000000000/* ** $Id: lstrlib.c,v 1.132a 2006/04/26 20:41:19 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ #include #include #include #include #include #define lstrlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* macro to `unsign' a character */ #define uchar(c) ((unsigned char)(c)) static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); lua_pushinteger(L, l); return 1; } static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { /* relative string position: negative means back from end */ return (pos>=0) ? pos : (ptrdiff_t)len+pos+1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; if (start <= end) lua_pushlstring(L, s+start-1, end-start+1); else lua_pushliteral(L, ""); return 1; } static int str_reverse (lua_State *L) { size_t l; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); luaL_buffinit(L, &b); while (l--) luaL_addchar(&b, s[l]); luaL_pushresult(&b); return 1; } static int str_lower (lua_State *L) { size_t l; size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); luaL_buffinit(L, &b); for (i=0; i 0) luaL_addlstring(&b, s, l); luaL_pushresult(&b); return 1; } static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); int n, i; if (posi <= 0) posi = 1; if ((size_t)pose > l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ n = (int)(pose - posi + 1); if (posi + n <= pose) /* overflow? */ luaL_error(L, "string slice too long"); luaL_checkstack(L, n, "string slice too long"); for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) return luaL_error(ms->L, "invalid capture index"); return l; } static int capture_to_close (MatchState *ms) { int level = ms->level; for (level--; level>=0; level--) if (ms->capture[level].len == CAP_UNFINISHED) return level; return luaL_error(ms->L, "invalid pattern capture"); } static const char *classend (MatchState *ms, const char *p) { switch (*p++) { case L_ESC: { if (*p == '\0') luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a `]' */ if (*p == '\0') luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); if (*(p++) == L_ESC && *p != '\0') p++; /* skip escapes (e.g. `%]') */ } while (*p != ']'); return p+1; } default: { return p; } } } static int match_class (int c, int cl) { int res; switch (tolower(cl)) { case 'a' : res = isalpha(c); break; case 'c' : res = iscntrl(c); break; case 'd' : res = isdigit(c); break; case 'l' : res = islower(c); break; case 'p' : res = ispunct(c); break; case 's' : res = isspace(c); break; case 'u' : res = isupper(c); break; case 'w' : res = isalnum(c); break; case 'x' : res = isxdigit(c); break; case 'z' : res = (c == 0); break; default: return (cl == c); } return (islower(cl) ? res : !res); } static int matchbracketclass (int c, const char *p, const char *ec) { int sig = 1; if (*(p+1) == '^') { sig = 0; p++; /* skip the `^' */ } while (++p < ec) { if (*p == L_ESC) { p++; if (match_class(c, uchar(*p))) return sig; } else if ((*(p+1) == '-') && (p+2 < ec)) { p+=2; if (uchar(*(p-2)) <= c && c <= uchar(*p)) return sig; } else if (uchar(*p) == c) return sig; } return !sig; } static int singlematch (int c, const char *p, const char *ep) { switch (*p) { case '.': return 1; /* matches any char */ case L_ESC: return match_class(c, uchar(*(p+1))); case '[': return matchbracketclass(c, p, ep-1); default: return (uchar(*p) == c); } } static const char *match (MatchState *ms, const char *s, const char *p); static const char *matchbalance (MatchState *ms, const char *s, const char *p) { if (*p == 0 || *(p+1) == 0) luaL_error(ms->L, "unbalanced pattern"); if (*s != *p) return NULL; else { int b = *p; int e = *(p+1); int cont = 1; while (++s < ms->src_end) { if (*s == e) { if (--cont == 0) return s+1; } else if (*s == b) cont++; } } return NULL; /* string ends out of balance */ } static const char *max_expand (MatchState *ms, const char *s, const char *p, const char *ep) { ptrdiff_t i = 0; /* counts maximum expand for item */ while ((s+i)src_end && singlematch(uchar(*(s+i)), p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { const char *res = match(ms, (s+i), ep+1); if (res) return res; i--; /* else didn't match; reduce 1 repetition to try again */ } return NULL; } static const char *min_expand (MatchState *ms, const char *s, const char *p, const char *ep) { for (;;) { const char *res = match(ms, s, ep+1); if (res != NULL) return res; else if (ssrc_end && singlematch(uchar(*s), p, ep)) s++; /* try with one more repetition */ else return NULL; } } static const char *start_capture (MatchState *ms, const char *s, const char *p, int what) { const char *res; int level = ms->level; if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); ms->capture[level].init = s; ms->capture[level].len = what; ms->level = level+1; if ((res=match(ms, s, p)) == NULL) /* match failed? */ ms->level--; /* undo capture */ return res; } static const char *end_capture (MatchState *ms, const char *s, const char *p) { int l = capture_to_close(ms); const char *res; ms->capture[l].len = s - ms->capture[l].init; /* close capture */ if ((res = match(ms, s, p)) == NULL) /* match failed? */ ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ return res; } static const char *match_capture (MatchState *ms, const char *s, int l) { size_t len; l = check_capture(ms, l); len = ms->capture[l].len; if ((size_t)(ms->src_end-s) >= len && memcmp(ms->capture[l].init, s, len) == 0) return s+len; else return NULL; } static const char *match (MatchState *ms, const char *s, const char *p) { init: /* using goto's to optimize tail recursion */ switch (*p) { case '(': { /* start capture */ if (*(p+1) == ')') /* position capture? */ return start_capture(ms, s, p+2, CAP_POSITION); else return start_capture(ms, s, p+1, CAP_UNFINISHED); } case ')': { /* end capture */ return end_capture(ms, s, p+1); } case L_ESC: { switch (*(p+1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p+2); if (s == NULL) return NULL; p+=4; goto init; /* else return match(ms, s, p+4); */ } case 'f': { /* frontier? */ const char *ep; char previous; p += 2; if (*p != '[') luaL_error(ms->L, "missing " LUA_QL("[") " after " LUA_QL("%%f") " in pattern"); ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s-1); if (matchbracketclass(uchar(previous), p, ep-1) || !matchbracketclass(uchar(*s), p, ep-1)) return NULL; p=ep; goto init; /* else return match(ms, s, ep); */ } default: { if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ s = match_capture(ms, s, uchar(*(p+1))); if (s == NULL) return NULL; p+=2; goto init; /* else return match(ms, s, p+2) */ } goto dflt; /* case default */ } } } case '\0': { /* end of pattern */ return s; /* match succeeded */ } case '$': { if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ return (s == ms->src_end) ? s : NULL; /* check end of string */ else goto dflt; } default: dflt: { /* it is a pattern item */ const char *ep = classend(ms, p); /* points to what is next */ int m = ssrc_end && singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { /* optional */ const char *res; if (m && ((res=match(ms, s+1, ep+1)) != NULL)) return res; p=ep+1; goto init; /* else return match(ms, s, ep+1); */ } case '*': { /* 0 or more repetitions */ return max_expand(ms, s, p, ep); } case '+': { /* 1 or more repetitions */ return (m ? max_expand(ms, s+1, p, ep) : NULL); } case '-': { /* 0 or more repetitions (minimum) */ return min_expand(ms, s, p, ep); } default: { if (!m) return NULL; s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ } } } } } static const char *lmemfind (const char *s1, size_t l1, const char *s2, size_t l2) { if (l2 == 0) return s1; /* empty strings are everywhere */ else if (l2 > l1) return NULL; /* avoids a negative `l1' */ else { const char *init; /* to search for a `*s2' inside `s1' */ l2--; /* 1st char will be checked by `memchr' */ l1 = l1-l2; /* `s2' cannot be found after that */ while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { init++; /* 1st char is already checked */ if (memcmp(init, s2+1, l2) == 0) return init-1; else { /* correct `l1' and `s1' to try again */ l1 -= init-s1; s1 = init; } } return NULL; /* not found */ } } static void push_onecapture (MatchState *ms, int i, const char *s, const char *e) { if (i >= ms->level) { if (i == 0) /* ms->level == 0, too */ lua_pushlstring(ms->L, s, e - s); /* add whole match */ else luaL_error(ms->L, "invalid capture index"); } else { ptrdiff_t l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); else lua_pushlstring(ms->L, ms->capture[i].init, l); } } static int push_captures (MatchState *ms, const char *s, const char *e) { int i; int nlevels = (ms->level == 0 && s) ? 1 : ms->level; luaL_checkstack(ms->L, nlevels, "too many captures"); for (i = 0; i < nlevels; i++) push_onecapture(ms, i, s, e); return nlevels; /* number of strings pushed */ } static int str_find_aux (lua_State *L, int find) { size_t l1, l2; const char *s = luaL_checklstring(L, 1, &l1); const char *p = luaL_checklstring(L, 2, &l2); ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; if (init < 0) init = 0; else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; if (find && (lua_toboolean(L, 4) || /* explicit request? */ strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ /* do a plain search */ const char *s2 = lmemfind(s+init, l1-init, p, l2); if (s2) { lua_pushinteger(L, s2-s+1); lua_pushinteger(L, s2-s+l2); return 2; } } else { MatchState ms; int anchor = (*p == '^') ? (p++, 1) : 0; const char *s1=s+init; ms.L = L; ms.src_init = s; ms.src_end = s+l1; do { const char *res; ms.level = 0; if ((res=match(&ms, s1, p)) != NULL) { if (find) { lua_pushinteger(L, s1-s+1); /* start */ lua_pushinteger(L, res-s); /* end */ return push_captures(&ms, NULL, 0) + 2; } else return push_captures(&ms, s1, res); } } while (s1++ < ms.src_end && !anchor); } lua_pushnil(L); /* not found */ return 1; } static int str_find (lua_State *L) { return str_find_aux(L, 1); } static int str_match (lua_State *L) { return str_find_aux(L, 0); } static int gmatch_aux (lua_State *L) { MatchState ms; size_t ls; const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); const char *p = lua_tostring(L, lua_upvalueindex(2)); const char *src; ms.L = L; ms.src_init = s; ms.src_end = s+ls; for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); src <= ms.src_end; src++) { const char *e; ms.level = 0; if ((e = match(&ms, src, p)) != NULL) { lua_Integer newstart = e-s; if (e == src) newstart++; /* empty match? go at least one position */ lua_pushinteger(L, newstart); lua_replace(L, lua_upvalueindex(3)); return push_captures(&ms, src, e); } } return 0; /* not found */ } static int gmatch (lua_State *L) { luaL_checkstring(L, 1); luaL_checkstring(L, 2); lua_settop(L, 2); lua_pushinteger(L, 0); lua_pushcclosure(L, gmatch_aux, 3); return 1; } static int gfind_nodef (lua_State *L) { return luaL_error(L, LUA_QL("string.gfind") " was renamed to " LUA_QL("string.gmatch")); } static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { size_t l, i; const char *news = lua_tolstring(ms->L, 3, &l); for (i = 0; i < l; i++) { if (news[i] != L_ESC) luaL_addchar(b, news[i]); else { i++; /* skip ESC */ if (!isdigit(uchar(news[i]))) luaL_addchar(b, news[i]); else if (news[i] == '0') luaL_addlstring(b, s, e - s); else { push_onecapture(ms, news[i] - '1', s, e); luaL_addvalue(b); /* add capture to accumulated result */ } } } } static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { lua_State *L = ms->L; switch (lua_type(L, 3)) { case LUA_TNUMBER: case LUA_TSTRING: { add_s(ms, b, s, e); return; } case LUA_TFUNCTION: { int n; lua_pushvalue(L, 3); n = push_captures(ms, s, e); lua_call(L, n, 1); break; } case LUA_TTABLE: { push_onecapture(ms, 0, s, e); lua_gettable(L, 3); break; } default: { luaL_argerror(L, 3, "string/function/table expected"); return; } } if (!lua_toboolean(L, -1)) { /* nil or false? */ lua_pop(L, 1); lua_pushlstring(L, s, e - s); /* keep original text */ } else if (!lua_isstring(L, -1)) luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); luaL_addvalue(b); /* add result to accumulator */ } static int str_gsub (lua_State *L) { size_t srcl; const char *src = luaL_checklstring(L, 1, &srcl); const char *p = luaL_checkstring(L, 2); int max_s = luaL_optint(L, 4, srcl+1); int anchor = (*p == '^') ? (p++, 1) : 0; int n = 0; MatchState ms; luaL_Buffer b; luaL_buffinit(L, &b); ms.L = L; ms.src_init = src; ms.src_end = src+srcl; while (n < max_s) { const char *e; ms.level = 0; e = match(&ms, src, p); if (e) { n++; add_value(&ms, &b, src, e); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ else if (src < ms.src_end) luaL_addchar(&b, *src++); else break; if (anchor) break; } luaL_addlstring(&b, src, ms.src_end-src); luaL_pushresult(&b); lua_pushinteger(L, n); /* number of substitutions */ return 2; } /* }====================================================== */ /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ #define MAX_ITEM 512 /* valid flags in a format specification */ #define FLAGS "-+ #0" /* ** maximum size of each format specification (such as '%-099.99d') ** (+10 accounts for %99.99x plus margin of error) */ #define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { size_t l; const char *s = luaL_checklstring(L, arg, &l); luaL_addchar(b, '"'); while (l--) { switch (*s) { case '"': case '\\': case '\n': { luaL_addchar(b, '\\'); luaL_addchar(b, *s); break; } case '\r': { luaL_addlstring(b, "\\r", 2); break; } case '\0': { luaL_addlstring(b, "\\000", 4); break; } default: { luaL_addchar(b, *s); break; } } s++; } luaL_addchar(b, '"'); } static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) luaL_error(L, "invalid format (repeated flags)"); if (isdigit(uchar(*p))) p++; /* skip width */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ if (*p == '.') { p++; if (isdigit(uchar(*p))) p++; /* skip precision */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ } if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; strncpy(form, strfrmt, p - strfrmt + 1); form += p - strfrmt + 1; *form = '\0'; return p; } static void addintlen (char *form) { size_t l = strlen(form); char spec = form[l - 1]; strcpy(form + l - 1, LUA_INTFRMLEN); form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; } static int str_format (lua_State *L) { int arg = 1; size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); const char *strfrmt_end = strfrmt+sfl; luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { if (*strfrmt != L_ESC) luaL_addchar(&b, *strfrmt++); else if (*++strfrmt == L_ESC) luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ char buff[MAX_ITEM]; /* to store the formatted item */ arg++; strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { sprintf(buff, form, (int)luaL_checknumber(L, arg)); break; } case 'd': case 'i': { addintlen(form); sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); break; } case 'o': case 'u': case 'x': case 'X': { addintlen(form); sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { sprintf(buff, form, (double)luaL_checknumber(L, arg)); break; } case 'q': { addquoted(L, &b, arg); continue; /* skip the 'addsize' at the end */ } case 's': { size_t l; const char *s = luaL_checklstring(L, arg, &l); if (!strchr(form, '.') && l >= 100) { /* no precision and string is too long to be formatted; keep original string */ lua_pushvalue(L, arg); luaL_addvalue(&b); continue; /* skip the `addsize' at the end */ } else { sprintf(buff, form, s); break; } } default: { /* also treat cases `pnLlh' */ return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " LUA_QL("format"), *(strfrmt - 1)); } } luaL_addlstring(&b, buff, strlen(buff)); } } luaL_pushresult(&b); return 1; } static const luaL_Reg strlib[] = { {"byte", str_byte}, {"char", str_char}, {"dump", str_dump}, {"find", str_find}, {"format", str_format}, {"gfind", gfind_nodef}, {"gmatch", gmatch}, {"gsub", str_gsub}, {"len", str_len}, {"lower", str_lower}, {"match", str_match}, {"rep", str_rep}, {"reverse", str_reverse}, {"sub", str_sub}, {"upper", str_upper}, {NULL, NULL} }; static void createmetatable (lua_State *L) { lua_createtable(L, 0, 1); /* create metatable for strings */ lua_pushliteral(L, ""); /* dummy string */ lua_pushvalue(L, -2); lua_setmetatable(L, -2); /* set string metatable */ lua_pop(L, 1); /* pop dummy string */ lua_pushvalue(L, -2); /* string library... */ lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ lua_pop(L, 1); /* pop metatable */ } /* ** Open string library */ LUALIB_API int luaopen_string (lua_State *L) { luaL_register(L, LUA_STRLIBNAME, strlib); #if defined(LUA_COMPAT_GFIND) lua_getfield(L, -1, "gmatch"); lua_setfield(L, -2, "gfind"); #endif createmetatable(L); return 1; } tagua-1.0-alpha2/lua/src/ltable.c000066400000000000000000000376101077523320400166110ustar00rootroot00000000000000/* ** $Id: ltable.c,v 2.32 2006/01/18 11:49:02 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ /* ** Implementation of tables (aka arrays, objects, or hash tables). ** Tables keep its elements in two parts: an array part and a hash part. ** Non-negative integer keys are all candidates to be kept in the array ** part. The actual size of the array is the largest `n' such that at ** least half the slots between 0 and n are in use. ** Hash uses a mix of chained scatter table with Brent's variation. ** A main invariant of these tables is that, if an element is not ** in its main position (i.e. the `original' position that its hash gives ** to it), then the colliding element is in its own main position. ** Hence even when the load factor reaches 100%, performance remains good. */ #include #include #define ltable_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "ltable.h" /* ** max size of array part is 2^MAXBITS */ #if LUAI_BITSINT > 26 #define MAXBITS 26 #else #define MAXBITS (LUAI_BITSINT-2) #endif #define MAXASIZE (1 << MAXBITS) #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) #define hashstr(t,str) hashpow2(t, (str)->tsv.hash) #define hashboolean(t,p) hashpow2(t, p) /* ** for some types, it is better to avoid modulus by power of 2, as ** they tend to have many 2 factors. */ #define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) #define hashpointer(t,p) hashmod(t, IntPoint(p)) /* ** number of ints inside a lua_Number */ #define numints cast_int(sizeof(lua_Number)/sizeof(int)) #define dummynode (&dummynode_) static const Node dummynode_ = { {{NULL}, LUA_TNIL}, /* value */ {{{NULL}, LUA_TNIL, NULL}} /* key */ }; /* ** hash for lua_Numbers */ static Node *hashnum (const Table *t, lua_Number n) { unsigned int a[numints]; int i; n += 1; /* normalize number (avoid -0) */ lua_assert(sizeof(a) <= sizeof(n)); memcpy(a, &n, sizeof(a)); for (i = 1; i < numints; i++) a[0] += a[i]; return hashmod(t, a[0]); } /* ** returns the `main' position of an element in a table (that is, the index ** of its hash value) */ static Node *mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNUMBER: return hashnum(t, nvalue(key)); case LUA_TSTRING: return hashstr(t, rawtsvalue(key)); case LUA_TBOOLEAN: return hashboolean(t, bvalue(key)); case LUA_TLIGHTUSERDATA: return hashpointer(t, pvalue(key)); default: return hashpointer(t, gcvalue(key)); } } /* ** returns the index for `key' if `key' is an appropriate key to live in ** the array part of the table, -1 otherwise. */ static int arrayindex (const TValue *key) { if (ttisnumber(key)) { lua_Number n = nvalue(key); int k; lua_number2int(k, n); if (luai_numeq(cast_num(k), n)) return k; } return -1; /* `key' did not match some condition */ } /* ** returns the index of a `key' for table traversals. First goes all ** elements in the array part, then elements in the hash part. The ** beginning of a traversal is signalled by -1. */ static int findindex (lua_State *L, Table *t, StkId key) { int i; if (ttisnil(key)) return -1; /* first iteration */ i = arrayindex(key); if (0 < i && i <= t->sizearray) /* is `key' inside array part? */ return i-1; /* yes; that's the index (corrected to C) */ else { Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ /* key may be dead already, but it is ok to use it in `next' */ if (luaO_rawequalObj(key2tval(n), key) || (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && gcvalue(gkey(n)) == gcvalue(key))) { i = cast_int(n - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ return i + t->sizearray; } else n = gnext(n); } while (n); luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */ return 0; /* to avoid warnings */ } } int luaH_next (lua_State *L, Table *t, StkId key) { int i = findindex(L, t, key); /* find original element */ for (i++; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ setnvalue(key, cast_num(i+1)); setobj2s(L, key+1, &t->array[i]); return 1; } } for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ setobj2s(L, key, key2tval(gnode(t, i))); setobj2s(L, key+1, gval(gnode(t, i))); return 1; } } return 0; /* no more elements */ } /* ** {============================================================= ** Rehash ** ============================================================== */ static int computesizes (int nums[], int *narray) { int i; int twotoi; /* 2^i */ int a = 0; /* number of elements smaller than 2^i */ int na = 0; /* number of elements to go to array part */ int n = 0; /* optimal size for array part */ for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { if (nums[i] > 0) { a += nums[i]; if (a > twotoi/2) { /* more than half elements present? */ n = twotoi; /* optimal size (till now) */ na = a; /* all elements smaller than n will go to array part */ } } if (a == *narray) break; /* all elements already counted */ } *narray = n; lua_assert(*narray/2 <= na && na <= *narray); return na; } static int countint (const TValue *key, int *nums) { int k = arrayindex(key); if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ nums[ceillog2(k)]++; /* count as such */ return 1; } else return 0; } static int numusearray (const Table *t, int *nums) { int lg; int ttlg; /* 2^lg */ int ause = 0; /* summation of `nums' */ int i = 1; /* count to traverse all array keys */ for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ int lc = 0; /* counter */ int lim = ttlg; if (lim > t->sizearray) { lim = t->sizearray; /* adjust upper limit */ if (i > lim) break; /* no more elements to count */ } /* count elements in range (2^(lg-1), 2^lg] */ for (; i <= lim; i++) { if (!ttisnil(&t->array[i-1])) lc++; } nums[lg] += lc; ause += lc; } return ause; } static int numusehash (const Table *t, int *nums, int *pnasize) { int totaluse = 0; /* total number of elements */ int ause = 0; /* summation of `nums' */ int i = sizenode(t); while (i--) { Node *n = &t->node[i]; if (!ttisnil(gval(n))) { ause += countint(key2tval(n), nums); totaluse++; } } *pnasize += ause; return totaluse; } static void setarrayvector (lua_State *L, Table *t, int size) { int i; luaM_reallocvector(L, t->array, t->sizearray, size, TValue); for (i=t->sizearray; iarray[i]); t->sizearray = size; } static void setnodevector (lua_State *L, Table *t, int size) { int lsize; if (size == 0) { /* no elements to hash part? */ t->node = cast(Node *, dummynode); /* use common `dummynode' */ lsize = 0; } else { int i; lsize = ceillog2(size); if (lsize > MAXBITS) luaG_runerror(L, "table overflow"); size = twoto(lsize); t->node = luaM_newvector(L, size, Node); for (i=0; ilsizenode = cast_byte(lsize); t->lastfree = gnode(t, size); /* all positions are free */ } static void resize (lua_State *L, Table *t, int nasize, int nhsize) { int i; int oldasize = t->sizearray; int oldhsize = t->lsizenode; Node *nold = t->node; /* save old hash ... */ if (nasize > oldasize) /* array part must grow? */ setarrayvector(L, t, nasize); /* create new hash part with appropriate size */ setnodevector(L, t, nhsize); if (nasize < oldasize) { /* array part must shrink? */ t->sizearray = nasize; /* re-insert elements from vanishing slice */ for (i=nasize; iarray[i])) setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]); } /* shrink array */ luaM_reallocvector(L, t->array, oldasize, nasize, TValue); } /* re-insert elements from hash part */ for (i = twoto(oldhsize) - 1; i >= 0; i--) { Node *old = nold+i; if (!ttisnil(gval(old))) setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); } if (nold != dummynode) luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ } void luaH_resizearray (lua_State *L, Table *t, int nasize) { int nsize = (t->node == dummynode) ? 0 : sizenode(t); resize(L, t, nasize, nsize); } static void rehash (lua_State *L, Table *t, const TValue *ek) { int nasize, na; int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */ int i; int totaluse; for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ nasize = numusearray(t, nums); /* count keys in array part */ totaluse = nasize; /* all those keys are integer keys */ totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ /* count extra key */ nasize += countint(ek, nums); totaluse++; /* compute new size for array part */ na = computesizes(nums, &nasize); /* resize the table to new computed sizes */ resize(L, t, nasize, totaluse - na); } /* ** }============================================================= */ Table *luaH_new (lua_State *L, int narray, int nhash) { Table *t = luaM_new(L, Table); luaC_link(L, obj2gco(t), LUA_TTABLE); t->metatable = NULL; t->flags = cast_byte(~0); /* temporary values (kept only if some malloc fails) */ t->array = NULL; t->sizearray = 0; t->lsizenode = 0; t->node = cast(Node *, dummynode); setarrayvector(L, t, narray); setnodevector(L, t, nhash); return t; } void luaH_free (lua_State *L, Table *t) { if (t->node != dummynode) luaM_freearray(L, t->node, sizenode(t), Node); luaM_freearray(L, t->array, t->sizearray, TValue); luaM_free(L, t); } static Node *getfreepos (Table *t) { while (t->lastfree-- > t->node) { if (ttisnil(gkey(t->lastfree))) return t->lastfree; } return NULL; /* could not find a free place */ } /* ** inserts a new key into a hash table; first, check whether key's main ** position is free. If not, check whether colliding node is in its main ** position or not: if it is not, move colliding node to an empty place and ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { Node *mp = mainposition(t, key); if (!ttisnil(gval(mp)) || mp == dummynode) { Node *othern; Node *n = getfreepos(t); /* get a free place */ if (n == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ return luaH_set(L, t, key); /* re-insert key into grown table */ } lua_assert(n != dummynode); othern = mainposition(t, key2tval(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ gnext(mp) = NULL; /* now `mp' is free */ setnilvalue(gval(mp)); } else { /* colliding node is in its own main position */ /* new node will go into free position */ gnext(n) = gnext(mp); /* chain new position */ gnext(mp) = n; mp = n; } } gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; luaC_barriert(L, t, key); lua_assert(ttisnil(gval(mp))); return gval(mp); } /* ** search function for integers */ const TValue *luaH_getnum (Table *t, int key) { /* (1 <= key && key <= t->sizearray) */ if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) return &t->array[key-1]; else { lua_Number nk = cast_num(key); Node *n = hashnum(t, nk); do { /* check whether `key' is somewhere in the chain */ if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) return gval(n); /* that's it */ else n = gnext(n); } while (n); return luaO_nilobject; } } /* ** search function for strings */ const TValue *luaH_getstr (Table *t, TString *key) { Node *n = hashstr(t, key); do { /* check whether `key' is somewhere in the chain */ if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) return gval(n); /* that's it */ else n = gnext(n); } while (n); return luaO_nilobject; } /* ** main search function */ const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNIL: return luaO_nilobject; case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { int k; lua_Number n = nvalue(key); lua_number2int(k, n); if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ return luaH_getnum(t, k); /* use specialized version */ /* else go through */ } default: { Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ if (luaO_rawequalObj(key2tval(n), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); return luaO_nilobject; } } } TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { const TValue *p = luaH_get(t, key); t->flags = 0; if (p != luaO_nilobject) return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); else if (ttisnumber(key) && luai_numisnan(nvalue(key))) luaG_runerror(L, "table index is NaN"); return newkey(L, t, key); } } TValue *luaH_setnum (lua_State *L, Table *t, int key) { const TValue *p = luaH_getnum(t, key); if (p != luaO_nilobject) return cast(TValue *, p); else { TValue k; setnvalue(&k, cast_num(key)); return newkey(L, t, &k); } } TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { const TValue *p = luaH_getstr(t, key); if (p != luaO_nilobject) return cast(TValue *, p); else { TValue k; setsvalue(L, &k, key); return newkey(L, t, &k); } } static int unbound_search (Table *t, unsigned int j) { unsigned int i = j; /* i is zero or a present index */ j++; /* find `i' and `j' such that i is present and j is not */ while (!ttisnil(luaH_getnum(t, j))) { i = j; j *= 2; if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ /* table was built with bad purposes: resort to linear search */ i = 1; while (!ttisnil(luaH_getnum(t, i))) i++; return i - 1; } } /* now do a binary search between them */ while (j - i > 1) { unsigned int m = (i+j)/2; if (ttisnil(luaH_getnum(t, m))) j = m; else i = m; } return i; } /* ** Try to find a boundary in table `t'. A `boundary' is an integer index ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). */ int luaH_getn (Table *t) { unsigned int j = t->sizearray; if (j > 0 && ttisnil(&t->array[j - 1])) { /* there is a boundary in the array part: (binary) search for it */ unsigned int i = 0; while (j - i > 1) { unsigned int m = (i+j)/2; if (ttisnil(&t->array[m - 1])) j = m; else i = m; } return i; } /* else must find a boundary in hash part */ else if (t->node == dummynode) /* hash part is empty? */ return j; /* that is easy... */ else return unbound_search(t, j); } #if defined(LUA_DEBUG) Node *luaH_mainposition (const Table *t, const TValue *key) { return mainposition(t, key); } int luaH_isdummy (Node *n) { return n == dummynode; } #endif tagua-1.0-alpha2/lua/src/ltable.h000066400000000000000000000022341077523320400166100ustar00rootroot00000000000000/* ** $Id: ltable.h,v 2.10 2006/01/10 13:13:06 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ #ifndef ltable_h #define ltable_h #include "lobject.h" #define gnode(t,i) (&(t)->node[i]) #define gkey(n) (&(n)->i_key.nk) #define gval(n) (&(n)->i_val) #define gnext(n) ((n)->i_key.nk.next) #define key2tval(n) (&(n)->i_key.tvk) LUAI_FUNC const TValue *luaH_getnum (Table *t, int key); LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash); LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize); LUAI_FUNC void luaH_free (lua_State *L, Table *t); LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); LUAI_FUNC int luaH_getn (Table *t); #if defined(LUA_DEBUG) LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); LUAI_FUNC int luaH_isdummy (Node *n); #endif #endif tagua-1.0-alpha2/lua/src/ltablib.c000066400000000000000000000156111077523320400167540ustar00rootroot00000000000000/* ** $Id: ltablib.c,v 1.38 2005/10/23 17:38:15 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ #include #define ltablib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" #define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) static int foreachi (lua_State *L) { int i; int n = aux_getn(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); for (i=1; i <= n; i++) { lua_pushvalue(L, 2); /* function */ lua_pushinteger(L, i); /* 1st argument */ lua_rawgeti(L, 1, i); /* 2nd argument */ lua_call(L, 2, 1); if (!lua_isnil(L, -1)) return 1; lua_pop(L, 1); /* remove nil result */ } return 0; } static int foreach (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 2, LUA_TFUNCTION); lua_pushnil(L); /* first key */ while (lua_next(L, 1)) { lua_pushvalue(L, 2); /* function */ lua_pushvalue(L, -3); /* key */ lua_pushvalue(L, -3); /* value */ lua_call(L, 2, 1); if (!lua_isnil(L, -1)) return 1; lua_pop(L, 2); /* remove value and result */ } return 0; } static int maxn (lua_State *L) { lua_Number max = 0; luaL_checktype(L, 1, LUA_TTABLE); lua_pushnil(L); /* first key */ while (lua_next(L, 1)) { lua_pop(L, 1); /* remove value */ if (lua_type(L, -1) == LUA_TNUMBER) { lua_Number v = lua_tonumber(L, -1); if (v > max) max = v; } } lua_pushnumber(L, max); return 1; } static int getn (lua_State *L) { lua_pushinteger(L, aux_getn(L, 1)); return 1; } static int setn (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); #ifndef luaL_setn luaL_setn(L, 1, luaL_checkint(L, 2)); #else luaL_error(L, LUA_QL("setn") " is obsolete"); #endif lua_pushvalue(L, 1); return 1; } static int tinsert (lua_State *L) { int e = aux_getn(L, 1) + 1; /* first empty element */ int pos; /* where to insert new element */ switch (lua_gettop(L)) { case 2: { /* called with only 2 arguments */ pos = e; /* insert new element at the end */ break; } case 3: { int i; pos = luaL_checkint(L, 2); /* 2nd argument is the position */ if (pos > e) e = pos; /* `grow' array if necessary */ for (i = e; i > pos; i--) { /* move up elements */ lua_rawgeti(L, 1, i-1); lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ } break; } default: { return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); } } luaL_setn(L, 1, e); /* new size */ lua_rawseti(L, 1, pos); /* t[pos] = v */ return 0; } static int tremove (lua_State *L) { int e = aux_getn(L, 1); int pos = luaL_optint(L, 2, e); if (e == 0) return 0; /* table is `empty' */ luaL_setn(L, 1, e - 1); /* t.n = n-1 */ lua_rawgeti(L, 1, pos); /* result = t[pos] */ for ( ;pos= P */ while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { if (i>u) luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[i] */ } /* repeat --j until a[j] <= P */ while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { if (j #define ltm_c #define LUA_CORE #include "lua.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" const char *const luaT_typenames[] = { "nil", "boolean", "userdata", "number", "string", "table", "function", "userdata", "thread", "proto", "upval" }; void luaT_init (lua_State *L) { static const char *const luaT_eventname[] = { /* ORDER TM */ "__index", "__newindex", "__gc", "__mode", "__eq", "__add", "__sub", "__mul", "__div", "__mod", "__pow", "__unm", "__len", "__lt", "__le", "__concat", "__call" }; int i; for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); luaS_fix(G(L)->tmname[i]); /* never collect these names */ } } /* ** function to be used with macro "fasttm": optimized for absence of ** tag methods */ const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { const TValue *tm = luaH_getstr(events, ename); lua_assert(event <= TM_EQ); if (ttisnil(tm)) { /* no tag method? */ events->flags |= cast_byte(1u<metatable; break; case LUA_TUSERDATA: mt = uvalue(o)->metatable; break; default: mt = G(L)->mt[ttype(o)]; } return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); } tagua-1.0-alpha2/lua/src/ltm.h000066400000000000000000000017661077523320400161520ustar00rootroot00000000000000/* ** $Id: ltm.h,v 2.6 2005/06/06 13:30:25 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ #ifndef ltm_h #define ltm_h #include "lobject.h" /* * WARNING: if you change the order of this enumeration, * grep "ORDER TM" */ typedef enum { TM_INDEX, TM_NEWINDEX, TM_GC, TM_MODE, TM_EQ, /* last tag method with `fast' access */ TM_ADD, TM_SUB, TM_MUL, TM_DIV, TM_MOD, TM_POW, TM_UNM, TM_LEN, TM_LT, TM_LE, TM_CONCAT, TM_CALL, TM_N /* number of elements in the enum */ } TMS; #define gfasttm(g,et,e) ((et) == NULL ? NULL : \ ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) #define fasttm(l,et,e) gfasttm(G(l), et, e) LUAI_DATA const char *const luaT_typenames[]; LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event); LUAI_FUNC void luaT_init (lua_State *L); #endif tagua-1.0-alpha2/lua/src/lua.c000066400000000000000000000235271077523320400161310ustar00rootroot00000000000000/* ** $Id: lua.c,v 1.160 2006/06/02 15:34:00 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ #include #include #include #include #define lua_c #include "lua.h" #include "lauxlib.h" #include "lualib.h" static lua_State *globalL = NULL; static const char *progname = LUA_PROGNAME; static void lstop (lua_State *L, lua_Debug *ar) { (void)ar; /* unused arg. */ lua_sethook(L, NULL, 0, 0); luaL_error(L, "interrupted!"); } static void laction (int i) { signal(i, SIG_DFL); /* if another SIGINT happens before lstop, terminate process (default action) */ lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } static void print_usage (void) { fprintf(stderr, "usage: %s [options] [script [args]].\n" "Available options are:\n" " -e stat execute string " LUA_QL("stat") "\n" " -l name require library " LUA_QL("name") "\n" " -i enter interactive mode after executing " LUA_QL("script") "\n" " -v show version information\n" " -- stop handling options\n" " - execute stdin and stop handling options\n" , progname); fflush(stderr); } static void l_message (const char *pname, const char *msg) { if (pname) fprintf(stderr, "%s: ", pname); fprintf(stderr, "%s\n", msg); fflush(stderr); } static int report (lua_State *L, int status) { if (status && !lua_isnil(L, -1)) { const char *msg = lua_tostring(L, -1); if (msg == NULL) msg = "(error object is not a string)"; l_message(progname, msg); lua_pop(L, 1); } return status; } static int traceback (lua_State *L) { lua_getfield(L, LUA_GLOBALSINDEX, "debug"); if (!lua_istable(L, -1)) { lua_pop(L, 1); return 1; } lua_getfield(L, -1, "traceback"); if (!lua_isfunction(L, -1)) { lua_pop(L, 2); return 1; } lua_pushvalue(L, 1); /* pass error message */ lua_pushinteger(L, 2); /* skip this function and traceback */ lua_call(L, 2, 1); /* call debug.traceback */ return 1; } static int docall (lua_State *L, int narg, int clear) { int status; int base = lua_gettop(L) - narg; /* function index */ lua_pushcfunction(L, traceback); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ signal(SIGINT, laction); status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); signal(SIGINT, SIG_DFL); lua_remove(L, base); /* remove traceback function */ /* force a complete garbage collection in case of errors */ if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); return status; } static void print_version (void) { l_message(NULL, LUA_RELEASE " " LUA_COPYRIGHT); } static int getargs (lua_State *L, char **argv, int n) { int narg; int i; int argc = 0; while (argv[argc]) argc++; /* count total number of arguments */ narg = argc - (n + 1); /* number of arguments to the script */ luaL_checkstack(L, narg + 3, "too many arguments to script"); for (i=n+1; i < argc; i++) lua_pushstring(L, argv[i]); lua_createtable(L, narg, n + 1); for (i=0; i < argc; i++) { lua_pushstring(L, argv[i]); lua_rawseti(L, -2, i - n); } return narg; } static int dofile (lua_State *L, const char *name) { int status = luaL_loadfile(L, name) || docall(L, 0, 1); return report(L, status); } static int dostring (lua_State *L, const char *s, const char *name) { int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); return report(L, status); } static int dolibrary (lua_State *L, const char *name) { lua_getglobal(L, "require"); lua_pushstring(L, name); return report(L, lua_pcall(L, 1, 0, 0)); } static const char *get_prompt (lua_State *L, int firstline) { const char *p; lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); lua_pop(L, 1); /* remove global */ return p; } static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring(L, -1, &lmsg); const char *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); if (strstr(msg, LUA_QL("")) == tp) { lua_pop(L, 1); return 1; } } return 0; /* else... */ } static int pushline (lua_State *L, int firstline) { char buffer[LUA_MAXINPUT]; char *b = buffer; size_t l; const char *prmt = get_prompt(L, firstline); if (lua_readline(L, b, prmt) == 0) return 0; /* no input */ l = strlen(b); if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ b[l-1] = '\0'; /* remove it */ if (firstline && b[0] == '=') /* first line starts with `=' ? */ lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ else lua_pushstring(L, b); lua_freeline(L, b); return 1; } static int loadline (lua_State *L) { int status; lua_settop(L, 0); if (!pushline(L, 1)) return -1; /* no input */ for (;;) { /* repeat until gets a complete line */ status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); if (!incomplete(L, status)) break; /* cannot try to add lines? */ if (!pushline(L, 0)) /* no more input? */ return -1; lua_pushliteral(L, "\n"); /* add a new line... */ lua_insert(L, -2); /* ...between the two lines */ lua_concat(L, 3); /* join them */ } lua_saveline(L, 1); lua_remove(L, 1); /* remove line */ return status; } static void dotty (lua_State *L) { int status; const char *oldprogname = progname; progname = NULL; while ((status = loadline(L)) != -1) { if (status == 0) status = docall(L, 0, 0); report(L, status); if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ lua_getglobal(L, "print"); lua_insert(L, 1); if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) l_message(progname, lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)", lua_tostring(L, -1))); } } lua_settop(L, 0); /* clear stack */ fputs("\n", stdout); fflush(stdout); progname = oldprogname; } static int handle_script (lua_State *L, char **argv, int n) { int status; const char *fname; int narg = getargs(L, argv, n); /* collect arguments */ lua_setglobal(L, "arg"); fname = argv[n]; if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) fname = NULL; /* stdin */ status = luaL_loadfile(L, fname); lua_insert(L, -(narg+1)); if (status == 0) status = docall(L, narg, 0); else lua_pop(L, narg); return report(L, status); } /* check that argument has no extra characters at the end */ #define notail(x) {if ((x)[2] != '\0') return -1;} static int collectargs (char **argv, int *pi, int *pv, int *pe) { int i; for (i = 1; argv[i] != NULL; i++) { if (argv[i][0] != '-') /* not an option? */ return i; switch (argv[i][1]) { /* option */ case '-': notail(argv[i]); return (argv[i+1] != NULL ? i+1 : 0); case '\0': return i; case 'i': notail(argv[i]); *pi = 1; /* go through */ case 'v': notail(argv[i]); *pv = 1; break; case 'e': *pe = 1; /* go through */ case 'l': if (argv[i][2] == '\0') { i++; if (argv[i] == NULL) return -1; } break; default: return -1; /* invalid option */ } } return 0; } static int runargs (lua_State *L, char **argv, int n) { int i; for (i = 1; i < n; i++) { if (argv[i] == NULL) continue; lua_assert(argv[i][0] == '-'); switch (argv[i][1]) { /* option */ case 'e': { const char *chunk = argv[i] + 2; if (*chunk == '\0') chunk = argv[++i]; lua_assert(chunk != NULL); if (dostring(L, chunk, "=(command line)") != 0) return 1; break; } case 'l': { const char *filename = argv[i] + 2; if (*filename == '\0') filename = argv[++i]; lua_assert(filename != NULL); if (dolibrary(L, filename)) return 1; /* stop if file fails */ break; } default: break; } } return 0; } static int handle_luainit (lua_State *L) { const char *init = getenv(LUA_INIT); if (init == NULL) return 0; /* status OK */ else if (init[0] == '@') return dofile(L, init+1); else return dostring(L, init, "=" LUA_INIT); } struct Smain { int argc; char **argv; int status; }; static int pmain (lua_State *L) { struct Smain *s = (struct Smain *)lua_touserdata(L, 1); char **argv = s->argv; int script; int has_i = 0, has_v = 0, has_e = 0; globalL = L; if (argv[0] && argv[0][0]) progname = argv[0]; lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ luaL_openlibs(L); /* open libraries */ lua_gc(L, LUA_GCRESTART, 0); s->status = handle_luainit(L); if (s->status != 0) return 0; script = collectargs(argv, &has_i, &has_v, &has_e); if (script < 0) { /* invalid args? */ print_usage(); s->status = 1; return 0; } if (has_v) print_version(); s->status = runargs(L, argv, (script > 0) ? script : s->argc); if (s->status != 0) return 0; if (script) s->status = handle_script(L, argv, script); if (s->status != 0) return 0; if (has_i) dotty(L); else if (script == 0 && !has_e && !has_v) { if (lua_stdin_is_tty()) { print_version(); dotty(L); } else dofile(L, NULL); /* executes stdin as a file */ } return 0; } int main (int argc, char **argv) { int status; struct Smain s; lua_State *L = lua_open(); /* create state */ if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; } s.argc = argc; s.argv = argv; status = lua_cpcall(L, &pmain, &s); report(L, status); lua_close(L); return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; } tagua-1.0-alpha2/lua/src/lua.h000066400000000000000000000265351077523320400161400ustar00rootroot00000000000000/* ** $Id: lua.h,v 1.218a 2006/06/02 15:34:00 roberto Exp $ ** Lua - An Extensible Extension Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file */ #ifndef lua_h #define lua_h #include #include #include "luaconf.h" #define LUA_VERSION "Lua 5.1" #define LUA_RELEASE "Lua 5.1.2" #define LUA_VERSION_NUM 501 #define LUA_COPYRIGHT "Copyright (C) 1994-2007 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" /* mark for precompiled code (`Lua') */ #define LUA_SIGNATURE "\033Lua" /* option for multiple returns in `lua_pcall' and `lua_call' */ #define LUA_MULTRET (-1) /* ** pseudo-indices */ #define LUA_REGISTRYINDEX (-10000) #define LUA_ENVIRONINDEX (-10001) #define LUA_GLOBALSINDEX (-10002) #define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) /* thread status; 0 is OK */ #define LUA_YIELD 1 #define LUA_ERRRUN 2 #define LUA_ERRSYNTAX 3 #define LUA_ERRMEM 4 #define LUA_ERRERR 5 typedef struct lua_State lua_State; typedef int (*lua_CFunction) (lua_State *L); /* ** functions that read/write blocks when loading/dumping Lua chunks */ typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); /* ** prototype for memory-allocation functions */ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); /* ** basic types */ #define LUA_TNONE (-1) #define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 #define LUA_TNUMBER 3 #define LUA_TSTRING 4 #define LUA_TTABLE 5 #define LUA_TFUNCTION 6 #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8 /* minimum Lua stack available to a C function */ #define LUA_MINSTACK 20 /* ** generic extra include file */ #if defined(LUA_USER_H) #include LUA_USER_H #endif /* type of numbers in Lua */ typedef LUA_NUMBER lua_Number; /* type for integer functions */ typedef LUA_INTEGER lua_Integer; /* ** state manipulation */ LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); LUA_API void (lua_close) (lua_State *L); LUA_API lua_State *(lua_newthread) (lua_State *L); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); /* ** basic stack manipulation */ LUA_API int (lua_gettop) (lua_State *L); LUA_API void (lua_settop) (lua_State *L, int idx); LUA_API void (lua_pushvalue) (lua_State *L, int idx); LUA_API void (lua_remove) (lua_State *L, int idx); LUA_API void (lua_insert) (lua_State *L, int idx); LUA_API void (lua_replace) (lua_State *L, int idx); LUA_API int (lua_checkstack) (lua_State *L, int sz); LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); /* ** access functions (stack -> C) */ LUA_API int (lua_isnumber) (lua_State *L, int idx); LUA_API int (lua_isstring) (lua_State *L, int idx); LUA_API int (lua_iscfunction) (lua_State *L, int idx); LUA_API int (lua_isuserdata) (lua_State *L, int idx); LUA_API int (lua_type) (lua_State *L, int idx); LUA_API const char *(lua_typename) (lua_State *L, int tp); LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2); LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); LUA_API size_t (lua_objlen) (lua_State *L, int idx); LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); LUA_API void *(lua_touserdata) (lua_State *L, int idx); LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); LUA_API const void *(lua_topointer) (lua_State *L, int idx); /* ** push functions (C -> stack) */ LUA_API void (lua_pushnil) (lua_State *L); LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l); LUA_API void (lua_pushstring) (lua_State *L, const char *s); LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp); LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); LUA_API void (lua_pushboolean) (lua_State *L, int b); LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); LUA_API int (lua_pushthread) (lua_State *L); /* ** get functions (Lua -> stack) */ LUA_API void (lua_gettable) (lua_State *L, int idx); LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_rawget) (lua_State *L, int idx); LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); LUA_API void (lua_getfenv) (lua_State *L, int idx); /* ** set functions (stack -> Lua) */ LUA_API void (lua_settable) (lua_State *L, int idx); LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_rawset) (lua_State *L, int idx); LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); LUA_API int (lua_setfenv) (lua_State *L, int idx); /* ** `load' and `call' functions (load and run Lua code) */ LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, const char *chunkname); LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); /* ** coroutine functions */ LUA_API int (lua_yield) (lua_State *L, int nresults); LUA_API int (lua_resume) (lua_State *L, int narg); LUA_API int (lua_status) (lua_State *L); /* ** garbage-collection function and options */ #define LUA_GCSTOP 0 #define LUA_GCRESTART 1 #define LUA_GCCOLLECT 2 #define LUA_GCCOUNT 3 #define LUA_GCCOUNTB 4 #define LUA_GCSTEP 5 #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 LUA_API int (lua_gc) (lua_State *L, int what, int data); /* ** miscellaneous functions */ LUA_API int (lua_error) (lua_State *L); LUA_API int (lua_next) (lua_State *L, int idx); LUA_API void (lua_concat) (lua_State *L, int n); LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); /* ** =============================================================== ** some useful macros ** =============================================================== */ #define lua_pop(L,n) lua_settop(L, -(n)-1) #define lua_newtable(L) lua_createtable(L, 0, 0) #define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) #define lua_strlen(L,i) lua_objlen(L, (i)) #define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) #define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) #define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) #define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) #define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) #define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) #define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) #define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) #define lua_pushliteral(L, s) \ lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) #define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) #define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) /* ** compatibility macros and functions */ #define lua_open() luaL_newstate() #define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) #define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) #define lua_Chunkreader lua_Reader #define lua_Chunkwriter lua_Writer /* ** {====================================================================== ** Debug API ** ======================================================================= */ /* ** Event codes */ #define LUA_HOOKCALL 0 #define LUA_HOOKRET 1 #define LUA_HOOKLINE 2 #define LUA_HOOKCOUNT 3 #define LUA_HOOKTAILRET 4 /* ** Event masks */ #define LUA_MASKCALL (1 << LUA_HOOKCALL) #define LUA_MASKRET (1 << LUA_HOOKRET) #define LUA_MASKLINE (1 << LUA_HOOKLINE) #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) typedef struct lua_Debug lua_Debug; /* activation record */ /* Functions to be called by the debuger in specific events */ typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n); LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n); LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count); LUA_API lua_Hook lua_gethook (lua_State *L); LUA_API int lua_gethookmask (lua_State *L); LUA_API int lua_gethookcount (lua_State *L); struct lua_Debug { int event; const char *name; /* (n) */ const char *namewhat; /* (n) `global', `local', `field', `method' */ const char *what; /* (S) `Lua', `C', `main', `tail' */ const char *source; /* (S) */ int currentline; /* (l) */ int nups; /* (u) number of upvalues */ int linedefined; /* (S) */ int lastlinedefined; /* (S) */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ int i_ci; /* active function */ }; /* }====================================================================== */ /****************************************************************************** * Copyright (C) 1994-2007 Lua.org, PUC-Rio. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ #endif tagua-1.0-alpha2/lua/src/luac.c000066400000000000000000000110651077523320400162660ustar00rootroot00000000000000/* ** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ #include #include #include #include #define luac_c #define LUA_CORE #include "lua.h" #include "lauxlib.h" #include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lstring.h" #include "lundump.h" #define PROGNAME "luac" /* default program name */ #define OUTPUT PROGNAME ".out" /* default output file */ static int listing=0; /* list bytecodes? */ static int dumping=1; /* dump bytecodes? */ static int stripping=0; /* strip debug information? */ static char Output[]={ OUTPUT }; /* default output file name */ static const char* output=Output; /* actual output file name */ static const char* progname=PROGNAME; /* actual program name */ static void fatal(const char* message) { fprintf(stderr,"%s: %s\n",progname,message); exit(EXIT_FAILURE); } static void cannot(const char* what) { fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); exit(EXIT_FAILURE); } static void usage(const char* message) { if (*message=='-') fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); else fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, "usage: %s [options] [filenames].\n" "Available options are:\n" " - process stdin\n" " -l list\n" " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" " -v show version information\n" " -- stop handling options\n", progname,Output); exit(EXIT_FAILURE); } #define IS(s) (strcmp(argv[i],s)==0) static int doargs(int argc, char* argv[]) { int i; int version=0; if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0]; for (i=1; itop+(i))->l.p) static const Proto* combine(lua_State* L, int n) { if (n==1) return toproto(L,-1); else { int i,pc; Proto* f=luaF_newproto(L); setptvalue2s(L,L->top,f); incr_top(L); f->source=luaS_newliteral(L,"=(" PROGNAME ")"); f->maxstacksize=1; pc=2*n+1; f->code=luaM_newvector(L,pc,Instruction); f->sizecode=pc; f->p=luaM_newvector(L,n,Proto*); f->sizep=n; pc=0; for (i=0; ip[i]=toproto(L,i-n-1); f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i); f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1); } f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0); return f; } } static int writer(lua_State* L, const void* p, size_t size, void* u) { UNUSED(L); return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); } struct Smain { int argc; char** argv; }; static int pmain(lua_State* L) { struct Smain* s = (struct Smain*)lua_touserdata(L, 1); int argc=s->argc; char** argv=s->argv; const Proto* f; int i; if (!lua_checkstack(L,argc)) fatal("too many input files"); for (i=0; i1); if (dumping) { FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); if (D==NULL) cannot("open"); lua_lock(L); luaU_dump(L,f,writer,D,stripping); lua_unlock(L); if (ferror(D)) cannot("write"); if (fclose(D)) cannot("close"); } return 0; } int main(int argc, char* argv[]) { lua_State* L; struct Smain s; int i=doargs(argc,argv); argc-=i; argv+=i; if (argc<=0) usage("no input files given"); L=lua_open(); if (L==NULL) fatal("not enough memory for state"); s.argc=argc; s.argv=argv; if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1)); lua_close(L); return EXIT_SUCCESS; } tagua-1.0-alpha2/lua/src/luaconf.h000066400000000000000000000533351077523320400170040ustar00rootroot00000000000000/* ** $Id: luaconf.h,v 1.82a 2006/04/10 18:27:23 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ #ifndef lconfig_h #define lconfig_h #include #include /* ** ================================================================== ** Search for "@@" to find all configurable definitions. ** =================================================================== */ /* @@ LUA_ANSI controls the use of non-ansi features. ** CHANGE it (define it) if you want Lua to avoid the use of any ** non-ansi feature or library. */ #if defined(__STRICT_ANSI__) #define LUA_ANSI #endif #if !defined(LUA_ANSI) && defined(_WIN32) #define LUA_WIN #endif #if defined(LUA_USE_LINUX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ #define LUA_USE_READLINE /* needs some extra libraries */ #endif #if defined(LUA_USE_MACOSX) #define LUA_USE_POSIX #define LUA_DL_DYLD /* does not need extra library */ #endif /* @@ LUA_USE_POSIX includes all functionallity listed as X/Open System @* Interfaces Extension (XSI). ** CHANGE it (define it) if your system is XSI compatible. */ #if defined(LUA_USE_POSIX) #define LUA_USE_MKSTEMP #define LUA_USE_ISATTY #define LUA_USE_POPEN #define LUA_USE_ULONGJMP #endif /* @@ LUA_PATH and LUA_CPATH are the names of the environment variables that @* Lua check to set its paths. @@ LUA_INIT is the name of the environment variable that Lua @* checks for initialization code. ** CHANGE them if you want different names. */ #define LUA_PATH "LUA_PATH" #define LUA_CPATH "LUA_CPATH" #define LUA_INIT "LUA_INIT" /* @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for @* Lua libraries. @@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for @* C libraries. ** CHANGE them if your machine has a non-conventional directory ** hierarchy or if you want to install your libraries in ** non-conventional directories. */ #if defined(_WIN32) /* ** In Windows, any exclamation mark ('!') in the path is replaced by the ** path of the directory of the executable file of the current process. */ #define LUA_LDIR "!\\lua\\" #define LUA_CDIR "!\\" #define LUA_PATH_DEFAULT \ ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua" #define LUA_CPATH_DEFAULT \ ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll" #else #define LUA_ROOT "/usr/local/" #define LUA_LDIR LUA_ROOT "share/lua/5.1/" #define LUA_CDIR LUA_ROOT "lib/lua/5.1/" #define LUA_PATH_DEFAULT \ "./?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua" #define LUA_CPATH_DEFAULT \ "./?.so;" LUA_CDIR"?.so;" LUA_CDIR"loadall.so" #endif /* @@ LUA_DIRSEP is the directory separator (for submodules). ** CHANGE it if your machine does not use "/" as the directory separator ** and is not Windows. (On Windows Lua automatically uses "\".) */ #if defined(_WIN32) #define LUA_DIRSEP "\\" #else #define LUA_DIRSEP "/" #endif /* @@ LUA_PATHSEP is the character that separates templates in a path. @@ LUA_PATH_MARK is the string that marks the substitution points in a @* template. @@ LUA_EXECDIR in a Windows path is replaced by the executable's @* directory. @@ LUA_IGMARK is a mark to ignore all before it when bulding the @* luaopen_ function name. ** CHANGE them if for some reason your system cannot use those ** characters. (E.g., if one of those characters is a common character ** in file/directory names.) Probably you do not need to change them. */ #define LUA_PATHSEP ";" #define LUA_PATH_MARK "?" #define LUA_EXECDIR "!" #define LUA_IGMARK "-" /* @@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. ** CHANGE that if ptrdiff_t is not adequate on your machine. (On most ** machines, ptrdiff_t gives a good choice between int or long.) */ #define LUA_INTEGER ptrdiff_t /* @@ LUA_API is a mark for all core API functions. @@ LUALIB_API is a mark for all standard library functions. ** CHANGE them if you need to define those functions in some special way. ** For instance, if you want to create one Windows DLL with the core and ** the libraries, you may want to use the following definition (define ** LUA_BUILD_AS_DLL to get it). */ #if defined(LUA_BUILD_AS_DLL) #if defined(LUA_CORE) || defined(LUA_LIB) #define LUA_API __declspec(dllexport) #else #define LUA_API __declspec(dllimport) #endif #else #define LUA_API extern #endif /* more often than not the libs go together with the core */ #define LUALIB_API LUA_API /* @@ LUAI_FUNC is a mark for all extern functions that are not to be @* exported to outside modules. @@ LUAI_DATA is a mark for all extern (const) variables that are not to @* be exported to outside modules. ** CHANGE them if you need to mark them in some special way. Elf/gcc ** (versions 3.2 and later) mark them as "hidden" to optimize access ** when Lua is compiled as a shared library. */ #if defined(luaall_c) #define LUAI_FUNC static #define LUAI_DATA /* empty */ #elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ defined(__ELF__) #define LUAI_FUNC __attribute__((visibility("hidden"))) extern #define LUAI_DATA LUAI_FUNC #else #define LUAI_FUNC extern #define LUAI_DATA extern #endif /* @@ LUA_QL describes how error messages quote program elements. ** CHANGE it if you want a different appearance. */ #define LUA_QL(x) "'" x "'" #define LUA_QS LUA_QL("%s") /* @@ LUA_IDSIZE gives the maximum size for the description of the source @* of a function in debug information. ** CHANGE it if you want a different size. */ #define LUA_IDSIZE 60 /* ** {================================================================== ** Stand-alone configuration ** =================================================================== */ #if defined(lua_c) || defined(luaall_c) /* @@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that @* is, whether we're running lua interactively). ** CHANGE it if you have a better definition for non-POSIX/non-Windows ** systems. */ #if defined(LUA_USE_ISATTY) #include #define lua_stdin_is_tty() isatty(0) #elif defined(LUA_WIN) #include #include #define lua_stdin_is_tty() _isatty(_fileno(stdin)) #else #define lua_stdin_is_tty() 1 /* assume stdin is a tty */ #endif /* @@ LUA_PROMPT is the default prompt used by stand-alone Lua. @@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua. ** CHANGE them if you want different prompts. (You can also change the ** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.) */ #define LUA_PROMPT "> " #define LUA_PROMPT2 ">> " /* @@ LUA_PROGNAME is the default name for the stand-alone Lua program. ** CHANGE it if your stand-alone interpreter has a different name and ** your system is not able to detect that name automatically. */ #define LUA_PROGNAME "lua" /* @@ LUA_MAXINPUT is the maximum length for an input line in the @* stand-alone interpreter. ** CHANGE it if you need longer lines. */ #define LUA_MAXINPUT 512 /* @@ lua_readline defines how to show a prompt and then read a line from @* the standard input. @@ lua_saveline defines how to "save" a read line in a "history". @@ lua_freeline defines how to free a line read by lua_readline. ** CHANGE them if you want to improve this functionality (e.g., by using ** GNU readline and history facilities). */ #if defined(LUA_USE_READLINE) #include #include #include #define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) #define lua_saveline(L,idx) \ if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ add_history(lua_tostring(L, idx)); /* add it to history */ #define lua_freeline(L,b) ((void)L, free(b)) #else #define lua_readline(L,b,p) \ ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ #define lua_saveline(L,idx) { (void)L; (void)idx; } #define lua_freeline(L,b) { (void)L; (void)b; } #endif #endif /* }================================================================== */ /* @@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles @* as a percentage. ** CHANGE it if you want the GC to run faster or slower (higher values ** mean larger pauses which mean slower collection.) You can also change ** this value dynamically. */ #define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */ /* @@ LUAI_GCMUL defines the default speed of garbage collection relative to @* memory allocation as a percentage. ** CHANGE it if you want to change the granularity of the garbage ** collection. (Higher values mean coarser collections. 0 represents ** infinity, where each step performs a full collection.) You can also ** change this value dynamically. */ #define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ /* @@ LUA_COMPAT_GETN controls compatibility with old getn behavior. ** CHANGE it (define it) if you want exact compatibility with the ** behavior of setn/getn in Lua 5.0. */ #undef LUA_COMPAT_GETN /* @@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. ** CHANGE it to undefined as soon as you do not need a global 'loadlib' ** function (the function is still available as 'package.loadlib'). */ #undef LUA_COMPAT_LOADLIB /* @@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. ** CHANGE it to undefined as soon as your programs use only '...' to ** access vararg parameters (instead of the old 'arg' table). */ #define LUA_COMPAT_VARARG /* @@ LUA_COMPAT_MOD controls compatibility with old math.mod function. ** CHANGE it to undefined as soon as your programs use 'math.fmod' or ** the new '%' operator instead of 'math.mod'. */ #define LUA_COMPAT_MOD /* @@ LUA_COMPAT_LSTR controls compatibility with old long string nesting @* facility. ** CHANGE it to 2 if you want the old behaviour, or undefine it to turn ** off the advisory error when nesting [[...]]. */ #define LUA_COMPAT_LSTR 1 /* @@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. ** CHANGE it to undefined as soon as you rename 'string.gfind' to ** 'string.gmatch'. */ #define LUA_COMPAT_GFIND /* @@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' @* behavior. ** CHANGE it to undefined as soon as you replace to 'luaL_register' ** your uses of 'luaL_openlib' */ #define LUA_COMPAT_OPENLIB /* @@ luai_apicheck is the assert macro used by the Lua-C API. ** CHANGE luai_apicheck if you want Lua to perform some checks in the ** parameters it gets from API calls. This may slow down the interpreter ** a bit, but may be quite useful when debugging C code that interfaces ** with Lua. A useful redefinition is to use assert.h. */ #if defined(LUA_USE_APICHECK) #include #define luai_apicheck(L,o) { (void)L; assert(o); } #else #define luai_apicheck(L,o) { (void)L; } #endif /* @@ LUAI_BITSINT defines the number of bits in an int. ** CHANGE here if Lua cannot automatically detect the number of bits of ** your machine. Probably you do not need to change this. */ /* avoid overflows in comparison */ #if INT_MAX-20 < 32760 #define LUAI_BITSINT 16 #elif INT_MAX > 2147483640L /* int has at least 32 bits */ #define LUAI_BITSINT 32 #else #error "you must define LUA_BITSINT with number of bits in an integer" #endif /* @@ LUAI_UINT32 is an unsigned integer with at least 32 bits. @@ LUAI_INT32 is an signed integer with at least 32 bits. @@ LUAI_UMEM is an unsigned integer big enough to count the total @* memory used by Lua. @@ LUAI_MEM is a signed integer big enough to count the total memory @* used by Lua. ** CHANGE here if for some weird reason the default definitions are not ** good enough for your machine. (The definitions in the 'else' ** part always works, but may waste space on machines with 64-bit ** longs.) Probably you do not need to change this. */ #if LUAI_BITSINT >= 32 #define LUAI_UINT32 unsigned int #define LUAI_INT32 int #define LUAI_MAXINT32 INT_MAX #define LUAI_UMEM size_t #define LUAI_MEM ptrdiff_t #else /* 16-bit ints */ #define LUAI_UINT32 unsigned long #define LUAI_INT32 long #define LUAI_MAXINT32 LONG_MAX #define LUAI_UMEM unsigned long #define LUAI_MEM long #endif /* @@ LUAI_MAXCALLS limits the number of nested calls. ** CHANGE it if you need really deep recursive calls. This limit is ** arbitrary; its only purpose is to stop infinite recursion before ** exhausting memory. */ #define LUAI_MAXCALLS 20000 /* @@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function @* can use. ** CHANGE it if you need lots of (Lua) stack space for your C ** functions. This limit is arbitrary; its only purpose is to stop C ** functions to consume unlimited stack space. */ #define LUAI_MAXCSTACK 2048 /* ** {================================================================== ** CHANGE (to smaller values) the following definitions if your system ** has a small C stack. (Or you may want to change them to larger ** values if your system has a large C stack and these limits are ** too rigid for you.) Some of these constants control the size of ** stack-allocated arrays used by the compiler or the interpreter, while ** others limit the maximum number of recursive calls that the compiler ** or the interpreter can perform. Values too large may cause a C stack ** overflow for some forms of deep constructs. ** =================================================================== */ /* @@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and @* syntactical nested non-terminals in a program. */ #define LUAI_MAXCCALLS 200 /* @@ LUAI_MAXVARS is the maximum number of local variables per function @* (must be smaller than 250). */ #define LUAI_MAXVARS 200 /* @@ LUAI_MAXUPVALUES is the maximum number of upvalues per function @* (must be smaller than 250). */ #define LUAI_MAXUPVALUES 60 /* @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. */ #define LUAL_BUFFERSIZE BUFSIZ /* }================================================================== */ /* ** {================================================================== @@ LUA_NUMBER is the type of numbers in Lua. ** CHANGE the following definitions only if you want to build Lua ** with a number type different from double. You may also need to ** change lua_number2int & lua_number2integer. ** =================================================================== */ #define LUA_NUMBER_DOUBLE #define LUA_NUMBER double /* @@ LUAI_UACNUMBER is the result of an 'usual argument conversion' @* over a number. */ #define LUAI_UACNUMBER double /* @@ LUA_NUMBER_SCAN is the format for reading numbers. @@ LUA_NUMBER_FMT is the format for writing numbers. @@ lua_number2str converts a number to a string. @@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. @@ lua_str2number converts a string to a number. */ #define LUA_NUMBER_SCAN "%lf" #define LUA_NUMBER_FMT "%.14g" #define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) #define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ #define lua_str2number(s,p) strtod((s), (p)) /* @@ The luai_num* macros define the primitive operations over numbers. */ #if defined(LUA_CORE) #include #define luai_numadd(a,b) ((a)+(b)) #define luai_numsub(a,b) ((a)-(b)) #define luai_nummul(a,b) ((a)*(b)) #define luai_numdiv(a,b) ((a)/(b)) #define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) #define luai_numpow(a,b) (pow(a,b)) #define luai_numunm(a) (-(a)) #define luai_numeq(a,b) ((a)==(b)) #define luai_numlt(a,b) ((a)<(b)) #define luai_numle(a,b) ((a)<=(b)) #define luai_numisnan(a) (!luai_numeq((a), (a))) #endif /* @@ lua_number2int is a macro to convert lua_Number to int. @@ lua_number2integer is a macro to convert lua_Number to lua_Integer. ** CHANGE them if you know a faster way to convert a lua_Number to ** int (with any rounding method and without throwing errors) in your ** system. In Pentium machines, a naive typecast from double to int ** in C is extremely slow, so any alternative is worth trying. */ /* On a Pentium, resort to a trick */ #if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ (defined(__i386) || defined (_M_IX86) || defined(__i386__)) /* On a Microsoft compiler, use assembler */ #if defined(_MSC_VER) #define lua_number2int(i,d) __asm fld d __asm fistp i #define lua_number2integer(i,n) lua_number2int(i, n) /* the next trick should work on any Pentium, but sometimes clashes with a DirectX idiosyncrasy */ #else union luai_Cast { double l_d; long l_l; }; #define lua_number2int(i,d) \ { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } #define lua_number2integer(i,n) lua_number2int(i, n) #endif /* this option always works, but may be slow */ #else #define lua_number2int(i,d) ((i)=(int)(d)) #define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) #endif /* }================================================================== */ /* @@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment. ** CHANGE it if your system requires alignments larger than double. (For ** instance, if your system supports long doubles and they must be ** aligned in 16-byte boundaries, then you should add long double in the ** union.) Probably you do not need to change this. */ #define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } /* @@ LUAI_THROW/LUAI_TRY define how Lua does exception handling. ** CHANGE them if you prefer to use longjmp/setjmp even with C++ ** or if want/don't to use _longjmp/_setjmp instead of regular ** longjmp/setjmp. By default, Lua handles errors with exceptions when ** compiling as C++ code, with _longjmp/_setjmp when asked to use them, ** and with longjmp/setjmp otherwise. */ #if defined(__cplusplus) /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) #define LUAI_TRY(L,c,a) try { a } catch(...) \ { if ((c)->status == 0) (c)->status = -1; } #define luai_jmpbuf int /* dummy variable */ #elif defined(LUA_USE_ULONGJMP) /* in Unix, try _longjmp/_setjmp (more efficient) */ #define LUAI_THROW(L,c) _longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #else /* default handling with long jumps */ #define LUAI_THROW(L,c) longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #endif /* @@ LUA_MAXCAPTURES is the maximum number of captures that a pattern @* can do during pattern-matching. ** CHANGE it if you need more captures. This limit is arbitrary. */ #define LUA_MAXCAPTURES 32 /* @@ lua_tmpnam is the function that the OS library uses to create a @* temporary name. @@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam. ** CHANGE them if you have an alternative to tmpnam (which is considered ** insecure) or if you want the original tmpnam anyway. By default, Lua ** uses tmpnam except when POSIX is available, where it uses mkstemp. */ #if defined(loslib_c) || defined(luaall_c) #if defined(LUA_USE_MKSTEMP) #include #define LUA_TMPNAMBUFSIZE 32 #define lua_tmpnam(b,e) { \ strcpy(b, "/tmp/lua_XXXXXX"); \ e = mkstemp(b); \ if (e != -1) close(e); \ e = (e == -1); } #else #define LUA_TMPNAMBUFSIZE L_tmpnam #define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } #endif #endif /* @@ lua_popen spawns a new process connected to the current one through @* the file streams. ** CHANGE it if you have a way to implement it in your system. */ #if defined(LUA_USE_POPEN) #define lua_popen(L,c,m) ((void)L, popen(c,m)) #define lua_pclose(L,file) ((void)L, (pclose(file) != -1)) #elif defined(LUA_WIN) #define lua_popen(L,c,m) ((void)L, _popen(c,m)) #define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) #else #define lua_popen(L,c,m) ((void)((void)c, m), \ luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) #define lua_pclose(L,file) ((void)((void)L, file), 0) #endif /* @@ LUA_DL_* define which dynamic-library system Lua should use. ** CHANGE here if Lua has problems choosing the appropriate ** dynamic-library system for your platform (either Windows' DLL, Mac's ** dyld, or Unix's dlopen). If your system is some kind of Unix, there ** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for ** it. To use dlopen you also need to adapt the src/Makefile (probably ** adding -ldl to the linker options), so Lua does not select it ** automatically. (When you change the makefile to add -ldl, you must ** also add -DLUA_USE_DLOPEN.) ** If you do not want any kind of dynamic library, undefine all these ** options. ** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD. */ #if defined(LUA_USE_DLOPEN) #define LUA_DL_DLOPEN #endif #if defined(LUA_WIN) #define LUA_DL_DLL #endif /* @@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State @* (the data goes just *before* the lua_State pointer). ** CHANGE (define) this if you really need that. This value must be ** a multiple of the maximum alignment required for your machine. */ #define LUAI_EXTRASPACE 0 /* @@ luai_userstate* allow user-specific actions on threads. ** CHANGE them if you defined LUAI_EXTRASPACE and need to do something ** extra when a thread is created/deleted/resumed/yielded. */ #define luai_userstateopen(L) ((void)L) #define luai_userstateclose(L) ((void)L) #define luai_userstatethread(L,L1) ((void)L) #define luai_userstatefree(L) ((void)L) #define luai_userstateresume(L,n) ((void)L) #define luai_userstateyield(L,n) ((void)L) /* @@ LUA_INTFRMLEN is the length modifier for integer conversions @* in 'string.format'. @@ LUA_INTFRM_T is the integer type correspoding to the previous length @* modifier. ** CHANGE them if your system supports long long or does not support long. */ #if defined(LUA_USELONGLONG) #define LUA_INTFRMLEN "ll" #define LUA_INTFRM_T long long #else #define LUA_INTFRMLEN "l" #define LUA_INTFRM_T long #endif /* =================================================================== */ /* ** Local configuration. You can use this space to add your redefinitions ** without modifying the main part of the file. */ #endif tagua-1.0-alpha2/lua/src/lualib.h000066400000000000000000000017761077523320400166270ustar00rootroot00000000000000/* ** $Id: lualib.h,v 1.36 2005/12/27 17:12:00 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ #ifndef lualib_h #define lualib_h #include "lua.h" /* Key to file-handle type */ #define LUA_FILEHANDLE "FILE*" #define LUA_COLIBNAME "coroutine" LUALIB_API int (luaopen_base) (lua_State *L); #define LUA_TABLIBNAME "table" LUALIB_API int (luaopen_table) (lua_State *L); #define LUA_IOLIBNAME "io" LUALIB_API int (luaopen_io) (lua_State *L); #define LUA_OSLIBNAME "os" LUALIB_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" LUALIB_API int (luaopen_string) (lua_State *L); #define LUA_MATHLIBNAME "math" LUALIB_API int (luaopen_math) (lua_State *L); #define LUA_DBLIBNAME "debug" LUALIB_API int (luaopen_debug) (lua_State *L); #define LUA_LOADLIBNAME "package" LUALIB_API int (luaopen_package) (lua_State *L); /* open all previous libraries */ LUALIB_API void (luaL_openlibs) (lua_State *L); #ifndef lua_assert #define lua_assert(x) ((void)0) #endif #endif tagua-1.0-alpha2/lua/src/lundump.c000066400000000000000000000106401077523320400170240ustar00rootroot00000000000000/* ** $Id: lundump.c,v 1.60 2006/02/16 15:53:49 lhf Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ #include #define lundump_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lobject.h" #include "lstring.h" #include "lundump.h" #include "lzio.h" typedef struct { lua_State* L; ZIO* Z; Mbuffer* b; const char* name; } LoadState; #ifdef LUAC_TRUST_BINARIES #define IF(c,s) #else #define IF(c,s) if (c) error(S,s) static void error(LoadState* S, const char* why) { luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why); luaD_throw(S->L,LUA_ERRSYNTAX); } #endif #define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) #define LoadByte(S) (lu_byte)LoadChar(S) #define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) #define LoadVector(S,b,n,size) LoadMem(S,b,n,size) static void LoadBlock(LoadState* S, void* b, size_t size) { size_t r=luaZ_read(S->Z,b,size); IF (r!=0, "unexpected end"); } static int LoadChar(LoadState* S) { char x; LoadVar(S,x); return x; } static int LoadInt(LoadState* S) { int x; LoadVar(S,x); IF (x<0, "bad integer"); return x; } static lua_Number LoadNumber(LoadState* S) { lua_Number x; LoadVar(S,x); return x; } static TString* LoadString(LoadState* S) { size_t size; LoadVar(S,size); if (size==0) return NULL; else { char* s=luaZ_openspace(S->L,S->b,size); LoadBlock(S,s,size); return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ } } static void LoadCode(LoadState* S, Proto* f) { int n=LoadInt(S); f->code=luaM_newvector(S->L,n,Instruction); f->sizecode=n; LoadVector(S,f->code,n,sizeof(Instruction)); } static Proto* LoadFunction(LoadState* S, TString* p); static void LoadConstants(LoadState* S, Proto* f) { int i,n; n=LoadInt(S); f->k=luaM_newvector(S->L,n,TValue); f->sizek=n; for (i=0; ik[i]); for (i=0; ik[i]; int t=LoadChar(S); switch (t) { case LUA_TNIL: setnilvalue(o); break; case LUA_TBOOLEAN: setbvalue(o,LoadChar(S)); break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); break; case LUA_TSTRING: setsvalue2n(S->L,o,LoadString(S)); break; default: IF (1, "bad constant"); break; } } n=LoadInt(S); f->p=luaM_newvector(S->L,n,Proto*); f->sizep=n; for (i=0; ip[i]=NULL; for (i=0; ip[i]=LoadFunction(S,f->source); } static void LoadDebug(LoadState* S, Proto* f) { int i,n; n=LoadInt(S); f->lineinfo=luaM_newvector(S->L,n,int); f->sizelineinfo=n; LoadVector(S,f->lineinfo,n,sizeof(int)); n=LoadInt(S); f->locvars=luaM_newvector(S->L,n,LocVar); f->sizelocvars=n; for (i=0; ilocvars[i].varname=NULL; for (i=0; ilocvars[i].varname=LoadString(S); f->locvars[i].startpc=LoadInt(S); f->locvars[i].endpc=LoadInt(S); } n=LoadInt(S); f->upvalues=luaM_newvector(S->L,n,TString*); f->sizeupvalues=n; for (i=0; iupvalues[i]=NULL; for (i=0; iupvalues[i]=LoadString(S); } static Proto* LoadFunction(LoadState* S, TString* p) { Proto* f=luaF_newproto(S->L); setptvalue2s(S->L,S->L->top,f); incr_top(S->L); f->source=LoadString(S); if (f->source==NULL) f->source=p; f->linedefined=LoadInt(S); f->lastlinedefined=LoadInt(S); f->nups=LoadByte(S); f->numparams=LoadByte(S); f->is_vararg=LoadByte(S); f->maxstacksize=LoadByte(S); LoadCode(S,f); LoadConstants(S,f); LoadDebug(S,f); IF (!luaG_checkcode(f), "bad code"); S->L->top--; return f; } static void LoadHeader(LoadState* S) { char h[LUAC_HEADERSIZE]; char s[LUAC_HEADERSIZE]; luaU_header(h); LoadBlock(S,s,LUAC_HEADERSIZE); IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header"); } /* ** load precompiled chunk */ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) { LoadState S; if (*name=='@' || *name=='=') S.name=name+1; else if (*name==LUA_SIGNATURE[0]) S.name="binary string"; else S.name=name; S.L=L; S.Z=Z; S.b=buff; LoadHeader(&S); return LoadFunction(&S,luaS_newliteral(L,"=?")); } /* * make header */ void luaU_header (char* h) { int x=1; memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1); h+=sizeof(LUA_SIGNATURE)-1; *h++=(char)LUAC_VERSION; *h++=(char)LUAC_FORMAT; *h++=(char)*(char*)&x; /* endianness */ *h++=(char)sizeof(int); *h++=(char)sizeof(size_t); *h++=(char)sizeof(Instruction); *h++=(char)sizeof(lua_Number); *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */ } tagua-1.0-alpha2/lua/src/lundump.h000066400000000000000000000015621077523320400170340ustar00rootroot00000000000000/* ** $Id: lundump.h,v 1.40 2005/11/11 14:03:13 lhf Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ #ifndef lundump_h #define lundump_h #include "lobject.h" #include "lzio.h" /* load one chunk; from lundump.c */ LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); /* make header; from lundump.c */ LUAI_FUNC void luaU_header (char* h); /* dump one chunk; from ldump.c */ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); #ifdef luac_c /* print one chunk; from print.c */ LUAI_FUNC void luaU_print (const Proto* f, int full); #endif /* for header of binary files -- this is Lua 5.1 */ #define LUAC_VERSION 0x51 /* for header of binary files -- this is the official format */ #define LUAC_FORMAT 0 /* size of header of binary files */ #define LUAC_HEADERSIZE 12 #endif tagua-1.0-alpha2/lua/src/lvm.c000066400000000000000000000551771077523320400161540ustar00rootroot00000000000000/* ** $Id: lvm.c,v 2.63a 2006/06/05 15:58:59 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ #include #include #include #define lvm_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lobject.h" #include "lopcodes.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lvm.h" /* limit for table tag-method chains (to avoid loops) */ #define MAXTAGLOOP 100 const TValue *luaV_tonumber (const TValue *obj, TValue *n) { lua_Number num; if (ttisnumber(obj)) return obj; if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { setnvalue(n, num); return n; } else return NULL; } int luaV_tostring (lua_State *L, StkId obj) { if (!ttisnumber(obj)) return 0; else { char s[LUAI_MAXNUMBER2STR]; lua_Number n = nvalue(obj); lua_number2str(s, n); setsvalue2s(L, obj, luaS_new(L, s)); return 1; } } static void traceexec (lua_State *L, const Instruction *pc) { lu_byte mask = L->hookmask; const Instruction *oldpc = L->savedpc; L->savedpc = pc; if (mask > LUA_MASKLINE) { /* instruction-hook set? */ if (L->hookcount == 0) { resethookcount(L); luaD_callhook(L, LUA_HOOKCOUNT, -1); } } if (mask & LUA_MASKLINE) { Proto *p = ci_func(L->ci)->l.p; int npc = pcRel(pc, p); int newline = getline(p, npc); /* call linehook when enter a new function, when jump back (loop), or when enter a new line */ if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) luaD_callhook(L, LUA_HOOKLINE, newline); } } static void callTMres (lua_State *L, StkId res, const TValue *f, const TValue *p1, const TValue *p2) { ptrdiff_t result = savestack(L, res); setobj2s(L, L->top, f); /* push function */ setobj2s(L, L->top+1, p1); /* 1st argument */ setobj2s(L, L->top+2, p2); /* 2nd argument */ luaD_checkstack(L, 3); L->top += 3; luaD_call(L, L->top - 3, 1); res = restorestack(L, result); L->top--; setobjs2s(L, res, L->top); } static void callTM (lua_State *L, const TValue *f, const TValue *p1, const TValue *p2, const TValue *p3) { setobj2s(L, L->top, f); /* push function */ setobj2s(L, L->top+1, p1); /* 1st argument */ setobj2s(L, L->top+2, p2); /* 2nd argument */ setobj2s(L, L->top+3, p3); /* 3th argument */ luaD_checkstack(L, 4); L->top += 4; luaD_call(L, L->top - 4, 0); } void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTMres(L, val, tm, t, key); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in gettable"); } void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barriert(L, h, val); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in settable"); } static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event) { const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (ttisnil(tm)) return 0; callTMres(L, res, tm, p1, p2); return 1; } static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, TMS event) { const TValue *tm1 = fasttm(L, mt1, event); const TValue *tm2; if (tm1 == NULL) return NULL; /* no metamethod */ if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ tm2 = fasttm(L, mt2, event); if (tm2 == NULL) return NULL; /* no metamethod */ if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */ return tm1; return NULL; } static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { const TValue *tm1 = luaT_gettmbyobj(L, p1, event); const TValue *tm2; if (ttisnil(tm1)) return -1; /* no metamethod? */ tm2 = luaT_gettmbyobj(L, p2, event); if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ return -1; callTMres(L, L->top, tm1, p1, p2); return !l_isfalse(L->top); } static int l_strcmp (const TString *ls, const TString *rs) { const char *l = getstr(ls); size_t ll = ls->tsv.len; const char *r = getstr(rs); size_t lr = rs->tsv.len; for (;;) { int temp = strcoll(l, r); if (temp != 0) return temp; else { /* strings are equal up to a `\0' */ size_t len = strlen(l); /* index of first `\0' in both strings */ if (len == lr) /* r is finished? */ return (len == ll) ? 0 : 1; else if (len == ll) /* l is finished? */ return -1; /* l is smaller than r (because r is not finished) */ /* both strings longer than `len'; go on comparing (after the `\0') */ len++; l += len; ll -= len; r += len; lr -= len; } } } int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) return luai_numlt(nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) return res; return luaG_ordererror(L, l, r); } static int lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) return luai_numle(nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ return res; else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ return !res; return luaG_ordererror(L, l, r); } int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { const TValue *tm; lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) return 0; /* no TM? */ callTMres(L, L->top, tm, t1, t2); /* call TM */ return !l_isfalse(L->top); } void luaV_concat (lua_State *L, int total, int last) { do { StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ (void)tostring(L, top - 2); /* result is first op (as string) */ else { /* at least two string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; char *buffer; int i; /* collect total length */ for (n = 1; n < total && tostring(L, top-n-1); n++) { size_t l = tsvalue(top-n-1)->len; if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); tl += l; } buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ size_t l = tsvalue(top-i)->len; memcpy(buffer+tl, svalue(top-i), l); tl += l; } setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; } while (total > 1); /* repeat until only 1 result left */ } static void Arith (lua_State *L, StkId ra, const TValue *rb, const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { lua_Number nb = nvalue(b), nc = nvalue(c); switch (op) { case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; default: lua_assert(0); break; } } else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); } /* ** some macros for common tasks in `luaV_execute' */ #define runtime_check(L, c) { if (!(c)) break; } #define RA(i) (base+GETARG_A(i)) /* to be used after possible stack reallocation */ #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) #define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) #define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) #define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) #define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) #define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} #define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } #define arith_op(op,tm) { \ TValue *rb = RKB(i); \ TValue *rc = RKC(i); \ if (ttisnumber(rb) && ttisnumber(rc)) { \ lua_Number nb = nvalue(rb), nc = nvalue(rc); \ setnvalue(ra, op(nb, nc)); \ } \ else \ Protect(Arith(L, ra, rb, rc, tm)); \ } void luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; StkId base; TValue *k; const Instruction *pc; reentry: /* entry point */ lua_assert(isLua(L->ci)); pc = L->savedpc; cl = &clvalue(L->ci->func)->l; base = L->base; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L, pc); if (L->status == LUA_YIELD) { /* did hook yield? */ L->savedpc = pc - 1; return; } base = L->base; } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); lua_assert(base == L->base && L->base == L->ci->base); lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(L, ra, RB(i)); continue; } case OP_LOADK: { setobj2s(L, ra, KBx(i)); continue; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ continue; } case OP_LOADNIL: { TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); continue; } case OP_GETUPVAL: { int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); continue; } case OP_GETGLOBAL: { TValue g; TValue *rb = KBx(i); sethvalue(L, &g, cl->env); lua_assert(ttisstring(rb)); Protect(luaV_gettable(L, &g, rb, ra)); continue; } case OP_GETTABLE: { Protect(luaV_gettable(L, RB(i), RKC(i), ra)); continue; } case OP_SETGLOBAL: { TValue g; sethvalue(L, &g, cl->env); lua_assert(ttisstring(KBx(i))); Protect(luaV_settable(L, &g, KBx(i), ra)); continue; } case OP_SETUPVAL: { UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_barrier(L, uv, ra); continue; } case OP_SETTABLE: { Protect(luaV_settable(L, ra, RKB(i), RKC(i))); continue; } case OP_NEWTABLE: { int b = GETARG_B(i); int c = GETARG_C(i); sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); Protect(luaC_checkGC(L)); continue; } case OP_SELF: { StkId rb = RB(i); setobjs2s(L, ra+1, rb); Protect(luaV_gettable(L, rb, RKC(i), ra)); continue; } case OP_ADD: { arith_op(luai_numadd, TM_ADD); continue; } case OP_SUB: { arith_op(luai_numsub, TM_SUB); continue; } case OP_MUL: { arith_op(luai_nummul, TM_MUL); continue; } case OP_DIV: { arith_op(luai_numdiv, TM_DIV); continue; } case OP_MOD: { arith_op(luai_nummod, TM_MOD); continue; } case OP_POW: { arith_op(luai_numpow, TM_POW); continue; } case OP_UNM: { TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); setnvalue(ra, luai_numunm(nb)); } else { Protect(Arith(L, ra, rb, rb, TM_UNM)); } continue; } case OP_NOT: { int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); continue; } case OP_LEN: { const TValue *rb = RB(i); switch (ttype(rb)) { case LUA_TTABLE: { setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); break; } case LUA_TSTRING: { setnvalue(ra, cast_num(tsvalue(rb)->len)); break; } default: { /* try metamethod */ Protect( if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) luaG_typeerror(L, rb, "get length of"); ) } } continue; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); setobjs2s(L, RA(i), base+b); continue; } case OP_JMP: { dojump(L, pc, GETARG_sBx(i)); continue; } case OP_EQ: { TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( if (equalobj(L, rb, rc) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_LT: { Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_LE: { Protect( if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_TEST: { if (l_isfalse(ra) != GETARG_C(i)) dojump(L, pc, GETARG_sBx(*pc)); pc++; continue; } case OP_TESTSET: { TValue *rb = RB(i); if (l_isfalse(rb) != GETARG_C(i)) { setobjs2s(L, ra, rb); dojump(L, pc, GETARG_sBx(*pc)); } pc++; continue; } case OP_CALL: { int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ L->savedpc = pc; switch (luaD_precall(L, ra, nresults)) { case PCRLUA: { nexeccalls++; goto reentry; /* restart luaV_execute over new Lua function */ } case PCRC: { /* it was a C function (`precall' called it); adjust results */ if (nresults >= 0) L->top = L->ci->top; base = L->base; continue; } default: { return; /* yield */ } } } case OP_TAILCALL: { int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ L->savedpc = pc; lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); switch (luaD_precall(L, ra, LUA_MULTRET)) { case PCRLUA: { /* tail call: put new frame in place of previous one */ CallInfo *ci = L->ci - 1; /* previous frame */ int aux; StkId func = ci->func; StkId pfunc = (ci+1)->func; /* previous function index */ if (L->openupval) luaF_close(L, ci->base); L->base = ci->base = ci->func + ((ci+1)->base - pfunc); for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ setobjs2s(L, func+aux, pfunc+aux); ci->top = L->top = func+aux; /* correct top */ lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); ci->savedpc = L->savedpc; ci->tailcalls++; /* one more call lost */ L->ci--; /* remove new frame */ goto reentry; } case PCRC: { /* it was a C function (`precall' called it) */ base = L->base; continue; } default: { return; /* yield */ } } } case OP_RETURN: { int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; if (L->openupval) luaF_close(L, base); L->savedpc = pc; b = luaD_poscall(L, ra); if (--nexeccalls == 0) /* was previous function running `here'? */ return; /* no: return */ else { /* yes: continue its execution */ if (b) L->top = L->ci->top; lua_assert(isLua(L->ci)); lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); goto reentry; } } case OP_FORLOOP: { lua_Number step = nvalue(ra+2); lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); if (luai_numlt(0, step) ? luai_numle(idx, limit) : luai_numle(limit, idx)) { dojump(L, pc, GETARG_sBx(i)); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } continue; } case OP_FORPREP: { const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; L->savedpc = pc; /* next steps may throw errors */ if (!tonumber(init, ra)) luaG_runerror(L, LUA_QL("for") " initial value must be a number"); else if (!tonumber(plimit, ra+1)) luaG_runerror(L, LUA_QL("for") " limit must be a number"); else if (!tonumber(pstep, ra+2)) luaG_runerror(L, LUA_QL("for") " step must be a number"); setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); dojump(L, pc, GETARG_sBx(i)); continue; } case OP_TFORLOOP: { StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); setobjs2s(L, cb, ra); L->top = cb+3; /* func. + 2 args (state and index) */ Protect(luaD_call(L, cb, GETARG_C(i))); L->top = L->ci->top; cb = RA(i) + 3; /* previous call may change the stack */ if (!ttisnil(cb)) { /* continue loop? */ setobjs2s(L, cb-1, cb); /* save control variable */ dojump(L, pc, GETARG_sBx(*pc)); /* jump back */ } pc++; continue; } case OP_SETLIST: { int n = GETARG_B(i); int c = GETARG_C(i); int last; Table *h; if (n == 0) { n = cast_int(L->top - ra) - 1; L->top = L->ci->top; } if (c == 0) c = cast_int(*pc++); runtime_check(L, ttistable(ra)); h = hvalue(ra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ luaH_resizearray(L, h, last); /* pre-alloc it at once */ for (; n > 0; n--) { TValue *val = ra+n; setobj2t(L, luaH_setnum(L, h, last--), val); luaC_barriert(L, h, val); } continue; } case OP_CLOSE: { luaF_close(L, ra); continue; } case OP_CLOSURE: { Proto *p; Closure *ncl; int nup, j; p = cl->p->p[GETARG_Bx(i)]; nup = p->nups; ncl = luaF_newLclosure(L, nup, cl->env); ncl->l.p = p; for (j=0; jl.upvals[j] = cl->upvals[GETARG_B(*pc)]; else { lua_assert(GET_OPCODE(*pc) == OP_MOVE); ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); } } setclvalue(L, ra, ncl); Protect(luaC_checkGC(L)); continue; } case OP_VARARG: { int b = GETARG_B(i) - 1; int j; CallInfo *ci = L->ci; int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; if (b == LUA_MULTRET) { Protect(luaD_checkstack(L, n)); ra = RA(i); /* previous call may change the stack */ b = n; L->top = ra + n; } for (j = 0; j < b; j++) { if (j < n) { setobjs2s(L, ra + j, ci->base - n + j); } else { setnilvalue(ra + j); } } continue; } } } } tagua-1.0-alpha2/lua/src/lvm.h000066400000000000000000000022031077523320400161370ustar00rootroot00000000000000/* ** $Id: lvm.h,v 2.5 2005/08/22 18:54:49 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ #ifndef lvm_h #define lvm_h #include "ldo.h" #include "lobject.h" #include "ltm.h" #define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o))) #define tonumber(o,n) (ttype(o) == LUA_TNUMBER || \ (((o) = luaV_tonumber(o,n)) != NULL)) #define equalobj(L,o1,o2) \ (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n); LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj); LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val); LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val); LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls); LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); #endif tagua-1.0-alpha2/lua/src/lzio.c000066400000000000000000000031301077523320400163110ustar00rootroot00000000000000/* ** $Id: lzio.c,v 1.31 2005/06/03 20:15:29 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ #include #define lzio_c #define LUA_CORE #include "lua.h" #include "llimits.h" #include "lmem.h" #include "lstate.h" #include "lzio.h" int luaZ_fill (ZIO *z) { size_t size; lua_State *L = z->L; const char *buff; lua_unlock(L); buff = z->reader(L, z->data, &size); lua_lock(L); if (buff == NULL || size == 0) return EOZ; z->n = size - 1; z->p = buff; return char2int(*(z->p++)); } int luaZ_lookahead (ZIO *z) { if (z->n == 0) { if (luaZ_fill(z) == EOZ) return EOZ; else { z->n++; /* luaZ_fill removed first byte; put back it */ z->p--; } } return char2int(*z->p); } void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { z->L = L; z->reader = reader; z->data = data; z->n = 0; z->p = NULL; } /* --------------------------------------------------------------- read --- */ size_t luaZ_read (ZIO *z, void *b, size_t n) { while (n) { size_t m; if (luaZ_lookahead(z) == EOZ) return n; /* return number of missing bytes */ m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ memcpy(b, z->p, m); z->n -= m; z->p += m; b = (char *)b + m; n -= m; } return 0; } /* ------------------------------------------------------------------------ */ char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { if (n > buff->buffsize) { if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; luaZ_resizebuffer(L, buff, n); } return buff->buffer; } tagua-1.0-alpha2/lua/src/lzio.h000066400000000000000000000030201077523320400163140ustar00rootroot00000000000000/* ** $Id: lzio.h,v 1.21 2005/05/17 19:49:15 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ #ifndef lzio_h #define lzio_h #include "lua.h" #include "lmem.h" #define EOZ (-1) /* end of stream */ typedef struct Zio ZIO; #define char2int(c) cast(int, cast(unsigned char, (c))) #define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) typedef struct Mbuffer { char *buffer; size_t n; size_t buffsize; } Mbuffer; #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) #define luaZ_buffer(buff) ((buff)->buffer) #define luaZ_sizebuffer(buff) ((buff)->buffsize) #define luaZ_bufflen(buff) ((buff)->n) #define luaZ_resetbuffer(buff) ((buff)->n = 0) #define luaZ_resizebuffer(L, buff, size) \ (luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ (buff)->buffsize = size) #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data); LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ LUAI_FUNC int luaZ_lookahead (ZIO *z); /* --------- Private Part ------------------ */ struct Zio { size_t n; /* bytes still unread */ const char *p; /* current position in buffer */ lua_Reader reader; void* data; /* additional data */ lua_State *L; /* Lua state (for reader) */ }; LUAI_FUNC int luaZ_fill (ZIO *z); #endif tagua-1.0-alpha2/lua/src/print.c000066400000000000000000000115201077523320400164720ustar00rootroot00000000000000/* ** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ #include #include #define luac_c #define LUA_CORE #include "ldebug.h" #include "lobject.h" #include "lopcodes.h" #include "lundump.h" #define PrintFunction luaU_print #define Sizeof(x) ((int)sizeof(x)) #define VOID(p) ((const void*)(p)) static void PrintString(const TString* ts) { const char* s=getstr(ts); size_t i,n=ts->tsv.len; putchar('"'); for (i=0; ik[i]; switch (ttype(o)) { case LUA_TNIL: printf("nil"); break; case LUA_TBOOLEAN: printf(bvalue(o) ? "true" : "false"); break; case LUA_TNUMBER: printf(LUA_NUMBER_FMT,nvalue(o)); break; case LUA_TSTRING: PrintString(rawtsvalue(o)); break; default: /* cannot happen */ printf("? type=%d",ttype(o)); break; } } static void PrintCode(const Proto* f) { const Instruction* code=f->code; int pc,n=f->sizecode; for (pc=0; pc0) printf("[%d]\t",line); else printf("[-]\t"); printf("%-9s\t",luaP_opnames[o]); switch (getOpMode(o)) { case iABC: printf("%d",a); if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b); if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); break; case iABx: if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); break; case iAsBx: if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); break; } switch (o) { case OP_LOADK: printf("\t; "); PrintConstant(f,bx); break; case OP_GETUPVAL: case OP_SETUPVAL: printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-"); break; case OP_GETGLOBAL: case OP_SETGLOBAL: printf("\t; %s",svalue(&f->k[bx])); break; case OP_GETTABLE: case OP_SELF: if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } break; case OP_SETTABLE: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_POW: case OP_EQ: case OP_LT: case OP_LE: if (ISK(b) || ISK(c)) { printf("\t; "); if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); printf(" "); if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); } break; case OP_JMP: case OP_FORLOOP: case OP_FORPREP: printf("\t; to %d",sbx+pc+2); break; case OP_CLOSURE: printf("\t; %p",VOID(f->p[bx])); break; case OP_SETLIST: if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c); break; default: break; } printf("\n"); } } #define SS(x) (x==1)?"":"s" #define S(x) x,SS(x) static void PrintHeader(const Proto* f) { const char* s=getstr(f->source); if (*s=='@' || *s=='=') s++; else if (*s==LUA_SIGNATURE[0]) s="(bstring)"; else s="(string)"; printf("\n%s <%s:%d,%d> (%d instruction%s, %d bytes at %p)\n", (f->linedefined==0)?"main":"function",s, f->linedefined,f->lastlinedefined, S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); printf("%d%s param%s, %d slot%s, %d upvalue%s, ", f->numparams,f->is_vararg?"+":"",SS(f->numparams), S(f->maxstacksize),S(f->nups)); printf("%d local%s, %d constant%s, %d function%s\n", S(f->sizelocvars),S(f->sizek),S(f->sizep)); } static void PrintConstants(const Proto* f) { int i,n=f->sizek; printf("constants (%d) for %p:\n",n,VOID(f)); for (i=0; isizelocvars; printf("locals (%d) for %p:\n",n,VOID(f)); for (i=0; ilocvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); } } static void PrintUpvalues(const Proto* f) { int i,n=f->sizeupvalues; printf("upvalues (%d) for %p:\n",n,VOID(f)); if (f->upvalues==NULL) return; for (i=0; iupvalues[i])); } } void PrintFunction(const Proto* f, int full) { int i,n=f->sizep; PrintHeader(f); PrintCode(f); if (full) { PrintConstants(f); PrintLocals(f); PrintUpvalues(f); } for (i=0; ip[i],full); } tagua-1.0-alpha2/lua/test/000077500000000000000000000000001077523320400153635ustar00rootroot00000000000000tagua-1.0-alpha2/lua/test/README000066400000000000000000000022311077523320400162410ustar00rootroot00000000000000These are simple tests for Lua. Some of them contain useful code. They are meant to be run to make sure Lua is built correctly and also to be read, to see how Lua programs look. Here is a one-line summary of each program: bisect.lua bisection method for solving non-linear equations cf.lua temperature conversion table (celsius to farenheit) echo.lua echo command line arguments env.lua environment variables as automatic global variables factorial.lua factorial without recursion fib.lua fibonacci function with cache fibfor.lua fibonacci numbers with coroutines and generators globals.lua report global variable usage hello.lua the first program in every language life.lua Conway's Game of Life luac.lua bare-bones luac printf.lua an implementation of printf readonly.lua make global variables readonly sieve.lua the sieve of of Eratosthenes programmed with coroutines sort.lua two implementations of a sort function table.lua make table, grouping all data for the same item trace-calls.lua trace calls trace-globals.lua trace assigments to global variables xd.lua hex dump tagua-1.0-alpha2/lua/test/bisect.lua000066400000000000000000000012051077523320400173350ustar00rootroot00000000000000-- bisection method for solving non-linear equations delta=1e-6 -- tolerance function bisect(f,a,b,fa,fb) local c=(a+b)/2 io.write(n," c=",c," a=",a," b=",b,"\n") if c==a or c==b or math.abs(a-b) posted to lua-l -- modified to use ANSI terminal escape sequences -- modified to use for instead of while local write=io.write ALIVE="" DEAD="" ALIVE="O" DEAD="-" function delay() -- NOTE: SYSTEM-DEPENDENT, adjust as necessary for i=1,10000 do end -- local i=os.clock()+1 while(os.clock() 0 do local xm1,x,xp1,xi=self.w-1,self.w,1,self.w while xi > 0 do local sum = self[ym1][xm1] + self[ym1][x] + self[ym1][xp1] + self[y][xm1] + self[y][xp1] + self[yp1][xm1] + self[yp1][x] + self[yp1][xp1] next[y][x] = ((sum==2) and self[y][x]) or ((sum==3) and 1) or 0 xm1,x,xp1,xi = x,xp1,xp1+1,xi-1 end ym1,y,yp1,yi = y,yp1,yp1+1,yi-1 end end -- output the array to screen function _CELLS:draw() local out="" -- accumulate to reduce flicker for y=1,self.h do for x=1,self.w do out=out..(((self[y][x]>0) and ALIVE) or DEAD) end out=out.."\n" end write(out) end -- constructor function CELLS(w,h) local c = ARRAY2D(w,h) c.spawn = _CELLS.spawn c.evolve = _CELLS.evolve c.draw = _CELLS.draw return c end -- -- shapes suitable for use with spawn() above -- HEART = { 1,0,1,1,0,1,1,1,1; w=3,h=3 } GLIDER = { 0,0,1,1,0,1,0,1,1; w=3,h=3 } EXPLODE = { 0,1,0,1,1,1,1,0,1,0,1,0; w=3,h=4 } FISH = { 0,1,1,1,1,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0; w=5,h=4 } BUTTERFLY = { 1,0,0,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,0,1,1,0,0,0,1; w=5,h=5 } -- the main routine function LIFE(w,h) -- create two arrays local thisgen = CELLS(w,h) local nextgen = CELLS(w,h) -- create some life -- about 1000 generations of fun, then a glider steady-state thisgen:spawn(GLIDER,5,4) thisgen:spawn(EXPLODE,25,10) thisgen:spawn(FISH,4,12) -- run until break local gen=1 write("\027[2J") -- ANSI clear screen while 1 do thisgen:evolve(nextgen) thisgen,nextgen = nextgen,thisgen write("\027[H") -- ANSI home cursor thisgen:draw() write("Life - generation ",gen,"\n") gen=gen+1 if gen>2000 then break end --delay() -- no delay end end LIFE(40,20) tagua-1.0-alpha2/lua/test/luac.lua000066400000000000000000000003521077523320400170120ustar00rootroot00000000000000-- bare-bones luac in Lua -- usage: lua luac.lua file.lua assert(arg[1]~=nil and arg[2]==nil,"usage: lua luac.lua file.lua") f=assert(io.open("luac.out","wb")) assert(f:write(string.dump(assert(loadfile(arg[1]))))) assert(f:close()) tagua-1.0-alpha2/lua/test/printf.lua000066400000000000000000000002511077523320400173660ustar00rootroot00000000000000-- an implementation of printf function printf(...) io.write(string.format(...)) end printf("Hello %s from %s on %s\n",os.getenv"USER" or "there",_VERSION,os.date()) tagua-1.0-alpha2/lua/test/readonly.lua000066400000000000000000000004041077523320400177010ustar00rootroot00000000000000-- make global variables readonly local f=function (t,i) error("cannot redefine global variable `"..i.."'",2) end local g={} local G=getfenv() setmetatable(g,{__index=G,__newindex=f}) setfenv(1,g) -- an example rawset(g,"x",3) x=2 y=1 -- cannot redefine `y' tagua-1.0-alpha2/lua/test/sieve.lua000066400000000000000000000014061077523320400172020ustar00rootroot00000000000000-- the sieve of of Eratosthenes programmed with coroutines -- typical usage: lua -e N=1000 sieve.lua | column -- generate all the numbers from 2 to n function gen (n) return coroutine.wrap(function () for i=2,n do coroutine.yield(i) end end) end -- filter the numbers generated by `g', removing multiples of `p' function filter (p, g) return coroutine.wrap(function () while 1 do local n = g() if n == nil then return end if math.mod(n, p) ~= 0 then coroutine.yield(n) end end end) end N=N or 1000 -- from command line x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done if n == nil then break end print(n) -- must be a prime number x = filter(n, x) -- now remove its multiples end tagua-1.0-alpha2/lua/test/sort.lua000066400000000000000000000027261077523320400170640ustar00rootroot00000000000000-- two implementations of a sort function -- this is an example only. Lua has now a built-in function "sort" -- extracted from Programming Pearls, page 110 function qsort(x,l,u,f) if ly end) show("after reverse selection sort",x) qsort(x,1,n,function (x,y) return x>> ",string.rep(" ",level)) if t~=nil and t.currentline>=0 then io.write(t.short_src,":",t.currentline," ") end t=debug.getinfo(2) if event=="call" then level=level+1 else level=level-1 if level<0 then level=0 end end if t.what=="main" then if event=="call" then io.write("begin ",t.short_src) else io.write("end ",t.short_src) end elseif t.what=="Lua" then -- table.foreach(t,print) io.write(event," ",t.name or "(Lua)"," <",t.linedefined,":",t.short_src,">") else io.write(event," ",t.name or "(C)"," [",t.what,"] ") end io.write("\n") end debug.sethook(hook,"cr") level=0 tagua-1.0-alpha2/lua/test/trace-globals.lua000066400000000000000000000013301077523320400206020ustar00rootroot00000000000000-- trace assigments to global variables do -- a tostring that quotes strings. note the use of the original tostring. local _tostring=tostring local tostring=function(a) if type(a)=="string" then return string.format("%q",a) else return _tostring(a) end end local log=function (name,old,new) local t=debug.getinfo(3,"Sl") local line=t.currentline io.write(t.short_src) if line>=0 then io.write(":",line) end io.write(": ",name," is now ",tostring(new)," (was ",tostring(old),")","\n") end local g={} local set=function (t,name,value) log(name,g[name],value) g[name]=value end setmetatable(getfenv(),{__index=g,__newindex=set}) end -- an example a=1 b=2 a=10 b=20 b=nil b=200 print(a,b,c) tagua-1.0-alpha2/lua/test/xd.lua000066400000000000000000000005541077523320400165050ustar00rootroot00000000000000-- hex dump -- usage: lua xd.lua < file local offset=0 while true do local s=io.read(16) if s==nil then return end io.write(string.format("%08X ",offset)) string.gsub(s,"(.)", function (c) io.write(string.format("%02X ",string.byte(c))) end) io.write(string.rep(" ",3*(16-string.len(s)))) io.write(" ",string.gsub(s,"%c","."),"\n") offset=offset+16 end tagua-1.0-alpha2/src/000077500000000000000000000000001077523320400144125ustar00rootroot00000000000000tagua-1.0-alpha2/src/.gitignore000066400000000000000000000002261077523320400164020ustar00rootroot00000000000000tagua_automoc.cpp.files DartTestfile.txt Makefile cmake_install.cmake taguaprivate_automoc.cpp.files moc_*.cpp ui_*.h *_automoc.cpp tagua tagua.shell tagua-1.0-alpha2/src/CMakeLists.txt000066400000000000000000000105311077523320400171520ustar00rootroot00000000000000 set(tagua_SRC controllers/editgame.cpp controllers/abstract.cpp controllers/editposition.cpp controllers/entitytoken.cpp loader/image.cpp loader/theme.cpp loader/context.cpp luaapi/lfunclib.c luaapi/options.cpp luaapi/luahl.cpp luaapi/genericwrapper.cpp luaapi/loader.cpp luaapi/imaging.cpp luaapi/luavalue.cpp entities/gameentity.cpp entities/userentity.cpp entities/examinationentity.cpp entities/entity.cpp entities/engineentity.cpp entities/icsentity.cpp hlvariant/chess/variant.cpp hlvariant/chess/san.cpp hlvariant/chess/icsverbose.cpp hlvariant/chess/move.cpp hlvariant/chess/gamestate.cpp hlvariant/chess/piece.cpp hlvariant/chess/actions.cpp hlvariant/dummy/variant.cpp hlvariant/crazyhouse/variant.cpp hlvariant/crazyhouse/piece.cpp hlvariant/minichess5/variant.cpp hlvariant/shogi/variant.cpp hlvariant/shogi/piece.cpp hlvariant/shogi/shogiactions.cpp hlvariant/minishogi/variant.cpp hlvariant/sho-shogi/variant.cpp hlvariant/tori-shogi/variant.cpp hlvariant/tori-shogi/piece.cpp animationfactory.cpp constrainedtext.cpp movelist.cpp infodisplay.cpp engineinfo.cpp premove.cpp mainanimation.cpp random.cpp point.cpp sprite.cpp pref_movelist.cpp option.cpp graphicalsystem.cpp agentgroup.cpp graphicalgame.cpp imageeffects.cpp crash.cpp flash.cpp histlineedit.cpp pathinfo.cpp pref_theme.cpp gameinfo.cpp console.cpp animation.cpp pref_engines.cpp clock.cpp chesstable.cpp index.cpp mastersettings.cpp location.cpp hline.cpp xboardengine.cpp gnushogiengine.cpp settings.cpp positioninfo.cpp engine.cpp ui.cpp movelist_widget.cpp pref_preferences.cpp poolinfo.cpp pixmaploader.cpp qconnect.cpp pref_board.cpp game.cpp piecepool.cpp movelist_textual.cpp icsconnection.cpp mainwindow.cpp board.cpp common.cpp pgnparser.cpp movement.cpp connection.cpp movelist_table.cpp newgame.cpp option_p.cpp themeinfo.cpp namedsprite.cpp icsgamedata.cpp turnpolicy.cpp decoratedmove.cpp variants.cpp actioncollection.cpp tabwidget.cpp ) # remove spurious xpressive warnings set_source_files_properties(icsconnection.cpp PROPERTIES COMPILE_FLAGS -Wno-extra) kde4_add_ui_files(tagua_SRC ui/pref_highlight.ui ui/newgamedialog.ui ui/pref_engines.ui ui/preferences.ui ui/gametags.ui ui/pref_movelist.ui ui/quickconnect.ui ui/pref_theme.ui ui/pref_theme_page.ui ui/pref_board.ui ) include_directories( ${KDE4_INCLUDES} ${LUA_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${BLITZ_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} ) add_definitions( ${LUA_CFLAGS} ) if(NOT DEFINED COMPILER_HAVE_X86_MMX) check_cxx_source_compiles(" int main() { __asm__(\"pxor %mm0, %mm0\") ; }" COMPILER_HAVE_X86_MMX) endif(NOT DEFINED COMPILER_HAVE_X86_MMX) if(NOT DEFINED COMPILER_HAVE_X86_SSE2) check_cxx_source_compiles(" int main() { __asm__(\"xorpd %xmm0, %xmm0\"); }" COMPILER_HAVE_X86_SSE2) endif(NOT DEFINED COMPILER_HAVE_X86_SSE2) if(COMPILER_HAVE_X86_MMX) list(APPEND tagua_SRC imageeffects_mmx.cpp) set_source_files_properties(imageeffects_mmx.cpp PROPERTIES COMPILE_FLAGS -mmmx) set_source_files_properties(imageeffects.cpp PROPERTIES COMPILE_FLAGS -DHAVE_X86_MMX) endif(COMPILER_HAVE_X86_MMX) if(COMPILER_HAVE_X86_SSE2) list(APPEND tagua_SRC imageeffects_sse.cpp) set_source_files_properties(imageeffects_sse.cpp PROPERTIES COMPILE_FLAGS -msse2) set_source_files_properties(imageeffects.cpp PROPERTIES COMPILE_FLAGS -DHAVE_X86_SSE2) endif(COMPILER_HAVE_X86_SSE2) if(DEBUG_BUILD) set(TAGUA_TARGET taguaprivate) kde4_add_library(taguaprivate SHARED ${tagua_SRC}) kde4_add_executable(tagua main.cpp) else(DEBUG_BUILD) set(TAGUA_TARGET tagua) kde4_add_executable(tagua main.cpp ${tagua_SRC}) endif(DEBUG_BUILD) link_directories( ${LUA_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${CMAKE_BINARY_DIR}/lib ) target_link_libraries(${TAGUA_TARGET} ${LUA_LINK_FLAGS} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${BLITZ_LIBRARIES} dl kdegames ) if(DEBUG_BUILD) target_link_libraries(tagua taguaprivate) install(TARGETS taguaprivate DESTINATION ${LIB_INSTALL_DIR}) endif(DEBUG_BUILD) INSTALL(TARGETS tagua DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) install(FILES tagua.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) install(FILES taguaui.rc DESTINATION ${DATA_INSTALL_DIR}/tagua) tagua-1.0-alpha2/src/Doxyfile000066400000000000000000000204571077523320400161300ustar00rootroot00000000000000# Doxyfile 1.4.7 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = Tagua PROJECT_NUMBER = 1.0 OUTPUT_DIRECTORY = doxy/en CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 2 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = NO EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_CLASSES = YES HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = YES GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = FILE_PATTERNS = RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = ui_* \ moc_* EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 2 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = doxy/header.html HTML_FOOTER = doxy/footer.html HTML_STYLESHEET = doxy/doxygen.css HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = YES ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = NO HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = YES CALLER_GRAPH = YES GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO tagua-1.0-alpha2/src/actioncollection.cpp000066400000000000000000000011641077523320400204510ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "actioncollection.h" #include ActionCollection::ActionCollection() { } void ActionCollection::add(QAction* action) { m_actions.append(action); } QList ActionCollection::actions() const { return m_actions; } tagua-1.0-alpha2/src/actioncollection.h000066400000000000000000000013541077523320400201170ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef ACTIONCOLLECTION_H #define ACTIONCOLLECTION_H #include #include #include #include class QAction; class ActionCollection : public QObject { Q_OBJECT QList m_actions; public: ActionCollection(); void add(QAction* action); QList actions() const; }; #endif // ACTIONCOLLECTION_H tagua-1.0-alpha2/src/agent.h000066400000000000000000000016061077523320400156640ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef AGENT_H #define AGENT_H #include "fwd.h" class Index; class Agent { protected: bool m_active; public: virtual ~Agent() { } Agent() : m_active(true) { } virtual void notifyClockUpdate(int, int) = 0; virtual void notifyMove(const Index& index) = 0; virtual void notifyBack() = 0; virtual void notifyForward() = 0; virtual void notifyGotoFirst() = 0; virtual void notifyGotoLast() = 0; virtual void stop() { m_active = false; } bool active() const { return m_active; } }; #endif // AGENT_H tagua-1.0-alpha2/src/agentgroup.cpp000066400000000000000000000042541077523320400172760ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "agentgroup.h" using namespace boost; void AgentGroup::addAgent(const AgentPtr& agent) { m_agents.insert(agent); } #define FORWARD(method, args) \ for (weak_set::iterator i = m_agents.begin(); \ i != m_agents.end(); \ ++i) { \ if (i.get() != source) { \ i->method args; \ } \ } void AgentGroup::clockUpdate(Agent* source, int white, int black) { FORWARD(notifyClockUpdate, (white, black)) } void AgentGroup::move(Agent* source, const Index& index) { FORWARD(notifyMove, (index)) } void AgentGroup::back(Agent* source) { FORWARD(notifyBack, ()) } void AgentGroup::forward(Agent* source) { FORWARD(notifyForward, ()) } void AgentGroup::gotoFirst(Agent* source) { FORWARD(notifyGotoFirst, ()) } void AgentGroup::gotoLast(Agent* source) { FORWARD(notifyGotoLast, ()) } #undef FORWARD AgentGroupDispatcher::AgentGroupDispatcher(AgentGroup* group, Agent* agent) : m_group(group) , m_agent(agent) { } void AgentGroupDispatcher::clockUpdate(int white, int black) { m_group->clockUpdate(m_agent, white, black); } bool AgentGroupDispatcher::move(const Index& index) { m_group->move(m_agent, index); return true; } bool AgentGroupDispatcher::back() { m_group->back(m_agent); return true; } bool AgentGroupDispatcher::forward() { m_group->forward(m_agent); return true; } bool AgentGroupDispatcher::gotoFirst() { m_group->gotoFirst(m_agent); return true; } bool AgentGroupDispatcher::gotoLast() { m_group->gotoLast(m_agent); return true; } tagua-1.0-alpha2/src/agentgroup.h000066400000000000000000000024371077523320400167440ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef AGENTGROUP_H #define AGENTGROUP_H #include #include #include "weakset.h" #include "tagua.h" #include "agent.h" class AgentGroup { typedef boost::shared_ptr AgentPtr; typedef std::vector AgentList; weak_set m_agents; public: void addAgent(const AgentPtr& agent); void clockUpdate(Agent* source, int, int); void move(Agent* source, const Index&); void back(Agent* source); void forward(Agent* source); void gotoFirst(Agent* source); void gotoLast(Agent* source); }; class AgentGroupDispatcher { AgentGroup* m_group; Agent* m_agent; public: AgentGroupDispatcher(AgentGroup* group, Agent* agent); virtual ~AgentGroupDispatcher(){} virtual void clockUpdate(int, int); virtual bool move(const Index&); virtual bool back(); virtual bool forward(); virtual bool gotoFirst(); virtual bool gotoLast(); }; #endif // AGENTGROUP_H tagua-1.0-alpha2/src/animation.cpp000066400000000000000000000401551077523320400171020ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include #include "common.h" #include "animation.h" #include "point.h" #include "sprite.h" #include "movement.h" using namespace std; using namespace boost; #undef ANIMATION_DEBUG //BEGIN ConcreteAnimation ConcreteAnimation::ConcreteAnimation(const SpritePtr& piece) : m_piece(piece) { } //END ConcreteAnimation //BEGIN MovementAnimation MovementAnimation::MovementAnimation(const SpritePtr& piece, const QPoint& destination, bool rotate, double speed) : ConcreteAnimation(piece) , m_source(piece) , m_target(piece) , m_destination(destination) , m_speed(speed) , m_state(Inactive) , m_rotate(rotate) { #ifdef ANIMATION_DEBUG kDebug() << "creating animation " << this << " for piece " << piece.get() << endl; #endif } MovementAnimation::~MovementAnimation() { #ifdef ANIMATION_DEBUG kDebug() << "destroying animation " << this << " for piece " << m_piece.get() << endl; if (m_piece->movementAnimation().lock()) kDebug() << " *********** BUG **************" << endl; #endif // m_piece->setMovementAnimation(0); } void MovementAnimation::setTarget(const SpritePtr& target) { m_target = target; } void MovementAnimation::setSource(const SpritePtr& source) { m_source = source; } boost::shared_ptr MovementAnimation::createMovement(const QPoint& from, const QPoint& to) const { return boost::shared_ptr(new SigmoidalMovement(from, to, m_rotate)); } void MovementAnimation::start() { #ifdef ANIMATION_DEBUG kDebug() << "starting movement animation " << this << " on piece " << m_piece.get() << endl; #endif { if (shared_ptr animation = m_source->movementAnimation().lock()) { #ifdef ANIMATION_DEBUG kDebug() << "aborting movement animation " << animation << " on piece " << m_source.get() << endl; #endif animation->abort(); } } m_source->setMovementAnimation(shared_ptr()); m_target->setMovementAnimation(shared_from_this()); m_piece->raise(); m_movement = createMovement(m_piece->pos(), m_destination); // The total time of the animation is proportional to the square root // of the distance and to the inverse of the speed factor. double distance = Point(m_destination - m_piece->pos()).norm(); Q_ASSERT(m_speed > 0.0); m_time = 35 * sqrt(distance) / m_speed; m_state = m_time > 0 ? Active : Inactive; } Animation::State MovementAnimation::animationAdvance(int msec) { switch (m_state) { case Inactive: m_start = msec; start(); if (m_state == Inactive) abort(); break; case Aborted: break; case Active: { // reparameterize the time variable in [0,1] Q_ASSERT(m_time > 0); double t = (msec - m_start) / m_time; Q_ASSERT(t >= 0); #ifdef ANIMATION_DEBUG kDebug() << "active: t = " << t << endl; #endif if (t >= 1) stop(); else { QPoint to = m_movement->pos(t); m_piece->moveTo(to); m_piece->setRotation(m_movement->rotation(t)); } } break; } #ifdef ANIMATION_DEBUG kDebug() << "advance (" << this << ") state = " << m_state << endl; #endif return m_state; } void MovementAnimation::stop() { #ifdef ANIMATION_DEBUG kDebug() << "stopping animation " << this << " on piece " << m_piece.get() << endl; #endif m_piece->moveTo(m_destination); m_piece->setRotation(0); abort(); m_state = Inactive; } void MovementAnimation::abort() { #ifdef ANIMATION_DEBUG kDebug() << "aborting animation " << this << " on piece " << m_piece.get() << endl; #endif m_state = Aborted; m_target->setMovementAnimation(shared_ptr()); } //END MovementAnimation //BEGIN KnightMovementAnimation KnightMovementAnimation::KnightMovementAnimation(const SpritePtr& piece, const QPoint& destination, bool rotate, double speed) : MovementAnimation(piece, destination, rotate, speed){ } boost::shared_ptr KnightMovementAnimation::createMovement(const QPoint& from, const QPoint& to) const { return boost::shared_ptr(new SigmoidalMovement(from, to, m_rotate)); } //END KnightMovementAnimation //BEGIN OneShotAnimation OneShotAnimation::OneShotAnimation(const SpritePtr& piece) : ConcreteAnimation(piece) { } Animation::State OneShotAnimation::animationAdvance(int) { shoot(); return Inactive; } //END OneShotAnimation //BEGIN InstantAnimation InstantAnimation::InstantAnimation(const SpritePtr& piece, const QPoint& destination) : OneShotAnimation(piece) , m_destination(destination) { } void InstantAnimation::shoot() { m_piece->moveTo(m_destination); if (shared_ptr animation = m_piece->movementAnimation().lock()) { animation->abort(); m_piece->setMovementAnimation(shared_ptr()); } } //END InstantAnimation //BEGIN CaptureAnimation CaptureAnimation::CaptureAnimation(const SpritePtr& piece) : OneShotAnimation(piece) { } void CaptureAnimation::shoot() { m_piece->hide(); if (shared_ptr animation = m_piece->movementAnimation().lock()) { animation->abort(); m_piece->setMovementAnimation(shared_ptr()); } } //END CaptureAnimation //BEGIN DropAnimation DropAnimation::DropAnimation(const SpritePtr& piece) : OneShotAnimation(piece) , m_valid_position(false) { } DropAnimation::DropAnimation(const SpritePtr& piece, const QPoint& pos) : OneShotAnimation(piece) , m_valid_position(true) , m_position(pos) { } void DropAnimation::shoot() { if (m_valid_position) m_piece->moveTo(m_position); m_piece->show(); } //END DropAnimation //BEGIN PromotionAnimation PromotionAnimation::PromotionAnimation(const SpritePtr& piece, const SpritePtr& promoted) : OneShotAnimation(piece) , m_promoted(promoted) { } void PromotionAnimation::shoot() { m_piece->hide(); m_promoted->show(); } //END PromotionAnimation //BEGIN CrossFadingAnimation CrossFadingAnimation::CrossFadingAnimation(const SpritePtr& piece, const SpritePtr& promoted) : m_piece(piece) { addPreAnimation(shared_ptr(new FadeAnimation(piece, 255, 0))); addPreAnimation(shared_ptr(new FadeAnimation(promoted, 0, 255))); } void CrossFadingAnimation::start() { AnimationGroup::start(); } //END CrossFadingAnimation //BEGIN DelayAnimation DelayAnimation::DelayAnimation(int secs) : Animation() , m_state(Inactive) , m_msecs(secs) { } void DelayAnimation::start() { m_state = Active; } Animation::State DelayAnimation::animationAdvance(int msec) { switch (m_state) { case Inactive: m_start = msec; start(); break; case Aborted: break; case Active: if(msec > m_start + m_msecs) stop(); break; } return m_state; } void DelayAnimation::stop() { m_state = Inactive; } void DelayAnimation::abort() { m_state = Aborted; } //END DelayAnimation //BEGIN FadeAnimation FadeAnimation::FadeAnimation(const SpritePtr& sprite, const QPoint& to, int fadeFrom, int fadeTo) : ConcreteAnimation(sprite) , m_fadeFrom(fadeFrom) , m_fadeTo(fadeTo) , m_to(to) , m_state(Inactive) { } FadeAnimation::FadeAnimation(const SpritePtr& sprite, int fadeFrom, int fadeTo) : ConcreteAnimation(sprite) , m_fadeFrom(fadeFrom) , m_fadeTo(fadeTo) , m_to(Point::invalid()) , m_state(Inactive) { } void FadeAnimation::start() { m_state = Active; if (m_to != Point::invalid()) { m_piece->moveTo(m_to); } m_piece->setOpacity(m_fadeFrom); m_piece->show(); } Animation::State FadeAnimation::animationAdvance(int msec) { switch (m_state) { case Inactive: m_start = msec; start(); break; case Aborted: break; case Active: { double t = (msec - m_start) / 400.0; Q_ASSERT(t >= 0); if(t >= 1) stop(); else { int op = static_cast(m_fadeTo * t + m_fadeFrom * (1 - t)); m_piece->setOpacity(op); } } break; } return m_state; } void FadeAnimation::stop() { m_piece->setOpacity(m_fadeTo); m_state = Inactive; } void FadeAnimation::abort() { m_state = Aborted; } //END FadeAnimation //BEGIN GrowAnimation GrowAnimation::GrowAnimation(const SpritePtr& sprite) : ConcreteAnimation(sprite) , m_state(Inactive) { } void GrowAnimation::start() { m_state = Active; m_piece->show(); m_piece->setScale(0.0); } Animation::State GrowAnimation::animationAdvance(int msec) { switch (m_state) { case Inactive: m_start = msec; start(); break; case Aborted: break; case Active: { double t = (msec - m_start) / 700.0; Q_ASSERT(t >= 0); if(t >= 1) stop(); else { t = sin(t*M_PI/2); m_piece->setScale(t); } } break; } return m_state; } void GrowAnimation::stop() { m_piece->setScale(1.0); m_state = Inactive; } void GrowAnimation::abort() { m_state = Aborted; } //END GrowAnimation //BEGIN ExplodeAnimation ExplodeAnimation::ExplodeAnimation(const SpritePtr& sprite, Random& random) : ConcreteAnimation(sprite) , m_state(Inactive) , m_random(random) { } void ExplodeAnimation::start() { m_state = Active; m_piece->show(); m_piece->setupExplosion(m_random); } Animation::State ExplodeAnimation::animationAdvance(int msec) { switch (m_state) { case Inactive: m_start = msec; start(); break; case Aborted: break; case Active: { double t = (msec - m_start) / 700.0; Q_ASSERT(t >= 0); if(t >= 1) stop(); else { t = sin(t*M_PI/2); m_piece->setExplosionStep(sin(t*M_PI/2)*0.7); //m_piece->setScale(1.0+t*0.2); m_piece->setOpacity(int(cos(t*M_PI/2)*255)); } } break; } return m_state; } void ExplodeAnimation::stop() { m_piece->setExplosionStep(0.7); //m_piece->setScale(1.2); m_state = Inactive; } void ExplodeAnimation::abort() { m_state = Aborted; } //END ExplodeAnimation //BEGIN AnimationGroup AnimationGroup::AnimationGroup(bool persistent) : Animation() , m_active(false) , m_persistent(persistent) , m_chain_abortions(!persistent) { } void AnimationGroup::start() { m_active = true; } bool AnimationGroup::empty() const { return pre.empty() && post.empty(); } Animation::State AnimationGroup::animationAdvance(int msec) { if (!m_active) { start(); } if (!pre.empty()) { // advance pre-animations for (Iterator i = pre.begin(); i != pre.end(); ) { State animation_state = (*i)->animationAdvance(msec); switch (animation_state) { case Aborted: #if 0 if (m_chain_abortions) { for (Iterator j = pre.begin(); j != pre.end(); ) { (*j)->stop(); j = pre.erase(j); } post.clear(); return Aborted; } #endif case Inactive: // the animation ended or has been aborted, // remove it from the list i = pre.erase(i); break; case Active: // handle next animation ++i; break; } } // if there are still pre-animations, we're done if (!pre.empty()) return Active; } else { // no pre-animations: handle post animations for (Iterator i = post.begin(); i != post.end(); ) { State animation_state = (*i)->animationAdvance(msec); switch (animation_state) { case Aborted: #if 0 if (m_chain_abortions) { return Aborted; } #endif case Inactive: // the animation ended or has been aborted, // remove it from the list i = pre.erase(i); break; case Active: // handle next animation ++i; break; } } } // go on animating if there are still animations left // or the group is persistent m_active = m_persistent || !post.empty(); return m_active ? Active : Inactive; } void AnimationGroup::addPreAnimation(AnimationPtr anim) { if (!anim) return; if (m_active) // cannot dynamically add pre-animations // adding it as a post-animation, instead addPostAnimation(anim); else pre.push_back(anim); } void AnimationGroup::addPostAnimation(AnimationPtr anim) { if (!anim) return; post.push_back(anim); } void AnimationGroup::stop() { // stop all animations for (Iterator i = pre.begin(); i != pre.end(); ) { (*i)->stop(); i = pre.erase(i); } for (Iterator i = post.begin(); i != post.end(); ) { (*i)->stop(); i = post.erase(i); } if (!m_persistent) m_active = false; } //END AnimationGroup //BEGIN TeleportAnimation TeleportAnimation::TeleportAnimation(const SpritePtr& sprite, const QPoint& from, const QPoint& to) : AnimationGroup(1.0) { SpritePtr copy(sprite->duplicate()); copy->show(); addPreAnimation(AnimationPtr(new FadeAnimation(copy, from, 255, 0))); addPreAnimation(AnimationPtr(new FadeAnimation(sprite, to, 0, 255))); } TeleportAnimation::TeleportAnimation(const SpritePtr& sprite, const QPoint& to) : AnimationGroup(1.0) { SpritePtr copy(sprite->duplicate()); copy->show(); addPreAnimation(AnimationPtr(new FadeAnimation(copy, copy->pos(), 255, 0))); addPreAnimation(AnimationPtr(new FadeAnimation(sprite, to, 0, 255))); } //END TeleportAnimation //BEGIN DelayedAnimationSet DelayedAnimationSet::DelayedAnimationSet(Random& random) : m_random(random) , m_state(Inactive) { } void DelayedAnimationSet::addAnimation(const shared_ptr& animation) { if (animation && m_state == Inactive) m_animations.push_back(animation); } void DelayedAnimationSet::start() { const int n = m_animations.size(); if (n == 0) m_state = Inactive; else { // animation time is proportional to the // number of animations m_time = 100 * n; // one animation starts immediately int immediate = m_random.rand(0, n - 1)(); m_events.push_back(Event(immediate, m_start)); // generate event times Random::IntegerGenerator event_time = m_random.rand(m_start, m_start + m_time); for (int i = 0; i < n; i++) { if (i == immediate) continue; m_events.push_back(Event(i, event_time())); } // sort events sort(m_events.begin(), m_events.end()); // set next event m_next_event = m_events.begin(); m_state = Active; } } Animation::State DelayedAnimationSet::animationAdvance(int msec) { switch (m_state) { case Inactive: m_start = msec; start(); if (m_state == Inactive) abort(); break; case Aborted: break; case Active: { // if there are still events left if (m_next_event != m_events.end()) { // if the event period is elapsed if (msec >= m_start + m_time) { // execute all remaining animations while (m_next_event != m_events.end()) execute((m_next_event++)->index()); } else { // if the event time has elapsed while (m_next_event != m_events.end() && msec >= m_next_event->time()) { // run the corresponding animation execute((m_next_event++)->index()); } } } // step all active animations // continue animating until m_group is over m_state = m_group.animationAdvance(msec); } break; } return m_state; } void DelayedAnimationSet::execute(int index) { // start animation adding it to m_group m_group.addPostAnimation(m_animations[index]); // remove it from the animation vector m_animations[index] = shared_ptr(); } void DelayedAnimationSet::stop() { m_group.stop(); m_animations.clear(); m_state = Inactive; } void DelayedAnimationSet::abort() { m_state = Aborted; m_animations.clear(); } //END DelayedAnimationSet tagua-1.0-alpha2/src/animation.h000066400000000000000000000156341077523320400165530ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ANIMATION_H #define ANIMATION_H #include #include #include #include #include #include "sprite.h" #include "fwd.h" class Movement; class Random; class Animation : public boost::enable_shared_from_this { protected: enum State { Active, Inactive, Aborted }; public: virtual ~Animation() { } virtual bool sticky() const { return false; } virtual State animationAdvance(int msec) = 0; virtual void stop() = 0; virtual void abort() = 0; }; class ConflictingAnimation { public: virtual ~ConflictingAnimation() { } virtual void setTarget(const SpritePtr&) = 0; virtual void setSource(const SpritePtr&) = 0; }; class ConcreteAnimation : public Animation { protected: SpritePtr m_piece; public: ConcreteAnimation(const SpritePtr& piece); virtual void stop() { } }; class OneShotAnimation : public ConcreteAnimation { protected: virtual void shoot() = 0; public: OneShotAnimation(const SpritePtr& piece); virtual State animationAdvance(int); virtual void abort() { } }; class InstantAnimation : public OneShotAnimation , public ConflictingAnimation { QPoint m_destination; SpritePtr m_source; public: InstantAnimation(const SpritePtr& piece, const QPoint& destination); virtual void shoot(); virtual void setTarget(const SpritePtr&) { } virtual void setSource(const SpritePtr& source) { m_source = source; } }; class MovementAnimation : public ConcreteAnimation , public ConflictingAnimation { protected: SpritePtr m_source; SpritePtr m_target; QPoint m_destination; double m_speed; State m_state; double m_time; int m_start; boost::shared_ptr m_movement; bool m_rotate; virtual boost::shared_ptr createMovement(const QPoint& from, const QPoint& to) const; void start(); public: MovementAnimation(const SpritePtr& piece, const QPoint& destination, bool rotate = false, double speed = 1.0); virtual ~MovementAnimation(); virtual State animationAdvance(int msec); virtual void stop(); virtual void abort(); virtual void setTarget(const SpritePtr& target); virtual void setSource(const SpritePtr& source); }; class KnightMovementAnimation : public MovementAnimation { protected: virtual boost::shared_ptr createMovement(const QPoint& from, const QPoint& to) const; public: KnightMovementAnimation(const SpritePtr& piece, const QPoint& destination, bool rotate, double speed = 1.0); }; class CaptureAnimation : public OneShotAnimation { protected: virtual void shoot(); public: CaptureAnimation(const SpritePtr& piece); }; class DropAnimation : public OneShotAnimation { bool m_valid_position; QPoint m_position; protected: virtual void shoot(); public: DropAnimation(const SpritePtr& piece); DropAnimation(const SpritePtr& piece, const QPoint&); }; class PromotionAnimation : public OneShotAnimation { protected: SpritePtr m_promoted; virtual void shoot(); public: PromotionAnimation(const SpritePtr& piece, const SpritePtr& promoted); }; class DelayAnimation : public Animation { State m_state; int m_msecs; int m_start; void start(); public: DelayAnimation(int msecs); virtual State animationAdvance(int msec); virtual void stop(); virtual void abort(); }; class FadeAnimation : public ConcreteAnimation { int m_fadeFrom; int m_fadeTo; QPoint m_to; State m_state; int m_start; void start(); public: FadeAnimation(const SpritePtr& sprite, const QPoint& pos, int fadeFrom, int fadeTo); FadeAnimation(const SpritePtr& sprite, int fadeFrom, int fadeTo); virtual State animationAdvance(int msec); virtual void stop(); virtual void abort(); }; class GrowAnimation : public ConcreteAnimation { State m_state; int m_start; void start(); public: GrowAnimation(const SpritePtr& sprite); virtual State animationAdvance(int msec); virtual void stop(); virtual void abort(); }; class ExplodeAnimation : public ConcreteAnimation { State m_state; Random& m_random; int m_start; void start(); public: ExplodeAnimation(const SpritePtr& sprite, Random& random); virtual State animationAdvance(int msec); virtual void stop(); virtual void abort(); }; /** * @brief Two groups of animations, to be executed one after the other. * * A double list of animations: pre-animations and post-animations. * When an AnimationGroup is advanced, pre-animations are handled first, * and removed from the list as they finish animating. * When all pre-animations are gone, post-animations are handled. */ class AnimationGroup : public Animation { private: typedef std::list AnimationList; typedef AnimationList::iterator Iterator; AnimationList pre; AnimationList post; protected: bool m_active; bool m_persistent; bool m_chain_abortions; virtual void start(); bool empty() const; public: AnimationGroup(bool persistent = false); virtual bool sticky() const { return m_persistent; } void setPersistent(bool value) { m_persistent = value; } void setChainAbortions(bool value) { m_chain_abortions = value; } void addPreAnimation(AnimationPtr); void addPostAnimation(AnimationPtr); virtual State animationAdvance(int msec); virtual void stop(); virtual void abort() { stop(); } }; class TeleportAnimation : public AnimationGroup { public: TeleportAnimation(const SpritePtr& sprite, const QPoint& from, const QPoint& to); TeleportAnimation(const SpritePtr& sprite, const QPoint& to); }; class CrossFadingAnimation : public AnimationGroup { SpritePtr m_piece; protected: virtual void start(); public: CrossFadingAnimation(const SpritePtr& piece, const SpritePtr& promoted); }; class DelayedAnimationSet : public Animation { class Event { int m_index; int m_time; public: Event(int index, int time) : m_index(index), m_time(time) { } int index() const { return m_index; } int time() const { return m_time; } bool operator<(const Event& other) const { return m_time < other.m_time; } }; int m_time; int m_start; Random& m_random; State m_state; std::vector > m_animations; AnimationGroup m_group; std::vector m_events; std::vector::iterator m_next_event; void execute(int); public: DelayedAnimationSet(Random& random); void addAnimation(const boost::shared_ptr& animation); void start(); virtual State animationAdvance(int msec); virtual void stop(); virtual void abort(); }; #endif // ANIMATION_H tagua-1.0-alpha2/src/animationfactory.cpp000066400000000000000000000142701077523320400204710ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "animationfactory.h" #include "animation.h" #include "namedsprite.h" #include "pointconverter.h" #include "indexconverter.h" #include "graphicalapi.h" #include "mastersettings.h" namespace Common { AnimationPtr appear(const AnimationSettings& s, const NamedSprite& sprite, Animate::AnimationType type) { if (!s.fading) type = Animate::Instant; switch (type) { case Animate::Normal: return AnimationPtr(new FadeAnimation(sprite.sprite(), 0, 255)); case Animate::Instant: default: return AnimationPtr(new DropAnimation(sprite.sprite())); } } AnimationPtr disappear(const AnimationSettings& s, const NamedSprite& sprite, Animate::AnimationType type) { if (!s.fading) type = Animate::Instant; switch (type) { case Animate::Normal: return AnimationPtr(new FadeAnimation(sprite.sprite(), 255, 0)); case Animate::Instant: default: return AnimationPtr(new CaptureAnimation(sprite.sprite())); } } }; AnimationSettings::AnimationSettings() { reload(); } void AnimationSettings::reload() { Settings s = settings().group("animations"); enabled = s.flag("enabled", true); maxSequence = s.group("sequence").flag("enabled", true) ? s.group("sequence")["max"].value() : 0; movement = s["movement"].flag("enabled", true); explode = s["explode"].flag("enabled", true); fading = s["fading"].flag("enabled", true); transform = s["transform"].flag("enabled", true); } AnimationFactory::AnimationFactory(GraphicalAPI* api) : m_api(api) { m_group = AnimationGroupPtr(new AnimationGroup); } AnimationGroupPtr AnimationFactory::group() const { return m_group; } void AnimationFactory::setGroup(const AnimationGroupPtr& group) { m_group = group; } void AnimationFactory::addPreAnimation(const Animate::Scheme& scheme, Animate::AnimationType type) { m_group->addPreAnimation(m_api->animate(scheme, type)); } void AnimationFactory::addPostAnimation(const Animate::Scheme& scheme, Animate::AnimationType type) { m_group->addPostAnimation(m_api->animate(scheme, type)); } AnimationFactory::operator AnimationGroupPtr() const { return group(); } namespace Animate { Scheme::~Scheme() { } move::move(const NamedSprite& sprite, const Point& to, int type) : m_sprite(sprite) , m_to(to) , m_type(type) { } AnimationPtr move::run(const AnimationSettings& s, const PointConverter* converter, AnimationType type) const { int mov_type = m_type; if (!s.movement) type = Instant; else if (!s.transform) { mov_type &= ~Rotating; } switch (type) { case Normal: { MovementAnimation* mov; QPoint destination = converter->toReal(m_to); Point origin = converter->toLogical(m_sprite.sprite()->pos() + Point(converter->squareSize(), converter->squareSize()) / 2); if ((mov_type & LShaped) && origin != m_to) { mov = new KnightMovementAnimation(m_sprite.sprite(), destination, mov_type & Rotating); } else { mov = new MovementAnimation(m_sprite.sprite(), destination, mov_type & Rotating); } return AnimationPtr(mov); } case Instant: default: return AnimationPtr(new InstantAnimation(m_sprite.sprite(), converter->toReal(m_to))); } } appear::appear(const NamedSprite& sprite) : m_sprite(sprite) { } AnimationPtr appear::run(const AnimationSettings& s, const PointConverter*, AnimationType type) const { return Common::appear(s, m_sprite, type); } disappear::disappear(const NamedSprite& sprite) : m_sprite(sprite) { } AnimationPtr disappear::run(const AnimationSettings& s, const PointConverter*, AnimationType type) const { return Common::disappear(s, m_sprite, type); } destroy::destroy(const NamedSprite& sprite) : m_sprite(sprite) { } AnimationPtr destroy::run(const AnimationSettings& s, const PointConverter*, AnimationType type) const { if (!s.explode) { return Common::disappear(s, m_sprite, type); } switch (type) { case Normal: return AnimationPtr(new ExplodeAnimation(m_sprite.sprite(), Random::instance())); case Instant: default: return AnimationPtr(new CaptureAnimation(m_sprite.sprite())); } } morph::morph(const NamedSprite& sprite, const NamedSprite& new_sprite) : m_sprite(sprite) , m_new_sprite(new_sprite) { } AnimationPtr morph::run(const AnimationSettings& s, const PointConverter*, AnimationType type) const { if (!s.fading) type = Instant; switch (type) { case Normal: return AnimationPtr(new CrossFadingAnimation(m_sprite.sprite(), m_new_sprite.sprite())); case Instant: default: return AnimationPtr(new PromotionAnimation(m_sprite.sprite(), m_new_sprite.sprite())); } } namespace Pool { move::move(const NamedSprite& sprite, int to) : m_sprite(sprite) , m_to(to) { } AnimationPtr move::run(const AnimationSettings& s, const IndexConverter* converter, AnimationType type) const { if (!s.movement) type = Instant; switch (type) { case Normal: return AnimationPtr(new MovementAnimation(m_sprite.sprite(), converter->toReal(m_to))); case Instant: default: return AnimationPtr(new InstantAnimation(m_sprite.sprite(), converter->toReal(m_to))); } } appear::appear(const NamedSprite& sprite) : m_sprite(sprite) { } AnimationPtr appear::run(const AnimationSettings& s, const IndexConverter*, AnimationType type) const { return Common::appear(s, m_sprite, type); } disappear::disappear(const NamedSprite& sprite) : m_sprite(sprite) { } AnimationPtr disappear::run(const AnimationSettings& s, const IndexConverter*, AnimationType type) const { return Common::disappear(s, m_sprite, type); } } } tagua-1.0-alpha2/src/animationfactory.h000066400000000000000000000150501077523320400201330ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef ANIMATIONFACTORY_H #define ANIMATIONFACTORY_H #include "animation.h" #include "fwd.h" #include "point.h" class NamedSprite; class PointConverter; class IndexConverter; class GraphicalAPI; class AnimationSettings; namespace Animate { /** * AnimationType distinguishes between those animations which honor settings * and those that are instantaneous regardless of user preferences. */ enum AnimationType { Normal, /// Honor user settings. Instant /// Instantaneous animation. }; /** * @brief A scheme of animations. * * Animation schemes are descriptions of an animation, i.e. what the animation * should suggest to the user. The actual Animation class implementing the scheme * depends of various factors, such as the AnimationType that the animator imposes * and user settings. */ class Scheme { public: virtual ~Scheme(); /** * Convert the scheme into an actual animation which can be enqueued in the * animation system, or grouped into an AnimationGroup. */ virtual AnimationPtr run(const AnimationSettings& s, const PointConverter*, AnimationType) const = 0; }; } struct AnimationSettings { bool enabled; int maxSequence; bool movement; bool explode; bool fading; bool transform; AnimationSettings(); void reload(); }; /** * @brief A convenience wrapper around an AnimationGroup, useful for Animators. * * An AnimationFactory is a wrapper around AnimationGroup that accepts shemes instead * of Animations in its addPreAnimation() and addPostAnimation() methods. * It offers a convenient syntax to an animator when composing animations into groups. */ class AnimationFactory { AnimationGroupPtr m_group; GraphicalAPI* m_api; public: AnimationFactory(GraphicalAPI* api); /** \return The wrapped animation group. */ AnimationGroupPtr group() const; /** Change the wrapped animation group. */ void setGroup(const AnimationGroupPtr& group); /** * Add a pre-animation to the group. * \param scheme The scheme producing the animation to be added. * \param type The AnimationType to be used when creating the animation. */ void addPreAnimation(const Animate::Scheme& scheme, Animate::AnimationType type = Animate::Normal); /** * Add a post-animation to the group. * \param scheme The scheme producing the animation to be added. * \param type The AnimationType to be used when creating the animation. */ void addPostAnimation(const Animate::Scheme& scheme, Animate::AnimationType type = Animate::Normal); /** * Implicitly convert the object to an AnimationGroup shared pointer, * using the group() member function. */ operator AnimationGroupPtr() const; }; namespace Animate { /** * @brief A movement animation scheme. * * Used to animate the movement of a piece on the board to a destination square. */ class move : public Scheme { public: enum MovementType { Straight = 0x00, Rotating = 0x01, LShaped = 0x02 }; private: const NamedSprite& m_sprite; Point m_to; int m_type; public: move(const NamedSprite& sprite, const Point& to, int type = Straight); virtual AnimationPtr run(const AnimationSettings& s, const PointConverter* converter, AnimationType type) const; }; /** * @brief Appear animation scheme. * * The appear scheme visualizes a new piece coming into existence. It is * used, for example, when retracting a capture in chess, to restore the captured * piece on the chessboard. */ class appear : public Scheme { const NamedSprite& m_sprite; public: appear(const NamedSprite& sprite); virtual AnimationPtr run(const AnimationSettings& s, const PointConverter* converter, AnimationType type) const; }; /** * @brief Disappear animation scheme. * * The disappear scheme visualizes a piece being removed from the board. */ class disappear : public Scheme { const NamedSprite& m_sprite; public: disappear(const NamedSprite& sprite); virtual AnimationPtr run(const AnimationSettings& s, const PointConverter* converter, AnimationType type) const; }; /** * @brief Animation scheme destroying a piece. * * This animation scheme is used to destroy a piece, removing it from the * board. It is similar to the disappear scheme, but can provide an additional * effect like an explosion. */ class destroy : public Scheme { const NamedSprite& m_sprite; public: destroy(const NamedSprite& sprite); virtual AnimationPtr run(const AnimationSettings& s, const PointConverter* converter, AnimationType type) const; }; /** * @brief Animation scheme for changing a piece into another. * * The morph animation scheme is used when a piece changes, like in chess promotions. */ class morph : public Scheme { const NamedSprite& m_sprite; const NamedSprite& m_new_sprite; public: morph(const NamedSprite& sprite, const NamedSprite& new_sprite); virtual AnimationPtr run(const AnimationSettings& s, const PointConverter* converter, AnimationType type) const; }; /** * Animations of the pool. */ namespace Pool { class Scheme { public: virtual ~Scheme() { } virtual AnimationPtr run(const AnimationSettings& s, const IndexConverter* converter, AnimationType) const = 0; }; class move : public Scheme { const NamedSprite& m_sprite; int m_to; public: move(const NamedSprite& sprite, int to); virtual AnimationPtr run(const AnimationSettings& s, const IndexConverter*, AnimationType type) const; }; class appear : public Scheme { const NamedSprite& m_sprite; public: appear(const NamedSprite& sprite); virtual AnimationPtr run(const AnimationSettings& s, const IndexConverter*, AnimationType type) const; }; class disappear : public Scheme { const NamedSprite& m_sprite; public: disappear(const NamedSprite& sprite); virtual AnimationPtr run(const AnimationSettings& s, const IndexConverter*, AnimationType type) const; }; } } #endif // ANIMATIONFACTORY_H tagua-1.0-alpha2/src/board.cpp000066400000000000000000000503061077523320400162110ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include #include #include "mastersettings.h" #include "board.h" #include "sprite.h" #include "animation.h" #include "pointconverter.h" #include "entities/userentity.h" #include "mainanimation.h" #include "premove.h" #include "constrainedtext.h" using namespace boost; /** inherit instead of typedef to ease forward declaration :) */ class BoardTags : public std::map > > { }; Board::Board(const AnimationSettings& animSettings, KGameCanvasAbstract* parent) : ClickableCanvas(parent) , m_flipped(false) , m_square_size(0) , m_border_size(0) , m_sprites(0,0) , m_hinting_pos(Point::invalid()) , selection(Point::invalid()) , lastSelection(Point::invalid()) , m_dropped_pool(-1) , m_dropped_index(-1) , m_anim_settings(animSettings) { m_main_animation = new MainAnimation( 1.0 ); m_tags = BoardTagsPtr(new BoardTags); m_canvas_background = new KGameCanvasGroup(this); m_canvas_background->show(); m_canvas_border = new KGameCanvasGroup(this); m_canvas_border->show(); m_canvas_border_text = new KGameCanvasGroup(this); m_canvas_border_text->show(); m_pieces_group = new KGameCanvasGroup(this); m_pieces_group->show(); settingsChanged(); } Board::~Board() { delete m_pieces_group; while(!m_canvas_background->items()->isEmpty()) delete m_canvas_background->items()->first(); delete m_canvas_background; while(!m_canvas_border->items()->isEmpty()) delete m_canvas_border->items()->first(); delete m_canvas_border; delete m_main_animation; } void Board::settingsChanged() { Settings s_anim = settings().group("animations"); int speed = (s_anim["speed"] | 16); int smoothness = (s_anim["smoothness"] | 16); m_main_animation->setSpeed( 0.4*pow(10.0, speed/32.0) ); m_main_animation->setDelay( int(70.0*pow(10.0, -smoothness/32.0)) ); m_border_text_color = m_controls_loader.getStaticValue("border_color"); m_border_font = m_controls_loader.getStaticValue("border_font"); recreateBorder(); } void Board::updateBackground() { while(!m_canvas_background->items()->isEmpty()) delete m_canvas_background->items()->first(); if(!m_square_size) return; Loader::PixmapOrMap bg = m_tags_loader.getValue("background"); if(const QPixmap* p = boost::get(&bg)) { KGameCanvasTiledPixmap *t = new KGameCanvasTiledPixmap(*p, boardRect().size(), QPoint(), true, m_canvas_background); t->show(); } else if(const Loader::PixmapMap* p = boost::get(&bg)) { for(Loader::PixmapMap::const_iterator it = p->begin(); it != p->end(); ++it) { KGameCanvasTiledPixmap *t = new KGameCanvasTiledPixmap(it->second, it->first.size(), QPoint(), true, m_canvas_background); t->moveTo(it->first.topLeft()); t->show(); } } else kError() << "Board::updateBackground(): unexpected type in boost::variant!"; } void Board::enqueue(const shared_ptr& anim) { m_main_animation->addAnimation(anim); } void Board::adjustSprite(const Point& p, bool immediate) { SpritePtr sprite = m_sprites[p].sprite(); if(!sprite) return; enqueue( 1 /*BROKEN m_anim_movement*/ && !immediate ? AnimationPtr(new MovementAnimation(sprite, converter()->toReal(p), 1.0)) : AnimationPtr(new InstantAnimation(sprite, converter()->toReal(p))) ); } boost::shared_ptr Board::addTag(const QString& name, Point pt, bool over) { if(!m_sprites.valid(pt)) return boost::shared_ptr(); QPixmap p = m_tags_loader.getPixmap(name); boost::shared_ptr item = boost::shared_ptr(new KGameCanvasPixmap(p, this)); item->moveTo(converter()->toReal(pt)); if(over) item->stackOver(m_pieces_group); else item->stackUnder(m_pieces_group); item->show(); (*m_tags)[name][pt] = item; return item; } void Board::clearTags(const QString& name) { m_tags->erase(name); } void Board::clearTags() { m_tags->clear(); } void Board::setTags(const QString& name, Point p1, Point p2, Point p3, Point p4, Point p5, Point p6 ) { //TODO: maybe this could be optimized a bit clearTags(name); addTag(name, p1); addTag(name, p2); addTag(name, p3); addTag(name, p4); addTag(name, p5); addTag(name, p6); } void Board::recreateBorder() { m_border_text.clear(); while(!m_canvas_border_text->items()->isEmpty()) delete m_canvas_border_text->items()->first(); if(m_border_coords.size() == 0) return; Point s = m_sprites.getSize(); for(int w = 0; w<2; w++) for(int i = 0;ic ? m_border_coords[c] : QString(); ConstrainedText *item = new ConstrainedText(m_canvas_border_text); item->setColor(m_border_text_color); item->setText(l); item->setFont(m_border_font); item->setColor(m_border_text_color); item->show(); m_border_text.push_back(item); } for(int w = 0; w<2; w++) for(int i = 0;ic ? m_border_coords[c] : QString(); ConstrainedText *item = new ConstrainedText(m_canvas_border_text); item->setColor(m_border_text_color); item->setText(n); item->setFont(m_border_font); item->setColor(m_border_text_color); item->show(); m_border_text.push_back(item); } m_pieces_group->raise(); updateBorder(); } void Board::updateBorder() { while(!m_canvas_border->items()->isEmpty()) delete m_canvas_border->items()->first(); if(!m_square_size) return; int at = 0; for(int w = 0; w<2; w++) for(int i = 0;isetVisible(m_border_text_near != m_border_text_far); m_border_text[at]->setConstrainRect(QRect(x,y,m_square_size,m_border_text_far-m_border_text_near)); at++; } for(int w = 0; w<2; w++) for(int i = 0;isetVisible(m_border_text_near != m_border_text_far); m_border_text[at]->setConstrainRect(QRect(x-m_square_size/2,y,m_square_size,m_border_text_far-m_border_text_near)); at++; } ::LuaApi::LuaValueMap params; params["width"] = m_square_size*m_sprites.getSize().x; params["height"] = m_square_size*m_sprites.getSize().y; Loader::PixmapOrMap bord = m_controls_loader.getValue("border", ¶ms); if(const QPixmap* p = boost::get(&bord)) { KGameCanvasTiledPixmap *t = new KGameCanvasTiledPixmap(*p, boardRect().size(), QPoint(), true, m_canvas_border); t->show(); } else if(const Loader::PixmapMap* p = boost::get(&bord)) { for(Loader::PixmapMap::const_iterator it = p->begin(); it != p->end(); ++it) { KGameCanvasTiledPixmap *t = new KGameCanvasTiledPixmap(it->second, it->first.size(), QPoint(), true, m_canvas_border); t->moveTo(it->first.topLeft()); t->show(); } } else kError() << "Board::updateBorder(): unexpected type in boost::variant!"; } void Board::createGrid(Point p, const QStringList& border_coords) { m_border_coords = border_coords; m_sprites = PieceGrid(p.x,p.y); recreateBorder(); } QPixmap Board::loadSprite(const QString& id) { return m_loader.piecePixmap(id, m_flipped); } QRect Board::computeRect(Point p) const { QPoint realPoint = converter()->toReal(p); return squareRect(realPoint.x(), realPoint.y()); } QRect Board::squareRect(int x, int y) const { return QRect(x, y, m_square_size, m_square_size); } QRegion Board::computeRegion(Point p) const { return QRegion(computeRect(p)); } // selection void Board::setSelection(const Point& p) { lastSelection = selection; selection = p; setTags("selection", p); } void Board::cancelSelection() { lastSelection = selection; selection = Point::invalid(); clearTags("selection"); } // premove void Board::setPremove(const NormalUserMove& premove) { m_premove_from = premove.from; m_premove_to = premove.to; setTags("premove", m_premove_from, m_premove_to); } void Board::setPremove(const DropUserMove& premove) { m_premove_from = Point::invalid(); m_premove_to = premove.to; setTags("premove", m_premove_to); } void Board::setPremove(const Premove& premove) { setPremove(premove.toUserMove()); } void Board::cancelPremove() { m_premove_from = Point::invalid(); m_premove_to = Point::invalid(); clearTags("premove"); } void Board::updateSprites() { // adjust piece positions for (Point i = m_sprites.first(); i <= m_sprites.last(); i = m_sprites.next(i)) { boost::shared_ptr p = m_sprites[i].sprite(); if (p) { // drawing sprite p->setPixmap(loadSprite(m_sprites[i].name())); adjustSprite(i, true); } } } void Board::updateTags() { if(!m_square_size) return; for(BoardTags::iterator tit = m_tags->begin(); tit != m_tags->end(); ++tit) for(std::map >::iterator pt = tit->second.begin(); pt != tit->second.end(); ++pt) { pt->second->moveTo(converter()->toReal(pt->first)); pt->second->setPixmap(m_tags_loader.getPixmap(tit->first)); } } bool Board::doMove(const NormalUserMove& m) { if (m_entity.lock()->oneClickMoves() || m_entity.lock()->validTurn(m.from) == Moving) { AbstractMove::Ptr mv = m_entity.lock()->testMove(m); if (mv) { m_entity.lock()->executeMove(mv); return true; } } kDebug() << "invalid move"; error(InvalidMove); return false; } void Board::onResize(int new_size, int border_size, int border_text_near, int border_text_far, bool force_reload) { if(m_square_size == new_size && !force_reload) return; m_square_size = new_size; m_border_size = border_size; m_border_text_near = border_text_near; m_border_text_far = border_text_far; // update the size of the piece loader m_loader.setSize(m_square_size); // update the size of the tag loader m_tags_loader.setSize(m_square_size); // update the size of the controls loader m_controls_loader.setSize(m_border_size); // update canvas background updateBackground(); // update the sprites updateSprites(); // update piece tags updateTags(); // update border updateBorder(); } void Board::onMousePress(const QPoint& pos, int button) { Point point = converter()->toLogical(pos); if (!m_sprites.valid(point)) return; //BEGIN left click if (button == Qt::LeftButton) { if (m_entity.lock()->oneClickMoves()) { NormalUserMove m = m_entity.lock()->createMove(Point::invalid(), point); doMove(m); } else { shared_ptr piece = m_sprites[point].sprite(); if (piece && m_entity.lock()->movable(point)) { cancelSelection(); m_drag_info = DragInfoPtr(new DragInfo(point, pos, piece, m_entity.lock()->validTurn(point)) ); piece->raise(); } // if selection is valid, (pre)move to point else if (selection != Point::invalid()) { piece = m_sprites[selection].sprite(); Q_ASSERT(piece); NormalUserMove m = m_entity.lock()->createMove(selection, point); switch(m_entity.lock()->validTurn(selection)) { case Moving: doMove(m); cancelSelection(); break; case Premoving: if (m_entity.lock()->testPremove(m)) { m_entity.lock()->addPremove(m); setPremove(m); cancelSelection(); } break; default: break; } } } } //END left click //BEGIN right click else if (button == Qt::RightButton) { cancelSelection(); if (point == m_premove_from || point == m_premove_to) cancelPremove(); m_entity.lock()->handleRightClick(point); } //END right click } void Board::onMouseRelease(const QPoint& pos, int button) { Point point = converter()->toLogical(pos); //BEGIN left click if (button == Qt::LeftButton) { if (m_drag_info) { // Q_ASSERT(m_drag_info->piece); Q_ASSERT(m_drag_info->sprite); bool moved = false; // remove valid move highlighting clearTags("validmove"); // toggle selection if the piece didn't move if (m_drag_info->from == point) { if (lastSelection == point) cancelSelection(); else setSelection(point); } else { NormalUserMove m = m_entity.lock()->createMove(m_drag_info->from, point); if (!m_sprites.valid(point)) m.to = Point::invalid(); switch(m_entity.lock()->validTurn(m_drag_info->from)) { case Moving: if (doMove(m)) moved = true; break; case Premoving: if (m_entity.lock()->testPremove(m)) { m_entity.lock()->addPremove(m); setPremove(m); } break; default: break; } } shared_ptr s = m_sprites[m_drag_info->from].sprite(); if (!moved && s && s->pos() != converter()->toReal(m_drag_info->from)) { Q_ASSERT(s); QPoint real = converter()->toReal(m_drag_info->from); if( (point == m_drag_info->from) ? 0/* !m_anim_movement*/ : 0 /* !m_anim_fade*/) //BROKEN enqueue(shared_ptr(new InstantAnimation(s, real))); else if (point == m_drag_info->from) enqueue(shared_ptr(new MovementAnimation(s, real))); else enqueue(shared_ptr(new TeleportAnimation(s, s->pos(), real))); } m_drag_info = DragInfoPtr(); } } //END left button } void Board::onMouseMove(const QPoint& pos, int /*button*/) { Point point = converter()->toLogical(pos); if (m_drag_info) { Q_ASSERT(m_drag_info->sprite); // check drag threshold if (!m_drag_info->dragStarted) { QPoint delta = pos - m_drag_info->real; if (delta.x() * delta.x() + delta.y() * delta.y() > DragInfo::DRAG_THRESHOLD) { m_drag_info->dragStarted = true; } } if (m_drag_info->dragStarted) m_drag_info->sprite->moveTo(pos - QPoint(m_square_size / 2, m_square_size / 2) ); // highlight valid moves NormalUserMove move = m_entity.lock()->createMove(m_drag_info->from, point); bool valid = m_sprites.valid(point); if (valid) { InteractionType action = m_entity.lock()->validTurn(m_drag_info->from); if (action == Moving) valid = m_entity.lock()->testMove(move); } if (valid) setTags("validmove", point); else clearTags("validmove"); } else if (m_entity.lock()->oneClickMoves()) { if(point == m_hinting_pos) return; AbstractPiece::Ptr hint; if (m_sprites.valid(point)) { if (AbstractMove::Ptr move = m_entity.lock()->testMove( m_entity.lock()->createMove(Point::invalid(), point))) { // set move hint hint = m_entity.lock()->moveHint(move); } } updateHinting(point, hint); } } void Board::onPositionChanged() { if (m_entity.lock() && m_entity.lock()->oneClickMoves() && m_sprites.valid(m_hinting_pos)) { AbstractPiece::Ptr hint; if (AbstractMove::Ptr move = m_entity.lock()->testMove( m_entity.lock()->createMove(Point::invalid(), m_hinting_pos))) { // set move hint hint = m_entity.lock()->moveHint(move); } updateHinting(m_hinting_pos, hint); } } void Board::onMouseLeave() { updateHinting(Point::invalid(), AbstractPiece::Ptr()); } void Board::updateHinting(Point pt, AbstractPiece::Ptr piece) { if(!m_sprites.valid(pt)) piece = AbstractPiece::Ptr(); if(!piece || !m_sprites.valid(pt)) { if(m_hinting.sprite()) { if(1 /*BROKEN m_anim_fade*/) enqueue( boost::shared_ptr(new FadeAnimation(m_hinting.sprite(), m_hinting.sprite()->pos(), 160, 0)) ); else enqueue( boost::shared_ptr(new CaptureAnimation(m_hinting.sprite())) ); } m_hinting_pos = Point::invalid(); m_hinting = NamedSprite(); } else { if(pt == m_hinting_pos) { if(!(piece->name() == m_hinting.name())) { m_hinting = NamedSprite(piece->name(), m_hinting.sprite()); m_hinting.sprite()->setPixmap(loadSprite(piece->name())); } } else { if(m_hinting.sprite()) { if(1 /*BROKEN m_anim_fade*/) enqueue( boost::shared_ptr(new FadeAnimation(m_hinting.sprite(), m_hinting.sprite()->pos(), 160, 0)) ); else enqueue( boost::shared_ptr(new CaptureAnimation(m_hinting.sprite())) ); } QPixmap pix = loadSprite(piece->name()); SpritePtr sprite(new Sprite(pix, piecesGroup(), converter()->toReal(pt))); sprite->setOpacity(160); sprite->raise(); sprite->show(); m_hinting_pos = pt; m_hinting = NamedSprite(piece->name(), sprite); /*if(m_anim_fade) enqueue( boost::shared_ptr(new FadeAnimation(m_hinting.sprite(), m_hinting.sprite()->pos(), 0, 160)) ); else { m_hinting.sprite()->setOpacity(160); enqueue(boost::shared_ptr(new DropAnimation(m_hinting.sprite())) ); }*/ } } } void Board::reset() { clearTags(); cancelSelection(); cancelPremove(); m_main_animation->stop(); } void Board::flip(bool flipped) { if (m_flipped != flipped) { m_flipped = flipped; // update sprite positions for (Point i = m_sprites.first(); i <= m_sprites.last(); i = m_sprites.next(i)) { SpritePtr p = m_sprites[i].sprite(); if (p) { p->setPixmap(loadSprite(m_sprites[i].name())); adjustSprite(i, true); } } updateTags(); updateBorder(); } } void Board::draggingOn(int pool, int index, const QPoint& point) { Point to = converter()->toLogical(point); if (m_sprites.valid(to)) switch(m_entity.lock()->validTurn(pool)) { case Moving: { DropUserMove m = m_entity.lock()->createDrop(pool, index, to); AbstractMove::Ptr mv = m_entity.lock()->testMove(m); if (mv) { setTags("validmove", to); return; } break; } case Premoving: setTags("validmove", to); return; default: break; } clearTags("validmove"); } bool Board::dropOn(int pool, int index, const QPoint& point) { Point to = converter()->toLogical(point); if (!m_sprites.valid(to)) return false; clearTags("validmove"); switch(m_entity.lock()->validTurn(pool)) { case Moving: { DropUserMove m = m_entity.lock()->createDrop(pool, index, to); AbstractMove::Ptr mv = m_entity.lock()->testMove(m); if (mv) { m_entity.lock()->executeMove(mv); return true; } break; } case Premoving: { DropUserMove m = m_entity.lock()->createDrop(pool, index, to); if (m_entity.lock()->testPremove(m)) { m_entity.lock()->addPremove(m); setPremove(m); } break; } default: break; } kDebug() << "invalid move"; error(InvalidMove); return false; } tagua-1.0-alpha2/src/board.h000066400000000000000000000212201077523320400156470ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef BOARD_H #define BOARD_H #include #include #include #include #include #include "kgamecanvas.h" #include "entities/userentity.h" #include "common.h" #include "grid.h" #include "usermove.h" #include "mainanimation.h" #include "pointconverter.h" #include "pixmaploader.h" #include "clickablecanvas.h" #include "namedsprite.h" class DragInfo; class Animation; class UserEntity; class ConstrainedText; class AnimationSettings; class BoardTags; typedef boost::shared_ptr BoardTagsPtr; /** * @class Board * @brief Board visualization class * * This class is a KGameCanvasItem that displaying a board filled with pieces. * You can set custom tags for each square. * @sa Table, @sa PiecePool, @sa Sprite */ class Board : public QObject, public ClickableCanvas, protected PointConverter { Q_OBJECT public: friend class GraphicalSystem; friend class PiecePool; typedef Grid PieceGrid; private: class DragInfo { public: static const int DRAG_THRESHOLD = 100; // pixels ^ 2 boost::shared_ptr sprite; Point from; // logical coordinates QPoint real; /// real starting point, used to honor drag threshold bool dragging; bool dragStarted; bool droppedOut; InteractionType action; DragInfo(Point from, const QPoint& real, const boost::shared_ptr& sprite, InteractionType action) : sprite(sprite) , from(from) , real(real) , dragging(false) , dragStarted(false) , droppedOut(false) , action(action) {} }; typedef boost::shared_ptr DragInfoPtr; /** true if the board is flipped */ bool m_flipped; /** size of a square in points */ int m_square_size; /** size of the border */ int m_border_size; /** margin for text */ int m_border_text_near; /** far margin for text */ int m_border_text_far; /** loader class, to load pieces */ PixmapLoader m_loader; /** main animation structure */ MainAnimation* m_main_animation; /** the piece being dragged */ DragInfoPtr m_drag_info; /** displayed m_sprites */ PieceGrid m_sprites; /** the visual move hint */ NamedSprite m_hinting; Point m_hinting_pos; /** the canvas group that holds the pieces */ KGameCanvasGroup *m_pieces_group; /** the canvas item that holds the background of the board */ KGameCanvasGroup *m_canvas_background; /** the canvas item that holds board border */ KGameCanvasGroup *m_canvas_border; /** the canvas item that holds board border text */ KGameCanvasGroup *m_canvas_border_text; /** all the tags on the board */ BoardTagsPtr m_tags; /** the @a PixmapLoader used to create tags */ PixmapLoader m_tags_loader; /** the @a PixmapLoader used for controls */ PixmapLoader m_controls_loader; /** the entity responsible of all the interctions with the board */ boost::weak_ptr m_entity; /** The currently selected square */ Point selection; /** The reviously selected square */ Point lastSelection; /** premove */ Point m_premove_from; Point m_premove_to; QColor m_border_text_color; QFont m_border_font; QStringList m_border_coords; int m_dropped_pool; int m_dropped_index; const AnimationSettings& m_anim_settings; /** the text items for the border */ std::vector m_border_text; /** this internal function updates the background after the board has been resized */ void updateBackground(); /** this internal function updates the border after the board has been resized */ void updateBorder(); /** this internal function creates a new border, if needed */ void recreateBorder(); void updateHinting(Point pt, AbstractPiece::Ptr piece); /** this internal function updates the sprites after the board has been resized */ void updateSprites(); /** this internal function updates the tags after the board has been resized */ void updateTags(); void setPremove(const NormalUserMove& move); void setPremove(const DropUserMove& move); void setPremove(const class Premove& move); void updatePremove(); void setSelection(const Point& p); QRect computeRect(Point) const; QRegion computeRegion(Point) const; QRect squareRect(int x, int y) const; /** this function tries to notify the move to the entity */ bool doMove(const NormalUserMove&); public: /** constructor, requires the canvas parent */ Board(const AnimationSettings& animSettings, KGameCanvasAbstract* parent); ~Board(); /** set the board flipping */ void flip(bool flipped); /** flips the board */ void flip() { flip(!m_flipped); } /** returns the flipped value */ bool flipped() const { return m_flipped; } /** returns the size of a square */ int squareSize() const { return m_square_size; } /** returns the area covered by the piece grid */ QRect boardRect() { return QRect(pos(), QSize(m_square_size*gridSize().x, m_square_size*gridSize().y)); } /** returns the size of the grid */ Point gridSize() const { return m_sprites.getSize(); } /** recreates the board underlying grid */ void createGrid(Point p, const QStringList& border_coords); /** return the group that contains the pieces */ KGameCanvasAbstract* piecesGroup() { return m_pieces_group; } /** returns the point converter class */ PointConverter* converter() { return static_cast(this); } /** returns the point converter class */ const PointConverter* converter() const { return static_cast(this); } /** returns the sprite loader */ PixmapLoader* loader() { return &m_loader; } /** Load a sprite using the sprite loader */ QPixmap loadSprite(const QString& id); /** returns the sprite loader */ const PixmapLoader* loader() const { return &m_loader; } /** adds a tag with name name, the tag will stay over the pieces if over is true */ boost::shared_ptr addTag(const QString& name, Point at, bool over=false); /** clears the tags with name name */ void clearTags(const QString& name); /** clears all the tags */ void clearTags(); /** clear all the tags twith name name, than sets them to the valid given ones */ void setTags(const QString& name, Point p1 = Point::invalid(), Point p2 = Point::invalid(), Point p3 = Point::invalid(), Point p4 = Point::invalid(), Point p5 = Point::invalid(), Point p6 = Point::invalid() ); /** returns a reference to the loader used to load tag pixmaps */ PixmapLoader* tagsLoader() { return &m_tags_loader; } /** returns a reference to the loader used to load controls pixmaps */ PixmapLoader* controlsLoader() { return &m_controls_loader; } void cancelPremove(); void cancelSelection(); /** enqueue an animation */ void enqueue(const boost::shared_ptr&); /** Brings the sprite to its correct position */ void adjustSprite(const Point& p, bool immediate = false); /** sets the controlling entity */ inline void setEntity(const boost::shared_ptr& entity) { m_entity = entity; } /** Notifies to the board that a certain piece is being dragged over the board */ void draggingOn(int pool, int index, const QPoint& p); /** Executes a drop. This function id typically called by by a PiecePool */ bool dropOn(int pool, int index, const QPoint& point); /** mouse release event */ virtual void onMouseRelease(const QPoint& pos, int button); /** mouse press event */ virtual void onMousePress(const QPoint& pos, int button); /** mouse move event */ virtual void onMouseMove(const QPoint& pos, int button); /** mouse leave event */ virtual void onMouseLeave(); /** resize event (new_size is the new size of a SQUARE) */ virtual void onResize(int new_size, int border_size, int border_text_near, int border_text_far, bool force_reload = false); /** the position changed (will update the move highlighting) */ virtual void onPositionChanged(); /** changed settings handler */ virtual void settingsChanged(); /** resets all tags and stops all animations */ void reset(); Q_SIGNALS: void error(ErrorCode code); }; #endif //BOARD_H tagua-1.0-alpha2/src/chesstable.cpp000066400000000000000000000234311077523320400172360ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include "chesstable.h" #include "game.h" #include "gameinfo.h" #include "connection.h" #include "piecepool.h" #include "clock.h" #include "mastersettings.h" #include "movelist_table.h" #include "infodisplay.h" using namespace boost; ChessTable::ChessTable(QWidget* parent) : KGameCanvasWidget(parent) , m_wallpaper(NULL) , m_current(NULL) , m_mousegrab(NULL) , m_need_reload(false) { setMouseTracking(true); // create m_board m_board = new Board(m_anim_settings, this); m_board->show(); // create move list m_movelist = new MoveList::Table; // create clocks for(int i=0;i<2;i++) { m_clocks[i] = new Clock(i, this); m_clocks[i]->show(); } m_clocks[0]->activate(0); // create info display m_info = new InfoDisplay(this); // m_info->show(); // create pools for(int i=0;i<2;i++) { m_pools[i] = new PiecePool(i, m_board, m_anim_settings, this); m_pools[i]->show(); } m_board->raise(); settingsChanged(); } ChessTable::~ChessTable() { for(int i=0;i<2;i++) delete m_clocks[i]; delete m_movelist; delete m_board; for(int i=0;i<2;i++) delete m_pools[i]; delete m_info; } void ChessTable::renderWallpaper() { if (!m_background_pixmap.isNull()) { QPixmap bg = m_background_pixmap; // scale & crop background double ratio_x = (double) width() / m_background_pixmap.width(); double ratio_y = (double) height() / m_background_pixmap.height(); if (ratio_x > ratio_y) bg = bg.scaledToWidth(width(), Qt::SmoothTransformation); else bg = bg.scaledToHeight(height(), Qt::SmoothTransformation); QSize size(width(), height()); QImage res(size, QImage::Format_ARGB32_Premultiplied); { QPoint pos( (bg.width() - width()) / 2, (bg.height() - height()) / 2); kDebug() << "img size" << bg.size(); kDebug() << "size" << size; kDebug() << "pos" << pos; QPainter p(&res); p.drawPixmap(QPoint(0,0), bg, QRectF(pos, size)); } bg = QPixmap::fromImage(res); if (m_wallpaper) { m_wallpaper->setPixmap(bg); } else { delete m_wallpaper; m_wallpaper = new KGameCanvasPixmap(QPixmap::fromImage(res), this); m_wallpaper->lower(); m_wallpaper->show(); } } else { delete m_wallpaper; m_wallpaper = 0; } } void ChessTable::settingsChanged() { m_anim_settings.reload(); m_board->settingsChanged(); for(int i=0;i<2;i++) m_clocks[i]->settingsChanged(); m_info->settingsChanged(); for(int i=0;i<2;i++) m_pools[i]->settingsChanged(); m_background_pixmap = m_board->controlsLoader()->getStaticValue("wallpaper", 0, true); renderWallpaper(); /* redo the layout, forcing reload */ if(isVisible()) layout(true); else m_need_reload = true; } ClickableCanvas* ChessTable::eventItemAt(QPoint pos) { if (m_board->boardRect().contains(pos)) return m_board; for (int i=0; i<2; i++) if (m_pools[i]->boardRect().contains(pos)) return m_pools[i]; for (int i=0; i<2; i++) if (m_clocks[i]->rect().contains(pos)) return m_clocks[i]; return NULL; } void ChessTable::setEntity(const boost::shared_ptr& entity) { m_board->setEntity(entity); } void ChessTable::layout(bool force_reload) { force_reload |= m_need_reload; m_need_reload = false; renderWallpaper(); ::LuaApi::LuaValueMap params; params["width"] = width(); params["height"] = height(); params["grid_size"] = QPointF(m_board->gridSize()); ::LuaApi::LuaValueMap lvals = m_board->controlsLoader()->getStaticValue< ::LuaApi::LuaValueMap>("layout", ¶ms); #if 0 for(::LuaApi::LuaValueMap::iterator it = lvals.begin(); it != lvals.end(); ++it) if(double* val = boost::get(&it.value())) kDebug() << "lvals[" << it.key() << "] = " << *val; else if(QPointF* val = boost::get(&it.value())) kDebug() << "lvals[" << it.key() << "] = Point(" << val->x() << "," << val->y() << ")"; else if(QRectF* val = boost::get(&it.value())) kDebug() << "lvals[" << it.key() << "] = Rect(" << val->x() << "," << val->y() << "," << val->width() << "," << val->height() << ")"; #endif #define GET_INT(name) \ int name = 0; \ {::LuaApi::LuaValueMap::iterator it = lvals.find(#name);\ if(double* val = (it==lvals.end()) ? 0 : boost::get(&lvals[#name]) ) \ name = (int)*val; \ else \ kError() << "Theme error:" << #name << "should be set to a number in the layout";} #define GET_POINT(name) \ QPoint name; \ {::LuaApi::LuaValueMap::iterator it = lvals.find(#name);\ if(QPointF* val = (it==lvals.end()) ? 0 : boost::get(&lvals[#name]) ) \ name = val->toPoint(); \ else \ kError() << "Theme error:" << #name << "should be set to a point in the layout";} GET_POINT(board_position); GET_INT(square_size); GET_INT(border_size); GET_INT(border_text_near); GET_INT(border_text_far); GET_POINT(clock0_position); GET_POINT(clock1_position); GET_INT(clock_size); GET_POINT(pool0_position); GET_POINT(pool1_position); GET_INT(pool_piece_size); GET_INT(pool_width); m_board->moveTo(board_position.x(), board_position.y()); m_board->onResize( square_size, border_size, border_text_near, border_text_far, force_reload); int x = !m_board->flipped(); m_clocks[x]->resize(clock_size); m_clocks[x]->moveTo(clock0_position.x(), clock0_position.y()); // kDebug() << "moving clock " << x << " to " << clock0_position.y(); m_clocks[!x]->resize(clock_size); m_clocks[!x]->moveTo(clock1_position.x(), clock1_position.y()); // kDebug() << "moving clock " << !x << " to " << clock1_position.y(); m_pools[x]->m_flipped = false; m_pools[x]->onResize(pool_piece_size, force_reload); m_pools[x]->moveTo(pool0_position.x(), pool0_position.y()); m_pools[x]->setGridWidth(pool_width); m_pools[!x]->m_flipped = true; m_pools[!x]->onResize(pool_piece_size, force_reload); m_pools[!x]->moveTo(pool1_position.x(), pool1_position.y()); m_pools[!x]->setGridWidth(pool_width); } void ChessTable::resizeEvent(QResizeEvent* /*e*/) { layout(); } void ChessTable::mouseReleaseEvent(QMouseEvent* e) { if(m_mousegrab) { m_mousegrab->onMouseRelease(e->pos() - m_mousegrab->pos(), e->button() ); if(!e->buttons()) { m_mousegrab = NULL; ClickableCanvas* cb = eventItemAt(e->pos()); if(cb != m_current) { if(m_current) m_current->onMouseLeave(); if(cb) { cb->onMouseEnter(); cb->onMouseMove(e->pos() - cb->pos(), 0); } m_current = cb; } } return; } } void ChessTable::mousePressEvent(QMouseEvent* e) { if(m_mousegrab) { m_mousegrab->onMousePress(e->pos() - m_mousegrab->pos(), e->button() ); return; } ClickableCanvas* cb = eventItemAt(e->pos()); if(cb != m_current) { if(m_current) m_current->onMouseLeave(); if(cb) cb->onMouseEnter(); m_current = cb; } if(cb) { cb->onMousePress(e->pos() - cb->pos(), e->button() ); m_mousegrab = cb; } } void ChessTable::mouseMoveEvent(QMouseEvent* e) { if(m_mousegrab) { m_mousegrab->onMouseMove(e->pos() - m_mousegrab->pos(), e->button() ); return; } ClickableCanvas* cb = eventItemAt(e->pos()); if(cb != m_current) { if(m_current) m_current->onMouseLeave(); if(cb) cb->onMouseEnter(); m_current = cb; } if(cb) cb->onMouseMove(e->pos() - cb->pos(), e->button() ); } void ChessTable::enterEvent(QEvent*) { } void ChessTable::leaveEvent(QEvent*) { if(m_current) m_current->onMouseLeave(); m_current = NULL; } void ChessTable::flip() { m_board->flip(); int delta = qAbs(m_pools[0]->pos().y() - m_pools[1]->pos().y()); for(int i=0;i<2;i++) m_pools[i]->flipAndMoveBy( QPoint(0, delta) ); // flip clocks QPoint pos = m_clocks[0]->pos(); m_clocks[0]->moveTo(m_clocks[1]->pos()); m_clocks[1]->moveTo(pos); } void ChessTable::flip(bool flipped) { if(m_board->flipped() != flipped) flip(); } void ChessTable::changeClock(int color) { if(m_clocks[0]->running() || m_clocks[1]->running()) for(int i=0;i<2;i++) { if ( (i == color) != m_clocks[i]->running() ) if( i==color ) m_clocks[i]->start(); else m_clocks[i]->stop(); } } void ChessTable::updateTurn(int color) { for(int i=0; i<2; i++) m_clocks[i]->activate(color == i); } void ChessTable::stopClocks() { for(int i=0; i<2; i++) m_clocks[i]->stop(); } void ChessTable::updateTime(int white, int black) { m_clocks[0]->setTime(white); m_clocks[1]->setTime(black); } void ChessTable::resetClock() { stopClocks(); updateTime(0, 0); for(int i=0; i<2; i++) m_clocks[i]->setPlayer(Player()); } void ChessTable::setPlayers(const Player& white, const Player& black) { m_clocks[0]->setPlayer(white); m_clocks[1]->setPlayer(black); } void ChessTable::run() { for(int i=0;i<2;i++) if(m_clocks[i]->active() && !m_clocks[i]->running()) m_clocks[i]->start(); } void ChessTable::displayMessage(const QString& msg) { kDebug() << msg; message(msg); } const AnimationSettings& ChessTable::animationSettings() const { return m_anim_settings; } tagua-1.0-alpha2/src/chesstable.h000066400000000000000000000047411077523320400167060ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef CHESSTABLE_H #define CHESSTABLE_H #include #include #include "kgamecanvas.h" #include "positioninfo.h" #include "board.h" #include "common.h" #include "animationfactory.h" class PiecePool; class Player; class Clock; class InfoDisplay; namespace MoveList { class Table; } namespace Canvas { class TiledPixmap; } class ChessTable : public KGameCanvasWidget { Q_OBJECT KGameCanvasPixmap* m_wallpaper; QPixmap m_background_pixmap; Clock* m_clocks[2]; Board* m_board; PiecePool* m_pools[2]; MoveList::Table* m_movelist; InfoDisplay* m_info; ClickableCanvas* m_current; ClickableCanvas* m_mousegrab; bool m_need_reload; ClickableCanvas* eventItemAt(QPoint pos); void layout(bool force_reload = false); void renderWallpaper(); AnimationSettings m_anim_settings; public: ChessTable(QWidget* parent = 0); ~ChessTable(); inline Board* board() const { return m_board; } inline PiecePool* pool(int index) const { return m_pools[index]; } inline MoveList::Table* moveListTable() const { return m_movelist; } inline Clock* clock(int index) const { return m_clocks[index]; } inline InfoDisplay* info() const { return m_info; } void flip(bool); void flip(); void run(); void stopClocks(); void setEntity(const boost::shared_ptr& entity); void displayMessage(const QString&); virtual void resizeEvent(QResizeEvent*); virtual void mouseReleaseEvent(QMouseEvent*); virtual void mousePressEvent(QMouseEvent*); virtual void mouseMoveEvent(QMouseEvent*); virtual void enterEvent (QEvent * event); virtual void leaveEvent (QEvent * event); void settingsChanged(); //called by GraphicalInfo, for better theme change const AnimationSettings& animationSettings() const; public Q_SLOTS: void updateTurn(int color); void changeClock(int color); void updateTime(int white, int black); void setPlayers(const Player&, const Player&); void resetClock(); Q_SIGNALS: void message(const QString&); void error(ErrorCode); }; #endif // CHESSTABLE_H tagua-1.0-alpha2/src/clickablecanvas.h000066400000000000000000000016051077523320400176720ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef CLICKABLECANVAS_H #define CLICKABLECANVAS_H #include "kgamecanvas.h" class ClickableCanvas : public KGameCanvasGroup { public: ClickableCanvas(KGameCanvasAbstract* canvas = NULL) : KGameCanvasGroup(canvas) { } virtual void onMousePress(const QPoint& point, int button) = 0; virtual void onMouseMove(const QPoint& point, int button) = 0; virtual void onMouseRelease(const QPoint& point, int button) = 0; virtual void onMouseEnter() {} virtual void onMouseLeave() {} }; #endif // CLICKABLECANVAS_H tagua-1.0-alpha2/src/clock.cpp000066400000000000000000000115001077523320400162060ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "clock.h" #include "constrainedtext.h" #include #include Clock::Clock(int col, KGameCanvasAbstract* canvas) : ClickableCanvas(canvas) , m_color(col) , m_running(false) { m_background = new KGameCanvasPixmap(this); m_caption = new ConstrainedText(this); m_time_label = new ConstrainedText(this); m_player_name = new ConstrainedText(this); m_decs = new ConstrainedText(this); m_background->show(); m_caption->show(); m_time_label->show(); m_player_name->show(); setTime(0); setPlayer(Player()); m_caption->setText(col == 0 ? "White" : "Black"); connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick())); } Clock::~Clock() { delete m_background; delete m_caption; delete m_time_label; delete m_player_name; delete m_decs; } void Clock::start() { m_running = true; m_time.start(); m_timer.start(100); } void Clock::stop() { if (m_running) m_total_time -= m_time.elapsed(); m_running = false; m_timer.stop(); } void Clock::activate(bool a) { if(m_active == a) return; m_active = a; m_background->setPixmap(m_active ? m_active_pixmap : m_inactive_pixmap); m_time_label->setColor(m_active ? m_active_text : m_inactive_text); m_player_name->setColor(m_active ? m_active_text : m_inactive_text); m_caption->setColor(m_active ? m_active_text : m_inactive_text); } void Clock::tick() { computeTime(); } void Clock::computeTime() { int time = m_total_time; if (m_running) time -= m_time.elapsed(); bool positive; int total_secs; int decs = -1; if (time > 0 && time < 10000) { int total_decs = static_cast(ceil(time / 100.0)); positive = total_decs >= 0; if (!positive) total_decs = -total_decs; decs = total_decs % 10; total_secs = total_decs / 10; } else { total_secs = static_cast(ceil(time / 1000.0)); positive = total_secs >= 0; if (!positive) total_secs = -total_secs; } int secs = total_secs % 60; int mins = total_secs / 60; QString timeText; { QString secText = QString::number(secs); if (secText.length() < 2) secText = "0" + secText; QString minText = QString::number(mins); if (minText.length() < 2) minText = "0" + minText; timeText = minText + ":" + secText; if (!positive) timeText = "-" + timeText; #if 0 if (positive && decs != -1) { int dec = static_cast(ceil(time / 100.0)) % 10; m_decs->moveTo(m_time_label->rect().bottomRight() + QPoint(2, 0)); m_decs->setText(":" + QString::number(dec)); m_decs->show(); } else m_decs->hide(); #endif } m_time_label->setText(timeText); } QString Clock::playerString(const Player& player) { QString rating = player.rating != -1 ? QString(" (%1)").arg(player.rating) : QString(); return QString("%1").arg(player.name) + rating; } void Clock::setPlayer(const Player& player) { m_player_name->setText(playerString(player)); } void Clock::setTime(int t) { m_total_time = t; tick(); } void Clock::onMousePress(const QPoint& /*pos*/, int /*button*/) { } void Clock::resize(int size) { m_controls_loader.setSize(size); m_height = (int)m_controls_loader.getValue("clock_height"); m_active_pixmap = m_controls_loader.getValue("clock_active_background"); m_inactive_pixmap = m_controls_loader.getValue("clock_inactive_background"); m_active_text = m_controls_loader.getValue("clock_active_text").color(); m_inactive_text = m_controls_loader.getValue("clock_inactive_text").color(); m_background->setPixmap(m_active ? m_active_pixmap : m_inactive_pixmap); m_background->moveTo(m_controls_loader.getValue("clock_background_offset").toPoint()); m_time_label->setConstrainRect(m_controls_loader.getValue("clock_time_rect").toRect()); m_time_label->setColor(m_active ? m_active_text : m_inactive_text); m_player_name->setConstrainRect(m_controls_loader.getValue("clock_player_rect").toRect()); m_player_name->setColor(m_active ? m_active_text : m_inactive_text); m_caption->setConstrainRect(m_controls_loader.getValue("clock_caption_rect").toRect()); m_caption->setColor(m_active ? m_active_text : m_inactive_text); } void Clock::settingsChanged() { m_caption->setFont(m_controls_loader.getStaticValue("clock_caption_font")); m_player_name->setFont(m_controls_loader.getStaticValue("clock_player_font")); m_time_label->setFont(m_controls_loader.getStaticValue("clock_time_font")); } tagua-1.0-alpha2/src/clock.h000066400000000000000000000037071077523320400156650ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef CLOCK_H #define CLOCK_H #include #include #include #include "kgamecanvas.h" #include "player.h" #include "pixmaploader.h" #include "clickablecanvas.h" class ConstrainedText; class Clock : public QObject, public ClickableCanvas { Q_OBJECT int m_color; QTimer m_timer; QTime m_time; int m_total_time; bool m_running; bool m_active; KGameCanvasPixmap* m_background; ConstrainedText* m_caption; ConstrainedText* m_time_label; ConstrainedText* m_player_name; ConstrainedText* m_decs; QPixmap m_active_pixmap; QPixmap m_inactive_pixmap; QColor m_active_text; QColor m_inactive_text; int m_height; /** the @a PixmapLoader used for controls */ PixmapLoader m_controls_loader; void computeTime(); static QString playerString(const Player& player); public: Clock(int col, KGameCanvasAbstract* canvas); ~Clock(); /** returns a reference to the loader used to load controls pixmaps */ PixmapLoader* controlsLoader() { return &m_controls_loader; } bool running() { return m_running; } void start(); void stop(); bool active() { return m_active; } void activate(bool); void setPlayer(const Player& p); void setTime(int t); virtual void onMousePress(const QPoint& pos, int button); virtual void onMouseRelease(const QPoint& /*pos*/, int /*button*/) { } virtual void onMouseMove(const QPoint& /*pos*/, int /*button*/) { } void resize(int size); int height() { return m_height; } void settingsChanged(); private Q_SLOTS: void tick(); Q_SIGNALS: void labelClicked(int); }; #endif // CLOCK_H tagua-1.0-alpha2/src/common.cpp000066400000000000000000000016001077523320400164030ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "common.h" #include namespace boost { // throw exception: used by boost void throw_exception(std::exception const &) { kError() << "[bug] boost exception"; } } #ifdef Q_CC_GNU #include #include #endif //Q_CC_GNU QString prettyTypeName(const char* name) { #ifdef Q_CC_GNU int s; const char* res = abi::__cxa_demangle(name, NULL, NULL, &s); if(res) { QString retv(res); free((void*)res); return retv; } #endif //Q_CC_GNU return QString(name); } tagua-1.0-alpha2/src/common.h000066400000000000000000000011501077523320400160500ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef COMMON_H #define COMMON_H #include "export.h" #include class QString; enum ErrorCode { InvalidMove }; QString prettyTypeName(const char* name); #ifndef M_PI #define M_PI 3.1415926 #endif #endif // COMMON_H tagua-1.0-alpha2/src/config.xsd000066400000000000000000000215501077523320400164020ustar00rootroot00000000000000 tagua-1.0-alpha2/src/connection.cpp000066400000000000000000000074661077523320400172720ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "connection.h" #include #include #include #include #include #include #include #include "common.h" #include "settings.h" Connection::Connection() : m_device(NULL) , m_connected(false) , m_initialized(false) { QString logFileName; if (!logFileName.isEmpty()) { logFile = new QFile(logFileName); logFile->open(QIODevice::WriteOnly); logStream = 0; //= new QTextStream(logFile); } else logStream = 0; } Connection::~Connection() { if (logStream) { delete logStream; logFile->close(); delete logFile; } if (m_device) { KProcess* p = qobject_cast(m_device); if (p) p->kill(); delete m_device; } } void Connection::establish(const char* host, quint16 port, const QString& helper, const QString& helper_cmd) { if (m_device) { KProcess* p = qobject_cast(m_device); if (p) p->kill(); delete m_device; } strncpy(m_host, host, 256); m_port = port; m_helper = helper; m_helper_cmd = helper_cmd; if (helper.isEmpty()) { QTcpSocket *s = new QTcpSocket(this); s->setObjectName("IcsSocket"); connect(s, SIGNAL(hostFound()), this, SIGNAL(hostFound())); connect(s, SIGNAL(connected()), this, SIGNAL(established())); hostLookup(); s->connectToHost(m_host, m_port); m_device = s; m_connected = true; } else { m_device = new KProcess(this); m_device->setObjectName("IcsHelper"); if (m_helper_cmd.contains("$(HOST_IP)")) { QHostInfo::lookupHost(m_host, this, SLOT(lookedUp(const QHostInfo))); } else { lookedUp(QHostInfo()); } } connect(m_device, SIGNAL(readyRead()), this, SLOT(processLine())); } void Connection::lookedUp(const QHostInfo &hi) { KProcess* p = m_device ? qobject_cast(m_device) : NULL; if (p) { QString args = m_helper_cmd; args.replace("$(HOST_NAME)", QString(m_host) ); args.replace("$(HOST_IP)", hi.addresses().isEmpty() ? QString() : hi.addresses().first().toString () ); args.replace("$(PORT)", QString::number(m_port)); p->setOutputChannelMode(KProcess::OnlyStdoutChannel); p->setProgram(m_helper, args.split(' ')); p->start(); m_connected = true; if(!m_unsent_text.isEmpty()) { QTextStream os(m_device); os << m_unsent_text; if (logStream) (*logStream) << "> " << m_unsent_text; m_unsent_text = QString(); } } } void Connection::processLine() { if(!m_device) { kError() << "No device"; return; } while (m_device->canReadLine()) { QString line = m_device->readLine(); line = buffer + line.replace("\r", ""); receivedLine(line, buffer.length()); if (logStream) (*logStream) << "< " << line << "\n"; buffer = ""; } int size; if ((size = m_device->bytesAvailable()) > 0) { char* data = new char[size + 1]; m_device->read(data, size); data[size] = '\0'; int offset = buffer.length(); buffer += QString(data).replace("\r", ""); delete[] data; receivedText(buffer, offset); } } void Connection::sendText(const QString& text) { if(!m_connected) { m_unsent_text += text + "\n"; return; } if(!m_device) { kDebug() << "No device"; return; } processLine(); QTextStream os(m_device); os << text << "\n"; if (logStream) (*logStream) << "> " << text << "\n"; } tagua-1.0-alpha2/src/connection.h000066400000000000000000000064401077523320400167260ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef CONNECTION_H #define CONNECTION_H #include class QTextStream; class QIODevice; class QFile; class QHostInfo; /** * @brief Manage a connection with a remote server. * * This class can be used to manage a connection with a chess server. Once connected, * it emits the signal @ref receivedLine whenever a new whole line is received. * Partial lines are kept in an internal buffer. * The Connection class supports the use of a helper such as timeseal. */ class Connection : public QObject { Q_OBJECT QIODevice* m_device; QString buffer; QFile* logFile; QTextStream* logStream; bool m_connected; bool m_initialized; QString m_unsent_text; char m_host[256]; quint16 m_port; QString m_helper; QString m_helper_cmd; public: /** * Create a new connection object. No actual connection is made * until @ref establish is called. */ Connection(); /** * Destroy the object and kill the helper, if present. */ virtual ~Connection(); /** * Create an actual connection to an internet host. * @param host Fully qualified name of the host. * @param port Host port to connect to. * @param helper Full path of a helper. A null or empty string if no helper is needed. * @param args Helper arguments. They can optionally contain variabiles which will be expaded * before they are passed to the helper. * Supported variables: $(HOST_NAME), $(HOST_IP), $(PORT). */ void establish(const char* host, quint16 port, const QString& helper, const QString& args); /** * Whether the connection has been initialized. */ inline bool initialized() const { return m_initialized; } /** * Set the inizialized flag of the connection. Use this after you have * sent initial commands. */ inline void setInitialized() { m_initialized = true; } public Q_SLOTS: /** * Send some text to the server using the connection. A newline will be sent afterwards. */ void sendText(const QString&); void lookedUp(const QHostInfo &host); protected Q_SLOTS: /** * Read data from the socket and appropriate signals. */ void processLine(); Q_SIGNALS: void hostLookup(); void hostFound(); void established(); /** * Emitted when a partial line is received. * * @param text Received text. * @param newDataOffset Offset where new data starts. * @note Whenever a partial line is received, is it recorded in an internal buffer, * and an offset is incremented, to distinguish new data from old data * as the next payload arrives. */ void receivedText(QString text, int newDataOffset); /** * Emitted when a full line is received. * * @param line Received line. * @param newDataOffset Offset where new data starts. * * @sa receivedText */ void receivedLine(QString line, int newDataOffset); }; #endif // CONNECTION_H tagua-1.0-alpha2/src/console.cpp000066400000000000000000000174341077523320400165710ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "console.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "foreach.h" #include "histlineedit.h" #include "highlighter.h" #include "mastersettings.h" class BackInserterPatternIteratorAdaptor : public PatternListAdaptorOutputIterator { std::vector& m_vector; public: BackInserterPatternIteratorAdaptor(std::vector& vector) : m_vector(vector) { } virtual void add(const Highlighter::Pattern& p) { m_vector.push_back(p); } }; ConsoleOutput::ConsoleOutput(QTextEdit* edit, bool force_scroll) : m_edit(edit) { m_old_val = m_edit->verticalScrollBar()->value(); m_scroll_to = force_scroll || (m_edit->verticalScrollBar()->value() >= m_edit->verticalScrollBar()->maximum() ); QTextCursor cursor = m_edit->textCursor(); cursor.movePosition(QTextCursor::End); m_edit->setTextCursor(cursor); } ConsoleOutput::~ConsoleOutput() { if(m_scroll_to) m_edit->verticalScrollBar()->setValue(m_edit->verticalScrollBar()->maximum()); else m_edit->verticalScrollBar()->setValue(m_old_val); //m_edit->ensureCursorVisible(); } void ConsoleOutput::operator()(const QString& text) { m_edit->insertPlainText(text); } LuaConsoleHighlighter::LuaConsoleHighlighter() : m_display(0) { KStandardDirs* dirs = KGlobal::dirs(); QString luaHighlightingLibrary = dirs->locate("appdata", "scripts/hllib.lua"); kDebug() << "lua lib: " << luaHighlightingLibrary; m_api.runFile(qPrintable(luaHighlightingLibrary)); QStringList highlighting = dirs->findAllResources("appdata", "highlighting/*.lua", KStandardDirs::Recursive); foreach (QString f, highlighting) { kDebug() << "lua highlighting file: " << f; m_api.runFile(qPrintable(f)); } } void LuaConsoleHighlighter::setDisplay(QTextEdit* display) { m_display = display; } LuaConsoleHighlighter::Executor::Executor(QTextEdit* display, ConsoleOutput& output) : m_display(display) , m_output(output) { } void LuaConsoleHighlighter::Executor::writeChunk(const QString& text) { m_output(text); } void LuaConsoleHighlighter::Executor::setFormat(const QTextCharFormat& format) { m_display->setCurrentCharFormat(format); } LuaConsoleHighlighter::Executor::~Executor() { // m_output("\n"); } void LuaConsoleHighlighter::operator()(const QString& text, ConsoleOutput& output) { QStringList lines = text.split('\n'); for (int i = 0; i < lines.size(); i++) { const QString& line = lines[i]; boost::scoped_ptr hline(m_api.highlight(line)); if (hline) { Executor executor(m_display, output); hline->run(executor); if (i < lines.size() - 1) output("\n"); } } } #if 0 ConsoleHighlighter::ConsoleHighlighter() : m_display(0) { BackInserterPatternIteratorAdaptor out(m_patterns); Highlighter::load(out); } void ConsoleHighlighter::setDisplay(QTextEdit* display) { m_display = display; m_basic_format = m_display->currentCharFormat(); } void ConsoleHighlighter::operator()(const QString& text, ConsoleOutput& output) { Q_ASSERT(m_display); int offset = 0; m_display->setCurrentCharFormat(m_basic_format); while (true) { int best = -1; int best_offset = -1; int best_length = 0; // try each pattern and find the closest matching one for (uint i = 0; i < m_patterns.size(); i++) { int match_offset = text.indexOf(m_patterns[i].pattern, offset); if (match_offset >= 0 && (best_offset == -1 || match_offset < best_offset)) { int length = m_patterns[i].pattern.matchedLength(); if (length > 0) { best = i; best_offset = match_offset; best_length = length; } } } if (best >= 0) { // output the portion of the text before the matching // substring // kDebug() << "outputting plain: " << text.mid(offset, best_offset - offset); // kDebug() << "weight = " << m_display->currentCharFormat().fontWeight(); output(text.mid(offset, best_offset - offset)); // change format m_display->setCurrentCharFormat(m_patterns[best].format); // output the matching substring // kDebug() << "outputting formatted: " << text.mid(best_offset, best_length); // kDebug() << "weight = " << m_display->currentCharFormat().fontWeight(); output(text.mid(best_offset, best_length)); // restore basic format m_display->setCurrentCharFormat(m_basic_format); // kDebug() << "restored"; // kDebug() << "weight = " << m_display->currentCharFormat().fontWeight(); // update offset offset = best_offset + best_length; } else break; } // output the last portion of the text // kDebug() << "outputting plain: " << text.mid(offset); output(text.mid(offset)); // kDebug() << "weight = " << m_display->currentCharFormat().fontWeight(); } #endif QRegExp Console::promptRegexp("([a-zA-Z0-9]*% )"); Console::Console(QWidget* parent, const QString& caption) : QWidget(parent) { setObjectName("console"); resize(600,600); setWindowTitle(caption); QBoxLayout* layout = new QVBoxLayout(this); QHBoxLayout* promptLayout = new QHBoxLayout; layout->setMargin(0); layout->setSpacing(0); promptLayout->setMargin(0); promptLayout->setSpacing(0); edit = new HistLineEdit(this); display = new QTextEdit(this); prompt = new QLabel(this); setFocusProxy(edit); layout->addWidget(display); layout->addLayout(promptLayout); promptLayout->addWidget(prompt); promptLayout->addWidget(edit); display->setFocusProxy(edit); display->setReadOnly(true); ////display->setTextFormat(QTextEdit::PlainText); display->setAcceptRichText(false); display->setWordWrapMode (QTextOption::NoWrap); display->setUndoRedoEnabled (false); Settings s_console = settings().group("console"); if (!s_console["font"]) { QFont f = QApplication::font(); f.setFamily("Monospace"); s_console["font"] = f; } display->setFont(s_console["font"].value()); display->setFontWeight(QFont::Normal); m_highlighter.setDisplay(display); connect(edit, SIGNAL(receivedInput(const QString&)), this, SLOT(input(const QString&))); } void Console::echo(const QString& text) { ConsoleOutput output(display, true); display->setFontWeight(QFont::Bold); output(text + "\n"); display->setFontWeight(QFont::Normal); } void Console::input(const QString& text) { if (edit->echoMode() == QLineEdit::Password) { // edit->setEchoMode(QLineEdit::Normal); echo("(password sent)"); } else { // echo inputted text echo(text); } if (m_notifier) m_notifier->textNotify(text); receivedInput(text); } void Console::displayText(QString text, int offset) { if (offset == 0 && promptRegexp.indexIn(text) == 0) { prompt->setText(" " + promptRegexp.cap(1)); offset += promptRegexp.cap(1).length(); } text = text.mid(offset); text.replace("\t", " "); QByteArray bytes = text.toAscii(); if (bytes.contains("\xff\xfc\x01")) { edit->setEchoMode(QLineEdit::Normal); } else if (bytes.contains("\xff\xfb\x01")) { edit->setEchoMode(QLineEdit::Password); } if (text[offset].isPrint()) { ConsoleOutput output(display); m_highlighter(text, output); } } void Console::clear() { display->clear(); } tagua-1.0-alpha2/src/console.h000066400000000000000000000025431077523320400162310ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef CONSOLE_H #define CONSOLE_H #include #include #include #include "histlineedit.h" #include "console_p.h" class QLabel; class QTextEdit; class TextNotifier; class Console : public QWidget { Q_OBJECT HistLineEdit* edit; QTextEdit* display; QLabel* prompt; static QRegExp promptRegexp; boost::shared_ptr m_notifier; LuaConsoleHighlighter m_highlighter; public: Console(QWidget* parent, const QString& caption); inline QLineEdit* commandLine() const { return edit; } void clear(); void setNotifier(const boost::shared_ptr& notifier) { m_notifier = notifier; } public Q_SLOTS: void displayText(QString, int offset); void echo(const QString&); protected Q_SLOTS: void input(const QString&); Q_SIGNALS: void receivedInput(const QString&); void notify(); }; class TextNotifier { public: virtual ~TextNotifier() { } virtual void textNotify(const QString& text) = 0; }; #endif // CONSOLE_H tagua-1.0-alpha2/src/console_p.h000066400000000000000000000033401077523320400165440ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef CONSOLE_P_H #define CONSOLE_P_H #include "highlighter.h" #include "hline.h" #include "luaapi/luahl.h" #include class QTextEdit; //BEGIN ConsoleOutput --------------------------------------- /** * An utility class to perform a simple output operation * on a QTextEdit with RAII. */ class ConsoleOutput { QTextEdit* m_edit; int m_old_val; bool m_scroll_to; public: ConsoleOutput(QTextEdit* edit, bool force_scroll = false); virtual ~ConsoleOutput(); virtual void operator()(const QString& text); }; class ConsoleHighlighter { std::vector m_patterns; QTextEdit* m_display; QTextCharFormat m_basic_format; public: ConsoleHighlighter(); void setDisplay(QTextEdit* display); void operator()(const QString& text, ConsoleOutput& output); }; class LuaConsoleHighlighter { QTextEdit* m_display; LuaApi::Api m_api; class Executor : public HLineExecutor { QTextEdit* m_display; ConsoleOutput& m_output; public: Executor(QTextEdit* display, ConsoleOutput& output); virtual ~Executor(); virtual void writeChunk(const QString& text); virtual void setFormat(const QTextCharFormat& format); }; public: LuaConsoleHighlighter(); void setDisplay(QTextEdit* display); void operator()(const QString& text, ConsoleOutput& output); }; #endif // CONSOLE_P_H tagua-1.0-alpha2/src/constrainedtext.cpp000066400000000000000000000050201077523320400203310ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "constrainedtext.h" #include ConstrainedText::ConstrainedText(const QString& text, const QColor& color, const QFont& font, const QRect& rect, KGameCanvasAbstract* Constrained) : KGameCanvasItem(Constrained) , m_text(text) , m_color(color) , m_font(font) , m_constr(rect) { calcBoundingRect(); } ConstrainedText::ConstrainedText(KGameCanvasAbstract* Constrained) : KGameCanvasItem(Constrained) //, m_text("") , m_color(Qt::black) , m_font(QApplication::font()) { } ConstrainedText::~ConstrainedText() { } void ConstrainedText::calcBoundingRect() { QString test; for(int i=0;isetPen(m_color); p->setFont(m_font); double fact = qMin(double(m_constr.width())/m_bounding_rect_max.width(), double(m_constr.height())/m_bounding_rect_max.height()); QMatrix savem = p->matrix(); //p->fillRect( m_constr, Qt::blue ); p->translate(QRectF(m_constr).center()); p->scale(fact, fact); p->translate(-QRectF(m_bounding_rect_max).center()); //p->fillRect( m_bounding_rect_max, Qt::red ); p->drawText( QPoint((m_bounding_rect_max.width()-m_bounding_rect.width())/2,0), m_text); p->setMatrix(savem); } QRect ConstrainedText::rect() const { return m_constr; //suboptimal. oh, well... } tagua-1.0-alpha2/src/constrainedtext.h000066400000000000000000000026611077523320400200060ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef CONSTRAINEDTEXT_H #define CONSTRAINEDTEXT_H #include class ConstrainedText : public KGameCanvasItem { private: QString m_text; QColor m_color; QFont m_font; QRect m_constr; QRect m_bounding_rect; QRect m_bounding_rect_max; void calcBoundingRect(); public: ConstrainedText(const QString& text, const QColor& color, const QFont& font, const QRect& rect, KGameCanvasAbstract* canvas = NULL); ConstrainedText(KGameCanvasAbstract* canvas = NULL); virtual ~ConstrainedText(); QRect constrainRect() const { return m_constr; } void setConstrainRect(const QRect& ); QString text() const { return m_text; } void setText(const QString& text); QColor color() const { return m_color; } void setColor(const QColor& color); QFont font() const { return m_font; } void setFont(const QFont& font); virtual void paint(QPainter* p); virtual QRect rect() const; virtual bool layered() const { return false; } }; #endif //CONSTRAINEDTEXT_H tagua-1.0-alpha2/src/controllers/000077500000000000000000000000001077523320400167605ustar00rootroot00000000000000tagua-1.0-alpha2/src/controllers/abstract.cpp000066400000000000000000000023511077523320400212700ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "abstract.h" #include "entities/userentity.h" Controller::Controller(ChessTable* view) : m_view(view) { } Controller::~Controller() { } bool Controller::undo() { return entity()->undo(); } bool Controller::redo() { return entity()->redo(); } bool Controller::truncate() { return entity()->truncate(); } bool Controller::promoteVariation() { return entity()->promoteVariation(); } bool Controller::back() { return entity()->back(); } bool Controller::forward() { return entity()->forward(); } void Controller::gotoFirst() { entity()->gotoFirst(); } void Controller::gotoLast() { entity()->gotoLast(); } QString Controller::save() { return entity()->save(); } void Controller::loadPGN(const PGN& pgn) { entity()->loadPGN(pgn); } KUrl Controller::url() const { return m_url; } void Controller::setUrl(const KUrl& url) { m_url = url; } tagua-1.0-alpha2/src/controllers/abstract.h000066400000000000000000000117121077523320400207360ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef CONTROLLER_H #define CONTROLLER_H #include #include #include #include "common.h" #include "entitytoken.h" #include "fwd.h" class ChessTable; class UserEntity; class Engine; class PGN; class ActionCollection; class UI; /** * @b Controller is the base abstract class for all controllers in Tagua. * Tagua can be used in different modes, such as game editing or position editing. * Each mode corresponds to a concrete subclass of Controller, and defines its behaviour * in response to user events (history navigation, move executions...). * By default, events are routed to the user entity returned by the virtual function * entity. */ class Controller : public boost::enable_shared_from_this { protected: ChessTable* m_view; virtual boost::shared_ptr entity() const = 0; KUrl m_url; public: Controller(ChessTable* view); virtual ~Controller(); /** * Variant specific actions. */ virtual ActionCollection* variantActions() const = 0; /** * Variant associated to the controller. */ virtual QString variant() const = 0; /** * Terminate activity, create another controller and delegate everything to it. * @return The delegate controller, or simply @b this if controller does not need * to be terminated. */ virtual boost::shared_ptr end() { return shared_from_this(); } /** * Detach from resources without disposing them. */ virtual void detach() { } /** * Clear board. Undefined for almost all controllers. * @return Whether the action has been successfully executed. */ virtual bool clearBoard() { return false; } /** * Set starting position on the board. Undefined for almost all controllers. * @return Whether the action has been successfully executed. */ virtual bool setStartingPosition() { return false; } /** * Set a position on the board. Undefined for almost all controllers. * @param fen The position to be set, in FEN notation. * @return Whether the action has been successfully executed. */ virtual bool setFEN(const QString&) { return false; } /** * Get a FEN string representing the current position on the board. */ virtual QString fen() { return ""; } /** * @return current position, or a null shared_ptr if no current position * concept is defined for this controller. */ virtual PositionPtr currentPosition() const { return PositionPtr(); } /** * Change turn. Used for example in edit position mode. */ virtual void setTurn(int) { } /** * Forward a movelist undo call. */ virtual bool undo(); /** * Forward a movelist redo call. */ virtual bool redo(); /** * Forward a movelist truncate call. */ virtual bool truncate(); /** * Forward a movelist promote variation call. */ virtual bool promoteVariation(); /** * Navigate back in history. */ virtual bool back(); /** * Navigate forward in history. */ virtual bool forward(); /** * Warp to the beginning of the history. */ virtual void gotoFirst(); /** * Warp to the end of the history. */ virtual void gotoLast(); /** * Save game. */ virtual QString save(); /** * Load game from a PGN. */ virtual void loadPGN(const PGN&); /** * Create a CTRL Action. * @sa UI::createCtrlAction */ virtual void createCtrlAction() { } /** * Destroy a CTRL Action. * @sa UI::createCtrlAction. */ virtual void destroyCtrlAction() { }; /** * Let an engine play as player @a side. * @return a token which uniquely identifies the engine entity * and can be used to remove it from the entity list. */ virtual EntityToken addPlayingEngine(int /*side*/, const boost::shared_ptr&) { return EntityToken(); } /** * Remove an entity from the controller list. */ virtual void removeEntity(const EntityToken&) { } virtual void reloadSettings() = 0; /** * Set owning user interface. * Used to setup callbacks towards the main window, like action state * change notifications. */ virtual void setUI(UI& ui) = 0; /** * Called whenever a controller becomes active in the main window. */ virtual void activate() = 0; /** * Each controller has an associated URL that will be used for saving * its content. * @return The URL associated with this controller. */ virtual KUrl url() const; /** * Set this controller's URL. * @sa url() */ virtual void setUrl(const KUrl& url); }; #endif tagua-1.0-alpha2/src/controllers/editgame.cpp000066400000000000000000000220341077523320400212440ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "editgame.h" #include #include "graphicalgame.h" #include "graphicalsystem.h" #include "xboardengine.h" #include "entities/engineentity.h" #include "entities/gameentity.h" #include "entities/icsentity.h" #include "entities/examinationentity.h" #include "movelist_table.h" #include "console.h" #include "icsconnection.h" #include "chesstable.h" #include "foreach.h" #include "actioncollection.h" #include "ui.h" using namespace boost; class ClockAgent : public Agent { ChessTable* m_view; shared_ptr m_game; public: ClockAgent(ChessTable* view, const shared_ptr& game) : m_view(view) , m_game(game) { } virtual void notifyClockUpdate(int, int) { } virtual void notifyMove(const Index& index) { // start clock after the first 2 moves if (index.totalNumMoves() >= 2) m_view->run(); m_view->changeClock(m_game->position(index)->turn()); } virtual void notifyBack() { } virtual void notifyForward() { } virtual void notifyGotoFirst() { } virtual void notifyGotoLast() { } virtual void stop() { Agent::stop(); m_view->stopClocks(); } }; class ClockUpdateAgent : public Agent { ChessTable* m_view; public: ClockUpdateAgent(ChessTable* view) : m_view(view) { } virtual void notifyClockUpdate(int white, int black) { m_view->updateTime(white, black); } virtual void notifyMove(const Index&) { } virtual void notifyBack() { } virtual void notifyForward() { } virtual void notifyGotoFirst() { } virtual void notifyGotoLast() { } }; EditGameController::EditGameController(ChessTable* view, const VariantPtr& variant, AbstractPosition::Ptr startingPosition) : Controller(view) , m_variant(variant) { AbstractPosition::Ptr position; if (!startingPosition) { position = m_variant->createPosition(); position->setup(); } else position = startingPosition; m_graphical = shared_ptr(new GraphicalSystem(m_view, position, m_variant)); m_game = shared_ptr(new GraphicalGame(m_graphical.get(), m_view->moveListTable())); m_game->reset(position); m_entity = shared_ptr(new GameEntity(m_variant, m_game, m_view->board(), &m_agents)); m_entity->enableEditingTools(true); m_graphical->setup(m_entity); m_game->setEntity(m_entity); init(AbstractPosition::Ptr()); } EditGameController::~EditGameController() { } void EditGameController::init(AbstractPosition::Ptr startingPosition) { m_players[0] = m_entity; m_players[1] = m_entity; m_entity->turnTest().setSimplePolicy(0, true); m_entity->turnTest().setSimplePolicy(1, true); if (startingPosition) { // TODO update to the starting position } // add user agent m_agents.addAgent(m_entity); m_clock_agent = shared_ptr(new ClockAgent(m_view, m_game)); m_update_agent = shared_ptr(new ClockUpdateAgent(m_view)); // add clock update agent m_agents.addAgent(m_update_agent); } ActionCollection* EditGameController::variantActions() const { return m_variant->actions(); } QString EditGameController::variant() const { PositionPtr pos = m_game->position(); if (pos) return pos->variant(); else return QString(); } void EditGameController::onNavigation() { } EntityToken EditGameController::addPlayingEngine(int side, const shared_ptr& engine) { Q_ASSERT(side == 0 || side == 1); if (!engine) return EntityToken(); if (m_players[side]->canDetach()) { shared_ptr entity(new EngineEntity(m_variant, m_game, side, engine, &m_agents)); entity->setup(); m_agents.addAgent(entity); m_players[side] = entity; // the user cannot move the entity's pieces m_entity->turnTest().setSimplePolicy(side, false); return EntityToken(entity); } else { kDebug() << "** could not detach entity playing " << side << "**"; } return EntityToken(); } // EntityToken EditGameController::addAnalysingEngine(const shared_ptr& engine) { // Q_ASSERT(engine.use_count() == 1); // shared_ptr entity(new EngineEntity(m_variant, m_game, -1, engine, &m_agents)); // m_agents.addAgent(entity); // EntityToken res(m_entities.insert(entity).first); // // engine->setNotifier(entity); // engine->start(); // engine->setBoard(m_game->position(), 0, 0); // engine->startAnalysis(); // // return res; // } void EditGameController::removeEntity(const EntityToken& token) { shared_ptr entity = token.entity(); if (entity) { // check players for (int i = 0; i < 2; i++) { if (entity == m_players[i]) { m_players[i] = m_entity; m_entity->turnTest().setSimplePolicy(i, true); } } // check other entities std::set >::iterator it = m_entities.find(entity); if (it != m_entities.end()) { m_entities.erase(it); } } kDebug() << "there are " << m_entities.size() << " entities left"; } bool EditGameController::addICSPlayer(int side, int game_number, const shared_ptr& connection) { Q_ASSERT(side == 0 || side == 1); if (m_players[side]->canDetach()) { shared_ptr entity(new ICSEntity(m_variant, m_game, side, game_number, connection, &m_agents)); if (entity->attach()) { kDebug() << "added ICS agent " << entity.get(); m_agents.addAgent(entity); m_players[side] = entity; connection->setListener(game_number, entity); entity->setupTurnTest(m_entity->turnTest()); m_view->flip(m_players[1] == m_entity); // flip if we're black! m_agents.addAgent(m_clock_agent); } else { kDebug() << "** could not attach ics entity **"; return false; } } else { kDebug() << "** could not detach entity playing " << side << "**"; return false; } return true; } bool EditGameController::setExaminationMode(int game_number, const shared_ptr& connection) { kDebug() << "[controller " << this << "] setting examination mode"; if (m_players[0]->canDetach() && m_players[1]->canDetach()) { shared_ptr entity(new ExaminationEntity(m_variant, m_game, game_number, connection, &m_agents)); if (entity->attach()) { m_entity = entity; m_view->setEntity(entity); m_agents.addAgent(entity); m_players[0] = entity; m_players[1] = entity; connection->setListener(game_number, entity); m_view->flip(false); m_entity->turnTest().clear(); return true; } else kDebug() << "** could not attach examination entity **"; } else kDebug() << "** could not detach entity **"; return false; } bool EditGameController::setObserveMode(int game_number, const shared_ptr& connection) { if (m_players[0]->canDetach() && m_players[1]->canDetach()) { shared_ptr entity(new ObservingEntity(m_variant, m_game, game_number, connection, &m_agents)); if (entity->attach()) { m_agents.addAgent(entity); m_players[0] = entity; m_players[1] = entity; connection->setListener(game_number, entity); m_view->flip(false); m_entity->turnTest().clear(); return true; } else kDebug() << "** could not attach ics entity for observe mode ** "; } else kDebug() << "** could not detach entity **"; return false; } void EditGameController::loadPGN(const PGN& pgn) { end(); m_view->resetClock(); entity()->loadPGN(pgn); } void EditGameController::createCtrlAction() { m_game->createCtrlAction(); } void EditGameController::destroyCtrlAction() { m_game->destroyCtrlAction(); } void EditGameController::detach() { m_entity->detach(); m_players[0]->detach(); m_players[1]->detach(); foreach (shared_ptr entity, m_entities) entity->detach(); } shared_ptr EditGameController::end() { // stop clocks if (m_clock_agent) { m_clock_agent->stop(); m_clock_agent = shared_ptr(new ClockAgent(m_view, m_game)); } // return to edit game mode m_players[0] = m_entity; m_players[1] = m_entity; m_entity->turnTest().setSimplePolicy(0, true); m_entity->turnTest().setSimplePolicy(1, true); return Controller::end(); } void EditGameController::reloadSettings() { m_graphical->settingsChanged(); } void EditGameController::setUI(UI& ui) { m_game->setActionStateObserver(ui.createActionStateObserver(shared_from_this())); m_game->onActionStateChange(); } void EditGameController::activate() { m_game->onActionStateChange(); } tagua-1.0-alpha2/src/controllers/editgame.h000066400000000000000000000051571077523320400207200ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef EDITGAMECONTROLLER_H #define EDITGAMECONTROLLER_H #include #include "abstract.h" #include "agentgroup.h" #include "tagua.h" class Entity; class Engine; class Agent; class ICSConnection; class UserEntity; class GraphicalGame; class GraphicalSystem; /** * @brief A controller to edit or play games. * * EditGameController is used to play games, either locally or * on an ICS server. A pair of entities @code m_players, representing * the two players, is mantained as well as a set of additional entities, * @code m_entities. * If an entity needs to be notified about how the game progresses, one * should register it as an agent, adding it to @code m_agents. */ class EditGameController : public Controller { void init(AbstractPosition::Ptr); boost::shared_ptr m_clock_agent; boost::shared_ptr m_update_agent; protected: virtual void onNavigation(); boost::shared_ptr m_entity; boost::shared_ptr m_graphical; AgentGroup m_agents; VariantPtr m_variant; boost::shared_ptr m_game; virtual boost::shared_ptr entity() const { return m_entity; } boost::shared_ptr m_players[2]; std::set > m_entities; public: EditGameController(ChessTable*, const VariantPtr& variant, AbstractPosition::Ptr startingPos = AbstractPosition::Ptr()); ~EditGameController(); virtual ActionCollection* variantActions() const; virtual QString variant() const; EntityToken addPlayingEngine(int side, const boost::shared_ptr& engine); // EntityToken addAnalysingEngine(const boost::shared_ptr& engine); void removeEntity(const EntityToken& token); bool addICSPlayer(int side, int game_number, const boost::shared_ptr& connection); bool setExaminationMode(int game_number, const boost::shared_ptr& connection); bool setObserveMode(int game_number, const boost::shared_ptr& connection); virtual void loadPGN(const PGN&); virtual void createCtrlAction(); virtual void destroyCtrlAction(); virtual boost::shared_ptr end(); virtual void detach(); virtual void reloadSettings(); virtual void setUI(UI& ui); virtual void activate(); }; #endif tagua-1.0-alpha2/src/controllers/editposition.cpp000066400000000000000000000254651077523320400222120ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "editposition.h" #include "graphicalsystem.h" #include "entities/userentity.h" #include "piecefunction.h" #if 0 //BROKEN using namespace boost; //BEGIN UndoHistory UndoHistory::UndoHistory() { m_index = 0; } void UndoHistory::add(const UndoAction& action) { m_history.erase(m_history.begin() + m_index, m_history.end()); m_history.push_back(action); m_index++; } const UndoAction* UndoHistory::undo() { if (m_index <= 0) return 0; m_index--; return &m_history[m_index]; } const UndoAction* UndoHistory::redo() { if (m_index >= m_history.size()) return 0; UndoAction* res = &m_history[m_index]; m_index++; return res; } //END UndoHistory class EditAction : public AbstractMove { typedef variant UserMove; UserMove m_move; class ConvertToNormalUserMove : public static_visitor { public: NormalUserMove operator()(const NormalUserMove& m) const { return m; } NormalUserMove operator()(const DropUserMove& m) const { return NormalUserMove(Point::invalid(), m.m_to); } }; public: EditAction(const UserMove& move) : m_move(move) { } virtual QString SAN(boost::shared_ptr) const { return QString(); } virtual DecoratedMove toDecoratedMove(boost::shared_ptr) const { return DecoratedMove(); } virtual QString toString(boost::shared_ptr) const { return QString(); } virtual NormalUserMove toUserMove() const { return apply_visitor(ConvertToNormalUserMove(), m_move); } virtual AbstractPiece::Ptr pieceHint() const { if (const DropUserMove* move = get(&m_move)) return move->m_piece; else return AbstractPiece::Ptr(); } virtual bool equals(AbstractMove::Ptr /*other*/) const { // EditAction* move = dynamic_cast(other.get()); // return move && (m_move == move->m_move); // FIXME: the above does not compile return false; } UserMove& move() { return m_move; } }; class EditPositionEntity : public UserEntity { struct EditPositionEntityInternal { shared_ptr m_graphical; VariantInfo* m_variant; EditPositionEntityInternal(const shared_ptr& graphical, VariantInfo* variant) : m_graphical(graphical) , m_variant(variant) { } }; EditPositionEntityInternal m_data; UndoHistory& m_undo_history; class ExecuteMoveVisitor : public static_visitor { EditPositionEntityInternal& m_data; public: ExecuteMoveVisitor(EditPositionEntityInternal& data) : m_data(data) { } UndoAction operator()(const NormalUserMove& move) { if (move.to.valid()) { Element removedElement = m_data.m_graphical->getElement(move.to); m_data.m_graphical->setElement( move.to, m_data.m_graphical->getElement(move.from)); m_data.m_graphical->adjustSprite(move.to); m_data.m_graphical->removeElement(move.from); return MoveAction(move.from, move.to, removedElement.piece()); } else { Element removedElement = m_data.m_graphical->getElement(move.from); m_data.m_graphical->removeElement(move.from); return RemoveAction(move.from, removedElement.piece()); } } UndoAction operator()(const DropUserMove& move) { AbstractPiece::Ptr dropped = move.m_piece; m_data.m_graphical->setPiece( move.m_to, dropped, true); m_data.m_graphical->adjustSprite(move.m_to); return DropAction(move.m_to, dropped); } }; class UndoActionVisitor : public static_visitor { EditPositionEntityInternal& m_data; public: UndoActionVisitor(EditPositionEntityInternal& data) : m_data(data) { } void operator()(const DropAction& action) { m_data.m_graphical->removeElement(action.m_to); } void operator()(const RemoveAction& action) { if (action.m_piece) m_data.m_graphical->setPiece(action.m_to, action.m_piece); } void operator()(const MoveAction& action) { m_data.m_graphical->setElement( action.m_from, m_data.m_graphical->getElement(action.m_to)); if (action.m_piece) m_data.m_graphical->setPiece(action.m_to, action.m_piece); else m_data.m_graphical->removeElement(action.m_to); m_data.m_graphical->adjustSprite(action.m_from); } void operator()(const WarpAction& action) { kDebug() << "undo warp from:"; kDebug() << action.m_from->fen(0, 0); kDebug() << "to"; kDebug() << action.m_to->fen(0, 0); m_data.m_graphical->warp(AbstractMove::Ptr(), action.m_from); } }; class RedoActionVisitor : public static_visitor { EditPositionEntityInternal& m_data; public: RedoActionVisitor(EditPositionEntityInternal& data) : m_data(data) { } void operator()(const DropAction& action) { if (action.m_piece) m_data.m_graphical->setPiece(action.m_to, action.m_piece); } void operator()(const RemoveAction& action) { m_data.m_graphical->removeElement(action.m_to); } void operator()(const MoveAction& action) { m_data.m_graphical->setElement( action.m_to, m_data.m_graphical->getElement(action.m_from)); m_data.m_graphical->removeElement(action.m_from); m_data.m_graphical->adjustSprite(action.m_to); } void operator()(const WarpAction& action) { m_data.m_graphical->warp(AbstractMove::Ptr(), action.m_to); } }; public: EditPositionEntity(VariantInfo* variant, const shared_ptr& graphical, UndoHistory& undo_history) : UserEntity(0) , m_data(graphical, variant) , m_undo_history(undo_history) { } virtual QString save() const { return ""; } virtual void loadPGN(const PGN&) { } virtual AbstractMove::Ptr testMove(const NormalUserMove& m) const { return AbstractMove::Ptr(new EditAction(m)); } virtual AbstractMove::Ptr testMove(const DropUserMove& m) const { return AbstractMove::Ptr(new EditAction(m)); } virtual bool testPremove(const NormalUserMove&) const { return false; } virtual bool testPremove(const DropUserMove&) const { return false; } virtual void executeMove(AbstractMove::Ptr move) { EditAction* action = dynamic_cast(move.get()); if (action) { ExecuteMoveVisitor visitor(m_data); UndoAction undo_action = apply_visitor(visitor, action->move()); m_undo_history.add(undo_action); } } virtual void handleRightClick(const Point& p) const { Element removedElement = m_data.m_graphical->getElement(p); UndoAction action = RemoveAction(p, removedElement.piece()); m_data.m_graphical->removeElement(p); m_undo_history.add(action); } virtual void addPremove(const NormalUserMove&) { } virtual void addPremove(const DropUserMove&) { } virtual void cancelPremove() { } virtual Action validTurn(const Point&) const { return Moving; } virtual Action validTurn(int) const { return Moving; } virtual bool movable(const Point&) const { return true; } virtual bool jump(const Index&) { return false; } virtual bool goTo(const Index&) { return false; } virtual bool gotoFirst() { return false; } virtual bool gotoLast() { return false; } virtual bool forward() { return false; } virtual bool back() { return false; } virtual bool undo() { if (const UndoAction* action = m_undo_history.undo()) { UndoActionVisitor visitor(m_data); apply_visitor(visitor, *action); return true; } else return false; } virtual bool redo() { if (const UndoAction* action = m_undo_history.redo()) { RedoActionVisitor visitor(m_data); apply_visitor(visitor, *action); return true; } else return false; } virtual bool truncate() { return false; } virtual bool promoteVariation() { return false; } virtual void notifyClockUpdate(int, int) { } virtual void notifyMove(AbstractMove::Ptr, AbstractPosition::Ptr) { } virtual void notifyBack() { } virtual void notifyForward() { } virtual void notifyGotoFirst() { } virtual void notifyGotoLast() { } }; class FillPool : public PieceFunction { shared_ptr m_graphical; VariantInfo* m_variant; public: FillPool(VariantInfo* variant, const shared_ptr& graphical) : m_graphical(graphical) , m_variant(variant) { } virtual void operator()(int color, int type) { m_graphical->addToPool( m_variant->createPiece(color, type), 1 ); } }; EditPositionController::EditPositionController(ChessTable* view, VariantInfo* variant) : Controller(view) , m_variant(variant) { m_graphical = shared_ptr( new GraphicalInfo(m_view, AbstractPosition::Ptr(), m_variant)); m_entity = shared_ptr( new EditPositionEntity(m_variant, m_graphical, m_undo_history)); m_graphical->setup(m_entity); FillPool fill_pool(m_variant, m_graphical); m_variant->forallPieces(fill_pool); } shared_ptr EditPositionController::entity() const { return m_entity; } bool EditPositionController::clearBoard() { AbstractPosition::Ptr position = m_variant->createPosition(); m_undo_history.add(WarpAction(m_graphical->position()->clone(), position)); m_graphical->warp(AbstractMove::Ptr(), position); return true; } bool EditPositionController::setStartingPosition() { AbstractPosition::Ptr startingPosition = m_variant->createPosition(); startingPosition->setup(); kDebug() << "adding warp to undo history:"; kDebug() << m_graphical->position()->fen(0, 0); kDebug() << startingPosition->fen(0, 0); m_undo_history.add(WarpAction(m_graphical->position()->clone(), startingPosition)); m_graphical->warp(AbstractMove::Ptr(), startingPosition); return true; } QString EditPositionController::fen() { return m_graphical->position()->fen(0,0); } bool EditPositionController::setFEN(const QString& fen) { AbstractPosition::Ptr pos = m_variant->createPositionFromFEN(fen); if (pos) { kDebug() << "warping to fen " << fen; m_undo_history.add(WarpAction(m_graphical->position()->clone(), pos)); m_graphical->warp(AbstractMove::Ptr(), pos); return true; } else { kDebug() << "invalid fen"; return false; } } void EditPositionController::setTurn(int turn) { m_graphical->setTurn(turn); } AbstractPosition::Ptr EditPositionController::currentPosition() const { return m_graphical->position(); } #endif tagua-1.0-alpha2/src/controllers/editposition.h000066400000000000000000000050461077523320400216500ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef EDITPOSITIONCONTROLLER_H #define EDITPOSITIONCONTROLLER_H #include "abstract.h" #include "point.h" #include "tagua.h" #include #include #if 0 //BROKEN class VariantInfo; class GraphicalInfo; class EditPositionEntity; //BEGIN UndoAction class DropAction { public: Point m_to; AbstractPiece::Ptr m_piece; DropAction(const Point& to, AbstractPiece::Ptr piece) : m_to(to) , m_piece(piece) { } }; class RemoveAction { public: Point m_to; AbstractPiece::Ptr m_piece; RemoveAction(const Point& to, AbstractPiece::Ptr piece) : m_to(to) , m_piece(piece) { } }; class MoveAction { public: Point m_from; Point m_to; AbstractPiece::Ptr m_piece; MoveAction(const Point& from, const Point& to, AbstractPiece::Ptr piece) : m_from(from) , m_to(to) , m_piece(piece) { } }; class WarpAction { public: AbstractPosition::Ptr m_from; AbstractPosition::Ptr m_to; WarpAction(AbstractPosition::Ptr from, AbstractPosition::Ptr to) : m_from(from) , m_to(to) { } }; typedef boost::variant UndoAction; class UndoHistory { typedef std::vector Vector; Vector m_history; uint m_index; public: UndoHistory(); void add(const UndoAction& action); const UndoAction* undo(); const UndoAction* redo(); }; //END UndoAction class EditPositionController : public Controller { boost::shared_ptr m_graphical; boost::shared_ptr m_entity; UndoHistory m_undo_history; VariantInfo* m_variant; protected: virtual boost::shared_ptr entity() const; public: EditPositionController(ChessTable* view, VariantInfo* variant); virtual boost::shared_ptr end() { return shared_from_this(); } virtual bool clearBoard(); virtual bool setStartingPosition(); virtual bool setFEN(const QString&); virtual QString fen(); virtual void setPromotionType(int) { } virtual void setTurn(int); virtual void handleMoveList(const class PGN&) { } virtual QString save() { return ""; } virtual void loadPGN(const PGN&) { } virtual AbstractPosition::Ptr currentPosition() const; }; #endif #endif // EDITPOSITIONCONTROLLER_H tagua-1.0-alpha2/src/controllers/entitytoken.cpp000066400000000000000000000012321077523320400220370ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "entitytoken.h" EntityToken::EntityToken(const boost::shared_ptr& entity) : m_entity(entity) { } EntityToken::EntityToken() { } boost::shared_ptr EntityToken::entity() const { return m_entity.lock(); } bool EntityToken::valid() const { return entity(); } tagua-1.0-alpha2/src/controllers/entitytoken.h000066400000000000000000000013741077523320400215130ustar00rootroot00000000000000/* Copyright (c) 2006-2007 Paolo Capriotti (c) 2006-2007 Maurizio Monge 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. */ #ifndef ENTITYTOKEN_H #define ENTITYTOKEN_H #include #include #include class Entity; class EntityToken { boost::weak_ptr m_entity; public: EntityToken(const boost::shared_ptr& entity); EntityToken(); boost::shared_ptr entity() const; bool valid() const; }; #endif // ENTITYTOKEN_H tagua-1.0-alpha2/src/crash.cpp000066400000000000000000000016041077523320400162170ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include "crash.h" #if defined(Q_OS_UNIX) && defined(TAGUA_DEBUG) #include #include #include #include #include static void handler(int) { printf("Sange & Crasha!!!!\n"); printf("I'm sorry, i crashed.\n"); printf("Now run somewhere\n"); printf(" gdb attach %d\n", getpid() ); exit(0); } void CrashHandler::install() { signal(SIGSEGV, handler); signal(SIGABRT, handler); } #else void CrashHandler::install() { } #endif tagua-1.0-alpha2/src/crash.h000066400000000000000000000010141077523320400156570ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef CRASH_H #define CRASH_H #include "export.h" class TAGUA_EXPORT CrashHandler { public: static void install(); }; #endif //CRASH_H tagua-1.0-alpha2/src/decoratedmove.cpp000066400000000000000000000024611077523320400177420ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "decoratedmove.h" #include #include #include "common.h" DecoratedMove::DecoratedMove() { } DecoratedMove::DecoratedMove(const QString& str) { load(str); } void DecoratedMove::load(const QString& str) { static QRegExp figurine("\\{[^}]*\\}"); int offset = 0; int begin; while ((begin = figurine.indexIn(str, offset)) != -1) { if (begin > offset) { m_elements.push_back(str.mid(offset, begin - offset)); } m_elements.push_back(MovePart(str.mid(begin + 1, figurine.matchedLength() - 2), MovePart::Figurine)); offset = begin + figurine.matchedLength(); } if (offset < str.length()) m_elements.push_back(str.mid(offset)); } void DecoratedMove::push_back(const MovePart& part) { m_elements.push_back(part); } MovePart DecoratedMove::operator[](int index) const { return m_elements[index]; } unsigned int DecoratedMove::size() const { return m_elements.size(); } tagua-1.0-alpha2/src/decoratedmove.h000066400000000000000000000020371077523320400174060ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef DECORATEDMOVE_H #define DECORATEDMOVE_H #include #include #include "export.h" class MovePart { public: enum Type { Text, Figurine }; QString m_string; Type m_type; MovePart(const QString& s, Type t = Text) : m_string(s), m_type(t) {} }; class TAGUA_EXPORT DecoratedMove { typedef QList ElementList; ElementList m_elements; public: DecoratedMove(); explicit DecoratedMove(const QString& str); void load(const QString& str); MovePart operator[](int index) const; unsigned int size() const; // deprecated methods void push_back(const MovePart& part); }; #endif //DECORATEDMOVE_H tagua-1.0-alpha2/src/doxy/000077500000000000000000000000001077523320400153755ustar00rootroot00000000000000tagua-1.0-alpha2/src/doxy/bottom1.png000066400000000000000000000002501077523320400174650ustar00rootroot00000000000000PNG  IHDR;X(;bKGD pHYs  d_tIME4  5IDATxc, Ĩİ` #-0޿D?Īc[>ZP.n$zIENDB`tagua-1.0-alpha2/src/doxy/bottom2.png000066400000000000000000000155031077523320400174750ustar00rootroot00000000000000PNG  IHDR;=gAMA abKGDR| pHYs  #utIME)ΒHIDATxyW32"3+vTJ- Muhg,hz|lYiOtO{P@{G6`K,־Rjʪb?"%UJR]iwGǙ"/}ຮK*U^wTQc*KTY"ȯ T! T)7U1.< !2,#s;4.dX, lڝz8ÿJ}hUŸH$s~r$ 4MS 0>>N" 311|f$!):S|۶4M$IBXH ,$*,W(b\.m6$k֬AejkkOL&έꬎL&qM4mN 1ɲi &''Ep:!F'_qD"'Ȫ+{G(B<QfppFz.(B"󈢈(2;-2/"\xh67b\cl۶N'D}e˖M(Bs($ r\Јb B$BP]Lb| [pvLMM155E>!r]w!I*hʕ+ٹs'tLDQD366F:P({ˈ8HP 2 Yr9,q j:,_җH&,_:0MsѬɈE]?O.h4zƂrgԩehhl6K>~JqUb, n =iDYÇFK^˲l,d2 ip=pA蠫˗/8a^}U$IիWzj=OE.R~_.gPg>î]4 EQ$i%I0 V\ F*@} à2==M4ewVK^/bE+ᩧyG+Vʕ+ رx<۷oqYv-~s `ժU۷/`1H$ZBмބ(hFSSD5s@)*Wfٹs7W]~ms( 冷q]%줱]"KDMM X0,Iz!y_2Pf{9zzz0MUU4mA"eD"ϪU׵Y1 YJ*Eu]wg|CQKX'Irw2E__덌:-⯿78p۶ $ jkkXupUU1MzZZZhoo㢋./gŊ<쳳-\r%qQ&''m{Ac9QQ]׉D"y_555`&P"T-cY$ ]qHmxi7MM 477p+_Cǹմ֖^)WqW-[H&ǩ6=-wTU% 0Fb1吝-[F>رcH$ɭTq;o[[oYb9=q˖|kZ/Рإ-%^ 7}pގ?ai .;y]3~~$I((<'1<<|]O{/gqH$$Id22LUU6DQVX05kO =l߾{z]vE IPjȭwկdpFikk4Ͳ|W2b6B!frrrw>|}}} Bľˀ?֪g߾oEFFFX^]|[EЁؼit JDhmmeՁU,,5;|O@QI:2LPA'Çm6zzzHRXUq9FZƲ!"c457P?Mv-3SI1s-喿dB!Rq-[F[[[+e%\eYrY1 CuB/uLOsug^^zengڝ+K~*w}N.l q~D[ضeYA4u1-W:fttILX˖5k.:ڛ{Wil}3sǴr%Q[0###LOO/8xYu]qf(ML&;ws[\{&}DA` >Wk~?w-6#Gj*8$.d\h÷d,===̅򕯰 b[ۯ\ZO T*GO hu-/Tq۶msST^FGG _, eMᔚT`\].k߷M|Xbʶ:d'C!,10M@U$jL/ދnD<6naӦg1z:K6g34`?H[:>Oy6z;A:YxEk;K?y];wmۉbhp w^"pd᷀ r :"@Y Ѷm~.eb1Ɠ4%NVEQ h-o|Cbw/<.$Q&^$JDj"Pd嬽Qa |*rs5e"KA(:"\ bPPiѧlbhY|}\M68.' Bpcۄe<1 ',(m7 ]!u7kKq 6ǎ "I"i"K2cccD"gB\qܰ9ߊc?aÛ(Ͽ.Ɉ"+l=RbO<ļLx/A2>|˲!= rnF:'<p,,C2{7Osjbs#I7|,)dY&9ڼ߭+G 蠻5k֠?u{cH v9dzֆ$QA۲7nϽce'V.Vv,200@MM&,L!3eBmMgD) 2æXo|%[nGY>Z(?SB40aib?Oz*jA䶒XtxsCڹ13huuaF"Hҍ^}!mVTsq,ebtO fHv5466v͖Hd)a磊==J vE@gQ8@Xnݢ ! !X?[N.s]כn|OH1:2‹.(V2HWضCƖ8w^9QR.^*4ךt.%DVpگrxTjTju9ƶmߕI4t],ay;qf'gzz˶f'(ZN$Q *yTUES`YS8 \VKO2::J*"-(; "1jkků*Ie4l9yBug:ƍq>J4ESB>xnϣ"u1#E5HDLG%H-"gzzT*}߿j_{> @?d?g^UeOeli&H#K"2u˻dNw۶?|ǎbFLfJUPd|>O.öl` (" AMTuP QoϤWmM(򹏉_kʞFoZ1_w|w/~D~ǻC70L jf UJ(82VŝUR|,u:f?3Pc=?*IB.[T?eH&ɟmo?_aC+; BSq25t5$Z/a[\zJq)z~菮n-~3kls= tڛ*D(Q)o6ʒ/N.>~L˲od2322H$` 珱 < b3i:Wu=*l6SWWG8FS+U0`Y) 7$du1MH$BmmmC?83iT54K^Tzhhh8ezuFq7WjB(ebbM (2Ph־ oTS=8TqeJq;~P(D4 NH5?r(eN, yu]:Y>qMh,{,8|8aihhX,Vr|L+cGߥVx ,8ȲLOO{155E]]MMM466R___O]@-ʛY7vrd Ep:jjj줹NTl>x(oΔq`<grru Ԅi}TQil6K6P(^ _VR.bR}/4/wQo\bRePwTY"^wIENDB`tagua-1.0-alpha2/src/doxy/docheadergears.png000066400000000000000000000221021077523320400210400ustar00rootroot00000000000000PNG  IHDRxU 4mgAMA abKGD pHYs  #utIME'8a IDATx}i$u2vw^X,! %"EQ [vH2 I`P!ْMÒeI&-"E$@]{aٙ{*̬(*Q@tWge~+C2DD @>C$@v ;] 7)/ttP"P{h'6mSp|EW@¨T(?\Hb` ~bAoŷ^gzgB)X3O7Q(DDD@)QqE*>>#"ʿ@ӊ(N<He, _0tA{z/}/M/`lAu_5?hY1$WY.{|'Kd93,vxp@â 6qS~JB B-HXd+YkPhT)^᱖rCeKG/loS\~œ)D?.z:dN-ivX -ѕtBNI{SEqTf[L v2wCKc#g-/ʃ)axm-iXHKIvVZX3ٯd|zx#*KB](٫BuOYEfKWG| s&%`i mԈǷ~p;=?3~:0o|p鷾{Ťb)M},])f/3pr`-bjm}I %fyK+o]}ߡԵ~T R?:ܹczHg_\:-/Ag6WxizUHy[o -7% 5 {>reu+o޿03TPȡ Tt&]hT,^Wyc Z"/:,G`:ɣ ʛWj^a6ɘ쾛Z%'vHhG)%깗=458QGZ;ң{m`ZBXWw}.,Gƣo5t]\%OiR䭙 ~*!:*z"5Ksd;(w~*(|$t+0 ]\k R(hnQ(h Θt@0mkHO߳oxzjy 49UGs+{T5&iV[ZFABl`D:wԕΖKMOGCPm `* %äȚ0J|(j=@*HfPe[a)E`""H5<3_2\ѳiuIz0=D^80J(ӂɘ#uN?|mSЅ6Ӎ͉=ân3Zٹ|r6¡2{E]QtܢΤr4F}5]z/d!od/|W ©,C=t3KL>pW?P0uSՠȫ0J!8^3tQ [޺yIL~U3zYg=,klViäțk7 5n{G0e(Rϧ %kNN΍pPTB+#WoWe^G>jxDTvˣr|џ~מ.lǿ3{v}ădzJk'NYD=[F!*:*)lx[vSQP*n-Wzэg_Yi52~0©عDvc WwPuO G %+J퀀^ Kl)RTXWg'@87sQ>ܕ9N$GwMvtǷ=`fUV;6W+j)#es5AXpu7K i ɄL ȿfCB֫kEhhWl yo\0j]WKןPӎR %:Vb-h3fp @|u.|6- 6{u6g(O]iC/= -u=SvXhGy;oNۋ| Kхztӏ^}[ޅv &YNQsm_WʻFEۡOs @0mdǏ7qժfC//s%K=gs ʞ|oD{CA'`i-l ӦiWw33*N̡^:km*s'DjlK"۲ѯ֨-bhJyjm>~;1+6tvHcͪ8-- R겱//0~E2>I \/};SO"jɕÇ~6U_]8ƈ+풤s\##h%$aWl#߰{2T6 `%ʏ9q]#!YF@`_-vB^J. >V*0hasև>_:a^ϟ3sOX&eޔyZ]*ͮܥr+aQ栅LzMXo3'9>P慭>[&oEH3567k`*k{P*0&E+ ef@޸v+fshce\}0Bp`;;1;iakQ i0)`wa: 2a-h KDk](jN( Zvٱ3|Qm,SXrju`+N53$6gަI'O4s9vRd)F J\JD'R<5$-LFbրODH`ʤ? #FeJ$T+\S(#KPi Uq!Va;2\ d[]yFSO~$cs8MJ:32AXSgg)X`[̛3Q9fW_l?D oꓬ2"RFuJb@FZe3 oH,iA?-\`ƣcV_pA)s|l,wN".CHBfʶm&ZLs!SaD DWZv FmN_4:ZDD ZWQz1rU>_otcȑ?|Ct*FH{e@p|;i 6<[i88"k!X9m"ӂ!Y3t7w2T$` J(`m@oDC_]݄y_?>\y"ٮ]_=}[֛hnh~ͫ7ˮh y (qb8箑 4T廑=wa/jl}6gFn3最َjsMt(ǜaQ+\pD0#ӣ6__ޛ&ӯ{+ކ2v yr.hq8 HF_KzeFmm@56X(E%<.]oUv?׵U0 #f@\ :@Q\V7ԦJu UDh(-@ ٫~_~O?8wVG1Gm_/S׬2K,MOkעfQT,TԔd#m_ rP(v3oѵ'gqhh~5%J̹@V/WdK} /QT$ Ѫ/"i /\EIu3;& I~zX-C "Wjt[l[._2OI krۇKU+.BYۦ3Iʑ.m~uJ==~/:>ysCrMkBbе(MyQ\8/dSrC;*cX=kt7D/uGG` ]Q:%kʳp>ȉ\ƨź}Z浼h+;e"@yoLsw}7g>&Ah?ٱ93Y:%Wai`l4ux0ۿg/ßLT(*%"bq5H;4dƢe~iO!l1mH,FCW$oӶit3|é?nH{$s/+gHo1ZǸjQ .>2>l3_swR}*z&sY'P$-XΡ+lYC6ժԲhaV~_/A%-2u^HDA% &T1LϽKާR9<ߞ7qm䃴:hznCGi3\hLmHv![c)ɢX%_tNrQP cYWE`S{l}$/KyH%A_?TP>cJ(MЉM`ضS Sףc" t VMh={I\}M:5/1m/FK` $c]uaWޡS>lƦȞ:B*U"MjT`3 ,^U$*\ZVXUyS־棧:KJ ϼVˏgܬ^Z4AZ 2ĚEC>Z PTKt*}ܕ%(9m ".ʮılAMB*Je'JE!RDfFf{ӓ"IǨP>4d.ˋh#dD;vEcsr>\60G;WF: |UH:!2B*`$NbH37n XM0hU[IL`|P sV~_³c>1qLkD{4Y7ySJ+ԅ !FDD(B(;nڵniڥ˨`lS=` $Ifx+a2(%Il)\ ̯#nk_H\BZ`;.j 0ܹW?#wc!j  X&~ i;{RN([{WTГH$vv%UX =ф`R7Jb-2Rrny6o8>56푛QIIxe enyp*BMTݥHg vR~^5^qNbNJ[uC+lm^{yPTfcbX4;ejoRd-"K1JS}3ǥidqVUr١̰&&{7(iIGOwEQG!noU㙧@v~=Puhu6yY;lm,(~cU\SfS\FsA3<7ܪ(sXN<@h}mt'uQWJC-m686&*e֩7/ܒ2 :V0 o0 *]]O1oRq(c:P2 sxrq8eXD tQŞhe/G؈ *[@62$&|> d/4 7 PDtI2ݤXJvwڔX ma OAТD1TF*5 4[ IDAT`BPM$MT]y~}WP"tq.\Y"jSii+n"(VD9**v .*ah]O! wU jlLΊ lc{K|_ ;4U3ЀQ"IQ ̈́ݠOxnHfU*X0`Aqn+½/T䃵*6zWTD3%P͞cA;ۘ̂W"lwN-tIqB5 ݁5N(r?CUfBZA[bv(y_3C]i8n tz\ǎ`P K K 63D.BuN;Wt@;տn[7Pm״?Q2#p vE_8HnI8v>K4#ԝf]<'&"۫ljpV 12,x| gG5z"y'.ܼ(  {p+YZ!QT`YZcwL*T >yK1^^qnq%%hCH%@_t}puvp(@YtTX0\7KCEHfy_uST C%p(w9ekWew'˿wUz3K@DWu(IYy&D/޵.ő۶?AFx?Gx%(13Hmje] (ڽgB'F_yb% Jkʣ}E PF׮n]D 7? 6?}-*Z˾" V39RP xzs&nAΓ!a!J $uݲz.@_7g^VݱW{JpG)2\}u&&̴IENDB`tagua-1.0-alpha2/src/doxy/doxygen.css000066400000000000000000000110011077523320400175550ustar00rootroot00000000000000/******************************************************************************* Style sheet for kdelibs doxygen documentation. Copyright (c) Anders Lund 2002 This script is made available under the terms of the General Public License. You should have received a copy of the GNU General Public License along with this software; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ********************************************************************************/ body { margin: 0px; color: black; background-color: white; } a { color: #0000C0; } /* decorative header */ div.header { background-color: #298730; background-image: url("headerbg.png"); } div.header table { padding: 0px; margin: 0px } div.header table tr td h1 { color: white; font: bold 20pt courier; padding-top: 0.5em; } /* global lind buttons at bottom of decorative header */ table.links { float: right; border:0; padding-left:1px } table.links td a { color: white } table.links td:hover { background-color:#0C4293; } table.links td a:hover { color: white; background-color:#0C4293 } table.links td { border-left: 1px solid #4A81D5; /*padding: 0px 12px 0px 12px;*/ background-color:#0E4EAF; font-size:9pt; /*font-weight: bold;*/ } /* little gradient below decorative/navigation header */ div#hgrad { height: 12px; background-image: url("grad.png"); } /* contents part of page */ div.text { margin: 12px } /* contents, mostly equivalent to the default doxugen style sheet */ H1 { text-align: center; } CAPTION { font-weight: bold } A.qindex {} A.qindexRef {} A.el { text-decoration: none; font-weight: bold } A.elRef { font-weight: bold } A.code { text-decoration: none; font-weight: normal; color: #4444ee } A.codeRef { font-weight: normal; color: #4444ee } A:hover { text-decoration: none; background-color: #ececec } DL.el { margin-left: -1cm } DIV.fragment { width: 100%; border: none; background-color: #ffffee; padding: 12px } DIV.ah { background-color: navy; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } TABLE.mdTable { background-color: #f8f8f8; border: .2em solid #d7d7d7; } TD.mdRow { padding: 8px 20px; } TD.md { font-weight: bold; } TD.mdname1 { font-weight: bold; color: #602020; } TD.mdname { font-weight: bold; color: #602020; width: 600px; } DIV.groupHeader { margin-left: 16px; margin-top: 12px; margin-bottom: 6px; font-weight: bold } DIV.groupText { margin-left: 16px; font-style: italic; font-size: smaller } BODY { background: white } TD.memItemLeft { padding: 1px 0px 0px 8px; margin: 4px; border: solid .1em white; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #f8f8f8; } TD.memItemRight { padding: 1px 0px 0px 8px; margin: 4px; border: solid .1em white; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #f8f8f8; } TD.indexkey { background-color: #e0eef8; font-weight: bold; padding-right : 10px; padding-top : 2px; padding-left : 10px; padding-bottom : 2px; margin-left : 0px; margin-right : 0px; margin-top : 2px; margin-bottom : 2px } TD.indexvalue { background-color: #e0eef8; font-style: normal; padding-right : 10px; padding-top : 2px; padding-left : 10px; padding-bottom : 2px; margin-left : 0px; margin-right : 0px; margin-top : 2px; margin-bottom : 2px } SPAN.keyword { color: #008000 } SPAN.keywordtype { color: #604020 } SPAN.keywordflow { color: #e08000 } SPAN.comment { color: #800000 } SPAN.preprocessor { color: #806020 } SPAN.stringliteral { color: #002080 } SPAN.charliteral { color: #008080 } /* kde decoration at bottom */ div#bottom-nav { position : relative; background-color: transparent; /*width : 100%;*/ /*top: 0px; left: 0px; right: 0px; margin-left: 0px; margin-right:0px;*/ margin-top: 12px; height: 50px; background-image : url('bottom1.png'); background-repeat : repeat-x; } /* copyright etc at bottom */ div.bottom { margin: 12px; font-size: 9pt; text-align: right; } div.bottom a { color: #aaaaaa } tagua-1.0-alpha2/src/doxy/footer.html000066400000000000000000000010401077523320400175540ustar00rootroot00000000000000

KDE Logo
This file is part of the documentation for $projectname $projectnumber.
Documentation copyright © 1998-2005 the KDevelop developers.
Generated on $datetime by doxygen $doxygenversion written by Dimitri van Heesch, © 1997-2005
tagua-1.0-alpha2/src/doxy/grad.png000066400000000000000000000003701077523320400170200ustar00rootroot00000000000000PNG  IHDR /C=gAMA a-PLTERPR@|tRNS@fbKGDH pHYs  d_tIME,/4IDATxcpP`Hr` v`  @A 0I#ϫIENDB`tagua-1.0-alpha2/src/doxy/header.html000066400000000000000000000032441077523320400175160ustar00rootroot00000000000000 $title ($projectname)
tagua-1.0-alpha2/src/doxy/headerbg.png000066400000000000000000000007551077523320400176530ustar00rootroot00000000000000PNG  IHDRxuogAMA abKGD pHYs  ~tIME(PjIDATxA@PAssQCAuA ?`O;MY}r?or@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHI9 )$値r@RHIuoIENDB`tagua-1.0-alpha2/src/doxy/logo.png000066400000000000000000000211511077523320400170430ustar00rootroot00000000000000PNG  IHDRxUV : pHYs  #u IDATxݝ_׽?6T@)m, d&1&1ģXЃe`arYs{ βlL`7!Q.lV҃W-ʹB%@5h PnS}8uNn9};U'@[y^8`Cpuy~6^l#!{ݏf\aȥK|c{G U8NeE˾y=0M4vK ζ+~ݮv!2F Gz]9^\nyu*' 8.gw.;+ 2mYl7+E(3ڏ׵{h*M[c)m&o!DAތ5D2r3gRblH@9<rj7 тd`*iCѵZ%o#@cSHµnkrV z^C 8H}z)=RNHҜkn@ȭgqvοMjcydqUp1$Ic?je~7L6o> >iV܋G9z(9s0r1~¿})w70z΅.c!#+cQ\b 6ktAi,> :>+/X\f"% [^?2IE[_\Ƈ}ԑdȝ>--\dODݶnQޯt?>뺰ȤFdg?oS=8ix =O4ٹ# :q,![qTF| r-O=Bd9W>N"H.'12ϕq KKl~I~_d=`R`uitl / T&I׾8ws7\C,ĽVu+p<)>@33H6RʐR&j]iN2<!w/ er䃏ս˭:BH&xe8RZBtU5݌㓿.x PFQY=ț@JB*K- XWJSq4'אkv0Bq!THF@J;yn?I mc*pȓLRoﮒ+%l"\7j{^\Gt\6 {W9pu|᱑+w8G9'h7.5"@IZ! CrX)-gJy %W$MBoV 8. q<6%n3z>?9fZFrk3d@t4.EX,0=)ݲJ!W3!Ǖ1x|RF|Oc#X]7:J=Yb*5hmqr0Te79JT+X}^dDJ\0V:)T{W(Tn<ڔ /K}xh,mʋ$O~-Okr'\ȕ71HlGzbVM]._ R": [M \6ݱ\ݭseK规!NDKx <1!'^ȵHFqDTg"YF绲:KMJo!¹eނypeD.RNj7qTwyk@:J`3X;B0'Mx7z=$R)4OGFnqi"BPY\d@} Tved"l>zoVTO`A2  2)c>ȈwczK=D%?gnZse!} G􏳢i4 =gוTt[$lx7"Gpԫ&%zTʵcmr;TMIy -$yFo<CӾB. w P˘5 O!Bn)+aLT5EyXgY=.%z'{}gU!d=V=|ݻ΍;Cq5x bo6ڍcuzfRB+c8<]ԗ7/ιy:y#Vڛ,Ӛ]{/"o2ZO).& ~~e?(UcLٖńd ނ !JN2_(DJM7eqN߹aB5VM!\g6%~ƬZCt`*kǁe6o|Q1BͳQJp̧wr_"x ڢycqpQW|pF7Mld҅Jnm=@x&+\ <3e*qxBނS"Vp c]9)_)p[ %OSݮ[0ԋyh7aK߼KlpW԰ʠJTۆBw~vq!|Pd"!J I}QM \$%O׽.*e0Q!(#ڋ1HwcBH;I־DA8:dee>H._ pM5V)Jt./,}aN+Eaʕ˱u\&<3ϩyȭV`.T[EkU%.#݉*d=Ø4MZ)醋@t|4(CỈ Ƀ!Xar֋"|W,#2)p"<ؗx >#M)2X Cn#ʞ_.8`Mg+whO֝j®Us/!'LdcIflYN2Jt^Lt/fU`! ڍo D>~B6TYr0N^ٺK⽄(Arˢ5Ƞq:XM~"%t}|þ$ɪnD 2+9甃S;Q/ q20(6X3{&MhA!}($Og9rb2YIK.r5$˸^Z+Y}aoaY<)',MA2ϕXWg9GWJkchmB#\m8܍-K*kTˀ\W Z +sBʵzG=Q u||W++G[=s?>O4o%eG/dyNWO3x([`+@eXpIV3J֖)WVc!̘0G9 Gނ$MTaCO{Wndk%DQ `#' mh{>^# ]=Q˺rdHqE(.S6R?ބ]?H [{Lo$)@LV.JY.JXnVl$Sb]WFa;1(%\ 0+Y񫬀TJFVL+QQ i9?l܊u)CBGUQ]+2.ჷ=|$(Cv>!xƙ zOBG&$ >wgx*笰D`-Բs∝v{=\)]u:ۃ*7SW.!Xh՛jE>J ^QlR3R#Ť4F9ŀ+/.q .]; /PSf[`VlqZ$f6愃5Y2 p7 8\4VnAvuqsE:-W4]سBjiK2ᅥ-d,-o;eWJx&c?ӻl~]\\gaVSʥuᄍLZ}B\QSwc`Zr&4@>7~ɫg3!7_uܠϱJxB4l\OӁQXsՈCnאl2*v7>bRjɚr8UA 2*FY/]wY[Y!X z3%dYNW.5w_TG%x/oI9#1IOYQcj:PESs{ZpӁXM]浩Ӝsn}E6^bgF$i@~PyXHiRRRmي9#Iσ+n^{-% Z-UA[w/eMѽzjM*v]/PzZ-rwI  [w"[7[yдfEڝ-E3-üӂ`}\Ԯיgm`/s⓿E~ʩWX*K m\TB8۷ws_Z!ydRyE1܋j YlU)F 會Ł8ָ\w,6܍9mkvq' ⽘KBShmiP06rT ~5v8k2=\E7k͋grp6bB&R-z0O^ D ǔrIDAT@/b }V!x"FpeD.FX8XQokQvԯ<@{=fr6E7X]?6r~Q!vij%sDTmQfm\sum*U׋\alڽ"!zVJsZO*̓5mׄܶ9n?sۑhsCAd9X+jo,ԶhZosAncYH`Q(*Íy]m!sF#6@nR~5o D<9FZ3Za\8\qp99KZm+ P|\Bs`͌ (c) 2006 Maurizio Monge 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. */ #include "engine.h" #include #define ENGINE_DEBUG #ifdef ENGINE_DEBUG #include #endif using namespace boost; Engine::Engine(const QString& path, const QStringList& arguments) : m_path(path) , m_arguments(arguments) ,m_side(-1) { connect(&m_engine, SIGNAL(readyReadStandardOutput()), this, SLOT(processInput())); connect(&m_engine, SIGNAL(started()), this, SLOT(engineRunning())); connect(&m_engine, SIGNAL(finished(int, QProcess::ExitStatus)), this, SIGNAL(lostConnection())); } Engine::~Engine() { } void Engine::start() { if (!m_workPath.isNull()) m_engine.setWorkingDirectory(m_workPath); m_engine.setOutputChannelMode(KProcess::OnlyStdoutChannel); m_engine.setProgram(m_path, m_arguments); m_engine.start(); initializeEngine(); } void Engine::engineRunning() { Q_ASSERT(m_engine.state() == QProcess::Running); while (!m_command_queue.empty()) { sendCommand(m_command_queue.front(), false); m_command_queue.pop(); } } void Engine::sendCommand(const QString& command, bool echo) { if (echo && m_console) m_console->echo(command); if (m_engine.state() == QProcess::Running) { QTextStream os(&m_engine); os << command << "\n"; #ifdef ENGINE_DEBUG kDebug() << "" << m_side << ">" << command; #endif } else { m_command_queue.push(command); } } void Engine::processInput() { // process only full lines while (m_engine.canReadLine()) { QString line = m_engine.readLine(); line.remove("\n").remove("\r"); #ifdef ENGINE_DEBUG kDebug() << m_side << "<" << line; #endif if (m_console) m_console->displayText(line + "\n", 0); receivedCommand(line); } } void Engine::textNotify(const QString& text) { sendCommand(text, false); } void Engine::setNotifier(const shared_ptr& notifier) { m_notifier = notifier; } void Engine::setConsole(const shared_ptr& console) { m_console = console; } tagua-1.0-alpha2/src/engine.h000066400000000000000000000054521077523320400160360ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ENGINE_H #define ENGINE_H #include #include #include #include "console.h" #include "tagua.h" class EngineNotifier; /** * @brief An external chess engine. * * This class incapsulates a connection with * an external engine process in a protocol * independent way. */ class Engine : public QObject, public TextNotifier { Q_OBJECT protected: QString m_path; QStringList m_arguments; KProcess m_engine; QString m_workPath; boost::shared_ptr m_console; boost::weak_ptr m_notifier; std::queue m_command_queue; int m_side; virtual void initializeEngine() = 0; public: /** * Create an engine, setting the path to the engine * program and its arguments. */ Engine(const QString& path, const QStringList& arguments); void setWorkingPath(const QString& workPath) { m_workPath = workPath; } void setSide(int side) { m_side = side; } virtual ~Engine(); /** * Start the engine program. The initialization will * take place automatically after the program has started. */ void start(); /** * Send a command to the engine. */ void sendCommand(const QString& command, bool echo = true); /** * Send a move to the engine. */ virtual void sendMove(AbstractMove::Ptr move, AbstractPosition::Ptr ref) = 0; /** * Back up a move. * @param pos The position before the move. Used if the engine * does not support the undo command. */ virtual void backUp(AbstractPosition::Ptr pos) = 0; virtual void setBoard(AbstractPosition::Ptr pos, int halfmove, int fullmove) = 0; virtual void startAnalysis() = 0; virtual void stopAnalysis() = 0; /** * Begin a new game. */ virtual void reset() = 0; /** * Start playing. */ virtual void play() = 0; /** * Stop the engine. */ virtual void stop() = 0; /** * Receive a user command. */ virtual void textNotify(const QString& text); void setNotifier(const boost::shared_ptr& notifier); void setConsole(const boost::shared_ptr& console); private Q_SLOTS: void engineRunning(); void processInput(); Q_SIGNALS: /** * Emitted when the engine sends a command to the interface. */ void receivedCommand(const QString& command); /** * Emitted when the engine exits (or crashes, etc...). */ void lostConnection(); }; #endif // ENGINE_H tagua-1.0-alpha2/src/engineinfo.cpp000066400000000000000000000040471077523320400172440ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "engineinfo.h" #include "xboardengine.h" #include "gnushogiengine.h" #include "ui.h" #include using namespace boost; void EngineDetails::load(Settings s) { s["name"] >> name; s["path"] >> path; type = typeFromName(s["type"].value()); if (s["work-path"]) s["work-path"] >> workPath; } void EngineDetails::save(Settings s) { s["name"] = name; s["path"] = path; s["type"] = typeName(type); s["work-path"] = workPath; } void EngineInfo::playAsWhite() { playAs(0); } void EngineInfo::playAsBlack() { playAs(1); } void EngineInfo::playAs(int player) { if (m_token[player].valid()) { m_ui.removeEntity(m_token[player]); m_token[player] = EntityToken(); } else { m_token[player] = m_ui.addPlayingEngine(player, engine(player)); } } // void EngineInfo::analyze() { // if (m_token.valid()) { // m_ui.removeAnalysingEngine(m_token); // m_token = EntityToken(); // } // else // m_token = m_ui.addAnalysingEngine(engine()); // } EngineInfo::EngineInfo(const EngineDetails& details, UI& ui) : QObject(&ui) , m_details(details) , m_ui(ui) { } shared_ptr EngineInfo::engine(int player) { shared_ptr res; if (m_details.type == EngineDetails::XBoard) res = shared_ptr(new XBoardEngine(m_details.path, QStringList())); else if (m_details.type == EngineDetails::GNUShogi) res = shared_ptr(new GNUShogiEngine(m_details.path, QStringList())); else { kError() << "Unimplemented engine type" << EngineDetails::typeName(m_details.type); return shared_ptr(); } if (res) { res->setWorkingPath(m_details.workPath); res->setSide(player); } return res; } tagua-1.0-alpha2/src/engineinfo.h000066400000000000000000000040551077523320400167100ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ENGINEINFO_H #define ENGINEINFO_H #include #include #include #include "controllers/entitytoken.h" #include "settings.h" class Engine; class UI; struct EngineDetails { enum EngineType { XBoard, UCI, TaguaText, TaguaDBUS, GNUShogi, Unknown }; QString name; QString path; EngineType type; QString workPath; EngineDetails(const QString& name, const QString& path, const EngineType& type) : name(name), path(path), type(type) { } EngineDetails() { } static QString typeName(EngineType t) { switch (t) { case XBoard: return "xboard"; case UCI: return "UCI"; case TaguaText: return "tagua-text"; case TaguaDBUS: return "tagua-dbus"; case GNUShogi: return "gnushogi"; default: return "unknown"; } } static EngineType typeFromName(const QString& name) { if (name == "xboard") return XBoard; else if (name == "UCI") return UCI; else if (name == "tagua-text") return TaguaText; else if (name == "tagua-dbus") return TaguaDBUS; else if (name == "gnushogi") return GNUShogi; else return Unknown; } void load(Settings s); void save(Settings s); }; class EngineInfo : public QObject { Q_OBJECT EngineDetails m_details; UI& m_ui; EntityToken m_token[2]; protected: virtual boost::shared_ptr engine(int player); void playAs(int player); public: EngineInfo(const EngineDetails& details, UI& ui); void setWorkPath(const QString& wp) { m_details.workPath = wp; } public Q_SLOTS: void playAsWhite(); void playAsBlack(); // void analyze(); }; #endif // ENGINEINFO_H tagua-1.0-alpha2/src/enginenotifier.h000066400000000000000000000013061077523320400175700ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ENGINENOTIFIER_H #define ENGINENOTIFIER_H #include class QString; class EngineNotifier : public boost::enable_shared_from_this { public: virtual ~EngineNotifier() { } virtual void notifyEngineMove(const QString&) = 0; }; #endif // ENGINENOTIFIER_H tagua-1.0-alpha2/src/entities/000077500000000000000000000000001077523320400162365ustar00rootroot00000000000000tagua-1.0-alpha2/src/entities/engineentity.cpp000066400000000000000000000053721077523320400214530ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "engineentity.h" #include #include "game.h" #include "engine.h" #include using namespace boost; EngineEntity::EngineEntity(const VariantPtr& variant, const shared_ptr& game, int side, const shared_ptr& engine, AgentGroup* group) : Entity(game) , m_variant(variant) , m_side(side) , m_last_index(0) , m_playing(false) , m_engine(engine) , m_dispatcher(group, this) { } void EngineEntity::setup() { // setup engine m_engine->setNotifier(shared_from_this()); m_engine->start(); m_engine->reset(); // find all indexes of the current variation std::stack m_indexes; Index index = m_game->index(); while (index != 0) { m_indexes.push(index); kDebug() << "pushed index " << index; index = index.prev(); } // set engine state playing all moves // in the current variation while (!m_indexes.empty()) { PositionPtr pos = m_game->position(index); kDebug() << "REF:"; pos->dump(); index = m_indexes.top(); m_indexes.pop(); MovePtr move = m_game->move(index); kDebug() << "move = " << move->toString("simple", pos); m_engine->sendMove(move, pos); } m_last_index = m_game->index(); checkPlaying(); } void EngineEntity::notifyEngineMove(const QString& move_str) { AbstractMove::Ptr move = position()->getMove(move_str); if (position()->testMove(move)) { Q_ASSERT(move); AbstractPosition::Ptr ref = position(); AbstractPosition::Ptr pos = ref->clone(); pos->move(move); m_game->add(move, pos); m_last_index = m_game->index(); m_dispatcher.move(m_game->index()); } else kError() << "Engine attempted to execute an invalid move:" << move_str; } void EngineEntity::checkPlaying() { if (!m_playing && m_side == m_game->position(m_last_index)->turn()) { m_engine->play(); m_playing = true; } } void EngineEntity::notifyMove(const Index& index) { if (index == m_last_index) { // TODO: check for consistency and update if necessary } else if (index.prev() == m_last_index) { // play move m_engine->sendMove(m_game->move(index), m_game->position(index.prev())); m_last_index = index; checkPlaying(); } else { // TODO: handle move notification in arbitrary indexes kWarning() << "engine entity can't handle index" << index << "(m_last_index =" << m_last_index << ")"; } } tagua-1.0-alpha2/src/entities/engineentity.h000066400000000000000000000027211077523320400211130ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ENGINEENTITY_H #define ENGINEENTITY_H #include "agent.h" #include "agentgroup.h" #include "enginenotifier.h" #include "entity.h" #include "index.h" #include "tagua.h" #include "fwd.h" class Engine; class EngineEntity : public Entity , public Agent , public EngineNotifier { VariantPtr m_variant; int m_side; Index m_last_index; bool m_playing; boost::shared_ptr m_engine; AgentGroupDispatcher m_dispatcher; void checkPlaying(); public: boost::shared_ptr engine() { return m_engine; } EngineEntity(const VariantPtr& variant, const boost::shared_ptr&, int side, const boost::shared_ptr& engine, AgentGroup* group); void setup(); virtual void notifyEngineMove(const QString&); virtual bool canDetach() const { return true; } virtual void notifyClockUpdate(int, int) { } virtual void notifyMove(const Index& index); virtual void notifyBack() { } virtual void notifyForward() { } virtual void notifyGotoFirst() { } virtual void notifyGotoLast() { } }; #endif // ENGINEENTITY_H tagua-1.0-alpha2/src/entities/entity.cpp000066400000000000000000000012401077523320400202530ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "entity.h" #include "game.h" Entity::Entity(const GamePtr& game) : m_enabled(true) , m_highlight(true) , m_game(game) { } Entity::~Entity() { } GamePtr Entity::game() const { return m_game; } PositionPtr Entity::position() const { return m_game->position(); } tagua-1.0-alpha2/src/entities/entity.h000066400000000000000000000020651077523320400177260ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ENTITY_H #define ENTITY_H #include "fwd.h" #include "usermove.h" class Entity { protected: bool m_enabled : 1; bool m_highlight : 1; GamePtr m_game; public: explicit Entity(const GamePtr& game); /** * Detach from dependent resource disposing it. */ virtual ~Entity(); bool highlight() const { return m_highlight; } void setHighlight(bool highlight) { m_highlight = highlight; } void setEnabled(bool enabled) { m_enabled = enabled; } virtual bool canDetach() const = 0; /** * Detach from dependent resource without disposing it. */ virtual void detach() { } GamePtr game() const; PositionPtr position() const; }; #endif // ENTITY_H tagua-1.0-alpha2/src/entities/examinationentity.cpp000066400000000000000000000074111077523320400225160ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "examinationentity.h" #include "game.h" #include "icsconnection.h" #include "positioninfo.h" #include "pgnparser.h" #include "hlvariant/chess/piece.h" #include "icsapi.h" #include ExaminationEntity::ExaminationEntity(const VariantPtr& variant, const boost::shared_ptr& game, int game_number, const boost::shared_ptr& connection, AgentGroup* group) : UserEntity(game) , m_variant(variant) , m_icsapi(variant->icsAPI()) , m_game_number(game_number) , m_connection(connection) , m_dispatcher(group, this) { Q_ASSERT(m_icsapi); } QString ExaminationEntity::save() const { return m_game->pgn(); } void ExaminationEntity::loadPGN(const PGN& pgn) { m_game->load(pgn); } AbstractMove::Ptr ExaminationEntity::testMove(const NormalUserMove&) const { return AbstractMove::Ptr(); } AbstractMove::Ptr ExaminationEntity::testMove(const DropUserMove&) const { return AbstractMove::Ptr(); } bool ExaminationEntity::testPremove(const NormalUserMove&) const { return false; } bool ExaminationEntity::testPremove(const DropUserMove&) const { return false; } void ExaminationEntity::executeMove(boost::shared_ptr) { } void ExaminationEntity::addPremove(const NormalUserMove&) { } void ExaminationEntity::addPremove(const DropUserMove&) { } void ExaminationEntity::cancelPremove() { } InteractionType ExaminationEntity::validTurn(const Point&) const { return NoAction; } InteractionType ExaminationEntity::validTurn(int) const { return NoAction; } bool ExaminationEntity::movable(const Point&) const { return false; } bool ExaminationEntity::jump(const Index&) { return true; } bool ExaminationEntity::gotoFirst() { m_connection->sendText("back 99999"); return true; } bool ExaminationEntity::gotoLast() { m_connection->sendText("forward 99999"); return true; } bool ExaminationEntity::goTo(const Index& index) { std::pair steps = m_game->index().stepsTo(index); if (steps.first == 0) { m_connection->sendText(QString("forward %1").arg(steps.second)); return true; } else if (steps.second == 0) { m_connection->sendText(QString("back %1").arg(steps.first)); return true; } else return false; } bool ExaminationEntity::forward() { m_connection->sendText("forward"); return true; } bool ExaminationEntity::back() { m_connection->sendText("back"); return true; } bool ExaminationEntity::undo() { return true; } bool ExaminationEntity::redo() { return true; } bool ExaminationEntity::truncate() { return true; } bool ExaminationEntity::promoteVariation() { return true; } void ExaminationEntity::notifyStyle12(const PositionInfo& style12, bool /*is_starting*/) { m_dispatcher.clockUpdate(style12.whiteTime, style12.blackTime); if (style12.index() > 0) { MovePtr last_move = m_icsapi->parseVerbose(style12.lastMove, style12.position); m_game->insert(last_move, style12.position, style12.index()); } m_game->goTo(style12.index()); } void ExaminationEntity::notifyPool(const class PoolInfo&) { /*TODO */ } void ExaminationEntity::notifyMoveList(int, AbstractPosition::Ptr, const PGN&){ /* TODO */ } void ExaminationEntity::notifyMove(const Index&) { } void ExaminationEntity::notifyBack() { } void ExaminationEntity::notifyForward() { } void ExaminationEntity::notifyGotoFirst() { } void ExaminationEntity::notifyGotoLast() { } bool ExaminationEntity::attach() { return m_game->lastMainlineIndex() == 0; } tagua-1.0-alpha2/src/entities/examinationentity.h000066400000000000000000000045401077523320400221630ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef EXAMINATIONENTITY_H #define EXAMINATIONENTITY_H #include "userentity.h" #include "tagua.h" #include "icslistener.h" #include "agent.h" #include "agentgroup.h" #include "fwd.h" class ICSConnection; class ExaminationEntity : public UserEntity , public ICSListener { VariantPtr m_variant; ICSAPIPtr m_icsapi; int m_game_number; boost::shared_ptr m_connection; AgentGroupDispatcher m_dispatcher; public: ExaminationEntity(const VariantPtr&, const boost::shared_ptr&, int, const boost::shared_ptr&, AgentGroup*); virtual QString save() const; virtual void loadPGN(const PGN&); virtual AbstractMove::Ptr testMove(const NormalUserMove&) const; virtual AbstractMove::Ptr testMove(const DropUserMove&) const; virtual bool testPremove(const NormalUserMove&) const; virtual bool testPremove(const DropUserMove&) const; virtual void executeMove(boost::shared_ptr); virtual void addPremove(const NormalUserMove&); virtual void addPremove(const DropUserMove&); virtual void cancelPremove(); virtual InteractionType validTurn(const Point&) const; virtual InteractionType validTurn(int) const; virtual bool movable(const Point&) const; virtual bool jump(const Index&); virtual bool gotoFirst(); virtual bool gotoLast(); virtual bool goTo(const Index&); virtual bool forward(); virtual bool back(); virtual bool undo(); virtual bool redo(); virtual bool truncate(); virtual bool promoteVariation(); virtual void notifyStyle12(const PositionInfo&, bool is_starting); virtual void notifyPool(const class PoolInfo&); virtual void notifyMoveList(int, AbstractPosition::Ptr, const PGN&); virtual void notifyClockUpdate(int, int) { } virtual void notifyMove(const Index&); virtual void notifyBack(); virtual void notifyForward(); virtual void notifyGotoFirst(); virtual void notifyGotoLast(); virtual bool attach(); }; #endif // EXAMINATIONENTITY_H tagua-1.0-alpha2/src/entities/gameentity.cpp000066400000000000000000000105361077523320400211150ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "gameentity.h" #include "premove.h" #include "game.h" #include "board.h" #include "pgnparser.h" using namespace boost; GameEntity::GameEntity(const VariantPtr& variant, const boost::shared_ptr& game, Board* chessboard, AgentGroup* group) : UserEntity(game) , m_variant(variant) , m_chessboard(chessboard) , m_dispatcher(group, this) { } QString GameEntity::save() const { return ((m_variant->name() == "Chess") ? QString() : ("[Variant \"" + m_variant->name()) + "\"]\n") + m_game->pgn(); } void GameEntity::loadPGN(const PGN& pgn) { m_game->load(pgn); } AbstractPosition::Ptr GameEntity::doMove(AbstractMove::Ptr move) const { AbstractPosition::Ptr newPosition = position()->clone(); newPosition->move(move); return newPosition; } void GameEntity::executeMove(AbstractMove::Ptr move) { AbstractPosition::Ptr ref = position(); AbstractPosition::Ptr pos = doMove(move); m_game->add(move, pos); m_dispatcher.move(m_game->index()); } void GameEntity::addPremove(const NormalUserMove& m) { m_premoveQueue = shared_ptr(new Premove(m_variant->createNormalMove(m))); } void GameEntity::addPremove(const DropUserMove& m) { m_premoveQueue = shared_ptr(new Premove(m_variant->createDropMove(m))); } void GameEntity::cancelPremove() { m_premoveQueue.reset(); m_chessboard->cancelPremove(); } void GameEntity::notifyMove(const Index&) { // the other player moved: execute premove if (m_premoveQueue) { AbstractMove::Ptr move = m_premoveQueue->execute(m_game->position()); if (move) executeMove(move); } cancelPremove(); } void GameEntity::notifyBack() { } void GameEntity::notifyForward() { } void GameEntity::notifyGotoFirst() { } void GameEntity::notifyGotoLast() { } NormalUserMove GameEntity::createMove(const Point& from, const Point& to) const { NormalUserMove m = UserEntity::createMove(from, to); m_variant->setupMove(m); return m; } AbstractMove::Ptr GameEntity::testMove(const NormalUserMove& move) const { AbstractMove::Ptr m = m_variant->createNormalMove(move); if (m && position()->testMove(m)) return m; else return AbstractMove::Ptr(); } AbstractMove::Ptr GameEntity::testMove(const DropUserMove& move) const { AbstractMove::Ptr m = m_variant->createDropMove(move); if (m && position()->testMove(m)) return m; else return AbstractMove::Ptr (); } AbstractPiece::Ptr GameEntity::moveHint(AbstractMove::Ptr move) const { return position()->moveHint(move); } bool GameEntity::testPremove(const NormalUserMove&) const { return true; // TODO } bool GameEntity::testPremove(const DropUserMove&) const { return true; // TODO } InteractionType GameEntity::validTurn(int pool) const { return position()->droppable(m_turn_test, pool); } InteractionType GameEntity::validTurn(const Point& point) const { // TODO: maybe replace this call with a new API position()->owner(point) ?? return position()->movable(m_turn_test, point); } bool GameEntity::movable(const Point& point) const { if (!m_enabled) return false; InteractionType action = validTurn(point); return m_turn_test.premove() ? action != NoAction : action == Moving; } bool GameEntity::oneClickMoves() const { return m_variant->simpleMoves(); } bool GameEntity::gotoFirst() { m_game->gotoFirst(); return true; } bool GameEntity::gotoLast() { m_game->gotoLast(); return true; } bool GameEntity::goTo(const Index& index) { m_game->goTo(index); return true; } bool GameEntity::forward() { return m_game->forward(); } bool GameEntity::back() { return m_game->back(); } bool GameEntity::undo() { if (m_editing_tools) m_game->undo(); return true; } bool GameEntity::redo() { if (m_editing_tools) m_game->redo(); return true; } bool GameEntity::truncate() { if (m_editing_tools) m_game->truncate(); return true; } bool GameEntity::promoteVariation() { if (m_editing_tools) m_game->promoteVariation(); return true; } bool GameEntity::canDetach() const { return true; } tagua-1.0-alpha2/src/entities/gameentity.h000066400000000000000000000045201077523320400205560ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef GAMEENTITY_H #define GAMEENTITY_H #include "userentity.h" #include "agent.h" #include "agentgroup.h" #include "fwd.h" class Board; class GameEntity : public UserEntity { VariantPtr m_variant; Board* m_chessboard; AgentGroupDispatcher m_dispatcher; boost::shared_ptr m_premoveQueue; AbstractPosition::Ptr doMove(AbstractMove::Ptr move) const; public: GameEntity(const VariantPtr& variant, const boost::shared_ptr& game, Board* chessboard, AgentGroup* group); /** * Return a PGN for the game. */ virtual QString save() const; /** * Load the content of a PGN inside the game. */ virtual void loadPGN(const PGN& pgn); virtual void executeMove(AbstractMove::Ptr move); virtual void addPremove(const NormalUserMove& m); virtual void addPremove(const DropUserMove& m); virtual void cancelPremove(); virtual void notifyClockUpdate(int, int) { } virtual void notifyMove(const Index&); virtual void notifyBack(); virtual void notifyForward(); virtual void notifyGotoFirst(); virtual void notifyGotoLast(); virtual NormalUserMove createMove(const Point& from, const Point& to) const; virtual AbstractMove::Ptr testMove(const NormalUserMove&) const; virtual AbstractMove::Ptr testMove(const DropUserMove&) const; virtual AbstractPiece::Ptr moveHint(AbstractMove::Ptr move) const; virtual bool testPremove(const NormalUserMove&) const; virtual bool testPremove(const DropUserMove&) const; virtual InteractionType validTurn(const Point&) const; virtual InteractionType validTurn(int) const; virtual bool movable(const Point&) const; virtual bool oneClickMoves() const; virtual bool gotoFirst(); virtual bool gotoLast(); virtual bool goTo(const Index& index); virtual bool forward(); virtual bool back(); virtual bool undo(); virtual bool redo(); virtual bool truncate(); virtual bool promoteVariation(); virtual bool canDetach() const; }; #endif // GAMEENTITY_H tagua-1.0-alpha2/src/entities/icsentity.cpp000066400000000000000000000147731077523320400207710ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "icsentity.h" #include #include "game.h" #include "icsconnection.h" #include "positioninfo.h" #include "poolinfo.h" #include "icsapi.h" using namespace boost; class ICSTurnPolicy : public TurnPolicy::Abstract { const ICSEntity* m_entity; public: ICSTurnPolicy(const ICSEntity* entity); virtual bool check() const; }; ICSTurnPolicy::ICSTurnPolicy(const ICSEntity* entity) : m_entity(entity) { } bool ICSTurnPolicy::check() const { return m_entity->canEdit(); } class ICSPremovePolicy : public TurnPolicy::Premove { const ICSEntity* m_entity; public: ICSPremovePolicy(const ICSEntity* entity); virtual bool check() const; }; ICSPremovePolicy::ICSPremovePolicy(const ICSEntity* entity) : m_entity(entity) { } bool ICSPremovePolicy::check() const { return !m_entity->canEdit(); } ICSEntity::ICSEntity(const VariantPtr& variant, const shared_ptr& game, int side, int gameNumber, const shared_ptr& connection, AgentGroup* group) : Entity(game) , m_variant(variant) , m_icsapi(variant->icsAPI()) , m_connection(connection) , m_side(side) , m_game_number(gameNumber) , m_editing_mode(false) , m_dispatcher(group, this) { Q_ASSERT(m_icsapi); } AbstractPosition::Ptr ICSEntity::position() const { return m_game->position(); } void ICSEntity::executeMove(AbstractMove::Ptr) { } void ICSEntity::updateGame(const Index& index, AbstractMove::Ptr icsMove, AbstractPosition::Ptr icsPos) { if (index > 0 && m_game->containsIndex(index.prev()) && icsMove) { if (AbstractPosition::Ptr position = m_game->position(index.prev())) { position = position->clone(); if (position->testMove(icsMove)) { position->move(icsMove); icsPos->copyPoolFrom(position); if (!position->equals(icsPos)) kDebug() << "[inconsistency] computed position differs from expected!"; } else kDebug() << "[inconsistency] invalid move from server!"; } } if (m_game->lastMainlineIndex() > index) m_game->truncate(index); m_game->insert(icsMove, icsPos, index); m_game->goTo(index); m_dispatcher.move(index); } ICSEntity::UpdateType ICSEntity::getUpdate(const Index& index) { std::pair steps = m_game->index().stepsTo(index); if (steps.first == 0) { if (steps.second == 0) return NoMove; else if (steps.second == 1) return MoveForward; else return Forward; } else if (steps.first == 1 && steps.second == 0) return MoveBack; else if (steps.second == 0) return Back; return NonComparableIndexes; } void ICSEntity::notifyStyle12(const PositionInfo& style12, bool is_starting) { if (style12.gameNumber != m_game_number) return; m_dispatcher.clockUpdate(style12.whiteTime, style12.blackTime); // get last move verbose notation AbstractMove::Ptr last_move; if (!is_starting) last_move = m_icsapi->parseVerbose(style12.lastMove, style12.position); if (style12.index() > 0 && m_game->containsIndex(style12.index() - 1) && last_move && m_variant->name() != "Dummy") { AbstractPosition::Ptr position = m_game->position(style12.index() - 1); if (position) { AbstractMove::Ptr mv = position->getMove(style12.lastMoveSAN); if (!mv || !mv->equals(last_move)) { kDebug() << "[server inconsistency] SAN for last move is different from verbose notation" ; } } } if (style12.index() > 0 && m_variant->name() != "Dummy" && (!m_game->containsIndex(style12.index() - 1) || !m_game->position(style12.index() - 1)) ) requestMoves(); updateGame(style12.index(), last_move, style12.position); } void ICSEntity::notifyPool(const PoolInfo& pi) { if (pi.m_game_num != m_game_number) return; return; // BROKEN if (m_game->containsIndex(pi.m_pos_index)) { AbstractPosition::Ptr p = m_game->position(pi.m_pos_index); //BROKEN //p->setPool(pi.m_pool); m_game->insert(m_game->move(pi.m_pos_index), p, pi.m_pos_index ); } } void ICSEntity::notifyMoveList(int num, AbstractPosition::Ptr pos, const PGN& pgn) { if (m_game_number != num) return; if(pos->variant() != m_variant->name()) { kDebug() << "Mismatch for move list, this variant is \"" << m_variant->name() << "\",\n" " got move list for \"" << pos->variant() << "\""; return; } Game g; g.reset(pos); g.load(pgn); for(int i=0;i<=g.lastMainlineIndex().num_moves;i++) { m_game->insert(g.move(i), g.position(i), i); } //m_game->load(pos, pgn); } bool ICSEntity::canDetach() const { // TODO: ask whether abort or resign... return true; } bool ICSEntity::attach() { // an ICS player can attach only if no move for that side has been made //kDebug() << "[ICS attach] index = " << m_game->lastMainlineIndex(); if (m_game->lastMainlineIndex() == 0) return true; if (m_game->lastMainlineIndex() == 1 && m_side == 1) { // white already played, inform black m_dispatcher.move(0); return true; } return false; } void ICSEntity::notifyMove(const Index& index) { if (!canEdit()) { m_connection->sendText(m_game->move(index)->toString( "simple", m_game->position(index.prev()))); } } void ICSEntity::requestMoves() { m_connection->sendText(QString("moves %1").arg(m_game_number)); } bool ICSEntity::canEdit() const { return canEdit(m_game->index()); } bool ICSEntity::canEdit(const Index& index) const { return m_editing_mode || index != m_game->lastMainlineIndex(); } void ICSEntity::setupTurnTest(TurnTest& test) const { test.setPolicy(m_side, shared_ptr(new ICSTurnPolicy(this))); test.setPremovePolicy(shared_ptr(new ICSPremovePolicy(this))); } ObservingEntity::ObservingEntity(const VariantPtr& variant, const shared_ptr& game, int gameNumber,const shared_ptr& connection, AgentGroup* group) : ICSEntity(variant, game, -1, gameNumber, connection, group) , m_attached(true) { } void ObservingEntity::detach() { m_attached = false; } ObservingEntity::~ObservingEntity() { if (m_attached) m_connection->sendText(QString("unobs %1").arg(m_game_number)); } tagua-1.0-alpha2/src/entities/icsentity.h000066400000000000000000000044641077523320400204320ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ICSENTITY_H #define ICSENTITY_H #include "entity.h" #include "agent.h" #include "agentgroup.h" #include "icslistener.h" #include "tagua.h" #include "fwd.h" class ICSConnection; class ICSEntity : public Entity , public Agent , public ICSListener { protected: VariantPtr m_variant; ICSAPIPtr m_icsapi; boost::shared_ptr m_connection; int m_side; int m_game_number; bool m_editing_mode; AgentGroupDispatcher m_dispatcher; void updateGame(const Index& index, AbstractMove::Ptr icsMove, AbstractPosition::Ptr icsPos); enum UpdateType { MoveForward, MoveBack, Forward, Back, NoMove, NonComparableIndexes }; UpdateType getUpdate(const Index& index); public: ICSEntity(const VariantPtr&, const boost::shared_ptr&, int, int, const boost::shared_ptr&, AgentGroup*); virtual void executeMove(AbstractMove::Ptr); virtual void notifyStyle12(const PositionInfo&, bool is_starting); virtual void notifyPool(const class PoolInfo&); virtual void notifyMoveList(int, AbstractPosition::Ptr, const PGN&); virtual AbstractPosition::Ptr position() const; virtual void notifyClockUpdate(int, int) { } virtual void notifyMove(const Index&); virtual void notifyBack() { } virtual void notifyForward() { } virtual void notifyGotoFirst() { } virtual void notifyGotoLast() { } void requestMoves(); virtual bool canDetach() const; virtual bool attach(); bool canEdit() const; bool canEdit(const Index& index) const; void setupTurnTest(TurnTest& test) const; }; class ObservingEntity : public ICSEntity { protected: bool m_attached; public: ObservingEntity(const VariantPtr&, const boost::shared_ptr&, int gameNumber, const boost::shared_ptr&, AgentGroup*); ~ObservingEntity(); virtual void detach(); }; #endif // ICSENTITY_H tagua-1.0-alpha2/src/entities/userentity.cpp000066400000000000000000000016611077523320400211610ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "userentity.h" UserEntity::UserEntity(const GamePtr& game) : Entity(game) , m_editing_tools(false) { } void UserEntity::enableEditingTools(bool value) { m_editing_tools = value; } NormalUserMove UserEntity::createMove(const Point& from, const Point& to) const { return NormalUserMove(from, to); } DropUserMove UserEntity::createDrop(int pool, int index, const Point& to) const { return DropUserMove(pool, index, to); } void UserEntity::handleRightClick(const Point&) const { } bool UserEntity::canDetach() const { return true; } tagua-1.0-alpha2/src/entities/userentity.h000066400000000000000000000057131077523320400206300ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef USERENTITY_H #define USERENTITY_H #ifndef GAMEBASEDRULES_H #define GAMEBASEDRULES_H #include "entity.h" #include "fwd.h" #include "tagua.h" #include "usermove.h" #include "agent.h" #include "turnpolicy.h" class PGN; class UserEntity : public Entity , public Agent { protected: TurnPolicy::Collection m_turn_test; bool m_editing_tools; public: UserEntity(const GamePtr& game); virtual TurnPolicy::Collection& turnTest() { return m_turn_test; } virtual void enableEditingTools(bool value); /** * Return a PGN for the game. */ virtual QString save() const = 0; /** * Load the content of a PGN inside the game. */ virtual void loadPGN(const PGN& pgn) = 0; virtual NormalUserMove createMove(const Point& from, const Point& to) const; virtual DropUserMove createDrop(int pool, int index, const Point& to) const; virtual AbstractMove::Ptr testMove(const NormalUserMove& m) const = 0; virtual AbstractMove::Ptr testMove(const DropUserMove& m) const = 0; virtual bool testPremove(const NormalUserMove& m) const = 0; virtual bool testPremove(const DropUserMove&) const = 0; virtual void executeMove(AbstractMove::Ptr move) = 0; virtual void addPremove(const NormalUserMove& m) = 0; virtual void addPremove(const DropUserMove& m) = 0; virtual void cancelPremove() = 0; virtual void handleRightClick(const Point&) const; virtual InteractionType validTurn(const Point&) const = 0; virtual InteractionType validTurn(int) const = 0; virtual bool movable(const Point&) const = 0; virtual bool oneClickMoves() const { return false; } /** * Jump to the end of the game. */ virtual bool gotoFirst() = 0; /** * Jump to the beginning of the game. */ virtual bool gotoLast() = 0; /** * Jump to an arbitrary index. */ virtual bool goTo(const Index& index) = 0; /** * Go forward one move in the game. */ virtual bool forward() = 0; /** * Go back one move in the game. */ virtual bool back() = 0; /** * Undo the last editing action. */ virtual bool undo() = 0; /** * Redo the last editing action. */ virtual bool redo() = 0; /** * Remove the current position. */ virtual bool truncate() = 0; /** * Promote the current variation to mainline. */ virtual bool promoteVariation() = 0; /** * Move hint. * @sa AbstractPosition::moveHint */ virtual AbstractPiece::Ptr moveHint(AbstractMove::Ptr) const { return AbstractPiece::Ptr(); } virtual bool canDetach() const; }; #endif // GAMEBASEDRULES_H #endif // USERENTITY_H tagua-1.0-alpha2/src/export.h000066400000000000000000000012631077523320400161060ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef EXPORT_H #define EXPORT_H #include #ifdef TAGUA_DEBUG #ifdef MAKE_TAGUAPRIVATE_LIB #define TAGUA_EXPORT KDE_EXPORT #else #define TAGUA_EXPORT KDE_IMPORT #endif // MAKE_TAGUAPRIVATE_LIB #else // TAGUA_DEBUG #define TAGUA_EXPORT #endif // TAGUA_DEBUG #endif // EXPORT_H tagua-1.0-alpha2/src/flash.cpp000066400000000000000000000006351077523320400162170ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "flash.h" tagua-1.0-alpha2/src/flash.h000066400000000000000000000010111077523320400156510ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef FLASH_H #define FLASH_H class QWidget; class Flash { public: static void flash(QWidget*) { } }; #endif // FLASH_H tagua-1.0-alpha2/src/foreach.h000066400000000000000000000007631077523320400162000ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef FOREACH_H #define FOREACH_H #include #define foreach BOOST_FOREACH #endif // FOREACH_H tagua-1.0-alpha2/src/fwd.h000066400000000000000000000044761077523320400153560ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef FWD_H #define FWD_H #include typedef boost::shared_ptr MovePtr; typedef boost::shared_ptr PositionPtr; typedef boost::shared_ptr PoolPtr; typedef boost::shared_ptr PiecePtr; typedef boost::shared_ptr AnimatorPtr; typedef boost::shared_ptr ICSAPIPtr; typedef boost::shared_ptr VariantPtr; template class UnwrappedGraphicalAPI; template struct UnwrappedGraphicalAPIPtr { typedef boost::shared_ptr > type; }; namespace HLVariant { template class UnwrappedGraphicalAPI; template struct UnwrappedGraphicalAPIPtr { typedef boost::shared_ptr > type; }; } typedef boost::shared_ptr AnimationPtr; typedef boost::shared_ptr AnimationGroupPtr; typedef boost::shared_ptr DropAnimationPtr; typedef boost::shared_ptr PromotionAnimationPtr; typedef boost::shared_ptr CaptureAnimationPtr; typedef boost::shared_ptr InstantAnimationPtr; typedef boost::shared_ptr DelayAnimationPtr; typedef boost::shared_ptr MovementAnimationPtr; typedef boost::shared_ptr FadeAnimationPtr; typedef boost::shared_ptr GrowAnimationPtr; typedef boost::shared_ptr ExplodeAnimationPtr; typedef boost::shared_ptr TeleportAnimationPtr; typedef boost::shared_ptr CrossFadingAnimationPtr; namespace Animate { class Scheme; } typedef boost::shared_ptr SchemePtr; typedef boost::shared_ptr SpritePtr; typedef boost::shared_ptr GamePtr; #endif //FWD_H tagua-1.0-alpha2/src/game.cpp000066400000000000000000000573131077523320400160400ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #ifdef Q_CC_MSVC #pragma warning( push ) #pragma warning( disable : 4100 ) #include #pragma warning( pop ) #else #include #endif #include "variants.h" #include "pgnparser.h" #include "tagua.h" #include "game.h" #include "game_p.h" using namespace GamePrivate; Game::Game() : current(-1) , undo_pos(0) { } Game::~Game() { } void Game::onAdded(const Index&) { } void Game::onRemoved(const Index&) { } void Game::onEntryChanged(const Index&, int) { } void Game::onPromoteVariation(const Index&, int) { } void Game::onSetComment(const Index&, const QString&) { } void Game::onSetVComment(const Index&, int, const QString&) { } void Game::onCurrentIndexChanged(const Index&) { } void Game::onAvailableUndo(bool) { } void Game::onAvailableRedo(bool) { } Entry* Game::fetch(const Index& ix) { int at; History *vec = fetchRef(ix, &at); return vec ? &(*vec)[at] : NULL; } const Entry* Game::fetch(const Index& ix) const { int at; const History *vec = fetchRef(ix, &at); return vec ? &(*vec)[at] : NULL; } History* Game::fetchRef(const Index& ix, int* idx) { if(ix.num_moves >= (int)history.size() || ix.num_moves < 0 ) return NULL; History* aretv = &history; Entry* retv = &history[ix.num_moves]; if(idx) *idx = ix.num_moves; for(int i=0; i<(int)ix.nested.size();i++) { Variations::iterator it = retv->variations.find(ix.nested[i].variation); if(it == retv->variations.end() || ix.nested[i].num_moves >= (int)it->second.size() || ix.nested[i].num_moves < 0 ) return NULL; aretv = &it->second; retv = &it->second[ix.nested[i].num_moves]; if(idx) *idx = ix.nested[i].num_moves; } return aretv; } const History* Game::fetchRef(const Index& ix, int* idx) const { return const_cast(const_cast(this)->fetchRef(ix, idx)); } void Game::testMove(const Index& ix) { if (ix != Index(0)) { Entry *e1 = fetch(ix.prev()); Entry *e2 = fetch(ix); if(!e1 || !e2 || !e1->position || !e2->move) return; if (!e1->position->testMove(e2->move)) kError() << "invalid move added to game history"; } } void Game::testMove() { testMove(current); } void Game::saveUndo(const UndoOp& op) { bool redo = undo_pos < (int)undo_history.size(); while(undo_pos < (int)undo_history.size()) undo_history.pop_back(); undo_history.push_back(op); undo_pos++; if(undo_pos == 1) onAvailableUndo(true); if(redo) onAvailableRedo(false); } Index Game::index() const { return current; } Index Game::lastMainlineIndex() const { return Index(history.size()-1); } bool Game::containsIndex(const Index& index) const { return !!fetch(index); } MovePtr Game::move() const { return move(current); } MovePtr Game::move(const Index& index) const { Entry *e = (Entry*)fetch(index); if(!e) { kError() << "Index out of range"; return MovePtr(); } return e->move; } PositionPtr Game::position() const { return position(current); } PositionPtr Game::position(const Index& index) const { Entry *e = (Entry*)fetch(index); if(!e) { kError() << "Index" << index << "out of range"; return PositionPtr(); } return e->position; } QString Game::comment() const { return comment(current); } QString Game::comment(const Index& index) const { const Entry *e = fetch(index); if(!e) { kError() << "Index out of range"; return QString(); } return e->comment; } void Game::reset(PositionPtr pos) { Q_ASSERT(pos); undo_pos = 0; undo_history.clear(); history.clear(); history.push_back( Entry(MovePtr(), pos) ); current = Index(0); onCurrentIndexChanged(); } void Game::undo() { if(undo_pos <= 0) { kError() << "Nothing to undo"; return; } bool last_undo = undo_pos == 1; bool now_redo = undo_pos == (int)undo_history.size(); undo_pos--; UndoOp* op = &(undo_history[undo_pos]); if(boost::get(op)) { UndoAdd *a = boost::get(op); if(a->index.atVariationStart() ) { Entry* e = fetch(a->index.prev()); Q_ASSERT(e); int v = a->index.nested.back().variation; Q_ASSERT(e->variations.count(v) == 1); Q_ASSERT(e->variations[v].size() == 1); e->variations.erase(v); } else { int at; std::vector* vec = fetchRef(a->index, &at); Q_ASSERT(vec); Q_ASSERT((int)vec->size() == at+1); vec->pop_back(); } if(current == a->index) { current = current.prev(); onCurrentIndexChanged(); } onRemoved(a->index); } else if(boost::get(op)) { UndoPromote *p = boost::get(op); int at; std::vector* vec = fetchRef(p->index, &at); Q_ASSERT(vec); Q_ASSERT((*vec)[at].variations.count(p->variation)==1); History vold = (*vec)[at].variations[p->variation]; History vnew; for(int i=at+1; i<(int)vec->size(); i++) vnew.push_back((*vec)[i]); while((int)vec->size()>at+1) vec->pop_back(); for(int i=0; i<(int)vold.size(); i++) vec->push_back(vold[i]); (*vec)[at].variations[p->variation] = vnew; current = current.flipVariation(p->index, p->variation); onPromoteVariation(p->index, p->variation); //onCurrentIndexChanged(); } else if(boost::get(op)) { UndoTruncate *t = boost::get(op); int at; std::vector* vec = fetchRef(t->index, &at); Q_ASSERT(vec); Q_ASSERT((int)vec->size() == at+1); Q_ASSERT((*vec)[at].variations.empty()); for(int i=0;i<(int)t->history.size();i++) vec->push_back(t->history[i]); (*vec)[at].variations = t->variations; (*vec)[at].vcomments = t->vcomments; if(t->history.size()) onAdded(t->index.next()); for(Variations::iterator it = t->variations.begin(); it != t->variations.end(); ++it) onAdded(t->index.next(it->first)); for(VComments::iterator it = t->vcomments.begin(); it != t->vcomments.end(); ++it) onSetVComment(t->index, it->first, it->second); } else if(boost::get(op)) { UndoRemove *r = boost::get(op); Entry *e = fetch(r->index); e->variations[r->variation] = r->history; onAdded(r->index.next(r->variation)); if(!r->vcomment.isEmpty()) { e->vcomments[r->variation] = r->vcomment; onSetVComment(r->index, r->variation, r->vcomment); } } else if(boost::get(op)) { UndoClear *c = boost::get(op); Entry *e = fetch(c->index); e->variations = c->variations; e->vcomments = c->vcomments; for(Variations::iterator it = c->variations.begin(); it != c->variations.end(); ++it) onAdded(c->index.next(it->first)); for(VComments::iterator it = c->vcomments.begin(); it != c->vcomments.end(); ++it) onSetVComment(c->index, it->first, it->second); } else if(boost::get(op)) { UndoSetComment *sc = boost::get(op); Entry *e = fetch(sc->index); Q_ASSERT(e); if(sc->variation == -1) { e->comment = sc->old_comment; onSetComment(sc->index, sc->old_comment); } else { if(sc->old_comment.isEmpty()) e->vcomments.erase(sc->variation); else e->vcomments[sc->variation] = sc->old_comment; onSetVComment(sc->index, sc->variation, sc->old_comment); } } else kError() << "Unexpected type in boost::variant"; if(last_undo) onAvailableUndo(false); if(now_redo) onAvailableRedo(true); } void Game::redo() { if(undo_pos >= (int)undo_history.size()) { kError() << "Nothing to redo"; return; } bool now_undo = undo_pos == 0; bool last_redo = undo_pos == (int)undo_history.size()-1; UndoOp* op = &(undo_history[undo_pos]); undo_pos++; if(boost::get(op)) { UndoAdd *a = boost::get(op); if(a->index.atVariationStart() ) { Entry* e = fetch(a->index.prev()); Q_ASSERT(e); int v = a->index.nested.back().variation; Q_ASSERT(e->variations.count(v) == 0); History h; h.push_back(a->entry); e->variations[v] = h; } else { int at; std::vector* vec = fetchRef(a->index.prev(), &at); Q_ASSERT(vec); Q_ASSERT((int)vec->size() == at+1); vec->push_back(a->entry); } onAdded(a->index); current = a->index; onCurrentIndexChanged(); } else if(boost::get(op)) { UndoPromote *p = boost::get(op); int at; std::vector* vec = fetchRef(p->index, &at); Q_ASSERT(vec); Q_ASSERT((*vec)[at].variations.count(p->variation)==1); History vold = (*vec)[at].variations[p->variation]; History vnew; for(int i=at+1; i<(int)vec->size(); i++) vnew.push_back((*vec)[i]); while((int)vec->size()>at+1) vec->pop_back(); for(int i=0; i<(int)vold.size(); i++) vec->push_back(vold[i]); (*vec)[at].variations[p->variation] = vnew; current = current.flipVariation(p->index, p->variation); onPromoteVariation(p->index, p->variation); //onCurrentIndexChanged(); } else if(boost::get(op)) { UndoTruncate *t = boost::get(op); int at; std::vector* vec = fetchRef(t->index, &at); Q_ASSERT(vec); Q_ASSERT((int)vec->size() == at+1+(int)t->history.size()); while((int)vec->size() > at+1) vec->pop_back(); (*vec)[at].variations.clear(); (*vec)[at].vcomments.clear(); if(current > t->index) { current = t->index; onCurrentIndexChanged(); } if(t->history.size()) onRemoved(t->index.next()); for(Variations::iterator it = t->variations.begin(); it != t->variations.end(); ++it) onRemoved(t->index.next(it->first)); } else if(boost::get(op)) { UndoRemove *r = boost::get(op); Entry *e = fetch(r->index); e->variations.erase(r->variation); e->vcomments.erase(r->variation); onRemoved(r->index.next(r->variation)); } else if(boost::get(op)) { UndoClear *c = boost::get(op); Entry *e = fetch(c->index); e->variations.clear(); e->vcomments.clear(); for(Variations::iterator it = c->variations.begin(); it != c->variations.end(); ++it) onRemoved(c->index.next(it->first)); } else if(boost::get(op)) { UndoSetComment *sc = boost::get(op); Entry *e = fetch(sc->index); Q_ASSERT(e); if(sc->variation == -1) { e->comment = sc->new_comment; onSetComment(sc->index, sc->new_comment); } else { if(sc->new_comment.isEmpty()) e->vcomments.erase(sc->variation); else e->vcomments[sc->variation] = sc->new_comment; onSetVComment(sc->index, sc->variation, sc->new_comment); } } else kError() << "Unexpected type in boost::variant"; if(now_undo) onAvailableUndo(true); if(last_redo) onAvailableRedo(false); } void Game::setComment(const QString& c) { setComment(current, c); } void Game::setComment(const Index& ix, const QString& c) { Entry* e = fetch(ix); if(!e) { kError() << "Invalid index"; return; } if(e->comment == c) return; saveUndo(UndoSetComment(ix, -1, e->comment, c)); e->comment = c; onSetComment(ix, c); } void Game::setVComment(const Index& ix, int v, const QString& c) { Entry* e = fetch(ix); if(!e) { kError() << "Invalid index"; return; } QString oc = e->vcomments.count(v) ? e->vcomments[v] : QString(); if(oc == c) return; saveUndo(UndoSetComment(ix, v, oc, c)); if(c.isEmpty()) e->vcomments.erase(v); else e->vcomments[v] = c; onSetVComment(ix, v, c); } void Game::promoteVariation() { promoteVariation(current); } void Game::promoteVariation(const Index& _ix) { if(_ix.nested.size()==0) { kError() << "Cannot promote main line"; return; } Index ix = _ix; int v = ix.nested.back().variation; ix.nested.pop_back(); promoteVariation(ix, v); } void Game::promoteVariation(const Index& ix, int v) { int at; std::vector* vec = fetchRef(ix, &at); Q_ASSERT(vec); Q_ASSERT((*vec)[at].variations.count(v)==1); History vold = (*vec)[at].variations[v]; History vnew; for(int i=at+1; i<(int)vec->size(); i++) vnew.push_back((*vec)[i]); while((int)vec->size()>at+1) vec->pop_back(); for(int i=0; i<(int)vold.size(); i++) vec->push_back(vold[i]); (*vec)[at].variations[v] = vnew; saveUndo(UndoPromote(ix, v)); current = current.flipVariation(ix, v); onPromoteVariation(ix, v); //don't call onCurrentIndexChanged(), as the position did not change actually } void Game::removeVariation(int v) { removeVariation(current, v); } void Game::removeVariation(const Index& _ix) { if(_ix.nested.size()==0) { kError() << "Cannot remove main line"; return; } Index ix = _ix; int v = ix.nested.back().variation; ix.nested.pop_back(); removeVariation(ix, v); } void Game::removeVariation(const Index& ix, int v) { Entry* e = fetch(ix); saveUndo(UndoRemove(ix, v, e->variations[v], e->vcomments.count(v) ? e->vcomments[v] : QString() )); e->variations.erase(v); e->vcomments.erase(v); onRemoved(ix.next(v)); if(current >= ix.next(v)) { current = ix; onCurrentIndexChanged(); } } void Game::clearVariations() { clearVariations(current); } void Game::clearVariations(const Index& ix) { Entry* e = fetch(ix); UndoClear uc(ix, e->variations, e->vcomments); saveUndo(uc); e->variations.clear(); e->vcomments.clear(); for(Variations::iterator it = uc.variations.begin(); it != uc.variations.end(); ++it) onRemoved(ix.next(it->first)); if(current > ix && !(current >= ix.next())) { current = ix; onCurrentIndexChanged(); } } void Game::truncate() { truncate(current); } void Game::truncate(const Index& ix) { int at; History* vec = fetchRef(ix, &at); if(!vec) { kError() << "Truncating at an unexisting index"; return; } Entry *e = &(*vec)[at]; UndoTruncate undo(ix); for(int i=at+1; i<(int)vec->size();i++) undo.history.push_back((*vec)[i]); while((int)vec->size()>at+1) vec->pop_back(); undo.variations = e->variations; undo.vcomments = e->vcomments; saveUndo(undo); e->variations.clear(); e->vcomments.clear(); if(undo.history.size()) onRemoved(undo.index.next()); for(Variations::iterator it = undo.variations.begin(); it != undo.variations.end(); ++it) onRemoved(undo.index.next(it->first)); if(current > ix) { current = ix; onCurrentIndexChanged(); } } void Game::add(MovePtr m, PositionPtr pos) { Q_ASSERT(pos); Index old_c = current; int at; std::vector* vec = fetchRef(current, &at); Q_ASSERT(vec); /* add the move on the mainline */ if((int)vec->size() <= at+1 ) { Q_ASSERT((int)vec->size() == at+1); vec->push_back(Entry(m, pos)); current = current.next(); testMove(); saveUndo(UndoAdd(current, Entry(m, pos))); onAdded(current); onCurrentIndexChanged(old_c); } /* we are playing the move that is already next in the mainline */ else if( (*vec)[at+1].position && (*vec)[at+1].position->equals(pos)) { current = current.next(); onCurrentIndexChanged(old_c); /* no need to test the move */ } else { Entry *e = fetch(current); Q_ASSERT(e); /* check if a variations with this move already exists. */ for(Variations::iterator it = e->variations.begin(); it != e->variations.end(); ++it) if(it->second.size() > 0 && it->second[0].position && it->second[0].position->equals(pos) ) { current = current.next(it->first); onCurrentIndexChanged(old_c); return; } int var_id = e->last_var_id++; e->variations[var_id].push_back(Entry(m, pos)); current = current.next(var_id); testMove(); saveUndo(UndoAdd(current, Entry(m, pos))); onAdded(current); onCurrentIndexChanged(old_c); } } bool Game::insert(MovePtr m, PositionPtr pos, const Index& at) { Entry *e = fetch(at); if(!e) { if(at.nested.size() == 0) { if(undo_history.size()) { undo_pos = 0; undo_history.clear(); } int hs = history.size(); history.resize(at.num_moves + 1); history[at.num_moves] = Entry(m, pos); testMove(at); onAdded(Index(hs)); return true; } else { kError() << "Index out if range"; return false; } } if(undo_history.size()) { undo_pos = 0; undo_history.clear(); } bool res = e->position && e->position->equals(pos); e->move = m; e->position = pos; testMove(at); testMove(at.next()); for (Variations::const_iterator it = e->variations.begin(); it != e->variations.end(); ++it) testMove(at.next(it->first)); onEntryChanged(at); return res; } bool Game::lastPosition() const { return !fetch(current.next()); } bool Game::back() { if (current <= 0) return false; // first entry or uninitialized Index old_c = current; Index new_c = current.prev(); Entry *e = fetch(new_c); if(!e || e->position == 0) return false; // gap immediately before current current = new_c; onCurrentIndexChanged(old_c); return true; } bool Game::forward() { Index old_c = current; Index new_c = current.next(); Entry *e = fetch(new_c); if(!e || e->position == 0) { return false; // gap immediately before current } current = new_c; onCurrentIndexChanged(old_c); return true; } void Game::gotoFirst() { Index old_c = current; current = Index(0); onCurrentIndexChanged(old_c); } void Game::gotoLast() { int at; std::vector* vec = fetchRef(current, &at); Q_ASSERT(vec); Q_ASSERT((int)vec->size() > at); if((int)vec->size() > at+1) { Index old_c = current; current = current.next(-1, vec->size()-1-at); onCurrentIndexChanged(old_c); } } bool Game::goTo(const Index& index) { if (fetch(index)) { Index old_c = current; current = index; onCurrentIndexChanged(old_c); return true; } return false; } QString Game::variationPgn(const History& vec, const Entry& e, int start, const Index& _ix) const { Index ix = _ix; QString res; for (int i = start; i < static_cast(vec.size()); i++) { const Entry& preve = (i > start) ? vec[i-1] : e; QString mv = (vec[i].move && preve.position) ? vec[i].move->toString("compact", preve.position ) : "???"; #if 0 if (ix == current) mv = "[[" + mv + "]]"; #endif int n = ix.totalNumMoves()+1; if(i==start || n%2==0) mv = QString::number(n/2)+(n%2==1 ? ". ... " : ". ") + mv; if (i > start) mv = " " + mv; res += mv; if(!vec[i].comment.isEmpty()) res += " {" + vec[i].comment + "}"; if(i > 0) { for(Variations::const_iterator it = vec[i-1].variations.begin(); it != vec[i-1].variations.end(); ++it) { res += " ("; if(vec[i-1].vcomments.count(it->first)) res += "{" + vec[i-1].vcomments.find(it->first)->second + "} "; res += variationPgn(it->second, vec[i - 1], 0, ix.prev().next(it->first)) + ")"; } } ix = ix.next(); } return res; } QString Game::pgn() const { return variationPgn(history, history[0], 1, Index(1)); } void Game::load(const PGN& pgn) { std::map::const_iterator var = pgn.m_tags.find("Variant"); VariantPtr vi; if (var == pgn.m_tags.end()) { vi = Variants::instance().get("chess"); } else if (!(vi = Variants::instance().get(var->second))) { kError() << "No such variant" << var->second; return; } std::map::const_iterator fen = pgn.m_tags.find("FEN"); PositionPtr pos; //if(var == pgn.m_tags.end()) { pos = vi->createPosition(); pos->setup(); //} #if 0 // BROKEN else if( !(pos = vi->createPositionFromFEN(fen->second))) { kError() << "Wrong fen " << fen->second; return; } #endif //TODO: what about options? FEN rules? load(pos, pgn); } void Game::load(PositionPtr pos, const PGN& pgn) { current = Index(0); undo_history.clear(); undo_pos = 0; // setup an empty history, clear as needed if(history.size()) { Entry* fe = &history[0]; int old_history_size = history.size(); std::vector v_ids; while(history.size()>1) history.pop_back(); for(Variations::const_iterator it = fe->variations.begin(); it != fe->variations.end(); ++it) v_ids.push_back(it->first); fe->variations.clear(); fe->vcomments.clear(); for(int i=0;i<(int)v_ids.size();i++) onRemoved(Index(0).next(v_ids[i])); if(old_history_size>1) onRemoved(Index(1)); v_ids.clear(); history[0].position = pos; } else history.push_back( Entry(MovePtr(), pos) ); // apply moves from PGN, one by one QString vcomment; std::vector var_stack; bool var_start = false; for (uint i = 0; i < pgn.m_entries.size(); i++) { if(boost::get(pgn[i])) { if(var_start) vcomment += *boost::get(pgn[i]); else { Entry *e = fetch(current); Q_ASSERT(e); e->comment += *boost::get(pgn[i]); } } else if(boost::get(pgn[i])) { var_stack.push_back(current); var_start = true; } else if(boost::get(pgn[i])) { if(var_stack.size() == 0) { kError() << "Unexpected end variation"; break; } current = var_stack.back(); var_stack.pop_back(); } else if(boost::get(pgn[i])) { const PGN::Move *pm = boost::get(pgn[i]); int n = current.totalNumMoves()+1; if(var_start) { if(!pm->m_number) // not all moves get numbered in PGN, usually only 1st player ones current = current.prev(); else if(pm->m_number>n+1) kError() << "Too far variation"; else { if(pm->m_numberm_number); } } else if(pm->m_number && pm->m_number!=n+1) kError() << "Move number mismatch"; PositionPtr pos = position(); MovePtr m = pos->getMove(pm->m_move); if(!m || !pos->testMove(m)) break; PositionPtr newPos = pos->clone(); newPos->move(m); int at; History *vec = fetchRef(current, &at); Q_ASSERT(vec); if(var_start) { Entry *e = &(*vec)[at]; int var_id = e->last_var_id++; e->variations[var_id].push_back(Entry(m, newPos)); if(!vcomment.isEmpty()) { e->vcomments[var_id] = vcomment; vcomment = QString(); } /* this is a hack, but the mainline should NEVER be empty if there is a variation*/ if((int)vec->size() - 1 == at) vec->push_back(Entry(m, newPos)); current = current.next(var_id); } else { if((int)vec->size() - 1 == at) vec->push_back(Entry(m, newPos)); else (*vec)[at] = Entry(m, newPos); current = current.next(); } var_start = false; } else kError() << "Unexpected type in boost::variant"; } if(history.size()>1) onAdded(Index(1)); Entry* e = fetch(Index(0)); for(Variations::const_iterator it = e->variations.begin(); it != e->variations.end(); ++it) onAdded(Index(0).next(it->first)); for(VComments::const_iterator it = e->vcomments.begin(); it != e->vcomments.end(); ++it) onSetVComment(Index(0), it->first, it->second); current = Index(0); onCurrentIndexChanged(); } tagua-1.0-alpha2/src/game.h000066400000000000000000000123211077523320400154730ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef GAME_H #define GAME_H #include #include #include #include "fwd.h" #include "index.h" class PGN; namespace GamePrivate { class Entry; typedef std::vector History; typedef boost::variant UndoOp; typedef std::vector UndoHistory; } /** \class Game game.h \brief A game with history and variations. This template class encapsulates an editable game with history and undo editing. */ class Game { public: GamePrivate::History history; Index current; GamePrivate::UndoHistory undo_history; int undo_pos; GamePrivate::Entry* fetch(const Index& ix); const GamePrivate::Entry* fetch(const Index& ix) const; GamePrivate::History* fetchRef(const Index& ix, int* idx); const GamePrivate::History* fetchRef(const Index& ix, int* idx) const; void testMove(); void testMove(const Index& ix); void saveUndo(const GamePrivate::UndoOp& op); QString variationPgn(const GamePrivate::History&, const GamePrivate::Entry&, int start, const Index& _ix) const; virtual void onAdded(const Index& i); virtual void onRemoved(const Index& i); virtual void onEntryChanged(const Index& at, int propagate=1); virtual void onPromoteVariation(const Index& i, int v); virtual void onSetComment(const Index& i, const QString& c); virtual void onSetVComment(const Index& i, int v, const QString& c); virtual void onCurrentIndexChanged(const Index& old = Index(-1)); virtual void onAvailableUndo(bool); virtual void onAvailableRedo(bool); public: /** Constructor, creates an empty game*/ Game(); /** destructor */ virtual ~Game(); /** \return the index of the current position */ Index index() const; /** \return an index opinting to the last position in the main line */ Index lastMainlineIndex() const; /** \return true if the game contains the index */ bool containsIndex(const Index& index) const; /** \return the current move */ MovePtr move() const; /** \return the move at the given index */ MovePtr move(const Index& index) const; /** \return the current position */ PositionPtr position() const; /** \return the position at the given index */ PositionPtr position(const Index& index) const; /** \return the current comment */ QString comment() const; /** \return the comment at the given index */ QString comment(const Index& index) const; /** clears the games, and puts \a pos as root position */ void reset(PositionPtr pos); /** undo */ void undo(); /** redo */ void redo(); /** sets the comment in the current index */ void setComment(const QString& c); /** sets the comment at the given index */ void setComment(const Index& index, const QString& c); /** sets the variation comment at the given index/variation */ void setVComment(const Index& index, int v, const QString& c); /** promotes the current position in the upper main line */ void promoteVariation(); /** promotes the given position in the upper main line */ void promoteVariation(const Index& index); /** promotes the given variation in the upper main line */ void promoteVariation(const Index& index, int v); /** removes the given variation in the current index */ void removeVariation(int v); /** removes the given variation in the given index */ void removeVariation(const Index& index); /** removes the given variation in the given index */ void removeVariation(const Index& index, int v); /** removes the given variation in the current index */ void clearVariations(); /** removes the given variation in the given index */ void clearVariations(const Index& index); /** removes all the successors of the current position */ void truncate(); /** removes all the successors of the given position */ void truncate(const Index& index); /** adds a new move+position after the current one, on the main line if possible, or else in a new variation */ void add(MovePtr move, PositionPtr pos); /** forces a move+position at in certain index */ bool insert(MovePtr move, PositionPtr pos, const Index& index); /** \return true if we cannot go forward */ bool lastPosition() const; /** go back */ bool back(); /** go forward (in the current mainline) */ bool forward(); /** go to the root position */ void gotoFirst(); /** go to the last position (in the current mainline) */ void gotoLast(); /** go to a specified index */ bool goTo(const Index& index); /** \return a pgn containing the whole game (with variations) */ QString pgn() const; /** loads a pgn in the current game */ void load(PositionPtr, const PGN& pgn); /** loads a pgn in the current game */ void load(const PGN& pgn); }; #endif // GAME_H tagua-1.0-alpha2/src/game_p.h000066400000000000000000000043531077523320400160200ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef GAME_P_H #define GAME_P_H #include #include #include "game.h" namespace GamePrivate { typedef std::map Variations; typedef std::map VComments; /** * A class to store game entries */ class Entry { public: MovePtr move; PositionPtr position; QString comment; Variations variations; VComments vcomments; int last_var_id; Entry(MovePtr move, PositionPtr position) : move(move) , position(position) , last_var_id(0) { } Entry() : last_var_id(0) { } ~Entry() { } }; /* data and structs for undo */ class UndoAdd { public: Index index; Entry entry; UndoAdd(const Index& ix, const Entry& e) : index(ix), entry(e) {} }; class UndoPromote { public: Index index; int variation; UndoPromote(const Index& ix, int v) : index(ix), variation(v) {} }; class UndoTruncate { public: Index index; History history; Variations variations; VComments vcomments; UndoTruncate(const Index& ix) : index(ix) {} UndoTruncate(const Index& ix, const History& h, const Variations& v, const VComments& c) : index(ix), history(h), variations(v), vcomments(c) {} }; class UndoRemove { public: Index index; int variation; History history; QString vcomment; UndoRemove(const Index& ix, int v, const History& h, const QString& c) : index(ix), variation(v), history(h), vcomment(c) {} }; class UndoClear { public: Index index; Variations variations; VComments vcomments; UndoClear(const Index& ix, const Variations& v, const VComments& c) : index(ix), variations(v), vcomments(c) {} }; class UndoSetComment { public: Index index; int variation; QString old_comment; QString new_comment; UndoSetComment(const Index& ix, int v, const QString& o, const QString& n) : index(ix), variation(v), old_comment(o), new_comment(n) {} }; } #endif //GAME_P_H tagua-1.0-alpha2/src/gameinfo.cpp000066400000000000000000000027001077523320400167020ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "gameinfo.h" GameInfo::GameInfo(const Player& white, const Player& black, const QString& rated, const QString& type, int time, int increment) : m_white(white) , m_black(black) , m_rated(rated) , m_type(type) , m_time(time) , m_increment(increment) , m_game_num(-1) { m_variant = variantCode(m_type); } GameInfo::GameInfo(QRegExp& pattern, int offset) : m_white(Player(pattern.cap(offset), pattern.cap(offset + 1).toInt())) , m_black(Player(pattern.cap(offset + 2), pattern.cap(offset + 3).toInt())) , m_rated(pattern.cap(offset + 4)) , m_type(pattern.cap(offset + 5)) , m_time(pattern.cap(offset + 6).toInt()) , m_increment(pattern.cap(offset + 7).toInt()) , m_game_num(-1) { m_variant = variantCode(m_type); } QString GameInfo::variantCode(const QString& type) { if (type == "blitz" || type == "standard" || type == "lightning" || type == "untimed" || type == "chess") return "Chess"; else if (type == "atomic") return "Atomic"; else if (type == "crazyhouse") return "Crazyhouse"; else return "Dummy"; } tagua-1.0-alpha2/src/gameinfo.h000066400000000000000000000024411077523320400163510ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef GAMEINFO_H #define GAMEINFO_H #include #include "player.h" #include "qstring.h" class GameInfo { Player m_white, m_black; QString m_rated, m_type; QString m_variant; int m_time, m_increment; int m_game_num; public: GameInfo(const Player& white, const Player& black, const QString& rated, const QString& type, int time, int increment); GameInfo(QRegExp& pattern, int offset); static QString variantCode(const QString& type); const Player& white() const { return m_white; } const Player& black() const { return m_black; } QString rated() const { return m_rated; } QString type() const { return m_type; } int time() const { return m_time; } int increment() const { return m_increment; } int gameNumber() const { return m_game_num; } void setGameNumber(int g) { m_game_num = g; } QString variant() const { return m_variant; } }; #endif // GAMEINFO_H tagua-1.0-alpha2/src/genericposition.h000066400000000000000000000024511077523320400177660ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef GENERICPOSITION_H #define GENERICPOSITION_H #include "point.h" #include "piece.h" class GenericPosition { public: virtual const ChessPiece* operator[](const Point&) const = 0; virtual ChessPiece* operator[](const Point&) = 0; virtual const Point first() const = 0; virtual const Point last() const = 0; virtual Point next(const Point&) const = 0; virtual bool valid(const Point&) const = 0; virtual void setup() = 0; virtual GenericPosition* clone() const = 0; virtual GenericPosition* _new() const = 0; // // virtual void basicMovePiece(const ChessMove&) = 0; // virtual void basicDropPiece(ChessPiece*, const Point&) = 0; // virtual void removePiece(const Point&) = 0; // virtual void setPiece(const Point&, ChessPiece*) = 0; // // virtual void move(const ChessMove&) = 0; virtual ChessPiece::Color turn() const = 0; // virtual QString type() const = 0; }; #endif tagua-1.0-alpha2/src/gnushogiengine.cpp000066400000000000000000000064421077523320400201350ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "gnushogiengine.h" #include #include #include #include "enginenotifier.h" #include "foreach.h" using namespace boost; QRegExp GNUShogiEngine::m_move_pattern("[0-9]*\\. \\.\\.\\. ([^ ]*) .*"); GNUShogiEngine::GNUShogiEngine(const QString& path, const QStringList& arguments) : Engine(path, arguments) , m_analysing(false) { // set default features m_features.ping = false; m_features.setboard = false; m_features.playother = false; m_features.san = false; m_features.usermove = false; m_features.time = true; m_features.draw = true; m_features.sigint = true; m_features.sigterm = true; m_features.reuse = true; m_features.analyze = false; m_features.colors = true; m_features.ics = false; m_features.name = false; m_features.pause = false; m_features.myname = QFileInfo(m_path).baseName(); connect(this, SIGNAL(receivedCommand(const QString&)), this, SLOT(processCommand(const QString&))); } GNUShogiEngine::~GNUShogiEngine() { kDebug() << "[debug] destroying engine"; stop(); m_engine.kill(); } void GNUShogiEngine::initializeEngine() { // nothing special to do } void GNUShogiEngine::reset() { sendCommand("new"); // start a new game sendCommand("force"); // do not think } void GNUShogiEngine::play() { sendCommand("go"); // start playing } void GNUShogiEngine::stop() { sendCommand("quit"); if (m_features.sigterm) m_engine.kill(); } void GNUShogiEngine::processCommand(const QString& command) { //QStringList arg_list = command.split(QRegExp("\\s+")); //QString cmd = arg_list.takeFirst(); if (m_move_pattern.indexIn(command) == 0) { if (shared_ptr notifier = m_notifier.lock()) notifier->notifyEngineMove(m_move_pattern.cap(1)); } } void GNUShogiEngine::sendMove(AbstractMove::Ptr move, AbstractPosition::Ptr ref) { QString move_str = move->toString("simple", ref); sendCommand(move_str); } void GNUShogiEngine::backUp(AbstractPosition::Ptr) { sendCommand("undo"); } void GNUShogiEngine::startAnalysis() { sendCommand("post"); sendCommand("analyze"); m_analysing = true; } void GNUShogiEngine::stopAnalysis() { sendCommand("exit"); m_analysing = false; } void GNUShogiEngine::setBoard(AbstractPosition::Ptr, int, int) { #if 0 if (m_features.setboard) { sendCommand(QString("setboard %1").arg(pos->fen(halfmove, fullmove))); } else { // this is pretty meaningless for generic variants if (pos->turn() != 0) { sendCommand("new"); sendCommand("a2a3"); } sendCommand("edit"); sendCommand("#"); Point size = pos->size(); for (int i = 0; i < size.x; i++) { for (int j = 0; j < size.y; j++) { Point p(i, j); AbstractPiece::Ptr piece = pos->get(p); if (piece) sendCommand(QString("%1%2") .arg(piece->type()) .arg(p.toString(8))); } } sendCommand("."); } #endif } tagua-1.0-alpha2/src/gnushogiengine.h000066400000000000000000000045051077523320400176000ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef GNUSHOGIENGINE_H #define GNUSHOGIENGINE_H #include "engine.h" #include "tagua.h" class QRegExp; /** * @brief A shogi engine compatible with gnushogi. * * @note This code is partially stolen from the XBoard engine class */ class GNUShogiEngine : public Engine { Q_OBJECT struct Features { bool ping : 1; bool setboard : 1; bool playother : 1; bool san : 1; bool usermove : 1; bool time : 1; bool draw : 1; bool sigint : 1; bool sigterm : 1; bool reuse : 1; bool analyze : 1; QString myname; QString variants; bool colors : 1; bool ics : 1; bool name : 1; bool pause : 1; bool done : 1; }; Features m_features; bool m_analysing; static QRegExp m_move_pattern; protected: /** * Initialize the engine. */ virtual void initializeEngine(); protected Q_SLOTS: /** * Parse engine command line and the appropriate * signals. */ void processCommand(const QString& command); public: /** * Create an gnushogi compatible engine. */ GNUShogiEngine(const QString& path, const QStringList& arguments); /** * Terminate the engine. */ virtual ~GNUShogiEngine(); /** * Send a move to the engine. */ virtual void sendMove(AbstractMove::Ptr move, AbstractPosition::Ptr ref); /** * Back up a move. * @param pos The position before the move. Used if the engine * does not support the undo command. */ virtual void backUp(AbstractPosition::Ptr pos); virtual void setBoard(AbstractPosition::Ptr pos, int halfmove, int fullmove); /** * Begin a new game. */ virtual void reset(); /** * Start playing. */ virtual void play(); /** * Stop the engine. */ virtual void stop(); virtual void startAnalysis(); virtual void stopAnalysis(); }; #endif // GNUSHOGIENGINE_H tagua-1.0-alpha2/src/graphicalapi.h000066400000000000000000000060061077523320400172110ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef GRAPHICALAPI_H #define GRAPHICALAPI_H #include #include #include "animationfactory.h" #include "tagua.h" #include "pointconverter.h" #include "namedsprite.h" #include "fwd.h" typedef boost::shared_ptr SpritePtr; /** * This class defines the interface that will be used by the animator to modify * tagua graphics. */ class GraphicalAPI { public: virtual ~GraphicalAPI() { } /** * \return the current abstract position. */ virtual const PointConverter* converter() const = 0; /** * \return the current abstract position. */ virtual AbstractPosition::Ptr position() const = 0; /** * \return a sprite at the position \a index in the graphical pool. */ virtual NamedSprite getSprite(const Point& p) = 0; /** * Removes a sprite at the position \a index in the graphical pool. * \return the newly created sprite. */ virtual NamedSprite takeSprite(const Point& p) = 0; /** * Sets the piece at the position \a index in the graphical pool. * \return the newly created sprite. */ virtual NamedSprite setPiece(const Point& p, const AbstractPiece* piece, bool show) = 0; /** * Create a new piece, but do not add it to the graphical system. * \return the newly created sprite. */ virtual NamedSprite createPiece(const Point& p, const AbstractPiece* piece, bool show) = 0; /** * Sets the sprite at the position \a index in the graphical pool. * \return the newly created sprite. */ virtual void setSprite(const Point& p, const NamedSprite& sprite) = 0; /** * \return how many sprites are contained in the pool */ virtual int poolSize(int pool) = 0; /** * \return the sprite at the position \a index in the graphical pool. */ virtual NamedSprite getPoolSprite(int pool, int index) = 0; /** * Removes the sprite at the position \a index in the graphical pool. */ virtual void removePoolSprite(int pool, int index) = 0; /** * Removes the sprite at the position \a index in the graphical pool (only for drops). * \return the removed sprite. */ virtual NamedSprite takePoolSprite(int pool, int index) = 0; /** * Inserts a sprite at the position \a index in the graphical pool. * \return the newly created sprite. */ virtual NamedSprite insertPoolPiece(int pool, int index, const AbstractPiece* piece) = 0; /** * \return the piece of the pool that has been dropped, or (-1,-1) */ virtual std::pair droppedPoolPiece() = 0; virtual AnimationPtr animate(const Animate::Scheme& scheme, Animate::AnimationType type) = 0; }; #endif //GRAPHICALAPI_H tagua-1.0-alpha2/src/graphicalapi_unwrapped.h000066400000000000000000000057561077523320400213110ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef UNWRAPPEDGRAPHICALAPI_H #define UNWRAPPEDGRAPHICALAPI_H #include "graphicalapi.h" /** * This class moves the interface that will be used by the animator to modify * tagua graphics into the variant's semantics. */ template class UnwrappedGraphicalAPI { GraphicalAPI* m_graphical_api; public: typedef boost::shared_ptr Ptr; UnwrappedGraphicalAPI(GraphicalAPI* interface) : m_graphical_api(interface) { } virtual ~UnwrappedGraphicalAPI(){} virtual const PointConverter* converter() { return m_graphical_api->converter(); } virtual const typename Variant::Position* position() { const WrappedPosition *p = dynamic_cast*>(m_graphical_api->position().get()); if(p) return &p->inner(); else { MISMATCH(m_graphical_api->position(), WrappedPosition); return NULL; } } virtual NamedSprite setPiece(const Point& p, const typename Variant::Piece& piece, bool show) { WrappedPiece wpiece(piece); return m_graphical_api->setPiece(p, &wpiece, show); } virtual NamedSprite createPiece(const Point& p, const typename Variant::Piece& piece, bool show) { WrappedPiece wpiece(piece); return m_graphical_api->createPiece(p, &wpiece, show); } virtual void setSprite(const Point& p, const NamedSprite& s) { m_graphical_api->setSprite(p, s); } virtual NamedSprite getSprite(const Point& p) { return m_graphical_api->getSprite(p); } virtual NamedSprite takeSprite(const Point& p) { return m_graphical_api->takeSprite(p); } virtual int poolSize(int pool) const { return m_graphical_api->poolSize(pool); } virtual NamedSprite insertPoolPiece(int pool, int index, const typename Variant::Piece& piece) { WrappedPiece wpiece(piece); return m_graphical_api->insertPoolPiece(pool, index, &wpiece); } // virtual NamedSprite getPoolSprite(int pool, int index) { // return m_graphical_api->getPoolSprite(pool, index); // } virtual void removePoolSprite(int pool, int index) { m_graphical_api->removePoolSprite(pool, index); } virtual NamedSprite takePoolSprite(int pool, int index) { return m_graphical_api->takePoolSprite(pool, index); } virtual std::pair droppedPoolPiece() { return m_graphical_api->droppedPoolPiece(); } virtual AnimationPtr animate(const Animate::Scheme& scheme, Animate::AnimationType type = Animate::Normal) { return m_graphical_api->animate(scheme, type); } GraphicalAPI* inner() const { return m_graphical_api; } }; #endif //UNWRAPPEDGRAPHICALAPI_H tagua-1.0-alpha2/src/graphicalgame.cpp000066400000000000000000000215351077523320400177100ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "graphicalgame.h" #include #include "game.h" #include "game_p.h" #include "mastersettings.h" #include "graphicalsystem.h" #include "movelist_table.h" #include "decoratedmove.h" #include "entities/userentity.h" using namespace GamePrivate; // is this ok? template inline void setFlag(QFlags& flag, Enum e, bool value) { if (value) flag |= e; else flag &= ~e; } class CtrlAction { Game* m_game; bool m_done; Index m_index; public: CtrlAction(Game* game) : m_game(game) , m_index(game->index()) { m_done = m_game->back(); } void forfait() { m_done = false; } ~CtrlAction() { if (m_done) m_game->goTo(m_index); } }; GraphicalGame::GraphicalGame(GraphicalSystem* graphical, MoveList::Table* m) : Game() , m_graphical(graphical) , m_movelist(m) , m_anim_sequence(false) { m_action_state = 0; if(m_movelist) { m_movelist->reset(); m_movelist->setLayoutStyle(graphical->m_variant->moveListLayout()); m_movelist->setNotifier( static_cast(this) ); m_movelist->show(); } settings().onChange(this, "settingsChanged", "Loader::Theme"); settingsChanged(); } GraphicalGame::~GraphicalGame() { if(m_movelist) { Q_ASSERT(m_movelist->getNotifier() == static_cast(this)); m_movelist->setNotifier(NULL, false); } } void GraphicalGame::settingsChanged() { m_anim_sequence = settings().flag("animations", true) && settings()("animations").flag("sequence", true); m_anim_sequence_max = settings()("animations")("sequence")[QString("max")] | 10; } void GraphicalGame::onAdded(const Index& ix) { onAddedInternal(ix); updateActionState(); } void GraphicalGame::onAddedInternal(const Index& ix, bool confirm_promotion) { if(!m_movelist) return; int at; History *vec = fetchRef(ix, &at); if(!vec) { kError() << "invalid index " << ix; return; } m_movelist->remove(ix, confirm_promotion); //clear existing, if any Index index = ix; for(int i=at;i<(int)vec->size();i++) { Entry* e = &(*vec)[i]; PositionPtr prev = position(index.prev()); DecoratedMove mv( (e->move && prev) ? e->move->toString("decorated", prev) : (e->position ? "(-)" : "???")); int turn = prev ? prev->turn() : (index.totalNumMoves()+1)%2; //mv += " " + QString::number(turn); m_movelist->setMove(index, turn, mv, e->comment, confirm_promotion); for (Variations::const_iterator it = e->variations.begin(); it != e->variations.end(); ++it) onAddedInternal(index.next(it->first), confirm_promotion); for (VComments::const_iterator it = e->vcomments.begin(); it != e->vcomments.end(); ++it) m_movelist->setVComment(index, it->first, it->second, confirm_promotion); index = index.next(); } } void GraphicalGame::onEntryChanged(const Index& at, int propagate) { if(at <= Index(0)) { Entry* e = fetch(at); if(!e) return; if(at == current && e->position) m_graphical->warp(e->move, e->position); return; } if(m_movelist) { Entry* e = fetch(at); if(!e) return; Entry* pe = fetch(at.prev()); AbstractPosition::Ptr last_pos; if (pe) last_pos = pe->position; DecoratedMove mv( (e->move && last_pos) ? e->move->toString("decorated", last_pos) : (e->position ? "(-)" : "???")); int turn = last_pos ? last_pos->turn() : (at.totalNumMoves()+1)%2; m_movelist->setMove(at, turn, mv, e->comment); if(at == current && e->position) m_graphical->warp(e->move, e->position); // when an entry changes, chances are that we get some more information about the // next ones as well if(propagate) { onEntryChanged(at.next(), propagate-1); for (Variations::const_iterator it = e->variations.begin(); it != e->variations.end(); ++it) onEntryChanged(at.next(it->first), propagate-1); } } } void GraphicalGame::onRemoved(const Index& i) { if(m_movelist) m_movelist->remove(i); updateActionState(); } void GraphicalGame::onPromoteVariation(const Index& i, int v) { if(m_movelist) { m_movelist->promoteVariation(i,v); onAddedInternal(i.next(), true); onAddedInternal(i.next(v), true); VComments vc = fetch(i)->vcomments; VComments::const_iterator it = vc.find(v); if(it != vc.end()) m_movelist->setVComment(i, v, it->second, true); m_movelist->select(current, true); } updateActionState(); } void GraphicalGame::onSetComment(const Index& i, const QString& s) { if(m_movelist) m_movelist->setComment(i, s); } void GraphicalGame::onSetVComment(const Index& i, int v, const QString& s) { if(m_movelist) m_movelist->setVComment(i, v, s); } void GraphicalGame::updateActionState() { ActionState old_state = m_action_state; setFlag(m_action_state, BACK, current != 0); setFlag(m_action_state, BEGIN, current != 0); Entry* next_entry = fetch(current.next()); setFlag(m_action_state, FORWARD, next_entry); setFlag(m_action_state, END, next_entry); if (old_state != m_action_state) onActionStateChange(); } void GraphicalGame::onCurrentIndexChanged(const Index& old_c) { if (m_ctrl) m_ctrl->forfait(); if(m_movelist) m_movelist->select(current); updateActionState(); Entry *oe = fetch(old_c); Entry *e = fetch(current); std::pair steps = old_c.stepsTo(current); if(!e || !e->position) return; if(!oe || !oe->position) { m_graphical->warp(move(), position()); return; } bool can_animate = (steps.first+steps.second <= 1) || (m_anim_sequence && (steps.first+steps.second <= m_anim_sequence_max)); if(can_animate) for(int i=1;i<=steps.first;i++) if( !move(old_c.prev(i-1)) || !position(old_c.prev(i))) { can_animate = false; break; } if(can_animate) for(int i=steps.second-1;i>=0;i--) if( !move(current.prev(i)) || !position(current.prev(i))) { can_animate = false; break; } if(can_animate) { for(int i=1;i<=steps.first;i++) m_graphical->back( move(old_c.prev(i)), move(old_c.prev(i-1)), position(old_c.prev(i))); for(int i=steps.second-1;i>=0;i--) m_graphical->forward( move(current.prev(i)), position(current.prev(i))); } else m_graphical->warp( move(), position()); // set m_action_state } void GraphicalGame::onAvailableUndo(bool e) { setFlag(m_action_state, UNDO, e); onActionStateChange(); } void GraphicalGame::onAvailableRedo(bool e) { setFlag(m_action_state, REDO, e); onActionStateChange(); } void GraphicalGame::onUserSelectMove(const Index& i) { if (boost::shared_ptr entity = m_listener_entity.lock()) if (entity->goTo(i)) return; // fallback goTo(i); } void GraphicalGame::onUserSetComment(const Index& i, QString s) { setComment(i, s); } void GraphicalGame::onUserSetVComment(const Index& i, int v, QString s) { setVComment(i, v, s); } void GraphicalGame::onUserClearVariations(const Index& i) { clearVariations(i); } void GraphicalGame::onUserTruncate(const Index& i) { if (i == index()) if (boost::shared_ptr entity = m_listener_entity.lock()) if (entity->truncate()) return; // fallback truncate(i); } void GraphicalGame::onUserPromoteVariation(const Index& i) { if (i == index()) if (boost::shared_ptr entity = m_listener_entity.lock()) if (entity->promoteVariation()) return; // fallback promoteVariation(i); } void GraphicalGame::onUserRemoveVariation(const Index& i) { removeVariation(i); } void GraphicalGame::onUserUndo() { if (boost::shared_ptr entity = m_listener_entity.lock()) if (entity->undo()) return; // fallback undo(); } void GraphicalGame::onUserRedo() { if (boost::shared_ptr entity = m_listener_entity.lock()) if (entity->redo()) return; // fallback redo(); } void GraphicalGame::onDetachNotifier() { Q_ASSERT(m_movelist->getNotifier() == static_cast(this)); m_movelist = NULL; } void GraphicalGame::createCtrlAction() { m_ctrl = boost::shared_ptr(new CtrlAction(this)); } void GraphicalGame::destroyCtrlAction() { m_ctrl.reset(); } void GraphicalGame::setActionStateObserver( const boost::shared_ptr& obs) { m_action_state_observer = obs; } void GraphicalGame::onActionStateChange() { m_action_state_observer->notifyActionStateChange(m_action_state); } ActionStateObserver::~ActionStateObserver() { } tagua-1.0-alpha2/src/graphicalgame.h000066400000000000000000000062511077523320400173530ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef GRAPHICALGAME_H #define GRAPHICALGAME_H #include #include #include #include "game.h" #include "movelist_notifier.h" class GraphicalSystem; class CtrlAction; class UserEntity; class GraphicalGame; class ActionStateObserver; namespace MoveList { class Table; } class GraphicalGame : public QObject, public Game, public MoveList::Notifier { Q_OBJECT public: /** * @brief State of GUI actions associated to a game. */ enum ActionStateFlag { UNDO = 0x1, REDO = 0x2, BEGIN = 0x4, BACK = 0x8, FORWARD = 0x10, END = 0x20 }; Q_DECLARE_FLAGS(ActionState, ActionStateFlag) private: GraphicalSystem* m_graphical; MoveList::Table* m_movelist; bool m_anim_sequence; int m_anim_sequence_max; boost::shared_ptr m_ctrl; boost::weak_ptr m_listener_entity; boost::shared_ptr m_action_state_observer; ActionState m_action_state; void updateActionState(); private Q_SLOTS: void settingsChanged(); public: GraphicalGame(GraphicalSystem* graphical, MoveList::Table* m); ~GraphicalGame(); void onAddedInternal(const Index& i, bool confirm_promotion = false); virtual void onAdded(const Index& i); virtual void onRemoved(const Index& i); virtual void onEntryChanged(const Index& at, int propagate=1); virtual void onPromoteVariation(const Index& i, int v); virtual void onSetComment(const Index& i, const QString& s); virtual void onSetVComment(const Index& i, int v, const QString& s); virtual void onCurrentIndexChanged(const Index& old_c); virtual void onAvailableUndo(bool e); virtual void onAvailableRedo(bool e); virtual void onUserSelectMove(const Index& i); virtual void onUserSetComment(const Index& i, QString s); virtual void onUserSetVComment(const Index& i, int v, QString s); virtual void onUserClearVariations(const Index& i); virtual void onUserTruncate(const Index& i); virtual void onUserPromoteVariation(const Index& i); virtual void onUserRemoveVariation(const Index& i); virtual void onUserUndo(); virtual void onUserRedo(); virtual void onDetachNotifier(); virtual void createCtrlAction(); virtual void destroyCtrlAction(); void setEntity(const boost::shared_ptr& entity) { m_listener_entity = entity; } void detachEntity() { m_listener_entity.reset(); } void setActionStateObserver(const boost::shared_ptr& obs); void onActionStateChange(); }; Q_DECLARE_OPERATORS_FOR_FLAGS(GraphicalGame::ActionState) /** * @brief An observer that is notified of changes in the ActionState flags. */ class ActionStateObserver { public: virtual ~ActionStateObserver(); virtual void notifyActionStateChange(GraphicalGame::ActionState state) = 0; }; #endif //GRAPHICALGAME_H tagua-1.0-alpha2/src/graphicalsystem.cpp000066400000000000000000000237111077523320400203210ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "graphicalsystem.h" #include "chesstable.h" #include "board.h" #include "clock.h" #include "piecepool.h" #include "pointconverter.h" #include "sprite.h" #include "animation.h" #include "pref_theme.h" #include "movelist_table.h" #include "mastersettings.h" using namespace boost; //BEGIN GraphicalSystem GraphicalSystem::GraphicalSystem(ChessTable* view, AbstractPosition::Ptr startingPosition, const VariantPtr& variant) : m_view(view) , m_variant(variant) { m_pos = startingPosition->clone(); Point s = m_pos->size(); for(int i=0;iset(Point(i,j), AbstractPiece::Ptr()); m_board = view->board(); m_board->createGrid(m_pos->size(), m_pos->borderCoords()); m_board->reset(); m_view->pool(0)->clear(); m_view->pool(1)->clear(); m_animator = m_variant->createAnimator(this); // settings().onChange(this, "settingsChanged", "Loader::Theme"); settingsChanged(); if (startingPosition) warp(AbstractMove::Ptr(), startingPosition); } GraphicalSystem::~GraphicalSystem() { } const PointConverter* GraphicalSystem::converter() const { return m_board->converter(); } AbstractPosition::Ptr GraphicalSystem::position() const { return m_pos; } void GraphicalSystem::settingsChanged() { /* recreate the animator to reload its settings */ m_animator = m_variant->createAnimator(this); ThemeInfo theme = PrefTheme::getBestTheme(m_variant, "pieces"); ThemeInfo sqtheme = PrefTheme::getBestTheme(m_variant, "squares"); ThemeInfo figtheme = PrefTheme::getBestTheme(m_variant, "figurines"); ThemeInfo ctrltheme = PrefTheme::getBestTheme(m_variant, "controls"); m_board->loader()->setTheme(theme); m_board->tagsLoader()->setTheme(sqtheme); m_board->controlsLoader()->setTheme(ctrltheme); for(int i=0;i<2;i++) m_view->pool(i)->loader()->setTheme(theme); for(int i=0;i<2;i++) m_view->clock(i)->controlsLoader()->setTheme(ctrltheme); m_view->moveListTable()->setLoaderTheme(figtheme); m_view->moveListTable()->settingsChanged(); //clear board and pool, forcing reload m_view->settingsChanged(); } void GraphicalSystem::setup(const shared_ptr& entity) { m_view->setEntity(entity); } NamedSprite GraphicalSystem::getSprite(const Point& p) { if (!m_board->m_sprites.valid(p)) return NamedSprite(); return m_board->m_sprites[p]; } NamedSprite GraphicalSystem::takeSprite(const Point& p) { if (!m_board->m_sprites.valid(p)) return NamedSprite(); NamedSprite retv = m_board->m_sprites[p]; m_board->m_sprites[p] = NamedSprite(); return retv; } NamedSprite GraphicalSystem::setPiece(const Point& p, const AbstractPiece* piece, bool show) { return m_board->m_sprites[p] = createPiece(p, piece, show); } NamedSprite GraphicalSystem::createPiece(const Point& p, const AbstractPiece* piece, bool show) { Q_ASSERT(piece); if (!m_board->m_sprites.valid(p)) return NamedSprite(); NamedSprite s(piece->name(), SpritePtr(new Sprite(m_board->loadSprite(piece->name()), m_board->piecesGroup(), m_board->converter()->toReal(p))) ); if (show) s.sprite()->show(); return s; } void GraphicalSystem::setSprite(const Point& p, const NamedSprite& sprite) { if (!m_board->m_sprites.valid(p)) return; m_board->m_sprites[p] = sprite; } int GraphicalSystem::poolSize(int pool) { return m_view->pool(pool)->fill(); } NamedSprite GraphicalSystem::getPoolSprite(int pool, int index) { return m_view->pool(pool)->getSprite(index); } void GraphicalSystem::removePoolSprite(int pool, int index) { m_view->pool(pool)->removeSprite(index); } NamedSprite GraphicalSystem::takePoolSprite(int pool, int index) { return m_view->pool(pool)->takeSprite(index); } NamedSprite GraphicalSystem::insertPoolPiece(int pool, int index, const AbstractPiece* piece) { PiecePool *pl = m_view->pool(pool); QPixmap px = pl->loadSprite(piece->name()); // QPixmap px = pl->m_loader(piece->name()); NamedSprite s( piece->name(), SpritePtr( new Sprite( px, pl, QPoint() ) ) ); pl->insertSprite(index, s); return s; } std::pair GraphicalSystem::droppedPoolPiece() { return std::pair(m_board->m_dropped_pool, m_board->m_dropped_index); } AnimationPtr GraphicalSystem::animate(const Animate::Scheme& scheme, Animate::AnimationType type) { return scheme.run(m_view->animationSettings(), converter(), type); } #if 0 void GraphicalSystem::updatePool(AbstractPosition::PoolPtr pool) { AbstractPosition::PoolPtr curr = m_pos->pool(); AbstractPosition::AbstractPool::iterator oldit = curr->begin(); AbstractPosition::AbstractPool::iterator newit = pool->begin(); while(oldit != curr->end() || newit != pool->end()) { if(newit == pool->end() || (oldit != curr->end() && oldit->first->less(newit->first) )) { removeFromPool(oldit->first, oldit->second); ++oldit; } else if (oldit == curr->end() || (newit != pool->end() && newit->first->less(oldit->first) )) { addToPool(newit->first, newit->second); ++newit; } else { Q_ASSERT(newit->first->equals(oldit->first)); if(oldit->second < newit->second) addToPool(newit->first, newit->second - oldit->second); else if(oldit->second > newit->second) removeFromPool(newit->first, oldit->second - newit->second); ++newit; ++oldit; } } } void GraphicalSystem::addToPool(AbstractPiece::Ptr piece, int n) { PiecePool *pool = m_view->pool(!piece->color()); QPixmap px = pool->m_loader(piece->name()); for(int i=0;ipiecesGroup(), QPoint() ) ); pool->addPiece(Element(piece, s)); } m_pos->addToPool(piece, n); } void GraphicalSystem::removeFromPool(AbstractPiece::Ptr piece, int n) { PiecePool *pool = m_view->pool(!piece->color()); for(int i=0;itakePiece(piece); m_pos->removeFromPool(piece, n); } #endif #if 0 void GraphicalSystem::addTag(const QString& name, Point pt, bool over) { m_board->addTag(name, pt, over); } void GraphicalSystem::clearTags(const QString& name) { m_board->clearTags(name); } void GraphicalSystem::setTags(const QString& name, Point p1, Point p2, Point p3, Point p4, Point p5, Point p6 ) { m_board->setTags(name, p1, p2, p3, p4, p5, p6); } #endif #if 0 bool GraphicalSystem::consistent() const { for (Point i = first(); i <= last(); i = next(i)) { Element e = getElement(i); if (static_cast(e.piece()) ^ static_cast(e.sprite())) return false; } return true; } #endif #if 0 Point GraphicalSystem::first() const { return m_board->m_sprites.first(); } Point GraphicalSystem::last() const { return m_board->m_sprites.last(); } Point GraphicalSystem::next(const Point& p) const { return m_board->m_sprites.next(p); } bool GraphicalSystem::valid(const Point& p) const { return m_board->m_sprites.valid(p); } #endif void GraphicalSystem::forward(const AbstractMove::Ptr& move, const AbstractPosition::Ptr& pos, const SpritePtr& /*movingSprite*/) { AbstractPiece::Ptr sel1 = m_pos->get(m_board->selection); if (move) { AnimationPtr animation = m_animator->forward(pos, move); //??? animation->setChainAbortions(false); m_board->enqueue(animation); m_board->setTags("highlighting", move->toUserMove().from, move->toUserMove().to); m_pos->copyFrom(pos); } else warp(AbstractMove::Ptr(), pos); AbstractPiece::Ptr sel2 = m_pos->get(m_board->selection); if(!(sel1 && sel2 && sel1->equals(sel2))) m_board->cancelSelection(); m_board->cancelPremove(); m_view->updateTurn(pos->turn()); m_board->onPositionChanged(); } void GraphicalSystem::back(const AbstractMove::Ptr& lastMove, const AbstractMove::Ptr& move, const AbstractPosition::Ptr& pos) { AbstractPiece::Ptr sel1 = m_pos->get(m_board->selection); if (move) { AnimationPtr animation = m_animator->back(pos, move); //??? animation->setChainAbortions(false); m_board->enqueue(animation); m_pos->copyFrom(pos); } else warp(lastMove, pos); if (lastMove) m_board->setTags("highlighting", lastMove->toUserMove().from, lastMove->toUserMove().to); else m_board->clearTags("highlighting"); AbstractPiece::Ptr sel2 = m_pos->get(m_board->selection); if(!(sel1 && sel2 && sel1->equals(sel2))) m_board->cancelSelection(); m_board->cancelPremove(); m_view->updateTurn(pos->turn()); m_board->onPositionChanged(); } void GraphicalSystem::warp(const AbstractMove::Ptr& lastMove, const AbstractPosition::Ptr& pos) { AbstractPiece::Ptr sel1 = m_pos->get(m_board->selection); AnimationPtr animation = m_animator->warp(pos); //??? animation->setChainAbortions(false); if (animation) { m_board->enqueue(animation); } m_pos->copyFrom(pos); if (lastMove) m_board->setTags("highlighting", lastMove->toUserMove().from, lastMove->toUserMove().to); else m_board->clearTags("highlighting"); AbstractPiece::Ptr sel2 = m_pos->get(m_board->selection); if(!(sel1 && sel2 && sel1->equals(sel2))) m_board->cancelSelection(); m_view->updateTurn(pos->turn()); m_board->onPositionChanged(); } void GraphicalSystem::adjustSprite(const Point& p) { SpritePtr sprite = m_board->m_sprites[p].sprite(); Q_ASSERT(sprite); QPoint destination = m_board->converter()->toReal(p); shared_ptr animation(new MovementAnimation(sprite, destination)); m_board->enqueue(animation); } void GraphicalSystem::setTurn(int turn) { m_pos->setTurn(turn); m_view->updateTurn(m_pos->turn()); } tagua-1.0-alpha2/src/graphicalsystem.h000066400000000000000000000122021077523320400177570ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef GRAPHICALSYSTEM_H #define GRAPHICALSYSTEM_H #include #include #include "graphicalapi.h" class ChessTable; class Board; class UserEntity; class GraphicalSystem : public QObject, private GraphicalAPI { Q_OBJECT public: /** The current chess table */ ChessTable* m_view; /** The current board */ Board* m_board; /** The position data */ AbstractPosition::Ptr m_pos; /** The variant specific animator */ AbstractAnimator::Ptr m_animator; /** The current variant */ VariantPtr m_variant; /** @a GraphicalPosition interface function implementation */ // virtual void addTag(const QString& name, Point, bool over = false); /** @a GraphicalPosition interface function implementation */ // virtual void clearTags(const QString& name); /** @a GraphicalPosition interface function implementation */ // virtual void setTags(const QString& name, Point p1 = Point::invalid(), Point p2 = Point::invalid(), // Point p3 = Point::invalid(), Point p4 = Point::invalid(), // Point p5 = Point::invalid(), Point p6 = Point::invalid() ); public Q_SLOTS: /** internal function to listen at setting changes */ void settingsChanged(); private: /** * \return the current abstract position. (interface for GraphicalAPI) */ virtual const PointConverter* converter() const; /** * \return the current abstract position. (interface for GraphicalAPI) */ virtual AbstractPosition::Ptr position() const; /** * \return a sprite at the position \a index in the graphical pool. (interface for GraphicalAPI) */ virtual NamedSprite getSprite(const Point& p); /** * Removes a sprite at the position \a index in the graphical pool. (interface for GraphicalAPI) * \return the newly created sprite. */ virtual NamedSprite takeSprite(const Point& p); /** * Sets the piece at the position \a index in the graphical pool. (interface for GraphicalAPI) * \return the newly created sprite. */ virtual NamedSprite setPiece(const Point& p, const AbstractPiece* piece, bool show); /** * Create a new piece, but do not add it to the graphical system. * \return the newly created sprite. */ virtual NamedSprite createPiece(const Point& p, const AbstractPiece* piece, bool show); /** * Sets the sprite at the position \a index in the graphical pool. (interface for GraphicalAPI) * \return the newly created sprite. */ virtual void setSprite(const Point& p, const NamedSprite& sprite); /** * \return how many sprites are contained in the pool */ virtual int poolSize(int pool); /** * \return the sprite at the position \a index in the graphical pool. (interface for GraphicalAPI) */ virtual NamedSprite getPoolSprite(int pool, int index); /** * Removes the sprite at the position \a index in the graphical pool. (interface for GraphicalAPI) */ virtual void removePoolSprite(int pool, int index); /** * Removes the sprite at the position \a index in the graphical pool (only for drops). * (interface for GraphicalAPI) * \return the removed sprite. */ virtual NamedSprite takePoolSprite(int pool, int index); /** * Inserts a sprite at the position \a index in the graphical pool. (interface for GraphicalAPI) * \return the newly created sprite. */ virtual NamedSprite insertPoolPiece(int pool, int index, const AbstractPiece* piece); /** * \return the piece of the pool that has been dropped, or (-1,-1). (interface for GraphicalAPI) */ virtual std::pair droppedPoolPiece(); /** * Create an animation from a scheme. */ virtual AnimationPtr animate(const Animate::Scheme& scheme, Animate::AnimationType type); public: /** Constructor */ GraphicalSystem(ChessTable* view, AbstractPosition::Ptr startingPosition, const VariantPtr& variant); virtual ~GraphicalSystem(); /** Sets the reference entity */ void setup(const boost::shared_ptr& entity); /** Goes forward playing a move, that has to be legal and checked */ void forward(const AbstractMove::Ptr& move, const AbstractPosition::Ptr& pos, const SpritePtr& = SpritePtr()); /** Goes back undoing a move, that has to be legal and checked */ void back(const AbstractMove::Ptr& lastMove, const AbstractMove::Ptr& move, const AbstractPosition::Ptr& pos); /** Warps to a new position */ void warp(const AbstractMove::Ptr& lastMove, const AbstractPosition::Ptr& pos); /** Adjusts a sprite to the correct position */ void adjustSprite(const Point& p); /** Sets the current turn */ void setTurn(int turn); }; #endif //GRAPHICALSYSTEM_H tagua-1.0-alpha2/src/grid.h000066400000000000000000000061731077523320400155170ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef GRID_H #define GRID_H #include #include #include #include #include "point.h" #include "pathinfo.h" template class Grid { int sizeX, sizeY; protected: std::vector board; public: template friend class Grid; Grid(int sizeX, int sizeY, const T& defaultValue) : sizeX(sizeX), sizeY(sizeY) { board.resize(sizeX * sizeY, defaultValue); } Grid(int sizeX, int sizeY) : sizeX(sizeX), sizeY(sizeY) { board.resize(sizeX * sizeY); } Grid(const Grid& other) : sizeX(other.sizeX), sizeY(other.sizeY) , board(other.board) { } template Grid(const Grid& other) : sizeX(other.getSize().x), sizeY(other.getSize().y) { board.resize(sizeX * sizeY); for(int i=sizeX * sizeY-1; i>=0;i--) board[i] = other.board[i]; } Point getSize() const { return Point(sizeX, sizeY); } void changeSize(int x, int y) { sizeX = x; sizeY = y; board.resize(sizeX * sizeY); } const T& operator[](Point p) const { Q_ASSERT(valid(p)); return board[p.x + p.y * sizeX]; } T& operator[](Point p) { Q_ASSERT(valid(p)); return board[p.x + p.y * sizeX]; } /** \return the nth point in the grid, that is not guaranteed to be valid */ Point nTh(int index) const { return Point(index%sizeX, index/sizeX); } Point first() const { return Point(0,0); } Point last() const { return Point(sizeX-1, sizeY-1); } Point next(const Point& p) const { if (p.x >= sizeX-1) return Point(0, p.y+1); else return Point(p.x+1, p.y); } bool valid(const Point& p) const { return (0 <= p.x) && (p.x < sizeX) && (0 <= p.y) && (p.y < sizeY); } bool operator==(const Grid& g) const { if(g.sizeX != sizeX || g.sizeY != sizeY) return false; for(unsigned int i=0;i (c) 2006 Maurizio Monge 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. */ #ifndef HIGHLIGHTER_H #define HIGHLIGHTER_H #include #include #include class PatternListAdaptorOutputIterator; class PatternListAdaptorInputIterator; class Highlighter : public QSyntaxHighlighter { Q_OBJECT public: struct Pattern { QString name; QRegExp pattern; QTextCharFormat format; }; private: std::vector m_patterns; public: Highlighter(QTextDocument* parent); Highlighter(QTextDocument* parent, const Pattern& pattern); void reload(); static void load(PatternListAdaptorOutputIterator& out); static void save(const PatternListAdaptorInputIterator& in); virtual void highlightBlock(const QString& text); std::vector& patterns(); }; class PatternListAdaptorOutputIterator { public: virtual ~PatternListAdaptorOutputIterator() { } virtual void add(const Highlighter::Pattern&) = 0; }; class PatternListAdaptorInputIterator { public: virtual ~PatternListAdaptorInputIterator() { } virtual boost::shared_ptr clone() const = 0; virtual bool valid() const = 0; virtual PatternListAdaptorInputIterator& inc() = 0; virtual const Highlighter::Pattern& value() const = 0; }; #endif // HIGHLIGHTER_H tagua-1.0-alpha2/src/histlineedit.cpp000066400000000000000000000027611077523320400176110ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include "histlineedit.h" HistLineEdit::HistLineEdit(QWidget* parent) : QLineEdit(parent) { current = 0; connect(this, SIGNAL(returnPressed()), this, SLOT(updateHistory())); } void HistLineEdit::keyPressEvent(QKeyEvent* e) { if (echoMode() == Password) { e->ignore(); QLineEdit::keyPressEvent(e); return; } if (e->key() == Qt::Key_Up) { if (current > 0) setHistoryText(current-1); } else if (e->key() == Qt::Key_Down) { if (current < history.size()) setHistoryText(current+1); } else if (e->key() == Qt::Key_PageUp) pageUp(); else if (e->key() == Qt::Key_PageDown) pageDown(); else e->ignore(); QLineEdit::keyPressEvent(e); } void HistLineEdit::setHistoryText(uint index) { if (current == history.size()) buffer = text(); if (index == history.size()) setText(buffer); else setText(history[index]); current = index; } void HistLineEdit::updateHistory() { if (echoMode() != Password) { history.push_back(text()); buffer = ""; current = history.size(); } receivedInput(text()); setText(""); } tagua-1.0-alpha2/src/histlineedit.h000066400000000000000000000015521077523320400172530ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef HISTLINEEDIT_H #define HISTLINEEDIT_H #include #include class HistLineEdit : public QLineEdit { Q_OBJECT std::vector history; uint current; void setHistoryText(uint index); QString buffer; public: HistLineEdit(QWidget* parent); protected: void keyPressEvent(QKeyEvent*); public Q_SLOTS: void updateHistory(); Q_SIGNALS: void pageUp(); void pageDown(); void receivedInput(const QString&); }; #endif // HISTLINEEDIT_H tagua-1.0-alpha2/src/hline.cpp000066400000000000000000000105171077523320400162210ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "hline.h" #include class TrivialExecutor : public HLineExecutor { public: virtual ~TrivialExecutor() { kDebug(); } virtual void writeChunk(const QString& text) { kDebug() << text << "|"; } virtual void setFormat(const QTextCharFormat&) { } }; void HLine::Format::applyTo(QTextCharFormat& fmt) const { if (m_bold.first) { fmt.setFontWeight(m_bold.second ? QFont::Bold : QFont::Normal); } if (m_italic.first) { fmt.setFontItalic(m_italic.second); } if (m_color.first) fmt.setForeground(m_color.second); } HLine::HLine(const QString& text, const QTextCharFormat& baseFormat) : m_text(text) { m_regions.push_back(Region(text.length(), baseFormat)); } HLine::HLine(const HLine& other) : m_regions(other.m_regions) , m_text(other.m_text) { } uint HLine::findRegion(int index) const { if (index >= m_text.length()) return m_regions.size(); uint r = 0; while (index >= m_regions[r].end()) r++; Q_ASSERT(r < m_regions.size()); return r; } int HLine::begin(uint r) const { if (r == 0) return 0; else return m_regions[r - 1].end(); } uint HLine::splitRegion(int index) { if (index >= m_text.length()) return m_regions.size(); int r = findRegion(index); if (begin(r) != index) { m_regions.insert( m_regions.begin() + r + 1, m_regions[r]); m_regions[r].setEnd(index); return r + 1; } else return r; } const QTextCharFormat& HLine::getFormat(int index) const { return m_regions[findRegion(index)].format(); } void HLine::setFormat(int begin, int end, const Format& format) { Q_ASSERT(begin < m_text.length()); Q_ASSERT(end <= m_text.length()); if (begin >= end) return; int r1 = splitRegion(begin); int r2 = splitRegion(end); for (int r = r1; r < r2; r++) { QTextCharFormat fmt = m_regions[r].format(); format.applyTo(fmt); m_regions[r].setFormat(fmt); } } void HLine::setBold(int begin, int end, bool value) { Format format; format.m_bold = std::make_pair(true, value); setFormat(begin, end, format); } void HLine::setItalic(int begin, int end, bool value) { Format format; format.m_italic = std::make_pair(true, value); setFormat(begin, end, format); } void HLine::setColor(int begin, int end, const QColor& color) { Format format; format.m_color = std::make_pair(true, color); setFormat(begin, end, format); } QString HLine::mid(int begin, int end) const { return m_text.mid(begin, end - begin); } HLine* HLine::extract(int begin, int end) const { HLine* res = new HLine(*this); int r1 = res->splitRegion(begin); int r2 = res->splitRegion(end); // adjust text res->m_text = mid(begin, end); // remove superfluous regions res->m_regions.erase( res->m_regions.begin() + r2, res->m_regions.end()); res->m_regions.erase( res->m_regions.begin(), res->m_regions.begin() + r1); // adjust regions for (uint i = 0; i < res->m_regions.size(); i++) { res->m_regions[i].setEnd(res->m_regions[i].end() - begin); } return res; } HLine* HLine::append(const HLine& other, int begin, int end) const { HLine* res = new HLine(*this); int old_r = res->m_regions.size(); int old_length = res->m_text.length(); // append text res->m_text += other.mid(begin, end); // add regions int r1 = other.findRegion(begin); int r2 = other.findRegion(end); std::copy(other.m_regions.begin() + r1, other.m_regions.begin() + r2, std::back_insert_iterator >(res->m_regions)); // adjust regions for (uint i = old_r; i < res->m_regions.size(); i++) { int new_end = old_length + res->m_regions[i].end() - begin; res->m_regions[i].setEnd(new_end); } return res; } void HLine::dump() const { TrivialExecutor executor; run(executor); } void HLine::run(HLineExecutor& executor) const { int begin = 0; for (uint i = 0; i < m_regions.size(); i++) { int end = m_regions[i].end(); executor.setFormat(m_regions[i].format()); executor.writeChunk(mid(begin, end)); begin = end; } } tagua-1.0-alpha2/src/hline.h000066400000000000000000000042551077523320400156700ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef HLINE_H #define HLINE_H #include #include #include #include class HLineExecutor { public: virtual ~HLineExecutor() { } virtual void writeChunk(const QString&) = 0; virtual void setFormat(const QTextCharFormat&) = 0; }; class HLine { class Region { int m_end; QTextCharFormat m_format; public: Region(int end, QTextCharFormat format) : m_end(end) , m_format(format) { } int end() const { return m_end; } const QTextCharFormat& format() const { return m_format; } QTextCharFormat& format() { return m_format; } void setEnd(int index) { m_end = index; } void setFormat(const QTextCharFormat& format) { m_format = format; } }; struct Format { std::pair m_bold; std::pair m_italic; std::pair m_color; Format() : m_bold(false, false) , m_italic(false, false) , m_color(false, QColor()) { } void applyTo(QTextCharFormat& fmt) const; }; std::vector m_regions; QString m_text; int begin(uint index) const; uint findRegion(int index) const; uint splitRegion(int index); void setFormat(int begin, int end, const Format&); public: HLine(const QString& text, const QTextCharFormat& baseFormat); HLine(const HLine& other); const QTextCharFormat& getFormat(int index) const; void setBold(int begin, int end, bool value); void setItalic(int begin, int end, bool value); void setColor(int begin, int end, const QColor& color); QString mid(int begin, int end) const; int length() const { return m_text.length(); } HLine* extract(int begin, int end) const; HLine* append(const HLine& other, int begin, int end) const; void dump() const; void run(HLineExecutor&) const; }; #endif // HLINE_H tagua-1.0-alpha2/src/hlvariant/000077500000000000000000000000001077523320400164025ustar00rootroot00000000000000tagua-1.0-alpha2/src/hlvariant/animator.h000066400000000000000000000173071077523320400203750ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef HLVARIANT__ANIMATOR_H #define HLVARIANT__ANIMATOR_H #include "animation.h" #include #include "fwd.h" #include "variantdata.h" #include "namedsprite.h" #include "animationfactory.h" #include "common.h" class NamedSprite; class Point; class AnimationFactory; namespace HLVariant { /** * A generic animator. * Can be used as a base class for other specialized animators. */ template class BaseAnimator { public: typedef _Variant Variant; protected: typedef typename UnwrappedGraphicalAPIPtr::type API; typedef typename VariantData::GameState GameState; typedef typename VariantData::Move Move; typedef typename VariantData::Piece Piece; API m_cinterface; public: BaseAnimator(API cinterface) : m_cinterface(cinterface) { } virtual ~BaseAnimator() { } virtual AnimationGroupPtr warp(const GameState& final); virtual AnimationGroupPtr forward(const GameState& final, const Move& move); virtual AnimationGroupPtr back(const GameState& final, const Move& move); }; template class SimpleAnimator : BaseAnimator<_Variant> { public: typedef _Variant Variant; private: typedef BaseAnimator Base; protected: typedef typename Base::API API; typedef typename Base::GameState GameState; typedef typename Base::Move Move; typedef typename Base::Piece Piece; using Base::m_cinterface; virtual SchemePtr movement(const NamedSprite& sprite, const Point& from, const Point& to); public: SimpleAnimator(API cinterface) : Base(cinterface) { } virtual AnimationGroupPtr warp(const GameState& final); virtual AnimationGroupPtr forward(const GameState& final, const Move& move); virtual AnimationGroupPtr back(const GameState& final, const Move& move); }; // IMPLEMENTATION template AnimationGroupPtr BaseAnimator::warp(const GameState& final) { const GameState* current = m_cinterface->position(); AnimationFactory res(m_cinterface->inner()); for (int i = 0; i < current->board().size().x; i++) { for (int j = 0; j < current->board().size().y; j++) { Point p(i, j); NamedSprite sprite = m_cinterface->getSprite(p); Piece piece = final.board().get(p); if (!sprite && piece != Piece()) { res.addPreAnimation(Animate::appear(m_cinterface->setPiece(p, piece, false)), Animate::Instant); } else if (sprite && piece == Piece()) { m_cinterface->takeSprite(p); res.addPreAnimation(Animate::disappear(sprite), Animate::Instant); } // sprite and piece differ else if (sprite && piece != Piece() && piece.name() != sprite.name()) { m_cinterface->takeSprite(p); res.addPreAnimation(Animate::morph(sprite, m_cinterface->setPiece(p, piece, false)), Animate::Instant); } } } return res; } template AnimationGroupPtr BaseAnimator::forward(const GameState& final, const Move&) { return warp(final); } template AnimationGroupPtr BaseAnimator::back(const GameState& final, const Move&) { return warp(final); } template AnimationGroupPtr SimpleAnimator::warp(const GameState& final) { AnimationFactory res(m_cinterface->inner()); res.setGroup(Base::warp(final)); return res; } template SchemePtr SimpleAnimator::movement(const NamedSprite& sprite, const Point& from, const Point& to) { bool knight = m_cinterface->position()->board().get(from).type() == Piece::KNIGHT; int mtype = knight ? Animate::move::LShaped | Animate::move::Rotating : Animate::move::Straight; return SchemePtr(new Animate::move(sprite, to, mtype)); } template AnimationGroupPtr SimpleAnimator::forward(const GameState& final, const Move& move) { AnimationFactory res(m_cinterface->inner()); NamedSprite piece = m_cinterface->takeSprite(move.from()); NamedSprite captured = m_cinterface->takeSprite(move.captureSquare()); m_cinterface->setSprite(move.to(), piece); if (piece) res.addPreAnimation(*movement(piece, move.from(), move.to())); else kError() << "Scheduling movement animation for a null piece"; if (captured) res.addPostAnimation(Animate::destroy(captured)); if (move.promoteTo() != -1) { Piece promoted = final.board().get(move.to()); if (promoted != Piece()) { QPoint real = m_cinterface->converter()->toReal(move.to()); NamedSprite old_sprite = m_cinterface->getSprite(move.to()); NamedSprite new_sprite = m_cinterface->setPiece(move.to(), promoted, /*false,*/ false); res.addPostAnimation(Animate::morph(old_sprite, new_sprite)); } else kError() << "Scheduling morph animation for a null piece"; } else if (move.kingSideCastling()) { Point rookSquare = move.to() + Point(1,0); Point rookDestination = move.from() + Point(1,0); NamedSprite rook = m_cinterface->takeSprite(rookSquare); m_cinterface->setSprite(rookDestination, rook); res.addPreAnimation(Animate::move(rook, rookDestination)); } else if (move.queenSideCastling()) { Point rookSquare = move.to() + Point(-2,0); Point rookDestination = move.from() + Point(-1,0); NamedSprite rook = m_cinterface->takeSprite(rookSquare); m_cinterface->setSprite(rookDestination, rook); res.addPreAnimation(Animate::move(rook, rookDestination)); } res.group()->addPostAnimation(warp(final)); return res; } template AnimationGroupPtr SimpleAnimator::back(const GameState& final, const Move& move) { AnimationFactory res(m_cinterface->inner()); NamedSprite piece = m_cinterface->takeSprite(move.to()); NamedSprite captured; Piece captured_piece = final.board().get(move.captureSquare()); if (captured_piece != Piece()) { captured = m_cinterface->setPiece(move.captureSquare(), captured_piece, false); res.addPreAnimation(Animate::appear(captured)); } if (!piece) { piece = m_cinterface->createPiece(move.to(), final.board().get(move.from()), false); res.addPreAnimation(Animate::appear(piece)); } m_cinterface->setSprite(move.from(), piece); if (move.promoteTo() != -1) { Piece pawn_piece = final.board().get(move.from()); if (pawn_piece != Piece()) { NamedSprite pawn = m_cinterface->createPiece(move.to(), pawn_piece, false); res.addPreAnimation(Animate::morph(piece, pawn)); // replace piece with pawn m_cinterface->setSprite(move.from(), pawn); piece = pawn; } } else if (move.kingSideCastling()) { Point rookSquare = move.to() + Point(1,0); Point rookDestination = move.from() + Point(1,0); NamedSprite rook = m_cinterface->takeSprite(rookDestination); m_cinterface->setSprite(rookSquare, rook); res.addPreAnimation(Animate::move(rook, rookSquare)); } else if (move.queenSideCastling()) { Point rookSquare = move.to() + Point(-2,0); Point rookDestination = move.from() + Point(-1,0); NamedSprite rook = m_cinterface->takeSprite(rookDestination); m_cinterface->setSprite(rookSquare, rook); res.addPreAnimation(Animate::move(rook, rookSquare)); } res.addPreAnimation(*movement(piece, move.to(), move.from())); res.group()->addPostAnimation(warp(final)); return res; } } #endif // HLVARIANT__ANIMATOR_H tagua-1.0-alpha2/src/hlvariant/board.h000066400000000000000000000113321077523320400176420ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__BOARD_H #define HLVARIANT__BOARD_H #include #include #include "point.h" #include "pathinfo.h" namespace HLVariant { template class Board { public: typedef _Piece Piece; private: Point m_size; std::vector m_data; public: /** * Create a new Board with the given size. */ Board(const Point& size); /** * Create a Board copying a given one. */ Board(const Board& other); /** * Compare two boards for equality. */ bool operator==(const Board& other) const; bool operator!=(const Board& other) const; /** * \return Board size. */ Point size() const; /** * Retrieve a piece from the board. * \param p Coordinates of the piece. * \return The piece at that square, or an invalid piece, if the square is out of the board. */ Piece get(const Point& p) const; /** * Add a piece to the board. * \param p Coordinates of the piece. * \param piece The piece to add. * \note This function does nothing if @a p is out of the board. */ void set(const Point& p, const Piece& piece); /** * \return Whether @a p is a valid board square. */ bool valid(const Point& p) const; /** * \return Information on the path joining @a from and @a to. */ PathInfo path(const Point& from, const Point& to) const; /** * Searches the board for a given piece. * \return The first square where the piece is found, or an * invalid point, if no such piece exists on the board. */ Point find(const Piece& piece) const; /** * Coordinates displayed at the board border. */ QStringList borderCoords() const; }; // IMPLEMENTATION template Board::Board(const Point& size) : m_size(size) { m_data.resize(m_size.x * m_size.y); } template Board::Board(const Board& other) : m_size(other.m_size) , m_data(other.m_data) { } template bool Board::operator==(const Board& other) const { if (m_size != other.m_size) return false; const unsigned int total = m_data.size(); for (unsigned int i = 0; i < total; i++) { if (m_data[i] != other.m_data[i]) return false; } return true; } template bool Board::operator!=(const Board& other) const { return !((*this) == other); } template Point Board::size() const { return m_size; } template Piece Board::get(const Point& p) const { if (valid(p)) { return m_data[p.x + p.y * m_size.x]; } else { return Piece(); } } template void Board::set(const Point& p, const Piece& piece) { if (valid(p)) { m_data[p.x + p.y * m_size.x] = piece; } } template bool Board::valid(const Point& p) const { return p.x < m_size.x && p.x >= 0 && p.y < m_size.y && p.y >= 0; } template PathInfo Board::path(const Point& from, const Point& to) const { if (!valid(from) || !valid(to)) return PathInfo(PathInfo::Undefined, 0); Point delta = to - from; PathInfo::Direction direction; if (delta.x == 0) direction = PathInfo::Vertical; else if (delta.y == 0) direction = PathInfo::Horizontal; else if (delta.x == delta.y) direction = PathInfo::Diagonal1; else if (delta.x == -delta.y) direction = PathInfo::Diagonal2; else direction = PathInfo::Undefined; int num_obs = 0; if (direction != PathInfo::Undefined) { Point step = delta.normalizeInfinity(); Point position = from; while ((position += step) != to) { if (get(position) == Piece()) continue; num_obs++; } } return PathInfo(direction, num_obs); } template Point Board::find(const Piece& piece) const { for (int i = 0; i < m_size.x; i++) { for (int j = 0; j < m_size.y; j++) { Point p(i, j); if (get(p) == piece) return p; } } return Point::invalid(); } template QStringList Board::borderCoords() const { QStringList retv; Point p = size(); for (int i = 0; i < p.x; i++) retv << Point(i, 0).col(); for (int i = 1; i <= p.y; i++) retv << QString::number(i); return retv + retv; } } #endif // HLVARIANT__BOARD_H tagua-1.0-alpha2/src/hlvariant/chess/000077500000000000000000000000001077523320400175075ustar00rootroot00000000000000tagua-1.0-alpha2/src/hlvariant/chess/actions.cpp000066400000000000000000000037631077523320400216640ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "actions.h" #include "../variantdata.h" #include "variant.h" #include #include #include QAction* createAction(QActionGroup* group, const KIcon& icon, const QString& text) { QAction* action = new KAction(icon, text, group); action->setCheckable(true); group->addAction(action); return action; } namespace HLVariant { namespace Chess { Actions::Actions() : m_promotion(VariantData::Piece::QUEEN) { QActionGroup* group = new QActionGroup(this); QAction* queen = createAction(group, KIcon("promoteQueen"), "Promote to queen"); queen->setChecked(true); add(queen); connect(queen, SIGNAL(triggered()), this, SLOT(promote_to_queen())); QAction* rook = createAction(group, KIcon("promoteRook"), "Promote to rook"); add(rook); connect(rook, SIGNAL(triggered()), this, SLOT(promote_to_rook())); QAction* bishop = createAction(group, KIcon("promoteBishop"), "Promote to bishop"); add(bishop); connect(bishop, SIGNAL(triggered()), this, SLOT(promote_to_bishop())); QAction* knight = createAction(group, KIcon("promoteKnight"), "Promote to knight"); add(knight); connect(knight, SIGNAL(triggered()), this, SLOT(promote_to_knight())); } int Actions::promotion() const { return m_promotion; } void Actions::promote_to_queen() { m_promotion = VariantData::Piece::QUEEN; } void Actions::promote_to_rook() { m_promotion = VariantData::Piece::ROOK; } void Actions::promote_to_bishop() { m_promotion = VariantData::Piece::BISHOP; } void Actions::promote_to_knight() { m_promotion = VariantData::Piece::KNIGHT; } } } tagua-1.0-alpha2/src/hlvariant/chess/actions.h000066400000000000000000000015761077523320400213310ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CHESS__ACTIONS_H #define HLVARIANT__CHESS__ACTIONS_H #include "actioncollection.h" namespace HLVariant { namespace Chess { class Actions : public ActionCollection { Q_OBJECT int m_promotion; public: Actions(); int promotion() const; private Q_SLOTS: virtual void promote_to_queen(); virtual void promote_to_rook(); virtual void promote_to_bishop(); virtual void promote_to_knight(); }; } // namespace Chess } // namespace HLVariant #endif // HLVARIANT__CHESS__ACTIONS_H tagua-1.0-alpha2/src/hlvariant/chess/gamestate.cpp000066400000000000000000000015241077523320400221670ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "gamestate.h" namespace HLVariant { namespace Chess { CastlingData::CastlingData() : wk(true) , wq(true) , bk(true) , bq(true) { } CastlingData::CastlingData(bool wk, bool wq, bool bk, bool bq) : wk(wk) , wq(wq) , bk(bk) , bq(bq) { } bool CastlingData::operator==(const CastlingData& other) const { return wk == other.wk && wq == other.wq && bk == other.bk && bq == other.bq; } } // namespace Chess } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/chess/gamestate.h000066400000000000000000000173151077523320400216410ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CHESS__GAMESTATE_H #define HLVARIANT__CHESS__GAMESTATE_H #include "../customboard.h" #include "piece.h" #include "move.h" #include "nopool.h" #include "export.h" namespace HLVariant { namespace Chess { struct TAGUA_EXPORT CastlingData { bool wk : 1; bool wq : 1; bool bk : 1; bool bq : 1; CastlingData(); CastlingData(bool, bool, bool, bool); bool operator==(const CastlingData& other) const; }; template class GameState { public: typedef _Board Board; typedef _Move Move; typedef typename Board::Piece Piece; typedef NoPool Pool; protected: Board m_board; CastlingData m_castling; Point m_en_passant; typename Piece::Color m_turn; public: GameState(); GameState(typename Piece::Color, bool, bool, bool, bool, const Point&); virtual ~GameState() { } virtual Board& board(); virtual const Board& board() const; virtual void setup(); virtual bool operator==(const GameState& other) const; virtual Point enPassant() const; virtual bool kingCastling(typename Piece::Color color) const; virtual bool queenCastling(typename Piece::Color color) const; virtual void move(const Move& m); virtual void basicMove(const Move& m); virtual void handleCastling(const Piece& piece, const Move& m); virtual void captureOn(const Point& p); virtual void setTurn(typename Piece::Color color); virtual typename Piece::Color previousTurn() const; virtual void switchTurn(); virtual typename Piece::Color turn() const; virtual int startingRank(typename Piece::Color color) const; virtual int promotionRank(typename Piece::Color color) const; virtual Point kingStartingPosition(typename Piece::Color color) const; virtual Point direction(typename Piece::Color color) const; }; // IMPLEMENTATION template GameState::GameState() : m_en_passant(Point::invalid()) , m_turn(Piece::WHITE) { } template GameState::GameState( typename Piece::Color turn, bool wkCastle, bool wqCastle, bool bkCastle, bool bqCastle, const Point& ep) : m_castling(wkCastle, wqCastle, bkCastle, bqCastle) , m_en_passant(ep) , m_turn(turn) { } template Board& GameState::board() { return m_board; } template const Board& GameState::board() const { return m_board; } template Point GameState::enPassant() const { return m_en_passant; } template bool GameState::kingCastling(typename Piece::Color color) const { if (color == Piece::WHITE) { return m_castling.wk; } else { return m_castling.bk; } } template bool GameState::queenCastling(typename Piece::Color color) const { if (color == Piece::WHITE) { return m_castling.wq; } else { return m_castling.bq; } } template void GameState::setup() { for (int c = 0; c < 2; c++) { typename Piece::Color color = static_cast(c); int rank = startingRank(color); for (int i = 0; i < m_board.size().x; i++) { m_board.set(Point(i, rank + direction(color).y), Piece(color, Piece::PAWN)); } m_board.set(Point(0, rank), Piece(color, Piece::ROOK)); m_board.set(Point(1, rank), Piece(color, Piece::KNIGHT)); m_board.set(Point(2, rank), Piece(color, Piece::BISHOP)); m_board.set(Point(3, rank), Piece(color, Piece::QUEEN)); m_board.set(Point(4, rank), Piece(color, Piece::KING)); m_board.set(Point(5, rank), Piece(color, Piece::BISHOP)); m_board.set(Point(6, rank), Piece(color, Piece::KNIGHT)); m_board.set(Point(7, rank), Piece(color, Piece::ROOK)); } } template bool GameState::operator==(const GameState& other) const { return m_board == other.m_board && m_castling == other.m_castling && m_en_passant == other.m_en_passant; } template void GameState::captureOn(const Point& p) { m_board.set(p, Piece()); } template void GameState::basicMove(const Move& m) { if (m.from() != m.to()) { m_board.set(m.to(), m_board.get(m.from())); m_board.set(m.from(), Piece()); } } template void GameState::handleCastling(const Piece& piece, const Move& m) { if (m.kingSideCastling()) { Point rookSquare = m.to() + Point(1,0); Point rookDestination = m.from() + Point(1,0); basicMove(Move(rookSquare, rookDestination)); } else if (m.queenSideCastling()) { Point rookSquare = m.to() - Point(2,0); Point rookDestination = m.from() - Point(1,0); basicMove(Move(rookSquare, rookDestination)); } typename Piece::Type type = piece.type(); typename Piece::Color color = piece.color(); if (type == Piece::KING) { if (color == Piece::WHITE) { m_castling.wk = false; m_castling.wq = false; } else { m_castling.bk = false; m_castling.bq = false; } } if (m.from() == Point(0,0) || m.to() == Point(0,0)) m_castling.bq = false; else if (m.from() == Point(7,0) || m.to() == Point(7,0)) m_castling.bk = false; else if (m.from() == Point(0,7) || m.to() == Point(0,7)) m_castling.wq = false; else if (m.from() == Point(7,7) || m.to() == Point(7,7)) m_castling.wk = false; } template void GameState::switchTurn() { m_turn = Piece::oppositeColor(m_turn); } template void GameState::move(const Move& m) { Piece piece = m_board.get(m.from()); if (piece == Piece()) return; captureOn(m.captureSquare()); basicMove(m); m_en_passant = m.enPassantTrigger(); typename Piece::Type promotion_type = static_cast(m.promoteTo()); if (promotion_type != Piece::INVALID_TYPE) { m_board.set(m.to(), Piece(piece.color(), promotion_type)); } handleCastling(piece, m); switchTurn(); } template typename Board::Piece::Color GameState::turn() const { return m_turn; } template typename Board::Piece::Color GameState::previousTurn() const { return Piece::oppositeColor(m_turn); } template void GameState::setTurn(typename Piece::Color color) { m_turn = color; } template int GameState::startingRank(typename Piece::Color color) const { return color == Piece::WHITE ? m_board.size().y - 1 : 0; } template int GameState::promotionRank(typename Piece::Color color) const { return startingRank(Piece::oppositeColor(color)); } template Point GameState::kingStartingPosition(typename Piece::Color color) const { return Point(4, startingRank(color)); } template Point GameState::direction(typename Piece::Color color) const { return Point(0, color == Piece::WHITE ? -1 : 1); } } // namespace Chess } // namespace HLVariant #endif // HLVARIANT__CHESS__GAMESTATE_H tagua-1.0-alpha2/src/hlvariant/chess/icsverbose.cpp000066400000000000000000000033371077523320400223650ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "icsverbose.h" namespace HLVariant { namespace Chess { // 1 2 3 5 QRegExp ICSVerbose::pattern("([PRNBKQ])/([a-zA-Z]\\d+|@@)-([a-zA-Z]\\d+)(=([PRNBKQ]))?"); QRegExp ICSVerbose::kingCastlingPattern("[oO0]-[oO0]"); QRegExp ICSVerbose::queenCastlingPattern("[oO0]-[oO0]-[oO0]"); QRegExp ICSVerbose::nonePattern("none"); ICSVerbose::ICSVerbose() : from(Point::invalid()) , to(Point::invalid()) , promotion(-1) , castling(SAN::NoCastling) { } void ICSVerbose::load(const QString& str, int ysize) { if (nonePattern.indexIn(str) == 0) { from = Point::invalid(); to = Point::invalid(); } else if (pattern.indexIn(str) == 0) { if (pattern.cap(2) == "@@") from = Point::invalid(); else from = Point(pattern.cap(2), ysize); to = Point(pattern.cap(3), ysize); type = SAN::getType(pattern.cap(1)); if (!pattern.cap(5).isEmpty()) promotion = SAN::getType(pattern.cap(6)); else promotion = -1; castling = SAN::NoCastling; } else if (queenCastlingPattern.indexIn(str) == 0) castling = SAN::QueenSide; else if (kingCastlingPattern.indexIn(str) == 0) castling = SAN::KingSide; else { from = Point::invalid(); to = Point::invalid(); castling = SAN::NoCastling; } } } // namespace HLVariant } // namespace Chess tagua-1.0-alpha2/src/hlvariant/chess/icsverbose.h000066400000000000000000000020521077523320400220230ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CHESS__ICSVERBOSE_H #define HLVARIANT__CHESS__ICSVERBOSE_H #include "san.h" namespace HLVariant { namespace Chess { class ICSVerbose { static QRegExp pattern; static QRegExp kingCastlingPattern; static QRegExp queenCastlingPattern; static QRegExp nonePattern; public: ICSVerbose(); void load(const QString&, int ysize); Point from, to; int type, promotion; SAN::CastlingType castling; inline bool invalid() const { return (from == Point::invalid() && to == Point::invalid()); } inline bool valid() const { return !invalid(); } }; } // namespace Chess } // namespace HLVariant #endif // HLVARIANT__CHESS__ICSVERBOSE_H tagua-1.0-alpha2/src/hlvariant/chess/legalitycheck.h000066400000000000000000000213721077523320400224750ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CHESS__LEGALITYCHECK_H #define HLVARIANT__CHESS__LEGALITYCHECK_H #include "gamestate.h" #include "interactiontype.h" #include "turnpolicy.h" namespace HLVariant { namespace Chess { template class LegalityCheck { public: typedef _GameState GameState; typedef typename GameState::Board Board; typedef typename GameState::Move Move; typedef typename GameState::Piece Piece; protected: const GameState& m_state; public: LegalityCheck(const GameState& state); virtual ~LegalityCheck(); virtual typename Move::Type getMoveType( const Piece& piece, const Move& move, const Piece& target = Piece()) const; virtual bool pseudolegal(Move& move) const; virtual bool legal(Move& move) const; virtual bool attacks( typename Piece::Color color, const Point& p, const Piece& target = Piece()) const; virtual bool checkPromotion(typename Piece::Type type) const; virtual typename Piece::Color mover(const Move& move) const; virtual InteractionType movable(const TurnTest&, const Point& x) const; virtual InteractionType droppable(const TurnTest&, int index) const; }; // IMPLEMENTATION template LegalityCheck::~LegalityCheck() { } template LegalityCheck::LegalityCheck(const GameState& state) : m_state(state) { } template bool LegalityCheck::legal(Move& move) const { if (pseudolegal(move)) { typename Piece::Color turn = mover(move); GameState tmp(m_state); tmp.move(move); Point kingPos = tmp.board().find(Piece(turn, Piece::KING)); if (kingPos == Point::invalid()) return false; LegalityCheck tmpLegality(tmp); if (tmpLegality.attacks(Piece::oppositeColor(turn), kingPos)) return false; return true; } else { return false; } } template bool LegalityCheck::pseudolegal(Move& move) const { if (!move.valid()) return false; if (!m_state.board().valid(move.from())) return false; if (!m_state.board().valid(move.to())) return false; Piece piece = m_state.board().get(move.from()); if (piece == Piece()) return false; typename Piece::Color thisTurn = piece.color(); typename Piece::Color otherTurn = Piece::oppositeColor(thisTurn); if (piece != Piece() && m_state.turn() == thisTurn) { typename Move::Type move_type = getMoveType(piece, move); move.setType(move_type); if (!move.valid()) return false; if (!checkPromotion(static_cast(move.promoteTo()))) return false; if (move.kingSideCastling()) { if (attacks(otherTurn, move.from()) || attacks(otherTurn, move.from() + Point(1, 0), piece)) return false; } if (move.queenSideCastling()) { if (attacks(otherTurn, move.from()) || attacks(otherTurn, move.from() + Point(-1, 0), piece)) return false; } return true; } else { return false; } } template typename GameState::Move::Type LegalityCheck:: getMoveType(const Piece& piece, const Move& move, const Piece& _target) const { Piece target = _target == Piece() ? m_state.board().get(move.to()) : _target; switch (piece.type()) { case Piece::ROOK: { if (move.from() == move.to()) return Move::INVALID; PathInfo path = m_state.board().path(move.from(), move.to()); if (path.parallel() && path.clear() && target.color() != piece.color()) return Move::NORMAL; else return Move::INVALID; } case Piece::BISHOP: { if (move.from() == move.to()) return Move::INVALID; PathInfo path = m_state.board().path(move.from(), move.to()); if (path.diagonal() && path.clear() && target.color() != piece.color()) return Move::NORMAL; else return Move::INVALID; } case Piece::KNIGHT: if (target.color() == piece.color()) return Move::INVALID; else { Point delta = move.from() - move.to(); if (abs(delta.x) == 1 && abs(delta.y) == 2) return Move::NORMAL; if (abs(delta.y) == 1 && abs(delta.x) == 2) return Move::NORMAL; return Move::INVALID; } case Piece::QUEEN: { if (move.from() == move.to()) return Move::INVALID; PathInfo path = m_state.board().path(move.from(), move.to()); if (path.valid() && path.clear() && target.color() != piece.color()) return Move::NORMAL; else return Move::INVALID; } case Piece::KING: { if (move.from() == move.to()) return Move::INVALID; Point delta = move.to() - move.from(); if (abs(delta.x) <= 1 && abs(delta.y) <= 1 && target.color() != piece.color()) { return Move::NORMAL; } else if (move.from() == m_state.kingStartingPosition(piece.color())) { if (delta == Point(2,0)) { if (m_state.board().get(move.from() + Point(1,0)) == Piece() && m_state.board().get(move.to()) == Piece() && m_state.kingCastling(piece.color())) return Move::KING_SIDE_CASTLING; } else if (delta == Point(-2,0)) { if (m_state.board().get(move.from() - Point(1, 0)) == Piece() && m_state.board().get(move.to() + Point(1, 0)) == Piece() && m_state.board().get(move.to()) == Piece() && m_state.queenCastling(piece.color())) return Move::QUEEN_SIDE_CASTLING; } } return Move::INVALID; } case Piece::PAWN: { Point delta = move.to() - move.from(); bool enPassant = m_state.enPassant() == move.to(); // moving if (target == Piece() && !enPassant) { if (delta == m_state.direction(piece.color())) { if (move.to().y == m_state.promotionRank(piece.color())) return Move::PROMOTION; else return Move::NORMAL; } if (move.from().y == m_state.startingRank(piece.color()) + m_state.direction(piece.color()).y && delta == m_state.direction(piece.color()) * 2 && m_state.board().get(move.from() + m_state.direction(piece.color())) == Piece()) return Move::EN_PASSANT_TRIGGER; else return Move::INVALID; } // capturing else if (enPassant || target.color() != piece.color()) { if (delta.y == m_state.direction(piece.color()).y && abs(delta.x) == 1) { if (enPassant) return Move::EN_PASSANT_CAPTURE; else if (move.to().y == m_state.promotionRank(piece.color())) return Move::PROMOTION; else return Move::NORMAL; } } return Move::INVALID; } default: return Move::INVALID; } } template bool LegalityCheck::attacks(typename Piece::Color color, const Point& to, const Piece& target) const { for (int i = 0; i < m_state.board().size().x; i++) { for (int j = 0; j < m_state.board().size().y; j++) { Point p(i, j); Piece piece = m_state.board().get(p); Move move(p, to); if (piece != Piece() && piece.color() == color && getMoveType(piece, move, target) != Move::INVALID) return true; } } return false; } template bool LegalityCheck::checkPromotion(typename Piece::Type type) const { return type == -1 || type == Piece::QUEEN || type == Piece::ROOK || type == Piece::BISHOP || type == Piece::KNIGHT; } template typename LegalityCheck::Piece::Color LegalityCheck::mover(const Move& move) const { return m_state.board().get(move.from()).color(); } template InteractionType LegalityCheck::movable(const TurnTest& test, const Point& p) const { Piece piece = m_state.board().get(p); if (piece == Piece() || !test(piece.color())) return NoAction; return piece.color() == m_state.turn() ? Moving : Premoving; } template InteractionType LegalityCheck::droppable(const TurnTest& test, int index) const { if (!test(index)) return NoAction; typename Piece::Color c = static_cast(index); return c == m_state.turn() ? Moving : Premoving; } } // namespace Chess } // namespace HLVariant #endif // HLVARIANT__CHESS__LEGALITYCHECK_H tagua-1.0-alpha2/src/hlvariant/chess/move.cpp000066400000000000000000000033661077523320400211710ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "move.h" namespace HLVariant { namespace Chess { Move::Move(const Point& from, const Point& to, int promotionType) : m_type(NORMAL) , m_from(from) , m_to(to) , m_promotion(promotionType) { } Move::Move() : m_type(INVALID) , m_from(Point::invalid()) , m_to(Point::invalid()) , m_promotion(-1) { } Move::~Move() { } Point Move::enPassantTrigger() const { if (m_type == EN_PASSANT_TRIGGER) { return (m_from + m_to) / 2; } else { return Point::invalid(); } } Point Move::captureSquare() const { if (m_type == EN_PASSANT_CAPTURE) { return Point(m_to.x, m_from.y); } else { return m_to; } } int Move::promoteTo() const { if (m_type == PROMOTION) { return m_promotion; } else { return -1; } } bool Move::kingSideCastling() const { return m_type == KING_SIDE_CASTLING; } bool Move::queenSideCastling() const { return m_type == QUEEN_SIDE_CASTLING; } Point Move::from() const { return m_from; } Point Move::to() const { return m_to; } bool Move::valid() const { return //m_from != Point::invalid() && m_to != Point::invalid() && m_type != INVALID; } void Move::setType(Type type) { m_type = type; } bool Move::operator==(const Move& move) const { return m_from == move.m_from && m_to == move.m_to && m_promotion == move.m_promotion; } } // namespace Chess } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/chess/move.h000066400000000000000000000025531077523320400206330ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CHESS__MOVE_H #define HLVARIANT__CHESS__MOVE_H #include "point.h" #include "export.h" namespace HLVariant { namespace Chess { class TAGUA_EXPORT Move { public: enum Type { INVALID = -1, NORMAL, EN_PASSANT_CAPTURE, EN_PASSANT_TRIGGER, KING_SIDE_CASTLING, QUEEN_SIDE_CASTLING, PROMOTION }; private: Type m_type; Point m_from; Point m_to; int m_promotion; public: Move(); Move(const Point& from, const Point& to, int promotionType = -1); virtual ~Move(); virtual Point enPassantTrigger() const; virtual Point captureSquare() const; virtual int promoteTo() const; virtual bool kingSideCastling() const; virtual bool queenSideCastling() const; virtual Point from() const; virtual Point to() const; virtual bool valid() const; virtual void setType(Type type); virtual bool operator==(const Move& move) const; }; } // namespace Chess } // namespace HLVariant #endif // HLVARIANT__CHESS__MOVE_H tagua-1.0-alpha2/src/hlvariant/chess/movegenerator.h000066400000000000000000000145541077523320400225460ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CHESS__MOVEGENERATOR_H #define HLVARIANT__CHESS__MOVEGENERATOR_H #include "legalitycheck.h" namespace HLVariant { namespace Chess { template class MoveGenerator { public: typedef _LegalityCheck LegalityCheck; typedef typename LegalityCheck::GameState GameState; typedef typename GameState::Move Move; typedef typename GameState::Board::Piece Piece; class MoveCallback { public: virtual ~MoveCallback() { } virtual bool operator()(const Move&) = 0; }; protected: const GameState& m_state; class FindMove : public MoveCallback { bool m_found; public: FindMove() : m_found(false) { } virtual bool operator()(const Move&) { m_found = true; return false; } bool found() const { return m_found; } }; virtual bool addMove(const Move& m, MoveCallback&) const; virtual bool addAllPromotions(const Move& m, MoveCallback&) const; virtual bool generateSlide(const Point& p, const Point& dir, MoveCallback&) const; public: MoveGenerator(const GameState& state); virtual ~MoveGenerator(); virtual bool check(typename Piece::Color) const; virtual bool stalled() const; virtual void generate(MoveCallback&) const; virtual bool generateFrom(const Point& p, MoveCallback&) const; }; // IMPLEMENTATION template MoveGenerator::MoveGenerator(const GameState& state) : m_state(state) { } template MoveGenerator::~MoveGenerator() { } template bool MoveGenerator::check(typename Piece::Color turn) const { Point kingPosition = m_state.board().find(Piece(turn, Piece::KING)); if (!kingPosition.valid()) { // a missing king is considered in check return true; } else { LegalityCheck check(m_state); return check.attacks(Piece::oppositeColor(turn), kingPosition); } } template bool MoveGenerator::stalled() const { FindMove findMove; generate(findMove); return !findMove.found(); } template void MoveGenerator::generate(MoveCallback& callback) const { for (int i = 0; i < m_state.board().size().x; i++) { for (int j = 0; j < m_state.board().size().y; j++) { generateFrom(Point(i, j), callback); } } } template bool MoveGenerator::generateFrom(const Point& p, MoveCallback& callback) const { Piece piece = m_state.board().get(p); if (piece.color() == m_state.turn()) { switch (piece.type()) { case Piece::PAWN: { Point dir = m_state.direction(piece.color()); if ((p + dir).y == m_state.promotionRank(piece.color())) { return addAllPromotions(Move(p, p + dir), callback) && addAllPromotions(Move(p, p + dir + Point(1, 0)), callback) && addAllPromotions(Move(p, p + dir + Point(-1, 0)), callback); } else { return addMove(Move(p, p + dir), callback) && addMove(Move(p, p + dir * 2), callback) && addMove(Move(p, p + dir + Point(1, 0)), callback) && addMove(Move(p, p + dir - Point(1, 0)), callback); } } case Piece::KNIGHT: return addMove(Move(p, p + Point(1, 2)), callback) && addMove(Move(p, p + Point(1, -2)), callback) && addMove(Move(p, p + Point(-1, 2)), callback) && addMove(Move(p, p + Point(-1, -2)), callback) && addMove(Move(p, p + Point(2, 1)), callback) && addMove(Move(p, p + Point(2, -1)), callback) && addMove(Move(p, p + Point(-2, 1)), callback) && addMove(Move(p, p + Point(-2, -1)), callback); case Piece::BISHOP: return generateSlide(p, Point(1, 1), callback) && generateSlide(p, Point(1, -1), callback) && generateSlide(p, Point(-1, -1), callback) && generateSlide(p, Point(-1, 1), callback); case Piece::ROOK: return generateSlide(p, Point(1, 0), callback) && generateSlide(p, Point(0, 1), callback) && generateSlide(p, Point(-1, 0), callback) && generateSlide(p, Point(0, -1), callback); case Piece::QUEEN: return generateSlide(p, Point(1, 0), callback) && generateSlide(p, Point(0, 1), callback) && generateSlide(p, Point(-1, 0), callback) && generateSlide(p, Point(0, -1), callback) && generateSlide(p, Point(1, 1), callback) && generateSlide(p, Point(1, -1), callback) && generateSlide(p, Point(-1, -1), callback) && generateSlide(p, Point(-1, 1), callback); case Piece::KING: return addMove(Move(p, p + Point(1,0)), callback) && addMove(Move(p, p + Point(1,1)), callback) && addMove(Move(p, p + Point(0,1)), callback) && addMove(Move(p, p + Point(-1,1)), callback) && addMove(Move(p, p + Point(-1,0)), callback) && addMove(Move(p, p + Point(-1,-1)), callback) && addMove(Move(p, p + Point(0,-1)), callback) && addMove(Move(p, p + Point(1,-1)), callback); default: return true; } } return true; } template bool MoveGenerator:: generateSlide(const Point& p, const Point& dir, MoveCallback& callback) const { Point q = p + dir; while (m_state.board().valid(q)) { if (!addMove(Move(p, q), callback)) return false; q += dir; } return true; } template bool MoveGenerator::addMove(const Move& m, MoveCallback& callback) const { LegalityCheck check(m_state); Move move(m); if (check.legal(move)) { return callback(move); } return true; } template bool MoveGenerator::addAllPromotions(const Move& m, MoveCallback& callback) const { return addMove(Move(m.from(), m.to(), Piece::QUEEN), callback) && addMove(Move(m.from(), m.to(), Piece::ROOK), callback) && addMove(Move(m.from(), m.to(), Piece::KNIGHT), callback) && addMove(Move(m.from(), m.to(), Piece::BISHOP), callback); } } // namespace Chess } // namespace HLVariant #endif // HLVARIANT__CHESS__MOVEGENERATOR_H tagua-1.0-alpha2/src/hlvariant/chess/piece.cpp000066400000000000000000000043111077523320400212770ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "piece.h" #include "san.h" namespace HLVariant { namespace Chess { Piece::~Piece() { } Piece::Piece(Color color, Type type) : m_color(color) , m_type(type) { } Piece::Color Piece::color() const { return m_color; } Piece::Type Piece::type() const { return m_type; } QString Piece::colorName() const { return colorName(m_color); } QString Piece::colorName(Color color) { switch (color) { case WHITE: return "white"; case BLACK: return "black"; default: return "unknown"; } } QString Piece::typeName() const { return typeName(m_type); } QString Piece::typeName(Type type) { switch (type) { case ROOK: return "rook"; case BISHOP: return "bishop"; case KNIGHT: return "knight"; case QUEEN: return "queen"; case KING: return "king"; case PAWN: return "pawn"; default: return "unknown"; } } QString Piece::name() const { return colorName() + '_' + typeName(); } Piece::Color Piece::oppositeColor(Color color) { switch (color) { case WHITE: return BLACK; case BLACK: return WHITE; default: return INVALID_COLOR; } } bool Piece::operator==(const Piece& other) const { return m_color == other.m_color && m_type == other.m_type; } bool Piece::operator!=(const Piece& other) const { return !((*this) == other); } Piece Piece::fromDescription(const QString& description) { if (description.size() == 1) { QChar c = description[0]; Color color; if (c.category() == QChar::Letter_Uppercase) { color = WHITE; } else if (c.category() == QChar::Letter_Lowercase) { color = BLACK; } else { return Piece(); } Type type = static_cast(SAN::getType(c)); if (type != INVALID_TYPE) { return Piece(color, type); } } return Piece(); } } // namespace HLVariant } // namespace Chess tagua-1.0-alpha2/src/hlvariant/chess/piece.h000066400000000000000000000026201077523320400207450ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CHESS__PIECE_H #define HLVARIANT__CHESS__PIECE_H #include #include "export.h" namespace HLVariant { namespace Chess { class TAGUA_EXPORT Piece { public: enum Color { INVALID_COLOR = -1, WHITE, BLACK }; enum Type { INVALID_TYPE = -1, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING }; private: Color m_color; Type m_type; public: Piece(Color color = INVALID_COLOR, Type type = INVALID_TYPE); virtual ~Piece(); virtual Color color() const; virtual Type type() const; virtual QString colorName() const; static QString colorName(Color color); virtual QString typeName() const; static QString typeName(Type type); virtual QString name() const; static Color oppositeColor(Color color); static Piece fromDescription(const QString& description); virtual bool operator==(const Piece& other) const; virtual bool operator!=(const Piece& other) const; }; } // namespace Chess } // namespace HLVariant #endif // HLVARIANT__CHESS__PIECE_H tagua-1.0-alpha2/src/hlvariant/chess/san.cpp000066400000000000000000000055031077523320400207770ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "san.h" #include "piece.h" namespace HLVariant { namespace Chess { // 1 2 3 QRegExp SAN::pattern("^([PRNBKQ])?([a-wyzA-Z]?\\d*|x\\d+)([-x@])?" // 4 5 6 "([a-zA-Z]\\d+)(=?([RNBKQrnbkq]))?[+#]?[\?!]*"); QRegExp SAN::kingCastlingPattern("^[oO0]-?[oO0][+#]?"); QRegExp SAN::queenCastlingPattern("^[oO0]-?[oO0]-?[oO0][+#]?"); QRegExp SAN::nonePattern("^none"); SAN::SAN() : from(Point::invalid()) , to(Point::invalid()) , type(-1) , promotion(-1) , castling(NoCastling) , drop(false) { } int SAN::getType(const QString& letter) { if (letter.isEmpty()) return Piece::PAWN; switch(letter[0].toLower().toAscii()) { case 'k': return Piece::KING; case 'q': return Piece::QUEEN; case 'r': return Piece::ROOK; case 'n': return Piece::KNIGHT; case 'b': return Piece::BISHOP; case 'p': return Piece::PAWN; default: return Piece::INVALID_TYPE; } } void SAN::load(const QString& str, int& offset, int ysize) { if (nonePattern.indexIn(str, offset, QRegExp::CaretAtOffset) != -1) { from = Point::invalid(); to = Point::invalid(); offset += nonePattern.matchedLength(); } else if (pattern.indexIn(str, offset, QRegExp::CaretAtOffset) != -1) { type = getType(pattern.cap(1)); drop = pattern.cap(3) == "@"; if (drop) from = Point::invalid(); else from = Point(pattern.cap(2), ysize); to = Point(pattern.cap(4), ysize); promotion = pattern.cap(6).isEmpty() ? -1 : getType(pattern.cap(6)); castling = NoCastling; offset += pattern.matchedLength(); } else if (queenCastlingPattern.indexIn(str, offset, QRegExp::CaretAtOffset) != -1) { castling = QueenSide; offset += queenCastlingPattern.matchedLength(); } else if (kingCastlingPattern.indexIn(str, offset, QRegExp::CaretAtOffset) != -1) { castling = KingSide; offset += kingCastlingPattern.matchedLength(); } else { //kDebug() << "error!!!! " << str.mid(offset); to = Point::invalid(); } } void SAN::load(const QString& str, int ysize) { int offset = 0; load(str, offset, ysize); } QDebug operator<<(QDebug os, const SAN& move) { if (move.castling == SAN::KingSide) os << "O-O"; else if (move.castling == SAN::QueenSide) os << "O-O-O"; else os << move.type << ": " << move.from << " -> " << move.to; return os; } } // namespace Chess } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/chess/san.h000066400000000000000000000025201077523320400204400ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CHESS__SAN_H #define HLVARIANT__CHESS__SAN_H #include #include #include #include "export.h" #include "point.h" namespace HLVariant { namespace Chess { class TAGUA_EXPORT SAN { friend QDebug operator<<(QDebug os, const SAN& move); static QRegExp pattern; static QRegExp kingCastlingPattern; static QRegExp queenCastlingPattern; static QRegExp nonePattern; public: enum CastlingType { NoCastling, KingSide, QueenSide }; SAN(); static int getType(const QString& letter); void load(const QString&, int& offset, int ysize); void load(const QString&, int ysize); Point from, to; int type; int promotion; CastlingType castling; bool drop; inline bool invalid() const { return (to == Point::invalid()) && (castling == NoCastling); } inline bool valid() const { return !invalid(); } }; } // namespace Chess } // namespace HLVariant #endif // HLVARIANT__CHESS__SAN_H tagua-1.0-alpha2/src/hlvariant/chess/serializer.h000066400000000000000000000202331077523320400220310ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CHESS__SERIALIZER_H #define HLVARIANT__CHESS__SERIALIZER_H #include #include "legalitycheck.h" #include "san.h" #include "icsverbose.h" namespace HLVariant { namespace Chess { template class Serializer { protected: typedef typename MoveGenerator::LegalityCheck LegalityCheck; typedef typename LegalityCheck::GameState GameState; typedef typename GameState::Move Move; typedef typename GameState::Board::Piece Piece; QString m_rep; protected: virtual QString suffix(const Move& move, const GameState& ref); virtual QString san(const Move& move, const GameState& ref); virtual void minimal_notation(SAN& san, const GameState& ref); virtual Move get_san(const SAN& san, const GameState& ref); virtual QChar symbol(typename Piece::Type type) const; virtual Move parse_ics_verbose(const QString& str, const GameState& ref); public: /** * Create a serializer to a given string representation for moves. * \param rep A move representation type. */ Serializer(const QString& rep); virtual ~Serializer(); /** * Serialize a move given a reference game state. * We assume the move has already been tested against @a ref. * Calling this function on an untested or illegal move is safe but its return * value is undefined. * Do not try to call this function on an invalid move. * \param ref The position in which this move shall be executed. * \return A string representation for this move. */ virtual QString serialize(const Move& move, const GameState& ref); /** * Convert a string representation of a move back to a move object. * \param ref The position in which this move shall be executed. * \return A move corresponding to the given string representation. */ virtual Move deserialize(const QString& str, const GameState& ref); }; // IMPLEMENTATION template Serializer::Serializer(const QString& rep) : m_rep(rep) { } template Serializer::~Serializer() { } template QString Serializer::san(const Move& move, const GameState& ref) { if (!move.valid()) return ""; QString res; Piece piece = ref.board().get(move.from()); Piece captured = ref.board().get(move.captureSquare()); if (piece == Piece()) return ""; // no piece in the initial square if (move.kingSideCastling()) { res = "O-O"; } else if (move.queenSideCastling()) { res = "O-O-O"; } else if (piece.type() == Piece::PAWN) { if (captured != Piece()) res = move.from().col() + "x"; res += move.to().toString(ref.board().size().y); } else { if (piece.type() != Piece::PAWN) res = symbol(piece.type()).toUpper(); SAN tmp; tmp.from = move.from(); tmp.to = move.to(); tmp.type = piece.type(); tmp.castling = SAN::NoCastling; minimal_notation(tmp, ref); res += tmp.from.toString(ref.board().size().y); if (captured != Piece()) res += "x"; res += tmp.to.toString(ref.board().size().y); } if (move.promoteTo() != -1) res += "=" + QString(symbol(static_cast(move.promoteTo())).toUpper()); res += suffix(move, ref); return res; } template QString Serializer::serialize(const Move& move, const GameState& ref) { if (m_rep == "simple") { int ysize = ref.board().size().y; QString res = move.from().toString(ysize) + move.to().toString(ysize); if (move.promoteTo() != -1) res = res + "=" + symbol( static_cast(move.promoteTo()) ).toUpper(); return res; } else if (m_rep == "compact") { return san(move, ref); } else if (m_rep == "decorated") { QString res = san(move, ref); res.replace('K', "{king}"); res.replace('Q', "{queen}"); res.replace('R', "{rook}"); res.replace('N', "{knight}"); res.replace('B', "{bishop}"); res.replace('P', "{pawn}"); return res; } else { return ""; } } template QString Serializer::suffix(const Move& move, const GameState& ref) { GameState tmp(ref); tmp.move(move); MoveGenerator generator(tmp); if (generator.check(Piece::oppositeColor(ref.turn()))) { if (generator.stalled()) return "#"; else return "+"; } else { return ""; } } template typename Serializer::Move Serializer::get_san(const SAN& san, const GameState& ref) { Move candidate; if (san.invalid()) return candidate; if (san.castling != SAN::NoCastling) { Point from = ref.kingStartingPosition(ref.turn()); Point to = from + (san.castling == SAN::KingSide? Point(2,0) : Point(-2,0)); Piece king = ref.board().get(from); if (king.type() != Piece::KING) return candidate; else { candidate = Move(from, to); LegalityCheck check(ref); if (check.legal(candidate)) return candidate; else return Move(); } } if (san.from.valid()) { candidate = Move(san.from, san.to, static_cast(san.promotion)); } else { for (int i = 0; i < ref.board().size().x; i++) { for (int j = 0; j < ref.board().size().y; j++) { Point p(i, j); Piece piece = ref.board().get(p); Move mv(p, san.to, static_cast(san.promotion)); if (p.resembles(san.from) && piece.type() == san.type && piece.color() == ref.turn()) { LegalityCheck check(ref); if (check.legal(mv)) { if (candidate.valid()) { // ambiguous! return Move(); } else { // ok, we have found a candidate move candidate = mv; } } } } } } return candidate; } template typename Serializer::Move Serializer::deserialize(const QString& str, const GameState& ref) { if (m_rep == "compact") { SAN tmp; tmp.load(str, ref.board().size().y); return get_san(tmp, ref); } else if (m_rep == "ics-verbose") { return parse_ics_verbose(str, ref); } else { // no need to parse simple or decorated moves return Move(); } } #define TRY(x) if(get_san(x, ref).valid()) return; template void Serializer::minimal_notation(SAN& san, const GameState& ref) { Point from = san.from; san.castling = SAN::NoCastling; // try notation without starting point san.from = Point::invalid(); TRY(san); // add column indication san.from = Point(from.x, -1); TRY(san); // add row indication san.from = Point(-1, from.y); TRY(san); // add complete starting point san.from = from; } #undef TRY template QChar Serializer::symbol(typename Piece::Type type) const { if (type == Piece::KNIGHT) return 'n'; else return Piece::typeName(type)[0]; } template typename Serializer::Move Serializer::parse_ics_verbose(const QString& str, const GameState& ref) { // here ref is the position _after_ this move ICSVerbose verbose; verbose.load(str, ref.board().size().y); Point from; Point to; if (verbose.castling == SAN::NoCastling) { from = verbose.from; to = verbose.to; } else { from = ref.kingStartingPosition(ref.previousTurn()); to = from + (verbose.castling == SAN::KingSide ? Point(2,0) : Point(-2, 0)); } return Move(from, to, static_cast(verbose.promotion)); } } // namespace Chess } // namespace HLVariant #endif // HLVARIANT__CHESS__SERIALIZER_H tagua-1.0-alpha2/src/hlvariant/chess/variant.cpp000066400000000000000000000016361077523320400216650ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "variant.h" #include #include #include #include #include "../tagua_wrapped.h" #include "actioncollection.h" namespace HLVariant { namespace Chess { const char* Variant::m_name = "Chess"; const char* Variant::m_theme_proxy = "Chess"; void Variant::setupMove(NormalUserMove& move) const { move.promotionType = m_actions.promotion(); } ActionCollection* Variant::actions() { return &m_actions; } DEFINE_VARIANT_FACTORY(); } // namespace Chess } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/chess/variant.h000066400000000000000000000027431077523320400213320ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CHESS__VARIANT_H #define HLVARIANT__CHESS__VARIANT_H #include "movegenerator.h" #include "serializer.h" #include "export.h" #include "option.h" #include "../animator.h" #include "../movefactory.h" #include "actions.h" class ActionCollection; namespace HLVariant { namespace Chess { struct TAGUA_EXPORT Variant { typedef GameState, Move> GameState; typedef LegalityCheck LegalityCheck; typedef MoveGenerator MoveGenerator; typedef Serializer Serializer; typedef SimpleAnimator Animator; typedef MoveFactory MoveFactory; static const bool hasICS = true; static const bool m_simple_moves = false; static const bool m_hidden = false; static const char *m_name; static const char *m_theme_proxy; static int moveListLayout() { return 0; } OptList positionOptions() const { return OptList(); } void setupMove(NormalUserMove& m) const; ActionCollection* actions(); private: Actions m_actions; }; } // namespace Chess } // namespace HLVariant #endif // HLVARIANT__CHESS__VARIANT_H tagua-1.0-alpha2/src/hlvariant/crazyhouse/000077500000000000000000000000001077523320400205765ustar00rootroot00000000000000tagua-1.0-alpha2/src/hlvariant/crazyhouse/gamestate.h000066400000000000000000000055541077523320400227320ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CRAZYHOUSE__GAMESTATE_H #define HLVARIANT__CRAZYHOUSE__GAMESTATE_H #include "../chess/gamestate.h" #include "../pool.h" #include "../poolcollection.h" namespace HLVariant { namespace Crazyhouse { template class GameState : public HLVariant::Chess::GameState<_Board, _Move> { typedef HLVariant::Chess::GameState<_Board, _Move> Base; public: typedef typename Base::Board Board; typedef typename Base::Move Move; typedef typename Base::Piece Piece; typedef Pool Pool; typedef PoolCollection Pools; private: using Base::m_board; Pools m_pools; public: GameState(); GameState(typename Piece::Color, bool, bool, bool, bool, const Point&); virtual const Pools& pools() const; virtual Pools& pools(); virtual void captureOn(const Point& p); virtual void move(const Move& m); }; // IMPLEMENTATION template GameState::GameState() { } template GameState::GameState( typename Piece::Color turn, bool wk, bool wq, bool bk, bool bq, const Point& ep) : Base(turn, wk, wq, bk, bq, ep) { } template const typename GameState::Pools& GameState::pools() const { return m_pools; } template typename GameState::Pools& GameState::pools() { return m_pools; } template void GameState::move(const Move& m) { if (m.drop() == Piece()) { Base::move(m); if (m.promoteTo() != -1) { Piece promoted = m_board.get(m.to()); promoted.setPromoted(); m_board.set(m.to(), promoted); } } else { Piece captured = m_board.get(m.to()); m_board.set(m.to(), m.drop()); m_pools.pool(m.drop().color()).remove(m.drop().type()); // handle capturing by drop: some variants // could use it if (captured != Piece()) m_pools.pool(Piece::oppositeColor(captured.color())).add(captured.type()); this->switchTurn(); } } template void GameState::captureOn(const Point& p) { Piece captured = m_board.get(p); if (captured != Piece()) { m_pools.pool(Piece::oppositeColor(captured.color())) .add(captured.actualType()); } Base::captureOn(p); } } // namespace Crazyhouse } // namespace HLVariant #endif // HLVARIANT__CRAZYHOUSE__GAMESTATE_H tagua-1.0-alpha2/src/hlvariant/crazyhouse/legalitycheck.h000066400000000000000000000046261077523320400235670ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CRAZYHOUSE__LEGALITYCHECK_H #define HLVARIANT__CRAZYHOUSE__LEGALITYCHECK_H #include "../chess/legalitycheck.h" namespace HLVariant { namespace Crazyhouse { template class LegalityCheck : public Chess::LegalityCheck<_GameState> { public: typedef _GameState GameState; private: typedef Chess::LegalityCheck Base; typedef typename Base::Board Board; typedef typename Base::Move Move; typedef typename Base::Piece Piece; protected: using Base::m_state; public: LegalityCheck(const GameState& state); virtual bool pseudolegal(Move& move) const; virtual typename Piece::Color mover(const Move& move) const; }; // IMPLEMENTATION template LegalityCheck::LegalityCheck(const GameState& state) : Base(state) { } template bool LegalityCheck::pseudolegal(Move& move) const { // add drop information to move, if missing if (move.drop() == Piece() && move.pool() != Piece::INVALID_COLOR && move.index() != -1) { move.setDrop(m_state.pools().pool(move.pool()).get(move.index())); } Piece dropped = move.drop(); if (dropped == Piece()) { return Base::pseudolegal(move); } else { // dropping on a valid square if (!m_state.board().valid(move.to())) return false; // cannot drop on occupied squares if (m_state.board().get(move.to()) != Piece()) return false; // cannot drop pawns in first or eighth rank if (dropped.type() == Piece::PAWN && (move.to().y == m_state.startingRank(Piece::WHITE) || move.to().y == m_state.promotionRank(Piece::WHITE))) return false; return true; } } template typename LegalityCheck::Piece::Color LegalityCheck::mover(const Move& move) const { if (move.drop() != Piece()) return move.drop().color(); else return Base::mover(move); } } // namespace Crazyhouse } // namespace HLVariant #endif // HLVARIANT__CRAZYHOUSE__LEGALITYCHECK_H tagua-1.0-alpha2/src/hlvariant/crazyhouse/move.h000066400000000000000000000045021077523320400217160ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CRAZYHOUSE__MOVE_H #define HLVARIANT__CRAZYHOUSE__MOVE_H #include "point.h" namespace HLVariant { namespace Crazyhouse { template class MoveMixin : public _Move { public: typedef _Move Move; typedef _Piece Piece; private: typedef typename Piece::Color Color; Color m_pool; int m_index; Piece m_drop; public: MoveMixin(); MoveMixin(const Point& from, const Point& to, int promotionType = -1); MoveMixin(Color pool, int index, const Point& to); MoveMixin(const Piece& dropped, const Point& to); Piece drop() const; void setDrop(const Piece& piece); Color pool() const; int index() const; }; // IMPLEMENTATION template MoveMixin::MoveMixin() : m_pool(Piece::INVALID_COLOR) , m_index(-1) { } template MoveMixin::MoveMixin(const Point& from, const Point& to, int promotionType) : Move(from, to, promotionType) , m_pool(Piece::INVALID_COLOR) , m_index(-1) { } template MoveMixin::MoveMixin(Color pool, int index, const Point& to) : Move(Point::invalid(), to) , m_pool(pool) , m_index(index) { } template MoveMixin::MoveMixin(const Piece& dropped, const Point& to) : Move(Point::invalid(), to) , m_pool(dropped.color()) , m_index(-1) , m_drop(dropped) { } template Piece MoveMixin::drop() const { return m_drop; } template void MoveMixin::setDrop(const Piece& drop) { m_drop = drop; } template typename Piece::Color MoveMixin::pool() const { return m_pool; } template int MoveMixin::index() const { return m_index; } }; // namespace Crazyhouse }; // namespace HLVariant #endif // HLVARIANT__CRAZYHOUSE__MOVE_H tagua-1.0-alpha2/src/hlvariant/crazyhouse/movefactory.h000066400000000000000000000020761077523320400233120ustar00rootroot00000000000000/* Copyright (c) 2006-2007 Paolo Capriotti (c) 2006-2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CRAZYHOUSE__MOVEFACTORY_H #define HLVARIANT__CRAZYHOUSE__MOVEFACTORY_H #include "../movefactory.h" namespace HLVariant { namespace Crazyhouse { template class MoveFactory : public HLVariant::MoveFactory { public: typedef typename HLVariant::MoveFactory Base; typedef typename Base::Move Move; typedef typename Base::Piece Piece; virtual Move createDropMove(const DropUserMove& drop) { return Move(static_cast(drop.pool), drop.piece_index, drop.to); } }; } // namespace Crazyhouse } // namespace HLVariant #endif // HLVARIANT__CRAZYHOUSE__MOVEFACTORY_H tagua-1.0-alpha2/src/hlvariant/crazyhouse/movegenerator.h000066400000000000000000000033771077523320400236360ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CRAZYHOUSE__MOVEGENERATOR_H #define HLVARIANT__CRAZYHOUSE__MOVEGENERATOR_H #include "../chess/movegenerator.h" namespace HLVariant { namespace Crazyhouse { template class MoveGenerator : public Chess::MoveGenerator<_LegalityCheck> { typedef Chess::MoveGenerator<_LegalityCheck> Base; using Base::m_state; public: typedef typename Base::LegalityCheck LegalityCheck; typedef typename Base::GameState GameState; typedef typename Base::Move Move; typedef typename Base::Piece Piece; typedef typename Base::MoveCallback MoveCallback; MoveGenerator(const GameState& m_state); virtual void generate(MoveCallback& callback) const; }; // IMPLEMENTATION template MoveGenerator::MoveGenerator(const GameState& state) : Base(state) { } template void MoveGenerator::generate(MoveCallback& callback) const { Base::generate(callback); // generate drops const int n = m_state.pools().pool(m_state.turn()).size(); for (int i = 0; i < m_state.board().size().x; i++) { for (int j = 0; j < m_state.board().size().y; j++) { Point p(i, j); for (int k = 0; k < n; k++) { addMove(Move(m_state.turn(), k, p), callback); } } } } } // namespace Crazyhouse } // namespace HLVariant #endif // HLVARIANT__CRAZYHOUSE__MOVEGENERATOR_H tagua-1.0-alpha2/src/hlvariant/crazyhouse/piece.cpp000066400000000000000000000020241077523320400223650ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "piece.h" namespace HLVariant { namespace Crazyhouse { Piece::Piece(Color color, Type type) : Chess::Piece(color, type) , m_promoted(false) { } bool Piece::operator==(const Piece& other) const { return Chess::Piece::operator==(other) && m_promoted == other.m_promoted; } void Piece::setPromoted() { m_promoted = true; } Piece::Type Piece::actualType() const { if (m_promoted) return PAWN; else return type(); } Piece Piece::fromDescription(const QString& description) { Chess::Piece res = Chess::Piece::fromDescription(description); return Piece(res.color(), res.type()); } } // namespace Crazyhouse } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/crazyhouse/piece.h000066400000000000000000000016611077523320400220400ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CRAZYHOUSE__PIECE_H #define HLVARIANT__CRAZYHOUSE__PIECE_H #include "../chess/piece.h" namespace HLVariant { namespace Crazyhouse { class Piece : public Chess::Piece { bool m_promoted; public: Piece(Color color = INVALID_COLOR, Type type = INVALID_TYPE); virtual bool operator==(const Piece& other) const; virtual void setPromoted(); virtual Type actualType() const; static Piece fromDescription(const QString& description); }; } // namespace Crazyhouse } // namespace HLVariant #endif // HLVARIANT__CRAZYHOUSE__PIECE_H tagua-1.0-alpha2/src/hlvariant/crazyhouse/serializer.h000066400000000000000000000031421077523320400231200ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CRAZYHOUSE__SERIALIZER_H #define HLVARIANT__CRAZYHOUSE__SERIALIZER_H #include "../chess/serializer.h" namespace HLVariant { namespace Crazyhouse { template class Serializer : public Chess::Serializer { typedef Chess::Serializer Base; typedef typename Base::GameState GameState; typedef typename Base::Piece Piece; typedef typename Base::Move Move; protected: using Base::m_rep; public: Serializer(const QString& rep); virtual QString serialize(const Move& move, const GameState& ref); }; // IMPLEMENTATION template Serializer::Serializer(const QString& rep) : Base(rep) { } template QString Serializer::serialize(const Move& move, const GameState& ref) { if (move.drop() == Piece()) { return Base::serialize(move, ref); } QString res; if (m_rep == "decorated") { res = "{" + move.drop().typeName() + '}'; } else { res = symbol(move.drop().type()).toUpper(); } return res + '@' + move.to().toString(ref.board().size().y) + suffix(move, ref); } } // namespace Crazyhouse } // namespace HLVariant #endif // HLVARIANT__CRAZYHOUSE__SERIALIZER_H tagua-1.0-alpha2/src/hlvariant/crazyhouse/variant.cpp000066400000000000000000000014461077523320400227530ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "variant.h" #include "../tagua_wrapped.h" namespace HLVariant { namespace Crazyhouse { const char* Variant::m_name = "Crazyhouse"; const char* Variant::m_theme_proxy = "Chess"; void Variant::setupMove(NormalUserMove& m) const { m.promotionType = m_actions.promotion(); } ActionCollection* Variant::actions() { return &m_actions; } DEFINE_VARIANT_FACTORY(); } // namespace Chess } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/crazyhouse/variant.h000066400000000000000000000033731077523320400224210ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CRAZYHOUSE__VARIANT_H #define HLVARIANT__CRAZYHOUSE__VARIANT_H #include "movegenerator.h" #include "serializer.h" #include "piece.h" #include "gamestate.h" #include "move.h" #include "../chess/move.h" #include "../chess/variant.h" #include "export.h" #include "option.h" #include "legalitycheck.h" #include "../animator.h" #include "../dropanimator.h" #include "movefactory.h" #include "../chess/actions.h" namespace HLVariant { namespace Crazyhouse { struct TAGUA_EXPORT Variant { typedef MoveMixin Move; typedef CustomBoard<8, 8, Piece> Board; typedef GameState GameState; typedef LegalityCheck LegalityCheck; typedef MoveGenerator MoveGenerator; typedef Serializer Serializer; typedef DropAnimatorMixin > Animator; typedef MoveFactory MoveFactory; static const bool hasICS = true; static const bool m_simple_moves = false; static const bool m_hidden = false; static const char *m_name; static const char *m_theme_proxy; static int moveListLayout() { return 0; } OptList positionOptions() const { return OptList(); } void setupMove(NormalUserMove& m) const; ActionCollection* actions(); private: Chess::Actions m_actions; }; } // namespace Chess } // namespace HLVariant #endif // HLVARIANT__CRAZYHOUSE__VARIANT_H tagua-1.0-alpha2/src/hlvariant/customboard.h000066400000000000000000000021161077523320400210750ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__CUSTOMBOARD_H #define HLVARIANT__CUSTOMBOARD_H #include "board.h" namespace HLVariant { template class CustomBoard : public Board<_Piece> { typedef Board<_Piece> Base; public: typedef _Piece Piece; CustomBoard(); CustomBoard(const CustomBoard& other); }; // IMPLEMENTATION template CustomBoard::CustomBoard() : Base(Point(size_x, size_y)) { } template CustomBoard::CustomBoard(const CustomBoard& other) : Base(other) { } } #endif // HLVARIANT__BOARD_H tagua-1.0-alpha2/src/hlvariant/dropanimator.h000066400000000000000000000110641077523320400212540ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__DROPANIMATOR_H #define HLVARIANT__DROPANIMATOR_H #include "animationfactory.h" #include "namedsprite.h" #include "common.h" namespace HLVariant { template class DropAnimatorMixin : public Base { typedef typename Base::Variant Variant; using Base::m_cinterface; protected: typedef typename Base::API API; typedef typename Base::GameState GameState; typedef typename Base::Piece Piece; typedef typename Base::Move Move; virtual void updatePool(const GameState& final); public: DropAnimatorMixin(API cinterface); virtual AnimationGroupPtr warp(const GameState& final); virtual AnimationGroupPtr forward(const GameState& final, const Move& move); virtual AnimationGroupPtr back(const GameState& final, const Move& move); }; // IMPLEMENTATION template DropAnimatorMixin::DropAnimatorMixin(API cinterface) : Base(cinterface) { } template void DropAnimatorMixin::updatePool(const GameState& final) { for(int color = 0; color < 2; color++) { typename Piece::Color c = static_cast(color); const typename GameState::Pool pool = final.pools().pool(c); const int n = pool.size(); for (int index = 0; index < n; ) { // precondition: pool and graphical pool match up to index // no more sprites on the graphical pool if (index >= m_cinterface->poolSize(color)) { // add extra sprites for (int i = index; i < n; i++) m_cinterface->insertPoolPiece(color, i, pool.get(i)); // done break; } NamedSprite sprite = m_cinterface->getPoolSprite(color, index); int i; // find a matching piece on the pool for (i = index; i < n; i++) { if (pool.get(i).name() == sprite.name()) break; } if (i < n) { // matching piece found on the pool // insert all pieces before this one on the graphical pool for (int j = index; j < i; j++) m_cinterface->insertPoolPiece(color, j, pool.get(j)); index = i + 1; } else { // no such piece found: remove it from the graphical pool m_cinterface->removePoolSprite(color, index); } } // remove extra pieces from the graphical pool while (m_cinterface->poolSize(color) > n) m_cinterface->removePoolSprite(color, n); } } template AnimationGroupPtr DropAnimatorMixin::warp(const GameState& final) { updatePool(final); return Base::warp(final); } template AnimationGroupPtr DropAnimatorMixin::forward(const GameState& final, const Move& move) { AnimationFactory res(m_cinterface->inner()); if (move.drop() != Piece()) { NamedSprite captured = m_cinterface->takeSprite(move.to()); std::pair dropped = m_cinterface->droppedPoolPiece(); if (dropped.first != -1 && dropped.second != -1 && m_cinterface->position()->pools().pool( static_cast(dropped.first) ).get( static_cast(dropped.second) ) == move.drop()) { NamedSprite drop = m_cinterface->takePoolSprite(dropped.first, dropped.second); m_cinterface->setSprite(move.to(), drop); res.addPreAnimation(Animate::move(drop, move.to())); } else { NamedSprite drop = m_cinterface->setPiece(move.to(), move.drop(), false); drop.sprite()->raise(); res.addPreAnimation(Animate::appear(drop)); } if (captured) res.addPostAnimation(Animate::destroy(captured)); res.group()->addPostAnimation(warp(final)); } else { res.setGroup(Base::forward(final, move)); } return res; } template AnimationGroupPtr DropAnimatorMixin::back(const GameState& final, const Move& move) { AnimationFactory res(m_cinterface->inner()); if(move.drop() != Piece()) { NamedSprite drop = m_cinterface->takeSprite(move.to()); res.addPostAnimation(Animate::disappear(drop)); res.group()->addPostAnimation(warp(final)); } else { res.setGroup(Base::back(final, move)); } return res; } } #endif // HLVARIANT__DROPANIMATOR_H tagua-1.0-alpha2/src/hlvariant/dummy/000077500000000000000000000000001077523320400175355ustar00rootroot00000000000000tagua-1.0-alpha2/src/hlvariant/dummy/gamestate.h000066400000000000000000000022631077523320400216630ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__DUMMY__LEGALITYCHECK_H #define HLVARIANT__DUMMY__LEGALITYCHECK_H #include "../chess/legalitycheck.h" #include "interactiontype.h" #include "turnpolicy.h" namespace HLVariant { namespace Dummy { template class LegalityCheck { public: typedef _GameState GameState; private: typedef typename GameState::Board Board; typedef typename GameState::Move Move; typedef typename Board::Piece Piece; public: LegalityCheck(const GameState&) { } virtual bool legal(Move& move) const { return true; } virtual InteractionType movable(const TurnTest& test, const Point& p) { return Moving; } virtual InteractionType droppable(const TurnTest& test, int index) { return Moving; } }; } // namespace Dummy } // namespace HLVariant #endif // HLVARIANT__DUMMY__LEGALITYCHECK_H tagua-1.0-alpha2/src/hlvariant/dummy/legalitycheck.h000066400000000000000000000040221077523320400225140ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__DUMMY__LEGALITYCHECK_H #define HLVARIANT__DUMMY__LEGALITYCHECK_H #include "../chess/legalitycheck.h" #include "interactiontype.h" #include "turnpolicy.h" namespace HLVariant { namespace Dummy { template class LegalityCheck { public: typedef _GameState GameState; protected: typedef typename GameState::Board Board; typedef typename GameState::Move Move; typedef typename Board::Piece Piece; const GameState& m_state; public: LegalityCheck(const GameState&); virtual ~LegalityCheck(); virtual bool legal(Move&) const; virtual InteractionType movable(const TurnTest&, const Point&); virtual InteractionType droppable(const TurnTest&, int); }; // IMPLEMENTATION template LegalityCheck::LegalityCheck(const GameState& state) : m_state(state) { } template LegalityCheck::~LegalityCheck() { } template bool LegalityCheck::legal(Move& move) const { if (move.drop() == Piece() && move.index() != -1 && move.pool() != -1) { move.setDrop(m_state.pools().pool(move.pool()).get(move.index())); } return true; } template InteractionType LegalityCheck::movable(const TurnTest& test, const Point& p) { Piece piece = m_state.board().get(p); return piece != Piece() && test(piece.color()) ? Moving : NoAction; } template InteractionType LegalityCheck::droppable(const TurnTest& test, int index) { return test(index) ? Moving : NoAction; } } // namespace Dummy } // namespace HLVariant #endif // HLVARIANT__DUMMY__LEGALITYCHECK_H tagua-1.0-alpha2/src/hlvariant/dummy/movegenerator.h000066400000000000000000000020151077523320400225610ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__DUMMY__MOVEGENERATOR_H #define HLVARIANT__DUMMY__MOVEGENERATOR_H namespace HLVariant { namespace Dummy { template class MoveGenerator { public: typedef _LegalityCheck LegalityCheck; typedef typename LegalityCheck::GameState GameState; typedef typename GameState::Board Board; typedef typename Board::Piece Piece; MoveGenerator(const GameState& ) { } virtual ~MoveGenerator() { } virtual bool stalled() const { return false; } virtual bool check(typename Piece::Color) const { return false; } }; } // namespace Dummy } // namespace HLVariant #endif // HLVARIANT__DUMMY__MOVEGENERATOR_H tagua-1.0-alpha2/src/hlvariant/dummy/variant.cpp000066400000000000000000000014321077523320400217050ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "variant.h" #include "../tagua_wrapped.h" namespace HLVariant { namespace Dummy { const char* Variant::m_name = "Dummy"; const char* Variant::m_theme_proxy = "Chess"; void Variant::setupMove(NormalUserMove& m) const { m.promotionType = m_actions.promotion(); } ActionCollection* Variant::actions() { return &m_actions; } DEFINE_VARIANT_FACTORY(); } // namespace Dummy } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/dummy/variant.h000066400000000000000000000030111077523320400213450ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__DUMMY__VARIANT_H #define HLVARIANT__DUMMY__VARIANT_H #include "../crazyhouse/variant.h" #include "legalitycheck.h" #include "movegenerator.h" #include "../chess/actions.h" namespace HLVariant { namespace Dummy { struct TAGUA_EXPORT Variant { typedef Crazyhouse::Variant::Move Move; typedef Crazyhouse::Variant::GameState GameState; typedef LegalityCheck LegalityCheck; typedef MoveGenerator MoveGenerator; // to make VariantData happy typedef Crazyhouse::Serializer Serializer; typedef DropAnimatorMixin > Animator; typedef Crazyhouse::MoveFactory MoveFactory; static const bool hasICS = true; static const bool m_simple_moves = false; static const bool m_hidden = true; static const char *m_name; static const char *m_theme_proxy; static int moveListLayout() { return 0; } OptList positionOptions() const { return OptList(); } void setupMove(NormalUserMove& m) const; ActionCollection* actions(); private: Chess::Actions m_actions; }; } // namespace Dummy } // namespace HLVariant #endif // HLVARIANT__DUMMY__VARIANT_H tagua-1.0-alpha2/src/hlvariant/graphicalapi_unwrapped.h000066400000000000000000000064431077523320400232730ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__UNWRAPPEDGRAPHICALAPI_H #define HLVARIANT__UNWRAPPEDGRAPHICALAPI_H #include "graphicalapi.h" #include "variantdata.h" namespace HLVariant { /** * This class moves the interface that will be used by the animator to modify * tagua graphics into the variant's semantics. */ template class UnwrappedGraphicalAPI { GraphicalAPI* m_graphical_api; typedef typename VariantData::GameState GameState; typedef typename VariantData::Piece Piece; public: typedef boost::shared_ptr Ptr; UnwrappedGraphicalAPI(GraphicalAPI* interface) : m_graphical_api(interface) { } virtual ~UnwrappedGraphicalAPI(){} virtual const PointConverter* converter() { return m_graphical_api->converter(); } virtual const GameState* position() { const WrappedPosition *p = dynamic_cast*>(m_graphical_api->position().get()); if (p) { return &p->inner(); } else { MISMATCH(m_graphical_api->position(), WrappedPosition); return NULL; } } virtual NamedSprite setPiece(const Point& p, const Piece& piece, bool show) { WrappedPiece wpiece(piece); return m_graphical_api->setPiece(p, &wpiece, show); } virtual NamedSprite createPiece(const Point& p, const Piece& piece, bool show) { WrappedPiece wpiece(piece); return m_graphical_api->createPiece(p, &wpiece, show); } virtual void setSprite(const Point& p, const NamedSprite& s) { m_graphical_api->setSprite(p, s); } virtual NamedSprite getSprite(const Point& p) { return m_graphical_api->getSprite(p); } virtual NamedSprite takeSprite(const Point& p) { return m_graphical_api->takeSprite(p); } virtual int poolSize(int pool) const { return m_graphical_api->poolSize(pool); } virtual NamedSprite insertPoolPiece(int pool, int index, const Piece& piece) { WrappedPiece wpiece(piece); return m_graphical_api->insertPoolPiece(pool, index, &wpiece); } virtual NamedSprite getPoolSprite(int pool, int index) { return m_graphical_api->getPoolSprite(pool, index); } virtual void removePoolSprite(int pool, int index) { m_graphical_api->removePoolSprite(pool, index); } virtual NamedSprite takePoolSprite(int pool, int index) { return m_graphical_api->takePoolSprite(pool, index); } virtual std::pair droppedPoolPiece() { return m_graphical_api->droppedPoolPiece(); } virtual AnimationPtr animate(const Animate::Scheme& scheme, Animate::AnimationType type = Animate::Normal) { return m_graphical_api->animate(scheme, type); } GraphicalAPI* inner() const { return m_graphical_api; } }; } #endif // HLVARIANT__UNWRAPPEDGRAPHICALAPI_H tagua-1.0-alpha2/src/hlvariant/icsapi_wrapped.h000066400000000000000000000052771077523320400215600ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__ICSAPI_WRAPPED_H #define HLVARIANT__ICSAPI_WRAPPED_H #include "icsapi.h" #include "tagua_wrapped.h" namespace HLVariant { template class WrappedICSAPI : public ICSAPI { public: virtual PositionPtr createChessboard(int, bool, bool, bool, bool, const Point&); virtual PiecePtr createPiece(const QString& description); virtual MovePtr parseVerbose(const QString& str, const PositionPtr& ref); }; // IMPLEMENTATION template PositionPtr WrappedICSAPI::createChessboard( int turn, bool wkCastle, bool wqCastle, bool bkCastle, bool bqCastle, const Point& enPassant) { return PositionPtr(new WrappedPosition( typename VariantData::GameState( static_cast::Piece::Color>(turn), wkCastle, wqCastle, bkCastle, bqCastle, enPassant))); } template PiecePtr WrappedICSAPI::createPiece(const QString& description) { return PiecePtr(new WrappedPiece( VariantData::Piece::fromDescription(description))); } template MovePtr WrappedICSAPI::parseVerbose(const QString& str, const PositionPtr& _ref) { if (!_ref) return MovePtr(); WrappedPosition* ref = dynamic_cast*>(_ref.get()); if (ref) { typename VariantData::Serializer serializer("ics-verbose"); return MovePtr(new WrappedMove( serializer.deserialize(str, ref->inner()))); } else { MISMATCH(*_ref.get(), WrappedPosition); return MovePtr(); } } /** * Helper metafunction to create a null ICSAPI object * if the variant does not support ICS. */ template struct ReturnICSAPIAux { }; template struct ReturnICSAPIAux { static ICSAPI* apply() { return new WrappedICSAPI(); } }; template struct ReturnICSAPIAux { static ICSAPI* apply() { return 0; } }; template struct ReturnICSAPI : public ReturnICSAPIAux { }; } #endif // HLVARIANT__ICSAPI_WRAPPED_H tagua-1.0-alpha2/src/hlvariant/minichess5/000077500000000000000000000000001077523320400204515ustar00rootroot00000000000000tagua-1.0-alpha2/src/hlvariant/minichess5/variant.cpp000066400000000000000000000014641077523320400226260ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "variant.h" #include "../tagua_wrapped.h" namespace HLVariant { namespace Minichess5 { const char* Variant::m_name = "Chess 5x5"; const char* Variant::m_theme_proxy = "Chess"; void Variant::setupMove(NormalUserMove& m) const { m.promotionType = m_actions.promotion(); } ActionCollection* Variant::actions() { return &m_actions; } DEFINE_VARIANT_FACTORY(); } // namespace Minichess5 } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/minichess5/variant.h000066400000000000000000000027671077523320400223020ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__MINICHESS5__VARIANT_H #define HLVARIANT__MINICHESS5__VARIANT_H #include "../chess/variant.h" #include "../chess/actions.h" namespace HLVariant { namespace Minichess5 { struct TAGUA_EXPORT Variant { typedef Chess::Move Move; typedef Chess::Piece Piece; typedef CustomBoard<5, 5, Piece> Board; typedef Chess::GameState GameState; typedef Chess::LegalityCheck LegalityCheck; typedef Chess::MoveGenerator MoveGenerator; typedef Chess::Serializer Serializer; typedef SimpleAnimator Animator; typedef MoveFactory MoveFactory; static const bool hasICS = false; static const bool m_simple_moves = false; static const bool m_hidden = false; static const char *m_name; static const char *m_theme_proxy; static int moveListLayout() { return 0; } OptList positionOptions() const { return OptList(); } void setupMove(NormalUserMove& m) const; ActionCollection* actions(); private: Chess::Actions m_actions; }; } // namespace Minichess5 } // namespace HLVariant #endif // HLVARIANT__MINICHESS5__VARIANT_H tagua-1.0-alpha2/src/hlvariant/minishogi/000077500000000000000000000000001077523320400203705ustar00rootroot00000000000000tagua-1.0-alpha2/src/hlvariant/minishogi/gamestate.h000066400000000000000000000040271077523320400225160ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge (c) 2007 Yann Dirson 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. */ #ifndef HLVARIANT__MINISHOGI__GAMESTATE_H #define HLVARIANT__MINISHOGI__GAMESTATE_H #include "../shogi/gamestate.h" #include "../shogi/piece.h" namespace HLVariant { namespace MiniShogi { template class GameState: public Shogi::GameState<_Board, _Move> { public: virtual void setup(); virtual bool promotionZone(typename Shogi::Piece::Color player, const Point& p) const; }; // IMPLEMENTATION #define MS_COL(i, c) c == Shogi::Piece::BLACK ? (i) : \ (Shogi::GameState::board().size().x - i - 1) #define MS_ROW(i, c) rank + i * Shogi::GameState::direction(color).y #define MS_PIECE(x,y,p) Shogi::GameState::board().set(Point(MS_COL(x, c), MS_ROW(y, c)), \ Shogi::Piece(color, p)) template void GameState::setup() { for (int c = 0; c < 2; c++) { typename Shogi::Piece::Color color = static_cast(c); int rank = Shogi::GameState::startingRank(color); MS_PIECE(0, 0, Shogi::Piece::KING); MS_PIECE(1, 0, Shogi::Piece::GOLD); MS_PIECE(2, 0, Shogi::Piece::SILVER); MS_PIECE(3, 0, Shogi::Piece::BISHOP); MS_PIECE(4, 0, Shogi::Piece::ROOK); MS_PIECE(0, 1, Shogi::Piece::PAWN); } } #undef MS_PIECE #undef MS_ROW #undef MS_COL template bool GameState::promotionZone(typename Shogi::Piece::Color player, const Point& p) const { return player == Shogi::Piece::WHITE ? p.y == 4 : p.y == 0; } } // namespace MiniShogi } // namespace HLVariant #endif // HLVARIANT__MINISHOGI__GAMESTATE_H tagua-1.0-alpha2/src/hlvariant/minishogi/variant.cpp000066400000000000000000000015361077523320400225450ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge (c) 2007 Yann Dirson 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. */ #include "variant.h" #include "../tagua_wrapped.h" namespace HLVariant { namespace MiniShogi { const char* Variant::m_name = "MiniShogi"; const char* Variant::m_theme_proxy = "Shogi"; void Variant::setupMove(NormalUserMove& m) const { m.promotionType = m_actions.promotion() ? 0 : -1; } ActionCollection* Variant::actions() { return &m_actions; } DEFINE_VARIANT_FACTORY(); } // namespace MiniShogi } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/minishogi/variant.h000066400000000000000000000035051077523320400222100ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge (c) 2007 Yann Dirson 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. */ #ifndef HLVARIANT__MINISHOGI__VARIANT_H #define HLVARIANT__MINISHOGI__VARIANT_H #include "../shogi/piece.h" #include "../shogi/shogiban.h" #include "../chess/move.h" #include "../crazyhouse/move.h" #include "gamestate.h" #include "../shogi/legalitycheck.h" #include "../shogi/serializer.h" #include "../crazyhouse/movefactory.h" #include "../animator.h" #include "../dropanimator.h" #include "../shogi/shogiactions.h" namespace HLVariant { namespace MiniShogi { struct TAGUA_EXPORT Variant { typedef Crazyhouse::MoveMixin Move; typedef GameState, Move> GameState; typedef Shogi::LegalityCheck LegalityCheck; typedef Shogi::Serializer Serializer; typedef DropAnimatorMixin > Animator; typedef Crazyhouse::MoveFactory MoveFactory; typedef Variant MoveGenerator; // to make VariantData happy static const bool hasICS = false; static const bool m_simple_moves = false; static const bool m_hidden = false; static const char *m_name; static const char *m_theme_proxy; static int moveListLayout() { return 0; } OptList positionOptions() const { return OptList(); } void setupMove(NormalUserMove& m) const; ActionCollection* actions(); private: Shogi::ShogiActions m_actions; }; } // namespace MiniShogi } // namespace HLVariant #endif // HLVARIANT__MINISHOGI__VARIANT_H tagua-1.0-alpha2/src/hlvariant/movefactory.h000066400000000000000000000021271077523320400211130ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef HLVARIANT__MOVEFACTORY_H #define HLVARIANT__MOVEFACTORY_H #include "tagua.h" #include "usermove.h" #include "variantdata.h" namespace HLVariant { template class MoveFactory { public: typedef typename GameState::Move Move; typedef typename GameState::Board::Piece Piece; virtual ~MoveFactory() { } virtual Move createNormalMove(const NormalUserMove& move) { return Move(move.from, move.to, static_cast(move.promotionType)); } virtual Move createDropMove(const DropUserMove&) { return Move(); } virtual NormalUserMove toNormal(const Move& move) { return NormalUserMove(move.from(), move.to()); } }; } #endif // HLVARIANT__MOVEFACTORY_H tagua-1.0-alpha2/src/hlvariant/pool.h000066400000000000000000000070701077523320400175300ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__POOL_H #define HLVARIANT__POOL_H #include namespace HLVariant { template class Pool { public: typedef _Piece Piece; private: typedef typename Piece::Color Color; typedef typename Piece::Type Type; typedef std::map Data; Color m_owner; Data m_data; public: Pool(Color owner); virtual ~Pool(); virtual bool operator==(const Pool& other) const; virtual bool operator!=(const Pool& other) const; virtual int count(Type type) const; virtual int add(Type type); virtual int remove(Type type); virtual bool empty() const; virtual int size() const; virtual int insert(int index, const Piece& piece); virtual Piece get(int index) const; virtual Piece take(int index); typedef Data RawData; const RawData& rawData() const { return m_data; } }; // IMPLEMENTATION template Pool::Pool(Color owner) : m_owner(owner) { } template Pool::~Pool() { } template bool Pool::operator==(const Pool& other) const { return m_owner == other.m_owner && m_data == other.m_data; } template bool Pool::operator!=(const Pool& other) const { return !((*this) == other); } template int Pool::count(Type type) const { typename Data::const_iterator it = m_data.find(type); if (it != m_data.end()) { return it->second; } else { return 0; } } template int Pool::add(Type type) { return ++m_data[type]; } template int Pool::remove(Type type) { int n = --m_data[type]; if (n <= 0) { m_data.erase(type); return 0; } return n; } template bool Pool::empty() const { return m_data.empty(); } template int Pool::size() const { int count = 0; for (typename Data::const_iterator end = m_data.end(), it = m_data.begin(); it != end; ++it) count += it->second; return count; } template int Pool::insert(int index, const Piece& piece) { if (m_owner != piece.color()) return -1; int fill = 0; for (typename Data::iterator end = m_data.end(), i = m_data.begin(); i != end && i->first < piece.type(); ++i) { fill += i->second; } int nump = add(piece.type()); if (index < fill) return fill; if (index >= fill + nump) return fill + nump - 1; return index; } template Piece Pool::get(int index) const { if (index < 0) return Piece(); int fill = 0; for (typename Data::const_iterator end = m_data.end(), i = m_data.begin(); i != end; ++i) { if (index < fill + i->second) return Piece(m_owner, i->first); fill += i->second; } return Piece(); } template Piece Pool::take(int index) { if (index < 0) return Piece(); int fill = 0; for (typename Data::iterator end = m_data.end(), i = m_data.begin(); i != end; ++i) { if(index < fill + i->second) { Type type = i->first; remove(type); return Piece(m_owner, type); } fill += i->second; } return Piece(); } } #endif // HLVARIANT__POOL_H tagua-1.0-alpha2/src/hlvariant/poolcollection.h000066400000000000000000000053001077523320400215760ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__POOLCOLLECTION_H #define HLVARIANT__POOLCOLLECTION_H namespace HLVariant { template class PoolCollection { public: typedef _Pool Pool; private: typedef typename Pool::Piece Piece; typedef typename Piece::Color Color; typedef std::map Pools; Pools m_pools; public: virtual ~PoolCollection(); virtual bool operator==(const PoolCollection& other) const; virtual bool operator!=(const PoolCollection& other) const; virtual Pool& pool(Color player); virtual const Pool& pool(Color player) const; }; // IMPLEMENTATION template PoolCollection::~PoolCollection() { } template bool PoolCollection::operator==(const PoolCollection& other) const { typename Pools::const_iterator i = m_pools.begin(); typename Pools::const_iterator j = other.m_pools.begin(); while (i != m_pools.end() && j != other.m_pools.end()) { if (i->first < j->first) { if (!i->second.empty()) return false; else ++i; } else if (i->first > j->first) { if (!j->second.empty()) return false; else ++j; } else { // same key, compare values if (i->second != j->second) return false; else { ++i; ++j; } } } // check tail while (i != m_pools.end()) { if (!i->second.empty()) return false; ++i; } while (j != other.m_pools.end()) { if (!j->second.empty()) return false; ++j; } return true; } template bool PoolCollection::operator!=(const PoolCollection& other) const { return !((*this) == other); } template Pool& PoolCollection::pool(Color player) { // return pool if it exists typename Pools::iterator it = m_pools.find(player); if (it != m_pools.end()) { return it->second; } // if not, create it m_pools.insert(std::make_pair(player, Pool(player))); return m_pools.find(player)->second; } template const Pool& PoolCollection::pool(Color player) const { // here we use const cast, because our semantics of PoolCollection // considers an empty pool the same thing as no pool. return const_cast(this)->pool(player); } } #endif // HLVARIANT__POOLCOLLECTION_H tagua-1.0-alpha2/src/hlvariant/sho-shogi/000077500000000000000000000000001077523320400203025ustar00rootroot00000000000000tagua-1.0-alpha2/src/hlvariant/sho-shogi/gamestate.h000066400000000000000000000041501077523320400224250ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge (c) 2007 Yann Dirson 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. */ #ifndef HLVARIANT__SHOSHOGI__GAMESTATE_H #define HLVARIANT__SHOSHOGI__GAMESTATE_H #include "../shogi/gamestate.h" #include "../shogi/piece.h" namespace HLVariant { namespace ShoShogi { template class GameState: public Shogi::GameState<_Board, _Move> { public: virtual void setup(); }; // IMPLEMENTATION #define MS_COL(i, c) c == Shogi::Piece::BLACK ? (i) : \ (Shogi::GameState::board().size().x - i - 1) #define MS_ROW(i, c) rank + i * Shogi::GameState::direction(color).y #define MS_PIECE(x,y,p) Shogi::GameState::board().set(Point(MS_COL(x, c), MS_ROW(y, c)), \ Shogi::Piece(color, p)) template void GameState::setup() { for (int c = 0; c < 2; c++) { typename Shogi::Piece::Color color = static_cast(c); int rank = Shogi::GameState::startingRank(color); for (int i = 0; i < Shogi::GameState::board().size().x; i++) { MS_PIECE(i, 2, Shogi::Piece::PAWN); } MS_PIECE(0, 0, Shogi::Piece::LANCE); MS_PIECE(1, 0, Shogi::Piece::KNIGHT); MS_PIECE(2, 0, Shogi::Piece::SILVER); MS_PIECE(3, 0, Shogi::Piece::GOLD); MS_PIECE(4, 0, Shogi::Piece::KING); MS_PIECE(5, 0, Shogi::Piece::GOLD); MS_PIECE(6, 0, Shogi::Piece::SILVER); MS_PIECE(7, 0, Shogi::Piece::KNIGHT); MS_PIECE(8, 0, Shogi::Piece::LANCE); MS_PIECE(1, 1, Shogi::Piece::BISHOP); MS_PIECE(4, 1, Shogi::Piece::DRUNKEN_ELEPHANT); MS_PIECE(7, 1, Shogi::Piece::ROOK); } } #undef MS_PIECE #undef MS_ROW #undef MS_COL } // namespace ShoShogi } // namespace HLVariant #endif // HLVARIANT__SHOSHOGI__GAMESTATE_H tagua-1.0-alpha2/src/hlvariant/sho-shogi/legalitycheck.h000066400000000000000000000041271077523320400232670ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__SHOSHOGI__LEGALITYCHECK_H #define HLVARIANT__SHOSHOGI__LEGALITYCHECK_H #include "interactiontype.h" #include "../shogi/legalitycheck.h" namespace HLVariant { namespace ShoShogi { template class LegalityCheck: public Shogi::LegalityCheck<_GameState> { typedef Shogi::LegalityCheck<_GameState> Base; public: typedef _GameState GameState; typedef typename GameState::Board Board; typedef typename Board::Piece Piece; typedef typename GameState::Move Move; LegalityCheck(const GameState& state); bool legal(Move& move) const; virtual InteractionType droppable(const TurnTest&, int index) const; }; // IMPLEMENTATION template LegalityCheck::LegalityCheck(const GameState& state) : Base(state) { } template InteractionType LegalityCheck::droppable(const TurnTest&, int) const { return NoAction; } template bool LegalityCheck::legal(Move& move) const { if (!pseudolegal(move)) return false; GameState tmp(Base::m_state); tmp.move(move); // find king and prince positions Point king_pos = tmp.board().find(Piece(Base::m_state.turn(), Piece::KING)); Point prince_pos = tmp.board().find(Piece(Base::m_state.turn(), Piece::DRUNKEN_ELEPHANT, true)); // check if the king and prince can be captured if ((canBeCaptured(tmp, king_pos) && canBeCaptured(tmp, prince_pos)) || (canBeCaptured(tmp, king_pos) && !prince_pos.valid()) || (canBeCaptured(tmp, prince_pos) && !king_pos.valid()) || (!prince_pos.valid() && !king_pos.valid())) return false; return true; } } // namespace ShoShogi } // namespace HLVariant #endif // HLVARIANT__SHOSHOGI__LEGALITYCHECK_H tagua-1.0-alpha2/src/hlvariant/sho-shogi/variant.cpp000066400000000000000000000015361077523320400224570ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge (c) 2007 Yann Dirson 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. */ #include "variant.h" #include "../tagua_wrapped.h" namespace HLVariant { namespace ShoShogi { const char* Variant::m_name = "Sho Shogi"; const char* Variant::m_theme_proxy = "LargeShogi"; void Variant::setupMove(NormalUserMove& m) const { m.promotionType = m_actions.promotion() ? 0 : -1; } ActionCollection* Variant::actions() { return &m_actions; } DEFINE_VARIANT_FACTORY(); } // namespace ShoShogi } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/sho-shogi/variant.h000066400000000000000000000034551077523320400221260ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge (c) 2007 Yann Dirson 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. */ #ifndef HLVARIANT__SHOSHOGI__VARIANT_H #define HLVARIANT__SHOSHOGI__VARIANT_H #include "../shogi/piece.h" #include "../shogi/shogiban.h" #include "../chess/move.h" #include "../crazyhouse/move.h" #include "gamestate.h" #include "legalitycheck.h" #include "../shogi/serializer.h" #include "../crazyhouse/movefactory.h" #include "../animator.h" #include "../dropanimator.h" #include "../shogi/shogiactions.h" namespace HLVariant { namespace ShoShogi { struct TAGUA_EXPORT Variant { typedef Crazyhouse::MoveMixin Move; typedef GameState, Move> GameState; typedef LegalityCheck LegalityCheck; typedef Shogi::Serializer Serializer; typedef DropAnimatorMixin > Animator; typedef Crazyhouse::MoveFactory MoveFactory; typedef Variant MoveGenerator; // to make VariantData happy static const bool hasICS = false; static const bool m_simple_moves = false; static const bool m_hidden = false; static const char *m_name; static const char *m_theme_proxy; static int moveListLayout() { return 0; } OptList positionOptions() const { return OptList(); } void setupMove(NormalUserMove& m) const; ActionCollection* actions(); private: Shogi::ShogiActions m_actions; }; } // namespace ShoShogi } // namespace HLVariant #endif // HLVARIANT__SHOSHOGI__VARIANT_H tagua-1.0-alpha2/src/hlvariant/shogi/000077500000000000000000000000001077523320400175135ustar00rootroot00000000000000tagua-1.0-alpha2/src/hlvariant/shogi/gamestate.h000066400000000000000000000150111077523320400216340ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__SHOGI__GAMESTATE_H #define HLVARIANT__SHOGI__GAMESTATE_H #include "../crazyhouse/gamestate.h" #include "../pool.h" #include "../poolcollection.h" namespace HLVariant { namespace Shogi { template class GameState { public: typedef _Board Board; typedef _Move Move; typedef typename Board::Piece Piece; typedef Pool Pool; typedef PoolCollection Pools; private: Board m_board; Pools m_pools; typename Piece::Color m_turn; public: GameState(); virtual ~GameState(); virtual Board& board(); virtual const Board& board() const; virtual Pools& pools(); virtual const Pools& pools() const; virtual void setup(); virtual bool operator==(const GameState& other) const; virtual void move(const Move& m); virtual void basicMove(const Move& m); virtual void captureOn(const Point& p); virtual bool promotionZone(typename Piece::Color player, const Point& p) const; virtual bool canPromote(const Piece& p) const; virtual void setTurn(typename Piece::Color color); virtual typename Piece::Color previousTurn() const; virtual void switchTurn(); virtual typename Piece::Color turn() const; virtual int startingRank(typename Piece::Color color) const; virtual int promotionRank(typename Piece::Color color) const; virtual Point kingStartingPosition(typename Piece::Color color) const; virtual Point direction(typename Piece::Color color) const; }; // IMPLEMENTATION template GameState::GameState() : m_turn(Piece::BLACK) { } template GameState::~GameState() { } template Board& GameState::board() { return m_board; } template const Board& GameState::board() const { return m_board; } template typename GameState::Pools& GameState::pools() { return m_pools; } template const typename GameState::Pools& GameState::pools() const { return m_pools; } #define COL(i, c) c == Piece::BLACK ? (i) : (m_board.size().x - i - 1) template void GameState::setup() { for (int c = 0; c < 2; c++) { typename Piece::Color color = static_cast(c); int rank = startingRank(color); for (int i = 0; i < m_board.size().x; i++) { m_board.set(Point(i, rank + direction(color).y * 2), Piece(color, Piece::PAWN)); } m_board.set(Point(0, rank), Piece(color, Piece::LANCE)); m_board.set(Point(1, rank), Piece(color, Piece::KNIGHT)); m_board.set(Point(2, rank), Piece(color, Piece::SILVER)); m_board.set(Point(3, rank), Piece(color, Piece::GOLD)); m_board.set(Point(4, rank), Piece(color, Piece::KING)); m_board.set(Point(5, rank), Piece(color, Piece::GOLD)); m_board.set(Point(6, rank), Piece(color, Piece::SILVER)); m_board.set(Point(7, rank), Piece(color, Piece::KNIGHT)); m_board.set(Point(8, rank), Piece(color, Piece::LANCE)); m_board.set(Point(COL(1, c), rank + direction(color).y), Piece(color, Piece::BISHOP)); m_board.set(Point(COL(7, c), rank + direction(color).y), Piece(color, Piece::ROOK)); } } #undef COL template bool GameState::promotionZone(typename Piece::Color player, const Point& p) const { return player == Piece::WHITE ? p.y >= 6 : p.y <= 2; } template bool GameState::canPromote(const Piece& p) const { if (p.promoted()) return false; if ((p.type() == Piece::KING) || (p.type() == Piece::GOLD)) return false; else return true; } template bool GameState::operator==(const GameState& other) const { return m_turn == other.m_turn && m_board == other.m_board; } template void GameState::move(const Move& m) { if (m.drop() == Piece()) { captureOn(m.to()); basicMove(m); if (m.promoteTo() != -1) { Piece piece = m_board.get(m.to()); piece.setPromoted(); m_board.set(m.to(), piece); } } else { m_board.set(m.to(), m.drop()); m_pools.pool(m.drop().color()).remove(m.drop().type()); } switchTurn(); } template void GameState::captureOn(const Point& p) { Piece captured = m_board.get(p); m_board.set(p, Piece()); m_pools.pool(Piece::oppositeColor(captured.color())).add(captured.type()); } template void GameState::basicMove(const Move& m) { if (m.from() != m.to()) { m_board.set(m.to(), m_board.get(m.from())); m_board.set(m.from(), Piece()); } } template void GameState::switchTurn() { m_turn = Piece::oppositeColor(m_turn); } template typename Board::Piece::Color GameState::turn() const { return m_turn; } template typename Board::Piece::Color GameState::previousTurn() const { return Piece::oppositeColor(m_turn); } template void GameState::setTurn(typename Piece::Color color) { m_turn = color; } template int GameState::startingRank(typename Piece::Color color) const { return color == Piece::BLACK ? m_board.size().y - 1 : 0; } template int GameState::promotionRank(typename Piece::Color color) const { return startingRank(Piece::oppositeColor(color)); } template Point GameState::kingStartingPosition(typename Piece::Color color) const { return Point(4, startingRank(color)); } template Point GameState::direction(typename Piece::Color color) const { return Point(0, color == Piece::BLACK ? -1 : 1); } } // namespace Shogi } // namespace HLVariant #endif // HLVARIANT__SHOGI__GAMESTATE_H tagua-1.0-alpha2/src/hlvariant/shogi/legalitycheck.h000066400000000000000000000166571077523320400225130ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__SHOGI__LEGALITYCHECK_H #define HLVARIANT__SHOGI__LEGALITYCHECK_H #include "interactiontype.h" #include #include "turnpolicy.h" namespace HLVariant { namespace Shogi { template class LegalityCheck { public: typedef _GameState GameState; typedef typename GameState::Board Board; typedef typename Board::Piece Piece; typedef typename GameState::Move Move; protected: const GameState& m_state; virtual bool stuckPiece(const Piece& piece, const Point& p) const; public: LegalityCheck(const GameState& state); virtual ~LegalityCheck(); virtual bool getMoveType(const Piece& piece, const Move& move) const; bool legal(Move& move) const; bool pseudolegal(Move& move) const; bool canBeCaptured(const GameState& state, const Point& point) const; virtual InteractionType movable(const TurnTest&, const Point& x) const; virtual InteractionType droppable(const TurnTest&, int index) const; }; // IMPLEMENTATION template LegalityCheck::LegalityCheck(const GameState& state) : m_state(state) { } template LegalityCheck::~LegalityCheck() { } template bool LegalityCheck::getMoveType(const Piece& piece, const Move& move) const { if (!move.valid()) return false; if (move.from() == move.to()) return false; if (m_state.board().get(move.to()).color() == piece.color()) return false; Point delta = move.to() - move.from(); if (!piece.promoted()) { switch (piece.type()) { case Piece::KING: return abs(delta.x) <= 1 && abs(delta.y) <= 1; case Piece::GOLD: return (delta.x == 0 && abs(delta.y) == 1) || (delta.y == 0 && abs(delta.x) == 1) || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1); case Piece::SILVER: return (abs(delta.x) == abs(delta.y) && abs(delta.x) == 1) || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1); case Piece::ROOK: { PathInfo path = m_state.board().path(move.from(), move.to()); return path.parallel() && path.clear(); } case Piece::BISHOP: { PathInfo path = m_state.board().path(move.from(), move.to()); return path.diagonal() && path.clear(); } case Piece::KNIGHT: { return abs(delta.x) == 1 && delta.y == m_state.direction(piece.color()).y * 2; } case Piece::LANCE: { PathInfo path = m_state.board().path(move.from(), move.to()); return delta.x == 0 && path.clear() && (delta.y * m_state.direction(piece.color()).y > 0); } case Piece::PAWN: return delta == m_state.direction(piece.color()); case Piece::DRUNKEN_ELEPHANT: return (abs(delta.x) == 1 && abs(delta.y) <= 1) || (delta.x == 0 && delta.y == m_state.direction(piece.color()).y); default: return false; } } else { switch (piece.type()) { case Piece::SILVER: case Piece::PAWN: case Piece::LANCE: case Piece::KNIGHT: return (delta.x == 0 && abs(delta.y) == 1) || (delta.y == 0 && abs(delta.x) == 1) || (delta.y == m_state.direction(piece.color()).y && abs(delta.x) <= 1); case Piece::ROOK: { if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true; PathInfo path = m_state.board().path(move.from(), move.to()); return path.parallel() && path.clear(); } case Piece::BISHOP: { if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true; PathInfo path = m_state.board().path(move.from(), move.to()); return path.diagonal() && path.clear(); } case Piece::DRUNKEN_ELEPHANT: // Crown Prince return abs(delta.x) <= 1 && abs(delta.y) <= 1; default: return false; } } } template bool LegalityCheck::pseudolegal(Move& move) const { if (move.drop() == Piece() && move.pool() != -1 && move.index() != -1) { move.setDrop(m_state.pools().pool(move.pool()).get(move.index())); } Piece dropped = move.drop(); if (dropped != Piece()) { if (m_state.board().get(move.to()) != Piece()) return false; if (stuckPiece(dropped, move.to())) return false; if (dropped.type() == Piece::PAWN) { for (int i = 0; i < m_state.board().size().y; i++) { Piece other = m_state.board().get(Point(move.to().x, i)); if (other.type() == Piece::PAWN && other.color() == m_state.turn() && !other.promoted()) return false; } } return true; } else { Piece piece = m_state.board().get(move.from()); if (piece != Piece() && getMoveType(piece, move)) { if (m_state.canPromote(piece) && (m_state.promotionZone(piece.color(), move.to()) || m_state.promotionZone(piece.color(), move.from()))) move.setType(Move::PROMOTION); return true; } else { return false; } } } template bool LegalityCheck::canBeCaptured(const GameState& state, const Point& point) const { for (int i = 0; i < m_state.board().size().x; i++) { for (int j = 0; j < m_state.board().size().y; j++) { Point p(i, j); Piece piece = state.board().get(p); LegalityCheck check(state); if (piece.color() == state.turn() && check.getMoveType(piece, Move(p, point))) { return true; } } } return false; } template bool LegalityCheck::legal(Move& move) const { if (!pseudolegal(move)) return false; GameState tmp(m_state); tmp.move(move); // find king position Point king_pos = tmp.board().find(Piece(m_state.turn(), Piece::KING)); if (!king_pos.valid()) return false; // check if the king can be captured if (canBeCaptured(tmp, king_pos)) return false; return true; } template bool LegalityCheck::stuckPiece(const Piece& piece, const Point& p) const { if (piece.type() == Piece::PAWN || piece.type() == Piece::LANCE) { return p.y == m_state.startingRank(Piece::oppositeColor(piece.color())); } else if (piece.type() == Piece::KNIGHT) { int rank = m_state.startingRank(Piece::oppositeColor(piece.color())); return p.y == rank || p.y == rank - m_state.direction(piece.color()).y; } else { return false; } } template InteractionType LegalityCheck::movable(const TurnTest& test, const Point& p) const { Piece piece = m_state.board().get(p); if (piece == Piece() || !test(piece.color())) return NoAction; return piece.color() == m_state.turn() ? Moving : Premoving; } template InteractionType LegalityCheck::droppable(const TurnTest& test, int index) const { if (!test(index)) return NoAction; typename Piece::Color c = static_cast(index); return c == m_state.turn() ? Moving : Premoving; } } // namespace Shogi } // namespace HLVariant #endif // HLVARIANT__SHOGI__LEGALITYCHECK_H tagua-1.0-alpha2/src/hlvariant/shogi/piece.cpp000066400000000000000000000040301077523320400213010ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "piece.h" namespace HLVariant { namespace Shogi { Piece::Piece(Color color, Type type, bool promoted) : m_color(color) , m_type(type) , m_promoted(promoted) { } Piece::~Piece() { } void Piece::setPromoted() { m_promoted = true; } bool Piece::promoted() const { return m_promoted; } Piece::Color Piece::color() const { return m_color; } Piece::Type Piece::type() const { return m_type; } QString Piece::colorName() const { return colorName(m_color); } QString Piece::colorName(Color color) { switch (color) { case WHITE: return "white"; case BLACK: return "black"; default: return "unknown"; } } QString Piece::typeName() const { return typeName(m_type); } QString Piece::typeName(Type type) { switch (type) { case KING: return "king"; case GOLD: return "gold"; case SILVER: return "silver"; case KNIGHT: return "knight"; case LANCE: return "lance"; case ROOK: return "rook"; case BISHOP: return "bishop"; case PAWN: return "pawn"; case DRUNKEN_ELEPHANT: return "drunken_elephant"; default: return "unknown"; } } QString Piece::name() const { QString res = colorName() + '_'; if (m_promoted) res += "p_"; return res + typeName(); } Piece::Color Piece::oppositeColor(Color color) { return (color == WHITE) ? BLACK : (color == BLACK) ? WHITE : INVALID_COLOR; } bool Piece::operator==(const Piece& other) const { return m_color == other.m_color && m_type == other.m_type && m_promoted == other.m_promoted; } bool Piece::operator!=(const Piece& other) const { return !((*this) == other); } } // namespace Shogi } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/shogi/piece.h000066400000000000000000000027561077523320400207630ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__SHOGI__PIECE_H #define HLVARIANT__SHOGI__PIECE_H #include #include "export.h" namespace HLVariant { namespace Shogi { class TAGUA_EXPORT Piece { public: enum Color { INVALID_COLOR = -1, BLACK, WHITE }; enum Type { KING, GOLD, SILVER, KNIGHT, LANCE, ROOK, BISHOP, PAWN, // Sho Shogi DRUNKEN_ELEPHANT, INVALID_TYPE = -1 }; private: Color m_color; Type m_type; bool m_promoted; public: Piece(Color color = INVALID_COLOR, Type type = INVALID_TYPE, bool promoted = false); virtual ~Piece(); virtual Color color() const; virtual Type type() const; virtual QString colorName() const; static QString colorName(Color color); virtual QString typeName() const; static QString typeName(Type type); virtual QString name() const; static Color oppositeColor(Color color); virtual bool operator==(const Piece& other) const; virtual bool operator!=(const Piece& other) const; void setPromoted(); bool promoted() const; }; } // namespace Shogi } // namespace HLVariant #endif // HLVARIANT__SHOGI__VARIANT_H tagua-1.0-alpha2/src/hlvariant/shogi/serializer.h000066400000000000000000000176061077523320400220470ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__SHOGI__SERIALIZER_H #define HLVARIANT__SHOGI__SERIALIZER_H #include #include #include namespace HLVariant { namespace Shogi { template class Serializer { static QRegExp pattern; public: typedef _LegalityCheck LegalityCheck; typedef typename LegalityCheck::GameState GameState; typedef typename GameState::Board Board; typedef typename Board::Piece Piece; typedef typename GameState::Move Move; protected: QString m_rep; virtual bool isAmbiguous(const Move& move, const GameState& ref) const; virtual QString square(const Point& p, const Point& size) const; virtual QString symbol(const Piece& piece) const; virtual typename Piece::Type getType(const QChar& letter) const; public: Serializer(const QString& rep); virtual ~Serializer(); QString serialize(const Move&, const GameState& ref); Move deserialize(const QString& str, const GameState& ref); Move parse(const QString&, int& offset, int ysize, const GameState& ref); Move parse(const QString&, int ysize, const GameState& ref); }; // IMPLEMENTATION template Serializer::Serializer(const QString& rep) : m_rep(rep) { } template Serializer::~Serializer() { } template bool Serializer::isAmbiguous(const Move& move, const GameState& ref) const { Piece piece = move.drop(); if (piece == Piece()) piece = ref.board().get(move.from()); bool ambiguous = false; if (move.drop() == Piece()) { for (int i = 0; i < ref.board().size().x; i++) { for (int j = 0; j < ref.board().size().x; j++) { Point p(i, j); if (p == move.from() || ref.board().get(p) != piece) continue; Move mv(p, move.to()); LegalityCheck check(ref); if (check.legal(mv)) { ambiguous = true; break; } } } } return ambiguous; } template QString Serializer::square(const Point& p, const Point& size) const { QString res = QString::number(size.x - p.x); if (m_rep == "decorated") { res += "{num_" + QString::number(p.y + 1) + "}"; } else { res += QString(p.y + 'a'); } return res; } template QString Serializer::serialize(const Move& move, const GameState& ref) { Piece piece = move.drop(); if (piece == Piece()) piece = ref.board().get(move.from()); QString res; if (m_rep == "simple") { if (move.drop() != Piece()) { res += symbol(piece); res += '*'; } else res += square(move.from(), ref.board().size()); res += square(move.to(), ref.board().size()); if (move.promoteTo() != -1) res += "+"; return res; } else { bool ambiguous = isAmbiguous(move, ref); QString res; if (piece.promoted()) res += "+"; res += symbol(piece); if (ambiguous) { res += square(move.from(), ref.board().size()); } if (move.drop() != Piece()) res += "*"; else if (ref.board().get(move.to()) != Piece()) res += "x"; else res += "-"; res += square(move.to(), ref.board().size()); // if it is a promotion if (move.promoteTo() != -1) res += "+"; // if it is a refused promotion else if (ref.canPromote(piece) && move.drop() == Piece() && ref.promotionZone(ref.turn(), move.to())) { res += "="; } return res; } } template QString Serializer::symbol(const Piece& piece) const { if (m_rep == "decorated") { QString res = "{"; if (piece.promoted()) res += "p_"; res += piece.typeName(); if (piece.type() == Piece::KING) res += piece.color() == Piece::BLACK ? '1' : '2'; return res + "}"; } else { if (piece.type() == Piece::KNIGHT) return "N"; else return piece.typeName()[0].toUpper(); } } template typename Serializer::Piece::Type Serializer::getType(const QChar& letter) const { switch(letter.toLower().toAscii()) { case 'p': return Piece::PAWN; case 'r': return Piece::ROOK; case 'b': return Piece::BISHOP; case 'l': return Piece::LANCE; case 'n': return Piece::KNIGHT; case 's': return Piece::SILVER; case 'g': return Piece::GOLD; case 'k': return Piece::KING; default: return Piece::INVALID_TYPE; } } template QRegExp Serializer:: // 1 2 3 4 5 6 7 pattern("^(([+])?([PRBLNSGK]))?((\\d*)([a-wyzA-Z])?)([-x*])?" // 8 9 "(\\d+[a-zA-Z])?([+=])?[\?!]*"); template typename Serializer::Move Serializer::parse(const QString& str, int& offset, int ysize, const GameState& ref) { if (pattern.indexIn(str, offset, QRegExp::CaretAtOffset) != -1) { Point from; typename Serializer::Piece::Type type; bool promoted; int promotion; Move candidate; type = getType(pattern.cap(3)[0]); promoted = pattern.cap(2) == "+"; Point to(ref.board().size().x - pattern.cap(8)[0].digitValue(), pattern.cap(8)[1].toAscii() - 'a'); promotion = (pattern.cap(9) == "+") ? 1 : -1; if (pattern.cap(7) == "*") // is a drop ? return Move(Piece(ref.turn(), type), to); from = Point((pattern.cap(5).length() == 0) ? -1 : ref.board().size().x - pattern.cap(5)[0].digitValue(), (pattern.cap(6).length() == 0) ? -1 : pattern.cap(6)[0].toAscii() - 'a'); if (from.valid()) { // explicit from ? candidate = Move(from, to, static_cast(promotion)); } else { // resolve implicit from for (int i = 0; i < ref.board().size().x; i++) { for (int j = 0; j < ref.board().size().y; j++) { Point p(i, j); Piece piece = ref.board().get(p); Move mv(p, to, static_cast(promotion)); if (p.resembles(from) && piece.type() == type && piece.promoted() == promoted && piece.color() == ref.turn()) { LegalityCheck check(ref); if (check.legal(mv)) { if (candidate.valid()) { // ambiguous! kDebug() << "ambiguous"; return Move(); } else { // ok, we have found a candidate move candidate = mv; } } } } } } if (!candidate.valid()) kError() << "Piece not found"; offset += pattern.matchedLength(); return candidate; } else { kDebug() << "error!!!! " << qPrintable(str.mid(offset)); return Move(Point::invalid(),Point::invalid()); } } template typename Serializer::Move Serializer::parse(const QString& str, int ysize, const GameState& ref) { int offset = 0; return parse(str, offset, ysize, ref); } template typename Serializer::Move Serializer::deserialize(const QString& str, const GameState& ref) { if (str[0].isDigit()) { // this is a move Point orig(ref.board().size().x - str[0].digitValue(), str[1].toAscii() - 'a'); Point dest(ref.board().size().x - str[2].digitValue(), str[3].toAscii() - 'a'); return Move(orig, dest, ((str.size() > 4) && (str[4] == '+')) ? 1 : -1); } else return parse(str, ref.board().size().y, ref); } } // namespace Shogi } // namespace HLVariant #endif // HLVARIANT__SHOGI__SERIALIZER_H tagua-1.0-alpha2/src/hlvariant/shogi/shogiactions.cpp000066400000000000000000000016731077523320400227200ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "shogiactions.h" #include #include namespace HLVariant { namespace Shogi { ShogiActions::ShogiActions() : m_promotion(true) { QAction* toggle = new KAction(KIcon("games-solve"), "Promote automatically", this); toggle->setCheckable(true); toggle->setChecked(true); connect(toggle, SIGNAL(triggered()), this, SLOT(toggle_promotion())); add(toggle); } bool ShogiActions::promotion() const { return m_promotion; } void ShogiActions::toggle_promotion() { m_promotion = !m_promotion; } } // namespace Shogi } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/shogi/shogiactions.h000066400000000000000000000014461077523320400223630ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__SHOGI__SHOGIACTIONS_H #define HLVARIANT__SHOGI__SHOGIACTIONS_H #include "actioncollection.h" namespace HLVariant { namespace Shogi { class ShogiActions : public ActionCollection { Q_OBJECT bool m_promotion; public: ShogiActions(); bool promotion() const; private Q_SLOTS: void toggle_promotion(); }; } // namespace Shogi } // namespace HLVariant #endif // HLVARIANT__SHOGI__SHOGIACTIONS_H tagua-1.0-alpha2/src/hlvariant/shogi/shogiban.h000066400000000000000000000027271077523320400214660ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__SHOGI__SHOGIBAN_H #define HLVARIANT__SHOGI__SHOGIBAN_H #include "../customboard.h" namespace HLVariant { namespace Shogi { template class ShogiBan : public CustomBoard { public: typedef _Piece Piece; typedef CustomBoard Base; QStringList borderCoords() const; }; // IMPLEMENTATION template QStringList ShogiBan::borderCoords() const { QStringList retv; for (int i = this->size().y; i > 0; i--) retv += QString::number(i); switch (this->size().x) { default: case 9: retv << QChar(0x4e5d); case 8: retv << QChar(0x516b); case 7: retv << QChar(0x4e03); case 6: retv << QChar(0x516d); case 5: retv << QChar(0x4e94); case 4: retv << QChar(0x56db); case 3: retv << QChar(0x4e09); case 2: retv << QChar(0x4e8c); case 1: retv << QChar(0x4e00); } return retv + retv; } } // namespace Shogi } // namespace HLVariant #endif // HLVARIANT__SHOGI__SHOGIBAN_H tagua-1.0-alpha2/src/hlvariant/shogi/variant.cpp000066400000000000000000000014431077523320400216650ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "variant.h" #include "../tagua_wrapped.h" namespace HLVariant { namespace Shogi { const char* Variant::m_name = "Shogi"; const char* Variant::m_theme_proxy = "Shogi"; void Variant::setupMove(NormalUserMove& m) const { m.promotionType = m_actions.promotion() ? 0 : -1; } ActionCollection* Variant::actions() { return &m_actions; } DEFINE_VARIANT_FACTORY(); } // namespace Shogi } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/shogi/variant.h000066400000000000000000000032521077523320400213320ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__SHOGI__VARIANT_H #define HLVARIANT__SHOGI__VARIANT_H #include "piece.h" #include "shogiban.h" #include "../chess/move.h" #include "../crazyhouse/move.h" #include "gamestate.h" #include "legalitycheck.h" #include "serializer.h" #include "../crazyhouse/movefactory.h" #include "../animator.h" #include "../dropanimator.h" #include "shogiactions.h" namespace HLVariant { namespace Shogi { struct TAGUA_EXPORT Variant { typedef Crazyhouse::MoveMixin Move; typedef GameState, Move> GameState; typedef LegalityCheck LegalityCheck; typedef Serializer Serializer; typedef DropAnimatorMixin > Animator; typedef Crazyhouse::MoveFactory MoveFactory; typedef Variant MoveGenerator; // to make VariantData happy static const bool hasICS = false; static const bool m_simple_moves = false; static const bool m_hidden = false; static const char *m_name; static const char *m_theme_proxy; static int moveListLayout() { return 0; } OptList positionOptions() const { return OptList(); } void setupMove(NormalUserMove& m) const; ActionCollection* actions(); private: ShogiActions m_actions; }; } // namespace Shogi } // namespace HLVariant #endif // HLVARIANT__SHOGI__VARIANT_H tagua-1.0-alpha2/src/hlvariant/tagua_wrapped.h000066400000000000000000000353721077523320400214100ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__TAGUA_WRAPPED_H #define HLVARIANT__TAGUA_WRAPPED_H #include "tagua.h" #include "fwd.h" #include "movefactory.h" #include "nopool.h" #include "variantdata.h" #ifdef Q_CC_GNU #define __FUNC__ __PRETTY_FUNCTION__ #else #define __FUNC__ __FUNCTION__ #endif #define MISMATCH(x,y) (kDebug() << " --> Error in "<<__FUNC__<<", MISMATCH!" \ << " got type " << prettyTypeName(typeid(x).name()) \ << " instead of " << prettyTypeName(typeid(y).name()) \ << " this is " << prettyTypeName(typeid(*this).name()) ) #define DEFINE_VARIANT_FACTORY() \ VariantFactory* createFactory() { \ return new WrappedVariantFactory; \ } namespace HLVariant { template class WrappedPosition; template class WrappedPiece : public AbstractPiece { typedef typename VariantData::Piece Piece; Piece m_piece; public: const Piece& inner() const { return m_piece; } WrappedPiece(const Piece& piece) : m_piece(piece) { } virtual bool equals(const PiecePtr& _other) const { if (!_other) return false; WrappedPiece* other = dynamic_cast*>(_other.get()); if (other) return m_piece == other->inner(); else { MISMATCH(*_other.get(),WrappedPiece); return false; } } virtual QString name() const { return m_piece.name(); } virtual PiecePtr clone() const { return PiecePtr(new WrappedPiece(m_piece)); } }; template class WrappedPool : public AbstractPool { typedef typename VariantData::Pool Pool; typedef typename VariantData::Piece Piece; Pool& m_pool; public: WrappedPool(Pool& pool) : m_pool(pool) { } WrappedPool(const Pool& pool) : m_pool(const_cast(pool)) { // FIXME: const_cast is not necessary, here, but to avoid it // we would need to change the API, adding for example an // AbstractConstPool with only const functions and changing the // wrapper accordingly. } virtual int size() { return m_pool.size(); } virtual int insert(int pref_index, const PiecePtr& _piece) { if (!_piece) { return m_pool.insert(pref_index, Piece()); } else { WrappedPiece* piece = dynamic_cast*>(_piece.get()); if (piece) return m_pool.insert(pref_index, Piece(piece->inner()) ); else { MISMATCH(*_piece.get(), WrappedPiece); return -1; } } } virtual PiecePtr get(int index) { Piece piece = m_pool.get(index); if (piece != Piece()) return PiecePtr(new WrappedPiece(piece)); else return PiecePtr(); } virtual PiecePtr take(int index) { Piece piece = m_pool.take(index); if (piece != Piece()) return PiecePtr(new WrappedPiece(piece)); else return PiecePtr(); } }; template class WrappedMove : public AbstractMove { typedef typename VariantData::LegalityCheck LegalityCheck; typedef typename VariantData::Serializer Serializer; typedef typename VariantData::Move Move; typedef typename VariantData::GameState GameState; Move m_move; public: const Move& inner() const { return m_move; } Move& inner() { return m_move; } WrappedMove(const Move& move) : m_move(move) { } virtual QString toString(const QString& rep, const PositionPtr& _ref) const { WrappedPosition* ref = dynamic_cast*>(_ref.get()); if (ref) { Serializer serializer(rep); return serializer.serialize(m_move, ref->inner()); } else { MISMATCH(*_ref.get(), WrappedPosition); return "$@%"; } } virtual NormalUserMove toUserMove() const { typename VariantData::MoveFactory factory; return factory.toNormal(m_move); } virtual bool equals(const MovePtr& _other) const { WrappedMove* other = dynamic_cast*>(_other.get()); if (other) return m_move == other->inner(); else { MISMATCH(*_other.get(), WrappedMove); return false; } } }; /** * Metafunction that returns a null pointer when * its template argument is NoPool. */ template struct ReturnPoolAux { static PoolPtr apply(typename VariantData::GameState& state, int player) { return PoolPtr(new WrappedPool(state.pools().pool( static_cast::Piece::Color>(player)))); } }; template struct ReturnPoolAux { static PoolPtr apply(typename VariantData::GameState&, int) { return PoolPtr(); } }; template struct ReturnPool { static PoolPtr apply(typename VariantData::GameState& state, int player) { return ReturnPoolAux::Pool>::apply(state, player); } }; template class WrappedPosition : public AbstractPosition { typedef typename VariantData::LegalityCheck LegalityCheck; typedef typename VariantData::GameState GameState; typedef typename VariantData::Board Board; typedef typename VariantData::Piece Piece; typedef typename VariantData::Move Move; typedef typename VariantData::Serializer Serializer; GameState m_state; public: const GameState& inner() const { return m_state; } GameState& inner() { return m_state; } WrappedPosition(const GameState& state) : m_state(state) { } virtual Point size() const { return m_state.board().size(); } virtual QStringList borderCoords() const { return m_state.board().borderCoords(); } virtual void setup() { m_state.setup(); } virtual PiecePtr get(const Point& p) const { Piece piece = m_state.board().get(p); if (piece != Piece()) return PiecePtr(new WrappedPiece(piece)); else return PiecePtr(); } virtual void set(const Point& p, const PiecePtr& _piece) { if (!_piece) { m_state.board().set(p, Piece()); } else { WrappedPiece* piece = dynamic_cast*>(_piece.get()); if (piece) m_state.board().set(p, piece->inner()); else MISMATCH(*_piece.get(), WrappedPiece); } } virtual PoolPtr pool(int player) { return ReturnPool::apply(m_state, player); } virtual void copyPoolFrom(const PositionPtr&) { // BROKEN } virtual InteractionType movable(const TurnTest& test, const Point& p) const { LegalityCheck check(m_state); return check.movable(test, p); } virtual InteractionType droppable(const TurnTest& test, int index) const { LegalityCheck check(m_state); return check.droppable(test, index); } virtual int turn() const { return static_cast(m_state.turn()); } virtual void setTurn(int turn) { m_state.setTurn(static_cast(turn)); } virtual int previousTurn() const { return static_cast(m_state.previousTurn()); } virtual void switchTurn() { m_state.switchTurn(); } virtual bool testMove(const MovePtr& _move) const { if (!_move) return false; WrappedMove* move = dynamic_cast*>(_move.get()); if (move) { LegalityCheck check(m_state); return check.legal(move->inner()); } else { MISMATCH(*_move.get(), WrappedMove); return false; } } virtual void move(const MovePtr& _move) { if (!_move) return; WrappedMove* move = dynamic_cast*>(_move.get()); if (move) m_state.move(move->inner()); else MISMATCH(*_move.get(), WrappedMove); } virtual PositionPtr clone() const { return PositionPtr(new WrappedPosition(m_state)); } virtual void copyFrom(const PositionPtr& _p) { // TODO: check if this is used somewhere WrappedPosition* p = dynamic_cast*>(_p.get()); if (p) m_state = p->inner(); else MISMATCH(*_p.get(), WrappedPosition); } virtual bool equals(const PositionPtr& _other) const { WrappedPosition* other = dynamic_cast*>(_other.get()); if (other) return m_state == other->inner(); else { MISMATCH(*_other.get(), WrappedPosition); return false; } } virtual MovePtr getMove(const QString& san) const { Serializer serializer("compact"); Move res = serializer.deserialize(san, m_state); if (res.valid()) { return MovePtr(new WrappedMove(res)); } else return MovePtr(); } virtual QString state() const { return ""; // BROKEN } virtual PiecePtr moveHint(const MovePtr&) const { return PiecePtr(); // BROKEN } virtual QString variant() const { return Variant::m_name; } virtual void dump() const { // BROKEN } }; } #include "graphicalapi_unwrapped.h" #include "icsapi_wrapped.h" namespace HLVariant { template class WrappedAnimator : public AbstractAnimator { typedef typename VariantData::GameState GameState; typedef typename VariantData::Animator Animator; typedef typename VariantData::Move Move; Animator m_animator; public: const Animator& inner() const { return m_animator; } WrappedAnimator(const Animator& animator) : m_animator(animator) { } virtual AnimationPtr warp(const PositionPtr& _pos) { WrappedPosition* pos = dynamic_cast*>(_pos.get()); if (pos) return m_animator.warp(pos->inner()); else { MISMATCH(*_pos.get(), WrappedPosition); return AnimationPtr(); } } virtual AnimationPtr forward(const PositionPtr& _pos, const MovePtr& _move) { WrappedPosition* pos = dynamic_cast*>(_pos.get()); WrappedMove* move = dynamic_cast*>(_move.get()); if (move && pos) return m_animator.forward(pos->inner(), move->inner()); else { if (!move) MISMATCH(*_move.get(), WrappedMove); if (!pos) MISMATCH(*_pos.get(), WrappedPosition); return AnimationPtr(); } } virtual AnimationPtr back(const PositionPtr& _pos, const MovePtr& _move) { WrappedPosition* pos = dynamic_cast*>(_pos.get()); WrappedMove* move = dynamic_cast*>(_move.get()); if (move && pos) return m_animator.back(pos->inner(), move->inner()); else { if (!move) MISMATCH(*_move.get(), WrappedMove); if (!pos) MISMATCH(*_pos.get(), WrappedPosition); return AnimationPtr(); } } }; template class WrappedVariantInfo : public VariantInfo { typedef typename VariantData::Animator Animator; typedef typename VariantData::GameState GameState; typedef typename VariantData::Piece Piece; typedef typename VariantData::Move Move; // typedef typename VariantData::Pool Pool; Variant m_variant; public: virtual PositionPtr createPosition() { return PositionPtr( new WrappedPosition(GameState())); } virtual PositionPtr createCustomPosition(const OptList&) { return PositionPtr( new WrappedPosition(GameState())); // BROKEN } virtual void forallPieces(class PieceFunction&) { // BROKEN } virtual int moveListLayout() const { return Variant::moveListLayout(); } virtual AnimatorPtr createAnimator(GraphicalAPI* graphical_api) { return AnimatorPtr(new WrappedAnimator( Animator( typename UnwrappedGraphicalAPIPtr::type( new UnwrappedGraphicalAPI(graphical_api))))); } virtual MovePtr createNormalMove(const NormalUserMove& move) { typename VariantData::MoveFactory factory; Move m = factory.createNormalMove(move); return MovePtr(new WrappedMove(m)); } virtual MovePtr createDropMove(const DropUserMove& move) { typename VariantData::MoveFactory factory; Move m = factory.createDropMove(move); return MovePtr(new WrappedMove(m)); } virtual MovePtr getVerboseMove(int, const VerboseNotation&) const { return MovePtr(); } virtual bool simpleMoves() { return Variant::m_simple_moves; } virtual QString name() const { return Variant::m_name; } virtual QString themeProxy() const { return Variant::m_theme_proxy; } virtual OptList positionOptions() const { return m_variant.positionOptions(); } virtual ICSAPIPtr icsAPI() const { return ICSAPIPtr(ReturnICSAPI::apply()); } virtual ActionCollection* actions() { return m_variant.actions(); } virtual void setupMove(NormalUserMove& m) const { m_variant.setupMove(m); } }; template class WrappedVariantFactory : public VariantFactory { public: virtual VariantInfo* createVariant() const { return new WrappedVariantInfo; } virtual QString name() const { return Variant::m_name; } virtual QString themeProxy() const { return Variant::m_theme_proxy; } virtual bool hidden() const { return Variant::m_hidden; } }; } #endif // HLVARIANT__TAGUA_WRAPPED_H tagua-1.0-alpha2/src/hlvariant/tori-shogi/000077500000000000000000000000001077523320400204665ustar00rootroot00000000000000tagua-1.0-alpha2/src/hlvariant/tori-shogi/gamestate.h000066400000000000000000000051171077523320400226150ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge (c) 2007 Yann Dirson 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. */ #ifndef HLVARIANT__TORI_SHOGI__GAMESTATE_H #define HLVARIANT__TORI_SHOGI__GAMESTATE_H #include "../shogi/gamestate.h" #include "piece.h" namespace HLVariant { namespace ToriShogi { template class GameState: public Shogi::GameState<_Board, _Move> { public: virtual void setup(); virtual bool promotionZone(typename Piece::Color player, const Point& p) const; virtual bool canPromote(const Piece& p) const; }; // IMPLEMENTATION #define MS_COL(i, c) c == Piece::BLACK ? (i) : \ (Shogi::GameState::board().size().x - i - 1) #define MS_ROW(i, c) rank + i * Shogi::GameState::direction(color).y #define MS_PIECE(x,y,p) Shogi::GameState::board().set(Point(MS_COL(x, c), MS_ROW(y, c)), \ Piece(color, p)) template void GameState::setup() { for (int c = 0; c < 2; c++) { typename Piece::Color color = static_cast(c); int rank = Shogi::GameState::startingRank(color); MS_PIECE(0, 0, ToriShogi::Piece::LEFT_QUAIL); MS_PIECE(1, 0, ToriShogi::Piece::PHEASANT); MS_PIECE(2, 0, ToriShogi::Piece::CRANE); MS_PIECE(3, 0, ToriShogi::Piece::PHOENIX); MS_PIECE(4, 0, ToriShogi::Piece::CRANE); MS_PIECE(5, 0, ToriShogi::Piece::PHEASANT); MS_PIECE(6, 0, ToriShogi::Piece::RIGHT_QUAIL); MS_PIECE(3, 1, ToriShogi::Piece::FALCON); for (int i = 0; i < Shogi::GameState::board().size().x; i++) { MS_PIECE(i, 2, ToriShogi::Piece::SWALLOW); } MS_PIECE(4, 3, ToriShogi::Piece::SWALLOW); } } #undef MS_PIECE #undef MS_ROW #undef MS_COL template bool GameState::promotionZone(typename Piece::Color player, const Point& p) const { return player == Piece::WHITE ? p.y >= 5 : p.y <= 1; } template bool GameState::canPromote(const Piece& p) const { if (p.promoted()) return false; if ((p.type() == Piece::SWALLOW) || (p.type() == Piece::FALCON)) return true; else return false; } } // namespace MiniShogi } // namespace HLVariant #endif // HLVARIANT__TORI_SHOGI__GAMESTATE_H tagua-1.0-alpha2/src/hlvariant/tori-shogi/legalitycheck.h000066400000000000000000000150701077523320400234520ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge (c) 2007 Yann Dirson 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. */ #ifndef HLVARIANT__TORISHOGI__LEGALITYCHECK_H #define HLVARIANT__TORISHOGI__LEGALITYCHECK_H #include "interactiontype.h" #include "../shogi/legalitycheck.h" namespace HLVariant { namespace ToriShogi { template class LegalityCheck: public Shogi::LegalityCheck<_GameState> { typedef Shogi::LegalityCheck<_GameState> Base; public: typedef _GameState GameState; typedef typename GameState::Board Board; typedef typename Board::Piece Piece; typedef typename GameState::Move Move; LegalityCheck(const GameState& state); virtual bool getMoveType(const Piece& piece, const Move& move) const; bool legal(Move& move) const; bool pseudolegal(Move& move) const; bool canBeCaptured(const GameState& state, const Point& point) const; protected: virtual bool stuckPiece(const Piece& piece, const Point& p) const; }; // IMPLEMENTATION template LegalityCheck::LegalityCheck(const GameState& state) : Base(state) { } template bool LegalityCheck::getMoveType(const Piece& piece, const Move& move) const { if (!move.valid()) return false; if (move.from() == move.to()) return false; if (Base::m_state.board().get(move.to()).color() == piece.color()) return false; Point delta = move.to() - move.from(); if (!piece.promoted()) { switch (piece.type()) { case Piece::PHOENIX: return abs(delta.x) <= 1 && abs(delta.y) <= 1; case Piece::FALCON: return (abs(delta.x) == 1 && abs(delta.y) <= 1) || (delta.x == 0 && delta.y == Base::m_state.direction(piece.color()).y); case Piece::CRANE: return (abs(delta.y) == 1 && abs(delta.x) <= 1); case Piece::PHEASANT: return (delta.x == 0 && delta.y == 2 * Base::m_state.direction(piece.color()).y) || (abs(delta.x) == 1 && delta.y == -Base::m_state.direction(piece.color()).y); case Piece::SWALLOW: return delta == Base::m_state.direction(piece.color()); case Piece::RIGHT_QUAIL: { if (delta.x == 1 && delta.y == -Base::m_state.direction(piece.color()).y) return true; PathInfo path = Base::m_state.board().path(move.from(), move.to()); return ((path.parallel() && delta.y * Base::m_state.direction(piece.color()).y > 0) || (path.diagonal() && delta.y * Base::m_state.direction(piece.color()).y < 0 && delta.x < 0)) && path.clear(); } case Piece::LEFT_QUAIL: { if (delta.x == -1 && delta.y == -Base::m_state.direction(piece.color()).y) return true; PathInfo path = Base::m_state.board().path(move.from(), move.to()); return ((path.parallel() && delta.y * Base::m_state.direction(piece.color()).y > 0) || (path.diagonal() && delta.y * Base::m_state.direction(piece.color()).y < 0 && delta.x > 0)) && path.clear(); } default: return false; } } else { switch (piece.type()) { case Piece::SWALLOW: // Goose return (delta.x == 0 && delta.y == -2 * Base::m_state.direction(piece.color()).y) || (abs(delta.x) == 2 && delta.y == 2 * Base::m_state.direction(piece.color()).y); case Piece::FALCON: // Eagle { if (abs(delta.x) <= 1 && abs(delta.y) <= 1) return true; PathInfo path = Base::m_state.board().path(move.from(), move.to()); return ((path.parallel() && delta.y * Base::m_state.direction(piece.color()).y < 0) || (path.diagonal() && delta.y * Base::m_state.direction(piece.color()).y > 0) || (path.diagonal() && delta.y * Base::m_state.direction(piece.color()).y == -2)) && path.clear(); } default: return false; } } } template bool LegalityCheck::pseudolegal(Move& move) const { if (move.drop() == Piece() && move.pool() != -1 && move.index() != -1) { move.setDrop(Base::m_state.pools().pool(move.pool()).get(move.index())); } Piece dropped = move.drop(); if (dropped != Piece()) { if (Base::m_state.board().get(move.to()) != Piece()) return false; if (stuckPiece(dropped, move.to())) return false; if (dropped.type() == Piece::SWALLOW) { int otherswallows = 0; for (int i = 0; i < Base::m_state.board().size().y; i++) { Piece other = Base::m_state.board().get(Point(move.to().x, i)); if (other.type() == Piece::SWALLOW && other.color() == Base::m_state.turn() && !other.promoted()) { otherswallows++; if (otherswallows >= 2) return false; } } } return true; } else { Piece piece = Base::m_state.board().get(move.from()); if (piece != Piece() && getMoveType(piece, move)) { if (Base::m_state.canPromote(piece) && (Base::m_state.promotionZone(piece.color(), move.to()) || Base::m_state.promotionZone(piece.color(), move.from()))) move.setType(Move::PROMOTION); return true; } else { return false; } } } // strict copy from Shogi, for template-instantation reasons template bool LegalityCheck::canBeCaptured(const GameState& state, const Point& point) const { for (int i = 0; i < state.board().size().x; i++) { for (int j = 0; j < state.board().size().y; j++) { Point p(i, j); Piece piece = state.board().get(p); LegalityCheck check(state); if (piece.color() == state.turn() && check.getMoveType(piece, Move(p, point))) { return true; } } } return false; } template bool LegalityCheck::legal(Move& move) const { if (!pseudolegal(move)) return false; GameState tmp(Base::m_state); tmp.move(move); // find king position Point king_pos = tmp.board().find(Piece(Base::m_state.turn(), Piece::PHOENIX)); if (!king_pos.valid()) return false; // check if the king can be captured if (canBeCaptured(tmp, king_pos)) return false; return true; } template bool LegalityCheck::stuckPiece(const Piece& piece, const Point& p) const { if (piece.type() == Piece::SWALLOW) { return p.y == Base::m_state.startingRank(Piece::oppositeColor(piece.color())); } else { return false; } } } // namespace ToriShogi } // namespace HLVariant #endif // HLVARIANT__TORISHOGI__LEGALITYCHECK_H tagua-1.0-alpha2/src/hlvariant/tori-shogi/piece.cpp000066400000000000000000000040411077523320400222560ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge (c) 2007 Yann Dirson 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. */ #include "piece.h" namespace HLVariant { namespace ToriShogi { Piece::Piece(Color color, Type type, bool promoted) : m_color(color) , m_type(type) , m_promoted(promoted) { } Piece::~Piece() { } void Piece::setPromoted() { m_promoted = true; } bool Piece::promoted() const { return m_promoted; } Piece::Color Piece::color() const { return m_color; } Piece::Type Piece::type() const { return m_type; } QString Piece::colorName() const { return colorName(m_color); } QString Piece::colorName(Color color) { switch (color) { case WHITE: return "white"; case BLACK: return "black"; default: return "unknown"; } } QString Piece::typeName() const { return typeName(m_type); } QString Piece::typeName(Type type) { switch (type) { case PHOENIX: return "phoenix"; case FALCON: return "falcon"; case CRANE: return "crane"; case PHEASANT: return "pheasant"; case LEFT_QUAIL: return "left_quail"; case RIGHT_QUAIL: return "right_quail"; case SWALLOW: return "swallow"; default: return "unknown"; } } QString Piece::name() const { QString res = colorName() + '_'; if (m_promoted) res += "p_"; return res + typeName(); } Piece::Color Piece::oppositeColor(Color color) { return (color == WHITE) ? BLACK : (color == BLACK) ? WHITE : INVALID_COLOR; } bool Piece::operator==(const Piece& other) const { return m_color == other.m_color && m_type == other.m_type && m_promoted == other.m_promoted; } bool Piece::operator!=(const Piece& other) const { return !((*this) == other); } } // namespace ToriShogi } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/tori-shogi/piece.h000066400000000000000000000033331077523320400217260ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge (c) 2007 Yann Dirson 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. */ #ifndef HLVARIANT__TORI_SHOGI__PIECE_H #define HLVARIANT__TORI_SHOGI__PIECE_H #include #include "export.h" #include "../shogi/piece.h" namespace HLVariant { namespace ToriShogi { class TAGUA_EXPORT Piece { public: enum Color { INVALID_COLOR = -1, BLACK, WHITE }; enum Type { PHOENIX, FALCON, CRANE, PHEASANT, LEFT_QUAIL, RIGHT_QUAIL, SWALLOW, // FIXME: stub names to wait for Piece refactoring KING, GOLD, SILVER, KNIGHT, LANCE, ROOK, BISHOP, PAWN, DRUNKEN_ELEPHANT, INVALID_TYPE = -1 }; private: Color m_color; Type m_type; bool m_promoted; public: Piece(Color color = INVALID_COLOR, Type type = INVALID_TYPE, bool promoted = false); virtual ~Piece(); virtual Color color() const; virtual Type type() const; virtual QString colorName() const; static QString colorName(Color color); virtual QString typeName() const; static QString typeName(Type type); virtual QString name() const; static Color oppositeColor(Color color); virtual bool operator==(const Piece& other) const; virtual bool operator!=(const Piece& other) const; void setPromoted(); bool promoted() const; }; } // namespace ToriShogi } // namespace HLVariant #endif // HLVARIANT__TORI_SHOGI__PIECE_H tagua-1.0-alpha2/src/hlvariant/tori-shogi/serializer.h000066400000000000000000000036651077523320400230220ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANT__TORI_SHOGI__SERIALIZER_H #define HLVARIANT__TORI_SHOGI__SERIALIZER_H #include "../shogi/serializer.h" #include "piece.h" // FIXME: // - needs a deserializer and getType() API able to deal with 2-char type namespace HLVariant { namespace ToriShogi { template class Serializer: public HLVariant::Shogi::Serializer<_LegalityCheck> { public: typedef HLVariant::Shogi::Serializer<_LegalityCheck> Base; typedef _LegalityCheck LegalityCheck; typedef typename LegalityCheck::GameState GameState; typedef typename GameState::Board Board; typedef typename Board::Piece Piece; Serializer(const QString& rep); protected: virtual QString symbol(const Piece& piece) const; }; template Serializer::Serializer(const QString& rep) : Base(rep) { } template QString Serializer::symbol(const Piece& piece) const { if (Base::m_rep == "decorated") { QString res = "{"; if (piece.promoted()) res += "p_"; res += piece.typeName(); return res + "}"; } else { switch (piece.type()) { case Piece::PHOENIX: return "Ph"; case Piece::FALCON: return "Fa"; case Piece::CRANE: return "Cr"; case Piece::PHEASANT: return "Pt"; case Piece::LEFT_QUAIL: return "LQ"; case Piece::RIGHT_QUAIL: return "RQ"; case Piece::SWALLOW: return "Sw"; default: return "??"; } } } } // namespace ToriShogi } // namespace HLVariant #endif // HLVARIANT__TORI_SHOGI__SERIALIZER_H tagua-1.0-alpha2/src/hlvariant/tori-shogi/variant.cpp000066400000000000000000000014641077523320400226430ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "variant.h" #include "../tagua_wrapped.h" namespace HLVariant { namespace ToriShogi { const char* Variant::m_name = "Tori Shogi"; const char* Variant::m_theme_proxy = "ToriShogi"; void Variant::setupMove(NormalUserMove& m) const { m.promotionType = m_actions.promotion() ? 0 : -1; } ActionCollection* Variant::actions() { return &m_actions; } DEFINE_VARIANT_FACTORY(); } // namespace ToriShogi } // namespace HLVariant tagua-1.0-alpha2/src/hlvariant/tori-shogi/variant.h000066400000000000000000000034211077523320400223030ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge (c) 2007 Yann Dirson 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. */ #ifndef HLVARIANT__TORI_SHOGI__VARIANT_H #define HLVARIANT__TORI_SHOGI__VARIANT_H #include "piece.h" #include "../shogi/shogiban.h" #include "../chess/move.h" #include "../crazyhouse/move.h" #include "gamestate.h" #include "legalitycheck.h" #include "serializer.h" #include "../crazyhouse/movefactory.h" #include "../animator.h" #include "../dropanimator.h" #include "../shogi/shogiactions.h" namespace HLVariant { namespace ToriShogi { struct TAGUA_EXPORT Variant { typedef Crazyhouse::MoveMixin Move; typedef GameState, Move> GameState; typedef LegalityCheck LegalityCheck; typedef Serializer Serializer; typedef DropAnimatorMixin > Animator; typedef Crazyhouse::MoveFactory MoveFactory; typedef Variant MoveGenerator; // to make VariantData happy static const bool hasICS = false; static const bool m_simple_moves = false; static const bool m_hidden = false; static const char *m_name; static const char *m_theme_proxy; static int moveListLayout() { return 0; } OptList positionOptions() const { return OptList(); } void setupMove(NormalUserMove& m) const; ActionCollection* actions(); private: Shogi::ShogiActions m_actions; }; } // namespace Shogi } // namespace HLVariant #endif // HLVARIANT__TORI_SHOGI__VARIANT_H tagua-1.0-alpha2/src/hlvariant/variantdata.h000066400000000000000000000020111077523320400210430ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef HLVARIANTS__VARIANTDATA_H #define HLVARIANTS__VARIANTDATA_H template struct VariantData { typedef typename Variant::MoveGenerator MoveGenerator; typedef typename MoveGenerator::LegalityCheck LegalityCheck; typedef typename LegalityCheck::GameState GameState; typedef typename GameState::Board Board; typedef typename GameState::Pool Pool; typedef typename GameState::Move Move; typedef typename Board::Piece Piece; typedef typename Variant::Animator Animator; typedef typename Variant::Serializer Serializer; typedef typename Variant::MoveFactory MoveFactory; }; #endif // HLVARIANTS__VARIANTDATA_H tagua-1.0-alpha2/src/icsaction.h000066400000000000000000000015741077523320400165460ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ICSACTION_H #define ICSACTION_H class ICSAction { public: enum Direction { Forward, Back }; private: Direction m_direction; int m_moves; QString m_actor; public: ICSAction(const Direction& direction, int moves, const QString& actor) : m_direction(direction) , m_moves(moves) , m_actor(actor) { } Direction direction() const { return m_direction; } int moves() const { return m_moves; } QString actor() const { return m_actor; } }; #endif // ICSACTION_H tagua-1.0-alpha2/src/icsapi.h000066400000000000000000000041121077523320400160310ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef ICSAPI_H #define ICSAPI_H #include "tagua.h" class ICSAPI { public: virtual ~ICSAPI() { } /** * Create a position using the information of a style12 line. * \param turn Current turn. * \param wkCastle King-side castling is possible for white * \param wqCastle Queen-side castling is possible for white * \param bkCastle King-side castling is possible for black * \param bqCastle Queen-side castling is possible for black * \param ep En-passant square. */ virtual PositionPtr createChessboard( int turn, bool wkCastle, bool wqCastle, bool bkCastle, bool bqCastle, const Point& ep) = 0; /** * Create a new piece using the given description string. * \param description A string representing the piece to be created. Its * meaning is defined by the variant. * \return A newly created piece. */ virtual PiecePtr createPiece(const QString& description) = 0; /** * Parse ICS verbose notation. * \param str A string representation of the move to be parsed. * \param turn The player who is moving. * \return A move object corresponding to the given verbose representation. */ virtual MovePtr parseVerbose(const QString& str, const PositionPtr& ref) = 0; }; // wrapper template class WrappedICSAPI : public ICSAPI { public: virtual PositionPtr createChessboard(int, bool, bool, bool, bool, const Point&); virtual PiecePtr createPiece(const QString& description); virtual MovePtr parseVerbose(const QString&, const PositionPtr&) { return MovePtr(); } }; #endif // ICSAPI_H tagua-1.0-alpha2/src/icsapi.impl.h000066400000000000000000000022501077523320400167720ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ICSAPI_IMPL_H #define ICSAPI_IMPL_H #include "tagua_wrapped.h" #include "piecefactory.h" template PositionPtr WrappedICSAPI::createChessboard( int turn, bool wkCastle, bool wqCastle, bool bkCastle, bool bqCastle, const Point& ep) { return PositionPtr( new WrappedPosition(typename Variant::Position( static_cast(turn), wkCastle, wqCastle, bkCastle, bqCastle, ep))); } template PiecePtr WrappedICSAPI::createPiece(const QString& description) { return AbstractPiece::Ptr(new WrappedPiece( PieceFactory::createPiece(description))); } #endif // ICSAPI_IMPL_H tagua-1.0-alpha2/src/icsconnection.cpp000066400000000000000000000326001077523320400177550ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "icsconnection.h" #include #include #include #include "poolinfo.h" #include "positioninfo.h" #include "player.h" #include "gameinfo.h" #include "pgnparser.h" #include "icslistener.h" #include "variants.h" using namespace boost; QRegExp ICSConnection::pressReturn("^Press return to enter the server as \"\\S+\":"); // example: Creating: azsxdc (++++) Hispanico (1684) unrated crazyhouse 3 0 QRegExp ICSConnection::creating("^Creating: (\\S+)\\s+\\((\\S*)\\)\\s+(\\S+)\\s+\\((\\S*)\\)" "\\s+(\\S+)\\s+(\\S+)\\s+(\\d+)\\s+(\\d+)\\s*.*$"); // example: {Game 149 (azsxdc vs. Hispanico) Creating unrated crazyhouse match.} // example: {Game 149 (azsxdc vs. Hispanico) Game aborted on move 1} * QRegExp ICSConnection::game("^\\{Game\\s+(\\d+)\\s+\\((\\S+)\\s+vs\\.\\s+(\\S+)\\)\\s+" "(\\S+.*)\\}(?:\\s+(\\S+.*)|\\s*)$"); QRegExp ICSConnection::unexamine("^You\\s+are\\s+no\\s+longer\\s+examining\\s+game\\s+(\\d+)"); QRegExp ICSConnection::unobserve("^Removing\\s+game\\s+(\\d+)\\s+from\\s+observation\\s+list\\s*"); // example: 124 848 shanmark 1155 damopn [ br 2 12] 2:04 - 2:08 (39-39) W: 3 //QRegExp ICSConnection::gameInfo("^(\\d+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+" // "\\[\\s+(\\S+)\\s+(\\d+)\\s+(\\d+)\\s+\\]"); // 1 2 3 4 5 6 7 8 9 // example: Game 124: shanmark ( 848) damopn (1155) rated blitz 2 12 // Game 170: AstralVision (2167) vladx (2197) rated standard 15 0 QRegExp ICSConnection::observed_game("^Game\\s+(\\d+):\\s+(\\S+)\\s+\\(\\s*(\\S+)\\s*\\)\\s+" "(\\S+)\\s+\\(\\s*(\\S+)\\s*\\)\\s+" "(\\S+)\\s+(\\S+)\\s+(\\d+)\\s+(\\d+)"); QRegExp ICSConnection::login("^login: $"); QRegExp ICSConnection::password("^password: $"); QRegExp ICSConnection::fics("^\\S+% "); QRegExp ICSConnection::beep("^\a"); //ex: Movelist for game 95: QRegExp ICSConnection::move_list_start("^Movelist\\s+for\\s+game\\s+(\\d+):"); //ex: npssnt (1586) vs. mikkk (1487) --- Sun Sep 3, 18:16 PDT 2006 QRegExp ICSConnection::move_list_players("^(\\S+)\\s+\\((\\S*)\\)\\s+vs.\\s+(\\S+)\\s+\\((\\S*)\\)\\s*.*"); //ex: Unrated blitz match, initial time: 3 minutes, increment: 0 seconds. QRegExp ICSConnection::move_list_game("^(\\S+)\\s+(\\S+)\\s+.*initial\\s+time:\\s*(\\d+)" "\\s+.*increment:\\s*(\\d+)\\s*.*"); //ex: Move npssnt mikkk QRegExp ICSConnection::move_list_ignore1("^Move\\s+(\\S+)\\s+(\\S+)"); //ex: ---- ---------------- ---------------- QRegExp ICSConnection::move_list_ignore2("^( +|-+)+"); QRegExp ICSConnection::move_list_terminator("^\\s*$"); QRegExp ICSConnection::goForward("^Game (\\d+): (\\S+) goes forward (\\d+) moves?\\."); QRegExp ICSConnection::goBack("^Game (\\d+): (\\S+) backs up (\\d+) moves?\\."); ICSConnection::ICSConnection() : incomingGameInfo(0) , m_move_list_game_info(NULL) , m_move_list_position_info(NULL) , m_move_list_pool_info(NULL) { state = Normal; connect(this, SIGNAL(receivedLine(QString, int)), this, SLOT(process(QString))); connect(this, SIGNAL(receivedText(QString, int)), this, SLOT(processPartialLine(QString))); } bool ICSConnection::test(const QRegExp& pattern, const QString& str) { if (pattern.indexIn(str, m_processed_offset, QRegExp::CaretAtOffset) >= 0) { m_processed_offset = pattern.matchedLength(); return true; } else return false; } void ICSConnection::processPartialLine(QString str) { // kDebug() << "processing (partial) " << str; if (test(fics, str)) { // kDebug() << "matched prompt"; prompt(); } else if (test(beep, str)) { notification(); } else if (test(pressReturn, str)) { registeredNickname(); } else if (test(login, str)) { loginPrompt(); } else if (test(password, str)) { passwordPrompt(); } else { // no match, but it could be a partial command m_processed_offset = 0; } } void ICSConnection::process(QString str) { switch(state) { case Normal: if (test(creating, str)) { delete incomingGameInfo; incomingGameInfo = new GameInfo(creating, 1); } else if(test(observed_game, str)) { if(incomingGameInfo) delete incomingGameInfo; incomingGameInfo = new GameInfo(Player(observed_game.cap(2), observed_game.cap(3).toInt()), Player(observed_game.cap(4), observed_game.cap(5).toInt()), observed_game.cap(6), observed_game.cap(7), observed_game.cap(8).toInt(), observed_game.cap(9).toInt() ); int number = observed_game.cap(1).toInt(); incomingGameInfo->setGameNumber(number); m_games[number] = ICSGameData(-1, incomingGameInfo->type()); //kDebug() << "ok, obs " << number << " of type " << incomingGameInfo->type(); } else if (test(game, str)) { //kDebug() << "matched game. incomingGameInfo = " << incomingGameInfo; if(game.cap(4).startsWith("Creating") || game.cap(4).startsWith("Continuing") ) { if (!incomingGameInfo) { //this should really never happen, but anyway... QStringList info = game.cap(4).split(' '); if(info.size() >= 3) incomingGameInfo = new GameInfo(Player(game.cap(2), 0), Player(game.cap(3), 0), info[1], info[2], 0, 0 ); } if (incomingGameInfo) { int number = game.cap(1).toInt(); incomingGameInfo->setGameNumber(number); m_games.insert(std::make_pair(number, ICSGameData(-1, incomingGameInfo->type()))); } } else { if (!incomingGameInfo) { int number = game.cap(1).toInt(); //kDebug() << "matching game " << number << " end"; m_games.erase(number); QString what = game.cap(4); QString result = game.cap(5); endingGame(what, result); } } } else if (test(unexamine, str)) { //kDebug() << "matching examined game end"; int gameNumber = unexamine.cap(1).toInt(); m_games.erase(gameNumber); endingExaminedGame(gameNumber); } else if (test(unobserve, str)) { int gameNumber = unobserve.cap(1).toInt(); m_games.erase(gameNumber); endingObservedGame(gameNumber); } else if (test(move_list_start, str)) { //kDebug() << "entering move list state"; m_move_list_game_num = move_list_start.cap(1).toInt(); state = MoveListHeader; } else { PositionInfo positionInfo; bool game_start = positionInfo.load(m_games, str); if (positionInfo.valid) { int gameNumber = positionInfo.gameNumber; GameList::const_iterator game_it = m_games.find(gameNumber); Q_ASSERT(game_it != m_games.end()); bool incoming = incomingGameInfo && incomingGameInfo->gameNumber() == gameNumber; if (game_start || incoming) { // delete extraneous game info if (incomingGameInfo && incomingGameInfo->gameNumber() != gameNumber) { int n = incomingGameInfo->gameNumber(); if (n != -1) m_games.erase(n); delete incomingGameInfo; incomingGameInfo = 0; } // no info on this game if (!incomingGameInfo) { kWarning() << "unexpected style 12 for game" << gameNumber; incomingGameInfo = new GameInfo(Player(positionInfo.whitePlayer, 0), Player(positionInfo.blackPlayer, 0), "rated", "", 0, 0); } switch (positionInfo.relation) { case PositionInfo::NotMyMove: case PositionInfo::MyMove: //kDebug() << "creating game"; creatingGame(incomingGameInfo, positionInfo); break; case PositionInfo::Examining: //kDebug() << "creating examination"; creatingExaminedGame(incomingGameInfo, positionInfo); break; case PositionInfo::ObservingPlayed: case PositionInfo::ObservingExamined: //kDebug() << "creating obs " << gameNumber << " " << incomingGameInfo->type(); creatingObservedGame(incomingGameInfo, positionInfo); break; default: // unknown relation: ignoring break; } delete incomingGameInfo; incomingGameInfo = 0; } if (shared_ptr listener = m_games[positionInfo.gameNumber].listener.lock()) listener->notifyStyle12(positionInfo, game_start); if (positionInfo.relation == PositionInfo::MyMove) { notification(); } } else { PoolInfo pool_info(m_games, str); if (pool_info.m_valid) { // BROKEN if (!pool_info.m_added_piece) { if (shared_ptr listener = m_games[pool_info.m_game_num].listener.lock()) listener->notifyPool(pool_info); } } } } break; case MoveListHeader: if (test(move_list_players, str)){ //kDebug() << "move list players: " << str; m_move_list_players = move_list_players.capturedTexts(); } else if (test(move_list_game, str)){ //kDebug() << "move list game: " << str; if (m_move_list_game_info) delete m_move_list_game_info; if (m_move_list_players.size()>=5) m_move_list_game_info = new GameInfo( Player(m_move_list_players[1], m_move_list_players[2].toInt()), Player(m_move_list_players[3], m_move_list_players[4].toInt()), move_list_game.cap(1).toLower(), move_list_game.cap(2), move_list_game.cap(3).toInt(), move_list_game.cap(4).toInt() ); else m_move_list_game_info = new GameInfo( Player("unknown",0), Player("unknown",0), move_list_game.cap(1).toLower(), move_list_game.cap(2), move_list_game.cap(3).toInt(), move_list_game.cap(4).toInt() ); m_move_list_game_info->setGameNumber(m_move_list_game_num); //NOTE: here is where an unknown variant will be "upgraded" to the correct variant m_games[m_move_list_game_num].setType(move_list_game.cap(2)); } else if (test(move_list_terminator, str)) { //kDebug() << "move list ign3: " << str; } else if (test(move_list_ignore1, str)){ //kDebug() << "move list ign1: " << str; } else if (test(move_list_ignore2, str)) { //kDebug() << "move list ign2: " << str; state = MoveListMoves; } else { PositionInfo pi; pi.load(m_games, str); if (pi.valid) m_move_list_position_info = new PositionInfo(pi); else { PoolInfo pooli(m_games, str); if(pooli.m_valid) m_move_list_pool_info = new PoolInfo(pooli); } } break; case MoveListMoves: if (test(move_list_terminator, str)){ if (shared_ptr listener = m_games[m_move_list_game_num].listener.lock()) { AbstractPosition::Ptr p; if (m_move_list_position_info) p = m_move_list_position_info->position; else { std::map::const_iterator gi = m_games.find(m_move_list_game_num); if (gi == m_games.end()) { kError() << "Received move list for unknown game " << m_move_list_game_num; } else { VariantPtr variant = gi->second.variant; p = variant->createPosition(); p->setup(); } } if (p) { if (m_move_list_pool_info) { //BROKEN //p->setPool(m_move_list_pool_info->m_pool); } PGN pgn(m_move_list); if (!pgn.valid()) kDebug() << "parse error on move list"; else listener->notifyMoveList(m_move_list_game_num, p, pgn); } } if (m_move_list_game_info) delete m_move_list_game_info; if (m_move_list_position_info) delete m_move_list_position_info; if (m_move_list_pool_info) delete m_move_list_pool_info; m_move_list_game_info = NULL; m_move_list_position_info = NULL; m_move_list_pool_info = NULL; m_move_list = QString(); state = Normal; } else m_move_list += str; break; } m_processed_offset = 0; } void ICSConnection::setListener(int gameNumber, const weak_ptr& listener) { m_games[gameNumber].listener = listener; } void ICSConnection::startup() { sendText("alias $ @"); sendText("iset startpos 1"); sendText("iset ms 1"); sendText("iset lock 1"); sendText("set interface Tagua-0.10 (http://www.tagua-project.org)"); sendText("set style 12"); } tagua-1.0-alpha2/src/icsconnection.h000066400000000000000000000044411077523320400174240ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ICSCONNECTION_H #define ICSCONNECTION_H #include #include #include #include #include "connection.h" #include "icsgamedata.h" class GameInfo; class PGN; class PositionInfo; class PoolInfo; class ICSListener; class ICSConnection : public Connection { Q_OBJECT typedef std::map GameList; enum State { Normal, MoveListHeader, MoveListMoves } state; // patterns static QRegExp pressReturn; static QRegExp creating; static QRegExp game; static QRegExp login; static QRegExp password; static QRegExp fics; static QRegExp beep; static QRegExp unexamine, unobserve; static QRegExp move_list_start, move_list_players, move_list_game, move_list_ignore1, move_list_ignore2, move_list_terminator; static QRegExp observed_game; static QRegExp goForward, goBack; GameInfo* incomingGameInfo; int m_processed_offset; GameList m_games; int m_move_list_game_num; QStringList m_move_list_players; GameInfo *m_move_list_game_info; PositionInfo *m_move_list_position_info; PoolInfo *m_move_list_pool_info; QString m_move_list; bool test(const QRegExp& pattern, const QString& str); public: ICSConnection(); void setListener(int gameNumber, const boost::weak_ptr& listener); void startup(); public Q_SLOTS: void process(QString str); void processPartialLine(QString str); Q_SIGNALS: void notification(); void moves(const PGN&); void time(int, int); void loginPrompt(); void passwordPrompt(); void prompt(); void registeredNickname(); void creatingGame(const GameInfo*, const PositionInfo&); void creatingExaminedGame(const GameInfo*, const PositionInfo&); void creatingObservedGame(const GameInfo*, const PositionInfo&); void endingGame(const QString&, const QString&); void endingExaminedGame(int); void endingObservedGame(int); }; #endif // ICSCONNECTION_H tagua-1.0-alpha2/src/icsgamedata.cpp000066400000000000000000000020261077523320400173600ustar00rootroot00000000000000/* Copyright (c) 2006-2008 Paolo Capriotti (c) 2006-2007 Maurizio Monge 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. */ #include "icsgamedata.h" #include #include "tagua.h" #include "gameinfo.h" #include "variants.h" ICSGameData::ICSGameData() : index(0) { setType(""); } ICSGameData::ICSGameData(int index, const QString& type) : index(index) { setType(type); } void ICSGameData::setType(const QString& type) { variant = Variants::instance().get(GameInfo::variantCode(type)); if (!variant) { kError() << "No variant corresponding to " << type; } else if (!(icsapi = variant->icsAPI())) { // There's no ICSAPI in this variant. // This means we cannot use it for ICS stuff, so we // fall back to the dummy variant. // TODO } } tagua-1.0-alpha2/src/icsgamedata.h000066400000000000000000000014121077523320400170230ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ICSGAMEDATA_H #define ICSGAMEDATA_H #include #include #include "fwd.h" class ICSListener; struct ICSGameData { int index; VariantPtr variant; ICSAPIPtr icsapi; boost::weak_ptr listener; ICSGameData(); ICSGameData(int index, const QString& type); void setType(const QString& var); }; #endif // ICSGAMEDATA_H tagua-1.0-alpha2/src/icslistener.h000066400000000000000000000013601077523320400171070ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef ICSLISTENER_H #define ICSLISTENER_H #include "tagua.h" class ICSListener { public: virtual ~ICSListener() { } virtual void notifyStyle12(const class PositionInfo&, bool is_starting=false) = 0; virtual void notifyPool(const class PoolInfo&) = 0; virtual void notifyMoveList(int, AbstractPosition::Ptr, const class PGN&) = 0; }; #endif // ICSLISTENER_H tagua-1.0-alpha2/src/imageeffects.cpp000066400000000000000000000223221077523320400175410ustar00rootroot00000000000000/* Copyright (c) 2006 Maurizio Monge 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. Part of the code been contributed by Jani Huhtanen. Copyright (c) 2006 Jani Huhtanen. */ #include #include #include #include "imageeffects.h" template static inline void blurinner(unsigned char *bptr, int &zR, int &zG, int &zB, int &zA, int alpha); template static inline void blurrow(QImage & im, int line, int alpha); template static inline void blurcol(QImage & im, int col, int alpha); /* * expblur(QImage &img, int radius) * * In-place blur of image 'img' with kernel * of approximate radius 'radius'. * * Blurs with two sided exponential impulse * response. * * aprec = precision of alpha parameter * in fixed-point format 0.aprec * * zprec = precision of state parameters * zR,zG,zB and zA in fp format 8.zprec */ template static void expblur(QImage &img, int radius ) { if (radius < 1) return; /* Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity) */ int alpha = (int)((1<(img,row,alpha); } for(int col=0;col(img,col,alpha); } return; } template static inline void blurinner(unsigned char *bptr, int &zR, int &zG, int &zB, int &zA, int alpha) { int R,G,B,A; R = *bptr; G = *(bptr+1); B = *(bptr+2); A = *(bptr+3); zR += (alpha * ((R<>aprec; zG += (alpha * ((G<>aprec; zB += (alpha * ((B<>aprec; zA += (alpha * ((A<>aprec; *bptr = zR>>zprec; *(bptr+1) = zG>>zprec; *(bptr+2) = zB>>zprec; *(bptr+3) = zA>>zprec; } template static inline void blurrow( QImage & im, int line, int alpha) { int zR,zG,zB,zA; QRgb *ptr = (QRgb *)im.scanLine(line); zR = *((unsigned char *)ptr )<((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha); } for(int index=im.width()-2; index>=0; index--) { blurinner((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha); } } template static inline void blurcol(QImage & im, int col, int alpha) { int zR,zG,zB,zA; QRgb *ptr = (QRgb *)im.bits(); ptr+=col; zR = *((unsigned char *)ptr )<((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha); } for(int index=(im.height()-2)*im.width(); index>=0; index-=im.width()) { blurinner((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha); } } namespace ImageEffects { #ifdef HAVE_X86_SSE2 void expblur_sse( QImage &img, int radius ); #endif //HAVE_X86_SSE2 #ifdef HAVE_X86_MMX void expblur_mmx( QImage &img, int radius ); #endif //HAVE_X86_MMX void expBlur(QImage& img, int radius) { //KCPUInfo:: returns false on x86_64, and x86_64 always have sse/mmx #ifdef HAVE_X86_SSE2 #ifndef __x86_64__ if(BlitzCPUInfo::haveExtension( BlitzCPUInfo::SSE2 ) ) #endif //__x86_64__ return expblur_sse(img, radius); #endif //HAVE_X86_SSE2 #ifdef HAVE_X86_MMX #ifndef __x86_64__ if(BlitzCPUInfo::haveExtension( BlitzCPUInfo::MMX ) ) #endif //__x86_64__ return expblur_mmx(img, radius); #endif //HAVE_X86_MMX return expblur<15,7>(img, radius); } QImage addShadow(const QImage& image, int r, QColor color, int offx, int offy, int growx, int growy) { QPainter p; QImage retv(image.width()+growx, image.height()+growy, QImage::Format_ARGB32_Premultiplied); int dx = (growx-offx)/2, dy = (growy-offy)/2; p.begin(&retv); p.setCompositionMode(QPainter::CompositionMode_Source); p.fillRect(0,0,retv.width(), retv.height(), QColor(0,0,0,0)); p.fillRect(dx+offx, dy+offy, image.width(), image.height(), color); p.setCompositionMode(QPainter::CompositionMode_DestinationAtop ); p.drawImage(dx+offx, dy+offy, image); p.end(); expBlur(retv, r); p.begin(&retv); p.drawImage(dx, dy, image); p.end(); return retv; } QImage growBorder(const QImage& image) { int w = image.width(); int h = image.height(); QPainter p; QImage retv(w+2, h+2, QImage::Format_ARGB32_Premultiplied); p.begin(&retv); p.setCompositionMode(QPainter::CompositionMode_Source); p.drawImage(0, 0, image, 0, 0, 1, 1); p.drawImage(w+1, 0, image, w-1, 0, 1, 1); p.drawImage(0, h+1, image, 0, h-1, 1, 1); p.drawImage(w+1, h+1, image, w-1, h-1, 1, 1); p.drawImage(1, 0, image, 0, 0, w, 1); p.drawImage(1, h+1, image, 0, h-1, w, 1); p.drawImage(0, 1, image, 0, 0, 1, h); p.drawImage(w+1, 1, image, w-1, 0, 1, h); p.drawImage(1, 1, image); p.end(); return retv; } struct Line { int y, x1, x2; Line(){} Line(int _y, int _x1, int _x2) : y(_y), x1(_x1), x2(_x2) {} }; void floodFill(QImage& image, QPoint point, QColor color, bool invade_border, std::vector* border) { int* ptr = (int*)image.bits(); int h = image.height(); int w = image.width(); int newcol = color.rgba(); int oldcol = ptr[point.x()+point.y()*w]; std::vector lines; { Line l(point.y(), point.x(), point.x()+1); int *scanline = ptr+point.y()*w; scanline[l.x1] = newcol; while(l.x1 > 0 && scanline[l.x1-1] == oldcol) scanline[--l.x1] = newcol; while(l.x2 < w && scanline[l.x2] == oldcol) scanline[l.x2++] = newcol; lines.push_back(l); } while(!lines.empty()) { Line ll = lines.back(); lines.pop_back(); if(ll.x1>0) { if(invade_border) ptr[ll.y*w + ll.x1 - 1] = newcol; if(border) border->push_back(QPoint(ll.x1-1, ll.y)); } if(ll.x2push_back(QPoint(ll.x2, ll.y)); } for(int d=-1; d<=1; d+=2) if( (d == -1) ? (ll.y > 0) : (ll.y < h-1) ) { int *scanline = ptr + (ll.y+d)*w; for(int i=ll.x1;i 0 && scanline[l.x1-1] == oldcol) scanline[--l.x1] = newcol; while(l.x2 < w && scanline[l.x2] == oldcol) scanline[l.x2++] = newcol; lines.push_back(l); i = l.x2; } if(ipush_back(QPoint(i, ll.y+d)); } } } } } void floodFillBlueThreshold(QImage& image, QPoint point, QColor color, unsigned int thresh, bool invade_border, std::vector* border) { unsigned int* ptr = (unsigned int*)image.bits(); int h = image.height(); int w = image.width(); unsigned int newcol = color.rgba(); std::vector lines; #define TEST(x) ((((x) & 0xff) < thresh) && ((x) != newcol)) { Line l(point.y(), point.x(), point.x()+1); unsigned int *scanline = ptr+point.y()*w; scanline[l.x1] = newcol; while(l.x1 > 0 && TEST(scanline[l.x1-1])) scanline[--l.x1] = newcol; while(l.x2 < w && TEST(scanline[l.x2])) scanline[l.x2++] = newcol; lines.push_back(l); } while(!lines.empty()) { Line ll = lines.back(); lines.pop_back(); if(ll.x1>0) { if(invade_border) ptr[ll.y*w + ll.x1 - 1] = newcol; if(border) border->push_back(QPoint(ll.x1-1, ll.y)); } if(ll.x2push_back(QPoint(ll.x2, ll.y)); } for(int d=-1; d<=1; d+=2) if( (d == -1) ? (ll.y > 0) : (ll.y < h-1) ) { unsigned int *scanline = ptr + (ll.y+d)*w; for(int i=ll.x1;i 0 && TEST(scanline[l.x1-1])) scanline[--l.x1] = newcol; while(l.x2 < w && TEST(scanline[l.x2])) scanline[l.x2++] = newcol; lines.push_back(l); i = l.x2; } if(ipush_back(QPoint(i, ll.y+d)); } } } } } } tagua-1.0-alpha2/src/imageeffects.h000066400000000000000000000021111077523320400172000ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef IMAGEEFFECTS_H #define IMAGEEFFECTS_H #include #include #include namespace ImageEffects { void expBlur(QImage& img, int radius); QImage addShadow(const QImage& image, int radius, QColor color, int offx, int offy, int growx, int growy); void floodFill(QImage& image, QPoint point, QColor color, bool invade_border = false, std::vector* border = NULL); void floodFillBlueThreshold(QImage& image, QPoint point, QColor color, unsigned int thresh, bool invade_border = false, std::vector* border = NULL); QImage growBorder(const QImage& image); } //end namespace ImageEffects #endif //IMAGEEFFECTS_H tagua-1.0-alpha2/src/imageeffects_mmx.cpp000066400000000000000000000044021077523320400204210ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include namespace ImageEffects { union vec4s { uint16_t i[4]; __m64 v; }; static inline void blur_mmx(void *px, __m64& v, __m64& alpha) { uint64_t z1 = 0ULL; uint64_t z2 = 0ULL; asm( "movd %[pixel], %[t1]\n" "punpcklbw %[t1], %[t2]\n" "psrlw $1, %[t2]\n" "psubw %[accum], %[t2]\n" "pmulhw %[alpha], %[t2]\n" "psllw $1, %[t2]\n" "paddw %[t2], %[accum]\n" "movq %[accum], %[t1]\n" "psrlw $7, %[t1]\n" // "pand %[mask], %[t1]\n" "packuswb %[t1], %[t1]\n" "movd %[t1], %[pixel]\n" : [pixel] "+m"(*(uint32_t*)px) , [accum] "+y"(v) , [t1] "+y"(z1) , [t2] "+y"(z2) : [alpha] "y"(alpha) // , [mask] "y"(0x00ff00ff00ff00ffULL) ); } void expblur_mmx( QImage &img, int radius ) { if(radius<1) return; /* Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity) */ uint16_t alpha = (uint16_t)((1<<15)*(1.0f-expf(-2.3f/(radius+1.f)))); vec4s a; QRgb *ptr = (QRgb *)img.bits(); int h = img.height(); int w = img.width(); int hw = (img.height()-1)*img.width(); for(int i=0;i<4;i++) a.i[i] = alpha; for(int row=0;row=0; index--) blur_mmx(&cptr[index*4], z.v, a.v); } for(int col=0;col=0; index-=w) blur_mmx(&cptr[index*4], z.v, a.v); } asm("emms"); return; } } //end namespace ImageEffects tagua-1.0-alpha2/src/imageeffects_sse.cpp000066400000000000000000000125171077523320400204200ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include namespace ImageEffects { union vec4i { uint16_t i[8]; __m128i v; }; static inline void blur_sse_near(void* pixels, __m128i& state, __m128i alpha) { uint64_t z1 = 0ULL; uint64_t z2 = 0ULL; uint64_t z3 = 0ULL; asm( "movq %[ppix], %[pixels]\n" "punpcklbw %[pixels], %[aux1]\n" // unpack two pixels setting their bytes // as the most significant in the corr. word "psrlw $1, %[aux1]\n" // shift right by 1, i.e. shift the colour // bytes left by 7 "psubw %[state], %[aux1]\n" // - state "pmulhw %[alpha], %[aux1]\n" // * alpha, and take the 16 most significant bits "psllw $1, %[aux1]\n" // shift left (we trade 1 bit for performance, here) "paddw %[aux1], %[state]\n" // sum result to state "movdqa %[state], %[aux2]\n" // copy state to the aux2 register "psrlw $7, %[aux2]\n" // shift right by 7: this is the new pixel value "packuswb %[aux2], %[aux2]\n" // pack pixels as 8 bits "movq %[aux2], %[ppix]\n" : [state] "+x"(state) , [ppix] "+m"(*(uint64_t*)pixels) , [aux1] "+x"(z1) , [aux2] "+x"(z2) , [pixels] "+x"(z3) : [alpha] "x"(alpha) ); } static inline void blur_sse_sep(void* pixel1, void* pixel2, __m128i& state, __m128i alpha) { uint64_t z1 = 0ULL; uint64_t z2 = 0ULL; uint64_t z3 = 0ULL; uint64_t z4 = 0ULL; asm( "movd %[ppix1], %[pixels]\n" // load the first pixel "movd %[ppix2], %[tmp]\n" // load the second pixel in [tmp] "pslldq $4, %[tmp]\n" // shift left the second pixel "paddd %[tmp], %[pixels]\n" // now both pixel are packed in [pixels] "punpcklbw %[pixels], %[aux1]\n" // unpack two pixels setting their bytes // as the most significant in the corr. word "psrlw $1, %[aux1]\n" // shift right by 1, i.e. shift the colour // bytes left by 7 "psubw %[state], %[aux1]\n" // - state "pmulhw %[alpha], %[aux1]\n" // * alpha, and take the 16 most significant bits "psllw $1, %[aux1]\n" // shift left (we trade 1 bit for performance, here) "paddw %[aux1], %[state]\n" // sum result to state "movdqa %[state], %[aux2]\n" // copy state to the aux2 register "psrlw $7, %[aux2]\n" // shift right by 7: this is the new pixel value "packuswb %[aux2], %[aux2]\n" // pack pixels as 8 bits "movd %[aux2], %[ppix1]\n" "psrldq $4, %[aux2]\n" "movd %[aux2], %[ppix2]\n" : [state] "+x"(state) , [ppix1] "+m"(*(uint32_t*)pixel1) , [ppix2] "+m"(*(uint32_t*)pixel2) , [aux1] "+x"(z1) , [aux2] "+x"(z2) , [tmp] "+x"(z3) , [pixels] "+x"(z4) : [alpha] "x"(alpha) ); } void expblur_sse( QImage &img, int radius ) { if(radius<1) return; /* Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity) */ uint16_t alpha = (uint16_t)((1<<15)*(1.0f-expf(-2.3f/(radius+1.f)))); vec4i a; QRgb *ptr = (QRgb *)img.bits(); int h = img.height(); int w = img.width(); int hw = (img.height()-1)*img.width(); for(int i=0;i<8;i++) a.i[i] = alpha; for(int row=0;row=0; index--) blur_sse_sep(&cptr[index*4], &cptr[(index+w)*4] , z.v, a.v); } if(h & 1) { vec4i z; int dummy; uint8_t *cptr = (uint8_t*)(ptr+(h-1)*w); for(int i=0;i<4;i++) z.i[i] = cptr[i]<<7; for(int index=1; index=0; index--) blur_sse_sep(&cptr[index*4], &dummy, z.v, a.v); } for(int col=0;col=0; index-=w) blur_sse_near(&cptr[index*4], z.v, a.v); } if(w & 1) { vec4i z; int dummy; uint8_t *cptr = (uint8_t*)(ptr+w-1); for(int i=0;i<4;i++) z.i[i] = cptr[i]<<7; for(int index=w; index=0; index-=w) blur_sse_sep(&cptr[index*4], &dummy, z.v, a.v); } return; } } //end namespace ImageEffects tagua-1.0-alpha2/src/index.cpp000066400000000000000000000130111077523320400162210ustar00rootroot00000000000000 /* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include "index.h" Index::operator QString() const { QString retv = QString::number(num_moves); for(int i = 0; i < (int)nested.size(); i++) retv += QString("_%1.%2").arg( nested[i].variation ).arg( nested[i].num_moves ); return retv; } Index Index::fromString(const QString& s) { QStringList l = s.split("_"); if(l.isEmpty()) return Index(-1); Index retv(l[0].toInt()); for(int i=1;i nested[s-1].num_moves) return *this; if(nested[s-1].num_moves > vstart.nested[s-1].num_moves) { Index retv(num_moves); for(int i=0;i s && nested[s].variation == v_id) { Index retv(num_moves); for(int i=0;i vstart.num_moves) { Index retv(vstart.num_moves); retv.nested.push_back(Ref(v_id,num_moves - vstart.num_moves - 1)); for(int i=0;i<(int)nested.size();i++) retv.nested.push_back(nested[i]); return retv; } else if(num_moves == vstart.num_moves && nested.size() > 0 && nested[0].variation == v_id) { Index retv(num_moves + nested[0].num_moves + 1); for(int i=1;i<(int)nested.size();i++) retv.nested.push_back(nested[i]); return retv; } else return *this; } Index Index::next(int variation_id, int num) const { Index retv = *this; if(variation_id != -1) retv.nested.push_back( Ref(variation_id, num-1) ); else if(retv.nested.size() == 0) retv.num_moves += num; else retv.nested.last().num_moves += num; return retv; } Index Index::prev(int _num) const { int num = _num; Index retv = *this; while(num) { if(retv.nested.size() == 0) { if(retv.num_moves < num) { kError() << "Cannot rewind index" << *this << "by" << _num; return Index(-1); } retv.num_moves -= num; num = 0; } else { if(retv.nested.last().num_moves >= num) { retv.nested.last().num_moves -= num; num = 0; } else { num -= retv.nested.last().num_moves+1; retv.nested.pop_back(); } } } return retv; } Index Index::min(const Index& ix) const { if(ix.num_moves != num_moves) return Index( std::min(ix.num_moves, num_moves) ); Index retv(num_moves); for(int i = 0; (i < (int)nested.size()) && (i < (int)ix.nested.size()); i++) { if(nested[i].variation != ix.nested[i].variation) break; retv.nested.push_back(Ref(nested[i].variation, std::min(ix.nested[i].num_moves, nested[i].num_moves) )); if(ix.nested[i].num_moves != nested[i].num_moves) break; } return retv; } std::pair Index::stepsTo(const Index& ix) const { int i; int down = 0, up = 0; bool branch = ix.num_moves != num_moves; if(num_moves>ix.num_moves) down += num_moves-ix.num_moves; if(num_movesix.nested[i].num_moves) down += nested[i].num_moves-ix.nested[i].num_moves; if(nested[i].num_moves(down, up); } int Index::lastIndex() { return nested.size() ? nested.back().num_moves : num_moves; } bool Index::mainLine() const { return nested.empty(); } tagua-1.0-alpha2/src/index.h000066400000000000000000000076061077523320400157030ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef INDEX_H #define INDEX_H #include #include #include "common.h" #include /** \class Index index.h \brief An index in a multi-variations game. This is a class that you can use to refer to a position in a game. */ class Index { public: class Ref { public: Ref() : variation(-1), num_moves(-1) {} Ref(int v, int n) : variation(v), num_moves(n) {} int variation; int num_moves; bool operator==(const Ref& r) const { return r.variation == variation && r.num_moves == num_moves; } bool operator!=(const Ref& r) const { return !((*this)==r); } }; int num_moves; QVector nested; /** Constructor, you can contruct it from an integer that is the number of moves played in the main line */ Index(int n = -1) : num_moves(n) {} /** return a string like "1_2.3_4.5" */ operator QString() const; /** returns the number of moves from the start of the game */ int totalNumMoves() const; /** \return true if this index is the first of a variation branch */ bool atVariationStart() const; /** flip variation: returns the current index changed as if it was in the subvariation \a vid at \a vstart instead of mainline and viceversa, ie at \a vstart the mainline becames subvariation \a vid and viceversa */ Index flipVariation(const Index& vstart, int v_id) const; /** Returns an index the point to the next position. If variation is != -1, you will be entering in the sub-variation with this id instead of continuing in the current main line. You can also specify the number of moves you want to go on (in the main line or in the specified variation) */ Index next(int variation_id = -1, int num = 1) const; /** Returns an index pointing to the previous position (or to a position n moves back) */ Index prev(int _num = 1) const; /** Returns an index that is the minimum of this index and the given one, ie the branch point of the lines from start to the two indices. */ Index min(const Index& ix) const; /** Returns the number of steps down and up you have to do to go from this index to the given one */ std::pair stepsTo(const Index& ix) const; /** returns the number of moves in the most nested variation */ int lastIndex(); /** True if this index refers to a position 'before' than the given one */ bool operator<(const Index& ix) const { std::pair s = stepsTo(ix); return s.first == 0 && s.second>0; } /** True if this index refers to a position 'before or equal' than the given one */ bool operator<=(const Index& ix) const { std::pair s = stepsTo(ix); return s.first == 0; } /** True if this index refers to a position 'after' than the given one */ bool operator>(const Index& ix) const { return ix < *this; } /** True if this index refers to a position 'after or equal' than the given one */ bool operator>=(const Index& ix) const { return ix <= *this; } /** True if this index refers to the same position of the given one */ bool operator==(const Index& ix) const { std::pair s = stepsTo(ix); return s.first == 0 && s.second == 0; } /** True if this index refers to a different position of the given one */ bool operator!=(const Index& ix) const { return !(*this == ix); } /** \return an index from a string like "1_2.3_4.5" */ static Index fromString(const QString& s); /** \return whether this index points to the mainline */ bool mainLine() const; }; #endif //INDEX_H tagua-1.0-alpha2/src/indexconverter.h000066400000000000000000000011651077523320400176250ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef INDEXCONVERTER_H #define INDEXCONVERTER_H class IndexConverter { public: virtual ~IndexConverter() { }; virtual QPoint toReal(int index) const = 0; virtual int toLogical(const QPoint& p) const = 0; }; #endif // INDEXCONVERTER_H tagua-1.0-alpha2/src/infodisplay.cpp000066400000000000000000000022621077523320400174410ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include "infodisplay.h" #include "kgamecanvas.h" class MessageItem : public KGameCanvasText { public: MessageItem(const QString& text, const QFont& font, KGameCanvasAbstract* canvas) : KGameCanvasText(text, Qt::black, font, KGameCanvasText::HStart, KGameCanvasText::VCenter, canvas) { } }; InfoDisplay::InfoDisplay(KGameCanvasAbstract* parent) : KGameCanvasGroup(parent) { m_message = new MessageItem("", QFont(), this); m_message->moveTo(QPoint(0, 0)); m_message->show(); } InfoDisplay::~InfoDisplay() { delete m_message; } void InfoDisplay::resizeEvent(QResizeEvent* e) { // m_message->setSize(e->size()); } void InfoDisplay::setMessage(const QString& msg) { m_message->setText(msg); } void InfoDisplay::settingsChanged() { } tagua-1.0-alpha2/src/infodisplay.h000066400000000000000000000013761077523320400171130ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef INFODISPLAY_H #define INFODISPLAY_H #include "kgamecanvas.h" class MessageItem; class InfoDisplay : public KGameCanvasGroup { MessageItem* m_message; protected: void resizeEvent(QResizeEvent*); public: InfoDisplay(KGameCanvasAbstract* parent = 0); ~InfoDisplay(); void setMessage(const QString&); void settingsChanged(); }; #endif // INFODISPLAY_H tagua-1.0-alpha2/src/interactiontype.h000066400000000000000000000011661077523320400200100ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef INTERACTIONTYPE_H #define INTERACTIONTYPE_H /** * @brief An enumerated type to specify the type of an interaction with a position */ enum InteractionType { NoAction, Moving, Premoving }; #endif //INTERACTIONTYPE_H tagua-1.0-alpha2/src/loader/000077500000000000000000000000001077523320400156605ustar00rootroot00000000000000tagua-1.0-alpha2/src/loader/context.cpp000066400000000000000000000016711077523320400200550ustar00rootroot00000000000000/* Copyright (c) 2006-2008 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "common.h" #include #include "loader/context.h" namespace Loader { Context::Cache Context::s_cache; void Context::flush() { for(KeySet::iterator i = m_references.begin(); i != m_references.end(); ) { Cache::iterator cit = s_cache.find(*i); Q_ASSERT(cit != s_cache.end()); Q_ASSERT(cit->second.m_ref_count > 0); m_references.erase(i++); if( !--cit->second.m_ref_count ) s_cache.erase(cit); } } Context::~Context() { flush(); Q_ASSERT(m_references.empty()); } } //end namespace Loader tagua-1.0-alpha2/src/loader/context.h000066400000000000000000000047661077523320400175320ustar00rootroot00000000000000/* Copyright (c) 2006-2008 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LOADER__CONTEXT_H #define LOADER__CONTEXT_H #include #include #include #include namespace Loader { /** * @class Context * @brief A resource loading context * * This class offers a set of references in a global cache, to access * a global cache remembering which elements of the cache are being used. * */ class Context { public: class Key { public: QString m_name; const char *m_type; Key(const QString& name, const char *type) : m_name(name) , m_type(type) { } bool operator<(const Key& ref) const { return (m_name < ref.m_name) || ((m_name == ref.m_name) && (strcmp(m_type, ref.m_type) < 0)); } }; class Resource { public: int m_ref_count; boost::any m_data; Resource() : m_ref_count(1) {} template Resource(const T& data) : m_ref_count(1) , m_data(data) { } }; typedef std::map Cache; typedef std::set KeySet; static Cache s_cache; KeySet m_references; public: /** Destructor (flushes the context) */ ~Context(); /** Flushes all the references in this context. */ void flush(); /** * Gets a resource by name. * @param name The resource name * @return The resource pointer, or null if not found. */ template T* get(const QString& name) { Key key(name, typeid(T).name()); Cache::iterator it = s_cache.find(key); if(it == s_cache.end()) return NULL; if(!m_references.count(key)) { it->second.m_ref_count++; m_references.insert(key); } return boost::any_cast(&it->second.m_data); } /** * Puts a new resource in the global cache, and makes it * referenced by this context. * @param name The resource name */ template void put(const QString& name, const T& data) { Key key(name, typeid(T).name()); Q_ASSERT(!s_cache.count(key)); Q_ASSERT(!m_references.count(key)); s_cache[key] = Resource(data); m_references.insert(key); } }; } //end namespace Loader #endif //LOADER__CONTEXT_H tagua-1.0-alpha2/src/loader/image.cpp000066400000000000000000000251651077523320400174570ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include #include #include "common.h" #include "imageeffects.h" #include "loader/context.h" #include "loader/image.h" namespace Loader { //BEGIN Font------------------------------------------------------------------- Font::Font(int id, int size) : m_id(id) , m_families(QFontDatabase::applicationFontFamilies(id)) , m_font(m_families.empty()?QString():m_families[0], size) { //for(int i=0;iget(k)) font_glyph = *f; else { /* get the font (from cache if possible) */ FontPtr font = Font::create(ctx, file); if(!font) return false; font_glyph = FontGlyphPtr(new FontGlyph); /* get a few metrics */ QFontMetrics fm(font->m_font); if(!fm.inFont(glyph)) return false; int h = fm.height(); int w = fm.width(glyph); font_glyph->m_height = h; /* create the path from the char */ font_glyph->m_path.addText((h-w)/2, fm.ascent(), font->m_font, glyph); /* save in cache */ ctx->put(k, font_glyph); } /* create lazily the inner background region */ if(!font_glyph->m_inner_background_init && draw_inner_bg && (_bg.style() != Qt::NoBrush && !(_bg.style() <= 14 && _bg.color().alpha()==0))) { //14 is the last color-based brush int h = font_glyph->m_height; QImage bg_img(h, h, QImage::Format_ARGB32_Premultiplied ); bg_img.fill( QColor(Qt::black).rgba() ); //fill all black /* render the piece in blue */ QPainter p; p.begin(&bg_img); p.setBrush( Qt::blue ); p.setPen( Qt::NoPen); p.setCompositionMode(QPainter::CompositionMode_Source); p.setRenderHint(QPainter::Antialiasing, true); p.drawPath(font_glyph->m_path); p.end(); /* flood fill the connected component where blue is <192 with a transparent color */ ImageEffects::floodFillBlueThreshold(bg_img, QPoint(0,0), Qt::transparent, 192, true); /* And we've got our region */ font_glyph->m_inner_background = bg_img.createAlphaMask(); font_glyph->m_inner_background.setColor(0, Qt::transparent); font_glyph->m_inner_background_init = true; } /* draw the glyph, at last :) */ int h = font_glyph->m_height; QPainter p(&m_image); init_painter(&p); p.translate(dest.x(), dest.y()); p.scale(dest.width()/h, dest.height()/h); //14 is the last color-based brush if(_bg.style() != Qt::NoBrush && !(_bg.style() <= 14 && _bg.color().alpha()==0)) { QBrush bg = _bg; QMatrix m = bg.matrix(); m = m * QMatrix().translate(-dest.x(), -dest.y()); m = m * QMatrix().scale(h/dest.width(), h/dest.height()); bg.setMatrix(m); if(draw_inner_bg) { QMatrix m = p.matrix(); QRectF r = m.mapRect(QRectF(0,0,h,h)); QRect ir = r.toRect(); QImage tmp(ir.size(), QImage::Format_ARGB32_Premultiplied); tmp.fill(0); { QPainter ptmp(&tmp); ptmp.setRenderHint(QPainter::Antialiasing); ptmp.setRenderHint(QPainter::TextAntialiasing); ptmp.setRenderHint(QPainter::SmoothPixmapTransform); ptmp.translate(-ir.x(), -ir.y()); ptmp.setMatrix(m, true); ptmp.drawImage(QRect(0,0,h,h), font_glyph->m_inner_background); if(border > 0.0 || !_fg.isOpaque() ) { ptmp.setBrush( _fg.isOpaque() ? QBrush(Qt::NoBrush) : QBrush(Qt::red) ); ptmp.setPen( (border > 0.0) ? QPen( Qt::green, h*border/100.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) : Qt::NoPen ); ptmp.drawPath(font_glyph->m_path); } ptmp.setCompositionMode(QPainter::CompositionMode_SourceIn); ptmp.fillRect(QRect(0,0,h,h), bg); } p.resetMatrix(); p.drawImage(ir, tmp); p.setMatrix(m); } else if(border > 0.0 || !_fg.isOpaque() ) { p.setBrush( _fg.isOpaque() ? Qt::NoBrush : bg ); p.setPen( (border > 0.0) ? QPen(bg, h*border/100.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) : Qt::NoPen ); p.drawPath(font_glyph->m_path); } } if(_fg.style() != Qt::NoBrush) { QBrush fg = _fg; QMatrix m = fg.matrix(); m = m * QMatrix().translate(-dest.x(), -dest.y()); m = m * QMatrix().scale(h/dest.width(), h/dest.height()); fg.setMatrix(m); p.setBrush( fg ); p.setPen( Qt::NoPen ); p.drawPath(font_glyph->m_path); } return true; } void Image::expBlur(double radius) { if(m_image.format() != QImage::Format_RGB32 && m_image.format() != QImage::Format_ARGB32 && m_image.format() != QImage::Format_ARGB32_Premultiplied) m_image = m_image.convertToFormat(QImage::Format_ARGB32_Premultiplied); ImageEffects::expBlur(m_image, int(radius) ); } Image Image::createShadow(double radius, const QColor& color, const QPoint& grow, const QPointF& offset) { Image retv(width()+grow.x(), height()+grow.y()); int px = int(grow.x()*0.5+offset.x()); int py = int(grow.y()*0.5+offset.y()); QPainter p; retv.m_image.fill(0); p.begin(&retv.m_image); p.setCompositionMode(QPainter::CompositionMode_Source); p.fillRect( QRect(px, py, width(), height()), color); p.setCompositionMode(QPainter::CompositionMode_DestinationAtop ); p.drawImage( QPoint(px, py), m_image); p.end(); ImageEffects::expBlur(retv.m_image, int(radius) ); return retv; } //END Image-------------------------------------------------------------------- //BEGIN Glyph------------------------------------------------------------------ Glyph::Glyph(const QString& c, int d) : m_font_valid(false) , m_char(c) , m_delta(d) { } Glyph::Glyph(Context* ctx, const QString& file, const QChar& c, int d) : m_font_valid(false) , m_char(c) , m_delta(d) { if(ctx) { if(FontPtr ff = Font::create(ctx, file)) { m_font_valid = true; m_font = ff->m_font; } } } Glyph::Glyph(const QChar& c) : m_font_valid(false) , m_char(c) , m_delta(0) { } //END Glyph-------------------------------------------------------------------- } //end namespace Loader tagua-1.0-alpha2/src/loader/image.h000066400000000000000000000165731077523320400171270ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LOADER__IMAGE_H #define LOADER__IMAGE_H #include #include #include #include #include #include class QPainter; /** * @namespace Loader * @brief Namespace holding image (and more generally resource) loading functions */ namespace Loader { class Context; /** * @class Image * @brief The image class to be used with lua */ class Image { private: QImage m_image; QMatrix m_draw_matrix; double m_draw_opacity; bool m_draw_over; void init_painter(QPainter*); public: /** * Creates an image. Image data will be undefined. * @param width The width of the image. * @param height The height of the image. */ Image(int width, int height); /** * Creates an image from a file. If the files is not found or could not be * loaded, the resulting image will have width and height equal to 0 * @param ctx The current context (theme) reference (should be implicit in lua) * @param file The file name. */ Image(Context* ctx, const QString& file, bool use_cache = true); /** \return the QImage */ QImage image() { return m_image; } /** Returns the width of the image */ int width() { return m_image.width(); } /** Returns the height of the image */ int height() { return m_image.height(); } /** * Sets the transformation matrix */ void setMatrix(const QMatrix& m) { m_draw_matrix = m; } /** * Resets the transformation matrix */ void resetMatrix() { m_draw_matrix.reset(); } /** * Scales the transformation matrix */ void scale(double x, double y) { m_draw_matrix = m_draw_matrix * QMatrix().scale(x,y); } /** * Rotates the transformation matrix */ void rotate(double angle) { m_draw_matrix = m_draw_matrix * QMatrix().rotate(angle); } /** * Translates the transformation matrix */ void translate(double x, double y) { m_draw_matrix = m_draw_matrix * QMatrix().translate(x,y); } /** * Returns the transformation matrix */ QMatrix matrix() { return m_draw_matrix; } /** * Sets the opacity of the drawing operations */ void setOpacity(double o) { m_draw_opacity = o; } /** * Returns the opacity of the drawing operations */ double opacity() { return m_draw_opacity; } /** * Sets the composition mode * @param over If true the painting operations will paint over, * if false will replace the destination color. */ void setPaintOver(bool over) { m_draw_over = over; } /** * Clears the image. * @param color The color to fill the image with (default transparent) */ void clear(const QColor& color = Qt::transparent); /** * Fills a rectangle. * @param rect The rectangle * @param brush The fill brush */ void fillRect(const QRectF& rect, const QBrush& brush); /** * Draws a line. * @param from The starting point * @param to The end point * @param col The pen color * @param width The pen width */ void drawLine(const QPointF& from, const QPointF& to, const QColor& col, double width); /** * Draws an image on the over the current one. * @param dest The destination rectangle. * @param src_img The source image. * @param src The source rectangle. */ void drawImage(const QRectF& dest, const Image& src_img, const QRectF& src = QRectF(0.0,0.0,0.0,0.0)); /** * Draws an image on the over the current one (overload). * @param ctx The current context (theme) reference (should be implicit in lua) * @param dest The destination rectangle. * @param src_img The source image file. * @param src The source rectangle, WITH RELATIVE COORDINATES 0.0 - 1.0 (of course). * @return True if it was possible to load the image file. */ bool drawImage(Context* ctx, const QRectF& dest, const QString& src_img, const QRectF& src = QRectF(0.0,0.0,0.0,0.0), bool use_cache = true); /** * Draws an SVG file over the image. * @param ctx The current context (theme) reference (should be implicit in lua) * @param dest The destination rectangle. * @param file The file to load. * @return True if it was possible to load the SVG file. * TODO: add css support (When Qt will support it) */ bool drawSVG(Context* ctx, const QRectF& dest, const QString& file); /** * Draws a font glyph over the image. * @param ctx The current context (theme) reference (should be implicit in lua) * @param dest The destination rectangle. * @param font The font file to load. * @param glyph The unicode glyph code. * @param fg The foreground color. * @param bg The background color. * @param border The background expansion. * @param draw_inner_bg If true the 'inner part' (detected with a flood fill algorithm) will be filled with the background brush. * @return True if it was possible to load the font file and find the glyph. */ bool drawGlyph(Context* ctx, const QRectF& dest, const QString& font, unsigned int glyph, const QBrush& fg = Qt::black, const QBrush& bg = Qt::white, double border = 0.0, bool draw_inner_bg = true); /** * Blurs the image itself. */ void expBlur(double radius); /** * Returns a shadow image for the current image. * @param radius The shadow radius. * @param color The shadow color. * @param grow How bigger the output image will be. * @param offset Position of the shadow (relatively from being centered in the output). */ Image createShadow(double radius, const QColor& color, const QPoint& grow = QPoint(), const QPointF& offset = QPointF() ); }; /** * @class Glyph * @brief A simple class that represents a glyph in a font to be used with lua */ class Glyph { private: friend class Theme; bool m_font_valid; QFont m_font; QString m_char; int m_delta; public: Glyph(const QString& str, int = 0); Glyph(Context* ctx, const QString&, const QChar& c, int = 0); Glyph(const QChar& = QChar()); QFont font() const { return m_font; } bool fontValid() const { return m_font_valid; } QString str() const { return m_char; } int delta() const { return m_delta; } }; typedef boost::shared_ptr FontPtr; class Font { private: friend class Image; friend class Glyph; QString m_file; int m_id; QStringList m_families; QFont m_font; public: Font(int id, int size = 128); Font(const QFont& font); ~Font(); QFont font() { return m_font; } QStringList families() { return m_families; } static FontPtr create(Context* ctx, const QString& file); }; } //end namespace Loader #endif //LOADER__IMAGE_H tagua-1.0-alpha2/src/loader/theme.cpp000066400000000000000000000126421077523320400174730ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "theme.h" #include #include #include "common.h" #include "mastersettings.h" namespace Loader { PixmapOrMap Theme::to_pixmap_map(const ::LuaApi::ImageOrMap& m) { if(const QImage *i = boost::get(&m)) { return i->isNull() ? PixmapOrMap() : PixmapOrMap(QPixmap::fromImage(*i)); } else if(const ::LuaApi::ImageMap *i = boost::get< ::LuaApi::ImageMap>(&m)) { PixmapMap p; for(::LuaApi::ImageMap::const_iterator it = i->begin(); it != i->end(); ++it) { p[it->first] = QPixmap::fromImage(it->second); } return PixmapOrMap(p); } else return PixmapOrMap(); } Theme::Theme(const ThemeInfo& theme) : m_theme(theme) , m_context() , m_lua_loader(&m_context, theme) { m_lua_loader.runFile(m_theme.file_name); if(m_lua_loader.error()) kError() << "Script load error:" << m_lua_loader.errorString(); settings().onChange(this, "onSettingsChanged"); onSettingsChanged(); } Theme::~Theme() { if(!m_cache.empty()) kError() << "Sizes still referenced."; } void Theme::onSettingsChanged() { SettingMap s_lua = settings().group("lua-settings").map("entry", "file-name"); Settings entry = s_lua.insert(m_theme.file_name); OptList ol = m_lua_loader.getValue("options", 0, NULL, true); if(m_lua_loader.error()) { m_lua_loader.clearError(); return; } if(options_list_load_from_settings(ol, entry.group("options"))) for(Cache::iterator it = m_cache.begin(); it != m_cache.end(); ++it) it->second.m_pixmaps_cache.clear(); } void Theme::refSize(int size) { m_cache[size].m_ref_count++; } void Theme::unrefSize(int size) { Cache::iterator it = m_cache.find(size); if(it == m_cache.end()) { kError() << "Size" << size << "not referenced."; return; } if(!--it->second.m_ref_count) m_cache.erase(size); } template T Theme::getValue(const QString& key, int size, const ::LuaApi::LuaValueMap* args, bool allow_nil) { if(m_lua_loader.error()) return T(); Cache::iterator it = m_cache.find(size); if(it == m_cache.end()) { kError() << "Size" << size << "not referenced."; return T(); } T retv = m_lua_loader.getValue(key, size, args, allow_nil); if(m_lua_loader.error()) { kError() << "Script run error:" << m_lua_loader.errorString(); m_lua_loader.clearError(); } return retv; } template<> PixmapOrMap Theme::getValue(const QString& key, int size, const ::LuaApi::LuaValueMap* args, bool allow_nil) { if(m_lua_loader.error()) return PixmapOrMap(); Cache::iterator it = m_cache.find(size); if(it == m_cache.end()) { kError() << "Size" << size << "not referenced."; return PixmapOrMap(); } if(!args) { SizeCache::PixmapsCache::iterator pix = it->second.m_pixmaps_cache.find(key); if(pix != it->second.m_pixmaps_cache.end()) return pix->second; } PixmapOrMap retv = to_pixmap_map(m_lua_loader.getValue< ::LuaApi::ImageOrMap>(key, size, args, allow_nil)); if(m_lua_loader.error()) { kError() << "Script run error:" << m_lua_loader.errorString(); m_lua_loader.clearError(); } if(!args) it->second.m_pixmaps_cache[key] = retv; return retv; } template<> QPixmap Theme::getValue(const QString& key, int size, const ::LuaApi::LuaValueMap* args, bool allow_nil) { PixmapOrMap p = getValue(key, size, args, allow_nil); if(QPixmap *px = boost::get(&p)) return *px; return QPixmap(); } template<> Glyph Theme::getValue(const QString& key, int size, const ::LuaApi::LuaValueMap* args, bool allow_nil) { if(m_lua_loader.error()) return Glyph(); Cache::iterator it = m_cache.find(size); if(it == m_cache.end()) { kError() << "Size" << size << "not referenced."; return Glyph(); } if(!args) { SizeCache::GlyphsCache::iterator pix = it->second.m_glyphs_cache.find(key); if(pix != it->second.m_glyphs_cache.end()) return pix->second; } Glyph retv = m_lua_loader.getValue(key, size, args, allow_nil); if(m_lua_loader.error()) { kError() << "Script run error:" << m_lua_loader.errorString(); m_lua_loader.clearError(); } retv.m_font.setPointSize(size+retv.delta()); if(!args) it->second.m_glyphs_cache[key] = retv; return retv; } template double Theme::getValue(const QString&, int, const ::LuaApi::LuaValueMap* args, bool allow_nil); template QPointF Theme::getValue(const QString&, int, const ::LuaApi::LuaValueMap* args, bool allow_nil); template QRectF Theme::getValue(const QString&, int, const ::LuaApi::LuaValueMap* args, bool allow_nil); template QBrush Theme::getValue(const QString&, int, const ::LuaApi::LuaValueMap* args, bool allow_nil); template QColor Theme::getValue(const QString&, int, const ::LuaApi::LuaValueMap* args, bool allow_nil); template QFont Theme::getValue(const QString&, int, const ::LuaApi::LuaValueMap* args, bool allow_nil); template ::LuaApi::LuaValueMap Theme::getValue< ::LuaApi::LuaValueMap>(const QString&, int, const ::LuaApi::LuaValueMap* args, bool allow_nil); } //end namespace Loader tagua-1.0-alpha2/src/loader/theme.h000066400000000000000000000040651077523320400171400ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LOADER__THEME_H #define LOADER__THEME_H #include #include #include #include "loader/context.h" #include "luaapi/loader.h" #include "themeinfo.h" namespace Loader { typedef std::map PixmapMap; typedef boost::variant PixmapOrMap; /** * @class Theme * @brief A class that represents and caches all images loaded by a theme. * * This class will be created once for each lua-scripted theme, and will cache * images loaded from that theme. */ class Theme : public QObject { Q_OBJECT private: ThemeInfo m_theme; /** there will be one such class for each size, and i will store pixmaps and glyphs */ class SizeCache { public: typedef std::map PixmapsCache; typedef std::map GlyphsCache; int m_ref_count; PixmapsCache m_pixmaps_cache; GlyphsCache m_glyphs_cache; SizeCache() : m_ref_count(0) {} }; typedef std::map Cache; Context m_context; LuaApi::Loader m_lua_loader; Cache m_cache; static PixmapOrMap to_pixmap_map(const ::LuaApi::ImageOrMap& m); private Q_SLOTS: void onSettingsChanged(); public: /** Constructor, created the class from a lua theme file */ Theme(const ThemeInfo& theme); ~Theme(); /** References the size \a size, enabling you to get pixmaps of size \a size */ void refSize(int size); /** Unreferences the size */ void unrefSize(int size); /** Loads a value */ template T getValue(const QString& key, int size, const ::LuaApi::LuaValueMap* args = NULL, bool allow_nil = false); }; } //end namespace loader #endif //LOADER__THEME_H tagua-1.0-alpha2/src/location.cpp000066400000000000000000000006411077523320400167270ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "location.h" tagua-1.0-alpha2/src/location.h000066400000000000000000000010461077523320400163740ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LOCATION_H #define LOCATION_H class __Board; class __Position; struct Location { const __Board& board; const __Position& position; }; #endif tagua-1.0-alpha2/src/luaapi/000077500000000000000000000000001077523320400156655ustar00rootroot00000000000000tagua-1.0-alpha2/src/luaapi/genericwrapper.cpp000066400000000000000000000066561077523320400214230ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include "genericwrapper.h" namespace LuaApi { QString GenericWrapperBase::file_path(lua_State* l, const QString& f) { StackCheck check(l); lua_getfield(l, LUA_REGISTRYINDEX, CURRENT_DIRECTORY); QDir* dir = reinterpret_cast(lua_touserdata(l, -1)); lua_pop(l, 1); return QDir::cleanPath(QDir::isAbsolutePath(f) ? f : dir->filePath(f)); } Loader::Context* GenericWrapperBase::retrieve_context(lua_State* l) { StackCheck check(l); lua_getfield(l, LUA_REGISTRYINDEX, LOADING_CONTEXT); Loader::Context* retv = reinterpret_cast(lua_touserdata(l, -1)); lua_pop(l, 1); return retv; } void GenericWrapperBase::set_property(lua_State* l, const char* name, lua_CFunction get, lua_CFunction set, int index) { StackCheck check(l); lua_getfield(l,index,".get"); lua_pushcfunction(l, get); lua_setfield(l, -2, name); lua_pop(l, 1); if(set) { lua_getfield(l,index,".set"); lua_pushcfunction(l, set); lua_setfield(l, -2, name); lua_pop(l, 1); } } void GenericWrapperBase::set_method(lua_State* l, lua_CFunction f, const char* name, int index) { StackCheck check(l); lua_getfield(l,index,".methods"); lua_pushcfunction(l, f); lua_setfield(l, -2, name); lua_pop(l, 1); } void GenericWrapperBase::set_meta_method(lua_State* l, lua_CFunction f, const char* name, int index) { StackCheck check(l); lua_pushcfunction(l, f); lua_setfield(l, index-1, name); } int GenericWrapperBase::object_meta_index_event(lua_State* l) { /* should i check the object before the meta table? no... */ lua_getmetatable(l,-2); //key, MT lua_pushstring(l,".methods"); lua_rawget(l,-2); lua_pushvalue(l,-3); lua_gettable(l,-2); //key, MT, .methods, method if(!lua_isnil(l,-1)) { lua_remove(l,-2); lua_remove(l,-2); lua_remove(l,-2); return 1; } lua_pop(l,2); //key, MT lua_pushstring(l,".get"); lua_rawget(l,-2); lua_pushvalue(l,-3); lua_gettable(l,-2); //key, MT, .get, getter if(!lua_isnil(l,-1)) { lua_remove(l,-2); lua_remove(l,-2); lua_remove(l,-2); lua_pushvalue(l,-2); lua_call(l, 1, 1); return 1; } luaL_error(l, "Can't get unexisting method/property %s\n", lua_tostring(l,-4)); lua_pop(l,4); return 0; } int GenericWrapperBase::object_meta_newindex_event(lua_State* l) { StackCheck check(l, -2); /* should i check the object before the meta table? no... */ lua_getmetatable(l,-3); //key, value, MT lua_pushstring(l,".set"); lua_rawget(l,-2); lua_pushvalue(l,-4); lua_gettable(l,-2); //key, value, MT, .set, setter if(!lua_isnil(l,-1)) { lua_remove(l,-2); lua_remove(l,-2); lua_remove(l,-3); lua_pushvalue(l,-3); lua_pushvalue(l,-3); lua_remove(l,-4); lua_call(l, 2, 0); return 0; } luaL_error(l, "Can't set unexisting property %s\n", lua_tostring(l,-5)); lua_pop(l, 5); return 0; } } //end namespace LuaApi tagua-1.0-alpha2/src/luaapi/genericwrapper.h000066400000000000000000000406551077523320400210650ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LUAAPI__GENERICWRAPPER_H #define LUAAPI__GENERICWRAPPER_H extern "C" { #include #include #include #include "lfunclib.h" } #include #include #include "common.h" namespace Loader { class Context; } namespace LuaApi { #define WRAP_0(func, selftype, restype) \ static int func(lua_State* l) { \ selftype* self = retrieve(l, 1); \ CAT0(lua_push, restype)(l, self->func()); \ return 1; \ } #define PROPERTY_RW(PROP, GET, SET, restype) \ static int get_##PROP(lua_State* l) { \ lua_push##restype(l, retrieve(l, 1, DontCheck)->GET()); \ return 1; \ } \ \ static int set_##PROP(lua_State* l) { \ retrieve(l, 1, DontCheck)->SET( lua_to##restype(l, 2) ); \ return 0; \ } #define PROPERTY_RO(PROP, GET, restype) \ static int get_##PROP(lua_State* l) { \ lua_push##restype(l, retrieve(l, 1, DontCheck)->GET()); \ return 1; \ } #define PROPERTY_RW_TYPE(PROP, GET, SET, restype, TYPE) \ static int get_##PROP(lua_State* l) { \ lua_push##restype(l, retrieve(l, 1, DontCheck)->GET()); \ return 1; \ } \ \ static int set_##PROP(lua_State* l) { \ retrieve(l, 1, DontCheck)->SET( TYPE(lua_to##restype(l, 2)) ); \ return 0; \ } #define PROPERTY_RO_TYPE(PROP, GET, restype, TYPE) \ static int get_##PROP(lua_State* l) { \ lua_push##restype(l, retrieve(l, 1, DontCheck)->GET()); \ return 1; \ } #define PROPERTY_RW_CLASS(PROP, GET, SET, CLASS) \ static int get_##PROP(lua_State* l) { \ Wrapper::create(l, retrieve(l, 1, DontCheck)->GET()); \ return 1; \ } \ \ static int set_##PROP(lua_State* l) { \ retrieve(l, 1, DontCheck)->SET( *Wrapper::retrieve(l, 2, AssertOk) ); \ return 0; \ } #define PROPERTY_RO_CLASS(PROP, GET, CLASS) \ static int get_##PROP(lua_State* l) { \ Wrapper::create(l, retrieve(l, 1, DontCheck)->GET()); \ return 1; \ } #define PROPERTY_RO_QSTRING(PROP, GET) \ static int get_##PROP(lua_State* l) { \ QString s = retrieve(l, 1, DontCheck)->GET(); \ lua_pushstring(l, s.toAscii().constData()); \ return 1; \ } #define PROPERTY_RW_QSTRING(PROP, GET, SET) \ static int get_##PROP(lua_State* l) { \ QString s = retrieve(l, 1, DontCheck)->GET(); \ lua_pushstring(l, s.toAscii().constData()); \ return 1; \ } \ \ static int set_##PROP(lua_State* l) { \ retrieve(l, 1, DontCheck)->SET( QString(lua_tostring(l, 2)) ); \ return 0; \ } #define SET_PROPERTY_RW(LUA, PROP) \ set_property(LUA, #PROP, get_##PROP, set_##PROP); #define SET_PROPERTY_RO(LUA, PROP) \ set_property(LUA, #PROP, get_##PROP, NULL); #define LOADING_CONTEXT "tagua_loading_context" #define CURRENT_DIRECTORY "tagua_script_curr_dir" #define API_LOADER "tagua_api_loader" /** * A simple class that read lua stack level at creation and checks it * when destroyed, printing and error message if different from expected. */ class StackCheck { lua_State* l; int top; public: StackCheck(lua_State* l, int expect = 0) : l(l) { top = lua_gettop(l) + expect; } ~StackCheck() { if (lua_gettop(l) != top) { kDebug() << "Wrong lua stack size!\n" " expected = " << top << "\n" " actual = " << lua_gettop(l); } } }; /** * An enumarated value to test how strongly casts will be checked */ enum CheckStrenght { DontCheck, Check, AssertOk }; template class Wrapper; //BEGIN GenericWrappeBase------------------------------------------------------ class GenericWrapperBase { public: static QString file_path(lua_State* l, const QString& f); static Loader::Context* retrieve_context(lua_State* l); /** * Add property \a f to the table at @a index. */ static void set_property(lua_State* l, const char* name, lua_CFunction get, lua_CFunction set = NULL, int index = -1); /** * Add method \a f to the table at @a index. */ static void set_method(lua_State* l, lua_CFunction f, const char* name, int index = -1); /** * Add meta method \a f to the table at @a index. */ static void set_meta_method(lua_State* l, lua_CFunction f, const char* name, int index = -1); /** * Object index read event */ static int object_meta_index_event(lua_State* l); /** * Object index write event */ static int object_meta_newindex_event(lua_State* l); }; //END GenericWrapperBase------------------------------------------------------- //BEGIN GenericWrapprCommon---------------------------------------------------- template class GenericWrapperCommon : public GenericWrapperBase { public: /** * Checks the type, will return true if ok, or false or raise a lua * error if not (in case of Check/AssertOk parameters). */ static bool check_type(lua_State* l, int index, CheckStrenght check) { StackCheck s(l); if(check != DontCheck) { if(!lua_getmetatable(l,index)) { if(check == AssertOk) luaL_error(l, "Mismatch, got object of unknown type expecting %s", Wrapper::class_name()); return false; } Wrapper::push_meta_table(l); if(!lua_rawequal(l, -2, -1)) { if(check == AssertOk) { if(lua_istable(l, -2)) { lua_getfield(l, -2, ".type"); if(lua_isstring(l, -1)) luaL_error(l, "Mismatch, got object of type %s expecting %s", lua_tostring(l,-1), Wrapper::class_name()); } lua_pop(l,2); luaL_error(l, "Mismatch, got object of unknown type expecting %s", Wrapper::class_name()); } lua_pop(l,2); return false; } lua_pop(l,2); } return true; } /** * Create the factory class and static metatable. */ static void register_class(lua_State* l) { StackCheck s(l); lua_newtable(l); // factory class lua_newtable(l); // metatable lua_pushcfunction(l, &Wrapper::constructor_wrapper); lua_setfield(l, -2, "__call"); lua_setmetatable(l, -2); lua_newtable(l); // object metatable // add gc metamethod lua_pushcfunction(l, &Wrapper::deallocate); lua_setfield(l, -2, "__gc"); // add index metamethod lua_pushcfunction(l, &Wrapper::object_meta_index_event); lua_setfield(l, -2, "__index"); // add newindex metamethod lua_pushcfunction(l, &Wrapper::object_meta_newindex_event); lua_setfield(l, -2, "__newindex"); lua_newtable(l); lua_setfield(l, -2, ".methods"); lua_newtable(l); lua_setfield(l, -2, ".get"); lua_newtable(l); lua_setfield(l, -2, ".set"); lua_pushstring(l, Wrapper::class_name() ); lua_setfield(l, -2, ".type"); Wrapper::create_index_table(l); lua_setfield(l, -2, "object_meta_table"); lua_setglobal(l, Wrapper::class_name() ); } /** * Calls the Wrapper<T> constructor */ static int constructor_wrapper(lua_State* l) { lua_remove(l, 1); return Wrapper::constructor(l); } /** * Pushes this object's meta table. */ static void push_meta_table(lua_State* l) { StackCheck s(l, 1); lua_getglobal(l, Wrapper::class_name()); lua_pushstring(l, "object_meta_table"); lua_rawget(l,-2); lua_remove(l,-2); } }; //END GenericWrapperCommon----------------------------------------------------- //BEGIN GenericWrapper--------------------------------------------------------- template class GenericWrapper : public GenericWrapperCommon { public: /** * Retrieve a wrapped object on the stack. */ static T* retrieve(lua_State* l, int index = -1, CheckStrenght check = Check); /** * Destroy a wrapped object of type T. */ static int deallocate(lua_State* l); /** * Wrap an object of type T in a Lua userdatum. * Lua takes ownership of the object, so that it is * automatically disposed by the Lua garbage collector. */ static void allocate(lua_State* l, T* x); }; template T* GenericWrapper::retrieve(lua_State* l, int index, CheckStrenght check) { if(!GenericWrapperCommon::check_type(l, index, check)) return NULL; T** data = reinterpret_cast( lua_touserdata(l, index) ); return data ? *data : NULL; } template int GenericWrapper::deallocate(lua_State* l) { StackCheck s(l, -1); T* data = retrieve(l); lua_pop(l, 1); delete data; return 0; } template void GenericWrapper::allocate(lua_State* l, T* x) { StackCheck s(l, 1); // create userdata T** data = reinterpret_cast( lua_newuserdata(l, sizeof(T*)) ); *data = x; // set metatable GenericWrapperCommon::push_meta_table(l); lua_setmetatable(l, -2); } //END GenericWrapper----------------------------------------------------------- //BEGIN GenericWrapperByValue--------------------------------------------------------- template class GenericWrapperByValue : public GenericWrapperCommon { public: /** * Retrieve a wrapped object on the stack. */ static T* retrieve(lua_State* l, int index = -1, CheckStrenght check = Check); /** * Destroy a wrapped object of type T. */ static int deallocate(lua_State* l); /** * Create an object of type T in a Lua userdatum. * Lua takes ownership of the object, so that it is * automatically disposed by the Lua garbage collector. */ static void create(lua_State* l); template static void create(lua_State* l, const A1&); template static void create(lua_State* l, const A1&, const A2&); template static void create(lua_State* l, const A1&, const A2&, const A3&); template static void create(lua_State* l, const A1&, const A2&, const A3&, const A4&); template static void create(lua_State* l, const A1&, const A2&, const A3&, const A4&, const A5&); }; template T* GenericWrapperByValue::retrieve(lua_State* l, int index, CheckStrenght check) { if(!GenericWrapperCommon::check_type(l, index, check)) return NULL; T* data = reinterpret_cast( lua_touserdata(l, index) ); return data; } template int GenericWrapperByValue::deallocate(lua_State* l) { StackCheck s(l, -1); T* data = retrieve(l); lua_pop(l, 1); data->~T(); //placement delete return 0; } template void GenericWrapperByValue::create(lua_State* l) { StackCheck s(l, 1); T* data = reinterpret_cast(lua_newuserdata(l, sizeof(T))); new(data) T(); //placement new GenericWrapperCommon::push_meta_table(l); lua_setmetatable(l, -2); } template template void GenericWrapperByValue::create(lua_State* l, const A1& a1) { StackCheck s(l, 1); T* data = reinterpret_cast(lua_newuserdata(l, sizeof(T))); new(data) T(a1); //placement new GenericWrapperCommon::push_meta_table(l); lua_setmetatable(l, -2); } template template void GenericWrapperByValue::create(lua_State* l, const A1& a1, const A2& a2) { StackCheck s(l, 1); T* data = reinterpret_cast(lua_newuserdata(l, sizeof(T))); new(data) T(a1, a2); //placement new GenericWrapperCommon::push_meta_table(l); lua_setmetatable(l, -2); } template template void GenericWrapperByValue::create(lua_State* l, const A1& a1, const A2& a2, const A3& a3) { StackCheck s(l, 1); T* data = reinterpret_cast(lua_newuserdata(l, sizeof(T))); new(data) T(a1, a2, a3); //placement new GenericWrapperCommon::push_meta_table(l); lua_setmetatable(l, -2); } template template void GenericWrapperByValue::create(lua_State* l, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { StackCheck s(l, 1); T* data = reinterpret_cast(lua_newuserdata(l, sizeof(T))); new(data) T(a1, a2, a3, a4); //placement new GenericWrapperCommon::push_meta_table(l); lua_setmetatable(l, -2); } template template void GenericWrapperByValue::create(lua_State* l, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { StackCheck s(l, 1); T* data = reinterpret_cast(lua_newuserdata(l, sizeof(T))); new(data) T(a1, a2, a3, a4, a5); //placement new GenericWrapperCommon::push_meta_table(l); lua_setmetatable(l, -2); } //END GenericWrapperByValue----------------------------------------------------------- template class Comparable { public: static void register_in_index_table(lua_State* l); static int eq_event(lua_State* l); }; template void Comparable::register_in_index_table(lua_State* l) { Wrapper::set_meta_method(l, &eq_event, "__eq"); } template int Comparable::eq_event(lua_State* l) { int n = lua_gettop(l); if(n != 2) luaL_error(l, "Wrong argument count %d for __eq", n); T *p1 = Wrapper::retrieve(l, 1, AssertOk); T *p2 = Wrapper::retrieve(l, 2, AssertOk); lua_pop(l, n); lua_pushboolean(l, *p1 == *p2); return 1; } template class Summable { public: static void register_in_index_table(lua_State* l); static int add_event(lua_State* l); static int sub_event(lua_State* l); static int unm_event(lua_State* l); }; template void Summable::register_in_index_table(lua_State* l) { Wrapper::set_meta_method(l, &add_event, "__add"); Wrapper::set_meta_method(l, &sub_event, "__sub"); Wrapper::set_meta_method(l, &unm_event, "__unm"); } template int Summable::add_event(lua_State* l) { int n = lua_gettop(l); if(n != 2) luaL_error(l, "Wrong argument count %d for __add", n); T *p1 = Wrapper::retrieve(l, 1, AssertOk); T *p2 = Wrapper::retrieve(l, 2, AssertOk); lua_pop(l, n); Wrapper::create(l, *p1 + *p2); return 1; } template int Summable::sub_event(lua_State* l) { int n = lua_gettop(l); if(n != 2) luaL_error(l, "Wrong argument count %d for __sub", n); T *p1 = Wrapper::retrieve(l, 1, AssertOk); T *p2 = Wrapper::retrieve(l, 2, AssertOk); lua_pop(l, n); Wrapper::create(l, *p1 - *p2); return 1; } template int Summable::unm_event(lua_State* l) { int n = lua_gettop(l); /* for some strange reason unm gets 2 copies of the same argument */ if(n != 2) luaL_error(l, "Wrong argument count %d for __unm", n); T *p1 = Wrapper::retrieve(l, 1, AssertOk); lua_pop(l, n); Wrapper::create(l, -*p1); return 1; } } //end namespace LuaApi #endif //LUAAPI__GENERICWRAPPER_H tagua-1.0-alpha2/src/luaapi/imaging.cpp000066400000000000000000000545151077523320400200160ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include "luaapi/imaging.h" using namespace Loader; namespace LuaApi { //BEGIN Wrapper ------------------------------------------------------- const char* Wrapper::class_name() { return "Rect"; } int Wrapper::translate(lua_State* l) { QRectF *r = retrieve(l, 1, AssertOk); QPointF *p = Wrapper::retrieve(l, 2, AssertOk); r->translate(*p); return 0; } int Wrapper::to_string(lua_State* l) { QRectF *r = retrieve(l, 1, AssertOk); lua_pushfstring(l, "(%f, %f, %f, %f)", r->x(), r->y(), r->width(), r->height() ); return 1; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RW(l, x); SET_PROPERTY_RW(l, y); SET_PROPERTY_RW(l, width); SET_PROPERTY_RW(l, height); SET_PROPERTY_RO(l, left); SET_PROPERTY_RO(l, right); SET_PROPERTY_RO(l, top); SET_PROPERTY_RO(l, bottom); set_method(l, &translate, "translate"); set_meta_method(l, &to_string, "__tostring"); Comparable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); switch (n) { case 0: create(l); break; case 1: { QRectF res = *retrieve(l, 1, AssertOk); lua_pop(l, 1); create(l,res); break; } case 4: { double x = lua_tonumber(l, 1); double y = lua_tonumber(l, 2); double width = lua_tonumber(l, 3); double height = lua_tonumber(l, 4); lua_pop(l, 4); create(l, x, y, width, height); } break; default: luaL_error(l, "Wrong parameter list for Rect constructor"); } return 1; } //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------ const char* Wrapper::class_name() { return "Point"; } int Wrapper::to_string(lua_State* l) { QPointF *p = retrieve(l, 1, AssertOk); lua_pushfstring(l, "(%f, %f)", p->x(), p->y() ); return 1; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RW(l, x); SET_PROPERTY_RW(l, y); SET_PROPERTY_RO(l, length); set_meta_method(l, &to_string, "__tostring"); set_meta_method(l, &get_length, "__len"); Comparable::register_in_index_table(l); Summable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); switch(n) { case 0: create(l); break; case 1: { QPointF res = *retrieve(l, 1, AssertOk); lua_pop(l,1); create(l, res); break; } case 2: { double x = lua_tonumber(l, 1); double y = lua_tonumber(l, 2); lua_pop(l,2); create(l, x, y); } break; default: luaL_error(l, "Wrong argument count for Point constructor"); break; } return 1; } int Wrapper::get_length(lua_State* l) { QPointF *p = retrieve(l, 1, DontCheck); lua_pushnumber(l, sqrt(p->x()*p->x() + p->y()*p->y()) ); return 1; } //END Wrapper -------------------------------------------------------- //BEGIN Wrapper-------------------------------------------------------- const char* Wrapper::class_name() { return "Color"; } int Wrapper::to_string(lua_State* l) { QColor *r = retrieve(l, 1, AssertOk); char buf[32]; snprintf(buf, 32, "#%08x", r->rgba()); lua_pushstring(l, buf); return 1; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RW(l, r); SET_PROPERTY_RW(l, g); SET_PROPERTY_RW(l, b); SET_PROPERTY_RW(l, a); set_meta_method(l, &to_string, "__tostring"); } QColor Wrapper::get(lua_State* l, int index) { if(lua_isstring(l, index)) { QColor retv(lua_tostring(l, index)); if(!retv.isValid()) luaL_error(l, "Wrong color string \"%s\"", lua_tostring(l, index)); return retv; } else return *retrieve(l, index, AssertOk); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); switch (n) { case 0: create(l); break; case 1: { QColor c = get(l, 1); lua_pop(l, 1); create(l, c); break; } case 3: case 4: { int r = int(lua_tonumber(l, 1)); int g = int(lua_tonumber(l, 2)); int b = int(lua_tonumber(l, 3)); int a = (n == 3) ? 255 : int(lua_tonumber(l, 4)); lua_pop(l, n); create(l, r, g, b, a); } break; default: luaL_error(l, "Wrong parameter list for Color constructor"); } return 1; } //END Wrapper---------------------------------------------------------- template int GradientWrapper::index_event(lua_State* l) { if(!lua_isnumber(l, -1)) return GenericWrapperBase::object_meta_index_event(l); T *g = Wrapper::retrieve(l, -2, AssertOk); double stopnum = lua_tonumber(l, -1); lua_pop(l, 1); QGradientStops s = g->stops(); int retv; if(s.size()) { int min = 0; int max = s.size(); while(min < max-1) { int mid = (min+max)/2; if(stopnum > s[(min+max)/2].first) min = mid; else max = mid; } if(qAbs(s[max].first-stopnum) < qAbs(s[min].first-stopnum)) retv = max; else retv = min; } Wrapper::create(l, s[retv].second); lua_pushnumber(l, s[retv].first); return 2; } template int GradientWrapper::newindex_event(lua_State* l) { if(!lua_isnumber(l, -2)) return GenericWrapperBase::object_meta_newindex_event(l); T *g = Wrapper::retrieve(l, -3, AssertOk); double stopnum = lua_tonumber(l, -2); QColor col = Wrapper::get(l, -1); lua_pop(l, 3); g->setColorAt(stopnum, col); return 0; } //BEGIN Wrapper-------------------------------------------------------- const char* Wrapper::class_name() { return "LinearGradient"; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RW(l, start); SET_PROPERTY_RW(l, finish); //set_meta_method(l, &index_event, "__index"); set_meta_method(l, &newindex_event, "__newindex"); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); switch(n) { case 0: create(l); break; case 2: { QPointF* start = Wrapper::retrieve(l, 1, AssertOk); QPointF* final = Wrapper::retrieve(l, 2, AssertOk); lua_pop(l, 2); create(l, *start, *final); break; } default: luaL_error(l, "Wrong parameter list for LinearGradient constructor"); break; } return 1; } //END Wrapper---------------------------------------------------------- //BEGIN Wrapper-------------------------------------------------------- const char* Wrapper::class_name() { return "RadialGradient"; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RW(l, center); SET_PROPERTY_RW(l, radius); SET_PROPERTY_RW(l, focus); //set_meta_method(l, &index_event, "__index"); set_meta_method(l, &newindex_event, "__newindex"); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); switch(n) { case 0: create(l); break; case 2: { QPointF* center = Wrapper::retrieve(l, 1, AssertOk); double radius = lua_tonumber(l, 2); lua_pop(l, 2); create(l, *center, radius); break; } case 3: { QPointF* center = Wrapper::retrieve(l, 1, AssertOk); double radius = lua_tonumber(l, 2); QPointF* focus = Wrapper::retrieve(l, 3, AssertOk); lua_pop(l, 3); create(l, *center, radius, *focus); break; } default: luaL_error(l, "Wrong parameter list for RadialGradient constructor"); break; } return 1; } //END Wrapper---------------------------------------------------------- //BEGIN Wrapper-------------------------------------------------------- const char* Wrapper::class_name() { return "ConicalGradient"; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RW(l, center); SET_PROPERTY_RW(l, angle); //set_meta_method(l, &index_event, "__index"); set_meta_method(l, &newindex_event, "__newindex"); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); switch(n) { case 0: create(l); break; case 2: { QPointF* center = Wrapper::retrieve(l, 1, AssertOk); double angle = lua_tonumber(l, 2); lua_pop(l, 2); create(l, *center, angle); break; } default: luaL_error(l, "Wrong parameter list for Color constructor"); break; } return 1; } //END Wrapper---------------------------------------------------------- //BEGIN Wrapper-------------------------------------------------------- const char* Wrapper::class_name() { return "Brush"; } void Wrapper::create_index_table(lua_State* l) { //set_meta_method(l, &to_string, "__tostring"); set_method(l, &translate, "translate"); set_method(l, &rotate, "rotate"); set_method(l, &scale, "scale"); } QBrush Wrapper::get(lua_State* l, int index) { if(QBrush *b = retrieve(l, index)) return *b; else if(QLinearGradient* g = Wrapper::retrieve(l, index)) return QBrush(*g); else if(QRadialGradient* g = Wrapper::retrieve(l, index)) return QBrush(*g); else if(QConicalGradient* g = Wrapper::retrieve(l, index)) return QBrush(*g); else if(Loader::Image* img = Wrapper::retrieve(l, index)) return QBrush(img->image()); else return QBrush(Wrapper::get(l, index)); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); switch (n) { case 0: create(l, Qt::NoBrush); break; case 1: { QBrush b = get(l, 1); lua_pop(l, 1); create(l, b); break; } default: luaL_error(l, "Wrong parameter list for Brush constructor"); } return 1; } int Wrapper::rotate(lua_State* l) { const int n = lua_gettop(l); if (n != 2) luaL_error(l, "Wrong argument count for Brush::rotate"); QBrush* brush = retrieve(l, 1, AssertOk); double r = lua_tonumber(l, 2); lua_pop(l, n); QMatrix m = brush->matrix(); m = m * QMatrix().rotate(r); brush->setMatrix(m); return 0; } int Wrapper::scale(lua_State* l) { const int n = lua_gettop(l); if (n != 3) luaL_error(l, "Wrong argument count for Brush::scale"); QBrush* brush = retrieve(l, 1, AssertOk); double x = lua_tonumber(l, 2); double y = lua_tonumber(l, 3); lua_pop(l, n); QMatrix m = brush->matrix(); m = m * QMatrix().scale(x, y); brush->setMatrix(m); return 0; } int Wrapper::translate(lua_State* l) { const int n = lua_gettop(l); if (n < 2 || n > 3) luaL_error(l, "Wrong argument count for Brush::translate"); QBrush* brush = retrieve(l, 1, AssertOk); if(n == 3) { double x = lua_tonumber(l, 2); double y = lua_tonumber(l, 3); lua_pop(l, n); QMatrix m = brush->matrix(); m = m * QMatrix().translate(x, y); brush->setMatrix(m); } else { QPointF* point = Wrapper::retrieve(l, 2, AssertOk); lua_pop(l, n); QMatrix m = brush->matrix(); m = m * QMatrix().translate(point->x(), point->y()); brush->setMatrix(m); } return 0; } //END Wrapper---------------------------------------------------------- //BEGIN Wrapper-------------------------------------------------------- const char* Wrapper::class_name() { return "Font"; } void Wrapper::create_index_table(lua_State* l) { set_meta_method(l, &to_string, "__tostring"); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); switch (n) { case 0: create(l, QApplication::font()); break; case 1: { QFont *b = retrieve(l, 1, AssertOk); lua_pop(l, 1); create(l, *b); break; } case 3: { QString family = lua_tostring(l, 1); bool bold = lua_toboolean(l, 2); bool italic = lua_toboolean(l, 3); lua_pop(l, 3); create(l, family, 12, bold ? QFont::Bold : QFont::Normal, italic); break; } default: luaL_error(l, "Wrong parameter list for Font constructor"); } return 1; } int Wrapper::to_string(lua_State* l) { QFont *r = retrieve(l, 1, AssertOk); lua_pushstring(l, r->rawName().toAscii().constData()); return 1; } //END Wrapper---------------------------------------------------------- //BEGIN Wrapper -------------------------------------------------------- const char* Wrapper::class_name() { return "Image"; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RO(l, width); SET_PROPERTY_RO(l, height); SET_PROPERTY_RW(l, opacity); set_method(l, &resetMatrix, "reset_matrix"); set_method(l, &rotate, "rotate"); set_method(l, &scale, "scale"); set_method(l, &translate, "translate"); set_method(l, &setPaintOver, "set_paint_over"); set_method(l, &clear, "clear"); set_method(l, &fillRect, "fill_rect"); set_method(l, &drawLine, "draw_line"); set_method(l, &drawImage, "draw_image"); set_method(l, &drawSVG, "draw_svg"); set_method(l, &drawGlyph, "draw_glyph"); set_method(l, &expBlur, "exp_blur"); set_method(l, &createShadow, "create_shadow"); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); switch (n) { case 1: { if(lua_isstring(l, 1)) { QString path = file_path(l, lua_tostring(l, 1)); Context* context = retrieve_context(l); lua_pop(l, 1); create(l, context, path ); } else { Image *res = retrieve(l, 1, AssertOk); lua_pop(l, 1); create(l, *res ); } } break; case 2: { if(lua_isnumber(l, 1)) { int width = static_cast(lua_tonumber(l, 1)); int height = static_cast(lua_tonumber(l, 2)); lua_pop(l, 2); create(l, width, height); } else { QString path = file_path(l, lua_tostring(l, 1)); bool use_cache = lua_toboolean(l, 2); Context* context = retrieve_context(l); lua_pop(l, 2); create(l, context, path, use_cache ); } } break; default: luaL_error(l, "Wrong argument count for Image constructor"); } return 1; } int Wrapper::resetMatrix(lua_State* l) { const int n = lua_gettop(l); if (n != 1) luaL_error(l, "Wrong argument count for Image::reset_matrix"); Image* img = retrieve(l, 1, AssertOk); lua_pop(l, n); img->resetMatrix(); return 0; } int Wrapper::rotate(lua_State* l) { const int n = lua_gettop(l); if (n != 2) luaL_error(l, "Wrong argument count for Image::rotate"); Image* img = retrieve(l, 1, AssertOk); double r = lua_tonumber(l, 2); lua_pop(l, n); img->rotate(r); return 0; } int Wrapper::scale(lua_State* l) { const int n = lua_gettop(l); if (n != 3) luaL_error(l, "Wrong argument count for Image::scale"); Image* img = retrieve(l, 1, AssertOk); double x = lua_tonumber(l, 2); double y = lua_tonumber(l, 3); lua_pop(l, n); img->scale(x, y); return 0; } int Wrapper::translate(lua_State* l) { const int n = lua_gettop(l); if (n < 2 || n > 3) luaL_error(l, "Wrong argument count for Image::translate"); Image* img = retrieve(l, 1, AssertOk); if(n == 3) { double x = lua_tonumber(l, 2); double y = lua_tonumber(l, 3); lua_pop(l, n); img->translate(x, y); } else { QPointF* point = Wrapper::retrieve(l, 2, AssertOk); lua_pop(l, n); img->translate(point->x(), point->y()); } return 0; } int Wrapper::clear(lua_State* l) { const int n = lua_gettop(l); if (n < 1 || n > 2) luaL_error(l, "Wrong argument count for Image::clear"); Image* img = retrieve(l, 1, AssertOk); if(n == 2) { QColor col = Wrapper::get(l, 2); lua_pop(l, n); img->clear(col); } else { lua_pop(l, n); img->clear(); } return 0; } int Wrapper::setPaintOver(lua_State* l) { const int n = lua_gettop(l); if (n != 2) luaL_error(l, "Wrong argument count for Image::set_paint_over"); Image* img = retrieve(l, 1, AssertOk); bool p = lua_toboolean(l, 2); lua_pop(l, n); img->setPaintOver(p); return 0; } int Wrapper::fillRect(lua_State* l) { const int n = lua_gettop(l); if (n != 3) luaL_error(l, "Wrong argument count for Image::fill_rect"); Image* img = retrieve(l, 1, AssertOk); QRectF* rect = Wrapper::retrieve(l, 2, AssertOk); QBrush brush = Wrapper::get(l, 3); lua_pop(l, n); img->fillRect(*rect, brush); return 0; } int Wrapper::drawLine(lua_State* l) { const int n = lua_gettop(l); if (n > 5 || n < 4) luaL_error(l, "Wrong argument count for Image::draw_line"); Image* img = retrieve(l, 1, AssertOk); QPointF* from = Wrapper::retrieve(l, 2, AssertOk); QPointF* to = Wrapper::retrieve(l, 3, AssertOk); QColor color = Wrapper::get(l, 4); double width = (n==5) ? lua_tonumber(l, 5) : 0.0; lua_pop(l, n); img->drawLine(*from, *to, color, width); return 0; } int Wrapper::drawImage(lua_State* l) { const int n = lua_gettop(l); if (n < 3 || n > 5) luaL_error(l, "Wrong argument count for Image::draw_image"); Image* img = retrieve(l, 1, AssertOk); QRectF* dest = Wrapper::retrieve(l, 2, AssertOk); if (lua_isstring(l, 3)) { Context* context = retrieve_context(l); const char* image_path = lua_tostring(l, 3); bool res; if (n >= 4) { QRectF* src = Wrapper::retrieve(l, 4, AssertOk); bool use_cache = n == 5 ? lua_toboolean(l, 5) : true; res = img->drawImage(context, *dest, file_path(l, image_path), *src, use_cache); } else res = img->drawImage(context, *dest, file_path(l, image_path) ); lua_pop(l, n); lua_pushboolean(l, res); return 1; } else { if (n == 5) luaL_error(l, "Wrong argument count for Image::draw_image"); Image* image = retrieve(l, 3, AssertOk); if (n == 4) { QRectF* src = Wrapper::retrieve(l, 4, AssertOk); img->drawImage(*dest, *image, *src); } else img->drawImage(*dest, *image); lua_pop(l, n); return 0; } } int Wrapper::drawSVG(lua_State* l) { const int n = lua_gettop(l); if (n != 3) luaL_error(l, "Wrong argument count for Image::draw_svg"); Image* img = retrieve(l, 1, AssertOk); QRectF* rect = Wrapper::retrieve(l, 2, AssertOk); const char* file = lua_tostring(l, 3); Context* context = retrieve_context(l); lua_pop(l, n); bool res = img->drawSVG(context, *rect, file_path(l, file) ); lua_pushboolean(l, res); return 1; } int Wrapper::drawGlyph(lua_State* l) { int n = lua_gettop(l); if (n < 4 || n > 8) luaL_error(l, "Wrong argument count for Image::draw_glyph"); Image* img = retrieve(l, 1, AssertOk); QRectF* rect = Wrapper::retrieve(l, 2, AssertOk); const char* font = lua_tostring(l, 3); const char* glyph_str = lua_tostring(l, 4); if(!font || !glyph_str) luaL_error(l, "Null arguments for Image::draw_glyph"); unsigned int glyph = strtoul(glyph_str, NULL, 0); bool draw_inner_bg = true; double border = 0.0; QBrush fg = Qt::black; QBrush bg = Qt::white; switch (n) { case 8: draw_inner_bg = lua_toboolean(l, 8); case 7: border = lua_tonumber(l, 7); case 6: bg = Wrapper::get(l, 6); case 5: fg = Wrapper::get(l, 5); default: break; } lua_pop(l, n); Context* context = retrieve_context(l); bool res = img->drawGlyph(context, *rect, file_path(l, font), glyph, fg, bg, border, draw_inner_bg); lua_pushboolean(l, res); return 1; } int Wrapper::expBlur(lua_State* l) { int n = lua_gettop(l); if (n != 2) luaL_error(l, "Wrong argument count for Image::exp_blur"); Image* img = retrieve(l, 1, AssertOk); double radius = lua_tonumber(l, 2); img->expBlur(radius); lua_pop(l, n); return 0; } int Wrapper::createShadow(lua_State* l) { int n = lua_gettop(l); if (n < 3 || n > 5) luaL_error(l, "Wrong argument count for Image::create_shadow"); Image* img = retrieve(l, 1, AssertOk); double radius = lua_tonumber(l, 2); QColor color = Wrapper::get(l, 3); QPoint grow; QPointF offset; switch (n) { case 5: offset = *Wrapper::retrieve(l, 5, AssertOk); case 4: grow = Wrapper::retrieve(l, 4, AssertOk)->toPoint(); default: break; } lua_pop(l, n); create(l, img->createShadow(radius, color, grow, offset)); return 1; } //END Wrapper ---------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------ const char* Wrapper::class_name() { return "Glyph"; } void Wrapper::create_index_table(lua_State* /*l*/) { } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); switch(n) { case 1: { unsigned int c = strtoul(lua_tostring(l, 1), NULL, 0); lua_pop(l, 1); create(l, c); } break; case 2: { Context* context = retrieve_context(l); QString path = file_path(l, lua_tostring(l, 1)); unsigned int c = strtoul(lua_tostring(l, 2), NULL, 0); lua_pop(l, 2); create(l, context, path, c); } break; case 3: { Context* context = retrieve_context(l); if (lua_isnil(l, 1)) { // no font path, just load the string QString str(lua_tostring(l, 2)); int d = static_cast(lua_tonumber(l, 3)); lua_pop(l, 3); create(l, str, d); } else { QString path = file_path(l, lua_tostring(l, 1)); unsigned int c = strtoul(lua_tostring(l, 2), NULL, 0); int d = int(lua_tonumber(l, 3)); lua_pop(l, 3); create(l, context, path, c, d); } } break; default: luaL_error(l, "Wrong argument count for Glyph constructor"); break; } return 1; } //END Wrapper -------------------------------------------------------- } //end namespace LuaApi tagua-1.0-alpha2/src/luaapi/imaging.h000066400000000000000000000151031077523320400174510ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LUAAPI__IMAGING_H #define LUAAPI__IMAGING_H #include #include "loader/image.h" #include "luaapi/genericwrapper.h" namespace LuaApi { //BEGIN Wrapper ------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RW(x, x, setX, number) PROPERTY_RW(y, y, setY, number) PROPERTY_RW(width, width, setWidth, number) PROPERTY_RW(height, height, setHeight, number) PROPERTY_RO(left, left, number) PROPERTY_RO(right, right, number) PROPERTY_RO(top, top, number) PROPERTY_RO(bottom, bottom, number) static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); static int translate(lua_State* l); }; //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------ template <> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RW(x, x, setX, number) PROPERTY_RW(y, y, setY, number) static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); static int get_length(lua_State* l); }; //END Wrapper -------------------------------------------------------- //BEGIN Wrapper-------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RW_TYPE(r, red, setRed, number, int) PROPERTY_RW_TYPE(g, green, setGreen, number, int) PROPERTY_RW_TYPE(b, blue, setBlue, number, int) PROPERTY_RW_TYPE(a, alpha, setAlpha, number, int) static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static QColor get(lua_State* l, int index); static int constructor(lua_State* l); }; //END Wrapper---------------------------------------------------------- //BEGIN GradientWrapper-------------------------------------------------------- template class GradientWrapper : public GenericWrapperByValue { public: static int index_event(lua_State* l); static int newindex_event(lua_State* l); }; //END GradientWrapper---------------------------------------------------------- //BEGIN Wrapper----------------------------------------------- template <> class Wrapper : public GradientWrapper { public: PROPERTY_RW_CLASS(start, start, setStart, QPointF) PROPERTY_RW_CLASS(finish, finalStop, setFinalStop, QPointF) static const char* class_name(); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper------------------------------------------------- //BEGIN Wrapper----------------------------------------------- template <> class Wrapper : public GradientWrapper { public: PROPERTY_RW_CLASS(center, center, setCenter, QPointF) PROPERTY_RW(radius, radius, setRadius, number) PROPERTY_RW_CLASS(focus, focalPoint, setFocalPoint, QPointF) static const char* class_name(); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper------------------------------------------------- //BEGIN Wrapper---------------------------------------------- template <> class Wrapper : public GradientWrapper { public: PROPERTY_RW_CLASS(center, center, setCenter, QPointF) PROPERTY_RW(angle, angle, setAngle, number) static const char* class_name(); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper------------------------------------------------ //BEGIN Wrapper-------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: static const char* class_name(); static void create_index_table(lua_State* l); static QBrush get(lua_State* l, int index); static int constructor(lua_State* l); static int rotate(lua_State* l); static int scale(lua_State* l); static int translate(lua_State* l); }; //END Wrapper---------------------------------------------------------- //BEGIN Wrapper -------------------------------------------------------- template<> class Wrapper : public GenericWrapperByValue { public: static const char* class_name(); static void create_index_table(lua_State* l); static int constructor(lua_State* l); static int to_string(lua_State* l); }; //END Wrapper ---------------------------------------------------------- //BEGIN Wrapper -------------------------------------------------------- template<> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RO(width, width, number) PROPERTY_RO(height, height, number) PROPERTY_RW(opacity, opacity, setOpacity, number) static const char* class_name(); static void create_index_table(lua_State* l); static int constructor(lua_State* l); static int resetMatrix(lua_State* l); static int rotate(lua_State* l); static int scale(lua_State* l); static int translate(lua_State* l); static int clear(lua_State* l); static int setPaintOver(lua_State* l); static int fillRect(lua_State* l); static int drawLine(lua_State* l); static int drawImage(lua_State* l); static int drawSVG(lua_State* l); static int drawGlyph(lua_State* l); static int expBlur(lua_State* l); static int createShadow(lua_State* l); }; //END Wrapper ---------------------------------------------------------- //BEGIN Wrapper -------------------------------------------------------- template<> class Wrapper : public GenericWrapperByValue { public: static const char* class_name(); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper ---------------------------------------------------------- } //end namespace LuaApi #endif //LUAAPI__IMAGING_H tagua-1.0-alpha2/src/luaapi/lfunclib.c000066400000000000000000000341301077523320400176300ustar00rootroot00000000000000/* Copyright (c) 2006 Maurizio Monge 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 file has been contributed by Rici Lake under the Lua license: Copyright (c) 2006 Rici Lake Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include "luaapi/lfunclib.h" /* "Constructors" (or collectors, if you prefer). Take an iterator * and return a value. */ /* foreach just applies the self-function to each iteration tuple * in turn. The return the result is the last return value * of the function * * func:foreach() ==> * * local rv... * for val... in do * rv... = func(val...) * end * return rv... * */ static int f_foreach (lua_State *L) { lua_settop(L, 4); for (;;) { int callbase = lua_gettop(L); lua_pushvalue(L, 2); lua_pushvalue(L, 3); lua_pushvalue(L, 4); lua_call(L, 2, LUA_MULTRET); if (lua_isnoneornil(L, callbase + 1)) { lua_settop(L, callbase); return callbase - 4; } lua_pushvalue(L, callbase + 1); lua_replace(L, 4); /* ctl = newctl */ lua_pushvalue(L, 1); if (callbase == 4) { lua_insert(L, 5); } else { lua_replace(L, 5); for (; callbase > 5; --callbase) lua_remove(L, callbase); } lua_call(L, lua_gettop(L) - 5, LUA_MULTRET); } } /* first calls the self-function on each iteration tuple in turn, * and returns the first true (not non-null) return of the self-function. func:first() ==> for val... in do local rv... = func(val...) if (rv...) then return rv... end end end 1: self_func 2: iter_func 3: base 4: control 5: copy_self 6: returned control */ static int f_first (lua_State *L) { for (;;) { lua_settop(L, 4); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_pushvalue(L, 3); lua_pushvalue(L, 4); lua_call(L, 2, LUA_MULTRET); if (lua_isnoneornil(L, 6)) return 0; lua_pushvalue(L, 6); lua_replace(L, 4); lua_call(L, lua_gettop(L) - 5, LUA_MULTRET); if (lua_toboolean(L, 5)) return lua_gettop(L) - 5; } } /* func:fold1(init, ) for val... in do init = func(init, val...) end return init end func:fold2(init, ) for val, rest... in do init = func(init, rest...) end return init end 1: self_func 2: init val 3: iter_func 4: base 5: control 6: copy self 7: copy init 8: returned control 6: returned init */ static int f_fold1 (lua_State *L) { lua_settop(L, 5); for (;;) { lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_pushvalue(L, 3); lua_pushvalue(L, 4); lua_pushvalue(L, 5); lua_call(L, 2, LUA_MULTRET); if (lua_isnoneornil(L, 8)) { lua_settop(L, 7); return 1; } lua_pushvalue(L, 8); lua_replace(L, 5); lua_call(L, lua_gettop(L) - 6, 1); lua_replace(L, 2); } } static int f_fold2 (lua_State *L) { lua_settop(L, 5); for (;;) { lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_pushvalue(L, 3); lua_pushvalue(L, 4); lua_pushvalue(L, 5); lua_call(L, 2, LUA_MULTRET); if (lua_isnoneornil(L, 8)) { lua_settop(L, 7); return 1; } lua_pushvalue(L, 8); lua_replace(L, 5); lua_remove(L, 8); lua_call(L, lua_gettop(L) - 6, 1); lua_replace(L, 2); } } /* func:reduce{1,2}(default, ) is like * func:fold{1,2}(init, ) except that the initial * value is taken from the first iteration of the loop. * If the loop fails to produce even one value, the default * argument is returned. Otherwise, default is not used. */ static int f_reduce1 (lua_State *L) { lua_settop(L, 5); lua_pushvalue(L, 3); lua_pushvalue(L, 4); lua_pushvalue(L, 5); lua_call(L, 2, 1); if (lua_isnil(L, -1)) { lua_settop(L, 2); return 1; } lua_pushvalue(L, -1); lua_replace(L, 2); lua_replace(L, 5); return f_fold1(L); } static int f_reduce2 (lua_State *L) { lua_settop(L, 5); lua_pushvalue(L, 3); lua_pushvalue(L, 4); lua_pushvalue(L, 5); lua_call(L, 2, 2); if (lua_isnil(L, -2)) { lua_settop(L, 2); return 1; } lua_replace(L, 2); lua_replace(L, 5); return f_fold2(L); } /* These ones could easily be implemented in terms of fold, but * the direct implementation uses fewer temporary objects. * Unlike the other stuff in this module, these are not * function methods; they're just functions in the collect * library. */ /* collect * .keys => an array of the keys (or control variable, anyway) * .vals => an array of the second iterator return * .pairs => an table of (first) = (second) * .keyset => a set of (first) = true * .valset => a set of (second) = true */ static int c_advance_aux (lua_State *L, int iter, int nr, int cb) { lua_settop(L, cb - 1); lua_pushvalue(L, iter); lua_pushvalue(L, iter+1); lua_pushvalue(L, iter+2); lua_call(L, 2, nr); if (lua_isnoneornil(L, cb)) return 0; lua_pushvalue(L, cb); lua_replace(L, iter+2); return 1; } static int c_keys (lua_State *L) { int index = 0; lua_newtable(L); lua_insert(L, 1); while (c_advance_aux(L, 2, 1, 5)) lua_rawseti(L, 1, ++index); lua_settop(L, 1); return 1; } static int c_vals (lua_State *L) { int index = 0; lua_newtable(L); lua_insert(L, 1); while (c_advance_aux(L, 2, 2, 5)) lua_rawseti(L, 1, ++index); lua_settop(L, 1); return 1; } static int c_pairs (lua_State *L) { lua_newtable(L); lua_insert(L, 1); while (c_advance_aux(L, 2, 2, 5)) lua_rawset(L, 1); lua_settop(L, 1); return 1; } static int c_keyset (lua_State *L) { lua_newtable(L); lua_insert(L, 1); while (c_advance_aux(L, 2, 1, 5)) { lua_pushboolean(L, 1); lua_rawset(L, 1); } lua_settop(L, 1); return 1; } static int c_valset (lua_State *L) { lua_newtable(L); lua_insert(L, 1); while (c_advance_aux(L, 2, 2, 5)) { lua_pushboolean(L, 1); lua_rawset(L, 1); } lua_settop(L, 1); return 1; } /* func:dropping(i) -> function * The returned function drops its ith argument (default 1) and * returns the application of func to the remaining arguments. * This is useful for removing keys from iterators in some of * these iterator methods */ static int f_dropping_aux (lua_State *L) { int i = lua_tointeger(L, lua_upvalueindex(2)); int top = lua_gettop(L); lua_pushvalue(L, lua_upvalueindex(1)); lua_insert(L, 1); if (i <= top) { lua_remove(L, i + 1); --top; } lua_call(L, top, LUA_MULTRET); return lua_gettop(L); } static int f_dropping (lua_State *L) { luaL_checkany(L, 1); lua_settop(L, 2); if (lua_isnil(L, 2)) { lua_pushinteger(L, 1); lua_replace(L, 2); } else { luaL_checknumber(L, 2); } lua_pushcclosure(L, f_dropping_aux, 2); return 1; } /* Yuk. */ static int aux_nups (lua_State *L) { lua_Debug ar; lua_getstack(L, 0, &ar); lua_getinfo(L, "u", &ar); return ar.nups; } static int aux_insertupvalues (lua_State *L, int where) { int i; int nups = aux_nups(L); luaL_checkstack(L, nups, "insert upvalues"); if (where > 0) { for (i = 1; i <= nups; ++i, ++where) { lua_pushvalue(L, lua_upvalueindex(i)); lua_insert(L, where); } } else if (where < 0) { --where; for (i = 1; i <= nups; ++i) { lua_pushvalue(L, lua_upvalueindex(i)); lua_insert(L, where); } } else { for (i = 1; i <= nups; ++i) lua_pushvalue(L, lua_upvalueindex(i)); } return nups; } /* func:partial(...) -> function * The returned function is the original function with the given * arguments "filled in" from the left. */ static int f_partial_aux (lua_State *L) { aux_insertupvalues(L, 1); lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); return lua_gettop(L); } static int f_partial (lua_State *L) { int top = lua_gettop(L); if (top >= LUAI_MAXUPVALUES) { luaL_error(L, "too many arguments, maximum is %d", LUAI_MAXUPVALUES); } if (lua_tocfunction(L, 1) == f_partial_aux) { int i = 1; /* We should find out how many there are, really. */ luaL_checkstack(L, LUAI_MAXUPVALUES, "partial combination"); for (; lua_getupvalue(L, 1, i); ++i) { lua_insert(L, i + 1); } top += i - 2; } lua_pushcclosure(L, f_partial_aux, top); return 1; } /* Building block */ #if 0 static int f_reorder_aux (lua_State *L) { const char *format = lua_tostring(L, lua_upvalueindex(1)); int nups = lua_tointeger(L, lua_upvalueindex(2)); int top = lua_gettop(L); lua_pushvalue(L, lua_upvalueindex(3)); /* The function */ for (;;) { switch (*format++) { case '%': { int base = *format++ - '0'; int ch; for (ch = *format; '0' <= ch && ch <= '9'; ch = *++format) base = base * 10 + ch - '0'; if (ch == '.') { while (*++format == '.'); if (base <= nups) { luaL_checkstack(L, nups - base, ""); for (; base <= nups; ++base) lua_pushvalue(L, lua_upvalueindex(base + 3)); } } else if (base <= nups) lua_pushvalue(L, lua_upvalueindex(base)); else lua_pushnil(L); break; } case '$': { /* duplicate above, but with top */ } case '(': { int func = lua_gettop(L); /* recursive call */ /* get count or ... */ lua_call(L, lua_gettop(L) - func, nups); break; } case ')': { return; } case '\0': { return lua_gettop(L) - top; } } } } #endif /* Functions which take iterators and return iterators */ /* for vals... in f:map() do end * ==> * for temp... in do * local vals... = f(temp...) * * end */ static int f_map_aux (lua_State *L) { lua_settop(L, 0); lua_pushvalue(L, lua_upvalueindex(1)); lua_pushvalue(L, lua_upvalueindex(2)); lua_pushvalue(L, lua_upvalueindex(3)); lua_pushvalue(L, lua_upvalueindex(4)); lua_call(L, 2, LUA_MULTRET); if (lua_isnoneornil(L, 2)) return 0; lua_pushvalue(L, 2); lua_replace(L, lua_upvalueindex(4)); lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); return lua_gettop(L); } static int f_map (lua_State *L) { lua_settop(L, 4); lua_pushcclosure(L, f_map_aux, 4); return 1; } /* Possibly more useful. * for k, vals... in f:mapvals() do end * ==> * for k, temp... in do * local vals... = f(temp...) * * end */ static int f_mapvals_aux (lua_State *L) { lua_pushvalue(L, lua_upvalueindex(2)); lua_insert(L, 1); lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); if (lua_isnoneornil(L, 1)) return 0; lua_pushvalue(L, lua_upvalueindex(1)); lua_insert(L, 2); lua_call(L, lua_gettop(L) - 2, LUA_MULTRET); return lua_gettop(L); } /* Factor this out */ static int f_mapvals (lua_State *L) { lua_settop(L, 4); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_pushcclosure(L, f_mapvals_aux, 2); lua_replace(L, 2); return 3; } /* for vals... in f:filter() do end * ==> * for vals... in do * if f(vals...) then * * end * end */ static int f_filter_aux (lua_State *L) { int i, top; do { lua_settop(L, 2); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_pushvalue(L, lua_upvalueindex(2)); lua_replace(L, 2); /* Obj IterFunc Obj Ctl */ lua_call(L, 2, LUA_MULTRET); top = lua_gettop(L); if (top == 1 || lua_isnil(L, 2)) return 0; luaL_checkstack(L, top, "filtered iterator returned too many results"); lua_pushvalue(L, lua_upvalueindex(1)); for (i = 2; i <= top; ++i) lua_pushvalue(L, i); lua_call(L, top - 1, 1); } while (!lua_toboolean(L, -1)); lua_pop(L, 1); return top - 1; } static int f_filter (lua_State *L) { lua_settop(L, 4); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_pushcclosure(L, f_filter_aux, 2); lua_replace(L, 2); return 3; } /* TODO: * Things to add: * pcall, coroutine.wrap -> both are appropriate function methods * possibly some introspection stuff * something like the new python with modifier: i.e. safely do a call * with a prelude and postlude. */ static const luaL_reg func_funcs[] = { { "first", f_first }, { "foreach", f_foreach }, { "fold1", f_fold1 }, { "fold2", f_fold2 }, { "reduce1", f_reduce1 }, { "reduce2", f_reduce2 }, { "dropping", f_dropping }, { "partial", f_partial }, { "map", f_map }, { "mapvals", f_mapvals }, { "filter", f_filter }, { NULL, NULL } }; static const luaL_reg collect_funcs[] = { { "keys", c_keys }, { "vals", c_vals }, { "pairs", c_pairs }, { "keyset", c_keyset }, { "valset", c_valset }, { NULL, NULL } }; int luaopen_func (lua_State *L) { luaL_register(L, LUA_FUNCLIBNAME, func_funcs); lua_pushcfunction(L, luaopen_func); /* A function */ if (!lua_getmetatable(L, -1)) { lua_createtable(L, 0, 0); lua_pushvalue(L, -3); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); lua_pop(L, 1); } else lua_pop(L, 2); return 1; } int luaopen_collect (lua_State *L) { luaL_register(L, LUA_COLLECTLIBNAME, collect_funcs); return 1; } tagua-1.0-alpha2/src/luaapi/lfunclib.h000066400000000000000000000011251077523320400176330ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LFUNCLIB_H #define LFUNCLIB_H #define LUA_FUNCLIBNAME "func" #define LUA_COLLECTLIBNAME "collect" int luaopen_func (lua_State *L); int luaopen_collect (lua_State *L); #endif /*LFUNCLIB_H*/ tagua-1.0-alpha2/src/luaapi/loader.cpp000066400000000000000000000244411077523320400176440ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include #include #include #include "common.h" #include "loader/image.h" #include "luaapi/imaging.h" #include "luaapi/loader.h" #include "luaapi/options.h" #include "themeinfo.h" namespace LuaApi { const luaL_Reg Loader::lualibs[] = { {"", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {LUA_FUNCLIBNAME, luaopen_func}, {LUA_COLLECTLIBNAME, luaopen_collect}, {NULL, NULL} }; Loader::Loader() : m_error(false) { initialize(0); lua_newtable(m_state); lua_setglobal(m_state, "theme"); } Loader::Loader(::Loader::Context *ctx, const ThemeInfo& theme) : m_error(false) { initialize(ctx); addMetaData(theme); } void Loader::addMetaData(const ThemeInfo& theme) { lua_State* const l = m_state; lua_newtable(l); #define ADD_FIELD_AUX(FIELD_NAME, FIELD) \ lua_pushstring(l, FIELD_NAME); \ lua_pushstring(l, qPrintable(theme.FIELD)); \ lua_settable(l, -3); #define ADD_FIELD(FIELD) ADD_FIELD_AUX(#FIELD, FIELD) ADD_FIELD(name); ADD_FIELD(description); ADD_FIELD_AUX("desktop_file", desktopFile); ADD_FIELD(file_name); lua_pushstring(l, "variants"); lua_newtable(l); for (int i = 0; i < theme.variants.size(); i++) { lua_pushnumber(l, i); lua_pushstring(l, qPrintable(theme.variants[i])); lua_settable(l, -3); } lua_settable(l, -3); #undef ADD_FIELD_AUX #undef ADD_FIELD lua_setglobal(l, "theme"); } void Loader::initialize(::Loader::Context *ctx) { lua_State* l = lua_open(); m_state = l; for (const luaL_Reg *lib = lualibs; lib->func; lib++) { lua_pushcfunction(l, lib->func); lua_pushstring(l, lib->name); lua_call(l, 1, 0); } Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper< ::Loader::Image>::register_class(l); Wrapper< ::Loader::Glyph>::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); Wrapper::register_class(l); lua_pushlightuserdata(l, ctx); lua_setfield(l, LUA_REGISTRYINDEX, LOADING_CONTEXT); lua_pushlightuserdata(l, this); lua_setfield(l, LUA_REGISTRYINDEX, API_LOADER); lua_pushlightuserdata(m_state, &m_curr_dir); lua_setfield(m_state, LUA_REGISTRYINDEX, CURRENT_DIRECTORY); lua_pushcfunction(l, import_func); lua_setglobal(l, "import"); } Loader::~Loader() { lua_close(m_state); } bool Loader::runFile(const QString& file, bool setdir) { QString path = QDir::cleanPath( QDir::isAbsolutePath(file) ? file : m_curr_dir.filePath(file) ); if (!QFile::exists(path)) { // find it in the scripts dir path = KStandardDirs::locate("appdata", "scripts/" + file); } if (!QFile::exists(path)) { // give up return false; } if(setdir) { QFileInfo f_info( path ); m_curr_dir = f_info.dir(); } bool retv; if(luaL_loadfile(m_state, path.toAscii().constData()) == 0) { if(lua_pcall(m_state, 0, LUA_MULTRET, 0) != 0) retv = false; else retv = true; } else retv = false; if(!retv) { m_error = true; m_error_string = QString(lua_tostring(m_state, -1)); lua_pop(m_state, 1); } return retv; } template struct Loader::create_value_data { const QString& key; int size; const LuaValueMap* args; bool allow_nil; T out; create_value_data(const QString& _key, int _size, const LuaValueMap* _args, bool _allow_nil) : key(_key) , size(_size) , args(_args) , allow_nil(_allow_nil) { } }; template T Loader::getValue(const QString& key, int size, const LuaValueMap* args, bool allow_nil) { StackCheck s(m_state); create_value_data data(key, size, args, allow_nil); if(lua_cpcall(m_state, create_value_func, &data) != 0) { m_error = true; m_error_string = QString(lua_tostring(m_state, -1))+"\nsearched key was: "+key; lua_pop(m_state, 1); return T(); } return data.out; } template ::Loader::Glyph Loader::getValue< ::Loader::Glyph>(const QString&, int, const LuaValueMap*, bool); template OptList Loader::getValue(const QString&, int, const LuaValueMap*, bool); template QString Loader::getValue(const QString&, int, const LuaValueMap*, bool); template QStringList Loader::getValue(const QString&, int, const LuaValueMap*, bool); template QImage Loader::getValue(const QString&, int, const LuaValueMap*, bool); template ImageOrMap Loader::getValue(const QString&, int, const LuaValueMap*, bool); template double Loader::getValue(const QString&, int, const LuaValueMap*, bool); template QPointF Loader::getValue(const QString&, int, const LuaValueMap*, bool); template QRectF Loader::getValue(const QString&, int, const LuaValueMap*, bool); template QColor Loader::getValue(const QString&, int, const LuaValueMap*, bool); template QBrush Loader::getValue(const QString&, int, const LuaValueMap*, bool); template QFont Loader::getValue(const QString&, int, const LuaValueMap*, bool); template LuaValueMap Loader::getValue(const QString&, int, const LuaValueMap*, bool); template void Loader::retrieve(create_value_data* d, lua_State *l, int pos) { d->out = *Wrapper::retrieve(l, pos, AssertOk); } template<> void Loader::retrieve(create_value_data* d, lua_State *l, int pos) { d->out = lua_tonumber(l, pos); } template<> void Loader::retrieve(create_value_data* d, lua_State *l, int pos) { d->out = lua_tostring(l, pos); } template<> void Loader::retrieve(create_value_data* d, lua_State *l, int pos) { d->out = Wrapper::get(l, pos); } template<> void Loader::retrieve(create_value_data* d, lua_State *l, int pos) { d->out = Wrapper::get(l, pos); } template<> void Loader::retrieve(create_value_data* d, lua_State *l, int pos) { if(lua_isstring(l, pos)) d->out << QString(lua_tostring(l, -1)); else if(lua_istable(l, pos)) { lua_pushnil(l); while (lua_next(l, pos<0 ? pos-1 : pos) != 0) { d->out << QString(lua_tostring(l, -1)); lua_pop(l, 1); } } else luaL_error(l, "Can't convert to a QStringList (not string nor table)"); } template<> void Loader::retrieve(create_value_data* d, lua_State *l, int pos) { if(lua_istable(l, pos)) { lua_pushnil(l); while (lua_next(l, pos<0 ? pos-1 : pos) != 0) { QString key = lua_tostring(l, -2); if(QPointF *res = Wrapper::retrieve(l, -1, Check)) d->out[key] = *res; else if(QRectF *res = Wrapper::retrieve(l, -1, Check)) d->out[key] = *res; else d->out[key] = lua_tonumber(l, -1); lua_pop(l, 1); } } else luaL_error(l, "Can't convert to a LuaValueMap (not table)"); } template<> void Loader::retrieve(create_value_data* d, lua_State *l, int pos) { ::Loader::Image *retv = Wrapper< ::Loader::Image>::retrieve(l, pos, AssertOk); d->out = retv->image(); } template<> void Loader::retrieve(create_value_data* d, lua_State *l, int pos) { if(::Loader::Image *img = Wrapper< ::Loader::Image>::retrieve(l, pos)) d->out = img->image(); else if(lua_istable(l, pos)) { //collect the images in this way to avoid leaking memory if Wrapper::retrieve raises an exception d->out = ImageMap(); ImageMap& out = boost::get(d->out); lua_pushnil(l); while (lua_next(l, pos<0 ? pos-1 : pos) != 0) { QRectF *rect = Wrapper::retrieve(l, -2, AssertOk); ::Loader::Image *img = Wrapper< ::Loader::Image>::retrieve(l, -1, AssertOk); QRect r = rect->toRect(); out[rect->toRect()] = img->image(); lua_pop(l, 1); } } else luaL_error(l, "Can't convert to a ImageOrMap (not image nor table)"); } template int Loader::create_value_func(lua_State *l) { StackCheck s(l, -1); create_value_data* data = reinterpret_cast*>(lua_touserdata(l, -1)); lua_pop(l, 1); lua_getglobal(l, "theme"); lua_getfield(l, -1, data->key.toAscii().constData()); lua_remove(l, -2); // If it is a function, call it if(lua_isfunction(l, -1)) { int nparams = 0; if(data->size) { lua_pushnumber(l, data->size); nparams++; } if(data->args) { lua_pushvaluemap(l, data->args); nparams++; } lua_call(l, nparams, 1); } // retrieve value if (!lua_isnil(l, -1)) { retrieve(data, l, -1); } else if (!data->allow_nil) { luaL_error(l, "No such entry: %s", data->key.toAscii().constData()); } lua_pop(l, 1); return 0; } int Loader::import_func(lua_State *l) { lua_getfield(l, LUA_REGISTRYINDEX, API_LOADER); Loader* api = reinterpret_cast(lua_touserdata(l, -1)); lua_pop(l, 1); int n = lua_gettop(l); if (n != 1) luaL_error(l, "Wrong argument count for \"import\""); QString file(lua_tostring(l, 1)); lua_pop(l, n); if (!api->runFile(file, false)) { luaL_error(l, "Error importing \"%s\":\n%s", file.toAscii().constData(), api->errorString().toAscii().constData() ); } return 0; } } // namespace LuaLoader tagua-1.0-alpha2/src/luaapi/loader.h000066400000000000000000000042131077523320400173040ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LUAAPI__LOADER_H #define LUAAPI__LOADER_H #include #include #include #include #include #include "loader/image.h" #include "luaapi/luavalue.h" #include "option.h" class lua_State; class luaL_Reg; class ThemeInfo; namespace Loader { class Context; } namespace LuaApi { class RectLess { public: bool operator()(const QRect& a, const QRect& b) { return a.x() != b.x() ? a.x() < b.x() : a.y() != b.y() ? a.y() < b.y() : a.width() != b.width() ? a.width() < b.width() : a.height() < b.height(); } }; typedef std::map ImageMap; typedef boost::variant ImageOrMap; class Loader { bool m_error; QString m_error_string; lua_State* m_state; QDir m_curr_dir; static const luaL_Reg lualibs[]; template struct create_value_data; template static void retrieve(create_value_data*, lua_State *l, int pos); template static int create_value_func(lua_State *l); static int import_func(lua_State* l); void initialize(::Loader::Context *ctx); /** * Add the theme table to the environment, with all theme metadata. */ void addMetaData(const ThemeInfo& theme); public: Loader(::Loader::Context *ctx, const ThemeInfo& theme); Loader(); ~Loader(); lua_State* state() const { return m_state; } bool runFile(const QString& file, bool set_dir = true); template T getValue(const QString& key, int size = 0, const LuaValueMap* args = NULL, bool allow_nil = false); bool error() { return m_error; } void clearError() { m_error = false; } QString errorString() { return m_error_string; } }; } //end namespace LuaApi #endif // LUAAPI__LOADERAPI_H tagua-1.0-alpha2/src/luaapi/luahl.cpp000066400000000000000000000215111077523320400174760ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "luahl.h" #include "genericwrapper.h" #include #include #include "common.h" #include "hline.h" #include "imaging.h" #define ARG_CHECK(exp, func) \ if (n != (exp)) luaL_error(l, "Wrong argument count for %s::%s", class_name() ,#func) namespace LuaApi { template <> class Wrapper : public GenericWrapper { public: static const char* class_name() { return "HLine"; } PROPERTY_RO(length, length, number); static void create_index_table(lua_State* l) { SET_PROPERTY_RO(l, length); set_method(l, &mid, "mid"); set_method(l, &set_bold, "set_bold"); set_method(l, &set_italic, "set_italic"); set_method(l, &set_color, "set_color"); set_method(l, &clone, "clone"); set_method(l, &extract, "extract"); set_method(l, &append, "append"); set_method(l, &dump, "dump"); } static int constructor(lua_State* l) { const int n = lua_gettop(l); ARG_CHECK(1, HLine); const char* str = lua_tostring(l, 1); lua_pop(l, n); HLine* hline = new HLine(str, QTextCharFormat()); allocate(l, hline); return 1; } /** * Release the object at @a index from Lua's ownership. */ static void release(lua_State* l, int index) { StackCheck check(l); lua_getmetatable(l, index); lua_pushstring(l, "__gc"); lua_pushnil(l); lua_settable(l, -3); lua_pop(l, 1); } static int clone(lua_State* l) { const int n = lua_gettop(l); ARG_CHECK(1, clone); HLine* self = retrieve(l, 1, AssertOk); lua_pop(l, n); allocate(l, new HLine(*self)); return 1; } static int extract(lua_State* l) { const int n = lua_gettop(l); ARG_CHECK(3, extract); HLine* self = retrieve(l, 1, AssertOk); int begin = static_cast(lua_tonumber(l, 2)); int end = static_cast(lua_tonumber(l, 3)); lua_pop(l, n); allocate(l, self->extract(begin, end)); return 1; } static int append(lua_State* l) { const int n = lua_gettop(l); ARG_CHECK(4, append); HLine* self = retrieve(l, 1, AssertOk); HLine* other = retrieve(l, 2, AssertOk); int begin = static_cast(lua_tonumber(l, 3)); int end = static_cast(lua_tonumber(l, 4)); lua_pop(l, n); allocate(l, self->append(*other, begin, end)); return 1; } static int mid(lua_State* l) { const int n = lua_gettop(l); ARG_CHECK(3, mid); HLine* self = retrieve(l, 1, AssertOk); int from = static_cast(lua_tonumber(l, 2)); int to = static_cast(lua_tonumber(l, 3)); lua_pop(l, n); lua_pushstring(l, qPrintable(self->mid(from, to))); return 1; } static int set_bold(lua_State* l) { const int n = lua_gettop(l); ARG_CHECK(4, set_bold); HLine* self = retrieve(l, 1, AssertOk); int from = static_cast(lua_tonumber(l, 2)); int to = static_cast(lua_tonumber(l, 3)); bool value = lua_toboolean(l, 4); lua_pop(l, n); self->setBold(from, to, value); return 0; } static int set_italic(lua_State* l) { const int n = lua_gettop(l); ARG_CHECK(4, set_italic); HLine* self = retrieve(l, 1, AssertOk); int from = static_cast(lua_tonumber(l, 2)); int to = static_cast(lua_tonumber(l, 3)); bool value = lua_toboolean(l, 4); lua_pop(l, n); self->setItalic(from, to, value); return 0; } static int set_color(lua_State* l) { const int n = lua_gettop(l); ARG_CHECK(4, set_bold); HLine* self = retrieve(l, 1, AssertOk); int from = static_cast(lua_tonumber(l, 2)); int to = static_cast(lua_tonumber(l, 3)); QColor color = Wrapper::get(l, 4); lua_pop(l, n); self->setColor(from, to, color); return 0; } static int dump(lua_State* l) { const int n = lua_gettop(l); ARG_CHECK(1, dump); HLine* self = retrieve(l, 1, AssertOk); lua_pop(l, n); self->dump(); return 0; } }; static const luaL_Reg lualibs[] = { {"", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {NULL, NULL} }; LUALIB_API void luaL_openlibs (lua_State*) { } Api::Api() { lua_State* l = lua_open(); m_state = l; for (const luaL_Reg *lib = lualibs; lib->func; lib++) { lua_pushcfunction(l, lib->func); lua_pushstring(l, lib->name); lua_call(l, 1, 0); } Wrapper::register_class(l); Wrapper::register_class(l); } Api::~Api() { lua_close(m_state); } void Api::runFile(const char* file) { //luaL_dofile(m_state, file); if (QFile(file).exists()) { if(luaL_loadfile(m_state, file) == 0) pcall(0, LUA_MULTRET); else { kDebug() << "LOADFILE FOR " << file << " FAILED"; kDebug() << lua_tostring(m_state, -1); } } else kDebug() << "FILE " << file << " DOES NOT EXIST"; } void Api::pcall(int nArgs, int nResults) { if (lua_pcall(m_state, nArgs, nResults, 0) != 0) { kDebug() << "RUNTIME ERROR: " << lua_tostring(m_state, -1); } } #if 0 int Api::create_line(lua_State* l) { const char* line = lua_tostring(l, -1); lua_pop(l, 1); lua_getglobal(l, "Text"); Wrapper::allocate(l, new HLine(line, QTextCharFormat())); if (lua_pcall(l, 1, 1, 0) != 0) kDebug() << "ERROR INSIDE create_line"; return 1; } void Api::loadTest() { lua_pushcfunction(m_state, &create_line); lua_setglobal(m_state, "create_line"); } #endif HLine* Api::highlight(const QString& text) { // iterate through patterns StackCheck check(m_state); lua_getglobal(m_state, "__patterns__"); if (lua_istable(m_state, -1)) { lua_pushnil(m_state); while (lua_next(m_state, -2) != 0) { int i = static_cast(lua_tonumber(m_state, -2)); lua_pushstring(m_state, "pattern"); lua_gettable(m_state, -2); QString pattern(lua_tostring(m_state, -1)); QRegExp re(pattern.replace("%", "\\")); lua_pop(m_state, 2); std::pair res = runEvent(text, i, re); if (res.first) { lua_pop(m_state, 2); return res.second; } } } lua_pop(m_state, 1); return new HLine(text, QTextCharFormat()); } void Api::pushpair(int x, int y) { lua_newtable(m_state); lua_pushstring(m_state, "from"); lua_pushnumber(m_state, x); lua_settable(m_state, -3); lua_pushstring(m_state, "to"); lua_pushnumber(m_state, y); lua_settable(m_state, -3); } std::pair Api::runEvent(const QString& text, int eventIndex, QRegExp& pattern) { StackCheck check(m_state); // match regexp against text int index = pattern.indexIn(text); if (index == -1) return std::pair(false, 0); lua_getglobal(m_state, "__run_event__"); if (!lua_isfunction(m_state, -1)) { kDebug() << "** ERROR: __run_event__ is corrupted (type = " << lua_typename(m_state, lua_type(m_state, -1)) << ") **"; lua_pop(m_state, 1); return std::pair(false, 0); } // event lua_getglobal(m_state, "__patterns__"); if (!lua_istable(m_state, -1)) { kDebug() << "** ERROR: __patterns__ is corrupted **"; lua_pop(m_state, 2); return std::pair(false, 0); } lua_pushnumber(m_state, eventIndex); lua_gettable(m_state, -2); lua_remove(m_state, -2); // str lua_pushstring(m_state, qPrintable(text)); // match pushpair(index, index + pattern.matchedLength()); // ref lua_newtable(m_state); const int n = pattern.numCaptures(); for (int i = 1; i <= n; i++) { int pos = pattern.pos(i); lua_pushnumber(m_state, i); pushpair(pos, pos + pattern.cap(i).length()); lua_settable(m_state, -3); } // state lua_newtable(m_state); // TODO: fill state pcall(5, 1); if (lua_isnil(m_state, -1)) { lua_pop(m_state, 1); return std::pair(true, 0); } { lua_pushstring(m_state, "from"); lua_gettable(m_state, -2); int from = static_cast(lua_tonumber(m_state, -1)); lua_pop(m_state, 1); lua_pushstring(m_state, "to"); lua_gettable(m_state, -2); int to = static_cast(lua_tonumber(m_state, -1)); lua_pop(m_state, 1); lua_pushstring(m_state, "line"); lua_gettable(m_state, -2); HLine* res = Wrapper::retrieve(m_state, -1, AssertOk); if (from == 0 && to == 0) Wrapper::release(m_state, -1); else res = res->extract(from, to); lua_pop(m_state, 2); return std::make_pair(true, res); } } } // namespace LuaApi tagua-1.0-alpha2/src/luaapi/luahl.h000066400000000000000000000016201077523320400171420ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LUAHL_H #define LUAHL_H #include #include class lua_State; class HLine; namespace LuaApi { class Api { lua_State* m_state; void pcall(int nArgs, int nResults); void pushpair(int x, int y); std::pair runEvent(const QString& text, int eventIndex, QRegExp& pattern); public: Api(); ~Api(); lua_State* state() const { return m_state; } void runFile(const char* file); HLine* highlight(const QString& text); }; } // namespace LuaHl #endif // LUAHL_H tagua-1.0-alpha2/src/luaapi/luavalue.cpp000066400000000000000000000022031077523320400202040ustar00rootroot00000000000000/* Copyright (c) 2006-2008 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "luavalue.h" #include #include "imaging.h" namespace LuaApi { void lua_pushvalue(lua_State* l, const LuaValue& value) { if(const double* v = boost::get(&value)) lua_pushnumber(l, *v); else if(const QPointF* v = boost::get(&value)) Wrapper::create(l, *v); else if(const QRectF* v = boost::get(&value)) Wrapper::create(l, *v); else kError() << "Unknown variant type!"; } void lua_pushvaluemap(lua_State* l, const LuaValueMap* valuemap) { lua_newtable(l); // metatable for(LuaValueMap::const_iterator it = valuemap->begin(); it != valuemap->end(); ++it) { lua_pushvalue(l, it.value()); lua_setfield(l, -2, it.key().toAscii().constData()); } } } //end namespace LuaApi tagua-1.0-alpha2/src/luaapi/luavalue.h000066400000000000000000000015221077523320400176540ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LUAAPI__LUAVALUE_H #define LUAAPI__LUAVALUE_H #include #include #include class QPointF; class QRectF; class lua_State; namespace LuaApi { typedef boost::variant LuaValue; typedef QMap LuaValueMap; void lua_pushvalue(lua_State* l, const LuaValue& value); void lua_pushvaluemap(lua_State* l, const LuaValueMap* valuemap); } //end namespace LuaApi #endif //LUAAPI__LUAVALUE_H tagua-1.0-alpha2/src/luaapi/options.cpp000066400000000000000000000367401077523320400200760ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "options.h" #include #include "luaapi/loader.h" namespace LuaApi { //BEGIN Wrapper ------------------------------------------------------- const char* Wrapper::class_name() { return "OptList"; } int Wrapper::to_string(lua_State* l) { OptList r = *retrieve(l, 1, AssertOk); QString s; for(int i=0;iname(); s = "list["+s+"]"; lua_pop(l, 1); lua_pushstring(l, s.toAscii().constData()); return 1; } int Wrapper::newindex_event(lua_State* l) { lua_pop(l,3); luaL_error(l, "OptList cannot be modified after being constructed!!!"); return 0; } int Wrapper::index_event(lua_State* l) { const char *k = lua_tostring(l, -1); OptList& list = *retrieve(l, -2); lua_pop(l,2); for(int i=0; iname() == k) { if(BoolOptPtr p = boost::dynamic_pointer_cast(list[i])) GenericWrapperByValue::create(l, p); else if(IntOptPtr p = boost::dynamic_pointer_cast(list[i])) GenericWrapperByValue::create(l, p); else if(StringOptPtr p = boost::dynamic_pointer_cast(list[i])) GenericWrapperByValue::create(l, p); else if(UrlOptPtr p = boost::dynamic_pointer_cast(list[i])) GenericWrapperByValue::create(l, p); else if(ColorOptPtr p = boost::dynamic_pointer_cast(list[i])) GenericWrapperByValue::create(l, p); else if(FontOptPtr p = boost::dynamic_pointer_cast(list[i])) GenericWrapperByValue::create(l, p); else if(ComboOptPtr p = boost::dynamic_pointer_cast(list[i])) GenericWrapperByValue::create(l, p); else if(SelectOptPtr p = boost::dynamic_pointer_cast(list[i])) GenericWrapperByValue::create(l, p); else luaL_error(l, "WFT?"); return 1; } } luaL_error(l, "No item with name %s", k); return 0; } void Wrapper::create_index_table(lua_State* l) { set_meta_method(l, &to_string, "__tostring"); set_meta_method(l, &newindex_event, "__newindex"); set_meta_method(l, &index_event, "__index"); Comparable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); if(n!=1) luaL_error(l, "Wrong parameter list for OptList constructor"); OptList list; lua_pushnil(l); while (lua_next(l, -2) != 0) { if(BoolOptPtr *p = Wrapper::retrieve(l, -1)) list << BoolOptPtr(*p); else if(IntOptPtr *p = Wrapper::retrieve(l, -1)) list << IntOptPtr(*p); else if(StringOptPtr *p = Wrapper::retrieve(l, -1)) list << StringOptPtr(*p); else if(UrlOptPtr *p = Wrapper::retrieve(l, -1)) list << UrlOptPtr(*p); else if(ColorOptPtr *p = Wrapper::retrieve(l, -1)) list << ColorOptPtr(*p); else if(FontOptPtr *p = Wrapper::retrieve(l, -1)) list << FontOptPtr(*p); else if(ComboOptPtr *p = Wrapper::retrieve(l, -1)) list << ComboOptPtr(*p); else if(SelectOptPtr *p = Wrapper::retrieve(l, -1)) list << SelectOptPtr(*p); else luaL_error(l, "Wrong item in list for OptList constructor"); lua_pop(l, 1); } lua_pop(l, n); // for(int i=0;i::to_string(lua_State* l) { BoolOptList r = *retrieve(l, 1, AssertOk); QString s; for(int i=0;iname(); s = "bool_list["+s+"]"; lua_pop(l, 1); lua_pushstring(l, s.toAscii().constData()); return 1; } int Wrapper::newindex_event(lua_State* l) { lua_pop(l,3); luaL_error(l, "BoolOptList cannot be modified after being constructed!!!"); return 0; } int Wrapper::index_event(lua_State* l) { const char *k = lua_tostring(l, -1); BoolOptList& list = *retrieve(l, -2); lua_pop(l,2); for(int i=0; iname() == k) { GenericWrapperByValue::create(l, list[i]); return 1; } } luaL_error(l, "No bool item with name %s", k); return 0; } void Wrapper::create_index_table(lua_State* l) { set_meta_method(l, &to_string, "__tostring"); set_meta_method(l, &newindex_event, "__newindex"); set_meta_method(l, &index_event, "__index"); Comparable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); if(n!=1) luaL_error(l, "Wrong parameter list for BoolOptList constructor"); BoolOptList list; lua_pushnil(l); while (lua_next(l, -2) != 0) { list << *Wrapper::retrieve(l, -1, AssertOk); lua_pop(l, 1); } lua_pop(l, n); create(l, list); return 1; } //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- const char* Wrapper::class_name() { return "BoolOpt"; } int Wrapper::to_string(lua_State* l) { BoolOptPtr r = *retrieve(l, 1, AssertOk); lua_pop(l, 1); lua_pushfstring(l, "bool[%s] = %s", r->name().toAscii().constData(), r->value()?"true":"false" ); return 1; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RO(l, name); SET_PROPERTY_RO(l, label); SET_PROPERTY_RO(l, sub_options); SET_PROPERTY_RW(l, value); set_meta_method(l, &to_string, "__tostring"); Comparable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); if(n<3 || n>4) luaL_error(l, "Wrong parameter list for BoolOpt constructor"); const char* name = lua_tostring(l, 1); const char* label = lua_tostring(l, 2); bool value = lua_toboolean(l, 3); OptList sub_opt; if(n==4) sub_opt = *Wrapper::retrieve(l, 4, AssertOk); lua_pop(l, n); create(l, BoolOptPtr(new BoolOpt(name, label, value, sub_opt))); return 1; } //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- const char* Wrapper::class_name() { return "IntOpt"; } int Wrapper::to_string(lua_State* l) { IntOptPtr r = *retrieve(l, 1, AssertOk); lua_pop(l, 1); lua_pushfstring(l, "int[%s] = %d", r->name().toAscii().constData(), r->value() ); return 1; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RO(l, name); SET_PROPERTY_RO(l, label); SET_PROPERTY_RO(l, min); SET_PROPERTY_RO(l, max); SET_PROPERTY_RW(l, value); SET_PROPERTY_RO(l, visualization); set_meta_method(l, &to_string, "__tostring"); Comparable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); if(n<5 || n>6) luaL_error(l, "Wrong parameter list for IntOpt constructor"); const char* name = lua_tostring(l, 1); const char* label = lua_tostring(l, 2); int value = int(lua_tonumber(l, 3)); int min = int(lua_tonumber(l, 4)); int max = int(lua_tonumber(l, 5)); IntOpt::Visualization visualization = IntOpt::SpinBox; if (n > 5) { QString vstring = lua_tostring(l, 6); if (vstring.compare("slider", Qt::CaseInsensitive) == 0) { visualization = IntOpt::Slider; } else if (vstring.compare("spinbox", Qt::CaseInsensitive) != 0) { kError() << "No such visualization `" << vstring << "'. Using `spinbox' instead"; } } lua_pop(l, n); create(l, IntOptPtr(new IntOpt(name, label, value, min, max, visualization)) ); return 1; } //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- const char* Wrapper::class_name() { return "StringOpt"; } int Wrapper::to_string(lua_State* l) { StringOptPtr r = *retrieve(l, 1, AssertOk); lua_pop(l, 1); lua_pushfstring(l, "string[%s] = %s", r->name().toAscii().constData(), r->value().toAscii().constData() ); return 1; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RO(l, name); SET_PROPERTY_RO(l, label); SET_PROPERTY_RW(l, value); set_meta_method(l, &to_string, "__tostring"); Comparable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); if(n!=3) luaL_error(l, "Wrong parameter list for StringOpt constructor"); const char* name = lua_tostring(l, 1); const char* label = lua_tostring(l, 2); const char* value = lua_tostring(l, 3); lua_pop(l, n); create(l, StringOptPtr(new StringOpt(name, label, value))); return 1; } //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- const char* Wrapper::class_name() { return "UrlOpt"; } int Wrapper::to_string(lua_State* l) { UrlOptPtr r = *retrieve(l, 1, AssertOk); lua_pop(l, 1); lua_pushfstring(l, "url[%s] = %s", r->name().toAscii().constData(), r->value().toAscii().constData() ); return 1; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RO(l, name); SET_PROPERTY_RO(l, label); SET_PROPERTY_RW(l, value); set_meta_method(l, &to_string, "__tostring"); Comparable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); if(n!=3) luaL_error(l, "Wrong parameter list for UrlOpt constructor"); const char* name = lua_tostring(l, 1); const char* label = lua_tostring(l, 2); const char* value = lua_tostring(l, 3); lua_pop(l, n); create(l, UrlOptPtr(new UrlOpt(name, label, file_path(l, value) ))); return 1; } //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- const char* Wrapper::class_name() { return "ColorOpt"; } int Wrapper::to_string(lua_State* l) { ColorOptPtr r = *retrieve(l, 1, AssertOk); lua_pop(l, 1); lua_pushfstring(l, "color[%s] = %s", r->name().toAscii().constData(), r->value().name().toAscii().constData() ); return 1; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RO(l, name); SET_PROPERTY_RO(l, label); SET_PROPERTY_RW(l, value); set_meta_method(l, &to_string, "__tostring"); Comparable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); if(n!=3) luaL_error(l, "Wrong parameter list for ColorOpt constructor"); const char* name = lua_tostring(l, 1); const char* label = lua_tostring(l, 2); QColor value = Wrapper::get(l, 3); lua_pop(l, n); create(l, ColorOptPtr(new ColorOpt(name, label, value))); return 1; } //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- const char* Wrapper::class_name() { return "FontOpt"; } int Wrapper::to_string(lua_State* l) { FontOptPtr r = *retrieve(l, 1, AssertOk); lua_pop(l, 1); lua_pushfstring(l, "font[%s] = %s", r->name().toAscii().constData(), r->value().toString().toAscii().constData() ); return 1; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RO(l, name); SET_PROPERTY_RO(l, label); SET_PROPERTY_RW(l, value); set_meta_method(l, &to_string, "__tostring"); Comparable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); if(n!=3) luaL_error(l, "Wrong parameter list for FontOpt constructor"); const char* name = lua_tostring(l, 1); const char* label = lua_tostring(l, 2); QFont* value = Wrapper::retrieve(l, 3, AssertOk); lua_pop(l, n); create(l, FontOptPtr(new FontOpt(name, label, *value))); return 1; } //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- const char* Wrapper::class_name() { return "ComboOpt"; } int Wrapper::to_string(lua_State* l) { ComboOptPtr r = *retrieve(l, 1, AssertOk); lua_pop(l, 1); lua_pushfstring(l, "combo[%s] = %s", r->name().toAscii().constData(), r->values().join(",").toAscii().constData() ); return 1; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RO(l, name); SET_PROPERTY_RO(l, label); SET_PROPERTY_RW(l, selected); set_meta_method(l, &to_string, "__tostring"); Comparable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); if(n<3 || n>4) luaL_error(l, "Wrong parameter list for ComboOpt constructor"); const char* name = lua_tostring(l, 1); const char* label = lua_tostring(l, 2); int selected = n==4 ? int(lua_tonumber(l, 4)) : 0; QStringList values; lua_pushnil(l); while (lua_next(l, 3) != 0) { values << lua_tostring(l, -1); lua_pop(l, 1); } lua_pop(l, n); create(l, ComboOptPtr(new ComboOpt(name, label, values, selected))); return 1; } //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- const char* Wrapper::class_name() { return "SelectOpt"; } int Wrapper::to_string(lua_State* l) { SelectOptPtr r = *retrieve(l, 1, AssertOk); lua_pop(l, 1); lua_pushfstring(l, "select[%s] = !!", r->name().toAscii().constData() ); return 1; } void Wrapper::create_index_table(lua_State* l) { SET_PROPERTY_RO(l, name); SET_PROPERTY_RO(l, label); SET_PROPERTY_RO(l, options); SET_PROPERTY_RW(l, selected); set_meta_method(l, &to_string, "__tostring"); Comparable::register_in_index_table(l); } int Wrapper::constructor(lua_State* l) { const int n = lua_gettop(l); if(n<3 || n>4) luaL_error(l, "Wrong parameter list for SelectOpt constructor"); const char* name = lua_tostring(l, 1); const char* label = lua_tostring(l, 2); BoolOptList values = *Wrapper::retrieve(l, 3, AssertOk); int selected = n==4 ? int(lua_tonumber(l, 4)) : 0; lua_pop(l, n); create(l, SelectOptPtr(new SelectOpt(name, label, values, selected))); return 1; } //END Wrapper --------------------------------------------------------- } //end namespace luaapi tagua-1.0-alpha2/src/luaapi/options.h000066400000000000000000000152101077523320400175300ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LUAAPI__OPTIONS_H #define LUAAPI__OPTIONS_H #include "option.h" #include "luaapi/genericwrapper.h" #include "luaapi/imaging.h" namespace LuaApi { //BEGIN Wrapper ------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); static int newindex_event(lua_State* l); static int index_event(lua_State* l); }; //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); static int newindex_event(lua_State* l); static int index_event(lua_State* l); }; //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RO_QSTRING(name, get()->name) PROPERTY_RO_QSTRING(label, get()->label) PROPERTY_RO_CLASS(sub_options, get()->subOptions, OptList) PROPERTY_RW(value, get()->value, get()->setValue, boolean) static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RO_QSTRING(name, get()->name) PROPERTY_RO_QSTRING(label, get()->label) PROPERTY_RO_TYPE(min, get()->min, number, int) PROPERTY_RO_TYPE(max, get()->max, number, int) PROPERTY_RW_TYPE(value, get()->value, get()->setValue, number, int) static int get_visualization(lua_State* l) { IntOpt::Visualization vis = retrieve(l, 1, DontCheck)->get()->visualization(); switch (vis) { case IntOpt::SpinBox: lua_pushstring(l, "spinbox"); break; case IntOpt::Slider: lua_pushstring(l, "slider"); break; } return 1; } static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RO_QSTRING(name, get()->name) PROPERTY_RO_QSTRING(label, get()->label) PROPERTY_RW_QSTRING(value, get()->value, get()->setValue) static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RO_QSTRING(name, get()->name) PROPERTY_RO_QSTRING(label, get()->label) PROPERTY_RW_QSTRING(value, get()->value, get()->setValue) static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RO_QSTRING(name, get()->name) PROPERTY_RO_QSTRING(label, get()->label) PROPERTY_RW_CLASS(value, get()->value, get()->setValue, QColor) static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RO_QSTRING(name, get()->name) PROPERTY_RO_QSTRING(label, get()->label) PROPERTY_RW_CLASS(value, get()->value, get()->setValue, QFont) static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RO_QSTRING(name, get()->name) PROPERTY_RO_QSTRING(label, get()->label) PROPERTY_RW_TYPE(selected, get()->selected, get()->setSelected, number, int) static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper --------------------------------------------------------- //BEGIN Wrapper ------------------------------------------------------- template <> class Wrapper : public GenericWrapperByValue { public: PROPERTY_RO_QSTRING(name, get()->name) PROPERTY_RO_QSTRING(label, get()->label) PROPERTY_RO_CLASS(options, get()->options, BoolOptList) PROPERTY_RW_TYPE(selected, get()->selected, get()->setSelected, number, int) static const char* class_name(); static int to_string(lua_State* l); static void create_index_table(lua_State* l); static int constructor(lua_State* l); }; //END Wrapper --------------------------------------------------------- } //end namespace luaapi #endif //LUAAPI__OPTIONS_H tagua-1.0-alpha2/src/main.cpp000066400000000000000000000037241077523320400160500ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include #include #include #include #include "mainwindow.h" #include "crash.h" static const char description[] = "A generic board game interface"; static const char version[] = "0.9.1"; void trap() { printf("Press enter to quit.\n"); char dummy[4096]; fgets(dummy, 4096, stdin); } int main(int argc, char **argv) { KAboutData about( "tagua", 0, ki18n("Tagua"), version, ki18n(description), KAboutData::License_GPL, ki18n("(C) 2006 Paolo Capriotti, Maurizio Monge") ); about.addAuthor(ki18n("Paolo Capriotti"), KLocalizedString(), "p.capriotti@gmail.com"); about.addAuthor(ki18n("Maurizio Monge"), KLocalizedString(), "p.capriotti@gmail.com"); about.addCredit(ki18n("Jani Huhtanen"), ki18n("Gaussian blur code")); about.addCredit(ki18n("Rici Lake"), ki18n("funclib lua library")); about.addCredit(ki18n("Riccardo Iaconelli"), ki18n("Various fixes and cleanups")); about.addCredit(ki18n("Yann Dirson"), ki18n("Shogi related patches")); about.addCredit(ki18n("Pieter Stouten"), ki18n("Allowed free use of images on shogi.net")); KCmdLineOptions options; options.add("+variant", ki18n("Initial variant")); KCmdLineArgs::init(argc, argv, &about); KCmdLineArgs::addCmdLineOptions(options); KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); QString variant = args->count() > 0 ? args->arg(0) : "chess"; KApplication app; MainWindow* widget = new MainWindow(variant); widget->show(); return app.exec(); } tagua-1.0-alpha2/src/mainanimation.cpp000066400000000000000000000026401077523320400177440ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "mainanimation.h" using namespace boost; MainAnimation::MainAnimation(double speed) : AnimationGroup(true) , m_translate(0) , m_speed(speed) , m_delay(20) { m_active = true; connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick())); } void MainAnimation::addAnimation(const shared_ptr& a) { if (!m_timer.isActive()) { m_timer.start(m_delay); m_time.restart(); } AnimationGroup::addPostAnimation(a); tick(); } void MainAnimation::stop() { AnimationGroup::stop(); } void MainAnimation::tick() { animationAdvance(static_cast(m_time.elapsed() * m_speed) + m_translate); if (empty()) { // no more animations, stop the clock! m_timer.stop(); } } void MainAnimation::setSpeed(double speed) { int e = m_time.elapsed(); m_translate = int((e*m_speed + m_translate) - e*speed); m_speed = speed; } void MainAnimation::setDelay(int delay) { m_timer.setInterval(m_delay = delay); } MainAnimation& MainAnimation::global() { static MainAnimation instance; return instance; } tagua-1.0-alpha2/src/mainanimation.h000066400000000000000000000026421077523320400174130ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef MAINANIMATION_H #define MAINANIMATION_H #include #include #include #include "animation.h" #include /** * @a MainAnimation is a persistent animation used to activate * all chessboard animations. */ class MainAnimation : public QObject, protected AnimationGroup { Q_OBJECT QTime m_time; QTimer m_timer; int m_translate; double m_speed; int m_delay; public: MainAnimation(double speed = 1.0); /** * Activate the animation @a a. */ void addAnimation(const boost::shared_ptr& a); /** * Stop all animations. */ void stop(); /** * Sets the overall speed factor (default is 1.0). * This function is implemented to avoid time gaps. */ void setSpeed(double speed); /** * Sets the frame delay. */ void setDelay(int delay); /** * Return a global MasterAnimation, i.e. not tied to a particular board. */ static MainAnimation& global(); protected Q_SLOTS: void tick(); }; #endif // MAINANIMATION_H tagua-1.0-alpha2/src/mainwindow.cpp000066400000000000000000000532161077523320400173010ustar00rootroot00000000000000/* Copyright (c) 2006-2008 Paolo Capriotti (c) 2006-2007 Maurizio Monge 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. */ #include "mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "actioncollection.h" #include "chesstable.h" #include "console.h" #include "clock.h" #include "newgame.h" #include "variants.h" #include "gameinfo.h" #include "controllers/editgame.h" #include "controllers/editposition.h" #include "engineinfo.h" #include "movelist_table.h" #include "icsconnection.h" #include "qconnect.h" #include "mastersettings.h" #include "flash.h" #include "foreach.h" #include "pgnparser.h" #include "pref_highlight.h" #include "pref_preferences.h" #include "tabwidget.h" using namespace Qt; using namespace boost; MainWindow::~MainWindow() { delete console; qApp->quit(); } MainWindow::MainWindow(const QString& variant) : KXmlGuiWindow(0) , m_ui(actionCollection()) { setObjectName("tagua_main"); m_main = new TabWidget(this); m_main->setTabBarHidden(true); setCentralWidget(m_main); m_movelist_stack = new QStackedWidget; connect(m_main, SIGNAL(currentChanged(int)), this, SLOT(changeTab(int))); connect(m_main, SIGNAL(closeTab()), this, SLOT(closeTab())); movelist_dock = new QDockWidget(this); movelist_dock->setWidget(m_movelist_stack); movelist_dock->setWindowTitle(i18n("Move list")); movelist_dock->setObjectName("move_list"); addDockWidget(Qt::LeftDockWidgetArea, movelist_dock, Qt::Vertical); movelist_dock->show(); ChessTable* board = new ChessTable; board->setFocus(); console_dock = new QDockWidget(this); console = new Console(0, i18n("FICS Connection")); console_dock->setWidget(console); console_dock->setFocusProxy(console); console_dock->setWindowTitle(i18n("Console")); console_dock->setObjectName("console"); addDockWidget(Qt::BottomDockWidgetArea, console_dock, Qt::Horizontal); console_dock->setWindowFlags(console_dock->windowFlags() & ~Qt::WindowStaysOnTopHint); console_dock->show(); settings().onChange(this, "settingsChanged"); connect(board, SIGNAL(error(ErrorCode)), this, SLOT(displayErrorMessage(ErrorCode))); //BROKEN connect(board->clock(), SIGNAL(labelClicked(int)), &ui(), SLOT(setTurn(int))); setupActions(); setupGUI(); setupEngineMenu(); // start in edit game mode newGame(variant, AbstractPosition::Ptr(), true); updateVariantActions(); } ChessTable* MainWindow::table() { return qobject_cast(m_main->currentWidget()); } KAction* MainWindow::installRegularAction(const QString& name, const KIcon& icon, const QString& text, QObject* obj, const char* slot) { KAction* temp = new KAction(icon, text, this); actionCollection()->addAction(name, temp); connect(temp, SIGNAL(triggered(bool)), obj, slot); return temp; } void MainWindow::setupEngineMenu() { QMenu* engine_menu = 0; SettingArray engine_settings = settings().group("engines").array("engine"); foreach (Settings s, engine_settings) { if (!engine_menu) { // this way the menu is created only if there is at least one engine engine_menu = menuBar()->addMenu(i18n("E&ngines")); } QString name; EngineDetails engine_details; engine_details.load(s); EngineInfo* engine = new EngineInfo(engine_details, ui()); m_engines.push_back(engine); QMenu* menu = engine_menu->addMenu(engine_details.name); { KAction* play_white = new KAction(i18n("Play as &white"), this); play_white->setCheckable(true); connect(play_white, SIGNAL(triggered()), engine, SLOT(playAsWhite())); menu->addAction(play_white); } { KAction* play_black = new KAction(i18n("Play as &black"), this); play_black->setCheckable(true); connect(play_black, SIGNAL(triggered()), engine, SLOT(playAsBlack())); menu->addAction(play_black); } #if 0 // disable analysis for the moment { KAction* analyze = new KAction(i18n("&Analyze"), this); analyze->setCheckable(true); connect(analyze, SIGNAL(triggered()), engine, SLOT(analyze())); menu->addAction(analyze); } #endif } } void MainWindow::setupActions() { KAction* tmp; KStandardAction::openNew(this, SLOT(newGame()), actionCollection()); KStandardAction::open(this, SLOT(loadGame()), actionCollection()); KStandardAction::save(this, SLOT(saveGame()), actionCollection()); KStandardAction::saveAs(this, SLOT(saveGameAs()), actionCollection()); KStandardAction::quit(this, SLOT(quit()), actionCollection()); KStandardAction::preferences(this, SLOT(preferences()), actionCollection()); installRegularAction("back", KIcon("go-previous"), i18n("&Back"), &ui(), SLOT(back())); installRegularAction("forward", KIcon("go-next"), i18n("&Forward"), &ui(), SLOT(forward())); installRegularAction("begin", KIcon("go-first"), i18n("Be&gin"), &ui(), SLOT(gotoFirst())); installRegularAction("end", KIcon("go-last"), i18n("&End"), &ui(), SLOT(gotoLast())); installRegularAction("connect", KIcon("network-connect"), i18n("&Connect"), this, SLOT(icsConnect())); installRegularAction("disconnect", KIcon("network-disconnect"), i18n("&Disconnect"), this, SLOT(icsDisconnect())); KStandardAction::undo(&ui(), SLOT(undo()), actionCollection()); KStandardAction::redo(&ui(), SLOT(redo()), actionCollection()); // installRegularAction("pgnCopy", KIcon("edit-copy"), i18n("Copy PGN"), this, SLOT(pgnCopy())); // installRegularAction("pgnPaste", KIcon("edit-paste"), i18n("Paste PGN"), this, SLOT(pgnPaste())); installRegularAction("editPosition", KIcon("edit"), i18n("&Edit position"), this, SLOT(editPosition())); installRegularAction("clearBoard", KIcon("edit-delete"), i18n("&Clear board"), &ui(), SLOT(clearBoard())); installRegularAction("setStartingPosition", KIcon("contents"), i18n("&Set starting position"), &ui(), SLOT(setStartingPosition())); // installRegularAction("copyPosition", KIcon(), i18n("&Copy position"), &ui(), SLOT(copyPosition())); // installRegularAction("pastePosition", KIcon(), i18n("&Paste position"), &ui(), SLOT(pastePosition())); tmp = installRegularAction("flip", KIcon("object-rotate-left"), i18n("&Flip view"), this, SLOT(flipView())); tmp->setShortcut(Qt::CTRL + Qt::Key_F); installRegularAction("toggleConsole", KIcon("utilities-terminal"), i18n("Toggle &console"), this, SLOT(toggleConsole())); installRegularAction("toggleMoveList", KIcon("view-list-tree"), i18n("Toggle &move list"), this, SLOT(toggleMoveList())); } void MainWindow::updateVariantActions(bool unplug) { ActionCollection* variant_actions = m_ui.variantActions(); if (unplug) unplugActionList("variantActions"); if (variant_actions) { plugActionList("variantActions", variant_actions->actions()); } else { kWarning() << "No variant actions"; } } void MainWindow::readSettings() { } void MainWindow::writeSettings() { } void MainWindow::closeEvent(QCloseEvent* e) { e->accept(); writeSettings(); delete this; } void MainWindow::keyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_F5) { ui().createCtrlAction(); } } void MainWindow::keyReleaseEvent(QKeyEvent* event) { if (event->key() == Qt::Key_F5) { ui().destroyCtrlAction(); } } void MainWindow::changeTab(int index) { m_ui.setCurrentTab(m_main->currentWidget()); m_movelist_stack->setCurrentIndex(index); updateVariantActions(); } void MainWindow::closeTab() { if (m_main->count() > 1) { int old_index = m_main->currentIndex(); ChessTable* old_board = table(); int new_index = old_index - 1; if (new_index < 0) new_index = old_index + 1; m_main->setCurrentIndex(new_index); m_main->removeTab(old_index); m_movelist_stack->removeWidget(m_movelist_stack->widget(old_index)); m_ui.removeController(old_board); if (m_main->count() <= 1) { m_main->setTabBarHidden(true); } #if 0 // this doesn't work... why? ChessTable* old_board = table(); m_ui.removeController(old_board); m_movelist_stack->removeWidget( m_movelist_stack->widget(m_main->currentIndex())); m_main->removeTab(m_main->currentIndex()); delete old_board; if (m_main->count() <= 1) { m_main->hideTabBar(); } // update ui controller (just in case...) m_ui.setCurrentTab(m_main->currentWidget()); #endif } } void MainWindow::createTab(ChessTable* board, const shared_ptr& controller, const QString& caption, int index) { if (index == -1) index = m_main->addTab(board, caption); else m_main->insertTab(index, board, caption); m_ui.addController(board, controller); // m_ui.setCurrentTab(board); m_movelist_stack->addWidget(board->moveListTable()); m_main->setCurrentIndex(index); m_movelist_stack->setCurrentIndex(index); if (m_main->count() > 1) m_main->setTabBarHidden(false); } void MainWindow::cleanupGame(const QString& what, const QString& result) { Q_UNUSED(what); Q_UNUSED(result); cleanupGame(); } void MainWindow::cleanupGame() { ui().detach(); ui().end(); } bool MainWindow::newGame(const QString& variantName, AbstractPosition::Ptr startingPos, bool newTab) { VariantPtr variant = Variants::instance().get(variantName); if (!variant) { kWarning() << "no variant" << variantName << "found"; variant = Variants::instance().get("chess"); } if (variant) { ChessTable* board = newTab ? new ChessTable : table(); QString text = QString("Editing %1 game").arg(variant->name().toLower()); shared_ptr controller(new EditGameController( board, variant, startingPos)); if (newTab) { createTab(board, controller, text); } else { unplugActionList("variantActions"); ui().setController(controller); table()->setPlayers(Player(), Player()); m_main->setTabText(m_main->currentIndex(), text); updateVariantActions(false); } return true; } else { kError() << "Could not find the chess variant"; exit(1); return false; } } void MainWindow::editPosition() { //BROKEN #if 0 shared_ptr controller(new EditPositionController(table(), ChessVariant::info())); m_main->setTabText(m_main->currentIndex(), "Editing chess position"); ui().setController(controller); #endif } void MainWindow::setupGame(const GameInfo* gameInfo, const PositionInfo& style12) { QString variantCode = gameInfo->variant(); VariantPtr variant = Variants::instance().get(variantCode); shared_ptr controller(new EditGameController( table(), variant)); Q_ASSERT(style12.relation == PositionInfo::NotMyMove || style12.relation == PositionInfo::MyMove); // set opponent side int side = (style12.relation == PositionInfo::MyMove ^ style12.turn == 0) ? 0 : 1; if (controller->addICSPlayer(side, style12.gameNumber, m_connection)) { ui().setController(controller); table()->setPlayers(gameInfo->white(), gameInfo->black()); m_main->setTabText(m_main->currentIndex(), QString("FICS Game - %1 vs %2").arg(style12.whitePlayer) .arg(style12.blackPlayer)); } } void MainWindow::setupExaminedGame(const GameInfo* gameInfo, const PositionInfo& style12) { shared_ptr controller( new EditGameController(table(), Variants::instance().get(gameInfo->variant()))); if (controller->setExaminationMode(style12.gameNumber, m_connection)) { table()->setPlayers(Player(style12.whitePlayer, -1), Player(style12.blackPlayer, -1)); ui().setController(controller); m_main->setTabText(m_main->currentIndex(), QString("Examining - %1 vs %2").arg(style12.whitePlayer) .arg(style12.blackPlayer)); } } void MainWindow::setupObservedGame(const GameInfo* g, const PositionInfo& style12) { std::auto_ptr board(new ChessTable); shared_ptr controller(new EditGameController( board.get(), Variants::instance().get(g->variant()))); if (controller->setObserveMode(style12.gameNumber, m_connection)) { board->setPlayers(Player(style12.whitePlayer, -1), Player(style12.blackPlayer, -1)); // ui().setController(controller); //kDebug() << "adding tab"; createTab(board.get(), controller, QString("Observing - %1 vs %2").arg(style12.whitePlayer) .arg(style12.blackPlayer)); board.release(); } } void MainWindow::setupPGN(const QString& s) { PGN pgn(s); std::map::const_iterator var = pgn.m_tags.find("Variant"); QString variant; if (var == pgn.m_tags.end()) variant = "chess"; else variant = var->second; newGame(variant, PositionPtr(), false); ui().pgnPaste(pgn); } bool MainWindow::openFile(const QString& filename) { QFileInfo info(filename); if(info.isDir()) { KMessageBox::sorry(this, i18n("You have specified a folder"), i18n("Error")); return false; } if(!info.exists() || !info.isFile()) { KMessageBox::sorry(this, i18n("The specified file does not exist"), i18n("Error")); return false; } QFile file(filename); if(!file.open(QIODevice::ReadOnly)) { KMessageBox::sorry(this, i18n("You do not have read permission to this file."), i18n("Error")); return false; } QTextStream stream(&file); QTextCodec *codec; codec = QTextCodec::codecForLocale(); stream.setCodec(codec); setupPGN(stream.readAll()); //ui().pgnPaste(stream.readAll()); return true; } void MainWindow::loadGame() { KUrl url = KFileDialog::getOpenUrl(KUrl(), "*.pgn", this, i18n("Open PGN file")); if(url.isEmpty()) return; QString tmp_file; if (KIO::NetAccess::download(url, tmp_file, this)) { openFile(tmp_file); KIO::NetAccess::removeTempFile(tmp_file); } else KMessageBox::error(this, KIO::NetAccess::lastErrorString()); } void MainWindow::saveGame() { if (ui().url().isEmpty()) saveGameAs(); else ui().setUrl(saveGame(ui().url())); } void MainWindow::saveGameAs() { ui().setUrl(saveGame(KFileDialog::getSaveUrl(KUrl(), "*.pgn", this, i18n("Save PGN file")))); } bool MainWindow::checkOverwrite(const KUrl& url) { if (!url.isLocalFile()) return true; QFileInfo info(url.path()); if (!info.exists()) return true; return KMessageBox::Cancel != KMessageBox::warningContinueCancel(this, i18n("A file named \"%1\" already exists. " "Are you sure you want to overwrite it?" , info.fileName()), i18n("Overwrite File?"), KGuiItem(i18n("&Overwrite"))); } KUrl MainWindow::saveGame(const KUrl& url) { if (!checkOverwrite(url)) return KUrl(); if (url.isEmpty()) return KUrl(); if (!url.isLocalFile()) { // save in a temporary file KTemporaryFile tmp_file; tmp_file.open(); saveFile(tmp_file); if (!KIO::NetAccess::upload(tmp_file.fileName(), url, this)) return KUrl(); } else { QFile file(url.path()); if (!file.open(QIODevice::WriteOnly)) return KUrl(); saveFile(file); } return url; } void MainWindow::saveFile(QFile& file) { QTextStream stream(&file); QTextCodec *codec; codec = QTextCodec::codecForLocale(); stream.setCodec(codec); stream << ui().currentPGN() << "\n"; } void MainWindow::createConnection(const QString& username, const QString& password, const QString& host, quint16 port, const QString& timeseal, const QString& timeseal_cmd) { m_connection = shared_ptr(new ICSConnection); connect(m_connection.get(), SIGNAL(established()), this, SLOT(onEstablishConnection())); connect(m_connection.get(), SIGNAL(hostLookup()), this, SLOT(onHostLookup())); connect(m_connection.get(), SIGNAL(hostFound()), this, SLOT(onHostFound())); connect(m_connection.get(), SIGNAL(receivedLine(QString, int)), console, SLOT(displayText(QString, int))); connect(m_connection.get(), SIGNAL(receivedText(QString, int)), console, SLOT(displayText(QString, int))); connect(console, SIGNAL(receivedInput(const QString&)), m_connection.get(), SLOT(sendText(const QString&))); connect(console, SIGNAL(notify()), this, SLOT(flash())); connect(m_connection.get(), SIGNAL(loginPrompt()), this, SLOT(sendLogin())); connect(m_connection.get(), SIGNAL(registeredNickname()), this, SLOT(sendBlankPassword())); connect(m_connection.get(), SIGNAL(prompt()), this, SLOT(prompt())); connect(m_connection.get(), SIGNAL(creatingExaminedGame(const GameInfo*, const PositionInfo&)), this, SLOT(setupExaminedGame(const GameInfo*, const PositionInfo&))); connect(m_connection.get(), SIGNAL(endingExaminedGame(int)), this, SLOT(cleanupGame())); connect(m_connection.get(), SIGNAL(creatingObservedGame(const GameInfo*, const PositionInfo&)), this, SLOT(setupObservedGame(const GameInfo*, const PositionInfo&))); connect(m_connection.get(), SIGNAL(endingObservedGame(int)), this, SLOT(cleanupGame())); connect(m_connection.get(), SIGNAL(creatingGame(const GameInfo*, const PositionInfo&)), this, SLOT(setupGame(const GameInfo*, const PositionInfo&))); connect(m_connection.get(), SIGNAL(endingGame(const QString&, const QString&)), this, SLOT(cleanupGame(const QString&, const QString&))); connect(m_connection.get(), SIGNAL(notification()), this, SLOT(flash())); m_connection->establish(host.toAscii().constData(), port, timeseal, timeseal_cmd); console->show(); // send username / password combination if (!username.isEmpty()) { m_connection->sendText(username); m_connection->sendText(password); } quickConnectDialog.reset(); } void MainWindow::icsConnect() { quickConnectDialog = shared_ptr(new QConnect(this)); connect(quickConnectDialog.get(), SIGNAL(acceptConnection(const QString&, const QString&, const QString&, quint16, const QString&, const QString&)), this, SLOT(createConnection(const QString&, const QString&, const QString&, quint16, const QString&, const QString&))); quickConnectDialog->show(); } void MainWindow::destroyConnection() { m_connection.reset(); } void MainWindow::icsDisconnect() { destroyConnection(); console->hide(); console->clear(); } void MainWindow::testConnect() { Settings s_ics = settings().group("ics"); if (s_ics["username"]) { QString username = s_ics["username"].value(); QString password = (s_ics["password"] | ""); QString host = (s_ics["icsHost"] | "freechess.org"); quint16 port = (s_ics["icsPort"] | 5000); createConnection(username, password, host, port, QString(), QString() ); } else icsConnect(); } void MainWindow::onEstablishConnection() { // kDebug() << "connection established"; } void MainWindow::onConnectionError(int ) { // kDebug() << "connection error (" << code << ")"; } void MainWindow::onHostLookup() { // kDebug() << "hostLookup..." << std::flush; } void MainWindow::onHostFound() { // kDebug() << "found"; } void MainWindow::sendLogin() { // kDebug() << "sending username"; // connection->sendText(connection->username()); } void MainWindow::sendBlankPassword() { m_connection->sendText(""); } void MainWindow::prompt() { if (!m_connection->initialized()) { m_connection->startup(); m_connection->setInitialized(); } } void MainWindow::newGame() { AbstractPosition::Ptr pos = ui().position(); scoped_ptr dialog(new NewGame(this)); if (dialog->exec() == QDialog::Accepted) { if (!newGame(dialog->variant(), PositionPtr(), dialog->newTab())) QMessageBox::information(this, i18n("Error"), i18n("Error creating game")); } } void MainWindow::quit() { delete this; } void MainWindow::flipView() { table()->flip(); } void MainWindow::toggleConsole() { if (console_dock->isVisible()) console_dock->hide(); else { console_dock->show(); console_dock->setFocus(Qt::MouseFocusReason /*Qt::ActiveWindowFocusReason*/ /*Qt::OtherFocusReason*/); } } void MainWindow::toggleMoveList() { if (movelist_dock->isVisible()) movelist_dock->hide(); else { movelist_dock->show(); movelist_dock->setFocus(Qt::OtherFocusReason); } } void MainWindow::displayMessage(const QString& msg) { Q_UNUSED(msg); // TODO // statusBar()->message(msg, 2000); } void MainWindow::displayErrorMessage(ErrorCode code) { switch(code) { case InvalidMove: displayMessage(i18n("Illegal move")); break; } } void MainWindow::flash() { if( !isAncestorOf(QApplication::focusWidget()) ) Flash::flash(this); } #if 0 void MainWindow::prefHighlight() { PrefHighlight dialog; int result = dialog.exec(); if (result == QDialog::Accepted) { dialog.apply(); } } #endif void MainWindow::preferences() { Preferences dialog(ui().currentVariant()); int result = dialog.exec(); if (result == QDialog::Accepted) dialog.apply(); } void MainWindow::settingsChanged() { ui().reloadSettings(); } tagua-1.0-alpha2/src/mainwindow.h000066400000000000000000000071221077523320400167410ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include #include #include "boost/shared_ptr.hpp" #include "ui.h" #include "common.h" #include "export.h" class ChessTable; class ICSConnection; class Console; class GameInfo; class PositionInfo; class Controller; class QConnect; class NewGame; class EngineInfo; class QDockWidget; class TabWidget; class QStackedWidget; class QActionGroup; class KAction; class KIcon; class TAGUA_EXPORT MainWindow : public KXmlGuiWindow { Q_OBJECT QDockWidget* movelist_dock; QDockWidget* console_dock; TabWidget* m_main; QStackedWidget* m_movelist_stack; boost::shared_ptr m_connection; Console* console; QMenu* m_engine_menu; ChessTable* table(); UI m_ui; UI& ui() { return m_ui; } void createTab(ChessTable*, const boost::shared_ptr&, const QString& label, int index = -1); // QDir m_iconDir; std::vector m_engines; boost::shared_ptr quickConnectDialog; NewGame* newGameDialog; // // QAction *mkAction(const QString& txt, QKeySequence shk, QObject *o, // const char *sl, QString name, QObject *par = NULL); void setupActions(); void setupEngineMenu(); KAction* addPromotionAction(const QString& name, const QString& text, const char* uiSlot); KAction* installRegularAction(const QString& name, const KIcon& icon, const QString& text, QObject* obj, const char* slot); void updateVariantActions(bool unplug = true); bool openFile(const QString&); void saveFile(QFile&); KUrl saveGame(const KUrl& url); void readSettings(); void writeSettings(); public: MainWindow(const QString& variant); virtual ~MainWindow(); protected: void closeEvent(QCloseEvent*); void keyPressEvent(QKeyEvent*); void keyReleaseEvent(QKeyEvent*); private Q_SLOTS: void changeTab(int); void closeTab(); public Q_SLOTS: void createConnection(const QString&, const QString&, const QString&, quint16, const QString&, const QString&); void destroyConnection(); void testConnect(); // DEBUG void icsConnect(); void icsDisconnect(); // // void receivedCommand(const QString&); // void onEstablishConnection(); void onHostLookup(); void onConnectionError(int); void onHostFound(); // void sendLogin(); void sendBlankPassword(); void prompt(); void cleanupGame(const QString&, const QString&); void cleanupGame(); void editPosition(); void setupGame(const GameInfo*, const PositionInfo&); void setupPGN(const QString& s); void setupExaminedGame(const GameInfo*, const PositionInfo&); void setupObservedGame(const GameInfo*, const PositionInfo&); void newGame(); bool newGame(const QString& var, AbstractPosition::Ptr, bool); void loadGame(); void saveGame(); void saveGameAs(); bool checkOverwrite(const KUrl& url); void quit(); void flipView(); void toggleConsole(); void toggleMoveList(); void displayMessage(const QString& msg); void displayErrorMessage(ErrorCode); void flash(); // void prefHighlight(); void preferences(); void settingsChanged(); }; #endif // MAINWINDOW_H tagua-1.0-alpha2/src/mastersettings.cpp000066400000000000000000000111121077523320400201660ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "mastersettings.h" #include #include #include #include "common.h" #include "foreach.h" QDomElement MasterSettings::node() const { if (m_node.isNull()) { QFile f(m_filename); if (!f.open(QFile::ReadOnly | QFile::Text) || !m_doc.setContent(&f)) { kWarning() << "Unable to open configuration file for reading."; // // create a stub configuration file // { // QFile stub(m_filename); // if (!stub.open(QFile::WriteOnly | QFile::Text)) { // kDebug() << "Unable to write to configuration file."; // exit(1); // } // QTextStream stream(&stub); // stream << "\n" // "\n" // "\n"; // } // // // reopen it // if (!f.open(QFile::ReadOnly | QFile::Text)) // exit(1); m_doc.appendChild(m_doc.createElement("configuration")); // kDebug() << m_doc.toString(); } const_cast(m_node) = m_doc.documentElement(); Q_ASSERT(!m_node.isNull()); Q_ASSERT(!m_node.ownerDocument().isNull()); } return m_node; } MasterSettings::MasterSettings() { m_filename = KStandardDirs::locateLocal("config", "taguarc.xml"); } MasterSettings::MasterSettings(const QString& filename, LookupType lookup) { if (lookup == PathLookup) m_filename = filename; else m_filename = KStandardDirs::locateLocal("config", filename); } MasterSettings::~MasterSettings() { sync(); } void MasterSettings::setupObserver(Observer& observer) { connect(observer.object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); } void MasterSettings::onChange(QObject* obj, const char* method) { m_observers.push_front(Observer(obj, method, 0)); setupObserver(m_observers.front()); } void MasterSettings::onChange(QObject* obj, const char* method, const char* dependency) { if (dependency) { // go backwards through all existing observers, searching for something // on which we depend. for (ObserverList::reverse_iterator it = m_observers.rbegin(); it != m_observers.rend(); ++it) { const char* observer_class = it->object->metaObject()->className(); if (observer_class && strcmp(observer_class, dependency) == 0) { // we hit a dependency wall: we can't be notified // before *it, so add the new Observer just here ObserverList::iterator us = m_observers.insert(it.base(), Observer(obj, method, dependency)); setupObserver(*us); // now check for a cyclic dependency const char* this_class = obj->metaObject()->className(); for (ObserverList::iterator it2 = m_observers.begin(); it2 != us; ++it2) { if (it2->dependency && strcmp(it2->dependency, this_class) == 0) { // something which is notified before has us a dependency // this means that there is a cyclic dependency it2 -> us -> it. kWarning() << "Removing a cyclic dependency:" << it2->object->metaObject()->className() << "->" << this_class << "->" << observer_class; // remove the cycle it2->dependency = 0; } } // done return; } } } // no dependency onChange(obj, method); } void MasterSettings::sync() { // store to file QFile f(m_filename); if (!f.open(QFile::WriteOnly | QFile::Text)) kError() << "Cannot open configuration file for writing"; else { QTextStream stream(&f); stream << node().ownerDocument().toString(); } } void MasterSettings::objectDestroyed(QObject* obj) { for (ObserverList::iterator it = m_observers.begin(); it != m_observers.end();) { if (it->object == obj) { it = m_observers.erase(it); } else { ++it; } } } void MasterSettings::changed() { foreach (Observer& observer, m_observers) { observer.object->metaObject()->invokeMethod(observer.object, observer.method, Qt::DirectConnection); } sync(); } QString MasterSettings::filename() const { return m_filename; } MasterSettings& settings() { static MasterSettings static_settings; return static_settings; } tagua-1.0-alpha2/src/mastersettings.h000066400000000000000000000045431077523320400176450ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef MASTERSETTINGS_H #define MASTERSETTINGS_H #include #include #include #include #include "settings.h" class MasterSettings : public QObject , public Settings { Q_OBJECT public: enum LookupType { PathLookup, StandardDirsLookup }; private: struct Observer { QObject* object; const char* dependency; const char* method; Observer(QObject* obj, const char* meth, const char* dep) : object(obj) , dependency(dep) , method(meth) { } }; typedef std::list ObserverList; ObserverList m_observers; QString m_filename; mutable QDomDocument m_doc; void setupObserver(Observer&); private Q_SLOTS: void objectDestroyed(QObject* o); protected: virtual QDomElement node() const; public: MasterSettings(const QString& file, LookupType lookup = StandardDirsLookup); /** * Bind to the local configuration file. */ MasterSettings(); ~MasterSettings(); /** * Set up an observer to be notified whenever settings change. * \param observer The object to be notified. * \param method The callback method for the notification, specified as a C string. * \note @a method should be just the method name (no parentheses, no SLOT macro). */ void onChange(QObject* observer, const char* method); /** * Set up an observer to be notified whenever settings change. * \param observer The object to be notified. * \param method The callback method for the notification, specified as a C string. * \param dependency A C string representing a type (inheriting from QObject). Objects * of this type will be notified before @a observer. * \note @a method should be just the method name (no parentheses, no SLOT macro). */ void onChange(QObject* observer, const char* method, const char* dependency); void changed(); void sync(); QString filename() const; }; MasterSettings& settings(); #endif // MASTERSETTINGS_H tagua-1.0-alpha2/src/movefactory.h000066400000000000000000000020421077523320400171170ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef MOVEFACTORY_H #define MOVEFACTORY_H #include "tagua.h" #include "usermove.h" template struct MoveFactory { static typename Variant::Move createNormalMove(const NormalUserMove& move) { return typename Variant::Move(move.from, move.to, static_cast(move.promotionType)); } static typename Variant::Move createDropMove(const DropUserMove& move) { return Variant::Move::createDropMove(move.m_pool, move.m_piece_index, move.m_to); } static NormalUserMove toNormal(const typename Variant::Move& move) { return NormalUserMove(move.from, move.to); } }; #endif // MOVEFACTORY_H tagua-1.0-alpha2/src/movelist.cpp000066400000000000000000001075361077523320400167740ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "movelist_widget.h" #include "movelist_table.h" #include "movelist_notifier.h" #include "movelist_p.h" #include "mastersettings.h" #include "pref_theme.h" namespace MoveList { #define MARGIN_LEFT 2 #define MARGIN_RIGHT 4 #define MARGIN_TOP 1 #define MARGIN_BOTTOM 0 #define MIDDLE_PAD 3 #define COMMENT_INDENTATION 4 #define VAR_INDENTATION 16 #define BORDER_LEFT 3 #define BORDER_RIGHT 3 #define BORDER_TOP 3 #define BORDER_BOTTOM 3 #define MIN_COL_WIDTH 5.0 #define DEFAULT_ANIMATION_TIME 350.0 //BEGIN FancyItem-------------------------------------------------------------- bool FancyItem::showing() { return !(time_opacity!=-1 && target_opacity == 0) && ((time_opacity!=-1 && target_opacity == 255) || (visible() && opacity() == 255)); } void FancyItem::appear() { if((time_opacity!=-1 && target_opacity == 255) || (visible() && opacity() == 255)) return; Widget *m = dynamic_cast(topLevelCanvas()); if(!m->m_settings->anim_enabled || !m->m_settings->anim_hideshow) show(); else { old_opacity = 0; target_opacity = 255; time_opacity = m->layout_time; setAnimated(true); } } void FancyItem::disappear() { if((time_opacity!=-1 && target_opacity == 0) || !visible() || opacity() == 0) return; Widget *m = dynamic_cast(topLevelCanvas()); setHighlight(false); if(!m->m_settings->anim_enabled || !m->m_settings->anim_hideshow) hide(); else { old_opacity = 255; target_opacity = 0; time_opacity = m->layout_time; setAnimated(true); } } void FancyItem::goTo(QPoint p) { if((time_pos!=-1 && target_pos == p) || (time_pos==-1 && pos() == p)) return; Widget *m = dynamic_cast(topLevelCanvas()); if(!m->m_settings->anim_enabled || !m->m_settings->anim_moving) moveTo(p); else { old_pos = pos(); target_pos = p; time_pos = m->layout_time; setAnimated(true); } } void FancyItem::setHighlight(bool h) { if(highlighted == h) return; Widget *m = dynamic_cast(topLevelCanvas()); if(!m->m_settings->anim_enabled || !m->m_settings->anim_highlight) { curr_highlight = h ? 255 : 0; highlighted = h; changed(); } else { old_highlight = highlighted ? 255 : 0; target_highlight = h ? 255 : 0; highlighted = h; time_highlight = m->mSecs(); setAnimated(true); } } void FancyItem::advance(int time) { Widget *m = dynamic_cast(topLevelCanvas()); if(time_highlight != -1) { float fact = (time - time_highlight) / m->m_settings->anim_time; if(fact >= 1.0) { curr_highlight = target_highlight; time_highlight = -1; } else curr_highlight = int(target_highlight*fact + old_highlight*(1-fact)); changed(); } if(time_opacity != -1) { float fact = (time - time_opacity) / m->m_settings->anim_time; if(fact >= 1.0) { setOpacity(target_opacity); setVisible(target_opacity != 0); time_opacity = -1; } else { setOpacity( int(target_opacity*fact + old_opacity*(1-fact)) ); setVisible(true); } } if(time_pos != -1) { float fact = (time - time_pos) / m->m_settings->anim_time; if(fact >= 1.0) { moveTo(target_pos); time_pos = -1; } else { moveTo( int(target_pos.x()*fact + old_pos.x()*(1-fact)+0.5), int(target_pos.y()*fact + old_pos.y()*(1-fact)+0.5)); } } if(canStop()) { setAnimated(false); } } bool FancyItem::layered() const { return false; } //END FancyItem---------------------------------------------------------------- //BEGIN Brace------------------------------------------------------------------ void Brace::setHeight(int h) { if(h<0) h=0; if((animated() && target_height == h) || height == h) return; Widget *m = dynamic_cast(topLevelCanvas()); if(!m->m_settings->anim_enabled || !m->m_settings->anim_moving) { height = h; changed(); } else { old_height = height; target_height = h; time_height = m->layout_time; if(visible()) setAnimated(true); } } void Brace::advance(int time) { if(time_height != -1) { Widget *m = dynamic_cast(topLevelCanvas()); float fact = (time - time_height) / m->m_settings->anim_time; if(fact >= 1.0) { height = target_height; time_height = -1; } else height = int(target_height*fact + old_height*(1-fact) + 0.5); changed(); } FancyItem::advance(time); } void Brace::paint (QPainter *p) { Widget *m = dynamic_cast(topLevelCanvas()); if(height < m->entry_size) return; QPointF p1((pos().x()*2+width)/2.0, (pos().y()*2+m->entry_size)/2.0); QPointF p2((pos().x()*2+width)/2.0, (pos().y()*2+height*2-m->entry_size)/2.0); p->save(); QPen q; if(depth % 2) { p->setBrush(QColor(255,192,224)); q = QColor(128,0,64); } else { p->setBrush(QColor(192,255,224)); q = QColor(0,128,64); } q.setWidth(2); p->setPen(q); p->setRenderHint(QPainter::Antialiasing); int s = std::min(m->entry_size, width); float cs1 = (0.4 + 0.2*(curr_highlight/255.0)) * s; float cs2 = 0.2 * s; p->drawLine(p1,p2); p->drawEllipse(QRectF(-cs1/2,-cs1/2,cs1,cs1).translated(p1)); p->setBrush(p->pen().color()); p->drawEllipse(QRectF(-cs2/2,-cs2/2,cs2,cs2).translated(p2)); p->restore(); } QRect Brace::rect () const { return QRect(pos(), QSize(width, height)); } //END Brace-------------------------------------------------------------------- //BEGIN Text------------------------------------------------------------------- void Text::paint (QPainter *p) { Widget *m = dynamic_cast(topLevelCanvas()); if(curr_highlight != 0) { p->setBrush(QColor(192,224,208, curr_highlight)); p->setPen(QColor(64,128,96, curr_highlight)); p->drawRect(rect().adjusted(0,0,-1,-1)); } p->setFont(selected ? m->m_settings->sel_mv_font : m->m_settings->mv_font); p->setPen(selected ? m->m_settings->select_color : Qt::black); p->drawText(pos()+QPoint(MARGIN_LEFT, MARGIN_TOP+m->m_settings->mv_fmetrics.ascent()), text); } QRect Text::rect () const { return QRect(pos(), QSize(width, height)); } void Text::doUpdate () { if(!needs_update) return; Widget *m = dynamic_cast(topLevelCanvas()); width = (selected ? m->m_settings->sel_mv_fmetrics : m->m_settings->mv_fmetrics).boundingRect(text).right() + MARGIN_LEFT + MARGIN_RIGHT; height = m->entry_size; needs_update = false; changed(); } //END Text--------------------------------------------------------------------- //BEGIN Comment---------------------------------------------------------------- void Comment::paint (QPainter *p) { Widget *m = dynamic_cast(topLevelCanvas()); if(curr_highlight != 0) { p->setBrush(QColor(255,255,255, curr_highlight)); p->setPen(QColor(192,192,192, curr_highlight)); p->drawRect(rect().adjusted(0,0,-1,-1)); } p->setFont(m->m_settings->comm_font); p->setPen(m->m_settings->comment_color); p->drawText(pos().x() + MARGIN_RIGHT, pos().y(), width - MARGIN_LEFT - MARGIN_RIGHT, 9999, Qt::AlignLeft|Qt::AlignTop|Qt::TextWordWrap, text); } QRect Comment::rect () const { return QRect(pos(), QSize(width, height)); } void Comment::doUpdate () { if(!needs_update) return; Widget *m = dynamic_cast(topLevelCanvas()); QPoint dest = ((time_pos != -1) ? target_pos : pos()); width = std::max(m->width() - dest.x(), m->entry_size); height = m->m_settings->comm_fmetrics.boundingRect(0,0,width - MARGIN_LEFT - MARGIN_RIGHT, 99999, Qt::AlignLeft|Qt::AlignTop|Qt::TextWordWrap, text).height() + MARGIN_TOP + MARGIN_BOTTOM; needs_update = false; changed(); } //END Comment------------------------------------------------------------------ //BEGIN Entry------------------------------------------------------------------ void Entry::paint (QPainter *p) { Widget *m = dynamic_cast(topLevelCanvas()); if(curr_highlight != 0) { p->setBrush(QColor(192,224,255, curr_highlight)); p->setPen(QColor(64,96,128, curr_highlight)); p->drawRect(rect().adjusted(0,0,-1,-1)); } p->setPen(selected ? m->m_settings->select_color : Qt::black); int x = pos().x()+MARGIN_LEFT; int y = pos().y()+MARGIN_TOP+m_ascent; p->setRenderHint(QPainter::TextAntialiasing); QFont tf = selected ? m->m_settings->sel_mv_font : m->m_settings->mv_font; QFontMetrics& fm = selected ? m->m_settings->sel_mv_fmetrics : m->m_settings->mv_fmetrics; QRect r(0,0,0,0); for(int i=0;i<(int)move.size();i++) { if(move[i].m_type == MovePart::Text) { p->setFont(tf); p->drawText(QPoint(x+r.width(), y), move[i].m_string); QRect b = fm.boundingRect(move[i].m_string); r |= b.translated(r.width()-b.x(), 0); } else if(move[i].m_type == MovePart::Figurine) { ::Loader::Glyph g = m->m_loader.getValue< ::Loader::Glyph>(move[i].m_string); QFont font = g.fontValid() ? g.font() : tf; p->setFont(font); p->drawText(QPoint(x+r.width(), y), g.str()); QFontMetrics fi(font); QRect b = fi.boundingRect(g.str()); r |= b.translated(r.width()-b.x(), 0); } } } QRect Entry::rect () const { return m_rect.translated(pos().x()+MARGIN_LEFT, pos().y()+MARGIN_TOP+m_ascent); } void Entry::doUpdate () { if(!needs_update) return; Widget *m = dynamic_cast(topLevelCanvas()); QFont tf = selected ? m->m_settings->sel_mv_font : m->m_settings->mv_font; QFontMetrics& fm = selected ? m->m_settings->sel_mv_fmetrics : m->m_settings->mv_fmetrics; m_ascent = m->m_settings->mv_fmetrics.ascent(); m_rect = QRect(0,0,0,0); for(int i=0;i<(int)move.size();i++) { if(move[i].m_type == MovePart::Text) { QRect b = fm.boundingRect(move[i].m_string); m_rect |= b.translated(m_rect.width()-b.x(), 0); } else if(move[i].m_type == MovePart::Figurine) { ::Loader::Glyph g = m->m_loader.getValue< ::Loader::Glyph>(move[i].m_string); QFontMetrics fi(g.fontValid() ? g.font() : tf); QRect b = fi.boundingRect(g.str()); m_rect |= b.translated(m_rect.width()-b.x(), 0); } } m_rect = QRect(m_rect.x(),m_rect.y(),m_rect.width()+MARGIN_RIGHT,m_rect.height()); needs_update = false; changed(); } //END Entry-------------------------------------------------------------------- //BEGIN Settings--------------------------------------------------------------- void Settings::load() { ::Settings s = settings().group("move-list"); ::Settings s_anim = s.group("animations"); anim_enabled = s.group("animations").flag("enabled", true); anim_moving = s_anim.group("moving").flag("enabled", true); anim_hideshow = s_anim.group("hideshow").flag("enabled", true); anim_highlight = s_anim.group("highlight").flag("enabled", true); anim_speed = s_anim["speed"] | 16; anim_time = DEFAULT_ANIMATION_TIME*pow(5.0, 1.0 - anim_speed/16.0); anim_smoothness = s_anim["smoothness"] | 16; select_color = s["select-color"] | QColor(Qt::red); comment_color = s["comment-color"] | QColor(64,64,64); mv_font = QApplication::font(); if ((use_mv_font = s.group("moves-font").flag("enabled", true))) mv_font = s["moves-font"] | mv_font; sel_mv_font = mv_font; sel_mv_font.setBold(true); comm_font = QApplication::font(); comm_font.setItalic(true); if ((use_comm_font = s.group("comment-font").flag("enabled", true))) comm_font = s["CommentFont"] | comm_font; mv_fmetrics = QFontMetrics(mv_font); sel_mv_fmetrics = QFontMetrics(sel_mv_font); comm_fmetrics = QFontMetrics(comm_font); } void Settings::save() { ::Settings s = settings().group("move-list"); ::Settings s_anim = s.group("animations"); s.group("animations").setFlag("enabled", anim_enabled); s_anim.group("moving").setFlag("enabled", anim_moving); s_anim.group("hideshow").setFlag("enabled", anim_hideshow); s_anim.group("highlight").setFlag("enabled", anim_highlight); s_anim["speed"] = anim_speed; s_anim["smoothness"] = anim_smoothness; s["select-color"] = select_color; s["comment-color"] = comment_color; s.group("moves-font").flag("enabled", use_mv_font); s["moves-font"] = mv_font; s.group("comment-font").flag("enabled", use_comm_font); s["comment-font"] = comm_font; } //END Settings----------------------------------------------------------------- //BEGIN Widget----------------------------------------------------------------- Widget::Widget(QWidget *parent, Table *o) : KGameCanvasWidget(parent) , curr_highlight(-1) , curr_selected(-1) , comment_editor(NULL) , layout_pending(false) , layout_style(0) , layout_goto_selected(false) , layout_width_changed(true) , layout_must_relayout(true) , notifier(NULL) , owner_table(o) , m_settings(new Settings) { resize(50,100); setSizePolicy ( QSizePolicy::MinimumExpanding, QSizePolicy::Minimum ); setMouseTracking(true); settingsChanged(); reset(); } Widget::~Widget() { delete m_settings; } void Widget::reset() { curr_highlight = Index(-1); curr_selected = Index(-1); if(comment_editor) { delete comment_editor; comment_editor = NULL; } DecoratedMove mv; mv.push_back(MovePart(QString("Mainline:"))); history.clear(); history.push_back( EntryPtr(new Entry(-1, mv, Index(0), this)) ); layout(); } EntryPtr Widget::fetch(const Index& ix) { int at; History *vec = fetchRef(ix, &at); return vec ? (*vec)[at] : EntryPtr(); } History* Widget::fetchRef(const Index& ix, int* idx) { if(ix.num_moves >= (int)history.size() || ix.num_moves < 0 ) return NULL; History* aretv = &history; EntryPtr retv = history[ix.num_moves]; if(idx) *idx = ix.num_moves; for(int i=0; i<(int)ix.nested.size();i++) { Variations::iterator it = retv->variations.find(ix.nested[i].variation); if(it == retv->variations.end() || ix.nested[i].num_moves >= (int)it->second.size() || ix.nested[i].num_moves < 0 ) return NULL; aretv = &it->second; retv = it->second[ix.nested[i].num_moves]; if(idx) *idx = ix.nested[i].num_moves; } return aretv; } Notifier* Widget::getNotifier() { return notifier; } void Widget::setNotifier(Notifier* n, bool detach_prev){ if(detach_prev && notifier && notifier != n) notifier->onDetachNotifier(); notifier = n; } void Widget::settingsChanged() { m_settings->load(); setAnimationDelay( int(70.0*pow(10.0, -m_settings->anim_smoothness/32.0)) ); entry_size = m_settings->mv_fmetrics.height()+MARGIN_TOP+MARGIN_BOTTOM; owner_table->m_scroll_area->setMinimumSize(entry_size*6, entry_size*9); m_loader.setSize(m_settings->mv_font.pointSize()); layout_must_relayout = true; layout(); } void Widget::mouseMoveEvent ( QMouseEvent * event ) { KGameCanvasItem *i = itemAt(event->pos()); Entry* e = i ? dynamic_cast(i) : NULL; Text* f = i ? dynamic_cast(i) : NULL; Brace* b = i ? dynamic_cast(i) : NULL; Comment* c = i ? dynamic_cast(i) : NULL; EntryPtr olde = fetch(curr_highlight); f = f && f->type == 1 ? f : NULL; int oldtype = curr_highlight_type; if(e) { if(curr_highlight == e->index && curr_highlight_type==-1) return; e->setHighlight(true); curr_highlight = e->index; curr_highlight_type = -1; } else if(f) { if(curr_highlight == f->entry->index && curr_highlight_type==-2) return; f->setHighlight(true); curr_highlight = f->entry->index; curr_highlight_type = -2; } else if(c) { if( (curr_highlight==c->entry->index) && ((c->variation==-1) ? (curr_highlight_type == -3) : (curr_highlight_type == -1000-c->variation) ) ) return; c->setHighlight(true); curr_highlight = c->entry->index; curr_highlight_type = (c->variation==-1) ? -3 : (-1000-c->variation); } else if(b) { if(curr_highlight == b->entry->index && curr_highlight_type==b->variation) return; b->setHighlight(true); curr_highlight = b->entry->index; curr_highlight_type = b->variation; } else curr_highlight = Index(-1); if(olde) { if(oldtype==-1) olde->setHighlight(false); else if(oldtype==-2 && olde->fregna) olde->fregna->setHighlight(false); else if(oldtype==-3 && olde->comment) olde->comment->setHighlight(false); else if(oldtype<=-1000 && olde->vcomments.count(-1000-oldtype)==1) olde->vcomments[-1000-oldtype]->setHighlight(false); else if(oldtype>=0 && olde->braces.count(oldtype)==1) olde->braces[oldtype]->setHighlight(false); } } void Widget::startEditing(const Index& i, int v) { stopEditing(); EntryPtr e = fetch(i); if(!e) { kError() << "Invalid index " << i; return; } CommentPtr c = v == -1 ? e->comment : (e->vcomments.count(v) ? e->vcomments[v] : CommentPtr()); QRect rect; if(c) rect = c->rect(); else { TextPtr n = e->number; if(!n && i > Index(0)) n = fetch(i.prev())->number; int x = (n ? n->pos().x() : e->pos().x()) + ((v == -1) ? 0 : VAR_INDENTATION); rect = QRect(x, e->pos().y()+entry_size, width()-x, 0); } edited_comment_variation = v; edited_comment = boost::weak_ptr(e); comment_editor = new QTextEdit(c ? c->text : QString(), this); comment_editor->setGeometry(rect.adjusted(0,0,0,entry_size*3)); comment_editor->show(); comment_editor->setFocus(Qt::MouseFocusReason); comment_editor->installEventFilter(this); } bool Widget::eventFilter(QObject *obj, QEvent *event) { if(obj == comment_editor && event->type() == QEvent::FocusOut ) { stopEditing(); return true; } return false; } void Widget::stopEditing() { EntryPtr e = edited_comment.lock(); if(e) { if(comment_editor && notifier) { QString c = comment_editor->toPlainText(); c.replace(QRegExp("(?:[ \t]\r?\n\r?|\r?\n\r?[ \t]|\r?\n\r?)"), " "); if(edited_comment_variation == -1) notifier->onUserSetComment(e->index, c); else notifier->onUserSetVComment(e->index, edited_comment_variation, c); } edited_comment.reset(); } if(comment_editor) { comment_editor->deleteLater(); comment_editor = NULL; } } void Widget::mousePressEvent ( QMouseEvent * event ) { stopEditing(); KGameCanvasItem *i = itemAt(event->pos()); if(!i) return; Text *t = dynamic_cast(i); if(t && t->type == 1) { Entry *e = t->entry; if(e->hide_next) { e->hide_next = false; e->expanded = true; } else e->expanded = !e->expanded; layout(); return; } Brace *b = dynamic_cast(i); if(b) { if(event->button() == Qt::LeftButton) { Entry* e = b->entry; EntryPtr first = e->variations[b->variation][0]; first->hide_next = !first->hide_next; layout(); } else if(event->button() == Qt::RightButton) { QAction *a; QMenu m(this); a = m.addAction(KIcon("pen"), i18n("&Set Comment")); a->setData("comment"); m.addSeparator(); a = m.addAction(KIcon(), i18n("&Promote Variation")); a->setData("promote"); a = m.addAction(KIcon("edit-delete"), i18n("&Remove Variation")); a->setData("remove"); boost::weak_ptr ewptr = boost::weak_ptr(fetch(b->entry->index)); int v = b->variation; a = m.exec(event->globalPos()); /* beware, here, after exec, e could be a dangling pointer */ EntryPtr eptr = ewptr.lock(); if(a && notifier && eptr && eptr->variations.count(v)) { if(a->data() == "comment") startEditing(eptr->index, v); else if(a->data() == "promote") notifier->onUserPromoteVariation(eptr->index.next(v)); else if(a->data() == "remove") notifier->onUserRemoveVariation(eptr->index.next(v)); } } return; } Comment *c = dynamic_cast(i); if(c) { startEditing(c->entry->index, c->variation); return; } Entry *e = dynamic_cast(i); if(e) { if(event->button() == Qt::LeftButton) { if(notifier) notifier->onUserSelectMove(e->index); } else if(event->button() == Qt::RightButton) { QAction *a; QMenu m(this); a = m.addAction(KIcon("pen"), i18n("&Set Comment")); a->setData("comment"); a = m.addAction(KIcon("edit-clear"), i18n("&Clear Variations")); a->setEnabled(!e->variations.empty()); a->setData("clear"); a = m.addAction(KIcon("cut"), i18n("&Truncate")); a->setEnabled(fetch(e->index.next())); a->setData("truncate"); m.addSeparator(); a = m.addAction(KIcon(), i18n("&Promote variation")); a->setEnabled(e->index.nested.size()); a->setData("promote"); a = m.addAction(KIcon("edit-delete"), i18n("&Remove variation")); a->setEnabled(e->index.nested.size()); a->setData("remove"); boost::weak_ptr ewptr = boost::weak_ptr(fetch(e->index)); a = m.exec(event->globalPos()); /* beware, here, after exec, e could be a dangling pointer */ EntryPtr eptr = ewptr.lock(); if(a && notifier && eptr) { if(a->data() == "comment") startEditing(eptr->index, -1); else if(a->data() == "clear") notifier->onUserClearVariations(eptr->index); else if(a->data() == "truncate") notifier->onUserTruncate(eptr->index); else if(a->data() == "promote") notifier->onUserPromoteVariation(eptr->index); else if(a->data() == "remove") notifier->onUserRemoveVariation(eptr->index); } } return; } } void Widget::mouseReleaseEvent ( QMouseEvent * /*event*/ ) { } void Widget::resizeEvent ( QResizeEvent * event ) { stopEditing(); if(event->size().width() != event->oldSize().width()) { layout_width_changed = true; layout(); } } void Widget::layout() { if(layout_pending) return; layout_pending = true; QTimer::singleShot( 0, this, SLOT(doLayout()) ); } void Widget::doLayout() { layout_time = mSecs(); layout_pending = false; layout_max_width = 0; //kDebug() << "layout_must_relayout = " << layout_must_relayout; int h = layoutHistory(history, BORDER_LEFT, BORDER_TOP, -1, 0, 0, true); QSize s(std::max(entry_size*7, layout_max_width+BORDER_RIGHT), std::max(entry_size*10, h+BORDER_BOTTOM) ); setMinimumSize(s); layout_width_changed = false; layout_must_relayout = false; if(layout_goto_selected) { EntryPtr e = fetch(curr_selected); if(e) owner_table->m_scroll_area->ensureVisible( int(e->pos().x() + e->m_rect.width()*0.5), int(e->pos().y() + e->m_rect.height()*0.5) ); layout_goto_selected = false; } } int Widget::layoutHistory(History& array, int at_x, int at_y, int a_prev_turn, int mv_num, int sub_mv_num, bool visible) { int flow_y = at_y; int flow_x = at_x; int nflow_x = at_x; int col_num = 0; int prev_turn = a_prev_turn; for(int i=0;i<(int)array.size();i++) { EntryPtr e = array[i]; /* if this is not visible, hide the item and hide all the number/fregna tags */ if(!visible) { e->disappear(); if(e->number) e->number->disappear(); if(e->fregna) e->fregna->disappear(); if(e->comment) e->comment->disappear(); /* hide the subvariations */ for(Variations::iterator it = e->variations.begin(); it != e->variations.end(); ++it) layoutHistory(it->second, 0, 0, e->move_turn, mv_num, sub_mv_num, false); for(Braces::iterator it = e->braces.begin(); it != e->braces.end(); ++it) it->second->disappear(); for(VComments::iterator it = e->vcomments.begin(); it != e->vcomments.end(); ++it) it->second->disappear(); mv_num++; continue; } /* adjust the position if this is paired on the right */ bool draw_num = false; { if(e->move_turn != prev_turn) { mv_num++; sub_mv_num = 0; } else sub_mv_num++; if(layout_style==0) { if(e->move_turn == 0 || i==0 || array[i-1]->childs_height != 0) { if(mv_num>=1 && (e->move_turn != prev_turn || i==0 || array[i-1]->childs_height != 0)) { draw_num = true; flow_x = at_x; } else flow_x = (mv_num>=1) ? nflow_x : at_x; } else { if(e->move_turn != prev_turn) { flow_x = std::max(flow_x + MIDDLE_PAD, int(MIN_COL_WIDTH*entry_size)); flow_y -= entry_size; } else flow_x = int(MIN_COL_WIDTH*entry_size); } } else { if(e->move_turn != prev_turn || i==0 || array[i-1]->childs_height != 0) { col_num = 0; flow_x = at_x; if(mv_num>=1) draw_num = true; } else if(col_num == layout_style) { col_num = 0; flow_x = nflow_x; } else { flow_y -= entry_size; flow_x = std::max(flow_x + MIDDLE_PAD, at_x + col_num*int(MIN_COL_WIDTH*entry_size)); } } } col_num++; /* update the number */ if(draw_num) { TextPtr& n = e->number; if(!n) { n = TextPtr(new Text(e.get(), 0, this)); if(layout_style==0) n->text = QString::number((mv_num+1)/2)+(mv_num&1 ? "." : ". ..."); else n->text = QString::number(mv_num)+ (sub_mv_num ? "+"+QString::number(sub_mv_num) : QString())+"."; n->needs_update = true; } else if( !n->showing() || layout_must_relayout) n->needs_update = true; /* Mh, the number should never change, only appear disappear. should this change, add here the code to enable number changes. */ QPoint dest(flow_x, flow_y); if(n->pos() != dest) if(n->visible()) n->goTo(dest); else n->moveTo(dest); n->doUpdate(); n->appear(); flow_x += n->width; nflow_x = flow_x; } else if(e->number) e->number->disappear(); /* update the entry */ QPoint dest(flow_x, flow_y); if(e->pos() != dest) if(e->visible()) e->goTo(dest); else e->moveTo(dest); if( !e->showing() || layout_must_relayout) e->needs_update = true; e->doUpdate(); e->appear(); e->childs_height = 0; flow_x += e->m_rect.width(); /* Update the fregna. The fregna is visible if there are subvariations in this entry, or if this entry is the first one of a variation where the remaining entries are hidden and that contains the current position */ bool expandable = !e->variations.empty() || e->comment; bool sel = (e->hide_next && e->indexexpanded && expandable && e->indexindex.next()<=curr_selected)); if(expandable || sel ) { if(!e->fregna) e->fregna = TextPtr(new Text(e.get(), 1, this)); /* update the data, if needed */ TextPtr f = e->fregna; const char *text = (sel||!e->expanded||e->hide_next) ? "[+]" : "[-]"; if(f->text != text || f->selected != sel) { f->text = text; f->selected = sel; f->needs_update = true; } else if( !f->showing() || layout_must_relayout) f->needs_update = true; QPoint dest(flow_x, flow_y); if(f->pos() != dest) if(f->visible()) f->goTo(QPoint(flow_x, flow_y)); else f->moveTo(QPoint(flow_x, flow_y)); f->doUpdate(); f->appear(); flow_x += f->width; } else if(e->fregna) e->fregna->disappear(); /* update the flow information */ flow_y += entry_size; layout_max_width = std::max(flow_x, layout_max_width); int prev_pos = flow_y; /* update the comment */ if(e->comment) { CommentPtr c = e->comment; if(e->expanded && !e->hide_next) { QPoint dest(at_x + COMMENT_INDENTATION, flow_y); if(c->pos() != dest ) { if(c->visible()) c->goTo(dest); else c->moveTo(dest); c->needs_update = true; } else if( !c->showing() || layout_width_changed || layout_must_relayout) c->needs_update = true; c->doUpdate(); c->appear(); flow_y += c->height; } else c->disappear(); } /* update the variations */ for(Variations::iterator it = e->variations.begin(); it != e->variations.end(); ++it) { int old_pos = flow_y; /* update the variation's comment */ if(e->vcomments.count(it->first)) { CommentPtr c = e->vcomments[it->first]; if(e->expanded && !e->hide_next) { QPoint dest(at_x + VAR_INDENTATION + COMMENT_INDENTATION, flow_y); if( !c->showing() || layout_must_relayout) c->needs_update = true; if(c->pos() != dest) if(c->visible()) c->goTo(dest); else c->moveTo(dest); c->doUpdate(); c->appear(); flow_y += c->height; } else c->disappear(); } /* layout the variation */ flow_y = layoutHistory(it->second, at_x + VAR_INDENTATION, flow_y, e->move_turn, mv_num, sub_mv_num, e->expanded && !e->hide_next); /* update the brace of the variation */ BracePtr b = e->braces[it->first]; if(e->expanded && !e->hide_next) { b->depth = e->index.nested.size(); b->setHeight((it->second.size() && it->second[0]->hide_next) ? entry_size : flow_y - old_pos); b->width = VAR_INDENTATION; if(b->visible()) b->goTo(QPoint(at_x, old_pos)); else b->moveTo(QPoint(at_x, old_pos)); b->appear(); } else b->disappear(); } e->childs_height = flow_y - prev_pos; if(e->hide_next) visible = false; prev_turn = e->move_turn; } return flow_y; } QPixmap Widget::getPixmap(const QString& s, bool selected) { QString k = selected ? s+"_sel":s; if(loaded_pixmaps.contains(k)) return loaded_pixmaps[k]; QString iconFile = KStandardDirs::locate("appdata", "piece_icons/" + s + ".png"); QImage img(iconFile); if(selected) { QPainter p(&img); p.setCompositionMode(QPainter::CompositionMode_SourceAtop ); p.fillRect(0,0,img.width(), img.height(), m_settings->select_color); } return loaded_pixmaps[k] = QPixmap::fromImage(img.scaled(m_settings->mv_fmetrics.ascent(), m_settings->mv_fmetrics.ascent(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } void Widget::setComment(EntryPtr e, int v, const QString& comment) { if(comment.isEmpty()) { if(v == -1) { if(e->comment) e->comment = CommentPtr(); } else { if(e->vcomments.count(v)) e->vcomments.erase(v); } } else { CommentPtr p; if(v == -1) { if(!e->comment) e->comment = CommentPtr(new Comment(e.get(), this)); p = e->comment; } else { if(!e->variations.count(v)) return; if(!e->vcomments.count(v)) p = e->vcomments[v] = CommentPtr(new Comment(e.get(), this, v)); else p = e->vcomments[v]; } if(p->text == comment) return; p->text = comment; p->needs_update = true; } layout(); } void Widget::setComment(const Index& index, const QString& comment) { EntryPtr e = fetch(index); if(!e) { kError() << "Invalid index" << index; return; } setComment(e, -1, comment); } void Widget::setVComment(const Index& index, int v, const QString& comment) { EntryPtr e = fetch(index); if(!e || !e->variations.count(v)) { kError() << "Invalid index" << index; return; } setComment(e, v, comment); } void Widget::setMove(const Index& index, int turn, const QString& move, const QString& comment) { DecoratedMove mv; #if 1 mv.push_back(MovePart(move)); #else //TODO: move this code in some other place, it really should not stay here QRegExp reg("[KQRBNP]"); int x = 0; while(reg.indexIn(move, x) != -1) { if(reg.pos() > x) mv.push_back(MovePart(MoveText, move.mid(x, reg.pos()-x))); mv.push_back(MovePart(MovePixmap, reg.cap().toLower())); x = reg.pos() + reg.matchedLength(); } if(xmove_turn = turn; e->move = move; e->needs_update = true; setComment(e, -1, comment); layout(); return; } int at; History *vec = fetchRef(index.prev(), &at); if(!vec) { kError() << "Invalid index" << index; return; } if(index.nested.size() && index.nested.back().num_moves == 0) { History var; int v = index.nested.back().variation; var.push_back(e = EntryPtr( new Entry(turn, move, index, this)) ); (*vec)[at]->variations[v] = var; (*vec)[at]->braces[v] = BracePtr( new Brace( (*vec)[at].get(), v, this) ); } else vec->push_back(e = EntryPtr( new Entry(turn, move, index, this)) ); setComment(e, -1, comment); e->hide(); layout(); } void Widget::remove(const Index& index) { if(index.atVariationStart() ) { EntryPtr e = fetch(index.prev()); if(!e) return; int v = index.nested.back().variation; if(!e->variations.count(v)) return; e->variations.erase(v); e->braces.erase(v); e->vcomments.erase(v); } else { int at; History *vec = fetchRef(index, &at); if(!vec) return; while((int)vec->size() > at) vec->pop_back(); } layout(); } void Widget::fixIndices(const Index& ix) { int at; History *vec = fetchRef(ix, &at); if(!vec) { kError() << "Invalid index" << ix; return; } Index index = ix; for(int i=at;i<(int)vec->size();i++) { EntryPtr e = (*vec)[i]; e->index = index; for(Variations::const_iterator it = e->variations.begin(); it != e->variations.end(); ++it) fixIndices(index.next(it->first)); index = index.next(); } } void Widget::promoteVariation(const Index& ix, int v) { int at; History *vec = fetchRef(ix, &at); if(!vec) { kError() << "Invalid index" << ix; return; } History vold = (*vec)[at]->variations[v]; History vnew; for(int i=at+1; i<(int)vec->size(); i++) vnew.push_back((*vec)[i]); while((int)vec->size()>at+1) vec->pop_back(); for(int i=0; i<(int)vold.size(); i++) vec->push_back(vold[i]); (*vec)[at]->variations[v] = vnew; Q_ASSERT((int)vec->size()>at+1); (*vec)[at+1]->hide_next = false; fixIndices(ix.next()); fixIndices(ix.next(v)); curr_selected = curr_selected.flipVariation(ix, v); curr_highlight = curr_highlight.flipVariation(ix, v); layout(); } void Widget::select(const Index& index) { if(curr_selected == index) return; EntryPtr e = fetch(index); EntryPtr olde = fetch(curr_selected); if(olde) { olde->selected = false; olde->needs_update = true; } if(e) { e->selected = true; e->needs_update = true; layout_goto_selected = true; } curr_selected = index; layout(); } void Widget::setLoaderTheme(const ThemeInfo& theme) { m_loader.setTheme(theme); } //END Widget------------------------------------------------------------------- } //end namespace MoveList tagua-1.0-alpha2/src/movelist_notifier.h000066400000000000000000000036521077523320400203320ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef MOVELIST_NOTIFIER_H #define MOVELIST_NOTIFIER_H #include "index.h" namespace MoveList { class Widget; /** * @class Notifier * @brief An observer class for user actions on the movelist. * * This class can be registered to a MoveList::Widget to be notified * of user interactions with the move list. */ class Notifier { public: virtual ~Notifier(){} /** the user clicked on a move */ virtual void onUserSelectMove(const Index&) = 0; /** the user changed a comment */ virtual void onUserSetComment(const Index&, QString) = 0; /** the user changed a comment at the start of a variation */ virtual void onUserSetVComment(const Index&, int v, QString) = 0; /** the user wants to clear all the subvariations of the given index */ virtual void onUserClearVariations(const Index&) = 0; /** the user wants to truncate the game at the given index */ virtual void onUserTruncate(const Index&) = 0; /** the user wants to clear all the subvariations of the given entry */ virtual void onUserPromoteVariation(const Index&) = 0; /** the user wants to remove the subvariations containing the given entry */ virtual void onUserRemoveVariation(const Index&) = 0; /** the user wants to undo last change */ virtual void onUserUndo() = 0; /** the user wants to redo last change */ virtual void onUserRedo() = 0; /** this notifier has been kicked off by the movelist */ virtual void onDetachNotifier() = 0; }; } #endif //MOVELIST_NOTIFIER_H tagua-1.0-alpha2/src/movelist_p.h000066400000000000000000000107101077523320400167430ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef MOVELIST_P_H #define MOVELIST_P_H #include #include #include #include #include #include #include #include "index.h" #include "decoratedmove.h" #include "kgamecanvas.h" namespace MoveList { typedef boost::shared_ptr EntryPtr; typedef boost::shared_ptr BracePtr; typedef boost::shared_ptr TextPtr; typedef boost::shared_ptr CommentPtr; typedef std::vector History; typedef std::map Variations; typedef std::map Braces; typedef std::map VComments; class Settings { public: bool anim_enabled; bool anim_moving; bool anim_hideshow; bool anim_highlight; int anim_speed; int anim_smoothness; double anim_time; QColor select_color; QColor comment_color; QString icons; bool use_mv_font; bool use_comm_font; QFont mv_font; QFontMetrics mv_fmetrics; QFont sel_mv_font; QFontMetrics sel_mv_fmetrics; QFont comm_font; QFontMetrics comm_fmetrics; Settings() : mv_fmetrics(QFont()) , sel_mv_fmetrics(QFont()) , comm_fmetrics(QFont()) {} void load(); void save(); }; class FancyItem : public KGameCanvasItem { public: int time_pos; QPoint target_pos; QPoint old_pos; int time_opacity; int target_opacity; int old_opacity; bool highlighted; int curr_highlight; int time_highlight; int target_highlight; int old_highlight; FancyItem(KGameCanvasAbstract* c = NULL) : KGameCanvasItem(c) , time_pos(-1) , time_opacity(-1) , highlighted(false) , curr_highlight(0) , time_highlight(-1) { } bool showing(); void appear(); void disappear(); void goTo(QPoint pos); void setHighlight(bool h); virtual bool canStop() { return time_highlight==-1 && time_pos==-1 && time_opacity==-1; } virtual void advance(int time); virtual bool layered() const; }; class Brace : public FancyItem { public: int width; int height; int depth; Entry* entry; int variation; int time_height; int target_height; int old_height; virtual void paint (QPainter *p); virtual QRect rect () const; void setHeight(int h); virtual bool canStop() { return time_height==-1 && FancyItem::canStop(); } virtual void advance(int time); Brace(Entry* e, int var, KGameCanvasAbstract* c = NULL) : FancyItem(c) , width(0) , height(0) , entry(e) , variation(var) , time_height(-1) { } }; class Text : public FancyItem { public: int width; int height; int type; bool selected; QString text; Entry *entry; bool needs_update; void doUpdate(); virtual void paint (QPainter *p); virtual QRect rect () const; Text(Entry* e, int t, KGameCanvasAbstract* c = NULL) : FancyItem(c) , width(0) , height(0) , type(t) , selected(false) , entry(e) , needs_update(true) {} }; class Comment : public FancyItem { public: int width; int height; QString text; Entry *entry; int variation; bool needs_update; void doUpdate(); virtual void paint (QPainter *p); virtual QRect rect () const; Comment(Entry* e, KGameCanvasAbstract* c = NULL, int v = -1) : FancyItem(c) , width(0) , height(0) , entry(e) , variation(v) , needs_update(true) {} }; class Entry : public FancyItem { public: bool expanded; bool hide_next; bool selected; QRect m_rect; int m_ascent; int childs_height; int move_turn; DecoratedMove move; Index index; bool needs_update; TextPtr number; TextPtr fregna; CommentPtr comment; Variations variations; Braces braces; VComments vcomments; void doUpdate(); virtual void paint (QPainter *p); virtual QRect rect () const; virtual bool canStop() { return time_highlight==-1 && FancyItem::canStop(); } Entry(int turn, const DecoratedMove& m, const Index& i, KGameCanvasAbstract* c = NULL) : FancyItem(c) , expanded(true) , hide_next(false) , selected(false) , move_turn(turn) , move(m) , index(i) , needs_update(true) {} }; } #endif //MOVELIST_P_H tagua-1.0-alpha2/src/movelist_table.cpp000066400000000000000000000104051077523320400201270ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include #include #include #include #include #include "mastersettings.h" #include "movelist_textual.h" #include "movelist_notifier.h" #include "movelist_widget.h" #include "movelist_table.h" namespace MoveList { //BEGIN Table------------------------------------------------------------------ Table::Table(QWidget* w) : QWidget(w) { setWindowTitle("Move List"); QVBoxLayout *vbox = new QVBoxLayout(this); // here there used to be a QTabWidget m_scroll_area = new QScrollArea(this); m_movelist = new Widget(m_scroll_area, this); m_scroll_area->setFocusPolicy(Qt::NoFocus); m_scroll_area->setWidgetResizable(true); m_scroll_area->setWidget(m_movelist); vbox->addWidget(m_scroll_area); m_movelist_textual = NULL; //m_movelist_textual = new Textual(tw); //tw->addTab(m_movelist_textual->widget(), KIcon("html"), "&Html"); } void Table::settingsChanged() { if(m_movelist) m_movelist->settingsChanged(); if(m_movelist_textual) m_movelist_textual->settingsChanged(); } void Table::setLoaderTheme(const ThemeInfo& theme) { if(m_movelist) m_movelist->setLoaderTheme(theme); if(m_movelist_textual) m_movelist_textual->setLoaderTheme(theme); } void Table::onUndo() { if(m_movelist->notifier) if(m_movelist) m_movelist->notifier->onUserUndo(); } void Table::onRedo() { if(m_movelist->notifier) if(m_movelist) m_movelist->notifier->onUserRedo(); } void Table::setComment(const Index& index, const QString& comment) { if(m_movelist) m_movelist->setComment(index, comment); if(m_movelist_textual) m_movelist_textual->setComment(index, comment); } void Table::setVComment(const Index& index, int v, const QString& comment, bool confirm_promotion) { if(!confirm_promotion) if(m_movelist) m_movelist->setVComment(index, v, comment); if(m_movelist_textual) m_movelist_textual->setVComment(index, v, comment); } void Table::setMove(const Index& index, int turn, const DecoratedMove& move, const QString& comment, bool confirm_promotion) { if(!confirm_promotion) if(m_movelist) m_movelist->setMove(index, turn, move, comment); if(m_movelist_textual) m_movelist_textual->setMove(index, turn, move, comment); } void Table::setMove(const Index& index, int turn, const QString& move, const QString& comment, bool confirm_promotion) { if(!confirm_promotion) if(m_movelist) m_movelist->setMove(index, turn, move, comment); if(m_movelist_textual) m_movelist_textual->setMove(index, turn, move, comment); } void Table::remove(const Index& index, bool confirm_promotion) { if(!confirm_promotion) if(m_movelist) m_movelist->remove(index); if(m_movelist_textual) m_movelist_textual->remove(index); } void Table::Table::promoteVariation(const Index& ix, int v) { if(m_movelist) m_movelist->promoteVariation(ix, v); //m_movelist_textual->promoteVariation(index); } void Table::select(const Index& index, bool confirm_promotion) { if(!confirm_promotion) if(m_movelist) m_movelist->select(index); if(m_movelist_textual) m_movelist_textual->select(index); } void Table::reset() { if(m_movelist) m_movelist->reset(); if(m_movelist_textual) m_movelist_textual->reset(); } Notifier* Table::getNotifier() { return m_movelist->getNotifier(); } void Table::setNotifier(Notifier* n, bool detach_prev) { if(m_movelist) m_movelist->setNotifier(n, detach_prev); if(m_movelist_textual) m_movelist_textual->setNotifier(n, false); //false here, it is important } int Table::layoutStyle() { return m_movelist->layoutStyle(); } void Table::setLayoutStyle(int x) { if(m_movelist) m_movelist->setLayoutStyle(x); if(m_movelist_textual) m_movelist_textual->setLayoutStyle(x); } //END Table-------------------------------------------------------------------- } //end namespace MoveList tagua-1.0-alpha2/src/movelist_table.h000066400000000000000000000050451077523320400176000ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef MOVELIST_TABLE_H #define MOVELIST_TABLE_H #include #include "movelist_widget.h" class QAction; class QScrollArea; class ThemeInfo; namespace MoveList { class Widget; class Textual; /** * @class Table * @brief The widget that holds the move list in a scrolled view. * * This class is a widget that contains a MoveList::Widget and a few * convenience buttons for undo and redo. */ class Table : public QWidget { Q_OBJECT public: /** the scroll area that contains the move list */ QScrollArea *m_scroll_area; /** the move list widget */ Widget *m_movelist; /** the move list textual widget */ Textual *m_movelist_textual; Table(QWidget* p = NULL); void settingsChanged(); void setLoaderTheme(const ThemeInfo& theme); /** Sets the move comment at the given index */ void setComment(const Index& index, const QString& comment); /** Sets the comment at the given index before the give subvariation */ void setVComment(const Index& index, int v, const QString& comment, bool confirm_promotion = false); /** Sets the move at the given index */ void setMove(const Index& index, int turn, const DecoratedMove& move, const QString& comment = QString(), bool confirm_promotion = false); /** Sets the move at the given index */ void setMove(const Index& index, int turn, const QString& move, const QString& comment = QString(), bool confirm_promotion = false); /** Removes the given index and all those that come after */ void remove(const Index& index, bool confirm_promotion = false); /** Promotes the given variation in the main line */ void promoteVariation(const Index& ix, int v); void reset(); Notifier* getNotifier(); void setNotifier(Notifier* n, bool detach_prev=true); int layoutStyle(); void setLayoutStyle(int x); /** Sets the currently selected index */ void select(const Index& index, bool confirm_promotion = false); private Q_SLOTS: void onUndo(); void onRedo(); }; } //end namespace MoveList #endif //MOVELIST_TABLE_H tagua-1.0-alpha2/src/movelist_textual.cpp000066400000000000000000000276301077523320400205360ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifdef HAVE_KHTML #include #include #include #include #include #include #include #include #include #include #include #include "mastersettings.h" #include "decoratedmove.h" #include "movelist_p.h" #include "movelist_textual.h" namespace MoveList { Textual::Textual(QWidget *parent) : KHTMLPart(parent, parent, KHTMLPart::BrowserViewGUI) , m_curr_selected(-1) , m_layout_style(0) { m_loader.setSize(12); connect(browserExtension(), SIGNAL(openUrlRequest(const KUrl&,const KParts::URLArgs&)), this, SLOT(onURL(const KUrl&))); setJScriptEnabled(false); setJavaEnabled(false); setMetaRefreshEnabled(false); setPluginsEnabled(false); QString fpath = KStandardDirs::locate("appdata", "scripts/movelist_textual.html"); //kDebug() << "HTML file is:"<< fpath; QFile file(fpath); file.open(QIODevice::ReadOnly); QTextStream stream(&file); QString html = stream.readAll(); //kDebug() << "Using HTML:"< Error in Textual::onURL, what should i do with url \""<< u <<"\"?"; return; } QString p = u.mid(8); Index ix = Index::fromString(p); kDebug() << "Open Link \"" << p << "\" = \"" << ix << "\""; m_notifier->onUserSelectMove(ix); } void Textual::setComment(const Index& index, const QString& comment) { DOM::HTMLDocument document = htmlDocument(); DOM::Element this_cm = document.getElementById("cm_"+index); if(this_cm.isNull()) { kDebug() << " --> Error in Textual::setComment, invalid index!"; return; } clear_node(this_cm); if(!comment.isEmpty()) { this_cm.appendChild(document.createTextNode(comment)); this_cm.appendChild(document.createTextNode(QString(" "))); } } void Textual::setVComment(const Index& index, int v, const QString& comment) { DOM::HTMLDocument document = htmlDocument(); DOM::Element this_cm = document.getElementById("vk_"+index.next(v)); if(this_cm.isNull()) { kDebug() << " --> Error in Textual::setVComment, invalid index!"; return; } clear_node(this_cm); if(!comment.isEmpty()) { this_cm.appendChild(document.createTextNode(comment)); this_cm.appendChild(document.createTextNode(QString(" "))); } } void Textual::remove(const Index& index) { DOM::HTMLDocument document = htmlDocument(); if(index.atVariationStart()) { DOM::Element vc = document.getElementById("vc_"+index); if(!vc.isNull()) { /* remove a number? */ DOM::Element comm(vc.previousSibling()); DOM::Element mvnum(vc.nextSibling()); if(!mvnum.isNull() && mvnum.getAttribute("id").string().startsWith("nm_") && !comm.isNull() && comm.getAttribute("id").string().startsWith("cm_")) { DOM::Element move(mvnum.nextSibling()); int mv_num = move.getAttribute("mvnum").string().toInt(); int sub_mv_num = move.getAttribute("submvnum").string().toInt(); if(!(mv_num>0 && (sub_mv_num==0 && (mv_num%2 || m_layout_style)))) mvnum.parentNode().removeChild(mvnum); } vc.parentNode().removeChild(vc); } } else { DOM::Element rm = document.getElementById("nm_"+index); if(rm.isNull()) rm = document.getElementById("mv_"+index); if(!rm.isNull()) clear_from(rm); } if(m_curr_selected >= index) m_curr_selected = Index(-1); } void Textual::select(const Index& index) { if(index == m_curr_selected) return; DOM::HTMLDocument document = htmlDocument(); DOM::Element currs = document.getElementById("mv_"+m_curr_selected); DOM::Element news = document.getElementById("mv_"+index); if(!currs.isNull()) currs.style().removeProperty("background-color"); if(!news.isNull()) news.style().setProperty("background-color", "#C0E0FF", "important"); m_curr_selected = index; } void Textual::setMove(const Index& index, int turn, const QString& move, const QString& comment) { DecoratedMove m; m << MovePart(move); setMove(index, turn, m, comment); } // void Textual::setMove(const Index& index, int turn, const DecoratedMove& move, // const QString& comment) { // setMove(index, turn, move[0].m_string, comment); // } void Textual::setMove(const Index& index, int turn, const DecoratedMove& move, const QString& comment) { //kDebug() << "i= " << index; DOM::HTMLDocument document = htmlDocument(); QString istr = (QString)index; DOM::Element this_mv = document.getElementById("mv_"+istr); DOM::Element this_cm = document.getElementById("cm_"+istr); if(!this_mv.isNull() && !this_cm.isNull()) { clear_node(this_mv); for(int i=0;i Error in Textual::setMove, no previous move!"; return; } } int mv_num = 0; int sub_mv_num = 0; if(!prev_mv.isNull()) { int prev_turn = prev_mv.getAttribute("turn").string().toInt(); int prev_mv_num = prev_mv.getAttribute("mvnum").string().toInt(); int prev_sub_mv_num = prev_mv.getAttribute("submvnum").string().toInt(); if(prev_turn != turn) mv_num = prev_mv_num+1; else { mv_num = prev_mv_num; sub_mv_num = prev_sub_mv_num+1; } } if(!index.nested.size()) { parent = document.body(); if(parent.isNull()) { kDebug() << "QUEEEEEEEEE!!!!!!!"; return; } } else if(index.atVariationStart()) { QString var_id = "vc_" + istr; DOM::Element add_before = prev_cm.nextSibling(); while(!add_before.isNull()) { QString id = add_before.getAttribute("id").string(); if(id.startsWith("vc_") && id < var_id) add_before = add_before.nextSibling(); else break; } DOM::Element var_el = document.createElement("span"); var_el.setAttribute("id", var_id); var_el.setAttribute("class", "variation"); var_el.appendChild(document.createTextNode("[ ")); parent = document.createElement("span"); parent.setAttribute("id", "vr_" + istr); DOM::Element vk_el = document.createElement("span"); vk_el.setAttribute("id", "vk_" + istr); vk_el.setAttribute("class", "comment"); //vk_el.setContentEditable(true); parent.appendChild(vk_el); var_el.appendChild(parent); var_el.appendChild(document.createTextNode("] ")); prev_cm.parentNode().insertBefore(var_el, add_before); if(!add_before.isNull() && add_before.getAttribute("id").string().startsWith("mv_")) { int mv_num = add_before.getAttribute("mvnum").string().toInt(); int sub_mv_num = add_before.getAttribute("submvnum").string().toInt(); QString num_str; if(m_layout_style == 0) { if(mv_num%2) num_str = QString("%1. ").arg((mv_num+1)/2); else num_str = QString("%1. ... ").arg((mv_num+2)/2); } else { if(sub_mv_num==0) num_str = QString("%1. ").arg(mv_num); else num_str = QString("%1+%2. ").arg(mv_num).arg(sub_mv_num); } DOM::Element num_el = document.createElement("a"); num_el.setAttribute("class", "mvnum"); num_el.setAttribute("id", "nm_"+istr); num_el.appendChild(document.createTextNode(num_str)); prev_cm.parentNode().insertBefore(num_el, add_before); } } else { Index pi = index.prev(index.nested.back().num_moves); parent = document.getElementById("vr_"+pi); if(parent.isNull()) { kDebug() << " --> Error in Textual::setMove, no variation?!?!?"; return; } } if(mv_num>0 && ((sub_mv_num==0 && (mv_num%2 || m_layout_style)) || parent.lastChild() != prev_cm) ) { QString num_str; if(m_layout_style == 0) { if(mv_num%2) num_str = QString("%1. ").arg((mv_num+1)/2); else num_str = QString("%1. ... ").arg((mv_num+2)/2); } else { if(sub_mv_num==0) num_str = QString("%1. ").arg(mv_num); else num_str = QString("%1+%2. ").arg(mv_num).arg(sub_mv_num); } DOM::Element num_el = document.createElement("a"); num_el.setAttribute("class", "mvnum"); num_el.setAttribute("id", "nm_"+istr); num_el.appendChild(document.createTextNode(num_str)); parent.appendChild(num_el); } DOM::Element mv_el = document.createElement("a"); mv_el.setAttribute("id", "mv_"+istr); mv_el.setAttribute("href", "index://"+istr); mv_el.setAttribute("class", "move"); mv_el.setAttribute("turn", QString::number(turn)); mv_el.setAttribute("mvnum", QString::number(mv_num)); mv_el.setAttribute("submvnum", QString::number(sub_mv_num)); for(int i=0;i(move[i].m_string); DOM::Element el = document.createElement("span"); #if 1 kDebug() << "size = " << QString("%1%").arg(g.m_font.pointSize()*100/12); el.style().setProperty("font-size", QString("%1%").arg(g.m_font.pointSize()*100/12), "important"); el.style().setProperty("line-height", QString("%1%").arg(g.m_font.pointSize()*100/12), "important"); #endif kDebug() << "familiy = " << g.m_font.family(); el.style().setProperty("font-weight", "normal", "important"); el.style().setProperty("font-family", g.m_font.family(), "important"); DOM::Text t = document.createTextNode(QString(g.m_char)); el.appendChild(t); mv_el.appendChild(el); } else { DOM::Text t = document.createTextNode(move[i].m_string); mv_el.appendChild(t); } } parent.appendChild(mv_el); parent.appendChild(document.createTextNode(QString(" "))); DOM::Element cm_el = document.createElement("span"); cm_el.setAttribute("id", "cm_"+istr); cm_el.setAttribute("class", "comment"); if(!comment.isEmpty()) { cm_el.appendChild(document.createTextNode(comment)); cm_el.appendChild(document.createTextNode(QString(" "))); } //cm_el.setContentEditable(true); parent.appendChild(cm_el); } void Textual::reset() { clear_node(htmlDocument().body()); setMove(0, -1, "Mainline:"); } Notifier* Textual::getNotifier() { return m_notifier; } void Textual::setNotifier(Notifier* n, bool detach_prev) { if(detach_prev && m_notifier && m_notifier != n) m_notifier->onDetachNotifier(); m_notifier = n; } int Textual::layoutStyle() { return m_layout_style; } void Textual::setLayoutStyle(int x) { m_layout_style = x; } } //end namespace MoveList #endif //HAVE_KHTML tagua-1.0-alpha2/src/movelist_textual.h000066400000000000000000000061231077523320400201750ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef MOVELIST_TEXTUAL_H #define MOVELIST_TEXTUAL_H #ifdef HAVE_KHTML #include #include #include #include "decoratedmove.h" #include "pixmaploader.h" #include "movelist_notifier.h" class KHTMLPart; class KUrl; class ThemeInfo; namespace MoveList { class Textual : public KHTMLPart { Q_OBJECT Index m_curr_selected; int m_layout_style; Notifier *m_notifier; PixmapLoader m_loader; public: Textual(QWidget *parent = NULL); void settingsChanged() {} void setLoaderTheme(const ThemeInfo& theme) { m_loader.setTheme(theme); } /** Sets the move comment at the given index */ void setComment(const Index& index, const QString& comment); /** Sets the comment at the given index before the give subvariation */ void setVComment(const Index& index, int v, const QString& comment); /** Sets the move at the given index */ void setMove(const Index& index, int turn, const DecoratedMove& move, const QString& comment = QString()); /** Sets the move at the given index */ void setMove(const Index& index, int turn, const QString& move, const QString& comment = QString()); /** Removes the given index and all those that come after */ void remove(const Index& index); void reset(); Notifier* getNotifier(); void setNotifier(Notifier* n, bool detach_prev=true); int layoutStyle(); void setLayoutStyle(int x); /** Sets the currently selected index */ void select(const Index& index); private Q_SLOTS: void onURL(const KUrl &url); }; } //end namespace MoveList #else //HAVE_KHTML #include #include "decoratedmove.h" #include "index.h" class ThemeInfo; namespace MoveList { class Notifier; class Textual : public QWidget { Q_OBJECT public: Textual(QWidget *parent = NULL) : QWidget(parent){} void settingsChanged() {} void setLoaderTheme(const ThemeInfo& /*theme*/){} void setComment(const Index& /*index*/, const QString& /*comment*/){} void setVComment(const Index& /*index*/, int /*v*/, const QString& /*comment*/){} void setMove(const Index& /*index*/, int /*turn*/, const DecoratedMove& /*move*/, const QString& /*comment*/ = QString()){} void setMove(const Index& /*index*/, int /*turn*/, const QString& /*move*/, const QString& /*comment*/ = QString()){} void remove(const Index& /*index*/){} void reset(){} Notifier* getNotifier(){ return NULL; } void setNotifier(Notifier* /*n*/, bool /*detach_prev*/=true){} int layoutStyle(){ return 0; } void setLayoutStyle(int /*x*/){} void select(const Index& /*index*/){} }; } //end namespace MoveList #endif //HAVE_KHTML #endif //MOVELIST_TEXTUAL_H tagua-1.0-alpha2/src/movelist_widget.cpp000066400000000000000000000006121077523320400203220ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ tagua-1.0-alpha2/src/movelist_widget.h000066400000000000000000000106251077523320400177740ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef MOVELISTWIDGET_H #define MOVELISTWIDGET_H #include #include #include #include #include #include #include #include #include "index.h" #include "decoratedmove.h" #include "pixmaploader.h" #include "kgamecanvas.h" class ThemeInfo; namespace MoveList { typedef boost::shared_ptr EntryPtr; typedef boost::shared_ptr BracePtr; typedef boost::shared_ptr TextPtr; typedef boost::shared_ptr CommentPtr; typedef std::vector History; typedef std::map Variations; typedef std::map Braces; typedef std::map VComments; class Notifier; class Table; class Settings; /** * @class Widget * @brief The widget can be used to display a tree of moves. * * This class is a widget that can be used to display a tree of moves */ class Widget : public KGameCanvasWidget { private: Q_OBJECT friend class FancyItem; friend class Entry; friend class Brace; friend class Text; friend class Comment; friend class Table; History history; int entry_size; Index curr_highlight; int curr_highlight_type; Index curr_selected; boost::weak_ptr edited_comment; int edited_comment_variation; class QTextEdit* comment_editor; int layout_max_width; bool layout_pending; int layout_style; int layout_time; bool layout_goto_selected; bool layout_width_changed; bool layout_must_relayout; Notifier *notifier; QHash loaded_pixmaps; Table *owner_table; Settings *m_settings; PixmapLoader m_loader; History* fetchRef(const Index& ix, int* idx = NULL); EntryPtr fetch(const Index& ix); bool eventFilter(QObject *obj, QEvent *event); void startEditing(const Index& ix, int v); void stopEditing(); void layout(); int layoutHistory(History& array, int at_x, int at_y, int prev_turn, int mv_num, int sub_mv_num, bool visible); void fixIndices(const Index& ix); void setComment(EntryPtr e, int v, const QString& comment); QPixmap getPixmap(const QString& s, bool selected = false); virtual void resizeEvent ( QResizeEvent * event ); virtual void mouseMoveEvent ( QMouseEvent * event ); virtual void mousePressEvent ( QMouseEvent * event ); virtual void mouseReleaseEvent ( QMouseEvent * event ); private Q_SLOTS: void doLayout(); public: Widget(QWidget *parent = NULL, Table *o = NULL); virtual ~Widget(); Notifier* getNotifier(); void setNotifier(Notifier* n, bool detach_prev=true); void settingsChanged(); void setLoaderTheme(const ThemeInfo& theme); /** Clears all the moves */ void reset(); /** returns the style of layout */ int layoutStyle(){ return layout_style; } /** sets the style of layout. 0 mean the the moves are paired, like in chess. any value x>0 will layout the moves in x columns for each player (useful for progressive chess, for instance) */ void setLayoutStyle(int x) { layout_style = x; layout(); } /** Sets the move comment at the given index */ void setComment(const Index& index, const QString& comment); /** Sets the comment at the given index before the give subvariation */ void setVComment(const Index& index, int v, const QString& comment); /** Sets the move at the given index */ void setMove(const Index& index, int turn, const DecoratedMove& move, const QString& comment = QString()); /** Sets the move at the given index */ void setMove(const Index& index, int turn, const QString& move, const QString& comment = QString()); /** Removes the given index and all those that come after */ void remove(const Index& index); /** Promotes the given variation in the main line */ void promoteVariation(const Index& ix, int v); /** Sets the currently selected index */ void select(const Index& index); }; } //end namespace #endif tagua-1.0-alpha2/src/movement.cpp000066400000000000000000000034761077523320400167620ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "movement.h" #include "common.h" #include using std::abs; #define QUINTIC_SIGMOID double Movement::sigmoid(double t) { #ifdef CUBIC_SIGMOID return -2 * pow(t - 0.5, 3) + 1.5 * t - 0.25; #else return 6 * pow(t - 0.5, 5) - 5 * pow(t, 3) + 7.5 * t * t - 15 * 0.125 * t + 3.0 / 16; #endif } double Movement::half_sigmoid(double t) { // use the second half of the sigmoid parameterization return sigmoid(0.5 * (t + 1)); } LinearMovement::LinearMovement(const QPoint& from, const QPoint& to, bool /*rotate*/) : m_from(from) , m_velocity(to - from) { } QPoint LinearMovement::pos(double t) const { return m_from + m_velocity * t; } LMovement::LMovement(const QPoint& from, const QPoint& to, bool rotate) : m_from(from) , m_velocity(to - from) , m_rotate(rotate) { if (abs(static_cast(m_velocity.x())) >= abs(static_cast(m_velocity.y()))) { m_x = LMovement::nonlinear; m_y = LMovement::linear; } else { m_y = LMovement::nonlinear; m_x = LMovement::linear; } } double LMovement::nonlinear(double t) { return (exp( (double)(3 * t) ) - 1) / (exp( (double)3 ) - 1); } QPoint LMovement::pos(double t) const { return m_from + QPoint( static_cast(m_velocity.x() * m_x(t)), static_cast(m_velocity.y() * m_y(t))); } double LMovement::rotation(double t) const { if(!m_rotate) return 0.0; double r = (1.0-cos(t*M_PI))*M_PI; return m_velocity.x() >= 0 ? r : -r; } tagua-1.0-alpha2/src/movement.h000066400000000000000000000046431077523320400164240ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef MOVEMENT_H #define MOVEMENT_H #include #include /** * Abstract class representing a parameterization of a curve * in a plane and a rotation angle. * The parameter @a t for both the position and the rotation * is assumed to lie in the closed interval [0,1]. */ class Movement { public: virtual ~Movement() { } virtual QPoint pos(double t) const = 0; virtual double rotation(double /*t*/) const { return 0.0; } static double sigmoid(double t); static double half_sigmoid(double t); }; /** * A straight path, no rotation. */ class LinearMovement : public Movement { QPoint m_from; QPoint m_velocity; public: /// create a path from @a from to @a to. LinearMovement(const QPoint& from, const QPoint& to, bool /*rotate*/); virtual QPoint pos(double t) const; }; /** * An L-shaped path. First along the shortest side, then along the other. * Use an exponential parameterization for the longest side. */ class LMovement : public Movement { QPoint m_from; QPoint m_velocity; bool m_rotate; double (*m_x)(double); double (*m_y)(double); static double linear(double t) { return t; } static double nonlinear(double t); public: /// create an L-path from @a from to @a to. LMovement(const QPoint& from, const QPoint& to, bool rotate = false); virtual QPoint pos(double t) const; virtual double rotation(double t) const; }; /** * Movement mixin: apply to a Movement to get a sigmoidal * variant of it. */ template class SigmoidalMovement : public Mov { public: SigmoidalMovement(const QPoint& from, const QPoint& to, bool rotate = false) : Mov(from, to, rotate) { } virtual QPoint pos(double t) const { return Mov::pos(Movement::sigmoid(t)); } }; template class HalfSigmoidalMovement : public Mov { public: HalfSigmoidalMovement(const QPoint& from, const QPoint& to, bool rotate = false) : Mov(from, to, rotate) { } virtual QPoint pos(double t) const { return Mov::pos(Movement::half_sigmoid(t)); } }; #endif // MOVEMENT_H tagua-1.0-alpha2/src/namedsprite.cpp000066400000000000000000000013161077523320400174320ustar00rootroot00000000000000/* Copyright (c) 2006-2007 Paolo Capriotti (c) 2006-2007 Maurizio Monge 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. */ #include "namedsprite.h" NamedSprite::NamedSprite() { } NamedSprite NamedSprite::duplicate() const { if (m_sprite) { return NamedSprite(m_name, SpritePtr(m_sprite->duplicate())); } else { return *this; } } NamedSprite::NamedSprite(const QString& name, const SpritePtr& s) : m_name(name) , m_sprite(s) { } tagua-1.0-alpha2/src/namedsprite.h000066400000000000000000000015071077523320400171010ustar00rootroot00000000000000/* Copyright (c) 2006-2007 Paolo Capriotti (c) 2006-2007 Maurizio Monge 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. */ #ifndef NAMEDSPRITE_H #define NAMEDSPRITE_H #include #include "sprite.h" #include "fwd.h" class NamedSprite { public: QString m_name; SpritePtr m_sprite; NamedSprite(); NamedSprite(const QString& name, const SpritePtr& s); QString name() const { return m_name; } SpritePtr sprite() const { return m_sprite; } operator bool() const { return !!m_sprite; } NamedSprite duplicate() const; }; #endif //NAMEDSPRITE_H tagua-1.0-alpha2/src/newgame.cpp000066400000000000000000000015121077523320400165400ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "newgame.h" #include "foreach.h" #include "variants.h" NewGame::NewGame(QWidget* parent) : QDialog(parent) { setupUi(this); QStringList variants = Variants::instance().all(); foreach (QString variant, variants) { m_variant->addItem(variant, QVariant(variant)); } } QString NewGame::variant() const { return m_variant->itemData(m_variant->currentIndex()).toString(); } bool NewGame::newTab() const { return m_new_tab->isChecked(); } tagua-1.0-alpha2/src/newgame.h000066400000000000000000000011771077523320400162140ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef NEWGAME_H #define NEWGAME_H #include #include "ui_newgamedialog.h" class NewGame : public QDialog, public Ui::NewGameDialog { Q_OBJECT public: NewGame(QWidget* parent = 0); QString variant() const; bool newTab() const; }; #endif tagua-1.0-alpha2/src/nopool.h000066400000000000000000000007721077523320400160770ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef NO_POOL #define NO_POOL /// Placeholder for variants that do not have pools. class NoPool { }; #endif // NO_POOL tagua-1.0-alpha2/src/option.cpp000066400000000000000000000360641077523320400164370ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include #include #include "settings.h" #include "common.h" #include "option.h" #include "option_p.h" OptionWidget::OptionWidget(const OptList& options, QWidget* parent) : QWidget(parent) , m_dont_fire(false) , m_options(options) { setupOptionWidget(this, m_options); } void OptionWidget::notifyChange() { if(m_dont_fire) m_changed = true; else { dump_options_list(m_options); changed(m_options); } } void OptionWidget::setValues(OptList& newopts) { m_changed = false; m_dont_fire = true; setOptionWidgetValues(this, newopts); m_dont_fire = false; if(m_changed) notifyChange(); } void OptionWidget::setupOptionWidget(QWidget* widget, OptList& options, bool indent) { QGridLayout *layout = new QGridLayout(widget); if(indent) layout->setMargin(0); int left = indent ? 1 : 0; int right = indent ? 2 : 1; int lpos = 0; for(int i=0;i(_o)) { OptCheckBox *cb = new OptCheckBox(o, this, widget); cb->setObjectName(QString("%02d_check").arg(i)); layout->addWidget(cb, lpos++, left, 1, 2); if(o->m_sub_options.size()) { QWidget *w = new QWidget(widget); w->setObjectName(QString("%02d_check_sub").arg(i)); setupOptionWidget(w, o->m_sub_options, true); w->setEnabled(o->value()); QObject::connect(cb, SIGNAL(toggled(bool)), w, SLOT(setEnabled(bool))); layout->addWidget(w, lpos++, left, 1, 2); } } else if(SelectOptPtr o = boost::dynamic_pointer_cast(_o)) { QGroupBox *gb = new QGroupBox(o->label(), widget); gb->setObjectName(QString("%02d_group").arg(i)); QVBoxLayout *vbox = new QVBoxLayout(gb); //vbox->setMargin(0); for(int j=0;jm_options.size();j++) { BoolOptPtr so = o->m_options[j]; OptRadioButton *rb = new OptRadioButton(o, j, this, gb); rb->setObjectName(QString("%02d_radio_%02d").arg(i).arg(j)); vbox->addWidget(rb); if(so->m_sub_options.size()) { QWidget *w = new QWidget(widget); w->setObjectName(QString("%02d_radio_%02d_sub").arg(i).arg(j)); setupOptionWidget(w, so->m_sub_options, true); w->setEnabled(so->value()); QObject::connect(rb, SIGNAL(toggled(bool)), w, SLOT(setEnabled(bool))); vbox->addWidget(w); } } layout->addWidget(gb, lpos++, left, 1, 2); } else if (IntOptPtr o = boost::dynamic_pointer_cast(_o)) { layout->addWidget(new QLabel(o->label()), lpos, left); switch (o->visualization()) { case IntOpt::SpinBox: { OptSpinBox *sb = new OptSpinBox(o, this, widget); sb->setObjectName(QString("%02d_spin").arg(i)); layout->addWidget(sb, lpos++, right); break; } case IntOpt::Slider: { OptSlider *sl = new OptSlider(o, this, widget); sl->setObjectName(QString("%02d_slid").arg(i)); layout->addWidget(sl, lpos++, right); break; } } } else if(StringOptPtr o = boost::dynamic_pointer_cast(_o)) { layout->addWidget(new QLabel(o->label()), lpos, left); OptLineEdit *ow = new OptLineEdit(o, this, widget); ow->setObjectName(QString("%02d_line").arg(i)); layout->addWidget(ow, lpos++, right); } else if(UrlOptPtr o = boost::dynamic_pointer_cast(_o)) { layout->addWidget(new QLabel(o->label()), lpos, left); OptUrlRequester *ow = new OptUrlRequester(o, this, widget); ow->setObjectName(QString("%02d_url").arg(i)); layout->addWidget(ow, lpos++, right); } else if(ComboOptPtr o = boost::dynamic_pointer_cast(_o)) { layout->addWidget(new QLabel(o->label()), lpos, left); OptComboBox *ow = new OptComboBox(o, this, widget); ow->setObjectName(QString("%02d_combo").arg(i)); layout->addWidget(ow, lpos++, right); } else if(ColorOptPtr o = boost::dynamic_pointer_cast(_o)) { layout->addWidget(new QLabel(o->label()), lpos, left); OptColorButton *ow = new OptColorButton(o, this, widget); ow->setObjectName(QString("%02d_color").arg(i)); layout->addWidget(ow, lpos++, right); } else if(FontOptPtr o = boost::dynamic_pointer_cast(_o)) { layout->addWidget(new QLabel(o->label()), lpos, left); OptFontRequester *ow = new OptFontRequester(o,this, widget); ow->setObjectName(QString("%02d_font").arg(i)); layout->addWidget(ow, lpos++, right); } else kError() << "Unknown option of type" << prettyTypeName(typeid(*_o).name()); } if(indent) layout->addItem(new QSpacerItem(25, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 0, 0, lpos, 1); } void OptionWidget::setOptionWidgetValues(QWidget* widget, OptList& newopts) { for(int i=0;i(_o)) { OptCheckBox *cb = widget->findChild(QString("%02d_check").arg(i)); if(!cb) goto fail; cb->setChecked(o->value()); if(o->m_sub_options.size()) { QWidget *w = widget->findChild(QString("%02d_check_sub").arg(i)); if(!w) goto fail; setOptionWidgetValues(w, o->m_sub_options); } } else if(SelectOptPtr o = boost::dynamic_pointer_cast(_o)) { QGroupBox *gb = widget->findChild(QString("%02d_group").arg(i)); if(!gb) goto fail; for(int j=0;jm_options.size();j++) { BoolOptPtr so = o->m_options[j]; OptRadioButton *rb = gb->findChild(QString("%02d_radio_%02d").arg(i).arg(j)); if(!rb) goto fail; rb->setChecked(so->value()); if(so->m_sub_options.size()) { QWidget *w = widget->findChild(QString("%02d_radio_%02d_sub").arg(i).arg(j)); if(!w) goto fail; setOptionWidgetValues(w, so->m_sub_options); } } } else if(IntOptPtr o = boost::dynamic_pointer_cast(_o)) { switch (o->visualization()) { case IntOpt::SpinBox: { OptSpinBox *sb = widget->findChild(QString("%02d_spin").arg(i)); if(!sb) goto fail; sb->setValue(o->value()); break; } case IntOpt::Slider: { OptSlider *sl = widget->findChild(QString("%02d_slid").arg(i)); if(!sl) goto fail; sl->setValue(o->value()); break; } } } else if(StringOptPtr o = boost::dynamic_pointer_cast(_o)) { OptLineEdit *ow = widget->findChild(QString("%02d_line").arg(i)); if(!ow) goto fail; ow->setText(o->value()); } else if(UrlOptPtr o = boost::dynamic_pointer_cast(_o)) { OptUrlRequester *ow = widget->findChild(QString("%02d_url").arg(i)); if(!ow) goto fail; ow->setUrl(o->value()); } else if(ComboOptPtr o = boost::dynamic_pointer_cast(_o)) { OptComboBox *ow = widget->findChild(QString("%02d_combo").arg(i)); if(!ow) goto fail; ow->setCurrentIndex(o->selected()); } else if(ColorOptPtr o = boost::dynamic_pointer_cast(_o)) { OptColorButton *ow = widget->findChild(QString("%02d_color").arg(i)); if(!ow) goto fail; ow->setColor(o->value()); } else if(FontOptPtr o = boost::dynamic_pointer_cast(_o)) { OptFontRequester *ow = widget->findChild(QString("%02d_font").arg(i)); if(!ow) goto fail; ow->setFont(o->value()); } else kError() << "Unknown option of type" << prettyTypeName(typeid(*_o).name()); } return; fail: kError() << "Options/Widget mismatch!"; } void dump_options_list(const OptList& options, int indent) { if(!indent)kDebug() << "---- begin dump ----"; for(int i=0;i(_o)) { for(int j=0;jvalue()?"[X]":"[ ]") << " " << o->label(); dump_options_list(o->subOptions(), indent+1); } else if(IntOptPtr o = boost::dynamic_pointer_cast(_o)) { for(int j=0;jlabel() << " |" << o->value() << "|"; } else if(StringOptPtr o = boost::dynamic_pointer_cast(_o)) { for(int j=0;jlabel() << " [" << o->value() << "]"; } else if(UrlOptPtr o = boost::dynamic_pointer_cast(_o)) { for(int j=0;jlabel() << " {" << o->value() << "}"; } else if(ColorOptPtr o = boost::dynamic_pointer_cast(_o)) { for(int j=0;jlabel() << " {" << o->value().name() << "}"; } else if(FontOptPtr o = boost::dynamic_pointer_cast(_o)) { for(int j=0;jlabel() << " {" << o->value().toString() << "}"; } else if(ComboOptPtr o = boost::dynamic_pointer_cast(_o)) { for(int j=0;jlabel(); for(int k=0;kvalues().size();k++) { for(int j=0;jselected()) kDebug() << " *<" << o->values()[k] << ">*"; else kDebug() << " <" << o->values()[k] << ">"; } } else if(SelectOptPtr o = boost::dynamic_pointer_cast(_o)) { for(int j=0;jlabel(); for(int j=0;joptions().size();j++) { BoolOptPtr so = o->options()[j]; for(int j=0;jvalue()?"(*)":"( )") << " " << so->label(); if(so->subOptions().size()) dump_options_list(so->subOptions(), indent+2); } } else { kDebug() << "dump_options_list: Error, unknown option of type " << prettyTypeName(typeid(*_o).name()); } } if(!indent)kDebug() << "---- end dump ----"; } bool options_list_load_from_settings(OptList& options, const Settings& s) { bool retv = false; for(int i=0;i(_o)) { Settings bool_group = s.group(o->name()); retv |= options_list_load_from_settings(o->m_sub_options, bool_group); bool newval = bool_group.flag("value", o->value()); retv |= (newval != o->value()); o->setValue( newval ); } else if(IntOptPtr o = boost::dynamic_pointer_cast(_o)) { int newval = s[o->name()] | o->value(); retv |= (newval != o->value()); o->setValue( newval ); } else if(StringOptPtr o = boost::dynamic_pointer_cast(_o)) { QString newval = s[o->name()] | o->value(); retv |= (newval != o->value()); o->setValue( newval ); } else if(UrlOptPtr o = boost::dynamic_pointer_cast(_o)) { QString newval = s[o->name()] | o->value(); retv |= (newval != o->value()); o->setValue( newval ); } else if(ColorOptPtr o = boost::dynamic_pointer_cast(_o)) { QColor newval = s[o->name()] | o->value(); retv |= (newval != o->value()); o->setValue( newval ); } else if(FontOptPtr o = boost::dynamic_pointer_cast(_o)) { QFont newval = s[o->name()] | o->value(); retv |= (newval != o->value()); o->setValue( newval ); } else if(ComboOptPtr o = boost::dynamic_pointer_cast(_o)) { int newval = s[o->name()] | o->selected(); retv |= (newval != o->selected()); o->setSelected( newval ); } else if(SelectOptPtr o = boost::dynamic_pointer_cast(_o)) { OptList l; for(int i=0;im_options.size();i++) l << o->m_options[i]; Settings sel_group = s.group(o->name()); retv |= options_list_load_from_settings(l, sel_group.group("sel-options")); int newval = sel_group["value"] | o->selected(); retv |= (newval != o->selected()); o->setSelected( newval ); } else kError() << "option of type" << prettyTypeName(typeid(*_o).name()); } return retv; } void options_list_save_to_settings(const OptList& options, Settings s) { for(int i=0;i(_o)) { Settings bool_group = s.group(o->name()); options_list_save_to_settings(o->subOptions(), bool_group); bool_group.setFlag("value", o->value()); } else if(IntOptPtr o = boost::dynamic_pointer_cast(_o)) { s[o->name()] = o->value(); } else if(StringOptPtr o = boost::dynamic_pointer_cast(_o)) { s[o->name()] = o->value(); } else if(UrlOptPtr o = boost::dynamic_pointer_cast(_o)) { s[o->name()] = o->value(); } else if(ColorOptPtr o = boost::dynamic_pointer_cast(_o)) { s[o->name()] = o->value(); } else if(FontOptPtr o = boost::dynamic_pointer_cast(_o)) { s[o->name()] = o->value(); } else if(ComboOptPtr o = boost::dynamic_pointer_cast(_o)) { s[o->name()] = o->value(); } else if(SelectOptPtr o = boost::dynamic_pointer_cast(_o)) { OptList l; for(int i=0;ioptions().size();i++) l << o->options()[i]; Settings sel_group = s.group(o->name()); options_list_save_to_settings(l, sel_group.group("sel-options")); sel_group["value"] = o->value(); } else kError() << "option of type" << prettyTypeName(typeid(*_o).name()); } } tagua-1.0-alpha2/src/option.h000066400000000000000000000240501077523320400160740ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef OPTION_H #define OPTION_H #include #include #include #include #include #include #include #include #include class Settings; class BaseOpt; class BoolOpt; class IntOpt; class StringOpt; class ColorOpt; class FontOpt; class ComboOpt; class SelectOpt; class UrlOpt; typedef boost::shared_ptr OptPtr; typedef boost::shared_ptr BoolOptPtr; typedef boost::shared_ptr IntOptPtr; typedef boost::shared_ptr StringOptPtr; typedef boost::shared_ptr ColorOptPtr; typedef boost::shared_ptr FontOptPtr; typedef boost::shared_ptr ComboOptPtr; typedef boost::shared_ptr SelectOptPtr; typedef boost::shared_ptr UrlOptPtr; typedef QList OptList; typedef QList BoolOptList; typedef boost::shared_ptr OptListPtr; typedef boost::shared_ptr BoolOptListPtr; template QList > options_list_duplicate(const QList >& o) { QList > retv; for(int i=0;i(o[i]->clone()); return retv; } template bool options_list_equals(const QList >& o1, const QList >& o2) { if(o1.size() != o2.size()) return false; for(int i=0;iequals(*o2[i])) return false; return true; } void dump_options_list(const OptList& options, int indent = 0); class BaseOpt { private: QString m_name; QString m_label; public: BaseOpt(const QString& name, const QString& label) : m_name(name) , m_label(label) {} virtual ~BaseOpt() {}; QString name() const { return m_name; } QString label() const { return m_label; } virtual OptPtr clone() const = 0; virtual bool equals(const BaseOpt&) const = 0; }; class BoolOpt : public BaseOpt { private: friend class OptionWidget; friend bool options_list_load_from_settings(OptList& options, const Settings& s); bool m_value; QList m_sub_options; public: typedef bool ValueType; BoolOpt(const QString& name, const QString& label, bool def = false, const QList& suboptions = QList()) : BaseOpt(name, label) , m_value(def) , m_sub_options(suboptions) {} bool value() const { return m_value; } void setValue(bool v) { m_value = v; } OptList subOptions() { return m_sub_options; } virtual OptPtr clone() const { BoolOpt *o = new BoolOpt(name(), label(), m_value, options_list_duplicate(m_sub_options) ); return OptPtr(o); } virtual bool equals(const BaseOpt& _o) const { const BoolOpt* o = dynamic_cast(&_o); return o && m_value != o->m_value && options_list_equals(m_sub_options, o->m_sub_options); } }; class IntOpt : public BaseOpt { public: enum Visualization { SpinBox, Slider }; private: int m_min; int m_max; int m_value; Visualization m_visualization; public: typedef int ValueType; IntOpt(const QString& name, const QString& label, int def, int min, int max, Visualization visualization) : BaseOpt(name, label) , m_min(min) , m_max(max) , m_value(def) , m_visualization(visualization) {} int min() const { return m_min; } int max() const { return m_max; } int value() const { return m_value; } Visualization visualization() const { return m_visualization; } void setValue(int v) { m_value = v; } virtual OptPtr clone() const { IntOpt *o = new IntOpt(name(), label(), m_value, m_min, m_max, m_visualization); return OptPtr(o); } virtual bool equals(const BaseOpt& _o) const { const IntOpt* o = dynamic_cast(&_o); return o && m_min != o->m_min && m_max != o->m_max && m_value != o->m_value && m_visualization != o->m_visualization; } }; class StringOpt : public BaseOpt { private: QString m_value; public: typedef QString ValueType; StringOpt(const QString& name, const QString& label, QString def = QString()) : BaseOpt(name, label) , m_value(def) {} QString value() const { return m_value; } void setValue(QString v) { m_value = v; } virtual OptPtr clone() const { StringOpt *o = new StringOpt(name(), label(), m_value); return OptPtr(o); } virtual bool equals(const BaseOpt& _o) const { const StringOpt* o = dynamic_cast(&_o); return o && m_value != o->m_value; } }; class UrlOpt : public BaseOpt { private: QString m_value; public: typedef QString ValueType; UrlOpt(const QString& name, const QString& label, QString def = QString() ) : BaseOpt(name, label) , m_value(def) {} QString value() const { return m_value; } void setValue(QString v) { m_value = v; } virtual OptPtr clone() const { UrlOpt *o = new UrlOpt(name(), label(), m_value); return OptPtr(o); } virtual bool equals(const BaseOpt& _o) const { const UrlOpt* o = dynamic_cast(&_o); return o && m_value != o->m_value; } }; class ColorOpt : public BaseOpt { private: QColor m_value; public: typedef QColor ValueType; ColorOpt(const QString& name, const QString& label, QColor def = Qt::black) : BaseOpt(name, label) , m_value(def) {} QColor value() const { return m_value; } void setValue(QColor v) { m_value = v; } virtual OptPtr clone() const { ColorOpt *o = new ColorOpt(name(), label(), m_value); return OptPtr(o); } virtual bool equals(const BaseOpt& _o) const { const ColorOpt* o = dynamic_cast(&_o); return o && m_value != o->m_value; } }; class FontOpt : public BaseOpt { private: QFont m_value; public: typedef QFont ValueType; FontOpt(const QString& name, const QString& label, QFont def = QApplication::font()) : BaseOpt(name, label) , m_value(def) {} QFont value() const { return m_value; } void setValue(QFont v) { m_value = v; } virtual OptPtr clone() const { FontOpt *o = new FontOpt(name(), label(), m_value); return OptPtr(o); } virtual bool equals(const BaseOpt& _o) const { const FontOpt* o = dynamic_cast(&_o); return o && m_value != o->m_value; } }; class ComboOpt : public BaseOpt { private: QStringList m_values; int m_selected; public: typedef int ValueType; ComboOpt(const QString& name, const QString& label, const QStringList& values, int selected = 0) : BaseOpt(name, label) , m_values(values) , m_selected(selected) {} int value() const { return m_selected; } int selected() const { return m_selected; } void setSelected(int v) { m_selected = v; } QStringList values() const { return m_values; } virtual OptPtr clone() const { ComboOpt *o = new ComboOpt(name(), label(), m_values, m_selected); return OptPtr(o); } virtual bool equals(const BaseOpt& _o) const { const ComboOpt* o = dynamic_cast(&_o); return o && m_values == o->m_values && m_selected != o->m_selected; } }; class SelectOpt : public BaseOpt { private: friend class OptionWidget; friend bool options_list_load_from_settings(OptList& options, const Settings& s); QList m_options; int m_selected; public: typedef int ValueType; SelectOpt(const QString& name, const QString& label, QList options, int selected = 0) : BaseOpt(name, label) , m_options(options) { setSelected(selected); } int value() const { return m_selected; } int selected() const { return m_selected; } void setSelected(int s) { m_selected = std::min(std::max(s, 0), m_options.size()-1); for(int i=0;isetValue(i==m_selected); } BoolOptList options(){ return m_options; } virtual OptPtr clone() const { return OptPtr(new SelectOpt(name(), label(), options_list_duplicate(m_options), m_selected)); } virtual bool equals(const BaseOpt& _o) const { const SelectOpt* o = dynamic_cast(&_o); return o && m_selected != o->m_selected && options_list_equals(m_options, o->m_options); } }; template boost::shared_ptr options_list_find(const OptList& o, const QString& name) { for(int i=0;iname() == name) if(boost::shared_ptr retv = boost::dynamic_pointer_cast(o[i])) return retv; return boost::shared_ptr(); } template typename O::ValueType options_list_find(const OptList& o, const QString& name, const typename O::ValueType& def) { for(int i=0;iname() == name) if(boost::shared_ptr retv = boost::dynamic_pointer_cast(o[i])) return retv->value(); return def; } bool options_list_load_from_settings(OptList&, const Settings& s); void options_list_save_to_settings(const OptList&, Settings s); class OptionWidget : public QWidget { Q_OBJECT bool m_changed; bool m_dont_fire; QList m_options; void setupOptionWidget(QWidget*, OptList&, bool indent = false); void setOptionWidgetValues(QWidget*, OptList&); void notifyChange(); friend class OptCheckBox; friend class OptRadioButton; friend class OptSpinBox; friend class OptSlider; friend class OptLineEdit; friend class OptColorButton; friend class OptFontRequester; friend class OptUrlRequester; friend class OptComboBox; public: OptionWidget(const OptList& options, QWidget* parent = NULL); void setValues(OptList& newopts); Q_SIGNALS: void changed(const OptList& options); }; #endif //OPTION_H tagua-1.0-alpha2/src/option_p.cpp000066400000000000000000000072071077523320400167530ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "option_p.h" OptCheckBox::OptCheckBox(BoolOptPtr opt, OptionWidget *owner, QWidget *parent) : QCheckBox(opt->label(), parent) , m_owner(owner) , m_opt(opt) { setChecked(m_opt->value()); connect(this, SIGNAL(toggled(bool)), this, SLOT(setOpt(bool))); } void OptCheckBox::setOpt(bool b) { m_opt->setValue(b); m_owner->notifyChange(); } OptRadioButton::OptRadioButton(SelectOptPtr opt, int i, OptionWidget *owner, QWidget *parent) : QRadioButton(opt->options()[i]->label(), parent) , m_owner(owner) , m_opt(opt) , m_index(i) { setChecked(m_opt->options()[i]->value()); connect(this, SIGNAL(toggled(bool)), this, SLOT(setOpt(bool))); } void OptRadioButton::setOpt(bool b) { if(b) { m_opt->setSelected(m_index); m_owner->notifyChange(); } } OptSpinBox::OptSpinBox(IntOptPtr opt, OptionWidget *owner, QWidget *parent) : QSpinBox(parent) , m_owner(owner) , m_opt(opt) { setMinimum(m_opt->min()); setMaximum(m_opt->max()); setValue(m_opt->value()); connect(this, SIGNAL(valueChanged(int)), this, SLOT(setOpt(int))); } void OptSpinBox::setOpt(int i) { m_opt->setValue(i); m_owner->notifyChange(); } OptSlider::OptSlider(IntOptPtr opt, OptionWidget *owner, QWidget *parent) : QSlider(parent) , m_owner(owner) , m_opt(opt) { setOrientation(Qt::Horizontal); setMinimum(m_opt->min()); setMaximum(m_opt->max()); setValue(m_opt->value()); connect(this, SIGNAL(valueChanged(int)), this, SLOT(setOpt(int))); } void OptSlider::setOpt(int i) { m_opt->setValue(i); m_owner->notifyChange(); } OptLineEdit::OptLineEdit(StringOptPtr opt, OptionWidget *owner, QWidget *parent) : QLineEdit(parent) , m_owner(owner) , m_opt(opt) { setText(m_opt->value()); connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(setOpt(const QString&))); } void OptLineEdit::setOpt(const QString& s) { m_opt->setValue(s); m_owner->notifyChange(); } OptUrlRequester::OptUrlRequester(UrlOptPtr opt, OptionWidget *owner, QWidget *parent) : KUrlRequester(parent) , m_owner(owner) , m_opt(opt) { setUrl(m_opt->value()); connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(setOpt(const QString&))); } void OptUrlRequester::setOpt(const QString& s) { m_opt->setValue(s); m_owner->notifyChange(); } OptComboBox::OptComboBox(ComboOptPtr opt, OptionWidget *owner, QWidget *parent) : QComboBox(parent) , m_owner(owner) , m_opt(opt) { addItems(m_opt->values()); setCurrentIndex(m_opt->selected()); connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(setOpt(int))); } void OptComboBox::setOpt(int c) { m_opt->setSelected(c); m_owner->notifyChange(); } OptColorButton::OptColorButton(ColorOptPtr opt, OptionWidget *owner, QWidget *parent) : KColorButton(parent) , m_owner(owner) , m_opt(opt) { setColor(m_opt->value()); connect(this, SIGNAL(changed(const QColor&)), this, SLOT(setOpt(const QColor&))); } void OptColorButton::setOpt(const QColor& c) { m_opt->setValue(c); m_owner->notifyChange(); } OptFontRequester::OptFontRequester(FontOptPtr opt, OptionWidget *owner, QWidget *parent) : KFontRequester(parent) , m_owner(owner) , m_opt(opt) { setFont(m_opt->value()); connect(this, SIGNAL(fontSelected(const QFont&)), this, SLOT(setOpt(const QFont&))); } void OptFontRequester::setOpt(const QFont& f) { m_opt->setValue(f); m_owner->notifyChange(); } tagua-1.0-alpha2/src/option_p.h000066400000000000000000000052771077523320400164250ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef OPTION_P_H #define OPTION_P_H #include #include #include #include #include #include #include #include #include "option.h" class OptCheckBox : public QCheckBox { Q_OBJECT OptionWidget *m_owner; BoolOptPtr m_opt; public: OptCheckBox(BoolOptPtr opt, OptionWidget *owner, QWidget *parent = NULL); private Q_SLOTS: void setOpt(bool); }; class OptRadioButton : public QRadioButton { Q_OBJECT OptionWidget *m_owner; SelectOptPtr m_opt; int m_index; public: OptRadioButton(SelectOptPtr opt, int i, OptionWidget *owner, QWidget *parent = NULL); private Q_SLOTS: void setOpt(bool); }; class OptSpinBox : public QSpinBox { Q_OBJECT OptionWidget *m_owner; IntOptPtr m_opt; public: OptSpinBox(IntOptPtr opt, OptionWidget *owner, QWidget *parent = NULL); private Q_SLOTS: void setOpt(int); }; class OptSlider : public QSlider { Q_OBJECT OptionWidget *m_owner; IntOptPtr m_opt; public: OptSlider(IntOptPtr opt, OptionWidget *owner, QWidget *parent = NULL); private Q_SLOTS: void setOpt(int); }; class OptLineEdit : public QLineEdit { Q_OBJECT OptionWidget *m_owner; StringOptPtr m_opt; public: OptLineEdit(StringOptPtr opt, OptionWidget *owner, QWidget *parent = NULL); private Q_SLOTS: void setOpt(const QString&); }; class OptUrlRequester : public KUrlRequester { Q_OBJECT OptionWidget *m_owner; UrlOptPtr m_opt; public: OptUrlRequester(UrlOptPtr opt, OptionWidget *owner, QWidget *parent = NULL); private Q_SLOTS: void setOpt(const QString&); }; class OptComboBox : public QComboBox { Q_OBJECT OptionWidget *m_owner; ComboOptPtr m_opt; public: OptComboBox(ComboOptPtr opt, OptionWidget *owner, QWidget *parent = NULL); private Q_SLOTS: void setOpt(int); }; class OptColorButton : public KColorButton { Q_OBJECT OptionWidget *m_owner; ColorOptPtr m_opt; public: OptColorButton(ColorOptPtr opt, OptionWidget *owner, QWidget *parent = NULL); private Q_SLOTS: void setOpt(const QColor&); }; class OptFontRequester : public KFontRequester { Q_OBJECT OptionWidget *m_owner; FontOptPtr m_opt; public: OptFontRequester(FontOptPtr opt, OptionWidget *owner, QWidget *parent = NULL); private Q_SLOTS: void setOpt(const QFont&); }; #endif //OPTION_P_H tagua-1.0-alpha2/src/pathinfo.cpp000066400000000000000000000010261077523320400167250ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "pathinfo.h" PathInfo::PathInfo(PathInfo::Direction direction, int num_obstacles) : m_direction(direction), m_num_obstacles(num_obstacles) {} tagua-1.0-alpha2/src/pathinfo.h000066400000000000000000000021411077523320400163710ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PATHINFO_H #define PATHINFO_H #include "export.h" class TAGUA_EXPORT PathInfo { public: enum Direction { Undefined, Horizontal, Vertical, Diagonal1, Diagonal2 }; private: Direction m_direction; int m_num_obstacles; public: PathInfo(Direction direction, int num_obstacles); Direction direction() const { return m_direction; } bool parallel() const { return m_direction == Horizontal || m_direction == Vertical; } bool diagonal() const { return m_direction == Diagonal1 || m_direction == Diagonal2; } bool clear() const { return m_num_obstacles == 0; } int numObstacles() const { return m_num_obstacles; } bool valid() const { return m_direction != Undefined; } }; #endif // PATHINFO_H tagua-1.0-alpha2/src/pgnparser.cpp000066400000000000000000000063531077523320400171260ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "pgnparser.h" #include #include QRegExp PGN::number("^(\\d+)(?:(?:\\.\\s+)?(\\.\\.\\.)|\\.?)?"); QRegExp PGN::begin_var("^\\("); QRegExp PGN::end_var("^\\)"); QRegExp PGN::comment("^\\{[^}]*\\}"); QRegExp PGN::comment2("^;[^\\n]*\\n"); QRegExp PGN::wsPattern("^\\s+"); QRegExp PGN::tag("^\\[(\\S+)\\s+\"((?:[^\"]|\\\\\")*)\"\\]"); QRegExp PGN::move_tag("^\\$(\\d+)"); QRegExp PGN::move("^[^$\\{\\(\\[\\s][^\\{\\(\\)\\[\\s]*"); QRegExp PGN::result("^(?:\\*|1-0|0-1|1/2-1/2)"); QRegExp PGN::time("^\\([\\d:.]*\\)"); QRegExp PGN::eol("(?:[ \t]\r?\n\r?|\r?\n\r?[ \t]|\r?\n\r?)"); bool PGN::tryRegExp(QRegExp& re, const QString& str, int& offset) { if (re.indexIn(str, offset, QRegExp::CaretAtOffset) != -1) { offset += re.matchedLength(); return true; } else return false; } #define IGNORE(re) if (tryRegExp((re), pgn, offset)) continue; bool PGN::parse(const QString& pgn) { int offset = 0; while (offset < pgn.length()) { IGNORE(wsPattern); // read result if (result.indexIn(pgn, offset, QRegExp::CaretAtOffset) != -1) { QString res = pgn.mid(offset, result.matchedLength()); offset += result.matchedLength(); return true; } IGNORE(comment2); IGNORE(time); // read comment if (tag.indexIn(pgn, offset, QRegExp::CaretAtOffset) != -1) { m_tags[tag.cap(1)] = tag.cap(2); offset += tag.matchedLength(); continue; } // read comment if (comment.indexIn(pgn, offset, QRegExp::CaretAtOffset) != -1) { m_entries.push_back(pgn.mid(offset + 1, comment.matchedLength() - 2).replace(eol, " ")); offset += comment.matchedLength(); continue; } // read var, 1 if (begin_var.indexIn(pgn, offset, QRegExp::CaretAtOffset) != -1) { m_entries.push_back(BeginVariation()); offset += begin_var.matchedLength(); continue; } // read var, 2 if (end_var.indexIn(pgn, offset, QRegExp::CaretAtOffset) != -1) { m_entries.push_back(EndVariation()); offset += end_var.matchedLength(); continue; } // read move tag if (move_tag.indexIn(pgn, offset, QRegExp::CaretAtOffset) != -1) { // not nothing :) tryRegExp(wsPattern, pgn, offset); } int num = 0; // read number, and do not continue if (number.indexIn(pgn, offset, QRegExp::CaretAtOffset) != -1) { num = number.cap(1).toInt()*2 + (number.cap(2).isEmpty() ? 0 : 1); offset += number.matchedLength(); tryRegExp(wsPattern, pgn, offset); } // read move if (move.indexIn(pgn, offset, QRegExp::CaretAtOffset) != -1) { m_entries.push_back(Move(num, move.cap(0))); offset += move.matchedLength(); continue; } // parse error! kDebug() << "pgn parse error! at" << pgn.mid(offset, 100); return false; } return true; } #undef IGNORE PGN::PGN(const QString& str) { m_valid = parse(str); } tagua-1.0-alpha2/src/pgnparser.h000066400000000000000000000031571077523320400165720ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PGNPARSER_H #define PGNPARSER_H #include #include #include #ifdef Q_CC_MSVC #pragma warning( push ) #pragma warning( disable : 4100 ) #include #pragma warning( pop ) #else #include #endif #include class QRegExp; class PGN { public: class Move { public: int m_number; QString m_move; Move(int n, const QString& s) : m_number(n), m_move(s) { } }; class BeginVariation {}; class EndVariation {}; typedef boost::variant Entry; private: /* friend std::ostream& operator<<(std::ostream& os, const PGN& pgn);*/ QString m_result; bool m_valid; static QRegExp number, begin_var, end_var, comment, comment2, wsPattern, tag, result, time, eol, move_tag, move; static bool tryRegExp(QRegExp& re, const QString& str, int& offset); bool parse(const QString& pgn); public: std::vector m_entries; std::map m_tags; explicit PGN(const QString&); inline bool valid() const { return m_valid; } inline uint size() const { return m_entries.size(); } const Entry* operator[](int index) const { return &m_entries[index]; } }; #endif // PGNPARSER_H tagua-1.0-alpha2/src/piecefactory.h000066400000000000000000000011731077523320400172420ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef PIECEFACTORY_H #define PIECEFACTORY_H #include template class PieceFactory { public: static typename Variant::Piece createPiece(const QString&) { return typename Variant::Piece(); } }; #endif // PIECEFACTORY_H tagua-1.0-alpha2/src/piecefunction.h000066400000000000000000000011121077523320400174110ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PIECEFUNCTION_H #define PIECEFUNCTION_H class PieceFunction { public: virtual ~PieceFunction() { } virtual void operator()(int color, int type) = 0; }; #endif // PIECEFUNCTION_H tagua-1.0-alpha2/src/piecegrid.h000066400000000000000000000043271077523320400165240ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PIECEGRID_H #define PIECEGRID_H #include "grid.h" /** * A specialization of Grid useful for containing pointers. * It is used only to contain pointers to Piece and derived classes. */ template class PointerGrid : public Grid { public: using Grid::board; // why??? PointerGrid(int sizeX, int sizeY); PointerGrid(const PointerGrid& other); template PointerGrid(const PointerGrid& other); bool operator==(const PointerGrid& other) const; Point find(const T& x) const { for (Point i = this->first(); i <= this->last(); i = this->next(i)) { if ((*this)[i] && *(*this)[i] == x) return i; } return Point::invalid(); } virtual ~PointerGrid(); }; //BEGIN Implementation template PointerGrid::PointerGrid(int sizeX, int sizeY) : Grid(sizeX, sizeY, 0) {} template PointerGrid::PointerGrid(const PointerGrid& other) : Grid(other) { for (uint i = 0; i < board.size(); ++i) { T* p = other.board[i]; if (p) board[i] = new T(*p); else board[i] = 0; } } template template PointerGrid::PointerGrid(const PointerGrid& other) : Grid(other.getSize().x, other.getSize().y) { for (uint i = 0; i < board.size(); ++i) { T1* p = other.board[i]; if (p) board[i] = new T(*p); else board[i] = 0; } } template PointerGrid::~PointerGrid() { for (uint i = 0; i < board.size(); ++i) delete board[i]; } template bool PointerGrid::operator==(const PointerGrid& other) const { for (uint i = 0; i < board.size(); ++i) { if (!board[i]) { if (other.board[i]) return false; } else if (! board[i]->equals(other.board[i])) return false; } return true; } //END Implementation #endif // PIECEGRID_H tagua-1.0-alpha2/src/piecepool.cpp000066400000000000000000000166151077523320400171060ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "piecepool.h" #include "board.h" #include PiecePool::PiecePool(int num, Board* b, const AnimationSettings& animSettings, KGameCanvasAbstract* parent) : ClickableCanvas(parent) , m_pool_num(num) , m_board(b) , m_flipped(false) , m_square_size(0) , m_width(1) , m_dragged_index(-1) , m_anim_settings(animSettings) { m_main_animation = new MainAnimation( 1.0 ); setGridWidth(1); } PiecePool::~PiecePool() { delete m_main_animation; } QPoint PiecePool::toReal(int i) const { int x = i % m_width; int y = i / m_width; if (y & 1) x = m_width - 1 - x; if (m_flipped) y = -1 - y; return QPoint(x, y) * m_square_size; } int PiecePool::toLogical(const QPoint& p) const { int x = p.x() / m_square_size; int y = p.y() / m_square_size; if (x<0 || x >= m_width) return -1; if (m_flipped) y = -y; if (y & 1) x = m_width - 1 - x; int retv = y * m_width + x; if (retv < 0 || static_cast(retv) >= m_sprites.size()) return -1; return retv; } void PiecePool::settingsChanged() { } void PiecePool::setGridWidth(int w) { m_width = w > 0 ? w : 1; } QRect PiecePool::boardRect() { Q_ASSERT(m_width > 0); int height = (m_sprites.size() + m_width - 1) / m_width; QSize sz(m_width, m_flipped ? -height : height); return QRect(pos(), sz * m_square_size); } int PiecePool::fill() { return m_sprites.size(); } void PiecePool::clear() { m_sprites.clear(); } void PiecePool::animate(const Animate::Pool::Scheme& scheme, Animate::AnimationType type) { m_main_animation->addAnimation(scheme.run(m_anim_settings, this, type)); } void PiecePool::insertSprite(int index, const NamedSprite& nsprite) { if(m_dragged && index > m_dragged_index) index--; if(index < 0 || index > fill() ) { kError() << "invalid index" << index; return; } m_sprites.resize(m_sprites.size()+1); for(int i = m_sprites.size()-1; i > index; i--) { // double speed = (1.0 + 1.0 / (i - index + 1)) * 0.4; m_sprites[i] = m_sprites[i-1]; animate(Animate::Pool::move(m_sprites[i], i)); } m_sprites[index] = nsprite; animate(Animate::Pool::move(m_sprites[index], index), Animate::Instant); animate(Animate::Pool::appear(m_sprites[index])); } NamedSprite PiecePool::getSprite(int index) { if(m_dragged && index == m_dragged_index) return m_dragged; if(m_dragged && index > m_dragged_index) index--; if(index < 0 || index >= (int)m_sprites.size() ) { kError() << "invalid index" << index; return NamedSprite(); } return m_sprites[index]; } void PiecePool::removeSprite(int index) { if(m_dragged && index == m_dragged_index) { m_dragged = NamedSprite(); m_dragged_index = -1; return; } if(m_dragged && index > m_dragged_index) index--; if(index < 0 || index >= (int)m_sprites.size() ) { kError() << "invalid index" << index; return; } takeSpriteAt(index); } NamedSprite PiecePool::takeSprite(int index) { if(m_dragged && index == m_dragged_index) { NamedSprite retv = m_dragged; m_dragged = NamedSprite(); m_dragged_index = -1; return retv; } kError() << "Only the sprite being dropped can be taken from the pool."; return NamedSprite(); #if 0 if(m_dragged && index > m_dragged_index) index--; if(index < 0 || index >= (int)m_sprites.size() ) { kError() << "invalid index" << index; return NamedSprite(); } return takeSpriteAt(index); #endif } NamedSprite PiecePool::takeSpriteAt(int index) { if(index < 0 || index >= (int)m_sprites.size() ) { kError() << "invalid index" << index; return NamedSprite(); } NamedSprite retv = m_sprites[index]; if (!retv) return NamedSprite(); animate(Animate::Pool::disappear(retv)); for(int i = index; i < (int)m_sprites.size()-1; i++) { // double speed = (1.0 + 1.0 / (i - index + 1)) * 0.4; m_sprites[i] = m_sprites[i+1]; animate(Animate::Pool::move(m_sprites[i], i)); } m_sprites.resize(m_sprites.size()-1); return retv; } void PiecePool::cancelDragging(bool fadeOff) { if(!m_dragged) return; if (fadeOff) { NamedSprite phantom = m_dragged.duplicate(); animate(Animate::Pool::disappear(phantom)); } m_dragged.sprite()->putInCanvas(this); m_dragged.sprite()->setPixmap(loadSprite(m_dragged.name())); insertSprite(m_dragged_index, m_dragged); m_dragged = NamedSprite(); m_dragged_index = -1; } void PiecePool::flipAndMoveBy(QPoint p) { QPoint deltapos = m_flipped ? -p : p; moveTo(pos() + deltapos); m_flipped = !m_flipped; for(int i=0;i<(int)m_sprites.size(); i++) { SpritePtr p = m_sprites[i].sprite(); p->setPixmap(loadSprite(m_sprites[i].name())); animate(Animate::Pool::move(m_sprites[i], i), Animate::Instant); } } void PiecePool::onResize(int new_size, bool force_reload) { if (m_square_size == new_size && !force_reload) return; m_square_size = new_size; m_loader.setSize(m_square_size); // update the sprites for (int i=0;i<(int)m_sprites.size(); i++) { m_sprites[i].sprite()->setPixmap(loadSprite(m_sprites[i].name())); m_main_animation->addAnimation(AnimationPtr(new InstantAnimation(m_sprites[i].sprite(), toReal(i)))); } } void PiecePool::onMouseRelease(const QPoint& pos, int button) { if (button != Qt::LeftButton || !m_dragged) return; m_board->m_dropped_pool = m_pool_num; m_board->m_dropped_index = m_dragged_index; /* did the board take this sprite? */ m_board->dropOn( m_pool_num, m_dragged_index, pos + this->pos() - m_board->pos() ); m_board->m_dropped_pool = -1; m_board->m_dropped_index = -1; cancelDragging(true); } void PiecePool::onMousePress(const QPoint& pos, int button) { if (button != Qt::LeftButton) return; if(m_dragged) { kError() << "Eh? We are already dragging?"; cancelDragging(); //never remove implicitly a piece from the pool } int index = toLogical(pos); if(index == -1) return; NamedSprite got = takeSpriteAt(index); if(!got) return; got.sprite()->hide(); /* recreate the sprite, as "got" may be being animated */ QPixmap px = m_board->loadSprite(got.name()); QPoint at = pos + this->pos() - m_board->pos() - QPoint(px.width(), px.height())/2; m_dragged = NamedSprite( got.name(), SpritePtr(new Sprite(px, m_board->piecesGroup(), at) ) ); m_dragged.sprite()->raise(); m_dragged.sprite()->show(); m_dragged_index = index; } void PiecePool::onMouseMove(const QPoint& pos, int /*button*/) { if(m_dragged) { m_dragged.sprite()->moveTo(pos + this->pos() - m_board->pos() - QPoint(m_dragged.sprite()->pixmap().width(), m_dragged.sprite()->pixmap().height() ) / 2 ); m_board->draggingOn( m_pool_num, m_dragged_index, pos + this->pos() - m_board->pos() ); } } QPixmap PiecePool::loadSprite(const QString& id) { // use board flipped state here, because the pool // flipping only refers to the displaying of pieces // and should not affect their orientation (which should // stay coherent with that of the pieces on the board). return m_loader.piecePixmap(id, m_board->flipped()); } tagua-1.0-alpha2/src/piecepool.h000066400000000000000000000105221077523320400165420ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PIECEPOOL_H #define PIECEPOOL_H #include #include "animationfactory.h" #include "clickablecanvas.h" #include "indexconverter.h" #include "mainanimation.h" #include "namedsprite.h" #include "pixmaploader.h" /** * @class PiecePool * @brief The class representing a crazyhouse-like piece pool. * * PiecePool is a canvas item attached to a Board that keeps a * stack of pieces and lets you drop them on the board, notifying * the board. */ class PiecePool : public ClickableCanvas , private IndexConverter { private: int m_pool_num; /** displayed m_sprites */ std::vector m_sprites; /** refrence board */ class Board* m_board; /** true if flipped */ bool m_flipped; /** size if a square */ int m_square_size; /** the width of the pool (ie how many pieces) */ int m_width; /** loader class, to load pieces */ PixmapLoader m_loader; /** the piece that is being dragged, if any */ NamedSprite m_dragged; /** the index of the piece being dragged */ int m_dragged_index; /** main animation structure */ MainAnimation* m_main_animation; const AnimationSettings& m_anim_settings; /** internal function, resizes the grid vector to hold x pieces */ void setFill(int x); /** removes the drag putting it back together with his friends in the pool. if fadeOff is true the current drag will fade off while a new piece will fade in the pool, while if fadeOff is false the fade off is not done. fadeOff will typically be false if the piece sprite has been used in the board and we don't want a clone that is fading off */ void cancelDragging(bool fadeOff = true); /** takes the named sprite */ NamedSprite takeSpriteAt(int i); /** converts an index to the upper left point of the corresponding square */ virtual QPoint toReal(int i) const; /** finds to which index corresponds the point p, or -1 if corresponds to none */ virtual int toLogical(const QPoint& p) const; void animate(const Animate::Pool::Scheme& scheme, Animate::AnimationType type = Animate::Normal); public: friend class GraphicalSystem; friend class ChessTable; /** Constructor, requires the board the pool will be attached to */ PiecePool(int num, Board* b, const AnimationSettings&, KGameCanvasAbstract* parent); ~PiecePool(); /** returns the sprite loader */ PixmapLoader* loader() { return &m_loader; } /** returns the sprite loader */ const PixmapLoader* loader() const { return &m_loader; } /** Load a sprite using the sprite loader */ QPixmap loadSprite(const QString& id); /** returns the flipped value */ bool flipped() const { return m_flipped; } /** returns the number of pieces in the pool */ int fill(); /** removes all the pieces */ void clear(); /** adds a sprite to the pool */ void insertSprite(int index, const NamedSprite& sprite); /** \return the sprite at the given index. */ NamedSprite getSprite(int index); /** removes the sprite at the given index from the pool. */ void removeSprite(int index); /** removes the sprite at the given index from the pool and returns it. */ NamedSprite takeSprite(int index); /** sets the width of the grid (the fill will stay the same, and the grid height will be recalculated) */ void setGridWidth(int w); /** the rect that will be covered by the pool */ virtual QRect boardRect(); /** flips and moves the pieces in the pool at the same time */ void flipAndMoveBy(QPoint p); /** mouse release event */ virtual void onMouseRelease(const QPoint& pos, int button); /** mouse press event */ virtual void onMousePress(const QPoint& pos, int button); /** mouse move event */ virtual void onMouseMove(const QPoint& pos, int button); /** resize event (new_size is the new size of a SQUARE) */ virtual void onResize(int new_size, bool force_reload = false); /** changed settings handler */ virtual void settingsChanged(); }; #endif //PIECEPOOL_H tagua-1.0-alpha2/src/pixmaploader.cpp000066400000000000000000000121021077523320400175770ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include "common.h" #include "loader/theme.h" #include "pixmaploader.h" #include "themeinfo.h" class PixmapLoader::ThemeLoader : public Loader::Theme { public: int m_ref_count; ThemeLoader(const ThemeInfo& t) : Loader::Theme(t) , m_ref_count(0) { } }; PixmapLoader::PixmapLoader() : m_loader(NULL) , m_size(0) { } PixmapLoader::~PixmapLoader() { flush(); } PixmapLoader::ThemeLoadersCache& PixmapLoader::loaders() { static ThemeLoadersCache cache; return cache; } void PixmapLoader::flush() { if (m_loader) { /* unref the size */ if(m_size) m_loader->unrefSize(m_size); m_loader->unrefSize(0); /* unref the loader, and possibly destroy it */ if(!--m_loader->m_ref_count) { delete m_loader; loaders().remove(m_theme); } m_loader = NULL; } } void PixmapLoader::setTheme(const ThemeInfo& theme) { if (theme == m_theme) return; flush(); m_theme = theme; } void PixmapLoader::setSize(int s) { if(s == m_size) return; if(m_loader) { if(s) m_loader->refSize(s); if(m_size) m_loader->unrefSize(m_size); } m_size = s; } void PixmapLoader::initialize() { if (m_loader) return; /* try to get a loader */ m_loader = loaders().value(m_theme, 0); if (!m_loader) { // no loader, yet // create it m_loader = new ThemeLoader(m_theme); loaders().insert(m_theme, m_loader); } Q_ASSERT(m_loader); m_loader->m_ref_count++; if (m_size) m_loader->refSize(m_size); m_loader->refSize(0); } QPixmap PixmapLoader::getPixmap(const QString& id) { return getValue(id); } QPixmap PixmapLoader::piecePixmap(const QString& id, bool flipped) { ::LuaApi::LuaValueMap args; if (flipped) args["flipped"] = 0.0; return getValue(id, &args); // return getValue(id); } template T PixmapLoader::getValue(const QString& id, const ::LuaApi::LuaValueMap* args, bool allow_nil) { if (!m_size || !m_theme) return T(); if (!m_loader) initialize(); return m_loader->getValue(id, m_size, args, allow_nil); } template QPixmap PixmapLoader::getValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template Loader::PixmapOrMap PixmapLoader::getValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template Loader::Glyph PixmapLoader::getValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template double PixmapLoader::getValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template QPointF PixmapLoader::getValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template QRectF PixmapLoader::getValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template QBrush PixmapLoader::getValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template QColor PixmapLoader::getValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template QFont PixmapLoader::getValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template ::LuaApi::LuaValueMap PixmapLoader::getValue< ::LuaApi::LuaValueMap>(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template T PixmapLoader::getStaticValue(const QString& id, const ::LuaApi::LuaValueMap* args, bool allow_nil) { if (!m_theme) return T(); if (!m_loader) initialize(); return m_loader->getValue(id, 0, args, allow_nil); } template QPixmap PixmapLoader::getStaticValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template Loader::PixmapOrMap PixmapLoader::getStaticValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template Loader::Glyph PixmapLoader::getStaticValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template double PixmapLoader::getStaticValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template QPointF PixmapLoader::getStaticValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template QRectF PixmapLoader::getStaticValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template QBrush PixmapLoader::getStaticValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template QColor PixmapLoader::getStaticValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template QFont PixmapLoader::getStaticValue(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); template ::LuaApi::LuaValueMap PixmapLoader::getStaticValue< ::LuaApi::LuaValueMap>(const QString&, const ::LuaApi::LuaValueMap*, bool allow_nil); tagua-1.0-alpha2/src/pixmaploader.h000066400000000000000000000050321077523320400172500ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PIXMAPLOADER_H #define PIXMAPLOADER_H #include #include #include #include "loader/theme.h" #include "themeinfo.h" /** * @class PixmapLoader * @brief The simple pixmap loading facility. * * This is the utility class used by the interface to load pixmap from resource ids. * It acts simply as a wrapper around PixmapLoader::ThemeLoader, making it possible to * use it in a simple and afficient way. * * Note that pixmaps will not be all of the specified size, the size is only the base size. */ class PixmapLoader { private: class ThemeLoader; typedef QHash ThemeLoadersCache; /** static cache of the loaders, there should be only one for each (theme,variant) pair */ static ThemeLoadersCache& loaders(); /** the current loader, or NULL */ ThemeLoader *m_loader; /** the current size */ int m_size; /** the current theme */ ThemeInfo m_theme; /** internal, clears references to the currently used loader, if any. */ void flush(); /** internal, gets or creates a loader good for the current (theme,variant) pair and refs the size */ void initialize(); public: /** constructor */ PixmapLoader(); ~PixmapLoader(); /** set the theme */ void setTheme(const ThemeInfo& theme); /** set the base size of the pixmaps. Note that returned pixmaps's size can be different. * For instance, if the size is 100 the "background" generated by the * chess variant will be 200x200 (and it will be tiled on the Board) */ void setSize(int s); /** looks up a string id (for instance a predefined id, like "background" or "highlighting") */ // QPixmap operator()(const QString& id); QPixmap getPixmap(const QString& id); QPixmap piecePixmap(const QString& id, bool flipped = false); /** returns a value */ template T getValue(const QString& id, const ::LuaApi::LuaValueMap* args = NULL, bool allow_nil = false); /** returns a static value (not depending on the size) */ template T getStaticValue(const QString& id, const ::LuaApi::LuaValueMap* args = NULL, bool allow_nil = false); }; #endif // PIXMAPLOADER_H tagua-1.0-alpha2/src/player.h000066400000000000000000000013611077523320400160600ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PLAYER_H #define PLAYER_H #include class Player { public: QString name; int rating; Player(const QString& name, int rating) : name(name) , rating(rating) { } Player() : name("unknown") , rating(-1) { } bool operator==(const QString& otherName) const { return name == otherName; } }; #endif // PLAYER_H tagua-1.0-alpha2/src/point.cpp000066400000000000000000000067311077523320400162560ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include "common.h" #include "point.h" Point::Point(int x, int y) : x(x), y(y) { } Point::Point(const QPoint& p) : x(p.x()), y(p.y()) { } Point::Point() { } Point::Point(const QString& str, int ysize) { x = y = -1; int length = str.length(); if(length == 0) return; if(str[0].isLetter()) { char c = str[0].toAscii(); if(c >= 'a' && c <= 'z') x = c-'a'; else if(c >= 'A' && c <= 'Z') x = c-'A'; if(length>1) y = ysize - str.mid(1).toInt(); } else y = ysize - str.toInt(); } QString Point::row(int ysize) const { if (y != -1) return QString::number(ysize - y); else return QString(); } QString Point::numcol(int xsize) const { if (x != -1) return QString::number(xsize - x); else return QString(); } QString Point::col() const { if (x != -1) { if(x >= 26) return QChar(static_cast(x - 26 + 'A')); else return QChar(static_cast(x + 'a')); } else return QString(); } QString Point::alpharow() const { if (y != -1) { if(y >= 26) return QChar(static_cast(y - 26 + 'A')); else return QChar(static_cast(y + 'a')); } else return QString(); } QString Point::toString(int ysize) const { return col() + row(ysize); } Point Point::operator+(const Point& other) const { return Point(x + other.x, y + other.y); } Point Point::operator+=(const Point& other) { return *this = *this + other; } Point Point::operator-() const { return Point(-x, -y); } Point Point::operator-(const Point& other) const { return Point(x - other.x, y - other.y); } Point Point::operator*(int n) const { return Point(x * n, y * n); } Point Point::operator/(int n) const { return Point(x / n, y / n); } Point Point::div(int n) const { return Point(x >= 0 ? x / n : x / n - 1, y >= 0 ? y / n : y / n - 1); } bool Point::operator==(const Point& other) const { return x == other.x && y == other.y; } bool Point::operator!=(const Point& other) const { return !(*this == other); } bool Point::operator<(const Point& other) const { return y < other.y || (y == other.y && x < other.x); } bool Point::operator<=(const Point& other) const { return y <= other.y || (y == other.y && x <= other.x); } bool Point::resembles(const Point& other) const { return (other.x == -1 || x == other.x) && (other.y == -1 || y == other.y); } Point::operator QPoint() const { return QPoint(x,y); } Point Point::normalizeInfinity() const { return Point( normalizeInfinityHelper(x), normalizeInfinityHelper(y) ); } double Point::norm() const { return sqrt((double)(x*x + y*y)); } int Point::normalizeInfinityHelper(int n) const { if (n == 0) return 0; else return n > 0 ? 1 : -1; } QDebug operator<<(QDebug dbg, const Point& p) { dbg << "(" << (p.x == -1 ? QString("?") : QString::number(p.x)) << ", " << (p.y == -1 ? QString("?") : QString::number(p.y)) << ")"; return dbg; } tagua-1.0-alpha2/src/point.h000066400000000000000000000032621077523320400157170ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef POINT_H #define POINT_H #include #include #include "export.h" struct TAGUA_EXPORT Point { static Point invalid() { return Point(-1, -1); } bool valid() const { return x != -1 && y != -1; } int x, y; Point(int x, int y); Point(); QString row(int ysize) const; QString numcol(int xsize) const; QString col() const; QString alpharow() const; explicit Point(const QString& str, int ysize); explicit Point(const QPoint&); QString toString(int ysize) const; Point operator+(const Point& other) const; Point operator+=(const Point& other); Point operator-() const; Point operator-(const Point& other) const; Point operator*(int n) const; Point operator/(int n) const; Point div(int n) const; bool operator==(const Point& other) const; bool operator!=(const Point& other) const; bool operator<(const Point& other) const; bool operator<=(const Point& other) const; // true if for each coordinate of other, either it // is -1, or it is equal to the corresponding // coordinate of this bool resembles(const Point& other) const; operator QPoint() const; Point normalizeInfinity() const; double norm() const; private: int normalizeInfinityHelper(int n) const; }; TAGUA_EXPORT QDebug operator<<(QDebug dbg, const Point& c); #endif // POINT_H tagua-1.0-alpha2/src/pointconverter.h000066400000000000000000000031461077523320400176500ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef POINTCONVERTER_H #define POINTCONVERTER_H #include #if 0 class PointConverter { int m_size; bool m_flipped; inline Point flipPoint(const Point& p) const { if (m_flipped) return Point(7-p.x, 7-p.y); else return p; } public: PointConverter(int size, bool flipped) : m_size(size) , m_flipped(flipped) { } inline Point toLogical(const QPoint& real) const { return flipPoint(Point(real).div(m_size)); } inline QPoint toReal(const Point& logical) const { return flipPoint(logical) * m_size; } inline void flip(bool flipped) { m_flipped = flipped; } inline void resize(int size) { m_size = size; } }; #endif class PointConverter { protected: virtual ~PointConverter(){}; public: virtual bool flipped() const = 0; virtual int squareSize() const = 0; virtual Point gridSize() const = 0; virtual Point flipPoint(const Point& p) const { if (flipped()) return gridSize()-Point(1,1)-p; else return p; } virtual Point toLogical(const QPoint& real) const { return flipPoint(Point(real).div( squareSize() )); } virtual QPoint toReal(const Point& logical) const { return flipPoint(logical) * squareSize(); } }; #endif // POINTCONVERTER_H tagua-1.0-alpha2/src/poolinfo.cpp000066400000000000000000000045011077523320400167430ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "poolinfo.h" #include "gameinfo.h" #include "variants.h" QRegExp PoolInfo::s_pattern("^\\s+game\\s+(\\d+)" //game num "\\s+white\\s+\\[([QKBNRP]*)\\]" // white pieces "\\s+black\\s+\\[([QKBNRP]*)\\]" // black pieces "(?:\\s+<\\-\\s+([WB][QKBNRP]))?" // added piece ); PoolInfo::PoolInfo(const std::map& games, const QString& str) : m_valid(false) , m_pos_index(-1) { // if (s_pattern.indexIn(str) != 0) // return; // // m_game_num = s_pattern.cap(1).toInt(); // std::map::const_iterator gi = games.find(m_game_num); // if (gi == games.end()) // return; // // QString var = !gi->second.variant.isEmpty() ? gi->second.variant : QString("chess"); // VariantInfo* variant = Variant::variant(GameInfo::variantCode(var)); // m_pos_index = gi->second.index; // // m_pool = //BROKEN #if 0 if (s_pattern.indexIn(str) != 0) return; m_game_num = s_pattern.cap(1).toInt(); std::map::const_iterator gi = games.find(m_game_num); if(gi == games.end()) return; QString var = !gi->second.variant.isEmpty() ? gi->second.variant : QString("chess"); VariantInfo* variant = Variant::variant(GameInfo::variantCode(var)); m_pos_index = gi->second.index; m_pool = AbstractPosition::PoolPtr(new AbstractPosition::AbstractPool); for(int i=0;i<2;i++) { QString cap = s_pattern.cap(i+2); int color = (i==0) ? WHITE : BLACK; for(int j=0;jtype(cap.at(j)); AbstractPiece::Ptr p = variant->createPiece(color, type); (*m_pool)[p]++; } } QString added = s_pattern.cap(4); if(!added.isEmpty()) { int color = (added.at(0) == 'W') ? WHITE : BLACK; int type = variant->type(added.at(1)); m_added_piece = variant->createPiece(color, type); } m_valid = true; #endif } tagua-1.0-alpha2/src/poolinfo.h000066400000000000000000000014261077523320400164130ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef POOLINFO_H #define POOLINFO_H #include #include #include "index.h" #include "tagua.h" #include "icsgamedata.h" class PoolInfo { public: bool m_valid; int m_game_num; Index m_pos_index; PoolPtr m_pool[2]; PiecePtr m_added_piece; static QRegExp s_pattern; PoolInfo(const std::map& games, const QString& s); }; #endif //POOLINFO_H tagua-1.0-alpha2/src/positioninfo.cpp000066400000000000000000000134521077523320400176430ustar00rootroot00000000000000/* Copyright (c) 2006-2007 Paolo Capriotti (c) 2006-2007 Maurizio Monge 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. */ #include "positioninfo.h" #include #include "variants.h" #include "gameinfo.h" #include "icsapi.h" using namespace boost; // Style 12 was designed by Daniel Sleator (sleator+@cs.cmu.edu) Darooha@ICC QRegExp PositionInfo::pattern( "^<12>\\s+" //header "([qkbnrpQKBNRP-]{8})\\s+" //chessboard "([qkbnrpQKBNRP-]{8})\\s+" //chessboard "([qkbnrpQKBNRP-]{8})\\s+" //chessboard "([qkbnrpQKBNRP-]{8})\\s+" //chessboard "([qkbnrpQKBNRP-]{8})\\s+" //chessboard "([qkbnrpQKBNRP-]{8})\\s+" //chessboard "([qkbnrpQKBNRP-]{8})\\s+" //chessboard "([qkbnrpQKBNRP-]{8})\\s+" //chessboard "([BW])\\s+" //black/white "(-1|[0-7])\\s+" //passing pawn "([01])\\s+" //castle rights "([01])\\s+" //castle rights "([01])\\s+" //castle rights "([01])\\s+" //castle rights "(-?\\d+)\\s+" //50 moves made "(\\d+)\\s+" //game num "(\\S+)\\s+" //white name "(\\S+)\\s+" //black name "(-[1-4]|[0-2])\\s+" //status "(\\d+)\\s+" //time "(\\d+)\\s+" //inc "(\\d+)\\s+" //w material "(\\d+)\\s+" //b material "(-?\\d+)\\s+" //w time "(-?\\d+)\\s+" //b time "(\\d+)\\s+" //move made "(\\S+)\\s+" //coordmove "(\\S+)\\s+" //time used "(\\S+)\\s+" //algmove "([0-1])" //flip ); PositionInfo::PositionRow::PositionRow(const ICSAPIPtr& icsapi, const QString& str) { Q_ASSERT(str.length() == 8); row.resize(str.length()); for (int i = 0; i < str.length(); ++i) { QChar c = str[i]; row[i] = icsapi->createPiece(c); } } /** * @return Position index as a 0-based halfmove count. */ int PositionInfo::index() const { int res = (moveIndex - 1) * 2; if (turn == 1) res++; return res; } PositionInfo::PositionInfo() : valid(false) { } bool PositionInfo::load(std::map& games, const QString& str) { if (pattern.indexIn(str) != 0) { valid = false; return true; } bool new_game = false; valid = true; int gn = pattern.cap(CaptureIndexes::GameNumber).toInt(); std::map::iterator gi = games.find(gn); ICSAPIPtr icsapi; if (gi == games.end()) { kWarning() << "Received style12 for unknown game" << gn; // create a gameinfo of type "dummy" gi = games.insert(std::make_pair(gn, ICSGameData(gn, ""))).first; new_game = true; } icsapi = gi->second.icsapi; std::vector rows; for (uint i = 0; i < 8; ++i) rows.push_back(PositionRow(icsapi, pattern.cap(CaptureIndexes::ChessboardStart + i))); gameNumber = pattern.cap(CaptureIndexes::GameNumber).toInt(); moveIndex = pattern.cap(CaptureIndexes::MoveOrdinal).toInt(); whitePlayer = pattern.cap(CaptureIndexes::WhitePlayer); blackPlayer = pattern.cap(CaptureIndexes::BlackPlayer); turn = pattern.cap(CaptureIndexes::Turn) == "W"? 0 : 1; int ep = pattern.cap(CaptureIndexes::EnPassant).toInt(); if (ep == -1) enPassantSquare = Point::invalid(); else enPassantSquare = Point(ep, turn == 0? 2 : 5); bool wkCastle = pattern.cap(CaptureIndexes::WhiteKingCastle).toInt() == 1; bool wqCastle = pattern.cap(CaptureIndexes::WhiteQueenCastle).toInt() == 1; bool bkCastle = pattern.cap(CaptureIndexes::BlackKingCastle).toInt() == 1; bool bqCastle = pattern.cap(CaptureIndexes::BlackQueenCastle).toInt() == 1; position = icsapi->createChessboard(turn, wkCastle, wqCastle, bkCastle, bqCastle, enPassantSquare); for (uint i = 0; i < 8; ++i) { for (uint j = 0; j < rows[i].row.size(); ++j) { position->set(Point(j,i), rows[i].row[j]); } } relation = static_cast(pattern.cap(CaptureIndexes::Relation).toInt()); whiteTime = pattern.cap(CaptureIndexes::WhiteTime).toInt(); blackTime = pattern.cap(CaptureIndexes::BlackTime).toInt(); if (pattern.cap(CaptureIndexes::TimeUsed).indexOf('.') == -1) { // time is in seconds whiteTime *= 1000; blackTime *= 1000; } lastMoveSAN = pattern.cap(CaptureIndexes::LastMove); lastMove = pattern.cap(CaptureIndexes::LastMoveVerbose); return new_game; } tagua-1.0-alpha2/src/positioninfo.h000066400000000000000000000044311077523320400173050ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef POSITIONINFO_H #define POSITIONINFO_H #include #include #include #include #include "tagua.h" #include "icsgamedata.h" #include "fwd.h" class PositionInfo { public: enum Relation { MoveListStart = -4, IsolatedPosition = -3, ObservingExamined = -2, NotMyMove = -1, ObservingPlayed = 0, MyMove = 1, Examining = 2, UnknownRelation = -255 }; class CaptureIndexes { public: enum { ChessboardStart = 1, Turn = 9, EnPassant = 10, WhiteKingCastle = 11, WhiteQueenCastle = 12, BlackKingCastle = 13, BlackQueenCastle = 14, ReversibleMoves = 15, GameNumber = 16, WhitePlayer = 17, BlackPlayer = 18, Relation = 19, StartingTime = 20, StartingIncrement = 21, WhiteTime = 24, BlackTime = 25, MoveOrdinal = 26, LastMoveVerbose = 27, TimeUsed = 28, LastMove = 29, Flip = 30 }; }; class PositionRow { public: std::vector row; explicit PositionRow(const ICSAPIPtr& icsapi, const QString& str); }; static QRegExp pattern; bool valid; PositionInfo(); /** * Parse a style12 line filling the fields of this PositionInfo object. * \param games Games we know about. * \param style12 A style12 line. * \return Whether the game is new. */ bool load(std::map& games, const QString& style12); int turn; int moveIndex; int index() const; int gameNumber; QString whitePlayer; QString blackPlayer; AbstractPosition::Ptr position; Point enPassantSquare; Relation relation; QString lastMoveSAN; QString lastMove; int whiteTime; int blackTime; }; #endif // POSITIONINFO_H tagua-1.0-alpha2/src/pref_board.cpp000066400000000000000000000051521077523320400172240ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include "mastersettings.h" #include "pref_board.h" PrefBoard::PrefBoard(const QString&, QWidget *parent) : QWidget(parent) { setupUi(this); { Settings s_anim = settings().group("animations"); groupAnimations->setChecked(s_anim.flag("enabled", true)); checkMovements->setChecked(s_anim["movement"].flag("enabled", true)); checkExplosions->setChecked(s_anim["explode"].flag("enabled", true)); checkFading->setChecked(s_anim["fading"].flag("enabled", true)); checkTransformations->setChecked(s_anim["transform"].flag("enabled", true)); { Settings s_sequence = s_anim.group("sequence"); checkSequence->setChecked(s_sequence.flag("enabled", true)); spinSequenceMax->setValue(s_sequence["max"] | 10); } sliderSpeed->setValue(s_anim["speed"] | 16); sliderSmoothness->setValue(s_anim["smoothness"] | 16); } { Settings s_border = settings().group("board-border"); groupBorder->setChecked(s_border.flag("visible", "true")); colorBorder->setColor(s_border["color"] |= QColor(Qt::white)); colorBorderText->setColor(s_border["text-color"] |= QColor(Qt::black)); fontBorder->setFont(s_border["font"] |= QApplication::font()); } } PrefBoard::~PrefBoard() { } void PrefBoard::apply() { { Settings s_anim = settings().group("animations"); s_anim.setFlag("enabled", groupAnimations->isChecked()); s_anim.group("movement").setFlag("enabled", checkMovements->isChecked()); s_anim.group("explode").setFlag("enabled", checkExplosions->isChecked()); s_anim.group("fading").setFlag("enabled", checkFading->isChecked()); s_anim.group("transform").setFlag("enabled", checkTransformations->isChecked()); { Settings s_sequence = s_anim.group("sequence"); s_sequence.setFlag("enabled", checkSequence->isChecked()); s_sequence["max"] = spinSequenceMax->value(); } s_anim["speed"] = sliderSpeed->value(); s_anim["smoothness"] = sliderSmoothness->value(); } { Settings s_border = settings().group("board-border"); s_border.setFlag("visible", groupBorder->isChecked()); s_border["color"] = colorBorder->color(); s_border["text-color"] = colorBorderText->color(); s_border["font"] = fontBorder->font(); } } tagua-1.0-alpha2/src/pref_board.h000066400000000000000000000013061077523320400166660ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PREFERENCES__BOARD_H #define PREFERENCES__BOARD_H #include "ui_pref_board.h" class PrefBoard : public QWidget , private Ui::PrefBoard { Q_OBJECT public: PrefBoard(const QString& currentVariant, QWidget *parent = 0); ~PrefBoard(); public Q_SLOTS: void apply(); }; #endif //PREFERENCES__BOARD_H tagua-1.0-alpha2/src/pref_engines.cpp000066400000000000000000000120731077523320400175650ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "pref_engines.h" #include #include #include #include #include #include #include #include "foreach.h" #include "mastersettings.h" class EditEngine : public KDialog { KLineEdit* m_name; KComboBox* m_type; KUrlRequester* m_path; KUrlRequester* m_work_dir; public: EditEngine(const QString& caption, QWidget* parent) : KDialog(parent) { setCaption(caption); setButtons(Ok | Cancel); QFrame* page = new QFrame(this); QVBoxLayout* layout = new QVBoxLayout; QHBoxLayout* tmp; QLabel* lbl; tmp = new QHBoxLayout; lbl = new QLabel(i18n("&Name:"), this); tmp->addWidget(lbl); // tmp->addStretch(); m_name = new KLineEdit(this); lbl->setBuddy(m_name); tmp->addWidget(m_name); tmp->addStretch(); lbl = new QLabel(i18n("&Type:"), this); tmp->addWidget(lbl); // tmp->addStretch(); m_type = new KComboBox(this); lbl->setBuddy(m_type); m_type->addItem(i18n("XBoard"), "xboard"); m_type->addItem(i18n("UCI"), "UCI"); m_type->addItem(i18n("Tagua (textual)"), "tagua-text"); m_type->addItem(i18n("Tagua (DBUS)"), "tagua-dbus"); m_type->addItem(i18n("GNU Shogi"), "gnushogi"); tmp->addWidget(m_type); layout->addLayout(tmp); tmp = new QHBoxLayout; lbl = new QLabel(i18n("&Path:"), this); tmp->addWidget(lbl); // tmp->addStretch(); m_path = new KUrlRequester(this); lbl->setBuddy(m_path); tmp->addWidget(m_path); layout->addLayout(tmp); tmp = new QHBoxLayout; lbl = new QLabel(i18n("&Work directory:"), this); tmp->addWidget(lbl); // tmp->addStretch(); m_work_dir = new KUrlRequester(this); lbl->setBuddy(m_work_dir); tmp->addWidget(m_work_dir); layout->addLayout(tmp); page->setLayout(layout); setMainWidget(page); m_name->setFocus(); } void load(const EngineDetails& e) { m_name->setText(e.name); m_type->setCurrentIndex(e.type); m_path->setPath(e.path); m_work_dir->setPath(e.workPath); } bool validate() { if (m_name->text().isEmpty()) { KMessageBox::error(this, i18n("Choose a name for the engine"), i18n("No engine name")); return false; } return true; } void save(EngineDetails& e) { if (validate()) { e.name = m_name->text(); e.type = static_cast(m_type->currentIndex()); e.path = m_path->url().path(); e.workPath = m_work_dir->url().path(); } } }; PrefEngines::PrefEngines(const QString&, QWidget* parent) : QWidget(parent) { QHBoxLayout* layout = new QHBoxLayout; m_list = new QListWidget(this); layout->addWidget(m_list); QVBoxLayout* buttons = new QVBoxLayout; m_new = new QPushButton(i18n("&New..."), this); buttons->addWidget(m_new); m_edit = new QPushButton(i18n("&Edit..."), this); buttons->addWidget(m_edit); m_delete = new QPushButton(i18n("&Delete"), this); buttons->addWidget(m_delete); buttons->addStretch(); layout->addLayout(buttons); setLayout(layout); connect(m_new, SIGNAL(pressed()), this, SLOT(new_engine())); connect(m_edit, SIGNAL(pressed()), this, SLOT(edit_engine())); connect(m_delete, SIGNAL(pressed()), this, SLOT(delete_engine())); connect(m_list, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(edit_engine())); // load engines foreach (Settings s, settings().group("engines").array("engine")) { EngineDetails e; e.load(s); m_engines.append(e); } reload_engines(); connect(m_list, SIGNAL(currentRowChanged(int)), this, SLOT(update_buttons())); update_buttons(); } PrefEngines::~PrefEngines() { } void PrefEngines::apply() { SettingArray engines = settings().group("engines").newArray("engine"); foreach (EngineDetails e, m_engines) { e.save(engines.append()); } } void PrefEngines::reload_engines() { m_list->clear(); foreach (EngineDetails e, m_engines) { m_list->addItem(e.name); } } void PrefEngines::new_engine() { EditEngine dialog("New engine", this); dialog.exec(); EngineDetails e; dialog.save(e); m_engines.append(e); reload_engines(); } void PrefEngines::edit_engine() { int row = m_list->currentRow(); Q_ASSERT(row != -1); EditEngine dialog("Edit engine", this); EngineDetails& e = m_engines[m_list->currentRow()]; dialog.load(e); dialog.exec(); dialog.save(e); reload_engines(); } void PrefEngines::delete_engine() { int row = m_list->currentRow(); Q_ASSERT(row != -1); m_engines.removeAt(row); reload_engines(); } void PrefEngines::update_buttons() { bool sel = m_list->currentRow() != -1; m_edit->setEnabled(sel); m_delete->setEnabled(sel); } tagua-1.0-alpha2/src/pref_engines.h000066400000000000000000000020001077523320400172170ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PREF_ENGINES_H #define PREF_ENGINES_H #include "ui_pref_engines.h" #include "engineinfo.h" #include "settings.h" #include #include class QPushButton; class QListWidget; class PrefEngines : public QWidget { Q_OBJECT QPushButton* m_new; QPushButton* m_edit; QPushButton* m_delete; QListWidget* m_list; QList m_engines; void reload_engines(); public: PrefEngines(const QString&, QWidget* parent = 0); ~PrefEngines(); void apply(); private Q_SLOTS: void new_engine(); void edit_engine(); void delete_engine(); void update_buttons(); }; #endif // PREF_ENGINES_H tagua-1.0-alpha2/src/pref_highlight.h000066400000000000000000000032331077523320400175470ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PREF_HIGHLIGHT_H #define PREF_HIGHLIGHT_H #include "ui_pref_highlight.h" #include "highlighter.h" #include #include #include #include class ItemMapBackInserter : public PatternListAdaptorOutputIterator { public: typedef std::map ItemMap; private: ItemMap& m_map; QListWidget* m_list; public: ItemMapBackInserter(ItemMap& map, QListWidget* list); virtual void add(const Highlighter::Pattern& p); QListWidgetItem* addItem(const Highlighter::Pattern& p); }; class PrefHighlight : public QDialog , private Ui::PrefHighlight { Q_OBJECT public: typedef ItemMapBackInserter::ItemMap ItemMap; private: ItemMap m_patterns; boost::shared_ptr m_highlighter; ItemMapBackInserter* m_inserter; public: PrefHighlight(); void apply(); Highlighter::Pattern& currentPattern(); void updateHighlighting(); public Q_SLOTS: void updateRegExp(); void updateBold(); void updateItalic(); void updateColor(const QColor&); void changePattern(QListWidgetItem*); void editPatternName(QListWidgetItem* index); void addEntry(); void removeEntry(); void moveEntryUp(); void moveEntryDown(); void moveEntry(int); }; #endif // PREF_HIGHLIGHT_H tagua-1.0-alpha2/src/pref_movelist.cpp000066400000000000000000000040211077523320400177710ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "settings.h" #include "movelist_p.h" #include "pref_movelist.h" PrefMoveList::PrefMoveList(const QString&, QWidget *parent) : QWidget(parent) { setupUi(this); m_settings = new MoveList::Settings; m_settings->load(); groupAnimations->setChecked(m_settings->anim_enabled); checkFading->setChecked(m_settings->anim_hideshow); checkHighlighting->setChecked(m_settings->anim_highlight); checkMovements->setChecked(m_settings->anim_moving); sliderSpeed->setValue(m_settings->anim_speed); sliderSmoothness->setValue(m_settings->anim_smoothness); colorSelected->setColor(m_settings->select_color); colorComments->setColor(m_settings->comment_color); checkMovesFont->setChecked(m_settings->use_mv_font); fontMoves->setFont(m_settings->mv_font); checkCommentsFont->setChecked(m_settings->use_comm_font); fontComments->setFont(m_settings->comm_font); } PrefMoveList::~PrefMoveList() { delete m_settings; } void PrefMoveList::apply() { m_settings->anim_enabled = groupAnimations->isChecked(); m_settings->anim_hideshow = checkFading->isChecked(); m_settings->anim_highlight = checkHighlighting->isChecked(); m_settings->anim_moving = checkMovements->isChecked(); m_settings->anim_speed = sliderSpeed->value(); m_settings->anim_smoothness = sliderSmoothness->value(); m_settings->select_color = colorSelected->color(); m_settings->comment_color = colorComments->color(); m_settings->use_mv_font = checkMovesFont->isChecked(); m_settings->mv_font = fontMoves->font(); m_settings->use_comm_font = checkCommentsFont->isChecked(); m_settings->comm_font = fontComments->font(); m_settings->save(); } tagua-1.0-alpha2/src/pref_movelist.h000066400000000000000000000014351077523320400174440ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PREFERENCES__MOVELIST_H #define PREFERENCES__MOVELIST_H #include "ui_pref_movelist.h" namespace MoveList { class Settings; } class PrefMoveList : public QWidget , private Ui::PrefMoveList { Q_OBJECT MoveList::Settings *m_settings; public: PrefMoveList(const QString&, QWidget *parent = 0); ~PrefMoveList(); public Q_SLOTS: void apply(); }; #endif //PREFERENCES__MOVELIST_H tagua-1.0-alpha2/src/pref_preferences.cpp000066400000000000000000000046731077523320400204450ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include "mastersettings.h" #include "pref_board.h" #include "pref_movelist.h" #include "pref_theme.h" #include "pref_engines.h" #include "pref_preferences.h" template class PrefWrapper : public PrefBase { private: T* m_inner; QString m_variant; public: PrefWrapper(const QString currentVariant, QWidget *parent = 0) : PrefBase(parent) , m_inner(0) , m_variant(currentVariant) { } virtual void apply() { if (m_inner) m_inner->apply(); } virtual void showEvent(QShowEvent*) { if (m_inner) return; m_inner = new T(m_variant, this); QHBoxLayout *l = new QHBoxLayout(this); l->addWidget(m_inner); m_inner->show(); } }; Preferences::Preferences(const QString& currentVariant, QWidget *parent) : QDialog(parent) { setupUi(this); setWindowIcon(KIcon("tagua")); connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(apply())); pagePref->hide(); PrefBase *b; KPageWidgetItem *i; b = new PrefWrapper(currentVariant, this); connect(this, SIGNAL(applied()), b, SLOT(apply())); i = pagePref->addPage(b, "Board"); i->setHeader("Board preferences:"); i->setIcon(KIcon("games-config-board")); b = new PrefWrapper(currentVariant, this); connect(this, SIGNAL(applied()), b, SLOT(apply())); i = pagePref->addPage(b, "Move list"); i->setHeader("Move list preferences:"); i->setIcon(KIcon("view-list-tree")); b = new PrefWrapper(currentVariant, this); connect(this, SIGNAL(applied()), b, SLOT(apply())); i = pagePref->addPage(b, "Theme"); i->setHeader("Pieces & squares theme:"); i->setIcon(KIcon("games-config-theme")); pagePref->show(); b = new PrefWrapper(currentVariant, this); connect(this, SIGNAL(applied()), b, SLOT(apply())); i = pagePref->addPage(b, "Engines"); i->setHeader("Engines:"); i->setIcon(KIcon("help-hint")); pagePref->show(); } Preferences::~Preferences() { } void Preferences::apply() { applied(); settings().changed(); } tagua-1.0-alpha2/src/pref_preferences.h000066400000000000000000000017161077523320400201050ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PREFERENCES__PREFERENCES_H #define PREFERENCES__PREFERENCES_H #include #include "ui_preferences.h" class PrefBase : public QWidget { Q_OBJECT public: PrefBase(QWidget *parent = 0) : QWidget(parent) {} public Q_SLOTS: virtual void apply() = 0; }; class Preferences : public QDialog , private Ui::Preferences { Q_OBJECT std::list m_pages; public: Preferences(const QString& currentVariant, QWidget *parent = 0); ~Preferences(); Q_SIGNALS: void applied(); public Q_SLOTS: void apply(); }; #endif //PREFERENCES__PREFERENCES_H tagua-1.0-alpha2/src/pref_theme.cpp000066400000000000000000000304721077523320400172420ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. // */ #include #include #include #include #include #include #include "foreach.h" #include "mastersettings.h" #include "luaapi/loader.h" #include "variants.h" #include "tagua.h" #include "pref_theme.h" PrefTheme::ThemeInfoList PrefTheme::to_theme_info_list(const QStringList& files, const Settings& s) { //kDebug() << "about to examine " << files.size() << " desktop files"; std::map cached_info; SettingArray themes = s.group("themes").array("theme"); foreach (Settings s_theme, themes) { ThemeInfo info = ThemeInfo::fromSettings(s_theme); cached_info[info.desktopFile] = info; } ThemeInfoList all_themes; bool updated = false; for(int i = 0; i < files.size(); i++) { QFileInfo file_info(files[i]); std::map::iterator it = cached_info.find(files[i]); if (it != cached_info.end() && file_info.exists() && it->second.last_modified == file_info.lastModified() ) { all_themes << it->second; cached_info.erase(it); } else { updated = true; ThemeInfo theme_info = ThemeInfo::fromDesktopFile(files[i]); all_themes << theme_info; if (theme_info.name.isEmpty()) { kError() << "No name property in" << files[i]; } } } if(!cached_info.empty()) updated = true; /* rewrite the cached configuration */ if(updated) { SettingArray themes = s.group("themes").newArray("theme"); for (int i = 0; i < all_themes.size(); i++) { Settings s_theme = themes.append(); all_themes[i].save(s_theme); } } return all_themes; } OptList PrefTheme::get_file_options(const QString& f, bool reload_defaults) { //kDebug() << "get file options for " << f; if(!reload_defaults) { std::map::iterator it = m_new_theme_options.find(f); if(it != m_new_theme_options.end()) return it->second; } LuaApi::Loader lua_context; lua_context.runFile(f); if(lua_context.error()) { kError() << lua_context.errorString(); lua_context.clearError(); m_new_theme_options[f] = OptList(); return OptList(); } OptList o = lua_context.getValue("options", 0, NULL, true); if(lua_context.error()) { kError() << lua_context.errorString(); lua_context.clearError(); } if(!reload_defaults) { SettingMap s_lua = settings().group("lua-settings").map("entry", "file-name"); Settings entry = s_lua.insert(f); options_list_load_from_settings(o, entry.group("options")); m_new_theme_options[f] = o; } return o; } int PrefTheme::theme_ok_for_variant(const ThemeInfo& theme_info, const QString& variant_name) { if(theme_info.variants.contains(variant_name+"[default]", Qt::CaseInsensitive)) return 4; if(theme_info.variants.contains(variant_name, Qt::CaseInsensitive)) return 3; if(theme_info.variants.contains("any[default]", Qt::CaseInsensitive)) return 2; if(theme_info.variants.contains("any", Qt::CaseInsensitive)) return 1; return 0; } PrefTheme::PrefTheme(const QString& currentVariant, QWidget *parent) : QWidget(parent) { setupUi(this); Category *c; c = new Category(NULL, this); m_categories["pieces"] = c; tabWidget->addTab(c, "&Pieces"); c = new Category(NULL, this); m_categories["squares"] = c; tabWidget->addTab(c, "&Squares"); c = new Category(NULL, this); m_categories["controls"] = c; tabWidget->addTab(c, "&Controls"); MasterSettings cached_theme_info("tagua_config_cache.xml"); connect(comboVariant, SIGNAL(currentIndexChanged(int)), this, SLOT(variantChanged())); for(CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) { Category* c = cit->second; c->m_list->setSelectionMode(QAbstractItemView::SingleSelection); connect(c->m_list, SIGNAL(itemSelectionChanged()), c, SLOT(themeChanged())); connect(c->m_check, SIGNAL(toggled(bool)), c, SLOT(themeChecked(bool))); c->m_opt_layout = new QHBoxLayout(c->m_widget); c->m_opt_layout->setMargin(0); c->m_themes = to_theme_info_list( KGlobal::dirs()->findAllResources("appdata", "themes/"+cit->first+"/*.desktop", KStandardDirs::Recursive), cached_theme_info.group(cit->first) ); //kDebug() << "loaded " << c->m_themes.size() << " themes"; } QStringList all = Variants::instance().all(); int index = 0; int current = -1; foreach (QString variant, all) { if (variant == currentVariant) { current = index; } comboVariant->addItem(variant, QVariant(variant)); index++; } if (current != -1) comboVariant->setCurrentIndex(current); variantChanged(); } PrefTheme::~PrefTheme() { } void PrefTheme::apply() { SettingMap variants = settings().group("variants").map("variant", "name"); for(CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) { Category* c = cit->second; for(std::map::iterator it = c->m_new_themes.begin(); it != c->m_new_themes.end(); ++it) { Settings var = variants.insert(it->first); var[cit->first+"-theme"] = it->second; } for(std::map::iterator it = c->m_new_use_def.begin(); it != c->m_new_use_def.end(); ++it) { Settings var = variants.insert(it->first); var[cit->first+"-use-def"] = it->second; } } for(std::map::iterator it = m_new_theme_options.begin(); it != m_new_theme_options.end(); ++it) { SettingMap s_lua = settings().group("lua-settings").map("entry", "file-name"); Settings entry = s_lua.insert(it->first); options_list_save_to_settings(it->second, entry.group("options")); } } void PrefTheme::update_list_view(QListWidget* list, const ThemeInfoList& themes, QString variant_name, QString settings_theme) { list->clear(); int selected_ok = 0; QListWidgetItem *item_to_select = NULL; for (int i = 0; i < themes.size(); i++) { int ok = theme_ok_for_variant(themes[i], variant_name); if (!ok) continue; ok = (themes[i].desktopFile == settings_theme) ? 5 : ok; QListWidgetItem *list_item = new QListWidgetItem(themes[i].name, list); list_item->setData(Qt::UserRole, i); if(ok > selected_ok) { item_to_select = list_item; selected_ok = ok; } } if(item_to_select) list->setItemSelected(item_to_select, true); } void PrefTheme::variantChanged() { QString category = comboVariant->itemData(comboVariant->currentIndex()).toString(); VariantFactory* vi = Variants::instance().getFactory(category); if (!vi) { for (CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) { Category* c = cit->second; c->m_check->hide(); c->m_list->clear(); c->m_list->setEnabled(false); c->m_label->setText(QString()); c->m_label->setEnabled(false); } return; } QString variant_name = vi->name(); QString variant_proxy = vi->themeProxy(); SettingMap variants = settings().group("variants").map("variant", "name"); Settings var = variants.insert(variant_name); bool check_proxy = variant_name != variant_proxy; for(CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) { Category* c = cit->second; c->m_check->setVisible(check_proxy); if(check_proxy) { bool use_def = c->m_new_use_def.count(variant_name) ? c->m_new_use_def[variant_name] : (var[cit->first+"-use-def"] | true).value(); c->m_check->setText("Same as "+variant_proxy); c->m_check->setChecked(use_def); c->m_list->setEnabled(!use_def); c->m_label->setEnabled(!use_def); } else { c->m_list->setEnabled(true); c->m_label->setEnabled(true); } QString settings_theme = c->m_new_themes.count(variant_name) ? c->m_new_themes[variant_name] : (var[cit->first+"-theme"] | QString()).value(); update_list_view(c->m_list, c->m_themes, variant_proxy, settings_theme); } } ThemeInfo PrefTheme::getBestTheme(const VariantPtr& vi, const QString& category) { QString tag = category + "-theme"; QString deftag = category + "-use-def"; QString variant_name = vi->name(); QString variant_proxy_name = vi->themeProxy(); SettingMap variants = settings().group("variants").map("variant", "name"); if (variant_name != vi->themeProxy() && (variants.insert(variant_name)[deftag] | true) ) variant_name = vi->themeProxy(); Settings var_settings = variants.insert(variant_name); if (var_settings[tag] && QFile::exists(var_settings[tag].value()) ) { // there is a theme in the settings, so pick this ThemeInfo res = ThemeInfo::fromDesktopFile(var_settings[tag].value()); if(theme_ok_for_variant(res, variant_proxy_name)) return res; } MasterSettings cached_theme_info("tagua_config_cache.xml"); KStandardDirs* std_dirs = KGlobal::dirs(); ThemeInfoList themes = to_theme_info_list(std_dirs->findAllResources("appdata", "themes/" + category + "/*.desktop", KStandardDirs::Recursive ), cached_theme_info.group(category)); int best = 0; ThemeInfo* retv = 0; for(int i = 0; i < themes.size(); i++) { int ok = theme_ok_for_variant(themes[i], variant_proxy_name); if (!ok) continue; if (ok > best) { retv = &themes[i]; best = ok; } } if (retv && *retv) { var_settings[tag] = retv->desktopFile; } return retv ? *retv : ThemeInfo(); } PrefThemeCategory::PrefThemeCategory(QWidget* parent, PrefTheme* owner) : QWidget(parent) , m_parent(owner) , m_opt_layout(NULL) , m_opt_widget(NULL) { setupUi(this); m_reset = new QAction(KIcon("edit-clear"), i18n("&Reset to Default"), this); m_reset->setShortcut(Qt::CTRL+Qt::Key_Z); connect(m_reset, SIGNAL(triggered()), this, SLOT(reset())); m_resetButton->setDefaultAction(m_reset); m_resetButton->setToolButtonStyle(Qt::ToolButtonIconOnly); } void PrefThemeCategory::reset() { if(!m_opt_widget) return; QList l = m_list->selectedItems(); if(l.isEmpty()) return; int i = l[0]->data(Qt::UserRole).toInt(); if (i >= 0 && i < m_themes.size()) { OptList ol = m_parent->get_file_options(m_themes[i].file_name, true); qobject_cast(m_opt_widget)->setValues(ol); } } void PrefThemeCategory::themeChanged() { QList l = m_list->selectedItems(); if(!l.isEmpty()) { int i = l[0]->data(Qt::UserRole).toInt(); if(i>=0 && isetText(m_themes[i].description); QString c = m_parent->comboVariant->itemData(m_parent->comboVariant->currentIndex()).toString(); VariantFactory* vi = Variants::instance().getFactory(c); if(vi) m_new_themes[vi->name()] = m_themes[i].desktopFile; if(m_opt_widget) { delete m_opt_widget; m_opt_widget = NULL; } OptList ol = m_parent->get_file_options(m_themes[i].file_name); if (ol.size() != 0 && m_list->isEnabled()) { m_opt_widget = new OptionWidget(ol, m_widget); m_opt_layout->addWidget(m_opt_widget); m_reset->setEnabled(true); } else m_reset->setEnabled(false); return; } } m_label->setText(QString()); } void PrefThemeCategory::themeChecked(bool ck) { m_list->setEnabled(!ck); m_label->setEnabled(!ck); QString c = m_parent->comboVariant->itemData(m_parent->comboVariant->currentIndex()).toString(); VariantFactory* vi = Variants::instance().getFactory(c); if (vi) m_new_use_def[vi->name()] = ck; themeChanged(); } tagua-1.0-alpha2/src/pref_theme.h000066400000000000000000000042621077523320400167050ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PREFERENCES__THEME_H #define PREFERENCES__THEME_H #include #include #include #include #include #include "option.h" #include "themeinfo.h" #include "ui_pref_theme.h" #include "ui_pref_theme_page.h" #include "fwd.h" class VariantInfo; class Settings; class QAction; class PrefTheme : public QWidget , private Ui::PrefTheme { Q_OBJECT friend class PrefThemeCategory; typedef class PrefThemeCategory Category; typedef QList ThemeInfoList; typedef std::map CategoryMap; std::map m_new_theme_options; CategoryMap m_categories; OptList get_file_options(const QString&, bool reload_defaults = false); static ThemeInfoList to_theme_info_list(const QStringList& files, const Settings& s); static int theme_ok_for_variant(const ThemeInfo&, const QString&); static void update_list_view(QListWidget* list, const ThemeInfoList& themes, QString variant, QString settings); private Q_SLOTS: void variantChanged(); public: PrefTheme(const QString&, QWidget *parent = 0); ~PrefTheme(); void apply(); static ThemeInfo getBestTheme(const VariantPtr& vi, const QString&); }; class PrefThemeCategory : public QWidget , private Ui::PrefThemePage { Q_OBJECT public: friend class PrefTheme; QAction* m_reset; PrefTheme* m_parent; QString m_id; PrefTheme::ThemeInfoList m_themes; std::map m_new_themes; std::map m_new_use_def; QLayout *m_opt_layout; QWidget *m_opt_widget; PrefThemeCategory(QWidget* parent, PrefTheme* owner); public Q_SLOTS: void reset(); void themeChanged(); void themeChecked(bool ck); }; #endif //PREFERENCES__THEME_H tagua-1.0-alpha2/src/premove.cpp000066400000000000000000000013501077523320400165720ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "premove.h" #include "usermove.h" Premove::Premove(AbstractMove::Ptr move) : m_move(move) { } AbstractMove::Ptr Premove::execute(AbstractPosition::Ptr position) { if (position->testMove(m_move)) { return m_move; } else return AbstractMove::Ptr(); } NormalUserMove Premove::toUserMove() const { return m_move->toUserMove(); } tagua-1.0-alpha2/src/premove.h000066400000000000000000000012721077523320400162420ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef PREMOVE_H #define PREMOVE_H #include "tagua.h" class Premove { protected: AbstractMove::Ptr m_move; public: Premove(AbstractMove::Ptr move); virtual ~Premove() { } virtual AbstractMove::Ptr execute(AbstractPosition::Ptr); virtual class NormalUserMove toUserMove() const; }; #endif // PREMOVE_H tagua-1.0-alpha2/src/qconnect.cpp000066400000000000000000000061341077523320400167340ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include #include #include "qconnect.h" #include "mastersettings.h" static const char* timeseal_cmd_tool_tip = "Expandable variables ref:\n" " $(HOST_IP) - The resolved ip address of the host\n" " $(HOST_NAME) - The host name\n" " $(PORT) - The TCP port to connect to"; QConnect::QConnect(QWidget *parent, const char *name) : QDialog(parent) { setObjectName(name); setupUi(this); connect(buttonTimesealPath, SIGNAL(clicked()), this, SLOT(setTimesealPath())); chkTimesealCmd->setToolTip(timeseal_cmd_tool_tip); editTimesealCmd->setToolTip(timeseal_cmd_tool_tip); //kDebug() << "initializing dialog"; Settings s_ics = settings().group("ics"); if (s_ics["username"]) editUsername->setText(s_ics["username"].value()); if (s_ics["password"]) { editPassword->setText(s_ics["password"].value()); chkStore->setChecked(true); } if (s_ics["host"]) editHost->setText(s_ics["host"] | ""); spinPort->setValue((s_ics["port"] | 5000)); Settings s_timeseal = s_ics.group("timeseal"); groupTimeseal->setChecked(s_timeseal.flag("use", false)); editTimeseal->setText(s_timeseal["path"] |= QString()); chkTimesealCmd->setChecked(s_timeseal["command"].flag("use", false)); editTimesealCmd->setText(s_timeseal["command"] |= "$(HOST_IP) $(PORT)"); } void QConnect::setTimesealPath() { KUrl url = KFileDialog::getOpenUrl(KUrl(), "*", this, i18n("Select timeseal binary")); if (!url.isLocalFile()) { KMessageBox::sorry(0, i18n("Only local executables supported")); return; } if (!url.isEmpty()) editTimeseal->setText(url.path()); } void QConnect::accept() { QDialog::accept(); Settings s_ics = settings().group("ics"); s_ics["username"] = editUsername->text(); if (chkStore->isChecked()) s_ics["password"] = editPassword->text(); else s_ics["password"].remove(); s_ics["host"] = editHost->text(); s_ics["port"] = spinPort->value(); { Settings s_timeseal = s_ics.group("timeseal"); s_timeseal.setFlag("use", groupTimeseal->isChecked()); s_timeseal["path"] = editTimeseal->text(); s_timeseal.group("command").setFlag("use", chkTimesealCmd->isChecked()); s_timeseal["command"] = editTimesealCmd->text(); } acceptConnection(editUsername->text(), editPassword->text(), editHost->text(), spinPort->value(), groupTimeseal->isChecked() ? editTimeseal->text() : QString(), chkTimesealCmd->isChecked() ? editTimesealCmd->text() : QString("$(HOST_IP) $(PORT)") ); } tagua-1.0-alpha2/src/qconnect.h000066400000000000000000000015161077523320400164000ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef QCONNECT_H #define QCONNECT_H #include "ui_quickconnect.h" class QConnect: public QDialog, public Ui::QuickConnect { Q_OBJECT public: QConnect(QWidget *parent = 0, const char *name = 0); public Q_SLOTS: virtual void accept(); void setTimesealPath(); Q_SIGNALS: void acceptConnection(const QString&, const QString&, const QString&, quint16, const QString&, const QString&); }; #endif tagua-1.0-alpha2/src/random.cpp000066400000000000000000000017261077523320400164040ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "random.h" Random* Random::m_instance = 0; Random::Random() { } Random::IntegerGenerator Random::rand(int min, int max) { return IntegerGenerator(&m_generator, IntegerDistribution(min, max)); } Random::RealGenerator Random::rand(float min, float max) { return RealGenerator(&m_generator, RealDistribution(min, max)); } Random::RealGenerator Random::rand(double min, double max) { return rand(static_cast(min), static_cast(max)); } Random& Random::instance() { if (!m_instance) { m_instance = new Random; } return *m_instance; } tagua-1.0-alpha2/src/random.h000066400000000000000000000023471077523320400160510ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef RANDOM_H #define RANDOM_H #include #include #include #include class Random { public: typedef boost::mt19937 RandomGenerator; typedef boost::uniform_smallint<> IntegerDistribution; typedef boost::uniform_real RealDistribution; typedef boost::variate_generator IntegerGenerator; typedef boost::variate_generator RealGenerator; private: RandomGenerator m_generator; Random(); // singleton static Random* m_instance; public: IntegerGenerator rand(int min, int max); RealGenerator rand(float min, float max); RealGenerator rand(double min, double max); static Random& instance(); }; #endif // RANDOM_H tagua-1.0-alpha2/src/rubyutils.h000066400000000000000000000014031077523320400166230ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ extern "C" { #include } #include "point.h" namespace Ruby { Point value2point(VALUE); VALUE point2value(const Point&); #if 0 VALUE pcall(int* res, VALUE rcpt, ID id); VALUE pcall(int* res, VALUE rcpt, ID id, VALUE arg1); VALUE pcall(int* res, VALUE rcpt, ID id, VALUE arg1, VALUE arg2); VALUE pcall(int* res, VALUE rcpt, ID id, VALUE arg1, VALUE arg2, VALUE arg3); #endif } tagua-1.0-alpha2/src/serverinfo.h000066400000000000000000000041631077523320400167510ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef SERVERINFO_H #define SERVERINFO_H #include #ifdef Q_CC_MSVC #pragma warning( push ) #pragma warning( disable : 4100 ) #include #pragma warning( pop ) #else #include #endif #include "varianttraits.h" template class ChessServerInfo { public: boost::shared_ptr position; ChessServerInfo(const boost::shared_ptr position) : position(position) { } }; template class PoolServerInfo { public: typename PoolArray< typename PoolTraits::type, PoolTraits::number>::type pools; }; template struct ServerInfo { typedef boost::variant, PoolServerInfo > type; }; #if 0 template class ServerInfoVisitor; template class ServerInfo { public: virtual void apply(ServerInfoVisitor& visitor) const = 0; }; template class ChessServerInfo; template class PoolServerInfo; template class ServerInfoVisitor { public: virtual void visit(const ChessServerInfo& info) = 0; virtual void visit(const PoolServerInfo& info) = 0; }; template class ChessServerInfo : public ServerInfo { public: boost::shared_ptr position; virtual void apply(ServerInfoVisitor& visitor) const { visitor.visit(*this); } ChessServerInfo(const boost::shared_ptr position) : position(position) { } }; template class PoolServerInfo : public ServerInfo { public: typename PoolTraits::type pools[PoolTraits::number]; virtual void apply(ServerInfoVisitor& visitor) const { visitor.visit(*this); } }; #endif // 0 #endif // SERVERINFO_H tagua-1.0-alpha2/src/serverreference.h000066400000000000000000000051421077523320400177520ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef CHESSREFERENCE_H #define CHESSREFERENCE_H #include #include "serverinfo.h" template struct ComparePosition { static bool apply(const Pos& chessPos, const Pos& pos) { return static_cast(chessPos) == pos; } }; /** * @brief Common base for ServerReference specializations. */ template struct ServerReferenceBase { typedef Pos Position; class InfoVisitor : public boost::static_visitor { const Position& m_position; public: InfoVisitor(const Position& position) : m_position(position) { } bool operator()(const ChessServerInfo& info) const { return ComparePosition::apply( *info.position, m_position); } bool operator()(const PoolServerInfo&) const { return true; // FIXME } }; /** * Compare a position with a @a ChessPosition. Used to check locally * computed positions against server provided positions. */ static bool checkPosition(const Position& pos, const ChessPosition& serverPos) { return serverPos == pos; } /** * Retrieve a position shared pointer from a @a ChessPosition * pointer. Used to retrieve variant specific position * information from @a style12.position */ static boost::shared_ptr getPosition( const boost::shared_ptr& pos) { return boost::shared_ptr( new Position(*pos)); } /** * Compare a position with partial information contained in another position. */ static bool checkPartialPosition(const Position& pos, const typename ServerInfo::type& server) { return boost::apply_visitor(InfoVisitor(pos), server); } }; /** * @brief ServerReference is used whenever information coming from * the server has to be compared with variant specific structures. */ template struct ServerReference : public ServerReferenceBase { }; template <> struct ServerReference : public ServerReferenceBase { static boost::shared_ptr getPosition( const boost::shared_ptr& pos) { return pos; } }; #endif // CHESSREFERENCE_H tagua-1.0-alpha2/src/settings.cpp000066400000000000000000000122621077523320400167610ustar00rootroot00000000000000/* Copyright 2006-2007 Paolo Capriotti BSD License Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "settings.h" #ifdef __SETTINGS_DEBUG #include #include #endif SettingConstRef::SettingConstRef(const QDomElement& element) : m_element(element) { if (!m_element.isNull()) { if (m_element.firstChild().toText().isNull()) m_element.appendChild(m_element.ownerDocument().createTextNode( QString() )); } } SettingRefBase::operator bool() const { return !element().isNull(); } bool SettingRefBase::flag(const QString& attr, bool def) const { return element().attribute(attr, def ? "true" : "false") == "true"; } SettingRef::SettingRef(const QDomElement& parent, const QString& key) : m_parent(parent) , m_key(key) { } void SettingRef::remove() { m_parent.removeChild(element()); } Settings::Settings(const QDomElement& node) : m_node(node) { } Settings::Settings(const Settings& other) : m_node(other.node()) { } Settings& Settings::operator=(const Settings& other) { m_node = other.node(); return *this; } SettingRef Settings::operator[](const QString& key) { return SettingRef(node(), key); } SettingConstRef Settings::operator[](const QString& key) const { return SettingConstRef(node().firstChildElement(key)); } SettingGroup Settings::group(const QString& name) const { return SettingGroup(node(), name); } SettingGroup Settings::operator()(const QString& name) const { return group(name); } SettingArray Settings::array(const QString& name) const { return SettingArray(node(), name); } SettingArray Settings::newArray(const QString& name) const { SettingArray res(node(), name); res.clear(); return res; } void Settings::ensureExistence(QDomElement& node, QDomElement parent, const QString& name) { if (node.isNull()) { node = parent.firstChildElement(name); if (node.isNull()) { node = parent.ownerDocument().createElement(name); parent.appendChild(node); } } Q_ASSERT(!node.isNull()); } bool Settings::flag(const QString& attr, bool def) const { //kDebug() << "get flag " << node().isNull() << " " << attr << " = " //<< node().attribute(attr, def ? "true" : "false"); return node().attribute(attr, def ? "true" : "false") == "true"; } void Settings::setFlag(const QString& attr, bool val) { node().setAttribute(attr, val ? "true" : "false"); } SettingGroup::SettingGroup(const QDomElement& parent, const QString& name) : m_name(name) , m_parent(parent) { } QDomElement SettingGroup::node() const { ensureExistence(const_cast(m_node), m_parent, m_name); Q_ASSERT(!m_node.isNull()); return m_node; } void SettingGroup::remove() { node().parentNode().removeChild(node()); } SettingArray::SettingArray(const QDomElement& node, const QString& element) : m_node(node) , m_element(element) { QDomNodeList elements = m_node.elementsByTagName(m_element); m_array.resize(elements.size()); for (int i = 0; i < elements.size(); i++) m_array[i] = elements.item(i).toElement(); } Settings SettingArray::get(int index) const { return m_array[index]; } Settings SettingArray::insert(int index) { QDomElement el = node().ownerDocument().createElement(m_element); node().insertBefore(el, m_array[index].node()); Settings res = el; m_array.insert(m_array.begin() + index, res); return res; } Settings SettingArray::append() { QDomElement el = node().ownerDocument().createElement(m_element); node().appendChild(el); Settings res = el; m_array.push_back(res); return res; } void SettingArray::clear() { QDomNodeList children = node().childNodes(); while (children.size() > 0) { QDomElement e = children.item(0).toElement(); if (!e.isNull() || e.tagName() == m_element) node().removeChild(e); } } #ifdef __SETTINGS_DEBUG void Settings::dump() const { QFile outf; outf.open(stdout, QIODevice::WriteOnly); QTextStream out(&outf); if (node().isNull()) { out << "" << endl; return; } QDomDocument temp; temp.appendChild(temp.importNode(node(), true)); out << temp.toString() << endl; } #endif tagua-1.0-alpha2/src/settings.h000066400000000000000000000431641077523320400164330ustar00rootroot00000000000000/* Copyright 2006-2007 Paolo Capriotti BSD License Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SETTINGS_H #define SETTINGS_H #include #include #include #include #include #include #include #include template class TypedSettingRef; template struct ReturnType { typedef T type; typedef TypedSettingRef wrapper; }; template struct ReturnType { typedef const T* type; typedef type wrapper; }; template struct SettingConversionBase { static typename ReturnType::type getValue(const QDomElement&, const QDomText& text) { return text.data(); } static void setValue(QDomElement, QDomText text, const T& val) { text.setData(val); } }; template struct SettingConversion : public SettingConversionBase { }; template struct SettingConversion : public SettingConversionBase { static const char* getValue(const QDomElement&, const QDomText& text) { return qPrintable(text.data()); } static void setValue(QDomElement, QDomText text, const char* val) { text.setData(val); } }; template <> struct SettingConversion { static int getValue(const QDomElement&, const QDomText& text) { return text.data().toInt(); } static void setValue(QDomElement, QDomText text, int val) { text.setData(QString::number(val)); } }; template <> struct SettingConversion { static QColor getValue(const QDomElement& e, const QDomText&) { int r = e.attribute("r", "0").toInt(); int g = e.attribute("g", "0").toInt(); int b = e.attribute("b", "0").toInt(); return QColor(r, g, b); } static void setValue(QDomElement e, QDomText, const QColor& val) { e.setAttribute("r", val.red()); e.setAttribute("g", val.green()); e.setAttribute("b", val.blue()); } }; template <> struct SettingConversion : public SettingConversion { }; template <> struct SettingConversion { static QFont getValue(const QDomElement&, const QDomText& text) { QFont res; res.fromString(text.data()); return res; } static void setValue(QDomElement, QDomText text, const QFont& font) { text.setData(font.toString()); } }; template <> struct SettingConversion { static bool getValue(const QDomElement&, const QDomText& text) { return text.data().toLower() == "true"; } static void setValue(QDomElement, QDomText text, bool val) { text.setData(val ? "true" : "false"); } }; class SettingRefBase { protected: virtual QDomElement element() const = 0; virtual QDomText node() const { return element().firstChild().toText(); } public: virtual ~SettingRefBase() { } template typename ReturnType::wrapper operator|(const T& val) const; template typename ReturnType::type value(const T& defaultValue) const; template typename ReturnType::type value() const; template void operator>>(T& out) const; operator bool() const; bool flag(const QString& attr, bool def) const; }; class SettingConstRef : public SettingRefBase { QDomElement m_element; protected: virtual QDomElement element() const { return m_element; } public: SettingConstRef(const QDomElement& node); }; class SettingRef : public SettingRefBase { QDomElement m_parent; QString m_key; protected: virtual QDomElement element() const { return m_parent.firstChildElement(m_key); } public: SettingRef(const QDomElement& node, const QString& key); void remove(); template typename ReturnType::wrapper operator|=(const T& val); template typename ReturnType::wrapper operator=(const T& val); }; // class GenericSettingRef : public SettingRef { // QDomElement m_element; // protected: // virtual QDomElement element() const { return m_element; } // public: // GenericSettingRef(const QDomElement& element, const QString& key); // }; template class TypedSettingRef { T m_value; public: TypedSettingRef(const T& value) : m_value(value) { } operator typename ReturnType::type() const { return value(); } template void operator>>(U& out) const { out = m_value; } typename ReturnType::type value() const { return m_value; } }; template class SettingMap; /** * @brief The Settings class provides persistent application settings on an XML file. * * Use this class to store your application settings if you need an hierarchical * configuration stored on a human-readable text file. * * Settings completely abstracts the serialization and deserialization procedures for * simple data types, and allows a customized XML serialization for user defined types. * * The configuration is hierarchical, with a Settings object representing a node of the * tree. Each node can contain key-value pairs, accessed as * settings["key"] * both for reading and writing. * * Accessing a group returns another Settings object, and there's no need to "close" the * group (like with the QSettings class) when you're done reading or writing. * * Settings support aggregates of objects in the form of linear or associative arrays. */ class Settings { friend class SettingArray; protected: QDomElement m_node; virtual QDomElement node() const { return m_node; } public: /** Create an invalid Settings object. */ Settings() { } virtual ~Settings() { } /** * Create a Settings object attached on a specified XML node. * @param node An XML node to be used as the root of the Settings */ Settings(const QDomElement& node); /** * Create a copy of the Settings object */ Settings(const Settings& other); /** * Assign a Settings object to another. */ Settings& operator=(const Settings& other); /** * Read the value associated with @a key. Values returned from * a read operation on Settings can be converted using the * template member function @a value. */ SettingRef operator[](const QString& key); /** * Just like the above function, but returns a constant reference. */ SettingConstRef operator[](const QString& key) const; /** * Overload */ SettingRef operator[](const char* key) { return operator[](QString(key)); } /** * Overload */ SettingConstRef operator[](const char* key) const { return operator[](QString(key)); } /** * Access a setting group. * @param name The name of the group. * @returns A Settings object representing the specified group. */ class SettingGroup group(const QString& name) const; /** * Shotcat to access a setting group, same as \a group * @param name The name of the group. * @returns A Settings object representing the specified group. */ class SettingGroup operator()(const QString& name) const; /** * Access a setting map with keys of type @a T. * @param element The name of every map element. * @param key The element acting as a key. * @returns A SettingMap object representing the specified map. * @sa SettingMap */ template SettingMap map(const QString& element, const QString& key) const; /** * Just like the above function, but clear the returned map. Use this * function if the desired behaviour is to overwrite the existing map * in the associated setting node. */ template SettingMap newMap(const QString& element, const QString& key) const; /** * Access a setting array. * @param element The name of every array element. * @returns a SettingArray object representing the specified array. * @sa SettingArray */ class SettingArray array(const QString& element) const; /** * Just like the above function, but clear the returned array. Use this * function if the desired behaviour is to overwrite the existing array * in the associated setting node. */ class SettingArray newArray(const QString& element) const; /** * Retrieve a global boolean flag for the associated setting node. * Boolean flags are stored as XML attributes in the configuration file. * @param attr The name of the flag. * @param def The default value for the flag. * @returns The flag value, or @a def, in case the specified flag does not exist. */ bool flag(const QString& attr, bool def) const; /** * Set a global boolean flag for the associated setting node. * Boolean flags are stored as XML attributes in the configuration file. * @param attr The name of the flag. * @param value The value of the flag. */ void setFlag(const QString& attr, bool value); /** * @note This function is internal to the Settings class framework. Do not use * in client code. */ static void ensureExistence(QDomElement& node, QDomElement parent, const QString& name); #ifdef __SETTINGS_DEBUG void dump() const; #endif }; /** * @brief A group of settings. * * Client code can use instance of this class just like they were Settings objects. * The only external difference is that SettingGroup object can be implicitly * converted to bool to test their existence. * * SettingGroup can be accessed with the Settings member function @a group. * @sa Settings::group */ class SettingGroup : public Settings { QString m_name; QDomElement m_parent; protected: virtual QDomElement node() const; public: SettingGroup(const QDomElement& parent, const QString& name); /** * Check if the SettingGroup exists. */ operator bool() const { return !m_node.isNull(); } void remove(); }; /** * @brief A collection of setting nodes arranged as an associative container. * * A setting map is a collection of setting nodes, all having the same * parent node and the same name, and containing an inner node acting as * a key. * The following is an example of how the configuration node containing a * setting map may look like. The element name is "event" and the key name * is "name". * *
  * 
  * click
  *   action1
  * 
  * 
  *   double-click
  *   action2
  * 
  * 
* * Other than the key, each element of the map may contain any arbitrarily * nested nodes. * * To use a map, you simply access its elements by keys using the @a get member * function, which returns a Settings object associated to the specified element. * * Elements are cached as an STL map, which is kept in sync with the configuration * file, so read operation have the same complexity of the corresponding * STL operations (i.e. logarithmic). */ template class SettingMap { std::map m_map; protected: mutable QDomElement m_node; virtual QDomElement node() const { return m_node; } QString m_element; QString m_key; public: SettingMap(const QDomElement& node, const QString& element, const QString& key); virtual ~SettingMap() { } /** * @returns The number of elements in the map. */ uint size() const { return m_map.size(); } /** * Retrieve an element by key. * @param index The key of the element. * @returns The Settings object corresponding to the specified element. */ Settings get(const Key& index) const; /** * Insert an element into the map. * @param index The key of the element. * @returns An Settings object containing only the specified key. This object * can be used to add arbitrary content to the map element. */ Settings insert(const Key& index); /** * Clear the map, removing all its elements. */ void clear(); }; /** * @brief A collection of nodes, acting as a linear container. * * A setting array is like a setting map without a special key * node inside every element. * * The elements of a setting array can be only accessed by a numerical * index, just like an STL vector. * * SettingsArray provides a STL-like container interface with * random access constant iterators, so that the collection can be * used for STL algorithms acting read-only on it. */ class SettingArray { std::vector m_array; protected: mutable QDomElement m_node; virtual QDomElement node() const { return m_node; } QString m_element; public: typedef std::vector::const_iterator iterator; typedef std::vector::const_iterator const_iterator; SettingArray(const QDomElement& node, const QString& element); virtual ~SettingArray() { } /** * @returns The number of elements in the array. */ uint size() const { return m_array.size(); } /** * Retrieve an element by index. * @param index The (0-based) index of the element. * @returns A Settings object associated to the specified element. */ Settings get(int index) const; /** * Insert an element before the specified index. * @param index The (0-based) index of the element. * @returns An empty Settings object. This object can be used to add * arbitrary content to the array element. */ Settings insert(int index); /** * Append an element into the array. * @returns An empty Settings object. This object can be used to add * arbitrary content to the array element. */ Settings append(); /** * Clear the array, removing all its elements. */ void clear(); /** * @returns A random access iterator pointing to the beginning of the array. */ const_iterator begin() const { return m_array.begin(); } /** * @returns A random access iterator pointing past the end of the array. */ const_iterator end() const { return m_array.end(); } operator bool() const { return !m_node.isNull(); } }; // Implementation template typename ReturnType::type SettingRefBase::value(const T& def) const { if (element().isNull()) return def; else return SettingConversion::getValue(element(), node()); } template typename ReturnType::type SettingRefBase::value() const { return value(T()); } template typename ReturnType::wrapper SettingRefBase::operator|(const T& val) const { return value(val); } template void SettingRefBase::operator>>(T& out) const { out = value(out); } template typename ReturnType::wrapper SettingRef::operator|=(const T& val) { if (element().isNull()) return operator=(val); return value(val); } template typename ReturnType::wrapper SettingRef::operator=(const T& val) { if (element().isNull()) m_parent.appendChild(m_parent.ownerDocument().createElement(m_key)); element().appendChild(element().ownerDocument().createTextNode("")); SettingConversion::setValue(element(), node(), val); return val; } template SettingMap Settings::map(const QString& element, const QString& key) const { return SettingMap(node(), element, key); } template SettingMap Settings::newMap(const QString& element, const QString& key) const { SettingMap res(node(), element, key); res.clear(); return res; } template SettingMap::SettingMap(const QDomElement& node, const QString& element, const QString& key) : m_node(node) , m_element(element) , m_key(key) { if (!m_node.isNull()) { // scan all 'name' elements of node QDomNodeList elements = m_node.elementsByTagName(m_element); for (int i = 0; i < elements.size(); i++) { QDomElement el = elements.item(i).toElement(); // find the key inside el QDomElement key_element = el.firstChildElement(m_key); Key k = SettingConstRef(key_element).value(); // insert the corresponding Settings object into the map m_map[k] = el; } } } template Settings SettingMap::get(const Key& key) const { return m_map.find(key)->second; } template Settings SettingMap::insert(const Key& key) { typename std::map::const_iterator it = m_map.find(key); if (it != m_map.end()) return it->second; else { QDomElement el = node().ownerDocument().createElement(m_element); node().appendChild(el); Settings res = el; m_map[key] = res; res[m_key] = key; return res; } } template void SettingMap::clear() { QDomNode it = node().firstChild(); while (!it.isNull()) { QDomNode nextit = it.nextSibling(); QDomElement e = it.toElement(); if (!e.isNull() && e.tagName() == m_element) node().removeChild(e); it = nextit; } } #endif // SETTINGS_H tagua-1.0-alpha2/src/sprite.cpp000066400000000000000000000215671077523320400164370ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include #include #include #include "common.h" #include "point.h" #include "sprite.h" using namespace boost; struct ExplosionFragment { QPoint m_polygon[6]; int m_pcount; QPoint m_speed; ExplosionFragment() : m_pcount(0) {} }; /* inherit instead of typedef to ease forward declaration :) */ class SpriteExplosion : public std::vector { }; Sprite::Sprite(const QPixmap& pix, KGameCanvasAbstract* canvas, const QPoint& location) : KGameCanvasPixmap(pix, canvas) , m_pixmap(pix) , m_explode_step(0.0) , m_explosion(NULL) , m_rotation(0.0) , m_scale(1.0) #ifdef DEBUG_PIECE , m_dummy_opacity(255) , m_dummy_visible(false) #endif { moveTo(location); lower(); #ifdef DEBUG_PIECE update_from_dummy(); #endif } Sprite::~Sprite() { if(m_explosion) delete m_explosion; } Sprite* Sprite::duplicate() const { return new Sprite(pixmap(), canvas(), pos() ); } void Sprite::setThumb(const QImage& thumb) { kDebug() << "setting thumb"; QPixmap pix = m_pixmap; int width = pix.width() / 2; int height = pix.height() / 2; QPixmap thumb_pix = QPixmap::fromImage( thumb.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); { QPainter painter(&pix); painter.drawPixmap(pix.width() - width, 0, thumb_pix); } KGameCanvasPixmap::setPixmap(pix); } void Sprite::removeThumb() { KGameCanvasPixmap::setPixmap(m_pixmap); } void Sprite::setPixmap(const QPixmap& pix) { m_pixmap = pix; KGameCanvasPixmap::setPixmap(pix); } void Sprite::setMovementAnimation(const shared_ptr& animation) { m_movement_animation = animation; } weak_ptr Sprite::movementAnimation() const { return m_movement_animation; } /* void Sprite::setFadeAnimation(const shared_ptr& animation) { m_fade_animation = animation; } weak_ptr Sprite::fadeAnimation() const { return m_fade_animation; }*/ void Sprite::setExplosionStep(float f) { m_explode_step = f; changed(); } void Sprite::setupExplosion(Random& random) { if (m_explosion) { delete m_explosion; m_explosion = NULL; } m_explosion = createExplosion(random); } /* * this function generate many polygons that fill the image, + their random speeds * * Split points are some random point on the border (ordered accordin to the angle). * The generated polygons are created cutting from each split point to (according * to random's will) the center -or- a point in the mid way from the center to the * previous or next split point. */ SpriteExplosion* Sprite::createExplosion(Random& random) { SpriteExplosion* retv = new SpriteExplosion; int w = pixmap().width(); int h = pixmap().height(); float splits[40]; float splits_r[40]; float splits_i[40]; int split_side[40]; // the side of the image, 0 to 3 int split_start[40]; // -1 to 1 QPoint split_point[40]; QPoint split_start_point[40]; int num_splits = 0; if(w==0 || h==0) return retv; /* generate few subsequent angles */ Random::RealGenerator random_float = random.rand(0.4, 0.7); for(float s = 0; s < 2*M_PI-0.3; s += random_float()) { splits[num_splits] = s; splits_r[num_splits] = cos(s); splits_i[num_splits] = sin(s); num_splits++; } /* generate the random center and calculate the relative corners */ random_float = random.rand(0.4, 0.6); QPoint center(int(w * random_float()), int(h * random_float())); QPoint corners[4] = { -center, QPoint(w,0)-center, QPoint(w,h)-center, QPoint(0,h)-center }; /* for each split angle, find the size of the rect that contains the split point */ for(int i=0;i0 and <0 */ if(corners[j].x()*splits_i[i]-corners[j].y()*splits_r[i] >= 0 && corners[j1].x()*splits_i[i]-corners[j1].y()*splits_r[i] < 0 ) { split_side[i] = j; float fact = (corners[j].x()*corners[j1].y()-corners[j].y()*corners[j1].x())/ (splits_r[i]*(corners[j1].y()-corners[j].y())- splits_i[i]*(corners[j1].x()-corners[j].x())); float x = splits_r[i]*fact; float y = splits_i[i]*fact; split_point[i] = QPoint(int(x+0.5), int(y+0.5)); break; } } /* there should really be one :) */ Q_ASSERT(split_side[i] != -1); } /* generate the split points connections. Some will be connected with the center (0), others will be connected to a mid-way point of the previous or next points (-1/+1) */ Random::IntegerGenerator coin = random.rand(0, 1); Random::IntegerGenerator die3 = random.rand(0, 2); split_start[0] = 0; for(int i=1;i=num_splits ? 0 : r; if(r == i) split_start_point[i] = QPoint(); else split_start_point[i] = split_point[r] * random_float(); } random_float = random.rand(0.5, 1.2); for(int i=0;ipush_back(f); } return retv; } void Sprite::setRotation(float f) { m_rotation = f; changed(); } void Sprite::setScale(float f) { m_scale = f; changed(); } void Sprite::paint(QPainter* p) { QMatrix savem; /* if scale/rotate change the painter matrix */ if(m_rotation != 0.0 || m_scale != 1.0) { QRectF rect = pixmap().rect(); QPointF center(rect.width()*0.5, rect.height()*0.5); savem = p->matrix(); p->translate(center+pos()); p->rotate(m_rotation*180.0/M_PI); p->scale(m_scale, m_scale); p->translate(-center-pos()); } if(m_explosion) { p->setPen(Qt::NoPen); p->setBrush(pixmap()); p->translate(pos()); for(int i=0;isize());i++) { ExplosionFragment& f = (*m_explosion)[i]; QPoint delta = f.m_speed*m_explode_step; p->translate(delta); p->drawConvexPolygon(f.m_polygon, f.m_pcount); p->translate(-delta); } p->translate(-pos()); } else KGameCanvasPixmap::paint(p); if(m_rotation != 0.0 || m_scale != 1.0) p->setMatrix(savem); } QRect Sprite::rect() const { QRect retv; /* if exploding, set the rect to the bounding rect of the pieces */ if(m_explosion) { int x1=99999, x2=-99999, y1=99999, y2=-99999; for(int i=0;isize());i++) { ExplosionFragment& f = (*m_explosion)[i]; QPoint delta = f.m_speed*m_explode_step; for(int j=0;j (c) 2006 Maurizio Monge 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. */ #ifndef SPRITE_H #define SPRITE_H #include "kgamecanvas.h" #include "random.h" #include #include class QPoint; class QImage; class Animation; class FadeAnimation; class SpriteExplosion; #undef DEBUG_PIECE /** * @class Sprite * @brief The sprite of a piece. * * This class is a KGameCanvasPixmap that enables a few nifty * effects and keeps some piece-related information. */ class Sprite : public KGameCanvasPixmap { private: /** the piece id (for convenience) */ int m_id; /** the piece color (for convenience, could be -1) */ int m_color; /** the piece type (for convenience, could be -1) */ int m_type; QPixmap m_pixmap; /** the movement animation class */ boost::weak_ptr m_movement_animation; /** the step in the explostion */ float m_explode_step; /** the explostion object */ SpriteExplosion* m_explosion; /** rotation factor */ float m_rotation; /** scaling factor */ float m_scale; /** creates a new explosion object */ SpriteExplosion* createExplosion(Random& random); /** painting implementation */ virtual void paint(QPainter* p); /** returns the rectangle having to be painted */ virtual QRect rect() const; public: /** Constructor */ Sprite(const QPixmap& pix, KGameCanvasAbstract* canvas, const QPoint& location); virtual ~Sprite(); /** duplicates the piece */ Sprite* duplicate() const; void setThumb(const QImage& thumb); void removeThumb(); /** updates the pixmap */ /* NOTE for paolo: why virtual? */ virtual void setPixmap(const QPixmap&); /** set the movement animation */ void setMovementAnimation(const boost::shared_ptr& animation); /** returns the movement animation */ boost::weak_ptr movementAnimation() const; // void setFadeAnimation(const boost:shared_ptr& animation); // boost:weak_ptr fadeAnimation() const; /** set the explosion step (you have to call setupExplosion before) */ void setExplosionStep(float f); /** set the rotations factor */ void setRotation(float f); /** set the scaling factor */ void setScale(float f); /** prepares a new explosion animation */ void setupExplosion(Random& random); #ifdef DEBUG_PIECE int m_dummy_opacity; bool m_dummy_visible; void update_from_dummy(){ KGameCanvasItem::show(); KGameCanvasItem::setOpacity(m_dummy_visible ? 64+m_dummy_opacity*3/8 : 64); } /* those should be enough, even if they are not virtual, as Piece is never casted IIRC */ int opacity(){ return m_dummy_opacity; } int visible(){ return m_dummy_visible; } void setOpacity(int v){ m_dummy_opacity=v; update_from_dummy(); } void setVisible(bool v){ m_dummy_visible=v; update_from_dummy(); } void show(){ m_dummy_visible=true; update_from_dummy(); } void hide(){ m_dummy_visible=false; update_from_dummy(); } #endif }; #endif // SPRITE_H tagua-1.0-alpha2/src/tabwidget.cpp000066400000000000000000000023511077523320400170710ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "tabwidget.h" #include #include #include #include #include TabWidget::TabWidget(QWidget* parent) : KTabWidget(parent) { m_close = new QPushButton(this); m_close->setToolTip(i18n("Close the current tab")); m_close->setIcon(KIcon("tab-close")); m_close->adjustSize(); connect(m_close, SIGNAL(clicked()), this, SIGNAL(closeTab())); setCornerWidget(m_close); setTabBarHidden(true); } // void TabWidget::insertTab(int index, QWidget* widget, const QString& caption) { // KTabWidget::insertTab(index, widget, caption); // kDebug() << "showing"; // if (count() > 1) // setTabBarHidden(false); // } // // void TabWidget::removeTab(int index) { // KTabWidget::removeTab(index); // kDebug() << "hiding"; // if (count() <= 1) // setTabBarHidden(true); // } tagua-1.0-alpha2/src/tabwidget.h000066400000000000000000000013571077523320400165430ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef TABWIDGET_H #define TABWIDGET_H #include class QPushButton; class TabWidget : public KTabWidget { Q_OBJECT QPushButton* m_close; public: TabWidget(QWidget* parent); // void insertTab(int index, QWidget* widget, const QString& caption); // void removeTab(int index); Q_SIGNALS: void closeTab(); }; #endif // TABWIDGET_H tagua-1.0-alpha2/src/tagua.desktop000066400000000000000000000007071077523320400171120ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Tagua Name[cs]=Tagua Name[it]=Tagua Name[xx]=xxTaguaxx GenericName=Generic Board Game GenericName[cs]=Deskové hry GenericName[fr]=Jeux de pions Exec=tagua %i -caption "%c" Icon=tagua Type=Application Categories=Qt;KDE;Game;BoardGame; DocPath=tagua/tagua.html Comment=A generic board game application. Comment[cs]=Aplikace pro různé deskové hry. Comment[fr]=Divers jeux de pions (échecs, shogi, ...) Terminal=false tagua-1.0-alpha2/src/tagua.h000066400000000000000000000253561077523320400156770ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef LOWLEVEL_H #define LOWLEVEL_H #include #include #include #include #include "point.h" #include "usermove.h" #include "index.h" #include "option.h" #include "decoratedmove.h" #include "interactiontype.h" #include "turnpolicy.h" #include "fwd.h" class GraphicalAPI; class ICSAPI; class ActionCollection; /** * @file tagua.h * @brief Low level abstract classes used by the interface framework. * * This file includes definitions for abstract classes used from within * the interface framework to access variant details using dynamic time * polymorphism. * * One of the big problems with this approach is what I call 'lack of * functional dependency support' for runtime polymorphism. * What is missing is the ability to override a virtual member function * in a derived class changing its signature. Or better, it is possible * to only change its return type with a covariant type, while it would * often be useful to change any of its argument types with covariant or * even controvariant types. * For controvariant types, I foresee no problems, and all type checking * can be done statically (of course the method has to be dynamically * bound) as they are now. * When using covariant types, the compiler could insert appropriate * dynamic cast's and type checks in the calling code, when there's no * way to know the exact type of an argument at compile time. * * The file @ref tagua_wrapped.h tries to address this problem doing part * of the compiler's work. One exception is that type checking code * is inserted in a method wrapper, instead of the calling place, so * even calling a method of a noncasted instance would cause some * upcast / downcast overhead; this is negligible, though, because * that scenario is rather unlikely, since wrapped classes are always * kept in variables of abstract types. */ /** * @brief A superclass for all the piece classes. */ class AbstractPiece { public: typedef boost::shared_ptr Ptr; virtual ~AbstractPiece() { } /** * Piece equality. Return false if the second pointer * is null. */ virtual bool equals(const PiecePtr& other) const = 0; /** * Return a unique key for the piece. * Used to store pixmaps. */ virtual QString name() const = 0; /** * Create a deep copy of the piece. */ virtual PiecePtr clone() const = 0; }; /** * @brief A superclass for all the move classes. * * An abstract move is simply something that can serialize * itself either as SAN notation, or as coordinate notation. */ class AbstractMove { public: typedef boost::shared_ptr Ptr; virtual ~AbstractMove() { } /** * Serialize the move. * \param rep The type of representation to use. * \param ref A reference position. Its meaning is defined by the serializer. */ virtual QString toString(const QString& rep, const PositionPtr& ref) const = 0; /** * Convert the move to a normal user move. Used to * perform move highlighting. */ virtual NormalUserMove toUserMove() const = 0; /** * Checks if the two moves are equal. */ virtual bool equals(const MovePtr& other) const = 0; }; /** * @brief Superclass for pools * * A general interface for pools. */ class AbstractPool { public: typedef boost::shared_ptr Ptr; virtual ~AbstractPool() {} /** * \return the number of items in the pool */ virtual int size() = 0; /** * Inserts a piece in the pool, preferably at the position \a pref_index. * But the pool can be unpredictable and the piece can be placed at an arbitrary position. * \return the position at which the item was placed. */ virtual int insert(int pref_index, const PiecePtr& piece) = 0; /** * Gets the piece at the position \a index in the pool. */ virtual PiecePtr get(int index) = 0; /** * Removes the piece at the position \a index in the pool. * \return the removed piece. */ virtual PiecePtr take(int index) = 0; }; /** * @brief A superclass for all the position classes. * * A general interface for positions. It is used from within * the graphical framework to validate external input wrt * the played variant. */ class AbstractPosition { public: typedef boost::shared_ptr Ptr; typedef boost::shared_ptr PoolPtr; virtual ~AbstractPosition() { } /** * Return board size in logical units. This could be * static if C++ permitted virtual static functions. */ virtual Point size() const = 0; /** * Returns the text to be used for the border surrounding this position in a board */ virtual QStringList borderCoords() const = 0; /** * Create the starting piece setup. */ virtual void setup() = 0; /** * Retrieve the piece on square @a p. * Return a null pointer if that square is empty. */ virtual PiecePtr get(const Point& p) const = 0; /** * Set a piece on the board. */ virtual void set(const Point& p, const PiecePtr& piece) = 0; /** * \return an interface to modify the pool of the board relative to \a player */ virtual PoolPtr pool(int player) = 0; /** * Set a position pool, copying it from a given position. */ virtual void copyPoolFrom(const PositionPtr& pos) = 0; /** * \return 1 if the piece can be moved, -1 if could be moved in the future (premove), or else 0. */ virtual InteractionType movable(const TurnPolicy::Collection& test, const Point& p) const = 0; /** * \return 1 if this pool can be dropped, -1 if could be dropped in the future (premove), or else 0. */ virtual InteractionType droppable(const TurnPolicy::Collection& test, int) const = 0; /** * \return an id corresponding to the player * who is in turn. */ virtual int turn() const = 0; /** * Sets the player on move */ virtual void setTurn(int) = 0; /** * \return the player that just moved */ virtual int previousTurn() const = 0; /** * Switch to the next player. */ virtual void switchTurn() = 0; /** * Check move legality. Set move fields as needed. * Return whether the move is legal. * This function should return immediately if \a m * has already been tested. */ virtual bool testMove(const MovePtr& m) const = 0; /** * Execute move \a m. Assume that \a m is legal and tested. */ virtual void move(const MovePtr& m) = 0; /** * Create a deep copy of the position. */ virtual PositionPtr clone() const = 0; /** * Make the position equal to the given one. */ virtual void copyFrom(const PositionPtr&) = 0; /** * Tests if two positions are equal. */ virtual bool equals(const PositionPtr& p) const = 0; /** * Return a move from an algebraic notation, or a null pointer. */ virtual MovePtr getMove(const QString&) const = 0; /** * Return a string representing the current state of the position. */ virtual QString state() const = 0; /** * A piece somehow representing or related to the move * which has to be drawn by the interface. * Examples: * * for one click moves, the piece that would * appear on the square. * * for promotions in chesslike variants, the promoted * piece. * @note Return a null pointer if the move has no valid * piece hint defined. */ virtual PiecePtr moveHint(const MovePtr&) const = 0; /** * Variant introspection */ virtual QString variant() const = 0; /** * For debugging */ virtual void dump() const = 0; }; class AnimationGroup; /** * @brief An abstract superclass for all animator classes. * * An animator is a class which is given a difference between * a graphical and a logical position, and schedules an animation * which graphically does an update. * If the difference is due to a move, the animator tries to * create a smooth animation which could possibly work for many * chess-like variants, and then fills in the gaps with a direct * update. */ class AbstractAnimator { public: typedef boost::shared_ptr Ptr; virtual ~AbstractAnimator() { } /** * Sync the graphical position with the given position. */ virtual AnimationPtr warp(const PositionPtr&) = 0; /** * Animate forward syncing to the given position. */ virtual AnimationPtr forward(const PositionPtr&, const MovePtr&) = 0; /** * Animate back syncing to the given position. */ virtual AnimationPtr back(const PositionPtr&, const MovePtr&) = 0; }; class VariantInfo { public: virtual ~VariantInfo() { } virtual PositionPtr createPosition() = 0; virtual PositionPtr createCustomPosition(const OptList& l) = 0; virtual void forallPieces(class PieceFunction&) = 0; virtual int moveListLayout() const = 0; virtual AnimatorPtr createAnimator(GraphicalAPI* graphical_api) = 0; virtual MovePtr createNormalMove(const NormalUserMove&) = 0; virtual MovePtr createDropMove(const DropUserMove&) = 0; virtual MovePtr getVerboseMove(int turn, const class VerboseNotation&) const = 0; /** * \return if moves are done by just clicking */ virtual bool simpleMoves() = 0; /** * \return the name of the variant */ virtual QString name() const = 0; /** * \return the name of the theme proxy variant, ie the variant whose theme can be used * for the current one (for instance crazyhouse can use chess themes). */ virtual QString themeProxy() const = 0; /** * \return the (subvariant) options that can be specified for position creation, such as board size, etc */ virtual OptList positionOptions() const = 0; /** * \return The ICS API for this variant, or a null pointer, if the variant does not support * ICS (in that case a Dummy variant will be used). */ virtual ICSAPIPtr icsAPI() const = 0; /** * Setup a list of variant specific actions to be displayed on a game toolbar * and menu. */ virtual ActionCollection* actions() = 0; /** * Add variant specific information (i.e. promotionType) to a move. */ virtual void setupMove(NormalUserMove& m) const = 0; }; class VariantFactory { public: virtual ~VariantFactory() { } virtual VariantInfo* createVariant() const = 0; virtual QString name() const = 0; virtual QString themeProxy() const = 0; virtual bool hidden() const = 0; }; #endif // LOWLEVEL_H tagua-1.0-alpha2/src/tagua.lsm000066400000000000000000000007331077523320400162330ustar00rootroot00000000000000Begin3 Title: tagua -- Some description Version: 0.9.9 Entered-date: Description: Keywords: KDE Qt Author: Paolo Capriotti Maintained-by: Paolo Capriotti Home-page: Alternate-site: Primary-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils xxxxxx tagua-0.1.tar.gz xxx tagua-0.1.lsm Platform: Linux. Needs KDE Copying-policy: Custom End tagua-1.0-alpha2/src/tagua_it.ts000066400000000000000000000246701077523320400165700ustar00rootroot00000000000000 Form Form Maschera Round: Round: Time: Tempo: Result: Risultato: Increment: Incremento: Site: Luogo: Black rating: Punteggio del nero: Event: Evento: Black: Nero: White: Bianco: Date: Data: White rating: Punteggio del bianco: ECO: ECO: MainWindow &File &File &Edit &Modifica &Tools &Strumenti Actions Azioni Settings Impostazioni &New game... &Nuova partita... &Load game... &Carica partita... &Quit &Esci &Back &Indietro &Forward &Avanti Be&gin I&nizio &End &Fine &Connect &Connetti Test connect Connessione di prova &Disconnect &Disconnetti C&opy game &Copia partita P&aste game Inco&lla partita &Undo A&nnulla &Redo &Ripeti &Truncate &Tronca &Promote Variation &Promuovi variante &Edit position &Modifica posizione &Clear board &Cancella scacchiera &Set starting position &Imposta posizione iniziale &Paste position Inc&olla posizione &Copy position Copi&a posizione Promote to &queen Promuovi a &donna Promote to &rook Promuovi a &torre Promote to &bishop Promuovi ad &alfiere Promote to k&night Promuovi a &cavallo &Flip view Inverti &visuale Toggle &console Mostra / nascondi &console Highlight preferences... Preferenze evidenziazione... E&ngines &Motori Play as &white Gioca con il &bianco Play as &black Gioca con il &nero &Analyze &Analisi You have specified a folder Hai scelto una directory The specified file does not exist Il file scelto non esiste You do not have read permission to this file. Non hai permesso di lettura su questo file. Open PGN file Apri file PGN NewGameDialog New game Nuova partita &Variant: &Variante: &Starting position &Imposta posizione iniziale C&urrent &Corrente Alt+U Alt+U S&tandard S&tandard Alt+T Alt+T &Help &Aiuto F1 F1 &OK &OK C&ancel A&nnulla Alt+A Alt+A PrefHighlight Dialog Dialogo Pattern Modello Bold Grassetto Italic Corsivo Use this box to test your regular expression Usa questa casella per provare la tua espressione regolare Add Aggiungi Remove Cancella Up Muovi in alto Down Muovi in basso OK OK Cancel Annulla QuickConnect Quick Connect Connessione rapida GroupBox Gruppo &Password: &Password: &Username: &Nome utente: &Store password on this computer &Conserva la password su questo computer Alt+S Alt+S Ser&ver: Ser&ver: ICS &host: &Host ICS: ICS p&ort: &Porta: &OK &OK &Cancel A&nnulla tagua-1.0-alpha2/src/taguaui.rc000066400000000000000000000026241077523320400164030ustar00rootroot00000000000000 &Edit &Game &View Game Toolbar tagua-1.0-alpha2/src/themeinfo.cpp000066400000000000000000000052741077523320400171040ustar00rootroot00000000000000/* Copyright (c) 2006-2007 Paolo Capriotti (c) 2006-2007 Maurizio Monge 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. */ #include "themeinfo.h" #include #include #include #include #include #include "foreach.h" #include "settings.h" ThemeInfo::operator bool() const { return !file_name.isEmpty(); } void ThemeInfo::save(Settings& s) { s["file-name"] = file_name; s["name"] = name; s["description"] = description; { SettingArray s_variants = s.group("variants").newArray("variant"); foreach (QString v, variants) { Settings s_var = s_variants.append(); s_var["name"] = v; } } s["last-modified"] = last_modified.toString(); s["desktop-file"] = desktopFile; } ThemeInfo ThemeInfo::fromSettings(const Settings& s) { ThemeInfo res; s["file-name"] >> res.file_name; s["name"] >> res.name; s["description"] >> res.description; s["desktop-file"] >> res.desktopFile; res.last_modified = QDateTime::fromString(s["last-modified"].value()); SettingArray variants = s.group("variants").array("variant"); foreach (Settings var, variants) { res.variants.append(var["name"].value()); } return res; } ThemeInfo ThemeInfo::fromDesktopFile(const QString& desktop_file) { ThemeInfo res; QFileInfo desktop_file_info(desktop_file); res.desktopFile = desktop_file; if (!KDesktopFile::isDesktopFile(desktop_file)) { return res; } KDesktopFile theme(desktop_file); KConfigGroup themeData = theme.desktopGroup(); res.name = theme.readName(); res.description = theme.readComment(); res.description.replace("|", "\n"); res.variants = themeData.readEntry("X-Tagua-Variants").split(QRegExp("\\s*,\\s*")); res.file_name = themeData.readEntry("X-Tagua-Script"); if (res.file_name.isEmpty()) { // use a file with the same name as the .desktop, but with .lua extension res.file_name = desktop_file; res.file_name.replace(QRegExp("\\.desktop$"), ".lua"); } else { if (!QDir::isAbsolutePath(res.file_name)) { // the file is relative to the .desktop directory res.file_name = QDir(desktop_file_info.path()).filePath(res.file_name); } } res.last_modified = desktop_file_info.lastModified(); return res; } uint qHash(const ThemeInfo& info) { return qHash(info.file_name); } bool ThemeInfo::operator==(const ThemeInfo& info) const { return desktopFile == info.desktopFile; } tagua-1.0-alpha2/src/themeinfo.h000066400000000000000000000016271077523320400165470ustar00rootroot00000000000000/* Copyright (c) 2006-2007 Paolo Capriotti (c) 2006-2007 Maurizio Monge 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. */ #ifndef THEMEINFO_H #define THEMEINFO_H #include #include class Settings; struct ThemeInfo { QString file_name; QString name; QString description; QString desktopFile; QStringList variants; QDateTime last_modified; operator bool() const; bool operator==(const ThemeInfo& info) const; void save(Settings& s); static ThemeInfo fromSettings(const Settings& s); static ThemeInfo fromDesktopFile(const QString& f); }; uint qHash(const ThemeInfo& info); #endif // THEMEINFO_H tagua-1.0-alpha2/src/turnpolicy.cpp000066400000000000000000000025621077523320400173330ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #include "turnpolicy.h" namespace TurnPolicy { Abstract::~Abstract() { } class Simple : public Abstract { bool m_value; public: Simple(bool value) : m_value(value) { } bool check() const { return m_value; } }; Premove::~Premove() { } bool Collection::operator()(int turn) const { Policies::const_iterator it = m_policies.find(turn); if (it == m_policies.end()) { return false; } else { return it->second->check(); } } void Collection::setPolicy(int turn, const PolicyPtr& policy) { m_policies[turn] = policy; } void Collection::setSimplePolicy(int turn, bool value) { setPolicy(turn, boost::shared_ptr(new Simple(value))); } void Collection::clear() { m_policies.clear(); m_premove.reset(); } bool Collection::premove() const { return m_premove ? m_premove->check() : false; } void Collection::setPremovePolicy(const PremovePolicyPtr& policy) { m_premove = policy; } } tagua-1.0-alpha2/src/turnpolicy.h000066400000000000000000000027651077523320400170050ustar00rootroot00000000000000/* Copyright (c) 2007 Paolo Capriotti (c) 2007 Maurizio Monge 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. */ #ifndef TURNPOLICY_H #define TURNPOLICY_H #include #include #include "export.h" namespace TurnPolicy { /** * An abstract class encapsulating the user ability * to move in a given turn. */ class Abstract { public: virtual ~Abstract(); virtual bool check() const = 0; }; /** * Premove policy. Used to check whether premoving is allowed. * It is a global policy. */ class Premove { public: virtual ~Premove(); virtual bool check() const = 0; }; class TAGUA_EXPORT Collection { typedef boost::shared_ptr PolicyPtr; typedef std::map Policies; typedef boost::shared_ptr PremovePolicyPtr; Policies m_policies; PremovePolicyPtr m_premove; public: bool operator()(int turn) const; void setPolicy(int turn, const PolicyPtr& policy); void setSimplePolicy(int turn, bool value); void clear(); void setPremovePolicy(const PremovePolicyPtr& policy); bool premove() const; }; } typedef TurnPolicy::Collection TurnTest; #endif // TURNPOLICY_H tagua-1.0-alpha2/src/ui.cpp000066400000000000000000000117171077523320400155420ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include #include #include #include #include #include "ui.h" #include "controllers/abstract.h" #include "graphicalgame.h" using namespace boost; #define SYNC_ACTION(NAME, ENUM) \ m_ui->m_actions->action(NAME)->setEnabled(state & GraphicalGame::ENUM) class UIActionStateObserver : public ActionStateObserver { const UI* m_ui; Controller* m_controller; public: UIActionStateObserver(const UI* ui, const shared_ptr& controller) : m_ui(ui) , m_controller(controller.get()) { } virtual void notifyActionStateChange(GraphicalGame::ActionState state) { // check that the associated controller is active if (m_ui->controller().get() == m_controller) { SYNC_ACTION("begin", BEGIN); SYNC_ACTION("back", BACK); SYNC_ACTION("forward", FORWARD); SYNC_ACTION("end", END); SYNC_ACTION("edit_undo", UNDO); SYNC_ACTION("edit_redo", REDO); } } }; #undef SYNC_ACTION UI::UI(KActionCollection* actions) : m_current_tab(NULL) , m_actions(actions) { } boost::shared_ptr& UI::controller() { Q_ASSERT(m_current_tab); boost::shared_ptr& res = m_controller[m_current_tab]; Q_ASSERT(res); return res; } boost::shared_ptr UI::controller() const { Q_ASSERT(m_current_tab); ControllerMap::const_iterator it = m_controller.find(m_current_tab); Q_ASSERT(it != m_controller.end()); return it->second; } void UI::addController(QWidget* w, const shared_ptr& controller) { m_current_tab = w; setController(controller); } void UI::setController(const shared_ptr& controller) { Q_ASSERT(m_current_tab); m_controller[m_current_tab] = controller; controller->setUI(*this); } void UI::removeController(QWidget* w) { controller()->end(); kDebug() << "removing controller " << w; m_controller.erase(w); } void UI::setCurrentTab(QWidget* w) { m_current_tab = w; controller()->activate(); } bool UI::undo() { controller()->undo(); return true; } bool UI::redo() { controller()->redo(); return true; } bool UI::truncate() { controller()->truncate(); return true; } bool UI::promoteVariation() { controller()->promoteVariation(); return true; } bool UI::back() { return controller()->back(); } bool UI::forward() { return controller()->forward(); } void UI::gotoFirst() { controller()->gotoFirst(); } void UI::gotoLast() { controller()->gotoLast(); } void UI::pgnCopy() { QClipboard* cb = QApplication::clipboard(); cb->setText(currentPGN()); } QString UI::currentPGN() { return controller()->save(); } void UI::pgnPaste() { QClipboard* cb = QApplication::clipboard(); pgnPaste(cb->text()); } void UI::pgnPaste(const QString&) { //controller()->loadPGN(pgn); } void UI::pgnPaste(const PGN& pgn) { controller()->loadPGN(pgn); } void UI::clearBoard() { controller()->clearBoard(); } void UI::setStartingPosition() { controller()->setStartingPosition(); } void UI::copyPosition() { QClipboard* cb = QApplication::clipboard(); cb->setText(controller()->fen()); } void UI::pastePosition() { QClipboard* cb = QApplication::clipboard(); controller()->setFEN(cb->text()); } void UI::setTurn(int turn) { controller()->setTurn(turn); } AbstractPosition::Ptr UI::position() const { return controller()->currentPosition(); } void UI::createCtrlAction() { controller()->createCtrlAction(); } void UI::destroyCtrlAction() { controller()->destroyCtrlAction(); } ActionCollection* UI::variantActions() const { return controller()->variantActions(); } EntityToken UI::addPlayingEngine(int side, const shared_ptr& engine) { return controller()->addPlayingEngine(side, engine); } // EntityToken UI::addAnalysingEngine(const shared_ptr& engine) { // return controller()->addAnalysingEngine(engine); // } void UI::removeEntity(const EntityToken& token) { controller()->removeEntity(token); } void UI::end() { controller() = controller()->end(); } void UI::detach() { controller()->detach(); } QString UI::currentVariant() const { return controller()->variant(); } void UI::reloadSettings() { for (ControllerMap::iterator it = m_controller.begin(), end = m_controller.end(); it != end; ++it) { it->second->reloadSettings(); } } shared_ptr UI::createActionStateObserver(const shared_ptr& controller) const { return shared_ptr( new UIActionStateObserver(this, controller)); } KUrl UI::url() const { return controller()->url(); } void UI::setUrl(const KUrl& url) { controller()->setUrl(url); } tagua-1.0-alpha2/src/ui.h000066400000000000000000000101751077523320400152040ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef UI_H #define UI_H #include #include #include #include "common.h" #include "controllers/entitytoken.h" #include "tagua.h" #include class Controller; class Engine; class ActionCollection; class KActionCollection; class ActionStateObserver; class PGN; /** * @brief Utility class to handle GUI actions. * * An instance of UI is owned by MainWindow, and every GUI action * is connected to a slot of UI. * A UI instance maintains a correspondence between Tagua tabs and * associated controllers. Besides, UI knows the active tab (hence * controller) and directs all user interaction to it. * Whenever a new tab is created, the corresponding controller is * added to the association, and its setUI member function is called, * so that it can setup all the observers. * * To add a new tab <-> controller association, use the addController * member function. * If you want to replace the current controller, use setController. * Both functions assume that the controller is new, hence initialize * it via setUI. */ class UI : public QObject { Q_OBJECT typedef std::map > ControllerMap; ControllerMap m_controller; QWidget* m_current_tab; boost::shared_ptr& controller(); boost::shared_ptr controller() const; KActionCollection* m_actions; KUrl m_url; friend class UIActionStateObserver; public: /** * Constructor. * \param actions The action collection associated to this UI instance. * This will be used to enable/disable actions according * to notifications coming from the controller. */ UI(KActionCollection* actions); /** * Add a new tab <-> controller association. * The controller is assumed to be new, and it is initialized by calling * its setUI member function. */ void addController(QWidget* tab, const boost::shared_ptr&); /** * Just like addController, but replace the current controller instead * of creating a new association. The old controller is no longer referenced * by UI, so it will be destroyed, unless other objects keep it alive. */ void setController(const boost::shared_ptr& controller); /** * Remove a controller. The controller will no longer be referenced by * UI, so it will be destroyed, unless other objects keep it alive. */ void removeController(QWidget* tab); /** * Create an action state observer that reacts to action state * updates by enabling / disabling the corresponding actions. * \sa ActionStateObserver */ boost::shared_ptr createActionStateObserver(const boost::shared_ptr&) const; public Q_SLOTS: /** * Change the current tab and associated controller. */ void setCurrentTab(QWidget* tab); bool undo(); bool redo(); bool truncate(); bool promoteVariation(); bool back(); bool forward(); void gotoFirst(); void gotoLast(); void setTurn(int); void createCtrlAction(); void destroyCtrlAction(); ActionCollection* variantActions() const; void pgnCopy(); void pgnPaste(); void pgnPaste(const QString&); void pgnPaste(const PGN& pgn); QString currentPGN(); // editing void clearBoard(); void setStartingPosition(); void copyPosition(); void pastePosition(); AbstractPosition::Ptr position() const; EntityToken addPlayingEngine(int side, const boost::shared_ptr& engine); // EntityToken addAnalysingEngine(const boost::shared_ptr& engine); void removeEntity(const EntityToken& token); void end(); void detach(); QString currentVariant() const; void reloadSettings(); KUrl url() const; void setUrl(const KUrl& url); }; #endif tagua-1.0-alpha2/src/ui/000077500000000000000000000000001077523320400150275ustar00rootroot00000000000000tagua-1.0-alpha2/src/ui/gametags.ui000066400000000000000000000100711077523320400171550ustar00rootroot00000000000000 Form 0 0 140 463 Form 9 6 Round: Time: Result: Increment: Site: Black rating: Event: Black: White: Date: White rating: ECO: Qt::Vertical 20 40 tagua-1.0-alpha2/src/ui/newgamedialog.ui000066400000000000000000000061401077523320400201720ustar00rootroot00000000000000 NewGameDialog 0 0 263 108 New game true 6 0 0 0 0 &Variant: m_variant Qt::Horizontal 20 10 1 0 Create in new &tab true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::NoButton|QDialogButtonBox::Ok qPixmapFromMimeSource buttonBox accepted() NewGameDialog accept() 310 349 286 198 buttonBox rejected() NewGameDialog reject() 211 349 176 230 tagua-1.0-alpha2/src/ui/pref_board.ui000066400000000000000000000270561077523320400175030ustar00rootroot00000000000000 PrefBoard 0 0 403 467 Form 0 6 5 5 0 2 Qt::StrongFocus &Animations true 9 6 &Transformations &Explosions &Movements &Fading 0 6 Rough (little CPU usage) Qt::AlignCenter sliderSmoothness 32 4 Qt::Horizontal Smooth (high CPU usage) Qt::AlignCenter sliderSmoothness Animation s&moothness: Qt::AlignCenter sliderSmoothness 0 6 Slow sliderSpeed 32 1 4 Qt::Horizontal Fast sliderSpeed Animation s&peed: Qt::AlignCenter sliderSpeed 0 6 Qt::Horizontal 31 20 7 5 15 0 &Max sequence length: spinSequenceMax 9999 2 Animate move &sequences true 5 5 0 1 Qt::StrongFocus &Border true 9 6 &Color colorBorder &Text Color colorBorderText 1 0 1 0 Custom &font: true Qt::StrongFocus KColorButton QPushButton
kcolorbutton.h
KFontRequester QWidget
kfontrequester.h
groupAnimations checkMovements checkFading checkExplosions checkTransformations checkSequence spinSequenceMax sliderSpeed sliderSmoothness groupBorder colorBorder colorBorderText checkBorderFont fontBorder checkBorderFont toggled(bool) fontBorder setEnabled(bool) 228 442 374 444 checkSequence toggled(bool) label_9 setEnabled(bool) 158 113 151 139 checkSequence toggled(bool) spinSequenceMax setEnabled(bool) 376 112 404 143
tagua-1.0-alpha2/src/ui/pref_engines.ui000066400000000000000000000122641077523320400200370ustar00rootroot00000000000000 PrefEngines 0 0 400 329 Engines 9 6 Engine list 9 6 0 6 Qt::Vertical 20 40 Qt::Vertical 382 16 Engine properties 9 6 0 6 &Path: m_path 0 6 &Type: m_type XBoard UCI Tagua (text) Tagua (D-BUS) 0 6 &Work dir: m_workdir KUrlRequester QWidget
kurlrequester.h
m_type m_add_engine m_remove_engine
tagua-1.0-alpha2/src/ui/pref_highlight.ui000066400000000000000000000202071077523320400203520ustar00rootroot00000000000000 PrefHighlight 0 0 515 363 Dialog 9 6 Qt::Horizontal 0 6 0 6 Pattern 0 6 0 6 Bold Italic Qt::Horizontal 40 20 Qt::Vertical 20 52 0 6 Sans Serif 8 50 true false false false Use this box to test your regular expression Qt::Vertical 20 51 0 6 0 6 Add Remove Qt::Horizontal 20 20 0 6 Up Down 0 6 Qt::Horizontal 131 31 OK Cancel KColorButton QPushButton
kcolorbutton.h
m_ok clicked() PrefHighlight accept() 423 350 96 254 m_cancel clicked() PrefHighlight reject() 504 350 179 282
tagua-1.0-alpha2/src/ui/pref_movelist.ui000066400000000000000000000227721077523320400202560ustar00rootroot00000000000000 PrefMoveList 0 0 434 431 Form 0 6 5 5 0 1 Qt::StrongFocus &Animations true 9 6 0 6 Rough (little CPU usage) Qt::AlignCenter sliderSmoothness 32 4 Qt::Horizontal Smooth (high CPU usage) Qt::AlignCenter sliderSmoothness Animation s&peed: Qt::AlignCenter sliderSpeed 0 6 Slow sliderSpeed 32 4 Qt::Horizontal Fast sliderSpeed &Movements &Fading &Smooth highlighting Animation s&moothness: Qt::AlignCenter sliderSmoothness 5 5 0 1 &Colors and fonts 9 6 C&omments color: colorComments 1 0 1 0 Cus&tom comments font: true C&ustom moves font: true S&elected move color: colorSelected Qt::StrongFocus Qt::StrongFocus KColorButton QPushButton
kcolorbutton.h
KFontRequester QWidget
kfontrequester.h
groupAnimations checkMovements checkFading checkHighlighting sliderSpeed sliderSmoothness colorSelected colorComments checkMovesFont fontMoves checkCommentsFont fontComments checkMovesFont toggled(bool) fontMoves setEnabled(bool) 269 360 359 364 checkCommentsFont toggled(bool) fontComments setEnabled(bool) 282 397 370 397
tagua-1.0-alpha2/src/ui/pref_theme.ui000066400000000000000000000031051077523320400175030ustar00rootroot00000000000000 PrefTheme 0 0 448 458 6 9 9 9 9 6 0 0 0 0 &Variant: comboVariant comboVariant tagua-1.0-alpha2/src/ui/pref_theme_page.ui000066400000000000000000000020501077523320400204750ustar00rootroot00000000000000 PrefThemePage 0 0 430 467 ... m_check m_list m_resetButton tagua-1.0-alpha2/src/ui/preferences.ui000066400000000000000000000034351077523320400176740ustar00rootroot00000000000000 Preferences 0 0 473 367 Change Tagua Settings 9 6 Qt::Horizontal QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok KPageWidget QWidget
kpagewidget.h
buttonBox accepted() Preferences accept() 269 346 271 366 buttonBox rejected() Preferences reject() 425 350 425 364
tagua-1.0-alpha2/src/ui/quickconnect.ui000066400000000000000000000206261077523320400200620ustar00rootroot00000000000000 QuickConnect 0 0 345 459 Quick Connect false 9 6 &Login 9 6 QLineEdit::Password &Password: editPassword &Username: editUsername &Store password on this computer Alt+S Ser&ver: 9 6 ICS p&ort: spinPort 65536 ICS &host: editHost Qt::StrongFocus &Timeseal true true 9 6 ... &File Path: editTimeseal Use &custom command line arguments Alt+S true Qt::Vertical 327 21 0 6 Qt::Horizontal QSizePolicy::Expanding 20 20 &OK true true &Cancel true qPixmapFromMimeSource editUsername editPassword chkStore editHost spinPort groupTimeseal editTimeseal buttonTimesealPath chkTimesealCmd editTimesealCmd buttonOk buttonCancel buttonCancel clicked() QuickConnect reject() 303 506 20 20 buttonOk clicked() QuickConnect accept() 217 506 20 20 chkTimesealCmd toggled(bool) editTimesealCmd setEnabled(bool) 84 382 85 406 tagua-1.0-alpha2/src/usermove.h000066400000000000000000000017201077523320400164300ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef USERMOVE_H #define USERMOVE_H #include #include "fwd.h" #include "point.h" struct NormalUserMove { Point from; Point to; int promotionType; NormalUserMove(const Point& from, const Point& to) : from(from) , to(to) , promotionType(-1) { } bool valid() const { return from != Point::invalid() && to != Point::invalid(); } }; struct DropUserMove { int pool; int piece_index; Point to; DropUserMove(int pool, int piece_index, const Point& to) : pool(pool) , piece_index(piece_index) , to(to) { } }; #endif //USERMOVE_H tagua-1.0-alpha2/src/variants.cpp000066400000000000000000000036071077523320400167530ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "variants.h" using namespace HLVariant; #define DECLARE_FACTORY(VARIANT) \ namespace HLVariant { \ namespace VARIANT { \ VariantFactory* createFactory(); \ } \ } DECLARE_FACTORY(Chess) DECLARE_FACTORY(Minichess5) DECLARE_FACTORY(Crazyhouse) DECLARE_FACTORY(Dummy) DECLARE_FACTORY(Shogi) DECLARE_FACTORY(MiniShogi) DECLARE_FACTORY(ShoShogi) DECLARE_FACTORY(ToriShogi) #undef DECLARE_FACTORY Variants::Variants() { addFactory(Chess::createFactory()); addFactory(Minichess5::createFactory()); addFactory(Crazyhouse::createFactory()); addFactory(Dummy::createFactory()); addFactory(Shogi::createFactory()); addFactory(MiniShogi::createFactory()); addFactory(ShoShogi::createFactory()); addFactory(ToriShogi::createFactory()); } Variants& Variants::instance() { static Variants inst; return inst; } VariantFactory* Variants::getFactory(const QString& name) const { Factories::const_iterator it = m_factories.find(name); if (it != m_factories.end()) { return it->second; } return 0; } VariantPtr Variants::get(const QString& name) const { VariantFactory* factory = getFactory(name); return factory ? VariantPtr(factory->createVariant()) : VariantPtr(); } void Variants::addFactory(VariantFactory* factory) { m_factories[factory->name()] = factory; } QStringList Variants::all() const { QStringList s; for (Factories::const_iterator end = m_factories.end(), it = m_factories.begin(); it != end; ++it) { if (!it->second->hidden()) s << it->first; } return s; } tagua-1.0-alpha2/src/variants.h000066400000000000000000000021071077523320400164120ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef VARIANTS_H #define VARIANTS_H #include #include #include "tagua.h" #include "fwd.h" class Variants { class case_comparer { public: bool operator()(const QString& a, const QString& b) const { return a.compare(b, Qt::CaseInsensitive) < 0; } }; typedef std::map Factories; Factories m_factories; Variants(); public: VariantPtr get(const QString& name) const; VariantFactory* getFactory(const QString& name) const; void addFactory(VariantFactory* factory); /** * \return a list of all non-hidden variants. */ QStringList all() const; static Variants& instance(); }; #endif // VARIANTS_H tagua-1.0-alpha2/src/weakset.h000066400000000000000000000110331077523320400162240ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef WEAK_SET #define WEAK_SET #include #include #ifdef WEAK_SET_DEBUG #include using namespace std; #endif // WEAK_SET_DEBUG /** * @brief An implementation of a set of weak references. * * weak_set is a set of weak_pointers which are automatically collected * and removed when the pointed object is destroyed. */ template class weak_set { typedef std::list > inner_set; typedef typename inner_set::iterator inner_iterator; friend class iterator; mutable inner_set m_set; public: class iterator { friend class weak_set; mutable inner_iterator m_it; boost::shared_ptr obj; // this prevents the stored object from being collected weak_set& m_parent; iterator(const inner_iterator& it, weak_set& parent) : m_it(it) , m_parent(parent) { skip_garbage(); } void skip_garbage() { #ifdef WEAK_SET_DEBUG kDebug() << "skipping garbage" << endl; uint c = 0; #endif // WEAK_SET_DEBUG while (true) { if (m_it == m_parent.m_set.end()) break; boost::weak_ptr wp = *m_it; if (obj = wp.lock()) break; // while (m_it != m_parent.m_set.end() && !(obj = (*m_it).lock())) { #ifdef WEAK_SET_DEBUG kDebug() << "iteration " << c++ << endl; #endif // WEAK_SET_DEBUG // the current reference is dangling: // remove it from the list and get the next one #ifdef WEAK_SET_DEBUG kDebug() << "dangling reference! removing it" << endl; #endif // WEAK_SET_DEBUG m_it = m_parent.m_set.erase(m_it); } // at this point either // m_it < m_parent.m_set.end() _and_ obj is a valid shared_ptr // or // m_it == m_parent.m_set.end() #ifdef WEAK_SET_DEBUG if (obj) kDebug() << "no iteration done: uses = " << obj.use_count() << ", obj = " << *obj << endl; else kDebug() << "we're at the end" << endl; #endif // WEAK_SET_DEBUG } public: /** * Check two iterators for equality. */ bool operator==(const iterator& other) { return m_it == other.m_it; } /** * Equivalent to !operator==. */ bool operator!=(const iterator& other) { return !operator==(other); } /** * Pre-increment operator. Modifity the iterator so * that it points to the next valid object. * @return The incremented iterator. */ iterator& operator++() { #ifdef WEAK_SET_DEBUG kDebug() << "incrementing" << endl; #endif // WEAK_SET_DEBUG ++m_it; obj.reset(); skip_garbage(); #ifdef WEAK_SET_DEBUG kDebug() << "done incrementing" << endl; #endif // WEAK_SET_DEBUG return *this; } /** * Post-increment operator. Modifity the iterator so * that it points to the next valid object. * @return The iterator before being incremented. */ // iterator operator++(int) { return iterator(m_it++, m_parent); } /** * @return a pointer to the stored object. * @note This function is guaranteed to return a valid * non-null pointer if the iterator is valid * and less than the past-the-end iterator. */ T* get() { return obj.get(); } /** * @return a pointer to the stored object. * @sa get */ T* operator->() { return get(); } /** * @return a reference to the stored object. * @sa get */ T& operator*() { return *get(); } }; /** * Add an object to the container. * @return an iterator referring to the newly inserted object. * @note No iterator is invalidated by an insert operation. */ iterator insert(const boost::shared_ptr& x) { return iterator(m_set.insert(m_set.end(), x), *this); } /** * @return an iterator pointing to the first element of * the container, which can be used for iterating. */ iterator begin() { return iterator(m_set.begin(), *this); } /** * @return a past-the-end iterator. */ iterator end() { return iterator(m_set.end(), *this); } }; #endif // WEAK_SET tagua-1.0-alpha2/src/xboardengine.cpp000066400000000000000000000126651077523320400175750ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #include "xboardengine.h" #include #include #include #include "enginenotifier.h" #include "foreach.h" using namespace boost; QRegExp XBoardEngine::m_move_pattern("My move is: (.*)"); XBoardEngine::XBoardEngine(const QString& path, const QStringList& arguments) : Engine(path, arguments) , m_analysing(false) { // set default features m_features.ping = false; m_features.setboard = false; m_features.playother = false; m_features.san = false; m_features.usermove = false; m_features.time = true; m_features.draw = true; m_features.sigint = true; m_features.sigterm = true; m_features.reuse = true; m_features.analyze = true; m_features.colors = true; m_features.ics = false; m_features.name = false; m_features.pause = false; m_features.myname = QFileInfo(m_path).baseName(); connect(this, SIGNAL(receivedCommand(const QString&)), this, SLOT(processCommand(const QString&))); } XBoardEngine::~XBoardEngine() { kDebug() << "[debug] destroying engine"; stop(); m_engine.kill(); } void XBoardEngine::initializeEngine() { // set up in xboard mode sendCommand("xboard"); // we're using xboard protocol version 2 sendCommand("protover 2"); // don't flood me! sendCommand("nopost"); } void XBoardEngine::reset() { sendCommand("new"); // start a new game sendCommand("force"); // do not think } void XBoardEngine::play() { sendCommand("go"); // start playing } void XBoardEngine::stop() { sendCommand("quit"); if (m_features.sigterm) m_engine.kill(); } void XBoardEngine::processCommand(const QString& command) { QStringList arg_list = command.split(QRegExp("\\s+")); QString cmd = arg_list.takeFirst(); if (cmd == "feature") { QRegExp feature("(\\S+)=(\\S+)"); foreach (QString arg, arg_list) { if (feature.indexIn(arg) == 0) { bool rejected = false; QString key = feature.cap(1); QString value = feature.cap(2); if (key == "ping") m_features.ping = value == "1"; else if (key == "setboard") m_features.setboard = value == "1"; else if (key == "playother") m_features.playother = value == "1"; else if (key == "san") m_features.san = value == "1"; else if (key == "usermove") m_features.usermove = value == "1"; else if (key == "time") m_features.time = value == "1"; else if (key == "draw") m_features.draw = value == "1"; else if (key == "sigint") m_features.sigint = value == "1"; else if (key == "sigterm") m_features.sigterm = value == "1"; else if (key == "reuse") m_features.reuse = value == "1"; else if (key == "analyze") m_features.analyze = value == "1"; else if (key == "myname") m_features.myname = value.mid(1, value.length() - 2); else if (key == "variants") m_features.variants = value.mid(1, value.length() - 2); else if (key == "colors") m_features.colors = value == "1"; else if (key == "ics") m_features.ics = value == "1"; else if (key == "name") m_features.name = value == "1"; else if (key == "pause") m_features.pause = value == "1"; else if (key == "done") m_features.done = value == "1"; else rejected = true; if (rejected) sendCommand("rejected " + key); else sendCommand("accepted " + key); } } } else if (cmd == "move") { if (shared_ptr notifier = m_notifier.lock()) notifier->notifyEngineMove(arg_list[0]); } else if (m_move_pattern.indexIn(command) == 0) { if (shared_ptr notifier = m_notifier.lock()) notifier->notifyEngineMove(m_move_pattern.cap(1)); } } void XBoardEngine::sendMove(AbstractMove::Ptr move, AbstractPosition::Ptr ref) { QString move_str = move->toString(m_features.san ? "compact" : "simple", ref); if (m_features.usermove) move_str = "usermove " + move_str; sendCommand(move_str); } void XBoardEngine::backUp(AbstractPosition::Ptr) { sendCommand("undo"); } void XBoardEngine::startAnalysis() { sendCommand("post"); sendCommand("analyze"); m_analysing = true; } void XBoardEngine::stopAnalysis() { sendCommand("exit"); m_analysing = false; } void XBoardEngine::setBoard(AbstractPosition::Ptr, int, int) { #if 0 if (m_features.setboard) { sendCommand(QString("setboard %1").arg(pos->fen(halfmove, fullmove))); } else { // this is pretty meaningless for generic variants if (pos->turn() != 0) { sendCommand("new"); sendCommand("a2a3"); } sendCommand("edit"); sendCommand("#"); Point size = pos->size(); for (int i = 0; i < size.x; i++) { for (int j = 0; j < size.y; j++) { Point p(i, j); AbstractPiece::Ptr piece = pos->get(p); if (piece) sendCommand(QString("%1%2") .arg(piece->type()) .arg(p.toString(8))); } } sendCommand("."); } #endif } tagua-1.0-alpha2/src/xboardengine.h000066400000000000000000000053341077523320400172350ustar00rootroot00000000000000/* Copyright (c) 2006 Paolo Capriotti (c) 2006 Maurizio Monge 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. */ #ifndef XBOARDENGINE_H #define XBOARDENGINE_H #include "engine.h" #include "tagua.h" class QRegExp; /** * @brief A chess engine compatible with xboard. * * XBoard compatible engines are defined by Tim Mann's * Chess Engine Communication Protocol (available at * http://tim-mann.org/xboard/engine-intf.html), used * by GNU Chess, Crafty and many other free and commercial * chess engines. * This class encapsulates such communication protocol, * calling appropriate methods of the notifier upon engine * generated events. * * @note This code is partially stolen from Maurizio Monge's * old interface project outoftime. */ class XBoardEngine : public Engine { Q_OBJECT struct Features { bool ping : 1; bool setboard : 1; bool playother : 1; bool san : 1; bool usermove : 1; bool time : 1; bool draw : 1; bool sigint : 1; bool sigterm : 1; bool reuse : 1; bool analyze : 1; QString myname; QString variants; bool colors : 1; bool ics : 1; bool name : 1; bool pause : 1; bool done : 1; }; Features m_features; bool m_analysing; static QRegExp m_move_pattern; protected: /** * Initialize the engine. */ virtual void initializeEngine(); protected Q_SLOTS: /** * Parse engine command line and the appropriate * signals. */ void processCommand(const QString& command); public: /** * Create an xboard compatible engine. */ XBoardEngine(const QString& path, const QStringList& arguments); /** * Terminate the engine. */ virtual ~XBoardEngine(); /** * Send a move to the engine. */ virtual void sendMove(AbstractMove::Ptr move, AbstractPosition::Ptr ref); /** * Back up a move. * @param pos The position before the move. Used if the engine * does not support the undo command. */ virtual void backUp(AbstractPosition::Ptr pos); virtual void setBoard(AbstractPosition::Ptr pos, int halfmove, int fullmove); /** * Begin a new game. */ virtual void reset(); /** * Start playing. */ virtual void play(); /** * Stop the engine. */ virtual void stop(); virtual void startAnalysis(); virtual void stopAnalysis(); }; #endif // XBOARDENGINE_H tagua-1.0-alpha2/strip_font.rb000077500000000000000000000020501077523320400163370ustar00rootroot00000000000000#!/usr/bin/ruby require 'optparse' require 'set' input_file = nil output_file = nil font_name = nil $options = OptionParser.new do |opt| opt.banner = "Usage: strip_font.rb [options] luafiles" opt.on( '-n', '--name FONT_NAME', 'Output font name' ) do |name| font_name = name end opt.on( '-i', '--input INPUT_FONT', 'Input font') do |file| input_file = file end opt.on( '-o', '--output OUTPUT_FONT', 'Font to generate') do |file| output_file = file end end $options.parse!(ARGV) lua_files = ARGV selection = Set.new ARGV.each do |file| File.open(file) do |f| content = f.read content.scan(/(["'])0x([0-9a-fA-F]{4})\1/).each do |match| print(match.inspect+"\n") selection.add "SelectMore(0u"+match[1]+");" end end end a = %{ Open("#{input_file}"); #{selection.to_a.join("\n")} SelectInvert(); DetachAndRemoveGlyphs(); SetFontNames("#{font_name}", "#{font_name}", "#{font_name}"); SetUniqueID(0); Generate("#{output_file}"); } system("echo -en #{a.inspect} | fontforge -c") tagua-1.0-alpha2/tagua.pot000066400000000000000000000353741077523320400154640ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: http://trac.tagua-project.org\n" "POT-Creation-Date: 2008-02-26 23:43+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: main.cpp:35 msgid "Tagua" msgstr "" #: main.cpp:37 msgid "(C) 2006 Paolo Capriotti, Maurizio Monge" msgstr "" #: main.cpp:38 msgid "Paolo Capriotti" msgstr "" #: main.cpp:39 msgid "Maurizio Monge" msgstr "" #: main.cpp:40 msgid "Jani Huhtanen" msgstr "" #: main.cpp:40 msgid "Gaussian blur code" msgstr "" #: main.cpp:41 msgid "Rici Lake" msgstr "" #: main.cpp:41 msgid "funclib lua library" msgstr "" #: main.cpp:42 msgid "Riccardo Iaconelli" msgstr "" #: main.cpp:42 msgid "Various fixes and cleanups" msgstr "" #: main.cpp:43 msgid "Yann Dirson" msgstr "" #: main.cpp:43 msgid "Shogi related patches" msgstr "" #: main.cpp:44 msgid "Pieter Stouten" msgstr "" #: main.cpp:44 msgid "Allowed free use of images on shogi.net" msgstr "" #: main.cpp:47 msgid "Initial variant" msgstr "" #: mainwindow.cpp:79 msgid "Move list" msgstr "" #: mainwindow.cpp:89 msgid "FICS Connection" msgstr "" #: mainwindow.cpp:92 msgid "Console" msgstr "" #: mainwindow.cpp:129 msgid "E&ngines" msgstr "" #: mainwindow.cpp:143 msgid "Play as &white" msgstr "" #: mainwindow.cpp:149 msgid "Play as &black" msgstr "" #: mainwindow.cpp:156 msgid "&Analyze" msgstr "" #: mainwindow.cpp:175 msgid "&Back" msgstr "" #: mainwindow.cpp:176 msgid "&Forward" msgstr "" #: mainwindow.cpp:177 msgid "Be&gin" msgstr "" #: mainwindow.cpp:178 msgid "&End" msgstr "" #: mainwindow.cpp:179 msgid "&Connect" msgstr "" #: mainwindow.cpp:181 msgid "&Disconnect" msgstr "" #: mainwindow.cpp:188 msgid "&Edit position" msgstr "" #: mainwindow.cpp:189 msgid "&Clear board" msgstr "" #: mainwindow.cpp:190 msgid "&Set starting position" msgstr "" #: mainwindow.cpp:194 msgid "&Flip view" msgstr "" #: mainwindow.cpp:196 msgid "Toggle &console" msgstr "" #: mainwindow.cpp:197 msgid "Toggle &move list" msgstr "" #: mainwindow.cpp:420 msgid "You have specified a folder" msgstr "" #: mainwindow.cpp:420 mainwindow.cpp:425 mainwindow.cpp:432 mainwindow.cpp:647 msgid "Error" msgstr "" #: mainwindow.cpp:425 msgid "The specified file does not exist" msgstr "" #: mainwindow.cpp:432 msgid "You do not have read permission to this file." msgstr "" #: mainwindow.cpp:447 msgid "Open PGN file" msgstr "" #: mainwindow.cpp:469 msgid "Save PGN file" msgstr "" #: mainwindow.cpp:481 msgid "" "A file named \"%1\" already exists. Are you sure you want to overwrite it?" msgstr "" #: mainwindow.cpp:483 msgid "Overwrite File?" msgstr "" #: mainwindow.cpp:484 msgid "&Overwrite" msgstr "" #: mainwindow.cpp:647 msgid "Error creating game" msgstr "" #: mainwindow.cpp:687 msgid "Illegal move" msgstr "" #: movelist.cpp:684 movelist.cpp:725 msgid "&Set Comment" msgstr "" #: movelist.cpp:687 msgid "&Promote Variation" msgstr "" #: movelist.cpp:689 msgid "&Remove Variation" msgstr "" #: movelist.cpp:727 msgid "&Clear Variations" msgstr "" #: movelist.cpp:730 msgid "&Truncate" msgstr "" #: movelist.cpp:734 msgid "&Promote variation" msgstr "" #: movelist.cpp:737 msgid "&Remove variation" msgstr "" #: pref_engines.cpp:39 msgid "&Name:" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 136 #: pref_engines.cpp:47 extractedrc.cpp:131 msgid "&Type:" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 147 #: pref_engines.cpp:52 extractedrc.cpp:134 msgid "XBoard" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 152 #: pref_engines.cpp:53 extractedrc.cpp:137 msgid "UCI" msgstr "" #: pref_engines.cpp:54 msgid "Tagua (textual)" msgstr "" #: pref_engines.cpp:55 msgid "Tagua (DBUS)" msgstr "" #: pref_engines.cpp:56 msgid "GNU Shogi" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 113 #: pref_engines.cpp:61 extractedrc.cpp:128 msgid "&Path:" msgstr "" #: pref_engines.cpp:70 msgid "&Work directory:" msgstr "" #: pref_engines.cpp:93 msgid "Choose a name for the engine" msgstr "" #: pref_engines.cpp:93 msgid "No engine name" msgstr "" #: pref_engines.cpp:117 msgid "&New..." msgstr "" #: pref_engines.cpp:119 msgid "&Edit..." msgstr "" #: pref_engines.cpp:121 msgid "&Delete" msgstr "" #: pref_theme.cpp:344 msgid "&Reset to Default" msgstr "" #: qconnect.cpp:56 msgid "Select timeseal binary" msgstr "" #: qconnect.cpp:59 msgid "Only local executables supported" msgstr "" #: tabwidget.cpp:24 msgid "Close the current tab" msgstr "" #. i18n: tag Text #. i18n: file ./taguaui.rc line 15 #: extractedrc.cpp:3 msgid "&Edit" msgstr "" #. i18n: tag text #. i18n: file ./taguaui.rc line 24 #: extractedrc.cpp:6 msgid "&Game" msgstr "" #. i18n: tag text #. i18n: file ./taguaui.rc line 33 #: extractedrc.cpp:9 msgid "&View" msgstr "" #. i18n: tag text #. i18n: file ./taguaui.rc line 47 #: extractedrc.cpp:12 msgid "Game Toolbar" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 13 #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 13 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 13 #: extractedrc.cpp:15 extractedrc.cpp:63 extractedrc.cpp:182 msgid "Form" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 25 #: extractedrc.cpp:18 msgid "Round:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 35 #: extractedrc.cpp:21 msgid "Time:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 54 #: extractedrc.cpp:24 msgid "Result:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 61 #: extractedrc.cpp:27 msgid "Increment:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 71 #: extractedrc.cpp:30 msgid "Site:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 78 #: extractedrc.cpp:33 msgid "Black rating:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 85 #: extractedrc.cpp:36 msgid "Event:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 92 #: extractedrc.cpp:39 msgid "Black:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 99 #: extractedrc.cpp:42 msgid "White:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 121 #: extractedrc.cpp:45 msgid "Date:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 131 #: extractedrc.cpp:48 msgid "White rating:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 138 #: extractedrc.cpp:51 msgid "ECO:" msgstr "" #. i18n: tag string #. i18n: file ./ui/newgamedialog.ui line 13 #: extractedrc.cpp:54 msgid "New game" msgstr "" #. i18n: tag string #. i18n: file ./ui/newgamedialog.ui line 39 #. i18n: tag string #. i18n: file ./ui/pref_theme.ui line 48 #: extractedrc.cpp:57 extractedrc.cpp:232 msgid "&Variant:" msgstr "" #. i18n: tag string #. i18n: file ./ui/newgamedialog.ui line 74 #: extractedrc.cpp:60 msgid "Create in new &tab" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 36 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 36 #: extractedrc.cpp:66 extractedrc.cpp:185 msgid "&Animations" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 51 #: extractedrc.cpp:69 msgid "&Transformations" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 58 #: extractedrc.cpp:72 msgid "&Explosions" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 65 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 158 #: extractedrc.cpp:75 extractedrc.cpp:205 msgid "&Movements" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 72 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 165 #: extractedrc.cpp:78 extractedrc.cpp:208 msgid "&Fading" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 88 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 60 #: extractedrc.cpp:81 extractedrc.cpp:188 msgid "" "Rough\n" "(little CPU usage)" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 115 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 87 #: extractedrc.cpp:85 extractedrc.cpp:192 msgid "" "Smooth\n" "(high CPU usage)" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 130 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 179 #: extractedrc.cpp:89 extractedrc.cpp:214 msgid "Animation s&moothness:" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 151 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 123 #: extractedrc.cpp:92 extractedrc.cpp:199 msgid "Slow" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 177 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 146 #: extractedrc.cpp:95 extractedrc.cpp:202 msgid "Fast" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 189 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 102 #: extractedrc.cpp:98 extractedrc.cpp:196 msgid "Animation s&peed:" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 231 #: extractedrc.cpp:101 msgid "&Max sequence length:" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 253 #: extractedrc.cpp:104 msgid "Animate move &sequences" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 277 #: extractedrc.cpp:107 msgid "&Border" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 292 #: extractedrc.cpp:110 msgid "&Color" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 302 #: extractedrc.cpp:113 msgid "&Text Color" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 320 #: extractedrc.cpp:116 msgid "Custom &font:" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 13 #: extractedrc.cpp:119 msgid "Engines" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 25 #: extractedrc.cpp:122 msgid "Engine list" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 93 #: extractedrc.cpp:125 msgid "Engine properties" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 157 #: extractedrc.cpp:140 msgid "Tagua (text)" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 162 #: extractedrc.cpp:143 msgid "Tagua (D-BUS)" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 180 #: extractedrc.cpp:146 msgid "&Work dir:" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 13 #: extractedrc.cpp:149 msgid "Dialog" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 47 #: extractedrc.cpp:152 msgid "Pattern" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 75 #: extractedrc.cpp:155 msgid "Bold" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 82 #: extractedrc.cpp:158 msgid "Italic" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 148 #: extractedrc.cpp:161 msgid "Use this box to test your regular expression" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 186 #: extractedrc.cpp:164 msgid "Add" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 193 #: extractedrc.cpp:167 msgid "Remove" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 223 #: extractedrc.cpp:170 msgid "Up" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 230 #: extractedrc.cpp:173 msgid "Down" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 266 #: extractedrc.cpp:176 msgid "OK" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 273 #: extractedrc.cpp:179 msgid "Cancel" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 172 #: extractedrc.cpp:211 msgid "&Smooth highlighting" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 203 #: extractedrc.cpp:217 msgid "&Colors and fonts" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 215 #: extractedrc.cpp:220 msgid "C&omments color:" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 233 #: extractedrc.cpp:223 msgid "Cus&tom comments font:" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 243 #: extractedrc.cpp:226 msgid "C&ustom moves font:" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 253 #: extractedrc.cpp:229 msgid "S&elected move color:" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_theme_page.ui line 31 #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 149 #: extractedrc.cpp:235 extractedrc.cpp:271 msgid "..." msgstr "" #. i18n: tag string #. i18n: file ./ui/preferences.ui line 13 #: extractedrc.cpp:238 msgid "Change Tagua Settings" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 13 #: extractedrc.cpp:241 msgid "Quick Connect" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 28 #: extractedrc.cpp:244 msgid "&Login" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 47 #: extractedrc.cpp:247 msgid "&Password:" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 60 #: extractedrc.cpp:250 msgid "&Username:" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 70 #: extractedrc.cpp:253 msgid "&Store password on this computer" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 73 #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 182 #: extractedrc.cpp:256 extractedrc.cpp:280 msgid "Alt+S" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 83 #: extractedrc.cpp:259 msgid "Ser&ver:" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 98 #: extractedrc.cpp:262 msgid "ICS p&ort:" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 115 #: extractedrc.cpp:265 msgid "ICS &host:" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 131 #: extractedrc.cpp:268 msgid "&Timeseal" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 159 #: extractedrc.cpp:274 msgid "&File Path:" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 179 #: extractedrc.cpp:277 msgid "Use &custom command line arguments" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 232 #: extractedrc.cpp:283 msgid "&OK" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 248 #: extractedrc.cpp:286 msgid "&Cancel" msgstr "" #: extractedrc.cpp:287 msgctxt "NAME OF TRANSLATORS" msgid "Your names" msgstr "" #: extractedrc.cpp:288 msgctxt "EMAIL OF TRANSLATORS" msgid "Your emails" msgstr "" tagua-1.0-alpha2/templates/000077500000000000000000000000001077523320400156215ustar00rootroot00000000000000tagua-1.0-alpha2/templates/cpp000066400000000000000000000000001077523320400163140ustar00rootroot00000000000000tagua-1.0-alpha2/templates/h000066400000000000000000000000001077523320400157610ustar00rootroot00000000000000tagua-1.0-alpha2/templates/variant_template.cpp.erb000066400000000000000000000033331077523320400224350ustar00rootroot00000000000000<% cvariant = variant.capitalize %> #include "<%= variant %>.h" #include "xchess/animator.h" #include "xchess/piece.h" #include "xchess/move.h" class <%= cvariant %>Position : public ChessPosition { public: typedef ChessPosition::Piece Piece; <%= cvariant %>Position(); <%= cvariant %>Position(const ChessPosition&); <%= cvariant %>Position(Piece::Color turn, bool wk, bool wq, bool bk, bool bq, const Point& ep); virtual <%= cvariant %>Position* clone() const { return new <%= cvariant %>Position(*this); } }; <%= cvariant %>Position::<%= cvariant %>Position() { } <%= cvariant %>Position::<%= cvariant %>Position(const ChessPosition& other) : ChessPosition(other) { } <%= cvariant %>Position::<%= cvariant %>Position(Piece::Color turn, bool wk, bool wq, bool bk, bool bq, const Point& ep) : ChessPosition(turn, wk, wq, bk, bq, ep) { } class <%= cvariant %>VariantInfo { public: typedef <%= cvariant %>Position Position; typedef Position::Move Move; typedef Position::Piece Piece; typedef ChessAnimator Animator; static void loadPieces(PixmapLoader::Info&); static void forallPieces(PieceFunction& f); static int moveListLayout() { return 0; } }; void <%= cvariant %>VariantInfo::loadPieces(PixmapLoader::Info& info) { ChessVariant::loadPieces(info); } void <%= cvariant %>VariantInfo::forallPieces(PieceFunction& f) { ChessVariant::forallPieces(f); } VariantInfo* <%= cvariant %>Variant::static_<%= variant %>_variant = 0; VariantInfo* <%= cvariant %>Variant::info() { if (!static_<%= variant %>_variant) static_<%= variant %>_variant = new WrappedVariantInfo<<%= cvariant %>VariantInfo>; return static_<%= variant %>_variant; } tagua-1.0-alpha2/templates/variant_template.h.erb000066400000000000000000000004511077523320400221000ustar00rootroot00000000000000<% vtag = "#{variant.upcase}VARIANT_H" %> <% cvariant = variant.capitalize %> #ifndef <%= vtag %> #define <%= vtag %> #include "chess.h" class <%= cvariant %>Variant { private: static VariantInfo* static_<%= variant %>_variant; public: static VariantInfo* info(); }; #endif // <%= vtag %> tagua-1.0-alpha2/tests/000077500000000000000000000000001077523320400147655ustar00rootroot00000000000000tagua-1.0-alpha2/tests/.gitignore000066400000000000000000000001421077523320400167520ustar00rootroot00000000000000DartTestfile.txt DartTestfile.txt Makefile Makefile cmake_install.cmake cmake_install.cmake *.pgn tagua-1.0-alpha2/tests/CMakeLists.txt000066400000000000000000000004211077523320400175220ustar00rootroot00000000000000# some tests require cppunit find_package(CPPUNIT) if(CPPUNIT_FOUND) add_subdirectory(settings) add_subdirectory(weak_set) add_subdirectory(hlvariants) else(CPPUNIT_FOUND) message("CppUnit not found. Tests requiring it will not be compiled.") endif(CPPUNIT_FOUND) tagua-1.0-alpha2/tests/add_test.rb000077500000000000000000000007671077523320400171160ustar00rootroot00000000000000#!/usr/bin/ruby require 'erb' def usage warn "Usage: #$0 [(-f | --filename) FILENAME] TEST_NAME [TEST] [TEST] ..." exit 1 end arg = ARGV.shift or usage if arg =~ /^-/ case arg when '-f', '--filename' @filename = ARGV.shift or usage else usage end else @name = arg @filename = @name.downcase end @tests = ARGV %w(cpp h).each do |ext| File.open("#{@name.downcase}.#{ext}",'w') do |file| file.write(ERB.new(File.open("template.#{ext}.erb").read).result(binding)) end end tagua-1.0-alpha2/tests/cppunit_main.cpp000066400000000000000000000005321077523320400201570ustar00rootroot00000000000000#include #include int main(int, char**) { CppUnit::TextUi::TestRunner runner; CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); runner.addTest(registry.makeTest()); int res = runner.run( "", false ) ? 0 : 1; return res; } tagua-1.0-alpha2/tests/hlvariants/000077500000000000000000000000001077523320400171405ustar00rootroot00000000000000tagua-1.0-alpha2/tests/hlvariants/CMakeLists.txt000066400000000000000000000010171077523320400216770ustar00rootroot00000000000000set(main_dir "../../src") SET(hl_SRC ../cppunit_main.cpp boardtest.cpp chesspiecetest.cpp chessgamestatetest.cpp chessmovetest.cpp chesslegalitytest.cpp chesswrappedtest.cpp chessserializationtest.cpp pooltest.cpp shogideserializationtest.cpp ) include_directories( ${KDE4_INCLUDES} ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${main_dir} ) add_executable(hl_test ${hl_SRC}) target_link_libraries(hl_test taguaprivate ${CPPUNIT_LIBRARIES}) add_test(hl hl_test) tagua-1.0-alpha2/tests/hlvariants/boardtest.cpp000066400000000000000000000070271077523320400216410ustar00rootroot00000000000000#include "boardtest.h" #include "point.h" #include "hlvariant/board.h" CPPUNIT_TEST_SUITE_REGISTRATION(BoardTest); void BoardTest::setUp() { m_board = new HLVariant::Board(Point(8, 8)); } void BoardTest::tearDown() { delete m_board; } void BoardTest::test_size() { CPPUNIT_ASSERT_EQUAL(8, m_board->size().x); CPPUNIT_ASSERT_EQUAL(8, m_board->size().y); } void BoardTest::test_get_null() { int x = m_board->get(Point(3, 2)); CPPUNIT_ASSERT_EQUAL(int(), x); } void BoardTest::test_set_get() { m_board->set(Point(3, 2), 37); CPPUNIT_ASSERT_EQUAL(37, m_board->get(Point(3, 2))); } void BoardTest::test_valid() { CPPUNIT_ASSERT(!m_board->valid(Point(-1, 3))); CPPUNIT_ASSERT(!m_board->valid(Point(7, -1))); CPPUNIT_ASSERT(!m_board->valid(Point(8, 0))); CPPUNIT_ASSERT(!m_board->valid(Point(8, 7))); CPPUNIT_ASSERT(m_board->valid(Point(1, 3))); CPPUNIT_ASSERT(m_board->valid(Point(4, 7))); CPPUNIT_ASSERT(m_board->valid(Point(0, 0))); CPPUNIT_ASSERT(m_board->valid(Point(7, 7))); } void BoardTest::test_set_invalid() { m_board->set(Point(8, 2), 42); CPPUNIT_ASSERT_EQUAL(int(), m_board->get(Point(8, 2))); } void BoardTest::test_compare() { m_board->set(Point(3, 4), 3); m_board->set(Point(5, 1), 7); HLVariant::Board other(m_board->size()); other.set(Point(3, 4), 3); CPPUNIT_ASSERT(other != (*m_board)); CPPUNIT_ASSERT(!(other == (*m_board))); other.set(Point(5, 1), 7); CPPUNIT_ASSERT(other == (*m_board)); } void BoardTest::test_clone() { m_board->set(Point(3, 4), 23); HLVariant::Board other(*m_board); CPPUNIT_ASSERT_EQUAL(23, other.get(Point(3, 4))); m_board->set(Point(3, 5), 21); CPPUNIT_ASSERT_EQUAL(int(), other.get(Point(3, 5))); } void BoardTest::test_pathinfo_h() { PathInfo path = m_board->path(Point(3, 4), Point(6, 4)); CPPUNIT_ASSERT(path.direction() == PathInfo::Horizontal); CPPUNIT_ASSERT(path.parallel()); } void BoardTest::test_pathinfo_v() { PathInfo path = m_board->path(Point(7, 2), Point(7, 4)); CPPUNIT_ASSERT(path.direction() == PathInfo::Vertical); CPPUNIT_ASSERT(path.parallel()); } void BoardTest::test_pathinfo_d() { PathInfo path = m_board->path(Point(3, 3), Point(5, 5)); CPPUNIT_ASSERT(path.diagonal()); path = m_board->path(Point(2, 7), Point(5, 4)); CPPUNIT_ASSERT(path.diagonal()); } void BoardTest::test_pathinfo_invalid() { PathInfo path = m_board->path(Point(-1, 3), Point(7, 3)); CPPUNIT_ASSERT(!path.valid()); path = m_board->path(Point(3, 3), Point(5, 4)); CPPUNIT_ASSERT(!path.valid()); } void BoardTest::test_pathinfo_obstacles() { PathInfo path = m_board->path(Point(1, 1), Point(4, 4)); CPPUNIT_ASSERT(path.clear()); m_board->set(Point(2, 2), 37); path = m_board->path(Point(1, 1), Point(4, 4)); CPPUNIT_ASSERT(!path.clear()); CPPUNIT_ASSERT_EQUAL(1, path.numObstacles()); m_board->set(Point(6, 2), 42); path = m_board->path(Point(0, 2), Point(5, 2)); CPPUNIT_ASSERT_EQUAL(1, path.numObstacles()); path = m_board->path(Point(0, 2), Point(6, 2)); CPPUNIT_ASSERT_EQUAL(1, path.numObstacles()); path = m_board->path(Point(0, 2), Point(7, 2)); CPPUNIT_ASSERT_EQUAL(2, path.numObstacles()); path = m_board->path(Point(2, 2), Point(6, 2)); CPPUNIT_ASSERT(path.clear()); } void BoardTest::test_find() { m_board->set(Point(3, 4), 32); m_board->set(Point(5, 6), 22); m_board->set(Point(7, 7), 22); CPPUNIT_ASSERT(m_board->find(17) == Point::invalid()); CPPUNIT_ASSERT(m_board->find(22) == Point(5, 6)); CPPUNIT_ASSERT(m_board->find(32) == Point(3, 4)); } tagua-1.0-alpha2/tests/hlvariants/boardtest.h000066400000000000000000000024021077523320400212760ustar00rootroot00000000000000#ifndef BOARDTEST_H #define BOARDTEST_H #include #include #include #include #include namespace HLVariant { template class Board; } class BoardTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(BoardTest); CPPUNIT_TEST(test_size); CPPUNIT_TEST(test_get_null); CPPUNIT_TEST(test_set_get); CPPUNIT_TEST(test_valid); CPPUNIT_TEST(test_set_invalid); CPPUNIT_TEST(test_compare); CPPUNIT_TEST(test_clone); CPPUNIT_TEST(test_find); CPPUNIT_TEST(test_pathinfo_h); CPPUNIT_TEST(test_pathinfo_v); CPPUNIT_TEST(test_pathinfo_d); CPPUNIT_TEST(test_pathinfo_invalid); CPPUNIT_TEST(test_pathinfo_obstacles); CPPUNIT_TEST_SUITE_END(); private: HLVariant::Board* m_board; public: void setUp(); void tearDown(); // basic stuff void test_size(); void test_get_null(); void test_set_get(); void test_valid(); void test_set_invalid(); void test_compare(); void test_clone(); void test_find(); // path info void test_pathinfo_h(); void test_pathinfo_v(); void test_pathinfo_d(); void test_pathinfo_invalid(); void test_pathinfo_obstacles(); }; #endif // BOARDTEST_H tagua-1.0-alpha2/tests/hlvariants/chessgamestatetest.cpp000066400000000000000000000067431077523320400235560ustar00rootroot00000000000000#include "chessgamestatetest.h" #include "hlvariant/chess/gamestate.h" CPPUNIT_TEST_SUITE_REGISTRATION(ChessGameStateTest); void ChessGameStateTest::setUp() { m_state = new ChessGameState; m_state->setup(); } void ChessGameStateTest::tearDown() { delete m_state; } void ChessGameStateTest::test_setup() { for (int i = 0; i < 8; i++) { CPPUNIT_ASSERT_EQUAL(ChessPiece::BLACK, m_state->board().get(Point(i, 0)).color()); CPPUNIT_ASSERT_EQUAL(ChessPiece::BLACK, m_state->board().get(Point(i, 1)).color()); CPPUNIT_ASSERT_EQUAL(ChessPiece::WHITE, m_state->board().get(Point(i, 6)).color()); CPPUNIT_ASSERT_EQUAL(ChessPiece::WHITE, m_state->board().get(Point(i, 7)).color()); CPPUNIT_ASSERT(m_state->board().get(Point(i, 4)) == ChessPiece()); } CPPUNIT_ASSERT_EQUAL(ChessPiece::ROOK, m_state->board().get(Point(0, 0)).type()); CPPUNIT_ASSERT_EQUAL(ChessPiece::KING, m_state->board().get(Point(4, 7)).type()); CPPUNIT_ASSERT_EQUAL(ChessPiece::PAWN, m_state->board().get(Point(6, 6)).type()); } void ChessGameStateTest::test_simple_move() { m_state->move(ChessMove(Point(4, 6), Point(4, 5))); // e4 CPPUNIT_ASSERT(m_state->board().get(Point(4, 6)) == ChessPiece()); CPPUNIT_ASSERT(m_state->board().get(Point(4, 5)) == ChessPiece(ChessPiece::WHITE, ChessPiece::PAWN)); } void ChessGameStateTest::test_capture() { m_state->move(ChessMove(Point(4, 6), Point(4, 4))); // e4 m_state->move(ChessMove(Point(3, 1), Point(3, 3))); // d5 m_state->move(ChessMove(Point(4, 4), Point(3, 3))); // exd5 CPPUNIT_ASSERT(m_state->board().get(Point(3, 3)) == ChessPiece(ChessPiece::WHITE, ChessPiece::PAWN)); } void ChessGameStateTest::test_en_passant() { m_state->move(ChessMove(Point(4, 6), Point(4, 4))); // e4 m_state->move(ChessMove(Point(7, 1), Point(7, 2))); // h6 m_state->move(ChessMove(Point(4, 4), Point(4, 3))); // e5 ChessMove d5(Point(3, 1), Point(3, 3)); d5.setType(ChessMove::EN_PASSANT_TRIGGER); m_state->move(d5); CPPUNIT_ASSERT(m_state->enPassant() == Point(3, 2)); ChessMove exd6(Point(4, 3), Point(3, 2)); exd6.setType(ChessMove::EN_PASSANT_CAPTURE); m_state->move(exd6); CPPUNIT_ASSERT(m_state->board().get(Point(3, 3)) == ChessPiece()); } void ChessGameStateTest::test_kingside_castling() { ChessMove oo(Point(4, 7), Point(6, 7)); oo.setType(ChessMove::KING_SIDE_CASTLING); m_state->move(oo); CPPUNIT_ASSERT(m_state->board().get(Point(6, 7)) == ChessPiece(ChessPiece::WHITE, ChessPiece::KING)); CPPUNIT_ASSERT(m_state->board().get(Point(5, 7)) == ChessPiece(ChessPiece::WHITE, ChessPiece::ROOK)); CPPUNIT_ASSERT(m_state->board().get(Point(7, 7)) == ChessPiece()); } void ChessGameStateTest::test_queenside_castling() { ChessMove oo(Point(4, 7), Point(2, 7)); oo.setType(ChessMove::QUEEN_SIDE_CASTLING); m_state->move(oo); CPPUNIT_ASSERT(m_state->board().get(Point(2, 7)) == ChessPiece(ChessPiece::WHITE, ChessPiece::KING)); CPPUNIT_ASSERT(m_state->board().get(Point(3, 7)) == ChessPiece(ChessPiece::WHITE, ChessPiece::ROOK)); CPPUNIT_ASSERT(m_state->board().get(Point(0, 7)) == ChessPiece()); } void ChessGameStateTest::test_promotion() { m_state->board().set(Point(7, 1), ChessPiece(ChessPiece::WHITE, ChessPiece::PAWN)); ChessMove h8B(Point(7, 1), Point(7, 0), ChessPiece::BISHOP); h8B.setType(ChessMove::PROMOTION); m_state->move(h8B); CPPUNIT_ASSERT(m_state->board().get(Point(7, 0)) == ChessPiece(ChessPiece::WHITE, ChessPiece::BISHOP)); } tagua-1.0-alpha2/tests/hlvariants/chessgamestatetest.h000066400000000000000000000025341077523320400232150ustar00rootroot00000000000000#ifndef CHESSGAMESTATETEST_H #define CHESSGAMESTATETEST_H #include #include #include #include #include #include "hlvariant/customboard.h" // forward decl namespace HLVariant { template class Board; namespace Chess { template class GameState; class Move; class Piece; } } typedef HLVariant::Chess::Move ChessMove; typedef HLVariant::Chess::Piece ChessPiece; typedef HLVariant::CustomBoard<8, 8, ChessPiece> Chessboard; typedef HLVariant::Chess::GameState ChessGameState; class ChessGameStateTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ChessGameStateTest); CPPUNIT_TEST(test_setup); CPPUNIT_TEST(test_simple_move); CPPUNIT_TEST(test_capture); CPPUNIT_TEST(test_en_passant); CPPUNIT_TEST(test_kingside_castling); CPPUNIT_TEST(test_queenside_castling); CPPUNIT_TEST(test_promotion); CPPUNIT_TEST_SUITE_END(); private: ChessGameState* m_state; public: void setUp(); void tearDown(); void test_setup(); void test_simple_move(); void test_capture(); void test_en_passant(); void test_kingside_castling(); void test_queenside_castling(); void test_promotion(); }; #endif // CHESSGAMESTATETEST_H tagua-1.0-alpha2/tests/hlvariants/chesslegalitytest.cpp000066400000000000000000000127211077523320400234070ustar00rootroot00000000000000#include "chesslegalitytest.h" #include "hlvariant/chess/legalitycheck.h" CPPUNIT_TEST_SUITE_REGISTRATION(ChessLegalityTest); void ChessLegalityTest::setUp() { m_state = new ChessGameState; m_state->setup(); m_legality_check = new ChessLegalityCheck(*m_state); } void ChessLegalityTest::tearDown() { delete m_state; delete m_legality_check; } void ChessLegalityTest::test_movements() { ChessMove e4(Point(4, 6), Point(4, 4)); CPPUNIT_ASSERT_EQUAL(ChessMove::EN_PASSANT_TRIGGER, m_legality_check->getMoveType( m_state->board().get(Point(4, 6)), e4)); ChessMove crazy(Point(0, 0), Point(7, 4)); CPPUNIT_ASSERT_EQUAL(ChessMove::INVALID, m_legality_check->getMoveType( m_state->board().get(Point(0, 0)), crazy)); } void ChessLegalityTest::test_pseudolegal() { ChessMove e4(Point(4, 6), Point(4, 4)); CPPUNIT_ASSERT(m_legality_check->pseudolegal(e4)); ChessMove e5(Point(4, 6), Point(4, 3)); CPPUNIT_ASSERT(!m_legality_check->pseudolegal(e5)); ChessMove Nf3(Point(6, 7), Point(5, 5)); CPPUNIT_ASSERT(m_legality_check->pseudolegal(Nf3)); ChessMove Bc4(Point(5, 7), Point(2, 4)); CPPUNIT_ASSERT(!m_legality_check->pseudolegal(Bc4)); // black moves m_state->switchTurn(); ChessMove crazy(Point(0, 0), Point(4, 7)); CPPUNIT_ASSERT(!m_legality_check->pseudolegal(crazy)); ChessMove e5_(Point(4, 1), Point(4, 3)); CPPUNIT_ASSERT(m_legality_check->pseudolegal(e5_)); } void ChessLegalityTest::test_simple_move() { ChessMove e4(Point(4, 6), Point(4, 4)); CPPUNIT_ASSERT(m_legality_check->legal(e4)); ChessMove e5(Point(4, 6), Point(4, 3)); CPPUNIT_ASSERT(!m_legality_check->pseudolegal(e5)); ChessMove Nf3(Point(6, 7), Point(5, 5)); CPPUNIT_ASSERT(m_legality_check->legal(Nf3)); ChessMove Bc4(Point(5, 7), Point(2, 4)); CPPUNIT_ASSERT(!m_legality_check->pseudolegal(Bc4)); { ChessMove tmp(Point(5, 7), Point(2, 4)); m_state->board().set(Point(4, 6), ChessPiece()); CPPUNIT_ASSERT(m_legality_check->legal(tmp)); } ChessMove e6(Point(4, 1), Point(4, 2)); CPPUNIT_ASSERT(!m_legality_check->pseudolegal(e6)); { ChessMove tmp(Point(4, 1), Point(4, 2)); m_state->switchTurn(); CPPUNIT_ASSERT(m_legality_check->legal(tmp)); } } void ChessLegalityTest::test_promotion() { m_state->board().set(Point(7, 1), ChessPiece(ChessPiece::WHITE, ChessPiece::PAWN)); ChessMove h8Q(Point(7, 1), Point(7, 0), ChessPiece::QUEEN); CPPUNIT_ASSERT(!m_legality_check->pseudolegal(h8Q)); ChessMove hxg8R(Point(7, 1), Point(6, 0), ChessPiece::ROOK); CPPUNIT_ASSERT(m_legality_check->pseudolegal(hxg8R)); CPPUNIT_ASSERT(m_legality_check->legal(hxg8R)); CPPUNIT_ASSERT_EQUAL((int)ChessPiece::ROOK, hxg8R.promoteTo()); } void ChessLegalityTest::test_en_passant() { m_state->move(ChessMove(Point(4, 6), Point(4, 4))); m_state->move(ChessMove(Point(7, 1), Point(7, 2))); m_state->move(ChessMove(Point(4, 4), Point(4, 3))); ChessMove d5(Point(3, 1), Point(3, 3)); CPPUNIT_ASSERT(m_legality_check->legal(d5)); CPPUNIT_ASSERT(d5.enPassantTrigger() == Point(3, 2)); m_state->move(d5); ChessMove exd6(Point(4, 3), Point(3, 2)); CPPUNIT_ASSERT(m_legality_check->legal(exd6)); CPPUNIT_ASSERT(exd6.captureSquare() == Point(3, 3)); m_state->move(ChessMove(Point(7, 6), Point(7, 5))); m_state->move(ChessMove(Point(7, 2), Point(7, 3))); ChessMove tmp(Point(4, 3), Point(3, 2)); CPPUNIT_ASSERT(!m_legality_check->pseudolegal(tmp)); } void ChessLegalityTest::test_castling() { ChessMove oo(Point(4, 7), Point(6, 7)); m_state->board().set(Point(6, 7), ChessPiece()); { ChessMove tmp(oo); CPPUNIT_ASSERT(!m_legality_check->pseudolegal(tmp)); } m_state->board().set(Point(5, 7), ChessPiece()); { ChessMove tmp(oo); CPPUNIT_ASSERT(m_legality_check->legal(tmp)); } m_state->board().set(Point(3, 6), ChessPiece(ChessPiece::BLACK, ChessPiece::PAWN)); { ChessMove tmp(oo); CPPUNIT_ASSERT(!m_legality_check->pseudolegal(tmp)); } m_state->board().set(Point(3, 6), ChessPiece()); m_state->board().set(Point(4, 6), ChessPiece(ChessPiece::BLACK, ChessPiece::PAWN)); { ChessMove tmp(oo); CPPUNIT_ASSERT(!m_legality_check->pseudolegal(tmp)); } } void ChessLegalityTest::test_attack1() { m_state->board().set(Point(5, 5), ChessPiece(ChessPiece::BLACK, ChessPiece::ROOK)); CPPUNIT_ASSERT(m_legality_check->attacks(ChessPiece::WHITE, Point(5, 5))); } void ChessLegalityTest::test_attack2() { m_state->board().set(Point(4, 4), ChessPiece(ChessPiece::BLACK, ChessPiece::QUEEN)); CPPUNIT_ASSERT(!m_legality_check->attacks(ChessPiece::WHITE, Point(4, 4))); } void ChessLegalityTest::test_attack3() { m_state->board().set(Point(0, 5), ChessPiece(ChessPiece::BLACK, ChessPiece::KING)); m_state->board().set(Point(1, 6), ChessPiece(ChessPiece::WHITE, ChessPiece::ROOK)); // b2: pawn -> rook CPPUNIT_ASSERT(m_legality_check->attacks(ChessPiece::WHITE, Point(0, 5))); m_state->board().set(Point(1, 7), ChessPiece()); // remove knight on b1 CPPUNIT_ASSERT(!m_legality_check->attacks(ChessPiece::WHITE, Point(0, 5))); m_state->board().set(Point(0, 6), ChessPiece()); // remove pawn on a2 CPPUNIT_ASSERT(m_legality_check->attacks(ChessPiece::WHITE, Point(0, 5))); m_state->board().set(Point(0, 7), ChessPiece()); // remove rook on a1 CPPUNIT_ASSERT(!m_legality_check->attacks(ChessPiece::WHITE, Point(0, 5))); } void ChessLegalityTest::test_attack4() { CPPUNIT_ASSERT(!m_legality_check->attacks(ChessPiece::BLACK, Point(4, 7))); } tagua-1.0-alpha2/tests/hlvariants/chesslegalitytest.h000066400000000000000000000032111077523320400230460ustar00rootroot00000000000000#ifndef CHESSGAMESTATETEST_H #define CHESSGAMESTATETEST_H #include #include #include #include #include #include "hlvariant/customboard.h" // forward decl namespace HLVariant { template class Board; namespace Chess { template class GameState; template class LegalityCheck; class Move; class Piece; } } typedef HLVariant::Chess::Move ChessMove; typedef HLVariant::Chess::Piece ChessPiece; typedef HLVariant::CustomBoard<8, 8, ChessPiece> Chessboard; typedef HLVariant::Chess::GameState ChessGameState; typedef HLVariant::Chess::LegalityCheck ChessLegalityCheck; class ChessLegalityTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ChessLegalityTest); CPPUNIT_TEST(test_movements); CPPUNIT_TEST(test_pseudolegal); CPPUNIT_TEST(test_simple_move); CPPUNIT_TEST(test_promotion); CPPUNIT_TEST(test_en_passant); CPPUNIT_TEST(test_castling); CPPUNIT_TEST(test_attack1); CPPUNIT_TEST(test_attack2); CPPUNIT_TEST(test_attack3); CPPUNIT_TEST(test_attack4); CPPUNIT_TEST_SUITE_END(); private: ChessGameState* m_state; ChessLegalityCheck* m_legality_check; public: void setUp(); void tearDown(); void test_movements(); void test_pseudolegal(); void test_simple_move(); void test_promotion(); void test_en_passant(); void test_castling(); void test_attack1(); void test_attack2(); void test_attack3(); void test_attack4(); }; #endif // CHESSGAMESTATETEST_H tagua-1.0-alpha2/tests/hlvariants/chessmovetest.cpp000066400000000000000000000020701077523320400225370ustar00rootroot00000000000000#include "chessmovetest.h" #include "hlvariant/chess/move.h" #include "hlvariant/chess/piece.h" typedef HLVariant::Chess::Piece ChessPiece; CPPUNIT_TEST_SUITE_REGISTRATION(ChessMoveTest); void ChessMoveTest::setUp() { } void ChessMoveTest::tearDown() { } void ChessMoveTest::test_capture_square() { ChessMove m(Point(4, 3), Point(3, 2)); CPPUNIT_ASSERT(m.captureSquare() == Point(3, 2)); m.setType(ChessMove::EN_PASSANT_CAPTURE); CPPUNIT_ASSERT(m.captureSquare() == Point(3, 3)); } void ChessMoveTest::test_en_passant_trigger() { ChessMove m(Point(4, 6), Point(4, 4)); m.setType(ChessMove::EN_PASSANT_TRIGGER); CPPUNIT_ASSERT(m.enPassantTrigger() == Point(4, 5)); ChessMove m2(Point(3, 1), Point(3, 3)); m2.setType(ChessMove::EN_PASSANT_TRIGGER); CPPUNIT_ASSERT(m2.enPassantTrigger() == Point(3, 2)); } void ChessMoveTest::test_promotion() { ChessMove m(Point(5, 1), Point(5, 0), ChessPiece::ROOK); CPPUNIT_ASSERT_EQUAL(-1, m.promoteTo()); m.setType(ChessMove::PROMOTION); CPPUNIT_ASSERT_EQUAL((int)ChessPiece::ROOK, m.promoteTo()); } tagua-1.0-alpha2/tests/hlvariants/chessmovetest.h000066400000000000000000000013451077523320400222100ustar00rootroot00000000000000#ifndef CHESSMOVETEST_H #define CHESSMOVETEST_H #include #include #include #include #include // forward decl namespace HLVariant { namespace Chess { class Move; } } typedef HLVariant::Chess::Move ChessMove; class ChessMoveTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ChessMoveTest); CPPUNIT_TEST(test_capture_square); CPPUNIT_TEST(test_en_passant_trigger); CPPUNIT_TEST(test_promotion); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void test_capture_square(); void test_en_passant_trigger(); void test_promotion(); }; #endif // CHESSMOVETEST_H tagua-1.0-alpha2/tests/hlvariants/chesspiecetest.cpp000066400000000000000000000017411077523320400226620ustar00rootroot00000000000000#include "chesspiecetest.h" #include "hlvariant/chess/piece.h" typedef HLVariant::Chess::Piece ChessPiece; CPPUNIT_TEST_SUITE_REGISTRATION(ChessPieceTest); void ChessPieceTest::setUp() { } void ChessPieceTest::tearDown() { } void ChessPieceTest::test_basic() { ChessPiece p(ChessPiece::WHITE, ChessPiece::ROOK); CPPUNIT_ASSERT_EQUAL(ChessPiece::WHITE, p.color()); CPPUNIT_ASSERT_EQUAL(ChessPiece::ROOK, p.type()); } void ChessPieceTest::test_names() { ChessPiece p(ChessPiece::BLACK, ChessPiece::BISHOP); CPPUNIT_ASSERT(p.colorName() == "black"); CPPUNIT_ASSERT(p.typeName() == "bishop"); CPPUNIT_ASSERT(p.name() == "black_bishop"); } void ChessPieceTest::test_compare() { ChessPiece a(ChessPiece::BLACK, ChessPiece::KING); ChessPiece b(ChessPiece::WHITE, ChessPiece::QUEEN); ChessPiece c(ChessPiece::BLACK, ChessPiece::KING); CPPUNIT_ASSERT(a != b); CPPUNIT_ASSERT(!(a == b)); CPPUNIT_ASSERT(a == c); CPPUNIT_ASSERT(c == a); CPPUNIT_ASSERT(a == a); } tagua-1.0-alpha2/tests/hlvariants/chesspiecetest.h000066400000000000000000000011701077523320400223230ustar00rootroot00000000000000#ifndef CHESSPIECETEST_H #define CHESSPIECETEST_H #include #include #include #include #include namespace HLVariant { namespace Chess { class Piece; } } class ChessPieceTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ChessPieceTest); CPPUNIT_TEST(test_basic); CPPUNIT_TEST(test_names); CPPUNIT_TEST(test_compare); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void test_basic(); void test_names(); void test_compare(); }; #endif // CHESSPIECETEST_H tagua-1.0-alpha2/tests/hlvariants/chessserializationtest.cpp000066400000000000000000000167671077523320400244700ustar00rootroot00000000000000#include "chessserializationtest.h" #include "common.h" CPPUNIT_TEST_SUITE_REGISTRATION(ChessSerializationTest); void ChessSerializationTest::setUp() { m_state = new ChessGameState; m_check = new ChessCheck(*m_state); } void ChessSerializationTest::tearDown() { delete m_check; delete m_state; } void ChessSerializationTest::test_pawn() { m_state->setup(); ChessMove move(Point(4, 6), Point(4, 4)); CPPUNIT_ASSERT(m_check->legal(move)); ChessSerializer san(ChessSerializer::COMPACT); CPPUNIT_ASSERT_EQUAL(QString("e4"), san.serialize(move, *m_state)); ChessSerializer simple(ChessSerializer::SIMPLE); CPPUNIT_ASSERT_EQUAL(QString("e2e4"), simple.serialize(move, *m_state)); } void ChessSerializationTest::test_check() { m_state->board().set(Point(5, 5), ChessPiece(ChessPiece::BLACK, ChessPiece::KING)); m_state->board().set(Point(0, 0), ChessPiece(ChessPiece::WHITE, ChessPiece::KING)); m_state->board().set(Point(3, 5), ChessPiece(ChessPiece::WHITE, ChessPiece::BISHOP)); ChessMove move(Point(3, 5), Point(4, 4)); CPPUNIT_ASSERT(m_check->legal(move)); ChessSerializer san(ChessSerializer::COMPACT); CPPUNIT_ASSERT_EQUAL(QString("Be4+"), san.serialize(move, *m_state)); ChessSerializer simple(ChessSerializer::SIMPLE); CPPUNIT_ASSERT_EQUAL(QString("d3e4"), simple.serialize(move, *m_state)); ChessSerializer dec(ChessSerializer::DECORATED); CPPUNIT_ASSERT_EQUAL(QString("{bishop}e4+"), dec.serialize(move, *m_state)); } void ChessSerializationTest::test_check_capture() { m_state->board().set(Point(5, 5), ChessPiece(ChessPiece::BLACK, ChessPiece::KING)); m_state->board().set(Point(0, 0), ChessPiece(ChessPiece::WHITE, ChessPiece::KING)); m_state->board().set(Point(3, 5), ChessPiece(ChessPiece::WHITE, ChessPiece::BISHOP)); m_state->board().set(Point(4, 4), ChessPiece(ChessPiece::BLACK, ChessPiece::ROOK)); ChessMove move(Point(3, 5), Point(4, 4)); CPPUNIT_ASSERT(m_check->legal(move)); ChessSerializer san(ChessSerializer::COMPACT); CPPUNIT_ASSERT_EQUAL(QString("Bxe4+"), san.serialize(move, *m_state)); ChessSerializer simple(ChessSerializer::SIMPLE); CPPUNIT_ASSERT_EQUAL(QString("d3e4"), simple.serialize(move, *m_state)); ChessSerializer dec(ChessSerializer::DECORATED); CPPUNIT_ASSERT_EQUAL(QString("{bishop}xe4+"), dec.serialize(move, *m_state)); } void ChessSerializationTest::test_promotion() { m_state->board().set(Point(4, 7), ChessPiece(ChessPiece::BLACK, ChessPiece::KING)); m_state->board().set(Point(0, 0), ChessPiece(ChessPiece::WHITE, ChessPiece::KING)); m_state->board().set(Point(7, 1), ChessPiece(ChessPiece::WHITE, ChessPiece::PAWN)); ChessMove move(Point(7, 1), Point(7, 0), ChessPiece::ROOK); CPPUNIT_ASSERT(m_check->legal(move)); ChessSerializer san(ChessSerializer::COMPACT); CPPUNIT_ASSERT_EQUAL(QString("h8=R"), san.serialize(move, *m_state)); ChessSerializer simple(ChessSerializer::SIMPLE); CPPUNIT_ASSERT_EQUAL(QString("h7h8=R"), simple.serialize(move, *m_state)); ChessSerializer dec(ChessSerializer::DECORATED); CPPUNIT_ASSERT_EQUAL(QString("h8={rook}"), dec.serialize(move, *m_state)); } void ChessSerializationTest::test_promotion_capture() { m_state->board().set(Point(4, 7), ChessPiece(ChessPiece::BLACK, ChessPiece::KING)); m_state->board().set(Point(0, 0), ChessPiece(ChessPiece::WHITE, ChessPiece::KING)); m_state->board().set(Point(7, 1), ChessPiece(ChessPiece::WHITE, ChessPiece::PAWN)); m_state->board().set(Point(6, 0), ChessPiece(ChessPiece::BLACK, ChessPiece::BISHOP)); ChessMove move(Point(7, 1), Point(6, 0), ChessPiece::ROOK); CPPUNIT_ASSERT(m_check->legal(move)); ChessSerializer san(ChessSerializer::COMPACT); CPPUNIT_ASSERT_EQUAL(QString("hxg8=R"), san.serialize(move, *m_state)); ChessSerializer simple(ChessSerializer::SIMPLE); CPPUNIT_ASSERT_EQUAL(QString("h7g8=R"), simple.serialize(move, *m_state)); ChessSerializer dec(ChessSerializer::DECORATED); CPPUNIT_ASSERT_EQUAL(QString("hxg8={rook}"), dec.serialize(move, *m_state)); } void ChessSerializationTest::test_promotion_check() { m_state->board().set(Point(4, 0), ChessPiece(ChessPiece::BLACK, ChessPiece::KING)); m_state->board().set(Point(0, 0), ChessPiece(ChessPiece::WHITE, ChessPiece::KING)); m_state->board().set(Point(7, 1), ChessPiece(ChessPiece::WHITE, ChessPiece::PAWN)); ChessMove move(Point(7, 1), Point(7, 0), ChessPiece::ROOK); CPPUNIT_ASSERT(m_check->legal(move)); ChessSerializer san(ChessSerializer::COMPACT); CPPUNIT_ASSERT_EQUAL(QString("h8=R+"), san.serialize(move, *m_state)); ChessSerializer simple(ChessSerializer::SIMPLE); CPPUNIT_ASSERT_EQUAL(QString("h7h8=R"), simple.serialize(move, *m_state)); ChessSerializer dec(ChessSerializer::DECORATED); CPPUNIT_ASSERT_EQUAL(QString("h8={rook}+"), dec.serialize(move, *m_state)); } void ChessSerializationTest::test_promotion_capture_check() { m_state->board().set(Point(4, 0), ChessPiece(ChessPiece::BLACK, ChessPiece::KING)); m_state->board().set(Point(0, 0), ChessPiece(ChessPiece::WHITE, ChessPiece::KING)); m_state->board().set(Point(7, 1), ChessPiece(ChessPiece::WHITE, ChessPiece::PAWN)); m_state->board().set(Point(6, 0), ChessPiece(ChessPiece::BLACK, ChessPiece::BISHOP)); ChessMove move(Point(7, 1), Point(6, 0), ChessPiece::ROOK); CPPUNIT_ASSERT(m_check->legal(move)); ChessSerializer san(ChessSerializer::COMPACT); CPPUNIT_ASSERT_EQUAL(QString("hxg8=R+"), san.serialize(move, *m_state)); ChessSerializer simple(ChessSerializer::SIMPLE); CPPUNIT_ASSERT_EQUAL(QString("h7g8=R"), simple.serialize(move, *m_state)); ChessSerializer dec(ChessSerializer::DECORATED); CPPUNIT_ASSERT_EQUAL(QString("hxg8={rook}+"), dec.serialize(move, *m_state)); } void ChessSerializationTest::test_castling_k() { m_state->setup(); m_state->board().set(Point(5, 7), ChessPiece()); m_state->board().set(Point(6, 7), ChessPiece()); ChessMove move(Point(4, 7), Point(6, 7)); CPPUNIT_ASSERT(m_check->legal(move)); ChessSerializer san(ChessSerializer::COMPACT); CPPUNIT_ASSERT_EQUAL(QString("O-O"), san.serialize(move, *m_state)); ChessSerializer simple(ChessSerializer::SIMPLE); CPPUNIT_ASSERT_EQUAL(QString("e1g1"), simple.serialize(move, *m_state)); ChessSerializer dec(ChessSerializer::DECORATED); CPPUNIT_ASSERT_EQUAL(QString("O-O"), dec.serialize(move, *m_state)); } void ChessSerializationTest::test_castling_q() { m_state->setup(); m_state->board().set(Point(3, 7), ChessPiece()); m_state->board().set(Point(2, 7), ChessPiece()); m_state->board().set(Point(1, 7), ChessPiece()); ChessMove move(Point(4, 7), Point(2, 7)); CPPUNIT_ASSERT(m_check->legal(move)); ChessSerializer san(ChessSerializer::COMPACT); CPPUNIT_ASSERT_EQUAL(QString("O-O-O"), san.serialize(move, *m_state)); ChessSerializer simple(ChessSerializer::SIMPLE); CPPUNIT_ASSERT_EQUAL(QString("e1c1"), simple.serialize(move, *m_state)); ChessSerializer dec(ChessSerializer::DECORATED); CPPUNIT_ASSERT_EQUAL(QString("O-O-O"), dec.serialize(move, *m_state)); } void ChessSerializationTest::regression_knight_king() { m_state->setup(); ChessMove move(Point(6, 7), Point(5, 5)); CPPUNIT_ASSERT(m_check->legal(move)); ChessSerializer san(ChessSerializer::COMPACT); CPPUNIT_ASSERT_EQUAL(QString("Nf3"), san.serialize(move, *m_state)); ChessSerializer simple(ChessSerializer::SIMPLE); CPPUNIT_ASSERT_EQUAL(QString("g1f3"), simple.serialize(move, *m_state)); ChessSerializer dec(ChessSerializer::DECORATED); CPPUNIT_ASSERT_EQUAL(QString("{knight}f3"), dec.serialize(move, *m_state)); } tagua-1.0-alpha2/tests/hlvariants/chessserializationtest.h000066400000000000000000000027721077523320400241240ustar00rootroot00000000000000#ifndef CHESSSERIALIZATIONTEST_H #define CHESSSERIALIZATIONTEST_H #include #include #include #include #include #include "hlvariant/variantdata.h" #include "hlvariant/chess/variant.h" typedef HLVariant::Chess::Variant Chess; typedef VariantData::LegalityCheck ChessCheck; typedef VariantData::GameState ChessGameState; typedef VariantData::Serializer ChessSerializer; typedef VariantData::Piece ChessPiece; typedef VariantData::Move ChessMove; class ChessSerializationTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ChessSerializationTest); CPPUNIT_TEST(test_pawn); CPPUNIT_TEST(test_check); CPPUNIT_TEST(test_check_capture); CPPUNIT_TEST(test_promotion); CPPUNIT_TEST(test_promotion_capture); CPPUNIT_TEST(test_promotion_check); CPPUNIT_TEST(test_promotion_capture_check); CPPUNIT_TEST(test_castling_k); CPPUNIT_TEST(test_castling_q); CPPUNIT_TEST(regression_knight_king); CPPUNIT_TEST_SUITE_END(); private: ChessGameState* m_state; ChessCheck* m_check; public: void setUp(); void tearDown(); void test_pawn(); void test_check(); void test_check_capture(); void test_promotion(); void test_promotion_capture(); void test_promotion_check(); void test_promotion_capture_check(); void test_castling_k(); void test_castling_q(); void regression_knight_king(); }; #endif // CHESSSERIALIZATIONTEST_H tagua-1.0-alpha2/tests/hlvariants/chesswrappedtest.cpp000066400000000000000000000062641077523320400232440ustar00rootroot00000000000000#include "chesswrappedtest.h" #include "hlvariant/tagua_wrapped.h" #include "hlvariant/chess/variant.h" #include "hlvariant/variantdata.h" #define MOVE(x) { MovePtr _tmp = m_pos->getMove(#x); \ CPPUNIT_ASSERT(_tmp); \ m_pos->move(_tmp); } CPPUNIT_TEST_SUITE_REGISTRATION(ChessWrappedTest); typedef HLVariant::Chess::Variant Chess; typedef VariantData::LegalityCheck LegalityCheck; typedef VariantData::MoveGenerator MoveGenerator; typedef LegalityCheck::GameState GameState; typedef GameState::Move ChessMove; typedef VariantData::Piece ChessPiece; void ChessWrappedTest::setUp() { m_pos = PositionPtr(new HLVariant::WrappedPosition(GameState())); } void ChessWrappedTest::tearDown() { m_pos.reset(); } void ChessWrappedTest::test_setup() { m_pos->setup(); CPPUNIT_ASSERT(m_pos->get(Point(4, 1))); CPPUNIT_ASSERT_EQUAL(QString("black_pawn"), m_pos->get(Point(4, 1))->name()); CPPUNIT_ASSERT(m_pos->get(Point(4, 6))); CPPUNIT_ASSERT(m_pos->get(Point(4, 6))->name() == "white_pawn"); CPPUNIT_ASSERT(!m_pos->get(Point(5, 5))); CPPUNIT_ASSERT(m_pos->get(Point(0, 0))); CPPUNIT_ASSERT(m_pos->get(Point(0, 0))->name() == "black_rook"); } void ChessWrappedTest::test_move() { m_pos->setup(); MovePtr move(new HLVariant::WrappedMove(ChessMove(Point(4, 6), Point(4, 4)))); CPPUNIT_ASSERT(m_pos->testMove(move)); m_pos->move(move); CPPUNIT_ASSERT(!m_pos->get(Point(4, 6))); CPPUNIT_ASSERT(m_pos->get(Point(4, 4))->name() == "white_pawn"); } void ChessWrappedTest::test_movable() { m_pos->setup(); TurnTest test; CPPUNIT_ASSERT_EQUAL(NoAction, m_pos->movable(test, Point(4, 6))); CPPUNIT_ASSERT_EQUAL(NoAction, m_pos->droppable(test, 0)); test.setSimplePolicy(0, true); CPPUNIT_ASSERT_EQUAL(Moving, m_pos->movable(test, Point(4, 6))); CPPUNIT_ASSERT_EQUAL(NoAction, m_pos->movable(test, Point(5, 5))); CPPUNIT_ASSERT_EQUAL(NoAction, m_pos->movable(test, Point(7, 1))); CPPUNIT_ASSERT_EQUAL(Moving, m_pos->droppable(test, 0)); CPPUNIT_ASSERT_EQUAL(NoAction, m_pos->droppable(test, 1)); test.setSimplePolicy(1, true); CPPUNIT_ASSERT_EQUAL(Premoving, m_pos->movable(test, Point(6, 0))); } void ChessWrappedTest::test_san1() { m_pos->setup(); MovePtr move(new HLVariant::WrappedMove(ChessMove(Point(4, 6), Point(4, 4)))); CPPUNIT_ASSERT_EQUAL(QString("e4"), move->SAN(m_pos)); } void ChessWrappedTest::test_get_move1() { m_pos->setup(); MovePtr move = m_pos->getMove("e4"); CPPUNIT_ASSERT_EQUAL(QString("e4"), move->SAN(m_pos)); } void ChessWrappedTest::test_fools_mate() { m_pos->setup(); MOVE(f3); MOVE(e5); MOVE(g4); MOVE(Qh4); HLVariant::WrappedPosition* pos = dynamic_cast*>(m_pos.get()); CPPUNIT_ASSERT(pos); MoveGenerator generator(pos->inner()); CPPUNIT_ASSERT(generator.check(static_cast(m_pos->turn()))); CPPUNIT_ASSERT(generator.stalled()); } void ChessWrappedTest::test_check() { m_pos->setup(); MOVE(e4); MOVE(d5); MOVE(Bb5); CPPUNIT_ASSERT(!m_pos->getMove("Na6")); CPPUNIT_ASSERT(m_pos->getMove("Nc6")); } #undef MOVE tagua-1.0-alpha2/tests/hlvariants/chesswrappedtest.h000066400000000000000000000015111077523320400226770ustar00rootroot00000000000000#ifndef CHESSWRAPPEDTEST_H #define CHESSWRAPPEDTEST_H #include #include #include #include #include #include "fwd.h" class ChessWrappedTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ChessWrappedTest); CPPUNIT_TEST(test_setup); CPPUNIT_TEST(test_move); CPPUNIT_TEST(test_movable); CPPUNIT_TEST(test_san1); CPPUNIT_TEST(test_get_move1); CPPUNIT_TEST(test_fools_mate); CPPUNIT_TEST(test_check); CPPUNIT_TEST_SUITE_END(); private: PositionPtr m_pos; public: void setUp(); void tearDown(); void test_setup(); void test_move(); void test_movable(); void test_san1(); void test_get_move1(); void test_fools_mate(); void test_check(); }; #endif // CHESSWRAPPEDTEST_H tagua-1.0-alpha2/tests/hlvariants/pooltest.cpp000066400000000000000000000067171077523320400215300ustar00rootroot00000000000000#include "pooltest.h" #include "hlvariant/pool.h" #include "hlvariant/poolcollection.h" #include "hlvariant/chess/piece.h" CPPUNIT_TEST_SUITE_REGISTRATION(PoolTest); void PoolTest::setUp() { m_pools = new ChessPoolCollection; } void PoolTest::tearDown() { delete m_pools; } void PoolTest::test_empty_pool() { CPPUNIT_ASSERT(m_pools->pool(ChessPiece::WHITE).empty()); CPPUNIT_ASSERT_EQUAL(0, m_pools->pool(ChessPiece::WHITE).count(ChessPiece::KING)); } void PoolTest::test_add() { m_pools->pool(ChessPiece::WHITE).add(ChessPiece::KNIGHT); CPPUNIT_ASSERT_EQUAL(1, m_pools->pool(ChessPiece::WHITE).count(ChessPiece::KNIGHT)); m_pools->pool(ChessPiece::WHITE).add(ChessPiece::KNIGHT); CPPUNIT_ASSERT_EQUAL(2, m_pools->pool(ChessPiece::WHITE).count(ChessPiece::KNIGHT)); } void PoolTest::test_remove() { m_pools->pool(ChessPiece::WHITE).add(ChessPiece::ROOK); m_pools->pool(ChessPiece::WHITE).add(ChessPiece::ROOK); m_pools->pool(ChessPiece::WHITE).remove(ChessPiece::ROOK); CPPUNIT_ASSERT_EQUAL(1, m_pools->pool(ChessPiece::WHITE).count(ChessPiece::ROOK)); } void PoolTest::test_remove_clear() { m_pools->pool(ChessPiece::WHITE).add(ChessPiece::ROOK); m_pools->pool(ChessPiece::WHITE).remove(ChessPiece::ROOK); CPPUNIT_ASSERT_EQUAL(0, m_pools->pool(ChessPiece::WHITE).count(ChessPiece::ROOK)); CPPUNIT_ASSERT(m_pools->pool(ChessPiece::WHITE).empty()); } void PoolTest::test_size() { CPPUNIT_ASSERT_EQUAL(0, m_pools->pool(ChessPiece::WHITE).size()); m_pools->pool(ChessPiece::WHITE).add(ChessPiece::ROOK); m_pools->pool(ChessPiece::WHITE).add(ChessPiece::ROOK); m_pools->pool(ChessPiece::WHITE).add(ChessPiece::KNIGHT); m_pools->pool(ChessPiece::WHITE).add(ChessPiece::KNIGHT); m_pools->pool(ChessPiece::WHITE).add(ChessPiece::KNIGHT); m_pools->pool(ChessPiece::WHITE).add(ChessPiece::BISHOP); m_pools->pool(ChessPiece::BLACK).add(ChessPiece::BISHOP); CPPUNIT_ASSERT_EQUAL(6, m_pools->pool(ChessPiece::WHITE).size()); CPPUNIT_ASSERT_EQUAL(1, m_pools->pool(ChessPiece::BLACK).size()); } void PoolTest::test_empty_remove() { m_pools->pool(ChessPiece::WHITE).remove(ChessPiece::BISHOP); CPPUNIT_ASSERT_EQUAL(0, m_pools->pool(ChessPiece::WHITE).count(ChessPiece::ROOK)); CPPUNIT_ASSERT(m_pools->pool(ChessPiece::WHITE).empty()); } void PoolTest::test_pool_equality() { CPPUNIT_ASSERT(m_pools->pool(ChessPiece::WHITE) != m_pools->pool(ChessPiece::BLACK)); CPPUNIT_ASSERT(m_pools->pool(ChessPiece::WHITE) == m_pools->pool(ChessPiece::WHITE)); ChessPoolCollection other; other.pool(ChessPiece::BLACK).add(ChessPiece::KING); CPPUNIT_ASSERT(m_pools->pool(ChessPiece::BLACK) != other.pool(ChessPiece::BLACK)); other.pool(ChessPiece::BLACK).remove(ChessPiece::KING); CPPUNIT_ASSERT(m_pools->pool(ChessPiece::BLACK) == other.pool(ChessPiece::BLACK)); other.pool(ChessPiece::WHITE).add(ChessPiece::ROOK); m_pools->pool(ChessPiece::WHITE).add(ChessPiece::ROOK); CPPUNIT_ASSERT(m_pools->pool(ChessPiece::WHITE) == other.pool(ChessPiece::WHITE)); } void PoolTest::test_collection_equality() { CPPUNIT_ASSERT((*m_pools) == (*m_pools)); ChessPoolCollection other; other.pool(ChessPiece::BLACK).add(ChessPiece::KING); CPPUNIT_ASSERT((*m_pools) != other); other.pool(ChessPiece::BLACK).remove(ChessPiece::KING); CPPUNIT_ASSERT((*m_pools) == other); other.pool(ChessPiece::WHITE).add(ChessPiece::ROOK); m_pools->pool(ChessPiece::WHITE).add(ChessPiece::ROOK); CPPUNIT_ASSERT((*m_pools) == other); } tagua-1.0-alpha2/tests/hlvariants/pooltest.h000066400000000000000000000022721077523320400211650ustar00rootroot00000000000000#ifndef POOLTEST_H #define POOLTEST_H #include #include #include #include #include namespace HLVariant { template class Pool; template class PoolCollection; namespace Chess { class Piece; } } typedef HLVariant::Chess::Piece ChessPiece; typedef HLVariant::Pool ChessPool; typedef HLVariant::PoolCollection ChessPoolCollection; class PoolTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(PoolTest); CPPUNIT_TEST(test_empty_pool); CPPUNIT_TEST(test_add); CPPUNIT_TEST(test_remove); CPPUNIT_TEST(test_remove_clear); CPPUNIT_TEST(test_size); CPPUNIT_TEST(test_empty_remove); CPPUNIT_TEST(test_pool_equality); CPPUNIT_TEST(test_collection_equality); CPPUNIT_TEST_SUITE_END(); private: ChessPoolCollection* m_pools; public: void setUp(); void tearDown(); void test_empty_pool(); void test_add(); void test_remove(); void test_remove_clear(); void test_size(); void test_empty_remove(); void test_pool_equality(); void test_collection_equality(); }; #endif // POOLTEST_H tagua-1.0-alpha2/tests/hlvariants/shogideserializationtest.cpp000066400000000000000000000015531077523320400247700ustar00rootroot00000000000000#include "shogideserializationtest.h" CPPUNIT_TEST_SUITE_REGISTRATION(ShogiDeserializationTest); void ShogiDeserializationTest::setUp() { m_state = new ShogiGameState; } void ShogiDeserializationTest::tearDown() { delete m_state; } void ShogiDeserializationTest::regression_P_drop_2c() { ShogiSerializer s(ShogiSerializer::SIMPLE); m_state->pools().pool(ShogiPiece::BLACK).add(ShogiPiece::PAWN); ShogiMove m = s.deserialize("P*2c", *m_state); CPPUNIT_ASSERT(m.drop() == ShogiPiece(ShogiPiece::BLACK, ShogiPiece::PAWN)); CPPUNIT_ASSERT(m.to() == Point(7, 2)); m_state->setup(); m_state->board().set(Point(7, 2), ShogiPiece()); m_state->board().set(Point(7, 6), ShogiPiece()); m = s.deserialize("P*2c", *m_state); CPPUNIT_ASSERT(m.drop() == ShogiPiece(ShogiPiece::BLACK, ShogiPiece::PAWN)); CPPUNIT_ASSERT(m.to() == Point(7, 2)); } tagua-1.0-alpha2/tests/hlvariants/shogideserializationtest.h000066400000000000000000000016251077523320400244350ustar00rootroot00000000000000#ifndef SHOGIDESERIALIZATIONTEST_H #define SHOGIDESERIALIZATIONTEST_H #include #include #include #include #include #include "hlvariant/shogi/variant.h" #include "hlvariant/variantdata.h" using namespace HLVariant; typedef VariantData::GameState ShogiGameState; typedef VariantData::Serializer ShogiSerializer; typedef VariantData::Piece ShogiPiece; typedef VariantData::Move ShogiMove; class ShogiDeserializationTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ShogiDeserializationTest); CPPUNIT_TEST(regression_P_drop_2c); CPPUNIT_TEST_SUITE_END(); private: ShogiGameState* m_state; public: void setUp(); void tearDown(); void regression_P_drop_2c(); }; #endif // SHOGIDESERIALIZATIONTEST_H tagua-1.0-alpha2/tests/kovacevic_keene_1973.pgn000066400000000000000000000053411077523320400213020ustar00rootroot00000000000000[Event "It"] [Site "Amsterdam (Netherlands)"] [Date "1973.??.??"] [EventDate "?"] [Round "?"] [Result "1-0"] [White "Keene Raymond D"] [Black "Kovacevic Vladimir"] [ECO "A06"] [WhiteElo "?"] [BlackElo "?"] [PlyCount "50"] 1. Nf3 { Notes by Raymond Keene. } d5 2. b3 Bg4 3. Bb2 Nd7 4. g3 Bxf3 {A bold decision indicating that Black is playing for a win. This was the last round and if Kovacevic could beat me he would have tied with me.} 5. exf3 Ngf6 6. f4 e6 7. Bg2 {?! Dubious. 7 Bh3! intending the disruptive advance f4-f5 is less stereotyped.} 7...Be7 8. O-O O-O 9. d3 a5 10. a4 c6 11. Nd2 b5 12. Qe2 bxa4 {? Now White obtains the upper hand. It was essential for Black to maintain the tension with moves such as ...Rb8 and ...Re8 when his position would even be slightly preferable.} 13. Rxa4 Nb6 14. Ra2 {!} a4 15. Rfa1 axb3 16. Rxa8 Nxa8 17. Nxb3 Nb6 {Not good: White now has the opportunity to launch a variety of favourable combinations, but it's clear that Black's position is already far from satisfactory (White is better developed and his well co-ordinated pieces control the vital a-file and a1-h8 diagonal).} 18. f5 {! Inaugurating the combination. Black must accept the sacrifice, otherwise (after 19 fxe6) he would shed his e-pawn to the combined onslaught of White's pieces.} 18...exf5 19. Nd4 Qd7 20. Bh3 {! Also good was 20 Nxc6 Qxc6 21 Qxe7 but the text is more accurate. Black cannot allow the white knight to reach f5 since the threats against g7 would be intolerable.} 20...g6 {Or 20...Ng4 21 Nxf5!} 21. Bxf5 {!! Once again 21 Nxc6 Qxc6 22 Qxe7 was very good, but White has something more ambitious in mind.} 21...gxf5 22. Ra7 {!! This move visibly came as a shock to my opponent. Black has no choice but to fall in with White's plans.} 22...Qxa7 23. Nxc6 Qd7 {There are two major alternative defences: a) 23...Qa2 24 Nxe7+ Kg7 25 Nxf5+ Kg8 (or 25...Kg6 26 Ne7+ Kg7 27 Qg4+) 26 Qg4+ Nxg4 27 Ne7 mate. b) 23...Ba3! (Best) 24 Nxa7 (24 Bxf6 Qa4! is highly unclear) 24...Bxb2 when White has queen for rook and two pieces, but Black's forces are rather awkwardly placed and this enables White to increase his advantage as follows: 25 c4! Bd4 26 Nb5 Re8! 27 Qf3 Bc5 28 d4 Bf8 29 c5 Nc4 30 Qxf5, and in view of the powerful c-pawn, Black's weakened kingside and the scattered dispositions of the black army, White should win. However, this was Black's only chance of resistance. But, as so often, a combinational blow disturbs the balance of the victim's objectivity and he fails to discover the most tenacious defensive possibilities.} 24. Nxe7+ Kg7 25. Qh5 {! Completely unanswerable. For example: 25...Qxe7 26 Qg5+ Kh8 27 Bxf6+ picking up the other knight in addition; or 25...h6 26 Nxf5+ or 25...Ra8 26 Qg5+ Kf8 27 Bxf6 with Qg8 mate to follow.} 1-0 tagua-1.0-alpha2/tests/luaimage/000077500000000000000000000000001077523320400165515ustar00rootroot00000000000000tagua-1.0-alpha2/tests/luaimage/CMakeLists.txt000066400000000000000000000020641077523320400213130ustar00rootroot00000000000000 SET(this_test luaimage) FILE(GLOB_RECURSE ${this_test}_SRC_CXX *.cpp) FILE(GLOB_RECURSE ${this_test}_SRC_C *.c) SET(${this_test}_SRC ${${this_test}_SRC_CXX} ${${this_test}_SRC_C}) FILE(GLOB_RECURSE ${this_test}_UIS *.ui) # i have to do this because QT4_WRAP_UI is stupid SET(old_bin_dir ${CMAKE_CURRENT_BINARY_DIR}) SET(CMAKE_CURRENT_BINARY_DIR ${old_bin_dir}/ui) QT4_WRAP_UI(${this_test}_UIS_H ${${this_test}_UIS}) SET(CMAKE_CURRENT_BINARY_DIR ${old_bin_dir}) # QT4_AUTOMOC is not very intelligent either QT4_AUTOMOC( ${${this_test}_SRC}) ADD_EXECUTABLE( ${this_test} ${${this_test}_SRC}) INCLUDE_DIRECTORIES( . ${QT_INCLUDE_DIR} #${QT_QTNETWORK_INCLUDE_DIR} ${QT_QTSVG_INCLUDE_DIR} ${QT_QTXML_INCLUDE_DIR} ${LUA_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${KDE4_INCLUDE_DIR} ) ADD_DEFINITIONS( ${LUA_CFLAGS} ) LINK_DIRECTORIES( ${LUA_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ) TARGET_LINK_LIBRARIES(${this_test} ${QT_LIBRARIES} #${QT_QTNETWORK_LIBRARIES} ${QT_QTSVG_LIBRARIES} ${LUA_LINK_FLAGS} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ) tagua-1.0-alpha2/tests/luaimage/maintest.lua000066400000000000000000000011341077523320400210770ustar00rootroot00000000000000 import("test.lua") -- -- a = LinearGradient(Point(4,5), Point(7,13)) -- -- print("a.start = " .. tostring(a.start)) -- print("a.finish = " .. tostring(a.finish)) -- -- a[0.2] = "black" -- a[0.9] = "white" -- -- a = Point(5,6) -- a = -a -- -- print(a) -- print(Rect(1,2,3,4) == Rect(1,2,3,4)) -- -- --q,w = a[0.5] -- --print("a[0.5] = " .. tostring(q).." "..w) -- -- function theme.puppamelo(s) -- i = Image(400,400) -- --i:fill_rect(Rect(0,0,400,400),LinearGradient(Point(0,0),Point(400,400))) -- i:fill_rect(Rect(0,0,400,400),RadialGradient(Point(0,0),400,Point(200,200))) -- return i -- end tagua-1.0-alpha2/tests/luaimage/test.cpp000066400000000000000000000040301077523320400202310ustar00rootroot00000000000000#include #include #include #include #include #include "loader/theme.h" using namespace Loader; #if 0 Image do_something(LoadingContext* x) { Image i(300, 300); i.clear(); i.rotate(20); i.translate(50,-30); i.drawImage(x, QRectF(100,100,200,200), "data/white_rook.png"); i.drawSVG(x, QRectF(0,0,200,200), "data/wk.svg"); i.resetMatrix(); /*i.drawGlyph(x, QRectF(100,0,200,200), "tests_image/Enquil.ttf", 0x006B, QColor(255,0,0,128), QColor(0,128,128,96), 2.0);*/ i.drawGlyph(x, QRectF(100,0,200,200), "data/Enquil.ttf", 0x006B, Qt::blue, Qt::red, 5.0, false); Image i2(150, 150); i2.clear(); if(!i2.drawGlyph(x, QRectF(0,0,150,150), "data/Enquil.ttf", 0x0071, Qt::NoBrush, Qt::white)) { i2.drawLine(QPointF(10,10),QPointF(140,140), Qt::white, 15); i2.drawLine(QPointF(10,140),QPointF(140,10), Qt::white, 15); } i.drawImage(QRectF(50,50,200,200), i2.createShadow(10, Qt::green) ); return i; } #endif void mkWidget(QImage img) { QPainter p; p.begin(&img); p.setCompositionMode(QPainter::CompositionMode_DestinationOver); for(int i=0;idump(); delete x; #endif Theme p("maintest.lua"); p.refSize(250); mkWidget(p.getPixmap("puppamelo",250).toImage()); p.unrefSize(250); return app.exec(); } tagua-1.0-alpha2/tests/luaimage/test.lua000066400000000000000000000025161077523320400202370ustar00rootroot00000000000000 print("Hello!!") a = Rect("1",3,4,5) b = Point(4,5) print(a) a.x = -3 a:translate(b) print(a.x) print("right = "..a.right) print(a) puppamelo = Image(200,800) puppamelo:clear() if(true) then puppamelo:fill_rect(Rect(0,0,200,800), Color(255,0,0,128)) puppamelo:fill_rect(Rect(50,50,100,700), "#ffff00") puppamelo:fill_rect(Rect(75,100,50,600), "#0000ff") puppamelo:draw_image(Rect(0,0,200,200), "data/white_rook.png") puppamelo:draw_svg(Rect(0,200,200,200), "data/wk.svg") if(true) then puppamelo:fill_rect(Rect(0,400,200,200), "yellow") ziocane = Brush(Image("data/white_rook.png")) ziocane:scale(0.2,0.2) ziocane:rotate(45) ziocane = Color(255,0,0,128) puppamelo:draw_glyph(Rect(0,200,128,4*128), "data/Enquil.ttf", "0x006B", Color(0,128,0,128), ziocane, 0.0, true); end else puppamelo:fill_rect(Rect(50,50,200,800), Image("data/white_rook.png")) end teto = Image(200,200) teto:clear() teto:draw_glyph(Rect(0,0,200,200), "data/Enquil.ttf", "0x0071", "#ffff00", "#ffffff", 5.0, false) shad = teto:create_shadow(25, "#000000") puppamelo:draw_image(Rect(0,600,200,200), shad) puppamelo:draw_image(Rect(0,600,200,200), teto) theme.puppamelo = function(size) print("porca zoccola! "..size) return puppamelo; end -- --puppamelo = shad -- a:translate(a) tagua-1.0-alpha2/tests/movelist/000077500000000000000000000000001077523320400166275ustar00rootroot00000000000000tagua-1.0-alpha2/tests/movelist/CMakeLists.txt000066400000000000000000000017701077523320400213740ustar00rootroot00000000000000 SET(this_test movelist) SETUP_SOURCES(${this_test}_SRC ${this_test}_UIS) # i have to do this because QT4_WRAP_UI is stupid SET(old_bin_dir ${CMAKE_CURRENT_BINARY_DIR}) SET(CMAKE_CURRENT_BINARY_DIR ${old_bin_dir}/ui) QT4_WRAP_UI(${this_test}_UIS_H ${${this_test}_UIS}) SET(CMAKE_CURRENT_BINARY_DIR ${old_bin_dir}) # QT4_AUTOMOC is not very intelligent either QT4_AUTOMOC( ${${this_test}_SRC}) ADD_EXECUTABLE( ${this_test} ${${this_test}_SRC}) INCLUDE_DIRECTORIES( ${QT_INCLUDE_DIR} #${QT_QTNETWORK_INCLUDE_DIR} #${QT_QTSVG_INCLUDE_DIR} ${QT_QTXML_INCLUDE_DIR} #${LUA_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${KDE4_INCLUDE_DIR} . ${CMAKE_CURRENT_BINARY_DIR} ) ADD_DEFINITIONS( ${LUA_CFLAGS} -DNO_PGN ) LINK_DIRECTORIES( #${LUA_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ) TARGET_LINK_LIBRARIES(${this_test} ${QT_LIBRARIES} #${QT_QTNETWORK_LIBRARIES} #${QT_QTSVG_LIBRARIES} ${QT_QTXML_LIBRARIES} #${LUA_LINK_FLAGS} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${KDE4_KHTML_LIBS} ) tagua-1.0-alpha2/tests/movelist/main.cpp000066400000000000000000000022221077523320400202550ustar00rootroot00000000000000#include #include #include "movelist_textual.h" int main(int argc, char* argv[]) { KCmdLineArgs::init(argc, argv, argv[0], 0, KLocalizedString(), NULL); KApplication app; MoveList::Textual w; w.setMove(Index(1), 0, "e4"); w.setMove(Index(2), 1, "e5"); w.setComment(Index(2), "A good answer"); w.setMove(Index(2).next(0,1), 0, "Nf3"); w.setVComment(Index(2), 0, "Sadly, many people still play this move"); w.setComment(Index(2).next(0,1), "This move is much worse than f4"); w.setMove(Index(2).next(0,2), 1, "Nc6"); w.setMove(Index(2).next(0,3), 0, "Bb5"); w.setMove(Index(2).next(0,4), 1, "Nf6"); w.setMove(Index(2).next(0,3).next(0,1), 1, "f5"); w.setVComment(Index(2).next(0,3), 0, "Here is the confutation of Bb5"); w.setComment(Index(2).next(0,3).next(0,1), "White is hopeless"); w.setMove(Index(2).next(1,1), 0, "Nc3"); w.setVComment(Index(2), 1, "Another playable move"); w.setComment(Index(2).next(1,1), "Ok?"); w.setMove(Index(3), 0, "f4"); w.setMove(Index(4), 1, "Bc5"); w.select(Index(1)); w.select(Index(4)); //w.remove(Index(2).next(0,1)); w.show(); return app.exec(); } tagua-1.0-alpha2/tests/options/000077500000000000000000000000001077523320400164605ustar00rootroot00000000000000tagua-1.0-alpha2/tests/options/CMakeLists.txt000066400000000000000000000017231077523320400212230ustar00rootroot00000000000000 SET(this_test options) SETUP_SOURCES(${this_test}_SRC ${this_test}_UIS) # i have to do this because QT4_WRAP_UI is stupid SET(old_bin_dir ${CMAKE_CURRENT_BINARY_DIR}) SET(CMAKE_CURRENT_BINARY_DIR ${old_bin_dir}/ui) QT4_WRAP_UI(${this_test}_UIS_H ${${this_test}_UIS}) SET(CMAKE_CURRENT_BINARY_DIR ${old_bin_dir}) # QT4_AUTOMOC is not very intelligent either QT4_AUTOMOC( ${${this_test}_SRC}) ADD_EXECUTABLE( ${this_test} ${${this_test}_SRC}) INCLUDE_DIRECTORIES( ${QT_INCLUDE_DIR} #${QT_QTNETWORK_INCLUDE_DIR} ${QT_QTSVG_INCLUDE_DIR} ${QT_QTXML_INCLUDE_DIR} ${LUA_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${KDE4_INCLUDE_DIR} . ${CMAKE_CURRENT_BINARY_DIR} ) ADD_DEFINITIONS( ${LUA_CFLAGS} ) LINK_DIRECTORIES( #${LUA_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ) TARGET_LINK_LIBRARIES(${this_test} ${QT_LIBRARIES} #${QT_QTNETWORK_LIBRARIES} ${QT_QTSVG_LIBRARIES} ${QT_QTXML_LIBRARIES} ${LUA_LINK_FLAGS} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ) tagua-1.0-alpha2/tests/options/foreach.hpp000066400000000000000000000745701077523320400206150ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // foreach.hpp header file // // Copyright 2004 Eric Niebler. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Credits: // Anson Tsao - for the initial inspiration and several good suggestions. // Thorsten Ottosen - for Boost.Range, and for suggesting a way to detect // const-qualified rvalues at compile time on VC7.1+ // Russell Hind - For help porting to Borland // Alisdair Meredith - For help porting to Borland // Stefan Slapeta - For help porting to Intel #ifndef BOOST_FOREACH // MS compatible compilers support #pragma once #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include #include // for std::pair #include #include #if 0 // Some compilers let us detect even const-qualified rvalues at compile-time #if BOOST_WORKAROUND(BOOST_MSVC, >= 1310) \ || BOOST_WORKAROUND(__GNUC__, >= 4) \ || (BOOST_WORKAROUND(__GNUC__, == 3) && (__GNUC_MINOR__ >= 4)) # define BOOST_FOREACH_COMPILE_TIME_CONST_RVALUE_DETECTION #else // Some compilers allow temporaries to be bound to non-const references. // These compilers make it impossible to for BOOST_FOREACH to detect // temporaries and avoid reevaluation of the collection expression. # if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) \ || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) \ || (BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, <= 700) && defined(_MSC_VER)) \ || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x570)) \ || BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) # define BOOST_FOREACH_NO_RVALUE_DETECTION # endif // Some compilers do not correctly implement the lvalue/rvalue conversion // rules of the ternary conditional operator. # if defined(BOOST_FOREACH_NO_RVALUE_DETECTION) \ || defined(BOOST_NO_SFINAE) \ || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400)) \ || BOOST_WORKAROUND(BOOST_INTEL_WIN, <= 810) \ || BOOST_WORKAROUND(__GNUC__, < 3) \ || (BOOST_WORKAROUND(__GNUC__, == 3) && (__GNUC_MINOR__ <= 2)) \ || (BOOST_WORKAROUND(__GNUC__, == 3) && (__GNUC_MINOR__ <= 3) && defined(__APPLE_CC__)) \ || BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) \ || BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206)) # define BOOST_FOREACH_NO_CONST_RVALUE_DETECTION # else # define BOOST_FOREACH_RUN_TIME_CONST_RVALUE_DETECTION # endif #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BOOST_FOREACH_RUN_TIME_CONST_RVALUE_DETECTION # include # include # include # include #endif // This must be at global scope, hence the uglified name enum boost_foreach_argument_dependent_lookup_hack { boost_foreach_argument_dependent_lookup_hack_value }; namespace boost { // forward declarations for iterator_range template class iterator_range; // forward declarations for sub_range template class sub_range; namespace foreach { /////////////////////////////////////////////////////////////////////////////// // in_range // template inline std::pair in_range(T begin, T end) { return std::make_pair(begin, end); } /////////////////////////////////////////////////////////////////////////////// // boost::foreach::tag // typedef boost_foreach_argument_dependent_lookup_hack tag; /////////////////////////////////////////////////////////////////////////////// // boost::foreach::is_lightweight_proxy // Specialize this for user-defined collection types if they are inexpensive to copy. // This tells BOOST_FOREACH it can avoid the rvalue/lvalue detection stuff. template struct is_lightweight_proxy : boost::mpl::false_ { }; /////////////////////////////////////////////////////////////////////////////// // boost::foreach::is_noncopyable // Specialize this for user-defined collection types if they cannot be copied. // This also tells BOOST_FOREACH to avoid the rvalue/lvalue detection stuff. template struct is_noncopyable #if !defined(BOOST_BROKEN_IS_BASE_AND_DERIVED) && !defined(BOOST_NO_IS_ABSTRACT) : boost::mpl::or_< boost::is_abstract , boost::is_base_and_derived > #elif !defined(BOOST_BROKEN_IS_BASE_AND_DERIVED) : boost::is_base_and_derived #elif !defined(BOOST_NO_IS_ABSTRACT) : boost::is_abstract #else : boost::mpl::false_ #endif { }; } // namespace foreach } // namespace boost // vc6/7 needs help ordering the following overloads #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING # define BOOST_FOREACH_TAG_DEFAULT ... #else # define BOOST_FOREACH_TAG_DEFAULT boost::foreach::tag #endif /////////////////////////////////////////////////////////////////////////////// // boost_foreach_is_lightweight_proxy // Another customization point for the is_lightweight_proxy optimization, // this one works on legacy compilers. Overload boost_foreach_is_lightweight_proxy // at the global namespace for your type. template inline boost::foreach::is_lightweight_proxy * boost_foreach_is_lightweight_proxy(T *&, BOOST_FOREACH_TAG_DEFAULT) { return 0; } template inline boost::mpl::true_ * boost_foreach_is_lightweight_proxy(std::pair *&, boost::foreach::tag) { return 0; } template inline boost::mpl::true_ * boost_foreach_is_lightweight_proxy(boost::iterator_range *&, boost::foreach::tag) { return 0; } template inline boost::mpl::true_ * boost_foreach_is_lightweight_proxy(boost::sub_range *&, boost::foreach::tag) { return 0; } template inline boost::mpl::true_ * boost_foreach_is_lightweight_proxy(T **&, boost::foreach::tag) { return 0; } /////////////////////////////////////////////////////////////////////////////// // boost_foreach_is_noncopyable // Another customization point for the is_noncopyable trait, // this one works on legacy compilers. Overload boost_foreach_is_noncopyable // at the global namespace for your type. template inline boost::foreach::is_noncopyable * boost_foreach_is_noncopyable(T *&, BOOST_FOREACH_TAG_DEFAULT) { return 0; } namespace boost { namespace foreach_detail_ { /////////////////////////////////////////////////////////////////////////////// // Define some utilities for assessing the properties of expressions // typedef char yes_type; typedef char (&no_type)[2]; yes_type is_true(boost::mpl::true_ *); no_type is_true(boost::mpl::false_ *); // Extracts the desired property from the expression without evaluating it #define BOOST_FOREACH_PROTECT(expr) \ (static_cast *>(0)) template inline boost::mpl::and_ *and_(Bool1 *, Bool2 *) { return 0; } template inline boost::mpl::and_ *and_(Bool1 *, Bool2 *, Bool3 *) { return 0; } template inline boost::mpl::or_ *or_(Bool1 *, Bool2 *) { return 0; } template inline boost::mpl::or_ *or_(Bool1 *, Bool2 *, Bool3 *) { return 0; } template inline boost::mpl::not_ *not_(Bool *) { return 0; } template inline boost::mpl::false_ *is_rvalue_(T &, int) { return 0; } template inline boost::mpl::true_ *is_rvalue_(T const &, ...) { return 0; } template inline boost::is_array *is_array_(T const &) { return 0; } template inline boost::is_const *is_const_(T &) { return 0; } #ifndef BOOST_FOREACH_NO_RVALUE_DETECTION template inline boost::mpl::true_ *is_const_(T const &) { return 0; } #endif /////////////////////////////////////////////////////////////////////////////// // auto_any_t/auto_any // General utility for putting an object of any type into automatic storage struct auto_any_base { // auto_any_base must evaluate to false in boolean context so that // they can be declared in if() statements. operator bool() const { return false; } }; template struct auto_any : auto_any_base { auto_any(T const &t) : item(t) { } // temporaries of type auto_any will be bound to const auto_any_base // references, but we still want to be able to mutate the stored // data, so declare it as mutable. mutable T item; }; typedef auto_any_base const &auto_any_t; template inline BOOST_DEDUCED_TYPENAME boost::mpl::if_::type &auto_any_cast(auto_any_t a) { return static_cast const &>(a).item; } typedef boost::mpl::true_ const_; /////////////////////////////////////////////////////////////////////////////// // type2type // template struct type2type : boost::mpl::if_ { }; template struct foreach_iterator { typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if< C , range_const_iterator , range_iterator >::type type; }; template struct foreach_reference : iterator_reference::type> { }; /////////////////////////////////////////////////////////////////////////////// // encode_type // template inline type2type *encode_type(T &, boost::mpl::false_ *) { return 0; } template inline type2type *encode_type(T const &, boost::mpl::true_ *) { return 0; } /////////////////////////////////////////////////////////////////////////////// // set_false // inline bool set_false(bool &b) { return b = false; } /////////////////////////////////////////////////////////////////////////////// // to_ptr // template inline T *&to_ptr(T const &) { static T *t = 0; return t; } // Borland needs a little extra help with arrays #if 0 // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) template inline T (*&to_ptr(T (&)[N]))[N] { static T (*t)[N] = 0; return t; } #endif /////////////////////////////////////////////////////////////////////////////// // derefof // template inline T &derefof(T *t) { // This is a work-around for a compiler bug in Borland. If T* is a pointer to array type U(*)[N], // then dereferencing it results in a U* instead of U(&)[N]. The cast forces the issue. return reinterpret_cast( *const_cast( reinterpret_cast(t) ) ); } #ifdef BOOST_FOREACH_COMPILE_TIME_CONST_RVALUE_DETECTION /////////////////////////////////////////////////////////////////////////////// // Detect at compile-time whether an expression yields an rvalue or // an lvalue. This is rather non-standard, but some popular compilers // accept it. /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // rvalue_probe // template struct rvalue_probe { struct private_type_ {}; // can't ever return an array by value typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_< boost::mpl::or_, boost::is_array >, private_type_, T >::type value_type; operator value_type(); operator T &() const; }; template rvalue_probe const make_probe(T const &t); # define BOOST_FOREACH_IS_RVALUE(COL) \ boost::foreach_detail_::and_( \ boost::foreach_detail_::not_(boost::foreach_detail_::is_array_(COL)) \ , BOOST_FOREACH_PROTECT(boost::foreach_detail_::is_rvalue_( \ (true ? boost::foreach_detail_::make_probe(COL) : (COL)), 0))) #elif defined(BOOST_FOREACH_RUN_TIME_CONST_RVALUE_DETECTION) /////////////////////////////////////////////////////////////////////////////// // Detect at run-time whether an expression yields an rvalue // or an lvalue. This is 100% standard C++, but not all compilers // accept it. Also, it causes FOREACH to break when used with non- // copyable collection types. /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // rvalue_probe // template struct rvalue_probe { rvalue_probe(T &t, bool &b) : value(t) , is_rvalue(b) { } struct private_type_ {}; // can't ever return an array or an abstract type by value #ifdef BOOST_NO_IS_ABSTRACT typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_< boost::is_array, private_type_, T >::type value_type; #else typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_< boost::mpl::or_, boost::is_array >, private_type_, T >::type value_type; #endif operator value_type() { this->is_rvalue = true; return this->value; } operator T &() const { return this->value; } private: T &value; bool &is_rvalue; }; template rvalue_probe make_probe(T &t, bool &b) { return rvalue_probe(t, b); } template rvalue_probe make_probe(T const &t, bool &b) { return rvalue_probe(t, b); } /////////////////////////////////////////////////////////////////////////////// // simple_variant // holds either a T or a T const* template struct simple_variant { simple_variant(T const *t) : is_rvalue(false) { *static_cast(this->data.address()) = t; } simple_variant(T const &t) : is_rvalue(true) { ::new(this->data.address()) T(t); } simple_variant(simple_variant const &that) : is_rvalue(that.is_rvalue) { if(this->is_rvalue) ::new(this->data.address()) T(*that.get()); else *static_cast(this->data.address()) = that.get(); } ~simple_variant() { if(this->is_rvalue) this->get()->~T(); } T const *get() const { if(this->is_rvalue) return static_cast(this->data.address()); else return *static_cast(this->data.address()); } private: enum size_type { size = sizeof(T) > sizeof(T*) ? sizeof(T) : sizeof(T*) }; simple_variant &operator =(simple_variant const &); bool const is_rvalue; aligned_storage data; }; // If the collection is an array or is noncopyable, it must be an lvalue. // If the collection is a lightweight proxy, treat it as an rvalue // BUGBUG what about a noncopyable proxy? template inline BOOST_DEDUCED_TYPENAME boost::enable_if, IsProxy>::type * should_copy_impl(LValue *, IsProxy *, bool *) { return 0; } // Otherwise, we must determine at runtime whether it's an lvalue or rvalue inline bool * should_copy_impl(boost::mpl::false_ *, boost::mpl::false_ *, bool *is_rvalue) { return is_rvalue; } #endif /////////////////////////////////////////////////////////////////////////////// // contain // template inline auto_any contain(T const &t, boost::mpl::true_ *) // rvalue { return t; } template inline auto_any contain(T &t, boost::mpl::false_ *) // lvalue { // Cannot seem to get sunpro to handle addressof() with array types. #if 0 // BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x570)) return &t; #else return boost::addressof(t); #endif } #ifdef BOOST_FOREACH_RUN_TIME_CONST_RVALUE_DETECTION template auto_any > contain(T const &t, bool *rvalue) { return *rvalue ? simple_variant(t) : simple_variant(&t); } #endif ///////////////////////////////////////////////////////////////////////////// // begin // template inline auto_any::type> begin(auto_any_t col, type2type *, boost::mpl::true_ *) // rvalue { return boost::begin(auto_any_cast(col)); } template inline auto_any::type> begin(auto_any_t col, type2type *, boost::mpl::false_ *) // lvalue { typedef BOOST_DEDUCED_TYPENAME type2type::type type; typedef BOOST_DEDUCED_TYPENAME foreach_iterator::type iterator; return iterator(boost::begin(derefof(auto_any_cast(col)))); } #ifdef BOOST_FOREACH_RUN_TIME_CONST_RVALUE_DETECTION template auto_any::type> begin(auto_any_t col, type2type *, bool *) { return boost::begin(*auto_any_cast, boost::mpl::false_>(col).get()); } #endif /////////////////////////////////////////////////////////////////////////////// // end // template inline auto_any::type> end(auto_any_t col, type2type *, boost::mpl::true_ *) // rvalue { return boost::end(auto_any_cast(col)); } template inline auto_any::type> end(auto_any_t col, type2type *, boost::mpl::false_ *) // lvalue { typedef BOOST_DEDUCED_TYPENAME type2type::type type; typedef BOOST_DEDUCED_TYPENAME foreach_iterator::type iterator; return iterator(boost::end(derefof(auto_any_cast(col)))); } #ifdef BOOST_FOREACH_RUN_TIME_CONST_RVALUE_DETECTION template auto_any::type> end(auto_any_t col, type2type *, bool *) { return boost::end(*auto_any_cast, boost::mpl::false_>(col).get()); } #endif #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING template inline auto_any end(auto_any_t col, type2type *, boost::mpl::true_ *) // null-terminated C-style strings { return 0; // not used } #endif /////////////////////////////////////////////////////////////////////////////// // done // template inline bool done(auto_any_t cur, auto_any_t end, type2type *) { typedef BOOST_DEDUCED_TYPENAME foreach_iterator::type iter_t; return auto_any_cast(cur) == auto_any_cast(end); } #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING template inline bool done(auto_any_t cur, auto_any_t, type2type *) // null-terminated C-style strings { return ! *auto_any_cast(cur); } #endif /////////////////////////////////////////////////////////////////////////////// // next // template inline void next(auto_any_t cur, type2type *) { typedef BOOST_DEDUCED_TYPENAME foreach_iterator::type iter_t; ++auto_any_cast(cur); } /////////////////////////////////////////////////////////////////////////////// // deref // template inline BOOST_DEDUCED_TYPENAME foreach_reference::type deref(auto_any_t cur, type2type *) { typedef BOOST_DEDUCED_TYPENAME foreach_iterator::type iter_t; return *auto_any_cast(cur); } } // namespace foreach_detail_ } // namespace boost // A sneaky way to get the type of the collection without evaluating the expression #define BOOST_FOREACH_TYPEOF(COL) \ (true ? 0 : boost::foreach_detail_::encode_type(COL, boost::foreach_detail_::is_const_(COL))) // returns true_* if the type is noncopyable #define BOOST_FOREACH_IS_NONCOPYABLE(COL) \ boost_foreach_is_noncopyable( \ boost::foreach_detail_::to_ptr(COL) \ , boost_foreach_argument_dependent_lookup_hack_value) // returns true_* if the type is a lightweight proxy (and is not noncopyable) #define BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(COL) \ boost::foreach_detail_::and_( \ boost::foreach_detail_::not_(BOOST_FOREACH_IS_NONCOPYABLE(COL)) \ , boost_foreach_is_lightweight_proxy( \ boost::foreach_detail_::to_ptr(COL) \ , boost_foreach_argument_dependent_lookup_hack_value)) #ifdef BOOST_FOREACH_COMPILE_TIME_CONST_RVALUE_DETECTION /////////////////////////////////////////////////////////////////////////////// // R-values and const R-values supported here with zero runtime overhead /////////////////////////////////////////////////////////////////////////////// // No variable is needed to track the rvalue-ness of the collection expression # define BOOST_FOREACH_PREAMBLE() \ /**/ // Evaluate the collection expression # define BOOST_FOREACH_EVALUATE(COL) \ (COL) # define BOOST_FOREACH_SHOULD_COPY(COL) \ (true ? 0 : boost::foreach_detail_::or_( \ BOOST_FOREACH_IS_RVALUE(COL) \ , BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(COL))) #elif defined(BOOST_FOREACH_RUN_TIME_CONST_RVALUE_DETECTION) /////////////////////////////////////////////////////////////////////////////// // R-values and const R-values supported here /////////////////////////////////////////////////////////////////////////////// // Declare a variable to track the rvalue-ness of the collection expression # define BOOST_FOREACH_PREAMBLE() \ if (bool _foreach_is_rvalue = false) {} else // Evaluate the collection expression, and detect if it is an lvalue or and rvalue # define BOOST_FOREACH_EVALUATE(COL) \ (true ? boost::foreach_detail_::make_probe((COL), _foreach_is_rvalue) : (COL)) // The rvalue/lvalue-ness of the collection expression is determined dynamically, unless // type type is an array or is noncopyable or is non-const, in which case we know it's an lvalue. // If the type happens to be a lightweight proxy, always make a copy. # define BOOST_FOREACH_SHOULD_COPY(COL) \ (boost::foreach_detail_::should_copy_impl( \ true ? 0 : boost::foreach_detail_::or_( \ boost::foreach_detail_::is_array_(COL) \ , BOOST_FOREACH_IS_NONCOPYABLE(COL) \ , boost::foreach_detail_::not_(boost::foreach_detail_::is_const_(COL))) \ , true ? 0 : BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(COL) \ , &_foreach_is_rvalue)) #elif !defined(BOOST_FOREACH_NO_RVALUE_DETECTION) /////////////////////////////////////////////////////////////////////////////// // R-values supported here, const R-values NOT supported here /////////////////////////////////////////////////////////////////////////////// // No variable is needed to track the rvalue-ness of the collection expression # define BOOST_FOREACH_PREAMBLE() \ /**/ // Evaluate the collection expression # define BOOST_FOREACH_EVALUATE(COL) \ (COL) // Determine whether the collection expression is an lvalue or an rvalue. // NOTE: this gets the answer wrong for const rvalues. # define BOOST_FOREACH_SHOULD_COPY(COL) \ (true ? 0 : boost::foreach_detail_::or_( \ boost::foreach_detail_::is_rvalue_((COL), 0) \ , BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(COL))) #else /////////////////////////////////////////////////////////////////////////////// // R-values NOT supported here /////////////////////////////////////////////////////////////////////////////// // No variable is needed to track the rvalue-ness of the collection expression # define BOOST_FOREACH_PREAMBLE() \ /**/ // Evaluate the collection expression # define BOOST_FOREACH_EVALUATE(COL) \ (COL) // Can't use rvalues with BOOST_FOREACH (unless they are lightweight proxies) # define BOOST_FOREACH_SHOULD_COPY(COL) \ (true ? 0 : BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(COL)) #endif #define BOOST_FOREACH_CONTAIN(COL) \ boost::foreach_detail_::contain( \ BOOST_FOREACH_EVALUATE(COL) \ , BOOST_FOREACH_SHOULD_COPY(COL)) #define BOOST_FOREACH_BEGIN(COL) \ boost::foreach_detail_::begin( \ _foreach_col \ , BOOST_FOREACH_TYPEOF(COL) \ , BOOST_FOREACH_SHOULD_COPY(COL)) #define BOOST_FOREACH_END(COL) \ boost::foreach_detail_::end( \ _foreach_col \ , BOOST_FOREACH_TYPEOF(COL) \ , BOOST_FOREACH_SHOULD_COPY(COL)) #define BOOST_FOREACH_DONE(COL) \ boost::foreach_detail_::done( \ _foreach_cur \ , _foreach_end \ , BOOST_FOREACH_TYPEOF(COL)) #define BOOST_FOREACH_NEXT(COL) \ boost::foreach_detail_::next( \ _foreach_cur \ , BOOST_FOREACH_TYPEOF(COL)) #define BOOST_FOREACH_DEREF(COL) \ boost::foreach_detail_::deref( \ _foreach_cur \ , BOOST_FOREACH_TYPEOF(COL)) /////////////////////////////////////////////////////////////////////////////// // BOOST_FOREACH // // For iterating over collections. Collections can be // arrays, null-terminated strings, or STL containers. // The loop variable can be a value or reference. For // example: // // std::list int_list(/*stuff*/); // BOOST_FOREACH(int &i, int_list) // { // /* // * loop body goes here. // * i is a reference to the int in int_list. // */ // } // // Alternately, you can declare the loop variable first, // so you can access it after the loop finishes. Obviously, // if you do it this way, then the loop variable cannot be // a reference. // // int i; // BOOST_FOREACH(i, int_list) // { ... } // #define BOOST_FOREACH(VAR, COL) \ BOOST_FOREACH_PREAMBLE() \ if (boost::foreach_detail_::auto_any_t _foreach_col = BOOST_FOREACH_CONTAIN(COL)) {} else \ if (boost::foreach_detail_::auto_any_t _foreach_cur = BOOST_FOREACH_BEGIN(COL)) {} else \ if (boost::foreach_detail_::auto_any_t _foreach_end = BOOST_FOREACH_END(COL)) {} else \ for (bool _foreach_continue = true; \ _foreach_continue && !BOOST_FOREACH_DONE(COL); \ _foreach_continue ? BOOST_FOREACH_NEXT(COL) : (void)0) \ if (boost::foreach_detail_::set_false(_foreach_continue)) {} else \ for (VAR = BOOST_FOREACH_DEREF(COL); !_foreach_continue; _foreach_continue = true) #endif tagua-1.0-alpha2/tests/options/main.cpp000066400000000000000000000042501077523320400201110ustar00rootroot00000000000000 #include #include #include #include #include "common.h" #include "settings.h" #include "option.h" #include "luaapi/loader.h" OptList opts = OptList() << OptPtr(new BoolOpt("teto", "Is this C++?", true)) << OptPtr(new BoolOpt("fufi", "Fufi?", true, OptList() << OptPtr(new BoolOpt("gni", "Gni gni?", true, OptList() << OptPtr(new ColorOpt("pappa", "Pappa?", Qt::red)) << OptPtr(new FontOpt("ciccia", "Ciccia!", QFont("Monospace"))) )) << OptPtr(new BoolOpt("gnu", "Gnu gnu?", false)) )) << OptPtr(new IntOpt("ratta", "Ratta:", 5, 0, 10)) << OptPtr(new ComboOpt("schiatta", "Fai a Paolo:", QStringList() << "Incula" << "Impala" << "Spezza" << "Uccidi" << "Tortura" )) << OptPtr(new SelectOpt("affa", "Affanculo:", BoolOptList() << BoolOptPtr(new BoolOpt("ght", "Case1", true, OptList() << OptPtr(new BoolOpt("gni2", "Gni gni?", true)) )) << BoolOptPtr(new BoolOpt("cvb", "Case2", true, OptList() << OptPtr(new StringOpt("sheshe", "She She:", "Sho shu?")) << OptPtr(new UrlOpt("shesdsshe", "She She:", "Sho shu?")) )) )); int main(int argc, char *argv[]) { KCmdLineArgs::init(argc, argv, argv[0], 0, KLocalizedString(), NULL); KApplication app; LuaApi::Loader ja(NULL); //Settings sets("test.settings"); ja.runFile("test.lua"); OptList opts2 = ja.getOptList("options"); if(ja.error()) kDebug()()() << ja.errorString() << std::endl; else { /*sets.qSettings()->beginGroup("o2"); options_list_load_from_settings(opts2, sets); sets.qSettings()->endGroup();*/ dump_options_list(opts2); OptionWidget& w2 = *new OptionWidget(opts2); w2.show(); } /*sets.qSettings()->beginGroup("o1"); options_list_load_from_settings(opts, sets); sets.qSettings()->endGroup();*/ OptionWidget w(opts); w.show(); app.exec(); /*sets.qSettings()->beginGroup("o1"); options_list_save_to_settings(opts, sets); sets.qSettings()->endGroup(); sets.qSettings()->beginGroup("o2"); options_list_save_to_settings(opts2, sets); sets.qSettings()->endGroup();*/ return 0; } tagua-1.0-alpha2/tests/options/test.lua000066400000000000000000000021741077523320400201460ustar00rootroot00000000000000 -- options = OptList { -- BoolOpt("pippo", "Pluto", true), -- BoolOpt("gnugnu", "Jerry", false, OptList{ -- BoolOpt("zio", "Porco!", true) -- }) -- } options = OptList { BoolOpt("teto", "Is this LUA?", true), BoolOpt("fufi", "Fufi?", true, OptList{ BoolOpt("gni", "Gni gni?", true, OptList { ColorOpt("pappa", "Pappa?", "red"), FontOpt("ciccia", "Ciccia!", "Monospace") }), BoolOpt("gnu", "Gnu gnu?", false) }), IntOpt("ratta", "Ratta:", 5, 0, 10), ComboOpt("schiatta", "Fai a Paolo:", {"Incula", "Impala", "Spezza","Uccidi", "Tortura"}), SelectOpt("affa", "Affanculo:", BoolOptList { BoolOpt("ght", "Case1", true, OptList { BoolOpt("gni2", "Gni gni?", true) }), BoolOpt("cvb", "Case2", true, OptList { StringOpt("sheshe", "She She:", "Sho shu?"), UrlOpt("shesdsshe", "She She:", "Sho shu?") }) }) } -- print(options) -- print(options.pippo.value) -- print(options.pippo.name) -- print(options.pippo.label) -- print(options.gnugnu.sub_options) -- print(options.gnugnu.sub_options.zio.value) tagua-1.0-alpha2/tests/settings/000077500000000000000000000000001077523320400166255ustar00rootroot00000000000000tagua-1.0-alpha2/tests/settings/.gitignore000066400000000000000000000001161077523320400206130ustar00rootroot00000000000000settings_test_automoc.cpp.files DartTestfile.txt Makefile cmake_install.cmake tagua-1.0-alpha2/tests/settings/CMakeLists.txt000066400000000000000000000007271077523320400213730ustar00rootroot00000000000000set(main_dir "../../src") SET(settings_SRC ${main_dir}/mastersettings.cpp ${main_dir}/settings.cpp settingstest.cpp ../cppunit_main.cpp ) include_directories( ${KDE4_INCLUDES} ${LUA_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${main_dir} ) kde4_add_executable(settings_test ${settings_SRC}) target_link_libraries(settings_test ${KDE4_KDEUI_LIBS} ${CPPUNIT_LIBRARIES}) add_test(settings settings_test) tagua-1.0-alpha2/tests/settings/settingstest.cpp000066400000000000000000000034721077523320400220770ustar00rootroot00000000000000#include "settingstest.h" #include "mastersettings.h" CPPUNIT_TEST_SUITE_REGISTRATION(SettingsTest); MasterSettings& SettingsTest::test_settings() { return *m_instance; } void SettingsTest::setUp() { system("rm tmp.xml"); m_instance = new MasterSettings("tmp.xml", MasterSettings::PathLookup); } void SettingsTest::tearDown() { delete m_instance; } void SettingsTest::test_null() { CPPUNIT_ASSERT(!test_settings()["dummy"]); CPPUNIT_ASSERT(!test_settings()["fourtytwo"]); } void SettingsTest::test_create_and_remove() { test_settings()["dummy"] = QColor(3, 4, 5); CPPUNIT_ASSERT(test_settings()["dummy"]); CPPUNIT_ASSERT(QColor(3, 4, 5) == test_settings()["dummy"].value()); test_settings()["dummy"].remove(); CPPUNIT_ASSERT(!test_settings()["dummy"]); } void SettingsTest::test_map() { SettingMap map = test_settings().newMap("duck", "name"); { Settings s = map.insert("paperino"); s["age"] = 34; } { Settings s = map.insert("gastone"); s["age"] = 29; } { Settings s = map.insert("qui"); s["age"] = 12; } { Settings s = map.insert("quo"); s["age"] = 12; } { Settings s = map.insert("qua"); s["age"] = 12; } CPPUNIT_ASSERT(map.size() == 5); Settings s = map.get("gastone"); CPPUNIT_ASSERT(s["age"].value() == 29); map.clear(); CPPUNIT_ASSERT(!test_settings()["duck"]); } void SettingsTest::test_array() { SettingArray array = test_settings().newArray("duck"); { Settings s = array.append(); s["name"] = "nonna papera"; } { Settings s = array.append(); s["name"] = "ciccio"; } CPPUNIT_ASSERT(array.size() == 2); Settings s = array.get(1); CPPUNIT_ASSERT(s["name"].value() == "ciccio"); array.clear(); CPPUNIT_ASSERT(!test_settings()["duck"]); } tagua-1.0-alpha2/tests/settings/settingstest.h000066400000000000000000000013231077523320400215350ustar00rootroot00000000000000#ifndef SETTINGSTEST_H #define SETTINGSTEST_H #include #include #include #include #include class MasterSettings; class SettingsTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(SettingsTest); CPPUNIT_TEST(test_null); CPPUNIT_TEST(test_create_and_remove); CPPUNIT_TEST(test_map); CPPUNIT_TEST(test_array); CPPUNIT_TEST_SUITE_END(); private: MasterSettings* m_instance; MasterSettings& test_settings(); public: void setUp(); void tearDown(); void test_null(); void test_create_and_remove(); void test_map(); void test_array(); }; #endif // SETTINGSTEST_H tagua-1.0-alpha2/tests/templates/000077500000000000000000000000001077523320400167635ustar00rootroot00000000000000tagua-1.0-alpha2/tests/templates/template.cpp.erb000066400000000000000000000004301077523320400220460ustar00rootroot00000000000000#include "<%= @name.downcase %>.h" CPPUNIT_TEST_SUITE_REGISTRATION(<%= @name %>Test); void <%= @name %>Test::setUp() { L = new LuaState(); } void <%= @name %>Test::tearDown() { delete L; } <% @tests.each do |test| %> void <%= @name %>Test::<%= test %>() { } <%- end %> tagua-1.0-alpha2/tests/templates/template.h.erb000066400000000000000000000011611077523320400215150ustar00rootroot00000000000000#ifndef CPPLUA_TEST_<%= @name.upcase %>_H #define CPPLUA_TEST_<%= @name.upcase %>_H #include #include #include #include #include class <%= @name %>Test : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(<%= @name.capitalize %>Test); <% @tests.each do |test| %> CPPUNIT_TEST(<%= test %>) <%- end %> CPPUNIT_TEST_SUITE_END(); private: public: void setUp(); void tearDown(); <% @tests.each do |test| %> void <%= test %>(); <%- end %> }; #endif // CPPLUA_TEST_<%= @name.upcase %>_H tagua-1.0-alpha2/tests/test.lua000066400000000000000000000013731077523320400164530ustar00rootroot00000000000000function out(x) dump(x, "", "") end function dump(x, indent1, indent2) mt = getmetatable(x) if mt then io.write("> metatable: ") dump(mt, "", indent2 .. " ") io.write("> object: ") else io.write(indent1) end if type(x) == "string" then io.write(x) elseif type(x) == "number" then io.write(x) elseif type(x) == "table" then print("{") for k, v in pairs(x) do dump(k, indent2 .. " ", indent2 .. " ") io.write(" = ") dump(v, "", indent2 .. " ") print("") end print(indent2 .. "}") else io.write("<" .. type(x) .. ">") end end function debug() print "Rect" out(Rect) print "" print "r" out(r) print "" end r = Rect(2, 3, 100, 400) print(r:height()) tagua-1.0-alpha2/tests/test_canvas.cpp000066400000000000000000000061221077523320400200040ustar00rootroot00000000000000#include #include #include #include "canvas.h" class Puppas : public Canvas { CanvasItem *ppp; QPoint delta; public: Puppas(QWidget *p = NULL) : Canvas(p), ppp(NULL) {} virtual ~Puppas(){} virtual void keyPressEvent ( QKeyEvent * event ) { if(event->key() == Qt::Key_Tab) (*items())[0]->raise(); } virtual void mousePressEvent ( QMouseEvent * event ) { ppp = itemAt(event->pos()); if(ppp) { delta = ppp->pos() - event->pos(); if(event->button() == Qt::LeftButton) ppp->raise(); } } virtual void mouseMoveEvent ( QMouseEvent * event ) { if(ppp) ppp->moveTo(event->pos() + delta ); } }; QPicture make_pic() { QPicture pic; QPainter p(&pic); p.setPen(Qt::yellow); p.setBrush(Qt::darkGreen); p.drawEllipse(0,0,200,100); return pic; } /*QPixmap tp(QPixmap px) { QPixmap retv(px.size); QPainter p(retv); return retv; }*/ int main(int argc, char *argv[]) { QApplication app(argc, argv); Canvas *c = new Puppas(); c->resize(500,500); CanvasGroup *cg = new CanvasGroup( c ); cg->moveTo(0,0); cg->show(); CanvasPixmap *p = new CanvasPixmap( QPixmap( "/home/monge/chess_pieces/out/img_fantasy/kboard_theme/white_rook.png"), cg ); p->moveTo(0,0); p->show(); CanvasPixmap *p2 = new CanvasPixmap( QPixmap( "/home/monge/chess_pieces/out/img_skulls/kboard_theme/black_bishop.png"), cg ); p2->moveTo(200,50); p2->show(); CanvasPixmap *p3 = new CanvasPixmap( QPixmap( "/home/monge/chess_pieces/out/img_freak/kboard_theme/white_knight.png"), c ); p3->moveTo(100,250); p3->show(); CanvasPixmap *p4 = new CanvasPixmap( QPixmap( "/home/monge/chess_pieces/out/img_spatial/kboard_theme/black_king.png"), c ); p4->moveTo(20,150); p4->show(); CanvasPixmap *p5 = new CanvasPixmap( QPixmap( "/home/monge/chess_pieces/out/img_prmi/kboard_theme/white_queen.png"), c ); p5->moveTo(300,200); p5->show(); CanvasTiledPixmap *p6 = new CanvasTiledPixmap( QPixmap( "/home/monge/chess_pieces/out/icons/20/r.png"), QSize(200,150), QPoint(0,0), false, c ); p6->moveTo(200,100); p6->show(); CanvasRectangle *p7 = new CanvasRectangle( QColor(255,0,0,192), QSize(200,150), c ); p7->moveTo(50,350); p7->show(); /* CanvasRectangle *p8a = new CanvasRectangle( QColor(128,128,0,255), QSize(1,200), c ); p8a->moveTo(200,0); p8a->show(); CanvasRectangle *p8b = new CanvasRectangle( QColor(0,128,0,255), QSize(300,1), c ); p8b->moveTo(100,80); p8b->show(); */ CanvasText *p8 = new CanvasText( "Fuck", QColor(0,0,255,192), QFont("Sans", 70, QFont::Bold), CanvasText::HCenter, CanvasText::VCenter, c ); p8->moveTo(200,80); p8->show(); CanvasPicture *p9 = new CanvasPicture( make_pic(), c ); p9->moveTo(200,100); p9->show(); c->show(); return app.exec(); } tagua-1.0-alpha2/tests/test_lua.cpp000066400000000000000000000003461077523320400173140ustar00rootroot00000000000000#include "../src/luaconfig.h" using namespace LuaLoader; int main(int argc, char** argv) { const char* file; if (argc > 1) file = argv[1]; else file = "test.lua"; Api api; api.runFile(file); return 0; } tagua-1.0-alpha2/tests/test_pgn.pgn000066400000000000000000000165321077523320400173250ustar00rootroot00000000000000 [Site "?"] [Date "????.??.??"] [Round "?"] [White "White player"] [Black "Black player"] [Result "*"] [WhiteElo "0"] [BlackElo "0"] [ECO "C30"] [TimeControl "0"] 1. e4 e5 2. f4 {This is really a good move.} Bc5 ({This is a comment at the start of a variation.} 2. ... exf4 {And this is a comment after.} 3. Nf3 g5 4. h4 g4 5. Ne5 Nf6 6. Nxg4 (6. Nc3 d6 7. Nxf7 ) ) 3. Nf3 Nc6 4. Bc4 {The bishop is attacking f7 and is threatening to checkmate the black king} d6 5. c3 (5. d3 Nf6 6. Nc3 Bg4 7. Na4 Bb4+ 8. c3 Ba5 9. Be3 (9. Bd2 Bxf3 10. Qxf3 Nh5 (10. ... O-O 11. O-O-O a6 12. b4 b5 13. bxa5 bxc4 14. d4 exd4 15. cxd4 Nxd4 ) ) Nd4 10. O-O Nxf3+ 11. gxf3 Bh3 12. Rf2 a6 (12. ... O-O 13. b4 Bb6 14. Nxb6 axb6 15. a4 Nh5 16. f5 g6 17. f4 (17. Bh6 Re8 18. f4 Nxf4 19. Bxf4 exf4 20. Qf3 Qg5+ ) Nxf4 18. Bxf4 exf4 19. Rxf4 ) 13. b4 b5 14. bxa5 {After this one white is in a hopeless position} bxc4 15. dxc4 Qd7 16. Nb2 Nh5 17. f5 ) Nf6 6. Qe2 Ng4 7. Rf1 O-O 8. d3 Be6 9. Bb3 * [White "Maurizio"] [Black "Rattatechess"] 1. e4 c5 2. Nf3 e6 3. Nc3 Nc6 4. d4 cxd4 5. Nxd4 Nf6 6. f3 Bb4 7. Be3 Bxc3+ 8. bxc3 Nxe4 9. fxe4 Qh4+ 10. Bf2 Qxe4+ 11. Qe2 Qd5 12. c4 Qd6 13. Qd3 Qb4+ 14. c3 Qb2 15. Rd1 Qxa2 16. Nxc6 bxc6 17. Bc5 Qa5 18. Qd6 Qxc3+ 19. Kf2 Qf6+ 20. Kg1 Qg5 21. h4 Qd8 22. Rh3 f5 23. Rg3 Qf6 24. Be2 Rg8 25. h5 g6 26. Bf3 Qf8 27. Qe5 Qh6 28. Rd6 Qc1+ 29. Kh2 Qxc4 30. Rxc6 g5 31. Qf6 Qxc5 32. Rxc5 f4 33. Rgxg5 Rf8 34. Qg7 Bb7 35. Bxb7 Rd8 36. Qxh7 Rf7 37. Rg7 Rxg7 38. Qxg7 Rb8 39. h6 Rd8 40. h7 Rc8 41. h8=Q# [White "Maurizio"] [Black "Rattatechess"] 1. d4 Nf6 2. c4 g6 3. Nc3 Bg7 4. e4 d6 5. Nf3 O-O 6. Bd3 c5 7. d5 Na6 8. O-O Nb4 9. Re1 Ng4 10. h3 Bxc3 11. bxc3 Nxd3 12. Qxd3 Nf6 13. e5 dxe5 14. Nxe5 Bf5 15. Qf3 Nd7 16. g4 Nxe5 17. Rxe5 Qd6 18. Bf4 Bc8 19. Rae1 Qa6 20. Rxe7 Qf6 21. Qe3 Rd8 22. Bg5 Qd6 23. Re8+ Rxe8 24. Qxe8+ Kg7 25. Be7 Be6 26. Qxa8 Qxe7 27. dxe6 fxe6 28. Qb8 b6 29. Qe5+ Qf6 30. g5 Qxe5 31. Rxe5 Kf7 32. Kg2 a6 33. a4 Ke7 34. a5 bxa5 35. Rxc5 a4 36. Ra5 e5 37. Rxa4 Kd6 38. Rxa6+ Kc5 39. Kf3 Kxc4 40. Rc6+ Kd3 41. Rc8 Kd2 42. c4 Kd3 43. c5 Kc4 44. c6 Kd5 45. Ke3 Kc5 46. Ke4 Kd6 47. f3 Kc5 48. Kxe5 Kb5 49. Kd6 Kc4 50. c7 Kd3 51. Re8 Kd2 52. c8=Q Kd3 53. Qc5 Kd2 54. Re3 Kd1 55. Qc3 h6 56. Re1# [White "Maurizio"] [Black "Rattatechess"] 1. e4 c5 2. Nf3 Nc6 3. Nc3 g6 4. d4 cxd4 5. Nxd4 Bg7 6. Be3 Nf6 7. f3 Qc7 8. Qd2 a6 9. O-O-O e5 10. Ndb5 axb5 11. Nxb5 Qb8 12. Nd6+ Kf8 13. a3 Kg8 14. Bc4 Nd8 15. Bb6 Ne6 16. Qc3 Nh5 17. Nb5 Bh6+ 18. Kb1 Bg5 19. Bxe6 Bd2 20. Rxd2 d5 21. Bxf7+ Kxf7 22. Bc7 Bd7 23. Nd6+ Kg8 24. Bxb8 Rxb8 25. Rxd5 Nf4 26. Rxe5 Ne6 27. Qb3 Kg7 28. Rxe6 Bxe6 29. Qxe6 Rhf8 30. Rd1 Rbd8 31. Qe7+ Kg8 32. Ka2 Ra8 33. Nf5 Rf7 34. Qe6 gxf5 35. Rd7 Rf8 36. exf5 b5 37. g4 Kh8 38. Rxf7 Rxf7 39. Qxf7 h5 40. g5 h4 41. g6 b4 42. Qf8# [Event "Convergence"] 1. e4 e5 2. f4 d6 3. d4 f6 4. Nf3 Nc6 5. Na3 Nh6 6. b3 Nf7 7. Nc4 Qe7 8. Nb2 g6 9. Nd3 Bg7 10. Bb2 O-O 11. Bc3 Re8 12. Qb1 b5 13. a4 bxa4 14. Rxa4 Bb7 15. Qa1 Qd7 16. Be2 Re7 17. h4 Rae8 18. h5 gxh5 19. Rxh5 Qg4 20. Ra5 Qg3+ 21. Kd1 Kh8 {E ora un magna-magna generale} 22. fxe5 fxe5 23. dxe5 dxe5 24. Nfxe5 Ncxe5 25. Nxe5 Nxe5 26. Bxe5 Bxe5 27. Rhxe5 Rxe5 28. Rxe5 Rxe5 29. Qxe5+ Qxe5 [Event "Bachetto!!!! (42. Qb1#)"] 1. e4 d5 2. exd5 Qxd5 3. Nc3 Qc6 4. Bb5 Qxb5 5. Nxb5 Na6 6. Qf3 Nf6 7. Kd1 Bg4 8. Qxg4 Nxg4 9. Nh3 O-O-O 10. f3 Ne5 11. Re1 Ng6 12. c3 Nc5 13. Nxa7+ Kb8 14. Nb5 Nd3 15. Re3 e6 16. Kc2 Nde5 17. d4 Nc4 18. Rd3 c6 19. Na3 Nxa3+ 20. bxa3 Rd5 21. Rb1 Ra5 22. Rb3 Bd6 23. g3 Rd8 24. Ng5 f6 25. Ne4 Bc7 26. Be3 Ne7 27. c4 Kc8 28. Bd2 Rh5 29. h4 f5 30. Ng5 Bxg3 31. Nxe6 Rd6 32. Nxg7 Rxh4 33. Nxf5 Nxf5 34. Kc3 Nxd4 35. c5 Rf6 36. Rxd4 Rxd4 37. Kxd4 R@d5+ 38. Kc3 Q@d3+ 39. Kb2 N@c4+ 40. Ka1 N@c2+ 41. Kb1 N2xa3+ 42. Ka1 Qb1# 43. Rxb1 Nc2# [Event "Lo stesso bachetto"] 1. d4 g6 2. d5 Nf6 3. Qd4 Bh6 4. g4 Nxg4 5. Qxh8# [Event "Reversi"] 1. f5 f6 2. f7 g7 3. c4 c3 4. c2 b2 5. e6 d6 6. e7 d8 7. g6 g5 8. f4 g8 9. h8 h7 10. a1 f3 11. f8 d3 12. h6 b3 13. h5 g4 14. e8 d7 15. c8 b1 16. c7 c6 17. h4 b8 18. a8 b7 19. b6 h3 20. g3 g2 21. c1 a3 22. a2 e3 23. f2 c5 24. a7 a6 25. b4 b5 26. a4 a5 27. h2 d2 28. d1 e2 29. e1 g1 30. h1 f1 [Event "Reversi2"] 1. f5 d6 2. c5 f6 3. c4 f4 4. e6 d7 5. e7 c7 6. g6 f8 7. g4 h6 8. g7 g5 9. f7 f3 10. e8 h8 11. g8 d8 12. f2 h7 13. c8 b8 14. c6 h5 15. b7 h4 16. h3 g3 17. e3 g2 18. d3 e2 19. a8 h1 20. h2 g1 21. b6 c2 22. b3 b5 23. c3 a6 24. e1 d2 25. f1 b4 26. a5 b2 27. d1 a7 28. a1 c1 29. b1 a3 30. a2 a4 [Event "dfasdfadf ][] \"\"\" neally nasty tag"] 1. e4 f5 2. g4 [Event "QUEEEE"] 1. d4 e6 2. c4 Nf6 3. Nc3 d5 4. Bg5 Nbd7 5. e3 Be7 6. Nf3 O-O 7. Qc2 c6 8. a3 Re8 9. Rd1 dxc4 10. Bxc4 Nd5 11. Bxe7 Qxe7 12. O-O Nxc3 13. Qxc3 c5 14. d5 exd5 15. Rxd5 b6 16. Rfd1 Rf8 17. b4 cxb4 18. axb4 Nf6 19. Re5 Qc7 20. Ng5 Bb7 21. Ne6 Qc6 22. f3 Ba6 23. Rd4 Rfc8 24. Nd8 (24. b5 Bxb5 25. Nxg7 (25. Rxb5 fxe6) Bxc4 (25. ... Kxg7 26. Rg4+ (26. Rg5+ Kh6 27. Rh4+ (27. Rf4 Kxg5 28. h4+ Kg6) (27. Qe1 Kxg5 28. Qg3+ Kf5 (28. ... Kh6 29. Rh4+ Nh5 30. Qf4+) 29. Rf4+ Ke5 30. Rg4+ (30. Rh4+ Kf5) Kf5 31. Qf4#) Kxg5 28. Qe5+ Kg6) Nxg4 (26. ... Kf8 27. Qa3+ (27. Qb4+ Qc5 28. Rxc5 Rxc5 29. Bxb5 Nxg4 30. fxg4)) (26. ... Kh6 27. Reg5 Qxc4) (26. ... Kh8 27. Re6 (27. Rxb5 Rg8 28. Rxg8+ Kxg8 (28. ... Rxg8 29. Rf5 Kg7 (29. ... Rg6 30. g4 (30. h4 Kg8 (30. ... Qd6 31. h5 Rh6 32. Bxf7 Kg7 33. Bb3)) Kg7 31. g5 b5 32. Rxb5 Qxf3) 30. Rg5+ (30. g4 b5 31. Rxb5 Kf8 32. Rb8+ Ke7 33. Qe5+ Kd7 34. Bb5) Kf8 (30. ... Kh8 31. Rxg8+) 31. Qb4+ Ke8 32. Bb5))) 27. Rg5+ Kf8 28. Qb4+ (28. Qg7+ Ke7 29. Qxf7+ Kd6 30. Qf4+ Ke7 31. Rg7+ (31. Qf7+ Kd6 32. Rd5+ Qxd5 33. Qxd5+ Kc7 34. Bxb5 Nh6) Kd8 32. Qf8# (32. Qg5+ Qf6 33. Qd5+ Ke8 34. Bxb5+) Qe8 33. Qd6+ Bd7 34. Rg8 Qxg8 35. Bxg8) Qc5 (28. ... Ke8 29. Rg8+ (29. Bxb5) Kd7) 29. Rxc5 bxc5 (29. ... Rxc5 30. Bxb5 Nf6) 30. Qxb5 Nf6 (30. ... Nh6 31. Qd7 a5 32. Qd6+ Kg7 33. Qe5+ Kg8 (33. ... Kf8 34. Qh8+ Ke7 35. Qxh7 Rh8 36. Qe4+)) 31. Qb7) 26. Rg5 (26. Nf5 Qc5 (26. ... Qc7 27. Rg4+ Kh8 28. Re8#) (26. ... Rc7 27. Rg4+ Kh8 28. Rxc4) (26. ... Qa4 27. Rg4+ (27. Re8+ Qxe8 (27. ... Nxe8 28. Rg4+ Ng7) (27. ... Rxe8 28. Rg4+ Kf8 29. Qxf6 Qd1+ 30. Kf2 Qf1+ 31. Kg3 Qe1+ 32. Kh3 Qg3+) 28. Rg4+ Kf8 29. Qb4+ (29. Qxf6) Rc5) Kf8)) Ba6 (26. ... Bd5) 27. Rd8+ Ne8 28. Rxe8# Qxe8 29. Nxe8+ Kf8 30. Qh8+ Ke7) Qc7 25. Rg4 Qxd8 26. Reg5 Qd1+ 27. Kf2 Nxg4+ 28. Rxg4 g6 29. Bxf7+ Kxf7 30. Rf4+ Kg8 31. Qf6 Qd7 [Event "A chain reaction game"] 1. d4 e4 2. d4 e4 3. d4 e4 4. d5 e5 5. d4 f5 6. e5 f5 7. e5 f7 8. e7 f7 9. e7 f7 10. d7 e7 11. d6 d7 12. c7 d7 13. c6 d6 14. c6 c5 15. d5 c7 16. c6 b8 17. a7 b8 18. a7 b8 19. a7 c8 20. b7 b5 21. d7 e8 22. d7 f6 23. a5 b5 24. b4 b5 25. b4 b5 26. b3 b4 27. c3 c4 28. a3 b4 29. a3 b5 30. b4 d6 31. c3 (31. b4 d8 (31. ... c7) 32. d5 d7 33. e5 d7 34. b5 (34. e5 d7) e8 (34. ... d8) 35. e5 f8 36. e5 f3 37. d4 d7) b7 32. c4 d7 33. b5 c6 34. a6 c6 35. b3 d6 36. b3 e6 37. e3 d7 38. e4 d8 39. e4 b7 40. f3 e8 41. b5 (41. e4) [Event "Edited CRAZYHOUSE game"] [Site "fucklandia"] [Date "2006.10.07"] [Round "-"] [White "-"] [Black "-"] [Result "*"] [Variant "crazyhouse"] [FEN "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBKQBNR w kq - 0 1"] [SetUp "1"] {-------------- r n b q k b n r p p p p p p p p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . P P P P P P P P R N B K Q B N R white to play --------------} 1. e4 d5 2. exd5 Qxd5 3. P@e3 P@e4 4. Nf3 exf3 5. gxf3 N@c4 6.P@e4 Qxe4 7. fxe4 P@f3 8. Q@g4 * tagua-1.0-alpha2/tests/test_weakset.cpp000066400000000000000000000024751077523320400202030ustar00rootroot00000000000000//#define WEAK_SET_DEBUG #include "../src/weakset.h" #include using boost::unit_test::test_suite; template uint weak_set_size(weak_set& w) { uint c = 0; for (typename weak_set::iterator i = w.begin(); i != w.end(); ++i) { ++c; } return c; } void test_insertion() { boost::shared_ptr n(new int(8)); boost::shared_ptr m(new int(1)); weak_set s; s.insert(n); s.insert(m); BOOST_CHECK_EQUAL(2, weak_set_size(s)); } void test_garbage_collection() { #ifdef WEAK_SET_DEBUG kDebug()() << "\n\ntesting garbage collection\n\n" << endl; #endif // WEAK_SET_DEBUG weak_set s; boost::shared_ptr u(new int(37)); s.insert(u); { boost::shared_ptr m(new int(1)); s.insert(m); } boost::shared_ptr n(new int(8)); s.insert(n); BOOST_CHECK_EQUAL(2, weak_set_size(s)); } void test_get() { weak_set s; boost::shared_ptr n(new int(42)); s.insert(n); BOOST_CHECK_EQUAL(42, *s.begin()); } test_suite* init_unit_test_suite(int, char*[]) { test_suite* test= BOOST_TEST_SUITE( "Weak set test suite" ); test->add(BOOST_TEST_CASE(&test_insertion), 0); test->add(BOOST_TEST_CASE(&test_garbage_collection), 0); test->add(BOOST_TEST_CASE(&test_get), 0); return test; } tagua-1.0-alpha2/tests/weak_set/000077500000000000000000000000001077523320400165675ustar00rootroot00000000000000tagua-1.0-alpha2/tests/weak_set/CMakeLists.txt000066400000000000000000000005241077523320400213300ustar00rootroot00000000000000set(main_dir "../../src") SET(weakset_SRC weakset_test.cpp ../cppunit_main.cpp ) include_directories( ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${main_dir} ) add_executable(weakset_test ${weakset_SRC}) target_link_libraries(weakset_test ${CPPUNIT_LIBRARIES}) add_test(weakset weakset_test) tagua-1.0-alpha2/tests/weak_set/test_weakset.cpp000066400000000000000000000027511077523320400220020ustar00rootroot00000000000000#include "weakset.h" #include using boost::unit_test::test_suite; template uint weak_set_size(weak_set& w) { uint c = 0; for (typename weak_set::iterator i = w.begin(); i != w.end(); ++i) { ++c; } return c; } void test_insertion() { boost::shared_ptr n(new int(8)); boost::shared_ptr m(new int(1)); weak_set s; s.insert(n); s.insert(m); BOOST_CHECK_EQUAL(2, weak_set_size(s)); } void test_garbage_collection() { #ifdef WEAK_SET_DEBUG kDebug()() << "\n\ntesting garbage collection\n\n" << endl; #endif // WEAK_SET_DEBUG weak_set s; boost::shared_ptr u(new int(37)); s.insert(u); { boost::shared_ptr m(new int(1)); s.insert(m); } boost::shared_ptr n(new int(8)); s.insert(n); BOOST_CHECK_EQUAL(2, weak_set_size(s)); } void test_get() { weak_set s; boost::shared_ptr n(new int(42)); s.insert(n); BOOST_CHECK_EQUAL(42, *s.begin()); } void test_empty() { weak_set s; { boost::shared_ptr m(new int(37)); s.insert(m); } BOOST_CHECK_EQUAL(0, weak_set_size(s)); } test_suite* init_unit_test_suite(int, char*[]) { test_suite* test= BOOST_TEST_SUITE( "Weak set test suite" ); test->add(BOOST_TEST_CASE(&test_insertion), 0); test->add(BOOST_TEST_CASE(&test_garbage_collection), 0); test->add(BOOST_TEST_CASE(&test_get), 0); test->add(BOOST_TEST_CASE(&test_empty), 0); return test; } tagua-1.0-alpha2/tests/weak_set/weakset_test.cpp000066400000000000000000000021541077523320400217770ustar00rootroot00000000000000#include "weakset_test.h" #include "weakset.h" CPPUNIT_TEST_SUITE_REGISTRATION(WeaksetTest); template uint weak_set_size(weak_set& w) { uint c = 0; for (typename weak_set::iterator i = w.begin(); i != w.end(); ++i) { ++c; } return c; } void WeaksetTest::test_insertion() { boost::shared_ptr n(new int(8)); boost::shared_ptr m(new int(1)); weak_set s; s.insert(n); s.insert(m); CPPUNIT_ASSERT_EQUAL(2U, weak_set_size(s)); } void WeaksetTest::test_garbage_collection() { weak_set s; boost::shared_ptr u(new int(37)); s.insert(u); { boost::shared_ptr m(new int(1)); s.insert(m); } boost::shared_ptr n(new int(8)); s.insert(n); CPPUNIT_ASSERT_EQUAL(2U, weak_set_size(s)); } void WeaksetTest::test_get() { weak_set s; boost::shared_ptr n(new int(42)); s.insert(n); CPPUNIT_ASSERT_EQUAL(42, *s.begin()); } void WeaksetTest::test_empty() { weak_set s; { boost::shared_ptr m(new int(37)); s.insert(m); } CPPUNIT_ASSERT_EQUAL(0U, weak_set_size(s)); } tagua-1.0-alpha2/tests/weak_set/weakset_test.h000066400000000000000000000011771077523320400214500ustar00rootroot00000000000000#ifndef WEAKSETTEST_H #define WEAKSETTEST_H #include #include #include #include #include class WeaksetTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(WeaksetTest); CPPUNIT_TEST(test_insertion); CPPUNIT_TEST(test_garbage_collection); CPPUNIT_TEST(test_get); CPPUNIT_TEST(test_empty); CPPUNIT_TEST_SUITE_END(); public: void setUp() { } void tearDown() { } void test_insertion(); void test_garbage_collection(); void test_get(); void test_empty(); }; #endif // WEAKSETTEST_H tagua-1.0-alpha2/translations/000077500000000000000000000000001077523320400163445ustar00rootroot00000000000000tagua-1.0-alpha2/translations/CMakeLists.txt000066400000000000000000000015241077523320400211060ustar00rootroot00000000000000find_program(GETTEXT_MSGFMT_EXECUTABLE msgfmt) if(NOT GETTEXT_MSGFMT_EXECUTABLE) message("NOTE: msgfmt not found. Translations will *not* be installed") else(NOT GETTEXT_MSGFMT_EXECUTABLE) set(catalogname tagua) file(GLOB PO_FILES *.po) foreach(_poFile ${PO_FILES}) message("Found translation: ${_poFile}") get_filename_component(_lang ${_poFile} NAME_WE) set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo) add_custom_command(OUTPUT ${_gmoFile} COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} --check -o ${_gmoFile} ${_poFile} DEPENDS ${_poFile}) add_custom_target(translation-${_lang} ALL DEPENDS ${_gmoFile}) install(FILES ${_gmoFile} DESTINATION ${LOCALE_INSTALL_DIR}/${_lang}/LC_MESSAGES/ RENAME ${catalogname}.mo) endforeach(_poFile ${PO_FILES}) endif(NOT GETTEXT_MSGFMT_EXECUTABLE) tagua-1.0-alpha2/translations/cs.po000066400000000000000000000420551077523320400173170ustar00rootroot00000000000000# translation of cs.po to čeština # translation of cs.po to # translation of tagua.pot to Czech # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Karel Volný , 2007. msgid "" msgstr "" "Project-Id-Version: cs\n" "Report-Msgid-Bugs-To: http://trac.tagua-project.org\n" "POT-Creation-Date: 2008-02-26 23:43+0000\n" "PO-Revision-Date: 2007-11-29 18:54+0100\n" "Last-Translator: Karel Volný \n" "Language-Team: čeština \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" #: main.cpp:35 msgid "Tagua" msgstr "Tagua" #: main.cpp:37 msgid "(C) 2006 Paolo Capriotti, Maurizio Monge" msgstr "© 2006 Paolo Capriotti, Maurizio Monge" #: main.cpp:38 msgid "Paolo Capriotti" msgstr "Paolo Capriotti" #: main.cpp:39 msgid "Maurizio Monge" msgstr "Maurizio Monge" #: main.cpp:40 msgid "Jani Huhtanen" msgstr "Jani Huhtanen" #: main.cpp:40 msgid "Gaussian blur code" msgstr "kód gausovského rozostření" #: main.cpp:41 msgid "Rici Lake" msgstr "Rici Lake" #: main.cpp:41 msgid "funclib lua library" msgstr "knihovna funclib pro lua" #: main.cpp:42 msgid "Riccardo Iaconelli" msgstr "Riccardo Iaconelli" #: main.cpp:42 msgid "Various fixes and cleanups" msgstr "různé opravy a pročištění" #: main.cpp:43 msgid "Yann Dirson" msgstr "Yann Dirson" #: main.cpp:43 msgid "Shogi related patches" msgstr "patche pro šógi" #: main.cpp:44 msgid "Pieter Stouten" msgstr "Pieter Stouten" #: main.cpp:44 msgid "Allowed free use of images on shogi.net" msgstr "umožnění volného použití obrázků ze shogi.net" #: main.cpp:47 msgid "Initial variant" msgstr "původní varianta" #: mainwindow.cpp:79 msgid "Move list" msgstr "Seznam tahů" #: mainwindow.cpp:89 msgid "FICS Connection" msgstr "Připojení k FICS" #: mainwindow.cpp:92 msgid "Console" msgstr "Konsole" #: mainwindow.cpp:129 msgid "E&ngines" msgstr "&Programy" #: mainwindow.cpp:143 msgid "Play as &white" msgstr "Hrát za &bílého" #: mainwindow.cpp:149 msgid "Play as &black" msgstr "Hrát za &černého" #: mainwindow.cpp:156 msgid "&Analyze" msgstr "&Analyzovat" #: mainwindow.cpp:175 msgid "&Back" msgstr "&Zpět" #: mainwindow.cpp:176 msgid "&Forward" msgstr "&Vpřed" #: mainwindow.cpp:177 msgid "Be&gin" msgstr "Z&ačátek" #: mainwindow.cpp:178 msgid "&End" msgstr "&Konec" #: mainwindow.cpp:179 msgid "&Connect" msgstr "&Připojit" #: mainwindow.cpp:181 msgid "&Disconnect" msgstr "&Odpojit" #: mainwindow.cpp:188 msgid "&Edit position" msgstr "&Upravit posici" #: mainwindow.cpp:189 msgid "&Clear board" msgstr "&Vyčistit desku" #: mainwindow.cpp:190 msgid "&Set starting position" msgstr "&Nastavit počáteční posici" #: mainwindow.cpp:194 msgid "&Flip view" msgstr "&Otočit desku" #: mainwindow.cpp:196 msgid "Toggle &console" msgstr "Přepnout &konsoli" #: mainwindow.cpp:197 msgid "Toggle &move list" msgstr "Přepnout &seznam tahů" #: mainwindow.cpp:420 msgid "You have specified a folder" msgstr "Byl vybrán adresář" #: mainwindow.cpp:420 mainwindow.cpp:425 mainwindow.cpp:432 mainwindow.cpp:647 msgid "Error" msgstr "Chyba" #: mainwindow.cpp:425 msgid "The specified file does not exist" msgstr "Zadaný soubor neexistuje" #: mainwindow.cpp:432 msgid "You do not have read permission to this file." msgstr "Nemáte potřebná oprávnění k tomuto souboru." #: mainwindow.cpp:447 msgid "Open PGN file" msgstr "Otevřít soubor PNG" #: mainwindow.cpp:469 msgid "Save PGN file" msgstr "Uložit soubor PNG" #: mainwindow.cpp:481 msgid "" "A file named \"%1\" already exists. Are you sure you want to overwrite it?" msgstr "" #: mainwindow.cpp:483 msgid "Overwrite File?" msgstr "" #: mainwindow.cpp:484 msgid "&Overwrite" msgstr "" #: mainwindow.cpp:647 msgid "Error creating game" msgstr "Chyba při vytváření hry" #: mainwindow.cpp:687 msgid "Illegal move" msgstr "Neplatný tah" #: movelist.cpp:684 movelist.cpp:725 msgid "&Set Comment" msgstr "" #: movelist.cpp:687 msgid "&Promote Variation" msgstr "" #: movelist.cpp:689 msgid "&Remove Variation" msgstr "" #: movelist.cpp:727 #, fuzzy msgid "&Clear Variations" msgstr "&Vyčistit desku" #: movelist.cpp:730 msgid "&Truncate" msgstr "" #: movelist.cpp:734 msgid "&Promote variation" msgstr "" #: movelist.cpp:737 msgid "&Remove variation" msgstr "" #: pref_engines.cpp:39 msgid "&Name:" msgstr "&Jméno:" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 136 #: pref_engines.cpp:47 extractedrc.cpp:131 msgid "&Type:" msgstr "&Typ:" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 147 #: pref_engines.cpp:52 extractedrc.cpp:134 msgid "XBoard" msgstr "XBoard" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 152 #: pref_engines.cpp:53 extractedrc.cpp:137 msgid "UCI" msgstr "UCI" #: pref_engines.cpp:54 msgid "Tagua (textual)" msgstr "Tagua (textové)" #: pref_engines.cpp:55 msgid "Tagua (DBUS)" msgstr "Tagua (DBUS)" #: pref_engines.cpp:56 msgid "GNU Shogi" msgstr "GNU Shogi" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 113 #: pref_engines.cpp:61 extractedrc.cpp:128 msgid "&Path:" msgstr "&Cesta:" #: pref_engines.cpp:70 msgid "&Work directory:" msgstr "Pracovní &adresář:" #: pref_engines.cpp:93 msgid "Choose a name for the engine" msgstr "Zvolte jméno pro program" #: pref_engines.cpp:93 msgid "No engine name" msgstr "Není jméno pro program" #: pref_engines.cpp:117 #, fuzzy msgid "&New..." msgstr "…" #: pref_engines.cpp:119 #, fuzzy msgid "&Edit..." msgstr "Ú&pravy" #: pref_engines.cpp:121 msgid "&Delete" msgstr "" #: pref_theme.cpp:344 msgid "&Reset to Default" msgstr "" #: qconnect.cpp:56 msgid "Select timeseal binary" msgstr "Vyberte program timeseal" #: qconnect.cpp:59 msgid "Only local executables supported" msgstr "Jsou podporovány pouze lokální programy" #: tabwidget.cpp:24 msgid "Close the current tab" msgstr "Zavřít současnou kartu" #. i18n: tag Text #. i18n: file ./taguaui.rc line 15 #: extractedrc.cpp:3 #, fuzzy msgid "&Edit" msgstr "Ú&pravy" #. i18n: tag text #. i18n: file ./taguaui.rc line 24 #: extractedrc.cpp:6 msgid "&Game" msgstr "&Hra" #. i18n: tag text #. i18n: file ./taguaui.rc line 33 #: extractedrc.cpp:9 msgid "&View" msgstr "Po&hled" #. i18n: tag text #. i18n: file ./taguaui.rc line 47 #: extractedrc.cpp:12 msgid "Game Toolbar" msgstr "Nástrojová lišta hry" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 13 #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 13 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 13 #: extractedrc.cpp:15 extractedrc.cpp:63 extractedrc.cpp:182 msgid "Form" msgstr "Formát" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 25 #: extractedrc.cpp:18 msgid "Round:" msgstr "Kolo:" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 35 #: extractedrc.cpp:21 msgid "Time:" msgstr "Čas:" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 54 #: extractedrc.cpp:24 msgid "Result:" msgstr "Výsledek:" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 61 #: extractedrc.cpp:27 msgid "Increment:" msgstr "Přírůstek:" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 71 #: extractedrc.cpp:30 msgid "Site:" msgstr "Místo:" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 78 #: extractedrc.cpp:33 msgid "Black rating:" msgstr "Hodnocení černého:" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 85 #: extractedrc.cpp:36 msgid "Event:" msgstr "Událost:" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 92 #: extractedrc.cpp:39 msgid "Black:" msgstr "Černý:" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 99 #: extractedrc.cpp:42 msgid "White:" msgstr "Bílý:" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 121 #: extractedrc.cpp:45 msgid "Date:" msgstr "Datum:" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 131 #: extractedrc.cpp:48 msgid "White rating:" msgstr "Hodnocení bílého:" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 138 #: extractedrc.cpp:51 msgid "ECO:" msgstr "ECO:" #. i18n: tag string #. i18n: file ./ui/newgamedialog.ui line 13 #: extractedrc.cpp:54 msgid "New game" msgstr "Nová hra" #. i18n: tag string #. i18n: file ./ui/newgamedialog.ui line 39 #. i18n: tag string #. i18n: file ./ui/pref_theme.ui line 48 #: extractedrc.cpp:57 extractedrc.cpp:232 msgid "&Variant:" msgstr "&Hra:" #. i18n: tag string #. i18n: file ./ui/newgamedialog.ui line 74 #: extractedrc.cpp:60 msgid "Create in new &tab" msgstr "Vytvořit v nové &kartě" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 36 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 36 #: extractedrc.cpp:66 extractedrc.cpp:185 msgid "&Animations" msgstr "&Animace" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 51 #: extractedrc.cpp:69 msgid "&Transformations" msgstr "&Transformace" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 58 #: extractedrc.cpp:72 msgid "&Explosions" msgstr "&Explose" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 65 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 158 #: extractedrc.cpp:75 extractedrc.cpp:205 msgid "&Movements" msgstr "Ta&hy" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 72 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 165 #: extractedrc.cpp:78 extractedrc.cpp:208 #, fuzzy msgid "&Fading" msgstr "&Mizení" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 88 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 60 #: extractedrc.cpp:81 extractedrc.cpp:188 msgid "" "Rough\n" "(little CPU usage)" msgstr "Hrubé
(malé využití CPU)" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 115 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 87 #: extractedrc.cpp:85 extractedrc.cpp:192 msgid "" "Smooth\n" "(high CPU usage)" msgstr "Jemné
(velké využití CPU)" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 130 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 179 #: extractedrc.cpp:89 extractedrc.cpp:214 msgid "Animation s&moothness:" msgstr "&Plynulost animací:" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 151 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 123 #: extractedrc.cpp:92 extractedrc.cpp:199 msgid "Slow" msgstr "Pomalu" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 177 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 146 #: extractedrc.cpp:95 extractedrc.cpp:202 msgid "Fast" msgstr "Rychle" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 189 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 102 #: extractedrc.cpp:98 extractedrc.cpp:196 msgid "Animation s&peed:" msgstr "&Rychlost animací:" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 231 #: extractedrc.cpp:101 msgid "&Max sequence length:" msgstr "&Maximální délka posloupnosti:" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 253 #: extractedrc.cpp:104 msgid "Animate move &sequences" msgstr "Animovat po&sloupnosti tahů:" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 277 #: extractedrc.cpp:107 msgid "&Border" msgstr "&Okraj" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 292 #: extractedrc.cpp:110 msgid "&Color" msgstr "&Barva" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 302 #: extractedrc.cpp:113 msgid "&Text Color" msgstr "Barva &textu" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 320 #: extractedrc.cpp:116 msgid "Custom &font:" msgstr "Uživatelské &písmo:" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 13 #: extractedrc.cpp:119 msgid "Engines" msgstr "Programy" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 25 #: extractedrc.cpp:122 msgid "Engine list" msgstr "Seznam programů" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 93 #: extractedrc.cpp:125 msgid "Engine properties" msgstr "Vlastnosti programu" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 157 #: extractedrc.cpp:140 msgid "Tagua (text)" msgstr "Tagua (textové)" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 162 #: extractedrc.cpp:143 msgid "Tagua (D-BUS)" msgstr "Tagua (DBUS)" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 180 #: extractedrc.cpp:146 msgid "&Work dir:" msgstr "Pracovní &adresář:" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 13 #: extractedrc.cpp:149 msgid "Dialog" msgstr "Dialog" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 47 #: extractedrc.cpp:152 msgid "Pattern" msgstr "Vzorek" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 75 #: extractedrc.cpp:155 msgid "Bold" msgstr "Tučné" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 82 #: extractedrc.cpp:158 msgid "Italic" msgstr "Kursiva" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 148 #: extractedrc.cpp:161 msgid "Use this box to test your regular expression" msgstr "Pro vyzkoušení regulárního výrazu použijte toto pole" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 186 #: extractedrc.cpp:164 msgid "Add" msgstr "Přidat" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 193 #: extractedrc.cpp:167 msgid "Remove" msgstr "Odstranit" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 223 #: extractedrc.cpp:170 msgid "Up" msgstr "Nahoru" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 230 #: extractedrc.cpp:173 msgid "Down" msgstr "Dolů" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 266 #: extractedrc.cpp:176 msgid "OK" msgstr "OK" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 273 #: extractedrc.cpp:179 msgid "Cancel" msgstr "Zrušit" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 172 #: extractedrc.cpp:211 msgid "&Smooth highlighting" msgstr "&Jemné zvýrazňování" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 203 #: extractedrc.cpp:217 msgid "&Colors and fonts" msgstr "&Barvy a písma" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 215 #: extractedrc.cpp:220 msgid "C&omments color:" msgstr "Barva &poznámek:" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 233 #: extractedrc.cpp:223 msgid "Cus&tom comments font:" msgstr "Uživatelské písmo pro po&známky:" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 243 #: extractedrc.cpp:226 msgid "C&ustom moves font:" msgstr "Uživatelské písmo pro &tahy:" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 253 #: extractedrc.cpp:229 msgid "S&elected move color:" msgstr "Barva &vybraného tahu:" #. i18n: tag string #. i18n: file ./ui/pref_theme_page.ui line 31 #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 149 #: extractedrc.cpp:235 extractedrc.cpp:271 #, fuzzy msgid "..." msgstr "…" #. i18n: tag string #. i18n: file ./ui/preferences.ui line 13 #: extractedrc.cpp:238 msgid "Change Tagua Settings" msgstr "Změnit nastavení Tagua" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 13 #: extractedrc.cpp:241 msgid "Quick Connect" msgstr "Rychlé připojení" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 28 #: extractedrc.cpp:244 msgid "&Login" msgstr "&Přihlášení" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 47 #: extractedrc.cpp:247 msgid "&Password:" msgstr "&Heslo:" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 60 #: extractedrc.cpp:250 msgid "&Username:" msgstr "&Uživatelské jméno:" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 70 #: extractedrc.cpp:253 msgid "&Store password on this computer" msgstr "Uložit he&slo na tomto počítači" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 73 #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 182 #: extractedrc.cpp:256 extractedrc.cpp:280 msgid "Alt+S" msgstr "Alt+S" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 83 #: extractedrc.cpp:259 msgid "Ser&ver:" msgstr "Ser&ver:" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 98 #: extractedrc.cpp:262 msgid "ICS p&ort:" msgstr "&Port pro ICS:" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 115 #: extractedrc.cpp:265 msgid "ICS &host:" msgstr "&Hostitel ICS:" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 131 #: extractedrc.cpp:268 msgid "&Timeseal" msgstr "&Timeseal" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 159 #: extractedrc.cpp:274 msgid "&File Path:" msgstr "&Cesta k souboru:" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 179 #: extractedrc.cpp:277 msgid "Use &custom command line arguments" msgstr "Použít &uživatelské parametry na příkazové řádce" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 232 #: extractedrc.cpp:283 msgid "&OK" msgstr "&OK" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 248 #: extractedrc.cpp:286 msgid "&Cancel" msgstr "&Zrušit" #: extractedrc.cpp:287 msgctxt "NAME OF TRANSLATORS" msgid "Your names" msgstr "Karel Volný" #: extractedrc.cpp:288 msgctxt "EMAIL OF TRANSLATORS" msgid "Your emails" msgstr "kavol@seznam.cz" tagua-1.0-alpha2/translations/fr.po000066400000000000000000000416511077523320400173220ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: tagua 1.0-alpha\n" "Report-Msgid-Bugs-To: http://trac.tagua-project.org\n" "POT-Creation-Date: 2008-02-26 23:43+0000\n" "PO-Revision-Date: 2008-02-27 01:06+0100\n" "Last-Translator: Yann Dirson \n" "Language-Team: French \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: main.cpp:35 msgid "Tagua" msgstr "Tagua" #: main.cpp:37 msgid "(C) 2006 Paolo Capriotti, Maurizio Monge" msgstr "(C) 2006 Paolo Capriotti, Maurizio Monge" #: main.cpp:38 msgid "Paolo Capriotti" msgstr "Paolo Capriotti" #: main.cpp:39 msgid "Maurizio Monge" msgstr "Maurizio Monge" #: main.cpp:40 msgid "Jani Huhtanen" msgstr "Jani Huhtanen" #: main.cpp:40 msgid "Gaussian blur code" msgstr "Code de flou gaussien" #: main.cpp:41 msgid "Rici Lake" msgstr "Rici Lake" #: main.cpp:41 msgid "funclib lua library" msgstr "bibliothque lua \"funclib\"" #: main.cpp:42 msgid "Riccardo Iaconelli" msgstr "Riccardo Iaconelli" #: main.cpp:42 msgid "Various fixes and cleanups" msgstr "Divers correctifs et nettoyages" #: main.cpp:43 msgid "Yann Dirson" msgstr "Yann Dirson" #: main.cpp:43 msgid "Shogi related patches" msgstr "Contributions lies au Shogi" #: main.cpp:44 msgid "Pieter Stouten" msgstr "Pieter Stouten" #: main.cpp:44 msgid "Allowed free use of images on shogi.net" msgstr "A autoris la libre utilisation des images de shogi.net" #: main.cpp:47 msgid "Initial variant" msgstr "Variante de dpart" #: mainwindow.cpp:79 msgid "Move list" msgstr "Liste des coups" #: mainwindow.cpp:89 msgid "FICS Connection" msgstr "Connection FICS" #: mainwindow.cpp:92 msgid "Console" msgstr "Console" #: mainwindow.cpp:129 msgid "E&ngines" msgstr "IA" #: mainwindow.cpp:143 msgid "Play as &white" msgstr "Jouer les &blancs" #: mainwindow.cpp:149 msgid "Play as &black" msgstr "Jouer les &noirs" #: mainwindow.cpp:156 msgid "&Analyze" msgstr "Analyser" #: mainwindow.cpp:175 msgid "&Back" msgstr "Prcdent" #: mainwindow.cpp:176 msgid "&Forward" msgstr "Suivant" #: mainwindow.cpp:177 msgid "Be&gin" msgstr "Dbut" #: mainwindow.cpp:178 msgid "&End" msgstr "Fin" #: mainwindow.cpp:179 msgid "&Connect" msgstr "Connexion" #: mainwindow.cpp:181 msgid "&Disconnect" msgstr "Dconnexion" #: mainwindow.cpp:188 msgid "&Edit position" msgstr "Modifier la position des pices" #: mainwindow.cpp:189 msgid "&Clear board" msgstr "Vider le plateau" #: mainwindow.cpp:190 msgid "&Set starting position" msgstr "Etablir la position de dpart" #: mainwindow.cpp:194 msgid "&Flip view" msgstr "Changer l'orientation du plateau" #: mainwindow.cpp:196 msgid "Toggle &console" msgstr "Affichage de la console" #: mainwindow.cpp:197 msgid "Toggle &move list" msgstr "Affichage de la liste des coups" #: mainwindow.cpp:420 msgid "You have specified a folder" msgstr "Vous avez choisi un rpertoire" #: mainwindow.cpp:420 mainwindow.cpp:425 mainwindow.cpp:432 mainwindow.cpp:647 msgid "Error" msgstr "Erreur" #: mainwindow.cpp:425 msgid "The specified file does not exist" msgstr "Le fichier choisi n'existe pas" #: mainwindow.cpp:432 msgid "You do not have read permission to this file." msgstr "Vous n'avez pas les droits de lecture sur ce fichier." #: mainwindow.cpp:447 msgid "Open PGN file" msgstr "Charger un fichier PGN" #: mainwindow.cpp:469 msgid "Save PGN file" msgstr "Enregistrer au format PGN" #: mainwindow.cpp:481 msgid "" "A file named \"%1\" already exists. Are you sure you want to overwrite it?" msgstr "" "Un fichier nomm \"%l\" existe dj. tes-vous sr de vouloir l'craser ?" #: mainwindow.cpp:483 msgid "Overwrite File?" msgstr "craser le fichier ?" #: mainwindow.cpp:484 msgid "&Overwrite" msgstr "craser" #: mainwindow.cpp:647 msgid "Error creating game" msgstr "Error lors de la cration du jeu" #: mainwindow.cpp:687 msgid "Illegal move" msgstr "Dplacement illgal" #: movelist.cpp:684 movelist.cpp:725 msgid "&Set Comment" msgstr "&Ajouter commentaire" #: movelist.cpp:687 msgid "&Promote Variation" msgstr "&Promouvoir la variation" #: movelist.cpp:689 msgid "&Remove Variation" msgstr "&Supprimer la variation" #: movelist.cpp:727 msgid "&Clear Variations" msgstr "Supprimer les variations en ce point" #: movelist.cpp:730 msgid "&Truncate" msgstr "&Tronquer" #: movelist.cpp:734 msgid "&Promote variation" msgstr "&Promouvoir la variation" #: movelist.cpp:737 msgid "&Remove variation" msgstr "&Supprimer la variation" #: pref_engines.cpp:39 msgid "&Name:" msgstr "Nom :" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 136 #: pref_engines.cpp:47 extractedrc.cpp:131 msgid "&Type:" msgstr "&Type :" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 147 #: pref_engines.cpp:52 extractedrc.cpp:134 msgid "XBoard" msgstr "XBoard" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 152 #: pref_engines.cpp:53 extractedrc.cpp:137 msgid "UCI" msgstr "UCI" #: pref_engines.cpp:54 msgid "Tagua (textual)" msgstr "Tagua (textuel)" #: pref_engines.cpp:55 msgid "Tagua (DBUS)" msgstr "Tagua (DBUS)" #: pref_engines.cpp:56 msgid "GNU Shogi" msgstr "GNU Shogi" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 113 #: pref_engines.cpp:61 extractedrc.cpp:128 msgid "&Path:" msgstr "Chemin d'accs" #: pref_engines.cpp:70 msgid "&Work directory:" msgstr "Rpertoire de travail" #: pref_engines.cpp:93 msgid "Choose a name for the engine" msgstr "Choisir un nom pour l'IA" #: pref_engines.cpp:93 msgid "No engine name" msgstr "Pas de nom d'IA" #: pref_engines.cpp:117 msgid "&New..." msgstr "&Nouveau..." #: pref_engines.cpp:119 msgid "&Edit..." msgstr "&Editer..." #: pref_engines.cpp:121 msgid "&Delete" msgstr "&Supprimer" #: pref_theme.cpp:344 msgid "&Reset to Default" msgstr "Valeurs par dfaut" #: qconnect.cpp:56 msgid "Select timeseal binary" msgstr "Slectionner le binaire timeseal" #: qconnect.cpp:59 msgid "Only local executables supported" msgstr "Seuls les excutables sont supports" #: tabwidget.cpp:24 msgid "Close the current tab" msgstr "Fermer l'onglet actuel" #. i18n: tag Text #. i18n: file ./taguaui.rc line 15 #: extractedrc.cpp:3 msgid "&Edit" msgstr "&Edition" #. i18n: tag text #. i18n: file ./taguaui.rc line 24 #: extractedrc.cpp:6 msgid "&Game" msgstr "&Jeu" #. i18n: tag text #. i18n: file ./taguaui.rc line 33 #: extractedrc.cpp:9 msgid "&View" msgstr "&Affichage" #. i18n: tag text #. i18n: file ./taguaui.rc line 47 #: extractedrc.cpp:12 msgid "Game Toolbar" msgstr "Barre d'outils \"Jeu\"" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 13 #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 13 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 13 #: extractedrc.cpp:15 extractedrc.cpp:63 extractedrc.cpp:182 msgid "Form" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 25 #: extractedrc.cpp:18 msgid "Round:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 35 #: extractedrc.cpp:21 msgid "Time:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 54 #: extractedrc.cpp:24 msgid "Result:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 61 #: extractedrc.cpp:27 msgid "Increment:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 71 #: extractedrc.cpp:30 #, fuzzy msgid "Site:" msgstr "Blanc :" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 78 #: extractedrc.cpp:33 #, fuzzy msgid "Black rating:" msgstr "Noir :" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 85 #: extractedrc.cpp:36 msgid "Event:" msgstr "" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 92 #: extractedrc.cpp:39 msgid "Black:" msgstr "Noir :" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 99 #: extractedrc.cpp:42 msgid "White:" msgstr "Blanc :" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 121 #: extractedrc.cpp:45 msgid "Date:" msgstr "Date :" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 131 #: extractedrc.cpp:48 #, fuzzy msgid "White rating:" msgstr "Blanc :" #. i18n: tag string #. i18n: file ./ui/gametags.ui line 138 #: extractedrc.cpp:51 msgid "ECO:" msgstr "" #. i18n: tag string #. i18n: file ./ui/newgamedialog.ui line 13 #: extractedrc.cpp:54 msgid "New game" msgstr "Nouveau jeu" #. i18n: tag string #. i18n: file ./ui/newgamedialog.ui line 39 #. i18n: tag string #. i18n: file ./ui/pref_theme.ui line 48 #: extractedrc.cpp:57 extractedrc.cpp:232 msgid "&Variant:" msgstr "&Variante :" #. i18n: tag string #. i18n: file ./ui/newgamedialog.ui line 74 #: extractedrc.cpp:60 msgid "Create in new &tab" msgstr "Crer dans un nouvel onglet" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 36 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 36 #: extractedrc.cpp:66 extractedrc.cpp:185 msgid "&Animations" msgstr "&Animations" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 51 #: extractedrc.cpp:69 msgid "&Transformations" msgstr "&Transformations" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 58 #: extractedrc.cpp:72 msgid "&Explosions" msgstr "&Explosions" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 65 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 158 #: extractedrc.cpp:75 extractedrc.cpp:205 msgid "&Movements" msgstr "&Coups" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 72 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 165 #: extractedrc.cpp:78 extractedrc.cpp:208 msgid "&Fading" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 88 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 60 #: extractedrc.cpp:81 extractedrc.cpp:188 msgid "" "Rough\n" "(little CPU usage)" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 115 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 87 #: extractedrc.cpp:85 extractedrc.cpp:192 msgid "" "Smooth\n" "(high CPU usage)" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 130 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 179 #: extractedrc.cpp:89 extractedrc.cpp:214 #, fuzzy msgid "Animation s&moothness:" msgstr "Vitesse d'animation" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 151 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 123 #: extractedrc.cpp:92 extractedrc.cpp:199 msgid "Slow" msgstr "Lent" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 177 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 146 #: extractedrc.cpp:95 extractedrc.cpp:202 msgid "Fast" msgstr "Rapide" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 189 #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 102 #: extractedrc.cpp:98 extractedrc.cpp:196 msgid "Animation s&peed:" msgstr "Vitesse d'animation" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 231 #: extractedrc.cpp:101 msgid "&Max sequence length:" msgstr "Longueur maximale de squence" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 253 #: extractedrc.cpp:104 msgid "Animate move &sequences" msgstr "Animer les squences de coups" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 277 #: extractedrc.cpp:107 msgid "&Border" msgstr "&Bord" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 292 #: extractedrc.cpp:110 msgid "&Color" msgstr "&Couleur" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 302 #: extractedrc.cpp:113 msgid "&Text Color" msgstr "Couleur du &texte" #. i18n: tag string #. i18n: file ./ui/pref_board.ui line 320 #: extractedrc.cpp:116 msgid "Custom &font:" msgstr "Police personnalise :" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 13 #: extractedrc.cpp:119 msgid "Engines" msgstr "IA" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 25 #: extractedrc.cpp:122 msgid "Engine list" msgstr "Liste des IA" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 93 #: extractedrc.cpp:125 msgid "Engine properties" msgstr "Proprits des IA" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 157 #: extractedrc.cpp:140 msgid "Tagua (text)" msgstr "Tagua (textuel)" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 162 #: extractedrc.cpp:143 msgid "Tagua (D-BUS)" msgstr "Tagua (D-BUS)" #. i18n: tag string #. i18n: file ./ui/pref_engines.ui line 180 #: extractedrc.cpp:146 msgid "&Work dir:" msgstr "Rpertoire de travail :" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 13 #: extractedrc.cpp:149 msgid "Dialog" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 47 #: extractedrc.cpp:152 msgid "Pattern" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 75 #: extractedrc.cpp:155 msgid "Bold" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 82 #: extractedrc.cpp:158 msgid "Italic" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 148 #: extractedrc.cpp:161 msgid "Use this box to test your regular expression" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 186 #: extractedrc.cpp:164 msgid "Add" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 193 #: extractedrc.cpp:167 msgid "Remove" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 223 #: extractedrc.cpp:170 msgid "Up" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 230 #: extractedrc.cpp:173 msgid "Down" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 266 #: extractedrc.cpp:176 msgid "OK" msgstr "OK" #. i18n: tag string #. i18n: file ./ui/pref_highlight.ui line 273 #: extractedrc.cpp:179 msgid "Cancel" msgstr "Annuler" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 172 #: extractedrc.cpp:211 msgid "&Smooth highlighting" msgstr "" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 203 #: extractedrc.cpp:217 msgid "&Colors and fonts" msgstr "&Couleurs et polices" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 215 #: extractedrc.cpp:220 msgid "C&omments color:" msgstr "Couleur des c&ommentaires :" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 233 #: extractedrc.cpp:223 msgid "Cus&tom comments font:" msgstr "Choix de police des commentaires :" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 243 #: extractedrc.cpp:226 msgid "C&ustom moves font:" msgstr "Choix de police des coups :" #. i18n: tag string #. i18n: file ./ui/pref_movelist.ui line 253 #: extractedrc.cpp:229 msgid "S&elected move color:" msgstr "Couleur du coup slectionn" #. i18n: tag string #. i18n: file ./ui/pref_theme_page.ui line 31 #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 149 #: extractedrc.cpp:235 extractedrc.cpp:271 msgid "..." msgstr "..." #. i18n: tag string #. i18n: file ./ui/preferences.ui line 13 #: extractedrc.cpp:238 msgid "Change Tagua Settings" msgstr "Modifier les paramtres de Tagua" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 13 #: extractedrc.cpp:241 msgid "Quick Connect" msgstr "Connexion rapide" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 28 #: extractedrc.cpp:244 msgid "&Login" msgstr "Connexion" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 47 #: extractedrc.cpp:247 msgid "&Password:" msgstr "Mot de passe :" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 60 #: extractedrc.cpp:250 msgid "&Username:" msgstr "Nom d'utilisateur :" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 70 #: extractedrc.cpp:253 msgid "&Store password on this computer" msgstr "Mmoriser le mot de passe sur cet ordinateur" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 73 #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 182 #: extractedrc.cpp:256 extractedrc.cpp:280 msgid "Alt+S" msgstr "" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 83 #: extractedrc.cpp:259 msgid "Ser&ver:" msgstr "Ser&veur" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 98 #: extractedrc.cpp:262 msgid "ICS p&ort:" msgstr "P&ort ICS :" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 115 #: extractedrc.cpp:265 msgid "ICS &host:" msgstr "Machine ICS :" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 131 #: extractedrc.cpp:268 msgid "&Timeseal" msgstr "&Timeseal" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 159 #: extractedrc.cpp:274 msgid "&File Path:" msgstr "Chemin d'accs au fichier :" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 179 #: extractedrc.cpp:277 msgid "Use &custom command line arguments" msgstr "Passer des arguments personnaliss en ligne de commande" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 232 #: extractedrc.cpp:283 msgid "&OK" msgstr "&OK" #. i18n: tag string #. i18n: file ./ui/quickconnect.ui line 248 #: extractedrc.cpp:286 msgid "&Cancel" msgstr "&Annuler" #: extractedrc.cpp:287 msgctxt "NAME OF TRANSLATORS" msgid "Your names" msgstr "" #: extractedrc.cpp:288 msgctxt "EMAIL OF TRANSLATORS" msgid "Your emails" msgstr ""

Tim Mann

LPH^-:>R pmkssWQ[w"HY@cI$s]SnA**U QS;6l^;>[ 0V`s'J'֗RT$I !o# R]θqa`XxL̦VnFMgDĴZmU||)uETK@JԧC *YAJ7[KI絢3_fQm鶚K -OL:꜓usCt=gPqrF덟֜x6aVtlMkFe/xN'@6uf`RVon#H͡[P.$늸ߵt;0a\+Ķ/nM|1 BxR?_7MOKJ>ryN}OYO/KAȩ7jm`U4H l[3.7Y$.>7 6%mILnḁ۬.$m<^>ŗ>'?|2dZ3K>Dũ&n6x@'d Z3PuMSޘ 33-TȹH`G\w+u#wZʺ~ijH$/jAU}LyEQW&K+OTW&0|BM-u!ekS_# sc4V*^yumʼ)"rp{{zډjrqSn<+ Uӷ1cKj%u,@(Rn-狴w{?m.uKJUhii6ܪ*@B|m6&ٰ:*,|.Sq4Qֵ琉a=UW3˽dBgK/{x<~֏ZII9ɕ0h['u*B&܂xuQb"coZE.d;+l|u?x6tT֙;cce|KG5&zqwshKiOXczP4ă3kaJ{s~beJ0kOgTm l/0*gI>8v!x!SZ08}2sNPeؖqibheCK7 wU*Z;GUsSJ2$.ۢX@x>\QO2[L8֏yq.8Ic9a~.:Ǧu^KJBlT=ވOG5=5&埧R<0(,>ݍPeW(,mw qac9W#n7*pHIk~4qjk @YJ@ڜ["׈r~e D/3l\ܠl>RJɰ~Eg|LΫoIAPٴplm|f0mAG&ۨ0hHR^FR6^ |0&ֺJ;.Ӂ+@$#ݢeaq)s'ժVuN$p@u:]oMKKZ2jqYP"'qH? Tf B0˵|MP>)tuM'q68؁ah$OiQ]FfJgT˾ MRo}͸􉦺m|f˭Y(Ri|#HnLe5 /q)&ļņ*!o2а=͍o=&@H/?=SJ[(WANnr=5UOQ^p/CyEZid%u(raHcⲃYJ)ˁe!L{|2[F.ʤOP(TjjIvolR >mo:,Iij~fbU3BG*LQ79&^i4O} RN;?i)tAmkm)2TFshT:SVLV~Nq!Jx$Nn=PM.6>(5RdR4ĶHR&l`4JU!)Kp/oaćL̾K~"U[6&me-.&ashd(˸ 7 ^Xy7yhi>L#w'TLĠpG92Bƥ{.&Y鵅O!DԎg46E-P' oHhjM6zv[WSļ߂VRS}r6mxV[ %KTK5$'v}Дޢ =GxlI/K̵-Mg^i=)Jbf[m u2ߌ Sq| }}_Mڒ%\q6 "_b318vs”kI-ی*71.|*KU A.Ikh[S0Jgf^| H>DhxLUdQJtH##x]v@nG=0NVxLļʃ*)0|]X7BT\9v4-5z.|iuxm,'ly;zEjnHUɴĬĘ*pHT/oc*lVd U[zA¿'ih9F%s {ߚ:Թ+KPn^,sECRtcHTTB]ocb@ۛEi\#1*犞5C#{\~Ԧ2j :{=gE}*UIjp6K=0@<g!TN,PQ#XF[,ukRԇ G.Vij%.N}喒x~ jW~]gY^ۍ=͍SUOJ,Y;M4T`o\DH΂ҘiJ Kj wdžgюT:ԶQ9/ +:CXЖ]V' >6?5.К&z2螭?2.fI"bPҵZ2J)79&Mri#F-z(CJI aɘ[Js{nY)6WQ24RԇMmEJ.L y?($,63aLI6솬f[a8ڈ0oCRߧCI),:Fd PqAN|*j =9Gi6f'XĩddHM^J}Quگ[yϼ9ԪX`󸔤J[䂳`!ԟo*m7$ p X[-e^$Fh +z2Q͹>I74/lAok>J"QXhfڙ('vF9ZNe\AT~KJ Pi@\XdXo= Mk HIDh;!Jߓh`Kms2E@mUhI ڤf H n M7 qlae$sX-$A+JbNıQ(bRMLy0fùa @MJBuS2J-zkE ]II[<<0oɋ*xjuޅ: UXh#Ɣeoe]LN%ONhc@IAe_J%o^q$t/SR5$jJl porRP%\w#ucFQQ[uBnpݪ\Ҥ"0G(YHXU-1>u,:Xе%aڕGKSu[L,>[ Dˁr=a0 $QO5=LypXpDozezH>6I9 6yA6`RM{}c>Jdz֧Ӧ+Mi'B;.ǂNJI>_n8u:oR$zbNjfIM"Ғ6 /{Ee@I9 _ѓUx4P-}eF\QÚK]ZB1->ά:RNꮠl}ӽ4AmZ Y i~Ѱ=J.yy0''+ݤL(`W '~(FFxgbDÉW&6-K'mQ]h  n׏=j U5ԧN>lΗ[kpDvN?>KqvTDg< @J_^/w.ad"^HCK73s lܥ]E\Dˊ:0W2BA q=Y q3J^]Jo2E<[pdx\mĕ9se+ !%I4玕 wjJ(mÃ9.m]@0RU-;R9Op &k[PB\'-J(Jw`b\i#il{K2S.l7v-ZZuOpox'.`;AwDcQQ<[Up.R1Z[Z-ءH fN8VVH#wŷ"=Cۖ,ovears.Lf{ Bm܅9t@87jAV8ǧx4Uge-|pHna G>_HH =3C%% 8ŕf*I0n6:0H  눲RmBDe*!~!XMq XRl;p/=0^@n7 $͉%_b,$?,&`rBF{HQ APP9<,[6D⇀8PHHErrU|WU @V;BoaRۋ @nk]R(K\g%P 9s%Ci?~0Sj,Q<.-JR( ;o`ẗ́$T-š܆#EŰvޱn`(y* XhX? >,0S;lI[7'Xw 8Z sgRRp8 )<1yϘ) :ɱ4juMY@O x7 $F9HORM=[JMmYHJQ^eCQ6 pE[5(.XH7\aEzZU~9RQnHa nKUq/+6QoEo <rbbwP*'ܺ?BKIu]Jx2za ֭6":KN28 罌<,&E&/WmKf鎤ͦt"jy / g[!_Sb:ҞLɹ%Un6fm.1e(rA>u4\ZT|%%rm<( R[ <߃ ZD|>I^.9136먨,Y7n tzK};rJRVZݸN u ZRvRR9㘺iyHl;Pϭb8ʈN?Θ?XtUfV~Ke!*4jVe2.y{E=LJ+L%7j2K`\"څ~jM\zMSйwgt A?ewo@yMo5CB2і8NJ@PciG<]&'->>-%8Gw橵JI&ԒI6[ӌLҚlWԿ t i&yr鿆 0= ]12g[7?ۂakPOEp=X gɳ܎tQպɖO\jaM܀PQU# bzޥbgj,%je;Iؤ2򐂤$XΛFnQ*QpdBIE-=]%蒳Fj٧$J "__q792%؋}$)l~Ӕ[ڮ`(84J 6vKDFl*Y%-xTļNV]ɩKAMIXI0A꒪{NYUɈ-m@3JpQ'gwYvYl:ߑͯl#<|RBJk}1-!x򄄨.LjhfT5ߧ.⻧^\B>+hm`֋nU lt/+[@R"پ91R B2g?}j}2z7ugT+'] dڄB!JgT`y DB/˔svێ'ZJpOb0s%]Ei$ Bҥ,ŏ@i뢦k tJu=>jmԪqnWe}(,5~eu$Zb㎭BTO{܌C!N͑-L2 :I ?)B^*JMkۋx v(gN>Q.9.B>]_kC$SBfCzr~N@A ׸K.Lx[(_ FW෤56̫^ÄnSl`mǤLd&`^I*.18fd*[Twes*A\r ;xFMܵ9wm KNsvH 嵍Y38˛xOk( ፲kXO6;Ҡ2=#UQP\ˊu S5GQ\GD4n&\ɰ _=+u?B(Zq mayUu r@wu )M!`L9ed{BZY]m/x* HYv8y^M.TY/-Go<{A:1La7E3i@ZH.{w:BNjmZ}dLxtT* msŁU8M)ǔ)Vo\뮟03Cd)ɿ=*Ԕs4l{ ۹:LD,2oV)yuf}5[eE$9IrM&YYQ$"v[SSLKO.#eRU>V9AWAҥߛzYG9%NKOˊq!tmRM 7mJ|] SaN";siYVee6(nN 991tB33+_RhfPNŨbT86, ɹ>H4?Ĩ—uR4v.A9{= )LYHYRP]`c#ЋEO[U2&f2$D~-܅'dgk=i5'h..ʝuI&jo]hU@N$9\zzDZkjs[RCks|Af&+Z4t8-77HSͽ"!Os]7V@4:$G(0}"AҙDO˦ֻ ;?,ML[,Mdz}"ziI-5LRêS$[MA$m0,*o⫦:fZ?U615,[B.X.3"z룗0Ɣ˻vФofôfujtžY m ߜEV~Zvj&Y}7g{Bۆ1Z5Wj9zCe􄺋›$d cczbi-K+aMks÷[*vߙi+؅MTl~.>1|L[S !biAqpH+ V~::nYդ8wRh 9Xw>3Y;CvLܮJk&_eHyMb}'VH'|mJ!Ά>XKŪԠ=6^HQzJ)ut7HbF^E܋(`{Sѷ R-*RޓdO,w%+ %P]Me`/ =!z/t~vyiP!e|H?G;OǏm B@ijHVwCm`)AmBZF N74J#.X"+S#UVKr ,@'G1y?CbDk"ywL;&w_8ګablhJ0ģIMnZ]Q>δJʌC`UbSbhԺ^i99PJ- %AGbǘҿZ}Gdf,`nGn"2l$ ji5zOBJ~jfQ{Rr#H$w'UbwTں2s Lp \@Mӧ"GAľm;!yJ+rTe{%fP$p2;@;:SYΦju忄r EfyN"]'P>Rv'_sxzjPv!0ÇĖ\BnH%Ch1hEH|Г*rYMص }WT5&[MuD**vMK(VԆJňMlDzzwUKZ+8!/xd\$ŞCnʶf*u.p NA88Vs $p'fuil˨xd5kǓDɺVN߱=Լg d >tR9&JB^(`Xhf{V!g\Ԃm*pT-J 4 \= zC>mk$.,Y6nl( )w:YO˦= !7p Ţk7P{TYlB,(*?›-#U(qa`,;z/U')3D: ?&UrP+F1v+)>}MEV2lKB IxPH{HQht̵NrapA|`ZhyCTUnQSGdzwO5!Iꦅȳ"dӊҧvt4P-{Œޤ4ӒuİD%+[shY/ P36=dn)АPdča *JETfl-,ʀ^#qڔ <S֌=#mRdYyG`{jfuJS3-vQ \Ek1( 9W\SgÝzbuFGp=LJ#SRU9*S-mIunk(qۏ_]zkl!nb1FsVSu%he!*Hf 0? #UBWqeG ׇ}A'/3)8S* ;783”,MyGfҩǛZ‡`oo K.UVۄ9CzǤɕ24f!ŶT4hJw;ss1TSIvN%23,,xP6Io"YwPLmj9 q"ߠNiJBGbpm}"EuT L~UԩaU1JPedR44qH+S) oָܓq5v!]%-!8 F?h)!J~5"H3s0Vy2uo$2AeqɱE RMI*~YWۛfvMn%VZ<2w\|2M1禜nmR)^xa!wBMИ7CLunZjnE$b.q/fL_XKL ›+ҔUͭk߉$MBʇ.oߟC Q}i)l-6?(oSk&٧n;NmS|Z׈LaMJ0l6me)_cK~e:fqk:jz)Cq#.UR\QU=ǿ7նY'O*SjO4#\p/iRZ~V&e,, Q4xMS-[4RV4Jl*5ZCUWe%2))Ds *2mv8s$Գ2F֞anlTF{~!+uxUra[d^O"ٷ~!JJ(ZmfSn9b>d G1]tT)Ϸ5U[ǀ,w \lTzIj7R%$N*h!yo1dj&ӳ<)F>^(`#^Rdm\sf;M,w&O:Dr hm2,ckmꮌ!W}:J۪mEU`JWۼkZ*Soz]4&ciF<$~Q ;SS3S,uKv FC#tA 6-Bi.t8KMeGn)gؖ6CMBEˇ9o )CJ"jEm?0TR>VZEi?^iٗ}/7)8%pJ$HpyŢ^~fHfT;cΛ|Y/TUܛualL2\E-ILQaR"ZQF\S`V8xO$N.㊘Simh~"wq|ߔRj]6trYaK~E6Dcx\)65;PRZyS}A{EV>)<׏"UZ$|"jjid6&[6%6ɿl[Rj8W'!%3 cF$ېy*&N>ղ()x JM緤/Ik9:tޞPu(eߖ1.i-͹`1mnbGX&(U?]wBR9.qrx7M"2c6%ƒ; I(w$KRRO͖Mޫ!(ۿ{ɯ_=(+zCl!M<|!ֲO G9Ky!To m s{zZ_\JߊܻwuHok6#s!ų& VnE{f)\DgZRsة_X5KM-ƅՒ2Ӥe\̝$#mf\\a#F'Ƈkϥ.N%_7ױN}82ͦ}[/0ln~Fqyjw$tGſsc4i\Stԓ/TN۩UcQrraK"WeJ%^b JmoLFv'?ؓs eOK6P'?<K Ud+%Ŵ\'R=vۋ) w ^IkSй23jTIP02*zPVtĉmjdƖ7ȽaczUך5Px5,Zkq SJ DjU<}aFzyy/x>$É{ÒhEb|oV T~I ؃06 {EsHM-t+R>ˀ:)Q) %^^ֽHtzrHX}ʢm<x)iv[+ Ҥi %ҿ*$[(VU0<ϗ-rAM[6'on,6eԄ4<ȐSk;kq4g4"F5 }@57JIڅl!& .0S-(RBeJs1O:vJ]䜲x"JѴ<πSL:%IY@g?hn֏fE+n^M3 ZJ< prSkAmHreE>}"Z:ZY5@O RTצ̕Q5Z>ٲ'crBڻO}HG?.0),m=O7s'Ɍy- D},7RnڜtqԾStoMi.fSE\77:{YVs Oɥ *bWvrze@ĒQn=f$>so㇫uS:zkL$Xq I&ڼfBO~S[$Ҽ6BxPYeO[/M[uK+C+VQQa,b$+諏xr~a/R=TP+nEH̺Kfqm#71*IfV/Xi[j8ےIFrmREnd$'#baRfQbPiEPxl+/"#>7h].]3g%ۗ)J44p%.$gI?YQ% 38Ґ >B.NSn9'KHuOIE~u vvkzpX^_;~j-E),6TI^_׌^ݢlK9Qzړ)9M6+KRy- N7`j f{A)NYF)<UBl-)>Rږ))oxV|]!c}'T JKjaToqm{w9dn)IC͋ BjB3q0 &)!<$F JJR;FI Ґ m|K(ق7džAPhRrVAҳ%ak!&ď``g [l`! qa4RH_ sʤm80N}p(6# TT0a[Qp ؏ ڒ*Ry m`,ׄI*7ţC#ʹ @oScux4bcA0R8R{$H{7  okB*m`:ۉ`-kYBˑɼ KUw罠Hu^ǵMqKN!r>@v}adTA>MɸuvP.y/ %V} @ܫ+g؋bj Ǭ*̳)Ci>4"$8N2V ͟))@QYRfuԛyl~4Y(44Cd,{I%%_M]<t䄺*HeTCԇӒ6IUW&sIHJ VAH{EqSOԦI.r p"Ğ{D/L36RBSR Ǥf 9sVe+ˌVVUm'71w>Գt!ZH&]L3mʺ\_88F\l aV7 Pd> mXzØ"+tjN&4{M5Siy[j  12*^:4w^HSR L %Lj%J?̓ĪZѳ IMm Spaqb y=I7B&_D:Py)aT6rR.A}"bKQҝ~Bq7.nOz\ a)sڊ&|JcRfBohƃi2ERaĜNYE6C3?PR{"jN159"Ƣ${2gFZ `p$uDg0M(جs&tB'wDk]98VcT`I۰B/ޱZegXQBp_H"[0\o%.9=ѾH8+P IdԮhԷ֟ZGLɭK+ pS()!v U8θj;{!d-6_z?*\QPcJ B BR.vZ<.0ʥUlRP3b=$SbEmVA-yRE 7t;`V)*RՏB*̟猩. NċBŝIrm #"I<i(Z;NAy@JoSʝm;HŽ"|®6lTU~..3 Tl&PqvB<؄pC (7.o RJ›Vȶl2HDY/p{ÃkA0Ͳm,:=aChBP8Ń'VZe[J ;RKdxjSn)q6*Ͱr&9|P|DA \pO F2)+u{kAS26857)wW>67r} yMaq.#2_8k[Z e7q.v$AT!@ԒLwY/\!M IxS0*SPB9.R/WA&w x 0[_8Xq]Za$!RU+ `1s<4l&2aA'כC/Ǚ$R@J3itua>a1&m؈ٲUt}!$Ft&4m[,Vm 8¤ll/LJ71,HmpA>;Jl$>h:&~]Y@W ?#eo\H%k}"@Dw+8կU:,vRn[;6_Qo:l((8K߅N~FLX\K:6IS9~@˨l 캒Y.XyśԥE`Sʗm|qJr 2iv=a̳+.,lGfIʰʑy["bBAe/C|R_ Sq\~+%3(R Hjcdq&dy<܂G9I&PK %fe6P rgVesB WM\miZros IJQ Vnn;sTmtLXq~DmNB,}o'e4RJ%^P}Ϥ8j }XLvIo7P/n!B}&$ߚk:NuN˰ZxP,t:߈\n;Ti]3jiߞ3 ZR%@s5|Wu^cΗ[Z[@6`֋Φ|PMKRUHδ0 )3c.Hn>r3B몎gLj2/̥ J~7%@go4z'96j\ML);JN]^mѾg'U[Qu֒à$z-99R{wJ|izzZVi$~J[vkn,2n85[A z̦<ضЉ]MLD52֫_q 7M!7*7?!T|J7!ĩ!W O9)*f:柔Sd-n%-lc@\j/Iu'LY;7kPd Fm>7r '5~ԩiRe+V/sEק&Y0Ch}`pqtn_mS.R楤C+eJhܐ7Q!K|+suZVZU ;@]ocb(H"]|XuYd=~1Fp#šmRNƔ"ې9"OF*2ՉQ. S*{Ur|mվuBM2*w b^B^ t- GNQ[KVKYIpC Tƾ ii.Qui5pVq!\>`\N.CvF bN⻪tr]_᝞2) #rMXŹ(}FV-yWdᲉϵɸE?:sg'978B%V &svjyהpk03c]-ka<;VwRˬ6C,֥S0e)@>7"~Э-,oU> 5ʯ&f ot682]'I&$tl MAv!b`-E+EG5f.s2JI?"YOQO 0;R(7$]n-+@ [`]uZ0Lł`J@U:zV24KŲ̕T6"Yow[\)^/J0D.RQ7HDc.3 SQ0g}LcGM3; @,͡9Im/BuNh$b~Q6!טpRZh%Ch_xN*Yv$6J@䨘Qul9 __!Lx؃ ؅e)C}3dP/$Q )CH" 8n{jMqoXo=KP#)I#A,oaz3IS/-<(\} "䪄,:Qe -Vܞ-3R,€X'o,v nX-~2 S.[@zmj@PWEQIFm9.Sl!Z[Pon!ʨ v(,4u56$<6&?-DYjN,S}@ƥ=foMKQ0quU;zDoGɥꖟXmL;d%**Ì~dmJ .* hIJfܞrsFYT/WjJ ~z7K;&(*WHcaS'zJcRiT)UjbZܗ q|poF)JfXiWXػs| ,?'~\)*Uva\Q20ۯ? HL%ڿP$먭zBUs> u)*O$s;<ڎa4T3rn07je RMzSjԪu+_vH*]5zq45GGSAu)mx7O>C@vwp#Dg8ĬQUnI-n7BTObJ,Tfj0i%C(;bfso2Zr$/MRéPC-Nb4 K<ӎ(K$IcCB暦eMw Pqp{>M@g2JHmM$X*kLy6<ͭ'rOkg&QC̜R.}Bq)8:ޚXD}9$I9NTM'DRD[h_snޱHiuSr9wVf&RB>pFONԞ[DYk`ߞ KW.buLaapQTԳCMRjS R͝4rQ;!,Ue Gb@_R3UD*Z.Juŀ,m׈zf%C:qk*WS7ul\+/ 8Iie=]%[LeJ 2\m\RD2]覃T*BD8M+eCr]hz]5u2)׭R wCZ.RvzVNXZ oK H%>?H ɺz)2m\ %S.+qM^+yS7\J6|Yhԩ_kW,L 2BPȍc㗫4yؚU[trSکu"fNiF'HvSbeԉg٘&zlq{dC6'+/UQx4 Xn$1ͻB6lq_̾տģK7'~*d5<#6KuxH:ue g\T<9jm2WA+vs;)tzO:zeIuSrH-u|b"_'TMMhK6J$,E! %h3є] kD*,do4Q_RB ~.!:>$k9 w>l&" acLPiuROtQyǬQkz{T'UθZk6n 0tx u/O:F̳3*Z` ݻ^:g_J+4J! y2loGĺ7ߑM&~JU݈H.N6KIUJ;\ɢBeIJ.6$L]1ϬOs Yj+F.5>+=m=M<*ثܛJϘ-F#_MԚRzt:V*3T K+Fӑ7(lV 'PRcȫyb> ( 4\NԵy8QF먌1.MM|ϊiԐ dF?OtKVR՝cLxq6(k\!R@ϩ38χixro6^ZM= K淥$A.('a"|d~ߴDCG%hYib Ob/8 %V!B9BF@EϴIGaJRp$tzC)iboqC1 '$Zy@D9$)/6òش2#L6TRSk R{“3so&8w^ !P0{榎&SNa;[JZJqR?{t9EX8;A5l+{@LXf Upmk$ T.N`ЀTz6<̨X}⏜ Xdw[6pRӘsN?Ӧ? Z.͸+*d,8=qQ۳/>RTy&6ooԙ QRZ)'$ +O?CN=B,sn6"9iQ {Gmdq􅛖B\qVۮ4no\Bh,~r@y8ŠW-?,6[\qh^67#&z(QmA 犄mmo-#u͈*baq.n5O&TcJA*HW1G9;xY#B d;nXBʍcM9Ťln;ɲS @w`HNV¡(7\U 'mJ6o65Ox܄p /,KkhRb8[מRܟE@ؐ6<Q@<s `{ňG +⨨ +@ u.P`u6GqL$E׽XZ)ҢHW0wj?X]PX*m; 'oBd-JI(#* Y  :s5JXfN~m!HokG'ߘ4 Ru Ӓ, ~2uPs&@,~O7Je2^8v)WI ʬ1h!eח %[B Tu%,(?Ha2B%EoǼrH#!S-me6樆djS)P }"'SӤXuOmQiҰz}"- CU斀?l Ǵ0l+pöK&JУ^ Y9b̴i!-IЧSf /$(^*wb>hE7+2&4\g > Qy SR,1KuI^d>O pAߤԍ>p8KA3mO[$?t]>k\qX1zl~j)[KlN%$zȴGU%guU6NTf &7z,4ΟòMKKTe4ei -9kmɹ ϣ> O-ϥʬI-QRU6IftES} $!hXH8]2ւWg˥6ihl4'(v1{PLk, ḭ°C;m 0oSm6S+& Ԥ+QN/spl'6R[- O1kՊ:WAT(y56Oh\EI}:ʒ"z^pƂrT\u C+SmY*W+TtΝ(glZT. @l/e'vPȹ;.5M|Wą&ۂHiny 8#PԺR^+Ssiif?]5\M$k 3opJڞ l8% $َee,NGB%Y9vtTE +M#Z*N/#Sae,x[[$B8)I'#6{z@nqƃ Q@8l,xZ;y/e `,d,  V/8yI%6 cBQVH%!I"׿b$PR+)%[0ijʜ C5rMmˬEǺ LI'~Ub?^ #U?#0FPn]@Z Bw^<B"d+07&9L̪k67%P h H$m9 16UBA)!I 􄍩0ܺ@I#Jotob`v8 % qSM;llm\:\e2}x86 >vm%W&v%CfɌ0Ẅ́n;AQˆhKx@~gfTY'eJlbfp!Ң{6۷Pu+9YM>;s%ԀJKB`O768@]wPnoRAJm`IrKMWzU3gRq^~VکT?; =lnaI7([} )>Ĉ6@AAxZ )QʂER*!3.ܶW68m˨YOahhVe%ͅsnas(>R C[}aV&\mcrm9u+ ;Qw*HeV} ɧVAü/+8oZtB*X\7RJ"īJ,DԞNoWQ<)-%#Y} #G}.PDJpHU6[RwU6Td>u9*.JF,,vqY.,ib)'4(JV$}<*>eoLNK̩[)0u`mlEcYStM Rar9a ZSm?xMUQ JKRC)m h nUϘD?}ә]E0LnSsyQB .:kRQ-ij:ҩ*\Ljg;~+Q=́hfg]E*u ))H.)38&C B&Sw+GVIUA&ɜbmko,cJ)2y\Kxu/sNLRmNwBajRv2?{ˉ=IE=*rd0cnݻ"& +&Mց5):3˲meɋ0IjZ,\ ە_98K-VEʔx"ĎO[:j˲3-0ǧ*]).5-FIܳa8.E NMVԳ[;.@; D @r},Y3T%`(msUZ@}.6-,J6r9<˝qR[sc$uI91l9%䃧]\ 1xj}AFfTdH"a$&'0'0Z 2f]u (=sԲ@P\Sa! J0OU&_ll%^ @#̫{`ª2)W`! i]ނHZ-s *ʂw \s8 ٌs,&mʝl/rwsc'93"h>/[eHtR[hGh# *rvzx0$LX=(//r8b/Jӕ;RFsųZ4@0Ei;' (<]ĕ9eUi mC%G3 8=NH|^s{ $\cY')U7 tbfS3]CJѰ";zu6`a+Rp9?FG6ܜ{9j8_%U-^5g<\"])I V[E%77DI02[wԵp~-߼Z+ʤ2$qdߜ9"lQŀIYS}),(yj,yͼ7>VC=xh%o˥!2M66rs^{Ej0xmypa JpqoC{T@Zfo::XgUHK:9.ʵӽ*W3 mӨ R\K7 &n +~ FRLHʏGQѾRԺuGOO13@'Pm{EIW+m`.*J'Ͷ>!)*psvao"n <"zFkmJ^Eh@\ ܞ-gP+JR~e*p'!r 2u-JS+72[ _[RNHWل[QˊK_Kڕ{($st~ӌMo& /*QUrH:GON\ZtSI. qk@'IJieLT :lsr/׎hٶmP%*lvJcf_PJvYOZY 7 ĄtEMMJRʔ{0WQ !-I4 #r̴N)WonA LHKl{W)9 )sILϴK*](7l UF՘81np]RI$A?(hZZfLN2eb3q}"ĭW&e٪"nڤܞRm:?kR3M$nXhz[Sjt%VRJ|Cݷ=TU* XԄm '-[!vp-fIs 'fO$۸<ޘKx4BR&6op߸%BfEs mEk[9#U*͉ %^i/09ګ(B$^gFhRf RFpN}KTi212 }ؗ;9>ZiC_]j HdLĄ(MRN&xoRCQ՚e^M*Am8Pۥg<͔.N-(J͌ҩZckn%dfAyuNmS̬% 쫎a{mq/w,SѲ+4\)ĸLP+q&X}__k u4[CʧArJn9aTnҫ%:b\jSuO{\v$.ruy2K͸xһp1q|'Ex#NS'L晐3ZWPy@IPHQEbZ[)k2\8aeXry'bKjmaMK.]L|muXXcl<^vi uLԫ R/mU` e[$v&6VE*R=o;|b0JTwo0=ncO7NAZ| l$%+m[M .+IQß NҴ)w܎ brz R̸l)xKPȠm<‹8q67n/h&VՕ$X#C0d9_qW$ 7GX@SDMJ`mWyJ)?H6bc60PR}m H{`iԍI7L~NRFE#" WG+|C{j,,*Sar 6!- Bmnfamf$G"G9wI ?"R HW$shMf t]?+/*VafK@~w6ʌ*O4f'1JRPҮh[jZ%>Q|m q|_ p.qJ$3ϼ"Tl w[)Ø&`߷R-<  h; c 6D m~ ,"(m JoÓqbj gAĮ~+4f'VS.( z 9N*Tz%dj=D۟[aʵtpTZ(kꭦ]Sԣb MkpV}4g*.$-,䄥JדMF^+4tʜG ru`ҙJڑ|OE#p{bG1/Au*)%3M?뺢RsGPTR9$i;uE8ͅGV1FȘ×\}gWnCi% ^I*{{ 6~Mj jbSsL]n(H'FH5=)2W%'[u gruK% y5=#(˧͵leuSFn`4K i$[H.|[9J6/ R5J2_x4) H*QܑF*R)QJ\H#L0HE+WU)m, _j|D`JdW$P0yn֔ Bi Rc|ZarNEIsC)EBeܹpM;Gu*#nl8^ڐɽp`Z͹O #1qBǔV9W %Y6šŚq[8ARZQscx/ox0tw'^.~P[lo{G">`Sar` PɎJm*Ȃu6'&Nc6ua _%qed{T GZUM$ڟPCvi>Кv>1$Ef$ l- $$83rHm<6,ja'wA}Eu_#hh~@Qp`6@Kٹ{8Rh8 0[Zޢ if lu&l_=Ck$0*q{zG+nn/haI'B@7RN/p-^e?_738qE3wA*mnA90/JJyD l* 2RP7\}` %sL"r Sjl\-Cmø Jw4r+OTWm( "AGuDFoKB9e*~i. HGƁY)XJǤ=7^늳